-- cgit From 9cb0b933e260008c6a03e24a4a149f726b8d86b2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 8 Jun 2004 23:54:24 +0000 Subject: initial commit git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@3 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile | 10 ++ src/client.c | 32 ++++ src/client.h | 21 +++ src/core.c | 81 ++++++++++ src/core.h | 21 +++ src/idxset.c | 329 +++++++++++++++++++++++++++++++++++++++++ src/idxset.h | 28 ++++ src/inputstream.c | 50 +++++++ src/inputstream.h | 25 ++++ src/iochannel.c | 158 ++++++++++++++++++++ src/iochannel.h | 20 +++ src/main.c | 26 ++++ src/mainloop.c | 331 +++++++++++++++++++++++++++++++++++++++++ src/mainloop.h | 38 +++++ src/memblock.c | 67 +++++++++ src/memblock.h | 31 ++++ src/memblockq.c | 156 ++++++++++++++++++++ src/memblockq.h | 24 +++ src/module.c | 98 +++++++++++++ src/module.h | 27 ++++ src/oss.c | 30 ++++ src/outputstream.c | 41 ++++++ src/outputstream.h | 22 +++ src/packet.c | 29 ++++ src/packet.h | 18 +++ src/protocol-native-tcp.c | 19 +++ src/protocol-native-unix.c | 27 ++++ src/protocol-native.c | 49 +++++++ src/protocol-native.h | 9 ++ src/protocol-simple-tcp.c | 24 +++ src/protocol-simple.c | 173 ++++++++++++++++++++++ src/protocol-simple.h | 17 +++ src/pstream.c | 359 +++++++++++++++++++++++++++++++++++++++++++++ src/pstream.h | 22 +++ src/queue.c | 77 ++++++++++ src/queue.h | 13 ++ src/sample.c | 80 ++++++++++ src/sample.h | 35 +++++ src/sink-pipe.c | 155 +++++++++++++++++++ src/sink.c | 217 +++++++++++++++++++++++++++ src/sink.h | 38 +++++ src/socket-server.c | 157 ++++++++++++++++++++ src/socket-server.h | 18 +++ src/source.c | 58 ++++++++ src/source.h | 30 ++++ src/strbuf.c | 122 +++++++++++++++ src/strbuf.h | 13 ++ 47 files changed, 3425 insertions(+) create mode 100644 src/Makefile create mode 100644 src/client.c create mode 100644 src/client.h create mode 100644 src/core.c create mode 100644 src/core.h create mode 100644 src/idxset.c create mode 100644 src/idxset.h create mode 100644 src/inputstream.c create mode 100644 src/inputstream.h create mode 100644 src/iochannel.c create mode 100644 src/iochannel.h create mode 100644 src/main.c create mode 100644 src/mainloop.c create mode 100644 src/mainloop.h create mode 100644 src/memblock.c create mode 100644 src/memblock.h create mode 100644 src/memblockq.c create mode 100644 src/memblockq.h create mode 100644 src/module.c create mode 100644 src/module.h create mode 100644 src/oss.c create mode 100644 src/outputstream.c create mode 100644 src/outputstream.h create mode 100644 src/packet.c create mode 100644 src/packet.h create mode 100644 src/protocol-native-tcp.c create mode 100644 src/protocol-native-unix.c create mode 100644 src/protocol-native.c create mode 100644 src/protocol-native.h create mode 100644 src/protocol-simple-tcp.c create mode 100644 src/protocol-simple.c create mode 100644 src/protocol-simple.h create mode 100644 src/pstream.c create mode 100644 src/pstream.h create mode 100644 src/queue.c create mode 100644 src/queue.h create mode 100644 src/sample.c create mode 100644 src/sample.h create mode 100644 src/sink-pipe.c create mode 100644 src/sink.c create mode 100644 src/sink.h create mode 100644 src/socket-server.c create mode 100644 src/socket-server.h create mode 100644 src/source.c create mode 100644 src/source.h create mode 100644 src/strbuf.c create mode 100644 src/strbuf.h diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 00000000..366e84e6 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,10 @@ +CFLAGS=-Wall -pipe -ansi -D_GNU_SOURCE + +all: idxset.o queue.o strbuf.o mainloop.o iochannel.o packet.o \ + memblock.o sample.o socket-server.o memblockq.o client.o \ + core.o main.o outputstream.o inputstream.o source.o sink.o \ + pstream.o protocol-simple.o protocol-simple-tcp.o sink-pipe.o \ + module.o + +clean: + rm -f *.o diff --git a/src/client.c b/src/client.c new file mode 100644 index 00000000..56d85734 --- /dev/null +++ b/src/client.c @@ -0,0 +1,32 @@ +#include +#include +#include + +#include "client.h" + +struct client *client_new(struct core *core, const char *protocol_name, char *name) { + struct client *c; + int r; + assert(core); + + c = malloc(sizeof(struct client)); + assert(c); + c->protocol_name = protocol_name; + c->name = name ? strdup(name) : NULL; + c->kill = NULL; + c->userdata = NULL; + c->core = core; + + r = idxset_put(core->clients, c, &c->index); + assert(c->index != IDXSET_INVALID && r >= 0); + + return c; +} + +void client_free(struct client *c) { + assert(c && c->core); + + idxset_remove_by_data(c->core->clients, c, NULL); + free(c->name); + free(c); +} diff --git a/src/client.h b/src/client.h new file mode 100644 index 00000000..7128a452 --- /dev/null +++ b/src/client.h @@ -0,0 +1,21 @@ +#ifndef fooclienthfoo +#define fooclienthfoo + +#include "core.h" + +struct client { + char *name; + uint32_t index; + + const char *protocol_name; + + void *userdata; + void (*kill)(struct client *c); + + struct core *core; +}; + +struct client *client_new(struct core *c, const char *protocol_name, char *name); +void client_free(struct client *c); + +#endif diff --git a/src/core.c b/src/core.c new file mode 100644 index 00000000..7cfa66e3 --- /dev/null +++ b/src/core.c @@ -0,0 +1,81 @@ +#include +#include +#include + +#include "core.h" +#include "module.h" +#include "sink.h" +#include "source.h" + +struct core* core_new(struct mainloop *m) { + struct core* c; + c = malloc(sizeof(struct core)); + assert(c); + + c->mainloop = m; + c->clients = idxset_new(NULL, NULL); + c->sinks = idxset_new(NULL, NULL); + c->sources = idxset_new(NULL, NULL); + c->output_streams = idxset_new(NULL, NULL); + c->input_streams = idxset_new(NULL, NULL); + + c->default_source_index = c->default_sink_index = IDXSET_INVALID; + + c->modules = NULL; + + return c; +}; + +void core_free(struct core *c) { + assert(c); + + module_unload_all(c); + assert(!c->modules); + + assert(idxset_isempty(c->clients)); + idxset_free(c->clients, NULL, NULL); + + assert(idxset_isempty(c->sinks)); + idxset_free(c->sinks, NULL, NULL); + + assert(idxset_isempty(c->sources)); + idxset_free(c->sources, NULL, NULL); + + assert(idxset_isempty(c->output_streams)); + idxset_free(c->output_streams, NULL, NULL); + + assert(idxset_isempty(c->input_streams)); + idxset_free(c->input_streams, NULL, NULL); + + 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_rrobin(c->sinks, NULL))) + return NULL; + + fprintf(stderr, "Default sink vanished, setting to %u\n", sink->index); + c->default_sink_index = 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_rrobin(c->sources, NULL))) + return NULL; + + fprintf(stderr, "Default source vanished, setting to %u\n", source->index); + c->default_source_index = source->index; + return source; +} diff --git a/src/core.h b/src/core.h new file mode 100644 index 00000000..649c9dba --- /dev/null +++ b/src/core.h @@ -0,0 +1,21 @@ +#ifndef foocorehfoo +#define foocorehfoo + +#include "idxset.h" +#include "mainloop.h" + +struct core { + struct mainloop *mainloop; + + struct idxset *clients, *sinks, *sources, *output_streams, *input_streams, *modules; + + uint32_t default_source_index, default_sink_index; +}; + +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 diff --git a/src/idxset.c b/src/idxset.c new file mode 100644 index 00000000..eaea34f4 --- /dev/null +++ b/src/idxset.c @@ -0,0 +1,329 @@ +#include +#include +#include + +#include "idxset.h" + +struct idxset_entry { + void *data; + uint32_t index; + unsigned hash_value; + + struct idxset_entry *hash_prev, *hash_next; + struct idxset_entry* iterate_prev, *iterate_next; +}; + +struct idxset { + unsigned (*hash_func) (void *p); + int (*compare_func)(void *a, void *b); + + unsigned hash_table_size, n_entries; + struct idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail, *rrobin; + uint32_t index, start_index, array_size; +}; + +static unsigned trivial_hash_func(void *p) { + return (unsigned) p; +} + +static int trivial_compare_func(void *a, void *b) { + return !(a == b); +} + +struct idxset* idxset_new(unsigned (*hash_func) (void *p), int (*compare_func) (void*a, void*b)) { + struct idxset *s; + + s = malloc(sizeof(struct idxset)); + assert(s); + s->hash_func = hash_func ? hash_func : trivial_hash_func; + s->compare_func = compare_func ? compare_func : trivial_compare_func; + s->hash_table_size = 1023; + s->hash_table = malloc(sizeof(struct idxset_entry*)*s->hash_table_size); + assert(s->hash_table); + s->array = NULL; + s->array_size = 0; + s->index = 0; + s->start_index = 0; + s->n_entries = 0; + + s->iterate_list_head = s->iterate_list_tail = NULL; + + return s; +} + +void idxset_free(struct idxset *s, void (*free_func) (void *p, void *userdata), void *userdata) { + assert(s); + + if (free_func) { + while (s->iterate_list_head) { + struct idxset_entry *e = s->iterate_list_head; + s->iterate_list_head = s->iterate_list_head->iterate_next; + + if (free_func) + free_func(e->data, userdata); + free(e); + } + } + + free(s->hash_table); + free(s->array); + free(s); +} + +static struct idxset_entry* hash_scan(struct idxset *s, struct idxset_entry* e, void *p) { + assert(p); + + assert(s->compare_func); + for (; e; e = e->hash_next) + if (s->compare_func(e->data, p)) + return e; + + return NULL; +} + +static void extend_array(struct idxset *s, uint32_t index) { + uint32_t i, j, l; + struct idxset_entry** n; + assert(index >= s->start_index ); + + if (index <= s->start_index + s->array_size) + return; + + for (i = 0; i < s->array_size; i++) + if (s->array[i]) + break; + + l = index - s->start_index - i + 100; + n = malloc(sizeof(struct hash_table_entry*)*l); + assert(n); + memset(n, 0, sizeof(struct hash_table_entry*)*l); + + for (j = 0; j < s->array_size-i; j++) + n[j] = s->array[i+j]; + + free(s->array); + + s->array = n; + s->array_size = l; + s->start_index += i; +} + +static struct idxset_entry** array_index(struct idxset*s, uint32_t index) { + + if (index >= s->start_index + s->array_size) + return NULL; + + if (index < s->start_index) + return NULL; + + return s->array + (index - s->start_index); +} + +int idxset_put(struct idxset*s, void *p, uint32_t *index) { + unsigned h; + struct idxset_entry *e, **a; + assert(s && p); + + assert(s->hash_func); + h = s->hash_func(p) % s->hash_table_size; + + assert(s->hash_table); + if ((e = hash_scan(s, s->hash_table[h], p))) { + if (index) + *index = e->index; + + return -1; + } + + e = malloc(sizeof(struct idxset_entry)); + assert(e); + + e->data = p; + e->index = s->index++; + e->hash_value = h; + + /* Insert into hash table */ + e->hash_next = s->hash_table[h]; + e->hash_prev = NULL; + if (s->hash_table[h]) + s->hash_table[h]->hash_prev = e; + s->hash_table[h] = e; + + /* Insert into array */ + extend_array(s, s->index); + a = array_index(s, s->index); + assert(a && !*a); + *a = e; + + /* Insert into linked list */ + e->iterate_next = NULL; + e->iterate_prev = s->iterate_list_tail; + if (s->iterate_list_tail) { + assert(s->iterate_list_head); + s->iterate_list_tail->iterate_next = e; + } else { + assert(!s->iterate_list_head); + s->iterate_list_head = e; + } + s->iterate_list_tail = e; + + s->n_entries++; + assert(s->n_entries >= 1); + + if (index) + *index = e->index; + + return 0; +} + +void* idxset_get_by_index(struct idxset*s, uint32_t index) { + struct idxset_entry **a; + assert(s); + + if (!(a = array_index(s, index))) + return NULL; + + return (*a)->data; +} + +void* idxset_get_by_data(struct idxset*s, void *p, uint32_t *index) { + unsigned h; + struct idxset_entry *e; + assert(s && p); + + assert(s->hash_func); + h = s->hash_func(p) % s->hash_table_size; + + assert(s->hash_table); + if (!(e = hash_scan(s, s->hash_table[h], p))) + return NULL; + + if (index) + *index = e->index; + + return e->data; +} + +static void remove_entry(struct idxset *s, struct idxset_entry *e) { + struct idxset_entry **a; + assert(s && e); + + /* Remove from array */ + a = array_index(s, s->index); + assert(a && *a == e); + *a = NULL; + + /* Remove from linked list */ + if (e->iterate_next) + e->iterate_next->iterate_prev = e->iterate_prev; + else + s->iterate_list_tail = e->iterate_prev; + + if (e->iterate_prev) + e->iterate_prev->iterate_next = e->iterate_next; + else + s->iterate_list_head = e->iterate_next; + + /* Remove from hash table */ + if (e->hash_next) + e->hash_next->hash_prev = e->hash_prev; + + if (e->hash_prev) + e->hash_prev->hash_next = e->hash_next; + else + s->hash_table[e->hash_value] = e->hash_next; + + if (s->rrobin == e) + s->rrobin = NULL; + + free(e); + + assert(s->n_entries >= 1); + s->n_entries--; +} + +void* idxset_remove_by_index(struct idxset*s, uint32_t index) { + struct idxset_entry **a; + void *data; + + assert(s); + + if (!(a = array_index(s, index))) + return NULL; + + data = (*a)->data; + remove_entry(s, *a); + + return data; +} + +void* idxset_remove_by_data(struct idxset*s, void *data, uint32_t *index) { + struct idxset_entry *e; + unsigned h; + + assert(s->hash_func); + h = s->hash_func(data) % s->hash_table_size; + + assert(s->hash_table); + if (!(e = hash_scan(s, s->hash_table[h], data))) + return NULL; + + data = e->data; + if (index) + *index = e->index; + + remove_entry(s, e); + + return data; +} + +void* idxset_rrobin(struct idxset *s, uint32_t *index) { + assert(s && index); + + if (s->rrobin) + s->rrobin = s->rrobin->iterate_next; + + if (!s->rrobin) + s->rrobin = s->iterate_list_head; + + if (!s->rrobin) + return NULL; + + if (index) + *index = s->rrobin->index; + + return s->rrobin->data; +} + +int idxset_foreach(struct idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata) { + struct idxset_entry *e; + assert(s && func); + + e = s->iterate_list_head; + while (e) { + int del = 0, r; + struct idxset_entry *n = e->iterate_next; + + r = func(e->data, e->index, &del, userdata); + + if (del) + remove_entry(s, e); + + if (r < 0) + return r; + + e = n; + } + + return 0; +} + +unsigned idxset_ncontents(struct idxset*s) { + assert(s); + return s->n_entries; +} + +int idxset_isempty(struct idxset *s) { + assert(s); + return s->n_entries == 0; +} diff --git a/src/idxset.h b/src/idxset.h new file mode 100644 index 00000000..f649e23e --- /dev/null +++ b/src/idxset.h @@ -0,0 +1,28 @@ +#ifndef fooidxsethfoo +#define fooidxsethfoo + +#include + +#define IDXSET_INVALID ((uint32_t) -1) + +struct idxset; + +struct idxset* idxset_new(unsigned (*hash_func) (void *p), int (*compare_func) (void*a, void*b)); +void idxset_free(struct idxset *s, void (*free_func) (void *p, void *userdata), void *userdata); + +int idxset_put(struct idxset*s, void *p, uint32_t *index); + +void* idxset_get_by_index(struct idxset*s, uint32_t index); +void* idxset_get_by_data(struct idxset*s, void *p, uint32_t *index); + +void* idxset_remove_by_index(struct idxset*s, uint32_t index); +void* idxset_remove_by_data(struct idxset*s, void *p, uint32_t *index); + +void* idxset_rrobin(struct idxset *s, uint32_t *index); + +int idxset_foreach(struct idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata); + +unsigned idxset_ncontents(struct idxset*s); +int idxset_isempty(struct idxset *s); + +#endif diff --git a/src/inputstream.c b/src/inputstream.c new file mode 100644 index 00000000..c7b4b4c7 --- /dev/null +++ b/src/inputstream.c @@ -0,0 +1,50 @@ +#include +#include +#include + +#include "inputstream.h" + +struct input_stream* input_stream_new(struct sink *s, struct sample_spec *spec, const char *name) { + struct input_stream *i; + int r; + assert(s && spec); + + i = malloc(sizeof(struct input_stream)); + assert(i); + i->name = name ? strdup(name) : NULL; + i->sink = s; + i->spec = *spec; + + i->memblockq = memblockq_new(bytes_per_second(spec)*5, sample_size(spec)); + assert(i->memblockq); + + assert(s->core); + r = idxset_put(s->core->input_streams, i, &i->index); + assert(r == 0 && i->index != IDXSET_INVALID); + r = idxset_put(s->input_streams, i, NULL); + assert(r == 0); + + return i; +} + +void input_stream_free(struct input_stream* i) { + assert(i); + + memblockq_free(i->memblockq); + + assert(i->sink && i->sink->core); + idxset_remove_by_data(i->sink->core->input_streams, i, NULL); + idxset_remove_by_data(i->sink->input_streams, i, NULL); + + free(i->name); + free(i); +} + +void input_stream_notify(struct input_stream *i) { + assert(i); + + if (memblockq_is_empty(i->memblockq)) + return; + + sink_notify(i->sink); +} diff --git a/src/inputstream.h b/src/inputstream.h new file mode 100644 index 00000000..0353799e --- /dev/null +++ b/src/inputstream.h @@ -0,0 +1,25 @@ +#ifndef fooinputstreamhfoo +#define fooinputstreamhfoo + +#include + +#include "sink.h" +#include "sample.h" +#include "memblockq.h" + +struct input_stream { + char *name; + uint32_t index; + + struct sink *sink; + struct sample_spec spec; + + struct memblockq *memblockq; +}; + +struct input_stream* input_stream_new(struct sink *s, struct sample_spec *spec, const char *name); +void input_stream_free(struct input_stream* i); + +void input_stream_notify(struct input_stream *i); + +#endif diff --git a/src/iochannel.c b/src/iochannel.c new file mode 100644 index 00000000..db9717a9 --- /dev/null +++ b/src/iochannel.c @@ -0,0 +1,158 @@ +#include +#include +#include +#include + +#include "iochannel.h" + +struct iochannel { + int ifd, ofd; + struct mainloop* mainloop; + + void (*callback)(struct iochannel*io, void *userdata); + void*userdata; + + int readable; + int writable; + + struct mainloop_source* input_source, *output_source; +}; + +static void enable_mainloop_sources(struct iochannel *io) { + assert(io); + + if (io->input_source == io->output_source) { + enum mainloop_io_event e = MAINLOOP_IO_EVENT_NULL; + assert(io->input_source); + + if (!io->readable) + e |= MAINLOOP_IO_EVENT_IN; + if (!io->writable) + e |= MAINLOOP_IO_EVENT_OUT; + + mainloop_source_io_set_events(io->input_source, e); + } else { + if (io->input_source) + mainloop_source_io_set_events(io->input_source, io->readable ? MAINLOOP_IO_EVENT_NULL : MAINLOOP_IO_EVENT_IN); + if (io->output_source) + mainloop_source_io_set_events(io->output_source, io->writable ? MAINLOOP_IO_EVENT_NULL : MAINLOOP_IO_EVENT_OUT); + } +} + +static void callback(struct mainloop_source*s, int fd, enum mainloop_io_event events, void *userdata) { + struct iochannel *io = userdata; + int changed; + assert(s && fd >= 0 && userdata); + + if (events & MAINLOOP_IO_EVENT_IN && !io->readable) { + io->readable = 1; + changed = 1; + } + + if (events & MAINLOOP_IO_EVENT_OUT && !io->writable) { + io->writable = 1; + changed = 1; + } + + if (changed) { + enable_mainloop_sources(io); + + if (io->callback) + io->callback(io, io->userdata); + } +} + +static void make_nonblock_fd(int fd) { + int v; + + if ((v = fcntl(fd, F_GETFL)) >= 0) + if (!(v & O_NONBLOCK)) + fcntl(fd, F_SETFL, v|O_NONBLOCK); +} + +struct iochannel* iochannel_new(struct mainloop*m, int ifd, int ofd) { + struct iochannel *io; + assert(m && (ifd >= 0 || ofd >= 0)); + + io = malloc(sizeof(struct iochannel)); + io->ifd = ifd; + io->ofd = ofd; + io->mainloop = m; + + io->userdata = NULL; + io->callback = NULL; + io->readable = 0; + io->writable = 0; + + if (ifd == ofd) { + assert(ifd >= 0); + make_nonblock_fd(io->ifd); + io->input_source = io->output_source = mainloop_source_new_io(m, ifd, MAINLOOP_IO_EVENT_IN|MAINLOOP_IO_EVENT_OUT, callback, io); + } else { + + if (ifd >= 0) { + make_nonblock_fd(io->ifd); + io->input_source = mainloop_source_new_io(m, ifd, MAINLOOP_IO_EVENT_IN, callback, io); + } else + io->input_source = NULL; + + if (ofd >= 0) { + make_nonblock_fd(io->ofd); + io->output_source = mainloop_source_new_io(m, ofd, MAINLOOP_IO_EVENT_OUT, callback, io); + } else + io->output_source = NULL; + } + + return io; +} + +void iochannel_free(struct iochannel*io) { + assert(io); + + if (io->ifd >= 0) + close(io->ifd); + if (io->ofd >= 0 && io->ofd != io->ifd) + close(io->ofd); + + if (io->input_source) + mainloop_source_free(io->input_source); + if (io->output_source) + mainloop_source_free(io->output_source); + + free(io); +} + +int iochannel_is_readable(struct iochannel*io) { + assert(io); + return io->readable; +} + +int iochannel_is_writable(struct iochannel*io) { + assert(io); + return io->writable; +} + +ssize_t iochannel_write(struct iochannel*io, const void*data, size_t l) { + ssize_t r; + assert(io && data && l && io->ofd >= 0); + + if ((r = write(io->ofd, data, l)) >= 0) { + io->writable = 0; + enable_mainloop_sources(io); + } + + return r; +} + +ssize_t iochannel_read(struct iochannel*io, void*data, size_t l) { + ssize_t r; + + assert(io && data && l && io->ifd >= 0); + + if ((r = read(io->ifd, data, l)) >= 0) { + io->readable = 0; + enable_mainloop_sources(io); + } + + return r; +} diff --git a/src/iochannel.h b/src/iochannel.h new file mode 100644 index 00000000..f97fabba --- /dev/null +++ b/src/iochannel.h @@ -0,0 +1,20 @@ +#ifndef fooiochannelhfoo +#define fooiochannelhfoo + +#include +#include "mainloop.h" + +struct iochannel; + +struct iochannel* iochannel_new(struct mainloop*m, int ifd, int ofd); +void iochannel_free(struct iochannel*io); + +ssize_t iochannel_write(struct iochannel*io, const void*data, size_t l); +ssize_t iochannel_read(struct iochannel*io, void*data, size_t l); + +int iochannel_is_readable(struct iochannel*io); +int iochannel_is_writable(struct iochannel*io); + +void iochannel_set_callback(struct iochannel*io, void (*callback)(struct iochannel*io, void *userdata), void *userdata); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 00000000..3104c264 --- /dev/null +++ b/src/main.c @@ -0,0 +1,26 @@ +#include +#include + +#include "core.h" +#include "mainloop.h" +#include "module.h" + +int main(int argc, char *argv[]) { + struct mainloop *m; + struct core *c; + + m = mainloop_new(); + assert(m); + c = core_new(m); + assert(c); + + module_load(c, "sink-pipe", NULL); + module_load(c, "protocol-simple-tcp", NULL); + + mainloop_run(m); + + core_free(c); + mainloop_free(m); + + return 0; +} diff --git a/src/mainloop.c b/src/mainloop.c new file mode 100644 index 00000000..d043ce90 --- /dev/null +++ b/src/mainloop.c @@ -0,0 +1,331 @@ +#include +#include +#include +#include + +#include "mainloop.h" + +struct mainloop_source { + struct mainloop_source *next; + struct mainloop *mainloop; + enum mainloop_source_type type; + + int enabled; + int dead; + void *userdata; + + struct { + int fd; + enum mainloop_io_event events; + void (*callback)(struct mainloop_source*s, int fd, enum mainloop_io_event event, void *userdata); + struct pollfd pollfd; + } io; + + struct { + void (*callback)(struct mainloop_source*s, void *userdata); + } prepare; + + struct { + void (*callback)(struct mainloop_source*s, void *userdata); + } idle; +}; + +struct mainloop_source_list { + struct mainloop_source *sources; + int n_sources; + int dead_sources; +}; + +struct mainloop { + struct mainloop_source_list io_sources, prepare_sources, idle_sources; + + struct pollfd *pollfds; + int max_pollfds, n_pollfds; + int rebuild_pollfds; + + int quit; + int running; +}; + +struct mainloop *mainloop_new(void) { + struct mainloop *m; + + m = malloc(sizeof(struct mainloop)); + assert(m); + memset(m, 0, sizeof(struct mainloop)); + + return m; +} + +static void free_sources(struct mainloop_source_list *l, int all) { + struct mainloop_source *s, *p; + assert(l); + + if (!l->dead_sources) + return; + + p = NULL; + s = l->sources; + while (s) { + if (all || s->dead) { + struct mainloop_source *t = s; + s = s->next; + + if (p) + p->next = s; + else + l->sources = s; + + free(t); + } else { + p = s; + s = s->next; + } + } + + l->dead_sources = 0; + + if (all) { + assert(l->sources); + l->n_sources = 0; + } +} + +void mainloop_free(struct mainloop* m) { + assert(m); + free_sources(&m->io_sources, 1); + free_sources(&m->prepare_sources, 1); + free_sources(&m->idle_sources, 1); + free(m->pollfds); +} + +static void rebuild_pollfds(struct mainloop *m) { + struct mainloop_source*s; + struct pollfd *p; + + if (m->max_pollfds < m->io_sources.n_sources) { + m->max_pollfds = m->io_sources.n_sources*2; + m->pollfds = realloc(m->pollfds, sizeof(struct pollfd)*m->max_pollfds); + } + + m->n_pollfds = 0; + p = m->pollfds; + for (s = m->io_sources.sources; s; s = s->next) { + assert(s->type == MAINLOOP_SOURCE_TYPE_IO); + if (!s->dead && s->enabled && s->io.events != MAINLOOP_IO_EVENT_NULL) { + *(p++) = s->io.pollfd; + m->n_pollfds++; + } + } +} + +static void dispatch_pollfds(struct mainloop *m) { + int i; + struct pollfd *p; + struct mainloop_source *s; + /* This loop assumes that m->sources and m->pollfds have the same + * order and that m->pollfds is a subset of m->sources! */ + + s = m->io_sources.sources; + for (p = m->pollfds, i = 0; i < m->n_pollfds; p++, i++) { + for (;;) { + assert(s && s->type == MAINLOOP_SOURCE_TYPE_IO); + + if (p->fd == s->io.fd) { + if (!s->dead && s->enabled) { + enum mainloop_io_event e = (p->revents & POLLIN ? MAINLOOP_IO_EVENT_IN : 0) | (p->revents & POLLOUT ? MAINLOOP_IO_EVENT_OUT : 0); + if (e) { + assert(s->io.callback); + s->io.callback(s, s->io.fd, e, s->userdata); + } + } + + break; + } + s = s->next; + } + } +} + +int mainloop_iterate(struct mainloop *m, int block) { + struct mainloop_source *s; + int c; + assert(m && !m->running); + + if(m->quit) + return m->quit; + + free_sources(&m->io_sources, 0); + free_sources(&m->prepare_sources, 0); + free_sources(&m->idle_sources, 0); + + for (s = m->prepare_sources.sources; s; s = s->next) { + assert(!s->dead && s->type == MAINLOOP_SOURCE_TYPE_PREPARE); + if (s->enabled) { + assert(s->prepare.callback); + s->prepare.callback(s, s->userdata); + } + } + + if (m->rebuild_pollfds) + rebuild_pollfds(m); + + m->running = 1; + + if ((c = poll(m->pollfds, m->n_pollfds, (block && !m->idle_sources.n_sources) ? -1 : 0)) > 0) + dispatch_pollfds(m); + else if (c == 0) { + for (s = m->idle_sources.sources; s; s = s->next) { + assert(!s->dead && s->type == MAINLOOP_SOURCE_TYPE_IDLE); + if (s->enabled) { + assert(s->idle.callback); + s->idle.callback(s, s->userdata); + } + } + } + + m->running = 0; + return c < 0 ? -1 : 0; +} + +int mainloop_run(struct mainloop *m) { + int r; + while (!(r = mainloop_iterate(m, 1))); + return r; +} + +void mainloop_quit(struct mainloop *m, int r) { + assert(m); + m->quit = r; +} + +static struct mainloop_source_list* get_source_list(struct mainloop *m, enum mainloop_source_type type) { + struct mainloop_source_list *l; + + switch(type) { + case MAINLOOP_SOURCE_TYPE_IO: + l = &m->io_sources; + break; + case MAINLOOP_SOURCE_TYPE_PREPARE: + l = &m->prepare_sources; + break; + case MAINLOOP_SOURCE_TYPE_IDLE: + l = &m->idle_sources; + break; + default: + l = NULL; + break; + } + + return l; +} + +static struct mainloop_source *source_new(struct mainloop*m, enum mainloop_source_type type) { + struct mainloop_source_list *l; + struct mainloop_source* s; + assert(m); + + s = malloc(sizeof(struct mainloop_source)); + assert(s); + memset(s, 0, sizeof(struct mainloop_source)); + + s->type = type; + s->mainloop = m; + + l = get_source_list(m, type); + assert(l); + + s->next = l->sources; + l->sources = s; + l->n_sources++; + return s; +} + +struct mainloop_source* mainloop_source_new_io(struct mainloop*m, int fd, enum mainloop_io_event event, void (*callback)(struct mainloop_source*s, int fd, enum mainloop_io_event event, void *userdata), void *userdata) { + struct mainloop_source* s; + assert(m && fd>=0 && callback); + + s = source_new(m, MAINLOOP_SOURCE_TYPE_IO); + + s->io.fd = fd; + s->io.events = event; + s->io.callback = callback; + s->userdata = userdata; + s->io.pollfd.fd = fd; + s->io.pollfd.events = (event & MAINLOOP_IO_EVENT_IN ? POLLIN : 0) | (event & MAINLOOP_IO_EVENT_OUT ? POLLOUT : 0); + s->io.pollfd.revents = 0; + + s->enabled = 1; + + m->rebuild_pollfds = 1; + return s; +} + +struct mainloop_source* mainloop_source_new_prepare(struct mainloop*m, void (*callback)(struct mainloop_source *s, void*userdata), void*userdata) { + struct mainloop_source* s; + assert(m && callback); + + s = source_new(m, MAINLOOP_SOURCE_TYPE_PREPARE); + + s->prepare.callback = callback; + s->userdata = userdata; + s->enabled = 1; + return s; +} + +struct mainloop_source* mainloop_source_new_idle(struct mainloop*m, void (*callback)(struct mainloop_source *s, void*userdata), void*userdata) { + struct mainloop_source* s; + assert(m && callback); + + s = source_new(m, MAINLOOP_SOURCE_TYPE_IDLE); + + s->prepare.callback = callback; + s->userdata = userdata; + s->enabled = 1; + return s; +} + +void mainloop_source_free(struct mainloop_source*s) { + struct mainloop_source_list *l; + assert(s && !s->dead); + s->dead = 1; + + assert(s->mainloop); + l = get_source_list(s->mainloop, s->type); + assert(l); + + l->n_sources--; + l->dead_sources = 1; + + if (s->type == MAINLOOP_SOURCE_TYPE_IO) + s->mainloop->rebuild_pollfds = 1; +} + +void mainloop_source_enable(struct mainloop_source*s, int b) { + assert(s && !s->dead); + + if (s->type == MAINLOOP_SOURCE_TYPE_IO && ((s->enabled && !b) || (!s->enabled && b))) { + assert(s->mainloop); + s->mainloop->rebuild_pollfds = 1; + } + + s->enabled = b; +} + +void mainloop_source_io_set_events(struct mainloop_source*s, enum mainloop_io_event events) { + assert(s && !s->dead && s->type == MAINLOOP_SOURCE_TYPE_IO); + + if ((s->io.events && !events) || (!s->io.events && events)) { + assert(s->mainloop); + s->mainloop->rebuild_pollfds = 1; + } + + s->io.events = events; + s->io.pollfd.events = ((events & MAINLOOP_IO_EVENT_IN) ? POLLIN : 0) | ((events & MAINLOOP_IO_EVENT_OUT) ? POLLOUT : 0); +} + +struct mainloop *mainloop_source_get_mainloop(struct mainloop_source *s) { + assert(s); + + return s->mainloop; +} diff --git a/src/mainloop.h b/src/mainloop.h new file mode 100644 index 00000000..72376c72 --- /dev/null +++ b/src/mainloop.h @@ -0,0 +1,38 @@ +#ifndef foomainloophfoo +#define foomainloophfoo + +struct mainloop; +struct mainloop_source; + +enum mainloop_io_event { + MAINLOOP_IO_EVENT_NULL = 0, + MAINLOOP_IO_EVENT_IN = 1, + MAINLOOP_IO_EVENT_OUT = 2, + MAINLOOP_IO_EVENT_BOTH = 3 +}; + +enum mainloop_source_type { + MAINLOOP_SOURCE_TYPE_IO, + MAINLOOP_SOURCE_TYPE_PREPARE, + MAINLOOP_SOURCE_TYPE_IDLE +}; + +struct mainloop *mainloop_new(void); +void mainloop_free(struct mainloop* m); + +int mainloop_iterate(struct mainloop *m, int block); +int mainloop_run(struct mainloop *m); +void mainloop_quit(struct mainloop *m, int r); + +struct mainloop_source* mainloop_source_new_io(struct mainloop*m, int fd, enum mainloop_io_event event, void (*callback)(struct mainloop_source*s, int fd, enum mainloop_io_event event, void *userdata), void *userdata); +struct mainloop_source* mainloop_source_new_prepare(struct mainloop*m, void (*callback)(struct mainloop_source *s, void*userdata), void*userdata); +struct mainloop_source* mainloop_source_new_idle(struct mainloop*m, void (*callback)(struct mainloop_source *s, void*userdata), void*userdata); + +void mainloop_source_free(struct mainloop_source*s); +void mainloop_source_enable(struct mainloop_source*s, int b); + +void mainloop_source_io_set_events(struct mainloop_source*s, enum mainloop_io_event event); + +struct mainloop *mainloop_source_get_mainloop(struct mainloop_source *s); + +#endif diff --git a/src/memblock.c b/src/memblock.c new file mode 100644 index 00000000..3bef4944 --- /dev/null +++ b/src/memblock.c @@ -0,0 +1,67 @@ +#include +#include +#include + +#include "memblock.h" + +struct memblock *memblock_new(size_t length) { + struct memblock *b = malloc(sizeof(struct memblock)+length); + b->type = MEMBLOCK_APPENDED; + b->ref = 1; + b->length = length; + b->data = b+1; + return b; +} + +struct memblock *memblock_new_fixed(void *d, size_t length) { + struct memblock *b = malloc(sizeof(struct memblock)); + b->type = MEMBLOCK_FIXED; + b->ref = 1; + b->length = length; + b->data = d; + return b; +} + +struct memblock *memblock_new_dynamic(void *d, size_t length) { + struct memblock *b = malloc(sizeof(struct memblock)); + b->type = MEMBLOCK_DYNAMIC; + b->ref = 1; + b->length = length; + b->data = d; + return b; +} + +struct memblock* memblock_ref(struct memblock*b) { + assert(b && b->ref >= 1); + b->ref++; + return b; +} + +void memblock_unref(struct memblock*b) { + assert(b && b->ref >= 1); + b->ref--; + + if (b->ref == 0) { + if (b->type == MEMBLOCK_DYNAMIC) + free(b->data); + free(b); + } +} + +void memblock_unref_fixed(struct memblock *b) { + void *d; + + assert(b && b->ref >= 1); + + if (b->ref == 1) { + memblock_unref(b); + return; + } + + d = malloc(b->length); + assert(d); + memcpy(d, b->data, b->length); + b->data = d; + b->type = MEMBLOCK_DYNAMIC; +} + diff --git a/src/memblock.h b/src/memblock.h new file mode 100644 index 00000000..48e87286 --- /dev/null +++ b/src/memblock.h @@ -0,0 +1,31 @@ +#ifndef foomemblockhfoo +#define foomemblockhfoo + +#include + +enum memblock_type { MEMBLOCK_FIXED, MEMBLOCK_APPENDED, MEMBLOCK_DYNAMIC }; + +struct memblock { + enum memblock_type type; + unsigned ref; + size_t length; + void *data; +}; + +struct memchunk { + struct memblock *memblock; + size_t index, length; +}; + +struct memblock *memblock_new(size_t length); +struct memblock *memblock_new_fixed(void *data, size_t length); +struct memblock *memblock_new_dynamic(void *data, size_t length); + +void memblock_unref(struct memblock*b); +struct memblock* memblock_ref(struct memblock*b); + +void memblock_unref_fixed(struct memblock*b); + +#define memblock_assert_exclusive(b) assert((b)->ref == 1) + +#endif diff --git a/src/memblockq.c b/src/memblockq.c new file mode 100644 index 00000000..1424c556 --- /dev/null +++ b/src/memblockq.c @@ -0,0 +1,156 @@ +#include +#include + +#include "memblockq.h" + +struct memblock_list { + struct memblock_list *next; + struct memchunk chunk; +}; + +struct memblockq { + struct memblock_list *blocks, *blocks_tail; + unsigned n_blocks; + size_t total_length; + size_t maxlength; + size_t base; +}; + +struct memblockq* memblockq_new(size_t maxlength, size_t base) { + struct memblockq* bq; + assert(maxlength && base); + + bq = malloc(sizeof(struct memblockq)); + assert(bq); + bq->blocks = bq->blocks_tail = 0; + bq->n_blocks = 0; + bq->total_length = 0; + bq->base = base; + bq->maxlength = ((maxlength+base-1)/base)*base; + assert(bq->maxlength >= base); + return bq; +} + +void memblockq_free(struct memblockq* bq) { + struct memblock_list *l; + assert(bq); + + while ((l = bq->blocks)) { + bq->blocks = l->next; + memblock_unref(l->chunk.memblock); + free(l); + } + + free(bq); +} + +void memblockq_push(struct memblockq* bq, struct memchunk *chunk, size_t delta) { + struct memblock_list *q; + assert(bq && chunk && chunk->memblock && chunk->index); + + q = malloc(sizeof(struct memblock_list)); + assert(q); + + q->chunk = *chunk; + memblock_ref(q->chunk.memblock); + assert(q->chunk.index+q->chunk.length <= q->chunk.memblock->length); + q->next = NULL; + + if (bq->blocks_tail) + bq->blocks_tail->next = q; + else + bq->blocks = q; + + bq->blocks_tail = q; + + bq->n_blocks++; + bq->total_length += chunk->length; + + memblockq_shorten(bq, bq->maxlength); +} + +int memblockq_peek(struct memblockq* bq, struct memchunk *chunk) { + assert(bq && chunk); + + if (!bq->blocks) + return -1; + + *chunk = bq->blocks->chunk; + memblock_ref(chunk->memblock); + return 0; +} + +int memblockq_pop(struct memblockq* bq, struct memchunk *chunk) { + struct memblock_list *q; + + assert(bq && chunk); + + if (!bq->blocks) + return -1; + + q = bq->blocks; + bq->blocks = bq->blocks->next; + + *chunk = q->chunk; + + bq->n_blocks--; + bq->total_length -= chunk->length; + + free(q); + return 0; +} + +void memblockq_drop(struct memblockq *bq, size_t length) { + assert(bq); + + while (length > 0) { + size_t l = length; + assert(bq->blocks && bq->total_length >= length); + + if (l > bq->blocks->chunk.length) + l = bq->blocks->chunk.length; + + bq->blocks->chunk.index += l; + bq->blocks->chunk.length -= l; + bq->total_length -= l; + + if (bq->blocks->chunk.length == 0) { + struct memblock_list *q; + + q = bq->blocks; + bq->blocks = bq->blocks->next; + memblock_unref(q->chunk.memblock); + free(q); + + bq->n_blocks--; + } + + length -= l; + } +} + +void memblockq_shorten(struct memblockq *bq, size_t length) { + size_t l; + assert(bq); + + if (bq->total_length <= length) + return; + + l = bq->total_length - length; + l /= bq->base; + l *= bq->base; + + memblockq_drop(bq, l); +} + + +void memblockq_empty(struct memblockq *bq) { + assert(bq); + memblockq_shorten(bq, 0); +} + +int memblockq_is_empty(struct memblockq *bq) { + assert(bq); + + return bq->total_length >= bq->base; +} diff --git a/src/memblockq.h b/src/memblockq.h new file mode 100644 index 00000000..75c5e59e --- /dev/null +++ b/src/memblockq.h @@ -0,0 +1,24 @@ +#ifndef foomemblockqhfoo +#define foomemblockqhfoo + +#include + +#include "memblock.h" + +struct memblockq; + +struct memblockq* memblockq_new(size_t maxlength, size_t base); +void memblockq_free(struct memblockq* bq); + +void memblockq_push(struct memblockq* bq, struct memchunk *chunk, size_t delta); + +int memblockq_pop(struct memblockq* bq, struct memchunk *chunk); +int memblockq_peek(struct memblockq* bq, struct memchunk *chunk); +void memblockq_drop(struct memblockq *bq, size_t length); + +void memblockq_shorten(struct memblockq *bq, size_t length); +void memblockq_empty(struct memblockq *bq); + +int memblockq_is_empty(struct memblockq *bq); + +#endif diff --git a/src/module.c b/src/module.c new file mode 100644 index 00000000..bcd0b6c0 --- /dev/null +++ b/src/module.c @@ -0,0 +1,98 @@ +#include +#include + +#include "module.h" + +struct module* module_load(struct core *c, const char *name, const char *argument) { + struct module *m = NULL; + + assert(c && name); + + m = malloc(sizeof(struct module)); + assert(m); + + if (!(m->dl = lt_dlopenext(name))) + goto fail; + + if (!(m->init = lt_dlsym(m->dl, "module_init"))) + goto fail; + + if (!(m->done = lt_dlsym(m->dl, "module_done"))) + goto fail; + + m->name = strdup(name); + m->argument = argument ? strdup(argument) : NULL; + m->userdata = NULL; + + assert(m->init); + if (m->init(c, m) < 0) + goto fail; + + if (!c->modules) + c->modules = idxset_new(NULL, NULL); + + assert(c->modules); + r = idxset_put(c->modules, m, &m->index); + assert(r >= 0 && m->index != IDXSET_INVALID); + return m; + +fail: + if (m) { + if (m->dl) + lt_dlclose(m->dl); + + free(m); + } + + return NULL; +} + +static void module_free(struct module *m) { + assert(m && m->done); + m->done(c, m); + + lt_dlcose(m->dl); + free(m->name); + free(m->argument); + free(m); +} + +void module_unload(struct core *c, struct module *m) { + struct module *m; + assert(c && index != IDXSET_INVALID); + + assert(c->modules); + if (!(m = idxset_remove_by_data(c->modules, m, NULL))) + return; + + module_free(m); +} + +void module_unload_by_index(struct core *c, guint32_t index) { + struct module *m; + assert(c && index != IDXSET_INVALID); + + assert(c->modules); + if (!(m = idxset_remove_by_index(c->modules, index))) + return; + + module_free(m); +} + + +void free_callback(void *p, void *userdata) { + struct module *m = p; + assert(m); + module_free(m); +} + +void module_unload_all(struct core *c) { + assert(c); + + if (!c->modules) + return; + + idxset_free(c->modules, free_callback, NULL); + c->modules = NULL; +} + diff --git a/src/module.h b/src/module.h new file mode 100644 index 00000000..d0dfa045 --- /dev/null +++ b/src/module.h @@ -0,0 +1,27 @@ +#ifndef foomodulehfoo +#define foomodulehfoo + +#include +#include + +#include "core.h" + +struct module { + char *name, *argument; + uint32_t index; + + lt_dlhandle *dl; + + int (*init)(struct core *c, struct module*m); + void (*done)(struct core *c, struct module*m); + + void *userdata; +}; + +struct module* module_load(struct core *c, const char *name, const char*argument); +void module_unload(struct core *c, struct module *m); +void module_unload_by_index(struct core *c, uint32_t index); + +void module_unload_all(struct core *c); + +#endif diff --git a/src/oss.c b/src/oss.c new file mode 100644 index 00000000..42e60360 --- /dev/null +++ b/src/oss.c @@ -0,0 +1,30 @@ +#include "module.h" + +struct userdata { + struct sink *sink; + struct source *source; + int fd; +}; + +int module_init(struct core *c, struct module*m) { + struct userdata *u; + assert(c && m); + + u = malloc(sizeof(struct userdata)); + assert(u); + memset(u, 0, sizeof(struct userdata)); + m->userdata = u; + + return 0; +} + +void module_done(struct core *c, struct module*m) { + struct userdata *u; + assert(c && m); + + u = m->userdata; + + sink_free(u->sink); + source_free(u->source); + free(u); +} diff --git a/src/outputstream.c b/src/outputstream.c new file mode 100644 index 00000000..ffec77da --- /dev/null +++ b/src/outputstream.c @@ -0,0 +1,41 @@ +#include +#include +#include + +#include "outputstream.h" + +struct output_stream* output_stream_new(struct source *s, struct sample_spec *spec, const char *name) { + struct output_stream *o; + int r; + assert(s && spec); + + o = malloc(sizeof(struct output_stream)); + assert(o); + o->name = name ? strdup(name) : NULL; + o->source = s; + o->spec = *spec; + + o->memblockq = memblockq_new(bytes_per_second(spec)*5, sample_size(spec)); + assert(o->memblockq); + + assert(s->core); + r = idxset_put(s->core->output_streams, o, &o->index); + assert(r == 0 && o->index != IDXSET_INVALID); + r = idxset_put(s->output_streams, o, NULL); + assert(r == 0); + + return o; +} + +void output_stream_free(struct output_stream* o) { + assert(o); + + memblockq_free(o->memblockq); + + assert(o->source && o->source->core); + idxset_remove_by_data(o->source->core->output_streams, o, NULL); + idxset_remove_by_data(o->source->output_streams, o, NULL); + + free(o->name); + free(o); +} diff --git a/src/outputstream.h b/src/outputstream.h new file mode 100644 index 00000000..41054341 --- /dev/null +++ b/src/outputstream.h @@ -0,0 +1,22 @@ +#ifndef foooutputstreamhfoo +#define foooutputstreamhfoo + +#include +#include "source.h" +#include "sample.h" +#include "memblockq.h" + +struct output_stream { + char *name; + uint32_t index; + + struct source *source; + struct sample_spec spec; + + struct memblockq *memblockq; +}; + +struct output_stream* output_stream_new(struct source *s, struct sample_spec *spec, const char *name); +void output_stream_free(struct output_stream* o); + +#endif diff --git a/src/packet.c b/src/packet.c new file mode 100644 index 00000000..086e4b2a --- /dev/null +++ b/src/packet.c @@ -0,0 +1,29 @@ +#include +#include + +#include "packet.h" + +struct packet* packet_new(uint32_t length) { + struct packet *p; + assert(length); + p = malloc(sizeof(struct packet)+length); + assert(p); + + p->ref = 1; + p->length = length; + return p; +} + +struct packet* packet_ref(struct packet *p) { + assert(p && p->ref >= 1); + p->ref++; + return p; +} + +void packet_unref(struct packet *p) { + assert(p && p->ref >= 1); + p->ref--; + + if (p->ref == 0) + free(p); +} diff --git a/src/packet.h b/src/packet.h new file mode 100644 index 00000000..781c0e66 --- /dev/null +++ b/src/packet.h @@ -0,0 +1,18 @@ +#ifndef foopackethfoo +#define foopackethfoo + +#include +#include + +struct packet { + unsigned ref; + size_t length; + uint8_t data[]; +}; + +struct packet* packet_new(uint32_t length); + +struct packet* packet_ref(struct packet *p); +void packet_unref(struct packet *p); + +#endif diff --git a/src/protocol-native-tcp.c b/src/protocol-native-tcp.c new file mode 100644 index 00000000..b33f3e15 --- /dev/null +++ b/src/protocol-native-tcp.c @@ -0,0 +1,19 @@ +#include "module.h" + +int module_init(struct core *c, struct module*m) { + struct socket_server *s; + assert(c && m); + + if (!(s = socket_server_new_ipv4(c->mainloop, INADDR_LOOPBACK, 4711))) + return -1; + + m->userdata = protocol_native_new(s); + assert(m->userdata); + return 0; +} + +void module_done(struct core *c, struct module*m) { + assert(c && m); + + protocol_native_free(m->userdata); +} diff --git a/src/protocol-native-unix.c b/src/protocol-native-unix.c new file mode 100644 index 00000000..a18965cd --- /dev/null +++ b/src/protocol-native-unix.c @@ -0,0 +1,27 @@ +#include "module.h" + +int module_init(struct core *c, struct module*m) { + struct fn[PATH_MAX]; + struct socket_server *s; + char *t; + assert(c && m); + + if (!(t = getenv("TMP"))) + if (!(t = getenv("TEMP"))) + t = "/tmp"; + + snprintf(fn, sizeof(fn), "%s/foosock", t); + + if (!(s = socket_server_new_unix(c->mainloop, fn))) + return -1; + + m->userdata = protocol_native_new(s); + assert(m->userdata); + return 0; +} + +void module_done(struct core *c, struct module*m) { + assert(c && m); + + protocol_native_free(m->userdata); +} diff --git a/src/protocol-native.c b/src/protocol-native.c new file mode 100644 index 00000000..bdb69355 --- /dev/null +++ b/src/protocol-native.c @@ -0,0 +1,49 @@ +#include "protocol-native.h" + +struct protocol_native { + struct socket_server*server; + struct idxset *connection; +}; + +struct stream_info { + guint32_t tag; + + union { + struct output_stream *output_stream; + struct input_stream *input_stream; + } +}; + +struct connection { + struct client *client; + struct serializer *serializer; + + +}; + +static void on_connection(struct socket_server *server, struct iochannel *io, void *userdata) { + struct protocol_native *p = userdata; + assert(server && io && p && p->server == server); + + +} + +struct protocol_native* protocol_native(struct socket_server *server) { + struct protocol_native *p; + assert(server); + + p = malloc(sizeof(struct protocol_native)); + assert(p); + + p->server = server; + socket_server_set_callback(p->server, callback, p); + + return p; +} + +void protocol_native_free(struct protocol_native *p) { + assert(p); + + socket_server_free(p->server); + free(p); +} diff --git a/src/protocol-native.h b/src/protocol-native.h new file mode 100644 index 00000000..bdad03b4 --- /dev/null +++ b/src/protocol-native.h @@ -0,0 +1,9 @@ +#ifndef fooprotocolnativehfoo +#define fooprotocolnativehfoo + +struct protocol_native; + +struct protocol_native* protocol_native(struct socket_server *server); +void protocol_native_free(struct protocol_native *n); + +#endif diff --git a/src/protocol-simple-tcp.c b/src/protocol-simple-tcp.c new file mode 100644 index 00000000..e71d7142 --- /dev/null +++ b/src/protocol-simple-tcp.c @@ -0,0 +1,24 @@ +#include +#include + +#include "module.h" +#include "socket-server.h" +#include "protocol-simple.h" + +int module_init(struct core *c, struct module*m) { + struct socket_server *s; + assert(c && m); + + if (!(s = socket_server_new_ipv4(c->mainloop, INADDR_LOOPBACK, 4712))) + return -1; + + m->userdata = protocol_simple_new(c, s, PROTOCOL_SIMPLE_PLAYBACK); + assert(m->userdata); + return 0; +} + +void module_done(struct core *c, struct module*m) { + assert(c && m); + + protocol_simple_free(m->userdata); +} diff --git a/src/protocol-simple.c b/src/protocol-simple.c new file mode 100644 index 00000000..3335bc14 --- /dev/null +++ b/src/protocol-simple.c @@ -0,0 +1,173 @@ +#include +#include +#include +#include +#include +#include + +#include "inputstream.h" +#include "outputstream.h" +#include "protocol-simple.h" +#include "client.h" + +struct connection { + struct protocol_simple *protocol; + struct iochannel *io; + struct input_stream *istream; + struct output_stream *ostream; + struct client *client; +}; + +struct protocol_simple { + struct core *core; + struct socket_server*server; + struct idxset *connections; + enum protocol_simple_mode mode; +}; + +#define BUFSIZE PIPE_BUF + +static void free_connection(void *data, void *userdata) { + struct connection *c = data; + assert(data); + + if (c->istream) + input_stream_free(c->istream); + if (c->ostream) + output_stream_free(c->ostream); + + client_free(c->client); + + iochannel_free(c->io); + free(c); +} + +static void io_callback(struct iochannel*io, void *userdata) { + struct connection *c = userdata; + assert(io && c); + + if (c->istream && iochannel_is_readable(io)) { + struct memchunk chunk; + ssize_t r; + + chunk.memblock = memblock_new(BUFSIZE); + assert(chunk.memblock); + + if ((r = iochannel_read(io, chunk.memblock->data, BUFSIZE)) <= 0) { + fprintf(stderr, "read(): %s\n", r == 0 ? "EOF" : strerror(errno)); + memblock_unref(chunk.memblock); + goto fail; + } + + chunk.memblock->length = r; + chunk.length = r; + chunk.index = 0; + + memblockq_push(c->istream->memblockq, &chunk, 0); + input_stream_notify(c->istream); + memblock_unref(chunk.memblock); + } + + if (c->ostream && iochannel_is_writable(io)) { + struct memchunk chunk; + ssize_t r; + + memblockq_peek(c->ostream->memblockq, &chunk); + assert(chunk.memblock && chunk.length); + + if ((r = iochannel_write(io, chunk.memblock->data+chunk.index, chunk.length)) < 0) { + fprintf(stderr, "write(): %s\n", strerror(errno)); + memblock_unref(chunk.memblock); + goto fail; + } + + memblockq_drop(c->ostream->memblockq, r); + memblock_unref(chunk.memblock); + } + + return; + +fail: + idxset_remove_by_data(c->protocol->connections, c, NULL); + free_connection(c, NULL); +} + +static void on_connection(struct socket_server*s, struct iochannel *io, void *userdata) { + struct protocol_simple *p = userdata; + struct connection *c = NULL; + assert(s && io && p); + + c = malloc(sizeof(struct connection)); + assert(c); + c->io = io; + c->istream = NULL; + c->ostream = NULL; + c->protocol = p; + + if (p->mode & PROTOCOL_SIMPLE_RECORD) { + struct source *source; + + if (!(source = core_get_default_source(p->core))) { + fprintf(stderr, "Failed to get default source.\n"); + goto fail; + } + + c->ostream = output_stream_new(source, &DEFAULT_SAMPLE_SPEC, c->client->name); + assert(c->ostream); + } + + if (p->mode & PROTOCOL_SIMPLE_PLAYBACK) { + struct sink *sink; + + if (!(sink = core_get_default_sink(p->core))) { + fprintf(stderr, "Failed to get default sink.\n"); + goto fail; + } + + c->istream = input_stream_new(sink, &DEFAULT_SAMPLE_SPEC, c->client->name); + assert(c->istream); + } + + c->client = client_new(p->core, "SIMPLE", "Client"); + assert(c->client); + + iochannel_set_callback(c->io, io_callback, c); + idxset_put(p->connections, c, NULL); + return; + +fail: + if (c) { + if (c->istream) + input_stream_free(c->istream); + if (c->ostream) + output_stream_free(c->ostream); + + iochannel_free(c->io); + free(c); + } +} + +struct protocol_simple* protocol_simple_new(struct core *core, struct socket_server *server, enum protocol_simple_mode mode) { + struct protocol_simple* p; + assert(core && server && mode <= PROTOCOL_SIMPLE_DUPLEX && mode > 0); + + p = malloc(sizeof(struct protocol_simple)); + assert(p); + p->core = core; + p->server = server; + p->connections = idxset_new(NULL, NULL); + p->mode = mode; + + socket_server_set_callback(p->server, on_connection, p); + + return p; +} + + +void protocol_simple_free(struct protocol_simple *p) { + assert(p); + + idxset_free(p->connections, free_connection, NULL); + socket_server_free(p->server); + free(p); +} diff --git a/src/protocol-simple.h b/src/protocol-simple.h new file mode 100644 index 00000000..f6210436 --- /dev/null +++ b/src/protocol-simple.h @@ -0,0 +1,17 @@ +#ifndef fooprotocolsimplehfoo +#define fooprotocolsimplehfoo + +#include "socket-server.h" + +struct protocol_simple; + +enum protocol_simple_mode { + PROTOCOL_SIMPLE_RECORD = 1, + PROTOCOL_SIMPLE_PLAYBACK = 2, + PROTOCOL_SIMPLE_DUPLEX = 3 +}; + +struct protocol_simple* protocol_simple_new(struct core *core, struct socket_server *server, enum protocol_simple_mode mode); +void protocol_simple_free(struct protocol_simple *n); + +#endif diff --git a/src/pstream.c b/src/pstream.c new file mode 100644 index 00000000..083ebc22 --- /dev/null +++ b/src/pstream.c @@ -0,0 +1,359 @@ +#include +#include + +#include "pstream.h" +#include "queue.h" + +enum pstream_descriptor_index { + PSTREAM_DESCRIPTOR_LENGTH, + PSTREAM_DESCRIPTOR_CHANNEL, + PSTREAM_DESCRIPTOR_DELTA, + PSTREAM_DESCRIPTOR_MAX +}; + +typedef uint32_t pstream_descriptor[PSTREAM_DESCRIPTOR_MAX]; + +#define PSTREAM_DESCRIPTOR_SIZE (PSTREAM_DESCRIPTOR_MAX*sizeof(uint32_t)) +#define FRAME_SIZE_MAX (1024*64) + +struct item_info { + enum { PSTREAM_ITEM_PACKET, PSTREAM_ITEM_MEMBLOCK } type; + + /* memblock info */ + struct memchunk chunk; + uint32_t channel; + int32_t delta; + + /* packet info */ + struct packet *packet; +}; + +struct pstream { + struct mainloop *mainloop; + struct mainloop_source *mainloop_source; + struct iochannel *io; + struct queue *send_queue; + + int dead; + + struct { + struct item_info* current; + pstream_descriptor descriptor; + void *data; + size_t index; + } write; + + void (*send_callback) (struct pstream *p, void *userdata); + void *send_callback_userdata; + + struct { + struct memblock *memblock; + struct packet *packet; + pstream_descriptor descriptor; + void *data; + size_t index; + } read; + + void (*recieve_packet_callback) (struct pstream *p, struct packet *packet, void *userdata); + void *recieve_packet_callback_userdata; + + void (*recieve_memblock_callback) (struct pstream *p, uint32_t channel, int32_t delta, struct memchunk *chunk, void *userdata); + void *recieve_memblock_callback_userdata; +}; + +static void do_write(struct pstream *p); +static void do_read(struct pstream *p); + +static void io_callback(struct iochannel*io, void *userdata) { + struct pstream *p = userdata; + assert(p && p->io == io); + do_write(p); + do_read(p); +} + +static void prepare_callback(struct mainloop_source *s, void*userdata) { + struct pstream *p = userdata; + assert(p && p->mainloop_source == s); + do_write(p); + do_read(p); +} + +struct pstream *pstream_new(struct mainloop *m, struct iochannel *io) { + struct pstream *p; + assert(io); + + p = malloc(sizeof(struct pstream)); + assert(p); + + p->io = io; + iochannel_set_callback(io, io_callback, p); + + p->dead = 0; + + p->mainloop = m; + p->mainloop_source = mainloop_source_new_prepare(m, prepare_callback, p); + mainloop_source_enable(p->mainloop_source, 0); + + p->send_queue = queue_new(); + assert(p->send_queue); + + p->write.current = NULL; + p->write.index = 0; + + p->read.memblock = NULL; + p->read.packet = NULL; + p->read.index = 0; + + p->send_callback = NULL; + p->send_callback_userdata = NULL; + + p->recieve_packet_callback = NULL; + p->recieve_packet_callback_userdata = NULL; + + p->recieve_memblock_callback = NULL; + p->recieve_memblock_callback_userdata = NULL; + + return p; +} + +static void item_free(void *item, void *p) { + struct item_info *i = item; + assert(i); + + if (i->type == PSTREAM_ITEM_PACKET) { + assert(i->chunk.memblock); + memblock_unref(i->chunk.memblock); + } else { + assert(i->type == PSTREAM_ITEM_MEMBLOCK); + assert(i->packet); + packet_unref(i->packet); + } + + free(i); +} + +void pstream_free(struct pstream *p) { + assert(p); + + iochannel_free(p->io); + queue_free(p->send_queue, item_free, NULL); + + if (p->write.current) + item_free(p->write.current, NULL); + + if (p->read.memblock) + memblock_unref(p->read.memblock); + + if (p->read.packet) + packet_unref(p->read.packet); + + mainloop_source_free(p->mainloop_source); + free(p); +} + +void pstream_set_send_callback(struct pstream*p, void (*callback) (struct pstream *p, void *userdata), void *userdata) { + assert(p && callback); + + p->send_callback = callback; + p->send_callback_userdata = userdata; +} + +void pstream_send_packet(struct pstream*p, struct packet *packet) { + struct item_info *i; + assert(p && packet); + + i = malloc(sizeof(struct item_info)); + assert(i); + i->type = PSTREAM_ITEM_PACKET; + i->packet = packet; + + queue_push(p->send_queue, i); + mainloop_source_enable(p->mainloop_source, 1); +} + +void pstream_send_memblock(struct pstream*p, uint32_t channel, int32_t delta, struct memchunk *chunk) { + struct item_info *i; + assert(p && channel && chunk); + + i = malloc(sizeof(struct item_info)); + assert(i); + i->type = PSTREAM_ITEM_MEMBLOCK; + i->chunk = *chunk; + i->channel = channel; + i->delta = delta; + + queue_push(p->send_queue, i); + mainloop_source_enable(p->mainloop_source, 1); +} + +void pstream_set_recieve_packet_callback(struct pstream *p, void (*callback) (struct pstream *p, struct packet *packet, void *userdata), void *userdata) { + assert(p && callback); + + p->recieve_packet_callback = callback; + p->recieve_packet_callback_userdata = userdata; +} + +void pstream_set_recieve_memblock_callback(struct pstream *p, void (*callback) (struct pstream *p, uint32_t channel, int32_t delta, struct memchunk *chunk, void *userdata), void *userdata) { + assert(p && callback); + + p->recieve_memblock_callback = callback; + p->recieve_memblock_callback_userdata = userdata; +} + +static void prepare_next_write_item(struct pstream *p) { + assert(p); + + if (!(p->write.current = queue_pop(p->send_queue))) + return; + + p->write.index = 0; + + if (p->write.current->type == PSTREAM_ITEM_PACKET) { + assert(p->write.current->packet); + p->write.data = p->write.current->packet->data; + p->write.descriptor[PSTREAM_DESCRIPTOR_LENGTH] = p->write.current->packet->length; + p->write.descriptor[PSTREAM_DESCRIPTOR_CHANNEL] = 0; + p->write.descriptor[PSTREAM_DESCRIPTOR_DELTA] = 0; + } else { + assert(p->write.current->type == PSTREAM_ITEM_MEMBLOCK && p->write.current->chunk.memblock); + p->write.data = p->write.current->chunk.memblock->data + p->write.current->chunk.index; + p->write.descriptor[PSTREAM_DESCRIPTOR_LENGTH] = p->write.current->chunk.length; + p->write.descriptor[PSTREAM_DESCRIPTOR_CHANNEL] = p->write.current->channel; + p->write.descriptor[PSTREAM_DESCRIPTOR_DELTA] = p->write.current->delta; + } +} + +static void do_write(struct pstream *p) { + void *d; + size_t l; + ssize_t r; + assert(p); + + mainloop_source_enable(p->mainloop_source, 0); + + if (p->dead || !iochannel_is_writable(p->io)) + return; + + if (!p->write.current) + prepare_next_write_item(p); + + if (!p->write.current) + return; + + assert(p->write.data); + + if (p->write.index < PSTREAM_DESCRIPTOR_SIZE) { + d = (void*) p->write.descriptor + p->write.index; + l = PSTREAM_DESCRIPTOR_SIZE - p->write.index; + } else { + d = (void*) p->write.data + p->write.index - PSTREAM_DESCRIPTOR_SIZE; + l = p->write.descriptor[PSTREAM_DESCRIPTOR_LENGTH] - p->write.index - PSTREAM_DESCRIPTOR_SIZE; + } + + if ((r = iochannel_write(p->io, d, l)) < 0) { + p->dead = 1; + return; + } + + p->write.index += r; + + if (p->write.index >= PSTREAM_DESCRIPTOR_SIZE+p->write.descriptor[PSTREAM_DESCRIPTOR_LENGTH]) { + assert(p->write.current); + item_free(p->write.current, (void *) 1); + p->write.current = NULL; + + if (p->send_callback && queue_is_empty(p->send_queue)) + p->send_callback(p, p->send_callback_userdata); + } +} + +static void do_read(struct pstream *p) { + void *d; + size_t l; + ssize_t r; + assert(p); + + mainloop_source_enable(p->mainloop_source, 0); + + if (p->dead || !iochannel_is_readable(p->io)) + return; + + if (p->read.index < PSTREAM_DESCRIPTOR_SIZE) { + d = (void*) p->read.descriptor + p->read.index; + l = PSTREAM_DESCRIPTOR_SIZE - p->read.index; + } else { + assert(p->read.data); + d = (void*) p->read.data + p->read.index - PSTREAM_DESCRIPTOR_SIZE; + l = p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH] - p->read.index - PSTREAM_DESCRIPTOR_SIZE; + } + + if ((r = iochannel_read(p->io, d, l)) <= 0) { + p->dead = 1; + return; + } + + p->read.index += r; + + if (p->read.index == PSTREAM_DESCRIPTOR_SIZE) { + /* Reading of frame descriptor complete */ + + /* Frame size too large */ + if (p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH] > FRAME_SIZE_MAX) { + p->dead = 1; + return; + } + + assert(!p->read.packet && !p->read.memblock); + + if (p->read.descriptor[PSTREAM_DESCRIPTOR_CHANNEL] == 0) { + /* Frame is a packet frame */ + p->read.packet = packet_new(p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH]); + assert(p->read.packet); + p->read.data = p->read.packet->data; + } else { + /* Frame is a memblock frame */ + p->read.memblock = memblock_new(p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH]); + assert(p->read.memblock); + p->read.data = p->read.memblock->data; + } + + } else if (p->read.index > PSTREAM_DESCRIPTOR_SIZE) { + /* Frame payload available */ + + if (p->read.memblock && p->recieve_memblock_callback) { /* Is this memblockd data? Than pass it to the user */ + size_t l; + + l = p->read.index - r < PSTREAM_DESCRIPTOR_SIZE ? p->read.index - PSTREAM_DESCRIPTOR_SIZE : r; + + if (l > 0) { + struct memchunk chunk; + + chunk.memblock = p->read.memblock; + chunk.index = p->read.index - PSTREAM_DESCRIPTOR_SIZE - l; + chunk.length = l; + + p->recieve_memblock_callback(p, p->read.descriptor[PSTREAM_DESCRIPTOR_CHANNEL], (int32_t) p->read.descriptor[PSTREAM_DESCRIPTOR_DELTA], &chunk, p->recieve_memblock_callback_userdata); + } + } + + /* Frame complete */ + if (p->read.index >= p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH] + PSTREAM_DESCRIPTOR_SIZE) { + if (p->read.memblock) { + assert(!p->read.packet); + + memblock_unref(p->read.memblock); + p->read.memblock = NULL; + } else { + assert(p->read.packet); + + if (p->recieve_packet_callback) + p->recieve_packet_callback(p, p->read.packet, p->recieve_packet_callback_userdata); + + packet_unref(p->read.packet); + p->read.packet = NULL; + } + + p->read.index = 0; + } + } +} diff --git a/src/pstream.h b/src/pstream.h new file mode 100644 index 00000000..c0b57496 --- /dev/null +++ b/src/pstream.h @@ -0,0 +1,22 @@ +#ifndef foopstreamhfoo +#define foopstreamhfoo + +#include + +#include "packet.h" +#include "memblock.h" +#include "iochannel.h" + +struct pstream; + +struct pstream* pstream_new(struct mainloop *m, struct iochannel *io); +void pstream_free(struct pstream*p); + +void pstream_set_send_callback(struct pstream*p, void (*callback) (struct pstream *p, void *userdata), void *userdata); +void pstream_send_packet(struct pstream*p, struct packet *packet); +void pstream_send_memblock(struct pstream*p, uint32_t channel, int32_t delta, struct memchunk *chunk); + +void pstream_set_recieve_packet_callback(struct pstream *p, void (*callback) (struct pstream *p, struct packet *packet, void *userdata), void *userdata); +void pstream_set_recieve_memblock_callback(struct pstream *p, void (*callback) (struct pstream *p, uint32_t channel, int32_t delta, struct memchunk *chunk, void *userdata), void *userdata); + +#endif diff --git a/src/queue.c b/src/queue.c new file mode 100644 index 00000000..90823ae6 --- /dev/null +++ b/src/queue.c @@ -0,0 +1,77 @@ +#include +#include + +#include "queue.h" + +struct queue_entry { + struct queue_entry *next; + void *data; +}; + +struct queue { + struct queue_entry *front, *back; + unsigned length; +}; + +struct queue* queue_new(void) { + struct queue *q = malloc(sizeof(struct queue)); + assert(q); + q->front = q->back = NULL; + q->length = 0; + return q; +} + +void queue_free(struct queue* q, void (*destroy)(void *p, void *userdata), void *userdata) { + struct queue_entry *e; + assert(q); + + e = q->front; + while (e) { + struct queue_entry *n = e->next; + + if (destroy) + destroy(e->data, userdata); + + free(e); + e = n; + } + + free(q); +} + +void queue_push(struct queue *q, void *p) { + struct queue_entry *e; + + e = malloc(sizeof(struct queue_entry)); + + e->data = p; + e->next = NULL; + + if (q->back) + q->back->next = e; + else { + assert(!q->front); + q->front = e; + } + + q->back = e; + q->length++; +} + +void* queue_pop(struct queue *q) { + void *p; + struct queue_entry *e; + assert(q); + + if (!(e = q->front)) + return NULL; + + q->front = e->next; + if (q->back == e) + q->back = NULL; + + p = e->data; + free(e); + + return p; +} diff --git a/src/queue.h b/src/queue.h new file mode 100644 index 00000000..6b371a81 --- /dev/null +++ b/src/queue.h @@ -0,0 +1,13 @@ +#ifndef fooqueuehfoo +#define fooqueuehfoo + +struct queue; + +struct queue* queue_new(void); +void queue_free(struct queue* q, void (*destroy)(void *p, void *userdata), void *userdata); +void queue_push(struct queue *q, void *p); +void* queue_pop(struct queue *q); + +int queue_is_empty(struct queue *q); + +#endif diff --git a/src/sample.c b/src/sample.c new file mode 100644 index 00000000..74a54937 --- /dev/null +++ b/src/sample.c @@ -0,0 +1,80 @@ +#include +#include + +#include "sample.h" + +struct sample_spec default_sample_spec = { + .format = SAMPLE_S16NE, + .rate = 44100, + .channels = 2 +}; + +struct memblock *silence(struct memblock* b, struct sample_spec *spec) { + char c; + assert(b && spec); + memblock_assert_exclusive(b); + + switch (spec->format) { + case SAMPLE_U8: + c = 127; + break; + case SAMPLE_S16LE: + case SAMPLE_S16BE: + case SAMPLE_FLOAT32: + c = 0; + break; + case SAMPLE_ALAW: + case SAMPLE_ULAW: + c = 80; + break; + } + + memset(b->data, c, b->length); + return b; +} + +void add_clip(struct memchunk *target, struct memchunk *chunk, struct sample_spec *spec) { + int16_t *p, *d; + size_t i; + assert(target && target->memblock && chunk && chunk->memblock && spec); + assert(spec->format == SAMPLE_S16NE); + assert((target->length & 1) == 0); + + d = target->memblock->data + target->index; + p = chunk->memblock->data + chunk->index; + + for (i = 0; i < target->length && i < chunk->length; i++) { + int32_t r = (int32_t) *d + (int32_t) *p; + if (r < -0x8000) r = 0x8000; + if (r > 0x7FFF) r = 0x7FFF; + *d = (int16_t) r; + } +} + +size_t sample_size(struct sample_spec *spec) { + assert(spec); + size_t b; + + switch (spec->format) { + case SAMPLE_U8: + case SAMPLE_ULAW: + case SAMPLE_ALAW: + b = 1; + break; + case SAMPLE_S16LE: + case SAMPLE_S16BE: + b = 2; + break; + case SAMPLE_FLOAT32: + b = 4; + break; + } + + return b * spec->channels; +} + +size_t bytes_per_second(struct sample_spec *spec) { + assert(spec); + return spec->rate*sample_size(spec); +} + diff --git a/src/sample.h b/src/sample.h new file mode 100644 index 00000000..ecbe33f2 --- /dev/null +++ b/src/sample.h @@ -0,0 +1,35 @@ +#ifndef foosamplehfoo +#define foosamplehfoo + +#include + +#include "memblock.h" + +enum sample_format { + SAMPLE_U8, + SAMPLE_ALAW, + SAMPLE_ULAW, + SAMPLE_S16LE, + SAMPLE_S16BE, + SAMPLE_FLOAT32 +}; + +#define SAMPLE_S16NE SAMPLE_S16LE + +struct sample_spec { + enum sample_format format; + uint32_t rate; + uint32_t channels; +}; + +#define DEFAULT_SAMPLE_SPEC default_sample_spec + +extern struct sample_spec default_sample_spec; + +struct memblock *silence(struct memblock* b, struct sample_spec *spec); +void add_clip(struct memchunk *target, struct memchunk *chunk, struct sample_spec *spec); + +size_t bytes_per_second(struct sample_spec *spec); +size_t sample_size(struct sample_spec *spec); + +#endif diff --git a/src/sink-pipe.c b/src/sink-pipe.c new file mode 100644 index 00000000..4a8348f8 --- /dev/null +++ b/src/sink-pipe.c @@ -0,0 +1,155 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iochannel.h" +#include "sink.h" +#include "module.h" + +struct userdata { + struct sink *sink; + struct iochannel *io; + struct core *core; + struct mainloop_source *mainloop_source; + + struct memchunk memchunk; +}; + +static void do_write(struct userdata *u) { + ssize_t r; + assert(u); + + mainloop_source_enable(u->mainloop_source, 0); + + if (!iochannel_is_writable(u->io)) + return; + + if (!u->memchunk.length) + if (sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0) + return; + + assert(u->memchunk.memblock && u->memchunk.length); + + if ((r = iochannel_write(u->io, u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { + fprintf(stderr, "write() failed: %s\n", strerror(errno)); + return; + } + + u->memchunk.index += r; + u->memchunk.length -= r; + + if (u->memchunk.length <= 0) { + memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + } +} + +static void notify_callback(struct sink*s, void *userdata) { + struct userdata *u = userdata; + assert(u); + + if (iochannel_is_writable(u->io)) + mainloop_source_enable(u->mainloop_source, 1); +} + +static void prepare_callback(struct mainloop_source *src, void *userdata) { + struct userdata *u = userdata; + assert(u); + do_write(u); +} + +static void io_callback(struct iochannel *io, void*userdata) { + struct userdata *u = userdata; + assert(u); + do_write(u); +} + +int module_init(struct core *c, struct module*m) { + struct userdata *u = NULL; + struct stat st; + struct sink *sink; + char *p; + int fd = -1; + const static struct sample_spec ss = { + .format = SAMPLE_S16NE, + .rate = 44100, + .channels = 2, + }; + assert(c && m); + + mkfifo((p = m->argument ? m->argument : "/tmp/musicfifo"), 0777); + + if ((fd = open(p, O_RDWR) < 0)) { + fprintf(stderr, "open('%s'): %s\n", p, strerror(errno)); + goto fail; + } + + if (fstat(fd, &st) < 0) { + fprintf(stderr, "fstat('%s'): %s\n", p, strerror(errno)); + goto fail; + } + + if (!S_ISFIFO(st.st_mode)) { + fprintf(stderr, "'%s' is not a FIFO\n", p); + goto fail; + } + + if (!(sink = sink_new(c, "fifo", &ss))) { + fprintf(stderr, "Failed to allocate new sink!\n"); + goto fail; + } + + u = malloc(sizeof(struct userdata)); + assert(u); + + u->core = c; + u->sink = sink; + sink_set_notify_callback(sink, notify_callback, u); + + u->io = iochannel_new(c->mainloop, -1, fd); + assert(u->io); + iochannel_set_callback(u->io, io_callback, u); + + u->memchunk.memblock = NULL; + u->memchunk.length = 0; + + u->mainloop_source = mainloop_source_new_prepare(c->mainloop, prepare_callback, u); + assert(u->mainloop_source); + mainloop_source_enable(u->mainloop_source, 0); + + m->userdata = u; + + + return 0; + +fail: + if (fd >= 0) + close(fd); + + if (u) + free(u); + + return -1; +} + +void module_done(struct core *c, struct module*m) { + struct userdata *u; + assert(c && m); + + u = m->userdata; + assert(u); + + if (u->memchunk.memblock) + memblock_unref(u->memchunk.memblock); + + sink_free(u->sink); + iochannel_free(u->io); + mainloop_source_free(u->mainloop_source); + free(u); +} diff --git a/src/sink.c b/src/sink.c new file mode 100644 index 00000000..ac387c78 --- /dev/null +++ b/src/sink.c @@ -0,0 +1,217 @@ +#include +#include +#include +#include + +#include "sink.h" +#include "inputstream.h" + +struct sink* sink_new(struct core *core, const char *name, const struct sample_spec *spec) { + struct sink *s; + char *n = NULL; + int r; + assert(core && spec); + + s = malloc(sizeof(struct sink)); + assert(s); + + s->name = name ? strdup(name) : NULL; + r = idxset_put(core->sinks, s, &s->index); + assert(s->index != IDXSET_INVALID && r >= 0); + + s->core = core; + s->sample_spec = *spec; + s->input_streams = idxset_new(NULL, NULL); + + if (name) { + n = malloc(strlen(name)+9); + sprintf(n, "%s_monitor", name); + } + + s->monitor_source = source_new(core, n, spec); + s->volume = 0xFF; + + s->notify_callback = NULL; + s->userdata = NULL; + + return s; +} + +void sink_free(struct sink *s) { + struct input_stream *i; + assert(s); + + idxset_remove_by_data(s->core->sinks, s, NULL); + source_free(s->monitor_source); + + while ((i = idxset_rrobin(s->input_streams, NULL))) + input_stream_free(i); + + free(s->name); + free(s); +} + +struct pass1_info { + size_t maxlength; + unsigned count; + struct input_stream *last_input_stream; +}; + +static int get_max_length(void *p, uint32_t index, int *del, void*userdata) { + struct memchunk chunk; + struct pass1_info *info = userdata; + struct input_stream*i = p; + assert(info && i); + + if (memblockq_peek(i->memblockq, &chunk) != 0) + return 0; + + assert(chunk.length); + + if (info->maxlength > chunk.length) + info->maxlength = chunk.length; + + info->count++; + info->last_input_stream = i; + + return 0; +} + +struct pass2_info { + struct memchunk *chunk; + struct sample_spec *spec; +}; + +static int do_mix(void *p, uint32_t index, int *del, void*userdata) { + struct memchunk chunk; + struct pass2_info *info = userdata; + struct input_stream*i = p; + assert(info && info->chunk && info->chunk->memblock && i && info->spec); + + if (memblockq_peek(i->memblockq, &chunk) != 0) + return 0; + + memblock_assert_exclusive(info->chunk->memblock); + assert(chunk.length && chunk.length <= info->chunk->memblock->length - info->chunk->index); + + add_clip(info->chunk, &chunk, info->spec); + return 0; +} + +int sink_render_into(struct sink*s, struct memblock *target, struct memchunk *result) { + struct pass1_info pass1_info; + struct pass2_info pass2_info; + assert(s && target && result); + memblock_assert_exclusive(target); + + /* Calculate how many bytes to mix */ + pass1_info.maxlength = target->length; + pass1_info.count = 0; + + idxset_foreach(s->input_streams, get_max_length, &pass1_info); + assert(pass1_info.maxlength); + + /* No data to mix */ + if (pass1_info.count == 0) + return -1; + + /* A shortcut if only a single input stream is connected */ + if (pass1_info.count == 1) { + struct input_stream *i = pass1_info.last_input_stream; + struct memchunk chunk; + size_t l; + + assert(i); + + if (memblockq_peek(i->memblockq, &chunk) != 0) + return -1; + + l = target->length < chunk.length ? target->length : chunk.length; + memcpy(target->data, result->memblock+result->index, l); + target->length = l; + memblock_unref(chunk.memblock); + memblockq_drop(i->memblockq, l); + + result->memblock = target; + result->length = l; + result->index = 0; + return 0; + } + + /* Do the real mixing */ + result->memblock = silence(target, &s->sample_spec); + result->index = 0; + result->length = pass1_info.maxlength; + pass2_info.chunk = result; + pass2_info.spec = &s->sample_spec; + idxset_foreach(s->input_streams, do_mix, &pass2_info); + + assert(s->monitor_source); + source_post(s->monitor_source, result); + + return 0; +} + +int sink_render(struct sink*s, size_t length, struct memchunk *result) { + struct pass1_info pass1_info; + struct pass2_info pass2_info; + assert(s && result); + + if (!length) + length = (size_t) -1; + + /* Calculate how many bytes to mix */ + pass1_info.maxlength = length; + pass1_info.count = 0; + + idxset_foreach(s->input_streams, get_max_length, &pass1_info); + assert(pass1_info.maxlength); + + /* No data to mix */ + if (pass1_info.count == 0) + return -1; + + if (pass1_info.count == 1) { + struct input_stream *i = pass1_info.last_input_stream; + size_t l; + + assert(i); + + if (memblockq_peek(i->memblockq, result) != 0) + return -1; + + l = length < result->length ? length : result->length; + result->length = l; + memblockq_drop(i->memblockq, l); + return 0; + } + + /* Do the mixing */ + result->memblock = silence(memblock_new(result->length), &s->sample_spec); + result->index = 0; + result->length = pass1_info.maxlength; + pass2_info.chunk = result; + pass2_info.spec = &s->sample_spec; + idxset_foreach(s->input_streams, do_mix, &pass2_info); + + assert(s->monitor_source); + + source_post(s->monitor_source, result); + return 0; +} + +void sink_notify(struct sink*s) { + assert(s); + + if (s->notify_callback) + s->notify_callback(s, s->userdata); +} + +void sink_set_notify_callback(struct sink *s, void (*notify_callback)(struct sink*sink, void *userdata), void *userdata) { + assert(s && notify_callback); + + s->notify_callback = notify_callback; + s->userdata = userdata; +} + + diff --git a/src/sink.h b/src/sink.h new file mode 100644 index 00000000..a6f98005 --- /dev/null +++ b/src/sink.h @@ -0,0 +1,38 @@ +#ifndef foosinkhfoo +#define foosinkhfoo + +struct sink; + +#include + +#include "core.h" +#include "sample.h" +#include "idxset.h" +#include "source.h" + +struct sink { + char *name; + uint32_t index; + + struct core *core; + struct sample_spec sample_spec; + struct idxset *input_streams; + + struct source *monitor_source; + + uint8_t volume; + + void (*notify_callback)(struct sink*sink, void *userdata); + void *userdata; +}; + +struct sink* sink_new(struct core *core, const char *name, const struct sample_spec *spec); +void sink_free(struct sink* s); + +int sink_render(struct sink*s, size_t length, struct memchunk *result); +int sink_render_into(struct sink*s, struct memblock *target, struct memchunk *result); + +void sink_notify(struct sink*s); +void sink_set_notify_callback(struct sink *s, void (*notify_callback)(struct sink*sink, void *userdata), void *userdata); + +#endif diff --git a/src/socket-server.c b/src/socket-server.c new file mode 100644 index 00000000..2a1db9a0 --- /dev/null +++ b/src/socket-server.c @@ -0,0 +1,157 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "socket-server.h" + +struct socket_server { + int fd; + char *filename; + + void (*on_connection)(struct socket_server*s, struct iochannel *io, void *userdata); + void *userdata; + + struct mainloop_source *mainloop_source; +}; + +static void callback(struct mainloop_source*src, int fd, enum mainloop_io_event event, void *userdata) { + struct socket_server *s = userdata; + struct iochannel *io; + int nfd; + assert(src && fd >= 0 && fd == s->fd && event == MAINLOOP_IO_EVENT_IN && s); + + if ((nfd = accept(fd, NULL, NULL)) < 0) { + fprintf(stderr, "accept(): %s\n", strerror(errno)); + return; + } + + if (!s->on_connection) { + close(nfd); + return; + } + + io = iochannel_new(mainloop_source_get_mainloop(src), nfd, nfd); + assert(io); + s->on_connection(s, io, s->userdata); +} + +struct socket_server* socket_server_new(struct mainloop *m, int fd) { + struct socket_server *s; + assert(m && fd >= 0); + + s = malloc(sizeof(struct socket_server)); + assert(s); + s->fd = fd; + s->filename = NULL; + s->on_connection = NULL; + s->userdata = NULL; + + s->mainloop_source = mainloop_source_new_io(m, fd, MAINLOOP_IO_EVENT_IN, callback, s); + assert(s->mainloop_source); + + return s; +} + +struct socket_server* socket_server_new_unix(struct mainloop *m, const char *filename) { + int fd = -1; + struct sockaddr_un sa; + struct socket_server *s; + + assert(m && filename); + + if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "socket(): %s\n", strerror(errno)); + goto fail; + } + + sa.sun_family = AF_LOCAL; + strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); + sa.sun_path[sizeof(sa.sun_path) - 1] = 0; + + if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) { + fprintf(stderr, "bind(): %s\n", strerror(errno)); + goto fail; + } + + if (listen(fd, 5) < 0) { + fprintf(stderr, "listen(): %s\n", strerror(errno)); + goto fail; + } + + s = socket_server_new(m, fd); + assert(s); + + s->filename = strdup(filename); + assert(s->filename); + + return s; + +fail: + if (fd >= 0) + close(fd); + + return NULL; +} + +struct socket_server* socket_server_new_ipv4(struct mainloop *m, uint32_t address, uint16_t port) { + int fd = -1; + struct sockaddr_in sa; + + assert(m && port); + + if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "socket(): %s\n", strerror(errno)); + goto fail; + } + + sa.sin_family = AF_INET; + sa.sin_port = htons(port); + sa.sin_addr.s_addr = htonl(address); + + if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { + fprintf(stderr, "bind(): %s\n", strerror(errno)); + goto fail; + } + + if (listen(fd, 5) < 0) { + fprintf(stderr, "listen(): %s\n", strerror(errno)); + goto fail; + } + + return socket_server_new(m, fd); + +fail: + if (fd >= 0) + close(fd); + + return NULL; +} + +void socket_server_free(struct socket_server*s) { + assert(s); + close(s->fd); + + if (s->filename) { + unlink(s->filename); + free(s->filename); + } + + mainloop_source_free(s->mainloop_source); + + free(s); +} + +void socket_server_set_callback(struct socket_server*s, void (*on_connection)(struct socket_server*s, struct iochannel *io, void *userdata), void *userdata) { + assert(s); + + s->on_connection = on_connection; + s->userdata = userdata; +} diff --git a/src/socket-server.h b/src/socket-server.h new file mode 100644 index 00000000..4814fc62 --- /dev/null +++ b/src/socket-server.h @@ -0,0 +1,18 @@ +#ifndef foosocketserverhfoo +#define foosocketserverhfoo + +#include +#include "mainloop.h" +#include "iochannel.h" + +struct socket_server; + +struct socket_server* socket_server_new(struct mainloop *m, int fd); +struct socket_server* socket_server_new_unix(struct mainloop *m, const char *filename); +struct socket_server* socket_server_new_ipv4(struct mainloop *m, uint32_t address, uint16_t port); + +void socket_server_free(struct socket_server*s); + +void socket_server_set_callback(struct socket_server*s, void (*on_connection)(struct socket_server*s, struct iochannel *io, void *userdata), void *userdata); + +#endif diff --git a/src/source.c b/src/source.c new file mode 100644 index 00000000..2f34c461 --- /dev/null +++ b/src/source.c @@ -0,0 +1,58 @@ +#include +#include +#include + +#include "source.h" +#include "outputstream.h" + +struct source* source_new(struct core *core, const char *name, const struct sample_spec *spec) { + struct source *s; + int r; + assert(core && spec); + + s = malloc(sizeof(struct source)); + assert(s); + + s->name = name ? strdup(name) : NULL; + r = idxset_put(core->sources, s, &s->index); + assert(s->index != IDXSET_INVALID && r >= 0); + + s->core = core; + s->sample_spec = *spec; + s->output_streams = idxset_new(NULL, NULL); + + s->link_change_callback = NULL; + s->userdata = NULL; + + return s; +} + +static void do_free(void *p, void *userdata) { + struct output_stream *o = p; + assert(o); + output_stream_free(o); +}; + +void source_free(struct source *s) { + assert(s); + + idxset_remove_by_data(s->core->sources, s, NULL); + idxset_free(s->output_streams, do_free, NULL); + free(s->name); + free(s); +} + +static int do_post(void *p, uint32_t index, int *del, void*userdata) { + struct memchunk *chunk = userdata; + struct output_stream *o = p; + assert(o && o->memblockq && index && del && chunk); + + memblockq_push(o->memblockq, chunk, 0); + return 0; +} + +void source_post(struct source*s, struct memchunk *chunk) { + assert(s && chunk); + + idxset_foreach(s->output_streams, do_post, chunk); +} diff --git a/src/source.h b/src/source.h new file mode 100644 index 00000000..3beb3f96 --- /dev/null +++ b/src/source.h @@ -0,0 +1,30 @@ +#ifndef foosourcehfoo +#define foosourcehfoo + +struct source; + +#include +#include "core.h" +#include "sample.h" +#include "idxset.h" +#include "memblock.h" + +struct source { + char *name; + uint32_t index; + + struct core *core; + struct sample_spec sample_spec; + struct idxset *output_streams; + + void (*link_change_callback)(struct source*source, void *userdata); + void *userdata; +}; + +struct source* source_new(struct core *core, const char *name, const struct sample_spec *spec); +void source_free(struct source *s); + +/* Pass a new memory block to all output streams */ +void source_post(struct source*s, struct memchunk *b); + +#endif diff --git a/src/strbuf.c b/src/strbuf.c new file mode 100644 index 00000000..7c8b965d --- /dev/null +++ b/src/strbuf.c @@ -0,0 +1,122 @@ +#ifndef foostrbufhfoo +#define foostrbufhfoo + +#include +#include +#include +#include +#include +#include + +struct chunk { + struct chunk *next; + char text[]; +}; + +struct strbuf { + size_t length; + struct chunk *head, *tail; +}; + +struct strbuf *strbuf_new(void) { + struct strbuf *sb = malloc(sizeof(struct strbuf)); + assert(sb); + sb->length = 0; + sb->head = sb->tail = NULL; + return sb; +} + +void strbuf_free(struct strbuf *sb) { + assert(sb); + while (sb->head) { + struct chunk *c = sb->head; + sb->head = sb->head->next; + free(c); + } + + free(sb); +} + +char *strbuf_tostring(struct strbuf *sb) { + char *t, *e; + struct chunk *c; + assert(sb); + + t = malloc(sb->length+1); + assert(t); + + e = t; + *e = 0; + for (c = sb->head; c; c = c->next) { + strcpy(e, c->text); + e = strchr(e, 0); + } + + return t; +} + +void strbuf_puts(struct strbuf *sb, const char *t) { + struct chunk *c; + size_t l; + assert(sb && t); + + l = strlen(t); + c = malloc(sizeof(struct chunk)+l); + assert(c); + + c->next = NULL; + strcpy(c->text, t); + + if (sb->tail) { + assert(sb->head); + sb->tail->next = c; + } else { + assert(!sb->head); + sb->head = c; + } + + sb->tail = c; + sb->length += l; +} + +int strbuf_printf(struct strbuf *sb, const char *format, ...) { + int r, size = 100; + struct chunk *c = NULL; + + assert(sb); + + for(;;) { + va_list ap; + + c = realloc(c, sizeof(struct chunk)+size); + assert(c); + + va_start(ap, format); + r = vsnprintf(c->text, size, format, ap); + va_end(ap); + + if (r > -1 && r < size) { + c->next = NULL; + + if (sb->tail) { + assert(sb->head); + sb->tail->next = c; + } else { + assert(!sb->head); + sb->head = c; + } + + sb->tail = c; + sb->length += r; + + return r; + } + + if (r > -1) /* glibc 2.1 */ + size = r+1; + else /* glibc 2.0 */ + size *= 2; + } +} + +#endif diff --git a/src/strbuf.h b/src/strbuf.h new file mode 100644 index 00000000..6ad582a3 --- /dev/null +++ b/src/strbuf.h @@ -0,0 +1,13 @@ +#ifndef foostrbufhfoo +#define foostrbufhfoo + +struct strbuf; + +struct strbuf *strbuf_new(void); +void strbuf_free(struct strbuf *sb); +char *strbuf_tostring(struct strbuf *sb); + +int strbuf_printf(struct strbuf *sb, const char *format, ...); +void strbuf_puts(struct strbuf *sb, const char *t); + +#endif -- cgit From a5daff7859c3a8904cb379c59f3cefbaae4f57f2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 10 Jun 2004 23:22:16 +0000 Subject: make it compile git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@4 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/module.c | 15 +++++++++------ src/module.h | 3 ++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/module.c b/src/module.c index bcd0b6c0..94a43124 100644 --- a/src/module.c +++ b/src/module.c @@ -1,10 +1,12 @@ #include #include +#include #include "module.h" struct module* module_load(struct core *c, const char *name, const char *argument) { struct module *m = NULL; + int r; assert(c && name); @@ -23,6 +25,7 @@ struct module* module_load(struct core *c, const char *name, const char *argumen m->name = strdup(name); m->argument = argument ? strdup(argument) : NULL; m->userdata = NULL; + m->core = c; assert(m->init); if (m->init(c, m) < 0) @@ -30,6 +33,7 @@ struct module* module_load(struct core *c, const char *name, const char *argumen if (!c->modules) c->modules = idxset_new(NULL, NULL); + assert(c->modules); r = idxset_put(c->modules, m, &m->index); @@ -48,18 +52,17 @@ fail: } static void module_free(struct module *m) { - assert(m && m->done); - m->done(c, m); + assert(m && m->done && m->core); + m->done(m->core, m); - lt_dlcose(m->dl); + lt_dlclose(m->dl); free(m->name); free(m->argument); free(m); } void module_unload(struct core *c, struct module *m) { - struct module *m; - assert(c && index != IDXSET_INVALID); + assert(c && m); assert(c->modules); if (!(m = idxset_remove_by_data(c->modules, m, NULL))) @@ -68,7 +71,7 @@ void module_unload(struct core *c, struct module *m) { module_free(m); } -void module_unload_by_index(struct core *c, guint32_t index) { +void module_unload_by_index(struct core *c, uint32_t index) { struct module *m; assert(c && index != IDXSET_INVALID); diff --git a/src/module.h b/src/module.h index d0dfa045..4ecef86e 100644 --- a/src/module.h +++ b/src/module.h @@ -7,10 +7,11 @@ #include "core.h" struct module { + struct core *core; char *name, *argument; uint32_t index; - lt_dlhandle *dl; + lt_dlhandle dl; int (*init)(struct core *c, struct module*m); void (*done)(struct core *c, struct module*m); -- cgit From 9e3ad2380a28a7473a1dfa9ae41697ebacfd85cc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Jun 2004 00:33:43 +0000 Subject: autoconf git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@5 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 23 +++++++++++++++++++++++ bootstrap.sh | 39 +++++++++++++++++++++++++++++++++++++++ configure.ac | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/Makefile | 10 ---------- src/Makefile.am | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 7 +++++++ src/sample.c | 4 ++-- 7 files changed, 175 insertions(+), 12 deletions(-) create mode 100644 Makefile.am create mode 100755 bootstrap.sh create mode 100644 configure.ac delete mode 100644 src/Makefile create mode 100644 src/Makefile.am diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..7266cba5 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,23 @@ +# $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + +EXTRA_DIST = bootstrap.sh +SUBDIRS=src + +distcleancheck: + @: diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 00000000..f26ceb15 --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# $Id$ + +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + +if [ "x$1" = "xam" ] ; then + set -ex + automake -a -c --foreign + ./config.status +else + set -ex + + rm -rf autom4te.cache + rm -f config.cache + + aclocal + libtoolize -c --force + autoheader + automake -a -c + autoconf -Wall + + ./configure --sysconfdir=/etc "$@" + + make clean +fi diff --git a/configure.ac b/configure.ac new file mode 100644 index 00000000..de1a94ff --- /dev/null +++ b/configure.ac @@ -0,0 +1,49 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +# $Id$ + +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + +AC_PREREQ(2.57) +AC_INIT([polypaudio],[0.0],[mzcbylcnhqvb (at) 0pointer (dot) de]) +AC_CONFIG_SRCDIR([src/main.c]) +AC_CONFIG_HEADERS([config.h]) +AM_INIT_AUTOMAKE([foreign -Wall]) + +AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/polypaudio/]) + +if type -p stow > /dev/null && test -d /usr/local/stow ; then + AC_MSG_NOTICE([*** Found /usr/local/stow: default install prefix set to /usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION} ***]) + ac_default_prefix="/usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION}" +fi + +# Checks for programs. +AC_PROG_CC +AC_LIBLTDL_INSTALLABLE +AC_SUBST(INCLTDL) +AC_SUBST(LIBLTDL) +AC_LIBTOOL_DLOPEN +AC_PROG_LIBTOOL + +# If using GCC specifiy some additional parameters +if test "x$GCC" = "xyes" ; then + CFLAGS="$CFLAGS -pipe -Wall" +fi + +AC_CONFIG_FILES([Makefile src/Makefile]) +AC_OUTPUT diff --git a/src/Makefile b/src/Makefile deleted file mode 100644 index 366e84e6..00000000 --- a/src/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -CFLAGS=-Wall -pipe -ansi -D_GNU_SOURCE - -all: idxset.o queue.o strbuf.o mainloop.o iochannel.o packet.o \ - memblock.o sample.o socket-server.o memblockq.o client.o \ - core.o main.o outputstream.o inputstream.o source.o sink.o \ - pstream.o protocol-simple.o protocol-simple-tcp.o sink-pipe.o \ - module.o - -clean: - rm -f *.o diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 00000000..c64babb3 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,55 @@ +# $Id: Makefile.am 27 2003-10-22 22:34:06Z lennart $ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + +AM_CFLAGS=-ansi -D_GNU_SOURCE + +bin_PROGRAMS = polypaudio + +pkglib_LTLIBRARIES=protocol-simple.la protocol-simple-tcp.la \ + socket-server.la sink-pipe.la pstream.la iochannel.la packet.la + +polypaudio_SOURCES = idxset.c queue.c strbuf.c mainloop.c \ + memblock.c sample.c memblockq.c client.c \ + core.c main.c outputstream.c inputstream.c source.c sink.c \ + module.c +polypaudio_INCLUDES = $(INCLTDL) +polypaudio_LDADD = $(LIBLTDL) +polypaudio_LDFLAGS=-export-dynamic + +protocol_simple_la_SOURCES = protocol-simple.c +protocol_simple_la_LDFLAGS = -module -avoid-version + +protocol_simple_tcp_la_SOURCES = protocol-simple-tcp.c +protocol_simple_tcp_la_LDFLAGS = -module -avoid-version +protocol_simple_tcp_la_LIBADD = protocol-simple.la socket-server.la + +socket_server_la_SOURCES = socket-server.c +socket_server_la_LDFLAGS = -module -avoid-version + +sink_pipe_la_SOURCES = sink-pipe.c +sink_pipe_la_LDFLAGS = -module -avoid-version + +pstream_la_SOURCES = pstream.c +pstream_la_LDFLAGS = -module -avoid-version + +iochannel_la_SOURCES = pstream.c +iochannel_la_LDFLAGS = -module -avoid-version + +packet_la_SOURCES = pstream.c +packet_la_LDFLAGS = -module -avoid-version + diff --git a/src/main.c b/src/main.c index 3104c264..0785b39c 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,6 @@ #include #include +#include #include "core.h" #include "mainloop.h" @@ -8,7 +9,11 @@ int main(int argc, char *argv[]) { struct mainloop *m; struct core *c; + int r; + r = lt_dlinit(); + assert(r == 0); + m = mainloop_new(); assert(m); c = core_new(m); @@ -21,6 +26,8 @@ int main(int argc, char *argv[]) { core_free(c); mainloop_free(m); + + lt_dlexit(); return 0; } diff --git a/src/sample.c b/src/sample.c index 74a54937..2e46eac7 100644 --- a/src/sample.c +++ b/src/sample.c @@ -10,7 +10,7 @@ struct sample_spec default_sample_spec = { }; struct memblock *silence(struct memblock* b, struct sample_spec *spec) { - char c; + char c = 0; assert(b && spec); memblock_assert_exclusive(b); @@ -53,7 +53,7 @@ void add_clip(struct memchunk *target, struct memchunk *chunk, struct sample_spe size_t sample_size(struct sample_spec *spec) { assert(spec); - size_t b; + size_t b = 1; switch (spec->format) { case SAMPLE_U8: -- cgit -- cgit From aae40dcea260296d7d02d185b42f9275f34cb238 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Jun 2004 17:18:40 +0000 Subject: module dependencie foo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@7 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/module.c | 70 ++++++++++++++++++++++++++++++++++++++++-- src/module.h | 7 +++++ src/protocol-simple-tcp.moddep | 2 ++ src/protocol-simple.moddep | 1 + src/sink-pipe.moddep | 1 + src/socket-server.moddep | 1 + 6 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 src/protocol-simple-tcp.moddep create mode 100644 src/protocol-simple.moddep create mode 100644 src/sink-pipe.moddep create mode 100644 src/socket-server.moddep diff --git a/src/module.c b/src/module.c index 94a43124..4aa9fd68 100644 --- a/src/module.c +++ b/src/module.c @@ -1,9 +1,68 @@ +#include +#include #include #include #include #include "module.h" + +static void free_deps(struct dependency_module** deps) { + assert(deps); + + while (*deps) { + struct dependency_module *next = (*deps)->next; + lt_dlclose((*deps)->dl); + free(deps); + *deps = next; + } +} + +static int load_deps(const char *fname, struct dependency_module **deps) { + char line[PATH_MAX]; + FILE *f; + char depfile[PATH_MAX]; + assert(fname && deps); + + snprintf(depfile, sizeof(depfile), "%s.moddep", fname); + + if (!(f = fopen(depfile, "r"))) + return -1; + + while (fgets(line, sizeof(line)-1, f)) { + lt_dlhandle dl; + char *p; + size_t l; + struct dependency_module* d; + + p = line + strspn(line, " \t"); + + l = strlen(p); + if (p[l-1] == '\n') + p[l-1] = 0; + + if (*p == '#' || *p == 0) + continue; + + load_deps(p, deps); + + if (!(dl = lt_dlopenext(p))) { + free_deps(deps); + fclose(f); + return -1; + } + + d = malloc(sizeof(struct dependency_module)); + assert(d); + d->dl = dl; + d->next = *deps; + *deps = d; + } + + fclose(f); + return 0; +} + struct module* module_load(struct core *c, const char *name, const char *argument) { struct module *m = NULL; int r; @@ -13,6 +72,12 @@ struct module* module_load(struct core *c, const char *name, const char *argumen m = malloc(sizeof(struct module)); assert(m); + m->dl = NULL; + + m->dependencies = NULL; + if (load_deps(name, &m->dependencies) < 0) + goto fail; + if (!(m->dl = lt_dlopenext(name))) goto fail; @@ -33,7 +98,6 @@ struct module* module_load(struct core *c, const char *name, const char *argumen if (!c->modules) c->modules = idxset_new(NULL, NULL); - assert(c->modules); r = idxset_put(c->modules, m, &m->index); @@ -45,6 +109,7 @@ fail: if (m->dl) lt_dlclose(m->dl); + free_deps(&m->dependencies); free(m); } @@ -56,11 +121,13 @@ static void module_free(struct module *m) { m->done(m->core, m); lt_dlclose(m->dl); + free_deps(&m->dependencies); free(m->name); free(m->argument); free(m); } + void module_unload(struct core *c, struct module *m) { assert(c && m); @@ -82,7 +149,6 @@ void module_unload_by_index(struct core *c, uint32_t index) { module_free(m); } - void free_callback(void *p, void *userdata) { struct module *m = p; assert(m); diff --git a/src/module.h b/src/module.h index 4ecef86e..d16c25cd 100644 --- a/src/module.h +++ b/src/module.h @@ -6,12 +6,19 @@ #include "core.h" +struct dependency_module { + lt_dlhandle dl; + struct dependency_module *next; +}; + struct module { struct core *core; char *name, *argument; uint32_t index; lt_dlhandle dl; + struct dependency_module *dependencies; + int (*init)(struct core *c, struct module*m); void (*done)(struct core *c, struct module*m); diff --git a/src/protocol-simple-tcp.moddep b/src/protocol-simple-tcp.moddep new file mode 100644 index 00000000..88f964a0 --- /dev/null +++ b/src/protocol-simple-tcp.moddep @@ -0,0 +1,2 @@ +socket-server +protocol-simple diff --git a/src/protocol-simple.moddep b/src/protocol-simple.moddep new file mode 100644 index 00000000..c49501d8 --- /dev/null +++ b/src/protocol-simple.moddep @@ -0,0 +1 @@ +socket-server diff --git a/src/sink-pipe.moddep b/src/sink-pipe.moddep new file mode 100644 index 00000000..6958f9fc --- /dev/null +++ b/src/sink-pipe.moddep @@ -0,0 +1 @@ +iochannel diff --git a/src/socket-server.moddep b/src/socket-server.moddep new file mode 100644 index 00000000..6958f9fc --- /dev/null +++ b/src/socket-server.moddep @@ -0,0 +1 @@ +iochannel -- cgit From 7dfeb1fc745757f1c2b7bf43bae80cf0f49fc9a6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Jun 2004 21:30:16 +0000 Subject: make the whole stuff run and clean it self up again git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@8 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 39 ++++++++-------- src/idxset.c | 8 ++-- src/iochannel.c | 6 +++ src/main.c | 10 ++++ src/mainloop.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++----- src/mainloop.h | 4 +- src/module.c | 69 ++-------------------------- src/module.h | 2 - src/sink-pipe.c | 2 +- src/sink.c | 9 ++-- src/source.c | 6 +++ 11 files changed, 189 insertions(+), 104 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index c64babb3..485513df 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -20,8 +20,8 @@ AM_CFLAGS=-ansi -D_GNU_SOURCE bin_PROGRAMS = polypaudio -pkglib_LTLIBRARIES=protocol-simple.la protocol-simple-tcp.la \ - socket-server.la sink-pipe.la pstream.la iochannel.la packet.la +pkglib_LTLIBRARIES=libprotocol-simple.la protocol-simple-tcp.la \ + libsocket-server.la sink-pipe.la libpstream.la libiochannel.la libpacket.la polypaudio_SOURCES = idxset.c queue.c strbuf.c mainloop.c \ memblock.c sample.c memblockq.c client.c \ @@ -31,25 +31,28 @@ polypaudio_INCLUDES = $(INCLTDL) polypaudio_LDADD = $(LIBLTDL) polypaudio_LDFLAGS=-export-dynamic -protocol_simple_la_SOURCES = protocol-simple.c -protocol_simple_la_LDFLAGS = -module -avoid-version +libprotocol_simple_la_SOURCES = protocol-simple.c +libprotocol_simple_la_LDFLAGS = -avoid-version +libprotocol_simple_la_LIBADD = libsocket-server.la libiochannel.la -protocol_simple_tcp_la_SOURCES = protocol-simple-tcp.c -protocol_simple_tcp_la_LDFLAGS = -module -avoid-version -protocol_simple_tcp_la_LIBADD = protocol-simple.la socket-server.la - -socket_server_la_SOURCES = socket-server.c -socket_server_la_LDFLAGS = -module -avoid-version +libsocket_server_la_SOURCES = socket-server.c +libsocket_server_la_LDFLAGS = -avoid-version +libsocket_server_la_LIBADD = libiochannel.la -sink_pipe_la_SOURCES = sink-pipe.c -sink_pipe_la_LDFLAGS = -module -avoid-version +libpstream_la_SOURCES = pstream.c +libpstream_la_LDFLAGS = -avoid-version +libpstream_la_LIBADD = libpacket.la -pstream_la_SOURCES = pstream.c -pstream_la_LDFLAGS = -module -avoid-version +libiochannel_la_SOURCES = iochannel.c +libiochannel_la_LDFLAGS = -avoid-version -iochannel_la_SOURCES = pstream.c -iochannel_la_LDFLAGS = -module -avoid-version +libpacket_la_SOURCES = packet.c +libpacket_la_LDFLAGS = -avoid-version -packet_la_SOURCES = pstream.c -packet_la_LDFLAGS = -module -avoid-version +protocol_simple_tcp_la_SOURCES = protocol-simple-tcp.c +protocol_simple_tcp_la_LDFLAGS = -module -avoid-version +protocol_simple_tcp_la_LIBADD = libprotocol-simple.la libiochannel.la +sink_pipe_la_SOURCES = sink-pipe.c +sink_pipe_la_LDFLAGS = -module -avoid-version +sink_pipe_la_LIBADD = libiochannel.la diff --git a/src/idxset.c b/src/idxset.c index eaea34f4..f0d7ad87 100644 --- a/src/idxset.c +++ b/src/idxset.c @@ -27,7 +27,7 @@ static unsigned trivial_hash_func(void *p) { } static int trivial_compare_func(void *a, void *b) { - return !(a == b); + return a != b; } struct idxset* idxset_new(unsigned (*hash_func) (void *p), int (*compare_func) (void*a, void*b)) { @@ -40,11 +40,13 @@ struct idxset* idxset_new(unsigned (*hash_func) (void *p), int (*compare_func) ( s->hash_table_size = 1023; s->hash_table = malloc(sizeof(struct idxset_entry*)*s->hash_table_size); assert(s->hash_table); + memset(s->hash_table, 0, sizeof(struct idxset_entry*)*s->hash_table_size); s->array = NULL; s->array_size = 0; s->index = 0; s->start_index = 0; s->n_entries = 0; + s->rrobin = NULL; s->iterate_list_head = s->iterate_list_tail = NULL; @@ -75,7 +77,7 @@ static struct idxset_entry* hash_scan(struct idxset *s, struct idxset_entry* e, assert(s->compare_func); for (; e; e = e->hash_next) - if (s->compare_func(e->data, p)) + if (s->compare_func(e->data, p) == 0) return e; return NULL; @@ -278,7 +280,7 @@ void* idxset_remove_by_data(struct idxset*s, void *data, uint32_t *index) { } void* idxset_rrobin(struct idxset *s, uint32_t *index) { - assert(s && index); + assert(s); if (s->rrobin) s->rrobin = s->rrobin->iterate_next; diff --git a/src/iochannel.c b/src/iochannel.c index db9717a9..aa7de714 100644 --- a/src/iochannel.c +++ b/src/iochannel.c @@ -156,3 +156,9 @@ ssize_t iochannel_read(struct iochannel*io, void*data, size_t l) { return r; } + +void iochannel_set_callback(struct iochannel*io, void (*callback)(struct iochannel*io, void *userdata), void *userdata) { + assert(io); + io->callback = callback; + io->userdata = userdata; +} diff --git a/src/main.c b/src/main.c index 0785b39c..436dd30b 100644 --- a/src/main.c +++ b/src/main.c @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -6,6 +8,11 @@ #include "mainloop.h" #include "module.h" +static void signal_callback(struct mainloop_source *m, int sig, void *userdata) { + mainloop_quit(mainloop_source_get_mainloop(m), -1); + fprintf(stderr, "Got signal.\n"); +} + int main(int argc, char *argv[]) { struct mainloop *m; struct core *c; @@ -19,6 +26,9 @@ int main(int argc, char *argv[]) { c = core_new(m); assert(c); + mainloop_source_new_signal(m, SIGINT, signal_callback, NULL); + signal(SIGPIPE, SIG_IGN); + module_load(c, "sink-pipe", NULL); module_load(c, "protocol-simple-tcp", NULL); diff --git a/src/mainloop.c b/src/mainloop.c index d043ce90..0f5811f2 100644 --- a/src/mainloop.c +++ b/src/mainloop.c @@ -1,7 +1,11 @@ +#include +#include #include #include #include #include +#include +#include #include "mainloop.h" @@ -28,6 +32,12 @@ struct mainloop_source { struct { void (*callback)(struct mainloop_source*s, void *userdata); } idle; + + struct { + int sig; + struct sigaction sigaction; + void (*callback)(struct mainloop_source*s, int sig, void *userdata); + } signal; }; struct mainloop_source_list { @@ -37,7 +47,7 @@ struct mainloop_source_list { }; struct mainloop { - struct mainloop_source_list io_sources, prepare_sources, idle_sources; + struct mainloop_source_list io_sources, prepare_sources, idle_sources, signal_sources; struct pollfd *pollfds; int max_pollfds, n_pollfds; @@ -45,14 +55,43 @@ struct mainloop { int quit; int running; + int signal_pipe[2]; + struct pollfd signal_pollfd; }; +static int signal_pipe = -1; + +static void signal_func(int sig) { + if (signal_pipe >= 0) + write(signal_pipe, &sig, sizeof(sig)); +} + +static void make_nonblock(int fd) { + int v; + + if ((v = fcntl(fd, F_GETFL)) >= 0) + fcntl(fd, F_SETFL, v|O_NONBLOCK); +} + + struct mainloop *mainloop_new(void) { + int r; struct mainloop *m; m = malloc(sizeof(struct mainloop)); assert(m); memset(m, 0, sizeof(struct mainloop)); + + r = pipe(m->signal_pipe); + assert(r >= 0 && m->signal_pipe[0] >= 0 && m->signal_pipe[1] >= 0); + + make_nonblock(m->signal_pipe[0]); + make_nonblock(m->signal_pipe[1]); + + signal_pipe = m->signal_pipe[1]; + m->signal_pollfd.fd = m->signal_pipe[0]; + m->signal_pollfd.events = POLLIN; + m->signal_pollfd.revents = 0; return m; } @@ -61,7 +100,7 @@ static void free_sources(struct mainloop_source_list *l, int all) { struct mainloop_source *s, *p; assert(l); - if (!l->dead_sources) + if (!all && !l->dead_sources) return; p = NULL; @@ -86,7 +125,7 @@ static void free_sources(struct mainloop_source_list *l, int all) { l->dead_sources = 0; if (all) { - assert(l->sources); + assert(!l->sources); l->n_sources = 0; } } @@ -96,15 +135,23 @@ void mainloop_free(struct mainloop* m) { free_sources(&m->io_sources, 1); free_sources(&m->prepare_sources, 1); free_sources(&m->idle_sources, 1); + free_sources(&m->signal_sources, 1); + + if (signal_pipe == m->signal_pipe[1]) + signal_pipe = -1; + close(m->signal_pipe[0]); + close(m->signal_pipe[1]); + free(m->pollfds); + free(m); } static void rebuild_pollfds(struct mainloop *m) { struct mainloop_source*s; struct pollfd *p; - if (m->max_pollfds < m->io_sources.n_sources) { - m->max_pollfds = m->io_sources.n_sources*2; + if (m->max_pollfds < m->io_sources.n_sources+1) { + m->max_pollfds = (m->io_sources.n_sources+1)*2; m->pollfds = realloc(m->pollfds, sizeof(struct pollfd)*m->max_pollfds); } @@ -117,6 +164,9 @@ static void rebuild_pollfds(struct mainloop *m) { m->n_pollfds++; } } + + *(p++) = m->signal_pollfd; + m->n_pollfds++; } static void dispatch_pollfds(struct mainloop *m) { @@ -128,10 +178,42 @@ static void dispatch_pollfds(struct mainloop *m) { s = m->io_sources.sources; for (p = m->pollfds, i = 0; i < m->n_pollfds; p++, i++) { - for (;;) { - assert(s && s->type == MAINLOOP_SOURCE_TYPE_IO); + if (!p->revents) + continue; + + if (p->fd == m->signal_pipe[0]) { + /* Event from signal pipe */ + + if (p->revents & POLLIN) { + int sig; + ssize_t r; + r = read(m->signal_pipe[0], &sig, sizeof(sig)); + assert((r < 0 && errno == EAGAIN) || r == sizeof(sig)); - if (p->fd == s->io.fd) { + if (r == sizeof(sig)) { + struct mainloop_source *l = m->signal_sources.sources; + while (l) { + assert(l->type == MAINLOOP_SOURCE_TYPE_SIGNAL); + + if (l->signal.sig == sig && l->enabled && !l->dead) { + assert(l->signal.callback); + l->signal.callback(l, sig, l->userdata); + } + + l = l->next; + } + } + } + + } else { + /* Event from I/O source */ + + for (; s; s = s->next) { + if (p->fd != s->io.fd) + continue; + + assert(s->type == MAINLOOP_SOURCE_TYPE_IO); + if (!s->dead && s->enabled) { enum mainloop_io_event e = (p->revents & POLLIN ? MAINLOOP_IO_EVENT_IN : 0) | (p->revents & POLLOUT ? MAINLOOP_IO_EVENT_OUT : 0); if (e) { @@ -142,7 +224,6 @@ static void dispatch_pollfds(struct mainloop *m) { break; } - s = s->next; } } } @@ -172,7 +253,11 @@ int mainloop_iterate(struct mainloop *m, int block) { m->running = 1; - if ((c = poll(m->pollfds, m->n_pollfds, (block && !m->idle_sources.n_sources) ? -1 : 0)) > 0) + do { + c = poll(m->pollfds, m->n_pollfds, (block && !m->idle_sources.n_sources) ? -1 : 0); + } while (c < 0 && errno == EINTR); + + if (c > 0) dispatch_pollfds(m); else if (c == 0) { for (s = m->idle_sources.sources; s; s = s->next) { @@ -212,6 +297,9 @@ static struct mainloop_source_list* get_source_list(struct mainloop *m, enum mai case MAINLOOP_SOURCE_TYPE_IDLE: l = &m->idle_sources; break; + case MAINLOOP_SOURCE_TYPE_SIGNAL: + l = &m->signal_sources; + break; default: l = NULL; break; @@ -279,7 +367,33 @@ struct mainloop_source* mainloop_source_new_idle(struct mainloop*m, void (*callb s = source_new(m, MAINLOOP_SOURCE_TYPE_IDLE); - s->prepare.callback = callback; + s->idle.callback = callback; + s->userdata = userdata; + s->enabled = 1; + return s; +} + +struct mainloop_source* mainloop_source_new_signal(struct mainloop*m, int sig, void (*callback)(struct mainloop_source *s, int sig, void*userdata), void*userdata) { + struct mainloop_source* s; + struct sigaction save_sa, sa; + + assert(m && callback); + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = signal_func; + sa.sa_flags = SA_RESTART; + sigemptyset(&sa.sa_mask); + + memset(&save_sa, 0, sizeof(save_sa)); + + if (sigaction(sig, &sa, &save_sa) < 0) + return NULL; + + s = source_new(m, MAINLOOP_SOURCE_TYPE_SIGNAL); + s->signal.sig = sig; + s->signal.sigaction = save_sa; + + s->signal.callback = callback; s->userdata = userdata; s->enabled = 1; return s; @@ -299,6 +413,8 @@ void mainloop_source_free(struct mainloop_source*s) { if (s->type == MAINLOOP_SOURCE_TYPE_IO) s->mainloop->rebuild_pollfds = 1; + else if (s->type == MAINLOOP_SOURCE_TYPE_SIGNAL) + sigaction(s->signal.sig, &s->signal.sigaction, NULL); } void mainloop_source_enable(struct mainloop_source*s, int b) { diff --git a/src/mainloop.h b/src/mainloop.h index 72376c72..3c6d7e37 100644 --- a/src/mainloop.h +++ b/src/mainloop.h @@ -14,7 +14,8 @@ enum mainloop_io_event { enum mainloop_source_type { MAINLOOP_SOURCE_TYPE_IO, MAINLOOP_SOURCE_TYPE_PREPARE, - MAINLOOP_SOURCE_TYPE_IDLE + MAINLOOP_SOURCE_TYPE_IDLE, + MAINLOOP_SOURCE_TYPE_SIGNAL }; struct mainloop *mainloop_new(void); @@ -27,6 +28,7 @@ void mainloop_quit(struct mainloop *m, int r); struct mainloop_source* mainloop_source_new_io(struct mainloop*m, int fd, enum mainloop_io_event event, void (*callback)(struct mainloop_source*s, int fd, enum mainloop_io_event event, void *userdata), void *userdata); struct mainloop_source* mainloop_source_new_prepare(struct mainloop*m, void (*callback)(struct mainloop_source *s, void*userdata), void*userdata); struct mainloop_source* mainloop_source_new_idle(struct mainloop*m, void (*callback)(struct mainloop_source *s, void*userdata), void*userdata); +struct mainloop_source* mainloop_source_new_signal(struct mainloop*m, int sig, void (*callback)(struct mainloop_source *s, int sig, void*userdata), void*userdata); void mainloop_source_free(struct mainloop_source*s); void mainloop_source_enable(struct mainloop_source*s, int b); diff --git a/src/module.c b/src/module.c index 4aa9fd68..62204e4c 100644 --- a/src/module.c +++ b/src/module.c @@ -3,66 +3,10 @@ #include #include #include +#include #include "module.h" - -static void free_deps(struct dependency_module** deps) { - assert(deps); - - while (*deps) { - struct dependency_module *next = (*deps)->next; - lt_dlclose((*deps)->dl); - free(deps); - *deps = next; - } -} - -static int load_deps(const char *fname, struct dependency_module **deps) { - char line[PATH_MAX]; - FILE *f; - char depfile[PATH_MAX]; - assert(fname && deps); - - snprintf(depfile, sizeof(depfile), "%s.moddep", fname); - - if (!(f = fopen(depfile, "r"))) - return -1; - - while (fgets(line, sizeof(line)-1, f)) { - lt_dlhandle dl; - char *p; - size_t l; - struct dependency_module* d; - - p = line + strspn(line, " \t"); - - l = strlen(p); - if (p[l-1] == '\n') - p[l-1] = 0; - - if (*p == '#' || *p == 0) - continue; - - load_deps(p, deps); - - if (!(dl = lt_dlopenext(p))) { - free_deps(deps); - fclose(f); - return -1; - } - - d = malloc(sizeof(struct dependency_module)); - assert(d); - d->dl = dl; - d->next = *deps; - *deps = d; - } - - fclose(f); - return 0; -} - struct module* module_load(struct core *c, const char *name, const char *argument) { struct module *m = NULL; int r; @@ -72,12 +16,6 @@ struct module* module_load(struct core *c, const char *name, const char *argumen m = malloc(sizeof(struct module)); assert(m); - m->dl = NULL; - - m->dependencies = NULL; - if (load_deps(name, &m->dependencies) < 0) - goto fail; - if (!(m->dl = lt_dlopenext(name))) goto fail; @@ -106,10 +44,12 @@ struct module* module_load(struct core *c, const char *name, const char *argumen fail: if (m) { + free(m->argument); + free(m->name); + if (m->dl) lt_dlclose(m->dl); - free_deps(&m->dependencies); free(m); } @@ -121,7 +61,6 @@ static void module_free(struct module *m) { m->done(m->core, m); lt_dlclose(m->dl); - free_deps(&m->dependencies); free(m->name); free(m->argument); free(m); diff --git a/src/module.h b/src/module.h index d16c25cd..98082194 100644 --- a/src/module.h +++ b/src/module.h @@ -17,8 +17,6 @@ struct module { uint32_t index; lt_dlhandle dl; - struct dependency_module *dependencies; - int (*init)(struct core *c, struct module*m); void (*done)(struct core *c, struct module*m); diff --git a/src/sink-pipe.c b/src/sink-pipe.c index 4a8348f8..78ea7bf2 100644 --- a/src/sink-pipe.c +++ b/src/sink-pipe.c @@ -85,7 +85,7 @@ int module_init(struct core *c, struct module*m) { mkfifo((p = m->argument ? m->argument : "/tmp/musicfifo"), 0777); - if ((fd = open(p, O_RDWR) < 0)) { + if ((fd = open(p, O_RDWR)) < 0) { fprintf(stderr, "open('%s'): %s\n", p, strerror(errno)); goto fail; } diff --git a/src/sink.c b/src/sink.c index ac387c78..0e68cf8b 100644 --- a/src/sink.c +++ b/src/sink.c @@ -29,6 +29,8 @@ struct sink* sink_new(struct core *core, const char *name, const struct sample_s } s->monitor_source = source_new(core, n, spec); + free(n); + s->volume = 0xFF; s->notify_callback = NULL; @@ -41,12 +43,13 @@ void sink_free(struct sink *s) { struct input_stream *i; assert(s); - idxset_remove_by_data(s->core->sinks, s, NULL); - source_free(s->monitor_source); - while ((i = idxset_rrobin(s->input_streams, NULL))) input_stream_free(i); + idxset_free(s->input_streams, NULL, NULL); + idxset_remove_by_data(s->core->sinks, s, NULL); + source_free(s->monitor_source); + free(s->name); free(s); } diff --git a/src/source.c b/src/source.c index 2f34c461..98df2447 100644 --- a/src/source.c +++ b/src/source.c @@ -34,10 +34,16 @@ static void do_free(void *p, void *userdata) { }; void source_free(struct source *s) { + struct output_stream *o; assert(s); + while ((o = idxset_rrobin(s->output_streams, NULL))) + output_stream_free(o); + idxset_free(s->output_streams, NULL, NULL); + idxset_remove_by_data(s->core->sources, s, NULL); idxset_free(s->output_streams, do_free, NULL); + free(s->name); free(s); } -- cgit From edfad835cb7e4ab9f62de81cf4bf6b6ad9610b02 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Jun 2004 21:30:51 +0000 Subject: remove moddep files (since they are obsolete) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@9 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/protocol-simple-tcp.moddep | 2 -- src/protocol-simple.moddep | 1 - src/sink-pipe.moddep | 1 - src/socket-server.moddep | 1 - 4 files changed, 5 deletions(-) delete mode 100644 src/protocol-simple-tcp.moddep delete mode 100644 src/protocol-simple.moddep delete mode 100644 src/sink-pipe.moddep delete mode 100644 src/socket-server.moddep diff --git a/src/protocol-simple-tcp.moddep b/src/protocol-simple-tcp.moddep deleted file mode 100644 index 88f964a0..00000000 --- a/src/protocol-simple-tcp.moddep +++ /dev/null @@ -1,2 +0,0 @@ -socket-server -protocol-simple diff --git a/src/protocol-simple.moddep b/src/protocol-simple.moddep deleted file mode 100644 index c49501d8..00000000 --- a/src/protocol-simple.moddep +++ /dev/null @@ -1 +0,0 @@ -socket-server diff --git a/src/sink-pipe.moddep b/src/sink-pipe.moddep deleted file mode 100644 index 6958f9fc..00000000 --- a/src/sink-pipe.moddep +++ /dev/null @@ -1 +0,0 @@ -iochannel diff --git a/src/socket-server.moddep b/src/socket-server.moddep deleted file mode 100644 index 6958f9fc..00000000 --- a/src/socket-server.moddep +++ /dev/null @@ -1 +0,0 @@ -iochannel -- cgit From c8cf0c1ce9cf1b38b302ae4a2a6fa798fef85f08 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 14 Jun 2004 18:38:50 +0000 Subject: a bunch of fixes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@10 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/idxset.c | 7 +++++-- src/iochannel.c | 8 ++++---- src/mainloop.c | 6 ++++-- src/memblockq.c | 4 ++-- src/protocol-simple.c | 9 ++++++--- src/sink.c | 2 ++ src/socket-server.c | 6 +++++- src/source.c | 7 ------- 8 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/idxset.c b/src/idxset.c index f0d7ad87..fe447ac6 100644 --- a/src/idxset.c +++ b/src/idxset.c @@ -152,8 +152,8 @@ int idxset_put(struct idxset*s, void *p, uint32_t *index) { s->hash_table[h] = e; /* Insert into array */ - extend_array(s, s->index); - a = array_index(s, s->index); + extend_array(s, e->index); + a = array_index(s, e->index); assert(a && !*a); *a = e; @@ -185,6 +185,9 @@ void* idxset_get_by_index(struct idxset*s, uint32_t index) { if (!(a = array_index(s, index))) return NULL; + if (!*a) + return NULL; + return (*a)->data; } diff --git a/src/iochannel.c b/src/iochannel.c index aa7de714..2044d561 100644 --- a/src/iochannel.c +++ b/src/iochannel.c @@ -41,15 +41,15 @@ static void enable_mainloop_sources(struct iochannel *io) { static void callback(struct mainloop_source*s, int fd, enum mainloop_io_event events, void *userdata) { struct iochannel *io = userdata; - int changed; + int changed = 0; assert(s && fd >= 0 && userdata); - if (events & MAINLOOP_IO_EVENT_IN && !io->readable) { + if ((events & MAINLOOP_IO_EVENT_IN) && !io->readable) { io->readable = 1; changed = 1; } - if (events & MAINLOOP_IO_EVENT_OUT && !io->writable) { + if ((events & MAINLOOP_IO_EVENT_OUT) && !io->writable) { io->writable = 1; changed = 1; } @@ -116,7 +116,7 @@ void iochannel_free(struct iochannel*io) { if (io->input_source) mainloop_source_free(io->input_source); - if (io->output_source) + if (io->output_source && io->output_source != io->input_source) mainloop_source_free(io->output_source); free(io); diff --git a/src/mainloop.c b/src/mainloop.c index 0f5811f2..2992673a 100644 --- a/src/mainloop.c +++ b/src/mainloop.c @@ -248,8 +248,10 @@ int mainloop_iterate(struct mainloop *m, int block) { } } - if (m->rebuild_pollfds) + if (m->rebuild_pollfds) { rebuild_pollfds(m); + m->rebuild_pollfds = 0; + } m->running = 1; @@ -431,7 +433,7 @@ void mainloop_source_enable(struct mainloop_source*s, int b) { void mainloop_source_io_set_events(struct mainloop_source*s, enum mainloop_io_event events) { assert(s && !s->dead && s->type == MAINLOOP_SOURCE_TYPE_IO); - if ((s->io.events && !events) || (!s->io.events && events)) { + if (s->io.events != events) { assert(s->mainloop); s->mainloop->rebuild_pollfds = 1; } diff --git a/src/memblockq.c b/src/memblockq.c index 1424c556..a422cf09 100644 --- a/src/memblockq.c +++ b/src/memblockq.c @@ -46,7 +46,7 @@ void memblockq_free(struct memblockq* bq) { void memblockq_push(struct memblockq* bq, struct memchunk *chunk, size_t delta) { struct memblock_list *q; - assert(bq && chunk && chunk->memblock && chunk->index); + assert(bq && chunk && chunk->memblock && chunk->length); q = malloc(sizeof(struct memblock_list)); assert(q); @@ -152,5 +152,5 @@ void memblockq_empty(struct memblockq *bq) { int memblockq_is_empty(struct memblockq *bq) { assert(bq); - return bq->total_length >= bq->base; + return bq->total_length < bq->base; } diff --git a/src/protocol-simple.c b/src/protocol-simple.c index 3335bc14..e930f9ae 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -103,7 +103,10 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c->istream = NULL; c->ostream = NULL; c->protocol = p; - + + c->client = client_new(p->core, "SIMPLE", "Client"); + assert(c->client); + if (p->mode & PROTOCOL_SIMPLE_RECORD) { struct source *source; @@ -128,8 +131,6 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us assert(c->istream); } - c->client = client_new(p->core, "SIMPLE", "Client"); - assert(c->client); iochannel_set_callback(c->io, io_callback, c); idxset_put(p->connections, c, NULL); @@ -137,6 +138,8 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us fail: if (c) { + if (c->client) + client_free(c->client); if (c->istream) input_stream_free(c->istream); if (c->ostream) diff --git a/src/sink.c b/src/sink.c index 0e68cf8b..02ca3468 100644 --- a/src/sink.c +++ b/src/sink.c @@ -77,6 +77,8 @@ static int get_max_length(void *p, uint32_t index, int *del, void*userdata) { info->count++; info->last_input_stream = i; + memblock_unref(chunk.memblock); + return 0; } diff --git a/src/socket-server.c b/src/socket-server.c index 2a1db9a0..6ad225e3 100644 --- a/src/socket-server.c +++ b/src/socket-server.c @@ -104,6 +104,7 @@ fail: struct socket_server* socket_server_new_ipv4(struct mainloop *m, uint32_t address, uint16_t port) { int fd = -1; struct sockaddr_in sa; + int on = 1; assert(m && port); @@ -112,10 +113,13 @@ struct socket_server* socket_server_new_ipv4(struct mainloop *m, uint32_t addres goto fail; } + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) + fprintf(stderr, "setsockopt(): %s\n", strerror(errno)); + sa.sin_family = AF_INET; sa.sin_port = htons(port); sa.sin_addr.s_addr = htonl(address); - + if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { fprintf(stderr, "bind(): %s\n", strerror(errno)); goto fail; diff --git a/src/source.c b/src/source.c index 98df2447..a1e7b245 100644 --- a/src/source.c +++ b/src/source.c @@ -27,12 +27,6 @@ struct source* source_new(struct core *core, const char *name, const struct samp return s; } -static void do_free(void *p, void *userdata) { - struct output_stream *o = p; - assert(o); - output_stream_free(o); -}; - void source_free(struct source *s) { struct output_stream *o; assert(s); @@ -42,7 +36,6 @@ void source_free(struct source *s) { idxset_free(s->output_streams, NULL, NULL); idxset_remove_by_data(s->core->sources, s, NULL); - idxset_free(s->output_streams, do_free, NULL); free(s->name); free(s); -- cgit From 5ce204829fe6706a5edaec50769abf7eed266656 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 14 Jun 2004 20:30:50 +0000 Subject: more cleanups git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@11 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/client.c | 14 +++++++++++++- src/client.h | 15 +++++++++++++-- src/core.c | 6 ++---- src/idxset.c | 51 ++++++++++++++++++++++++++++++--------------------- src/idxset.h | 7 +++++++ src/inputstream.c | 18 +++++++++++++++++- src/inputstream.h | 17 ++++++++++++++++- src/memblockq.c | 2 ++ src/outputstream.c | 16 ++++++++++++++++ src/outputstream.h | 5 +++++ src/protocol-simple.c | 32 +++++++++++++++++++++++++++++--- src/sink.c | 9 ++++++--- src/source.c | 7 +++++-- 13 files changed, 161 insertions(+), 38 deletions(-) diff --git a/src/client.c b/src/client.c index 56d85734..3dd37668 100644 --- a/src/client.c +++ b/src/client.c @@ -14,7 +14,7 @@ struct client *client_new(struct core *core, const char *protocol_name, char *na c->protocol_name = protocol_name; c->name = name ? strdup(name) : NULL; c->kill = NULL; - c->userdata = NULL; + c->kill_userdata = NULL; c->core = core; r = idxset_put(core->clients, c, &c->index); @@ -30,3 +30,15 @@ void client_free(struct client *c) { free(c->name); free(c); } + +void client_set_kill_callback(struct client *c, void (*kill)(struct client *c, void *userdata), void *userdata) { + assert(c && kill); + c->kill = kill; + c->kill_userdata = userdata; +} + +void client_kill(struct client *c) { + assert(c); + c->kill(c, c->kill_userdata); +} + diff --git a/src/client.h b/src/client.h index 7128a452..8d9e519c 100644 --- a/src/client.h +++ b/src/client.h @@ -9,13 +9,24 @@ struct client { const char *protocol_name; - void *userdata; - void (*kill)(struct client *c); + void *kill_userdata; + void (*kill)(struct client *c, void *userdata); struct core *core; }; struct client *client_new(struct core *c, const char *protocol_name, char *name); + +/* This function should be called only by the code that created the client */ void client_free(struct client *c); +/* The registrant of the client should call this function to set a + * callback function which is called when destruction of the client is + * requested */ +void client_set_kill_callback(struct client *c, void (*kill)(struct client *c, void *userdata), void *userdata); + +/* Code that didn't create the client should call this function to + * request destruction of the client */ +void client_kill(struct client *c); + #endif diff --git a/src/core.c b/src/core.c index 7cfa66e3..0457f4f3 100644 --- a/src/core.c +++ b/src/core.c @@ -57,11 +57,10 @@ struct sink* core_get_default_sink(struct core *c) { if ((sink = idxset_get_by_index(c->sinks, c->default_sink_index))) return sink; - if (!(sink = idxset_rrobin(c->sinks, NULL))) + if (!(sink = idxset_first(c->sinks, &c->default_sink_index))) return NULL; fprintf(stderr, "Default sink vanished, setting to %u\n", sink->index); - c->default_sink_index = sink->index; return sink; } @@ -72,10 +71,9 @@ struct source* core_get_default_source(struct core *c) { if ((source = idxset_get_by_index(c->sources, c->default_source_index))) return source; - if (!(source = idxset_rrobin(c->sources, NULL))) + if (!(source = idxset_first(c->sources, &c->default_source_index))) return NULL; fprintf(stderr, "Default source vanished, setting to %u\n", source->index); - c->default_source_index = source->index; return source; } diff --git a/src/idxset.c b/src/idxset.c index fe447ac6..4442190d 100644 --- a/src/idxset.c +++ b/src/idxset.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -18,7 +19,7 @@ struct idxset { int (*compare_func)(void *a, void *b); unsigned hash_table_size, n_entries; - struct idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail, *rrobin; + struct idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail; uint32_t index, start_index, array_size; }; @@ -46,7 +47,6 @@ struct idxset* idxset_new(unsigned (*hash_func) (void *p), int (*compare_func) ( s->index = 0; s->start_index = 0; s->n_entries = 0; - s->rrobin = NULL; s->iterate_list_head = s->iterate_list_tail = NULL; @@ -86,9 +86,9 @@ static struct idxset_entry* hash_scan(struct idxset *s, struct idxset_entry* e, static void extend_array(struct idxset *s, uint32_t index) { uint32_t i, j, l; struct idxset_entry** n; - assert(index >= s->start_index ); + assert(index >= s->start_index); - if (index <= s->start_index + s->array_size) + if (index < s->start_index + s->array_size) return; for (i = 0; i < s->array_size; i++) @@ -111,13 +111,12 @@ static void extend_array(struct idxset *s, uint32_t index) { } static struct idxset_entry** array_index(struct idxset*s, uint32_t index) { - if (index >= s->start_index + s->array_size) return NULL; if (index < s->start_index) return NULL; - + return s->array + (index - s->start_index); } @@ -214,8 +213,8 @@ static void remove_entry(struct idxset *s, struct idxset_entry *e) { assert(s && e); /* Remove from array */ - a = array_index(s, s->index); - assert(a && *a == e); + a = array_index(s, e->index); + assert(a && *a && *a == e); *a = NULL; /* Remove from linked list */ @@ -238,9 +237,6 @@ static void remove_entry(struct idxset *s, struct idxset_entry *e) { else s->hash_table[e->hash_value] = e->hash_next; - if (s->rrobin == e) - s->rrobin = NULL; - free(e); assert(s->n_entries >= 1); @@ -265,7 +261,7 @@ void* idxset_remove_by_index(struct idxset*s, uint32_t index) { void* idxset_remove_by_data(struct idxset*s, void *data, uint32_t *index) { struct idxset_entry *e; unsigned h; - + assert(s->hash_func); h = s->hash_func(data) % s->hash_table_size; @@ -283,23 +279,36 @@ void* idxset_remove_by_data(struct idxset*s, void *data, uint32_t *index) { } void* idxset_rrobin(struct idxset *s, uint32_t *index) { - assert(s); + struct idxset_entry **a, *e = NULL; + assert(s && index); + + if ((a = array_index(s, *index)) && *a) + e = (*a)->iterate_next; + + if (!e) + e = s->iterate_list_head; - if (s->rrobin) - s->rrobin = s->rrobin->iterate_next; + if (!e) + return NULL; - if (!s->rrobin) - s->rrobin = s->iterate_list_head; + if (index) + *index = e->index; + + return e->data; +} + +void* idxset_first(struct idxset *s, uint32_t *index) { + assert(s); - if (!s->rrobin) + if (!s->iterate_list_head) return NULL; if (index) - *index = s->rrobin->index; - - return s->rrobin->data; + *index = s->iterate_list_head->index; + return s->iterate_list_head->data; } + int idxset_foreach(struct idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata) { struct idxset_entry *e; assert(s && func); diff --git a/src/idxset.h b/src/idxset.h index f649e23e..fdcb7b54 100644 --- a/src/idxset.h +++ b/src/idxset.h @@ -18,8 +18,15 @@ void* idxset_get_by_data(struct idxset*s, void *p, uint32_t *index); void* idxset_remove_by_index(struct idxset*s, uint32_t index); void* idxset_remove_by_data(struct idxset*s, void *p, uint32_t *index); +/* This may be used to iterate through all entries. When called with + an invalid index value it returns the first entry, otherwise the + next following. The function is best called with *index = + IDXSET_VALID first. */ void* idxset_rrobin(struct idxset *s, uint32_t *index); +/* Return the oldest entry in the idxset */ +void* idxset_first(struct idxset *s, uint32_t *index); + int idxset_foreach(struct idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata); unsigned idxset_ncontents(struct idxset*s); diff --git a/src/inputstream.c b/src/inputstream.c index c7b4b4c7..81719288 100644 --- a/src/inputstream.c +++ b/src/inputstream.c @@ -14,6 +14,8 @@ struct input_stream* input_stream_new(struct sink *s, struct sample_spec *spec, i->name = name ? strdup(name) : NULL; i->sink = s; i->spec = *spec; + i->kill = NULL; + i->kill_userdata = NULL; i->memblockq = memblockq_new(bytes_per_second(spec)*5, sample_size(spec)); assert(i->memblockq); @@ -40,7 +42,7 @@ void input_stream_free(struct input_stream* i) { free(i); } -void input_stream_notify(struct input_stream *i) { +void input_stream_notify_sink(struct input_stream *i) { assert(i); if (memblockq_is_empty(i->memblockq)) @@ -48,3 +50,17 @@ void input_stream_notify(struct input_stream *i) { sink_notify(i->sink); } + +void input_stream_set_kill_callback(struct input_stream *i, void (*kill)(struct input_stream*i, void *userdata), void *userdata) { + assert(i && kill); + i->kill = kill; + i->kill_userdata = userdata; +} + + +void input_stream_kill(struct input_stream*i) { + assert(i); + + if (i->kill) + i->kill(i, i->kill_userdata); +} diff --git a/src/inputstream.h b/src/inputstream.h index 0353799e..a258c3d1 100644 --- a/src/inputstream.h +++ b/src/inputstream.h @@ -15,11 +15,26 @@ struct input_stream { struct sample_spec spec; struct memblockq *memblockq; + + void (*kill)(struct input_stream* i, void *userdata); + void *kill_userdata; }; struct input_stream* input_stream_new(struct sink *s, struct sample_spec *spec, const char *name); void input_stream_free(struct input_stream* i); -void input_stream_notify(struct input_stream *i); +/* This function notifies the attached sink that new data is available + * in the memblockq */ +void input_stream_notify_sink(struct input_stream *i); + + +/* The registrant of the input stream should call this function to set a + * callback function which is called when destruction of the input stream is + * requested */ +void input_stream_set_kill_callback(struct input_stream *c, void (*kill)(struct input_stream*i, void *userdata), void *userdata); + +/* Code that didn't create the input stream should call this function to + * request destruction of it */ +void input_stream_kill(struct input_stream *c); #endif diff --git a/src/memblockq.c b/src/memblockq.c index a422cf09..6437dd5b 100644 --- a/src/memblockq.c +++ b/src/memblockq.c @@ -119,6 +119,8 @@ void memblockq_drop(struct memblockq *bq, size_t length) { q = bq->blocks; bq->blocks = bq->blocks->next; + if (bq->blocks == NULL) + bq->blocks_tail = NULL; memblock_unref(q->chunk.memblock); free(q); diff --git a/src/outputstream.c b/src/outputstream.c index ffec77da..c6681d29 100644 --- a/src/outputstream.c +++ b/src/outputstream.c @@ -14,6 +14,8 @@ struct output_stream* output_stream_new(struct source *s, struct sample_spec *sp o->name = name ? strdup(name) : NULL; o->source = s; o->spec = *spec; + o->kill = NULL; + o->kill_userdata = NULL; o->memblockq = memblockq_new(bytes_per_second(spec)*5, sample_size(spec)); assert(o->memblockq); @@ -39,3 +41,17 @@ void output_stream_free(struct output_stream* o) { free(o->name); free(o); } + +void output_stream_set_kill_callback(struct output_stream *i, void (*kill)(struct output_stream*i, void *userdata), void *userdata) { + assert(i && kill); + i->kill = kill; + i->kill_userdata = userdata; +} + + +void output_stream_kill(struct output_stream*i) { + assert(i); + + if (i->kill) + i->kill(i, i->kill_userdata); +} diff --git a/src/outputstream.h b/src/outputstream.h index 41054341..c6c0a717 100644 --- a/src/outputstream.h +++ b/src/outputstream.h @@ -14,9 +14,14 @@ struct output_stream { struct sample_spec spec; struct memblockq *memblockq; + void (*kill)(struct output_stream* i, void *userdata); + void *kill_userdata; }; struct output_stream* output_stream_new(struct source *s, struct sample_spec *spec, const char *name); void output_stream_free(struct output_stream* o); +void output_stream_set_kill_callback(struct output_stream *i, void (*kill)(struct output_stream*i, void *userdata), void *userdata); +void output_stream_kill(struct output_stream*i); + #endif diff --git a/src/protocol-simple.c b/src/protocol-simple.c index e930f9ae..ec121faa 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -42,6 +42,30 @@ static void free_connection(void *data, void *userdata) { free(c); } +static void destroy_connection(struct connection *c) { + assert(c && c->protocol); + idxset_remove_by_data(c->protocol->connections, c, NULL); + free_connection(c, NULL); +} + +static void istream_kill_cb(struct input_stream *i, void *userdata) { + struct connection *c = userdata; + assert(i && c); + destroy_connection(c); +} + +static void ostream_kill_cb(struct output_stream *o, void *userdata) { + struct connection *c = userdata; + assert(o && c); + destroy_connection(c); +} + +static void client_kill_cb(struct client *client, void*userdata) { + struct connection *c= userdata; + assert(client && c); + destroy_connection(c); +} + static void io_callback(struct iochannel*io, void *userdata) { struct connection *c = userdata; assert(io && c); @@ -64,7 +88,7 @@ static void io_callback(struct iochannel*io, void *userdata) { chunk.index = 0; memblockq_push(c->istream->memblockq, &chunk, 0); - input_stream_notify(c->istream); + input_stream_notify_sink(c->istream); memblock_unref(chunk.memblock); } @@ -88,8 +112,7 @@ static void io_callback(struct iochannel*io, void *userdata) { return; fail: - idxset_remove_by_data(c->protocol->connections, c, NULL); - free_connection(c, NULL); + destroy_connection(c); } static void on_connection(struct socket_server*s, struct iochannel *io, void *userdata) { @@ -106,6 +129,7 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c->client = client_new(p->core, "SIMPLE", "Client"); assert(c->client); + client_set_kill_callback(c->client, client_kill_cb, c); if (p->mode & PROTOCOL_SIMPLE_RECORD) { struct source *source; @@ -117,6 +141,7 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c->ostream = output_stream_new(source, &DEFAULT_SAMPLE_SPEC, c->client->name); assert(c->ostream); + output_stream_set_kill_callback(c->ostream, ostream_kill_cb, c); } if (p->mode & PROTOCOL_SIMPLE_PLAYBACK) { @@ -129,6 +154,7 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c->istream = input_stream_new(sink, &DEFAULT_SAMPLE_SPEC, c->client->name); assert(c->istream); + input_stream_set_kill_callback(c->istream, istream_kill_cb, c); } diff --git a/src/sink.c b/src/sink.c index 02ca3468..dfe1bcb9 100644 --- a/src/sink.c +++ b/src/sink.c @@ -40,11 +40,14 @@ struct sink* sink_new(struct core *core, const char *name, const struct sample_s } void sink_free(struct sink *s) { - struct input_stream *i; + struct input_stream *i, *j = NULL; assert(s); - while ((i = idxset_rrobin(s->input_streams, NULL))) - input_stream_free(i); + while ((i = idxset_first(s->input_streams, NULL))) { + assert(i != j); + input_stream_kill(i); + j = i; + } idxset_free(s->input_streams, NULL, NULL); idxset_remove_by_data(s->core->sinks, s, NULL); diff --git a/src/source.c b/src/source.c index a1e7b245..2d5e9bbd 100644 --- a/src/source.c +++ b/src/source.c @@ -28,11 +28,14 @@ struct source* source_new(struct core *core, const char *name, const struct samp } void source_free(struct source *s) { - struct output_stream *o; + struct output_stream *o, *j = NULL; assert(s); - while ((o = idxset_rrobin(s->output_streams, NULL))) + while ((o = idxset_first(s->output_streams, NULL))) { + assert(o != j); output_stream_free(o); + j = o; + } idxset_free(s->output_streams, NULL, NULL); idxset_remove_by_data(s->core->sources, s, NULL); -- cgit From 0575fc66e9b175fef129a250697f07d7053e9108 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 14 Jun 2004 20:34:33 +0000 Subject: remove oss.c git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@12 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/oss.c | 30 ------------------------------ 1 file changed, 30 deletions(-) delete mode 100644 src/oss.c diff --git a/src/oss.c b/src/oss.c deleted file mode 100644 index 42e60360..00000000 --- a/src/oss.c +++ /dev/null @@ -1,30 +0,0 @@ -#include "module.h" - -struct userdata { - struct sink *sink; - struct source *source; - int fd; -}; - -int module_init(struct core *c, struct module*m) { - struct userdata *u; - assert(c && m); - - u = malloc(sizeof(struct userdata)); - assert(u); - memset(u, 0, sizeof(struct userdata)); - m->userdata = u; - - return 0; -} - -void module_done(struct core *c, struct module*m) { - struct userdata *u; - assert(c && m); - - u = m->userdata; - - sink_free(u->sink); - source_free(u->source); - free(u); -} -- cgit From f78e9b68cbc45015af05db497d1547c0e02d2751 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 14 Jun 2004 22:47:12 +0000 Subject: commit some work and rename git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@13 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 4 + src/mainloop.c | 27 ++--- src/mainloop.h | 4 +- src/module-oss.c | 234 +++++++++++++++++++++++++++++++++++++++ src/module-simple-protocol-tcp.c | 24 ++++ src/protocol-simple-tcp.c | 24 ---- src/pstream.c | 2 +- src/sink-pipe.c | 25 +++-- 8 files changed, 292 insertions(+), 52 deletions(-) create mode 100644 src/module-oss.c create mode 100644 src/module-simple-protocol-tcp.c delete mode 100644 src/protocol-simple-tcp.c diff --git a/src/Makefile.am b/src/Makefile.am index 485513df..d249964b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -56,3 +56,7 @@ protocol_simple_tcp_la_LIBADD = libprotocol-simple.la libiochannel.la sink_pipe_la_SOURCES = sink-pipe.c sink_pipe_la_LDFLAGS = -module -avoid-version sink_pipe_la_LIBADD = libiochannel.la + +sink_oss_la_SOURCES = sink-pipe.c +sink_oss_la_LDFLAGS = -module -avoid-version +sink_oss_la_LIBADD = libiochannel.la diff --git a/src/mainloop.c b/src/mainloop.c index 2992673a..37dbdb12 100644 --- a/src/mainloop.c +++ b/src/mainloop.c @@ -27,7 +27,7 @@ struct mainloop_source { struct { void (*callback)(struct mainloop_source*s, void *userdata); - } prepare; + } fixed; struct { void (*callback)(struct mainloop_source*s, void *userdata); @@ -47,7 +47,7 @@ struct mainloop_source_list { }; struct mainloop { - struct mainloop_source_list io_sources, prepare_sources, idle_sources, signal_sources; + struct mainloop_source_list io_sources, fixed_sources, idle_sources, signal_sources; struct pollfd *pollfds; int max_pollfds, n_pollfds; @@ -133,7 +133,7 @@ static void free_sources(struct mainloop_source_list *l, int all) { void mainloop_free(struct mainloop* m) { assert(m); free_sources(&m->io_sources, 1); - free_sources(&m->prepare_sources, 1); + free_sources(&m->fixed_sources, 1); free_sources(&m->idle_sources, 1); free_sources(&m->signal_sources, 1); @@ -237,14 +237,15 @@ int mainloop_iterate(struct mainloop *m, int block) { return m->quit; free_sources(&m->io_sources, 0); - free_sources(&m->prepare_sources, 0); + free_sources(&m->fixed_sources, 0); free_sources(&m->idle_sources, 0); + free_sources(&m->signal_sources, 0); - for (s = m->prepare_sources.sources; s; s = s->next) { - assert(!s->dead && s->type == MAINLOOP_SOURCE_TYPE_PREPARE); + for (s = m->fixed_sources.sources; s; s = s->next) { + assert(!s->dead && s->type == MAINLOOP_SOURCE_TYPE_FIXED); if (s->enabled) { - assert(s->prepare.callback); - s->prepare.callback(s, s->userdata); + assert(s->fixed.callback); + s->fixed.callback(s, s->userdata); } } @@ -293,8 +294,8 @@ static struct mainloop_source_list* get_source_list(struct mainloop *m, enum mai case MAINLOOP_SOURCE_TYPE_IO: l = &m->io_sources; break; - case MAINLOOP_SOURCE_TYPE_PREPARE: - l = &m->prepare_sources; + case MAINLOOP_SOURCE_TYPE_FIXED: + l = &m->fixed_sources; break; case MAINLOOP_SOURCE_TYPE_IDLE: l = &m->idle_sources; @@ -351,13 +352,13 @@ struct mainloop_source* mainloop_source_new_io(struct mainloop*m, int fd, enum m return s; } -struct mainloop_source* mainloop_source_new_prepare(struct mainloop*m, void (*callback)(struct mainloop_source *s, void*userdata), void*userdata) { +struct mainloop_source* mainloop_source_new_fixed(struct mainloop*m, void (*callback)(struct mainloop_source *s, void*userdata), void*userdata) { struct mainloop_source* s; assert(m && callback); - s = source_new(m, MAINLOOP_SOURCE_TYPE_PREPARE); + s = source_new(m, MAINLOOP_SOURCE_TYPE_FIXED); - s->prepare.callback = callback; + s->fixed.callback = callback; s->userdata = userdata; s->enabled = 1; return s; diff --git a/src/mainloop.h b/src/mainloop.h index 3c6d7e37..3fe26fd0 100644 --- a/src/mainloop.h +++ b/src/mainloop.h @@ -13,7 +13,7 @@ enum mainloop_io_event { enum mainloop_source_type { MAINLOOP_SOURCE_TYPE_IO, - MAINLOOP_SOURCE_TYPE_PREPARE, + MAINLOOP_SOURCE_TYPE_FIXED, MAINLOOP_SOURCE_TYPE_IDLE, MAINLOOP_SOURCE_TYPE_SIGNAL }; @@ -26,7 +26,7 @@ int mainloop_run(struct mainloop *m); void mainloop_quit(struct mainloop *m, int r); struct mainloop_source* mainloop_source_new_io(struct mainloop*m, int fd, enum mainloop_io_event event, void (*callback)(struct mainloop_source*s, int fd, enum mainloop_io_event event, void *userdata), void *userdata); -struct mainloop_source* mainloop_source_new_prepare(struct mainloop*m, void (*callback)(struct mainloop_source *s, void*userdata), void*userdata); +struct mainloop_source* mainloop_source_new_fixed(struct mainloop*m, void (*callback)(struct mainloop_source *s, void*userdata), void*userdata); struct mainloop_source* mainloop_source_new_idle(struct mainloop*m, void (*callback)(struct mainloop_source *s, void*userdata), void*userdata); struct mainloop_source* mainloop_source_new_signal(struct mainloop*m, int sig, void (*callback)(struct mainloop_source *s, int sig, void*userdata), void*userdata); diff --git a/src/module-oss.c b/src/module-oss.c new file mode 100644 index 00000000..b2b106b4 --- /dev/null +++ b/src/module-oss.c @@ -0,0 +1,234 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iochannel.h" +#include "sink.h" +#include "source.h" +#include "module.h" + +struct userdata { + struct sink *sink; + struct source *source; + struct iochannel *io; + struct core *core; + + struct memchunk memchunk, silence; + + uint32_t fragment_size; +}; + +static void do_write(struct userdata *u) { + struct memchunk *memchunk; + ssize_t r; + assert(u); + + if (!iochannel_is_writable(u->io)) + return; + + if (!u->memchunk.length) { + if (sink_render(u->sink, fragment_size, &u->memchunk) < 0) + memchunk = &u->silence; + else + memchunk = &u->memchunk; + } + + assert(memchunk->memblock && memchunk->length); + + if ((r = iochannel_write(u->io, memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { + fprintf(stderr, "write() failed: %s\n", strerror(errno)); + return; + } + + if (memchunk == &u->silence) + assert(r % u->sample_size == 0); + else { + u->memchunk.index += r; + u->memchunk.length -= r; + + if (u->memchunk.length <= 0) { + memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + } + } +} + +static void do_read(struct userdata *u) { + struct memchunk memchunk; + ssize_t r; + assert(u); + + if (!iochannel_is_readable(u->io)) + return; + + memchunk.memblock = memblock_new(u->fragment_size); + assert(memchunk.memblock); + if ((r = iochannel_read(u->io, memchunk.memblock->data, memchunk->memblock->length)) < 0) { + memblock_unref(memchunk.memblock); + fprintf(stderr, "read() failed: %s\n", strerror(errno)); + return; + } + + assert(r < memchunk->memblock->length); + memchunk.length = memchunk.memblock->length = r; + memchunk.index = 0; + + source_post(u->source, &memchunk); + memblock_unref(memchunk.memblock); +}; + +static void io_callback(struct iochannel *io, void*userdata) { + struct userdata *u = userdata; + assert(u); + do_write(u); + do_read(u); +} + +int module_init(struct core *c, struct module*m) { + struct userdata *u = NULL; + struct stat st; + char *p; + int fd = -1; + int format, channels, speed, frag_size; + int m; + const static struct sample_spec ss; + assert(c && m); + + p = m->argument ? m->argument : "/dev/dsp"; + if ((fd = open(p, m = O_RDWR)) >= 0) { + int caps; + + ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0); + + if (ioctl(fd, SNDCTL_DSP_GETCAPS, &caps) < 0) { + fprintf(stderr, "SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); + goto fail; + } + + if (!(caps & DSP_CAP_DUPLEX)) { + close(fd); + fd = -1; + } + } + + if (fd < 0) { + if ((fd = open(p, m = O_WRONLY)) < 0) { + if ((fd = open(p, m = O_RDONLY)) < 0) { + fprintf(stderr, "open('%s'): %s\n", p, strerror(errno)); + goto fail; + } + } + } + + frags = 0x7fff0000 | (10 << 16); /* 1024 bytes fragment size */ + if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frags) < 0) { + fprintf(stderr, "SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno)); + goto fail; + } + + format = AFMT_S16_NE; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_S16_NE) { + int f = AFMT_S16_NE == AFMT_S16_LE ? AFMT_S16_BE : AFMT_S16_LE; + format = f; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != f) { + format = AFMT_U8; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_U8) { + fprintf(stderr, "SNDCTL_DSP_SETFMT: %s\n", format != AFMT_U8 ? "No supported sample format" : strerror(errno)); + goto fail; + } else + ss.format = SAMPLE_U8; + } else + ss.format = f == AFMT_S16_LE ? SAMPLE_S16LE : SAMPLE_S16BE; + } else + ss.format = SAMPLE_S16NE; + + channels = 2; + if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) { + fprintf(stderr, "SNDCTL_DSP_CHANNELS: %s\n", strerror(errno)); + goto fail; + } + assert(channels); + ss.channels = channels; + + speed = 44100; + if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) { + fprintf(stderr, "SNDCTL_DSP_SPEED: %s\n", strerror(errno)); + goto fail; + } + assert(speed); + ss.rate = speed; + + if (ioctl(fd, SNCTL_DSP_GETBLKSIZE, &frag_size) < 0) { + fprintf(stderr, "SNDCTL_DSP_GETBLKSIZE: %s\n", strerror(errno)); + goto fail; + } + + assert(frag_size); + + u = malloc(sizeof(struct userdata)); + assert(u); + + u->core = c; + + if (m != O_RDONLY) { + u->sink = sink_new(c, "dsp", &ss); + assert(u->sink); + } else + u->sink = NULL; + + if (m != O_WRONLY) { + u->source = source_new(c, "dsp", &ss); + assert(u->source); + } else + u->source = NULL; + + assert(u->source || u->sink); + + u->io = iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : 0); + assert(u->io); + iochannel_set_callback(u->io, io_callback, u); + + u->memchunk.memblock = NULL; + u->memchunk.length = 0; + + u->fragment_size = frag_size; + u->silence.memblock = memblock_new(u->fragment_size); + assert(u->silence); + u->silence.length = u->fragment_size; + u->silence.index = 0; + + m->userdata = u; + + return 0; + +fail: + if (fd >= 0) + close(fd); + + return -1; +} + +void module_done(struct core *c, struct module*m) { + struct userdata *u; + assert(c && m); + + u = m->userdata; + assert(u); + + if (u->memchunk.memblock) + memblock_unref(u->memchunk.memblock); + if (u->silence.memblock) + memblock_unref(u->silence.memblock); + + sink_free(u->sink); + source_free(u->source); + iochannel_free(u->io); + free(u); +} diff --git a/src/module-simple-protocol-tcp.c b/src/module-simple-protocol-tcp.c new file mode 100644 index 00000000..e71d7142 --- /dev/null +++ b/src/module-simple-protocol-tcp.c @@ -0,0 +1,24 @@ +#include +#include + +#include "module.h" +#include "socket-server.h" +#include "protocol-simple.h" + +int module_init(struct core *c, struct module*m) { + struct socket_server *s; + assert(c && m); + + if (!(s = socket_server_new_ipv4(c->mainloop, INADDR_LOOPBACK, 4712))) + return -1; + + m->userdata = protocol_simple_new(c, s, PROTOCOL_SIMPLE_PLAYBACK); + assert(m->userdata); + return 0; +} + +void module_done(struct core *c, struct module*m) { + assert(c && m); + + protocol_simple_free(m->userdata); +} diff --git a/src/protocol-simple-tcp.c b/src/protocol-simple-tcp.c deleted file mode 100644 index e71d7142..00000000 --- a/src/protocol-simple-tcp.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include - -#include "module.h" -#include "socket-server.h" -#include "protocol-simple.h" - -int module_init(struct core *c, struct module*m) { - struct socket_server *s; - assert(c && m); - - if (!(s = socket_server_new_ipv4(c->mainloop, INADDR_LOOPBACK, 4712))) - return -1; - - m->userdata = protocol_simple_new(c, s, PROTOCOL_SIMPLE_PLAYBACK); - assert(m->userdata); - return 0; -} - -void module_done(struct core *c, struct module*m) { - assert(c && m); - - protocol_simple_free(m->userdata); -} diff --git a/src/pstream.c b/src/pstream.c index 083ebc22..0336d161 100644 --- a/src/pstream.c +++ b/src/pstream.c @@ -91,7 +91,7 @@ struct pstream *pstream_new(struct mainloop *m, struct iochannel *io) { p->dead = 0; p->mainloop = m; - p->mainloop_source = mainloop_source_new_prepare(m, prepare_callback, p); + p->mainloop_source = mainloop_source_new_fixed(m, prepare_callback, p); mainloop_source_enable(p->mainloop_source, 0); p->send_queue = queue_new(); diff --git a/src/sink-pipe.c b/src/sink-pipe.c index 78ea7bf2..e63a7a86 100644 --- a/src/sink-pipe.c +++ b/src/sink-pipe.c @@ -13,6 +13,8 @@ #include "module.h" struct userdata { + char *filename; + struct sink *sink; struct iochannel *io; struct core *core; @@ -73,7 +75,6 @@ static void io_callback(struct iochannel *io, void*userdata) { int module_init(struct core *c, struct module*m) { struct userdata *u = NULL; struct stat st; - struct sink *sink; char *p; int fd = -1; const static struct sample_spec ss = { @@ -100,17 +101,16 @@ int module_init(struct core *c, struct module*m) { goto fail; } - if (!(sink = sink_new(c, "fifo", &ss))) { - fprintf(stderr, "Failed to allocate new sink!\n"); - goto fail; - } u = malloc(sizeof(struct userdata)); assert(u); + u->filename = strdup(p); + assert(u->filename); u->core = c; - u->sink = sink; - sink_set_notify_callback(sink, notify_callback, u); + u->sink = sink_new(c, "fifo", &ss); + assert(u->sink); + sink_set_notify_callback(u->sink, notify_callback, u); u->io = iochannel_new(c->mainloop, -1, fd); assert(u->io); @@ -119,22 +119,18 @@ int module_init(struct core *c, struct module*m) { u->memchunk.memblock = NULL; u->memchunk.length = 0; - u->mainloop_source = mainloop_source_new_prepare(c->mainloop, prepare_callback, u); + u->mainloop_source = mainloop_source_new_fixed(c->mainloop, prepare_callback, u); assert(u->mainloop_source); mainloop_source_enable(u->mainloop_source, 0); m->userdata = u; - return 0; fail: if (fd >= 0) close(fd); - if (u) - free(u); - return -1; } @@ -151,5 +147,10 @@ void module_done(struct core *c, struct module*m) { sink_free(u->sink); iochannel_free(u->io); mainloop_source_free(u->mainloop_source); + + assert(u->filename); + unlink(u->filename); + free(u->filename); + free(u); } -- cgit From bfcde99a8f7fe31be504e1d55c4a065c760bb533 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 14 Jun 2004 22:47:29 +0000 Subject: rename some more git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@14 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/module-pipe-sink.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++ src/sink-pipe.c | 156 ------------------------------------------------- 2 files changed, 156 insertions(+), 156 deletions(-) create mode 100644 src/module-pipe-sink.c delete mode 100644 src/sink-pipe.c diff --git a/src/module-pipe-sink.c b/src/module-pipe-sink.c new file mode 100644 index 00000000..e63a7a86 --- /dev/null +++ b/src/module-pipe-sink.c @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iochannel.h" +#include "sink.h" +#include "module.h" + +struct userdata { + char *filename; + + struct sink *sink; + struct iochannel *io; + struct core *core; + struct mainloop_source *mainloop_source; + + struct memchunk memchunk; +}; + +static void do_write(struct userdata *u) { + ssize_t r; + assert(u); + + mainloop_source_enable(u->mainloop_source, 0); + + if (!iochannel_is_writable(u->io)) + return; + + if (!u->memchunk.length) + if (sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0) + return; + + assert(u->memchunk.memblock && u->memchunk.length); + + if ((r = iochannel_write(u->io, u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { + fprintf(stderr, "write() failed: %s\n", strerror(errno)); + return; + } + + u->memchunk.index += r; + u->memchunk.length -= r; + + if (u->memchunk.length <= 0) { + memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + } +} + +static void notify_callback(struct sink*s, void *userdata) { + struct userdata *u = userdata; + assert(u); + + if (iochannel_is_writable(u->io)) + mainloop_source_enable(u->mainloop_source, 1); +} + +static void prepare_callback(struct mainloop_source *src, void *userdata) { + struct userdata *u = userdata; + assert(u); + do_write(u); +} + +static void io_callback(struct iochannel *io, void*userdata) { + struct userdata *u = userdata; + assert(u); + do_write(u); +} + +int module_init(struct core *c, struct module*m) { + struct userdata *u = NULL; + struct stat st; + char *p; + int fd = -1; + const static struct sample_spec ss = { + .format = SAMPLE_S16NE, + .rate = 44100, + .channels = 2, + }; + assert(c && m); + + mkfifo((p = m->argument ? m->argument : "/tmp/musicfifo"), 0777); + + if ((fd = open(p, O_RDWR)) < 0) { + fprintf(stderr, "open('%s'): %s\n", p, strerror(errno)); + goto fail; + } + + if (fstat(fd, &st) < 0) { + fprintf(stderr, "fstat('%s'): %s\n", p, strerror(errno)); + goto fail; + } + + if (!S_ISFIFO(st.st_mode)) { + fprintf(stderr, "'%s' is not a FIFO\n", p); + goto fail; + } + + + u = malloc(sizeof(struct userdata)); + assert(u); + + u->filename = strdup(p); + assert(u->filename); + u->core = c; + u->sink = sink_new(c, "fifo", &ss); + assert(u->sink); + sink_set_notify_callback(u->sink, notify_callback, u); + + u->io = iochannel_new(c->mainloop, -1, fd); + assert(u->io); + iochannel_set_callback(u->io, io_callback, u); + + u->memchunk.memblock = NULL; + u->memchunk.length = 0; + + u->mainloop_source = mainloop_source_new_fixed(c->mainloop, prepare_callback, u); + assert(u->mainloop_source); + mainloop_source_enable(u->mainloop_source, 0); + + m->userdata = u; + + return 0; + +fail: + if (fd >= 0) + close(fd); + + return -1; +} + +void module_done(struct core *c, struct module*m) { + struct userdata *u; + assert(c && m); + + u = m->userdata; + assert(u); + + if (u->memchunk.memblock) + memblock_unref(u->memchunk.memblock); + + sink_free(u->sink); + iochannel_free(u->io); + mainloop_source_free(u->mainloop_source); + + assert(u->filename); + unlink(u->filename); + free(u->filename); + + free(u); +} diff --git a/src/sink-pipe.c b/src/sink-pipe.c deleted file mode 100644 index e63a7a86..00000000 --- a/src/sink-pipe.c +++ /dev/null @@ -1,156 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "iochannel.h" -#include "sink.h" -#include "module.h" - -struct userdata { - char *filename; - - struct sink *sink; - struct iochannel *io; - struct core *core; - struct mainloop_source *mainloop_source; - - struct memchunk memchunk; -}; - -static void do_write(struct userdata *u) { - ssize_t r; - assert(u); - - mainloop_source_enable(u->mainloop_source, 0); - - if (!iochannel_is_writable(u->io)) - return; - - if (!u->memchunk.length) - if (sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0) - return; - - assert(u->memchunk.memblock && u->memchunk.length); - - if ((r = iochannel_write(u->io, u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { - fprintf(stderr, "write() failed: %s\n", strerror(errno)); - return; - } - - u->memchunk.index += r; - u->memchunk.length -= r; - - if (u->memchunk.length <= 0) { - memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - } -} - -static void notify_callback(struct sink*s, void *userdata) { - struct userdata *u = userdata; - assert(u); - - if (iochannel_is_writable(u->io)) - mainloop_source_enable(u->mainloop_source, 1); -} - -static void prepare_callback(struct mainloop_source *src, void *userdata) { - struct userdata *u = userdata; - assert(u); - do_write(u); -} - -static void io_callback(struct iochannel *io, void*userdata) { - struct userdata *u = userdata; - assert(u); - do_write(u); -} - -int module_init(struct core *c, struct module*m) { - struct userdata *u = NULL; - struct stat st; - char *p; - int fd = -1; - const static struct sample_spec ss = { - .format = SAMPLE_S16NE, - .rate = 44100, - .channels = 2, - }; - assert(c && m); - - mkfifo((p = m->argument ? m->argument : "/tmp/musicfifo"), 0777); - - if ((fd = open(p, O_RDWR)) < 0) { - fprintf(stderr, "open('%s'): %s\n", p, strerror(errno)); - goto fail; - } - - if (fstat(fd, &st) < 0) { - fprintf(stderr, "fstat('%s'): %s\n", p, strerror(errno)); - goto fail; - } - - if (!S_ISFIFO(st.st_mode)) { - fprintf(stderr, "'%s' is not a FIFO\n", p); - goto fail; - } - - - u = malloc(sizeof(struct userdata)); - assert(u); - - u->filename = strdup(p); - assert(u->filename); - u->core = c; - u->sink = sink_new(c, "fifo", &ss); - assert(u->sink); - sink_set_notify_callback(u->sink, notify_callback, u); - - u->io = iochannel_new(c->mainloop, -1, fd); - assert(u->io); - iochannel_set_callback(u->io, io_callback, u); - - u->memchunk.memblock = NULL; - u->memchunk.length = 0; - - u->mainloop_source = mainloop_source_new_fixed(c->mainloop, prepare_callback, u); - assert(u->mainloop_source); - mainloop_source_enable(u->mainloop_source, 0); - - m->userdata = u; - - return 0; - -fail: - if (fd >= 0) - close(fd); - - return -1; -} - -void module_done(struct core *c, struct module*m) { - struct userdata *u; - assert(c && m); - - u = m->userdata; - assert(u); - - if (u->memchunk.memblock) - memblock_unref(u->memchunk.memblock); - - sink_free(u->sink); - iochannel_free(u->io); - mainloop_source_free(u->mainloop_source); - - assert(u->filename); - unlink(u->filename); - free(u->filename); - - free(u); -} -- cgit From 1a5060720d67fa6e4d4cb3b08c5067ec5216b0fd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 15 Jun 2004 00:29:01 +0000 Subject: oss output works git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@15 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 23 +++++++------ src/inputstream.c | 20 +++++++++-- src/inputstream.h | 14 ++++++-- src/main.c | 5 +-- src/memblockq.c | 30 +++++++++++++--- src/memblockq.h | 5 +-- src/module-oss.c | 63 ++++++++++++++++++++-------------- src/outputstream.c | 2 +- src/protocol-simple.c | 95 +++++++++++++++++++++++++++++++-------------------- src/sink.c | 20 +++++++---- src/sink.h | 4 +-- src/todo | 16 +++++++++ 12 files changed, 202 insertions(+), 95 deletions(-) create mode 100644 src/todo diff --git a/src/Makefile.am b/src/Makefile.am index d249964b..f0953846 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -20,8 +20,9 @@ AM_CFLAGS=-ansi -D_GNU_SOURCE bin_PROGRAMS = polypaudio -pkglib_LTLIBRARIES=libprotocol-simple.la protocol-simple-tcp.la \ - libsocket-server.la sink-pipe.la libpstream.la libiochannel.la libpacket.la +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 polypaudio_SOURCES = idxset.c queue.c strbuf.c mainloop.c \ memblock.c sample.c memblockq.c client.c \ @@ -49,14 +50,14 @@ libiochannel_la_LDFLAGS = -avoid-version libpacket_la_SOURCES = packet.c libpacket_la_LDFLAGS = -avoid-version -protocol_simple_tcp_la_SOURCES = protocol-simple-tcp.c -protocol_simple_tcp_la_LDFLAGS = -module -avoid-version -protocol_simple_tcp_la_LIBADD = libprotocol-simple.la libiochannel.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 -sink_pipe_la_SOURCES = sink-pipe.c -sink_pipe_la_LDFLAGS = -module -avoid-version -sink_pipe_la_LIBADD = libiochannel.la +module_pipe_sink_la_SOURCES = module-pipe-sink.c +module_pipe_sink_la_LDFLAGS = -module -avoid-version +module_pipe_sink_la_LIBADD = libiochannel.la -sink_oss_la_SOURCES = sink-pipe.c -sink_oss_la_LDFLAGS = -module -avoid-version -sink_oss_la_LIBADD = libiochannel.la +module_oss_la_SOURCES = module-oss.c +module_oss_la_LDFLAGS = -module -avoid-version +module_oss_la_LIBADD = libiochannel.la diff --git a/src/inputstream.c b/src/inputstream.c index 81719288..7ece3b5c 100644 --- a/src/inputstream.c +++ b/src/inputstream.c @@ -14,10 +14,13 @@ struct input_stream* input_stream_new(struct sink *s, struct sample_spec *spec, i->name = name ? strdup(name) : NULL; i->sink = s; i->spec = *spec; + i->kill = NULL; i->kill_userdata = NULL; + i->notify = NULL; + i->notify_userdata = NULL; - i->memblockq = memblockq_new(bytes_per_second(spec)*5, sample_size(spec)); + i->memblockq = memblockq_new(bytes_per_second(spec)*5, sample_size(spec), (size_t) -1); assert(i->memblockq); assert(s->core); @@ -45,7 +48,7 @@ void input_stream_free(struct input_stream* i) { void input_stream_notify_sink(struct input_stream *i) { assert(i); - if (memblockq_is_empty(i->memblockq)) + if (!memblockq_is_readable(i->memblockq)) return; sink_notify(i->sink); @@ -64,3 +67,16 @@ void input_stream_kill(struct input_stream*i) { if (i->kill) i->kill(i, i->kill_userdata); } + +void input_stream_set_notify_callback(struct input_stream *i, void (*notify)(struct input_stream*i, void *userdata), void *userdata) { + assert(i && notify); + + i->notify = notify; + i->notify_userdata = userdata; +} + +void input_stream_notify(struct input_stream *i) { + assert(i); + if (i->notify) + i->notify(i, i->notify_userdata); +} diff --git a/src/inputstream.h b/src/inputstream.h index a258c3d1..544c3318 100644 --- a/src/inputstream.h +++ b/src/inputstream.h @@ -18,6 +18,9 @@ struct input_stream { void (*kill)(struct input_stream* i, void *userdata); void *kill_userdata; + + void (*notify)(struct input_stream*i, void *userdata); + void *notify_userdata; }; struct input_stream* input_stream_new(struct sink *s, struct sample_spec *spec, const char *name); @@ -31,10 +34,17 @@ void input_stream_notify_sink(struct input_stream *i); /* The registrant of the input stream should call this function to set a * callback function which is called when destruction of the input stream is * requested */ -void input_stream_set_kill_callback(struct input_stream *c, void (*kill)(struct input_stream*i, void *userdata), void *userdata); +void input_stream_set_kill_callback(struct input_stream *i, void (*kill)(struct input_stream*i, void *userdata), void *userdata); /* Code that didn't create the input stream should call this function to * request destruction of it */ -void input_stream_kill(struct input_stream *c); +void input_stream_kill(struct input_stream *i); + +/* Notify the code that created this input stream that some data has + * been removed from the memblockq */ +void input_stream_set_notify_callback(struct input_stream *i, void (*notify)(struct input_stream*i, void *userdata), void *userdata); + +void input_stream_notify(struct input_stream *i); + #endif diff --git a/src/main.c b/src/main.c index 436dd30b..d54bee0a 100644 --- a/src/main.c +++ b/src/main.c @@ -29,8 +29,9 @@ int main(int argc, char *argv[]) { mainloop_source_new_signal(m, SIGINT, signal_callback, NULL); signal(SIGPIPE, SIG_IGN); - module_load(c, "sink-pipe", NULL); - module_load(c, "protocol-simple-tcp", NULL); + module_load(c, "module-oss", NULL); + module_load(c, "module-pipe-sink", NULL); + module_load(c, "module-simple-protocol-tcp", NULL); mainloop_run(m); diff --git a/src/memblockq.c b/src/memblockq.c index 6437dd5b..b25adc65 100644 --- a/src/memblockq.c +++ b/src/memblockq.c @@ -1,3 +1,4 @@ +#include #include #include @@ -14,9 +15,10 @@ struct memblockq { size_t total_length; size_t maxlength; size_t base; + size_t prebuf; }; -struct memblockq* memblockq_new(size_t maxlength, size_t base) { +struct memblockq* memblockq_new(size_t maxlength, size_t base, size_t prebuf) { struct memblockq* bq; assert(maxlength && base); @@ -27,6 +29,11 @@ struct memblockq* memblockq_new(size_t maxlength, size_t base) { bq->total_length = 0; bq->base = base; bq->maxlength = ((maxlength+base-1)/base)*base; + bq->prebuf = prebuf == (size_t) -1 ? bq->maxlength/2 : prebuf; + + if (bq->prebuf > bq->maxlength) + bq->prebuf = bq->maxlength; + assert(bq->maxlength >= base); return bq; } @@ -72,9 +79,11 @@ void memblockq_push(struct memblockq* bq, struct memchunk *chunk, size_t delta) int memblockq_peek(struct memblockq* bq, struct memchunk *chunk) { assert(bq && chunk); - if (!bq->blocks) + if (!bq->blocks || bq->total_length < bq->prebuf) return -1; + bq->prebuf = 0; + *chunk = bq->blocks->chunk; memblock_ref(chunk->memblock); return 0; @@ -85,9 +94,11 @@ int memblockq_pop(struct memblockq* bq, struct memchunk *chunk) { assert(bq && chunk); - if (!bq->blocks) + if (!bq->blocks || bq->total_length < bq->prebuf) return -1; + bq->prebuf = 0; + q = bq->blocks; bq->blocks = bq->blocks->next; @@ -138,6 +149,8 @@ void memblockq_shorten(struct memblockq *bq, size_t length) { if (bq->total_length <= length) return; + fprintf(stderr, "Warning! memblockq_shorten()\n"); + l = bq->total_length - length; l /= bq->base; l *= bq->base; @@ -151,8 +164,15 @@ void memblockq_empty(struct memblockq *bq) { memblockq_shorten(bq, 0); } -int memblockq_is_empty(struct memblockq *bq) { +int memblockq_is_readable(struct memblockq *bq) { + assert(bq); + + return bq->total_length >= bq->prebuf; +} + +int memblockq_is_writable(struct memblockq *bq, size_t length) { assert(bq); - return bq->total_length < bq->base; + assert(length <= bq->maxlength); + return bq->total_length + length <= bq->maxlength; } diff --git a/src/memblockq.h b/src/memblockq.h index 75c5e59e..48050d49 100644 --- a/src/memblockq.h +++ b/src/memblockq.h @@ -7,7 +7,7 @@ struct memblockq; -struct memblockq* memblockq_new(size_t maxlength, size_t base); +struct memblockq* memblockq_new(size_t maxlength, size_t base, size_t prebuf); void memblockq_free(struct memblockq* bq); void memblockq_push(struct memblockq* bq, struct memchunk *chunk, size_t delta); @@ -19,6 +19,7 @@ void memblockq_drop(struct memblockq *bq, size_t length); void memblockq_shorten(struct memblockq *bq, size_t length); void memblockq_empty(struct memblockq *bq); -int memblockq_is_empty(struct memblockq *bq); +int memblockq_is_readable(struct memblockq *bq); +int memblockq_is_writable(struct memblockq *bq, size_t length); #endif diff --git a/src/module-oss.c b/src/module-oss.c index b2b106b4..7a1482e7 100644 --- a/src/module-oss.c +++ b/src/module-oss.c @@ -1,4 +1,5 @@ -#include +#include +#include #include #include #include @@ -22,7 +23,7 @@ struct userdata { struct memchunk memchunk, silence; - uint32_t fragment_size; + uint32_t in_fragment_size, out_fragment_size, sample_size; }; static void do_write(struct userdata *u) { @@ -34,7 +35,7 @@ static void do_write(struct userdata *u) { return; if (!u->memchunk.length) { - if (sink_render(u->sink, fragment_size, &u->memchunk) < 0) + if (sink_render(u->sink, u->out_fragment_size, &u->memchunk) < 0) memchunk = &u->silence; else memchunk = &u->memchunk; @@ -68,15 +69,15 @@ static void do_read(struct userdata *u) { if (!iochannel_is_readable(u->io)) return; - memchunk.memblock = memblock_new(u->fragment_size); + memchunk.memblock = memblock_new(u->in_fragment_size); assert(memchunk.memblock); - if ((r = iochannel_read(u->io, memchunk.memblock->data, memchunk->memblock->length)) < 0) { + if ((r = iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { memblock_unref(memchunk.memblock); fprintf(stderr, "read() failed: %s\n", strerror(errno)); return; } - assert(r < memchunk->memblock->length); + assert(r <= memchunk.memblock->length); memchunk.length = memchunk.memblock->length = r; memchunk.index = 0; @@ -92,17 +93,17 @@ static void io_callback(struct iochannel *io, void*userdata) { } int module_init(struct core *c, struct module*m) { + struct audio_buf_info info; struct userdata *u = NULL; - struct stat st; char *p; int fd = -1; - int format, channels, speed, frag_size; - int m; - const static struct sample_spec ss; + int format, channels, speed, frag_size, in_frag_size, out_frag_size; + int mode; + struct sample_spec ss; assert(c && m); p = m->argument ? m->argument : "/dev/dsp"; - if ((fd = open(p, m = O_RDWR)) >= 0) { + if ((fd = open(p, mode = O_RDWR)) >= 0) { int caps; ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0); @@ -119,16 +120,16 @@ int module_init(struct core *c, struct module*m) { } if (fd < 0) { - if ((fd = open(p, m = O_WRONLY)) < 0) { - if ((fd = open(p, m = O_RDONLY)) < 0) { + if ((fd = open(p, mode = O_WRONLY)) < 0) { + if ((fd = open(p, mode = O_RDONLY)) < 0) { fprintf(stderr, "open('%s'): %s\n", p, strerror(errno)); goto fail; } } } - - frags = 0x7fff0000 | (10 << 16); /* 1024 bytes fragment size */ - if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frags) < 0) { + + frag_size = ((int) 0x7ffff << 4) | 10; /* nfrags = 4; frag_size = 2^10 */ + if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag_size) < 0) { fprintf(stderr, "SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno)); goto fail; } @@ -165,25 +166,35 @@ int module_init(struct core *c, struct module*m) { assert(speed); ss.rate = speed; - if (ioctl(fd, SNCTL_DSP_GETBLKSIZE, &frag_size) < 0) { + if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) { fprintf(stderr, "SNDCTL_DSP_GETBLKSIZE: %s\n", strerror(errno)); goto fail; } - assert(frag_size); - + in_frag_size = out_frag_size = frag_size; + + if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { + fprintf(stderr, "INPUT: %u fragments of size %u.\n", info.fragstotal, info.fragsize); + in_frag_size = info.fragsize; + } + + if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) { + fprintf(stderr, "OUTUT: %u fragments of size %u.\n", info.fragstotal, info.fragsize); + out_frag_size = info.fragsize; + } + u = malloc(sizeof(struct userdata)); assert(u); u->core = c; - if (m != O_RDONLY) { + if (mode != O_RDONLY) { u->sink = sink_new(c, "dsp", &ss); assert(u->sink); } else u->sink = NULL; - if (m != O_WRONLY) { + if (mode != O_WRONLY) { u->source = source_new(c, "dsp", &ss); assert(u->source); } else @@ -197,11 +208,13 @@ int module_init(struct core *c, struct module*m) { u->memchunk.memblock = NULL; u->memchunk.length = 0; + u->sample_size = sample_size(&ss); - u->fragment_size = frag_size; - u->silence.memblock = memblock_new(u->fragment_size); - assert(u->silence); - u->silence.length = u->fragment_size; + u->out_fragment_size = out_frag_size; + u->in_fragment_size = in_frag_size; + u->silence.memblock = memblock_new(u->silence.length = u->out_fragment_size); + assert(u->silence.memblock); + silence(u->silence.memblock, &ss); u->silence.index = 0; m->userdata = u; diff --git a/src/outputstream.c b/src/outputstream.c index c6681d29..c3f68a0e 100644 --- a/src/outputstream.c +++ b/src/outputstream.c @@ -17,7 +17,7 @@ struct output_stream* output_stream_new(struct source *s, struct sample_spec *sp o->kill = NULL; o->kill_userdata = NULL; - o->memblockq = memblockq_new(bytes_per_second(spec)*5, sample_size(spec)); + o->memblockq = memblockq_new(bytes_per_second(spec)*5, sample_size(spec), (size_t) -1); assert(o->memblockq); assert(s->core); diff --git a/src/protocol-simple.c b/src/protocol-simple.c index ec121faa..1c462b39 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -66,53 +66,73 @@ static void client_kill_cb(struct client *client, void*userdata) { destroy_connection(c); } -static void io_callback(struct iochannel*io, void *userdata) { - struct connection *c = userdata; - assert(io && c); - - if (c->istream && iochannel_is_readable(io)) { - struct memchunk chunk; - ssize_t r; - - chunk.memblock = memblock_new(BUFSIZE); - assert(chunk.memblock); +static int do_read(struct connection *c) { + struct memchunk chunk; + ssize_t r; - if ((r = iochannel_read(io, chunk.memblock->data, BUFSIZE)) <= 0) { - fprintf(stderr, "read(): %s\n", r == 0 ? "EOF" : strerror(errno)); - memblock_unref(chunk.memblock); - goto fail; - } - - chunk.memblock->length = r; - chunk.length = r; - chunk.index = 0; - - memblockq_push(c->istream->memblockq, &chunk, 0); - input_stream_notify_sink(c->istream); + if (!iochannel_is_readable(c->io)) + return 0; + + if (!c->istream || !memblockq_is_writable(c->istream->memblockq, BUFSIZE)) + return 0; + + chunk.memblock = memblock_new(BUFSIZE); + assert(chunk.memblock); + + if ((r = iochannel_read(c->io, chunk.memblock->data, BUFSIZE)) <= 0) { + fprintf(stderr, "read(): %s\n", r == 0 ? "EOF" : strerror(errno)); memblock_unref(chunk.memblock); + return -1; } + + chunk.memblock->length = r; + chunk.length = r; + chunk.index = 0; + + memblockq_push(c->istream->memblockq, &chunk, 0); + input_stream_notify_sink(c->istream); + memblock_unref(chunk.memblock); + return 0; +} - if (c->ostream && iochannel_is_writable(io)) { - struct memchunk chunk; - ssize_t r; +static int do_write(struct connection *c) { + struct memchunk chunk; + ssize_t r; - memblockq_peek(c->ostream->memblockq, &chunk); - assert(chunk.memblock && chunk.length); + if (!iochannel_is_writable(c->io)) + return 0; + + if (!c->ostream) + return 0; - if ((r = iochannel_write(io, chunk.memblock->data+chunk.index, chunk.length)) < 0) { - fprintf(stderr, "write(): %s\n", strerror(errno)); - memblock_unref(chunk.memblock); - goto fail; - } - - memblockq_drop(c->ostream->memblockq, r); + memblockq_peek(c->ostream->memblockq, &chunk); + assert(chunk.memblock && chunk.length); + + if ((r = iochannel_write(c->io, chunk.memblock->data+chunk.index, chunk.length)) < 0) { + fprintf(stderr, "write(): %s\n", strerror(errno)); memblock_unref(chunk.memblock); + return -1; } + + memblockq_drop(c->ostream->memblockq, r); + memblock_unref(chunk.memblock); + return 0; +} - return; +static void io_callback(struct iochannel*io, void *userdata) { + struct connection *c = userdata; + assert(io && c && c->io == io); + + if (do_read(c) < 0 || do_write(c) < 0) + destroy_connection(c); +} + +static void istream_notify_cb(struct input_stream *i, void *userdata) { + struct connection*c = userdata; + assert(i && c && c->istream == i); -fail: - destroy_connection(c); + if (do_read(c) < 0) + destroy_connection(c); } static void on_connection(struct socket_server*s, struct iochannel *io, void *userdata) { @@ -155,6 +175,7 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c->istream = input_stream_new(sink, &DEFAULT_SAMPLE_SPEC, c->client->name); assert(c->istream); input_stream_set_kill_callback(c->istream, istream_kill_cb, c); + input_stream_set_notify_callback(c->istream, istream_notify_cb, c); } diff --git a/src/sink.c b/src/sink.c index dfe1bcb9..f2d5373d 100644 --- a/src/sink.c +++ b/src/sink.c @@ -33,8 +33,8 @@ struct sink* sink_new(struct core *core, const char *name, const struct sample_s s->volume = 0xFF; - s->notify_callback = NULL; - s->userdata = NULL; + s->notify = NULL; + s->notify_userdata = NULL; return s; } @@ -103,6 +103,10 @@ static int do_mix(void *p, uint32_t index, int *del, void*userdata) { assert(chunk.length && chunk.length <= info->chunk->memblock->length - info->chunk->index); add_clip(info->chunk, &chunk, info->spec); + memblock_unref(chunk.memblock); + memblockq_drop(i->memblockq, info->chunk->length); + + input_stream_notify(i); return 0; } @@ -139,6 +143,8 @@ int sink_render_into(struct sink*s, struct memblock *target, struct memchunk *re target->length = l; memblock_unref(chunk.memblock); memblockq_drop(i->memblockq, l); + + input_stream_notify(i); result->memblock = target; result->length = l; @@ -191,6 +197,8 @@ int sink_render(struct sink*s, size_t length, struct memchunk *result) { l = length < result->length ? length : result->length; result->length = l; memblockq_drop(i->memblockq, l); + input_stream_notify(i); + return 0; } @@ -211,15 +219,15 @@ int sink_render(struct sink*s, size_t length, struct memchunk *result) { void sink_notify(struct sink*s) { assert(s); - if (s->notify_callback) - s->notify_callback(s, s->userdata); + if (s->notify) + s->notify(s, s->notify_userdata); } void sink_set_notify_callback(struct sink *s, void (*notify_callback)(struct sink*sink, void *userdata), void *userdata) { assert(s && notify_callback); - s->notify_callback = notify_callback; - s->userdata = userdata; + s->notify = notify_callback; + s->notify_userdata = userdata; } diff --git a/src/sink.h b/src/sink.h index a6f98005..1678fc75 100644 --- a/src/sink.h +++ b/src/sink.h @@ -22,8 +22,8 @@ struct sink { uint8_t volume; - void (*notify_callback)(struct sink*sink, void *userdata); - void *userdata; + void (*notify)(struct sink*sink, void *userdata); + void *notify_userdata; }; struct sink* sink_new(struct core *core, const char *name, const struct sample_spec *spec); diff --git a/src/todo b/src/todo new file mode 100644 index 00000000..d4cc5f18 --- /dev/null +++ b/src/todo @@ -0,0 +1,16 @@ +- mixing +- resampling +- native protocol/library +- oss/mmap +- esound prodocol +- config-parser +-- 0.1 +- future cancellation +- client-ui + +drivers: +- libao +- xmms +- portaudio +- mplayer +- python -- cgit From 98f41f1e70e66dcfc4c457ae47bffb07ed83947f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 15 Jun 2004 15:17:22 +0000 Subject: minor work git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@16 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/inputstream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/inputstream.c b/src/inputstream.c index 7ece3b5c..6bc841ac 100644 --- a/src/inputstream.c +++ b/src/inputstream.c @@ -20,7 +20,7 @@ struct input_stream* input_stream_new(struct sink *s, struct sample_spec *spec, i->notify = NULL; i->notify_userdata = NULL; - i->memblockq = memblockq_new(bytes_per_second(spec)*5, sample_size(spec), (size_t) -1); + i->memblockq = memblockq_new(bytes_per_second(spec)/2, sample_size(spec), (size_t) -1); assert(i->memblockq); assert(s->core); -- cgit From 78f386ad45dc046d673fca5441dff188a7297059 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 15 Jun 2004 15:18:33 +0000 Subject: more work git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@17 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/client.c | 4 + src/core.c | 4 +- src/inputstream.c | 82 ----------------- src/inputstream.h | 50 ----------- src/main.c | 12 ++- src/memblock.c | 38 ++++++++ src/memblock.h | 7 ++ src/memblockq.c | 2 + src/memblockq.h | 1 + src/module-oss.c | 26 +++--- src/module.c | 6 ++ src/outputstream.c | 57 ------------ src/outputstream.h | 27 ------ src/protocol-simple.c | 4 +- src/sample.c | 53 +++++++---- src/sample.h | 10 ++- src/sink.c | 245 +++++++++++++++++++++----------------------------- src/sink.h | 13 ++- src/sinkinput.c | 82 +++++++++++++++++ src/sinkinput.h | 50 +++++++++++ src/source.c | 5 ++ src/sourceoutput.c | 57 ++++++++++++ src/sourceoutput.h | 27 ++++++ 23 files changed, 465 insertions(+), 397 deletions(-) delete mode 100644 src/inputstream.c delete mode 100644 src/inputstream.h delete mode 100644 src/outputstream.c delete mode 100644 src/outputstream.h create mode 100644 src/sinkinput.c create mode 100644 src/sinkinput.h create mode 100644 src/sourceoutput.c create mode 100644 src/sourceoutput.h diff --git a/src/client.c b/src/client.c index 3dd37668..578d51c3 100644 --- a/src/client.c +++ b/src/client.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -19,6 +20,8 @@ struct client *client_new(struct core *core, const char *protocol_name, char *na r = idxset_put(core->clients, c, &c->index); assert(c->index != IDXSET_INVALID && r >= 0); + + fprintf(stderr, "client: created %u \"%s\"\n", c->index, c->name); return c; } @@ -27,6 +30,7 @@ void client_free(struct client *c) { assert(c && c->core); idxset_remove_by_data(c->core->clients, c, NULL); + fprintf(stderr, "client: freed %u \"%s\"\n", c->index, c->name); free(c->name); free(c); } diff --git a/src/core.c b/src/core.c index 0457f4f3..2e67118a 100644 --- a/src/core.c +++ b/src/core.c @@ -60,7 +60,7 @@ struct sink* core_get_default_sink(struct core *c) { if (!(sink = idxset_first(c->sinks, &c->default_sink_index))) return NULL; - fprintf(stderr, "Default sink vanished, setting to %u\n", sink->index); + fprintf(stderr, "core: default sink vanished, setting to %u.\n", sink->index); return sink; } @@ -74,6 +74,6 @@ struct source* core_get_default_source(struct core *c) { if (!(source = idxset_first(c->sources, &c->default_source_index))) return NULL; - fprintf(stderr, "Default source vanished, setting to %u\n", source->index); + fprintf(stderr, "core: default source vanished, setting to %u.\n", source->index); return source; } diff --git a/src/inputstream.c b/src/inputstream.c deleted file mode 100644 index 6bc841ac..00000000 --- a/src/inputstream.c +++ /dev/null @@ -1,82 +0,0 @@ -#include -#include -#include - -#include "inputstream.h" - -struct input_stream* input_stream_new(struct sink *s, struct sample_spec *spec, const char *name) { - struct input_stream *i; - int r; - assert(s && spec); - - i = malloc(sizeof(struct input_stream)); - assert(i); - i->name = name ? strdup(name) : NULL; - i->sink = s; - i->spec = *spec; - - i->kill = NULL; - i->kill_userdata = NULL; - i->notify = NULL; - i->notify_userdata = NULL; - - i->memblockq = memblockq_new(bytes_per_second(spec)/2, sample_size(spec), (size_t) -1); - assert(i->memblockq); - - assert(s->core); - r = idxset_put(s->core->input_streams, i, &i->index); - assert(r == 0 && i->index != IDXSET_INVALID); - r = idxset_put(s->input_streams, i, NULL); - assert(r == 0); - - return i; -} - -void input_stream_free(struct input_stream* i) { - assert(i); - - memblockq_free(i->memblockq); - - assert(i->sink && i->sink->core); - idxset_remove_by_data(i->sink->core->input_streams, i, NULL); - idxset_remove_by_data(i->sink->input_streams, i, NULL); - - free(i->name); - free(i); -} - -void input_stream_notify_sink(struct input_stream *i) { - assert(i); - - if (!memblockq_is_readable(i->memblockq)) - return; - - sink_notify(i->sink); -} - -void input_stream_set_kill_callback(struct input_stream *i, void (*kill)(struct input_stream*i, void *userdata), void *userdata) { - assert(i && kill); - i->kill = kill; - i->kill_userdata = userdata; -} - - -void input_stream_kill(struct input_stream*i) { - assert(i); - - if (i->kill) - i->kill(i, i->kill_userdata); -} - -void input_stream_set_notify_callback(struct input_stream *i, void (*notify)(struct input_stream*i, void *userdata), void *userdata) { - assert(i && notify); - - i->notify = notify; - i->notify_userdata = userdata; -} - -void input_stream_notify(struct input_stream *i) { - assert(i); - if (i->notify) - i->notify(i, i->notify_userdata); -} diff --git a/src/inputstream.h b/src/inputstream.h deleted file mode 100644 index 544c3318..00000000 --- a/src/inputstream.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef fooinputstreamhfoo -#define fooinputstreamhfoo - -#include - -#include "sink.h" -#include "sample.h" -#include "memblockq.h" - -struct input_stream { - char *name; - uint32_t index; - - struct sink *sink; - struct sample_spec spec; - - struct memblockq *memblockq; - - void (*kill)(struct input_stream* i, void *userdata); - void *kill_userdata; - - void (*notify)(struct input_stream*i, void *userdata); - void *notify_userdata; -}; - -struct input_stream* input_stream_new(struct sink *s, struct sample_spec *spec, const char *name); -void input_stream_free(struct input_stream* i); - -/* This function notifies the attached sink that new data is available - * in the memblockq */ -void input_stream_notify_sink(struct input_stream *i); - - -/* The registrant of the input stream should call this function to set a - * callback function which is called when destruction of the input stream is - * requested */ -void input_stream_set_kill_callback(struct input_stream *i, void (*kill)(struct input_stream*i, void *userdata), void *userdata); - -/* Code that didn't create the input stream should call this function to - * request destruction of it */ -void input_stream_kill(struct input_stream *i); - -/* Notify the code that created this input stream that some data has - * been removed from the memblockq */ -void input_stream_set_notify_callback(struct input_stream *i, void (*notify)(struct input_stream*i, void *userdata), void *userdata); - -void input_stream_notify(struct input_stream *i); - - -#endif diff --git a/src/main.c b/src/main.c index d54bee0a..a42eaa82 100644 --- a/src/main.c +++ b/src/main.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "core.h" #include "mainloop.h" @@ -10,7 +11,7 @@ static void signal_callback(struct mainloop_source *m, int sig, void *userdata) { mainloop_quit(mainloop_source_get_mainloop(m), -1); - fprintf(stderr, "Got signal.\n"); + fprintf(stderr, "main: got signal.\n"); } int main(int argc, char *argv[]) { @@ -29,10 +30,17 @@ int main(int argc, char *argv[]) { mainloop_source_new_signal(m, SIGINT, signal_callback, NULL); signal(SIGPIPE, SIG_IGN); - module_load(c, "module-oss", NULL); + module_load(c, "module-oss", "/dev/dsp1"); module_load(c, "module-pipe-sink", NULL); module_load(c, "module-simple-protocol-tcp", 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); core_free(c); diff --git a/src/memblock.c b/src/memblock.c index 3bef4944..2d346769 100644 --- a/src/memblock.c +++ b/src/memblock.c @@ -1,15 +1,22 @@ +#include #include #include #include +#include +#include #include "memblock.h" +unsigned n_blocks = 0; + struct memblock *memblock_new(size_t length) { struct memblock *b = malloc(sizeof(struct memblock)+length); b->type = MEMBLOCK_APPENDED; b->ref = 1; b->length = length; b->data = b+1; + n_blocks++; + timerclear(&b->stamp); return b; } @@ -19,6 +26,8 @@ struct memblock *memblock_new_fixed(void *d, size_t length) { b->ref = 1; b->length = length; b->data = d; + n_blocks++; + timerclear(&b->stamp); return b; } @@ -28,6 +37,8 @@ struct memblock *memblock_new_dynamic(void *d, size_t length) { b->ref = 1; b->length = length; b->data = d; + n_blocks++; + timerclear(&b->stamp); return b; } @@ -45,6 +56,7 @@ void memblock_unref(struct memblock*b) { if (b->type == MEMBLOCK_DYNAMIC) free(b->data); free(b); + n_blocks--; } } @@ -65,3 +77,29 @@ void memblock_unref_fixed(struct memblock *b) { b->type = MEMBLOCK_DYNAMIC; } +void memblock_stamp(struct memblock*b) { + assert(b); + gettimeofday(&b->stamp, NULL); +} + +uint32_t memblock_age(struct memblock*b) { + assert(b); + struct timeval tv; + uint32_t r; + + if (b->stamp.tv_sec == 0) + return (suseconds_t) -1; + + gettimeofday(&tv, NULL); + + /*fprintf(stderr, "memblock: (%lu,%lu) -- (%lu,%lu)\r", b->stamp.tv_sec, b->stamp.tv_usec, tv.tv_sec, tv.tv_usec);*/ + + r = (tv.tv_sec-b->stamp.tv_sec) * 1000000; + + if (tv.tv_usec >= b->stamp.tv_usec) + r += tv.tv_usec - b->stamp.tv_usec; + else + r -= b->stamp.tv_usec - tv.tv_usec; + + return r; +} diff --git a/src/memblock.h b/src/memblock.h index 48e87286..c0fb6708 100644 --- a/src/memblock.h +++ b/src/memblock.h @@ -2,6 +2,7 @@ #define foomemblockhfoo #include +#include enum memblock_type { MEMBLOCK_FIXED, MEMBLOCK_APPENDED, MEMBLOCK_DYNAMIC }; @@ -10,6 +11,7 @@ struct memblock { unsigned ref; size_t length; void *data; + struct timeval stamp; }; struct memchunk { @@ -26,6 +28,11 @@ struct memblock* memblock_ref(struct memblock*b); void memblock_unref_fixed(struct memblock*b); +void memblock_stamp(struct memblock*b); +uint32_t memblock_age(struct memblock*b); + #define memblock_assert_exclusive(b) assert((b)->ref == 1) +extern unsigned n_blocks; + #endif diff --git a/src/memblockq.c b/src/memblockq.c index b25adc65..3c0d4326 100644 --- a/src/memblockq.c +++ b/src/memblockq.c @@ -18,6 +18,7 @@ struct memblockq { size_t prebuf; }; + struct memblockq* memblockq_new(size_t maxlength, size_t base, size_t prebuf) { struct memblockq* bq; assert(maxlength && base); @@ -35,6 +36,7 @@ struct memblockq* memblockq_new(size_t maxlength, size_t base, size_t prebuf) { bq->prebuf = bq->maxlength; assert(bq->maxlength >= base); + return bq; } diff --git a/src/memblockq.h b/src/memblockq.h index 48050d49..25c2f2d4 100644 --- a/src/memblockq.h +++ b/src/memblockq.h @@ -22,4 +22,5 @@ void memblockq_empty(struct memblockq *bq); int memblockq_is_readable(struct memblockq *bq); int memblockq_is_writable(struct memblockq *bq, size_t length); + #endif diff --git a/src/module-oss.c b/src/module-oss.c index 7a1482e7..07a407d8 100644 --- a/src/module-oss.c +++ b/src/module-oss.c @@ -31,7 +31,7 @@ static void do_write(struct userdata *u) { ssize_t r; assert(u); - if (!iochannel_is_writable(u->io)) + if (!u->sink || !iochannel_is_writable(u->io)) return; if (!u->memchunk.length) { @@ -66,7 +66,7 @@ static void do_read(struct userdata *u) { ssize_t r; assert(u); - if (!iochannel_is_readable(u->io)) + if (!u->source || !iochannel_is_readable(u->io)) return; memchunk.memblock = memblock_new(u->in_fragment_size); @@ -103,7 +103,7 @@ int module_init(struct core *c, struct module*m) { assert(c && m); p = m->argument ? m->argument : "/dev/dsp"; - if ((fd = open(p, mode = O_RDWR)) >= 0) { + if ((fd = open(p, (mode = O_RDWR)|O_NDELAY)) >= 0) { int caps; ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0); @@ -120,15 +120,17 @@ int module_init(struct core *c, struct module*m) { } if (fd < 0) { - if ((fd = open(p, mode = O_WRONLY)) < 0) { - if ((fd = open(p, mode = O_RDONLY)) < 0) { + if ((fd = open(p, (mode = O_WRONLY)|O_NDELAY)) < 0) { + if ((fd = open(p, (mode = O_RDONLY)|O_NDELAY)) < 0) { fprintf(stderr, "open('%s'): %s\n", p, strerror(errno)); goto fail; } } } + + fprintf(stderr, "module-oss: device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); - frag_size = ((int) 0x7ffff << 4) | 10; /* nfrags = 4; frag_size = 2^10 */ + frag_size = ((int) 4 << 16) | 10; /* nfrags = 4; frag_size = 2^10 */ if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag_size) < 0) { fprintf(stderr, "SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno)); goto fail; @@ -174,12 +176,12 @@ int module_init(struct core *c, struct module*m) { in_frag_size = out_frag_size = frag_size; if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { - fprintf(stderr, "INPUT: %u fragments of size %u.\n", info.fragstotal, info.fragsize); + fprintf(stderr, "module-oss: input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); in_frag_size = info.fragsize; } if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) { - fprintf(stderr, "OUTUT: %u fragments of size %u.\n", info.fragstotal, info.fragsize); + fprintf(stderr, "module-oss: output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); out_frag_size = info.fragsize; } @@ -239,9 +241,11 @@ void module_done(struct core *c, struct module*m) { memblock_unref(u->memchunk.memblock); if (u->silence.memblock) memblock_unref(u->silence.memblock); - - sink_free(u->sink); - source_free(u->source); + + if (u->sink) + sink_free(u->sink); + if (u->source) + source_free(u->source); iochannel_free(u->io); free(u); } diff --git a/src/module.c b/src/module.c index 62204e4c..7f2bc218 100644 --- a/src/module.c +++ b/src/module.c @@ -40,6 +40,9 @@ struct module* module_load(struct core *c, const char *name, const char *argumen assert(c->modules); r = idxset_put(c->modules, m, &m->index); assert(r >= 0 && m->index != IDXSET_INVALID); + + fprintf(stderr, "module: loaded %u \"%s\" with argument \"%s\".\n", m->index, m->name, m->argument); + return m; fail: @@ -61,6 +64,9 @@ static void module_free(struct module *m) { m->done(m->core, m); lt_dlclose(m->dl); + + fprintf(stderr, "module: unloaded %u \"%s\".\n", m->index, m->name); + free(m->name); free(m->argument); free(m); diff --git a/src/outputstream.c b/src/outputstream.c deleted file mode 100644 index c3f68a0e..00000000 --- a/src/outputstream.c +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include -#include - -#include "outputstream.h" - -struct output_stream* output_stream_new(struct source *s, struct sample_spec *spec, const char *name) { - struct output_stream *o; - int r; - assert(s && spec); - - o = malloc(sizeof(struct output_stream)); - assert(o); - o->name = name ? strdup(name) : NULL; - o->source = s; - o->spec = *spec; - o->kill = NULL; - o->kill_userdata = NULL; - - o->memblockq = memblockq_new(bytes_per_second(spec)*5, sample_size(spec), (size_t) -1); - assert(o->memblockq); - - assert(s->core); - r = idxset_put(s->core->output_streams, o, &o->index); - assert(r == 0 && o->index != IDXSET_INVALID); - r = idxset_put(s->output_streams, o, NULL); - assert(r == 0); - - return o; -} - -void output_stream_free(struct output_stream* o) { - assert(o); - - memblockq_free(o->memblockq); - - assert(o->source && o->source->core); - idxset_remove_by_data(o->source->core->output_streams, o, NULL); - idxset_remove_by_data(o->source->output_streams, o, NULL); - - free(o->name); - free(o); -} - -void output_stream_set_kill_callback(struct output_stream *i, void (*kill)(struct output_stream*i, void *userdata), void *userdata) { - assert(i && kill); - i->kill = kill; - i->kill_userdata = userdata; -} - - -void output_stream_kill(struct output_stream*i) { - assert(i); - - if (i->kill) - i->kill(i, i->kill_userdata); -} diff --git a/src/outputstream.h b/src/outputstream.h deleted file mode 100644 index c6c0a717..00000000 --- a/src/outputstream.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef foooutputstreamhfoo -#define foooutputstreamhfoo - -#include -#include "source.h" -#include "sample.h" -#include "memblockq.h" - -struct output_stream { - char *name; - uint32_t index; - - struct source *source; - struct sample_spec spec; - - struct memblockq *memblockq; - void (*kill)(struct output_stream* i, void *userdata); - void *kill_userdata; -}; - -struct output_stream* output_stream_new(struct source *s, struct sample_spec *spec, const char *name); -void output_stream_free(struct output_stream* o); - -void output_stream_set_kill_callback(struct output_stream *i, void (*kill)(struct output_stream*i, void *userdata), void *userdata); -void output_stream_kill(struct output_stream*i); - -#endif diff --git a/src/protocol-simple.c b/src/protocol-simple.c index 1c462b39..d34a5d02 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -78,13 +78,15 @@ static int do_read(struct connection *c) { chunk.memblock = memblock_new(BUFSIZE); assert(chunk.memblock); + + memblock_stamp(chunk.memblock); if ((r = iochannel_read(c->io, chunk.memblock->data, BUFSIZE)) <= 0) { fprintf(stderr, "read(): %s\n", r == 0 ? "EOF" : strerror(errno)); memblock_unref(chunk.memblock); return -1; } - + chunk.memblock->length = r; chunk.length = r; chunk.index = 0; diff --git a/src/sample.c b/src/sample.c index 2e46eac7..6a000228 100644 --- a/src/sample.c +++ b/src/sample.c @@ -33,24 +33,6 @@ struct memblock *silence(struct memblock* b, struct sample_spec *spec) { return b; } -void add_clip(struct memchunk *target, struct memchunk *chunk, struct sample_spec *spec) { - int16_t *p, *d; - size_t i; - assert(target && target->memblock && chunk && chunk->memblock && spec); - assert(spec->format == SAMPLE_S16NE); - assert((target->length & 1) == 0); - - d = target->memblock->data + target->index; - p = chunk->memblock->data + chunk->index; - - for (i = 0; i < target->length && i < chunk->length; i++) { - int32_t r = (int32_t) *d + (int32_t) *p; - if (r < -0x8000) r = 0x8000; - if (r > 0x7FFF) r = 0x7FFF; - *d = (int16_t) r; - } -} - size_t sample_size(struct sample_spec *spec) { assert(spec); size_t b = 1; @@ -78,3 +60,38 @@ size_t bytes_per_second(struct sample_spec *spec) { return spec->rate*sample_size(spec); } +size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct sample_spec *spec) { + unsigned c, d; + assert(chunks && target && spec); + assert(spec->format == SAMPLE_S16NE); + + for (d = 0;; d += sizeof(int16_t)) { + int32_t sum = 0; + + if (d >= length) + return d; + + for (c = 0; c < nchannels; c++) { + int32_t v; + uint8_t volume = channels[c].volume; + + if (d >= channels[c].chunk.length) + return d; + + if (volume == 0) + v = 0; + else { + v = *((int16_t*) (channels[c].chunk->memblock->data + channels[c].chunk->index + d)); + + if (volume != 0xFF) + v = v*volume/0xFF; + } + + sum += v; + } + + if (sum < -0x8000) sum = -0x8000; + if (sum > 0x7FFF) sum = 0x7FFF; + *(data++) = sum; + } +} diff --git a/src/sample.h b/src/sample.h index ecbe33f2..651788ba 100644 --- a/src/sample.h +++ b/src/sample.h @@ -27,7 +27,15 @@ struct sample_spec { extern struct sample_spec default_sample_spec; struct memblock *silence(struct memblock* b, struct sample_spec *spec); -void add_clip(struct memchunk *target, struct memchunk *chunk, struct sample_spec *spec); + + +struct mix_info { + struct memchunk chunk; + uint8_t volume; + void *userdata; +}; + +size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct sample_spec *spec) { size_t bytes_per_second(struct sample_spec *spec); size_t sample_size(struct sample_spec *spec); diff --git a/src/sink.c b/src/sink.c index f2d5373d..82cde8f2 100644 --- a/src/sink.c +++ b/src/sink.c @@ -21,7 +21,7 @@ struct sink* sink_new(struct core *core, const char *name, const struct sample_s s->core = core; s->sample_spec = *spec; - s->input_streams = idxset_new(NULL, NULL); + s->inputs = idxset_new(NULL, NULL); if (name) { n = malloc(strlen(name)+9); @@ -36,198 +36,153 @@ struct sink* sink_new(struct core *core, const char *name, const struct sample_s s->notify = NULL; s->notify_userdata = NULL; + fprintf(stderr, "sink: created %u \"%s\".\n", s->index, s->name); + return s; } void sink_free(struct sink *s) { - struct input_stream *i, *j = NULL; + struct sink_input *i, *j = NULL; assert(s); - while ((i = idxset_first(s->input_streams, NULL))) { - assert(i != j); - input_stream_kill(i); + while ((i = idxset_first(s->inputs, NULL))) { + assert(i != j && i->kill); + i->kill(i); j = i; } - idxset_free(s->input_streams, NULL, NULL); + + idxset_free(s->inputs, NULL, NULL); idxset_remove_by_data(s->core->sinks, s, NULL); source_free(s->monitor_source); + fprintf(stderr, "sink: freed %u \"%s\"\n", s->index, s->name); + free(s->name); free(s); } -struct pass1_info { - size_t maxlength; - unsigned count; - struct input_stream *last_input_stream; -}; - -static int get_max_length(void *p, uint32_t index, int *del, void*userdata) { - struct memchunk chunk; - struct pass1_info *info = userdata; - struct input_stream*i = p; - assert(info && i); - - if (memblockq_peek(i->memblockq, &chunk) != 0) - return 0; - - assert(chunk.length); - - if (info->maxlength > chunk.length) - info->maxlength = chunk.length; - - info->count++; - info->last_input_stream = i; - - memblock_unref(chunk.memblock); +void sink_notify(struct sink*s) { + assert(s); - return 0; + if (s->notify) + s->notify(s, s->notify_userdata); } -struct pass2_info { - struct memchunk *chunk; - struct sample_spec *spec; -}; - -static int do_mix(void *p, uint32_t index, int *del, void*userdata) { - struct memchunk chunk; - struct pass2_info *info = userdata; - struct input_stream*i = p; - assert(info && info->chunk && info->chunk->memblock && i && info->spec); - - if (memblockq_peek(i->memblockq, &chunk) != 0) - return 0; - - memblock_assert_exclusive(info->chunk->memblock); - assert(chunk.length && chunk.length <= info->chunk->memblock->length - info->chunk->index); - - add_clip(info->chunk, &chunk, info->spec); - memblock_unref(chunk.memblock); - memblockq_drop(i->memblockq, info->chunk->length); +void sink_set_notify_callback(struct sink *s, void (*notify_callback)(struct sink*sink, void *userdata), void *userdata) { + assert(s && notify_callback); - input_stream_notify(i); - return 0; + s->notify = notify_callback; + s->notify_userdata = userdata; } -int sink_render_into(struct sink*s, struct memblock *target, struct memchunk *result) { - struct pass1_info pass1_info; - struct pass2_info pass2_info; - assert(s && target && result); - memblock_assert_exclusive(target); - - /* Calculate how many bytes to mix */ - pass1_info.maxlength = target->length; - pass1_info.count = 0; - - idxset_foreach(s->input_streams, get_max_length, &pass1_info); - assert(pass1_info.maxlength); - - /* No data to mix */ - if (pass1_info.count == 0) - return -1; +static unsigned fill_mix_info(struct sink *s, struct mix_info *info, unsigned maxinfo) { + uint32_t index = IDXSET_ANY; + struct sink_input *i; + unsigned n; - /* A shortcut if only a single input stream is connected */ - if (pass1_info.count == 1) { - struct input_stream *i = pass1_info.last_input_stream; - struct memchunk chunk; - size_t l; - - assert(i); - - if (memblockq_peek(i->memblockq, &chunk) != 0) - return -1; + assert(s && info); - l = target->length < chunk.length ? target->length : chunk.length; - memcpy(target->data, result->memblock+result->index, l); - target->length = l; - memblock_unref(chunk.memblock); - memblockq_drop(i->memblockq, l); + while (maxinfo > 0 && i = idxset_rrobin(s->inputs, &index)) { + assert(i->peek); + if (i->peek(i, &info->chunk, &info->volume) < 0) + continue; - input_stream_notify(i); + assert(info->chunk.memblock && info->chunk.memblock->data && info->chunk.length); + info->userdata = i; - result->memblock = target; - result->length = l; - result->index = 0; - return 0; + info++; + maxinfo--; + n++; } - /* Do the real mixing */ - result->memblock = silence(target, &s->sample_spec); - result->index = 0; - result->length = pass1_info.maxlength; - pass2_info.chunk = result; - pass2_info.spec = &s->sample_spec; - idxset_foreach(s->input_streams, do_mix, &pass2_info); + return n; +} - assert(s->monitor_source); - source_post(s->monitor_source, result); +static void inputs_drop(struct sink *s, struct mix_info *info, unsigned maxinfo, size_t length) { + assert(s && info); - return 0; + for (; maxinfo > 0; maxinfo--, info++) { + struct sink_input *i = info->userdata; + assert(i && info->chunk.memblock); + + memblock_unref(info->chunk.memblock); + assert(i->drop); + i->drop(i, length); + } } int sink_render(struct sink*s, size_t length, struct memchunk *result) { - struct pass1_info pass1_info; - struct pass2_info pass2_info; - assert(s && result); - - if (!length) - length = (size_t) -1; + struct mix_info info[MAX_MIX_CHANNELS]; + unsigned n; + size_t l; + assert(s && length && result); - /* Calculate how many bytes to mix */ - pass1_info.maxlength = length; - pass1_info.count = 0; - - idxset_foreach(s->input_streams, get_max_length, &pass1_info); - assert(pass1_info.maxlength); + n = fill_mix_info(s, info, MAX_MIX_CHANNELS); - /* No data to mix */ - if (pass1_info.count == 0) + if (n <= 0) return -1; - if (pass1_info.count == 1) { - struct input_stream *i = pass1_info.last_input_stream; - size_t l; + if (n == 1) { + struct sink_info *i = info[0].userdata; + assert(i && b); + *result = info[0].chunk; + memblock_ref(result->memblock); - assert(i); + if (result->length > length) + result->length = length; - if (memblockq_peek(i->memblockq, result) != 0) - return -1; + l = result->length; + } else { + result->memblock = memblock_new(length); + assert(result->memblock); - l = length < result->length ? length : result->length; - result->length = l; - memblockq_drop(i->memblockq, l); - input_stream_notify(i); + result->length = l = mix_chunks(info, n, result->memblock->data, length, &s->sample_spec); + result->index = 0; - return 0; + assert(l); } - /* Do the mixing */ - result->memblock = silence(memblock_new(result->length), &s->sample_spec); - result->index = 0; - result->length = pass1_info.maxlength; - pass2_info.chunk = result; - pass2_info.spec = &s->sample_spec; - idxset_foreach(s->input_streams, do_mix, &pass2_info); - - assert(s->monitor_source); - - source_post(s->monitor_source, result); + inputs_drop(s, info, n, l); return 0; } -void sink_notify(struct sink*s) { - assert(s); +int sink_render_into(struct sink*s, struct memblock *target, struct memchunk *result) { + struct mix_info info[MAX_MIX_CHANNELS]; + unsigned n; + size_t l; + assert(s && target && target->length && target->data && result); + + n = fill_mix_info(s, info, MAX_MIX_CHANNELS); - if (s->notify) - s->notify(s, s->notify_userdata); -} + if (n <= 0) + return -1; -void sink_set_notify_callback(struct sink *s, void (*notify_callback)(struct sink*sink, void *userdata), void *userdata) { - assert(s && notify_callback); + if (n == 1) { + struct sink_info *i = info[0].userdata; + assert(i && b); - s->notify = notify_callback; - s->notify_userdata = userdata; -} + l = target->length; + if (l > info[0].chunk.length) + l = info[0].chunk.length; + + result->memblock = target; + memcpy(target->data, info[0].chunk.memblock->data + info[0].chunk.index, l); + result->length = target->length = l; + result->index = 0; + if (result->length > length) + result->length = length; + l = result->length; + } else { + + result->memblock = target; + result->length = l = mix_chunks(info, n, target->data, target->length, &s->sample_spec); + result->index = 0; + assert(l); + } + + inputs_drop(s, info, n, l); + return 0; +} diff --git a/src/sink.h b/src/sink.h index 1678fc75..bd43d49d 100644 --- a/src/sink.h +++ b/src/sink.h @@ -10,13 +10,24 @@ struct sink; #include "idxset.h" #include "source.h" + +struct sink_input { + int (*peek) (struct sink_input *i, struct memchunk *chunk, uint8_t *volume); + void (*drop) (struct sink_input *i, size_t length); + void (*kill) (struct sink_input *i); + + void *userdata; + int index; + struct sink *sink; +}; + struct sink { char *name; uint32_t index; struct core *core; struct sample_spec sample_spec; - struct idxset *input_streams; + struct idxset *inputs; struct source *monitor_source; diff --git a/src/sinkinput.c b/src/sinkinput.c new file mode 100644 index 00000000..6bc841ac --- /dev/null +++ b/src/sinkinput.c @@ -0,0 +1,82 @@ +#include +#include +#include + +#include "inputstream.h" + +struct input_stream* input_stream_new(struct sink *s, struct sample_spec *spec, const char *name) { + struct input_stream *i; + int r; + assert(s && spec); + + i = malloc(sizeof(struct input_stream)); + assert(i); + i->name = name ? strdup(name) : NULL; + i->sink = s; + i->spec = *spec; + + i->kill = NULL; + i->kill_userdata = NULL; + i->notify = NULL; + i->notify_userdata = NULL; + + i->memblockq = memblockq_new(bytes_per_second(spec)/2, sample_size(spec), (size_t) -1); + assert(i->memblockq); + + assert(s->core); + r = idxset_put(s->core->input_streams, i, &i->index); + assert(r == 0 && i->index != IDXSET_INVALID); + r = idxset_put(s->input_streams, i, NULL); + assert(r == 0); + + return i; +} + +void input_stream_free(struct input_stream* i) { + assert(i); + + memblockq_free(i->memblockq); + + assert(i->sink && i->sink->core); + idxset_remove_by_data(i->sink->core->input_streams, i, NULL); + idxset_remove_by_data(i->sink->input_streams, i, NULL); + + free(i->name); + free(i); +} + +void input_stream_notify_sink(struct input_stream *i) { + assert(i); + + if (!memblockq_is_readable(i->memblockq)) + return; + + sink_notify(i->sink); +} + +void input_stream_set_kill_callback(struct input_stream *i, void (*kill)(struct input_stream*i, void *userdata), void *userdata) { + assert(i && kill); + i->kill = kill; + i->kill_userdata = userdata; +} + + +void input_stream_kill(struct input_stream*i) { + assert(i); + + if (i->kill) + i->kill(i, i->kill_userdata); +} + +void input_stream_set_notify_callback(struct input_stream *i, void (*notify)(struct input_stream*i, void *userdata), void *userdata) { + assert(i && notify); + + i->notify = notify; + i->notify_userdata = userdata; +} + +void input_stream_notify(struct input_stream *i) { + assert(i); + if (i->notify) + i->notify(i, i->notify_userdata); +} diff --git a/src/sinkinput.h b/src/sinkinput.h new file mode 100644 index 00000000..544c3318 --- /dev/null +++ b/src/sinkinput.h @@ -0,0 +1,50 @@ +#ifndef fooinputstreamhfoo +#define fooinputstreamhfoo + +#include + +#include "sink.h" +#include "sample.h" +#include "memblockq.h" + +struct input_stream { + char *name; + uint32_t index; + + struct sink *sink; + struct sample_spec spec; + + struct memblockq *memblockq; + + void (*kill)(struct input_stream* i, void *userdata); + void *kill_userdata; + + void (*notify)(struct input_stream*i, void *userdata); + void *notify_userdata; +}; + +struct input_stream* input_stream_new(struct sink *s, struct sample_spec *spec, const char *name); +void input_stream_free(struct input_stream* i); + +/* This function notifies the attached sink that new data is available + * in the memblockq */ +void input_stream_notify_sink(struct input_stream *i); + + +/* The registrant of the input stream should call this function to set a + * callback function which is called when destruction of the input stream is + * requested */ +void input_stream_set_kill_callback(struct input_stream *i, void (*kill)(struct input_stream*i, void *userdata), void *userdata); + +/* Code that didn't create the input stream should call this function to + * request destruction of it */ +void input_stream_kill(struct input_stream *i); + +/* Notify the code that created this input stream that some data has + * been removed from the memblockq */ +void input_stream_set_notify_callback(struct input_stream *i, void (*notify)(struct input_stream*i, void *userdata), void *userdata); + +void input_stream_notify(struct input_stream *i); + + +#endif diff --git a/src/source.c b/src/source.c index 2d5e9bbd..a7fc9a64 100644 --- a/src/source.c +++ b/src/source.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -24,6 +25,8 @@ struct source* source_new(struct core *core, const char *name, const struct samp s->link_change_callback = NULL; s->userdata = NULL; + fprintf(stderr, "source: created %u \"%s\"\n", s->index, s->name); + return s; } @@ -40,6 +43,8 @@ void source_free(struct source *s) { idxset_remove_by_data(s->core->sources, s, NULL); + fprintf(stderr, "source: freed %u \"%s\"\n", s->index, s->name); + free(s->name); free(s); } diff --git a/src/sourceoutput.c b/src/sourceoutput.c new file mode 100644 index 00000000..c3f68a0e --- /dev/null +++ b/src/sourceoutput.c @@ -0,0 +1,57 @@ +#include +#include +#include + +#include "outputstream.h" + +struct output_stream* output_stream_new(struct source *s, struct sample_spec *spec, const char *name) { + struct output_stream *o; + int r; + assert(s && spec); + + o = malloc(sizeof(struct output_stream)); + assert(o); + o->name = name ? strdup(name) : NULL; + o->source = s; + o->spec = *spec; + o->kill = NULL; + o->kill_userdata = NULL; + + o->memblockq = memblockq_new(bytes_per_second(spec)*5, sample_size(spec), (size_t) -1); + assert(o->memblockq); + + assert(s->core); + r = idxset_put(s->core->output_streams, o, &o->index); + assert(r == 0 && o->index != IDXSET_INVALID); + r = idxset_put(s->output_streams, o, NULL); + assert(r == 0); + + return o; +} + +void output_stream_free(struct output_stream* o) { + assert(o); + + memblockq_free(o->memblockq); + + assert(o->source && o->source->core); + idxset_remove_by_data(o->source->core->output_streams, o, NULL); + idxset_remove_by_data(o->source->output_streams, o, NULL); + + free(o->name); + free(o); +} + +void output_stream_set_kill_callback(struct output_stream *i, void (*kill)(struct output_stream*i, void *userdata), void *userdata) { + assert(i && kill); + i->kill = kill; + i->kill_userdata = userdata; +} + + +void output_stream_kill(struct output_stream*i) { + assert(i); + + if (i->kill) + i->kill(i, i->kill_userdata); +} diff --git a/src/sourceoutput.h b/src/sourceoutput.h new file mode 100644 index 00000000..c6c0a717 --- /dev/null +++ b/src/sourceoutput.h @@ -0,0 +1,27 @@ +#ifndef foooutputstreamhfoo +#define foooutputstreamhfoo + +#include +#include "source.h" +#include "sample.h" +#include "memblockq.h" + +struct output_stream { + char *name; + uint32_t index; + + struct source *source; + struct sample_spec spec; + + struct memblockq *memblockq; + void (*kill)(struct output_stream* i, void *userdata); + void *kill_userdata; +}; + +struct output_stream* output_stream_new(struct source *s, struct sample_spec *spec, const char *name); +void output_stream_free(struct output_stream* o); + +void output_stream_set_kill_callback(struct output_stream *i, void (*kill)(struct output_stream*i, void *userdata), void *userdata); +void output_stream_kill(struct output_stream*i); + +#endif -- cgit From b24546bedee168778a7aef11200dfb0378dfae43 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 15 Jun 2004 17:05:03 +0000 Subject: cleanup git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@18 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 2 +- src/client.c | 16 ++--- src/client.h | 15 ++--- src/core.c | 12 ++-- src/core.h | 2 +- src/idxset.c | 21 ++++++- src/idxset.h | 2 + src/module-pipe-sink.c | 11 ++-- src/protocol-simple.c | 165 +++++++++++++++++++++++++++++++------------------ src/sample.c | 15 +++-- src/sample.h | 2 +- src/sink.c | 49 ++++++--------- src/sink.h | 20 ++---- src/sinkinput.c | 62 +++++-------------- src/sinkinput.h | 40 ++++-------- src/source.c | 35 ++++++----- src/source.h | 8 ++- src/sourceoutput.c | 38 +++++------- src/sourceoutput.h | 23 +++---- 19 files changed, 261 insertions(+), 277 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index f0953846..40e2039d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,7 +26,7 @@ pkglib_LTLIBRARIES=libprotocol-simple.la module-simple-protocol-tcp.la \ polypaudio_SOURCES = idxset.c queue.c strbuf.c mainloop.c \ memblock.c sample.c memblockq.c client.c \ - core.c main.c outputstream.c inputstream.c source.c sink.c \ + core.c main.c sourceoutput.c sinkinput.c source.c sink.c \ module.c polypaudio_INCLUDES = $(INCLTDL) polypaudio_LDADD = $(LIBLTDL) diff --git a/src/client.c b/src/client.c index 578d51c3..1b84c6bf 100644 --- a/src/client.c +++ b/src/client.c @@ -12,11 +12,12 @@ struct client *client_new(struct core *core, const char *protocol_name, char *na c = malloc(sizeof(struct client)); assert(c); - c->protocol_name = protocol_name; c->name = name ? strdup(name) : NULL; - c->kill = NULL; - c->kill_userdata = NULL; c->core = core; + c->protocol_name = protocol_name; + + c->kill = NULL; + c->userdata = NULL; r = idxset_put(core->clients, c, &c->index); assert(c->index != IDXSET_INVALID && r >= 0); @@ -35,14 +36,9 @@ void client_free(struct client *c) { free(c); } -void client_set_kill_callback(struct client *c, void (*kill)(struct client *c, void *userdata), void *userdata) { - assert(c && kill); - c->kill = kill; - c->kill_userdata = userdata; -} - void client_kill(struct client *c) { assert(c); - c->kill(c, c->kill_userdata); + if (c->kill) + c->kill(c); } diff --git a/src/client.h b/src/client.h index 8d9e519c..556b5fb3 100644 --- a/src/client.h +++ b/src/client.h @@ -4,15 +4,15 @@ #include "core.h" struct client { - char *name; uint32_t index; - + + char *name; + struct core *core; const char *protocol_name; - void *kill_userdata; - void (*kill)(struct client *c, void *userdata); + void (*kill)(struct client *c); - struct core *core; + void *userdata; }; struct client *client_new(struct core *c, const char *protocol_name, char *name); @@ -20,11 +20,6 @@ struct client *client_new(struct core *c, const char *protocol_name, char *name) /* This function should be called only by the code that created the client */ void client_free(struct client *c); -/* The registrant of the client should call this function to set a - * callback function which is called when destruction of the client is - * requested */ -void client_set_kill_callback(struct client *c, void (*kill)(struct client *c, void *userdata), void *userdata); - /* Code that didn't create the client should call this function to * request destruction of the client */ void client_kill(struct client *c); diff --git a/src/core.c b/src/core.c index 2e67118a..0bc13a5b 100644 --- a/src/core.c +++ b/src/core.c @@ -16,8 +16,8 @@ struct core* core_new(struct mainloop *m) { c->clients = idxset_new(NULL, NULL); c->sinks = idxset_new(NULL, NULL); c->sources = idxset_new(NULL, NULL); - c->output_streams = idxset_new(NULL, NULL); - c->input_streams = idxset_new(NULL, NULL); + c->source_outputs = idxset_new(NULL, NULL); + c->sink_inputs = idxset_new(NULL, NULL); c->default_source_index = c->default_sink_index = IDXSET_INVALID; @@ -41,11 +41,11 @@ void core_free(struct core *c) { assert(idxset_isempty(c->sources)); idxset_free(c->sources, NULL, NULL); - assert(idxset_isempty(c->output_streams)); - idxset_free(c->output_streams, NULL, NULL); + assert(idxset_isempty(c->source_outputs)); + idxset_free(c->source_outputs, NULL, NULL); - assert(idxset_isempty(c->input_streams)); - idxset_free(c->input_streams, NULL, NULL); + assert(idxset_isempty(c->sink_inputs)); + idxset_free(c->sink_inputs, NULL, NULL); free(c); }; diff --git a/src/core.h b/src/core.h index 649c9dba..a8a140b8 100644 --- a/src/core.h +++ b/src/core.h @@ -7,7 +7,7 @@ struct core { struct mainloop *mainloop; - struct idxset *clients, *sinks, *sources, *output_streams, *input_streams, *modules; + struct idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules; uint32_t default_source_index, default_sink_index; }; diff --git a/src/idxset.c b/src/idxset.c index 4442190d..ea609f60 100644 --- a/src/idxset.c +++ b/src/idxset.c @@ -291,9 +291,7 @@ void* idxset_rrobin(struct idxset *s, uint32_t *index) { if (!e) return NULL; - if (index) - *index = e->index; - + *index = e->index; return e->data; } @@ -308,6 +306,22 @@ void* idxset_first(struct idxset *s, uint32_t *index) { return s->iterate_list_head->data; } +void *idxset_next(struct idxset *s, uint32_t *index) { + struct idxset_entry **a, *e = NULL; + assert(s && index); + + if ((a = array_index(s, *index)) && *a) + e = (*a)->iterate_next; + + if (e) { + *index = e->index; + return e->data; + } else { + *index = IDXSET_INVALID; + return NULL; + } +} + int idxset_foreach(struct idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata) { struct idxset_entry *e; @@ -341,3 +355,4 @@ int idxset_isempty(struct idxset *s) { assert(s); return s->n_entries == 0; } + diff --git a/src/idxset.h b/src/idxset.h index fdcb7b54..90b9d247 100644 --- a/src/idxset.h +++ b/src/idxset.h @@ -26,10 +26,12 @@ void* idxset_rrobin(struct idxset *s, uint32_t *index); /* Return the oldest entry in the idxset */ void* idxset_first(struct idxset *s, uint32_t *index); +void *idxset_next(struct idxset *s, uint32_t *index); int idxset_foreach(struct idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata); unsigned idxset_ncontents(struct idxset*s); int idxset_isempty(struct idxset *s); + #endif diff --git a/src/module-pipe-sink.c b/src/module-pipe-sink.c index e63a7a86..c0a903e9 100644 --- a/src/module-pipe-sink.c +++ b/src/module-pipe-sink.c @@ -52,9 +52,9 @@ static void do_write(struct userdata *u) { } } -static void notify_callback(struct sink*s, void *userdata) { - struct userdata *u = userdata; - assert(u); +static void notify_cb(struct sink*s) { + struct userdata *u = s->userdata; + assert(s && u); if (iochannel_is_writable(u->io)) mainloop_source_enable(u->mainloop_source, 1); @@ -77,7 +77,7 @@ int module_init(struct core *c, struct module*m) { struct stat st; char *p; int fd = -1; - const static struct sample_spec ss = { + static const struct sample_spec ss = { .format = SAMPLE_S16NE, .rate = 44100, .channels = 2, @@ -110,7 +110,8 @@ int module_init(struct core *c, struct module*m) { u->core = c; u->sink = sink_new(c, "fifo", &ss); assert(u->sink); - sink_set_notify_callback(u->sink, notify_callback, u); + u->sink->notify = notify_cb; + u->sink->userdata = u; u->io = iochannel_new(c->mainloop, -1, fd); assert(u->io); diff --git a/src/protocol-simple.c b/src/protocol-simple.c index d34a5d02..1803936e 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -5,17 +5,18 @@ #include #include -#include "inputstream.h" -#include "outputstream.h" +#include "sinkinput.h" +#include "sourceoutput.h" #include "protocol-simple.h" #include "client.h" struct connection { struct protocol_simple *protocol; struct iochannel *io; - struct input_stream *istream; - struct output_stream *ostream; + struct sink_input *sink_input; + struct source_output *source_output; struct client *client; + struct memblockq *input_memblockq, *output_memblockq; }; struct protocol_simple { @@ -31,14 +32,18 @@ static void free_connection(void *data, void *userdata) { struct connection *c = data; assert(data); - if (c->istream) - input_stream_free(c->istream); - if (c->ostream) - output_stream_free(c->ostream); - - client_free(c->client); - - iochannel_free(c->io); + if (c->sink_input) + sink_input_free(c->sink_input); + if (c->source_output) + source_output_free(c->source_output); + if (c->client) + client_free(c->client); + if (c->io) + iochannel_free(c->io); + if (c->input_memblockq) + memblockq_free(c->input_memblockq); + if (c->output_memblockq) + memblockq_free(c->output_memblockq); free(c); } @@ -48,24 +53,6 @@ static void destroy_connection(struct connection *c) { free_connection(c, NULL); } -static void istream_kill_cb(struct input_stream *i, void *userdata) { - struct connection *c = userdata; - assert(i && c); - destroy_connection(c); -} - -static void ostream_kill_cb(struct output_stream *o, void *userdata) { - struct connection *c = userdata; - assert(o && c); - destroy_connection(c); -} - -static void client_kill_cb(struct client *client, void*userdata) { - struct connection *c= userdata; - assert(client && c); - destroy_connection(c); -} - static int do_read(struct connection *c) { struct memchunk chunk; ssize_t r; @@ -73,7 +60,7 @@ static int do_read(struct connection *c) { if (!iochannel_is_readable(c->io)) return 0; - if (!c->istream || !memblockq_is_writable(c->istream->memblockq, BUFSIZE)) + if (!c->sink_input || !memblockq_is_writable(c->input_memblockq, BUFSIZE)) return 0; chunk.memblock = memblock_new(BUFSIZE); @@ -90,10 +77,11 @@ static int do_read(struct connection *c) { chunk.memblock->length = r; chunk.length = r; chunk.index = 0; - - memblockq_push(c->istream->memblockq, &chunk, 0); - input_stream_notify_sink(c->istream); + + assert(c->input_memblockq); + memblockq_push(c->input_memblockq, &chunk, 0); memblock_unref(chunk.memblock); + sink_notify(c->sink_input->sink); return 0; } @@ -104,10 +92,11 @@ static int do_write(struct connection *c) { if (!iochannel_is_writable(c->io)) return 0; - if (!c->ostream) + if (!c->source_output) return 0; - memblockq_peek(c->ostream->memblockq, &chunk); + assert(c->output_memblockq); + memblockq_peek(c->output_memblockq, &chunk); assert(chunk.memblock && chunk.length); if ((r = iochannel_write(c->io, chunk.memblock->data+chunk.index, chunk.length)) < 0) { @@ -116,11 +105,63 @@ static int do_write(struct connection *c) { return -1; } - memblockq_drop(c->ostream->memblockq, r); + memblockq_drop(c->output_memblockq, r); memblock_unref(chunk.memblock); return 0; } +/*** sink_input callbacks ***/ + +static int sink_input_peek_cb(struct sink_input *i, struct memchunk *chunk, uint8_t *volume) { + struct connection*c = i->userdata; + assert(i && c && chunk && volume); + + if (memblockq_peek(c->input_memblockq, chunk) < 0) + return -1; + + *volume = 0xFF; + return 0; +} + +static void sink_input_drop_cb(struct sink_input *i, size_t length) { + struct connection*c = i->userdata; + assert(i && c && length); + + memblockq_drop(c->input_memblockq, length); + + if (do_read(c) < 0) + destroy_connection(c); +} + +static void sink_input_kill_cb(struct sink_input *i) { + assert(i && i->userdata); + destroy_connection((struct connection *) i->userdata); +} + +/*** source_output callbacks ***/ + +static void source_output_push_cb(struct source_output *o, struct memchunk *chunk) { + struct connection *c = o->userdata; + assert(o && c && chunk); + + memblockq_push(c->output_memblockq, chunk, 0); +} + +static void source_output_kill_cb(struct source_output *o) { + assert(o && o->userdata); + destroy_connection((struct connection *) o->userdata); +} + + +/*** client callbacks ***/ + +static void client_kill_cb(struct client *c) { + assert(c && c->userdata); + destroy_connection((struct connection *) c->userdata); +} + +/*** iochannel callbacks ***/ + static void io_callback(struct iochannel*io, void *userdata) { struct connection *c = userdata; assert(io && c && c->io == io); @@ -129,13 +170,7 @@ static void io_callback(struct iochannel*io, void *userdata) { destroy_connection(c); } -static void istream_notify_cb(struct input_stream *i, void *userdata) { - struct connection*c = userdata; - assert(i && c && c->istream == i); - - if (do_read(c) < 0) - destroy_connection(c); -} +/*** socket_server callbacks */ static void on_connection(struct socket_server*s, struct iochannel *io, void *userdata) { struct protocol_simple *p = userdata; @@ -145,39 +180,53 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c = malloc(sizeof(struct connection)); assert(c); c->io = io; - c->istream = NULL; - c->ostream = NULL; + c->sink_input = NULL; + c->source_output = NULL; + c->input_memblockq = c->output_memblockq = NULL; c->protocol = p; c->client = client_new(p->core, "SIMPLE", "Client"); assert(c->client); - client_set_kill_callback(c->client, client_kill_cb, c); + c->client->kill = client_kill_cb; + c->client->userdata = c; if (p->mode & PROTOCOL_SIMPLE_RECORD) { struct source *source; + size_t l; if (!(source = core_get_default_source(p->core))) { fprintf(stderr, "Failed to get default source.\n"); goto fail; } - c->ostream = output_stream_new(source, &DEFAULT_SAMPLE_SPEC, c->client->name); - assert(c->ostream); - output_stream_set_kill_callback(c->ostream, ostream_kill_cb, c); + c->source_output = source_output_new(source, &DEFAULT_SAMPLE_SPEC, c->client->name); + assert(c->source_output); + c->source_output->push = source_output_push_cb; + c->source_output->kill = source_output_kill_cb; + c->source_output->userdata = c; + + l = 5*bytes_per_second(&DEFAULT_SAMPLE_SPEC); + c->output_memblockq = memblockq_new(l, sample_size(&DEFAULT_SAMPLE_SPEC), l/2); } if (p->mode & PROTOCOL_SIMPLE_PLAYBACK) { struct sink *sink; + size_t l; if (!(sink = core_get_default_sink(p->core))) { fprintf(stderr, "Failed to get default sink.\n"); goto fail; } - c->istream = input_stream_new(sink, &DEFAULT_SAMPLE_SPEC, c->client->name); - assert(c->istream); - input_stream_set_kill_callback(c->istream, istream_kill_cb, c); - input_stream_set_notify_callback(c->istream, istream_notify_cb, c); + c->sink_input = sink_input_new(sink, &DEFAULT_SAMPLE_SPEC, c->client->name); + assert(c->sink_input); + c->sink_input->peek = sink_input_peek_cb; + c->sink_input->drop = sink_input_drop_cb; + c->sink_input->kill = sink_input_kill_cb; + c->sink_input->userdata = c; + + l = 5*bytes_per_second(&DEFAULT_SAMPLE_SPEC); + c->input_memblockq = memblockq_new(l, sample_size(&DEFAULT_SAMPLE_SPEC), l/2); } @@ -187,13 +236,7 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us fail: if (c) { - if (c->client) - client_free(c->client); - if (c->istream) - input_stream_free(c->istream); - if (c->ostream) - output_stream_free(c->ostream); - + free_connection(c, NULL); iochannel_free(c->io); free(c); } diff --git a/src/sample.c b/src/sample.c index 6a000228..21c04628 100644 --- a/src/sample.c +++ b/src/sample.c @@ -60,9 +60,9 @@ size_t bytes_per_second(struct sample_spec *spec) { return spec->rate*sample_size(spec); } -size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct sample_spec *spec) { +size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct sample_spec *spec, uint8_t volume) { unsigned c, d; - assert(chunks && target && spec); + assert(channels && data && length && spec); assert(spec->format == SAMPLE_S16NE); for (d = 0;; d += sizeof(int16_t)) { @@ -81,7 +81,7 @@ size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, si if (volume == 0) v = 0; else { - v = *((int16_t*) (channels[c].chunk->memblock->data + channels[c].chunk->index + d)); + v = *((int16_t*) (channels[c].chunk.memblock->data + channels[c].chunk.index + d)); if (volume != 0xFF) v = v*volume/0xFF; @@ -90,8 +90,15 @@ size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, si sum += v; } + if (volume == 0) + sum = 0; + else if (volume != 0xFF) + sum = sum*volume/0xFF; + if (sum < -0x8000) sum = -0x8000; if (sum > 0x7FFF) sum = 0x7FFF; - *(data++) = sum; + + *((int16_t*) data) = sum; + data += sizeof(int16_t); } } diff --git a/src/sample.h b/src/sample.h index 651788ba..f8ba6698 100644 --- a/src/sample.h +++ b/src/sample.h @@ -35,7 +35,7 @@ struct mix_info { void *userdata; }; -size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct sample_spec *spec) { +size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct sample_spec *spec, uint8_t volume); size_t bytes_per_second(struct sample_spec *spec); size_t sample_size(struct sample_spec *spec); diff --git a/src/sink.c b/src/sink.c index 82cde8f2..951191dd 100644 --- a/src/sink.c +++ b/src/sink.c @@ -4,7 +4,9 @@ #include #include "sink.h" -#include "inputstream.h" +#include "sinkinput.h" + +#define MAX_MIX_CHANNELS 32 struct sink* sink_new(struct core *core, const char *name, const struct sample_spec *spec) { struct sink *s; @@ -16,9 +18,6 @@ struct sink* sink_new(struct core *core, const char *name, const struct sample_s assert(s); s->name = name ? strdup(name) : NULL; - r = idxset_put(core->sinks, s, &s->index); - assert(s->index != IDXSET_INVALID && r >= 0); - s->core = core; s->sample_spec = *spec; s->inputs = idxset_new(NULL, NULL); @@ -34,8 +33,11 @@ struct sink* sink_new(struct core *core, const char *name, const struct sample_s s->volume = 0xFF; s->notify = NULL; - s->notify_userdata = NULL; + s->userdata = NULL; + r = idxset_put(core->sinks, s, &s->index); + assert(s->index != IDXSET_INVALID && r >= 0); + fprintf(stderr, "sink: created %u \"%s\".\n", s->index, s->name); return s; @@ -46,15 +48,14 @@ void sink_free(struct sink *s) { assert(s); while ((i = idxset_first(s->inputs, NULL))) { - assert(i != j && i->kill); - i->kill(i); + assert(i != j); + sink_input_kill(i); j = i; } - idxset_free(s->inputs, NULL, NULL); - - idxset_remove_by_data(s->core->sinks, s, NULL); + source_free(s->monitor_source); + idxset_remove_by_data(s->core->sinks, s, NULL); fprintf(stderr, "sink: freed %u \"%s\"\n", s->index, s->name); @@ -66,24 +67,17 @@ void sink_notify(struct sink*s) { assert(s); if (s->notify) - s->notify(s, s->notify_userdata); -} - -void sink_set_notify_callback(struct sink *s, void (*notify_callback)(struct sink*sink, void *userdata), void *userdata) { - assert(s && notify_callback); - - s->notify = notify_callback; - s->notify_userdata = userdata; + s->notify(s); } static unsigned fill_mix_info(struct sink *s, struct mix_info *info, unsigned maxinfo) { - uint32_t index = IDXSET_ANY; + uint32_t index = IDXSET_INVALID; struct sink_input *i; - unsigned n; + unsigned n = 0; assert(s && info); - while (maxinfo > 0 && i = idxset_rrobin(s->inputs, &index)) { + for (i = idxset_first(s->inputs, &index); maxinfo > 0 && i; i = idxset_next(s->inputs, &index)) { assert(i->peek); if (i->peek(i, &info->chunk, &info->volume) < 0) continue; @@ -125,7 +119,7 @@ int sink_render(struct sink*s, size_t length, struct memchunk *result) { if (n == 1) { struct sink_info *i = info[0].userdata; - assert(i && b); + assert(i); *result = info[0].chunk; memblock_ref(result->memblock); @@ -137,7 +131,7 @@ int sink_render(struct sink*s, size_t length, struct memchunk *result) { result->memblock = memblock_new(length); assert(result->memblock); - result->length = l = mix_chunks(info, n, result->memblock->data, length, &s->sample_spec); + result->length = l = mix_chunks(info, n, result->memblock->data, length, &s->sample_spec, s->volume); result->index = 0; assert(l); @@ -160,7 +154,7 @@ int sink_render_into(struct sink*s, struct memblock *target, struct memchunk *re if (n == 1) { struct sink_info *i = info[0].userdata; - assert(i && b); + assert(i); l = target->length; if (l > info[0].chunk.length) @@ -170,15 +164,10 @@ int sink_render_into(struct sink*s, struct memblock *target, struct memchunk *re memcpy(target->data, info[0].chunk.memblock->data + info[0].chunk.index, l); result->length = target->length = l; result->index = 0; - - if (result->length > length) - result->length = length; - - l = result->length; } else { result->memblock = target; - result->length = l = mix_chunks(info, n, target->data, target->length, &s->sample_spec); + result->length = l = mix_chunks(info, n, target->data, target->length, &s->sample_spec, s->volume); result->index = 0; assert(l); } diff --git a/src/sink.h b/src/sink.h index bd43d49d..ccfa2590 100644 --- a/src/sink.h +++ b/src/sink.h @@ -10,21 +10,10 @@ struct sink; #include "idxset.h" #include "source.h" - -struct sink_input { - int (*peek) (struct sink_input *i, struct memchunk *chunk, uint8_t *volume); - void (*drop) (struct sink_input *i, size_t length); - void (*kill) (struct sink_input *i); - - void *userdata; - int index; - struct sink *sink; -}; - struct sink { - char *name; uint32_t index; - + + char *name; struct core *core; struct sample_spec sample_spec; struct idxset *inputs; @@ -33,8 +22,8 @@ struct sink { uint8_t volume; - void (*notify)(struct sink*sink, void *userdata); - void *notify_userdata; + void (*notify)(struct sink*sink); + void *userdata; }; struct sink* sink_new(struct core *core, const char *name, const struct sample_spec *spec); @@ -44,6 +33,5 @@ int sink_render(struct sink*s, size_t length, struct memchunk *result); int sink_render_into(struct sink*s, struct memblock *target, struct memchunk *result); void sink_notify(struct sink*s); -void sink_set_notify_callback(struct sink *s, void (*notify_callback)(struct sink*sink, void *userdata), void *userdata); #endif diff --git a/src/sinkinput.c b/src/sinkinput.c index 6bc841ac..ae7b27ff 100644 --- a/src/sinkinput.c +++ b/src/sinkinput.c @@ -2,81 +2,47 @@ #include #include -#include "inputstream.h" +#include "sinkinput.h" -struct input_stream* input_stream_new(struct sink *s, struct sample_spec *spec, const char *name) { - struct input_stream *i; +struct sink_input* sink_input_new(struct sink *s, struct sample_spec *spec, const char *name) { + struct sink_input *i; int r; assert(s && spec); - i = malloc(sizeof(struct input_stream)); + i = malloc(sizeof(struct sink_input)); assert(i); i->name = name ? strdup(name) : NULL; i->sink = s; i->spec = *spec; + i->peek = NULL; + i->drop = NULL; i->kill = NULL; - i->kill_userdata = NULL; - i->notify = NULL; - i->notify_userdata = NULL; + i->userdata = NULL; - i->memblockq = memblockq_new(bytes_per_second(spec)/2, sample_size(spec), (size_t) -1); - assert(i->memblockq); - assert(s->core); - r = idxset_put(s->core->input_streams, i, &i->index); + r = idxset_put(s->core->sink_inputs, i, &i->index); assert(r == 0 && i->index != IDXSET_INVALID); - r = idxset_put(s->input_streams, i, NULL); + r = idxset_put(s->inputs, i, NULL); assert(r == 0); return i; } -void input_stream_free(struct input_stream* i) { +void sink_input_free(struct sink_input* i) { assert(i); - memblockq_free(i->memblockq); - assert(i->sink && i->sink->core); - idxset_remove_by_data(i->sink->core->input_streams, i, NULL); - idxset_remove_by_data(i->sink->input_streams, i, NULL); + idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); + idxset_remove_by_data(i->sink->inputs, i, NULL); free(i->name); free(i); } -void input_stream_notify_sink(struct input_stream *i) { - assert(i); - - if (!memblockq_is_readable(i->memblockq)) - return; - - sink_notify(i->sink); -} - -void input_stream_set_kill_callback(struct input_stream *i, void (*kill)(struct input_stream*i, void *userdata), void *userdata) { - assert(i && kill); - i->kill = kill; - i->kill_userdata = userdata; -} - - -void input_stream_kill(struct input_stream*i) { +void sink_input_kill(struct sink_input*i) { assert(i); if (i->kill) - i->kill(i, i->kill_userdata); -} - -void input_stream_set_notify_callback(struct input_stream *i, void (*notify)(struct input_stream*i, void *userdata), void *userdata) { - assert(i && notify); - - i->notify = notify; - i->notify_userdata = userdata; -} - -void input_stream_notify(struct input_stream *i) { - assert(i); - if (i->notify) - i->notify(i, i->notify_userdata); + i->kill(i); } diff --git a/src/sinkinput.h b/src/sinkinput.h index 544c3318..5e71d210 100644 --- a/src/sinkinput.h +++ b/src/sinkinput.h @@ -1,5 +1,5 @@ -#ifndef fooinputstreamhfoo -#define fooinputstreamhfoo +#ifndef foosinkinputhfoo +#define foosinkinputhfoo #include @@ -7,44 +7,26 @@ #include "sample.h" #include "memblockq.h" -struct input_stream { - char *name; +struct sink_input { uint32_t index; + char *name; struct sink *sink; struct sample_spec spec; - struct memblockq *memblockq; + int (*peek) (struct sink_input *i, struct memchunk *chunk, uint8_t *volume); + void (*drop) (struct sink_input *i, size_t length); + void (*kill) (struct sink_input *i); - void (*kill)(struct input_stream* i, void *userdata); - void *kill_userdata; - - void (*notify)(struct input_stream*i, void *userdata); - void *notify_userdata; + void *userdata; }; -struct input_stream* input_stream_new(struct sink *s, struct sample_spec *spec, const char *name); -void input_stream_free(struct input_stream* i); - -/* This function notifies the attached sink that new data is available - * in the memblockq */ -void input_stream_notify_sink(struct input_stream *i); - - -/* The registrant of the input stream should call this function to set a - * callback function which is called when destruction of the input stream is - * requested */ -void input_stream_set_kill_callback(struct input_stream *i, void (*kill)(struct input_stream*i, void *userdata), void *userdata); +struct sink_input* sink_input_new(struct sink *s, struct sample_spec *spec, const char *name); +void sink_input_free(struct sink_input* i); /* Code that didn't create the input stream should call this function to * request destruction of it */ -void input_stream_kill(struct input_stream *i); - -/* Notify the code that created this input stream that some data has - * been removed from the memblockq */ -void input_stream_set_notify_callback(struct input_stream *i, void (*notify)(struct input_stream*i, void *userdata), void *userdata); - -void input_stream_notify(struct input_stream *i); +void sink_input_kill(struct sink_input *i); #endif diff --git a/src/source.c b/src/source.c index a7fc9a64..e01e9f83 100644 --- a/src/source.c +++ b/src/source.c @@ -4,7 +4,7 @@ #include #include "source.h" -#include "outputstream.h" +#include "sourceoutput.h" struct source* source_new(struct core *core, const char *name, const struct sample_spec *spec) { struct source *s; @@ -15,31 +15,31 @@ struct source* source_new(struct core *core, const char *name, const struct samp assert(s); s->name = name ? strdup(name) : NULL; - r = idxset_put(core->sources, s, &s->index); - assert(s->index != IDXSET_INVALID && r >= 0); - s->core = core; s->sample_spec = *spec; - s->output_streams = idxset_new(NULL, NULL); + s->outputs = idxset_new(NULL, NULL); - s->link_change_callback = NULL; + s->notify = NULL; s->userdata = NULL; + r = idxset_put(core->sources, s, &s->index); + assert(s->index != IDXSET_INVALID && r >= 0); + fprintf(stderr, "source: created %u \"%s\"\n", s->index, s->name); return s; } void source_free(struct source *s) { - struct output_stream *o, *j = NULL; + struct source_output *o, *j = NULL; assert(s); - while ((o = idxset_first(s->output_streams, NULL))) { + while ((o = idxset_first(s->outputs, NULL))) { assert(o != j); - output_stream_free(o); + source_output_kill(o); j = o; } - idxset_free(s->output_streams, NULL, NULL); + idxset_free(s->outputs, NULL, NULL); idxset_remove_by_data(s->core->sources, s, NULL); @@ -49,17 +49,24 @@ void source_free(struct source *s) { free(s); } +void source_notify(struct source*s) { + assert(s); + + if (s->notify) + s->notify(s); +} + static int do_post(void *p, uint32_t index, int *del, void*userdata) { struct memchunk *chunk = userdata; - struct output_stream *o = p; - assert(o && o->memblockq && index && del && chunk); + struct source_output *o = p; + assert(o && o->push && index && del && chunk); - memblockq_push(o->memblockq, chunk, 0); + o->push(o, chunk); return 0; } void source_post(struct source*s, struct memchunk *chunk) { assert(s && chunk); - idxset_foreach(s->output_streams, do_post, chunk); + idxset_foreach(s->outputs, do_post, chunk); } diff --git a/src/source.h b/src/source.h index 3beb3f96..1442b9f0 100644 --- a/src/source.h +++ b/src/source.h @@ -10,14 +10,14 @@ struct source; #include "memblock.h" struct source { - char *name; uint32_t index; + char *name; struct core *core; struct sample_spec sample_spec; - struct idxset *output_streams; + struct idxset *outputs; - void (*link_change_callback)(struct source*source, void *userdata); + void (*notify)(struct source*source); void *userdata; }; @@ -27,4 +27,6 @@ void source_free(struct source *s); /* Pass a new memory block to all output streams */ void source_post(struct source*s, struct memchunk *b); +void source_notify(struct source *s); + #endif diff --git a/src/sourceoutput.c b/src/sourceoutput.c index c3f68a0e..d4e7a50f 100644 --- a/src/sourceoutput.c +++ b/src/sourceoutput.c @@ -2,56 +2,46 @@ #include #include -#include "outputstream.h" +#include "sourceoutput.h" -struct output_stream* output_stream_new(struct source *s, struct sample_spec *spec, const char *name) { - struct output_stream *o; +struct source_output* source_output_new(struct source *s, struct sample_spec *spec, const char *name) { + struct source_output *o; int r; assert(s && spec); - o = malloc(sizeof(struct output_stream)); + o = malloc(sizeof(struct source_output)); assert(o); o->name = name ? strdup(name) : NULL; o->source = s; o->spec = *spec; - o->kill = NULL; - o->kill_userdata = NULL; - o->memblockq = memblockq_new(bytes_per_second(spec)*5, sample_size(spec), (size_t) -1); - assert(o->memblockq); + o->push = NULL; + o->kill = NULL; + o->userdata = NULL; assert(s->core); - r = idxset_put(s->core->output_streams, o, &o->index); + r = idxset_put(s->core->source_outputs, o, &o->index); assert(r == 0 && o->index != IDXSET_INVALID); - r = idxset_put(s->output_streams, o, NULL); + r = idxset_put(s->outputs, o, NULL); assert(r == 0); return o; } -void output_stream_free(struct output_stream* o) { +void source_output_free(struct source_output* o) { assert(o); - memblockq_free(o->memblockq); - assert(o->source && o->source->core); - idxset_remove_by_data(o->source->core->output_streams, o, NULL); - idxset_remove_by_data(o->source->output_streams, o, NULL); + idxset_remove_by_data(o->source->core->source_outputs, o, NULL); + idxset_remove_by_data(o->source->outputs, o, NULL); free(o->name); free(o); } -void output_stream_set_kill_callback(struct output_stream *i, void (*kill)(struct output_stream*i, void *userdata), void *userdata) { - assert(i && kill); - i->kill = kill; - i->kill_userdata = userdata; -} - - -void output_stream_kill(struct output_stream*i) { +void source_output_kill(struct source_output*i) { assert(i); if (i->kill) - i->kill(i, i->kill_userdata); + i->kill(i); } diff --git a/src/sourceoutput.h b/src/sourceoutput.h index c6c0a717..fecfea34 100644 --- a/src/sourceoutput.h +++ b/src/sourceoutput.h @@ -1,27 +1,28 @@ -#ifndef foooutputstreamhfoo -#define foooutputstreamhfoo +#ifndef foosourceoutputhfoo +#define foosourceoutputhfoo #include + #include "source.h" #include "sample.h" #include "memblockq.h" -struct output_stream { - char *name; +struct source_output { uint32_t index; + char *name; struct source *source; struct sample_spec spec; - struct memblockq *memblockq; - void (*kill)(struct output_stream* i, void *userdata); - void *kill_userdata; + void (*push)(struct source_output *o, struct memchunk *chunk); + void (*kill)(struct source_output* o); + + void *userdata; }; -struct output_stream* output_stream_new(struct source *s, struct sample_spec *spec, const char *name); -void output_stream_free(struct output_stream* o); +struct source_output* source_output_new(struct source *s, struct sample_spec *spec, const char *name); +void source_output_free(struct source_output* o); -void output_stream_set_kill_callback(struct output_stream *i, void (*kill)(struct output_stream*i, void *userdata), void *userdata); -void output_stream_kill(struct output_stream*i); +void source_output_kill(struct source_output*o); #endif -- cgit From a8f788111cb0b18ca3517a51657881d5ffcfabae Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 15 Jun 2004 17:19:20 +0000 Subject: fix mixing git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@19 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/module-oss.c | 2 +- src/todo | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/module-oss.c b/src/module-oss.c index 07a407d8..bb8112b0 100644 --- a/src/module-oss.c +++ b/src/module-oss.c @@ -130,7 +130,7 @@ int module_init(struct core *c, struct module*m) { fprintf(stderr, "module-oss: device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); - frag_size = ((int) 4 << 16) | 10; /* nfrags = 4; frag_size = 2^10 */ + frag_size = ((int) 12 << 16) | 10; /* nfrags = 12; frag_size = 2^10 */ if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag_size) < 0) { fprintf(stderr, "SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno)); goto fail; diff --git a/src/todo b/src/todo index d4cc5f18..563ab804 100644 --- a/src/todo +++ b/src/todo @@ -1,4 +1,6 @@ - mixing +- latenzoptimierung +- optimierung von rebuild_pollfds() - resampling - native protocol/library - oss/mmap -- cgit From 4b86ff0e6cfea2c34be71ebe1102eb307bd5dc0b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 16 Jun 2004 00:05:30 +0000 Subject: got mmap oss output working git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@20 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 11 +- src/main.c | 3 +- src/memblock.c | 31 ----- src/memblock.h | 4 - src/memblockq.c | 48 ++++++- src/memblockq.h | 1 + src/module-oss-mmap.c | 369 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/module-oss.c | 60 ++++---- src/oss.c | 48 +++++++ src/oss.h | 8 ++ src/protocol-simple.c | 21 ++- src/sample.c | 21 ++- src/sample.h | 5 +- src/sink.c | 65 +++++++-- src/sink.h | 6 +- src/source.c | 2 +- src/todo | 14 +- 17 files changed, 606 insertions(+), 111 deletions(-) create mode 100644 src/module-oss-mmap.c create mode 100644 src/oss.c create mode 100644 src/oss.h diff --git a/src/Makefile.am b/src/Makefile.am index 40e2039d..8ce5202d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,7 +22,7 @@ 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 + libpacket.la module-oss.la module-oss-mmap.la liboss.la polypaudio_SOURCES = idxset.c queue.c strbuf.c mainloop.c \ memblock.c sample.c memblockq.c client.c \ @@ -50,6 +50,9 @@ libiochannel_la_LDFLAGS = -avoid-version libpacket_la_SOURCES = packet.c libpacket_la_LDFLAGS = -avoid-version +liboss_la_SOURCES = oss.c +liboss_la_LDFLAGS = -avoid-version + 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 @@ -60,4 +63,8 @@ module_pipe_sink_la_LIBADD = libiochannel.la module_oss_la_SOURCES = module-oss.c module_oss_la_LDFLAGS = -module -avoid-version -module_oss_la_LIBADD = libiochannel.la +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 diff --git a/src/main.c b/src/main.c index a42eaa82..bce07823 100644 --- a/src/main.c +++ b/src/main.c @@ -30,11 +30,10 @@ int main(int argc, char *argv[]) { mainloop_source_new_signal(m, SIGINT, signal_callback, NULL); signal(SIGPIPE, SIG_IGN); - module_load(c, "module-oss", "/dev/dsp1"); + module_load(c, "module-oss-mmap", "/dev/dsp1"); module_load(c, "module-pipe-sink", NULL); module_load(c, "module-simple-protocol-tcp", NULL); - fprintf(stderr, "main: mainloop entry.\n"); while (mainloop_iterate(m, 1) == 0); /* fprintf(stderr, "main: %u blocks\n", n_blocks);*/ diff --git a/src/memblock.c b/src/memblock.c index 2d346769..6f05918a 100644 --- a/src/memblock.c +++ b/src/memblock.c @@ -2,8 +2,6 @@ #include #include #include -#include -#include #include "memblock.h" @@ -16,7 +14,6 @@ struct memblock *memblock_new(size_t length) { b->length = length; b->data = b+1; n_blocks++; - timerclear(&b->stamp); return b; } @@ -27,7 +24,6 @@ struct memblock *memblock_new_fixed(void *d, size_t length) { b->length = length; b->data = d; n_blocks++; - timerclear(&b->stamp); return b; } @@ -38,7 +34,6 @@ struct memblock *memblock_new_dynamic(void *d, size_t length) { b->length = length; b->data = d; n_blocks++; - timerclear(&b->stamp); return b; } @@ -77,29 +72,3 @@ void memblock_unref_fixed(struct memblock *b) { b->type = MEMBLOCK_DYNAMIC; } -void memblock_stamp(struct memblock*b) { - assert(b); - gettimeofday(&b->stamp, NULL); -} - -uint32_t memblock_age(struct memblock*b) { - assert(b); - struct timeval tv; - uint32_t r; - - if (b->stamp.tv_sec == 0) - return (suseconds_t) -1; - - gettimeofday(&tv, NULL); - - /*fprintf(stderr, "memblock: (%lu,%lu) -- (%lu,%lu)\r", b->stamp.tv_sec, b->stamp.tv_usec, tv.tv_sec, tv.tv_usec);*/ - - r = (tv.tv_sec-b->stamp.tv_sec) * 1000000; - - if (tv.tv_usec >= b->stamp.tv_usec) - r += tv.tv_usec - b->stamp.tv_usec; - else - r -= b->stamp.tv_usec - tv.tv_usec; - - return r; -} diff --git a/src/memblock.h b/src/memblock.h index c0fb6708..52f1fe50 100644 --- a/src/memblock.h +++ b/src/memblock.h @@ -11,7 +11,6 @@ struct memblock { unsigned ref; size_t length; void *data; - struct timeval stamp; }; struct memchunk { @@ -28,9 +27,6 @@ struct memblock* memblock_ref(struct memblock*b); void memblock_unref_fixed(struct memblock*b); -void memblock_stamp(struct memblock*b); -uint32_t memblock_age(struct memblock*b); - #define memblock_assert_exclusive(b) assert((b)->ref == 1) extern unsigned n_blocks; diff --git a/src/memblockq.c b/src/memblockq.c index 3c0d4326..9e9c109f 100644 --- a/src/memblockq.c +++ b/src/memblockq.c @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -7,18 +9,17 @@ struct memblock_list { struct memblock_list *next; struct memchunk chunk; + struct timeval stamp; }; struct memblockq { struct memblock_list *blocks, *blocks_tail; unsigned n_blocks; - size_t total_length; - size_t maxlength; - size_t base; - size_t prebuf; + size_t total_length, maxlength, base, prebuf; + int measure_latency; + uint32_t latency; }; - struct memblockq* memblockq_new(size_t maxlength, size_t base, size_t prebuf) { struct memblockq* bq; assert(maxlength && base); @@ -37,6 +38,9 @@ struct memblockq* memblockq_new(size_t maxlength, size_t base, size_t prebuf) { assert(bq->maxlength >= base); + bq->measure_latency = 1; + bq->latency = 0; + return bq; } @@ -60,6 +64,11 @@ void memblockq_push(struct memblockq* bq, struct memchunk *chunk, size_t delta) q = malloc(sizeof(struct memblock_list)); assert(q); + if (bq->measure_latency) + gettimeofday(&q->stamp, NULL); + else + timerclear(&q->stamp); + q->chunk = *chunk; memblock_ref(q->chunk.memblock); assert(q->chunk.index+q->chunk.length <= q->chunk.memblock->length); @@ -113,6 +122,26 @@ int memblockq_pop(struct memblockq* bq, struct memchunk *chunk) { return 0; } +static uint32_t age(struct timeval *tv) { + assert(tv); + struct timeval now; + uint32_t r; + + if (tv->tv_sec == 0) + return 0; + + gettimeofday(&now, NULL); + + r = (now.tv_sec-tv->tv_sec) * 1000000; + + if (now.tv_usec >= tv->tv_usec) + r += now.tv_usec - tv->tv_usec; + else + r -= tv->tv_usec - now.tv_usec; + + return r; +} + void memblockq_drop(struct memblockq *bq, size_t length) { assert(bq); @@ -122,7 +151,10 @@ void memblockq_drop(struct memblockq *bq, size_t length) { if (l > bq->blocks->chunk.length) l = bq->blocks->chunk.length; - + + if (bq->measure_latency) + bq->latency = age(&bq->blocks->stamp); + bq->blocks->chunk.index += l; bq->blocks->chunk.length -= l; bq->total_length -= l; @@ -178,3 +210,7 @@ int memblockq_is_writable(struct memblockq *bq, size_t length) { assert(length <= bq->maxlength); return bq->total_length + length <= bq->maxlength; } + +uint32_t memblockq_get_latency(struct memblockq *bq) { + return bq->latency; +} diff --git a/src/memblockq.h b/src/memblockq.h index 25c2f2d4..9543b40a 100644 --- a/src/memblockq.h +++ b/src/memblockq.h @@ -22,5 +22,6 @@ void memblockq_empty(struct memblockq *bq); int memblockq_is_readable(struct memblockq *bq); int memblockq_is_writable(struct memblockq *bq, size_t length); +uint32_t memblockq_get_latency(struct memblockq *bq); #endif diff --git a/src/module-oss-mmap.c b/src/module-oss-mmap.c new file mode 100644 index 00000000..bfc3a6fa --- /dev/null +++ b/src/module-oss-mmap.c @@ -0,0 +1,369 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iochannel.h" +#include "sink.h" +#include "source.h" +#include "module.h" +#include "oss.h" + +struct userdata { + struct sink *sink; + struct source *source; + struct core *core; + struct sample_spec sample_spec; + + size_t in_fragment_size, out_fragment_size, in_fragments, out_fragments, sample_size, out_fill; + uint32_t sample_usec; + + int fd; + + void *in_mmap, *out_mmap; + size_t in_mmap_length, out_mmap_length; + + struct mainloop_source *mainloop_source; + + struct memblock **in_memblocks, **out_memblocks; + unsigned out_current, in_current; +}; + +void module_done(struct core *c, struct module*m); + +static void out_clear_memblocks(struct userdata*u, unsigned n) { + unsigned i = u->out_current; + assert(u && u->out_memblocks); + + if (n > u->out_fragments) + n = u->out_fragments; + + while (n > 0) { + if (u->out_memblocks[i]) { + memblock_unref_fixed(u->out_memblocks[i]); + u->out_memblocks[i] = NULL; + } + + i++; + while (i >= u->out_fragments) + i -= u->out_fragments; + + n--; + } +} + +static void out_fill_memblocks(struct userdata *u, unsigned n) { + assert(u && u->out_memblocks); + + while (n > 0) { + struct memchunk chunk; + + if (!u->out_memblocks[u->out_current]) { + + u->out_memblocks[u->out_current] = chunk.memblock = memblock_new_fixed(u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size); + chunk.length = chunk.memblock->length; + chunk.index = 0; + + sink_render_into_full(u->sink, &chunk); + } + + u->out_current++; + while (u->out_current >= u->out_fragments) + u->out_current -= u->out_fragments; + + n--; + } +} + +static void do_write(struct userdata *u) { + struct count_info info; + assert(u && u->sink); + + if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { + fprintf(stderr, "SNDCTL_DSP_GETOPTR: %s\n", strerror(errno)); + return; + } + + u->out_fill = (u->out_fragment_size * u->out_fragments) - (info.ptr % u->out_fragment_size); + + if (!info.blocks) + return; + + out_clear_memblocks(u, info.blocks); + out_fill_memblocks(u, info.blocks); + +} + +static void in_post_memblocks(struct userdata *u, unsigned n) { + assert(u && u->in_memblocks); + + while (n > 0) { + struct memchunk chunk; + + if (!u->in_memblocks[u->in_current]) { + u->in_memblocks[u->in_current] = chunk.memblock = memblock_new_fixed(u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size); + chunk.length = chunk.memblock->length; + chunk.index = 0; + + source_post(u->source, &chunk); + } + + u->in_current++; + while (u->in_current >= u->in_fragments) + u->in_current -= u->in_fragments; + + n--; + } +} + +static void in_clear_memblocks(struct userdata*u, unsigned n) { + unsigned i = u->in_current; + assert(u && u->in_memblocks); + + if (n > u->in_fragments) + n = u->in_fragments; + + while (n > 0) { + if (u->in_memblocks[i]) { + memblock_unref_fixed(u->in_memblocks[i]); + u->in_memblocks[i] = NULL; + } + + i++; + while (i >= u->in_fragments) + i -= u->in_fragments; + + n--; + } +} + +static void do_read(struct userdata *u) { + struct count_info info; + assert(u && u->source); + + if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { + fprintf(stderr, "SNDCTL_DSP_GETIPTR: %s\n", strerror(errno)); + return; + } + + if (!info.blocks) + return; + + in_post_memblocks(u, info.blocks); + in_clear_memblocks(u, u->in_fragments/2); +}; + +static void io_callback(struct mainloop_source*s, int fd, enum mainloop_io_event event, void *userdata) { + struct userdata *u = userdata; + + if (event & MAINLOOP_IO_EVENT_IN) + do_read(u); + if (event & MAINLOOP_IO_EVENT_OUT) + do_write(u); +} + +static uint32_t sink_get_latency_cb(struct sink *s) { + struct userdata *u = s->userdata; + assert(s && u); + + do_write(u); + return u->out_fill/u->sample_size*u->sample_usec; +} + +int module_init(struct core *c, struct module*m) { + struct audio_buf_info info; + struct userdata *u = NULL; + char *p; + int frag_size; + int mode, caps, caps_read = 0; + int enable_bits = 0, zero = 0; + assert(c && m); + + m->userdata = u = malloc(sizeof(struct userdata)); + assert(u); + memset(u, 0, sizeof(struct userdata)); + u->fd = -1; + u->core = c; + + p = m->argument ? m->argument : "/dev/dsp"; + if ((u->fd = open(p, (mode = O_RDWR)|O_NDELAY)) >= 0) { + ioctl(u->fd, SNDCTL_DSP_SETDUPLEX, 0); + + if (ioctl(u->fd, SNDCTL_DSP_GETCAPS, &caps) < 0) { + fprintf(stderr, "SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); + goto fail; + } + + if (!(caps & DSP_CAP_DUPLEX)) { + close(u->fd); + u->fd = -1; + } else + caps_read = 1; + } + + if (u->fd < 0) { + if ((u->fd = open(p, (mode = O_WRONLY)|O_NDELAY)) < 0) { + if ((u->fd = open(p, (mode = O_RDONLY)|O_NDELAY)) < 0) { + fprintf(stderr, "open('%s'): %s\n", p, strerror(errno)); + goto fail; + } + } + } + + if (!caps_read) { + if (ioctl(u->fd, SNDCTL_DSP_GETCAPS, &caps) < 0) { + fprintf(stderr, "SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); + goto fail; + } + } + + if (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_REALTIME) || !(caps & DSP_CAP_TRIGGER)) { + fprintf(stderr, "OSS device not mmap capable.\n"); + goto fail; + } + + fprintf(stderr, "module-oss: device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + + frag_size = ((int) 12 << 16) | 10; /* nfrags = 12; frag_size = 2^10 */ + if (ioctl(u->fd, SNDCTL_DSP_SETFRAGMENT, &frag_size) < 0) { + fprintf(stderr, "SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno)); + goto fail; + } + + if (oss_auto_format(u->fd, &u->sample_spec) < 0) + goto fail; + + if (mode != O_WRONLY) { + if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { + fprintf(stderr, "SNDCTL_DSP_GETISPACE: %s\n", strerror(errno)); + goto fail; + } + + fprintf(stderr, "module-oss-mmap: input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + u->in_mmap_length = (u->in_fragment_size = info.fragsize) * (u->in_fragments = info.fragstotal); + + if ((u->in_mmap = mmap(NULL, u->in_mmap_length, PROT_READ, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { + if (mode == O_RDWR) { + fprintf(stderr, "module-oss-mmap: mmap failed for input. Changing to O_WRONLY mode.\n"); + mode = O_WRONLY; + } else { + fprintf(stderr, "modeule-oss-mmap: mmap(): %s\n", strerror(errno)); + goto fail; + } + } else { + + u->source = source_new(c, "dsp", &u->sample_spec); + assert(u->source); + u->source->userdata = u; + + u->in_memblocks = malloc(sizeof(struct memblock *)*u->in_fragments); + memset(u->in_memblocks, 0, sizeof(struct memblock *)*u->in_fragments); + + enable_bits |= PCM_ENABLE_INPUT; + } + } + + if (m != O_RDONLY) { + if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { + fprintf(stderr, "SNDCTL_DSP_GETOSPACE: %s\n", strerror(errno)); + goto fail; + } + + fprintf(stderr, "module-oss: output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + u->out_mmap_length = (u->out_fragment_size = info.fragsize) * (u->out_fragments = info.fragstotal); + + if ((u->out_mmap = mmap(NULL, u->out_mmap_length, PROT_WRITE, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { + if (mode == O_RDWR) { + 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)); + goto fail; + } + } else { + silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec); + + u->sink = sink_new(c, "dsp", &u->sample_spec); + assert(u->sink); + u->sink->get_latency = sink_get_latency_cb; + u->sink->userdata = u; + + u->out_memblocks = malloc(sizeof(struct memblock *)*u->out_fragments); + memset(u->out_memblocks, 0, sizeof(struct memblock *)*u->out_fragments); + + enable_bits |= PCM_ENABLE_OUTPUT; + } + } + + zero = 0; + if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero) < 0) { + fprintf(stderr, "SNDCTL_DSP_SETTRIGGER: %s\n", strerror(errno)); + goto fail; + } + + if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0) { + fprintf(stderr, "SNDCTL_DSP_SETTRIGGER: %s\n", strerror(errno)); + goto fail; + } + + assert(u->source || u->sink); + + u->sample_size = sample_size(&u->sample_spec); + u->sample_usec = 1000000/u->sample_spec.rate; + + u->mainloop_source = mainloop_source_new_io(c->mainloop, u->fd, (u->source ? MAINLOOP_IO_EVENT_IN : 0) | (u->sink ? MAINLOOP_IO_EVENT_OUT : 0), io_callback, u); + assert(u->mainloop_source); + + return 0; + +fail: + module_done(c, m); + + return -1; +} + +void module_done(struct core *c, struct module*m) { + struct userdata *u; + assert(c && m); + + u = m->userdata; + assert(u); + + if (u->out_memblocks) { + out_clear_memblocks(u, u->out_fragments); + free(u->out_memblocks); + } + + if (u->in_memblocks) { + in_clear_memblocks(u, u->in_fragments); + free(u->in_memblocks); + } + + if (u->in_mmap && u->in_mmap != MAP_FAILED) + munmap(u->in_mmap, u->in_mmap_length); + + if (u->out_mmap && u->out_mmap != MAP_FAILED) + munmap(u->out_mmap, u->out_mmap_length); + + if (u->sink) + sink_free(u->sink); + + if (u->source) + source_free(u->source); + + if (u->mainloop_source) + mainloop_source_free(u->mainloop_source); + + if (u->fd >= 0) + close(u->fd); + + free(u); +} diff --git a/src/module-oss.c b/src/module-oss.c index bb8112b0..170d864d 100644 --- a/src/module-oss.c +++ b/src/module-oss.c @@ -14,6 +14,8 @@ #include "sink.h" #include "source.h" #include "module.h" +#include "oss.h" +#include "sample.h" struct userdata { struct sink *sink; @@ -23,7 +25,9 @@ struct userdata { struct memchunk memchunk, silence; - uint32_t in_fragment_size, out_fragment_size, sample_size; + uint32_t in_fragment_size, out_fragment_size, sample_size, sample_usec; + + int fd; }; static void do_write(struct userdata *u) { @@ -92,12 +96,26 @@ static void io_callback(struct iochannel *io, void*userdata) { do_read(u); } +static uint32_t sink_get_latency_cb(struct sink *s) { + int arg; + struct userdata *u = s->userdata; + assert(s && u); + + if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { + fprintf(stderr, "module-oss: device doesn't support SNDCTL_DSP_GETODELAY.\n"); + s->get_latency = NULL; + return 0; + } + + return arg/u->sample_size*u->sample_usec; +} + int module_init(struct core *c, struct module*m) { struct audio_buf_info info; struct userdata *u = NULL; char *p; int fd = -1; - int format, channels, speed, frag_size, in_frag_size, out_frag_size; + int frag_size, in_frag_size, out_frag_size; int mode; struct sample_spec ss; assert(c && m); @@ -136,37 +154,8 @@ int module_init(struct core *c, struct module*m) { goto fail; } - format = AFMT_S16_NE; - if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_S16_NE) { - int f = AFMT_S16_NE == AFMT_S16_LE ? AFMT_S16_BE : AFMT_S16_LE; - format = f; - if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != f) { - format = AFMT_U8; - if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_U8) { - fprintf(stderr, "SNDCTL_DSP_SETFMT: %s\n", format != AFMT_U8 ? "No supported sample format" : strerror(errno)); - goto fail; - } else - ss.format = SAMPLE_U8; - } else - ss.format = f == AFMT_S16_LE ? SAMPLE_S16LE : SAMPLE_S16BE; - } else - ss.format = SAMPLE_S16NE; - - channels = 2; - if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) { - fprintf(stderr, "SNDCTL_DSP_CHANNELS: %s\n", strerror(errno)); - goto fail; - } - assert(channels); - ss.channels = channels; - - speed = 44100; - if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) { - fprintf(stderr, "SNDCTL_DSP_SPEED: %s\n", strerror(errno)); + if (oss_auto_format(fd, &ss) < 0) goto fail; - } - assert(speed); - ss.rate = speed; if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) { fprintf(stderr, "SNDCTL_DSP_GETBLKSIZE: %s\n", strerror(errno)); @@ -193,12 +182,15 @@ int module_init(struct core *c, struct module*m) { if (mode != O_RDONLY) { u->sink = sink_new(c, "dsp", &ss); assert(u->sink); + u->sink->get_latency = sink_get_latency_cb; + u->sink->userdata = u; } else u->sink = NULL; if (mode != O_WRONLY) { u->source = source_new(c, "dsp", &ss); assert(u->source); + u->source->userdata = u; } else u->source = NULL; @@ -207,16 +199,18 @@ int module_init(struct core *c, struct module*m) { u->io = iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : 0); assert(u->io); iochannel_set_callback(u->io, io_callback, u); + u->fd = fd; u->memchunk.memblock = NULL; u->memchunk.length = 0; u->sample_size = sample_size(&ss); + u->sample_usec = 1000000/ss.rate; u->out_fragment_size = out_frag_size; u->in_fragment_size = in_frag_size; u->silence.memblock = memblock_new(u->silence.length = u->out_fragment_size); assert(u->silence.memblock); - silence(u->silence.memblock, &ss); + silence_memblock(u->silence.memblock, &ss); u->silence.index = 0; m->userdata = u; diff --git a/src/oss.c b/src/oss.c new file mode 100644 index 00000000..7b1315c0 --- /dev/null +++ b/src/oss.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include + +#include "oss.h" + +int oss_auto_format(int fd, struct sample_spec *ss) { + int format, channels, speed; + + assert(fd >= 0 && ss); + + format = AFMT_S16_NE; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_S16_NE) { + int f = AFMT_S16_NE == AFMT_S16_LE ? AFMT_S16_BE : AFMT_S16_LE; + format = f; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != f) { + format = AFMT_U8; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_U8) { + fprintf(stderr, "SNDCTL_DSP_SETFMT: %s\n", format != AFMT_U8 ? "No supported sample format" : strerror(errno)); + return -1; + } else + ss->format = SAMPLE_U8; + } else + ss->format = f == AFMT_S16_LE ? SAMPLE_S16LE : SAMPLE_S16BE; + } else + ss->format = SAMPLE_S16NE; + + channels = 2; + if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) { + fprintf(stderr, "SNDCTL_DSP_CHANNELS: %s\n", strerror(errno)); + return -1; + } + assert(channels); + ss->channels = channels; + + speed = 44100; + if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) { + fprintf(stderr, "SNDCTL_DSP_SPEED: %s\n", strerror(errno)); + return -1; + } + assert(speed); + ss->rate = speed; + + return 0; +} diff --git a/src/oss.h b/src/oss.h new file mode 100644 index 00000000..35d2dd02 --- /dev/null +++ b/src/oss.h @@ -0,0 +1,8 @@ +#ifndef fooosshfoo +#define fooosshfoo + +#include "sample.h" + +int oss_auto_format(int fd, struct sample_spec *ss); + +#endif diff --git a/src/protocol-simple.c b/src/protocol-simple.c index 1803936e..f779a56a 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -56,6 +56,7 @@ static void destroy_connection(struct connection *c) { static int do_read(struct connection *c) { struct memchunk chunk; ssize_t r; + uint32_t u1, u2; if (!iochannel_is_readable(c->io)) return 0; @@ -66,8 +67,6 @@ static int do_read(struct connection *c) { chunk.memblock = memblock_new(BUFSIZE); assert(chunk.memblock); - memblock_stamp(chunk.memblock); - if ((r = iochannel_read(c->io, chunk.memblock->data, BUFSIZE)) <= 0) { fprintf(stderr, "read(): %s\n", r == 0 ? "EOF" : strerror(errno)); memblock_unref(chunk.memblock); @@ -82,6 +81,13 @@ static int do_read(struct connection *c) { memblockq_push(c->input_memblockq, &chunk, 0); memblock_unref(chunk.memblock); sink_notify(c->sink_input->sink); + + + u1 = memblockq_get_latency(c->input_memblockq); + u2 = sink_get_latency(c->sink_input->sink); + + fprintf(stderr, "latency: %u+%u=%u\r", u1, u2, u1+u2); + return 0; } @@ -96,7 +102,9 @@ static int do_write(struct connection *c) { return 0; assert(c->output_memblockq); - memblockq_peek(c->output_memblockq, &chunk); + if (memblockq_peek(c->output_memblockq, &chunk) < 0) + return 0; + assert(chunk.memblock && chunk.length); if ((r = iochannel_write(c->io, chunk.memblock->data+chunk.index, chunk.length)) < 0) { @@ -145,6 +153,9 @@ static void source_output_push_cb(struct source_output *o, struct memchunk *chun assert(o && c && chunk); memblockq_push(c->output_memblockq, chunk, 0); + + if (do_write(c) < 0) + destroy_connection(c); } static void source_output_kill_cb(struct source_output *o) { @@ -205,7 +216,7 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c->source_output->kill = source_output_kill_cb; c->source_output->userdata = c; - l = 5*bytes_per_second(&DEFAULT_SAMPLE_SPEC); + l = 5*bytes_per_second(&DEFAULT_SAMPLE_SPEC); /* 5s */ c->output_memblockq = memblockq_new(l, sample_size(&DEFAULT_SAMPLE_SPEC), l/2); } @@ -225,7 +236,7 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c->sink_input->kill = sink_input_kill_cb; c->sink_input->userdata = c; - l = 5*bytes_per_second(&DEFAULT_SAMPLE_SPEC); + l = bytes_per_second(&DEFAULT_SAMPLE_SPEC)/2; /* half a second */ c->input_memblockq = memblockq_new(l, sample_size(&DEFAULT_SAMPLE_SPEC), l/2); } diff --git a/src/sample.c b/src/sample.c index 21c04628..81fe6991 100644 --- a/src/sample.c +++ b/src/sample.c @@ -9,10 +9,22 @@ struct sample_spec default_sample_spec = { .channels = 2 }; -struct memblock *silence(struct memblock* b, struct sample_spec *spec) { - char c = 0; - assert(b && spec); +struct memblock *silence_memblock(struct memblock* b, struct sample_spec *spec) { + assert(b && b->data && spec); memblock_assert_exclusive(b); + silence_memory(b->data, b->length, spec); + return b; +} + +void silence_memchunk(struct memchunk *c, struct sample_spec *spec) { + assert(c && c->memblock && c->memblock->data && spec && c->length); + memblock_assert_exclusive(c->memblock); + silence_memory(c->memblock->data+c->index, c->length, spec); +} + +void silence_memory(void *p, size_t length, struct sample_spec *spec) { + char c = 0; + assert(p && length && spec); switch (spec->format) { case SAMPLE_U8: @@ -29,8 +41,7 @@ struct memblock *silence(struct memblock* b, struct sample_spec *spec) { break; } - memset(b->data, c, b->length); - return b; + memset(p, c, length); } size_t sample_size(struct sample_spec *spec) { diff --git a/src/sample.h b/src/sample.h index f8ba6698..23fc0883 100644 --- a/src/sample.h +++ b/src/sample.h @@ -26,8 +26,9 @@ struct sample_spec { extern struct sample_spec default_sample_spec; -struct memblock *silence(struct memblock* b, struct sample_spec *spec); - +struct memblock *silence_memblock(struct memblock* b, struct sample_spec *spec); +void silence_memchunk(struct memchunk *c, struct sample_spec *spec); +void silence_memory(void *p, size_t length, struct sample_spec *spec); struct mix_info { struct memchunk chunk; diff --git a/src/sink.c b/src/sink.c index 951191dd..4d3206d8 100644 --- a/src/sink.c +++ b/src/sink.c @@ -33,6 +33,7 @@ struct sink* sink_new(struct core *core, const char *name, const struct sample_s s->volume = 0xFF; s->notify = NULL; + s->get_latency = NULL; s->userdata = NULL; r = idxset_put(core->sinks, s, &s->index); @@ -138,14 +139,18 @@ int sink_render(struct sink*s, size_t length, struct memchunk *result) { } inputs_drop(s, info, n, l); + + assert(s->monitor_source); + source_post(s->monitor_source, result); + return 0; } -int sink_render_into(struct sink*s, struct memblock *target, struct memchunk *result) { +int sink_render_into(struct sink*s, struct memchunk *target) { struct mix_info info[MAX_MIX_CHANNELS]; unsigned n; size_t l; - assert(s && target && target->length && target->data && result); + assert(s && target && target->length && target->memblock && target->memblock->data); n = fill_mix_info(s, info, MAX_MIX_CHANNELS); @@ -160,18 +165,52 @@ int sink_render_into(struct sink*s, struct memblock *target, struct memchunk *re if (l > info[0].chunk.length) l = info[0].chunk.length; - result->memblock = target; - memcpy(target->data, info[0].chunk.memblock->data + info[0].chunk.index, l); - result->length = target->length = l; - result->index = 0; - } else { + memcpy(target->memblock->data+target->index, info[0].chunk.memblock->data + info[0].chunk.index, l); + target->length = l; + } else + target->length = l = mix_chunks(info, n, target->memblock->data+target->index, target->length, &s->sample_spec, s->volume); + + assert(l); + inputs_drop(s, info, n, l); - result->memblock = target; - result->length = l = mix_chunks(info, n, target->data, target->length, &s->sample_spec, s->volume); - result->index = 0; - assert(l); - } + assert(s->monitor_source); + source_post(s->monitor_source, target); - inputs_drop(s, info, n, l); return 0; } + +void sink_render_into_full(struct sink *s, struct memchunk *target) { + struct memchunk chunk; + size_t l, d; + assert(s && target && target->memblock && target->length && target->memblock->data); + + l = target->length; + d = 0; + while (l > 0) { + chunk = *target; + chunk.index += d; + chunk.length -= d; + + if (sink_render_into(s, &chunk) < 0) + break; + + d += chunk.length; + l -= chunk.length; + } + + if (l > 0) { + chunk = *target; + chunk.index += d; + chunk.length -= d; + silence_memchunk(&chunk, &s->sample_spec); + } +} + +uint32_t sink_get_latency(struct sink *s) { + assert(s); + + if (!s->get_latency) + return 0; + + return s->get_latency(s); +} diff --git a/src/sink.h b/src/sink.h index ccfa2590..1a9fb8ca 100644 --- a/src/sink.h +++ b/src/sink.h @@ -23,6 +23,7 @@ struct sink { uint8_t volume; void (*notify)(struct sink*sink); + uint32_t (*get_latency)(struct sink *s); void *userdata; }; @@ -30,7 +31,10 @@ struct sink* sink_new(struct core *core, const char *name, const struct sample_s void sink_free(struct sink* s); int sink_render(struct sink*s, size_t length, struct memchunk *result); -int sink_render_into(struct sink*s, struct memblock *target, struct memchunk *result); +int sink_render_into(struct sink*s, struct memchunk *target); +void sink_render_into_full(struct sink *s, struct memchunk *target); + +uint32_t sink_get_latency(struct sink *s); void sink_notify(struct sink*s); diff --git a/src/source.c b/src/source.c index e01e9f83..c950b54d 100644 --- a/src/source.c +++ b/src/source.c @@ -59,7 +59,7 @@ void source_notify(struct source*s) { static int do_post(void *p, uint32_t index, int *del, void*userdata) { struct memchunk *chunk = userdata; struct source_output *o = p; - assert(o && o->push && index && del && chunk); + assert(o && o->push && del && chunk); o->push(o, chunk); return 0; diff --git a/src/todo b/src/todo index 563ab804..2ff7cc6a 100644 --- a/src/todo +++ b/src/todo @@ -1,12 +1,11 @@ -- mixing -- latenzoptimierung -- optimierung von rebuild_pollfds() -- resampling +- simple control protocol - native protocol/library -- oss/mmap -- esound prodocol +- resampling +- esound protocol - config-parser +- record-testing -- 0.1 +- optimierung von rebuild_pollfds() - future cancellation - client-ui @@ -16,3 +15,6 @@ drivers: - portaudio - mplayer - python + +modules: +- alsa? -- cgit From eb946dbdbeda66b95039b1e5ada3b9006dc33c8c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 16 Jun 2004 00:05:47 +0000 Subject: configure fix git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@21 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index de1a94ff..16376902 100644 --- a/configure.ac +++ b/configure.ac @@ -42,7 +42,7 @@ AC_PROG_LIBTOOL # If using GCC specifiy some additional parameters if test "x$GCC" = "xyes" ; then - CFLAGS="$CFLAGS -pipe -Wall" + CFLAGS="$CFLAGS -pipe -Wall -W" fi AC_CONFIG_FILES([Makefile src/Makefile]) -- cgit From 993d1bce74f4cc5be2bfa69a467aae106e2194ab Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Jun 2004 00:22:37 +0000 Subject: basic cli interface git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@22 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 35 ++++++++-- src/cli.c | 83 ++++++++++++++++++++++ src/cli.h | 14 ++++ src/client.c | 18 +++++ src/client.h | 3 +- src/core.c | 27 ------- src/core.h | 3 - src/ioline.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/ioline.h | 14 ++++ src/main.c | 4 +- src/main.h | 6 ++ src/module-cli.c | 34 +++++++++ src/module.c | 17 +++++ src/module.h | 7 +- src/protocol-simple.c | 4 +- src/sink.c | 36 ++++++++++ src/sink.h | 6 ++ src/source.c | 35 ++++++++++ src/source.h | 4 ++ src/strbuf.c | 13 ++-- src/strbuf.h | 1 + 21 files changed, 505 insertions(+), 49 deletions(-) create mode 100644 src/cli.c create mode 100644 src/cli.h create mode 100644 src/ioline.c create mode 100644 src/ioline.h create mode 100644 src/main.h create mode 100644 src/module-cli.c diff --git a/src/Makefile.am b/src/Makefile.am index 8ce5202d..5afc5bc0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 diff --git a/src/cli.c b/src/cli.c new file mode 100644 index 00000000..9aad7f56 --- /dev/null +++ b/src/cli.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include + +#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; +} diff --git a/src/cli.h b/src/cli.h new file mode 100644 index 00000000..f1b74397 --- /dev/null +++ b/src/cli.h @@ -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 diff --git a/src/client.c b/src/client.c index 1b84c6bf..4c8a0491 100644 --- a/src/client.c +++ b/src/client.c @@ -4,6 +4,7 @@ #include #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); +} + diff --git a/src/client.h b/src/client.h index 556b5fb3..48172051 100644 --- a/src/client.h +++ b/src/client.h @@ -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 diff --git a/src/core.c b/src/core.c index 0bc13a5b..50248501 100644 --- a/src/core.c +++ b/src/core.c @@ -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; -} diff --git a/src/core.h b/src/core.h index a8a140b8..f6f794b9 100644 --- a/src/core.h +++ b/src/core.h @@ -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 diff --git a/src/ioline.c b/src/ioline.c new file mode 100644 index 00000000..c37737a6 --- /dev/null +++ b/src/ioline.c @@ -0,0 +1,190 @@ +#include +#include +#include +#include +#include + +#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; +} diff --git a/src/ioline.h b/src/ioline.h new file mode 100644 index 00000000..55d7d4a3 --- /dev/null +++ b/src/ioline.h @@ -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 diff --git a/src/main.c b/src/main.c index bce07823..f35505ec 100644 --- a/src/main.c +++ b/src/main.c @@ -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); diff --git a/src/main.h b/src/main.h new file mode 100644 index 00000000..c4bea049 --- /dev/null +++ b/src/main.h @@ -0,0 +1,6 @@ +#ifndef foomainhfoo +#define foomainhfoo + +extern int stdin_inuse, stdout_inuse; + +#endif diff --git a/src/module-cli.c b/src/module-cli.c new file mode 100644 index 00000000..4af37f67 --- /dev/null +++ b/src/module-cli.c @@ -0,0 +1,34 @@ +#include +#include +#include + +#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; +} diff --git a/src/module.c b/src/module.c index 7f2bc218..0be7f5ed 100644 --- a/src/module.c +++ b/src/module.c @@ -6,6 +6,7 @@ #include #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); +} diff --git a/src/module.h b/src/module.h index 98082194..709c7f55 100644 --- a/src/module.h +++ b/src/module.h @@ -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 diff --git a/src/protocol-simple.c b/src/protocol-simple.c index f779a56a..3563419e 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -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; } diff --git a/src/sink.c b/src/sink.c index 4d3206d8..89f5e088 100644 --- a/src/sink.c +++ b/src/sink.c @@ -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); +} diff --git a/src/sink.h b/src/sink.h index 1a9fb8ca..394abb5b 100644 --- a/src/sink.h +++ b/src/sink.h @@ -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 diff --git a/src/source.c b/src/source.c index c950b54d..44d77532 100644 --- a/src/source.c +++ b/src/source.c @@ -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); +} + diff --git a/src/source.h b/src/source.h index 1442b9f0..078fb1c9 100644 --- a/src/source.h +++ b/src/source.h @@ -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 diff --git a/src/strbuf.c b/src/strbuf.c index 7c8b965d..97c451c1 100644 --- a/src/strbuf.c +++ b/src/strbuf.c @@ -1,6 +1,3 @@ -#ifndef foostrbufhfoo -#define foostrbufhfoo - #include #include #include @@ -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 diff --git a/src/strbuf.h b/src/strbuf.h index 6ad582a3..f530a0dc 100644 --- a/src/strbuf.h +++ b/src/strbuf.h @@ -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); -- cgit From 382e7aefd471a4600010a04e6497d4bfd2fd8663 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Jun 2004 17:12:50 +0000 Subject: some more work git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@23 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/cli.c | 28 +++++++++++++++++++++++++--- src/memblock.c | 16 +++++++++++----- src/memblock.h | 2 +- src/memblockq.c | 24 +++++++++++++++--------- src/memblockq.h | 3 ++- src/module-oss.c | 7 +++---- src/protocol-simple.c | 21 ++++++++++----------- src/sample.c | 6 ++++++ src/sample.h | 1 + src/sink.c | 4 +++- src/sinkinput.c | 39 +++++++++++++++++++++++++++++++++++++++ src/sinkinput.h | 7 ++++++- src/sourceoutput.c | 23 +++++++++++++++++++++++ src/sourceoutput.h | 2 ++ 14 files changed, 147 insertions(+), 36 deletions(-) diff --git a/src/cli.c b/src/cli.c index 9aad7f56..4a198141 100644 --- a/src/cli.c +++ b/src/cli.c @@ -9,6 +9,8 @@ #include "sink.h" #include "source.h" #include "client.h" +#include "sinkinput.h" +#include "sourceoutput.h" struct cli { struct core *core; @@ -34,7 +36,7 @@ struct cli* cli_new(struct core *core, struct iochannel *io) { c->eof_callback = NULL; ioline_set_callback(c->line, line_callback, c); - ioline_puts(c->line, "Welcome to polypaudio!\n> "); + ioline_puts(c->line, "Welcome to polypaudio! Use \"help\" for usage information.\n> "); return c; } @@ -66,10 +68,30 @@ static void line_callback(struct ioline *line, const char *s, void *userdata) { 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")) { + else if (!strcmp(s, "source_outputs")) + ioline_puts(line, (t = source_output_list_to_string(c->core))); + else if (!strcmp(s, "sink_inputs")) + ioline_puts(line, (t = sink_input_list_to_string(c->core))); + else if (!strcmp(s, "stat")) { + char txt[256]; + snprintf(txt, sizeof(txt), "Memory blocks allocated: %u, total size: %u bytes.\n", memblock_count, memblock_total); + ioline_puts(line, txt); + } else if (!strcmp(s, "exit")) { assert(c->core && c->core->mainloop); mainloop_quit(c->core->mainloop, -1); - } else if (*s) + } else if (!strcmp(s, "help")) + ioline_puts(line, + "Available commands:\n" + " modules\t\tlist modules\n" + " sinks\t\tlist sinks\n" + " sources\t\tlist sources\n" + " clients\t\tlist clients\n" + " source_outputs\tlist source outputs\n" + " sink_inputs\t\tlist sink inputs\n" + " stat\t\tshow memblock statistics\n" + " exit\t\tterminate the daemon\n" + " help\t\tshow this help\n"); + else if (*s) ioline_puts(line, "Unknown command\n"); free(t); diff --git a/src/memblock.c b/src/memblock.c index 6f05918a..067243c5 100644 --- a/src/memblock.c +++ b/src/memblock.c @@ -5,7 +5,7 @@ #include "memblock.h" -unsigned n_blocks = 0; +unsigned memblock_count = 0, memblock_total = 0; struct memblock *memblock_new(size_t length) { struct memblock *b = malloc(sizeof(struct memblock)+length); @@ -13,7 +13,8 @@ struct memblock *memblock_new(size_t length) { b->ref = 1; b->length = length; b->data = b+1; - n_blocks++; + memblock_count++; + memblock_total += length; return b; } @@ -23,7 +24,8 @@ struct memblock *memblock_new_fixed(void *d, size_t length) { b->ref = 1; b->length = length; b->data = d; - n_blocks++; + memblock_count++; + memblock_total += length; return b; } @@ -33,7 +35,8 @@ struct memblock *memblock_new_dynamic(void *d, size_t length) { b->ref = 1; b->length = length; b->data = d; - n_blocks++; + memblock_count++; + memblock_total += length; return b; } @@ -50,8 +53,11 @@ void memblock_unref(struct memblock*b) { if (b->ref == 0) { if (b->type == MEMBLOCK_DYNAMIC) free(b->data); + + memblock_count--; + memblock_total -= b->length; + free(b); - n_blocks--; } } diff --git a/src/memblock.h b/src/memblock.h index 52f1fe50..cba11101 100644 --- a/src/memblock.h +++ b/src/memblock.h @@ -29,6 +29,6 @@ void memblock_unref_fixed(struct memblock*b); #define memblock_assert_exclusive(b) assert((b)->ref == 1) -extern unsigned n_blocks; +extern unsigned memblock_count, memblock_total; #endif diff --git a/src/memblockq.c b/src/memblockq.c index 9e9c109f..10c59e50 100644 --- a/src/memblockq.c +++ b/src/memblockq.c @@ -16,8 +16,8 @@ struct memblockq { struct memblock_list *blocks, *blocks_tail; unsigned n_blocks; size_t total_length, maxlength, base, prebuf; - int measure_latency; - uint32_t latency; + int measure_delay; + uint32_t delay; }; struct memblockq* memblockq_new(size_t maxlength, size_t base, size_t prebuf) { @@ -38,8 +38,8 @@ struct memblockq* memblockq_new(size_t maxlength, size_t base, size_t prebuf) { assert(bq->maxlength >= base); - bq->measure_latency = 1; - bq->latency = 0; + bq->measure_delay = 0; + bq->delay = 0; return bq; } @@ -64,7 +64,7 @@ void memblockq_push(struct memblockq* bq, struct memchunk *chunk, size_t delta) q = malloc(sizeof(struct memblock_list)); assert(q); - if (bq->measure_latency) + if (bq->measure_delay) gettimeofday(&q->stamp, NULL); else timerclear(&q->stamp); @@ -152,8 +152,8 @@ void memblockq_drop(struct memblockq *bq, size_t length) { if (l > bq->blocks->chunk.length) l = bq->blocks->chunk.length; - if (bq->measure_latency) - bq->latency = age(&bq->blocks->stamp); + if (bq->measure_delay) + bq->delay = age(&bq->blocks->stamp); bq->blocks->chunk.index += l; bq->blocks->chunk.length -= l; @@ -211,6 +211,12 @@ int memblockq_is_writable(struct memblockq *bq, size_t length) { return bq->total_length + length <= bq->maxlength; } -uint32_t memblockq_get_latency(struct memblockq *bq) { - return bq->latency; +uint32_t memblockq_get_delay(struct memblockq *bq) { + assert(bq); + return bq->delay; +} + +uint32_t memblockq_get_length(struct memblockq *bq) { + assert(bq); + return bq->total_length; } diff --git a/src/memblockq.h b/src/memblockq.h index 9543b40a..0a68ddaf 100644 --- a/src/memblockq.h +++ b/src/memblockq.h @@ -22,6 +22,7 @@ void memblockq_empty(struct memblockq *bq); int memblockq_is_readable(struct memblockq *bq); int memblockq_is_writable(struct memblockq *bq, size_t length); -uint32_t memblockq_get_latency(struct memblockq *bq); +uint32_t memblockq_get_delay(struct memblockq *bq); +uint32_t memblockq_get_length(struct memblockq *bq); #endif diff --git a/src/module-oss.c b/src/module-oss.c index 170d864d..fab5c8c5 100644 --- a/src/module-oss.c +++ b/src/module-oss.c @@ -25,7 +25,7 @@ struct userdata { struct memchunk memchunk, silence; - uint32_t in_fragment_size, out_fragment_size, sample_size, sample_usec; + uint32_t in_fragment_size, out_fragment_size, sample_size; int fd; }; @@ -99,7 +99,7 @@ static void io_callback(struct iochannel *io, void*userdata) { static uint32_t sink_get_latency_cb(struct sink *s) { int arg; struct userdata *u = s->userdata; - assert(s && u); + assert(s && u && u->sink); if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { fprintf(stderr, "module-oss: device doesn't support SNDCTL_DSP_GETODELAY.\n"); @@ -107,7 +107,7 @@ static uint32_t sink_get_latency_cb(struct sink *s) { return 0; } - return arg/u->sample_size*u->sample_usec; + return samples_usec(arg, &s->sample_spec); } int module_init(struct core *c, struct module*m) { @@ -204,7 +204,6 @@ int module_init(struct core *c, struct module*m) { u->memchunk.memblock = NULL; u->memchunk.length = 0; u->sample_size = sample_size(&ss); - u->sample_usec = 1000000/ss.rate; u->out_fragment_size = out_frag_size; u->in_fragment_size = in_frag_size; diff --git a/src/protocol-simple.c b/src/protocol-simple.c index 3563419e..a0a996cb 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -56,7 +56,6 @@ static void destroy_connection(struct connection *c) { static int do_read(struct connection *c) { struct memchunk chunk; ssize_t r; - uint32_t u1, u2; if (!iochannel_is_readable(c->io)) return 0; @@ -81,12 +80,6 @@ static int do_read(struct connection *c) { memblockq_push(c->input_memblockq, &chunk, 0); memblock_unref(chunk.memblock); sink_notify(c->sink_input->sink); - - - u1 = memblockq_get_latency(c->input_memblockq); - u2 = sink_get_latency(c->sink_input->sink); - - fprintf(stderr, "latency: %u+%u=%u\r", u1, u2, u1+u2); return 0; } @@ -120,14 +113,13 @@ static int do_write(struct connection *c) { /*** sink_input callbacks ***/ -static int sink_input_peek_cb(struct sink_input *i, struct memchunk *chunk, uint8_t *volume) { +static int sink_input_peek_cb(struct sink_input *i, struct memchunk *chunk) { struct connection*c = i->userdata; - assert(i && c && chunk && volume); + assert(i && c && chunk); if (memblockq_peek(c->input_memblockq, chunk) < 0) return -1; - *volume = 0xFF; return 0; } @@ -146,6 +138,13 @@ static void sink_input_kill_cb(struct sink_input *i) { destroy_connection((struct connection *) i->userdata); } + +static uint32_t sink_input_get_latency_cb(struct sink_input *i) { + struct connection*c = i->userdata; + assert(i && c); + return samples_usec(memblockq_get_length(c->input_memblockq), &DEFAULT_SAMPLE_SPEC); +} + /*** source_output callbacks ***/ static void source_output_push_cb(struct source_output *o, struct memchunk *chunk) { @@ -163,7 +162,6 @@ static void source_output_kill_cb(struct source_output *o) { destroy_connection((struct connection *) o->userdata); } - /*** client callbacks ***/ static void client_kill_cb(struct client *c) { @@ -234,6 +232,7 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c->sink_input->peek = sink_input_peek_cb; c->sink_input->drop = sink_input_drop_cb; c->sink_input->kill = sink_input_kill_cb; + c->sink_input->get_latency = sink_input_get_latency_cb; c->sink_input->userdata = c; l = bytes_per_second(&DEFAULT_SAMPLE_SPEC)/2; /* half a second */ diff --git a/src/sample.c b/src/sample.c index 81fe6991..c270f255 100644 --- a/src/sample.c +++ b/src/sample.c @@ -113,3 +113,9 @@ size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, si data += sizeof(int16_t); } } + +uint32_t samples_usec(size_t length, struct sample_spec *spec) { + assert(spec); + + return (uint32_t) (((double) length /sample_size(spec))/spec->rate*1000000); +} diff --git a/src/sample.h b/src/sample.h index 23fc0883..5ed740e4 100644 --- a/src/sample.h +++ b/src/sample.h @@ -40,5 +40,6 @@ size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, si size_t bytes_per_second(struct sample_spec *spec); size_t sample_size(struct sample_spec *spec); +uint32_t samples_usec(size_t length, struct sample_spec *spec); #endif diff --git a/src/sink.c b/src/sink.c index 89f5e088..cd12b463 100644 --- a/src/sink.c +++ b/src/sink.c @@ -81,9 +81,11 @@ static unsigned fill_mix_info(struct sink *s, struct mix_info *info, unsigned ma for (i = idxset_first(s->inputs, &index); maxinfo > 0 && i; i = idxset_next(s->inputs, &index)) { assert(i->peek); - if (i->peek(i, &info->chunk, &info->volume) < 0) + if (i->peek(i, &info->chunk) < 0) continue; + info->volume = i->volume; + assert(info->chunk.memblock && info->chunk.memblock->data && info->chunk.length); info->userdata = i; diff --git a/src/sinkinput.c b/src/sinkinput.c index ae7b27ff..f589b4d9 100644 --- a/src/sinkinput.c +++ b/src/sinkinput.c @@ -3,6 +3,7 @@ #include #include "sinkinput.h" +#include "strbuf.h" struct sink_input* sink_input_new(struct sink *s, struct sample_spec *spec, const char *name) { struct sink_input *i; @@ -18,6 +19,7 @@ struct sink_input* sink_input_new(struct sink *s, struct sample_spec *spec, cons i->peek = NULL; i->drop = NULL; i->kill = NULL; + i->get_latency = NULL; i->userdata = NULL; assert(s->core); @@ -46,3 +48,40 @@ void sink_input_kill(struct sink_input*i) { if (i->kill) i->kill(i); } + +char *sink_input_list_to_string(struct core *c) { + struct strbuf *s; + struct sink_input *i; + uint32_t index = IDXSET_INVALID; + assert(c); + + s = strbuf_new(); + assert(s); + + strbuf_printf(s, "%u sink input(s) available.\n", idxset_ncontents(c->sink_inputs)); + + for (i = idxset_first(c->sink_inputs, &index); i; i = idxset_next(c->sink_inputs, &index)) { + assert(i->sink); + strbuf_printf(s, " index: %u, name: <%s>, sink: <%u>; volume: <0x%02x>, latency: <%u usec>\n", + i->index, + i->name, + i->sink->index, + (unsigned) i->volume, + sink_input_get_latency(i)); + } + + return strbuf_tostring_free(s); +} + +uint32_t sink_input_get_latency(struct sink_input *i) { + uint32_t l = 0; + + assert(i); + if (i->get_latency) + l += i->get_latency(i); + + assert(i->sink); + l += sink_get_latency(i->sink); + + return l; +} diff --git a/src/sinkinput.h b/src/sinkinput.h index 5e71d210..f62070c4 100644 --- a/src/sinkinput.h +++ b/src/sinkinput.h @@ -13,10 +13,13 @@ struct sink_input { char *name; struct sink *sink; struct sample_spec spec; + uint8_t volume; - int (*peek) (struct sink_input *i, struct memchunk *chunk, uint8_t *volume); + int (*peek) (struct sink_input *i, struct memchunk *chunk); void (*drop) (struct sink_input *i, size_t length); void (*kill) (struct sink_input *i); + uint32_t (*get_latency) (struct sink_input *i); + void *userdata; }; @@ -28,5 +31,7 @@ void sink_input_free(struct sink_input* i); * request destruction of it */ void sink_input_kill(struct sink_input *i); +uint32_t sink_input_get_latency(struct sink_input *i); +char *sink_input_list_to_string(struct core *c); #endif diff --git a/src/sourceoutput.c b/src/sourceoutput.c index d4e7a50f..8021b522 100644 --- a/src/sourceoutput.c +++ b/src/sourceoutput.c @@ -3,6 +3,7 @@ #include #include "sourceoutput.h" +#include "strbuf.h" struct source_output* source_output_new(struct source *s, struct sample_spec *spec, const char *name) { struct source_output *o; @@ -45,3 +46,25 @@ void source_output_kill(struct source_output*i) { if (i->kill) i->kill(i); } + +char *source_output_list_to_string(struct core *c) { + struct strbuf *s; + struct source_output *o; + uint32_t index = IDXSET_INVALID; + assert(c); + + s = strbuf_new(); + assert(s); + + strbuf_printf(s, "%u source outputs(s) available.\n", idxset_ncontents(c->source_outputs)); + + for (o = idxset_first(c->source_outputs, &index); o; o = idxset_next(c->source_outputs, &index)) { + assert(o->source); + strbuf_printf(s, " %c index: %u, name: <%s>, source: <%u>\n", + o->index, + o->name, + o->source->index); + } + + return strbuf_tostring_free(s); +} diff --git a/src/sourceoutput.h b/src/sourceoutput.h index fecfea34..359ff151 100644 --- a/src/sourceoutput.h +++ b/src/sourceoutput.h @@ -25,4 +25,6 @@ void source_output_free(struct source_output* o); void source_output_kill(struct source_output*o); +char *source_output_list_to_string(struct core *c); + #endif -- cgit From 56f8c953dd609bc5c94011fe4acdd9ef6b875747 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Jun 2004 01:01:09 +0000 Subject: some more work on the cli git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@24 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 27 ++++--- src/cli.c | 242 +++++++++++++++++++++++++++++++++++++++++++++++--------- src/dynarray.c | 73 +++++++++++++++++ src/dynarray.h | 16 ++++ src/mainloop.c | 33 +++++++- src/mainloop.h | 2 + src/module.c | 30 ++++++- src/module.h | 3 + src/sinkinput.c | 2 + src/strbuf.c | 12 ++- src/todo | 3 +- src/tokenizer.c | 64 +++++++++++++++ src/tokenizer.h | 11 +++ 13 files changed, 459 insertions(+), 59 deletions(-) create mode 100644 src/dynarray.c create mode 100644 src/dynarray.h create mode 100644 src/tokenizer.c create mode 100644 src/tokenizer.h diff --git a/src/Makefile.am b/src/Makefile.am index 5afc5bc0..9ec640c2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,7 +23,7 @@ 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 libioline.la \ - libcli.la module-cli.la + libcli.la module-cli.la libtokenizer.la libdynarray.la polypaudio_SOURCES = idxset.c idxset.h \ queue.c queue.h \ @@ -45,35 +45,42 @@ polypaudio_INCLUDES = $(INCLTDL) polypaudio_LDADD = $(LIBLTDL) polypaudio_LDFLAGS=-export-dynamic -libprotocol_simple_la_SOURCES = protocol-simple.c +libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h libprotocol_simple_la_LDFLAGS = -avoid-version libprotocol_simple_la_LIBADD = libsocket-server.la libiochannel.la -libsocket_server_la_SOURCES = socket-server.c +libsocket_server_la_SOURCES = socket-server.c socket-server.h libsocket_server_la_LDFLAGS = -avoid-version libsocket_server_la_LIBADD = libiochannel.la -libpstream_la_SOURCES = pstream.c +libpstream_la_SOURCES = pstream.c pstream.h libpstream_la_LDFLAGS = -avoid-version libpstream_la_LIBADD = libpacket.la -libiochannel_la_SOURCES = iochannel.c +libiochannel_la_SOURCES = iochannel.c iochannel.h libiochannel_la_LDFLAGS = -avoid-version -libpacket_la_SOURCES = packet.c +libpacket_la_SOURCES = packet.c packet.h libpacket_la_LDFLAGS = -avoid-version -liboss_la_SOURCES = oss.c +liboss_la_SOURCES = oss.c oss.h liboss_la_LDFLAGS = -avoid-version -libioline_la_SOURCES = ioline.c +libioline_la_SOURCES = ioline.c ioline.h libioline_la_LDFLAGS = -avoid-version libioline_la_LIBADD = libiochannel.la -libcli_la_SOURCES = cli.c +libcli_la_SOURCES = cli.c cli.h libcli_la_LDFLAGS = -avoid-version libcli_la_LIBADD = libiochannel.la libioline.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 + 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 @@ -92,4 +99,4 @@ 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 +module_cli_la_LIBADD = libcli.la libiochannel.la libtokenizer.la diff --git a/src/cli.c b/src/cli.c index 4a198141..4f67f8b7 100644 --- a/src/cli.c +++ b/src/cli.c @@ -11,6 +11,8 @@ #include "client.h" #include "sinkinput.h" #include "sourceoutput.h" +#include "tokenizer.h" +#include "strbuf.h" struct cli { struct core *core; @@ -20,8 +22,46 @@ struct cli { void *userdata; }; +struct command { + const char *name; + void (*proc) (struct cli *cli, struct tokenizer*t); + const char *help; + unsigned args; +}; + static void line_callback(struct ioline *line, const char *s, void *userdata); +static void cli_command_exit(struct cli *c, struct tokenizer *t); +static void cli_command_help(struct cli *c, struct tokenizer *t); +static void cli_command_modules(struct cli *c, struct tokenizer *t); +static void cli_command_clients(struct cli *c, struct tokenizer *t); +static void cli_command_sinks(struct cli *c, struct tokenizer *t); +static void cli_command_sources(struct cli *c, struct tokenizer *t); +static void cli_command_sink_inputs(struct cli *c, struct tokenizer *t); +static void cli_command_source_outputs(struct cli *c, struct tokenizer *t); +static void cli_command_stat(struct cli *c, struct tokenizer *t); +static void cli_command_info(struct cli *c, struct tokenizer *t); +static void cli_command_load(struct cli *c, struct tokenizer *t); +static void cli_command_unload(struct cli *c, struct tokenizer *t); + +static const struct command commands[] = { + { "exit", cli_command_exit, "Terminate the daemon", 1 }, + { "help", cli_command_help, "Show this help", 1 }, + { "modules", cli_command_modules, "List loaded modules", 1 }, + { "sinks", cli_command_sinks, "List loaded sinks", 1 }, + { "sources", cli_command_sources, "List loaded sources", 1 }, + { "clients", cli_command_clients, "List loaded clients", 1 }, + { "sink_inputs", cli_command_sink_inputs, "List sink inputs", 1 }, + { "source_outputs", cli_command_source_outputs, "List source outputs", 1 }, + { "stat", cli_command_stat, "Show memory block statistics", 1 }, + { "info", cli_command_info, "Show comprehensive status", 1 }, + { "load", cli_command_load, "Load a module (given by name and arguments)", 3 }, + { "unload", cli_command_unload, "Unload a module (specified by index)", 2 }, + { NULL, NULL, NULL, 0 } +}; + +static const char prompt[] = ">>> "; + struct cli* cli_new(struct core *core, struct iochannel *io) { struct cli *c; assert(io); @@ -36,7 +76,8 @@ struct cli* cli_new(struct core *core, struct iochannel *io) { c->eof_callback = NULL; ioline_set_callback(c->line, line_callback, c); - ioline_puts(c->line, "Welcome to polypaudio! Use \"help\" for usage information.\n> "); + ioline_puts(c->line, "Welcome to polypaudio! Use \"help\" for usage information.\n"); + ioline_puts(c->line, prompt); return c; } @@ -49,7 +90,8 @@ void cli_free(struct cli *c) { static void line_callback(struct ioline *line, const char *s, void *userdata) { struct cli *c = userdata; - char *t = NULL; + const char *cs; + const char delimiter[] = " \t\n\r"; assert(line && c); if (!s) { @@ -60,42 +102,29 @@ static void line_callback(struct ioline *line, const char *s, void *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, "source_outputs")) - ioline_puts(line, (t = source_output_list_to_string(c->core))); - else if (!strcmp(s, "sink_inputs")) - ioline_puts(line, (t = sink_input_list_to_string(c->core))); - else if (!strcmp(s, "stat")) { - char txt[256]; - snprintf(txt, sizeof(txt), "Memory blocks allocated: %u, total size: %u bytes.\n", memblock_count, memblock_total); - ioline_puts(line, txt); - } else if (!strcmp(s, "exit")) { - assert(c->core && c->core->mainloop); - mainloop_quit(c->core->mainloop, -1); - } else if (!strcmp(s, "help")) - ioline_puts(line, - "Available commands:\n" - " modules\t\tlist modules\n" - " sinks\t\tlist sinks\n" - " sources\t\tlist sources\n" - " clients\t\tlist clients\n" - " source_outputs\tlist source outputs\n" - " sink_inputs\t\tlist sink inputs\n" - " stat\t\tshow memblock statistics\n" - " exit\t\tterminate the daemon\n" - " help\t\tshow this help\n"); - else if (*s) - ioline_puts(line, "Unknown command\n"); - - free(t); - ioline_puts(line, "> "); + 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 (!strncmp(s, command->name, l)) { + struct tokenizer *t = tokenizer_new(s, command->args); + assert(t); + command->proc(c, t); + tokenizer_free(t); + unknown = 0; + break; + } + + if (unknown) + ioline_puts(line, "Unknown command\n"); + } + + ioline_puts(c->line, prompt); } void cli_set_eof_callback(struct cli *c, void (*cb)(struct cli*c, void *userdata), void *userdata) { @@ -103,3 +132,140 @@ void cli_set_eof_callback(struct cli *c, void (*cb)(struct cli*c, void *userdata c->eof_callback = cb; c->userdata = userdata; } + +static void cli_command_exit(struct cli *c, struct tokenizer *t) { + assert(c && c->core && c->core->mainloop && t); + mainloop_quit(c->core->mainloop, -1); +} + +static void cli_command_help(struct cli *c, struct tokenizer *t) { + const struct command*command; + struct strbuf *strbuf; + char *p; + assert(c && t); + + strbuf = strbuf_new(); + assert(strbuf); + + strbuf_puts(strbuf, "Available commands:\n"); + + for (command = commands; command->name; command++) + strbuf_printf(strbuf, " %-20s %s\n", command->name, command->help); + + ioline_puts(c->line, p = strbuf_tostring_free(strbuf)); + free(p); +} + +static void cli_command_modules(struct cli *c, struct tokenizer *t) { + char *s; + assert(c && t); + s = module_list_to_string(c->core); + assert(s); + ioline_puts(c->line, s); + free(s); +} + +static void cli_command_clients(struct cli *c, struct tokenizer *t) { + char *s; + assert(c && t); + s = client_list_to_string(c->core); + assert(s); + ioline_puts(c->line, s); + free(s); +} + +static void cli_command_sinks(struct cli *c, struct tokenizer *t) { + char *s; + assert(c && t); + s = sink_list_to_string(c->core); + assert(s); + ioline_puts(c->line, s); + free(s); +} + +static void cli_command_sources(struct cli *c, struct tokenizer *t) { + char *s; + assert(c && t); + s = source_list_to_string(c->core); + assert(s); + ioline_puts(c->line, s); + free(s); +} + +static void cli_command_sink_inputs(struct cli *c, struct tokenizer *t) { + char *s; + assert(c && t); + s = sink_input_list_to_string(c->core); + assert(s); + ioline_puts(c->line, s); + free(s); +} + +static void cli_command_source_outputs(struct cli *c, struct tokenizer *t) { + char *s; + assert(c && t); + s = source_output_list_to_string(c->core); + assert(s); + ioline_puts(c->line, s); + free(s); +} + +static void cli_command_stat(struct cli *c, struct tokenizer *t) { + char txt[256]; + assert(c && t); + snprintf(txt, sizeof(txt), "Memory blocks allocated: %u, total size: %u bytes.\n", memblock_count, memblock_total); + ioline_puts(c->line, txt); +} + +static void cli_command_info(struct cli *c, struct tokenizer *t) { + assert(c && t); + cli_command_stat(c, t); + cli_command_modules(c, t); + cli_command_sources(c, t); + cli_command_sinks(c, t); + cli_command_clients(c, t); + cli_command_sink_inputs(c, t); + cli_command_source_outputs(c, t); +} + +static void cli_command_load(struct cli *c, struct tokenizer *t) { + struct module *m; + const char *name; + char txt[256]; + assert(c && t); + + if (!(name = tokenizer_get(t, 1))) { + ioline_puts(c->line, "You need to specfiy the module name and optionally arguments.\n"); + return; + } + + if (!(m = module_load(c->core, name, tokenizer_get(t, 2)))) { + ioline_puts(c->line, "Module load failed.\n"); + return; + } + + snprintf(txt, sizeof(txt), "Module successfully loaded, index: %u.\n", m->index); + ioline_puts(c->line, txt); +} + +static void cli_command_unload(struct cli *c, struct tokenizer *t) { + struct module *m; + uint32_t index; + const char *i; + char *e; + assert(c && t); + + if (!(i = tokenizer_get(t, 1))) { + ioline_puts(c->line, "You need to specfiy the module index.\n"); + return; + } + + index = (uint32_t) strtoul(i, &e, 10); + if (*e || !(m = idxset_get_by_index(c->core->modules, index))) { + ioline_puts(c->line, "Invalid module index.\n"); + return; + } + + module_unload_request(c->core, m); +} + diff --git a/src/dynarray.c b/src/dynarray.c new file mode 100644 index 00000000..9a7060ee --- /dev/null +++ b/src/dynarray.c @@ -0,0 +1,73 @@ +#include +#include +#include + +#include "dynarray.h" + +struct dynarray { + void **data; + unsigned n_allocated, n_entries; +}; + +struct dynarray* dynarray_new(void) { + struct dynarray *a; + a = malloc(sizeof(struct dynarray)); + assert(a); + a->data = NULL; + a->n_entries = 0; + a->n_allocated = 0; + return a; +} + +void dynarray_free(struct dynarray* a, void (*func)(void *p, void *userdata), void *userdata) { + unsigned i; + assert(a); + + if (func) + for (i = 0; i < a->n_entries; i++) + if (a->data[i]) + func(a->data[i], userdata); + + free(a->data); + free(a); +} + +void dynarray_put(struct dynarray*a, unsigned i, void *p) { + assert(a); + + if (i >= a->n_allocated) { + unsigned n; + + if (!p) + return; + + n = i+100; + a->data = realloc(a->data, sizeof(void*)*n); + memset(a->data+a->n_allocated, 0, sizeof(void*)*(n-a->n_allocated)); + a->n_allocated = n; + } + + a->data[i] = p; + + if (i >= a->n_entries) + a->n_entries = i+1; +} + +unsigned dynarray_append(struct dynarray*a, void *p) { + unsigned i = a->n_entries; + dynarray_put(a, i, p); + return i; +} + +void *dynarray_get(struct dynarray*a, unsigned i) { + assert(a); + if (i >= a->n_allocated) + return NULL; + assert(a->data); + return a->data[i]; +} + +unsigned dynarray_ncontents(struct dynarray*a) { + assert(a); + return a->n_entries; +} diff --git a/src/dynarray.h b/src/dynarray.h new file mode 100644 index 00000000..9ab861ce --- /dev/null +++ b/src/dynarray.h @@ -0,0 +1,16 @@ +#ifndef foodynarrayhfoo +#define foodynarrayhfoo + +struct dynarray; + +struct dynarray* dynarray_new(void); +void dynarray_free(struct dynarray* a, void (*func)(void *p, void *userdata), void *userdata); + +void dynarray_put(struct dynarray*a, unsigned i, void *p); +unsigned dynarray_append(struct dynarray*a, void *p); + +void *dynarray_get(struct dynarray*a, unsigned i); + +unsigned dynarray_ncontents(struct dynarray*a); + +#endif diff --git a/src/mainloop.c b/src/mainloop.c index 37dbdb12..fba0461c 100644 --- a/src/mainloop.c +++ b/src/mainloop.c @@ -242,8 +242,8 @@ int mainloop_iterate(struct mainloop *m, int block) { free_sources(&m->signal_sources, 0); for (s = m->fixed_sources.sources; s; s = s->next) { - assert(!s->dead && s->type == MAINLOOP_SOURCE_TYPE_FIXED); - if (s->enabled) { + assert(s->type == MAINLOOP_SOURCE_TYPE_FIXED); + if (!s->dead && s->enabled) { assert(s->fixed.callback); s->fixed.callback(s, s->userdata); } @@ -264,8 +264,8 @@ int mainloop_iterate(struct mainloop *m, int block) { dispatch_pollfds(m); else if (c == 0) { for (s = m->idle_sources.sources; s; s = s->next) { - assert(!s->dead && s->type == MAINLOOP_SOURCE_TYPE_IDLE); - if (s->enabled) { + assert(s->type == MAINLOOP_SOURCE_TYPE_IDLE); + if (!s->dead && s->enabled) { assert(s->idle.callback); s->idle.callback(s, s->userdata); } @@ -448,3 +448,28 @@ struct mainloop *mainloop_source_get_mainloop(struct mainloop_source *s) { return s->mainloop; } + +struct once_info { + void (*callback)(void *userdata); + void *userdata; +}; + +static void once_callback(struct mainloop_source *s, void *userdata) { + struct once_info *i = userdata; + assert(s && i && i->callback); + i->callback(i->userdata); + mainloop_source_free(s); + free(i); +} + +void mainloop_once(struct mainloop*m, void (*callback)(void *userdata), void *userdata) { + struct once_info *i; + assert(m && callback); + + i = malloc(sizeof(struct once_info)); + assert(i); + i->callback = callback; + i->userdata = userdata; + + mainloop_source_new_fixed(m, once_callback, i); +} diff --git a/src/mainloop.h b/src/mainloop.h index 3fe26fd0..c1bfc62a 100644 --- a/src/mainloop.h +++ b/src/mainloop.h @@ -30,6 +30,8 @@ struct mainloop_source* mainloop_source_new_fixed(struct mainloop*m, void (*call struct mainloop_source* mainloop_source_new_idle(struct mainloop*m, void (*callback)(struct mainloop_source *s, void*userdata), void*userdata); struct mainloop_source* mainloop_source_new_signal(struct mainloop*m, int sig, void (*callback)(struct mainloop_source *s, int sig, void*userdata), void*userdata); +void mainloop_once(struct mainloop*m, void (*callback)(void *userdata), void *userdata); + void mainloop_source_free(struct mainloop_source*s); void mainloop_source_enable(struct mainloop_source*s, int b); diff --git a/src/module.c b/src/module.c index 0be7f5ed..c6de1751 100644 --- a/src/module.c +++ b/src/module.c @@ -17,6 +17,9 @@ struct module* module_load(struct core *c, const char *name, const char *argumen m = malloc(sizeof(struct module)); assert(m); + m->name = strdup(name); + m->argument = argument ? strdup(argument) : NULL; + if (!(m->dl = lt_dlopenext(name))) goto fail; @@ -26,8 +29,6 @@ struct module* module_load(struct core *c, const char *name, const char *argumen if (!(m->done = lt_dlsym(m->dl, "module_done"))) goto fail; - m->name = strdup(name); - m->argument = argument ? strdup(argument) : NULL; m->userdata = NULL; m->core = c; @@ -127,3 +128,28 @@ char *module_list_to_string(struct core *c) { return strbuf_tostring_free(s); } + + +struct once_info { + struct core *core; + uint32_t index; +}; + + +void module_unload_once_callback(void *userdata) { + struct once_info *i = userdata; + assert(i); + module_unload_by_index(i->core, i->index); + free(i); +} + +void module_unload_request(struct core *c, struct module *m) { + struct once_info *i; + assert(c && m); + + i = malloc(sizeof(struct once_info)); + assert(i); + i->core = c; + i->index = m->index; + mainloop_once(c->mainloop, module_unload_once_callback, i); +} diff --git a/src/module.h b/src/module.h index 709c7f55..cdb61347 100644 --- a/src/module.h +++ b/src/module.h @@ -27,4 +27,7 @@ void module_unload_all(struct core *c); char *module_list_to_string(struct core *c); +void module_unload_request(struct core *c, struct module *m); + + #endif diff --git a/src/sinkinput.c b/src/sinkinput.c index f589b4d9..2e6a8c36 100644 --- a/src/sinkinput.c +++ b/src/sinkinput.c @@ -22,6 +22,8 @@ struct sink_input* sink_input_new(struct sink *s, struct sample_spec *spec, cons i->get_latency = NULL; i->userdata = NULL; + i->volume = 0xFF; + assert(s->core); r = idxset_put(s->core->sink_inputs, i, &i->index); assert(r == 0 && i->index != IDXSET_INVALID); diff --git a/src/strbuf.c b/src/strbuf.c index 97c451c1..9ce67ec3 100644 --- a/src/strbuf.c +++ b/src/strbuf.c @@ -7,6 +7,7 @@ struct chunk { struct chunk *next; + size_t length; char text[]; }; @@ -43,12 +44,13 @@ char *strbuf_tostring(struct strbuf *sb) { assert(t); e = t; - *e = 0; for (c = sb->head; c; c = c->next) { - strcpy(e, c->text); - e = strchr(e, 0); + memcpy(e, c->text, c->length); + e += c->length; } + *e = 0; + return t; } @@ -70,7 +72,8 @@ void strbuf_puts(struct strbuf *sb, const char *t) { assert(c); c->next = NULL; - strcpy(c->text, t); + c->length = l; + memcpy(c->text, t, l); if (sb->tail) { assert(sb->head); @@ -101,6 +104,7 @@ int strbuf_printf(struct strbuf *sb, const char *format, ...) { va_end(ap); if (r > -1 && r < size) { + c->length = r; c->next = NULL; if (sb->tail) { diff --git a/src/todo b/src/todo index 2ff7cc6a..7e60ac3b 100644 --- a/src/todo +++ b/src/todo @@ -1,4 +1,5 @@ -- simple control protocol +- +- simple control protocol: kill client/input/output; set_volume - native protocol/library - resampling - esound protocol diff --git a/src/tokenizer.c b/src/tokenizer.c new file mode 100644 index 00000000..0d266a9a --- /dev/null +++ b/src/tokenizer.c @@ -0,0 +1,64 @@ +#include +#include +#include + +#include "tokenizer.h" +#include "dynarray.h" + +struct tokenizer { + struct dynarray *dynarray; +}; + +static void token_free(void *p, void *userdata) { + free(p); +} + +static void parse(struct dynarray*a, const char *s, unsigned args) { + int infty = 0; + const char delimiter[] = " \t\n\r"; + const char *p; + assert(a && s); + + if (args == 0) + infty = 1; + + p = s+strspn(s, delimiter); + while (*p && (infty || args >= 2)) { + size_t l = strcspn(p, delimiter); + char *n = strndup(p, l); + assert(n); + dynarray_append(a, n); + p += l; + p += strspn(p, delimiter); + args--; + } + + if (args && *p) { + char *n = strdup(p); + assert(n); + dynarray_append(a, n); + } +} + +struct tokenizer* tokenizer_new(const char *s, unsigned args) { + struct tokenizer *t; + + t = malloc(sizeof(struct tokenizer)); + assert(t); + t->dynarray = dynarray_new(); + assert(t->dynarray); + + parse(t->dynarray, s, args); + return t; +} + +void tokenizer_free(struct tokenizer *t) { + assert(t); + dynarray_free(t->dynarray, token_free, NULL); + free(t); +} + +const char *tokenizer_get(struct tokenizer *t, unsigned i) { + assert(t); + return dynarray_get(t->dynarray, i); +} diff --git a/src/tokenizer.h b/src/tokenizer.h new file mode 100644 index 00000000..c71ae790 --- /dev/null +++ b/src/tokenizer.h @@ -0,0 +1,11 @@ +#ifndef footokenizerhfoo +#define footokenizerhfoo + +struct tokenizer; + +struct tokenizer* tokenizer_new(const char *s, unsigned args); +void tokenizer_free(struct tokenizer *t); + +const char *tokenizer_get(struct tokenizer *t, unsigned i); + +#endif -- cgit From b4e3f5c5c5fb1cb0ddb10d123d69c211516c4ac7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Jun 2004 18:41:24 +0000 Subject: add simple ptorocol with unix git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@25 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 11 +++++++++-- src/module-simple-protocol-tcp.c | 24 ------------------------ src/module-simple-protocol.c | 29 +++++++++++++++++++++++++++++ src/todo | 9 +++++---- 4 files changed, 43 insertions(+), 30 deletions(-) delete mode 100644 src/module-simple-protocol-tcp.c create mode 100644 src/module-simple-protocol.c diff --git a/src/Makefile.am b/src/Makefile.am index 9ec640c2..59e61568 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,7 +23,8 @@ 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 libioline.la \ - libcli.la module-cli.la libtokenizer.la libdynarray.la + libcli.la module-cli.la libtokenizer.la libdynarray.la \ + module-simple-protocol-unix.la polypaudio_SOURCES = idxset.c idxset.h \ queue.c queue.h \ @@ -81,10 +82,16 @@ libtokenizer_la_SOURCES = tokenizer.c tokenizer.h libtokenizer_la_LDFLAGS = -avoid-version libtokenizer_la_LIBADD = libdynarray.la -module_simple_protocol_tcp_la_SOURCES = module-simple-protocol-tcp.c +module_simple_protocol_tcp_la_SOURCES = module-simple-protocol.c +module_simple_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS $(AM_CFLAGS) module_simple_protocol_tcp_la_LDFLAGS = -module -avoid-version module_simple_protocol_tcp_la_LIBADD = libprotocol-simple.la libiochannel.la +module_simple_protocol_unix_la_SOURCES = module-simple-protocol.c +module_simple_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS $(AM_CFLAGS) +module_simple_protocol_unix_la_LDFLAGS = -module -avoid-version +module_simple_protocol_unix_la_LIBADD = libprotocol-simple.la libiochannel.la + module_pipe_sink_la_SOURCES = module-pipe-sink.c module_pipe_sink_la_LDFLAGS = -module -avoid-version module_pipe_sink_la_LIBADD = libiochannel.la diff --git a/src/module-simple-protocol-tcp.c b/src/module-simple-protocol-tcp.c deleted file mode 100644 index e71d7142..00000000 --- a/src/module-simple-protocol-tcp.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include - -#include "module.h" -#include "socket-server.h" -#include "protocol-simple.h" - -int module_init(struct core *c, struct module*m) { - struct socket_server *s; - assert(c && m); - - if (!(s = socket_server_new_ipv4(c->mainloop, INADDR_LOOPBACK, 4712))) - return -1; - - m->userdata = protocol_simple_new(c, s, PROTOCOL_SIMPLE_PLAYBACK); - assert(m->userdata); - return 0; -} - -void module_done(struct core *c, struct module*m) { - assert(c && m); - - protocol_simple_free(m->userdata); -} diff --git a/src/module-simple-protocol.c b/src/module-simple-protocol.c new file mode 100644 index 00000000..c25ff06a --- /dev/null +++ b/src/module-simple-protocol.c @@ -0,0 +1,29 @@ +#include +#include + +#include "module.h" +#include "socket-server.h" +#include "protocol-simple.h" + +int module_init(struct core *c, struct module*m) { + struct socket_server *s; + assert(c && m); + +#ifdef USE_TCP_SOCKETS + if (!(s = socket_server_new_ipv4(c->mainloop, INADDR_LOOPBACK, 4712))) + return -1; +#else + if (!(s = socket_server_new_unix(c->mainloop, "/tmp/polypsimple"))) + return -1; +#endif + + m->userdata = protocol_simple_new(c, s, PROTOCOL_SIMPLE_PLAYBACK); + assert(m->userdata); + return 0; +} + +void module_done(struct core *c, struct module*m) { + assert(c && m); + + protocol_simple_free(m->userdata); +} diff --git a/src/todo b/src/todo index 7e60ac3b..87b5c304 100644 --- a/src/todo +++ b/src/todo @@ -1,14 +1,15 @@ -- -- simple control protocol: kill client/input/output; set_volume +- cli protocol - native protocol/library +- simple control protocol: kill client/input/output; set_volume - resampling - esound protocol -- config-parser -- record-testing +- config parser +- record testing -- 0.1 - optimierung von rebuild_pollfds() - future cancellation - client-ui +- clip cache drivers: - libao -- cgit From 787bf6cb64efaa502dfcc8c2631a8d577d591a23 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Jun 2004 18:51:30 +0000 Subject: minor work git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@26 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 20 +++++++++++++++----- src/module-simple-protocol.c | 19 ++++++++++++++++++- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 59e61568..fc7b3933 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,7 +24,8 @@ 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 libioline.la \ libcli.la module-cli.la libtokenizer.la libdynarray.la \ - module-simple-protocol-unix.la + module-simple-protocol-unix.la module-cli-protocol-tcp.la \ + libprotocol-cli.la polypaudio_SOURCES = idxset.c idxset.h \ queue.c queue.h \ @@ -82,16 +83,25 @@ libtokenizer_la_SOURCES = tokenizer.c tokenizer.h libtokenizer_la_LDFLAGS = -avoid-version libtokenizer_la_LIBADD = libdynarray.la -module_simple_protocol_tcp_la_SOURCES = module-simple-protocol.c -module_simple_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS $(AM_CFLAGS) +libprotocol_cli_la_SOURCES = protocol-cli.c protocol-cli.h +libprotocol_cli_la_LDFLAGS = -avoid-version +libprotocol_cli_la_LIBADD = libsocket-server.la libiochannel.la libcli.la + +module_simple_protocol_tcp_la_SOURCES = module-protocol-stub.c +module_simple_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) module_simple_protocol_tcp_la_LDFLAGS = -module -avoid-version module_simple_protocol_tcp_la_LIBADD = libprotocol-simple.la libiochannel.la -module_simple_protocol_unix_la_SOURCES = module-simple-protocol.c -module_simple_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS $(AM_CFLAGS) +module_simple_protocol_unix_la_SOURCES = module-protocol-stub.c +module_simple_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) module_simple_protocol_unix_la_LDFLAGS = -module -avoid-version module_simple_protocol_unix_la_LIBADD = libprotocol-simple.la libiochannel.la +module_cli_protocol_tcp_la_SOURCES = module-protocol-stub.c +module_cli_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) +module_cli_protocol_tcp_la_LDFLAGS = -module -avoid-version +module_cli_protocol_tcp_la_LIBADD = libprotocol-cli.la libiochannel.la + module_pipe_sink_la_SOURCES = module-pipe-sink.c module_pipe_sink_la_LDFLAGS = -module -avoid-version module_pipe_sink_la_LIBADD = libiochannel.la diff --git a/src/module-simple-protocol.c b/src/module-simple-protocol.c index c25ff06a..905594c6 100644 --- a/src/module-simple-protocol.c +++ b/src/module-simple-protocol.c @@ -3,7 +3,19 @@ #include "module.h" #include "socket-server.h" -#include "protocol-simple.h" + +#ifdef USE_PROTOCOL_SIMPLE + #include "protocol-simple.h" + #define protocol_free protcol_simple_free +#else + #ifdef USE_PROTOCOL_CLI + #include "protocol-cli.h" + #define protocol_new protocol_cli_new + #define protocol_free protocol_cli_free + #else + #error "Broken build system" + #endif +#endif int module_init(struct core *c, struct module*m) { struct socket_server *s; @@ -17,7 +29,12 @@ int module_init(struct core *c, struct module*m) { return -1; #endif +#ifdef USE_PROTOCOL_SIMPLE m->userdata = protocol_simple_new(c, s, PROTOCOL_SIMPLE_PLAYBACK); +#else + m->userdata = protocol_new(c, s); +#endif + assert(m->userdata); return 0; } -- cgit From 6eddcc2f856e2b8910046702e0a096e75942c2d6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Jun 2004 18:51:46 +0000 Subject: rename module-simple-protocol to module-protocol-stub git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@27 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/module-protocol-stub.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ src/module-simple-protocol.c | 46 -------------------------------------------- 2 files changed, 46 insertions(+), 46 deletions(-) create mode 100644 src/module-protocol-stub.c delete mode 100644 src/module-simple-protocol.c diff --git a/src/module-protocol-stub.c b/src/module-protocol-stub.c new file mode 100644 index 00000000..905594c6 --- /dev/null +++ b/src/module-protocol-stub.c @@ -0,0 +1,46 @@ +#include +#include + +#include "module.h" +#include "socket-server.h" + +#ifdef USE_PROTOCOL_SIMPLE + #include "protocol-simple.h" + #define protocol_free protcol_simple_free +#else + #ifdef USE_PROTOCOL_CLI + #include "protocol-cli.h" + #define protocol_new protocol_cli_new + #define protocol_free protocol_cli_free + #else + #error "Broken build system" + #endif +#endif + +int module_init(struct core *c, struct module*m) { + struct socket_server *s; + assert(c && m); + +#ifdef USE_TCP_SOCKETS + if (!(s = socket_server_new_ipv4(c->mainloop, INADDR_LOOPBACK, 4712))) + return -1; +#else + if (!(s = socket_server_new_unix(c->mainloop, "/tmp/polypsimple"))) + return -1; +#endif + +#ifdef USE_PROTOCOL_SIMPLE + m->userdata = protocol_simple_new(c, s, PROTOCOL_SIMPLE_PLAYBACK); +#else + m->userdata = protocol_new(c, s); +#endif + + assert(m->userdata); + return 0; +} + +void module_done(struct core *c, struct module*m) { + assert(c && m); + + protocol_simple_free(m->userdata); +} diff --git a/src/module-simple-protocol.c b/src/module-simple-protocol.c deleted file mode 100644 index 905594c6..00000000 --- a/src/module-simple-protocol.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include - -#include "module.h" -#include "socket-server.h" - -#ifdef USE_PROTOCOL_SIMPLE - #include "protocol-simple.h" - #define protocol_free protcol_simple_free -#else - #ifdef USE_PROTOCOL_CLI - #include "protocol-cli.h" - #define protocol_new protocol_cli_new - #define protocol_free protocol_cli_free - #else - #error "Broken build system" - #endif -#endif - -int module_init(struct core *c, struct module*m) { - struct socket_server *s; - assert(c && m); - -#ifdef USE_TCP_SOCKETS - if (!(s = socket_server_new_ipv4(c->mainloop, INADDR_LOOPBACK, 4712))) - return -1; -#else - if (!(s = socket_server_new_unix(c->mainloop, "/tmp/polypsimple"))) - return -1; -#endif - -#ifdef USE_PROTOCOL_SIMPLE - m->userdata = protocol_simple_new(c, s, PROTOCOL_SIMPLE_PLAYBACK); -#else - m->userdata = protocol_new(c, s); -#endif - - assert(m->userdata); - return 0; -} - -void module_done(struct core *c, struct module*m) { - assert(c && m); - - protocol_simple_free(m->userdata); -} -- cgit From 81447ed392e57f822e09cf648cb16732a3e3773f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Jun 2004 19:27:47 +0000 Subject: cli protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@28 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/cli.c | 2 +- src/iochannel.c | 18 ++++++++++---- src/iochannel.h | 2 ++ src/module-cli.c | 1 + src/module-protocol-stub.c | 8 ++++--- src/protocol-cli.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++ src/protocol-cli.h | 12 ++++++++++ 7 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 src/protocol-cli.c create mode 100644 src/protocol-cli.h diff --git a/src/cli.c b/src/cli.c index 4f67f8b7..ec484ace 100644 --- a/src/cli.c +++ b/src/cli.c @@ -111,7 +111,7 @@ static void line_callback(struct ioline *line, const char *s, void *userdata) { l = strcspn(s, delimiter); for (command = commands; command->name; command++) - if (!strncmp(s, command->name, l)) { + if (strlen(command->name) == l && !strncmp(s, command->name, l)) { struct tokenizer *t = tokenizer_new(s, command->args); assert(t); command->proc(c, t); diff --git a/src/iochannel.c b/src/iochannel.c index 2044d561..f0c4c499 100644 --- a/src/iochannel.c +++ b/src/iochannel.c @@ -15,6 +15,8 @@ struct iochannel { int readable; int writable; + int no_close; + struct mainloop_source* input_source, *output_source; }; @@ -83,6 +85,7 @@ struct iochannel* iochannel_new(struct mainloop*m, int ifd, int ofd) { io->callback = NULL; io->readable = 0; io->writable = 0; + io->no_close = 0; if (ifd == ofd) { assert(ifd >= 0); @@ -109,10 +112,12 @@ struct iochannel* iochannel_new(struct mainloop*m, int ifd, int ofd) { void iochannel_free(struct iochannel*io) { assert(io); - if (io->ifd >= 0) - close(io->ifd); - if (io->ofd >= 0 && io->ofd != io->ifd) - close(io->ofd); + if (!io->no_close) { + if (io->ifd >= 0) + close(io->ifd); + if (io->ofd >= 0 && io->ofd != io->ifd) + close(io->ofd); + } if (io->input_source) mainloop_source_free(io->input_source); @@ -162,3 +167,8 @@ void iochannel_set_callback(struct iochannel*io, void (*callback)(struct iochann io->callback = callback; io->userdata = userdata; } + +void iochannel_set_noclose(struct iochannel*io, int b) { + assert(io); + io->no_close = b; +} diff --git a/src/iochannel.h b/src/iochannel.h index f97fabba..8ed8b878 100644 --- a/src/iochannel.h +++ b/src/iochannel.h @@ -15,6 +15,8 @@ ssize_t iochannel_read(struct iochannel*io, void*data, size_t l); int iochannel_is_readable(struct iochannel*io); int iochannel_is_writable(struct iochannel*io); +void iochannel_set_noclose(struct iochannel*io, int b); + void iochannel_set_callback(struct iochannel*io, void (*callback)(struct iochannel*io, void *userdata), void *userdata); #endif diff --git a/src/module-cli.c b/src/module-cli.c index 4af37f67..883f4f53 100644 --- a/src/module-cli.c +++ b/src/module-cli.c @@ -19,6 +19,7 @@ int module_init(struct core *c, struct module*m) { stdin_inuse = stdout_inuse = 1; io = iochannel_new(c->mainloop, STDIN_FILENO, STDOUT_FILENO); assert(io); + iochannel_set_noclose(io, 1); m->userdata = cli_new(c, io); assert(m->userdata); diff --git a/src/module-protocol-stub.c b/src/module-protocol-stub.c index 905594c6..9cbf236e 100644 --- a/src/module-protocol-stub.c +++ b/src/module-protocol-stub.c @@ -6,12 +6,14 @@ #ifdef USE_PROTOCOL_SIMPLE #include "protocol-simple.h" - #define protocol_free protcol_simple_free + #define protocol_free protocol_simple_free + #define IPV4_PORT 4712 #else #ifdef USE_PROTOCOL_CLI #include "protocol-cli.h" #define protocol_new protocol_cli_new #define protocol_free protocol_cli_free + #define IPV4_PORT 4711 #else #error "Broken build system" #endif @@ -22,7 +24,7 @@ int module_init(struct core *c, struct module*m) { assert(c && m); #ifdef USE_TCP_SOCKETS - if (!(s = socket_server_new_ipv4(c->mainloop, INADDR_LOOPBACK, 4712))) + if (!(s = socket_server_new_ipv4(c->mainloop, INADDR_LOOPBACK, IPV4_PORT))) return -1; #else if (!(s = socket_server_new_unix(c->mainloop, "/tmp/polypsimple"))) @@ -42,5 +44,5 @@ int module_init(struct core *c, struct module*m) { void module_done(struct core *c, struct module*m) { assert(c && m); - protocol_simple_free(m->userdata); + protocol_free(m->userdata); } diff --git a/src/protocol-cli.c b/src/protocol-cli.c new file mode 100644 index 00000000..c0c93d98 --- /dev/null +++ b/src/protocol-cli.c @@ -0,0 +1,59 @@ +#include +#include + +#include "protocol-cli.h" +#include "cli.h" + +struct protocol_cli { + struct core *core; + struct socket_server*server; + struct idxset *connections; +}; + +static void cli_eof_cb(struct cli*c, void*userdata) { + struct protocol_cli *p = userdata; + assert(c && p); + + idxset_remove_by_data(p->connections, c, NULL); + cli_free(c); +} + +static void on_connection(struct socket_server*s, struct iochannel *io, void *userdata) { + struct protocol_cli *p = userdata; + struct cli *c; + assert(s && io && p); + + c = cli_new(p->core, io); + assert(c); + cli_set_eof_callback(c, cli_eof_cb, p); + + idxset_put(p->connections, c, NULL); +} + +struct protocol_cli* protocol_cli_new(struct core *core, struct socket_server *server) { + struct protocol_cli* p; + assert(core && server); + + p = malloc(sizeof(struct protocol_cli)); + assert(p); + p->core = core; + p->server = server; + p->connections = idxset_new(NULL, NULL); + + socket_server_set_callback(p->server, on_connection, p); + + return p; +} + +static void free_connection(void *p, void *userdata) { + assert(p); + cli_free(p); +} + +void protocol_cli_free(struct protocol_cli *p) { + assert(p); + + idxset_free(p->connections, free_connection, NULL); + socket_server_free(p->server); + free(p); +} diff --git a/src/protocol-cli.h b/src/protocol-cli.h new file mode 100644 index 00000000..8c150ce1 --- /dev/null +++ b/src/protocol-cli.h @@ -0,0 +1,12 @@ +#ifndef fooprotocolclihfoo +#define fooprotocolclihfoo + +#include "core.h" +#include "socket-server.h" + +struct protocol_cli; + +struct protocol_cli* protocol_cli_new(struct core *core, struct socket_server *server); +void protocol_cli_free(struct protocol_cli *n); + +#endif -- cgit -- cgit From eecf602476ff5b51bdc08f8fd0e4aa70d2b0ef5a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 20 Jun 2004 01:12:13 +0000 Subject: partial implementation of native protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@30 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 27 +++- src/module-protocol-stub.c | 13 +- src/packet.c | 21 ++- src/packet.h | 6 +- src/protocol-native-tcp.c | 19 --- src/protocol-native-unix.c | 27 ---- src/protocol-native.c | 349 ++++++++++++++++++++++++++++++++++++++++++--- src/protocol-native.h | 5 +- src/protocol-simple.c | 1 + src/pstream.c | 95 +++++++----- src/pstream.h | 6 +- src/sample.h | 2 +- src/sinkinput.h | 1 - src/tagstruct.c | 187 ++++++++++++++++++++++++ src/tagstruct.h | 30 ++++ src/todo | 1 - 16 files changed, 680 insertions(+), 110 deletions(-) delete mode 100644 src/protocol-native-tcp.c delete mode 100644 src/protocol-native-unix.c create mode 100644 src/tagstruct.c create mode 100644 src/tagstruct.h diff --git a/src/Makefile.am b/src/Makefile.am index fc7b3933..443a25f2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -# $Id: Makefile.am 27 2003-10-22 22:34:06Z lennart $ +# $Id$ # # This file is part of polypaudio. # @@ -25,7 +25,8 @@ pkglib_LTLIBRARIES=libprotocol-simple.la module-simple-protocol-tcp.la \ libpacket.la module-oss.la module-oss-mmap.la liboss.la libioline.la \ libcli.la module-cli.la libtokenizer.la libdynarray.la \ module-simple-protocol-unix.la module-cli-protocol-tcp.la \ - libprotocol-cli.la + libprotocol-cli.la libprotocol-native.la module-native-protocol-tcp.la \ + module-native-protocol-unix.la module-cli-protocol-unix.la libtagstruct.la polypaudio_SOURCES = idxset.c idxset.h \ queue.c queue.h \ @@ -87,6 +88,13 @@ libprotocol_cli_la_SOURCES = protocol-cli.c protocol-cli.h libprotocol_cli_la_LDFLAGS = -avoid-version libprotocol_cli_la_LIBADD = libsocket-server.la libiochannel.la libcli.la +libprotocol_native_la_SOURCES = protocol-native.c protocol-native.h +libprotocol_native_la_LDFLAGS = -avoid-version +libprotocol_native_la_LIBADD = libsocket-server.la libiochannel.la libpacket.la libpstream.la + +libtagstruct_la_SOURCES = tagstruct.c tagstruct.h +libtagstruct_la_LDFLAGS = -avoid-version + module_simple_protocol_tcp_la_SOURCES = module-protocol-stub.c module_simple_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) module_simple_protocol_tcp_la_LDFLAGS = -module -avoid-version @@ -102,6 +110,21 @@ module_cli_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CF module_cli_protocol_tcp_la_LDFLAGS = -module -avoid-version module_cli_protocol_tcp_la_LIBADD = libprotocol-cli.la libiochannel.la +module_cli_protocol_unix_la_SOURCES = module-protocol-stub.c +module_cli_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) +module_cli_protocol_unix_la_LDFLAGS = -module -avoid-version +module_cli_protocol_unix_la_LIBADD = libprotocol-cli.la libiochannel.la + +module_native_protocol_tcp_la_SOURCES = module-protocol-stub.c +module_native_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) +module_native_protocol_tcp_la_LDFLAGS = -module -avoid-version +module_native_protocol_tcp_la_LIBADD = libprotocol-native.la libiochannel.la libtagstruct.la + +module_native_protocol_unix_la_SOURCES = module-protocol-stub.c +module_native_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) +module_native_protocol_unix_la_LDFLAGS = -module -avoid-version +module_native_protocol_unix_la_LIBADD = libprotocol-native.la libiochannel.la libtagstruct.la + module_pipe_sink_la_SOURCES = module-pipe-sink.c module_pipe_sink_la_LDFLAGS = -module -avoid-version module_pipe_sink_la_LIBADD = libiochannel.la diff --git a/src/module-protocol-stub.c b/src/module-protocol-stub.c index 9cbf236e..2387017c 100644 --- a/src/module-protocol-stub.c +++ b/src/module-protocol-stub.c @@ -7,15 +7,22 @@ #ifdef USE_PROTOCOL_SIMPLE #include "protocol-simple.h" #define protocol_free protocol_simple_free - #define IPV4_PORT 4712 + #define IPV4_PORT 4711 #else #ifdef USE_PROTOCOL_CLI #include "protocol-cli.h" #define protocol_new protocol_cli_new #define protocol_free protocol_cli_free - #define IPV4_PORT 4711 + #define IPV4_PORT 4712 #else - #error "Broken build system" + #ifdef USE_PROTOCOL_NATIVE + #include "protocol-native.h" + #define protocol_new protocol_native_new + #define protocol_free protocol_native_free + #define IPV4_PORT 4713 + #else + #error "Broken build system" + #endif #endif #endif diff --git a/src/packet.c b/src/packet.c index 086e4b2a..47fce919 100644 --- a/src/packet.c +++ b/src/packet.c @@ -3,7 +3,7 @@ #include "packet.h" -struct packet* packet_new(uint32_t length) { +struct packet* packet_new(size_t length) { struct packet *p; assert(length); p = malloc(sizeof(struct packet)+length); @@ -11,9 +11,23 @@ struct packet* packet_new(uint32_t length) { p->ref = 1; p->length = length; + p->data = (uint8_t*) (p+1); + p->type = PACKET_APPENDED; return p; } +struct packet* packet_dynamic(uint8_t* data, size_t length) { + struct packet *p; + assert(data && length); + p = malloc(sizeof(struct packet)); + assert(p); + + p->ref = 1; + p->length = length; + p->data = data; + p->type = PACKET_DYNAMIC; +} + struct packet* packet_ref(struct packet *p) { assert(p && p->ref >= 1); p->ref++; @@ -24,6 +38,9 @@ void packet_unref(struct packet *p) { assert(p && p->ref >= 1); p->ref--; - if (p->ref == 0) + if (p->ref == 0) { + if (p->type == PACKET_DYNAMIC) + free(p->data); free(p); + } } diff --git a/src/packet.h b/src/packet.h index 781c0e66..7e2e0066 100644 --- a/src/packet.h +++ b/src/packet.h @@ -5,12 +5,14 @@ #include struct packet { + enum { PACKET_APPENDED, PACKET_DYNAMIC } type; unsigned ref; size_t length; - uint8_t data[]; + uint8_t *data; }; -struct packet* packet_new(uint32_t length); +struct packet* packet_new(size_t length); +struct packet* packet_new_dynamic(uint8_t* data, size_t length); struct packet* packet_ref(struct packet *p); void packet_unref(struct packet *p); diff --git a/src/protocol-native-tcp.c b/src/protocol-native-tcp.c deleted file mode 100644 index b33f3e15..00000000 --- a/src/protocol-native-tcp.c +++ /dev/null @@ -1,19 +0,0 @@ -#include "module.h" - -int module_init(struct core *c, struct module*m) { - struct socket_server *s; - assert(c && m); - - if (!(s = socket_server_new_ipv4(c->mainloop, INADDR_LOOPBACK, 4711))) - return -1; - - m->userdata = protocol_native_new(s); - assert(m->userdata); - return 0; -} - -void module_done(struct core *c, struct module*m) { - assert(c && m); - - protocol_native_free(m->userdata); -} diff --git a/src/protocol-native-unix.c b/src/protocol-native-unix.c deleted file mode 100644 index a18965cd..00000000 --- a/src/protocol-native-unix.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "module.h" - -int module_init(struct core *c, struct module*m) { - struct fn[PATH_MAX]; - struct socket_server *s; - char *t; - assert(c && m); - - if (!(t = getenv("TMP"))) - if (!(t = getenv("TEMP"))) - t = "/tmp"; - - snprintf(fn, sizeof(fn), "%s/foosock", t); - - if (!(s = socket_server_new_unix(c->mainloop, fn))) - return -1; - - m->userdata = protocol_native_new(s); - assert(m->userdata); - return 0; -} - -void module_done(struct core *c, struct module*m) { - assert(c && m); - - protocol_native_free(m->userdata); -} diff --git a/src/protocol-native.c b/src/protocol-native.c index bdb69355..e9cca7c1 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -1,49 +1,364 @@ +#include +#include +#include + #include "protocol-native.h" +#include "packet.h" +#include "client.h" +#include "sourceoutput.h" +#include "sinkinput.h" +#include "pstream.h" +#include "tagstruct.h" -struct protocol_native { - struct socket_server*server; - struct idxset *connection; +struct connection; +struct protocol_native; + +enum { + COMMAND_ERROR, + COMMAND_REPLY, + COMMAND_CREATE_PLAYBACK_STREAM, + COMMAND_DELETE_PLAYBACK_STREAM, + COMMAND_CREATE_RECORD_STREAM, + COMMAND_DELETE_RECORD_STREAM, + COMMAND_EXIT, + COMMAND_MAX }; -struct stream_info { - guint32_t tag; - - union { - struct output_stream *output_stream; - struct input_stream *input_stream; - } +enum { + ERROR_ACCESS, + ERROR_COMMAND, + ERROR_ARGUMENT, + ERROR_EXIST +}; + +struct record_stream { + struct connection *connection; + uint32_t index; + struct source_output *source_output; + struct memblockq *memblockq; +}; + +struct playback_stream { + struct connection *connection; + uint32_t index; + struct sink_input *sink_input; + struct memblockq *memblockq; }; struct connection { + int authorized; + struct protocol_native *protocol; struct client *client; - struct serializer *serializer; + struct pstream *pstream; + struct idxset *record_streams, *playback_streams; +}; +struct protocol_native { + int public; + struct core *core; + struct socket_server *server; + struct idxset *connections; +}; + +static void record_stream_free(struct record_stream* r) { + assert(r && r->connection); + + idxset_remove_by_data(r->connection->record_streams, r, NULL); + source_output_free(r->source_output); + memblockq_free(r->memblockq); + free(r); +} + +static struct playback_stream* playback_stream_new(struct connection *c, struct sink *sink, struct sample_spec *ss, const char *name, size_t maxlength, size_t prebuf) { + struct playback_stream *s; + + s = malloc(sizeof(struct playback_stream)); + assert (s); + s->connection = c; + s->sink_input = sink_input_new(sink, ss, name); + assert(s->sink_input); + s->memblockq = memblockq_new(maxlength, sample_size(ss), prebuf); + assert(s->memblockq); + + idxset_put(c->playback_streams, s, &s->index); + return s; +} + +static void playback_stream_free(struct playback_stream* p) { + assert(p && p->connection); + + idxset_remove_by_data(p->connection->playback_streams, p, NULL); + sink_input_free(p->sink_input); + memblockq_free(p->memblockq); + free(p); +} + +static void connection_free(struct connection *c) { + struct record_stream *r; + struct playback_stream *p; + assert(c && c->protocol); + + idxset_remove_by_data(c->protocol->connections, c, NULL); + pstream_free(c->pstream); + while ((r = idxset_first(c->record_streams, NULL))) + record_stream_free(r); + idxset_free(c->record_streams, NULL, NULL); + + while ((p = idxset_first(c->playback_streams, NULL))) + playback_stream_free(p); + idxset_free(c->playback_streams, NULL, NULL); + + client_free(c->client); + free(c); +} + +/*** pstream callbacks ***/ + +static void send_tagstruct(struct pstream *p, struct tagstruct *t) { + size_t length; + uint8_t *data; + struct packet *packet; + assert(p && t); + + data = tagstruct_free_data(t, &length); + assert(data && length); + packet = packet_new_dynamic(data, length); + assert(packet); + pstream_send_packet(p, packet); + packet_unref(packet); +} + +static void send_error(struct pstream *p, uint32_t tag, uint32_t error) { + struct tagstruct *t = tagstruct_new(NULL, 0); + assert(t); + tagstruct_putu32(t, COMMAND_ERROR); + tagstruct_putu32(t, tag); + tagstruct_putu32(t, error); + send_tagstruct(p, t); +} + +static void send_simple_ack(struct pstream *p, uint32_t tag) { + struct tagstruct *t = tagstruct_new(NULL, 0); + assert(t); + tagstruct_putu32(t, COMMAND_REPLY); + tagstruct_putu32(t, tag); + send_tagstruct(p, t); +} + +struct command { + int (*func)(struct connection *c, uint32_t tag, struct tagstruct *t); +}; + +static int command_create_playback_stream(struct connection *c, uint32_t tag, struct tagstruct *t) { + struct playback_stream *s; + size_t maxlength, prebuf; + uint32_t sink_index; + const char *name; + struct sample_spec ss; + struct tagstruct *reply; + struct sink *sink; + assert(c && t && c->protocol && c->protocol->core); + + if (tagstruct_gets(t, &name) < 0 || + tagstruct_get_sample_spec(t, &ss) < 0 || + tagstruct_getu32(t, &sink_index) < 0 || + tagstruct_getu32(t, &maxlength) < 0 || + tagstruct_getu32(t, &prebuf) < 0 || + !tagstruct_eof(t)) + return -1; + + if (!c->authorized) { + send_error(c->pstream, tag, ERROR_ACCESS); + return 0; + } + + if (sink_index == (uint32_t) -1) + sink = sink_get_default(c->protocol->core); + else + sink = idxset_get_by_index(c->protocol->core->sinks, sink_index); + + if (!sink) { + send_error(c->pstream, tag, ERROR_EXIST); + return 0; + } + if (!(s = playback_stream_new(c, sink, &ss, name, maxlength, prebuf))) { + send_error(c->pstream, tag, ERROR_ARGUMENT); + return 0; + } + + reply = tagstruct_new(NULL, 0); + assert(reply); + tagstruct_putu32(reply, COMMAND_REPLY); + tagstruct_putu32(reply, tag); + tagstruct_putu32(reply, s->index); + send_tagstruct(c->pstream, reply); + return 0; +} + +static int command_delete_playback_stream(struct connection *c, uint32_t tag, struct tagstruct *t) { + uint32_t channel; + struct playback_stream *s; + assert(c && t); + + if (tagstruct_getu32(t, &channel) < 0 || + !tagstruct_eof(t)) + return -1; + + if (!c->authorized) { + send_error(c->pstream, tag, ERROR_ACCESS); + return 0; + } + + if (!(s = idxset_get_by_index(c->playback_streams, channel))) { + send_error(c->pstream, tag, ERROR_EXIST); + return 0; + } + + send_simple_ack(c->pstream, tag); + return 0; +} + +static int command_exit(struct connection *c, uint32_t tag, struct tagstruct *t) { + assert(c && t); + + if (!tagstruct_eof(t)) + return -1; + + if (!c->authorized) { + send_error(c->pstream, tag, ERROR_ACCESS); + return 0; + } + + assert(c->protocol && c->protocol->core); + mainloop_quit(c->protocol->core->mainloop, -1); + send_simple_ack(c->pstream, tag); /* nonsense */ + return 0; +} + +static const struct command commands[] = { + [COMMAND_ERROR] = { NULL }, + [COMMAND_REPLY] = { NULL }, + [COMMAND_CREATE_PLAYBACK_STREAM] = { command_create_playback_stream }, + [COMMAND_DELETE_PLAYBACK_STREAM] = { command_delete_playback_stream }, + [COMMAND_CREATE_RECORD_STREAM] = { NULL }, + [COMMAND_DELETE_RECORD_STREAM] = { NULL }, + [COMMAND_EXIT] = { command_exit }, }; -static void on_connection(struct socket_server *server, struct iochannel *io, void *userdata) { - struct protocol_native *p = userdata; - assert(server && io && p && p->server == server); +static int packet_callback(struct pstream *p, struct packet *packet, void *userdata) { + struct connection *c = userdata; + uint32_t tag, command; + struct tagstruct *ts = NULL; + assert(p && packet && packet->data && c); + + if (packet->length <= 8) + goto fail; + + ts = tagstruct_new(packet->data, packet->length); + assert(ts); + + if (tagstruct_getu32(ts, &command) < 0 || + tagstruct_getu32(ts, &tag) < 0) + goto fail; + if (command >= COMMAND_MAX || !commands[command].func) + send_error(p, tag, ERROR_COMMAND); + else if (commands[command].func(c, tag, ts) < 0) + goto fail; + tagstruct_free(ts); + + return 0; + +fail: + if (ts) + tagstruct_free(ts); + + fprintf(stderr, "protocol-native: invalid packet.\n"); + return -1; + +} + +static int memblock_callback(struct pstream *p, uint32_t channel, int32_t delta, struct memchunk *chunk, void *userdata) { + struct connection *c = userdata; + struct playback_stream *stream; + assert(p && chunk && userdata); + + if (!(stream = idxset_get_by_index(c->playback_streams, channel))) { + fprintf(stderr, "protocol-native: client sent block for invalid stream.\n"); + return -1; + } + + memblockq_push(stream->memblockq, chunk, delta); + assert(stream->sink_input); + sink_notify(stream->sink_input->sink); + + return 0; +} + +static void die_callback(struct pstream *p, void *userdata) { + struct connection *c = userdata; + assert(p && c); + connection_free(c); + + fprintf(stderr, "protocol-native: connection died.\n"); } -struct protocol_native* protocol_native(struct socket_server *server) { +/*** socket server callbacks ***/ + +static void on_connection(struct socket_server*s, struct iochannel *io, void *userdata) { + struct protocol_native *p = userdata; + struct connection *c; + assert(s && io && p); + + c = malloc(sizeof(struct connection)); + assert(c); + c->authorized = p->public; + c->protocol = p; + assert(p->core); + c->client = client_new(p->core, "NATIVE", "Client"); + assert(c->client); + c->pstream = pstream_new(p->core->mainloop, io); + assert(c->pstream); + + pstream_set_recieve_packet_callback(c->pstream, packet_callback, c); + pstream_set_recieve_memblock_callback(c->pstream, memblock_callback, c); + pstream_set_die_callback(c->pstream, die_callback, c); + + c->record_streams = idxset_new(NULL, NULL); + c->playback_streams = idxset_new(NULL, NULL); + assert(c->record_streams && c->playback_streams); + + idxset_put(p->connections, c, NULL); +} + +/*** module entry points ***/ + +struct protocol_native* protocol_native_new(struct core *core, struct socket_server *server) { struct protocol_native *p; - assert(server); + assert(core && server); p = malloc(sizeof(struct protocol_native)); assert(p); + p->public = 1; p->server = server; - socket_server_set_callback(p->server, callback, p); + p->core = core; + p->connections = idxset_new(NULL, NULL); + socket_server_set_callback(p->server, on_connection, p); + return p; } void protocol_native_free(struct protocol_native *p) { + struct connection *c; assert(p); + while ((c = idxset_first(p->connections, NULL))) + connection_free(c); + idxset_free(p->connections, NULL, NULL); socket_server_free(p->server); free(p); } diff --git a/src/protocol-native.h b/src/protocol-native.h index bdad03b4..88283e1c 100644 --- a/src/protocol-native.h +++ b/src/protocol-native.h @@ -1,9 +1,12 @@ #ifndef fooprotocolnativehfoo #define fooprotocolnativehfoo +#include "core.h" +#include "socket-server.h" + struct protocol_native; -struct protocol_native* protocol_native(struct socket_server *server); +struct protocol_native* protocol_native_new(struct core*core, struct socket_server *server); void protocol_native_free(struct protocol_native *n); #endif diff --git a/src/protocol-simple.c b/src/protocol-simple.c index a0a996cb..8e4246cd 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -79,6 +79,7 @@ static int do_read(struct connection *c) { assert(c->input_memblockq); memblockq_push(c->input_memblockq, &chunk, 0); memblock_unref(chunk.memblock); + assert(c->sink_input); sink_notify(c->sink_input->sink); return 0; diff --git a/src/pstream.c b/src/pstream.c index 0336d161..a63e126d 100644 --- a/src/pstream.c +++ b/src/pstream.c @@ -1,5 +1,6 @@ #include #include +#include #include "pstream.h" #include "queue.h" @@ -35,6 +36,8 @@ struct pstream { struct queue *send_queue; int dead; + void (*die_callback) (struct pstream *p, void *userdad); + void *die_callback_userdata; struct { struct item_info* current; @@ -54,10 +57,10 @@ struct pstream { size_t index; } read; - void (*recieve_packet_callback) (struct pstream *p, struct packet *packet, void *userdata); + int (*recieve_packet_callback) (struct pstream *p, struct packet *packet, void *userdata); void *recieve_packet_callback_userdata; - void (*recieve_memblock_callback) (struct pstream *p, uint32_t channel, int32_t delta, struct memchunk *chunk, void *userdata); + int (*recieve_memblock_callback) (struct pstream *p, uint32_t channel, int32_t delta, struct memchunk *chunk, void *userdata); void *recieve_memblock_callback_userdata; }; @@ -89,6 +92,8 @@ struct pstream *pstream_new(struct mainloop *m, struct iochannel *io) { iochannel_set_callback(io, io_callback, p); p->dead = 0; + p->die_callback = NULL; + p->die_callback_userdata = NULL; p->mainloop = m; p->mainloop_source = mainloop_source_new_fixed(m, prepare_callback, p); @@ -165,7 +170,7 @@ void pstream_send_packet(struct pstream*p, struct packet *packet) { i = malloc(sizeof(struct item_info)); assert(i); i->type = PSTREAM_ITEM_PACKET; - i->packet = packet; + i->packet = packet_ref(packet); queue_push(p->send_queue, i); mainloop_source_enable(p->mainloop_source, 1); @@ -182,18 +187,20 @@ void pstream_send_memblock(struct pstream*p, uint32_t channel, int32_t delta, st i->channel = channel; i->delta = delta; + memblock_ref(i->chunk.memblock); + queue_push(p->send_queue, i); mainloop_source_enable(p->mainloop_source, 1); } -void pstream_set_recieve_packet_callback(struct pstream *p, void (*callback) (struct pstream *p, struct packet *packet, void *userdata), void *userdata) { +void pstream_set_recieve_packet_callback(struct pstream *p, int (*callback) (struct pstream *p, struct packet *packet, void *userdata), void *userdata) { assert(p && callback); p->recieve_packet_callback = callback; p->recieve_packet_callback_userdata = userdata; } -void pstream_set_recieve_memblock_callback(struct pstream *p, void (*callback) (struct pstream *p, uint32_t channel, int32_t delta, struct memchunk *chunk, void *userdata), void *userdata) { +void pstream_set_recieve_memblock_callback(struct pstream *p, int (*callback) (struct pstream *p, uint32_t channel, int32_t delta, struct memchunk *chunk, void *userdata), void *userdata) { assert(p && callback); p->recieve_memblock_callback = callback; @@ -211,15 +218,15 @@ static void prepare_next_write_item(struct pstream *p) { if (p->write.current->type == PSTREAM_ITEM_PACKET) { assert(p->write.current->packet); p->write.data = p->write.current->packet->data; - p->write.descriptor[PSTREAM_DESCRIPTOR_LENGTH] = p->write.current->packet->length; + p->write.descriptor[PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->packet->length); p->write.descriptor[PSTREAM_DESCRIPTOR_CHANNEL] = 0; p->write.descriptor[PSTREAM_DESCRIPTOR_DELTA] = 0; } else { assert(p->write.current->type == PSTREAM_ITEM_MEMBLOCK && p->write.current->chunk.memblock); p->write.data = p->write.current->chunk.memblock->data + p->write.current->chunk.index; - p->write.descriptor[PSTREAM_DESCRIPTOR_LENGTH] = p->write.current->chunk.length; - p->write.descriptor[PSTREAM_DESCRIPTOR_CHANNEL] = p->write.current->channel; - p->write.descriptor[PSTREAM_DESCRIPTOR_DELTA] = p->write.current->delta; + p->write.descriptor[PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length); + p->write.descriptor[PSTREAM_DESCRIPTOR_CHANNEL] = htonl(p->write.current->channel); + p->write.descriptor[PSTREAM_DESCRIPTOR_DELTA] = htonl(p->write.current->delta); } } @@ -247,17 +254,15 @@ static void do_write(struct pstream *p) { l = PSTREAM_DESCRIPTOR_SIZE - p->write.index; } else { d = (void*) p->write.data + p->write.index - PSTREAM_DESCRIPTOR_SIZE; - l = p->write.descriptor[PSTREAM_DESCRIPTOR_LENGTH] - p->write.index - PSTREAM_DESCRIPTOR_SIZE; + l = ntohl(p->write.descriptor[PSTREAM_DESCRIPTOR_LENGTH]) - p->write.index - PSTREAM_DESCRIPTOR_SIZE; } - if ((r = iochannel_write(p->io, d, l)) < 0) { - p->dead = 1; - return; - } + if ((r = iochannel_write(p->io, d, l)) < 0) + goto die; p->write.index += r; - if (p->write.index >= PSTREAM_DESCRIPTOR_SIZE+p->write.descriptor[PSTREAM_DESCRIPTOR_LENGTH]) { + if (p->write.index >= PSTREAM_DESCRIPTOR_SIZE+ntohl(p->write.descriptor[PSTREAM_DESCRIPTOR_LENGTH])) { assert(p->write.current); item_free(p->write.current, (void *) 1); p->write.current = NULL; @@ -265,6 +270,13 @@ static void do_write(struct pstream *p) { if (p->send_callback && queue_is_empty(p->send_queue)) p->send_callback(p, p->send_callback_userdata); } + + return; + +die: + p->dead = 1; + if (p->die_callback) + p->die_callback(p, p->die_callback_userdata); } static void do_read(struct pstream *p) { @@ -284,35 +296,31 @@ static void do_read(struct pstream *p) { } else { assert(p->read.data); d = (void*) p->read.data + p->read.index - PSTREAM_DESCRIPTOR_SIZE; - l = p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH] - p->read.index - PSTREAM_DESCRIPTOR_SIZE; - } - - if ((r = iochannel_read(p->io, d, l)) <= 0) { - p->dead = 1; - return; + l = ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH]) - p->read.index - PSTREAM_DESCRIPTOR_SIZE; } + if ((r = iochannel_read(p->io, d, l)) <= 0) + goto die; + p->read.index += r; if (p->read.index == PSTREAM_DESCRIPTOR_SIZE) { /* Reading of frame descriptor complete */ /* Frame size too large */ - if (p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH] > FRAME_SIZE_MAX) { - p->dead = 1; - return; - } + if (ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH]) > FRAME_SIZE_MAX) + goto die; assert(!p->read.packet && !p->read.memblock); - if (p->read.descriptor[PSTREAM_DESCRIPTOR_CHANNEL] == 0) { + if (ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_CHANNEL]) == 0) { /* Frame is a packet frame */ - p->read.packet = packet_new(p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH]); + p->read.packet = packet_new(ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH])); assert(p->read.packet); p->read.data = p->read.packet->data; } else { /* Frame is a memblock frame */ - p->read.memblock = memblock_new(p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH]); + p->read.memblock = memblock_new(ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH])); assert(p->read.memblock); p->read.data = p->read.memblock->data; } @@ -320,7 +328,7 @@ static void do_read(struct pstream *p) { } else if (p->read.index > PSTREAM_DESCRIPTOR_SIZE) { /* Frame payload available */ - if (p->read.memblock && p->recieve_memblock_callback) { /* Is this memblockd data? Than pass it to the user */ + if (p->read.memblock && p->recieve_memblock_callback) { /* Is this memblock data? Than pass it to the user */ size_t l; l = p->read.index - r < PSTREAM_DESCRIPTOR_SIZE ? p->read.index - PSTREAM_DESCRIPTOR_SIZE : r; @@ -332,28 +340,51 @@ static void do_read(struct pstream *p) { chunk.index = p->read.index - PSTREAM_DESCRIPTOR_SIZE - l; chunk.length = l; - p->recieve_memblock_callback(p, p->read.descriptor[PSTREAM_DESCRIPTOR_CHANNEL], (int32_t) p->read.descriptor[PSTREAM_DESCRIPTOR_DELTA], &chunk, p->recieve_memblock_callback_userdata); + if (p->recieve_memblock_callback(p, + ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_CHANNEL]), + (int32_t) ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_DELTA]), + &chunk, + p->recieve_memblock_callback_userdata) < 0) + goto die; } } /* Frame complete */ - if (p->read.index >= p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH] + PSTREAM_DESCRIPTOR_SIZE) { + if (p->read.index >= ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH]) + PSTREAM_DESCRIPTOR_SIZE) { if (p->read.memblock) { assert(!p->read.packet); memblock_unref(p->read.memblock); p->read.memblock = NULL; } else { + int r = 0; assert(p->read.packet); if (p->recieve_packet_callback) - p->recieve_packet_callback(p, p->read.packet, p->recieve_packet_callback_userdata); + r = p->recieve_packet_callback(p, p->read.packet, p->recieve_packet_callback_userdata); packet_unref(p->read.packet); p->read.packet = NULL; + + if (r < 0) + goto die; } p->read.index = 0; } } + + return; + +die: + p->dead = 1; + if (p->die_callback) + p->die_callback(p, p->die_callback_userdata); + +} + +void pstream_set_die_callback(struct pstream *p, void (*callback)(struct pstream *p, void *userdata), void *userdata) { + assert(p && callback); + p->die_callback = callback; + p->die_callback_userdata = userdata; } diff --git a/src/pstream.h b/src/pstream.h index c0b57496..7113681e 100644 --- a/src/pstream.h +++ b/src/pstream.h @@ -16,7 +16,9 @@ void pstream_set_send_callback(struct pstream*p, void (*callback) (struct pstrea void pstream_send_packet(struct pstream*p, struct packet *packet); void pstream_send_memblock(struct pstream*p, uint32_t channel, int32_t delta, struct memchunk *chunk); -void pstream_set_recieve_packet_callback(struct pstream *p, void (*callback) (struct pstream *p, struct packet *packet, void *userdata), void *userdata); -void pstream_set_recieve_memblock_callback(struct pstream *p, void (*callback) (struct pstream *p, uint32_t channel, int32_t delta, struct memchunk *chunk, void *userdata), void *userdata); +void pstream_set_recieve_packet_callback(struct pstream *p, int (*callback) (struct pstream *p, struct packet *packet, void *userdata), void *userdata); +void pstream_set_recieve_memblock_callback(struct pstream *p, int (*callback) (struct pstream *p, uint32_t channel, int32_t delta, struct memchunk *chunk, void *userdata), void *userdata); + +void pstream_set_die_callback(struct pstream *p, void (*callback)(struct pstream *p, void *userdata), void *userdata); #endif diff --git a/src/sample.h b/src/sample.h index 5ed740e4..b2f13cc4 100644 --- a/src/sample.h +++ b/src/sample.h @@ -19,7 +19,7 @@ enum sample_format { struct sample_spec { enum sample_format format; uint32_t rate; - uint32_t channels; + uint8_t channels; }; #define DEFAULT_SAMPLE_SPEC default_sample_spec diff --git a/src/sinkinput.h b/src/sinkinput.h index f62070c4..389d832d 100644 --- a/src/sinkinput.h +++ b/src/sinkinput.h @@ -19,7 +19,6 @@ struct sink_input { void (*drop) (struct sink_input *i, size_t length); void (*kill) (struct sink_input *i); uint32_t (*get_latency) (struct sink_input *i); - void *userdata; }; diff --git a/src/tagstruct.c b/src/tagstruct.c new file mode 100644 index 00000000..429dd408 --- /dev/null +++ b/src/tagstruct.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include + +#include "tagstruct.h" + +enum tags { + TAG_STRING = 't', + TAG_U32 = 'L', + TAG_S32 = 'l', + TAG_U16 = 'S', + TAG_S16 = 's', + TAG_U8 = 'B', + TAG_S8 = 'b', + TAG_SAMPLE_SPEC = 'a' +}; + +struct tagstruct { + uint8_t *data; + size_t length, allocated; + size_t rindex; + + int dynamic; +}; + +struct tagstruct *tagstruct_new(const uint8_t* data, size_t length) { + struct tagstruct*t; + + assert(!data || (data && length)); + + t = malloc(sizeof(struct tagstruct)); + assert(t); + t->data = (uint8_t*) data; + t->allocated = t->length = data ? length : 0; + t->rindex = 0; + t->dynamic = !!data; + return t; +} + +void tagstruct_free(struct tagstruct*t) { + assert(t); + if (t->dynamic) + free(t->data); + free(t); +} + +uint8_t* tagstruct_free_data(struct tagstruct*t, size_t *l) { + uint8_t *p; + assert(t && t->dynamic && l); + p = t->data; + *l = t->length; + free(t); + return p; +} + +static void extend(struct tagstruct*t, size_t l) { + assert(t && t->dynamic); + + if (t->allocated <= l) + return; + + t->data = realloc(t->data, t->allocated = l+100); + assert(t->data); +} + +void tagstruct_puts(struct tagstruct*t, const char *s) { + size_t l; + assert(t && s); + l = strlen(s)+2; + extend(t, l); + t->data[t->length] = TAG_STRING; + strcpy(t->data+t->length+1, s); + t->length += l; +} + +void tagstruct_putu32(struct tagstruct*t, uint32_t i) { + assert(t && i); + extend(t, 5); + t->data[t->length] = TAG_U32; + *((uint32_t*) (t->data+t->length+1)) = htonl(i); + t->length += 5; +} + +void tagstruct_putu8(struct tagstruct*t, uint8_t c) { + assert(t && c); + extend(t, 2); + t->data[t->length] = TAG_U8; + *(t->data+t->length+1) = c; + t->length += 2; +} + +void tagstruct_put_sample_spec(struct tagstruct *t, struct sample_spec *ss) { + assert(t && ss); + extend(t, 7); + t->data[t->length] = TAG_SAMPLE_SPEC; + t->data[t->length+1] = (uint8_t) ss->format; + t->data[t->length+2] = ss->channels; + *(uint32_t*) (t->data+t->length+3) = htonl(ss->rate); + t->length += 7; +} + +int tagstruct_gets(struct tagstruct*t, const char **s) { + int error = 0; + size_t n; + char *c; + assert(t && s); + + if (t->rindex+2 > t->length) + return -1; + + if (t->data[t->rindex] != TAG_STRING) + return -1; + + error = 1; + for (n = 0, c = (char*) (t->data+t->rindex+1); n < t->length-t->rindex-1; c++) + if (!*c) { + error = 0; + break; + } + + if (error) + return -1; + + *s = (char*) (t->data+t->rindex+1); + + t->rindex += n+1; + return 0; +} + +int tagstruct_getu32(struct tagstruct*t, uint32_t *i) { + assert(t && i); + + if (t->rindex+5 > t->length) + return -1; + + if (t->data[t->rindex] != TAG_U32) + return -1; + + *i = ntohl(*((uint32_t*) (t->data+t->rindex+1))); + t->rindex += 5; + return 0; +} + +int tagstruct_getu8(struct tagstruct*t, uint8_t *c) { + assert(t && c); + + if (t->rindex+2 > t->length) + return -1; + + if (t->data[t->rindex] != TAG_U8) + return -1; + + *c = t->data[t->rindex+1]; + t->rindex +=2; + return 0; +} + +int tagstruct_get_sample_spec(struct tagstruct *t, struct sample_spec *ss) { + assert(t && ss); + + if (t->rindex+7 > t->length) + return -1; + + if (t->data[t->rindex] != TAG_SAMPLE_SPEC) + return -1; + + ss->format = t->data[t->rindex+1]; + ss->channels = t->data[t->rindex+2]; + ss->rate = ntohl(*(uint32_t*) (t->data+t->rindex+3)); + + t->rindex += 7; + return 0; +} + + +int tagstruct_eof(struct tagstruct*t) { + assert(t); + return t->rindex >= t->length; +} + +const uint8_t* tagstruct_data(struct tagstruct*t, size_t *l) { + assert(t && t->dynamic && l); + *l = t->length; + return t->data; +} + diff --git a/src/tagstruct.h b/src/tagstruct.h new file mode 100644 index 00000000..5572c64c --- /dev/null +++ b/src/tagstruct.h @@ -0,0 +1,30 @@ +#ifndef footagstructhfoo +#define footagstructhfoo + +#include +#include + +#include "sample.h" + +struct tagstruct; + +struct tagstruct *tagstruct_new(const uint8_t* data, size_t length); +void tagstruct_free(struct tagstruct*t); +uint8_t* tagstruct_free_data(struct tagstruct*t, size_t *l); + +void tagstruct_puts(struct tagstruct*t, const char *s); +void tagstruct_putu32(struct tagstruct*t, uint32_t i); +void tagstruct_putu8(struct tagstruct*t, uint8_t c); +void tagstruct_put_sample_spec(struct tagstruct *t, struct sample_spec *ss); + +int tagstruct_gets(struct tagstruct*t, const char **s); +int tagstruct_getu32(struct tagstruct*t, uint32_t *i); +int tagstruct_getu8(struct tagstruct*t, uint8_t *c); +int tagstruct_get_sample_spec(struct tagstruct *t, struct sample_spec *ss); + +int tagstruct_eof(struct tagstruct*t); +const uint8_t* tagstruct_data(struct tagstruct*t, size_t *l); + + + +#endif diff --git a/src/todo b/src/todo index 87b5c304..aeb7ae5f 100644 --- a/src/todo +++ b/src/todo @@ -1,4 +1,3 @@ -- cli protocol - native protocol/library - simple control protocol: kill client/input/output; set_volume - resampling -- cgit From acb25b35102dfca08f66e155560f6c99cb8fa841 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 Jun 2004 23:17:30 +0000 Subject: main part of the native protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@31 fefdeb5f-60dc-0310-8127-8f9354f1896f --- bootstrap.sh | 2 +- configure.ac | 2 +- src/Makefile.am | 57 +++- src/cli.c | 12 +- src/core.c | 2 +- src/core.h | 6 +- src/iochannel.c | 52 ++-- src/iochannel.h | 6 +- src/main.c | 36 ++- src/mainloop-api.c | 35 +++ src/mainloop-api.h | 43 +++ src/mainloop-signal.c | 138 +++++++++ src/mainloop-signal.h | 12 + src/mainloop.c | 732 ++++++++++++++++++++++++--------------------- src/mainloop.h | 40 +-- src/memblockq.c | 9 + src/memblockq.h | 2 + src/module-oss-mmap.c | 23 +- src/module-oss.c | 10 +- src/module-pipe-sink.c | 20 +- src/module.c | 2 +- src/oss.c | 2 +- src/oss.h | 2 +- src/pacat.c | 169 +++++++++++ src/packet.c | 3 +- src/pdispatch.c | 149 +++++++++ src/pdispatch.h | 22 ++ src/polyp.c | 451 ++++++++++++++++++++++++++++ src/polyp.h | 53 ++++ src/polypdef.h | 18 ++ src/protocol-cli.c | 5 +- src/protocol-native-spec.h | 29 ++ src/protocol-native.c | 228 +++++++------- src/protocol-simple.c | 22 +- src/pstream-util.c | 35 +++ src/pstream-util.h | 14 + src/pstream.c | 34 ++- src/pstream.h | 3 +- src/queue.c | 7 + src/sample-util.c | 88 ++++++ src/sample-util.h | 23 ++ src/sample.c | 94 +----- src/sample.h | 31 +- src/simple.c | 120 ++++++++ src/simple.h | 25 ++ src/sink.c | 3 +- src/sink.h | 4 +- src/sinkinput.c | 4 +- src/sinkinput.h | 4 +- src/socket-client.c | 177 +++++++++++ src/socket-client.h | 17 ++ src/socket-server.c | 21 +- src/socket-server.h | 8 +- src/source.c | 2 +- src/source.h | 4 +- src/sourceoutput.c | 4 +- src/sourceoutput.h | 4 +- src/tagstruct.c | 4 +- src/tagstruct.h | 4 +- src/todo | 4 +- src/util.c | 62 ++++ src/util.h | 8 + 62 files changed, 2460 insertions(+), 742 deletions(-) create mode 100644 src/mainloop-api.c create mode 100644 src/mainloop-api.h create mode 100644 src/mainloop-signal.c create mode 100644 src/mainloop-signal.h create mode 100644 src/pacat.c create mode 100644 src/pdispatch.c create mode 100644 src/pdispatch.h create mode 100644 src/polyp.c create mode 100644 src/polyp.h create mode 100644 src/polypdef.h create mode 100644 src/protocol-native-spec.h create mode 100644 src/pstream-util.c create mode 100644 src/pstream-util.h create mode 100644 src/sample-util.c create mode 100644 src/sample-util.h create mode 100644 src/simple.c create mode 100644 src/simple.h create mode 100644 src/socket-client.c create mode 100644 src/socket-client.h create mode 100644 src/util.c create mode 100644 src/util.h diff --git a/bootstrap.sh b/bootstrap.sh index f26ceb15..c9880d85 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -33,7 +33,7 @@ else automake -a -c autoconf -Wall - ./configure --sysconfdir=/etc "$@" + CFLAGS="-g -O0" ./configure --sysconfdir=/etc "$@" make clean fi diff --git a/configure.ac b/configure.ac index 16376902..3a14a061 100644 --- a/configure.ac +++ b/configure.ac @@ -42,7 +42,7 @@ AC_PROG_LIBTOOL # If using GCC specifiy some additional parameters if test "x$GCC" = "xyes" ; then - CFLAGS="$CFLAGS -pipe -Wall -W" + CFLAGS="$CFLAGS -pipe -Wall -W -Wno-unused-parameter" fi AC_CONFIG_FILES([Makefile src/Makefile]) diff --git a/src/Makefile.am b/src/Makefile.am index 443a25f2..6ad1488f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,31 +18,39 @@ AM_CFLAGS=-ansi -D_GNU_SOURCE -bin_PROGRAMS = polypaudio +bin_PROGRAMS = polypaudio pacat -pkglib_LTLIBRARIES=libprotocol-simple.la module-simple-protocol-tcp.la \ - libsocket-server.la module-pipe-sink.la libpstream.la libiochannel.la \ +pkglib_LTLIBRARIES=libiochannel.la libsocket-server.la libsocket-client.la \ + libprotocol-simple.la module-simple-protocol-tcp.la \ + module-pipe-sink.la libpstream.la \ libpacket.la module-oss.la module-oss-mmap.la liboss.la libioline.la \ libcli.la module-cli.la libtokenizer.la libdynarray.la \ module-simple-protocol-unix.la module-cli-protocol-tcp.la \ - libprotocol-cli.la libprotocol-native.la module-native-protocol-tcp.la \ - module-native-protocol-unix.la module-cli-protocol-unix.la libtagstruct.la + libprotocol-cli.la module-cli-protocol-unix.la libtagstruct.la \ + libpdispatch.la libprotocol-native.la libpstream-util.la \ + module-native-protocol-tcp.la module-native-protocol-unix.la \ + libpolyp.la polypaudio_SOURCES = idxset.c idxset.h \ queue.c queue.h \ strbuf.c strbuf.h \ + main.c main.h \ mainloop.c mainloop.h \ memblock.c memblock.h \ sample.c sample.h \ + sample-util.c sample-util.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 + module.c module.h \ + mainloop-signal.c mainloop-signal.h \ + mainloop-api.c mainloop-api.h \ + util.c util.h +polypaudio_CFLAGS = $(AM_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) polypaudio_LDADD = $(LIBLTDL) @@ -56,10 +64,22 @@ libsocket_server_la_SOURCES = socket-server.c socket-server.h libsocket_server_la_LDFLAGS = -avoid-version libsocket_server_la_LIBADD = libiochannel.la +libsocket_client_la_SOURCES = socket-client.c socket-client.h +libsocket_client_la_LDFLAGS = -avoid-version +libsocket_client_la_LIBADD = libiochannel.la + libpstream_la_SOURCES = pstream.c pstream.h libpstream_la_LDFLAGS = -avoid-version libpstream_la_LIBADD = libpacket.la +libpstream_util_la_SOURCES = pstream-util.c pstream-util.h +libpstream_util_la_LDFLAGS = -avoid-version +libpstream_util_la_LIBADD = libpstream.la libtagstruct.la + +libpdispatch_la_SOURCES = pdispatch.c pdispatch.h +libpdispatch_la_LDFLAGS = -avoid-version +libpdispatch_la_LIBADD = libpacket.la libtagstruct.la + libiochannel_la_SOURCES = iochannel.c iochannel.h libiochannel_la_LDFLAGS = -avoid-version @@ -90,7 +110,7 @@ libprotocol_cli_la_LIBADD = libsocket-server.la libiochannel.la libcli.la libprotocol_native_la_SOURCES = protocol-native.c protocol-native.h libprotocol_native_la_LDFLAGS = -avoid-version -libprotocol_native_la_LIBADD = libsocket-server.la libiochannel.la libpacket.la libpstream.la +libprotocol_native_la_LIBADD = libsocket-server.la libiochannel.la libpacket.la libpstream.la libpstream-util.la libtagstruct_la_SOURCES = tagstruct.c tagstruct.h libtagstruct_la_LDFLAGS = -avoid-version @@ -140,3 +160,24 @@ 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 libtokenizer.la + +libpolyp_la_SOURCES = polyp.c polyp.h \ + polypdef.h \ + tagstruct.c tagstruct.h \ + iochannel.c iochannel.h \ + pstream.c pstream.h \ + pstream-util.c pstream-util.h \ + pdispatch.c pdispatch.h \ + protocol-native-spec.h \ + mainloop-api.c mainloop-api.h \ + mainloop.c mainloop.h \ + idxset.c idxset.h \ + util.c util.h \ + memblock.c memblock.h \ + socket-client.c socket-client.h \ + packet.c packet.h \ + queue.c queue.h \ + dynarray.c dynarray.h + +pacat_SOURCES = pacat.c +pacat_LDADD = libpolyp.la diff --git a/src/cli.c b/src/cli.c index ec484ace..09162351 100644 --- a/src/cli.c +++ b/src/cli.c @@ -20,6 +20,8 @@ struct cli { void (*eof_callback)(struct cli *c, void *userdata); void *userdata; + + struct client *client; }; struct command { @@ -63,6 +65,7 @@ static const struct command commands[] = { static const char prompt[] = ">>> "; struct cli* cli_new(struct core *core, struct iochannel *io) { + char cname[256]; struct cli *c; assert(io); @@ -75,16 +78,21 @@ struct cli* cli_new(struct core *core, struct iochannel *io) { c->userdata = NULL; c->eof_callback = NULL; + iochannel_peer_to_string(io, cname, sizeof(cname)); + c->client = client_new(core, "CLI", cname); + assert(c->client); + ioline_set_callback(c->line, line_callback, c); ioline_puts(c->line, "Welcome to polypaudio! Use \"help\" for usage information.\n"); ioline_puts(c->line, prompt); - + return c; } void cli_free(struct cli *c) { assert(c); ioline_free(c->line); + client_free(c->client); free(c); } @@ -135,7 +143,7 @@ void cli_set_eof_callback(struct cli *c, void (*cb)(struct cli*c, void *userdata static void cli_command_exit(struct cli *c, struct tokenizer *t) { assert(c && c->core && c->core->mainloop && t); - mainloop_quit(c->core->mainloop, -1); + c->core->mainloop->quit(c->core->mainloop, 0); } static void cli_command_help(struct cli *c, struct tokenizer *t) { diff --git a/src/core.c b/src/core.c index 50248501..d9df38e1 100644 --- a/src/core.c +++ b/src/core.c @@ -7,7 +7,7 @@ #include "sink.h" #include "source.h" -struct core* core_new(struct mainloop *m) { +struct core* core_new(struct pa_mainloop_api *m) { struct core* c; c = malloc(sizeof(struct core)); assert(c); diff --git a/src/core.h b/src/core.h index f6f794b9..8c4c6233 100644 --- a/src/core.h +++ b/src/core.h @@ -2,17 +2,17 @@ #define foocorehfoo #include "idxset.h" -#include "mainloop.h" +#include "mainloop-api.h" struct core { - struct mainloop *mainloop; + struct pa_mainloop_api *mainloop; struct idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules; uint32_t default_source_index, default_sink_index; }; -struct core* core_new(struct mainloop *m); +struct core* core_new(struct pa_mainloop_api *m); void core_free(struct core*c); #endif diff --git a/src/iochannel.c b/src/iochannel.c index f0c4c499..910b7e0b 100644 --- a/src/iochannel.c +++ b/src/iochannel.c @@ -4,10 +4,11 @@ #include #include "iochannel.h" +#include "util.h" struct iochannel { int ifd, ofd; - struct mainloop* mainloop; + struct pa_mainloop_api* mainloop; void (*callback)(struct iochannel*io, void *userdata); void*userdata; @@ -17,43 +18,45 @@ struct iochannel { int no_close; - struct mainloop_source* input_source, *output_source; + void* input_source, *output_source; }; static void enable_mainloop_sources(struct iochannel *io) { assert(io); if (io->input_source == io->output_source) { - enum mainloop_io_event e = MAINLOOP_IO_EVENT_NULL; + enum pa_mainloop_api_io_events e = PA_MAINLOOP_API_IO_EVENT_NULL; assert(io->input_source); if (!io->readable) - e |= MAINLOOP_IO_EVENT_IN; + e |= PA_MAINLOOP_API_IO_EVENT_INPUT; if (!io->writable) - e |= MAINLOOP_IO_EVENT_OUT; + e |= PA_MAINLOOP_API_IO_EVENT_OUTPUT; - mainloop_source_io_set_events(io->input_source, e); + io->mainloop->enable_io(io->mainloop, io->input_source, e); } else { if (io->input_source) - mainloop_source_io_set_events(io->input_source, io->readable ? MAINLOOP_IO_EVENT_NULL : MAINLOOP_IO_EVENT_IN); + io->mainloop->enable_io(io->mainloop, io->input_source, io->readable ? PA_MAINLOOP_API_IO_EVENT_NULL : PA_MAINLOOP_API_IO_EVENT_INPUT); if (io->output_source) - mainloop_source_io_set_events(io->output_source, io->writable ? MAINLOOP_IO_EVENT_NULL : MAINLOOP_IO_EVENT_OUT); + io->mainloop->enable_io(io->mainloop, io->output_source, io->writable ? PA_MAINLOOP_API_IO_EVENT_NULL : PA_MAINLOOP_API_IO_EVENT_OUTPUT); } } -static void callback(struct mainloop_source*s, int fd, enum mainloop_io_event events, void *userdata) { +static void callback(struct pa_mainloop_api* m, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { struct iochannel *io = userdata; int changed = 0; - assert(s && fd >= 0 && userdata); + assert(m && fd >= 0 && events && userdata); - if ((events & MAINLOOP_IO_EVENT_IN) && !io->readable) { + if ((events & PA_MAINLOOP_API_IO_EVENT_INPUT) && !io->readable) { io->readable = 1; changed = 1; + assert(id == io->input_source); } - if ((events & MAINLOOP_IO_EVENT_OUT) && !io->writable) { + if ((events & PA_MAINLOOP_API_IO_EVENT_OUTPUT) && !io->writable) { io->writable = 1; changed = 1; + assert(id == io->output_source); } if (changed) { @@ -64,15 +67,7 @@ static void callback(struct mainloop_source*s, int fd, enum mainloop_io_event ev } } -static void make_nonblock_fd(int fd) { - int v; - - if ((v = fcntl(fd, F_GETFL)) >= 0) - if (!(v & O_NONBLOCK)) - fcntl(fd, F_SETFL, v|O_NONBLOCK); -} - -struct iochannel* iochannel_new(struct mainloop*m, int ifd, int ofd) { +struct iochannel* iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd) { struct iochannel *io; assert(m && (ifd >= 0 || ofd >= 0)); @@ -90,18 +85,18 @@ struct iochannel* iochannel_new(struct mainloop*m, int ifd, int ofd) { if (ifd == ofd) { assert(ifd >= 0); make_nonblock_fd(io->ifd); - io->input_source = io->output_source = mainloop_source_new_io(m, ifd, MAINLOOP_IO_EVENT_IN|MAINLOOP_IO_EVENT_OUT, callback, io); + io->input_source = io->output_source = m->source_io(m, ifd, PA_MAINLOOP_API_IO_EVENT_BOTH, callback, io); } else { if (ifd >= 0) { make_nonblock_fd(io->ifd); - io->input_source = mainloop_source_new_io(m, ifd, MAINLOOP_IO_EVENT_IN, callback, io); + io->input_source = m->source_io(m, ifd, PA_MAINLOOP_API_IO_EVENT_INPUT, callback, io); } else io->input_source = NULL; if (ofd >= 0) { make_nonblock_fd(io->ofd); - io->output_source = mainloop_source_new_io(m, ofd, MAINLOOP_IO_EVENT_OUT, callback, io); + io->output_source = m->source_io(m, ofd, PA_MAINLOOP_API_IO_EVENT_OUTPUT, callback, io); } else io->output_source = NULL; } @@ -120,9 +115,9 @@ void iochannel_free(struct iochannel*io) { } if (io->input_source) - mainloop_source_free(io->input_source); + io->mainloop->cancel_io(io->mainloop, io->input_source); if (io->output_source && io->output_source != io->input_source) - mainloop_source_free(io->output_source); + io->mainloop->cancel_io(io->mainloop, io->output_source); free(io); } @@ -172,3 +167,8 @@ void iochannel_set_noclose(struct iochannel*io, int b) { assert(io); io->no_close = b; } + +void iochannel_peer_to_string(struct iochannel*io, char*s, size_t l) { + assert(io && s && l); + peer_to_string(s, l, io->ifd); +} diff --git a/src/iochannel.h b/src/iochannel.h index 8ed8b878..b0465a19 100644 --- a/src/iochannel.h +++ b/src/iochannel.h @@ -2,11 +2,11 @@ #define fooiochannelhfoo #include -#include "mainloop.h" +#include "mainloop-api.h" struct iochannel; -struct iochannel* iochannel_new(struct mainloop*m, int ifd, int ofd); +struct iochannel* iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd); void iochannel_free(struct iochannel*io); ssize_t iochannel_write(struct iochannel*io, const void*data, size_t l); @@ -19,4 +19,6 @@ void iochannel_set_noclose(struct iochannel*io, int b); void iochannel_set_callback(struct iochannel*io, void (*callback)(struct iochannel*io, void *userdata), void *userdata); +void iochannel_peer_to_string(struct iochannel*io, char*s, size_t l); + #endif diff --git a/src/main.c b/src/main.c index f35505ec..ef25b5e3 100644 --- a/src/main.c +++ b/src/main.c @@ -8,46 +8,52 @@ #include "core.h" #include "mainloop.h" #include "module.h" +#include "mainloop-signal.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); +static struct pa_mainloop *mainloop; + +static void signal_callback(void *id, int sig, void *userdata) { + struct pa_mainloop_api* m = pa_mainloop_get_api(mainloop); + m->quit(m, 1); fprintf(stderr, "main: got signal.\n"); } int main(int argc, char *argv[]) { - struct mainloop *m; struct core *c; - int r; + int r, retval = 0; r = lt_dlinit(); assert(r == 0); - m = mainloop_new(); - assert(m); - c = core_new(m); - assert(c); + mainloop = pa_mainloop_new(); + assert(mainloop); - mainloop_source_new_signal(m, SIGINT, signal_callback, NULL); + r = pa_signal_init(pa_mainloop_get_api(mainloop)); + assert(r == 0); + pa_signal_register(SIGINT, signal_callback, NULL); signal(SIGPIPE, SIG_IGN); + c = core_new(pa_mainloop_get_api(mainloop)); + assert(c); + 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);*/ + if (pa_mainloop_run(mainloop, &retval) < 0) + retval = 1; fprintf(stderr, "main: mainloop exit.\n"); - - mainloop_run(m); core_free(c); - mainloop_free(m); + + pa_signal_done(); + pa_mainloop_free(mainloop); lt_dlexit(); - return 0; + return retval; } diff --git a/src/mainloop-api.c b/src/mainloop-api.c new file mode 100644 index 00000000..6caa0c25 --- /dev/null +++ b/src/mainloop-api.c @@ -0,0 +1,35 @@ +#include +#include +#include "mainloop-api.h" + +struct once_info { + void (*callback)(void *userdata); + void *userdata; +}; + +static void once_callback(struct pa_mainloop_api *api, void *id, void *userdata) { + struct once_info *i = userdata; + assert(api && i && i->callback); + i->callback(i->userdata); + assert(api->cancel_fixed); + api->cancel_fixed(api, id); + free(i); +} + +void pa_mainloop_api_once(struct pa_mainloop_api* api, void (*callback)(void *userdata), void *userdata) { + struct once_info *i; + void *id; + assert(api && callback); + + i = malloc(sizeof(struct once_info)); + assert(i); + i->callback = callback; + i->userdata = userdata; + + assert(api->source_fixed); + id = api->source_fixed(api, once_callback, i); + assert(id); + + /* Note: if the mainloop is destroyed before once_callback() was called, some memory is leaked. */ +} + diff --git a/src/mainloop-api.h b/src/mainloop-api.h new file mode 100644 index 00000000..96dacc22 --- /dev/null +++ b/src/mainloop-api.h @@ -0,0 +1,43 @@ +#ifndef foomainloopapihfoo +#define foomainloopapihfoo + +#include +#include + +enum pa_mainloop_api_io_events { + PA_MAINLOOP_API_IO_EVENT_NULL = 0, + PA_MAINLOOP_API_IO_EVENT_INPUT = 1, + PA_MAINLOOP_API_IO_EVENT_OUTPUT = 2, + PA_MAINLOOP_API_IO_EVENT_BOTH = 3 +}; + +struct pa_mainloop_api { + void *userdata; + + /* IO sources */ + void* (*source_io)(struct pa_mainloop_api*a, int fd, enum pa_mainloop_api_io_events events, void (*callback) (struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata), void *userdata); + void (*enable_io)(struct pa_mainloop_api*a, void* id, enum pa_mainloop_api_io_events events); + void (*cancel_io)(struct pa_mainloop_api*a, void* id); + + /* Fixed sources */ + void* (*source_fixed)(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, void *id, void *userdata), void *userdata); + void (*enable_fixed)(struct pa_mainloop_api*a, void* id, int b); + void (*cancel_fixed)(struct pa_mainloop_api*a, void* id); + + /* Idle sources */ + void* (*source_idle)(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, void *id, void *userdata), void *userdata); + void (*enable_idle)(struct pa_mainloop_api*a, void* id, int b); + void (*cancel_idle)(struct pa_mainloop_api*a, void* id); + + /* Time sources */ + void* (*source_time)(struct pa_mainloop_api*a, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*a, void *id, const struct timeval *tv, void *userdata), void *userdata); + void (*enable_time)(struct pa_mainloop_api*a, void *id, const struct timeval *tv); + void (*cancel_time)(struct pa_mainloop_api*a, void* id); + + /* Exit mainloop */ + void (*quit)(struct pa_mainloop_api*a, int retval); +}; + +void pa_mainloop_api_once(struct pa_mainloop_api*m, void (*callback)(void *userdata), void *userdata); + +#endif diff --git a/src/mainloop-signal.c b/src/mainloop-signal.c new file mode 100644 index 00000000..dcc72f69 --- /dev/null +++ b/src/mainloop-signal.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "mainloop-signal.h" +#include "util.h" + +struct signal_info { + int sig; + struct sigaction saved_sigaction; + void (*callback) (void *id, int signal, void *userdata); + void *userdata; + struct signal_info *previous, *next; +}; + +static struct pa_mainloop_api *api = NULL; +static int signal_pipe[2] = { -1, -1 }; +static void* mainloop_source = NULL; +static struct signal_info *signals = NULL; + +static void signal_handler(int sig) { + write(signal_pipe[1], &sig, sizeof(sig)); +} + +static void callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { + assert(a && id && events == PA_MAINLOOP_API_IO_EVENT_INPUT && id == mainloop_source && fd == signal_pipe[0]); + + for (;;) { + ssize_t r; + int sig; + struct signal_info*s; + + if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) { + if (errno == EAGAIN) + return; + + fprintf(stderr, "signal.c: read(): %s\n", strerror(errno)); + return; + } + + if (r != sizeof(sig)) { + fprintf(stderr, "signal.c: short read()\n"); + return; + } + + for (s = signals; s; s = s->next) + if (s->sig == sig) { + assert(s->callback); + s->callback(s, sig, s->userdata); + break; + } + } +} + +int pa_signal_init(struct pa_mainloop_api *a) { + assert(a); + if (pipe(signal_pipe) < 0) { + fprintf(stderr, "pipe() failed: %s\n", strerror(errno)); + return -1; + } + + make_nonblock_fd(signal_pipe[0]); + make_nonblock_fd(signal_pipe[1]); + + api = a; + mainloop_source = api->source_io(api, signal_pipe[0], PA_MAINLOOP_API_IO_EVENT_INPUT, callback, NULL); + assert(mainloop_source); + return 0; +} + +void pa_signal_done(void) { + assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && mainloop_source); + + api->cancel_io(api, mainloop_source); + mainloop_source = NULL; + + close(signal_pipe[0]); + close(signal_pipe[1]); + signal_pipe[0] = signal_pipe[1] = -1; + + while (signals) + pa_signal_unregister(signals); + + api = NULL; +} + +void* pa_signal_register(int sig, void (*callback) (void *id, int signal, void *userdata), void *userdata) { + struct signal_info *s = NULL; + struct sigaction sa; + assert(sig > 0 && callback); + + for (s = signals; s; s = s->next) + if (s->sig == sig) + goto fail; + + s = malloc(sizeof(struct signal_info)); + assert(s); + s->sig = sig; + s->callback = callback; + s->userdata = userdata; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = signal_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + + if (sigaction(sig, &sa, &s->saved_sigaction) < 0) + goto fail; + + s->previous = NULL; + s->next = signals; + signals = s; + + return s; +fail: + if (s) + free(s); + return NULL; +} + +void pa_signal_unregister(void *id) { + struct signal_info *s = id; + assert(s); + + if (s->next) + s->next->previous = s->previous; + if (s->previous) + s->previous->next = s->next; + else + signals = s->next; + + sigaction(s->sig, &s->saved_sigaction, NULL); + free(s); +} diff --git a/src/mainloop-signal.h b/src/mainloop-signal.h new file mode 100644 index 00000000..e3e2364d --- /dev/null +++ b/src/mainloop-signal.h @@ -0,0 +1,12 @@ +#ifndef foomainloopsignalhfoo +#define foomainloopsignalhfoo + +#include "mainloop-api.h" + +int pa_signal_init(struct pa_mainloop_api *api); +void pa_signal_done(void); + +void* pa_signal_register(int signal, void (*callback) (void *id, int signal, void *userdata), void *userdata); +void pa_signal_unregister(void *id); + +#endif diff --git a/src/mainloop.c b/src/mainloop.c index fba0461c..a1758c65 100644 --- a/src/mainloop.c +++ b/src/mainloop.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -8,468 +9,515 @@ #include #include "mainloop.h" +#include "util.h" +#include "idxset.h" -struct mainloop_source { - struct mainloop_source *next; - struct mainloop *mainloop; - enum mainloop_source_type type; - - int enabled; +struct mainloop_source_header { + struct pa_mainloop *mainloop; int dead; - void *userdata; - - struct { - int fd; - enum mainloop_io_event events; - void (*callback)(struct mainloop_source*s, int fd, enum mainloop_io_event event, void *userdata); - struct pollfd pollfd; - } io; +}; - struct { - void (*callback)(struct mainloop_source*s, void *userdata); - } fixed; +struct mainloop_source_io { + struct mainloop_source_header header; - struct { - void (*callback)(struct mainloop_source*s, void *userdata); - } idle; - - struct { - int sig; - struct sigaction sigaction; - void (*callback)(struct mainloop_source*s, int sig, void *userdata); - } signal; + int fd; + enum pa_mainloop_api_io_events events; + void (*callback) (struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata); + void *userdata; + + struct pollfd *pollfd; }; -struct mainloop_source_list { - struct mainloop_source *sources; - int n_sources; - int dead_sources; +struct mainloop_source_fixed_or_idle { + struct mainloop_source_header header; + int enabled; + + void (*callback)(struct pa_mainloop_api*a, void *id, void *userdata); + void *userdata; }; -struct mainloop { - struct mainloop_source_list io_sources, fixed_sources, idle_sources, signal_sources; +struct mainloop_source_time { + struct mainloop_source_header header; + int enabled; + struct timeval timeval; + void (*callback)(struct pa_mainloop_api*a, void *id, const struct timeval*tv, void *userdata); + void *userdata; +}; + +struct pa_mainloop { + struct idxset *io_sources, *fixed_sources, *idle_sources, *time_sources; + int io_sources_scan_dead, fixed_sources_scan_dead, idle_sources_scan_dead, time_sources_scan_dead; + struct pollfd *pollfds; - int max_pollfds, n_pollfds; + unsigned max_pollfds, n_pollfds; int rebuild_pollfds; - int quit; - int running; - int signal_pipe[2]; - struct pollfd signal_pollfd; + int quit, running, retval; + struct pa_mainloop_api api; }; -static int signal_pipe = -1; +static void setup_api(struct pa_mainloop *m); -static void signal_func(int sig) { - if (signal_pipe >= 0) - write(signal_pipe, &sig, sizeof(sig)); -} +struct pa_mainloop *pa_mainloop_new(void) { + struct pa_mainloop *m; -static void make_nonblock(int fd) { - int v; - - if ((v = fcntl(fd, F_GETFL)) >= 0) - fcntl(fd, F_SETFL, v|O_NONBLOCK); -} + m = malloc(sizeof(struct pa_mainloop)); + assert(m); + m->io_sources = idxset_new(NULL, NULL); + m->fixed_sources = idxset_new(NULL, NULL); + m->idle_sources = idxset_new(NULL, NULL); + m->time_sources = idxset_new(NULL, NULL); -struct mainloop *mainloop_new(void) { - int r; - struct mainloop *m; + assert(m->io_sources && m->fixed_sources && m->idle_sources && m->time_sources); - m = malloc(sizeof(struct mainloop)); - assert(m); - memset(m, 0, sizeof(struct mainloop)); + m->io_sources_scan_dead = m->fixed_sources_scan_dead = m->idle_sources_scan_dead = m->time_sources_scan_dead = 0; + + m->pollfds = NULL; + m->max_pollfds = m->n_pollfds = m->rebuild_pollfds = 0; - r = pipe(m->signal_pipe); - assert(r >= 0 && m->signal_pipe[0] >= 0 && m->signal_pipe[1] >= 0); + m->quit = m->running = m->retval = 0; - make_nonblock(m->signal_pipe[0]); - make_nonblock(m->signal_pipe[1]); - - signal_pipe = m->signal_pipe[1]; - m->signal_pollfd.fd = m->signal_pipe[0]; - m->signal_pollfd.events = POLLIN; - m->signal_pollfd.revents = 0; + setup_api(m); return m; } -static void free_sources(struct mainloop_source_list *l, int all) { - struct mainloop_source *s, *p; - assert(l); +static int foreach(void *p, uint32_t index, int *del, void*userdata) { + struct mainloop_source_header *h = p; + int *all = userdata; + assert(p && del && all); - if (!all && !l->dead_sources) - return; - - p = NULL; - s = l->sources; - while (s) { - if (all || s->dead) { - struct mainloop_source *t = s; - s = s->next; - - if (p) - p->next = s; - else - l->sources = s; - - free(t); - } else { - p = s; - s = s->next; - } + if (*all || h->dead) { + free(h); + *del = 1; } - l->dead_sources = 0; - - if (all) { - assert(!l->sources); - l->n_sources = 0; - } -} + return 0; +}; -void mainloop_free(struct mainloop* m) { +void pa_mainloop_free(struct pa_mainloop* m) { + int all = 1; assert(m); - free_sources(&m->io_sources, 1); - free_sources(&m->fixed_sources, 1); - free_sources(&m->idle_sources, 1); - free_sources(&m->signal_sources, 1); - - if (signal_pipe == m->signal_pipe[1]) - signal_pipe = -1; - close(m->signal_pipe[0]); - close(m->signal_pipe[1]); - + idxset_foreach(m->io_sources, foreach, &all); + idxset_foreach(m->fixed_sources, foreach, &all); + idxset_foreach(m->idle_sources, foreach, &all); + idxset_foreach(m->time_sources, foreach, &all); + + idxset_free(m->io_sources, NULL, NULL); + idxset_free(m->fixed_sources, NULL, NULL); + idxset_free(m->idle_sources, NULL, NULL); + idxset_free(m->time_sources, NULL, NULL); + free(m->pollfds); free(m); } -static void rebuild_pollfds(struct mainloop *m) { - struct mainloop_source*s; +static void scan_dead(struct pa_mainloop *m) { + int all = 0; + assert(m); + if (m->io_sources_scan_dead) + idxset_foreach(m->io_sources, foreach, &all); + if (m->fixed_sources_scan_dead) + idxset_foreach(m->fixed_sources, foreach, &all); + if (m->idle_sources_scan_dead) + idxset_foreach(m->idle_sources, foreach, &all); + if (m->time_sources_scan_dead) + idxset_foreach(m->time_sources, foreach, &all); +} + +static void rebuild_pollfds(struct pa_mainloop *m) { + struct mainloop_source_io*s; struct pollfd *p; - - if (m->max_pollfds < m->io_sources.n_sources+1) { - m->max_pollfds = (m->io_sources.n_sources+1)*2; - m->pollfds = realloc(m->pollfds, sizeof(struct pollfd)*m->max_pollfds); + uint32_t index = IDXSET_INVALID; + unsigned l; + + l = idxset_ncontents(m->io_sources); + if (m->max_pollfds < l) { + m->pollfds = realloc(m->pollfds, sizeof(struct pollfd)*l); + m->max_pollfds = l; } m->n_pollfds = 0; p = m->pollfds; - for (s = m->io_sources.sources; s; s = s->next) { - assert(s->type == MAINLOOP_SOURCE_TYPE_IO); - if (!s->dead && s->enabled && s->io.events != MAINLOOP_IO_EVENT_NULL) { - *(p++) = s->io.pollfd; - m->n_pollfds++; + for (s = idxset_first(m->io_sources, &index); s; s = idxset_next(m->io_sources, &index)) { + if (s->header.dead) { + s->pollfd = NULL; + continue; } + + s->pollfd = p; + p->fd = s->fd; + p->events = ((s->events & PA_MAINLOOP_API_IO_EVENT_INPUT) ? POLLIN : 0) | ((s->events & PA_MAINLOOP_API_IO_EVENT_OUTPUT) ? POLLOUT : 0); + p->revents = 0; + + p++; + m->n_pollfds++; } +} + +static void dispatch_pollfds(struct pa_mainloop *m) { + uint32_t index = IDXSET_INVALID; + struct mainloop_source_io *s; - *(p++) = m->signal_pollfd; - m->n_pollfds++; + for (s = idxset_first(m->io_sources, &index); s; s = idxset_next(m->io_sources, &index)) { + if (s->header.dead || !s->events || !s->pollfd || !s->pollfd->revents) + continue; + + assert(s->pollfd->revents <= s->pollfd->events && s->pollfd->fd == s->fd && s->callback); + s->callback(&m->api, s, s->fd, ((s->pollfd->revents & POLLIN) ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | ((s->pollfd->revents & POLLOUT) ? PA_MAINLOOP_API_IO_EVENT_OUTPUT : 0), s->userdata); + } } -static void dispatch_pollfds(struct mainloop *m) { - int i; - struct pollfd *p; - struct mainloop_source *s; - /* This loop assumes that m->sources and m->pollfds have the same - * order and that m->pollfds is a subset of m->sources! */ +static void run_fixed_or_idle(struct pa_mainloop *m, struct idxset *i) { + uint32_t index = IDXSET_INVALID; + struct mainloop_source_fixed_or_idle *s; - s = m->io_sources.sources; - for (p = m->pollfds, i = 0; i < m->n_pollfds; p++, i++) { - if (!p->revents) + for (s = idxset_first(i, &index); s; s = idxset_next(i, &index)) { + if (s->header.dead || !s->enabled) continue; - if (p->fd == m->signal_pipe[0]) { - /* Event from signal pipe */ + assert(s->callback); + s->callback(&m->api, s, s->userdata); + } +} + +static int calc_next_timeout(struct pa_mainloop *m) { + uint32_t index = IDXSET_INVALID; + struct mainloop_source_time *s; + struct timeval now; + int t = -1; - if (p->revents & POLLIN) { - int sig; - ssize_t r; - r = read(m->signal_pipe[0], &sig, sizeof(sig)); - assert((r < 0 && errno == EAGAIN) || r == sizeof(sig)); + if (idxset_isempty(m->time_sources)) + return -1; + + gettimeofday(&now, NULL); + + for (s = idxset_first(m->time_sources, &index); s; s = idxset_next(m->time_sources, &index)) { + int tmp; + + if (s->header.dead || !s->enabled) + continue; + + if (s->timeval.tv_sec < now.tv_sec || (s->timeval.tv_sec == now.tv_sec && s->timeval.tv_usec <= now.tv_usec)) + return 0; + + tmp = (s->timeval.tv_sec - now.tv_sec)*1000; - if (r == sizeof(sig)) { - struct mainloop_source *l = m->signal_sources.sources; - while (l) { - assert(l->type == MAINLOOP_SOURCE_TYPE_SIGNAL); - - if (l->signal.sig == sig && l->enabled && !l->dead) { - assert(l->signal.callback); - l->signal.callback(l, sig, l->userdata); - } - - l = l->next; - } - } - } - - } else { - /* Event from I/O source */ - - for (; s; s = s->next) { - if (p->fd != s->io.fd) - continue; - - assert(s->type == MAINLOOP_SOURCE_TYPE_IO); - - if (!s->dead && s->enabled) { - enum mainloop_io_event e = (p->revents & POLLIN ? MAINLOOP_IO_EVENT_IN : 0) | (p->revents & POLLOUT ? MAINLOOP_IO_EVENT_OUT : 0); - if (e) { - assert(s->io.callback); - s->io.callback(s, s->io.fd, e, s->userdata); - } - } - - break; - } + if (s->timeval.tv_usec > now.tv_usec) + tmp += (s->timeval.tv_usec - now.tv_usec)/1000; + else + tmp -= (now.tv_usec - s->timeval.tv_usec)/1000; + + if (tmp == 0) + return 0; + else if (tmp < t) + t = tmp; + } + + return t; +} + +static void dispatch_timeout(struct pa_mainloop *m) { + uint32_t index = IDXSET_INVALID; + struct mainloop_source_time *s; + struct timeval now; + assert(m); + + if (idxset_isempty(m->time_sources)) + return; + + gettimeofday(&now, NULL); + for (s = idxset_first(m->time_sources, &index); s; s = idxset_next(m->time_sources, &index)) { + + if (s->header.dead || !s->enabled) + continue; + + if (s->timeval.tv_sec < now.tv_sec || (s->timeval.tv_sec == now.tv_sec && s->timeval.tv_usec <= now.tv_usec)) { + assert(s->callback); + + s->enabled = 0; + s->callback(&m->api, s, &s->timeval, s->userdata); } } } -int mainloop_iterate(struct mainloop *m, int block) { - struct mainloop_source *s; - int c; +static int any_idle_sources(struct pa_mainloop *m) { + struct mainloop_source_fixed_or_idle *s; + uint32_t index; + assert(m); + + for (s = idxset_first(m->idle_sources, &index); s; s = idxset_next(m->idle_sources, &index)) + if (!s->header.dead && s->enabled) + return 1; + + return 0; +} + +int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval) { + int r, idle; assert(m && !m->running); - if(m->quit) - return m->quit; - - free_sources(&m->io_sources, 0); - free_sources(&m->fixed_sources, 0); - free_sources(&m->idle_sources, 0); - free_sources(&m->signal_sources, 0); - - for (s = m->fixed_sources.sources; s; s = s->next) { - assert(s->type == MAINLOOP_SOURCE_TYPE_FIXED); - if (!s->dead && s->enabled) { - assert(s->fixed.callback); - s->fixed.callback(s, s->userdata); - } + if(m->quit) { + if (retval) + *retval = m->retval; + return 1; } + m->running = 1; + + scan_dead(m); + run_fixed_or_idle(m, m->fixed_sources); + if (m->rebuild_pollfds) { rebuild_pollfds(m); m->rebuild_pollfds = 0; } - m->running = 1; + idle = any_idle_sources(m); do { - c = poll(m->pollfds, m->n_pollfds, (block && !m->idle_sources.n_sources) ? -1 : 0); - } while (c < 0 && errno == EINTR); - - if (c > 0) + int t; + + if (!block || idle) + t = 0; + else + t = calc_next_timeout(m); + + r = poll(m->pollfds, m->n_pollfds, t); + } while (r < 0 && errno == EINTR); + + dispatch_timeout(m); + + if (r > 0) dispatch_pollfds(m); - else if (c == 0) { - for (s = m->idle_sources.sources; s; s = s->next) { - assert(s->type == MAINLOOP_SOURCE_TYPE_IDLE); - if (!s->dead && s->enabled) { - assert(s->idle.callback); - s->idle.callback(s, s->userdata); - } - } - } + else if (r == 0 && idle) + run_fixed_or_idle(m, m->idle_sources); + else if (r < 0) + fprintf(stderr, "select(): %s\n", strerror(errno)); m->running = 0; - return c < 0 ? -1 : 0; + return r < 0 ? -1 : 0; } -int mainloop_run(struct mainloop *m) { +int pa_mainloop_run(struct pa_mainloop *m, int *retval) { int r; - while (!(r = mainloop_iterate(m, 1))); + while ((r = pa_mainloop_iterate(m, 1, retval)) == 0); return r; } -void mainloop_quit(struct mainloop *m, int r) { +void pa_mainloop_quit(struct pa_mainloop *m, int r) { assert(m); m->quit = r; } -static struct mainloop_source_list* get_source_list(struct mainloop *m, enum mainloop_source_type type) { - struct mainloop_source_list *l; - - switch(type) { - case MAINLOOP_SOURCE_TYPE_IO: - l = &m->io_sources; - break; - case MAINLOOP_SOURCE_TYPE_FIXED: - l = &m->fixed_sources; - break; - case MAINLOOP_SOURCE_TYPE_IDLE: - l = &m->idle_sources; - break; - case MAINLOOP_SOURCE_TYPE_SIGNAL: - l = &m->signal_sources; - break; - default: - l = NULL; - break; - } - - return l; -} - -static struct mainloop_source *source_new(struct mainloop*m, enum mainloop_source_type type) { - struct mainloop_source_list *l; - struct mainloop_source* s; - assert(m); +/* IO sources */ +static void* mainloop_source_io(struct pa_mainloop_api*a, int fd, enum pa_mainloop_api_io_events events, void (*callback) (struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata), void *userdata) { + struct pa_mainloop *m; + struct mainloop_source_io *s; + assert(a && a->userdata && fd >= 0 && callback); + m = a->userdata; + assert(a == &m->api); - s = malloc(sizeof(struct mainloop_source)); + s = malloc(sizeof(struct mainloop_source_io)); assert(s); - memset(s, 0, sizeof(struct mainloop_source)); + s->header.mainloop = m; + s->header.dead = 0; - s->type = type; - s->mainloop = m; + s->fd = fd; + s->events = events; + s->callback = callback; + s->userdata = userdata; + s->pollfd = NULL; - l = get_source_list(m, type); - assert(l); - - s->next = l->sources; - l->sources = s; - l->n_sources++; + idxset_put(m->io_sources, s, NULL); + m->rebuild_pollfds = 1; return s; } -struct mainloop_source* mainloop_source_new_io(struct mainloop*m, int fd, enum mainloop_io_event event, void (*callback)(struct mainloop_source*s, int fd, enum mainloop_io_event event, void *userdata), void *userdata) { - struct mainloop_source* s; - assert(m && fd>=0 && callback); +static void mainloop_enable_io(struct pa_mainloop_api*a, void* id, enum pa_mainloop_api_io_events events) { + struct pa_mainloop *m; + struct mainloop_source_io *s = id; + assert(a && a->userdata && s && !s->header.dead); + m = a->userdata; + assert(a == &m->api && s->header.mainloop == m); - s = source_new(m, MAINLOOP_SOURCE_TYPE_IO); + s->events = events; + if (s->pollfd) + s->pollfd->events = ((s->events & PA_MAINLOOP_API_IO_EVENT_INPUT) ? POLLIN : 0) | ((s->events & PA_MAINLOOP_API_IO_EVENT_OUTPUT) ? POLLOUT : 0); +} - s->io.fd = fd; - s->io.events = event; - s->io.callback = callback; - s->userdata = userdata; - s->io.pollfd.fd = fd; - s->io.pollfd.events = (event & MAINLOOP_IO_EVENT_IN ? POLLIN : 0) | (event & MAINLOOP_IO_EVENT_OUT ? POLLOUT : 0); - s->io.pollfd.revents = 0; +static void mainloop_cancel_io(struct pa_mainloop_api*a, void* id) { + struct pa_mainloop *m; + struct mainloop_source_io *s = id; + assert(a && a->userdata && s && !s->header.dead); + m = a->userdata; + assert(a == &m->api && s->header.mainloop == m); - s->enabled = 1; - - m->rebuild_pollfds = 1; - return s; + s->header.dead = 1; + m->io_sources_scan_dead = 1; } -struct mainloop_source* mainloop_source_new_fixed(struct mainloop*m, void (*callback)(struct mainloop_source *s, void*userdata), void*userdata) { - struct mainloop_source* s; - assert(m && callback); +/* Fixed sources */ +static void* mainloop_source_fixed(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, void *id, void *userdata), void *userdata) { + struct pa_mainloop *m; + struct mainloop_source_fixed_or_idle *s; + assert(a && a->userdata && callback); + m = a->userdata; + assert(a == &m->api); - s = source_new(m, MAINLOOP_SOURCE_TYPE_FIXED); + s = malloc(sizeof(struct mainloop_source_fixed_or_idle)); + assert(s); + s->header.mainloop = m; + s->header.dead = 0; - s->fixed.callback = callback; - s->userdata = userdata; s->enabled = 1; + s->callback = callback; + s->userdata = userdata; + + idxset_put(m->fixed_sources, s, NULL); return s; } -struct mainloop_source* mainloop_source_new_idle(struct mainloop*m, void (*callback)(struct mainloop_source *s, void*userdata), void*userdata) { - struct mainloop_source* s; - assert(m && callback); - - s = source_new(m, MAINLOOP_SOURCE_TYPE_IDLE); +static void mainloop_enable_fixed(struct pa_mainloop_api*a, void* id, int b) { + struct pa_mainloop *m; + struct mainloop_source_fixed_or_idle *s = id; + assert(a && a->userdata && s && !s->header.dead); + m = a->userdata; + assert(a == &m->api); - s->idle.callback = callback; - s->userdata = userdata; - s->enabled = 1; - return s; + s->enabled = b; } -struct mainloop_source* mainloop_source_new_signal(struct mainloop*m, int sig, void (*callback)(struct mainloop_source *s, int sig, void*userdata), void*userdata) { - struct mainloop_source* s; - struct sigaction save_sa, sa; - - assert(m && callback); +static void mainloop_cancel_fixed(struct pa_mainloop_api*a, void* id) { + struct pa_mainloop *m; + struct mainloop_source_fixed_or_idle *s = id; + assert(a && a->userdata && s && !s->header.dead); + m = a->userdata; + assert(a == &m->api); - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = signal_func; - sa.sa_flags = SA_RESTART; - sigemptyset(&sa.sa_mask); + s->header.dead = 1; + m->fixed_sources_scan_dead = 1; +} - memset(&save_sa, 0, sizeof(save_sa)); +/* Idle sources */ +static void* mainloop_source_idle(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, void *id, void *userdata), void *userdata) { + struct pa_mainloop *m; + struct mainloop_source_fixed_or_idle *s; + assert(a && a->userdata && callback); + m = a->userdata; + assert(a == &m->api); + + s = malloc(sizeof(struct mainloop_source_fixed_or_idle)); + assert(s); + s->header.mainloop = m; + s->header.dead = 0; - if (sigaction(sig, &sa, &save_sa) < 0) - return NULL; - - s = source_new(m, MAINLOOP_SOURCE_TYPE_SIGNAL); - s->signal.sig = sig; - s->signal.sigaction = save_sa; - - s->signal.callback = callback; - s->userdata = userdata; s->enabled = 1; + s->callback = callback; + s->userdata = userdata; + + idxset_put(m->idle_sources, s, NULL); return s; } -void mainloop_source_free(struct mainloop_source*s) { - struct mainloop_source_list *l; - assert(s && !s->dead); - s->dead = 1; - - assert(s->mainloop); - l = get_source_list(s->mainloop, s->type); - assert(l); +static void mainloop_cancel_idle(struct pa_mainloop_api*a, void* id) { + struct pa_mainloop *m; + struct mainloop_source_fixed_or_idle *s = id; + assert(a && a->userdata && s && !s->header.dead); + m = a->userdata; + assert(a == &m->api); - l->n_sources--; - l->dead_sources = 1; - - if (s->type == MAINLOOP_SOURCE_TYPE_IO) - s->mainloop->rebuild_pollfds = 1; - else if (s->type == MAINLOOP_SOURCE_TYPE_SIGNAL) - sigaction(s->signal.sig, &s->signal.sigaction, NULL); + s->header.dead = 1; + m->idle_sources_scan_dead = 1; } -void mainloop_source_enable(struct mainloop_source*s, int b) { - assert(s && !s->dead); +/* Time sources */ +static void* mainloop_source_time(struct pa_mainloop_api*a, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*a, void *id, const struct timeval *tv, void *userdata), void *userdata) { + struct pa_mainloop *m; + struct mainloop_source_time *s; + assert(a && a->userdata && callback); + m = a->userdata; + assert(a == &m->api); - if (s->type == MAINLOOP_SOURCE_TYPE_IO && ((s->enabled && !b) || (!s->enabled && b))) { - assert(s->mainloop); - s->mainloop->rebuild_pollfds = 1; - } + s = malloc(sizeof(struct mainloop_source_time)); + assert(s); + s->header.mainloop = m; + s->header.dead = 0; - s->enabled = b; -} + s->enabled = !!tv; + if (tv) + s->timeval = *tv; -void mainloop_source_io_set_events(struct mainloop_source*s, enum mainloop_io_event events) { - assert(s && !s->dead && s->type == MAINLOOP_SOURCE_TYPE_IO); + s->callback = callback; + s->userdata = userdata; - if (s->io.events != events) { - assert(s->mainloop); - s->mainloop->rebuild_pollfds = 1; - } + idxset_put(m->time_sources, s, NULL); + return s; +} - s->io.events = events; - s->io.pollfd.events = ((events & MAINLOOP_IO_EVENT_IN) ? POLLIN : 0) | ((events & MAINLOOP_IO_EVENT_OUT) ? POLLOUT : 0); +static void mainloop_enable_time(struct pa_mainloop_api*a, void *id, const struct timeval *tv) { + struct pa_mainloop *m; + struct mainloop_source_time *s = id; + assert(a && a->userdata && s && !s->header.dead); + m = a->userdata; + assert(a == &m->api); + + if (tv) { + s->enabled = 1; + s->timeval = *tv; + } else + s->enabled = 0; } -struct mainloop *mainloop_source_get_mainloop(struct mainloop_source *s) { - assert(s); +static void mainloop_cancel_time(struct pa_mainloop_api*a, void* id) { + struct pa_mainloop *m; + struct mainloop_source_time *s = id; + assert(a && a->userdata && s && !s->header.dead); + m = a->userdata; + assert(a == &m->api); + + s->header.dead = 1; + m->time_sources_scan_dead = 1; - return s->mainloop; } -struct once_info { - void (*callback)(void *userdata); - void *userdata; -}; +static void mainloop_quit(struct pa_mainloop_api*a, int retval) { + struct pa_mainloop *m; + assert(a && a->userdata); + m = a->userdata; + assert(a == &m->api); -static void once_callback(struct mainloop_source *s, void *userdata) { - struct once_info *i = userdata; - assert(s && i && i->callback); - i->callback(i->userdata); - mainloop_source_free(s); - free(i); + m->quit = 1; + m->retval = retval; } + +static void setup_api(struct pa_mainloop *m) { + assert(m); + + m->api.userdata = m; + m->api.source_io = mainloop_source_io; + m->api.enable_io = mainloop_enable_io; + m->api.cancel_io = mainloop_cancel_io; + + m->api.source_fixed = mainloop_source_fixed; + m->api.enable_fixed = mainloop_enable_fixed; + m->api.cancel_fixed = mainloop_cancel_fixed; + + m->api.source_idle = mainloop_source_idle; + m->api.enable_idle = mainloop_enable_fixed; /* (!) */ + m->api.cancel_idle = mainloop_cancel_idle; + + m->api.source_time = mainloop_source_time; + m->api.enable_time = mainloop_enable_time; + m->api.cancel_time = mainloop_cancel_time; -void mainloop_once(struct mainloop*m, void (*callback)(void *userdata), void *userdata) { - struct once_info *i; - assert(m && callback); + m->api.quit = mainloop_quit; +} - i = malloc(sizeof(struct once_info)); - assert(i); - i->callback = callback; - i->userdata = userdata; - - mainloop_source_new_fixed(m, once_callback, i); +struct pa_mainloop_api* pa_mainloop_get_api(struct pa_mainloop*m) { + assert(m); + return &m->api; } + diff --git a/src/mainloop.h b/src/mainloop.h index c1bfc62a..7837636f 100644 --- a/src/mainloop.h +++ b/src/mainloop.h @@ -1,42 +1,16 @@ #ifndef foomainloophfoo #define foomainloophfoo -struct mainloop; -struct mainloop_source; +#include "mainloop-api.h" -enum mainloop_io_event { - MAINLOOP_IO_EVENT_NULL = 0, - MAINLOOP_IO_EVENT_IN = 1, - MAINLOOP_IO_EVENT_OUT = 2, - MAINLOOP_IO_EVENT_BOTH = 3 -}; +struct pa_mainloop; -enum mainloop_source_type { - MAINLOOP_SOURCE_TYPE_IO, - MAINLOOP_SOURCE_TYPE_FIXED, - MAINLOOP_SOURCE_TYPE_IDLE, - MAINLOOP_SOURCE_TYPE_SIGNAL -}; +struct pa_mainloop *pa_mainloop_new(void); +void pa_mainloop_free(struct pa_mainloop* m); -struct mainloop *mainloop_new(void); -void mainloop_free(struct mainloop* m); +int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval); +int pa_mainloop_run(struct pa_mainloop *m, int *retval); -int mainloop_iterate(struct mainloop *m, int block); -int mainloop_run(struct mainloop *m); -void mainloop_quit(struct mainloop *m, int r); - -struct mainloop_source* mainloop_source_new_io(struct mainloop*m, int fd, enum mainloop_io_event event, void (*callback)(struct mainloop_source*s, int fd, enum mainloop_io_event event, void *userdata), void *userdata); -struct mainloop_source* mainloop_source_new_fixed(struct mainloop*m, void (*callback)(struct mainloop_source *s, void*userdata), void*userdata); -struct mainloop_source* mainloop_source_new_idle(struct mainloop*m, void (*callback)(struct mainloop_source *s, void*userdata), void*userdata); -struct mainloop_source* mainloop_source_new_signal(struct mainloop*m, int sig, void (*callback)(struct mainloop_source *s, int sig, void*userdata), void*userdata); - -void mainloop_once(struct mainloop*m, void (*callback)(void *userdata), void *userdata); - -void mainloop_source_free(struct mainloop_source*s); -void mainloop_source_enable(struct mainloop_source*s, int b); - -void mainloop_source_io_set_events(struct mainloop_source*s, enum mainloop_io_event event); - -struct mainloop *mainloop_source_get_mainloop(struct mainloop_source *s); +struct pa_mainloop_api* pa_mainloop_get_api(struct pa_mainloop*m); #endif diff --git a/src/memblockq.c b/src/memblockq.c index 10c59e50..9a601c3a 100644 --- a/src/memblockq.c +++ b/src/memblockq.c @@ -220,3 +220,12 @@ uint32_t memblockq_get_length(struct memblockq *bq) { assert(bq); return bq->total_length; } + +uint32_t memblockq_missing_to(struct memblockq *bq, size_t qlen) { + assert(bq && qlen); + + if (bq->total_length >= qlen) + return 0; + + return qlen - bq->total_length; +} diff --git a/src/memblockq.h b/src/memblockq.h index 0a68ddaf..a681ff08 100644 --- a/src/memblockq.h +++ b/src/memblockq.h @@ -25,4 +25,6 @@ int memblockq_is_writable(struct memblockq *bq, size_t length); uint32_t memblockq_get_delay(struct memblockq *bq); uint32_t memblockq_get_length(struct memblockq *bq); +uint32_t memblockq_missing_to(struct memblockq *bq, size_t qlen); + #endif diff --git a/src/module-oss-mmap.c b/src/module-oss-mmap.c index bfc3a6fa..b70ea6bd 100644 --- a/src/module-oss-mmap.c +++ b/src/module-oss-mmap.c @@ -16,15 +16,15 @@ #include "source.h" #include "module.h" #include "oss.h" +#include "sample-util.h" struct userdata { struct sink *sink; struct source *source; struct core *core; - struct sample_spec sample_spec; + struct pa_sample_spec sample_spec; - size_t in_fragment_size, out_fragment_size, in_fragments, out_fragments, sample_size, out_fill; - uint32_t sample_usec; + size_t in_fragment_size, out_fragment_size, in_fragments, out_fragments, out_fill; int fd; @@ -161,12 +161,14 @@ static void do_read(struct userdata *u) { in_clear_memblocks(u, u->in_fragments/2); }; -static void io_callback(struct mainloop_source*s, int fd, enum mainloop_io_event event, void *userdata) { +static void io_callback(struct pa_mainloop_api *m, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { struct userdata *u = userdata; - if (event & MAINLOOP_IO_EVENT_IN) + assert (u && u->core->mainloop == m && u->mainloop_source == id); + + if (events & PA_MAINLOOP_API_IO_EVENT_INPUT) do_read(u); - if (event & MAINLOOP_IO_EVENT_OUT) + if (events & PA_MAINLOOP_API_IO_EVENT_OUTPUT) do_write(u); } @@ -175,7 +177,7 @@ static uint32_t sink_get_latency_cb(struct sink *s) { assert(s && u); do_write(u); - return u->out_fill/u->sample_size*u->sample_usec; + return pa_samples_usec(u->out_fill, &s->sample_spec); } int module_init(struct core *c, struct module*m) { @@ -316,10 +318,7 @@ int module_init(struct core *c, struct module*m) { assert(u->source || u->sink); - u->sample_size = sample_size(&u->sample_spec); - u->sample_usec = 1000000/u->sample_spec.rate; - - u->mainloop_source = mainloop_source_new_io(c->mainloop, u->fd, (u->source ? MAINLOOP_IO_EVENT_IN : 0) | (u->sink ? MAINLOOP_IO_EVENT_OUT : 0), io_callback, u); + u->mainloop_source = c->mainloop->source_io(c->mainloop, u->fd, (u->source ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | (u->sink ? PA_MAINLOOP_API_IO_EVENT_OUTPUT : 0), io_callback, u); assert(u->mainloop_source); return 0; @@ -360,7 +359,7 @@ void module_done(struct core *c, struct module*m) { source_free(u->source); if (u->mainloop_source) - mainloop_source_free(u->mainloop_source); + u->core->mainloop->cancel_io(u->core->mainloop, u->mainloop_source); if (u->fd >= 0) close(u->fd); diff --git a/src/module-oss.c b/src/module-oss.c index fab5c8c5..4f307545 100644 --- a/src/module-oss.c +++ b/src/module-oss.c @@ -15,7 +15,7 @@ #include "source.h" #include "module.h" #include "oss.h" -#include "sample.h" +#include "sample-util.h" struct userdata { struct sink *sink; @@ -81,7 +81,7 @@ static void do_read(struct userdata *u) { return; } - assert(r <= memchunk.memblock->length); + assert(r <= (ssize_t) memchunk.memblock->length); memchunk.length = memchunk.memblock->length = r; memchunk.index = 0; @@ -107,7 +107,7 @@ static uint32_t sink_get_latency_cb(struct sink *s) { return 0; } - return samples_usec(arg, &s->sample_spec); + return pa_samples_usec(arg, &s->sample_spec); } int module_init(struct core *c, struct module*m) { @@ -117,7 +117,7 @@ int module_init(struct core *c, struct module*m) { int fd = -1; int frag_size, in_frag_size, out_frag_size; int mode; - struct sample_spec ss; + struct pa_sample_spec ss; assert(c && m); p = m->argument ? m->argument : "/dev/dsp"; @@ -203,7 +203,7 @@ int module_init(struct core *c, struct module*m) { u->memchunk.memblock = NULL; u->memchunk.length = 0; - u->sample_size = sample_size(&ss); + u->sample_size = pa_sample_size(&ss); u->out_fragment_size = out_frag_size; u->in_fragment_size = in_frag_size; diff --git a/src/module-pipe-sink.c b/src/module-pipe-sink.c index c0a903e9..9dcf5d23 100644 --- a/src/module-pipe-sink.c +++ b/src/module-pipe-sink.c @@ -18,7 +18,8 @@ struct userdata { struct sink *sink; struct iochannel *io; struct core *core; - struct mainloop_source *mainloop_source; + void *mainloop_source; + struct pa_mainloop_api *mainloop; struct memchunk memchunk; }; @@ -27,7 +28,7 @@ static void do_write(struct userdata *u) { ssize_t r; assert(u); - mainloop_source_enable(u->mainloop_source, 0); + u->mainloop->enable_fixed(u->mainloop, u->mainloop_source, 0); if (!iochannel_is_writable(u->io)) return; @@ -57,10 +58,10 @@ static void notify_cb(struct sink*s) { assert(s && u); if (iochannel_is_writable(u->io)) - mainloop_source_enable(u->mainloop_source, 1); + u->mainloop->enable_fixed(u->mainloop, u->mainloop_source, 1); } -static void prepare_callback(struct mainloop_source *src, void *userdata) { +static void fixed_callback(struct pa_mainloop_api *m, void *id, void *userdata) { struct userdata *u = userdata; assert(u); do_write(u); @@ -77,7 +78,7 @@ int module_init(struct core *c, struct module*m) { struct stat st; char *p; int fd = -1; - static const struct sample_spec ss = { + static const struct pa_sample_spec ss = { .format = SAMPLE_S16NE, .rate = 44100, .channels = 2, @@ -120,10 +121,11 @@ int module_init(struct core *c, struct module*m) { u->memchunk.memblock = NULL; u->memchunk.length = 0; - u->mainloop_source = mainloop_source_new_fixed(c->mainloop, prepare_callback, u); + u->mainloop = c->mainloop; + u->mainloop_source = u->mainloop->source_fixed(u->mainloop, fixed_callback, u); assert(u->mainloop_source); - mainloop_source_enable(u->mainloop_source, 0); - + u->mainloop->enable_fixed(u->mainloop, u->mainloop_source, 0); + m->userdata = u; return 0; @@ -147,7 +149,7 @@ void module_done(struct core *c, struct module*m) { sink_free(u->sink); iochannel_free(u->io); - mainloop_source_free(u->mainloop_source); + u->mainloop->cancel_fixed(u->mainloop, u->mainloop_source); assert(u->filename); unlink(u->filename); diff --git a/src/module.c b/src/module.c index c6de1751..883a22df 100644 --- a/src/module.c +++ b/src/module.c @@ -151,5 +151,5 @@ void module_unload_request(struct core *c, struct module *m) { assert(i); i->core = c; i->index = m->index; - mainloop_once(c->mainloop, module_unload_once_callback, i); + pa_mainloop_api_once(c->mainloop, module_unload_once_callback, i); } diff --git a/src/oss.c b/src/oss.c index 7b1315c0..02bf8cd1 100644 --- a/src/oss.c +++ b/src/oss.c @@ -7,7 +7,7 @@ #include "oss.h" -int oss_auto_format(int fd, struct sample_spec *ss) { +int oss_auto_format(int fd, struct pa_sample_spec *ss) { int format, channels, speed; assert(fd >= 0 && ss); diff --git a/src/oss.h b/src/oss.h index 35d2dd02..34ac9c66 100644 --- a/src/oss.h +++ b/src/oss.h @@ -3,6 +3,6 @@ #include "sample.h" -int oss_auto_format(int fd, struct sample_spec *ss); +int oss_auto_format(int fd, struct pa_sample_spec *ss); #endif diff --git a/src/pacat.c b/src/pacat.c new file mode 100644 index 00000000..5f5a373b --- /dev/null +++ b/src/pacat.c @@ -0,0 +1,169 @@ +#include +#include +#include +#include +#include +#include + +#include "polyp.h" +#include "mainloop.h" + +static struct pa_context *context = NULL; +static struct pa_stream *stream = NULL; +static struct pa_mainloop_api *mainloop_api = NULL; + +static void *buffer = NULL; +static size_t buffer_length = 0, buffer_index = 0; + +static void* stdin_source = NULL; + +static void context_die_callback(struct pa_context *c, void *userdata) { + assert(c); + fprintf(stderr, "Connection to server shut down, exiting.\n"); + mainloop_api->quit(mainloop_api, 1); +} + +static void stream_die_callback(struct pa_stream *s, void *userdata) { + assert(s); + fprintf(stderr, "Stream deleted, exiting.\n"); + mainloop_api->quit(mainloop_api, 1); +} + +static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) { + size_t l; + assert(s && length); + + mainloop_api->enable_io(mainloop_api, stdin_source, PA_STREAM_PLAYBACK); + + if (!buffer) + return; + + assert(buffer_length); + + l = length; + if (l > buffer_length) + l = buffer_length; + + pa_stream_write(s, buffer+buffer_index, l); + buffer_length -= l; + buffer_index += l; + + if (!buffer_length) { + free(buffer); + buffer = NULL; + buffer_index = buffer_length = 0; + } +} + +static void stream_complete_callback(struct pa_context*c, struct pa_stream *s, void *userdata) { + assert(c); + + if (!s) { + fprintf(stderr, "Stream creation failed.\n"); + mainloop_api->quit(mainloop_api, 1); + } + + stream = s; + pa_stream_set_die_callback(stream, stream_die_callback, NULL); + pa_stream_set_write_callback(stream, stream_write_callback, NULL); +} + +static void context_complete_callback(struct pa_context *c, int success, void *userdata) { + static const struct pa_sample_spec ss = { + .format = SAMPLE_S16NE, + .rate = 44100, + .channels = 2 + }; + + assert(c && !stream); + + if (!success) { + fprintf(stderr, "Connection failed\n"); + goto fail; + } + + if (pa_stream_new(c, PA_STREAM_PLAYBACK, NULL, "pacat", &ss, NULL, stream_complete_callback, NULL) < 0) { + fprintf(stderr, "pa_stream_new() failed.\n"); + goto fail; + } + + return; + +fail: + mainloop_api->quit(mainloop_api, 1); +} + +static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { + size_t l; + ssize_t r; + assert(a == mainloop_api && id && fd == STDIN_FILENO && events == PA_MAINLOOP_API_IO_EVENT_INPUT); + + if (buffer) { + mainloop_api->enable_io(mainloop_api, stdin_source, PA_MAINLOOP_API_IO_EVENT_NULL); + return; + } + + if (!(l = pa_stream_writable_size(stream))) + l = 4096; + buffer = malloc(l); + assert(buffer); + if ((r = read(fd, buffer, l)) <= 0) { + if (r == 0) + mainloop_api->quit(mainloop_api, 0); + else { + fprintf(stderr, "read() failed: %s\n", strerror(errno)); + mainloop_api->quit(mainloop_api, 1); + } + + return; + } + + buffer_length = r; + buffer_index = 0; +} + +int main(int argc, char *argv[]) { + struct pa_mainloop* m; + int ret = 1; + + if (!(m = pa_mainloop_new())) { + fprintf(stderr, "pa_mainloop_new() failed.\n"); + goto quit; + } + + mainloop_api = pa_mainloop_get_api(m); + + if (!(stdin_source = mainloop_api->source_io(mainloop_api, STDIN_FILENO, PA_MAINLOOP_API_IO_EVENT_INPUT, stdin_callback, NULL))) { + fprintf(stderr, "source_io() failed.\n"); + goto quit; + } + + if (!(context = pa_context_new(mainloop_api, argv[0]))) { + fprintf(stderr, "pa_context_new() failed.\n"); + goto quit; + } + + if (pa_context_connect(context, NULL, context_complete_callback, NULL) < 0) { + fprintf(stderr, "pa_context_connext() failed.\n"); + goto quit; + } + + pa_context_set_die_callback(context, context_die_callback, NULL); + + if (pa_mainloop_run(m, &ret) < 0) { + fprintf(stderr, "pa_mainloop_run() failed.\n"); + goto quit; + } + +quit: + if (stream) + pa_stream_free(stream); + if (context) + pa_context_free(context); + if (m) + pa_mainloop_free(m); + if (buffer) + free(buffer); + + return ret; +} diff --git a/src/packet.c b/src/packet.c index 47fce919..0f966d9a 100644 --- a/src/packet.c +++ b/src/packet.c @@ -16,7 +16,7 @@ struct packet* packet_new(size_t length) { return p; } -struct packet* packet_dynamic(uint8_t* data, size_t length) { +struct packet* packet_new_dynamic(uint8_t* data, size_t length) { struct packet *p; assert(data && length); p = malloc(sizeof(struct packet)); @@ -26,6 +26,7 @@ struct packet* packet_dynamic(uint8_t* data, size_t length) { p->length = length; p->data = data; p->type = PACKET_DYNAMIC; + return p; } struct packet* packet_ref(struct packet *p) { diff --git a/src/pdispatch.c b/src/pdispatch.c new file mode 100644 index 00000000..48b6639d --- /dev/null +++ b/src/pdispatch.c @@ -0,0 +1,149 @@ +#include +#include +#include +#include "pdispatch.h" +#include "protocol-native-spec.h" + +struct reply_info { + struct pdispatch *pdispatch; + struct reply_info *next, *previous; + int (*callback)(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata); + void *userdata; + uint32_t tag; + void *mainloop_timeout; +}; + +struct pdispatch { + struct pa_mainloop_api *mainloop; + const struct pdispatch_command *command_table; + unsigned n_commands; + struct reply_info *replies; +}; + +static void reply_info_free(struct reply_info *r) { + assert(r && r->pdispatch && r->pdispatch->mainloop); + r->pdispatch->mainloop->cancel_time(r->pdispatch->mainloop, r->mainloop_timeout); + + if (r->previous) + r->previous->next = r->next; + else + r->pdispatch->replies = r->next; + + if (r->next) + r->next->previous = r->previous; + + free(r); +} + +struct pdispatch* pdispatch_new(struct pa_mainloop_api *mainloop, const struct pdispatch_command*table, unsigned entries) { + struct pdispatch *pd; + assert(mainloop); + + assert((entries && table) || (!entries && !table)); + + pd = malloc(sizeof(struct pdispatch)); + assert(pd); + pd->mainloop = mainloop; + pd->command_table = table; + pd->n_commands = entries; + return pd; +} + +void pdispatch_free(struct pdispatch *pd) { + assert(pd); + while (pd->replies) + reply_info_free(pd->replies); + free(pd); +} + +int pdispatch_run(struct pdispatch *pd, struct packet*packet, void *userdata) { + uint32_t tag, command; + assert(pd && packet); + struct tagstruct *ts = NULL; + assert(pd && packet && packet->data); + + if (packet->length <= 8) + goto fail; + + ts = tagstruct_new(packet->data, packet->length); + assert(ts); + + if (tagstruct_getu32(ts, &command) < 0 || + tagstruct_getu32(ts, &tag) < 0) + goto fail; + + if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) { + struct reply_info *r; + int done = 0; + + for (r = pd->replies; r; r = r->next) { + if (r->tag == tag) { + int ret = r->callback(r->pdispatch, command, tag, ts, r->userdata); + reply_info_free(r); + + if (ret < 0) + goto fail; + + done = 1; + break; + } + } + + if (!done) + goto fail; + + } else if (pd->command_table && command < pd->n_commands) { + const struct pdispatch_command *c = pd->command_table+command; + + if (!c->proc) + goto fail; + + if (c->proc(pd, command, tag, ts, userdata) < 0) + goto fail; + } else + goto fail; + + tagstruct_free(ts); + + return 0; + +fail: + if (ts) + tagstruct_free(ts); + + fprintf(stderr, "protocol-native: invalid packet.\n"); + return -1; +} + +static void timeout_callback(struct pa_mainloop_api*m, void *id, const struct timeval *tv, void *userdata) { + struct reply_info*r = userdata; + assert (r && r->mainloop_timeout == id && r->pdispatch && r->pdispatch->mainloop == m && r->callback); + + r->callback(r->pdispatch, PA_COMMAND_TIMEOUT, r->tag, NULL, r->userdata); + reply_info_free(r); +} + +void pdispatch_register_reply(struct pdispatch *pd, uint32_t tag, int timeout, int (*cb)(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata), void *userdata) { + struct reply_info *r; + struct timeval tv; + assert(pd && cb); + + r = malloc(sizeof(struct reply_info)); + assert(r); + r->pdispatch = pd; + r->callback = cb; + r->userdata = userdata; + r->tag = tag; + + gettimeofday(&tv, NULL); + tv.tv_sec += timeout; + + r->mainloop_timeout = pd->mainloop->source_time(pd->mainloop, &tv, timeout_callback, r); + assert(r->mainloop_timeout); + + r->previous = NULL; + r->next = pd->replies; + if (r->next) + r->next->previous = r; + pd->replies = r; +} diff --git a/src/pdispatch.h b/src/pdispatch.h new file mode 100644 index 00000000..466da9a4 --- /dev/null +++ b/src/pdispatch.h @@ -0,0 +1,22 @@ +#ifndef foopdispatchhfoo +#define foopdispatchhfoo + +#include +#include "tagstruct.h" +#include "packet.h" +#include "mainloop-api.h" + +struct pdispatch; + +struct pdispatch_command { + int (*proc)(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata); +}; + +struct pdispatch* pdispatch_new(struct pa_mainloop_api *m, const struct pdispatch_command*table, unsigned entries); +void pdispatch_free(struct pdispatch *pd); + +int pdispatch_run(struct pdispatch *pd, struct packet*p, void *userdata); + +void pdispatch_register_reply(struct pdispatch *pd, uint32_t tag, int timeout, int (*cb)(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata), void *userdata); + +#endif diff --git a/src/polyp.c b/src/polyp.c new file mode 100644 index 00000000..fdff7f9c --- /dev/null +++ b/src/polyp.c @@ -0,0 +1,451 @@ +#include +#include +#include +#include + +#include "polyp.h" +#include "protocol-native-spec.h" +#include "pdispatch.h" +#include "pstream.h" +#include "dynarray.h" +#include "socket-client.h" +#include "pstream-util.h" + +#define DEFAULT_QUEUE_LENGTH 10240 +#define DEFAULT_MAX_LENGTH 20480 +#define DEFAULT_PREBUF 4096 +#define DEFAULT_TIMEOUT 5 + +struct pa_context { + char *name; + struct pa_mainloop_api* mainloop; + struct socket_client *client; + struct pstream *pstream; + struct pdispatch *pdispatch; + struct dynarray *streams; + struct pa_stream *first_stream; + uint32_t ctag; + uint32_t errno; + enum { CONTEXT_UNCONNECTED, CONTEXT_CONNECTING, CONTEXT_READY, CONTEXT_DEAD} state; + + void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); + void *connect_complete_userdata; + + void (*die_callback)(struct pa_context*c, void *userdata); + void *die_userdata; +}; + +struct pa_stream { + struct pa_context *context; + struct pa_stream *next, *previous; + uint32_t channel; + int channel_valid; + enum pa_stream_direction direction; + enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; + uint32_t requested_bytes; + + void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); + void *read_userdata; + + void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); + void *write_userdata; + + void (*create_complete_callback)(struct pa_context*c, struct pa_stream *s, void *userdata); + void *create_complete_userdata; + + void (*die_callback)(struct pa_stream*c, void *userdata); + void *die_userdata; +}; + +static int command_request(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata); + +static const struct pdispatch_command command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = { NULL }, + [PA_COMMAND_REPLY] = { NULL }, + [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_EXIT] = { NULL }, + [PA_COMMAND_REQUEST] = { command_request }, +}; + +struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { + assert(mainloop && name); + struct pa_context *c; + c = malloc(sizeof(struct pa_context)); + assert(c); + c->name = strdup(name); + c->mainloop = mainloop; + c->client = NULL; + c->pstream = NULL; + c->pdispatch = NULL; + c->streams = dynarray_new(); + assert(c->streams); + c->first_stream = NULL; + c->errno = PA_ERROR_OK; + c->state = CONTEXT_UNCONNECTED; + c->ctag = 0; + + c->connect_complete_callback = NULL; + c->connect_complete_userdata = NULL; + + c->die_callback = NULL; + c->die_userdata = NULL; + + return c; +} + +void pa_context_free(struct pa_context *c) { + assert(c); + + while (c->first_stream) + pa_stream_free(c->first_stream); + + if (c->client) + socket_client_free(c->client); + if (c->pdispatch) + pdispatch_free(c->pdispatch); + if (c->pstream) + pstream_free(c->pstream); + if (c->streams) + dynarray_free(c->streams, NULL, NULL); + + free(c->name); + free(c); +} + +static void stream_dead(struct pa_stream *s) { + if (s->state == STREAM_DEAD) + return; + + s->state = STREAM_DEAD; + if (s->die_callback) + s->die_callback(s, s->die_userdata); +} + +static void context_dead(struct pa_context *c) { + struct pa_stream *s; + assert(c); + + for (s = c->first_stream; s; s = s->next) + stream_dead(s); + + if (c->state == CONTEXT_DEAD) + return; + + c->state = CONTEXT_DEAD; + if (c->die_callback) + c->die_callback(c, c->die_userdata); +} + +static void pstream_die_callback(struct pstream *p, void *userdata) { + struct pa_context *c = userdata; + assert(p && c); + + assert(c->state != CONTEXT_DEAD); + + c->state = CONTEXT_DEAD; + + context_dead(c); +} + +static int pstream_packet_callback(struct pstream *p, struct packet *packet, void *userdata) { + struct pa_context *c = userdata; + assert(p && packet && c); + + if (pdispatch_run(c->pdispatch, packet, c) < 0) { + fprintf(stderr, "polyp.c: invalid packet.\n"); + return -1; + } + + return 0; +} + +static int pstream_memblock_callback(struct pstream *p, uint32_t channel, int32_t delta, struct memchunk *chunk, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + assert(p && chunk && c && chunk->memblock && chunk->memblock->data); + + if (!(s = dynarray_get(c->streams, channel))) + return -1; + + if (s->read_callback) + s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); + + return 0; +} + +static void on_connection(struct socket_client *client, struct iochannel*io, void *userdata) { + struct pa_context *c = userdata; + assert(client && io && c && c->state == CONTEXT_CONNECTING); + + socket_client_free(client); + c->client = NULL; + + if (!io) { + c->errno = PA_ERROR_CONNECTIONREFUSED; + c->state = CONTEXT_UNCONNECTED; + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return; + } + + c->pstream = pstream_new(c->mainloop, io); + assert(c->pstream); + pstream_set_die_callback(c->pstream, pstream_die_callback, c); + pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); + pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); + + c->pdispatch = pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); + assert(c->pdispatch); + + c->state = CONTEXT_READY; + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 1, c->connect_complete_userdata); +} + +int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { + assert(c && c->state == CONTEXT_UNCONNECTED); + + assert(!c->client); + if (!(c->client = socket_client_new_unix(c->mainloop, server))) { + c->errno = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + + c->connect_complete_callback = complete; + c->connect_complete_userdata = userdata; + + socket_client_set_callback(c->client, on_connection, c); + c->state = CONTEXT_CONNECTING; + + return 0; +} + +int pa_context_is_dead(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_DEAD; +} + +int pa_context_is_ready(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_READY; +} + +int pa_context_errno(struct pa_context *c) { + assert(c); + return c->errno; +} + +void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { + assert(c); + c->die_callback = cb; + c->die_userdata = userdata; +} + +static int command_request(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata) { + struct pa_stream *s; + struct pa_context *c = userdata; + uint32_t bytes, channel; + assert(pd && command == PA_COMMAND_REQUEST && t && s); + + if (tagstruct_getu32(t, &channel) < 0 || + tagstruct_getu32(t, &bytes) < 0 || + tagstruct_eof(t)) { + c->errno = PA_ERROR_PROTOCOL; + return -1; + } + + if (!(s = dynarray_get(c->streams, channel))) { + c->errno = PA_ERROR_PROTOCOL; + return -1; + } + + s->requested_bytes += bytes; + + if (s->requested_bytes && s->write_callback) + s->write_callback(s, s->requested_bytes, s->write_userdata); + + return 0; +} + +static int create_playback_callback(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata) { + int ret = 0; + struct pa_stream *s = userdata; + assert(pd && s && s->state == STREAM_CREATING); + + if (command != PA_COMMAND_REPLY) { + struct pa_context *c = s->context; + assert(c); + + if (command == PA_COMMAND_ERROR && tagstruct_getu32(t, &s->context->errno) < 0) { + s->context->errno = PA_ERROR_PROTOCOL; + ret = -1; + } else if (command == PA_COMMAND_TIMEOUT) { + s->context->errno = PA_ERROR_TIMEOUT; + ret = -1; + } + + goto fail; + } + + if (tagstruct_getu32(t, &s->channel) < 0 || + tagstruct_eof(t)) { + s->context->errno = PA_ERROR_PROTOCOL; + ret = -1; + goto fail; + } + + s->channel_valid = 1; + dynarray_put(s->context->streams, s->channel, s); + + s->state = STREAM_READY; + assert(s->create_complete_callback); + s->create_complete_callback(s->context, s, s->create_complete_userdata); + return 0; + +fail: + assert(s->create_complete_callback); + s->create_complete_callback(s->context, NULL, s->create_complete_userdata); + pa_stream_free(s); + return ret; +} + +int pa_stream_new( + struct pa_context *c, + enum pa_stream_direction dir, + const char *dev, + const char *name, + const struct pa_sample_spec *ss, + const struct pa_buffer_attr *attr, + void (*complete) (struct pa_context*c, struct pa_stream *s, void *userdata), + void *userdata) { + + struct pa_stream *s; + struct tagstruct *t; + uint32_t tag; + + assert(c && name && ss && c->state == CONTEXT_READY && complete); + + s = malloc(sizeof(struct pa_stream)); + assert(s); + s->context = c; + + s->read_callback = NULL; + s->read_userdata = NULL; + s->write_callback = NULL; + s->write_userdata = NULL; + s->die_callback = NULL; + s->die_userdata = NULL; + s->create_complete_callback = complete; + s->create_complete_userdata = NULL; + + s->state = STREAM_CREATING; + s->requested_bytes = 0; + s->channel = 0; + s->channel_valid = 0; + s->direction = dir; + + t = tagstruct_new(NULL, 0); + assert(t); + + tagstruct_putu32(t, dir == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); + tagstruct_putu32(t, tag = c->ctag++); + tagstruct_puts(t, name); + tagstruct_put_sample_spec(t, ss); + tagstruct_putu32(t, (uint32_t) -1); + tagstruct_putu32(t, attr ? attr->queue_length : DEFAULT_QUEUE_LENGTH); + tagstruct_putu32(t, attr ? attr->max_length : DEFAULT_MAX_LENGTH); + tagstruct_putu32(t, attr ? attr->prebuf : DEFAULT_PREBUF); + + pstream_send_tagstruct(c->pstream, t); + + pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_playback_callback, s); + + s->next = c->first_stream; + if (s->next) + s->next->previous = s; + s->previous = NULL; + c->first_stream = s; + + return 0; +} + +void pa_stream_free(struct pa_stream *s) { + assert(s && s->context); + + if (s->channel_valid) { + struct tagstruct *t = tagstruct_new(NULL, 0); + assert(t); + + tagstruct_putu32(t, PA_COMMAND_DELETE_PLAYBACK_STREAM); + tagstruct_putu32(t, s->context->ctag++); + tagstruct_putu32(t, s->channel); + pstream_send_tagstruct(s->context->pstream, t); + } + + if (s->channel_valid) + dynarray_put(s->context->streams, s->channel, NULL); + + if (s->next) + s->next->previous = s->previous; + if (s->previous) + s->previous->next = s->next; + else + s->context->first_stream = s->next; + + free(s); +} + +void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { + assert(s && cb); + s->write_callback = cb; + s->write_userdata = userdata; +} + +void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { + struct memchunk chunk; + assert(s && s->context && data && length); + + chunk.memblock = memblock_new(length); + assert(chunk.memblock && chunk.memblock->data); + memcpy(chunk.memblock->data, data, length); + chunk.index = 0; + chunk.length = length; + + pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); + + if (length < s->requested_bytes) + s->requested_bytes -= length; + else + s->requested_bytes = 0; +} + +size_t pa_stream_writable_size(struct pa_stream *s) { + assert(s); + return s->requested_bytes; +} + +void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { + assert(s && cb); + s->read_callback = cb; + s->read_userdata = userdata; +} + +int pa_stream_is_dead(struct pa_stream *s) { + return s->state == STREAM_DEAD; +} + +int pa_stream_is_ready(struct pa_stream*s) { + return s->state == STREAM_READY; +} + +void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { + assert(s); + s->die_callback = cb; + s->die_userdata = userdata; +} diff --git a/src/polyp.h b/src/polyp.h new file mode 100644 index 00000000..171e3bdf --- /dev/null +++ b/src/polyp.h @@ -0,0 +1,53 @@ +#ifndef foopolyphfoo +#define foopolyphfoo + +#include + +#include "sample.h" +#include "polypdef.h" +#include "mainloop-api.h" + +struct pa_context; + +struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); + +int pa_context_connect( + struct pa_context *c, + const char *server, + void (*complete) (struct pa_context*c, int success, void *userdata), + void *userdata); + +void pa_context_free(struct pa_context *c); + +void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); + +int pa_context_is_dead(struct pa_context *c); +int pa_context_is_ready(struct pa_context *c); +int pa_contect_errno(struct pa_context *c); + +struct pa_stream; + +int pa_stream_new( + struct pa_context *c, + enum pa_stream_direction dir, + const char *dev, + const char *name, + const struct pa_sample_spec *ss, + const struct pa_buffer_attr *attr, + void (*complete) (struct pa_context*c, struct pa_stream *s, void *userdata), + void *userdata); + +void pa_stream_free(struct pa_stream *p); + +void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); + +void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); +void pa_stream_write(struct pa_stream *p, const void *data, size_t length); +size_t pa_stream_writable_size(struct pa_stream *p); + +void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); + +int pa_stream_is_dead(struct pa_stream *p); +int pa_stream_is_ready(struct pa_stream*p); + +#endif diff --git a/src/polypdef.h b/src/polypdef.h new file mode 100644 index 00000000..aa6e6bf6 --- /dev/null +++ b/src/polypdef.h @@ -0,0 +1,18 @@ +#ifndef foopolypdefhfoo +#define foopolypdefhfoo + +#include + +enum pa_stream_direction { + PA_STREAM_PLAYBACK, + PA_STREAM_RECORD +}; + +struct pa_buffer_attr { + uint32_t queue_length; + uint32_t max_length; + uint32_t prebuf; +}; + + +#endif diff --git a/src/protocol-cli.c b/src/protocol-cli.c index c0c93d98..b6460fec 100644 --- a/src/protocol-cli.c +++ b/src/protocol-cli.c @@ -12,8 +12,7 @@ struct protocol_cli { static void cli_eof_cb(struct cli*c, void*userdata) { struct protocol_cli *p = userdata; - assert(c && p); - + assert(p); idxset_remove_by_data(p->connections, c, NULL); cli_free(c); } @@ -22,7 +21,7 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us struct protocol_cli *p = userdata; struct cli *c; assert(s && io && p); - + c = cli_new(p->core, io); assert(c); cli_set_eof_callback(c, cli_eof_cb, p); diff --git a/src/protocol-native-spec.h b/src/protocol-native-spec.h new file mode 100644 index 00000000..df11ae3c --- /dev/null +++ b/src/protocol-native-spec.h @@ -0,0 +1,29 @@ +#ifndef fooprotocolnativespech +#define fooprotocolnativespech + +enum { + PA_COMMAND_ERROR, + PA_COMMAND_TIMEOUT, /* pseudo command */ + PA_COMMAND_REPLY, + PA_COMMAND_CREATE_PLAYBACK_STREAM, + PA_COMMAND_DELETE_PLAYBACK_STREAM, + PA_COMMAND_CREATE_RECORD_STREAM, + PA_COMMAND_DELETE_RECORD_STREAM, + PA_COMMAND_EXIT, + PA_COMMAND_REQUEST, + PA_COMMAND_MAX +}; + +enum { + PA_ERROR_OK, + PA_ERROR_ACCESS, + PA_ERROR_COMMAND, + PA_ERROR_INVALID, + PA_ERROR_EXIST, + PA_ERROR_NOENTITY, + PA_ERROR_CONNECTIONREFUSED, + PA_ERROR_PROTOCOL, + PA_ERROR_TIMEOUT +}; + +#endif diff --git a/src/protocol-native.c b/src/protocol-native.c index e9cca7c1..a39880b8 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -3,34 +3,19 @@ #include #include "protocol-native.h" +#include "protocol-native-spec.h" #include "packet.h" #include "client.h" #include "sourceoutput.h" #include "sinkinput.h" #include "pstream.h" #include "tagstruct.h" +#include "pdispatch.h" +#include "pstream-util.h" struct connection; struct protocol_native; -enum { - COMMAND_ERROR, - COMMAND_REPLY, - COMMAND_CREATE_PLAYBACK_STREAM, - COMMAND_DELETE_PLAYBACK_STREAM, - COMMAND_CREATE_RECORD_STREAM, - COMMAND_DELETE_RECORD_STREAM, - COMMAND_EXIT, - COMMAND_MAX -}; - -enum { - ERROR_ACCESS, - ERROR_COMMAND, - ERROR_ARGUMENT, - ERROR_EXIST -}; - struct record_stream { struct connection *connection; uint32_t index; @@ -41,6 +26,7 @@ struct record_stream { struct playback_stream { struct connection *connection; uint32_t index; + size_t qlength; struct sink_input *sink_input; struct memblockq *memblockq; }; @@ -50,6 +36,7 @@ struct connection { struct protocol_native *protocol; struct client *client; struct pstream *pstream; + struct pdispatch *pdispatch; struct idxset *record_streams, *playback_streams; }; @@ -60,6 +47,29 @@ struct protocol_native { struct idxset *connections; }; +static int sink_input_peek_cb(struct sink_input *i, struct memchunk *chunk); +static void sink_input_drop_cb(struct sink_input *i, size_t length); +static void sink_input_kill_cb(struct sink_input *i); +static uint32_t sink_input_get_latency_cb(struct sink_input *i); + +static void request_bytes(struct playback_stream*s); + +static int command_exit(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata); +static int command_create_playback_stream(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata); +static int command_delete_playback_stream(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata); + +static const struct pdispatch_command command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = { NULL }, + [PA_COMMAND_REPLY] = { NULL }, + [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { command_create_playback_stream }, + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { command_delete_playback_stream }, + [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_EXIT] = { command_exit }, +}; + +/* structure management */ + static void record_stream_free(struct record_stream* r) { assert(r && r->connection); @@ -69,18 +79,28 @@ static void record_stream_free(struct record_stream* r) { free(r); } -static struct playback_stream* playback_stream_new(struct connection *c, struct sink *sink, struct sample_spec *ss, const char *name, size_t maxlength, size_t prebuf) { +static struct playback_stream* playback_stream_new(struct connection *c, struct sink *sink, struct pa_sample_spec *ss, const char *name, size_t qlen, size_t maxlength, size_t prebuf) { struct playback_stream *s; + assert(c && sink && s && name && qlen && maxlength && prebuf); s = malloc(sizeof(struct playback_stream)); assert (s); s->connection = c; + s->qlength = qlen; + s->sink_input = sink_input_new(sink, ss, name); assert(s->sink_input); - s->memblockq = memblockq_new(maxlength, sample_size(ss), prebuf); + s->sink_input->peek = sink_input_peek_cb; + s->sink_input->drop = sink_input_drop_cb; + s->sink_input->kill = sink_input_kill_cb; + s->sink_input->get_latency = sink_input_get_latency_cb; + s->sink_input->userdata = s; + + s->memblockq = memblockq_new(maxlength, pa_sample_size(ss), prebuf); assert(s->memblockq); idxset_put(c->playback_streams, s, &s->index); + request_bytes(s); return s; } @@ -99,7 +119,6 @@ static void connection_free(struct connection *c) { assert(c && c->protocol); idxset_remove_by_data(c->protocol->connections, c, NULL); - pstream_free(c->pstream); while ((r = idxset_first(c->record_streams, NULL))) record_stream_free(r); idxset_free(c->record_streams, NULL, NULL); @@ -108,67 +127,90 @@ static void connection_free(struct connection *c) { playback_stream_free(p); idxset_free(c->playback_streams, NULL, NULL); + pdispatch_free(c->pdispatch); + pstream_free(c->pstream); client_free(c->client); free(c); } -/*** pstream callbacks ***/ +static void request_bytes(struct playback_stream *s) { + struct tagstruct *t; + size_t l; + assert(s); -static void send_tagstruct(struct pstream *p, struct tagstruct *t) { - size_t length; - uint8_t *data; - struct packet *packet; - assert(p && t); - - data = tagstruct_free_data(t, &length); - assert(data && length); - packet = packet_new_dynamic(data, length); - assert(packet); - pstream_send_packet(p, packet); - packet_unref(packet); -} + if (!(l = memblockq_missing_to(s->memblockq, s->qlength))) + return; -static void send_error(struct pstream *p, uint32_t tag, uint32_t error) { - struct tagstruct *t = tagstruct_new(NULL, 0); + t = tagstruct_new(NULL, 0); assert(t); - tagstruct_putu32(t, COMMAND_ERROR); - tagstruct_putu32(t, tag); - tagstruct_putu32(t, error); - send_tagstruct(p, t); + tagstruct_putu32(t, PA_COMMAND_REQUEST); + tagstruct_putu32(t, s->index); + tagstruct_putu32(t, l); + pstream_send_tagstruct(s->connection->pstream, t); } -static void send_simple_ack(struct pstream *p, uint32_t tag) { - struct tagstruct *t = tagstruct_new(NULL, 0); - assert(t); - tagstruct_putu32(t, COMMAND_REPLY); - tagstruct_putu32(t, tag); - send_tagstruct(p, t); +/*** sinkinput callbacks ***/ + +static int sink_input_peek_cb(struct sink_input *i, struct memchunk *chunk) { + struct playback_stream *s; + assert(i && i->userdata && chunk); + s = i->userdata; + + if (memblockq_peek(s->memblockq, chunk) < 0) + return -1; + + return 0; } -struct command { - int (*func)(struct connection *c, uint32_t tag, struct tagstruct *t); -}; +static void sink_input_drop_cb(struct sink_input *i, size_t length) { + struct playback_stream *s; + assert(i && i->userdata && length); + s = i->userdata; -static int command_create_playback_stream(struct connection *c, uint32_t tag, struct tagstruct *t) { + memblockq_drop(s->memblockq, length); + request_bytes(s); +} + +static void sink_input_kill_cb(struct sink_input *i) { struct playback_stream *s; - size_t maxlength, prebuf; + assert(i && i->userdata); + s = i->userdata; + + playback_stream_free(s); +} + +static uint32_t sink_input_get_latency_cb(struct sink_input *i) { + struct playback_stream *s; + assert(i && i->userdata); + s = i->userdata; + + return pa_samples_usec(memblockq_get_length(s->memblockq), &s->sink_input->sample_spec); +} + +/*** pdispatch callbacks ***/ + +static int command_create_playback_stream(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata) { + struct connection *c = userdata; + struct playback_stream *s; + size_t maxlength, prebuf, qlength; uint32_t sink_index; const char *name; - struct sample_spec ss; + struct pa_sample_spec ss; struct tagstruct *reply; struct sink *sink; assert(c && t && c->protocol && c->protocol->core); if (tagstruct_gets(t, &name) < 0 || tagstruct_get_sample_spec(t, &ss) < 0 || - tagstruct_getu32(t, &sink_index) < 0 || + tagstruct_getu32(t, &sink_index) < 0 || + tagstruct_getu32(t, &qlength) < 0 || tagstruct_getu32(t, &maxlength) < 0 || tagstruct_getu32(t, &prebuf) < 0 || !tagstruct_eof(t)) return -1; if (!c->authorized) { - send_error(c->pstream, tag, ERROR_ACCESS); + pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); return 0; } @@ -178,25 +220,28 @@ static int command_create_playback_stream(struct connection *c, uint32_t tag, st sink = idxset_get_by_index(c->protocol->core->sinks, sink_index); if (!sink) { - send_error(c->pstream, tag, ERROR_EXIST); + pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); return 0; } - if (!(s = playback_stream_new(c, sink, &ss, name, maxlength, prebuf))) { - send_error(c->pstream, tag, ERROR_ARGUMENT); + if (!(s = playback_stream_new(c, sink, &ss, name, qlength, maxlength, prebuf))) { + pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); return 0; } reply = tagstruct_new(NULL, 0); assert(reply); - tagstruct_putu32(reply, COMMAND_REPLY); + tagstruct_putu32(reply, PA_COMMAND_REPLY); tagstruct_putu32(reply, tag); tagstruct_putu32(reply, s->index); - send_tagstruct(c->pstream, reply); + assert(s->sink_input); + tagstruct_putu32(reply, s->sink_input->index); + pstream_send_tagstruct(c->pstream, reply); return 0; } -static int command_delete_playback_stream(struct connection *c, uint32_t tag, struct tagstruct *t) { +static int command_delete_playback_stream(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata) { + struct connection *c = userdata; uint32_t channel; struct playback_stream *s; assert(c && t); @@ -206,78 +251,50 @@ static int command_delete_playback_stream(struct connection *c, uint32_t tag, st return -1; if (!c->authorized) { - send_error(c->pstream, tag, ERROR_ACCESS); + pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); return 0; } if (!(s = idxset_get_by_index(c->playback_streams, channel))) { - send_error(c->pstream, tag, ERROR_EXIST); + pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); return 0; } - send_simple_ack(c->pstream, tag); + pstream_send_simple_ack(c->pstream, tag); return 0; } -static int command_exit(struct connection *c, uint32_t tag, struct tagstruct *t) { +static int command_exit(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata) { + struct connection *c = userdata; assert(c && t); if (!tagstruct_eof(t)) return -1; if (!c->authorized) { - send_error(c->pstream, tag, ERROR_ACCESS); + pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); return 0; } - assert(c->protocol && c->protocol->core); - mainloop_quit(c->protocol->core->mainloop, -1); - send_simple_ack(c->pstream, tag); /* nonsense */ + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop); + c->protocol->core->mainloop->quit(c->protocol->core->mainloop, 0); + pstream_send_simple_ack(c->pstream, tag); /* nonsense */ return 0; } -static const struct command commands[] = { - [COMMAND_ERROR] = { NULL }, - [COMMAND_REPLY] = { NULL }, - [COMMAND_CREATE_PLAYBACK_STREAM] = { command_create_playback_stream }, - [COMMAND_DELETE_PLAYBACK_STREAM] = { command_delete_playback_stream }, - [COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [COMMAND_DELETE_RECORD_STREAM] = { NULL }, - [COMMAND_EXIT] = { command_exit }, -}; +/*** pstream callbacks ***/ + static int packet_callback(struct pstream *p, struct packet *packet, void *userdata) { struct connection *c = userdata; - uint32_t tag, command; - struct tagstruct *ts = NULL; assert(p && packet && packet->data && c); - if (packet->length <= 8) - goto fail; - - ts = tagstruct_new(packet->data, packet->length); - assert(ts); - - if (tagstruct_getu32(ts, &command) < 0 || - tagstruct_getu32(ts, &tag) < 0) - goto fail; - - if (command >= COMMAND_MAX || !commands[command].func) - send_error(p, tag, ERROR_COMMAND); - else if (commands[command].func(c, tag, ts) < 0) - goto fail; + if (pdispatch_run(c->pdispatch, packet, c) < 0) { + fprintf(stderr, "protocol-native: invalid packet.\n"); + return -1; + } - tagstruct_free(ts); - return 0; - -fail: - if (ts) - tagstruct_free(ts); - - fprintf(stderr, "protocol-native: invalid packet.\n"); - return -1; - } static int memblock_callback(struct pstream *p, uint32_t channel, int32_t delta, struct memchunk *chunk, void *userdata) { @@ -326,6 +343,9 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us pstream_set_recieve_memblock_callback(c->pstream, memblock_callback, c); pstream_set_die_callback(c->pstream, die_callback, c); + c->pdispatch = pdispatch_new(p->core->mainloop, command_table, PA_COMMAND_MAX); + assert(c->pdispatch); + c->record_streams = idxset_new(NULL, NULL); c->playback_streams = idxset_new(NULL, NULL); assert(c->record_streams && c->playback_streams); diff --git a/src/protocol-simple.c b/src/protocol-simple.c index 8e4246cd..c8c45854 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -9,6 +9,7 @@ #include "sourceoutput.h" #include "protocol-simple.h" #include "client.h" +#include "sample-util.h" struct connection { struct protocol_simple *protocol; @@ -115,9 +116,10 @@ static int do_write(struct connection *c) { /*** sink_input callbacks ***/ static int sink_input_peek_cb(struct sink_input *i, struct memchunk *chunk) { - struct connection*c = i->userdata; - assert(i && c && chunk); - + struct connection*c; + assert(i && i->userdata && chunk); + c = i->userdata; + if (memblockq_peek(c->input_memblockq, chunk) < 0) return -1; @@ -143,7 +145,7 @@ static void sink_input_kill_cb(struct sink_input *i) { static uint32_t sink_input_get_latency_cb(struct sink_input *i) { struct connection*c = i->userdata; assert(i && c); - return samples_usec(memblockq_get_length(c->input_memblockq), &DEFAULT_SAMPLE_SPEC); + return pa_samples_usec(memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); } /*** source_output callbacks ***/ @@ -185,6 +187,7 @@ static void io_callback(struct iochannel*io, void *userdata) { static void on_connection(struct socket_server*s, struct iochannel *io, void *userdata) { struct protocol_simple *p = userdata; struct connection *c = NULL; + char cname[256]; assert(s && io && p); c = malloc(sizeof(struct connection)); @@ -195,7 +198,8 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c->input_memblockq = c->output_memblockq = NULL; c->protocol = p; - c->client = client_new(p->core, "SIMPLE", "Client"); + iochannel_peer_to_string(io, cname, sizeof(cname)); + c->client = client_new(p->core, "SIMPLE", cname); assert(c->client); c->client->kill = client_kill_cb; c->client->userdata = c; @@ -215,8 +219,8 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c->source_output->kill = source_output_kill_cb; c->source_output->userdata = c; - l = 5*bytes_per_second(&DEFAULT_SAMPLE_SPEC); /* 5s */ - c->output_memblockq = memblockq_new(l, sample_size(&DEFAULT_SAMPLE_SPEC), l/2); + l = 5*pa_bytes_per_second(&DEFAULT_SAMPLE_SPEC); /* 5s */ + c->output_memblockq = memblockq_new(l, pa_sample_size(&DEFAULT_SAMPLE_SPEC), l/2); } if (p->mode & PROTOCOL_SIMPLE_PLAYBACK) { @@ -236,8 +240,8 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c->sink_input->get_latency = sink_input_get_latency_cb; c->sink_input->userdata = c; - l = bytes_per_second(&DEFAULT_SAMPLE_SPEC)/2; /* half a second */ - c->input_memblockq = memblockq_new(l, sample_size(&DEFAULT_SAMPLE_SPEC), l/2); + l = pa_bytes_per_second(&DEFAULT_SAMPLE_SPEC)/2; /* half a second */ + c->input_memblockq = memblockq_new(l, pa_sample_size(&DEFAULT_SAMPLE_SPEC), l/2); } diff --git a/src/pstream-util.c b/src/pstream-util.c new file mode 100644 index 00000000..2fab2b61 --- /dev/null +++ b/src/pstream-util.c @@ -0,0 +1,35 @@ +#include + +#include "protocol-native-spec.h" +#include "pstream-util.h" + +void pstream_send_tagstruct(struct pstream *p, struct tagstruct *t) { + size_t length; + uint8_t *data; + struct packet *packet; + assert(p && t); + + data = tagstruct_free_data(t, &length); + assert(data && length); + packet = packet_new_dynamic(data, length); + assert(packet); + pstream_send_packet(p, packet); + packet_unref(packet); +} + +void pstream_send_error(struct pstream *p, uint32_t tag, uint32_t error) { + struct tagstruct *t = tagstruct_new(NULL, 0); + assert(t); + tagstruct_putu32(t, PA_COMMAND_ERROR); + tagstruct_putu32(t, tag); + tagstruct_putu32(t, error); + pstream_send_tagstruct(p, t); +} + +void pstream_send_simple_ack(struct pstream *p, uint32_t tag) { + struct tagstruct *t = tagstruct_new(NULL, 0); + assert(t); + tagstruct_putu32(t, PA_COMMAND_REPLY); + tagstruct_putu32(t, tag); + pstream_send_tagstruct(p, t); +} diff --git a/src/pstream-util.h b/src/pstream-util.h new file mode 100644 index 00000000..4e64a95c --- /dev/null +++ b/src/pstream-util.h @@ -0,0 +1,14 @@ +#ifndef foopstreamutilhfoo +#define foopstreamutilhfoo + +#include +#include "pstream.h" +#include "tagstruct.h" + +/* The tagstruct is freed!*/ +void pstream_send_tagstruct(struct pstream *p, struct tagstruct *t); + +void pstream_send_error(struct pstream *p, uint32_t tag, uint32_t error); +void pstream_send_simple_ack(struct pstream *p, uint32_t tag); + +#endif diff --git a/src/pstream.c b/src/pstream.c index a63e126d..4a3a648b 100644 --- a/src/pstream.c +++ b/src/pstream.c @@ -30,7 +30,7 @@ struct item_info { }; struct pstream { - struct mainloop *mainloop; + struct pa_mainloop_api *mainloop; struct mainloop_source *mainloop_source; struct iochannel *io; struct queue *send_queue; @@ -70,18 +70,24 @@ static void do_read(struct pstream *p); static void io_callback(struct iochannel*io, void *userdata) { struct pstream *p = userdata; assert(p && p->io == io); + + p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 0); + do_write(p); do_read(p); } -static void prepare_callback(struct mainloop_source *s, void*userdata) { +static void fixed_callback(struct pa_mainloop_api *m, void *id, void*userdata) { struct pstream *p = userdata; - assert(p && p->mainloop_source == s); + assert(p && p->mainloop_source == id && p->mainloop == m); + + p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 0); + do_write(p); do_read(p); } -struct pstream *pstream_new(struct mainloop *m, struct iochannel *io) { +struct pstream *pstream_new(struct pa_mainloop_api *m, struct iochannel *io) { struct pstream *p; assert(io); @@ -96,8 +102,8 @@ struct pstream *pstream_new(struct mainloop *m, struct iochannel *io) { p->die_callback_userdata = NULL; p->mainloop = m; - p->mainloop_source = mainloop_source_new_fixed(m, prepare_callback, p); - mainloop_source_enable(p->mainloop_source, 0); + p->mainloop_source = m->source_fixed(m, fixed_callback, p); + m->enable_fixed(m, p->mainloop_source, 0); p->send_queue = queue_new(); assert(p->send_queue); @@ -152,7 +158,7 @@ void pstream_free(struct pstream *p) { if (p->read.packet) packet_unref(p->read.packet); - mainloop_source_free(p->mainloop_source); + p->mainloop->cancel_fixed(p->mainloop, p->mainloop_source); free(p); } @@ -173,7 +179,7 @@ void pstream_send_packet(struct pstream*p, struct packet *packet) { i->packet = packet_ref(packet); queue_push(p->send_queue, i); - mainloop_source_enable(p->mainloop_source, 1); + p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 1); } void pstream_send_memblock(struct pstream*p, uint32_t channel, int32_t delta, struct memchunk *chunk) { @@ -190,7 +196,7 @@ void pstream_send_memblock(struct pstream*p, uint32_t channel, int32_t delta, st memblock_ref(i->chunk.memblock); queue_push(p->send_queue, i); - mainloop_source_enable(p->mainloop_source, 1); + p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 1); } void pstream_set_recieve_packet_callback(struct pstream *p, int (*callback) (struct pstream *p, struct packet *packet, void *userdata), void *userdata) { @@ -219,7 +225,7 @@ static void prepare_next_write_item(struct pstream *p) { assert(p->write.current->packet); p->write.data = p->write.current->packet->data; p->write.descriptor[PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->packet->length); - p->write.descriptor[PSTREAM_DESCRIPTOR_CHANNEL] = 0; + p->write.descriptor[PSTREAM_DESCRIPTOR_CHANNEL] = htonl((uint32_t) -1); p->write.descriptor[PSTREAM_DESCRIPTOR_DELTA] = 0; } else { assert(p->write.current->type == PSTREAM_ITEM_MEMBLOCK && p->write.current->chunk.memblock); @@ -236,8 +242,6 @@ static void do_write(struct pstream *p) { ssize_t r; assert(p); - mainloop_source_enable(p->mainloop_source, 0); - if (p->dead || !iochannel_is_writable(p->io)) return; @@ -285,8 +289,6 @@ static void do_read(struct pstream *p) { ssize_t r; assert(p); - mainloop_source_enable(p->mainloop_source, 0); - if (p->dead || !iochannel_is_readable(p->io)) return; @@ -313,7 +315,7 @@ static void do_read(struct pstream *p) { assert(!p->read.packet && !p->read.memblock); - if (ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_CHANNEL]) == 0) { + if (ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_CHANNEL]) == (uint32_t) -1) { /* Frame is a packet frame */ p->read.packet = packet_new(ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH])); assert(p->read.packet); @@ -331,7 +333,7 @@ static void do_read(struct pstream *p) { if (p->read.memblock && p->recieve_memblock_callback) { /* Is this memblock data? Than pass it to the user */ size_t l; - l = p->read.index - r < PSTREAM_DESCRIPTOR_SIZE ? p->read.index - PSTREAM_DESCRIPTOR_SIZE : r; + l = (p->read.index - r) < PSTREAM_DESCRIPTOR_SIZE ? p->read.index - PSTREAM_DESCRIPTOR_SIZE : (size_t) r; if (l > 0) { struct memchunk chunk; diff --git a/src/pstream.h b/src/pstream.h index 7113681e..d418908e 100644 --- a/src/pstream.h +++ b/src/pstream.h @@ -6,10 +6,11 @@ #include "packet.h" #include "memblock.h" #include "iochannel.h" +#include "mainloop-api.h" struct pstream; -struct pstream* pstream_new(struct mainloop *m, struct iochannel *io); +struct pstream* pstream_new(struct pa_mainloop_api *m, struct iochannel *io); void pstream_free(struct pstream*p); void pstream_set_send_callback(struct pstream*p, void (*callback) (struct pstream *p, void *userdata), void *userdata); diff --git a/src/queue.c b/src/queue.c index 90823ae6..5c2e7a67 100644 --- a/src/queue.c +++ b/src/queue.c @@ -73,5 +73,12 @@ void* queue_pop(struct queue *q) { p = e->data; free(e); + q->length--; + return p; } + +int queue_is_empty(struct queue *q) { + assert(q); + return q->length == 0; +} diff --git a/src/sample-util.c b/src/sample-util.c new file mode 100644 index 00000000..7a3c267a --- /dev/null +++ b/src/sample-util.c @@ -0,0 +1,88 @@ +#include +#include + +#include "sample-util.h" + +struct pa_sample_spec default_sample_spec = { + .format = SAMPLE_S16NE, + .rate = 44100, + .channels = 2 +}; + +struct memblock *silence_memblock(struct memblock* b, struct pa_sample_spec *spec) { + assert(b && b->data && spec); + memblock_assert_exclusive(b); + silence_memory(b->data, b->length, spec); + return b; +} + +void silence_memchunk(struct memchunk *c, struct pa_sample_spec *spec) { + assert(c && c->memblock && c->memblock->data && spec && c->length); + memblock_assert_exclusive(c->memblock); + silence_memory(c->memblock->data+c->index, c->length, spec); +} + +void silence_memory(void *p, size_t length, struct pa_sample_spec *spec) { + char c = 0; + assert(p && length && spec); + + switch (spec->format) { + case SAMPLE_U8: + c = 127; + break; + case SAMPLE_S16LE: + case SAMPLE_S16BE: + case SAMPLE_FLOAT32: + c = 0; + break; + case SAMPLE_ALAW: + case SAMPLE_ULAW: + c = 80; + break; + } + + memset(p, c, length); +} + +size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct pa_sample_spec *spec, uint8_t volume) { + unsigned c, d; + assert(channels && data && length && spec); + assert(spec->format == SAMPLE_S16NE); + + for (d = 0;; d += sizeof(int16_t)) { + int32_t sum = 0; + + if (d >= length) + return d; + + for (c = 0; c < nchannels; c++) { + int32_t v; + uint8_t volume = channels[c].volume; + + if (d >= channels[c].chunk.length) + return d; + + if (volume == 0) + v = 0; + else { + v = *((int16_t*) (channels[c].chunk.memblock->data + channels[c].chunk.index + d)); + + if (volume != 0xFF) + v = v*volume/0xFF; + } + + sum += v; + } + + if (volume == 0) + sum = 0; + else if (volume != 0xFF) + sum = sum*volume/0xFF; + + if (sum < -0x8000) sum = -0x8000; + if (sum > 0x7FFF) sum = 0x7FFF; + + *((int16_t*) data) = sum; + data += sizeof(int16_t); + } +} diff --git a/src/sample-util.h b/src/sample-util.h new file mode 100644 index 00000000..0a3f7c89 --- /dev/null +++ b/src/sample-util.h @@ -0,0 +1,23 @@ +#ifndef foosampleutilhfoo +#define foosampleutilhfoo + +#include "sample.h" +#include "memblock.h" + +#define DEFAULT_SAMPLE_SPEC default_sample_spec + +extern struct pa_sample_spec default_sample_spec; + +struct memblock *silence_memblock(struct memblock* b, struct pa_sample_spec *spec); +void silence_memchunk(struct memchunk *c, struct pa_sample_spec *spec); +void silence_memory(void *p, size_t length, struct pa_sample_spec *spec); + +struct mix_info { + struct memchunk chunk; + uint8_t volume; + void *userdata; +}; + +size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct pa_sample_spec *spec, uint8_t volume); + +#endif diff --git a/src/sample.c b/src/sample.c index c270f255..2454630c 100644 --- a/src/sample.c +++ b/src/sample.c @@ -1,50 +1,8 @@ -#include #include #include "sample.h" -struct sample_spec default_sample_spec = { - .format = SAMPLE_S16NE, - .rate = 44100, - .channels = 2 -}; - -struct memblock *silence_memblock(struct memblock* b, struct sample_spec *spec) { - assert(b && b->data && spec); - memblock_assert_exclusive(b); - silence_memory(b->data, b->length, spec); - return b; -} - -void silence_memchunk(struct memchunk *c, struct sample_spec *spec) { - assert(c && c->memblock && c->memblock->data && spec && c->length); - memblock_assert_exclusive(c->memblock); - silence_memory(c->memblock->data+c->index, c->length, spec); -} - -void silence_memory(void *p, size_t length, struct sample_spec *spec) { - char c = 0; - assert(p && length && spec); - - switch (spec->format) { - case SAMPLE_U8: - c = 127; - break; - case SAMPLE_S16LE: - case SAMPLE_S16BE: - case SAMPLE_FLOAT32: - c = 0; - break; - case SAMPLE_ALAW: - case SAMPLE_ULAW: - c = 80; - break; - } - - memset(p, c, length); -} - -size_t sample_size(struct sample_spec *spec) { +size_t pa_sample_size(struct pa_sample_spec *spec) { assert(spec); size_t b = 1; @@ -66,56 +24,14 @@ size_t sample_size(struct sample_spec *spec) { return b * spec->channels; } -size_t bytes_per_second(struct sample_spec *spec) { +size_t pa_bytes_per_second(struct pa_sample_spec *spec) { assert(spec); - return spec->rate*sample_size(spec); + return spec->rate*pa_sample_size(spec); } -size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct sample_spec *spec, uint8_t volume) { - unsigned c, d; - assert(channels && data && length && spec); - assert(spec->format == SAMPLE_S16NE); - - for (d = 0;; d += sizeof(int16_t)) { - int32_t sum = 0; - - if (d >= length) - return d; - - for (c = 0; c < nchannels; c++) { - int32_t v; - uint8_t volume = channels[c].volume; - - if (d >= channels[c].chunk.length) - return d; - - if (volume == 0) - v = 0; - else { - v = *((int16_t*) (channels[c].chunk.memblock->data + channels[c].chunk.index + d)); - - if (volume != 0xFF) - v = v*volume/0xFF; - } - - sum += v; - } - - if (volume == 0) - sum = 0; - else if (volume != 0xFF) - sum = sum*volume/0xFF; - - if (sum < -0x8000) sum = -0x8000; - if (sum > 0x7FFF) sum = 0x7FFF; - - *((int16_t*) data) = sum; - data += sizeof(int16_t); - } -} -uint32_t samples_usec(size_t length, struct sample_spec *spec) { +uint32_t pa_samples_usec(size_t length, struct pa_sample_spec *spec) { assert(spec); - return (uint32_t) (((double) length /sample_size(spec))/spec->rate*1000000); + return (uint32_t) (((double) length /pa_sample_size(spec))/spec->rate*1000000); } diff --git a/src/sample.h b/src/sample.h index b2f13cc4..a4a973bf 100644 --- a/src/sample.h +++ b/src/sample.h @@ -2,10 +2,9 @@ #define foosamplehfoo #include +#include -#include "memblock.h" - -enum sample_format { +enum pa_sample_format { SAMPLE_U8, SAMPLE_ALAW, SAMPLE_ULAW, @@ -16,30 +15,14 @@ enum sample_format { #define SAMPLE_S16NE SAMPLE_S16LE -struct sample_spec { - enum sample_format format; +struct pa_sample_spec { + enum pa_sample_format format; uint32_t rate; uint8_t channels; }; -#define DEFAULT_SAMPLE_SPEC default_sample_spec - -extern struct sample_spec default_sample_spec; - -struct memblock *silence_memblock(struct memblock* b, struct sample_spec *spec); -void silence_memchunk(struct memchunk *c, struct sample_spec *spec); -void silence_memory(void *p, size_t length, struct sample_spec *spec); - -struct mix_info { - struct memchunk chunk; - uint8_t volume; - void *userdata; -}; - -size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct sample_spec *spec, uint8_t volume); - -size_t bytes_per_second(struct sample_spec *spec); -size_t sample_size(struct sample_spec *spec); -uint32_t samples_usec(size_t length, struct sample_spec *spec); +size_t pa_bytes_per_second(struct pa_sample_spec *spec); +size_t pa_sample_size(struct pa_sample_spec *spec); +uint32_t pa_samples_usec(size_t length, struct pa_sample_spec *spec); #endif diff --git a/src/simple.c b/src/simple.c new file mode 100644 index 00000000..a90d22bd --- /dev/null +++ b/src/simple.c @@ -0,0 +1,120 @@ +#include "simple.h" +#include "polyp.h" +#include "mainloop.h" + +struct pa_simple { + struct mainloop *mainloop; + struct pa_context *context; + struct pa_stream *stream; + + size_t requested; + int dead; +}; + +static void playback_callback(struct pa_stream *p, size_t length, void *userdata) { + struct pa_stream *sp = userdata; + assert(p && length && sp); + + sp->requested = length; +} + +struct pa_simple* pa_simple_new( + const char *server, + const char *name, + enum pa_stream_direction dir, + const char *dev, + const char *stream_name, + const struct pa_sample_spec *ss, + const struct pa_buffer_attr *attr) { + + struct pa_simple *p; + assert(ss); + + p = malloc(sizeof(struct pa_simple)); + assert(p); + p->context = NULL; + p->stream = NULL; + p->mainloop = pa_mainloop_new(); + assert(p->mainloop); + p->requested = 0; + p->dead = 0; + + if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name))) + goto fail; + + if (pa_context_connect(c, server, NULL, NULL) < 0) + goto fail; + + while (!pa_context_is_ready(c)) { + if (pa_context_is_dead(c)) + goto fail; + + if (mainloop_iterate(p->mainloop) < 0) + goto fail; + } + + if (!(p->stream = pa_stream_new(p->context, dir, sink, stream_name, ss, attr, NULL, NULL))) + goto fail; + + while (!pa_stream_is_ready(c)) { + if (pa_stream_is_dead(c)) + goto fail; + + if (mainloop_iterate(p->mainloop) < 0) + goto fail; + } + + pa_stream_set_write_callback(p->stream, playback_callback, p); + + return p; + +fail: + pa_simple_free(p); + return NULL; +} + +void pa_simple_free(struct pa_simple *s) { + assert(s); + + if (s->stream) + pa_stream_free(s->stream); + + if (s->context) + pa_context_free(s->context); + + if (s->mainloop) + mainloop_free(s->mainloop); + + free(s); +} + +int pa_simple_write(struct pa_simple *s, const void*data, size_t length) { + assert(s && data); + + while (length > 0) { + size_t l; + + while (!s->requested) { + if (pa_context_is_dead(c)) + return -1; + + if (mainloop_iterate(s->mainloop) < 0) + return -1; + } + + l = length; + if (l > s->requested) + l = s->requested; + + pa_stream_write(s->stream, data, l); + data += l; + length -= l; + s->requested = -l; + } + + return 0; +} + +int pa_simple_read(struct pa_simple *s, const void*data, size_t length) { + assert(0); +} diff --git a/src/simple.h b/src/simple.h new file mode 100644 index 00000000..80693056 --- /dev/null +++ b/src/simple.h @@ -0,0 +1,25 @@ +#ifndef foosimplehfoo +#define foosimplehfoo + +#include + +#include "sample.h" +#include "polypdef.h" + +struct pa_simple; + +struct pa_simple* pa_simple_new( + const char *server, + const char *name, + enum pa_stream_direction dir, + const char *dev, + const char *stream_name, + const struct pa_sample_spec *ss, + const struct pa_buffer_attr *attr); + +void pa_simple_free(struct pa_simple *s); + +int pa_simple_write(struct pa_simple *s, const void*data, size_t length); +int pa_simple_read(struct pa_simple *s, const void*data, size_t length); + +#endif diff --git a/src/sink.c b/src/sink.c index cd12b463..a334424c 100644 --- a/src/sink.c +++ b/src/sink.c @@ -6,10 +6,11 @@ #include "sink.h" #include "sinkinput.h" #include "strbuf.h" +#include "sample-util.h" #define MAX_MIX_CHANNELS 32 -struct sink* sink_new(struct core *core, const char *name, const struct sample_spec *spec) { +struct sink* sink_new(struct core *core, const char *name, const struct pa_sample_spec *spec) { struct sink *s; char *n = NULL; int r; diff --git a/src/sink.h b/src/sink.h index 394abb5b..d9f80059 100644 --- a/src/sink.h +++ b/src/sink.h @@ -15,7 +15,7 @@ struct sink { char *name; struct core *core; - struct sample_spec sample_spec; + struct pa_sample_spec sample_spec; struct idxset *inputs; struct source *monitor_source; @@ -27,7 +27,7 @@ struct sink { void *userdata; }; -struct sink* sink_new(struct core *core, const char *name, const struct sample_spec *spec); +struct sink* sink_new(struct core *core, const char *name, const struct pa_sample_spec *spec); void sink_free(struct sink* s); int sink_render(struct sink*s, size_t length, struct memchunk *result); diff --git a/src/sinkinput.c b/src/sinkinput.c index 2e6a8c36..b81c9c71 100644 --- a/src/sinkinput.c +++ b/src/sinkinput.c @@ -5,7 +5,7 @@ #include "sinkinput.h" #include "strbuf.h" -struct sink_input* sink_input_new(struct sink *s, struct sample_spec *spec, const char *name) { +struct sink_input* sink_input_new(struct sink *s, struct pa_sample_spec *spec, const char *name) { struct sink_input *i; int r; assert(s && spec); @@ -14,7 +14,7 @@ struct sink_input* sink_input_new(struct sink *s, struct sample_spec *spec, cons assert(i); i->name = name ? strdup(name) : NULL; i->sink = s; - i->spec = *spec; + i->sample_spec = *spec; i->peek = NULL; i->drop = NULL; diff --git a/src/sinkinput.h b/src/sinkinput.h index 389d832d..f04ecb95 100644 --- a/src/sinkinput.h +++ b/src/sinkinput.h @@ -12,7 +12,7 @@ struct sink_input { char *name; struct sink *sink; - struct sample_spec spec; + struct pa_sample_spec sample_spec; uint8_t volume; int (*peek) (struct sink_input *i, struct memchunk *chunk); @@ -23,7 +23,7 @@ struct sink_input { void *userdata; }; -struct sink_input* sink_input_new(struct sink *s, struct sample_spec *spec, const char *name); +struct sink_input* sink_input_new(struct sink *s, struct pa_sample_spec *spec, const char *name); void sink_input_free(struct sink_input* i); /* Code that didn't create the input stream should call this function to diff --git a/src/socket-client.c b/src/socket-client.c new file mode 100644 index 00000000..812c43f3 --- /dev/null +++ b/src/socket-client.c @@ -0,0 +1,177 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "socket-client.h" +#include "util.h" + +struct socket_client { + struct pa_mainloop_api *mainloop; + int fd; + + void *io_source, *fixed_source; + void (*callback)(struct socket_client*c, struct iochannel *io, void *userdata); + void *userdata; +}; + +static struct socket_client*socket_client_new(struct pa_mainloop_api *m) { + struct socket_client *c; + assert(m); + + c = malloc(sizeof(struct socket_client)); + assert(c); + c->mainloop = m; + c->fd = -1; + c->io_source = c->fixed_source = NULL; + c->callback = NULL; + c->userdata = NULL; + return c; +} + +static void do_call(struct socket_client *c) { + struct iochannel *io; + int error, lerror; + assert(c && c->callback); + + lerror = sizeof(error); + if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &error, &lerror) < 0) { + fprintf(stderr, "getsockopt(): %s\n", strerror(errno)); + goto failed; + } + + if (lerror != sizeof(error)) { + fprintf(stderr, "getsocktop() returned invalid size.\n"); + goto failed; + } + + if (error != 0) { + fprintf(stderr, "connect(): %s\n", strerror(error)); + goto failed; + } + + io = iochannel_new(c->mainloop, c->fd, c->fd); + assert(io); + c->fd = -1; + c->callback(c, io, c->userdata); + + return; + +failed: + close(c->fd); + c->fd = -1; + c->callback(c, NULL, c->userdata); + return; +} + +static void connect_fixed_cb(struct pa_mainloop_api *m, void *id, void *userdata) { + struct socket_client *c = userdata; + assert(m && c && c->fixed_source == id); + m->cancel_fixed(m, c->fixed_source); + c->fixed_source = NULL; + do_call(c); +} + +static void connect_io_cb(struct pa_mainloop_api*m, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { + struct socket_client *c = userdata; + assert(m && c && c->io_source == id && fd >= 0 && events == PA_MAINLOOP_API_IO_EVENT_OUTPUT); + m->cancel_io(m, c->io_source); + c->io_source = NULL; + do_call(c); +} + +static int do_connect(struct socket_client *c, const struct sockaddr *sa, socklen_t len) { + int r; + assert(c && sa && len); + + make_nonblock_fd(c->fd); + + if ((r = connect(c->fd, sa, len)) < 0) { + if (r != EINPROGRESS) { + fprintf(stderr, "connect(): %s\n", strerror(errno)); + return -1; + } + + c->io_source = c->mainloop->source_io(c->mainloop, c->fd, PA_MAINLOOP_API_IO_EVENT_OUTPUT, connect_io_cb, c); + assert(c->io_source); + } else { + c->fixed_source = c->mainloop->source_fixed(c->mainloop, connect_fixed_cb, c); + assert(c->io_source); + } + + return 0; +} + +struct socket_client* socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port) { + struct socket_client *c; + struct sockaddr_in sa; + + c = socket_client_new(m); + assert(c); + + if ((c->fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "socket(): %s\n", strerror(errno)); + goto fail; + } + + sa.sin_family = AF_INET; + sa.sin_port = htons(port); + sa.sin_addr.s_addr = htonl(address); + + if (do_connect(c, (struct sockaddr*) &sa, sizeof(sa)) < 0) + goto fail; + + return c; + +fail: + socket_client_free(c); + return NULL; +} + +struct socket_client* socket_client_new_unix(struct pa_mainloop_api *m, const char *filename) { + struct socket_client *c; + struct sockaddr_un sa; + + c = socket_client_new(m); + assert(c); + + if ((c->fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "socket(): %s\n", strerror(errno)); + goto fail; + } + + sa.sun_family = AF_LOCAL; + strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); + sa.sun_path[sizeof(sa.sun_path) - 1] = 0; + + if (do_connect(c, (struct sockaddr*) &sa, sizeof(sa)) < 0) + goto fail; + + return c; + +fail: + socket_client_free(c); + return NULL; +} + +void socket_client_free(struct socket_client *c) { + assert(c && c->mainloop); + if (c->io_source) + c->mainloop->cancel_io(c->mainloop, c->io_source); + if (c->fixed_source) + c->mainloop->cancel_fixed(c->mainloop, c->fixed_source); + if (c->fd >= 0) + close(c->fd); + free(c); +} + +void socket_client_set_callback(struct socket_client *c, void (*on_connection)(struct socket_client *c, struct iochannel*io, void *userdata), void *userdata) { + assert(c); + c->callback = on_connection; + c->userdata = userdata; +} diff --git a/src/socket-client.h b/src/socket-client.h new file mode 100644 index 00000000..4de01e34 --- /dev/null +++ b/src/socket-client.h @@ -0,0 +1,17 @@ +#ifndef foosocketclienthfoo +#define foosocketclienthfoo + +#include +#include "mainloop-api.h" +#include "iochannel.h" + +struct socket_client; + +struct socket_client* socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port); +struct socket_client* socket_client_new_unix(struct pa_mainloop_api *m, const char *filename); + +void socket_client_free(struct socket_client *c); + +void socket_client_set_callback(struct socket_client *c, void (*on_connection)(struct socket_client *c, struct iochannel*io, void *userdata), void *userdata); + +#endif diff --git a/src/socket-server.c b/src/socket-server.c index 6ad225e3..87fe1476 100644 --- a/src/socket-server.c +++ b/src/socket-server.c @@ -19,14 +19,15 @@ struct socket_server { void (*on_connection)(struct socket_server*s, struct iochannel *io, void *userdata); void *userdata; - struct mainloop_source *mainloop_source; + void *mainloop_source; + struct pa_mainloop_api *mainloop; }; -static void callback(struct mainloop_source*src, int fd, enum mainloop_io_event event, void *userdata) { +static void callback(struct pa_mainloop_api *mainloop, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { struct socket_server *s = userdata; struct iochannel *io; int nfd; - assert(src && fd >= 0 && fd == s->fd && event == MAINLOOP_IO_EVENT_IN && s); + assert(s && s->mainloop == mainloop && s->mainloop_source == id && id && fd >= 0 && fd == s->fd && events == PA_MAINLOOP_API_IO_EVENT_INPUT); if ((nfd = accept(fd, NULL, NULL)) < 0) { fprintf(stderr, "accept(): %s\n", strerror(errno)); @@ -38,12 +39,12 @@ static void callback(struct mainloop_source*src, int fd, enum mainloop_io_event return; } - io = iochannel_new(mainloop_source_get_mainloop(src), nfd, nfd); + io = iochannel_new(s->mainloop, nfd, nfd); assert(io); s->on_connection(s, io, s->userdata); } -struct socket_server* socket_server_new(struct mainloop *m, int fd) { +struct socket_server* socket_server_new(struct pa_mainloop_api *m, int fd) { struct socket_server *s; assert(m && fd >= 0); @@ -54,13 +55,14 @@ struct socket_server* socket_server_new(struct mainloop *m, int fd) { s->on_connection = NULL; s->userdata = NULL; - s->mainloop_source = mainloop_source_new_io(m, fd, MAINLOOP_IO_EVENT_IN, callback, s); + s->mainloop = m; + s->mainloop_source = m->source_io(m, fd, PA_MAINLOOP_API_IO_EVENT_INPUT, callback, s); assert(s->mainloop_source); return s; } -struct socket_server* socket_server_new_unix(struct mainloop *m, const char *filename) { +struct socket_server* socket_server_new_unix(struct pa_mainloop_api *m, const char *filename) { int fd = -1; struct sockaddr_un sa; struct socket_server *s; @@ -101,7 +103,7 @@ fail: return NULL; } -struct socket_server* socket_server_new_ipv4(struct mainloop *m, uint32_t address, uint16_t port) { +struct socket_server* socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port) { int fd = -1; struct sockaddr_in sa; int on = 1; @@ -148,7 +150,8 @@ void socket_server_free(struct socket_server*s) { free(s->filename); } - mainloop_source_free(s->mainloop_source); + + s->mainloop->cancel_io(s->mainloop, s->mainloop_source); free(s); } diff --git a/src/socket-server.h b/src/socket-server.h index 4814fc62..80895f8d 100644 --- a/src/socket-server.h +++ b/src/socket-server.h @@ -2,14 +2,14 @@ #define foosocketserverhfoo #include -#include "mainloop.h" +#include "mainloop-api.h" #include "iochannel.h" struct socket_server; -struct socket_server* socket_server_new(struct mainloop *m, int fd); -struct socket_server* socket_server_new_unix(struct mainloop *m, const char *filename); -struct socket_server* socket_server_new_ipv4(struct mainloop *m, uint32_t address, uint16_t port); +struct socket_server* socket_server_new(struct pa_mainloop_api *m, int fd); +struct socket_server* socket_server_new_unix(struct pa_mainloop_api *m, const char *filename); +struct socket_server* socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port); void socket_server_free(struct socket_server*s); diff --git a/src/source.c b/src/source.c index 44d77532..21ac24f3 100644 --- a/src/source.c +++ b/src/source.c @@ -7,7 +7,7 @@ #include "sourceoutput.h" #include "strbuf.h" -struct source* source_new(struct core *core, const char *name, const struct sample_spec *spec) { +struct source* source_new(struct core *core, const char *name, const struct pa_sample_spec *spec) { struct source *s; int r; assert(core && spec); diff --git a/src/source.h b/src/source.h index 078fb1c9..04f3984f 100644 --- a/src/source.h +++ b/src/source.h @@ -14,14 +14,14 @@ struct source { char *name; struct core *core; - struct sample_spec sample_spec; + struct pa_sample_spec sample_spec; struct idxset *outputs; void (*notify)(struct source*source); void *userdata; }; -struct source* source_new(struct core *core, const char *name, const struct sample_spec *spec); +struct source* source_new(struct core *core, const char *name, const struct pa_sample_spec *spec); void source_free(struct source *s); /* Pass a new memory block to all output streams */ diff --git a/src/sourceoutput.c b/src/sourceoutput.c index 8021b522..e2e1dacc 100644 --- a/src/sourceoutput.c +++ b/src/sourceoutput.c @@ -5,7 +5,7 @@ #include "sourceoutput.h" #include "strbuf.h" -struct source_output* source_output_new(struct source *s, struct sample_spec *spec, const char *name) { +struct source_output* source_output_new(struct source *s, struct pa_sample_spec *spec, const char *name) { struct source_output *o; int r; assert(s && spec); @@ -14,7 +14,7 @@ struct source_output* source_output_new(struct source *s, struct sample_spec *sp assert(o); o->name = name ? strdup(name) : NULL; o->source = s; - o->spec = *spec; + o->sample_spec = *spec; o->push = NULL; o->kill = NULL; diff --git a/src/sourceoutput.h b/src/sourceoutput.h index 359ff151..50cb9caf 100644 --- a/src/sourceoutput.h +++ b/src/sourceoutput.h @@ -12,7 +12,7 @@ struct source_output { char *name; struct source *source; - struct sample_spec spec; + struct pa_sample_spec sample_spec; void (*push)(struct source_output *o, struct memchunk *chunk); void (*kill)(struct source_output* o); @@ -20,7 +20,7 @@ struct source_output { void *userdata; }; -struct source_output* source_output_new(struct source *s, struct sample_spec *spec, const char *name); +struct source_output* source_output_new(struct source *s, struct pa_sample_spec *spec, const char *name); void source_output_free(struct source_output* o); void source_output_kill(struct source_output*o); diff --git a/src/tagstruct.c b/src/tagstruct.c index 429dd408..47e17839 100644 --- a/src/tagstruct.c +++ b/src/tagstruct.c @@ -90,7 +90,7 @@ void tagstruct_putu8(struct tagstruct*t, uint8_t c) { t->length += 2; } -void tagstruct_put_sample_spec(struct tagstruct *t, struct sample_spec *ss) { +void tagstruct_put_sample_spec(struct tagstruct *t, const struct pa_sample_spec *ss) { assert(t && ss); extend(t, 7); t->data[t->length] = TAG_SAMPLE_SPEC; @@ -156,7 +156,7 @@ int tagstruct_getu8(struct tagstruct*t, uint8_t *c) { return 0; } -int tagstruct_get_sample_spec(struct tagstruct *t, struct sample_spec *ss) { +int tagstruct_get_sample_spec(struct tagstruct *t, struct pa_sample_spec *ss) { assert(t && ss); if (t->rindex+7 > t->length) diff --git a/src/tagstruct.h b/src/tagstruct.h index 5572c64c..9f6a0bf4 100644 --- a/src/tagstruct.h +++ b/src/tagstruct.h @@ -15,12 +15,12 @@ uint8_t* tagstruct_free_data(struct tagstruct*t, size_t *l); void tagstruct_puts(struct tagstruct*t, const char *s); void tagstruct_putu32(struct tagstruct*t, uint32_t i); void tagstruct_putu8(struct tagstruct*t, uint8_t c); -void tagstruct_put_sample_spec(struct tagstruct *t, struct sample_spec *ss); +void tagstruct_put_sample_spec(struct tagstruct *t, const struct pa_sample_spec *ss); int tagstruct_gets(struct tagstruct*t, const char **s); int tagstruct_getu32(struct tagstruct*t, uint32_t *i); int tagstruct_getu8(struct tagstruct*t, uint8_t *c); -int tagstruct_get_sample_spec(struct tagstruct *t, struct sample_spec *ss); +int tagstruct_get_sample_spec(struct tagstruct *t, struct pa_sample_spec *ss); int tagstruct_eof(struct tagstruct*t); const uint8_t* tagstruct_data(struct tagstruct*t, size_t *l); diff --git a/src/todo b/src/todo index aeb7ae5f..47344ab4 100644 --- a/src/todo +++ b/src/todo @@ -1,8 +1,10 @@ +- sync() function in native library +- name registrar - native protocol/library - simple control protocol: kill client/input/output; set_volume - resampling - esound protocol -- config parser +- config parser/cmdline - record testing -- 0.1 - optimierung von rebuild_pollfds() diff --git a/src/util.c b/src/util.c new file mode 100644 index 00000000..0383a0ad --- /dev/null +++ b/src/util.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include +#include + +#include "util.h" + +void make_nonblock_fd(int fd) { + int v; + + if ((v = fcntl(fd, F_GETFL)) >= 0) + if (!(v & O_NONBLOCK)) + fcntl(fd, F_SETFL, v|O_NONBLOCK); +} + +void peer_to_string(char *c, size_t l, int fd) { + struct stat st; + + assert(c && l && fd >= 0); + + if (fstat(fd, &st) < 0) { + snprintf(c, l, "Invalid client fd"); + return; + } + + if (S_ISSOCK(st.st_mode)) { + union { + struct sockaddr sa; + struct sockaddr_in in; + struct sockaddr_un un; + } sa; + socklen_t sa_len = sizeof(sa); + + if (getpeername(fd, &sa.sa, &sa_len) >= 0) { + + if (sa.sa.sa_family == AF_INET) { + uint32_t ip = ntohl(sa.in.sin_addr.s_addr); + + snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u", + ip >> 24, + (ip >> 16) & 0xFF, + (ip >> 8) & 0xFF, + ip & 0xFF, + ntohs(sa.in.sin_port)); + return; + } else if (sa.sa.sa_family == AF_LOCAL) { + snprintf(c, l, "UNIX client for %s", sa.un.sun_path); + return; + } + + } + snprintf(c, l, "Unknown network client"); + return; + } else if (S_ISCHR(st.st_mode) && (fd == 0 || fd == 1)) { + snprintf(c, l, "STDIN/STDOUT client"); + return; + } + + snprintf(c, l, "Unknown client"); +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 00000000..830ee2e0 --- /dev/null +++ b/src/util.h @@ -0,0 +1,8 @@ +#ifndef fooutilhfoo +#define fooutilhfoo + +void make_nonblock_fd(int fd); + +void peer_to_string(char *c, size_t l, int fd); + +#endif -- cgit -- cgit From b9e0fa84f3a327ffc395ac184686a78a95c2bb3b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 Jun 2004 23:38:33 +0000 Subject: minor compile work git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@33 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp.c | 3 ++- src/socket-client.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/polyp.c b/src/polyp.c index fdff7f9c..a373841a 100644 --- a/src/polyp.c +++ b/src/polyp.c @@ -15,6 +15,7 @@ #define DEFAULT_MAX_LENGTH 20480 #define DEFAULT_PREBUF 4096 #define DEFAULT_TIMEOUT 5 +#define DEFAULT_SERVER "/tmp/foo" struct pa_context { char *name; @@ -212,7 +213,7 @@ int pa_context_connect(struct pa_context *c, const char *server, void (*complete assert(c && c->state == CONTEXT_UNCONNECTED); assert(!c->client); - if (!(c->client = socket_client_new_unix(c->mainloop, server))) { + if (!(c->client = socket_client_new_unix(c->mainloop, server ? server : DEFAULT_SERVER))) { c->errno = PA_ERROR_CONNECTIONREFUSED; return -1; } diff --git a/src/socket-client.c b/src/socket-client.c index 812c43f3..42859392 100644 --- a/src/socket-client.c +++ b/src/socket-client.c @@ -110,6 +110,7 @@ static int do_connect(struct socket_client *c, const struct sockaddr *sa, sockle struct socket_client* socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port) { struct socket_client *c; struct sockaddr_in sa; + assert(m && address && port); c = socket_client_new(m); assert(c); @@ -136,6 +137,7 @@ fail: struct socket_client* socket_client_new_unix(struct pa_mainloop_api *m, const char *filename) { struct socket_client *c; struct sockaddr_un sa; + assert(m && filename); c = socket_client_new(m); assert(c); -- cgit From c050d7254c13c22baafb71c127e56eb1d5f6ffdb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 Jun 2004 23:40:39 +0000 Subject: rename oss.[ch] to oss-util.[ch] git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@34 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/oss-util.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ src/oss-util.h | 8 ++++++++ src/oss.c | 48 ------------------------------------------------ src/oss.h | 8 -------- 4 files changed, 56 insertions(+), 56 deletions(-) create mode 100644 src/oss-util.c create mode 100644 src/oss-util.h delete mode 100644 src/oss.c delete mode 100644 src/oss.h diff --git a/src/oss-util.c b/src/oss-util.c new file mode 100644 index 00000000..02bf8cd1 --- /dev/null +++ b/src/oss-util.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include + +#include "oss.h" + +int oss_auto_format(int fd, struct pa_sample_spec *ss) { + int format, channels, speed; + + assert(fd >= 0 && ss); + + format = AFMT_S16_NE; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_S16_NE) { + int f = AFMT_S16_NE == AFMT_S16_LE ? AFMT_S16_BE : AFMT_S16_LE; + format = f; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != f) { + format = AFMT_U8; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_U8) { + fprintf(stderr, "SNDCTL_DSP_SETFMT: %s\n", format != AFMT_U8 ? "No supported sample format" : strerror(errno)); + return -1; + } else + ss->format = SAMPLE_U8; + } else + ss->format = f == AFMT_S16_LE ? SAMPLE_S16LE : SAMPLE_S16BE; + } else + ss->format = SAMPLE_S16NE; + + channels = 2; + if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) { + fprintf(stderr, "SNDCTL_DSP_CHANNELS: %s\n", strerror(errno)); + return -1; + } + assert(channels); + ss->channels = channels; + + speed = 44100; + if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) { + fprintf(stderr, "SNDCTL_DSP_SPEED: %s\n", strerror(errno)); + return -1; + } + assert(speed); + ss->rate = speed; + + return 0; +} diff --git a/src/oss-util.h b/src/oss-util.h new file mode 100644 index 00000000..34ac9c66 --- /dev/null +++ b/src/oss-util.h @@ -0,0 +1,8 @@ +#ifndef fooosshfoo +#define fooosshfoo + +#include "sample.h" + +int oss_auto_format(int fd, struct pa_sample_spec *ss); + +#endif diff --git a/src/oss.c b/src/oss.c deleted file mode 100644 index 02bf8cd1..00000000 --- a/src/oss.c +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "oss.h" - -int oss_auto_format(int fd, struct pa_sample_spec *ss) { - int format, channels, speed; - - assert(fd >= 0 && ss); - - format = AFMT_S16_NE; - if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_S16_NE) { - int f = AFMT_S16_NE == AFMT_S16_LE ? AFMT_S16_BE : AFMT_S16_LE; - format = f; - if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != f) { - format = AFMT_U8; - if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_U8) { - fprintf(stderr, "SNDCTL_DSP_SETFMT: %s\n", format != AFMT_U8 ? "No supported sample format" : strerror(errno)); - return -1; - } else - ss->format = SAMPLE_U8; - } else - ss->format = f == AFMT_S16_LE ? SAMPLE_S16LE : SAMPLE_S16BE; - } else - ss->format = SAMPLE_S16NE; - - channels = 2; - if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) { - fprintf(stderr, "SNDCTL_DSP_CHANNELS: %s\n", strerror(errno)); - return -1; - } - assert(channels); - ss->channels = channels; - - speed = 44100; - if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) { - fprintf(stderr, "SNDCTL_DSP_SPEED: %s\n", strerror(errno)); - return -1; - } - assert(speed); - ss->rate = speed; - - return 0; -} diff --git a/src/oss.h b/src/oss.h deleted file mode 100644 index 34ac9c66..00000000 --- a/src/oss.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef fooosshfoo -#define fooosshfoo - -#include "sample.h" - -int oss_auto_format(int fd, struct pa_sample_spec *ss); - -#endif -- cgit From a1b59db7127f328820336837c8f9f215e923dc8d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 Jun 2004 23:43:42 +0000 Subject: make rename of oss.[ch] to oss-util.[ch] complete git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@35 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 12 ++++++------ src/module-oss-mmap.c | 2 +- src/module-oss.c | 2 +- src/oss-util.c | 2 +- src/oss-util.h | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 6ad1488f..c3a33ce3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,12 +23,12 @@ bin_PROGRAMS = polypaudio pacat pkglib_LTLIBRARIES=libiochannel.la libsocket-server.la libsocket-client.la \ libprotocol-simple.la module-simple-protocol-tcp.la \ module-pipe-sink.la libpstream.la \ - libpacket.la module-oss.la module-oss-mmap.la liboss.la libioline.la \ + libpacket.la module-oss.la module-oss-mmap.la liboss-util.la libioline.la \ libcli.la module-cli.la libtokenizer.la libdynarray.la \ module-simple-protocol-unix.la module-cli-protocol-tcp.la \ libprotocol-cli.la module-cli-protocol-unix.la libtagstruct.la \ libpdispatch.la libprotocol-native.la libpstream-util.la \ - module-native-protocol-tcp.la module-native-protocol-unix.la \ + module-native-protocol-tcp.la module-native-protocol-unix.la \ libpolyp.la polypaudio_SOURCES = idxset.c idxset.h \ @@ -86,8 +86,8 @@ libiochannel_la_LDFLAGS = -avoid-version libpacket_la_SOURCES = packet.c packet.h libpacket_la_LDFLAGS = -avoid-version -liboss_la_SOURCES = oss.c oss.h -liboss_la_LDFLAGS = -avoid-version +liboss_util_la_SOURCES = oss-util.c oss-util.h +liboss_util_la_LDFLAGS = -avoid-version libioline_la_SOURCES = ioline.c ioline.h libioline_la_LDFLAGS = -avoid-version @@ -151,11 +151,11 @@ module_pipe_sink_la_LIBADD = libiochannel.la module_oss_la_SOURCES = module-oss.c module_oss_la_LDFLAGS = -module -avoid-version -module_oss_la_LIBADD = libiochannel.la liboss.la +module_oss_la_LIBADD = libiochannel.la liboss-util.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_oss_mmap_la_LIBADD = libiochannel.la liboss-util.la module_cli_la_SOURCES = module-cli.c module_cli_la_LDFLAGS = -module -avoid-version diff --git a/src/module-oss-mmap.c b/src/module-oss-mmap.c index b70ea6bd..f08dd7d3 100644 --- a/src/module-oss-mmap.c +++ b/src/module-oss-mmap.c @@ -15,7 +15,7 @@ #include "sink.h" #include "source.h" #include "module.h" -#include "oss.h" +#include "oss-util.h" #include "sample-util.h" struct userdata { diff --git a/src/module-oss.c b/src/module-oss.c index 4f307545..b5d1427a 100644 --- a/src/module-oss.c +++ b/src/module-oss.c @@ -14,7 +14,7 @@ #include "sink.h" #include "source.h" #include "module.h" -#include "oss.h" +#include "oss-util.h" #include "sample-util.h" struct userdata { diff --git a/src/oss-util.c b/src/oss-util.c index 02bf8cd1..bf6b62e2 100644 --- a/src/oss-util.c +++ b/src/oss-util.c @@ -5,7 +5,7 @@ #include #include -#include "oss.h" +#include "oss-util.h" int oss_auto_format(int fd, struct pa_sample_spec *ss) { int format, channels, speed; diff --git a/src/oss-util.h b/src/oss-util.h index 34ac9c66..5fc08b0b 100644 --- a/src/oss-util.h +++ b/src/oss-util.h @@ -1,5 +1,5 @@ -#ifndef fooosshfoo -#define fooosshfoo +#ifndef fooossutilhfoo +#define fooossutilhfoo #include "sample.h" -- cgit From 1ad4ff1ca446fafb3abe9353a4048893dd3d9b77 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 24 Jun 2004 23:27:06 +0000 Subject: some fixes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@36 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 4 ++-- src/main.c | 7 ++++++- src/module-protocol-stub.c | 5 ++++- src/pdispatch.c | 1 + src/polyp.c | 2 +- src/socket-client.c | 2 +- src/tagstruct.c | 8 ++++---- 7 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index c3a33ce3..75da02c1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -28,7 +28,7 @@ pkglib_LTLIBRARIES=libiochannel.la libsocket-server.la libsocket-client.la \ module-simple-protocol-unix.la module-cli-protocol-tcp.la \ libprotocol-cli.la module-cli-protocol-unix.la libtagstruct.la \ libpdispatch.la libprotocol-native.la libpstream-util.la \ - module-native-protocol-tcp.la module-native-protocol-unix.la \ + module-native-protocol-tcp.la module-native-protocol-unix.la \ libpolyp.la polypaudio_SOURCES = idxset.c idxset.h \ @@ -110,7 +110,7 @@ libprotocol_cli_la_LIBADD = libsocket-server.la libiochannel.la libcli.la libprotocol_native_la_SOURCES = protocol-native.c protocol-native.h libprotocol_native_la_LDFLAGS = -avoid-version -libprotocol_native_la_LIBADD = libsocket-server.la libiochannel.la libpacket.la libpstream.la libpstream-util.la +libprotocol_native_la_LIBADD = libsocket-server.la libiochannel.la libpacket.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct_la_SOURCES = tagstruct.c tagstruct.h libtagstruct_la_LDFLAGS = -avoid-version diff --git a/src/main.c b/src/main.c index ef25b5e3..0fe333e0 100644 --- a/src/main.c +++ b/src/main.c @@ -39,8 +39,13 @@ int main(int argc, char *argv[]) { assert(c); module_load(c, "module-oss-mmap", "/dev/dsp1"); - module_load(c, "module-pipe-sink", NULL); +/* module_load(c, "module-pipe-sink", NULL); module_load(c, "module-simple-protocol-tcp", NULL); + module_load(c, "module-simple-protocol-unix", NULL);*/ + module_load(c, "module-cli-protocol-tcp", NULL); +/* module_load(c, "module-cli-protocol-unix", NULL); + module_load(c, "module-native-protocol-tcp", NULL);*/ + module_load(c, "module-native-protocol-unix", NULL); module_load(c, "module-cli", NULL); fprintf(stderr, "main: mainloop entry.\n"); diff --git a/src/module-protocol-stub.c b/src/module-protocol-stub.c index 2387017c..97bf5ef3 100644 --- a/src/module-protocol-stub.c +++ b/src/module-protocol-stub.c @@ -8,18 +8,21 @@ #include "protocol-simple.h" #define protocol_free protocol_simple_free #define IPV4_PORT 4711 + #define UNIX_SOCKET "/tmp/polypaudio_simple" #else #ifdef USE_PROTOCOL_CLI #include "protocol-cli.h" #define protocol_new protocol_cli_new #define protocol_free protocol_cli_free #define IPV4_PORT 4712 + #define UNIX_SOCKET "/tmp/polypaudio_cli" #else #ifdef USE_PROTOCOL_NATIVE #include "protocol-native.h" #define protocol_new protocol_native_new #define protocol_free protocol_native_free #define IPV4_PORT 4713 + #define UNIX_SOCKET "/tmp/polypaudio_native" #else #error "Broken build system" #endif @@ -34,7 +37,7 @@ int module_init(struct core *c, struct module*m) { if (!(s = socket_server_new_ipv4(c->mainloop, INADDR_LOOPBACK, IPV4_PORT))) return -1; #else - if (!(s = socket_server_new_unix(c->mainloop, "/tmp/polypsimple"))) + if (!(s = socket_server_new_unix(c->mainloop, UNIX_SOCKET))) return -1; #endif diff --git a/src/pdispatch.c b/src/pdispatch.c index 48b6639d..15f4b1b5 100644 --- a/src/pdispatch.c +++ b/src/pdispatch.c @@ -46,6 +46,7 @@ struct pdispatch* pdispatch_new(struct pa_mainloop_api *mainloop, const struct p pd->mainloop = mainloop; pd->command_table = table; pd->n_commands = entries; + pd->replies = NULL; return pd; } diff --git a/src/polyp.c b/src/polyp.c index a373841a..69b85c21 100644 --- a/src/polyp.c +++ b/src/polyp.c @@ -15,7 +15,7 @@ #define DEFAULT_MAX_LENGTH 20480 #define DEFAULT_PREBUF 4096 #define DEFAULT_TIMEOUT 5 -#define DEFAULT_SERVER "/tmp/foo" +#define DEFAULT_SERVER "/tmp/polypaudio_native" struct pa_context { char *name; diff --git a/src/socket-client.c b/src/socket-client.c index 42859392..b10f8ab1 100644 --- a/src/socket-client.c +++ b/src/socket-client.c @@ -101,7 +101,7 @@ static int do_connect(struct socket_client *c, const struct sockaddr *sa, sockle assert(c->io_source); } else { c->fixed_source = c->mainloop->source_fixed(c->mainloop, connect_fixed_cb, c); - assert(c->io_source); + assert(c->fixed_source); } return 0; diff --git a/src/tagstruct.c b/src/tagstruct.c index 47e17839..407440d3 100644 --- a/src/tagstruct.c +++ b/src/tagstruct.c @@ -34,7 +34,7 @@ struct tagstruct *tagstruct_new(const uint8_t* data, size_t length) { t->data = (uint8_t*) data; t->allocated = t->length = data ? length : 0; t->rindex = 0; - t->dynamic = !!data; + t->dynamic = !data; return t; } @@ -57,7 +57,7 @@ uint8_t* tagstruct_free_data(struct tagstruct*t, size_t *l) { static void extend(struct tagstruct*t, size_t l) { assert(t && t->dynamic); - if (t->allocated <= l) + if (l <= t->allocated) return; t->data = realloc(t->data, t->allocated = l+100); @@ -75,7 +75,7 @@ void tagstruct_puts(struct tagstruct*t, const char *s) { } void tagstruct_putu32(struct tagstruct*t, uint32_t i) { - assert(t && i); + assert(t); extend(t, 5); t->data[t->length] = TAG_U32; *((uint32_t*) (t->data+t->length+1)) = htonl(i); @@ -83,7 +83,7 @@ void tagstruct_putu32(struct tagstruct*t, uint32_t i) { } void tagstruct_putu8(struct tagstruct*t, uint8_t c) { - assert(t && c); + assert(t); extend(t, 2); t->data[t->length] = TAG_U8; *(t->data+t->length+1) = c; -- cgit From 57dc42709fa258844db05f2042dfffe6ca8ade8b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 27 Jun 2004 17:50:02 +0000 Subject: many fixes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@37 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/mainloop.c | 12 ++++++++---- src/pacat.c | 32 ++++++++++++++++++++------------ src/pdispatch.c | 5 +++-- src/polyp.c | 16 ++++++++++++---- src/protocol-native.c | 24 +++++++++++++++++++++--- src/pstream.c | 10 +++++----- src/tagstruct.c | 4 ++-- 7 files changed, 71 insertions(+), 32 deletions(-) diff --git a/src/mainloop.c b/src/mainloop.c index a1758c65..8629add2 100644 --- a/src/mainloop.c +++ b/src/mainloop.c @@ -162,11 +162,14 @@ static void dispatch_pollfds(struct pa_mainloop *m) { struct mainloop_source_io *s; for (s = idxset_first(m->io_sources, &index); s; s = idxset_next(m->io_sources, &index)) { - if (s->header.dead || !s->events || !s->pollfd || !s->pollfd->revents) + if (s->header.dead || !s->pollfd || !s->pollfd->revents) continue; - assert(s->pollfd->revents <= s->pollfd->events && s->pollfd->fd == s->fd && s->callback); - s->callback(&m->api, s, s->fd, ((s->pollfd->revents & POLLIN) ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | ((s->pollfd->revents & POLLOUT) ? PA_MAINLOOP_API_IO_EVENT_OUTPUT : 0), s->userdata); + assert(s->pollfd->fd == s->fd && s->callback); + s->callback(&m->api, s, s->fd, + ((s->pollfd->revents & (POLLIN|POLLHUP|POLLERR)) ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | + ((s->pollfd->revents & POLLOUT) ? PA_MAINLOOP_API_IO_EVENT_OUTPUT : 0), s->userdata); + s->pollfd->revents = 0; } } @@ -212,7 +215,7 @@ static int calc_next_timeout(struct pa_mainloop *m) { if (tmp == 0) return 0; - else if (tmp < t) + else if (t == -1 || tmp < t) t = tmp; } @@ -357,6 +360,7 @@ static void mainloop_cancel_io(struct pa_mainloop_api*a, void* id) { s->header.dead = 1; m->io_sources_scan_dead = 1; + m->rebuild_pollfds = 1; } /* Fixed sources */ diff --git a/src/pacat.c b/src/pacat.c index 5f5a373b..5ee1b866 100644 --- a/src/pacat.c +++ b/src/pacat.c @@ -29,22 +29,15 @@ static void stream_die_callback(struct pa_stream *s, void *userdata) { mainloop_api->quit(mainloop_api, 1); } -static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) { +static void do_write(size_t length) { size_t l; - assert(s && length); - - mainloop_api->enable_io(mainloop_api, stdin_source, PA_STREAM_PLAYBACK); - - if (!buffer) - return; - - assert(buffer_length); + assert(buffer && buffer_length); l = length; if (l > buffer_length) l = buffer_length; - pa_stream_write(s, buffer+buffer_index, l); + pa_stream_write(stream, buffer+buffer_index, l); buffer_length -= l; buffer_index += l; @@ -55,12 +48,24 @@ static void stream_write_callback(struct pa_stream *s, size_t length, void *user } } +static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) { + assert(s && length); + + mainloop_api->enable_io(mainloop_api, stdin_source, PA_MAINLOOP_API_IO_EVENT_INPUT); + + if (!buffer) + return; + + do_write(length); +} + static void stream_complete_callback(struct pa_context*c, struct pa_stream *s, void *userdata) { assert(c); if (!s) { fprintf(stderr, "Stream creation failed.\n"); mainloop_api->quit(mainloop_api, 1); + return; } stream = s; @@ -94,7 +99,7 @@ fail: } static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { - size_t l; + size_t l, w = 0; ssize_t r; assert(a == mainloop_api && id && fd == STDIN_FILENO && events == PA_MAINLOOP_API_IO_EVENT_INPUT); @@ -103,7 +108,7 @@ static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_m return; } - if (!(l = pa_stream_writable_size(stream))) + if (!stream || !(l = w = pa_stream_writable_size(stream))) l = 4096; buffer = malloc(l); assert(buffer); @@ -120,6 +125,9 @@ static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_m buffer_length = r; buffer_index = 0; + + if (w) + do_write(w); } int main(int argc, char *argv[]) { diff --git a/src/pdispatch.c b/src/pdispatch.c index 15f4b1b5..65dcd747 100644 --- a/src/pdispatch.c +++ b/src/pdispatch.c @@ -22,7 +22,9 @@ struct pdispatch { static void reply_info_free(struct reply_info *r) { assert(r && r->pdispatch && r->pdispatch->mainloop); - r->pdispatch->mainloop->cancel_time(r->pdispatch->mainloop, r->mainloop_timeout); + + if (r->pdispatch) + r->pdispatch->mainloop->cancel_time(r->pdispatch->mainloop, r->mainloop_timeout); if (r->previous) r->previous->next = r->next; @@ -112,7 +114,6 @@ fail: if (ts) tagstruct_free(ts); - fprintf(stderr, "protocol-native: invalid packet.\n"); return -1; } diff --git a/src/polyp.c b/src/polyp.c index 69b85c21..c298d46d 100644 --- a/src/polyp.c +++ b/src/polyp.c @@ -14,7 +14,7 @@ #define DEFAULT_QUEUE_LENGTH 10240 #define DEFAULT_MAX_LENGTH 20480 #define DEFAULT_PREBUF 4096 -#define DEFAULT_TIMEOUT 5 +#define DEFAULT_TIMEOUT (5*60) #define DEFAULT_SERVER "/tmp/polypaudio_native" struct pa_context { @@ -39,6 +39,7 @@ struct pa_context { struct pa_stream { struct pa_context *context; struct pa_stream *next, *previous; + uint32_t device_index; uint32_t channel; int channel_valid; enum pa_stream_direction direction; @@ -252,11 +253,11 @@ static int command_request(struct pdispatch *pd, uint32_t command, uint32_t tag, struct pa_stream *s; struct pa_context *c = userdata; uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && s); + assert(pd && command == PA_COMMAND_REQUEST && t && c); if (tagstruct_getu32(t, &channel) < 0 || tagstruct_getu32(t, &bytes) < 0 || - tagstruct_eof(t)) { + !tagstruct_eof(t)) { c->errno = PA_ERROR_PROTOCOL; return -1; } @@ -266,6 +267,8 @@ static int command_request(struct pdispatch *pd, uint32_t command, uint32_t tag, return -1; } + fprintf(stderr, "Requested %u bytes\n", bytes); + s->requested_bytes += bytes; if (s->requested_bytes && s->write_callback) @@ -295,7 +298,8 @@ static int create_playback_callback(struct pdispatch *pd, uint32_t command, uint } if (tagstruct_getu32(t, &s->channel) < 0 || - tagstruct_eof(t)) { + tagstruct_getu32(t, &s->device_index) < 0 || + !tagstruct_eof(t)) { s->context->errno = PA_ERROR_PROTOCOL; ret = -1; goto fail; @@ -349,6 +353,7 @@ int pa_stream_new( s->requested_bytes = 0; s->channel = 0; s->channel_valid = 0; + s->device_index = (uint32_t) -1; s->direction = dir; t = tagstruct_new(NULL, 0); @@ -419,7 +424,10 @@ void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { chunk.length = length; pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); + memblock_unref(chunk.memblock); + fprintf(stderr, "Sent %u bytes\n", length); + if (length < s->requested_bytes) s->requested_bytes -= length; else diff --git a/src/protocol-native.c b/src/protocol-native.c index a39880b8..b8a461ae 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -29,6 +29,7 @@ struct playback_stream { size_t qlength; struct sink_input *sink_input; struct memblockq *memblockq; + size_t requested_bytes; }; struct connection { @@ -81,7 +82,7 @@ static void record_stream_free(struct record_stream* r) { static struct playback_stream* playback_stream_new(struct connection *c, struct sink *sink, struct pa_sample_spec *ss, const char *name, size_t qlen, size_t maxlength, size_t prebuf) { struct playback_stream *s; - assert(c && sink && s && name && qlen && maxlength && prebuf); + assert(c && sink && ss && name && qlen && maxlength && prebuf); s = malloc(sizeof(struct playback_stream)); assert (s); @@ -99,8 +100,9 @@ static struct playback_stream* playback_stream_new(struct connection *c, struct s->memblockq = memblockq_new(maxlength, pa_sample_size(ss), prebuf); assert(s->memblockq); + s->requested_bytes = 0; + idxset_put(c->playback_streams, s, &s->index); - request_bytes(s); return s; } @@ -141,12 +143,21 @@ static void request_bytes(struct playback_stream *s) { if (!(l = memblockq_missing_to(s->memblockq, s->qlength))) return; + if (l <= s->requested_bytes) + return; + + l -= s->requested_bytes; + s->requested_bytes += l; + t = tagstruct_new(NULL, 0); assert(t); tagstruct_putu32(t, PA_COMMAND_REQUEST); + tagstruct_putu32(t, (uint32_t) -1); /* tag */ tagstruct_putu32(t, s->index); tagstruct_putu32(t, l); pstream_send_tagstruct(s->connection->pstream, t); + + fprintf(stderr, "Requesting %u bytes\n", l); } /*** sinkinput callbacks ***/ @@ -237,6 +248,7 @@ static int command_create_playback_stream(struct pdispatch *pd, uint32_t command assert(s->sink_input); tagstruct_putu32(reply, s->sink_input->index); pstream_send_tagstruct(c->pstream, reply); + request_bytes(s); return 0; } @@ -284,7 +296,6 @@ static int command_exit(struct pdispatch *pd, uint32_t command, uint32_t tag, st /*** pstream callbacks ***/ - static int packet_callback(struct pstream *p, struct packet *packet, void *userdata) { struct connection *c = userdata; assert(p && packet && packet->data && c); @@ -307,10 +318,17 @@ static int memblock_callback(struct pstream *p, uint32_t channel, int32_t delta, return -1; } + if (chunk->length >= stream->requested_bytes) + stream->requested_bytes = 0; + else + stream->requested_bytes -= chunk->length; + memblockq_push(stream->memblockq, chunk, delta); assert(stream->sink_input); sink_notify(stream->sink_input->sink); + fprintf(stderr, "Recieved %u bytes.\n", chunk->length); + return 0; } diff --git a/src/pstream.c b/src/pstream.c index 4a3a648b..e3f59816 100644 --- a/src/pstream.c +++ b/src/pstream.c @@ -131,11 +131,11 @@ static void item_free(void *item, void *p) { struct item_info *i = item; assert(i); - if (i->type == PSTREAM_ITEM_PACKET) { + if (i->type == PSTREAM_ITEM_MEMBLOCK) { assert(i->chunk.memblock); memblock_unref(i->chunk.memblock); } else { - assert(i->type == PSTREAM_ITEM_MEMBLOCK); + assert(i->type == PSTREAM_ITEM_PACKET); assert(i->packet); packet_unref(i->packet); } @@ -184,7 +184,7 @@ void pstream_send_packet(struct pstream*p, struct packet *packet) { void pstream_send_memblock(struct pstream*p, uint32_t channel, int32_t delta, struct memchunk *chunk) { struct item_info *i; - assert(p && channel && chunk); + assert(p && channel != (uint32_t) -1 && chunk); i = malloc(sizeof(struct item_info)); assert(i); @@ -258,7 +258,7 @@ static void do_write(struct pstream *p) { l = PSTREAM_DESCRIPTOR_SIZE - p->write.index; } else { d = (void*) p->write.data + p->write.index - PSTREAM_DESCRIPTOR_SIZE; - l = ntohl(p->write.descriptor[PSTREAM_DESCRIPTOR_LENGTH]) - p->write.index - PSTREAM_DESCRIPTOR_SIZE; + l = ntohl(p->write.descriptor[PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PSTREAM_DESCRIPTOR_SIZE); } if ((r = iochannel_write(p->io, d, l)) < 0) @@ -298,7 +298,7 @@ static void do_read(struct pstream *p) { } else { assert(p->read.data); d = (void*) p->read.data + p->read.index - PSTREAM_DESCRIPTOR_SIZE; - l = ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH]) - p->read.index - PSTREAM_DESCRIPTOR_SIZE; + l = ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH]) - (p->read.index - PSTREAM_DESCRIPTOR_SIZE); } if ((r = iochannel_read(p->io, d, l)) <= 0) diff --git a/src/tagstruct.c b/src/tagstruct.c index 407440d3..e6d6b2b2 100644 --- a/src/tagstruct.c +++ b/src/tagstruct.c @@ -113,7 +113,7 @@ int tagstruct_gets(struct tagstruct*t, const char **s) { return -1; error = 1; - for (n = 0, c = (char*) (t->data+t->rindex+1); n < t->length-t->rindex-1; c++) + for (n = 0, c = (char*) (t->data+t->rindex+1); t->rindex+1+n < t->length; n++, c++) if (!*c) { error = 0; break; @@ -124,7 +124,7 @@ int tagstruct_gets(struct tagstruct*t, const char **s) { *s = (char*) (t->data+t->rindex+1); - t->rindex += n+1; + t->rindex += n+2; return 0; } -- cgit From 010378643e89e2ca4ea3502cb7dc6d8e16480832 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 27 Jun 2004 20:00:26 +0000 Subject: make native playback work git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@38 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/iochannel.c | 2 +- src/ioline.c | 29 +++++++++++++++++------------ src/polyp.c | 4 ++-- src/protocol-native.c | 4 ++-- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/iochannel.c b/src/iochannel.c index 910b7e0b..fa55875f 100644 --- a/src/iochannel.c +++ b/src/iochannel.c @@ -116,7 +116,7 @@ void iochannel_free(struct iochannel*io) { if (io->input_source) io->mainloop->cancel_io(io->mainloop, io->input_source); - if (io->output_source && io->output_source != io->input_source) + if (io->output_source && (io->output_source != io->input_source)) io->mainloop->cancel_io(io->mainloop, io->output_source); free(io); diff --git a/src/ioline.c b/src/ioline.c index c37737a6..ada9cee0 100644 --- a/src/ioline.c +++ b/src/ioline.c @@ -98,7 +98,7 @@ void ioline_set_callback(struct ioline*l, void (*callback)(struct ioline*io, con static int do_read(struct ioline *l) { ssize_t r; size_t m, len; - char *p, *e; + char *e; assert(l); if (!iochannel_is_readable(l->io)) @@ -135,21 +135,26 @@ static int do_read(struct ioline *l) { 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) + if (!e &&l->rbuf_valid_length >= BUFFER_LIMIT) e = l->rbuf+BUFFER_LIMIT-1; + + if (e) { + char *p; - *e = 0; - p = l->rbuf+l->rbuf_index; - m = strlen(p); + *e = 0; + + p = l->rbuf+l->rbuf_index; + m = strlen(p); - if (l->callback) - l->callback(l, p, l->userdata); + if (l->callback) + l->callback(l, p, l->userdata); - l->rbuf_index += m+1; - l->rbuf_valid_length -= m+1; + l->rbuf_index += m+1; + l->rbuf_valid_length -= m+1; - if (l->rbuf_valid_length == 0) - l->rbuf_index = 0; + if (l->rbuf_valid_length == 0) + l->rbuf_index = 0; + } return 0; } @@ -184,7 +189,7 @@ static void io_callback(struct iochannel*io, void *userdata) { return; fail: + l->dead = 1; if (l->callback) l->callback(l, NULL, l->userdata); - l->dead = 1; } diff --git a/src/polyp.c b/src/polyp.c index c298d46d..c2d1d822 100644 --- a/src/polyp.c +++ b/src/polyp.c @@ -267,7 +267,7 @@ static int command_request(struct pdispatch *pd, uint32_t command, uint32_t tag, return -1; } - fprintf(stderr, "Requested %u bytes\n", bytes); + /*fprintf(stderr, "Requested %u bytes\n", bytes);*/ s->requested_bytes += bytes; @@ -426,7 +426,7 @@ void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); memblock_unref(chunk.memblock); - fprintf(stderr, "Sent %u bytes\n", length); + /*fprintf(stderr, "Sent %u bytes\n", length);*/ if (length < s->requested_bytes) s->requested_bytes -= length; diff --git a/src/protocol-native.c b/src/protocol-native.c index b8a461ae..27b547a6 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -157,7 +157,7 @@ static void request_bytes(struct playback_stream *s) { tagstruct_putu32(t, l); pstream_send_tagstruct(s->connection->pstream, t); - fprintf(stderr, "Requesting %u bytes\n", l); +/* fprintf(stderr, "Requesting %u bytes\n", l);*/ } /*** sinkinput callbacks ***/ @@ -327,7 +327,7 @@ static int memblock_callback(struct pstream *p, uint32_t channel, int32_t delta, assert(stream->sink_input); sink_notify(stream->sink_input->sink); - fprintf(stderr, "Recieved %u bytes.\n", chunk->length); + /*fprintf(stderr, "Recieved %u bytes.\n", chunk->length);*/ return 0; } -- cgit From a74cd2a1bd92eac6a4140d0794ac4b557be6c133 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 27 Jun 2004 22:42:17 +0000 Subject: add name registrar git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@39 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 5 +- src/core.c | 4 ++ src/core.h | 3 + src/hashset.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++ src/hashset.h | 16 ++++++ src/idxset.c | 28 +++++++--- src/idxset.h | 8 ++- src/module-oss-mmap.c | 4 +- src/module-oss.c | 4 +- src/module-pipe-sink.c | 2 +- src/namereg.c | 97 +++++++++++++++++++++++++++++++++ src/namereg.h | 17 ++++++ src/sink.c | 15 ++++- src/sink.h | 2 +- src/source.c | 12 +++- src/source.h | 2 +- src/todo | 16 ++++-- 17 files changed, 354 insertions(+), 26 deletions(-) create mode 100644 src/hashset.c create mode 100644 src/hashset.h create mode 100644 src/namereg.c create mode 100644 src/namereg.h diff --git a/src/Makefile.am b/src/Makefile.am index 75da02c1..a67f395e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -49,7 +49,10 @@ polypaudio_SOURCES = idxset.c idxset.h \ module.c module.h \ mainloop-signal.c mainloop-signal.h \ mainloop-api.c mainloop-api.h \ - util.c util.h + util.c util.h \ + hashset.c hashset.h \ + namereg.c namereg.h + polypaudio_CFLAGS = $(AM_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) diff --git a/src/core.c b/src/core.c index d9df38e1..ec38da91 100644 --- a/src/core.c +++ b/src/core.c @@ -6,6 +6,7 @@ #include "module.h" #include "sink.h" #include "source.h" +#include "namereg.h" struct core* core_new(struct pa_mainloop_api *m) { struct core* c; @@ -22,6 +23,7 @@ struct core* core_new(struct pa_mainloop_api *m) { c->default_source_index = c->default_sink_index = IDXSET_INVALID; c->modules = NULL; + c->namereg = NULL; return c; }; @@ -47,6 +49,8 @@ void core_free(struct core *c) { assert(idxset_isempty(c->sink_inputs)); idxset_free(c->sink_inputs, NULL, NULL); + namereg_free(c); + free(c); }; diff --git a/src/core.h b/src/core.h index 8c4c6233..289bec85 100644 --- a/src/core.h +++ b/src/core.h @@ -2,6 +2,7 @@ #define foocorehfoo #include "idxset.h" +#include "hashset.h" #include "mainloop-api.h" struct core { @@ -9,6 +10,8 @@ struct core { struct idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules; + struct hashset *namereg; + uint32_t default_source_index, default_sink_index; }; diff --git a/src/hashset.c b/src/hashset.c new file mode 100644 index 00000000..298650d5 --- /dev/null +++ b/src/hashset.c @@ -0,0 +1,145 @@ +#include +#include +#include + +#include "hashset.h" +#include "idxset.h" + +struct hashset_entry { + struct hashset_entry *next, *previous, *bucket_next, *bucket_previous; + unsigned hash; + const void *key; + void *value; +}; + +struct hashset { + unsigned size; + struct hashset_entry **data; + struct hashset_entry *first_entry; + + unsigned n_entries; + unsigned (*hash_func) (const void *p); + int (*compare_func) (const void*a, const void*b); +}; + +struct hashset *hashset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { + struct hashset *h; + h = malloc(sizeof(struct hashset)); + assert(h); + h->data = malloc(sizeof(struct hashset_entry*)*(h->size = 1023)); + assert(h->data); + memset(h->data, 0, sizeof(struct hashset_entry*)*(h->size = 1023)); + h->first_entry = NULL; + h->n_entries = 0; + h->hash_func = hash_func ? hash_func : idxset_trivial_hash_func; + h->compare_func = compare_func ? compare_func : idxset_trivial_compare_func; + return h; +} + +static void remove(struct hashset *h, struct hashset_entry *e) { + assert(e); + + if (e->next) + e->next->previous = e->previous; + if (e->previous) + e->previous->next = e->next; + else + h->first_entry = e->next; + + if (e->bucket_next) + e->bucket_next->bucket_previous = e->bucket_previous; + if (e->bucket_previous) + e->bucket_previous->bucket_next = e->bucket_next; + else + h->data[e->hash] = e->bucket_next; + + free(e); + h->n_entries--; +} + +void hashset_free(struct hashset*h, void (*free_func)(void *p, void *userdata), void *userdata) { + assert(h); + + while (h->first_entry) { + if (free_func) + free_func(h->first_entry->value, userdata); + remove(h, h->first_entry); + } + + free(h->data); + free(h); +} + +static struct hashset_entry *get(struct hashset *h, unsigned hash, const void *key) { + struct hashset_entry *e; + + for (e = h->data[hash]; e; e = e->bucket_next) + if (h->compare_func(e->key, key) == 0) + return e; + + return NULL; +} + +int hashset_put(struct hashset *h, const void *key, void *value) { + struct hashset_entry *e; + unsigned hash; + assert(h && key); + + hash = h->hash_func(key) % h->size; + + if ((e = get(h, hash, key))) + return -1; + + e = malloc(sizeof(struct hashset_entry)); + assert(e); + + e->hash = hash; + e->key = key; + e->value = value; + + e->previous = NULL; + e->next = h->first_entry; + if (h->first_entry) + h->first_entry->previous = e; + h->first_entry = e; + + e->bucket_previous = NULL; + e->bucket_next = h->data[hash]; + if (h->data[hash]) + h->data[hash]->bucket_previous = e; + h->data[hash] = e; + + h->n_entries ++; + return 0; +} + +void* hashset_get(struct hashset *h, const void *key) { + unsigned hash; + struct hashset_entry *e; + assert(h && key); + + hash = h->hash_func(key) % h->size; + + if (!(e = get(h, hash, key))) + return NULL; + + return e->value; +} + +int hashset_remove(struct hashset *h, const void *key) { + struct hashset_entry *e; + unsigned hash; + assert(h && key); + + hash = h->hash_func(key) % h->size; + + if (!(e = get(h, hash, key))) + return 1; + + remove(h, e); + return 0; +} + +unsigned hashset_ncontents(struct hashset *h) { + return h->n_entries; +} diff --git a/src/hashset.h b/src/hashset.h new file mode 100644 index 00000000..7e035c02 --- /dev/null +++ b/src/hashset.h @@ -0,0 +1,16 @@ +#ifndef foohashsethfoo +#define foohashsethfoo + +struct hashset; + +struct hashset *hashset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); +void hashset_free(struct hashset*, void (*free_func)(void *p, void *userdata), void *userdata); + +int hashset_put(struct hashset *h, const void *key, void *value); +void* hashset_get(struct hashset *h, const void *key); + +int hashset_remove(struct hashset *h, const void *key); + +unsigned hashset_ncontents(struct hashset *h); + +#endif diff --git a/src/idxset.c b/src/idxset.c index ea609f60..090bfc72 100644 --- a/src/idxset.c +++ b/src/idxset.c @@ -15,29 +15,43 @@ struct idxset_entry { }; struct idxset { - unsigned (*hash_func) (void *p); - int (*compare_func)(void *a, void *b); + unsigned (*hash_func) (const void *p); + int (*compare_func)(const void *a, const void *b); unsigned hash_table_size, n_entries; struct idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail; uint32_t index, start_index, array_size; }; -static unsigned trivial_hash_func(void *p) { +unsigned idxset_string_hash_func(const void *p) { + unsigned hash = 0; + const char *c; + + for (c = p; *c; c++) + hash = 31 * hash + *c; + + return hash; +} + +int idxset_string_compare_func(const void *a, const void *b) { + return strcmp(a, b); +} + +unsigned idxset_trivial_hash_func(const void *p) { return (unsigned) p; } -static int trivial_compare_func(void *a, void *b) { +int idxset_trivial_compare_func(const void *a, const void *b) { return a != b; } -struct idxset* idxset_new(unsigned (*hash_func) (void *p), int (*compare_func) (void*a, void*b)) { +struct idxset* idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { struct idxset *s; s = malloc(sizeof(struct idxset)); assert(s); - s->hash_func = hash_func ? hash_func : trivial_hash_func; - s->compare_func = compare_func ? compare_func : trivial_compare_func; + s->hash_func = hash_func ? hash_func : idxset_trivial_hash_func; + s->compare_func = compare_func ? compare_func : idxset_trivial_compare_func; s->hash_table_size = 1023; s->hash_table = malloc(sizeof(struct idxset_entry*)*s->hash_table_size); assert(s->hash_table); diff --git a/src/idxset.h b/src/idxset.h index 90b9d247..61503977 100644 --- a/src/idxset.h +++ b/src/idxset.h @@ -5,9 +5,15 @@ #define IDXSET_INVALID ((uint32_t) -1) +unsigned idxset_trivial_hash_func(const void *p); +int idxset_trivial_compare_func(const void *a, const void *b); + +unsigned idxset_string_hash_func(const void *p); +int idxset_string_compare_func(const void *a, const void *b); + struct idxset; -struct idxset* idxset_new(unsigned (*hash_func) (void *p), int (*compare_func) (void*a, void*b)); +struct idxset* idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); void idxset_free(struct idxset *s, void (*free_func) (void *p, void *userdata), void *userdata); int idxset_put(struct idxset*s, void *p, uint32_t *index); diff --git a/src/module-oss-mmap.c b/src/module-oss-mmap.c index f08dd7d3..3997c490 100644 --- a/src/module-oss-mmap.c +++ b/src/module-oss-mmap.c @@ -262,7 +262,7 @@ int module_init(struct core *c, struct module*m) { } } else { - u->source = source_new(c, "dsp", &u->sample_spec); + u->source = source_new(c, "dsp", 0, &u->sample_spec); assert(u->source); u->source->userdata = u; @@ -293,7 +293,7 @@ int module_init(struct core *c, struct module*m) { } else { silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec); - u->sink = sink_new(c, "dsp", &u->sample_spec); + u->sink = sink_new(c, "dsp", 0, &u->sample_spec); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; u->sink->userdata = u; diff --git a/src/module-oss.c b/src/module-oss.c index b5d1427a..75082a7f 100644 --- a/src/module-oss.c +++ b/src/module-oss.c @@ -180,7 +180,7 @@ int module_init(struct core *c, struct module*m) { u->core = c; if (mode != O_RDONLY) { - u->sink = sink_new(c, "dsp", &ss); + u->sink = sink_new(c, "dsp", 0, &ss); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; u->sink->userdata = u; @@ -188,7 +188,7 @@ int module_init(struct core *c, struct module*m) { u->sink = NULL; if (mode != O_WRONLY) { - u->source = source_new(c, "dsp", &ss); + u->source = source_new(c, "dsp", 0, &ss); assert(u->source); u->source->userdata = u; } else diff --git a/src/module-pipe-sink.c b/src/module-pipe-sink.c index 9dcf5d23..6cc4de88 100644 --- a/src/module-pipe-sink.c +++ b/src/module-pipe-sink.c @@ -109,7 +109,7 @@ int module_init(struct core *c, struct module*m) { u->filename = strdup(p); assert(u->filename); u->core = c; - u->sink = sink_new(c, "fifo", &ss); + u->sink = sink_new(c, "fifo", 0, &ss); assert(u->sink); u->sink->notify = notify_cb; u->sink->userdata = u; diff --git a/src/namereg.c b/src/namereg.c new file mode 100644 index 00000000..b286171d --- /dev/null +++ b/src/namereg.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include + +#include "namereg.h" + +struct namereg_entry { + enum namereg_type type; + char *name; + void *data; +}; + +void namereg_free(struct core *c) { + assert(c); + if (!c->namereg) + return; + assert(hashset_ncontents(c->namereg) == 0); + hashset_free(c->namereg, NULL, NULL); +} + +const char *namereg_register(struct core *c, const char *name, enum namereg_type type, void *data, int fail) { + struct namereg_entry *e; + char *n = NULL; + int r; + + assert(c && name && data); + + if (!c->namereg) { + c->namereg = hashset_new(idxset_string_hash_func, idxset_string_compare_func); + assert(c->namereg); + } + + if ((e = hashset_get(c->namereg, name)) && fail) + return NULL; + + if (!e) + n = strdup(name); + else { + unsigned i; + size_t l = strlen(name); + n = malloc(l+3); + assert(n); + + for (i = 1; i <= 99; i++) { + snprintf(n, l+2, "%s%u", name, i); + + if (!(e = hashset_get(c->namereg, n))) + break; + } + + if (e) { + free(n); + return NULL; + } + } + + assert(n); + e = malloc(sizeof(struct namereg_entry)); + assert(e); + e->type = type; + e->name = n; + e->data = data; + + r = hashset_put(c->namereg, e->name, e); + assert (r >= 0); + + return e->name; + +} + +void namereg_unregister(struct core *c, const char *name) { + struct namereg_entry *e; + int r; + assert(c && name); + + e = hashset_get(c->namereg, name); + assert(e); + + r = hashset_remove(c->namereg, name); + assert(r >= 0); + + free(e->name); + free(e); +} + +void* namereg_get(struct core *c, const char *name, enum namereg_type type) { + struct namereg_entry *e; + assert(c && name); + + if (!(e = hashset_get(c->namereg, name))) + if (e->type == e->type) + return e->data; + + return NULL; +} diff --git a/src/namereg.h b/src/namereg.h new file mode 100644 index 00000000..5632143b --- /dev/null +++ b/src/namereg.h @@ -0,0 +1,17 @@ +#ifndef foonamereghfoo +#define foonamereghfoo + +#include "core.h" + +enum namereg_type { + NAMEREG_SINK, + NAMEREG_SOURCE +}; + +void namereg_free(struct core *c); + +const char *namereg_register(struct core *c, const char *name, enum namereg_type type, void *data, int fail); +void namereg_unregister(struct core *c, const char *name); +void* namereg_get(struct core *c, const char *name, enum namereg_type type); + +#endif diff --git a/src/sink.c b/src/sink.c index a334424c..5ab1a7a7 100644 --- a/src/sink.c +++ b/src/sink.c @@ -7,10 +7,11 @@ #include "sinkinput.h" #include "strbuf.h" #include "sample-util.h" +#include "namereg.h" #define MAX_MIX_CHANNELS 32 -struct sink* sink_new(struct core *core, const char *name, const struct pa_sample_spec *spec) { +struct sink* sink_new(struct core *core, const char *name, int fail, const struct pa_sample_spec *spec) { struct sink *s; char *n = NULL; int r; @@ -18,8 +19,13 @@ struct sink* sink_new(struct core *core, const char *name, const struct pa_sampl s = malloc(sizeof(struct sink)); assert(s); + + if (!(name = namereg_register(core, name, NAMEREG_SINK, s, fail))) { + free(s); + return NULL; + } - s->name = name ? strdup(name) : NULL; + s->name = strdup(name); s->core = core; s->sample_spec = *spec; s->inputs = idxset_new(NULL, NULL); @@ -29,7 +35,8 @@ struct sink* sink_new(struct core *core, const char *name, const struct pa_sampl sprintf(n, "%s_monitor", name); } - s->monitor_source = source_new(core, n, spec); + s->monitor_source = source_new(core, n, 0, spec); + assert(s->monitor_source); free(n); s->volume = 0xFF; @@ -50,6 +57,8 @@ void sink_free(struct sink *s) { struct sink_input *i, *j = NULL; assert(s); + namereg_unregister(s->core, s->name); + while ((i = idxset_first(s->inputs, NULL))) { assert(i != j); sink_input_kill(i); diff --git a/src/sink.h b/src/sink.h index d9f80059..a5b1ff68 100644 --- a/src/sink.h +++ b/src/sink.h @@ -27,7 +27,7 @@ struct sink { void *userdata; }; -struct sink* sink_new(struct core *core, const char *name, const struct pa_sample_spec *spec); +struct sink* sink_new(struct core *core, const char *name, int fail, const struct pa_sample_spec *spec); void sink_free(struct sink* s); int sink_render(struct sink*s, size_t length, struct memchunk *result); diff --git a/src/source.c b/src/source.c index 21ac24f3..deacfb3d 100644 --- a/src/source.c +++ b/src/source.c @@ -6,8 +6,9 @@ #include "source.h" #include "sourceoutput.h" #include "strbuf.h" +#include "namereg.h" -struct source* source_new(struct core *core, const char *name, const struct pa_sample_spec *spec) { +struct source* source_new(struct core *core, const char *name, int fail, const struct pa_sample_spec *spec) { struct source *s; int r; assert(core && spec); @@ -15,7 +16,12 @@ struct source* source_new(struct core *core, const char *name, const struct pa_s s = malloc(sizeof(struct source)); assert(s); - s->name = name ? strdup(name) : NULL; + if (!(name = namereg_register(core, name, NAMEREG_SOURCE, s, fail))) { + free(s); + return NULL; + } + + s->name = strdup(name); s->core = core; s->sample_spec = *spec; s->outputs = idxset_new(NULL, NULL); @@ -35,6 +41,8 @@ void source_free(struct source *s) { struct source_output *o, *j = NULL; assert(s); + namereg_unregister(s->core, s->name); + while ((o = idxset_first(s->outputs, NULL))) { assert(o != j); source_output_kill(o); diff --git a/src/source.h b/src/source.h index 04f3984f..afae5a68 100644 --- a/src/source.h +++ b/src/source.h @@ -21,7 +21,7 @@ struct source { void *userdata; }; -struct source* source_new(struct core *core, const char *name, const struct pa_sample_spec *spec); +struct source* source_new(struct core *core, const char *name, int fail, const struct pa_sample_spec *spec); void source_free(struct source *s); /* Pass a new memory block to all output streams */ diff --git a/src/todo b/src/todo index 47344ab4..78768be0 100644 --- a/src/todo +++ b/src/todo @@ -1,13 +1,19 @@ -- sync() function in native library -- name registrar -- native protocol/library -- simple control protocol: kill client/input/output; set_volume +- native library/protocol: + recording + sync() function + more functions +- simple library +- simple control protocol: + kill client/input/output + set_volume - resampling +- volume adjust on single sink input +- fp volume scaling (both < and > 1) - esound protocol - config parser/cmdline - record testing + -- 0.1 -- optimierung von rebuild_pollfds() - future cancellation - client-ui - clip cache -- cgit From ef422fa4ae626e9638ca70d1c56f27e701dd69c2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 29 Jun 2004 16:48:37 +0000 Subject: esound protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@40 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 31 ++- src/client.c | 6 + src/client.h | 2 + src/esound-spec.h | 191 +++++++++++++++++++ src/main.c | 9 +- src/module-pipe-sink.c | 2 +- src/module-protocol-stub.c | 39 +++- src/oss-util.c | 6 +- src/pacat.c | 2 +- src/protocol-esound.c | 462 +++++++++++++++++++++++++++++++++++++++++++++ src/protocol-esound.h | 12 ++ src/protocol-native.c | 1 + src/protocol-simple.c | 3 +- src/sample-util.c | 18 +- src/sample.c | 26 ++- src/sample.h | 17 +- src/util.c | 23 +++ src/util.h | 2 + 18 files changed, 806 insertions(+), 46 deletions(-) create mode 100644 src/esound-spec.h create mode 100644 src/protocol-esound.c create mode 100644 src/protocol-esound.h diff --git a/src/Makefile.am b/src/Makefile.am index a67f395e..af4478be 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -29,7 +29,8 @@ pkglib_LTLIBRARIES=libiochannel.la libsocket-server.la libsocket-client.la \ libprotocol-cli.la module-cli-protocol-unix.la libtagstruct.la \ libpdispatch.la libprotocol-native.la libpstream-util.la \ module-native-protocol-tcp.la module-native-protocol-unix.la \ - libpolyp.la + libpolyp.la libprotocol-esound.la module-esound-protocol-unix.la \ + module-esound-protocol-tcp.la polypaudio_SOURCES = idxset.c idxset.h \ queue.c queue.h \ @@ -113,40 +114,54 @@ libprotocol_cli_la_LIBADD = libsocket-server.la libiochannel.la libcli.la libprotocol_native_la_SOURCES = protocol-native.c protocol-native.h libprotocol_native_la_LDFLAGS = -avoid-version -libprotocol_native_la_LIBADD = libsocket-server.la libiochannel.la libpacket.la libpstream.la libpstream-util.la libpdispatch.la +libprotocol_native_la_LIBADD = libsocket-server.la libiochannel.la libpacket.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libtagstruct_la_SOURCES = tagstruct.c tagstruct.h libtagstruct_la_LDFLAGS = -avoid-version +libprotocol_esound_la_SOURCES = protocol-esound.c protocol-esound.h protocol-esound-spec.h +libprotocol_esound_la_LDFLAGS = -avoid-version +libprotocol_esound_la_LIBADD = libsocket-server.la libiochannel.la + module_simple_protocol_tcp_la_SOURCES = module-protocol-stub.c module_simple_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) module_simple_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_simple_protocol_tcp_la_LIBADD = libprotocol-simple.la libiochannel.la +module_simple_protocol_tcp_la_LIBADD = libprotocol-simple.la libsocket-server.la module_simple_protocol_unix_la_SOURCES = module-protocol-stub.c module_simple_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) module_simple_protocol_unix_la_LDFLAGS = -module -avoid-version -module_simple_protocol_unix_la_LIBADD = libprotocol-simple.la libiochannel.la +module_simple_protocol_unix_la_LIBADD = libprotocol-simple.la libsocket-server.la module_cli_protocol_tcp_la_SOURCES = module-protocol-stub.c module_cli_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) module_cli_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_cli_protocol_tcp_la_LIBADD = libprotocol-cli.la libiochannel.la +module_cli_protocol_tcp_la_LIBADD = libprotocol-cli.la libsocket-server.la module_cli_protocol_unix_la_SOURCES = module-protocol-stub.c module_cli_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) module_cli_protocol_unix_la_LDFLAGS = -module -avoid-version -module_cli_protocol_unix_la_LIBADD = libprotocol-cli.la libiochannel.la +module_cli_protocol_unix_la_LIBADD = libprotocol-cli.la libsocket-server.la module_native_protocol_tcp_la_SOURCES = module-protocol-stub.c module_native_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) module_native_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_native_protocol_tcp_la_LIBADD = libprotocol-native.la libiochannel.la libtagstruct.la +module_native_protocol_tcp_la_LIBADD = libprotocol-native.la libsocket-server.la module_native_protocol_unix_la_SOURCES = module-protocol-stub.c module_native_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) module_native_protocol_unix_la_LDFLAGS = -module -avoid-version -module_native_protocol_unix_la_LIBADD = libprotocol-native.la libiochannel.la libtagstruct.la +module_native_protocol_unix_la_LIBADD = libprotocol-native.la libsocket-server.la + +module_esound_protocol_tcp_la_SOURCES = module-protocol-stub.c +module_esound_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) +module_esound_protocol_tcp_la_LDFLAGS = -module -avoid-version +module_esound_protocol_tcp_la_LIBADD = libprotocol-esound.la libsocket-server.la + +module_esound_protocol_unix_la_SOURCES = module-protocol-stub.c +module_esound_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) +module_esound_protocol_unix_la_LDFLAGS = -module -avoid-version +module_esound_protocol_unix_la_LIBADD = libprotocol-esound.la libsocket-server.la module_pipe_sink_la_SOURCES = module-pipe-sink.c module_pipe_sink_la_LDFLAGS = -module -avoid-version diff --git a/src/client.c b/src/client.c index 4c8a0491..37691283 100644 --- a/src/client.c +++ b/src/client.c @@ -60,3 +60,9 @@ char *client_list_to_string(struct core *c) { return strbuf_tostring_free(s); } + +void client_rename(struct client *c, const char *name) { + assert(c); + free(c->name); + c->name = name ? strdup(name) : NULL; +} diff --git a/src/client.h b/src/client.h index 48172051..39167ee7 100644 --- a/src/client.h +++ b/src/client.h @@ -25,4 +25,6 @@ void client_kill(struct client *c); char *client_list_to_string(struct core *c); +void client_rename(struct client *c, const char *name); + #endif diff --git a/src/esound-spec.h b/src/esound-spec.h new file mode 100644 index 00000000..1c2dc022 --- /dev/null +++ b/src/esound-spec.h @@ -0,0 +1,191 @@ +#ifndef fooesoundhfoo +#define fooesoundhfoo + +/* Most of the following is blatantly stolen from esound. */ + + +/* path and name of the default EsounD domain socket */ +#define ESD_UNIX_SOCKET_DIR "/tmp/.esd" +#define ESD_UNIX_SOCKET_NAME "/tmp/.esd/socket" + +/* length of the audio buffer size */ +#define ESD_BUF_SIZE (4 * 1024) +/* maximum size we can write(). Otherwise we might overflow */ +#define ESD_MAX_WRITE_SIZE (21 * 4096) + +/* length of the authorization key, octets */ +#define ESD_KEY_LEN (16) + +/* default port for the EsounD server */ +#define ESD_DEFAULT_PORT (16001) + +/* default sample rate for the EsounD server */ +#define ESD_DEFAULT_RATE (44100) + +/* maximum length of a stream/sample name */ +#define ESD_NAME_MAX (128) + +/* a magic number to identify the relative endianness of a client */ +#define ESD_ENDIAN_KEY ((uint32_t) (('E' << 24) + ('N' << 16) + ('D' << 8) + ('N'))) + +#define ESD_VOLUME_BASE (256) + + +/*************************************/ +/* what can we do to/with the EsounD */ +enum esd_proto { + ESD_PROTO_CONNECT, /* implied on inital client connection */ + + /* pseudo "security" functionality */ + ESD_PROTO_LOCK, /* disable "foreign" client connections */ + ESD_PROTO_UNLOCK, /* enable "foreign" client connections */ + + /* stream functionality: play, record, monitor */ + ESD_PROTO_STREAM_PLAY, /* play all following data as a stream */ + ESD_PROTO_STREAM_REC, /* record data from card as a stream */ + ESD_PROTO_STREAM_MON, /* send mixed buffer output as a stream */ + + /* sample functionality: cache, free, play, loop, EOL, kill */ + ESD_PROTO_SAMPLE_CACHE, /* cache a sample in the server */ + ESD_PROTO_SAMPLE_FREE, /* release a sample in the server */ + ESD_PROTO_SAMPLE_PLAY, /* play a cached sample */ + ESD_PROTO_SAMPLE_LOOP, /* loop a cached sample, til eoloop */ + ESD_PROTO_SAMPLE_STOP, /* stop a looping sample when done */ + ESD_PROTO_SAMPLE_KILL, /* stop the looping sample immed. */ + + /* free and reclaim /dev/dsp functionality */ + ESD_PROTO_STANDBY, /* release /dev/dsp and ignore all data */ + ESD_PROTO_RESUME, /* reclaim /dev/dsp and play sounds again */ + + /* TODO: move these to a more logical place. NOTE: will break the protocol */ + ESD_PROTO_SAMPLE_GETID, /* get the ID for an already-cached sample */ + ESD_PROTO_STREAM_FILT, /* filter mixed buffer output as a stream */ + + /* esd remote management */ + ESD_PROTO_SERVER_INFO, /* get server info (ver, sample rate, format) */ + ESD_PROTO_ALL_INFO, /* get all info (server info, players, samples) */ + ESD_PROTO_SUBSCRIBE, /* track new and removed players and samples */ + ESD_PROTO_UNSUBSCRIBE, /* stop tracking updates */ + + /* esd remote control */ + ESD_PROTO_STREAM_PAN, /* set stream panning */ + ESD_PROTO_SAMPLE_PAN, /* set default sample panning */ + + /* esd status */ + ESD_PROTO_STANDBY_MODE, /* see if server is in standby, autostandby, etc */ + + /* esd latency */ + ESD_PROTO_LATENCY, /* retrieve latency between write()'s and output */ + + ESD_PROTO_MAX /* for bounds checking */ +}; + +/******************/ +/* The EsounD api */ + +/* the properties of a sound buffer are logically or'd */ + +/* bits of stream/sample data */ +#define ESD_MASK_BITS ( 0x000F ) +#define ESD_BITS8 ( 0x0000 ) +#define ESD_BITS16 ( 0x0001 ) + +/* how many interleaved channels of data */ +#define ESD_MASK_CHAN ( 0x00F0 ) +#define ESD_MONO ( 0x0010 ) +#define ESD_STEREO ( 0x0020 ) + +/* whether it's a stream or a sample */ +#define ESD_MASK_MODE ( 0x0F00 ) +#define ESD_STREAM ( 0x0000 ) +#define ESD_SAMPLE ( 0x0100 ) +#define ESD_ADPCM ( 0x0200 ) /* TODO: anyone up for this? =P */ + +/* the function of the stream/sample, and common functions */ +#define ESD_MASK_FUNC ( 0xF000 ) +#define ESD_PLAY ( 0x1000 ) +/* functions for streams only */ +#define ESD_MONITOR ( 0x0000 ) +#define ESD_RECORD ( 0x2000 ) +/* functions for samples only */ +#define ESD_STOP ( 0x0000 ) +#define ESD_LOOP ( 0x2000 ) + +typedef int esd_format_t; +typedef int esd_proto_t; + +/*******************************************************************/ +/* esdmgr.c - functions to implement a "sound manager" for esd */ + +/* structures to retrieve information about streams/samples from the server */ +typedef struct esd_server_info { + + int version; /* server version encoded as an int */ + esd_format_t format; /* magic int with the format info */ + int rate; /* sample rate */ + +} esd_server_info_t; + +typedef struct esd_player_info { + + struct esd_player_info *next; /* point to next entry in list */ + esd_server_info_t *server; /* the server that contains this stream */ + + int source_id; /* either a stream fd or sample id */ + char name[ ESD_NAME_MAX ]; /* name of stream for remote control */ + int rate; /* sample rate */ + int left_vol_scale; /* volume scaling */ + int right_vol_scale; + + esd_format_t format; /* magic int with the format info */ + +} esd_player_info_t; + +typedef struct esd_sample_info { + + struct esd_sample_info *next; /* point to next entry in list */ + esd_server_info_t *server; /* the server that contains this sample */ + + int sample_id; /* either a stream fd or sample id */ + char name[ ESD_NAME_MAX ]; /* name of stream for remote control */ + int rate; /* sample rate */ + int left_vol_scale; /* volume scaling */ + int right_vol_scale; + + esd_format_t format; /* magic int with the format info */ + int length; /* total buffer length */ + +} esd_sample_info_t; + +typedef struct esd_info { + + esd_server_info_t *server; + esd_player_info_t *player_list; + esd_sample_info_t *sample_list; + +} esd_info_t; + +enum esd_standby_mode { + ESM_ERROR, ESM_ON_STANDBY, ESM_ON_AUTOSTANDBY, ESM_RUNNING +}; +typedef int esd_standby_mode_t; + +enum esd_client_state { + ESD_STREAMING_DATA, /* data from here on is streamed data */ + ESD_CACHING_SAMPLE, /* midway through caching a sample */ + ESD_NEEDS_REQDATA, /* more data needed to complere request */ + ESD_NEXT_REQUEST, /* proceed to next request */ + ESD_CLIENT_STATE_MAX /* place holder */ +}; +typedef int esd_client_state_t; + +/* switch endian order for cross platform playing */ +#define swap_endian_32(x) ((x >> 24) | ((x >> 8) & 0xFF00) | (((x & 0xFF00) << 8)) | (x << 24)) + +/* the endian key is transferred in binary, if it's read into int, */ +/* and matches ESD_ENDIAN_KEY (ENDN), then the endianness of the */ +/* server and the client match; if it's SWAP_ENDIAN_KEY, swap data */ +#define ESD_SWAP_ENDIAN_KEY ((uint32_t) swap_endian_32(ESD_ENDIAN_KEY)) + + +#endif diff --git a/src/main.c b/src/main.c index 0fe333e0..e50321f8 100644 --- a/src/main.c +++ b/src/main.c @@ -41,11 +41,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-simple-protocol-unix", NULL);*/ + module_load(c, "module-simple-protocol-unix", NULL); module_load(c, "module-cli-protocol-tcp", NULL); -/* module_load(c, "module-cli-protocol-unix", NULL); - module_load(c, "module-native-protocol-tcp", NULL);*/ - module_load(c, "module-native-protocol-unix", NULL); + module_load(c, "module-cli-protocol-unix", NULL); + module_load(c, "module-native-protocol-tcp", NULL); + module_load(c, "module-native-protocol-unix", NULL);*/ + module_load(c, "module-esound-protocol-tcp", NULL); module_load(c, "module-cli", NULL); fprintf(stderr, "main: mainloop entry.\n"); diff --git a/src/module-pipe-sink.c b/src/module-pipe-sink.c index 6cc4de88..9747c330 100644 --- a/src/module-pipe-sink.c +++ b/src/module-pipe-sink.c @@ -79,7 +79,7 @@ int module_init(struct core *c, struct module*m) { char *p; int fd = -1; static const struct pa_sample_spec ss = { - .format = SAMPLE_S16NE, + .format = PA_SAMPLE_S16NE, .rate = 44100, .channels = 2, }; diff --git a/src/module-protocol-stub.c b/src/module-protocol-stub.c index 97bf5ef3..29ce6b18 100644 --- a/src/module-protocol-stub.c +++ b/src/module-protocol-stub.c @@ -1,31 +1,47 @@ +#include #include #include +#include #include "module.h" #include "socket-server.h" +#include "util.h" #ifdef USE_PROTOCOL_SIMPLE #include "protocol-simple.h" #define protocol_free protocol_simple_free #define IPV4_PORT 4711 - #define UNIX_SOCKET "/tmp/polypaudio_simple" + #define UNIX_SOCKET_DIR "/tmp/polypaudio" + #define UNIX_SOCKET "/tmp/polypaudio/simple" #else #ifdef USE_PROTOCOL_CLI #include "protocol-cli.h" #define protocol_new protocol_cli_new #define protocol_free protocol_cli_free #define IPV4_PORT 4712 - #define UNIX_SOCKET "/tmp/polypaudio_cli" + #define UNIX_SOCKET_DIR "/tmp/polypaudio" + #define UNIX_SOCKET "/tmp/polypaudio/cli" #else #ifdef USE_PROTOCOL_NATIVE #include "protocol-native.h" #define protocol_new protocol_native_new #define protocol_free protocol_native_free #define IPV4_PORT 4713 - #define UNIX_SOCKET "/tmp/polypaudio_native" + #define UNIX_SOCKET_DIR "/tmp/polypaudio" + #define UNIX_SOCKET "/tmp/polypaudio/native" #else - #error "Broken build system" - #endif + #ifdef USE_PROTOCOL_ESOUND + #include "protocol-esound.h" + #include "esound-spec.h" + #define protocol_new protocol_esound_new + #define protocol_free protocol_esound_free + #define IPV4_PORT ESD_DEFAULT_PORT + #define UNIX_SOCKET_DIR ESD_UNIX_SOCKET_DIR + #define UNIX_SOCKET ESD_UNIX_SOCKET_NAME + #else + #error "Broken build system" + #endif + #endif #endif #endif @@ -37,8 +53,15 @@ int module_init(struct core *c, struct module*m) { if (!(s = socket_server_new_ipv4(c->mainloop, INADDR_LOOPBACK, IPV4_PORT))) return -1; #else - if (!(s = socket_server_new_unix(c->mainloop, UNIX_SOCKET))) + if (make_secure_dir(UNIX_SOCKET_DIR) < 0) { + fprintf(stderr, "Failed to create secure socket directory.\n"); return -1; + } + + if (!(s = socket_server_new_unix(c->mainloop, UNIX_SOCKET))) { + rmdir(UNIX_SOCKET_DIR); + return -1; + } #endif #ifdef USE_PROTOCOL_SIMPLE @@ -55,4 +78,8 @@ void module_done(struct core *c, struct module*m) { assert(c && m); protocol_free(m->userdata); + +#ifndef USE_TCP_SOCKETS + rmdir(UNIX_SOCKET_DIR); +#endif } diff --git a/src/oss-util.c b/src/oss-util.c index bf6b62e2..d3a5fecb 100644 --- a/src/oss-util.c +++ b/src/oss-util.c @@ -22,11 +22,11 @@ int oss_auto_format(int fd, struct pa_sample_spec *ss) { fprintf(stderr, "SNDCTL_DSP_SETFMT: %s\n", format != AFMT_U8 ? "No supported sample format" : strerror(errno)); return -1; } else - ss->format = SAMPLE_U8; + ss->format = PA_SAMPLE_U8; } else - ss->format = f == AFMT_S16_LE ? SAMPLE_S16LE : SAMPLE_S16BE; + ss->format = f == AFMT_S16_LE ? PA_SAMPLE_S16LE : PA_SAMPLE_S16BE; } else - ss->format = SAMPLE_S16NE; + ss->format = PA_SAMPLE_S16NE; channels = 2; if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) { diff --git a/src/pacat.c b/src/pacat.c index 5ee1b866..fbd1d081 100644 --- a/src/pacat.c +++ b/src/pacat.c @@ -75,7 +75,7 @@ static void stream_complete_callback(struct pa_context*c, struct pa_stream *s, v static void context_complete_callback(struct pa_context *c, int success, void *userdata) { static const struct pa_sample_spec ss = { - .format = SAMPLE_S16NE, + .format = PA_SAMPLE_S16NE, .rate = 44100, .channels = 2 }; diff --git a/src/protocol-esound.c b/src/protocol-esound.c new file mode 100644 index 00000000..1668ef55 --- /dev/null +++ b/src/protocol-esound.c @@ -0,0 +1,462 @@ +#include +#include +#include +#include +#include +#include + +#include "protocol-esound.h" +#include "esound-spec.h" +#include "memblock.h" +#include "client.h" +#include "sinkinput.h" +#include "sink.h" +#include "sample.h" + +/* This is heavily based on esound's code */ + +struct connection { + struct protocol_esound *protocol; + struct iochannel *io; + struct client *client; + int authorized, swap_byte_order; + void *read_data; + size_t read_data_alloc, read_data_length; + void *write_data; + size_t write_data_alloc, write_data_index, write_data_length; + esd_proto_t request; + esd_client_state_t state; + struct sink_input *sink_input; + struct memblockq *input_memblockq; +}; + +struct protocol_esound { + int public; + struct core *core; + struct socket_server *server; + struct idxset *connections; +}; + +typedef struct proto_handler { + size_t data_length; + int (*proc)(struct connection *c, const void *data, size_t length); + const char *description; +} esd_proto_handler_info_t; + +#define BUFSIZE PIPE_BUF + +static void sink_input_drop_cb(struct sink_input *i, size_t length); +static int sink_input_peek_cb(struct sink_input *i, struct memchunk *chunk); +static void sink_input_kill_cb(struct sink_input *i); +static uint32_t sink_input_get_latency_cb(struct sink_input *i); + +static int esd_proto_connect(struct connection *c, const void *data, size_t length); +static int esd_proto_stream_play(struct connection *c, const void *data, size_t length); +static int esd_proto_stream_record(struct connection *c, const void *data, size_t length); + +static int do_write(struct connection *c); + +/* the big map of protocol handler info */ +static struct proto_handler proto_map[ESD_PROTO_MAX] = { + { ESD_KEY_LEN + sizeof(int), &esd_proto_connect, "connect" }, + { ESD_KEY_LEN + sizeof(int), NULL, "lock" }, + { ESD_KEY_LEN + sizeof(int), NULL, "unlock" }, + + { ESD_NAME_MAX + 2 * sizeof(int), &esd_proto_stream_play, "stream play" }, + { ESD_NAME_MAX + 2 * sizeof(int), &esd_proto_stream_record, "stream rec" }, + { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream mon" }, + + { ESD_NAME_MAX + 3 * sizeof(int), NULL, "sample cache" }, + { sizeof(int), NULL, "sample free" }, + { sizeof(int), NULL, "sample play" }, + { sizeof(int), NULL, "sample loop" }, + { sizeof(int), NULL, "sample stop" }, + { -1, NULL, "TODO: sample kill" }, + + { ESD_KEY_LEN + sizeof(int), NULL, "standby" }, + { ESD_KEY_LEN + sizeof(int), NULL, "resume" }, + + { ESD_NAME_MAX, NULL, "sample getid" }, + { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" }, + + { sizeof(int), NULL, "server info" }, + { sizeof(int), NULL, "all info" }, + { -1, NULL, "TODO: subscribe" }, + { -1, NULL, "TODO: unsubscribe" }, + + { 3 * sizeof(int), NULL, "stream pan"}, + { 3 * sizeof(int), NULL, "sample pan" }, + + { sizeof(int), NULL, "standby mode" }, + { 0, NULL, "get latency" } +}; + + +static void connection_free(struct connection *c) { + assert(c); + idxset_remove_by_data(c->protocol->connections, c, NULL); + + client_free(c->client); + + if (c->sink_input) + sink_input_free(c->sink_input); + if (c->input_memblockq) + memblockq_free(c->input_memblockq); + + free(c->read_data); + free(c->write_data); + + iochannel_free(c->io); + free(c); +} + +static struct sink* get_output_sink(struct protocol_esound *p) { + assert(p); + return sink_get_default(p->core); +} + +static void* connection_write(struct connection *c, size_t length) { + size_t t, i; + assert(c); + + t = c->write_data_length+length; + + if (c->write_data_alloc < t) + c->write_data = realloc(c->write_data, c->write_data_alloc = t); + + assert(c->write_data); + + i = c->write_data_length; + c->write_data_length += length; + + return c->write_data+i; +} + +/*** esound commands ***/ + +static int esd_proto_connect(struct connection *c, const void *data, size_t length) { + uint32_t ekey; + int *ok; + assert(length == (ESD_KEY_LEN + sizeof(uint32_t))); + + c->authorized = 1; + + ekey = *(uint32_t*)(data+ESD_KEY_LEN); + if (ekey == ESD_ENDIAN_KEY) + c->swap_byte_order = 0; + else if (ekey == ESD_SWAP_ENDIAN_KEY) + c->swap_byte_order = 1; + else { + fprintf(stderr, "protocol-esound.c: client sent invalid endian key\n"); + return -1; + } + + ok = connection_write(c, sizeof(int)); + assert(ok); + *ok = 1; + + do_write(c); + + return 0; +} + +static int esd_proto_stream_play(struct connection *c, const void *data, size_t length) { + char name[ESD_NAME_MAX]; + int format, rate; + struct sink *sink; + struct pa_sample_spec ss; + assert(length == (sizeof(int)*2+ESD_NAME_MAX)); + + format = *(int*)data; + rate = *((int*)data + 1); + + if (c->swap_byte_order) + format = swap_endian_32(format); + if (c->swap_byte_order) + rate = swap_endian_32(rate); + + ss.rate = rate; + ss.channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; + ss.format = ((format & ESD_MASK_BITS) == ESD_BITS16) ? PA_SAMPLE_S16NE : PA_SAMPLE_U8; + + if (!pa_sample_spec_valid(&ss)) + return -1; + + if (!(sink = get_output_sink(c->protocol))) + return -1; + + strncpy(name, data + sizeof(int)*2, sizeof(name)); + name[sizeof(name)-1] = 0; + + client_rename(c->client, name); + + assert(!c->input_memblockq); + c->input_memblockq = memblockq_new(1024*10, pa_sample_size(&ss), 1024*2); + assert(c->input_memblockq); + + assert(!c->sink_input); + c->sink_input = sink_input_new(sink, &ss, name); + assert(c->sink_input); + + c->sink_input->peek = sink_input_peek_cb; + c->sink_input->drop = sink_input_drop_cb; + c->sink_input->kill = sink_input_kill_cb; + c->sink_input->get_latency = sink_input_get_latency_cb; + c->sink_input->userdata = c; + + c->state = ESD_STREAMING_DATA; + + return 0; +} + +static int esd_proto_stream_record(struct connection *c, const void *data, size_t length) { + assert(0); +} + +/*** client callbacks ***/ + +static void client_kill_cb(struct client *c) { + assert(c && c->userdata); + connection_free(c->userdata); +} + +/*** iochannel callbacks ***/ + +static int do_read(struct connection *c) { + assert(c && c->io); + + if (!iochannel_is_readable(c->io)) + return 0; + + if (c->state == ESD_NEXT_REQUEST) { + ssize_t r; + assert(c->read_data_length < sizeof(c->request)); + + if ((r = iochannel_read(c->io, ((void*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { + fprintf(stderr, "protocol-esound.c: read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + return -1; + } + + if ((c->read_data_length+= r) >= sizeof(c->request)) { + struct proto_handler *handler; + + if (c->swap_byte_order) + c->request = swap_endian_32(c->request); + + if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) { + fprintf(stderr, "protocol-esound.c: recieved invalid request.\n"); + return -1; + } + + handler = proto_map+c->request; + + if (!handler->proc) { + fprintf(stderr, "protocol-sound.c: recieved unimplemented request.\n"); + return -1; + } + + if (handler->data_length == 0) { + c->read_data_length = 0; + + if (handler->proc(c, NULL, 0) < 0) + return -1; + + } else { + if (c->read_data_alloc < handler->data_length) + c->read_data = realloc(c->read_data, c->read_data_alloc = handler->data_length); + assert(c->read_data); + + c->state = ESD_NEEDS_REQDATA; + c->read_data_length = 0; + } + } + + } else if (c->state == ESD_NEEDS_REQDATA) { + ssize_t r; + struct proto_handler *handler = proto_map+c->request; + + assert(handler->proc); + + assert(c->read_data && c->read_data_length < handler->data_length); + + if ((r = iochannel_read(c->io, c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { + fprintf(stderr, "protocol-esound.c: read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + return -1; + } + + if ((c->read_data_length+= r) >= handler->data_length) { + size_t l = c->read_data_length; + assert(handler->proc); + + c->state = ESD_NEXT_REQUEST; + c->read_data_length = 0; + + if (handler->proc(c, c->read_data, l) < 0) + return -1; + } + } else if (c->state == ESD_STREAMING_DATA) { + struct memchunk chunk; + ssize_t r; + + assert(c->input_memblockq); + + if (!memblockq_is_writable(c->input_memblockq, BUFSIZE)) + return 0; + + chunk.memblock = memblock_new(BUFSIZE); + assert(chunk.memblock && chunk.memblock->data); + + if ((r = iochannel_read(c->io, chunk.memblock->data, BUFSIZE)) <= 0) { + fprintf(stderr, "protocol-esound.c: read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + memblock_unref(chunk.memblock); + return -1; + } + + chunk.memblock->length = chunk.length = r; + chunk.index = 0; + + assert(c->input_memblockq); + memblockq_push(c->input_memblockq, &chunk, 0); + memblock_unref(chunk.memblock); + assert(c->sink_input); + sink_notify(c->sink_input->sink); + } else + assert(0); + + return 0; +} + +static int do_write(struct connection *c) { + ssize_t r; + assert(c && c->io); + + if (!iochannel_is_writable(c->io)) + return 0; + + if (!c->write_data_length) + return 0; + + assert(c->write_data_index < c->write_data_length); + if ((r = iochannel_write(c->io, c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { + fprintf(stderr, "protocol-esound.c: write() failed: %s\n", strerror(errno)); + return -1; + } + + if ((c->write_data_index +=r) >= c->write_data_length) + c->write_data_length = c->write_data_index = 0; + + return 0; +} + +static void io_callback(struct iochannel*io, void *userdata) { + struct connection *c = userdata; + assert(io && c && c->io == io); + + if (do_read(c) < 0 || do_write(c) < 0) + connection_free(c); +} + +/*** sink_input callbacks ***/ + +static int sink_input_peek_cb(struct sink_input *i, struct memchunk *chunk) { + struct connection*c; + assert(i && i->userdata && chunk); + c = i->userdata; + + if (memblockq_peek(c->input_memblockq, chunk) < 0) + return -1; + + return 0; +} + +static void sink_input_drop_cb(struct sink_input *i, size_t length) { + struct connection*c = i->userdata; + assert(i && c && length); + + memblockq_drop(c->input_memblockq, length); + + if (do_read(c) < 0) + connection_free(c); +} + +static void sink_input_kill_cb(struct sink_input *i) { + assert(i && i->userdata); + connection_free((struct connection *) i->userdata); +} + + +static uint32_t sink_input_get_latency_cb(struct sink_input *i) { + struct connection*c = i->userdata; + assert(i && c); + return pa_samples_usec(memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); +} + +/*** socket server callback ***/ + +static void on_connection(struct socket_server*s, struct iochannel *io, void *userdata) { + struct connection *c; + char cname[256]; + assert(s && io && userdata); + + c = malloc(sizeof(struct connection)); + assert(c); + c->protocol = userdata; + c->io = io; + iochannel_set_callback(c->io, io_callback, c); + + iochannel_peer_to_string(io, cname, sizeof(cname)); + assert(c->protocol->core); + c->client = client_new(c->protocol->core, "ESOUND", cname); + assert(c->client); + c->client->kill = client_kill_cb; + c->client->userdata = c; + + c->authorized = c->protocol->public; + c->swap_byte_order = 0; + + c->read_data_length = 0; + c->read_data = malloc(c->read_data_alloc = proto_map[ESD_PROTO_CONNECT].data_length); + assert(c->read_data); + + c->write_data_length = c->write_data_index = c->write_data_alloc = 0; + c->write_data = NULL; + + c->state = ESD_NEEDS_REQDATA; + c->request = ESD_PROTO_CONNECT; + + c->sink_input = NULL; + c->input_memblockq = NULL; + + idxset_put(c->protocol->connections, c, NULL); +} + +/*** entry points ***/ + +struct protocol_esound* protocol_esound_new(struct core*core, struct socket_server *server) { + struct protocol_esound *p; + assert(core && server); + + p = malloc(sizeof(struct protocol_esound)); + assert(p); + p->public = 1; + p->server = server; + p->core = core; + p->connections = idxset_new(NULL, NULL); + assert(p->connections); + + socket_server_set_callback(p->server, on_connection, p); + + return p; +} + +void protocol_esound_free(struct protocol_esound *p) { + struct connection *c; + assert(p); + + while ((c = idxset_first(p->connections, NULL))) + connection_free(c); + + idxset_free(p->connections, NULL, NULL); + socket_server_free(p->server); + free(p); +} diff --git a/src/protocol-esound.h b/src/protocol-esound.h new file mode 100644 index 00000000..2600cfae --- /dev/null +++ b/src/protocol-esound.h @@ -0,0 +1,12 @@ +#ifndef fooprotocolesoundhfoo +#define fooprotocolesoundhfoo + +#include "core.h" +#include "socket-server.h" + +struct protocol_esound; + +struct protocol_esound* protocol_esound_new(struct core*core, struct socket_server *server); +void protocol_esound_free(struct protocol_esound *p); + +#endif diff --git a/src/protocol-native.c b/src/protocol-native.c index 27b547a6..9af438a9 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -384,6 +384,7 @@ struct protocol_native* protocol_native_new(struct core *core, struct socket_ser p->server = server; p->core = core; p->connections = idxset_new(NULL, NULL); + assert(p->connections); socket_server_set_callback(p->server, on_connection, p); diff --git a/src/protocol-simple.c b/src/protocol-simple.c index c8c45854..80249eef 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -73,8 +73,7 @@ static int do_read(struct connection *c) { return -1; } - chunk.memblock->length = r; - chunk.length = r; + chunk.memblock->length = chunk.length = r; chunk.index = 0; assert(c->input_memblockq); diff --git a/src/sample-util.c b/src/sample-util.c index 7a3c267a..ff14548c 100644 --- a/src/sample-util.c +++ b/src/sample-util.c @@ -4,7 +4,7 @@ #include "sample-util.h" struct pa_sample_spec default_sample_spec = { - .format = SAMPLE_S16NE, + .format = PA_SAMPLE_S16NE, .rate = 44100, .channels = 2 }; @@ -27,18 +27,20 @@ void silence_memory(void *p, size_t length, struct pa_sample_spec *spec) { assert(p && length && spec); switch (spec->format) { - case SAMPLE_U8: + case PA_SAMPLE_U8: c = 127; break; - case SAMPLE_S16LE: - case SAMPLE_S16BE: - case SAMPLE_FLOAT32: + case PA_SAMPLE_S16LE: + case PA_SAMPLE_S16BE: + case PA_SAMPLE_FLOAT32: c = 0; break; - case SAMPLE_ALAW: - case SAMPLE_ULAW: + case PA_SAMPLE_ALAW: + case PA_SAMPLE_ULAW: c = 80; break; + default: + assert(0); } memset(p, c, length); @@ -47,7 +49,7 @@ void silence_memory(void *p, size_t length, struct pa_sample_spec *spec) { size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct pa_sample_spec *spec, uint8_t volume) { unsigned c, d; assert(channels && data && length && spec); - assert(spec->format == SAMPLE_S16NE); + assert(spec->format == PA_SAMPLE_S16NE); for (d = 0;; d += sizeof(int16_t)) { int32_t sum = 0; diff --git a/src/sample.c b/src/sample.c index 2454630c..b0d0cdbd 100644 --- a/src/sample.c +++ b/src/sample.c @@ -7,18 +7,20 @@ size_t pa_sample_size(struct pa_sample_spec *spec) { size_t b = 1; switch (spec->format) { - case SAMPLE_U8: - case SAMPLE_ULAW: - case SAMPLE_ALAW: + case PA_SAMPLE_U8: + case PA_SAMPLE_ULAW: + case PA_SAMPLE_ALAW: b = 1; break; - case SAMPLE_S16LE: - case SAMPLE_S16BE: + case PA_SAMPLE_S16LE: + case PA_SAMPLE_S16BE: b = 2; break; - case SAMPLE_FLOAT32: + case PA_SAMPLE_FLOAT32: b = 4; break; + default: + assert(0); } return b * spec->channels; @@ -35,3 +37,15 @@ uint32_t pa_samples_usec(size_t length, struct pa_sample_spec *spec) { return (uint32_t) (((double) length /pa_sample_size(spec))/spec->rate*1000000); } + +int pa_sample_spec_valid(struct pa_sample_spec *spec) { + assert(spec); + + if (!spec->rate || !spec->channels) + return 0; + + if (spec->format <= 0 || spec->format >= PA_SAMPLE_MAX) + return 0; + + return 1; +} diff --git a/src/sample.h b/src/sample.h index a4a973bf..697937e0 100644 --- a/src/sample.h +++ b/src/sample.h @@ -5,15 +5,16 @@ #include enum pa_sample_format { - SAMPLE_U8, - SAMPLE_ALAW, - SAMPLE_ULAW, - SAMPLE_S16LE, - SAMPLE_S16BE, - SAMPLE_FLOAT32 + PA_SAMPLE_U8, + PA_SAMPLE_ALAW, + PA_SAMPLE_ULAW, + PA_SAMPLE_S16LE, + PA_SAMPLE_S16BE, + PA_SAMPLE_FLOAT32, + PA_SAMPLE_MAX }; -#define SAMPLE_S16NE SAMPLE_S16LE +#define PA_SAMPLE_S16NE PA_SAMPLE_S16LE struct pa_sample_spec { enum pa_sample_format format; @@ -25,4 +26,6 @@ size_t pa_bytes_per_second(struct pa_sample_spec *spec); size_t pa_sample_size(struct pa_sample_spec *spec); uint32_t pa_samples_usec(size_t length, struct pa_sample_spec *spec); +int pa_sample_spec_valid(struct pa_sample_spec *spec); + #endif diff --git a/src/util.c b/src/util.c index 0383a0ad..95350421 100644 --- a/src/util.c +++ b/src/util.c @@ -1,9 +1,12 @@ +#include #include #include #include #include #include #include +#include +#include #include "util.h" @@ -60,3 +63,23 @@ void peer_to_string(char *c, size_t l, int fd) { snprintf(c, l, "Unknown client"); } + +int make_secure_dir(const char* dir) { + struct stat st; + + if (mkdir(dir, 0700) < 0) + if (errno != EEXIST) + return -1; + + if (lstat(dir, &st) < 0) + goto fail; + + if (!S_ISDIR(st.st_mode) || (st.st_uid != getuid()) || ((st.st_mode & 0777) != 0700)) + goto fail; + + return 0; + +fail: + rmdir(dir); + return -1; +} diff --git a/src/util.h b/src/util.h index 830ee2e0..2a507198 100644 --- a/src/util.h +++ b/src/util.h @@ -5,4 +5,6 @@ void make_nonblock_fd(int fd); void peer_to_string(char *c, size_t l, int fd); +int make_secure_dir(const char* dir); + #endif -- cgit From e31bac02573cc3090cac5816bea62a2fea888399 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 29 Jun 2004 18:50:14 +0000 Subject: extended esound protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@41 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/protocol-esound.c | 111 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 86 insertions(+), 25 deletions(-) diff --git a/src/protocol-esound.c b/src/protocol-esound.c index 1668ef55..5db7a13f 100644 --- a/src/protocol-esound.c +++ b/src/protocol-esound.c @@ -35,6 +35,7 @@ struct protocol_esound { struct core *core; struct socket_server *server; struct idxset *connections; + uint32_t sink_index; }; typedef struct proto_handler { @@ -43,6 +44,9 @@ typedef struct proto_handler { const char *description; } esd_proto_handler_info_t; +#define MEMBLOCKQ_LENGTH (10*1204) +#define MEMBLOCKQ_PREBUF (2*1024) + #define BUFSIZE PIPE_BUF static void sink_input_drop_cb(struct sink_input *i, size_t length); @@ -53,42 +57,44 @@ static uint32_t sink_input_get_latency_cb(struct sink_input *i); static int esd_proto_connect(struct connection *c, const void *data, size_t length); static int esd_proto_stream_play(struct connection *c, const void *data, size_t length); static int esd_proto_stream_record(struct connection *c, const void *data, size_t length); +static int esd_proto_get_latency(struct connection *c, const void *data, size_t length); +static int esd_proto_server_info(struct connection *c, const void *data, size_t length); static int do_write(struct connection *c); /* the big map of protocol handler info */ static struct proto_handler proto_map[ESD_PROTO_MAX] = { - { ESD_KEY_LEN + sizeof(int), &esd_proto_connect, "connect" }, - { ESD_KEY_LEN + sizeof(int), NULL, "lock" }, - { ESD_KEY_LEN + sizeof(int), NULL, "unlock" }, + { ESD_KEY_LEN + sizeof(int), esd_proto_connect, "connect" }, + { ESD_KEY_LEN + sizeof(int), NULL, "lock" }, + { ESD_KEY_LEN + sizeof(int), NULL, "unlock" }, - { ESD_NAME_MAX + 2 * sizeof(int), &esd_proto_stream_play, "stream play" }, - { ESD_NAME_MAX + 2 * sizeof(int), &esd_proto_stream_record, "stream rec" }, + { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_play, "stream play" }, + { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream rec" }, { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream mon" }, { ESD_NAME_MAX + 3 * sizeof(int), NULL, "sample cache" }, - { sizeof(int), NULL, "sample free" }, - { sizeof(int), NULL, "sample play" }, - { sizeof(int), NULL, "sample loop" }, - { sizeof(int), NULL, "sample stop" }, - { -1, NULL, "TODO: sample kill" }, + { sizeof(int), NULL, "sample free" }, + { sizeof(int), NULL, "sample play" }, + { sizeof(int), NULL, "sample loop" }, + { sizeof(int), NULL, "sample stop" }, + { -1, NULL, "TODO: sample kill" }, - { ESD_KEY_LEN + sizeof(int), NULL, "standby" }, - { ESD_KEY_LEN + sizeof(int), NULL, "resume" }, + { ESD_KEY_LEN + sizeof(int), NULL, "standby" }, + { ESD_KEY_LEN + sizeof(int), NULL, "resume" }, - { ESD_NAME_MAX, NULL, "sample getid" }, + { ESD_NAME_MAX, NULL, "sample getid" }, { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" }, - { sizeof(int), NULL, "server info" }, - { sizeof(int), NULL, "all info" }, - { -1, NULL, "TODO: subscribe" }, - { -1, NULL, "TODO: unsubscribe" }, - - { 3 * sizeof(int), NULL, "stream pan"}, - { 3 * sizeof(int), NULL, "sample pan" }, + { sizeof(int), esd_proto_server_info, "server info" }, + { sizeof(int), NULL, "all info" }, + { -1, NULL, "TODO: subscribe" }, + { -1, NULL, "TODO: unsubscribe" }, - { sizeof(int), NULL, "standby mode" }, - { 0, NULL, "get latency" } + { 3 * sizeof(int), NULL, "stream pan"}, + { 3 * sizeof(int), NULL, "sample pan" }, + + { sizeof(int), NULL, "standby mode" }, + { 0, esd_proto_get_latency, "get latency" } }; @@ -111,8 +117,18 @@ static void connection_free(struct connection *c) { } static struct sink* get_output_sink(struct protocol_esound *p) { + struct sink *s; assert(p); - return sink_get_default(p->core); + + if (!(s = idxset_get_by_index(p->core->sinks, p->sink_index))) + s = sink_get_default(p->core); + + if (s->index) + p->sink_index = s->index; + else + p->sink_index = IDXSET_INVALID; + + return s; } static void* connection_write(struct connection *c, size_t length) { @@ -191,7 +207,7 @@ static int esd_proto_stream_play(struct connection *c, const void *data, size_t client_rename(c->client, name); assert(!c->input_memblockq); - c->input_memblockq = memblockq_new(1024*10, pa_sample_size(&ss), 1024*2); + c->input_memblockq = memblockq_new(MEMBLOCKQ_LENGTH, pa_sample_size(&ss), MEMBLOCKQ_PREBUF); assert(c->input_memblockq); assert(!c->sink_input); @@ -210,9 +226,53 @@ static int esd_proto_stream_play(struct connection *c, const void *data, size_t } static int esd_proto_stream_record(struct connection *c, const void *data, size_t length) { + assert(c && data && length == (sizeof(int)*2+ESD_NAME_MAX)); + assert(0); } +static int esd_proto_get_latency(struct connection *c, const void *data, size_t length) { + struct sink *sink; + int latency, *lag; + assert(c && data && length == 0); + + if (!(sink = get_output_sink(c->protocol))) + latency = 0; + else { + float usec = sink_get_latency(sink); + usec += pa_samples_usec(MEMBLOCKQ_LENGTH, &sink->sample_spec); + latency = (int) (usec*441/10000); + } + + lag = connection_write(c, sizeof(int)); + assert(lag); + *lag = c->swap_byte_order ? swap_endian_32(latency) : latency; + + do_write(c); + return 0; +} + +static int esd_proto_server_info(struct connection *c, const void *data, size_t length) { + int rate = 44100, format = ESD_STEREO|ESD_BITS16; + int *response; + struct sink *sink; + assert(c && data && length == sizeof(int)); + + if ((sink = get_output_sink(c->protocol))) { + rate = sink->sample_spec.rate; + format = (sink->sample_spec.format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16; + format |= (sink->sample_spec.channels >= 2) ? ESD_STEREO : ESD_MONO; + } + + response = connection_write(c, sizeof(int)*3); + assert(response); + *(response++) = 0; + *(response++) = c->swap_byte_order ? swap_endian_32(rate) : rate; + *(response++) = c->swap_byte_order ? swap_endian_32(format) : format; + do_write(c); + return 0; +} + /*** client callbacks ***/ static void client_kill_cb(struct client *c) { @@ -426,7 +486,7 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c->sink_input = NULL; c->input_memblockq = NULL; - + idxset_put(c->protocol->connections, c, NULL); } @@ -443,6 +503,7 @@ struct protocol_esound* protocol_esound_new(struct core*core, struct socket_serv p->core = core; p->connections = idxset_new(NULL, NULL); assert(p->connections); + p->sink_index = IDXSET_INVALID; socket_server_set_callback(p->server, on_connection, p); -- cgit From d571be6f5109ff5b256e4c14f391c916264f0a8e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 29 Jun 2004 20:37:24 +0000 Subject: volume work git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@42 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/cli.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++------- src/main.c | 2 +- src/memblock.c | 14 ++++++++ src/memblock.h | 2 ++ src/namereg.c | 18 +++++++++-- src/sample-util.c | 54 ++++++++++++++++++++++++++----- src/sample-util.h | 11 +++++-- src/sink.c | 22 +++++++++++-- src/sink.h | 2 +- src/sinkinput.c | 5 +-- src/sinkinput.h | 2 +- src/todo | 9 +++--- 12 files changed, 203 insertions(+), 35 deletions(-) diff --git a/src/cli.c b/src/cli.c index 09162351..10e780cd 100644 --- a/src/cli.c +++ b/src/cli.c @@ -13,6 +13,7 @@ #include "sourceoutput.h" #include "tokenizer.h" #include "strbuf.h" +#include "namereg.h" struct cli { struct core *core; @@ -45,20 +46,24 @@ static void cli_command_stat(struct cli *c, struct tokenizer *t); static void cli_command_info(struct cli *c, struct tokenizer *t); static void cli_command_load(struct cli *c, struct tokenizer *t); static void cli_command_unload(struct cli *c, struct tokenizer *t); +static void cli_command_sink_volume(struct cli *c, struct tokenizer *t); +static void cli_command_sink_input_volume(struct cli *c, struct tokenizer *t); static const struct command commands[] = { - { "exit", cli_command_exit, "Terminate the daemon", 1 }, - { "help", cli_command_help, "Show this help", 1 }, - { "modules", cli_command_modules, "List loaded modules", 1 }, - { "sinks", cli_command_sinks, "List loaded sinks", 1 }, - { "sources", cli_command_sources, "List loaded sources", 1 }, - { "clients", cli_command_clients, "List loaded clients", 1 }, - { "sink_inputs", cli_command_sink_inputs, "List sink inputs", 1 }, - { "source_outputs", cli_command_source_outputs, "List source outputs", 1 }, - { "stat", cli_command_stat, "Show memory block statistics", 1 }, - { "info", cli_command_info, "Show comprehensive status", 1 }, - { "load", cli_command_load, "Load a module (given by name and arguments)", 3 }, - { "unload", cli_command_unload, "Unload a module (specified by index)", 2 }, + { "exit", cli_command_exit, "Terminate the daemon", 1 }, + { "help", cli_command_help, "Show this help", 1 }, + { "modules", cli_command_modules, "List loaded modules", 1 }, + { "sinks", cli_command_sinks, "List loaded sinks", 1 }, + { "sources", cli_command_sources, "List loaded sources", 1 }, + { "clients", cli_command_clients, "List loaded clients", 1 }, + { "sink_inputs", cli_command_sink_inputs, "List sink inputs", 1 }, + { "source_outputs", cli_command_source_outputs, "List source outputs", 1 }, + { "stat", cli_command_stat, "Show memory block statistics", 1 }, + { "info", cli_command_info, "Show comprehensive status", 1 }, + { "load", cli_command_load, "Load a module (args: name, arguments)", 3}, + { "unload", cli_command_unload, "Unload a module (args: index)", 2}, + { "sink_volume", cli_command_sink_volume, "Set the volume of a sink (args: sink, volume)", 3}, + { "sink_input_volume", cli_command_sink_input_volume, "Set the volume of a sink input (args: sink input, volume)", 3}, { NULL, NULL, NULL, 0 } }; @@ -277,3 +282,71 @@ static void cli_command_unload(struct cli *c, struct tokenizer *t) { module_unload_request(c->core, m); } + +static void cli_command_sink_volume(struct cli *c, struct tokenizer *t) { + const char *n, *v; + char *x = NULL; + struct sink *sink; + long volume; + + if (!(n = tokenizer_get(t, 1))) { + ioline_puts(c->line, "You need to specify a sink either by its name or its index.\n"); + return; + } + + if (!(v = tokenizer_get(t, 2))) { + ioline_puts(c->line, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n"); + return; + } + + volume = strtol(v, &x, 0); + if (!x || *x != 0 || volume < 0) { + ioline_puts(c->line, "Failed to parse volume.\n"); + return; + } + + if (!(sink = namereg_get(c->core, n, NAMEREG_SINK))) { + ioline_puts(c->line, "No sink found by this name or index.\n"); + return; + } + + sink->volume = (uint32_t) volume; +} + +static void cli_command_sink_input_volume(struct cli *c, struct tokenizer *t) { + const char *n, *v; + char *x = NULL; + struct sink_input *si; + long index, volume; + + if (!(n = tokenizer_get(t, 1))) { + ioline_puts(c->line, "You need to specify a sink input by its index.\n"); + return; + } + + index = strtol(n, &x, 0); + if (!x || *x != 0 || index < 0) { + ioline_puts(c->line, "Failed to parse index.\n"); + return; + } + + if (!(v = tokenizer_get(t, 2))) { + ioline_puts(c->line, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n"); + return; + } + + x = NULL; + volume = strtol(v, &x, 0); + if (!x || *x != 0 || volume < 0) { + ioline_puts(c->line, "Failed to parse volume.\n"); + return; + } + + if (!(si = idxset_get_by_index(c->core->sink_inputs, (uint32_t) index))) { + ioline_puts(c->line, "No sink input found with this index.\n"); + return; + } + + si->volume = (uint32_t) volume; +} + diff --git a/src/main.c b/src/main.c index e50321f8..3512c5ba 100644 --- a/src/main.c +++ b/src/main.c @@ -38,7 +38,7 @@ int main(int argc, char *argv[]) { c = core_new(pa_mainloop_get_api(mainloop)); assert(c); - module_load(c, "module-oss-mmap", "/dev/dsp1"); + module_load(c, "module-oss", "/dev/dsp1"); /* module_load(c, "module-pipe-sink", NULL); module_load(c, "module-simple-protocol-tcp", NULL); module_load(c, "module-simple-protocol-unix", NULL); diff --git a/src/memblock.c b/src/memblock.c index 067243c5..79fe2977 100644 --- a/src/memblock.c +++ b/src/memblock.c @@ -78,3 +78,17 @@ void memblock_unref_fixed(struct memblock *b) { b->type = MEMBLOCK_DYNAMIC; } +void memchunk_make_writable(struct memchunk *c) { + struct memblock *n; + assert(c && c->memblock && c->memblock->ref >= 1); + + if (c->memblock->ref == 1) + return; + + n = memblock_new(c->length); + assert(n); + memcpy(n->data, c->memblock->data+c->index, c->length); + memblock_unref(c->memblock); + c->memblock = n; + c->index = 0; +} diff --git a/src/memblock.h b/src/memblock.h index cba11101..0c215e85 100644 --- a/src/memblock.h +++ b/src/memblock.h @@ -29,6 +29,8 @@ void memblock_unref_fixed(struct memblock*b); #define memblock_assert_exclusive(b) assert((b)->ref == 1) +void memchunk_make_writable(struct memchunk *c); + extern unsigned memblock_count, memblock_total; #endif diff --git a/src/namereg.c b/src/namereg.c index b286171d..0af46189 100644 --- a/src/namereg.c +++ b/src/namereg.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -87,11 +88,24 @@ void namereg_unregister(struct core *c, const char *name) { void* namereg_get(struct core *c, const char *name, enum namereg_type type) { struct namereg_entry *e; + uint32_t index; + char *x = NULL; + void *d = NULL; assert(c && name); - if (!(e = hashset_get(c->namereg, name))) + if ((e = hashset_get(c->namereg, name))) if (e->type == e->type) return e->data; - return NULL; + index = (uint32_t) strtol(name, &x, 0); + + if (!x || *x != 0) + return NULL; + + if (type == NAMEREG_SINK) + d = idxset_get_by_index(c->sinks, index); + else if (type == NAMEREG_SOURCE) + d = idxset_get_by_index(c->sources, index); + + return d; } diff --git a/src/sample-util.c b/src/sample-util.c index ff14548c..09511a3c 100644 --- a/src/sample-util.c +++ b/src/sample-util.c @@ -1,3 +1,4 @@ +#include #include #include @@ -46,7 +47,7 @@ void silence_memory(void *p, size_t length, struct pa_sample_spec *spec) { memset(p, c, length); } -size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct pa_sample_spec *spec, uint8_t volume) { +size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct pa_sample_spec *spec, uint32_t volume) { unsigned c, d; assert(channels && data && length && spec); assert(spec->format == PA_SAMPLE_S16NE); @@ -59,27 +60,27 @@ size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, si for (c = 0; c < nchannels; c++) { int32_t v; - uint8_t volume = channels[c].volume; + uint32_t volume = channels[c].volume; if (d >= channels[c].chunk.length) return d; - if (volume == 0) + if (volume == VOLUME_MUTE) v = 0; else { v = *((int16_t*) (channels[c].chunk.memblock->data + channels[c].chunk.index + d)); - if (volume != 0xFF) - v = v*volume/0xFF; + if (volume != VOLUME_NORM) + v = (int32_t) ((float)v*volume/VOLUME_NORM); } sum += v; } - if (volume == 0) + if (volume == VOLUME_MUTE) sum = 0; - else if (volume != 0xFF) - sum = sum*volume/0xFF; + else if (volume != VOLUME_NORM) + sum = (int32_t) ((float) sum*volume/VOLUME_NORM); if (sum < -0x8000) sum = -0x8000; if (sum > 0x7FFF) sum = 0x7FFF; @@ -88,3 +89,40 @@ size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, si data += sizeof(int16_t); } } + + +void volume_memchunk(struct memchunk*c, struct pa_sample_spec *spec, uint32_t volume) { + int16_t *d; + size_t n; + assert(c && spec && (c->length % pa_sample_size(spec) == 0)); + assert(spec->format == PA_SAMPLE_S16NE); + memblock_assert_exclusive(c->memblock); + + if (volume == VOLUME_NORM) + return; + + if (volume == VOLUME_MUTE) { + silence_memchunk(c, spec); + return; + } + + for (d = (c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { + int32_t t = (int32_t)(*d); + + t *= volume; + t /= VOLUME_NORM; + + if (t < -0x8000) t = -0x8000; + if (t > 0x7FFF) t = 0x7FFF; + + *d = (int16_t) t; + } +} + +uint32_t volume_multiply(uint32_t a, uint32_t b) { + uint64_t p = a; + p *= b; + p /= VOLUME_NORM; + + return (uint32_t) p; +} diff --git a/src/sample-util.h b/src/sample-util.h index 0a3f7c89..2f2539d0 100644 --- a/src/sample-util.h +++ b/src/sample-util.h @@ -8,16 +8,23 @@ extern struct pa_sample_spec default_sample_spec; +#define VOLUME_NORM (0x100) +#define VOLUME_MUTE (0) + struct memblock *silence_memblock(struct memblock* b, struct pa_sample_spec *spec); void silence_memchunk(struct memchunk *c, struct pa_sample_spec *spec); void silence_memory(void *p, size_t length, struct pa_sample_spec *spec); struct mix_info { struct memchunk chunk; - uint8_t volume; + uint32_t volume; void *userdata; }; -size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct pa_sample_spec *spec, uint8_t volume); +size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct pa_sample_spec *spec, uint32_t volume); + +void volume_memchunk(struct memchunk*c, struct pa_sample_spec *spec, uint32_t volume); + +uint32_t volume_multiply(uint32_t a, uint32_t b); #endif diff --git a/src/sink.c b/src/sink.c index 5ab1a7a7..8a510f1b 100644 --- a/src/sink.c +++ b/src/sink.c @@ -39,7 +39,7 @@ struct sink* sink_new(struct core *core, const char *name, int fail, const struc assert(s->monitor_source); free(n); - s->volume = 0xFF; + s->volume = VOLUME_NORM; s->notify = NULL; s->get_latency = NULL; @@ -132,6 +132,7 @@ int sink_render(struct sink*s, size_t length, struct memchunk *result) { return -1; if (n == 1) { + uint32_t volume = VOLUME_NORM; struct sink_info *i = info[0].userdata; assert(i); *result = info[0].chunk; @@ -141,6 +142,14 @@ int sink_render(struct sink*s, size_t length, struct memchunk *result) { result->length = length; l = result->length; + + if (s->volume != VOLUME_NORM || info[0].volume != VOLUME_NORM) + volume = volume_multiply(s->volume, info[0].volume); + + if (volume != VOLUME_NORM) { + memchunk_make_writable(result); + volume_memchunk(result, &s->sample_spec, volume); + } } else { result->memblock = memblock_new(length); assert(result->memblock); @@ -164,6 +173,7 @@ int sink_render_into(struct sink*s, struct memchunk *target) { unsigned n; size_t l; assert(s && target && target->length && target->memblock && target->memblock->data); + memblock_assert_exclusive(target->memblock); n = fill_mix_info(s, info, MAX_MIX_CHANNELS); @@ -171,6 +181,7 @@ int sink_render_into(struct sink*s, struct memchunk *target) { return -1; if (n == 1) { + uint32_t volume = VOLUME_NORM; struct sink_info *i = info[0].userdata; assert(i); @@ -180,6 +191,12 @@ int sink_render_into(struct sink*s, struct memchunk *target) { memcpy(target->memblock->data+target->index, info[0].chunk.memblock->data + info[0].chunk.index, l); target->length = l; + + if (s->volume != VOLUME_NORM || info[0].volume != VOLUME_NORM) + volume = volume_multiply(s->volume, info[0].volume); + + if (volume != VOLUME_NORM) + volume_memchunk(target, &s->sample_spec, volume); } else target->length = l = mix_chunks(info, n, target->memblock->data+target->index, target->length, &s->sample_spec, s->volume); @@ -257,8 +274,9 @@ char *sink_list_to_string(struct core *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); + strbuf_printf(s, " %c index: %u, name: <%s>, volume: <0x%04x>, 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); } + diff --git a/src/sink.h b/src/sink.h index a5b1ff68..f251c0b9 100644 --- a/src/sink.h +++ b/src/sink.h @@ -20,7 +20,7 @@ struct sink { struct source *monitor_source; - uint8_t volume; + uint32_t volume; void (*notify)(struct sink*sink); uint32_t (*get_latency)(struct sink *s); diff --git a/src/sinkinput.c b/src/sinkinput.c index b81c9c71..54bc98a6 100644 --- a/src/sinkinput.c +++ b/src/sinkinput.c @@ -4,6 +4,7 @@ #include "sinkinput.h" #include "strbuf.h" +#include "sample-util.h" struct sink_input* sink_input_new(struct sink *s, struct pa_sample_spec *spec, const char *name) { struct sink_input *i; @@ -22,7 +23,7 @@ struct sink_input* sink_input_new(struct sink *s, struct pa_sample_spec *spec, c i->get_latency = NULL; i->userdata = NULL; - i->volume = 0xFF; + i->volume = VOLUME_NORM; assert(s->core); r = idxset_put(s->core->sink_inputs, i, &i->index); @@ -64,7 +65,7 @@ char *sink_input_list_to_string(struct core *c) { for (i = idxset_first(c->sink_inputs, &index); i; i = idxset_next(c->sink_inputs, &index)) { assert(i->sink); - strbuf_printf(s, " index: %u, name: <%s>, sink: <%u>; volume: <0x%02x>, latency: <%u usec>\n", + strbuf_printf(s, " index: %u, name: <%s>, sink: <%u>; volume: <0x%04x>, latency: <%u usec>\n", i->index, i->name, i->sink->index, diff --git a/src/sinkinput.h b/src/sinkinput.h index f04ecb95..4fe39e2a 100644 --- a/src/sinkinput.h +++ b/src/sinkinput.h @@ -13,7 +13,7 @@ struct sink_input { char *name; struct sink *sink; struct pa_sample_spec sample_spec; - uint8_t volume; + uint32_t volume; int (*peek) (struct sink_input *i, struct memchunk *chunk); void (*drop) (struct sink_input *i, size_t length); diff --git a/src/todo b/src/todo index 78768be0..e1cdb9f1 100644 --- a/src/todo +++ b/src/todo @@ -2,16 +2,17 @@ recording sync() function more functions +- esound protocol: + recording +- split oss-dma? - simple library - simple control protocol: kill client/input/output - set_volume - resampling -- volume adjust on single sink input -- fp volume scaling (both < and > 1) -- esound protocol - config parser/cmdline - record testing +- mixing/volume +- kill() routines in all modules -- 0.1 - future cancellation -- cgit From 961fb4466a9396a11f1a9a6e7d4193409b8949d6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 30 Jun 2004 00:00:52 +0000 Subject: latency esound volume changing git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@43 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/esound-spec.h | 1 + src/main.c | 2 +- src/protocol-esound.c | 131 +++++++++++++++++++++++++++++++++++++++++--------- src/socket-client.c | 4 ++ src/socket-server.c | 8 +++ src/util.c | 41 ++++++++++++++++ src/util.h | 3 ++ 7 files changed, 167 insertions(+), 23 deletions(-) diff --git a/src/esound-spec.h b/src/esound-spec.h index 1c2dc022..f7a4d3db 100644 --- a/src/esound-spec.h +++ b/src/esound-spec.h @@ -181,6 +181,7 @@ typedef int esd_client_state_t; /* switch endian order for cross platform playing */ #define swap_endian_32(x) ((x >> 24) | ((x >> 8) & 0xFF00) | (((x & 0xFF00) << 8)) | (x << 24)) +#define maybe_swap_endian_32(c,x) ((c) ? swap_endian_32(x) : x) /* the endian key is transferred in binary, if it's read into int, */ /* and matches ESD_ENDIAN_KEY (ENDN), then the endianness of the */ diff --git a/src/main.c b/src/main.c index 3512c5ba..e50321f8 100644 --- a/src/main.c +++ b/src/main.c @@ -38,7 +38,7 @@ int main(int argc, char *argv[]) { c = core_new(pa_mainloop_get_api(mainloop)); assert(c); - module_load(c, "module-oss", "/dev/dsp1"); + 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-simple-protocol-unix", NULL); diff --git a/src/protocol-esound.c b/src/protocol-esound.c index 5db7a13f..56c85285 100644 --- a/src/protocol-esound.c +++ b/src/protocol-esound.c @@ -16,6 +16,7 @@ /* This is heavily based on esound's code */ struct connection { + uint32_t index; struct protocol_esound *protocol; struct iochannel *io; struct client *client; @@ -36,6 +37,7 @@ struct protocol_esound { struct socket_server *server; struct idxset *connections; uint32_t sink_index; + unsigned n_player; }; typedef struct proto_handler { @@ -47,7 +49,7 @@ typedef struct proto_handler { #define MEMBLOCKQ_LENGTH (10*1204) #define MEMBLOCKQ_PREBUF (2*1024) -#define BUFSIZE PIPE_BUF +#define BUFSIZE (1024) static void sink_input_drop_cb(struct sink_input *i, size_t length); static int sink_input_peek_cb(struct sink_input *i, struct memchunk *chunk); @@ -59,6 +61,8 @@ static int esd_proto_stream_play(struct connection *c, const void *data, size_t static int esd_proto_stream_record(struct connection *c, const void *data, size_t length); static int esd_proto_get_latency(struct connection *c, const void *data, size_t length); static int esd_proto_server_info(struct connection *c, const void *data, size_t length); +static int esd_proto_all_info(struct connection *c, const void *data, size_t length); +static int esd_proto_stream_pan(struct connection *c, const void *data, size_t length); static int do_write(struct connection *c); @@ -86,11 +90,11 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = { { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" }, { sizeof(int), esd_proto_server_info, "server info" }, - { sizeof(int), NULL, "all info" }, + { sizeof(int), esd_proto_all_info, "all info" }, { -1, NULL, "TODO: subscribe" }, { -1, NULL, "TODO: unsubscribe" }, - { 3 * sizeof(int), NULL, "stream pan"}, + { 3 * sizeof(int), esd_proto_stream_pan, "stream pan"}, { 3 * sizeof(int), NULL, "sample pan" }, { sizeof(int), NULL, "standby mode" }, @@ -102,6 +106,9 @@ static void connection_free(struct connection *c) { assert(c); idxset_remove_by_data(c->protocol->connections, c, NULL); + if (c->state == ESD_STREAMING_DATA) + c->protocol->n_player--; + client_free(c->client); if (c->sink_input) @@ -170,9 +177,6 @@ static int esd_proto_connect(struct connection *c, const void *data, size_t leng ok = connection_write(c, sizeof(int)); assert(ok); *ok = 1; - - do_write(c); - return 0; } @@ -183,13 +187,8 @@ static int esd_proto_stream_play(struct connection *c, const void *data, size_t struct pa_sample_spec ss; assert(length == (sizeof(int)*2+ESD_NAME_MAX)); - format = *(int*)data; - rate = *((int*)data + 1); - - if (c->swap_byte_order) - format = swap_endian_32(format); - if (c->swap_byte_order) - rate = swap_endian_32(rate); + format = maybe_swap_endian_32(c->swap_byte_order, *(int*)data); + rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); ss.rate = rate; ss.channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; @@ -222,6 +221,8 @@ static int esd_proto_stream_play(struct connection *c, const void *data, size_t c->state = ESD_STREAMING_DATA; + c->protocol->n_player++; + return 0; } @@ -234,21 +235,19 @@ static int esd_proto_stream_record(struct connection *c, const void *data, size_ static int esd_proto_get_latency(struct connection *c, const void *data, size_t length) { struct sink *sink; int latency, *lag; - assert(c && data && length == 0); + assert(c && !data && length == 0); if (!(sink = get_output_sink(c->protocol))) latency = 0; else { float usec = sink_get_latency(sink); - usec += pa_samples_usec(MEMBLOCKQ_LENGTH, &sink->sample_spec); - latency = (int) (usec*441/10000); + usec += pa_samples_usec(MEMBLOCKQ_LENGTH-BUFSIZE, &sink->sample_spec); + latency = (int) ((usec*44100)/1000000); } lag = connection_write(c, sizeof(int)); assert(lag); *lag = c->swap_byte_order ? swap_endian_32(latency) : latency; - - do_write(c); return 0; } @@ -267,9 +266,94 @@ static int esd_proto_server_info(struct connection *c, const void *data, size_t response = connection_write(c, sizeof(int)*3); assert(response); *(response++) = 0; - *(response++) = c->swap_byte_order ? swap_endian_32(rate) : rate; - *(response++) = c->swap_byte_order ? swap_endian_32(format) : format; - do_write(c); + *(response++) = maybe_swap_endian_32(c->swap_byte_order, rate); + *(response++) = maybe_swap_endian_32(c->swap_byte_order, format); + return 0; +} + +static int esd_proto_all_info(struct connection *c, const void *data, size_t length) { + void *response; + size_t t, k, s; + struct connection *conn; + size_t index = IDXSET_INVALID; + assert(c && data && length == sizeof(int)); + + if (esd_proto_server_info(c, data, length) < 0) + return -1; + + k = sizeof(int)*5+ESD_NAME_MAX; + s = sizeof(int)*6+ESD_NAME_MAX; + response = connection_write(c, (t = s+k*(c->protocol->n_player+1))); + assert(k); + + for (conn = idxset_first(c->protocol->connections, &index); conn; conn = idxset_next(c->protocol->connections, &index)) { + int format = ESD_BITS16 | ESD_STEREO, rate = 44100, volume = 0xFF; + + if (conn->state != ESD_STREAMING_DATA) + continue; + + assert(t >= s+k+k); + + if (conn->sink_input) { + rate = conn->sink_input->sample_spec.rate; + volume = (conn->sink_input->volume*0xFF)/0x100; + format = (conn->sink_input->sample_spec.format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16; + format |= (conn->sink_input->sample_spec.channels >= 2) ? ESD_STEREO : ESD_MONO; + } + + /* id */ + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (int) conn->index); + response += sizeof(int); + + /* name */ + assert(conn->client); + strncpy(response, conn->client->name, ESD_NAME_MAX); + response += ESD_NAME_MAX; + + /* rate */ + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, rate); + response += sizeof(int); + + /* left */ + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, volume); + response += sizeof(int); + + /*right*/ + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, volume); + response += sizeof(int); + + /*format*/ + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, format); + response += sizeof(int); + + t-= k; + } + + assert(t == s+k); + memset(response, 0, t); + return 0; +} + +static int esd_proto_stream_pan(struct connection *c, const void *data, size_t length) { + int *ok; + uint32_t index, volume; + struct connection *conn; + assert(c && data && length == sizeof(int)*3); + + index = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *(int*)data); + volume = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); + volume = (volume*0x100)/0xFF; + + ok = connection_write(c, sizeof(int)); + assert(ok); + + if ((conn = idxset_get_by_index(c->protocol->connections, index))) { + assert(conn->sink_input); + conn->sink_input->volume = volume; + *ok = 1; + } else + *ok = 0; + return 0; } @@ -380,6 +464,7 @@ static int do_read(struct connection *c) { memblock_unref(chunk.memblock); assert(c->sink_input); sink_notify(c->sink_input->sink); + } else assert(0); @@ -487,7 +572,7 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c->sink_input = NULL; c->input_memblockq = NULL; - idxset_put(c->protocol->connections, c, NULL); + idxset_put(c->protocol->connections, c, &c->index); } /*** entry points ***/ @@ -505,6 +590,8 @@ struct protocol_esound* protocol_esound_new(struct core*core, struct socket_serv assert(p->connections); p->sink_index = IDXSET_INVALID; + p->n_player = 0; + socket_server_set_callback(p->server, on_connection, p); return p; diff --git a/src/socket-client.c b/src/socket-client.c index b10f8ab1..95c76813 100644 --- a/src/socket-client.c +++ b/src/socket-client.c @@ -120,6 +120,8 @@ struct socket_client* socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t goto fail; } + make_tcp_socket_low_delay(c->fd); + sa.sin_family = AF_INET; sa.sin_port = htons(port); sa.sin_addr.s_addr = htonl(address); @@ -147,6 +149,8 @@ struct socket_client* socket_client_new_unix(struct pa_mainloop_api *m, const ch goto fail; } + make_socket_low_delay(c->fd); + sa.sun_family = AF_LOCAL; strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); sa.sun_path[sizeof(sa.sun_path) - 1] = 0; diff --git a/src/socket-server.c b/src/socket-server.c index 87fe1476..bd590f3c 100644 --- a/src/socket-server.c +++ b/src/socket-server.c @@ -11,6 +11,7 @@ #include #include "socket-server.h" +#include "util.h" struct socket_server { int fd; @@ -39,6 +40,9 @@ static void callback(struct pa_mainloop_api *mainloop, void *id, int fd, enum pa return; } + /* There should be a check for socket type here */ + make_tcp_socket_low_delay(fd); + io = iochannel_new(s->mainloop, nfd, nfd); assert(io); s->on_connection(s, io, s->userdata); @@ -78,6 +82,8 @@ struct socket_server* socket_server_new_unix(struct pa_mainloop_api *m, const ch strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); sa.sun_path[sizeof(sa.sun_path) - 1] = 0; + make_socket_low_delay(fd); + if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) { fprintf(stderr, "bind(): %s\n", strerror(errno)); goto fail; @@ -117,6 +123,8 @@ struct socket_server* socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) fprintf(stderr, "setsockopt(): %s\n", strerror(errno)); + + make_tcp_socket_low_delay(fd); sa.sin_family = AF_INET; sa.sin_port = htons(port); diff --git a/src/util.c b/src/util.c index 95350421..8f444336 100644 --- a/src/util.c +++ b/src/util.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include "util.h" @@ -83,3 +85,42 @@ fail: rmdir(dir); return -1; } + +int make_socket_low_delay(int fd) { + int ret = 0, buf_size, priority; + + assert(fd >= 0); + + buf_size = 1024; + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof(buf_size)) < 0) + ret = -1; + + buf_size = 1024; + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(buf_size)) < 0) + ret = -1; + + priority = 7; + if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) + ret = -1; + + return ret; +} + +int make_tcp_socket_low_delay(int fd) { + int ret, tos, on; + + assert(fd >= 0); + + ret = make_socket_low_delay(fd); + + on = 1; + if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) + ret = -1; + + tos = IPTOS_LOWDELAY; + if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0) + ret = -1; + + return ret; + +} diff --git a/src/util.h b/src/util.h index 2a507198..8e9a3796 100644 --- a/src/util.h +++ b/src/util.h @@ -7,4 +7,7 @@ void peer_to_string(char *c, size_t l, int fd); int make_secure_dir(const char* dir); +int make_socket_low_delay(int fd); +int make_tcp_socket_low_delay(int fd); + #endif -- cgit From 13b35a2489e7e1d6341effe6e25b8cb8a0a94a02 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 2 Jul 2004 18:47:03 +0000 Subject: add resampler git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@44 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 11 ++-- src/endianmacros.h | 41 ++++++++++++++ src/iochannel.c | 2 +- src/resampler.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/resampler.h | 15 +++++ src/sample.c | 8 +-- src/sample.h | 12 ++-- src/sconv.c | 99 ++++++++++++++++++++++++++++++++ src/sconv.h | 14 +++++ src/sinkinput.c | 1 + src/sinkinput.h | 3 + src/todo | 5 +- 12 files changed, 357 insertions(+), 16 deletions(-) create mode 100644 src/endianmacros.h create mode 100644 src/resampler.c create mode 100644 src/resampler.h create mode 100644 src/sconv.c create mode 100644 src/sconv.h diff --git a/src/Makefile.am b/src/Makefile.am index af4478be..7982802e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -52,12 +52,13 @@ polypaudio_SOURCES = idxset.c idxset.h \ mainloop-api.c mainloop-api.h \ util.c util.h \ hashset.c hashset.h \ - namereg.c namereg.h - -polypaudio_CFLAGS = $(AM_CFLAGS) - + namereg.c namereg.h \ + sconv.c sconv.h \ + resampler.c resampler.h \ + endianmacros.h +polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) -polypaudio_LDADD = $(LIBLTDL) +polypaudio_LDADD = $(LIBLTDL) $(LIBSAMPLERATE_LIBS) polypaudio_LDFLAGS=-export-dynamic libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h diff --git a/src/endianmacros.h b/src/endianmacros.h new file mode 100644 index 00000000..2394b3e8 --- /dev/null +++ b/src/endianmacros.h @@ -0,0 +1,41 @@ +#ifndef fooendianmacroshfoo +#define fooendianmacroshfoo + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define INT16_SWAP(x) ((int16_t)(((int16_t) x >> 8) | ((int16_t) x << 8))) +#define UINT16_SWAP(x) ((uint16_t)(((uint16_t) x >> 8) | ((uint16_t) x << 8))) +#define INT32_SWAP(x) ((int32_t)(((int32_t) x >> 24) | ((int32_t) x << 24) | (((int32_t) x & 0xFF00) << 16) | (((int32_t) x) >> 16) & 0xFF00)) +#define UINT32_SWAP(x) ((uint32_t)(((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 16) | (((uint32_t) x) >> 16) & 0xFF00)) + +#ifdef WORDS_BIGENDIAN + #define INT16_FROM_LE(x) INT16_SWAP(x) + #define INT16_FROM_BE(x) ((int16_t)(x)) + #define INT16_TO_LE(x) INT16_SWAP(x) + #define INT16_TO_BE(x) ((int16_t)(x)) + + #define UINT16_FROM_LE(x) UINT16_SWAP(x) + #define UINT16_FROM_BE(x) ((uint16_t)(x)) + #define INT32_FROM_LE(x) INT32_SWAP(x) + #define INT32_FROM_BE(x) ((int32_t)(x)) + #define UINT32_FROM_LE(x) UINT32_SWAP(x) + #define UINT32_FROM_BE(x) ((uint32_t)(x)) +#else + #define INT16_FROM_LE(x) ((int16_t)(x)) + #define INT16_FROM_BE(x) INT16_SWAP(x) + #define INT16_TO_LE(x) ((int16_t)(x)) + #define INT16_TO_BE(x) INT16_SWAP(x) + + #define UINT16_FROM_LE(x) ((uint16_t)(x)) + #define UINT16_FROM_BE(x) UINT16_SWAP(x) + #define INT32_FROM_LE(x) ((int32_t)(x)) + #define INT32_FROM_BE(x) INT32_SWAP(x) + #define UINT32_FROM_LE(x) ((uint32_t)(x)) + #define UINT32_FROM_BE(x) UINT32_SWAP(x) +#endif + +#endif diff --git a/src/iochannel.c b/src/iochannel.c index fa55875f..25d6b05e 100644 --- a/src/iochannel.c +++ b/src/iochannel.c @@ -1,6 +1,6 @@ +#include #include #include -#include #include #include "iochannel.h" diff --git a/src/resampler.c b/src/resampler.c new file mode 100644 index 00000000..aa37f1ac --- /dev/null +++ b/src/resampler.c @@ -0,0 +1,162 @@ +#include +#include + +#include + +#include "resampler.h" +#include "sconv.h" + +struct resampler { + struct pa_sample_spec i_ss, o_ss; + float* i_buf, *o_buf; + unsigned i_alloc, o_alloc; + size_t i_sz, o_sz; + + int channels; + + convert_to_float32_func_t to_float32_func; + convert_from_float32_func_t from_float32_func; + SRC_STATE *src_state; +}; + +struct resampler* resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b) { + struct resampler *r; + int err; + assert(a && b && pa_sample_spec_valid(a) && pa_sample_spec_valid(b)); + + if (a->channels != b->channels && a->channels != 1 && b->channels != 1) + goto fail; + + if (a->format == PA_SAMPLE_ALAW || a->format == PA_SAMPLE_ULAW || b->format == PA_SAMPLE_ALAW || b->format == PA_SAMPLE_ULAW) + goto fail; + + r->channels = a->channels; + if (b->channels < r->channels) + r->channels = b->channels; + + r = malloc(sizeof(struct resampler)); + assert(r); + r->i_buf = r->o_buf = NULL; + r->i_alloc = r->o_alloc = 0; + + if (a->rate != b->rate) { + r->src_state = src_new(SRC_SINC_FASTEST, r->channels, &err); + if (err != 0 || !r->src_state) + goto fail; + } else + r->src_state = NULL; + + r->i_ss = *a; + r->o_ss = *b; + + r->i_sz = pa_sample_size(a); + r->o_sz = pa_sample_size(b); + + r->to_float32_func = get_convert_to_float32_function(a->format); + r->from_float32_func = get_convert_from_float32_function(b->format); + + assert(r->to_float32_func && r->from_float32_func); + + return r; + +fail: + if (r) + free(r); + + return NULL; +} + +void resampler_free(struct resampler *r) { + assert(r); + if (r->src_state) + src_delete(r->src_state); + free(r->i_buf); + free(r->o_buf); + free(r); +} + +size_t resampler_request(struct resampler *r, size_t out_length) { + assert(r && (out_length % r->o_sz) == 0); + + return (((out_length / r->o_sz)*r->i_ss.rate)/r->o_ss.rate) * r->i_sz; +} + + +int resampler_run(struct resampler *r, struct memchunk *in, struct memchunk *out) { + unsigned i_nchannels, o_nchannels, ins, ons, eff_ins, eff_ons; + float *cbuf; + size_t in_bytes_used = 0; + assert(r && in && out && in->length && in->memblock); + + /* How many input samples? */ + ins = in->length/r->i_sz; + + /* How much space for output samples? */ + if (r->src_state) + ons = (ins*r->o_ss.rate/r->i_ss.rate)+1024; + else + ons = ins; + + /* How many channels? */ + if (r->i_ss.channels == r->o_ss.channels) { + i_nchannels = o_nchannels = 1; + eff_ins = ins*r->i_ss.channels; /* effective samples */ + eff_ons = ons*r->o_ss.channels; + } else { + i_nchannels = r->i_ss.channels; + o_nchannels = r->o_ss.channels; + eff_ins = ins; + eff_ons = ons; + } + + out->memblock = memblock_new(out->length = (ons*r->o_sz)); + out->index = 0; + assert(out->memblock); + + if (r->i_alloc < eff_ins) + r->i_buf = realloc(r->i_buf, sizeof(float) * (r->i_alloc = eff_ins)); + assert(r->i_buf); + + r->to_float32_func(eff_ins, in->memblock->data+in->index, i_nchannels, r->i_buf); + + if (r->src_state) { + int ret; + SRC_DATA data; + + if (r->o_alloc < eff_ons) + r->o_buf = realloc(r->o_buf, sizeof(float) * (r->o_alloc = eff_ons)); + assert(r->o_buf); + + data.data_in = r->i_buf; + data.input_frames = ins; + + data.data_out = r->o_buf; + data.output_frames = ons; + + data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate; + data.end_of_input = 0; + + ret = src_process(r->src_state, &data); + assert(ret == 0); + + in_bytes_used = data.input_frames_used*r->i_sz; + cbuf = r->o_buf; + ons = data.output_frames_gen; + + if (r->i_ss.channels == r->o_ss.channels) + eff_ons = ons*r->o_ss.channels; + else + eff_ons = ons; + } else { + in_bytes_used = ins*r->i_sz; + cbuf = r->i_buf; + } + + assert(in_bytes_used < in->length); + in->index += in_bytes_used; + in->length -= in_bytes_used; + + r->from_float32_func(eff_ons, cbuf, out->memblock->data+out->index, o_nchannels); + out->length = ons*r->o_sz; + return 0; +} diff --git a/src/resampler.h b/src/resampler.h new file mode 100644 index 00000000..000f73ce --- /dev/null +++ b/src/resampler.h @@ -0,0 +1,15 @@ +#ifndef fooresamplerhfoo +#define fooresamplerhfoo + +#include "sample.h" +#include "memblock.h" + +struct resampler; + +struct resampler* resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b); +void resampler_free(struct resampler *r); + +size_t resampler_request(struct resampler *r, size_t out_length); +int resampler_run(struct resampler *r, struct memchunk *in, struct memchunk *out); + +#endif diff --git a/src/sample.c b/src/sample.c index b0d0cdbd..497358fa 100644 --- a/src/sample.c +++ b/src/sample.c @@ -2,7 +2,7 @@ #include "sample.h" -size_t pa_sample_size(struct pa_sample_spec *spec) { +size_t pa_sample_size(const struct pa_sample_spec *spec) { assert(spec); size_t b = 1; @@ -26,19 +26,19 @@ size_t pa_sample_size(struct pa_sample_spec *spec) { return b * spec->channels; } -size_t pa_bytes_per_second(struct pa_sample_spec *spec) { +size_t pa_bytes_per_second(const struct pa_sample_spec *spec) { assert(spec); return spec->rate*pa_sample_size(spec); } -uint32_t pa_samples_usec(size_t length, struct pa_sample_spec *spec) { +uint32_t pa_samples_usec(size_t length, const struct pa_sample_spec *spec) { assert(spec); return (uint32_t) (((double) length /pa_sample_size(spec))/spec->rate*1000000); } -int pa_sample_spec_valid(struct pa_sample_spec *spec) { +int pa_sample_spec_valid(const struct pa_sample_spec *spec) { assert(spec); if (!spec->rate || !spec->channels) diff --git a/src/sample.h b/src/sample.h index 697937e0..1fd764d7 100644 --- a/src/sample.h +++ b/src/sample.h @@ -14,7 +14,11 @@ enum pa_sample_format { PA_SAMPLE_MAX }; +#ifdef WORDS_BIGENDIAN +#define PA_SAMPLE_S16NE PA_SAMPLE_S16BE +#else #define PA_SAMPLE_S16NE PA_SAMPLE_S16LE +#endif struct pa_sample_spec { enum pa_sample_format format; @@ -22,10 +26,10 @@ struct pa_sample_spec { uint8_t channels; }; -size_t pa_bytes_per_second(struct pa_sample_spec *spec); -size_t pa_sample_size(struct pa_sample_spec *spec); -uint32_t pa_samples_usec(size_t length, struct pa_sample_spec *spec); +size_t pa_bytes_per_second(const struct pa_sample_spec *spec); +size_t pa_sample_size(const struct pa_sample_spec *spec); +uint32_t pa_samples_usec(size_t length, const struct pa_sample_spec *spec); -int pa_sample_spec_valid(struct pa_sample_spec *spec); +int pa_sample_spec_valid(const struct pa_sample_spec *spec); #endif diff --git a/src/sconv.c b/src/sconv.c new file mode 100644 index 00000000..11438b41 --- /dev/null +++ b/src/sconv.c @@ -0,0 +1,99 @@ +#include +#include +#include "endianmacros.h" +#include "sconv.h" + +static void s16le_to_float32(unsigned n, const void *a, unsigned an, float *b) { + const int16_t *ca = a; + assert(n && a && an && b); + + for (; n > 0; n--) { + unsigned i; + float sum = 0; + + for (i = 0; i < an; i++) { + int16_t s = *(ca++); + sum += ((float) INT16_FROM_LE(s))/0x7FFF; + } + + if (sum > 1) + sum = 1; + if (sum < -1) + sum = -1; + + *(b++) = sum; + } +} + +static void s16le_from_float32(unsigned n, const float *a, void *b, unsigned bn) { + int16_t *cb = b; + assert(n && a && b && bn); + + for (; n > 0; n--) { + unsigned i; + int16_t s; + float v = *(a++); + + if (v > 1) + v = 1; + if (v < -1) + v = -1; + + s = (int16_t) (v * 0x7FFF); + + for (i = 0; i < bn; i++) + *(cb++) = INT16_TO_LE(v); + } +} + +static void float32_to_float32(unsigned n, const void *a, unsigned an, float *b) { + unsigned i; + const float *ca = a; + assert(n && a && an && b); + for (; n > 0; n--) { + float sum = 0; + + for (i = 0; i < an; i++) + sum += *(ca++); + + if (sum > 1) + sum = 1; + if (sum < -1) + sum = -1; + + *(b++) = sum; + } +} + +static void float32_from_float32(unsigned n, const float *a, void *b, unsigned bn) { + unsigned i; + float *cb = b; + assert(n && a && b && bn); + for (; n > 0; n--) { + float v = *(a++); + for (i = 0; i < bn; i++) + *(cb++) = v; + } +} + +convert_to_float32_func_t get_convert_to_float32_function(enum pa_sample_format f) { + switch(f) { + case PA_SAMPLE_S16LE: + return s16le_to_float32; + case PA_SAMPLE_FLOAT32: + return float32_to_float32; + default: + return NULL; + } +} + +convert_from_float32_func_t get_convert_from_float32_function(enum pa_sample_format f) { + switch(f) { + case PA_SAMPLE_S16LE: + return s16le_from_float32; + case PA_SAMPLE_FLOAT32: + return float32_from_float32; + default: + return NULL; + } +} diff --git a/src/sconv.h b/src/sconv.h new file mode 100644 index 00000000..8667d2ae --- /dev/null +++ b/src/sconv.h @@ -0,0 +1,14 @@ +#ifndef foosconvhfoo +#define foosconvhfoo + +#include "sample.h" + +typedef void (*convert_to_float32_func_t)(unsigned n, const void *a, unsigned an, float *b); +typedef void (*convert_from_float32_func_t)(unsigned n, const float *a, void *b, unsigned bn); + +convert_to_float32_func_t get_convert_to_float32_function(enum pa_sample_format f); +convert_from_float32_func_t get_convert_from_float32_function(enum pa_sample_format f); + + + +#endif diff --git a/src/sinkinput.c b/src/sinkinput.c index 54bc98a6..dd0504d0 100644 --- a/src/sinkinput.c +++ b/src/sinkinput.c @@ -88,3 +88,4 @@ uint32_t sink_input_get_latency(struct sink_input *i) { return l; } + diff --git a/src/sinkinput.h b/src/sinkinput.h index 4fe39e2a..e3114d94 100644 --- a/src/sinkinput.h +++ b/src/sinkinput.h @@ -33,4 +33,7 @@ void sink_input_kill(struct sink_input *i); uint32_t sink_input_get_latency(struct sink_input *i); char *sink_input_list_to_string(struct core *c); + + + #endif diff --git a/src/todo b/src/todo index e1cdb9f1..0dd999a1 100644 --- a/src/todo +++ b/src/todo @@ -4,20 +4,21 @@ more functions - esound protocol: recording -- split oss-dma? +- move more stuff from module-oss[-dma] to liboss-util - simple library - simple control protocol: kill client/input/output +- kill() routines in all modules - resampling - config parser/cmdline - record testing - mixing/volume -- kill() routines in all modules -- 0.1 - future cancellation - client-ui - clip cache +- autoloading/autounloading drivers: - libao -- cgit From 741aa44ffc8afd63cd29e5ae46f778dc68340df8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 3 Jul 2004 00:19:17 +0000 Subject: add resampling git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@45 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 6 +++-- src/iochannel.c | 6 ++--- src/main.c | 12 ++++----- src/memblock.c | 14 ----------- src/memblock.h | 7 ------ src/memblockq.c | 41 +++++++++++++++++++++++++++--- src/memblockq.h | 27 +++++++++++++++++--- src/pacat.c | 2 +- src/polyp.c | 2 +- src/protocol-esound.c | 6 ++--- src/protocol-native.c | 4 +-- src/protocol-simple.c | 57 +++++++++++++++++++++-------------------- src/pstream.h | 1 + src/resampler.c | 23 ++++++----------- src/resampler.h | 3 ++- src/sample-util.h | 1 + src/sample.c | 6 +++++ src/sample.h | 2 +- src/sink.c | 8 +++--- src/sinkinput.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/sinkinput.h | 10 +++++--- src/source.c | 2 +- src/source.h | 1 + src/sourceoutput.c | 29 ++++++++++++++++++++- src/sourceoutput.h | 9 +++++-- src/todo | 17 ++++++------- 26 files changed, 251 insertions(+), 115 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 7982802e..ec234481 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -55,7 +55,8 @@ polypaudio_SOURCES = idxset.c idxset.h \ namereg.c namereg.h \ sconv.c sconv.h \ resampler.c resampler.h \ - endianmacros.h + endianmacros.h \ + memchunk.c memchunk.h polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) polypaudio_LDADD = $(LIBLTDL) $(LIBSAMPLERATE_LIBS) @@ -196,7 +197,8 @@ libpolyp_la_SOURCES = polyp.c polyp.h \ socket-client.c socket-client.h \ packet.c packet.h \ queue.c queue.h \ - dynarray.c dynarray.h + dynarray.c dynarray.h \ + memchunk.c memchunk.h pacat_SOURCES = pacat.c pacat_LDADD = libpolyp.la diff --git a/src/iochannel.c b/src/iochannel.c index 25d6b05e..a133fdef 100644 --- a/src/iochannel.c +++ b/src/iochannel.c @@ -15,7 +15,7 @@ struct iochannel { int readable; int writable; - + int no_close; void* input_source, *output_source; @@ -147,8 +147,8 @@ ssize_t iochannel_write(struct iochannel*io, const void*data, size_t l) { ssize_t iochannel_read(struct iochannel*io, void*data, size_t l) { ssize_t r; - assert(io && data && l && io->ifd >= 0); - + assert(io && data && io->ifd >= 0); + if ((r = read(io->ifd, data, l)) >= 0) { io->readable = 0; enable_mainloop_sources(io); diff --git a/src/main.c b/src/main.c index e50321f8..67109682 100644 --- a/src/main.c +++ b/src/main.c @@ -38,15 +38,15 @@ int main(int argc, char *argv[]) { c = core_new(pa_mainloop_get_api(mainloop)); assert(c); - module_load(c, "module-oss-mmap", "/dev/dsp1"); -/* module_load(c, "module-pipe-sink", NULL); + module_load(c, "module-oss-mmap", "/dev/dsp"); +/* module_load(c, "module-pipe-sink", NULL);*/ module_load(c, "module-simple-protocol-tcp", NULL); - module_load(c, "module-simple-protocol-unix", NULL); +/* module_load(c, "module-simple-protocol-unix", NULL); module_load(c, "module-cli-protocol-tcp", NULL); module_load(c, "module-cli-protocol-unix", NULL); - module_load(c, "module-native-protocol-tcp", NULL); - module_load(c, "module-native-protocol-unix", NULL);*/ - module_load(c, "module-esound-protocol-tcp", NULL); + module_load(c, "module-native-protocol-tcp", NULL);*/ + module_load(c, "module-native-protocol-unix", NULL); +/* module_load(c, "module-esound-protocol-tcp", NULL);*/ module_load(c, "module-cli", NULL); fprintf(stderr, "main: mainloop entry.\n"); diff --git a/src/memblock.c b/src/memblock.c index 79fe2977..067243c5 100644 --- a/src/memblock.c +++ b/src/memblock.c @@ -78,17 +78,3 @@ void memblock_unref_fixed(struct memblock *b) { b->type = MEMBLOCK_DYNAMIC; } -void memchunk_make_writable(struct memchunk *c) { - struct memblock *n; - assert(c && c->memblock && c->memblock->ref >= 1); - - if (c->memblock->ref == 1) - return; - - n = memblock_new(c->length); - assert(n); - memcpy(n->data, c->memblock->data+c->index, c->length); - memblock_unref(c->memblock); - c->memblock = n; - c->index = 0; -} diff --git a/src/memblock.h b/src/memblock.h index 0c215e85..e4a578b8 100644 --- a/src/memblock.h +++ b/src/memblock.h @@ -13,11 +13,6 @@ struct memblock { void *data; }; -struct memchunk { - struct memblock *memblock; - size_t index, length; -}; - struct memblock *memblock_new(size_t length); struct memblock *memblock_new_fixed(void *data, size_t length); struct memblock *memblock_new_dynamic(void *data, size_t length); @@ -29,8 +24,6 @@ void memblock_unref_fixed(struct memblock*b); #define memblock_assert_exclusive(b) assert((b)->ref == 1) -void memchunk_make_writable(struct memchunk *c); - extern unsigned memblock_count, memblock_total; #endif diff --git a/src/memblockq.c b/src/memblockq.c index 9a601c3a..cab02bed 100644 --- a/src/memblockq.c +++ b/src/memblockq.c @@ -18,6 +18,7 @@ struct memblockq { size_t total_length, maxlength, base, prebuf; int measure_delay; uint32_t delay; + struct mcalign *mcalign; }; struct memblockq* memblockq_new(size_t maxlength, size_t base, size_t prebuf) { @@ -40,6 +41,8 @@ struct memblockq* memblockq_new(size_t maxlength, size_t base, size_t prebuf) { bq->measure_delay = 0; bq->delay = 0; + + bq->mcalign = NULL; return bq; } @@ -48,6 +51,9 @@ void memblockq_free(struct memblockq* bq) { struct memblock_list *l; assert(bq); + if (bq->mcalign) + mcalign_free(bq->mcalign); + while ((l = bq->blocks)) { bq->blocks = l->next; memblock_unref(l->chunk.memblock); @@ -57,9 +63,9 @@ void memblockq_free(struct memblockq* bq) { free(bq); } -void memblockq_push(struct memblockq* bq, struct memchunk *chunk, size_t delta) { +void memblockq_push(struct memblockq* bq, const struct memchunk *chunk, size_t delta) { struct memblock_list *q; - assert(bq && chunk && chunk->memblock && chunk->length); + assert(bq && chunk && chunk->memblock && chunk->length && (chunk->length % bq->base) == 0); q = malloc(sizeof(struct memblock_list)); assert(q); @@ -97,9 +103,14 @@ int memblockq_peek(struct memblockq* bq, struct memchunk *chunk) { *chunk = bq->blocks->chunk; memblock_ref(chunk->memblock); + + if (chunk->memblock->ref != 2) + fprintf(stderr, "block %p with ref %u peeked.\n", chunk->memblock, chunk->memblock->ref); + return 0; } +/* int memblockq_pop(struct memblockq* bq, struct memchunk *chunk) { struct memblock_list *q; @@ -121,6 +132,7 @@ int memblockq_pop(struct memblockq* bq, struct memchunk *chunk) { free(q); return 0; } +*/ static uint32_t age(struct timeval *tv) { assert(tv); @@ -143,7 +155,7 @@ static uint32_t age(struct timeval *tv) { } void memblockq_drop(struct memblockq *bq, size_t length) { - assert(bq); + assert(bq && length && (length % bq->base) == 0); while (length > 0) { size_t l = length; @@ -229,3 +241,26 @@ uint32_t memblockq_missing_to(struct memblockq *bq, size_t qlen) { return qlen - bq->total_length; } + +void memblockq_push_align(struct memblockq* bq, const struct memchunk *chunk, size_t delta) { + struct memchunk rchunk; + assert(bq && chunk && bq->base); + + if (bq->base == 1) { + memblockq_push(bq, chunk, delta); + return; + } + + if (!bq->mcalign) { + bq->mcalign = mcalign_new(bq->base); + assert(bq->mcalign); + } + + mcalign_push(bq->mcalign, chunk); + + while (mcalign_pop(bq->mcalign, &rchunk) >= 0) { + memblockq_push(bq, &rchunk, delta); + memblock_unref(rchunk.memblock); + delta = 0; + } +} diff --git a/src/memblockq.h b/src/memblockq.h index a681ff08..d19aac0e 100644 --- a/src/memblockq.h +++ b/src/memblockq.h @@ -4,27 +4,48 @@ #include #include "memblock.h" +#include "memchunk.h" struct memblockq; +/* Parameters: the maximum length of the memblock queue, a base value +for all operations (that is, all byte operations shall work on +multiples of this base value) and an amount of bytes to prebuffer +before having memblockq_peek() succeed. */ struct memblockq* memblockq_new(size_t maxlength, size_t base, size_t prebuf); -void memblockq_free(struct memblockq* bq); +void memblockq_free(struct memblockq*bq); -void memblockq_push(struct memblockq* bq, struct memchunk *chunk, size_t delta); +/* Push a new memory chunk into the queue. Optionally specify a value for future cancellation. This is currently not implemented, however! */ +void memblockq_push(struct memblockq* bq, const struct memchunk *chunk, size_t delta); -int memblockq_pop(struct memblockq* bq, struct memchunk *chunk); +/* Same as memblockq_push(), however chunks are filtered through a mcalign object, and thus aligned to multiples of base */ +void memblockq_push_align(struct memblockq* bq, const struct memchunk *chunk, size_t delta); + +/* Return a copy of the next memory chunk in the queue. It is not removed from the queue */ int memblockq_peek(struct memblockq* bq, struct memchunk *chunk); + +/* Drop the specified bytes from the queue */ void memblockq_drop(struct memblockq *bq, size_t length); +/* Shorten the memblockq to the specified length by dropping data at the end of the queue */ void memblockq_shorten(struct memblockq *bq, size_t length); + +/* Empty the memblockq */ void memblockq_empty(struct memblockq *bq); +/* Test if the memblockq is currently readable, that is, more data than base */ int memblockq_is_readable(struct memblockq *bq); + +/* Test if the memblockq is currently writable for the specified amount of bytes */ int memblockq_is_writable(struct memblockq *bq, size_t length); +/* The time memory chunks stay in the queue until they are removed completely in usecs */ uint32_t memblockq_get_delay(struct memblockq *bq); + +/* Return the length of the queue in bytes */ uint32_t memblockq_get_length(struct memblockq *bq); +/* Return how many bytes are missing in queue to the specified fill amount */ uint32_t memblockq_missing_to(struct memblockq *bq, size_t qlen); #endif diff --git a/src/pacat.c b/src/pacat.c index fbd1d081..ccad0189 100644 --- a/src/pacat.c +++ b/src/pacat.c @@ -77,7 +77,7 @@ static void context_complete_callback(struct pa_context *c, int success, void *u static const struct pa_sample_spec ss = { .format = PA_SAMPLE_S16NE, .rate = 44100, - .channels = 2 + .channels = 1 }; assert(c && !stream); diff --git a/src/polyp.c b/src/polyp.c index c2d1d822..32974fc4 100644 --- a/src/polyp.c +++ b/src/polyp.c @@ -15,7 +15,7 @@ #define DEFAULT_MAX_LENGTH 20480 #define DEFAULT_PREBUF 4096 #define DEFAULT_TIMEOUT (5*60) -#define DEFAULT_SERVER "/tmp/polypaudio_native" +#define DEFAULT_SERVER "/tmp/polypaudio/native" struct pa_context { char *name; diff --git a/src/protocol-esound.c b/src/protocol-esound.c index 56c85285..12d6f38c 100644 --- a/src/protocol-esound.c +++ b/src/protocol-esound.c @@ -210,7 +210,7 @@ static int esd_proto_stream_play(struct connection *c, const void *data, size_t assert(c->input_memblockq); assert(!c->sink_input); - c->sink_input = sink_input_new(sink, &ss, name); + c->sink_input = sink_input_new(sink, name, &ss); assert(c->sink_input); c->sink_input->peek = sink_input_peek_cb; @@ -218,7 +218,7 @@ static int esd_proto_stream_play(struct connection *c, const void *data, size_t c->sink_input->kill = sink_input_kill_cb; c->sink_input->get_latency = sink_input_get_latency_cb; c->sink_input->userdata = c; - + c->state = ESD_STREAMING_DATA; c->protocol->n_player++; @@ -460,7 +460,7 @@ static int do_read(struct connection *c) { chunk.index = 0; assert(c->input_memblockq); - memblockq_push(c->input_memblockq, &chunk, 0); + memblockq_push_align(c->input_memblockq, &chunk, 0); memblock_unref(chunk.memblock); assert(c->sink_input); sink_notify(c->sink_input->sink); diff --git a/src/protocol-native.c b/src/protocol-native.c index 9af438a9..425f4ba4 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -89,7 +89,7 @@ static struct playback_stream* playback_stream_new(struct connection *c, struct s->connection = c; s->qlength = qlen; - s->sink_input = sink_input_new(sink, ss, name); + s->sink_input = sink_input_new(sink, name, ss); assert(s->sink_input); s->sink_input->peek = sink_input_peek_cb; s->sink_input->drop = sink_input_drop_cb; @@ -323,7 +323,7 @@ static int memblock_callback(struct pstream *p, uint32_t channel, int32_t delta, else stream->requested_bytes -= chunk->length; - memblockq_push(stream->memblockq, chunk, delta); + memblockq_push_align(stream->memblockq, chunk, delta); assert(stream->sink_input); sink_notify(stream->sink_input->sink); diff --git a/src/protocol-simple.c b/src/protocol-simple.c index 80249eef..a7f3eb7e 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -25,14 +25,16 @@ struct protocol_simple { struct socket_server*server; struct idxset *connections; enum protocol_simple_mode mode; + struct pa_sample_spec sample_spec; }; #define BUFSIZE PIPE_BUF -static void free_connection(void *data, void *userdata) { - struct connection *c = data; - assert(data); - +static void connection_free(struct connection *c) { + assert(c); + + idxset_remove_by_data(c->protocol->connections, c, NULL); + if (c->sink_input) sink_input_free(c->sink_input); if (c->source_output) @@ -47,13 +49,6 @@ static void free_connection(void *data, void *userdata) { memblockq_free(c->output_memblockq); free(c); } - -static void destroy_connection(struct connection *c) { - assert(c && c->protocol); - idxset_remove_by_data(c->protocol->connections, c, NULL); - free_connection(c, NULL); -} - static int do_read(struct connection *c) { struct memchunk chunk; ssize_t r; @@ -77,7 +72,7 @@ static int do_read(struct connection *c) { chunk.index = 0; assert(c->input_memblockq); - memblockq_push(c->input_memblockq, &chunk, 0); + memblockq_push_align(c->input_memblockq, &chunk, 0); memblock_unref(chunk.memblock); assert(c->sink_input); sink_notify(c->sink_input->sink); @@ -132,12 +127,12 @@ static void sink_input_drop_cb(struct sink_input *i, size_t length) { memblockq_drop(c->input_memblockq, length); if (do_read(c) < 0) - destroy_connection(c); + connection_free(c); } static void sink_input_kill_cb(struct sink_input *i) { assert(i && i->userdata); - destroy_connection((struct connection *) i->userdata); + connection_free((struct connection *) i->userdata); } @@ -149,26 +144,26 @@ static uint32_t sink_input_get_latency_cb(struct sink_input *i) { /*** source_output callbacks ***/ -static void source_output_push_cb(struct source_output *o, struct memchunk *chunk) { +static void source_output_push_cb(struct source_output *o, const struct memchunk *chunk) { struct connection *c = o->userdata; assert(o && c && chunk); memblockq_push(c->output_memblockq, chunk, 0); if (do_write(c) < 0) - destroy_connection(c); + connection_free(c); } static void source_output_kill_cb(struct source_output *o) { assert(o && o->userdata); - destroy_connection((struct connection *) o->userdata); + connection_free((struct connection *) o->userdata); } /*** client callbacks ***/ static void client_kill_cb(struct client *c) { assert(c && c->userdata); - destroy_connection((struct connection *) c->userdata); + connection_free((struct connection *) c->userdata); } /*** iochannel callbacks ***/ @@ -178,7 +173,7 @@ static void io_callback(struct iochannel*io, void *userdata) { assert(io && c && c->io == io); if (do_read(c) < 0 || do_write(c) < 0) - destroy_connection(c); + connection_free(c); } /*** socket_server callbacks */ @@ -212,14 +207,14 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us goto fail; } - c->source_output = source_output_new(source, &DEFAULT_SAMPLE_SPEC, c->client->name); + c->source_output = source_output_new(source, c->client->name, &p->sample_spec); assert(c->source_output); c->source_output->push = source_output_push_cb; c->source_output->kill = source_output_kill_cb; c->source_output->userdata = c; l = 5*pa_bytes_per_second(&DEFAULT_SAMPLE_SPEC); /* 5s */ - c->output_memblockq = memblockq_new(l, pa_sample_size(&DEFAULT_SAMPLE_SPEC), l/2); + c->output_memblockq = memblockq_new(l, pa_sample_size(&p->sample_spec), l/2); } if (p->mode & PROTOCOL_SIMPLE_PLAYBACK) { @@ -231,7 +226,7 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us goto fail; } - c->sink_input = sink_input_new(sink, &DEFAULT_SAMPLE_SPEC, c->client->name); + c->sink_input = sink_input_new(sink, c->client->name, &p->sample_spec); assert(c->sink_input); c->sink_input->peek = sink_input_peek_cb; c->sink_input->drop = sink_input_drop_cb; @@ -240,7 +235,7 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c->sink_input->userdata = c; l = pa_bytes_per_second(&DEFAULT_SAMPLE_SPEC)/2; /* half a second */ - c->input_memblockq = memblockq_new(l, pa_sample_size(&DEFAULT_SAMPLE_SPEC), l/2); + c->input_memblockq = memblockq_new(l, pa_sample_size(&p->sample_spec), l/2); } @@ -249,11 +244,8 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us return; fail: - if (c) { - free_connection(c, NULL); - iochannel_free(c->io); - free(c); - } + if (c) + connection_free(c); } struct protocol_simple* protocol_simple_new(struct core *core, struct socket_server *server, enum protocol_simple_mode mode) { @@ -266,6 +258,7 @@ struct protocol_simple* protocol_simple_new(struct core *core, struct socket_ser p->server = server; p->connections = idxset_new(NULL, NULL); p->mode = mode; + p->sample_spec = DEFAULT_SAMPLE_SPEC; socket_server_set_callback(p->server, on_connection, p); @@ -274,9 +267,15 @@ struct protocol_simple* protocol_simple_new(struct core *core, struct socket_ser void protocol_simple_free(struct protocol_simple *p) { + struct connection *c; assert(p); - idxset_free(p->connections, free_connection, NULL); + while((c = idxset_first(p->connections, NULL))) + connection_free(c); + + idxset_free(p->connections, NULL, NULL); + socket_server_free(p->server); free(p); } + diff --git a/src/pstream.h b/src/pstream.h index d418908e..a623156a 100644 --- a/src/pstream.h +++ b/src/pstream.h @@ -7,6 +7,7 @@ #include "memblock.h" #include "iochannel.h" #include "mainloop-api.h" +#include "memchunk.h" struct pstream; diff --git a/src/resampler.c b/src/resampler.c index aa37f1ac..c2d79174 100644 --- a/src/resampler.c +++ b/src/resampler.c @@ -30,12 +30,13 @@ struct resampler* resampler_new(const struct pa_sample_spec *a, const struct pa_ if (a->format == PA_SAMPLE_ALAW || a->format == PA_SAMPLE_ULAW || b->format == PA_SAMPLE_ALAW || b->format == PA_SAMPLE_ULAW) goto fail; + r = malloc(sizeof(struct resampler)); + assert(r); + r->channels = a->channels; if (b->channels < r->channels) r->channels = b->channels; - r = malloc(sizeof(struct resampler)); - assert(r); r->i_buf = r->o_buf = NULL; r->i_alloc = r->o_alloc = 0; @@ -82,11 +83,10 @@ size_t resampler_request(struct resampler *r, size_t out_length) { } -int resampler_run(struct resampler *r, struct memchunk *in, struct memchunk *out) { +void resampler_run(struct resampler *r, const struct memchunk *in, struct memchunk *out) { unsigned i_nchannels, o_nchannels, ins, ons, eff_ins, eff_ons; float *cbuf; - size_t in_bytes_used = 0; - assert(r && in && out && in->length && in->memblock); + assert(r && in && out && in->length && in->memblock && (in->length % r->i_sz) == 0); /* How many input samples? */ ins = in->length/r->i_sz; @@ -138,8 +138,8 @@ int resampler_run(struct resampler *r, struct memchunk *in, struct memchunk *out ret = src_process(r->src_state, &data); assert(ret == 0); - - in_bytes_used = data.input_frames_used*r->i_sz; + assert((unsigned) data.input_frames_used == ins); + cbuf = r->o_buf; ons = data.output_frames_gen; @@ -147,16 +147,9 @@ int resampler_run(struct resampler *r, struct memchunk *in, struct memchunk *out eff_ons = ons*r->o_ss.channels; else eff_ons = ons; - } else { - in_bytes_used = ins*r->i_sz; + } else cbuf = r->i_buf; - } - assert(in_bytes_used < in->length); - in->index += in_bytes_used; - in->length -= in_bytes_used; - r->from_float32_func(eff_ons, cbuf, out->memblock->data+out->index, o_nchannels); out->length = ons*r->o_sz; - return 0; } diff --git a/src/resampler.h b/src/resampler.h index 000f73ce..257ba662 100644 --- a/src/resampler.h +++ b/src/resampler.h @@ -3,6 +3,7 @@ #include "sample.h" #include "memblock.h" +#include "memchunk.h" struct resampler; @@ -10,6 +11,6 @@ struct resampler* resampler_new(const struct pa_sample_spec *a, const struct pa_ void resampler_free(struct resampler *r); size_t resampler_request(struct resampler *r, size_t out_length); -int resampler_run(struct resampler *r, struct memchunk *in, struct memchunk *out); +void resampler_run(struct resampler *r, const struct memchunk *in, struct memchunk *out); #endif diff --git a/src/sample-util.h b/src/sample-util.h index 2f2539d0..bc51e524 100644 --- a/src/sample-util.h +++ b/src/sample-util.h @@ -3,6 +3,7 @@ #include "sample.h" #include "memblock.h" +#include "memchunk.h" #define DEFAULT_SAMPLE_SPEC default_sample_spec diff --git a/src/sample.c b/src/sample.c index 497358fa..706880e4 100644 --- a/src/sample.c +++ b/src/sample.c @@ -49,3 +49,9 @@ int pa_sample_spec_valid(const struct pa_sample_spec *spec) { return 1; } + +int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b) { + assert(a && b); + + return (a->format == b->format) && (a->rate == b->rate) && (a->channels == b->channels); +} diff --git a/src/sample.h b/src/sample.h index 1fd764d7..fcb0e6e1 100644 --- a/src/sample.h +++ b/src/sample.h @@ -29,7 +29,7 @@ struct pa_sample_spec { size_t pa_bytes_per_second(const struct pa_sample_spec *spec); size_t pa_sample_size(const struct pa_sample_spec *spec); uint32_t pa_samples_usec(size_t length, const struct pa_sample_spec *spec); - int pa_sample_spec_valid(const struct pa_sample_spec *spec); +int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b); #endif diff --git a/src/sink.c b/src/sink.c index 8a510f1b..2ecb6445 100644 --- a/src/sink.c +++ b/src/sink.c @@ -90,8 +90,7 @@ static unsigned fill_mix_info(struct sink *s, struct mix_info *info, unsigned ma assert(s && info); for (i = idxset_first(s->inputs, &index); maxinfo > 0 && i; i = idxset_next(s->inputs, &index)) { - assert(i->peek); - if (i->peek(i, &info->chunk) < 0) + if (sink_input_peek(i, &info->chunk) < 0) continue; info->volume = i->volume; @@ -115,11 +114,10 @@ static void inputs_drop(struct sink *s, struct mix_info *info, unsigned maxinfo, assert(i && info->chunk.memblock); memblock_unref(info->chunk.memblock); - assert(i->drop); - i->drop(i, length); + sink_input_drop(i, length); } } - + int sink_render(struct sink*s, size_t length, struct memchunk *result) { struct mix_info info[MAX_MIX_CHANNELS]; unsigned n; diff --git a/src/sinkinput.c b/src/sinkinput.c index dd0504d0..c9614a5f 100644 --- a/src/sinkinput.c +++ b/src/sinkinput.c @@ -6,11 +6,18 @@ #include "strbuf.h" #include "sample-util.h" -struct sink_input* sink_input_new(struct sink *s, struct pa_sample_spec *spec, const char *name) { +#define CONVERT_BUFFER_LENGTH 4096 + +struct sink_input* sink_input_new(struct sink *s, const char *name, const struct pa_sample_spec *spec) { struct sink_input *i; + struct resampler *resampler = NULL; int r; assert(s && spec); + if (!pa_sample_spec_equal(spec, &s->sample_spec)) + if (!(resampler = resampler_new(spec, &s->sample_spec))) + return NULL; + i = malloc(sizeof(struct sink_input)); assert(i); i->name = name ? strdup(name) : NULL; @@ -25,12 +32,16 @@ struct sink_input* sink_input_new(struct sink *s, struct pa_sample_spec *spec, c i->volume = VOLUME_NORM; + i->resampled_chunk.memblock = NULL; + i->resampled_chunk.index = i->resampled_chunk.length = 0; + i->resampler = resampler; + assert(s->core); r = idxset_put(s->core->sink_inputs, i, &i->index); assert(r == 0 && i->index != IDXSET_INVALID); r = idxset_put(s->inputs, i, NULL); assert(r == 0); - + return i; } @@ -40,6 +51,11 @@ void sink_input_free(struct sink_input* i) { assert(i->sink && i->sink->core); idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); idxset_remove_by_data(i->sink->inputs, i, NULL); + + if (i->resampled_chunk.memblock) + memblock_unref(i->resampled_chunk.memblock); + if (i->resampler) + resampler_free(i->resampler); free(i->name); free(i); @@ -89,3 +105,53 @@ uint32_t sink_input_get_latency(struct sink_input *i) { return l; } + +int sink_input_peek(struct sink_input *i, struct memchunk *chunk) { + assert(i && chunk && i->peek && i->drop); + + if (!i->resampler) + return i->peek(i, chunk); + + if (!i->resampled_chunk.memblock) { + struct memchunk tchunk; + size_t l; + int ret; + + if ((ret = i->peek(i, &tchunk)) < 0) + return ret; + + l = resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); + if (tchunk.length > l) + tchunk.length = l; + + i->drop(i, tchunk.length); + + resampler_run(i->resampler, &tchunk, &i->resampled_chunk); + memblock_unref(tchunk.memblock); + } + + assert(i->resampled_chunk.memblock && i->resampled_chunk.length); + *chunk = i->resampled_chunk; + memblock_ref(i->resampled_chunk.memblock); + return 0; +} + +void sink_input_drop(struct sink_input *i, size_t length) { + assert(i && length); + + if (!i->resampler) { + i->drop(i, length); + return; + } + + assert(i->resampled_chunk.memblock && i->resampled_chunk.length >= length); + + i->resampled_chunk.index += length; + i->resampled_chunk.length -= length; + + if (!i->resampled_chunk.length) { + memblock_unref(i->resampled_chunk.memblock); + i->resampled_chunk.memblock = NULL; + i->resampled_chunk.index = i->resampled_chunk.length = 0; + } +} diff --git a/src/sinkinput.h b/src/sinkinput.h index e3114d94..8899a9ed 100644 --- a/src/sinkinput.h +++ b/src/sinkinput.h @@ -6,6 +6,7 @@ #include "sink.h" #include "sample.h" #include "memblockq.h" +#include "resampler.h" struct sink_input { uint32_t index; @@ -21,9 +22,12 @@ struct sink_input { uint32_t (*get_latency) (struct sink_input *i); void *userdata; + + struct memchunk resampled_chunk; + struct resampler *resampler; }; -struct sink_input* sink_input_new(struct sink *s, struct pa_sample_spec *spec, const char *name); +struct sink_input* sink_input_new(struct sink *s, const char *name, const struct pa_sample_spec *spec); void sink_input_free(struct sink_input* i); /* Code that didn't create the input stream should call this function to @@ -33,7 +37,7 @@ void sink_input_kill(struct sink_input *i); uint32_t sink_input_get_latency(struct sink_input *i); char *sink_input_list_to_string(struct core *c); - - +int sink_input_peek(struct sink_input *i, struct memchunk *chunk); +void sink_input_drop(struct sink_input *i, size_t length); #endif diff --git a/src/source.c b/src/source.c index deacfb3d..f3eeb516 100644 --- a/src/source.c +++ b/src/source.c @@ -70,7 +70,7 @@ static int do_post(void *p, uint32_t index, int *del, void*userdata) { struct source_output *o = p; assert(o && o->push && del && chunk); - o->push(o, chunk); + source_output_push(o, chunk); return 0; } diff --git a/src/source.h b/src/source.h index afae5a68..186271c0 100644 --- a/src/source.h +++ b/src/source.h @@ -8,6 +8,7 @@ struct source; #include "sample.h" #include "idxset.h" #include "memblock.h" +#include "memchunk.h" struct source { uint32_t index; diff --git a/src/sourceoutput.c b/src/sourceoutput.c index e2e1dacc..e0ed0798 100644 --- a/src/sourceoutput.c +++ b/src/sourceoutput.c @@ -5,11 +5,16 @@ #include "sourceoutput.h" #include "strbuf.h" -struct source_output* source_output_new(struct source *s, struct pa_sample_spec *spec, const char *name) { +struct source_output* source_output_new(struct source *s, const char *name, const struct pa_sample_spec *spec) { struct source_output *o; + struct resampler *resampler = NULL; int r; assert(s && spec); + if (!pa_sample_spec_equal(&s->sample_spec, spec)) + if (!(resampler = resampler_new(&s->sample_spec, spec))) + return NULL; + o = malloc(sizeof(struct source_output)); assert(o); o->name = name ? strdup(name) : NULL; @@ -19,6 +24,7 @@ struct source_output* source_output_new(struct source *s, struct pa_sample_spec o->push = NULL; o->kill = NULL; o->userdata = NULL; + o->resampler = resampler; assert(s->core); r = idxset_put(s->core->source_outputs, o, &o->index); @@ -35,6 +41,9 @@ void source_output_free(struct source_output* o) { assert(o->source && o->source->core); idxset_remove_by_data(o->source->core->source_outputs, o, NULL); idxset_remove_by_data(o->source->outputs, o, NULL); + + if (o->resampler) + resampler_free(o->resampler); free(o->name); free(o); @@ -68,3 +77,21 @@ char *source_output_list_to_string(struct core *c) { return strbuf_tostring_free(s); } + +void source_output_push(struct source_output *o, const struct memchunk *chunk) { + struct memchunk rchunk; + assert(o && chunk && chunk->length && o->push); + + if (!o->resampler) { + o->push(o, chunk); + return; + } + + resampler_run(o->resampler, chunk, &rchunk); + if (!rchunk.length) + return; + + assert(rchunk.memblock); + o->push(o, &rchunk); + memblock_unref(rchunk.memblock); +} diff --git a/src/sourceoutput.h b/src/sourceoutput.h index 50cb9caf..4db2362d 100644 --- a/src/sourceoutput.h +++ b/src/sourceoutput.h @@ -6,6 +6,7 @@ #include "source.h" #include "sample.h" #include "memblockq.h" +#include "resampler.h" struct source_output { uint32_t index; @@ -14,17 +15,21 @@ struct source_output { struct source *source; struct pa_sample_spec sample_spec; - void (*push)(struct source_output *o, struct memchunk *chunk); + void (*push)(struct source_output *o, const struct memchunk *chunk); void (*kill)(struct source_output* o); + struct resampler* resampler; + void *userdata; }; -struct source_output* source_output_new(struct source *s, struct pa_sample_spec *spec, const char *name); +struct source_output* source_output_new(struct source *s, const char *name, const struct pa_sample_spec *spec); void source_output_free(struct source_output* o); void source_output_kill(struct source_output*o); char *source_output_list_to_string(struct core *c); +void source_output_push(struct source_output *o, const struct memchunk *chunk); + #endif diff --git a/src/todo b/src/todo index 0dd999a1..0f88b043 100644 --- a/src/todo +++ b/src/todo @@ -1,20 +1,17 @@ +- recording (general, simple, esound, native) +- make it embedable (add pa_ prefix too all identifiers) - native library/protocol: - recording sync() function more functions -- esound protocol: - recording -- move more stuff from module-oss[-dma] to liboss-util - simple library -- simple control protocol: - kill client/input/output - kill() routines in all modules -- resampling +- command line protocol: + kill client/input/output - config parser/cmdline -- record testing -- mixing/volume +- move more stuff from module-oss[-dma] to liboss-util +- svn-id and license in every file --- 0.1 +-- post 0.1 - future cancellation - client-ui - clip cache -- cgit From 253c540e84a261d37721e9b8a0ed5c5222111adb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 3 Jul 2004 00:19:40 +0000 Subject: forgot to add memchunk.[ch] git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@46 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/memchunk.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/memchunk.h | 20 ++++++++++ 2 files changed, 144 insertions(+) create mode 100644 src/memchunk.c create mode 100644 src/memchunk.h diff --git a/src/memchunk.c b/src/memchunk.c new file mode 100644 index 00000000..faee4508 --- /dev/null +++ b/src/memchunk.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include + +#include "memchunk.h" + +void memchunk_make_writable(struct memchunk *c) { + struct memblock *n; + assert(c && c->memblock && c->memblock->ref >= 1); + + if (c->memblock->ref == 1) + return; + + n = memblock_new(c->length); + assert(n); + memcpy(n->data, c->memblock->data+c->index, c->length); + memblock_unref(c->memblock); + c->memblock = n; + c->index = 0; +} + + +struct mcalign { + size_t base; + struct memchunk chunk; + uint8_t *buffer; + size_t buffer_fill; +}; + +struct mcalign *mcalign_new(size_t base) { + struct mcalign *m; + assert(base); + + m = malloc(sizeof(struct mcalign)); + assert(m); + m->base = base; + m->chunk.memblock = NULL; + m->chunk.length = m->chunk.index = 0; + m->buffer = NULL; + m->buffer_fill = 0; + return m; +} + +void mcalign_free(struct mcalign *m) { + assert(m); + + free(m->buffer); + + if (m->chunk.memblock) + memblock_unref(m->chunk.memblock); + + free(m); +} + +void mcalign_push(struct mcalign *m, const struct memchunk *c) { + assert(m && c && !m->chunk.memblock && c->memblock && c->length); + + m->chunk = *c; + memblock_ref(m->chunk.memblock); +} + +int mcalign_pop(struct mcalign *m, struct memchunk *c) { + assert(m && c && m->base > m->buffer_fill); + int ret; + + if (!m->chunk.memblock) + return -1; + + if (m->buffer_fill) { + size_t l = m->base - m->buffer_fill; + if (l > m->chunk.length) + l = m->chunk.length; + assert(m->buffer && l); + + memcpy(m->buffer + m->buffer_fill, m->chunk.memblock->data + m->chunk.index, l); + m->buffer_fill += l; + m->chunk.index += l; + m->chunk.length -= l; + + if (m->chunk.length == 0) { + m->chunk.length = m->chunk.index = 0; + memblock_unref(m->chunk.memblock); + m->chunk.memblock = NULL; + } + + assert(m->buffer_fill <= m->base); + if (m->buffer_fill == m->base) { + c->memblock = memblock_new_dynamic(m->buffer, m->base); + assert(c->memblock); + c->index = 0; + c->length = m->base; + m->buffer = NULL; + m->buffer_fill = 0; + + return 0; + } + + return -1; + } + + m->buffer_fill = m->chunk.length % m->base; + + if (m->buffer_fill) { + assert(!m->buffer); + m->buffer = malloc(m->base); + assert(m->buffer); + m->chunk.length -= m->buffer_fill; + memcpy(m->buffer, m->chunk.memblock->data + m->chunk.index + m->chunk.length, m->buffer_fill); + } + + if (m->chunk.length) { + *c = m->chunk; + memblock_ref(c->memblock); + ret = 0; + } else + ret = -1; + + m->chunk.length = m->chunk.index = 0; + memblock_unref(m->chunk.memblock); + m->chunk.memblock = NULL; + + return ret; +} diff --git a/src/memchunk.h b/src/memchunk.h new file mode 100644 index 00000000..d395cf2c --- /dev/null +++ b/src/memchunk.h @@ -0,0 +1,20 @@ +#ifndef foomemchunkhfoo +#define foomemchunkhfoo + +#include "memblock.h" + +struct memchunk { + struct memblock *memblock; + size_t index, length; +}; + +void memchunk_make_writable(struct memchunk *c); + +struct mcalign; + +struct mcalign *mcalign_new(size_t base); +void mcalign_free(struct mcalign *m); +void mcalign_push(struct mcalign *m, const struct memchunk *c); +int mcalign_pop(struct mcalign *m, struct memchunk *c); + +#endif -- cgit From 3ac2437abd693839a7abb78f1e16f82f91712242 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 3 Jul 2004 00:20:06 +0000 Subject: add libsamplerate dependency git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@47 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/configure.ac b/configure.ac index 3a14a061..647bfab7 100644 --- a/configure.ac +++ b/configure.ac @@ -40,6 +40,12 @@ AC_SUBST(LIBLTDL) AC_LIBTOOL_DLOPEN AC_PROG_LIBTOOL +AC_C_BIGENDIAN + +PKG_CHECK_MODULES(LIBSAMPLERATE, [ samplerate >= 0.1.0 ]) +AC_SUBST(LIBSAMPLERATE_CFLAGS) +AC_SUBST(LIBSAMPLERATE_LIBS) + # If using GCC specifiy some additional parameters if test "x$GCC" = "xyes" ; then CFLAGS="$CFLAGS -pipe -Wall -W -Wno-unused-parameter" -- cgit From a8a5ab1c79c0b6567ecc98343ff1ae944f2285b9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 3 Jul 2004 00:32:31 +0000 Subject: fix minor typo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@48 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/main.c | 2 +- src/module-oss-mmap.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.c b/src/main.c index 67109682..d10ce0d5 100644 --- a/src/main.c +++ b/src/main.c @@ -38,7 +38,7 @@ int main(int argc, char *argv[]) { c = core_new(pa_mainloop_get_api(mainloop)); assert(c); - module_load(c, "module-oss-mmap", "/dev/dsp"); + 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-simple-protocol-unix", NULL); diff --git a/src/module-oss-mmap.c b/src/module-oss-mmap.c index 3997c490..3f69e05b 100644 --- a/src/module-oss-mmap.c +++ b/src/module-oss-mmap.c @@ -273,7 +273,7 @@ int module_init(struct core *c, struct module*m) { } } - if (m != O_RDONLY) { + if (mode != O_RDONLY) { if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { fprintf(stderr, "SNDCTL_DSP_GETOSPACE: %s\n", strerror(errno)); goto fail; -- cgit From e61c2dddb7bc392ab4073d5691870615ada82922 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 3 Jul 2004 23:35:12 +0000 Subject: add pa_ prefix to all identifiers. fix downsampling/resampling add support for U8 samples git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@49 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 45 +++++--- src/cli.c | 250 ++++++++++++++++++++++----------------------- src/cli.h | 8 +- src/client.c | 36 +++---- src/client.h | 16 +-- src/core.c | 44 ++++---- src/core.h | 10 +- src/dynarray.c | 20 ++-- src/dynarray.h | 14 +-- src/hashset.c | 26 ++--- src/hashset.h | 14 +-- src/idxset.c | 54 +++++----- src/idxset.h | 41 ++++---- src/iochannel.c | 38 +++---- src/iochannel.h | 20 ++-- src/ioline.c | 42 ++++---- src/ioline.h | 10 +- src/main.c | 28 ++--- src/main.h | 2 +- src/mainloop-signal.c | 4 +- src/mainloop.c | 72 ++++++------- src/memblock.c | 48 ++++----- src/memblock.h | 22 ++-- src/memblockq.c | 74 +++++++------- src/memblockq.h | 40 ++++---- src/memchunk.c | 36 +++---- src/memchunk.h | 16 +-- src/module-cli.c | 22 ++-- src/module-oss-mmap.c | 52 +++++----- src/module-oss.c | 66 ++++++------ src/module-pipe-sink.c | 38 +++---- src/module-protocol-stub.c | 28 ++--- src/module.c | 66 ++++++------ src/module.h | 20 ++-- src/namereg.c | 36 +++---- src/namereg.h | 14 +-- src/oss-util.c | 2 +- src/oss-util.h | 2 +- src/pacat.c | 4 +- src/packet.c | 22 ++-- src/packet.h | 12 +-- src/pdispatch.c | 34 +++--- src/pdispatch.h | 14 +-- src/polyp.c | 120 +++++++++++----------- src/protocol-cli.c | 46 ++++----- src/protocol-cli.h | 6 +- src/protocol-esound.c | 142 ++++++++++++------------- src/protocol-esound.h | 6 +- src/protocol-native.c | 228 ++++++++++++++++++++--------------------- src/protocol-native.h | 6 +- src/protocol-simple.c | 152 +++++++++++++-------------- src/protocol-simple.h | 14 +-- src/pstream-util.c | 34 +++--- src/pstream-util.h | 6 +- src/pstream.c | 184 ++++++++++++++++----------------- src/pstream.h | 18 ++-- src/queue.c | 14 +-- src/queue.h | 12 +-- src/resampler.c | 24 ++--- src/resampler.h | 10 +- src/sample-util.c | 46 ++++----- src/sample-util.h | 24 ++--- src/sample.c | 17 ++- src/sample.h | 2 + src/sconv-s16be.c | 9 ++ src/sconv-s16be.h | 7 ++ src/sconv-s16le.c | 57 +++++++++++ src/sconv-s16le.h | 7 ++ src/sconv.c | 53 ++++++---- src/sconv.h | 10 +- src/sink.c | 144 +++++++++++++------------- src/sink.h | 32 +++--- src/sinkinput.c | 75 +++++++------- src/sinkinput.h | 30 +++--- src/socket-client.c | 48 ++++----- src/socket-client.h | 10 +- src/socket-server.c | 48 +++++---- src/socket-server.h | 12 +-- src/source.c | 72 ++++++------- src/source.h | 22 ++-- src/sourceoutput.c | 58 +++++------ src/sourceoutput.h | 20 ++-- src/strbuf.c | 20 ++-- src/strbuf.h | 14 +-- src/tagstruct.c | 34 +++--- src/tagstruct.h | 28 ++--- src/todo | 3 +- src/tokenizer.c | 26 ++--- src/tokenizer.h | 8 +- src/util.c | 12 +-- src/util.h | 12 ++- 91 files changed, 1798 insertions(+), 1646 deletions(-) create mode 100644 src/sconv-s16be.c create mode 100644 src/sconv-s16be.h create mode 100644 src/sconv-s16le.c create mode 100644 src/sconv-s16le.h diff --git a/src/Makefile.am b/src/Makefile.am index ec234481..167bc91c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -20,17 +20,36 @@ AM_CFLAGS=-ansi -D_GNU_SOURCE bin_PROGRAMS = polypaudio pacat -pkglib_LTLIBRARIES=libiochannel.la libsocket-server.la libsocket-client.la \ - libprotocol-simple.la module-simple-protocol-tcp.la \ - module-pipe-sink.la libpstream.la \ - libpacket.la module-oss.la module-oss-mmap.la liboss-util.la libioline.la \ - libcli.la module-cli.la libtokenizer.la libdynarray.la \ - module-simple-protocol-unix.la module-cli-protocol-tcp.la \ - libprotocol-cli.la module-cli-protocol-unix.la libtagstruct.la \ - libpdispatch.la libprotocol-native.la libpstream-util.la \ - module-native-protocol-tcp.la module-native-protocol-unix.la \ - libpolyp.la libprotocol-esound.la module-esound-protocol-unix.la \ - module-esound-protocol-tcp.la +pkglib_LTLIBRARIES=libiochannel.la \ + libsocket-server.la \ + libsocket-client.la \ + libpstream.la \ + libpacket.la \ + liboss-util.la \ + libioline.la \ + libcli.la \ + libtokenizer.la \ + libdynarray.la \ + libprotocol-cli.la \ + libtagstruct.la \ + libpstream-util.la \ + libpdispatch.la \ + libprotocol-simple.la \ + libprotocol-esound.la \ + libprotocol-native.la \ + module-cli.la \ + module-cli-protocol-tcp.la \ + module-cli-protocol-unix.la \ + module-pipe-sink.la \ + module-oss.la \ + module-oss-mmap.la \ + module-simple-protocol-tcp.la \ + module-simple-protocol-unix.la \ + module-esound-protocol-tcp.la \ + module-esound-protocol-unix.la \ + module-native-protocol-tcp.la \ + module-native-protocol-unix.la \ + libpolyp.la polypaudio_SOURCES = idxset.c idxset.h \ queue.c queue.h \ @@ -56,7 +75,9 @@ polypaudio_SOURCES = idxset.c idxset.h \ sconv.c sconv.h \ resampler.c resampler.h \ endianmacros.h \ - memchunk.c memchunk.h + memchunk.c memchunk.h \ + sconv-s16le.c sconv-s16le.h \ + sconv-s16be.c sconv-s16be.h polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) polypaudio_LDADD = $(LIBLTDL) $(LIBSAMPLERATE_LIBS) diff --git a/src/cli.c b/src/cli.c index 10e780cd..659523b1 100644 --- a/src/cli.c +++ b/src/cli.c @@ -15,94 +15,94 @@ #include "strbuf.h" #include "namereg.h" -struct cli { - struct core *core; - struct ioline *line; +struct pa_cli { + struct pa_core *core; + struct pa_ioline *line; - void (*eof_callback)(struct cli *c, void *userdata); + void (*eof_callback)(struct pa_cli *c, void *userdata); void *userdata; - struct client *client; + struct pa_client *client; }; struct command { const char *name; - void (*proc) (struct cli *cli, struct tokenizer*t); + void (*proc) (struct pa_cli *cli, struct pa_tokenizer*t); const char *help; unsigned args; }; -static void line_callback(struct ioline *line, const char *s, void *userdata); - -static void cli_command_exit(struct cli *c, struct tokenizer *t); -static void cli_command_help(struct cli *c, struct tokenizer *t); -static void cli_command_modules(struct cli *c, struct tokenizer *t); -static void cli_command_clients(struct cli *c, struct tokenizer *t); -static void cli_command_sinks(struct cli *c, struct tokenizer *t); -static void cli_command_sources(struct cli *c, struct tokenizer *t); -static void cli_command_sink_inputs(struct cli *c, struct tokenizer *t); -static void cli_command_source_outputs(struct cli *c, struct tokenizer *t); -static void cli_command_stat(struct cli *c, struct tokenizer *t); -static void cli_command_info(struct cli *c, struct tokenizer *t); -static void cli_command_load(struct cli *c, struct tokenizer *t); -static void cli_command_unload(struct cli *c, struct tokenizer *t); -static void cli_command_sink_volume(struct cli *c, struct tokenizer *t); -static void cli_command_sink_input_volume(struct cli *c, struct tokenizer *t); +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 const struct command commands[] = { - { "exit", cli_command_exit, "Terminate the daemon", 1 }, - { "help", cli_command_help, "Show this help", 1 }, - { "modules", cli_command_modules, "List loaded modules", 1 }, - { "sinks", cli_command_sinks, "List loaded sinks", 1 }, - { "sources", cli_command_sources, "List loaded sources", 1 }, - { "clients", cli_command_clients, "List loaded clients", 1 }, - { "sink_inputs", cli_command_sink_inputs, "List sink inputs", 1 }, - { "source_outputs", cli_command_source_outputs, "List source outputs", 1 }, - { "stat", cli_command_stat, "Show memory block statistics", 1 }, - { "info", cli_command_info, "Show comprehensive status", 1 }, - { "load", cli_command_load, "Load a module (args: name, arguments)", 3}, - { "unload", cli_command_unload, "Unload a module (args: index)", 2}, - { "sink_volume", cli_command_sink_volume, "Set the volume of a sink (args: sink, volume)", 3}, - { "sink_input_volume", 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 }, + { "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}, { NULL, NULL, NULL, 0 } }; static const char prompt[] = ">>> "; -struct cli* cli_new(struct core *core, struct iochannel *io) { +struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io) { char cname[256]; - struct cli *c; + struct pa_cli *c; assert(io); - c = malloc(sizeof(struct cli)); + c = malloc(sizeof(struct pa_cli)); assert(c); c->core = core; - c->line = ioline_new(io); + c->line = pa_ioline_new(io); assert(c->line); c->userdata = NULL; c->eof_callback = NULL; - iochannel_peer_to_string(io, cname, sizeof(cname)); - c->client = client_new(core, "CLI", cname); + pa_iochannel_peer_to_string(io, cname, sizeof(cname)); + c->client = pa_client_new(core, "CLI", cname); assert(c->client); - ioline_set_callback(c->line, line_callback, c); - ioline_puts(c->line, "Welcome to polypaudio! Use \"help\" for usage information.\n"); - ioline_puts(c->line, prompt); + 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); return c; } -void cli_free(struct cli *c) { +void pa_cli_free(struct pa_cli *c) { assert(c); - ioline_free(c->line); - client_free(c->client); + pa_ioline_free(c->line); + pa_client_free(c->client); free(c); } -static void line_callback(struct ioline *line, const char *s, void *userdata) { - struct cli *c = userdata; +static void line_callback(struct pa_ioline *line, const char *s, void *userdata) { + struct pa_cli *c = userdata; const char *cs; const char delimiter[] = " \t\n\r"; assert(line && c); @@ -125,225 +125,225 @@ static void line_callback(struct ioline *line, const char *s, void *userdata) { for (command = commands; command->name; command++) if (strlen(command->name) == l && !strncmp(s, command->name, l)) { - struct tokenizer *t = tokenizer_new(s, command->args); + struct pa_tokenizer *t = pa_tokenizer_new(s, command->args); assert(t); command->proc(c, t); - tokenizer_free(t); + pa_tokenizer_free(t); unknown = 0; break; } if (unknown) - ioline_puts(line, "Unknown command\n"); + pa_ioline_puts(line, "Unknown command\n"); } - ioline_puts(c->line, prompt); + pa_ioline_puts(c->line, prompt); } -void cli_set_eof_callback(struct cli *c, void (*cb)(struct cli*c, void *userdata), void *userdata) { +void pa_cli_set_eof_callback(struct pa_cli *c, void (*cb)(struct pa_cli*c, void *userdata), void *userdata) { assert(c && cb); c->eof_callback = cb; c->userdata = userdata; } -static void cli_command_exit(struct cli *c, struct tokenizer *t) { +static void 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); } -static void cli_command_help(struct cli *c, struct tokenizer *t) { +static void pa_cli_command_help(struct pa_cli *c, struct pa_tokenizer *t) { const struct command*command; - struct strbuf *strbuf; + struct pa_strbuf *pa_strbuf; char *p; assert(c && t); - strbuf = strbuf_new(); - assert(strbuf); + pa_strbuf = pa_strbuf_new(); + assert(pa_strbuf); - strbuf_puts(strbuf, "Available commands:\n"); + pa_strbuf_puts(pa_strbuf, "Available commands:\n"); for (command = commands; command->name; command++) - strbuf_printf(strbuf, " %-20s %s\n", command->name, command->help); + pa_strbuf_printf(pa_strbuf, " %-20s %s\n", command->name, command->help); - ioline_puts(c->line, p = strbuf_tostring_free(strbuf)); + pa_ioline_puts(c->line, p = pa_strbuf_tostring_free(pa_strbuf)); free(p); } -static void cli_command_modules(struct cli *c, struct tokenizer *t) { +static void pa_cli_command_modules(struct pa_cli *c, struct pa_tokenizer *t) { char *s; assert(c && t); - s = module_list_to_string(c->core); + s = pa_module_list_to_string(c->core); assert(s); - ioline_puts(c->line, s); + pa_ioline_puts(c->line, s); free(s); } -static void cli_command_clients(struct cli *c, struct tokenizer *t) { +static void pa_cli_command_clients(struct pa_cli *c, struct pa_tokenizer *t) { char *s; assert(c && t); - s = client_list_to_string(c->core); + s = pa_client_list_to_string(c->core); assert(s); - ioline_puts(c->line, s); + pa_ioline_puts(c->line, s); free(s); } -static void cli_command_sinks(struct cli *c, struct tokenizer *t) { +static void pa_cli_command_sinks(struct pa_cli *c, struct pa_tokenizer *t) { char *s; assert(c && t); - s = sink_list_to_string(c->core); + s = pa_sink_list_to_string(c->core); assert(s); - ioline_puts(c->line, s); + pa_ioline_puts(c->line, s); free(s); } -static void cli_command_sources(struct cli *c, struct tokenizer *t) { +static void pa_cli_command_sources(struct pa_cli *c, struct pa_tokenizer *t) { char *s; assert(c && t); - s = source_list_to_string(c->core); + s = pa_source_list_to_string(c->core); assert(s); - ioline_puts(c->line, s); + pa_ioline_puts(c->line, s); free(s); } -static void cli_command_sink_inputs(struct cli *c, struct tokenizer *t) { +static void pa_cli_command_sink_inputs(struct pa_cli *c, struct pa_tokenizer *t) { char *s; assert(c && t); - s = sink_input_list_to_string(c->core); + s = pa_sink_input_list_to_string(c->core); assert(s); - ioline_puts(c->line, s); + pa_ioline_puts(c->line, s); free(s); } -static void cli_command_source_outputs(struct cli *c, struct tokenizer *t) { +static void pa_cli_command_source_outputs(struct pa_cli *c, struct pa_tokenizer *t) { char *s; assert(c && t); - s = source_output_list_to_string(c->core); + s = pa_source_output_list_to_string(c->core); assert(s); - ioline_puts(c->line, s); + pa_ioline_puts(c->line, s); free(s); } -static void cli_command_stat(struct cli *c, struct tokenizer *t) { +static void 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", memblock_count, memblock_total); - ioline_puts(c->line, txt); + 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); } -static void cli_command_info(struct cli *c, struct tokenizer *t) { +static void pa_cli_command_info(struct pa_cli *c, struct pa_tokenizer *t) { assert(c && t); - cli_command_stat(c, t); - cli_command_modules(c, t); - cli_command_sources(c, t); - cli_command_sinks(c, t); - cli_command_clients(c, t); - cli_command_sink_inputs(c, t); - cli_command_source_outputs(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_clients(c, t); + pa_cli_command_sink_inputs(c, t); + pa_cli_command_source_outputs(c, t); } -static void cli_command_load(struct cli *c, struct tokenizer *t) { - struct module *m; +static void 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 = tokenizer_get(t, 1))) { - ioline_puts(c->line, "You need to specfiy the module name and optionally arguments.\n"); + if (!(name = pa_tokenizer_get(t, 1))) { + pa_ioline_puts(c->line, "You need to specfiy the module name and optionally arguments.\n"); return; } - if (!(m = module_load(c->core, name, tokenizer_get(t, 2)))) { - ioline_puts(c->line, "Module load failed.\n"); + if (!(m = pa_module_load(c->core, name, pa_tokenizer_get(t, 2)))) { + pa_ioline_puts(c->line, "Module load failed.\n"); return; } snprintf(txt, sizeof(txt), "Module successfully loaded, index: %u.\n", m->index); - ioline_puts(c->line, txt); + pa_ioline_puts(c->line, txt); } -static void cli_command_unload(struct cli *c, struct tokenizer *t) { - struct module *m; +static void 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 = tokenizer_get(t, 1))) { - ioline_puts(c->line, "You need to specfiy the module index.\n"); + if (!(i = pa_tokenizer_get(t, 1))) { + pa_ioline_puts(c->line, "You need to specfiy the module index.\n"); return; } index = (uint32_t) strtoul(i, &e, 10); - if (*e || !(m = idxset_get_by_index(c->core->modules, index))) { - ioline_puts(c->line, "Invalid module index.\n"); + if (*e || !(m = pa_idxset_get_by_index(c->core->modules, index))) { + pa_ioline_puts(c->line, "Invalid module index.\n"); return; } - module_unload_request(c->core, m); + pa_module_unload_request(c->core, m); } -static void cli_command_sink_volume(struct cli *c, struct tokenizer *t) { +static void pa_cli_command_sink_volume(struct pa_cli *c, struct pa_tokenizer *t) { const char *n, *v; char *x = NULL; - struct sink *sink; + struct pa_sink *sink; long volume; - if (!(n = tokenizer_get(t, 1))) { - ioline_puts(c->line, "You need to specify a sink either by its name or its index.\n"); + 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; } - if (!(v = tokenizer_get(t, 2))) { - ioline_puts(c->line, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n"); + 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; } volume = strtol(v, &x, 0); if (!x || *x != 0 || volume < 0) { - ioline_puts(c->line, "Failed to parse volume.\n"); + pa_ioline_puts(c->line, "Failed to parse volume.\n"); return; } - if (!(sink = namereg_get(c->core, n, NAMEREG_SINK))) { - ioline_puts(c->line, "No sink found by this name or index.\n"); + 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; } sink->volume = (uint32_t) volume; } -static void cli_command_sink_input_volume(struct cli *c, struct tokenizer *t) { +static void pa_cli_command_sink_input_volume(struct pa_cli *c, struct pa_tokenizer *t) { const char *n, *v; char *x = NULL; - struct sink_input *si; + struct pa_sink_input *si; long index, volume; - if (!(n = tokenizer_get(t, 1))) { - ioline_puts(c->line, "You need to specify a sink input by its index.\n"); + if (!(n = pa_tokenizer_get(t, 1))) { + pa_ioline_puts(c->line, "You need to specify a sink input by its index.\n"); return; } index = strtol(n, &x, 0); if (!x || *x != 0 || index < 0) { - ioline_puts(c->line, "Failed to parse index.\n"); + pa_ioline_puts(c->line, "Failed to parse index.\n"); return; } - if (!(v = tokenizer_get(t, 2))) { - ioline_puts(c->line, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n"); + 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; } x = NULL; volume = strtol(v, &x, 0); if (!x || *x != 0 || volume < 0) { - ioline_puts(c->line, "Failed to parse volume.\n"); + pa_ioline_puts(c->line, "Failed to parse volume.\n"); return; } - if (!(si = idxset_get_by_index(c->core->sink_inputs, (uint32_t) index))) { - ioline_puts(c->line, "No sink input found with this index.\n"); + 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; } diff --git a/src/cli.h b/src/cli.h index f1b74397..80d9fec7 100644 --- a/src/cli.h +++ b/src/cli.h @@ -4,11 +4,11 @@ #include "iochannel.h" #include "core.h" -struct cli; +struct pa_cli; -struct cli* cli_new(struct core *core, struct iochannel *io); -void cli_free(struct cli *cli); +struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io); +void pa_cli_free(struct pa_cli *cli); -void cli_set_eof_callback(struct cli *cli, void (*cb)(struct cli*c, void *userdata), void *userdata); +void pa_cli_set_eof_callback(struct pa_cli *cli, void (*cb)(struct pa_cli*c, void *userdata), void *userdata); #endif diff --git a/src/client.c b/src/client.c index 37691283..eb06c52f 100644 --- a/src/client.c +++ b/src/client.c @@ -6,12 +6,12 @@ #include "client.h" #include "strbuf.h" -struct client *client_new(struct core *core, const char *protocol_name, char *name) { - struct client *c; +struct pa_client *pa_client_new(struct pa_core *core, const char *protocol_name, char *name) { + struct pa_client *c; int r; assert(core); - c = malloc(sizeof(struct client)); + c = malloc(sizeof(struct pa_client)); assert(c); c->name = name ? strdup(name) : NULL; c->core = core; @@ -20,48 +20,48 @@ struct client *client_new(struct core *core, const char *protocol_name, char *na c->kill = NULL; c->userdata = NULL; - r = idxset_put(core->clients, c, &c->index); - assert(c->index != IDXSET_INVALID && r >= 0); + r = pa_idxset_put(core->clients, c, &c->index); + assert(c->index != PA_IDXSET_INVALID && r >= 0); fprintf(stderr, "client: created %u \"%s\"\n", c->index, c->name); return c; } -void client_free(struct client *c) { +void pa_client_free(struct pa_client *c) { assert(c && c->core); - idxset_remove_by_data(c->core->clients, c, NULL); + pa_idxset_remove_by_data(c->core->clients, c, NULL); fprintf(stderr, "client: freed %u \"%s\"\n", c->index, c->name); free(c->name); free(c); } -void client_kill(struct client *c) { +void pa_client_kill(struct pa_client *c) { assert(c); if (c->kill) c->kill(c); } -char *client_list_to_string(struct core *c) { - struct strbuf *s; - struct client *client; - uint32_t index = IDXSET_INVALID; +char *pa_client_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_client *client; + uint32_t index = PA_IDXSET_INVALID; assert(c); - s = strbuf_new(); + s = pa_strbuf_new(); assert(s); - strbuf_printf(s, "%u client(s).\n", idxset_ncontents(c->clients)); + pa_strbuf_printf(s, "%u client(s).\n", pa_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); + for (client = pa_idxset_first(c->clients, &index); client; client = pa_idxset_next(c->clients, &index)) + pa_strbuf_printf(s, " index: %u, name: <%s>, protocol_name: <%s>\n", client->index, client->name, client->protocol_name); - return strbuf_tostring_free(s); + return pa_strbuf_tostring_free(s); } -void client_rename(struct client *c, const char *name) { +void pa_client_rename(struct pa_client *c, const char *name) { assert(c); free(c->name); c->name = name ? strdup(name) : NULL; diff --git a/src/client.h b/src/client.h index 39167ee7..4ca8d96e 100644 --- a/src/client.h +++ b/src/client.h @@ -3,28 +3,28 @@ #include "core.h" -struct client { +struct pa_client { uint32_t index; char *name; - struct core *core; + struct pa_core *core; const char *protocol_name; - void (*kill)(struct client *c); + void (*kill)(struct pa_client *c); void *userdata; }; -struct client *client_new(struct core *c, const char *protocol_name, char *name); +struct pa_client *pa_client_new(struct pa_core *c, const char *protocol_name, char *name); /* This function should be called only by the code that created the client */ -void client_free(struct client *c); +void pa_client_free(struct pa_client *c); /* Code that didn't create the client should call this function to * request destruction of the client */ -void client_kill(struct client *c); +void pa_client_kill(struct pa_client *c); -char *client_list_to_string(struct core *c); +char *pa_client_list_to_string(struct pa_core *c); -void client_rename(struct client *c, const char *name); +void pa_client_rename(struct pa_client *c, const char *name); #endif diff --git a/src/core.c b/src/core.c index ec38da91..46159037 100644 --- a/src/core.c +++ b/src/core.c @@ -8,19 +8,19 @@ #include "source.h" #include "namereg.h" -struct core* core_new(struct pa_mainloop_api *m) { - struct core* c; - c = malloc(sizeof(struct core)); +struct pa_core* pa_core_new(struct pa_mainloop_api *m) { + struct pa_core* c; + c = malloc(sizeof(struct pa_core)); assert(c); c->mainloop = m; - c->clients = idxset_new(NULL, NULL); - c->sinks = idxset_new(NULL, NULL); - c->sources = idxset_new(NULL, NULL); - c->source_outputs = idxset_new(NULL, NULL); - c->sink_inputs = idxset_new(NULL, NULL); + c->clients = pa_idxset_new(NULL, NULL); + c->sinks = pa_idxset_new(NULL, NULL); + c->sources = pa_idxset_new(NULL, NULL); + c->source_outputs = pa_idxset_new(NULL, NULL); + c->sink_inputs = pa_idxset_new(NULL, NULL); - c->default_source_index = c->default_sink_index = IDXSET_INVALID; + c->default_source_index = c->default_sink_index = PA_IDXSET_INVALID; c->modules = NULL; c->namereg = NULL; @@ -28,28 +28,28 @@ struct core* core_new(struct pa_mainloop_api *m) { return c; }; -void core_free(struct core *c) { +void pa_core_free(struct pa_core *c) { assert(c); - module_unload_all(c); + pa_module_unload_all(c); assert(!c->modules); - assert(idxset_isempty(c->clients)); - idxset_free(c->clients, NULL, NULL); + assert(pa_idxset_isempty(c->clients)); + pa_idxset_free(c->clients, NULL, NULL); - assert(idxset_isempty(c->sinks)); - idxset_free(c->sinks, NULL, NULL); + assert(pa_idxset_isempty(c->sinks)); + pa_idxset_free(c->sinks, NULL, NULL); - assert(idxset_isempty(c->sources)); - idxset_free(c->sources, NULL, NULL); + assert(pa_idxset_isempty(c->sources)); + pa_idxset_free(c->sources, NULL, NULL); - assert(idxset_isempty(c->source_outputs)); - idxset_free(c->source_outputs, NULL, NULL); + assert(pa_idxset_isempty(c->source_outputs)); + pa_idxset_free(c->source_outputs, NULL, NULL); - assert(idxset_isempty(c->sink_inputs)); - idxset_free(c->sink_inputs, NULL, NULL); + assert(pa_idxset_isempty(c->sink_inputs)); + pa_idxset_free(c->sink_inputs, NULL, NULL); - namereg_free(c); + pa_namereg_free(c); free(c); }; diff --git a/src/core.h b/src/core.h index 289bec85..8eb638d9 100644 --- a/src/core.h +++ b/src/core.h @@ -5,17 +5,17 @@ #include "hashset.h" #include "mainloop-api.h" -struct core { +struct pa_core { struct pa_mainloop_api *mainloop; - struct idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules; + struct pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules; - struct hashset *namereg; + struct pa_hashset *namereg; uint32_t default_source_index, default_sink_index; }; -struct core* core_new(struct pa_mainloop_api *m); -void core_free(struct core*c); +struct pa_core* pa_core_new(struct pa_mainloop_api *m); +void pa_core_free(struct pa_core*c); #endif diff --git a/src/dynarray.c b/src/dynarray.c index 9a7060ee..7f34eef8 100644 --- a/src/dynarray.c +++ b/src/dynarray.c @@ -4,14 +4,14 @@ #include "dynarray.h" -struct dynarray { +struct pa_dynarray { void **data; unsigned n_allocated, n_entries; }; -struct dynarray* dynarray_new(void) { - struct dynarray *a; - a = malloc(sizeof(struct dynarray)); +struct pa_dynarray* pa_dynarray_new(void) { + struct pa_dynarray *a; + a = malloc(sizeof(struct pa_dynarray)); assert(a); a->data = NULL; a->n_entries = 0; @@ -19,7 +19,7 @@ struct dynarray* dynarray_new(void) { return a; } -void dynarray_free(struct dynarray* a, void (*func)(void *p, void *userdata), void *userdata) { +void pa_dynarray_free(struct pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata) { unsigned i; assert(a); @@ -32,7 +32,7 @@ void dynarray_free(struct dynarray* a, void (*func)(void *p, void *userdata), vo free(a); } -void dynarray_put(struct dynarray*a, unsigned i, void *p) { +void pa_dynarray_put(struct pa_dynarray*a, unsigned i, void *p) { assert(a); if (i >= a->n_allocated) { @@ -53,13 +53,13 @@ void dynarray_put(struct dynarray*a, unsigned i, void *p) { a->n_entries = i+1; } -unsigned dynarray_append(struct dynarray*a, void *p) { +unsigned pa_dynarray_append(struct pa_dynarray*a, void *p) { unsigned i = a->n_entries; - dynarray_put(a, i, p); + pa_dynarray_put(a, i, p); return i; } -void *dynarray_get(struct dynarray*a, unsigned i) { +void *pa_dynarray_get(struct pa_dynarray*a, unsigned i) { assert(a); if (i >= a->n_allocated) return NULL; @@ -67,7 +67,7 @@ void *dynarray_get(struct dynarray*a, unsigned i) { return a->data[i]; } -unsigned dynarray_ncontents(struct dynarray*a) { +unsigned pa_dynarray_ncontents(struct pa_dynarray*a) { assert(a); return a->n_entries; } diff --git a/src/dynarray.h b/src/dynarray.h index 9ab861ce..fab3841d 100644 --- a/src/dynarray.h +++ b/src/dynarray.h @@ -1,16 +1,16 @@ #ifndef foodynarrayhfoo #define foodynarrayhfoo -struct dynarray; +struct pa_dynarray; -struct dynarray* dynarray_new(void); -void dynarray_free(struct dynarray* a, void (*func)(void *p, void *userdata), void *userdata); +struct pa_dynarray* pa_dynarray_new(void); +void pa_dynarray_free(struct pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata); -void dynarray_put(struct dynarray*a, unsigned i, void *p); -unsigned dynarray_append(struct dynarray*a, void *p); +void pa_dynarray_put(struct pa_dynarray*a, unsigned i, void *p); +unsigned pa_dynarray_append(struct pa_dynarray*a, void *p); -void *dynarray_get(struct dynarray*a, unsigned i); +void *pa_dynarray_get(struct pa_dynarray*a, unsigned i); -unsigned dynarray_ncontents(struct dynarray*a); +unsigned pa_dynarray_ncontents(struct pa_dynarray*a); #endif diff --git a/src/hashset.c b/src/hashset.c index 298650d5..4815a13a 100644 --- a/src/hashset.c +++ b/src/hashset.c @@ -12,7 +12,7 @@ struct hashset_entry { void *value; }; -struct hashset { +struct pa_hashset { unsigned size; struct hashset_entry **data; struct hashset_entry *first_entry; @@ -22,21 +22,21 @@ struct hashset { int (*compare_func) (const void*a, const void*b); }; -struct hashset *hashset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { - struct hashset *h; - h = malloc(sizeof(struct hashset)); +struct pa_hashset *pa_hashset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { + struct pa_hashset *h; + h = malloc(sizeof(struct pa_hashset)); assert(h); h->data = malloc(sizeof(struct hashset_entry*)*(h->size = 1023)); assert(h->data); memset(h->data, 0, sizeof(struct hashset_entry*)*(h->size = 1023)); h->first_entry = NULL; h->n_entries = 0; - h->hash_func = hash_func ? hash_func : idxset_trivial_hash_func; - h->compare_func = compare_func ? compare_func : idxset_trivial_compare_func; + h->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; + h->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; return h; } -static void remove(struct hashset *h, struct hashset_entry *e) { +static void remove(struct pa_hashset *h, struct hashset_entry *e) { assert(e); if (e->next) @@ -57,7 +57,7 @@ static void remove(struct hashset *h, struct hashset_entry *e) { h->n_entries--; } -void hashset_free(struct hashset*h, void (*free_func)(void *p, void *userdata), void *userdata) { +void pa_hashset_free(struct pa_hashset*h, void (*free_func)(void *p, void *userdata), void *userdata) { assert(h); while (h->first_entry) { @@ -70,7 +70,7 @@ void hashset_free(struct hashset*h, void (*free_func)(void *p, void *userdata), free(h); } -static struct hashset_entry *get(struct hashset *h, unsigned hash, const void *key) { +static struct hashset_entry *get(struct pa_hashset *h, unsigned hash, const void *key) { struct hashset_entry *e; for (e = h->data[hash]; e; e = e->bucket_next) @@ -80,7 +80,7 @@ static struct hashset_entry *get(struct hashset *h, unsigned hash, const void *k return NULL; } -int hashset_put(struct hashset *h, const void *key, void *value) { +int pa_hashset_put(struct pa_hashset *h, const void *key, void *value) { struct hashset_entry *e; unsigned hash; assert(h && key); @@ -113,7 +113,7 @@ int hashset_put(struct hashset *h, const void *key, void *value) { return 0; } -void* hashset_get(struct hashset *h, const void *key) { +void* pa_hashset_get(struct pa_hashset *h, const void *key) { unsigned hash; struct hashset_entry *e; assert(h && key); @@ -126,7 +126,7 @@ void* hashset_get(struct hashset *h, const void *key) { return e->value; } -int hashset_remove(struct hashset *h, const void *key) { +int pa_hashset_remove(struct pa_hashset *h, const void *key) { struct hashset_entry *e; unsigned hash; assert(h && key); @@ -140,6 +140,6 @@ int hashset_remove(struct hashset *h, const void *key) { return 0; } -unsigned hashset_ncontents(struct hashset *h) { +unsigned pa_hashset_ncontents(struct pa_hashset *h) { return h->n_entries; } diff --git a/src/hashset.h b/src/hashset.h index 7e035c02..a6ece8bf 100644 --- a/src/hashset.h +++ b/src/hashset.h @@ -1,16 +1,16 @@ #ifndef foohashsethfoo #define foohashsethfoo -struct hashset; +struct pa_hashset; -struct hashset *hashset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); -void hashset_free(struct hashset*, void (*free_func)(void *p, void *userdata), void *userdata); +struct pa_hashset *pa_hashset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); +void pa_hashset_free(struct pa_hashset*, void (*free_func)(void *p, void *userdata), void *userdata); -int hashset_put(struct hashset *h, const void *key, void *value); -void* hashset_get(struct hashset *h, const void *key); +int pa_hashset_put(struct pa_hashset *h, const void *key, void *value); +void* pa_hashset_get(struct pa_hashset *h, const void *key); -int hashset_remove(struct hashset *h, const void *key); +int pa_hashset_remove(struct pa_hashset *h, const void *key); -unsigned hashset_ncontents(struct hashset *h); +unsigned pa_hashset_ncontents(struct pa_hashset *h); #endif diff --git a/src/idxset.c b/src/idxset.c index 090bfc72..ba740250 100644 --- a/src/idxset.c +++ b/src/idxset.c @@ -14,7 +14,7 @@ struct idxset_entry { struct idxset_entry* iterate_prev, *iterate_next; }; -struct idxset { +struct pa_idxset { unsigned (*hash_func) (const void *p); int (*compare_func)(const void *a, const void *b); @@ -23,7 +23,7 @@ struct idxset { uint32_t index, start_index, array_size; }; -unsigned idxset_string_hash_func(const void *p) { +unsigned pa_idxset_string_hash_func(const void *p) { unsigned hash = 0; const char *c; @@ -33,25 +33,25 @@ unsigned idxset_string_hash_func(const void *p) { return hash; } -int idxset_string_compare_func(const void *a, const void *b) { +int pa_idxset_string_compare_func(const void *a, const void *b) { return strcmp(a, b); } -unsigned idxset_trivial_hash_func(const void *p) { +unsigned pa_idxset_trivial_hash_func(const void *p) { return (unsigned) p; } -int idxset_trivial_compare_func(const void *a, const void *b) { +int pa_idxset_trivial_compare_func(const void *a, const void *b) { return a != b; } -struct idxset* idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { - struct idxset *s; +struct pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { + struct pa_idxset *s; - s = malloc(sizeof(struct idxset)); + s = malloc(sizeof(struct pa_idxset)); assert(s); - s->hash_func = hash_func ? hash_func : idxset_trivial_hash_func; - s->compare_func = compare_func ? compare_func : idxset_trivial_compare_func; + s->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; + s->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; s->hash_table_size = 1023; s->hash_table = malloc(sizeof(struct idxset_entry*)*s->hash_table_size); assert(s->hash_table); @@ -67,7 +67,7 @@ struct idxset* idxset_new(unsigned (*hash_func) (const void *p), int (*compare_f return s; } -void idxset_free(struct idxset *s, void (*free_func) (void *p, void *userdata), void *userdata) { +void pa_idxset_free(struct pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata) { assert(s); if (free_func) { @@ -86,7 +86,7 @@ void idxset_free(struct idxset *s, void (*free_func) (void *p, void *userdata), free(s); } -static struct idxset_entry* hash_scan(struct idxset *s, struct idxset_entry* e, void *p) { +static struct idxset_entry* hash_scan(struct pa_idxset *s, struct idxset_entry* e, void *p) { assert(p); assert(s->compare_func); @@ -97,7 +97,7 @@ static struct idxset_entry* hash_scan(struct idxset *s, struct idxset_entry* e, return NULL; } -static void extend_array(struct idxset *s, uint32_t index) { +static void extend_array(struct pa_idxset *s, uint32_t index) { uint32_t i, j, l; struct idxset_entry** n; assert(index >= s->start_index); @@ -124,7 +124,7 @@ static void extend_array(struct idxset *s, uint32_t index) { s->start_index += i; } -static struct idxset_entry** array_index(struct idxset*s, uint32_t index) { +static struct idxset_entry** array_index(struct pa_idxset*s, uint32_t index) { if (index >= s->start_index + s->array_size) return NULL; @@ -134,7 +134,7 @@ static struct idxset_entry** array_index(struct idxset*s, uint32_t index) { return s->array + (index - s->start_index); } -int idxset_put(struct idxset*s, void *p, uint32_t *index) { +int pa_idxset_put(struct pa_idxset*s, void *p, uint32_t *index) { unsigned h; struct idxset_entry *e, **a; assert(s && p); @@ -191,7 +191,7 @@ int idxset_put(struct idxset*s, void *p, uint32_t *index) { return 0; } -void* idxset_get_by_index(struct idxset*s, uint32_t index) { +void* pa_idxset_get_by_index(struct pa_idxset*s, uint32_t index) { struct idxset_entry **a; assert(s); @@ -204,7 +204,7 @@ void* idxset_get_by_index(struct idxset*s, uint32_t index) { return (*a)->data; } -void* idxset_get_by_data(struct idxset*s, void *p, uint32_t *index) { +void* pa_idxset_get_by_data(struct pa_idxset*s, void *p, uint32_t *index) { unsigned h; struct idxset_entry *e; assert(s && p); @@ -222,7 +222,7 @@ void* idxset_get_by_data(struct idxset*s, void *p, uint32_t *index) { return e->data; } -static void remove_entry(struct idxset *s, struct idxset_entry *e) { +static void remove_entry(struct pa_idxset *s, struct idxset_entry *e) { struct idxset_entry **a; assert(s && e); @@ -257,7 +257,7 @@ static void remove_entry(struct idxset *s, struct idxset_entry *e) { s->n_entries--; } -void* idxset_remove_by_index(struct idxset*s, uint32_t index) { +void* pa_idxset_remove_by_index(struct pa_idxset*s, uint32_t index) { struct idxset_entry **a; void *data; @@ -272,7 +272,7 @@ void* idxset_remove_by_index(struct idxset*s, uint32_t index) { return data; } -void* idxset_remove_by_data(struct idxset*s, void *data, uint32_t *index) { +void* pa_idxset_remove_by_data(struct pa_idxset*s, void *data, uint32_t *index) { struct idxset_entry *e; unsigned h; @@ -292,7 +292,7 @@ void* idxset_remove_by_data(struct idxset*s, void *data, uint32_t *index) { return data; } -void* idxset_rrobin(struct idxset *s, uint32_t *index) { +void* pa_idxset_rrobin(struct pa_idxset *s, uint32_t *index) { struct idxset_entry **a, *e = NULL; assert(s && index); @@ -309,7 +309,7 @@ void* idxset_rrobin(struct idxset *s, uint32_t *index) { return e->data; } -void* idxset_first(struct idxset *s, uint32_t *index) { +void* pa_idxset_first(struct pa_idxset *s, uint32_t *index) { assert(s); if (!s->iterate_list_head) @@ -320,7 +320,7 @@ void* idxset_first(struct idxset *s, uint32_t *index) { return s->iterate_list_head->data; } -void *idxset_next(struct idxset *s, uint32_t *index) { +void *pa_idxset_next(struct pa_idxset *s, uint32_t *index) { struct idxset_entry **a, *e = NULL; assert(s && index); @@ -331,13 +331,13 @@ void *idxset_next(struct idxset *s, uint32_t *index) { *index = e->index; return e->data; } else { - *index = IDXSET_INVALID; + *index = PA_IDXSET_INVALID; return NULL; } } -int idxset_foreach(struct idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata) { +int pa_idxset_foreach(struct pa_idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata) { struct idxset_entry *e; assert(s && func); @@ -360,12 +360,12 @@ int idxset_foreach(struct idxset*s, int (*func)(void *p, uint32_t index, int *de return 0; } -unsigned idxset_ncontents(struct idxset*s) { +unsigned pa_idxset_ncontents(struct pa_idxset*s) { assert(s); return s->n_entries; } -int idxset_isempty(struct idxset *s) { +int pa_idxset_isempty(struct pa_idxset *s) { assert(s); return s->n_entries == 0; } diff --git a/src/idxset.h b/src/idxset.h index 61503977..be5bb294 100644 --- a/src/idxset.h +++ b/src/idxset.h @@ -3,41 +3,40 @@ #include -#define IDXSET_INVALID ((uint32_t) -1) +#define PA_IDXSET_INVALID ((uint32_t) -1) -unsigned idxset_trivial_hash_func(const void *p); -int idxset_trivial_compare_func(const void *a, const void *b); +unsigned pa_idxset_trivial_hash_func(const void *p); +int pa_idxset_trivial_compare_func(const void *a, const void *b); -unsigned idxset_string_hash_func(const void *p); -int idxset_string_compare_func(const void *a, const void *b); +unsigned pa_idxset_string_hash_func(const void *p); +int pa_idxset_string_compare_func(const void *a, const void *b); -struct idxset; +struct pa_idxset; -struct idxset* idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); -void idxset_free(struct idxset *s, void (*free_func) (void *p, void *userdata), void *userdata); +struct pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); +void pa_idxset_free(struct pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata); -int idxset_put(struct idxset*s, void *p, uint32_t *index); +int pa_idxset_put(struct pa_idxset*s, void *p, uint32_t *index); -void* idxset_get_by_index(struct idxset*s, uint32_t index); -void* idxset_get_by_data(struct idxset*s, void *p, uint32_t *index); +void* pa_idxset_get_by_index(struct pa_idxset*s, uint32_t index); +void* pa_idxset_get_by_data(struct pa_idxset*s, void *p, uint32_t *index); -void* idxset_remove_by_index(struct idxset*s, uint32_t index); -void* idxset_remove_by_data(struct idxset*s, void *p, uint32_t *index); +void* pa_idxset_remove_by_index(struct pa_idxset*s, uint32_t index); +void* pa_idxset_remove_by_data(struct pa_idxset*s, void *p, uint32_t *index); /* This may be used to iterate through all entries. When called with an invalid index value it returns the first entry, otherwise the next following. The function is best called with *index = - IDXSET_VALID first. */ -void* idxset_rrobin(struct idxset *s, uint32_t *index); + PA_IDXSET_VALID first. */ +void* pa_idxset_rrobin(struct pa_idxset *s, uint32_t *index); /* Return the oldest entry in the idxset */ -void* idxset_first(struct idxset *s, uint32_t *index); -void *idxset_next(struct idxset *s, uint32_t *index); +void* pa_idxset_first(struct pa_idxset *s, uint32_t *index); +void *pa_idxset_next(struct pa_idxset *s, uint32_t *index); -int idxset_foreach(struct idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata); - -unsigned idxset_ncontents(struct idxset*s); -int idxset_isempty(struct idxset *s); +int pa_idxset_foreach(struct pa_idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata); +unsigned pa_idxset_ncontents(struct pa_idxset*s); +int pa_idxset_isempty(struct pa_idxset *s); #endif diff --git a/src/iochannel.c b/src/iochannel.c index a133fdef..afa94cff 100644 --- a/src/iochannel.c +++ b/src/iochannel.c @@ -6,11 +6,11 @@ #include "iochannel.h" #include "util.h" -struct iochannel { +struct pa_iochannel { int ifd, ofd; struct pa_mainloop_api* mainloop; - void (*callback)(struct iochannel*io, void *userdata); + void (*callback)(struct pa_iochannel*io, void *userdata); void*userdata; int readable; @@ -21,7 +21,7 @@ struct iochannel { void* input_source, *output_source; }; -static void enable_mainloop_sources(struct iochannel *io) { +static void enable_mainloop_sources(struct pa_iochannel *io) { assert(io); if (io->input_source == io->output_source) { @@ -43,7 +43,7 @@ static void enable_mainloop_sources(struct iochannel *io) { } static void callback(struct pa_mainloop_api* m, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { - struct iochannel *io = userdata; + struct pa_iochannel *io = userdata; int changed = 0; assert(m && fd >= 0 && events && userdata); @@ -67,11 +67,11 @@ static void callback(struct pa_mainloop_api* m, void *id, int fd, enum pa_mainlo } } -struct iochannel* iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd) { - struct iochannel *io; +struct pa_iochannel* pa_iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd) { + struct pa_iochannel *io; assert(m && (ifd >= 0 || ofd >= 0)); - io = malloc(sizeof(struct iochannel)); + io = malloc(sizeof(struct pa_iochannel)); io->ifd = ifd; io->ofd = ofd; io->mainloop = m; @@ -84,18 +84,18 @@ struct iochannel* iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd) { if (ifd == ofd) { assert(ifd >= 0); - make_nonblock_fd(io->ifd); + pa_make_nonblock_fd(io->ifd); io->input_source = io->output_source = m->source_io(m, ifd, PA_MAINLOOP_API_IO_EVENT_BOTH, callback, io); } else { if (ifd >= 0) { - make_nonblock_fd(io->ifd); + pa_make_nonblock_fd(io->ifd); io->input_source = m->source_io(m, ifd, PA_MAINLOOP_API_IO_EVENT_INPUT, callback, io); } else io->input_source = NULL; if (ofd >= 0) { - make_nonblock_fd(io->ofd); + pa_make_nonblock_fd(io->ofd); io->output_source = m->source_io(m, ofd, PA_MAINLOOP_API_IO_EVENT_OUTPUT, callback, io); } else io->output_source = NULL; @@ -104,7 +104,7 @@ struct iochannel* iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd) { return io; } -void iochannel_free(struct iochannel*io) { +void pa_iochannel_free(struct pa_iochannel*io) { assert(io); if (!io->no_close) { @@ -122,17 +122,17 @@ void iochannel_free(struct iochannel*io) { free(io); } -int iochannel_is_readable(struct iochannel*io) { +int pa_iochannel_is_readable(struct pa_iochannel*io) { assert(io); return io->readable; } -int iochannel_is_writable(struct iochannel*io) { +int pa_iochannel_is_writable(struct pa_iochannel*io) { assert(io); return io->writable; } -ssize_t iochannel_write(struct iochannel*io, const void*data, size_t l) { +ssize_t pa_iochannel_write(struct pa_iochannel*io, const void*data, size_t l) { ssize_t r; assert(io && data && l && io->ofd >= 0); @@ -144,7 +144,7 @@ ssize_t iochannel_write(struct iochannel*io, const void*data, size_t l) { return r; } -ssize_t iochannel_read(struct iochannel*io, void*data, size_t l) { +ssize_t pa_iochannel_read(struct pa_iochannel*io, void*data, size_t l) { ssize_t r; assert(io && data && io->ifd >= 0); @@ -157,18 +157,18 @@ ssize_t iochannel_read(struct iochannel*io, void*data, size_t l) { return r; } -void iochannel_set_callback(struct iochannel*io, void (*callback)(struct iochannel*io, void *userdata), void *userdata) { +void pa_iochannel_set_callback(struct pa_iochannel*io, void (*callback)(struct pa_iochannel*io, void *userdata), void *userdata) { assert(io); io->callback = callback; io->userdata = userdata; } -void iochannel_set_noclose(struct iochannel*io, int b) { +void pa_iochannel_set_noclose(struct pa_iochannel*io, int b) { assert(io); io->no_close = b; } -void iochannel_peer_to_string(struct iochannel*io, char*s, size_t l) { +void pa_iochannel_peer_to_string(struct pa_iochannel*io, char*s, size_t l) { assert(io && s && l); - peer_to_string(s, l, io->ifd); + pa_peer_to_string(s, l, io->ifd); } diff --git a/src/iochannel.h b/src/iochannel.h index b0465a19..c550af19 100644 --- a/src/iochannel.h +++ b/src/iochannel.h @@ -4,21 +4,21 @@ #include #include "mainloop-api.h" -struct iochannel; +struct pa_iochannel; -struct iochannel* iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd); -void iochannel_free(struct iochannel*io); +struct pa_iochannel* pa_iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd); +void pa_iochannel_free(struct pa_iochannel*io); -ssize_t iochannel_write(struct iochannel*io, const void*data, size_t l); -ssize_t iochannel_read(struct iochannel*io, void*data, size_t l); +ssize_t pa_iochannel_write(struct pa_iochannel*io, const void*data, size_t l); +ssize_t pa_iochannel_read(struct pa_iochannel*io, void*data, size_t l); -int iochannel_is_readable(struct iochannel*io); -int iochannel_is_writable(struct iochannel*io); +int pa_iochannel_is_readable(struct pa_iochannel*io); +int pa_iochannel_is_writable(struct pa_iochannel*io); -void iochannel_set_noclose(struct iochannel*io, int b); +void pa_iochannel_set_noclose(struct pa_iochannel*io, int b); -void iochannel_set_callback(struct iochannel*io, void (*callback)(struct iochannel*io, void *userdata), void *userdata); +void pa_iochannel_set_callback(struct pa_iochannel*io, void (*callback)(struct pa_iochannel*io, void *userdata), void *userdata); -void iochannel_peer_to_string(struct iochannel*io, char*s, size_t l); +void pa_iochannel_peer_to_string(struct pa_iochannel*io, char*s, size_t l); #endif diff --git a/src/ioline.c b/src/ioline.c index ada9cee0..ab7cb517 100644 --- a/src/ioline.c +++ b/src/ioline.c @@ -9,8 +9,8 @@ #define BUFFER_LIMIT (64*1024) #define READ_SIZE (1024) -struct ioline { - struct iochannel *io; +struct pa_ioline { + struct pa_iochannel *io; int dead; char *wbuf; @@ -19,18 +19,18 @@ struct ioline { char *rbuf; size_t rbuf_length, rbuf_index, rbuf_valid_length; - void (*callback)(struct ioline*io, const char *s, void *userdata); + void (*callback)(struct pa_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); +static void io_callback(struct pa_iochannel*io, void *userdata); +static int do_write(struct pa_ioline *l); -struct ioline* ioline_new(struct iochannel *io) { - struct ioline *l; +struct pa_ioline* pa_ioline_new(struct pa_iochannel *io) { + struct pa_ioline *l; assert(io); - l = malloc(sizeof(struct ioline)); + l = malloc(sizeof(struct pa_ioline)); assert(l); l->io = io; l->dead = 0; @@ -44,20 +44,20 @@ struct ioline* ioline_new(struct iochannel *io) { l->callback = NULL; l->userdata = NULL; - iochannel_set_callback(io, io_callback, l); + pa_iochannel_set_callback(io, io_callback, l); return l; } -void ioline_free(struct ioline *l) { +void pa_ioline_free(struct pa_ioline *l) { assert(l); - iochannel_free(l->io); + pa_iochannel_free(l->io); free(l->wbuf); free(l->rbuf); free(l); } -void ioline_puts(struct ioline *l, const char *c) { +void pa_ioline_puts(struct pa_ioline *l, const char *c) { size_t len; assert(l && c); @@ -89,19 +89,19 @@ void ioline_puts(struct ioline *l, const char *c) { do_write(l); } -void ioline_set_callback(struct ioline*l, void (*callback)(struct ioline*io, const char *s, void *userdata), void *userdata) { +void pa_ioline_set_callback(struct pa_ioline*l, void (*callback)(struct pa_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) { +static int do_read(struct pa_ioline *l) { ssize_t r; size_t m, len; char *e; assert(l); - if (!iochannel_is_readable(l->io)) + if (!pa_iochannel_is_readable(l->io)) return 0; len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length; @@ -129,7 +129,7 @@ static int do_read(struct ioline *l) { 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) + if ((r = pa_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); @@ -159,14 +159,14 @@ static int do_read(struct ioline *l) { return 0; } -static int do_write(struct ioline *l) { +static int do_write(struct pa_ioline *l) { ssize_t r; assert(l); - if (!l->wbuf_valid_length || !iochannel_is_writable(l->io)) + if (!l->wbuf_valid_length || !pa_iochannel_is_writable(l->io)) return 0; - if ((r = iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0) + if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0) return -1; l->wbuf_valid_length -= r; @@ -176,8 +176,8 @@ static int do_write(struct ioline *l) { return 0; } -static void io_callback(struct iochannel*io, void *userdata) { - struct ioline *l = userdata; +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) diff --git a/src/ioline.h b/src/ioline.h index 55d7d4a3..ba7cf540 100644 --- a/src/ioline.h +++ b/src/ioline.h @@ -3,12 +3,12 @@ #include "iochannel.h" -struct ioline; +struct pa_ioline; -struct ioline* ioline_new(struct iochannel *io); -void ioline_free(struct ioline *l); +struct pa_ioline* pa_ioline_new(struct pa_iochannel *io); +void pa_ioline_free(struct pa_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); +void pa_ioline_puts(struct pa_ioline *s, const char *c); +void pa_ioline_set_callback(struct pa_ioline*io, void (*callback)(struct pa_ioline*io, const char *s, void *userdata), void *userdata); #endif diff --git a/src/main.c b/src/main.c index d10ce0d5..be75b372 100644 --- a/src/main.c +++ b/src/main.c @@ -10,7 +10,7 @@ #include "module.h" #include "mainloop-signal.h" -int stdin_inuse = 0, stdout_inuse = 0; +int pa_stdin_inuse = 0, pa_stdout_inuse = 0; static struct pa_mainloop *mainloop; @@ -21,7 +21,7 @@ static void signal_callback(void *id, int sig, void *userdata) { } int main(int argc, char *argv[]) { - struct core *c; + struct pa_core *c; int r, retval = 0; r = lt_dlinit(); @@ -35,26 +35,26 @@ int main(int argc, char *argv[]) { pa_signal_register(SIGINT, signal_callback, NULL); signal(SIGPIPE, SIG_IGN); - c = core_new(pa_mainloop_get_api(mainloop)); + c = pa_core_new(pa_mainloop_get_api(mainloop)); assert(c); - 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-simple-protocol-unix", NULL); - module_load(c, "module-cli-protocol-tcp", NULL); - module_load(c, "module-cli-protocol-unix", NULL); - module_load(c, "module-native-protocol-tcp", NULL);*/ - module_load(c, "module-native-protocol-unix", NULL); -/* module_load(c, "module-esound-protocol-tcp", NULL);*/ - module_load(c, "module-cli", NULL); + pa_module_load(c, "module-oss", "/dev/dsp"); +/* 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-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-unix", NULL); +/* pa_module_load(c, "module-esound-protocol-tcp", NULL);*/ + pa_module_load(c, "module-cli", NULL); fprintf(stderr, "main: mainloop entry.\n"); if (pa_mainloop_run(mainloop, &retval) < 0) retval = 1; fprintf(stderr, "main: mainloop exit.\n"); - core_free(c); + pa_core_free(c); pa_signal_done(); pa_mainloop_free(mainloop); diff --git a/src/main.h b/src/main.h index c4bea049..35333bbf 100644 --- a/src/main.h +++ b/src/main.h @@ -1,6 +1,6 @@ #ifndef foomainhfoo #define foomainhfoo -extern int stdin_inuse, stdout_inuse; +extern int pa_stdin_inuse, pa_stdout_inuse; #endif diff --git a/src/mainloop-signal.c b/src/mainloop-signal.c index dcc72f69..3c55f800 100644 --- a/src/mainloop-signal.c +++ b/src/mainloop-signal.c @@ -63,8 +63,8 @@ int pa_signal_init(struct pa_mainloop_api *a) { return -1; } - make_nonblock_fd(signal_pipe[0]); - make_nonblock_fd(signal_pipe[1]); + pa_make_nonblock_fd(signal_pipe[0]); + pa_make_nonblock_fd(signal_pipe[1]); api = a; mainloop_source = api->source_io(api, signal_pipe[0], PA_MAINLOOP_API_IO_EVENT_INPUT, callback, NULL); diff --git a/src/mainloop.c b/src/mainloop.c index 8629add2..4755cc8f 100644 --- a/src/mainloop.c +++ b/src/mainloop.c @@ -46,7 +46,7 @@ struct mainloop_source_time { }; struct pa_mainloop { - struct idxset *io_sources, *fixed_sources, *idle_sources, *time_sources; + struct pa_idxset *io_sources, *fixed_sources, *idle_sources, *time_sources; int io_sources_scan_dead, fixed_sources_scan_dead, idle_sources_scan_dead, time_sources_scan_dead; struct pollfd *pollfds; @@ -65,10 +65,10 @@ struct pa_mainloop *pa_mainloop_new(void) { m = malloc(sizeof(struct pa_mainloop)); assert(m); - m->io_sources = idxset_new(NULL, NULL); - m->fixed_sources = idxset_new(NULL, NULL); - m->idle_sources = idxset_new(NULL, NULL); - m->time_sources = idxset_new(NULL, NULL); + m->io_sources = pa_idxset_new(NULL, NULL); + m->fixed_sources = pa_idxset_new(NULL, NULL); + m->idle_sources = pa_idxset_new(NULL, NULL); + m->time_sources = pa_idxset_new(NULL, NULL); assert(m->io_sources && m->fixed_sources && m->idle_sources && m->time_sources); @@ -100,15 +100,15 @@ static int foreach(void *p, uint32_t index, int *del, void*userdata) { void pa_mainloop_free(struct pa_mainloop* m) { int all = 1; assert(m); - idxset_foreach(m->io_sources, foreach, &all); - idxset_foreach(m->fixed_sources, foreach, &all); - idxset_foreach(m->idle_sources, foreach, &all); - idxset_foreach(m->time_sources, foreach, &all); + pa_idxset_foreach(m->io_sources, foreach, &all); + pa_idxset_foreach(m->fixed_sources, foreach, &all); + pa_idxset_foreach(m->idle_sources, foreach, &all); + pa_idxset_foreach(m->time_sources, foreach, &all); - idxset_free(m->io_sources, NULL, NULL); - idxset_free(m->fixed_sources, NULL, NULL); - idxset_free(m->idle_sources, NULL, NULL); - idxset_free(m->time_sources, NULL, NULL); + pa_idxset_free(m->io_sources, NULL, NULL); + pa_idxset_free(m->fixed_sources, NULL, NULL); + pa_idxset_free(m->idle_sources, NULL, NULL); + pa_idxset_free(m->time_sources, NULL, NULL); free(m->pollfds); free(m); @@ -118,22 +118,22 @@ static void scan_dead(struct pa_mainloop *m) { int all = 0; assert(m); if (m->io_sources_scan_dead) - idxset_foreach(m->io_sources, foreach, &all); + pa_idxset_foreach(m->io_sources, foreach, &all); if (m->fixed_sources_scan_dead) - idxset_foreach(m->fixed_sources, foreach, &all); + pa_idxset_foreach(m->fixed_sources, foreach, &all); if (m->idle_sources_scan_dead) - idxset_foreach(m->idle_sources, foreach, &all); + pa_idxset_foreach(m->idle_sources, foreach, &all); if (m->time_sources_scan_dead) - idxset_foreach(m->time_sources, foreach, &all); + pa_idxset_foreach(m->time_sources, foreach, &all); } static void rebuild_pollfds(struct pa_mainloop *m) { struct mainloop_source_io*s; struct pollfd *p; - uint32_t index = IDXSET_INVALID; + uint32_t index = PA_IDXSET_INVALID; unsigned l; - l = idxset_ncontents(m->io_sources); + l = pa_idxset_ncontents(m->io_sources); if (m->max_pollfds < l) { m->pollfds = realloc(m->pollfds, sizeof(struct pollfd)*l); m->max_pollfds = l; @@ -141,7 +141,7 @@ static void rebuild_pollfds(struct pa_mainloop *m) { m->n_pollfds = 0; p = m->pollfds; - for (s = idxset_first(m->io_sources, &index); s; s = idxset_next(m->io_sources, &index)) { + for (s = pa_idxset_first(m->io_sources, &index); s; s = pa_idxset_next(m->io_sources, &index)) { if (s->header.dead) { s->pollfd = NULL; continue; @@ -158,10 +158,10 @@ static void rebuild_pollfds(struct pa_mainloop *m) { } static void dispatch_pollfds(struct pa_mainloop *m) { - uint32_t index = IDXSET_INVALID; + uint32_t index = PA_IDXSET_INVALID; struct mainloop_source_io *s; - for (s = idxset_first(m->io_sources, &index); s; s = idxset_next(m->io_sources, &index)) { + for (s = pa_idxset_first(m->io_sources, &index); s; s = pa_idxset_next(m->io_sources, &index)) { if (s->header.dead || !s->pollfd || !s->pollfd->revents) continue; @@ -173,11 +173,11 @@ static void dispatch_pollfds(struct pa_mainloop *m) { } } -static void run_fixed_or_idle(struct pa_mainloop *m, struct idxset *i) { - uint32_t index = IDXSET_INVALID; +static void run_fixed_or_idle(struct pa_mainloop *m, struct pa_idxset *i) { + uint32_t index = PA_IDXSET_INVALID; struct mainloop_source_fixed_or_idle *s; - for (s = idxset_first(i, &index); s; s = idxset_next(i, &index)) { + for (s = pa_idxset_first(i, &index); s; s = pa_idxset_next(i, &index)) { if (s->header.dead || !s->enabled) continue; @@ -187,17 +187,17 @@ static void run_fixed_or_idle(struct pa_mainloop *m, struct idxset *i) { } static int calc_next_timeout(struct pa_mainloop *m) { - uint32_t index = IDXSET_INVALID; + uint32_t index = PA_IDXSET_INVALID; struct mainloop_source_time *s; struct timeval now; int t = -1; - if (idxset_isempty(m->time_sources)) + if (pa_idxset_isempty(m->time_sources)) return -1; gettimeofday(&now, NULL); - for (s = idxset_first(m->time_sources, &index); s; s = idxset_next(m->time_sources, &index)) { + for (s = pa_idxset_first(m->time_sources, &index); s; s = pa_idxset_next(m->time_sources, &index)) { int tmp; if (s->header.dead || !s->enabled) @@ -223,16 +223,16 @@ static int calc_next_timeout(struct pa_mainloop *m) { } static void dispatch_timeout(struct pa_mainloop *m) { - uint32_t index = IDXSET_INVALID; + uint32_t index = PA_IDXSET_INVALID; struct mainloop_source_time *s; struct timeval now; assert(m); - if (idxset_isempty(m->time_sources)) + if (pa_idxset_isempty(m->time_sources)) return; gettimeofday(&now, NULL); - for (s = idxset_first(m->time_sources, &index); s; s = idxset_next(m->time_sources, &index)) { + for (s = pa_idxset_first(m->time_sources, &index); s; s = pa_idxset_next(m->time_sources, &index)) { if (s->header.dead || !s->enabled) continue; @@ -251,7 +251,7 @@ static int any_idle_sources(struct pa_mainloop *m) { uint32_t index; assert(m); - for (s = idxset_first(m->idle_sources, &index); s; s = idxset_next(m->idle_sources, &index)) + for (s = pa_idxset_first(m->idle_sources, &index); s; s = pa_idxset_next(m->idle_sources, &index)) if (!s->header.dead && s->enabled) return 1; @@ -334,7 +334,7 @@ static void* mainloop_source_io(struct pa_mainloop_api*a, int fd, enum pa_mainlo s->userdata = userdata; s->pollfd = NULL; - idxset_put(m->io_sources, s, NULL); + pa_idxset_put(m->io_sources, s, NULL); m->rebuild_pollfds = 1; return s; } @@ -380,7 +380,7 @@ static void* mainloop_source_fixed(struct pa_mainloop_api*a, void (*callback) (s s->callback = callback; s->userdata = userdata; - idxset_put(m->fixed_sources, s, NULL); + pa_idxset_put(m->fixed_sources, s, NULL); return s; } @@ -422,7 +422,7 @@ static void* mainloop_source_idle(struct pa_mainloop_api*a, void (*callback) (st s->callback = callback; s->userdata = userdata; - idxset_put(m->idle_sources, s, NULL); + pa_idxset_put(m->idle_sources, s, NULL); return s; } @@ -457,7 +457,7 @@ static void* mainloop_source_time(struct pa_mainloop_api*a, const struct timeval s->callback = callback; s->userdata = userdata; - idxset_put(m->time_sources, s, NULL); + pa_idxset_put(m->time_sources, s, NULL); return s; } diff --git a/src/memblock.c b/src/memblock.c index 067243c5..af57e3a4 100644 --- a/src/memblock.c +++ b/src/memblock.c @@ -5,69 +5,69 @@ #include "memblock.h" -unsigned memblock_count = 0, memblock_total = 0; +unsigned pa_memblock_count = 0, pa_memblock_total = 0; -struct memblock *memblock_new(size_t length) { - struct memblock *b = malloc(sizeof(struct memblock)+length); - b->type = MEMBLOCK_APPENDED; +struct pa_memblock *pa_memblock_new(size_t length) { + struct pa_memblock *b = malloc(sizeof(struct pa_memblock)+length); + b->type = PA_MEMBLOCK_APPENDED; b->ref = 1; b->length = length; b->data = b+1; - memblock_count++; - memblock_total += length; + pa_memblock_count++; + pa_memblock_total += length; return b; } -struct memblock *memblock_new_fixed(void *d, size_t length) { - struct memblock *b = malloc(sizeof(struct memblock)); - b->type = MEMBLOCK_FIXED; +struct pa_memblock *pa_memblock_new_fixed(void *d, size_t length) { + struct pa_memblock *b = malloc(sizeof(struct pa_memblock)); + b->type = PA_MEMBLOCK_FIXED; b->ref = 1; b->length = length; b->data = d; - memblock_count++; - memblock_total += length; + pa_memblock_count++; + pa_memblock_total += length; return b; } -struct memblock *memblock_new_dynamic(void *d, size_t length) { - struct memblock *b = malloc(sizeof(struct memblock)); - b->type = MEMBLOCK_DYNAMIC; +struct pa_memblock *pa_memblock_new_dynamic(void *d, size_t length) { + struct pa_memblock *b = malloc(sizeof(struct pa_memblock)); + b->type = PA_MEMBLOCK_DYNAMIC; b->ref = 1; b->length = length; b->data = d; - memblock_count++; - memblock_total += length; + pa_memblock_count++; + pa_memblock_total += length; return b; } -struct memblock* memblock_ref(struct memblock*b) { +struct pa_memblock* pa_memblock_ref(struct pa_memblock*b) { assert(b && b->ref >= 1); b->ref++; return b; } -void memblock_unref(struct memblock*b) { +void pa_memblock_unref(struct pa_memblock*b) { assert(b && b->ref >= 1); b->ref--; if (b->ref == 0) { - if (b->type == MEMBLOCK_DYNAMIC) + if (b->type == PA_MEMBLOCK_DYNAMIC) free(b->data); - memblock_count--; - memblock_total -= b->length; + pa_memblock_count--; + pa_memblock_total -= b->length; free(b); } } -void memblock_unref_fixed(struct memblock *b) { +void pa_memblock_unref_fixed(struct pa_memblock *b) { void *d; assert(b && b->ref >= 1); if (b->ref == 1) { - memblock_unref(b); + pa_memblock_unref(b); return; } @@ -75,6 +75,6 @@ void memblock_unref_fixed(struct memblock *b) { assert(d); memcpy(d, b->data, b->length); b->data = d; - b->type = MEMBLOCK_DYNAMIC; + b->type = PA_MEMBLOCK_DYNAMIC; } diff --git a/src/memblock.h b/src/memblock.h index e4a578b8..acdae047 100644 --- a/src/memblock.h +++ b/src/memblock.h @@ -4,26 +4,26 @@ #include #include -enum memblock_type { MEMBLOCK_FIXED, MEMBLOCK_APPENDED, MEMBLOCK_DYNAMIC }; +enum pa_memblock_type { PA_MEMBLOCK_FIXED, PA_MEMBLOCK_APPENDED, PA_MEMBLOCK_DYNAMIC }; -struct memblock { - enum memblock_type type; +struct pa_memblock { + enum pa_memblock_type type; unsigned ref; size_t length; void *data; }; -struct memblock *memblock_new(size_t length); -struct memblock *memblock_new_fixed(void *data, size_t length); -struct memblock *memblock_new_dynamic(void *data, size_t length); +struct pa_memblock *pa_memblock_new(size_t length); +struct pa_memblock *pa_memblock_new_fixed(void *data, size_t length); +struct pa_memblock *pa_memblock_new_dynamic(void *data, size_t length); -void memblock_unref(struct memblock*b); -struct memblock* memblock_ref(struct memblock*b); +void pa_memblock_unref(struct pa_memblock*b); +struct pa_memblock* pa_memblock_ref(struct pa_memblock*b); -void memblock_unref_fixed(struct memblock*b); +void pa_memblock_unref_fixed(struct pa_memblock*b); -#define memblock_assert_exclusive(b) assert((b)->ref == 1) +#define pa_memblock_assert_exclusive(b) assert((b)->ref == 1) -extern unsigned memblock_count, memblock_total; +extern unsigned pa_memblock_count, pa_memblock_total; #endif diff --git a/src/memblockq.c b/src/memblockq.c index cab02bed..b70a67ff 100644 --- a/src/memblockq.c +++ b/src/memblockq.c @@ -8,24 +8,24 @@ struct memblock_list { struct memblock_list *next; - struct memchunk chunk; + struct pa_memchunk chunk; struct timeval stamp; }; -struct memblockq { +struct pa_memblockq { struct memblock_list *blocks, *blocks_tail; unsigned n_blocks; size_t total_length, maxlength, base, prebuf; int measure_delay; uint32_t delay; - struct mcalign *mcalign; + struct pa_mcalign *mcalign; }; -struct memblockq* memblockq_new(size_t maxlength, size_t base, size_t prebuf) { - struct memblockq* bq; +struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t base, size_t prebuf) { + struct pa_memblockq* bq; assert(maxlength && base); - bq = malloc(sizeof(struct memblockq)); + bq = malloc(sizeof(struct pa_memblockq)); assert(bq); bq->blocks = bq->blocks_tail = 0; bq->n_blocks = 0; @@ -47,23 +47,23 @@ struct memblockq* memblockq_new(size_t maxlength, size_t base, size_t prebuf) { return bq; } -void memblockq_free(struct memblockq* bq) { +void pa_memblockq_free(struct pa_memblockq* bq) { struct memblock_list *l; assert(bq); if (bq->mcalign) - mcalign_free(bq->mcalign); + pa_mcalign_free(bq->mcalign); while ((l = bq->blocks)) { bq->blocks = l->next; - memblock_unref(l->chunk.memblock); + pa_memblock_unref(l->chunk.memblock); free(l); } free(bq); } -void memblockq_push(struct memblockq* bq, const struct memchunk *chunk, size_t delta) { +void pa_memblockq_push(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta) { struct memblock_list *q; assert(bq && chunk && chunk->memblock && chunk->length && (chunk->length % bq->base) == 0); @@ -76,7 +76,7 @@ void memblockq_push(struct memblockq* bq, const struct memchunk *chunk, size_t d timerclear(&q->stamp); q->chunk = *chunk; - memblock_ref(q->chunk.memblock); + pa_memblock_ref(q->chunk.memblock); assert(q->chunk.index+q->chunk.length <= q->chunk.memblock->length); q->next = NULL; @@ -90,10 +90,10 @@ void memblockq_push(struct memblockq* bq, const struct memchunk *chunk, size_t d bq->n_blocks++; bq->total_length += chunk->length; - memblockq_shorten(bq, bq->maxlength); + pa_memblockq_shorten(bq, bq->maxlength); } -int memblockq_peek(struct memblockq* bq, struct memchunk *chunk) { +int pa_memblockq_peek(struct pa_memblockq* bq, struct pa_memchunk *chunk) { assert(bq && chunk); if (!bq->blocks || bq->total_length < bq->prebuf) @@ -102,16 +102,16 @@ int memblockq_peek(struct memblockq* bq, struct memchunk *chunk) { bq->prebuf = 0; *chunk = bq->blocks->chunk; - memblock_ref(chunk->memblock); + pa_memblock_ref(chunk->memblock); - if (chunk->memblock->ref != 2) - fprintf(stderr, "block %p with ref %u peeked.\n", chunk->memblock, chunk->memblock->ref); +/* if (chunk->memblock->ref != 2) */ +/* fprintf(stderr, "block %p with ref %u peeked.\n", chunk->memblock, chunk->memblock->ref); */ return 0; } /* -int memblockq_pop(struct memblockq* bq, struct memchunk *chunk) { +int memblockq_pop(struct memblockq* bq, struct pa_memchunk *chunk) { struct memblock_list *q; assert(bq && chunk); @@ -154,7 +154,7 @@ static uint32_t age(struct timeval *tv) { return r; } -void memblockq_drop(struct memblockq *bq, size_t length) { +void pa_memblockq_drop(struct pa_memblockq *bq, size_t length) { assert(bq && length && (length % bq->base) == 0); while (length > 0) { @@ -178,7 +178,7 @@ void memblockq_drop(struct memblockq *bq, size_t length) { bq->blocks = bq->blocks->next; if (bq->blocks == NULL) bq->blocks_tail = NULL; - memblock_unref(q->chunk.memblock); + pa_memblock_unref(q->chunk.memblock); free(q); bq->n_blocks--; @@ -188,52 +188,52 @@ void memblockq_drop(struct memblockq *bq, size_t length) { } } -void memblockq_shorten(struct memblockq *bq, size_t length) { +void pa_memblockq_shorten(struct pa_memblockq *bq, size_t length) { size_t l; assert(bq); if (bq->total_length <= length) return; - fprintf(stderr, "Warning! memblockq_shorten()\n"); + fprintf(stderr, "Warning! pa_memblockq_shorten()\n"); l = bq->total_length - length; l /= bq->base; l *= bq->base; - memblockq_drop(bq, l); + pa_memblockq_drop(bq, l); } -void memblockq_empty(struct memblockq *bq) { +void pa_memblockq_empty(struct pa_memblockq *bq) { assert(bq); - memblockq_shorten(bq, 0); + pa_memblockq_shorten(bq, 0); } -int memblockq_is_readable(struct memblockq *bq) { +int pa_memblockq_is_readable(struct pa_memblockq *bq) { assert(bq); return bq->total_length >= bq->prebuf; } -int memblockq_is_writable(struct memblockq *bq, size_t length) { +int pa_memblockq_is_writable(struct pa_memblockq *bq, size_t length) { assert(bq); assert(length <= bq->maxlength); return bq->total_length + length <= bq->maxlength; } -uint32_t memblockq_get_delay(struct memblockq *bq) { +uint32_t pa_memblockq_get_delay(struct pa_memblockq *bq) { assert(bq); return bq->delay; } -uint32_t memblockq_get_length(struct memblockq *bq) { +uint32_t pa_memblockq_get_length(struct pa_memblockq *bq) { assert(bq); return bq->total_length; } -uint32_t memblockq_missing_to(struct memblockq *bq, size_t qlen) { +uint32_t pa_memblockq_missing_to(struct pa_memblockq *bq, size_t qlen) { assert(bq && qlen); if (bq->total_length >= qlen) @@ -242,25 +242,25 @@ uint32_t memblockq_missing_to(struct memblockq *bq, size_t qlen) { return qlen - bq->total_length; } -void memblockq_push_align(struct memblockq* bq, const struct memchunk *chunk, size_t delta) { - struct memchunk rchunk; +void pa_memblockq_push_align(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta) { + struct pa_memchunk rchunk; assert(bq && chunk && bq->base); if (bq->base == 1) { - memblockq_push(bq, chunk, delta); + pa_memblockq_push(bq, chunk, delta); return; } if (!bq->mcalign) { - bq->mcalign = mcalign_new(bq->base); + bq->mcalign = pa_mcalign_new(bq->base); assert(bq->mcalign); } - mcalign_push(bq->mcalign, chunk); + pa_mcalign_push(bq->mcalign, chunk); - while (mcalign_pop(bq->mcalign, &rchunk) >= 0) { - memblockq_push(bq, &rchunk, delta); - memblock_unref(rchunk.memblock); + while (pa_mcalign_pop(bq->mcalign, &rchunk) >= 0) { + pa_memblockq_push(bq, &rchunk, delta); + pa_memblock_unref(rchunk.memblock); delta = 0; } } diff --git a/src/memblockq.h b/src/memblockq.h index d19aac0e..d8b9567f 100644 --- a/src/memblockq.h +++ b/src/memblockq.h @@ -6,46 +6,46 @@ #include "memblock.h" #include "memchunk.h" -struct memblockq; +struct pa_memblockq; /* Parameters: the maximum length of the memblock queue, a base value for all operations (that is, all byte operations shall work on multiples of this base value) and an amount of bytes to prebuffer -before having memblockq_peek() succeed. */ -struct memblockq* memblockq_new(size_t maxlength, size_t base, size_t prebuf); -void memblockq_free(struct memblockq*bq); +before having pa_memblockq_peek() succeed. */ +struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t base, size_t prebuf); +void pa_memblockq_free(struct pa_memblockq*bq); /* Push a new memory chunk into the queue. Optionally specify a value for future cancellation. This is currently not implemented, however! */ -void memblockq_push(struct memblockq* bq, const struct memchunk *chunk, size_t delta); +void pa_memblockq_push(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta); -/* Same as memblockq_push(), however chunks are filtered through a mcalign object, and thus aligned to multiples of base */ -void memblockq_push_align(struct memblockq* bq, const struct memchunk *chunk, size_t delta); +/* Same as pa_memblockq_push(), however chunks are filtered through a mcalign object, and thus aligned to multiples of base */ +void pa_memblockq_push_align(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta); /* Return a copy of the next memory chunk in the queue. It is not removed from the queue */ -int memblockq_peek(struct memblockq* bq, struct memchunk *chunk); +int pa_memblockq_peek(struct pa_memblockq* bq, struct pa_memchunk *chunk); /* Drop the specified bytes from the queue */ -void memblockq_drop(struct memblockq *bq, size_t length); +void pa_memblockq_drop(struct pa_memblockq *bq, size_t length); -/* Shorten the memblockq to the specified length by dropping data at the end of the queue */ -void memblockq_shorten(struct memblockq *bq, size_t length); +/* Shorten the pa_memblockq to the specified length by dropping data at the end of the queue */ +void pa_memblockq_shorten(struct pa_memblockq *bq, size_t length); -/* Empty the memblockq */ -void memblockq_empty(struct memblockq *bq); +/* Empty the pa_memblockq */ +void pa_memblockq_empty(struct pa_memblockq *bq); -/* Test if the memblockq is currently readable, that is, more data than base */ -int memblockq_is_readable(struct memblockq *bq); +/* Test if the pa_memblockq is currently readable, that is, more data than base */ +int pa_memblockq_is_readable(struct pa_memblockq *bq); -/* Test if the memblockq is currently writable for the specified amount of bytes */ -int memblockq_is_writable(struct memblockq *bq, size_t length); +/* Test if the pa_memblockq is currently writable for the specified amount of bytes */ +int pa_memblockq_is_writable(struct pa_memblockq *bq, size_t length); /* The time memory chunks stay in the queue until they are removed completely in usecs */ -uint32_t memblockq_get_delay(struct memblockq *bq); +uint32_t pa_memblockq_get_delay(struct pa_memblockq *bq); /* Return the length of the queue in bytes */ -uint32_t memblockq_get_length(struct memblockq *bq); +uint32_t pa_memblockq_get_length(struct pa_memblockq *bq); /* Return how many bytes are missing in queue to the specified fill amount */ -uint32_t memblockq_missing_to(struct memblockq *bq, size_t qlen); +uint32_t pa_memblockq_missing_to(struct pa_memblockq *bq, size_t qlen); #endif diff --git a/src/memchunk.c b/src/memchunk.c index faee4508..c0be8cce 100644 --- a/src/memchunk.c +++ b/src/memchunk.c @@ -5,34 +5,34 @@ #include "memchunk.h" -void memchunk_make_writable(struct memchunk *c) { - struct memblock *n; +void pa_memchunk_make_writable(struct pa_memchunk *c) { + struct pa_memblock *n; assert(c && c->memblock && c->memblock->ref >= 1); if (c->memblock->ref == 1) return; - n = memblock_new(c->length); + n = pa_memblock_new(c->length); assert(n); memcpy(n->data, c->memblock->data+c->index, c->length); - memblock_unref(c->memblock); + pa_memblock_unref(c->memblock); c->memblock = n; c->index = 0; } -struct mcalign { +struct pa_mcalign { size_t base; - struct memchunk chunk; + struct pa_memchunk chunk; uint8_t *buffer; size_t buffer_fill; }; -struct mcalign *mcalign_new(size_t base) { - struct mcalign *m; +struct pa_mcalign *pa_mcalign_new(size_t base) { + struct pa_mcalign *m; assert(base); - m = malloc(sizeof(struct mcalign)); + m = malloc(sizeof(struct pa_mcalign)); assert(m); m->base = base; m->chunk.memblock = NULL; @@ -42,25 +42,25 @@ struct mcalign *mcalign_new(size_t base) { return m; } -void mcalign_free(struct mcalign *m) { +void pa_mcalign_free(struct pa_mcalign *m) { assert(m); free(m->buffer); if (m->chunk.memblock) - memblock_unref(m->chunk.memblock); + pa_memblock_unref(m->chunk.memblock); free(m); } -void mcalign_push(struct mcalign *m, const struct memchunk *c) { +void pa_mcalign_push(struct pa_mcalign *m, const struct pa_memchunk *c) { assert(m && c && !m->chunk.memblock && c->memblock && c->length); m->chunk = *c; - memblock_ref(m->chunk.memblock); + pa_memblock_ref(m->chunk.memblock); } -int mcalign_pop(struct mcalign *m, struct memchunk *c) { +int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c) { assert(m && c && m->base > m->buffer_fill); int ret; @@ -80,13 +80,13 @@ int mcalign_pop(struct mcalign *m, struct memchunk *c) { if (m->chunk.length == 0) { m->chunk.length = m->chunk.index = 0; - memblock_unref(m->chunk.memblock); + pa_memblock_unref(m->chunk.memblock); m->chunk.memblock = NULL; } assert(m->buffer_fill <= m->base); if (m->buffer_fill == m->base) { - c->memblock = memblock_new_dynamic(m->buffer, m->base); + c->memblock = pa_memblock_new_dynamic(m->buffer, m->base); assert(c->memblock); c->index = 0; c->length = m->base; @@ -111,13 +111,13 @@ int mcalign_pop(struct mcalign *m, struct memchunk *c) { if (m->chunk.length) { *c = m->chunk; - memblock_ref(c->memblock); + pa_memblock_ref(c->memblock); ret = 0; } else ret = -1; m->chunk.length = m->chunk.index = 0; - memblock_unref(m->chunk.memblock); + pa_memblock_unref(m->chunk.memblock); m->chunk.memblock = NULL; return ret; diff --git a/src/memchunk.h b/src/memchunk.h index d395cf2c..24c031a5 100644 --- a/src/memchunk.h +++ b/src/memchunk.h @@ -3,18 +3,18 @@ #include "memblock.h" -struct memchunk { - struct memblock *memblock; +struct pa_memchunk { + struct pa_memblock *memblock; size_t index, length; }; -void memchunk_make_writable(struct memchunk *c); +void pa_memchunk_make_writable(struct pa_memchunk *c); -struct mcalign; +struct pa_mcalign; -struct mcalign *mcalign_new(size_t base); -void mcalign_free(struct mcalign *m); -void mcalign_push(struct mcalign *m, const struct memchunk *c); -int mcalign_pop(struct mcalign *m, struct memchunk *c); +struct pa_mcalign *pa_mcalign_new(size_t base); +void pa_mcalign_free(struct pa_mcalign *m); +void pa_mcalign_push(struct pa_mcalign *m, const struct pa_memchunk *c); +int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c); #endif diff --git a/src/module-cli.c b/src/module-cli.c index 883f4f53..4a1692ee 100644 --- a/src/module-cli.c +++ b/src/module-cli.c @@ -7,29 +7,29 @@ #include "iochannel.h" #include "cli.h" -int module_init(struct core *c, struct module*m) { - struct iochannel *io; +int module_init(struct pa_core *c, struct pa_module*m) { + struct pa_iochannel *io; assert(c && m); - if (stdin_inuse || stdout_inuse) { + if (pa_stdin_inuse || pa_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); + pa_stdin_inuse = pa_stdout_inuse = 1; + io = pa_iochannel_new(c->mainloop, STDIN_FILENO, STDOUT_FILENO); assert(io); - iochannel_set_noclose(io, 1); + pa_iochannel_set_noclose(io, 1); - m->userdata = cli_new(c, io); + m->userdata = pa_cli_new(c, io); assert(m->userdata); return 0; } -void module_done(struct core *c, struct module*m) { +void module_done(struct pa_core *c, struct pa_module*m) { assert(c && m); - cli_free(m->userdata); - assert(stdin_inuse && stdout_inuse); - stdin_inuse = stdout_inuse = 0; + pa_cli_free(m->userdata); + assert(pa_stdin_inuse && pa_stdout_inuse); + pa_stdin_inuse = pa_stdout_inuse = 0; } diff --git a/src/module-oss-mmap.c b/src/module-oss-mmap.c index 3f69e05b..ef2b19d0 100644 --- a/src/module-oss-mmap.c +++ b/src/module-oss-mmap.c @@ -19,9 +19,9 @@ #include "sample-util.h" struct userdata { - struct sink *sink; - struct source *source; - struct core *core; + struct pa_sink *sink; + struct pa_source *source; + struct pa_core *core; struct pa_sample_spec sample_spec; size_t in_fragment_size, out_fragment_size, in_fragments, out_fragments, out_fill; @@ -31,13 +31,13 @@ struct userdata { void *in_mmap, *out_mmap; size_t in_mmap_length, out_mmap_length; - struct mainloop_source *mainloop_source; + void *mainloop_source; - struct memblock **in_memblocks, **out_memblocks; + struct pa_memblock **in_memblocks, **out_memblocks; unsigned out_current, in_current; }; -void module_done(struct core *c, struct module*m); +void module_done(struct pa_core *c, struct pa_module*m); static void out_clear_memblocks(struct userdata*u, unsigned n) { unsigned i = u->out_current; @@ -48,7 +48,7 @@ static void out_clear_memblocks(struct userdata*u, unsigned n) { while (n > 0) { if (u->out_memblocks[i]) { - memblock_unref_fixed(u->out_memblocks[i]); + pa_memblock_unref_fixed(u->out_memblocks[i]); u->out_memblocks[i] = NULL; } @@ -64,15 +64,15 @@ static void out_fill_memblocks(struct userdata *u, unsigned n) { assert(u && u->out_memblocks); while (n > 0) { - struct memchunk chunk; + struct pa_memchunk chunk; if (!u->out_memblocks[u->out_current]) { - u->out_memblocks[u->out_current] = chunk.memblock = memblock_new_fixed(u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size); + u->out_memblocks[u->out_current] = chunk.memblock = pa_memblock_new_fixed(u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size); chunk.length = chunk.memblock->length; chunk.index = 0; - sink_render_into_full(u->sink, &chunk); + pa_sink_render_into_full(u->sink, &chunk); } u->out_current++; @@ -106,14 +106,14 @@ static void in_post_memblocks(struct userdata *u, unsigned n) { assert(u && u->in_memblocks); while (n > 0) { - struct memchunk chunk; + struct pa_memchunk chunk; if (!u->in_memblocks[u->in_current]) { - u->in_memblocks[u->in_current] = chunk.memblock = memblock_new_fixed(u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size); + u->in_memblocks[u->in_current] = chunk.memblock = pa_memblock_new_fixed(u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size); chunk.length = chunk.memblock->length; chunk.index = 0; - source_post(u->source, &chunk); + pa_source_post(u->source, &chunk); } u->in_current++; @@ -133,7 +133,7 @@ static void in_clear_memblocks(struct userdata*u, unsigned n) { while (n > 0) { if (u->in_memblocks[i]) { - memblock_unref_fixed(u->in_memblocks[i]); + pa_memblock_unref_fixed(u->in_memblocks[i]); u->in_memblocks[i] = NULL; } @@ -172,7 +172,7 @@ static void io_callback(struct pa_mainloop_api *m, void *id, int fd, enum pa_mai do_write(u); } -static uint32_t sink_get_latency_cb(struct sink *s) { +static uint32_t sink_get_latency_cb(struct pa_sink *s) { struct userdata *u = s->userdata; assert(s && u); @@ -180,7 +180,7 @@ static uint32_t sink_get_latency_cb(struct sink *s) { return pa_samples_usec(u->out_fill, &s->sample_spec); } -int module_init(struct core *c, struct module*m) { +int module_init(struct pa_core *c, struct pa_module*m) { struct audio_buf_info info; struct userdata *u = NULL; char *p; @@ -240,7 +240,7 @@ int module_init(struct core *c, struct module*m) { goto fail; } - if (oss_auto_format(u->fd, &u->sample_spec) < 0) + if (pa_oss_auto_format(u->fd, &u->sample_spec) < 0) goto fail; if (mode != O_WRONLY) { @@ -262,12 +262,12 @@ int module_init(struct core *c, struct module*m) { } } else { - u->source = source_new(c, "dsp", 0, &u->sample_spec); + u->source = pa_source_new(c, "dsp", 0, &u->sample_spec); assert(u->source); u->source->userdata = u; - u->in_memblocks = malloc(sizeof(struct memblock *)*u->in_fragments); - memset(u->in_memblocks, 0, sizeof(struct memblock *)*u->in_fragments); + u->in_memblocks = malloc(sizeof(struct pa_memblock *)*u->in_fragments); + memset(u->in_memblocks, 0, sizeof(struct pa_memblock *)*u->in_fragments); enable_bits |= PCM_ENABLE_INPUT; } @@ -291,15 +291,15 @@ int module_init(struct core *c, struct module*m) { goto fail; } } else { - silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec); + pa_silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec); - u->sink = sink_new(c, "dsp", 0, &u->sample_spec); + u->sink = pa_sink_new(c, "dsp", 0, &u->sample_spec); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; u->sink->userdata = u; u->out_memblocks = malloc(sizeof(struct memblock *)*u->out_fragments); - memset(u->out_memblocks, 0, sizeof(struct memblock *)*u->out_fragments); + memset(u->out_memblocks, 0, sizeof(struct pa_memblock *)*u->out_fragments); enable_bits |= PCM_ENABLE_OUTPUT; } @@ -329,7 +329,7 @@ fail: return -1; } -void module_done(struct core *c, struct module*m) { +void pa_module_done(struct pa_core *c, struct pa_module*m) { struct userdata *u; assert(c && m); @@ -353,10 +353,10 @@ void module_done(struct core *c, struct module*m) { munmap(u->out_mmap, u->out_mmap_length); if (u->sink) - sink_free(u->sink); + pa_sink_free(u->sink); if (u->source) - source_free(u->source); + pa_source_free(u->source); if (u->mainloop_source) u->core->mainloop->cancel_io(u->core->mainloop, u->mainloop_source); diff --git a/src/module-oss.c b/src/module-oss.c index 75082a7f..3a1afd47 100644 --- a/src/module-oss.c +++ b/src/module-oss.c @@ -18,12 +18,12 @@ #include "sample-util.h" struct userdata { - struct sink *sink; - struct source *source; - struct iochannel *io; - struct core *core; + struct pa_sink *sink; + struct pa_source *source; + struct pa_iochannel *io; + struct pa_core *core; - struct memchunk memchunk, silence; + struct pa_memchunk memchunk, silence; uint32_t in_fragment_size, out_fragment_size, sample_size; @@ -31,15 +31,15 @@ struct userdata { }; static void do_write(struct userdata *u) { - struct memchunk *memchunk; + struct pa_memchunk *memchunk; ssize_t r; assert(u); - if (!u->sink || !iochannel_is_writable(u->io)) + if (!u->sink || !pa_iochannel_is_writable(u->io)) return; if (!u->memchunk.length) { - if (sink_render(u->sink, u->out_fragment_size, &u->memchunk) < 0) + if (pa_sink_render(u->sink, u->out_fragment_size, &u->memchunk) < 0) memchunk = &u->silence; else memchunk = &u->memchunk; @@ -47,7 +47,7 @@ static void do_write(struct userdata *u) { assert(memchunk->memblock && memchunk->length); - if ((r = iochannel_write(u->io, memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { + if ((r = pa_iochannel_write(u->io, memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { fprintf(stderr, "write() failed: %s\n", strerror(errno)); return; } @@ -59,24 +59,24 @@ static void do_write(struct userdata *u) { u->memchunk.length -= r; if (u->memchunk.length <= 0) { - memblock_unref(u->memchunk.memblock); + pa_memblock_unref(u->memchunk.memblock); u->memchunk.memblock = NULL; } } } static void do_read(struct userdata *u) { - struct memchunk memchunk; + struct pa_memchunk memchunk; ssize_t r; assert(u); - if (!u->source || !iochannel_is_readable(u->io)) + if (!u->source || !pa_iochannel_is_readable(u->io)) return; - memchunk.memblock = memblock_new(u->in_fragment_size); + memchunk.memblock = pa_memblock_new(u->in_fragment_size); assert(memchunk.memblock); - if ((r = iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { - memblock_unref(memchunk.memblock); + if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { + pa_memblock_unref(memchunk.memblock); fprintf(stderr, "read() failed: %s\n", strerror(errno)); return; } @@ -85,18 +85,18 @@ static void do_read(struct userdata *u) { memchunk.length = memchunk.memblock->length = r; memchunk.index = 0; - source_post(u->source, &memchunk); - memblock_unref(memchunk.memblock); + pa_source_post(u->source, &memchunk); + pa_memblock_unref(memchunk.memblock); }; -static void io_callback(struct iochannel *io, void*userdata) { +static void io_callback(struct pa_iochannel *io, void*userdata) { struct userdata *u = userdata; assert(u); do_write(u); do_read(u); } -static uint32_t sink_get_latency_cb(struct sink *s) { +static uint32_t sink_get_latency_cb(struct pa_sink *s) { int arg; struct userdata *u = s->userdata; assert(s && u && u->sink); @@ -110,7 +110,7 @@ static uint32_t sink_get_latency_cb(struct sink *s) { return pa_samples_usec(arg, &s->sample_spec); } -int module_init(struct core *c, struct module*m) { +int module_init(struct pa_core *c, struct pa_module*m) { struct audio_buf_info info; struct userdata *u = NULL; char *p; @@ -154,7 +154,7 @@ int module_init(struct core *c, struct module*m) { goto fail; } - if (oss_auto_format(fd, &ss) < 0) + if (pa_oss_auto_format(fd, &ss) < 0) goto fail; if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) { @@ -180,7 +180,7 @@ int module_init(struct core *c, struct module*m) { u->core = c; if (mode != O_RDONLY) { - u->sink = sink_new(c, "dsp", 0, &ss); + u->sink = pa_sink_new(c, "dsp", 0, &ss); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; u->sink->userdata = u; @@ -188,7 +188,7 @@ int module_init(struct core *c, struct module*m) { u->sink = NULL; if (mode != O_WRONLY) { - u->source = source_new(c, "dsp", 0, &ss); + u->source = pa_source_new(c, "dsp", 0, &ss); assert(u->source); u->source->userdata = u; } else @@ -196,9 +196,9 @@ int module_init(struct core *c, struct module*m) { assert(u->source || u->sink); - u->io = iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : 0); + u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : 0); assert(u->io); - iochannel_set_callback(u->io, io_callback, u); + pa_iochannel_set_callback(u->io, io_callback, u); u->fd = fd; u->memchunk.memblock = NULL; @@ -207,9 +207,9 @@ int module_init(struct core *c, struct module*m) { u->out_fragment_size = out_frag_size; u->in_fragment_size = in_frag_size; - u->silence.memblock = memblock_new(u->silence.length = u->out_fragment_size); + u->silence.memblock = pa_memblock_new(u->silence.length = u->out_fragment_size); assert(u->silence.memblock); - silence_memblock(u->silence.memblock, &ss); + pa_silence_memblock(u->silence.memblock, &ss); u->silence.index = 0; m->userdata = u; @@ -223,7 +223,7 @@ fail: return -1; } -void module_done(struct core *c, struct module*m) { +void module_done(struct pa_core *c, struct pa_module*m) { struct userdata *u; assert(c && m); @@ -231,14 +231,14 @@ void module_done(struct core *c, struct module*m) { assert(u); if (u->memchunk.memblock) - memblock_unref(u->memchunk.memblock); + pa_memblock_unref(u->memchunk.memblock); if (u->silence.memblock) - memblock_unref(u->silence.memblock); + pa_memblock_unref(u->silence.memblock); if (u->sink) - sink_free(u->sink); + pa_sink_free(u->sink); if (u->source) - source_free(u->source); - iochannel_free(u->io); + pa_source_free(u->source); + pa_iochannel_free(u->io); free(u); } diff --git a/src/module-pipe-sink.c b/src/module-pipe-sink.c index 9747c330..ea5c15db 100644 --- a/src/module-pipe-sink.c +++ b/src/module-pipe-sink.c @@ -15,13 +15,13 @@ struct userdata { char *filename; - struct sink *sink; - struct iochannel *io; - struct core *core; + struct pa_sink *sink; + struct pa_iochannel *io; + struct pa_core *core; void *mainloop_source; struct pa_mainloop_api *mainloop; - struct memchunk memchunk; + struct pa_memchunk memchunk; }; static void do_write(struct userdata *u) { @@ -30,16 +30,16 @@ static void do_write(struct userdata *u) { u->mainloop->enable_fixed(u->mainloop, u->mainloop_source, 0); - if (!iochannel_is_writable(u->io)) + if (!pa_iochannel_is_writable(u->io)) return; if (!u->memchunk.length) - if (sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0) + if (pa_sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0) return; assert(u->memchunk.memblock && u->memchunk.length); - if ((r = iochannel_write(u->io, u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { + if ((r = pa_iochannel_write(u->io, u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { fprintf(stderr, "write() failed: %s\n", strerror(errno)); return; } @@ -48,16 +48,16 @@ static void do_write(struct userdata *u) { u->memchunk.length -= r; if (u->memchunk.length <= 0) { - memblock_unref(u->memchunk.memblock); + pa_memblock_unref(u->memchunk.memblock); u->memchunk.memblock = NULL; } } -static void notify_cb(struct sink*s) { +static void notify_cb(struct pa_sink*s) { struct userdata *u = s->userdata; assert(s && u); - if (iochannel_is_writable(u->io)) + if (pa_iochannel_is_writable(u->io)) u->mainloop->enable_fixed(u->mainloop, u->mainloop_source, 1); } @@ -67,13 +67,13 @@ static void fixed_callback(struct pa_mainloop_api *m, void *id, void *userdata) do_write(u); } -static void io_callback(struct iochannel *io, void*userdata) { +static void io_callback(struct pa_iochannel *io, void*userdata) { struct userdata *u = userdata; assert(u); do_write(u); } -int module_init(struct core *c, struct module*m) { +int module_init(struct pa_core *c, struct pa_module*m) { struct userdata *u = NULL; struct stat st; char *p; @@ -109,14 +109,14 @@ int module_init(struct core *c, struct module*m) { u->filename = strdup(p); assert(u->filename); u->core = c; - u->sink = sink_new(c, "fifo", 0, &ss); + u->sink = pa_sink_new(c, "fifo", 0, &ss); assert(u->sink); u->sink->notify = notify_cb; u->sink->userdata = u; - u->io = iochannel_new(c->mainloop, -1, fd); + u->io = pa_iochannel_new(c->mainloop, -1, fd); assert(u->io); - iochannel_set_callback(u->io, io_callback, u); + pa_iochannel_set_callback(u->io, io_callback, u); u->memchunk.memblock = NULL; u->memchunk.length = 0; @@ -137,7 +137,7 @@ fail: return -1; } -void module_done(struct core *c, struct module*m) { +void module_done(struct pa_core *c, struct pa_module*m) { struct userdata *u; assert(c && m); @@ -145,10 +145,10 @@ void module_done(struct core *c, struct module*m) { assert(u); if (u->memchunk.memblock) - memblock_unref(u->memchunk.memblock); + pa_memblock_unref(u->memchunk.memblock); - sink_free(u->sink); - iochannel_free(u->io); + pa_sink_free(u->sink); + pa_iochannel_free(u->io); u->mainloop->cancel_fixed(u->mainloop, u->mainloop_source); assert(u->filename); diff --git a/src/module-protocol-stub.c b/src/module-protocol-stub.c index 29ce6b18..1a655454 100644 --- a/src/module-protocol-stub.c +++ b/src/module-protocol-stub.c @@ -9,23 +9,23 @@ #ifdef USE_PROTOCOL_SIMPLE #include "protocol-simple.h" - #define protocol_free protocol_simple_free + #define protocol_free pa_protocol_simple_free #define IPV4_PORT 4711 #define UNIX_SOCKET_DIR "/tmp/polypaudio" #define UNIX_SOCKET "/tmp/polypaudio/simple" #else #ifdef USE_PROTOCOL_CLI #include "protocol-cli.h" - #define protocol_new protocol_cli_new - #define protocol_free protocol_cli_free + #define protocol_new pa_protocol_cli_new + #define protocol_free pa_protocol_cli_free #define IPV4_PORT 4712 #define UNIX_SOCKET_DIR "/tmp/polypaudio" #define UNIX_SOCKET "/tmp/polypaudio/cli" #else #ifdef USE_PROTOCOL_NATIVE #include "protocol-native.h" - #define protocol_new protocol_native_new - #define protocol_free protocol_native_free + #define protocol_new pa_protocol_native_new + #define protocol_free pa_protocol_native_free #define IPV4_PORT 4713 #define UNIX_SOCKET_DIR "/tmp/polypaudio" #define UNIX_SOCKET "/tmp/polypaudio/native" @@ -33,8 +33,8 @@ #ifdef USE_PROTOCOL_ESOUND #include "protocol-esound.h" #include "esound-spec.h" - #define protocol_new protocol_esound_new - #define protocol_free protocol_esound_free + #define protocol_new pa_protocol_esound_new + #define protocol_free pa_protocol_esound_free #define IPV4_PORT ESD_DEFAULT_PORT #define UNIX_SOCKET_DIR ESD_UNIX_SOCKET_DIR #define UNIX_SOCKET ESD_UNIX_SOCKET_NAME @@ -45,27 +45,27 @@ #endif #endif -int module_init(struct core *c, struct module*m) { - struct socket_server *s; +int module_init(struct pa_core *c, struct pa_module*m) { + struct pa_socket_server *s; assert(c && m); #ifdef USE_TCP_SOCKETS - if (!(s = socket_server_new_ipv4(c->mainloop, INADDR_LOOPBACK, IPV4_PORT))) + if (!(s = pa_socket_server_new_ipv4(c->mainloop, INADDR_LOOPBACK, IPV4_PORT))) return -1; #else - if (make_secure_dir(UNIX_SOCKET_DIR) < 0) { + if (pa_make_secure_dir(UNIX_SOCKET_DIR) < 0) { fprintf(stderr, "Failed to create secure socket directory.\n"); return -1; } - if (!(s = socket_server_new_unix(c->mainloop, UNIX_SOCKET))) { + if (!(s = pa_socket_server_new_unix(c->mainloop, UNIX_SOCKET))) { rmdir(UNIX_SOCKET_DIR); return -1; } #endif #ifdef USE_PROTOCOL_SIMPLE - m->userdata = protocol_simple_new(c, s, PROTOCOL_SIMPLE_PLAYBACK); + m->userdata = pa_protocol_simple_new(c, s, PA_PROTOCOL_SIMPLE_PLAYBACK); #else m->userdata = protocol_new(c, s); #endif @@ -74,7 +74,7 @@ int module_init(struct core *c, struct module*m) { return 0; } -void module_done(struct core *c, struct module*m) { +void module_done(struct pa_core *c, struct pa_module*m) { assert(c && m); protocol_free(m->userdata); diff --git a/src/module.c b/src/module.c index 883a22df..468998ba 100644 --- a/src/module.c +++ b/src/module.c @@ -8,13 +8,13 @@ #include "module.h" #include "strbuf.h" -struct module* module_load(struct core *c, const char *name, const char *argument) { - struct module *m = NULL; +struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char *argument) { + struct pa_module *m = NULL; int r; assert(c && name); - m = malloc(sizeof(struct module)); + m = malloc(sizeof(struct pa_module)); assert(m); m->name = strdup(name); @@ -37,11 +37,11 @@ struct module* module_load(struct core *c, const char *name, const char *argumen goto fail; if (!c->modules) - c->modules = idxset_new(NULL, NULL); + c->modules = pa_idxset_new(NULL, NULL); assert(c->modules); - r = idxset_put(c->modules, m, &m->index); - assert(r >= 0 && m->index != IDXSET_INVALID); + r = pa_idxset_put(c->modules, m, &m->index); + assert(r >= 0 && m->index != PA_IDXSET_INVALID); fprintf(stderr, "module: loaded %u \"%s\" with argument \"%s\".\n", m->index, m->name, m->argument); @@ -61,7 +61,7 @@ fail: return NULL; } -static void module_free(struct module *m) { +static void pa_module_free(struct pa_module *m) { assert(m && m->done && m->core); m->done(m->core, m); @@ -75,75 +75,75 @@ static void module_free(struct module *m) { } -void module_unload(struct core *c, struct module *m) { +void pa_module_unload(struct pa_core *c, struct pa_module *m) { assert(c && m); assert(c->modules); - if (!(m = idxset_remove_by_data(c->modules, m, NULL))) + if (!(m = pa_idxset_remove_by_data(c->modules, m, NULL))) return; - module_free(m); + pa_module_free(m); } -void module_unload_by_index(struct core *c, uint32_t index) { - struct module *m; - assert(c && index != IDXSET_INVALID); +void pa_module_unload_by_index(struct pa_core *c, uint32_t index) { + struct pa_module *m; + assert(c && index != PA_IDXSET_INVALID); assert(c->modules); - if (!(m = idxset_remove_by_index(c->modules, index))) + if (!(m = pa_idxset_remove_by_index(c->modules, index))) return; - module_free(m); + pa_module_free(m); } -void free_callback(void *p, void *userdata) { - struct module *m = p; +static void free_callback(void *p, void *userdata) { + struct pa_module *m = p; assert(m); - module_free(m); + pa_module_free(m); } -void module_unload_all(struct core *c) { +void pa_module_unload_all(struct pa_core *c) { assert(c); if (!c->modules) return; - idxset_free(c->modules, free_callback, NULL); + pa_idxset_free(c->modules, free_callback, NULL); c->modules = NULL; } -char *module_list_to_string(struct core *c) { - struct strbuf *s; - struct module *m; - uint32_t index = IDXSET_INVALID; +char *pa_module_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_module *m; + uint32_t index = PA_IDXSET_INVALID; assert(c); - s = strbuf_new(); + s = pa_strbuf_new(); assert(s); - strbuf_printf(s, "%u module(s) loaded.\n", idxset_ncontents(c->modules)); + pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_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); + for (m = pa_idxset_first(c->modules, &index); m; m = pa_idxset_next(c->modules, &index)) + pa_strbuf_printf(s, " index: %u, name: <%s>, argument: <%s>\n", m->index, m->name, m->argument); - return strbuf_tostring_free(s); + return pa_strbuf_tostring_free(s); } struct once_info { - struct core *core; + struct pa_core *core; uint32_t index; }; -void module_unload_once_callback(void *userdata) { +static void module_unload_once_callback(void *userdata) { struct once_info *i = userdata; assert(i); - module_unload_by_index(i->core, i->index); + pa_module_unload_by_index(i->core, i->index); free(i); } -void module_unload_request(struct core *c, struct module *m) { +void pa_module_unload_request(struct pa_core *c, struct pa_module *m) { struct once_info *i; assert(c && m); diff --git a/src/module.h b/src/module.h index cdb61347..1cc7d775 100644 --- a/src/module.h +++ b/src/module.h @@ -6,28 +6,28 @@ #include "core.h" -struct module { - struct core *core; +struct pa_module { + struct pa_core *core; char *name, *argument; uint32_t index; lt_dlhandle dl; - int (*init)(struct core *c, struct module*m); - void (*done)(struct core *c, struct module*m); + int (*init)(struct pa_core *c, struct pa_module*m); + void (*done)(struct pa_core *c, struct pa_module*m); void *userdata; }; -struct module* module_load(struct core *c, const char *name, const char*argument); -void module_unload(struct core *c, struct module *m); -void module_unload_by_index(struct core *c, uint32_t index); +struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char*argument); +void pa_module_unload(struct pa_core *c, struct pa_module *m); +void pa_module_unload_by_index(struct pa_core *c, uint32_t index); -void module_unload_all(struct core *c); +void pa_module_unload_all(struct pa_core *c); -char *module_list_to_string(struct core *c); +char *pa_module_list_to_string(struct pa_core *c); -void module_unload_request(struct core *c, struct module *m); +void pa_module_unload_request(struct pa_core *c, struct pa_module *m); #endif diff --git a/src/namereg.c b/src/namereg.c index 0af46189..9cfb7353 100644 --- a/src/namereg.c +++ b/src/namereg.c @@ -8,20 +8,20 @@ #include "namereg.h" struct namereg_entry { - enum namereg_type type; + enum pa_namereg_type type; char *name; void *data; }; -void namereg_free(struct core *c) { +void pa_namereg_free(struct pa_core *c) { assert(c); if (!c->namereg) return; - assert(hashset_ncontents(c->namereg) == 0); - hashset_free(c->namereg, NULL, NULL); + assert(pa_hashset_ncontents(c->namereg) == 0); + pa_hashset_free(c->namereg, NULL, NULL); } -const char *namereg_register(struct core *c, const char *name, enum namereg_type type, void *data, int fail) { +const char *pa_namereg_register(struct pa_core *c, const char *name, enum pa_namereg_type type, void *data, int fail) { struct namereg_entry *e; char *n = NULL; int r; @@ -29,11 +29,11 @@ const char *namereg_register(struct core *c, const char *name, enum namereg_type assert(c && name && data); if (!c->namereg) { - c->namereg = hashset_new(idxset_string_hash_func, idxset_string_compare_func); + c->namereg = pa_hashset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); assert(c->namereg); } - if ((e = hashset_get(c->namereg, name)) && fail) + if ((e = pa_hashset_get(c->namereg, name)) && fail) return NULL; if (!e) @@ -47,7 +47,7 @@ const char *namereg_register(struct core *c, const char *name, enum namereg_type for (i = 1; i <= 99; i++) { snprintf(n, l+2, "%s%u", name, i); - if (!(e = hashset_get(c->namereg, n))) + if (!(e = pa_hashset_get(c->namereg, n))) break; } @@ -64,36 +64,36 @@ const char *namereg_register(struct core *c, const char *name, enum namereg_type e->name = n; e->data = data; - r = hashset_put(c->namereg, e->name, e); + r = pa_hashset_put(c->namereg, e->name, e); assert (r >= 0); return e->name; } -void namereg_unregister(struct core *c, const char *name) { +void pa_namereg_unregister(struct pa_core *c, const char *name) { struct namereg_entry *e; int r; assert(c && name); - e = hashset_get(c->namereg, name); + e = pa_hashset_get(c->namereg, name); assert(e); - r = hashset_remove(c->namereg, name); + r = pa_hashset_remove(c->namereg, name); assert(r >= 0); free(e->name); free(e); } -void* namereg_get(struct core *c, const char *name, enum namereg_type type) { +void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type type) { struct namereg_entry *e; uint32_t index; char *x = NULL; void *d = NULL; assert(c && name); - if ((e = hashset_get(c->namereg, name))) + if ((e = pa_hashset_get(c->namereg, name))) if (e->type == e->type) return e->data; @@ -102,10 +102,10 @@ void* namereg_get(struct core *c, const char *name, enum namereg_type type) { if (!x || *x != 0) return NULL; - if (type == NAMEREG_SINK) - d = idxset_get_by_index(c->sinks, index); - else if (type == NAMEREG_SOURCE) - d = idxset_get_by_index(c->sources, index); + if (type == PA_NAMEREG_SINK) + d = pa_idxset_get_by_index(c->sinks, index); + else if (type == PA_NAMEREG_SOURCE) + d = pa_idxset_get_by_index(c->sources, index); return d; } diff --git a/src/namereg.h b/src/namereg.h index 5632143b..b53a8566 100644 --- a/src/namereg.h +++ b/src/namereg.h @@ -3,15 +3,15 @@ #include "core.h" -enum namereg_type { - NAMEREG_SINK, - NAMEREG_SOURCE +enum pa_namereg_type { + PA_NAMEREG_SINK, + PA_NAMEREG_SOURCE }; -void namereg_free(struct core *c); +void pa_namereg_free(struct pa_core *c); -const char *namereg_register(struct core *c, const char *name, enum namereg_type type, void *data, int fail); -void namereg_unregister(struct core *c, const char *name); -void* namereg_get(struct core *c, const char *name, enum namereg_type type); +const char *pa_namereg_register(struct pa_core *c, const char *name, enum pa_namereg_type type, void *data, int fail); +void pa_namereg_unregister(struct pa_core *c, const char *name); +void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type type); #endif diff --git a/src/oss-util.c b/src/oss-util.c index d3a5fecb..9c4f55ca 100644 --- a/src/oss-util.c +++ b/src/oss-util.c @@ -7,7 +7,7 @@ #include "oss-util.h" -int oss_auto_format(int fd, struct pa_sample_spec *ss) { +int pa_oss_auto_format(int fd, struct pa_sample_spec *ss) { int format, channels, speed; assert(fd >= 0 && ss); diff --git a/src/oss-util.h b/src/oss-util.h index 5fc08b0b..cf12e8e6 100644 --- a/src/oss-util.h +++ b/src/oss-util.h @@ -3,6 +3,6 @@ #include "sample.h" -int oss_auto_format(int fd, struct pa_sample_spec *ss); +int pa_oss_auto_format(int fd, struct pa_sample_spec *ss); #endif diff --git a/src/pacat.c b/src/pacat.c index ccad0189..32220aeb 100644 --- a/src/pacat.c +++ b/src/pacat.c @@ -75,9 +75,9 @@ static void stream_complete_callback(struct pa_context*c, struct pa_stream *s, v static void context_complete_callback(struct pa_context *c, int success, void *userdata) { static const struct pa_sample_spec ss = { - .format = PA_SAMPLE_S16NE, + .format = PA_SAMPLE_S16LE, .rate = 44100, - .channels = 1 + .channels = 2 }; assert(c && !stream); diff --git a/src/packet.c b/src/packet.c index 0f966d9a..304545c5 100644 --- a/src/packet.c +++ b/src/packet.c @@ -3,44 +3,44 @@ #include "packet.h" -struct packet* packet_new(size_t length) { - struct packet *p; +struct pa_packet* pa_packet_new(size_t length) { + struct pa_packet *p; assert(length); - p = malloc(sizeof(struct packet)+length); + p = malloc(sizeof(struct pa_packet)+length); assert(p); p->ref = 1; p->length = length; p->data = (uint8_t*) (p+1); - p->type = PACKET_APPENDED; + p->type = PA_PACKET_APPENDED; return p; } -struct packet* packet_new_dynamic(uint8_t* data, size_t length) { - struct packet *p; +struct pa_packet* pa_packet_new_dynamic(uint8_t* data, size_t length) { + struct pa_packet *p; assert(data && length); - p = malloc(sizeof(struct packet)); + p = malloc(sizeof(struct pa_packet)); assert(p); p->ref = 1; p->length = length; p->data = data; - p->type = PACKET_DYNAMIC; + p->type = PA_PACKET_DYNAMIC; return p; } -struct packet* packet_ref(struct packet *p) { +struct pa_packet* pa_packet_ref(struct pa_packet *p) { assert(p && p->ref >= 1); p->ref++; return p; } -void packet_unref(struct packet *p) { +void pa_packet_unref(struct pa_packet *p) { assert(p && p->ref >= 1); p->ref--; if (p->ref == 0) { - if (p->type == PACKET_DYNAMIC) + if (p->type == PA_PACKET_DYNAMIC) free(p->data); free(p); } diff --git a/src/packet.h b/src/packet.h index 7e2e0066..b6024dd0 100644 --- a/src/packet.h +++ b/src/packet.h @@ -4,17 +4,17 @@ #include #include -struct packet { - enum { PACKET_APPENDED, PACKET_DYNAMIC } type; +struct pa_packet { + enum { PA_PACKET_APPENDED, PA_PACKET_DYNAMIC } type; unsigned ref; size_t length; uint8_t *data; }; -struct packet* packet_new(size_t length); -struct packet* packet_new_dynamic(uint8_t* data, size_t length); +struct pa_packet* pa_packet_new(size_t length); +struct pa_packet* pa_packet_new_dynamic(uint8_t* data, size_t length); -struct packet* packet_ref(struct packet *p); -void packet_unref(struct packet *p); +struct pa_packet* pa_packet_ref(struct pa_packet *p); +void pa_packet_unref(struct pa_packet *p); #endif diff --git a/src/pdispatch.c b/src/pdispatch.c index 65dcd747..c2db134d 100644 --- a/src/pdispatch.c +++ b/src/pdispatch.c @@ -5,17 +5,17 @@ #include "protocol-native-spec.h" struct reply_info { - struct pdispatch *pdispatch; + struct pa_pdispatch *pdispatch; struct reply_info *next, *previous; - int (*callback)(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata); + int (*callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); void *userdata; uint32_t tag; void *mainloop_timeout; }; -struct pdispatch { +struct pa_pdispatch { struct pa_mainloop_api *mainloop; - const struct pdispatch_command *command_table; + const struct pa_pdispatch_command *command_table; unsigned n_commands; struct reply_info *replies; }; @@ -37,13 +37,13 @@ static void reply_info_free(struct reply_info *r) { free(r); } -struct pdispatch* pdispatch_new(struct pa_mainloop_api *mainloop, const struct pdispatch_command*table, unsigned entries) { - struct pdispatch *pd; +struct pa_pdispatch* pa_pdispatch_new(struct pa_mainloop_api *mainloop, const struct pa_pdispatch_command*table, unsigned entries) { + struct pa_pdispatch *pd; assert(mainloop); assert((entries && table) || (!entries && !table)); - pd = malloc(sizeof(struct pdispatch)); + pd = malloc(sizeof(struct pa_pdispatch)); assert(pd); pd->mainloop = mainloop; pd->command_table = table; @@ -52,27 +52,27 @@ struct pdispatch* pdispatch_new(struct pa_mainloop_api *mainloop, const struct p return pd; } -void pdispatch_free(struct pdispatch *pd) { +void pa_pdispatch_free(struct pa_pdispatch *pd) { assert(pd); while (pd->replies) reply_info_free(pd->replies); free(pd); } -int pdispatch_run(struct pdispatch *pd, struct packet*packet, void *userdata) { +int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *userdata) { uint32_t tag, command; assert(pd && packet); - struct tagstruct *ts = NULL; + struct pa_tagstruct *ts = NULL; assert(pd && packet && packet->data); if (packet->length <= 8) goto fail; - ts = tagstruct_new(packet->data, packet->length); + ts = pa_tagstruct_new(packet->data, packet->length); assert(ts); - if (tagstruct_getu32(ts, &command) < 0 || - tagstruct_getu32(ts, &tag) < 0) + if (pa_tagstruct_getu32(ts, &command) < 0 || + pa_tagstruct_getu32(ts, &tag) < 0) goto fail; if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) { @@ -96,7 +96,7 @@ int pdispatch_run(struct pdispatch *pd, struct packet*packet, void *userdata) { goto fail; } else if (pd->command_table && command < pd->n_commands) { - const struct pdispatch_command *c = pd->command_table+command; + const struct pa_pdispatch_command *c = pd->command_table+command; if (!c->proc) goto fail; @@ -106,13 +106,13 @@ int pdispatch_run(struct pdispatch *pd, struct packet*packet, void *userdata) { } else goto fail; - tagstruct_free(ts); + pa_tagstruct_free(ts); return 0; fail: if (ts) - tagstruct_free(ts); + pa_tagstruct_free(ts); return -1; } @@ -125,7 +125,7 @@ static void timeout_callback(struct pa_mainloop_api*m, void *id, const struct ti reply_info_free(r); } -void pdispatch_register_reply(struct pdispatch *pd, uint32_t tag, int timeout, int (*cb)(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata), void *userdata) { +void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int timeout, int (*cb)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void *userdata) { struct reply_info *r; struct timeval tv; assert(pd && cb); diff --git a/src/pdispatch.h b/src/pdispatch.h index 466da9a4..73686700 100644 --- a/src/pdispatch.h +++ b/src/pdispatch.h @@ -6,17 +6,17 @@ #include "packet.h" #include "mainloop-api.h" -struct pdispatch; +struct pa_pdispatch; -struct pdispatch_command { - int (*proc)(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata); +struct pa_pdispatch_command { + int (*proc)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); }; -struct pdispatch* pdispatch_new(struct pa_mainloop_api *m, const struct pdispatch_command*table, unsigned entries); -void pdispatch_free(struct pdispatch *pd); +struct pa_pdispatch* pa_pdispatch_new(struct pa_mainloop_api *m, const struct pa_pdispatch_command*table, unsigned entries); +void pa_pdispatch_free(struct pa_pdispatch *pd); -int pdispatch_run(struct pdispatch *pd, struct packet*p, void *userdata); +int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*p, void *userdata); -void pdispatch_register_reply(struct pdispatch *pd, uint32_t tag, int timeout, int (*cb)(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata), void *userdata); +void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int timeout, int (*cb)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void *userdata); #endif diff --git a/src/polyp.c b/src/polyp.c index 32974fc4..eb9a3c20 100644 --- a/src/polyp.c +++ b/src/polyp.c @@ -20,10 +20,10 @@ struct pa_context { char *name; struct pa_mainloop_api* mainloop; - struct socket_client *client; - struct pstream *pstream; - struct pdispatch *pdispatch; - struct dynarray *streams; + struct pa_socket_client *client; + struct pa_pstream *pstream; + struct pa_pdispatch *pdispatch; + struct pa_dynarray *streams; struct pa_stream *first_stream; uint32_t ctag; uint32_t errno; @@ -59,9 +59,9 @@ struct pa_stream { void *die_userdata; }; -static int command_request(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata); +static int command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static const struct pdispatch_command command_table[PA_COMMAND_MAX] = { +static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = { NULL }, [PA_COMMAND_REPLY] = { NULL }, [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, @@ -82,7 +82,7 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * c->client = NULL; c->pstream = NULL; c->pdispatch = NULL; - c->streams = dynarray_new(); + c->streams = pa_dynarray_new(); assert(c->streams); c->first_stream = NULL; c->errno = PA_ERROR_OK; @@ -105,13 +105,13 @@ void pa_context_free(struct pa_context *c) { pa_stream_free(c->first_stream); if (c->client) - socket_client_free(c->client); + pa_socket_client_free(c->client); if (c->pdispatch) - pdispatch_free(c->pdispatch); + pa_pdispatch_free(c->pdispatch); if (c->pstream) - pstream_free(c->pstream); + pa_pstream_free(c->pstream); if (c->streams) - dynarray_free(c->streams, NULL, NULL); + pa_dynarray_free(c->streams, NULL, NULL); free(c->name); free(c); @@ -141,7 +141,7 @@ static void context_dead(struct pa_context *c) { c->die_callback(c, c->die_userdata); } -static void pstream_die_callback(struct pstream *p, void *userdata) { +static void pstream_die_callback(struct pa_pstream *p, void *userdata) { struct pa_context *c = userdata; assert(p && c); @@ -152,11 +152,11 @@ static void pstream_die_callback(struct pstream *p, void *userdata) { context_dead(c); } -static int pstream_packet_callback(struct pstream *p, struct packet *packet, void *userdata) { +static int pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { struct pa_context *c = userdata; assert(p && packet && c); - if (pdispatch_run(c->pdispatch, packet, c) < 0) { + if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { fprintf(stderr, "polyp.c: invalid packet.\n"); return -1; } @@ -164,12 +164,12 @@ static int pstream_packet_callback(struct pstream *p, struct packet *packet, voi return 0; } -static int pstream_memblock_callback(struct pstream *p, uint32_t channel, int32_t delta, struct memchunk *chunk, void *userdata) { +static int pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata) { struct pa_context *c = userdata; struct pa_stream *s; assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - if (!(s = dynarray_get(c->streams, channel))) + if (!(s = pa_dynarray_get(c->streams, channel))) return -1; if (s->read_callback) @@ -178,11 +178,11 @@ static int pstream_memblock_callback(struct pstream *p, uint32_t channel, int32_ return 0; } -static void on_connection(struct socket_client *client, struct iochannel*io, void *userdata) { +static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { struct pa_context *c = userdata; assert(client && io && c && c->state == CONTEXT_CONNECTING); - socket_client_free(client); + pa_socket_client_free(client); c->client = NULL; if (!io) { @@ -195,13 +195,13 @@ static void on_connection(struct socket_client *client, struct iochannel*io, voi return; } - c->pstream = pstream_new(c->mainloop, io); + c->pstream = pa_pstream_new(c->mainloop, io); assert(c->pstream); - pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); + pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); + pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); + pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - c->pdispatch = pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); + c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); assert(c->pdispatch); c->state = CONTEXT_READY; @@ -214,7 +214,7 @@ int pa_context_connect(struct pa_context *c, const char *server, void (*complete assert(c && c->state == CONTEXT_UNCONNECTED); assert(!c->client); - if (!(c->client = socket_client_new_unix(c->mainloop, server ? server : DEFAULT_SERVER))) { + if (!(c->client = pa_socket_client_new_unix(c->mainloop, server ? server : DEFAULT_SERVER))) { c->errno = PA_ERROR_CONNECTIONREFUSED; return -1; } @@ -222,7 +222,7 @@ int pa_context_connect(struct pa_context *c, const char *server, void (*complete c->connect_complete_callback = complete; c->connect_complete_userdata = userdata; - socket_client_set_callback(c->client, on_connection, c); + pa_socket_client_set_callback(c->client, on_connection, c); c->state = CONTEXT_CONNECTING; return 0; @@ -249,20 +249,20 @@ void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_cont c->die_userdata = userdata; } -static int command_request(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata) { +static int command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_stream *s; struct pa_context *c = userdata; uint32_t bytes, channel; assert(pd && command == PA_COMMAND_REQUEST && t && c); - if (tagstruct_getu32(t, &channel) < 0 || - tagstruct_getu32(t, &bytes) < 0 || - !tagstruct_eof(t)) { + if (pa_tagstruct_getu32(t, &channel) < 0 || + pa_tagstruct_getu32(t, &bytes) < 0 || + !pa_tagstruct_eof(t)) { c->errno = PA_ERROR_PROTOCOL; return -1; } - if (!(s = dynarray_get(c->streams, channel))) { + if (!(s = pa_dynarray_get(c->streams, channel))) { c->errno = PA_ERROR_PROTOCOL; return -1; } @@ -277,7 +277,7 @@ static int command_request(struct pdispatch *pd, uint32_t command, uint32_t tag, return 0; } -static int create_playback_callback(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata) { +static int create_playback_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { int ret = 0; struct pa_stream *s = userdata; assert(pd && s && s->state == STREAM_CREATING); @@ -286,7 +286,7 @@ static int create_playback_callback(struct pdispatch *pd, uint32_t command, uint struct pa_context *c = s->context; assert(c); - if (command == PA_COMMAND_ERROR && tagstruct_getu32(t, &s->context->errno) < 0) { + if (command == PA_COMMAND_ERROR && pa_tagstruct_getu32(t, &s->context->errno) < 0) { s->context->errno = PA_ERROR_PROTOCOL; ret = -1; } else if (command == PA_COMMAND_TIMEOUT) { @@ -297,16 +297,16 @@ static int create_playback_callback(struct pdispatch *pd, uint32_t command, uint goto fail; } - if (tagstruct_getu32(t, &s->channel) < 0 || - tagstruct_getu32(t, &s->device_index) < 0 || - !tagstruct_eof(t)) { + if (pa_tagstruct_getu32(t, &s->channel) < 0 || + pa_tagstruct_getu32(t, &s->device_index) < 0 || + !pa_tagstruct_eof(t)) { s->context->errno = PA_ERROR_PROTOCOL; ret = -1; goto fail; } s->channel_valid = 1; - dynarray_put(s->context->streams, s->channel, s); + pa_dynarray_put(s->context->streams, s->channel, s); s->state = STREAM_READY; assert(s->create_complete_callback); @@ -331,7 +331,7 @@ int pa_stream_new( void *userdata) { struct pa_stream *s; - struct tagstruct *t; + struct pa_tagstruct *t; uint32_t tag; assert(c && name && ss && c->state == CONTEXT_READY && complete); @@ -356,21 +356,21 @@ int pa_stream_new( s->device_index = (uint32_t) -1; s->direction = dir; - t = tagstruct_new(NULL, 0); + t = pa_tagstruct_new(NULL, 0); assert(t); - tagstruct_putu32(t, dir == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); - tagstruct_putu32(t, tag = c->ctag++); - tagstruct_puts(t, name); - tagstruct_put_sample_spec(t, ss); - tagstruct_putu32(t, (uint32_t) -1); - tagstruct_putu32(t, attr ? attr->queue_length : DEFAULT_QUEUE_LENGTH); - tagstruct_putu32(t, attr ? attr->max_length : DEFAULT_MAX_LENGTH); - tagstruct_putu32(t, attr ? attr->prebuf : DEFAULT_PREBUF); - - pstream_send_tagstruct(c->pstream, t); - - pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_playback_callback, s); + pa_tagstruct_putu32(t, dir == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_put_sample_spec(t, ss); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_putu32(t, attr ? attr->queue_length : DEFAULT_QUEUE_LENGTH); + pa_tagstruct_putu32(t, attr ? attr->max_length : DEFAULT_MAX_LENGTH); + pa_tagstruct_putu32(t, attr ? attr->prebuf : DEFAULT_PREBUF); + + pa_pstream_send_tagstruct(c->pstream, t); + + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_playback_callback, s); s->next = c->first_stream; if (s->next) @@ -385,17 +385,17 @@ void pa_stream_free(struct pa_stream *s) { assert(s && s->context); if (s->channel_valid) { - struct tagstruct *t = tagstruct_new(NULL, 0); + struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); assert(t); - tagstruct_putu32(t, PA_COMMAND_DELETE_PLAYBACK_STREAM); - tagstruct_putu32(t, s->context->ctag++); - tagstruct_putu32(t, s->channel); - pstream_send_tagstruct(s->context->pstream, t); + pa_tagstruct_putu32(t, PA_COMMAND_DELETE_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); } if (s->channel_valid) - dynarray_put(s->context->streams, s->channel, NULL); + pa_dynarray_put(s->context->streams, s->channel, NULL); if (s->next) s->next->previous = s->previous; @@ -414,17 +414,17 @@ void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stre } void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { - struct memchunk chunk; + struct pa_memchunk chunk; assert(s && s->context && data && length); - chunk.memblock = memblock_new(length); + chunk.memblock = pa_memblock_new(length); assert(chunk.memblock && chunk.memblock->data); memcpy(chunk.memblock->data, data, length); chunk.index = 0; chunk.length = length; - pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); - memblock_unref(chunk.memblock); + pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); + pa_memblock_unref(chunk.memblock); /*fprintf(stderr, "Sent %u bytes\n", length);*/ diff --git a/src/protocol-cli.c b/src/protocol-cli.c index b6460fec..0cdf2db1 100644 --- a/src/protocol-cli.c +++ b/src/protocol-cli.c @@ -4,55 +4,55 @@ #include "protocol-cli.h" #include "cli.h" -struct protocol_cli { - struct core *core; - struct socket_server*server; - struct idxset *connections; +struct pa_protocol_cli { + struct pa_core *core; + struct pa_socket_server*server; + struct pa_idxset *connections; }; -static void cli_eof_cb(struct cli*c, void*userdata) { - struct protocol_cli *p = userdata; +static void cli_eof_cb(struct pa_cli*c, void*userdata) { + struct pa_protocol_cli *p = userdata; assert(p); - idxset_remove_by_data(p->connections, c, NULL); - cli_free(c); + pa_idxset_remove_by_data(p->connections, c, NULL); + pa_cli_free(c); } -static void on_connection(struct socket_server*s, struct iochannel *io, void *userdata) { - struct protocol_cli *p = userdata; - struct cli *c; +static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { + struct pa_protocol_cli *p = userdata; + struct pa_cli *c; assert(s && io && p); - c = cli_new(p->core, io); + c = pa_cli_new(p->core, io); assert(c); - cli_set_eof_callback(c, cli_eof_cb, p); + pa_cli_set_eof_callback(c, cli_eof_cb, p); - idxset_put(p->connections, c, NULL); + pa_idxset_put(p->connections, c, NULL); } -struct protocol_cli* protocol_cli_new(struct core *core, struct socket_server *server) { - struct protocol_cli* p; +struct pa_protocol_cli* pa_protocol_cli_new(struct pa_core *core, struct pa_socket_server *server) { + struct pa_protocol_cli* p; assert(core && server); - p = malloc(sizeof(struct protocol_cli)); + p = malloc(sizeof(struct pa_protocol_cli)); assert(p); p->core = core; p->server = server; - p->connections = idxset_new(NULL, NULL); + p->connections = pa_idxset_new(NULL, NULL); - socket_server_set_callback(p->server, on_connection, p); + pa_socket_server_set_callback(p->server, on_connection, p); return p; } static void free_connection(void *p, void *userdata) { assert(p); - cli_free(p); + pa_cli_free(p); } -void protocol_cli_free(struct protocol_cli *p) { +void pa_protocol_cli_free(struct pa_protocol_cli *p) { assert(p); - idxset_free(p->connections, free_connection, NULL); - socket_server_free(p->server); + pa_idxset_free(p->connections, free_connection, NULL); + pa_socket_server_free(p->server); free(p); } diff --git a/src/protocol-cli.h b/src/protocol-cli.h index 8c150ce1..fc6a7d65 100644 --- a/src/protocol-cli.h +++ b/src/protocol-cli.h @@ -4,9 +4,9 @@ #include "core.h" #include "socket-server.h" -struct protocol_cli; +struct pa_protocol_cli; -struct protocol_cli* protocol_cli_new(struct core *core, struct socket_server *server); -void protocol_cli_free(struct protocol_cli *n); +struct pa_protocol_cli* pa_protocol_cli_new(struct pa_core *core, struct pa_socket_server *server); +void pa_protocol_cli_free(struct pa_protocol_cli *n); #endif diff --git a/src/protocol-esound.c b/src/protocol-esound.c index 12d6f38c..8198e72f 100644 --- a/src/protocol-esound.c +++ b/src/protocol-esound.c @@ -17,9 +17,9 @@ struct connection { uint32_t index; - struct protocol_esound *protocol; - struct iochannel *io; - struct client *client; + struct pa_protocol_esound *protocol; + struct pa_iochannel *io; + struct pa_client *client; int authorized, swap_byte_order; void *read_data; size_t read_data_alloc, read_data_length; @@ -27,15 +27,15 @@ struct connection { size_t write_data_alloc, write_data_index, write_data_length; esd_proto_t request; esd_client_state_t state; - struct sink_input *sink_input; - struct memblockq *input_memblockq; + struct pa_sink_input *sink_input; + struct pa_memblockq *input_memblockq; }; -struct protocol_esound { +struct pa_protocol_esound { int public; - struct core *core; - struct socket_server *server; - struct idxset *connections; + struct pa_core *core; + struct pa_socket_server *server; + struct pa_idxset *connections; uint32_t sink_index; unsigned n_player; }; @@ -51,10 +51,10 @@ typedef struct proto_handler { #define BUFSIZE (1024) -static void sink_input_drop_cb(struct sink_input *i, size_t length); -static int sink_input_peek_cb(struct sink_input *i, struct memchunk *chunk); -static void sink_input_kill_cb(struct sink_input *i); -static uint32_t sink_input_get_latency_cb(struct sink_input *i); +static void sink_input_drop_cb(struct pa_sink_input *i, size_t length); +static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk); +static void sink_input_kill_cb(struct pa_sink_input *i); +static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i); static int esd_proto_connect(struct connection *c, const void *data, size_t length); static int esd_proto_stream_play(struct connection *c, const void *data, size_t length); @@ -104,36 +104,36 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = { static void connection_free(struct connection *c) { assert(c); - idxset_remove_by_data(c->protocol->connections, c, NULL); + pa_idxset_remove_by_data(c->protocol->connections, c, NULL); if (c->state == ESD_STREAMING_DATA) c->protocol->n_player--; - client_free(c->client); + pa_client_free(c->client); if (c->sink_input) - sink_input_free(c->sink_input); + pa_sink_input_free(c->sink_input); if (c->input_memblockq) - memblockq_free(c->input_memblockq); + pa_memblockq_free(c->input_memblockq); free(c->read_data); free(c->write_data); - iochannel_free(c->io); + pa_iochannel_free(c->io); free(c); } -static struct sink* get_output_sink(struct protocol_esound *p) { - struct sink *s; +static struct pa_sink* get_output_sink(struct pa_protocol_esound *p) { + struct pa_sink *s; assert(p); - if (!(s = idxset_get_by_index(p->core->sinks, p->sink_index))) - s = sink_get_default(p->core); + if (!(s = pa_idxset_get_by_index(p->core->sinks, p->sink_index))) + s = pa_sink_get_default(p->core); if (s->index) p->sink_index = s->index; else - p->sink_index = IDXSET_INVALID; + p->sink_index = PA_IDXSET_INVALID; return s; } @@ -183,7 +183,7 @@ static int esd_proto_connect(struct connection *c, const void *data, size_t leng static int esd_proto_stream_play(struct connection *c, const void *data, size_t length) { char name[ESD_NAME_MAX]; int format, rate; - struct sink *sink; + struct pa_sink *sink; struct pa_sample_spec ss; assert(length == (sizeof(int)*2+ESD_NAME_MAX)); @@ -203,14 +203,14 @@ static int esd_proto_stream_play(struct connection *c, const void *data, size_t strncpy(name, data + sizeof(int)*2, sizeof(name)); name[sizeof(name)-1] = 0; - client_rename(c->client, name); + pa_client_rename(c->client, name); assert(!c->input_memblockq); - c->input_memblockq = memblockq_new(MEMBLOCKQ_LENGTH, pa_sample_size(&ss), MEMBLOCKQ_PREBUF); + c->input_memblockq = pa_memblockq_new(MEMBLOCKQ_LENGTH, pa_sample_size(&ss), MEMBLOCKQ_PREBUF); assert(c->input_memblockq); assert(!c->sink_input); - c->sink_input = sink_input_new(sink, name, &ss); + c->sink_input = pa_sink_input_new(sink, name, &ss); assert(c->sink_input); c->sink_input->peek = sink_input_peek_cb; @@ -233,14 +233,14 @@ static int esd_proto_stream_record(struct connection *c, const void *data, size_ } static int esd_proto_get_latency(struct connection *c, const void *data, size_t length) { - struct sink *sink; + struct pa_sink *sink; int latency, *lag; assert(c && !data && length == 0); if (!(sink = get_output_sink(c->protocol))) latency = 0; else { - float usec = sink_get_latency(sink); + float usec = pa_sink_get_latency(sink); usec += pa_samples_usec(MEMBLOCKQ_LENGTH-BUFSIZE, &sink->sample_spec); latency = (int) ((usec*44100)/1000000); } @@ -254,7 +254,7 @@ static int esd_proto_get_latency(struct connection *c, const void *data, size_t static int esd_proto_server_info(struct connection *c, const void *data, size_t length) { int rate = 44100, format = ESD_STEREO|ESD_BITS16; int *response; - struct sink *sink; + struct pa_sink *sink; assert(c && data && length == sizeof(int)); if ((sink = get_output_sink(c->protocol))) { @@ -275,7 +275,7 @@ static int esd_proto_all_info(struct connection *c, const void *data, size_t len void *response; size_t t, k, s; struct connection *conn; - size_t index = IDXSET_INVALID; + size_t index = PA_IDXSET_INVALID; assert(c && data && length == sizeof(int)); if (esd_proto_server_info(c, data, length) < 0) @@ -286,7 +286,7 @@ static int esd_proto_all_info(struct connection *c, const void *data, size_t len response = connection_write(c, (t = s+k*(c->protocol->n_player+1))); assert(k); - for (conn = idxset_first(c->protocol->connections, &index); conn; conn = idxset_next(c->protocol->connections, &index)) { + for (conn = pa_idxset_first(c->protocol->connections, &index); conn; conn = pa_idxset_next(c->protocol->connections, &index)) { int format = ESD_BITS16 | ESD_STEREO, rate = 44100, volume = 0xFF; if (conn->state != ESD_STREAMING_DATA) @@ -347,7 +347,7 @@ static int esd_proto_stream_pan(struct connection *c, const void *data, size_t l ok = connection_write(c, sizeof(int)); assert(ok); - if ((conn = idxset_get_by_index(c->protocol->connections, index))) { + if ((conn = pa_idxset_get_by_index(c->protocol->connections, index))) { assert(conn->sink_input); conn->sink_input->volume = volume; *ok = 1; @@ -359,24 +359,24 @@ static int esd_proto_stream_pan(struct connection *c, const void *data, size_t l /*** client callbacks ***/ -static void client_kill_cb(struct client *c) { +static void client_kill_cb(struct pa_client *c) { assert(c && c->userdata); connection_free(c->userdata); } -/*** iochannel callbacks ***/ +/*** pa_iochannel callbacks ***/ static int do_read(struct connection *c) { assert(c && c->io); - if (!iochannel_is_readable(c->io)) + if (!pa_iochannel_is_readable(c->io)) return 0; if (c->state == ESD_NEXT_REQUEST) { ssize_t r; assert(c->read_data_length < sizeof(c->request)); - if ((r = iochannel_read(c->io, ((void*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { + if ((r = pa_iochannel_read(c->io, ((void*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { fprintf(stderr, "protocol-esound.c: read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } @@ -423,7 +423,7 @@ static int do_read(struct connection *c) { assert(c->read_data && c->read_data_length < handler->data_length); - if ((r = iochannel_read(c->io, c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { + if ((r = pa_iochannel_read(c->io, c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { fprintf(stderr, "protocol-esound.c: read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } @@ -439,20 +439,20 @@ static int do_read(struct connection *c) { return -1; } } else if (c->state == ESD_STREAMING_DATA) { - struct memchunk chunk; + struct pa_memchunk chunk; ssize_t r; assert(c->input_memblockq); - if (!memblockq_is_writable(c->input_memblockq, BUFSIZE)) + if (!pa_memblockq_is_writable(c->input_memblockq, BUFSIZE)) return 0; - chunk.memblock = memblock_new(BUFSIZE); + chunk.memblock = pa_memblock_new(BUFSIZE); assert(chunk.memblock && chunk.memblock->data); - if ((r = iochannel_read(c->io, chunk.memblock->data, BUFSIZE)) <= 0) { + if ((r = pa_iochannel_read(c->io, chunk.memblock->data, BUFSIZE)) <= 0) { fprintf(stderr, "protocol-esound.c: read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); - memblock_unref(chunk.memblock); + pa_memblock_unref(chunk.memblock); return -1; } @@ -460,10 +460,10 @@ static int do_read(struct connection *c) { chunk.index = 0; assert(c->input_memblockq); - memblockq_push_align(c->input_memblockq, &chunk, 0); - memblock_unref(chunk.memblock); + pa_memblockq_push_align(c->input_memblockq, &chunk, 0); + pa_memblock_unref(chunk.memblock); assert(c->sink_input); - sink_notify(c->sink_input->sink); + pa_sink_notify(c->sink_input->sink); } else assert(0); @@ -475,14 +475,14 @@ static int do_write(struct connection *c) { ssize_t r; assert(c && c->io); - if (!iochannel_is_writable(c->io)) + if (!pa_iochannel_is_writable(c->io)) return 0; if (!c->write_data_length) return 0; assert(c->write_data_index < c->write_data_length); - if ((r = iochannel_write(c->io, c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { + if ((r = pa_iochannel_write(c->io, c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { fprintf(stderr, "protocol-esound.c: write() failed: %s\n", strerror(errno)); return -1; } @@ -493,7 +493,7 @@ static int do_write(struct connection *c) { return 0; } -static void io_callback(struct iochannel*io, void *userdata) { +static void io_callback(struct pa_iochannel*io, void *userdata) { struct connection *c = userdata; assert(io && c && c->io == io); @@ -503,42 +503,42 @@ static void io_callback(struct iochannel*io, void *userdata) { /*** sink_input callbacks ***/ -static int sink_input_peek_cb(struct sink_input *i, struct memchunk *chunk) { +static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk) { struct connection*c; assert(i && i->userdata && chunk); c = i->userdata; - if (memblockq_peek(c->input_memblockq, chunk) < 0) + if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) return -1; return 0; } -static void sink_input_drop_cb(struct sink_input *i, size_t length) { +static void sink_input_drop_cb(struct pa_sink_input *i, size_t length) { struct connection*c = i->userdata; assert(i && c && length); - memblockq_drop(c->input_memblockq, length); + pa_memblockq_drop(c->input_memblockq, length); if (do_read(c) < 0) connection_free(c); } -static void sink_input_kill_cb(struct sink_input *i) { +static void sink_input_kill_cb(struct pa_sink_input *i) { assert(i && i->userdata); connection_free((struct connection *) i->userdata); } -static uint32_t sink_input_get_latency_cb(struct sink_input *i) { +static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { struct connection*c = i->userdata; assert(i && c); - return pa_samples_usec(memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); + return pa_samples_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); } /*** socket server callback ***/ -static void on_connection(struct socket_server*s, struct iochannel *io, void *userdata) { +static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { struct connection *c; char cname[256]; assert(s && io && userdata); @@ -547,11 +547,11 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us assert(c); c->protocol = userdata; c->io = io; - iochannel_set_callback(c->io, io_callback, c); + pa_iochannel_set_callback(c->io, io_callback, c); - iochannel_peer_to_string(io, cname, sizeof(cname)); + pa_iochannel_peer_to_string(io, cname, sizeof(cname)); assert(c->protocol->core); - c->client = client_new(c->protocol->core, "ESOUND", cname); + c->client = pa_client_new(c->protocol->core, "ESOUND", cname); assert(c->client); c->client->kill = client_kill_cb; c->client->userdata = c; @@ -572,39 +572,39 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c->sink_input = NULL; c->input_memblockq = NULL; - idxset_put(c->protocol->connections, c, &c->index); + pa_idxset_put(c->protocol->connections, c, &c->index); } /*** entry points ***/ -struct protocol_esound* protocol_esound_new(struct core*core, struct socket_server *server) { - struct protocol_esound *p; +struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server) { + struct pa_protocol_esound *p; assert(core && server); - p = malloc(sizeof(struct protocol_esound)); + p = malloc(sizeof(struct pa_protocol_esound)); assert(p); p->public = 1; p->server = server; p->core = core; - p->connections = idxset_new(NULL, NULL); + p->connections = pa_idxset_new(NULL, NULL); assert(p->connections); - p->sink_index = IDXSET_INVALID; + p->sink_index = PA_IDXSET_INVALID; p->n_player = 0; - socket_server_set_callback(p->server, on_connection, p); + pa_socket_server_set_callback(p->server, on_connection, p); return p; } -void protocol_esound_free(struct protocol_esound *p) { +void pa_protocol_esound_free(struct pa_protocol_esound *p) { struct connection *c; assert(p); - while ((c = idxset_first(p->connections, NULL))) + while ((c = pa_idxset_first(p->connections, NULL))) connection_free(c); - idxset_free(p->connections, NULL, NULL); - socket_server_free(p->server); + pa_idxset_free(p->connections, NULL, NULL); + pa_socket_server_free(p->server); free(p); } diff --git a/src/protocol-esound.h b/src/protocol-esound.h index 2600cfae..cd505593 100644 --- a/src/protocol-esound.h +++ b/src/protocol-esound.h @@ -4,9 +4,9 @@ #include "core.h" #include "socket-server.h" -struct protocol_esound; +struct pa_protocol_esound; -struct protocol_esound* protocol_esound_new(struct core*core, struct socket_server *server); -void protocol_esound_free(struct protocol_esound *p); +struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server); +void pa_protocol_esound_free(struct pa_protocol_esound *p); #endif diff --git a/src/protocol-native.c b/src/protocol-native.c index 425f4ba4..8e4dcae1 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -14,52 +14,52 @@ #include "pstream-util.h" struct connection; -struct protocol_native; +struct pa_protocol_native; struct record_stream { struct connection *connection; uint32_t index; - struct source_output *source_output; - struct memblockq *memblockq; + struct pa_source_output *source_output; + struct pa_memblockq *memblockq; }; struct playback_stream { struct connection *connection; uint32_t index; size_t qlength; - struct sink_input *sink_input; - struct memblockq *memblockq; + struct pa_sink_input *sink_input; + struct pa_memblockq *memblockq; size_t requested_bytes; }; struct connection { int authorized; - struct protocol_native *protocol; - struct client *client; - struct pstream *pstream; - struct pdispatch *pdispatch; - struct idxset *record_streams, *playback_streams; + struct pa_protocol_native *protocol; + struct pa_client *client; + struct pa_pstream *pstream; + struct pa_pdispatch *pdispatch; + struct pa_idxset *record_streams, *playback_streams; }; -struct protocol_native { +struct pa_protocol_native { int public; - struct core *core; - struct socket_server *server; - struct idxset *connections; + struct pa_core *core; + struct pa_socket_server *server; + struct pa_idxset *connections; }; -static int sink_input_peek_cb(struct sink_input *i, struct memchunk *chunk); -static void sink_input_drop_cb(struct sink_input *i, size_t length); -static void sink_input_kill_cb(struct sink_input *i); -static uint32_t sink_input_get_latency_cb(struct sink_input *i); +static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk); +static void sink_input_drop_cb(struct pa_sink_input *i, size_t length); +static void sink_input_kill_cb(struct pa_sink_input *i); +static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i); static void request_bytes(struct playback_stream*s); -static int command_exit(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata); -static int command_create_playback_stream(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata); -static int command_delete_playback_stream(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata); +static int command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static int command_create_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static int command_delete_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static const struct pdispatch_command command_table[PA_COMMAND_MAX] = { +static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = { NULL }, [PA_COMMAND_REPLY] = { NULL }, [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { command_create_playback_stream }, @@ -74,13 +74,13 @@ static const struct pdispatch_command command_table[PA_COMMAND_MAX] = { static void record_stream_free(struct record_stream* r) { assert(r && r->connection); - idxset_remove_by_data(r->connection->record_streams, r, NULL); - source_output_free(r->source_output); - memblockq_free(r->memblockq); + pa_idxset_remove_by_data(r->connection->record_streams, r, NULL); + pa_source_output_free(r->source_output); + pa_memblockq_free(r->memblockq); free(r); } -static struct playback_stream* playback_stream_new(struct connection *c, struct sink *sink, struct pa_sample_spec *ss, const char *name, size_t qlen, size_t maxlength, size_t prebuf) { +static struct playback_stream* playback_stream_new(struct connection *c, struct pa_sink *sink, struct pa_sample_spec *ss, const char *name, size_t qlen, size_t maxlength, size_t prebuf) { struct playback_stream *s; assert(c && sink && ss && name && qlen && maxlength && prebuf); @@ -89,7 +89,7 @@ static struct playback_stream* playback_stream_new(struct connection *c, struct s->connection = c; s->qlength = qlen; - s->sink_input = sink_input_new(sink, name, ss); + s->sink_input = pa_sink_input_new(sink, name, ss); assert(s->sink_input); s->sink_input->peek = sink_input_peek_cb; s->sink_input->drop = sink_input_drop_cb; @@ -97,21 +97,21 @@ static struct playback_stream* playback_stream_new(struct connection *c, struct s->sink_input->get_latency = sink_input_get_latency_cb; s->sink_input->userdata = s; - s->memblockq = memblockq_new(maxlength, pa_sample_size(ss), prebuf); + s->memblockq = pa_memblockq_new(maxlength, pa_sample_size(ss), prebuf); assert(s->memblockq); s->requested_bytes = 0; - idxset_put(c->playback_streams, s, &s->index); + pa_idxset_put(c->playback_streams, s, &s->index); return s; } static void playback_stream_free(struct playback_stream* p) { assert(p && p->connection); - idxset_remove_by_data(p->connection->playback_streams, p, NULL); - sink_input_free(p->sink_input); - memblockq_free(p->memblockq); + pa_idxset_remove_by_data(p->connection->playback_streams, p, NULL); + pa_sink_input_free(p->sink_input); + pa_memblockq_free(p->memblockq); free(p); } @@ -120,27 +120,27 @@ static void connection_free(struct connection *c) { struct playback_stream *p; assert(c && c->protocol); - idxset_remove_by_data(c->protocol->connections, c, NULL); - while ((r = idxset_first(c->record_streams, NULL))) + pa_idxset_remove_by_data(c->protocol->connections, c, NULL); + while ((r = pa_idxset_first(c->record_streams, NULL))) record_stream_free(r); - idxset_free(c->record_streams, NULL, NULL); + pa_idxset_free(c->record_streams, NULL, NULL); - while ((p = idxset_first(c->playback_streams, NULL))) + while ((p = pa_idxset_first(c->playback_streams, NULL))) playback_stream_free(p); - idxset_free(c->playback_streams, NULL, NULL); + pa_idxset_free(c->playback_streams, NULL, NULL); - pdispatch_free(c->pdispatch); - pstream_free(c->pstream); - client_free(c->client); + pa_pdispatch_free(c->pdispatch); + pa_pstream_free(c->pstream); + pa_client_free(c->client); free(c); } static void request_bytes(struct playback_stream *s) { - struct tagstruct *t; + struct pa_tagstruct *t; size_t l; assert(s); - if (!(l = memblockq_missing_to(s->memblockq, s->qlength))) + if (!(l = pa_memblockq_missing_to(s->memblockq, s->qlength))) return; if (l <= s->requested_bytes) @@ -149,40 +149,40 @@ static void request_bytes(struct playback_stream *s) { l -= s->requested_bytes; s->requested_bytes += l; - t = tagstruct_new(NULL, 0); + t = pa_tagstruct_new(NULL, 0); assert(t); - tagstruct_putu32(t, PA_COMMAND_REQUEST); - tagstruct_putu32(t, (uint32_t) -1); /* tag */ - tagstruct_putu32(t, s->index); - tagstruct_putu32(t, l); - pstream_send_tagstruct(s->connection->pstream, t); + pa_tagstruct_putu32(t, PA_COMMAND_REQUEST); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, s->index); + pa_tagstruct_putu32(t, l); + pa_pstream_send_tagstruct(s->connection->pstream, t); /* fprintf(stderr, "Requesting %u bytes\n", l);*/ } /*** sinkinput callbacks ***/ -static int sink_input_peek_cb(struct sink_input *i, struct memchunk *chunk) { +static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk) { struct playback_stream *s; assert(i && i->userdata && chunk); s = i->userdata; - if (memblockq_peek(s->memblockq, chunk) < 0) + if (pa_memblockq_peek(s->memblockq, chunk) < 0) return -1; return 0; } -static void sink_input_drop_cb(struct sink_input *i, size_t length) { +static void sink_input_drop_cb(struct pa_sink_input *i, size_t length) { struct playback_stream *s; assert(i && i->userdata && length); s = i->userdata; - memblockq_drop(s->memblockq, length); + pa_memblockq_drop(s->memblockq, length); request_bytes(s); } -static void sink_input_kill_cb(struct sink_input *i) { +static void sink_input_kill_cb(struct pa_sink_input *i) { struct playback_stream *s; assert(i && i->userdata); s = i->userdata; @@ -190,117 +190,117 @@ static void sink_input_kill_cb(struct sink_input *i) { playback_stream_free(s); } -static uint32_t sink_input_get_latency_cb(struct sink_input *i) { +static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { struct playback_stream *s; assert(i && i->userdata); s = i->userdata; - return pa_samples_usec(memblockq_get_length(s->memblockq), &s->sink_input->sample_spec); + return pa_samples_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec); } /*** pdispatch callbacks ***/ -static int command_create_playback_stream(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata) { +static int command_create_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; struct playback_stream *s; size_t maxlength, prebuf, qlength; uint32_t sink_index; const char *name; struct pa_sample_spec ss; - struct tagstruct *reply; - struct sink *sink; + struct pa_tagstruct *reply; + struct pa_sink *sink; assert(c && t && c->protocol && c->protocol->core); - if (tagstruct_gets(t, &name) < 0 || - tagstruct_get_sample_spec(t, &ss) < 0 || - tagstruct_getu32(t, &sink_index) < 0 || - tagstruct_getu32(t, &qlength) < 0 || - tagstruct_getu32(t, &maxlength) < 0 || - tagstruct_getu32(t, &prebuf) < 0 || - !tagstruct_eof(t)) + if (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_getu32(t, &sink_index) < 0 || + pa_tagstruct_getu32(t, &qlength) < 0 || + pa_tagstruct_getu32(t, &maxlength) < 0 || + pa_tagstruct_getu32(t, &prebuf) < 0 || + !pa_tagstruct_eof(t)) return -1; if (!c->authorized) { - pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); return 0; } if (sink_index == (uint32_t) -1) - sink = sink_get_default(c->protocol->core); + sink = pa_sink_get_default(c->protocol->core); else - sink = idxset_get_by_index(c->protocol->core->sinks, sink_index); + sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); if (!sink) { - pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); return 0; } if (!(s = playback_stream_new(c, sink, &ss, name, qlength, maxlength, prebuf))) { - pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); + pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); return 0; } - reply = tagstruct_new(NULL, 0); + reply = pa_tagstruct_new(NULL, 0); assert(reply); - tagstruct_putu32(reply, PA_COMMAND_REPLY); - tagstruct_putu32(reply, tag); - tagstruct_putu32(reply, s->index); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, s->index); assert(s->sink_input); - tagstruct_putu32(reply, s->sink_input->index); - pstream_send_tagstruct(c->pstream, reply); + pa_tagstruct_putu32(reply, s->sink_input->index); + pa_pstream_send_tagstruct(c->pstream, reply); request_bytes(s); return 0; } -static int command_delete_playback_stream(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata) { +static int command_delete_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; uint32_t channel; struct playback_stream *s; assert(c && t); - if (tagstruct_getu32(t, &channel) < 0 || - !tagstruct_eof(t)) + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) return -1; if (!c->authorized) { - pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); return 0; } - if (!(s = idxset_get_by_index(c->playback_streams, channel))) { - pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + if (!(s = pa_idxset_get_by_index(c->playback_streams, channel))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); return 0; } - pstream_send_simple_ack(c->pstream, tag); + pa_pstream_send_simple_ack(c->pstream, tag); return 0; } -static int command_exit(struct pdispatch *pd, uint32_t command, uint32_t tag, struct tagstruct *t, void *userdata) { +static int command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; assert(c && t); - if (!tagstruct_eof(t)) + if (!pa_tagstruct_eof(t)) return -1; if (!c->authorized) { - pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); return 0; } assert(c->protocol && c->protocol->core && c->protocol->core->mainloop); c->protocol->core->mainloop->quit(c->protocol->core->mainloop, 0); - pstream_send_simple_ack(c->pstream, tag); /* nonsense */ + pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */ return 0; } /*** pstream callbacks ***/ -static int packet_callback(struct pstream *p, struct packet *packet, void *userdata) { +static int packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { struct connection *c = userdata; assert(p && packet && packet->data && c); - if (pdispatch_run(c->pdispatch, packet, c) < 0) { + if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { fprintf(stderr, "protocol-native: invalid packet.\n"); return -1; } @@ -308,12 +308,12 @@ static int packet_callback(struct pstream *p, struct packet *packet, void *userd return 0; } -static int memblock_callback(struct pstream *p, uint32_t channel, int32_t delta, struct memchunk *chunk, void *userdata) { +static int memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata) { struct connection *c = userdata; struct playback_stream *stream; assert(p && chunk && userdata); - if (!(stream = idxset_get_by_index(c->playback_streams, channel))) { + if (!(stream = pa_idxset_get_by_index(c->playback_streams, channel))) { fprintf(stderr, "protocol-native: client sent block for invalid stream.\n"); return -1; } @@ -323,16 +323,16 @@ static int memblock_callback(struct pstream *p, uint32_t channel, int32_t delta, else stream->requested_bytes -= chunk->length; - memblockq_push_align(stream->memblockq, chunk, delta); + pa_memblockq_push_align(stream->memblockq, chunk, delta); assert(stream->sink_input); - sink_notify(stream->sink_input->sink); + pa_sink_notify(stream->sink_input->sink); /*fprintf(stderr, "Recieved %u bytes.\n", chunk->length);*/ return 0; } -static void die_callback(struct pstream *p, void *userdata) { +static void die_callback(struct pa_pstream *p, void *userdata) { struct connection *c = userdata; assert(p && c); connection_free(c); @@ -342,8 +342,8 @@ static void die_callback(struct pstream *p, void *userdata) { /*** socket server callbacks ***/ -static void on_connection(struct socket_server*s, struct iochannel *io, void *userdata) { - struct protocol_native *p = userdata; +static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { + struct pa_protocol_native *p = userdata; struct connection *c; assert(s && io && p); @@ -352,52 +352,52 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c->authorized = p->public; c->protocol = p; assert(p->core); - c->client = client_new(p->core, "NATIVE", "Client"); + c->client = pa_client_new(p->core, "NATIVE", "Client"); assert(c->client); - c->pstream = pstream_new(p->core->mainloop, io); + c->pstream = pa_pstream_new(p->core->mainloop, io); assert(c->pstream); - pstream_set_recieve_packet_callback(c->pstream, packet_callback, c); - pstream_set_recieve_memblock_callback(c->pstream, memblock_callback, c); - pstream_set_die_callback(c->pstream, die_callback, c); + pa_pstream_set_recieve_packet_callback(c->pstream, packet_callback, c); + pa_pstream_set_recieve_memblock_callback(c->pstream, memblock_callback, c); + pa_pstream_set_die_callback(c->pstream, die_callback, c); - c->pdispatch = pdispatch_new(p->core->mainloop, command_table, PA_COMMAND_MAX); + c->pdispatch = pa_pdispatch_new(p->core->mainloop, command_table, PA_COMMAND_MAX); assert(c->pdispatch); - c->record_streams = idxset_new(NULL, NULL); - c->playback_streams = idxset_new(NULL, NULL); + c->record_streams = pa_idxset_new(NULL, NULL); + c->playback_streams = pa_idxset_new(NULL, NULL); assert(c->record_streams && c->playback_streams); - idxset_put(p->connections, c, NULL); + pa_idxset_put(p->connections, c, NULL); } /*** module entry points ***/ -struct protocol_native* protocol_native_new(struct core *core, struct socket_server *server) { - struct protocol_native *p; +struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct pa_socket_server *server) { + struct pa_protocol_native *p; assert(core && server); - p = malloc(sizeof(struct protocol_native)); + p = malloc(sizeof(struct pa_protocol_native)); assert(p); p->public = 1; p->server = server; p->core = core; - p->connections = idxset_new(NULL, NULL); + p->connections = pa_idxset_new(NULL, NULL); assert(p->connections); - socket_server_set_callback(p->server, on_connection, p); + pa_socket_server_set_callback(p->server, on_connection, p); return p; } -void protocol_native_free(struct protocol_native *p) { +void pa_protocol_native_free(struct pa_protocol_native *p) { struct connection *c; assert(p); - while ((c = idxset_first(p->connections, NULL))) + while ((c = pa_idxset_first(p->connections, NULL))) connection_free(c); - idxset_free(p->connections, NULL, NULL); - socket_server_free(p->server); + pa_idxset_free(p->connections, NULL, NULL); + pa_socket_server_free(p->server); free(p); } diff --git a/src/protocol-native.h b/src/protocol-native.h index 88283e1c..1a260149 100644 --- a/src/protocol-native.h +++ b/src/protocol-native.h @@ -4,9 +4,9 @@ #include "core.h" #include "socket-server.h" -struct protocol_native; +struct pa_protocol_native; -struct protocol_native* protocol_native_new(struct core*core, struct socket_server *server); -void protocol_native_free(struct protocol_native *n); +struct pa_protocol_native* pa_protocol_native_new(struct pa_core*core, struct pa_socket_server *server); +void pa_protocol_native_free(struct pa_protocol_native *n); #endif diff --git a/src/protocol-simple.c b/src/protocol-simple.c index a7f3eb7e..380b1802 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -12,19 +12,19 @@ #include "sample-util.h" struct connection { - struct protocol_simple *protocol; - struct iochannel *io; - struct sink_input *sink_input; - struct source_output *source_output; - struct client *client; - struct memblockq *input_memblockq, *output_memblockq; + struct pa_protocol_simple *protocol; + struct pa_iochannel *io; + struct pa_sink_input *sink_input; + struct pa_source_output *source_output; + struct pa_client *client; + struct pa_memblockq *input_memblockq, *output_memblockq; }; -struct protocol_simple { - struct core *core; - struct socket_server*server; - struct idxset *connections; - enum protocol_simple_mode mode; +struct pa_protocol_simple { + struct pa_core *core; + struct pa_socket_server*server; + struct pa_idxset *connections; + enum pa_protocol_simple_mode mode; struct pa_sample_spec sample_spec; }; @@ -33,38 +33,38 @@ struct protocol_simple { static void connection_free(struct connection *c) { assert(c); - idxset_remove_by_data(c->protocol->connections, c, NULL); + pa_idxset_remove_by_data(c->protocol->connections, c, NULL); if (c->sink_input) - sink_input_free(c->sink_input); + pa_sink_input_free(c->sink_input); if (c->source_output) - source_output_free(c->source_output); + pa_source_output_free(c->source_output); if (c->client) - client_free(c->client); + pa_client_free(c->client); if (c->io) - iochannel_free(c->io); + pa_iochannel_free(c->io); if (c->input_memblockq) - memblockq_free(c->input_memblockq); + pa_memblockq_free(c->input_memblockq); if (c->output_memblockq) - memblockq_free(c->output_memblockq); + pa_memblockq_free(c->output_memblockq); free(c); } static int do_read(struct connection *c) { - struct memchunk chunk; + struct pa_memchunk chunk; ssize_t r; - if (!iochannel_is_readable(c->io)) + if (!pa_iochannel_is_readable(c->io)) return 0; - if (!c->sink_input || !memblockq_is_writable(c->input_memblockq, BUFSIZE)) + if (!c->sink_input || !pa_memblockq_is_writable(c->input_memblockq, BUFSIZE)) return 0; - chunk.memblock = memblock_new(BUFSIZE); + chunk.memblock = pa_memblock_new(BUFSIZE); assert(chunk.memblock); - if ((r = iochannel_read(c->io, chunk.memblock->data, BUFSIZE)) <= 0) { + if ((r = pa_iochannel_read(c->io, chunk.memblock->data, BUFSIZE)) <= 0) { fprintf(stderr, "read(): %s\n", r == 0 ? "EOF" : strerror(errno)); - memblock_unref(chunk.memblock); + pa_memblock_unref(chunk.memblock); return -1; } @@ -72,103 +72,103 @@ static int do_read(struct connection *c) { chunk.index = 0; assert(c->input_memblockq); - memblockq_push_align(c->input_memblockq, &chunk, 0); - memblock_unref(chunk.memblock); + pa_memblockq_push_align(c->input_memblockq, &chunk, 0); + pa_memblock_unref(chunk.memblock); assert(c->sink_input); - sink_notify(c->sink_input->sink); + pa_sink_notify(c->sink_input->sink); return 0; } static int do_write(struct connection *c) { - struct memchunk chunk; + struct pa_memchunk chunk; ssize_t r; - if (!iochannel_is_writable(c->io)) + if (!pa_iochannel_is_writable(c->io)) return 0; if (!c->source_output) return 0; assert(c->output_memblockq); - if (memblockq_peek(c->output_memblockq, &chunk) < 0) + if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) return 0; assert(chunk.memblock && chunk.length); - if ((r = iochannel_write(c->io, chunk.memblock->data+chunk.index, chunk.length)) < 0) { + if ((r = pa_iochannel_write(c->io, chunk.memblock->data+chunk.index, chunk.length)) < 0) { fprintf(stderr, "write(): %s\n", strerror(errno)); - memblock_unref(chunk.memblock); + pa_memblock_unref(chunk.memblock); return -1; } - memblockq_drop(c->output_memblockq, r); - memblock_unref(chunk.memblock); + pa_memblockq_drop(c->output_memblockq, r); + pa_memblock_unref(chunk.memblock); return 0; } /*** sink_input callbacks ***/ -static int sink_input_peek_cb(struct sink_input *i, struct memchunk *chunk) { +static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk) { struct connection*c; assert(i && i->userdata && chunk); c = i->userdata; - if (memblockq_peek(c->input_memblockq, chunk) < 0) + if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) return -1; return 0; } -static void sink_input_drop_cb(struct sink_input *i, size_t length) { +static void sink_input_drop_cb(struct pa_sink_input *i, size_t length) { struct connection*c = i->userdata; assert(i && c && length); - memblockq_drop(c->input_memblockq, length); + pa_memblockq_drop(c->input_memblockq, length); if (do_read(c) < 0) connection_free(c); } -static void sink_input_kill_cb(struct sink_input *i) { +static void sink_input_kill_cb(struct pa_sink_input *i) { assert(i && i->userdata); connection_free((struct connection *) i->userdata); } -static uint32_t sink_input_get_latency_cb(struct sink_input *i) { +static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { struct connection*c = i->userdata; assert(i && c); - return pa_samples_usec(memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); + return pa_samples_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); } /*** source_output callbacks ***/ -static void source_output_push_cb(struct source_output *o, const struct memchunk *chunk) { +static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk) { struct connection *c = o->userdata; assert(o && c && chunk); - memblockq_push(c->output_memblockq, chunk, 0); + pa_memblockq_push(c->output_memblockq, chunk, 0); if (do_write(c) < 0) connection_free(c); } -static void source_output_kill_cb(struct source_output *o) { +static void source_output_kill_cb(struct pa_source_output *o) { assert(o && o->userdata); connection_free((struct connection *) o->userdata); } /*** client callbacks ***/ -static void client_kill_cb(struct client *c) { +static void client_kill_cb(struct pa_client *c) { assert(c && c->userdata); connection_free((struct connection *) c->userdata); } -/*** iochannel callbacks ***/ +/*** pa_iochannel callbacks ***/ -static void io_callback(struct iochannel*io, void *userdata) { +static void io_callback(struct pa_iochannel*io, void *userdata) { struct connection *c = userdata; assert(io && c && c->io == io); @@ -178,8 +178,8 @@ static void io_callback(struct iochannel*io, void *userdata) { /*** socket_server callbacks */ -static void on_connection(struct socket_server*s, struct iochannel *io, void *userdata) { - struct protocol_simple *p = userdata; +static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { + struct pa_protocol_simple *p = userdata; struct connection *c = NULL; char cname[256]; assert(s && io && p); @@ -192,41 +192,41 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c->input_memblockq = c->output_memblockq = NULL; c->protocol = p; - iochannel_peer_to_string(io, cname, sizeof(cname)); - c->client = client_new(p->core, "SIMPLE", cname); + pa_iochannel_peer_to_string(io, cname, sizeof(cname)); + c->client = pa_client_new(p->core, "SIMPLE", cname); assert(c->client); c->client->kill = client_kill_cb; c->client->userdata = c; - if (p->mode & PROTOCOL_SIMPLE_RECORD) { - struct source *source; + if (p->mode & PA_PROTOCOL_SIMPLE_RECORD) { + struct pa_source *source; size_t l; - if (!(source = source_get_default(p->core))) { + if (!(source = pa_source_get_default(p->core))) { fprintf(stderr, "Failed to get default source.\n"); goto fail; } - c->source_output = source_output_new(source, c->client->name, &p->sample_spec); + c->source_output = pa_source_output_new(source, c->client->name, &p->sample_spec); assert(c->source_output); c->source_output->push = source_output_push_cb; c->source_output->kill = source_output_kill_cb; c->source_output->userdata = c; - l = 5*pa_bytes_per_second(&DEFAULT_SAMPLE_SPEC); /* 5s */ - c->output_memblockq = memblockq_new(l, pa_sample_size(&p->sample_spec), l/2); + l = 5*pa_bytes_per_second(&p->sample_spec); /* 5s */ + c->output_memblockq = pa_memblockq_new(l, pa_sample_size(&p->sample_spec), l/2); } - if (p->mode & PROTOCOL_SIMPLE_PLAYBACK) { - struct sink *sink; + if (p->mode & PA_PROTOCOL_SIMPLE_PLAYBACK) { + struct pa_sink *sink; size_t l; - if (!(sink = sink_get_default(p->core))) { + if (!(sink = pa_sink_get_default(p->core))) { fprintf(stderr, "Failed to get default sink.\n"); goto fail; } - c->sink_input = sink_input_new(sink, c->client->name, &p->sample_spec); + c->sink_input = pa_sink_input_new(sink, c->client->name, &p->sample_spec); assert(c->sink_input); c->sink_input->peek = sink_input_peek_cb; c->sink_input->drop = sink_input_drop_cb; @@ -234,13 +234,13 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c->sink_input->get_latency = sink_input_get_latency_cb; c->sink_input->userdata = c; - l = pa_bytes_per_second(&DEFAULT_SAMPLE_SPEC)/2; /* half a second */ - c->input_memblockq = memblockq_new(l, pa_sample_size(&p->sample_spec), l/2); + l = pa_bytes_per_second(&p->sample_spec)/2; /* half a second */ + c->input_memblockq = pa_memblockq_new(l, pa_sample_size(&p->sample_spec), l/2); } - iochannel_set_callback(c->io, io_callback, c); - idxset_put(p->connections, c, NULL); + pa_iochannel_set_callback(c->io, io_callback, c); + pa_idxset_put(p->connections, c, NULL); return; fail: @@ -248,34 +248,34 @@ fail: connection_free(c); } -struct protocol_simple* protocol_simple_new(struct core *core, struct socket_server *server, enum protocol_simple_mode mode) { - struct protocol_simple* p; - assert(core && server && mode <= PROTOCOL_SIMPLE_DUPLEX && mode > 0); +struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct pa_socket_server *server, enum pa_protocol_simple_mode mode) { + struct pa_protocol_simple* p; + assert(core && server && mode <= PA_PROTOCOL_SIMPLE_DUPLEX && mode > 0); - p = malloc(sizeof(struct protocol_simple)); + p = malloc(sizeof(struct pa_protocol_simple)); assert(p); p->core = core; p->server = server; - p->connections = idxset_new(NULL, NULL); + p->connections = pa_idxset_new(NULL, NULL); p->mode = mode; - p->sample_spec = DEFAULT_SAMPLE_SPEC; + p->sample_spec = PA_DEFAULT_SAMPLE_SPEC; - socket_server_set_callback(p->server, on_connection, p); + pa_socket_server_set_callback(p->server, on_connection, p); return p; } -void protocol_simple_free(struct protocol_simple *p) { +void pa_protocol_simple_free(struct pa_protocol_simple *p) { struct connection *c; assert(p); - while((c = idxset_first(p->connections, NULL))) + while((c = pa_idxset_first(p->connections, NULL))) connection_free(c); - idxset_free(p->connections, NULL, NULL); + pa_idxset_free(p->connections, NULL, NULL); - socket_server_free(p->server); + pa_socket_server_free(p->server); free(p); } diff --git a/src/protocol-simple.h b/src/protocol-simple.h index f6210436..15ae36a6 100644 --- a/src/protocol-simple.h +++ b/src/protocol-simple.h @@ -3,15 +3,15 @@ #include "socket-server.h" -struct protocol_simple; +struct pa_protocol_simple; -enum protocol_simple_mode { - PROTOCOL_SIMPLE_RECORD = 1, - PROTOCOL_SIMPLE_PLAYBACK = 2, - PROTOCOL_SIMPLE_DUPLEX = 3 +enum pa_protocol_simple_mode { + PA_PROTOCOL_SIMPLE_RECORD = 1, + PA_PROTOCOL_SIMPLE_PLAYBACK = 2, + PA_PROTOCOL_SIMPLE_DUPLEX = 3 }; -struct protocol_simple* protocol_simple_new(struct core *core, struct socket_server *server, enum protocol_simple_mode mode); -void protocol_simple_free(struct protocol_simple *n); +struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct pa_socket_server *server, enum pa_protocol_simple_mode mode); +void pa_protocol_simple_free(struct pa_protocol_simple *n); #endif diff --git a/src/pstream-util.c b/src/pstream-util.c index 2fab2b61..cdcde5fa 100644 --- a/src/pstream-util.c +++ b/src/pstream-util.c @@ -3,33 +3,33 @@ #include "protocol-native-spec.h" #include "pstream-util.h" -void pstream_send_tagstruct(struct pstream *p, struct tagstruct *t) { +void pa_pstream_send_tagstruct(struct pa_pstream *p, struct pa_tagstruct *t) { size_t length; uint8_t *data; - struct packet *packet; + struct pa_packet *packet; assert(p && t); - data = tagstruct_free_data(t, &length); + data = pa_tagstruct_free_data(t, &length); assert(data && length); - packet = packet_new_dynamic(data, length); + packet = pa_packet_new_dynamic(data, length); assert(packet); - pstream_send_packet(p, packet); - packet_unref(packet); + pa_pstream_send_packet(p, packet); + pa_packet_unref(packet); } -void pstream_send_error(struct pstream *p, uint32_t tag, uint32_t error) { - struct tagstruct *t = tagstruct_new(NULL, 0); +void pa_pstream_send_error(struct pa_pstream *p, uint32_t tag, uint32_t error) { + struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); assert(t); - tagstruct_putu32(t, PA_COMMAND_ERROR); - tagstruct_putu32(t, tag); - tagstruct_putu32(t, error); - pstream_send_tagstruct(p, t); + pa_tagstruct_putu32(t, PA_COMMAND_ERROR); + pa_tagstruct_putu32(t, tag); + pa_tagstruct_putu32(t, error); + pa_pstream_send_tagstruct(p, t); } -void pstream_send_simple_ack(struct pstream *p, uint32_t tag) { - struct tagstruct *t = tagstruct_new(NULL, 0); +void pa_pstream_send_simple_ack(struct pa_pstream *p, uint32_t tag) { + struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); assert(t); - tagstruct_putu32(t, PA_COMMAND_REPLY); - tagstruct_putu32(t, tag); - pstream_send_tagstruct(p, t); + pa_tagstruct_putu32(t, PA_COMMAND_REPLY); + pa_tagstruct_putu32(t, tag); + pa_pstream_send_tagstruct(p, t); } diff --git a/src/pstream-util.h b/src/pstream-util.h index 4e64a95c..43051260 100644 --- a/src/pstream-util.h +++ b/src/pstream-util.h @@ -6,9 +6,9 @@ #include "tagstruct.h" /* The tagstruct is freed!*/ -void pstream_send_tagstruct(struct pstream *p, struct tagstruct *t); +void pa_pstream_send_tagstruct(struct pa_pstream *p, struct pa_tagstruct *t); -void pstream_send_error(struct pstream *p, uint32_t tag, uint32_t error); -void pstream_send_simple_ack(struct pstream *p, uint32_t tag); +void pa_pstream_send_error(struct pa_pstream *p, uint32_t tag, uint32_t error); +void pa_pstream_send_simple_ack(struct pa_pstream *p, uint32_t tag); #endif diff --git a/src/pstream.c b/src/pstream.c index e3f59816..1739780e 100644 --- a/src/pstream.c +++ b/src/pstream.c @@ -5,70 +5,70 @@ #include "pstream.h" #include "queue.h" -enum pstream_descriptor_index { - PSTREAM_DESCRIPTOR_LENGTH, - PSTREAM_DESCRIPTOR_CHANNEL, - PSTREAM_DESCRIPTOR_DELTA, - PSTREAM_DESCRIPTOR_MAX +enum pa_pstream_descriptor_index { + PA_PSTREAM_DESCRIPTOR_LENGTH, + PA_PSTREAM_DESCRIPTOR_CHANNEL, + PA_PSTREAM_DESCRIPTOR_DELTA, + PA_PSTREAM_DESCRIPTOR_MAX }; -typedef uint32_t pstream_descriptor[PSTREAM_DESCRIPTOR_MAX]; +typedef uint32_t pa_pstream_descriptor[PA_PSTREAM_DESCRIPTOR_MAX]; -#define PSTREAM_DESCRIPTOR_SIZE (PSTREAM_DESCRIPTOR_MAX*sizeof(uint32_t)) +#define PA_PSTREAM_DESCRIPTOR_SIZE (PA_PSTREAM_DESCRIPTOR_MAX*sizeof(uint32_t)) #define FRAME_SIZE_MAX (1024*64) struct item_info { - enum { PSTREAM_ITEM_PACKET, PSTREAM_ITEM_MEMBLOCK } type; + enum { PA_PSTREAM_ITEM_PACKET, PA_PSTREAM_ITEM_MEMBLOCK } type; /* memblock info */ - struct memchunk chunk; + struct pa_memchunk chunk; uint32_t channel; int32_t delta; /* packet info */ - struct packet *packet; + struct pa_packet *packet; }; -struct pstream { +struct pa_pstream { struct pa_mainloop_api *mainloop; struct mainloop_source *mainloop_source; - struct iochannel *io; - struct queue *send_queue; + struct pa_iochannel *io; + struct pa_queue *send_queue; int dead; - void (*die_callback) (struct pstream *p, void *userdad); + void (*die_callback) (struct pa_pstream *p, void *userdad); void *die_callback_userdata; struct { struct item_info* current; - pstream_descriptor descriptor; + pa_pstream_descriptor descriptor; void *data; size_t index; } write; - void (*send_callback) (struct pstream *p, void *userdata); + void (*send_callback) (struct pa_pstream *p, void *userdata); void *send_callback_userdata; struct { - struct memblock *memblock; - struct packet *packet; - pstream_descriptor descriptor; + struct pa_memblock *memblock; + struct pa_packet *packet; + pa_pstream_descriptor descriptor; void *data; size_t index; } read; - int (*recieve_packet_callback) (struct pstream *p, struct packet *packet, void *userdata); + int (*recieve_packet_callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata); void *recieve_packet_callback_userdata; - int (*recieve_memblock_callback) (struct pstream *p, uint32_t channel, int32_t delta, struct memchunk *chunk, void *userdata); + int (*recieve_memblock_callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata); void *recieve_memblock_callback_userdata; }; -static void do_write(struct pstream *p); -static void do_read(struct pstream *p); +static void do_write(struct pa_pstream *p); +static void do_read(struct pa_pstream *p); -static void io_callback(struct iochannel*io, void *userdata) { - struct pstream *p = userdata; +static void io_callback(struct pa_iochannel*io, void *userdata) { + struct pa_pstream *p = userdata; assert(p && p->io == io); p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 0); @@ -78,7 +78,7 @@ static void io_callback(struct iochannel*io, void *userdata) { } static void fixed_callback(struct pa_mainloop_api *m, void *id, void*userdata) { - struct pstream *p = userdata; + struct pa_pstream *p = userdata; assert(p && p->mainloop_source == id && p->mainloop == m); p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 0); @@ -87,15 +87,15 @@ static void fixed_callback(struct pa_mainloop_api *m, void *id, void*userdata) { do_read(p); } -struct pstream *pstream_new(struct pa_mainloop_api *m, struct iochannel *io) { - struct pstream *p; +struct pa_pstream *pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel *io) { + struct pa_pstream *p; assert(io); - p = malloc(sizeof(struct pstream)); + p = malloc(sizeof(struct pa_pstream)); assert(p); p->io = io; - iochannel_set_callback(io, io_callback, p); + pa_iochannel_set_callback(io, io_callback, p); p->dead = 0; p->die_callback = NULL; @@ -105,7 +105,7 @@ struct pstream *pstream_new(struct pa_mainloop_api *m, struct iochannel *io) { p->mainloop_source = m->source_fixed(m, fixed_callback, p); m->enable_fixed(m, p->mainloop_source, 0); - p->send_queue = queue_new(); + p->send_queue = pa_queue_new(); assert(p->send_queue); p->write.current = NULL; @@ -131,118 +131,118 @@ static void item_free(void *item, void *p) { struct item_info *i = item; assert(i); - if (i->type == PSTREAM_ITEM_MEMBLOCK) { + if (i->type == PA_PSTREAM_ITEM_MEMBLOCK) { assert(i->chunk.memblock); - memblock_unref(i->chunk.memblock); + pa_memblock_unref(i->chunk.memblock); } else { - assert(i->type == PSTREAM_ITEM_PACKET); + assert(i->type == PA_PSTREAM_ITEM_PACKET); assert(i->packet); - packet_unref(i->packet); + pa_packet_unref(i->packet); } free(i); } -void pstream_free(struct pstream *p) { +void pa_pstream_free(struct pa_pstream *p) { assert(p); - iochannel_free(p->io); - queue_free(p->send_queue, item_free, NULL); + pa_iochannel_free(p->io); + pa_queue_free(p->send_queue, item_free, NULL); if (p->write.current) item_free(p->write.current, NULL); if (p->read.memblock) - memblock_unref(p->read.memblock); + pa_memblock_unref(p->read.memblock); if (p->read.packet) - packet_unref(p->read.packet); + pa_packet_unref(p->read.packet); p->mainloop->cancel_fixed(p->mainloop, p->mainloop_source); free(p); } -void pstream_set_send_callback(struct pstream*p, void (*callback) (struct pstream *p, void *userdata), void *userdata) { +void pa_pstream_set_send_callback(struct pa_pstream*p, void (*callback) (struct pa_pstream *p, void *userdata), void *userdata) { assert(p && callback); p->send_callback = callback; p->send_callback_userdata = userdata; } -void pstream_send_packet(struct pstream*p, struct packet *packet) { +void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet) { struct item_info *i; assert(p && packet); i = malloc(sizeof(struct item_info)); assert(i); - i->type = PSTREAM_ITEM_PACKET; - i->packet = packet_ref(packet); + i->type = PA_PSTREAM_ITEM_PACKET; + i->packet = pa_packet_ref(packet); - queue_push(p->send_queue, i); + pa_queue_push(p->send_queue, i); p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 1); } -void pstream_send_memblock(struct pstream*p, uint32_t channel, int32_t delta, struct memchunk *chunk) { +void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk) { struct item_info *i; assert(p && channel != (uint32_t) -1 && chunk); i = malloc(sizeof(struct item_info)); assert(i); - i->type = PSTREAM_ITEM_MEMBLOCK; + i->type = PA_PSTREAM_ITEM_MEMBLOCK; i->chunk = *chunk; i->channel = channel; i->delta = delta; - memblock_ref(i->chunk.memblock); + pa_memblock_ref(i->chunk.memblock); - queue_push(p->send_queue, i); + pa_queue_push(p->send_queue, i); p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 1); } -void pstream_set_recieve_packet_callback(struct pstream *p, int (*callback) (struct pstream *p, struct packet *packet, void *userdata), void *userdata) { +void pa_pstream_set_recieve_packet_callback(struct pa_pstream *p, int (*callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata), void *userdata) { assert(p && callback); p->recieve_packet_callback = callback; p->recieve_packet_callback_userdata = userdata; } -void pstream_set_recieve_memblock_callback(struct pstream *p, int (*callback) (struct pstream *p, uint32_t channel, int32_t delta, struct memchunk *chunk, void *userdata), void *userdata) { +void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, int (*callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata), void *userdata) { assert(p && callback); p->recieve_memblock_callback = callback; p->recieve_memblock_callback_userdata = userdata; } -static void prepare_next_write_item(struct pstream *p) { +static void prepare_next_write_item(struct pa_pstream *p) { assert(p); - if (!(p->write.current = queue_pop(p->send_queue))) + if (!(p->write.current = pa_queue_pop(p->send_queue))) return; p->write.index = 0; - if (p->write.current->type == PSTREAM_ITEM_PACKET) { + if (p->write.current->type == PA_PSTREAM_ITEM_PACKET) { assert(p->write.current->packet); p->write.data = p->write.current->packet->data; - p->write.descriptor[PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->packet->length); - p->write.descriptor[PSTREAM_DESCRIPTOR_CHANNEL] = htonl((uint32_t) -1); - p->write.descriptor[PSTREAM_DESCRIPTOR_DELTA] = 0; + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->packet->length); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl((uint32_t) -1); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA] = 0; } else { - assert(p->write.current->type == PSTREAM_ITEM_MEMBLOCK && p->write.current->chunk.memblock); + assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK && p->write.current->chunk.memblock); p->write.data = p->write.current->chunk.memblock->data + p->write.current->chunk.index; - p->write.descriptor[PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length); - p->write.descriptor[PSTREAM_DESCRIPTOR_CHANNEL] = htonl(p->write.current->channel); - p->write.descriptor[PSTREAM_DESCRIPTOR_DELTA] = htonl(p->write.current->delta); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl(p->write.current->channel); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA] = htonl(p->write.current->delta); } } -static void do_write(struct pstream *p) { +static void do_write(struct pa_pstream *p) { void *d; size_t l; ssize_t r; assert(p); - if (p->dead || !iochannel_is_writable(p->io)) + if (p->dead || !pa_iochannel_is_writable(p->io)) return; if (!p->write.current) @@ -253,25 +253,25 @@ static void do_write(struct pstream *p) { assert(p->write.data); - if (p->write.index < PSTREAM_DESCRIPTOR_SIZE) { + if (p->write.index < PA_PSTREAM_DESCRIPTOR_SIZE) { d = (void*) p->write.descriptor + p->write.index; - l = PSTREAM_DESCRIPTOR_SIZE - p->write.index; + l = PA_PSTREAM_DESCRIPTOR_SIZE - p->write.index; } else { - d = (void*) p->write.data + p->write.index - PSTREAM_DESCRIPTOR_SIZE; - l = ntohl(p->write.descriptor[PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PSTREAM_DESCRIPTOR_SIZE); + d = (void*) p->write.data + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE; + l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE); } - if ((r = iochannel_write(p->io, d, l)) < 0) + if ((r = pa_iochannel_write(p->io, d, l)) < 0) goto die; p->write.index += r; - if (p->write.index >= PSTREAM_DESCRIPTOR_SIZE+ntohl(p->write.descriptor[PSTREAM_DESCRIPTOR_LENGTH])) { + if (p->write.index >= PA_PSTREAM_DESCRIPTOR_SIZE+ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])) { assert(p->write.current); item_free(p->write.current, (void *) 1); p->write.current = NULL; - if (p->send_callback && queue_is_empty(p->send_queue)) + if (p->send_callback && pa_queue_is_empty(p->send_queue)) p->send_callback(p, p->send_callback_userdata); } @@ -283,68 +283,68 @@ die: p->die_callback(p, p->die_callback_userdata); } -static void do_read(struct pstream *p) { +static void do_read(struct pa_pstream *p) { void *d; size_t l; ssize_t r; assert(p); - if (p->dead || !iochannel_is_readable(p->io)) + if (p->dead || !pa_iochannel_is_readable(p->io)) return; - if (p->read.index < PSTREAM_DESCRIPTOR_SIZE) { + if (p->read.index < PA_PSTREAM_DESCRIPTOR_SIZE) { d = (void*) p->read.descriptor + p->read.index; - l = PSTREAM_DESCRIPTOR_SIZE - p->read.index; + l = PA_PSTREAM_DESCRIPTOR_SIZE - p->read.index; } else { assert(p->read.data); - d = (void*) p->read.data + p->read.index - PSTREAM_DESCRIPTOR_SIZE; - l = ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH]) - (p->read.index - PSTREAM_DESCRIPTOR_SIZE); + d = (void*) p->read.data + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE; + l = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE); } - if ((r = iochannel_read(p->io, d, l)) <= 0) + if ((r = pa_iochannel_read(p->io, d, l)) <= 0) goto die; p->read.index += r; - if (p->read.index == PSTREAM_DESCRIPTOR_SIZE) { + if (p->read.index == PA_PSTREAM_DESCRIPTOR_SIZE) { /* Reading of frame descriptor complete */ /* Frame size too large */ - if (ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH]) > FRAME_SIZE_MAX) + if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) > FRAME_SIZE_MAX) goto die; assert(!p->read.packet && !p->read.memblock); - if (ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_CHANNEL]) == (uint32_t) -1) { + if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]) == (uint32_t) -1) { /* Frame is a packet frame */ - p->read.packet = packet_new(ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH])); + p->read.packet = pa_packet_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])); assert(p->read.packet); p->read.data = p->read.packet->data; } else { /* Frame is a memblock frame */ - p->read.memblock = memblock_new(ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH])); + p->read.memblock = pa_memblock_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])); assert(p->read.memblock); p->read.data = p->read.memblock->data; } - } else if (p->read.index > PSTREAM_DESCRIPTOR_SIZE) { + } else if (p->read.index > PA_PSTREAM_DESCRIPTOR_SIZE) { /* Frame payload available */ if (p->read.memblock && p->recieve_memblock_callback) { /* Is this memblock data? Than pass it to the user */ size_t l; - l = (p->read.index - r) < PSTREAM_DESCRIPTOR_SIZE ? p->read.index - PSTREAM_DESCRIPTOR_SIZE : (size_t) r; + l = (p->read.index - r) < PA_PSTREAM_DESCRIPTOR_SIZE ? p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE : (size_t) r; if (l > 0) { - struct memchunk chunk; + struct pa_memchunk chunk; chunk.memblock = p->read.memblock; - chunk.index = p->read.index - PSTREAM_DESCRIPTOR_SIZE - l; + chunk.index = p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE - l; chunk.length = l; if (p->recieve_memblock_callback(p, - ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_CHANNEL]), - (int32_t) ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_DELTA]), + ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]), + (int32_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA]), &chunk, p->recieve_memblock_callback_userdata) < 0) goto die; @@ -352,11 +352,11 @@ static void do_read(struct pstream *p) { } /* Frame complete */ - if (p->read.index >= ntohl(p->read.descriptor[PSTREAM_DESCRIPTOR_LENGTH]) + PSTREAM_DESCRIPTOR_SIZE) { + if (p->read.index >= ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) + PA_PSTREAM_DESCRIPTOR_SIZE) { if (p->read.memblock) { assert(!p->read.packet); - memblock_unref(p->read.memblock); + pa_memblock_unref(p->read.memblock); p->read.memblock = NULL; } else { int r = 0; @@ -365,7 +365,7 @@ static void do_read(struct pstream *p) { if (p->recieve_packet_callback) r = p->recieve_packet_callback(p, p->read.packet, p->recieve_packet_callback_userdata); - packet_unref(p->read.packet); + pa_packet_unref(p->read.packet); p->read.packet = NULL; if (r < 0) @@ -385,7 +385,7 @@ die: } -void pstream_set_die_callback(struct pstream *p, void (*callback)(struct pstream *p, void *userdata), void *userdata) { +void pa_pstream_set_die_callback(struct pa_pstream *p, void (*callback)(struct pa_pstream *p, void *userdata), void *userdata) { assert(p && callback); p->die_callback = callback; p->die_callback_userdata = userdata; diff --git a/src/pstream.h b/src/pstream.h index a623156a..0f5975d2 100644 --- a/src/pstream.h +++ b/src/pstream.h @@ -9,18 +9,18 @@ #include "mainloop-api.h" #include "memchunk.h" -struct pstream; +struct pa_pstream; -struct pstream* pstream_new(struct pa_mainloop_api *m, struct iochannel *io); -void pstream_free(struct pstream*p); +struct pa_pstream* pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel *io); +void pa_pstream_free(struct pa_pstream*p); -void pstream_set_send_callback(struct pstream*p, void (*callback) (struct pstream *p, void *userdata), void *userdata); -void pstream_send_packet(struct pstream*p, struct packet *packet); -void pstream_send_memblock(struct pstream*p, uint32_t channel, int32_t delta, struct memchunk *chunk); +void pa_pstream_set_send_callback(struct pa_pstream*p, void (*callback) (struct pa_pstream *p, void *userdata), void *userdata); +void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet); +void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk); -void pstream_set_recieve_packet_callback(struct pstream *p, int (*callback) (struct pstream *p, struct packet *packet, void *userdata), void *userdata); -void pstream_set_recieve_memblock_callback(struct pstream *p, int (*callback) (struct pstream *p, uint32_t channel, int32_t delta, struct memchunk *chunk, void *userdata), void *userdata); +void pa_pstream_set_recieve_packet_callback(struct pa_pstream *p, int (*callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata), void *userdata); +void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, int (*callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata), void *userdata); -void pstream_set_die_callback(struct pstream *p, void (*callback)(struct pstream *p, void *userdata), void *userdata); +void pa_pstream_set_die_callback(struct pa_pstream *p, void (*callback)(struct pa_pstream *p, void *userdata), void *userdata); #endif diff --git a/src/queue.c b/src/queue.c index 5c2e7a67..9e775f44 100644 --- a/src/queue.c +++ b/src/queue.c @@ -8,20 +8,20 @@ struct queue_entry { void *data; }; -struct queue { +struct pa_queue { struct queue_entry *front, *back; unsigned length; }; -struct queue* queue_new(void) { - struct queue *q = malloc(sizeof(struct queue)); +struct pa_queue* pa_queue_new(void) { + struct pa_queue *q = malloc(sizeof(struct pa_queue)); assert(q); q->front = q->back = NULL; q->length = 0; return q; } -void queue_free(struct queue* q, void (*destroy)(void *p, void *userdata), void *userdata) { +void pa_queue_free(struct pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata) { struct queue_entry *e; assert(q); @@ -39,7 +39,7 @@ void queue_free(struct queue* q, void (*destroy)(void *p, void *userdata), void free(q); } -void queue_push(struct queue *q, void *p) { +void pa_queue_push(struct pa_queue *q, void *p) { struct queue_entry *e; e = malloc(sizeof(struct queue_entry)); @@ -58,7 +58,7 @@ void queue_push(struct queue *q, void *p) { q->length++; } -void* queue_pop(struct queue *q) { +void* pa_queue_pop(struct pa_queue *q) { void *p; struct queue_entry *e; assert(q); @@ -78,7 +78,7 @@ void* queue_pop(struct queue *q) { return p; } -int queue_is_empty(struct queue *q) { +int pa_queue_is_empty(struct pa_queue *q) { assert(q); return q->length == 0; } diff --git a/src/queue.h b/src/queue.h index 6b371a81..e06d69cb 100644 --- a/src/queue.h +++ b/src/queue.h @@ -1,13 +1,13 @@ #ifndef fooqueuehfoo #define fooqueuehfoo -struct queue; +struct pa_queue; -struct queue* queue_new(void); -void queue_free(struct queue* q, void (*destroy)(void *p, void *userdata), void *userdata); -void queue_push(struct queue *q, void *p); -void* queue_pop(struct queue *q); +struct pa_queue* pa_queue_new(void); +void pa_queue_free(struct pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata); +void pa_queue_push(struct pa_queue *q, void *p); +void* pa_queue_pop(struct pa_queue *q); -int queue_is_empty(struct queue *q); +int pa_queue_is_empty(struct pa_queue *q); #endif diff --git a/src/resampler.c b/src/resampler.c index c2d79174..67823e45 100644 --- a/src/resampler.c +++ b/src/resampler.c @@ -6,7 +6,7 @@ #include "resampler.h" #include "sconv.h" -struct resampler { +struct pa_resampler { struct pa_sample_spec i_ss, o_ss; float* i_buf, *o_buf; unsigned i_alloc, o_alloc; @@ -14,13 +14,13 @@ struct resampler { int channels; - convert_to_float32_func_t to_float32_func; - convert_from_float32_func_t from_float32_func; + pa_convert_to_float32_func_t to_float32_func; + pa_convert_from_float32_func_t from_float32_func; SRC_STATE *src_state; }; -struct resampler* resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b) { - struct resampler *r; +struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b) { + struct pa_resampler *r; int err; assert(a && b && pa_sample_spec_valid(a) && pa_sample_spec_valid(b)); @@ -30,7 +30,7 @@ struct resampler* resampler_new(const struct pa_sample_spec *a, const struct pa_ if (a->format == PA_SAMPLE_ALAW || a->format == PA_SAMPLE_ULAW || b->format == PA_SAMPLE_ALAW || b->format == PA_SAMPLE_ULAW) goto fail; - r = malloc(sizeof(struct resampler)); + r = malloc(sizeof(struct pa_resampler)); assert(r); r->channels = a->channels; @@ -53,8 +53,8 @@ struct resampler* resampler_new(const struct pa_sample_spec *a, const struct pa_ r->i_sz = pa_sample_size(a); r->o_sz = pa_sample_size(b); - r->to_float32_func = get_convert_to_float32_function(a->format); - r->from_float32_func = get_convert_from_float32_function(b->format); + r->to_float32_func = pa_get_convert_to_float32_function(a->format); + r->from_float32_func = pa_get_convert_from_float32_function(b->format); assert(r->to_float32_func && r->from_float32_func); @@ -67,7 +67,7 @@ fail: return NULL; } -void resampler_free(struct resampler *r) { +void pa_resampler_free(struct pa_resampler *r) { assert(r); if (r->src_state) src_delete(r->src_state); @@ -76,14 +76,14 @@ void resampler_free(struct resampler *r) { free(r); } -size_t resampler_request(struct resampler *r, size_t out_length) { +size_t pa_resampler_request(struct pa_resampler *r, size_t out_length) { assert(r && (out_length % r->o_sz) == 0); return (((out_length / r->o_sz)*r->i_ss.rate)/r->o_ss.rate) * r->i_sz; } -void resampler_run(struct resampler *r, const struct memchunk *in, struct memchunk *out) { +void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out) { unsigned i_nchannels, o_nchannels, ins, ons, eff_ins, eff_ons; float *cbuf; assert(r && in && out && in->length && in->memblock && (in->length % r->i_sz) == 0); @@ -109,7 +109,7 @@ void resampler_run(struct resampler *r, const struct memchunk *in, struct memchu eff_ons = ons; } - out->memblock = memblock_new(out->length = (ons*r->o_sz)); + out->memblock = pa_memblock_new(out->length = (ons*r->o_sz)); out->index = 0; assert(out->memblock); diff --git a/src/resampler.h b/src/resampler.h index 257ba662..1d42b365 100644 --- a/src/resampler.h +++ b/src/resampler.h @@ -5,12 +5,12 @@ #include "memblock.h" #include "memchunk.h" -struct resampler; +struct pa_resampler; -struct resampler* resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b); -void resampler_free(struct resampler *r); +struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b); +void pa_resampler_free(struct pa_resampler *r); -size_t resampler_request(struct resampler *r, size_t out_length); -void resampler_run(struct resampler *r, const struct memchunk *in, struct memchunk *out); +size_t pa_resampler_request(struct pa_resampler *r, size_t out_length); +void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out); #endif diff --git a/src/sample-util.c b/src/sample-util.c index 09511a3c..f37ac78b 100644 --- a/src/sample-util.c +++ b/src/sample-util.c @@ -4,26 +4,26 @@ #include "sample-util.h" -struct pa_sample_spec default_sample_spec = { +struct pa_sample_spec pa_default_sample_spec = { .format = PA_SAMPLE_S16NE, .rate = 44100, .channels = 2 }; -struct memblock *silence_memblock(struct memblock* b, struct pa_sample_spec *spec) { +struct pa_memblock *pa_silence_memblock(struct pa_memblock* b, const struct pa_sample_spec *spec) { assert(b && b->data && spec); - memblock_assert_exclusive(b); - silence_memory(b->data, b->length, spec); + pa_memblock_assert_exclusive(b); + pa_silence_memory(b->data, b->length, spec); return b; } -void silence_memchunk(struct memchunk *c, struct pa_sample_spec *spec) { +void pa_silence_memchunk(struct pa_memchunk *c, const struct pa_sample_spec *spec) { assert(c && c->memblock && c->memblock->data && spec && c->length); - memblock_assert_exclusive(c->memblock); - silence_memory(c->memblock->data+c->index, c->length, spec); + pa_memblock_assert_exclusive(c->memblock); + pa_silence_memory(c->memblock->data+c->index, c->length, spec); } -void silence_memory(void *p, size_t length, struct pa_sample_spec *spec) { +void pa_silence_memory(void *p, size_t length, const struct pa_sample_spec *spec) { char c = 0; assert(p && length && spec); @@ -47,7 +47,7 @@ void silence_memory(void *p, size_t length, struct pa_sample_spec *spec) { memset(p, c, length); } -size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct pa_sample_spec *spec, uint32_t volume) { +size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const struct pa_sample_spec *spec, uint32_t volume) { unsigned c, d; assert(channels && data && length && spec); assert(spec->format == PA_SAMPLE_S16NE); @@ -65,22 +65,22 @@ size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, si if (d >= channels[c].chunk.length) return d; - if (volume == VOLUME_MUTE) + if (volume == PA_VOLUME_MUTE) v = 0; else { v = *((int16_t*) (channels[c].chunk.memblock->data + channels[c].chunk.index + d)); - if (volume != VOLUME_NORM) - v = (int32_t) ((float)v*volume/VOLUME_NORM); + if (volume != PA_VOLUME_NORM) + v = (int32_t) ((float)v*volume/PA_VOLUME_NORM); } sum += v; } - if (volume == VOLUME_MUTE) + if (volume == PA_VOLUME_MUTE) sum = 0; - else if (volume != VOLUME_NORM) - sum = (int32_t) ((float) sum*volume/VOLUME_NORM); + else if (volume != PA_VOLUME_NORM) + sum = (int32_t) ((float) sum*volume/PA_VOLUME_NORM); if (sum < -0x8000) sum = -0x8000; if (sum > 0x7FFF) sum = 0x7FFF; @@ -91,18 +91,18 @@ size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, si } -void volume_memchunk(struct memchunk*c, struct pa_sample_spec *spec, uint32_t volume) { +void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, uint32_t volume) { int16_t *d; size_t n; assert(c && spec && (c->length % pa_sample_size(spec) == 0)); assert(spec->format == PA_SAMPLE_S16NE); - memblock_assert_exclusive(c->memblock); + pa_memblock_assert_exclusive(c->memblock); - if (volume == VOLUME_NORM) + if (volume == PA_VOLUME_NORM) return; - if (volume == VOLUME_MUTE) { - silence_memchunk(c, spec); + if (volume == PA_VOLUME_MUTE) { + pa_silence_memchunk(c, spec); return; } @@ -110,7 +110,7 @@ void volume_memchunk(struct memchunk*c, struct pa_sample_spec *spec, uint32_t vo int32_t t = (int32_t)(*d); t *= volume; - t /= VOLUME_NORM; + t /= PA_VOLUME_NORM; if (t < -0x8000) t = -0x8000; if (t > 0x7FFF) t = 0x7FFF; @@ -119,10 +119,10 @@ void volume_memchunk(struct memchunk*c, struct pa_sample_spec *spec, uint32_t vo } } -uint32_t volume_multiply(uint32_t a, uint32_t b) { +uint32_t pa_volume_multiply(uint32_t a, uint32_t b) { uint64_t p = a; p *= b; - p /= VOLUME_NORM; + p /= PA_VOLUME_NORM; return (uint32_t) p; } diff --git a/src/sample-util.h b/src/sample-util.h index bc51e524..6a593b9a 100644 --- a/src/sample-util.h +++ b/src/sample-util.h @@ -5,27 +5,27 @@ #include "memblock.h" #include "memchunk.h" -#define DEFAULT_SAMPLE_SPEC default_sample_spec +#define PA_DEFAULT_SAMPLE_SPEC pa_default_sample_spec -extern struct pa_sample_spec default_sample_spec; +extern struct pa_sample_spec pa_default_sample_spec; -#define VOLUME_NORM (0x100) -#define VOLUME_MUTE (0) +#define PA_VOLUME_NORM (0x100) +#define PA_VOLUME_MUTE (0) -struct memblock *silence_memblock(struct memblock* b, struct pa_sample_spec *spec); -void silence_memchunk(struct memchunk *c, struct pa_sample_spec *spec); -void silence_memory(void *p, size_t length, struct pa_sample_spec *spec); +struct pa_memblock *pa_silence_memblock(struct pa_memblock* b, const struct pa_sample_spec *spec); +void pa_silence_memchunk(struct pa_memchunk *c, const struct pa_sample_spec *spec); +void pa_silence_memory(void *p, size_t length, const struct pa_sample_spec *spec); -struct mix_info { - struct memchunk chunk; +struct pa_mix_info { + struct pa_memchunk chunk; uint32_t volume; void *userdata; }; -size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct pa_sample_spec *spec, uint32_t volume); +size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const struct pa_sample_spec *spec, uint32_t volume); -void volume_memchunk(struct memchunk*c, struct pa_sample_spec *spec, uint32_t volume); +void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, uint32_t volume); -uint32_t volume_multiply(uint32_t a, uint32_t b); +uint32_t pa_volume_multiply(uint32_t a, uint32_t b); #endif diff --git a/src/sample.c b/src/sample.c index 706880e4..20142a23 100644 --- a/src/sample.c +++ b/src/sample.c @@ -1,3 +1,4 @@ +#include #include #include "sample.h" @@ -44,7 +45,7 @@ int pa_sample_spec_valid(const struct pa_sample_spec *spec) { if (!spec->rate || !spec->channels) return 0; - if (spec->format <= 0 || spec->format >= PA_SAMPLE_MAX) + if (spec->format >= PA_SAMPLE_MAX) return 0; return 1; @@ -55,3 +56,17 @@ int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_s return (a->format == b->format) && (a->rate == b->rate) && (a->channels == b->channels); } + +void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec) { + static const char* const table[]= { + [PA_SAMPLE_U8] = "U8", + [PA_SAMPLE_ALAW] = "ALAW", + [PA_SAMPLE_ULAW] = "ULAW", + [PA_SAMPLE_S16LE] = "S16LE", + [PA_SAMPLE_S16BE] = "S16BE", + [PA_SAMPLE_FLOAT32] = "FLOAT32", + }; + + assert(pa_sample_spec_valid(spec)); + snprintf(s, l, "%s %uch %uHz", table[spec->format], spec->channels, spec->rate); +} diff --git a/src/sample.h b/src/sample.h index fcb0e6e1..4131992c 100644 --- a/src/sample.h +++ b/src/sample.h @@ -32,4 +32,6 @@ uint32_t pa_samples_usec(size_t length, const struct pa_sample_spec *spec); int pa_sample_spec_valid(const struct pa_sample_spec *spec); int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b); +void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec); + #endif diff --git a/src/sconv-s16be.c b/src/sconv-s16be.c new file mode 100644 index 00000000..728a4a05 --- /dev/null +++ b/src/sconv-s16be.c @@ -0,0 +1,9 @@ +#include "sconv-s16be.h" + +#define INT16_FROM INT16_FROM_BE +#define INT16_TO INT16_TO_BE + +#define pa_sconv_s16le_to_float32 pa_sconv_s16be_to_float32 +#define pa_sconv_s16le_from_float32 pa_sconv_s16be_from_float32 + +#include "sconv-s16le.c" diff --git a/src/sconv-s16be.h b/src/sconv-s16be.h new file mode 100644 index 00000000..257393c6 --- /dev/null +++ b/src/sconv-s16be.h @@ -0,0 +1,7 @@ +#ifndef foosconv_s16befoo +#define foosconv_s16befoo + +void pa_sconv_s16be_to_float32(unsigned n, const void *a, unsigned an, float *b); +void pa_sconv_s16be_from_float32(unsigned n, const float *a, void *b, unsigned bn); + +#endif diff --git a/src/sconv-s16le.c b/src/sconv-s16le.c new file mode 100644 index 00000000..ca984463 --- /dev/null +++ b/src/sconv-s16le.c @@ -0,0 +1,57 @@ +#include +#include + +#include "endianmacros.h" +#include "sconv.h" + +#ifndef INT16_FROM +#define INT16_FROM INT16_FROM_LE +#endif + +#ifndef INT16_TO +#define INT16_TO INT16_TO_LE +#endif + +void pa_sconv_s16le_to_float32(unsigned n, const void *a, unsigned an, float *b) { + const int16_t *ca = a; + assert(n && a && an && b); + + for (; n > 0; n--) { + unsigned i; + float sum = 0; + + for (i = 0; i < an; i++) { + int16_t s = *(ca++); + sum += ((float) INT16_FROM(s))/0x7FFF; + } + + if (sum > 1) + sum = 1; + if (sum < -1) + sum = -1; + + *(b++) = sum; + } +} + +void pa_sconv_s16le_from_float32(unsigned n, const float *a, void *b, unsigned bn) { + int16_t *cb = b; + assert(n && a && b && bn); + + for (; n > 0; n--) { + unsigned i; + int16_t s; + float v = *(a++); + + if (v > 1) + v = 1; + if (v < -1) + v = -1; + + s = (int16_t) (v * 0x7FFF); + s = INT16_TO(s); + + for (i = 0; i < bn; i++) + *(cb++) = s; + } +} diff --git a/src/sconv-s16le.h b/src/sconv-s16le.h new file mode 100644 index 00000000..cfbf81fd --- /dev/null +++ b/src/sconv-s16le.h @@ -0,0 +1,7 @@ +#ifndef foosconv_s16lefoo +#define foosconv_s16lefoo + +void pa_sconv_s16le_to_float32(unsigned n, const void *a, unsigned an, float *b); +void pa_sconv_s16le_from_float32(unsigned n, const float *a, void *b, unsigned bn); + +#endif diff --git a/src/sconv.c b/src/sconv.c index 11438b41..6dd165a4 100644 --- a/src/sconv.c +++ b/src/sconv.c @@ -1,48 +1,53 @@ +#include #include #include #include "endianmacros.h" #include "sconv.h" -static void s16le_to_float32(unsigned n, const void *a, unsigned an, float *b) { - const int16_t *ca = a; +#include "sconv-s16le.h" +#include "sconv-s16be.h" + +static void u8_to_float32(unsigned n, const void *a, unsigned an, float *b) { + unsigned i; + const uint8_t *ca = a; assert(n && a && an && b); for (; n > 0; n--) { - unsigned i; float sum = 0; - + for (i = 0; i < an; i++) { - int16_t s = *(ca++); - sum += ((float) INT16_FROM_LE(s))/0x7FFF; + uint8_t v = *(ca++); + sum += (((float) v)-127)/127; } if (sum > 1) sum = 1; if (sum < -1) sum = -1; - + *(b++) = sum; } -} +} + +static void u8_from_float32(unsigned n, const float *a, void *b, unsigned bn) { + unsigned i; + uint8_t *cb = b; -static void s16le_from_float32(unsigned n, const float *a, void *b, unsigned bn) { - int16_t *cb = b; assert(n && a && b && bn); - for (; n > 0; n--) { - unsigned i; - int16_t s; float v = *(a++); + uint8_t u; if (v > 1) v = 1; + if (v < -1) v = -1; - - s = (int16_t) (v * 0x7FFF); + u = (uint8_t) (v*127+127); + for (i = 0; i < bn; i++) - *(cb++) = INT16_TO_LE(v); + *(cb++) = u; } } @@ -76,10 +81,14 @@ static void float32_from_float32(unsigned n, const float *a, void *b, unsigned b } } -convert_to_float32_func_t get_convert_to_float32_function(enum pa_sample_format f) { +pa_convert_to_float32_func_t pa_get_convert_to_float32_function(enum pa_sample_format f) { switch(f) { + case PA_SAMPLE_U8: + return u8_to_float32; case PA_SAMPLE_S16LE: - return s16le_to_float32; + return pa_sconv_s16le_to_float32; + case PA_SAMPLE_S16BE: + return pa_sconv_s16be_to_float32; case PA_SAMPLE_FLOAT32: return float32_to_float32; default: @@ -87,10 +96,14 @@ convert_to_float32_func_t get_convert_to_float32_function(enum pa_sample_format } } -convert_from_float32_func_t get_convert_from_float32_function(enum pa_sample_format f) { +pa_convert_from_float32_func_t pa_get_convert_from_float32_function(enum pa_sample_format f) { switch(f) { + case PA_SAMPLE_U8: + return u8_from_float32; case PA_SAMPLE_S16LE: - return s16le_from_float32; + return pa_sconv_s16le_from_float32; + case PA_SAMPLE_S16BE: + return pa_sconv_s16be_from_float32; case PA_SAMPLE_FLOAT32: return float32_from_float32; default: diff --git a/src/sconv.h b/src/sconv.h index 8667d2ae..e16f2dcc 100644 --- a/src/sconv.h +++ b/src/sconv.h @@ -3,12 +3,10 @@ #include "sample.h" -typedef void (*convert_to_float32_func_t)(unsigned n, const void *a, unsigned an, float *b); -typedef void (*convert_from_float32_func_t)(unsigned n, const float *a, void *b, unsigned bn); - -convert_to_float32_func_t get_convert_to_float32_function(enum pa_sample_format f); -convert_from_float32_func_t get_convert_from_float32_function(enum pa_sample_format f); - +typedef void (*pa_convert_to_float32_func_t)(unsigned n, const void *a, unsigned an, float *b); +typedef void (*pa_convert_from_float32_func_t)(unsigned n, const float *a, void *b, unsigned bn); +pa_convert_to_float32_func_t pa_get_convert_to_float32_function(enum pa_sample_format f); +pa_convert_from_float32_func_t pa_get_convert_from_float32_function(enum pa_sample_format f); #endif diff --git a/src/sink.c b/src/sink.c index 2ecb6445..53ebb8bf 100644 --- a/src/sink.c +++ b/src/sink.c @@ -11,16 +11,17 @@ #define MAX_MIX_CHANNELS 32 -struct sink* sink_new(struct core *core, const char *name, int fail, const struct pa_sample_spec *spec) { - struct sink *s; +struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec) { + struct pa_sink *s; char *n = NULL; + char st[256]; int r; assert(core && spec); - s = malloc(sizeof(struct sink)); + s = malloc(sizeof(struct pa_sink)); assert(s); - if (!(name = namereg_register(core, name, NAMEREG_SINK, s, fail))) { + if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) { free(s); return NULL; } @@ -28,46 +29,47 @@ struct sink* sink_new(struct core *core, const char *name, int fail, const struc s->name = strdup(name); s->core = core; s->sample_spec = *spec; - s->inputs = idxset_new(NULL, NULL); + s->inputs = pa_idxset_new(NULL, NULL); if (name) { n = malloc(strlen(name)+9); sprintf(n, "%s_monitor", name); } - s->monitor_source = source_new(core, n, 0, spec); + s->monitor_source = pa_source_new(core, n, 0, spec); assert(s->monitor_source); free(n); - s->volume = VOLUME_NORM; + s->volume = PA_VOLUME_NORM; s->notify = NULL; s->get_latency = NULL; s->userdata = NULL; - r = idxset_put(core->sinks, s, &s->index); - assert(s->index != IDXSET_INVALID && r >= 0); + r = pa_idxset_put(core->sinks, s, &s->index); + assert(s->index != PA_IDXSET_INVALID && r >= 0); - fprintf(stderr, "sink: created %u \"%s\".\n", s->index, s->name); + pa_sample_snprint(st, sizeof(st), spec); + fprintf(stderr, "sink: created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); return s; } -void sink_free(struct sink *s) { - struct sink_input *i, *j = NULL; +void pa_sink_free(struct pa_sink *s) { + struct pa_sink_input *i, *j = NULL; assert(s); - namereg_unregister(s->core, s->name); + pa_namereg_unregister(s->core, s->name); - while ((i = idxset_first(s->inputs, NULL))) { + while ((i = pa_idxset_first(s->inputs, NULL))) { assert(i != j); - sink_input_kill(i); + pa_sink_input_kill(i); j = i; } - idxset_free(s->inputs, NULL, NULL); + pa_idxset_free(s->inputs, NULL, NULL); - source_free(s->monitor_source); - idxset_remove_by_data(s->core->sinks, s, NULL); + pa_source_free(s->monitor_source); + pa_idxset_remove_by_data(s->core->sinks, s, NULL); fprintf(stderr, "sink: freed %u \"%s\"\n", s->index, s->name); @@ -75,22 +77,22 @@ void sink_free(struct sink *s) { free(s); } -void sink_notify(struct sink*s) { +void pa_sink_notify(struct pa_sink*s) { assert(s); if (s->notify) s->notify(s); } -static unsigned fill_mix_info(struct sink *s, struct mix_info *info, unsigned maxinfo) { - uint32_t index = IDXSET_INVALID; - struct sink_input *i; +static unsigned fill_mix_info(struct pa_sink *s, struct pa_mix_info *info, unsigned maxinfo) { + uint32_t index = PA_IDXSET_INVALID; + struct pa_sink_input *i; unsigned n = 0; assert(s && info); - for (i = idxset_first(s->inputs, &index); maxinfo > 0 && i; i = idxset_next(s->inputs, &index)) { - if (sink_input_peek(i, &info->chunk) < 0) + for (i = pa_idxset_first(s->inputs, &index); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &index)) { + if (pa_sink_input_peek(i, &info->chunk) < 0) continue; info->volume = i->volume; @@ -106,20 +108,20 @@ static unsigned fill_mix_info(struct sink *s, struct mix_info *info, unsigned ma return n; } -static void inputs_drop(struct sink *s, struct mix_info *info, unsigned maxinfo, size_t length) { +static void inputs_drop(struct pa_sink *s, struct pa_mix_info *info, unsigned maxinfo, size_t length) { assert(s && info); for (; maxinfo > 0; maxinfo--, info++) { - struct sink_input *i = info->userdata; + struct pa_sink_input *i = info->userdata; assert(i && info->chunk.memblock); - memblock_unref(info->chunk.memblock); - sink_input_drop(i, length); + pa_memblock_unref(info->chunk.memblock); + pa_sink_input_drop(i, length); } } -int sink_render(struct sink*s, size_t length, struct memchunk *result) { - struct mix_info info[MAX_MIX_CHANNELS]; +int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result) { + struct pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; size_t l; assert(s && length && result); @@ -130,29 +132,29 @@ int sink_render(struct sink*s, size_t length, struct memchunk *result) { return -1; if (n == 1) { - uint32_t volume = VOLUME_NORM; - struct sink_info *i = info[0].userdata; + uint32_t volume = PA_VOLUME_NORM; + struct pa_sink_input *i = info[0].userdata; assert(i); *result = info[0].chunk; - memblock_ref(result->memblock); + pa_memblock_ref(result->memblock); if (result->length > length) result->length = length; l = result->length; - if (s->volume != VOLUME_NORM || info[0].volume != VOLUME_NORM) - volume = volume_multiply(s->volume, info[0].volume); + if (s->volume != PA_VOLUME_NORM || info[0].volume != PA_VOLUME_NORM) + volume = pa_volume_multiply(s->volume, info[0].volume); - if (volume != VOLUME_NORM) { - memchunk_make_writable(result); - volume_memchunk(result, &s->sample_spec, volume); + if (volume != PA_VOLUME_NORM) { + pa_memchunk_make_writable(result); + pa_volume_memchunk(result, &s->sample_spec, volume); } } else { - result->memblock = memblock_new(length); + result->memblock = pa_memblock_new(length); assert(result->memblock); - result->length = l = mix_chunks(info, n, result->memblock->data, length, &s->sample_spec, s->volume); + result->length = l = pa_mix(info, n, result->memblock->data, length, &s->sample_spec, s->volume); result->index = 0; assert(l); @@ -161,17 +163,17 @@ int sink_render(struct sink*s, size_t length, struct memchunk *result) { inputs_drop(s, info, n, l); assert(s->monitor_source); - source_post(s->monitor_source, result); + pa_source_post(s->monitor_source, result); return 0; } -int sink_render_into(struct sink*s, struct memchunk *target) { - struct mix_info info[MAX_MIX_CHANNELS]; +int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target) { + struct pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; size_t l; assert(s && target && target->length && target->memblock && target->memblock->data); - memblock_assert_exclusive(target->memblock); + pa_memblock_assert_exclusive(target->memblock); n = fill_mix_info(s, info, MAX_MIX_CHANNELS); @@ -179,8 +181,8 @@ int sink_render_into(struct sink*s, struct memchunk *target) { return -1; if (n == 1) { - uint32_t volume = VOLUME_NORM; - struct sink_info *i = info[0].userdata; + uint32_t volume = PA_VOLUME_NORM; + struct pa_sink_info *i = info[0].userdata; assert(i); l = target->length; @@ -190,25 +192,25 @@ int sink_render_into(struct sink*s, struct memchunk *target) { memcpy(target->memblock->data+target->index, info[0].chunk.memblock->data + info[0].chunk.index, l); target->length = l; - if (s->volume != VOLUME_NORM || info[0].volume != VOLUME_NORM) - volume = volume_multiply(s->volume, info[0].volume); + if (s->volume != PA_VOLUME_NORM || info[0].volume != PA_VOLUME_NORM) + volume = pa_volume_multiply(s->volume, info[0].volume); - if (volume != VOLUME_NORM) - volume_memchunk(target, &s->sample_spec, volume); + if (volume != PA_VOLUME_NORM) + pa_volume_memchunk(target, &s->sample_spec, volume); } else - target->length = l = mix_chunks(info, n, target->memblock->data+target->index, target->length, &s->sample_spec, s->volume); + target->length = l = pa_mix(info, n, target->memblock->data+target->index, target->length, &s->sample_spec, s->volume); assert(l); inputs_drop(s, info, n, l); assert(s->monitor_source); - source_post(s->monitor_source, target); + pa_source_post(s->monitor_source, target); return 0; } -void sink_render_into_full(struct sink *s, struct memchunk *target) { - struct memchunk chunk; +void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target) { + struct pa_memchunk chunk; size_t l, d; assert(s && target && target->memblock && target->length && target->memblock->data); @@ -219,7 +221,7 @@ void sink_render_into_full(struct sink *s, struct memchunk *target) { chunk.index += d; chunk.length -= d; - if (sink_render_into(s, &chunk) < 0) + if (pa_sink_render_into(s, &chunk) < 0) break; d += chunk.length; @@ -230,11 +232,11 @@ void sink_render_into_full(struct sink *s, struct memchunk *target) { chunk = *target; chunk.index += d; chunk.length -= d; - silence_memchunk(&chunk, &s->sample_spec); + pa_silence_memchunk(&chunk, &s->sample_spec); } } -uint32_t sink_get_latency(struct sink *s) { +uint32_t pa_sink_get_latency(struct pa_sink *s) { assert(s); if (!s->get_latency) @@ -243,38 +245,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; +struct pa_sink* pa_sink_get_default(struct pa_core *c) { + struct pa_sink *sink; assert(c); - if ((sink = idxset_get_by_index(c->sinks, c->default_sink_index))) + if ((sink = pa_idxset_get_by_index(c->sinks, c->default_sink_index))) return sink; - if (!(sink = idxset_first(c->sinks, &c->default_sink_index))) + if (!(sink = pa_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; +char *pa_sink_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_sink *sink, *default_sink; + uint32_t index = PA_IDXSET_INVALID; assert(c); - s = strbuf_new(); + s = pa_strbuf_new(); assert(s); - strbuf_printf(s, "%u sink(s) available.\n", idxset_ncontents(c->sinks)); + pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_ncontents(c->sinks)); - default_sink = sink_get_default(c); + default_sink = pa_sink_get_default(c); - for (sink = idxset_first(c->sinks, &index); sink; sink = idxset_next(c->sinks, &index)) { + for (sink = pa_idxset_first(c->sinks, &index); sink; sink = pa_idxset_next(c->sinks, &index)) { assert(sink->monitor_source); - strbuf_printf(s, " %c index: %u, name: <%s>, volume: <0x%04x>, 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); + pa_strbuf_printf(s, " %c index: %u, name: <%s>, volume: <0x%04x>, latency: <%u usec>, monitor_source: <%u>\n", sink == default_sink ? '*' : ' ', sink->index, sink->name, (unsigned) sink->volume, pa_sink_get_latency(sink), sink->monitor_source->index); } - return strbuf_tostring_free(s); + return pa_strbuf_tostring_free(s); } diff --git a/src/sink.h b/src/sink.h index f251c0b9..7186f531 100644 --- a/src/sink.h +++ b/src/sink.h @@ -1,7 +1,7 @@ #ifndef foosinkhfoo #define foosinkhfoo -struct sink; +struct pa_sink; #include @@ -10,37 +10,37 @@ struct sink; #include "idxset.h" #include "source.h" -struct sink { +struct pa_sink { uint32_t index; char *name; - struct core *core; + struct pa_core *core; struct pa_sample_spec sample_spec; - struct idxset *inputs; + struct pa_idxset *inputs; - struct source *monitor_source; + struct pa_source *monitor_source; uint32_t volume; - void (*notify)(struct sink*sink); - uint32_t (*get_latency)(struct sink *s); + void (*notify)(struct pa_sink*sink); + uint32_t (*get_latency)(struct pa_sink *s); void *userdata; }; -struct sink* sink_new(struct core *core, const char *name, int fail, const struct pa_sample_spec *spec); -void sink_free(struct sink* s); +struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec); +void pa_sink_free(struct pa_sink* s); -int sink_render(struct sink*s, size_t length, struct memchunk *result); -int sink_render_into(struct sink*s, struct memchunk *target); -void sink_render_into_full(struct sink *s, struct memchunk *target); +int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result); +int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target); +void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target); -uint32_t sink_get_latency(struct sink *s); +uint32_t pa_sink_get_latency(struct pa_sink *s); -void sink_notify(struct sink*s); +void pa_sink_notify(struct pa_sink*s); -char *sink_list_to_string(struct core *core); +char *pa_sink_list_to_string(struct pa_core *core); -struct sink* sink_get_default(struct core *c); +struct pa_sink* pa_sink_get_default(struct pa_core *c); diff --git a/src/sinkinput.c b/src/sinkinput.c index c9614a5f..aa6f3329 100644 --- a/src/sinkinput.c +++ b/src/sinkinput.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -8,17 +9,18 @@ #define CONVERT_BUFFER_LENGTH 4096 -struct sink_input* sink_input_new(struct sink *s, const char *name, const struct pa_sample_spec *spec) { - struct sink_input *i; - struct resampler *resampler = NULL; +struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec) { + struct pa_sink_input *i; + struct pa_resampler *resampler = NULL; int r; + char st[256]; assert(s && spec); if (!pa_sample_spec_equal(spec, &s->sample_spec)) - if (!(resampler = resampler_new(spec, &s->sample_spec))) + if (!(resampler = pa_resampler_new(spec, &s->sample_spec))) return NULL; - i = malloc(sizeof(struct sink_input)); + i = malloc(sizeof(struct pa_sink_input)); assert(i); i->name = name ? strdup(name) : NULL; i->sink = s; @@ -30,69 +32,72 @@ struct sink_input* sink_input_new(struct sink *s, const char *name, const struct i->get_latency = NULL; i->userdata = NULL; - i->volume = VOLUME_NORM; + i->volume = PA_VOLUME_NORM; i->resampled_chunk.memblock = NULL; i->resampled_chunk.index = i->resampled_chunk.length = 0; i->resampler = resampler; assert(s->core); - r = idxset_put(s->core->sink_inputs, i, &i->index); - assert(r == 0 && i->index != IDXSET_INVALID); - r = idxset_put(s->inputs, i, NULL); + r = pa_idxset_put(s->core->sink_inputs, i, &i->index); + assert(r == 0 && i->index != PA_IDXSET_INVALID); + r = pa_idxset_put(s->inputs, i, NULL); assert(r == 0); + pa_sample_snprint(st, sizeof(st), spec); + fprintf(stderr, "sink-input: created %u \"%s\" on %u with sample spec \"%s\"\n", i->index, i->name, s->index, st); + return i; } -void sink_input_free(struct sink_input* i) { +void pa_sink_input_free(struct pa_sink_input* i) { assert(i); assert(i->sink && i->sink->core); - idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); - idxset_remove_by_data(i->sink->inputs, i, NULL); + pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); + pa_idxset_remove_by_data(i->sink->inputs, i, NULL); if (i->resampled_chunk.memblock) - memblock_unref(i->resampled_chunk.memblock); + pa_memblock_unref(i->resampled_chunk.memblock); if (i->resampler) - resampler_free(i->resampler); + pa_resampler_free(i->resampler); free(i->name); free(i); } -void sink_input_kill(struct sink_input*i) { +void pa_sink_input_kill(struct pa_sink_input*i) { assert(i); if (i->kill) i->kill(i); } -char *sink_input_list_to_string(struct core *c) { - struct strbuf *s; - struct sink_input *i; - uint32_t index = IDXSET_INVALID; +char *pa_sink_input_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_sink_input *i; + uint32_t index = PA_IDXSET_INVALID; assert(c); - s = strbuf_new(); + s = pa_strbuf_new(); assert(s); - strbuf_printf(s, "%u sink input(s) available.\n", idxset_ncontents(c->sink_inputs)); + pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_ncontents(c->sink_inputs)); - for (i = idxset_first(c->sink_inputs, &index); i; i = idxset_next(c->sink_inputs, &index)) { + for (i = pa_idxset_first(c->sink_inputs, &index); i; i = pa_idxset_next(c->sink_inputs, &index)) { assert(i->sink); - strbuf_printf(s, " index: %u, name: <%s>, sink: <%u>; volume: <0x%04x>, latency: <%u usec>\n", + pa_strbuf_printf(s, " index: %u, name: <%s>, sink: <%u>; volume: <0x%04x>, latency: <%u usec>\n", i->index, i->name, i->sink->index, (unsigned) i->volume, - sink_input_get_latency(i)); + pa_sink_input_get_latency(i)); } - return strbuf_tostring_free(s); + return pa_strbuf_tostring_free(s); } -uint32_t sink_input_get_latency(struct sink_input *i) { +uint32_t pa_sink_input_get_latency(struct pa_sink_input *i) { uint32_t l = 0; assert(i); @@ -100,43 +105,43 @@ uint32_t sink_input_get_latency(struct sink_input *i) { l += i->get_latency(i); assert(i->sink); - l += sink_get_latency(i->sink); + l += pa_sink_get_latency(i->sink); return l; } -int sink_input_peek(struct sink_input *i, struct memchunk *chunk) { +int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { assert(i && chunk && i->peek && i->drop); if (!i->resampler) return i->peek(i, chunk); if (!i->resampled_chunk.memblock) { - struct memchunk tchunk; + struct pa_memchunk tchunk; size_t l; int ret; if ((ret = i->peek(i, &tchunk)) < 0) return ret; - l = resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); + l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); if (tchunk.length > l) tchunk.length = l; i->drop(i, tchunk.length); - resampler_run(i->resampler, &tchunk, &i->resampled_chunk); - memblock_unref(tchunk.memblock); + pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk); + pa_memblock_unref(tchunk.memblock); } assert(i->resampled_chunk.memblock && i->resampled_chunk.length); *chunk = i->resampled_chunk; - memblock_ref(i->resampled_chunk.memblock); + pa_memblock_ref(i->resampled_chunk.memblock); return 0; } -void sink_input_drop(struct sink_input *i, size_t length) { +void pa_sink_input_drop(struct pa_sink_input *i, size_t length) { assert(i && length); if (!i->resampler) { @@ -150,7 +155,7 @@ void sink_input_drop(struct sink_input *i, size_t length) { i->resampled_chunk.length -= length; if (!i->resampled_chunk.length) { - memblock_unref(i->resampled_chunk.memblock); + pa_memblock_unref(i->resampled_chunk.memblock); i->resampled_chunk.memblock = NULL; i->resampled_chunk.index = i->resampled_chunk.length = 0; } diff --git a/src/sinkinput.h b/src/sinkinput.h index 8899a9ed..b28b51ef 100644 --- a/src/sinkinput.h +++ b/src/sinkinput.h @@ -8,36 +8,36 @@ #include "memblockq.h" #include "resampler.h" -struct sink_input { +struct pa_sink_input { uint32_t index; char *name; - struct sink *sink; + struct pa_sink *sink; struct pa_sample_spec sample_spec; uint32_t volume; - int (*peek) (struct sink_input *i, struct memchunk *chunk); - void (*drop) (struct sink_input *i, size_t length); - void (*kill) (struct sink_input *i); - uint32_t (*get_latency) (struct sink_input *i); + int (*peek) (struct pa_sink_input *i, struct pa_memchunk *chunk); + void (*drop) (struct pa_sink_input *i, size_t length); + void (*kill) (struct pa_sink_input *i); + uint32_t (*get_latency) (struct pa_sink_input *i); void *userdata; - struct memchunk resampled_chunk; - struct resampler *resampler; + struct pa_memchunk resampled_chunk; + struct pa_resampler *resampler; }; -struct sink_input* sink_input_new(struct sink *s, const char *name, const struct pa_sample_spec *spec); -void sink_input_free(struct sink_input* i); +struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec); +void pa_sink_input_free(struct pa_sink_input* i); /* Code that didn't create the input stream should call this function to * request destruction of it */ -void sink_input_kill(struct sink_input *i); +void pa_sink_input_kill(struct pa_sink_input *i); -uint32_t sink_input_get_latency(struct sink_input *i); -char *sink_input_list_to_string(struct core *c); +uint32_t pa_sink_input_get_latency(struct pa_sink_input *i); +char *pa_sink_input_list_to_string(struct pa_core *c); -int sink_input_peek(struct sink_input *i, struct memchunk *chunk); -void sink_input_drop(struct sink_input *i, size_t length); +int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk); +void pa_sink_input_drop(struct pa_sink_input *i, size_t length); #endif diff --git a/src/socket-client.c b/src/socket-client.c index 95c76813..6ff11980 100644 --- a/src/socket-client.c +++ b/src/socket-client.c @@ -11,20 +11,20 @@ #include "socket-client.h" #include "util.h" -struct socket_client { +struct pa_socket_client { struct pa_mainloop_api *mainloop; int fd; void *io_source, *fixed_source; - void (*callback)(struct socket_client*c, struct iochannel *io, void *userdata); + void (*callback)(struct pa_socket_client*c, struct pa_iochannel *io, void *userdata); void *userdata; }; -static struct socket_client*socket_client_new(struct pa_mainloop_api *m) { - struct socket_client *c; +static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) { + struct pa_socket_client *c; assert(m); - c = malloc(sizeof(struct socket_client)); + c = malloc(sizeof(struct pa_socket_client)); assert(c); c->mainloop = m; c->fd = -1; @@ -34,8 +34,8 @@ static struct socket_client*socket_client_new(struct pa_mainloop_api *m) { return c; } -static void do_call(struct socket_client *c) { - struct iochannel *io; +static void do_call(struct pa_socket_client *c) { + struct pa_iochannel *io; int error, lerror; assert(c && c->callback); @@ -55,7 +55,7 @@ static void do_call(struct socket_client *c) { goto failed; } - io = iochannel_new(c->mainloop, c->fd, c->fd); + io = pa_iochannel_new(c->mainloop, c->fd, c->fd); assert(io); c->fd = -1; c->callback(c, io, c->userdata); @@ -70,7 +70,7 @@ failed: } static void connect_fixed_cb(struct pa_mainloop_api *m, void *id, void *userdata) { - struct socket_client *c = userdata; + struct pa_socket_client *c = userdata; assert(m && c && c->fixed_source == id); m->cancel_fixed(m, c->fixed_source); c->fixed_source = NULL; @@ -78,18 +78,18 @@ static void connect_fixed_cb(struct pa_mainloop_api *m, void *id, void *userdata } static void connect_io_cb(struct pa_mainloop_api*m, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { - struct socket_client *c = userdata; + struct pa_socket_client *c = userdata; assert(m && c && c->io_source == id && fd >= 0 && events == PA_MAINLOOP_API_IO_EVENT_OUTPUT); m->cancel_io(m, c->io_source); c->io_source = NULL; do_call(c); } -static int do_connect(struct socket_client *c, const struct sockaddr *sa, socklen_t len) { +static int do_connect(struct pa_socket_client *c, const struct sockaddr *sa, socklen_t len) { int r; assert(c && sa && len); - make_nonblock_fd(c->fd); + pa_make_nonblock_fd(c->fd); if ((r = connect(c->fd, sa, len)) < 0) { if (r != EINPROGRESS) { @@ -107,12 +107,12 @@ static int do_connect(struct socket_client *c, const struct sockaddr *sa, sockle return 0; } -struct socket_client* socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port) { - struct socket_client *c; +struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port) { + struct pa_socket_client *c; struct sockaddr_in sa; assert(m && address && port); - c = socket_client_new(m); + c = pa_socket_client_new(m); assert(c); if ((c->fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { @@ -120,7 +120,7 @@ struct socket_client* socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t goto fail; } - make_tcp_socket_low_delay(c->fd); + pa_make_tcp_socket_low_delay(c->fd); sa.sin_family = AF_INET; sa.sin_port = htons(port); @@ -132,16 +132,16 @@ struct socket_client* socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t return c; fail: - socket_client_free(c); + pa_socket_client_free(c); return NULL; } -struct socket_client* socket_client_new_unix(struct pa_mainloop_api *m, const char *filename) { - struct socket_client *c; +struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename) { + struct pa_socket_client *c; struct sockaddr_un sa; assert(m && filename); - c = socket_client_new(m); + c = pa_socket_client_new(m); assert(c); if ((c->fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { @@ -149,7 +149,7 @@ struct socket_client* socket_client_new_unix(struct pa_mainloop_api *m, const ch goto fail; } - make_socket_low_delay(c->fd); + pa_make_socket_low_delay(c->fd); sa.sun_family = AF_LOCAL; strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); @@ -161,11 +161,11 @@ struct socket_client* socket_client_new_unix(struct pa_mainloop_api *m, const ch return c; fail: - socket_client_free(c); + pa_socket_client_free(c); return NULL; } -void socket_client_free(struct socket_client *c) { +void pa_socket_client_free(struct pa_socket_client *c) { assert(c && c->mainloop); if (c->io_source) c->mainloop->cancel_io(c->mainloop, c->io_source); @@ -176,7 +176,7 @@ void socket_client_free(struct socket_client *c) { free(c); } -void socket_client_set_callback(struct socket_client *c, void (*on_connection)(struct socket_client *c, struct iochannel*io, void *userdata), void *userdata) { +void pa_socket_client_set_callback(struct pa_socket_client *c, void (*on_connection)(struct pa_socket_client *c, struct pa_iochannel*io, void *userdata), void *userdata) { assert(c); c->callback = on_connection; c->userdata = userdata; diff --git a/src/socket-client.h b/src/socket-client.h index 4de01e34..76126aee 100644 --- a/src/socket-client.h +++ b/src/socket-client.h @@ -5,13 +5,13 @@ #include "mainloop-api.h" #include "iochannel.h" -struct socket_client; +struct pa_socket_client; -struct socket_client* socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port); -struct socket_client* socket_client_new_unix(struct pa_mainloop_api *m, const char *filename); +struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port); +struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename); -void socket_client_free(struct socket_client *c); +void pa_socket_client_free(struct pa_socket_client *c); -void socket_client_set_callback(struct socket_client *c, void (*on_connection)(struct socket_client *c, struct iochannel*io, void *userdata), void *userdata); +void pa_socket_client_set_callback(struct pa_socket_client *c, void (*on_connection)(struct pa_socket_client *c, struct pa_iochannel*io, void *userdata), void *userdata); #endif diff --git a/src/socket-server.c b/src/socket-server.c index bd590f3c..6a7d9415 100644 --- a/src/socket-server.c +++ b/src/socket-server.c @@ -13,20 +13,21 @@ #include "socket-server.h" #include "util.h" -struct socket_server { +struct pa_socket_server { int fd; char *filename; - void (*on_connection)(struct socket_server*s, struct iochannel *io, void *userdata); + void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata); void *userdata; void *mainloop_source; struct pa_mainloop_api *mainloop; + enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX } type; }; static void callback(struct pa_mainloop_api *mainloop, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { - struct socket_server *s = userdata; - struct iochannel *io; + struct pa_socket_server *s = userdata; + struct pa_iochannel *io; int nfd; assert(s && s->mainloop == mainloop && s->mainloop_source == id && id && fd >= 0 && fd == s->fd && events == PA_MAINLOOP_API_IO_EVENT_INPUT); @@ -41,18 +42,21 @@ static void callback(struct pa_mainloop_api *mainloop, void *id, int fd, enum pa } /* There should be a check for socket type here */ - make_tcp_socket_low_delay(fd); + if (s->type == SOCKET_SERVER_IPV4) + pa_make_tcp_socket_low_delay(fd); + else + pa_make_socket_low_delay(fd); - io = iochannel_new(s->mainloop, nfd, nfd); + io = pa_iochannel_new(s->mainloop, nfd, nfd); assert(io); s->on_connection(s, io, s->userdata); } -struct socket_server* socket_server_new(struct pa_mainloop_api *m, int fd) { - struct socket_server *s; +struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd) { + struct pa_socket_server *s; assert(m && fd >= 0); - s = malloc(sizeof(struct socket_server)); + s = malloc(sizeof(struct pa_socket_server)); assert(s); s->fd = fd; s->filename = NULL; @@ -62,14 +66,16 @@ struct socket_server* socket_server_new(struct pa_mainloop_api *m, int fd) { s->mainloop = m; s->mainloop_source = m->source_io(m, fd, PA_MAINLOOP_API_IO_EVENT_INPUT, callback, s); assert(s->mainloop_source); + + s->type = SOCKET_SERVER_GENERIC; return s; } -struct socket_server* socket_server_new_unix(struct pa_mainloop_api *m, const char *filename) { +struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename) { int fd = -1; struct sockaddr_un sa; - struct socket_server *s; + struct pa_socket_server *s; assert(m && filename); @@ -82,7 +88,7 @@ struct socket_server* socket_server_new_unix(struct pa_mainloop_api *m, const ch strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); sa.sun_path[sizeof(sa.sun_path) - 1] = 0; - make_socket_low_delay(fd); + pa_make_socket_low_delay(fd); if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) { fprintf(stderr, "bind(): %s\n", strerror(errno)); @@ -94,12 +100,14 @@ struct socket_server* socket_server_new_unix(struct pa_mainloop_api *m, const ch goto fail; } - s = socket_server_new(m, fd); + s = pa_socket_server_new(m, fd); assert(s); s->filename = strdup(filename); assert(s->filename); + s->type = SOCKET_SERVER_UNIX; + return s; fail: @@ -109,7 +117,8 @@ fail: return NULL; } -struct socket_server* socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port) { +struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port) { + struct pa_socket_server *ss; int fd = -1; struct sockaddr_in sa; int on = 1; @@ -124,7 +133,7 @@ struct socket_server* socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) fprintf(stderr, "setsockopt(): %s\n", strerror(errno)); - make_tcp_socket_low_delay(fd); + pa_make_tcp_socket_low_delay(fd); sa.sin_family = AF_INET; sa.sin_port = htons(port); @@ -140,7 +149,10 @@ struct socket_server* socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t goto fail; } - return socket_server_new(m, fd); + if ((ss = pa_socket_server_new(m, fd))) + ss->type = SOCKET_SERVER_IPV4; + + return ss; fail: if (fd >= 0) @@ -149,7 +161,7 @@ fail: return NULL; } -void socket_server_free(struct socket_server*s) { +void pa_socket_server_free(struct pa_socket_server*s) { assert(s); close(s->fd); @@ -164,7 +176,7 @@ void socket_server_free(struct socket_server*s) { free(s); } -void socket_server_set_callback(struct socket_server*s, void (*on_connection)(struct socket_server*s, struct iochannel *io, void *userdata), void *userdata) { +void pa_socket_server_set_callback(struct pa_socket_server*s, void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata), void *userdata) { assert(s); s->on_connection = on_connection; diff --git a/src/socket-server.h b/src/socket-server.h index 80895f8d..d581fa37 100644 --- a/src/socket-server.h +++ b/src/socket-server.h @@ -5,14 +5,14 @@ #include "mainloop-api.h" #include "iochannel.h" -struct socket_server; +struct pa_socket_server; -struct socket_server* socket_server_new(struct pa_mainloop_api *m, int fd); -struct socket_server* socket_server_new_unix(struct pa_mainloop_api *m, const char *filename); -struct socket_server* socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port); +struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd); +struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename); +struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port); -void socket_server_free(struct socket_server*s); +void pa_socket_server_free(struct pa_socket_server*s); -void socket_server_set_callback(struct socket_server*s, void (*on_connection)(struct socket_server*s, struct iochannel *io, void *userdata), void *userdata); +void pa_socket_server_set_callback(struct pa_socket_server*s, void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata), void *userdata); #endif diff --git a/src/source.c b/src/source.c index f3eeb516..9a4f95a2 100644 --- a/src/source.c +++ b/src/source.c @@ -8,15 +8,16 @@ #include "strbuf.h" #include "namereg.h" -struct source* source_new(struct core *core, const char *name, int fail, const struct pa_sample_spec *spec) { - struct source *s; +struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec) { + struct pa_source *s; + char st[256]; int r; assert(core && spec); - s = malloc(sizeof(struct source)); + s = malloc(sizeof(struct pa_source)); assert(s); - if (!(name = namereg_register(core, name, NAMEREG_SOURCE, s, fail))) { + if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SOURCE, s, fail))) { free(s); return NULL; } @@ -24,33 +25,34 @@ struct source* source_new(struct core *core, const char *name, int fail, const s s->name = strdup(name); s->core = core; s->sample_spec = *spec; - s->outputs = idxset_new(NULL, NULL); + s->outputs = pa_idxset_new(NULL, NULL); s->notify = NULL; s->userdata = NULL; - r = idxset_put(core->sources, s, &s->index); - assert(s->index != IDXSET_INVALID && r >= 0); + r = pa_idxset_put(core->sources, s, &s->index); + assert(s->index != PA_IDXSET_INVALID && r >= 0); - fprintf(stderr, "source: created %u \"%s\"\n", s->index, s->name); + pa_sample_snprint(st, sizeof(st), spec); + fprintf(stderr, "source: created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); return s; } -void source_free(struct source *s) { - struct source_output *o, *j = NULL; +void pa_source_free(struct pa_source *s) { + struct pa_source_output *o, *j = NULL; assert(s); - namereg_unregister(s->core, s->name); + pa_namereg_unregister(s->core, s->name); - while ((o = idxset_first(s->outputs, NULL))) { + while ((o = pa_idxset_first(s->outputs, NULL))) { assert(o != j); - source_output_kill(o); + pa_source_output_kill(o); j = o; } - idxset_free(s->outputs, NULL, NULL); + pa_idxset_free(s->outputs, NULL, NULL); - idxset_remove_by_data(s->core->sources, s, NULL); + pa_idxset_remove_by_data(s->core->sources, s, NULL); fprintf(stderr, "source: freed %u \"%s\"\n", s->index, s->name); @@ -58,7 +60,7 @@ void source_free(struct source *s) { free(s); } -void source_notify(struct source*s) { +void pa_source_notify(struct pa_source*s) { assert(s); if (s->notify) @@ -66,50 +68,50 @@ void source_notify(struct source*s) { } static int do_post(void *p, uint32_t index, int *del, void*userdata) { - struct memchunk *chunk = userdata; - struct source_output *o = p; + struct pa_memchunk *chunk = userdata; + struct pa_source_output *o = p; assert(o && o->push && del && chunk); - source_output_push(o, chunk); + pa_source_output_push(o, chunk); return 0; } -void source_post(struct source*s, struct memchunk *chunk) { +void pa_source_post(struct pa_source*s, struct pa_memchunk *chunk) { assert(s && chunk); - idxset_foreach(s->outputs, do_post, chunk); + pa_idxset_foreach(s->outputs, do_post, chunk); } -struct source* source_get_default(struct core *c) { - struct source *source; +struct pa_source* pa_source_get_default(struct pa_core *c) { + struct pa_source *source; assert(c); - if ((source = idxset_get_by_index(c->sources, c->default_source_index))) + if ((source = pa_idxset_get_by_index(c->sources, c->default_source_index))) return source; - if (!(source = idxset_first(c->sources, &c->default_source_index))) + if (!(source = pa_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; +char *pa_source_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_source *source, *default_source; + uint32_t index = PA_IDXSET_INVALID; assert(c); - s = strbuf_new(); + s = pa_strbuf_new(); assert(s); - strbuf_printf(s, "%u source(s) available.\n", idxset_ncontents(c->sources)); + pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_ncontents(c->sources)); - default_source = source_get_default(c); + default_source = pa_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); + 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); - return strbuf_tostring_free(s); + return pa_strbuf_tostring_free(s); } diff --git a/src/source.h b/src/source.h index 186271c0..03d540c8 100644 --- a/src/source.h +++ b/src/source.h @@ -1,7 +1,7 @@ #ifndef foosourcehfoo #define foosourcehfoo -struct source; +struct pa_source; #include #include "core.h" @@ -10,28 +10,28 @@ struct source; #include "memblock.h" #include "memchunk.h" -struct source { +struct pa_source { uint32_t index; char *name; - struct core *core; + struct pa_core *core; struct pa_sample_spec sample_spec; - struct idxset *outputs; + struct pa_idxset *outputs; - void (*notify)(struct source*source); + void (*notify)(struct pa_source*source); void *userdata; }; -struct source* source_new(struct core *core, const char *name, int fail, const struct pa_sample_spec *spec); -void source_free(struct source *s); +struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec); +void pa_source_free(struct pa_source *s); /* Pass a new memory block to all output streams */ -void source_post(struct source*s, struct memchunk *b); +void pa_source_post(struct pa_source*s, struct pa_memchunk *b); -void source_notify(struct source *s); +void pa_source_notify(struct pa_source *s); -char *source_list_to_string(struct core *c); +char *pa_source_list_to_string(struct pa_core *c); -struct source* source_get_default(struct core *c); +struct pa_source* pa_source_get_default(struct pa_core *c); #endif diff --git a/src/sourceoutput.c b/src/sourceoutput.c index e0ed0798..4f9f821b 100644 --- a/src/sourceoutput.c +++ b/src/sourceoutput.c @@ -5,17 +5,17 @@ #include "sourceoutput.h" #include "strbuf.h" -struct source_output* source_output_new(struct source *s, const char *name, const struct pa_sample_spec *spec) { - struct source_output *o; - struct resampler *resampler = NULL; +struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec) { + struct pa_source_output *o; + struct pa_resampler *resampler = NULL; int r; assert(s && spec); if (!pa_sample_spec_equal(&s->sample_spec, spec)) - if (!(resampler = resampler_new(&s->sample_spec, spec))) + if (!(resampler = pa_resampler_new(&s->sample_spec, spec))) return NULL; - o = malloc(sizeof(struct source_output)); + o = malloc(sizeof(struct pa_source_output)); assert(o); o->name = name ? strdup(name) : NULL; o->source = s; @@ -27,59 +27,59 @@ struct source_output* source_output_new(struct source *s, const char *name, cons o->resampler = resampler; assert(s->core); - r = idxset_put(s->core->source_outputs, o, &o->index); - assert(r == 0 && o->index != IDXSET_INVALID); - r = idxset_put(s->outputs, o, NULL); + r = pa_idxset_put(s->core->source_outputs, o, &o->index); + assert(r == 0 && o->index != PA_IDXSET_INVALID); + r = pa_idxset_put(s->outputs, o, NULL); assert(r == 0); return o; } -void source_output_free(struct source_output* o) { +void pa_source_output_free(struct pa_source_output* o) { assert(o); assert(o->source && o->source->core); - idxset_remove_by_data(o->source->core->source_outputs, o, NULL); - idxset_remove_by_data(o->source->outputs, o, NULL); + pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); + pa_idxset_remove_by_data(o->source->outputs, o, NULL); if (o->resampler) - resampler_free(o->resampler); + pa_resampler_free(o->resampler); free(o->name); free(o); } -void source_output_kill(struct source_output*i) { +void pa_source_output_kill(struct pa_source_output*i) { assert(i); if (i->kill) i->kill(i); } -char *source_output_list_to_string(struct core *c) { - struct strbuf *s; - struct source_output *o; - uint32_t index = IDXSET_INVALID; +char *pa_source_output_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_source_output *o; + uint32_t index = PA_IDXSET_INVALID; assert(c); - s = strbuf_new(); + s = pa_strbuf_new(); assert(s); - strbuf_printf(s, "%u source outputs(s) available.\n", idxset_ncontents(c->source_outputs)); + pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_ncontents(c->source_outputs)); - for (o = idxset_first(c->source_outputs, &index); o; o = idxset_next(c->source_outputs, &index)) { + for (o = pa_idxset_first(c->source_outputs, &index); o; o = pa_idxset_next(c->source_outputs, &index)) { assert(o->source); - strbuf_printf(s, " %c index: %u, name: <%s>, source: <%u>\n", - o->index, - o->name, - o->source->index); + pa_strbuf_printf(s, " %c index: %u, name: <%s>, source: <%u>\n", + o->index, + o->name, + o->source->index); } - return strbuf_tostring_free(s); + return pa_strbuf_tostring_free(s); } -void source_output_push(struct source_output *o, const struct memchunk *chunk) { - struct memchunk rchunk; +void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk *chunk) { + struct pa_memchunk rchunk; assert(o && chunk && chunk->length && o->push); if (!o->resampler) { @@ -87,11 +87,11 @@ void source_output_push(struct source_output *o, const struct memchunk *chunk) { return; } - resampler_run(o->resampler, chunk, &rchunk); + pa_resampler_run(o->resampler, chunk, &rchunk); if (!rchunk.length) return; assert(rchunk.memblock); o->push(o, &rchunk); - memblock_unref(rchunk.memblock); + pa_memblock_unref(rchunk.memblock); } diff --git a/src/sourceoutput.h b/src/sourceoutput.h index 4db2362d..fb60182a 100644 --- a/src/sourceoutput.h +++ b/src/sourceoutput.h @@ -8,28 +8,28 @@ #include "memblockq.h" #include "resampler.h" -struct source_output { +struct pa_source_output { uint32_t index; char *name; - struct source *source; + struct pa_source *source; struct pa_sample_spec sample_spec; - void (*push)(struct source_output *o, const struct memchunk *chunk); - void (*kill)(struct source_output* o); + void (*push)(struct pa_source_output *o, const struct pa_memchunk *chunk); + void (*kill)(struct pa_source_output* o); - struct resampler* resampler; + struct pa_resampler* resampler; void *userdata; }; -struct source_output* source_output_new(struct source *s, const char *name, const struct pa_sample_spec *spec); -void source_output_free(struct source_output* o); +struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec); +void pa_source_output_free(struct pa_source_output* o); -void source_output_kill(struct source_output*o); +void pa_source_output_kill(struct pa_source_output*o); -char *source_output_list_to_string(struct core *c); +char *pa_source_output_list_to_string(struct pa_core *c); -void source_output_push(struct source_output *o, const struct memchunk *chunk); +void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk *chunk); #endif diff --git a/src/strbuf.c b/src/strbuf.c index 9ce67ec3..c2a6518e 100644 --- a/src/strbuf.c +++ b/src/strbuf.c @@ -11,20 +11,20 @@ struct chunk { char text[]; }; -struct strbuf { +struct pa_strbuf { size_t length; struct chunk *head, *tail; }; -struct strbuf *strbuf_new(void) { - struct strbuf *sb = malloc(sizeof(struct strbuf)); +struct pa_strbuf *pa_strbuf_new(void) { + struct pa_strbuf *sb = malloc(sizeof(struct pa_strbuf)); assert(sb); sb->length = 0; sb->head = sb->tail = NULL; return sb; } -void strbuf_free(struct strbuf *sb) { +void pa_strbuf_free(struct pa_strbuf *sb) { assert(sb); while (sb->head) { struct chunk *c = sb->head; @@ -35,7 +35,7 @@ void strbuf_free(struct strbuf *sb) { free(sb); } -char *strbuf_tostring(struct strbuf *sb) { +char *pa_strbuf_tostring(struct pa_strbuf *sb) { char *t, *e; struct chunk *c; assert(sb); @@ -54,15 +54,15 @@ char *strbuf_tostring(struct strbuf *sb) { return t; } -char *strbuf_tostring_free(struct strbuf *sb) { +char *pa_strbuf_tostring_free(struct pa_strbuf *sb) { char *t; assert(sb); - t = strbuf_tostring(sb); - strbuf_free(sb); + t = pa_strbuf_tostring(sb); + pa_strbuf_free(sb); return t; } -void strbuf_puts(struct strbuf *sb, const char *t) { +void pa_strbuf_puts(struct pa_strbuf *sb, const char *t) { struct chunk *c; size_t l; assert(sb && t); @@ -87,7 +87,7 @@ void strbuf_puts(struct strbuf *sb, const char *t) { sb->length += l; } -int strbuf_printf(struct strbuf *sb, const char *format, ...) { +int pa_strbuf_printf(struct pa_strbuf *sb, const char *format, ...) { int r, size = 100; struct chunk *c = NULL; diff --git a/src/strbuf.h b/src/strbuf.h index f530a0dc..bb972044 100644 --- a/src/strbuf.h +++ b/src/strbuf.h @@ -1,14 +1,14 @@ #ifndef foostrbufhfoo #define foostrbufhfoo -struct strbuf; +struct pa_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); +struct pa_strbuf *pa_strbuf_new(void); +void pa_strbuf_free(struct pa_strbuf *sb); +char *pa_strbuf_tostring(struct pa_strbuf *sb); +char *pa_strbuf_tostring_free(struct pa_strbuf *sb); -int strbuf_printf(struct strbuf *sb, const char *format, ...); -void strbuf_puts(struct strbuf *sb, const char *t); +int pa_strbuf_printf(struct pa_strbuf *sb, const char *format, ...); +void pa_strbuf_puts(struct pa_strbuf *sb, const char *t); #endif diff --git a/src/tagstruct.c b/src/tagstruct.c index e6d6b2b2..67f52461 100644 --- a/src/tagstruct.c +++ b/src/tagstruct.c @@ -16,7 +16,7 @@ enum tags { TAG_SAMPLE_SPEC = 'a' }; -struct tagstruct { +struct pa_tagstruct { uint8_t *data; size_t length, allocated; size_t rindex; @@ -24,12 +24,12 @@ struct tagstruct { int dynamic; }; -struct tagstruct *tagstruct_new(const uint8_t* data, size_t length) { - struct tagstruct*t; +struct pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) { + struct pa_tagstruct*t; assert(!data || (data && length)); - t = malloc(sizeof(struct tagstruct)); + t = malloc(sizeof(struct pa_tagstruct)); assert(t); t->data = (uint8_t*) data; t->allocated = t->length = data ? length : 0; @@ -38,14 +38,14 @@ struct tagstruct *tagstruct_new(const uint8_t* data, size_t length) { return t; } -void tagstruct_free(struct tagstruct*t) { +void pa_tagstruct_free(struct pa_tagstruct*t) { assert(t); if (t->dynamic) free(t->data); free(t); } -uint8_t* tagstruct_free_data(struct tagstruct*t, size_t *l) { +uint8_t* pa_tagstruct_free_data(struct pa_tagstruct*t, size_t *l) { uint8_t *p; assert(t && t->dynamic && l); p = t->data; @@ -54,7 +54,7 @@ uint8_t* tagstruct_free_data(struct tagstruct*t, size_t *l) { return p; } -static void extend(struct tagstruct*t, size_t l) { +static void extend(struct pa_tagstruct*t, size_t l) { assert(t && t->dynamic); if (l <= t->allocated) @@ -64,7 +64,7 @@ static void extend(struct tagstruct*t, size_t l) { assert(t->data); } -void tagstruct_puts(struct tagstruct*t, const char *s) { +void pa_tagstruct_puts(struct pa_tagstruct*t, const char *s) { size_t l; assert(t && s); l = strlen(s)+2; @@ -74,7 +74,7 @@ void tagstruct_puts(struct tagstruct*t, const char *s) { t->length += l; } -void tagstruct_putu32(struct tagstruct*t, uint32_t i) { +void pa_tagstruct_putu32(struct pa_tagstruct*t, uint32_t i) { assert(t); extend(t, 5); t->data[t->length] = TAG_U32; @@ -82,7 +82,7 @@ void tagstruct_putu32(struct tagstruct*t, uint32_t i) { t->length += 5; } -void tagstruct_putu8(struct tagstruct*t, uint8_t c) { +void pa_tagstruct_putu8(struct pa_tagstruct*t, uint8_t c) { assert(t); extend(t, 2); t->data[t->length] = TAG_U8; @@ -90,7 +90,7 @@ void tagstruct_putu8(struct tagstruct*t, uint8_t c) { t->length += 2; } -void tagstruct_put_sample_spec(struct tagstruct *t, const struct pa_sample_spec *ss) { +void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample_spec *ss) { assert(t && ss); extend(t, 7); t->data[t->length] = TAG_SAMPLE_SPEC; @@ -100,7 +100,7 @@ void tagstruct_put_sample_spec(struct tagstruct *t, const struct pa_sample_spec t->length += 7; } -int tagstruct_gets(struct tagstruct*t, const char **s) { +int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s) { int error = 0; size_t n; char *c; @@ -128,7 +128,7 @@ int tagstruct_gets(struct tagstruct*t, const char **s) { return 0; } -int tagstruct_getu32(struct tagstruct*t, uint32_t *i) { +int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i) { assert(t && i); if (t->rindex+5 > t->length) @@ -142,7 +142,7 @@ int tagstruct_getu32(struct tagstruct*t, uint32_t *i) { return 0; } -int tagstruct_getu8(struct tagstruct*t, uint8_t *c) { +int pa_tagstruct_getu8(struct pa_tagstruct*t, uint8_t *c) { assert(t && c); if (t->rindex+2 > t->length) @@ -156,7 +156,7 @@ int tagstruct_getu8(struct tagstruct*t, uint8_t *c) { return 0; } -int tagstruct_get_sample_spec(struct tagstruct *t, struct pa_sample_spec *ss) { +int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec *ss) { assert(t && ss); if (t->rindex+7 > t->length) @@ -174,12 +174,12 @@ int tagstruct_get_sample_spec(struct tagstruct *t, struct pa_sample_spec *ss) { } -int tagstruct_eof(struct tagstruct*t) { +int pa_tagstruct_eof(struct pa_tagstruct*t) { assert(t); return t->rindex >= t->length; } -const uint8_t* tagstruct_data(struct tagstruct*t, size_t *l) { +const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l) { assert(t && t->dynamic && l); *l = t->length; return t->data; diff --git a/src/tagstruct.h b/src/tagstruct.h index 9f6a0bf4..be4e01fa 100644 --- a/src/tagstruct.h +++ b/src/tagstruct.h @@ -6,24 +6,24 @@ #include "sample.h" -struct tagstruct; +struct pa_tagstruct; -struct tagstruct *tagstruct_new(const uint8_t* data, size_t length); -void tagstruct_free(struct tagstruct*t); -uint8_t* tagstruct_free_data(struct tagstruct*t, size_t *l); +struct pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length); +void pa_tagstruct_free(struct pa_tagstruct*t); +uint8_t* pa_tagstruct_free_data(struct pa_tagstruct*t, size_t *l); -void tagstruct_puts(struct tagstruct*t, const char *s); -void tagstruct_putu32(struct tagstruct*t, uint32_t i); -void tagstruct_putu8(struct tagstruct*t, uint8_t c); -void tagstruct_put_sample_spec(struct tagstruct *t, const struct pa_sample_spec *ss); +void pa_tagstruct_puts(struct pa_tagstruct*t, const char *s); +void pa_tagstruct_putu32(struct pa_tagstruct*t, uint32_t i); +void pa_tagstruct_putu8(struct pa_tagstruct*t, uint8_t c); +void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample_spec *ss); -int tagstruct_gets(struct tagstruct*t, const char **s); -int tagstruct_getu32(struct tagstruct*t, uint32_t *i); -int tagstruct_getu8(struct tagstruct*t, uint8_t *c); -int tagstruct_get_sample_spec(struct tagstruct *t, struct pa_sample_spec *ss); +int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s); +int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i); +int pa_tagstruct_getu8(struct pa_tagstruct*t, uint8_t *c); +int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec *ss); -int tagstruct_eof(struct tagstruct*t); -const uint8_t* tagstruct_data(struct tagstruct*t, size_t *l); +int pa_tagstruct_eof(struct pa_tagstruct*t); +const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l); diff --git a/src/todo b/src/todo index 0f88b043..15043813 100644 --- a/src/todo +++ b/src/todo @@ -1,5 +1,4 @@ - recording (general, simple, esound, native) -- make it embedable (add pa_ prefix too all identifiers) - native library/protocol: sync() function more functions @@ -7,8 +6,10 @@ - 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 -- post 0.1 diff --git a/src/tokenizer.c b/src/tokenizer.c index 0d266a9a..de82c8e1 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -5,15 +5,15 @@ #include "tokenizer.h" #include "dynarray.h" -struct tokenizer { - struct dynarray *dynarray; +struct pa_tokenizer { + struct pa_dynarray *dynarray; }; static void token_free(void *p, void *userdata) { free(p); } -static void parse(struct dynarray*a, const char *s, unsigned args) { +static void parse(struct pa_dynarray*a, const char *s, unsigned args) { int infty = 0; const char delimiter[] = " \t\n\r"; const char *p; @@ -27,7 +27,7 @@ static void parse(struct dynarray*a, const char *s, unsigned args) { size_t l = strcspn(p, delimiter); char *n = strndup(p, l); assert(n); - dynarray_append(a, n); + pa_dynarray_append(a, n); p += l; p += strspn(p, delimiter); args--; @@ -36,29 +36,29 @@ static void parse(struct dynarray*a, const char *s, unsigned args) { if (args && *p) { char *n = strdup(p); assert(n); - dynarray_append(a, n); + pa_dynarray_append(a, n); } } -struct tokenizer* tokenizer_new(const char *s, unsigned args) { - struct tokenizer *t; +struct pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args) { + struct pa_tokenizer *t; - t = malloc(sizeof(struct tokenizer)); + t = malloc(sizeof(struct pa_tokenizer)); assert(t); - t->dynarray = dynarray_new(); + t->dynarray = pa_dynarray_new(); assert(t->dynarray); parse(t->dynarray, s, args); return t; } -void tokenizer_free(struct tokenizer *t) { +void pa_tokenizer_free(struct pa_tokenizer *t) { assert(t); - dynarray_free(t->dynarray, token_free, NULL); + pa_dynarray_free(t->dynarray, token_free, NULL); free(t); } -const char *tokenizer_get(struct tokenizer *t, unsigned i) { +const char *pa_tokenizer_get(struct pa_tokenizer *t, unsigned i) { assert(t); - return dynarray_get(t->dynarray, i); + return pa_dynarray_get(t->dynarray, i); } diff --git a/src/tokenizer.h b/src/tokenizer.h index c71ae790..160b23e0 100644 --- a/src/tokenizer.h +++ b/src/tokenizer.h @@ -1,11 +1,11 @@ #ifndef footokenizerhfoo #define footokenizerhfoo -struct tokenizer; +struct pa_tokenizer; -struct tokenizer* tokenizer_new(const char *s, unsigned args); -void tokenizer_free(struct tokenizer *t); +struct pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args); +void pa_tokenizer_free(struct pa_tokenizer *t); -const char *tokenizer_get(struct tokenizer *t, unsigned i); +const char *pa_tokenizer_get(struct pa_tokenizer *t, unsigned i); #endif diff --git a/src/util.c b/src/util.c index 8f444336..5fff55e3 100644 --- a/src/util.c +++ b/src/util.c @@ -12,7 +12,7 @@ #include "util.h" -void make_nonblock_fd(int fd) { +void pa_make_nonblock_fd(int fd) { int v; if ((v = fcntl(fd, F_GETFL)) >= 0) @@ -20,7 +20,7 @@ void make_nonblock_fd(int fd) { fcntl(fd, F_SETFL, v|O_NONBLOCK); } -void peer_to_string(char *c, size_t l, int fd) { +void pa_peer_to_string(char *c, size_t l, int fd) { struct stat st; assert(c && l && fd >= 0); @@ -66,7 +66,7 @@ void peer_to_string(char *c, size_t l, int fd) { snprintf(c, l, "Unknown client"); } -int make_secure_dir(const char* dir) { +int pa_make_secure_dir(const char* dir) { struct stat st; if (mkdir(dir, 0700) < 0) @@ -86,7 +86,7 @@ fail: return -1; } -int make_socket_low_delay(int fd) { +int pa_make_socket_low_delay(int fd) { int ret = 0, buf_size, priority; assert(fd >= 0); @@ -106,12 +106,12 @@ int make_socket_low_delay(int fd) { return ret; } -int make_tcp_socket_low_delay(int fd) { +int pa_make_tcp_socket_low_delay(int fd) { int ret, tos, on; assert(fd >= 0); - ret = make_socket_low_delay(fd); + ret = pa_make_socket_low_delay(fd); on = 1; if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) diff --git a/src/util.h b/src/util.h index 8e9a3796..b8759ad8 100644 --- a/src/util.h +++ b/src/util.h @@ -1,13 +1,15 @@ #ifndef fooutilhfoo #define fooutilhfoo -void make_nonblock_fd(int fd); +#include -void peer_to_string(char *c, size_t l, int fd); +void pa_make_nonblock_fd(int fd); -int make_secure_dir(const char* dir); +void pa_peer_to_string(char *c, size_t l, int fd); -int make_socket_low_delay(int fd); -int make_tcp_socket_low_delay(int fd); +int pa_make_secure_dir(const char* dir); + +int pa_make_socket_low_delay(int fd); +int pa_make_tcp_socket_low_delay(int fd); #endif -- cgit From 722c2c8c8785d215ec3ec8757168b82c9600f4a3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 4 Jul 2004 17:40:15 +0000 Subject: add kill_* and default_* commands to CLI 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 --- src/Makefile.am | 6 +- src/cli.c | 301 +++++++++++++++++++++++++++++++++++++++++++------------ src/client.c | 8 +- src/ioline.c | 10 +- src/main.c | 2 - src/main.h | 6 -- src/module-cli.c | 18 +++- src/sink.c | 1 + src/sioman.c | 17 ++++ src/sioman.h | 7 ++ src/source.c | 9 +- src/source.h | 2 + src/todo | 5 +- 13 files changed, 298 insertions(+), 94 deletions(-) delete mode 100644 src/main.h create mode 100644 src/sioman.c create mode 100644 src/sioman.h diff --git a/src/Makefile.am b/src/Makefile.am index 167bc91c..62b1a3a6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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) diff --git a/src/cli.c b/src/cli.c index 659523b1..ecde5763 100644 --- 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; +} diff --git a/src/client.c b/src/client.c index eb06c52f..7f1648a7 100644 --- a/src/client.c +++ b/src/client.c @@ -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) { diff --git a/src/ioline.c b/src/ioline.c index ab7cb517..86ab5720 100644 --- a/src/ioline.c +++ b/src/ioline.c @@ -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; diff --git a/src/main.c b/src/main.c index be75b372..f44a8d47 100644 --- a/src/main.c +++ b/src/main.c @@ -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 index 35333bbf..00000000 --- a/src/main.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef foomainhfoo -#define foomainhfoo - -extern int pa_stdin_inuse, pa_stdout_inuse; - -#endif diff --git a/src/module-cli.c b/src/module-cli.c index 4a1692ee..7306ade5 100644 --- a/src/module-cli.c +++ b/src/module-cli.c @@ -2,27 +2,36 @@ #include #include -#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(); } diff --git a/src/sink.c b/src/sink.c index 53ebb8bf..79bf1778 100644 --- a/src/sink.c +++ b/src/sink.c @@ -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 index 00000000..1a4b08b0 --- /dev/null +++ b/src/sioman.c @@ -0,0 +1,17 @@ +#include +#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 index 00000000..e675c80e --- /dev/null +++ b/src/sioman.h @@ -0,0 +1,7 @@ +#ifndef foosiomanhfoo +#define foosiomanhfoo + +int pa_stdio_acquire(void); +void pa_stdio_release(void); + +#endif diff --git a/src/source.c b/src/source.c index 9a4f95a2..1c97604b 100644 --- a/src/source.c +++ b/src/source.c @@ -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); } diff --git a/src/source.h b/src/source.h index 03d540c8..3b66cd36 100644 --- a/src/source.h +++ b/src/source.h @@ -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; diff --git a/src/todo b/src/todo index 15043813..505eeac2 100644 --- 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 -- cgit From f8cbde54dab2783e2c6ba699dfaee9ef51b1e098 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 6 Jul 2004 00:08:44 +0000 Subject: auth support in esound and native AUTH and SET_NAME operatins in native simple library git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@51 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 33 ++++++++++--- src/authkey.c | 115 +++++++++++++++++++++++++++++++++++++++++++++ src/authkey.h | 9 ++++ src/main.c | 2 +- src/module-oss.c | 3 +- src/module-protocol-stub.c | 23 +++++++-- src/pacat-simple.c | 52 ++++++++++++++++++++ src/pacat.c | 13 +++-- src/polyp-error.c | 25 ++++++++++ src/polyp-error.h | 10 ++++ src/polyp.c | 108 +++++++++++++++++++++++++++++++----------- src/polyp.h | 6 +-- src/protocol-esound.c | 35 ++++++++++---- src/protocol-native-spec.h | 10 +++- src/protocol-native.c | 57 ++++++++++++++++++++++ src/simple.c | 70 ++++++++++++++------------- src/simple.h | 7 +-- src/tagstruct.c | 31 +++++++++++- src/tagstruct.h | 2 + src/todo | 12 ++++- src/util.c | 84 +++++++++++++++++++++++++++++++++ src/util.h | 6 +++ 22 files changed, 615 insertions(+), 98 deletions(-) create mode 100644 src/authkey.c create mode 100644 src/authkey.h create mode 100644 src/pacat-simple.c create mode 100644 src/polyp-error.c create mode 100644 src/polyp-error.h diff --git a/src/Makefile.am b/src/Makefile.am index 62b1a3a6..70e7e09b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,7 +18,7 @@ AM_CFLAGS=-ansi -D_GNU_SOURCE -bin_PROGRAMS = polypaudio pacat +bin_PROGRAMS = polypaudio pacat pacat-simple pkglib_LTLIBRARIES=libiochannel.la \ libsocket-server.la \ @@ -34,6 +34,7 @@ pkglib_LTLIBRARIES=libiochannel.la \ libtagstruct.la \ libpstream-util.la \ libpdispatch.la \ + libauthkey.la \ libprotocol-simple.la \ libprotocol-esound.la \ libprotocol-native.la \ @@ -49,7 +50,9 @@ pkglib_LTLIBRARIES=libiochannel.la \ module-esound-protocol-unix.la \ module-native-protocol-tcp.la \ module-native-protocol-unix.la \ - libpolyp.la + libpolyp.la \ + libpolyp-simple.la \ + libpolyp-error.la polypaudio_SOURCES = idxset.c idxset.h \ queue.c queue.h \ @@ -139,14 +142,17 @@ libprotocol_cli_la_LIBADD = libsocket-server.la libiochannel.la libcli.la libprotocol_native_la_SOURCES = protocol-native.c protocol-native.h libprotocol_native_la_LDFLAGS = -avoid-version -libprotocol_native_la_LIBADD = libsocket-server.la libiochannel.la libpacket.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la +libprotocol_native_la_LIBADD = libsocket-server.la libiochannel.la libpacket.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libtagstruct_la_SOURCES = tagstruct.c tagstruct.h libtagstruct_la_LDFLAGS = -avoid-version libprotocol_esound_la_SOURCES = protocol-esound.c protocol-esound.h protocol-esound-spec.h libprotocol_esound_la_LDFLAGS = -avoid-version -libprotocol_esound_la_LIBADD = libsocket-server.la libiochannel.la +libprotocol_esound_la_LIBADD = libsocket-server.la libiochannel.la libauthkey.la + +libauthkey_la_SOURCES = authkey.c authkey.h +libauthkey_la_LDFLAGS = -avoid-version module_simple_protocol_tcp_la_SOURCES = module-protocol-stub.c module_simple_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) @@ -221,7 +227,22 @@ libpolyp_la_SOURCES = polyp.c polyp.h \ packet.c packet.h \ queue.c queue.h \ dynarray.c dynarray.h \ - memchunk.c memchunk.h + memchunk.c memchunk.h \ + authkey.c authkey.h +libpolyp_la_CFLAGS = $(AM_CFLAGS) +#libpolyp_la_LIBADD = libpolyp-error.la + +libpolyp_error_la_SOURCES = polyp-error.c polyp-error.h +libpolyp_error_la_CFLAGS = $(AM_CFLAGS) -pacat_SOURCES = pacat.c +libpolyp_simple_la_SOURCES = simple.c simple.h +libpolyp_simple_la_CFLAGS = $(AM_CFLAGS) +libpolyp_simple_la_LIBADD = libpolyp.la #libpolyp-error.la + +pacat_SOURCES = pacat.c #$(libpolyp_la_SOURCES) pacat_LDADD = libpolyp.la +pacat_CFLAGS = $(AM_CFLAGS) + +pacat_simple_SOURCES = pacat-simple.c +pacat_simple_LDADD = libpolyp-simple.a +pacat_simple_CFLAGS = $(AM_CFLAGS) diff --git a/src/authkey.c b/src/authkey.c new file mode 100644 index 00000000..cd284fb5 --- /dev/null +++ b/src/authkey.c @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "authkey.h" +#include "util.h" + +#define RANDOM_DEVICE "/dev/urandom" + +static int load(const char *fn, void *data, size_t length) { + int fd = -1, ret = -1; + ssize_t r; + + assert(fn && data && length); + + if ((fd = open(fn, O_RDONLY)) < 0) + goto finish; + + if ((r = pa_loop_read(fd, data, length)) < 0 || (size_t) r != length) { + ret = -2; + goto finish; + } + + ret = 0; + +finish: + if (fd >= 0) + close(fd); + + return ret; +} + +static int generate(const char *fn, void *data, size_t length) { + int fd = -1, random_fd = -1, ret = -1; + ssize_t r; + assert(fn && data && length); + + if ((fd = open(fn, O_WRONLY|O_EXCL|O_CREAT, S_IRUSR | S_IWUSR)) < 0) + goto finish; + + if ((random_fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) { + + if ((r = pa_loop_read(random_fd, data, length)) < 0 || (size_t) r != length) { + ret = -2; + goto finish; + } + + } else { + uint8_t *p; + size_t l; + fprintf(stderr, "WARNING: Failed to open entropy device '"RANDOM_DEVICE"': %s, falling back to unsecure pseudo RNG.\n", strerror(errno)); + + srandom(time(NULL)); + + for (p = data, l = length; l > 0; p++, l--) + *p = (uint8_t) random(); + } + + if ((r = pa_loop_write(fd, data, length)) < 0 || (size_t) r != length) { + ret = -2; + goto finish; + } + + ret = 0; + +finish: + if (fd >= 0) { + if (ret != 0) + unlink(fn); + close(fd); + } + if (random_fd >= 0) + close(random_fd); + + return ret; +} + +int pa_authkey_load(const char *path, void *data, size_t length) { + int ret, i; + + assert(path && data && length); + + for (i = 0; i < 10; i++) { + if ((ret = load(path, data, length)) < 0) + if (ret == -1 && errno == ENOENT) + if ((ret = generate(path, data, length)) < 0) + if (ret == -1 && errno == EEXIST) + continue; + break; + } + + if (ret < 0) + fprintf(stderr, "Failed to load authorization key '%s': %s\n", path, (ret == -1) ? strerror(errno) : "file corrupt"); + + return ret; +} + +int pa_authkey_load_from_home(const char *fn, void *data, size_t length) { + char *home; + char path[PATH_MAX]; + + if (!(home = getenv("HOME"))) + return -2; + + snprintf(path, sizeof(path), "%s/%s", home, fn); + + return pa_authkey_load(path, data, length); +} diff --git a/src/authkey.h b/src/authkey.h new file mode 100644 index 00000000..cc0fcb28 --- /dev/null +++ b/src/authkey.h @@ -0,0 +1,9 @@ +#ifndef fooauthkeyhfoo +#define fooauthkeyhfoo + +#include + +int pa_authkey_load(const char *path, void *data, size_t len); +int pa_authkey_load_from_home(const char *fn, void *data, size_t length); + +#endif diff --git a/src/main.c b/src/main.c index f44a8d47..88552fed 100644 --- a/src/main.c +++ b/src/main.c @@ -44,7 +44,7 @@ int main(int argc, char *argv[]) { 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-unix", NULL); -/* pa_module_load(c, "module-esound-protocol-tcp", NULL);*/ + pa_module_load(c, "module-esound-protocol-tcp", NULL); pa_module_load(c, "module-cli", NULL); fprintf(stderr, "main: mainloop entry.\n"); diff --git a/src/module-oss.c b/src/module-oss.c index 3a1afd47..310c89c0 100644 --- a/src/module-oss.c +++ b/src/module-oss.c @@ -77,7 +77,8 @@ static void do_read(struct userdata *u) { assert(memchunk.memblock); if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); - fprintf(stderr, "read() failed: %s\n", strerror(errno)); + if (errno != EAGAIN) + fprintf(stderr, "read() failed: %s\n", strerror(errno)); return; } diff --git a/src/module-protocol-stub.c b/src/module-protocol-stub.c index 1a655454..713e0ab8 100644 --- a/src/module-protocol-stub.c +++ b/src/module-protocol-stub.c @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -50,13 +52,24 @@ int module_init(struct pa_core *c, struct pa_module*m) { assert(c && m); #ifdef USE_TCP_SOCKETS - if (!(s = pa_socket_server_new_ipv4(c->mainloop, INADDR_LOOPBACK, IPV4_PORT))) + if (!(s = pa_socket_server_new_ipv4(c->mainloop, INADDR_ANY, IPV4_PORT))) return -1; #else if (pa_make_secure_dir(UNIX_SOCKET_DIR) < 0) { fprintf(stderr, "Failed to create secure socket directory.\n"); return -1; } + + { + int r; + if ((r = pa_unix_socket_remove_stale(UNIX_SOCKET)) < 0) { + fprintf(stderr, "Failed to remove stale UNIX socket '%s': %s\n", UNIX_SOCKET, strerror(errno)); + return -1; + } + + if (r) + fprintf(stderr, "Removed stale UNIX socket '%s'.", UNIX_SOCKET); + } if (!(s = pa_socket_server_new_unix(c->mainloop, UNIX_SOCKET))) { rmdir(UNIX_SOCKET_DIR); @@ -69,8 +82,12 @@ int module_init(struct pa_core *c, struct pa_module*m) { #else m->userdata = protocol_new(c, s); #endif - - assert(m->userdata); + + if (!m->userdata) { + pa_socket_server_free(s); + return -1; + } + return 0; } diff --git a/src/pacat-simple.c b/src/pacat-simple.c new file mode 100644 index 00000000..5408221c --- /dev/null +++ b/src/pacat-simple.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +#include "simple.h" +#include "polyp-error.h" + +#define BUFSIZE 1024 + +int main(int argc, char*argv[]) { + static const struct pa_sample_spec ss = { + .format = PA_SAMPLE_S16LE, + .rate = 44100, + .channels = 2 + }; + struct pa_simple *s = NULL; + int ret = 1; + int error; + + if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, &error))) { + fprintf(stderr, "Failed to connect to server: %s\n", pa_strerror(error)); + goto finish; + } + + for (;;) { + uint8_t buf[BUFSIZE]; + ssize_t r; + + if ((r = read(STDIN_FILENO, buf, sizeof(buf))) <= 0) { + if (r == 0) /* eof */ + break; + + fprintf(stderr, "read() failed: %s\n", strerror(errno)); + goto finish; + } + + if (pa_simple_write(s, buf, r, &error) < 0) { + fprintf(stderr, "Failed to write data: %s\n", pa_strerror(error)); + goto finish; + } + } + + ret = 0; + +finish: + + if (s) + pa_simple_free(s); + + return ret; +} diff --git a/src/pacat.c b/src/pacat.c index 32220aeb..c69148e6 100644 --- a/src/pacat.c +++ b/src/pacat.c @@ -59,18 +59,17 @@ static void stream_write_callback(struct pa_stream *s, size_t length, void *user do_write(length); } -static void stream_complete_callback(struct pa_context*c, struct pa_stream *s, void *userdata) { - assert(c); +static void stream_complete_callback(struct pa_stream*s, int success, void *userdata) { + assert(s); - if (!s) { + if (!success) { fprintf(stderr, "Stream creation failed.\n"); mainloop_api->quit(mainloop_api, 1); return; } - stream = s; - pa_stream_set_die_callback(stream, stream_die_callback, NULL); - pa_stream_set_write_callback(stream, stream_write_callback, NULL); + pa_stream_set_die_callback(s, stream_die_callback, NULL); + pa_stream_set_write_callback(s, stream_write_callback, NULL); } static void context_complete_callback(struct pa_context *c, int success, void *userdata) { @@ -87,7 +86,7 @@ static void context_complete_callback(struct pa_context *c, int success, void *u goto fail; } - if (pa_stream_new(c, PA_STREAM_PLAYBACK, NULL, "pacat", &ss, NULL, stream_complete_callback, NULL) < 0) { + if (!(stream = pa_stream_new(c, PA_STREAM_PLAYBACK, NULL, "pacat", &ss, NULL, stream_complete_callback, NULL))) { fprintf(stderr, "pa_stream_new() failed.\n"); goto fail; } diff --git a/src/polyp-error.c b/src/polyp-error.c new file mode 100644 index 00000000..861711a2 --- /dev/null +++ b/src/polyp-error.c @@ -0,0 +1,25 @@ +#include + +#include "polyp-error.h" +#include "protocol-native-spec.h" + +static const char* const errortab[PA_ERROR_MAX] = { + [PA_ERROR_OK] = "OK", + [PA_ERROR_ACCESS] = "Access denied", + [PA_ERROR_COMMAND] = "Unknown command", + [PA_ERROR_INVALID] = "Invalid argument", + [PA_ERROR_EXIST] = "Entity exists", + [PA_ERROR_NOENTITY] = "No such entity", + [PA_ERROR_CONNECTIONREFUSED] = "Connection refused", + [PA_ERROR_PROTOCOL] = "Protocol corrupt", + [PA_ERROR_TIMEOUT] = "Timeout", + [PA_ERROR_AUTHKEY] = "Not authorization key", + [PA_ERROR_INTERNAL] = "Internal error" +}; + +const char*pa_strerror(uint32_t error) { + if (error >= PA_ERROR_MAX) + return NULL; + + return errortab[error]; +} diff --git a/src/polyp-error.h b/src/polyp-error.h new file mode 100644 index 00000000..7407f34c --- /dev/null +++ b/src/polyp-error.h @@ -0,0 +1,10 @@ +#ifndef foopolyperrhfoo +#define foopolyperrhfoo + +#include + +#include "protocol-native-spec.h" + +const char* pa_strerror(uint32_t error); + +#endif diff --git a/src/polyp.c b/src/polyp.c index eb9a3c20..c15d5d9f 100644 --- a/src/polyp.c +++ b/src/polyp.c @@ -10,6 +10,7 @@ #include "dynarray.h" #include "socket-client.h" #include "pstream-util.h" +#include "authkey.h" #define DEFAULT_QUEUE_LENGTH 10240 #define DEFAULT_MAX_LENGTH 20480 @@ -26,14 +27,16 @@ struct pa_context { struct pa_dynarray *streams; struct pa_stream *first_stream; uint32_t ctag; - uint32_t errno; - enum { CONTEXT_UNCONNECTED, CONTEXT_CONNECTING, CONTEXT_READY, CONTEXT_DEAD} state; + uint32_t error; + enum { CONTEXT_UNCONNECTED, CONTEXT_CONNECTING, CONTEXT_AUTHORIZING, CONTEXT_SETTING_NAME, CONTEXT_READY, CONTEXT_DEAD} state; void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); void *connect_complete_userdata; void (*die_callback)(struct pa_context*c, void *userdata); void *die_userdata; + + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; }; struct pa_stream { @@ -52,7 +55,7 @@ struct pa_stream { void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); void *write_userdata; - void (*create_complete_callback)(struct pa_context*c, struct pa_stream *s, void *userdata); + void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); void *create_complete_userdata; void (*die_callback)(struct pa_stream*c, void *userdata); @@ -85,7 +88,7 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * c->streams = pa_dynarray_new(); assert(c->streams); c->first_stream = NULL; - c->errno = PA_ERROR_OK; + c->error = PA_ERROR_OK; c->state = CONTEXT_UNCONNECTED; c->ctag = 0; @@ -158,9 +161,11 @@ static int pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packe if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { fprintf(stderr, "polyp.c: invalid packet.\n"); + context_dead(c); return -1; } + return 0; } @@ -170,7 +175,7 @@ static int pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int assert(p && chunk && c && chunk->memblock && chunk->memblock->data); if (!(s = pa_dynarray_get(c->streams, channel))) - return -1; + return 0; if (s->read_callback) s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); @@ -178,15 +183,57 @@ static int pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int return 0; } +static int auth_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); + + if (command != PA_COMMAND_REPLY) { + if (command == PA_COMMAND_ERROR && pa_tagstruct_getu32(t, &c->error) < 0) + c->error = PA_ERROR_PROTOCOL; + else if (command == PA_COMMAND_TIMEOUT) + c->error = PA_ERROR_TIMEOUT; + + c->state = CONTEXT_DEAD; + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return -1; + } + + if (c->state == CONTEXT_AUTHORIZING) { + struct pa_tagstruct *t; + c->state = CONTEXT_SETTING_NAME; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, c->name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, auth_complete_callback, c); + } else { + assert(c->state == CONTEXT_SETTING_NAME); + + c->state = CONTEXT_READY; + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 1, c->connect_complete_userdata); + } + + return 0; +} + static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { struct pa_context *c = userdata; + struct pa_tagstruct *t; + uint32_t tag; assert(client && io && c && c->state == CONTEXT_CONNECTING); pa_socket_client_free(client); c->client = NULL; if (!io) { - c->errno = PA_ERROR_CONNECTIONREFUSED; + c->error = PA_ERROR_CONNECTIONREFUSED; c->state = CONTEXT_UNCONNECTED; if (c->connect_complete_callback) @@ -204,18 +251,27 @@ static void on_connection(struct pa_socket_client *client, struct pa_iochannel*i c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); assert(c->pdispatch); - c->state = CONTEXT_READY; - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 1, c->connect_complete_userdata); + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_AUTH); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, auth_complete_callback, c); + c->state = CONTEXT_AUTHORIZING; } int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { assert(c && c->state == CONTEXT_UNCONNECTED); + if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { + c->error = PA_ERROR_AUTHKEY; + return -1; + } + assert(!c->client); if (!(c->client = pa_socket_client_new_unix(c->mainloop, server ? server : DEFAULT_SERVER))) { - c->errno = PA_ERROR_CONNECTIONREFUSED; + c->error = PA_ERROR_CONNECTIONREFUSED; return -1; } @@ -240,7 +296,7 @@ int pa_context_is_ready(struct pa_context *c) { int pa_context_errno(struct pa_context *c) { assert(c); - return c->errno; + return c->error; } void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { @@ -258,12 +314,12 @@ static int command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t t if (pa_tagstruct_getu32(t, &channel) < 0 || pa_tagstruct_getu32(t, &bytes) < 0 || !pa_tagstruct_eof(t)) { - c->errno = PA_ERROR_PROTOCOL; + c->error = PA_ERROR_PROTOCOL; return -1; } if (!(s = pa_dynarray_get(c->streams, channel))) { - c->errno = PA_ERROR_PROTOCOL; + c->error = PA_ERROR_PROTOCOL; return -1; } @@ -286,21 +342,19 @@ static int create_playback_callback(struct pa_pdispatch *pd, uint32_t command, u struct pa_context *c = s->context; assert(c); - if (command == PA_COMMAND_ERROR && pa_tagstruct_getu32(t, &s->context->errno) < 0) { - s->context->errno = PA_ERROR_PROTOCOL; - ret = -1; - } else if (command == PA_COMMAND_TIMEOUT) { - s->context->errno = PA_ERROR_TIMEOUT; - ret = -1; - } - + if (command == PA_COMMAND_ERROR && pa_tagstruct_getu32(t, &s->context->error) < 0) + s->context->error = PA_ERROR_PROTOCOL; + else if (command == PA_COMMAND_TIMEOUT) + s->context->error = PA_ERROR_TIMEOUT; + + ret = -1; goto fail; } if (pa_tagstruct_getu32(t, &s->channel) < 0 || pa_tagstruct_getu32(t, &s->device_index) < 0 || !pa_tagstruct_eof(t)) { - s->context->errno = PA_ERROR_PROTOCOL; + s->context->error = PA_ERROR_PROTOCOL; ret = -1; goto fail; } @@ -310,24 +364,24 @@ static int create_playback_callback(struct pa_pdispatch *pd, uint32_t command, u s->state = STREAM_READY; assert(s->create_complete_callback); - s->create_complete_callback(s->context, s, s->create_complete_userdata); + s->create_complete_callback(s, 1, s->create_complete_userdata); return 0; fail: assert(s->create_complete_callback); - s->create_complete_callback(s->context, NULL, s->create_complete_userdata); + s->create_complete_callback(s, 0, s->create_complete_userdata); pa_stream_free(s); return ret; } -int pa_stream_new( +struct pa_stream* pa_stream_new( struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, - void (*complete) (struct pa_context*c, struct pa_stream *s, void *userdata), + void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata) { struct pa_stream *s; diff --git a/src/polyp.h b/src/polyp.h index 171e3bdf..77a6966f 100644 --- a/src/polyp.h +++ b/src/polyp.h @@ -23,18 +23,18 @@ void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_cont int pa_context_is_dead(struct pa_context *c); int pa_context_is_ready(struct pa_context *c); -int pa_contect_errno(struct pa_context *c); +int pa_context_errno(struct pa_context *c); struct pa_stream; -int pa_stream_new( +struct pa_stream* pa_stream_new( struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, - void (*complete) (struct pa_context*c, struct pa_stream *s, void *userdata), + void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); void pa_stream_free(struct pa_stream *p); diff --git a/src/protocol-esound.c b/src/protocol-esound.c index 8198e72f..cd6448fc 100644 --- a/src/protocol-esound.c +++ b/src/protocol-esound.c @@ -13,6 +13,14 @@ #include "sink.h" #include "sample.h" +#include "authkey.h" + +#define COOKIE_FILE ".esd_auth" + +#define MEMBLOCKQ_LENGTH (10*1204) +#define MEMBLOCKQ_PREBUF (2*1024) +#define BUFSIZE (1024) + /* This is heavily based on esound's code */ struct connection { @@ -38,6 +46,7 @@ struct pa_protocol_esound { struct pa_idxset *connections; uint32_t sink_index; unsigned n_player; + uint8_t esd_key[ESD_KEY_LEN]; }; typedef struct proto_handler { @@ -46,11 +55,6 @@ typedef struct proto_handler { const char *description; } esd_proto_handler_info_t; -#define MEMBLOCKQ_LENGTH (10*1204) -#define MEMBLOCKQ_PREBUF (2*1024) - -#define BUFSIZE (1024) - static void sink_input_drop_cb(struct pa_sink_input *i, size_t length); static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk); static void sink_input_kill_cb(struct pa_sink_input *i); @@ -162,7 +166,14 @@ static int esd_proto_connect(struct connection *c, const void *data, size_t leng int *ok; assert(length == (ESD_KEY_LEN + sizeof(uint32_t))); - c->authorized = 1; + if (!c->authorized) { + if (memcmp(data, c->protocol->esd_key, ESD_KEY_LEN) != 0) { + fprintf(stderr, "protocol-esound.c: Kicked client with invalid authorization key.\n"); + return -1; + } + + c->authorized = 1; + } ekey = *(uint32_t*)(data+ESD_KEY_LEN); if (ekey == ESD_ENDIAN_KEY) @@ -583,17 +594,21 @@ struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa p = malloc(sizeof(struct pa_protocol_esound)); assert(p); - p->public = 1; + + if (pa_authkey_load_from_home(COOKIE_FILE, p->esd_key, sizeof(p->esd_key)) < 0) { + free(p); + return NULL; + } + + p->public = 0; p->server = server; + pa_socket_server_set_callback(p->server, on_connection, p); p->core = core; p->connections = pa_idxset_new(NULL, NULL); assert(p->connections); p->sink_index = PA_IDXSET_INVALID; - p->n_player = 0; - pa_socket_server_set_callback(p->server, on_connection, p); - return p; } diff --git a/src/protocol-native-spec.h b/src/protocol-native-spec.h index df11ae3c..07fc735b 100644 --- a/src/protocol-native-spec.h +++ b/src/protocol-native-spec.h @@ -11,6 +11,8 @@ enum { PA_COMMAND_DELETE_RECORD_STREAM, PA_COMMAND_EXIT, PA_COMMAND_REQUEST, + PA_COMMAND_AUTH, + PA_COMMAND_SET_NAME, PA_COMMAND_MAX }; @@ -23,7 +25,13 @@ enum { PA_ERROR_NOENTITY, PA_ERROR_CONNECTIONREFUSED, PA_ERROR_PROTOCOL, - PA_ERROR_TIMEOUT + PA_ERROR_TIMEOUT, + PA_ERROR_AUTHKEY, + PA_ERROR_INTERNAL, + PA_ERROR_MAX }; +#define PA_NATIVE_COOKIE_LENGTH 256 +#define PA_NATIVE_COOKIE_FILE ".polypaudio-cookie" + #endif diff --git a/src/protocol-native.c b/src/protocol-native.c index 8e4dcae1..9463a469 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -12,6 +13,7 @@ #include "tagstruct.h" #include "pdispatch.h" #include "pstream-util.h" +#include "authkey.h" struct connection; struct pa_protocol_native; @@ -46,6 +48,7 @@ struct pa_protocol_native { struct pa_core *core; struct pa_socket_server *server; struct pa_idxset *connections; + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; }; static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk); @@ -58,15 +61,21 @@ static void request_bytes(struct playback_stream*s); static int command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static int command_create_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static int command_delete_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static int command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static int command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = { NULL }, + [PA_COMMAND_TIMEOUT] = { NULL }, [PA_COMMAND_REPLY] = { NULL }, [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { command_create_playback_stream }, [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { command_delete_playback_stream }, [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_AUTH] = { command_auth }, + [PA_COMMAND_REQUEST] = { NULL }, [PA_COMMAND_EXIT] = { command_exit }, + [PA_COMMAND_SET_NAME] = { command_set_name }, }; /* structure management */ @@ -294,6 +303,40 @@ static int command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, return 0; } +static int command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const void*cookie; + assert(c && t); + + if (pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 || + !pa_tagstruct_eof(t)) + return -1; + + if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) != 0) { + fprintf(stderr, "protocol-native.c: Denied access to client with invalid authorization key.\n"); + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return 0; + } + + c->authorized = 1; + pa_pstream_send_simple_ack(c->pstream, tag); + return 0; +} + +static int command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const char *name; + assert(c && t); + + if (pa_tagstruct_gets(t, &name) < 0 || + !pa_tagstruct_eof(t)) + return -1; + + pa_client_rename(c->client, name); + pa_pstream_send_simple_ack(c->pstream, tag); + return 0; +} + /*** pstream callbacks ***/ static int packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { @@ -340,6 +383,13 @@ static void die_callback(struct pa_pstream *p, void *userdata) { fprintf(stderr, "protocol-native: connection died.\n"); } +/*** client callbacks ***/ + +static void client_kill_cb(struct pa_client *c) { + assert(c && c->userdata); + connection_free(c->userdata); +} + /*** socket server callbacks ***/ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { @@ -354,6 +404,8 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo assert(p->core); c->client = pa_client_new(p->core, "NATIVE", "Client"); assert(c->client); + c->client->kill = client_kill_cb; + c->client->userdata = c; c->pstream = pa_pstream_new(p->core->mainloop, io); assert(c->pstream); @@ -380,6 +432,11 @@ struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct p p = malloc(sizeof(struct pa_protocol_native)); assert(p); + if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, p->auth_cookie, sizeof(p->auth_cookie)) < 0) { + free(p); + return NULL; + } + p->public = 1; p->server = server; p->core = core; diff --git a/src/simple.c b/src/simple.c index a90d22bd..c1d1e96c 100644 --- a/src/simple.c +++ b/src/simple.c @@ -1,23 +1,19 @@ +#include +#include + #include "simple.h" #include "polyp.h" #include "mainloop.h" +#include "polyp-error.h" struct pa_simple { - struct mainloop *mainloop; + struct pa_mainloop *mainloop; struct pa_context *context; struct pa_stream *stream; - size_t requested; int dead; }; -static void playback_callback(struct pa_stream *p, size_t length, void *userdata) { - struct pa_stream *sp = userdata; - assert(p && length && sp); - - sp->requested = length; -} - struct pa_simple* pa_simple_new( const char *server, const char *name, @@ -25,9 +21,11 @@ struct pa_simple* pa_simple_new( const char *dev, const char *stream_name, const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr) { + const struct pa_buffer_attr *attr, + int *perror) { struct pa_simple *p; + int error = PA_ERROR_INTERNAL; assert(ss); p = malloc(sizeof(struct pa_simple)); @@ -36,39 +34,43 @@ struct pa_simple* pa_simple_new( p->stream = NULL; p->mainloop = pa_mainloop_new(); assert(p->mainloop); - p->requested = 0; p->dead = 0; if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name))) goto fail; - if (pa_context_connect(c, server, NULL, NULL) < 0) + if (pa_context_connect(p->context, server, NULL, NULL) < 0) { + error = pa_context_errno(p->context); goto fail; + } - while (!pa_context_is_ready(c)) { - if (pa_context_is_dead(c)) + while (!pa_context_is_ready(p->context)) { + if (pa_context_is_dead(p->context)) { + error = pa_context_errno(p->context); goto fail; + } - if (mainloop_iterate(p->mainloop) < 0) + if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) goto fail; } - if (!(p->stream = pa_stream_new(p->context, dir, sink, stream_name, ss, attr, NULL, NULL))) + if (!(p->stream = pa_stream_new(p->context, dir, dev, stream_name, ss, attr, NULL, NULL))) goto fail; - while (!pa_stream_is_ready(c)) { - if (pa_stream_is_dead(c)) + while (!pa_stream_is_ready(p->stream)) { + if (pa_stream_is_dead(p->stream)) { + error = pa_context_errno(p->context); goto fail; + } - if (mainloop_iterate(p->mainloop) < 0) + if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) goto fail; } - pa_stream_set_write_callback(p->stream, playback_callback, p); - return p; fail: + *perror = error; pa_simple_free(p); return NULL; } @@ -83,38 +85,40 @@ void pa_simple_free(struct pa_simple *s) { pa_context_free(s->context); if (s->mainloop) - mainloop_free(s->mainloop); + pa_mainloop_free(s->mainloop); free(s); } -int pa_simple_write(struct pa_simple *s, const void*data, size_t length) { - assert(s && data); +int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *perror) { + assert(p && data); while (length > 0) { size_t l; - while (!s->requested) { - if (pa_context_is_dead(c)) + while (!(l = pa_stream_writable_size(p->stream))) { + if (pa_context_is_dead(p->context)) { + *perror = pa_context_errno(p->context); return -1; + } - if (mainloop_iterate(s->mainloop) < 0) + if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) { + *perror = PA_ERROR_INTERNAL; return -1; + } } - l = length; - if (l > s->requested) - l = s->requested; + if (l > length) + l = length; - pa_stream_write(s->stream, data, l); + pa_stream_write(p->stream, data, l); data += l; length -= l; - s->requested = -l; } return 0; } -int pa_simple_read(struct pa_simple *s, const void*data, size_t length) { +int pa_simple_read(struct pa_simple *s, void*data, size_t length, int *perror) { assert(0); } diff --git a/src/simple.h b/src/simple.h index 80693056..ed181201 100644 --- a/src/simple.h +++ b/src/simple.h @@ -15,11 +15,12 @@ struct pa_simple* pa_simple_new( const char *dev, const char *stream_name, const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr); + const struct pa_buffer_attr *attr, + int *error); void pa_simple_free(struct pa_simple *s); -int pa_simple_write(struct pa_simple *s, const void*data, size_t length); -int pa_simple_read(struct pa_simple *s, const void*data, size_t length); +int pa_simple_write(struct pa_simple *s, const void*data, size_t length, int *error); +int pa_simple_read(struct pa_simple *s, void*data, size_t length, int *error); #endif diff --git a/src/tagstruct.c b/src/tagstruct.c index 67f52461..e57e755c 100644 --- a/src/tagstruct.c +++ b/src/tagstruct.c @@ -13,7 +13,8 @@ enum tags { TAG_S16 = 's', TAG_U8 = 'B', TAG_S8 = 'b', - TAG_SAMPLE_SPEC = 'a' + TAG_SAMPLE_SPEC = 'a', + TAG_ARBITRARY = 'x' }; struct pa_tagstruct { @@ -100,6 +101,18 @@ void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample t->length += 7; } + +void pa_tagstruct_put_arbitrary(struct pa_tagstruct *t, const void *p, size_t length) { + assert(t && p); + + extend(t, 5+length); + t->data[t->length] = TAG_ARBITRARY; + *((uint32_t*) (t->data+t->length+1)) = htonl(length); + if (length) + memcpy(t->data+t->length+5, p, length); + t->length += 5+length; +} + int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s) { int error = 0; size_t n; @@ -173,6 +186,22 @@ int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec * return 0; } +int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t length) { + assert(t && p); + + if (t->rindex+5+length > t->length) + return -1; + + if (t->data[t->rindex] != TAG_ARBITRARY) + return -1; + + if (ntohl(*((uint32_t*) (t->data+t->rindex+1))) != length) + return -1; + + *p = t->data+t->rindex+5; + t->rindex += 5+length; + return 0; +} int pa_tagstruct_eof(struct pa_tagstruct*t) { assert(t); diff --git a/src/tagstruct.h b/src/tagstruct.h index be4e01fa..2c1ae587 100644 --- a/src/tagstruct.h +++ b/src/tagstruct.h @@ -16,11 +16,13 @@ void pa_tagstruct_puts(struct pa_tagstruct*t, const char *s); void pa_tagstruct_putu32(struct pa_tagstruct*t, uint32_t i); void pa_tagstruct_putu8(struct pa_tagstruct*t, uint8_t c); void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample_spec *ss); +void pa_tagstruct_put_arbitrary(struct pa_tagstruct*t, const void *p, size_t length); int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s); int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i); int pa_tagstruct_getu8(struct pa_tagstruct*t, uint8_t *c); int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec *ss); +int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t length); int pa_tagstruct_eof(struct pa_tagstruct*t); const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l); diff --git a/src/todo b/src/todo index 505eeac2..5b0d893f 100644 --- a/src/todo +++ b/src/todo @@ -3,17 +3,25 @@ sync() function more functions - simple library -- kill() routines in all modules + - config parser/cmdline + - move more stuff from module-oss[-dma] to liboss-util -- svn-id and license in every file - in module-oss: create source first, than sink +- rename files +- svn-id and license in every file +- documentation + + + -- post 0.1 - future cancellation - client-ui - clip cache - autoloading/autounloading +- ldap/rendezvous +- doxygen drivers: - libao diff --git a/src/util.c b/src/util.c index 5fff55e3..4ade681a 100644 --- a/src/util.c +++ b/src/util.c @@ -124,3 +124,87 @@ int pa_make_tcp_socket_low_delay(int fd) { return ret; } + +ssize_t pa_loop_read(int fd, void*data, size_t size) { + ssize_t ret = 0; + assert(fd >= 0 && data && size); + + while (size > 0) { + ssize_t r; + + if ((r = read(fd, data, size)) < 0) + return r; + + if (r == 0) + break; + + ret += r; + data += r; + size -= r; + } + + return ret; +} + +ssize_t pa_loop_write(int fd, const void*data, size_t size) { + ssize_t ret = 0; + assert(fd >= 0 && data && size); + + while (size > 0) { + ssize_t r; + + if ((r = write(fd, data, size)) < 0) + return r; + + if (r == 0) + break; + + ret += r; + data += r; + size -= r; + } + + return ret; +} + +int pa_unix_socket_is_stale(const char *fn) { + struct sockaddr_un sa; + int fd = -1, ret = -1; + + if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "socket(): %s\n", strerror(errno)); + goto finish; + } + + sa.sun_family = AF_LOCAL; + strncpy(sa.sun_path, fn, sizeof(sa.sun_path)-1); + sa.sun_path[sizeof(sa.sun_path) - 1] = 0; + + if (connect(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) { + if (errno == ECONNREFUSED) + ret = 1; + } else + ret = 0; + +finish: + if (fd >= 0) + close(fd); + + return ret; +} + +int pa_unix_socket_remove_stale(const char *fn) { + int r; + + if ((r = pa_unix_socket_is_stale(fn)) < 0) + return errno != ENOENT ? -1 : 0; + + if (!r) + return 0; + + /* Yes, here is a race condition. But who cares? */ + if (unlink(fn) < 0) + return -1; + + return 0; +} diff --git a/src/util.h b/src/util.h index b8759ad8..40095e01 100644 --- a/src/util.h +++ b/src/util.h @@ -12,4 +12,10 @@ int pa_make_secure_dir(const char* dir); int pa_make_socket_low_delay(int fd); int pa_make_tcp_socket_low_delay(int fd); +ssize_t pa_loop_read(int fd, void*data, size_t size); +ssize_t pa_loop_write(int fd, const void*data, size_t size); + +int pa_unix_socket_is_stale(const char *fn); +int pa_unix_socket_remove_stale(const char *fn); + #endif -- cgit From e8d1185c4221fef9d712c1f375d8e592721b6943 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 7 Jul 2004 00:22:46 +0000 Subject: draining ind native protocol fixes in callback code on object destruction simple protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@52 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 12 +- src/client.c | 2 +- src/core.c | 3 + src/iochannel.h | 2 + src/main.c | 17 ++- src/memblockq.c | 67 ++++++--- src/memblockq.h | 22 ++- src/module-cli.c | 4 +- src/module-oss-mmap.c | 2 +- src/module-oss.c | 4 +- src/module-pipe-sink.c | 4 +- src/module-protocol-stub.c | 4 +- src/module.c | 6 +- src/module.h | 4 + src/pacat-simple.c | 8 +- src/pacat.c | 76 +++++++--- src/pdispatch.c | 107 +++++++++---- src/pdispatch.h | 10 +- src/polyp.c | 363 +++++++++++++++++++++++++++++++++------------ src/polyp.h | 9 ++ src/polypdef.h | 5 +- src/protocol-esound.c | 18 ++- src/protocol-native-spec.h | 2 + src/protocol-native.c | 159 +++++++++++++------- src/protocol-simple.c | 20 +-- src/pstream.c | 118 +++++++++------ src/pstream.h | 10 +- src/sample.h | 2 + src/simple.c | 54 ++++--- src/sink.c | 12 +- src/sinkinput.c | 17 ++- src/socket-client.h | 2 + src/socket-server.h | 2 + src/source.c | 6 +- src/sourceoutput.c | 13 +- src/todo | 10 +- src/util.c | 15 +- src/util.h | 2 + 38 files changed, 836 insertions(+), 357 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 70e7e09b..d7002caf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -220,6 +220,7 @@ libpolyp_la_SOURCES = polyp.c polyp.h \ protocol-native-spec.h \ mainloop-api.c mainloop-api.h \ mainloop.c mainloop.h \ + mainloop-signal.c mainloop-signal.h \ idxset.c idxset.h \ util.c util.h \ memblock.c memblock.h \ @@ -237,12 +238,13 @@ libpolyp_error_la_CFLAGS = $(AM_CFLAGS) libpolyp_simple_la_SOURCES = simple.c simple.h libpolyp_simple_la_CFLAGS = $(AM_CFLAGS) -libpolyp_simple_la_LIBADD = libpolyp.la #libpolyp-error.la +libpolyp_simple_la_LIBADD = libpolyp.la +#libpolyp-error.la -pacat_SOURCES = pacat.c #$(libpolyp_la_SOURCES) -pacat_LDADD = libpolyp.la +pacat_SOURCES = pacat.c $(libpolyp_la_SOURCES) $(libpolyp_error_la_SOURCES) +#pacat_LDADD = libpolyp.la pacat_CFLAGS = $(AM_CFLAGS) -pacat_simple_SOURCES = pacat-simple.c -pacat_simple_LDADD = libpolyp-simple.a +pacat_simple_SOURCES = pacat-simple.c $(libpolyp_la_SOURCES) $(libpolyp_simple_la_SOURCES) $(libpolyp_error_la_SOURCES) +#pacat_simple_LDADD = libpolyp-simple.la libpolyp-error.la pacat_simple_CFLAGS = $(AM_CFLAGS) diff --git a/src/client.c b/src/client.c index 7f1648a7..d07f188f 100644 --- a/src/client.c +++ b/src/client.c @@ -59,7 +59,7 @@ char *pa_client_list_to_string(struct pa_core *c) { pa_strbuf_printf(s, "%u client(s).\n", pa_idxset_ncontents(c->clients)); for (client = pa_idxset_first(c->clients, &index); client; client = pa_idxset_next(c->clients, &index)) - pa_strbuf_printf(s, " index: %u, name: <%s>, protocol_name: <%s>\n", client->index, client->name, client->protocol_name); + pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\tprotocol_name: <%s>\n", client->index, client->name, client->protocol_name); return pa_strbuf_tostring_free(s); } diff --git a/src/core.c b/src/core.c index 46159037..a1fe7d97 100644 --- a/src/core.c +++ b/src/core.c @@ -7,6 +7,7 @@ #include "sink.h" #include "source.h" #include "namereg.h" +#include "util.h" struct pa_core* pa_core_new(struct pa_mainloop_api *m) { struct pa_core* c; @@ -24,6 +25,8 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->modules = NULL; c->namereg = NULL; + + pa_check_for_sigpipe(); return c; }; diff --git a/src/iochannel.h b/src/iochannel.h index c550af19..1a5057d6 100644 --- a/src/iochannel.h +++ b/src/iochannel.h @@ -4,6 +4,8 @@ #include #include "mainloop-api.h" +/* It is safe to destroy the calling iochannel object from the callback */ + struct pa_iochannel; struct pa_iochannel* pa_iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd); diff --git a/src/main.c b/src/main.c index 88552fed..c7a83fec 100644 --- a/src/main.c +++ b/src/main.c @@ -12,10 +12,16 @@ static struct pa_mainloop *mainloop; -static void signal_callback(void *id, int sig, void *userdata) { +static void exit_signal_callback(void *id, int sig, void *userdata) { struct pa_mainloop_api* m = pa_mainloop_get_api(mainloop); m->quit(m, 1); - fprintf(stderr, "main: got signal.\n"); + fprintf(stderr, __FILE__": got signal.\n"); +} + +static void aux_signal_callback(void *id, int sig, void *userdata) { + struct pa_core *c = userdata; + assert(c); + pa_module_load(c, sig == SIGUSR1 ? "module-cli" : "module-cli-protocol-unix", NULL); } int main(int argc, char *argv[]) { @@ -30,12 +36,12 @@ int main(int argc, char *argv[]) { r = pa_signal_init(pa_mainloop_get_api(mainloop)); assert(r == 0); - pa_signal_register(SIGINT, signal_callback, NULL); + pa_signal_register(SIGINT, exit_signal_callback, NULL); signal(SIGPIPE, SIG_IGN); c = pa_core_new(pa_mainloop_get_api(mainloop)); assert(c); - + pa_module_load(c, "module-oss", "/dev/dsp"); /* pa_module_load(c, "module-pipe-sink", NULL);*/ pa_module_load(c, "module-simple-protocol-tcp", NULL); @@ -46,6 +52,9 @@ int main(int argc, char *argv[]) { 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_signal_register(SIGUSR1, aux_signal_callback, c); + pa_signal_register(SIGUSR2, aux_signal_callback, c); fprintf(stderr, "main: mainloop entry.\n"); if (pa_mainloop_run(mainloop, &retval) < 0) diff --git a/src/memblockq.c b/src/memblockq.c index b70a67ff..e5dab687 100644 --- a/src/memblockq.c +++ b/src/memblockq.c @@ -15,30 +15,45 @@ struct memblock_list { struct pa_memblockq { struct memblock_list *blocks, *blocks_tail; unsigned n_blocks; - size_t total_length, maxlength, base, prebuf; + size_t current_length, maxlength, tlength, base, prebuf, minreq; int measure_delay; uint32_t delay; struct pa_mcalign *mcalign; }; -struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t base, size_t prebuf) { +struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t base, size_t prebuf, size_t minreq) { struct pa_memblockq* bq; - assert(maxlength && base); + assert(maxlength && base && maxlength); bq = malloc(sizeof(struct pa_memblockq)); assert(bq); bq->blocks = bq->blocks_tail = 0; bq->n_blocks = 0; - bq->total_length = 0; + + bq->current_length = 0; + + fprintf(stderr, "memblockq requested: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", maxlength, tlength, base, prebuf, minreq); + bq->base = base; + bq->maxlength = ((maxlength+base-1)/base)*base; - bq->prebuf = prebuf == (size_t) -1 ? bq->maxlength/2 : prebuf; + assert(bq->maxlength >= base); + + bq->tlength = ((tlength+base-1)/base)*base; + if (bq->tlength == 0 || bq->tlength >= bq->maxlength) + bq->tlength = bq->maxlength; + bq->prebuf = (prebuf == (size_t) -1) ? bq->maxlength/2 : prebuf; + bq->prebuf = (bq->prebuf/base)*base; if (bq->prebuf > bq->maxlength) bq->prebuf = bq->maxlength; - assert(bq->maxlength >= base); + bq->minreq = (minreq/base)*base; + if (bq->minreq == 0) + bq->minreq = 1; + fprintf(stderr, "memblockq sanitized: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", bq->maxlength, bq->tlength, bq->base, bq->prebuf, bq->minreq); + bq->measure_delay = 0; bq->delay = 0; @@ -88,7 +103,7 @@ void pa_memblockq_push(struct pa_memblockq* bq, const struct pa_memchunk *chunk, bq->blocks_tail = q; bq->n_blocks++; - bq->total_length += chunk->length; + bq->current_length += chunk->length; pa_memblockq_shorten(bq, bq->maxlength); } @@ -96,7 +111,7 @@ void pa_memblockq_push(struct pa_memblockq* bq, const struct pa_memchunk *chunk, int pa_memblockq_peek(struct pa_memblockq* bq, struct pa_memchunk *chunk) { assert(bq && chunk); - if (!bq->blocks || bq->total_length < bq->prebuf) + if (!bq->blocks || bq->current_length < bq->prebuf) return -1; bq->prebuf = 0; @@ -116,7 +131,7 @@ int memblockq_pop(struct memblockq* bq, struct pa_memchunk *chunk) { assert(bq && chunk); - if (!bq->blocks || bq->total_length < bq->prebuf) + if (!bq->blocks || bq->current_length < bq->prebuf) return -1; bq->prebuf = 0; @@ -127,7 +142,7 @@ int memblockq_pop(struct memblockq* bq, struct pa_memchunk *chunk) { *chunk = q->chunk; bq->n_blocks--; - bq->total_length -= chunk->length; + bq->current_length -= chunk->length; free(q); return 0; @@ -159,7 +174,7 @@ void pa_memblockq_drop(struct pa_memblockq *bq, size_t length) { while (length > 0) { size_t l = length; - assert(bq->blocks && bq->total_length >= length); + assert(bq->blocks && bq->current_length >= length); if (l > bq->blocks->chunk.length) l = bq->blocks->chunk.length; @@ -169,7 +184,7 @@ void pa_memblockq_drop(struct pa_memblockq *bq, size_t length) { bq->blocks->chunk.index += l; bq->blocks->chunk.length -= l; - bq->total_length -= l; + bq->current_length -= l; if (bq->blocks->chunk.length == 0) { struct memblock_list *q; @@ -192,12 +207,12 @@ void pa_memblockq_shorten(struct pa_memblockq *bq, size_t length) { size_t l; assert(bq); - if (bq->total_length <= length) + if (bq->current_length <= length) return; fprintf(stderr, "Warning! pa_memblockq_shorten()\n"); - l = bq->total_length - length; + l = bq->current_length - length; l /= bq->base; l *= bq->base; @@ -213,14 +228,13 @@ void pa_memblockq_empty(struct pa_memblockq *bq) { int pa_memblockq_is_readable(struct pa_memblockq *bq) { assert(bq); - return bq->total_length >= bq->prebuf; + return bq->current_length >= bq->prebuf; } int pa_memblockq_is_writable(struct pa_memblockq *bq, size_t length) { assert(bq); - assert(length <= bq->maxlength); - return bq->total_length + length <= bq->maxlength; + return bq->current_length + length <= bq->tlength; } uint32_t pa_memblockq_get_delay(struct pa_memblockq *bq) { @@ -230,16 +244,20 @@ uint32_t pa_memblockq_get_delay(struct pa_memblockq *bq) { uint32_t pa_memblockq_get_length(struct pa_memblockq *bq) { assert(bq); - return bq->total_length; + return bq->current_length; } -uint32_t pa_memblockq_missing_to(struct pa_memblockq *bq, size_t qlen) { - assert(bq && qlen); +uint32_t pa_memblockq_missing(struct pa_memblockq *bq) { + size_t l; + assert(bq); - if (bq->total_length >= qlen) + if (bq->current_length >= bq->tlength) return 0; - return qlen - bq->total_length; + l = bq->tlength - bq->current_length; + assert(l); + + return (l >= bq->minreq) ? l : 0; } void pa_memblockq_push_align(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta) { @@ -264,3 +282,8 @@ void pa_memblockq_push_align(struct pa_memblockq* bq, const struct pa_memchunk * delta = 0; } } + +uint32_t pa_memblockq_get_minreq(struct pa_memblockq *bq) { + assert(bq); + return bq->minreq; +} diff --git a/src/memblockq.h b/src/memblockq.h index d8b9567f..bece4fd7 100644 --- a/src/memblockq.h +++ b/src/memblockq.h @@ -8,11 +8,18 @@ struct pa_memblockq; -/* Parameters: the maximum length of the memblock queue, a base value -for all operations (that is, all byte operations shall work on -multiples of this base value) and an amount of bytes to prebuffer -before having pa_memblockq_peek() succeed. */ -struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t base, size_t prebuf); +/* Parameters: + - maxlength: maximum length of queue. If more data is pushed into the queue, data from the front is dropped + - length: the target length of the queue. + - base: a base value for all metrics. Only multiples of this value are popped from the queue + - prebuf: before passing the first byte out, make sure that enough bytes are in the queue + - minreq: pa_memblockq_missing() will only return values greater than this value +*/ +struct pa_memblockq* pa_memblockq_new(size_t maxlength, + size_t tlength, + size_t base, + size_t prebuf, + size_t minreq); void pa_memblockq_free(struct pa_memblockq*bq); /* Push a new memory chunk into the queue. Optionally specify a value for future cancellation. This is currently not implemented, however! */ @@ -46,6 +53,9 @@ uint32_t pa_memblockq_get_delay(struct pa_memblockq *bq); uint32_t pa_memblockq_get_length(struct pa_memblockq *bq); /* Return how many bytes are missing in queue to the specified fill amount */ -uint32_t pa_memblockq_missing_to(struct pa_memblockq *bq, size_t qlen); +uint32_t pa_memblockq_missing(struct pa_memblockq *bq); + + +uint32_t pa_memblockq_get_minreq(struct pa_memblockq *bq); #endif diff --git a/src/module-cli.c b/src/module-cli.c index 7306ade5..a6e9582d 100644 --- a/src/module-cli.c +++ b/src/module-cli.c @@ -14,7 +14,7 @@ static void eof_cb(struct pa_cli*c, void *userdata) { pa_module_unload_request(m->core, m); } -int module_init(struct pa_core *c, struct pa_module*m) { +int pa_module_init(struct pa_core *c, struct pa_module*m) { struct pa_iochannel *io; assert(c && m); @@ -35,7 +35,7 @@ int module_init(struct pa_core *c, struct pa_module*m) { return 0; } -void module_done(struct pa_core *c, struct pa_module*m) { +void pa_module_done(struct pa_core *c, struct pa_module*m) { assert(c && m); pa_cli_free(m->userdata); diff --git a/src/module-oss-mmap.c b/src/module-oss-mmap.c index ef2b19d0..62c2cc2a 100644 --- a/src/module-oss-mmap.c +++ b/src/module-oss-mmap.c @@ -180,7 +180,7 @@ static uint32_t sink_get_latency_cb(struct pa_sink *s) { return pa_samples_usec(u->out_fill, &s->sample_spec); } -int module_init(struct pa_core *c, struct pa_module*m) { +int pa_module_init(struct pa_core *c, struct pa_module*m) { struct audio_buf_info info; struct userdata *u = NULL; char *p; diff --git a/src/module-oss.c b/src/module-oss.c index 310c89c0..5ec9d2d7 100644 --- a/src/module-oss.c +++ b/src/module-oss.c @@ -111,7 +111,7 @@ static uint32_t sink_get_latency_cb(struct pa_sink *s) { return pa_samples_usec(arg, &s->sample_spec); } -int module_init(struct pa_core *c, struct pa_module*m) { +int pa_module_init(struct pa_core *c, struct pa_module*m) { struct audio_buf_info info; struct userdata *u = NULL; char *p; @@ -224,7 +224,7 @@ fail: return -1; } -void module_done(struct pa_core *c, struct pa_module*m) { +void pa_module_done(struct pa_core *c, struct pa_module*m) { struct userdata *u; assert(c && m); diff --git a/src/module-pipe-sink.c b/src/module-pipe-sink.c index ea5c15db..efba3b5f 100644 --- a/src/module-pipe-sink.c +++ b/src/module-pipe-sink.c @@ -73,7 +73,7 @@ static void io_callback(struct pa_iochannel *io, void*userdata) { do_write(u); } -int module_init(struct pa_core *c, struct pa_module*m) { +int pa_module_init(struct pa_core *c, struct pa_module*m) { struct userdata *u = NULL; struct stat st; char *p; @@ -137,7 +137,7 @@ fail: return -1; } -void module_done(struct pa_core *c, struct pa_module*m) { +void pa_module_done(struct pa_core *c, struct pa_module*m) { struct userdata *u; assert(c && m); diff --git a/src/module-protocol-stub.c b/src/module-protocol-stub.c index 713e0ab8..885ea4c8 100644 --- a/src/module-protocol-stub.c +++ b/src/module-protocol-stub.c @@ -47,7 +47,7 @@ #endif #endif -int module_init(struct pa_core *c, struct pa_module*m) { +int pa_module_init(struct pa_core *c, struct pa_module*m) { struct pa_socket_server *s; assert(c && m); @@ -91,7 +91,7 @@ int module_init(struct pa_core *c, struct pa_module*m) { return 0; } -void module_done(struct pa_core *c, struct pa_module*m) { +void pa_module_done(struct pa_core *c, struct pa_module*m) { assert(c && m); protocol_free(m->userdata); diff --git a/src/module.c b/src/module.c index 468998ba..87df3b38 100644 --- a/src/module.c +++ b/src/module.c @@ -23,10 +23,10 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char if (!(m->dl = lt_dlopenext(name))) goto fail; - if (!(m->init = lt_dlsym(m->dl, "module_init"))) + if (!(m->init = lt_dlsym(m->dl, "pa_module_init"))) goto fail; - if (!(m->done = lt_dlsym(m->dl, "module_done"))) + if (!(m->done = lt_dlsym(m->dl, "pa_module_done"))) goto fail; m->userdata = NULL; @@ -124,7 +124,7 @@ char *pa_module_list_to_string(struct pa_core *c) { pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_ncontents(c->modules)); for (m = pa_idxset_first(c->modules, &index); m; m = pa_idxset_next(c->modules, &index)) - pa_strbuf_printf(s, " index: %u, name: <%s>, argument: <%s>\n", m->index, m->name, m->argument); + pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\targument: <%s>\n", m->index, m->name, m->argument); return pa_strbuf_tostring_free(s); } diff --git a/src/module.h b/src/module.h index 1cc7d775..2a9cf558 100644 --- a/src/module.h +++ b/src/module.h @@ -30,4 +30,8 @@ char *pa_module_list_to_string(struct pa_core *c); void pa_module_unload_request(struct pa_core *c, struct pa_module *m); +/* These to following prototypes are for module entrypoints and not implemented by the core */ +int pa_module_init(struct pa_core *c, struct pa_module*m); +void pa_module_done(struct pa_core *c, struct pa_module*m); + #endif diff --git a/src/pacat-simple.c b/src/pacat-simple.c index 5408221c..8b48bdd3 100644 --- a/src/pacat-simple.c +++ b/src/pacat-simple.c @@ -19,7 +19,7 @@ int main(int argc, char*argv[]) { int error; if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, &error))) { - fprintf(stderr, "Failed to connect to server: %s\n", pa_strerror(error)); + fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); goto finish; } @@ -31,16 +31,16 @@ int main(int argc, char*argv[]) { if (r == 0) /* eof */ break; - fprintf(stderr, "read() failed: %s\n", strerror(errno)); + fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno)); goto finish; } if (pa_simple_write(s, buf, r, &error) < 0) { - fprintf(stderr, "Failed to write data: %s\n", pa_strerror(error)); + fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error)); goto finish; } } - + ret = 0; finish: diff --git a/src/pacat.c b/src/pacat.c index c69148e6..75a94fc0 100644 --- a/src/pacat.c +++ b/src/pacat.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -6,7 +7,9 @@ #include #include "polyp.h" +#include "polyp-error.h" #include "mainloop.h" +#include "mainloop-signal.h" static struct pa_context *context = NULL; static struct pa_stream *stream = NULL; @@ -17,21 +20,29 @@ static size_t buffer_length = 0, buffer_index = 0; static void* stdin_source = NULL; +static void quit(int ret) { + assert(mainloop_api); + mainloop_api->quit(mainloop_api, ret); +} + static void context_die_callback(struct pa_context *c, void *userdata) { assert(c); fprintf(stderr, "Connection to server shut down, exiting.\n"); - mainloop_api->quit(mainloop_api, 1); + quit(1); } static void stream_die_callback(struct pa_stream *s, void *userdata) { assert(s); fprintf(stderr, "Stream deleted, exiting.\n"); - mainloop_api->quit(mainloop_api, 1); + quit(1); } static void do_write(size_t length) { size_t l; - assert(buffer && buffer_length); + assert(length); + + if (!buffer || !buffer_length) + return; l = length; if (l > buffer_length) @@ -50,8 +61,9 @@ static void do_write(size_t length) { static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) { assert(s && length); - - mainloop_api->enable_io(mainloop_api, stdin_source, PA_MAINLOOP_API_IO_EVENT_INPUT); + + if (stdin_source) + mainloop_api->enable_io(mainloop_api, stdin_source, PA_MAINLOOP_API_IO_EVENT_INPUT); if (!buffer) return; @@ -63,13 +75,12 @@ static void stream_complete_callback(struct pa_stream*s, int success, void *user assert(s); if (!success) { - fprintf(stderr, "Stream creation failed.\n"); - mainloop_api->quit(mainloop_api, 1); + fprintf(stderr, "Stream creation failed: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + quit(1); return; } - pa_stream_set_die_callback(s, stream_die_callback, NULL); - pa_stream_set_write_callback(s, stream_write_callback, NULL); + fprintf(stderr, "Stream created.\n"); } static void context_complete_callback(struct pa_context *c, int success, void *userdata) { @@ -82,43 +93,59 @@ static void context_complete_callback(struct pa_context *c, int success, void *u assert(c && !stream); if (!success) { - fprintf(stderr, "Connection failed\n"); + fprintf(stderr, "Connection failed: %s\n", pa_strerror(pa_context_errno(c))); goto fail; } + + fprintf(stderr, "Connection established.\n"); if (!(stream = pa_stream_new(c, PA_STREAM_PLAYBACK, NULL, "pacat", &ss, NULL, stream_complete_callback, NULL))) { - fprintf(stderr, "pa_stream_new() failed.\n"); + fprintf(stderr, "pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(c))); goto fail; } + pa_stream_set_die_callback(stream, stream_die_callback, NULL); + pa_stream_set_write_callback(stream, stream_write_callback, NULL); + return; fail: - mainloop_api->quit(mainloop_api, 1); + quit(1); +} + +static void context_drain_complete(struct pa_context*c, void *userdata) { + quit(0); } static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { size_t l, w = 0; ssize_t r; - assert(a == mainloop_api && id && fd == STDIN_FILENO && events == PA_MAINLOOP_API_IO_EVENT_INPUT); + assert(a == mainloop_api && id && fd == STDIN_FILENO && events == PA_MAINLOOP_API_IO_EVENT_INPUT && stdin_source == id); if (buffer) { mainloop_api->enable_io(mainloop_api, stdin_source, PA_MAINLOOP_API_IO_EVENT_NULL); return; } - if (!stream || !(l = w = pa_stream_writable_size(stream))) + if (!stream || !pa_stream_is_ready(stream) || !(l = w = pa_stream_writable_size(stream))) l = 4096; + buffer = malloc(l); assert(buffer); if ((r = read(fd, buffer, l)) <= 0) { - if (r == 0) - mainloop_api->quit(mainloop_api, 0); - else { + if (r == 0) { + fprintf(stderr, "Got EOF.\n"); + if (pa_context_drain(context, context_drain_complete, NULL) < 0) + quit(0); + else + fprintf(stderr, "Draining connection to server.\n"); + } else { fprintf(stderr, "read() failed: %s\n", strerror(errno)); - mainloop_api->quit(mainloop_api, 1); + quit(1); } + mainloop_api->cancel_io(mainloop_api, stdin_source); + stdin_source = NULL; return; } @@ -129,9 +156,15 @@ static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_m do_write(w); } + +static void exit_signal_callback(void *id, int sig, void *userdata) { + fprintf(stderr, "Got SIGINT, exiting.\n"); + quit(0); +} + int main(int argc, char *argv[]) { struct pa_mainloop* m; - int ret = 1; + int ret = 1, r; if (!(m = pa_mainloop_new())) { fprintf(stderr, "pa_mainloop_new() failed.\n"); @@ -140,6 +173,11 @@ int main(int argc, char *argv[]) { mainloop_api = pa_mainloop_get_api(m); + r = pa_signal_init(mainloop_api); + assert(r == 0); + pa_signal_register(SIGINT, exit_signal_callback, NULL); + signal(SIGPIPE, SIG_IGN); + if (!(stdin_source = mainloop_api->source_io(mainloop_api, STDIN_FILENO, PA_MAINLOOP_API_IO_EVENT_INPUT, stdin_callback, NULL))) { fprintf(stderr, "source_io() failed.\n"); goto quit; diff --git a/src/pdispatch.c b/src/pdispatch.c index c2db134d..ec454190 100644 --- a/src/pdispatch.c +++ b/src/pdispatch.c @@ -4,10 +4,26 @@ #include "pdispatch.h" #include "protocol-native-spec.h" +static const char *command_names[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = "ERROR", + [PA_COMMAND_TIMEOUT] = "TIMEOUT", + [PA_COMMAND_REPLY] = "REPLY", + [PA_COMMAND_CREATE_PLAYBACK_STREAM] = "CREATE_PLAYBACK_STREAM", + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = "DELETE_PLAYBACK_STREAM", + [PA_COMMAND_CREATE_RECORD_STREAM] = "CREATE_RECORD_STREAM", + [PA_COMMAND_DELETE_RECORD_STREAM] = "DELETE_RECORD_STREAM", + [PA_COMMAND_AUTH] = "AUTH", + [PA_COMMAND_REQUEST] = "REQUEST", + [PA_COMMAND_EXIT] = "EXIT", + [PA_COMMAND_SET_NAME] = "SET_NAME", + [PA_COMMAND_LOOKUP_SINK] = "LOOKUP_SINK", + [PA_COMMAND_LOOKUP_SOURCE] = "LOOKUP_SOURCE", +}; + struct reply_info { struct pa_pdispatch *pdispatch; struct reply_info *next, *previous; - int (*callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); + void (*callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); void *userdata; uint32_t tag; void *mainloop_timeout; @@ -18,6 +34,9 @@ struct pa_pdispatch { const struct pa_pdispatch_command *command_table; unsigned n_commands; struct reply_info *replies; + void (*drain_callback)(struct pa_pdispatch *pd, void *userdata); + void *drain_userdata; + int in_use, shall_free; }; static void reply_info_free(struct reply_info *r) { @@ -49,11 +68,21 @@ struct pa_pdispatch* pa_pdispatch_new(struct pa_mainloop_api *mainloop, const st pd->command_table = table; pd->n_commands = entries; pd->replies = NULL; + pd->drain_callback = NULL; + pd->drain_userdata = NULL; + + pd->in_use = pd->shall_free = 0; return pd; } void pa_pdispatch_free(struct pa_pdispatch *pd) { assert(pd); + + if (pd->in_use) { + pd->shall_free = 1; + return; + } + while (pd->replies) reply_info_free(pd->replies); free(pd); @@ -61,60 +90,61 @@ void pa_pdispatch_free(struct pa_pdispatch *pd) { int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *userdata) { uint32_t tag, command; - assert(pd && packet); struct pa_tagstruct *ts = NULL; - assert(pd && packet && packet->data); + int ret = -1; + assert(pd && packet && packet->data && !pd->in_use); if (packet->length <= 8) - goto fail; + goto finish; ts = pa_tagstruct_new(packet->data, packet->length); assert(ts); if (pa_tagstruct_getu32(ts, &command) < 0 || pa_tagstruct_getu32(ts, &tag) < 0) - goto fail; + goto finish; + + /*fprintf(stderr, __FILE__": Recieved opcode <%s>\n", command_names[command]);*/ if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) { struct reply_info *r; - int done = 0; for (r = pd->replies; r; r = r->next) { - if (r->tag == tag) { - int ret = r->callback(r->pdispatch, command, tag, ts, r->userdata); - reply_info_free(r); - - if (ret < 0) - goto fail; - - done = 1; + if (r->tag != tag) + continue; + + pd->in_use = 1; + assert(r->callback); + r->callback(r->pdispatch, command, tag, ts, r->userdata); + pd->in_use = 0; + reply_info_free(r); + + if (pd->shall_free) { + pa_pdispatch_free(pd); break; } - } - if (!done) - goto fail; + if (pd->drain_callback && !pa_pdispatch_is_pending(r->pdispatch)) + pd->drain_callback(r->pdispatch, r->pdispatch->drain_userdata); + + break; + } } else if (pd->command_table && command < pd->n_commands) { const struct pa_pdispatch_command *c = pd->command_table+command; - if (!c->proc) - goto fail; - - if (c->proc(pd, command, tag, ts, userdata) < 0) - goto fail; + if (c->proc) + c->proc(pd, command, tag, ts, userdata); } else - goto fail; - - pa_tagstruct_free(ts); - - return 0; + goto finish; -fail: + ret = 0; + +finish: if (ts) pa_tagstruct_free(ts); - return -1; + return ret; } static void timeout_callback(struct pa_mainloop_api*m, void *id, const struct timeval *tv, void *userdata) { @@ -123,9 +153,12 @@ static void timeout_callback(struct pa_mainloop_api*m, void *id, const struct ti r->callback(r->pdispatch, PA_COMMAND_TIMEOUT, r->tag, NULL, r->userdata); reply_info_free(r); + + if (r->pdispatch->drain_callback && !pa_pdispatch_is_pending(r->pdispatch)) + r->pdispatch->drain_callback(r->pdispatch, r->pdispatch->drain_userdata); } -void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int timeout, int (*cb)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void *userdata) { +void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int timeout, void (*cb)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void *userdata) { struct reply_info *r; struct timeval tv; assert(pd && cb); @@ -149,3 +182,17 @@ void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int time r->next->previous = r; pd->replies = r; } + +int pa_pdispatch_is_pending(struct pa_pdispatch *pd) { + assert(pd); + + return !!pd->replies; +} + +void pa_pdispatch_set_drain_callback(struct pa_pdispatch *pd, void (*cb)(struct pa_pdispatch *pd, void *userdata), void *userdata) { + assert(pd); + assert(!cb || pa_pdispatch_is_pending(pd)); + + pd->drain_callback = cb; + pd->drain_userdata = userdata; +} diff --git a/src/pdispatch.h b/src/pdispatch.h index 73686700..35e93829 100644 --- a/src/pdispatch.h +++ b/src/pdispatch.h @@ -8,8 +8,10 @@ struct pa_pdispatch; +/* It is safe to destroy the calling pdispatch object from all callbacks */ + struct pa_pdispatch_command { - int (*proc)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); + void (*proc)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); }; struct pa_pdispatch* pa_pdispatch_new(struct pa_mainloop_api *m, const struct pa_pdispatch_command*table, unsigned entries); @@ -17,6 +19,10 @@ void pa_pdispatch_free(struct pa_pdispatch *pd); int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*p, void *userdata); -void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int timeout, int (*cb)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void *userdata); +void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int timeout, void (*cb)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void *userdata); + +int pa_pdispatch_is_pending(struct pa_pdispatch *pd); + +void pa_pdispatch_set_drain_callback(struct pa_pdispatch *pd, void (*cb)(struct pa_pdispatch *pd, void *userdata), void *userdata); #endif diff --git a/src/polyp.c b/src/polyp.c index c15d5d9f..9af8d468 100644 --- a/src/polyp.c +++ b/src/polyp.c @@ -11,10 +11,13 @@ #include "socket-client.h" #include "pstream-util.h" #include "authkey.h" +#include "util.h" -#define DEFAULT_QUEUE_LENGTH 10240 -#define DEFAULT_MAX_LENGTH 20480 +#define DEFAULT_MAXLENGTH 20480 +#define DEFAULT_TLENGTH 10240 #define DEFAULT_PREBUF 4096 +#define DEFAULT_MINREQ 1024 + #define DEFAULT_TIMEOUT (5*60) #define DEFAULT_SERVER "/tmp/polypaudio/native" @@ -28,25 +31,40 @@ struct pa_context { struct pa_stream *first_stream; uint32_t ctag; uint32_t error; - enum { CONTEXT_UNCONNECTED, CONTEXT_CONNECTING, CONTEXT_AUTHORIZING, CONTEXT_SETTING_NAME, CONTEXT_READY, CONTEXT_DEAD} state; + enum { + CONTEXT_UNCONNECTED, + CONTEXT_CONNECTING, + CONTEXT_AUTHORIZING, + CONTEXT_SETTING_NAME, + CONTEXT_READY, + CONTEXT_DEAD + } state; void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); void *connect_complete_userdata; + void (*drain_complete_callback)(struct pa_context*c, void *userdata); + void *drain_complete_userdata; + void (*die_callback)(struct pa_context*c, void *userdata); void *die_userdata; - + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; }; struct pa_stream { struct pa_context *context; struct pa_stream *next, *previous; + + char *name; + struct pa_buffer_attr buffer_attr; + struct pa_sample_spec sample_spec; uint32_t device_index; uint32_t channel; int channel_valid; enum pa_stream_direction direction; - enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; + + enum { STREAM_LOOKING_UP, STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; uint32_t requested_bytes; void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); @@ -62,7 +80,7 @@ struct pa_stream { void *die_userdata; }; -static int command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = { NULL }, @@ -76,8 +94,9 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { }; struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { - assert(mainloop && name); struct pa_context *c; + assert(mainloop && name); + c = malloc(sizeof(struct pa_context)); assert(c); c->name = strdup(name); @@ -95,9 +114,13 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * c->connect_complete_callback = NULL; c->connect_complete_userdata = NULL; + c->drain_complete_callback = NULL; + c->drain_complete_userdata = NULL; + c->die_callback = NULL; c->die_userdata = NULL; - + + pa_check_for_sigpipe(); return c; } @@ -121,84 +144,105 @@ void pa_context_free(struct pa_context *c) { } static void stream_dead(struct pa_stream *s) { + assert(s); + if (s->state == STREAM_DEAD) return; - - s->state = STREAM_DEAD; - if (s->die_callback) - s->die_callback(s, s->die_userdata); + + if (s->state == STREAM_READY) { + s->state = STREAM_DEAD; + if (s->die_callback) + s->die_callback(s, s->die_userdata); + } else + s->state = STREAM_DEAD; } static void context_dead(struct pa_context *c) { struct pa_stream *s; assert(c); - for (s = c->first_stream; s; s = s->next) - stream_dead(s); - if (c->state == CONTEXT_DEAD) return; + + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + c->pdispatch = NULL; + + if (c->pstream) + pa_pstream_free(c->pstream); + c->pstream = NULL; + + if (c->client) + pa_socket_client_free(c->client); + c->client = NULL; - c->state = CONTEXT_DEAD; - if (c->die_callback) - c->die_callback(c, c->die_userdata); + for (s = c->first_stream; s; s = s->next) + stream_dead(s); + + if (c->state == CONTEXT_READY) { + c->state = CONTEXT_DEAD; + if (c->die_callback) + c->die_callback(c, c->die_userdata); + } else + s->state = CONTEXT_DEAD; } static void pstream_die_callback(struct pa_pstream *p, void *userdata) { struct pa_context *c = userdata; assert(p && c); - - assert(c->state != CONTEXT_DEAD); - - c->state = CONTEXT_DEAD; - context_dead(c); } -static int pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { +static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { struct pa_context *c = userdata; assert(p && packet && c); if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { fprintf(stderr, "polyp.c: invalid packet.\n"); context_dead(c); - return -1; } - - - return 0; } -static int pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata) { +static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata) { struct pa_context *c = userdata; struct pa_stream *s; assert(p && chunk && c && chunk->memblock && chunk->memblock->data); if (!(s = pa_dynarray_get(c->streams, channel))) - return 0; + return; if (s->read_callback) s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); +} + +static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { + assert(c && t); - return 0; + if (command == PA_COMMAND_ERROR) { + if (pa_tagstruct_getu32(t, &c->error) < 0) { + c->error = PA_ERROR_PROTOCOL; + return -1; + } + + return 0; + } + + c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; + return -1; } -static int auth_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_context *c = userdata; assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); if (command != PA_COMMAND_REPLY) { - if (command == PA_COMMAND_ERROR && pa_tagstruct_getu32(t, &c->error) < 0) - c->error = PA_ERROR_PROTOCOL; - else if (command == PA_COMMAND_TIMEOUT) - c->error = PA_ERROR_TIMEOUT; - - c->state = CONTEXT_DEAD; + handle_error(c, command, t); + context_dead(c); if (c->connect_complete_callback) c->connect_complete_callback(c, 0, c->connect_complete_userdata); - return -1; + return; } if (c->state == CONTEXT_AUTHORIZING) { @@ -210,7 +254,7 @@ static int auth_complete_callback(struct pa_pdispatch *pd, uint32_t command, uin pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_puts(t, c->name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, auth_complete_callback, c); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); } else { assert(c->state == CONTEXT_SETTING_NAME); @@ -220,7 +264,7 @@ static int auth_complete_callback(struct pa_pdispatch *pd, uint32_t command, uin c->connect_complete_callback(c, 1, c->connect_complete_userdata); } - return 0; + return; } static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { @@ -234,7 +278,7 @@ static void on_connection(struct pa_socket_client *client, struct pa_iochannel*i if (!io) { c->error = PA_ERROR_CONNECTIONREFUSED; - c->state = CONTEXT_UNCONNECTED; + context_dead(c); if (c->connect_complete_callback) c->connect_complete_callback(c, 0, c->connect_complete_userdata); @@ -257,7 +301,7 @@ static void on_connection(struct pa_socket_client *client, struct pa_iochannel*i pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, auth_complete_callback, c); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); c->state = CONTEXT_AUTHORIZING; } @@ -305,7 +349,7 @@ void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_cont c->die_userdata = userdata; } -static int command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_stream *s; struct pa_context *c = userdata; uint32_t bytes, channel; @@ -315,63 +359,122 @@ static int command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t t pa_tagstruct_getu32(t, &bytes) < 0 || !pa_tagstruct_eof(t)) { c->error = PA_ERROR_PROTOCOL; - return -1; + context_dead(c); + return; } - if (!(s = pa_dynarray_get(c->streams, channel))) { - c->error = PA_ERROR_PROTOCOL; - return -1; - } + if (!(s = pa_dynarray_get(c->streams, channel))) + return; - /*fprintf(stderr, "Requested %u bytes\n", bytes);*/ + if (s->state != STREAM_READY) + return; s->requested_bytes += bytes; if (s->requested_bytes && s->write_callback) s->write_callback(s, s->requested_bytes, s->write_userdata); - - return 0; } -static int create_playback_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - int ret = 0; +static void create_playback_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_stream *s = userdata; assert(pd && s && s->state == STREAM_CREATING); if (command != PA_COMMAND_REPLY) { - struct pa_context *c = s->context; - assert(c); + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } - if (command == PA_COMMAND_ERROR && pa_tagstruct_getu32(t, &s->context->error) < 0) - s->context->error = PA_ERROR_PROTOCOL; - else if (command == PA_COMMAND_TIMEOUT) - s->context->error = PA_ERROR_TIMEOUT; - - ret = -1; - goto fail; + stream_dead(s); + if (s->create_complete_callback) + s->create_complete_callback(s, 0, s->create_complete_userdata); + + return; } if (pa_tagstruct_getu32(t, &s->channel) < 0 || pa_tagstruct_getu32(t, &s->device_index) < 0 || !pa_tagstruct_eof(t)) { s->context->error = PA_ERROR_PROTOCOL; - ret = -1; - goto fail; + context_dead(s->context); + return; } s->channel_valid = 1; pa_dynarray_put(s->context->streams, s->channel, s); s->state = STREAM_READY; - assert(s->create_complete_callback); - s->create_complete_callback(s, 1, s->create_complete_userdata); - return 0; + if (s->create_complete_callback) + s->create_complete_callback(s, 1, s->create_complete_userdata); +} + +static void create_stream(struct pa_stream *s, uint32_t tdev_index) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s); -fail: - assert(s->create_complete_callback); - s->create_complete_callback(s, 0, s->create_complete_userdata); - pa_stream_free(s); - return ret; + s->state = STREAM_CREATING; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_puts(t, s->name); + pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_putu32(t, tdev_index); + pa_tagstruct_putu32(t, s->buffer_attr.maxlength); + pa_tagstruct_putu32(t, s->buffer_attr.tlength); + pa_tagstruct_putu32(t, s->buffer_attr.prebuf); + pa_tagstruct_putu32(t, s->buffer_attr.minreq); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_playback_callback, s); +} + +static void lookup_device_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + uint32_t tdev; + assert(pd && s && s->state == STREAM_LOOKING_UP); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + if (s->create_complete_callback) + s->create_complete_callback(s, 0, s->create_complete_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &tdev) < 0 || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + create_stream(s, tdev); +} + +static void lookup_device(struct pa_stream *s, const char *tdev) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s); + + s->state = STREAM_LOOKING_UP; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_LOOKUP_SINK : PA_COMMAND_LOOKUP_SOURCE); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_puts(t, tdev); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, lookup_device_callback, s); } struct pa_stream* pa_stream_new( @@ -385,10 +488,8 @@ struct pa_stream* pa_stream_new( void *userdata) { struct pa_stream *s; - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name && ss && c->state == CONTEXT_READY && complete); + assert(c && name && ss && c->state == CONTEXT_READY); s = malloc(sizeof(struct pa_stream)); assert(s); @@ -403,42 +504,43 @@ struct pa_stream* pa_stream_new( s->create_complete_callback = complete; s->create_complete_userdata = NULL; + s->name = strdup(name); s->state = STREAM_CREATING; s->requested_bytes = 0; s->channel = 0; s->channel_valid = 0; s->device_index = (uint32_t) -1; s->direction = dir; + s->sample_spec = *ss; + if (attr) + s->buffer_attr = *attr; + else { + s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; + s->buffer_attr.tlength = DEFAULT_TLENGTH; + s->buffer_attr.prebuf = DEFAULT_PREBUF; + s->buffer_attr.minreq = DEFAULT_MINREQ; + } - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, dir == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_sample_spec(t, ss); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_putu32(t, attr ? attr->queue_length : DEFAULT_QUEUE_LENGTH); - pa_tagstruct_putu32(t, attr ? attr->max_length : DEFAULT_MAX_LENGTH); - pa_tagstruct_putu32(t, attr ? attr->prebuf : DEFAULT_PREBUF); - - pa_pstream_send_tagstruct(c->pstream, t); - - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_playback_callback, s); - s->next = c->first_stream; if (s->next) s->next->previous = s; s->previous = NULL; c->first_stream = s; - return 0; + if (dev) + lookup_device(s, dev); + else + create_stream(s, (uint32_t) -1); + + return s; } void pa_stream_free(struct pa_stream *s) { assert(s && s->context); + + free(s->name); - if (s->channel_valid) { + if (s->channel_valid && s->context->state == CONTEXT_READY) { struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); assert(t); @@ -469,7 +571,7 @@ void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stre void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { struct pa_memchunk chunk; - assert(s && s->context && data && length); + assert(s && s->context && data && length && s->state == STREAM_READY); chunk.memblock = pa_memblock_new(length); assert(chunk.memblock && chunk.memblock->data); @@ -489,7 +591,7 @@ void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { } size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s); + assert(s && s->state == STREAM_READY); return s->requested_bytes; } @@ -512,3 +614,72 @@ void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream s->die_callback = cb; s->die_userdata = userdata; } + +int pa_context_is_pending(struct pa_context *c) { + assert(c); + + if (c->state != CONTEXT_READY) + return 0; + + return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); +} + +struct pa_context* pa_stream_get_context(struct pa_stream *p) { + assert(p); + return p->context; +} + +static void set_dispatch_callbacks(struct pa_context *c); + +static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void set_dispatch_callbacks(struct pa_context *c) { + assert(c && c->state == CONTEXT_READY); + + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + + if (pa_pdispatch_is_pending(c->pdispatch)) { + pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); + return; + } + + if (pa_pstream_is_pending(c->pstream)) { + pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); + return; + } + + assert(c->drain_complete_callback); + c->drain_complete_callback(c, c->drain_complete_userdata); +} + +int pa_context_drain( + struct pa_context *c, + void (*complete) (struct pa_context*c, void *userdata), + void *userdata) { + + assert(c && c->state == CONTEXT_READY); + + if (complete == NULL) { + c->drain_complete_callback = NULL; + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + return 0; + } + + if (!pa_context_is_pending(c)) + return -1; + + c->drain_complete_callback = complete; + c->drain_complete_userdata = userdata; + + set_dispatch_callbacks(c); + + return 0; +} diff --git a/src/polyp.h b/src/polyp.h index 77a6966f..25ee3bed 100644 --- a/src/polyp.h +++ b/src/polyp.h @@ -17,6 +17,11 @@ int pa_context_connect( void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); +int pa_context_drain( + struct pa_context *c, + void (*complete) (struct pa_context*c, void *userdata), + void *userdata); + void pa_context_free(struct pa_context *c); void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); @@ -25,6 +30,8 @@ int pa_context_is_dead(struct pa_context *c); int pa_context_is_ready(struct pa_context *c); int pa_context_errno(struct pa_context *c); +int pa_context_is_pending(struct pa_context *c); + struct pa_stream; struct pa_stream* pa_stream_new( @@ -50,4 +57,6 @@ void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_strea int pa_stream_is_dead(struct pa_stream *p); int pa_stream_is_ready(struct pa_stream*p); +struct pa_context* pa_stream_get_context(struct pa_stream *p); + #endif diff --git a/src/polypdef.h b/src/polypdef.h index aa6e6bf6..80b3cc6c 100644 --- a/src/polypdef.h +++ b/src/polypdef.h @@ -9,9 +9,10 @@ enum pa_stream_direction { }; struct pa_buffer_attr { - uint32_t queue_length; - uint32_t max_length; + uint32_t maxlength; + uint32_t tlength; uint32_t prebuf; + uint32_t minreq; }; diff --git a/src/protocol-esound.c b/src/protocol-esound.c index cd6448fc..04006d5d 100644 --- a/src/protocol-esound.c +++ b/src/protocol-esound.c @@ -17,9 +17,7 @@ #define COOKIE_FILE ".esd_auth" -#define MEMBLOCKQ_LENGTH (10*1204) -#define MEMBLOCKQ_PREBUF (2*1024) -#define BUFSIZE (1024) +#define BUFFER_SECONDS (0.5) /* This is heavily based on esound's code */ @@ -196,6 +194,7 @@ static int esd_proto_stream_play(struct connection *c, const void *data, size_t int format, rate; struct pa_sink *sink; struct pa_sample_spec ss; + size_t l; assert(length == (sizeof(int)*2+ESD_NAME_MAX)); format = maybe_swap_endian_32(c->swap_byte_order, *(int*)data); @@ -217,7 +216,9 @@ static int esd_proto_stream_play(struct connection *c, const void *data, size_t pa_client_rename(c->client, name); assert(!c->input_memblockq); - c->input_memblockq = pa_memblockq_new(MEMBLOCKQ_LENGTH, pa_sample_size(&ss), MEMBLOCKQ_PREBUF); + + l = (size_t) (pa_bytes_per_second(&ss)*BUFFER_SECONDS); + c->input_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&ss), l/2, l/10); assert(c->input_memblockq); assert(!c->sink_input); @@ -252,7 +253,7 @@ static int esd_proto_get_latency(struct connection *c, const void *data, size_t latency = 0; else { float usec = pa_sink_get_latency(sink); - usec += pa_samples_usec(MEMBLOCKQ_LENGTH-BUFSIZE, &sink->sample_spec); + usec += BUFFER_SECONDS*1000000*.9; /* A better estimation would be a good idea! */ latency = (int) ((usec*44100)/1000000); } @@ -452,16 +453,17 @@ static int do_read(struct connection *c) { } else if (c->state == ESD_STREAMING_DATA) { struct pa_memchunk chunk; ssize_t r; + size_t l; assert(c->input_memblockq); - if (!pa_memblockq_is_writable(c->input_memblockq, BUFSIZE)) + if (!(l = pa_memblockq_missing(c->input_memblockq))) return 0; - chunk.memblock = pa_memblock_new(BUFSIZE); + chunk.memblock = pa_memblock_new(l); assert(chunk.memblock && chunk.memblock->data); - if ((r = pa_iochannel_read(c->io, chunk.memblock->data, BUFSIZE)) <= 0) { + if ((r = pa_iochannel_read(c->io, chunk.memblock->data, l)) <= 0) { fprintf(stderr, "protocol-esound.c: read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); pa_memblock_unref(chunk.memblock); return -1; diff --git a/src/protocol-native-spec.h b/src/protocol-native-spec.h index 07fc735b..7fb9ac4a 100644 --- a/src/protocol-native-spec.h +++ b/src/protocol-native-spec.h @@ -13,6 +13,8 @@ enum { PA_COMMAND_REQUEST, PA_COMMAND_AUTH, PA_COMMAND_SET_NAME, + PA_COMMAND_LOOKUP_SINK, + PA_COMMAND_LOOKUP_SOURCE, PA_COMMAND_MAX }; diff --git a/src/protocol-native.c b/src/protocol-native.c index 9463a469..42ff4b52 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -14,6 +14,7 @@ #include "pdispatch.h" #include "pstream-util.h" #include "authkey.h" +#include "namereg.h" struct connection; struct pa_protocol_native; @@ -28,7 +29,6 @@ struct record_stream { struct playback_stream { struct connection *connection; uint32_t index; - size_t qlength; struct pa_sink_input *sink_input; struct pa_memblockq *memblockq; size_t requested_bytes; @@ -58,11 +58,12 @@ static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i); static void request_bytes(struct playback_stream*s); -static int command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static int command_create_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static int command_delete_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static int command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static int command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_delete_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = { NULL }, @@ -76,6 +77,8 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_REQUEST] = { NULL }, [PA_COMMAND_EXIT] = { command_exit }, [PA_COMMAND_SET_NAME] = { command_set_name }, + [PA_COMMAND_LOOKUP_SINK] = { command_lookup }, + [PA_COMMAND_LOOKUP_SOURCE] = { command_lookup }, }; /* structure management */ @@ -89,14 +92,17 @@ static void record_stream_free(struct record_stream* r) { free(r); } -static struct playback_stream* playback_stream_new(struct connection *c, struct pa_sink *sink, struct pa_sample_spec *ss, const char *name, size_t qlen, size_t maxlength, size_t prebuf) { +static struct playback_stream* playback_stream_new(struct connection *c, struct pa_sink *sink, struct pa_sample_spec *ss, const char *name, + size_t maxlength, + size_t tlength, + size_t prebuf, + size_t minreq) { struct playback_stream *s; - assert(c && sink && ss && name && qlen && maxlength && prebuf); + assert(c && sink && ss && name && maxlength); s = malloc(sizeof(struct playback_stream)); assert (s); s->connection = c; - s->qlength = qlen; s->sink_input = pa_sink_input_new(sink, name, ss); assert(s->sink_input); @@ -106,7 +112,7 @@ static struct playback_stream* playback_stream_new(struct connection *c, struct s->sink_input->get_latency = sink_input_get_latency_cb; s->sink_input->userdata = s; - s->memblockq = pa_memblockq_new(maxlength, pa_sample_size(ss), prebuf); + s->memblockq = pa_memblockq_new(maxlength, tlength, pa_sample_size(ss), prebuf, minreq); assert(s->memblockq); s->requested_bytes = 0; @@ -149,13 +155,17 @@ static void request_bytes(struct playback_stream *s) { size_t l; assert(s); - if (!(l = pa_memblockq_missing_to(s->memblockq, s->qlength))) + if (!(l = pa_memblockq_missing(s->memblockq))) return; if (l <= s->requested_bytes) return; l -= s->requested_bytes; + + if (l < pa_memblockq_get_minreq(s->memblockq)) + return; + s->requested_bytes += l; t = pa_tagstruct_new(NULL, 0); @@ -166,7 +176,7 @@ static void request_bytes(struct playback_stream *s) { pa_tagstruct_putu32(t, l); pa_pstream_send_tagstruct(s->connection->pstream, t); -/* fprintf(stderr, "Requesting %u bytes\n", l);*/ + /*fprintf(stderr, "Requesting %u bytes\n", l);*/ } /*** sinkinput callbacks ***/ @@ -209,10 +219,15 @@ static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { /*** pdispatch callbacks ***/ -static int command_create_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void protocol_error(struct connection *c) { + fprintf(stderr, __FILE__": protocol error, kicking client\n"); + connection_free(c); +} + +static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; struct playback_stream *s; - size_t maxlength, prebuf, qlength; + size_t maxlength, tlength, prebuf, minreq; uint32_t sink_index; const char *name; struct pa_sample_spec ss; @@ -223,15 +238,18 @@ static int command_create_playback_stream(struct pa_pdispatch *pd, uint32_t comm if (pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_get_sample_spec(t, &ss) < 0 || pa_tagstruct_getu32(t, &sink_index) < 0 || - pa_tagstruct_getu32(t, &qlength) < 0 || pa_tagstruct_getu32(t, &maxlength) < 0 || + pa_tagstruct_getu32(t, &tlength) < 0 || pa_tagstruct_getu32(t, &prebuf) < 0 || - !pa_tagstruct_eof(t)) - return -1; + pa_tagstruct_getu32(t, &minreq) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } if (!c->authorized) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return 0; + return; } if (sink_index == (uint32_t) -1) @@ -241,12 +259,12 @@ static int command_create_playback_stream(struct pa_pdispatch *pd, uint32_t comm if (!sink) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); - return 0; + return; } - if (!(s = playback_stream_new(c, sink, &ss, name, qlength, maxlength, prebuf))) { + if (!(s = playback_stream_new(c, sink, &ss, name, maxlength, tlength, prebuf, minreq))) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); - return 0; + return; } reply = pa_tagstruct_new(NULL, 0); @@ -258,107 +276,148 @@ static int command_create_playback_stream(struct pa_pdispatch *pd, uint32_t comm pa_tagstruct_putu32(reply, s->sink_input->index); pa_pstream_send_tagstruct(c->pstream, reply); request_bytes(s); - return 0; } -static int command_delete_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_delete_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; uint32_t channel; struct playback_stream *s; assert(c && t); if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) - return -1; + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } if (!c->authorized) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return 0; + return; } if (!(s = pa_idxset_get_by_index(c->playback_streams, channel))) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); - return 0; + return; } pa_pstream_send_simple_ack(c->pstream, tag); - return 0; } -static int command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; assert(c && t); - if (!pa_tagstruct_eof(t)) - return -1; + if (!pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } if (!c->authorized) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return 0; + return; } assert(c->protocol && c->protocol->core && c->protocol->core->mainloop); c->protocol->core->mainloop->quit(c->protocol->core->mainloop, 0); pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */ - return 0; + return; } -static int command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; const void*cookie; assert(c && t); if (pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 || - !pa_tagstruct_eof(t)) - return -1; - + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) != 0) { fprintf(stderr, "protocol-native.c: Denied access to client with invalid authorization key.\n"); pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return 0; + return; } c->authorized = 1; pa_pstream_send_simple_ack(c->pstream, tag); - return 0; + return; } -static int command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; const char *name; assert(c && t); if (pa_tagstruct_gets(t, &name) < 0 || - !pa_tagstruct_eof(t)) - return -1; + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } pa_client_rename(c->client, name); pa_pstream_send_simple_ack(c->pstream, tag); - return 0; + return; +} + +static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const char *name; + uint32_t index = PA_IDXSET_INVALID; + assert(c && t); + + if (pa_tagstruct_gets(t, &name) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (command == PA_COMMAND_LOOKUP_SINK) { + struct pa_sink *sink; + if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK))) + index = sink->index; + } else { + struct pa_source *source; + assert(command == PA_COMMAND_LOOKUP_SOURCE); + if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE))) + index = source->index; + } + + if (index == PA_IDXSET_INVALID) + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + else { + struct pa_tagstruct *reply; + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, index); + pa_pstream_send_tagstruct(c->pstream, reply); + } } /*** pstream callbacks ***/ -static int packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { +static void packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { struct connection *c = userdata; assert(p && packet && packet->data && c); if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { fprintf(stderr, "protocol-native: invalid packet.\n"); - return -1; + connection_free(c); } - - return 0; } -static int memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata) { +static void memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata) { struct connection *c = userdata; struct playback_stream *stream; assert(p && chunk && userdata); if (!(stream = pa_idxset_get_by_index(c->playback_streams, channel))) { fprintf(stderr, "protocol-native: client sent block for invalid stream.\n"); - return -1; + connection_free(c); + return; } if (chunk->length >= stream->requested_bytes) @@ -371,8 +430,6 @@ static int memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t del pa_sink_notify(stream->sink_input->sink); /*fprintf(stderr, "Recieved %u bytes.\n", chunk->length);*/ - - return 0; } static void die_callback(struct pa_pstream *p, void *userdata) { diff --git a/src/protocol-simple.c b/src/protocol-simple.c index 380b1802..91eab59a 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -28,7 +28,8 @@ struct pa_protocol_simple { struct pa_sample_spec sample_spec; }; -#define BUFSIZE PIPE_BUF +#define PLAYBACK_BUFFER_SECONDS (.5) +#define RECORD_BUFFER_SECONDS (5) static void connection_free(struct connection *c) { assert(c); @@ -52,17 +53,18 @@ static void connection_free(struct connection *c) { static int do_read(struct connection *c) { struct pa_memchunk chunk; ssize_t r; + size_t l; if (!pa_iochannel_is_readable(c->io)) return 0; - if (!c->sink_input || !pa_memblockq_is_writable(c->input_memblockq, BUFSIZE)) + if (!c->sink_input || !(l = pa_memblockq_missing(c->input_memblockq))) return 0; - - chunk.memblock = pa_memblock_new(BUFSIZE); + + chunk.memblock = pa_memblock_new(l); assert(chunk.memblock); - if ((r = pa_iochannel_read(c->io, chunk.memblock->data, BUFSIZE)) <= 0) { + if ((r = pa_iochannel_read(c->io, chunk.memblock->data, l)) <= 0) { fprintf(stderr, "read(): %s\n", r == 0 ? "EOF" : strerror(errno)); pa_memblock_unref(chunk.memblock); return -1; @@ -213,8 +215,8 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->source_output->kill = source_output_kill_cb; c->source_output->userdata = c; - l = 5*pa_bytes_per_second(&p->sample_spec); /* 5s */ - c->output_memblockq = pa_memblockq_new(l, pa_sample_size(&p->sample_spec), l/2); + l = (size_t) (pa_bytes_per_second(&p->sample_spec)*RECORD_BUFFER_SECONDS); + c->output_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&p->sample_spec), l/2, 0); } if (p->mode & PA_PROTOCOL_SIMPLE_PLAYBACK) { @@ -234,8 +236,8 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->sink_input->get_latency = sink_input_get_latency_cb; c->sink_input->userdata = c; - l = pa_bytes_per_second(&p->sample_spec)/2; /* half a second */ - c->input_memblockq = pa_memblockq_new(l, pa_sample_size(&p->sample_spec), l/2); + l = (size_t) (pa_bytes_per_second(&p->sample_spec)*PLAYBACK_BUFFER_SECONDS); + c->input_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&p->sample_spec), l/2, l/10); } diff --git a/src/pstream.c b/src/pstream.c index 1739780e..19f83e30 100644 --- a/src/pstream.c +++ b/src/pstream.c @@ -35,6 +35,8 @@ struct pa_pstream { struct pa_iochannel *io; struct pa_queue *send_queue; + int in_use, shall_free; + int dead; void (*die_callback) (struct pa_pstream *p, void *userdad); void *die_callback_userdata; @@ -46,9 +48,6 @@ struct pa_pstream { size_t index; } write; - void (*send_callback) (struct pa_pstream *p, void *userdata); - void *send_callback_userdata; - struct { struct pa_memblock *memblock; struct pa_packet *packet; @@ -57,34 +56,51 @@ struct pa_pstream { size_t index; } read; - int (*recieve_packet_callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata); + void (*recieve_packet_callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata); void *recieve_packet_callback_userdata; - int (*recieve_memblock_callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata); + void (*recieve_memblock_callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata); void *recieve_memblock_callback_userdata; + + void (*drain_callback)(struct pa_pstream *p, void *userdata); + void *drain_userdata; }; static void do_write(struct pa_pstream *p); static void do_read(struct pa_pstream *p); -static void io_callback(struct pa_iochannel*io, void *userdata) { - struct pa_pstream *p = userdata; - assert(p && p->io == io); - +static void do_something(struct pa_pstream *p) { + assert(p && !p->shall_free); p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 0); - + + p->in_use = 1; do_write(p); + p->in_use = 0; + + if (p->shall_free) { + pa_pstream_free(p); + return; + } + + p->in_use = 1; do_read(p); + p->in_use = 0; + if (p->shall_free) { + pa_pstream_free(p); + return; + } +} + +static void io_callback(struct pa_iochannel*io, void *userdata) { + struct pa_pstream *p = userdata; + assert(p && p->io == io); + do_something(p); } static void fixed_callback(struct pa_mainloop_api *m, void *id, void*userdata) { struct pa_pstream *p = userdata; assert(p && p->mainloop_source == id && p->mainloop == m); - - p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 0); - - do_write(p); - do_read(p); + do_something(p); } struct pa_pstream *pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel *io) { @@ -115,15 +131,17 @@ struct pa_pstream *pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel p->read.packet = NULL; p->read.index = 0; - p->send_callback = NULL; - p->send_callback_userdata = NULL; - p->recieve_packet_callback = NULL; p->recieve_packet_callback_userdata = NULL; p->recieve_memblock_callback = NULL; p->recieve_memblock_callback_userdata = NULL; + p->drain_callback = NULL; + p->drain_userdata = NULL; + + p->in_use = p->shall_free = 0; + return p; } @@ -146,6 +164,12 @@ static void item_free(void *item, void *p) { void pa_pstream_free(struct pa_pstream *p) { assert(p); + if (p->in_use) { + /* If this pstream object is used by someone else on the call stack, we have to postpone the freeing */ + p->dead = p->shall_free = 1; + return; + } + pa_iochannel_free(p->io); pa_queue_free(p->send_queue, item_free, NULL); @@ -162,13 +186,6 @@ void pa_pstream_free(struct pa_pstream *p) { free(p); } -void pa_pstream_set_send_callback(struct pa_pstream*p, void (*callback) (struct pa_pstream *p, void *userdata), void *userdata) { - assert(p && callback); - - p->send_callback = callback; - p->send_callback_userdata = userdata; -} - void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet) { struct item_info *i; assert(p && packet); @@ -199,14 +216,14 @@ void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, int32_t del p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 1); } -void pa_pstream_set_recieve_packet_callback(struct pa_pstream *p, int (*callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata), void *userdata) { +void pa_pstream_set_recieve_packet_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata), void *userdata) { assert(p && callback); p->recieve_packet_callback = callback; p->recieve_packet_callback_userdata = userdata; } -void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, int (*callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata), void *userdata) { +void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata), void *userdata) { assert(p && callback); p->recieve_memblock_callback = callback; @@ -261,7 +278,7 @@ static void do_write(struct pa_pstream *p) { l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE); } - if ((r = pa_iochannel_write(p->io, d, l)) < 0) + if ((r = pa_iochannel_write(p->io, d, l)) < 0) goto die; p->write.index += r; @@ -271,8 +288,8 @@ static void do_write(struct pa_pstream *p) { item_free(p->write.current, (void *) 1); p->write.current = NULL; - if (p->send_callback && pa_queue_is_empty(p->send_queue)) - p->send_callback(p, p->send_callback_userdata); + if (p->drain_callback && !pa_pstream_is_pending(p)) + p->drain_callback(p, p->drain_userdata); } return; @@ -341,13 +358,14 @@ static void do_read(struct pa_pstream *p) { chunk.memblock = p->read.memblock; chunk.index = p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE - l; chunk.length = l; - - if (p->recieve_memblock_callback(p, - ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]), - (int32_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA]), - &chunk, - p->recieve_memblock_callback_userdata) < 0) - goto die; + + if (p->recieve_memblock_callback) + p->recieve_memblock_callback( + p, + ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]), + (int32_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA]), + &chunk, + p->recieve_memblock_callback_userdata); } } @@ -359,17 +377,13 @@ static void do_read(struct pa_pstream *p) { pa_memblock_unref(p->read.memblock); p->read.memblock = NULL; } else { - int r = 0; assert(p->read.packet); - + if (p->recieve_packet_callback) - r = p->recieve_packet_callback(p, p->read.packet, p->recieve_packet_callback_userdata); + p->recieve_packet_callback(p, p->read.packet, p->recieve_packet_callback_userdata); pa_packet_unref(p->read.packet); p->read.packet = NULL; - - if (r < 0) - goto die; } p->read.index = 0; @@ -390,3 +404,21 @@ void pa_pstream_set_die_callback(struct pa_pstream *p, void (*callback)(struct p p->die_callback = callback; p->die_callback_userdata = userdata; } + +int pa_pstream_is_pending(struct pa_pstream *p) { + assert(p); + + if (p->dead) + return 0; + + return p->write.current || !pa_queue_is_empty(p->send_queue); +} + +void pa_pstream_set_drain_callback(struct pa_pstream *p, void (*cb)(struct pa_pstream *p, void *userdata), void *userdata) { + assert(p); + assert(!cb || pa_pstream_is_pending(p)); + + p->drain_callback = cb; + p->drain_userdata = userdata; +} + diff --git a/src/pstream.h b/src/pstream.h index 0f5975d2..011b8d12 100644 --- a/src/pstream.h +++ b/src/pstream.h @@ -9,18 +9,22 @@ #include "mainloop-api.h" #include "memchunk.h" +/* It is safe to destroy the calling pstream object from all callbacks */ + struct pa_pstream; struct pa_pstream* pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel *io); void pa_pstream_free(struct pa_pstream*p); -void pa_pstream_set_send_callback(struct pa_pstream*p, void (*callback) (struct pa_pstream *p, void *userdata), void *userdata); void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet); void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk); -void pa_pstream_set_recieve_packet_callback(struct pa_pstream *p, int (*callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata), void *userdata); -void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, int (*callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata), void *userdata); +void pa_pstream_set_recieve_packet_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata), void *userdata); +void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata), void *userdata); +void pa_pstream_set_drain_callback(struct pa_pstream *p, void (*cb)(struct pa_pstream *p, void *userdata), void *userdata); void pa_pstream_set_die_callback(struct pa_pstream *p, void (*callback)(struct pa_pstream *p, void *userdata), void *userdata); +int pa_pstream_is_pending(struct pa_pstream *p); + #endif diff --git a/src/sample.h b/src/sample.h index 4131992c..df12924b 100644 --- a/src/sample.h +++ b/src/sample.h @@ -32,6 +32,8 @@ uint32_t pa_samples_usec(size_t length, const struct pa_sample_spec *spec); int pa_sample_spec_valid(const struct pa_sample_spec *spec); int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b); + +#define PA_SAMPLE_SNPRINT_MAX_LENGTH 32 void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec); #endif diff --git a/src/simple.c b/src/simple.c index c1d1e96c..cf31ac52 100644 --- a/src/simple.c +++ b/src/simple.c @@ -14,6 +14,27 @@ struct pa_simple { int dead; }; +static int iterate(struct pa_simple *p, int block, int *perror) { + assert(p && p->context && p->mainloop && perror); + + if (!block && !pa_context_is_pending(p->context)) + return 0; + + do { + if (pa_context_is_dead(p->context) || (p->stream && pa_stream_is_dead(p->stream))) { + *perror = pa_context_errno(p->context); + return -1; + } + + if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) { + *perror = PA_ERROR_INTERNAL; + return -1; + } + } while (pa_context_is_pending(p->context)); + + return 0; +} + struct pa_simple* pa_simple_new( const char *server, const char *name, @@ -44,26 +65,18 @@ struct pa_simple* pa_simple_new( goto fail; } + /* Wait until the context is ready */ while (!pa_context_is_ready(p->context)) { - if (pa_context_is_dead(p->context)) { - error = pa_context_errno(p->context); - goto fail; - } - - if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) + if (iterate(p, 1, &error) < 0) goto fail; } if (!(p->stream = pa_stream_new(p->context, dir, dev, stream_name, ss, attr, NULL, NULL))) goto fail; + /* Wait until the stream is ready */ while (!pa_stream_is_ready(p->stream)) { - if (pa_stream_is_dead(p->stream)) { - error = pa_context_errno(p->context); - goto fail; - } - - if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) + if (iterate(p, 1, &error) < 0) goto fail; } @@ -96,17 +109,9 @@ int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *pe while (length > 0) { size_t l; - while (!(l = pa_stream_writable_size(p->stream))) { - if (pa_context_is_dead(p->context)) { - *perror = pa_context_errno(p->context); + while (!(l = pa_stream_writable_size(p->stream))) + if (iterate(p, 1, perror) < 0) return -1; - } - - if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) { - *perror = PA_ERROR_INTERNAL; - return -1; - } - } if (l > length) l = length; @@ -116,9 +121,14 @@ int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *pe length -= l; } + /* Make sure that no data is pending for write */ + if (iterate(p, 0, perror) < 0) + return -1; + return 0; } int pa_simple_read(struct pa_simple *s, void*data, size_t length, int *perror) { assert(0); } + diff --git a/src/sink.c b/src/sink.c index 79bf1778..4852edcc 100644 --- a/src/sink.c +++ b/src/sink.c @@ -274,8 +274,18 @@ char *pa_sink_list_to_string(struct pa_core *c) { default_sink = pa_sink_get_default(c); for (sink = pa_idxset_first(c->sinks, &index); sink; sink = pa_idxset_next(c->sinks, &index)) { + char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + pa_sample_snprint(ss, sizeof(ss), &sink->sample_spec); assert(sink->monitor_source); - pa_strbuf_printf(s, " %c index: %u, name: <%s>, volume: <0x%04x>, latency: <%u usec>, monitor_source: <%u>\n", sink == default_sink ? '*' : ' ', sink->index, sink->name, (unsigned) sink->volume, pa_sink_get_latency(sink), sink->monitor_source->index); + pa_strbuf_printf( + s, + " %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", + sink == default_sink ? '*' : ' ', + sink->index, sink->name, + (unsigned) sink->volume, + pa_sink_get_latency(sink), + sink->monitor_source->index, + ss); } return pa_strbuf_tostring_free(s); diff --git a/src/sinkinput.c b/src/sinkinput.c index aa6f3329..20ab25ea 100644 --- a/src/sinkinput.c +++ b/src/sinkinput.c @@ -85,13 +85,18 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_ncontents(c->sink_inputs)); for (i = pa_idxset_first(c->sink_inputs, &index); i; i = pa_idxset_next(c->sink_inputs, &index)) { + char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + pa_sample_snprint(ss, sizeof(ss), &i->sample_spec); assert(i->sink); - pa_strbuf_printf(s, " index: %u, name: <%s>, sink: <%u>; volume: <0x%04x>, latency: <%u usec>\n", - i->index, - i->name, - i->sink->index, - (unsigned) i->volume, - pa_sink_input_get_latency(i)); + pa_strbuf_printf( + s, + " index: %u\n\tname: <%s>\n\tsink: <%u>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tsample_spec: <%s>\n", + i->index, + i->name, + i->sink->index, + (unsigned) i->volume, + pa_sink_input_get_latency(i), + ss); } return pa_strbuf_tostring_free(s); diff --git a/src/socket-client.h b/src/socket-client.h index 76126aee..046cc3a5 100644 --- a/src/socket-client.h +++ b/src/socket-client.h @@ -5,6 +5,8 @@ #include "mainloop-api.h" #include "iochannel.h" +/* It is safe to destroy the calling socket_client object from the callback */ + struct pa_socket_client; struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port); diff --git a/src/socket-server.h b/src/socket-server.h index d581fa37..dbce172e 100644 --- a/src/socket-server.h +++ b/src/socket-server.h @@ -5,6 +5,8 @@ #include "mainloop-api.h" #include "iochannel.h" +/* It is safe to destroy the calling socket_server object from the callback */ + struct pa_socket_server; struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd); diff --git a/src/source.c b/src/source.c index 1c97604b..44d7da01 100644 --- a/src/source.c +++ b/src/source.c @@ -111,10 +111,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)) { + char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; 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); + snprintf(mo, sizeof(mo), "\n\tmonitor_of: <%u>", source->monitor_of->index); + pa_sample_snprint(ss, sizeof(ss), &source->sample_spec); + pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\tsample_spec: <%s>%s\n", source == default_source ? '*' : ' ', source->index, source->name, ss, mo); } return pa_strbuf_tostring_free(s); diff --git a/src/sourceoutput.c b/src/sourceoutput.c index 4f9f821b..388f1225 100644 --- a/src/sourceoutput.c +++ b/src/sourceoutput.c @@ -68,11 +68,16 @@ char *pa_source_output_list_to_string(struct pa_core *c) { pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_ncontents(c->source_outputs)); for (o = pa_idxset_first(c->source_outputs, &index); o; o = pa_idxset_next(c->source_outputs, &index)) { + char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + pa_sample_snprint(ss, sizeof(ss), &o->sample_spec); assert(o->source); - pa_strbuf_printf(s, " %c index: %u, name: <%s>, source: <%u>\n", - o->index, - o->name, - o->source->index); + pa_strbuf_printf( + s, " %c index: %u\n\tname: <%s>\n\tsource: <%u>\n\tsample_spec: <%u>\n", + o->index, + o->name, + o->source->index, + ss, + ss); } return pa_strbuf_tostring_free(s); diff --git a/src/todo b/src/todo index 5b0d893f..57040cd8 100644 --- a/src/todo +++ b/src/todo @@ -1,7 +1,7 @@ - recording (general, simple, esound, native) - native library/protocol: sync() function - more functions + more functions (esp. latency) - simple library - config parser/cmdline @@ -9,18 +9,20 @@ - move more stuff from module-oss[-dma] to liboss-util - in module-oss: create source first, than sink +- client field for sinkinput/sourceoutput + +- xmms+esound latency testing + - rename files - svn-id and license in every file - documentation - - -- post 0.1 - future cancellation - client-ui - clip cache - autoloading/autounloading -- ldap/rendezvous +- slp/rendezvous - doxygen drivers: diff --git a/src/util.c b/src/util.c index 4ade681a..3111bd5d 100644 --- a/src/util.c +++ b/src/util.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -51,7 +52,7 @@ void pa_peer_to_string(char *c, size_t l, int fd) { ntohs(sa.in.sin_port)); return; } else if (sa.sa.sa_family == AF_LOCAL) { - snprintf(c, l, "UNIX client for %s", sa.un.sun_path); + snprintf(c, l, "UNIX socket client"); return; } @@ -208,3 +209,15 @@ int pa_unix_socket_remove_stale(const char *fn) { return 0; } + +void pa_check_for_sigpipe(void) { + struct sigaction sa; + + if (sigaction(SIGPIPE, NULL, &sa) < 0) { + fprintf(stderr, __FILE__": sigaction() failed: %s\n", strerror(errno)); + return; + } + + if (sa.sa_handler == SIG_DFL) + fprintf(stderr, "polypaudio: WARNING: SIGPIPE is not trapped. This might cause malfunction!\n"); +} diff --git a/src/util.h b/src/util.h index 40095e01..ad9916e7 100644 --- a/src/util.h +++ b/src/util.h @@ -18,4 +18,6 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size); int pa_unix_socket_is_stale(const char *fn); int pa_unix_socket_remove_stale(const char *fn); +void pa_check_for_sigpipe(void); + #endif -- cgit From 863fb90d90c2e57e60a0f5b81e0847319399b8ed Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 7 Jul 2004 22:02:15 +0000 Subject: add output stream draining git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@53 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/memblockq.c | 2 +- src/pacat-simple.c | 6 +++++ src/pacat.c | 17 ++++++++++--- src/pdispatch.c | 43 ++++++++++++++++++++------------ src/pdispatch.h | 3 +++ src/polyp.c | 61 +++++++++++++++++++++++++++++++++++++++++++++- src/polyp.h | 6 +++++ src/protocol-native-spec.h | 1 + src/protocol-native.c | 52 ++++++++++++++++++++++++++++++++++++++- src/simple.c | 34 ++++++++++++++++++++++---- src/simple.h | 2 ++ src/todo | 1 - 12 files changed, 200 insertions(+), 28 deletions(-) diff --git a/src/memblockq.c b/src/memblockq.c index e5dab687..fb4cbc7e 100644 --- a/src/memblockq.c +++ b/src/memblockq.c @@ -228,7 +228,7 @@ void pa_memblockq_empty(struct pa_memblockq *bq) { int pa_memblockq_is_readable(struct pa_memblockq *bq) { assert(bq); - return bq->current_length >= bq->prebuf; + return bq->current_length && (bq->current_length >= bq->prebuf); } int pa_memblockq_is_writable(struct pa_memblockq *bq, size_t length) { diff --git a/src/pacat-simple.c b/src/pacat-simple.c index 8b48bdd3..896df814 100644 --- a/src/pacat-simple.c +++ b/src/pacat-simple.c @@ -41,6 +41,12 @@ int main(int argc, char*argv[]) { } } + /* Make sure that every single sample way played */ + if (pa_simple_drain(s, &error) < 0) { + fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(error)); + goto finish; + } + ret = 0; finish: diff --git a/src/pacat.c b/src/pacat.c index 75a94fc0..59ccc462 100644 --- a/src/pacat.c +++ b/src/pacat.c @@ -117,6 +117,18 @@ static void context_drain_complete(struct pa_context*c, void *userdata) { quit(0); } +static void stream_drain_complete(struct pa_stream*s, void *userdata) { + fprintf(stderr, "Playback stream drained.\n"); + + pa_stream_free(stream); + stream = NULL; + + if (pa_context_drain(context, context_drain_complete, NULL) < 0) + quit(0); + else + fprintf(stderr, "Draining connection to server.\n"); +} + static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { size_t l, w = 0; ssize_t r; @@ -135,10 +147,7 @@ static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_m if ((r = read(fd, buffer, l)) <= 0) { if (r == 0) { fprintf(stderr, "Got EOF.\n"); - if (pa_context_drain(context, context_drain_complete, NULL) < 0) - quit(0); - else - fprintf(stderr, "Draining connection to server.\n"); + pa_stream_drain(stream, stream_drain_complete, NULL); } else { fprintf(stderr, "read() failed: %s\n", strerror(errno)); quit(1); diff --git a/src/pdispatch.c b/src/pdispatch.c index ec454190..b7257dd4 100644 --- a/src/pdispatch.c +++ b/src/pdispatch.c @@ -18,6 +18,7 @@ static const char *command_names[PA_COMMAND_MAX] = { [PA_COMMAND_SET_NAME] = "SET_NAME", [PA_COMMAND_LOOKUP_SINK] = "LOOKUP_SINK", [PA_COMMAND_LOOKUP_SOURCE] = "LOOKUP_SOURCE", + [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = "DRAIN_PLAYBACK_STREAM", }; struct reply_info { @@ -27,6 +28,7 @@ struct reply_info { void *userdata; uint32_t tag; void *mainloop_timeout; + int callback_is_running; }; struct pa_pdispatch { @@ -77,7 +79,7 @@ struct pa_pdispatch* pa_pdispatch_new(struct pa_mainloop_api *mainloop, const st void pa_pdispatch_free(struct pa_pdispatch *pd) { assert(pd); - + if (pd->in_use) { pd->shall_free = 1; return; @@ -109,25 +111,23 @@ int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *use if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) { struct reply_info *r; - for (r = pd->replies; r; r = r->next) { - if (r->tag != tag) - continue; - - pd->in_use = 1; + for (r = pd->replies; r; r = r->next) + if (r->tag == tag) + break; + + if (r) { + pd->in_use = r->callback_is_running = 1; assert(r->callback); r->callback(r->pdispatch, command, tag, ts, r->userdata); - pd->in_use = 0; + pd->in_use = r->callback_is_running = 0; reply_info_free(r); - if (pd->shall_free) { + if (pd->shall_free) pa_pdispatch_free(pd); - break; + else { + if (pd->drain_callback && !pa_pdispatch_is_pending(pd)) + pd->drain_callback(pd, pd->drain_userdata); } - - if (pd->drain_callback && !pa_pdispatch_is_pending(r->pdispatch)) - pd->drain_callback(r->pdispatch, r->pdispatch->drain_userdata); - - break; } } else if (pd->command_table && command < pd->n_commands) { @@ -169,7 +169,8 @@ void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int time r->callback = cb; r->userdata = userdata; r->tag = tag; - + r->callback_is_running = 0; + gettimeofday(&tv, NULL); tv.tv_sec += timeout; @@ -196,3 +197,15 @@ void pa_pdispatch_set_drain_callback(struct pa_pdispatch *pd, void (*cb)(struct pd->drain_callback = cb; pd->drain_userdata = userdata; } + +void pa_pdispatch_unregister_reply(struct pa_pdispatch *pd, void *userdata) { + struct reply_info *r, *n; + assert(pd); + + for (r = pd->replies; r; r = n) { + n = r->next; + + if (!r->callback_is_running && r->userdata == userdata) /* when this item's callback is currently running it is destroyed anyway in the very near future */ + reply_info_free(r); + } +} diff --git a/src/pdispatch.h b/src/pdispatch.h index 35e93829..ac372477 100644 --- a/src/pdispatch.h +++ b/src/pdispatch.h @@ -25,4 +25,7 @@ int pa_pdispatch_is_pending(struct pa_pdispatch *pd); void pa_pdispatch_set_drain_callback(struct pa_pdispatch *pd, void (*cb)(struct pa_pdispatch *pd, void *userdata), void *userdata); +/* Remove all reply slots with the give userdata parameter */ +void pa_pdispatch_unregister_reply(struct pa_pdispatch *pd, void *userdata); + #endif diff --git a/src/polyp.c b/src/polyp.c index 9af8d468..0f2a9181 100644 --- a/src/polyp.c +++ b/src/polyp.c @@ -75,6 +75,9 @@ struct pa_stream { void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); void *create_complete_userdata; + + void (*drain_complete_callback)(struct pa_stream *s, void *userdata); + void *drain_complete_userdata; void (*die_callback)(struct pa_stream*c, void *userdata); void *die_userdata; @@ -538,8 +541,10 @@ struct pa_stream* pa_stream_new( void pa_stream_free(struct pa_stream *s) { assert(s && s->context); - free(s->name); + pa_pdispatch_unregister_reply(s->context->pdispatch, s); + free(s->name); + if (s->channel_valid && s->context->state == CONTEXT_READY) { struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); assert(t); @@ -683,3 +688,57 @@ int pa_context_drain( return 0; } + +static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + return; + } + + if (s->state != STREAM_READY) + return; + + if (!pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->drain_complete_callback) { + void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; + s->drain_complete_callback = NULL; + temp(s, s->drain_complete_userdata); + } +} + + +void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s && s->state == STREAM_READY); + + if (!complete) { + s->drain_complete_callback = NULL; + return; + } + + s->drain_complete_callback = complete; + s->drain_complete_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); +} diff --git a/src/polyp.h b/src/polyp.h index 25ee3bed..c49a72b2 100644 --- a/src/polyp.h +++ b/src/polyp.h @@ -46,6 +46,12 @@ struct pa_stream* pa_stream_new( void pa_stream_free(struct pa_stream *p); +void pa_stream_drain( + struct pa_stream *s, + void (*complete) (struct pa_stream*s, void *userdata), + void *userdata); + + void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); diff --git a/src/protocol-native-spec.h b/src/protocol-native-spec.h index 7fb9ac4a..fea14cc0 100644 --- a/src/protocol-native-spec.h +++ b/src/protocol-native-spec.h @@ -15,6 +15,7 @@ enum { PA_COMMAND_SET_NAME, PA_COMMAND_LOOKUP_SINK, PA_COMMAND_LOOKUP_SOURCE, + PA_COMMAND_DRAIN_PLAYBACK_STREAM, PA_COMMAND_MAX }; diff --git a/src/protocol-native.c b/src/protocol-native.c index 42ff4b52..110d0d6b 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -32,6 +32,8 @@ struct playback_stream { struct pa_sink_input *sink_input; struct pa_memblockq *memblockq; size_t requested_bytes; + int drain_request; + uint32_t drain_tag; }; struct connection { @@ -61,6 +63,7 @@ static void request_bytes(struct playback_stream*s); static void command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_delete_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); @@ -71,6 +74,7 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_REPLY] = { NULL }, [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { command_create_playback_stream }, [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { command_delete_playback_stream }, + [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = { command_drain_playback_stream }, [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, [PA_COMMAND_AUTH] = { command_auth }, @@ -116,6 +120,7 @@ static struct playback_stream* playback_stream_new(struct connection *c, struct assert(s->memblockq); s->requested_bytes = 0; + s->drain_request = 0; pa_idxset_put(c->playback_streams, s, &s->index); return s; @@ -124,6 +129,9 @@ static struct playback_stream* playback_stream_new(struct connection *c, struct static void playback_stream_free(struct playback_stream* p) { assert(p && p->connection); + if (p->drain_request) + pa_pstream_send_error(p->connection->pstream, p->drain_tag, PA_ERROR_NOENTITY); + pa_idxset_remove_by_data(p->connection->playback_streams, p, NULL); pa_sink_input_free(p->sink_input); pa_memblockq_free(p->memblockq); @@ -199,6 +207,11 @@ static void sink_input_drop_cb(struct pa_sink_input *i, size_t length) { pa_memblockq_drop(s->memblockq, length); request_bytes(s); + + if (s->drain_request && !pa_memblockq_is_readable(s->memblockq)) { + pa_pstream_send_simple_ack(s->connection->pstream, s->drain_tag); + s->drain_request = 0; + } } static void sink_input_kill_cb(struct pa_sink_input *i) { @@ -258,7 +271,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); if (!sink) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -373,6 +386,11 @@ static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t t return; } + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + if (command == PA_COMMAND_LOOKUP_SINK) { struct pa_sink *sink; if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK))) @@ -397,6 +415,38 @@ static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t t } } +static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t index; + struct playback_stream *s; + assert(c && t); + + if (pa_tagstruct_getu32(t, &index) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->playback_streams, index))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + s->drain_request = 0; + + if (!pa_memblockq_is_readable(s->memblockq)) + pa_pstream_send_simple_ack(c->pstream, tag); + else { + s->drain_request = 1; + s->drain_tag = tag; + } +} + /*** pstream callbacks ***/ static void packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { diff --git a/src/simple.c b/src/simple.c index cf31ac52..50bfea43 100644 --- a/src/simple.c +++ b/src/simple.c @@ -11,23 +11,25 @@ struct pa_simple { struct pa_context *context; struct pa_stream *stream; - int dead; + int dead, drained; }; static int iterate(struct pa_simple *p, int block, int *perror) { - assert(p && p->context && p->mainloop && perror); + assert(p && p->context && p->mainloop); if (!block && !pa_context_is_pending(p->context)) return 0; do { if (pa_context_is_dead(p->context) || (p->stream && pa_stream_is_dead(p->stream))) { - *perror = pa_context_errno(p->context); + if (perror) + *perror = pa_context_errno(p->context); return -1; } if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) { - *perror = PA_ERROR_INTERNAL; + if (perror) + *perror = PA_ERROR_INTERNAL; return -1; } } while (pa_context_is_pending(p->context)); @@ -83,7 +85,8 @@ struct pa_simple* pa_simple_new( return p; fail: - *perror = error; + if (perror) + *perror = error; pa_simple_free(p); return NULL; } @@ -132,3 +135,24 @@ int pa_simple_read(struct pa_simple *s, void*data, size_t length, int *perror) { assert(0); } + +static void drain_complete(struct pa_stream *s, void *userdata) { + struct pa_simple *p = userdata; + assert(s && p); + p->drained = 1; +} + +int pa_simple_drain(struct pa_simple *p, int *perror) { + assert(p); + p->drained = 0; + pa_stream_drain(p->stream, drain_complete, p); + + while (!p->drained) { + if (iterate(p, 1, perror) < 0) { + pa_stream_drain(p->stream, NULL, NULL); + return -1; + } + } + + return 0; +} diff --git a/src/simple.h b/src/simple.h index ed181201..f5f872ee 100644 --- a/src/simple.h +++ b/src/simple.h @@ -21,6 +21,8 @@ struct pa_simple* pa_simple_new( void pa_simple_free(struct pa_simple *s); int pa_simple_write(struct pa_simple *s, const void*data, size_t length, int *error); +int pa_simple_drain(struct pa_simple *s, int *error); + int pa_simple_read(struct pa_simple *s, void*data, size_t length, int *error); #endif diff --git a/src/todo b/src/todo index 57040cd8..93ba2821 100644 --- a/src/todo +++ b/src/todo @@ -1,6 +1,5 @@ - recording (general, simple, esound, native) - native library/protocol: - sync() function more functions (esp. latency) - simple library -- cgit From cffc7768bd5b8d16308c15102b4d03d08d287098 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 9 Jul 2004 23:26:10 +0000 Subject: fix recording for simpel and esound protocols git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@54 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/cli.c | 2 +- src/iochannel.c | 24 +++- src/iochannel.h | 5 +- src/main.c | 3 +- src/mainloop-api.h | 3 +- src/mainloop.c | 3 +- src/memblock.h | 2 - src/module-oss-mmap.c | 4 +- src/pacat.c | 3 +- src/polyp.c | 3 +- src/protocol-esound.c | 323 +++++++++++++++++++++++++++++++++++++++----------- src/protocol-simple.c | 162 ++++++++++++++++++------- src/sample-util.c | 3 - src/simple.c | 27 +++-- src/sink.c | 1 - src/sinkinput.c | 3 +- src/socket-client.c | 4 +- src/socket-server.c | 8 +- src/sourceoutput.c | 3 +- src/todo | 14 ++- src/util.c | 49 ++++---- src/util.h | 7 +- 22 files changed, 480 insertions(+), 176 deletions(-) diff --git a/src/cli.c b/src/cli.c index ecde5763..429aebf3 100644 --- a/src/cli.c +++ b/src/cli.c @@ -97,7 +97,7 @@ struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io) { c->userdata = NULL; c->eof_callback = NULL; - pa_iochannel_peer_to_string(io, cname, sizeof(cname)); + pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); c->client = pa_client_new(core, "CLI", cname); assert(c->client); c->client->kill = client_kill; diff --git a/src/iochannel.c b/src/iochannel.c index afa94cff..775c6139 100644 --- a/src/iochannel.c +++ b/src/iochannel.c @@ -15,6 +15,7 @@ struct pa_iochannel { int readable; int writable; + int hungup; int no_close; @@ -47,6 +48,11 @@ static void callback(struct pa_mainloop_api* m, void *id, int fd, enum pa_mainlo int changed = 0; assert(m && fd >= 0 && events && userdata); + if ((events & PA_MAINLOOP_API_IO_EVENT_HUP) && !io->hungup) { + io->hungup = 1; + changed = 1; + } + if ((events & PA_MAINLOOP_API_IO_EVENT_INPUT) && !io->readable) { io->readable = 1; changed = 1; @@ -80,6 +86,7 @@ struct pa_iochannel* pa_iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd io->callback = NULL; io->readable = 0; io->writable = 0; + io->hungup = 0; io->no_close = 0; if (ifd == ofd) { @@ -132,6 +139,11 @@ int pa_iochannel_is_writable(struct pa_iochannel*io) { return io->writable; } +int pa_iochannel_is_hungup(struct pa_iochannel*io) { + assert(io); + return io->hungup; +} + ssize_t pa_iochannel_write(struct pa_iochannel*io, const void*data, size_t l) { ssize_t r; assert(io && data && l && io->ofd >= 0); @@ -168,7 +180,17 @@ void pa_iochannel_set_noclose(struct pa_iochannel*io, int b) { io->no_close = b; } -void pa_iochannel_peer_to_string(struct pa_iochannel*io, char*s, size_t l) { +void pa_iochannel_socket_peer_to_string(struct pa_iochannel*io, char*s, size_t l) { assert(io && s && l); pa_peer_to_string(s, l, io->ifd); } + +int pa_iochannel_socket_set_rcvbuf(struct pa_iochannel *io, size_t l) { + assert(io); + return pa_socket_set_rcvbuf(io->ifd, l); +} + +int pa_iochannel_socket_set_sndbuf(struct pa_iochannel *io, size_t l) { + assert(io); + return pa_socket_set_sndbuf(io->ofd, l); +} diff --git a/src/iochannel.h b/src/iochannel.h index 1a5057d6..7e31b6ca 100644 --- a/src/iochannel.h +++ b/src/iochannel.h @@ -16,11 +16,14 @@ ssize_t pa_iochannel_read(struct pa_iochannel*io, void*data, size_t l); int pa_iochannel_is_readable(struct pa_iochannel*io); int pa_iochannel_is_writable(struct pa_iochannel*io); +int pa_iochannel_is_hungup(struct pa_iochannel*io); void pa_iochannel_set_noclose(struct pa_iochannel*io, int b); void pa_iochannel_set_callback(struct pa_iochannel*io, void (*callback)(struct pa_iochannel*io, void *userdata), void *userdata); -void pa_iochannel_peer_to_string(struct pa_iochannel*io, char*s, size_t l); +void pa_iochannel_socket_peer_to_string(struct pa_iochannel*io, char*s, size_t l); +int pa_iochannel_socket_set_rcvbuf(struct pa_iochannel*io, size_t l); +int pa_iochannel_socket_set_sndbuf(struct pa_iochannel*io, size_t l); #endif diff --git a/src/main.c b/src/main.c index c7a83fec..e2d86b48 100644 --- a/src/main.c +++ b/src/main.c @@ -42,7 +42,8 @@ int main(int argc, char *argv[]) { c = pa_core_new(pa_mainloop_get_api(mainloop)); assert(c); - pa_module_load(c, "module-oss", "/dev/dsp"); + pa_module_load(c, "module-oss-mmap", "/dev/dsp"); +/* 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); diff --git a/src/mainloop-api.h b/src/mainloop-api.h index 96dacc22..961a1a46 100644 --- a/src/mainloop-api.h +++ b/src/mainloop-api.h @@ -8,7 +8,8 @@ enum pa_mainloop_api_io_events { PA_MAINLOOP_API_IO_EVENT_NULL = 0, PA_MAINLOOP_API_IO_EVENT_INPUT = 1, PA_MAINLOOP_API_IO_EVENT_OUTPUT = 2, - PA_MAINLOOP_API_IO_EVENT_BOTH = 3 + PA_MAINLOOP_API_IO_EVENT_BOTH = 3, + PA_MAINLOOP_API_IO_EVENT_HUP = 4 }; struct pa_mainloop_api { diff --git a/src/mainloop.c b/src/mainloop.c index 4755cc8f..a485a963 100644 --- a/src/mainloop.c +++ b/src/mainloop.c @@ -167,7 +167,8 @@ static void dispatch_pollfds(struct pa_mainloop *m) { assert(s->pollfd->fd == s->fd && s->callback); s->callback(&m->api, s, s->fd, - ((s->pollfd->revents & (POLLIN|POLLHUP|POLLERR)) ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | + ((s->pollfd->revents & POLLHUP) ? PA_MAINLOOP_API_IO_EVENT_HUP : 0) | + ((s->pollfd->revents & POLLIN) ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | ((s->pollfd->revents & POLLOUT) ? PA_MAINLOOP_API_IO_EVENT_OUTPUT : 0), s->userdata); s->pollfd->revents = 0; } diff --git a/src/memblock.h b/src/memblock.h index acdae047..2635f023 100644 --- a/src/memblock.h +++ b/src/memblock.h @@ -22,8 +22,6 @@ struct pa_memblock* pa_memblock_ref(struct pa_memblock*b); void pa_memblock_unref_fixed(struct pa_memblock*b); -#define pa_memblock_assert_exclusive(b) assert((b)->ref == 1) - extern unsigned pa_memblock_count, pa_memblock_total; #endif diff --git a/src/module-oss-mmap.c b/src/module-oss-mmap.c index 62c2cc2a..a9cf84f3 100644 --- a/src/module-oss-mmap.c +++ b/src/module-oss-mmap.c @@ -68,10 +68,10 @@ static void out_fill_memblocks(struct userdata *u, unsigned n) { if (!u->out_memblocks[u->out_current]) { - u->out_memblocks[u->out_current] = chunk.memblock = pa_memblock_new_fixed(u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size); + chunk.memblock = u->out_memblocks[u->out_current] = pa_memblock_new_fixed(u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size); chunk.length = chunk.memblock->length; chunk.index = 0; - + pa_sink_render_into_full(u->sink, &chunk); } diff --git a/src/pacat.c b/src/pacat.c index 59ccc462..4fdf3f69 100644 --- a/src/pacat.c +++ b/src/pacat.c @@ -132,7 +132,7 @@ static void stream_drain_complete(struct pa_stream*s, void *userdata) { static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { size_t l, w = 0; ssize_t r; - assert(a == mainloop_api && id && fd == STDIN_FILENO && events == PA_MAINLOOP_API_IO_EVENT_INPUT && stdin_source == id); + assert(a == mainloop_api && id && fd == STDIN_FILENO && stdin_source == id); if (buffer) { mainloop_api->enable_io(mainloop_api, stdin_source, PA_MAINLOOP_API_IO_EVENT_NULL); @@ -169,6 +169,7 @@ static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_m static void exit_signal_callback(void *id, int sig, void *userdata) { fprintf(stderr, "Got SIGINT, exiting.\n"); quit(0); + } int main(int argc, char *argv[]) { diff --git a/src/polyp.c b/src/polyp.c index 0f2a9181..6bc7ab33 100644 --- a/src/polyp.c +++ b/src/polyp.c @@ -541,7 +541,8 @@ struct pa_stream* pa_stream_new( void pa_stream_free(struct pa_stream *s) { assert(s && s->context); - pa_pdispatch_unregister_reply(s->context->pdispatch, s); + if (s->context->pdispatch) + pa_pdispatch_unregister_reply(s->context->pdispatch, s); free(s->name); diff --git a/src/protocol-esound.c b/src/protocol-esound.c index 04006d5d..3dd9655b 100644 --- a/src/protocol-esound.c +++ b/src/protocol-esound.c @@ -11,13 +11,18 @@ #include "client.h" #include "sinkinput.h" #include "sink.h" +#include "sourceoutput.h" +#include "source.h" #include "sample.h" #include "authkey.h" #define COOKIE_FILE ".esd_auth" -#define BUFFER_SECONDS (0.5) +#define PLAYBACK_BUFFER_SECONDS (.5) +#define PLAYBACK_BUFFER_FRAGMENTS (10) +#define RECORD_BUFFER_SECONDS (5) +#define RECORD_BUFFER_FRAGMENTS (100) /* This is heavily based on esound's code */ @@ -27,14 +32,20 @@ struct connection { struct pa_iochannel *io; struct pa_client *client; int authorized, swap_byte_order; - void *read_data; - size_t read_data_alloc, read_data_length; void *write_data; size_t write_data_alloc, write_data_index, write_data_length; + void *read_data; + size_t read_data_alloc, read_data_length; esd_proto_t request; esd_client_state_t state; struct pa_sink_input *sink_input; - struct pa_memblockq *input_memblockq; + struct pa_source_output *source_output; + struct pa_memblockq *input_memblockq, *output_memblockq; + void *fixed_source; + struct { + struct pa_memblock *current_memblock; + size_t memblock_index, fragment_size; + } playback; }; struct pa_protocol_esound { @@ -42,14 +53,14 @@ struct pa_protocol_esound { struct pa_core *core; struct pa_socket_server *server; struct pa_idxset *connections; - uint32_t sink_index; + uint32_t sink_index, source_index; unsigned n_player; uint8_t esd_key[ESD_KEY_LEN]; }; typedef struct proto_handler { size_t data_length; - int (*proc)(struct connection *c, const void *data, size_t length); + int (*proc)(struct connection *c, esd_proto_t request, const void *data, size_t length); const char *description; } esd_proto_handler_info_t; @@ -58,15 +69,16 @@ static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk static void sink_input_kill_cb(struct pa_sink_input *i); static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i); -static int esd_proto_connect(struct connection *c, const void *data, size_t length); -static int esd_proto_stream_play(struct connection *c, const void *data, size_t length); -static int esd_proto_stream_record(struct connection *c, const void *data, size_t length); -static int esd_proto_get_latency(struct connection *c, const void *data, size_t length); -static int esd_proto_server_info(struct connection *c, const void *data, size_t length); -static int esd_proto_all_info(struct connection *c, const void *data, size_t length); -static int esd_proto_stream_pan(struct connection *c, const void *data, size_t length); +static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk); +static void source_output_kill_cb(struct pa_source_output *o); -static int do_write(struct connection *c); +static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_play(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_get_latency(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_server_info(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const void *data, size_t length); /* the big map of protocol handler info */ static struct proto_handler proto_map[ESD_PROTO_MAX] = { @@ -76,7 +88,7 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = { { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_play, "stream play" }, { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream rec" }, - { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream mon" }, + { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream mon" }, { ESD_NAME_MAX + 3 * sizeof(int), NULL, "sample cache" }, { sizeof(int), NULL, "sample free" }, @@ -112,16 +124,27 @@ static void connection_free(struct connection *c) { c->protocol->n_player--; pa_client_free(c->client); - + if (c->sink_input) pa_sink_input_free(c->sink_input); + if (c->source_output) + pa_source_output_free(c->source_output); if (c->input_memblockq) pa_memblockq_free(c->input_memblockq); + if (c->output_memblockq) + pa_memblockq_free(c->output_memblockq); + + if (c->playback.current_memblock) + pa_memblock_unref(c->playback.current_memblock); free(c->read_data); free(c->write_data); pa_iochannel_free(c->io); + + if (c->fixed_source) + c->protocol->core->mainloop->cancel_fixed(c->protocol->core->mainloop, c->fixed_source); + free(c); } @@ -132,11 +155,18 @@ static struct pa_sink* get_output_sink(struct pa_protocol_esound *p) { if (!(s = pa_idxset_get_by_index(p->core->sinks, p->sink_index))) s = pa_sink_get_default(p->core); - if (s->index) - p->sink_index = s->index; - else - p->sink_index = PA_IDXSET_INVALID; + p->sink_index = s ? s->index : PA_IDXSET_INVALID; + return s; +} + +static struct pa_source* get_input_source(struct pa_protocol_esound *p) { + struct pa_source *s; + assert(p); + + if (!(s = pa_idxset_get_by_index(p->core->sources, p->sink_index))) + s = pa_source_get_default(p->core); + p->source_index = s ? s->index : PA_IDXSET_INVALID; return s; } @@ -144,6 +174,9 @@ static void* connection_write(struct connection *c, size_t length) { size_t t, i; assert(c); + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); + c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); + t = c->write_data_length+length; if (c->write_data_alloc < t) @@ -159,14 +192,14 @@ static void* connection_write(struct connection *c, size_t length) { /*** esound commands ***/ -static int esd_proto_connect(struct connection *c, const void *data, size_t length) { +static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length) { uint32_t ekey; int *ok; assert(length == (ESD_KEY_LEN + sizeof(uint32_t))); if (!c->authorized) { if (memcmp(data, c->protocol->esd_key, ESD_KEY_LEN) != 0) { - fprintf(stderr, "protocol-esound.c: Kicked client with invalid authorization key.\n"); + fprintf(stderr, __FILE__": kicked client with invalid authorization key.\n"); return -1; } @@ -179,7 +212,7 @@ static int esd_proto_connect(struct connection *c, const void *data, size_t leng else if (ekey == ESD_SWAP_ENDIAN_KEY) c->swap_byte_order = 1; else { - fprintf(stderr, "protocol-esound.c: client sent invalid endian key\n"); + fprintf(stderr, __FILE__": client sent invalid endian key\n"); return -1; } @@ -189,13 +222,13 @@ static int esd_proto_connect(struct connection *c, const void *data, size_t leng return 0; } -static int esd_proto_stream_play(struct connection *c, const void *data, size_t length) { +static int esd_proto_stream_play(struct connection *c, esd_proto_t request, const void *data, size_t length) { char name[ESD_NAME_MAX]; int format, rate; struct pa_sink *sink; struct pa_sample_spec ss; size_t l; - assert(length == (sizeof(int)*2+ESD_NAME_MAX)); + assert(c && length == (sizeof(int)*2+ESD_NAME_MAX)); format = maybe_swap_endian_32(c->swap_byte_order, *(int*)data); rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); @@ -217,10 +250,12 @@ static int esd_proto_stream_play(struct connection *c, const void *data, size_t assert(!c->input_memblockq); - l = (size_t) (pa_bytes_per_second(&ss)*BUFFER_SECONDS); - c->input_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&ss), l/2, l/10); + l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); + c->input_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&ss), l/2, l/PLAYBACK_BUFFER_FRAGMENTS); assert(c->input_memblockq); - + pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*5); + c->playback.fragment_size = l/10; + assert(!c->sink_input); c->sink_input = pa_sink_input_new(sink, name, &ss); assert(c->sink_input); @@ -238,13 +273,67 @@ static int esd_proto_stream_play(struct connection *c, const void *data, size_t return 0; } -static int esd_proto_stream_record(struct connection *c, const void *data, size_t length) { - assert(c && data && length == (sizeof(int)*2+ESD_NAME_MAX)); +static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length) { + char name[ESD_NAME_MAX]; + int format, rate; + struct pa_source *source; + struct pa_sample_spec ss; + size_t l; + assert(c && length == (sizeof(int)*2+ESD_NAME_MAX)); + + format = maybe_swap_endian_32(c->swap_byte_order, *(int*)data); + rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); + + ss.rate = rate; + ss.channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; + ss.format = ((format & ESD_MASK_BITS) == ESD_BITS16) ? PA_SAMPLE_S16NE : PA_SAMPLE_U8; + + if (!pa_sample_spec_valid(&ss)) + return -1; + + if (request == ESD_PROTO_STREAM_MON) { + struct pa_sink* sink; + + if (!(sink = get_output_sink(c->protocol))) + return -1; + + if (!(source = sink->monitor_source)) + return -1; + } else { + assert(request == ESD_PROTO_STREAM_REC); + + if (!(source = get_input_source(c->protocol))) + return -1; + } + + strncpy(name, data + sizeof(int)*2, sizeof(name)); + name[sizeof(name)-1] = 0; + + pa_client_rename(c->client, name); + + assert(!c->output_memblockq); + + l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); + c->output_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&ss), 0, 0); + assert(c->output_memblockq); + pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); + + assert(!c->source_output); + c->source_output = pa_source_output_new(source, name, &ss); + assert(c->source_output); + + c->source_output->push = source_output_push_cb; + c->source_output->kill = source_output_kill_cb; + c->source_output->userdata = c; + + c->state = ESD_STREAMING_DATA; - assert(0); + c->protocol->n_player++; + + return 0; } -static int esd_proto_get_latency(struct connection *c, const void *data, size_t length) { +static int esd_proto_get_latency(struct connection *c, esd_proto_t request, const void *data, size_t length) { struct pa_sink *sink; int latency, *lag; assert(c && !data && length == 0); @@ -253,7 +342,7 @@ static int esd_proto_get_latency(struct connection *c, const void *data, size_t latency = 0; else { float usec = pa_sink_get_latency(sink); - usec += BUFFER_SECONDS*1000000*.9; /* A better estimation would be a good idea! */ + usec += PLAYBACK_BUFFER_SECONDS*1000000*.9; /* A better estimation would be a good idea! */ latency = (int) ((usec*44100)/1000000); } @@ -263,7 +352,7 @@ static int esd_proto_get_latency(struct connection *c, const void *data, size_t return 0; } -static int esd_proto_server_info(struct connection *c, const void *data, size_t length) { +static int esd_proto_server_info(struct connection *c, esd_proto_t request, const void *data, size_t length) { int rate = 44100, format = ESD_STEREO|ESD_BITS16; int *response; struct pa_sink *sink; @@ -283,14 +372,14 @@ static int esd_proto_server_info(struct connection *c, const void *data, size_t return 0; } -static int esd_proto_all_info(struct connection *c, const void *data, size_t length) { +static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length) { void *response; size_t t, k, s; struct connection *conn; size_t index = PA_IDXSET_INVALID; assert(c && data && length == sizeof(int)); - if (esd_proto_server_info(c, data, length) < 0) + if (esd_proto_server_info(c, request, data, length) < 0) return -1; k = sizeof(int)*5+ESD_NAME_MAX; @@ -346,7 +435,7 @@ static int esd_proto_all_info(struct connection *c, const void *data, size_t len return 0; } -static int esd_proto_stream_pan(struct connection *c, const void *data, size_t length) { +static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const void *data, size_t length) { int *ok; uint32_t index, volume; struct connection *conn; @@ -381,9 +470,6 @@ static void client_kill_cb(struct pa_client *c) { static int do_read(struct connection *c) { assert(c && c->io); - if (!pa_iochannel_is_readable(c->io)) - return 0; - if (c->state == ESD_NEXT_REQUEST) { ssize_t r; assert(c->read_data_length < sizeof(c->request)); @@ -414,7 +500,7 @@ static int do_read(struct connection *c) { if (handler->data_length == 0) { c->read_data_length = 0; - if (handler->proc(c, NULL, 0) < 0) + if (handler->proc(c, c->request, NULL, 0) < 0) return -1; } else { @@ -447,10 +533,10 @@ static int do_read(struct connection *c) { c->state = ESD_NEXT_REQUEST; c->read_data_length = 0; - if (handler->proc(c, c->read_data, l) < 0) + if (handler->proc(c, c->request, c->read_data, l) < 0) return -1; } - } else if (c->state == ESD_STREAMING_DATA) { + } else if (c->state == ESD_STREAMING_DATA && c->sink_input) { struct pa_memchunk chunk; ssize_t r; size_t l; @@ -460,21 +546,37 @@ static int do_read(struct connection *c) { if (!(l = pa_memblockq_missing(c->input_memblockq))) return 0; - chunk.memblock = pa_memblock_new(l); - assert(chunk.memblock && chunk.memblock->data); + if (l > c->playback.fragment_size) + l = c->playback.fragment_size; - if ((r = pa_iochannel_read(c->io, chunk.memblock->data, l)) <= 0) { - fprintf(stderr, "protocol-esound.c: read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); - pa_memblock_unref(chunk.memblock); - return -1; + if (c->playback.current_memblock) + if (c->playback.current_memblock->length - c->playback.memblock_index < l) { + pa_memblock_unref(c->playback.current_memblock); + c->playback.current_memblock = NULL; + c->playback.memblock_index = 0; + } + + + if (!c->playback.current_memblock) { + c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2); + assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); + c->playback.memblock_index = 0; } - chunk.memblock->length = chunk.length = r; - chunk.index = 0; + if ((r = pa_iochannel_read(c->io, c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { + fprintf(stderr, __FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + return -1; + } + + chunk.memblock = c->playback.current_memblock; + chunk.index = c->playback.memblock_index; + chunk.length = r; + assert(chunk.memblock); + c->playback.memblock_index += r; + assert(c->input_memblockq); pa_memblockq_push_align(c->input_memblockq, &chunk, 0); - pa_memblock_unref(chunk.memblock); assert(c->sink_input); pa_sink_notify(c->sink_input->sink); @@ -485,33 +587,80 @@ static int do_read(struct connection *c) { } static int do_write(struct connection *c) { - ssize_t r; assert(c && c->io); - if (!pa_iochannel_is_writable(c->io)) - return 0; - - if (!c->write_data_length) - return 0; + if (c->write_data_length) { + ssize_t r; + + assert(c->write_data_index < c->write_data_length); + if ((r = pa_iochannel_write(c->io, c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { + fprintf(stderr, __FILE__": write() failed: %s\n", strerror(errno)); + return -1; + } + + if ((c->write_data_index +=r) >= c->write_data_length) + c->write_data_length = c->write_data_index = 0; + + } else if (c->state == ESD_STREAMING_DATA && c->source_output) { + struct pa_memchunk chunk; + ssize_t r; - assert(c->write_data_index < c->write_data_length); - if ((r = pa_iochannel_write(c->io, c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { - fprintf(stderr, "protocol-esound.c: write() failed: %s\n", strerror(errno)); - return -1; + assert(c->output_memblockq); + if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) + return 0; + + assert(chunk.memblock && chunk.length); + + if ((r = pa_iochannel_write(c->io, chunk.memblock->data+chunk.index, chunk.length)) < 0) { + pa_memblock_unref(chunk.memblock); + fprintf(stderr, __FILE__": write(): %s\n", strerror(errno)); + return -1; + } + + pa_memblockq_drop(c->output_memblockq, r); + pa_memblock_unref(chunk.memblock); } - - if ((c->write_data_index +=r) >= c->write_data_length) - c->write_data_length = c->write_data_index = 0; return 0; } +static void do_work(struct connection *c) { + assert(c); + + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); + c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 0); + + if (pa_iochannel_is_hungup(c->io)) + goto fail; + + if (pa_iochannel_is_writable(c->io)) + if (do_write(c) < 0) + goto fail; + + if (pa_iochannel_is_readable(c->io)) + if (do_read(c) < 0) + goto fail; + + return; + +fail: + connection_free(c); +} + static void io_callback(struct pa_iochannel*io, void *userdata) { struct connection *c = userdata; assert(io && c && c->io == io); - if (do_read(c) < 0 || do_write(c) < 0) - connection_free(c); + do_work(c); +} + +/*** fixed callback ***/ + +void fixed_callback(struct pa_mainloop_api*a, void *id, void *userdata) { + struct connection *c = userdata; + assert(a && c && c->fixed_source == id); + + do_work(c); } /*** sink_input callbacks ***/ @@ -532,9 +681,10 @@ static void sink_input_drop_cb(struct pa_sink_input *i, size_t length) { assert(i && c && length); pa_memblockq_drop(c->input_memblockq, length); - - if (do_read(c) < 0) - connection_free(c); + + /* do something */ + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); + c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); } static void sink_input_kill_cb(struct pa_sink_input *i) { @@ -549,6 +699,24 @@ static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { return pa_samples_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); } +/*** source_output callbacks ***/ + +static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk) { + struct connection *c = o->userdata; + assert(o && c && chunk); + + pa_memblockq_push(c->output_memblockq, chunk, 0); + + /* do something */ + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); + c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); +} + +static void source_output_kill_cb(struct pa_source_output *o) { + assert(o && o->userdata); + connection_free((struct connection *) o->userdata); +} + /*** socket server callback ***/ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { @@ -562,7 +730,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->io = io; pa_iochannel_set_callback(c->io, io_callback, c); - pa_iochannel_peer_to_string(io, cname, sizeof(cname)); + pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); assert(c->protocol->core); c->client = pa_client_new(c->protocol->core, "ESOUND", cname); assert(c->client); @@ -585,6 +753,17 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->sink_input = NULL; c->input_memblockq = NULL; + c->source_output = NULL; + c->output_memblockq = NULL; + + c->playback.current_memblock = NULL; + c->playback.memblock_index = 0; + c->playback.fragment_size = 0; + + c->fixed_source = c->protocol->core->mainloop->source_fixed(c->protocol->core->mainloop, fixed_callback, c); + assert(c->fixed_source); + c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 0); + pa_idxset_put(c->protocol->connections, c, &c->index); } @@ -608,7 +787,7 @@ struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa p->core = core; p->connections = pa_idxset_new(NULL, NULL); assert(p->connections); - p->sink_index = PA_IDXSET_INVALID; + p->sink_index = p->source_index = PA_IDXSET_INVALID; p->n_player = 0; return p; diff --git a/src/protocol-simple.c b/src/protocol-simple.c index 91eab59a..3e2e7fda 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -18,6 +18,12 @@ struct connection { struct pa_source_output *source_output; struct pa_client *client; struct pa_memblockq *input_memblockq, *output_memblockq; + void *fixed_source; + + struct { + struct pa_memblock *current_memblock; + size_t memblock_index, fragment_size; + } playback; }; struct pa_protocol_simple { @@ -29,13 +35,17 @@ struct pa_protocol_simple { }; #define PLAYBACK_BUFFER_SECONDS (.5) +#define PLAYBACK_BUFFER_FRAGMENTS (10) #define RECORD_BUFFER_SECONDS (5) +#define RECORD_BUFFER_FRAGMENTS (100) static void connection_free(struct connection *c) { assert(c); pa_idxset_remove_by_data(c->protocol->connections, c, NULL); + if (c->playback.current_memblock) + pa_memblock_unref(c->playback.current_memblock); if (c->sink_input) pa_sink_input_free(c->sink_input); if (c->source_output) @@ -48,34 +58,49 @@ static void connection_free(struct connection *c) { pa_memblockq_free(c->input_memblockq); if (c->output_memblockq) pa_memblockq_free(c->output_memblockq); + if (c->fixed_source) + c->protocol->core->mainloop->cancel_fixed(c->protocol->core->mainloop, c->fixed_source); free(c); } + static int do_read(struct connection *c) { struct pa_memchunk chunk; ssize_t r; size_t l; - if (!pa_iochannel_is_readable(c->io)) - return 0; - if (!c->sink_input || !(l = pa_memblockq_missing(c->input_memblockq))) return 0; - chunk.memblock = pa_memblock_new(l); - assert(chunk.memblock); + if (l > c->playback.fragment_size) + l = c->playback.fragment_size; - if ((r = pa_iochannel_read(c->io, chunk.memblock->data, l)) <= 0) { - fprintf(stderr, "read(): %s\n", r == 0 ? "EOF" : strerror(errno)); - pa_memblock_unref(chunk.memblock); + if (c->playback.current_memblock) + if (c->playback.current_memblock->length - c->playback.memblock_index < l) { + pa_memblock_unref(c->playback.current_memblock); + c->playback.current_memblock = NULL; + c->playback.memblock_index = 0; + } + + if (!c->playback.current_memblock) { + c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2); + assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); + c->playback.memblock_index = 0; + } + + if ((r = pa_iochannel_read(c->io, c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { + fprintf(stderr, __FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } - chunk.memblock->length = chunk.length = r; - chunk.index = 0; + chunk.memblock = c->playback.current_memblock; + chunk.index = c->playback.memblock_index; + chunk.length = r; + assert(chunk.memblock); + c->playback.memblock_index += r; + assert(c->input_memblockq); pa_memblockq_push_align(c->input_memblockq, &chunk, 0); - pa_memblock_unref(chunk.memblock); assert(c->sink_input); pa_sink_notify(c->sink_input->sink); @@ -86,29 +111,51 @@ static int do_write(struct connection *c) { struct pa_memchunk chunk; ssize_t r; - if (!pa_iochannel_is_writable(c->io)) - return 0; - if (!c->source_output) return 0; assert(c->output_memblockq); if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) return 0; - + assert(chunk.memblock && chunk.length); if ((r = pa_iochannel_write(c->io, chunk.memblock->data+chunk.index, chunk.length)) < 0) { - fprintf(stderr, "write(): %s\n", strerror(errno)); pa_memblock_unref(chunk.memblock); + fprintf(stderr, "write(): %s\n", strerror(errno)); return -1; } pa_memblockq_drop(c->output_memblockq, r); pa_memblock_unref(chunk.memblock); + return 0; } + +static void do_work(struct connection *c) { + assert(c); + + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); + c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 0); + + if (pa_iochannel_is_hungup(c->io)) + goto fail; + + if (pa_iochannel_is_writable(c->io)) + if (do_write(c) < 0) + goto fail; + + if (pa_iochannel_is_readable(c->io)) + if (do_read(c) < 0) + goto fail; + + return; + +fail: + connection_free(c); +} + /*** sink_input callbacks ***/ static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk) { @@ -127,9 +174,10 @@ static void sink_input_drop_cb(struct pa_sink_input *i, size_t length) { assert(i && c && length); pa_memblockq_drop(c->input_memblockq, length); - - if (do_read(c) < 0) - connection_free(c); + + /* do something */ + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); + c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); } static void sink_input_kill_cb(struct pa_sink_input *i) { @@ -152,8 +200,9 @@ static void source_output_push_cb(struct pa_source_output *o, const struct pa_me pa_memblockq_push(c->output_memblockq, chunk, 0); - if (do_write(c) < 0) - connection_free(c); + /* do something */ + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); + c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); } static void source_output_kill_cb(struct pa_source_output *o) { @@ -174,11 +223,19 @@ static void io_callback(struct pa_iochannel*io, void *userdata) { struct connection *c = userdata; assert(io && c && c->io == io); - if (do_read(c) < 0 || do_write(c) < 0) - connection_free(c); + do_work(c); } -/*** socket_server callbacks */ +/*** fixed callback ***/ + +void fixed_callback(struct pa_mainloop_api*a, void *id, void *userdata) { + struct connection *c = userdata; + assert(a && c && c->fixed_source == id); + + do_work(c); +} + +/*** socket_server callbacks ***/ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { struct pa_protocol_simple *p = userdata; @@ -191,34 +248,19 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->io = io; c->sink_input = NULL; c->source_output = NULL; + c->fixed_source = NULL; c->input_memblockq = c->output_memblockq = NULL; c->protocol = p; - - pa_iochannel_peer_to_string(io, cname, sizeof(cname)); + c->playback.current_memblock = NULL; + c->playback.memblock_index = 0; + c->playback.fragment_size = 0; + + pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); c->client = pa_client_new(p->core, "SIMPLE", cname); assert(c->client); c->client->kill = client_kill_cb; c->client->userdata = c; - if (p->mode & PA_PROTOCOL_SIMPLE_RECORD) { - struct pa_source *source; - size_t l; - - if (!(source = pa_source_get_default(p->core))) { - fprintf(stderr, "Failed to get default source.\n"); - goto fail; - } - - c->source_output = pa_source_output_new(source, c->client->name, &p->sample_spec); - assert(c->source_output); - c->source_output->push = source_output_push_cb; - c->source_output->kill = source_output_kill_cb; - c->source_output->userdata = c; - - l = (size_t) (pa_bytes_per_second(&p->sample_spec)*RECORD_BUFFER_SECONDS); - c->output_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&p->sample_spec), l/2, 0); - } - if (p->mode & PA_PROTOCOL_SIMPLE_PLAYBACK) { struct pa_sink *sink; size_t l; @@ -237,12 +279,40 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->sink_input->userdata = c; l = (size_t) (pa_bytes_per_second(&p->sample_spec)*PLAYBACK_BUFFER_SECONDS); - c->input_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&p->sample_spec), l/2, l/10); + c->input_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&p->sample_spec), l/2, l/PLAYBACK_BUFFER_FRAGMENTS); + assert(c->input_memblockq); + pa_iochannel_socket_set_rcvbuf(io, l/PLAYBACK_BUFFER_FRAGMENTS*5); + c->playback.fragment_size = l/10; } + if (p->mode & PA_PROTOCOL_SIMPLE_RECORD) { + struct pa_source *source; + size_t l; + + if (!(source = pa_source_get_default(p->core))) { + fprintf(stderr, "Failed to get default source.\n"); + goto fail; + } + + c->source_output = pa_source_output_new(source, c->client->name, &p->sample_spec); + assert(c->source_output); + c->source_output->push = source_output_push_cb; + c->source_output->kill = source_output_kill_cb; + c->source_output->userdata = c; + + l = (size_t) (pa_bytes_per_second(&p->sample_spec)*RECORD_BUFFER_SECONDS); + c->output_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&p->sample_spec), 0, 0); + pa_iochannel_socket_set_sndbuf(io, l/RECORD_BUFFER_FRAGMENTS*2); + } + pa_iochannel_set_callback(c->io, io_callback, c); pa_idxset_put(p->connections, c, NULL); + + c->fixed_source = p->core->mainloop->source_fixed(p->core->mainloop, fixed_callback, c); + assert(c->fixed_source); + p->core->mainloop->enable_fixed(p->core->mainloop, c->fixed_source, 0); + return; fail: diff --git a/src/sample-util.c b/src/sample-util.c index f37ac78b..5344ecfa 100644 --- a/src/sample-util.c +++ b/src/sample-util.c @@ -12,14 +12,12 @@ struct pa_sample_spec pa_default_sample_spec = { struct pa_memblock *pa_silence_memblock(struct pa_memblock* b, const struct pa_sample_spec *spec) { assert(b && b->data && spec); - pa_memblock_assert_exclusive(b); pa_silence_memory(b->data, b->length, spec); return b; } void pa_silence_memchunk(struct pa_memchunk *c, const struct pa_sample_spec *spec) { assert(c && c->memblock && c->memblock->data && spec && c->length); - pa_memblock_assert_exclusive(c->memblock); pa_silence_memory(c->memblock->data+c->index, c->length, spec); } @@ -96,7 +94,6 @@ void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, size_t n; assert(c && spec && (c->length % pa_sample_size(spec) == 0)); assert(spec->format == PA_SAMPLE_S16NE); - pa_memblock_assert_exclusive(c->memblock); if (volume == PA_VOLUME_NORM) return; diff --git a/src/simple.c b/src/simple.c index 50bfea43..ba0a8f0c 100644 --- a/src/simple.c +++ b/src/simple.c @@ -14,24 +14,37 @@ struct pa_simple { int dead, drained; }; +static int check_error(struct pa_simple *p, int *perror) { + assert(p); + + if (pa_context_is_dead(p->context) || (p->stream && pa_stream_is_dead(p->stream))) { + if (perror) + *perror = pa_context_errno(p->context); + return -1; + } + + return 0; +} + static int iterate(struct pa_simple *p, int block, int *perror) { assert(p && p->context && p->mainloop); + if (check_error(p, perror) < 0) + return -1; + if (!block && !pa_context_is_pending(p->context)) return 0; - + do { - if (pa_context_is_dead(p->context) || (p->stream && pa_stream_is_dead(p->stream))) { - if (perror) - *perror = pa_context_errno(p->context); - return -1; - } - if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) { if (perror) *perror = PA_ERROR_INTERNAL; return -1; } + + if (check_error(p, perror) < 0) + return -1; + } while (pa_context_is_pending(p->context)); return 0; diff --git a/src/sink.c b/src/sink.c index 4852edcc..80560724 100644 --- a/src/sink.c +++ b/src/sink.c @@ -174,7 +174,6 @@ int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target) { unsigned n; size_t l; assert(s && target && target->length && target->memblock && target->memblock->data); - pa_memblock_assert_exclusive(target->memblock); n = fill_mix_info(s, info, MAX_MIX_CHANNELS); diff --git a/src/sinkinput.c b/src/sinkinput.c index 20ab25ea..f3e474bc 100644 --- a/src/sinkinput.c +++ b/src/sinkinput.c @@ -89,8 +89,7 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { pa_sample_snprint(ss, sizeof(ss), &i->sample_spec); assert(i->sink); pa_strbuf_printf( - s, - " index: %u\n\tname: <%s>\n\tsink: <%u>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tsample_spec: <%s>\n", + s, " index: %u\n\tname: <%s>\n\tsink: <%u>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tsample_spec: <%s>\n", i->index, i->name, i->sink->index, diff --git a/src/socket-client.c b/src/socket-client.c index 6ff11980..9a8c5607 100644 --- a/src/socket-client.c +++ b/src/socket-client.c @@ -120,7 +120,7 @@ struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, ui goto fail; } - pa_make_tcp_socket_low_delay(c->fd); + pa_socket_tcp_low_delay(c->fd); sa.sin_family = AF_INET; sa.sin_port = htons(port); @@ -149,7 +149,7 @@ struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, co goto fail; } - pa_make_socket_low_delay(c->fd); + pa_socket_low_delay(c->fd); sa.sun_family = AF_LOCAL; strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); diff --git a/src/socket-server.c b/src/socket-server.c index 6a7d9415..23d8f7e7 100644 --- a/src/socket-server.c +++ b/src/socket-server.c @@ -43,9 +43,9 @@ static void callback(struct pa_mainloop_api *mainloop, void *id, int fd, enum pa /* There should be a check for socket type here */ if (s->type == SOCKET_SERVER_IPV4) - pa_make_tcp_socket_low_delay(fd); + pa_socket_tcp_low_delay(fd); else - pa_make_socket_low_delay(fd); + pa_socket_low_delay(fd); io = pa_iochannel_new(s->mainloop, nfd, nfd); assert(io); @@ -88,7 +88,7 @@ struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, co strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); sa.sun_path[sizeof(sa.sun_path) - 1] = 0; - pa_make_socket_low_delay(fd); + pa_socket_low_delay(fd); if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) { fprintf(stderr, "bind(): %s\n", strerror(errno)); @@ -133,7 +133,7 @@ struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, ui if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) fprintf(stderr, "setsockopt(): %s\n", strerror(errno)); - pa_make_tcp_socket_low_delay(fd); + pa_socket_tcp_low_delay(fd); sa.sin_family = AF_INET; sa.sin_port = htons(port); diff --git a/src/sourceoutput.c b/src/sourceoutput.c index 388f1225..442dc7f4 100644 --- a/src/sourceoutput.c +++ b/src/sourceoutput.c @@ -72,11 +72,10 @@ char *pa_source_output_list_to_string(struct pa_core *c) { pa_sample_snprint(ss, sizeof(ss), &o->sample_spec); assert(o->source); pa_strbuf_printf( - s, " %c index: %u\n\tname: <%s>\n\tsource: <%u>\n\tsample_spec: <%u>\n", + s, " index: %u\n\tname: <%s>\n\tsource: <%u>\n\tsample_spec: <%s>\n", o->index, o->name, o->source->index, - ss, ss); } diff --git a/src/todo b/src/todo index 93ba2821..18da09d8 100644 --- a/src/todo +++ b/src/todo @@ -1,14 +1,20 @@ -- recording (general, simple, esound, native) +- recording (esound, native) - native library/protocol: more functions (esp. latency) -- simple library - config parser/cmdline +- description field for all entities +- client field for sinkinput/sourceoutput +- module field for all entities + - move more stuff from module-oss[-dma] to liboss-util - in module-oss: create source first, than sink -- client field for sinkinput/sourceoutput +- merge memchunks in memblockq + +- create libstatustext, libsocketutil +- prefix modules/libraries with pa_ - xmms+esound latency testing @@ -16,6 +22,8 @@ - svn-id and license in every file - documentation + + -- post 0.1 - future cancellation - client-ui diff --git a/src/util.c b/src/util.c index 3111bd5d..6fe4bbee 100644 --- a/src/util.c +++ b/src/util.c @@ -87,36 +87,27 @@ fail: return -1; } -int pa_make_socket_low_delay(int fd) { - int ret = 0, buf_size, priority; - +int pa_socket_low_delay(int fd) { + int priority; assert(fd >= 0); - buf_size = 1024; - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof(buf_size)) < 0) - ret = -1; - - buf_size = 1024; - if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(buf_size)) < 0) - ret = -1; - priority = 7; if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) - ret = -1; + return -1; - return ret; + return 0; } -int pa_make_tcp_socket_low_delay(int fd) { - int ret, tos, on; - +int pa_socket_tcp_low_delay(int fd) { + int ret, tos; + assert(fd >= 0); - ret = pa_make_socket_low_delay(fd); + ret = pa_socket_low_delay(fd); - on = 1; - if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) - ret = -1; +/* on = 1; */ +/* if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) */ +/* ret = -1; */ tos = IPTOS_LOWDELAY; if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0) @@ -126,6 +117,24 @@ int pa_make_tcp_socket_low_delay(int fd) { } +int pa_socket_set_rcvbuf(int fd, size_t l) { + assert(fd >= 0); + + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &l, sizeof(l)) < 0) + return -1; + + return 0; +} + +int pa_socket_set_sndbuf(int fd, size_t l) { + assert(fd >= 0); + + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &l, sizeof(l)) < 0) + return -1; + + return 0; +} + ssize_t pa_loop_read(int fd, void*data, size_t size) { ssize_t ret = 0; assert(fd >= 0 && data && size); diff --git a/src/util.h b/src/util.h index ad9916e7..dba89ee8 100644 --- a/src/util.h +++ b/src/util.h @@ -9,8 +9,11 @@ void pa_peer_to_string(char *c, size_t l, int fd); int pa_make_secure_dir(const char* dir); -int pa_make_socket_low_delay(int fd); -int pa_make_tcp_socket_low_delay(int fd); +int pa_socket_low_delay(int fd); +int pa_socket_tcp_low_delay(int fd); + +int pa_socket_set_sndbuf(int fd, size_t l); +int pa_socket_set_rcvbuf(int fd, size_t l); ssize_t pa_loop_read(int fd, void*data, size_t size); ssize_t pa_loop_write(int fd, const void*data, size_t size); -- cgit From 70bb8165ec0aefef08d524dc72baa29df658b4c0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 10 Jul 2004 16:50:22 +0000 Subject: implement recording in native API fix a memory leak in memblock.c git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@55 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/memblock.c | 13 ++-- src/module-oss-mmap.c | 55 +++++--------- src/pacat.c | 89 ++++++++++++++++++++--- src/polyp.c | 21 ++++-- src/polypdef.h | 1 + src/protocol-esound.c | 5 +- src/protocol-native.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++---- src/protocol-simple.c | 12 ++- src/pstream.c | 54 ++++++++------ src/pstream.h | 4 +- src/todo | 4 +- 11 files changed, 349 insertions(+), 107 deletions(-) diff --git a/src/memblock.c b/src/memblock.c index af57e3a4..2dfa6a9c 100644 --- a/src/memblock.c +++ b/src/memblock.c @@ -69,12 +69,13 @@ void pa_memblock_unref_fixed(struct pa_memblock *b) { if (b->ref == 1) { pa_memblock_unref(b); return; + } else { + d = malloc(b->length); + assert(d); + memcpy(d, b->data, b->length); + b->data = d; + b->type = PA_MEMBLOCK_DYNAMIC; + b->ref--; } - - d = malloc(b->length); - assert(d); - memcpy(d, b->data, b->length); - b->data = d; - b->type = PA_MEMBLOCK_DYNAMIC; } diff --git a/src/module-oss-mmap.c b/src/module-oss-mmap.c index a9cf84f3..280484d0 100644 --- a/src/module-oss-mmap.c +++ b/src/module-oss-mmap.c @@ -39,26 +39,6 @@ struct userdata { void module_done(struct pa_core *c, struct pa_module*m); -static void out_clear_memblocks(struct userdata*u, unsigned n) { - unsigned i = u->out_current; - assert(u && u->out_memblocks); - - if (n > u->out_fragments) - n = u->out_fragments; - - while (n > 0) { - if (u->out_memblocks[i]) { - pa_memblock_unref_fixed(u->out_memblocks[i]); - u->out_memblocks[i] = NULL; - } - - i++; - while (i >= u->out_fragments) - i -= u->out_fragments; - - n--; - } -} static void out_fill_memblocks(struct userdata *u, unsigned n) { assert(u && u->out_memblocks); @@ -66,14 +46,15 @@ static void out_fill_memblocks(struct userdata *u, unsigned n) { while (n > 0) { struct pa_memchunk chunk; - if (!u->out_memblocks[u->out_current]) { - - chunk.memblock = u->out_memblocks[u->out_current] = pa_memblock_new_fixed(u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size); - chunk.length = chunk.memblock->length; - chunk.index = 0; - - pa_sink_render_into_full(u->sink, &chunk); - } + if (u->out_memblocks[u->out_current]) + pa_memblock_unref_fixed(u->out_memblocks[u->out_current]); + + chunk.memblock = u->out_memblocks[u->out_current] = pa_memblock_new_fixed(u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size); + assert(chunk.memblock); + chunk.length = chunk.memblock->length; + chunk.index = 0; + + pa_sink_render_into_full(u->sink, &chunk); u->out_current++; while (u->out_current >= u->out_fragments) @@ -97,9 +78,7 @@ static void do_write(struct userdata *u) { if (!info.blocks) return; - out_clear_memblocks(u, info.blocks); out_fill_memblocks(u, info.blocks); - } static void in_post_memblocks(struct userdata *u, unsigned n) { @@ -109,7 +88,7 @@ static void in_post_memblocks(struct userdata *u, unsigned n) { struct pa_memchunk chunk; if (!u->in_memblocks[u->in_current]) { - u->in_memblocks[u->in_current] = chunk.memblock = pa_memblock_new_fixed(u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size); + chunk.memblock = u->in_memblocks[u->in_current] = pa_memblock_new_fixed(u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size); chunk.length = chunk.memblock->length; chunk.index = 0; @@ -262,7 +241,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { } } else { - u->source = pa_source_new(c, "dsp", 0, &u->sample_spec); + u->source = pa_source_new(c, "oss_input", 0, &u->sample_spec); assert(u->source); u->source->userdata = u; @@ -293,7 +272,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { } else { pa_silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec); - u->sink = pa_sink_new(c, "dsp", 0, &u->sample_spec); + u->sink = pa_sink_new(c, "oss_output", 0, &u->sample_spec); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; u->sink->userdata = u; @@ -337,12 +316,18 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { assert(u); if (u->out_memblocks) { - out_clear_memblocks(u, u->out_fragments); + unsigned i; + for (i = 0; i < u->out_fragments; i++) + if (u->out_memblocks[i]) + pa_memblock_unref_fixed(u->out_memblocks[i]); free(u->out_memblocks); } if (u->in_memblocks) { - in_clear_memblocks(u, u->in_fragments); + unsigned i; + for (i = 0; i < u->in_fragments; i++) + if (u->in_memblocks[i]) + pa_memblock_unref_fixed(u->in_memblocks[i]); free(u->in_memblocks); } diff --git a/src/pacat.c b/src/pacat.c index 4fdf3f69..80d4835f 100644 --- a/src/pacat.c +++ b/src/pacat.c @@ -11,6 +11,8 @@ #include "mainloop.h" #include "mainloop-signal.h" +static enum { RECORD, PLAYBACK } mode = PLAYBACK; + static struct pa_context *context = NULL; static struct pa_stream *stream = NULL; static struct pa_mainloop_api *mainloop_api = NULL; @@ -18,7 +20,7 @@ static struct pa_mainloop_api *mainloop_api = NULL; static void *buffer = NULL; static size_t buffer_length = 0, buffer_index = 0; -static void* stdin_source = NULL; +static void* stdio_source = NULL; static void quit(int ret) { assert(mainloop_api); @@ -37,7 +39,7 @@ static void stream_die_callback(struct pa_stream *s, void *userdata) { quit(1); } -static void do_write(size_t length) { +static void do_stream_write(size_t length) { size_t l; assert(length); @@ -62,13 +64,30 @@ static void do_write(size_t length) { static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) { assert(s && length); - if (stdin_source) - mainloop_api->enable_io(mainloop_api, stdin_source, PA_MAINLOOP_API_IO_EVENT_INPUT); + if (stdio_source) + mainloop_api->enable_io(mainloop_api, stdio_source, PA_MAINLOOP_API_IO_EVENT_INPUT); if (!buffer) return; - do_write(length); + do_stream_write(length); +} + +static void stream_read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata) { + assert(s && data && length); + + if (stdio_source) + mainloop_api->enable_io(mainloop_api, stdio_source, PA_MAINLOOP_API_IO_EVENT_OUTPUT); + + if (buffer) { + fprintf(stderr, "Buffer overrrun, dropping incoming data\n"); + return; + } + + buffer = malloc(buffer_length = length); + assert(buffer); + memcpy(buffer, data, length); + buffer_index = 0; } static void stream_complete_callback(struct pa_stream*s, int success, void *userdata) { @@ -99,13 +118,14 @@ static void context_complete_callback(struct pa_context *c, int success, void *u fprintf(stderr, "Connection established.\n"); - if (!(stream = pa_stream_new(c, PA_STREAM_PLAYBACK, NULL, "pacat", &ss, NULL, stream_complete_callback, NULL))) { + if (!(stream = pa_stream_new(c, mode == PLAYBACK ? PA_STREAM_PLAYBACK : PA_STREAM_RECORD, NULL, "pacat", &ss, NULL, stream_complete_callback, NULL))) { fprintf(stderr, "pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(c))); goto fail; } pa_stream_set_die_callback(stream, stream_die_callback, NULL); pa_stream_set_write_callback(stream, stream_write_callback, NULL); + pa_stream_set_read_callback(stream, stream_read_callback, NULL); return; @@ -132,10 +152,10 @@ static void stream_drain_complete(struct pa_stream*s, void *userdata) { static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { size_t l, w = 0; ssize_t r; - assert(a == mainloop_api && id && fd == STDIN_FILENO && stdin_source == id); + assert(a == mainloop_api && id && stdio_source == id); if (buffer) { - mainloop_api->enable_io(mainloop_api, stdin_source, PA_MAINLOOP_API_IO_EVENT_NULL); + mainloop_api->enable_io(mainloop_api, stdio_source, PA_MAINLOOP_API_IO_EVENT_NULL); return; } @@ -153,8 +173,8 @@ static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_m quit(1); } - mainloop_api->cancel_io(mainloop_api, stdin_source); - stdin_source = NULL; + mainloop_api->cancel_io(mainloop_api, stdio_source); + stdio_source = NULL; return; } @@ -162,9 +182,38 @@ static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_m buffer_index = 0; if (w) - do_write(w); + do_stream_write(w); } +static void stdout_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { + ssize_t r; + assert(a == mainloop_api && id && stdio_source == id); + + if (!buffer) { + mainloop_api->enable_io(mainloop_api, stdio_source, PA_MAINLOOP_API_IO_EVENT_NULL); + return; + } + + assert(buffer_length); + + if ((r = write(fd, buffer+buffer_index, buffer_length)) <= 0) { + fprintf(stderr, "write() failed: %s\n", strerror(errno)); + quit(1); + + mainloop_api->cancel_io(mainloop_api, stdio_source); + stdio_source = NULL; + return; + } + + buffer_length -= r; + buffer_index += r; + + if (!buffer_length) { + free(buffer); + buffer = NULL; + buffer_length = buffer_index = 0; + } +} static void exit_signal_callback(void *id, int sig, void *userdata) { fprintf(stderr, "Got SIGINT, exiting.\n"); @@ -175,7 +224,18 @@ static void exit_signal_callback(void *id, int sig, void *userdata) { int main(int argc, char *argv[]) { struct pa_mainloop* m; int ret = 1, r; + char *bn; + if (!(bn = strrchr(argv[0], '/'))) + bn = argv[0]; + + if (strstr(bn, "rec") || strstr(bn, "mon")) + mode = RECORD; + else if (strstr(bn, "cat") || strstr(bn, "play")) + mode = PLAYBACK; + + fprintf(stderr, "Opening a %s stream.\n", mode == RECORD ? "recording" : "playback"); + if (!(m = pa_mainloop_new())) { fprintf(stderr, "pa_mainloop_new() failed.\n"); goto quit; @@ -188,7 +248,10 @@ int main(int argc, char *argv[]) { pa_signal_register(SIGINT, exit_signal_callback, NULL); signal(SIGPIPE, SIG_IGN); - if (!(stdin_source = mainloop_api->source_io(mainloop_api, STDIN_FILENO, PA_MAINLOOP_API_IO_EVENT_INPUT, stdin_callback, NULL))) { + if (!(stdio_source = mainloop_api->source_io(mainloop_api, + mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO, + mode == PLAYBACK ? PA_MAINLOOP_API_IO_EVENT_INPUT : PA_MAINLOOP_API_IO_EVENT_OUTPUT, + mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) { fprintf(stderr, "source_io() failed.\n"); goto quit; } @@ -215,6 +278,8 @@ quit: pa_stream_free(stream); if (context) pa_context_free(context); + + pa_signal_done(); if (m) pa_mainloop_free(m); if (buffer) diff --git a/src/polyp.c b/src/polyp.c index 6bc7ab33..2c2810fb 100644 --- a/src/polyp.c +++ b/src/polyp.c @@ -13,10 +13,11 @@ #include "authkey.h" #include "util.h" -#define DEFAULT_MAXLENGTH 20480 +#define DEFAULT_MAXLENGTH 204800 #define DEFAULT_TLENGTH 10240 #define DEFAULT_PREBUF 4096 #define DEFAULT_MINREQ 1024 +#define DEFAULT_FRAGSIZE 1024 #define DEFAULT_TIMEOUT (5*60) #define DEFAULT_SERVER "/tmp/polypaudio/native" @@ -187,7 +188,7 @@ static void context_dead(struct pa_context *c) { if (c->die_callback) c->die_callback(c, c->die_userdata); } else - s->state = CONTEXT_DEAD; + c->state = CONTEXT_DEAD; } static void pstream_die_callback(struct pa_pstream *p, void *userdata) { @@ -206,7 +207,7 @@ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *pack } } -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata) { +static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { struct pa_context *c = userdata; struct pa_stream *s; assert(p && chunk && c && chunk->memblock && chunk->memblock->data); @@ -378,7 +379,7 @@ static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t s->write_callback(s, s->requested_bytes, s->write_userdata); } -static void create_playback_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_stream *s = userdata; assert(pd && s && s->state == STREAM_CREATING); @@ -427,12 +428,15 @@ static void create_stream(struct pa_stream *s, uint32_t tdev_index) { pa_tagstruct_put_sample_spec(t, &s->sample_spec); pa_tagstruct_putu32(t, tdev_index); pa_tagstruct_putu32(t, s->buffer_attr.maxlength); - pa_tagstruct_putu32(t, s->buffer_attr.tlength); - pa_tagstruct_putu32(t, s->buffer_attr.prebuf); - pa_tagstruct_putu32(t, s->buffer_attr.minreq); + if (s->direction == PA_STREAM_PLAYBACK) { + pa_tagstruct_putu32(t, s->buffer_attr.tlength); + pa_tagstruct_putu32(t, s->buffer_attr.prebuf); + pa_tagstruct_putu32(t, s->buffer_attr.minreq); + } else + pa_tagstruct_putu32(t, s->buffer_attr.fragsize); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_playback_callback, s); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); } static void lookup_device_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { @@ -522,6 +526,7 @@ struct pa_stream* pa_stream_new( s->buffer_attr.tlength = DEFAULT_TLENGTH; s->buffer_attr.prebuf = DEFAULT_PREBUF; s->buffer_attr.minreq = DEFAULT_MINREQ; + s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; } s->next = c->first_stream; diff --git a/src/polypdef.h b/src/polypdef.h index 80b3cc6c..6cfafc97 100644 --- a/src/polypdef.h +++ b/src/polypdef.h @@ -13,6 +13,7 @@ struct pa_buffer_attr { uint32_t tlength; uint32_t prebuf; uint32_t minreq; + uint32_t fragsize; }; diff --git a/src/protocol-esound.c b/src/protocol-esound.c index 3dd9655b..e97ab34d 100644 --- a/src/protocol-esound.c +++ b/src/protocol-esound.c @@ -580,9 +580,8 @@ static int do_read(struct connection *c) { assert(c->sink_input); pa_sink_notify(c->sink_input->sink); - } else - assert(0); - + } + return 0; } diff --git a/src/protocol-native.c b/src/protocol-native.c index 110d0d6b..fe086066 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -24,6 +24,7 @@ struct record_stream { uint32_t index; struct pa_source_output *source_output; struct pa_memblockq *memblockq; + size_t fragment_size; }; struct playback_stream { @@ -43,6 +44,7 @@ struct connection { struct pa_pstream *pstream; struct pa_pdispatch *pdispatch; struct pa_idxset *record_streams, *playback_streams; + uint32_t rrobin_index; }; struct pa_protocol_native { @@ -60,10 +62,15 @@ static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i); static void request_bytes(struct playback_stream*s); +static void source_output_kill_cb(struct pa_source_output *o); +static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk); + static void command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_delete_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_delete_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); @@ -75,8 +82,8 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { command_create_playback_stream }, [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { command_delete_playback_stream }, [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = { command_drain_playback_stream }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_CREATE_RECORD_STREAM] = { command_create_record_stream }, + [PA_COMMAND_DELETE_RECORD_STREAM] = { command_delete_record_stream }, [PA_COMMAND_AUTH] = { command_auth }, [PA_COMMAND_REQUEST] = { NULL }, [PA_COMMAND_EXIT] = { command_exit }, @@ -87,6 +94,34 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { /* structure management */ +static struct record_stream* record_stream_new(struct connection *c, struct pa_source *source, struct pa_sample_spec *ss, const char *name, size_t maxlength, size_t fragment_size) { + struct record_stream *s; + struct pa_source_output *source_output; + size_t base; + assert(c && source && ss && name && maxlength); + + if (!(source_output = pa_source_output_new(source, name, ss))) + return NULL; + + s = malloc(sizeof(struct record_stream)); + assert(s); + s->connection = c; + s->source_output = source_output; + s->source_output->push = source_output_push_cb; + s->source_output->kill = source_output_kill_cb; + s->source_output->userdata = s; + + s->memblockq = pa_memblockq_new(maxlength, 0, base = pa_sample_size(ss), 0, 0); + assert(s->memblockq); + + s->fragment_size = (fragment_size/base)*base; + if (!s->fragment_size) + s->fragment_size = base; + + pa_idxset_put(c->record_streams, s, &s->index); + return s; +} + static void record_stream_free(struct record_stream* r) { assert(r && r->connection); @@ -102,14 +137,17 @@ static struct playback_stream* playback_stream_new(struct connection *c, struct size_t prebuf, size_t minreq) { struct playback_stream *s; + struct pa_sink_input *sink_input; assert(c && sink && ss && name && maxlength); + if (!(sink_input = pa_sink_input_new(sink, name, ss))) + return NULL; + s = malloc(sizeof(struct playback_stream)); assert (s); s->connection = c; + s->sink_input = sink_input; - s->sink_input = pa_sink_input_new(sink, name, ss); - assert(s->sink_input); s->sink_input->peek = sink_input_peek_cb; s->sink_input->drop = sink_input_drop_cb; s->sink_input->kill = sink_input_kill_cb; @@ -187,6 +225,35 @@ static void request_bytes(struct playback_stream *s) { /*fprintf(stderr, "Requesting %u bytes\n", l);*/ } +static void send_memblock(struct connection *c) { + uint32_t start; + struct record_stream *r; + + start = PA_IDXSET_INVALID; + for (;;) { + struct pa_memchunk chunk; + + if (!(r = pa_idxset_rrobin(c->record_streams, &c->rrobin_index))) + return; + + if (start == PA_IDXSET_INVALID) + start = c->rrobin_index; + else if (start == c->rrobin_index) + return; + + if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) { + if (chunk.length > r->fragment_size) + chunk.length = r->fragment_size; + + pa_pstream_send_memblock(c->pstream, r->index, 0, &chunk); + pa_memblockq_drop(r->memblockq, chunk.length); + pa_memblock_unref(chunk.memblock); + + return; + } + } +} + /*** sinkinput callbacks ***/ static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk) { @@ -215,11 +282,8 @@ static void sink_input_drop_cb(struct pa_sink_input *i, size_t length) { } static void sink_input_kill_cb(struct pa_sink_input *i) { - struct playback_stream *s; assert(i && i->userdata); - s = i->userdata; - - playback_stream_free(s); + playback_stream_free((struct playback_stream *) i->userdata); } static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { @@ -230,6 +294,23 @@ static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { return pa_samples_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec); } +/*** source_output callbacks ***/ + +static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk) { + struct record_stream *s; + assert(o && o->userdata && chunk); + s = o->userdata; + + pa_memblockq_push(s->memblockq, chunk, 0); + if (!pa_pstream_is_pending(s->connection->pstream)) + send_memblock(s->connection); +} + +static void source_output_kill_cb(struct pa_source_output *o) { + assert(o && o->userdata); + record_stream_free((struct record_stream *) o->userdata); +} + /*** pdispatch callbacks ***/ static void protocol_error(struct connection *c) { @@ -313,6 +394,84 @@ static void command_delete_playback_stream(struct pa_pdispatch *pd, uint32_t com return; } + playback_stream_free(s); + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + struct record_stream *s; + size_t maxlength, fragment_size; + uint32_t source_index; + const char *name; + struct pa_sample_spec ss; + struct pa_tagstruct *reply; + struct pa_source *source; + assert(c && t && c->protocol && c->protocol->core); + + if (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_getu32(t, &source_index) < 0 || + pa_tagstruct_getu32(t, &maxlength) < 0 || + pa_tagstruct_getu32(t, &fragment_size) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (source_index == (uint32_t) -1) + source = pa_source_get_default(c->protocol->core); + else + source = pa_idxset_get_by_index(c->protocol->core->sources, source_index); + + if (!source) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + if (!(s = record_stream_new(c, source, &ss, name, maxlength, fragment_size))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, s->index); + assert(s->source_output); + pa_tagstruct_putu32(reply, s->source_output->index); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_delete_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t channel; + struct record_stream *s; + assert(c && t); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + return; + } + + record_stream_free(s); pa_pstream_send_simple_ack(c->pstream, tag); } @@ -449,7 +608,7 @@ static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t comm /*** pstream callbacks ***/ -static void packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { +static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { struct connection *c = userdata; assert(p && packet && packet->data && c); @@ -459,7 +618,7 @@ static void packet_callback(struct pa_pstream *p, struct pa_packet *packet, void } } -static void memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata) { +static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { struct connection *c = userdata; struct playback_stream *stream; assert(p && chunk && userdata); @@ -482,7 +641,7 @@ static void memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t de /*fprintf(stderr, "Recieved %u bytes.\n", chunk->length);*/ } -static void die_callback(struct pa_pstream *p, void *userdata) { +static void pstream_die_callback(struct pa_pstream *p, void *userdata) { struct connection *c = userdata; assert(p && c); connection_free(c); @@ -490,6 +649,14 @@ static void die_callback(struct pa_pstream *p, void *userdata) { fprintf(stderr, "protocol-native: connection died.\n"); } + +static void pstream_drain_callback(struct pa_pstream *p, void *userdata) { + struct connection *c = userdata; + assert(p && c); + + send_memblock(c); +} + /*** client callbacks ***/ static void client_kill_cb(struct pa_client *c) { @@ -516,9 +683,10 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->pstream = pa_pstream_new(p->core->mainloop, io); assert(c->pstream); - pa_pstream_set_recieve_packet_callback(c->pstream, packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, memblock_callback, c); - pa_pstream_set_die_callback(c->pstream, die_callback, c); + pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); + pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); + pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); + pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); c->pdispatch = pa_pdispatch_new(p->core->mainloop, command_table, PA_COMMAND_MAX); assert(c->pdispatch); @@ -527,6 +695,8 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->playback_streams = pa_idxset_new(NULL, NULL); assert(c->record_streams && c->playback_streams); + c->rrobin_index = PA_IDXSET_INVALID; + pa_idxset_put(p->connections, c, NULL); } diff --git a/src/protocol-simple.c b/src/protocol-simple.c index 3e2e7fda..e7ca0a76 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -271,7 +271,11 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo } c->sink_input = pa_sink_input_new(sink, c->client->name, &p->sample_spec); - assert(c->sink_input); + if (!c->sink_input) { + fprintf(stderr, "Failed to create sink input.\n"); + goto fail; + } + c->sink_input->peek = sink_input_peek_cb; c->sink_input->drop = sink_input_drop_cb; c->sink_input->kill = sink_input_kill_cb; @@ -296,7 +300,11 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo } c->source_output = pa_source_output_new(source, c->client->name, &p->sample_spec); - assert(c->source_output); + if (!c->source_output) { + fprintf(stderr, "Failed to create source output.\n"); + goto fail; + } + c->source_output->push = source_output_push_cb; c->source_output->kill = source_output_kill_cb; c->source_output->userdata = c; diff --git a/src/pstream.c b/src/pstream.c index 19f83e30..18d33b0d 100644 --- a/src/pstream.c +++ b/src/pstream.c @@ -38,7 +38,7 @@ struct pa_pstream { int in_use, shall_free; int dead; - void (*die_callback) (struct pa_pstream *p, void *userdad); + void (*die_callback) (struct pa_pstream *p, void *userdata); void *die_callback_userdata; struct { @@ -59,7 +59,7 @@ struct pa_pstream { void (*recieve_packet_callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata); void *recieve_packet_callback_userdata; - void (*recieve_memblock_callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata); + void (*recieve_memblock_callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata); void *recieve_memblock_callback_userdata; void (*drain_callback)(struct pa_pstream *p, void *userdata); @@ -73,21 +73,36 @@ static void do_something(struct pa_pstream *p) { assert(p && !p->shall_free); p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 0); - p->in_use = 1; - do_write(p); - p->in_use = 0; + if (p->dead) + return; + + if (pa_iochannel_is_hungup(p->io)) { + p->dead = 1; + if (p->die_callback) + p->die_callback(p, p->die_callback_userdata); - if (p->shall_free) { - pa_pstream_free(p); return; } - - p->in_use = 1; - do_read(p); - p->in_use = 0; - if (p->shall_free) { - pa_pstream_free(p); - return; + + if (pa_iochannel_is_writable(p->io)) { + p->in_use = 1; + do_write(p); + p->in_use = 0; + + if (p->shall_free) { + pa_pstream_free(p); + return; + } + } + + if (pa_iochannel_is_readable(p->io)) { + p->in_use = 1; + do_read(p); + p->in_use = 0; + if (p->shall_free) { + pa_pstream_free(p); + return; + } } } @@ -199,7 +214,7 @@ void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet) { p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 1); } -void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk) { +void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk) { struct item_info *i; assert(p && channel != (uint32_t) -1 && chunk); @@ -223,7 +238,7 @@ void pa_pstream_set_recieve_packet_callback(struct pa_pstream *p, void (*callbac p->recieve_packet_callback_userdata = userdata; } -void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata), void *userdata) { +void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata), void *userdata) { assert(p && callback); p->recieve_memblock_callback = callback; @@ -259,9 +274,6 @@ static void do_write(struct pa_pstream *p) { ssize_t r; assert(p); - if (p->dead || !pa_iochannel_is_writable(p->io)) - return; - if (!p->write.current) prepare_next_write_item(p); @@ -306,9 +318,6 @@ static void do_read(struct pa_pstream *p) { ssize_t r; assert(p); - if (p->dead || !pa_iochannel_is_readable(p->io)) - return; - if (p->read.index < PA_PSTREAM_DESCRIPTOR_SIZE) { d = (void*) p->read.descriptor + p->read.index; l = PA_PSTREAM_DESCRIPTOR_SIZE - p->read.index; @@ -416,7 +425,6 @@ int pa_pstream_is_pending(struct pa_pstream *p) { void pa_pstream_set_drain_callback(struct pa_pstream *p, void (*cb)(struct pa_pstream *p, void *userdata), void *userdata) { assert(p); - assert(!cb || pa_pstream_is_pending(p)); p->drain_callback = cb; p->drain_userdata = userdata; diff --git a/src/pstream.h b/src/pstream.h index 011b8d12..8525cb22 100644 --- a/src/pstream.h +++ b/src/pstream.h @@ -17,10 +17,10 @@ struct pa_pstream* pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel void pa_pstream_free(struct pa_pstream*p); void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet); -void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk); +void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk); void pa_pstream_set_recieve_packet_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata), void *userdata); -void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, struct pa_memchunk *chunk, void *userdata), void *userdata); +void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata), void *userdata); void pa_pstream_set_drain_callback(struct pa_pstream *p, void (*cb)(struct pa_pstream *p, void *userdata), void *userdata); void pa_pstream_set_die_callback(struct pa_pstream *p, void (*callback)(struct pa_pstream *p, void *userdata), void *userdata); diff --git a/src/todo b/src/todo index 18da09d8..ee971ca0 100644 --- a/src/todo +++ b/src/todo @@ -1,4 +1,4 @@ -- recording (esound, native) +- implement parec-simple - native library/protocol: more functions (esp. latency) @@ -9,7 +9,6 @@ - module field for all entities - move more stuff from module-oss[-dma] to liboss-util -- in module-oss: create source first, than sink - merge memchunks in memblockq @@ -41,3 +40,4 @@ drivers: modules: - alsa? +- http -- cgit From 5ea96e312be3aa495e77786283e1edea7592047f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 10 Jul 2004 19:04:21 +0000 Subject: implement parec-simple and matching simple recording API add support for killing source outputs in native protocol fix channel management in client library git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@56 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 6 +++- src/polyp-error.c | 5 +++- src/polyp.c | 47 +++++++++++++++++++++++++------ src/protocol-native-spec.h | 4 +++ src/protocol-native.c | 27 ++++++++++++++++++ src/simple.c | 70 +++++++++++++++++++++++++++++++++++++++++++--- src/todo | 3 +- 7 files changed, 145 insertions(+), 17 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index d7002caf..b02bfba6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,7 +18,7 @@ AM_CFLAGS=-ansi -D_GNU_SOURCE -bin_PROGRAMS = polypaudio pacat pacat-simple +bin_PROGRAMS = polypaudio pacat pacat-simple parec-simple pkglib_LTLIBRARIES=libiochannel.la \ libsocket-server.la \ @@ -248,3 +248,7 @@ pacat_CFLAGS = $(AM_CFLAGS) pacat_simple_SOURCES = pacat-simple.c $(libpolyp_la_SOURCES) $(libpolyp_simple_la_SOURCES) $(libpolyp_error_la_SOURCES) #pacat_simple_LDADD = libpolyp-simple.la libpolyp-error.la pacat_simple_CFLAGS = $(AM_CFLAGS) + +parec_simple_SOURCES = parec-simple.c $(libpolyp_la_SOURCES) $(libpolyp_simple_la_SOURCES) $(libpolyp_error_la_SOURCES) +#parec_simple_LDADD = libpolyp-simple.la libpolyp-error.la +parec_simple_CFLAGS = $(AM_CFLAGS) diff --git a/src/polyp-error.c b/src/polyp-error.c index 861711a2..86166b0c 100644 --- a/src/polyp-error.c +++ b/src/polyp-error.c @@ -1,3 +1,4 @@ +#include #include #include "polyp-error.h" @@ -14,7 +15,9 @@ static const char* const errortab[PA_ERROR_MAX] = { [PA_ERROR_PROTOCOL] = "Protocol corrupt", [PA_ERROR_TIMEOUT] = "Timeout", [PA_ERROR_AUTHKEY] = "Not authorization key", - [PA_ERROR_INTERNAL] = "Internal error" + [PA_ERROR_INTERNAL] = "Internal error", + [PA_ERROR_CONNECTIONTERMINATED] = "Connection terminated", + [PA_ERROR_KILLED] = "Entity killed", }; const char*pa_strerror(uint32_t error) { diff --git a/src/polyp.c b/src/polyp.c index 2c2810fb..fde0c68b 100644 --- a/src/polyp.c +++ b/src/polyp.c @@ -28,7 +28,7 @@ struct pa_context { struct pa_socket_client *client; struct pa_pstream *pstream; struct pa_pdispatch *pdispatch; - struct pa_dynarray *streams; + struct pa_dynarray *record_streams, *playback_streams; struct pa_stream *first_stream; uint32_t ctag; uint32_t error; @@ -85,6 +85,7 @@ struct pa_stream { }; static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = { NULL }, @@ -95,6 +96,8 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, [PA_COMMAND_EXIT] = { NULL }, [PA_COMMAND_REQUEST] = { command_request }, + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, + [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, }; struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { @@ -108,8 +111,10 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * c->client = NULL; c->pstream = NULL; c->pdispatch = NULL; - c->streams = pa_dynarray_new(); - assert(c->streams); + c->playback_streams = pa_dynarray_new(); + assert(c->playback_streams); + c->record_streams = pa_dynarray_new(); + assert(c->record_streams); c->first_stream = NULL; c->error = PA_ERROR_OK; c->state = CONTEXT_UNCONNECTED; @@ -140,8 +145,10 @@ void pa_context_free(struct pa_context *c) { pa_pdispatch_free(c->pdispatch); if (c->pstream) pa_pstream_free(c->pstream); - if (c->streams) - pa_dynarray_free(c->streams, NULL, NULL); + if (c->record_streams) + pa_dynarray_free(c->record_streams, NULL, NULL); + if (c->playback_streams) + pa_dynarray_free(c->playback_streams, NULL, NULL); free(c->name); free(c); @@ -194,6 +201,7 @@ static void context_dead(struct pa_context *c) { static void pstream_die_callback(struct pa_pstream *p, void *userdata) { struct pa_context *c = userdata; assert(p && c); + c->error = PA_ERROR_CONNECTIONTERMINATED; context_dead(c); } @@ -203,6 +211,7 @@ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *pack if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { fprintf(stderr, "polyp.c: invalid packet.\n"); + c->error = PA_ERROR_PROTOCOL; context_dead(c); } } @@ -212,7 +221,7 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, in struct pa_stream *s; assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - if (!(s = pa_dynarray_get(c->streams, channel))) + if (!(s = pa_dynarray_get(c->record_streams, channel))) return; if (s->read_callback) @@ -353,6 +362,26 @@ void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_cont c->die_userdata = userdata; } +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + uint32_t channel; + assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) + return; + + c->error = PA_ERROR_KILLED; + stream_dead(s); +} + static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_stream *s; struct pa_context *c = userdata; @@ -367,7 +396,7 @@ static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t return; } - if (!(s = pa_dynarray_get(c->streams, channel))) + if (!(s = pa_dynarray_get(c->playback_streams, channel))) return; if (s->state != STREAM_READY) @@ -405,7 +434,7 @@ static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, ui } s->channel_valid = 1; - pa_dynarray_put(s->context->streams, s->channel, s); + pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, s); s->state = STREAM_READY; if (s->create_complete_callback) @@ -562,7 +591,7 @@ void pa_stream_free(struct pa_stream *s) { } if (s->channel_valid) - pa_dynarray_put(s->context->streams, s->channel, NULL); + pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); if (s->next) s->next->previous = s->previous; diff --git a/src/protocol-native-spec.h b/src/protocol-native-spec.h index fea14cc0..5e67fe74 100644 --- a/src/protocol-native-spec.h +++ b/src/protocol-native-spec.h @@ -16,6 +16,8 @@ enum { PA_COMMAND_LOOKUP_SINK, PA_COMMAND_LOOKUP_SOURCE, PA_COMMAND_DRAIN_PLAYBACK_STREAM, + PA_COMMAND_PLAYBACK_STREAM_KILLED, + PA_COMMAND_RECORD_STREAM_KILLED, PA_COMMAND_MAX }; @@ -31,6 +33,8 @@ enum { PA_ERROR_TIMEOUT, PA_ERROR_AUTHKEY, PA_ERROR_INTERNAL, + PA_ERROR_CONNECTIONTERMINATED, + PA_ERROR_KILLED, PA_ERROR_MAX }; diff --git a/src/protocol-native.c b/src/protocol-native.c index fe086066..c7a7cce0 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -254,6 +254,31 @@ static void send_memblock(struct connection *c) { } } +static void send_playback_stream_killed(struct playback_stream *p) { + struct pa_tagstruct *t; + assert(p); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, p->index); + pa_pstream_send_tagstruct(p->connection->pstream, t); +} + +static void send_record_stream_killed(struct record_stream *r) { + struct pa_tagstruct *t; + assert(r); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, r->index); + pa_pstream_send_tagstruct(r->connection->pstream, t); +} + + /*** sinkinput callbacks ***/ static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk) { @@ -283,6 +308,7 @@ static void sink_input_drop_cb(struct pa_sink_input *i, size_t length) { static void sink_input_kill_cb(struct pa_sink_input *i) { assert(i && i->userdata); + send_playback_stream_killed((struct playback_stream *) i->userdata); playback_stream_free((struct playback_stream *) i->userdata); } @@ -308,6 +334,7 @@ static void source_output_push_cb(struct pa_source_output *o, const struct pa_me static void source_output_kill_cb(struct pa_source_output *o) { assert(o && o->userdata); + send_record_stream_killed((struct record_stream *) o->userdata); record_stream_free((struct record_stream *) o->userdata); } diff --git a/src/simple.c b/src/simple.c index ba0a8f0c..5f86c5bf 100644 --- a/src/simple.c +++ b/src/simple.c @@ -1,3 +1,5 @@ +#include +#include #include #include @@ -10,10 +12,16 @@ struct pa_simple { struct pa_mainloop *mainloop; struct pa_context *context; struct pa_stream *stream; + enum pa_stream_direction direction; int dead, drained; + + void *read_data; + size_t read_index, read_length; }; +static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata); + static int check_error(struct pa_simple *p, int *perror) { assert(p); @@ -71,6 +79,9 @@ struct pa_simple* pa_simple_new( p->mainloop = pa_mainloop_new(); assert(p->mainloop); p->dead = 0; + p->direction = dir; + p->read_data = NULL; + p->read_index = p->read_length = 0; if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name))) goto fail; @@ -95,6 +106,8 @@ struct pa_simple* pa_simple_new( goto fail; } + pa_stream_set_read_callback(p->stream, read_callback, p); + return p; fail: @@ -107,6 +120,8 @@ fail: void pa_simple_free(struct pa_simple *s) { assert(s); + free(s->read_data); + if (s->stream) pa_stream_free(s->stream); @@ -120,7 +135,7 @@ void pa_simple_free(struct pa_simple *s) { } int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *perror) { - assert(p && data); + assert(p && data && p->direction == PA_STREAM_PLAYBACK); while (length > 0) { size_t l; @@ -144,10 +159,57 @@ int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *pe return 0; } -int pa_simple_read(struct pa_simple *s, void*data, size_t length, int *perror) { - assert(0); +static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata) { + struct pa_simple *p = userdata; + assert(s && data && length && p); + + if (p->read_data) { + fprintf(stderr, __FILE__": Buffer overflow, dropping incoming memory blocks.\n"); + free(p->read_data); + } + + p->read_data = malloc(p->read_length = length); + assert(p->read_data); + memcpy(p->read_data, data, length); + p->read_index = 0; } +int pa_simple_read(struct pa_simple *p, void*data, size_t length, int *perror) { + assert(p && data && p->direction == PA_STREAM_RECORD); + + while (length > 0) { + if (p->read_data) { + size_t l = length; + + if (p->read_length <= l) + l = p->read_length; + + memcpy(data, p->read_data+p->read_index, l); + + data += l; + length -= l; + + p->read_index += l; + p->read_length -= l; + + if (!p->read_length) { + free(p->read_data); + p->read_data = NULL; + p->read_index = 0; + } + + if (!length) + return 0; + + assert(!p->read_data); + } + + if (iterate(p, 1, perror) < 0) + return -1; + } + + return 0; +} static void drain_complete(struct pa_stream *s, void *userdata) { struct pa_simple *p = userdata; @@ -156,7 +218,7 @@ static void drain_complete(struct pa_stream *s, void *userdata) { } int pa_simple_drain(struct pa_simple *p, int *perror) { - assert(p); + assert(p && p->direction == PA_STREAM_PLAYBACK); p->drained = 0; pa_stream_drain(p->stream, drain_complete, p); diff --git a/src/todo b/src/todo index ee971ca0..1e1e02c5 100644 --- a/src/todo +++ b/src/todo @@ -1,4 +1,3 @@ -- implement parec-simple - native library/protocol: more functions (esp. latency) @@ -21,7 +20,7 @@ - svn-id and license in every file - documentation - +- dependency checking script -- post 0.1 - future cancellation -- cgit From 5ee3a59469f9c86659e6de21e70f96f1d7627347 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 10 Jul 2004 19:06:48 +0000 Subject: forgot to add parec-simple git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@57 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/parec-simple.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/parec-simple.c diff --git a/src/parec-simple.c b/src/parec-simple.c new file mode 100644 index 00000000..a2841beb --- /dev/null +++ b/src/parec-simple.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include + +#include "simple.h" +#include "polyp-error.h" + +#define BUFSIZE 1024 + +static ssize_t loop_write(int fd, const void*data, size_t size) { + ssize_t ret = 0; + + while (size > 0) { + ssize_t r; + + if ((r = write(fd, data, size)) < 0) + return r; + + if (r == 0) + break; + + ret += r; + data += r; + size -= r; + } + + return ret; +} + +int main(int argc, char*argv[]) { + static const struct pa_sample_spec ss = { + .format = PA_SAMPLE_S16LE, + .rate = 44100, + .channels = 2 + }; + struct pa_simple *s = NULL; + int ret = 1; + int error; + + if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, &error))) { + fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); + goto finish; + } + + for (;;) { + uint8_t buf[BUFSIZE]; + ssize_t r; + + if (pa_simple_read(s, buf, sizeof(buf), &error) < 0) { + fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error)); + goto finish; + } + + if ((r = loop_write(STDOUT_FILENO, buf, sizeof(buf))) <= 0) { + fprintf(stderr, __FILE__": write() failed: %s\n", strerror(errno)); + goto finish; + } + } + + ret = 0; + +finish: + + if (s) + pa_simple_free(s); + + return ret; +} -- cgit From 025389693d292b7a1c5f2c6e0ce96efa14062274 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 10 Jul 2004 19:23:45 +0000 Subject: make memblockq merge chunks git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@58 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/memblockq.c | 12 ++++++++++++ src/protocol-esound.c | 2 +- src/todo | 3 +-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/memblockq.c b/src/memblockq.c index fb4cbc7e..6d4d712a 100644 --- a/src/memblockq.c +++ b/src/memblockq.c @@ -82,6 +82,18 @@ void pa_memblockq_push(struct pa_memblockq* bq, const struct pa_memchunk *chunk, struct memblock_list *q; assert(bq && chunk && chunk->memblock && chunk->length && (chunk->length % bq->base) == 0); + if (bq->blocks_tail && bq->blocks_tail->chunk.memblock == chunk->memblock) { + /* Try to merge memory chunks */ + + if (bq->blocks_tail->chunk.index+bq->blocks_tail->chunk.length == chunk->index) { + bq->blocks_tail->chunk.length += chunk->length; + bq->current_length += chunk->length; + + /* fprintf(stderr, __FILE__": merge succeeded: %u\n", chunk->length);*/ + return; + } + } + q = malloc(sizeof(struct memblock_list)); assert(q); diff --git a/src/protocol-esound.c b/src/protocol-esound.c index e97ab34d..4d9ca546 100644 --- a/src/protocol-esound.c +++ b/src/protocol-esound.c @@ -394,7 +394,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v continue; assert(t >= s+k+k); - + if (conn->sink_input) { rate = conn->sink_input->sample_spec.rate; volume = (conn->sink_input->volume*0xFF)/0x100; diff --git a/src/todo b/src/todo index 1e1e02c5..8c647a8d 100644 --- a/src/todo +++ b/src/todo @@ -9,8 +9,6 @@ - move more stuff from module-oss[-dma] to liboss-util -- merge memchunks in memblockq - - create libstatustext, libsocketutil - prefix modules/libraries with pa_ @@ -29,6 +27,7 @@ - autoloading/autounloading - slp/rendezvous - doxygen +- make mcalign merge chunks drivers: - libao -- cgit From c7bd759cdb2b8f16693750f89ed781707a53e5a9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 10 Jul 2004 20:56:38 +0000 Subject: add description field for sinks/sources add owner field to all entities add client file to source outputs and sink inputs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@59 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/cli.c | 3 ++- src/cli.h | 3 ++- src/client.c | 9 +++++++-- src/client.h | 2 ++ src/module-cli.c | 2 +- src/module-oss-mmap.c | 6 ++++++ src/module-oss.c | 21 +++++++++++++-------- src/module-pipe-sink.c | 4 ++++ src/module-protocol-stub.c | 4 ++-- src/protocol-cli.c | 6 ++++-- src/protocol-cli.h | 3 ++- src/protocol-esound.c | 13 ++++++++++--- src/protocol-esound.h | 3 ++- src/protocol-native.c | 12 ++++++++++-- src/protocol-native.h | 3 ++- src/protocol-simple.c | 9 ++++++++- src/protocol-simple.h | 4 +++- src/sink.c | 24 ++++++++++++++++++------ src/sink.h | 5 +++-- src/sinkinput.c | 7 +++++++ src/sinkinput.h | 4 ++++ src/source.c | 22 +++++++++++++++++----- src/source.h | 5 ++++- src/sourceoutput.c | 6 ++++++ src/sourceoutput.h | 4 ++++ src/strbuf.c | 2 ++ src/strbuf.h | 2 +- src/todo | 4 ---- src/util.c | 30 ++++++++++++++++++++++++++++++ src/util.h | 2 ++ 30 files changed, 178 insertions(+), 46 deletions(-) diff --git a/src/cli.c b/src/cli.c index 429aebf3..b7fc787a 100644 --- a/src/cli.c +++ b/src/cli.c @@ -83,7 +83,7 @@ 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) { +struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io, struct pa_module *m) { char cname[256]; struct pa_cli *c; assert(io); @@ -102,6 +102,7 @@ struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io) { assert(c->client); c->client->kill = client_kill; c->client->userdata = c; + c->client->owner = m; pa_ioline_set_callback(c->line, line_callback, c); pa_ioline_puts(c->line, "Welcome to polypaudio! Use \"help\" for usage information.\n"); diff --git a/src/cli.h b/src/cli.h index 80d9fec7..d6250b37 100644 --- a/src/cli.h +++ b/src/cli.h @@ -3,10 +3,11 @@ #include "iochannel.h" #include "core.h" +#include "module.h" struct pa_cli; -struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io); +struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io, struct pa_module *m); void pa_cli_free(struct pa_cli *cli); void pa_cli_set_eof_callback(struct pa_cli *cli, void (*cb)(struct pa_cli*c, void *userdata), void *userdata); diff --git a/src/client.c b/src/client.c index d07f188f..fa1a28d4 100644 --- a/src/client.c +++ b/src/client.c @@ -14,6 +14,7 @@ struct pa_client *pa_client_new(struct pa_core *core, const char *protocol_name, c = malloc(sizeof(struct pa_client)); assert(c); c->name = name ? strdup(name) : NULL; + c->owner = NULL; c->core = core; c->protocol_name = protocol_name; @@ -58,9 +59,13 @@ char *pa_client_list_to_string(struct pa_core *c) { pa_strbuf_printf(s, "%u client(s).\n", pa_idxset_ncontents(c->clients)); - for (client = pa_idxset_first(c->clients, &index); client; client = pa_idxset_next(c->clients, &index)) + for (client = pa_idxset_first(c->clients, &index); client; client = pa_idxset_next(c->clients, &index)) { pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\tprotocol_name: <%s>\n", client->index, client->name, client->protocol_name); - + + if (client->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", client->owner->index); + } + return pa_strbuf_tostring_free(s); } diff --git a/src/client.h b/src/client.h index 4ca8d96e..d603411d 100644 --- a/src/client.h +++ b/src/client.h @@ -2,10 +2,12 @@ #define fooclienthfoo #include "core.h" +#include "module.h" struct pa_client { uint32_t index; + struct pa_module *owner; char *name; struct pa_core *core; const char *protocol_name; diff --git a/src/module-cli.c b/src/module-cli.c index a6e9582d..440c4ba5 100644 --- a/src/module-cli.c +++ b/src/module-cli.c @@ -27,7 +27,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { assert(io); pa_iochannel_set_noclose(io, 1); - m->userdata = pa_cli_new(c, io); + m->userdata = pa_cli_new(c, io, m); assert(m->userdata); pa_cli_set_eof_callback(m->userdata, eof_cb, m); diff --git a/src/module-oss-mmap.c b/src/module-oss-mmap.c index 280484d0..772abf99 100644 --- a/src/module-oss-mmap.c +++ b/src/module-oss-mmap.c @@ -17,6 +17,7 @@ #include "module.h" #include "oss-util.h" #include "sample-util.h" +#include "util.h" struct userdata { struct pa_sink *sink; @@ -244,6 +245,9 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { u->source = pa_source_new(c, "oss_input", 0, &u->sample_spec); assert(u->source); u->source->userdata = u; + pa_source_set_owner(u->source, m); + u->source->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'", p); + u->in_memblocks = malloc(sizeof(struct pa_memblock *)*u->in_fragments); memset(u->in_memblocks, 0, sizeof(struct pa_memblock *)*u->in_fragments); @@ -276,6 +280,8 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { assert(u->sink); u->sink->get_latency = sink_get_latency_cb; u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'", p); u->out_memblocks = malloc(sizeof(struct memblock *)*u->out_fragments); memset(u->out_memblocks, 0, sizeof(struct pa_memblock *)*u->out_fragments); diff --git a/src/module-oss.c b/src/module-oss.c index 5ec9d2d7..b0677584 100644 --- a/src/module-oss.c +++ b/src/module-oss.c @@ -16,6 +16,7 @@ #include "module.h" #include "oss-util.h" #include "sample-util.h" +#include "util.h" struct userdata { struct pa_sink *sink; @@ -180,21 +181,25 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { u->core = c; + if (mode != O_WRONLY) { + u->source = pa_source_new(c, "oss_input", 0, &ss); + 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); + } else + u->source = NULL; + if (mode != O_RDONLY) { - u->sink = pa_sink_new(c, "dsp", 0, &ss); + u->sink = pa_sink_new(c, "oss_output", 0, &ss); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); } else u->sink = NULL; - if (mode != O_WRONLY) { - u->source = pa_source_new(c, "dsp", 0, &ss); - assert(u->source); - u->source->userdata = u; - } else - u->source = NULL; - assert(u->source || u->sink); u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : 0); diff --git a/src/module-pipe-sink.c b/src/module-pipe-sink.c index efba3b5f..67c02404 100644 --- a/src/module-pipe-sink.c +++ b/src/module-pipe-sink.c @@ -11,6 +11,7 @@ #include "iochannel.h" #include "sink.h" #include "module.h" +#include "util.h" struct userdata { char *filename; @@ -113,6 +114,9 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { assert(u->sink); u->sink->notify = notify_cb; u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Unix FIFO sink '%s'", p); + assert(u->sink->description); u->io = pa_iochannel_new(c->mainloop, -1, fd); assert(u->io); diff --git a/src/module-protocol-stub.c b/src/module-protocol-stub.c index 885ea4c8..3bb0a072 100644 --- a/src/module-protocol-stub.c +++ b/src/module-protocol-stub.c @@ -78,9 +78,9 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { #endif #ifdef USE_PROTOCOL_SIMPLE - m->userdata = pa_protocol_simple_new(c, s, PA_PROTOCOL_SIMPLE_PLAYBACK); + m->userdata = pa_protocol_simple_new(c, s, m, PA_PROTOCOL_SIMPLE_PLAYBACK); #else - m->userdata = protocol_new(c, s); + m->userdata = protocol_new(c, s, m); #endif if (!m->userdata) { diff --git a/src/protocol-cli.c b/src/protocol-cli.c index 0cdf2db1..55b4a8a0 100644 --- a/src/protocol-cli.c +++ b/src/protocol-cli.c @@ -5,6 +5,7 @@ #include "cli.h" struct pa_protocol_cli { + struct pa_module *module; struct pa_core *core; struct pa_socket_server*server; struct pa_idxset *connections; @@ -22,19 +23,20 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo struct pa_cli *c; assert(s && io && p); - c = pa_cli_new(p->core, io); + c = pa_cli_new(p->core, io, p->module); assert(c); pa_cli_set_eof_callback(c, cli_eof_cb, p); pa_idxset_put(p->connections, c, NULL); } -struct pa_protocol_cli* pa_protocol_cli_new(struct pa_core *core, struct pa_socket_server *server) { +struct pa_protocol_cli* pa_protocol_cli_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m) { struct pa_protocol_cli* p; assert(core && server); p = malloc(sizeof(struct pa_protocol_cli)); assert(p); + p->module = m; p->core = core; p->server = server; p->connections = pa_idxset_new(NULL, NULL); diff --git a/src/protocol-cli.h b/src/protocol-cli.h index fc6a7d65..c3bb8b4f 100644 --- a/src/protocol-cli.h +++ b/src/protocol-cli.h @@ -3,10 +3,11 @@ #include "core.h" #include "socket-server.h" +#include "module.h" struct pa_protocol_cli; -struct pa_protocol_cli* pa_protocol_cli_new(struct pa_core *core, struct pa_socket_server *server); +struct pa_protocol_cli* pa_protocol_cli_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m); void pa_protocol_cli_free(struct pa_protocol_cli *n); #endif diff --git a/src/protocol-esound.c b/src/protocol-esound.c index 4d9ca546..fc4444c3 100644 --- a/src/protocol-esound.c +++ b/src/protocol-esound.c @@ -50,6 +50,7 @@ struct connection { struct pa_protocol_esound { int public; + struct pa_module *module; struct pa_core *core; struct pa_socket_server *server; struct pa_idxset *connections; @@ -260,6 +261,8 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons c->sink_input = pa_sink_input_new(sink, name, &ss); assert(c->sink_input); + c->sink_input->owner = c->protocol->module; + c->sink_input->client = c->client; c->sink_input->peek = sink_input_peek_cb; c->sink_input->drop = sink_input_drop_cb; c->sink_input->kill = sink_input_kill_cb; @@ -321,7 +324,9 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co assert(!c->source_output); c->source_output = pa_source_output_new(source, name, &ss); assert(c->source_output); - + + c->source_output->owner = c->protocol->module; + c->source_output->client = c->client; c->source_output->push = source_output_push_cb; c->source_output->kill = source_output_kill_cb; c->source_output->userdata = c; @@ -733,6 +738,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo assert(c->protocol->core); c->client = pa_client_new(c->protocol->core, "ESOUND", cname); assert(c->client); + c->client->owner = c->protocol->module; c->client->kill = client_kill_cb; c->client->userdata = c; @@ -768,7 +774,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo /*** entry points ***/ -struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server) { +struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m) { struct pa_protocol_esound *p; assert(core && server); @@ -779,7 +785,8 @@ struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa free(p); return NULL; } - + + p->module = m; p->public = 0; p->server = server; pa_socket_server_set_callback(p->server, on_connection, p); diff --git a/src/protocol-esound.h b/src/protocol-esound.h index cd505593..6071699d 100644 --- a/src/protocol-esound.h +++ b/src/protocol-esound.h @@ -3,10 +3,11 @@ #include "core.h" #include "socket-server.h" +#include "module.h" struct pa_protocol_esound; -struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server); +struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m); void pa_protocol_esound_free(struct pa_protocol_esound *p); #endif diff --git a/src/protocol-native.c b/src/protocol-native.c index c7a7cce0..d6a5f9b2 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -48,6 +48,7 @@ struct connection { }; struct pa_protocol_native { + struct pa_module *module; int public; struct pa_core *core; struct pa_socket_server *server; @@ -110,6 +111,8 @@ static struct record_stream* record_stream_new(struct connection *c, struct pa_s s->source_output->push = source_output_push_cb; s->source_output->kill = source_output_kill_cb; s->source_output->userdata = s; + s->source_output->owner = c->protocol->module; + s->source_output->client = c->client; s->memblockq = pa_memblockq_new(maxlength, 0, base = pa_sample_size(ss), 0, 0); assert(s->memblockq); @@ -153,6 +156,8 @@ static struct playback_stream* playback_stream_new(struct connection *c, struct s->sink_input->kill = sink_input_kill_cb; s->sink_input->get_latency = sink_input_get_latency_cb; s->sink_input->userdata = s; + s->sink_input->owner = c->protocol->module; + s->sink_input->client = c->client; s->memblockq = pa_memblockq_new(maxlength, tlength, pa_sample_size(ss), prebuf, minreq); assert(s->memblockq); @@ -707,6 +712,8 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo assert(c->client); c->client->kill = client_kill_cb; c->client->userdata = c; + c->client->owner = p->module; + c->pstream = pa_pstream_new(p->core->mainloop, io); assert(c->pstream); @@ -729,7 +736,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo /*** module entry points ***/ -struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct pa_socket_server *server) { +struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m) { struct pa_protocol_native *p; assert(core && server); @@ -740,7 +747,8 @@ struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct p free(p); return NULL; } - + + p->module = m; p->public = 1; p->server = server; p->core = core; diff --git a/src/protocol-native.h b/src/protocol-native.h index 1a260149..811b4e4a 100644 --- a/src/protocol-native.h +++ b/src/protocol-native.h @@ -3,10 +3,11 @@ #include "core.h" #include "socket-server.h" +#include "module.h" struct pa_protocol_native; -struct pa_protocol_native* pa_protocol_native_new(struct pa_core*core, struct pa_socket_server *server); +struct pa_protocol_native* pa_protocol_native_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m); void pa_protocol_native_free(struct pa_protocol_native *n); #endif diff --git a/src/protocol-simple.c b/src/protocol-simple.c index e7ca0a76..518d5f24 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -27,6 +27,7 @@ struct connection { }; struct pa_protocol_simple { + struct pa_module *module; struct pa_core *core; struct pa_socket_server*server; struct pa_idxset *connections; @@ -258,6 +259,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); c->client = pa_client_new(p->core, "SIMPLE", cname); assert(c->client); + c->client->owner = p->module; c->client->kill = client_kill_cb; c->client->userdata = c; @@ -275,6 +277,8 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo fprintf(stderr, "Failed to create sink input.\n"); goto fail; } + c->sink_input->owner = p->module; + c->sink_input->client = c->client; c->sink_input->peek = sink_input_peek_cb; c->sink_input->drop = sink_input_drop_cb; @@ -304,6 +308,8 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo fprintf(stderr, "Failed to create source output.\n"); goto fail; } + c->source_output->owner = p->module; + c->source_output->client = c->client; c->source_output->push = source_output_push_cb; c->source_output->kill = source_output_kill_cb; @@ -328,12 +334,13 @@ fail: connection_free(c); } -struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct pa_socket_server *server, enum pa_protocol_simple_mode mode) { +struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, enum pa_protocol_simple_mode mode) { struct pa_protocol_simple* p; assert(core && server && mode <= PA_PROTOCOL_SIMPLE_DUPLEX && mode > 0); p = malloc(sizeof(struct pa_protocol_simple)); assert(p); + p->module = m; p->core = core; p->server = server; p->connections = pa_idxset_new(NULL, NULL); diff --git a/src/protocol-simple.h b/src/protocol-simple.h index 15ae36a6..6b2a2cd1 100644 --- a/src/protocol-simple.h +++ b/src/protocol-simple.h @@ -2,6 +2,8 @@ #define fooprotocolsimplehfoo #include "socket-server.h" +#include "module.h" +#include "core.h" struct pa_protocol_simple; @@ -11,7 +13,7 @@ enum pa_protocol_simple_mode { PA_PROTOCOL_SIMPLE_DUPLEX = 3 }; -struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct pa_socket_server *server, enum pa_protocol_simple_mode mode); +struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, enum pa_protocol_simple_mode mode); void pa_protocol_simple_free(struct pa_protocol_simple *n); #endif diff --git a/src/sink.c b/src/sink.c index 80560724..6a9f3580 100644 --- a/src/sink.c +++ b/src/sink.c @@ -8,6 +8,7 @@ #include "strbuf.h" #include "sample-util.h" #include "namereg.h" +#include "util.h" #define MAX_MIX_CHANNELS 32 @@ -16,7 +17,7 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co char *n = NULL; char st[256]; int r; - assert(core && spec); + assert(core && name && spec); s = malloc(sizeof(struct pa_sink)); assert(s); @@ -27,15 +28,14 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co } s->name = strdup(name); + s->description = NULL; + + s->owner = NULL; s->core = core; s->sample_spec = *spec; s->inputs = pa_idxset_new(NULL, NULL); - if (name) { - n = malloc(strlen(name)+9); - sprintf(n, "%s_monitor", name); - } - + n = pa_sprintf_malloc("%s_monitor", name); s->monitor_source = pa_source_new(core, n, 0, spec); assert(s->monitor_source); free(n); @@ -75,6 +75,7 @@ void pa_sink_free(struct pa_sink *s) { fprintf(stderr, "sink: freed %u \"%s\"\n", s->index, s->name); free(s->name); + free(s->description); free(s); } @@ -285,8 +286,19 @@ char *pa_sink_list_to_string(struct pa_core *c) { pa_sink_get_latency(sink), sink->monitor_source->index, ss); + + if (sink->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", sink->owner->index); + if (sink->description) + pa_strbuf_printf(s, "\tdescription: <%s>\n", sink->description); } return pa_strbuf_tostring_free(s); } +void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m) { + sink->owner = m; + + if (sink->monitor_source) + pa_source_set_owner(sink->monitor_source, m); +} diff --git a/src/sink.h b/src/sink.h index 7186f531..071ad094 100644 --- a/src/sink.h +++ b/src/sink.h @@ -13,7 +13,8 @@ struct pa_sink; struct pa_sink { uint32_t index; - char *name; + char *name, *description; + struct pa_module *owner; struct pa_core *core; struct pa_sample_spec sample_spec; struct pa_idxset *inputs; @@ -42,6 +43,6 @@ char *pa_sink_list_to_string(struct pa_core *core); struct pa_sink* pa_sink_get_default(struct pa_core *c); - +void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m); #endif diff --git a/src/sinkinput.c b/src/sinkinput.c index f3e474bc..3cfe49b3 100644 --- a/src/sinkinput.c +++ b/src/sinkinput.c @@ -23,6 +23,8 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con i = malloc(sizeof(struct pa_sink_input)); assert(i); i->name = name ? strdup(name) : NULL; + i->client = NULL; + i->owner = NULL; i->sink = s; i->sample_spec = *spec; @@ -96,6 +98,11 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { (unsigned) i->volume, pa_sink_input_get_latency(i), ss); + + if (i->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", i->owner->index); + if (i->client) + pa_strbuf_printf(s, "\tclient: <%u>\n", i->client->index); } return pa_strbuf_tostring_free(s); diff --git a/src/sinkinput.h b/src/sinkinput.h index b28b51ef..8c9813e5 100644 --- a/src/sinkinput.h +++ b/src/sinkinput.h @@ -7,11 +7,15 @@ #include "sample.h" #include "memblockq.h" #include "resampler.h" +#include "module.h" +#include "client.h" struct pa_sink_input { uint32_t index; char *name; + struct pa_module *owner; + struct pa_client *client; struct pa_sink *sink; struct pa_sample_spec sample_spec; uint32_t volume; diff --git a/src/source.c b/src/source.c index 44d7da01..45ccfb27 100644 --- a/src/source.c +++ b/src/source.c @@ -12,7 +12,7 @@ struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail struct pa_source *s; char st[256]; int r; - assert(core && spec); + assert(core && spec && name); s = malloc(sizeof(struct pa_source)); assert(s); @@ -23,6 +23,9 @@ struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail } s->name = strdup(name); + s->description = NULL; + + s->owner = NULL; s->core = core; s->sample_spec = *spec; s->outputs = pa_idxset_new(NULL, NULL); @@ -58,6 +61,7 @@ void pa_source_free(struct pa_source *s) { fprintf(stderr, "source: freed %u \"%s\"\n", s->index, s->name); free(s->name); + free(s->description); free(s); } @@ -112,13 +116,21 @@ char *pa_source_list_to_string(struct pa_core *c) { for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) { char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - char mo[256] = ""; - if (source->monitor_of) - snprintf(mo, sizeof(mo), "\n\tmonitor_of: <%u>", source->monitor_of->index); pa_sample_snprint(ss, sizeof(ss), &source->sample_spec); - pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\tsample_spec: <%s>%s\n", source == default_source ? '*' : ' ', source->index, source->name, ss, mo); + pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\tsample_spec: <%s>\n", source == default_source ? '*' : ' ', source->index, source->name, ss); + + if (source->monitor_of) + pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index); + if (source->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", source->owner->index); + if (source->description) + pa_strbuf_printf(s, "\tdescription: <%s>\n", source->description); } return pa_strbuf_tostring_free(s); } +void pa_source_set_owner(struct pa_source *s, struct pa_module *m) { + assert(s); + s->owner = m; +} diff --git a/src/source.h b/src/source.h index 3b66cd36..2bc5bea8 100644 --- a/src/source.h +++ b/src/source.h @@ -14,7 +14,8 @@ struct pa_source; struct pa_source { uint32_t index; - char *name; + char *name, *description; + struct pa_module *owner; struct pa_core *core; struct pa_sample_spec sample_spec; struct pa_idxset *outputs; @@ -36,4 +37,6 @@ char *pa_source_list_to_string(struct pa_core *c); struct pa_source* pa_source_get_default(struct pa_core *c); +void pa_source_set_owner(struct pa_source *s, struct pa_module *m); + #endif diff --git a/src/sourceoutput.c b/src/sourceoutput.c index 442dc7f4..ea727576 100644 --- a/src/sourceoutput.c +++ b/src/sourceoutput.c @@ -18,6 +18,8 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n o = malloc(sizeof(struct pa_source_output)); assert(o); o->name = name ? strdup(name) : NULL; + o->client = NULL; + o->owner = NULL; o->source = s; o->sample_spec = *spec; @@ -77,6 +79,10 @@ char *pa_source_output_list_to_string(struct pa_core *c) { o->name, o->source->index, ss); + if (o->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", o->owner->index); + if (o->client) + pa_strbuf_printf(s, "\tclient: <%u>\n", o->client->index); } return pa_strbuf_tostring_free(s); diff --git a/src/sourceoutput.h b/src/sourceoutput.h index fb60182a..dfd076db 100644 --- a/src/sourceoutput.h +++ b/src/sourceoutput.h @@ -7,11 +7,15 @@ #include "sample.h" #include "memblockq.h" #include "resampler.h" +#include "module.h" +#include "client.h" struct pa_source_output { uint32_t index; char *name; + struct pa_module *owner; + struct pa_client *client; struct pa_source *source; struct pa_sample_spec sample_spec; diff --git a/src/strbuf.c b/src/strbuf.c index c2a6518e..2082002a 100644 --- a/src/strbuf.c +++ b/src/strbuf.c @@ -87,6 +87,8 @@ void pa_strbuf_puts(struct pa_strbuf *sb, const char *t) { sb->length += l; } +/* The following is based on an example from the GNU libc documentation */ + int pa_strbuf_printf(struct pa_strbuf *sb, const char *format, ...) { int r, size = 100; struct chunk *c = NULL; diff --git a/src/strbuf.h b/src/strbuf.h index bb972044..ab0c6a74 100644 --- a/src/strbuf.h +++ b/src/strbuf.h @@ -8,7 +8,7 @@ void pa_strbuf_free(struct pa_strbuf *sb); char *pa_strbuf_tostring(struct pa_strbuf *sb); char *pa_strbuf_tostring_free(struct pa_strbuf *sb); -int pa_strbuf_printf(struct pa_strbuf *sb, const char *format, ...); +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); #endif diff --git a/src/todo b/src/todo index 8c647a8d..36e69a18 100644 --- a/src/todo +++ b/src/todo @@ -3,10 +3,6 @@ - config parser/cmdline -- description field for all entities -- client field for sinkinput/sourceoutput -- module field for all entities - - move more stuff from module-oss[-dma] to liboss-util - create libstatustext, libsocketutil diff --git a/src/util.c b/src/util.c index 6fe4bbee..aceb772d 100644 --- a/src/util.c +++ b/src/util.c @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -230,3 +232,31 @@ void pa_check_for_sigpipe(void) { if (sa.sa_handler == SIG_DFL) fprintf(stderr, "polypaudio: WARNING: SIGPIPE is not trapped. This might cause malfunction!\n"); } + +/* The following is based on an example from the GNU libc documentation */ +char *pa_sprintf_malloc(const char *format, ...) { + int size = 100; + char *c = NULL; + + assert(format); + + for(;;) { + int r; + va_list ap; + + c = realloc(c, size); + assert(c); + + va_start(ap, format); + r = vsnprintf(c, size, format, ap); + va_end(ap); + + if (r > -1 && r < size) + return c; + + if (r > -1) /* glibc 2.1 */ + size = r+1; + else /* glibc 2.0 */ + size *= 2; + } +} diff --git a/src/util.h b/src/util.h index dba89ee8..c5c6db82 100644 --- a/src/util.h +++ b/src/util.h @@ -23,4 +23,6 @@ int pa_unix_socket_remove_stale(const char *fn); void pa_check_for_sigpipe(void); +char *pa_sprintf_malloc(const char *format, ...) __attribute__ ((format (printf, 1, 2))); + #endif -- cgit From ccfd55420ebec191d7a3ed842ecb2740ceeb76ba Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 11 Jul 2004 01:09:46 +0000 Subject: add dependency script fix some dependencies split off socket-util.c and clitext.c git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@60 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 52 +++++++------ src/cli.c | 1 + src/client.c | 23 ------ src/client.h | 2 - src/clitext.c | 178 +++++++++++++++++++++++++++++++++++++++++++++ src/clitext.h | 14 ++++ src/depmod.py | 56 ++++++++++++++ src/iochannel.c | 3 +- src/module-protocol-stub.c | 1 + src/module.c | 19 ----- src/module.h | 3 - src/protocol-esound.c | 2 +- src/protocol-simple.c | 2 +- src/sink.c | 39 +--------- src/sink.h | 2 - src/sinkinput.c | 35 --------- src/sinkinput.h | 1 - src/socket-client.c | 1 + src/socket-server.c | 2 +- src/socket-util.c | 152 ++++++++++++++++++++++++++++++++++++++ src/socket-util.h | 17 +++++ src/source.c | 30 -------- src/source.h | 2 - src/sourceoutput.c | 31 -------- src/sourceoutput.h | 2 - src/todo | 3 - src/util.c | 140 ----------------------------------- src/util.h | 11 --- 28 files changed, 456 insertions(+), 368 deletions(-) create mode 100644 src/clitext.c create mode 100644 src/clitext.h create mode 100755 src/depmod.py create mode 100644 src/socket-util.c create mode 100644 src/socket-util.h diff --git a/src/Makefile.am b/src/Makefile.am index b02bfba6..51129534 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -35,6 +35,8 @@ pkglib_LTLIBRARIES=libiochannel.la \ libpstream-util.la \ libpdispatch.la \ libauthkey.la \ + libclitext.la \ + libsocket-util.la \ libprotocol-simple.la \ libprotocol-esound.la \ libprotocol-native.la \ @@ -94,26 +96,27 @@ libprotocol_simple_la_LIBADD = libsocket-server.la libiochannel.la libsocket_server_la_SOURCES = socket-server.c socket-server.h libsocket_server_la_LDFLAGS = -avoid-version -libsocket_server_la_LIBADD = libiochannel.la +libsocket_server_la_LIBADD = libiochannel.la libsocket-util.la libsocket_client_la_SOURCES = socket-client.c socket-client.h libsocket_client_la_LDFLAGS = -avoid-version -libsocket_client_la_LIBADD = libiochannel.la +libsocket_client_la_LIBADD = libiochannel.la libsocket-util.la libpstream_la_SOURCES = pstream.c pstream.h libpstream_la_LDFLAGS = -avoid-version -libpstream_la_LIBADD = libpacket.la +libpstream_la_LIBADD = libpacket.la libiochannel.la libpstream_util_la_SOURCES = pstream-util.c pstream-util.h libpstream_util_la_LDFLAGS = -avoid-version -libpstream_util_la_LIBADD = libpstream.la libtagstruct.la +libpstream_util_la_LIBADD = libpacket.la libpstream.la libtagstruct.la libpdispatch_la_SOURCES = pdispatch.c pdispatch.h libpdispatch_la_LDFLAGS = -avoid-version -libpdispatch_la_LIBADD = libpacket.la libtagstruct.la +libpdispatch_la_LIBADD = libtagstruct.la libiochannel_la_SOURCES = iochannel.c iochannel.h libiochannel_la_LDFLAGS = -avoid-version +libiochannel_la_LIBDADD = libsocket-util.la libpacket_la_SOURCES = packet.c packet.h libpacket_la_LDFLAGS = -avoid-version @@ -127,7 +130,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 +libcli_la_LIBADD = libiochannel.la libioline.la libclitext.la libtokenizer.la libdynarray_la_SOURCES = dynarray.c dynarray.h libdynarray_la_LDFLAGS = -avoid-version @@ -142,18 +145,24 @@ libprotocol_cli_la_LIBADD = libsocket-server.la libiochannel.la libcli.la libprotocol_native_la_SOURCES = protocol-native.c protocol-native.h libprotocol_native_la_LDFLAGS = -avoid-version -libprotocol_native_la_LIBADD = libsocket-server.la libiochannel.la libpacket.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la +libprotocol_native_la_LIBADD = libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libtagstruct_la_SOURCES = tagstruct.c tagstruct.h libtagstruct_la_LDFLAGS = -avoid-version -libprotocol_esound_la_SOURCES = protocol-esound.c protocol-esound.h protocol-esound-spec.h +libprotocol_esound_la_SOURCES = protocol-esound.c protocol-esound.h esound-spec.h libprotocol_esound_la_LDFLAGS = -avoid-version 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 + module_simple_protocol_tcp_la_SOURCES = module-protocol-stub.c module_simple_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) module_simple_protocol_tcp_la_LDFLAGS = -module -avoid-version @@ -162,7 +171,7 @@ module_simple_protocol_tcp_la_LIBADD = libprotocol-simple.la libsocket-server.la module_simple_protocol_unix_la_SOURCES = module-protocol-stub.c module_simple_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) module_simple_protocol_unix_la_LDFLAGS = -module -avoid-version -module_simple_protocol_unix_la_LIBADD = libprotocol-simple.la libsocket-server.la +module_simple_protocol_unix_la_LIBADD = libprotocol-simple.la libsocket-server.la libsocket-util.la module_cli_protocol_tcp_la_SOURCES = module-protocol-stub.c module_cli_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) @@ -172,7 +181,7 @@ module_cli_protocol_tcp_la_LIBADD = libprotocol-cli.la libsocket-server.la module_cli_protocol_unix_la_SOURCES = module-protocol-stub.c module_cli_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) module_cli_protocol_unix_la_LDFLAGS = -module -avoid-version -module_cli_protocol_unix_la_LIBADD = libprotocol-cli.la libsocket-server.la +module_cli_protocol_unix_la_LIBADD = libprotocol-cli.la libsocket-server.la libsocket-util.la module_native_protocol_tcp_la_SOURCES = module-protocol-stub.c module_native_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) @@ -182,7 +191,7 @@ module_native_protocol_tcp_la_LIBADD = libprotocol-native.la libsocket-server.la module_native_protocol_unix_la_SOURCES = module-protocol-stub.c module_native_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) module_native_protocol_unix_la_LDFLAGS = -module -avoid-version -module_native_protocol_unix_la_LIBADD = libprotocol-native.la libsocket-server.la +module_native_protocol_unix_la_LIBADD = libprotocol-native.la libsocket-server.la libsocket-util.la module_esound_protocol_tcp_la_SOURCES = module-protocol-stub.c module_esound_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) @@ -192,7 +201,7 @@ module_esound_protocol_tcp_la_LIBADD = libprotocol-esound.la libsocket-server.la module_esound_protocol_unix_la_SOURCES = module-protocol-stub.c module_esound_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) module_esound_protocol_unix_la_LDFLAGS = -module -avoid-version -module_esound_protocol_unix_la_LIBADD = libprotocol-esound.la libsocket-server.la +module_esound_protocol_unix_la_LIBADD = libprotocol-esound.la libsocket-server.la libsocket-util.la module_pipe_sink_la_SOURCES = module-pipe-sink.c module_pipe_sink_la_LDFLAGS = -module -avoid-version @@ -204,7 +213,7 @@ module_oss_la_LIBADD = libiochannel.la liboss-util.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-util.la +module_oss_mmap_la_LIBADD = liboss-util.la module_cli_la_SOURCES = module-cli.c module_cli_la_LDFLAGS = -module -avoid-version @@ -229,9 +238,9 @@ libpolyp_la_SOURCES = polyp.c polyp.h \ queue.c queue.h \ dynarray.c dynarray.h \ memchunk.c memchunk.h \ - authkey.c authkey.h + authkey.c authkey.h \ + socket-util.c socket-util.h libpolyp_la_CFLAGS = $(AM_CFLAGS) -#libpolyp_la_LIBADD = libpolyp-error.la libpolyp_error_la_SOURCES = polyp-error.c polyp-error.h libpolyp_error_la_CFLAGS = $(AM_CFLAGS) @@ -239,16 +248,15 @@ libpolyp_error_la_CFLAGS = $(AM_CFLAGS) libpolyp_simple_la_SOURCES = simple.c simple.h libpolyp_simple_la_CFLAGS = $(AM_CFLAGS) libpolyp_simple_la_LIBADD = libpolyp.la -#libpolyp-error.la -pacat_SOURCES = pacat.c $(libpolyp_la_SOURCES) $(libpolyp_error_la_SOURCES) -#pacat_LDADD = libpolyp.la +pacat_SOURCES = pacat.c #$(libpolyp_la_SOURCES) $(libpolyp_error_la_SOURCES) +pacat_LDADD = libpolyp.la libpolyp-error.la pacat_CFLAGS = $(AM_CFLAGS) -pacat_simple_SOURCES = pacat-simple.c $(libpolyp_la_SOURCES) $(libpolyp_simple_la_SOURCES) $(libpolyp_error_la_SOURCES) -#pacat_simple_LDADD = libpolyp-simple.la libpolyp-error.la +pacat_simple_SOURCES = pacat-simple.c #$(libpolyp_la_SOURCES) $(libpolyp_simple_la_SOURCES) $(libpolyp_error_la_SOURCES) +pacat_simple_LDADD = libpolyp-simple.la libpolyp-error.la pacat_simple_CFLAGS = $(AM_CFLAGS) -parec_simple_SOURCES = parec-simple.c $(libpolyp_la_SOURCES) $(libpolyp_simple_la_SOURCES) $(libpolyp_error_la_SOURCES) -#parec_simple_LDADD = libpolyp-simple.la libpolyp-error.la +parec_simple_SOURCES = parec-simple.c #$(libpolyp_la_SOURCES) $(libpolyp_simple_la_SOURCES) $(libpolyp_error_la_SOURCES) +parec_simple_LDADD = libpolyp-simple.la libpolyp-error.la parec_simple_CFLAGS = $(AM_CFLAGS) diff --git a/src/cli.c b/src/cli.c index b7fc787a..d5b46c46 100644 --- a/src/cli.c +++ b/src/cli.c @@ -14,6 +14,7 @@ #include "tokenizer.h" #include "strbuf.h" #include "namereg.h" +#include "clitext.h" struct pa_cli { struct pa_core *core; diff --git a/src/client.c b/src/client.c index fa1a28d4..c170e49a 100644 --- a/src/client.c +++ b/src/client.c @@ -4,7 +4,6 @@ #include #include "client.h" -#include "strbuf.h" struct pa_client *pa_client_new(struct pa_core *core, const char *protocol_name, char *name) { struct pa_client *c; @@ -48,28 +47,6 @@ void pa_client_kill(struct pa_client *c) { c->kill(c); } -char *pa_client_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_client *client; - uint32_t index = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u client(s).\n", pa_idxset_ncontents(c->clients)); - - for (client = pa_idxset_first(c->clients, &index); client; client = pa_idxset_next(c->clients, &index)) { - pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\tprotocol_name: <%s>\n", client->index, client->name, client->protocol_name); - - if (client->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", client->owner->index); - } - - return pa_strbuf_tostring_free(s); -} - - void pa_client_rename(struct pa_client *c, const char *name) { assert(c); free(c->name); diff --git a/src/client.h b/src/client.h index d603411d..10ffa8f3 100644 --- a/src/client.h +++ b/src/client.h @@ -25,8 +25,6 @@ void pa_client_free(struct pa_client *c); * request destruction of the client */ void pa_client_kill(struct pa_client *c); -char *pa_client_list_to_string(struct pa_core *c); - void pa_client_rename(struct pa_client *c, const char *name); #endif diff --git a/src/clitext.c b/src/clitext.c new file mode 100644 index 00000000..701cf2c0 --- /dev/null +++ b/src/clitext.c @@ -0,0 +1,178 @@ +#include + +#include "clitext.h" +#include "module.h" +#include "client.h" +#include "sink.h" +#include "source.h" +#include "sinkinput.h" +#include "sourceoutput.h" +#include "strbuf.h" +#include "sample-util.h" + +char *pa_module_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_module *m; + uint32_t index = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_ncontents(c->modules)); + + for (m = pa_idxset_first(c->modules, &index); m; m = pa_idxset_next(c->modules, &index)) + pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\targument: <%s>\n", m->index, m->name, m->argument); + + return pa_strbuf_tostring_free(s); +} + +char *pa_client_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_client *client; + uint32_t index = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u client(s).\n", pa_idxset_ncontents(c->clients)); + + for (client = pa_idxset_first(c->clients, &index); client; client = pa_idxset_next(c->clients, &index)) { + pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\tprotocol_name: <%s>\n", client->index, client->name, client->protocol_name); + + if (client->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", client->owner->index); + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_sink_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_sink *sink, *default_sink; + uint32_t index = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_ncontents(c->sinks)); + + default_sink = pa_sink_get_default(c); + + for (sink = pa_idxset_first(c->sinks, &index); sink; sink = pa_idxset_next(c->sinks, &index)) { + char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + pa_sample_snprint(ss, sizeof(ss), &sink->sample_spec); + assert(sink->monitor_source); + pa_strbuf_printf( + s, + " %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", + sink == default_sink ? '*' : ' ', + sink->index, sink->name, + (unsigned) sink->volume, + pa_sink_get_latency(sink), + sink->monitor_source->index, + ss); + + if (sink->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", sink->owner->index); + if (sink->description) + pa_strbuf_printf(s, "\tdescription: <%s>\n", sink->description); + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_source_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_source *source, *default_source; + uint32_t index = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_ncontents(c->sources)); + + default_source = pa_source_get_default(c); + + for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) { + char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + pa_sample_snprint(ss, sizeof(ss), &source->sample_spec); + pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\tsample_spec: <%s>\n", source == default_source ? '*' : ' ', source->index, source->name, ss); + + if (source->monitor_of) + pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index); + if (source->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", source->owner->index); + if (source->description) + pa_strbuf_printf(s, "\tdescription: <%s>\n", source->description); + } + + return pa_strbuf_tostring_free(s); +} + + +char *pa_source_output_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_source_output *o; + uint32_t index = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_ncontents(c->source_outputs)); + + for (o = pa_idxset_first(c->source_outputs, &index); o; o = pa_idxset_next(c->source_outputs, &index)) { + char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + pa_sample_snprint(ss, sizeof(ss), &o->sample_spec); + assert(o->source); + pa_strbuf_printf( + s, " index: %u\n\tname: <%s>\n\tsource: <%u>\n\tsample_spec: <%s>\n", + o->index, + o->name, + o->source->index, + ss); + if (o->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", o->owner->index); + if (o->client) + pa_strbuf_printf(s, "\tclient: <%u>\n", o->client->index); + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_sink_input_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_sink_input *i; + uint32_t index = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_ncontents(c->sink_inputs)); + + for (i = pa_idxset_first(c->sink_inputs, &index); i; i = pa_idxset_next(c->sink_inputs, &index)) { + char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + pa_sample_snprint(ss, sizeof(ss), &i->sample_spec); + assert(i->sink); + pa_strbuf_printf( + s, " index: %u\n\tname: <%s>\n\tsink: <%u>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tsample_spec: <%s>\n", + i->index, + i->name, + i->sink->index, + (unsigned) i->volume, + pa_sink_input_get_latency(i), + ss); + + if (i->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", i->owner->index); + if (i->client) + pa_strbuf_printf(s, "\tclient: <%u>\n", i->client->index); + } + + return pa_strbuf_tostring_free(s); +} diff --git a/src/clitext.h b/src/clitext.h new file mode 100644 index 00000000..5b17c2d7 --- /dev/null +++ b/src/clitext.h @@ -0,0 +1,14 @@ +#ifndef fooclitexthfoo +#define fooclitexthfoo + +#include "core.h" + +char *pa_sink_input_list_to_string(struct pa_core *c); +char *pa_source_output_list_to_string(struct pa_core *c); +char *pa_sink_list_to_string(struct pa_core *core); +char *pa_source_list_to_string(struct pa_core *c); +char *pa_client_list_to_string(struct pa_core *c); +char *pa_module_list_to_string(struct pa_core *c); + +#endif + diff --git a/src/depmod.py b/src/depmod.py new file mode 100755 index 00000000..d11cceb4 --- /dev/null +++ b/src/depmod.py @@ -0,0 +1,56 @@ +#!/usr/bin/python +# $Id$ + +import sys, os, string + +exported_symbols = {} +imported_symbols = {} + +for fn in sys.argv[1:]: + f = os.popen("nm '%s'" % fn, "r") + + imported_symbols[fn] = [] + + for line in f: + sym_address = line[:7].strip() + sym_type = line[9].strip() + sym_name = line[11:].strip() + + if sym_name in ('_fini', '_init'): + continue + + if sym_type in ('T', 'B', 'R', 'D' 'G', 'S', 'D'): + if exported_symbols.has_key(sym_name): + sys.stderr.write("CONFLICT: %s defined in both '%s' and '%s'.\n" % (sym_name, fn, exported_symbols[sym_name])) + else: + exported_symbols[sym_name] = fn + elif sym_type in ('U',): + if sym_name[:3] == 'pa_': + imported_symbols[fn].append(sym_name) + + f.close() + +dependencies = {} +unresolved_symbols = {} + +for fn in imported_symbols: + dependencies[fn] = [] + + for sym in imported_symbols[fn]: + if exported_symbols.has_key(sym): + if exported_symbols[sym] not in dependencies[fn]: + dependencies[fn].append(exported_symbols[sym]) + else: + if unresolved_symbols.has_key(sym): + unresolved_symbols[sym].append(fn) + else: + unresolved_symbols[sym] = [fn] + +for sym, files in unresolved_symbols.iteritems(): + print "WARNING: Unresolved symbol '%s' in %s" % (sym, `files`) + +k = dependencies.keys() +k.sort() +for fn in k: + dependencies[fn].sort() + print "%s: %s" % (fn, string.join(dependencies[fn], " ")) diff --git a/src/iochannel.c b/src/iochannel.c index 775c6139..38430034 100644 --- a/src/iochannel.c +++ b/src/iochannel.c @@ -5,6 +5,7 @@ #include "iochannel.h" #include "util.h" +#include "socket-util.h" struct pa_iochannel { int ifd, ofd; @@ -182,7 +183,7 @@ void pa_iochannel_set_noclose(struct pa_iochannel*io, int b) { void pa_iochannel_socket_peer_to_string(struct pa_iochannel*io, char*s, size_t l) { assert(io && s && l); - pa_peer_to_string(s, l, io->ifd); + pa_socket_peer_to_string(io->ifd, s, l); } int pa_iochannel_socket_set_rcvbuf(struct pa_iochannel *io, size_t l) { diff --git a/src/module-protocol-stub.c b/src/module-protocol-stub.c index 3bb0a072..0547f7e6 100644 --- a/src/module-protocol-stub.c +++ b/src/module-protocol-stub.c @@ -7,6 +7,7 @@ #include "module.h" #include "socket-server.h" +#include "socket-util.h" #include "util.h" #ifdef USE_PROTOCOL_SIMPLE diff --git a/src/module.c b/src/module.c index 87df3b38..b6a706c3 100644 --- a/src/module.c +++ b/src/module.c @@ -6,7 +6,6 @@ #include #include "module.h" -#include "strbuf.h" struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char *argument) { struct pa_module *m = NULL; @@ -112,24 +111,6 @@ void pa_module_unload_all(struct pa_core *c) { c->modules = NULL; } -char *pa_module_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_module *m; - uint32_t index = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_ncontents(c->modules)); - - for (m = pa_idxset_first(c->modules, &index); m; m = pa_idxset_next(c->modules, &index)) - pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\targument: <%s>\n", m->index, m->name, m->argument); - - return pa_strbuf_tostring_free(s); -} - - struct once_info { struct pa_core *core; uint32_t index; diff --git a/src/module.h b/src/module.h index 2a9cf558..174a8d09 100644 --- a/src/module.h +++ b/src/module.h @@ -25,11 +25,8 @@ void pa_module_unload_by_index(struct pa_core *c, uint32_t index); void pa_module_unload_all(struct pa_core *c); -char *pa_module_list_to_string(struct pa_core *c); - void pa_module_unload_request(struct pa_core *c, struct pa_module *m); - /* These to following prototypes are for module entrypoints and not implemented by the core */ int pa_module_init(struct pa_core *c, struct pa_module*m); void pa_module_done(struct pa_core *c, struct pa_module*m); diff --git a/src/protocol-esound.c b/src/protocol-esound.c index fc4444c3..955ab93c 100644 --- a/src/protocol-esound.c +++ b/src/protocol-esound.c @@ -660,7 +660,7 @@ static void io_callback(struct pa_iochannel*io, void *userdata) { /*** fixed callback ***/ -void fixed_callback(struct pa_mainloop_api*a, void *id, void *userdata) { +static void fixed_callback(struct pa_mainloop_api*a, void *id, void *userdata) { struct connection *c = userdata; assert(a && c && c->fixed_source == id); diff --git a/src/protocol-simple.c b/src/protocol-simple.c index 518d5f24..b57f324a 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -229,7 +229,7 @@ static void io_callback(struct pa_iochannel*io, void *userdata) { /*** fixed callback ***/ -void fixed_callback(struct pa_mainloop_api*a, void *id, void *userdata) { +static void fixed_callback(struct pa_mainloop_api*a, void *id, void *userdata) { struct connection *c = userdata; assert(a && c && c->fixed_source == id); diff --git a/src/sink.c b/src/sink.c index 6a9f3580..9ba79e39 100644 --- a/src/sink.c +++ b/src/sink.c @@ -5,10 +5,9 @@ #include "sink.h" #include "sinkinput.h" -#include "strbuf.h" -#include "sample-util.h" #include "namereg.h" #include "util.h" +#include "sample-util.h" #define MAX_MIX_CHANNELS 32 @@ -260,42 +259,6 @@ struct pa_sink* pa_sink_get_default(struct pa_core *c) { return sink; } -char *pa_sink_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_sink *sink, *default_sink; - uint32_t index = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_ncontents(c->sinks)); - - default_sink = pa_sink_get_default(c); - - for (sink = pa_idxset_first(c->sinks, &index); sink; sink = pa_idxset_next(c->sinks, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - pa_sample_snprint(ss, sizeof(ss), &sink->sample_spec); - assert(sink->monitor_source); - pa_strbuf_printf( - s, - " %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", - sink == default_sink ? '*' : ' ', - sink->index, sink->name, - (unsigned) sink->volume, - pa_sink_get_latency(sink), - sink->monitor_source->index, - ss); - - if (sink->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", sink->owner->index); - if (sink->description) - pa_strbuf_printf(s, "\tdescription: <%s>\n", sink->description); - } - - return pa_strbuf_tostring_free(s); -} - void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m) { sink->owner = m; diff --git a/src/sink.h b/src/sink.h index 071ad094..a25a4377 100644 --- a/src/sink.h +++ b/src/sink.h @@ -39,8 +39,6 @@ uint32_t pa_sink_get_latency(struct pa_sink *s); void pa_sink_notify(struct pa_sink*s); -char *pa_sink_list_to_string(struct pa_core *core); - struct pa_sink* pa_sink_get_default(struct pa_core *c); void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m); diff --git a/src/sinkinput.c b/src/sinkinput.c index 3cfe49b3..54778a81 100644 --- a/src/sinkinput.c +++ b/src/sinkinput.c @@ -4,7 +4,6 @@ #include #include "sinkinput.h" -#include "strbuf.h" #include "sample-util.h" #define CONVERT_BUFFER_LENGTH 4096 @@ -75,39 +74,6 @@ void pa_sink_input_kill(struct pa_sink_input*i) { i->kill(i); } -char *pa_sink_input_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_sink_input *i; - uint32_t index = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_ncontents(c->sink_inputs)); - - for (i = pa_idxset_first(c->sink_inputs, &index); i; i = pa_idxset_next(c->sink_inputs, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - pa_sample_snprint(ss, sizeof(ss), &i->sample_spec); - assert(i->sink); - pa_strbuf_printf( - s, " index: %u\n\tname: <%s>\n\tsink: <%u>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tsample_spec: <%s>\n", - i->index, - i->name, - i->sink->index, - (unsigned) i->volume, - pa_sink_input_get_latency(i), - ss); - - if (i->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", i->owner->index); - if (i->client) - pa_strbuf_printf(s, "\tclient: <%u>\n", i->client->index); - } - - return pa_strbuf_tostring_free(s); -} - uint32_t pa_sink_input_get_latency(struct pa_sink_input *i) { uint32_t l = 0; @@ -121,7 +87,6 @@ uint32_t pa_sink_input_get_latency(struct pa_sink_input *i) { return l; } - int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { assert(i && chunk && i->peek && i->drop); diff --git a/src/sinkinput.h b/src/sinkinput.h index 8c9813e5..02a2a117 100644 --- a/src/sinkinput.h +++ b/src/sinkinput.h @@ -39,7 +39,6 @@ void pa_sink_input_free(struct pa_sink_input* i); void pa_sink_input_kill(struct pa_sink_input *i); uint32_t pa_sink_input_get_latency(struct pa_sink_input *i); -char *pa_sink_input_list_to_string(struct pa_core *c); int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk); void pa_sink_input_drop(struct pa_sink_input *i, size_t length); diff --git a/src/socket-client.c b/src/socket-client.c index 9a8c5607..8b2bd384 100644 --- a/src/socket-client.c +++ b/src/socket-client.c @@ -9,6 +9,7 @@ #include #include "socket-client.h" +#include "socket-util.h" #include "util.h" struct pa_socket_client { diff --git a/src/socket-server.c b/src/socket-server.c index 23d8f7e7..02b4328f 100644 --- a/src/socket-server.c +++ b/src/socket-server.c @@ -11,7 +11,7 @@ #include #include "socket-server.h" -#include "util.h" +#include "socket-util.h" struct pa_socket_server { int fd; diff --git a/src/socket-util.c b/src/socket-util.c new file mode 100644 index 00000000..f9451af8 --- /dev/null +++ b/src/socket-util.c @@ -0,0 +1,152 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "socket-util.h" + +void pa_socket_peer_to_string(int fd, char *c, size_t l) { + struct stat st; + + assert(c && l && fd >= 0); + + if (fstat(fd, &st) < 0) { + snprintf(c, l, "Invalid client fd"); + return; + } + + if (S_ISSOCK(st.st_mode)) { + union { + struct sockaddr sa; + struct sockaddr_in in; + struct sockaddr_un un; + } sa; + socklen_t sa_len = sizeof(sa); + + if (getpeername(fd, &sa.sa, &sa_len) >= 0) { + + if (sa.sa.sa_family == AF_INET) { + uint32_t ip = ntohl(sa.in.sin_addr.s_addr); + + snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u", + ip >> 24, + (ip >> 16) & 0xFF, + (ip >> 8) & 0xFF, + ip & 0xFF, + ntohs(sa.in.sin_port)); + return; + } else if (sa.sa.sa_family == AF_LOCAL) { + snprintf(c, l, "UNIX socket client"); + return; + } + + } + snprintf(c, l, "Unknown network client"); + return; + } else if (S_ISCHR(st.st_mode) && (fd == 0 || fd == 1)) { + snprintf(c, l, "STDIN/STDOUT client"); + return; + } + + snprintf(c, l, "Unknown client"); +} + +int pa_socket_low_delay(int fd) { + int priority; + assert(fd >= 0); + + priority = 7; + if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) + return -1; + + return 0; +} + +int pa_socket_tcp_low_delay(int fd) { + int ret, tos; + + assert(fd >= 0); + + ret = pa_socket_low_delay(fd); + +/* on = 1; */ +/* if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) */ +/* ret = -1; */ + + tos = IPTOS_LOWDELAY; + if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0) + ret = -1; + + return ret; + +} + +int pa_socket_set_rcvbuf(int fd, size_t l) { + assert(fd >= 0); + + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &l, sizeof(l)) < 0) + return -1; + + return 0; +} + +int pa_socket_set_sndbuf(int fd, size_t l) { + assert(fd >= 0); + + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &l, sizeof(l)) < 0) + return -1; + + return 0; +} + +int pa_unix_socket_is_stale(const char *fn) { + struct sockaddr_un sa; + int fd = -1, ret = -1; + + if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "socket(): %s\n", strerror(errno)); + goto finish; + } + + sa.sun_family = AF_LOCAL; + strncpy(sa.sun_path, fn, sizeof(sa.sun_path)-1); + sa.sun_path[sizeof(sa.sun_path) - 1] = 0; + + if (connect(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) { + if (errno == ECONNREFUSED) + ret = 1; + } else + ret = 0; + +finish: + if (fd >= 0) + close(fd); + + return ret; +} + +int pa_unix_socket_remove_stale(const char *fn) { + int r; + + if ((r = pa_unix_socket_is_stale(fn)) < 0) + return errno != ENOENT ? -1 : 0; + + if (!r) + return 0; + + /* Yes, here is a race condition. But who cares? */ + if (unlink(fn) < 0) + return -1; + + return 0; +} diff --git a/src/socket-util.h b/src/socket-util.h new file mode 100644 index 00000000..1c4dbe35 --- /dev/null +++ b/src/socket-util.h @@ -0,0 +1,17 @@ +#ifndef foosocketutilhfoo +#define foosocketutilhfoo + +#include + +void pa_socket_peer_to_string(int fd, char *c, size_t l); + +int pa_socket_low_delay(int fd); +int pa_socket_tcp_low_delay(int fd); + +int pa_socket_set_sndbuf(int fd, size_t l); +int pa_socket_set_rcvbuf(int fd, size_t l); + +int pa_unix_socket_is_stale(const char *fn); +int pa_unix_socket_remove_stale(const char *fn); + +#endif diff --git a/src/source.c b/src/source.c index 45ccfb27..c0eec3ea 100644 --- a/src/source.c +++ b/src/source.c @@ -5,7 +5,6 @@ #include "source.h" #include "sourceoutput.h" -#include "strbuf.h" #include "namereg.h" struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec) { @@ -101,35 +100,6 @@ struct pa_source* pa_source_get_default(struct pa_core *c) { return source; } -char *pa_source_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_source *source, *default_source; - uint32_t index = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_ncontents(c->sources)); - - default_source = pa_source_get_default(c); - - for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - pa_sample_snprint(ss, sizeof(ss), &source->sample_spec); - pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\tsample_spec: <%s>\n", source == default_source ? '*' : ' ', source->index, source->name, ss); - - if (source->monitor_of) - pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index); - if (source->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", source->owner->index); - if (source->description) - pa_strbuf_printf(s, "\tdescription: <%s>\n", source->description); - } - - return pa_strbuf_tostring_free(s); -} - void pa_source_set_owner(struct pa_source *s, struct pa_module *m) { assert(s); s->owner = m; diff --git a/src/source.h b/src/source.h index 2bc5bea8..9e57bc0f 100644 --- a/src/source.h +++ b/src/source.h @@ -33,8 +33,6 @@ void pa_source_post(struct pa_source*s, struct pa_memchunk *b); void pa_source_notify(struct pa_source *s); -char *pa_source_list_to_string(struct pa_core *c); - struct pa_source* pa_source_get_default(struct pa_core *c); void pa_source_set_owner(struct pa_source *s, struct pa_module *m); diff --git a/src/sourceoutput.c b/src/sourceoutput.c index ea727576..25c661a9 100644 --- a/src/sourceoutput.c +++ b/src/sourceoutput.c @@ -3,7 +3,6 @@ #include #include "sourceoutput.h" -#include "strbuf.h" struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec) { struct pa_source_output *o; @@ -58,36 +57,6 @@ void pa_source_output_kill(struct pa_source_output*i) { i->kill(i); } -char *pa_source_output_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_source_output *o; - uint32_t index = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_ncontents(c->source_outputs)); - - for (o = pa_idxset_first(c->source_outputs, &index); o; o = pa_idxset_next(c->source_outputs, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - pa_sample_snprint(ss, sizeof(ss), &o->sample_spec); - assert(o->source); - pa_strbuf_printf( - s, " index: %u\n\tname: <%s>\n\tsource: <%u>\n\tsample_spec: <%s>\n", - o->index, - o->name, - o->source->index, - ss); - if (o->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", o->owner->index); - if (o->client) - pa_strbuf_printf(s, "\tclient: <%u>\n", o->client->index); - } - - return pa_strbuf_tostring_free(s); -} - void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk *chunk) { struct pa_memchunk rchunk; assert(o && chunk && chunk->length && o->push); diff --git a/src/sourceoutput.h b/src/sourceoutput.h index dfd076db..a8ea5a9f 100644 --- a/src/sourceoutput.h +++ b/src/sourceoutput.h @@ -32,8 +32,6 @@ void pa_source_output_free(struct pa_source_output* o); void pa_source_output_kill(struct pa_source_output*o); -char *pa_source_output_list_to_string(struct pa_core *c); - void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk *chunk); #endif diff --git a/src/todo b/src/todo index 36e69a18..bf01a4c4 100644 --- a/src/todo +++ b/src/todo @@ -5,7 +5,6 @@ - move more stuff from module-oss[-dma] to liboss-util -- create libstatustext, libsocketutil - prefix modules/libraries with pa_ - xmms+esound latency testing @@ -14,8 +13,6 @@ - svn-id and license in every file - documentation -- dependency checking script - -- post 0.1 - future cancellation - client-ui diff --git a/src/util.c b/src/util.c index aceb772d..773922b5 100644 --- a/src/util.c +++ b/src/util.c @@ -5,13 +5,9 @@ #include #include #include -#include -#include #include #include #include -#include -#include #include "util.h" @@ -23,52 +19,6 @@ void pa_make_nonblock_fd(int fd) { fcntl(fd, F_SETFL, v|O_NONBLOCK); } -void pa_peer_to_string(char *c, size_t l, int fd) { - struct stat st; - - assert(c && l && fd >= 0); - - if (fstat(fd, &st) < 0) { - snprintf(c, l, "Invalid client fd"); - return; - } - - if (S_ISSOCK(st.st_mode)) { - union { - struct sockaddr sa; - struct sockaddr_in in; - struct sockaddr_un un; - } sa; - socklen_t sa_len = sizeof(sa); - - if (getpeername(fd, &sa.sa, &sa_len) >= 0) { - - if (sa.sa.sa_family == AF_INET) { - uint32_t ip = ntohl(sa.in.sin_addr.s_addr); - - snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u", - ip >> 24, - (ip >> 16) & 0xFF, - (ip >> 8) & 0xFF, - ip & 0xFF, - ntohs(sa.in.sin_port)); - return; - } else if (sa.sa.sa_family == AF_LOCAL) { - snprintf(c, l, "UNIX socket client"); - return; - } - - } - snprintf(c, l, "Unknown network client"); - return; - } else if (S_ISCHR(st.st_mode) && (fd == 0 || fd == 1)) { - snprintf(c, l, "STDIN/STDOUT client"); - return; - } - - snprintf(c, l, "Unknown client"); -} - int pa_make_secure_dir(const char* dir) { struct stat st; @@ -89,54 +39,6 @@ fail: return -1; } -int pa_socket_low_delay(int fd) { - int priority; - assert(fd >= 0); - - priority = 7; - if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) - return -1; - - return 0; -} - -int pa_socket_tcp_low_delay(int fd) { - int ret, tos; - - assert(fd >= 0); - - ret = pa_socket_low_delay(fd); - -/* on = 1; */ -/* if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) */ -/* ret = -1; */ - - tos = IPTOS_LOWDELAY; - if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0) - ret = -1; - - return ret; - -} - -int pa_socket_set_rcvbuf(int fd, size_t l) { - assert(fd >= 0); - - if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &l, sizeof(l)) < 0) - return -1; - - return 0; -} - -int pa_socket_set_sndbuf(int fd, size_t l) { - assert(fd >= 0); - - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &l, sizeof(l)) < 0) - return -1; - - return 0; -} - ssize_t pa_loop_read(int fd, void*data, size_t size) { ssize_t ret = 0; assert(fd >= 0 && data && size); @@ -179,48 +81,6 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size) { return ret; } -int pa_unix_socket_is_stale(const char *fn) { - struct sockaddr_un sa; - int fd = -1, ret = -1; - - if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { - fprintf(stderr, "socket(): %s\n", strerror(errno)); - goto finish; - } - - sa.sun_family = AF_LOCAL; - strncpy(sa.sun_path, fn, sizeof(sa.sun_path)-1); - sa.sun_path[sizeof(sa.sun_path) - 1] = 0; - - if (connect(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) { - if (errno == ECONNREFUSED) - ret = 1; - } else - ret = 0; - -finish: - if (fd >= 0) - close(fd); - - return ret; -} - -int pa_unix_socket_remove_stale(const char *fn) { - int r; - - if ((r = pa_unix_socket_is_stale(fn)) < 0) - return errno != ENOENT ? -1 : 0; - - if (!r) - return 0; - - /* Yes, here is a race condition. But who cares? */ - if (unlink(fn) < 0) - return -1; - - return 0; -} - void pa_check_for_sigpipe(void) { struct sigaction sa; diff --git a/src/util.h b/src/util.h index c5c6db82..3e494434 100644 --- a/src/util.h +++ b/src/util.h @@ -5,22 +5,11 @@ void pa_make_nonblock_fd(int fd); -void pa_peer_to_string(char *c, size_t l, int fd); - int pa_make_secure_dir(const char* dir); -int pa_socket_low_delay(int fd); -int pa_socket_tcp_low_delay(int fd); - -int pa_socket_set_sndbuf(int fd, size_t l); -int pa_socket_set_rcvbuf(int fd, size_t l); - ssize_t pa_loop_read(int fd, void*data, size_t size); ssize_t pa_loop_write(int fd, const void*data, size_t size); -int pa_unix_socket_is_stale(const char *fn); -int pa_unix_socket_remove_stale(const char *fn); - void pa_check_for_sigpipe(void); char *pa_sprintf_malloc(const char *format, ...) __attribute__ ((format (printf, 1, 2))); -- cgit From a96ed347a30fdc7494b96542c0ad8a19ef178b25 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 11 Jul 2004 16:59:22 +0000 Subject: rename hashset to hashmap add module arguments parse in modargs.c make module-pipe-sink use it git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@61 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 5 +- src/core.h | 4 +- src/hashmap.c | 145 ++++++++++++++++++++++++++++++++ src/hashmap.h | 16 ++++ src/hashset.c | 145 -------------------------------- src/hashset.h | 16 ---- src/modargs.c | 222 +++++++++++++++++++++++++++++++++++++++++++++++++ src/modargs.h | 18 ++++ src/module-pipe-sink.c | 75 ++++++++++++----- src/namereg.c | 18 ++-- src/todo | 6 +- 11 files changed, 472 insertions(+), 198 deletions(-) create mode 100644 src/hashmap.c create mode 100644 src/hashmap.h delete mode 100644 src/hashset.c delete mode 100644 src/hashset.h create mode 100644 src/modargs.c create mode 100644 src/modargs.h diff --git a/src/Makefile.am b/src/Makefile.am index 51129534..e8704f78 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -75,7 +75,7 @@ polypaudio_SOURCES = idxset.c idxset.h \ mainloop-signal.c mainloop-signal.h \ mainloop-api.c mainloop-api.h \ util.c util.h \ - hashset.c hashset.h \ + hashmap.c hashmap.h \ namereg.c namereg.h \ sconv.c sconv.h \ resampler.c resampler.h \ @@ -83,7 +83,8 @@ polypaudio_SOURCES = idxset.c idxset.h \ memchunk.c memchunk.h \ sconv-s16le.c sconv-s16le.h \ sconv-s16be.c sconv-s16be.h \ - sioman.c sioman.h + sioman.c sioman.h \ + modargs.c modargs.h polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) diff --git a/src/core.h b/src/core.h index 8eb638d9..13374e40 100644 --- a/src/core.h +++ b/src/core.h @@ -2,7 +2,7 @@ #define foocorehfoo #include "idxset.h" -#include "hashset.h" +#include "hashmap.h" #include "mainloop-api.h" struct pa_core { @@ -10,7 +10,7 @@ struct pa_core { struct pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules; - struct pa_hashset *namereg; + struct pa_hashmap *namereg; uint32_t default_source_index, default_sink_index; }; diff --git a/src/hashmap.c b/src/hashmap.c new file mode 100644 index 00000000..0c963f12 --- /dev/null +++ b/src/hashmap.c @@ -0,0 +1,145 @@ +#include +#include +#include + +#include "hashmap.h" +#include "idxset.h" + +struct hashmap_entry { + struct hashmap_entry *next, *previous, *bucket_next, *bucket_previous; + unsigned hash; + const void *key; + void *value; +}; + +struct pa_hashmap { + unsigned size; + struct hashmap_entry **data; + struct hashmap_entry *first_entry; + + unsigned n_entries; + unsigned (*hash_func) (const void *p); + int (*compare_func) (const void*a, const void*b); +}; + +struct pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { + struct pa_hashmap *h; + h = malloc(sizeof(struct pa_hashmap)); + assert(h); + h->data = malloc(sizeof(struct hashmap_entry*)*(h->size = 1023)); + assert(h->data); + memset(h->data, 0, sizeof(struct hashmap_entry*)*(h->size = 1023)); + h->first_entry = NULL; + h->n_entries = 0; + h->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; + h->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; + return h; +} + +static void remove(struct pa_hashmap *h, struct hashmap_entry *e) { + assert(e); + + if (e->next) + e->next->previous = e->previous; + if (e->previous) + e->previous->next = e->next; + else + h->first_entry = e->next; + + if (e->bucket_next) + e->bucket_next->bucket_previous = e->bucket_previous; + if (e->bucket_previous) + e->bucket_previous->bucket_next = e->bucket_next; + else + h->data[e->hash] = e->bucket_next; + + free(e); + h->n_entries--; +} + +void pa_hashmap_free(struct pa_hashmap*h, void (*free_func)(void *p, void *userdata), void *userdata) { + assert(h); + + while (h->first_entry) { + if (free_func) + free_func(h->first_entry->value, userdata); + remove(h, h->first_entry); + } + + free(h->data); + free(h); +} + +static struct hashmap_entry *get(struct pa_hashmap *h, unsigned hash, const void *key) { + struct hashmap_entry *e; + + for (e = h->data[hash]; e; e = e->bucket_next) + if (h->compare_func(e->key, key) == 0) + return e; + + return NULL; +} + +int pa_hashmap_put(struct pa_hashmap *h, const void *key, void *value) { + struct hashmap_entry *e; + unsigned hash; + assert(h && key); + + hash = h->hash_func(key) % h->size; + + if ((e = get(h, hash, key))) + return -1; + + e = malloc(sizeof(struct hashmap_entry)); + assert(e); + + e->hash = hash; + e->key = key; + e->value = value; + + e->previous = NULL; + e->next = h->first_entry; + if (h->first_entry) + h->first_entry->previous = e; + h->first_entry = e; + + e->bucket_previous = NULL; + e->bucket_next = h->data[hash]; + if (h->data[hash]) + h->data[hash]->bucket_previous = e; + h->data[hash] = e; + + h->n_entries ++; + return 0; +} + +void* pa_hashmap_get(struct pa_hashmap *h, const void *key) { + unsigned hash; + struct hashmap_entry *e; + assert(h && key); + + hash = h->hash_func(key) % h->size; + + if (!(e = get(h, hash, key))) + return NULL; + + return e->value; +} + +int pa_hashmap_remove(struct pa_hashmap *h, const void *key) { + struct hashmap_entry *e; + unsigned hash; + assert(h && key); + + hash = h->hash_func(key) % h->size; + + if (!(e = get(h, hash, key))) + return 1; + + remove(h, e); + return 0; +} + +unsigned pa_hashmap_ncontents(struct pa_hashmap *h) { + return h->n_entries; +} diff --git a/src/hashmap.h b/src/hashmap.h new file mode 100644 index 00000000..4a0ad77e --- /dev/null +++ b/src/hashmap.h @@ -0,0 +1,16 @@ +#ifndef foohashmaphfoo +#define foohashmaphfoo + +struct pa_hashmap; + +struct pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); +void pa_hashmap_free(struct pa_hashmap*, void (*free_func)(void *p, void *userdata), void *userdata); + +int pa_hashmap_put(struct pa_hashmap *h, const void *key, void *value); +void* pa_hashmap_get(struct pa_hashmap *h, const void *key); + +int pa_hashmap_remove(struct pa_hashmap *h, const void *key); + +unsigned pa_hashmap_ncontents(struct pa_hashmap *h); + +#endif diff --git a/src/hashset.c b/src/hashset.c deleted file mode 100644 index 4815a13a..00000000 --- a/src/hashset.c +++ /dev/null @@ -1,145 +0,0 @@ -#include -#include -#include - -#include "hashset.h" -#include "idxset.h" - -struct hashset_entry { - struct hashset_entry *next, *previous, *bucket_next, *bucket_previous; - unsigned hash; - const void *key; - void *value; -}; - -struct pa_hashset { - unsigned size; - struct hashset_entry **data; - struct hashset_entry *first_entry; - - unsigned n_entries; - unsigned (*hash_func) (const void *p); - int (*compare_func) (const void*a, const void*b); -}; - -struct pa_hashset *pa_hashset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { - struct pa_hashset *h; - h = malloc(sizeof(struct pa_hashset)); - assert(h); - h->data = malloc(sizeof(struct hashset_entry*)*(h->size = 1023)); - assert(h->data); - memset(h->data, 0, sizeof(struct hashset_entry*)*(h->size = 1023)); - h->first_entry = NULL; - h->n_entries = 0; - h->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; - h->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; - return h; -} - -static void remove(struct pa_hashset *h, struct hashset_entry *e) { - assert(e); - - if (e->next) - e->next->previous = e->previous; - if (e->previous) - e->previous->next = e->next; - else - h->first_entry = e->next; - - if (e->bucket_next) - e->bucket_next->bucket_previous = e->bucket_previous; - if (e->bucket_previous) - e->bucket_previous->bucket_next = e->bucket_next; - else - h->data[e->hash] = e->bucket_next; - - free(e); - h->n_entries--; -} - -void pa_hashset_free(struct pa_hashset*h, void (*free_func)(void *p, void *userdata), void *userdata) { - assert(h); - - while (h->first_entry) { - if (free_func) - free_func(h->first_entry->value, userdata); - remove(h, h->first_entry); - } - - free(h->data); - free(h); -} - -static struct hashset_entry *get(struct pa_hashset *h, unsigned hash, const void *key) { - struct hashset_entry *e; - - for (e = h->data[hash]; e; e = e->bucket_next) - if (h->compare_func(e->key, key) == 0) - return e; - - return NULL; -} - -int pa_hashset_put(struct pa_hashset *h, const void *key, void *value) { - struct hashset_entry *e; - unsigned hash; - assert(h && key); - - hash = h->hash_func(key) % h->size; - - if ((e = get(h, hash, key))) - return -1; - - e = malloc(sizeof(struct hashset_entry)); - assert(e); - - e->hash = hash; - e->key = key; - e->value = value; - - e->previous = NULL; - e->next = h->first_entry; - if (h->first_entry) - h->first_entry->previous = e; - h->first_entry = e; - - e->bucket_previous = NULL; - e->bucket_next = h->data[hash]; - if (h->data[hash]) - h->data[hash]->bucket_previous = e; - h->data[hash] = e; - - h->n_entries ++; - return 0; -} - -void* pa_hashset_get(struct pa_hashset *h, const void *key) { - unsigned hash; - struct hashset_entry *e; - assert(h && key); - - hash = h->hash_func(key) % h->size; - - if (!(e = get(h, hash, key))) - return NULL; - - return e->value; -} - -int pa_hashset_remove(struct pa_hashset *h, const void *key) { - struct hashset_entry *e; - unsigned hash; - assert(h && key); - - hash = h->hash_func(key) % h->size; - - if (!(e = get(h, hash, key))) - return 1; - - remove(h, e); - return 0; -} - -unsigned pa_hashset_ncontents(struct pa_hashset *h) { - return h->n_entries; -} diff --git a/src/hashset.h b/src/hashset.h deleted file mode 100644 index a6ece8bf..00000000 --- a/src/hashset.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef foohashsethfoo -#define foohashsethfoo - -struct pa_hashset; - -struct pa_hashset *pa_hashset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); -void pa_hashset_free(struct pa_hashset*, void (*free_func)(void *p, void *userdata), void *userdata); - -int pa_hashset_put(struct pa_hashset *h, const void *key, void *value); -void* pa_hashset_get(struct pa_hashset *h, const void *key); - -int pa_hashset_remove(struct pa_hashset *h, const void *key); - -unsigned pa_hashset_ncontents(struct pa_hashset *h); - -#endif diff --git a/src/modargs.c b/src/modargs.c new file mode 100644 index 00000000..a7b48808 --- /dev/null +++ b/src/modargs.c @@ -0,0 +1,222 @@ +#include +#include +#include +#include + +#include "hashmap.h" +#include "modargs.h" +#include "idxset.h" +#include "sample-util.h" + +struct pa_modargs; + +struct entry { + char *key, *value; +}; + +static int add_key_value(struct pa_hashmap *map, char *key, char *value, const char* const* valid_keys) { + struct entry *e; + assert(map && key && value); + + if (valid_keys) { + const char*const* v; + for (v = valid_keys; *v; v++) + if (strcmp(*v, key) == 0) + break; + + if (!*v) { + free(key); + free(value); + return -1; + } + } + + e = malloc(sizeof(struct entry)); + assert(e); + e->key = key; + e->value = value; + pa_hashmap_put(map, key, e); + return 0; +} + +struct pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) { + struct pa_hashmap *map = NULL; + + map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + assert(map); + + if (args) { + enum { WHITESPACE, KEY, VALUE_START, VALUE_SIMPLE, VALUE_DOUBLE_QUOTES, VALUE_TICKS } state; + const char *p, *key, *value; + size_t key_len, value_len; + + key = value = NULL; + state = WHITESPACE; + for (p = args; *p; p++) { + switch (state) { + case WHITESPACE: + if (*p == '=') + goto fail; + else if (!isspace(*p)) { + key = p; + state = KEY; + key_len = 1; + } + break; + case KEY: + if (*p == '=') + state = VALUE_START; + else + key_len++; + break; + case VALUE_START: + if (*p == '\'') { + state = VALUE_TICKS; + value = p+1; + value_len = 0; + } else if (*p == '"') { + state = VALUE_DOUBLE_QUOTES; + value = p+1; + value_len = 0; + } else if (isspace(*p)) { + if (add_key_value(map, strndup(key, key_len), strdup(""), valid_keys) < 0) + goto fail; + state = WHITESPACE; + } else { + state = VALUE_SIMPLE; + value = p; + value_len = 1; + } + break; + case VALUE_SIMPLE: + if (isspace(*p)) { + if (add_key_value(map, strndup(key, key_len), strndup(value, value_len), valid_keys) < 0) + goto fail; + state = WHITESPACE; + } else + value_len++; + break; + case VALUE_DOUBLE_QUOTES: + if (*p == '"') { + if (add_key_value(map, strndup(key, key_len), strndup(value, value_len), valid_keys) < 0) + goto fail; + state = WHITESPACE; + } else + value_len++; + break; + case VALUE_TICKS: + if (*p == '\'') { + if (add_key_value(map, strndup(key, key_len), strndup(value, value_len), valid_keys) < 0) + goto fail; + state = WHITESPACE; + } else + value_len++; + break; + } + } + + if (state == VALUE_START) { + if (add_key_value(map, strndup(key, key_len), strdup(""), valid_keys) < 0) + goto fail; + } else if (state == VALUE_SIMPLE) { + if (add_key_value(map, strndup(key, key_len), strdup(value), valid_keys) < 0) + goto fail; + } else if (state != WHITESPACE) + goto fail; + } + + return (struct pa_modargs*) map; + +fail: + + if (map) + pa_modargs_free((struct pa_modargs*) map); + + return NULL; +} + + +static void free_func(void *p, void*userdata) { + struct entry *e = p; + assert(e); + free(e->key); + free(e->value); + free(e); +} + +void pa_modargs_free(struct pa_modargs*ma) { + struct pa_hashmap *map = (struct pa_hashmap*) ma; + pa_hashmap_free(map, free_func, NULL); +} + +const char *pa_modargs_get_value(struct pa_modargs *ma, const char *key, const char *def) { + struct pa_hashmap *map = (struct pa_hashmap*) ma; + struct entry*e; + + if (!(e = pa_hashmap_get(map, key))) + return def; + + return e->value; +} + +int pa_modargs_get_value_u32(struct pa_modargs *ma, const char *key, uint32_t *value) { + const char *v; + char *e; + unsigned long l; + assert(ma && key && value); + + if (!(v = pa_modargs_get_value(ma, key, NULL))) + return 0; + + if (!*v) + return -1; + + l = strtoul(v, &e, 0); + if (*e) + return -1; + + *value = (uint32_t) l; + return 0; +} + +int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *rss) { + const char *format; + uint32_t channels; + struct pa_sample_spec ss; + assert(ma && rss); + + ss = pa_default_sample_spec; + if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0) + return -1; + + channels = ss.channels; + if ((pa_modargs_get_value_u32(ma, "channels", &channels)) < 0) + return -1; + ss.channels = (uint8_t) channels; + + if ((format = pa_modargs_get_value(ma, "format", NULL))) { + if (strcmp(format, "s16le") == 0) + ss.format = PA_SAMPLE_S16LE; + else if (strcmp(format, "s16be") == 0) + ss.format = PA_SAMPLE_S16BE; + else if (strcmp(format, "s16ne") == 0 || strcmp(format, "s16") == 0 || strcmp(format, "16") == 0) + ss.format = PA_SAMPLE_S16NE; + else if (strcmp(format, "u8") == 0 || strcmp(format, "8") == 0) + ss.format = PA_SAMPLE_U8; + else if (strcmp(format, "float32") == 0) + ss.format = PA_SAMPLE_FLOAT32; + else if (strcmp(format, "ulaw") == 0) + ss.format = PA_SAMPLE_ULAW; + else if (strcmp(format, "alaw") == 0) + ss.format = PA_SAMPLE_ALAW; + else + return -1; + } + + if (!pa_sample_spec_valid(&ss)) + return -1; + + *rss = ss; + + return 0; +} diff --git a/src/modargs.h b/src/modargs.h new file mode 100644 index 00000000..437dd432 --- /dev/null +++ b/src/modargs.h @@ -0,0 +1,18 @@ +#ifndef foomodargshfoo +#define foomodargshfoo + +#include +#include "sample.h" + +struct pa_modargs; + +struct pa_modargs *pa_modargs_new(const char *args, const char* const* keys); +void pa_modargs_free(struct pa_modargs*ma); + +const char *pa_modargs_get_value(struct pa_modargs *ma, const char *key, const char *def); +int pa_modargs_get_value_u32(struct pa_modargs *ma, const char *key, uint32_t *value); + +int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *ss); + + +#endif diff --git a/src/module-pipe-sink.c b/src/module-pipe-sink.c index 67c02404..e5e97b51 100644 --- a/src/module-pipe-sink.c +++ b/src/module-pipe-sink.c @@ -12,24 +12,37 @@ #include "sink.h" #include "module.h" #include "util.h" +#include "modargs.h" + +#define DEFAULT_FIFO_NAME "/tmp/musicfifo" +#define DEFAULT_SINK_NAME "fifo_output" struct userdata { + struct pa_core *core; + char *filename; struct pa_sink *sink; struct pa_iochannel *io; - struct pa_core *core; void *mainloop_source; - struct pa_mainloop_api *mainloop; struct pa_memchunk memchunk; }; +static const char* const valid_modargs[] = { + "file", + "rate", + "channels", + "format", + "sink", + NULL +}; + static void do_write(struct userdata *u) { ssize_t r; assert(u); - u->mainloop->enable_fixed(u->mainloop, u->mainloop_source, 0); + u->core->mainloop->enable_fixed(u->core->mainloop, u->mainloop_source, 0); if (!pa_iochannel_is_writable(u->io)) return; @@ -59,7 +72,7 @@ static void notify_cb(struct pa_sink*s) { assert(s && u); if (pa_iochannel_is_writable(u->io)) - u->mainloop->enable_fixed(u->mainloop, u->mainloop_source, 1); + u->core->mainloop->enable_fixed(u->core->mainloop, u->mainloop_source, 1); } static void fixed_callback(struct pa_mainloop_api *m, void *id, void *userdata) { @@ -77,41 +90,51 @@ static void io_callback(struct pa_iochannel *io, void*userdata) { int pa_module_init(struct pa_core *c, struct pa_module*m) { struct userdata *u = NULL; struct stat st; - char *p; + const char *p; int fd = -1; - static const struct pa_sample_spec ss = { - .format = PA_SAMPLE_S16NE, - .rate = 44100, - .channels = 2, - }; + struct pa_sample_spec ss; + struct pa_modargs *ma = NULL; assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + fprintf(stderr, __FILE__": failed to parse module arguments\n"); + goto fail; + } - mkfifo((p = m->argument ? m->argument : "/tmp/musicfifo"), 0777); + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + fprintf(stderr, __FILE__": invalid sample format specification\n"); + goto fail; + } + + mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777); if ((fd = open(p, O_RDWR)) < 0) { - fprintf(stderr, "open('%s'): %s\n", p, strerror(errno)); + fprintf(stderr, __FILE__": open('%s'): %s\n", p, strerror(errno)); goto fail; } if (fstat(fd, &st) < 0) { - fprintf(stderr, "fstat('%s'): %s\n", p, strerror(errno)); + fprintf(stderr, __FILE__": fstat('%s'): %s\n", p, strerror(errno)); goto fail; } if (!S_ISFIFO(st.st_mode)) { - fprintf(stderr, "'%s' is not a FIFO\n", p); + fprintf(stderr, __FILE__": '%s' is not a FIFO.\n", p); goto fail; } - u = malloc(sizeof(struct userdata)); assert(u); + memset(u, 0, sizeof(struct userdata)); u->filename = strdup(p); assert(u->filename); u->core = c; - u->sink = pa_sink_new(c, "fifo", 0, &ss); - assert(u->sink); + + if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink", DEFAULT_SINK_NAME), 0, &ss))) { + fprintf(stderr, __FILE__": failed to create sink.\n"); + goto fail; + } u->sink->notify = notify_cb; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); @@ -125,19 +148,25 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { u->memchunk.memblock = NULL; u->memchunk.length = 0; - u->mainloop = c->mainloop; - u->mainloop_source = u->mainloop->source_fixed(u->mainloop, fixed_callback, u); + u->mainloop_source = c->mainloop->source_fixed(c->mainloop, fixed_callback, u); assert(u->mainloop_source); - u->mainloop->enable_fixed(u->mainloop, u->mainloop_source, 0); + c->mainloop->enable_fixed(c->mainloop, u->mainloop_source, 0); m->userdata = u; + pa_modargs_free(ma); + return 0; fail: + if (ma) + pa_modargs_free(ma); + if (fd >= 0) close(fd); + pa_module_done(c, m); + return -1; } @@ -145,15 +174,15 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { struct userdata *u; assert(c && m); - u = m->userdata; - assert(u); + if (!(u = m->userdata)) + return; if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); pa_sink_free(u->sink); pa_iochannel_free(u->io); - u->mainloop->cancel_fixed(u->mainloop, u->mainloop_source); + u->core->mainloop->cancel_fixed(u->core->mainloop, u->mainloop_source); assert(u->filename); unlink(u->filename); diff --git a/src/namereg.c b/src/namereg.c index 9cfb7353..bf381ae4 100644 --- a/src/namereg.c +++ b/src/namereg.c @@ -17,8 +17,8 @@ void pa_namereg_free(struct pa_core *c) { assert(c); if (!c->namereg) return; - assert(pa_hashset_ncontents(c->namereg) == 0); - pa_hashset_free(c->namereg, NULL, NULL); + assert(pa_hashmap_ncontents(c->namereg) == 0); + pa_hashmap_free(c->namereg, NULL, NULL); } const char *pa_namereg_register(struct pa_core *c, const char *name, enum pa_namereg_type type, void *data, int fail) { @@ -29,11 +29,11 @@ const char *pa_namereg_register(struct pa_core *c, const char *name, enum pa_nam assert(c && name && data); if (!c->namereg) { - c->namereg = pa_hashset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + c->namereg = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); assert(c->namereg); } - if ((e = pa_hashset_get(c->namereg, name)) && fail) + if ((e = pa_hashmap_get(c->namereg, name)) && fail) return NULL; if (!e) @@ -47,7 +47,7 @@ const char *pa_namereg_register(struct pa_core *c, const char *name, enum pa_nam for (i = 1; i <= 99; i++) { snprintf(n, l+2, "%s%u", name, i); - if (!(e = pa_hashset_get(c->namereg, n))) + if (!(e = pa_hashmap_get(c->namereg, n))) break; } @@ -64,7 +64,7 @@ const char *pa_namereg_register(struct pa_core *c, const char *name, enum pa_nam e->name = n; e->data = data; - r = pa_hashset_put(c->namereg, e->name, e); + r = pa_hashmap_put(c->namereg, e->name, e); assert (r >= 0); return e->name; @@ -76,10 +76,10 @@ void pa_namereg_unregister(struct pa_core *c, const char *name) { int r; assert(c && name); - e = pa_hashset_get(c->namereg, name); + e = pa_hashmap_get(c->namereg, name); assert(e); - r = pa_hashset_remove(c->namereg, name); + r = pa_hashmap_remove(c->namereg, name); assert(r >= 0); free(e->name); @@ -93,7 +93,7 @@ void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type t void *d = NULL; assert(c && name); - if ((e = pa_hashset_get(c->namereg, name))) + if ((e = pa_hashmap_get(c->namereg, name))) if (e->type == e->type) return e->data; diff --git a/src/todo b/src/todo index bf01a4c4..deab2163 100644 --- a/src/todo +++ b/src/todo @@ -1,7 +1,9 @@ - native library/protocol: more functions (esp. latency) -- config parser/cmdline +- make all modules use modargs.c +- cmdline +- daemonizing - move more stuff from module-oss[-dma] to liboss-util @@ -13,6 +15,8 @@ - svn-id and license in every file - documentation +- eliminate global variables + -- post 0.1 - future cancellation - client-ui -- cgit From 216591d95e00a0cb771088dad9a752efead55e10 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 11 Jul 2004 22:20:08 +0000 Subject: make the protocol plugins make use of modargs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@62 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/authkey.c | 11 ++++++ src/authkey.h | 1 + src/modargs.c | 37 ++++++++++++++++++ src/modargs.h | 3 ++ src/module-cli.c | 7 +++- src/module-protocol-stub.c | 96 ++++++++++++++++++++++++++++++---------------- src/protocol-cli.c | 2 +- src/protocol-cli.h | 3 +- src/protocol-esound.c | 21 +++++++--- src/protocol-esound.h | 3 +- src/protocol-native.c | 14 +++++-- src/protocol-native.h | 3 +- src/protocol-simple.c | 94 ++++++++++++++++++++++++++++++++++----------- src/protocol-simple.h | 9 +---- src/socket-util.c | 39 +++++++++++++++++++ src/socket-util.h | 3 ++ src/todo | 4 +- 17 files changed, 273 insertions(+), 77 deletions(-) diff --git a/src/authkey.c b/src/authkey.c index cd284fb5..7bf45165 100644 --- a/src/authkey.c +++ b/src/authkey.c @@ -106,6 +106,8 @@ int pa_authkey_load_from_home(const char *fn, void *data, size_t length) { char *home; char path[PATH_MAX]; + assert(fn && data && length); + if (!(home = getenv("HOME"))) return -2; @@ -113,3 +115,12 @@ int pa_authkey_load_from_home(const char *fn, void *data, size_t length) { return pa_authkey_load(path, data, length); } + +int pa_authkey_load_auto(const char *fn, void *data, size_t length) { + assert(fn && data && length); + + if (*fn == '/') + return pa_authkey_load(fn, data, length); + else + return pa_authkey_load_from_home(fn, data, length); +} diff --git a/src/authkey.h b/src/authkey.h index cc0fcb28..a0d695a9 100644 --- a/src/authkey.h +++ b/src/authkey.h @@ -5,5 +5,6 @@ int pa_authkey_load(const char *path, void *data, size_t len); int pa_authkey_load_from_home(const char *fn, void *data, size_t length); +int pa_authkey_load_auto(const char *fn, void *data, size_t length); #endif diff --git a/src/modargs.c b/src/modargs.c index a7b48808..a716a80e 100644 --- a/src/modargs.c +++ b/src/modargs.c @@ -7,6 +7,9 @@ #include "modargs.h" #include "idxset.h" #include "sample-util.h" +#include "namereg.h" +#include "sink.h" +#include "source.h" struct pa_modargs; @@ -220,3 +223,37 @@ int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *rss return 0; } + +int pa_modargs_get_source_index(struct pa_modargs *ma, struct pa_core *c, uint32_t *index) { + const char *t; + assert(ma && index); + + if (!(t = pa_modargs_get_value(ma, "source", NULL))) + *index = PA_IDXSET_INVALID; + else { + struct pa_source *source; + if (!(source = pa_namereg_get(c, t, PA_NAMEREG_SOURCE))) + return -1; + + *index = source->index; + } + + return 0; +} + +int pa_modargs_get_sink_index(struct pa_modargs *ma, struct pa_core *c, uint32_t *index) { + const char *t; + assert(ma && index); + + if (!(t = pa_modargs_get_value(ma, "sink", NULL))) + *index = PA_IDXSET_INVALID; + else { + struct pa_sink *sink; + if (!(sink = pa_namereg_get(c, t, PA_NAMEREG_SINK))) + return -1; + + *index = sink->index; + } + + return 0; +} diff --git a/src/modargs.h b/src/modargs.h index 437dd432..07792ef3 100644 --- a/src/modargs.h +++ b/src/modargs.h @@ -3,6 +3,7 @@ #include #include "sample.h" +#include "core.h" struct pa_modargs; @@ -14,5 +15,7 @@ int pa_modargs_get_value_u32(struct pa_modargs *ma, const char *key, uint32_t *v int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *ss); +int pa_modargs_get_source_index(struct pa_modargs *ma, struct pa_core *c, uint32_t *index); +int pa_modargs_get_sink_index(struct pa_modargs *ma, struct pa_core *c, uint32_t *index); #endif diff --git a/src/module-cli.c b/src/module-cli.c index 440c4ba5..135d3588 100644 --- a/src/module-cli.c +++ b/src/module-cli.c @@ -18,8 +18,13 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { struct pa_iochannel *io; assert(c && m); + if (m->argument) { + fprintf(stderr, __FILE__": module doesn't accept arguments.\n"); + return -1; + } + if (pa_stdio_acquire() < 0) { - fprintf(stderr, "STDIN/STDUSE already used\n"); + fprintf(stderr, __FILE__": STDIN/STDUSE already in use.\n"); return -1; } diff --git a/src/module-protocol-stub.c b/src/module-protocol-stub.c index 0547f7e6..4f82d4e0 100644 --- a/src/module-protocol-stub.c +++ b/src/module-protocol-stub.c @@ -9,29 +9,31 @@ #include "socket-server.h" #include "socket-util.h" #include "util.h" +#include "modargs.h" #ifdef USE_PROTOCOL_SIMPLE #include "protocol-simple.h" + #define protocol_new pa_protocol_simple_new #define protocol_free pa_protocol_simple_free #define IPV4_PORT 4711 - #define UNIX_SOCKET_DIR "/tmp/polypaudio" #define UNIX_SOCKET "/tmp/polypaudio/simple" + #define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record", #else #ifdef USE_PROTOCOL_CLI #include "protocol-cli.h" #define protocol_new pa_protocol_cli_new #define protocol_free pa_protocol_cli_free #define IPV4_PORT 4712 - #define UNIX_SOCKET_DIR "/tmp/polypaudio" #define UNIX_SOCKET "/tmp/polypaudio/cli" + #define MODULE_ARGUMENTS #else #ifdef USE_PROTOCOL_NATIVE #include "protocol-native.h" #define protocol_new pa_protocol_native_new #define protocol_free pa_protocol_native_free #define IPV4_PORT 4713 - #define UNIX_SOCKET_DIR "/tmp/polypaudio" #define UNIX_SOCKET "/tmp/polypaudio/native" + #define MODULE_ARGUMENTS "public", "cookie", #else #ifdef USE_PROTOCOL_ESOUND #include "protocol-esound.h" @@ -39,8 +41,8 @@ #define protocol_new pa_protocol_esound_new #define protocol_free pa_protocol_esound_free #define IPV4_PORT ESD_DEFAULT_PORT - #define UNIX_SOCKET_DIR ESD_UNIX_SOCKET_DIR #define UNIX_SOCKET ESD_UNIX_SOCKET_NAME + #define MODULE_ARGUMENTS "sink", "source", "public", "cookie", #else #error "Broken build system" #endif @@ -48,43 +50,75 @@ #endif #endif -int pa_module_init(struct pa_core *c, struct pa_module*m) { - struct pa_socket_server *s; - assert(c && m); +static const char* const valid_modargs[] = { + MODULE_ARGUMENTS +#ifdef USE_TCP_SOCKETS + "port", + "loopback", +#else + "socket", +#endif + NULL +}; +struct pa_socket_server *create_socket_server(struct pa_core *c, struct pa_modargs *ma) { + struct pa_socket_server *s; #ifdef USE_TCP_SOCKETS - if (!(s = pa_socket_server_new_ipv4(c->mainloop, INADDR_ANY, IPV4_PORT))) - return -1; + uint32_t loopback = 0, port = IPV4_PORT; + + if (pa_modargs_get_value_u32(ma, "loopback", &loopback) < 0) { + fprintf(stderr, "loopback= expects a numerical argument.\n"); + return NULL; + } + + if (pa_modargs_get_value_u32(ma, "port", &port) < 0) { + fprintf(stderr, "port= expects a numerical argument.\n"); + return NULL; + } + + if (!(s = pa_socket_server_new_ipv4(c->mainloop, loopback ? INADDR_LOOPBACK : INADDR_ANY, port))) + return NULL; #else - if (pa_make_secure_dir(UNIX_SOCKET_DIR) < 0) { + int r; + const char *p; + + p = pa_modargs_get_value(ma, "socket", UNIX_SOCKET); + assert(p); + + if (pa_unix_socket_make_secure_dir(p) < 0) { fprintf(stderr, "Failed to create secure socket directory.\n"); - return -1; + return NULL; } - { - int r; - if ((r = pa_unix_socket_remove_stale(UNIX_SOCKET)) < 0) { - fprintf(stderr, "Failed to remove stale UNIX socket '%s': %s\n", UNIX_SOCKET, strerror(errno)); - return -1; - } - - if (r) - fprintf(stderr, "Removed stale UNIX socket '%s'.", UNIX_SOCKET); + if ((r = pa_unix_socket_remove_stale(p)) < 0) { + fprintf(stderr, "Failed to remove stale UNIX socket '%s': %s\n", p, strerror(errno)); + return NULL; } - if (!(s = pa_socket_server_new_unix(c->mainloop, UNIX_SOCKET))) { - rmdir(UNIX_SOCKET_DIR); + if (r) + fprintf(stderr, "Removed stale UNIX socket '%s'.", p); + + if (!(s = pa_socket_server_new_unix(c->mainloop, p))) + return NULL; + +#endif + return s; +} + +int pa_module_init(struct pa_core *c, struct pa_module*m) { + struct pa_socket_server *s; + struct pa_modargs *ma; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + fprintf(stderr, "Failed to parse module arguments\n"); return -1; } -#endif -#ifdef USE_PROTOCOL_SIMPLE - m->userdata = pa_protocol_simple_new(c, s, m, PA_PROTOCOL_SIMPLE_PLAYBACK); -#else - m->userdata = protocol_new(c, s, m); -#endif + if (!(s = create_socket_server(c, ma))) + return -1; - if (!m->userdata) { + if (!(m->userdata = protocol_new(c, s, m, ma))) { pa_socket_server_free(s); return -1; } @@ -96,8 +130,4 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { assert(c && m); protocol_free(m->userdata); - -#ifndef USE_TCP_SOCKETS - rmdir(UNIX_SOCKET_DIR); -#endif } diff --git a/src/protocol-cli.c b/src/protocol-cli.c index 55b4a8a0..0e738321 100644 --- a/src/protocol-cli.c +++ b/src/protocol-cli.c @@ -30,7 +30,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo pa_idxset_put(p->connections, c, NULL); } -struct pa_protocol_cli* pa_protocol_cli_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m) { +struct pa_protocol_cli* pa_protocol_cli_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { struct pa_protocol_cli* p; assert(core && server); diff --git a/src/protocol-cli.h b/src/protocol-cli.h index c3bb8b4f..f970bb8d 100644 --- a/src/protocol-cli.h +++ b/src/protocol-cli.h @@ -4,10 +4,11 @@ #include "core.h" #include "socket-server.h" #include "module.h" +#include "modargs.h" struct pa_protocol_cli; -struct pa_protocol_cli* pa_protocol_cli_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m); +struct pa_protocol_cli* pa_protocol_cli_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma); void pa_protocol_cli_free(struct pa_protocol_cli *n); #endif diff --git a/src/protocol-esound.c b/src/protocol-esound.c index 955ab93c..cba72438 100644 --- a/src/protocol-esound.c +++ b/src/protocol-esound.c @@ -17,7 +17,7 @@ #include "authkey.h" -#define COOKIE_FILE ".esd_auth" +#define DEFAULT_COOKIE_FILE ".esd_auth" #define PLAYBACK_BUFFER_SECONDS (.5) #define PLAYBACK_BUFFER_FRAGMENTS (10) @@ -774,14 +774,24 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo /*** entry points ***/ -struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m) { +struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { + uint32_t source_index, sink_index; struct pa_protocol_esound *p; - assert(core && server); + assert(core && server && ma); + if (pa_modargs_get_source_index(ma, core, &source_index) < 0) { + fprintf(stderr, __FILE__": source does not exist.\n"); + return NULL; + } + + if (pa_modargs_get_sink_index(ma, core, &sink_index) < 0) { + fprintf(stderr, __FILE__": sink does not exist.\n"); + return NULL; + } p = malloc(sizeof(struct pa_protocol_esound)); assert(p); - if (pa_authkey_load_from_home(COOKIE_FILE, p->esd_key, sizeof(p->esd_key)) < 0) { + if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", DEFAULT_COOKIE_FILE), p->esd_key, sizeof(p->esd_key)) < 0) { free(p); return NULL; } @@ -793,7 +803,8 @@ struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa p->core = core; p->connections = pa_idxset_new(NULL, NULL); assert(p->connections); - p->sink_index = p->source_index = PA_IDXSET_INVALID; + p->sink_index = sink_index; + p->source_index = source_index; p->n_player = 0; return p; diff --git a/src/protocol-esound.h b/src/protocol-esound.h index 6071699d..8653949d 100644 --- a/src/protocol-esound.h +++ b/src/protocol-esound.h @@ -4,10 +4,11 @@ #include "core.h" #include "socket-server.h" #include "module.h" +#include "modargs.h" struct pa_protocol_esound; -struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m); +struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma); void pa_protocol_esound_free(struct pa_protocol_esound *p); #endif diff --git a/src/protocol-native.c b/src/protocol-native.c index d6a5f9b2..abd17026 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -736,20 +736,26 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo /*** module entry points ***/ -struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m) { +struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { struct pa_protocol_native *p; - assert(core && server); + uint32_t public; + assert(core && server && ma); + if (pa_modargs_get_value_u32(ma, "public", &public) < 0) { + fprintf(stderr, __FILE__": public= expects numeric argument.\n"); + return NULL; + } + p = malloc(sizeof(struct pa_protocol_native)); assert(p); - if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, p->auth_cookie, sizeof(p->auth_cookie)) < 0) { + if (pa_authkey_load_from_home(pa_modargs_get_value(ma, "cookie", PA_NATIVE_COOKIE_FILE), p->auth_cookie, sizeof(p->auth_cookie)) < 0) { free(p); return NULL; } p->module = m; - p->public = 1; + p->public = public; p->server = server; p->core = core; p->connections = pa_idxset_new(NULL, NULL); diff --git a/src/protocol-native.h b/src/protocol-native.h index 811b4e4a..89cb1634 100644 --- a/src/protocol-native.h +++ b/src/protocol-native.h @@ -4,10 +4,11 @@ #include "core.h" #include "socket-server.h" #include "module.h" +#include "modargs.h" struct pa_protocol_native; -struct pa_protocol_native* pa_protocol_native_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m); +struct pa_protocol_native* pa_protocol_native_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma); void pa_protocol_native_free(struct pa_protocol_native *n); #endif diff --git a/src/protocol-simple.c b/src/protocol-simple.c index b57f324a..89207133 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -10,6 +10,7 @@ #include "protocol-simple.h" #include "client.h" #include "sample-util.h" +#include "namereg.h" struct connection { struct pa_protocol_simple *protocol; @@ -31,8 +32,13 @@ struct pa_protocol_simple { struct pa_core *core; struct pa_socket_server*server; struct pa_idxset *connections; - enum pa_protocol_simple_mode mode; + enum { + RECORD = 1, + PLAYBACK = 2, + DUPLEX = 3 + } mode; struct pa_sample_spec sample_spec; + uint32_t sink_index, source_index; }; #define PLAYBACK_BUFFER_SECONDS (.5) @@ -263,14 +269,15 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->client->kill = client_kill_cb; c->client->userdata = c; - if (p->mode & PA_PROTOCOL_SIMPLE_PLAYBACK) { + if (p->mode & PLAYBACK) { struct pa_sink *sink; size_t l; - if (!(sink = pa_sink_get_default(p->core))) { - fprintf(stderr, "Failed to get default sink.\n"); - goto fail; - } + if (!(sink = pa_idxset_get_by_index(p->core->sinks, p->sink_index))) + if (!(sink = pa_sink_get_default(p->core))) { + fprintf(stderr, "Failed to get sink.\n"); + goto fail; + } c->sink_input = pa_sink_input_new(sink, c->client->name, &p->sample_spec); if (!c->sink_input) { @@ -293,15 +300,15 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->playback.fragment_size = l/10; } - - if (p->mode & PA_PROTOCOL_SIMPLE_RECORD) { + if (p->mode & RECORD) { struct pa_source *source; size_t l; - if (!(source = pa_source_get_default(p->core))) { - fprintf(stderr, "Failed to get default source.\n"); - goto fail; - } + if (!(source = pa_idxset_get_by_index(p->core->sources, p->source_index))) + if (!(source = pa_source_get_default(p->core))) { + fprintf(stderr, "Failed to get source.\n"); + goto fail; + } c->source_output = pa_source_output_new(source, c->client->name, &p->sample_spec); if (!c->source_output) { @@ -334,22 +341,62 @@ fail: connection_free(c); } -struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, enum pa_protocol_simple_mode mode) { - struct pa_protocol_simple* p; - assert(core && server && mode <= PA_PROTOCOL_SIMPLE_DUPLEX && mode > 0); +struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { + struct pa_protocol_simple* p = NULL; + uint32_t enable; + assert(core && server && ma); p = malloc(sizeof(struct pa_protocol_simple)); assert(p); + memset(p, 0, sizeof(struct pa_protocol_simple)); + p->module = m; p->core = core; p->server = server; p->connections = pa_idxset_new(NULL, NULL); - p->mode = mode; - p->sample_spec = PA_DEFAULT_SAMPLE_SPEC; + if (pa_modargs_get_sample_spec(ma, &p->sample_spec) < 0) { + fprintf(stderr, "Failed to parse sample type specification.\n"); + goto fail; + } + + if (pa_modargs_get_source_index(ma, core, &p->source_index) < 0) { + fprintf(stderr, __FILE__": source does not exist.\n"); + goto fail; + } + + if (pa_modargs_get_sink_index(ma, core, &p->sink_index) < 0) { + fprintf(stderr, __FILE__": sink does not exist.\n"); + goto fail; + } + + enable = 0; + if (pa_modargs_get_value_u32(ma, "record", &enable) < 0) { + fprintf(stderr, __FILE__": record= expects a numeric argument.\n"); + goto fail; + } + p->mode = enable ? RECORD : 0; + + enable = 1; + if (pa_modargs_get_value_u32(ma, "playback", &enable) < 0) { + fprintf(stderr, __FILE__": playback= expects a numeric argument.\n"); + goto fail; + } + p->mode |= enable ? PLAYBACK : 0; + + if ((p->mode & (RECORD|PLAYBACK)) == 0) { + fprintf(stderr, __FILE__": neither playback nor recording enabled for protocol.\n"); + goto fail; + } + pa_socket_server_set_callback(p->server, on_connection, p); return p; + +fail: + if (p) + pa_protocol_simple_free(p); + return NULL; } @@ -357,12 +404,15 @@ void pa_protocol_simple_free(struct pa_protocol_simple *p) { struct connection *c; assert(p); - while((c = pa_idxset_first(p->connections, NULL))) - connection_free(c); + if (p->connections) { + while((c = pa_idxset_first(p->connections, NULL))) + connection_free(c); + + pa_idxset_free(p->connections, NULL, NULL); + } - pa_idxset_free(p->connections, NULL, NULL); - - pa_socket_server_free(p->server); + if (p->server) + pa_socket_server_free(p->server); free(p); } diff --git a/src/protocol-simple.h b/src/protocol-simple.h index 6b2a2cd1..62682915 100644 --- a/src/protocol-simple.h +++ b/src/protocol-simple.h @@ -4,16 +4,11 @@ #include "socket-server.h" #include "module.h" #include "core.h" +#include "modargs.h" struct pa_protocol_simple; -enum pa_protocol_simple_mode { - PA_PROTOCOL_SIMPLE_RECORD = 1, - PA_PROTOCOL_SIMPLE_PLAYBACK = 2, - PA_PROTOCOL_SIMPLE_DUPLEX = 3 -}; - -struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, enum pa_protocol_simple_mode mode); +struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma); void pa_protocol_simple_free(struct pa_protocol_simple *n); #endif diff --git a/src/socket-util.c b/src/socket-util.c index f9451af8..f4648da5 100644 --- a/src/socket-util.c +++ b/src/socket-util.c @@ -14,6 +14,7 @@ #include #include "socket-util.h" +#include "util.h" void pa_socket_peer_to_string(int fd, char *c, size_t l) { struct stat st; @@ -150,3 +151,41 @@ int pa_unix_socket_remove_stale(const char *fn) { return 0; } + +int pa_unix_socket_make_secure_dir(const char *fn) { + int ret = -1; + char *slash, *dir = strdup(fn); + assert(dir); + + if (!(slash = strrchr(dir, '/'))) + goto finish; + *slash = 0; + + if (pa_make_secure_dir(dir) < 0) + goto finish; + + ret = 0; + +finish: + free(dir); + return ret; +} + +int pa_unix_socket_remove_secure_dir(const char *fn) { + int ret = -1; + char *slash, *dir = strdup(fn); + assert(dir); + + if (!(slash = strrchr(dir, '/'))) + goto finish; + *slash = 0; + + if (rmdir(dir) < 0) + goto finish; + + ret = 0; + +finish: + free(dir); + return ret; +} diff --git a/src/socket-util.h b/src/socket-util.h index 1c4dbe35..0133bfc3 100644 --- a/src/socket-util.h +++ b/src/socket-util.h @@ -14,4 +14,7 @@ int pa_socket_set_rcvbuf(int fd, size_t l); int pa_unix_socket_is_stale(const char *fn); int pa_unix_socket_remove_stale(const char *fn); +int pa_unix_socket_make_secure_dir(const char *fn); +int pa_unix_socket_remove_secure_dir(const char *fn); + #endif diff --git a/src/todo b/src/todo index deab2163..b131ac73 100644 --- a/src/todo +++ b/src/todo @@ -1,7 +1,9 @@ - native library/protocol: more functions (esp. latency) -- make all modules use modargs.c +- make all modules use modargs.c: + module-oss.c + module-oss-mmap.c - cmdline - daemonizing -- cgit From d4e0d51c157dea740d35089f077451b6ec7b11a5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 11 Jul 2004 23:21:32 +0000 Subject: make module-oss-* use modargs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@63 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/main.c | 2 +- src/module-oss-mmap.c | 68 +++++++++++++++++++++++++------------------------- src/module-oss.c | 62 ++++++++++++++++++++++++++------------------- src/module-pipe-sink.c | 4 +-- src/oss-util.c | 54 +++++++++++++++++++++++++++++++++++++++ src/oss-util.h | 1 + src/todo | 14 +++++------ 7 files changed, 135 insertions(+), 70 deletions(-) diff --git a/src/main.c b/src/main.c index e2d86b48..8ba554c8 100644 --- a/src/main.c +++ b/src/main.c @@ -42,7 +42,7 @@ int main(int argc, char *argv[]) { c = pa_core_new(pa_mainloop_get_api(mainloop)); assert(c); - pa_module_load(c, "module-oss-mmap", "/dev/dsp"); + 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); diff --git a/src/module-oss-mmap.c b/src/module-oss-mmap.c index 772abf99..a9e13086 100644 --- a/src/module-oss-mmap.c +++ b/src/module-oss-mmap.c @@ -18,6 +18,7 @@ #include "oss-util.h" #include "sample-util.h" #include "util.h" +#include "modargs.h" struct userdata { struct pa_sink *sink; @@ -38,8 +39,18 @@ struct userdata { unsigned out_current, in_current; }; -void module_done(struct pa_core *c, struct pa_module*m); +static const char* const valid_modargs[] = { + "sink_name", + "source_name", + "device", + "record", + "playback", + NULL +}; +#define DEFAULT_SINK_NAME "oss_output" +#define DEFAULT_SOURCE_NAME "oss_input" +#define DEFAULT_DEVICE "/dev/dsp" static void out_fill_memblocks(struct userdata *u, unsigned n) { assert(u && u->out_memblocks); @@ -163,10 +174,12 @@ static uint32_t sink_get_latency_cb(struct pa_sink *s) { int pa_module_init(struct pa_core *c, struct pa_module*m) { struct audio_buf_info info; struct userdata *u = NULL; - char *p; + const char *p; int frag_size; - int mode, caps, caps_read = 0; + int mode, caps; int enable_bits = 0, zero = 0; + int playback = 1, record = 1; + struct pa_modargs *ma = NULL; assert(c && m); m->userdata = u = malloc(sizeof(struct userdata)); @@ -174,39 +187,26 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { memset(u, 0, sizeof(struct userdata)); u->fd = -1; u->core = c; - - p = m->argument ? m->argument : "/dev/dsp"; - if ((u->fd = open(p, (mode = O_RDWR)|O_NDELAY)) >= 0) { - ioctl(u->fd, SNDCTL_DSP_SETDUPLEX, 0); - - if (ioctl(u->fd, SNDCTL_DSP_GETCAPS, &caps) < 0) { - fprintf(stderr, "SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); - goto fail; - } - if (!(caps & DSP_CAP_DUPLEX)) { - close(u->fd); - u->fd = -1; - } else - caps_read = 1; + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + fprintf(stderr, __FILE__": failed to parse module arguments.\n"); + goto fail; } - - if (u->fd < 0) { - if ((u->fd = open(p, (mode = O_WRONLY)|O_NDELAY)) < 0) { - if ((u->fd = open(p, (mode = O_RDONLY)|O_NDELAY)) < 0) { - fprintf(stderr, "open('%s'): %s\n", p, strerror(errno)); - goto fail; - } - } + + if (pa_modargs_get_value_u32(ma, "record", &record) < 0 || pa_modargs_get_value_u32(ma, "playback", &playback) < 0) { + fprintf(stderr, __FILE__": record= and playback= expect numeric arguments.\n"); + goto fail; } - if (!caps_read) { - if (ioctl(u->fd, SNDCTL_DSP_GETCAPS, &caps) < 0) { - fprintf(stderr, "SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); - goto fail; - } + mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); + if (mode == 0) { + fprintf(stderr, __FILE__": neither playback nor record enabled for device.\n"); + goto fail; } - + + if ((u->fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0) + goto fail; + if (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_REALTIME) || !(caps & DSP_CAP_TRIGGER)) { fprintf(stderr, "OSS device not mmap capable.\n"); goto fail; @@ -242,7 +242,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { } } else { - u->source = pa_source_new(c, "oss_input", 0, &u->sample_spec); + u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec); assert(u->source); u->source->userdata = u; pa_source_set_owner(u->source, m); @@ -276,7 +276,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { } else { pa_silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec); - u->sink = pa_sink_new(c, "oss_output", 0, &u->sample_spec); + u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; u->sink->userdata = u; @@ -309,7 +309,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { return 0; fail: - module_done(c, m); + pa_module_done(c, m); return -1; } diff --git a/src/module-oss.c b/src/module-oss.c index b0677584..31ca2dba 100644 --- a/src/module-oss.c +++ b/src/module-oss.c @@ -17,6 +17,7 @@ #include "oss-util.h" #include "sample-util.h" #include "util.h" +#include "modargs.h" struct userdata { struct pa_sink *sink; @@ -31,6 +32,19 @@ struct userdata { int fd; }; +static const char* const valid_modargs[] = { + "sink_name", + "source_name", + "device", + "record", + "playback", + NULL +}; + +#define DEFAULT_SINK_NAME "oss_output" +#define DEFAULT_SOURCE_NAME "oss_input" +#define DEFAULT_DEVICE "/dev/dsp" + static void do_write(struct userdata *u) { struct pa_memchunk *memchunk; ssize_t r; @@ -115,39 +129,34 @@ static uint32_t sink_get_latency_cb(struct pa_sink *s) { int pa_module_init(struct pa_core *c, struct pa_module*m) { struct audio_buf_info info; struct userdata *u = NULL; - char *p; + const char *p; int fd = -1; int frag_size, in_frag_size, out_frag_size; int mode; + uint32_t record = 1, playback = 1; struct pa_sample_spec ss; + struct pa_modargs *ma = NULL; assert(c && m); - p = m->argument ? m->argument : "/dev/dsp"; - if ((fd = open(p, (mode = O_RDWR)|O_NDELAY)) >= 0) { - int caps; - - ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0); - - if (ioctl(fd, SNDCTL_DSP_GETCAPS, &caps) < 0) { - fprintf(stderr, "SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); - goto fail; - } - - if (!(caps & DSP_CAP_DUPLEX)) { - close(fd); - fd = -1; - } + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + fprintf(stderr, __FILE__": failed to parse module arguments.\n"); + goto fail; + } + + if (pa_modargs_get_value_u32(ma, "record", &record) < 0 || pa_modargs_get_value_u32(ma, "playback", &playback) < 0) { + fprintf(stderr, __FILE__": record= and playback= expect numeric argument.\n"); + goto fail; } - if (fd < 0) { - if ((fd = open(p, (mode = O_WRONLY)|O_NDELAY)) < 0) { - if ((fd = open(p, (mode = O_RDONLY)|O_NDELAY)) < 0) { - fprintf(stderr, "open('%s'): %s\n", p, strerror(errno)); - goto fail; - } - } + mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); + if (mode == 0) { + fprintf(stderr, __FILE__": neither playback nor record enabled for device.\n"); + goto fail; } + if ((fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, NULL)) < 0) + goto fail; + fprintf(stderr, "module-oss: device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); frag_size = ((int) 12 << 16) | 10; /* nfrags = 12; frag_size = 2^10 */ @@ -182,7 +191,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { u->core = c; if (mode != O_WRONLY) { - u->source = pa_source_new(c, "oss_input", 0, &ss); + u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); assert(u->source); u->source->userdata = u; pa_source_set_owner(u->source, m); @@ -191,7 +200,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { u->source = NULL; if (mode != O_RDONLY) { - u->sink = pa_sink_new(c, "oss_output", 0, &ss); + u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; u->sink->userdata = u; @@ -226,6 +235,9 @@ fail: if (fd >= 0) close(fd); + if (ma) + pa_modargs_free(ma); + return -1; } diff --git a/src/module-pipe-sink.c b/src/module-pipe-sink.c index e5e97b51..29767ea8 100644 --- a/src/module-pipe-sink.c +++ b/src/module-pipe-sink.c @@ -34,7 +34,7 @@ static const char* const valid_modargs[] = { "rate", "channels", "format", - "sink", + "sink_name", NULL }; @@ -131,7 +131,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { assert(u->filename); u->core = c; - if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink", DEFAULT_SINK_NAME), 0, &ss))) { + if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { fprintf(stderr, __FILE__": failed to create sink.\n"); goto fail; } diff --git a/src/oss-util.c b/src/oss-util.c index 9c4f55ca..f1e07017 100644 --- a/src/oss-util.c +++ b/src/oss-util.c @@ -4,9 +4,63 @@ #include #include #include +#include +#include +#include +#include #include "oss-util.h" +int pa_oss_open(const char *device, int *mode, int* pcaps) { + int fd = -1; + assert(device && mode && (*mode == O_RDWR || *mode == O_RDONLY || *mode == O_WRONLY)); + + if (*mode == O_RDWR) { + if ((fd = open(device, O_RDWR|O_NDELAY)) >= 0) { + int dcaps, *tcaps; + ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0); + + tcaps = pcaps ? pcaps : &dcaps; + + if (ioctl(fd, SNDCTL_DSP_GETCAPS, tcaps) < 0) { + fprintf(stderr, __FILE__": SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); + goto fail; + } + + if (*tcaps & DSP_CAP_DUPLEX) + return fd; + + close(fd); + } + + if ((fd = open(device, (*mode = O_WRONLY)|O_NDELAY)) < 0) { + if ((fd = open(device, (*mode = O_RDONLY)|O_NDELAY)) < 0) { + fprintf(stderr, __FILE__": open('%s'): %s\n", device, strerror(errno)); + goto fail; + } + } + } else { + if ((fd = open(device, *mode|O_NDELAY)) < 0) { + fprintf(stderr, __FILE__": open('%s'): %s\n", device, strerror(errno)); + goto fail; + } + } + + if (pcaps) { + if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { + fprintf(stderr, "SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); + goto fail; + } + } + + return fd; + +fail: + if (fd >= 0) + close(fd); + return fd; +} + int pa_oss_auto_format(int fd, struct pa_sample_spec *ss) { int format, channels, speed; diff --git a/src/oss-util.h b/src/oss-util.h index cf12e8e6..030afba4 100644 --- a/src/oss-util.h +++ b/src/oss-util.h @@ -3,6 +3,7 @@ #include "sample.h" +int pa_oss_open(const char *device, int *mode, int* pcaps); int pa_oss_auto_format(int fd, struct pa_sample_spec *ss); #endif diff --git a/src/todo b/src/todo index b131ac73..febdca7c 100644 --- a/src/todo +++ b/src/todo @@ -1,13 +1,7 @@ - native library/protocol: more functions (esp. latency) -- make all modules use modargs.c: - module-oss.c - module-oss-mmap.c -- cmdline -- daemonizing - -- move more stuff from module-oss[-dma] to liboss-util +- cmdline & daemonizing - prefix modules/libraries with pa_ @@ -17,7 +11,10 @@ - svn-id and license in every file - documentation -- eliminate global variables +- eliminate global variables: + pa_default_sample_spec + pa_memblock_count + pa_memblock_total -- post 0.1 - future cancellation @@ -27,6 +24,7 @@ - slp/rendezvous - doxygen - make mcalign merge chunks +- modinfo drivers: - libao -- cgit From b69178b067d4151de08bdcdaa9922d2838134c3c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 12 Jul 2004 21:28:11 +0000 Subject: add preliminary command line parsing git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@64 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 3 +- src/cmdline.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/cmdline.h | 19 +++++++++++ src/main.c | 15 +++++++++ 4 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 src/cmdline.c create mode 100644 src/cmdline.h diff --git a/src/Makefile.am b/src/Makefile.am index e8704f78..bdd621ab 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -84,7 +84,8 @@ polypaudio_SOURCES = idxset.c idxset.h \ sconv-s16le.c sconv-s16le.h \ sconv-s16be.c sconv-s16be.h \ sioman.c sioman.h \ - modargs.c modargs.h + modargs.c modargs.h \ + cmdline.c cmdline.h polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) diff --git a/src/cmdline.c b/src/cmdline.c new file mode 100644 index 00000000..36fe3e61 --- /dev/null +++ b/src/cmdline.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include + +#include "cmdline.h" +#include "util.h" + +void pa_cmdline_help(const char *argv0) { + const char *e; + + if ((e = strrchr(argv0, '/'))) + e++; + else + e = 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" + " -D Daemonize after loading the modules\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; + assert(argc && argv); + + cmdline = malloc(sizeof(struct pa_cmdline)); + assert(cmdline); + cmdline->daemonize = cmdline->help = 0; + cmdline->first_module = cmdline->last_module = NULL; + + while ((c = getopt(argc, argv, "L:F:CDh")) != -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); + break; + } + case 'F': + add_module(cmdline, strdup("module-cli"), pa_sprintf_malloc("file='%s'", optarg)); + break; + case 'C': + add_module(cmdline, strdup("module-cli"), NULL); + break; + case 'D': + cmdline->daemonize = 1; + break; + case 'h': + cmdline->help = 1; + break; + default: + goto fail; + } + } + + return cmdline; + +fail: + if (cmdline) + pa_cmdline_free(cmdline); + 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); +} diff --git a/src/cmdline.h b/src/cmdline.h new file mode 100644 index 00000000..9a647706 --- /dev/null +++ b/src/cmdline.h @@ -0,0 +1,19 @@ +#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; +}; + +struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []); +void pa_cmdline_free(struct pa_cmdline *cmd); + +void pa_cmdline_help(const char *argv0); + +#endif diff --git a/src/main.c b/src/main.c index 8ba554c8..e2c8eb63 100644 --- a/src/main.c +++ b/src/main.c @@ -9,6 +9,7 @@ #include "mainloop.h" #include "module.h" #include "mainloop-signal.h" +#include "cmdline.h" static struct pa_mainloop *mainloop; @@ -26,8 +27,20 @@ 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; int r, retval = 0; + if (!(cmdline = pa_cmdline_parse(argc, argv))) { + fprintf(stderr, "Failed to parse command line.\n"); + return 1; + } + + if (cmdline->help) { + pa_cmdline_help(argv[0]); + pa_cmdline_free(cmdline); + return 0; + } + r = lt_dlinit(); assert(r == 0); @@ -67,6 +80,8 @@ int main(int argc, char *argv[]) { pa_signal_done(); pa_mainloop_free(mainloop); + + lt_dlexit(); return retval; -- cgit 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 From e83b7106ac1c008d1fa077c4bbb68423a46e604c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 14 Jul 2004 22:48:49 +0000 Subject: update todo fix polypaudio.run git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@66 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypaudio.run | 2 -- src/todo | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/polypaudio.run b/src/polypaudio.run index f82ad40e..5d258852 100755 --- a/src/polypaudio.run +++ b/src/polypaudio.run @@ -9,5 +9,3 @@ load module-native-protocol-unix load module-cli-protocol-unix load module-oss-mmap device="/dev/dsp" - -load module-cli diff --git a/src/todo b/src/todo index febdca7c..db007d97 100644 --- a/src/todo +++ b/src/todo @@ -1,7 +1,7 @@ - native library/protocol: more functions (esp. latency) -- cmdline & daemonizing +- daemonizing - prefix modules/libraries with pa_ -- cgit From 1416fef19796fa5372e6ed02cfd18574a040255f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 15 Jul 2004 00:16:27 +0000 Subject: implement client side TCP support git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@67 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/cli-command.c | 5 ++-- src/polyp.c | 65 +++++++++++++++++++++++++++++++++++++++++++--- src/protocol-native-spec.h | 1 + src/socket-client.c | 31 ++++++++++++++++++++-- src/socket-client.h | 1 + src/todo | 7 +++-- 6 files changed, 100 insertions(+), 10 deletions(-) diff --git a/src/cli-command.c b/src/cli-command.c index 06e0eb30..bf3ab0c4 100644 --- a/src/cli-command.c +++ b/src/cli-command.c @@ -193,9 +193,10 @@ static int pa_cli_command_load(struct pa_core *c, struct pa_tokenizer *t, struct return -1; } - if (*verbose) + if (*verbose) { snprintf(txt, sizeof(txt), "Module successfully loaded, index: %u.\n", m->index); - pa_strbuf_puts(buf, txt); + pa_strbuf_puts(buf, txt); + } return 0; } diff --git a/src/polyp.c b/src/polyp.c index fde0c68b..75187d79 100644 --- a/src/polyp.c +++ b/src/polyp.c @@ -2,6 +2,9 @@ #include #include #include +#include +#include +#include #include "polyp.h" #include "protocol-native-spec.h" @@ -21,6 +24,7 @@ #define DEFAULT_TIMEOUT (5*60) #define DEFAULT_SERVER "/tmp/polypaudio/native" +#define DEFAULT_PORT "4713" struct pa_context { char *name; @@ -284,7 +288,7 @@ static void on_connection(struct pa_socket_client *client, struct pa_iochannel*i struct pa_context *c = userdata; struct pa_tagstruct *t; uint32_t tag; - assert(client && io && c && c->state == CONTEXT_CONNECTING); + assert(client && c && c->state == CONTEXT_CONNECTING); pa_socket_client_free(client); c->client = NULL; @@ -318,6 +322,36 @@ static void on_connection(struct pa_socket_client *client, struct pa_iochannel*i c->state = CONTEXT_AUTHORIZING; } +static struct sockaddr *resolve_server(const char *server, size_t *len) { + struct sockaddr *sa; + struct addrinfo hints, *result = NULL; + char *port; + assert(server && len); + + if ((port = strrchr(server, ':'))) + port++; + if (!port) + port = DEFAULT_PORT; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + if (getaddrinfo(server, port, &hints, &result) != 0) + return NULL; + assert(result); + + sa = malloc(*len = result->ai_addrlen); + assert(sa); + memcpy(sa, result->ai_addr, *len); + + freeaddrinfo(result); + + return sa; + +} + int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { assert(c && c->state == CONTEXT_UNCONNECTED); @@ -326,10 +360,33 @@ int pa_context_connect(struct pa_context *c, const char *server, void (*complete return -1; } + if (!server) + if (!(server = getenv("POLYP_SERVER"))) + server = DEFAULT_SERVER; + assert(!c->client); - if (!(c->client = pa_socket_client_new_unix(c->mainloop, server ? server : DEFAULT_SERVER))) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; + + if (*server == '/') { + if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + } else { + struct sockaddr* sa; + size_t sa_len; + + if (!(sa = resolve_server(server, &sa_len))) { + c->error = PA_ERROR_INVALIDSERVER; + return -1; + } + + c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); + free(sa); + + if (!c->client) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } } c->connect_complete_callback = complete; diff --git a/src/protocol-native-spec.h b/src/protocol-native-spec.h index 5e67fe74..78dc06c2 100644 --- a/src/protocol-native-spec.h +++ b/src/protocol-native-spec.h @@ -35,6 +35,7 @@ enum { PA_ERROR_INTERNAL, PA_ERROR_CONNECTIONTERMINATED, PA_ERROR_KILLED, + PA_ERROR_INVALIDSERVER, PA_ERROR_MAX }; diff --git a/src/socket-client.c b/src/socket-client.c index 8b2bd384..b1e609ab 100644 --- a/src/socket-client.c +++ b/src/socket-client.c @@ -80,7 +80,7 @@ static void connect_fixed_cb(struct pa_mainloop_api *m, void *id, void *userdata static void connect_io_cb(struct pa_mainloop_api*m, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { struct pa_socket_client *c = userdata; - assert(m && c && c->io_source == id && fd >= 0 && events == PA_MAINLOOP_API_IO_EVENT_OUTPUT); + assert(m && c && c->io_source == id && fd >= 0); m->cancel_io(m, c->io_source); c->io_source = NULL; do_call(c); @@ -93,7 +93,7 @@ static int do_connect(struct pa_socket_client *c, const struct sockaddr *sa, soc pa_make_nonblock_fd(c->fd); if ((r = connect(c->fd, sa, len)) < 0) { - if (r != EINPROGRESS) { + if (errno != EINPROGRESS) { fprintf(stderr, "connect(): %s\n", strerror(errno)); return -1; } @@ -165,7 +165,34 @@ fail: pa_socket_client_free(c); return NULL; } + +struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) { + struct pa_socket_client *c; + assert(m && sa); + c = pa_socket_client_new(m); + assert(c); + + if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "socket(): %s\n", strerror(errno)); + goto fail; + } + + if (sa->sa_family == AF_INET) + pa_socket_tcp_low_delay(c->fd); + else + pa_socket_low_delay(c->fd); + + if (do_connect(c, sa, salen) < 0) + goto fail; + return c; + +fail: + pa_socket_client_free(c); + return NULL; + +} + void pa_socket_client_free(struct pa_socket_client *c) { assert(c && c->mainloop); if (c->io_source) diff --git a/src/socket-client.h b/src/socket-client.h index 046cc3a5..85753788 100644 --- a/src/socket-client.h +++ b/src/socket-client.h @@ -11,6 +11,7 @@ struct pa_socket_client; struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port); struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename); +struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m, const struct sockaddr *sa, size_t salen); void pa_socket_client_free(struct pa_socket_client *c); diff --git a/src/todo b/src/todo index db007d97..2bec6f18 100644 --- a/src/todo +++ b/src/todo @@ -1,8 +1,10 @@ +- modargs memory leak + +- clean secure directory handling (with username) + - native library/protocol: more functions (esp. latency) -- daemonizing - - prefix modules/libraries with pa_ - xmms+esound latency testing @@ -25,6 +27,7 @@ - doxygen - make mcalign merge chunks - modinfo +- daemonizing drivers: - libao -- cgit From ed9bd5f01fca5e8d610b4884358e3dda47c9ab00 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 15 Jul 2004 17:33:56 +0000 Subject: fix modargs memory leak git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@68 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/module-oss-mmap.c | 5 +++++ src/module-oss.c | 2 ++ src/module-protocol-stub.c | 17 ++++++++++++----- src/todo | 2 -- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/module-oss-mmap.c b/src/module-oss-mmap.c index 020daa2c..ceaae493 100644 --- a/src/module-oss-mmap.c +++ b/src/module-oss-mmap.c @@ -306,11 +306,16 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { u->mainloop_source = c->mainloop->source_io(c->mainloop, u->fd, (u->source ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | (u->sink ? PA_MAINLOOP_API_IO_EVENT_OUTPUT : 0), io_callback, u); assert(u->mainloop_source); + pa_modargs_free(ma); + return 0; fail: pa_module_done(c, m); + if (ma) + pa_modargs_free(ma); + return -1; } diff --git a/src/module-oss.c b/src/module-oss.c index 5a6513c3..48d10486 100644 --- a/src/module-oss.c +++ b/src/module-oss.c @@ -229,6 +229,8 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { m->userdata = u; + pa_modargs_free(ma); + return 0; fail: diff --git a/src/module-protocol-stub.c b/src/module-protocol-stub.c index 4f82d4e0..7338abc9 100644 --- a/src/module-protocol-stub.c +++ b/src/module-protocol-stub.c @@ -107,23 +107,30 @@ struct pa_socket_server *create_socket_server(struct pa_core *c, struct pa_modar int pa_module_init(struct pa_core *c, struct pa_module*m) { struct pa_socket_server *s; - struct pa_modargs *ma; + struct pa_modargs *ma = NULL; + int ret = -1; assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { fprintf(stderr, "Failed to parse module arguments\n"); - return -1; + goto finish; } if (!(s = create_socket_server(c, ma))) - return -1; + goto finish; if (!(m->userdata = protocol_new(c, s, m, ma))) { pa_socket_server_free(s); - return -1; + goto finish; } - return 0; + ret = 0; + +finish: + if (ma) + pa_modargs_free(ma); + + return ret; } void pa_module_done(struct pa_core *c, struct pa_module*m) { diff --git a/src/todo b/src/todo index 2bec6f18..5e90dfda 100644 --- a/src/todo +++ b/src/todo @@ -1,5 +1,3 @@ -- modargs memory leak - - clean secure directory handling (with username) - native library/protocol: -- cgit From 1a6fea24f51dc7e1dc5c0683de6eb9dc9aa8d88b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 15 Jul 2004 19:00:42 +0000 Subject: implement daemonizing git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@69 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/main.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++-------------- src/todo | 1 - 2 files changed, 71 insertions(+), 22 deletions(-) diff --git a/src/main.c b/src/main.c index d2ae61c9..9e2e0066 100644 --- a/src/main.c +++ b/src/main.c @@ -1,3 +1,6 @@ +#include +#include +#include #include #include #include @@ -12,6 +15,8 @@ #include "mainloop-signal.h" #include "cmdline.h" #include "cli-command.h" +#include "util.h" +#include "sioman.h" static struct pa_mainloop *mainloop; @@ -27,22 +32,70 @@ static void aux_signal_callback(void *id, int sig, void *userdata) { pa_module_load(c, sig == SIGUSR1 ? "module-cli" : "module-cli-protocol-unix", NULL); } +static void close_pipe(int p[2]) { + if (p[0] != -1) + close(p[0]); + if (p[1] != -1) + close(p[1]); + p[0] = p[1] = -1; +} + 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; + int r, retval = 1; + int daemon_pipe[2] = { -1, -1 }; if (!(cmdline = pa_cmdline_parse(argc, argv))) { fprintf(stderr, __FILE__": failed to parse command line.\n"); - return 1; + goto finish; } if (cmdline->help) { pa_cmdline_help(argv[0]); - pa_cmdline_free(cmdline); - return 0; + retval = 0; + goto finish; + } + + if (cmdline->daemonize) { + pid_t child; + + if (pa_stdio_acquire() < 0) { + fprintf(stderr, __FILE__": failed to acquire stdio.\n"); + goto finish; + } + + if (pipe(daemon_pipe) < 0) { + fprintf(stderr, __FILE__": failed to create pipe.\n"); + goto finish; + } + + if ((child = fork()) < 0) { + fprintf(stderr, __FILE__": fork() failed: %s\n", strerror(errno)); + goto finish; + } + + if (child != 0) { + /* Father */ + + close(daemon_pipe[1]); + daemon_pipe[1] = -1; + + if (pa_loop_read(daemon_pipe[0], &retval, sizeof(retval)) != sizeof(retval)) { + fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno)); + retval = 1; + } + + goto finish; + } + + close(daemon_pipe[0]); + daemon_pipe[0] = -1; + + setsid(); + setpgrp(); } r = lt_dlinit(); @@ -59,18 +112,6 @@ 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-simple-protocol-tcp", 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-unix", NULL); - pa_module_load(c, "module-esound-protocol-tcp", NULL); - pa_module_load(c, "module-cli", NULL);*/ - pa_signal_register(SIGUSR1, aux_signal_callback, c); pa_signal_register(SIGUSR2, aux_signal_callback, c); @@ -82,26 +123,35 @@ int main(int argc, char *argv[]) { if (r < 0 && cmdline->fail) { fprintf(stderr, __FILE__": failed to initialize daemon.\n"); - retval = 1; + if (cmdline->daemonize) + pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); } 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; + if (cmdline->daemonize) + pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); } else { + retval = 0; + if (cmdline->daemonize) + pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); 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(); + +finish: + + if (cmdline) + pa_cmdline_free(cmdline); + + close_pipe(daemon_pipe); return retval; } diff --git a/src/todo b/src/todo index 5e90dfda..963b57fd 100644 --- a/src/todo +++ b/src/todo @@ -25,7 +25,6 @@ - doxygen - make mcalign merge chunks - modinfo -- daemonizing drivers: - libao -- cgit From c36dadd2bdf01b26a3e5598def477b22a0b31e77 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 15 Jul 2004 20:12:21 +0000 Subject: remove global exported variables: pa_memblock statistics pa_default_sample_spec git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@70 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/cli-command.c | 2 +- src/core.c | 4 ++++ src/core.h | 3 +++ src/memblock.c | 25 ++++++++++++++++--------- src/memblock.h | 3 ++- src/modargs.c | 2 +- src/module-pipe-sink.c | 1 + src/protocol-simple.c | 1 + src/sample-util.c | 6 ------ src/sample-util.h | 4 ---- src/todo | 6 +----- 11 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/cli-command.c b/src/cli-command.c index bf3ab0c4..0c754c7e 100644 --- a/src/cli-command.c +++ b/src/cli-command.c @@ -161,7 +161,7 @@ static int pa_cli_command_source_outputs(struct pa_core *c, struct pa_tokenizer 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); + pa_strbuf_printf(buf, "Memory blocks allocated: %u, total size: %u bytes.\n", pa_memblock_get_count(), pa_memblock_get_total()); return 0; } diff --git a/src/core.c b/src/core.c index a1fe7d97..987bcc18 100644 --- a/src/core.c +++ b/src/core.c @@ -26,6 +26,10 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->modules = NULL; c->namereg = NULL; + c->default_sample_spec.format = PA_SAMPLE_S16NE; + c->default_sample_spec.rate = 44100; + c->default_sample_spec.channels = 2; + pa_check_for_sigpipe(); return c; diff --git a/src/core.h b/src/core.h index 13374e40..ee5bfc41 100644 --- a/src/core.h +++ b/src/core.h @@ -4,6 +4,7 @@ #include "idxset.h" #include "hashmap.h" #include "mainloop-api.h" +#include "sample.h" struct pa_core { struct pa_mainloop_api *mainloop; @@ -13,6 +14,8 @@ struct pa_core { struct pa_hashmap *namereg; uint32_t default_source_index, default_sink_index; + + struct pa_sample_spec default_sample_spec; }; struct pa_core* pa_core_new(struct pa_mainloop_api *m); diff --git a/src/memblock.c b/src/memblock.c index 2dfa6a9c..17038861 100644 --- a/src/memblock.c +++ b/src/memblock.c @@ -5,7 +5,7 @@ #include "memblock.h" -unsigned pa_memblock_count = 0, pa_memblock_total = 0; +static unsigned memblock_count = 0, memblock_total = 0; struct pa_memblock *pa_memblock_new(size_t length) { struct pa_memblock *b = malloc(sizeof(struct pa_memblock)+length); @@ -13,8 +13,8 @@ struct pa_memblock *pa_memblock_new(size_t length) { b->ref = 1; b->length = length; b->data = b+1; - pa_memblock_count++; - pa_memblock_total += length; + memblock_count++; + memblock_total += length; return b; } @@ -24,8 +24,8 @@ struct pa_memblock *pa_memblock_new_fixed(void *d, size_t length) { b->ref = 1; b->length = length; b->data = d; - pa_memblock_count++; - pa_memblock_total += length; + memblock_count++; + memblock_total += length; return b; } @@ -35,8 +35,8 @@ struct pa_memblock *pa_memblock_new_dynamic(void *d, size_t length) { b->ref = 1; b->length = length; b->data = d; - pa_memblock_count++; - pa_memblock_total += length; + memblock_count++; + memblock_total += length; return b; } @@ -54,8 +54,8 @@ void pa_memblock_unref(struct pa_memblock*b) { if (b->type == PA_MEMBLOCK_DYNAMIC) free(b->data); - pa_memblock_count--; - pa_memblock_total -= b->length; + memblock_count--; + memblock_total -= b->length; free(b); } @@ -79,3 +79,10 @@ void pa_memblock_unref_fixed(struct pa_memblock *b) { } } +unsigned pa_memblock_get_count(void) { + return memblock_count; +} + +unsigned pa_memblock_get_total(void) { + return memblock_total; +} diff --git a/src/memblock.h b/src/memblock.h index 2635f023..647a1c8c 100644 --- a/src/memblock.h +++ b/src/memblock.h @@ -22,6 +22,7 @@ struct pa_memblock* pa_memblock_ref(struct pa_memblock*b); void pa_memblock_unref_fixed(struct pa_memblock*b); -extern unsigned pa_memblock_count, pa_memblock_total; +unsigned pa_memblock_get_count(void); +unsigned pa_memblock_get_total(void); #endif diff --git a/src/modargs.c b/src/modargs.c index a716a80e..a4ef9af7 100644 --- a/src/modargs.c +++ b/src/modargs.c @@ -188,7 +188,7 @@ int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *rss struct pa_sample_spec ss; assert(ma && rss); - ss = pa_default_sample_spec; + ss = *rss; if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0) return -1; diff --git a/src/module-pipe-sink.c b/src/module-pipe-sink.c index 29767ea8..0a24f759 100644 --- a/src/module-pipe-sink.c +++ b/src/module-pipe-sink.c @@ -101,6 +101,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { goto fail; } + ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { fprintf(stderr, __FILE__": invalid sample format specification\n"); goto fail; diff --git a/src/protocol-simple.c b/src/protocol-simple.c index 89207133..4b52a246 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -355,6 +355,7 @@ struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct p p->server = server; p->connections = pa_idxset_new(NULL, NULL); + p->sample_spec = core->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &p->sample_spec) < 0) { fprintf(stderr, "Failed to parse sample type specification.\n"); goto fail; diff --git a/src/sample-util.c b/src/sample-util.c index 5344ecfa..c7a7b679 100644 --- a/src/sample-util.c +++ b/src/sample-util.c @@ -4,12 +4,6 @@ #include "sample-util.h" -struct pa_sample_spec pa_default_sample_spec = { - .format = PA_SAMPLE_S16NE, - .rate = 44100, - .channels = 2 -}; - struct pa_memblock *pa_silence_memblock(struct pa_memblock* b, const struct pa_sample_spec *spec) { assert(b && b->data && spec); pa_silence_memory(b->data, b->length, spec); diff --git a/src/sample-util.h b/src/sample-util.h index 6a593b9a..4efa59a4 100644 --- a/src/sample-util.h +++ b/src/sample-util.h @@ -5,10 +5,6 @@ #include "memblock.h" #include "memchunk.h" -#define PA_DEFAULT_SAMPLE_SPEC pa_default_sample_spec - -extern struct pa_sample_spec pa_default_sample_spec; - #define PA_VOLUME_NORM (0x100) #define PA_VOLUME_MUTE (0) diff --git a/src/todo b/src/todo index 963b57fd..5eb4329d 100644 --- a/src/todo +++ b/src/todo @@ -11,11 +11,6 @@ - svn-id and license in every file - documentation -- eliminate global variables: - pa_default_sample_spec - pa_memblock_count - pa_memblock_total - -- post 0.1 - future cancellation - client-ui @@ -25,6 +20,7 @@ - doxygen - make mcalign merge chunks - modinfo +- move the global memblock statistics variables to the core drivers: - libao -- cgit From d8f13006614dca80de8903f5380b7cb718f26fcc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 15 Jul 2004 20:51:55 +0000 Subject: add pactl tool git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@71 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 6 +- src/pacat.c | 8 ++- src/pactl.c | 141 +++++++++++++++++++++++++++++++++++++++++++++ src/polyp.c | 61 ++++++++++++++++++++ src/polyp.h | 3 + src/protocol-native-spec.h | 1 + src/protocol-native.c | 26 +++++++++ src/todo | 7 ++- 8 files changed, 246 insertions(+), 7 deletions(-) create mode 100644 src/pactl.c diff --git a/src/Makefile.am b/src/Makefile.am index c973af52..7aa07215 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,7 +18,7 @@ AM_CFLAGS=-ansi -D_GNU_SOURCE -bin_PROGRAMS = polypaudio pacat pacat-simple parec-simple +bin_PROGRAMS = polypaudio pacat pactl pacat-simple parec-simple pkglib_LTLIBRARIES=libiochannel.la \ libsocket-server.la \ @@ -246,6 +246,10 @@ pacat_SOURCES = pacat.c #$(libpolyp_la_SOURCES) $(libpolyp_error_la_SOURCES) pacat_LDADD = libpolyp.la libpolyp-error.la pacat_CFLAGS = $(AM_CFLAGS) +pactl_SOURCES = pactl.c #$(libpolyp_la_SOURCES) $(libpolyp_error_la_SOURCES) +pactl_LDADD = libpolyp.la libpolyp-error.la +pactl_CFLAGS = $(AM_CFLAGS) + pacat_simple_SOURCES = pacat-simple.c #$(libpolyp_la_SOURCES) $(libpolyp_simple_la_SOURCES) $(libpolyp_error_la_SOURCES) pacat_simple_LDADD = libpolyp-simple.la libpolyp-error.la pacat_simple_CFLAGS = $(AM_CFLAGS) diff --git a/src/pacat.c b/src/pacat.c index 80d4835f..c9257d03 100644 --- a/src/pacat.c +++ b/src/pacat.c @@ -222,7 +222,7 @@ static void exit_signal_callback(void *id, int sig, void *userdata) { } int main(int argc, char *argv[]) { - struct pa_mainloop* m; + struct pa_mainloop* m = NULL; int ret = 1, r; char *bn; @@ -279,9 +279,11 @@ quit: if (context) pa_context_free(context); - pa_signal_done(); - if (m) + if (m) { + pa_signal_done(); pa_mainloop_free(m); + } + if (buffer) free(buffer); diff --git a/src/pactl.c b/src/pactl.c new file mode 100644 index 00000000..688e1104 --- /dev/null +++ b/src/pactl.c @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "polyp.h" +#include "polyp-error.h" +#include "mainloop.h" +#include "mainloop-signal.h" + +static struct pa_context *context = NULL; +static struct pa_mainloop_api *mainloop_api = NULL; + +static enum { + NONE, + EXIT, + STAT +} action = NONE; + +static void quit(int ret) { + assert(mainloop_api); + mainloop_api->quit(mainloop_api, ret); +} + +static void context_die_callback(struct pa_context *c, void *userdata) { + assert(c); + fprintf(stderr, "Connection to server shut down, exiting.\n"); + quit(1); +} + +static void context_drain_complete(struct pa_context *c, void *userdata) { + assert(c); + fprintf(stderr, "Connection to server shut down, exiting.\n"); + quit(0); +} + +static void drain(void) { + if (pa_context_drain(context, context_drain_complete, NULL) < 0) + quit(0); +} + +static void stat_callback(struct pa_context *c, uint32_t blocks, uint32_t total, void *userdata) { + if (blocks == (uint32_t) -1) { + fprintf(stderr, "Failed to get statistics: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + fprintf(stderr, "Currently in use: %u blocks containing %u bytes total.\n", blocks, total); + drain(); +} + +static void context_complete_callback(struct pa_context *c, int success, void *userdata) { + assert(c); + + if (!success) { + fprintf(stderr, "Connection failed: %s\n", pa_strerror(pa_context_errno(c))); + goto fail; + } + + fprintf(stderr, "Connection established.\n"); + + if (action == STAT) + pa_context_stat(c, stat_callback, NULL); + else { + assert(action == EXIT); + pa_context_exit(c); + drain(); + } + + return; + +fail: + quit(1); +} + +static void exit_signal_callback(void *id, int sig, void *userdata) { + fprintf(stderr, "Got SIGINT, exiting.\n"); + quit(0); + +} + +int main(int argc, char *argv[]) { + struct pa_mainloop* m = NULL; + int ret = 1, r; + + if (argc >= 2) { + if (!strcmp(argv[1], "stat")) + action = STAT; + else if (!strcmp(argv[1], "exit")) + action = EXIT; + } + + if (action == NONE) { + fprintf(stderr, "No valid action specified. Use one of: stat, exit\n"); + goto quit; + } + + if (!(m = pa_mainloop_new())) { + fprintf(stderr, "pa_mainloop_new() failed.\n"); + goto quit; + } + + mainloop_api = pa_mainloop_get_api(m); + + r = pa_signal_init(mainloop_api); + assert(r == 0); + pa_signal_register(SIGINT, exit_signal_callback, NULL); + signal(SIGPIPE, SIG_IGN); + + if (!(context = pa_context_new(mainloop_api, argv[0]))) { + fprintf(stderr, "pa_context_new() failed.\n"); + goto quit; + } + + if (pa_context_connect(context, NULL, context_complete_callback, NULL) < 0) { + fprintf(stderr, "pa_context_connext() failed.\n"); + goto quit; + } + + pa_context_set_die_callback(context, context_die_callback, NULL); + + if (pa_mainloop_run(m, &ret) < 0) { + fprintf(stderr, "pa_mainloop_run() failed.\n"); + goto quit; + } + +quit: + if (context) + pa_context_free(context); + + if (m) { + pa_signal_done(); + pa_mainloop_free(m); + } + + return ret; +} diff --git a/src/polyp.c b/src/polyp.c index 75187d79..bc6bff5a 100644 --- a/src/polyp.c +++ b/src/polyp.c @@ -53,6 +53,9 @@ struct pa_context { void (*die_callback)(struct pa_context*c, void *userdata); void *die_userdata; + + void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); + void *stat_userdata; uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; }; @@ -133,6 +136,9 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * c->die_callback = NULL; c->die_userdata = NULL; + c->stat_callback = NULL; + c->stat_userdata = NULL; + pa_check_for_sigpipe(); return c; } @@ -834,3 +840,58 @@ void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); } + +void pa_context_exit(struct pa_context *c) { + struct pa_tagstruct *t; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_EXIT); + pa_tagstruct_putu32(t, c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + uint32_t total, count; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &count) < 0 || + pa_tagstruct_getu32(t, &total) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, count, total, c->stat_userdata); +} + +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + c->stat_callback = cb; + c->stat_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_STAT); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); +} diff --git a/src/polyp.h b/src/polyp.h index c49a72b2..5b730302 100644 --- a/src/polyp.h +++ b/src/polyp.h @@ -32,6 +32,9 @@ int pa_context_errno(struct pa_context *c); int pa_context_is_pending(struct pa_context *c); +void pa_context_exit(struct pa_context *c); +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); + struct pa_stream; struct pa_stream* pa_stream_new( diff --git a/src/protocol-native-spec.h b/src/protocol-native-spec.h index 78dc06c2..0a60fd80 100644 --- a/src/protocol-native-spec.h +++ b/src/protocol-native-spec.h @@ -18,6 +18,7 @@ enum { PA_COMMAND_DRAIN_PLAYBACK_STREAM, PA_COMMAND_PLAYBACK_STREAM_KILLED, PA_COMMAND_RECORD_STREAM_KILLED, + PA_COMMAND_STAT, PA_COMMAND_MAX }; diff --git a/src/protocol-native.c b/src/protocol-native.c index abd17026..56395e98 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -75,6 +75,7 @@ static void command_delete_record_stream(struct pa_pdispatch *pd, uint32_t comma static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = { NULL }, @@ -91,6 +92,7 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_SET_NAME] = { command_set_name }, [PA_COMMAND_LOOKUP_SINK] = { command_lookup }, [PA_COMMAND_LOOKUP_SOURCE] = { command_lookup }, + [PA_COMMAND_STAT] = { command_stat }, }; /* structure management */ @@ -638,6 +640,30 @@ static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t comm } } +static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + assert(c && t); + struct pa_tagstruct *reply; + + if (!pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, pa_memblock_get_count()); + pa_tagstruct_putu32(reply, pa_memblock_get_total()); + pa_pstream_send_tagstruct(c->pstream, reply); +} + /*** pstream callbacks ***/ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { diff --git a/src/todo b/src/todo index 5eb4329d..107fa787 100644 --- a/src/todo +++ b/src/todo @@ -1,12 +1,11 @@ -- clean secure directory handling (with username) +- pactl - native library/protocol: more functions (esp. latency) -- prefix modules/libraries with pa_ - - xmms+esound latency testing +- prefix modules/libraries with pa_ - rename files - svn-id and license in every file - documentation @@ -21,6 +20,8 @@ - make mcalign merge chunks - modinfo - move the global memblock statistics variables to the core +- unix socket directories include user name + drivers: - libao -- cgit From 710233bbf68c845ec5f1713679f4ff0b74c517de Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 15 Jul 2004 21:18:18 +0000 Subject: implement get_latency native command git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@72 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pacat.c | 20 ++++++++++++++++++ src/pdispatch.c | 12 ++++++++++- src/polyp.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++ src/polyp.h | 2 ++ src/protocol-native-spec.h | 1 + src/protocol-native.c | 34 +++++++++++++++++++++++++++++++ src/todo | 12 +++++------ 7 files changed, 125 insertions(+), 7 deletions(-) diff --git a/src/pacat.c b/src/pacat.c index c9257d03..2c5198fb 100644 --- a/src/pacat.c +++ b/src/pacat.c @@ -221,6 +221,25 @@ static void exit_signal_callback(void *id, int sig, void *userdata) { } +static void stream_get_latency_callback(struct pa_stream *s, uint32_t latency, void *userdata) { + assert(s); + + if (latency == (uint32_t) -1) { + fprintf(stderr, "Failed to get latency: %s\n", strerror(errno)); + quit(1); + return; + } + + fprintf(stderr, "Current latency is %u usecs.\n", latency); +} + +static void sigusr1_signal_callback(void *id, int sig, void *userdata) { + if (mode == PLAYBACK) { + fprintf(stderr, "Got SIGUSR1, requesting latency.\n"); + pa_stream_get_latency(stream, stream_get_latency_callback, NULL); + } +} + int main(int argc, char *argv[]) { struct pa_mainloop* m = NULL; int ret = 1, r; @@ -246,6 +265,7 @@ int main(int argc, char *argv[]) { r = pa_signal_init(mainloop_api); assert(r == 0); pa_signal_register(SIGINT, exit_signal_callback, NULL); + pa_signal_register(SIGUSR1, sigusr1_signal_callback, NULL); signal(SIGPIPE, SIG_IGN); if (!(stdio_source = mainloop_api->source_io(mainloop_api, diff --git a/src/pdispatch.c b/src/pdispatch.c index b7257dd4..32753963 100644 --- a/src/pdispatch.c +++ b/src/pdispatch.c @@ -4,6 +4,8 @@ #include "pdispatch.h" #include "protocol-native-spec.h" +#ifdef DEBUG_OPCODES + static const char *command_names[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = "ERROR", [PA_COMMAND_TIMEOUT] = "TIMEOUT", @@ -19,8 +21,14 @@ static const char *command_names[PA_COMMAND_MAX] = { [PA_COMMAND_LOOKUP_SINK] = "LOOKUP_SINK", [PA_COMMAND_LOOKUP_SOURCE] = "LOOKUP_SOURCE", [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = "DRAIN_PLAYBACK_STREAM", + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = "PLAYBACK_STREAM_KILLED", + [PA_COMMAND_RECORD_STREAM_KILLED] = "RECORD_STREAM_KILLED", + [PA_COMMAND_STAT] = "STAT", + [PA_COMMAND_GET_PLAYBACK_LATENCY] = "PLAYBACK_LATENCY", }; +#endif + struct reply_info { struct pa_pdispatch *pdispatch; struct reply_info *next, *previous; @@ -106,7 +114,9 @@ int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *use pa_tagstruct_getu32(ts, &tag) < 0) goto finish; - /*fprintf(stderr, __FILE__": Recieved opcode <%s>\n", command_names[command]);*/ +#ifdef DEBUG_OPCODES + fprintf(stderr, __FILE__": Recieved opcode <%s>\n", command_names[command]); +#endif if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) { struct reply_info *r; diff --git a/src/polyp.c b/src/polyp.c index bc6bff5a..d6d0f908 100644 --- a/src/polyp.c +++ b/src/polyp.c @@ -89,6 +89,9 @@ struct pa_stream { void (*die_callback)(struct pa_stream*c, void *userdata); void *die_userdata; + + void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); + void *get_latency_userdata; }; static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); @@ -602,6 +605,8 @@ struct pa_stream* pa_stream_new( s->die_userdata = NULL; s->create_complete_callback = complete; s->create_complete_userdata = NULL; + s->get_latency_callback = NULL; + s->get_latency_userdata = NULL; s->name = strdup(name); s->state = STREAM_CREATING; @@ -895,3 +900,49 @@ void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); } + +static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + uint32_t latency; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &latency) < 0 || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, latency, s->get_latency_userdata); +} + +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + p->get_latency_callback = cb; + p->get_latency_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); + pa_tagstruct_putu32(t, tag = p->context->ctag++); + pa_tagstruct_putu32(t, p->channel); + pa_pstream_send_tagstruct(p->context->pstream, t); + pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); +} diff --git a/src/polyp.h b/src/polyp.h index 5b730302..00849445 100644 --- a/src/polyp.h +++ b/src/polyp.h @@ -66,6 +66,8 @@ void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_strea int pa_stream_is_dead(struct pa_stream *p); int pa_stream_is_ready(struct pa_stream*p); +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); + struct pa_context* pa_stream_get_context(struct pa_stream *p); #endif diff --git a/src/protocol-native-spec.h b/src/protocol-native-spec.h index 0a60fd80..e1db6f64 100644 --- a/src/protocol-native-spec.h +++ b/src/protocol-native-spec.h @@ -19,6 +19,7 @@ enum { PA_COMMAND_PLAYBACK_STREAM_KILLED, PA_COMMAND_RECORD_STREAM_KILLED, PA_COMMAND_STAT, + PA_COMMAND_GET_PLAYBACK_LATENCY, PA_COMMAND_MAX }; diff --git a/src/protocol-native.c b/src/protocol-native.c index 56395e98..094c6630 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -76,6 +76,7 @@ static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag static void command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = { NULL }, @@ -93,6 +94,7 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_LOOKUP_SINK] = { command_lookup }, [PA_COMMAND_LOOKUP_SOURCE] = { command_lookup }, [PA_COMMAND_STAT] = { command_stat }, + [PA_COMMAND_GET_PLAYBACK_LATENCY] = { command_get_playback_latency }, }; /* structure management */ @@ -664,6 +666,38 @@ static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag pa_pstream_send_tagstruct(c->pstream, reply); } +static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + assert(c && t); + struct pa_tagstruct *reply; + struct playback_stream *s; + uint32_t index, latency; + + if (pa_tagstruct_getu32(t, &index) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->playback_streams, index))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + latency = pa_sink_input_get_latency(s->sink_input); + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, latency); + pa_pstream_send_tagstruct(c->pstream, reply); +} + /*** pstream callbacks ***/ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { diff --git a/src/todo b/src/todo index 107fa787..09a7a5c1 100644 --- a/src/todo +++ b/src/todo @@ -1,8 +1,3 @@ -- pactl - -- native library/protocol: - more functions (esp. latency) - - xmms+esound latency testing - prefix modules/libraries with pa_ @@ -21,7 +16,12 @@ - modinfo - move the global memblock statistics variables to the core - unix socket directories include user name - +- more complete pactl +- native library/protocol: + get server layout + subscription + module load/unload + kill client/... drivers: - libao -- cgit From b2405646d8216ceb058529348d87dab8c6a6954e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 15 Jul 2004 21:51:54 +0000 Subject: optimize esound latency for xmms git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@73 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/protocol-esound.c | 5 ++--- src/todo | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/protocol-esound.c b/src/protocol-esound.c index cba72438..d6d7e177 100644 --- a/src/protocol-esound.c +++ b/src/protocol-esound.c @@ -254,7 +254,7 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); c->input_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&ss), l/2, l/PLAYBACK_BUFFER_FRAGMENTS); assert(c->input_memblockq); - pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*5); + pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2); c->playback.fragment_size = l/10; assert(!c->sink_input); @@ -347,7 +347,7 @@ static int esd_proto_get_latency(struct connection *c, esd_proto_t request, cons latency = 0; else { float usec = pa_sink_get_latency(sink); - usec += PLAYBACK_BUFFER_SECONDS*1000000*.9; /* A better estimation would be a good idea! */ + usec += PLAYBACK_BUFFER_SECONDS*1000000; /* A better estimation would be a good idea! */ latency = (int) ((usec*44100)/1000000); } @@ -560,7 +560,6 @@ static int do_read(struct connection *c) { c->playback.current_memblock = NULL; c->playback.memblock_index = 0; } - if (!c->playback.current_memblock) { c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2); diff --git a/src/todo b/src/todo index 09a7a5c1..1a4e9956 100644 --- a/src/todo +++ b/src/todo @@ -1,5 +1,3 @@ -- xmms+esound latency testing - - prefix modules/libraries with pa_ - rename files - svn-id and license in every file -- cgit From b8eb0c088df2c5a0495cf43f8991977693258d5b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Jul 2004 00:27:02 +0000 Subject: add alsa sink git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@74 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 4 + src/Makefile.am | 6 ++ src/module-alsa-sink.c | 252 +++++++++++++++++++++++++++++++++++++++++++++++++ src/polypaudio.run | 3 +- src/todo | 5 +- 5 files changed, 268 insertions(+), 2 deletions(-) create mode 100644 src/module-alsa-sink.c diff --git a/configure.ac b/configure.ac index 647bfab7..672e6e3d 100644 --- a/configure.ac +++ b/configure.ac @@ -46,6 +46,10 @@ PKG_CHECK_MODULES(LIBSAMPLERATE, [ samplerate >= 0.1.0 ]) AC_SUBST(LIBSAMPLERATE_CFLAGS) AC_SUBST(LIBSAMPLERATE_LIBS) +PKG_CHECK_MODULES(ASOUNDLIB, [ alsa >= 1.0.0 ]) +AC_SUBST(ASOUNDLIB_CFLAGS) +AC_SUBST(ASOUNDLIB_LIBS) + # If using GCC specifiy some additional parameters if test "x$GCC" = "xyes" ; then CFLAGS="$CFLAGS -pipe -Wall -W -Wno-unused-parameter" diff --git a/src/Makefile.am b/src/Makefile.am index 7aa07215..53134792 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,6 +41,7 @@ pkglib_LTLIBRARIES=libiochannel.la \ module-cli-protocol-tcp.la \ module-cli-protocol-unix.la \ module-pipe-sink.la \ + module-alsa-sink.la \ module-oss.la \ module-oss-mmap.la \ module-simple-protocol-tcp.la \ @@ -200,6 +201,11 @@ module_pipe_sink_la_SOURCES = module-pipe-sink.c module_pipe_sink_la_LDFLAGS = -module -avoid-version module_pipe_sink_la_LIBADD = libiochannel.la +module_alsa_sink_la_SOURCES = module-alsa-sink.c +module_alsa_sink_la_LDFLAGS = -module -avoid-version +module_alsa_sink_la_LIBADD = $(ASOUNDLIB_LIBS) +module_alsa_sink_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) + module_oss_la_SOURCES = module-oss.c module_oss_la_LDFLAGS = -module -avoid-version module_oss_la_LIBADD = libiochannel.la liboss-util.la diff --git a/src/module-alsa-sink.c b/src/module-alsa-sink.c new file mode 100644 index 00000000..7afd24fd --- /dev/null +++ b/src/module-alsa-sink.c @@ -0,0 +1,252 @@ +#include +#include +#include + +#include + +#include "module.h" +#include "core.h" +#include "memchunk.h" +#include "sink.h" +#include "modargs.h" +#include "util.h" +#include "sample-util.h" + +struct userdata { + snd_pcm_t *pcm_handle; + struct pa_sink *sink; + void **io_sources; + unsigned n_io_sources; + + size_t frame_size, fragment_size; + struct pa_memchunk memchunk, silence; +}; + +static const char* const valid_modargs[] = { + "device", + "sink_name", + NULL +}; + +#define DEFAULT_SINK_NAME "alsa_output" +#define DEFAULT_DEVICE "plughw:0,0" + +static void xrun_recovery(struct userdata *u) { + assert(u); + + fprintf(stderr, "*** XRUN ***\n"); + + if (snd_pcm_prepare(u->pcm_handle) < 0) + fprintf(stderr, "snd_pcm_prepare() failed\n"); +} + +static void do_write(struct userdata *u) { + assert(u); + + for (;;) { + struct pa_memchunk *memchunk = NULL; + snd_pcm_sframes_t frames; + + if (u->memchunk.memblock) + memchunk = &u->memchunk; + else { + if (pa_sink_render(u->sink, u->fragment_size, &u->memchunk) < 0) + memchunk = &u->silence; + else + memchunk = &u->memchunk; + } + + assert(memchunk->memblock && memchunk->memblock->data && memchunk->length && memchunk->memblock->length && (memchunk->length % u->frame_size) == 0); + + assert(u->pcm_handle); + assert(memchunk->memblock); + assert(memchunk->memblock->data); + assert(memchunk->length); + assert(u->frame_size); + + if ((frames = snd_pcm_writei(u->pcm_handle, memchunk->memblock->data + memchunk->index, memchunk->length / u->frame_size)) < 0) { + if (frames == -EPIPE) { + xrun_recovery(u); + continue; + } + + fprintf(stderr, "snd_pcm_writei() failed\n"); + return; + } + + if (memchunk == &u->memchunk) { + memchunk->index += frames * u->frame_size; + memchunk->length -= frames * u->frame_size; + + if (memchunk->length == 0) { + pa_memblock_unref(memchunk->memblock); + memchunk->memblock = NULL; + memchunk->index = memchunk->length = 0; + } + } + + break; + } +} + +static void io_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { + struct userdata *u = userdata; + assert(u && a && id); + + if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) + xrun_recovery(u); + + do_write(u); +} + +static uint32_t sink_get_latency_cb(struct pa_sink *s) { + struct userdata *u = s->userdata; + snd_pcm_sframes_t frames; + assert(s && u && u->sink); + + if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { + fprintf(stderr, __FILE__": failed to get delay\n"); + s->get_latency = NULL; + return 0; + } + + if (frames < 0) + frames = 0; + + return pa_samples_usec(frames * u->frame_size, &s->sample_spec); +} + +int pa_module_init(struct pa_core *c, struct pa_module*m) { + struct pa_modargs *ma = NULL; + int ret = -1; + struct userdata *u = NULL; + snd_pcm_hw_params_t *hwparams; + const char *dev; + struct pollfd *pfds, *ppfd; + struct pa_sample_spec ss; + unsigned i, periods; + snd_pcm_uframes_t buffer_size; + void ** ios; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + fprintf(stderr, __FILE__": failed to parse module arguments\n"); + goto fail; + } + + u = malloc(sizeof(struct userdata)); + assert(u); + memset(u, 0, sizeof(struct userdata)); + m->userdata = u; + + if (snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) { + fprintf(stderr, "Error opening PCM device %s\n", dev); + goto fail; + } + + ss.format = PA_SAMPLE_S16LE; + ss.rate = 44100; + ss.channels = 2; + + periods = 12; + buffer_size = periods*256; + + snd_pcm_hw_params_alloca(&hwparams); + if (snd_pcm_hw_params_any(u->pcm_handle, hwparams) < 0 || + snd_pcm_hw_params_set_access(u->pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0 || + snd_pcm_hw_params_set_format(u->pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0 || + snd_pcm_hw_params_set_rate_near(u->pcm_handle, hwparams, &ss.rate, NULL) < 0 || + snd_pcm_hw_params_set_channels(u->pcm_handle, hwparams, ss.channels) < 0 || + snd_pcm_hw_params_set_periods_near(u->pcm_handle, hwparams, &periods, NULL) < 0 || + snd_pcm_hw_params_set_buffer_size_near(u->pcm_handle, hwparams, &buffer_size) < 0 || + snd_pcm_hw_params(u->pcm_handle, hwparams) < 0) { + fprintf(stderr, "Error setting HW params.\n"); + goto fail; + } + + u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); + assert(u->sink); + + u->sink->get_latency = sink_get_latency_cb; + u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); + + u->n_io_sources = snd_pcm_poll_descriptors_count(u->pcm_handle); + + pfds = malloc(sizeof(struct pollfd) * u->n_io_sources); + assert(pfds); + if (snd_pcm_poll_descriptors(u->pcm_handle, pfds, u->n_io_sources) < 0) { + printf("Unable to obtain poll descriptors for playback.\n"); + free(pfds); + goto fail; + } + + u->io_sources = malloc(sizeof(void*) * u->n_io_sources); + assert(u->io_sources); + + for (i = 0, ios = u->io_sources, ppfd = pfds; i < u->n_io_sources; i++, ios++, ppfd++) { + *ios = c->mainloop->source_io(c->mainloop, ppfd->fd, + ((ppfd->events & POLLIN) ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | + ((ppfd->events & POLLOUT) ? PA_MAINLOOP_API_IO_EVENT_OUTPUT : 0), io_callback, u); + assert(*ios); + } + + free(pfds); + + u->frame_size = pa_sample_size(&ss); + u->fragment_size = buffer_size*u->frame_size/periods; + + fprintf(stderr, __FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); + + u->silence.memblock = pa_memblock_new(u->silence.length = u->fragment_size); + assert(u->silence.memblock); + pa_silence_memblock(u->silence.memblock, &ss); + u->silence.index = 0; + + u->memchunk.memblock = NULL; + u->memchunk.index = u->memchunk.length = 0; + + ret = 0; + +finish: + if (ma) + pa_modargs_free(ma); + + return ret; + +fail: + + if (u) + pa_module_done(c, m); + + goto finish; +} + +void pa_module_done(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + assert(c && m); + + if ((u = m->userdata)) { + unsigned i; + void **ios; + + pa_sink_free(u->sink); + + for (ios = u->io_sources, i = 0; i < u->n_io_sources; i++, ios++) + c->mainloop->cancel_io(c->mainloop, *ios); + free(u->io_sources); + + if (u->pcm_handle) { + snd_pcm_drop(u->pcm_handle); + snd_pcm_close(u->pcm_handle); + } + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + if (u->silence.memblock) + pa_memblock_unref(u->silence.memblock); + + free(u); + } +} + diff --git a/src/polypaudio.run b/src/polypaudio.run index 5d258852..48c3f7ea 100755 --- a/src/polypaudio.run +++ b/src/polypaudio.run @@ -8,4 +8,5 @@ load module-simple-protocol-tcp load module-native-protocol-unix load module-cli-protocol-unix -load module-oss-mmap device="/dev/dsp" +load module-alsa-sink +#load module-oss-mmap device="/dev/dsp" diff --git a/src/todo b/src/todo index 1a4e9956..e6685b2e 100644 --- a/src/todo +++ b/src/todo @@ -1,7 +1,10 @@ +- alsa source + - prefix modules/libraries with pa_ - rename files - svn-id and license in every file - documentation +- pkgconfig -- post 0.1 - future cancellation @@ -20,6 +23,7 @@ subscription module load/unload kill client/... +- make alsa modules use mmap drivers: - libao @@ -29,5 +33,4 @@ drivers: - python modules: -- alsa? - http -- cgit From f2e08d53d03303376da4491559a5af6296bbfea8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Jul 2004 14:43:25 +0000 Subject: split PA_SAMPLE_FLOAT32 into PA_SAMPLE_FLOAT{LE,BE} add more configuration arguments to alsa sink git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@75 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/module-alsa-sink.c | 43 +++++++++++++++++++++++++++++++++---------- src/sample.c | 6 ++++-- src/sample.h | 6 +++++- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/module-alsa-sink.c b/src/module-alsa-sink.c index 7afd24fd..16571a2c 100644 --- a/src/module-alsa-sink.c +++ b/src/module-alsa-sink.c @@ -25,6 +25,11 @@ struct userdata { static const char* const valid_modargs[] = { "device", "sink_name", + "format", + "channels", + "rate", + "fragments", + "fragment_size", NULL }; @@ -124,14 +129,39 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { const char *dev; struct pollfd *pfds, *ppfd; struct pa_sample_spec ss; - unsigned i, periods; + unsigned i, periods, fragsize; snd_pcm_uframes_t buffer_size; void ** ios; + size_t frame_size; + static const snd_pcm_format_t format_trans[] = { + [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8, + [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW, + [PA_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW, + [PA_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE, + [PA_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE, + [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE, + [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, + }; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { fprintf(stderr, __FILE__": failed to parse module arguments\n"); goto fail; } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + fprintf(stderr, __FILE__": failed to parse sample specification\n"); + goto fail; + } + frame_size = pa_sample_size(&ss); + + periods = 12; + fragsize = 1024; + if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { + fprintf(stderr, __FILE__": failed to parse buffer metrics\n"); + goto fail; + } + buffer_size = fragsize/frame_size*periods; u = malloc(sizeof(struct userdata)); assert(u); @@ -142,18 +172,11 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { fprintf(stderr, "Error opening PCM device %s\n", dev); goto fail; } - - ss.format = PA_SAMPLE_S16LE; - ss.rate = 44100; - ss.channels = 2; - - periods = 12; - buffer_size = periods*256; snd_pcm_hw_params_alloca(&hwparams); if (snd_pcm_hw_params_any(u->pcm_handle, hwparams) < 0 || snd_pcm_hw_params_set_access(u->pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0 || - snd_pcm_hw_params_set_format(u->pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0 || + snd_pcm_hw_params_set_format(u->pcm_handle, hwparams, format_trans[ss.format]) < 0 || snd_pcm_hw_params_set_rate_near(u->pcm_handle, hwparams, &ss.rate, NULL) < 0 || snd_pcm_hw_params_set_channels(u->pcm_handle, hwparams, ss.channels) < 0 || snd_pcm_hw_params_set_periods_near(u->pcm_handle, hwparams, &periods, NULL) < 0 || @@ -193,7 +216,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { free(pfds); - u->frame_size = pa_sample_size(&ss); + u->frame_size = frame_size; u->fragment_size = buffer_size*u->frame_size/periods; fprintf(stderr, __FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); diff --git a/src/sample.c b/src/sample.c index 20142a23..2cdc9e72 100644 --- a/src/sample.c +++ b/src/sample.c @@ -17,7 +17,8 @@ size_t pa_sample_size(const struct pa_sample_spec *spec) { case PA_SAMPLE_S16BE: b = 2; break; - case PA_SAMPLE_FLOAT32: + case PA_SAMPLE_FLOAT32LE: + case PA_SAMPLE_FLOAT32BE: b = 4; break; default: @@ -64,7 +65,8 @@ void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec) { [PA_SAMPLE_ULAW] = "ULAW", [PA_SAMPLE_S16LE] = "S16LE", [PA_SAMPLE_S16BE] = "S16BE", - [PA_SAMPLE_FLOAT32] = "FLOAT32", + [PA_SAMPLE_FLOAT32LE] = "FLOAT32LE", + [PA_SAMPLE_FLOAT32BE] = "FLOAT32BE", }; assert(pa_sample_spec_valid(spec)); diff --git a/src/sample.h b/src/sample.h index df12924b..a755b76d 100644 --- a/src/sample.h +++ b/src/sample.h @@ -10,15 +10,19 @@ enum pa_sample_format { PA_SAMPLE_ULAW, PA_SAMPLE_S16LE, PA_SAMPLE_S16BE, - PA_SAMPLE_FLOAT32, + PA_SAMPLE_FLOAT32LE, + PA_SAMPLE_FLOAT32BE, PA_SAMPLE_MAX }; #ifdef WORDS_BIGENDIAN #define PA_SAMPLE_S16NE PA_SAMPLE_S16BE +#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32BE #else #define PA_SAMPLE_S16NE PA_SAMPLE_S16LE +#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32LE #endif +#define PA_SAMPLE_FLOAT32 PA_SAMPLE_FLOAT32NE struct pa_sample_spec { enum pa_sample_format format; -- cgit From 74bbf31c37b327be3c52c8043be72b96b8fee8f4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Jul 2004 17:03:11 +0000 Subject: implement alsa source split off alsa-util.c git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@76 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 14 +++- src/alsa-util.c | 73 ++++++++++++++++ src/alsa-util.h | 14 ++++ src/module-alsa-sink.c | 77 ++++------------- src/module-alsa-source.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++ src/polypaudio.run | 16 +++- src/todo | 5 +- 7 files changed, 344 insertions(+), 67 deletions(-) create mode 100644 src/alsa-util.c create mode 100644 src/alsa-util.h create mode 100644 src/module-alsa-source.c diff --git a/src/Makefile.am b/src/Makefile.am index 53134792..09df6284 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,6 +26,7 @@ pkglib_LTLIBRARIES=libiochannel.la \ libpstream.la \ libpacket.la \ liboss-util.la \ + libalsa-util.la \ libioline.la \ libcli.la \ libprotocol-cli.la \ @@ -42,6 +43,7 @@ pkglib_LTLIBRARIES=libiochannel.la \ module-cli-protocol-unix.la \ module-pipe-sink.la \ module-alsa-sink.la \ + module-alsa-source.la \ module-oss.la \ module-oss-mmap.la \ module-simple-protocol-tcp.la \ @@ -128,6 +130,11 @@ libpacket_la_LDFLAGS = -avoid-version liboss_util_la_SOURCES = oss-util.c oss-util.h liboss_util_la_LDFLAGS = -avoid-version +libalsa_util_la_SOURCES = alsa-util.c alsa-util.h +libalsa_util_la_LDFLAGS = -avoid-version +libalsa_util_la_LIBADD = $(ASOUNDLIB_LIBS) +libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) + libioline_la_SOURCES = ioline.c ioline.h libioline_la_LDFLAGS = -avoid-version libioline_la_LIBADD = libiochannel.la @@ -203,9 +210,14 @@ module_pipe_sink_la_LIBADD = libiochannel.la module_alsa_sink_la_SOURCES = module-alsa-sink.c module_alsa_sink_la_LDFLAGS = -module -avoid-version -module_alsa_sink_la_LIBADD = $(ASOUNDLIB_LIBS) +module_alsa_sink_la_LIBADD = $(ASOUNDLIB_LIBS) libalsa-util.la module_alsa_sink_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) +module_alsa_source_la_SOURCES = module-alsa-source.c +module_alsa_source_la_LDFLAGS = -module -avoid-version +module_alsa_source_la_LIBADD = $(ASOUNDLIB_LIBS) libalsa-util.la +module_alsa_source_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) + module_oss_la_SOURCES = module-oss.c module_oss_la_LDFLAGS = -module -avoid-version module_oss_la_LIBADD = libiochannel.la liboss-util.la diff --git a/src/alsa-util.c b/src/alsa-util.c new file mode 100644 index 00000000..edfd1613 --- /dev/null +++ b/src/alsa-util.c @@ -0,0 +1,73 @@ +#include + +#include "alsa-util.h" +#include "sample.h" + +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, struct pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *buffer_size) { + int ret = 0; + snd_pcm_hw_params_t *hwparams = NULL; + static const snd_pcm_format_t format_trans[] = { + [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8, + [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW, + [PA_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW, + [PA_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE, + [PA_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE, + [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE, + [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, + }; + + if (snd_pcm_hw_params_malloc(&hwparams) < 0 || + snd_pcm_hw_params_any(pcm_handle, hwparams) < 0 || + snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0 || + snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format]) < 0 || + snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &ss->rate, NULL) < 0 || + snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels) < 0 || + snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, periods, NULL) < 0 || + snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, buffer_size) < 0 || + snd_pcm_hw_params(pcm_handle, hwparams) < 0) { + ret = -1; + } + + if (hwparams) + snd_pcm_hw_params_free(hwparams); + return ret; +} + +int pa_create_io_sources(snd_pcm_t *pcm_handle, struct pa_mainloop_api* m, void ***io_sources, unsigned *n_io_sources, void (*cb)(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata), void *userdata) { + unsigned i; + struct pollfd *pfds, *ppfd; + void **ios; + assert(pcm_handle && m && io_sources && n_io_sources && cb); + + *n_io_sources = snd_pcm_poll_descriptors_count(pcm_handle); + + pfds = malloc(sizeof(struct pollfd) * *n_io_sources); + assert(pfds); + if (snd_pcm_poll_descriptors(pcm_handle, pfds, *n_io_sources) < 0) { + free(pfds); + return -1; + } + + *io_sources = malloc(sizeof(void*) * *n_io_sources); + assert(io_sources); + + for (i = 0, ios = *io_sources, ppfd = pfds; i < *n_io_sources; i++, ios++, ppfd++) { + *ios = m->source_io(m, ppfd->fd, + ((ppfd->events & POLLIN) ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | + ((ppfd->events & POLLOUT) ? PA_MAINLOOP_API_IO_EVENT_OUTPUT : 0), cb, userdata); + assert(*ios); + } + + free(pfds); + return 0; +} + +void pa_free_io_sources(struct pa_mainloop_api* m, void **io_sources, unsigned n_io_sources) { + unsigned i; + void **ios; + assert(m && io_sources); + + for (ios = io_sources, i = 0; i < n_io_sources; i++, ios++) + m->cancel_io(m, *ios); + free(io_sources); +} diff --git a/src/alsa-util.h b/src/alsa-util.h new file mode 100644 index 00000000..4468c9d8 --- /dev/null +++ b/src/alsa-util.h @@ -0,0 +1,14 @@ +#ifndef fooalsautilhfoo +#define fooalsautilhfoo + +#include + +#include "sample.h" +#include "mainloop-api.h" + +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, struct pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *buffer_size); + +int pa_create_io_sources(snd_pcm_t *pcm_handle, struct pa_mainloop_api *m, void ***io_sources, unsigned *n_io_sources, void (*cb)(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata), void *userdata); +void pa_free_io_sources(struct pa_mainloop_api* m, void **io_sources, unsigned n_io_sources); + +#endif diff --git a/src/module-alsa-sink.c b/src/module-alsa-sink.c index 16571a2c..a0b1e548 100644 --- a/src/module-alsa-sink.c +++ b/src/module-alsa-sink.c @@ -11,6 +11,7 @@ #include "modargs.h" #include "util.h" #include "sample-util.h" +#include "alsa-util.h" struct userdata { snd_pcm_t *pcm_handle; @@ -39,7 +40,7 @@ static const char* const valid_modargs[] = { static void xrun_recovery(struct userdata *u) { assert(u); - fprintf(stderr, "*** XRUN ***\n"); + fprintf(stderr, "*** ALSA-XRUN (playback) ***\n"); if (snd_pcm_prepare(u->pcm_handle) < 0) fprintf(stderr, "snd_pcm_prepare() failed\n"); @@ -63,13 +64,10 @@ static void do_write(struct userdata *u) { assert(memchunk->memblock && memchunk->memblock->data && memchunk->length && memchunk->memblock->length && (memchunk->length % u->frame_size) == 0); - assert(u->pcm_handle); - assert(memchunk->memblock); - assert(memchunk->memblock->data); - assert(memchunk->length); - assert(u->frame_size); - if ((frames = snd_pcm_writei(u->pcm_handle, memchunk->memblock->data + memchunk->index, memchunk->length / u->frame_size)) < 0) { + if (frames == -EAGAIN) + return; + if (frames == -EPIPE) { xrun_recovery(u); continue; @@ -80,8 +78,9 @@ static void do_write(struct userdata *u) { } if (memchunk == &u->memchunk) { - memchunk->index += frames * u->frame_size; - memchunk->length -= frames * u->frame_size; + size_t l = frames * u->frame_size; + memchunk->index += l; + memchunk->length -= l; if (memchunk->length == 0) { pa_memblock_unref(memchunk->memblock); @@ -125,23 +124,11 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { struct pa_modargs *ma = NULL; int ret = -1; struct userdata *u = NULL; - snd_pcm_hw_params_t *hwparams; const char *dev; - struct pollfd *pfds, *ppfd; struct pa_sample_spec ss; - unsigned i, periods, fragsize; + unsigned periods, fragsize; snd_pcm_uframes_t buffer_size; - void ** ios; size_t frame_size; - static const snd_pcm_format_t format_trans[] = { - [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8, - [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW, - [PA_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW, - [PA_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE, - [PA_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE, - [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE, - [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, - }; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { fprintf(stderr, __FILE__": failed to parse module arguments\n"); @@ -169,20 +156,12 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { m->userdata = u; if (snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) { - fprintf(stderr, "Error opening PCM device %s\n", dev); + fprintf(stderr, __FILE__": Error opening PCM device %s\n", dev); goto fail; } - snd_pcm_hw_params_alloca(&hwparams); - if (snd_pcm_hw_params_any(u->pcm_handle, hwparams) < 0 || - snd_pcm_hw_params_set_access(u->pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0 || - snd_pcm_hw_params_set_format(u->pcm_handle, hwparams, format_trans[ss.format]) < 0 || - snd_pcm_hw_params_set_rate_near(u->pcm_handle, hwparams, &ss.rate, NULL) < 0 || - snd_pcm_hw_params_set_channels(u->pcm_handle, hwparams, ss.channels) < 0 || - snd_pcm_hw_params_set_periods_near(u->pcm_handle, hwparams, &periods, NULL) < 0 || - snd_pcm_hw_params_set_buffer_size_near(u->pcm_handle, hwparams, &buffer_size) < 0 || - snd_pcm_hw_params(u->pcm_handle, hwparams) < 0) { - fprintf(stderr, "Error setting HW params.\n"); + if (pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &buffer_size) < 0) { + fprintf(stderr, __FILE__": Failed to set hardware parameters\n"); goto fail; } @@ -194,28 +173,11 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { pa_sink_set_owner(u->sink, m); u->sink->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); - u->n_io_sources = snd_pcm_poll_descriptors_count(u->pcm_handle); - - pfds = malloc(sizeof(struct pollfd) * u->n_io_sources); - assert(pfds); - if (snd_pcm_poll_descriptors(u->pcm_handle, pfds, u->n_io_sources) < 0) { - printf("Unable to obtain poll descriptors for playback.\n"); - free(pfds); + if (pa_create_io_sources(u->pcm_handle, c->mainloop, &u->io_sources, &u->n_io_sources, io_callback, u) < 0) { + fprintf(stderr, __FILE__": failed to obtain file descriptors\n"); goto fail; } - u->io_sources = malloc(sizeof(void*) * u->n_io_sources); - assert(u->io_sources); - - for (i = 0, ios = u->io_sources, ppfd = pfds; i < u->n_io_sources; i++, ios++, ppfd++) { - *ios = c->mainloop->source_io(c->mainloop, ppfd->fd, - ((ppfd->events & POLLIN) ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | - ((ppfd->events & POLLOUT) ? PA_MAINLOOP_API_IO_EVENT_OUTPUT : 0), io_callback, u); - assert(*ios); - } - - free(pfds); - u->frame_size = frame_size; u->fragment_size = buffer_size*u->frame_size/periods; @@ -250,14 +212,11 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { assert(c && m); if ((u = m->userdata)) { - unsigned i; - void **ios; - - pa_sink_free(u->sink); + if (u->sink) + pa_sink_free(u->sink); - for (ios = u->io_sources, i = 0; i < u->n_io_sources; i++, ios++) - c->mainloop->cancel_io(c->mainloop, *ios); - free(u->io_sources); + if (u->io_sources) + pa_free_io_sources(c->mainloop, u->io_sources, u->n_io_sources); if (u->pcm_handle) { snd_pcm_drop(u->pcm_handle); diff --git a/src/module-alsa-source.c b/src/module-alsa-source.c new file mode 100644 index 00000000..cc45254c --- /dev/null +++ b/src/module-alsa-source.c @@ -0,0 +1,212 @@ +#include +#include +#include + +#include + +#include "module.h" +#include "core.h" +#include "memchunk.h" +#include "sink.h" +#include "modargs.h" +#include "util.h" +#include "sample-util.h" +#include "alsa-util.h" + +struct userdata { + snd_pcm_t *pcm_handle; + struct pa_source *source; + void **io_sources; + unsigned n_io_sources; + + size_t frame_size, fragment_size; + struct pa_memchunk memchunk; +}; + +static const char* const valid_modargs[] = { + "device", + "source_name", + "format", + "channels", + "rate", + "fragments", + "fragment_size", + NULL +}; + +#define DEFAULT_SOURCE_NAME "alsa_input" +#define DEFAULT_DEVICE "hw:0,0" + +static void xrun_recovery(struct userdata *u) { + assert(u); + + fprintf(stderr, "*** ALSA-XRUN (capture) ***\n"); + + if (snd_pcm_prepare(u->pcm_handle) < 0) + fprintf(stderr, "snd_pcm_prepare() failed\n"); +} + +static void do_read(struct userdata *u) { + assert(u); + + for (;;) { + struct pa_memchunk post_memchunk; + snd_pcm_sframes_t frames; + size_t l; + + if (!u->memchunk.memblock) { + u->memchunk.memblock = pa_memblock_new(u->memchunk.length = u->fragment_size); + u->memchunk.index = 0; + } + + assert(u->memchunk.memblock && u->memchunk.memblock->data && u->memchunk.length && u->memchunk.memblock->length && (u->memchunk.length % u->frame_size) == 0); + + if ((frames = snd_pcm_readi(u->pcm_handle, u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { + if (frames == -EAGAIN) + return; + + if (frames == -EPIPE) { + xrun_recovery(u); + continue; + } + + fprintf(stderr, "snd_pcm_readi() failed: %s\n", strerror(-frames)); + return; + } + + l = frames * u->frame_size; + + post_memchunk = u->memchunk; + post_memchunk.length = l; + + pa_source_post(u->source, &post_memchunk); + + u->memchunk.index += l; + u->memchunk.length -= l; + + if (u->memchunk.length == 0) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + u->memchunk.index = u->memchunk.length = 0; + } + + break; + } +} + +static void io_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { + struct userdata *u = userdata; + assert(u && a && id); + + if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) + xrun_recovery(u); + + do_read(u); +} + +int pa_module_init(struct pa_core *c, struct pa_module*m) { + struct pa_modargs *ma = NULL; + int ret = -1; + struct userdata *u = NULL; + const char *dev; + struct pa_sample_spec ss; + unsigned periods, fragsize; + snd_pcm_uframes_t buffer_size; + size_t frame_size; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + fprintf(stderr, __FILE__": failed to parse module arguments\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + fprintf(stderr, __FILE__": failed to parse sample specification\n"); + goto fail; + } + frame_size = pa_sample_size(&ss); + + periods = 12; + fragsize = 1024; + if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { + fprintf(stderr, __FILE__": failed to parse buffer metrics\n"); + goto fail; + } + buffer_size = fragsize/frame_size*periods; + + u = malloc(sizeof(struct userdata)); + assert(u); + memset(u, 0, sizeof(struct userdata)); + m->userdata = u; + + if (snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK) < 0) { + fprintf(stderr, __FILE__": Error opening PCM device %s\n", dev); + goto fail; + } + + if (pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &buffer_size) < 0) { + fprintf(stderr, __FILE__": Failed to set hardware parameters\n"); + goto fail; + } + + u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); + assert(u->source); + + u->source->userdata = u; + pa_source_set_owner(u->source, m); + u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); + + if (pa_create_io_sources(u->pcm_handle, c->mainloop, &u->io_sources, &u->n_io_sources, io_callback, u) < 0) { + fprintf(stderr, __FILE__": failed to obtain file descriptors\n"); + goto fail; + } + + u->frame_size = frame_size; + u->fragment_size = buffer_size*u->frame_size/periods; + + fprintf(stderr, __FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); + + u->memchunk.memblock = NULL; + u->memchunk.index = u->memchunk.length = 0; + + snd_pcm_start(u->pcm_handle); + + ret = 0; + +finish: + if (ma) + pa_modargs_free(ma); + + return ret; + +fail: + + if (u) + pa_module_done(c, m); + + goto finish; +} + +void pa_module_done(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + assert(c && m); + + if ((u = m->userdata)) { + if (u->source) + pa_source_free(u->source); + + if (u->io_sources) + pa_free_io_sources(c->mainloop, u->io_sources, u->n_io_sources); + + if (u->pcm_handle) { + snd_pcm_drop(u->pcm_handle); + snd_pcm_close(u->pcm_handle); + } + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + + free(u); + } +} + diff --git a/src/polypaudio.run b/src/polypaudio.run index 48c3f7ea..2698c538 100755 --- a/src/polypaudio.run +++ b/src/polypaudio.run @@ -1,12 +1,20 @@ #!./polypaudio -F -# Load the CLI module -load module-cli +# Load audio drivers +load module-alsa-sink +load module-alsa-source device=plughw:1,0 +#load module-oss-mmap device="/dev/dsp" + +# Make some devices default +sink_default alsa_output +source_default alsa_input +# Load several protocols load module-esound-protocol-tcp load module-simple-protocol-tcp load module-native-protocol-unix load module-cli-protocol-unix -load module-alsa-sink -#load module-oss-mmap device="/dev/dsp" +# Load the CLI module +load module-cli + diff --git a/src/todo b/src/todo index e6685b2e..8a97ca6a 100644 --- a/src/todo +++ b/src/todo @@ -1,5 +1,4 @@ -- alsa source - +- make the sample spec configurable for oss devices - prefix modules/libraries with pa_ - rename files - svn-id and license in every file @@ -33,4 +32,4 @@ drivers: - python modules: -- http +- http? -- cgit From 554b01b6b3a82d201da9a10c54187a66b4804501 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Jul 2004 17:51:53 +0000 Subject: make oss sample spec configurable git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@77 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/module-oss-mmap.c | 27 +++++++++++++++----- src/module-oss.c | 27 +++++++++++++++----- src/oss-util.c | 70 ++++++++++++++++++++++++++++++++++++++------------- src/oss-util.h | 2 ++ src/polypaudio.run | 17 +++++++------ src/todo | 2 +- 6 files changed, 108 insertions(+), 37 deletions(-) diff --git a/src/module-oss-mmap.c b/src/module-oss-mmap.c index ceaae493..2b43cbad 100644 --- a/src/module-oss-mmap.c +++ b/src/module-oss-mmap.c @@ -45,6 +45,11 @@ static const char* const valid_modargs[] = { "device", "record", "playback", + "fragments", + "fragment_size", + "format", + "rate", + "channels", NULL }; @@ -175,7 +180,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { struct audio_buf_info info; struct userdata *u = NULL; const char *p; - int frag_size; + int nfrags, frag_size; int mode, caps; int enable_bits = 0, zero = 0; int playback = 1, record = 1; @@ -204,6 +209,19 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { goto fail; } + nfrags = 12; + frag_size = 1024; + if (pa_modargs_get_value_u32(ma, "fragments", &nfrags) < 0 || nfrags < 2 || pa_modargs_get_value_u32(ma, "fragment_size", &frag_size) < 0 || frag_size < 1) { + fprintf(stderr, __FILE__": failed to parse fragments arguments\n"); + goto fail; + } + + u->sample_spec = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &u->sample_spec) < 0) { + fprintf(stderr, __FILE__": failed to parse sample specification\n"); + goto fail; + } + if ((u->fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0) goto fail; @@ -214,12 +232,9 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { fprintf(stderr, "module-oss: device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); - frag_size = ((int) 12 << 16) | 10; /* nfrags = 12; frag_size = 2^10 */ - if (ioctl(u->fd, SNDCTL_DSP_SETFRAGMENT, &frag_size) < 0) { - fprintf(stderr, "SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno)); + if (pa_oss_set_fragments(u->fd, nfrags, frag_size) < 0) goto fail; - } - + if (pa_oss_auto_format(u->fd, &u->sample_spec) < 0) goto fail; diff --git a/src/module-oss.c b/src/module-oss.c index 48d10486..324bab3b 100644 --- a/src/module-oss.c +++ b/src/module-oss.c @@ -38,6 +38,11 @@ static const char* const valid_modargs[] = { "device", "record", "playback", + "fragments", + "fragment_size", + "format", + "rate", + "channels", NULL }; @@ -131,7 +136,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { struct userdata *u = NULL; const char *p; int fd = -1; - int frag_size, in_frag_size, out_frag_size; + int nfrags, frag_size, in_frag_size, out_frag_size; int mode; uint32_t record = 1, playback = 1; struct pa_sample_spec ss; @@ -154,16 +159,26 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { goto fail; } + nfrags = 12; + frag_size = 1024; + if (pa_modargs_get_value_u32(ma, "fragments", &nfrags) < 0 || nfrags < 2 || pa_modargs_get_value_u32(ma, "fragment_size", &frag_size) < 0 || frag_size < 1) { + fprintf(stderr, __FILE__": failed to parse fragments arguments\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + fprintf(stderr, __FILE__": failed to parse sample specification\n"); + goto fail; + } + if ((fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, NULL)) < 0) goto fail; fprintf(stderr, "module-oss: device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); - - frag_size = ((int) 12 << 16) | 10; /* nfrags = 12; frag_size = 2^10 */ - if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag_size) < 0) { - fprintf(stderr, "SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno)); + + if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) goto fail; - } if (pa_oss_auto_format(fd, &ss) < 0) goto fail; diff --git a/src/oss-util.c b/src/oss-util.c index f1e07017..7be91dcb 100644 --- a/src/oss-util.c +++ b/src/oss-util.c @@ -62,27 +62,39 @@ fail: } int pa_oss_auto_format(int fd, struct pa_sample_spec *ss) { - int format, channels, speed; + int format, channels, speed, reqformat; + static const int format_trans[] = { + [PA_SAMPLE_U8] = AFMT_U8, + [PA_SAMPLE_ALAW] = AFMT_A_LAW, + [PA_SAMPLE_ULAW] = AFMT_MU_LAW, + [PA_SAMPLE_S16LE] = AFMT_S16_LE, + [PA_SAMPLE_S16BE] = AFMT_S16_BE, + [PA_SAMPLE_FLOAT32LE] = AFMT_QUERY, /* not supported */ + [PA_SAMPLE_FLOAT32BE] = AFMT_QUERY, /* not supported */ + }; assert(fd >= 0 && ss); - - format = AFMT_S16_NE; - if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_S16_NE) { - int f = AFMT_S16_NE == AFMT_S16_LE ? AFMT_S16_BE : AFMT_S16_LE; - format = f; - if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != f) { - format = AFMT_U8; - if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_U8) { - fprintf(stderr, "SNDCTL_DSP_SETFMT: %s\n", format != AFMT_U8 ? "No supported sample format" : strerror(errno)); - return -1; + + reqformat = format = format_trans[ss->format]; + if (reqformat == AFMT_QUERY || ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != reqformat) { + format = AFMT_S16_NE; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_S16_NE) { + int f = AFMT_S16_NE == AFMT_S16_LE ? AFMT_S16_BE : AFMT_S16_LE; + format = f; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != f) { + format = AFMT_U8; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_U8) { + fprintf(stderr, "SNDCTL_DSP_SETFMT: %s\n", format != AFMT_U8 ? "No supported sample format" : strerror(errno)); + return -1; + } else + ss->format = PA_SAMPLE_U8; } else - ss->format = PA_SAMPLE_U8; + ss->format = f == AFMT_S16_LE ? PA_SAMPLE_S16LE : PA_SAMPLE_S16BE; } else - ss->format = f == AFMT_S16_LE ? PA_SAMPLE_S16LE : PA_SAMPLE_S16BE; - } else - ss->format = PA_SAMPLE_S16NE; + ss->format = PA_SAMPLE_S16NE; + } - channels = 2; + channels = ss->channels; if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) { fprintf(stderr, "SNDCTL_DSP_CHANNELS: %s\n", strerror(errno)); return -1; @@ -90,7 +102,7 @@ int pa_oss_auto_format(int fd, struct pa_sample_spec *ss) { assert(channels); ss->channels = channels; - speed = 44100; + speed = ss->rate; if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) { fprintf(stderr, "SNDCTL_DSP_SPEED: %s\n", strerror(errno)); return -1; @@ -100,3 +112,27 @@ int pa_oss_auto_format(int fd, struct pa_sample_spec *ss) { return 0; } + +static int log2(int v) { + int k = 0; + + for (;;) { + v >>= 1; + if (!v) break; + k++; + } + + return k; +} + +int pa_oss_set_fragments(int fd, int nfrags, int frag_size) { + int arg; + arg = ((int) nfrags << 16) | log2(frag_size); + + if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &arg) < 0) { + fprintf(stderr, "SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno)); + return -1; + } + + return 0; +} diff --git a/src/oss-util.h b/src/oss-util.h index 030afba4..a62eee1d 100644 --- a/src/oss-util.h +++ b/src/oss-util.h @@ -6,4 +6,6 @@ int pa_oss_open(const char *device, int *mode, int* pcaps); int pa_oss_auto_format(int fd, struct pa_sample_spec *ss); +int pa_oss_set_fragments(int fd, int frags, int frag_size); + #endif diff --git a/src/polypaudio.run b/src/polypaudio.run index 2698c538..25af2df6 100755 --- a/src/polypaudio.run +++ b/src/polypaudio.run @@ -1,13 +1,10 @@ #!./polypaudio -F # Load audio drivers -load module-alsa-sink -load module-alsa-source device=plughw:1,0 -#load module-oss-mmap device="/dev/dsp" - -# Make some devices default -sink_default alsa_output -source_default alsa_input +#load module-alsa-sink +#load module-alsa-source device=plughw:1,0 +#load module-oss device="/dev/dsp" +load module-oss-mmap device="/dev/dsp" # Load several protocols load module-esound-protocol-tcp @@ -18,3 +15,9 @@ load module-cli-protocol-unix # Load the CLI module load module-cli +.nofail + +# Make some devices default +sink_default alsa_output +source_default alsa_input + diff --git a/src/todo b/src/todo index 8a97ca6a..225fb227 100644 --- a/src/todo +++ b/src/todo @@ -1,4 +1,4 @@ -- make the sample spec configurable for oss devices +- run depmod once again - prefix modules/libraries with pa_ - rename files - svn-id and license in every file -- cgit From 00b53f3f4b27af2572656c975b1fd225e272e012 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Jul 2004 17:56:35 +0000 Subject: make a symbol in module-ptorocol-stub static git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@78 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/module-protocol-stub.c | 2 +- src/todo | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/module-protocol-stub.c b/src/module-protocol-stub.c index 7338abc9..f9ed62b8 100644 --- a/src/module-protocol-stub.c +++ b/src/module-protocol-stub.c @@ -61,7 +61,7 @@ static const char* const valid_modargs[] = { NULL }; -struct pa_socket_server *create_socket_server(struct pa_core *c, struct pa_modargs *ma) { +static struct pa_socket_server *create_socket_server(struct pa_core *c, struct pa_modargs *ma) { struct pa_socket_server *s; #ifdef USE_TCP_SOCKETS uint32_t loopback = 0, port = IPV4_PORT; diff --git a/src/todo b/src/todo index 225fb227..1e1ff873 100644 --- a/src/todo +++ b/src/todo @@ -1,4 +1,3 @@ -- run depmod once again - prefix modules/libraries with pa_ - rename files - svn-id and license in every file -- cgit From 2a6ee7731f6654b2efbc5dbf861f82c2823d1a54 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Jul 2004 18:40:20 +0000 Subject: rename a bunch of files git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@79 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/esound-spec.h | 192 --------- src/esound.h | 192 +++++++++ src/native-common.h | 47 +++ src/polyp-error.c | 28 -- src/polyp-error.h | 10 - src/polyp.c | 948 --------------------------------------------- src/polyp.h | 73 ---- src/polypdef.h | 20 - src/polyplib-def.h | 20 + src/polyplib-error.c | 28 ++ src/polyplib-error.h | 10 + src/polyplib-simple.c | 233 +++++++++++ src/polyplib-simple.h | 28 ++ src/polyplib.c | 948 +++++++++++++++++++++++++++++++++++++++++++++ src/polyplib.h | 73 ++++ src/protocol-native-spec.h | 47 --- src/simple.c | 233 ----------- src/simple.h | 28 -- src/sink-input.c | 138 +++++++ src/sink-input.h | 46 +++ src/sinkinput.c | 138 ------- src/sinkinput.h | 46 --- src/source-output.c | 76 ++++ src/source-output.h | 37 ++ src/sourceoutput.c | 76 ---- src/sourceoutput.h | 37 -- 26 files changed, 1876 insertions(+), 1876 deletions(-) delete mode 100644 src/esound-spec.h create mode 100644 src/esound.h create mode 100644 src/native-common.h delete mode 100644 src/polyp-error.c delete mode 100644 src/polyp-error.h delete mode 100644 src/polyp.c delete mode 100644 src/polyp.h delete mode 100644 src/polypdef.h create mode 100644 src/polyplib-def.h create mode 100644 src/polyplib-error.c create mode 100644 src/polyplib-error.h create mode 100644 src/polyplib-simple.c create mode 100644 src/polyplib-simple.h create mode 100644 src/polyplib.c create mode 100644 src/polyplib.h delete mode 100644 src/protocol-native-spec.h delete mode 100644 src/simple.c delete mode 100644 src/simple.h create mode 100644 src/sink-input.c create mode 100644 src/sink-input.h delete mode 100644 src/sinkinput.c delete mode 100644 src/sinkinput.h create mode 100644 src/source-output.c create mode 100644 src/source-output.h delete mode 100644 src/sourceoutput.c delete mode 100644 src/sourceoutput.h diff --git a/src/esound-spec.h b/src/esound-spec.h deleted file mode 100644 index f7a4d3db..00000000 --- a/src/esound-spec.h +++ /dev/null @@ -1,192 +0,0 @@ -#ifndef fooesoundhfoo -#define fooesoundhfoo - -/* Most of the following is blatantly stolen from esound. */ - - -/* path and name of the default EsounD domain socket */ -#define ESD_UNIX_SOCKET_DIR "/tmp/.esd" -#define ESD_UNIX_SOCKET_NAME "/tmp/.esd/socket" - -/* length of the audio buffer size */ -#define ESD_BUF_SIZE (4 * 1024) -/* maximum size we can write(). Otherwise we might overflow */ -#define ESD_MAX_WRITE_SIZE (21 * 4096) - -/* length of the authorization key, octets */ -#define ESD_KEY_LEN (16) - -/* default port for the EsounD server */ -#define ESD_DEFAULT_PORT (16001) - -/* default sample rate for the EsounD server */ -#define ESD_DEFAULT_RATE (44100) - -/* maximum length of a stream/sample name */ -#define ESD_NAME_MAX (128) - -/* a magic number to identify the relative endianness of a client */ -#define ESD_ENDIAN_KEY ((uint32_t) (('E' << 24) + ('N' << 16) + ('D' << 8) + ('N'))) - -#define ESD_VOLUME_BASE (256) - - -/*************************************/ -/* what can we do to/with the EsounD */ -enum esd_proto { - ESD_PROTO_CONNECT, /* implied on inital client connection */ - - /* pseudo "security" functionality */ - ESD_PROTO_LOCK, /* disable "foreign" client connections */ - ESD_PROTO_UNLOCK, /* enable "foreign" client connections */ - - /* stream functionality: play, record, monitor */ - ESD_PROTO_STREAM_PLAY, /* play all following data as a stream */ - ESD_PROTO_STREAM_REC, /* record data from card as a stream */ - ESD_PROTO_STREAM_MON, /* send mixed buffer output as a stream */ - - /* sample functionality: cache, free, play, loop, EOL, kill */ - ESD_PROTO_SAMPLE_CACHE, /* cache a sample in the server */ - ESD_PROTO_SAMPLE_FREE, /* release a sample in the server */ - ESD_PROTO_SAMPLE_PLAY, /* play a cached sample */ - ESD_PROTO_SAMPLE_LOOP, /* loop a cached sample, til eoloop */ - ESD_PROTO_SAMPLE_STOP, /* stop a looping sample when done */ - ESD_PROTO_SAMPLE_KILL, /* stop the looping sample immed. */ - - /* free and reclaim /dev/dsp functionality */ - ESD_PROTO_STANDBY, /* release /dev/dsp and ignore all data */ - ESD_PROTO_RESUME, /* reclaim /dev/dsp and play sounds again */ - - /* TODO: move these to a more logical place. NOTE: will break the protocol */ - ESD_PROTO_SAMPLE_GETID, /* get the ID for an already-cached sample */ - ESD_PROTO_STREAM_FILT, /* filter mixed buffer output as a stream */ - - /* esd remote management */ - ESD_PROTO_SERVER_INFO, /* get server info (ver, sample rate, format) */ - ESD_PROTO_ALL_INFO, /* get all info (server info, players, samples) */ - ESD_PROTO_SUBSCRIBE, /* track new and removed players and samples */ - ESD_PROTO_UNSUBSCRIBE, /* stop tracking updates */ - - /* esd remote control */ - ESD_PROTO_STREAM_PAN, /* set stream panning */ - ESD_PROTO_SAMPLE_PAN, /* set default sample panning */ - - /* esd status */ - ESD_PROTO_STANDBY_MODE, /* see if server is in standby, autostandby, etc */ - - /* esd latency */ - ESD_PROTO_LATENCY, /* retrieve latency between write()'s and output */ - - ESD_PROTO_MAX /* for bounds checking */ -}; - -/******************/ -/* The EsounD api */ - -/* the properties of a sound buffer are logically or'd */ - -/* bits of stream/sample data */ -#define ESD_MASK_BITS ( 0x000F ) -#define ESD_BITS8 ( 0x0000 ) -#define ESD_BITS16 ( 0x0001 ) - -/* how many interleaved channels of data */ -#define ESD_MASK_CHAN ( 0x00F0 ) -#define ESD_MONO ( 0x0010 ) -#define ESD_STEREO ( 0x0020 ) - -/* whether it's a stream or a sample */ -#define ESD_MASK_MODE ( 0x0F00 ) -#define ESD_STREAM ( 0x0000 ) -#define ESD_SAMPLE ( 0x0100 ) -#define ESD_ADPCM ( 0x0200 ) /* TODO: anyone up for this? =P */ - -/* the function of the stream/sample, and common functions */ -#define ESD_MASK_FUNC ( 0xF000 ) -#define ESD_PLAY ( 0x1000 ) -/* functions for streams only */ -#define ESD_MONITOR ( 0x0000 ) -#define ESD_RECORD ( 0x2000 ) -/* functions for samples only */ -#define ESD_STOP ( 0x0000 ) -#define ESD_LOOP ( 0x2000 ) - -typedef int esd_format_t; -typedef int esd_proto_t; - -/*******************************************************************/ -/* esdmgr.c - functions to implement a "sound manager" for esd */ - -/* structures to retrieve information about streams/samples from the server */ -typedef struct esd_server_info { - - int version; /* server version encoded as an int */ - esd_format_t format; /* magic int with the format info */ - int rate; /* sample rate */ - -} esd_server_info_t; - -typedef struct esd_player_info { - - struct esd_player_info *next; /* point to next entry in list */ - esd_server_info_t *server; /* the server that contains this stream */ - - int source_id; /* either a stream fd or sample id */ - char name[ ESD_NAME_MAX ]; /* name of stream for remote control */ - int rate; /* sample rate */ - int left_vol_scale; /* volume scaling */ - int right_vol_scale; - - esd_format_t format; /* magic int with the format info */ - -} esd_player_info_t; - -typedef struct esd_sample_info { - - struct esd_sample_info *next; /* point to next entry in list */ - esd_server_info_t *server; /* the server that contains this sample */ - - int sample_id; /* either a stream fd or sample id */ - char name[ ESD_NAME_MAX ]; /* name of stream for remote control */ - int rate; /* sample rate */ - int left_vol_scale; /* volume scaling */ - int right_vol_scale; - - esd_format_t format; /* magic int with the format info */ - int length; /* total buffer length */ - -} esd_sample_info_t; - -typedef struct esd_info { - - esd_server_info_t *server; - esd_player_info_t *player_list; - esd_sample_info_t *sample_list; - -} esd_info_t; - -enum esd_standby_mode { - ESM_ERROR, ESM_ON_STANDBY, ESM_ON_AUTOSTANDBY, ESM_RUNNING -}; -typedef int esd_standby_mode_t; - -enum esd_client_state { - ESD_STREAMING_DATA, /* data from here on is streamed data */ - ESD_CACHING_SAMPLE, /* midway through caching a sample */ - ESD_NEEDS_REQDATA, /* more data needed to complere request */ - ESD_NEXT_REQUEST, /* proceed to next request */ - ESD_CLIENT_STATE_MAX /* place holder */ -}; -typedef int esd_client_state_t; - -/* switch endian order for cross platform playing */ -#define swap_endian_32(x) ((x >> 24) | ((x >> 8) & 0xFF00) | (((x & 0xFF00) << 8)) | (x << 24)) -#define maybe_swap_endian_32(c,x) ((c) ? swap_endian_32(x) : x) - -/* the endian key is transferred in binary, if it's read into int, */ -/* and matches ESD_ENDIAN_KEY (ENDN), then the endianness of the */ -/* server and the client match; if it's SWAP_ENDIAN_KEY, swap data */ -#define ESD_SWAP_ENDIAN_KEY ((uint32_t) swap_endian_32(ESD_ENDIAN_KEY)) - - -#endif diff --git a/src/esound.h b/src/esound.h new file mode 100644 index 00000000..f7a4d3db --- /dev/null +++ b/src/esound.h @@ -0,0 +1,192 @@ +#ifndef fooesoundhfoo +#define fooesoundhfoo + +/* Most of the following is blatantly stolen from esound. */ + + +/* path and name of the default EsounD domain socket */ +#define ESD_UNIX_SOCKET_DIR "/tmp/.esd" +#define ESD_UNIX_SOCKET_NAME "/tmp/.esd/socket" + +/* length of the audio buffer size */ +#define ESD_BUF_SIZE (4 * 1024) +/* maximum size we can write(). Otherwise we might overflow */ +#define ESD_MAX_WRITE_SIZE (21 * 4096) + +/* length of the authorization key, octets */ +#define ESD_KEY_LEN (16) + +/* default port for the EsounD server */ +#define ESD_DEFAULT_PORT (16001) + +/* default sample rate for the EsounD server */ +#define ESD_DEFAULT_RATE (44100) + +/* maximum length of a stream/sample name */ +#define ESD_NAME_MAX (128) + +/* a magic number to identify the relative endianness of a client */ +#define ESD_ENDIAN_KEY ((uint32_t) (('E' << 24) + ('N' << 16) + ('D' << 8) + ('N'))) + +#define ESD_VOLUME_BASE (256) + + +/*************************************/ +/* what can we do to/with the EsounD */ +enum esd_proto { + ESD_PROTO_CONNECT, /* implied on inital client connection */ + + /* pseudo "security" functionality */ + ESD_PROTO_LOCK, /* disable "foreign" client connections */ + ESD_PROTO_UNLOCK, /* enable "foreign" client connections */ + + /* stream functionality: play, record, monitor */ + ESD_PROTO_STREAM_PLAY, /* play all following data as a stream */ + ESD_PROTO_STREAM_REC, /* record data from card as a stream */ + ESD_PROTO_STREAM_MON, /* send mixed buffer output as a stream */ + + /* sample functionality: cache, free, play, loop, EOL, kill */ + ESD_PROTO_SAMPLE_CACHE, /* cache a sample in the server */ + ESD_PROTO_SAMPLE_FREE, /* release a sample in the server */ + ESD_PROTO_SAMPLE_PLAY, /* play a cached sample */ + ESD_PROTO_SAMPLE_LOOP, /* loop a cached sample, til eoloop */ + ESD_PROTO_SAMPLE_STOP, /* stop a looping sample when done */ + ESD_PROTO_SAMPLE_KILL, /* stop the looping sample immed. */ + + /* free and reclaim /dev/dsp functionality */ + ESD_PROTO_STANDBY, /* release /dev/dsp and ignore all data */ + ESD_PROTO_RESUME, /* reclaim /dev/dsp and play sounds again */ + + /* TODO: move these to a more logical place. NOTE: will break the protocol */ + ESD_PROTO_SAMPLE_GETID, /* get the ID for an already-cached sample */ + ESD_PROTO_STREAM_FILT, /* filter mixed buffer output as a stream */ + + /* esd remote management */ + ESD_PROTO_SERVER_INFO, /* get server info (ver, sample rate, format) */ + ESD_PROTO_ALL_INFO, /* get all info (server info, players, samples) */ + ESD_PROTO_SUBSCRIBE, /* track new and removed players and samples */ + ESD_PROTO_UNSUBSCRIBE, /* stop tracking updates */ + + /* esd remote control */ + ESD_PROTO_STREAM_PAN, /* set stream panning */ + ESD_PROTO_SAMPLE_PAN, /* set default sample panning */ + + /* esd status */ + ESD_PROTO_STANDBY_MODE, /* see if server is in standby, autostandby, etc */ + + /* esd latency */ + ESD_PROTO_LATENCY, /* retrieve latency between write()'s and output */ + + ESD_PROTO_MAX /* for bounds checking */ +}; + +/******************/ +/* The EsounD api */ + +/* the properties of a sound buffer are logically or'd */ + +/* bits of stream/sample data */ +#define ESD_MASK_BITS ( 0x000F ) +#define ESD_BITS8 ( 0x0000 ) +#define ESD_BITS16 ( 0x0001 ) + +/* how many interleaved channels of data */ +#define ESD_MASK_CHAN ( 0x00F0 ) +#define ESD_MONO ( 0x0010 ) +#define ESD_STEREO ( 0x0020 ) + +/* whether it's a stream or a sample */ +#define ESD_MASK_MODE ( 0x0F00 ) +#define ESD_STREAM ( 0x0000 ) +#define ESD_SAMPLE ( 0x0100 ) +#define ESD_ADPCM ( 0x0200 ) /* TODO: anyone up for this? =P */ + +/* the function of the stream/sample, and common functions */ +#define ESD_MASK_FUNC ( 0xF000 ) +#define ESD_PLAY ( 0x1000 ) +/* functions for streams only */ +#define ESD_MONITOR ( 0x0000 ) +#define ESD_RECORD ( 0x2000 ) +/* functions for samples only */ +#define ESD_STOP ( 0x0000 ) +#define ESD_LOOP ( 0x2000 ) + +typedef int esd_format_t; +typedef int esd_proto_t; + +/*******************************************************************/ +/* esdmgr.c - functions to implement a "sound manager" for esd */ + +/* structures to retrieve information about streams/samples from the server */ +typedef struct esd_server_info { + + int version; /* server version encoded as an int */ + esd_format_t format; /* magic int with the format info */ + int rate; /* sample rate */ + +} esd_server_info_t; + +typedef struct esd_player_info { + + struct esd_player_info *next; /* point to next entry in list */ + esd_server_info_t *server; /* the server that contains this stream */ + + int source_id; /* either a stream fd or sample id */ + char name[ ESD_NAME_MAX ]; /* name of stream for remote control */ + int rate; /* sample rate */ + int left_vol_scale; /* volume scaling */ + int right_vol_scale; + + esd_format_t format; /* magic int with the format info */ + +} esd_player_info_t; + +typedef struct esd_sample_info { + + struct esd_sample_info *next; /* point to next entry in list */ + esd_server_info_t *server; /* the server that contains this sample */ + + int sample_id; /* either a stream fd or sample id */ + char name[ ESD_NAME_MAX ]; /* name of stream for remote control */ + int rate; /* sample rate */ + int left_vol_scale; /* volume scaling */ + int right_vol_scale; + + esd_format_t format; /* magic int with the format info */ + int length; /* total buffer length */ + +} esd_sample_info_t; + +typedef struct esd_info { + + esd_server_info_t *server; + esd_player_info_t *player_list; + esd_sample_info_t *sample_list; + +} esd_info_t; + +enum esd_standby_mode { + ESM_ERROR, ESM_ON_STANDBY, ESM_ON_AUTOSTANDBY, ESM_RUNNING +}; +typedef int esd_standby_mode_t; + +enum esd_client_state { + ESD_STREAMING_DATA, /* data from here on is streamed data */ + ESD_CACHING_SAMPLE, /* midway through caching a sample */ + ESD_NEEDS_REQDATA, /* more data needed to complere request */ + ESD_NEXT_REQUEST, /* proceed to next request */ + ESD_CLIENT_STATE_MAX /* place holder */ +}; +typedef int esd_client_state_t; + +/* switch endian order for cross platform playing */ +#define swap_endian_32(x) ((x >> 24) | ((x >> 8) & 0xFF00) | (((x & 0xFF00) << 8)) | (x << 24)) +#define maybe_swap_endian_32(c,x) ((c) ? swap_endian_32(x) : x) + +/* the endian key is transferred in binary, if it's read into int, */ +/* and matches ESD_ENDIAN_KEY (ENDN), then the endianness of the */ +/* server and the client match; if it's SWAP_ENDIAN_KEY, swap data */ +#define ESD_SWAP_ENDIAN_KEY ((uint32_t) swap_endian_32(ESD_ENDIAN_KEY)) + + +#endif diff --git a/src/native-common.h b/src/native-common.h new file mode 100644 index 00000000..e1db6f64 --- /dev/null +++ b/src/native-common.h @@ -0,0 +1,47 @@ +#ifndef fooprotocolnativespech +#define fooprotocolnativespech + +enum { + PA_COMMAND_ERROR, + PA_COMMAND_TIMEOUT, /* pseudo command */ + PA_COMMAND_REPLY, + PA_COMMAND_CREATE_PLAYBACK_STREAM, + PA_COMMAND_DELETE_PLAYBACK_STREAM, + PA_COMMAND_CREATE_RECORD_STREAM, + PA_COMMAND_DELETE_RECORD_STREAM, + PA_COMMAND_EXIT, + PA_COMMAND_REQUEST, + PA_COMMAND_AUTH, + PA_COMMAND_SET_NAME, + PA_COMMAND_LOOKUP_SINK, + PA_COMMAND_LOOKUP_SOURCE, + PA_COMMAND_DRAIN_PLAYBACK_STREAM, + PA_COMMAND_PLAYBACK_STREAM_KILLED, + PA_COMMAND_RECORD_STREAM_KILLED, + PA_COMMAND_STAT, + PA_COMMAND_GET_PLAYBACK_LATENCY, + PA_COMMAND_MAX +}; + +enum { + PA_ERROR_OK, + PA_ERROR_ACCESS, + PA_ERROR_COMMAND, + PA_ERROR_INVALID, + PA_ERROR_EXIST, + PA_ERROR_NOENTITY, + PA_ERROR_CONNECTIONREFUSED, + PA_ERROR_PROTOCOL, + PA_ERROR_TIMEOUT, + PA_ERROR_AUTHKEY, + PA_ERROR_INTERNAL, + PA_ERROR_CONNECTIONTERMINATED, + PA_ERROR_KILLED, + PA_ERROR_INVALIDSERVER, + PA_ERROR_MAX +}; + +#define PA_NATIVE_COOKIE_LENGTH 256 +#define PA_NATIVE_COOKIE_FILE ".polypaudio-cookie" + +#endif diff --git a/src/polyp-error.c b/src/polyp-error.c deleted file mode 100644 index 86166b0c..00000000 --- a/src/polyp-error.c +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include - -#include "polyp-error.h" -#include "protocol-native-spec.h" - -static const char* const errortab[PA_ERROR_MAX] = { - [PA_ERROR_OK] = "OK", - [PA_ERROR_ACCESS] = "Access denied", - [PA_ERROR_COMMAND] = "Unknown command", - [PA_ERROR_INVALID] = "Invalid argument", - [PA_ERROR_EXIST] = "Entity exists", - [PA_ERROR_NOENTITY] = "No such entity", - [PA_ERROR_CONNECTIONREFUSED] = "Connection refused", - [PA_ERROR_PROTOCOL] = "Protocol corrupt", - [PA_ERROR_TIMEOUT] = "Timeout", - [PA_ERROR_AUTHKEY] = "Not authorization key", - [PA_ERROR_INTERNAL] = "Internal error", - [PA_ERROR_CONNECTIONTERMINATED] = "Connection terminated", - [PA_ERROR_KILLED] = "Entity killed", -}; - -const char*pa_strerror(uint32_t error) { - if (error >= PA_ERROR_MAX) - return NULL; - - return errortab[error]; -} diff --git a/src/polyp-error.h b/src/polyp-error.h deleted file mode 100644 index 7407f34c..00000000 --- a/src/polyp-error.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef foopolyperrhfoo -#define foopolyperrhfoo - -#include - -#include "protocol-native-spec.h" - -const char* pa_strerror(uint32_t error); - -#endif diff --git a/src/polyp.c b/src/polyp.c deleted file mode 100644 index d6d0f908..00000000 --- a/src/polyp.c +++ /dev/null @@ -1,948 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "polyp.h" -#include "protocol-native-spec.h" -#include "pdispatch.h" -#include "pstream.h" -#include "dynarray.h" -#include "socket-client.h" -#include "pstream-util.h" -#include "authkey.h" -#include "util.h" - -#define DEFAULT_MAXLENGTH 204800 -#define DEFAULT_TLENGTH 10240 -#define DEFAULT_PREBUF 4096 -#define DEFAULT_MINREQ 1024 -#define DEFAULT_FRAGSIZE 1024 - -#define DEFAULT_TIMEOUT (5*60) -#define DEFAULT_SERVER "/tmp/polypaudio/native" -#define DEFAULT_PORT "4713" - -struct pa_context { - char *name; - struct pa_mainloop_api* mainloop; - struct pa_socket_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; - struct pa_dynarray *record_streams, *playback_streams; - struct pa_stream *first_stream; - uint32_t ctag; - uint32_t error; - enum { - CONTEXT_UNCONNECTED, - CONTEXT_CONNECTING, - CONTEXT_AUTHORIZING, - CONTEXT_SETTING_NAME, - CONTEXT_READY, - CONTEXT_DEAD - } state; - - void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); - void *connect_complete_userdata; - - void (*drain_complete_callback)(struct pa_context*c, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_context*c, void *userdata); - void *die_userdata; - - void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); - void *stat_userdata; - - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; -}; - -struct pa_stream { - struct pa_context *context; - struct pa_stream *next, *previous; - - char *name; - struct pa_buffer_attr buffer_attr; - struct pa_sample_spec sample_spec; - uint32_t device_index; - uint32_t channel; - int channel_valid; - enum pa_stream_direction direction; - - enum { STREAM_LOOKING_UP, STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; - uint32_t requested_bytes; - - void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); - void *read_userdata; - - void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); - void *write_userdata; - - void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); - void *create_complete_userdata; - - void (*drain_complete_callback)(struct pa_stream *s, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_stream*c, void *userdata); - void *die_userdata; - - void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); - void *get_latency_userdata; -}; - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_EXIT] = { NULL }, - [PA_COMMAND_REQUEST] = { command_request }, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, -}; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { - struct pa_context *c; - assert(mainloop && name); - - c = malloc(sizeof(struct pa_context)); - assert(c); - c->name = strdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - assert(c->playback_streams); - c->record_streams = pa_dynarray_new(); - assert(c->record_streams); - c->first_stream = NULL; - c->error = PA_ERROR_OK; - c->state = CONTEXT_UNCONNECTED; - c->ctag = 0; - - c->connect_complete_callback = NULL; - c->connect_complete_userdata = NULL; - - c->drain_complete_callback = NULL; - c->drain_complete_userdata = NULL; - - c->die_callback = NULL; - c->die_userdata = NULL; - - c->stat_callback = NULL; - c->stat_userdata = NULL; - - pa_check_for_sigpipe(); - return c; -} - -void pa_context_free(struct pa_context *c) { - assert(c); - - while (c->first_stream) - pa_stream_free(c->first_stream); - - if (c->client) - pa_socket_client_free(c->client); - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - if (c->pstream) - pa_pstream_free(c->pstream); - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - free(c->name); - free(c); -} - -static void stream_dead(struct pa_stream *s) { - assert(s); - - if (s->state == STREAM_DEAD) - return; - - if (s->state == STREAM_READY) { - s->state = STREAM_DEAD; - if (s->die_callback) - s->die_callback(s, s->die_userdata); - } else - s->state = STREAM_DEAD; -} - -static void context_dead(struct pa_context *c) { - struct pa_stream *s; - assert(c); - - if (c->state == CONTEXT_DEAD) - return; - - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) - pa_pstream_free(c->pstream); - c->pstream = NULL; - - if (c->client) - pa_socket_client_free(c->client); - c->client = NULL; - - for (s = c->first_stream; s; s = s->next) - stream_dead(s); - - if (c->state == CONTEXT_READY) { - c->state = CONTEXT_DEAD; - if (c->die_callback) - c->die_callback(c, c->die_userdata); - } else - c->state = CONTEXT_DEAD; -} - -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { - struct pa_context *c = userdata; - assert(p && c); - c->error = PA_ERROR_CONNECTIONTERMINATED; - context_dead(c); -} - -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { - struct pa_context *c = userdata; - assert(p && packet && c); - - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - fprintf(stderr, "polyp.c: invalid packet.\n"); - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - } -} - -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - - if (!(s = pa_dynarray_get(c->record_streams, channel))) - return; - - if (s->read_callback) - s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); -} - -static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { - assert(c && t); - - if (command == PA_COMMAND_ERROR) { - if (pa_tagstruct_getu32(t, &c->error) < 0) { - c->error = PA_ERROR_PROTOCOL; - return -1; - } - - return 0; - } - - c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; - return -1; -} - -static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); - - if (command != PA_COMMAND_REPLY) { - handle_error(c, command, t); - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - if (c->state == CONTEXT_AUTHORIZING) { - struct pa_tagstruct *t; - c->state = CONTEXT_SETTING_NAME; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, c->name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - } else { - assert(c->state == CONTEXT_SETTING_NAME); - - c->state = CONTEXT_READY; - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 1, c->connect_complete_userdata); - } - - return; -} - -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { - struct pa_context *c = userdata; - struct pa_tagstruct *t; - uint32_t tag; - assert(client && c && c->state == CONTEXT_CONNECTING); - - pa_socket_client_free(client); - c->client = NULL; - - if (!io) { - c->error = PA_ERROR_CONNECTIONREFUSED; - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - c->pstream = pa_pstream_new(c->mainloop, io); - assert(c->pstream); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - c->state = CONTEXT_AUTHORIZING; -} - -static struct sockaddr *resolve_server(const char *server, size_t *len) { - struct sockaddr *sa; - struct addrinfo hints, *result = NULL; - char *port; - assert(server && len); - - if ((port = strrchr(server, ':'))) - port++; - if (!port) - port = DEFAULT_PORT; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(server, port, &hints, &result) != 0) - return NULL; - assert(result); - - sa = malloc(*len = result->ai_addrlen); - assert(sa); - memcpy(sa, result->ai_addr, *len); - - freeaddrinfo(result); - - return sa; - -} - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { - assert(c && c->state == CONTEXT_UNCONNECTED); - - if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { - c->error = PA_ERROR_AUTHKEY; - return -1; - } - - if (!server) - if (!(server = getenv("POLYP_SERVER"))) - server = DEFAULT_SERVER; - - assert(!c->client); - - if (*server == '/') { - if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } else { - struct sockaddr* sa; - size_t sa_len; - - if (!(sa = resolve_server(server, &sa_len))) { - c->error = PA_ERROR_INVALIDSERVER; - return -1; - } - - c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); - free(sa); - - if (!c->client) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } - - c->connect_complete_callback = complete; - c->connect_complete_userdata = userdata; - - pa_socket_client_set_callback(c->client, on_connection, c); - c->state = CONTEXT_CONNECTING; - - return 0; -} - -int pa_context_is_dead(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_DEAD; -} - -int pa_context_is_ready(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_READY; -} - -int pa_context_errno(struct pa_context *c) { - assert(c); - return c->error; -} - -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { - assert(c); - c->die_callback = cb; - c->die_userdata = userdata; -} - -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - uint32_t channel; - assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - return; - - c->error = PA_ERROR_KILLED; - stream_dead(s); -} - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s; - struct pa_context *c = userdata; - uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - return; - - if (s->state != STREAM_READY) - return; - - s->requested_bytes += bytes; - - if (s->requested_bytes && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); -} - -static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s && s->state == STREAM_CREATING); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - - return; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - pa_tagstruct_getu32(t, &s->device_index) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, s); - - s->state = STREAM_READY; - if (s->create_complete_callback) - s->create_complete_callback(s, 1, s->create_complete_userdata); -} - -static void create_stream(struct pa_stream *s, uint32_t tdev_index) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s); - - s->state = STREAM_CREATING; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, tdev_index); - pa_tagstruct_putu32(t, s->buffer_attr.maxlength); - if (s->direction == PA_STREAM_PLAYBACK) { - pa_tagstruct_putu32(t, s->buffer_attr.tlength); - pa_tagstruct_putu32(t, s->buffer_attr.prebuf); - pa_tagstruct_putu32(t, s->buffer_attr.minreq); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); -} - -static void lookup_device_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t tdev; - assert(pd && s && s->state == STREAM_LOOKING_UP); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &tdev) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - create_stream(s, tdev); -} - -static void lookup_device(struct pa_stream *s, const char *tdev) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s); - - s->state = STREAM_LOOKING_UP; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_LOOKUP_SINK : PA_COMMAND_LOOKUP_SOURCE); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, tdev); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, lookup_device_callback, s); -} - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata) { - - struct pa_stream *s; - - assert(c && name && ss && c->state == CONTEXT_READY); - - s = malloc(sizeof(struct pa_stream)); - assert(s); - s->context = c; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->die_callback = NULL; - s->die_userdata = NULL; - s->create_complete_callback = complete; - s->create_complete_userdata = NULL; - s->get_latency_callback = NULL; - s->get_latency_userdata = NULL; - - s->name = strdup(name); - s->state = STREAM_CREATING; - s->requested_bytes = 0; - s->channel = 0; - s->channel_valid = 0; - s->device_index = (uint32_t) -1; - s->direction = dir; - s->sample_spec = *ss; - if (attr) - s->buffer_attr = *attr; - else { - s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; - s->buffer_attr.tlength = DEFAULT_TLENGTH; - s->buffer_attr.prebuf = DEFAULT_PREBUF; - s->buffer_attr.minreq = DEFAULT_MINREQ; - s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; - } - - s->next = c->first_stream; - if (s->next) - s->next->previous = s; - s->previous = NULL; - c->first_stream = s; - - if (dev) - lookup_device(s, dev); - else - create_stream(s, (uint32_t) -1); - - return s; -} - -void pa_stream_free(struct pa_stream *s) { - assert(s && s->context); - - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - free(s->name); - - if (s->channel_valid && s->context->state == CONTEXT_READY) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, PA_COMMAND_DELETE_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - } - - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; - else - s->context->first_stream = s->next; - - free(s); -} - -void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { - struct pa_memchunk chunk; - assert(s && s->context && data && length && s->state == STREAM_READY); - - chunk.memblock = pa_memblock_new(length); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); - pa_memblock_unref(chunk.memblock); - - /*fprintf(stderr, "Sent %u bytes\n", length);*/ - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; -} - -size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s && s->state == STREAM_READY); - return s->requested_bytes; -} - -void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->read_callback = cb; - s->read_userdata = userdata; -} - -int pa_stream_is_dead(struct pa_stream *s) { - return s->state == STREAM_DEAD; -} - -int pa_stream_is_ready(struct pa_stream*s) { - return s->state == STREAM_READY; -} - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { - assert(s); - s->die_callback = cb; - s->die_userdata = userdata; -} - -int pa_context_is_pending(struct pa_context *c) { - assert(c); - - if (c->state != CONTEXT_READY) - return 0; - - return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); -} - -struct pa_context* pa_stream_get_context(struct pa_stream *p) { - assert(p); - return p->context; -} - -static void set_dispatch_callbacks(struct pa_context *c); - -static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void set_dispatch_callbacks(struct pa_context *c) { - assert(c && c->state == CONTEXT_READY); - - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(c->pdispatch)) { - pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); - return; - } - - if (pa_pstream_is_pending(c->pstream)) { - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - return; - } - - assert(c->drain_complete_callback); - c->drain_complete_callback(c, c->drain_complete_userdata); -} - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata) { - - assert(c && c->state == CONTEXT_READY); - - if (complete == NULL) { - c->drain_complete_callback = NULL; - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - return 0; - } - - if (!pa_context_is_pending(c)) - return -1; - - c->drain_complete_callback = complete; - c->drain_complete_userdata = userdata; - - set_dispatch_callbacks(c); - - return 0; -} - -static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - return; - } - - if (s->state != STREAM_READY) - return; - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->drain_complete_callback) { - void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; - s->drain_complete_callback = NULL; - temp(s, s->drain_complete_userdata); - } -} - - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s && s->state == STREAM_READY); - - if (!complete) { - s->drain_complete_callback = NULL; - return; - } - - s->drain_complete_callback = complete; - s->drain_complete_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); -} - -void pa_context_exit(struct pa_context *c) { - struct pa_tagstruct *t; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - uint32_t total, count; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &count) < 0 || - pa_tagstruct_getu32(t, &total) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, count, total, c->stat_userdata); -} - -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - c->stat_callback = cb; - c->stat_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_STAT); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); -} - -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t latency; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &latency) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, latency, s->get_latency_userdata); -} - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - p->get_latency_callback = cb; - p->get_latency_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); -} diff --git a/src/polyp.h b/src/polyp.h deleted file mode 100644 index 00849445..00000000 --- a/src/polyp.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef foopolyphfoo -#define foopolyphfoo - -#include - -#include "sample.h" -#include "polypdef.h" -#include "mainloop-api.h" - -struct pa_context; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); - -int pa_context_connect( - struct pa_context *c, - const char *server, - void (*complete) (struct pa_context*c, int success, void *userdata), - void *userdata); - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata); - -void pa_context_free(struct pa_context *c); - -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); - -int pa_context_is_dead(struct pa_context *c); -int pa_context_is_ready(struct pa_context *c); -int pa_context_errno(struct pa_context *c); - -int pa_context_is_pending(struct pa_context *c); - -void pa_context_exit(struct pa_context *c); -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); - -struct pa_stream; - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata); - -void pa_stream_free(struct pa_stream *p); - -void pa_stream_drain( - struct pa_stream *s, - void (*complete) (struct pa_stream*s, void *userdata), - void *userdata); - - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); - -void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); -void pa_stream_write(struct pa_stream *p, const void *data, size_t length); -size_t pa_stream_writable_size(struct pa_stream *p); - -void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); - -int pa_stream_is_dead(struct pa_stream *p); -int pa_stream_is_ready(struct pa_stream*p); - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); - -struct pa_context* pa_stream_get_context(struct pa_stream *p); - -#endif diff --git a/src/polypdef.h b/src/polypdef.h deleted file mode 100644 index 6cfafc97..00000000 --- a/src/polypdef.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef foopolypdefhfoo -#define foopolypdefhfoo - -#include - -enum pa_stream_direction { - PA_STREAM_PLAYBACK, - PA_STREAM_RECORD -}; - -struct pa_buffer_attr { - uint32_t maxlength; - uint32_t tlength; - uint32_t prebuf; - uint32_t minreq; - uint32_t fragsize; -}; - - -#endif diff --git a/src/polyplib-def.h b/src/polyplib-def.h new file mode 100644 index 00000000..6cfafc97 --- /dev/null +++ b/src/polyplib-def.h @@ -0,0 +1,20 @@ +#ifndef foopolypdefhfoo +#define foopolypdefhfoo + +#include + +enum pa_stream_direction { + PA_STREAM_PLAYBACK, + PA_STREAM_RECORD +}; + +struct pa_buffer_attr { + uint32_t maxlength; + uint32_t tlength; + uint32_t prebuf; + uint32_t minreq; + uint32_t fragsize; +}; + + +#endif diff --git a/src/polyplib-error.c b/src/polyplib-error.c new file mode 100644 index 00000000..86166b0c --- /dev/null +++ b/src/polyplib-error.c @@ -0,0 +1,28 @@ +#include +#include + +#include "polyp-error.h" +#include "protocol-native-spec.h" + +static const char* const errortab[PA_ERROR_MAX] = { + [PA_ERROR_OK] = "OK", + [PA_ERROR_ACCESS] = "Access denied", + [PA_ERROR_COMMAND] = "Unknown command", + [PA_ERROR_INVALID] = "Invalid argument", + [PA_ERROR_EXIST] = "Entity exists", + [PA_ERROR_NOENTITY] = "No such entity", + [PA_ERROR_CONNECTIONREFUSED] = "Connection refused", + [PA_ERROR_PROTOCOL] = "Protocol corrupt", + [PA_ERROR_TIMEOUT] = "Timeout", + [PA_ERROR_AUTHKEY] = "Not authorization key", + [PA_ERROR_INTERNAL] = "Internal error", + [PA_ERROR_CONNECTIONTERMINATED] = "Connection terminated", + [PA_ERROR_KILLED] = "Entity killed", +}; + +const char*pa_strerror(uint32_t error) { + if (error >= PA_ERROR_MAX) + return NULL; + + return errortab[error]; +} diff --git a/src/polyplib-error.h b/src/polyplib-error.h new file mode 100644 index 00000000..7407f34c --- /dev/null +++ b/src/polyplib-error.h @@ -0,0 +1,10 @@ +#ifndef foopolyperrhfoo +#define foopolyperrhfoo + +#include + +#include "protocol-native-spec.h" + +const char* pa_strerror(uint32_t error); + +#endif diff --git a/src/polyplib-simple.c b/src/polyplib-simple.c new file mode 100644 index 00000000..5f86c5bf --- /dev/null +++ b/src/polyplib-simple.c @@ -0,0 +1,233 @@ +#include +#include +#include +#include + +#include "simple.h" +#include "polyp.h" +#include "mainloop.h" +#include "polyp-error.h" + +struct pa_simple { + struct pa_mainloop *mainloop; + struct pa_context *context; + struct pa_stream *stream; + enum pa_stream_direction direction; + + int dead, drained; + + void *read_data; + size_t read_index, read_length; +}; + +static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata); + +static int check_error(struct pa_simple *p, int *perror) { + assert(p); + + if (pa_context_is_dead(p->context) || (p->stream && pa_stream_is_dead(p->stream))) { + if (perror) + *perror = pa_context_errno(p->context); + return -1; + } + + return 0; +} + +static int iterate(struct pa_simple *p, int block, int *perror) { + assert(p && p->context && p->mainloop); + + if (check_error(p, perror) < 0) + return -1; + + if (!block && !pa_context_is_pending(p->context)) + return 0; + + do { + if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) { + if (perror) + *perror = PA_ERROR_INTERNAL; + return -1; + } + + if (check_error(p, perror) < 0) + return -1; + + } while (pa_context_is_pending(p->context)); + + return 0; +} + +struct pa_simple* pa_simple_new( + const char *server, + const char *name, + enum pa_stream_direction dir, + const char *dev, + const char *stream_name, + const struct pa_sample_spec *ss, + const struct pa_buffer_attr *attr, + int *perror) { + + struct pa_simple *p; + int error = PA_ERROR_INTERNAL; + assert(ss); + + p = malloc(sizeof(struct pa_simple)); + assert(p); + p->context = NULL; + p->stream = NULL; + p->mainloop = pa_mainloop_new(); + assert(p->mainloop); + p->dead = 0; + p->direction = dir; + p->read_data = NULL; + p->read_index = p->read_length = 0; + + if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name))) + goto fail; + + if (pa_context_connect(p->context, server, NULL, NULL) < 0) { + error = pa_context_errno(p->context); + goto fail; + } + + /* Wait until the context is ready */ + while (!pa_context_is_ready(p->context)) { + if (iterate(p, 1, &error) < 0) + goto fail; + } + + if (!(p->stream = pa_stream_new(p->context, dir, dev, stream_name, ss, attr, NULL, NULL))) + goto fail; + + /* Wait until the stream is ready */ + while (!pa_stream_is_ready(p->stream)) { + if (iterate(p, 1, &error) < 0) + goto fail; + } + + pa_stream_set_read_callback(p->stream, read_callback, p); + + return p; + +fail: + if (perror) + *perror = error; + pa_simple_free(p); + return NULL; +} + +void pa_simple_free(struct pa_simple *s) { + assert(s); + + free(s->read_data); + + if (s->stream) + pa_stream_free(s->stream); + + if (s->context) + pa_context_free(s->context); + + if (s->mainloop) + pa_mainloop_free(s->mainloop); + + free(s); +} + +int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *perror) { + assert(p && data && p->direction == PA_STREAM_PLAYBACK); + + while (length > 0) { + size_t l; + + while (!(l = pa_stream_writable_size(p->stream))) + if (iterate(p, 1, perror) < 0) + return -1; + + if (l > length) + l = length; + + pa_stream_write(p->stream, data, l); + data += l; + length -= l; + } + + /* Make sure that no data is pending for write */ + if (iterate(p, 0, perror) < 0) + return -1; + + return 0; +} + +static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata) { + struct pa_simple *p = userdata; + assert(s && data && length && p); + + if (p->read_data) { + fprintf(stderr, __FILE__": Buffer overflow, dropping incoming memory blocks.\n"); + free(p->read_data); + } + + p->read_data = malloc(p->read_length = length); + assert(p->read_data); + memcpy(p->read_data, data, length); + p->read_index = 0; +} + +int pa_simple_read(struct pa_simple *p, void*data, size_t length, int *perror) { + assert(p && data && p->direction == PA_STREAM_RECORD); + + while (length > 0) { + if (p->read_data) { + size_t l = length; + + if (p->read_length <= l) + l = p->read_length; + + memcpy(data, p->read_data+p->read_index, l); + + data += l; + length -= l; + + p->read_index += l; + p->read_length -= l; + + if (!p->read_length) { + free(p->read_data); + p->read_data = NULL; + p->read_index = 0; + } + + if (!length) + return 0; + + assert(!p->read_data); + } + + if (iterate(p, 1, perror) < 0) + return -1; + } + + return 0; +} + +static void drain_complete(struct pa_stream *s, void *userdata) { + struct pa_simple *p = userdata; + assert(s && p); + p->drained = 1; +} + +int pa_simple_drain(struct pa_simple *p, int *perror) { + assert(p && p->direction == PA_STREAM_PLAYBACK); + p->drained = 0; + pa_stream_drain(p->stream, drain_complete, p); + + while (!p->drained) { + if (iterate(p, 1, perror) < 0) { + pa_stream_drain(p->stream, NULL, NULL); + return -1; + } + } + + return 0; +} diff --git a/src/polyplib-simple.h b/src/polyplib-simple.h new file mode 100644 index 00000000..f5f872ee --- /dev/null +++ b/src/polyplib-simple.h @@ -0,0 +1,28 @@ +#ifndef foosimplehfoo +#define foosimplehfoo + +#include + +#include "sample.h" +#include "polypdef.h" + +struct pa_simple; + +struct pa_simple* pa_simple_new( + const char *server, + const char *name, + enum pa_stream_direction dir, + const char *dev, + const char *stream_name, + const struct pa_sample_spec *ss, + const struct pa_buffer_attr *attr, + int *error); + +void pa_simple_free(struct pa_simple *s); + +int pa_simple_write(struct pa_simple *s, const void*data, size_t length, int *error); +int pa_simple_drain(struct pa_simple *s, int *error); + +int pa_simple_read(struct pa_simple *s, void*data, size_t length, int *error); + +#endif diff --git a/src/polyplib.c b/src/polyplib.c new file mode 100644 index 00000000..d6d0f908 --- /dev/null +++ b/src/polyplib.c @@ -0,0 +1,948 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "polyp.h" +#include "protocol-native-spec.h" +#include "pdispatch.h" +#include "pstream.h" +#include "dynarray.h" +#include "socket-client.h" +#include "pstream-util.h" +#include "authkey.h" +#include "util.h" + +#define DEFAULT_MAXLENGTH 204800 +#define DEFAULT_TLENGTH 10240 +#define DEFAULT_PREBUF 4096 +#define DEFAULT_MINREQ 1024 +#define DEFAULT_FRAGSIZE 1024 + +#define DEFAULT_TIMEOUT (5*60) +#define DEFAULT_SERVER "/tmp/polypaudio/native" +#define DEFAULT_PORT "4713" + +struct pa_context { + char *name; + struct pa_mainloop_api* mainloop; + struct pa_socket_client *client; + struct pa_pstream *pstream; + struct pa_pdispatch *pdispatch; + struct pa_dynarray *record_streams, *playback_streams; + struct pa_stream *first_stream; + uint32_t ctag; + uint32_t error; + enum { + CONTEXT_UNCONNECTED, + CONTEXT_CONNECTING, + CONTEXT_AUTHORIZING, + CONTEXT_SETTING_NAME, + CONTEXT_READY, + CONTEXT_DEAD + } state; + + void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); + void *connect_complete_userdata; + + void (*drain_complete_callback)(struct pa_context*c, void *userdata); + void *drain_complete_userdata; + + void (*die_callback)(struct pa_context*c, void *userdata); + void *die_userdata; + + void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); + void *stat_userdata; + + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; +}; + +struct pa_stream { + struct pa_context *context; + struct pa_stream *next, *previous; + + char *name; + struct pa_buffer_attr buffer_attr; + struct pa_sample_spec sample_spec; + uint32_t device_index; + uint32_t channel; + int channel_valid; + enum pa_stream_direction direction; + + enum { STREAM_LOOKING_UP, STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; + uint32_t requested_bytes; + + void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); + void *read_userdata; + + void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); + void *write_userdata; + + void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); + void *create_complete_userdata; + + void (*drain_complete_callback)(struct pa_stream *s, void *userdata); + void *drain_complete_userdata; + + void (*die_callback)(struct pa_stream*c, void *userdata); + void *die_userdata; + + void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); + void *get_latency_userdata; +}; + +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); + +static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = { NULL }, + [PA_COMMAND_REPLY] = { NULL }, + [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_EXIT] = { NULL }, + [PA_COMMAND_REQUEST] = { command_request }, + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, + [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, +}; + +struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { + struct pa_context *c; + assert(mainloop && name); + + c = malloc(sizeof(struct pa_context)); + assert(c); + c->name = strdup(name); + c->mainloop = mainloop; + c->client = NULL; + c->pstream = NULL; + c->pdispatch = NULL; + c->playback_streams = pa_dynarray_new(); + assert(c->playback_streams); + c->record_streams = pa_dynarray_new(); + assert(c->record_streams); + c->first_stream = NULL; + c->error = PA_ERROR_OK; + c->state = CONTEXT_UNCONNECTED; + c->ctag = 0; + + c->connect_complete_callback = NULL; + c->connect_complete_userdata = NULL; + + c->drain_complete_callback = NULL; + c->drain_complete_userdata = NULL; + + c->die_callback = NULL; + c->die_userdata = NULL; + + c->stat_callback = NULL; + c->stat_userdata = NULL; + + pa_check_for_sigpipe(); + return c; +} + +void pa_context_free(struct pa_context *c) { + assert(c); + + while (c->first_stream) + pa_stream_free(c->first_stream); + + if (c->client) + pa_socket_client_free(c->client); + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + if (c->pstream) + pa_pstream_free(c->pstream); + if (c->record_streams) + pa_dynarray_free(c->record_streams, NULL, NULL); + if (c->playback_streams) + pa_dynarray_free(c->playback_streams, NULL, NULL); + + free(c->name); + free(c); +} + +static void stream_dead(struct pa_stream *s) { + assert(s); + + if (s->state == STREAM_DEAD) + return; + + if (s->state == STREAM_READY) { + s->state = STREAM_DEAD; + if (s->die_callback) + s->die_callback(s, s->die_userdata); + } else + s->state = STREAM_DEAD; +} + +static void context_dead(struct pa_context *c) { + struct pa_stream *s; + assert(c); + + if (c->state == CONTEXT_DEAD) + return; + + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + c->pdispatch = NULL; + + if (c->pstream) + pa_pstream_free(c->pstream); + c->pstream = NULL; + + if (c->client) + pa_socket_client_free(c->client); + c->client = NULL; + + for (s = c->first_stream; s; s = s->next) + stream_dead(s); + + if (c->state == CONTEXT_READY) { + c->state = CONTEXT_DEAD; + if (c->die_callback) + c->die_callback(c, c->die_userdata); + } else + c->state = CONTEXT_DEAD; +} + +static void pstream_die_callback(struct pa_pstream *p, void *userdata) { + struct pa_context *c = userdata; + assert(p && c); + c->error = PA_ERROR_CONNECTIONTERMINATED; + context_dead(c); +} + +static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { + struct pa_context *c = userdata; + assert(p && packet && c); + + if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { + fprintf(stderr, "polyp.c: invalid packet.\n"); + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + } +} + +static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + assert(p && chunk && c && chunk->memblock && chunk->memblock->data); + + if (!(s = pa_dynarray_get(c->record_streams, channel))) + return; + + if (s->read_callback) + s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); +} + +static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { + assert(c && t); + + if (command == PA_COMMAND_ERROR) { + if (pa_tagstruct_getu32(t, &c->error) < 0) { + c->error = PA_ERROR_PROTOCOL; + return -1; + } + + return 0; + } + + c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; + return -1; +} + +static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); + + if (command != PA_COMMAND_REPLY) { + handle_error(c, command, t); + context_dead(c); + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return; + } + + if (c->state == CONTEXT_AUTHORIZING) { + struct pa_tagstruct *t; + c->state = CONTEXT_SETTING_NAME; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, c->name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + } else { + assert(c->state == CONTEXT_SETTING_NAME); + + c->state = CONTEXT_READY; + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 1, c->connect_complete_userdata); + } + + return; +} + +static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { + struct pa_context *c = userdata; + struct pa_tagstruct *t; + uint32_t tag; + assert(client && c && c->state == CONTEXT_CONNECTING); + + pa_socket_client_free(client); + c->client = NULL; + + if (!io) { + c->error = PA_ERROR_CONNECTIONREFUSED; + context_dead(c); + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return; + } + + c->pstream = pa_pstream_new(c->mainloop, io); + assert(c->pstream); + pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); + pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); + pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); + + c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); + assert(c->pdispatch); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_AUTH); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + c->state = CONTEXT_AUTHORIZING; +} + +static struct sockaddr *resolve_server(const char *server, size_t *len) { + struct sockaddr *sa; + struct addrinfo hints, *result = NULL; + char *port; + assert(server && len); + + if ((port = strrchr(server, ':'))) + port++; + if (!port) + port = DEFAULT_PORT; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + if (getaddrinfo(server, port, &hints, &result) != 0) + return NULL; + assert(result); + + sa = malloc(*len = result->ai_addrlen); + assert(sa); + memcpy(sa, result->ai_addr, *len); + + freeaddrinfo(result); + + return sa; + +} + +int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { + assert(c && c->state == CONTEXT_UNCONNECTED); + + if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { + c->error = PA_ERROR_AUTHKEY; + return -1; + } + + if (!server) + if (!(server = getenv("POLYP_SERVER"))) + server = DEFAULT_SERVER; + + assert(!c->client); + + if (*server == '/') { + if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + } else { + struct sockaddr* sa; + size_t sa_len; + + if (!(sa = resolve_server(server, &sa_len))) { + c->error = PA_ERROR_INVALIDSERVER; + return -1; + } + + c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); + free(sa); + + if (!c->client) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + } + + c->connect_complete_callback = complete; + c->connect_complete_userdata = userdata; + + pa_socket_client_set_callback(c->client, on_connection, c); + c->state = CONTEXT_CONNECTING; + + return 0; +} + +int pa_context_is_dead(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_DEAD; +} + +int pa_context_is_ready(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_READY; +} + +int pa_context_errno(struct pa_context *c) { + assert(c); + return c->error; +} + +void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { + assert(c); + c->die_callback = cb; + c->die_userdata = userdata; +} + +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + uint32_t channel; + assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) + return; + + c->error = PA_ERROR_KILLED; + stream_dead(s); +} + +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s; + struct pa_context *c = userdata; + uint32_t bytes, channel; + assert(pd && command == PA_COMMAND_REQUEST && t && c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + pa_tagstruct_getu32(t, &bytes) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (!(s = pa_dynarray_get(c->playback_streams, channel))) + return; + + if (s->state != STREAM_READY) + return; + + s->requested_bytes += bytes; + + if (s->requested_bytes && s->write_callback) + s->write_callback(s, s->requested_bytes, s->write_userdata); +} + +static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s && s->state == STREAM_CREATING); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + if (s->create_complete_callback) + s->create_complete_callback(s, 0, s->create_complete_userdata); + + return; + } + + if (pa_tagstruct_getu32(t, &s->channel) < 0 || + pa_tagstruct_getu32(t, &s->device_index) < 0 || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + s->channel_valid = 1; + pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, s); + + s->state = STREAM_READY; + if (s->create_complete_callback) + s->create_complete_callback(s, 1, s->create_complete_userdata); +} + +static void create_stream(struct pa_stream *s, uint32_t tdev_index) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s); + + s->state = STREAM_CREATING; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_puts(t, s->name); + pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_putu32(t, tdev_index); + pa_tagstruct_putu32(t, s->buffer_attr.maxlength); + if (s->direction == PA_STREAM_PLAYBACK) { + pa_tagstruct_putu32(t, s->buffer_attr.tlength); + pa_tagstruct_putu32(t, s->buffer_attr.prebuf); + pa_tagstruct_putu32(t, s->buffer_attr.minreq); + } else + pa_tagstruct_putu32(t, s->buffer_attr.fragsize); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); +} + +static void lookup_device_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + uint32_t tdev; + assert(pd && s && s->state == STREAM_LOOKING_UP); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + if (s->create_complete_callback) + s->create_complete_callback(s, 0, s->create_complete_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &tdev) < 0 || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + create_stream(s, tdev); +} + +static void lookup_device(struct pa_stream *s, const char *tdev) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s); + + s->state = STREAM_LOOKING_UP; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_LOOKUP_SINK : PA_COMMAND_LOOKUP_SOURCE); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_puts(t, tdev); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, lookup_device_callback, s); +} + +struct pa_stream* pa_stream_new( + struct pa_context *c, + enum pa_stream_direction dir, + const char *dev, + const char *name, + const struct pa_sample_spec *ss, + const struct pa_buffer_attr *attr, + void (*complete) (struct pa_stream*s, int success, void *userdata), + void *userdata) { + + struct pa_stream *s; + + assert(c && name && ss && c->state == CONTEXT_READY); + + s = malloc(sizeof(struct pa_stream)); + assert(s); + s->context = c; + + s->read_callback = NULL; + s->read_userdata = NULL; + s->write_callback = NULL; + s->write_userdata = NULL; + s->die_callback = NULL; + s->die_userdata = NULL; + s->create_complete_callback = complete; + s->create_complete_userdata = NULL; + s->get_latency_callback = NULL; + s->get_latency_userdata = NULL; + + s->name = strdup(name); + s->state = STREAM_CREATING; + s->requested_bytes = 0; + s->channel = 0; + s->channel_valid = 0; + s->device_index = (uint32_t) -1; + s->direction = dir; + s->sample_spec = *ss; + if (attr) + s->buffer_attr = *attr; + else { + s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; + s->buffer_attr.tlength = DEFAULT_TLENGTH; + s->buffer_attr.prebuf = DEFAULT_PREBUF; + s->buffer_attr.minreq = DEFAULT_MINREQ; + s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; + } + + s->next = c->first_stream; + if (s->next) + s->next->previous = s; + s->previous = NULL; + c->first_stream = s; + + if (dev) + lookup_device(s, dev); + else + create_stream(s, (uint32_t) -1); + + return s; +} + +void pa_stream_free(struct pa_stream *s) { + assert(s && s->context); + + if (s->context->pdispatch) + pa_pdispatch_unregister_reply(s->context->pdispatch, s); + + free(s->name); + + if (s->channel_valid && s->context->state == CONTEXT_READY) { + struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, PA_COMMAND_DELETE_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + } + + if (s->channel_valid) + pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); + + if (s->next) + s->next->previous = s->previous; + if (s->previous) + s->previous->next = s->next; + else + s->context->first_stream = s->next; + + free(s); +} + +void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { + assert(s && cb); + s->write_callback = cb; + s->write_userdata = userdata; +} + +void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { + struct pa_memchunk chunk; + assert(s && s->context && data && length && s->state == STREAM_READY); + + chunk.memblock = pa_memblock_new(length); + assert(chunk.memblock && chunk.memblock->data); + memcpy(chunk.memblock->data, data, length); + chunk.index = 0; + chunk.length = length; + + pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); + pa_memblock_unref(chunk.memblock); + + /*fprintf(stderr, "Sent %u bytes\n", length);*/ + + if (length < s->requested_bytes) + s->requested_bytes -= length; + else + s->requested_bytes = 0; +} + +size_t pa_stream_writable_size(struct pa_stream *s) { + assert(s && s->state == STREAM_READY); + return s->requested_bytes; +} + +void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { + assert(s && cb); + s->read_callback = cb; + s->read_userdata = userdata; +} + +int pa_stream_is_dead(struct pa_stream *s) { + return s->state == STREAM_DEAD; +} + +int pa_stream_is_ready(struct pa_stream*s) { + return s->state == STREAM_READY; +} + +void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { + assert(s); + s->die_callback = cb; + s->die_userdata = userdata; +} + +int pa_context_is_pending(struct pa_context *c) { + assert(c); + + if (c->state != CONTEXT_READY) + return 0; + + return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); +} + +struct pa_context* pa_stream_get_context(struct pa_stream *p) { + assert(p); + return p->context; +} + +static void set_dispatch_callbacks(struct pa_context *c); + +static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void set_dispatch_callbacks(struct pa_context *c) { + assert(c && c->state == CONTEXT_READY); + + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + + if (pa_pdispatch_is_pending(c->pdispatch)) { + pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); + return; + } + + if (pa_pstream_is_pending(c->pstream)) { + pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); + return; + } + + assert(c->drain_complete_callback); + c->drain_complete_callback(c, c->drain_complete_userdata); +} + +int pa_context_drain( + struct pa_context *c, + void (*complete) (struct pa_context*c, void *userdata), + void *userdata) { + + assert(c && c->state == CONTEXT_READY); + + if (complete == NULL) { + c->drain_complete_callback = NULL; + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + return 0; + } + + if (!pa_context_is_pending(c)) + return -1; + + c->drain_complete_callback = complete; + c->drain_complete_userdata = userdata; + + set_dispatch_callbacks(c); + + return 0; +} + +static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + return; + } + + if (s->state != STREAM_READY) + return; + + if (!pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->drain_complete_callback) { + void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; + s->drain_complete_callback = NULL; + temp(s, s->drain_complete_userdata); + } +} + + +void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s && s->state == STREAM_READY); + + if (!complete) { + s->drain_complete_callback = NULL; + return; + } + + s->drain_complete_callback = complete; + s->drain_complete_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); +} + +void pa_context_exit(struct pa_context *c) { + struct pa_tagstruct *t; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_EXIT); + pa_tagstruct_putu32(t, c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + uint32_t total, count; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &count) < 0 || + pa_tagstruct_getu32(t, &total) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, count, total, c->stat_userdata); +} + +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + c->stat_callback = cb; + c->stat_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_STAT); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); +} + +static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + uint32_t latency; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &latency) < 0 || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, latency, s->get_latency_userdata); +} + +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + p->get_latency_callback = cb; + p->get_latency_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); + pa_tagstruct_putu32(t, tag = p->context->ctag++); + pa_tagstruct_putu32(t, p->channel); + pa_pstream_send_tagstruct(p->context->pstream, t); + pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); +} diff --git a/src/polyplib.h b/src/polyplib.h new file mode 100644 index 00000000..00849445 --- /dev/null +++ b/src/polyplib.h @@ -0,0 +1,73 @@ +#ifndef foopolyphfoo +#define foopolyphfoo + +#include + +#include "sample.h" +#include "polypdef.h" +#include "mainloop-api.h" + +struct pa_context; + +struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); + +int pa_context_connect( + struct pa_context *c, + const char *server, + void (*complete) (struct pa_context*c, int success, void *userdata), + void *userdata); + +int pa_context_drain( + struct pa_context *c, + void (*complete) (struct pa_context*c, void *userdata), + void *userdata); + +void pa_context_free(struct pa_context *c); + +void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); + +int pa_context_is_dead(struct pa_context *c); +int pa_context_is_ready(struct pa_context *c); +int pa_context_errno(struct pa_context *c); + +int pa_context_is_pending(struct pa_context *c); + +void pa_context_exit(struct pa_context *c); +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); + +struct pa_stream; + +struct pa_stream* pa_stream_new( + struct pa_context *c, + enum pa_stream_direction dir, + const char *dev, + const char *name, + const struct pa_sample_spec *ss, + const struct pa_buffer_attr *attr, + void (*complete) (struct pa_stream*s, int success, void *userdata), + void *userdata); + +void pa_stream_free(struct pa_stream *p); + +void pa_stream_drain( + struct pa_stream *s, + void (*complete) (struct pa_stream*s, void *userdata), + void *userdata); + + +void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); + +void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); +void pa_stream_write(struct pa_stream *p, const void *data, size_t length); +size_t pa_stream_writable_size(struct pa_stream *p); + +void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); + +int pa_stream_is_dead(struct pa_stream *p); +int pa_stream_is_ready(struct pa_stream*p); + +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); + +struct pa_context* pa_stream_get_context(struct pa_stream *p); + +#endif diff --git a/src/protocol-native-spec.h b/src/protocol-native-spec.h deleted file mode 100644 index e1db6f64..00000000 --- a/src/protocol-native-spec.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef fooprotocolnativespech -#define fooprotocolnativespech - -enum { - PA_COMMAND_ERROR, - PA_COMMAND_TIMEOUT, /* pseudo command */ - PA_COMMAND_REPLY, - PA_COMMAND_CREATE_PLAYBACK_STREAM, - PA_COMMAND_DELETE_PLAYBACK_STREAM, - PA_COMMAND_CREATE_RECORD_STREAM, - PA_COMMAND_DELETE_RECORD_STREAM, - PA_COMMAND_EXIT, - PA_COMMAND_REQUEST, - PA_COMMAND_AUTH, - PA_COMMAND_SET_NAME, - PA_COMMAND_LOOKUP_SINK, - PA_COMMAND_LOOKUP_SOURCE, - PA_COMMAND_DRAIN_PLAYBACK_STREAM, - PA_COMMAND_PLAYBACK_STREAM_KILLED, - PA_COMMAND_RECORD_STREAM_KILLED, - PA_COMMAND_STAT, - PA_COMMAND_GET_PLAYBACK_LATENCY, - PA_COMMAND_MAX -}; - -enum { - PA_ERROR_OK, - PA_ERROR_ACCESS, - PA_ERROR_COMMAND, - PA_ERROR_INVALID, - PA_ERROR_EXIST, - PA_ERROR_NOENTITY, - PA_ERROR_CONNECTIONREFUSED, - PA_ERROR_PROTOCOL, - PA_ERROR_TIMEOUT, - PA_ERROR_AUTHKEY, - PA_ERROR_INTERNAL, - PA_ERROR_CONNECTIONTERMINATED, - PA_ERROR_KILLED, - PA_ERROR_INVALIDSERVER, - PA_ERROR_MAX -}; - -#define PA_NATIVE_COOKIE_LENGTH 256 -#define PA_NATIVE_COOKIE_FILE ".polypaudio-cookie" - -#endif diff --git a/src/simple.c b/src/simple.c deleted file mode 100644 index 5f86c5bf..00000000 --- a/src/simple.c +++ /dev/null @@ -1,233 +0,0 @@ -#include -#include -#include -#include - -#include "simple.h" -#include "polyp.h" -#include "mainloop.h" -#include "polyp-error.h" - -struct pa_simple { - struct pa_mainloop *mainloop; - struct pa_context *context; - struct pa_stream *stream; - enum pa_stream_direction direction; - - int dead, drained; - - void *read_data; - size_t read_index, read_length; -}; - -static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata); - -static int check_error(struct pa_simple *p, int *perror) { - assert(p); - - if (pa_context_is_dead(p->context) || (p->stream && pa_stream_is_dead(p->stream))) { - if (perror) - *perror = pa_context_errno(p->context); - return -1; - } - - return 0; -} - -static int iterate(struct pa_simple *p, int block, int *perror) { - assert(p && p->context && p->mainloop); - - if (check_error(p, perror) < 0) - return -1; - - if (!block && !pa_context_is_pending(p->context)) - return 0; - - do { - if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) { - if (perror) - *perror = PA_ERROR_INTERNAL; - return -1; - } - - if (check_error(p, perror) < 0) - return -1; - - } while (pa_context_is_pending(p->context)); - - return 0; -} - -struct pa_simple* pa_simple_new( - const char *server, - const char *name, - enum pa_stream_direction dir, - const char *dev, - const char *stream_name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - int *perror) { - - struct pa_simple *p; - int error = PA_ERROR_INTERNAL; - assert(ss); - - p = malloc(sizeof(struct pa_simple)); - assert(p); - p->context = NULL; - p->stream = NULL; - p->mainloop = pa_mainloop_new(); - assert(p->mainloop); - p->dead = 0; - p->direction = dir; - p->read_data = NULL; - p->read_index = p->read_length = 0; - - if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name))) - goto fail; - - if (pa_context_connect(p->context, server, NULL, NULL) < 0) { - error = pa_context_errno(p->context); - goto fail; - } - - /* Wait until the context is ready */ - while (!pa_context_is_ready(p->context)) { - if (iterate(p, 1, &error) < 0) - goto fail; - } - - if (!(p->stream = pa_stream_new(p->context, dir, dev, stream_name, ss, attr, NULL, NULL))) - goto fail; - - /* Wait until the stream is ready */ - while (!pa_stream_is_ready(p->stream)) { - if (iterate(p, 1, &error) < 0) - goto fail; - } - - pa_stream_set_read_callback(p->stream, read_callback, p); - - return p; - -fail: - if (perror) - *perror = error; - pa_simple_free(p); - return NULL; -} - -void pa_simple_free(struct pa_simple *s) { - assert(s); - - free(s->read_data); - - if (s->stream) - pa_stream_free(s->stream); - - if (s->context) - pa_context_free(s->context); - - if (s->mainloop) - pa_mainloop_free(s->mainloop); - - free(s); -} - -int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *perror) { - assert(p && data && p->direction == PA_STREAM_PLAYBACK); - - while (length > 0) { - size_t l; - - while (!(l = pa_stream_writable_size(p->stream))) - if (iterate(p, 1, perror) < 0) - return -1; - - if (l > length) - l = length; - - pa_stream_write(p->stream, data, l); - data += l; - length -= l; - } - - /* Make sure that no data is pending for write */ - if (iterate(p, 0, perror) < 0) - return -1; - - return 0; -} - -static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata) { - struct pa_simple *p = userdata; - assert(s && data && length && p); - - if (p->read_data) { - fprintf(stderr, __FILE__": Buffer overflow, dropping incoming memory blocks.\n"); - free(p->read_data); - } - - p->read_data = malloc(p->read_length = length); - assert(p->read_data); - memcpy(p->read_data, data, length); - p->read_index = 0; -} - -int pa_simple_read(struct pa_simple *p, void*data, size_t length, int *perror) { - assert(p && data && p->direction == PA_STREAM_RECORD); - - while (length > 0) { - if (p->read_data) { - size_t l = length; - - if (p->read_length <= l) - l = p->read_length; - - memcpy(data, p->read_data+p->read_index, l); - - data += l; - length -= l; - - p->read_index += l; - p->read_length -= l; - - if (!p->read_length) { - free(p->read_data); - p->read_data = NULL; - p->read_index = 0; - } - - if (!length) - return 0; - - assert(!p->read_data); - } - - if (iterate(p, 1, perror) < 0) - return -1; - } - - return 0; -} - -static void drain_complete(struct pa_stream *s, void *userdata) { - struct pa_simple *p = userdata; - assert(s && p); - p->drained = 1; -} - -int pa_simple_drain(struct pa_simple *p, int *perror) { - assert(p && p->direction == PA_STREAM_PLAYBACK); - p->drained = 0; - pa_stream_drain(p->stream, drain_complete, p); - - while (!p->drained) { - if (iterate(p, 1, perror) < 0) { - pa_stream_drain(p->stream, NULL, NULL); - return -1; - } - } - - return 0; -} diff --git a/src/simple.h b/src/simple.h deleted file mode 100644 index f5f872ee..00000000 --- a/src/simple.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef foosimplehfoo -#define foosimplehfoo - -#include - -#include "sample.h" -#include "polypdef.h" - -struct pa_simple; - -struct pa_simple* pa_simple_new( - const char *server, - const char *name, - enum pa_stream_direction dir, - const char *dev, - const char *stream_name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - int *error); - -void pa_simple_free(struct pa_simple *s); - -int pa_simple_write(struct pa_simple *s, const void*data, size_t length, int *error); -int pa_simple_drain(struct pa_simple *s, int *error); - -int pa_simple_read(struct pa_simple *s, void*data, size_t length, int *error); - -#endif diff --git a/src/sink-input.c b/src/sink-input.c new file mode 100644 index 00000000..54778a81 --- /dev/null +++ b/src/sink-input.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include + +#include "sinkinput.h" +#include "sample-util.h" + +#define CONVERT_BUFFER_LENGTH 4096 + +struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec) { + struct pa_sink_input *i; + struct pa_resampler *resampler = NULL; + int r; + char st[256]; + assert(s && spec); + + if (!pa_sample_spec_equal(spec, &s->sample_spec)) + if (!(resampler = pa_resampler_new(spec, &s->sample_spec))) + return NULL; + + i = malloc(sizeof(struct pa_sink_input)); + assert(i); + i->name = name ? strdup(name) : NULL; + i->client = NULL; + i->owner = NULL; + i->sink = s; + i->sample_spec = *spec; + + i->peek = NULL; + i->drop = NULL; + i->kill = NULL; + i->get_latency = NULL; + i->userdata = NULL; + + i->volume = PA_VOLUME_NORM; + + i->resampled_chunk.memblock = NULL; + i->resampled_chunk.index = i->resampled_chunk.length = 0; + i->resampler = resampler; + + assert(s->core); + r = pa_idxset_put(s->core->sink_inputs, i, &i->index); + assert(r == 0 && i->index != PA_IDXSET_INVALID); + r = pa_idxset_put(s->inputs, i, NULL); + assert(r == 0); + + pa_sample_snprint(st, sizeof(st), spec); + fprintf(stderr, "sink-input: created %u \"%s\" on %u with sample spec \"%s\"\n", i->index, i->name, s->index, st); + + return i; +} + +void pa_sink_input_free(struct pa_sink_input* i) { + assert(i); + + assert(i->sink && i->sink->core); + pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); + pa_idxset_remove_by_data(i->sink->inputs, i, NULL); + + if (i->resampled_chunk.memblock) + pa_memblock_unref(i->resampled_chunk.memblock); + if (i->resampler) + pa_resampler_free(i->resampler); + + free(i->name); + free(i); +} + +void pa_sink_input_kill(struct pa_sink_input*i) { + assert(i); + + if (i->kill) + i->kill(i); +} + +uint32_t pa_sink_input_get_latency(struct pa_sink_input *i) { + uint32_t l = 0; + + assert(i); + if (i->get_latency) + l += i->get_latency(i); + + assert(i->sink); + l += pa_sink_get_latency(i->sink); + + return l; +} + +int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { + assert(i && chunk && i->peek && i->drop); + + if (!i->resampler) + return i->peek(i, chunk); + + if (!i->resampled_chunk.memblock) { + struct pa_memchunk tchunk; + size_t l; + int ret; + + if ((ret = i->peek(i, &tchunk)) < 0) + return ret; + + l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); + if (tchunk.length > l) + tchunk.length = l; + + i->drop(i, tchunk.length); + + pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk); + pa_memblock_unref(tchunk.memblock); + } + + assert(i->resampled_chunk.memblock && i->resampled_chunk.length); + *chunk = i->resampled_chunk; + pa_memblock_ref(i->resampled_chunk.memblock); + return 0; +} + +void pa_sink_input_drop(struct pa_sink_input *i, size_t length) { + assert(i && length); + + if (!i->resampler) { + i->drop(i, length); + return; + } + + assert(i->resampled_chunk.memblock && i->resampled_chunk.length >= length); + + i->resampled_chunk.index += length; + i->resampled_chunk.length -= length; + + if (!i->resampled_chunk.length) { + pa_memblock_unref(i->resampled_chunk.memblock); + i->resampled_chunk.memblock = NULL; + i->resampled_chunk.index = i->resampled_chunk.length = 0; + } +} diff --git a/src/sink-input.h b/src/sink-input.h new file mode 100644 index 00000000..02a2a117 --- /dev/null +++ b/src/sink-input.h @@ -0,0 +1,46 @@ +#ifndef foosinkinputhfoo +#define foosinkinputhfoo + +#include + +#include "sink.h" +#include "sample.h" +#include "memblockq.h" +#include "resampler.h" +#include "module.h" +#include "client.h" + +struct pa_sink_input { + uint32_t index; + + char *name; + struct pa_module *owner; + struct pa_client *client; + struct pa_sink *sink; + struct pa_sample_spec sample_spec; + uint32_t volume; + + int (*peek) (struct pa_sink_input *i, struct pa_memchunk *chunk); + void (*drop) (struct pa_sink_input *i, size_t length); + void (*kill) (struct pa_sink_input *i); + uint32_t (*get_latency) (struct pa_sink_input *i); + + void *userdata; + + struct pa_memchunk resampled_chunk; + struct pa_resampler *resampler; +}; + +struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec); +void pa_sink_input_free(struct pa_sink_input* i); + +/* Code that didn't create the input stream should call this function to + * request destruction of it */ +void pa_sink_input_kill(struct pa_sink_input *i); + +uint32_t pa_sink_input_get_latency(struct pa_sink_input *i); + +int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk); +void pa_sink_input_drop(struct pa_sink_input *i, size_t length); + +#endif diff --git a/src/sinkinput.c b/src/sinkinput.c deleted file mode 100644 index 54778a81..00000000 --- a/src/sinkinput.c +++ /dev/null @@ -1,138 +0,0 @@ -#include -#include -#include -#include - -#include "sinkinput.h" -#include "sample-util.h" - -#define CONVERT_BUFFER_LENGTH 4096 - -struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec) { - struct pa_sink_input *i; - struct pa_resampler *resampler = NULL; - int r; - char st[256]; - assert(s && spec); - - if (!pa_sample_spec_equal(spec, &s->sample_spec)) - if (!(resampler = pa_resampler_new(spec, &s->sample_spec))) - return NULL; - - i = malloc(sizeof(struct pa_sink_input)); - assert(i); - i->name = name ? strdup(name) : NULL; - i->client = NULL; - i->owner = NULL; - i->sink = s; - i->sample_spec = *spec; - - i->peek = NULL; - i->drop = NULL; - i->kill = NULL; - i->get_latency = NULL; - i->userdata = NULL; - - i->volume = PA_VOLUME_NORM; - - i->resampled_chunk.memblock = NULL; - i->resampled_chunk.index = i->resampled_chunk.length = 0; - i->resampler = resampler; - - assert(s->core); - r = pa_idxset_put(s->core->sink_inputs, i, &i->index); - assert(r == 0 && i->index != PA_IDXSET_INVALID); - r = pa_idxset_put(s->inputs, i, NULL); - assert(r == 0); - - pa_sample_snprint(st, sizeof(st), spec); - fprintf(stderr, "sink-input: created %u \"%s\" on %u with sample spec \"%s\"\n", i->index, i->name, s->index, st); - - return i; -} - -void pa_sink_input_free(struct pa_sink_input* i) { - assert(i); - - assert(i->sink && i->sink->core); - pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); - pa_idxset_remove_by_data(i->sink->inputs, i, NULL); - - if (i->resampled_chunk.memblock) - pa_memblock_unref(i->resampled_chunk.memblock); - if (i->resampler) - pa_resampler_free(i->resampler); - - free(i->name); - free(i); -} - -void pa_sink_input_kill(struct pa_sink_input*i) { - assert(i); - - if (i->kill) - i->kill(i); -} - -uint32_t pa_sink_input_get_latency(struct pa_sink_input *i) { - uint32_t l = 0; - - assert(i); - if (i->get_latency) - l += i->get_latency(i); - - assert(i->sink); - l += pa_sink_get_latency(i->sink); - - return l; -} - -int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { - assert(i && chunk && i->peek && i->drop); - - if (!i->resampler) - return i->peek(i, chunk); - - if (!i->resampled_chunk.memblock) { - struct pa_memchunk tchunk; - size_t l; - int ret; - - if ((ret = i->peek(i, &tchunk)) < 0) - return ret; - - l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); - if (tchunk.length > l) - tchunk.length = l; - - i->drop(i, tchunk.length); - - pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk); - pa_memblock_unref(tchunk.memblock); - } - - assert(i->resampled_chunk.memblock && i->resampled_chunk.length); - *chunk = i->resampled_chunk; - pa_memblock_ref(i->resampled_chunk.memblock); - return 0; -} - -void pa_sink_input_drop(struct pa_sink_input *i, size_t length) { - assert(i && length); - - if (!i->resampler) { - i->drop(i, length); - return; - } - - assert(i->resampled_chunk.memblock && i->resampled_chunk.length >= length); - - i->resampled_chunk.index += length; - i->resampled_chunk.length -= length; - - if (!i->resampled_chunk.length) { - pa_memblock_unref(i->resampled_chunk.memblock); - i->resampled_chunk.memblock = NULL; - i->resampled_chunk.index = i->resampled_chunk.length = 0; - } -} diff --git a/src/sinkinput.h b/src/sinkinput.h deleted file mode 100644 index 02a2a117..00000000 --- a/src/sinkinput.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef foosinkinputhfoo -#define foosinkinputhfoo - -#include - -#include "sink.h" -#include "sample.h" -#include "memblockq.h" -#include "resampler.h" -#include "module.h" -#include "client.h" - -struct pa_sink_input { - uint32_t index; - - char *name; - struct pa_module *owner; - struct pa_client *client; - struct pa_sink *sink; - struct pa_sample_spec sample_spec; - uint32_t volume; - - int (*peek) (struct pa_sink_input *i, struct pa_memchunk *chunk); - void (*drop) (struct pa_sink_input *i, size_t length); - void (*kill) (struct pa_sink_input *i); - uint32_t (*get_latency) (struct pa_sink_input *i); - - void *userdata; - - struct pa_memchunk resampled_chunk; - struct pa_resampler *resampler; -}; - -struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec); -void pa_sink_input_free(struct pa_sink_input* i); - -/* Code that didn't create the input stream should call this function to - * request destruction of it */ -void pa_sink_input_kill(struct pa_sink_input *i); - -uint32_t pa_sink_input_get_latency(struct pa_sink_input *i); - -int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk); -void pa_sink_input_drop(struct pa_sink_input *i, size_t length); - -#endif diff --git a/src/source-output.c b/src/source-output.c new file mode 100644 index 00000000..25c661a9 --- /dev/null +++ b/src/source-output.c @@ -0,0 +1,76 @@ +#include +#include +#include + +#include "sourceoutput.h" + +struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec) { + struct pa_source_output *o; + struct pa_resampler *resampler = NULL; + int r; + assert(s && spec); + + if (!pa_sample_spec_equal(&s->sample_spec, spec)) + if (!(resampler = pa_resampler_new(&s->sample_spec, spec))) + return NULL; + + o = malloc(sizeof(struct pa_source_output)); + assert(o); + o->name = name ? strdup(name) : NULL; + o->client = NULL; + o->owner = NULL; + o->source = s; + o->sample_spec = *spec; + + o->push = NULL; + o->kill = NULL; + o->userdata = NULL; + o->resampler = resampler; + + assert(s->core); + r = pa_idxset_put(s->core->source_outputs, o, &o->index); + assert(r == 0 && o->index != PA_IDXSET_INVALID); + r = pa_idxset_put(s->outputs, o, NULL); + assert(r == 0); + + return o; +} + +void pa_source_output_free(struct pa_source_output* o) { + assert(o); + + assert(o->source && o->source->core); + pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); + pa_idxset_remove_by_data(o->source->outputs, o, NULL); + + if (o->resampler) + pa_resampler_free(o->resampler); + + free(o->name); + free(o); +} + +void pa_source_output_kill(struct pa_source_output*i) { + assert(i); + + if (i->kill) + i->kill(i); +} + +void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk *chunk) { + struct pa_memchunk rchunk; + assert(o && chunk && chunk->length && o->push); + + if (!o->resampler) { + o->push(o, chunk); + return; + } + + pa_resampler_run(o->resampler, chunk, &rchunk); + if (!rchunk.length) + return; + + assert(rchunk.memblock); + o->push(o, &rchunk); + pa_memblock_unref(rchunk.memblock); +} diff --git a/src/source-output.h b/src/source-output.h new file mode 100644 index 00000000..a8ea5a9f --- /dev/null +++ b/src/source-output.h @@ -0,0 +1,37 @@ +#ifndef foosourceoutputhfoo +#define foosourceoutputhfoo + +#include + +#include "source.h" +#include "sample.h" +#include "memblockq.h" +#include "resampler.h" +#include "module.h" +#include "client.h" + +struct pa_source_output { + uint32_t index; + + char *name; + struct pa_module *owner; + struct pa_client *client; + struct pa_source *source; + struct pa_sample_spec sample_spec; + + void (*push)(struct pa_source_output *o, const struct pa_memchunk *chunk); + void (*kill)(struct pa_source_output* o); + + struct pa_resampler* resampler; + + void *userdata; +}; + +struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec); +void pa_source_output_free(struct pa_source_output* o); + +void pa_source_output_kill(struct pa_source_output*o); + +void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk *chunk); + +#endif diff --git a/src/sourceoutput.c b/src/sourceoutput.c deleted file mode 100644 index 25c661a9..00000000 --- a/src/sourceoutput.c +++ /dev/null @@ -1,76 +0,0 @@ -#include -#include -#include - -#include "sourceoutput.h" - -struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec) { - struct pa_source_output *o; - struct pa_resampler *resampler = NULL; - int r; - assert(s && spec); - - if (!pa_sample_spec_equal(&s->sample_spec, spec)) - if (!(resampler = pa_resampler_new(&s->sample_spec, spec))) - return NULL; - - o = malloc(sizeof(struct pa_source_output)); - assert(o); - o->name = name ? strdup(name) : NULL; - o->client = NULL; - o->owner = NULL; - o->source = s; - o->sample_spec = *spec; - - o->push = NULL; - o->kill = NULL; - o->userdata = NULL; - o->resampler = resampler; - - assert(s->core); - r = pa_idxset_put(s->core->source_outputs, o, &o->index); - assert(r == 0 && o->index != PA_IDXSET_INVALID); - r = pa_idxset_put(s->outputs, o, NULL); - assert(r == 0); - - return o; -} - -void pa_source_output_free(struct pa_source_output* o) { - assert(o); - - assert(o->source && o->source->core); - pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); - pa_idxset_remove_by_data(o->source->outputs, o, NULL); - - if (o->resampler) - pa_resampler_free(o->resampler); - - free(o->name); - free(o); -} - -void pa_source_output_kill(struct pa_source_output*i) { - assert(i); - - if (i->kill) - i->kill(i); -} - -void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk *chunk) { - struct pa_memchunk rchunk; - assert(o && chunk && chunk->length && o->push); - - if (!o->resampler) { - o->push(o, chunk); - return; - } - - pa_resampler_run(o->resampler, chunk, &rchunk); - if (!rchunk.length) - return; - - assert(rchunk.memblock); - o->push(o, &rchunk); - pa_memblock_unref(rchunk.memblock); -} diff --git a/src/sourceoutput.h b/src/sourceoutput.h deleted file mode 100644 index a8ea5a9f..00000000 --- a/src/sourceoutput.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef foosourceoutputhfoo -#define foosourceoutputhfoo - -#include - -#include "source.h" -#include "sample.h" -#include "memblockq.h" -#include "resampler.h" -#include "module.h" -#include "client.h" - -struct pa_source_output { - uint32_t index; - - char *name; - struct pa_module *owner; - struct pa_client *client; - struct pa_source *source; - struct pa_sample_spec sample_spec; - - void (*push)(struct pa_source_output *o, const struct pa_memchunk *chunk); - void (*kill)(struct pa_source_output* o); - - struct pa_resampler* resampler; - - void *userdata; -}; - -struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec); -void pa_source_output_free(struct pa_source_output* o); - -void pa_source_output_kill(struct pa_source_output*o); - -void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk *chunk); - -#endif -- cgit From 005cb3e013047e29b5c6e089fcb278e4ff225a1a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Jul 2004 18:58:23 +0000 Subject: adjust file references due to renaming git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@80 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 40 ++++++++++++++++++++++++---------------- src/cli-command.c | 4 ++-- src/cli.c | 4 ++-- src/clitext.c | 4 ++-- src/module-protocol-stub.c | 2 +- src/native-common.h | 4 ++-- src/pacat-simple.c | 4 ++-- src/pacat.c | 4 ++-- src/pactl.c | 4 ++-- src/parec-simple.c | 4 ++-- src/pdispatch.c | 3 ++- src/polyplib-def.h | 5 ++--- src/polyplib-error.c | 4 ++-- src/polyplib-error.h | 6 ++---- src/polyplib-simple.c | 7 ++++--- src/polyplib-simple.h | 6 +++--- src/polyplib.c | 4 ++-- src/polyplib.h | 6 +++--- src/protocol-esound.c | 6 +++--- src/protocol-native.c | 6 +++--- src/protocol-simple.c | 4 ++-- src/pstream-util.c | 2 +- src/sink-input.c | 2 +- src/sink.c | 2 +- src/source-output.c | 2 +- src/source.c | 2 +- 26 files changed, 74 insertions(+), 67 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 09df6284..8ca2bfed 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,7 +18,10 @@ AM_CFLAGS=-ansi -D_GNU_SOURCE -bin_PROGRAMS = polypaudio pacat pactl pacat-simple parec-simple +EXTRA_DIST = polypaudio.run +bin_PROGRAMS = polypaudio pacat pactl +noinst_PROGRAMS = pacat-simple parec-simple +noinst_SCRIPTS = depmod.py pkglib_LTLIBRARIES=libiochannel.la \ libsocket-server.la \ @@ -54,7 +57,8 @@ pkglib_LTLIBRARIES=libiochannel.la \ module-native-protocol-unix.la \ libpolyp.la \ libpolyp-simple.la \ - libpolyp-error.la + libpolyp-error.la \ + libpolyp-mainloop.la polypaudio_SOURCES = idxset.c idxset.h \ queue.c queue.h \ @@ -67,8 +71,8 @@ polypaudio_SOURCES = idxset.c idxset.h \ memblockq.c memblockq.h \ client.c client.h \ core.c core.h \ - sourceoutput.c sourceoutput.h \ - sinkinput.c sinkinput.h \ + source-output.c source-output.h \ + sink-input.c sink-input.h \ source.c source.h \ sink.c sink.h \ module.c module.h \ @@ -147,14 +151,14 @@ libprotocol_cli_la_SOURCES = protocol-cli.c protocol-cli.h libprotocol_cli_la_LDFLAGS = -avoid-version libprotocol_cli_la_LIBADD = libsocket-server.la libiochannel.la libcli.la -libprotocol_native_la_SOURCES = protocol-native.c protocol-native.h +libprotocol_native_la_SOURCES = protocol-native.c protocol-native.h native-common.h libprotocol_native_la_LDFLAGS = -avoid-version libprotocol_native_la_LIBADD = libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libtagstruct_la_SOURCES = tagstruct.c tagstruct.h libtagstruct_la_LDFLAGS = -avoid-version -libprotocol_esound_la_SOURCES = protocol-esound.c protocol-esound.h esound-spec.h +libprotocol_esound_la_SOURCES = protocol-esound.c protocol-esound.h esound.h libprotocol_esound_la_LDFLAGS = -avoid-version libprotocol_esound_la_LIBADD = libsocket-server.la libiochannel.la libauthkey.la @@ -230,8 +234,8 @@ module_cli_la_SOURCES = module-cli.c module_cli_la_LDFLAGS = -module -avoid-version module_cli_la_LIBADD = libcli.la libiochannel.la -libpolyp_la_SOURCES = polyp.c polyp.h \ - polypdef.h \ +libpolyp_la_SOURCES = polyplib.c polyplib.h \ + polyplib-def.h \ tagstruct.c tagstruct.h \ iochannel.c iochannel.h \ pstream.c pstream.h \ @@ -239,8 +243,6 @@ libpolyp_la_SOURCES = polyp.c polyp.h \ pdispatch.c pdispatch.h \ protocol-native-spec.h \ mainloop-api.c mainloop-api.h \ - mainloop.c mainloop.h \ - mainloop-signal.c mainloop-signal.h \ idxset.c idxset.h \ util.c util.h \ memblock.c memblock.h \ @@ -250,22 +252,28 @@ libpolyp_la_SOURCES = polyp.c polyp.h \ dynarray.c dynarray.h \ memchunk.c memchunk.h \ authkey.c authkey.h \ - socket-util.c socket-util.h + socket-util.c socket-util.h \ + native-common.h libpolyp_la_CFLAGS = $(AM_CFLAGS) -libpolyp_error_la_SOURCES = polyp-error.c polyp-error.h +libpolyp_mainloop_la_SOURCES = mainloop-api.h mainloop-api.c \ + mainloop.c mainloop.h \ + mainloop-signal.c mainloop-signal.h +libpolyp_mainloop_la_CFLAGS = $(AM_CFLAGS) + +libpolyp_error_la_SOURCES = polyplib-error.c polyplib-error.h libpolyp_error_la_CFLAGS = $(AM_CFLAGS) -libpolyp_simple_la_SOURCES = simple.c simple.h +libpolyp_simple_la_SOURCES = polyplib-simple.c polyplib-simple.h libpolyp_simple_la_CFLAGS = $(AM_CFLAGS) -libpolyp_simple_la_LIBADD = libpolyp.la +libpolyp_simple_la_LIBADD = libpolyp.la libpolyp-mainloop.la pacat_SOURCES = pacat.c #$(libpolyp_la_SOURCES) $(libpolyp_error_la_SOURCES) -pacat_LDADD = libpolyp.la libpolyp-error.la +pacat_LDADD = libpolyp.la libpolyp-error.la libpolyp-mainloop.la pacat_CFLAGS = $(AM_CFLAGS) pactl_SOURCES = pactl.c #$(libpolyp_la_SOURCES) $(libpolyp_error_la_SOURCES) -pactl_LDADD = libpolyp.la libpolyp-error.la +pactl_LDADD = libpolyp.la libpolyp-error.la libpolyp-mainloop.la pactl_CFLAGS = $(AM_CFLAGS) pacat_simple_SOURCES = pacat-simple.c #$(libpolyp_la_SOURCES) $(libpolyp_simple_la_SOURCES) $(libpolyp_error_la_SOURCES) diff --git a/src/cli-command.c b/src/cli-command.c index 0c754c7e..469e405e 100644 --- a/src/cli-command.c +++ b/src/cli-command.c @@ -9,8 +9,8 @@ #include "sink.h" #include "source.h" #include "client.h" -#include "sinkinput.h" -#include "sourceoutput.h" +#include "sink-input.h" +#include "source-output.h" #include "tokenizer.h" #include "strbuf.h" #include "namereg.h" diff --git a/src/cli.c b/src/cli.c index b4d6625d..578852d8 100644 --- a/src/cli.c +++ b/src/cli.c @@ -9,8 +9,8 @@ #include "sink.h" #include "source.h" #include "client.h" -#include "sinkinput.h" -#include "sourceoutput.h" +#include "sink-input.h" +#include "source-output.h" #include "tokenizer.h" #include "strbuf.h" #include "namereg.h" diff --git a/src/clitext.c b/src/clitext.c index 701cf2c0..6c3a0b2e 100644 --- a/src/clitext.c +++ b/src/clitext.c @@ -5,8 +5,8 @@ #include "client.h" #include "sink.h" #include "source.h" -#include "sinkinput.h" -#include "sourceoutput.h" +#include "sink-input.h" +#include "source-output.h" #include "strbuf.h" #include "sample-util.h" diff --git a/src/module-protocol-stub.c b/src/module-protocol-stub.c index f9ed62b8..4fbb2258 100644 --- a/src/module-protocol-stub.c +++ b/src/module-protocol-stub.c @@ -37,7 +37,7 @@ #else #ifdef USE_PROTOCOL_ESOUND #include "protocol-esound.h" - #include "esound-spec.h" + #include "esound.h" #define protocol_new pa_protocol_esound_new #define protocol_free pa_protocol_esound_free #define IPV4_PORT ESD_DEFAULT_PORT diff --git a/src/native-common.h b/src/native-common.h index e1db6f64..75fe483e 100644 --- a/src/native-common.h +++ b/src/native-common.h @@ -1,5 +1,5 @@ -#ifndef fooprotocolnativespech -#define fooprotocolnativespech +#ifndef foonativecommonhfoo +#define foonativecommonhfoo enum { PA_COMMAND_ERROR, diff --git a/src/pacat-simple.c b/src/pacat-simple.c index 896df814..be24c4fc 100644 --- a/src/pacat-simple.c +++ b/src/pacat-simple.c @@ -3,8 +3,8 @@ #include #include -#include "simple.h" -#include "polyp-error.h" +#include "polyplib-simple.h" +#include "polyplib-error.h" #define BUFSIZE 1024 diff --git a/src/pacat.c b/src/pacat.c index 2c5198fb..ca11b3e9 100644 --- a/src/pacat.c +++ b/src/pacat.c @@ -6,8 +6,8 @@ #include #include -#include "polyp.h" -#include "polyp-error.h" +#include "polyplib.h" +#include "polyplib-error.h" #include "mainloop.h" #include "mainloop-signal.h" diff --git a/src/pactl.c b/src/pactl.c index 688e1104..2f195907 100644 --- a/src/pactl.c +++ b/src/pactl.c @@ -6,8 +6,8 @@ #include #include -#include "polyp.h" -#include "polyp-error.h" +#include "polyplib.h" +#include "polyplib-error.h" #include "mainloop.h" #include "mainloop-signal.h" diff --git a/src/parec-simple.c b/src/parec-simple.c index a2841beb..83c4ea2f 100644 --- a/src/parec-simple.c +++ b/src/parec-simple.c @@ -3,8 +3,8 @@ #include #include -#include "simple.h" -#include "polyp-error.h" +#include "polyplib-simple.h" +#include "polyplib-error.h" #define BUFSIZE 1024 diff --git a/src/pdispatch.c b/src/pdispatch.c index 32753963..51f31725 100644 --- a/src/pdispatch.c +++ b/src/pdispatch.c @@ -1,8 +1,9 @@ #include #include #include + #include "pdispatch.h" -#include "protocol-native-spec.h" +#include "native-common.h" #ifdef DEBUG_OPCODES diff --git a/src/polyplib-def.h b/src/polyplib-def.h index 6cfafc97..85920d2b 100644 --- a/src/polyplib-def.h +++ b/src/polyplib-def.h @@ -1,5 +1,5 @@ -#ifndef foopolypdefhfoo -#define foopolypdefhfoo +#ifndef foopolyplibdefhfoo +#define foopolyplibdefhfoo #include @@ -16,5 +16,4 @@ struct pa_buffer_attr { uint32_t fragsize; }; - #endif diff --git a/src/polyplib-error.c b/src/polyplib-error.c index 86166b0c..87c9d8fa 100644 --- a/src/polyplib-error.c +++ b/src/polyplib-error.c @@ -1,8 +1,8 @@ #include #include -#include "polyp-error.h" -#include "protocol-native-spec.h" +#include "polyplib-error.h" +#include "native-common.h" static const char* const errortab[PA_ERROR_MAX] = { [PA_ERROR_OK] = "OK", diff --git a/src/polyplib-error.h b/src/polyplib-error.h index 7407f34c..7d31ec5a 100644 --- a/src/polyplib-error.h +++ b/src/polyplib-error.h @@ -1,10 +1,8 @@ -#ifndef foopolyperrhfoo -#define foopolyperrhfoo +#ifndef foopolypliberrorhfoo +#define foopolypliberrorhfoo #include -#include "protocol-native-spec.h" - const char* pa_strerror(uint32_t error); #endif diff --git a/src/polyplib-simple.c b/src/polyplib-simple.c index 5f86c5bf..6015b77d 100644 --- a/src/polyplib-simple.c +++ b/src/polyplib-simple.c @@ -3,10 +3,11 @@ #include #include -#include "simple.h" -#include "polyp.h" +#include "polyplib-simple.h" +#include "polyplib.h" #include "mainloop.h" -#include "polyp-error.h" +#include "native-common.h" +/*#include "polyp-error.h"*/ struct pa_simple { struct pa_mainloop *mainloop; diff --git a/src/polyplib-simple.h b/src/polyplib-simple.h index f5f872ee..8286811d 100644 --- a/src/polyplib-simple.h +++ b/src/polyplib-simple.h @@ -1,10 +1,10 @@ -#ifndef foosimplehfoo -#define foosimplehfoo +#ifndef foopolyplibsimplehfoo +#define foopolyplibsimplehfoo #include #include "sample.h" -#include "polypdef.h" +#include "polyplib-def.h" struct pa_simple; diff --git a/src/polyplib.c b/src/polyplib.c index d6d0f908..f60d9a2a 100644 --- a/src/polyplib.c +++ b/src/polyplib.c @@ -6,8 +6,8 @@ #include #include -#include "polyp.h" -#include "protocol-native-spec.h" +#include "polyplib.h" +#include "native-common.h" #include "pdispatch.h" #include "pstream.h" #include "dynarray.h" diff --git a/src/polyplib.h b/src/polyplib.h index 00849445..56d1ba66 100644 --- a/src/polyplib.h +++ b/src/polyplib.h @@ -1,10 +1,10 @@ -#ifndef foopolyphfoo -#define foopolyphfoo +#ifndef foopolyplibhfoo +#define foopolyplibhfoo #include #include "sample.h" -#include "polypdef.h" +#include "polyplib-def.h" #include "mainloop-api.h" struct pa_context; diff --git a/src/protocol-esound.c b/src/protocol-esound.c index d6d7e177..db57dfc7 100644 --- a/src/protocol-esound.c +++ b/src/protocol-esound.c @@ -6,12 +6,12 @@ #include #include "protocol-esound.h" -#include "esound-spec.h" +#include "esound.h" #include "memblock.h" #include "client.h" -#include "sinkinput.h" +#include "sink-input.h" #include "sink.h" -#include "sourceoutput.h" +#include "source-output.h" #include "source.h" #include "sample.h" diff --git a/src/protocol-native.c b/src/protocol-native.c index 094c6630..5165d671 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -4,11 +4,11 @@ #include #include "protocol-native.h" -#include "protocol-native-spec.h" +#include "native-common.h" #include "packet.h" #include "client.h" -#include "sourceoutput.h" -#include "sinkinput.h" +#include "source-output.h" +#include "sink-input.h" #include "pstream.h" #include "tagstruct.h" #include "pdispatch.h" diff --git a/src/protocol-simple.c b/src/protocol-simple.c index 4b52a246..6d27a284 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -5,8 +5,8 @@ #include #include -#include "sinkinput.h" -#include "sourceoutput.h" +#include "sink-input.h" +#include "source-output.h" #include "protocol-simple.h" #include "client.h" #include "sample-util.h" diff --git a/src/pstream-util.c b/src/pstream-util.c index cdcde5fa..4f545ab4 100644 --- a/src/pstream-util.c +++ b/src/pstream-util.c @@ -1,6 +1,6 @@ #include -#include "protocol-native-spec.h" +#include "native-common.h" #include "pstream-util.h" void pa_pstream_send_tagstruct(struct pa_pstream *p, struct pa_tagstruct *t) { diff --git a/src/sink-input.c b/src/sink-input.c index 54778a81..b31455dd 100644 --- a/src/sink-input.c +++ b/src/sink-input.c @@ -3,7 +3,7 @@ #include #include -#include "sinkinput.h" +#include "sink-input.h" #include "sample-util.h" #define CONVERT_BUFFER_LENGTH 4096 diff --git a/src/sink.c b/src/sink.c index 9ba79e39..4677e9fd 100644 --- a/src/sink.c +++ b/src/sink.c @@ -4,7 +4,7 @@ #include #include "sink.h" -#include "sinkinput.h" +#include "sink-input.h" #include "namereg.h" #include "util.h" #include "sample-util.h" diff --git a/src/source-output.c b/src/source-output.c index 25c661a9..eefc4f99 100644 --- a/src/source-output.c +++ b/src/source-output.c @@ -2,7 +2,7 @@ #include #include -#include "sourceoutput.h" +#include "source-output.h" struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec) { struct pa_source_output *o; diff --git a/src/source.c b/src/source.c index c0eec3ea..08ce46b7 100644 --- a/src/source.c +++ b/src/source.c @@ -4,7 +4,7 @@ #include #include "source.h" -#include "sourceoutput.h" +#include "source-output.h" #include "namereg.h" struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec) { -- cgit From dc812dada4a8a51429d28d6d297150dfb8b61aae Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Jul 2004 19:08:28 +0000 Subject: fix distcheck git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@81 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- src/Makefile.am | 4 +--- src/todo | 2 -- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 672e6e3d..19e813d9 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. AC_PREREQ(2.57) -AC_INIT([polypaudio],[0.0],[mzcbylcnhqvb (at) 0pointer (dot) de]) +AC_INIT([polypaudio],[0.1],[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([src/main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) diff --git a/src/Makefile.am b/src/Makefile.am index 8ca2bfed..8b5e80f0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,10 +18,9 @@ AM_CFLAGS=-ansi -D_GNU_SOURCE -EXTRA_DIST = polypaudio.run +EXTRA_DIST = polypaudio.run depmod.py bin_PROGRAMS = polypaudio pacat pactl noinst_PROGRAMS = pacat-simple parec-simple -noinst_SCRIPTS = depmod.py pkglib_LTLIBRARIES=libiochannel.la \ libsocket-server.la \ @@ -241,7 +240,6 @@ libpolyp_la_SOURCES = polyplib.c polyplib.h \ pstream.c pstream.h \ pstream-util.c pstream-util.h \ pdispatch.c pdispatch.h \ - protocol-native-spec.h \ mainloop-api.c mainloop-api.h \ idxset.c idxset.h \ util.c util.h \ diff --git a/src/todo b/src/todo index 1e1ff873..a6b2b3c8 100644 --- a/src/todo +++ b/src/todo @@ -1,5 +1,3 @@ -- prefix modules/libraries with pa_ -- rename files - svn-id and license in every file - documentation - pkgconfig -- cgit From b5384e09fa718c0a1c49ef2e296a8953d883fa73 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Jul 2004 19:16:42 +0000 Subject: include config.h in every file git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@82 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/alsa-util.c | 4 ++++ src/authkey.c | 4 ++++ src/cli-command.c | 4 ++++ src/cli.c | 4 ++++ src/client.c | 4 ++++ src/clitext.c | 4 ++++ src/cmdline.c | 4 ++++ src/core.c | 4 ++++ src/dynarray.c | 4 ++++ src/hashmap.c | 4 ++++ src/idxset.c | 4 ++++ src/iochannel.c | 4 ++++ src/ioline.c | 4 ++++ src/main.c | 4 ++++ src/mainloop-api.c | 4 ++++ src/mainloop-signal.c | 4 ++++ src/mainloop.c | 4 ++++ src/memblock.c | 4 ++++ src/memblockq.c | 4 ++++ src/memchunk.c | 4 ++++ src/modargs.c | 4 ++++ src/module-alsa-sink.c | 4 ++++ src/module-alsa-source.c | 4 ++++ src/module-cli.c | 4 ++++ src/module-oss-mmap.c | 4 ++++ src/module-oss.c | 4 ++++ src/module-pipe-sink.c | 4 ++++ src/module-protocol-stub.c | 4 ++++ src/module.c | 4 ++++ src/namereg.c | 4 ++++ src/oss-util.c | 4 ++++ src/pacat-simple.c | 4 ++++ src/pacat.c | 4 ++++ src/packet.c | 4 ++++ src/pactl.c | 4 ++++ src/parec-simple.c | 4 ++++ src/pdispatch.c | 4 ++++ src/polyplib-error.c | 4 ++++ src/polyplib-simple.c | 4 ++++ src/polyplib.c | 4 ++++ src/protocol-cli.c | 4 ++++ src/protocol-esound.c | 4 ++++ src/protocol-native.c | 4 ++++ src/protocol-simple.c | 4 ++++ src/pstream-util.c | 4 ++++ src/pstream.c | 4 ++++ src/queue.c | 4 ++++ src/resampler.c | 4 ++++ src/sample-util.c | 4 ++++ src/sample.c | 4 ++++ src/sconv-s16be.c | 4 ++++ src/sconv-s16le.c | 4 ++++ src/sconv.c | 4 ++++ src/sink-input.c | 4 ++++ src/sink.c | 4 ++++ src/sioman.c | 4 ++++ src/socket-client.c | 4 ++++ src/socket-server.c | 4 ++++ src/socket-util.c | 4 ++++ src/source-output.c | 4 ++++ src/source.c | 4 ++++ src/strbuf.c | 4 ++++ src/tagstruct.c | 4 ++++ src/todo | 1 + src/tokenizer.c | 4 ++++ src/util.c | 4 ++++ 66 files changed, 261 insertions(+) diff --git a/src/alsa-util.c b/src/alsa-util.c index edfd1613..be5b0437 100644 --- a/src/alsa-util.c +++ b/src/alsa-util.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include "alsa-util.h" diff --git a/src/authkey.c b/src/authkey.c index 7bf45165..bdccc8f3 100644 --- a/src/authkey.c +++ b/src/authkey.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/cli-command.c b/src/cli-command.c index 469e405e..57dff7ca 100644 --- a/src/cli-command.c +++ b/src/cli-command.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/cli.c b/src/cli.c index 578852d8..656ba049 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/client.c b/src/client.c index c170e49a..c6b958af 100644 --- a/src/client.c +++ b/src/client.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/clitext.c b/src/clitext.c index 6c3a0b2e..47f0f8ec 100644 --- a/src/clitext.c +++ b/src/clitext.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include "clitext.h" diff --git a/src/cmdline.c b/src/cmdline.c index d53d028b..e97a7a0a 100644 --- a/src/cmdline.c +++ b/src/cmdline.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/core.c b/src/core.c index 987bcc18..1782559e 100644 --- a/src/core.c +++ b/src/core.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/dynarray.c b/src/dynarray.c index 7f34eef8..c7af5b27 100644 --- a/src/dynarray.c +++ b/src/dynarray.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/hashmap.c b/src/hashmap.c index 0c963f12..db610c37 100644 --- a/src/hashmap.c +++ b/src/hashmap.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/idxset.c b/src/idxset.c index ba740250..aceb566a 100644 --- a/src/idxset.c +++ b/src/idxset.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/iochannel.c b/src/iochannel.c index 38430034..6d8ab322 100644 --- a/src/iochannel.c +++ b/src/iochannel.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/ioline.c b/src/ioline.c index 86ab5720..e6b35a2d 100644 --- a/src/ioline.c +++ b/src/ioline.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/main.c b/src/main.c index 9e2e0066..43e9e184 100644 --- a/src/main.c +++ b/src/main.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/mainloop-api.c b/src/mainloop-api.c index 6caa0c25..f6885206 100644 --- a/src/mainloop-api.c +++ b/src/mainloop-api.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include "mainloop-api.h" diff --git a/src/mainloop-signal.c b/src/mainloop-signal.c index 3c55f800..e8b592ea 100644 --- a/src/mainloop-signal.c +++ b/src/mainloop-signal.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/mainloop.c b/src/mainloop.c index a485a963..8fd16ef0 100644 --- a/src/mainloop.c +++ b/src/mainloop.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/memblock.c b/src/memblock.c index 17038861..199b64fa 100644 --- a/src/memblock.c +++ b/src/memblock.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/memblockq.c b/src/memblockq.c index 6d4d712a..b4607023 100644 --- a/src/memblockq.c +++ b/src/memblockq.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/memchunk.c b/src/memchunk.c index c0be8cce..d594d245 100644 --- a/src/memchunk.c +++ b/src/memchunk.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/modargs.c b/src/modargs.c index a4ef9af7..9419129b 100644 --- a/src/modargs.c +++ b/src/modargs.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/module-alsa-sink.c b/src/module-alsa-sink.c index a0b1e548..25533361 100644 --- a/src/module-alsa-sink.c +++ b/src/module-alsa-sink.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/module-alsa-source.c b/src/module-alsa-source.c index cc45254c..572d28b0 100644 --- a/src/module-alsa-source.c +++ b/src/module-alsa-source.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/module-cli.c b/src/module-cli.c index 135d3588..4c3d71c2 100644 --- a/src/module-cli.c +++ b/src/module-cli.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/module-oss-mmap.c b/src/module-oss-mmap.c index 2b43cbad..058bfa16 100644 --- a/src/module-oss-mmap.c +++ b/src/module-oss-mmap.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/module-oss.c b/src/module-oss.c index 324bab3b..7acdae93 100644 --- a/src/module-oss.c +++ b/src/module-oss.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/module-pipe-sink.c b/src/module-pipe-sink.c index 0a24f759..66658fd4 100644 --- a/src/module-pipe-sink.c +++ b/src/module-pipe-sink.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/module-protocol-stub.c b/src/module-protocol-stub.c index 4fbb2258..cb980b16 100644 --- a/src/module-protocol-stub.c +++ b/src/module-protocol-stub.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/module.c b/src/module.c index b6a706c3..fe27d617 100644 --- a/src/module.c +++ b/src/module.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/namereg.c b/src/namereg.c index bf381ae4..2406b50c 100644 --- a/src/namereg.c +++ b/src/namereg.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/oss-util.c b/src/oss-util.c index 7be91dcb..de8fa663 100644 --- a/src/oss-util.c +++ b/src/oss-util.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/pacat-simple.c b/src/pacat-simple.c index be24c4fc..c0e07146 100644 --- a/src/pacat-simple.c +++ b/src/pacat-simple.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/pacat.c b/src/pacat.c index ca11b3e9..b614af73 100644 --- a/src/pacat.c +++ b/src/pacat.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/packet.c b/src/packet.c index 304545c5..48685b1e 100644 --- a/src/packet.c +++ b/src/packet.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include diff --git a/src/pactl.c b/src/pactl.c index 2f195907..5208321f 100644 --- a/src/pactl.c +++ b/src/pactl.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/parec-simple.c b/src/parec-simple.c index 83c4ea2f..f26a1335 100644 --- a/src/parec-simple.c +++ b/src/parec-simple.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/pdispatch.c b/src/pdispatch.c index 51f31725..126c26ef 100644 --- a/src/pdispatch.c +++ b/src/pdispatch.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/polyplib-error.c b/src/polyplib-error.c index 87c9d8fa..1a9fe12d 100644 --- a/src/polyplib-error.c +++ b/src/polyplib-error.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include diff --git a/src/polyplib-simple.c b/src/polyplib-simple.c index 6015b77d..846c2f80 100644 --- a/src/polyplib-simple.c +++ b/src/polyplib-simple.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/polyplib.c b/src/polyplib.c index f60d9a2a..dd66c5d2 100644 --- a/src/polyplib.c +++ b/src/polyplib.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/protocol-cli.c b/src/protocol-cli.c index 0e738321..6f052ac4 100644 --- a/src/protocol-cli.c +++ b/src/protocol-cli.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include diff --git a/src/protocol-esound.c b/src/protocol-esound.c index db57dfc7..c28dfa3d 100644 --- a/src/protocol-esound.c +++ b/src/protocol-esound.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/protocol-native.c b/src/protocol-native.c index 5165d671..223a0972 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/protocol-simple.c b/src/protocol-simple.c index 6d27a284..563fee94 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/pstream-util.c b/src/pstream-util.c index 4f545ab4..82bdaa55 100644 --- a/src/pstream-util.c +++ b/src/pstream-util.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include "native-common.h" diff --git a/src/pstream.c b/src/pstream.c index 18d33b0d..4a0848f3 100644 --- a/src/pstream.c +++ b/src/pstream.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/queue.c b/src/queue.c index 9e775f44..f28b2607 100644 --- a/src/queue.c +++ b/src/queue.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include diff --git a/src/resampler.c b/src/resampler.c index 67823e45..42555eca 100644 --- a/src/resampler.c +++ b/src/resampler.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include diff --git a/src/sample-util.c b/src/sample-util.c index c7a7b679..df0b58c8 100644 --- a/src/sample-util.c +++ b/src/sample-util.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/sample.c b/src/sample.c index 2cdc9e72..3c93b376 100644 --- a/src/sample.c +++ b/src/sample.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include diff --git a/src/sconv-s16be.c b/src/sconv-s16be.c index 728a4a05..3640b9f7 100644 --- a/src/sconv-s16be.c +++ b/src/sconv-s16be.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include "sconv-s16be.h" #define INT16_FROM INT16_FROM_BE diff --git a/src/sconv-s16le.c b/src/sconv-s16le.c index ca984463..b61ca2bf 100644 --- a/src/sconv-s16le.c +++ b/src/sconv-s16le.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include diff --git a/src/sconv.c b/src/sconv.c index 6dd165a4..b0a57b77 100644 --- a/src/sconv.c +++ b/src/sconv.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/sink-input.c b/src/sink-input.c index b31455dd..7b580126 100644 --- a/src/sink-input.c +++ b/src/sink-input.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/sink.c b/src/sink.c index 4677e9fd..8c48c033 100644 --- a/src/sink.c +++ b/src/sink.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/sioman.c b/src/sioman.c index 1a4b08b0..a93e8f45 100644 --- a/src/sioman.c +++ b/src/sioman.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include "sioman.h" diff --git a/src/socket-client.c b/src/socket-client.c index b1e609ab..e7ffa33d 100644 --- a/src/socket-client.c +++ b/src/socket-client.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/socket-server.c b/src/socket-server.c index 02b4328f..193b3c48 100644 --- a/src/socket-server.c +++ b/src/socket-server.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/socket-util.c b/src/socket-util.c index f4648da5..c2bb277e 100644 --- a/src/socket-util.c +++ b/src/socket-util.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/source-output.c b/src/source-output.c index eefc4f99..7b93bcb3 100644 --- a/src/source-output.c +++ b/src/source-output.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/source.c b/src/source.c index 08ce46b7..fe7cf16e 100644 --- a/src/source.c +++ b/src/source.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/strbuf.c b/src/strbuf.c index 41c139bd..44fa5b40 100644 --- a/src/strbuf.c +++ b/src/strbuf.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/tagstruct.c b/src/tagstruct.c index e57e755c..50854c28 100644 --- a/src/tagstruct.c +++ b/src/tagstruct.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/todo b/src/todo index a6b2b3c8..c3414fe5 100644 --- a/src/todo +++ b/src/todo @@ -1,3 +1,4 @@ +- config.h - svn-id and license in every file - documentation - pkgconfig diff --git a/src/tokenizer.c b/src/tokenizer.c index de82c8e1..bdd05e44 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/src/util.c b/src/util.c index 773922b5..a13679a2 100644 --- a/src/util.c +++ b/src/util.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include -- cgit From e0d510df922d4c3440944a3c9670e52ad668056d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Jul 2004 19:56:36 +0000 Subject: include copyright and svn tag in *.[ch] git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@83 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/alsa-util.c | 21 +++++++++++++++++++++ src/alsa-util.h | 21 +++++++++++++++++++++ src/authkey.c | 21 +++++++++++++++++++++ src/authkey.h | 21 +++++++++++++++++++++ src/cli-command.c | 21 +++++++++++++++++++++ src/cli-command.h | 21 +++++++++++++++++++++ src/cli.c | 21 +++++++++++++++++++++ src/cli.h | 21 +++++++++++++++++++++ src/client.c | 21 +++++++++++++++++++++ src/client.h | 21 +++++++++++++++++++++ src/clitext.c | 21 +++++++++++++++++++++ src/clitext.h | 21 +++++++++++++++++++++ src/cmdline.c | 21 +++++++++++++++++++++ src/cmdline.h | 21 +++++++++++++++++++++ src/core.c | 21 +++++++++++++++++++++ src/core.h | 21 +++++++++++++++++++++ src/dynarray.c | 21 +++++++++++++++++++++ src/dynarray.h | 21 +++++++++++++++++++++ src/endianmacros.h | 21 +++++++++++++++++++++ src/esound.h | 21 +++++++++++++++++++++ src/hashmap.c | 21 +++++++++++++++++++++ src/hashmap.h | 21 +++++++++++++++++++++ src/idxset.c | 21 +++++++++++++++++++++ src/idxset.h | 21 +++++++++++++++++++++ src/iochannel.c | 21 +++++++++++++++++++++ src/iochannel.h | 21 +++++++++++++++++++++ src/ioline.c | 21 +++++++++++++++++++++ src/ioline.h | 21 +++++++++++++++++++++ src/main.c | 21 +++++++++++++++++++++ src/mainloop-api.c | 21 +++++++++++++++++++++ src/mainloop-api.h | 21 +++++++++++++++++++++ src/mainloop-signal.c | 21 +++++++++++++++++++++ src/mainloop-signal.h | 21 +++++++++++++++++++++ src/mainloop.c | 21 +++++++++++++++++++++ src/mainloop.h | 21 +++++++++++++++++++++ src/memblock.c | 21 +++++++++++++++++++++ src/memblock.h | 21 +++++++++++++++++++++ src/memblockq.c | 21 +++++++++++++++++++++ src/memblockq.h | 21 +++++++++++++++++++++ src/memchunk.c | 21 +++++++++++++++++++++ src/memchunk.h | 21 +++++++++++++++++++++ src/modargs.c | 21 +++++++++++++++++++++ src/modargs.h | 21 +++++++++++++++++++++ src/module-alsa-sink.c | 21 +++++++++++++++++++++ src/module-alsa-source.c | 21 +++++++++++++++++++++ src/module-cli.c | 21 +++++++++++++++++++++ src/module-oss-mmap.c | 21 +++++++++++++++++++++ src/module-oss.c | 21 +++++++++++++++++++++ src/module-pipe-sink.c | 21 +++++++++++++++++++++ src/module-protocol-stub.c | 21 +++++++++++++++++++++ src/module.c | 21 +++++++++++++++++++++ src/module.h | 21 +++++++++++++++++++++ src/namereg.c | 21 +++++++++++++++++++++ src/namereg.h | 21 +++++++++++++++++++++ src/native-common.h | 21 +++++++++++++++++++++ src/oss-util.c | 21 +++++++++++++++++++++ src/oss-util.h | 21 +++++++++++++++++++++ src/pacat-simple.c | 21 +++++++++++++++++++++ src/pacat.c | 21 +++++++++++++++++++++ src/packet.c | 21 +++++++++++++++++++++ src/packet.h | 21 +++++++++++++++++++++ src/pactl.c | 21 +++++++++++++++++++++ src/parec-simple.c | 21 +++++++++++++++++++++ src/pdispatch.c | 21 +++++++++++++++++++++ src/pdispatch.h | 21 +++++++++++++++++++++ src/polyplib-def.h | 21 +++++++++++++++++++++ src/polyplib-error.c | 21 +++++++++++++++++++++ src/polyplib-error.h | 21 +++++++++++++++++++++ src/polyplib-simple.c | 21 +++++++++++++++++++++ src/polyplib-simple.h | 21 +++++++++++++++++++++ src/polyplib.c | 21 +++++++++++++++++++++ src/polyplib.h | 21 +++++++++++++++++++++ src/protocol-cli.c | 21 +++++++++++++++++++++ src/protocol-cli.h | 21 +++++++++++++++++++++ src/protocol-esound.c | 21 +++++++++++++++++++++ src/protocol-esound.h | 21 +++++++++++++++++++++ src/protocol-native.c | 21 +++++++++++++++++++++ src/protocol-native.h | 21 +++++++++++++++++++++ src/protocol-simple.c | 21 +++++++++++++++++++++ src/protocol-simple.h | 21 +++++++++++++++++++++ src/pstream-util.c | 21 +++++++++++++++++++++ src/pstream-util.h | 21 +++++++++++++++++++++ src/pstream.c | 21 +++++++++++++++++++++ src/pstream.h | 21 +++++++++++++++++++++ src/queue.c | 21 +++++++++++++++++++++ src/queue.h | 21 +++++++++++++++++++++ src/resampler.c | 21 +++++++++++++++++++++ src/resampler.h | 21 +++++++++++++++++++++ src/sample-util.c | 21 +++++++++++++++++++++ src/sample-util.h | 21 +++++++++++++++++++++ src/sample.c | 21 +++++++++++++++++++++ src/sample.h | 21 +++++++++++++++++++++ src/sconv-s16be.c | 21 +++++++++++++++++++++ src/sconv-s16be.h | 21 +++++++++++++++++++++ src/sconv-s16le.c | 21 +++++++++++++++++++++ src/sconv-s16le.h | 21 +++++++++++++++++++++ src/sconv.c | 21 +++++++++++++++++++++ src/sconv.h | 21 +++++++++++++++++++++ src/sink-input.c | 21 +++++++++++++++++++++ src/sink-input.h | 21 +++++++++++++++++++++ src/sink.c | 21 +++++++++++++++++++++ src/sink.h | 21 +++++++++++++++++++++ src/sioman.c | 21 +++++++++++++++++++++ src/sioman.h | 21 +++++++++++++++++++++ src/socket-client.c | 21 +++++++++++++++++++++ src/socket-client.h | 21 +++++++++++++++++++++ src/socket-server.c | 21 +++++++++++++++++++++ src/socket-server.h | 21 +++++++++++++++++++++ src/socket-util.c | 21 +++++++++++++++++++++ src/socket-util.h | 21 +++++++++++++++++++++ src/source-output.c | 21 +++++++++++++++++++++ src/source-output.h | 21 +++++++++++++++++++++ src/source.c | 21 +++++++++++++++++++++ src/source.h | 21 +++++++++++++++++++++ src/strbuf.c | 21 +++++++++++++++++++++ src/strbuf.h | 21 +++++++++++++++++++++ src/tagstruct.c | 21 +++++++++++++++++++++ src/tagstruct.h | 21 +++++++++++++++++++++ src/tokenizer.c | 21 +++++++++++++++++++++ src/tokenizer.h | 21 +++++++++++++++++++++ src/util.c | 21 +++++++++++++++++++++ src/util.h | 21 +++++++++++++++++++++ 122 files changed, 2562 insertions(+) diff --git a/src/alsa-util.c b/src/alsa-util.c index be5b0437..7f266df5 100644 --- a/src/alsa-util.c +++ b/src/alsa-util.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/alsa-util.h b/src/alsa-util.h index 4468c9d8..03e427d9 100644 --- a/src/alsa-util.h +++ b/src/alsa-util.h @@ -1,6 +1,27 @@ #ifndef fooalsautilhfoo #define fooalsautilhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include "sample.h" diff --git a/src/authkey.c b/src/authkey.c index bdccc8f3..3180b8fd 100644 --- a/src/authkey.c +++ b/src/authkey.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/authkey.h b/src/authkey.h index a0d695a9..acdcc24d 100644 --- a/src/authkey.h +++ b/src/authkey.h @@ -1,6 +1,27 @@ #ifndef fooauthkeyhfoo #define fooauthkeyhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include int pa_authkey_load(const char *path, void *data, size_t len); diff --git a/src/cli-command.c b/src/cli-command.c index 57dff7ca..f3a2f8a0 100644 --- a/src/cli-command.c +++ b/src/cli-command.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/cli-command.h b/src/cli-command.h index f95261b7..b3c601ad 100644 --- a/src/cli-command.h +++ b/src/cli-command.h @@ -1,6 +1,27 @@ #ifndef fooclicommandhfoo #define fooclicommandhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "strbuf.h" #include "core.h" diff --git a/src/cli.c b/src/cli.c index 656ba049..f2aa5a65 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/cli.h b/src/cli.h index d6250b37..9cfee0d8 100644 --- a/src/cli.h +++ b/src/cli.h @@ -1,6 +1,27 @@ #ifndef fooclihfoo #define fooclihfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "iochannel.h" #include "core.h" #include "module.h" diff --git a/src/client.c b/src/client.c index c6b958af..0294c9e2 100644 --- a/src/client.c +++ b/src/client.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/client.h b/src/client.h index 10ffa8f3..c926208e 100644 --- a/src/client.h +++ b/src/client.h @@ -1,6 +1,27 @@ #ifndef fooclienthfoo #define fooclienthfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "core.h" #include "module.h" diff --git a/src/clitext.c b/src/clitext.c index 47f0f8ec..c1b9953b 100644 --- a/src/clitext.c +++ b/src/clitext.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/clitext.h b/src/clitext.h index 5b17c2d7..b1718cb5 100644 --- a/src/clitext.h +++ b/src/clitext.h @@ -1,6 +1,27 @@ #ifndef fooclitexthfoo #define fooclitexthfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "core.h" char *pa_sink_input_list_to_string(struct pa_core *c); diff --git a/src/cmdline.c b/src/cmdline.c index e97a7a0a..a3330145 100644 --- a/src/cmdline.c +++ b/src/cmdline.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/cmdline.h b/src/cmdline.h index ec2dd0c2..95ce91de 100644 --- a/src/cmdline.h +++ b/src/cmdline.h @@ -1,6 +1,27 @@ #ifndef foocmdlinehfoo #define foocmdlinehfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + struct pa_cmdline { int daemonize, help, fail, verbose; diff --git a/src/core.c b/src/core.c index 1782559e..dc9525a8 100644 --- a/src/core.c +++ b/src/core.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/core.h b/src/core.h index ee5bfc41..99d7d76a 100644 --- a/src/core.h +++ b/src/core.h @@ -1,6 +1,27 @@ #ifndef foocorehfoo #define foocorehfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "idxset.h" #include "hashmap.h" #include "mainloop-api.h" diff --git a/src/dynarray.c b/src/dynarray.c index c7af5b27..24306964 100644 --- a/src/dynarray.c +++ b/src/dynarray.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/dynarray.h b/src/dynarray.h index fab3841d..56ec5386 100644 --- a/src/dynarray.h +++ b/src/dynarray.h @@ -1,6 +1,27 @@ #ifndef foodynarrayhfoo #define foodynarrayhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + struct pa_dynarray; struct pa_dynarray* pa_dynarray_new(void); diff --git a/src/endianmacros.h b/src/endianmacros.h index 2394b3e8..cd7b7d83 100644 --- a/src/endianmacros.h +++ b/src/endianmacros.h @@ -1,6 +1,27 @@ #ifndef fooendianmacroshfoo #define fooendianmacroshfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #ifdef HAVE_CONFIG_H diff --git a/src/esound.h b/src/esound.h index f7a4d3db..01a2962f 100644 --- a/src/esound.h +++ b/src/esound.h @@ -1,6 +1,27 @@ #ifndef fooesoundhfoo #define fooesoundhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + /* Most of the following is blatantly stolen from esound. */ diff --git a/src/hashmap.c b/src/hashmap.c index db610c37..2c7c92b5 100644 --- a/src/hashmap.c +++ b/src/hashmap.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/hashmap.h b/src/hashmap.h index 4a0ad77e..b24e74a5 100644 --- a/src/hashmap.h +++ b/src/hashmap.h @@ -1,6 +1,27 @@ #ifndef foohashmaphfoo #define foohashmaphfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + struct pa_hashmap; struct pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); diff --git a/src/idxset.c b/src/idxset.c index aceb566a..cecda6b7 100644 --- a/src/idxset.c +++ b/src/idxset.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/idxset.h b/src/idxset.h index be5bb294..f26b03fb 100644 --- a/src/idxset.h +++ b/src/idxset.h @@ -1,6 +1,27 @@ #ifndef fooidxsethfoo #define fooidxsethfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #define PA_IDXSET_INVALID ((uint32_t) -1) diff --git a/src/iochannel.c b/src/iochannel.c index 6d8ab322..69d381f4 100644 --- a/src/iochannel.c +++ b/src/iochannel.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/iochannel.h b/src/iochannel.h index 7e31b6ca..6f5f351c 100644 --- a/src/iochannel.h +++ b/src/iochannel.h @@ -1,6 +1,27 @@ #ifndef fooiochannelhfoo #define fooiochannelhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include "mainloop-api.h" diff --git a/src/ioline.c b/src/ioline.c index e6b35a2d..ff9a03c2 100644 --- a/src/ioline.c +++ b/src/ioline.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/ioline.h b/src/ioline.h index ba7cf540..5f29a16b 100644 --- a/src/ioline.h +++ b/src/ioline.h @@ -1,6 +1,27 @@ #ifndef fooiolinehfoo #define fooiolinehfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "iochannel.h" struct pa_ioline; diff --git a/src/main.c b/src/main.c index 43e9e184..d9967cef 100644 --- a/src/main.c +++ b/src/main.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/mainloop-api.c b/src/mainloop-api.c index f6885206..cce49c06 100644 --- a/src/mainloop-api.c +++ b/src/mainloop-api.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/mainloop-api.h b/src/mainloop-api.h index 961a1a46..0228f580 100644 --- a/src/mainloop-api.h +++ b/src/mainloop-api.h @@ -1,6 +1,27 @@ #ifndef foomainloopapihfoo #define foomainloopapihfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include diff --git a/src/mainloop-signal.c b/src/mainloop-signal.c index e8b592ea..642ca5e0 100644 --- a/src/mainloop-signal.c +++ b/src/mainloop-signal.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/mainloop-signal.h b/src/mainloop-signal.h index e3e2364d..8afe9c8d 100644 --- a/src/mainloop-signal.h +++ b/src/mainloop-signal.h @@ -1,6 +1,27 @@ #ifndef foomainloopsignalhfoo #define foomainloopsignalhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "mainloop-api.h" int pa_signal_init(struct pa_mainloop_api *api); diff --git a/src/mainloop.c b/src/mainloop.c index 8fd16ef0..b9eee86d 100644 --- a/src/mainloop.c +++ b/src/mainloop.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/mainloop.h b/src/mainloop.h index 7837636f..58448c3e 100644 --- a/src/mainloop.h +++ b/src/mainloop.h @@ -1,6 +1,27 @@ #ifndef foomainloophfoo #define foomainloophfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "mainloop-api.h" struct pa_mainloop; diff --git a/src/memblock.c b/src/memblock.c index 199b64fa..8f24ff22 100644 --- a/src/memblock.c +++ b/src/memblock.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/memblock.h b/src/memblock.h index 647a1c8c..4bb02977 100644 --- a/src/memblock.h +++ b/src/memblock.h @@ -1,6 +1,27 @@ #ifndef foomemblockhfoo #define foomemblockhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include diff --git a/src/memblockq.c b/src/memblockq.c index b4607023..eff923b9 100644 --- a/src/memblockq.c +++ b/src/memblockq.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/memblockq.h b/src/memblockq.h index bece4fd7..e6ad01db 100644 --- a/src/memblockq.h +++ b/src/memblockq.h @@ -1,6 +1,27 @@ #ifndef foomemblockqhfoo #define foomemblockqhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include "memblock.h" diff --git a/src/memchunk.c b/src/memchunk.c index d594d245..d27ca61a 100644 --- a/src/memchunk.c +++ b/src/memchunk.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/memchunk.h b/src/memchunk.h index 24c031a5..341c145c 100644 --- a/src/memchunk.h +++ b/src/memchunk.h @@ -1,6 +1,27 @@ #ifndef foomemchunkhfoo #define foomemchunkhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "memblock.h" struct pa_memchunk { diff --git a/src/modargs.c b/src/modargs.c index 9419129b..da2bab87 100644 --- a/src/modargs.c +++ b/src/modargs.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/modargs.h b/src/modargs.h index 07792ef3..301dc297 100644 --- a/src/modargs.h +++ b/src/modargs.h @@ -1,6 +1,27 @@ #ifndef foomodargshfoo #define foomodargshfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include "sample.h" #include "core.h" diff --git a/src/module-alsa-sink.c b/src/module-alsa-sink.c index 25533361..8a3388af 100644 --- a/src/module-alsa-sink.c +++ b/src/module-alsa-sink.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/module-alsa-source.c b/src/module-alsa-source.c index 572d28b0..287a0350 100644 --- a/src/module-alsa-source.c +++ b/src/module-alsa-source.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/module-cli.c b/src/module-cli.c index 4c3d71c2..8897c9c6 100644 --- a/src/module-cli.c +++ b/src/module-cli.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/module-oss-mmap.c b/src/module-oss-mmap.c index 058bfa16..800eaf25 100644 --- a/src/module-oss-mmap.c +++ b/src/module-oss-mmap.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/module-oss.c b/src/module-oss.c index 7acdae93..d727534a 100644 --- a/src/module-oss.c +++ b/src/module-oss.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/module-pipe-sink.c b/src/module-pipe-sink.c index 66658fd4..df34f73a 100644 --- a/src/module-pipe-sink.c +++ b/src/module-pipe-sink.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/module-protocol-stub.c b/src/module-protocol-stub.c index cb980b16..545de3e8 100644 --- a/src/module-protocol-stub.c +++ b/src/module-protocol-stub.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/module.c b/src/module.c index fe27d617..5c6f0fb6 100644 --- a/src/module.c +++ b/src/module.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/module.h b/src/module.h index 174a8d09..af2d8552 100644 --- a/src/module.h +++ b/src/module.h @@ -1,6 +1,27 @@ #ifndef foomodulehfoo #define foomodulehfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include diff --git a/src/namereg.c b/src/namereg.c index 2406b50c..2349436f 100644 --- a/src/namereg.c +++ b/src/namereg.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/namereg.h b/src/namereg.h index b53a8566..0af83cd8 100644 --- a/src/namereg.h +++ b/src/namereg.h @@ -1,6 +1,27 @@ #ifndef foonamereghfoo #define foonamereghfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "core.h" enum pa_namereg_type { diff --git a/src/native-common.h b/src/native-common.h index 75fe483e..2acbae8e 100644 --- a/src/native-common.h +++ b/src/native-common.h @@ -1,6 +1,27 @@ #ifndef foonativecommonhfoo #define foonativecommonhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + enum { PA_COMMAND_ERROR, PA_COMMAND_TIMEOUT, /* pseudo command */ diff --git a/src/oss-util.c b/src/oss-util.c index de8fa663..cf55a6ee 100644 --- a/src/oss-util.c +++ b/src/oss-util.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/oss-util.h b/src/oss-util.h index a62eee1d..cb2ce33c 100644 --- a/src/oss-util.h +++ b/src/oss-util.h @@ -1,6 +1,27 @@ #ifndef fooossutilhfoo #define fooossutilhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "sample.h" int pa_oss_open(const char *device, int *mode, int* pcaps); diff --git a/src/pacat-simple.c b/src/pacat-simple.c index c0e07146..5018aa5f 100644 --- a/src/pacat-simple.c +++ b/src/pacat-simple.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/pacat.c b/src/pacat.c index b614af73..1d1cc3d5 100644 --- a/src/pacat.c +++ b/src/pacat.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/packet.c b/src/packet.c index 48685b1e..e94df057 100644 --- a/src/packet.c +++ b/src/packet.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/packet.h b/src/packet.h index b6024dd0..8bea07e1 100644 --- a/src/packet.h +++ b/src/packet.h @@ -1,6 +1,27 @@ #ifndef foopackethfoo #define foopackethfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include diff --git a/src/pactl.c b/src/pactl.c index 5208321f..2b1ed2c1 100644 --- a/src/pactl.c +++ b/src/pactl.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/parec-simple.c b/src/parec-simple.c index f26a1335..c4196a14 100644 --- a/src/parec-simple.c +++ b/src/parec-simple.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/pdispatch.c b/src/pdispatch.c index 126c26ef..a28458a4 100644 --- a/src/pdispatch.c +++ b/src/pdispatch.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/pdispatch.h b/src/pdispatch.h index ac372477..796c1e03 100644 --- a/src/pdispatch.h +++ b/src/pdispatch.h @@ -1,6 +1,27 @@ #ifndef foopdispatchhfoo #define foopdispatchhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include "tagstruct.h" #include "packet.h" diff --git a/src/polyplib-def.h b/src/polyplib-def.h index 85920d2b..e43f4b35 100644 --- a/src/polyplib-def.h +++ b/src/polyplib-def.h @@ -1,6 +1,27 @@ #ifndef foopolyplibdefhfoo #define foopolyplibdefhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include enum pa_stream_direction { diff --git a/src/polyplib-error.c b/src/polyplib-error.c index 1a9fe12d..10b637c4 100644 --- a/src/polyplib-error.c +++ b/src/polyplib-error.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/polyplib-error.h b/src/polyplib-error.h index 7d31ec5a..cb86864a 100644 --- a/src/polyplib-error.h +++ b/src/polyplib-error.h @@ -1,6 +1,27 @@ #ifndef foopolypliberrorhfoo #define foopolypliberrorhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include const char* pa_strerror(uint32_t error); diff --git a/src/polyplib-simple.c b/src/polyplib-simple.c index 846c2f80..024cb18a 100644 --- a/src/polyplib-simple.c +++ b/src/polyplib-simple.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/polyplib-simple.h b/src/polyplib-simple.h index 8286811d..0544410c 100644 --- a/src/polyplib-simple.h +++ b/src/polyplib-simple.h @@ -1,6 +1,27 @@ #ifndef foopolyplibsimplehfoo #define foopolyplibsimplehfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include "sample.h" diff --git a/src/polyplib.c b/src/polyplib.c index dd66c5d2..ea5003b4 100644 --- a/src/polyplib.c +++ b/src/polyplib.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/polyplib.h b/src/polyplib.h index 56d1ba66..440b9658 100644 --- a/src/polyplib.h +++ b/src/polyplib.h @@ -1,6 +1,27 @@ #ifndef foopolyplibhfoo #define foopolyplibhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include "sample.h" diff --git a/src/protocol-cli.c b/src/protocol-cli.c index 6f052ac4..d6e69b54 100644 --- a/src/protocol-cli.c +++ b/src/protocol-cli.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/protocol-cli.h b/src/protocol-cli.h index f970bb8d..7ad2db75 100644 --- a/src/protocol-cli.h +++ b/src/protocol-cli.h @@ -1,6 +1,27 @@ #ifndef fooprotocolclihfoo #define fooprotocolclihfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "core.h" #include "socket-server.h" #include "module.h" diff --git a/src/protocol-esound.c b/src/protocol-esound.c index c28dfa3d..8a7c4bcb 100644 --- a/src/protocol-esound.c +++ b/src/protocol-esound.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/protocol-esound.h b/src/protocol-esound.h index 8653949d..b2bdd31b 100644 --- a/src/protocol-esound.h +++ b/src/protocol-esound.h @@ -1,6 +1,27 @@ #ifndef fooprotocolesoundhfoo #define fooprotocolesoundhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "core.h" #include "socket-server.h" #include "module.h" diff --git a/src/protocol-native.c b/src/protocol-native.c index 223a0972..83c910d1 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/protocol-native.h b/src/protocol-native.h index 89cb1634..3d9fdde1 100644 --- a/src/protocol-native.h +++ b/src/protocol-native.h @@ -1,6 +1,27 @@ #ifndef fooprotocolnativehfoo #define fooprotocolnativehfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "core.h" #include "socket-server.h" #include "module.h" diff --git a/src/protocol-simple.c b/src/protocol-simple.c index 563fee94..3a52e311 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/protocol-simple.h b/src/protocol-simple.h index 62682915..0fc1e19d 100644 --- a/src/protocol-simple.h +++ b/src/protocol-simple.h @@ -1,6 +1,27 @@ #ifndef fooprotocolsimplehfoo #define fooprotocolsimplehfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "socket-server.h" #include "module.h" #include "core.h" diff --git a/src/pstream-util.c b/src/pstream-util.c index 82bdaa55..3957e643 100644 --- a/src/pstream-util.c +++ b/src/pstream-util.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/pstream-util.h b/src/pstream-util.h index 43051260..b3c89eb0 100644 --- a/src/pstream-util.h +++ b/src/pstream-util.h @@ -1,6 +1,27 @@ #ifndef foopstreamutilhfoo #define foopstreamutilhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include "pstream.h" #include "tagstruct.h" diff --git a/src/pstream.c b/src/pstream.c index 4a0848f3..3076b776 100644 --- a/src/pstream.c +++ b/src/pstream.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/pstream.h b/src/pstream.h index 8525cb22..6b91aeb0 100644 --- a/src/pstream.h +++ b/src/pstream.h @@ -1,6 +1,27 @@ #ifndef foopstreamhfoo #define foopstreamhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include "packet.h" diff --git a/src/queue.c b/src/queue.c index f28b2607..9befd475 100644 --- a/src/queue.c +++ b/src/queue.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/queue.h b/src/queue.h index e06d69cb..3ec13734 100644 --- a/src/queue.h +++ b/src/queue.h @@ -1,6 +1,27 @@ #ifndef fooqueuehfoo #define fooqueuehfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + struct pa_queue; struct pa_queue* pa_queue_new(void); diff --git a/src/resampler.c b/src/resampler.c index 42555eca..4f5f6be3 100644 --- a/src/resampler.c +++ b/src/resampler.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/resampler.h b/src/resampler.h index 1d42b365..8e979478 100644 --- a/src/resampler.h +++ b/src/resampler.h @@ -1,6 +1,27 @@ #ifndef fooresamplerhfoo #define fooresamplerhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "sample.h" #include "memblock.h" #include "memchunk.h" diff --git a/src/sample-util.c b/src/sample-util.c index df0b58c8..d608ce1b 100644 --- a/src/sample-util.c +++ b/src/sample-util.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/sample-util.h b/src/sample-util.h index 4efa59a4..73101ab4 100644 --- a/src/sample-util.h +++ b/src/sample-util.h @@ -1,6 +1,27 @@ #ifndef foosampleutilhfoo #define foosampleutilhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "sample.h" #include "memblock.h" #include "memchunk.h" diff --git a/src/sample.c b/src/sample.c index 3c93b376..8179475d 100644 --- a/src/sample.c +++ b/src/sample.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/sample.h b/src/sample.h index a755b76d..825441f2 100644 --- a/src/sample.h +++ b/src/sample.h @@ -1,6 +1,27 @@ #ifndef foosamplehfoo #define foosamplehfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include diff --git a/src/sconv-s16be.c b/src/sconv-s16be.c index 3640b9f7..a4c25cde 100644 --- a/src/sconv-s16be.c +++ b/src/sconv-s16be.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/sconv-s16be.h b/src/sconv-s16be.h index 257393c6..d112d9f2 100644 --- a/src/sconv-s16be.h +++ b/src/sconv-s16be.h @@ -1,6 +1,27 @@ #ifndef foosconv_s16befoo #define foosconv_s16befoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + void pa_sconv_s16be_to_float32(unsigned n, const void *a, unsigned an, float *b); void pa_sconv_s16be_from_float32(unsigned n, const float *a, void *b, unsigned bn); diff --git a/src/sconv-s16le.c b/src/sconv-s16le.c index b61ca2bf..45b28bdb 100644 --- a/src/sconv-s16le.c +++ b/src/sconv-s16le.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/sconv-s16le.h b/src/sconv-s16le.h index cfbf81fd..0f206ec3 100644 --- a/src/sconv-s16le.h +++ b/src/sconv-s16le.h @@ -1,6 +1,27 @@ #ifndef foosconv_s16lefoo #define foosconv_s16lefoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + void pa_sconv_s16le_to_float32(unsigned n, const void *a, unsigned an, float *b); void pa_sconv_s16le_from_float32(unsigned n, const float *a, void *b, unsigned bn); diff --git a/src/sconv.c b/src/sconv.c index b0a57b77..dd9dd241 100644 --- a/src/sconv.c +++ b/src/sconv.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/sconv.h b/src/sconv.h index e16f2dcc..1a62ed20 100644 --- a/src/sconv.h +++ b/src/sconv.h @@ -1,6 +1,27 @@ #ifndef foosconvhfoo #define foosconvhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "sample.h" typedef void (*pa_convert_to_float32_func_t)(unsigned n, const void *a, unsigned an, float *b); diff --git a/src/sink-input.c b/src/sink-input.c index 7b580126..5c2d3a13 100644 --- a/src/sink-input.c +++ b/src/sink-input.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/sink-input.h b/src/sink-input.h index 02a2a117..63dce71d 100644 --- a/src/sink-input.h +++ b/src/sink-input.h @@ -1,6 +1,27 @@ #ifndef foosinkinputhfoo #define foosinkinputhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include "sink.h" diff --git a/src/sink.c b/src/sink.c index 8c48c033..20fa76a6 100644 --- a/src/sink.c +++ b/src/sink.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/sink.h b/src/sink.h index a25a4377..2b5d9495 100644 --- a/src/sink.h +++ b/src/sink.h @@ -1,6 +1,27 @@ #ifndef foosinkhfoo #define foosinkhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + struct pa_sink; #include diff --git a/src/sioman.c b/src/sioman.c index a93e8f45..999b8a5c 100644 --- a/src/sioman.c +++ b/src/sioman.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/sioman.h b/src/sioman.h index e675c80e..1b60d4a9 100644 --- a/src/sioman.h +++ b/src/sioman.h @@ -1,6 +1,27 @@ #ifndef foosiomanhfoo #define foosiomanhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + int pa_stdio_acquire(void); void pa_stdio_release(void); diff --git a/src/socket-client.c b/src/socket-client.c index e7ffa33d..a2187e6a 100644 --- a/src/socket-client.c +++ b/src/socket-client.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/socket-client.h b/src/socket-client.h index 85753788..2a89210e 100644 --- a/src/socket-client.h +++ b/src/socket-client.h @@ -1,6 +1,27 @@ #ifndef foosocketclienthfoo #define foosocketclienthfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include "mainloop-api.h" #include "iochannel.h" diff --git a/src/socket-server.c b/src/socket-server.c index 193b3c48..0f497377 100644 --- a/src/socket-server.c +++ b/src/socket-server.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/socket-server.h b/src/socket-server.h index dbce172e..6661a66e 100644 --- a/src/socket-server.h +++ b/src/socket-server.h @@ -1,6 +1,27 @@ #ifndef foosocketserverhfoo #define foosocketserverhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include "mainloop-api.h" #include "iochannel.h" diff --git a/src/socket-util.c b/src/socket-util.c index c2bb277e..e0a3c28d 100644 --- a/src/socket-util.c +++ b/src/socket-util.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/socket-util.h b/src/socket-util.h index 0133bfc3..85133feb 100644 --- a/src/socket-util.h +++ b/src/socket-util.h @@ -1,6 +1,27 @@ #ifndef foosocketutilhfoo #define foosocketutilhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include void pa_socket_peer_to_string(int fd, char *c, size_t l); diff --git a/src/source-output.c b/src/source-output.c index 7b93bcb3..2705fdb3 100644 --- a/src/source-output.c +++ b/src/source-output.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/source-output.h b/src/source-output.h index a8ea5a9f..0e6e2cfd 100644 --- a/src/source-output.h +++ b/src/source-output.h @@ -1,6 +1,27 @@ #ifndef foosourceoutputhfoo #define foosourceoutputhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include "source.h" diff --git a/src/source.c b/src/source.c index fe7cf16e..ccde0e2f 100644 --- a/src/source.c +++ b/src/source.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/source.h b/src/source.h index 9e57bc0f..9c584a6d 100644 --- a/src/source.h +++ b/src/source.h @@ -1,6 +1,27 @@ #ifndef foosourcehfoo #define foosourcehfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + struct pa_source; #include diff --git a/src/strbuf.c b/src/strbuf.c index 44fa5b40..c6a3772d 100644 --- a/src/strbuf.c +++ b/src/strbuf.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/strbuf.h b/src/strbuf.h index 0e9bb5e3..d672c42a 100644 --- a/src/strbuf.h +++ b/src/strbuf.h @@ -1,6 +1,27 @@ #ifndef foostrbufhfoo #define foostrbufhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + struct pa_strbuf; struct pa_strbuf *pa_strbuf_new(void); diff --git a/src/tagstruct.c b/src/tagstruct.c index 50854c28..0d93c1e9 100644 --- a/src/tagstruct.c +++ b/src/tagstruct.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/tagstruct.h b/src/tagstruct.h index 2c1ae587..aefd03c4 100644 --- a/src/tagstruct.h +++ b/src/tagstruct.h @@ -1,6 +1,27 @@ #ifndef footagstructhfoo #define footagstructhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include diff --git a/src/tokenizer.c b/src/tokenizer.c index bdd05e44..c7f18d26 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/tokenizer.h b/src/tokenizer.h index 160b23e0..7d1cf9b5 100644 --- a/src/tokenizer.h +++ b/src/tokenizer.h @@ -1,6 +1,27 @@ #ifndef footokenizerhfoo #define footokenizerhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + struct pa_tokenizer; struct pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args); diff --git a/src/util.c b/src/util.c index a13679a2..6e75c240 100644 --- a/src/util.c +++ b/src/util.c @@ -1,3 +1,24 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #ifdef HAVE_CONFIG_H #include #endif diff --git a/src/util.h b/src/util.h index 3e494434..96fde11c 100644 --- a/src/util.h +++ b/src/util.h @@ -1,6 +1,27 @@ #ifndef fooutilhfoo #define fooutilhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include void pa_make_nonblock_fd(int fd); -- cgit From cf965cbda8a9330baf7a45dbea8ea9499a0e4e96 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Jul 2004 20:02:44 +0000 Subject: add missing liecenses git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@84 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 9 +++++---- src/Makefile.am | 9 +++++---- src/depmod.py | 17 +++++++++++++++++ src/polypaudio.run | 24 +++++++++++++++++++++--- src/todo | 6 +++--- 5 files changed, 51 insertions(+), 14 deletions(-) diff --git a/Makefile.am b/Makefile.am index 7266cba5..c03548b2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,8 +2,8 @@ # # This file is part of polypaudio. # -# polypaudio is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # @@ -13,8 +13,9 @@ # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with polypaudio; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. EXTRA_DIST = bootstrap.sh SUBDIRS=src diff --git a/src/Makefile.am b/src/Makefile.am index 8b5e80f0..c2ede9f3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,8 +2,8 @@ # # This file is part of polypaudio. # -# polypaudio is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # @@ -13,8 +13,9 @@ # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with polypaudio; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. AM_CFLAGS=-ansi -D_GNU_SOURCE diff --git a/src/depmod.py b/src/depmod.py index d11cceb4..85dc66a8 100755 --- a/src/depmod.py +++ b/src/depmod.py @@ -1,5 +1,22 @@ #!/usr/bin/python # $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. import sys, os, string diff --git a/src/polypaudio.run b/src/polypaudio.run index 25af2df6..177707ba 100755 --- a/src/polypaudio.run +++ b/src/polypaudio.run @@ -1,10 +1,28 @@ #!./polypaudio -F +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + + # Load audio drivers -#load module-alsa-sink -#load module-alsa-source device=plughw:1,0 +load module-alsa-sink +load module-alsa-source device=plughw:1,0 #load module-oss device="/dev/dsp" -load module-oss-mmap device="/dev/dsp" +#load module-oss-mmap device="/dev/dsp" # Load several protocols load module-esound-protocol-tcp diff --git a/src/todo b/src/todo index c3414fe5..68517338 100644 --- a/src/todo +++ b/src/todo @@ -1,9 +1,9 @@ -- config.h -- svn-id and license in every file +*** $Id$ *** + - documentation - pkgconfig --- post 0.1 +*** post 0.1 *** - future cancellation - client-ui - clip cache -- cgit From 3e379ca99d44c84b2117ac048ee6e84fc2837280 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Jul 2004 20:58:18 +0000 Subject: add pkgconfig stuff git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@85 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 3 ++ configure.ac | 4 ++- polyplib-error.pc.in | 10 ++++++ polyplib-mainloop.pc.in | 10 ++++++ polyplib-simple.pc.in | 10 ++++++ polyplib.pc.in | 10 ++++++ src/Makefile.am | 92 +++++++++++++++++++++++++++++++++++++++++++++---- 7 files changed, 132 insertions(+), 7 deletions(-) create mode 100644 polyplib-error.pc.in create mode 100644 polyplib-mainloop.pc.in create mode 100644 polyplib-simple.pc.in create mode 100644 polyplib.pc.in diff --git a/Makefile.am b/Makefile.am index c03548b2..dc7024a4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,5 +20,8 @@ EXTRA_DIST = bootstrap.sh SUBDIRS=src +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc + distcleancheck: @: diff --git a/configure.ac b/configure.ac index 19e813d9..e73cb033 100644 --- a/configure.ac +++ b/configure.ac @@ -55,5 +55,7 @@ if test "x$GCC" = "xyes" ; then CFLAGS="$CFLAGS -pipe -Wall -W -Wno-unused-parameter" fi -AC_CONFIG_FILES([Makefile src/Makefile]) +AM_CONDITIONAL(BUILD_LIBPOLYPCORE, false) + +AC_CONFIG_FILES([Makefile src/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc]) AC_OUTPUT diff --git a/polyplib-error.pc.in b/polyplib-error.pc.in new file mode 100644 index 00000000..b5289959 --- /dev/null +++ b/polyplib-error.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: polyplib-error +Description: Error library for the polypaudio sound daemon +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lpolyp-error +Cflags: -D_REENTRANT -I${includedir} diff --git a/polyplib-mainloop.pc.in b/polyplib-mainloop.pc.in new file mode 100644 index 00000000..f4bdba5b --- /dev/null +++ b/polyplib-mainloop.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: polyplib-mainloop +Description: Mainloop API of the polypaudio sound daemon +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lpolyp-mainloop +Cflags: -D_REENTRANT -I${includedir} diff --git a/polyplib-simple.pc.in b/polyplib-simple.pc.in new file mode 100644 index 00000000..efae9410 --- /dev/null +++ b/polyplib-simple.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: polyplib-simple +Description: Simplistic client interface to polypaudio sound daemon +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lpolyp-simple +Cflags: -D_REENTRANT -I${includedir} diff --git a/polyplib.pc.in b/polyplib.pc.in new file mode 100644 index 00000000..8a554cb1 --- /dev/null +++ b/polyplib.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: polyplib +Description: Client interface to polypaudio sound daemon +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lpolyp +Cflags: -D_REENTRANT -I${includedir} diff --git a/src/Makefile.am b/src/Makefile.am index c2ede9f3..86f86a5d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,6 +23,15 @@ EXTRA_DIST = polypaudio.run depmod.py bin_PROGRAMS = polypaudio pacat pactl noinst_PROGRAMS = pacat-simple parec-simple +pkginclude_HEADERS=polyplib.h \ + polyplib-def.h \ + polyplib-simple.h \ + polyplib-error.h \ + mainloop-api.h \ + mainloop.h \ + mainloop-signal.h \ + sample.h + pkglib_LTLIBRARIES=libiochannel.la \ libsocket-server.la \ libsocket-client.la \ @@ -54,8 +63,9 @@ pkglib_LTLIBRARIES=libiochannel.la \ module-esound-protocol-tcp.la \ module-esound-protocol-unix.la \ module-native-protocol-tcp.la \ - module-native-protocol-unix.la \ - libpolyp.la \ + module-native-protocol-unix.la + +lib_LTLIBRARIES=libpolyp.la \ libpolyp-simple.la \ libpolyp-error.la \ libpolyp-mainloop.la @@ -267,18 +277,88 @@ libpolyp_simple_la_SOURCES = polyplib-simple.c polyplib-simple.h libpolyp_simple_la_CFLAGS = $(AM_CFLAGS) libpolyp_simple_la_LIBADD = libpolyp.la libpolyp-mainloop.la -pacat_SOURCES = pacat.c #$(libpolyp_la_SOURCES) $(libpolyp_error_la_SOURCES) +pacat_SOURCES = pacat.c pacat_LDADD = libpolyp.la libpolyp-error.la libpolyp-mainloop.la pacat_CFLAGS = $(AM_CFLAGS) -pactl_SOURCES = pactl.c #$(libpolyp_la_SOURCES) $(libpolyp_error_la_SOURCES) +pactl_SOURCES = pactl.c pactl_LDADD = libpolyp.la libpolyp-error.la libpolyp-mainloop.la pactl_CFLAGS = $(AM_CFLAGS) -pacat_simple_SOURCES = pacat-simple.c #$(libpolyp_la_SOURCES) $(libpolyp_simple_la_SOURCES) $(libpolyp_error_la_SOURCES) +pacat_simple_SOURCES = pacat-simple.c pacat_simple_LDADD = libpolyp-simple.la libpolyp-error.la pacat_simple_CFLAGS = $(AM_CFLAGS) -parec_simple_SOURCES = parec-simple.c #$(libpolyp_la_SOURCES) $(libpolyp_simple_la_SOURCES) $(libpolyp_error_la_SOURCES) +parec_simple_SOURCES = parec-simple.c parec_simple_LDADD = libpolyp-simple.la libpolyp-error.la parec_simple_CFLAGS = $(AM_CFLAGS) + +if BUILD_LIBPOLYPCORE + +pkginclude_HEADERS+=cli-command.h\ + client.h \ + core.h \ + dynarray.h \ + endianmacros.h \ + hashmap.h \ + idxset.h \ + iochannel.h \ + memblock.h \ + memblockq.h \ + memchunk.h \ + modargs.h \ + module.h \ + namereg.h \ + queue.h \ + resampler.h \ + sample-util.h \ + sink.h \ + sink-input.h \ + sioman.h \ + socket-server.h \ + socket-client.h \ + socket-util.h \ + source.h \ + source-output.h \ + strbuf.h \ + tokenizer.h \ + tagstruct.h \ + util.h + +lib_LTLIBRARIES+= libpolypcore.la + +libpolypcore_la_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 \ + sample-util.c sample-util.h \ + memblockq.c memblockq.h \ + client.c client.h \ + core.c core.h \ + source-output.c source-output.h \ + sink-input.c sink-input.h \ + source.c source.h \ + sink.c sink.h \ + module.c module.h \ + mainloop-signal.c mainloop-signal.h \ + mainloop-api.c mainloop-api.h \ + util.c util.h \ + hashmap.c hashmap.h \ + namereg.c namereg.h \ + sconv.c sconv.h \ + resampler.c resampler.h \ + endianmacros.h \ + memchunk.c memchunk.h \ + sconv-s16le.c sconv-s16le.h \ + sconv-s16be.c sconv-s16be.h \ + sioman.c sioman.h \ + modargs.c modargs.h \ + cmdline.c cmdline.h \ + cli-command.c cli-command.h \ + clitext.c clitext.h \ + tokenizer.c tokenizer.h \ + dynarray.c dynarray.h + +endif -- cgit From 7b8c329578d642d31618d487b97864306c43073c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 17 Jul 2004 14:06:13 +0000 Subject: add documentation git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@86 fefdeb5f-60dc-0310-8127-8f9354f1896f --- LICENSE | 340 +++++++++++++++++++++++++++++++++++++++++++++ Makefile.am | 21 ++- configure.ac | 21 ++- doc/Makefile.am | 39 ++++++ doc/README.html.in | 133 ++++++++++++++++++ doc/cli.html.in | 152 ++++++++++++++++++++ doc/daemon.html.in | 51 +++++++ doc/modules.html.in | 191 +++++++++++++++++++++++++ doc/style.css | 34 +++++ src/Makefile.am | 1 - src/modargs.c | 6 +- src/module-protocol-stub.c | 2 +- src/todo | 1 - 13 files changed, 985 insertions(+), 7 deletions(-) create mode 100644 LICENSE create mode 100644 doc/Makefile.am create mode 100644 doc/README.html.in create mode 100644 doc/cli.html.in create mode 100644 doc/daemon.html.in create mode 100644 doc/modules.html.in create mode 100644 doc/style.css diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..d60c31a9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Makefile.am b/Makefile.am index dc7024a4..43009b44 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,11 +17,28 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -EXTRA_DIST = bootstrap.sh -SUBDIRS=src +EXTRA_DIST = bootstrap.sh README LICENSE +SUBDIRS=src doc + +MAINTAINERCLEANFILES=README +noinst_DATA = README pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc +README: + rm -f README + $(MAKE) -C doc README + cd $(srcdir) && ln -s doc/README README + +homepage: all dist + test -d $$HOME/homepage/private + mkdir -p $$HOME/homepage/private/projects/polypaudio + cp *.tar.gz $$HOME/homepage/private/projects/polypaudio + cp doc/README.html doc/cli.html doc/daemon.html doc/modules.html doc/style.css doc/NEWS $$HOME/homepage/private/projects/polypaudio + cp $$HOME/homepage/private/projects/polypaudio/README.html $$HOME/homepage/private/projects/polypaudio/index.html + distcleancheck: @: + +.PHONY: homepage distcleancheck diff --git a/configure.ac b/configure.ac index e73cb033..86398f4d 100644 --- a/configure.ac +++ b/configure.ac @@ -55,7 +55,26 @@ if test "x$GCC" = "xyes" ; then CFLAGS="$CFLAGS -pipe -Wall -W -Wno-unused-parameter" fi +# LYNX documentation generation +AC_ARG_ENABLE(lynx, + AS_HELP_STRING(--disable-lynx,Turn off lynx usage for documentation generation), +[case "${enableval}" in + yes) lynx=yes ;; + no) lynx=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-lynx) ;; +esac],[lynx=yes]) + +if test x$lynx = xyes ; then + AC_CHECK_PROG(have_lynx, lynx, yes, no) + + if test x$have_lynx = xno ; then + AC_MSG_ERROR([*** Sorry, you have to install lynx or use --disable-lynx ***]) + fi +fi + +AM_CONDITIONAL([USE_LYNX], [test "x$lynx" = xyes]) + AM_CONDITIONAL(BUILD_LIBPOLYPCORE, false) -AC_CONFIG_FILES([Makefile src/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc]) +AC_CONFIG_FILES([Makefile src/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html]) AC_OUTPUT diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 00000000..015d503d --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,39 @@ +# $Id$ + +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + +noinst_DATA = README.html cli.html modules.html daemon.html README +EXTRA_DIST = $(noinst_DATA) style.css README.html.in cli.html.in modules.html.in daemon.html.in + +MAINTAINERCLEANFILES = README README.html cli.html modules.html daemon.html +CLEANFILES = + +if USE_LYNX +README: README.html + lynx --dump $^ | sed 's,file://localhost/.*/doc/README.html,README,' > $@ + +CLEANFILES += README +endif + +tidy: README.html cli.html modules.html daemon.html + tidy -e < README.html + tidy -e < cli.html + tidy -e < modules.html + tidy -e < daemon.html + +.PHONY: tidy + diff --git a/doc/README.html.in b/doc/README.html.in new file mode 100644 index 00000000..a9b07d60 --- /dev/null +++ b/doc/README.html.in @@ -0,0 +1,133 @@ + + + + + +polypaudio @PACKAGE_VERSION@ + + + + +

polypaudio @PACKAGE_VERSION@

+ +

Copyright 2002-2004 Lennart Poettering <@PACKAGE_BUGREPORT@>

+ + + +

License

+ +

This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version.

+ +

This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details.

+ +

You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

+ +

News

+ + +
Sat Jul 17 2004:

Version 0.1 released

+ +

Overview

+ +

polypaudio is a sound server for Linux and other Unix like +operating systems. It is intended to be an improved drop-in +replacement for the Enlightened Sound +Daemon (ESOUND). In addition to the features ESOUND provides +polypaudio has:

+ +
    +
  • Extensible plugin architecture (dlopen())
  • +
  • Support for more than one sink/source
  • +
  • Better low latency behaviour
  • +
  • Embedabble into other software (the core is available as C library)
  • +
  • Completely asynchronous C API
  • +
  • Simple command line interface for reconfiguring the daemon while running
  • +
  • Flexible, implicit sample type conversion and resampling
  • +
  • "Zero-Copy" architecture
  • +
+ +

Both the core and the client API are completely asynchronous making +use of a simple main loop abstraction layer. This allows easy +integration with asynchronous applications using the +glib/gtk mainloop. Since the asynchronous API +available through polyplib is quite difficult to use there is +a simplified synchronous API wrapper polyplib-simple +available.

+ +

Status

+ +

Version @PACKAGE_VERSION@ is quite usable. polypaudio does +not yet match all ESOUND features: currently a sample cache and +automatic releasing of unused sound drivers are missing. Have a look on the more extensive TODO list.

+ +

Documentation

+ +

There is some prelimenary documentation available: modules.html, cli.html, daemeon.html.

+ +

Documentation for developing with polypaudio is not yet +available. Read the source, Luke!

+ +

Requirements

+ +

Currently, polypaudio is tested on Linux only. It requires an OSS or ALSA compatible soundcard.

+ +

polypaudio was developed and tested on Debian GNU/Linux +"testing" from July 2004, it should work on most other Linux +distributions (and maybe Unix versions) since it uses GNU autoconf and +GNU libtool for source code configuration and shared library +management.

+ +

polypaudio needs Secret Rabbit Code (aka libsamplerate) and alsa-lib.

+ +

Installation

+ +

As this package is made with the GNU autotools you should run +./configure inside the distribution directory for configuring +the source tree. After that you should run make for +compilation and make install (as root) for installation of +polypaudio.

+ +

Acknowledgements

+ +

Eric B. Mitchell for writing ESOUND

+ +

Download

+ +

The newest release is always available from @PACKAGE_URL@

+ +

The current release is @PACKAGE_VERSION@

+ +

Get polypaudio's development sources from the Subversion repository. (viewcvs)

+ +

If you want to be notified whenever I release a new version of this software use the subscription feature of Freshmeat.

+ +
+
Lennart Poettering <@PACKAGE_BUGREPORT@>, July 2004
+
$Id$
+ + + diff --git a/doc/cli.html.in b/doc/cli.html.in new file mode 100644 index 00000000..c67d78db --- /dev/null +++ b/doc/cli.html.in @@ -0,0 +1,152 @@ + + + + +polypaudio: Simple Command Line Language + + + + +

Simple Command Line Language

+ +

polypaudio provides a simple command line language used by +configuration scripts as well as the modules module-cli +and module-cli-protocol-{unix,tcp}. Empty lines and lines +beginning with a hashmark (#) are silently ignored. Several +commands are supported:

+ +

Miscellaneous Commands

+ +

help

+ +

Show a quick help on the commands available.

+ +

exit

+ +

Terminate the daemon. If you want to terminate a CLI connection +("log out") you might want to use C-d.

+ +

Status Commands

+ +

modules

+ +

Show all currently loaded modules with their arguments.

+ +

sinks/sources

+ +

Show all currently registered sinks (resp. sources).

+ +

clients

+ +

Show all currently active clients.

+ +

sink_inputs/sink_outputs

+ +

Show all currently active inputs to sinks (resp. outputs of sources).

+ +

stat

+ +

Show some simple statistics about the allocated memory blocks and +the space used by them.

+ +

info

+ +

A combination of all status commands described above. ls +and list are synonyms for info.

+ +

Module Management

+ +

load

+ +

Load a module specified by its name and arguments. For most modules +it is OK to be loaded more than once.

+ +

unload

+ +

Unload a module specified by its index in the module list as +returned by modules.

+ +

Configuration Commands

+ +

sink_volume

+ +

Set the volume of the specified sink. You may specify the sink either +by its index in the sink list or by its name. The volume should be an +integer value greater or equal than 0 (= muted). Volume 256 +(0x100) is normal volume, values greater than this amplify +the audio signal with clipping.

+ +

sink_input_volume

+ +

Set the volume of a sink input specified by its index the the sink +input list. The same volume rules apply as with sink_volume.

+ +

sink_default/source_default

+ +

Make a sink (resp. source) the default. You may specify the sink +(resp. ssource) by its index in the sink (resp. source) list or by its +name.

+ +

Killing clients/streams

+ +

kill_client

+ +

Remove a client forcibly from the server. There is no protection that +the client reconnects immediately.

+ +

kill_sink_input/kill_source_output

+ +

Remove a sink input (resp. source output) forcibly from the +server. This will not remove the owning client or any other streams +opened by the client from the server.

+ +

Meta Commands

+ +

In addition the the commands described above there a few meta +directives supported by the command line interpreter:

+ +

.include

+ +

Executes the commands from the specified script file.

+ +

.fail/.nofail

+ +

Enable (resp. disable) that following failing commands will cancel +the execution of the current script file. This is a ignored when used +on the interactive command line.

+ +

.verbose/.noverbose

+

Enable (resp. disable) extra verbosity.

+ +

Example Configuration Script

+ +
+#!/usr/bin/polaudio -F
+
+# Load audio drivers
+load module-alsa-sink device=plughw:0,0 rate=48000
+load module-alsa-source device=hw:1,0
+
+# Load several protocols
+load module-esound-protocol-tcp
+load module-simple-protocol-tcp
+load module-native-protocol-unix
+load module-cli-protocol-unix
+
+# Load the CLI module (This is similar to passing "-C" on the command line of polypaudio)
+load module-cli
+
+.nofail
+
+# Make some devices default
+sink_default alsa_output
+source_default alsa_input
+
+# Use digital amplification
+sink_volume alsa_output 0x200
+
+ +
+
Lennart Poettering <@PACKAGE_BUGREPORT@>, July 2004
+
$Id$
+ diff --git a/doc/daemon.html.in b/doc/daemon.html.in new file mode 100644 index 00000000..a5d933db --- /dev/null +++ b/doc/daemon.html.in @@ -0,0 +1,51 @@ + + + + +polypaudio: Daemon + + + + +

Daemon

+ +

Command Line Arguments

+ +The polypaudio daemon accepts several command line arguments: + +

-L MODULE: Load the specified module. This option may be specified more than once.

+

-F FILE: Run the specified script. This option may be specified more than once.

+

-C: Load the module module-cli after startup.

+

-D: Daemonize after successfully executing all scripts and loading all modules.

+

-f: Unless this option is given the daemon will terminate if any of the specified modules failed to load or the script didn't execute successfully.

+

-v: Increase the verbosity of the daemon.

+

-h: Show a quick help.

+ +

Example

+ +

It is a good idea to run the daemon like this:

+ +
polypaudio -D -F /etc/polypaudio/polypaudio.pa
+ +

/etc/polypaudio/polypaudio.pa should be a script written in the CLI language described in cli.html + +

Signals

+ +

The following signals are trapped specially:

+ +

SIGINT

+ +

The daemon is shut down cleanly.

+ +

SIGUSR1

+ +

The daemon tries to load the module module-cli, effectively providing a command line interface on the calling TTY.

+ +

SIGUSR2

+ +

The daemon tries to load the module module-cli-protocol-unix, effectively providing a command line interface on a special UNIX domain socket.

+ +
+
Lennart Poettering <@PACKAGE_BUGREPORT@>, July 2004
+
$Id$
+ diff --git a/doc/modules.html.in b/doc/modules.html.in new file mode 100644 index 00000000..6954418f --- /dev/null +++ b/doc/modules.html.in @@ -0,0 +1,191 @@ + + + + +polypaudio: Loadable Modules + + + + + +

Loadable Modules

+ +

The following loadable modules are provided with the polypaudio distribution:

+ +

Device Drivers

+ +

All device driver modules support the following parameters:

+ + + + + +
format=The sample format (one of u8, s16, s16le, s16le, float32, float32be, float32le, alaw, ulaw) (defaults to s16)
rate=The sample rate (defaults to 44100)
channels=Audio channels (defaults to 2)
sink_name=, source_name=Name for the sink (resp. source)
+ +

module-pipe-sink

+ +

Provides a simple test sink that writes the audio data to a FIFO +special file in the file system. The sink name defaults to pipe_output.

+ +

The following option is supported:

+ + + +
file=The name of the FIFO special file to use
+ + + +

module-alsa-sink

+ +

Provides a playback sink for devices supported by the Advanced Linux +Sound Architecture (ALSA). The sink name defaults to alsa_output.

+ +

In addition to the general device driver options described above this module supports:

+ + + + + +
device=The ALSA device to use. (defaults to "plughw:0,0")
fragments=The desired fragments when opening the device. (defaults to 12)
fragment_size=The desired fragment size in bytes when opening the device (defaults to 1024)
+ +

module-alsa-source

+ +

Provides a recording source for devices supported by the Advanced +Linux Sound Architecture (ALSA). The source name defaults to alsa_input.

+ +

This module supports device=, fragments= and fragment_size= arguments the same way as module-alsa-sink.

+ + + +

module-oss

+ +

Provides both a sink and a source for playback, resp. recording on +Open Sound System (OSS) compatible devices.

+ +

This module supports device= (which defaults to /dev/dsp), fragments= and fragment_size= arguments the same way as module-alsa-sink.

+ +

In addition this module supports the following options:

+ + + + +
record=Accepts a binary numerical value for enabling (resp. disabling) the recording on this device. (defaults: to 1)
playback=Accepts a binary numerical value for enabling (resp. disabling) the playback on this device. (defaults: to 1)
+ +

The sink name (resp. source name) defaults to oss_output (resp. oss_input).

+ +

module-oss-mmap

+ +

Similar to module-oss but uses memory mapped +(mmap()) access to the input/output buffers of the audio +device. This provides better latency behaviour but is not as +compatible as module-oss.

+ +

This module accepts exactly the same arguments as module-oss.

+ +

Protocols

+ + + +

module-cli

+ +

Provides the user with a simple command line interface on the +controlling TTY of the daemon. This module may not be loaded more than +once.

+ +

For an explanation of the simple command line language used by this +module see cli.html. + +

This module doesn't accept any arguments.

+ + + + + +

module-cli-protocol-{unix,tcp}

+ +

An implemenation of a simple command line based protocol for +controlling the polypaudio daemon. If loaded, the user may +connect with tools like netcat, telnet or +bidilink to the listening sockets and execute commands the +same way as with module-cli.

+ +

Beware! Users are not authenticated when connecting to this +service.

+ +

This module exists in two versions: with the suffix -unix +the service will listen on an UNIX domain socket in the local file +system. With the suffix -tcp it will listen on a network +transparent TCP/IP socket.

+ +

This module supports the following options:

+ + + + + +
port=(only for -tcp) The port number to listen on (defaults to 4712)
loopback=(only for -tcp) Accepts +a numerical binary value. If 1 the socket is bound to the loopback +device, i.e. not publicly accessible. (defaults to 1)
socket=(only for -unix) The UNIX socket name (defaults to /tmp/polypaudio/cli)
+ +

module-simple-protocol-{unix,tcp}

+ +

An implementation of a simple protocol which allows playback by using +simple tools like netcat. Just connect to the listening +socket of this module and write the audio data to it, or read it from +it for playback, resp. recording.

+ +

Beware! Users are not authenticated when connecting to this +service.

+ +

See module-cli-protocol-{unix,tcp} for more information +about the two possible suffixes of this module.

+ +

In addition to the options supported by module-cli-protocol-*, this module supports:

+ + + + + +
rate=, format=, channels=Sample format for streams connecting to this service.
playback=, record=Enable/disable playback/recording
sink=, source=Specify the sink/source this service connects to
+ +

module-esound-protocol-{unix,tcp}

+ +

An implemenation of a protocol compatible with the Enlightened Sound +Daemon (ESOUND, esd). When you load this module you may +access the polypaudio daemon with tools like esdcat, +esdrec or even esdctl. Many applications, such as +XMMS, include support for this protocol.

+ +

See module-cli-protocol-{unix,tcp} for more information +about the two possible suffixes of this module.

+ +

In addition to the options supported by module-cli-protocol-*, this module supports:

+ + + + + +
sink=, source=Specify the sink/source this service connects to
public=If set to 0 not authentication is required to connect to the service
cookie=Name of the cookie file for authentication purposes
+ +

This implementation misses some features the original ESOUND has: e.g. there is no sample cache yet. However: XMMS works fine.

+ +

module-native-protocol-{unix,tcp}

+ +

The native protocol of polypaudio.

+ +

See module-cli-protocol-{unix,tcp} for more information +about the two possible suffixes of this module.

+ +

In addition to the options supported by module-cli-protocol-*, this module supports:

+ + + + +
public=If set to 0 not authentication is required to connect to the service
cookie=Name of the cookie file for authentication purposes
+ + +
+
Lennart Poettering <@PACKAGE_BUGREPORT@>, July 2004
+
$Id$
+ diff --git a/doc/style.css b/doc/style.css new file mode 100644 index 00000000..e54a15a3 --- /dev/null +++ b/doc/style.css @@ -0,0 +1,34 @@ +/* $Id$ */ + +/*** + * This file is part of polypaudio. + * + * polypaudio is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * polypaudio is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with polypaudio; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + ***/ + +body { color: black; background-color: white; margin: 0.5cm; } +a:link, a:visited { color: #900000; } +p { margin-left: 0.5cm; margin-right: 0.5cm; } +div.news-date { margin-left: 0.5cm; font-size: 80%; color: #4f0000; } +p.news-text { margin-left: 1cm; } +h1 { color: #00009F; } +h2 { color: #00009F; } +h3 { color: #00004F; margin-left: 0.5cm; } +ul { margin-left: .5cm; } +ol { margin-left: .5cm; } +pre { margin-left: .5cm; background-color: #f0f0f0; padding: 0.4cm;} +.grey { color: #afafaf; } +table { margin-left: 1cm; border:1px solid lightgrey; padding: 0.2cm; } +td { padding-left:10px; padding-right:10px; } diff --git a/src/Makefile.am b/src/Makefile.am index 86f86a5d..c4da7342 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -355,7 +355,6 @@ libpolypcore_la_SOURCES = idxset.c idxset.h \ sconv-s16be.c sconv-s16be.h \ sioman.c sioman.h \ modargs.c modargs.h \ - cmdline.c cmdline.h \ cli-command.c cli-command.h \ clitext.c clitext.h \ tokenizer.c tokenizer.h \ diff --git a/src/modargs.c b/src/modargs.c index da2bab87..280a546d 100644 --- a/src/modargs.c +++ b/src/modargs.c @@ -231,8 +231,12 @@ int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *rss ss.format = PA_SAMPLE_S16NE; else if (strcmp(format, "u8") == 0 || strcmp(format, "8") == 0) ss.format = PA_SAMPLE_U8; - else if (strcmp(format, "float32") == 0) + else if (strcmp(format, "float32") == 0 || strcmp(format, "float32ne") == 0) ss.format = PA_SAMPLE_FLOAT32; + else if (strcmp(format, "float32le") == 0) + ss.format = PA_SAMPLE_FLOAT32LE; + else if (strcmp(format, "float32be") == 0) + ss.format = PA_SAMPLE_FLOAT32BE; else if (strcmp(format, "ulaw") == 0) ss.format = PA_SAMPLE_ULAW; else if (strcmp(format, "alaw") == 0) diff --git a/src/module-protocol-stub.c b/src/module-protocol-stub.c index 545de3e8..3ce18c31 100644 --- a/src/module-protocol-stub.c +++ b/src/module-protocol-stub.c @@ -89,7 +89,7 @@ static const char* const valid_modargs[] = { static struct pa_socket_server *create_socket_server(struct pa_core *c, struct pa_modargs *ma) { struct pa_socket_server *s; #ifdef USE_TCP_SOCKETS - uint32_t loopback = 0, port = IPV4_PORT; + uint32_t loopback = 1, port = IPV4_PORT; if (pa_modargs_get_value_u32(ma, "loopback", &loopback) < 0) { fprintf(stderr, "loopback= expects a numerical argument.\n"); diff --git a/src/todo b/src/todo index 68517338..5b944a36 100644 --- a/src/todo +++ b/src/todo @@ -1,7 +1,6 @@ *** $Id$ *** - documentation -- pkgconfig *** post 0.1 *** - future cancellation -- cgit -- cgit From 86f5b30e10773c3421486bf06062b416e2bfd5c1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 17 Jul 2004 14:08:26 +0000 Subject: move todo file git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@88 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 32 ++++++++++++++++++++++++++++++++ src/todo | 32 -------------------------------- 2 files changed, 32 insertions(+), 32 deletions(-) create mode 100644 doc/todo delete mode 100644 src/todo diff --git a/doc/todo b/doc/todo new file mode 100644 index 00000000..5b944a36 --- /dev/null +++ b/doc/todo @@ -0,0 +1,32 @@ +*** $Id$ *** + +- documentation + +*** post 0.1 *** +- future cancellation +- client-ui +- clip cache +- autoloading/autounloading +- slp/rendezvous +- doxygen +- make mcalign merge chunks +- modinfo +- move the global memblock statistics variables to the core +- unix socket directories include user name +- more complete pactl +- native library/protocol: + get server layout + subscription + module load/unload + kill client/... +- make alsa modules use mmap + +drivers: +- libao +- xmms +- portaudio +- mplayer +- python + +modules: +- http? diff --git a/src/todo b/src/todo deleted file mode 100644 index 5b944a36..00000000 --- a/src/todo +++ /dev/null @@ -1,32 +0,0 @@ -*** $Id$ *** - -- documentation - -*** post 0.1 *** -- future cancellation -- client-ui -- clip cache -- autoloading/autounloading -- slp/rendezvous -- doxygen -- make mcalign merge chunks -- modinfo -- move the global memblock statistics variables to the core -- unix socket directories include user name -- more complete pactl -- native library/protocol: - get server layout - subscription - module load/unload - kill client/... -- make alsa modules use mmap - -drivers: -- libao -- xmms -- portaudio -- mplayer -- python - -modules: -- http? -- cgit From 563201e128d600ec1ae4a33ca81d03b776501f82 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 17 Jul 2004 14:09:41 +0000 Subject: rename configuration file make sure the todo file is packaged git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@89 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/Makefile.am | 2 +- src/polypaudio.pa | 41 +++++++++++++++++++++++++++++++++++++++++ src/polypaudio.run | 41 ----------------------------------------- 3 files changed, 42 insertions(+), 42 deletions(-) create mode 100755 src/polypaudio.pa delete mode 100755 src/polypaudio.run diff --git a/doc/Makefile.am b/doc/Makefile.am index 015d503d..d88451f5 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -17,7 +17,7 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. noinst_DATA = README.html cli.html modules.html daemon.html README -EXTRA_DIST = $(noinst_DATA) style.css README.html.in cli.html.in modules.html.in daemon.html.in +EXTRA_DIST = $(noinst_DATA) style.css README.html.in cli.html.in modules.html.in daemon.html.in todo MAINTAINERCLEANFILES = README README.html cli.html modules.html daemon.html CLEANFILES = diff --git a/src/polypaudio.pa b/src/polypaudio.pa new file mode 100755 index 00000000..177707ba --- /dev/null +++ b/src/polypaudio.pa @@ -0,0 +1,41 @@ +#!./polypaudio -F + +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + + +# Load audio drivers +load module-alsa-sink +load module-alsa-source device=plughw:1,0 +#load module-oss device="/dev/dsp" +#load module-oss-mmap device="/dev/dsp" + +# Load several protocols +load module-esound-protocol-tcp +load module-simple-protocol-tcp +load module-native-protocol-unix +load module-cli-protocol-unix + +# Load the CLI module +load module-cli + +.nofail + +# Make some devices default +sink_default alsa_output +source_default alsa_input + diff --git a/src/polypaudio.run b/src/polypaudio.run deleted file mode 100755 index 177707ba..00000000 --- a/src/polypaudio.run +++ /dev/null @@ -1,41 +0,0 @@ -#!./polypaudio -F - -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with polypaudio; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - - -# Load audio drivers -load module-alsa-sink -load module-alsa-source device=plughw:1,0 -#load module-oss device="/dev/dsp" -#load module-oss-mmap device="/dev/dsp" - -# Load several protocols -load module-esound-protocol-tcp -load module-simple-protocol-tcp -load module-native-protocol-unix -load module-cli-protocol-unix - -# Load the CLI module -load module-cli - -.nofail - -# Make some devices default -sink_default alsa_output -source_default alsa_input - -- cgit From 41f6aea8fdbc744c13bc461056a2d694a5c4d06f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 17 Jul 2004 14:12:30 +0000 Subject: rename src to polyp git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@90 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 363 ++++++++++++++++ polyp/alsa-util.c | 98 +++++ polyp/alsa-util.h | 35 ++ polyp/authkey.c | 151 +++++++ polyp/authkey.h | 31 ++ polyp/cli-command.c | 557 +++++++++++++++++++++++++ polyp/cli-command.h | 32 ++ polyp/cli.c | 148 +++++++ polyp/cli.h | 36 ++ polyp/client.c | 79 ++++ polyp/client.h | 51 +++ polyp/clitext.c | 203 +++++++++ polyp/clitext.h | 35 ++ polyp/cmdline.c | 111 +++++ polyp/cmdline.h | 36 ++ polyp/core.c | 88 ++++ polyp/core.h | 45 ++ polyp/depmod.py | 73 ++++ polyp/dynarray.c | 98 +++++ polyp/dynarray.h | 37 ++ polyp/endianmacros.h | 62 +++ polyp/esound.h | 213 ++++++++++ polyp/hashmap.c | 170 ++++++++ polyp/hashmap.h | 37 ++ polyp/idxset.c | 397 ++++++++++++++++++ polyp/idxset.h | 63 +++ polyp/iochannel.c | 222 ++++++++++ polyp/iochannel.h | 50 +++ polyp/ioline.c | 220 ++++++++++ polyp/ioline.h | 35 ++ polyp/main.c | 182 ++++++++ polyp/mainloop-api.c | 60 +++ polyp/mainloop-api.h | 65 +++ polyp/mainloop-signal.c | 163 ++++++++ polyp/mainloop-signal.h | 33 ++ polyp/mainloop.c | 553 ++++++++++++++++++++++++ polyp/mainloop.h | 37 ++ polyp/memblock.c | 113 +++++ polyp/memblock.h | 49 +++ polyp/memblockq.c | 326 +++++++++++++++ polyp/memblockq.h | 82 ++++ polyp/memchunk.c | 149 +++++++ polyp/memchunk.h | 41 ++ polyp/modargs.c | 288 +++++++++++++ polyp/modargs.h | 42 ++ polyp/module-alsa-sink.c | 259 ++++++++++++ polyp/module-alsa-source.c | 237 +++++++++++ polyp/module-cli.c | 73 ++++ polyp/module-oss-mmap.c | 404 ++++++++++++++++++ polyp/module-oss.c | 304 ++++++++++++++ polyp/module-pipe-sink.c | 218 ++++++++++ polyp/module-protocol-stub.c | 165 ++++++++ polyp/module.c | 161 +++++++ polyp/module.h | 55 +++ polyp/namereg.c | 136 ++++++ polyp/namereg.h | 38 ++ polyp/native-common.h | 68 +++ polyp/oss-util.c | 163 ++++++++ polyp/oss-util.h | 32 ++ polyp/pacat-simple.c | 83 ++++ polyp/pacat.c | 336 +++++++++++++++ polyp/packet.c | 72 ++++ polyp/packet.h | 41 ++ polyp/pactl.c | 166 ++++++++ polyp/parec-simple.c | 94 +++++ polyp/pdispatch.c | 247 +++++++++++ polyp/pdispatch.h | 52 +++ polyp/polypaudio.pa | 41 ++ polyp/polyplib-def.h | 40 ++ polyp/polyplib-error.c | 53 +++ polyp/polyplib-error.h | 29 ++ polyp/polyplib-simple.c | 259 ++++++++++++ polyp/polyplib-simple.h | 49 +++ polyp/polyplib.c | 973 +++++++++++++++++++++++++++++++++++++++++++ polyp/polyplib.h | 94 +++++ polyp/protocol-cli.c | 85 ++++ polyp/protocol-cli.h | 35 ++ polyp/protocol-esound.c | 847 +++++++++++++++++++++++++++++++++++++ polyp/protocol-esound.h | 35 ++ polyp/protocol-native.c | 863 ++++++++++++++++++++++++++++++++++++++ polyp/protocol-native.h | 35 ++ polyp/protocol-simple.c | 444 ++++++++++++++++++++ polyp/protocol-simple.h | 35 ++ polyp/pstream-util.c | 60 +++ polyp/pstream-util.h | 35 ++ polyp/pstream.c | 457 ++++++++++++++++++++ polyp/pstream.h | 51 +++ polyp/queue.c | 109 +++++ polyp/queue.h | 34 ++ polyp/resampler.c | 180 ++++++++ polyp/resampler.h | 37 ++ polyp/sample-util.c | 144 +++++++ polyp/sample-util.h | 48 +++ polyp/sample.c | 99 +++++ polyp/sample.h | 64 +++ polyp/sconv-s16be.c | 34 ++ polyp/sconv-s16be.h | 28 ++ polyp/sconv-s16le.c | 82 ++++ polyp/sconv-s16le.h | 28 ++ polyp/sconv.c | 137 ++++++ polyp/sconv.h | 33 ++ polyp/sink-input.c | 163 ++++++++ polyp/sink-input.h | 67 +++ polyp/sink.c | 292 +++++++++++++ polyp/sink.h | 67 +++ polyp/sioman.c | 42 ++ polyp/sioman.h | 28 ++ polyp/socket-client.c | 236 +++++++++++ polyp/socket-client.h | 41 ++ polyp/socket-server.c | 209 ++++++++++ polyp/socket-server.h | 41 ++ polyp/socket-util.c | 216 ++++++++++ polyp/socket-util.h | 41 ++ polyp/source-output.c | 101 +++++ polyp/source-output.h | 58 +++ polyp/source.c | 131 ++++++ polyp/source.h | 61 +++ polyp/strbuf.c | 164 ++++++++ polyp/strbuf.h | 36 ++ polyp/tagstruct.c | 241 +++++++++++ polyp/tagstruct.h | 53 +++ polyp/tokenizer.c | 89 ++++ polyp/tokenizer.h | 32 ++ polyp/util.c | 147 +++++++ polyp/util.h | 38 ++ src/Makefile.am | 363 ---------------- src/alsa-util.c | 98 ----- src/alsa-util.h | 35 -- src/authkey.c | 151 ------- src/authkey.h | 31 -- src/cli-command.c | 557 ------------------------- src/cli-command.h | 32 -- src/cli.c | 148 ------- src/cli.h | 36 -- src/client.c | 79 ---- src/client.h | 51 --- src/clitext.c | 203 --------- src/clitext.h | 35 -- src/cmdline.c | 111 ----- src/cmdline.h | 36 -- src/core.c | 88 ---- src/core.h | 45 -- src/depmod.py | 73 ---- src/dynarray.c | 98 ----- src/dynarray.h | 37 -- src/endianmacros.h | 62 --- src/esound.h | 213 ---------- src/hashmap.c | 170 -------- src/hashmap.h | 37 -- src/idxset.c | 397 ------------------ src/idxset.h | 63 --- src/iochannel.c | 222 ---------- src/iochannel.h | 50 --- src/ioline.c | 220 ---------- src/ioline.h | 35 -- src/main.c | 182 -------- src/mainloop-api.c | 60 --- src/mainloop-api.h | 65 --- src/mainloop-signal.c | 163 -------- src/mainloop-signal.h | 33 -- src/mainloop.c | 553 ------------------------ src/mainloop.h | 37 -- src/memblock.c | 113 ----- src/memblock.h | 49 --- src/memblockq.c | 326 --------------- src/memblockq.h | 82 ---- src/memchunk.c | 149 ------- src/memchunk.h | 41 -- src/modargs.c | 288 ------------- src/modargs.h | 42 -- src/module-alsa-sink.c | 259 ------------ src/module-alsa-source.c | 237 ----------- src/module-cli.c | 73 ---- src/module-oss-mmap.c | 404 ------------------ src/module-oss.c | 304 -------------- src/module-pipe-sink.c | 218 ---------- src/module-protocol-stub.c | 165 -------- src/module.c | 161 ------- src/module.h | 55 --- src/namereg.c | 136 ------ src/namereg.h | 38 -- src/native-common.h | 68 --- src/oss-util.c | 163 -------- src/oss-util.h | 32 -- src/pacat-simple.c | 83 ---- src/pacat.c | 336 --------------- src/packet.c | 72 ---- src/packet.h | 41 -- src/pactl.c | 166 -------- src/parec-simple.c | 94 ----- src/pdispatch.c | 247 ----------- src/pdispatch.h | 52 --- src/polypaudio.pa | 41 -- src/polyplib-def.h | 40 -- src/polyplib-error.c | 53 --- src/polyplib-error.h | 29 -- src/polyplib-simple.c | 259 ------------ src/polyplib-simple.h | 49 --- src/polyplib.c | 973 ------------------------------------------- src/polyplib.h | 94 ----- src/protocol-cli.c | 85 ---- src/protocol-cli.h | 35 -- src/protocol-esound.c | 847 ------------------------------------- src/protocol-esound.h | 35 -- src/protocol-native.c | 863 -------------------------------------- src/protocol-native.h | 35 -- src/protocol-simple.c | 444 -------------------- src/protocol-simple.h | 35 -- src/pstream-util.c | 60 --- src/pstream-util.h | 35 -- src/pstream.c | 457 -------------------- src/pstream.h | 51 --- src/queue.c | 109 ----- src/queue.h | 34 -- src/resampler.c | 180 -------- src/resampler.h | 37 -- src/sample-util.c | 144 ------- src/sample-util.h | 48 --- src/sample.c | 99 ----- src/sample.h | 64 --- src/sconv-s16be.c | 34 -- src/sconv-s16be.h | 28 -- src/sconv-s16le.c | 82 ---- src/sconv-s16le.h | 28 -- src/sconv.c | 137 ------ src/sconv.h | 33 -- src/sink-input.c | 163 -------- src/sink-input.h | 67 --- src/sink.c | 292 ------------- src/sink.h | 67 --- src/sioman.c | 42 -- src/sioman.h | 28 -- src/socket-client.c | 236 ----------- src/socket-client.h | 41 -- src/socket-server.c | 209 ---------- src/socket-server.h | 41 -- src/socket-util.c | 216 ---------- src/socket-util.h | 41 -- src/source-output.c | 101 ----- src/source-output.h | 58 --- src/source.c | 131 ------ src/source.h | 61 --- src/strbuf.c | 164 -------- src/strbuf.h | 36 -- src/tagstruct.c | 241 ----------- src/tagstruct.h | 53 --- src/tokenizer.c | 89 ---- src/tokenizer.h | 32 -- src/util.c | 147 ------- src/util.h | 38 -- 250 files changed, 17534 insertions(+), 17534 deletions(-) create mode 100644 polyp/Makefile.am create mode 100644 polyp/alsa-util.c create mode 100644 polyp/alsa-util.h create mode 100644 polyp/authkey.c create mode 100644 polyp/authkey.h create mode 100644 polyp/cli-command.c create mode 100644 polyp/cli-command.h create mode 100644 polyp/cli.c create mode 100644 polyp/cli.h create mode 100644 polyp/client.c create mode 100644 polyp/client.h create mode 100644 polyp/clitext.c create mode 100644 polyp/clitext.h create mode 100644 polyp/cmdline.c create mode 100644 polyp/cmdline.h create mode 100644 polyp/core.c create mode 100644 polyp/core.h create mode 100755 polyp/depmod.py create mode 100644 polyp/dynarray.c create mode 100644 polyp/dynarray.h create mode 100644 polyp/endianmacros.h create mode 100644 polyp/esound.h create mode 100644 polyp/hashmap.c create mode 100644 polyp/hashmap.h create mode 100644 polyp/idxset.c create mode 100644 polyp/idxset.h create mode 100644 polyp/iochannel.c create mode 100644 polyp/iochannel.h create mode 100644 polyp/ioline.c create mode 100644 polyp/ioline.h create mode 100644 polyp/main.c create mode 100644 polyp/mainloop-api.c create mode 100644 polyp/mainloop-api.h create mode 100644 polyp/mainloop-signal.c create mode 100644 polyp/mainloop-signal.h create mode 100644 polyp/mainloop.c create mode 100644 polyp/mainloop.h create mode 100644 polyp/memblock.c create mode 100644 polyp/memblock.h create mode 100644 polyp/memblockq.c create mode 100644 polyp/memblockq.h create mode 100644 polyp/memchunk.c create mode 100644 polyp/memchunk.h create mode 100644 polyp/modargs.c create mode 100644 polyp/modargs.h create mode 100644 polyp/module-alsa-sink.c create mode 100644 polyp/module-alsa-source.c create mode 100644 polyp/module-cli.c create mode 100644 polyp/module-oss-mmap.c create mode 100644 polyp/module-oss.c create mode 100644 polyp/module-pipe-sink.c create mode 100644 polyp/module-protocol-stub.c create mode 100644 polyp/module.c create mode 100644 polyp/module.h create mode 100644 polyp/namereg.c create mode 100644 polyp/namereg.h create mode 100644 polyp/native-common.h create mode 100644 polyp/oss-util.c create mode 100644 polyp/oss-util.h create mode 100644 polyp/pacat-simple.c create mode 100644 polyp/pacat.c create mode 100644 polyp/packet.c create mode 100644 polyp/packet.h create mode 100644 polyp/pactl.c create mode 100644 polyp/parec-simple.c create mode 100644 polyp/pdispatch.c create mode 100644 polyp/pdispatch.h create mode 100755 polyp/polypaudio.pa create mode 100644 polyp/polyplib-def.h create mode 100644 polyp/polyplib-error.c create mode 100644 polyp/polyplib-error.h create mode 100644 polyp/polyplib-simple.c create mode 100644 polyp/polyplib-simple.h create mode 100644 polyp/polyplib.c create mode 100644 polyp/polyplib.h create mode 100644 polyp/protocol-cli.c create mode 100644 polyp/protocol-cli.h create mode 100644 polyp/protocol-esound.c create mode 100644 polyp/protocol-esound.h create mode 100644 polyp/protocol-native.c create mode 100644 polyp/protocol-native.h create mode 100644 polyp/protocol-simple.c create mode 100644 polyp/protocol-simple.h create mode 100644 polyp/pstream-util.c create mode 100644 polyp/pstream-util.h create mode 100644 polyp/pstream.c create mode 100644 polyp/pstream.h create mode 100644 polyp/queue.c create mode 100644 polyp/queue.h create mode 100644 polyp/resampler.c create mode 100644 polyp/resampler.h create mode 100644 polyp/sample-util.c create mode 100644 polyp/sample-util.h create mode 100644 polyp/sample.c create mode 100644 polyp/sample.h create mode 100644 polyp/sconv-s16be.c create mode 100644 polyp/sconv-s16be.h create mode 100644 polyp/sconv-s16le.c create mode 100644 polyp/sconv-s16le.h create mode 100644 polyp/sconv.c create mode 100644 polyp/sconv.h create mode 100644 polyp/sink-input.c create mode 100644 polyp/sink-input.h create mode 100644 polyp/sink.c create mode 100644 polyp/sink.h create mode 100644 polyp/sioman.c create mode 100644 polyp/sioman.h create mode 100644 polyp/socket-client.c create mode 100644 polyp/socket-client.h create mode 100644 polyp/socket-server.c create mode 100644 polyp/socket-server.h create mode 100644 polyp/socket-util.c create mode 100644 polyp/socket-util.h create mode 100644 polyp/source-output.c create mode 100644 polyp/source-output.h create mode 100644 polyp/source.c create mode 100644 polyp/source.h create mode 100644 polyp/strbuf.c create mode 100644 polyp/strbuf.h create mode 100644 polyp/tagstruct.c create mode 100644 polyp/tagstruct.h create mode 100644 polyp/tokenizer.c create mode 100644 polyp/tokenizer.h create mode 100644 polyp/util.c create mode 100644 polyp/util.h delete mode 100644 src/Makefile.am delete mode 100644 src/alsa-util.c delete mode 100644 src/alsa-util.h delete mode 100644 src/authkey.c delete mode 100644 src/authkey.h delete mode 100644 src/cli-command.c delete mode 100644 src/cli-command.h delete mode 100644 src/cli.c delete mode 100644 src/cli.h delete mode 100644 src/client.c delete mode 100644 src/client.h delete mode 100644 src/clitext.c delete mode 100644 src/clitext.h delete mode 100644 src/cmdline.c delete mode 100644 src/cmdline.h delete mode 100644 src/core.c delete mode 100644 src/core.h delete mode 100755 src/depmod.py delete mode 100644 src/dynarray.c delete mode 100644 src/dynarray.h delete mode 100644 src/endianmacros.h delete mode 100644 src/esound.h delete mode 100644 src/hashmap.c delete mode 100644 src/hashmap.h delete mode 100644 src/idxset.c delete mode 100644 src/idxset.h delete mode 100644 src/iochannel.c delete mode 100644 src/iochannel.h delete mode 100644 src/ioline.c delete mode 100644 src/ioline.h delete mode 100644 src/main.c delete mode 100644 src/mainloop-api.c delete mode 100644 src/mainloop-api.h delete mode 100644 src/mainloop-signal.c delete mode 100644 src/mainloop-signal.h delete mode 100644 src/mainloop.c delete mode 100644 src/mainloop.h delete mode 100644 src/memblock.c delete mode 100644 src/memblock.h delete mode 100644 src/memblockq.c delete mode 100644 src/memblockq.h delete mode 100644 src/memchunk.c delete mode 100644 src/memchunk.h delete mode 100644 src/modargs.c delete mode 100644 src/modargs.h delete mode 100644 src/module-alsa-sink.c delete mode 100644 src/module-alsa-source.c delete mode 100644 src/module-cli.c delete mode 100644 src/module-oss-mmap.c delete mode 100644 src/module-oss.c delete mode 100644 src/module-pipe-sink.c delete mode 100644 src/module-protocol-stub.c delete mode 100644 src/module.c delete mode 100644 src/module.h delete mode 100644 src/namereg.c delete mode 100644 src/namereg.h delete mode 100644 src/native-common.h delete mode 100644 src/oss-util.c delete mode 100644 src/oss-util.h delete mode 100644 src/pacat-simple.c delete mode 100644 src/pacat.c delete mode 100644 src/packet.c delete mode 100644 src/packet.h delete mode 100644 src/pactl.c delete mode 100644 src/parec-simple.c delete mode 100644 src/pdispatch.c delete mode 100644 src/pdispatch.h delete mode 100755 src/polypaudio.pa delete mode 100644 src/polyplib-def.h delete mode 100644 src/polyplib-error.c delete mode 100644 src/polyplib-error.h delete mode 100644 src/polyplib-simple.c delete mode 100644 src/polyplib-simple.h delete mode 100644 src/polyplib.c delete mode 100644 src/polyplib.h delete mode 100644 src/protocol-cli.c delete mode 100644 src/protocol-cli.h delete mode 100644 src/protocol-esound.c delete mode 100644 src/protocol-esound.h delete mode 100644 src/protocol-native.c delete mode 100644 src/protocol-native.h delete mode 100644 src/protocol-simple.c delete mode 100644 src/protocol-simple.h delete mode 100644 src/pstream-util.c delete mode 100644 src/pstream-util.h delete mode 100644 src/pstream.c delete mode 100644 src/pstream.h delete mode 100644 src/queue.c delete mode 100644 src/queue.h delete mode 100644 src/resampler.c delete mode 100644 src/resampler.h delete mode 100644 src/sample-util.c delete mode 100644 src/sample-util.h delete mode 100644 src/sample.c delete mode 100644 src/sample.h delete mode 100644 src/sconv-s16be.c delete mode 100644 src/sconv-s16be.h delete mode 100644 src/sconv-s16le.c delete mode 100644 src/sconv-s16le.h delete mode 100644 src/sconv.c delete mode 100644 src/sconv.h delete mode 100644 src/sink-input.c delete mode 100644 src/sink-input.h delete mode 100644 src/sink.c delete mode 100644 src/sink.h delete mode 100644 src/sioman.c delete mode 100644 src/sioman.h delete mode 100644 src/socket-client.c delete mode 100644 src/socket-client.h delete mode 100644 src/socket-server.c delete mode 100644 src/socket-server.h delete mode 100644 src/socket-util.c delete mode 100644 src/socket-util.h delete mode 100644 src/source-output.c delete mode 100644 src/source-output.h delete mode 100644 src/source.c delete mode 100644 src/source.h delete mode 100644 src/strbuf.c delete mode 100644 src/strbuf.h delete mode 100644 src/tagstruct.c delete mode 100644 src/tagstruct.h delete mode 100644 src/tokenizer.c delete mode 100644 src/tokenizer.h delete mode 100644 src/util.c delete mode 100644 src/util.h diff --git a/polyp/Makefile.am b/polyp/Makefile.am new file mode 100644 index 00000000..c4da7342 --- /dev/null +++ b/polyp/Makefile.am @@ -0,0 +1,363 @@ +# $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +AM_CFLAGS=-ansi -D_GNU_SOURCE + +EXTRA_DIST = polypaudio.run depmod.py +bin_PROGRAMS = polypaudio pacat pactl +noinst_PROGRAMS = pacat-simple parec-simple + +pkginclude_HEADERS=polyplib.h \ + polyplib-def.h \ + polyplib-simple.h \ + polyplib-error.h \ + mainloop-api.h \ + mainloop.h \ + mainloop-signal.h \ + sample.h + +pkglib_LTLIBRARIES=libiochannel.la \ + libsocket-server.la \ + libsocket-client.la \ + libpstream.la \ + libpacket.la \ + liboss-util.la \ + libalsa-util.la \ + libioline.la \ + libcli.la \ + libprotocol-cli.la \ + libtagstruct.la \ + libpstream-util.la \ + libpdispatch.la \ + libauthkey.la \ + libsocket-util.la \ + libprotocol-simple.la \ + libprotocol-esound.la \ + libprotocol-native.la \ + module-cli.la \ + module-cli-protocol-tcp.la \ + module-cli-protocol-unix.la \ + module-pipe-sink.la \ + module-alsa-sink.la \ + module-alsa-source.la \ + module-oss.la \ + module-oss-mmap.la \ + module-simple-protocol-tcp.la \ + module-simple-protocol-unix.la \ + module-esound-protocol-tcp.la \ + module-esound-protocol-unix.la \ + module-native-protocol-tcp.la \ + module-native-protocol-unix.la + +lib_LTLIBRARIES=libpolyp.la \ + libpolyp-simple.la \ + libpolyp-error.la \ + libpolyp-mainloop.la + +polypaudio_SOURCES = idxset.c idxset.h \ + queue.c queue.h \ + strbuf.c strbuf.h \ + main.c \ + mainloop.c mainloop.h \ + memblock.c memblock.h \ + sample.c sample.h \ + sample-util.c sample-util.h \ + memblockq.c memblockq.h \ + client.c client.h \ + core.c core.h \ + source-output.c source-output.h \ + sink-input.c sink-input.h \ + source.c source.h \ + sink.c sink.h \ + module.c module.h \ + mainloop-signal.c mainloop-signal.h \ + mainloop-api.c mainloop-api.h \ + util.c util.h \ + hashmap.c hashmap.h \ + namereg.c namereg.h \ + sconv.c sconv.h \ + resampler.c resampler.h \ + endianmacros.h \ + memchunk.c memchunk.h \ + sconv-s16le.c sconv-s16le.h \ + sconv-s16be.c sconv-s16be.h \ + sioman.c sioman.h \ + modargs.c modargs.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) +polypaudio_LDADD = $(LIBLTDL) $(LIBSAMPLERATE_LIBS) +polypaudio_LDFLAGS=-export-dynamic + +libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h +libprotocol_simple_la_LDFLAGS = -avoid-version +libprotocol_simple_la_LIBADD = libsocket-server.la libiochannel.la + +libsocket_server_la_SOURCES = socket-server.c socket-server.h +libsocket_server_la_LDFLAGS = -avoid-version +libsocket_server_la_LIBADD = libiochannel.la libsocket-util.la + +libsocket_client_la_SOURCES = socket-client.c socket-client.h +libsocket_client_la_LDFLAGS = -avoid-version +libsocket_client_la_LIBADD = libiochannel.la libsocket-util.la + +libpstream_la_SOURCES = pstream.c pstream.h +libpstream_la_LDFLAGS = -avoid-version +libpstream_la_LIBADD = libpacket.la libiochannel.la + +libpstream_util_la_SOURCES = pstream-util.c pstream-util.h +libpstream_util_la_LDFLAGS = -avoid-version +libpstream_util_la_LIBADD = libpacket.la libpstream.la libtagstruct.la + +libpdispatch_la_SOURCES = pdispatch.c pdispatch.h +libpdispatch_la_LDFLAGS = -avoid-version +libpdispatch_la_LIBADD = libtagstruct.la + +libiochannel_la_SOURCES = iochannel.c iochannel.h +libiochannel_la_LDFLAGS = -avoid-version +libiochannel_la_LIBADD = libsocket-util.la + +libpacket_la_SOURCES = packet.c packet.h +libpacket_la_LDFLAGS = -avoid-version + +liboss_util_la_SOURCES = oss-util.c oss-util.h +liboss_util_la_LDFLAGS = -avoid-version + +libalsa_util_la_SOURCES = alsa-util.c alsa-util.h +libalsa_util_la_LDFLAGS = -avoid-version +libalsa_util_la_LIBADD = $(ASOUNDLIB_LIBS) +libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) + +libioline_la_SOURCES = ioline.c ioline.h +libioline_la_LDFLAGS = -avoid-version +libioline_la_LIBADD = libiochannel.la + +libcli_la_SOURCES = cli.c cli.h +libcli_la_LDFLAGS = -avoid-version +libcli_la_LIBADD = libiochannel.la libioline.la + +libprotocol_cli_la_SOURCES = protocol-cli.c protocol-cli.h +libprotocol_cli_la_LDFLAGS = -avoid-version +libprotocol_cli_la_LIBADD = libsocket-server.la libiochannel.la libcli.la + +libprotocol_native_la_SOURCES = protocol-native.c protocol-native.h native-common.h +libprotocol_native_la_LDFLAGS = -avoid-version +libprotocol_native_la_LIBADD = libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la + +libtagstruct_la_SOURCES = tagstruct.c tagstruct.h +libtagstruct_la_LDFLAGS = -avoid-version + +libprotocol_esound_la_SOURCES = protocol-esound.c protocol-esound.h esound.h +libprotocol_esound_la_LDFLAGS = -avoid-version +libprotocol_esound_la_LIBADD = libsocket-server.la libiochannel.la libauthkey.la + +libauthkey_la_SOURCES = authkey.c authkey.h +libauthkey_la_LDFLAGS = -avoid-version + +libsocket_util_la_SOURCES = socket-util.c socket-util.h +libsocket_util_la_LDFLAGS = -avoid-version + +module_simple_protocol_tcp_la_SOURCES = module-protocol-stub.c +module_simple_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) +module_simple_protocol_tcp_la_LDFLAGS = -module -avoid-version +module_simple_protocol_tcp_la_LIBADD = libprotocol-simple.la libsocket-server.la + +module_simple_protocol_unix_la_SOURCES = module-protocol-stub.c +module_simple_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) +module_simple_protocol_unix_la_LDFLAGS = -module -avoid-version +module_simple_protocol_unix_la_LIBADD = libprotocol-simple.la libsocket-server.la libsocket-util.la + +module_cli_protocol_tcp_la_SOURCES = module-protocol-stub.c +module_cli_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) +module_cli_protocol_tcp_la_LDFLAGS = -module -avoid-version +module_cli_protocol_tcp_la_LIBADD = libprotocol-cli.la libsocket-server.la + +module_cli_protocol_unix_la_SOURCES = module-protocol-stub.c +module_cli_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) +module_cli_protocol_unix_la_LDFLAGS = -module -avoid-version +module_cli_protocol_unix_la_LIBADD = libprotocol-cli.la libsocket-server.la libsocket-util.la + +module_native_protocol_tcp_la_SOURCES = module-protocol-stub.c +module_native_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) +module_native_protocol_tcp_la_LDFLAGS = -module -avoid-version +module_native_protocol_tcp_la_LIBADD = libprotocol-native.la libsocket-server.la + +module_native_protocol_unix_la_SOURCES = module-protocol-stub.c +module_native_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) +module_native_protocol_unix_la_LDFLAGS = -module -avoid-version +module_native_protocol_unix_la_LIBADD = libprotocol-native.la libsocket-server.la libsocket-util.la + +module_esound_protocol_tcp_la_SOURCES = module-protocol-stub.c +module_esound_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) +module_esound_protocol_tcp_la_LDFLAGS = -module -avoid-version +module_esound_protocol_tcp_la_LIBADD = libprotocol-esound.la libsocket-server.la + +module_esound_protocol_unix_la_SOURCES = module-protocol-stub.c +module_esound_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) +module_esound_protocol_unix_la_LDFLAGS = -module -avoid-version +module_esound_protocol_unix_la_LIBADD = libprotocol-esound.la libsocket-server.la libsocket-util.la + +module_pipe_sink_la_SOURCES = module-pipe-sink.c +module_pipe_sink_la_LDFLAGS = -module -avoid-version +module_pipe_sink_la_LIBADD = libiochannel.la + +module_alsa_sink_la_SOURCES = module-alsa-sink.c +module_alsa_sink_la_LDFLAGS = -module -avoid-version +module_alsa_sink_la_LIBADD = $(ASOUNDLIB_LIBS) libalsa-util.la +module_alsa_sink_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) + +module_alsa_source_la_SOURCES = module-alsa-source.c +module_alsa_source_la_LDFLAGS = -module -avoid-version +module_alsa_source_la_LIBADD = $(ASOUNDLIB_LIBS) libalsa-util.la +module_alsa_source_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) + +module_oss_la_SOURCES = module-oss.c +module_oss_la_LDFLAGS = -module -avoid-version +module_oss_la_LIBADD = libiochannel.la liboss-util.la + +module_oss_mmap_la_SOURCES = module-oss-mmap.c +module_oss_mmap_la_LDFLAGS = -module -avoid-version +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 + +libpolyp_la_SOURCES = polyplib.c polyplib.h \ + polyplib-def.h \ + tagstruct.c tagstruct.h \ + iochannel.c iochannel.h \ + pstream.c pstream.h \ + pstream-util.c pstream-util.h \ + pdispatch.c pdispatch.h \ + mainloop-api.c mainloop-api.h \ + idxset.c idxset.h \ + util.c util.h \ + memblock.c memblock.h \ + socket-client.c socket-client.h \ + packet.c packet.h \ + queue.c queue.h \ + dynarray.c dynarray.h \ + memchunk.c memchunk.h \ + authkey.c authkey.h \ + socket-util.c socket-util.h \ + native-common.h +libpolyp_la_CFLAGS = $(AM_CFLAGS) + +libpolyp_mainloop_la_SOURCES = mainloop-api.h mainloop-api.c \ + mainloop.c mainloop.h \ + mainloop-signal.c mainloop-signal.h +libpolyp_mainloop_la_CFLAGS = $(AM_CFLAGS) + +libpolyp_error_la_SOURCES = polyplib-error.c polyplib-error.h +libpolyp_error_la_CFLAGS = $(AM_CFLAGS) + +libpolyp_simple_la_SOURCES = polyplib-simple.c polyplib-simple.h +libpolyp_simple_la_CFLAGS = $(AM_CFLAGS) +libpolyp_simple_la_LIBADD = libpolyp.la libpolyp-mainloop.la + +pacat_SOURCES = pacat.c +pacat_LDADD = libpolyp.la libpolyp-error.la libpolyp-mainloop.la +pacat_CFLAGS = $(AM_CFLAGS) + +pactl_SOURCES = pactl.c +pactl_LDADD = libpolyp.la libpolyp-error.la libpolyp-mainloop.la +pactl_CFLAGS = $(AM_CFLAGS) + +pacat_simple_SOURCES = pacat-simple.c +pacat_simple_LDADD = libpolyp-simple.la libpolyp-error.la +pacat_simple_CFLAGS = $(AM_CFLAGS) + +parec_simple_SOURCES = parec-simple.c +parec_simple_LDADD = libpolyp-simple.la libpolyp-error.la +parec_simple_CFLAGS = $(AM_CFLAGS) + +if BUILD_LIBPOLYPCORE + +pkginclude_HEADERS+=cli-command.h\ + client.h \ + core.h \ + dynarray.h \ + endianmacros.h \ + hashmap.h \ + idxset.h \ + iochannel.h \ + memblock.h \ + memblockq.h \ + memchunk.h \ + modargs.h \ + module.h \ + namereg.h \ + queue.h \ + resampler.h \ + sample-util.h \ + sink.h \ + sink-input.h \ + sioman.h \ + socket-server.h \ + socket-client.h \ + socket-util.h \ + source.h \ + source-output.h \ + strbuf.h \ + tokenizer.h \ + tagstruct.h \ + util.h + +lib_LTLIBRARIES+= libpolypcore.la + +libpolypcore_la_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 \ + sample-util.c sample-util.h \ + memblockq.c memblockq.h \ + client.c client.h \ + core.c core.h \ + source-output.c source-output.h \ + sink-input.c sink-input.h \ + source.c source.h \ + sink.c sink.h \ + module.c module.h \ + mainloop-signal.c mainloop-signal.h \ + mainloop-api.c mainloop-api.h \ + util.c util.h \ + hashmap.c hashmap.h \ + namereg.c namereg.h \ + sconv.c sconv.h \ + resampler.c resampler.h \ + endianmacros.h \ + memchunk.c memchunk.h \ + sconv-s16le.c sconv-s16le.h \ + sconv-s16be.c sconv-s16be.h \ + sioman.c sioman.h \ + modargs.c modargs.h \ + cli-command.c cli-command.h \ + clitext.c clitext.h \ + tokenizer.c tokenizer.h \ + dynarray.c dynarray.h + +endif diff --git a/polyp/alsa-util.c b/polyp/alsa-util.c new file mode 100644 index 00000000..7f266df5 --- /dev/null +++ b/polyp/alsa-util.c @@ -0,0 +1,98 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "alsa-util.h" +#include "sample.h" + +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, struct pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *buffer_size) { + int ret = 0; + snd_pcm_hw_params_t *hwparams = NULL; + static const snd_pcm_format_t format_trans[] = { + [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8, + [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW, + [PA_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW, + [PA_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE, + [PA_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE, + [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE, + [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, + }; + + if (snd_pcm_hw_params_malloc(&hwparams) < 0 || + snd_pcm_hw_params_any(pcm_handle, hwparams) < 0 || + snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0 || + snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format]) < 0 || + snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &ss->rate, NULL) < 0 || + snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels) < 0 || + snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, periods, NULL) < 0 || + snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, buffer_size) < 0 || + snd_pcm_hw_params(pcm_handle, hwparams) < 0) { + ret = -1; + } + + if (hwparams) + snd_pcm_hw_params_free(hwparams); + return ret; +} + +int pa_create_io_sources(snd_pcm_t *pcm_handle, struct pa_mainloop_api* m, void ***io_sources, unsigned *n_io_sources, void (*cb)(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata), void *userdata) { + unsigned i; + struct pollfd *pfds, *ppfd; + void **ios; + assert(pcm_handle && m && io_sources && n_io_sources && cb); + + *n_io_sources = snd_pcm_poll_descriptors_count(pcm_handle); + + pfds = malloc(sizeof(struct pollfd) * *n_io_sources); + assert(pfds); + if (snd_pcm_poll_descriptors(pcm_handle, pfds, *n_io_sources) < 0) { + free(pfds); + return -1; + } + + *io_sources = malloc(sizeof(void*) * *n_io_sources); + assert(io_sources); + + for (i = 0, ios = *io_sources, ppfd = pfds; i < *n_io_sources; i++, ios++, ppfd++) { + *ios = m->source_io(m, ppfd->fd, + ((ppfd->events & POLLIN) ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | + ((ppfd->events & POLLOUT) ? PA_MAINLOOP_API_IO_EVENT_OUTPUT : 0), cb, userdata); + assert(*ios); + } + + free(pfds); + return 0; +} + +void pa_free_io_sources(struct pa_mainloop_api* m, void **io_sources, unsigned n_io_sources) { + unsigned i; + void **ios; + assert(m && io_sources); + + for (ios = io_sources, i = 0; i < n_io_sources; i++, ios++) + m->cancel_io(m, *ios); + free(io_sources); +} diff --git a/polyp/alsa-util.h b/polyp/alsa-util.h new file mode 100644 index 00000000..03e427d9 --- /dev/null +++ b/polyp/alsa-util.h @@ -0,0 +1,35 @@ +#ifndef fooalsautilhfoo +#define fooalsautilhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "sample.h" +#include "mainloop-api.h" + +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, struct pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *buffer_size); + +int pa_create_io_sources(snd_pcm_t *pcm_handle, struct pa_mainloop_api *m, void ***io_sources, unsigned *n_io_sources, void (*cb)(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata), void *userdata); +void pa_free_io_sources(struct pa_mainloop_api* m, void **io_sources, unsigned n_io_sources); + +#endif diff --git a/polyp/authkey.c b/polyp/authkey.c new file mode 100644 index 00000000..3180b8fd --- /dev/null +++ b/polyp/authkey.c @@ -0,0 +1,151 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "authkey.h" +#include "util.h" + +#define RANDOM_DEVICE "/dev/urandom" + +static int load(const char *fn, void *data, size_t length) { + int fd = -1, ret = -1; + ssize_t r; + + assert(fn && data && length); + + if ((fd = open(fn, O_RDONLY)) < 0) + goto finish; + + if ((r = pa_loop_read(fd, data, length)) < 0 || (size_t) r != length) { + ret = -2; + goto finish; + } + + ret = 0; + +finish: + if (fd >= 0) + close(fd); + + return ret; +} + +static int generate(const char *fn, void *data, size_t length) { + int fd = -1, random_fd = -1, ret = -1; + ssize_t r; + assert(fn && data && length); + + if ((fd = open(fn, O_WRONLY|O_EXCL|O_CREAT, S_IRUSR | S_IWUSR)) < 0) + goto finish; + + if ((random_fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) { + + if ((r = pa_loop_read(random_fd, data, length)) < 0 || (size_t) r != length) { + ret = -2; + goto finish; + } + + } else { + uint8_t *p; + size_t l; + fprintf(stderr, "WARNING: Failed to open entropy device '"RANDOM_DEVICE"': %s, falling back to unsecure pseudo RNG.\n", strerror(errno)); + + srandom(time(NULL)); + + for (p = data, l = length; l > 0; p++, l--) + *p = (uint8_t) random(); + } + + if ((r = pa_loop_write(fd, data, length)) < 0 || (size_t) r != length) { + ret = -2; + goto finish; + } + + ret = 0; + +finish: + if (fd >= 0) { + if (ret != 0) + unlink(fn); + close(fd); + } + if (random_fd >= 0) + close(random_fd); + + return ret; +} + +int pa_authkey_load(const char *path, void *data, size_t length) { + int ret, i; + + assert(path && data && length); + + for (i = 0; i < 10; i++) { + if ((ret = load(path, data, length)) < 0) + if (ret == -1 && errno == ENOENT) + if ((ret = generate(path, data, length)) < 0) + if (ret == -1 && errno == EEXIST) + continue; + break; + } + + if (ret < 0) + fprintf(stderr, "Failed to load authorization key '%s': %s\n", path, (ret == -1) ? strerror(errno) : "file corrupt"); + + return ret; +} + +int pa_authkey_load_from_home(const char *fn, void *data, size_t length) { + char *home; + char path[PATH_MAX]; + + assert(fn && data && length); + + if (!(home = getenv("HOME"))) + return -2; + + snprintf(path, sizeof(path), "%s/%s", home, fn); + + return pa_authkey_load(path, data, length); +} + +int pa_authkey_load_auto(const char *fn, void *data, size_t length) { + assert(fn && data && length); + + if (*fn == '/') + return pa_authkey_load(fn, data, length); + else + return pa_authkey_load_from_home(fn, data, length); +} diff --git a/polyp/authkey.h b/polyp/authkey.h new file mode 100644 index 00000000..acdcc24d --- /dev/null +++ b/polyp/authkey.h @@ -0,0 +1,31 @@ +#ifndef fooauthkeyhfoo +#define fooauthkeyhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +int pa_authkey_load(const char *path, void *data, size_t len); +int pa_authkey_load_from_home(const char *fn, void *data, size_t length); +int pa_authkey_load_auto(const char *fn, void *data, size_t length); + +#endif diff --git a/polyp/cli-command.c b/polyp/cli-command.c new file mode 100644 index 00000000..f3a2f8a0 --- /dev/null +++ b/polyp/cli-command.c @@ -0,0 +1,557 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "cli-command.h" +#include "module.h" +#include "sink.h" +#include "source.h" +#include "client.h" +#include "sink-input.h" +#include "source-output.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_get_count(), pa_memblock_get_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/polyp/cli-command.h b/polyp/cli-command.h new file mode 100644 index 00000000..b3c601ad --- /dev/null +++ b/polyp/cli-command.h @@ -0,0 +1,32 @@ +#ifndef fooclicommandhfoo +#define fooclicommandhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#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/polyp/cli.c b/polyp/cli.c new file mode 100644 index 00000000..f2aa5a65 --- /dev/null +++ b/polyp/cli.c @@ -0,0 +1,148 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "ioline.h" +#include "cli.h" +#include "module.h" +#include "sink.h" +#include "source.h" +#include "client.h" +#include "sink-input.h" +#include "source-output.h" +#include "tokenizer.h" +#include "strbuf.h" +#include "namereg.h" +#include "clitext.h" +#include "cli-command.h" + +struct pa_cli { + struct pa_core *core; + struct pa_ioline *line; + + void (*eof_callback)(struct pa_cli *c, void *userdata); + void *userdata; + + struct pa_client *client; + + int fail, verbose, kill_requested, defer_kill; +}; + +static void line_callback(struct pa_ioline *line, const char *s, void *userdata); + +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, struct pa_module *m) { + char cname[256]; + struct pa_cli *c; + assert(io); + + c = malloc(sizeof(struct pa_cli)); + assert(c); + c->core = core; + c->line = pa_ioline_new(io); + assert(c->line); + + c->userdata = NULL; + c->eof_callback = NULL; + + pa_iochannel_socket_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; + c->client->owner = m; + + 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; +} + +void pa_cli_free(struct pa_cli *c) { + assert(c); + pa_ioline_free(c->line); + pa_client_free(c->client); + 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->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; + char *p; + assert(line && c); + + if (!s) { + fprintf(stderr, "CLI got EOF from user.\n"); + if (c->eof_callback) + c->eof_callback(c, c->userdata); + + return; + } + + 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 (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) { + assert(c && cb); + c->eof_callback = cb; + c->userdata = userdata; +} diff --git a/polyp/cli.h b/polyp/cli.h new file mode 100644 index 00000000..9cfee0d8 --- /dev/null +++ b/polyp/cli.h @@ -0,0 +1,36 @@ +#ifndef fooclihfoo +#define fooclihfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "iochannel.h" +#include "core.h" +#include "module.h" + +struct pa_cli; + +struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io, struct pa_module *m); +void pa_cli_free(struct pa_cli *cli); + +void pa_cli_set_eof_callback(struct pa_cli *cli, void (*cb)(struct pa_cli*c, void *userdata), void *userdata); + +#endif diff --git a/polyp/client.c b/polyp/client.c new file mode 100644 index 00000000..0294c9e2 --- /dev/null +++ b/polyp/client.c @@ -0,0 +1,79 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "client.h" + +struct pa_client *pa_client_new(struct pa_core *core, const char *protocol_name, char *name) { + struct pa_client *c; + int r; + assert(core); + + c = malloc(sizeof(struct pa_client)); + assert(c); + c->name = name ? strdup(name) : NULL; + c->owner = NULL; + c->core = core; + c->protocol_name = protocol_name; + + c->kill = NULL; + c->userdata = NULL; + + r = pa_idxset_put(core->clients, c, &c->index); + assert(c->index != PA_IDXSET_INVALID && r >= 0); + + fprintf(stderr, "client: created %u \"%s\"\n", c->index, c->name); + + return c; +} + +void pa_client_free(struct pa_client *c) { + assert(c && c->core); + + pa_idxset_remove_by_data(c->core->clients, c, NULL); + fprintf(stderr, "client: freed %u \"%s\"\n", c->index, c->name); + free(c->name); + free(c); +} + +void pa_client_kill(struct pa_client *c) { + assert(c); + if (!c->kill) { + fprintf(stderr, "kill() operation not implemented for client %u\n", c->index); + return; + } + + c->kill(c); +} + +void pa_client_rename(struct pa_client *c, const char *name) { + assert(c); + free(c->name); + c->name = name ? strdup(name) : NULL; +} diff --git a/polyp/client.h b/polyp/client.h new file mode 100644 index 00000000..c926208e --- /dev/null +++ b/polyp/client.h @@ -0,0 +1,51 @@ +#ifndef fooclienthfoo +#define fooclienthfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" +#include "module.h" + +struct pa_client { + uint32_t index; + + struct pa_module *owner; + char *name; + struct pa_core *core; + const char *protocol_name; + + void (*kill)(struct pa_client *c); + void *userdata; +}; + +struct pa_client *pa_client_new(struct pa_core *c, const char *protocol_name, char *name); + +/* This function should be called only by the code that created the client */ +void pa_client_free(struct pa_client *c); + +/* Code that didn't create the client should call this function to + * request destruction of the client */ +void pa_client_kill(struct pa_client *c); + +void pa_client_rename(struct pa_client *c, const char *name); + +#endif diff --git a/polyp/clitext.c b/polyp/clitext.c new file mode 100644 index 00000000..c1b9953b --- /dev/null +++ b/polyp/clitext.c @@ -0,0 +1,203 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "clitext.h" +#include "module.h" +#include "client.h" +#include "sink.h" +#include "source.h" +#include "sink-input.h" +#include "source-output.h" +#include "strbuf.h" +#include "sample-util.h" + +char *pa_module_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_module *m; + uint32_t index = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_ncontents(c->modules)); + + for (m = pa_idxset_first(c->modules, &index); m; m = pa_idxset_next(c->modules, &index)) + pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\targument: <%s>\n", m->index, m->name, m->argument); + + return pa_strbuf_tostring_free(s); +} + +char *pa_client_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_client *client; + uint32_t index = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u client(s).\n", pa_idxset_ncontents(c->clients)); + + for (client = pa_idxset_first(c->clients, &index); client; client = pa_idxset_next(c->clients, &index)) { + pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\tprotocol_name: <%s>\n", client->index, client->name, client->protocol_name); + + if (client->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", client->owner->index); + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_sink_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_sink *sink, *default_sink; + uint32_t index = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_ncontents(c->sinks)); + + default_sink = pa_sink_get_default(c); + + for (sink = pa_idxset_first(c->sinks, &index); sink; sink = pa_idxset_next(c->sinks, &index)) { + char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + pa_sample_snprint(ss, sizeof(ss), &sink->sample_spec); + assert(sink->monitor_source); + pa_strbuf_printf( + s, + " %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", + sink == default_sink ? '*' : ' ', + sink->index, sink->name, + (unsigned) sink->volume, + pa_sink_get_latency(sink), + sink->monitor_source->index, + ss); + + if (sink->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", sink->owner->index); + if (sink->description) + pa_strbuf_printf(s, "\tdescription: <%s>\n", sink->description); + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_source_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_source *source, *default_source; + uint32_t index = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_ncontents(c->sources)); + + default_source = pa_source_get_default(c); + + for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) { + char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + pa_sample_snprint(ss, sizeof(ss), &source->sample_spec); + pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\tsample_spec: <%s>\n", source == default_source ? '*' : ' ', source->index, source->name, ss); + + if (source->monitor_of) + pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index); + if (source->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", source->owner->index); + if (source->description) + pa_strbuf_printf(s, "\tdescription: <%s>\n", source->description); + } + + return pa_strbuf_tostring_free(s); +} + + +char *pa_source_output_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_source_output *o; + uint32_t index = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_ncontents(c->source_outputs)); + + for (o = pa_idxset_first(c->source_outputs, &index); o; o = pa_idxset_next(c->source_outputs, &index)) { + char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + pa_sample_snprint(ss, sizeof(ss), &o->sample_spec); + assert(o->source); + pa_strbuf_printf( + s, " index: %u\n\tname: <%s>\n\tsource: <%u>\n\tsample_spec: <%s>\n", + o->index, + o->name, + o->source->index, + ss); + if (o->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", o->owner->index); + if (o->client) + pa_strbuf_printf(s, "\tclient: <%u>\n", o->client->index); + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_sink_input_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_sink_input *i; + uint32_t index = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_ncontents(c->sink_inputs)); + + for (i = pa_idxset_first(c->sink_inputs, &index); i; i = pa_idxset_next(c->sink_inputs, &index)) { + char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + pa_sample_snprint(ss, sizeof(ss), &i->sample_spec); + assert(i->sink); + pa_strbuf_printf( + s, " index: %u\n\tname: <%s>\n\tsink: <%u>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tsample_spec: <%s>\n", + i->index, + i->name, + i->sink->index, + (unsigned) i->volume, + pa_sink_input_get_latency(i), + ss); + + if (i->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", i->owner->index); + if (i->client) + pa_strbuf_printf(s, "\tclient: <%u>\n", i->client->index); + } + + return pa_strbuf_tostring_free(s); +} diff --git a/polyp/clitext.h b/polyp/clitext.h new file mode 100644 index 00000000..b1718cb5 --- /dev/null +++ b/polyp/clitext.h @@ -0,0 +1,35 @@ +#ifndef fooclitexthfoo +#define fooclitexthfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" + +char *pa_sink_input_list_to_string(struct pa_core *c); +char *pa_source_output_list_to_string(struct pa_core *c); +char *pa_sink_list_to_string(struct pa_core *core); +char *pa_source_list_to_string(struct pa_core *c); +char *pa_client_list_to_string(struct pa_core *c); +char *pa_module_list_to_string(struct pa_core *c); + +#endif + diff --git a/polyp/cmdline.c b/polyp/cmdline.c new file mode 100644 index 00000000..a3330145 --- /dev/null +++ b/polyp/cmdline.c @@ -0,0 +1,111 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "cmdline.h" +#include "util.h" +#include "strbuf.h" + +void pa_cmdline_help(const char *argv0) { + const char *e; + + if ((e = strrchr(argv0, '/'))) + e++; + else + e = argv0; + + printf("%s [options]\n" + " -L MODULE Load the specified plugin module with the specified argument\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); +} + +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 = cmdline->verbose = 0; + cmdline->fail = 1; + + buf = pa_strbuf_new(); + assert(buf); + + while ((c = getopt(argc, argv, "L:F:CDhfv")) != -1) { + switch (c) { + case 'L': + pa_strbuf_printf(buf, "load %s\n", optarg); + break; + case 'F': + pa_strbuf_printf(buf, ".include %s\n", optarg); + break; + case 'C': + pa_strbuf_puts(buf, "load module-cli\n"); + break; + case 'D': + cmdline->daemonize = 1; + break; + 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) { + assert(cmd); + free(cmd->cli_commands); + free(cmd); +} diff --git a/polyp/cmdline.h b/polyp/cmdline.h new file mode 100644 index 00000000..95ce91de --- /dev/null +++ b/polyp/cmdline.h @@ -0,0 +1,36 @@ +#ifndef foocmdlinehfoo +#define foocmdlinehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + + +struct pa_cmdline { + int daemonize, help, fail, verbose; + char *cli_commands; +}; + +struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []); +void pa_cmdline_free(struct pa_cmdline *cmd); + +void pa_cmdline_help(const char *argv0); + +#endif diff --git a/polyp/core.c b/polyp/core.c new file mode 100644 index 00000000..dc9525a8 --- /dev/null +++ b/polyp/core.c @@ -0,0 +1,88 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "core.h" +#include "module.h" +#include "sink.h" +#include "source.h" +#include "namereg.h" +#include "util.h" + +struct pa_core* pa_core_new(struct pa_mainloop_api *m) { + struct pa_core* c; + c = malloc(sizeof(struct pa_core)); + assert(c); + + c->mainloop = m; + c->clients = pa_idxset_new(NULL, NULL); + c->sinks = pa_idxset_new(NULL, NULL); + c->sources = pa_idxset_new(NULL, NULL); + c->source_outputs = pa_idxset_new(NULL, NULL); + c->sink_inputs = pa_idxset_new(NULL, NULL); + + c->default_source_index = c->default_sink_index = PA_IDXSET_INVALID; + + c->modules = NULL; + c->namereg = NULL; + + c->default_sample_spec.format = PA_SAMPLE_S16NE; + c->default_sample_spec.rate = 44100; + c->default_sample_spec.channels = 2; + + pa_check_for_sigpipe(); + + return c; +}; + +void pa_core_free(struct pa_core *c) { + assert(c); + + pa_module_unload_all(c); + assert(!c->modules); + + assert(pa_idxset_isempty(c->clients)); + pa_idxset_free(c->clients, NULL, NULL); + + assert(pa_idxset_isempty(c->sinks)); + pa_idxset_free(c->sinks, NULL, NULL); + + assert(pa_idxset_isempty(c->sources)); + pa_idxset_free(c->sources, NULL, NULL); + + assert(pa_idxset_isempty(c->source_outputs)); + pa_idxset_free(c->source_outputs, NULL, NULL); + + assert(pa_idxset_isempty(c->sink_inputs)); + pa_idxset_free(c->sink_inputs, NULL, NULL); + + pa_namereg_free(c); + + free(c); +}; + diff --git a/polyp/core.h b/polyp/core.h new file mode 100644 index 00000000..99d7d76a --- /dev/null +++ b/polyp/core.h @@ -0,0 +1,45 @@ +#ifndef foocorehfoo +#define foocorehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "idxset.h" +#include "hashmap.h" +#include "mainloop-api.h" +#include "sample.h" + +struct pa_core { + struct pa_mainloop_api *mainloop; + + struct pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules; + + struct pa_hashmap *namereg; + + uint32_t default_source_index, default_sink_index; + + struct pa_sample_spec default_sample_spec; +}; + +struct pa_core* pa_core_new(struct pa_mainloop_api *m); +void pa_core_free(struct pa_core*c); + +#endif diff --git a/polyp/depmod.py b/polyp/depmod.py new file mode 100755 index 00000000..85dc66a8 --- /dev/null +++ b/polyp/depmod.py @@ -0,0 +1,73 @@ +#!/usr/bin/python +# $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +import sys, os, string + +exported_symbols = {} +imported_symbols = {} + +for fn in sys.argv[1:]: + f = os.popen("nm '%s'" % fn, "r") + + imported_symbols[fn] = [] + + for line in f: + sym_address = line[:7].strip() + sym_type = line[9].strip() + sym_name = line[11:].strip() + + if sym_name in ('_fini', '_init'): + continue + + if sym_type in ('T', 'B', 'R', 'D' 'G', 'S', 'D'): + if exported_symbols.has_key(sym_name): + sys.stderr.write("CONFLICT: %s defined in both '%s' and '%s'.\n" % (sym_name, fn, exported_symbols[sym_name])) + else: + exported_symbols[sym_name] = fn + elif sym_type in ('U',): + if sym_name[:3] == 'pa_': + imported_symbols[fn].append(sym_name) + + f.close() + +dependencies = {} +unresolved_symbols = {} + +for fn in imported_symbols: + dependencies[fn] = [] + + for sym in imported_symbols[fn]: + if exported_symbols.has_key(sym): + if exported_symbols[sym] not in dependencies[fn]: + dependencies[fn].append(exported_symbols[sym]) + else: + if unresolved_symbols.has_key(sym): + unresolved_symbols[sym].append(fn) + else: + unresolved_symbols[sym] = [fn] + +for sym, files in unresolved_symbols.iteritems(): + print "WARNING: Unresolved symbol '%s' in %s" % (sym, `files`) + +k = dependencies.keys() +k.sort() +for fn in k: + dependencies[fn].sort() + print "%s: %s" % (fn, string.join(dependencies[fn], " ")) diff --git a/polyp/dynarray.c b/polyp/dynarray.c new file mode 100644 index 00000000..24306964 --- /dev/null +++ b/polyp/dynarray.c @@ -0,0 +1,98 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "dynarray.h" + +struct pa_dynarray { + void **data; + unsigned n_allocated, n_entries; +}; + +struct pa_dynarray* pa_dynarray_new(void) { + struct pa_dynarray *a; + a = malloc(sizeof(struct pa_dynarray)); + assert(a); + a->data = NULL; + a->n_entries = 0; + a->n_allocated = 0; + return a; +} + +void pa_dynarray_free(struct pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata) { + unsigned i; + assert(a); + + if (func) + for (i = 0; i < a->n_entries; i++) + if (a->data[i]) + func(a->data[i], userdata); + + free(a->data); + free(a); +} + +void pa_dynarray_put(struct pa_dynarray*a, unsigned i, void *p) { + assert(a); + + if (i >= a->n_allocated) { + unsigned n; + + if (!p) + return; + + n = i+100; + a->data = realloc(a->data, sizeof(void*)*n); + memset(a->data+a->n_allocated, 0, sizeof(void*)*(n-a->n_allocated)); + a->n_allocated = n; + } + + a->data[i] = p; + + if (i >= a->n_entries) + a->n_entries = i+1; +} + +unsigned pa_dynarray_append(struct pa_dynarray*a, void *p) { + unsigned i = a->n_entries; + pa_dynarray_put(a, i, p); + return i; +} + +void *pa_dynarray_get(struct pa_dynarray*a, unsigned i) { + assert(a); + if (i >= a->n_allocated) + return NULL; + assert(a->data); + return a->data[i]; +} + +unsigned pa_dynarray_ncontents(struct pa_dynarray*a) { + assert(a); + return a->n_entries; +} diff --git a/polyp/dynarray.h b/polyp/dynarray.h new file mode 100644 index 00000000..56ec5386 --- /dev/null +++ b/polyp/dynarray.h @@ -0,0 +1,37 @@ +#ifndef foodynarrayhfoo +#define foodynarrayhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +struct pa_dynarray; + +struct pa_dynarray* pa_dynarray_new(void); +void pa_dynarray_free(struct pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata); + +void pa_dynarray_put(struct pa_dynarray*a, unsigned i, void *p); +unsigned pa_dynarray_append(struct pa_dynarray*a, void *p); + +void *pa_dynarray_get(struct pa_dynarray*a, unsigned i); + +unsigned pa_dynarray_ncontents(struct pa_dynarray*a); + +#endif diff --git a/polyp/endianmacros.h b/polyp/endianmacros.h new file mode 100644 index 00000000..cd7b7d83 --- /dev/null +++ b/polyp/endianmacros.h @@ -0,0 +1,62 @@ +#ifndef fooendianmacroshfoo +#define fooendianmacroshfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define INT16_SWAP(x) ((int16_t)(((int16_t) x >> 8) | ((int16_t) x << 8))) +#define UINT16_SWAP(x) ((uint16_t)(((uint16_t) x >> 8) | ((uint16_t) x << 8))) +#define INT32_SWAP(x) ((int32_t)(((int32_t) x >> 24) | ((int32_t) x << 24) | (((int32_t) x & 0xFF00) << 16) | (((int32_t) x) >> 16) & 0xFF00)) +#define UINT32_SWAP(x) ((uint32_t)(((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 16) | (((uint32_t) x) >> 16) & 0xFF00)) + +#ifdef WORDS_BIGENDIAN + #define INT16_FROM_LE(x) INT16_SWAP(x) + #define INT16_FROM_BE(x) ((int16_t)(x)) + #define INT16_TO_LE(x) INT16_SWAP(x) + #define INT16_TO_BE(x) ((int16_t)(x)) + + #define UINT16_FROM_LE(x) UINT16_SWAP(x) + #define UINT16_FROM_BE(x) ((uint16_t)(x)) + #define INT32_FROM_LE(x) INT32_SWAP(x) + #define INT32_FROM_BE(x) ((int32_t)(x)) + #define UINT32_FROM_LE(x) UINT32_SWAP(x) + #define UINT32_FROM_BE(x) ((uint32_t)(x)) +#else + #define INT16_FROM_LE(x) ((int16_t)(x)) + #define INT16_FROM_BE(x) INT16_SWAP(x) + #define INT16_TO_LE(x) ((int16_t)(x)) + #define INT16_TO_BE(x) INT16_SWAP(x) + + #define UINT16_FROM_LE(x) ((uint16_t)(x)) + #define UINT16_FROM_BE(x) UINT16_SWAP(x) + #define INT32_FROM_LE(x) ((int32_t)(x)) + #define INT32_FROM_BE(x) INT32_SWAP(x) + #define UINT32_FROM_LE(x) ((uint32_t)(x)) + #define UINT32_FROM_BE(x) UINT32_SWAP(x) +#endif + +#endif diff --git a/polyp/esound.h b/polyp/esound.h new file mode 100644 index 00000000..01a2962f --- /dev/null +++ b/polyp/esound.h @@ -0,0 +1,213 @@ +#ifndef fooesoundhfoo +#define fooesoundhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* Most of the following is blatantly stolen from esound. */ + + +/* path and name of the default EsounD domain socket */ +#define ESD_UNIX_SOCKET_DIR "/tmp/.esd" +#define ESD_UNIX_SOCKET_NAME "/tmp/.esd/socket" + +/* length of the audio buffer size */ +#define ESD_BUF_SIZE (4 * 1024) +/* maximum size we can write(). Otherwise we might overflow */ +#define ESD_MAX_WRITE_SIZE (21 * 4096) + +/* length of the authorization key, octets */ +#define ESD_KEY_LEN (16) + +/* default port for the EsounD server */ +#define ESD_DEFAULT_PORT (16001) + +/* default sample rate for the EsounD server */ +#define ESD_DEFAULT_RATE (44100) + +/* maximum length of a stream/sample name */ +#define ESD_NAME_MAX (128) + +/* a magic number to identify the relative endianness of a client */ +#define ESD_ENDIAN_KEY ((uint32_t) (('E' << 24) + ('N' << 16) + ('D' << 8) + ('N'))) + +#define ESD_VOLUME_BASE (256) + + +/*************************************/ +/* what can we do to/with the EsounD */ +enum esd_proto { + ESD_PROTO_CONNECT, /* implied on inital client connection */ + + /* pseudo "security" functionality */ + ESD_PROTO_LOCK, /* disable "foreign" client connections */ + ESD_PROTO_UNLOCK, /* enable "foreign" client connections */ + + /* stream functionality: play, record, monitor */ + ESD_PROTO_STREAM_PLAY, /* play all following data as a stream */ + ESD_PROTO_STREAM_REC, /* record data from card as a stream */ + ESD_PROTO_STREAM_MON, /* send mixed buffer output as a stream */ + + /* sample functionality: cache, free, play, loop, EOL, kill */ + ESD_PROTO_SAMPLE_CACHE, /* cache a sample in the server */ + ESD_PROTO_SAMPLE_FREE, /* release a sample in the server */ + ESD_PROTO_SAMPLE_PLAY, /* play a cached sample */ + ESD_PROTO_SAMPLE_LOOP, /* loop a cached sample, til eoloop */ + ESD_PROTO_SAMPLE_STOP, /* stop a looping sample when done */ + ESD_PROTO_SAMPLE_KILL, /* stop the looping sample immed. */ + + /* free and reclaim /dev/dsp functionality */ + ESD_PROTO_STANDBY, /* release /dev/dsp and ignore all data */ + ESD_PROTO_RESUME, /* reclaim /dev/dsp and play sounds again */ + + /* TODO: move these to a more logical place. NOTE: will break the protocol */ + ESD_PROTO_SAMPLE_GETID, /* get the ID for an already-cached sample */ + ESD_PROTO_STREAM_FILT, /* filter mixed buffer output as a stream */ + + /* esd remote management */ + ESD_PROTO_SERVER_INFO, /* get server info (ver, sample rate, format) */ + ESD_PROTO_ALL_INFO, /* get all info (server info, players, samples) */ + ESD_PROTO_SUBSCRIBE, /* track new and removed players and samples */ + ESD_PROTO_UNSUBSCRIBE, /* stop tracking updates */ + + /* esd remote control */ + ESD_PROTO_STREAM_PAN, /* set stream panning */ + ESD_PROTO_SAMPLE_PAN, /* set default sample panning */ + + /* esd status */ + ESD_PROTO_STANDBY_MODE, /* see if server is in standby, autostandby, etc */ + + /* esd latency */ + ESD_PROTO_LATENCY, /* retrieve latency between write()'s and output */ + + ESD_PROTO_MAX /* for bounds checking */ +}; + +/******************/ +/* The EsounD api */ + +/* the properties of a sound buffer are logically or'd */ + +/* bits of stream/sample data */ +#define ESD_MASK_BITS ( 0x000F ) +#define ESD_BITS8 ( 0x0000 ) +#define ESD_BITS16 ( 0x0001 ) + +/* how many interleaved channels of data */ +#define ESD_MASK_CHAN ( 0x00F0 ) +#define ESD_MONO ( 0x0010 ) +#define ESD_STEREO ( 0x0020 ) + +/* whether it's a stream or a sample */ +#define ESD_MASK_MODE ( 0x0F00 ) +#define ESD_STREAM ( 0x0000 ) +#define ESD_SAMPLE ( 0x0100 ) +#define ESD_ADPCM ( 0x0200 ) /* TODO: anyone up for this? =P */ + +/* the function of the stream/sample, and common functions */ +#define ESD_MASK_FUNC ( 0xF000 ) +#define ESD_PLAY ( 0x1000 ) +/* functions for streams only */ +#define ESD_MONITOR ( 0x0000 ) +#define ESD_RECORD ( 0x2000 ) +/* functions for samples only */ +#define ESD_STOP ( 0x0000 ) +#define ESD_LOOP ( 0x2000 ) + +typedef int esd_format_t; +typedef int esd_proto_t; + +/*******************************************************************/ +/* esdmgr.c - functions to implement a "sound manager" for esd */ + +/* structures to retrieve information about streams/samples from the server */ +typedef struct esd_server_info { + + int version; /* server version encoded as an int */ + esd_format_t format; /* magic int with the format info */ + int rate; /* sample rate */ + +} esd_server_info_t; + +typedef struct esd_player_info { + + struct esd_player_info *next; /* point to next entry in list */ + esd_server_info_t *server; /* the server that contains this stream */ + + int source_id; /* either a stream fd or sample id */ + char name[ ESD_NAME_MAX ]; /* name of stream for remote control */ + int rate; /* sample rate */ + int left_vol_scale; /* volume scaling */ + int right_vol_scale; + + esd_format_t format; /* magic int with the format info */ + +} esd_player_info_t; + +typedef struct esd_sample_info { + + struct esd_sample_info *next; /* point to next entry in list */ + esd_server_info_t *server; /* the server that contains this sample */ + + int sample_id; /* either a stream fd or sample id */ + char name[ ESD_NAME_MAX ]; /* name of stream for remote control */ + int rate; /* sample rate */ + int left_vol_scale; /* volume scaling */ + int right_vol_scale; + + esd_format_t format; /* magic int with the format info */ + int length; /* total buffer length */ + +} esd_sample_info_t; + +typedef struct esd_info { + + esd_server_info_t *server; + esd_player_info_t *player_list; + esd_sample_info_t *sample_list; + +} esd_info_t; + +enum esd_standby_mode { + ESM_ERROR, ESM_ON_STANDBY, ESM_ON_AUTOSTANDBY, ESM_RUNNING +}; +typedef int esd_standby_mode_t; + +enum esd_client_state { + ESD_STREAMING_DATA, /* data from here on is streamed data */ + ESD_CACHING_SAMPLE, /* midway through caching a sample */ + ESD_NEEDS_REQDATA, /* more data needed to complere request */ + ESD_NEXT_REQUEST, /* proceed to next request */ + ESD_CLIENT_STATE_MAX /* place holder */ +}; +typedef int esd_client_state_t; + +/* switch endian order for cross platform playing */ +#define swap_endian_32(x) ((x >> 24) | ((x >> 8) & 0xFF00) | (((x & 0xFF00) << 8)) | (x << 24)) +#define maybe_swap_endian_32(c,x) ((c) ? swap_endian_32(x) : x) + +/* the endian key is transferred in binary, if it's read into int, */ +/* and matches ESD_ENDIAN_KEY (ENDN), then the endianness of the */ +/* server and the client match; if it's SWAP_ENDIAN_KEY, swap data */ +#define ESD_SWAP_ENDIAN_KEY ((uint32_t) swap_endian_32(ESD_ENDIAN_KEY)) + + +#endif diff --git a/polyp/hashmap.c b/polyp/hashmap.c new file mode 100644 index 00000000..2c7c92b5 --- /dev/null +++ b/polyp/hashmap.c @@ -0,0 +1,170 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "hashmap.h" +#include "idxset.h" + +struct hashmap_entry { + struct hashmap_entry *next, *previous, *bucket_next, *bucket_previous; + unsigned hash; + const void *key; + void *value; +}; + +struct pa_hashmap { + unsigned size; + struct hashmap_entry **data; + struct hashmap_entry *first_entry; + + unsigned n_entries; + unsigned (*hash_func) (const void *p); + int (*compare_func) (const void*a, const void*b); +}; + +struct pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { + struct pa_hashmap *h; + h = malloc(sizeof(struct pa_hashmap)); + assert(h); + h->data = malloc(sizeof(struct hashmap_entry*)*(h->size = 1023)); + assert(h->data); + memset(h->data, 0, sizeof(struct hashmap_entry*)*(h->size = 1023)); + h->first_entry = NULL; + h->n_entries = 0; + h->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; + h->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; + return h; +} + +static void remove(struct pa_hashmap *h, struct hashmap_entry *e) { + assert(e); + + if (e->next) + e->next->previous = e->previous; + if (e->previous) + e->previous->next = e->next; + else + h->first_entry = e->next; + + if (e->bucket_next) + e->bucket_next->bucket_previous = e->bucket_previous; + if (e->bucket_previous) + e->bucket_previous->bucket_next = e->bucket_next; + else + h->data[e->hash] = e->bucket_next; + + free(e); + h->n_entries--; +} + +void pa_hashmap_free(struct pa_hashmap*h, void (*free_func)(void *p, void *userdata), void *userdata) { + assert(h); + + while (h->first_entry) { + if (free_func) + free_func(h->first_entry->value, userdata); + remove(h, h->first_entry); + } + + free(h->data); + free(h); +} + +static struct hashmap_entry *get(struct pa_hashmap *h, unsigned hash, const void *key) { + struct hashmap_entry *e; + + for (e = h->data[hash]; e; e = e->bucket_next) + if (h->compare_func(e->key, key) == 0) + return e; + + return NULL; +} + +int pa_hashmap_put(struct pa_hashmap *h, const void *key, void *value) { + struct hashmap_entry *e; + unsigned hash; + assert(h && key); + + hash = h->hash_func(key) % h->size; + + if ((e = get(h, hash, key))) + return -1; + + e = malloc(sizeof(struct hashmap_entry)); + assert(e); + + e->hash = hash; + e->key = key; + e->value = value; + + e->previous = NULL; + e->next = h->first_entry; + if (h->first_entry) + h->first_entry->previous = e; + h->first_entry = e; + + e->bucket_previous = NULL; + e->bucket_next = h->data[hash]; + if (h->data[hash]) + h->data[hash]->bucket_previous = e; + h->data[hash] = e; + + h->n_entries ++; + return 0; +} + +void* pa_hashmap_get(struct pa_hashmap *h, const void *key) { + unsigned hash; + struct hashmap_entry *e; + assert(h && key); + + hash = h->hash_func(key) % h->size; + + if (!(e = get(h, hash, key))) + return NULL; + + return e->value; +} + +int pa_hashmap_remove(struct pa_hashmap *h, const void *key) { + struct hashmap_entry *e; + unsigned hash; + assert(h && key); + + hash = h->hash_func(key) % h->size; + + if (!(e = get(h, hash, key))) + return 1; + + remove(h, e); + return 0; +} + +unsigned pa_hashmap_ncontents(struct pa_hashmap *h) { + return h->n_entries; +} diff --git a/polyp/hashmap.h b/polyp/hashmap.h new file mode 100644 index 00000000..b24e74a5 --- /dev/null +++ b/polyp/hashmap.h @@ -0,0 +1,37 @@ +#ifndef foohashmaphfoo +#define foohashmaphfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +struct pa_hashmap; + +struct pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); +void pa_hashmap_free(struct pa_hashmap*, void (*free_func)(void *p, void *userdata), void *userdata); + +int pa_hashmap_put(struct pa_hashmap *h, const void *key, void *value); +void* pa_hashmap_get(struct pa_hashmap *h, const void *key); + +int pa_hashmap_remove(struct pa_hashmap *h, const void *key); + +unsigned pa_hashmap_ncontents(struct pa_hashmap *h); + +#endif diff --git a/polyp/idxset.c b/polyp/idxset.c new file mode 100644 index 00000000..cecda6b7 --- /dev/null +++ b/polyp/idxset.c @@ -0,0 +1,397 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "idxset.h" + +struct idxset_entry { + void *data; + uint32_t index; + unsigned hash_value; + + struct idxset_entry *hash_prev, *hash_next; + struct idxset_entry* iterate_prev, *iterate_next; +}; + +struct pa_idxset { + unsigned (*hash_func) (const void *p); + int (*compare_func)(const void *a, const void *b); + + unsigned hash_table_size, n_entries; + struct idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail; + uint32_t index, start_index, array_size; +}; + +unsigned pa_idxset_string_hash_func(const void *p) { + unsigned hash = 0; + const char *c; + + for (c = p; *c; c++) + hash = 31 * hash + *c; + + return hash; +} + +int pa_idxset_string_compare_func(const void *a, const void *b) { + return strcmp(a, b); +} + +unsigned pa_idxset_trivial_hash_func(const void *p) { + return (unsigned) p; +} + +int pa_idxset_trivial_compare_func(const void *a, const void *b) { + return a != b; +} + +struct pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { + struct pa_idxset *s; + + s = malloc(sizeof(struct pa_idxset)); + assert(s); + s->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; + s->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; + s->hash_table_size = 1023; + s->hash_table = malloc(sizeof(struct idxset_entry*)*s->hash_table_size); + assert(s->hash_table); + memset(s->hash_table, 0, sizeof(struct idxset_entry*)*s->hash_table_size); + s->array = NULL; + s->array_size = 0; + s->index = 0; + s->start_index = 0; + s->n_entries = 0; + + s->iterate_list_head = s->iterate_list_tail = NULL; + + return s; +} + +void pa_idxset_free(struct pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata) { + assert(s); + + if (free_func) { + while (s->iterate_list_head) { + struct idxset_entry *e = s->iterate_list_head; + s->iterate_list_head = s->iterate_list_head->iterate_next; + + if (free_func) + free_func(e->data, userdata); + free(e); + } + } + + free(s->hash_table); + free(s->array); + free(s); +} + +static struct idxset_entry* hash_scan(struct pa_idxset *s, struct idxset_entry* e, void *p) { + assert(p); + + assert(s->compare_func); + for (; e; e = e->hash_next) + if (s->compare_func(e->data, p) == 0) + return e; + + return NULL; +} + +static void extend_array(struct pa_idxset *s, uint32_t index) { + uint32_t i, j, l; + struct idxset_entry** n; + assert(index >= s->start_index); + + if (index < s->start_index + s->array_size) + return; + + for (i = 0; i < s->array_size; i++) + if (s->array[i]) + break; + + l = index - s->start_index - i + 100; + n = malloc(sizeof(struct hash_table_entry*)*l); + assert(n); + memset(n, 0, sizeof(struct hash_table_entry*)*l); + + for (j = 0; j < s->array_size-i; j++) + n[j] = s->array[i+j]; + + free(s->array); + + s->array = n; + s->array_size = l; + s->start_index += i; +} + +static struct idxset_entry** array_index(struct pa_idxset*s, uint32_t index) { + if (index >= s->start_index + s->array_size) + return NULL; + + if (index < s->start_index) + return NULL; + + return s->array + (index - s->start_index); +} + +int pa_idxset_put(struct pa_idxset*s, void *p, uint32_t *index) { + unsigned h; + struct idxset_entry *e, **a; + assert(s && p); + + assert(s->hash_func); + h = s->hash_func(p) % s->hash_table_size; + + assert(s->hash_table); + if ((e = hash_scan(s, s->hash_table[h], p))) { + if (index) + *index = e->index; + + return -1; + } + + e = malloc(sizeof(struct idxset_entry)); + assert(e); + + e->data = p; + e->index = s->index++; + e->hash_value = h; + + /* Insert into hash table */ + e->hash_next = s->hash_table[h]; + e->hash_prev = NULL; + if (s->hash_table[h]) + s->hash_table[h]->hash_prev = e; + s->hash_table[h] = e; + + /* Insert into array */ + extend_array(s, e->index); + a = array_index(s, e->index); + assert(a && !*a); + *a = e; + + /* Insert into linked list */ + e->iterate_next = NULL; + e->iterate_prev = s->iterate_list_tail; + if (s->iterate_list_tail) { + assert(s->iterate_list_head); + s->iterate_list_tail->iterate_next = e; + } else { + assert(!s->iterate_list_head); + s->iterate_list_head = e; + } + s->iterate_list_tail = e; + + s->n_entries++; + assert(s->n_entries >= 1); + + if (index) + *index = e->index; + + return 0; +} + +void* pa_idxset_get_by_index(struct pa_idxset*s, uint32_t index) { + struct idxset_entry **a; + assert(s); + + if (!(a = array_index(s, index))) + return NULL; + + if (!*a) + return NULL; + + return (*a)->data; +} + +void* pa_idxset_get_by_data(struct pa_idxset*s, void *p, uint32_t *index) { + unsigned h; + struct idxset_entry *e; + assert(s && p); + + assert(s->hash_func); + h = s->hash_func(p) % s->hash_table_size; + + assert(s->hash_table); + if (!(e = hash_scan(s, s->hash_table[h], p))) + return NULL; + + if (index) + *index = e->index; + + return e->data; +} + +static void remove_entry(struct pa_idxset *s, struct idxset_entry *e) { + struct idxset_entry **a; + assert(s && e); + + /* Remove from array */ + a = array_index(s, e->index); + assert(a && *a && *a == e); + *a = NULL; + + /* Remove from linked list */ + if (e->iterate_next) + e->iterate_next->iterate_prev = e->iterate_prev; + else + s->iterate_list_tail = e->iterate_prev; + + if (e->iterate_prev) + e->iterate_prev->iterate_next = e->iterate_next; + else + s->iterate_list_head = e->iterate_next; + + /* Remove from hash table */ + if (e->hash_next) + e->hash_next->hash_prev = e->hash_prev; + + if (e->hash_prev) + e->hash_prev->hash_next = e->hash_next; + else + s->hash_table[e->hash_value] = e->hash_next; + + free(e); + + assert(s->n_entries >= 1); + s->n_entries--; +} + +void* pa_idxset_remove_by_index(struct pa_idxset*s, uint32_t index) { + struct idxset_entry **a; + void *data; + + assert(s); + + if (!(a = array_index(s, index))) + return NULL; + + data = (*a)->data; + remove_entry(s, *a); + + return data; +} + +void* pa_idxset_remove_by_data(struct pa_idxset*s, void *data, uint32_t *index) { + struct idxset_entry *e; + unsigned h; + + assert(s->hash_func); + h = s->hash_func(data) % s->hash_table_size; + + assert(s->hash_table); + if (!(e = hash_scan(s, s->hash_table[h], data))) + return NULL; + + data = e->data; + if (index) + *index = e->index; + + remove_entry(s, e); + + return data; +} + +void* pa_idxset_rrobin(struct pa_idxset *s, uint32_t *index) { + struct idxset_entry **a, *e = NULL; + assert(s && index); + + if ((a = array_index(s, *index)) && *a) + e = (*a)->iterate_next; + + if (!e) + e = s->iterate_list_head; + + if (!e) + return NULL; + + *index = e->index; + return e->data; +} + +void* pa_idxset_first(struct pa_idxset *s, uint32_t *index) { + assert(s); + + if (!s->iterate_list_head) + return NULL; + + if (index) + *index = s->iterate_list_head->index; + return s->iterate_list_head->data; +} + +void *pa_idxset_next(struct pa_idxset *s, uint32_t *index) { + struct idxset_entry **a, *e = NULL; + assert(s && index); + + if ((a = array_index(s, *index)) && *a) + e = (*a)->iterate_next; + + if (e) { + *index = e->index; + return e->data; + } else { + *index = PA_IDXSET_INVALID; + return NULL; + } +} + + +int pa_idxset_foreach(struct pa_idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata) { + struct idxset_entry *e; + assert(s && func); + + e = s->iterate_list_head; + while (e) { + int del = 0, r; + struct idxset_entry *n = e->iterate_next; + + r = func(e->data, e->index, &del, userdata); + + if (del) + remove_entry(s, e); + + if (r < 0) + return r; + + e = n; + } + + return 0; +} + +unsigned pa_idxset_ncontents(struct pa_idxset*s) { + assert(s); + return s->n_entries; +} + +int pa_idxset_isempty(struct pa_idxset *s) { + assert(s); + return s->n_entries == 0; +} + diff --git a/polyp/idxset.h b/polyp/idxset.h new file mode 100644 index 00000000..f26b03fb --- /dev/null +++ b/polyp/idxset.h @@ -0,0 +1,63 @@ +#ifndef fooidxsethfoo +#define fooidxsethfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#define PA_IDXSET_INVALID ((uint32_t) -1) + +unsigned pa_idxset_trivial_hash_func(const void *p); +int pa_idxset_trivial_compare_func(const void *a, const void *b); + +unsigned pa_idxset_string_hash_func(const void *p); +int pa_idxset_string_compare_func(const void *a, const void *b); + +struct pa_idxset; + +struct pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); +void pa_idxset_free(struct pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata); + +int pa_idxset_put(struct pa_idxset*s, void *p, uint32_t *index); + +void* pa_idxset_get_by_index(struct pa_idxset*s, uint32_t index); +void* pa_idxset_get_by_data(struct pa_idxset*s, void *p, uint32_t *index); + +void* pa_idxset_remove_by_index(struct pa_idxset*s, uint32_t index); +void* pa_idxset_remove_by_data(struct pa_idxset*s, void *p, uint32_t *index); + +/* This may be used to iterate through all entries. When called with + an invalid index value it returns the first entry, otherwise the + next following. The function is best called with *index = + PA_IDXSET_VALID first. */ +void* pa_idxset_rrobin(struct pa_idxset *s, uint32_t *index); + +/* Return the oldest entry in the idxset */ +void* pa_idxset_first(struct pa_idxset *s, uint32_t *index); +void *pa_idxset_next(struct pa_idxset *s, uint32_t *index); + +int pa_idxset_foreach(struct pa_idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata); + +unsigned pa_idxset_ncontents(struct pa_idxset*s); +int pa_idxset_isempty(struct pa_idxset *s); + +#endif diff --git a/polyp/iochannel.c b/polyp/iochannel.c new file mode 100644 index 00000000..69d381f4 --- /dev/null +++ b/polyp/iochannel.c @@ -0,0 +1,222 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "iochannel.h" +#include "util.h" +#include "socket-util.h" + +struct pa_iochannel { + int ifd, ofd; + struct pa_mainloop_api* mainloop; + + void (*callback)(struct pa_iochannel*io, void *userdata); + void*userdata; + + int readable; + int writable; + int hungup; + + int no_close; + + void* input_source, *output_source; +}; + +static void enable_mainloop_sources(struct pa_iochannel *io) { + assert(io); + + if (io->input_source == io->output_source) { + enum pa_mainloop_api_io_events e = PA_MAINLOOP_API_IO_EVENT_NULL; + assert(io->input_source); + + if (!io->readable) + e |= PA_MAINLOOP_API_IO_EVENT_INPUT; + if (!io->writable) + e |= PA_MAINLOOP_API_IO_EVENT_OUTPUT; + + io->mainloop->enable_io(io->mainloop, io->input_source, e); + } else { + if (io->input_source) + io->mainloop->enable_io(io->mainloop, io->input_source, io->readable ? PA_MAINLOOP_API_IO_EVENT_NULL : PA_MAINLOOP_API_IO_EVENT_INPUT); + if (io->output_source) + io->mainloop->enable_io(io->mainloop, io->output_source, io->writable ? PA_MAINLOOP_API_IO_EVENT_NULL : PA_MAINLOOP_API_IO_EVENT_OUTPUT); + } +} + +static void callback(struct pa_mainloop_api* m, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { + struct pa_iochannel *io = userdata; + int changed = 0; + assert(m && fd >= 0 && events && userdata); + + if ((events & PA_MAINLOOP_API_IO_EVENT_HUP) && !io->hungup) { + io->hungup = 1; + changed = 1; + } + + if ((events & PA_MAINLOOP_API_IO_EVENT_INPUT) && !io->readable) { + io->readable = 1; + changed = 1; + assert(id == io->input_source); + } + + if ((events & PA_MAINLOOP_API_IO_EVENT_OUTPUT) && !io->writable) { + io->writable = 1; + changed = 1; + assert(id == io->output_source); + } + + if (changed) { + enable_mainloop_sources(io); + + if (io->callback) + io->callback(io, io->userdata); + } +} + +struct pa_iochannel* pa_iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd) { + struct pa_iochannel *io; + assert(m && (ifd >= 0 || ofd >= 0)); + + io = malloc(sizeof(struct pa_iochannel)); + io->ifd = ifd; + io->ofd = ofd; + io->mainloop = m; + + io->userdata = NULL; + io->callback = NULL; + io->readable = 0; + io->writable = 0; + io->hungup = 0; + io->no_close = 0; + + if (ifd == ofd) { + assert(ifd >= 0); + pa_make_nonblock_fd(io->ifd); + io->input_source = io->output_source = m->source_io(m, ifd, PA_MAINLOOP_API_IO_EVENT_BOTH, callback, io); + } else { + + if (ifd >= 0) { + pa_make_nonblock_fd(io->ifd); + io->input_source = m->source_io(m, ifd, PA_MAINLOOP_API_IO_EVENT_INPUT, callback, io); + } else + io->input_source = NULL; + + if (ofd >= 0) { + pa_make_nonblock_fd(io->ofd); + io->output_source = m->source_io(m, ofd, PA_MAINLOOP_API_IO_EVENT_OUTPUT, callback, io); + } else + io->output_source = NULL; + } + + return io; +} + +void pa_iochannel_free(struct pa_iochannel*io) { + assert(io); + + if (!io->no_close) { + if (io->ifd >= 0) + close(io->ifd); + if (io->ofd >= 0 && io->ofd != io->ifd) + close(io->ofd); + } + + if (io->input_source) + io->mainloop->cancel_io(io->mainloop, io->input_source); + if (io->output_source && (io->output_source != io->input_source)) + io->mainloop->cancel_io(io->mainloop, io->output_source); + + free(io); +} + +int pa_iochannel_is_readable(struct pa_iochannel*io) { + assert(io); + return io->readable; +} + +int pa_iochannel_is_writable(struct pa_iochannel*io) { + assert(io); + return io->writable; +} + +int pa_iochannel_is_hungup(struct pa_iochannel*io) { + assert(io); + return io->hungup; +} + +ssize_t pa_iochannel_write(struct pa_iochannel*io, const void*data, size_t l) { + ssize_t r; + assert(io && data && l && io->ofd >= 0); + + if ((r = write(io->ofd, data, l)) >= 0) { + io->writable = 0; + enable_mainloop_sources(io); + } + + return r; +} + +ssize_t pa_iochannel_read(struct pa_iochannel*io, void*data, size_t l) { + ssize_t r; + + assert(io && data && io->ifd >= 0); + + if ((r = read(io->ifd, data, l)) >= 0) { + io->readable = 0; + enable_mainloop_sources(io); + } + + return r; +} + +void pa_iochannel_set_callback(struct pa_iochannel*io, void (*callback)(struct pa_iochannel*io, void *userdata), void *userdata) { + assert(io); + io->callback = callback; + io->userdata = userdata; +} + +void pa_iochannel_set_noclose(struct pa_iochannel*io, int b) { + assert(io); + io->no_close = b; +} + +void pa_iochannel_socket_peer_to_string(struct pa_iochannel*io, char*s, size_t l) { + assert(io && s && l); + pa_socket_peer_to_string(io->ifd, s, l); +} + +int pa_iochannel_socket_set_rcvbuf(struct pa_iochannel *io, size_t l) { + assert(io); + return pa_socket_set_rcvbuf(io->ifd, l); +} + +int pa_iochannel_socket_set_sndbuf(struct pa_iochannel *io, size_t l) { + assert(io); + return pa_socket_set_sndbuf(io->ofd, l); +} diff --git a/polyp/iochannel.h b/polyp/iochannel.h new file mode 100644 index 00000000..6f5f351c --- /dev/null +++ b/polyp/iochannel.h @@ -0,0 +1,50 @@ +#ifndef fooiochannelhfoo +#define fooiochannelhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include "mainloop-api.h" + +/* It is safe to destroy the calling iochannel object from the callback */ + +struct pa_iochannel; + +struct pa_iochannel* pa_iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd); +void pa_iochannel_free(struct pa_iochannel*io); + +ssize_t pa_iochannel_write(struct pa_iochannel*io, const void*data, size_t l); +ssize_t pa_iochannel_read(struct pa_iochannel*io, void*data, size_t l); + +int pa_iochannel_is_readable(struct pa_iochannel*io); +int pa_iochannel_is_writable(struct pa_iochannel*io); +int pa_iochannel_is_hungup(struct pa_iochannel*io); + +void pa_iochannel_set_noclose(struct pa_iochannel*io, int b); + +void pa_iochannel_set_callback(struct pa_iochannel*io, void (*callback)(struct pa_iochannel*io, void *userdata), void *userdata); + +void pa_iochannel_socket_peer_to_string(struct pa_iochannel*io, char*s, size_t l); +int pa_iochannel_socket_set_rcvbuf(struct pa_iochannel*io, size_t l); +int pa_iochannel_socket_set_sndbuf(struct pa_iochannel*io, size_t l); + +#endif diff --git a/polyp/ioline.c b/polyp/ioline.c new file mode 100644 index 00000000..ff9a03c2 --- /dev/null +++ b/polyp/ioline.c @@ -0,0 +1,220 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "ioline.h" + +#define BUFFER_LIMIT (64*1024) +#define READ_SIZE (1024) + +struct pa_ioline { + struct pa_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 pa_ioline*io, const char *s, void *userdata); + void *userdata; +}; + +static void io_callback(struct pa_iochannel*io, void *userdata); +static int do_write(struct pa_ioline *l); + +struct pa_ioline* pa_ioline_new(struct pa_iochannel *io) { + struct pa_ioline *l; + assert(io); + + l = malloc(sizeof(struct pa_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; + + pa_iochannel_set_callback(io, io_callback, l); + + return l; +} + +void pa_ioline_free(struct pa_ioline *l) { + assert(l); + pa_iochannel_free(l->io); + free(l->wbuf); + free(l->rbuf); + free(l); +} + +void pa_ioline_puts(struct pa_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 pa_ioline_set_callback(struct pa_ioline*l, void (*callback)(struct pa_ioline*io, const char *s, void *userdata), void *userdata) { + assert(l && callback); + l->callback = callback; + l->userdata = userdata; +} + +static int do_read(struct pa_ioline *l) { + ssize_t r; + size_t m, len; + char *e; + assert(l); + + if (!pa_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 = pa_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; + + if (e) { + char *p; + + *e = 0; + + p = l->rbuf+l->rbuf_index; + m = strlen(p); + + 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; +} + +static int do_write(struct pa_ioline *l) { + ssize_t r; + assert(l); + + if (!l->wbuf_valid_length || !pa_iochannel_is_writable(l->io)) + return 0; + + if ((r = pa_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 pa_iochannel*io, void *userdata) { + struct pa_ioline *l = userdata; + assert(io && l); + + if (!l->dead && do_write(l) < 0) + goto fail; + + if (!l->dead && do_read(l) < 0) + goto fail; + + return; + +fail: + l->dead = 1; + if (l->callback) + l->callback(l, NULL, l->userdata); +} diff --git a/polyp/ioline.h b/polyp/ioline.h new file mode 100644 index 00000000..5f29a16b --- /dev/null +++ b/polyp/ioline.h @@ -0,0 +1,35 @@ +#ifndef fooiolinehfoo +#define fooiolinehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "iochannel.h" + +struct pa_ioline; + +struct pa_ioline* pa_ioline_new(struct pa_iochannel *io); +void pa_ioline_free(struct pa_ioline *l); + +void pa_ioline_puts(struct pa_ioline *s, const char *c); +void pa_ioline_set_callback(struct pa_ioline*io, void (*callback)(struct pa_ioline*io, const char *s, void *userdata), void *userdata); + +#endif diff --git a/polyp/main.c b/polyp/main.c new file mode 100644 index 00000000..d9967cef --- /dev/null +++ b/polyp/main.c @@ -0,0 +1,182 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core.h" +#include "mainloop.h" +#include "module.h" +#include "mainloop-signal.h" +#include "cmdline.h" +#include "cli-command.h" +#include "util.h" +#include "sioman.h" + +static struct pa_mainloop *mainloop; + +static void exit_signal_callback(void *id, int sig, void *userdata) { + struct pa_mainloop_api* m = pa_mainloop_get_api(mainloop); + m->quit(m, 1); + fprintf(stderr, __FILE__": got signal.\n"); +} + +static void aux_signal_callback(void *id, int sig, void *userdata) { + struct pa_core *c = userdata; + assert(c); + pa_module_load(c, sig == SIGUSR1 ? "module-cli" : "module-cli-protocol-unix", NULL); +} + +static void close_pipe(int p[2]) { + if (p[0] != -1) + close(p[0]); + if (p[1] != -1) + close(p[1]); + p[0] = p[1] = -1; +} + +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 = 1; + int daemon_pipe[2] = { -1, -1 }; + + if (!(cmdline = pa_cmdline_parse(argc, argv))) { + fprintf(stderr, __FILE__": failed to parse command line.\n"); + goto finish; + } + + if (cmdline->help) { + pa_cmdline_help(argv[0]); + retval = 0; + goto finish; + } + + if (cmdline->daemonize) { + pid_t child; + + if (pa_stdio_acquire() < 0) { + fprintf(stderr, __FILE__": failed to acquire stdio.\n"); + goto finish; + } + + if (pipe(daemon_pipe) < 0) { + fprintf(stderr, __FILE__": failed to create pipe.\n"); + goto finish; + } + + if ((child = fork()) < 0) { + fprintf(stderr, __FILE__": fork() failed: %s\n", strerror(errno)); + goto finish; + } + + if (child != 0) { + /* Father */ + + close(daemon_pipe[1]); + daemon_pipe[1] = -1; + + if (pa_loop_read(daemon_pipe[0], &retval, sizeof(retval)) != sizeof(retval)) { + fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno)); + retval = 1; + } + + goto finish; + } + + close(daemon_pipe[0]); + daemon_pipe[0] = -1; + + setsid(); + setpgrp(); + } + + r = lt_dlinit(); + assert(r == 0); + + mainloop = pa_mainloop_new(); + assert(mainloop); + + r = pa_signal_init(pa_mainloop_get_api(mainloop)); + assert(r == 0); + pa_signal_register(SIGINT, exit_signal_callback, NULL); + signal(SIGPIPE, SIG_IGN); + + c = pa_core_new(pa_mainloop_get_api(mainloop)); + assert(c); + + 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); + + if (r < 0 && cmdline->fail) { + fprintf(stderr, __FILE__": failed to initialize daemon.\n"); + if (cmdline->daemonize) + pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); + } else if (!c->modules || pa_idxset_ncontents(c->modules) == 0) { + fprintf(stderr, __FILE__": daemon startup without any loaded modules, refusing to work.\n"); + if (cmdline->daemonize) + pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); + } else { + retval = 0; + if (cmdline->daemonize) + pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); + 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); + + lt_dlexit(); + +finish: + + if (cmdline) + pa_cmdline_free(cmdline); + + close_pipe(daemon_pipe); + + return retval; +} diff --git a/polyp/mainloop-api.c b/polyp/mainloop-api.c new file mode 100644 index 00000000..cce49c06 --- /dev/null +++ b/polyp/mainloop-api.c @@ -0,0 +1,60 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include "mainloop-api.h" + +struct once_info { + void (*callback)(void *userdata); + void *userdata; +}; + +static void once_callback(struct pa_mainloop_api *api, void *id, void *userdata) { + struct once_info *i = userdata; + assert(api && i && i->callback); + i->callback(i->userdata); + assert(api->cancel_fixed); + api->cancel_fixed(api, id); + free(i); +} + +void pa_mainloop_api_once(struct pa_mainloop_api* api, void (*callback)(void *userdata), void *userdata) { + struct once_info *i; + void *id; + assert(api && callback); + + i = malloc(sizeof(struct once_info)); + assert(i); + i->callback = callback; + i->userdata = userdata; + + assert(api->source_fixed); + id = api->source_fixed(api, once_callback, i); + assert(id); + + /* Note: if the mainloop is destroyed before once_callback() was called, some memory is leaked. */ +} + diff --git a/polyp/mainloop-api.h b/polyp/mainloop-api.h new file mode 100644 index 00000000..0228f580 --- /dev/null +++ b/polyp/mainloop-api.h @@ -0,0 +1,65 @@ +#ifndef foomainloopapihfoo +#define foomainloopapihfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +enum pa_mainloop_api_io_events { + PA_MAINLOOP_API_IO_EVENT_NULL = 0, + PA_MAINLOOP_API_IO_EVENT_INPUT = 1, + PA_MAINLOOP_API_IO_EVENT_OUTPUT = 2, + PA_MAINLOOP_API_IO_EVENT_BOTH = 3, + PA_MAINLOOP_API_IO_EVENT_HUP = 4 +}; + +struct pa_mainloop_api { + void *userdata; + + /* IO sources */ + void* (*source_io)(struct pa_mainloop_api*a, int fd, enum pa_mainloop_api_io_events events, void (*callback) (struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata), void *userdata); + void (*enable_io)(struct pa_mainloop_api*a, void* id, enum pa_mainloop_api_io_events events); + void (*cancel_io)(struct pa_mainloop_api*a, void* id); + + /* Fixed sources */ + void* (*source_fixed)(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, void *id, void *userdata), void *userdata); + void (*enable_fixed)(struct pa_mainloop_api*a, void* id, int b); + void (*cancel_fixed)(struct pa_mainloop_api*a, void* id); + + /* Idle sources */ + void* (*source_idle)(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, void *id, void *userdata), void *userdata); + void (*enable_idle)(struct pa_mainloop_api*a, void* id, int b); + void (*cancel_idle)(struct pa_mainloop_api*a, void* id); + + /* Time sources */ + void* (*source_time)(struct pa_mainloop_api*a, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*a, void *id, const struct timeval *tv, void *userdata), void *userdata); + void (*enable_time)(struct pa_mainloop_api*a, void *id, const struct timeval *tv); + void (*cancel_time)(struct pa_mainloop_api*a, void* id); + + /* Exit mainloop */ + void (*quit)(struct pa_mainloop_api*a, int retval); +}; + +void pa_mainloop_api_once(struct pa_mainloop_api*m, void (*callback)(void *userdata), void *userdata); + +#endif diff --git a/polyp/mainloop-signal.c b/polyp/mainloop-signal.c new file mode 100644 index 00000000..642ca5e0 --- /dev/null +++ b/polyp/mainloop-signal.c @@ -0,0 +1,163 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "mainloop-signal.h" +#include "util.h" + +struct signal_info { + int sig; + struct sigaction saved_sigaction; + void (*callback) (void *id, int signal, void *userdata); + void *userdata; + struct signal_info *previous, *next; +}; + +static struct pa_mainloop_api *api = NULL; +static int signal_pipe[2] = { -1, -1 }; +static void* mainloop_source = NULL; +static struct signal_info *signals = NULL; + +static void signal_handler(int sig) { + write(signal_pipe[1], &sig, sizeof(sig)); +} + +static void callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { + assert(a && id && events == PA_MAINLOOP_API_IO_EVENT_INPUT && id == mainloop_source && fd == signal_pipe[0]); + + for (;;) { + ssize_t r; + int sig; + struct signal_info*s; + + if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) { + if (errno == EAGAIN) + return; + + fprintf(stderr, "signal.c: read(): %s\n", strerror(errno)); + return; + } + + if (r != sizeof(sig)) { + fprintf(stderr, "signal.c: short read()\n"); + return; + } + + for (s = signals; s; s = s->next) + if (s->sig == sig) { + assert(s->callback); + s->callback(s, sig, s->userdata); + break; + } + } +} + +int pa_signal_init(struct pa_mainloop_api *a) { + assert(a); + if (pipe(signal_pipe) < 0) { + fprintf(stderr, "pipe() failed: %s\n", strerror(errno)); + return -1; + } + + pa_make_nonblock_fd(signal_pipe[0]); + pa_make_nonblock_fd(signal_pipe[1]); + + api = a; + mainloop_source = api->source_io(api, signal_pipe[0], PA_MAINLOOP_API_IO_EVENT_INPUT, callback, NULL); + assert(mainloop_source); + return 0; +} + +void pa_signal_done(void) { + assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && mainloop_source); + + api->cancel_io(api, mainloop_source); + mainloop_source = NULL; + + close(signal_pipe[0]); + close(signal_pipe[1]); + signal_pipe[0] = signal_pipe[1] = -1; + + while (signals) + pa_signal_unregister(signals); + + api = NULL; +} + +void* pa_signal_register(int sig, void (*callback) (void *id, int signal, void *userdata), void *userdata) { + struct signal_info *s = NULL; + struct sigaction sa; + assert(sig > 0 && callback); + + for (s = signals; s; s = s->next) + if (s->sig == sig) + goto fail; + + s = malloc(sizeof(struct signal_info)); + assert(s); + s->sig = sig; + s->callback = callback; + s->userdata = userdata; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = signal_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + + if (sigaction(sig, &sa, &s->saved_sigaction) < 0) + goto fail; + + s->previous = NULL; + s->next = signals; + signals = s; + + return s; +fail: + if (s) + free(s); + return NULL; +} + +void pa_signal_unregister(void *id) { + struct signal_info *s = id; + assert(s); + + if (s->next) + s->next->previous = s->previous; + if (s->previous) + s->previous->next = s->next; + else + signals = s->next; + + sigaction(s->sig, &s->saved_sigaction, NULL); + free(s); +} diff --git a/polyp/mainloop-signal.h b/polyp/mainloop-signal.h new file mode 100644 index 00000000..8afe9c8d --- /dev/null +++ b/polyp/mainloop-signal.h @@ -0,0 +1,33 @@ +#ifndef foomainloopsignalhfoo +#define foomainloopsignalhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "mainloop-api.h" + +int pa_signal_init(struct pa_mainloop_api *api); +void pa_signal_done(void); + +void* pa_signal_register(int signal, void (*callback) (void *id, int signal, void *userdata), void *userdata); +void pa_signal_unregister(void *id); + +#endif diff --git a/polyp/mainloop.c b/polyp/mainloop.c new file mode 100644 index 00000000..b9eee86d --- /dev/null +++ b/polyp/mainloop.c @@ -0,0 +1,553 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mainloop.h" +#include "util.h" +#include "idxset.h" + +struct mainloop_source_header { + struct pa_mainloop *mainloop; + int dead; +}; + +struct mainloop_source_io { + struct mainloop_source_header header; + + int fd; + enum pa_mainloop_api_io_events events; + void (*callback) (struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata); + void *userdata; + + struct pollfd *pollfd; +}; + +struct mainloop_source_fixed_or_idle { + struct mainloop_source_header header; + int enabled; + + void (*callback)(struct pa_mainloop_api*a, void *id, void *userdata); + void *userdata; +}; + +struct mainloop_source_time { + struct mainloop_source_header header; + int enabled; + + struct timeval timeval; + void (*callback)(struct pa_mainloop_api*a, void *id, const struct timeval*tv, void *userdata); + void *userdata; +}; + +struct pa_mainloop { + struct pa_idxset *io_sources, *fixed_sources, *idle_sources, *time_sources; + int io_sources_scan_dead, fixed_sources_scan_dead, idle_sources_scan_dead, time_sources_scan_dead; + + struct pollfd *pollfds; + unsigned max_pollfds, n_pollfds; + int rebuild_pollfds; + + int quit, running, retval; + struct pa_mainloop_api api; +}; + +static void setup_api(struct pa_mainloop *m); + +struct pa_mainloop *pa_mainloop_new(void) { + struct pa_mainloop *m; + + m = malloc(sizeof(struct pa_mainloop)); + assert(m); + + m->io_sources = pa_idxset_new(NULL, NULL); + m->fixed_sources = pa_idxset_new(NULL, NULL); + m->idle_sources = pa_idxset_new(NULL, NULL); + m->time_sources = pa_idxset_new(NULL, NULL); + + assert(m->io_sources && m->fixed_sources && m->idle_sources && m->time_sources); + + m->io_sources_scan_dead = m->fixed_sources_scan_dead = m->idle_sources_scan_dead = m->time_sources_scan_dead = 0; + + m->pollfds = NULL; + m->max_pollfds = m->n_pollfds = m->rebuild_pollfds = 0; + + m->quit = m->running = m->retval = 0; + + setup_api(m); + + return m; +} + +static int foreach(void *p, uint32_t index, int *del, void*userdata) { + struct mainloop_source_header *h = p; + int *all = userdata; + assert(p && del && all); + + if (*all || h->dead) { + free(h); + *del = 1; + } + + return 0; +}; + +void pa_mainloop_free(struct pa_mainloop* m) { + int all = 1; + assert(m); + pa_idxset_foreach(m->io_sources, foreach, &all); + pa_idxset_foreach(m->fixed_sources, foreach, &all); + pa_idxset_foreach(m->idle_sources, foreach, &all); + pa_idxset_foreach(m->time_sources, foreach, &all); + + pa_idxset_free(m->io_sources, NULL, NULL); + pa_idxset_free(m->fixed_sources, NULL, NULL); + pa_idxset_free(m->idle_sources, NULL, NULL); + pa_idxset_free(m->time_sources, NULL, NULL); + + free(m->pollfds); + free(m); +} + +static void scan_dead(struct pa_mainloop *m) { + int all = 0; + assert(m); + if (m->io_sources_scan_dead) + pa_idxset_foreach(m->io_sources, foreach, &all); + if (m->fixed_sources_scan_dead) + pa_idxset_foreach(m->fixed_sources, foreach, &all); + if (m->idle_sources_scan_dead) + pa_idxset_foreach(m->idle_sources, foreach, &all); + if (m->time_sources_scan_dead) + pa_idxset_foreach(m->time_sources, foreach, &all); +} + +static void rebuild_pollfds(struct pa_mainloop *m) { + struct mainloop_source_io*s; + struct pollfd *p; + uint32_t index = PA_IDXSET_INVALID; + unsigned l; + + l = pa_idxset_ncontents(m->io_sources); + if (m->max_pollfds < l) { + m->pollfds = realloc(m->pollfds, sizeof(struct pollfd)*l); + m->max_pollfds = l; + } + + m->n_pollfds = 0; + p = m->pollfds; + for (s = pa_idxset_first(m->io_sources, &index); s; s = pa_idxset_next(m->io_sources, &index)) { + if (s->header.dead) { + s->pollfd = NULL; + continue; + } + + s->pollfd = p; + p->fd = s->fd; + p->events = ((s->events & PA_MAINLOOP_API_IO_EVENT_INPUT) ? POLLIN : 0) | ((s->events & PA_MAINLOOP_API_IO_EVENT_OUTPUT) ? POLLOUT : 0); + p->revents = 0; + + p++; + m->n_pollfds++; + } +} + +static void dispatch_pollfds(struct pa_mainloop *m) { + uint32_t index = PA_IDXSET_INVALID; + struct mainloop_source_io *s; + + for (s = pa_idxset_first(m->io_sources, &index); s; s = pa_idxset_next(m->io_sources, &index)) { + if (s->header.dead || !s->pollfd || !s->pollfd->revents) + continue; + + assert(s->pollfd->fd == s->fd && s->callback); + s->callback(&m->api, s, s->fd, + ((s->pollfd->revents & POLLHUP) ? PA_MAINLOOP_API_IO_EVENT_HUP : 0) | + ((s->pollfd->revents & POLLIN) ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | + ((s->pollfd->revents & POLLOUT) ? PA_MAINLOOP_API_IO_EVENT_OUTPUT : 0), s->userdata); + s->pollfd->revents = 0; + } +} + +static void run_fixed_or_idle(struct pa_mainloop *m, struct pa_idxset *i) { + uint32_t index = PA_IDXSET_INVALID; + struct mainloop_source_fixed_or_idle *s; + + for (s = pa_idxset_first(i, &index); s; s = pa_idxset_next(i, &index)) { + if (s->header.dead || !s->enabled) + continue; + + assert(s->callback); + s->callback(&m->api, s, s->userdata); + } +} + +static int calc_next_timeout(struct pa_mainloop *m) { + uint32_t index = PA_IDXSET_INVALID; + struct mainloop_source_time *s; + struct timeval now; + int t = -1; + + if (pa_idxset_isempty(m->time_sources)) + return -1; + + gettimeofday(&now, NULL); + + for (s = pa_idxset_first(m->time_sources, &index); s; s = pa_idxset_next(m->time_sources, &index)) { + int tmp; + + if (s->header.dead || !s->enabled) + continue; + + if (s->timeval.tv_sec < now.tv_sec || (s->timeval.tv_sec == now.tv_sec && s->timeval.tv_usec <= now.tv_usec)) + return 0; + + tmp = (s->timeval.tv_sec - now.tv_sec)*1000; + + if (s->timeval.tv_usec > now.tv_usec) + tmp += (s->timeval.tv_usec - now.tv_usec)/1000; + else + tmp -= (now.tv_usec - s->timeval.tv_usec)/1000; + + if (tmp == 0) + return 0; + else if (t == -1 || tmp < t) + t = tmp; + } + + return t; +} + +static void dispatch_timeout(struct pa_mainloop *m) { + uint32_t index = PA_IDXSET_INVALID; + struct mainloop_source_time *s; + struct timeval now; + assert(m); + + if (pa_idxset_isempty(m->time_sources)) + return; + + gettimeofday(&now, NULL); + for (s = pa_idxset_first(m->time_sources, &index); s; s = pa_idxset_next(m->time_sources, &index)) { + + if (s->header.dead || !s->enabled) + continue; + + if (s->timeval.tv_sec < now.tv_sec || (s->timeval.tv_sec == now.tv_sec && s->timeval.tv_usec <= now.tv_usec)) { + assert(s->callback); + + s->enabled = 0; + s->callback(&m->api, s, &s->timeval, s->userdata); + } + } +} + +static int any_idle_sources(struct pa_mainloop *m) { + struct mainloop_source_fixed_or_idle *s; + uint32_t index; + assert(m); + + for (s = pa_idxset_first(m->idle_sources, &index); s; s = pa_idxset_next(m->idle_sources, &index)) + if (!s->header.dead && s->enabled) + return 1; + + return 0; +} + +int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval) { + int r, idle; + assert(m && !m->running); + + if(m->quit) { + if (retval) + *retval = m->retval; + return 1; + } + + m->running = 1; + + scan_dead(m); + run_fixed_or_idle(m, m->fixed_sources); + + if (m->rebuild_pollfds) { + rebuild_pollfds(m); + m->rebuild_pollfds = 0; + } + + idle = any_idle_sources(m); + + do { + int t; + + if (!block || idle) + t = 0; + else + t = calc_next_timeout(m); + + r = poll(m->pollfds, m->n_pollfds, t); + } while (r < 0 && errno == EINTR); + + dispatch_timeout(m); + + if (r > 0) + dispatch_pollfds(m); + else if (r == 0 && idle) + run_fixed_or_idle(m, m->idle_sources); + else if (r < 0) + fprintf(stderr, "select(): %s\n", strerror(errno)); + + m->running = 0; + return r < 0 ? -1 : 0; +} + +int pa_mainloop_run(struct pa_mainloop *m, int *retval) { + int r; + while ((r = pa_mainloop_iterate(m, 1, retval)) == 0); + return r; +} + +void pa_mainloop_quit(struct pa_mainloop *m, int r) { + assert(m); + m->quit = r; +} + +/* IO sources */ +static void* mainloop_source_io(struct pa_mainloop_api*a, int fd, enum pa_mainloop_api_io_events events, void (*callback) (struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata), void *userdata) { + struct pa_mainloop *m; + struct mainloop_source_io *s; + assert(a && a->userdata && fd >= 0 && callback); + m = a->userdata; + assert(a == &m->api); + + s = malloc(sizeof(struct mainloop_source_io)); + assert(s); + s->header.mainloop = m; + s->header.dead = 0; + + s->fd = fd; + s->events = events; + s->callback = callback; + s->userdata = userdata; + s->pollfd = NULL; + + pa_idxset_put(m->io_sources, s, NULL); + m->rebuild_pollfds = 1; + return s; +} + +static void mainloop_enable_io(struct pa_mainloop_api*a, void* id, enum pa_mainloop_api_io_events events) { + struct pa_mainloop *m; + struct mainloop_source_io *s = id; + assert(a && a->userdata && s && !s->header.dead); + m = a->userdata; + assert(a == &m->api && s->header.mainloop == m); + + s->events = events; + if (s->pollfd) + s->pollfd->events = ((s->events & PA_MAINLOOP_API_IO_EVENT_INPUT) ? POLLIN : 0) | ((s->events & PA_MAINLOOP_API_IO_EVENT_OUTPUT) ? POLLOUT : 0); +} + +static void mainloop_cancel_io(struct pa_mainloop_api*a, void* id) { + struct pa_mainloop *m; + struct mainloop_source_io *s = id; + assert(a && a->userdata && s && !s->header.dead); + m = a->userdata; + assert(a == &m->api && s->header.mainloop == m); + + s->header.dead = 1; + m->io_sources_scan_dead = 1; + m->rebuild_pollfds = 1; +} + +/* Fixed sources */ +static void* mainloop_source_fixed(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, void *id, void *userdata), void *userdata) { + struct pa_mainloop *m; + struct mainloop_source_fixed_or_idle *s; + assert(a && a->userdata && callback); + m = a->userdata; + assert(a == &m->api); + + s = malloc(sizeof(struct mainloop_source_fixed_or_idle)); + assert(s); + s->header.mainloop = m; + s->header.dead = 0; + + s->enabled = 1; + s->callback = callback; + s->userdata = userdata; + + pa_idxset_put(m->fixed_sources, s, NULL); + return s; +} + +static void mainloop_enable_fixed(struct pa_mainloop_api*a, void* id, int b) { + struct pa_mainloop *m; + struct mainloop_source_fixed_or_idle *s = id; + assert(a && a->userdata && s && !s->header.dead); + m = a->userdata; + assert(a == &m->api); + + s->enabled = b; +} + +static void mainloop_cancel_fixed(struct pa_mainloop_api*a, void* id) { + struct pa_mainloop *m; + struct mainloop_source_fixed_or_idle *s = id; + assert(a && a->userdata && s && !s->header.dead); + m = a->userdata; + assert(a == &m->api); + + s->header.dead = 1; + m->fixed_sources_scan_dead = 1; +} + +/* Idle sources */ +static void* mainloop_source_idle(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, void *id, void *userdata), void *userdata) { + struct pa_mainloop *m; + struct mainloop_source_fixed_or_idle *s; + assert(a && a->userdata && callback); + m = a->userdata; + assert(a == &m->api); + + s = malloc(sizeof(struct mainloop_source_fixed_or_idle)); + assert(s); + s->header.mainloop = m; + s->header.dead = 0; + + s->enabled = 1; + s->callback = callback; + s->userdata = userdata; + + pa_idxset_put(m->idle_sources, s, NULL); + return s; +} + +static void mainloop_cancel_idle(struct pa_mainloop_api*a, void* id) { + struct pa_mainloop *m; + struct mainloop_source_fixed_or_idle *s = id; + assert(a && a->userdata && s && !s->header.dead); + m = a->userdata; + assert(a == &m->api); + + s->header.dead = 1; + m->idle_sources_scan_dead = 1; +} + +/* Time sources */ +static void* mainloop_source_time(struct pa_mainloop_api*a, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*a, void *id, const struct timeval *tv, void *userdata), void *userdata) { + struct pa_mainloop *m; + struct mainloop_source_time *s; + assert(a && a->userdata && callback); + m = a->userdata; + assert(a == &m->api); + + s = malloc(sizeof(struct mainloop_source_time)); + assert(s); + s->header.mainloop = m; + s->header.dead = 0; + + s->enabled = !!tv; + if (tv) + s->timeval = *tv; + + s->callback = callback; + s->userdata = userdata; + + pa_idxset_put(m->time_sources, s, NULL); + return s; +} + +static void mainloop_enable_time(struct pa_mainloop_api*a, void *id, const struct timeval *tv) { + struct pa_mainloop *m; + struct mainloop_source_time *s = id; + assert(a && a->userdata && s && !s->header.dead); + m = a->userdata; + assert(a == &m->api); + + if (tv) { + s->enabled = 1; + s->timeval = *tv; + } else + s->enabled = 0; +} + +static void mainloop_cancel_time(struct pa_mainloop_api*a, void* id) { + struct pa_mainloop *m; + struct mainloop_source_time *s = id; + assert(a && a->userdata && s && !s->header.dead); + m = a->userdata; + assert(a == &m->api); + + s->header.dead = 1; + m->time_sources_scan_dead = 1; + +} + +static void mainloop_quit(struct pa_mainloop_api*a, int retval) { + struct pa_mainloop *m; + assert(a && a->userdata); + m = a->userdata; + assert(a == &m->api); + + m->quit = 1; + m->retval = retval; +} + +static void setup_api(struct pa_mainloop *m) { + assert(m); + + m->api.userdata = m; + m->api.source_io = mainloop_source_io; + m->api.enable_io = mainloop_enable_io; + m->api.cancel_io = mainloop_cancel_io; + + m->api.source_fixed = mainloop_source_fixed; + m->api.enable_fixed = mainloop_enable_fixed; + m->api.cancel_fixed = mainloop_cancel_fixed; + + m->api.source_idle = mainloop_source_idle; + m->api.enable_idle = mainloop_enable_fixed; /* (!) */ + m->api.cancel_idle = mainloop_cancel_idle; + + m->api.source_time = mainloop_source_time; + m->api.enable_time = mainloop_enable_time; + m->api.cancel_time = mainloop_cancel_time; + + m->api.quit = mainloop_quit; +} + +struct pa_mainloop_api* pa_mainloop_get_api(struct pa_mainloop*m) { + assert(m); + return &m->api; +} + diff --git a/polyp/mainloop.h b/polyp/mainloop.h new file mode 100644 index 00000000..58448c3e --- /dev/null +++ b/polyp/mainloop.h @@ -0,0 +1,37 @@ +#ifndef foomainloophfoo +#define foomainloophfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "mainloop-api.h" + +struct pa_mainloop; + +struct pa_mainloop *pa_mainloop_new(void); +void pa_mainloop_free(struct pa_mainloop* m); + +int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval); +int pa_mainloop_run(struct pa_mainloop *m, int *retval); + +struct pa_mainloop_api* pa_mainloop_get_api(struct pa_mainloop*m); + +#endif diff --git a/polyp/memblock.c b/polyp/memblock.c new file mode 100644 index 00000000..8f24ff22 --- /dev/null +++ b/polyp/memblock.c @@ -0,0 +1,113 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "memblock.h" + +static unsigned memblock_count = 0, memblock_total = 0; + +struct pa_memblock *pa_memblock_new(size_t length) { + struct pa_memblock *b = malloc(sizeof(struct pa_memblock)+length); + b->type = PA_MEMBLOCK_APPENDED; + b->ref = 1; + b->length = length; + b->data = b+1; + memblock_count++; + memblock_total += length; + return b; +} + +struct pa_memblock *pa_memblock_new_fixed(void *d, size_t length) { + struct pa_memblock *b = malloc(sizeof(struct pa_memblock)); + b->type = PA_MEMBLOCK_FIXED; + b->ref = 1; + b->length = length; + b->data = d; + memblock_count++; + memblock_total += length; + return b; +} + +struct pa_memblock *pa_memblock_new_dynamic(void *d, size_t length) { + struct pa_memblock *b = malloc(sizeof(struct pa_memblock)); + b->type = PA_MEMBLOCK_DYNAMIC; + b->ref = 1; + b->length = length; + b->data = d; + memblock_count++; + memblock_total += length; + return b; +} + +struct pa_memblock* pa_memblock_ref(struct pa_memblock*b) { + assert(b && b->ref >= 1); + b->ref++; + return b; +} + +void pa_memblock_unref(struct pa_memblock*b) { + assert(b && b->ref >= 1); + b->ref--; + + if (b->ref == 0) { + if (b->type == PA_MEMBLOCK_DYNAMIC) + free(b->data); + + memblock_count--; + memblock_total -= b->length; + + free(b); + } +} + +void pa_memblock_unref_fixed(struct pa_memblock *b) { + void *d; + + assert(b && b->ref >= 1); + + if (b->ref == 1) { + pa_memblock_unref(b); + return; + } else { + d = malloc(b->length); + assert(d); + memcpy(d, b->data, b->length); + b->data = d; + b->type = PA_MEMBLOCK_DYNAMIC; + b->ref--; + } +} + +unsigned pa_memblock_get_count(void) { + return memblock_count; +} + +unsigned pa_memblock_get_total(void) { + return memblock_total; +} diff --git a/polyp/memblock.h b/polyp/memblock.h new file mode 100644 index 00000000..4bb02977 --- /dev/null +++ b/polyp/memblock.h @@ -0,0 +1,49 @@ +#ifndef foomemblockhfoo +#define foomemblockhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +enum pa_memblock_type { PA_MEMBLOCK_FIXED, PA_MEMBLOCK_APPENDED, PA_MEMBLOCK_DYNAMIC }; + +struct pa_memblock { + enum pa_memblock_type type; + unsigned ref; + size_t length; + void *data; +}; + +struct pa_memblock *pa_memblock_new(size_t length); +struct pa_memblock *pa_memblock_new_fixed(void *data, size_t length); +struct pa_memblock *pa_memblock_new_dynamic(void *data, size_t length); + +void pa_memblock_unref(struct pa_memblock*b); +struct pa_memblock* pa_memblock_ref(struct pa_memblock*b); + +void pa_memblock_unref_fixed(struct pa_memblock*b); + +unsigned pa_memblock_get_count(void); +unsigned pa_memblock_get_total(void); + +#endif diff --git a/polyp/memblockq.c b/polyp/memblockq.c new file mode 100644 index 00000000..eff923b9 --- /dev/null +++ b/polyp/memblockq.c @@ -0,0 +1,326 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "memblockq.h" + +struct memblock_list { + struct memblock_list *next; + struct pa_memchunk chunk; + struct timeval stamp; +}; + +struct pa_memblockq { + struct memblock_list *blocks, *blocks_tail; + unsigned n_blocks; + size_t current_length, maxlength, tlength, base, prebuf, minreq; + int measure_delay; + uint32_t delay; + struct pa_mcalign *mcalign; +}; + +struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t base, size_t prebuf, size_t minreq) { + struct pa_memblockq* bq; + assert(maxlength && base && maxlength); + + bq = malloc(sizeof(struct pa_memblockq)); + assert(bq); + bq->blocks = bq->blocks_tail = 0; + bq->n_blocks = 0; + + bq->current_length = 0; + + fprintf(stderr, "memblockq requested: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", maxlength, tlength, base, prebuf, minreq); + + bq->base = base; + + bq->maxlength = ((maxlength+base-1)/base)*base; + assert(bq->maxlength >= base); + + bq->tlength = ((tlength+base-1)/base)*base; + if (bq->tlength == 0 || bq->tlength >= bq->maxlength) + bq->tlength = bq->maxlength; + + bq->prebuf = (prebuf == (size_t) -1) ? bq->maxlength/2 : prebuf; + bq->prebuf = (bq->prebuf/base)*base; + if (bq->prebuf > bq->maxlength) + bq->prebuf = bq->maxlength; + + bq->minreq = (minreq/base)*base; + if (bq->minreq == 0) + bq->minreq = 1; + + fprintf(stderr, "memblockq sanitized: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", bq->maxlength, bq->tlength, bq->base, bq->prebuf, bq->minreq); + + bq->measure_delay = 0; + bq->delay = 0; + + bq->mcalign = NULL; + + return bq; +} + +void pa_memblockq_free(struct pa_memblockq* bq) { + struct memblock_list *l; + assert(bq); + + if (bq->mcalign) + pa_mcalign_free(bq->mcalign); + + while ((l = bq->blocks)) { + bq->blocks = l->next; + pa_memblock_unref(l->chunk.memblock); + free(l); + } + + free(bq); +} + +void pa_memblockq_push(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta) { + struct memblock_list *q; + assert(bq && chunk && chunk->memblock && chunk->length && (chunk->length % bq->base) == 0); + + if (bq->blocks_tail && bq->blocks_tail->chunk.memblock == chunk->memblock) { + /* Try to merge memory chunks */ + + if (bq->blocks_tail->chunk.index+bq->blocks_tail->chunk.length == chunk->index) { + bq->blocks_tail->chunk.length += chunk->length; + bq->current_length += chunk->length; + + /* fprintf(stderr, __FILE__": merge succeeded: %u\n", chunk->length);*/ + return; + } + } + + q = malloc(sizeof(struct memblock_list)); + assert(q); + + if (bq->measure_delay) + gettimeofday(&q->stamp, NULL); + else + timerclear(&q->stamp); + + q->chunk = *chunk; + pa_memblock_ref(q->chunk.memblock); + assert(q->chunk.index+q->chunk.length <= q->chunk.memblock->length); + q->next = NULL; + + if (bq->blocks_tail) + bq->blocks_tail->next = q; + else + bq->blocks = q; + + bq->blocks_tail = q; + + bq->n_blocks++; + bq->current_length += chunk->length; + + pa_memblockq_shorten(bq, bq->maxlength); +} + +int pa_memblockq_peek(struct pa_memblockq* bq, struct pa_memchunk *chunk) { + assert(bq && chunk); + + if (!bq->blocks || bq->current_length < bq->prebuf) + return -1; + + bq->prebuf = 0; + + *chunk = bq->blocks->chunk; + pa_memblock_ref(chunk->memblock); + +/* if (chunk->memblock->ref != 2) */ +/* fprintf(stderr, "block %p with ref %u peeked.\n", chunk->memblock, chunk->memblock->ref); */ + + return 0; +} + +/* +int memblockq_pop(struct memblockq* bq, struct pa_memchunk *chunk) { + struct memblock_list *q; + + assert(bq && chunk); + + if (!bq->blocks || bq->current_length < bq->prebuf) + return -1; + + bq->prebuf = 0; + + q = bq->blocks; + bq->blocks = bq->blocks->next; + + *chunk = q->chunk; + + bq->n_blocks--; + bq->current_length -= chunk->length; + + free(q); + return 0; +} +*/ + +static uint32_t age(struct timeval *tv) { + assert(tv); + struct timeval now; + uint32_t r; + + if (tv->tv_sec == 0) + return 0; + + gettimeofday(&now, NULL); + + r = (now.tv_sec-tv->tv_sec) * 1000000; + + if (now.tv_usec >= tv->tv_usec) + r += now.tv_usec - tv->tv_usec; + else + r -= tv->tv_usec - now.tv_usec; + + return r; +} + +void pa_memblockq_drop(struct pa_memblockq *bq, size_t length) { + assert(bq && length && (length % bq->base) == 0); + + while (length > 0) { + size_t l = length; + assert(bq->blocks && bq->current_length >= length); + + if (l > bq->blocks->chunk.length) + l = bq->blocks->chunk.length; + + if (bq->measure_delay) + bq->delay = age(&bq->blocks->stamp); + + bq->blocks->chunk.index += l; + bq->blocks->chunk.length -= l; + bq->current_length -= l; + + if (bq->blocks->chunk.length == 0) { + struct memblock_list *q; + + q = bq->blocks; + bq->blocks = bq->blocks->next; + if (bq->blocks == NULL) + bq->blocks_tail = NULL; + pa_memblock_unref(q->chunk.memblock); + free(q); + + bq->n_blocks--; + } + + length -= l; + } +} + +void pa_memblockq_shorten(struct pa_memblockq *bq, size_t length) { + size_t l; + assert(bq); + + if (bq->current_length <= length) + return; + + fprintf(stderr, "Warning! pa_memblockq_shorten()\n"); + + l = bq->current_length - length; + l /= bq->base; + l *= bq->base; + + pa_memblockq_drop(bq, l); +} + + +void pa_memblockq_empty(struct pa_memblockq *bq) { + assert(bq); + pa_memblockq_shorten(bq, 0); +} + +int pa_memblockq_is_readable(struct pa_memblockq *bq) { + assert(bq); + + return bq->current_length && (bq->current_length >= bq->prebuf); +} + +int pa_memblockq_is_writable(struct pa_memblockq *bq, size_t length) { + assert(bq); + + return bq->current_length + length <= bq->tlength; +} + +uint32_t pa_memblockq_get_delay(struct pa_memblockq *bq) { + assert(bq); + return bq->delay; +} + +uint32_t pa_memblockq_get_length(struct pa_memblockq *bq) { + assert(bq); + return bq->current_length; +} + +uint32_t pa_memblockq_missing(struct pa_memblockq *bq) { + size_t l; + assert(bq); + + if (bq->current_length >= bq->tlength) + return 0; + + l = bq->tlength - bq->current_length; + assert(l); + + return (l >= bq->minreq) ? l : 0; +} + +void pa_memblockq_push_align(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta) { + struct pa_memchunk rchunk; + assert(bq && chunk && bq->base); + + if (bq->base == 1) { + pa_memblockq_push(bq, chunk, delta); + return; + } + + if (!bq->mcalign) { + bq->mcalign = pa_mcalign_new(bq->base); + assert(bq->mcalign); + } + + pa_mcalign_push(bq->mcalign, chunk); + + while (pa_mcalign_pop(bq->mcalign, &rchunk) >= 0) { + pa_memblockq_push(bq, &rchunk, delta); + pa_memblock_unref(rchunk.memblock); + delta = 0; + } +} + +uint32_t pa_memblockq_get_minreq(struct pa_memblockq *bq) { + assert(bq); + return bq->minreq; +} diff --git a/polyp/memblockq.h b/polyp/memblockq.h new file mode 100644 index 00000000..e6ad01db --- /dev/null +++ b/polyp/memblockq.h @@ -0,0 +1,82 @@ +#ifndef foomemblockqhfoo +#define foomemblockqhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "memblock.h" +#include "memchunk.h" + +struct pa_memblockq; + +/* Parameters: + - maxlength: maximum length of queue. If more data is pushed into the queue, data from the front is dropped + - length: the target length of the queue. + - base: a base value for all metrics. Only multiples of this value are popped from the queue + - prebuf: before passing the first byte out, make sure that enough bytes are in the queue + - minreq: pa_memblockq_missing() will only return values greater than this value +*/ +struct pa_memblockq* pa_memblockq_new(size_t maxlength, + size_t tlength, + size_t base, + size_t prebuf, + size_t minreq); +void pa_memblockq_free(struct pa_memblockq*bq); + +/* Push a new memory chunk into the queue. Optionally specify a value for future cancellation. This is currently not implemented, however! */ +void pa_memblockq_push(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta); + +/* Same as pa_memblockq_push(), however chunks are filtered through a mcalign object, and thus aligned to multiples of base */ +void pa_memblockq_push_align(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta); + +/* Return a copy of the next memory chunk in the queue. It is not removed from the queue */ +int pa_memblockq_peek(struct pa_memblockq* bq, struct pa_memchunk *chunk); + +/* Drop the specified bytes from the queue */ +void pa_memblockq_drop(struct pa_memblockq *bq, size_t length); + +/* Shorten the pa_memblockq to the specified length by dropping data at the end of the queue */ +void pa_memblockq_shorten(struct pa_memblockq *bq, size_t length); + +/* Empty the pa_memblockq */ +void pa_memblockq_empty(struct pa_memblockq *bq); + +/* Test if the pa_memblockq is currently readable, that is, more data than base */ +int pa_memblockq_is_readable(struct pa_memblockq *bq); + +/* Test if the pa_memblockq is currently writable for the specified amount of bytes */ +int pa_memblockq_is_writable(struct pa_memblockq *bq, size_t length); + +/* The time memory chunks stay in the queue until they are removed completely in usecs */ +uint32_t pa_memblockq_get_delay(struct pa_memblockq *bq); + +/* Return the length of the queue in bytes */ +uint32_t pa_memblockq_get_length(struct pa_memblockq *bq); + +/* Return how many bytes are missing in queue to the specified fill amount */ +uint32_t pa_memblockq_missing(struct pa_memblockq *bq); + + +uint32_t pa_memblockq_get_minreq(struct pa_memblockq *bq); + +#endif diff --git a/polyp/memchunk.c b/polyp/memchunk.c new file mode 100644 index 00000000..d27ca61a --- /dev/null +++ b/polyp/memchunk.c @@ -0,0 +1,149 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "memchunk.h" + +void pa_memchunk_make_writable(struct pa_memchunk *c) { + struct pa_memblock *n; + assert(c && c->memblock && c->memblock->ref >= 1); + + if (c->memblock->ref == 1) + return; + + n = pa_memblock_new(c->length); + assert(n); + memcpy(n->data, c->memblock->data+c->index, c->length); + pa_memblock_unref(c->memblock); + c->memblock = n; + c->index = 0; +} + + +struct pa_mcalign { + size_t base; + struct pa_memchunk chunk; + uint8_t *buffer; + size_t buffer_fill; +}; + +struct pa_mcalign *pa_mcalign_new(size_t base) { + struct pa_mcalign *m; + assert(base); + + m = malloc(sizeof(struct pa_mcalign)); + assert(m); + m->base = base; + m->chunk.memblock = NULL; + m->chunk.length = m->chunk.index = 0; + m->buffer = NULL; + m->buffer_fill = 0; + return m; +} + +void pa_mcalign_free(struct pa_mcalign *m) { + assert(m); + + free(m->buffer); + + if (m->chunk.memblock) + pa_memblock_unref(m->chunk.memblock); + + free(m); +} + +void pa_mcalign_push(struct pa_mcalign *m, const struct pa_memchunk *c) { + assert(m && c && !m->chunk.memblock && c->memblock && c->length); + + m->chunk = *c; + pa_memblock_ref(m->chunk.memblock); +} + +int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c) { + assert(m && c && m->base > m->buffer_fill); + int ret; + + if (!m->chunk.memblock) + return -1; + + if (m->buffer_fill) { + size_t l = m->base - m->buffer_fill; + if (l > m->chunk.length) + l = m->chunk.length; + assert(m->buffer && l); + + memcpy(m->buffer + m->buffer_fill, m->chunk.memblock->data + m->chunk.index, l); + m->buffer_fill += l; + m->chunk.index += l; + m->chunk.length -= l; + + if (m->chunk.length == 0) { + m->chunk.length = m->chunk.index = 0; + pa_memblock_unref(m->chunk.memblock); + m->chunk.memblock = NULL; + } + + assert(m->buffer_fill <= m->base); + if (m->buffer_fill == m->base) { + c->memblock = pa_memblock_new_dynamic(m->buffer, m->base); + assert(c->memblock); + c->index = 0; + c->length = m->base; + m->buffer = NULL; + m->buffer_fill = 0; + + return 0; + } + + return -1; + } + + m->buffer_fill = m->chunk.length % m->base; + + if (m->buffer_fill) { + assert(!m->buffer); + m->buffer = malloc(m->base); + assert(m->buffer); + m->chunk.length -= m->buffer_fill; + memcpy(m->buffer, m->chunk.memblock->data + m->chunk.index + m->chunk.length, m->buffer_fill); + } + + if (m->chunk.length) { + *c = m->chunk; + pa_memblock_ref(c->memblock); + ret = 0; + } else + ret = -1; + + m->chunk.length = m->chunk.index = 0; + pa_memblock_unref(m->chunk.memblock); + m->chunk.memblock = NULL; + + return ret; +} diff --git a/polyp/memchunk.h b/polyp/memchunk.h new file mode 100644 index 00000000..341c145c --- /dev/null +++ b/polyp/memchunk.h @@ -0,0 +1,41 @@ +#ifndef foomemchunkhfoo +#define foomemchunkhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "memblock.h" + +struct pa_memchunk { + struct pa_memblock *memblock; + size_t index, length; +}; + +void pa_memchunk_make_writable(struct pa_memchunk *c); + +struct pa_mcalign; + +struct pa_mcalign *pa_mcalign_new(size_t base); +void pa_mcalign_free(struct pa_mcalign *m); +void pa_mcalign_push(struct pa_mcalign *m, const struct pa_memchunk *c); +int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c); + +#endif diff --git a/polyp/modargs.c b/polyp/modargs.c new file mode 100644 index 00000000..280a546d --- /dev/null +++ b/polyp/modargs.c @@ -0,0 +1,288 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "hashmap.h" +#include "modargs.h" +#include "idxset.h" +#include "sample-util.h" +#include "namereg.h" +#include "sink.h" +#include "source.h" + +struct pa_modargs; + +struct entry { + char *key, *value; +}; + +static int add_key_value(struct pa_hashmap *map, char *key, char *value, const char* const* valid_keys) { + struct entry *e; + assert(map && key && value); + + if (valid_keys) { + const char*const* v; + for (v = valid_keys; *v; v++) + if (strcmp(*v, key) == 0) + break; + + if (!*v) { + free(key); + free(value); + return -1; + } + } + + e = malloc(sizeof(struct entry)); + assert(e); + e->key = key; + e->value = value; + pa_hashmap_put(map, key, e); + return 0; +} + +struct pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) { + struct pa_hashmap *map = NULL; + + map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + assert(map); + + if (args) { + enum { WHITESPACE, KEY, VALUE_START, VALUE_SIMPLE, VALUE_DOUBLE_QUOTES, VALUE_TICKS } state; + const char *p, *key, *value; + size_t key_len, value_len; + + key = value = NULL; + state = WHITESPACE; + for (p = args; *p; p++) { + switch (state) { + case WHITESPACE: + if (*p == '=') + goto fail; + else if (!isspace(*p)) { + key = p; + state = KEY; + key_len = 1; + } + break; + case KEY: + if (*p == '=') + state = VALUE_START; + else + key_len++; + break; + case VALUE_START: + if (*p == '\'') { + state = VALUE_TICKS; + value = p+1; + value_len = 0; + } else if (*p == '"') { + state = VALUE_DOUBLE_QUOTES; + value = p+1; + value_len = 0; + } else if (isspace(*p)) { + if (add_key_value(map, strndup(key, key_len), strdup(""), valid_keys) < 0) + goto fail; + state = WHITESPACE; + } else { + state = VALUE_SIMPLE; + value = p; + value_len = 1; + } + break; + case VALUE_SIMPLE: + if (isspace(*p)) { + if (add_key_value(map, strndup(key, key_len), strndup(value, value_len), valid_keys) < 0) + goto fail; + state = WHITESPACE; + } else + value_len++; + break; + case VALUE_DOUBLE_QUOTES: + if (*p == '"') { + if (add_key_value(map, strndup(key, key_len), strndup(value, value_len), valid_keys) < 0) + goto fail; + state = WHITESPACE; + } else + value_len++; + break; + case VALUE_TICKS: + if (*p == '\'') { + if (add_key_value(map, strndup(key, key_len), strndup(value, value_len), valid_keys) < 0) + goto fail; + state = WHITESPACE; + } else + value_len++; + break; + } + } + + if (state == VALUE_START) { + if (add_key_value(map, strndup(key, key_len), strdup(""), valid_keys) < 0) + goto fail; + } else if (state == VALUE_SIMPLE) { + if (add_key_value(map, strndup(key, key_len), strdup(value), valid_keys) < 0) + goto fail; + } else if (state != WHITESPACE) + goto fail; + } + + return (struct pa_modargs*) map; + +fail: + + if (map) + pa_modargs_free((struct pa_modargs*) map); + + return NULL; +} + + +static void free_func(void *p, void*userdata) { + struct entry *e = p; + assert(e); + free(e->key); + free(e->value); + free(e); +} + +void pa_modargs_free(struct pa_modargs*ma) { + struct pa_hashmap *map = (struct pa_hashmap*) ma; + pa_hashmap_free(map, free_func, NULL); +} + +const char *pa_modargs_get_value(struct pa_modargs *ma, const char *key, const char *def) { + struct pa_hashmap *map = (struct pa_hashmap*) ma; + struct entry*e; + + if (!(e = pa_hashmap_get(map, key))) + return def; + + return e->value; +} + +int pa_modargs_get_value_u32(struct pa_modargs *ma, const char *key, uint32_t *value) { + const char *v; + char *e; + unsigned long l; + assert(ma && key && value); + + if (!(v = pa_modargs_get_value(ma, key, NULL))) + return 0; + + if (!*v) + return -1; + + l = strtoul(v, &e, 0); + if (*e) + return -1; + + *value = (uint32_t) l; + return 0; +} + +int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *rss) { + const char *format; + uint32_t channels; + struct pa_sample_spec ss; + assert(ma && rss); + + ss = *rss; + if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0) + return -1; + + channels = ss.channels; + if ((pa_modargs_get_value_u32(ma, "channels", &channels)) < 0) + return -1; + ss.channels = (uint8_t) channels; + + if ((format = pa_modargs_get_value(ma, "format", NULL))) { + if (strcmp(format, "s16le") == 0) + ss.format = PA_SAMPLE_S16LE; + else if (strcmp(format, "s16be") == 0) + ss.format = PA_SAMPLE_S16BE; + else if (strcmp(format, "s16ne") == 0 || strcmp(format, "s16") == 0 || strcmp(format, "16") == 0) + ss.format = PA_SAMPLE_S16NE; + else if (strcmp(format, "u8") == 0 || strcmp(format, "8") == 0) + ss.format = PA_SAMPLE_U8; + else if (strcmp(format, "float32") == 0 || strcmp(format, "float32ne") == 0) + ss.format = PA_SAMPLE_FLOAT32; + else if (strcmp(format, "float32le") == 0) + ss.format = PA_SAMPLE_FLOAT32LE; + else if (strcmp(format, "float32be") == 0) + ss.format = PA_SAMPLE_FLOAT32BE; + else if (strcmp(format, "ulaw") == 0) + ss.format = PA_SAMPLE_ULAW; + else if (strcmp(format, "alaw") == 0) + ss.format = PA_SAMPLE_ALAW; + else + return -1; + } + + if (!pa_sample_spec_valid(&ss)) + return -1; + + *rss = ss; + + return 0; +} + +int pa_modargs_get_source_index(struct pa_modargs *ma, struct pa_core *c, uint32_t *index) { + const char *t; + assert(ma && index); + + if (!(t = pa_modargs_get_value(ma, "source", NULL))) + *index = PA_IDXSET_INVALID; + else { + struct pa_source *source; + if (!(source = pa_namereg_get(c, t, PA_NAMEREG_SOURCE))) + return -1; + + *index = source->index; + } + + return 0; +} + +int pa_modargs_get_sink_index(struct pa_modargs *ma, struct pa_core *c, uint32_t *index) { + const char *t; + assert(ma && index); + + if (!(t = pa_modargs_get_value(ma, "sink", NULL))) + *index = PA_IDXSET_INVALID; + else { + struct pa_sink *sink; + if (!(sink = pa_namereg_get(c, t, PA_NAMEREG_SINK))) + return -1; + + *index = sink->index; + } + + return 0; +} diff --git a/polyp/modargs.h b/polyp/modargs.h new file mode 100644 index 00000000..301dc297 --- /dev/null +++ b/polyp/modargs.h @@ -0,0 +1,42 @@ +#ifndef foomodargshfoo +#define foomodargshfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include "sample.h" +#include "core.h" + +struct pa_modargs; + +struct pa_modargs *pa_modargs_new(const char *args, const char* const* keys); +void pa_modargs_free(struct pa_modargs*ma); + +const char *pa_modargs_get_value(struct pa_modargs *ma, const char *key, const char *def); +int pa_modargs_get_value_u32(struct pa_modargs *ma, const char *key, uint32_t *value); + +int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *ss); + +int pa_modargs_get_source_index(struct pa_modargs *ma, struct pa_core *c, uint32_t *index); +int pa_modargs_get_sink_index(struct pa_modargs *ma, struct pa_core *c, uint32_t *index); + +#endif diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c new file mode 100644 index 00000000..8a3388af --- /dev/null +++ b/polyp/module-alsa-sink.c @@ -0,0 +1,259 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include "module.h" +#include "core.h" +#include "memchunk.h" +#include "sink.h" +#include "modargs.h" +#include "util.h" +#include "sample-util.h" +#include "alsa-util.h" + +struct userdata { + snd_pcm_t *pcm_handle; + struct pa_sink *sink; + void **io_sources; + unsigned n_io_sources; + + size_t frame_size, fragment_size; + struct pa_memchunk memchunk, silence; +}; + +static const char* const valid_modargs[] = { + "device", + "sink_name", + "format", + "channels", + "rate", + "fragments", + "fragment_size", + NULL +}; + +#define DEFAULT_SINK_NAME "alsa_output" +#define DEFAULT_DEVICE "plughw:0,0" + +static void xrun_recovery(struct userdata *u) { + assert(u); + + fprintf(stderr, "*** ALSA-XRUN (playback) ***\n"); + + if (snd_pcm_prepare(u->pcm_handle) < 0) + fprintf(stderr, "snd_pcm_prepare() failed\n"); +} + +static void do_write(struct userdata *u) { + assert(u); + + for (;;) { + struct pa_memchunk *memchunk = NULL; + snd_pcm_sframes_t frames; + + if (u->memchunk.memblock) + memchunk = &u->memchunk; + else { + if (pa_sink_render(u->sink, u->fragment_size, &u->memchunk) < 0) + memchunk = &u->silence; + else + memchunk = &u->memchunk; + } + + assert(memchunk->memblock && memchunk->memblock->data && memchunk->length && memchunk->memblock->length && (memchunk->length % u->frame_size) == 0); + + if ((frames = snd_pcm_writei(u->pcm_handle, memchunk->memblock->data + memchunk->index, memchunk->length / u->frame_size)) < 0) { + if (frames == -EAGAIN) + return; + + if (frames == -EPIPE) { + xrun_recovery(u); + continue; + } + + fprintf(stderr, "snd_pcm_writei() failed\n"); + return; + } + + if (memchunk == &u->memchunk) { + size_t l = frames * u->frame_size; + memchunk->index += l; + memchunk->length -= l; + + if (memchunk->length == 0) { + pa_memblock_unref(memchunk->memblock); + memchunk->memblock = NULL; + memchunk->index = memchunk->length = 0; + } + } + + break; + } +} + +static void io_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { + struct userdata *u = userdata; + assert(u && a && id); + + if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) + xrun_recovery(u); + + do_write(u); +} + +static uint32_t sink_get_latency_cb(struct pa_sink *s) { + struct userdata *u = s->userdata; + snd_pcm_sframes_t frames; + assert(s && u && u->sink); + + if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { + fprintf(stderr, __FILE__": failed to get delay\n"); + s->get_latency = NULL; + return 0; + } + + if (frames < 0) + frames = 0; + + return pa_samples_usec(frames * u->frame_size, &s->sample_spec); +} + +int pa_module_init(struct pa_core *c, struct pa_module*m) { + struct pa_modargs *ma = NULL; + int ret = -1; + struct userdata *u = NULL; + const char *dev; + struct pa_sample_spec ss; + unsigned periods, fragsize; + snd_pcm_uframes_t buffer_size; + size_t frame_size; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + fprintf(stderr, __FILE__": failed to parse module arguments\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + fprintf(stderr, __FILE__": failed to parse sample specification\n"); + goto fail; + } + frame_size = pa_sample_size(&ss); + + periods = 12; + fragsize = 1024; + if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { + fprintf(stderr, __FILE__": failed to parse buffer metrics\n"); + goto fail; + } + buffer_size = fragsize/frame_size*periods; + + u = malloc(sizeof(struct userdata)); + assert(u); + memset(u, 0, sizeof(struct userdata)); + m->userdata = u; + + if (snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) { + fprintf(stderr, __FILE__": Error opening PCM device %s\n", dev); + goto fail; + } + + if (pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &buffer_size) < 0) { + fprintf(stderr, __FILE__": Failed to set hardware parameters\n"); + goto fail; + } + + u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); + assert(u->sink); + + u->sink->get_latency = sink_get_latency_cb; + u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); + + if (pa_create_io_sources(u->pcm_handle, c->mainloop, &u->io_sources, &u->n_io_sources, io_callback, u) < 0) { + fprintf(stderr, __FILE__": failed to obtain file descriptors\n"); + goto fail; + } + + u->frame_size = frame_size; + u->fragment_size = buffer_size*u->frame_size/periods; + + fprintf(stderr, __FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); + + u->silence.memblock = pa_memblock_new(u->silence.length = u->fragment_size); + assert(u->silence.memblock); + pa_silence_memblock(u->silence.memblock, &ss); + u->silence.index = 0; + + u->memchunk.memblock = NULL; + u->memchunk.index = u->memchunk.length = 0; + + ret = 0; + +finish: + if (ma) + pa_modargs_free(ma); + + return ret; + +fail: + + if (u) + pa_module_done(c, m); + + goto finish; +} + +void pa_module_done(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + assert(c && m); + + if ((u = m->userdata)) { + if (u->sink) + pa_sink_free(u->sink); + + if (u->io_sources) + pa_free_io_sources(c->mainloop, u->io_sources, u->n_io_sources); + + if (u->pcm_handle) { + snd_pcm_drop(u->pcm_handle); + snd_pcm_close(u->pcm_handle); + } + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + if (u->silence.memblock) + pa_memblock_unref(u->silence.memblock); + + free(u); + } +} + diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c new file mode 100644 index 00000000..287a0350 --- /dev/null +++ b/polyp/module-alsa-source.c @@ -0,0 +1,237 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include "module.h" +#include "core.h" +#include "memchunk.h" +#include "sink.h" +#include "modargs.h" +#include "util.h" +#include "sample-util.h" +#include "alsa-util.h" + +struct userdata { + snd_pcm_t *pcm_handle; + struct pa_source *source; + void **io_sources; + unsigned n_io_sources; + + size_t frame_size, fragment_size; + struct pa_memchunk memchunk; +}; + +static const char* const valid_modargs[] = { + "device", + "source_name", + "format", + "channels", + "rate", + "fragments", + "fragment_size", + NULL +}; + +#define DEFAULT_SOURCE_NAME "alsa_input" +#define DEFAULT_DEVICE "hw:0,0" + +static void xrun_recovery(struct userdata *u) { + assert(u); + + fprintf(stderr, "*** ALSA-XRUN (capture) ***\n"); + + if (snd_pcm_prepare(u->pcm_handle) < 0) + fprintf(stderr, "snd_pcm_prepare() failed\n"); +} + +static void do_read(struct userdata *u) { + assert(u); + + for (;;) { + struct pa_memchunk post_memchunk; + snd_pcm_sframes_t frames; + size_t l; + + if (!u->memchunk.memblock) { + u->memchunk.memblock = pa_memblock_new(u->memchunk.length = u->fragment_size); + u->memchunk.index = 0; + } + + assert(u->memchunk.memblock && u->memchunk.memblock->data && u->memchunk.length && u->memchunk.memblock->length && (u->memchunk.length % u->frame_size) == 0); + + if ((frames = snd_pcm_readi(u->pcm_handle, u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { + if (frames == -EAGAIN) + return; + + if (frames == -EPIPE) { + xrun_recovery(u); + continue; + } + + fprintf(stderr, "snd_pcm_readi() failed: %s\n", strerror(-frames)); + return; + } + + l = frames * u->frame_size; + + post_memchunk = u->memchunk; + post_memchunk.length = l; + + pa_source_post(u->source, &post_memchunk); + + u->memchunk.index += l; + u->memchunk.length -= l; + + if (u->memchunk.length == 0) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + u->memchunk.index = u->memchunk.length = 0; + } + + break; + } +} + +static void io_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { + struct userdata *u = userdata; + assert(u && a && id); + + if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) + xrun_recovery(u); + + do_read(u); +} + +int pa_module_init(struct pa_core *c, struct pa_module*m) { + struct pa_modargs *ma = NULL; + int ret = -1; + struct userdata *u = NULL; + const char *dev; + struct pa_sample_spec ss; + unsigned periods, fragsize; + snd_pcm_uframes_t buffer_size; + size_t frame_size; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + fprintf(stderr, __FILE__": failed to parse module arguments\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + fprintf(stderr, __FILE__": failed to parse sample specification\n"); + goto fail; + } + frame_size = pa_sample_size(&ss); + + periods = 12; + fragsize = 1024; + if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { + fprintf(stderr, __FILE__": failed to parse buffer metrics\n"); + goto fail; + } + buffer_size = fragsize/frame_size*periods; + + u = malloc(sizeof(struct userdata)); + assert(u); + memset(u, 0, sizeof(struct userdata)); + m->userdata = u; + + if (snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK) < 0) { + fprintf(stderr, __FILE__": Error opening PCM device %s\n", dev); + goto fail; + } + + if (pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &buffer_size) < 0) { + fprintf(stderr, __FILE__": Failed to set hardware parameters\n"); + goto fail; + } + + u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); + assert(u->source); + + u->source->userdata = u; + pa_source_set_owner(u->source, m); + u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); + + if (pa_create_io_sources(u->pcm_handle, c->mainloop, &u->io_sources, &u->n_io_sources, io_callback, u) < 0) { + fprintf(stderr, __FILE__": failed to obtain file descriptors\n"); + goto fail; + } + + u->frame_size = frame_size; + u->fragment_size = buffer_size*u->frame_size/periods; + + fprintf(stderr, __FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); + + u->memchunk.memblock = NULL; + u->memchunk.index = u->memchunk.length = 0; + + snd_pcm_start(u->pcm_handle); + + ret = 0; + +finish: + if (ma) + pa_modargs_free(ma); + + return ret; + +fail: + + if (u) + pa_module_done(c, m); + + goto finish; +} + +void pa_module_done(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + assert(c && m); + + if ((u = m->userdata)) { + if (u->source) + pa_source_free(u->source); + + if (u->io_sources) + pa_free_io_sources(c->mainloop, u->io_sources, u->n_io_sources); + + if (u->pcm_handle) { + snd_pcm_drop(u->pcm_handle); + snd_pcm_close(u->pcm_handle); + } + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + + free(u); + } +} + diff --git a/polyp/module-cli.c b/polyp/module-cli.c new file mode 100644 index 00000000..8897c9c6 --- /dev/null +++ b/polyp/module-cli.c @@ -0,0 +1,73 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#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 pa_module_init(struct pa_core *c, struct pa_module*m) { + struct pa_iochannel *io; + assert(c && m); + + if (m->argument) { + fprintf(stderr, __FILE__": module doesn't accept arguments.\n"); + return -1; + } + + if (pa_stdio_acquire() < 0) { + fprintf(stderr, __FILE__": STDIN/STDUSE already in use.\n"); + return -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, m); + assert(m->userdata); + + pa_cli_set_eof_callback(m->userdata, eof_cb, m); + + return 0; +} + +void pa_module_done(struct pa_core *c, struct pa_module*m) { + assert(c && m); + + pa_cli_free(m->userdata); + pa_stdio_release(); +} diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c new file mode 100644 index 00000000..800eaf25 --- /dev/null +++ b/polyp/module-oss-mmap.c @@ -0,0 +1,404 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iochannel.h" +#include "sink.h" +#include "source.h" +#include "module.h" +#include "oss-util.h" +#include "sample-util.h" +#include "util.h" +#include "modargs.h" + +struct userdata { + struct pa_sink *sink; + struct pa_source *source; + struct pa_core *core; + struct pa_sample_spec sample_spec; + + size_t in_fragment_size, out_fragment_size, in_fragments, out_fragments, out_fill; + + int fd; + + void *in_mmap, *out_mmap; + size_t in_mmap_length, out_mmap_length; + + void *mainloop_source; + + struct pa_memblock **in_memblocks, **out_memblocks; + unsigned out_current, in_current; +}; + +static const char* const valid_modargs[] = { + "sink_name", + "source_name", + "device", + "record", + "playback", + "fragments", + "fragment_size", + "format", + "rate", + "channels", + NULL +}; + +#define DEFAULT_SINK_NAME "oss_output" +#define DEFAULT_SOURCE_NAME "oss_input" +#define DEFAULT_DEVICE "/dev/dsp" + +static void out_fill_memblocks(struct userdata *u, unsigned n) { + assert(u && u->out_memblocks); + + while (n > 0) { + struct pa_memchunk chunk; + + if (u->out_memblocks[u->out_current]) + pa_memblock_unref_fixed(u->out_memblocks[u->out_current]); + + chunk.memblock = u->out_memblocks[u->out_current] = pa_memblock_new_fixed(u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size); + assert(chunk.memblock); + chunk.length = chunk.memblock->length; + chunk.index = 0; + + pa_sink_render_into_full(u->sink, &chunk); + + u->out_current++; + while (u->out_current >= u->out_fragments) + u->out_current -= u->out_fragments; + + n--; + } +} + +static void do_write(struct userdata *u) { + struct count_info info; + assert(u && u->sink); + + if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { + fprintf(stderr, "SNDCTL_DSP_GETOPTR: %s\n", strerror(errno)); + return; + } + + u->out_fill = (u->out_fragment_size * u->out_fragments) - (info.ptr % u->out_fragment_size); + + if (!info.blocks) + return; + + out_fill_memblocks(u, info.blocks); +} + +static void in_post_memblocks(struct userdata *u, unsigned n) { + assert(u && u->in_memblocks); + + while (n > 0) { + struct pa_memchunk chunk; + + if (!u->in_memblocks[u->in_current]) { + chunk.memblock = u->in_memblocks[u->in_current] = pa_memblock_new_fixed(u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size); + chunk.length = chunk.memblock->length; + chunk.index = 0; + + pa_source_post(u->source, &chunk); + } + + u->in_current++; + while (u->in_current >= u->in_fragments) + u->in_current -= u->in_fragments; + + n--; + } +} + +static void in_clear_memblocks(struct userdata*u, unsigned n) { + unsigned i = u->in_current; + assert(u && u->in_memblocks); + + if (n > u->in_fragments) + n = u->in_fragments; + + while (n > 0) { + if (u->in_memblocks[i]) { + pa_memblock_unref_fixed(u->in_memblocks[i]); + u->in_memblocks[i] = NULL; + } + + i++; + while (i >= u->in_fragments) + i -= u->in_fragments; + + n--; + } +} + +static void do_read(struct userdata *u) { + struct count_info info; + assert(u && u->source); + + if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { + fprintf(stderr, "SNDCTL_DSP_GETIPTR: %s\n", strerror(errno)); + return; + } + + if (!info.blocks) + return; + + in_post_memblocks(u, info.blocks); + in_clear_memblocks(u, u->in_fragments/2); +}; + +static void io_callback(struct pa_mainloop_api *m, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { + struct userdata *u = userdata; + + assert (u && u->core->mainloop == m && u->mainloop_source == id); + + if (events & PA_MAINLOOP_API_IO_EVENT_INPUT) + do_read(u); + if (events & PA_MAINLOOP_API_IO_EVENT_OUTPUT) + do_write(u); +} + +static uint32_t sink_get_latency_cb(struct pa_sink *s) { + struct userdata *u = s->userdata; + assert(s && u); + + do_write(u); + return pa_samples_usec(u->out_fill, &s->sample_spec); +} + +int pa_module_init(struct pa_core *c, struct pa_module*m) { + struct audio_buf_info info; + struct userdata *u = NULL; + const char *p; + int nfrags, frag_size; + int mode, caps; + int enable_bits = 0, zero = 0; + int playback = 1, record = 1; + struct pa_modargs *ma = NULL; + assert(c && m); + + m->userdata = u = malloc(sizeof(struct userdata)); + assert(u); + memset(u, 0, sizeof(struct userdata)); + u->fd = -1; + u->core = c; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + fprintf(stderr, __FILE__": failed to parse module arguments.\n"); + goto fail; + } + + if (pa_modargs_get_value_u32(ma, "record", &record) < 0 || pa_modargs_get_value_u32(ma, "playback", &playback) < 0) { + fprintf(stderr, __FILE__": record= and playback= expect numeric arguments.\n"); + goto fail; + } + + mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); + if (mode == 0) { + fprintf(stderr, __FILE__": neither playback nor record enabled for device.\n"); + goto fail; + } + + nfrags = 12; + frag_size = 1024; + if (pa_modargs_get_value_u32(ma, "fragments", &nfrags) < 0 || nfrags < 2 || pa_modargs_get_value_u32(ma, "fragment_size", &frag_size) < 0 || frag_size < 1) { + fprintf(stderr, __FILE__": failed to parse fragments arguments\n"); + goto fail; + } + + u->sample_spec = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &u->sample_spec) < 0) { + fprintf(stderr, __FILE__": failed to parse sample specification\n"); + goto fail; + } + + if ((u->fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0) + goto fail; + + if (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_REALTIME) || !(caps & DSP_CAP_TRIGGER)) { + fprintf(stderr, "OSS device not mmap capable.\n"); + goto fail; + } + + fprintf(stderr, "module-oss: device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + + if (pa_oss_set_fragments(u->fd, nfrags, frag_size) < 0) + goto fail; + + if (pa_oss_auto_format(u->fd, &u->sample_spec) < 0) + goto fail; + + if (mode != O_WRONLY) { + if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { + fprintf(stderr, "SNDCTL_DSP_GETISPACE: %s\n", strerror(errno)); + goto fail; + } + + fprintf(stderr, "module-oss-mmap: input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + u->in_mmap_length = (u->in_fragment_size = info.fragsize) * (u->in_fragments = info.fragstotal); + + if ((u->in_mmap = mmap(NULL, u->in_mmap_length, PROT_READ, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { + if (mode == O_RDWR) { + fprintf(stderr, "module-oss-mmap: mmap failed for input. Changing to O_WRONLY mode.\n"); + mode = O_WRONLY; + } else { + fprintf(stderr, "modeule-oss-mmap: mmap(): %s\n", strerror(errno)); + goto fail; + } + } else { + + u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec); + assert(u->source); + u->source->userdata = u; + pa_source_set_owner(u->source, m); + u->source->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'", p); + + + u->in_memblocks = malloc(sizeof(struct pa_memblock *)*u->in_fragments); + memset(u->in_memblocks, 0, sizeof(struct pa_memblock *)*u->in_fragments); + + enable_bits |= PCM_ENABLE_INPUT; + } + } + + if (mode != O_RDONLY) { + if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { + fprintf(stderr, "SNDCTL_DSP_GETOSPACE: %s\n", strerror(errno)); + goto fail; + } + + fprintf(stderr, "module-oss: output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + u->out_mmap_length = (u->out_fragment_size = info.fragsize) * (u->out_fragments = info.fragstotal); + + if ((u->out_mmap = mmap(NULL, u->out_mmap_length, PROT_WRITE, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { + if (mode == O_RDWR) { + fprintf(stderr, "module-oss-mmap: mmap filed for output. Changing to O_RDONLY mode.\n"); + mode = O_RDONLY; + } else { + fprintf(stderr, "module-oss-mmap: mmap(): %s\n", strerror(errno)); + goto fail; + } + } else { + pa_silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec); + + u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec); + assert(u->sink); + u->sink->get_latency = sink_get_latency_cb; + u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'", p); + + u->out_memblocks = malloc(sizeof(struct memblock *)*u->out_fragments); + memset(u->out_memblocks, 0, sizeof(struct pa_memblock *)*u->out_fragments); + + enable_bits |= PCM_ENABLE_OUTPUT; + } + } + + zero = 0; + if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero) < 0) { + fprintf(stderr, "SNDCTL_DSP_SETTRIGGER: %s\n", strerror(errno)); + goto fail; + } + + if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0) { + fprintf(stderr, "SNDCTL_DSP_SETTRIGGER: %s\n", strerror(errno)); + goto fail; + } + + assert(u->source || u->sink); + + u->mainloop_source = c->mainloop->source_io(c->mainloop, u->fd, (u->source ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | (u->sink ? PA_MAINLOOP_API_IO_EVENT_OUTPUT : 0), io_callback, u); + assert(u->mainloop_source); + + pa_modargs_free(ma); + + return 0; + +fail: + pa_module_done(c, m); + + if (ma) + pa_modargs_free(ma); + + return -1; +} + +void pa_module_done(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + assert(c && m); + + u = m->userdata; + assert(u); + + if (u->out_memblocks) { + unsigned i; + for (i = 0; i < u->out_fragments; i++) + if (u->out_memblocks[i]) + pa_memblock_unref_fixed(u->out_memblocks[i]); + free(u->out_memblocks); + } + + if (u->in_memblocks) { + unsigned i; + for (i = 0; i < u->in_fragments; i++) + if (u->in_memblocks[i]) + pa_memblock_unref_fixed(u->in_memblocks[i]); + free(u->in_memblocks); + } + + if (u->in_mmap && u->in_mmap != MAP_FAILED) + munmap(u->in_mmap, u->in_mmap_length); + + if (u->out_mmap && u->out_mmap != MAP_FAILED) + munmap(u->out_mmap, u->out_mmap_length); + + if (u->sink) + pa_sink_free(u->sink); + + if (u->source) + pa_source_free(u->source); + + if (u->mainloop_source) + u->core->mainloop->cancel_io(u->core->mainloop, u->mainloop_source); + + if (u->fd >= 0) + close(u->fd); + + free(u); +} diff --git a/polyp/module-oss.c b/polyp/module-oss.c new file mode 100644 index 00000000..d727534a --- /dev/null +++ b/polyp/module-oss.c @@ -0,0 +1,304 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iochannel.h" +#include "sink.h" +#include "source.h" +#include "module.h" +#include "oss-util.h" +#include "sample-util.h" +#include "util.h" +#include "modargs.h" + +struct userdata { + struct pa_sink *sink; + struct pa_source *source; + struct pa_iochannel *io; + struct pa_core *core; + + struct pa_memchunk memchunk, silence; + + uint32_t in_fragment_size, out_fragment_size, sample_size; + + int fd; +}; + +static const char* const valid_modargs[] = { + "sink_name", + "source_name", + "device", + "record", + "playback", + "fragments", + "fragment_size", + "format", + "rate", + "channels", + NULL +}; + +#define DEFAULT_SINK_NAME "oss_output" +#define DEFAULT_SOURCE_NAME "oss_input" +#define DEFAULT_DEVICE "/dev/dsp" + +static void do_write(struct userdata *u) { + struct pa_memchunk *memchunk; + ssize_t r; + assert(u); + + if (!u->sink || !pa_iochannel_is_writable(u->io)) + return; + + if (!u->memchunk.length) { + if (pa_sink_render(u->sink, u->out_fragment_size, &u->memchunk) < 0) + memchunk = &u->silence; + else + memchunk = &u->memchunk; + } + + assert(memchunk->memblock && memchunk->length); + + if ((r = pa_iochannel_write(u->io, memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { + fprintf(stderr, "write() failed: %s\n", strerror(errno)); + return; + } + + if (memchunk == &u->silence) + assert(r % u->sample_size == 0); + else { + u->memchunk.index += r; + u->memchunk.length -= r; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + } + } +} + +static void do_read(struct userdata *u) { + struct pa_memchunk memchunk; + ssize_t r; + assert(u); + + if (!u->source || !pa_iochannel_is_readable(u->io)) + return; + + memchunk.memblock = pa_memblock_new(u->in_fragment_size); + assert(memchunk.memblock); + if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { + pa_memblock_unref(memchunk.memblock); + if (errno != EAGAIN) + fprintf(stderr, "read() failed: %s\n", strerror(errno)); + return; + } + + assert(r <= (ssize_t) memchunk.memblock->length); + memchunk.length = memchunk.memblock->length = r; + memchunk.index = 0; + + pa_source_post(u->source, &memchunk); + pa_memblock_unref(memchunk.memblock); +}; + +static void io_callback(struct pa_iochannel *io, void*userdata) { + struct userdata *u = userdata; + assert(u); + do_write(u); + do_read(u); +} + +static uint32_t sink_get_latency_cb(struct pa_sink *s) { + int arg; + struct userdata *u = s->userdata; + assert(s && u && u->sink); + + if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { + fprintf(stderr, "module-oss: device doesn't support SNDCTL_DSP_GETODELAY.\n"); + s->get_latency = NULL; + return 0; + } + + return pa_samples_usec(arg, &s->sample_spec); +} + +int pa_module_init(struct pa_core *c, struct pa_module*m) { + struct audio_buf_info info; + struct userdata *u = NULL; + const char *p; + int fd = -1; + int nfrags, frag_size, in_frag_size, out_frag_size; + int mode; + uint32_t record = 1, playback = 1; + struct pa_sample_spec ss; + struct pa_modargs *ma = NULL; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + fprintf(stderr, __FILE__": failed to parse module arguments.\n"); + goto fail; + } + + if (pa_modargs_get_value_u32(ma, "record", &record) < 0 || pa_modargs_get_value_u32(ma, "playback", &playback) < 0) { + fprintf(stderr, __FILE__": record= and playback= expect numeric argument.\n"); + goto fail; + } + + mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); + if (mode == 0) { + fprintf(stderr, __FILE__": neither playback nor record enabled for device.\n"); + goto fail; + } + + nfrags = 12; + frag_size = 1024; + if (pa_modargs_get_value_u32(ma, "fragments", &nfrags) < 0 || nfrags < 2 || pa_modargs_get_value_u32(ma, "fragment_size", &frag_size) < 0 || frag_size < 1) { + fprintf(stderr, __FILE__": failed to parse fragments arguments\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + fprintf(stderr, __FILE__": failed to parse sample specification\n"); + goto fail; + } + + if ((fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, NULL)) < 0) + goto fail; + + fprintf(stderr, "module-oss: device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + + if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) + goto fail; + + if (pa_oss_auto_format(fd, &ss) < 0) + goto fail; + + if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) { + fprintf(stderr, "SNDCTL_DSP_GETBLKSIZE: %s\n", strerror(errno)); + goto fail; + } + assert(frag_size); + in_frag_size = out_frag_size = frag_size; + + if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { + fprintf(stderr, "module-oss: input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + in_frag_size = info.fragsize; + } + + if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) { + fprintf(stderr, "module-oss: output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + out_frag_size = info.fragsize; + } + + u = malloc(sizeof(struct userdata)); + assert(u); + + u->core = c; + + if (mode != O_WRONLY) { + u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); + assert(u->source); + u->source->userdata = u; + pa_source_set_owner(u->source, m); + u->source->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); + } else + u->source = NULL; + + if (mode != O_RDONLY) { + u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); + assert(u->sink); + u->sink->get_latency = sink_get_latency_cb; + u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); + } else + u->sink = NULL; + + assert(u->source || u->sink); + + u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : 0); + assert(u->io); + pa_iochannel_set_callback(u->io, io_callback, u); + u->fd = fd; + + u->memchunk.memblock = NULL; + u->memchunk.length = 0; + u->sample_size = pa_sample_size(&ss); + + u->out_fragment_size = out_frag_size; + u->in_fragment_size = in_frag_size; + u->silence.memblock = pa_memblock_new(u->silence.length = u->out_fragment_size); + assert(u->silence.memblock); + pa_silence_memblock(u->silence.memblock, &ss); + u->silence.index = 0; + + m->userdata = u; + + pa_modargs_free(ma); + + return 0; + +fail: + if (fd >= 0) + close(fd); + + if (ma) + pa_modargs_free(ma); + + return -1; +} + +void pa_module_done(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + assert(c && m); + + u = m->userdata; + assert(u); + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + if (u->silence.memblock) + pa_memblock_unref(u->silence.memblock); + + if (u->sink) + pa_sink_free(u->sink); + if (u->source) + pa_source_free(u->source); + pa_iochannel_free(u->io); + free(u); +} diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c new file mode 100644 index 00000000..df34f73a --- /dev/null +++ b/polyp/module-pipe-sink.c @@ -0,0 +1,218 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iochannel.h" +#include "sink.h" +#include "module.h" +#include "util.h" +#include "modargs.h" + +#define DEFAULT_FIFO_NAME "/tmp/musicfifo" +#define DEFAULT_SINK_NAME "fifo_output" + +struct userdata { + struct pa_core *core; + + char *filename; + + struct pa_sink *sink; + struct pa_iochannel *io; + void *mainloop_source; + + struct pa_memchunk memchunk; +}; + +static const char* const valid_modargs[] = { + "file", + "rate", + "channels", + "format", + "sink_name", + NULL +}; + +static void do_write(struct userdata *u) { + ssize_t r; + assert(u); + + u->core->mainloop->enable_fixed(u->core->mainloop, u->mainloop_source, 0); + + if (!pa_iochannel_is_writable(u->io)) + return; + + if (!u->memchunk.length) + if (pa_sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0) + return; + + assert(u->memchunk.memblock && u->memchunk.length); + + if ((r = pa_iochannel_write(u->io, u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { + fprintf(stderr, "write() failed: %s\n", strerror(errno)); + return; + } + + u->memchunk.index += r; + u->memchunk.length -= r; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + } +} + +static void notify_cb(struct pa_sink*s) { + struct userdata *u = s->userdata; + assert(s && u); + + if (pa_iochannel_is_writable(u->io)) + u->core->mainloop->enable_fixed(u->core->mainloop, u->mainloop_source, 1); +} + +static void fixed_callback(struct pa_mainloop_api *m, void *id, void *userdata) { + struct userdata *u = userdata; + assert(u); + do_write(u); +} + +static void io_callback(struct pa_iochannel *io, void*userdata) { + struct userdata *u = userdata; + assert(u); + do_write(u); +} + +int pa_module_init(struct pa_core *c, struct pa_module*m) { + struct userdata *u = NULL; + struct stat st; + const char *p; + int fd = -1; + struct pa_sample_spec ss; + struct pa_modargs *ma = NULL; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + fprintf(stderr, __FILE__": failed to parse module arguments\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + fprintf(stderr, __FILE__": invalid sample format specification\n"); + goto fail; + } + + mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777); + + if ((fd = open(p, O_RDWR)) < 0) { + fprintf(stderr, __FILE__": open('%s'): %s\n", p, strerror(errno)); + goto fail; + } + + if (fstat(fd, &st) < 0) { + fprintf(stderr, __FILE__": fstat('%s'): %s\n", p, strerror(errno)); + goto fail; + } + + if (!S_ISFIFO(st.st_mode)) { + fprintf(stderr, __FILE__": '%s' is not a FIFO.\n", p); + goto fail; + } + + u = malloc(sizeof(struct userdata)); + assert(u); + memset(u, 0, sizeof(struct userdata)); + + u->filename = strdup(p); + assert(u->filename); + u->core = c; + + if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { + fprintf(stderr, __FILE__": failed to create sink.\n"); + goto fail; + } + u->sink->notify = notify_cb; + u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Unix FIFO sink '%s'", p); + assert(u->sink->description); + + u->io = pa_iochannel_new(c->mainloop, -1, fd); + assert(u->io); + pa_iochannel_set_callback(u->io, io_callback, u); + + u->memchunk.memblock = NULL; + u->memchunk.length = 0; + + u->mainloop_source = c->mainloop->source_fixed(c->mainloop, fixed_callback, u); + assert(u->mainloop_source); + c->mainloop->enable_fixed(c->mainloop, u->mainloop_source, 0); + + m->userdata = u; + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + if (fd >= 0) + close(fd); + + pa_module_done(c, m); + + return -1; +} + +void pa_module_done(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + + pa_sink_free(u->sink); + pa_iochannel_free(u->io); + u->core->mainloop->cancel_fixed(u->core->mainloop, u->mainloop_source); + + assert(u->filename); + unlink(u->filename); + free(u->filename); + + free(u); +} diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c new file mode 100644 index 00000000..3ce18c31 --- /dev/null +++ b/polyp/module-protocol-stub.c @@ -0,0 +1,165 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "module.h" +#include "socket-server.h" +#include "socket-util.h" +#include "util.h" +#include "modargs.h" + +#ifdef USE_PROTOCOL_SIMPLE + #include "protocol-simple.h" + #define protocol_new pa_protocol_simple_new + #define protocol_free pa_protocol_simple_free + #define IPV4_PORT 4711 + #define UNIX_SOCKET "/tmp/polypaudio/simple" + #define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record", +#else + #ifdef USE_PROTOCOL_CLI + #include "protocol-cli.h" + #define protocol_new pa_protocol_cli_new + #define protocol_free pa_protocol_cli_free + #define IPV4_PORT 4712 + #define UNIX_SOCKET "/tmp/polypaudio/cli" + #define MODULE_ARGUMENTS + #else + #ifdef USE_PROTOCOL_NATIVE + #include "protocol-native.h" + #define protocol_new pa_protocol_native_new + #define protocol_free pa_protocol_native_free + #define IPV4_PORT 4713 + #define UNIX_SOCKET "/tmp/polypaudio/native" + #define MODULE_ARGUMENTS "public", "cookie", + #else + #ifdef USE_PROTOCOL_ESOUND + #include "protocol-esound.h" + #include "esound.h" + #define protocol_new pa_protocol_esound_new + #define protocol_free pa_protocol_esound_free + #define IPV4_PORT ESD_DEFAULT_PORT + #define UNIX_SOCKET ESD_UNIX_SOCKET_NAME + #define MODULE_ARGUMENTS "sink", "source", "public", "cookie", + #else + #error "Broken build system" + #endif + #endif + #endif +#endif + +static const char* const valid_modargs[] = { + MODULE_ARGUMENTS +#ifdef USE_TCP_SOCKETS + "port", + "loopback", +#else + "socket", +#endif + NULL +}; + +static struct pa_socket_server *create_socket_server(struct pa_core *c, struct pa_modargs *ma) { + struct pa_socket_server *s; +#ifdef USE_TCP_SOCKETS + uint32_t loopback = 1, port = IPV4_PORT; + + if (pa_modargs_get_value_u32(ma, "loopback", &loopback) < 0) { + fprintf(stderr, "loopback= expects a numerical argument.\n"); + return NULL; + } + + if (pa_modargs_get_value_u32(ma, "port", &port) < 0) { + fprintf(stderr, "port= expects a numerical argument.\n"); + return NULL; + } + + if (!(s = pa_socket_server_new_ipv4(c->mainloop, loopback ? INADDR_LOOPBACK : INADDR_ANY, port))) + return NULL; +#else + int r; + const char *p; + + p = pa_modargs_get_value(ma, "socket", UNIX_SOCKET); + assert(p); + + if (pa_unix_socket_make_secure_dir(p) < 0) { + fprintf(stderr, "Failed to create secure socket directory.\n"); + return NULL; + } + + if ((r = pa_unix_socket_remove_stale(p)) < 0) { + fprintf(stderr, "Failed to remove stale UNIX socket '%s': %s\n", p, strerror(errno)); + return NULL; + } + + if (r) + fprintf(stderr, "Removed stale UNIX socket '%s'.", p); + + if (!(s = pa_socket_server_new_unix(c->mainloop, p))) + return NULL; + +#endif + return s; +} + +int pa_module_init(struct pa_core *c, struct pa_module*m) { + struct pa_socket_server *s; + struct pa_modargs *ma = NULL; + int ret = -1; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + fprintf(stderr, "Failed to parse module arguments\n"); + goto finish; + } + + if (!(s = create_socket_server(c, ma))) + goto finish; + + if (!(m->userdata = protocol_new(c, s, m, ma))) { + pa_socket_server_free(s); + goto finish; + } + + ret = 0; + +finish: + if (ma) + pa_modargs_free(ma); + + return ret; +} + +void pa_module_done(struct pa_core *c, struct pa_module*m) { + assert(c && m); + + protocol_free(m->userdata); +} diff --git a/polyp/module.c b/polyp/module.c new file mode 100644 index 00000000..5c6f0fb6 --- /dev/null +++ b/polyp/module.c @@ -0,0 +1,161 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "module.h" + +struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char *argument) { + struct pa_module *m = NULL; + int r; + + assert(c && name); + + m = malloc(sizeof(struct pa_module)); + assert(m); + + m->name = strdup(name); + m->argument = argument ? strdup(argument) : NULL; + + if (!(m->dl = lt_dlopenext(name))) + goto fail; + + if (!(m->init = lt_dlsym(m->dl, "pa_module_init"))) + goto fail; + + if (!(m->done = lt_dlsym(m->dl, "pa_module_done"))) + goto fail; + + m->userdata = NULL; + m->core = c; + + assert(m->init); + if (m->init(c, m) < 0) + goto fail; + + if (!c->modules) + c->modules = pa_idxset_new(NULL, NULL); + + assert(c->modules); + r = pa_idxset_put(c->modules, m, &m->index); + assert(r >= 0 && m->index != PA_IDXSET_INVALID); + + fprintf(stderr, "module: loaded %u \"%s\" with argument \"%s\".\n", m->index, m->name, m->argument); + + return m; + +fail: + if (m) { + free(m->argument); + free(m->name); + + if (m->dl) + lt_dlclose(m->dl); + + free(m); + } + + return NULL; +} + +static void pa_module_free(struct pa_module *m) { + assert(m && m->done && m->core); + m->done(m->core, m); + + lt_dlclose(m->dl); + + fprintf(stderr, "module: unloaded %u \"%s\".\n", m->index, m->name); + + free(m->name); + free(m->argument); + free(m); +} + + +void pa_module_unload(struct pa_core *c, struct pa_module *m) { + assert(c && m); + + assert(c->modules); + if (!(m = pa_idxset_remove_by_data(c->modules, m, NULL))) + return; + + pa_module_free(m); +} + +void pa_module_unload_by_index(struct pa_core *c, uint32_t index) { + struct pa_module *m; + assert(c && index != PA_IDXSET_INVALID); + + assert(c->modules); + if (!(m = pa_idxset_remove_by_index(c->modules, index))) + return; + + pa_module_free(m); +} + +static void free_callback(void *p, void *userdata) { + struct pa_module *m = p; + assert(m); + pa_module_free(m); +} + +void pa_module_unload_all(struct pa_core *c) { + assert(c); + + if (!c->modules) + return; + + pa_idxset_free(c->modules, free_callback, NULL); + c->modules = NULL; +} + +struct once_info { + struct pa_core *core; + uint32_t index; +}; + + +static void module_unload_once_callback(void *userdata) { + struct once_info *i = userdata; + assert(i); + pa_module_unload_by_index(i->core, i->index); + free(i); +} + +void pa_module_unload_request(struct pa_core *c, struct pa_module *m) { + struct once_info *i; + assert(c && m); + + i = malloc(sizeof(struct once_info)); + assert(i); + i->core = c; + i->index = m->index; + pa_mainloop_api_once(c->mainloop, module_unload_once_callback, i); +} diff --git a/polyp/module.h b/polyp/module.h new file mode 100644 index 00000000..af2d8552 --- /dev/null +++ b/polyp/module.h @@ -0,0 +1,55 @@ +#ifndef foomodulehfoo +#define foomodulehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include "core.h" + +struct pa_module { + struct pa_core *core; + char *name, *argument; + uint32_t index; + + lt_dlhandle dl; + + int (*init)(struct pa_core *c, struct pa_module*m); + void (*done)(struct pa_core *c, struct pa_module*m); + + void *userdata; +}; + +struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char*argument); +void pa_module_unload(struct pa_core *c, struct pa_module *m); +void pa_module_unload_by_index(struct pa_core *c, uint32_t index); + +void pa_module_unload_all(struct pa_core *c); + +void pa_module_unload_request(struct pa_core *c, struct pa_module *m); + +/* These to following prototypes are for module entrypoints and not implemented by the core */ +int pa_module_init(struct pa_core *c, struct pa_module*m); +void pa_module_done(struct pa_core *c, struct pa_module*m); + +#endif diff --git a/polyp/namereg.c b/polyp/namereg.c new file mode 100644 index 00000000..2349436f --- /dev/null +++ b/polyp/namereg.c @@ -0,0 +1,136 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "namereg.h" + +struct namereg_entry { + enum pa_namereg_type type; + char *name; + void *data; +}; + +void pa_namereg_free(struct pa_core *c) { + assert(c); + if (!c->namereg) + return; + assert(pa_hashmap_ncontents(c->namereg) == 0); + pa_hashmap_free(c->namereg, NULL, NULL); +} + +const char *pa_namereg_register(struct pa_core *c, const char *name, enum pa_namereg_type type, void *data, int fail) { + struct namereg_entry *e; + char *n = NULL; + int r; + + assert(c && name && data); + + if (!c->namereg) { + c->namereg = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + assert(c->namereg); + } + + if ((e = pa_hashmap_get(c->namereg, name)) && fail) + return NULL; + + if (!e) + n = strdup(name); + else { + unsigned i; + size_t l = strlen(name); + n = malloc(l+3); + assert(n); + + for (i = 1; i <= 99; i++) { + snprintf(n, l+2, "%s%u", name, i); + + if (!(e = pa_hashmap_get(c->namereg, n))) + break; + } + + if (e) { + free(n); + return NULL; + } + } + + assert(n); + e = malloc(sizeof(struct namereg_entry)); + assert(e); + e->type = type; + e->name = n; + e->data = data; + + r = pa_hashmap_put(c->namereg, e->name, e); + assert (r >= 0); + + return e->name; + +} + +void pa_namereg_unregister(struct pa_core *c, const char *name) { + struct namereg_entry *e; + int r; + assert(c && name); + + e = pa_hashmap_get(c->namereg, name); + assert(e); + + r = pa_hashmap_remove(c->namereg, name); + assert(r >= 0); + + free(e->name); + free(e); +} + +void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type type) { + struct namereg_entry *e; + uint32_t index; + char *x = NULL; + void *d = NULL; + assert(c && name); + + if ((e = pa_hashmap_get(c->namereg, name))) + if (e->type == e->type) + return e->data; + + index = (uint32_t) strtol(name, &x, 0); + + if (!x || *x != 0) + return NULL; + + if (type == PA_NAMEREG_SINK) + d = pa_idxset_get_by_index(c->sinks, index); + else if (type == PA_NAMEREG_SOURCE) + d = pa_idxset_get_by_index(c->sources, index); + + return d; +} diff --git a/polyp/namereg.h b/polyp/namereg.h new file mode 100644 index 00000000..0af83cd8 --- /dev/null +++ b/polyp/namereg.h @@ -0,0 +1,38 @@ +#ifndef foonamereghfoo +#define foonamereghfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" + +enum pa_namereg_type { + PA_NAMEREG_SINK, + PA_NAMEREG_SOURCE +}; + +void pa_namereg_free(struct pa_core *c); + +const char *pa_namereg_register(struct pa_core *c, const char *name, enum pa_namereg_type type, void *data, int fail); +void pa_namereg_unregister(struct pa_core *c, const char *name); +void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type type); + +#endif diff --git a/polyp/native-common.h b/polyp/native-common.h new file mode 100644 index 00000000..2acbae8e --- /dev/null +++ b/polyp/native-common.h @@ -0,0 +1,68 @@ +#ifndef foonativecommonhfoo +#define foonativecommonhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +enum { + PA_COMMAND_ERROR, + PA_COMMAND_TIMEOUT, /* pseudo command */ + PA_COMMAND_REPLY, + PA_COMMAND_CREATE_PLAYBACK_STREAM, + PA_COMMAND_DELETE_PLAYBACK_STREAM, + PA_COMMAND_CREATE_RECORD_STREAM, + PA_COMMAND_DELETE_RECORD_STREAM, + PA_COMMAND_EXIT, + PA_COMMAND_REQUEST, + PA_COMMAND_AUTH, + PA_COMMAND_SET_NAME, + PA_COMMAND_LOOKUP_SINK, + PA_COMMAND_LOOKUP_SOURCE, + PA_COMMAND_DRAIN_PLAYBACK_STREAM, + PA_COMMAND_PLAYBACK_STREAM_KILLED, + PA_COMMAND_RECORD_STREAM_KILLED, + PA_COMMAND_STAT, + PA_COMMAND_GET_PLAYBACK_LATENCY, + PA_COMMAND_MAX +}; + +enum { + PA_ERROR_OK, + PA_ERROR_ACCESS, + PA_ERROR_COMMAND, + PA_ERROR_INVALID, + PA_ERROR_EXIST, + PA_ERROR_NOENTITY, + PA_ERROR_CONNECTIONREFUSED, + PA_ERROR_PROTOCOL, + PA_ERROR_TIMEOUT, + PA_ERROR_AUTHKEY, + PA_ERROR_INTERNAL, + PA_ERROR_CONNECTIONTERMINATED, + PA_ERROR_KILLED, + PA_ERROR_INVALIDSERVER, + PA_ERROR_MAX +}; + +#define PA_NATIVE_COOKIE_LENGTH 256 +#define PA_NATIVE_COOKIE_FILE ".polypaudio-cookie" + +#endif diff --git a/polyp/oss-util.c b/polyp/oss-util.c new file mode 100644 index 00000000..cf55a6ee --- /dev/null +++ b/polyp/oss-util.c @@ -0,0 +1,163 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "oss-util.h" + +int pa_oss_open(const char *device, int *mode, int* pcaps) { + int fd = -1; + assert(device && mode && (*mode == O_RDWR || *mode == O_RDONLY || *mode == O_WRONLY)); + + if (*mode == O_RDWR) { + if ((fd = open(device, O_RDWR|O_NDELAY)) >= 0) { + int dcaps, *tcaps; + ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0); + + tcaps = pcaps ? pcaps : &dcaps; + + if (ioctl(fd, SNDCTL_DSP_GETCAPS, tcaps) < 0) { + fprintf(stderr, __FILE__": SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); + goto fail; + } + + if (*tcaps & DSP_CAP_DUPLEX) + return fd; + + close(fd); + } + + if ((fd = open(device, (*mode = O_WRONLY)|O_NDELAY)) < 0) { + if ((fd = open(device, (*mode = O_RDONLY)|O_NDELAY)) < 0) { + fprintf(stderr, __FILE__": open('%s'): %s\n", device, strerror(errno)); + goto fail; + } + } + } else { + if ((fd = open(device, *mode|O_NDELAY)) < 0) { + fprintf(stderr, __FILE__": open('%s'): %s\n", device, strerror(errno)); + goto fail; + } + } + + if (pcaps) { + if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { + fprintf(stderr, "SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); + goto fail; + } + } + + return fd; + +fail: + if (fd >= 0) + close(fd); + return fd; +} + +int pa_oss_auto_format(int fd, struct pa_sample_spec *ss) { + int format, channels, speed, reqformat; + static const int format_trans[] = { + [PA_SAMPLE_U8] = AFMT_U8, + [PA_SAMPLE_ALAW] = AFMT_A_LAW, + [PA_SAMPLE_ULAW] = AFMT_MU_LAW, + [PA_SAMPLE_S16LE] = AFMT_S16_LE, + [PA_SAMPLE_S16BE] = AFMT_S16_BE, + [PA_SAMPLE_FLOAT32LE] = AFMT_QUERY, /* not supported */ + [PA_SAMPLE_FLOAT32BE] = AFMT_QUERY, /* not supported */ + }; + + assert(fd >= 0 && ss); + + reqformat = format = format_trans[ss->format]; + if (reqformat == AFMT_QUERY || ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != reqformat) { + format = AFMT_S16_NE; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_S16_NE) { + int f = AFMT_S16_NE == AFMT_S16_LE ? AFMT_S16_BE : AFMT_S16_LE; + format = f; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != f) { + format = AFMT_U8; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_U8) { + fprintf(stderr, "SNDCTL_DSP_SETFMT: %s\n", format != AFMT_U8 ? "No supported sample format" : strerror(errno)); + return -1; + } else + ss->format = PA_SAMPLE_U8; + } else + ss->format = f == AFMT_S16_LE ? PA_SAMPLE_S16LE : PA_SAMPLE_S16BE; + } else + ss->format = PA_SAMPLE_S16NE; + } + + channels = ss->channels; + if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) { + fprintf(stderr, "SNDCTL_DSP_CHANNELS: %s\n", strerror(errno)); + return -1; + } + assert(channels); + ss->channels = channels; + + speed = ss->rate; + if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) { + fprintf(stderr, "SNDCTL_DSP_SPEED: %s\n", strerror(errno)); + return -1; + } + assert(speed); + ss->rate = speed; + + return 0; +} + +static int log2(int v) { + int k = 0; + + for (;;) { + v >>= 1; + if (!v) break; + k++; + } + + return k; +} + +int pa_oss_set_fragments(int fd, int nfrags, int frag_size) { + int arg; + arg = ((int) nfrags << 16) | log2(frag_size); + + if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &arg) < 0) { + fprintf(stderr, "SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno)); + return -1; + } + + return 0; +} diff --git a/polyp/oss-util.h b/polyp/oss-util.h new file mode 100644 index 00000000..cb2ce33c --- /dev/null +++ b/polyp/oss-util.h @@ -0,0 +1,32 @@ +#ifndef fooossutilhfoo +#define fooossutilhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "sample.h" + +int pa_oss_open(const char *device, int *mode, int* pcaps); +int pa_oss_auto_format(int fd, struct pa_sample_spec *ss); + +int pa_oss_set_fragments(int fd, int frags, int frag_size); + +#endif diff --git a/polyp/pacat-simple.c b/polyp/pacat-simple.c new file mode 100644 index 00000000..5018aa5f --- /dev/null +++ b/polyp/pacat-simple.c @@ -0,0 +1,83 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "polyplib-simple.h" +#include "polyplib-error.h" + +#define BUFSIZE 1024 + +int main(int argc, char*argv[]) { + static const struct pa_sample_spec ss = { + .format = PA_SAMPLE_S16LE, + .rate = 44100, + .channels = 2 + }; + struct pa_simple *s = NULL; + int ret = 1; + int error; + + if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, &error))) { + fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); + goto finish; + } + + for (;;) { + uint8_t buf[BUFSIZE]; + ssize_t r; + + if ((r = read(STDIN_FILENO, buf, sizeof(buf))) <= 0) { + if (r == 0) /* eof */ + break; + + fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno)); + goto finish; + } + + if (pa_simple_write(s, buf, r, &error) < 0) { + fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error)); + goto finish; + } + } + + /* Make sure that every single sample way played */ + if (pa_simple_drain(s, &error) < 0) { + fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(error)); + goto finish; + } + + ret = 0; + +finish: + + if (s) + pa_simple_free(s); + + return ret; +} diff --git a/polyp/pacat.c b/polyp/pacat.c new file mode 100644 index 00000000..1d1cc3d5 --- /dev/null +++ b/polyp/pacat.c @@ -0,0 +1,336 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "polyplib.h" +#include "polyplib-error.h" +#include "mainloop.h" +#include "mainloop-signal.h" + +static enum { RECORD, PLAYBACK } mode = PLAYBACK; + +static struct pa_context *context = NULL; +static struct pa_stream *stream = NULL; +static struct pa_mainloop_api *mainloop_api = NULL; + +static void *buffer = NULL; +static size_t buffer_length = 0, buffer_index = 0; + +static void* stdio_source = NULL; + +static void quit(int ret) { + assert(mainloop_api); + mainloop_api->quit(mainloop_api, ret); +} + +static void context_die_callback(struct pa_context *c, void *userdata) { + assert(c); + fprintf(stderr, "Connection to server shut down, exiting.\n"); + quit(1); +} + +static void stream_die_callback(struct pa_stream *s, void *userdata) { + assert(s); + fprintf(stderr, "Stream deleted, exiting.\n"); + quit(1); +} + +static void do_stream_write(size_t length) { + size_t l; + assert(length); + + if (!buffer || !buffer_length) + return; + + l = length; + if (l > buffer_length) + l = buffer_length; + + pa_stream_write(stream, buffer+buffer_index, l); + buffer_length -= l; + buffer_index += l; + + if (!buffer_length) { + free(buffer); + buffer = NULL; + buffer_index = buffer_length = 0; + } +} + +static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) { + assert(s && length); + + if (stdio_source) + mainloop_api->enable_io(mainloop_api, stdio_source, PA_MAINLOOP_API_IO_EVENT_INPUT); + + if (!buffer) + return; + + do_stream_write(length); +} + +static void stream_read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata) { + assert(s && data && length); + + if (stdio_source) + mainloop_api->enable_io(mainloop_api, stdio_source, PA_MAINLOOP_API_IO_EVENT_OUTPUT); + + if (buffer) { + fprintf(stderr, "Buffer overrrun, dropping incoming data\n"); + return; + } + + buffer = malloc(buffer_length = length); + assert(buffer); + memcpy(buffer, data, length); + buffer_index = 0; +} + +static void stream_complete_callback(struct pa_stream*s, int success, void *userdata) { + assert(s); + + if (!success) { + fprintf(stderr, "Stream creation failed: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + quit(1); + return; + } + + fprintf(stderr, "Stream created.\n"); +} + +static void context_complete_callback(struct pa_context *c, int success, void *userdata) { + static const struct pa_sample_spec ss = { + .format = PA_SAMPLE_S16LE, + .rate = 44100, + .channels = 2 + }; + + assert(c && !stream); + + if (!success) { + fprintf(stderr, "Connection failed: %s\n", pa_strerror(pa_context_errno(c))); + goto fail; + } + + fprintf(stderr, "Connection established.\n"); + + if (!(stream = pa_stream_new(c, mode == PLAYBACK ? PA_STREAM_PLAYBACK : PA_STREAM_RECORD, NULL, "pacat", &ss, NULL, stream_complete_callback, NULL))) { + fprintf(stderr, "pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(c))); + goto fail; + } + + pa_stream_set_die_callback(stream, stream_die_callback, NULL); + pa_stream_set_write_callback(stream, stream_write_callback, NULL); + pa_stream_set_read_callback(stream, stream_read_callback, NULL); + + return; + +fail: + quit(1); +} + +static void context_drain_complete(struct pa_context*c, void *userdata) { + quit(0); +} + +static void stream_drain_complete(struct pa_stream*s, void *userdata) { + fprintf(stderr, "Playback stream drained.\n"); + + pa_stream_free(stream); + stream = NULL; + + if (pa_context_drain(context, context_drain_complete, NULL) < 0) + quit(0); + else + fprintf(stderr, "Draining connection to server.\n"); +} + +static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { + size_t l, w = 0; + ssize_t r; + assert(a == mainloop_api && id && stdio_source == id); + + if (buffer) { + mainloop_api->enable_io(mainloop_api, stdio_source, PA_MAINLOOP_API_IO_EVENT_NULL); + return; + } + + if (!stream || !pa_stream_is_ready(stream) || !(l = w = pa_stream_writable_size(stream))) + l = 4096; + + buffer = malloc(l); + assert(buffer); + if ((r = read(fd, buffer, l)) <= 0) { + if (r == 0) { + fprintf(stderr, "Got EOF.\n"); + pa_stream_drain(stream, stream_drain_complete, NULL); + } else { + fprintf(stderr, "read() failed: %s\n", strerror(errno)); + quit(1); + } + + mainloop_api->cancel_io(mainloop_api, stdio_source); + stdio_source = NULL; + return; + } + + buffer_length = r; + buffer_index = 0; + + if (w) + do_stream_write(w); +} + +static void stdout_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { + ssize_t r; + assert(a == mainloop_api && id && stdio_source == id); + + if (!buffer) { + mainloop_api->enable_io(mainloop_api, stdio_source, PA_MAINLOOP_API_IO_EVENT_NULL); + return; + } + + assert(buffer_length); + + if ((r = write(fd, buffer+buffer_index, buffer_length)) <= 0) { + fprintf(stderr, "write() failed: %s\n", strerror(errno)); + quit(1); + + mainloop_api->cancel_io(mainloop_api, stdio_source); + stdio_source = NULL; + return; + } + + buffer_length -= r; + buffer_index += r; + + if (!buffer_length) { + free(buffer); + buffer = NULL; + buffer_length = buffer_index = 0; + } +} + +static void exit_signal_callback(void *id, int sig, void *userdata) { + fprintf(stderr, "Got SIGINT, exiting.\n"); + quit(0); + +} + +static void stream_get_latency_callback(struct pa_stream *s, uint32_t latency, void *userdata) { + assert(s); + + if (latency == (uint32_t) -1) { + fprintf(stderr, "Failed to get latency: %s\n", strerror(errno)); + quit(1); + return; + } + + fprintf(stderr, "Current latency is %u usecs.\n", latency); +} + +static void sigusr1_signal_callback(void *id, int sig, void *userdata) { + if (mode == PLAYBACK) { + fprintf(stderr, "Got SIGUSR1, requesting latency.\n"); + pa_stream_get_latency(stream, stream_get_latency_callback, NULL); + } +} + +int main(int argc, char *argv[]) { + struct pa_mainloop* m = NULL; + int ret = 1, r; + char *bn; + + if (!(bn = strrchr(argv[0], '/'))) + bn = argv[0]; + + if (strstr(bn, "rec") || strstr(bn, "mon")) + mode = RECORD; + else if (strstr(bn, "cat") || strstr(bn, "play")) + mode = PLAYBACK; + + fprintf(stderr, "Opening a %s stream.\n", mode == RECORD ? "recording" : "playback"); + + if (!(m = pa_mainloop_new())) { + fprintf(stderr, "pa_mainloop_new() failed.\n"); + goto quit; + } + + mainloop_api = pa_mainloop_get_api(m); + + r = pa_signal_init(mainloop_api); + assert(r == 0); + pa_signal_register(SIGINT, exit_signal_callback, NULL); + pa_signal_register(SIGUSR1, sigusr1_signal_callback, NULL); + signal(SIGPIPE, SIG_IGN); + + if (!(stdio_source = mainloop_api->source_io(mainloop_api, + mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO, + mode == PLAYBACK ? PA_MAINLOOP_API_IO_EVENT_INPUT : PA_MAINLOOP_API_IO_EVENT_OUTPUT, + mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) { + fprintf(stderr, "source_io() failed.\n"); + goto quit; + } + + if (!(context = pa_context_new(mainloop_api, argv[0]))) { + fprintf(stderr, "pa_context_new() failed.\n"); + goto quit; + } + + if (pa_context_connect(context, NULL, context_complete_callback, NULL) < 0) { + fprintf(stderr, "pa_context_connext() failed.\n"); + goto quit; + } + + pa_context_set_die_callback(context, context_die_callback, NULL); + + if (pa_mainloop_run(m, &ret) < 0) { + fprintf(stderr, "pa_mainloop_run() failed.\n"); + goto quit; + } + +quit: + if (stream) + pa_stream_free(stream); + if (context) + pa_context_free(context); + + if (m) { + pa_signal_done(); + pa_mainloop_free(m); + } + + if (buffer) + free(buffer); + + return ret; +} diff --git a/polyp/packet.c b/polyp/packet.c new file mode 100644 index 00000000..e94df057 --- /dev/null +++ b/polyp/packet.c @@ -0,0 +1,72 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "packet.h" + +struct pa_packet* pa_packet_new(size_t length) { + struct pa_packet *p; + assert(length); + p = malloc(sizeof(struct pa_packet)+length); + assert(p); + + p->ref = 1; + p->length = length; + p->data = (uint8_t*) (p+1); + p->type = PA_PACKET_APPENDED; + return p; +} + +struct pa_packet* pa_packet_new_dynamic(uint8_t* data, size_t length) { + struct pa_packet *p; + assert(data && length); + p = malloc(sizeof(struct pa_packet)); + assert(p); + + p->ref = 1; + p->length = length; + p->data = data; + p->type = PA_PACKET_DYNAMIC; + return p; +} + +struct pa_packet* pa_packet_ref(struct pa_packet *p) { + assert(p && p->ref >= 1); + p->ref++; + return p; +} + +void pa_packet_unref(struct pa_packet *p) { + assert(p && p->ref >= 1); + p->ref--; + + if (p->ref == 0) { + if (p->type == PA_PACKET_DYNAMIC) + free(p->data); + free(p); + } +} diff --git a/polyp/packet.h b/polyp/packet.h new file mode 100644 index 00000000..8bea07e1 --- /dev/null +++ b/polyp/packet.h @@ -0,0 +1,41 @@ +#ifndef foopackethfoo +#define foopackethfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +struct pa_packet { + enum { PA_PACKET_APPENDED, PA_PACKET_DYNAMIC } type; + unsigned ref; + size_t length; + uint8_t *data; +}; + +struct pa_packet* pa_packet_new(size_t length); +struct pa_packet* pa_packet_new_dynamic(uint8_t* data, size_t length); + +struct pa_packet* pa_packet_ref(struct pa_packet *p); +void pa_packet_unref(struct pa_packet *p); + +#endif diff --git a/polyp/pactl.c b/polyp/pactl.c new file mode 100644 index 00000000..2b1ed2c1 --- /dev/null +++ b/polyp/pactl.c @@ -0,0 +1,166 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "polyplib.h" +#include "polyplib-error.h" +#include "mainloop.h" +#include "mainloop-signal.h" + +static struct pa_context *context = NULL; +static struct pa_mainloop_api *mainloop_api = NULL; + +static enum { + NONE, + EXIT, + STAT +} action = NONE; + +static void quit(int ret) { + assert(mainloop_api); + mainloop_api->quit(mainloop_api, ret); +} + +static void context_die_callback(struct pa_context *c, void *userdata) { + assert(c); + fprintf(stderr, "Connection to server shut down, exiting.\n"); + quit(1); +} + +static void context_drain_complete(struct pa_context *c, void *userdata) { + assert(c); + fprintf(stderr, "Connection to server shut down, exiting.\n"); + quit(0); +} + +static void drain(void) { + if (pa_context_drain(context, context_drain_complete, NULL) < 0) + quit(0); +} + +static void stat_callback(struct pa_context *c, uint32_t blocks, uint32_t total, void *userdata) { + if (blocks == (uint32_t) -1) { + fprintf(stderr, "Failed to get statistics: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + fprintf(stderr, "Currently in use: %u blocks containing %u bytes total.\n", blocks, total); + drain(); +} + +static void context_complete_callback(struct pa_context *c, int success, void *userdata) { + assert(c); + + if (!success) { + fprintf(stderr, "Connection failed: %s\n", pa_strerror(pa_context_errno(c))); + goto fail; + } + + fprintf(stderr, "Connection established.\n"); + + if (action == STAT) + pa_context_stat(c, stat_callback, NULL); + else { + assert(action == EXIT); + pa_context_exit(c); + drain(); + } + + return; + +fail: + quit(1); +} + +static void exit_signal_callback(void *id, int sig, void *userdata) { + fprintf(stderr, "Got SIGINT, exiting.\n"); + quit(0); + +} + +int main(int argc, char *argv[]) { + struct pa_mainloop* m = NULL; + int ret = 1, r; + + if (argc >= 2) { + if (!strcmp(argv[1], "stat")) + action = STAT; + else if (!strcmp(argv[1], "exit")) + action = EXIT; + } + + if (action == NONE) { + fprintf(stderr, "No valid action specified. Use one of: stat, exit\n"); + goto quit; + } + + if (!(m = pa_mainloop_new())) { + fprintf(stderr, "pa_mainloop_new() failed.\n"); + goto quit; + } + + mainloop_api = pa_mainloop_get_api(m); + + r = pa_signal_init(mainloop_api); + assert(r == 0); + pa_signal_register(SIGINT, exit_signal_callback, NULL); + signal(SIGPIPE, SIG_IGN); + + if (!(context = pa_context_new(mainloop_api, argv[0]))) { + fprintf(stderr, "pa_context_new() failed.\n"); + goto quit; + } + + if (pa_context_connect(context, NULL, context_complete_callback, NULL) < 0) { + fprintf(stderr, "pa_context_connext() failed.\n"); + goto quit; + } + + pa_context_set_die_callback(context, context_die_callback, NULL); + + if (pa_mainloop_run(m, &ret) < 0) { + fprintf(stderr, "pa_mainloop_run() failed.\n"); + goto quit; + } + +quit: + if (context) + pa_context_free(context); + + if (m) { + pa_signal_done(); + pa_mainloop_free(m); + } + + return ret; +} diff --git a/polyp/parec-simple.c b/polyp/parec-simple.c new file mode 100644 index 00000000..c4196a14 --- /dev/null +++ b/polyp/parec-simple.c @@ -0,0 +1,94 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "polyplib-simple.h" +#include "polyplib-error.h" + +#define BUFSIZE 1024 + +static ssize_t loop_write(int fd, const void*data, size_t size) { + ssize_t ret = 0; + + while (size > 0) { + ssize_t r; + + if ((r = write(fd, data, size)) < 0) + return r; + + if (r == 0) + break; + + ret += r; + data += r; + size -= r; + } + + return ret; +} + +int main(int argc, char*argv[]) { + static const struct pa_sample_spec ss = { + .format = PA_SAMPLE_S16LE, + .rate = 44100, + .channels = 2 + }; + struct pa_simple *s = NULL; + int ret = 1; + int error; + + if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, &error))) { + fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); + goto finish; + } + + for (;;) { + uint8_t buf[BUFSIZE]; + ssize_t r; + + if (pa_simple_read(s, buf, sizeof(buf), &error) < 0) { + fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error)); + goto finish; + } + + if ((r = loop_write(STDOUT_FILENO, buf, sizeof(buf))) <= 0) { + fprintf(stderr, __FILE__": write() failed: %s\n", strerror(errno)); + goto finish; + } + } + + ret = 0; + +finish: + + if (s) + pa_simple_free(s); + + return ret; +} diff --git a/polyp/pdispatch.c b/polyp/pdispatch.c new file mode 100644 index 00000000..a28458a4 --- /dev/null +++ b/polyp/pdispatch.c @@ -0,0 +1,247 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "pdispatch.h" +#include "native-common.h" + +#ifdef DEBUG_OPCODES + +static const char *command_names[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = "ERROR", + [PA_COMMAND_TIMEOUT] = "TIMEOUT", + [PA_COMMAND_REPLY] = "REPLY", + [PA_COMMAND_CREATE_PLAYBACK_STREAM] = "CREATE_PLAYBACK_STREAM", + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = "DELETE_PLAYBACK_STREAM", + [PA_COMMAND_CREATE_RECORD_STREAM] = "CREATE_RECORD_STREAM", + [PA_COMMAND_DELETE_RECORD_STREAM] = "DELETE_RECORD_STREAM", + [PA_COMMAND_AUTH] = "AUTH", + [PA_COMMAND_REQUEST] = "REQUEST", + [PA_COMMAND_EXIT] = "EXIT", + [PA_COMMAND_SET_NAME] = "SET_NAME", + [PA_COMMAND_LOOKUP_SINK] = "LOOKUP_SINK", + [PA_COMMAND_LOOKUP_SOURCE] = "LOOKUP_SOURCE", + [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = "DRAIN_PLAYBACK_STREAM", + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = "PLAYBACK_STREAM_KILLED", + [PA_COMMAND_RECORD_STREAM_KILLED] = "RECORD_STREAM_KILLED", + [PA_COMMAND_STAT] = "STAT", + [PA_COMMAND_GET_PLAYBACK_LATENCY] = "PLAYBACK_LATENCY", +}; + +#endif + +struct reply_info { + struct pa_pdispatch *pdispatch; + struct reply_info *next, *previous; + void (*callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); + void *userdata; + uint32_t tag; + void *mainloop_timeout; + int callback_is_running; +}; + +struct pa_pdispatch { + struct pa_mainloop_api *mainloop; + const struct pa_pdispatch_command *command_table; + unsigned n_commands; + struct reply_info *replies; + void (*drain_callback)(struct pa_pdispatch *pd, void *userdata); + void *drain_userdata; + int in_use, shall_free; +}; + +static void reply_info_free(struct reply_info *r) { + assert(r && r->pdispatch && r->pdispatch->mainloop); + + if (r->pdispatch) + r->pdispatch->mainloop->cancel_time(r->pdispatch->mainloop, r->mainloop_timeout); + + if (r->previous) + r->previous->next = r->next; + else + r->pdispatch->replies = r->next; + + if (r->next) + r->next->previous = r->previous; + + free(r); +} + +struct pa_pdispatch* pa_pdispatch_new(struct pa_mainloop_api *mainloop, const struct pa_pdispatch_command*table, unsigned entries) { + struct pa_pdispatch *pd; + assert(mainloop); + + assert((entries && table) || (!entries && !table)); + + pd = malloc(sizeof(struct pa_pdispatch)); + assert(pd); + pd->mainloop = mainloop; + pd->command_table = table; + pd->n_commands = entries; + pd->replies = NULL; + pd->drain_callback = NULL; + pd->drain_userdata = NULL; + + pd->in_use = pd->shall_free = 0; + return pd; +} + +void pa_pdispatch_free(struct pa_pdispatch *pd) { + assert(pd); + + if (pd->in_use) { + pd->shall_free = 1; + return; + } + + while (pd->replies) + reply_info_free(pd->replies); + free(pd); +} + +int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *userdata) { + uint32_t tag, command; + struct pa_tagstruct *ts = NULL; + int ret = -1; + assert(pd && packet && packet->data && !pd->in_use); + + if (packet->length <= 8) + goto finish; + + ts = pa_tagstruct_new(packet->data, packet->length); + assert(ts); + + if (pa_tagstruct_getu32(ts, &command) < 0 || + pa_tagstruct_getu32(ts, &tag) < 0) + goto finish; + +#ifdef DEBUG_OPCODES + fprintf(stderr, __FILE__": Recieved opcode <%s>\n", command_names[command]); +#endif + + if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) { + struct reply_info *r; + + for (r = pd->replies; r; r = r->next) + if (r->tag == tag) + break; + + if (r) { + pd->in_use = r->callback_is_running = 1; + assert(r->callback); + r->callback(r->pdispatch, command, tag, ts, r->userdata); + pd->in_use = r->callback_is_running = 0; + reply_info_free(r); + + if (pd->shall_free) + pa_pdispatch_free(pd); + else { + if (pd->drain_callback && !pa_pdispatch_is_pending(pd)) + pd->drain_callback(pd, pd->drain_userdata); + } + } + + } else if (pd->command_table && command < pd->n_commands) { + const struct pa_pdispatch_command *c = pd->command_table+command; + + if (c->proc) + c->proc(pd, command, tag, ts, userdata); + } else + goto finish; + + ret = 0; + +finish: + if (ts) + pa_tagstruct_free(ts); + + return ret; +} + +static void timeout_callback(struct pa_mainloop_api*m, void *id, const struct timeval *tv, void *userdata) { + struct reply_info*r = userdata; + assert (r && r->mainloop_timeout == id && r->pdispatch && r->pdispatch->mainloop == m && r->callback); + + r->callback(r->pdispatch, PA_COMMAND_TIMEOUT, r->tag, NULL, r->userdata); + reply_info_free(r); + + if (r->pdispatch->drain_callback && !pa_pdispatch_is_pending(r->pdispatch)) + r->pdispatch->drain_callback(r->pdispatch, r->pdispatch->drain_userdata); +} + +void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int timeout, void (*cb)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void *userdata) { + struct reply_info *r; + struct timeval tv; + assert(pd && cb); + + r = malloc(sizeof(struct reply_info)); + assert(r); + r->pdispatch = pd; + r->callback = cb; + r->userdata = userdata; + r->tag = tag; + r->callback_is_running = 0; + + gettimeofday(&tv, NULL); + tv.tv_sec += timeout; + + r->mainloop_timeout = pd->mainloop->source_time(pd->mainloop, &tv, timeout_callback, r); + assert(r->mainloop_timeout); + + r->previous = NULL; + r->next = pd->replies; + if (r->next) + r->next->previous = r; + pd->replies = r; +} + +int pa_pdispatch_is_pending(struct pa_pdispatch *pd) { + assert(pd); + + return !!pd->replies; +} + +void pa_pdispatch_set_drain_callback(struct pa_pdispatch *pd, void (*cb)(struct pa_pdispatch *pd, void *userdata), void *userdata) { + assert(pd); + assert(!cb || pa_pdispatch_is_pending(pd)); + + pd->drain_callback = cb; + pd->drain_userdata = userdata; +} + +void pa_pdispatch_unregister_reply(struct pa_pdispatch *pd, void *userdata) { + struct reply_info *r, *n; + assert(pd); + + for (r = pd->replies; r; r = n) { + n = r->next; + + if (!r->callback_is_running && r->userdata == userdata) /* when this item's callback is currently running it is destroyed anyway in the very near future */ + reply_info_free(r); + } +} diff --git a/polyp/pdispatch.h b/polyp/pdispatch.h new file mode 100644 index 00000000..796c1e03 --- /dev/null +++ b/polyp/pdispatch.h @@ -0,0 +1,52 @@ +#ifndef foopdispatchhfoo +#define foopdispatchhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include "tagstruct.h" +#include "packet.h" +#include "mainloop-api.h" + +struct pa_pdispatch; + +/* It is safe to destroy the calling pdispatch object from all callbacks */ + +struct pa_pdispatch_command { + void (*proc)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +}; + +struct pa_pdispatch* pa_pdispatch_new(struct pa_mainloop_api *m, const struct pa_pdispatch_command*table, unsigned entries); +void pa_pdispatch_free(struct pa_pdispatch *pd); + +int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*p, void *userdata); + +void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int timeout, void (*cb)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void *userdata); + +int pa_pdispatch_is_pending(struct pa_pdispatch *pd); + +void pa_pdispatch_set_drain_callback(struct pa_pdispatch *pd, void (*cb)(struct pa_pdispatch *pd, void *userdata), void *userdata); + +/* Remove all reply slots with the give userdata parameter */ +void pa_pdispatch_unregister_reply(struct pa_pdispatch *pd, void *userdata); + +#endif diff --git a/polyp/polypaudio.pa b/polyp/polypaudio.pa new file mode 100755 index 00000000..177707ba --- /dev/null +++ b/polyp/polypaudio.pa @@ -0,0 +1,41 @@ +#!./polypaudio -F + +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + + +# Load audio drivers +load module-alsa-sink +load module-alsa-source device=plughw:1,0 +#load module-oss device="/dev/dsp" +#load module-oss-mmap device="/dev/dsp" + +# Load several protocols +load module-esound-protocol-tcp +load module-simple-protocol-tcp +load module-native-protocol-unix +load module-cli-protocol-unix + +# Load the CLI module +load module-cli + +.nofail + +# Make some devices default +sink_default alsa_output +source_default alsa_input + diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h new file mode 100644 index 00000000..e43f4b35 --- /dev/null +++ b/polyp/polyplib-def.h @@ -0,0 +1,40 @@ +#ifndef foopolyplibdefhfoo +#define foopolyplibdefhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +enum pa_stream_direction { + PA_STREAM_PLAYBACK, + PA_STREAM_RECORD +}; + +struct pa_buffer_attr { + uint32_t maxlength; + uint32_t tlength; + uint32_t prebuf; + uint32_t minreq; + uint32_t fragsize; +}; + +#endif diff --git a/polyp/polyplib-error.c b/polyp/polyplib-error.c new file mode 100644 index 00000000..10b637c4 --- /dev/null +++ b/polyp/polyplib-error.c @@ -0,0 +1,53 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "polyplib-error.h" +#include "native-common.h" + +static const char* const errortab[PA_ERROR_MAX] = { + [PA_ERROR_OK] = "OK", + [PA_ERROR_ACCESS] = "Access denied", + [PA_ERROR_COMMAND] = "Unknown command", + [PA_ERROR_INVALID] = "Invalid argument", + [PA_ERROR_EXIST] = "Entity exists", + [PA_ERROR_NOENTITY] = "No such entity", + [PA_ERROR_CONNECTIONREFUSED] = "Connection refused", + [PA_ERROR_PROTOCOL] = "Protocol corrupt", + [PA_ERROR_TIMEOUT] = "Timeout", + [PA_ERROR_AUTHKEY] = "Not authorization key", + [PA_ERROR_INTERNAL] = "Internal error", + [PA_ERROR_CONNECTIONTERMINATED] = "Connection terminated", + [PA_ERROR_KILLED] = "Entity killed", +}; + +const char*pa_strerror(uint32_t error) { + if (error >= PA_ERROR_MAX) + return NULL; + + return errortab[error]; +} diff --git a/polyp/polyplib-error.h b/polyp/polyplib-error.h new file mode 100644 index 00000000..cb86864a --- /dev/null +++ b/polyp/polyplib-error.h @@ -0,0 +1,29 @@ +#ifndef foopolypliberrorhfoo +#define foopolypliberrorhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +const char* pa_strerror(uint32_t error); + +#endif diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c new file mode 100644 index 00000000..024cb18a --- /dev/null +++ b/polyp/polyplib-simple.c @@ -0,0 +1,259 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "polyplib-simple.h" +#include "polyplib.h" +#include "mainloop.h" +#include "native-common.h" +/*#include "polyp-error.h"*/ + +struct pa_simple { + struct pa_mainloop *mainloop; + struct pa_context *context; + struct pa_stream *stream; + enum pa_stream_direction direction; + + int dead, drained; + + void *read_data; + size_t read_index, read_length; +}; + +static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata); + +static int check_error(struct pa_simple *p, int *perror) { + assert(p); + + if (pa_context_is_dead(p->context) || (p->stream && pa_stream_is_dead(p->stream))) { + if (perror) + *perror = pa_context_errno(p->context); + return -1; + } + + return 0; +} + +static int iterate(struct pa_simple *p, int block, int *perror) { + assert(p && p->context && p->mainloop); + + if (check_error(p, perror) < 0) + return -1; + + if (!block && !pa_context_is_pending(p->context)) + return 0; + + do { + if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) { + if (perror) + *perror = PA_ERROR_INTERNAL; + return -1; + } + + if (check_error(p, perror) < 0) + return -1; + + } while (pa_context_is_pending(p->context)); + + return 0; +} + +struct pa_simple* pa_simple_new( + const char *server, + const char *name, + enum pa_stream_direction dir, + const char *dev, + const char *stream_name, + const struct pa_sample_spec *ss, + const struct pa_buffer_attr *attr, + int *perror) { + + struct pa_simple *p; + int error = PA_ERROR_INTERNAL; + assert(ss); + + p = malloc(sizeof(struct pa_simple)); + assert(p); + p->context = NULL; + p->stream = NULL; + p->mainloop = pa_mainloop_new(); + assert(p->mainloop); + p->dead = 0; + p->direction = dir; + p->read_data = NULL; + p->read_index = p->read_length = 0; + + if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name))) + goto fail; + + if (pa_context_connect(p->context, server, NULL, NULL) < 0) { + error = pa_context_errno(p->context); + goto fail; + } + + /* Wait until the context is ready */ + while (!pa_context_is_ready(p->context)) { + if (iterate(p, 1, &error) < 0) + goto fail; + } + + if (!(p->stream = pa_stream_new(p->context, dir, dev, stream_name, ss, attr, NULL, NULL))) + goto fail; + + /* Wait until the stream is ready */ + while (!pa_stream_is_ready(p->stream)) { + if (iterate(p, 1, &error) < 0) + goto fail; + } + + pa_stream_set_read_callback(p->stream, read_callback, p); + + return p; + +fail: + if (perror) + *perror = error; + pa_simple_free(p); + return NULL; +} + +void pa_simple_free(struct pa_simple *s) { + assert(s); + + free(s->read_data); + + if (s->stream) + pa_stream_free(s->stream); + + if (s->context) + pa_context_free(s->context); + + if (s->mainloop) + pa_mainloop_free(s->mainloop); + + free(s); +} + +int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *perror) { + assert(p && data && p->direction == PA_STREAM_PLAYBACK); + + while (length > 0) { + size_t l; + + while (!(l = pa_stream_writable_size(p->stream))) + if (iterate(p, 1, perror) < 0) + return -1; + + if (l > length) + l = length; + + pa_stream_write(p->stream, data, l); + data += l; + length -= l; + } + + /* Make sure that no data is pending for write */ + if (iterate(p, 0, perror) < 0) + return -1; + + return 0; +} + +static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata) { + struct pa_simple *p = userdata; + assert(s && data && length && p); + + if (p->read_data) { + fprintf(stderr, __FILE__": Buffer overflow, dropping incoming memory blocks.\n"); + free(p->read_data); + } + + p->read_data = malloc(p->read_length = length); + assert(p->read_data); + memcpy(p->read_data, data, length); + p->read_index = 0; +} + +int pa_simple_read(struct pa_simple *p, void*data, size_t length, int *perror) { + assert(p && data && p->direction == PA_STREAM_RECORD); + + while (length > 0) { + if (p->read_data) { + size_t l = length; + + if (p->read_length <= l) + l = p->read_length; + + memcpy(data, p->read_data+p->read_index, l); + + data += l; + length -= l; + + p->read_index += l; + p->read_length -= l; + + if (!p->read_length) { + free(p->read_data); + p->read_data = NULL; + p->read_index = 0; + } + + if (!length) + return 0; + + assert(!p->read_data); + } + + if (iterate(p, 1, perror) < 0) + return -1; + } + + return 0; +} + +static void drain_complete(struct pa_stream *s, void *userdata) { + struct pa_simple *p = userdata; + assert(s && p); + p->drained = 1; +} + +int pa_simple_drain(struct pa_simple *p, int *perror) { + assert(p && p->direction == PA_STREAM_PLAYBACK); + p->drained = 0; + pa_stream_drain(p->stream, drain_complete, p); + + while (!p->drained) { + if (iterate(p, 1, perror) < 0) { + pa_stream_drain(p->stream, NULL, NULL); + return -1; + } + } + + return 0; +} diff --git a/polyp/polyplib-simple.h b/polyp/polyplib-simple.h new file mode 100644 index 00000000..0544410c --- /dev/null +++ b/polyp/polyplib-simple.h @@ -0,0 +1,49 @@ +#ifndef foopolyplibsimplehfoo +#define foopolyplibsimplehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "sample.h" +#include "polyplib-def.h" + +struct pa_simple; + +struct pa_simple* pa_simple_new( + const char *server, + const char *name, + enum pa_stream_direction dir, + const char *dev, + const char *stream_name, + const struct pa_sample_spec *ss, + const struct pa_buffer_attr *attr, + int *error); + +void pa_simple_free(struct pa_simple *s); + +int pa_simple_write(struct pa_simple *s, const void*data, size_t length, int *error); +int pa_simple_drain(struct pa_simple *s, int *error); + +int pa_simple_read(struct pa_simple *s, void*data, size_t length, int *error); + +#endif diff --git a/polyp/polyplib.c b/polyp/polyplib.c new file mode 100644 index 00000000..ea5003b4 --- /dev/null +++ b/polyp/polyplib.c @@ -0,0 +1,973 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "polyplib.h" +#include "native-common.h" +#include "pdispatch.h" +#include "pstream.h" +#include "dynarray.h" +#include "socket-client.h" +#include "pstream-util.h" +#include "authkey.h" +#include "util.h" + +#define DEFAULT_MAXLENGTH 204800 +#define DEFAULT_TLENGTH 10240 +#define DEFAULT_PREBUF 4096 +#define DEFAULT_MINREQ 1024 +#define DEFAULT_FRAGSIZE 1024 + +#define DEFAULT_TIMEOUT (5*60) +#define DEFAULT_SERVER "/tmp/polypaudio/native" +#define DEFAULT_PORT "4713" + +struct pa_context { + char *name; + struct pa_mainloop_api* mainloop; + struct pa_socket_client *client; + struct pa_pstream *pstream; + struct pa_pdispatch *pdispatch; + struct pa_dynarray *record_streams, *playback_streams; + struct pa_stream *first_stream; + uint32_t ctag; + uint32_t error; + enum { + CONTEXT_UNCONNECTED, + CONTEXT_CONNECTING, + CONTEXT_AUTHORIZING, + CONTEXT_SETTING_NAME, + CONTEXT_READY, + CONTEXT_DEAD + } state; + + void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); + void *connect_complete_userdata; + + void (*drain_complete_callback)(struct pa_context*c, void *userdata); + void *drain_complete_userdata; + + void (*die_callback)(struct pa_context*c, void *userdata); + void *die_userdata; + + void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); + void *stat_userdata; + + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; +}; + +struct pa_stream { + struct pa_context *context; + struct pa_stream *next, *previous; + + char *name; + struct pa_buffer_attr buffer_attr; + struct pa_sample_spec sample_spec; + uint32_t device_index; + uint32_t channel; + int channel_valid; + enum pa_stream_direction direction; + + enum { STREAM_LOOKING_UP, STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; + uint32_t requested_bytes; + + void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); + void *read_userdata; + + void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); + void *write_userdata; + + void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); + void *create_complete_userdata; + + void (*drain_complete_callback)(struct pa_stream *s, void *userdata); + void *drain_complete_userdata; + + void (*die_callback)(struct pa_stream*c, void *userdata); + void *die_userdata; + + void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); + void *get_latency_userdata; +}; + +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); + +static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = { NULL }, + [PA_COMMAND_REPLY] = { NULL }, + [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_EXIT] = { NULL }, + [PA_COMMAND_REQUEST] = { command_request }, + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, + [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, +}; + +struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { + struct pa_context *c; + assert(mainloop && name); + + c = malloc(sizeof(struct pa_context)); + assert(c); + c->name = strdup(name); + c->mainloop = mainloop; + c->client = NULL; + c->pstream = NULL; + c->pdispatch = NULL; + c->playback_streams = pa_dynarray_new(); + assert(c->playback_streams); + c->record_streams = pa_dynarray_new(); + assert(c->record_streams); + c->first_stream = NULL; + c->error = PA_ERROR_OK; + c->state = CONTEXT_UNCONNECTED; + c->ctag = 0; + + c->connect_complete_callback = NULL; + c->connect_complete_userdata = NULL; + + c->drain_complete_callback = NULL; + c->drain_complete_userdata = NULL; + + c->die_callback = NULL; + c->die_userdata = NULL; + + c->stat_callback = NULL; + c->stat_userdata = NULL; + + pa_check_for_sigpipe(); + return c; +} + +void pa_context_free(struct pa_context *c) { + assert(c); + + while (c->first_stream) + pa_stream_free(c->first_stream); + + if (c->client) + pa_socket_client_free(c->client); + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + if (c->pstream) + pa_pstream_free(c->pstream); + if (c->record_streams) + pa_dynarray_free(c->record_streams, NULL, NULL); + if (c->playback_streams) + pa_dynarray_free(c->playback_streams, NULL, NULL); + + free(c->name); + free(c); +} + +static void stream_dead(struct pa_stream *s) { + assert(s); + + if (s->state == STREAM_DEAD) + return; + + if (s->state == STREAM_READY) { + s->state = STREAM_DEAD; + if (s->die_callback) + s->die_callback(s, s->die_userdata); + } else + s->state = STREAM_DEAD; +} + +static void context_dead(struct pa_context *c) { + struct pa_stream *s; + assert(c); + + if (c->state == CONTEXT_DEAD) + return; + + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + c->pdispatch = NULL; + + if (c->pstream) + pa_pstream_free(c->pstream); + c->pstream = NULL; + + if (c->client) + pa_socket_client_free(c->client); + c->client = NULL; + + for (s = c->first_stream; s; s = s->next) + stream_dead(s); + + if (c->state == CONTEXT_READY) { + c->state = CONTEXT_DEAD; + if (c->die_callback) + c->die_callback(c, c->die_userdata); + } else + c->state = CONTEXT_DEAD; +} + +static void pstream_die_callback(struct pa_pstream *p, void *userdata) { + struct pa_context *c = userdata; + assert(p && c); + c->error = PA_ERROR_CONNECTIONTERMINATED; + context_dead(c); +} + +static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { + struct pa_context *c = userdata; + assert(p && packet && c); + + if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { + fprintf(stderr, "polyp.c: invalid packet.\n"); + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + } +} + +static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + assert(p && chunk && c && chunk->memblock && chunk->memblock->data); + + if (!(s = pa_dynarray_get(c->record_streams, channel))) + return; + + if (s->read_callback) + s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); +} + +static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { + assert(c && t); + + if (command == PA_COMMAND_ERROR) { + if (pa_tagstruct_getu32(t, &c->error) < 0) { + c->error = PA_ERROR_PROTOCOL; + return -1; + } + + return 0; + } + + c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; + return -1; +} + +static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); + + if (command != PA_COMMAND_REPLY) { + handle_error(c, command, t); + context_dead(c); + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return; + } + + if (c->state == CONTEXT_AUTHORIZING) { + struct pa_tagstruct *t; + c->state = CONTEXT_SETTING_NAME; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, c->name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + } else { + assert(c->state == CONTEXT_SETTING_NAME); + + c->state = CONTEXT_READY; + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 1, c->connect_complete_userdata); + } + + return; +} + +static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { + struct pa_context *c = userdata; + struct pa_tagstruct *t; + uint32_t tag; + assert(client && c && c->state == CONTEXT_CONNECTING); + + pa_socket_client_free(client); + c->client = NULL; + + if (!io) { + c->error = PA_ERROR_CONNECTIONREFUSED; + context_dead(c); + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return; + } + + c->pstream = pa_pstream_new(c->mainloop, io); + assert(c->pstream); + pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); + pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); + pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); + + c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); + assert(c->pdispatch); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_AUTH); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + c->state = CONTEXT_AUTHORIZING; +} + +static struct sockaddr *resolve_server(const char *server, size_t *len) { + struct sockaddr *sa; + struct addrinfo hints, *result = NULL; + char *port; + assert(server && len); + + if ((port = strrchr(server, ':'))) + port++; + if (!port) + port = DEFAULT_PORT; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + if (getaddrinfo(server, port, &hints, &result) != 0) + return NULL; + assert(result); + + sa = malloc(*len = result->ai_addrlen); + assert(sa); + memcpy(sa, result->ai_addr, *len); + + freeaddrinfo(result); + + return sa; + +} + +int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { + assert(c && c->state == CONTEXT_UNCONNECTED); + + if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { + c->error = PA_ERROR_AUTHKEY; + return -1; + } + + if (!server) + if (!(server = getenv("POLYP_SERVER"))) + server = DEFAULT_SERVER; + + assert(!c->client); + + if (*server == '/') { + if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + } else { + struct sockaddr* sa; + size_t sa_len; + + if (!(sa = resolve_server(server, &sa_len))) { + c->error = PA_ERROR_INVALIDSERVER; + return -1; + } + + c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); + free(sa); + + if (!c->client) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + } + + c->connect_complete_callback = complete; + c->connect_complete_userdata = userdata; + + pa_socket_client_set_callback(c->client, on_connection, c); + c->state = CONTEXT_CONNECTING; + + return 0; +} + +int pa_context_is_dead(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_DEAD; +} + +int pa_context_is_ready(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_READY; +} + +int pa_context_errno(struct pa_context *c) { + assert(c); + return c->error; +} + +void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { + assert(c); + c->die_callback = cb; + c->die_userdata = userdata; +} + +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + uint32_t channel; + assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) + return; + + c->error = PA_ERROR_KILLED; + stream_dead(s); +} + +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s; + struct pa_context *c = userdata; + uint32_t bytes, channel; + assert(pd && command == PA_COMMAND_REQUEST && t && c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + pa_tagstruct_getu32(t, &bytes) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (!(s = pa_dynarray_get(c->playback_streams, channel))) + return; + + if (s->state != STREAM_READY) + return; + + s->requested_bytes += bytes; + + if (s->requested_bytes && s->write_callback) + s->write_callback(s, s->requested_bytes, s->write_userdata); +} + +static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s && s->state == STREAM_CREATING); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + if (s->create_complete_callback) + s->create_complete_callback(s, 0, s->create_complete_userdata); + + return; + } + + if (pa_tagstruct_getu32(t, &s->channel) < 0 || + pa_tagstruct_getu32(t, &s->device_index) < 0 || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + s->channel_valid = 1; + pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, s); + + s->state = STREAM_READY; + if (s->create_complete_callback) + s->create_complete_callback(s, 1, s->create_complete_userdata); +} + +static void create_stream(struct pa_stream *s, uint32_t tdev_index) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s); + + s->state = STREAM_CREATING; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_puts(t, s->name); + pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_putu32(t, tdev_index); + pa_tagstruct_putu32(t, s->buffer_attr.maxlength); + if (s->direction == PA_STREAM_PLAYBACK) { + pa_tagstruct_putu32(t, s->buffer_attr.tlength); + pa_tagstruct_putu32(t, s->buffer_attr.prebuf); + pa_tagstruct_putu32(t, s->buffer_attr.minreq); + } else + pa_tagstruct_putu32(t, s->buffer_attr.fragsize); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); +} + +static void lookup_device_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + uint32_t tdev; + assert(pd && s && s->state == STREAM_LOOKING_UP); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + if (s->create_complete_callback) + s->create_complete_callback(s, 0, s->create_complete_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &tdev) < 0 || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + create_stream(s, tdev); +} + +static void lookup_device(struct pa_stream *s, const char *tdev) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s); + + s->state = STREAM_LOOKING_UP; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_LOOKUP_SINK : PA_COMMAND_LOOKUP_SOURCE); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_puts(t, tdev); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, lookup_device_callback, s); +} + +struct pa_stream* pa_stream_new( + struct pa_context *c, + enum pa_stream_direction dir, + const char *dev, + const char *name, + const struct pa_sample_spec *ss, + const struct pa_buffer_attr *attr, + void (*complete) (struct pa_stream*s, int success, void *userdata), + void *userdata) { + + struct pa_stream *s; + + assert(c && name && ss && c->state == CONTEXT_READY); + + s = malloc(sizeof(struct pa_stream)); + assert(s); + s->context = c; + + s->read_callback = NULL; + s->read_userdata = NULL; + s->write_callback = NULL; + s->write_userdata = NULL; + s->die_callback = NULL; + s->die_userdata = NULL; + s->create_complete_callback = complete; + s->create_complete_userdata = NULL; + s->get_latency_callback = NULL; + s->get_latency_userdata = NULL; + + s->name = strdup(name); + s->state = STREAM_CREATING; + s->requested_bytes = 0; + s->channel = 0; + s->channel_valid = 0; + s->device_index = (uint32_t) -1; + s->direction = dir; + s->sample_spec = *ss; + if (attr) + s->buffer_attr = *attr; + else { + s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; + s->buffer_attr.tlength = DEFAULT_TLENGTH; + s->buffer_attr.prebuf = DEFAULT_PREBUF; + s->buffer_attr.minreq = DEFAULT_MINREQ; + s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; + } + + s->next = c->first_stream; + if (s->next) + s->next->previous = s; + s->previous = NULL; + c->first_stream = s; + + if (dev) + lookup_device(s, dev); + else + create_stream(s, (uint32_t) -1); + + return s; +} + +void pa_stream_free(struct pa_stream *s) { + assert(s && s->context); + + if (s->context->pdispatch) + pa_pdispatch_unregister_reply(s->context->pdispatch, s); + + free(s->name); + + if (s->channel_valid && s->context->state == CONTEXT_READY) { + struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, PA_COMMAND_DELETE_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + } + + if (s->channel_valid) + pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); + + if (s->next) + s->next->previous = s->previous; + if (s->previous) + s->previous->next = s->next; + else + s->context->first_stream = s->next; + + free(s); +} + +void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { + assert(s && cb); + s->write_callback = cb; + s->write_userdata = userdata; +} + +void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { + struct pa_memchunk chunk; + assert(s && s->context && data && length && s->state == STREAM_READY); + + chunk.memblock = pa_memblock_new(length); + assert(chunk.memblock && chunk.memblock->data); + memcpy(chunk.memblock->data, data, length); + chunk.index = 0; + chunk.length = length; + + pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); + pa_memblock_unref(chunk.memblock); + + /*fprintf(stderr, "Sent %u bytes\n", length);*/ + + if (length < s->requested_bytes) + s->requested_bytes -= length; + else + s->requested_bytes = 0; +} + +size_t pa_stream_writable_size(struct pa_stream *s) { + assert(s && s->state == STREAM_READY); + return s->requested_bytes; +} + +void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { + assert(s && cb); + s->read_callback = cb; + s->read_userdata = userdata; +} + +int pa_stream_is_dead(struct pa_stream *s) { + return s->state == STREAM_DEAD; +} + +int pa_stream_is_ready(struct pa_stream*s) { + return s->state == STREAM_READY; +} + +void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { + assert(s); + s->die_callback = cb; + s->die_userdata = userdata; +} + +int pa_context_is_pending(struct pa_context *c) { + assert(c); + + if (c->state != CONTEXT_READY) + return 0; + + return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); +} + +struct pa_context* pa_stream_get_context(struct pa_stream *p) { + assert(p); + return p->context; +} + +static void set_dispatch_callbacks(struct pa_context *c); + +static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void set_dispatch_callbacks(struct pa_context *c) { + assert(c && c->state == CONTEXT_READY); + + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + + if (pa_pdispatch_is_pending(c->pdispatch)) { + pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); + return; + } + + if (pa_pstream_is_pending(c->pstream)) { + pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); + return; + } + + assert(c->drain_complete_callback); + c->drain_complete_callback(c, c->drain_complete_userdata); +} + +int pa_context_drain( + struct pa_context *c, + void (*complete) (struct pa_context*c, void *userdata), + void *userdata) { + + assert(c && c->state == CONTEXT_READY); + + if (complete == NULL) { + c->drain_complete_callback = NULL; + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + return 0; + } + + if (!pa_context_is_pending(c)) + return -1; + + c->drain_complete_callback = complete; + c->drain_complete_userdata = userdata; + + set_dispatch_callbacks(c); + + return 0; +} + +static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + return; + } + + if (s->state != STREAM_READY) + return; + + if (!pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->drain_complete_callback) { + void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; + s->drain_complete_callback = NULL; + temp(s, s->drain_complete_userdata); + } +} + + +void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s && s->state == STREAM_READY); + + if (!complete) { + s->drain_complete_callback = NULL; + return; + } + + s->drain_complete_callback = complete; + s->drain_complete_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); +} + +void pa_context_exit(struct pa_context *c) { + struct pa_tagstruct *t; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_EXIT); + pa_tagstruct_putu32(t, c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + uint32_t total, count; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &count) < 0 || + pa_tagstruct_getu32(t, &total) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, count, total, c->stat_userdata); +} + +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + c->stat_callback = cb; + c->stat_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_STAT); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); +} + +static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + uint32_t latency; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &latency) < 0 || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, latency, s->get_latency_userdata); +} + +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + p->get_latency_callback = cb; + p->get_latency_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); + pa_tagstruct_putu32(t, tag = p->context->ctag++); + pa_tagstruct_putu32(t, p->channel); + pa_pstream_send_tagstruct(p->context->pstream, t); + pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); +} diff --git a/polyp/polyplib.h b/polyp/polyplib.h new file mode 100644 index 00000000..440b9658 --- /dev/null +++ b/polyp/polyplib.h @@ -0,0 +1,94 @@ +#ifndef foopolyplibhfoo +#define foopolyplibhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "sample.h" +#include "polyplib-def.h" +#include "mainloop-api.h" + +struct pa_context; + +struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); + +int pa_context_connect( + struct pa_context *c, + const char *server, + void (*complete) (struct pa_context*c, int success, void *userdata), + void *userdata); + +int pa_context_drain( + struct pa_context *c, + void (*complete) (struct pa_context*c, void *userdata), + void *userdata); + +void pa_context_free(struct pa_context *c); + +void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); + +int pa_context_is_dead(struct pa_context *c); +int pa_context_is_ready(struct pa_context *c); +int pa_context_errno(struct pa_context *c); + +int pa_context_is_pending(struct pa_context *c); + +void pa_context_exit(struct pa_context *c); +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); + +struct pa_stream; + +struct pa_stream* pa_stream_new( + struct pa_context *c, + enum pa_stream_direction dir, + const char *dev, + const char *name, + const struct pa_sample_spec *ss, + const struct pa_buffer_attr *attr, + void (*complete) (struct pa_stream*s, int success, void *userdata), + void *userdata); + +void pa_stream_free(struct pa_stream *p); + +void pa_stream_drain( + struct pa_stream *s, + void (*complete) (struct pa_stream*s, void *userdata), + void *userdata); + + +void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); + +void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); +void pa_stream_write(struct pa_stream *p, const void *data, size_t length); +size_t pa_stream_writable_size(struct pa_stream *p); + +void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); + +int pa_stream_is_dead(struct pa_stream *p); +int pa_stream_is_ready(struct pa_stream*p); + +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); + +struct pa_context* pa_stream_get_context(struct pa_stream *p); + +#endif diff --git a/polyp/protocol-cli.c b/polyp/protocol-cli.c new file mode 100644 index 00000000..d6e69b54 --- /dev/null +++ b/polyp/protocol-cli.c @@ -0,0 +1,85 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "protocol-cli.h" +#include "cli.h" + +struct pa_protocol_cli { + struct pa_module *module; + struct pa_core *core; + struct pa_socket_server*server; + struct pa_idxset *connections; +}; + +static void cli_eof_cb(struct pa_cli*c, void*userdata) { + struct pa_protocol_cli *p = userdata; + assert(p); + pa_idxset_remove_by_data(p->connections, c, NULL); + pa_cli_free(c); +} + +static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { + struct pa_protocol_cli *p = userdata; + struct pa_cli *c; + assert(s && io && p); + + c = pa_cli_new(p->core, io, p->module); + assert(c); + pa_cli_set_eof_callback(c, cli_eof_cb, p); + + pa_idxset_put(p->connections, c, NULL); +} + +struct pa_protocol_cli* pa_protocol_cli_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { + struct pa_protocol_cli* p; + assert(core && server); + + p = malloc(sizeof(struct pa_protocol_cli)); + assert(p); + p->module = m; + p->core = core; + p->server = server; + p->connections = pa_idxset_new(NULL, NULL); + + pa_socket_server_set_callback(p->server, on_connection, p); + + return p; +} + +static void free_connection(void *p, void *userdata) { + assert(p); + pa_cli_free(p); +} + +void pa_protocol_cli_free(struct pa_protocol_cli *p) { + assert(p); + + pa_idxset_free(p->connections, free_connection, NULL); + pa_socket_server_free(p->server); + free(p); +} diff --git a/polyp/protocol-cli.h b/polyp/protocol-cli.h new file mode 100644 index 00000000..7ad2db75 --- /dev/null +++ b/polyp/protocol-cli.h @@ -0,0 +1,35 @@ +#ifndef fooprotocolclihfoo +#define fooprotocolclihfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" +#include "socket-server.h" +#include "module.h" +#include "modargs.h" + +struct pa_protocol_cli; + +struct pa_protocol_cli* pa_protocol_cli_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma); +void pa_protocol_cli_free(struct pa_protocol_cli *n); + +#endif diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c new file mode 100644 index 00000000..8a7c4bcb --- /dev/null +++ b/polyp/protocol-esound.c @@ -0,0 +1,847 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "protocol-esound.h" +#include "esound.h" +#include "memblock.h" +#include "client.h" +#include "sink-input.h" +#include "sink.h" +#include "source-output.h" +#include "source.h" +#include "sample.h" + +#include "authkey.h" + +#define DEFAULT_COOKIE_FILE ".esd_auth" + +#define PLAYBACK_BUFFER_SECONDS (.5) +#define PLAYBACK_BUFFER_FRAGMENTS (10) +#define RECORD_BUFFER_SECONDS (5) +#define RECORD_BUFFER_FRAGMENTS (100) + +/* This is heavily based on esound's code */ + +struct connection { + uint32_t index; + struct pa_protocol_esound *protocol; + struct pa_iochannel *io; + struct pa_client *client; + int authorized, swap_byte_order; + void *write_data; + size_t write_data_alloc, write_data_index, write_data_length; + void *read_data; + size_t read_data_alloc, read_data_length; + esd_proto_t request; + esd_client_state_t state; + struct pa_sink_input *sink_input; + struct pa_source_output *source_output; + struct pa_memblockq *input_memblockq, *output_memblockq; + void *fixed_source; + struct { + struct pa_memblock *current_memblock; + size_t memblock_index, fragment_size; + } playback; +}; + +struct pa_protocol_esound { + int public; + struct pa_module *module; + struct pa_core *core; + struct pa_socket_server *server; + struct pa_idxset *connections; + uint32_t sink_index, source_index; + unsigned n_player; + uint8_t esd_key[ESD_KEY_LEN]; +}; + +typedef struct proto_handler { + size_t data_length; + int (*proc)(struct connection *c, esd_proto_t request, const void *data, size_t length); + const char *description; +} esd_proto_handler_info_t; + +static void sink_input_drop_cb(struct pa_sink_input *i, size_t length); +static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk); +static void sink_input_kill_cb(struct pa_sink_input *i); +static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i); + +static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk); +static void source_output_kill_cb(struct pa_source_output *o); + +static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_play(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_get_latency(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_server_info(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const void *data, size_t length); + +/* the big map of protocol handler info */ +static struct proto_handler proto_map[ESD_PROTO_MAX] = { + { ESD_KEY_LEN + sizeof(int), esd_proto_connect, "connect" }, + { ESD_KEY_LEN + sizeof(int), NULL, "lock" }, + { ESD_KEY_LEN + sizeof(int), NULL, "unlock" }, + + { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_play, "stream play" }, + { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream rec" }, + { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream mon" }, + + { ESD_NAME_MAX + 3 * sizeof(int), NULL, "sample cache" }, + { sizeof(int), NULL, "sample free" }, + { sizeof(int), NULL, "sample play" }, + { sizeof(int), NULL, "sample loop" }, + { sizeof(int), NULL, "sample stop" }, + { -1, NULL, "TODO: sample kill" }, + + { ESD_KEY_LEN + sizeof(int), NULL, "standby" }, + { ESD_KEY_LEN + sizeof(int), NULL, "resume" }, + + { ESD_NAME_MAX, NULL, "sample getid" }, + { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" }, + + { sizeof(int), esd_proto_server_info, "server info" }, + { sizeof(int), esd_proto_all_info, "all info" }, + { -1, NULL, "TODO: subscribe" }, + { -1, NULL, "TODO: unsubscribe" }, + + { 3 * sizeof(int), esd_proto_stream_pan, "stream pan"}, + { 3 * sizeof(int), NULL, "sample pan" }, + + { sizeof(int), NULL, "standby mode" }, + { 0, esd_proto_get_latency, "get latency" } +}; + + +static void connection_free(struct connection *c) { + assert(c); + pa_idxset_remove_by_data(c->protocol->connections, c, NULL); + + if (c->state == ESD_STREAMING_DATA) + c->protocol->n_player--; + + pa_client_free(c->client); + + if (c->sink_input) + pa_sink_input_free(c->sink_input); + if (c->source_output) + pa_source_output_free(c->source_output); + if (c->input_memblockq) + pa_memblockq_free(c->input_memblockq); + if (c->output_memblockq) + pa_memblockq_free(c->output_memblockq); + + if (c->playback.current_memblock) + pa_memblock_unref(c->playback.current_memblock); + + free(c->read_data); + free(c->write_data); + + pa_iochannel_free(c->io); + + if (c->fixed_source) + c->protocol->core->mainloop->cancel_fixed(c->protocol->core->mainloop, c->fixed_source); + + free(c); +} + +static struct pa_sink* get_output_sink(struct pa_protocol_esound *p) { + struct pa_sink *s; + assert(p); + + if (!(s = pa_idxset_get_by_index(p->core->sinks, p->sink_index))) + s = pa_sink_get_default(p->core); + + p->sink_index = s ? s->index : PA_IDXSET_INVALID; + return s; +} + +static struct pa_source* get_input_source(struct pa_protocol_esound *p) { + struct pa_source *s; + assert(p); + + if (!(s = pa_idxset_get_by_index(p->core->sources, p->sink_index))) + s = pa_source_get_default(p->core); + + p->source_index = s ? s->index : PA_IDXSET_INVALID; + return s; +} + +static void* connection_write(struct connection *c, size_t length) { + size_t t, i; + assert(c); + + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); + c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); + + t = c->write_data_length+length; + + if (c->write_data_alloc < t) + c->write_data = realloc(c->write_data, c->write_data_alloc = t); + + assert(c->write_data); + + i = c->write_data_length; + c->write_data_length += length; + + return c->write_data+i; +} + +/*** esound commands ***/ + +static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length) { + uint32_t ekey; + int *ok; + assert(length == (ESD_KEY_LEN + sizeof(uint32_t))); + + if (!c->authorized) { + if (memcmp(data, c->protocol->esd_key, ESD_KEY_LEN) != 0) { + fprintf(stderr, __FILE__": kicked client with invalid authorization key.\n"); + return -1; + } + + c->authorized = 1; + } + + ekey = *(uint32_t*)(data+ESD_KEY_LEN); + if (ekey == ESD_ENDIAN_KEY) + c->swap_byte_order = 0; + else if (ekey == ESD_SWAP_ENDIAN_KEY) + c->swap_byte_order = 1; + else { + fprintf(stderr, __FILE__": client sent invalid endian key\n"); + return -1; + } + + ok = connection_write(c, sizeof(int)); + assert(ok); + *ok = 1; + return 0; +} + +static int esd_proto_stream_play(struct connection *c, esd_proto_t request, const void *data, size_t length) { + char name[ESD_NAME_MAX]; + int format, rate; + struct pa_sink *sink; + struct pa_sample_spec ss; + size_t l; + assert(c && length == (sizeof(int)*2+ESD_NAME_MAX)); + + format = maybe_swap_endian_32(c->swap_byte_order, *(int*)data); + rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); + + ss.rate = rate; + ss.channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; + ss.format = ((format & ESD_MASK_BITS) == ESD_BITS16) ? PA_SAMPLE_S16NE : PA_SAMPLE_U8; + + if (!pa_sample_spec_valid(&ss)) + return -1; + + if (!(sink = get_output_sink(c->protocol))) + return -1; + + strncpy(name, data + sizeof(int)*2, sizeof(name)); + name[sizeof(name)-1] = 0; + + pa_client_rename(c->client, name); + + assert(!c->input_memblockq); + + l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); + c->input_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&ss), l/2, l/PLAYBACK_BUFFER_FRAGMENTS); + assert(c->input_memblockq); + pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2); + c->playback.fragment_size = l/10; + + assert(!c->sink_input); + c->sink_input = pa_sink_input_new(sink, name, &ss); + assert(c->sink_input); + + c->sink_input->owner = c->protocol->module; + c->sink_input->client = c->client; + c->sink_input->peek = sink_input_peek_cb; + c->sink_input->drop = sink_input_drop_cb; + c->sink_input->kill = sink_input_kill_cb; + c->sink_input->get_latency = sink_input_get_latency_cb; + c->sink_input->userdata = c; + + c->state = ESD_STREAMING_DATA; + + c->protocol->n_player++; + + return 0; +} + +static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length) { + char name[ESD_NAME_MAX]; + int format, rate; + struct pa_source *source; + struct pa_sample_spec ss; + size_t l; + assert(c && length == (sizeof(int)*2+ESD_NAME_MAX)); + + format = maybe_swap_endian_32(c->swap_byte_order, *(int*)data); + rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); + + ss.rate = rate; + ss.channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; + ss.format = ((format & ESD_MASK_BITS) == ESD_BITS16) ? PA_SAMPLE_S16NE : PA_SAMPLE_U8; + + if (!pa_sample_spec_valid(&ss)) + return -1; + + if (request == ESD_PROTO_STREAM_MON) { + struct pa_sink* sink; + + if (!(sink = get_output_sink(c->protocol))) + return -1; + + if (!(source = sink->monitor_source)) + return -1; + } else { + assert(request == ESD_PROTO_STREAM_REC); + + if (!(source = get_input_source(c->protocol))) + return -1; + } + + strncpy(name, data + sizeof(int)*2, sizeof(name)); + name[sizeof(name)-1] = 0; + + pa_client_rename(c->client, name); + + assert(!c->output_memblockq); + + l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); + c->output_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&ss), 0, 0); + assert(c->output_memblockq); + pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); + + assert(!c->source_output); + c->source_output = pa_source_output_new(source, name, &ss); + assert(c->source_output); + + c->source_output->owner = c->protocol->module; + c->source_output->client = c->client; + c->source_output->push = source_output_push_cb; + c->source_output->kill = source_output_kill_cb; + c->source_output->userdata = c; + + c->state = ESD_STREAMING_DATA; + + c->protocol->n_player++; + + return 0; +} + +static int esd_proto_get_latency(struct connection *c, esd_proto_t request, const void *data, size_t length) { + struct pa_sink *sink; + int latency, *lag; + assert(c && !data && length == 0); + + if (!(sink = get_output_sink(c->protocol))) + latency = 0; + else { + float usec = pa_sink_get_latency(sink); + usec += PLAYBACK_BUFFER_SECONDS*1000000; /* A better estimation would be a good idea! */ + latency = (int) ((usec*44100)/1000000); + } + + lag = connection_write(c, sizeof(int)); + assert(lag); + *lag = c->swap_byte_order ? swap_endian_32(latency) : latency; + return 0; +} + +static int esd_proto_server_info(struct connection *c, esd_proto_t request, const void *data, size_t length) { + int rate = 44100, format = ESD_STEREO|ESD_BITS16; + int *response; + struct pa_sink *sink; + assert(c && data && length == sizeof(int)); + + if ((sink = get_output_sink(c->protocol))) { + rate = sink->sample_spec.rate; + format = (sink->sample_spec.format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16; + format |= (sink->sample_spec.channels >= 2) ? ESD_STEREO : ESD_MONO; + } + + response = connection_write(c, sizeof(int)*3); + assert(response); + *(response++) = 0; + *(response++) = maybe_swap_endian_32(c->swap_byte_order, rate); + *(response++) = maybe_swap_endian_32(c->swap_byte_order, format); + return 0; +} + +static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length) { + void *response; + size_t t, k, s; + struct connection *conn; + size_t index = PA_IDXSET_INVALID; + assert(c && data && length == sizeof(int)); + + if (esd_proto_server_info(c, request, data, length) < 0) + return -1; + + k = sizeof(int)*5+ESD_NAME_MAX; + s = sizeof(int)*6+ESD_NAME_MAX; + response = connection_write(c, (t = s+k*(c->protocol->n_player+1))); + assert(k); + + for (conn = pa_idxset_first(c->protocol->connections, &index); conn; conn = pa_idxset_next(c->protocol->connections, &index)) { + int format = ESD_BITS16 | ESD_STEREO, rate = 44100, volume = 0xFF; + + if (conn->state != ESD_STREAMING_DATA) + continue; + + assert(t >= s+k+k); + + if (conn->sink_input) { + rate = conn->sink_input->sample_spec.rate; + volume = (conn->sink_input->volume*0xFF)/0x100; + format = (conn->sink_input->sample_spec.format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16; + format |= (conn->sink_input->sample_spec.channels >= 2) ? ESD_STEREO : ESD_MONO; + } + + /* id */ + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (int) conn->index); + response += sizeof(int); + + /* name */ + assert(conn->client); + strncpy(response, conn->client->name, ESD_NAME_MAX); + response += ESD_NAME_MAX; + + /* rate */ + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, rate); + response += sizeof(int); + + /* left */ + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, volume); + response += sizeof(int); + + /*right*/ + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, volume); + response += sizeof(int); + + /*format*/ + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, format); + response += sizeof(int); + + t-= k; + } + + assert(t == s+k); + memset(response, 0, t); + return 0; +} + +static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const void *data, size_t length) { + int *ok; + uint32_t index, volume; + struct connection *conn; + assert(c && data && length == sizeof(int)*3); + + index = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *(int*)data); + volume = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); + volume = (volume*0x100)/0xFF; + + ok = connection_write(c, sizeof(int)); + assert(ok); + + if ((conn = pa_idxset_get_by_index(c->protocol->connections, index))) { + assert(conn->sink_input); + conn->sink_input->volume = volume; + *ok = 1; + } else + *ok = 0; + + return 0; +} + +/*** client callbacks ***/ + +static void client_kill_cb(struct pa_client *c) { + assert(c && c->userdata); + connection_free(c->userdata); +} + +/*** pa_iochannel callbacks ***/ + +static int do_read(struct connection *c) { + assert(c && c->io); + + if (c->state == ESD_NEXT_REQUEST) { + ssize_t r; + assert(c->read_data_length < sizeof(c->request)); + + if ((r = pa_iochannel_read(c->io, ((void*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { + fprintf(stderr, "protocol-esound.c: read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + return -1; + } + + if ((c->read_data_length+= r) >= sizeof(c->request)) { + struct proto_handler *handler; + + if (c->swap_byte_order) + c->request = swap_endian_32(c->request); + + if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) { + fprintf(stderr, "protocol-esound.c: recieved invalid request.\n"); + return -1; + } + + handler = proto_map+c->request; + + if (!handler->proc) { + fprintf(stderr, "protocol-sound.c: recieved unimplemented request.\n"); + return -1; + } + + if (handler->data_length == 0) { + c->read_data_length = 0; + + if (handler->proc(c, c->request, NULL, 0) < 0) + return -1; + + } else { + if (c->read_data_alloc < handler->data_length) + c->read_data = realloc(c->read_data, c->read_data_alloc = handler->data_length); + assert(c->read_data); + + c->state = ESD_NEEDS_REQDATA; + c->read_data_length = 0; + } + } + + } else if (c->state == ESD_NEEDS_REQDATA) { + ssize_t r; + struct proto_handler *handler = proto_map+c->request; + + assert(handler->proc); + + assert(c->read_data && c->read_data_length < handler->data_length); + + if ((r = pa_iochannel_read(c->io, c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { + fprintf(stderr, "protocol-esound.c: read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + return -1; + } + + if ((c->read_data_length+= r) >= handler->data_length) { + size_t l = c->read_data_length; + assert(handler->proc); + + c->state = ESD_NEXT_REQUEST; + c->read_data_length = 0; + + if (handler->proc(c, c->request, c->read_data, l) < 0) + return -1; + } + } else if (c->state == ESD_STREAMING_DATA && c->sink_input) { + struct pa_memchunk chunk; + ssize_t r; + size_t l; + + assert(c->input_memblockq); + + if (!(l = pa_memblockq_missing(c->input_memblockq))) + return 0; + + if (l > c->playback.fragment_size) + l = c->playback.fragment_size; + + if (c->playback.current_memblock) + if (c->playback.current_memblock->length - c->playback.memblock_index < l) { + pa_memblock_unref(c->playback.current_memblock); + c->playback.current_memblock = NULL; + c->playback.memblock_index = 0; + } + + if (!c->playback.current_memblock) { + c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2); + assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); + c->playback.memblock_index = 0; + } + + if ((r = pa_iochannel_read(c->io, c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { + fprintf(stderr, __FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + return -1; + } + + chunk.memblock = c->playback.current_memblock; + chunk.index = c->playback.memblock_index; + chunk.length = r; + assert(chunk.memblock); + + c->playback.memblock_index += r; + + assert(c->input_memblockq); + pa_memblockq_push_align(c->input_memblockq, &chunk, 0); + assert(c->sink_input); + pa_sink_notify(c->sink_input->sink); + + } + + return 0; +} + +static int do_write(struct connection *c) { + assert(c && c->io); + + if (c->write_data_length) { + ssize_t r; + + assert(c->write_data_index < c->write_data_length); + if ((r = pa_iochannel_write(c->io, c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { + fprintf(stderr, __FILE__": write() failed: %s\n", strerror(errno)); + return -1; + } + + if ((c->write_data_index +=r) >= c->write_data_length) + c->write_data_length = c->write_data_index = 0; + + } else if (c->state == ESD_STREAMING_DATA && c->source_output) { + struct pa_memchunk chunk; + ssize_t r; + + assert(c->output_memblockq); + if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) + return 0; + + assert(chunk.memblock && chunk.length); + + if ((r = pa_iochannel_write(c->io, chunk.memblock->data+chunk.index, chunk.length)) < 0) { + pa_memblock_unref(chunk.memblock); + fprintf(stderr, __FILE__": write(): %s\n", strerror(errno)); + return -1; + } + + pa_memblockq_drop(c->output_memblockq, r); + pa_memblock_unref(chunk.memblock); + } + + return 0; +} + +static void do_work(struct connection *c) { + assert(c); + + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); + c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 0); + + if (pa_iochannel_is_hungup(c->io)) + goto fail; + + if (pa_iochannel_is_writable(c->io)) + if (do_write(c) < 0) + goto fail; + + if (pa_iochannel_is_readable(c->io)) + if (do_read(c) < 0) + goto fail; + + return; + +fail: + connection_free(c); +} + +static void io_callback(struct pa_iochannel*io, void *userdata) { + struct connection *c = userdata; + assert(io && c && c->io == io); + + do_work(c); +} + +/*** fixed callback ***/ + +static void fixed_callback(struct pa_mainloop_api*a, void *id, void *userdata) { + struct connection *c = userdata; + assert(a && c && c->fixed_source == id); + + do_work(c); +} + +/*** sink_input callbacks ***/ + +static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk) { + struct connection*c; + assert(i && i->userdata && chunk); + c = i->userdata; + + if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) + return -1; + + return 0; +} + +static void sink_input_drop_cb(struct pa_sink_input *i, size_t length) { + struct connection*c = i->userdata; + assert(i && c && length); + + pa_memblockq_drop(c->input_memblockq, length); + + /* do something */ + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); + c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); +} + +static void sink_input_kill_cb(struct pa_sink_input *i) { + assert(i && i->userdata); + connection_free((struct connection *) i->userdata); +} + + +static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { + struct connection*c = i->userdata; + assert(i && c); + return pa_samples_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); +} + +/*** source_output callbacks ***/ + +static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk) { + struct connection *c = o->userdata; + assert(o && c && chunk); + + pa_memblockq_push(c->output_memblockq, chunk, 0); + + /* do something */ + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); + c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); +} + +static void source_output_kill_cb(struct pa_source_output *o) { + assert(o && o->userdata); + connection_free((struct connection *) o->userdata); +} + +/*** socket server callback ***/ + +static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { + struct connection *c; + char cname[256]; + assert(s && io && userdata); + + c = malloc(sizeof(struct connection)); + assert(c); + c->protocol = userdata; + c->io = io; + pa_iochannel_set_callback(c->io, io_callback, c); + + pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); + assert(c->protocol->core); + c->client = pa_client_new(c->protocol->core, "ESOUND", cname); + assert(c->client); + c->client->owner = c->protocol->module; + c->client->kill = client_kill_cb; + c->client->userdata = c; + + c->authorized = c->protocol->public; + c->swap_byte_order = 0; + + c->read_data_length = 0; + c->read_data = malloc(c->read_data_alloc = proto_map[ESD_PROTO_CONNECT].data_length); + assert(c->read_data); + + c->write_data_length = c->write_data_index = c->write_data_alloc = 0; + c->write_data = NULL; + + c->state = ESD_NEEDS_REQDATA; + c->request = ESD_PROTO_CONNECT; + + c->sink_input = NULL; + c->input_memblockq = NULL; + + c->source_output = NULL; + c->output_memblockq = NULL; + + c->playback.current_memblock = NULL; + c->playback.memblock_index = 0; + c->playback.fragment_size = 0; + + c->fixed_source = c->protocol->core->mainloop->source_fixed(c->protocol->core->mainloop, fixed_callback, c); + assert(c->fixed_source); + c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 0); + + pa_idxset_put(c->protocol->connections, c, &c->index); +} + +/*** entry points ***/ + +struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { + uint32_t source_index, sink_index; + struct pa_protocol_esound *p; + assert(core && server && ma); + + if (pa_modargs_get_source_index(ma, core, &source_index) < 0) { + fprintf(stderr, __FILE__": source does not exist.\n"); + return NULL; + } + + if (pa_modargs_get_sink_index(ma, core, &sink_index) < 0) { + fprintf(stderr, __FILE__": sink does not exist.\n"); + return NULL; + } + p = malloc(sizeof(struct pa_protocol_esound)); + assert(p); + + if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", DEFAULT_COOKIE_FILE), p->esd_key, sizeof(p->esd_key)) < 0) { + free(p); + return NULL; + } + + p->module = m; + p->public = 0; + p->server = server; + pa_socket_server_set_callback(p->server, on_connection, p); + p->core = core; + p->connections = pa_idxset_new(NULL, NULL); + assert(p->connections); + p->sink_index = sink_index; + p->source_index = source_index; + p->n_player = 0; + + return p; +} + +void pa_protocol_esound_free(struct pa_protocol_esound *p) { + struct connection *c; + assert(p); + + while ((c = pa_idxset_first(p->connections, NULL))) + connection_free(c); + + pa_idxset_free(p->connections, NULL, NULL); + pa_socket_server_free(p->server); + free(p); +} diff --git a/polyp/protocol-esound.h b/polyp/protocol-esound.h new file mode 100644 index 00000000..b2bdd31b --- /dev/null +++ b/polyp/protocol-esound.h @@ -0,0 +1,35 @@ +#ifndef fooprotocolesoundhfoo +#define fooprotocolesoundhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" +#include "socket-server.h" +#include "module.h" +#include "modargs.h" + +struct pa_protocol_esound; + +struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma); +void pa_protocol_esound_free(struct pa_protocol_esound *p); + +#endif diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c new file mode 100644 index 00000000..83c910d1 --- /dev/null +++ b/polyp/protocol-native.c @@ -0,0 +1,863 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "protocol-native.h" +#include "native-common.h" +#include "packet.h" +#include "client.h" +#include "source-output.h" +#include "sink-input.h" +#include "pstream.h" +#include "tagstruct.h" +#include "pdispatch.h" +#include "pstream-util.h" +#include "authkey.h" +#include "namereg.h" + +struct connection; +struct pa_protocol_native; + +struct record_stream { + struct connection *connection; + uint32_t index; + struct pa_source_output *source_output; + struct pa_memblockq *memblockq; + size_t fragment_size; +}; + +struct playback_stream { + struct connection *connection; + uint32_t index; + struct pa_sink_input *sink_input; + struct pa_memblockq *memblockq; + size_t requested_bytes; + int drain_request; + uint32_t drain_tag; +}; + +struct connection { + int authorized; + struct pa_protocol_native *protocol; + struct pa_client *client; + struct pa_pstream *pstream; + struct pa_pdispatch *pdispatch; + struct pa_idxset *record_streams, *playback_streams; + uint32_t rrobin_index; +}; + +struct pa_protocol_native { + struct pa_module *module; + int public; + struct pa_core *core; + struct pa_socket_server *server; + struct pa_idxset *connections; + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; +}; + +static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk); +static void sink_input_drop_cb(struct pa_sink_input *i, size_t length); +static void sink_input_kill_cb(struct pa_sink_input *i); +static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i); + +static void request_bytes(struct playback_stream*s); + +static void source_output_kill_cb(struct pa_source_output *o); +static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk); + +static void command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_delete_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_delete_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); + +static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = { NULL }, + [PA_COMMAND_TIMEOUT] = { NULL }, + [PA_COMMAND_REPLY] = { NULL }, + [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { command_create_playback_stream }, + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { command_delete_playback_stream }, + [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = { command_drain_playback_stream }, + [PA_COMMAND_CREATE_RECORD_STREAM] = { command_create_record_stream }, + [PA_COMMAND_DELETE_RECORD_STREAM] = { command_delete_record_stream }, + [PA_COMMAND_AUTH] = { command_auth }, + [PA_COMMAND_REQUEST] = { NULL }, + [PA_COMMAND_EXIT] = { command_exit }, + [PA_COMMAND_SET_NAME] = { command_set_name }, + [PA_COMMAND_LOOKUP_SINK] = { command_lookup }, + [PA_COMMAND_LOOKUP_SOURCE] = { command_lookup }, + [PA_COMMAND_STAT] = { command_stat }, + [PA_COMMAND_GET_PLAYBACK_LATENCY] = { command_get_playback_latency }, +}; + +/* structure management */ + +static struct record_stream* record_stream_new(struct connection *c, struct pa_source *source, struct pa_sample_spec *ss, const char *name, size_t maxlength, size_t fragment_size) { + struct record_stream *s; + struct pa_source_output *source_output; + size_t base; + assert(c && source && ss && name && maxlength); + + if (!(source_output = pa_source_output_new(source, name, ss))) + return NULL; + + s = malloc(sizeof(struct record_stream)); + assert(s); + s->connection = c; + s->source_output = source_output; + s->source_output->push = source_output_push_cb; + s->source_output->kill = source_output_kill_cb; + s->source_output->userdata = s; + s->source_output->owner = c->protocol->module; + s->source_output->client = c->client; + + s->memblockq = pa_memblockq_new(maxlength, 0, base = pa_sample_size(ss), 0, 0); + assert(s->memblockq); + + s->fragment_size = (fragment_size/base)*base; + if (!s->fragment_size) + s->fragment_size = base; + + pa_idxset_put(c->record_streams, s, &s->index); + return s; +} + +static void record_stream_free(struct record_stream* r) { + assert(r && r->connection); + + pa_idxset_remove_by_data(r->connection->record_streams, r, NULL); + pa_source_output_free(r->source_output); + pa_memblockq_free(r->memblockq); + free(r); +} + +static struct playback_stream* playback_stream_new(struct connection *c, struct pa_sink *sink, struct pa_sample_spec *ss, const char *name, + size_t maxlength, + size_t tlength, + size_t prebuf, + size_t minreq) { + struct playback_stream *s; + struct pa_sink_input *sink_input; + assert(c && sink && ss && name && maxlength); + + if (!(sink_input = pa_sink_input_new(sink, name, ss))) + return NULL; + + s = malloc(sizeof(struct playback_stream)); + assert (s); + s->connection = c; + s->sink_input = sink_input; + + s->sink_input->peek = sink_input_peek_cb; + s->sink_input->drop = sink_input_drop_cb; + s->sink_input->kill = sink_input_kill_cb; + s->sink_input->get_latency = sink_input_get_latency_cb; + s->sink_input->userdata = s; + s->sink_input->owner = c->protocol->module; + s->sink_input->client = c->client; + + s->memblockq = pa_memblockq_new(maxlength, tlength, pa_sample_size(ss), prebuf, minreq); + assert(s->memblockq); + + s->requested_bytes = 0; + s->drain_request = 0; + + pa_idxset_put(c->playback_streams, s, &s->index); + return s; +} + +static void playback_stream_free(struct playback_stream* p) { + assert(p && p->connection); + + if (p->drain_request) + pa_pstream_send_error(p->connection->pstream, p->drain_tag, PA_ERROR_NOENTITY); + + pa_idxset_remove_by_data(p->connection->playback_streams, p, NULL); + pa_sink_input_free(p->sink_input); + pa_memblockq_free(p->memblockq); + free(p); +} + +static void connection_free(struct connection *c) { + struct record_stream *r; + struct playback_stream *p; + assert(c && c->protocol); + + pa_idxset_remove_by_data(c->protocol->connections, c, NULL); + while ((r = pa_idxset_first(c->record_streams, NULL))) + record_stream_free(r); + pa_idxset_free(c->record_streams, NULL, NULL); + + while ((p = pa_idxset_first(c->playback_streams, NULL))) + playback_stream_free(p); + pa_idxset_free(c->playback_streams, NULL, NULL); + + pa_pdispatch_free(c->pdispatch); + pa_pstream_free(c->pstream); + pa_client_free(c->client); + free(c); +} + +static void request_bytes(struct playback_stream *s) { + struct pa_tagstruct *t; + size_t l; + assert(s); + + if (!(l = pa_memblockq_missing(s->memblockq))) + return; + + if (l <= s->requested_bytes) + return; + + l -= s->requested_bytes; + + if (l < pa_memblockq_get_minreq(s->memblockq)) + return; + + s->requested_bytes += l; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_REQUEST); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, s->index); + pa_tagstruct_putu32(t, l); + pa_pstream_send_tagstruct(s->connection->pstream, t); + + /*fprintf(stderr, "Requesting %u bytes\n", l);*/ +} + +static void send_memblock(struct connection *c) { + uint32_t start; + struct record_stream *r; + + start = PA_IDXSET_INVALID; + for (;;) { + struct pa_memchunk chunk; + + if (!(r = pa_idxset_rrobin(c->record_streams, &c->rrobin_index))) + return; + + if (start == PA_IDXSET_INVALID) + start = c->rrobin_index; + else if (start == c->rrobin_index) + return; + + if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) { + if (chunk.length > r->fragment_size) + chunk.length = r->fragment_size; + + pa_pstream_send_memblock(c->pstream, r->index, 0, &chunk); + pa_memblockq_drop(r->memblockq, chunk.length); + pa_memblock_unref(chunk.memblock); + + return; + } + } +} + +static void send_playback_stream_killed(struct playback_stream *p) { + struct pa_tagstruct *t; + assert(p); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, p->index); + pa_pstream_send_tagstruct(p->connection->pstream, t); +} + +static void send_record_stream_killed(struct record_stream *r) { + struct pa_tagstruct *t; + assert(r); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, r->index); + pa_pstream_send_tagstruct(r->connection->pstream, t); +} + + +/*** sinkinput callbacks ***/ + +static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk) { + struct playback_stream *s; + assert(i && i->userdata && chunk); + s = i->userdata; + + if (pa_memblockq_peek(s->memblockq, chunk) < 0) + return -1; + + return 0; +} + +static void sink_input_drop_cb(struct pa_sink_input *i, size_t length) { + struct playback_stream *s; + assert(i && i->userdata && length); + s = i->userdata; + + pa_memblockq_drop(s->memblockq, length); + request_bytes(s); + + if (s->drain_request && !pa_memblockq_is_readable(s->memblockq)) { + pa_pstream_send_simple_ack(s->connection->pstream, s->drain_tag); + s->drain_request = 0; + } +} + +static void sink_input_kill_cb(struct pa_sink_input *i) { + assert(i && i->userdata); + send_playback_stream_killed((struct playback_stream *) i->userdata); + playback_stream_free((struct playback_stream *) i->userdata); +} + +static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { + struct playback_stream *s; + assert(i && i->userdata); + s = i->userdata; + + return pa_samples_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec); +} + +/*** source_output callbacks ***/ + +static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk) { + struct record_stream *s; + assert(o && o->userdata && chunk); + s = o->userdata; + + pa_memblockq_push(s->memblockq, chunk, 0); + if (!pa_pstream_is_pending(s->connection->pstream)) + send_memblock(s->connection); +} + +static void source_output_kill_cb(struct pa_source_output *o) { + assert(o && o->userdata); + send_record_stream_killed((struct record_stream *) o->userdata); + record_stream_free((struct record_stream *) o->userdata); +} + +/*** pdispatch callbacks ***/ + +static void protocol_error(struct connection *c) { + fprintf(stderr, __FILE__": protocol error, kicking client\n"); + connection_free(c); +} + +static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + struct playback_stream *s; + size_t maxlength, tlength, prebuf, minreq; + uint32_t sink_index; + const char *name; + struct pa_sample_spec ss; + struct pa_tagstruct *reply; + struct pa_sink *sink; + assert(c && t && c->protocol && c->protocol->core); + + if (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_getu32(t, &sink_index) < 0 || + pa_tagstruct_getu32(t, &maxlength) < 0 || + pa_tagstruct_getu32(t, &tlength) < 0 || + pa_tagstruct_getu32(t, &prebuf) < 0 || + pa_tagstruct_getu32(t, &minreq) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (sink_index == (uint32_t) -1) + sink = pa_sink_get_default(c->protocol->core); + else + sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); + + if (!sink) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + if (!(s = playback_stream_new(c, sink, &ss, name, maxlength, tlength, prebuf, minreq))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, s->index); + assert(s->sink_input); + pa_tagstruct_putu32(reply, s->sink_input->index); + pa_pstream_send_tagstruct(c->pstream, reply); + request_bytes(s); +} + +static void command_delete_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t channel; + struct playback_stream *s; + assert(c && t); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->playback_streams, channel))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + return; + } + + playback_stream_free(s); + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + struct record_stream *s; + size_t maxlength, fragment_size; + uint32_t source_index; + const char *name; + struct pa_sample_spec ss; + struct pa_tagstruct *reply; + struct pa_source *source; + assert(c && t && c->protocol && c->protocol->core); + + if (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_getu32(t, &source_index) < 0 || + pa_tagstruct_getu32(t, &maxlength) < 0 || + pa_tagstruct_getu32(t, &fragment_size) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (source_index == (uint32_t) -1) + source = pa_source_get_default(c->protocol->core); + else + source = pa_idxset_get_by_index(c->protocol->core->sources, source_index); + + if (!source) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + if (!(s = record_stream_new(c, source, &ss, name, maxlength, fragment_size))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, s->index); + assert(s->source_output); + pa_tagstruct_putu32(reply, s->source_output->index); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_delete_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t channel; + struct record_stream *s; + assert(c && t); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + return; + } + + record_stream_free(s); + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + assert(c && t); + + if (!pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop); + c->protocol->core->mainloop->quit(c->protocol->core->mainloop, 0); + pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */ + return; +} + +static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const void*cookie; + assert(c && t); + + if (pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) != 0) { + fprintf(stderr, "protocol-native.c: Denied access to client with invalid authorization key.\n"); + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + c->authorized = 1; + pa_pstream_send_simple_ack(c->pstream, tag); + return; +} + +static void command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const char *name; + assert(c && t); + + if (pa_tagstruct_gets(t, &name) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + pa_client_rename(c->client, name); + pa_pstream_send_simple_ack(c->pstream, tag); + return; +} + +static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const char *name; + uint32_t index = PA_IDXSET_INVALID; + assert(c && t); + + if (pa_tagstruct_gets(t, &name) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (command == PA_COMMAND_LOOKUP_SINK) { + struct pa_sink *sink; + if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK))) + index = sink->index; + } else { + struct pa_source *source; + assert(command == PA_COMMAND_LOOKUP_SOURCE); + if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE))) + index = source->index; + } + + if (index == PA_IDXSET_INVALID) + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + else { + struct pa_tagstruct *reply; + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, index); + pa_pstream_send_tagstruct(c->pstream, reply); + } +} + +static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t index; + struct playback_stream *s; + assert(c && t); + + if (pa_tagstruct_getu32(t, &index) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->playback_streams, index))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + s->drain_request = 0; + + if (!pa_memblockq_is_readable(s->memblockq)) + pa_pstream_send_simple_ack(c->pstream, tag); + else { + s->drain_request = 1; + s->drain_tag = tag; + } +} + +static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + assert(c && t); + struct pa_tagstruct *reply; + + if (!pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, pa_memblock_get_count()); + pa_tagstruct_putu32(reply, pa_memblock_get_total()); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + assert(c && t); + struct pa_tagstruct *reply; + struct playback_stream *s; + uint32_t index, latency; + + if (pa_tagstruct_getu32(t, &index) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->playback_streams, index))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + latency = pa_sink_input_get_latency(s->sink_input); + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, latency); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +/*** pstream callbacks ***/ + +static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { + struct connection *c = userdata; + assert(p && packet && packet->data && c); + + if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { + fprintf(stderr, "protocol-native: invalid packet.\n"); + connection_free(c); + } +} + +static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { + struct connection *c = userdata; + struct playback_stream *stream; + assert(p && chunk && userdata); + + if (!(stream = pa_idxset_get_by_index(c->playback_streams, channel))) { + fprintf(stderr, "protocol-native: client sent block for invalid stream.\n"); + connection_free(c); + return; + } + + if (chunk->length >= stream->requested_bytes) + stream->requested_bytes = 0; + else + stream->requested_bytes -= chunk->length; + + pa_memblockq_push_align(stream->memblockq, chunk, delta); + assert(stream->sink_input); + pa_sink_notify(stream->sink_input->sink); + + /*fprintf(stderr, "Recieved %u bytes.\n", chunk->length);*/ +} + +static void pstream_die_callback(struct pa_pstream *p, void *userdata) { + struct connection *c = userdata; + assert(p && c); + connection_free(c); + + fprintf(stderr, "protocol-native: connection died.\n"); +} + + +static void pstream_drain_callback(struct pa_pstream *p, void *userdata) { + struct connection *c = userdata; + assert(p && c); + + send_memblock(c); +} + +/*** client callbacks ***/ + +static void client_kill_cb(struct pa_client *c) { + assert(c && c->userdata); + connection_free(c->userdata); +} + +/*** socket server callbacks ***/ + +static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { + struct pa_protocol_native *p = userdata; + struct connection *c; + assert(s && io && p); + + c = malloc(sizeof(struct connection)); + assert(c); + c->authorized = p->public; + c->protocol = p; + assert(p->core); + c->client = pa_client_new(p->core, "NATIVE", "Client"); + assert(c->client); + c->client->kill = client_kill_cb; + c->client->userdata = c; + c->client->owner = p->module; + + c->pstream = pa_pstream_new(p->core->mainloop, io); + assert(c->pstream); + + pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); + pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); + pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); + pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); + + c->pdispatch = pa_pdispatch_new(p->core->mainloop, command_table, PA_COMMAND_MAX); + assert(c->pdispatch); + + c->record_streams = pa_idxset_new(NULL, NULL); + c->playback_streams = pa_idxset_new(NULL, NULL); + assert(c->record_streams && c->playback_streams); + + c->rrobin_index = PA_IDXSET_INVALID; + + pa_idxset_put(p->connections, c, NULL); +} + +/*** module entry points ***/ + +struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { + struct pa_protocol_native *p; + uint32_t public; + assert(core && server && ma); + + if (pa_modargs_get_value_u32(ma, "public", &public) < 0) { + fprintf(stderr, __FILE__": public= expects numeric argument.\n"); + return NULL; + } + + p = malloc(sizeof(struct pa_protocol_native)); + assert(p); + + if (pa_authkey_load_from_home(pa_modargs_get_value(ma, "cookie", PA_NATIVE_COOKIE_FILE), p->auth_cookie, sizeof(p->auth_cookie)) < 0) { + free(p); + return NULL; + } + + p->module = m; + p->public = public; + p->server = server; + p->core = core; + p->connections = pa_idxset_new(NULL, NULL); + assert(p->connections); + + pa_socket_server_set_callback(p->server, on_connection, p); + + return p; +} + +void pa_protocol_native_free(struct pa_protocol_native *p) { + struct connection *c; + assert(p); + + while ((c = pa_idxset_first(p->connections, NULL))) + connection_free(c); + pa_idxset_free(p->connections, NULL, NULL); + pa_socket_server_free(p->server); + free(p); +} diff --git a/polyp/protocol-native.h b/polyp/protocol-native.h new file mode 100644 index 00000000..3d9fdde1 --- /dev/null +++ b/polyp/protocol-native.h @@ -0,0 +1,35 @@ +#ifndef fooprotocolnativehfoo +#define fooprotocolnativehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" +#include "socket-server.h" +#include "module.h" +#include "modargs.h" + +struct pa_protocol_native; + +struct pa_protocol_native* pa_protocol_native_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma); +void pa_protocol_native_free(struct pa_protocol_native *n); + +#endif diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c new file mode 100644 index 00000000..3a52e311 --- /dev/null +++ b/polyp/protocol-simple.c @@ -0,0 +1,444 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "sink-input.h" +#include "source-output.h" +#include "protocol-simple.h" +#include "client.h" +#include "sample-util.h" +#include "namereg.h" + +struct connection { + struct pa_protocol_simple *protocol; + struct pa_iochannel *io; + struct pa_sink_input *sink_input; + struct pa_source_output *source_output; + struct pa_client *client; + struct pa_memblockq *input_memblockq, *output_memblockq; + void *fixed_source; + + struct { + struct pa_memblock *current_memblock; + size_t memblock_index, fragment_size; + } playback; +}; + +struct pa_protocol_simple { + struct pa_module *module; + struct pa_core *core; + struct pa_socket_server*server; + struct pa_idxset *connections; + enum { + RECORD = 1, + PLAYBACK = 2, + DUPLEX = 3 + } mode; + struct pa_sample_spec sample_spec; + uint32_t sink_index, source_index; +}; + +#define PLAYBACK_BUFFER_SECONDS (.5) +#define PLAYBACK_BUFFER_FRAGMENTS (10) +#define RECORD_BUFFER_SECONDS (5) +#define RECORD_BUFFER_FRAGMENTS (100) + +static void connection_free(struct connection *c) { + assert(c); + + pa_idxset_remove_by_data(c->protocol->connections, c, NULL); + + if (c->playback.current_memblock) + pa_memblock_unref(c->playback.current_memblock); + if (c->sink_input) + pa_sink_input_free(c->sink_input); + if (c->source_output) + pa_source_output_free(c->source_output); + if (c->client) + pa_client_free(c->client); + if (c->io) + pa_iochannel_free(c->io); + if (c->input_memblockq) + pa_memblockq_free(c->input_memblockq); + if (c->output_memblockq) + pa_memblockq_free(c->output_memblockq); + if (c->fixed_source) + c->protocol->core->mainloop->cancel_fixed(c->protocol->core->mainloop, c->fixed_source); + free(c); +} + +static int do_read(struct connection *c) { + struct pa_memchunk chunk; + ssize_t r; + size_t l; + + if (!c->sink_input || !(l = pa_memblockq_missing(c->input_memblockq))) + return 0; + + if (l > c->playback.fragment_size) + l = c->playback.fragment_size; + + if (c->playback.current_memblock) + if (c->playback.current_memblock->length - c->playback.memblock_index < l) { + pa_memblock_unref(c->playback.current_memblock); + c->playback.current_memblock = NULL; + c->playback.memblock_index = 0; + } + + if (!c->playback.current_memblock) { + c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2); + assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); + c->playback.memblock_index = 0; + } + + if ((r = pa_iochannel_read(c->io, c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { + fprintf(stderr, __FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + return -1; + } + + chunk.memblock = c->playback.current_memblock; + chunk.index = c->playback.memblock_index; + chunk.length = r; + assert(chunk.memblock); + + c->playback.memblock_index += r; + + assert(c->input_memblockq); + pa_memblockq_push_align(c->input_memblockq, &chunk, 0); + assert(c->sink_input); + pa_sink_notify(c->sink_input->sink); + + return 0; +} + +static int do_write(struct connection *c) { + struct pa_memchunk chunk; + ssize_t r; + + if (!c->source_output) + return 0; + + assert(c->output_memblockq); + if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) + return 0; + + assert(chunk.memblock && chunk.length); + + if ((r = pa_iochannel_write(c->io, chunk.memblock->data+chunk.index, chunk.length)) < 0) { + pa_memblock_unref(chunk.memblock); + fprintf(stderr, "write(): %s\n", strerror(errno)); + return -1; + } + + pa_memblockq_drop(c->output_memblockq, r); + pa_memblock_unref(chunk.memblock); + + return 0; +} + + +static void do_work(struct connection *c) { + assert(c); + + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); + c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 0); + + if (pa_iochannel_is_hungup(c->io)) + goto fail; + + if (pa_iochannel_is_writable(c->io)) + if (do_write(c) < 0) + goto fail; + + if (pa_iochannel_is_readable(c->io)) + if (do_read(c) < 0) + goto fail; + + return; + +fail: + connection_free(c); +} + +/*** sink_input callbacks ***/ + +static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk) { + struct connection*c; + assert(i && i->userdata && chunk); + c = i->userdata; + + if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) + return -1; + + return 0; +} + +static void sink_input_drop_cb(struct pa_sink_input *i, size_t length) { + struct connection*c = i->userdata; + assert(i && c && length); + + pa_memblockq_drop(c->input_memblockq, length); + + /* do something */ + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); + c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); +} + +static void sink_input_kill_cb(struct pa_sink_input *i) { + assert(i && i->userdata); + connection_free((struct connection *) i->userdata); +} + + +static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { + struct connection*c = i->userdata; + assert(i && c); + return pa_samples_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); +} + +/*** source_output callbacks ***/ + +static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk) { + struct connection *c = o->userdata; + assert(o && c && chunk); + + pa_memblockq_push(c->output_memblockq, chunk, 0); + + /* do something */ + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); + c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); +} + +static void source_output_kill_cb(struct pa_source_output *o) { + assert(o && o->userdata); + connection_free((struct connection *) o->userdata); +} + +/*** client callbacks ***/ + +static void client_kill_cb(struct pa_client *c) { + assert(c && c->userdata); + connection_free((struct connection *) c->userdata); +} + +/*** pa_iochannel callbacks ***/ + +static void io_callback(struct pa_iochannel*io, void *userdata) { + struct connection *c = userdata; + assert(io && c && c->io == io); + + do_work(c); +} + +/*** fixed callback ***/ + +static void fixed_callback(struct pa_mainloop_api*a, void *id, void *userdata) { + struct connection *c = userdata; + assert(a && c && c->fixed_source == id); + + do_work(c); +} + +/*** socket_server callbacks ***/ + +static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { + struct pa_protocol_simple *p = userdata; + struct connection *c = NULL; + char cname[256]; + assert(s && io && p); + + c = malloc(sizeof(struct connection)); + assert(c); + c->io = io; + c->sink_input = NULL; + c->source_output = NULL; + c->fixed_source = NULL; + c->input_memblockq = c->output_memblockq = NULL; + c->protocol = p; + c->playback.current_memblock = NULL; + c->playback.memblock_index = 0; + c->playback.fragment_size = 0; + + pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); + c->client = pa_client_new(p->core, "SIMPLE", cname); + assert(c->client); + c->client->owner = p->module; + c->client->kill = client_kill_cb; + c->client->userdata = c; + + if (p->mode & PLAYBACK) { + struct pa_sink *sink; + size_t l; + + if (!(sink = pa_idxset_get_by_index(p->core->sinks, p->sink_index))) + if (!(sink = pa_sink_get_default(p->core))) { + fprintf(stderr, "Failed to get sink.\n"); + goto fail; + } + + c->sink_input = pa_sink_input_new(sink, c->client->name, &p->sample_spec); + if (!c->sink_input) { + fprintf(stderr, "Failed to create sink input.\n"); + goto fail; + } + c->sink_input->owner = p->module; + c->sink_input->client = c->client; + + c->sink_input->peek = sink_input_peek_cb; + c->sink_input->drop = sink_input_drop_cb; + c->sink_input->kill = sink_input_kill_cb; + c->sink_input->get_latency = sink_input_get_latency_cb; + c->sink_input->userdata = c; + + l = (size_t) (pa_bytes_per_second(&p->sample_spec)*PLAYBACK_BUFFER_SECONDS); + c->input_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&p->sample_spec), l/2, l/PLAYBACK_BUFFER_FRAGMENTS); + assert(c->input_memblockq); + pa_iochannel_socket_set_rcvbuf(io, l/PLAYBACK_BUFFER_FRAGMENTS*5); + c->playback.fragment_size = l/10; + } + + if (p->mode & RECORD) { + struct pa_source *source; + size_t l; + + if (!(source = pa_idxset_get_by_index(p->core->sources, p->source_index))) + if (!(source = pa_source_get_default(p->core))) { + fprintf(stderr, "Failed to get source.\n"); + goto fail; + } + + c->source_output = pa_source_output_new(source, c->client->name, &p->sample_spec); + if (!c->source_output) { + fprintf(stderr, "Failed to create source output.\n"); + goto fail; + } + c->source_output->owner = p->module; + c->source_output->client = c->client; + + c->source_output->push = source_output_push_cb; + c->source_output->kill = source_output_kill_cb; + c->source_output->userdata = c; + + l = (size_t) (pa_bytes_per_second(&p->sample_spec)*RECORD_BUFFER_SECONDS); + c->output_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&p->sample_spec), 0, 0); + pa_iochannel_socket_set_sndbuf(io, l/RECORD_BUFFER_FRAGMENTS*2); + } + + pa_iochannel_set_callback(c->io, io_callback, c); + pa_idxset_put(p->connections, c, NULL); + + c->fixed_source = p->core->mainloop->source_fixed(p->core->mainloop, fixed_callback, c); + assert(c->fixed_source); + p->core->mainloop->enable_fixed(p->core->mainloop, c->fixed_source, 0); + + return; + +fail: + if (c) + connection_free(c); +} + +struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { + struct pa_protocol_simple* p = NULL; + uint32_t enable; + assert(core && server && ma); + + p = malloc(sizeof(struct pa_protocol_simple)); + assert(p); + memset(p, 0, sizeof(struct pa_protocol_simple)); + + p->module = m; + p->core = core; + p->server = server; + p->connections = pa_idxset_new(NULL, NULL); + + p->sample_spec = core->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &p->sample_spec) < 0) { + fprintf(stderr, "Failed to parse sample type specification.\n"); + goto fail; + } + + if (pa_modargs_get_source_index(ma, core, &p->source_index) < 0) { + fprintf(stderr, __FILE__": source does not exist.\n"); + goto fail; + } + + if (pa_modargs_get_sink_index(ma, core, &p->sink_index) < 0) { + fprintf(stderr, __FILE__": sink does not exist.\n"); + goto fail; + } + + enable = 0; + if (pa_modargs_get_value_u32(ma, "record", &enable) < 0) { + fprintf(stderr, __FILE__": record= expects a numeric argument.\n"); + goto fail; + } + p->mode = enable ? RECORD : 0; + + enable = 1; + if (pa_modargs_get_value_u32(ma, "playback", &enable) < 0) { + fprintf(stderr, __FILE__": playback= expects a numeric argument.\n"); + goto fail; + } + p->mode |= enable ? PLAYBACK : 0; + + if ((p->mode & (RECORD|PLAYBACK)) == 0) { + fprintf(stderr, __FILE__": neither playback nor recording enabled for protocol.\n"); + goto fail; + } + + pa_socket_server_set_callback(p->server, on_connection, p); + + return p; + +fail: + if (p) + pa_protocol_simple_free(p); + return NULL; +} + + +void pa_protocol_simple_free(struct pa_protocol_simple *p) { + struct connection *c; + assert(p); + + if (p->connections) { + while((c = pa_idxset_first(p->connections, NULL))) + connection_free(c); + + pa_idxset_free(p->connections, NULL, NULL); + } + + if (p->server) + pa_socket_server_free(p->server); + free(p); +} + diff --git a/polyp/protocol-simple.h b/polyp/protocol-simple.h new file mode 100644 index 00000000..0fc1e19d --- /dev/null +++ b/polyp/protocol-simple.h @@ -0,0 +1,35 @@ +#ifndef fooprotocolsimplehfoo +#define fooprotocolsimplehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "socket-server.h" +#include "module.h" +#include "core.h" +#include "modargs.h" + +struct pa_protocol_simple; + +struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma); +void pa_protocol_simple_free(struct pa_protocol_simple *n); + +#endif diff --git a/polyp/pstream-util.c b/polyp/pstream-util.c new file mode 100644 index 00000000..3957e643 --- /dev/null +++ b/polyp/pstream-util.c @@ -0,0 +1,60 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "native-common.h" +#include "pstream-util.h" + +void pa_pstream_send_tagstruct(struct pa_pstream *p, struct pa_tagstruct *t) { + size_t length; + uint8_t *data; + struct pa_packet *packet; + assert(p && t); + + data = pa_tagstruct_free_data(t, &length); + assert(data && length); + packet = pa_packet_new_dynamic(data, length); + assert(packet); + pa_pstream_send_packet(p, packet); + pa_packet_unref(packet); +} + +void pa_pstream_send_error(struct pa_pstream *p, uint32_t tag, uint32_t error) { + struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_ERROR); + pa_tagstruct_putu32(t, tag); + pa_tagstruct_putu32(t, error); + pa_pstream_send_tagstruct(p, t); +} + +void pa_pstream_send_simple_ack(struct pa_pstream *p, uint32_t tag) { + struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_REPLY); + pa_tagstruct_putu32(t, tag); + pa_pstream_send_tagstruct(p, t); +} diff --git a/polyp/pstream-util.h b/polyp/pstream-util.h new file mode 100644 index 00000000..b3c89eb0 --- /dev/null +++ b/polyp/pstream-util.h @@ -0,0 +1,35 @@ +#ifndef foopstreamutilhfoo +#define foopstreamutilhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include "pstream.h" +#include "tagstruct.h" + +/* The tagstruct is freed!*/ +void pa_pstream_send_tagstruct(struct pa_pstream *p, struct pa_tagstruct *t); + +void pa_pstream_send_error(struct pa_pstream *p, uint32_t tag, uint32_t error); +void pa_pstream_send_simple_ack(struct pa_pstream *p, uint32_t tag); + +#endif diff --git a/polyp/pstream.c b/polyp/pstream.c new file mode 100644 index 00000000..3076b776 --- /dev/null +++ b/polyp/pstream.c @@ -0,0 +1,457 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "pstream.h" +#include "queue.h" + +enum pa_pstream_descriptor_index { + PA_PSTREAM_DESCRIPTOR_LENGTH, + PA_PSTREAM_DESCRIPTOR_CHANNEL, + PA_PSTREAM_DESCRIPTOR_DELTA, + PA_PSTREAM_DESCRIPTOR_MAX +}; + +typedef uint32_t pa_pstream_descriptor[PA_PSTREAM_DESCRIPTOR_MAX]; + +#define PA_PSTREAM_DESCRIPTOR_SIZE (PA_PSTREAM_DESCRIPTOR_MAX*sizeof(uint32_t)) +#define FRAME_SIZE_MAX (1024*64) + +struct item_info { + enum { PA_PSTREAM_ITEM_PACKET, PA_PSTREAM_ITEM_MEMBLOCK } type; + + /* memblock info */ + struct pa_memchunk chunk; + uint32_t channel; + int32_t delta; + + /* packet info */ + struct pa_packet *packet; +}; + +struct pa_pstream { + struct pa_mainloop_api *mainloop; + struct mainloop_source *mainloop_source; + struct pa_iochannel *io; + struct pa_queue *send_queue; + + int in_use, shall_free; + + int dead; + void (*die_callback) (struct pa_pstream *p, void *userdata); + void *die_callback_userdata; + + struct { + struct item_info* current; + pa_pstream_descriptor descriptor; + void *data; + size_t index; + } write; + + struct { + struct pa_memblock *memblock; + struct pa_packet *packet; + pa_pstream_descriptor descriptor; + void *data; + size_t index; + } read; + + void (*recieve_packet_callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata); + void *recieve_packet_callback_userdata; + + void (*recieve_memblock_callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata); + void *recieve_memblock_callback_userdata; + + void (*drain_callback)(struct pa_pstream *p, void *userdata); + void *drain_userdata; +}; + +static void do_write(struct pa_pstream *p); +static void do_read(struct pa_pstream *p); + +static void do_something(struct pa_pstream *p) { + assert(p && !p->shall_free); + p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 0); + + if (p->dead) + return; + + if (pa_iochannel_is_hungup(p->io)) { + p->dead = 1; + if (p->die_callback) + p->die_callback(p, p->die_callback_userdata); + + return; + } + + if (pa_iochannel_is_writable(p->io)) { + p->in_use = 1; + do_write(p); + p->in_use = 0; + + if (p->shall_free) { + pa_pstream_free(p); + return; + } + } + + if (pa_iochannel_is_readable(p->io)) { + p->in_use = 1; + do_read(p); + p->in_use = 0; + if (p->shall_free) { + pa_pstream_free(p); + return; + } + } +} + +static void io_callback(struct pa_iochannel*io, void *userdata) { + struct pa_pstream *p = userdata; + assert(p && p->io == io); + do_something(p); +} + +static void fixed_callback(struct pa_mainloop_api *m, void *id, void*userdata) { + struct pa_pstream *p = userdata; + assert(p && p->mainloop_source == id && p->mainloop == m); + do_something(p); +} + +struct pa_pstream *pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel *io) { + struct pa_pstream *p; + assert(io); + + p = malloc(sizeof(struct pa_pstream)); + assert(p); + + p->io = io; + pa_iochannel_set_callback(io, io_callback, p); + + p->dead = 0; + p->die_callback = NULL; + p->die_callback_userdata = NULL; + + p->mainloop = m; + p->mainloop_source = m->source_fixed(m, fixed_callback, p); + m->enable_fixed(m, p->mainloop_source, 0); + + p->send_queue = pa_queue_new(); + assert(p->send_queue); + + p->write.current = NULL; + p->write.index = 0; + + p->read.memblock = NULL; + p->read.packet = NULL; + p->read.index = 0; + + p->recieve_packet_callback = NULL; + p->recieve_packet_callback_userdata = NULL; + + p->recieve_memblock_callback = NULL; + p->recieve_memblock_callback_userdata = NULL; + + p->drain_callback = NULL; + p->drain_userdata = NULL; + + p->in_use = p->shall_free = 0; + + return p; +} + +static void item_free(void *item, void *p) { + struct item_info *i = item; + assert(i); + + if (i->type == PA_PSTREAM_ITEM_MEMBLOCK) { + assert(i->chunk.memblock); + pa_memblock_unref(i->chunk.memblock); + } else { + assert(i->type == PA_PSTREAM_ITEM_PACKET); + assert(i->packet); + pa_packet_unref(i->packet); + } + + free(i); +} + +void pa_pstream_free(struct pa_pstream *p) { + assert(p); + + if (p->in_use) { + /* If this pstream object is used by someone else on the call stack, we have to postpone the freeing */ + p->dead = p->shall_free = 1; + return; + } + + pa_iochannel_free(p->io); + pa_queue_free(p->send_queue, item_free, NULL); + + if (p->write.current) + item_free(p->write.current, NULL); + + if (p->read.memblock) + pa_memblock_unref(p->read.memblock); + + if (p->read.packet) + pa_packet_unref(p->read.packet); + + p->mainloop->cancel_fixed(p->mainloop, p->mainloop_source); + free(p); +} + +void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet) { + struct item_info *i; + assert(p && packet); + + i = malloc(sizeof(struct item_info)); + assert(i); + i->type = PA_PSTREAM_ITEM_PACKET; + i->packet = pa_packet_ref(packet); + + pa_queue_push(p->send_queue, i); + p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 1); +} + +void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk) { + struct item_info *i; + assert(p && channel != (uint32_t) -1 && chunk); + + i = malloc(sizeof(struct item_info)); + assert(i); + i->type = PA_PSTREAM_ITEM_MEMBLOCK; + i->chunk = *chunk; + i->channel = channel; + i->delta = delta; + + pa_memblock_ref(i->chunk.memblock); + + pa_queue_push(p->send_queue, i); + p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 1); +} + +void pa_pstream_set_recieve_packet_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata), void *userdata) { + assert(p && callback); + + p->recieve_packet_callback = callback; + p->recieve_packet_callback_userdata = userdata; +} + +void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata), void *userdata) { + assert(p && callback); + + p->recieve_memblock_callback = callback; + p->recieve_memblock_callback_userdata = userdata; +} + +static void prepare_next_write_item(struct pa_pstream *p) { + assert(p); + + if (!(p->write.current = pa_queue_pop(p->send_queue))) + return; + + p->write.index = 0; + + if (p->write.current->type == PA_PSTREAM_ITEM_PACKET) { + assert(p->write.current->packet); + p->write.data = p->write.current->packet->data; + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->packet->length); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl((uint32_t) -1); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA] = 0; + } else { + assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK && p->write.current->chunk.memblock); + p->write.data = p->write.current->chunk.memblock->data + p->write.current->chunk.index; + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl(p->write.current->channel); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA] = htonl(p->write.current->delta); + } +} + +static void do_write(struct pa_pstream *p) { + void *d; + size_t l; + ssize_t r; + assert(p); + + if (!p->write.current) + prepare_next_write_item(p); + + if (!p->write.current) + return; + + assert(p->write.data); + + if (p->write.index < PA_PSTREAM_DESCRIPTOR_SIZE) { + d = (void*) p->write.descriptor + p->write.index; + l = PA_PSTREAM_DESCRIPTOR_SIZE - p->write.index; + } else { + d = (void*) p->write.data + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE; + l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE); + } + + if ((r = pa_iochannel_write(p->io, d, l)) < 0) + goto die; + + p->write.index += r; + + if (p->write.index >= PA_PSTREAM_DESCRIPTOR_SIZE+ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])) { + assert(p->write.current); + item_free(p->write.current, (void *) 1); + p->write.current = NULL; + + if (p->drain_callback && !pa_pstream_is_pending(p)) + p->drain_callback(p, p->drain_userdata); + } + + return; + +die: + p->dead = 1; + if (p->die_callback) + p->die_callback(p, p->die_callback_userdata); +} + +static void do_read(struct pa_pstream *p) { + void *d; + size_t l; + ssize_t r; + assert(p); + + if (p->read.index < PA_PSTREAM_DESCRIPTOR_SIZE) { + d = (void*) p->read.descriptor + p->read.index; + l = PA_PSTREAM_DESCRIPTOR_SIZE - p->read.index; + } else { + assert(p->read.data); + d = (void*) p->read.data + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE; + l = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE); + } + + if ((r = pa_iochannel_read(p->io, d, l)) <= 0) + goto die; + + p->read.index += r; + + if (p->read.index == PA_PSTREAM_DESCRIPTOR_SIZE) { + /* Reading of frame descriptor complete */ + + /* Frame size too large */ + if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) > FRAME_SIZE_MAX) + goto die; + + assert(!p->read.packet && !p->read.memblock); + + if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]) == (uint32_t) -1) { + /* Frame is a packet frame */ + p->read.packet = pa_packet_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])); + assert(p->read.packet); + p->read.data = p->read.packet->data; + } else { + /* Frame is a memblock frame */ + p->read.memblock = pa_memblock_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])); + assert(p->read.memblock); + p->read.data = p->read.memblock->data; + } + + } else if (p->read.index > PA_PSTREAM_DESCRIPTOR_SIZE) { + /* Frame payload available */ + + if (p->read.memblock && p->recieve_memblock_callback) { /* Is this memblock data? Than pass it to the user */ + size_t l; + + l = (p->read.index - r) < PA_PSTREAM_DESCRIPTOR_SIZE ? p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE : (size_t) r; + + if (l > 0) { + struct pa_memchunk chunk; + + chunk.memblock = p->read.memblock; + chunk.index = p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE - l; + chunk.length = l; + + if (p->recieve_memblock_callback) + p->recieve_memblock_callback( + p, + ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]), + (int32_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA]), + &chunk, + p->recieve_memblock_callback_userdata); + } + } + + /* Frame complete */ + if (p->read.index >= ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) + PA_PSTREAM_DESCRIPTOR_SIZE) { + if (p->read.memblock) { + assert(!p->read.packet); + + pa_memblock_unref(p->read.memblock); + p->read.memblock = NULL; + } else { + assert(p->read.packet); + + if (p->recieve_packet_callback) + p->recieve_packet_callback(p, p->read.packet, p->recieve_packet_callback_userdata); + + pa_packet_unref(p->read.packet); + p->read.packet = NULL; + } + + p->read.index = 0; + } + } + + return; + +die: + p->dead = 1; + if (p->die_callback) + p->die_callback(p, p->die_callback_userdata); + +} + +void pa_pstream_set_die_callback(struct pa_pstream *p, void (*callback)(struct pa_pstream *p, void *userdata), void *userdata) { + assert(p && callback); + p->die_callback = callback; + p->die_callback_userdata = userdata; +} + +int pa_pstream_is_pending(struct pa_pstream *p) { + assert(p); + + if (p->dead) + return 0; + + return p->write.current || !pa_queue_is_empty(p->send_queue); +} + +void pa_pstream_set_drain_callback(struct pa_pstream *p, void (*cb)(struct pa_pstream *p, void *userdata), void *userdata) { + assert(p); + + p->drain_callback = cb; + p->drain_userdata = userdata; +} + diff --git a/polyp/pstream.h b/polyp/pstream.h new file mode 100644 index 00000000..6b91aeb0 --- /dev/null +++ b/polyp/pstream.h @@ -0,0 +1,51 @@ +#ifndef foopstreamhfoo +#define foopstreamhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "packet.h" +#include "memblock.h" +#include "iochannel.h" +#include "mainloop-api.h" +#include "memchunk.h" + +/* It is safe to destroy the calling pstream object from all callbacks */ + +struct pa_pstream; + +struct pa_pstream* pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel *io); +void pa_pstream_free(struct pa_pstream*p); + +void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet); +void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk); + +void pa_pstream_set_recieve_packet_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata), void *userdata); +void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata), void *userdata); +void pa_pstream_set_drain_callback(struct pa_pstream *p, void (*cb)(struct pa_pstream *p, void *userdata), void *userdata); + +void pa_pstream_set_die_callback(struct pa_pstream *p, void (*callback)(struct pa_pstream *p, void *userdata), void *userdata); + +int pa_pstream_is_pending(struct pa_pstream *p); + +#endif diff --git a/polyp/queue.c b/polyp/queue.c new file mode 100644 index 00000000..9befd475 --- /dev/null +++ b/polyp/queue.c @@ -0,0 +1,109 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "queue.h" + +struct queue_entry { + struct queue_entry *next; + void *data; +}; + +struct pa_queue { + struct queue_entry *front, *back; + unsigned length; +}; + +struct pa_queue* pa_queue_new(void) { + struct pa_queue *q = malloc(sizeof(struct pa_queue)); + assert(q); + q->front = q->back = NULL; + q->length = 0; + return q; +} + +void pa_queue_free(struct pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata) { + struct queue_entry *e; + assert(q); + + e = q->front; + while (e) { + struct queue_entry *n = e->next; + + if (destroy) + destroy(e->data, userdata); + + free(e); + e = n; + } + + free(q); +} + +void pa_queue_push(struct pa_queue *q, void *p) { + struct queue_entry *e; + + e = malloc(sizeof(struct queue_entry)); + + e->data = p; + e->next = NULL; + + if (q->back) + q->back->next = e; + else { + assert(!q->front); + q->front = e; + } + + q->back = e; + q->length++; +} + +void* pa_queue_pop(struct pa_queue *q) { + void *p; + struct queue_entry *e; + assert(q); + + if (!(e = q->front)) + return NULL; + + q->front = e->next; + if (q->back == e) + q->back = NULL; + + p = e->data; + free(e); + + q->length--; + + return p; +} + +int pa_queue_is_empty(struct pa_queue *q) { + assert(q); + return q->length == 0; +} diff --git a/polyp/queue.h b/polyp/queue.h new file mode 100644 index 00000000..3ec13734 --- /dev/null +++ b/polyp/queue.h @@ -0,0 +1,34 @@ +#ifndef fooqueuehfoo +#define fooqueuehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +struct pa_queue; + +struct pa_queue* pa_queue_new(void); +void pa_queue_free(struct pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata); +void pa_queue_push(struct pa_queue *q, void *p); +void* pa_queue_pop(struct pa_queue *q); + +int pa_queue_is_empty(struct pa_queue *q); + +#endif diff --git a/polyp/resampler.c b/polyp/resampler.c new file mode 100644 index 00000000..4f5f6be3 --- /dev/null +++ b/polyp/resampler.c @@ -0,0 +1,180 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include "resampler.h" +#include "sconv.h" + +struct pa_resampler { + struct pa_sample_spec i_ss, o_ss; + float* i_buf, *o_buf; + unsigned i_alloc, o_alloc; + size_t i_sz, o_sz; + + int channels; + + pa_convert_to_float32_func_t to_float32_func; + pa_convert_from_float32_func_t from_float32_func; + SRC_STATE *src_state; +}; + +struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b) { + struct pa_resampler *r; + int err; + assert(a && b && pa_sample_spec_valid(a) && pa_sample_spec_valid(b)); + + if (a->channels != b->channels && a->channels != 1 && b->channels != 1) + goto fail; + + if (a->format == PA_SAMPLE_ALAW || a->format == PA_SAMPLE_ULAW || b->format == PA_SAMPLE_ALAW || b->format == PA_SAMPLE_ULAW) + goto fail; + + r = malloc(sizeof(struct pa_resampler)); + assert(r); + + r->channels = a->channels; + if (b->channels < r->channels) + r->channels = b->channels; + + r->i_buf = r->o_buf = NULL; + r->i_alloc = r->o_alloc = 0; + + if (a->rate != b->rate) { + r->src_state = src_new(SRC_SINC_FASTEST, r->channels, &err); + if (err != 0 || !r->src_state) + goto fail; + } else + r->src_state = NULL; + + r->i_ss = *a; + r->o_ss = *b; + + r->i_sz = pa_sample_size(a); + r->o_sz = pa_sample_size(b); + + r->to_float32_func = pa_get_convert_to_float32_function(a->format); + r->from_float32_func = pa_get_convert_from_float32_function(b->format); + + assert(r->to_float32_func && r->from_float32_func); + + return r; + +fail: + if (r) + free(r); + + return NULL; +} + +void pa_resampler_free(struct pa_resampler *r) { + assert(r); + if (r->src_state) + src_delete(r->src_state); + free(r->i_buf); + free(r->o_buf); + free(r); +} + +size_t pa_resampler_request(struct pa_resampler *r, size_t out_length) { + assert(r && (out_length % r->o_sz) == 0); + + return (((out_length / r->o_sz)*r->i_ss.rate)/r->o_ss.rate) * r->i_sz; +} + + +void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out) { + unsigned i_nchannels, o_nchannels, ins, ons, eff_ins, eff_ons; + float *cbuf; + assert(r && in && out && in->length && in->memblock && (in->length % r->i_sz) == 0); + + /* How many input samples? */ + ins = in->length/r->i_sz; + + /* How much space for output samples? */ + if (r->src_state) + ons = (ins*r->o_ss.rate/r->i_ss.rate)+1024; + else + ons = ins; + + /* How many channels? */ + if (r->i_ss.channels == r->o_ss.channels) { + i_nchannels = o_nchannels = 1; + eff_ins = ins*r->i_ss.channels; /* effective samples */ + eff_ons = ons*r->o_ss.channels; + } else { + i_nchannels = r->i_ss.channels; + o_nchannels = r->o_ss.channels; + eff_ins = ins; + eff_ons = ons; + } + + out->memblock = pa_memblock_new(out->length = (ons*r->o_sz)); + out->index = 0; + assert(out->memblock); + + if (r->i_alloc < eff_ins) + r->i_buf = realloc(r->i_buf, sizeof(float) * (r->i_alloc = eff_ins)); + assert(r->i_buf); + + r->to_float32_func(eff_ins, in->memblock->data+in->index, i_nchannels, r->i_buf); + + if (r->src_state) { + int ret; + SRC_DATA data; + + if (r->o_alloc < eff_ons) + r->o_buf = realloc(r->o_buf, sizeof(float) * (r->o_alloc = eff_ons)); + assert(r->o_buf); + + data.data_in = r->i_buf; + data.input_frames = ins; + + data.data_out = r->o_buf; + data.output_frames = ons; + + data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate; + data.end_of_input = 0; + + ret = src_process(r->src_state, &data); + assert(ret == 0); + assert((unsigned) data.input_frames_used == ins); + + cbuf = r->o_buf; + ons = data.output_frames_gen; + + if (r->i_ss.channels == r->o_ss.channels) + eff_ons = ons*r->o_ss.channels; + else + eff_ons = ons; + } else + cbuf = r->i_buf; + + r->from_float32_func(eff_ons, cbuf, out->memblock->data+out->index, o_nchannels); + out->length = ons*r->o_sz; +} diff --git a/polyp/resampler.h b/polyp/resampler.h new file mode 100644 index 00000000..8e979478 --- /dev/null +++ b/polyp/resampler.h @@ -0,0 +1,37 @@ +#ifndef fooresamplerhfoo +#define fooresamplerhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "sample.h" +#include "memblock.h" +#include "memchunk.h" + +struct pa_resampler; + +struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b); +void pa_resampler_free(struct pa_resampler *r); + +size_t pa_resampler_request(struct pa_resampler *r, size_t out_length); +void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out); + +#endif diff --git a/polyp/sample-util.c b/polyp/sample-util.c new file mode 100644 index 00000000..d608ce1b --- /dev/null +++ b/polyp/sample-util.c @@ -0,0 +1,144 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "sample-util.h" + +struct pa_memblock *pa_silence_memblock(struct pa_memblock* b, const struct pa_sample_spec *spec) { + assert(b && b->data && spec); + pa_silence_memory(b->data, b->length, spec); + return b; +} + +void pa_silence_memchunk(struct pa_memchunk *c, const struct pa_sample_spec *spec) { + assert(c && c->memblock && c->memblock->data && spec && c->length); + pa_silence_memory(c->memblock->data+c->index, c->length, spec); +} + +void pa_silence_memory(void *p, size_t length, const struct pa_sample_spec *spec) { + char c = 0; + assert(p && length && spec); + + switch (spec->format) { + case PA_SAMPLE_U8: + c = 127; + break; + case PA_SAMPLE_S16LE: + case PA_SAMPLE_S16BE: + case PA_SAMPLE_FLOAT32: + c = 0; + break; + case PA_SAMPLE_ALAW: + case PA_SAMPLE_ULAW: + c = 80; + break; + default: + assert(0); + } + + memset(p, c, length); +} + +size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const struct pa_sample_spec *spec, uint32_t volume) { + unsigned c, d; + assert(channels && data && length && spec); + assert(spec->format == PA_SAMPLE_S16NE); + + for (d = 0;; d += sizeof(int16_t)) { + int32_t sum = 0; + + if (d >= length) + return d; + + for (c = 0; c < nchannels; c++) { + int32_t v; + uint32_t volume = channels[c].volume; + + if (d >= channels[c].chunk.length) + return d; + + if (volume == PA_VOLUME_MUTE) + v = 0; + else { + v = *((int16_t*) (channels[c].chunk.memblock->data + channels[c].chunk.index + d)); + + if (volume != PA_VOLUME_NORM) + v = (int32_t) ((float)v*volume/PA_VOLUME_NORM); + } + + sum += v; + } + + if (volume == PA_VOLUME_MUTE) + sum = 0; + else if (volume != PA_VOLUME_NORM) + sum = (int32_t) ((float) sum*volume/PA_VOLUME_NORM); + + if (sum < -0x8000) sum = -0x8000; + if (sum > 0x7FFF) sum = 0x7FFF; + + *((int16_t*) data) = sum; + data += sizeof(int16_t); + } +} + + +void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, uint32_t volume) { + int16_t *d; + size_t n; + assert(c && spec && (c->length % pa_sample_size(spec) == 0)); + assert(spec->format == PA_SAMPLE_S16NE); + + if (volume == PA_VOLUME_NORM) + return; + + if (volume == PA_VOLUME_MUTE) { + pa_silence_memchunk(c, spec); + return; + } + + for (d = (c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { + int32_t t = (int32_t)(*d); + + t *= volume; + t /= PA_VOLUME_NORM; + + if (t < -0x8000) t = -0x8000; + if (t > 0x7FFF) t = 0x7FFF; + + *d = (int16_t) t; + } +} + +uint32_t pa_volume_multiply(uint32_t a, uint32_t b) { + uint64_t p = a; + p *= b; + p /= PA_VOLUME_NORM; + + return (uint32_t) p; +} diff --git a/polyp/sample-util.h b/polyp/sample-util.h new file mode 100644 index 00000000..73101ab4 --- /dev/null +++ b/polyp/sample-util.h @@ -0,0 +1,48 @@ +#ifndef foosampleutilhfoo +#define foosampleutilhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "sample.h" +#include "memblock.h" +#include "memchunk.h" + +#define PA_VOLUME_NORM (0x100) +#define PA_VOLUME_MUTE (0) + +struct pa_memblock *pa_silence_memblock(struct pa_memblock* b, const struct pa_sample_spec *spec); +void pa_silence_memchunk(struct pa_memchunk *c, const struct pa_sample_spec *spec); +void pa_silence_memory(void *p, size_t length, const struct pa_sample_spec *spec); + +struct pa_mix_info { + struct pa_memchunk chunk; + uint32_t volume; + void *userdata; +}; + +size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const struct pa_sample_spec *spec, uint32_t volume); + +void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, uint32_t volume); + +uint32_t pa_volume_multiply(uint32_t a, uint32_t b); + +#endif diff --git a/polyp/sample.c b/polyp/sample.c new file mode 100644 index 00000000..8179475d --- /dev/null +++ b/polyp/sample.c @@ -0,0 +1,99 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "sample.h" + +size_t pa_sample_size(const struct pa_sample_spec *spec) { + assert(spec); + size_t b = 1; + + switch (spec->format) { + case PA_SAMPLE_U8: + case PA_SAMPLE_ULAW: + case PA_SAMPLE_ALAW: + b = 1; + break; + case PA_SAMPLE_S16LE: + case PA_SAMPLE_S16BE: + b = 2; + break; + case PA_SAMPLE_FLOAT32LE: + case PA_SAMPLE_FLOAT32BE: + b = 4; + break; + default: + assert(0); + } + + return b * spec->channels; +} + +size_t pa_bytes_per_second(const struct pa_sample_spec *spec) { + assert(spec); + return spec->rate*pa_sample_size(spec); +} + + +uint32_t pa_samples_usec(size_t length, const struct pa_sample_spec *spec) { + assert(spec); + + return (uint32_t) (((double) length /pa_sample_size(spec))/spec->rate*1000000); +} + +int pa_sample_spec_valid(const struct pa_sample_spec *spec) { + assert(spec); + + if (!spec->rate || !spec->channels) + return 0; + + if (spec->format >= PA_SAMPLE_MAX) + return 0; + + return 1; +} + +int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b) { + assert(a && b); + + return (a->format == b->format) && (a->rate == b->rate) && (a->channels == b->channels); +} + +void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec) { + static const char* const table[]= { + [PA_SAMPLE_U8] = "U8", + [PA_SAMPLE_ALAW] = "ALAW", + [PA_SAMPLE_ULAW] = "ULAW", + [PA_SAMPLE_S16LE] = "S16LE", + [PA_SAMPLE_S16BE] = "S16BE", + [PA_SAMPLE_FLOAT32LE] = "FLOAT32LE", + [PA_SAMPLE_FLOAT32BE] = "FLOAT32BE", + }; + + assert(pa_sample_spec_valid(spec)); + snprintf(s, l, "%s %uch %uHz", table[spec->format], spec->channels, spec->rate); +} diff --git a/polyp/sample.h b/polyp/sample.h new file mode 100644 index 00000000..825441f2 --- /dev/null +++ b/polyp/sample.h @@ -0,0 +1,64 @@ +#ifndef foosamplehfoo +#define foosamplehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +enum pa_sample_format { + PA_SAMPLE_U8, + PA_SAMPLE_ALAW, + PA_SAMPLE_ULAW, + PA_SAMPLE_S16LE, + PA_SAMPLE_S16BE, + PA_SAMPLE_FLOAT32LE, + PA_SAMPLE_FLOAT32BE, + PA_SAMPLE_MAX +}; + +#ifdef WORDS_BIGENDIAN +#define PA_SAMPLE_S16NE PA_SAMPLE_S16BE +#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32BE +#else +#define PA_SAMPLE_S16NE PA_SAMPLE_S16LE +#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32LE +#endif +#define PA_SAMPLE_FLOAT32 PA_SAMPLE_FLOAT32NE + +struct pa_sample_spec { + enum pa_sample_format format; + uint32_t rate; + uint8_t channels; +}; + +size_t pa_bytes_per_second(const struct pa_sample_spec *spec); +size_t pa_sample_size(const struct pa_sample_spec *spec); +uint32_t pa_samples_usec(size_t length, const struct pa_sample_spec *spec); +int pa_sample_spec_valid(const struct pa_sample_spec *spec); +int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b); + + +#define PA_SAMPLE_SNPRINT_MAX_LENGTH 32 +void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec); + +#endif diff --git a/polyp/sconv-s16be.c b/polyp/sconv-s16be.c new file mode 100644 index 00000000..a4c25cde --- /dev/null +++ b/polyp/sconv-s16be.c @@ -0,0 +1,34 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "sconv-s16be.h" + +#define INT16_FROM INT16_FROM_BE +#define INT16_TO INT16_TO_BE + +#define pa_sconv_s16le_to_float32 pa_sconv_s16be_to_float32 +#define pa_sconv_s16le_from_float32 pa_sconv_s16be_from_float32 + +#include "sconv-s16le.c" diff --git a/polyp/sconv-s16be.h b/polyp/sconv-s16be.h new file mode 100644 index 00000000..d112d9f2 --- /dev/null +++ b/polyp/sconv-s16be.h @@ -0,0 +1,28 @@ +#ifndef foosconv_s16befoo +#define foosconv_s16befoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +void pa_sconv_s16be_to_float32(unsigned n, const void *a, unsigned an, float *b); +void pa_sconv_s16be_from_float32(unsigned n, const float *a, void *b, unsigned bn); + +#endif diff --git a/polyp/sconv-s16le.c b/polyp/sconv-s16le.c new file mode 100644 index 00000000..45b28bdb --- /dev/null +++ b/polyp/sconv-s16le.c @@ -0,0 +1,82 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "endianmacros.h" +#include "sconv.h" + +#ifndef INT16_FROM +#define INT16_FROM INT16_FROM_LE +#endif + +#ifndef INT16_TO +#define INT16_TO INT16_TO_LE +#endif + +void pa_sconv_s16le_to_float32(unsigned n, const void *a, unsigned an, float *b) { + const int16_t *ca = a; + assert(n && a && an && b); + + for (; n > 0; n--) { + unsigned i; + float sum = 0; + + for (i = 0; i < an; i++) { + int16_t s = *(ca++); + sum += ((float) INT16_FROM(s))/0x7FFF; + } + + if (sum > 1) + sum = 1; + if (sum < -1) + sum = -1; + + *(b++) = sum; + } +} + +void pa_sconv_s16le_from_float32(unsigned n, const float *a, void *b, unsigned bn) { + int16_t *cb = b; + assert(n && a && b && bn); + + for (; n > 0; n--) { + unsigned i; + int16_t s; + float v = *(a++); + + if (v > 1) + v = 1; + if (v < -1) + v = -1; + + s = (int16_t) (v * 0x7FFF); + s = INT16_TO(s); + + for (i = 0; i < bn; i++) + *(cb++) = s; + } +} diff --git a/polyp/sconv-s16le.h b/polyp/sconv-s16le.h new file mode 100644 index 00000000..0f206ec3 --- /dev/null +++ b/polyp/sconv-s16le.h @@ -0,0 +1,28 @@ +#ifndef foosconv_s16lefoo +#define foosconv_s16lefoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +void pa_sconv_s16le_to_float32(unsigned n, const void *a, unsigned an, float *b); +void pa_sconv_s16le_from_float32(unsigned n, const float *a, void *b, unsigned bn); + +#endif diff --git a/polyp/sconv.c b/polyp/sconv.c new file mode 100644 index 00000000..dd9dd241 --- /dev/null +++ b/polyp/sconv.c @@ -0,0 +1,137 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include "endianmacros.h" +#include "sconv.h" + +#include "sconv-s16le.h" +#include "sconv-s16be.h" + +static void u8_to_float32(unsigned n, const void *a, unsigned an, float *b) { + unsigned i; + const uint8_t *ca = a; + assert(n && a && an && b); + + for (; n > 0; n--) { + float sum = 0; + + for (i = 0; i < an; i++) { + uint8_t v = *(ca++); + sum += (((float) v)-127)/127; + } + + if (sum > 1) + sum = 1; + if (sum < -1) + sum = -1; + + *(b++) = sum; + } +} + +static void u8_from_float32(unsigned n, const float *a, void *b, unsigned bn) { + unsigned i; + uint8_t *cb = b; + + assert(n && a && b && bn); + for (; n > 0; n--) { + float v = *(a++); + uint8_t u; + + if (v > 1) + v = 1; + + if (v < -1) + v = -1; + + u = (uint8_t) (v*127+127); + + for (i = 0; i < bn; i++) + *(cb++) = u; + } +} + +static void float32_to_float32(unsigned n, const void *a, unsigned an, float *b) { + unsigned i; + const float *ca = a; + assert(n && a && an && b); + for (; n > 0; n--) { + float sum = 0; + + for (i = 0; i < an; i++) + sum += *(ca++); + + if (sum > 1) + sum = 1; + if (sum < -1) + sum = -1; + + *(b++) = sum; + } +} + +static void float32_from_float32(unsigned n, const float *a, void *b, unsigned bn) { + unsigned i; + float *cb = b; + assert(n && a && b && bn); + for (; n > 0; n--) { + float v = *(a++); + for (i = 0; i < bn; i++) + *(cb++) = v; + } +} + +pa_convert_to_float32_func_t pa_get_convert_to_float32_function(enum pa_sample_format f) { + switch(f) { + case PA_SAMPLE_U8: + return u8_to_float32; + case PA_SAMPLE_S16LE: + return pa_sconv_s16le_to_float32; + case PA_SAMPLE_S16BE: + return pa_sconv_s16be_to_float32; + case PA_SAMPLE_FLOAT32: + return float32_to_float32; + default: + return NULL; + } +} + +pa_convert_from_float32_func_t pa_get_convert_from_float32_function(enum pa_sample_format f) { + switch(f) { + case PA_SAMPLE_U8: + return u8_from_float32; + case PA_SAMPLE_S16LE: + return pa_sconv_s16le_from_float32; + case PA_SAMPLE_S16BE: + return pa_sconv_s16be_from_float32; + case PA_SAMPLE_FLOAT32: + return float32_from_float32; + default: + return NULL; + } +} diff --git a/polyp/sconv.h b/polyp/sconv.h new file mode 100644 index 00000000..1a62ed20 --- /dev/null +++ b/polyp/sconv.h @@ -0,0 +1,33 @@ +#ifndef foosconvhfoo +#define foosconvhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "sample.h" + +typedef void (*pa_convert_to_float32_func_t)(unsigned n, const void *a, unsigned an, float *b); +typedef void (*pa_convert_from_float32_func_t)(unsigned n, const float *a, void *b, unsigned bn); + +pa_convert_to_float32_func_t pa_get_convert_to_float32_function(enum pa_sample_format f); +pa_convert_from_float32_func_t pa_get_convert_from_float32_function(enum pa_sample_format f); + +#endif diff --git a/polyp/sink-input.c b/polyp/sink-input.c new file mode 100644 index 00000000..5c2d3a13 --- /dev/null +++ b/polyp/sink-input.c @@ -0,0 +1,163 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "sink-input.h" +#include "sample-util.h" + +#define CONVERT_BUFFER_LENGTH 4096 + +struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec) { + struct pa_sink_input *i; + struct pa_resampler *resampler = NULL; + int r; + char st[256]; + assert(s && spec); + + if (!pa_sample_spec_equal(spec, &s->sample_spec)) + if (!(resampler = pa_resampler_new(spec, &s->sample_spec))) + return NULL; + + i = malloc(sizeof(struct pa_sink_input)); + assert(i); + i->name = name ? strdup(name) : NULL; + i->client = NULL; + i->owner = NULL; + i->sink = s; + i->sample_spec = *spec; + + i->peek = NULL; + i->drop = NULL; + i->kill = NULL; + i->get_latency = NULL; + i->userdata = NULL; + + i->volume = PA_VOLUME_NORM; + + i->resampled_chunk.memblock = NULL; + i->resampled_chunk.index = i->resampled_chunk.length = 0; + i->resampler = resampler; + + assert(s->core); + r = pa_idxset_put(s->core->sink_inputs, i, &i->index); + assert(r == 0 && i->index != PA_IDXSET_INVALID); + r = pa_idxset_put(s->inputs, i, NULL); + assert(r == 0); + + pa_sample_snprint(st, sizeof(st), spec); + fprintf(stderr, "sink-input: created %u \"%s\" on %u with sample spec \"%s\"\n", i->index, i->name, s->index, st); + + return i; +} + +void pa_sink_input_free(struct pa_sink_input* i) { + assert(i); + + assert(i->sink && i->sink->core); + pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); + pa_idxset_remove_by_data(i->sink->inputs, i, NULL); + + if (i->resampled_chunk.memblock) + pa_memblock_unref(i->resampled_chunk.memblock); + if (i->resampler) + pa_resampler_free(i->resampler); + + free(i->name); + free(i); +} + +void pa_sink_input_kill(struct pa_sink_input*i) { + assert(i); + + if (i->kill) + i->kill(i); +} + +uint32_t pa_sink_input_get_latency(struct pa_sink_input *i) { + uint32_t l = 0; + + assert(i); + if (i->get_latency) + l += i->get_latency(i); + + assert(i->sink); + l += pa_sink_get_latency(i->sink); + + return l; +} + +int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { + assert(i && chunk && i->peek && i->drop); + + if (!i->resampler) + return i->peek(i, chunk); + + if (!i->resampled_chunk.memblock) { + struct pa_memchunk tchunk; + size_t l; + int ret; + + if ((ret = i->peek(i, &tchunk)) < 0) + return ret; + + l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); + if (tchunk.length > l) + tchunk.length = l; + + i->drop(i, tchunk.length); + + pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk); + pa_memblock_unref(tchunk.memblock); + } + + assert(i->resampled_chunk.memblock && i->resampled_chunk.length); + *chunk = i->resampled_chunk; + pa_memblock_ref(i->resampled_chunk.memblock); + return 0; +} + +void pa_sink_input_drop(struct pa_sink_input *i, size_t length) { + assert(i && length); + + if (!i->resampler) { + i->drop(i, length); + return; + } + + assert(i->resampled_chunk.memblock && i->resampled_chunk.length >= length); + + i->resampled_chunk.index += length; + i->resampled_chunk.length -= length; + + if (!i->resampled_chunk.length) { + pa_memblock_unref(i->resampled_chunk.memblock); + i->resampled_chunk.memblock = NULL; + i->resampled_chunk.index = i->resampled_chunk.length = 0; + } +} diff --git a/polyp/sink-input.h b/polyp/sink-input.h new file mode 100644 index 00000000..63dce71d --- /dev/null +++ b/polyp/sink-input.h @@ -0,0 +1,67 @@ +#ifndef foosinkinputhfoo +#define foosinkinputhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "sink.h" +#include "sample.h" +#include "memblockq.h" +#include "resampler.h" +#include "module.h" +#include "client.h" + +struct pa_sink_input { + uint32_t index; + + char *name; + struct pa_module *owner; + struct pa_client *client; + struct pa_sink *sink; + struct pa_sample_spec sample_spec; + uint32_t volume; + + int (*peek) (struct pa_sink_input *i, struct pa_memchunk *chunk); + void (*drop) (struct pa_sink_input *i, size_t length); + void (*kill) (struct pa_sink_input *i); + uint32_t (*get_latency) (struct pa_sink_input *i); + + void *userdata; + + struct pa_memchunk resampled_chunk; + struct pa_resampler *resampler; +}; + +struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec); +void pa_sink_input_free(struct pa_sink_input* i); + +/* Code that didn't create the input stream should call this function to + * request destruction of it */ +void pa_sink_input_kill(struct pa_sink_input *i); + +uint32_t pa_sink_input_get_latency(struct pa_sink_input *i); + +int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk); +void pa_sink_input_drop(struct pa_sink_input *i, size_t length); + +#endif diff --git a/polyp/sink.c b/polyp/sink.c new file mode 100644 index 00000000..20fa76a6 --- /dev/null +++ b/polyp/sink.c @@ -0,0 +1,292 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "sink.h" +#include "sink-input.h" +#include "namereg.h" +#include "util.h" +#include "sample-util.h" + +#define MAX_MIX_CHANNELS 32 + +struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec) { + struct pa_sink *s; + char *n = NULL; + char st[256]; + int r; + assert(core && name && spec); + + s = malloc(sizeof(struct pa_sink)); + assert(s); + + if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) { + free(s); + return NULL; + } + + s->name = strdup(name); + s->description = NULL; + + s->owner = NULL; + s->core = core; + s->sample_spec = *spec; + s->inputs = pa_idxset_new(NULL, NULL); + + n = pa_sprintf_malloc("%s_monitor", name); + 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; + + s->notify = NULL; + s->get_latency = NULL; + s->userdata = NULL; + + r = pa_idxset_put(core->sinks, s, &s->index); + assert(s->index != PA_IDXSET_INVALID && r >= 0); + + pa_sample_snprint(st, sizeof(st), spec); + fprintf(stderr, "sink: created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); + + return s; +} + +void pa_sink_free(struct pa_sink *s) { + struct pa_sink_input *i, *j = NULL; + assert(s); + + pa_namereg_unregister(s->core, s->name); + + while ((i = pa_idxset_first(s->inputs, NULL))) { + assert(i != j); + pa_sink_input_kill(i); + j = i; + } + pa_idxset_free(s->inputs, NULL, NULL); + + pa_source_free(s->monitor_source); + pa_idxset_remove_by_data(s->core->sinks, s, NULL); + + fprintf(stderr, "sink: freed %u \"%s\"\n", s->index, s->name); + + free(s->name); + free(s->description); + free(s); +} + +void pa_sink_notify(struct pa_sink*s) { + assert(s); + + if (s->notify) + s->notify(s); +} + +static unsigned fill_mix_info(struct pa_sink *s, struct pa_mix_info *info, unsigned maxinfo) { + uint32_t index = PA_IDXSET_INVALID; + struct pa_sink_input *i; + unsigned n = 0; + + assert(s && info); + + for (i = pa_idxset_first(s->inputs, &index); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &index)) { + if (pa_sink_input_peek(i, &info->chunk) < 0) + continue; + + info->volume = i->volume; + + assert(info->chunk.memblock && info->chunk.memblock->data && info->chunk.length); + info->userdata = i; + + info++; + maxinfo--; + n++; + } + + return n; +} + +static void inputs_drop(struct pa_sink *s, struct pa_mix_info *info, unsigned maxinfo, size_t length) { + assert(s && info); + + for (; maxinfo > 0; maxinfo--, info++) { + struct pa_sink_input *i = info->userdata; + assert(i && info->chunk.memblock); + + pa_memblock_unref(info->chunk.memblock); + pa_sink_input_drop(i, length); + } +} + +int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result) { + struct pa_mix_info info[MAX_MIX_CHANNELS]; + unsigned n; + size_t l; + assert(s && length && result); + + n = fill_mix_info(s, info, MAX_MIX_CHANNELS); + + if (n <= 0) + return -1; + + if (n == 1) { + uint32_t volume = PA_VOLUME_NORM; + struct pa_sink_input *i = info[0].userdata; + assert(i); + *result = info[0].chunk; + pa_memblock_ref(result->memblock); + + if (result->length > length) + result->length = length; + + l = result->length; + + if (s->volume != PA_VOLUME_NORM || info[0].volume != PA_VOLUME_NORM) + volume = pa_volume_multiply(s->volume, info[0].volume); + + if (volume != PA_VOLUME_NORM) { + pa_memchunk_make_writable(result); + pa_volume_memchunk(result, &s->sample_spec, volume); + } + } else { + result->memblock = pa_memblock_new(length); + assert(result->memblock); + + result->length = l = pa_mix(info, n, result->memblock->data, length, &s->sample_spec, s->volume); + result->index = 0; + + assert(l); + } + + inputs_drop(s, info, n, l); + + assert(s->monitor_source); + pa_source_post(s->monitor_source, result); + + return 0; +} + +int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target) { + struct pa_mix_info info[MAX_MIX_CHANNELS]; + unsigned n; + size_t l; + assert(s && target && target->length && target->memblock && target->memblock->data); + + n = fill_mix_info(s, info, MAX_MIX_CHANNELS); + + if (n <= 0) + return -1; + + if (n == 1) { + uint32_t volume = PA_VOLUME_NORM; + struct pa_sink_info *i = info[0].userdata; + assert(i); + + l = target->length; + if (l > info[0].chunk.length) + l = info[0].chunk.length; + + memcpy(target->memblock->data+target->index, info[0].chunk.memblock->data + info[0].chunk.index, l); + target->length = l; + + if (s->volume != PA_VOLUME_NORM || info[0].volume != PA_VOLUME_NORM) + volume = pa_volume_multiply(s->volume, info[0].volume); + + if (volume != PA_VOLUME_NORM) + pa_volume_memchunk(target, &s->sample_spec, volume); + } else + target->length = l = pa_mix(info, n, target->memblock->data+target->index, target->length, &s->sample_spec, s->volume); + + assert(l); + inputs_drop(s, info, n, l); + + assert(s->monitor_source); + pa_source_post(s->monitor_source, target); + + return 0; +} + +void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target) { + struct pa_memchunk chunk; + size_t l, d; + assert(s && target && target->memblock && target->length && target->memblock->data); + + l = target->length; + d = 0; + while (l > 0) { + chunk = *target; + chunk.index += d; + chunk.length -= d; + + if (pa_sink_render_into(s, &chunk) < 0) + break; + + d += chunk.length; + l -= chunk.length; + } + + if (l > 0) { + chunk = *target; + chunk.index += d; + chunk.length -= d; + pa_silence_memchunk(&chunk, &s->sample_spec); + } +} + +uint32_t pa_sink_get_latency(struct pa_sink *s) { + assert(s); + + if (!s->get_latency) + return 0; + + return s->get_latency(s); +} + +struct pa_sink* pa_sink_get_default(struct pa_core *c) { + struct pa_sink *sink; + assert(c); + + if ((sink = pa_idxset_get_by_index(c->sinks, c->default_sink_index))) + return sink; + + if (!(sink = pa_idxset_first(c->sinks, &c->default_sink_index))) + return NULL; + + fprintf(stderr, "core: default sink vanished, setting to %u.\n", sink->index); + return sink; +} + +void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m) { + sink->owner = m; + + if (sink->monitor_source) + pa_source_set_owner(sink->monitor_source, m); +} diff --git a/polyp/sink.h b/polyp/sink.h new file mode 100644 index 00000000..2b5d9495 --- /dev/null +++ b/polyp/sink.h @@ -0,0 +1,67 @@ +#ifndef foosinkhfoo +#define foosinkhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +struct pa_sink; + +#include + +#include "core.h" +#include "sample.h" +#include "idxset.h" +#include "source.h" + +struct pa_sink { + uint32_t index; + + char *name, *description; + struct pa_module *owner; + struct pa_core *core; + struct pa_sample_spec sample_spec; + struct pa_idxset *inputs; + + struct pa_source *monitor_source; + + uint32_t volume; + + void (*notify)(struct pa_sink*sink); + uint32_t (*get_latency)(struct pa_sink *s); + void *userdata; +}; + +struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec); +void pa_sink_free(struct pa_sink* s); + +int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result); +int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target); +void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target); + +uint32_t pa_sink_get_latency(struct pa_sink *s); + +void pa_sink_notify(struct pa_sink*s); + +struct pa_sink* pa_sink_get_default(struct pa_core *c); + +void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m); + +#endif diff --git a/polyp/sioman.c b/polyp/sioman.c new file mode 100644 index 00000000..999b8a5c --- /dev/null +++ b/polyp/sioman.c @@ -0,0 +1,42 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#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/polyp/sioman.h b/polyp/sioman.h new file mode 100644 index 00000000..1b60d4a9 --- /dev/null +++ b/polyp/sioman.h @@ -0,0 +1,28 @@ +#ifndef foosiomanhfoo +#define foosiomanhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +int pa_stdio_acquire(void); +void pa_stdio_release(void); + +#endif diff --git a/polyp/socket-client.c b/polyp/socket-client.c new file mode 100644 index 00000000..a2187e6a --- /dev/null +++ b/polyp/socket-client.c @@ -0,0 +1,236 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "socket-client.h" +#include "socket-util.h" +#include "util.h" + +struct pa_socket_client { + struct pa_mainloop_api *mainloop; + int fd; + + void *io_source, *fixed_source; + void (*callback)(struct pa_socket_client*c, struct pa_iochannel *io, void *userdata); + void *userdata; +}; + +static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) { + struct pa_socket_client *c; + assert(m); + + c = malloc(sizeof(struct pa_socket_client)); + assert(c); + c->mainloop = m; + c->fd = -1; + c->io_source = c->fixed_source = NULL; + c->callback = NULL; + c->userdata = NULL; + return c; +} + +static void do_call(struct pa_socket_client *c) { + struct pa_iochannel *io; + int error, lerror; + assert(c && c->callback); + + lerror = sizeof(error); + if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &error, &lerror) < 0) { + fprintf(stderr, "getsockopt(): %s\n", strerror(errno)); + goto failed; + } + + if (lerror != sizeof(error)) { + fprintf(stderr, "getsocktop() returned invalid size.\n"); + goto failed; + } + + if (error != 0) { + fprintf(stderr, "connect(): %s\n", strerror(error)); + goto failed; + } + + io = pa_iochannel_new(c->mainloop, c->fd, c->fd); + assert(io); + c->fd = -1; + c->callback(c, io, c->userdata); + + return; + +failed: + close(c->fd); + c->fd = -1; + c->callback(c, NULL, c->userdata); + return; +} + +static void connect_fixed_cb(struct pa_mainloop_api *m, void *id, void *userdata) { + struct pa_socket_client *c = userdata; + assert(m && c && c->fixed_source == id); + m->cancel_fixed(m, c->fixed_source); + c->fixed_source = NULL; + do_call(c); +} + +static void connect_io_cb(struct pa_mainloop_api*m, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { + struct pa_socket_client *c = userdata; + assert(m && c && c->io_source == id && fd >= 0); + m->cancel_io(m, c->io_source); + c->io_source = NULL; + do_call(c); +} + +static int do_connect(struct pa_socket_client *c, const struct sockaddr *sa, socklen_t len) { + int r; + assert(c && sa && len); + + pa_make_nonblock_fd(c->fd); + + if ((r = connect(c->fd, sa, len)) < 0) { + if (errno != EINPROGRESS) { + fprintf(stderr, "connect(): %s\n", strerror(errno)); + return -1; + } + + c->io_source = c->mainloop->source_io(c->mainloop, c->fd, PA_MAINLOOP_API_IO_EVENT_OUTPUT, connect_io_cb, c); + assert(c->io_source); + } else { + c->fixed_source = c->mainloop->source_fixed(c->mainloop, connect_fixed_cb, c); + assert(c->fixed_source); + } + + return 0; +} + +struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port) { + struct pa_socket_client *c; + struct sockaddr_in sa; + assert(m && address && port); + + c = pa_socket_client_new(m); + assert(c); + + if ((c->fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "socket(): %s\n", strerror(errno)); + goto fail; + } + + pa_socket_tcp_low_delay(c->fd); + + sa.sin_family = AF_INET; + sa.sin_port = htons(port); + sa.sin_addr.s_addr = htonl(address); + + if (do_connect(c, (struct sockaddr*) &sa, sizeof(sa)) < 0) + goto fail; + + return c; + +fail: + pa_socket_client_free(c); + return NULL; +} + +struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename) { + struct pa_socket_client *c; + struct sockaddr_un sa; + assert(m && filename); + + c = pa_socket_client_new(m); + assert(c); + + if ((c->fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "socket(): %s\n", strerror(errno)); + goto fail; + } + + pa_socket_low_delay(c->fd); + + sa.sun_family = AF_LOCAL; + strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); + sa.sun_path[sizeof(sa.sun_path) - 1] = 0; + + if (do_connect(c, (struct sockaddr*) &sa, sizeof(sa)) < 0) + goto fail; + + return c; + +fail: + pa_socket_client_free(c); + return NULL; +} + +struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) { + struct pa_socket_client *c; + assert(m && sa); + c = pa_socket_client_new(m); + assert(c); + + if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "socket(): %s\n", strerror(errno)); + goto fail; + } + + if (sa->sa_family == AF_INET) + pa_socket_tcp_low_delay(c->fd); + else + pa_socket_low_delay(c->fd); + + if (do_connect(c, sa, salen) < 0) + goto fail; + + return c; + +fail: + pa_socket_client_free(c); + return NULL; + +} + +void pa_socket_client_free(struct pa_socket_client *c) { + assert(c && c->mainloop); + if (c->io_source) + c->mainloop->cancel_io(c->mainloop, c->io_source); + if (c->fixed_source) + c->mainloop->cancel_fixed(c->mainloop, c->fixed_source); + if (c->fd >= 0) + close(c->fd); + free(c); +} + +void pa_socket_client_set_callback(struct pa_socket_client *c, void (*on_connection)(struct pa_socket_client *c, struct pa_iochannel*io, void *userdata), void *userdata) { + assert(c); + c->callback = on_connection; + c->userdata = userdata; +} diff --git a/polyp/socket-client.h b/polyp/socket-client.h new file mode 100644 index 00000000..2a89210e --- /dev/null +++ b/polyp/socket-client.h @@ -0,0 +1,41 @@ +#ifndef foosocketclienthfoo +#define foosocketclienthfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include "mainloop-api.h" +#include "iochannel.h" + +/* It is safe to destroy the calling socket_client object from the callback */ + +struct pa_socket_client; + +struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port); +struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename); +struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m, const struct sockaddr *sa, size_t salen); + +void pa_socket_client_free(struct pa_socket_client *c); + +void pa_socket_client_set_callback(struct pa_socket_client *c, void (*on_connection)(struct pa_socket_client *c, struct pa_iochannel*io, void *userdata), void *userdata); + +#endif diff --git a/polyp/socket-server.c b/polyp/socket-server.c new file mode 100644 index 00000000..0f497377 --- /dev/null +++ b/polyp/socket-server.c @@ -0,0 +1,209 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "socket-server.h" +#include "socket-util.h" + +struct pa_socket_server { + int fd; + char *filename; + + void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata); + void *userdata; + + void *mainloop_source; + struct pa_mainloop_api *mainloop; + enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX } type; +}; + +static void callback(struct pa_mainloop_api *mainloop, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { + struct pa_socket_server *s = userdata; + struct pa_iochannel *io; + int nfd; + assert(s && s->mainloop == mainloop && s->mainloop_source == id && id && fd >= 0 && fd == s->fd && events == PA_MAINLOOP_API_IO_EVENT_INPUT); + + if ((nfd = accept(fd, NULL, NULL)) < 0) { + fprintf(stderr, "accept(): %s\n", strerror(errno)); + return; + } + + if (!s->on_connection) { + close(nfd); + return; + } + + /* There should be a check for socket type here */ + if (s->type == SOCKET_SERVER_IPV4) + pa_socket_tcp_low_delay(fd); + else + pa_socket_low_delay(fd); + + io = pa_iochannel_new(s->mainloop, nfd, nfd); + assert(io); + s->on_connection(s, io, s->userdata); +} + +struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd) { + struct pa_socket_server *s; + assert(m && fd >= 0); + + s = malloc(sizeof(struct pa_socket_server)); + assert(s); + s->fd = fd; + s->filename = NULL; + s->on_connection = NULL; + s->userdata = NULL; + + s->mainloop = m; + s->mainloop_source = m->source_io(m, fd, PA_MAINLOOP_API_IO_EVENT_INPUT, callback, s); + assert(s->mainloop_source); + + s->type = SOCKET_SERVER_GENERIC; + + return s; +} + +struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename) { + int fd = -1; + struct sockaddr_un sa; + struct pa_socket_server *s; + + assert(m && filename); + + if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "socket(): %s\n", strerror(errno)); + goto fail; + } + + sa.sun_family = AF_LOCAL; + strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); + sa.sun_path[sizeof(sa.sun_path) - 1] = 0; + + pa_socket_low_delay(fd); + + if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) { + fprintf(stderr, "bind(): %s\n", strerror(errno)); + goto fail; + } + + if (listen(fd, 5) < 0) { + fprintf(stderr, "listen(): %s\n", strerror(errno)); + goto fail; + } + + s = pa_socket_server_new(m, fd); + assert(s); + + s->filename = strdup(filename); + assert(s->filename); + + s->type = SOCKET_SERVER_UNIX; + + return s; + +fail: + if (fd >= 0) + close(fd); + + return NULL; +} + +struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port) { + struct pa_socket_server *ss; + int fd = -1; + struct sockaddr_in sa; + int on = 1; + + assert(m && port); + + if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "socket(): %s\n", strerror(errno)); + goto fail; + } + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) + fprintf(stderr, "setsockopt(): %s\n", strerror(errno)); + + pa_socket_tcp_low_delay(fd); + + sa.sin_family = AF_INET; + sa.sin_port = htons(port); + sa.sin_addr.s_addr = htonl(address); + + if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { + fprintf(stderr, "bind(): %s\n", strerror(errno)); + goto fail; + } + + if (listen(fd, 5) < 0) { + fprintf(stderr, "listen(): %s\n", strerror(errno)); + goto fail; + } + + if ((ss = pa_socket_server_new(m, fd))) + ss->type = SOCKET_SERVER_IPV4; + + return ss; + +fail: + if (fd >= 0) + close(fd); + + return NULL; +} + +void pa_socket_server_free(struct pa_socket_server*s) { + assert(s); + close(s->fd); + + if (s->filename) { + unlink(s->filename); + free(s->filename); + } + + + s->mainloop->cancel_io(s->mainloop, s->mainloop_source); + + free(s); +} + +void pa_socket_server_set_callback(struct pa_socket_server*s, void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata), void *userdata) { + assert(s); + + s->on_connection = on_connection; + s->userdata = userdata; +} diff --git a/polyp/socket-server.h b/polyp/socket-server.h new file mode 100644 index 00000000..6661a66e --- /dev/null +++ b/polyp/socket-server.h @@ -0,0 +1,41 @@ +#ifndef foosocketserverhfoo +#define foosocketserverhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include "mainloop-api.h" +#include "iochannel.h" + +/* It is safe to destroy the calling socket_server object from the callback */ + +struct pa_socket_server; + +struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd); +struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename); +struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port); + +void pa_socket_server_free(struct pa_socket_server*s); + +void pa_socket_server_set_callback(struct pa_socket_server*s, void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata), void *userdata); + +#endif diff --git a/polyp/socket-util.c b/polyp/socket-util.c new file mode 100644 index 00000000..e0a3c28d --- /dev/null +++ b/polyp/socket-util.c @@ -0,0 +1,216 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "socket-util.h" +#include "util.h" + +void pa_socket_peer_to_string(int fd, char *c, size_t l) { + struct stat st; + + assert(c && l && fd >= 0); + + if (fstat(fd, &st) < 0) { + snprintf(c, l, "Invalid client fd"); + return; + } + + if (S_ISSOCK(st.st_mode)) { + union { + struct sockaddr sa; + struct sockaddr_in in; + struct sockaddr_un un; + } sa; + socklen_t sa_len = sizeof(sa); + + if (getpeername(fd, &sa.sa, &sa_len) >= 0) { + + if (sa.sa.sa_family == AF_INET) { + uint32_t ip = ntohl(sa.in.sin_addr.s_addr); + + snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u", + ip >> 24, + (ip >> 16) & 0xFF, + (ip >> 8) & 0xFF, + ip & 0xFF, + ntohs(sa.in.sin_port)); + return; + } else if (sa.sa.sa_family == AF_LOCAL) { + snprintf(c, l, "UNIX socket client"); + return; + } + + } + snprintf(c, l, "Unknown network client"); + return; + } else if (S_ISCHR(st.st_mode) && (fd == 0 || fd == 1)) { + snprintf(c, l, "STDIN/STDOUT client"); + return; + } + + snprintf(c, l, "Unknown client"); +} + +int pa_socket_low_delay(int fd) { + int priority; + assert(fd >= 0); + + priority = 7; + if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) + return -1; + + return 0; +} + +int pa_socket_tcp_low_delay(int fd) { + int ret, tos; + + assert(fd >= 0); + + ret = pa_socket_low_delay(fd); + +/* on = 1; */ +/* if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) */ +/* ret = -1; */ + + tos = IPTOS_LOWDELAY; + if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0) + ret = -1; + + return ret; + +} + +int pa_socket_set_rcvbuf(int fd, size_t l) { + assert(fd >= 0); + + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &l, sizeof(l)) < 0) + return -1; + + return 0; +} + +int pa_socket_set_sndbuf(int fd, size_t l) { + assert(fd >= 0); + + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &l, sizeof(l)) < 0) + return -1; + + return 0; +} + +int pa_unix_socket_is_stale(const char *fn) { + struct sockaddr_un sa; + int fd = -1, ret = -1; + + if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "socket(): %s\n", strerror(errno)); + goto finish; + } + + sa.sun_family = AF_LOCAL; + strncpy(sa.sun_path, fn, sizeof(sa.sun_path)-1); + sa.sun_path[sizeof(sa.sun_path) - 1] = 0; + + if (connect(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) { + if (errno == ECONNREFUSED) + ret = 1; + } else + ret = 0; + +finish: + if (fd >= 0) + close(fd); + + return ret; +} + +int pa_unix_socket_remove_stale(const char *fn) { + int r; + + if ((r = pa_unix_socket_is_stale(fn)) < 0) + return errno != ENOENT ? -1 : 0; + + if (!r) + return 0; + + /* Yes, here is a race condition. But who cares? */ + if (unlink(fn) < 0) + return -1; + + return 0; +} + +int pa_unix_socket_make_secure_dir(const char *fn) { + int ret = -1; + char *slash, *dir = strdup(fn); + assert(dir); + + if (!(slash = strrchr(dir, '/'))) + goto finish; + *slash = 0; + + if (pa_make_secure_dir(dir) < 0) + goto finish; + + ret = 0; + +finish: + free(dir); + return ret; +} + +int pa_unix_socket_remove_secure_dir(const char *fn) { + int ret = -1; + char *slash, *dir = strdup(fn); + assert(dir); + + if (!(slash = strrchr(dir, '/'))) + goto finish; + *slash = 0; + + if (rmdir(dir) < 0) + goto finish; + + ret = 0; + +finish: + free(dir); + return ret; +} diff --git a/polyp/socket-util.h b/polyp/socket-util.h new file mode 100644 index 00000000..85133feb --- /dev/null +++ b/polyp/socket-util.h @@ -0,0 +1,41 @@ +#ifndef foosocketutilhfoo +#define foosocketutilhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +void pa_socket_peer_to_string(int fd, char *c, size_t l); + +int pa_socket_low_delay(int fd); +int pa_socket_tcp_low_delay(int fd); + +int pa_socket_set_sndbuf(int fd, size_t l); +int pa_socket_set_rcvbuf(int fd, size_t l); + +int pa_unix_socket_is_stale(const char *fn); +int pa_unix_socket_remove_stale(const char *fn); + +int pa_unix_socket_make_secure_dir(const char *fn); +int pa_unix_socket_remove_secure_dir(const char *fn); + +#endif diff --git a/polyp/source-output.c b/polyp/source-output.c new file mode 100644 index 00000000..2705fdb3 --- /dev/null +++ b/polyp/source-output.c @@ -0,0 +1,101 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "source-output.h" + +struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec) { + struct pa_source_output *o; + struct pa_resampler *resampler = NULL; + int r; + assert(s && spec); + + if (!pa_sample_spec_equal(&s->sample_spec, spec)) + if (!(resampler = pa_resampler_new(&s->sample_spec, spec))) + return NULL; + + o = malloc(sizeof(struct pa_source_output)); + assert(o); + o->name = name ? strdup(name) : NULL; + o->client = NULL; + o->owner = NULL; + o->source = s; + o->sample_spec = *spec; + + o->push = NULL; + o->kill = NULL; + o->userdata = NULL; + o->resampler = resampler; + + assert(s->core); + r = pa_idxset_put(s->core->source_outputs, o, &o->index); + assert(r == 0 && o->index != PA_IDXSET_INVALID); + r = pa_idxset_put(s->outputs, o, NULL); + assert(r == 0); + + return o; +} + +void pa_source_output_free(struct pa_source_output* o) { + assert(o); + + assert(o->source && o->source->core); + pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); + pa_idxset_remove_by_data(o->source->outputs, o, NULL); + + if (o->resampler) + pa_resampler_free(o->resampler); + + free(o->name); + free(o); +} + +void pa_source_output_kill(struct pa_source_output*i) { + assert(i); + + if (i->kill) + i->kill(i); +} + +void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk *chunk) { + struct pa_memchunk rchunk; + assert(o && chunk && chunk->length && o->push); + + if (!o->resampler) { + o->push(o, chunk); + return; + } + + pa_resampler_run(o->resampler, chunk, &rchunk); + if (!rchunk.length) + return; + + assert(rchunk.memblock); + o->push(o, &rchunk); + pa_memblock_unref(rchunk.memblock); +} diff --git a/polyp/source-output.h b/polyp/source-output.h new file mode 100644 index 00000000..0e6e2cfd --- /dev/null +++ b/polyp/source-output.h @@ -0,0 +1,58 @@ +#ifndef foosourceoutputhfoo +#define foosourceoutputhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "source.h" +#include "sample.h" +#include "memblockq.h" +#include "resampler.h" +#include "module.h" +#include "client.h" + +struct pa_source_output { + uint32_t index; + + char *name; + struct pa_module *owner; + struct pa_client *client; + struct pa_source *source; + struct pa_sample_spec sample_spec; + + void (*push)(struct pa_source_output *o, const struct pa_memchunk *chunk); + void (*kill)(struct pa_source_output* o); + + struct pa_resampler* resampler; + + void *userdata; +}; + +struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec); +void pa_source_output_free(struct pa_source_output* o); + +void pa_source_output_kill(struct pa_source_output*o); + +void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk *chunk); + +#endif diff --git a/polyp/source.c b/polyp/source.c new file mode 100644 index 00000000..ccde0e2f --- /dev/null +++ b/polyp/source.c @@ -0,0 +1,131 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "source.h" +#include "source-output.h" +#include "namereg.h" + +struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec) { + struct pa_source *s; + char st[256]; + int r; + assert(core && spec && name); + + s = malloc(sizeof(struct pa_source)); + assert(s); + + if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SOURCE, s, fail))) { + free(s); + return NULL; + } + + s->name = strdup(name); + s->description = NULL; + + s->owner = NULL; + s->core = core; + s->sample_spec = *spec; + s->outputs = pa_idxset_new(NULL, NULL); + s->monitor_of = NULL; + + s->notify = NULL; + s->userdata = NULL; + + r = pa_idxset_put(core->sources, s, &s->index); + assert(s->index != PA_IDXSET_INVALID && r >= 0); + + pa_sample_snprint(st, sizeof(st), spec); + fprintf(stderr, "source: created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); + + return s; +} + +void pa_source_free(struct pa_source *s) { + struct pa_source_output *o, *j = NULL; + assert(s); + + pa_namereg_unregister(s->core, s->name); + + while ((o = pa_idxset_first(s->outputs, NULL))) { + assert(o != j); + pa_source_output_kill(o); + j = o; + } + pa_idxset_free(s->outputs, NULL, NULL); + + pa_idxset_remove_by_data(s->core->sources, s, NULL); + + fprintf(stderr, "source: freed %u \"%s\"\n", s->index, s->name); + + free(s->name); + free(s->description); + free(s); +} + +void pa_source_notify(struct pa_source*s) { + assert(s); + + if (s->notify) + s->notify(s); +} + +static int do_post(void *p, uint32_t index, int *del, void*userdata) { + struct pa_memchunk *chunk = userdata; + struct pa_source_output *o = p; + assert(o && o->push && del && chunk); + + pa_source_output_push(o, chunk); + return 0; +} + +void pa_source_post(struct pa_source*s, struct pa_memchunk *chunk) { + assert(s && chunk); + + pa_idxset_foreach(s->outputs, do_post, chunk); +} + +struct pa_source* pa_source_get_default(struct pa_core *c) { + struct pa_source *source; + assert(c); + + if ((source = pa_idxset_get_by_index(c->sources, c->default_source_index))) + return source; + + if (!(source = pa_idxset_first(c->sources, &c->default_source_index))) + return NULL; + + fprintf(stderr, "core: default source vanished, setting to %u.\n", source->index); + return source; +} + +void pa_source_set_owner(struct pa_source *s, struct pa_module *m) { + assert(s); + s->owner = m; +} diff --git a/polyp/source.h b/polyp/source.h new file mode 100644 index 00000000..9c584a6d --- /dev/null +++ b/polyp/source.h @@ -0,0 +1,61 @@ +#ifndef foosourcehfoo +#define foosourcehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +struct pa_source; + +#include +#include "core.h" +#include "sample.h" +#include "idxset.h" +#include "memblock.h" +#include "memchunk.h" +#include "sink.h" + +struct pa_source { + uint32_t index; + + char *name, *description; + struct pa_module *owner; + 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; +}; + +struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec); +void pa_source_free(struct pa_source *s); + +/* Pass a new memory block to all output streams */ +void pa_source_post(struct pa_source*s, struct pa_memchunk *b); + +void pa_source_notify(struct pa_source *s); + +struct pa_source* pa_source_get_default(struct pa_core *c); + +void pa_source_set_owner(struct pa_source *s, struct pa_module *m); + +#endif diff --git a/polyp/strbuf.c b/polyp/strbuf.c new file mode 100644 index 00000000..c6a3772d --- /dev/null +++ b/polyp/strbuf.c @@ -0,0 +1,164 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "strbuf.h" + +struct chunk { + struct chunk *next; + size_t length; + char text[]; +}; + +struct pa_strbuf { + size_t length; + struct chunk *head, *tail; +}; + +struct pa_strbuf *pa_strbuf_new(void) { + struct pa_strbuf *sb = malloc(sizeof(struct pa_strbuf)); + assert(sb); + sb->length = 0; + sb->head = sb->tail = NULL; + return sb; +} + +void pa_strbuf_free(struct pa_strbuf *sb) { + assert(sb); + while (sb->head) { + struct chunk *c = sb->head; + sb->head = sb->head->next; + free(c); + } + + free(sb); +} + +char *pa_strbuf_tostring(struct pa_strbuf *sb) { + char *t, *e; + struct chunk *c; + assert(sb); + + t = malloc(sb->length+1); + assert(t); + + e = t; + for (c = sb->head; c; c = c->next) { + memcpy(e, c->text, c->length); + e += c->length; + } + + *e = 0; + + return t; +} + +char *pa_strbuf_tostring_free(struct pa_strbuf *sb) { + char *t; + assert(sb); + t = pa_strbuf_tostring(sb); + pa_strbuf_free(sb); + return t; +} + +void pa_strbuf_puts(struct pa_strbuf *sb, const char *t) { + assert(sb && t); + pa_strbuf_putsn(sb, t, 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); + + c->next = NULL; + c->length = l; + memcpy(c->text, t, l); + + if (sb->tail) { + assert(sb->head); + sb->tail->next = c; + } else { + assert(!sb->head); + sb->head = c; + } + + sb->tail = c; + sb->length += l; +} + +/* The following is based on an example from the GNU libc documentation */ + +int pa_strbuf_printf(struct pa_strbuf *sb, const char *format, ...) { + int r, size = 100; + struct chunk *c = NULL; + + assert(sb); + + for(;;) { + va_list ap; + + c = realloc(c, sizeof(struct chunk)+size); + assert(c); + + va_start(ap, format); + r = vsnprintf(c->text, size, format, ap); + va_end(ap); + + if (r > -1 && r < size) { + c->length = r; + c->next = NULL; + + if (sb->tail) { + assert(sb->head); + sb->tail->next = c; + } else { + assert(!sb->head); + sb->head = c; + } + + sb->tail = c; + sb->length += r; + + return r; + } + + if (r > -1) /* glibc 2.1 */ + size = r+1; + else /* glibc 2.0 */ + size *= 2; + } +} diff --git a/polyp/strbuf.h b/polyp/strbuf.h new file mode 100644 index 00000000..d672c42a --- /dev/null +++ b/polyp/strbuf.h @@ -0,0 +1,36 @@ +#ifndef foostrbufhfoo +#define foostrbufhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +struct pa_strbuf; + +struct pa_strbuf *pa_strbuf_new(void); +void pa_strbuf_free(struct pa_strbuf *sb); +char *pa_strbuf_tostring(struct pa_strbuf *sb); +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 diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c new file mode 100644 index 00000000..0d93c1e9 --- /dev/null +++ b/polyp/tagstruct.c @@ -0,0 +1,241 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "tagstruct.h" + +enum tags { + TAG_STRING = 't', + TAG_U32 = 'L', + TAG_S32 = 'l', + TAG_U16 = 'S', + TAG_S16 = 's', + TAG_U8 = 'B', + TAG_S8 = 'b', + TAG_SAMPLE_SPEC = 'a', + TAG_ARBITRARY = 'x' +}; + +struct pa_tagstruct { + uint8_t *data; + size_t length, allocated; + size_t rindex; + + int dynamic; +}; + +struct pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) { + struct pa_tagstruct*t; + + assert(!data || (data && length)); + + t = malloc(sizeof(struct pa_tagstruct)); + assert(t); + t->data = (uint8_t*) data; + t->allocated = t->length = data ? length : 0; + t->rindex = 0; + t->dynamic = !data; + return t; +} + +void pa_tagstruct_free(struct pa_tagstruct*t) { + assert(t); + if (t->dynamic) + free(t->data); + free(t); +} + +uint8_t* pa_tagstruct_free_data(struct pa_tagstruct*t, size_t *l) { + uint8_t *p; + assert(t && t->dynamic && l); + p = t->data; + *l = t->length; + free(t); + return p; +} + +static void extend(struct pa_tagstruct*t, size_t l) { + assert(t && t->dynamic); + + if (l <= t->allocated) + return; + + t->data = realloc(t->data, t->allocated = l+100); + assert(t->data); +} + +void pa_tagstruct_puts(struct pa_tagstruct*t, const char *s) { + size_t l; + assert(t && s); + l = strlen(s)+2; + extend(t, l); + t->data[t->length] = TAG_STRING; + strcpy(t->data+t->length+1, s); + t->length += l; +} + +void pa_tagstruct_putu32(struct pa_tagstruct*t, uint32_t i) { + assert(t); + extend(t, 5); + t->data[t->length] = TAG_U32; + *((uint32_t*) (t->data+t->length+1)) = htonl(i); + t->length += 5; +} + +void pa_tagstruct_putu8(struct pa_tagstruct*t, uint8_t c) { + assert(t); + extend(t, 2); + t->data[t->length] = TAG_U8; + *(t->data+t->length+1) = c; + t->length += 2; +} + +void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample_spec *ss) { + assert(t && ss); + extend(t, 7); + t->data[t->length] = TAG_SAMPLE_SPEC; + t->data[t->length+1] = (uint8_t) ss->format; + t->data[t->length+2] = ss->channels; + *(uint32_t*) (t->data+t->length+3) = htonl(ss->rate); + t->length += 7; +} + + +void pa_tagstruct_put_arbitrary(struct pa_tagstruct *t, const void *p, size_t length) { + assert(t && p); + + extend(t, 5+length); + t->data[t->length] = TAG_ARBITRARY; + *((uint32_t*) (t->data+t->length+1)) = htonl(length); + if (length) + memcpy(t->data+t->length+5, p, length); + t->length += 5+length; +} + +int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s) { + int error = 0; + size_t n; + char *c; + assert(t && s); + + if (t->rindex+2 > t->length) + return -1; + + if (t->data[t->rindex] != TAG_STRING) + return -1; + + error = 1; + for (n = 0, c = (char*) (t->data+t->rindex+1); t->rindex+1+n < t->length; n++, c++) + if (!*c) { + error = 0; + break; + } + + if (error) + return -1; + + *s = (char*) (t->data+t->rindex+1); + + t->rindex += n+2; + return 0; +} + +int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i) { + assert(t && i); + + if (t->rindex+5 > t->length) + return -1; + + if (t->data[t->rindex] != TAG_U32) + return -1; + + *i = ntohl(*((uint32_t*) (t->data+t->rindex+1))); + t->rindex += 5; + return 0; +} + +int pa_tagstruct_getu8(struct pa_tagstruct*t, uint8_t *c) { + assert(t && c); + + if (t->rindex+2 > t->length) + return -1; + + if (t->data[t->rindex] != TAG_U8) + return -1; + + *c = t->data[t->rindex+1]; + t->rindex +=2; + return 0; +} + +int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec *ss) { + assert(t && ss); + + if (t->rindex+7 > t->length) + return -1; + + if (t->data[t->rindex] != TAG_SAMPLE_SPEC) + return -1; + + ss->format = t->data[t->rindex+1]; + ss->channels = t->data[t->rindex+2]; + ss->rate = ntohl(*(uint32_t*) (t->data+t->rindex+3)); + + t->rindex += 7; + return 0; +} + +int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t length) { + assert(t && p); + + if (t->rindex+5+length > t->length) + return -1; + + if (t->data[t->rindex] != TAG_ARBITRARY) + return -1; + + if (ntohl(*((uint32_t*) (t->data+t->rindex+1))) != length) + return -1; + + *p = t->data+t->rindex+5; + t->rindex += 5+length; + return 0; +} + +int pa_tagstruct_eof(struct pa_tagstruct*t) { + assert(t); + return t->rindex >= t->length; +} + +const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l) { + assert(t && t->dynamic && l); + *l = t->length; + return t->data; +} + diff --git a/polyp/tagstruct.h b/polyp/tagstruct.h new file mode 100644 index 00000000..aefd03c4 --- /dev/null +++ b/polyp/tagstruct.h @@ -0,0 +1,53 @@ +#ifndef footagstructhfoo +#define footagstructhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include "sample.h" + +struct pa_tagstruct; + +struct pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length); +void pa_tagstruct_free(struct pa_tagstruct*t); +uint8_t* pa_tagstruct_free_data(struct pa_tagstruct*t, size_t *l); + +void pa_tagstruct_puts(struct pa_tagstruct*t, const char *s); +void pa_tagstruct_putu32(struct pa_tagstruct*t, uint32_t i); +void pa_tagstruct_putu8(struct pa_tagstruct*t, uint8_t c); +void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample_spec *ss); +void pa_tagstruct_put_arbitrary(struct pa_tagstruct*t, const void *p, size_t length); + +int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s); +int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i); +int pa_tagstruct_getu8(struct pa_tagstruct*t, uint8_t *c); +int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec *ss); +int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t length); + +int pa_tagstruct_eof(struct pa_tagstruct*t); +const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l); + + + +#endif diff --git a/polyp/tokenizer.c b/polyp/tokenizer.c new file mode 100644 index 00000000..c7f18d26 --- /dev/null +++ b/polyp/tokenizer.c @@ -0,0 +1,89 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "tokenizer.h" +#include "dynarray.h" + +struct pa_tokenizer { + struct pa_dynarray *dynarray; +}; + +static void token_free(void *p, void *userdata) { + free(p); +} + +static void parse(struct pa_dynarray*a, const char *s, unsigned args) { + int infty = 0; + const char delimiter[] = " \t\n\r"; + const char *p; + assert(a && s); + + if (args == 0) + infty = 1; + + p = s+strspn(s, delimiter); + while (*p && (infty || args >= 2)) { + size_t l = strcspn(p, delimiter); + char *n = strndup(p, l); + assert(n); + pa_dynarray_append(a, n); + p += l; + p += strspn(p, delimiter); + args--; + } + + if (args && *p) { + char *n = strdup(p); + assert(n); + pa_dynarray_append(a, n); + } +} + +struct pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args) { + struct pa_tokenizer *t; + + t = malloc(sizeof(struct pa_tokenizer)); + assert(t); + t->dynarray = pa_dynarray_new(); + assert(t->dynarray); + + parse(t->dynarray, s, args); + return t; +} + +void pa_tokenizer_free(struct pa_tokenizer *t) { + assert(t); + pa_dynarray_free(t->dynarray, token_free, NULL); + free(t); +} + +const char *pa_tokenizer_get(struct pa_tokenizer *t, unsigned i) { + assert(t); + return pa_dynarray_get(t->dynarray, i); +} diff --git a/polyp/tokenizer.h b/polyp/tokenizer.h new file mode 100644 index 00000000..7d1cf9b5 --- /dev/null +++ b/polyp/tokenizer.h @@ -0,0 +1,32 @@ +#ifndef footokenizerhfoo +#define footokenizerhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +struct pa_tokenizer; + +struct pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args); +void pa_tokenizer_free(struct pa_tokenizer *t); + +const char *pa_tokenizer_get(struct pa_tokenizer *t, unsigned i); + +#endif diff --git a/polyp/util.c b/polyp/util.c new file mode 100644 index 00000000..6e75c240 --- /dev/null +++ b/polyp/util.c @@ -0,0 +1,147 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" + +void pa_make_nonblock_fd(int fd) { + int v; + + if ((v = fcntl(fd, F_GETFL)) >= 0) + if (!(v & O_NONBLOCK)) + fcntl(fd, F_SETFL, v|O_NONBLOCK); +} + +int pa_make_secure_dir(const char* dir) { + struct stat st; + + if (mkdir(dir, 0700) < 0) + if (errno != EEXIST) + return -1; + + if (lstat(dir, &st) < 0) + goto fail; + + if (!S_ISDIR(st.st_mode) || (st.st_uid != getuid()) || ((st.st_mode & 0777) != 0700)) + goto fail; + + return 0; + +fail: + rmdir(dir); + return -1; +} + +ssize_t pa_loop_read(int fd, void*data, size_t size) { + ssize_t ret = 0; + assert(fd >= 0 && data && size); + + while (size > 0) { + ssize_t r; + + if ((r = read(fd, data, size)) < 0) + return r; + + if (r == 0) + break; + + ret += r; + data += r; + size -= r; + } + + return ret; +} + +ssize_t pa_loop_write(int fd, const void*data, size_t size) { + ssize_t ret = 0; + assert(fd >= 0 && data && size); + + while (size > 0) { + ssize_t r; + + if ((r = write(fd, data, size)) < 0) + return r; + + if (r == 0) + break; + + ret += r; + data += r; + size -= r; + } + + return ret; +} + +void pa_check_for_sigpipe(void) { + struct sigaction sa; + + if (sigaction(SIGPIPE, NULL, &sa) < 0) { + fprintf(stderr, __FILE__": sigaction() failed: %s\n", strerror(errno)); + return; + } + + if (sa.sa_handler == SIG_DFL) + fprintf(stderr, "polypaudio: WARNING: SIGPIPE is not trapped. This might cause malfunction!\n"); +} + +/* The following is based on an example from the GNU libc documentation */ +char *pa_sprintf_malloc(const char *format, ...) { + int size = 100; + char *c = NULL; + + assert(format); + + for(;;) { + int r; + va_list ap; + + c = realloc(c, size); + assert(c); + + va_start(ap, format); + r = vsnprintf(c, size, format, ap); + va_end(ap); + + if (r > -1 && r < size) + return c; + + if (r > -1) /* glibc 2.1 */ + size = r+1; + else /* glibc 2.0 */ + size *= 2; + } +} diff --git a/polyp/util.h b/polyp/util.h new file mode 100644 index 00000000..96fde11c --- /dev/null +++ b/polyp/util.h @@ -0,0 +1,38 @@ +#ifndef fooutilhfoo +#define fooutilhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +void pa_make_nonblock_fd(int fd); + +int pa_make_secure_dir(const char* dir); + +ssize_t pa_loop_read(int fd, void*data, size_t size); +ssize_t pa_loop_write(int fd, const void*data, size_t size); + +void pa_check_for_sigpipe(void); + +char *pa_sprintf_malloc(const char *format, ...) __attribute__ ((format (printf, 1, 2))); + +#endif diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index c4da7342..00000000 --- a/src/Makefile.am +++ /dev/null @@ -1,363 +0,0 @@ -# $Id$ -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with polypaudio; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -AM_CFLAGS=-ansi -D_GNU_SOURCE - -EXTRA_DIST = polypaudio.run depmod.py -bin_PROGRAMS = polypaudio pacat pactl -noinst_PROGRAMS = pacat-simple parec-simple - -pkginclude_HEADERS=polyplib.h \ - polyplib-def.h \ - polyplib-simple.h \ - polyplib-error.h \ - mainloop-api.h \ - mainloop.h \ - mainloop-signal.h \ - sample.h - -pkglib_LTLIBRARIES=libiochannel.la \ - libsocket-server.la \ - libsocket-client.la \ - libpstream.la \ - libpacket.la \ - liboss-util.la \ - libalsa-util.la \ - libioline.la \ - libcli.la \ - libprotocol-cli.la \ - libtagstruct.la \ - libpstream-util.la \ - libpdispatch.la \ - libauthkey.la \ - libsocket-util.la \ - libprotocol-simple.la \ - libprotocol-esound.la \ - libprotocol-native.la \ - module-cli.la \ - module-cli-protocol-tcp.la \ - module-cli-protocol-unix.la \ - module-pipe-sink.la \ - module-alsa-sink.la \ - module-alsa-source.la \ - module-oss.la \ - module-oss-mmap.la \ - module-simple-protocol-tcp.la \ - module-simple-protocol-unix.la \ - module-esound-protocol-tcp.la \ - module-esound-protocol-unix.la \ - module-native-protocol-tcp.la \ - module-native-protocol-unix.la - -lib_LTLIBRARIES=libpolyp.la \ - libpolyp-simple.la \ - libpolyp-error.la \ - libpolyp-mainloop.la - -polypaudio_SOURCES = idxset.c idxset.h \ - queue.c queue.h \ - strbuf.c strbuf.h \ - main.c \ - mainloop.c mainloop.h \ - memblock.c memblock.h \ - sample.c sample.h \ - sample-util.c sample-util.h \ - memblockq.c memblockq.h \ - client.c client.h \ - core.c core.h \ - source-output.c source-output.h \ - sink-input.c sink-input.h \ - source.c source.h \ - sink.c sink.h \ - module.c module.h \ - mainloop-signal.c mainloop-signal.h \ - mainloop-api.c mainloop-api.h \ - util.c util.h \ - hashmap.c hashmap.h \ - namereg.c namereg.h \ - sconv.c sconv.h \ - resampler.c resampler.h \ - endianmacros.h \ - memchunk.c memchunk.h \ - sconv-s16le.c sconv-s16le.h \ - sconv-s16be.c sconv-s16be.h \ - sioman.c sioman.h \ - modargs.c modargs.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) -polypaudio_LDADD = $(LIBLTDL) $(LIBSAMPLERATE_LIBS) -polypaudio_LDFLAGS=-export-dynamic - -libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h -libprotocol_simple_la_LDFLAGS = -avoid-version -libprotocol_simple_la_LIBADD = libsocket-server.la libiochannel.la - -libsocket_server_la_SOURCES = socket-server.c socket-server.h -libsocket_server_la_LDFLAGS = -avoid-version -libsocket_server_la_LIBADD = libiochannel.la libsocket-util.la - -libsocket_client_la_SOURCES = socket-client.c socket-client.h -libsocket_client_la_LDFLAGS = -avoid-version -libsocket_client_la_LIBADD = libiochannel.la libsocket-util.la - -libpstream_la_SOURCES = pstream.c pstream.h -libpstream_la_LDFLAGS = -avoid-version -libpstream_la_LIBADD = libpacket.la libiochannel.la - -libpstream_util_la_SOURCES = pstream-util.c pstream-util.h -libpstream_util_la_LDFLAGS = -avoid-version -libpstream_util_la_LIBADD = libpacket.la libpstream.la libtagstruct.la - -libpdispatch_la_SOURCES = pdispatch.c pdispatch.h -libpdispatch_la_LDFLAGS = -avoid-version -libpdispatch_la_LIBADD = libtagstruct.la - -libiochannel_la_SOURCES = iochannel.c iochannel.h -libiochannel_la_LDFLAGS = -avoid-version -libiochannel_la_LIBADD = libsocket-util.la - -libpacket_la_SOURCES = packet.c packet.h -libpacket_la_LDFLAGS = -avoid-version - -liboss_util_la_SOURCES = oss-util.c oss-util.h -liboss_util_la_LDFLAGS = -avoid-version - -libalsa_util_la_SOURCES = alsa-util.c alsa-util.h -libalsa_util_la_LDFLAGS = -avoid-version -libalsa_util_la_LIBADD = $(ASOUNDLIB_LIBS) -libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) - -libioline_la_SOURCES = ioline.c ioline.h -libioline_la_LDFLAGS = -avoid-version -libioline_la_LIBADD = libiochannel.la - -libcli_la_SOURCES = cli.c cli.h -libcli_la_LDFLAGS = -avoid-version -libcli_la_LIBADD = libiochannel.la libioline.la - -libprotocol_cli_la_SOURCES = protocol-cli.c protocol-cli.h -libprotocol_cli_la_LDFLAGS = -avoid-version -libprotocol_cli_la_LIBADD = libsocket-server.la libiochannel.la libcli.la - -libprotocol_native_la_SOURCES = protocol-native.c protocol-native.h native-common.h -libprotocol_native_la_LDFLAGS = -avoid-version -libprotocol_native_la_LIBADD = libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la - -libtagstruct_la_SOURCES = tagstruct.c tagstruct.h -libtagstruct_la_LDFLAGS = -avoid-version - -libprotocol_esound_la_SOURCES = protocol-esound.c protocol-esound.h esound.h -libprotocol_esound_la_LDFLAGS = -avoid-version -libprotocol_esound_la_LIBADD = libsocket-server.la libiochannel.la libauthkey.la - -libauthkey_la_SOURCES = authkey.c authkey.h -libauthkey_la_LDFLAGS = -avoid-version - -libsocket_util_la_SOURCES = socket-util.c socket-util.h -libsocket_util_la_LDFLAGS = -avoid-version - -module_simple_protocol_tcp_la_SOURCES = module-protocol-stub.c -module_simple_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) -module_simple_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_simple_protocol_tcp_la_LIBADD = libprotocol-simple.la libsocket-server.la - -module_simple_protocol_unix_la_SOURCES = module-protocol-stub.c -module_simple_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) -module_simple_protocol_unix_la_LDFLAGS = -module -avoid-version -module_simple_protocol_unix_la_LIBADD = libprotocol-simple.la libsocket-server.la libsocket-util.la - -module_cli_protocol_tcp_la_SOURCES = module-protocol-stub.c -module_cli_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) -module_cli_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_cli_protocol_tcp_la_LIBADD = libprotocol-cli.la libsocket-server.la - -module_cli_protocol_unix_la_SOURCES = module-protocol-stub.c -module_cli_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) -module_cli_protocol_unix_la_LDFLAGS = -module -avoid-version -module_cli_protocol_unix_la_LIBADD = libprotocol-cli.la libsocket-server.la libsocket-util.la - -module_native_protocol_tcp_la_SOURCES = module-protocol-stub.c -module_native_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) -module_native_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_native_protocol_tcp_la_LIBADD = libprotocol-native.la libsocket-server.la - -module_native_protocol_unix_la_SOURCES = module-protocol-stub.c -module_native_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) -module_native_protocol_unix_la_LDFLAGS = -module -avoid-version -module_native_protocol_unix_la_LIBADD = libprotocol-native.la libsocket-server.la libsocket-util.la - -module_esound_protocol_tcp_la_SOURCES = module-protocol-stub.c -module_esound_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) -module_esound_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_esound_protocol_tcp_la_LIBADD = libprotocol-esound.la libsocket-server.la - -module_esound_protocol_unix_la_SOURCES = module-protocol-stub.c -module_esound_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) -module_esound_protocol_unix_la_LDFLAGS = -module -avoid-version -module_esound_protocol_unix_la_LIBADD = libprotocol-esound.la libsocket-server.la libsocket-util.la - -module_pipe_sink_la_SOURCES = module-pipe-sink.c -module_pipe_sink_la_LDFLAGS = -module -avoid-version -module_pipe_sink_la_LIBADD = libiochannel.la - -module_alsa_sink_la_SOURCES = module-alsa-sink.c -module_alsa_sink_la_LDFLAGS = -module -avoid-version -module_alsa_sink_la_LIBADD = $(ASOUNDLIB_LIBS) libalsa-util.la -module_alsa_sink_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) - -module_alsa_source_la_SOURCES = module-alsa-source.c -module_alsa_source_la_LDFLAGS = -module -avoid-version -module_alsa_source_la_LIBADD = $(ASOUNDLIB_LIBS) libalsa-util.la -module_alsa_source_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) - -module_oss_la_SOURCES = module-oss.c -module_oss_la_LDFLAGS = -module -avoid-version -module_oss_la_LIBADD = libiochannel.la liboss-util.la - -module_oss_mmap_la_SOURCES = module-oss-mmap.c -module_oss_mmap_la_LDFLAGS = -module -avoid-version -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 - -libpolyp_la_SOURCES = polyplib.c polyplib.h \ - polyplib-def.h \ - tagstruct.c tagstruct.h \ - iochannel.c iochannel.h \ - pstream.c pstream.h \ - pstream-util.c pstream-util.h \ - pdispatch.c pdispatch.h \ - mainloop-api.c mainloop-api.h \ - idxset.c idxset.h \ - util.c util.h \ - memblock.c memblock.h \ - socket-client.c socket-client.h \ - packet.c packet.h \ - queue.c queue.h \ - dynarray.c dynarray.h \ - memchunk.c memchunk.h \ - authkey.c authkey.h \ - socket-util.c socket-util.h \ - native-common.h -libpolyp_la_CFLAGS = $(AM_CFLAGS) - -libpolyp_mainloop_la_SOURCES = mainloop-api.h mainloop-api.c \ - mainloop.c mainloop.h \ - mainloop-signal.c mainloop-signal.h -libpolyp_mainloop_la_CFLAGS = $(AM_CFLAGS) - -libpolyp_error_la_SOURCES = polyplib-error.c polyplib-error.h -libpolyp_error_la_CFLAGS = $(AM_CFLAGS) - -libpolyp_simple_la_SOURCES = polyplib-simple.c polyplib-simple.h -libpolyp_simple_la_CFLAGS = $(AM_CFLAGS) -libpolyp_simple_la_LIBADD = libpolyp.la libpolyp-mainloop.la - -pacat_SOURCES = pacat.c -pacat_LDADD = libpolyp.la libpolyp-error.la libpolyp-mainloop.la -pacat_CFLAGS = $(AM_CFLAGS) - -pactl_SOURCES = pactl.c -pactl_LDADD = libpolyp.la libpolyp-error.la libpolyp-mainloop.la -pactl_CFLAGS = $(AM_CFLAGS) - -pacat_simple_SOURCES = pacat-simple.c -pacat_simple_LDADD = libpolyp-simple.la libpolyp-error.la -pacat_simple_CFLAGS = $(AM_CFLAGS) - -parec_simple_SOURCES = parec-simple.c -parec_simple_LDADD = libpolyp-simple.la libpolyp-error.la -parec_simple_CFLAGS = $(AM_CFLAGS) - -if BUILD_LIBPOLYPCORE - -pkginclude_HEADERS+=cli-command.h\ - client.h \ - core.h \ - dynarray.h \ - endianmacros.h \ - hashmap.h \ - idxset.h \ - iochannel.h \ - memblock.h \ - memblockq.h \ - memchunk.h \ - modargs.h \ - module.h \ - namereg.h \ - queue.h \ - resampler.h \ - sample-util.h \ - sink.h \ - sink-input.h \ - sioman.h \ - socket-server.h \ - socket-client.h \ - socket-util.h \ - source.h \ - source-output.h \ - strbuf.h \ - tokenizer.h \ - tagstruct.h \ - util.h - -lib_LTLIBRARIES+= libpolypcore.la - -libpolypcore_la_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 \ - sample-util.c sample-util.h \ - memblockq.c memblockq.h \ - client.c client.h \ - core.c core.h \ - source-output.c source-output.h \ - sink-input.c sink-input.h \ - source.c source.h \ - sink.c sink.h \ - module.c module.h \ - mainloop-signal.c mainloop-signal.h \ - mainloop-api.c mainloop-api.h \ - util.c util.h \ - hashmap.c hashmap.h \ - namereg.c namereg.h \ - sconv.c sconv.h \ - resampler.c resampler.h \ - endianmacros.h \ - memchunk.c memchunk.h \ - sconv-s16le.c sconv-s16le.h \ - sconv-s16be.c sconv-s16be.h \ - sioman.c sioman.h \ - modargs.c modargs.h \ - cli-command.c cli-command.h \ - clitext.c clitext.h \ - tokenizer.c tokenizer.h \ - dynarray.c dynarray.h - -endif diff --git a/src/alsa-util.c b/src/alsa-util.c deleted file mode 100644 index 7f266df5..00000000 --- a/src/alsa-util.c +++ /dev/null @@ -1,98 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "alsa-util.h" -#include "sample.h" - -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, struct pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *buffer_size) { - int ret = 0; - snd_pcm_hw_params_t *hwparams = NULL; - static const snd_pcm_format_t format_trans[] = { - [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8, - [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW, - [PA_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW, - [PA_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE, - [PA_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE, - [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE, - [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, - }; - - if (snd_pcm_hw_params_malloc(&hwparams) < 0 || - snd_pcm_hw_params_any(pcm_handle, hwparams) < 0 || - snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0 || - snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format]) < 0 || - snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &ss->rate, NULL) < 0 || - snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels) < 0 || - snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, periods, NULL) < 0 || - snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, buffer_size) < 0 || - snd_pcm_hw_params(pcm_handle, hwparams) < 0) { - ret = -1; - } - - if (hwparams) - snd_pcm_hw_params_free(hwparams); - return ret; -} - -int pa_create_io_sources(snd_pcm_t *pcm_handle, struct pa_mainloop_api* m, void ***io_sources, unsigned *n_io_sources, void (*cb)(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata), void *userdata) { - unsigned i; - struct pollfd *pfds, *ppfd; - void **ios; - assert(pcm_handle && m && io_sources && n_io_sources && cb); - - *n_io_sources = snd_pcm_poll_descriptors_count(pcm_handle); - - pfds = malloc(sizeof(struct pollfd) * *n_io_sources); - assert(pfds); - if (snd_pcm_poll_descriptors(pcm_handle, pfds, *n_io_sources) < 0) { - free(pfds); - return -1; - } - - *io_sources = malloc(sizeof(void*) * *n_io_sources); - assert(io_sources); - - for (i = 0, ios = *io_sources, ppfd = pfds; i < *n_io_sources; i++, ios++, ppfd++) { - *ios = m->source_io(m, ppfd->fd, - ((ppfd->events & POLLIN) ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | - ((ppfd->events & POLLOUT) ? PA_MAINLOOP_API_IO_EVENT_OUTPUT : 0), cb, userdata); - assert(*ios); - } - - free(pfds); - return 0; -} - -void pa_free_io_sources(struct pa_mainloop_api* m, void **io_sources, unsigned n_io_sources) { - unsigned i; - void **ios; - assert(m && io_sources); - - for (ios = io_sources, i = 0; i < n_io_sources; i++, ios++) - m->cancel_io(m, *ios); - free(io_sources); -} diff --git a/src/alsa-util.h b/src/alsa-util.h deleted file mode 100644 index 03e427d9..00000000 --- a/src/alsa-util.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef fooalsautilhfoo -#define fooalsautilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "sample.h" -#include "mainloop-api.h" - -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, struct pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *buffer_size); - -int pa_create_io_sources(snd_pcm_t *pcm_handle, struct pa_mainloop_api *m, void ***io_sources, unsigned *n_io_sources, void (*cb)(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata), void *userdata); -void pa_free_io_sources(struct pa_mainloop_api* m, void **io_sources, unsigned n_io_sources); - -#endif diff --git a/src/authkey.c b/src/authkey.c deleted file mode 100644 index 3180b8fd..00000000 --- a/src/authkey.c +++ /dev/null @@ -1,151 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "authkey.h" -#include "util.h" - -#define RANDOM_DEVICE "/dev/urandom" - -static int load(const char *fn, void *data, size_t length) { - int fd = -1, ret = -1; - ssize_t r; - - assert(fn && data && length); - - if ((fd = open(fn, O_RDONLY)) < 0) - goto finish; - - if ((r = pa_loop_read(fd, data, length)) < 0 || (size_t) r != length) { - ret = -2; - goto finish; - } - - ret = 0; - -finish: - if (fd >= 0) - close(fd); - - return ret; -} - -static int generate(const char *fn, void *data, size_t length) { - int fd = -1, random_fd = -1, ret = -1; - ssize_t r; - assert(fn && data && length); - - if ((fd = open(fn, O_WRONLY|O_EXCL|O_CREAT, S_IRUSR | S_IWUSR)) < 0) - goto finish; - - if ((random_fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) { - - if ((r = pa_loop_read(random_fd, data, length)) < 0 || (size_t) r != length) { - ret = -2; - goto finish; - } - - } else { - uint8_t *p; - size_t l; - fprintf(stderr, "WARNING: Failed to open entropy device '"RANDOM_DEVICE"': %s, falling back to unsecure pseudo RNG.\n", strerror(errno)); - - srandom(time(NULL)); - - for (p = data, l = length; l > 0; p++, l--) - *p = (uint8_t) random(); - } - - if ((r = pa_loop_write(fd, data, length)) < 0 || (size_t) r != length) { - ret = -2; - goto finish; - } - - ret = 0; - -finish: - if (fd >= 0) { - if (ret != 0) - unlink(fn); - close(fd); - } - if (random_fd >= 0) - close(random_fd); - - return ret; -} - -int pa_authkey_load(const char *path, void *data, size_t length) { - int ret, i; - - assert(path && data && length); - - for (i = 0; i < 10; i++) { - if ((ret = load(path, data, length)) < 0) - if (ret == -1 && errno == ENOENT) - if ((ret = generate(path, data, length)) < 0) - if (ret == -1 && errno == EEXIST) - continue; - break; - } - - if (ret < 0) - fprintf(stderr, "Failed to load authorization key '%s': %s\n", path, (ret == -1) ? strerror(errno) : "file corrupt"); - - return ret; -} - -int pa_authkey_load_from_home(const char *fn, void *data, size_t length) { - char *home; - char path[PATH_MAX]; - - assert(fn && data && length); - - if (!(home = getenv("HOME"))) - return -2; - - snprintf(path, sizeof(path), "%s/%s", home, fn); - - return pa_authkey_load(path, data, length); -} - -int pa_authkey_load_auto(const char *fn, void *data, size_t length) { - assert(fn && data && length); - - if (*fn == '/') - return pa_authkey_load(fn, data, length); - else - return pa_authkey_load_from_home(fn, data, length); -} diff --git a/src/authkey.h b/src/authkey.h deleted file mode 100644 index acdcc24d..00000000 --- a/src/authkey.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef fooauthkeyhfoo -#define fooauthkeyhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -int pa_authkey_load(const char *path, void *data, size_t len); -int pa_authkey_load_from_home(const char *fn, void *data, size_t length); -int pa_authkey_load_auto(const char *fn, void *data, size_t length); - -#endif diff --git a/src/cli-command.c b/src/cli-command.c deleted file mode 100644 index f3a2f8a0..00000000 --- a/src/cli-command.c +++ /dev/null @@ -1,557 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "cli-command.h" -#include "module.h" -#include "sink.h" -#include "source.h" -#include "client.h" -#include "sink-input.h" -#include "source-output.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_get_count(), pa_memblock_get_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 deleted file mode 100644 index b3c601ad..00000000 --- a/src/cli-command.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef fooclicommandhfoo -#define fooclicommandhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#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 deleted file mode 100644 index f2aa5a65..00000000 --- a/src/cli.c +++ /dev/null @@ -1,148 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "ioline.h" -#include "cli.h" -#include "module.h" -#include "sink.h" -#include "source.h" -#include "client.h" -#include "sink-input.h" -#include "source-output.h" -#include "tokenizer.h" -#include "strbuf.h" -#include "namereg.h" -#include "clitext.h" -#include "cli-command.h" - -struct pa_cli { - struct pa_core *core; - struct pa_ioline *line; - - void (*eof_callback)(struct pa_cli *c, void *userdata); - void *userdata; - - struct pa_client *client; - - int fail, verbose, kill_requested, defer_kill; -}; - -static void line_callback(struct pa_ioline *line, const char *s, void *userdata); - -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, struct pa_module *m) { - char cname[256]; - struct pa_cli *c; - assert(io); - - c = malloc(sizeof(struct pa_cli)); - assert(c); - c->core = core; - c->line = pa_ioline_new(io); - assert(c->line); - - c->userdata = NULL; - c->eof_callback = NULL; - - pa_iochannel_socket_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; - c->client->owner = m; - - 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; -} - -void pa_cli_free(struct pa_cli *c) { - assert(c); - pa_ioline_free(c->line); - pa_client_free(c->client); - 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->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; - char *p; - assert(line && c); - - if (!s) { - fprintf(stderr, "CLI got EOF from user.\n"); - if (c->eof_callback) - c->eof_callback(c, c->userdata); - - return; - } - - 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 (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) { - assert(c && cb); - c->eof_callback = cb; - c->userdata = userdata; -} diff --git a/src/cli.h b/src/cli.h deleted file mode 100644 index 9cfee0d8..00000000 --- a/src/cli.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef fooclihfoo -#define fooclihfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "iochannel.h" -#include "core.h" -#include "module.h" - -struct pa_cli; - -struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io, struct pa_module *m); -void pa_cli_free(struct pa_cli *cli); - -void pa_cli_set_eof_callback(struct pa_cli *cli, void (*cb)(struct pa_cli*c, void *userdata), void *userdata); - -#endif diff --git a/src/client.c b/src/client.c deleted file mode 100644 index 0294c9e2..00000000 --- a/src/client.c +++ /dev/null @@ -1,79 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "client.h" - -struct pa_client *pa_client_new(struct pa_core *core, const char *protocol_name, char *name) { - struct pa_client *c; - int r; - assert(core); - - c = malloc(sizeof(struct pa_client)); - assert(c); - c->name = name ? strdup(name) : NULL; - c->owner = NULL; - c->core = core; - c->protocol_name = protocol_name; - - c->kill = NULL; - c->userdata = NULL; - - r = pa_idxset_put(core->clients, c, &c->index); - assert(c->index != PA_IDXSET_INVALID && r >= 0); - - fprintf(stderr, "client: created %u \"%s\"\n", c->index, c->name); - - return c; -} - -void pa_client_free(struct pa_client *c) { - assert(c && c->core); - - pa_idxset_remove_by_data(c->core->clients, c, NULL); - fprintf(stderr, "client: freed %u \"%s\"\n", c->index, c->name); - free(c->name); - free(c); -} - -void pa_client_kill(struct pa_client *c) { - assert(c); - if (!c->kill) { - fprintf(stderr, "kill() operation not implemented for client %u\n", c->index); - return; - } - - c->kill(c); -} - -void pa_client_rename(struct pa_client *c, const char *name) { - assert(c); - free(c->name); - c->name = name ? strdup(name) : NULL; -} diff --git a/src/client.h b/src/client.h deleted file mode 100644 index c926208e..00000000 --- a/src/client.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef fooclienthfoo -#define fooclienthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "core.h" -#include "module.h" - -struct pa_client { - uint32_t index; - - struct pa_module *owner; - char *name; - struct pa_core *core; - const char *protocol_name; - - void (*kill)(struct pa_client *c); - void *userdata; -}; - -struct pa_client *pa_client_new(struct pa_core *c, const char *protocol_name, char *name); - -/* This function should be called only by the code that created the client */ -void pa_client_free(struct pa_client *c); - -/* Code that didn't create the client should call this function to - * request destruction of the client */ -void pa_client_kill(struct pa_client *c); - -void pa_client_rename(struct pa_client *c, const char *name); - -#endif diff --git a/src/clitext.c b/src/clitext.c deleted file mode 100644 index c1b9953b..00000000 --- a/src/clitext.c +++ /dev/null @@ -1,203 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "clitext.h" -#include "module.h" -#include "client.h" -#include "sink.h" -#include "source.h" -#include "sink-input.h" -#include "source-output.h" -#include "strbuf.h" -#include "sample-util.h" - -char *pa_module_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_module *m; - uint32_t index = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_ncontents(c->modules)); - - for (m = pa_idxset_first(c->modules, &index); m; m = pa_idxset_next(c->modules, &index)) - pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\targument: <%s>\n", m->index, m->name, m->argument); - - return pa_strbuf_tostring_free(s); -} - -char *pa_client_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_client *client; - uint32_t index = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u client(s).\n", pa_idxset_ncontents(c->clients)); - - for (client = pa_idxset_first(c->clients, &index); client; client = pa_idxset_next(c->clients, &index)) { - pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\tprotocol_name: <%s>\n", client->index, client->name, client->protocol_name); - - if (client->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", client->owner->index); - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_sink_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_sink *sink, *default_sink; - uint32_t index = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_ncontents(c->sinks)); - - default_sink = pa_sink_get_default(c); - - for (sink = pa_idxset_first(c->sinks, &index); sink; sink = pa_idxset_next(c->sinks, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - pa_sample_snprint(ss, sizeof(ss), &sink->sample_spec); - assert(sink->monitor_source); - pa_strbuf_printf( - s, - " %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", - sink == default_sink ? '*' : ' ', - sink->index, sink->name, - (unsigned) sink->volume, - pa_sink_get_latency(sink), - sink->monitor_source->index, - ss); - - if (sink->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", sink->owner->index); - if (sink->description) - pa_strbuf_printf(s, "\tdescription: <%s>\n", sink->description); - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_source_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_source *source, *default_source; - uint32_t index = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_ncontents(c->sources)); - - default_source = pa_source_get_default(c); - - for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - pa_sample_snprint(ss, sizeof(ss), &source->sample_spec); - pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\tsample_spec: <%s>\n", source == default_source ? '*' : ' ', source->index, source->name, ss); - - if (source->monitor_of) - pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index); - if (source->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", source->owner->index); - if (source->description) - pa_strbuf_printf(s, "\tdescription: <%s>\n", source->description); - } - - return pa_strbuf_tostring_free(s); -} - - -char *pa_source_output_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_source_output *o; - uint32_t index = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_ncontents(c->source_outputs)); - - for (o = pa_idxset_first(c->source_outputs, &index); o; o = pa_idxset_next(c->source_outputs, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - pa_sample_snprint(ss, sizeof(ss), &o->sample_spec); - assert(o->source); - pa_strbuf_printf( - s, " index: %u\n\tname: <%s>\n\tsource: <%u>\n\tsample_spec: <%s>\n", - o->index, - o->name, - o->source->index, - ss); - if (o->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", o->owner->index); - if (o->client) - pa_strbuf_printf(s, "\tclient: <%u>\n", o->client->index); - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_sink_input_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_sink_input *i; - uint32_t index = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_ncontents(c->sink_inputs)); - - for (i = pa_idxset_first(c->sink_inputs, &index); i; i = pa_idxset_next(c->sink_inputs, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - pa_sample_snprint(ss, sizeof(ss), &i->sample_spec); - assert(i->sink); - pa_strbuf_printf( - s, " index: %u\n\tname: <%s>\n\tsink: <%u>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tsample_spec: <%s>\n", - i->index, - i->name, - i->sink->index, - (unsigned) i->volume, - pa_sink_input_get_latency(i), - ss); - - if (i->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", i->owner->index); - if (i->client) - pa_strbuf_printf(s, "\tclient: <%u>\n", i->client->index); - } - - return pa_strbuf_tostring_free(s); -} diff --git a/src/clitext.h b/src/clitext.h deleted file mode 100644 index b1718cb5..00000000 --- a/src/clitext.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef fooclitexthfoo -#define fooclitexthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "core.h" - -char *pa_sink_input_list_to_string(struct pa_core *c); -char *pa_source_output_list_to_string(struct pa_core *c); -char *pa_sink_list_to_string(struct pa_core *core); -char *pa_source_list_to_string(struct pa_core *c); -char *pa_client_list_to_string(struct pa_core *c); -char *pa_module_list_to_string(struct pa_core *c); - -#endif - diff --git a/src/cmdline.c b/src/cmdline.c deleted file mode 100644 index a3330145..00000000 --- a/src/cmdline.c +++ /dev/null @@ -1,111 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "cmdline.h" -#include "util.h" -#include "strbuf.h" - -void pa_cmdline_help(const char *argv0) { - const char *e; - - if ((e = strrchr(argv0, '/'))) - e++; - else - e = argv0; - - printf("%s [options]\n" - " -L MODULE Load the specified plugin module with the specified argument\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); -} - -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 = cmdline->verbose = 0; - cmdline->fail = 1; - - buf = pa_strbuf_new(); - assert(buf); - - while ((c = getopt(argc, argv, "L:F:CDhfv")) != -1) { - switch (c) { - case 'L': - pa_strbuf_printf(buf, "load %s\n", optarg); - break; - case 'F': - pa_strbuf_printf(buf, ".include %s\n", optarg); - break; - case 'C': - pa_strbuf_puts(buf, "load module-cli\n"); - break; - case 'D': - cmdline->daemonize = 1; - break; - 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) { - assert(cmd); - free(cmd->cli_commands); - free(cmd); -} diff --git a/src/cmdline.h b/src/cmdline.h deleted file mode 100644 index 95ce91de..00000000 --- a/src/cmdline.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef foocmdlinehfoo -#define foocmdlinehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - - -struct pa_cmdline { - int daemonize, help, fail, verbose; - char *cli_commands; -}; - -struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []); -void pa_cmdline_free(struct pa_cmdline *cmd); - -void pa_cmdline_help(const char *argv0); - -#endif diff --git a/src/core.c b/src/core.c deleted file mode 100644 index dc9525a8..00000000 --- a/src/core.c +++ /dev/null @@ -1,88 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "core.h" -#include "module.h" -#include "sink.h" -#include "source.h" -#include "namereg.h" -#include "util.h" - -struct pa_core* pa_core_new(struct pa_mainloop_api *m) { - struct pa_core* c; - c = malloc(sizeof(struct pa_core)); - assert(c); - - c->mainloop = m; - c->clients = pa_idxset_new(NULL, NULL); - c->sinks = pa_idxset_new(NULL, NULL); - c->sources = pa_idxset_new(NULL, NULL); - c->source_outputs = pa_idxset_new(NULL, NULL); - c->sink_inputs = pa_idxset_new(NULL, NULL); - - c->default_source_index = c->default_sink_index = PA_IDXSET_INVALID; - - c->modules = NULL; - c->namereg = NULL; - - c->default_sample_spec.format = PA_SAMPLE_S16NE; - c->default_sample_spec.rate = 44100; - c->default_sample_spec.channels = 2; - - pa_check_for_sigpipe(); - - return c; -}; - -void pa_core_free(struct pa_core *c) { - assert(c); - - pa_module_unload_all(c); - assert(!c->modules); - - assert(pa_idxset_isempty(c->clients)); - pa_idxset_free(c->clients, NULL, NULL); - - assert(pa_idxset_isempty(c->sinks)); - pa_idxset_free(c->sinks, NULL, NULL); - - assert(pa_idxset_isempty(c->sources)); - pa_idxset_free(c->sources, NULL, NULL); - - assert(pa_idxset_isempty(c->source_outputs)); - pa_idxset_free(c->source_outputs, NULL, NULL); - - assert(pa_idxset_isempty(c->sink_inputs)); - pa_idxset_free(c->sink_inputs, NULL, NULL); - - pa_namereg_free(c); - - free(c); -}; - diff --git a/src/core.h b/src/core.h deleted file mode 100644 index 99d7d76a..00000000 --- a/src/core.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef foocorehfoo -#define foocorehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "idxset.h" -#include "hashmap.h" -#include "mainloop-api.h" -#include "sample.h" - -struct pa_core { - struct pa_mainloop_api *mainloop; - - struct pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules; - - struct pa_hashmap *namereg; - - uint32_t default_source_index, default_sink_index; - - struct pa_sample_spec default_sample_spec; -}; - -struct pa_core* pa_core_new(struct pa_mainloop_api *m); -void pa_core_free(struct pa_core*c); - -#endif diff --git a/src/depmod.py b/src/depmod.py deleted file mode 100755 index 85dc66a8..00000000 --- a/src/depmod.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/python -# $Id$ -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with polypaudio; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -import sys, os, string - -exported_symbols = {} -imported_symbols = {} - -for fn in sys.argv[1:]: - f = os.popen("nm '%s'" % fn, "r") - - imported_symbols[fn] = [] - - for line in f: - sym_address = line[:7].strip() - sym_type = line[9].strip() - sym_name = line[11:].strip() - - if sym_name in ('_fini', '_init'): - continue - - if sym_type in ('T', 'B', 'R', 'D' 'G', 'S', 'D'): - if exported_symbols.has_key(sym_name): - sys.stderr.write("CONFLICT: %s defined in both '%s' and '%s'.\n" % (sym_name, fn, exported_symbols[sym_name])) - else: - exported_symbols[sym_name] = fn - elif sym_type in ('U',): - if sym_name[:3] == 'pa_': - imported_symbols[fn].append(sym_name) - - f.close() - -dependencies = {} -unresolved_symbols = {} - -for fn in imported_symbols: - dependencies[fn] = [] - - for sym in imported_symbols[fn]: - if exported_symbols.has_key(sym): - if exported_symbols[sym] not in dependencies[fn]: - dependencies[fn].append(exported_symbols[sym]) - else: - if unresolved_symbols.has_key(sym): - unresolved_symbols[sym].append(fn) - else: - unresolved_symbols[sym] = [fn] - -for sym, files in unresolved_symbols.iteritems(): - print "WARNING: Unresolved symbol '%s' in %s" % (sym, `files`) - -k = dependencies.keys() -k.sort() -for fn in k: - dependencies[fn].sort() - print "%s: %s" % (fn, string.join(dependencies[fn], " ")) diff --git a/src/dynarray.c b/src/dynarray.c deleted file mode 100644 index 24306964..00000000 --- a/src/dynarray.c +++ /dev/null @@ -1,98 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "dynarray.h" - -struct pa_dynarray { - void **data; - unsigned n_allocated, n_entries; -}; - -struct pa_dynarray* pa_dynarray_new(void) { - struct pa_dynarray *a; - a = malloc(sizeof(struct pa_dynarray)); - assert(a); - a->data = NULL; - a->n_entries = 0; - a->n_allocated = 0; - return a; -} - -void pa_dynarray_free(struct pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata) { - unsigned i; - assert(a); - - if (func) - for (i = 0; i < a->n_entries; i++) - if (a->data[i]) - func(a->data[i], userdata); - - free(a->data); - free(a); -} - -void pa_dynarray_put(struct pa_dynarray*a, unsigned i, void *p) { - assert(a); - - if (i >= a->n_allocated) { - unsigned n; - - if (!p) - return; - - n = i+100; - a->data = realloc(a->data, sizeof(void*)*n); - memset(a->data+a->n_allocated, 0, sizeof(void*)*(n-a->n_allocated)); - a->n_allocated = n; - } - - a->data[i] = p; - - if (i >= a->n_entries) - a->n_entries = i+1; -} - -unsigned pa_dynarray_append(struct pa_dynarray*a, void *p) { - unsigned i = a->n_entries; - pa_dynarray_put(a, i, p); - return i; -} - -void *pa_dynarray_get(struct pa_dynarray*a, unsigned i) { - assert(a); - if (i >= a->n_allocated) - return NULL; - assert(a->data); - return a->data[i]; -} - -unsigned pa_dynarray_ncontents(struct pa_dynarray*a) { - assert(a); - return a->n_entries; -} diff --git a/src/dynarray.h b/src/dynarray.h deleted file mode 100644 index 56ec5386..00000000 --- a/src/dynarray.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef foodynarrayhfoo -#define foodynarrayhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -struct pa_dynarray; - -struct pa_dynarray* pa_dynarray_new(void); -void pa_dynarray_free(struct pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata); - -void pa_dynarray_put(struct pa_dynarray*a, unsigned i, void *p); -unsigned pa_dynarray_append(struct pa_dynarray*a, void *p); - -void *pa_dynarray_get(struct pa_dynarray*a, unsigned i); - -unsigned pa_dynarray_ncontents(struct pa_dynarray*a); - -#endif diff --git a/src/endianmacros.h b/src/endianmacros.h deleted file mode 100644 index cd7b7d83..00000000 --- a/src/endianmacros.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef fooendianmacroshfoo -#define fooendianmacroshfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define INT16_SWAP(x) ((int16_t)(((int16_t) x >> 8) | ((int16_t) x << 8))) -#define UINT16_SWAP(x) ((uint16_t)(((uint16_t) x >> 8) | ((uint16_t) x << 8))) -#define INT32_SWAP(x) ((int32_t)(((int32_t) x >> 24) | ((int32_t) x << 24) | (((int32_t) x & 0xFF00) << 16) | (((int32_t) x) >> 16) & 0xFF00)) -#define UINT32_SWAP(x) ((uint32_t)(((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 16) | (((uint32_t) x) >> 16) & 0xFF00)) - -#ifdef WORDS_BIGENDIAN - #define INT16_FROM_LE(x) INT16_SWAP(x) - #define INT16_FROM_BE(x) ((int16_t)(x)) - #define INT16_TO_LE(x) INT16_SWAP(x) - #define INT16_TO_BE(x) ((int16_t)(x)) - - #define UINT16_FROM_LE(x) UINT16_SWAP(x) - #define UINT16_FROM_BE(x) ((uint16_t)(x)) - #define INT32_FROM_LE(x) INT32_SWAP(x) - #define INT32_FROM_BE(x) ((int32_t)(x)) - #define UINT32_FROM_LE(x) UINT32_SWAP(x) - #define UINT32_FROM_BE(x) ((uint32_t)(x)) -#else - #define INT16_FROM_LE(x) ((int16_t)(x)) - #define INT16_FROM_BE(x) INT16_SWAP(x) - #define INT16_TO_LE(x) ((int16_t)(x)) - #define INT16_TO_BE(x) INT16_SWAP(x) - - #define UINT16_FROM_LE(x) ((uint16_t)(x)) - #define UINT16_FROM_BE(x) UINT16_SWAP(x) - #define INT32_FROM_LE(x) ((int32_t)(x)) - #define INT32_FROM_BE(x) INT32_SWAP(x) - #define UINT32_FROM_LE(x) ((uint32_t)(x)) - #define UINT32_FROM_BE(x) UINT32_SWAP(x) -#endif - -#endif diff --git a/src/esound.h b/src/esound.h deleted file mode 100644 index 01a2962f..00000000 --- a/src/esound.h +++ /dev/null @@ -1,213 +0,0 @@ -#ifndef fooesoundhfoo -#define fooesoundhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -/* Most of the following is blatantly stolen from esound. */ - - -/* path and name of the default EsounD domain socket */ -#define ESD_UNIX_SOCKET_DIR "/tmp/.esd" -#define ESD_UNIX_SOCKET_NAME "/tmp/.esd/socket" - -/* length of the audio buffer size */ -#define ESD_BUF_SIZE (4 * 1024) -/* maximum size we can write(). Otherwise we might overflow */ -#define ESD_MAX_WRITE_SIZE (21 * 4096) - -/* length of the authorization key, octets */ -#define ESD_KEY_LEN (16) - -/* default port for the EsounD server */ -#define ESD_DEFAULT_PORT (16001) - -/* default sample rate for the EsounD server */ -#define ESD_DEFAULT_RATE (44100) - -/* maximum length of a stream/sample name */ -#define ESD_NAME_MAX (128) - -/* a magic number to identify the relative endianness of a client */ -#define ESD_ENDIAN_KEY ((uint32_t) (('E' << 24) + ('N' << 16) + ('D' << 8) + ('N'))) - -#define ESD_VOLUME_BASE (256) - - -/*************************************/ -/* what can we do to/with the EsounD */ -enum esd_proto { - ESD_PROTO_CONNECT, /* implied on inital client connection */ - - /* pseudo "security" functionality */ - ESD_PROTO_LOCK, /* disable "foreign" client connections */ - ESD_PROTO_UNLOCK, /* enable "foreign" client connections */ - - /* stream functionality: play, record, monitor */ - ESD_PROTO_STREAM_PLAY, /* play all following data as a stream */ - ESD_PROTO_STREAM_REC, /* record data from card as a stream */ - ESD_PROTO_STREAM_MON, /* send mixed buffer output as a stream */ - - /* sample functionality: cache, free, play, loop, EOL, kill */ - ESD_PROTO_SAMPLE_CACHE, /* cache a sample in the server */ - ESD_PROTO_SAMPLE_FREE, /* release a sample in the server */ - ESD_PROTO_SAMPLE_PLAY, /* play a cached sample */ - ESD_PROTO_SAMPLE_LOOP, /* loop a cached sample, til eoloop */ - ESD_PROTO_SAMPLE_STOP, /* stop a looping sample when done */ - ESD_PROTO_SAMPLE_KILL, /* stop the looping sample immed. */ - - /* free and reclaim /dev/dsp functionality */ - ESD_PROTO_STANDBY, /* release /dev/dsp and ignore all data */ - ESD_PROTO_RESUME, /* reclaim /dev/dsp and play sounds again */ - - /* TODO: move these to a more logical place. NOTE: will break the protocol */ - ESD_PROTO_SAMPLE_GETID, /* get the ID for an already-cached sample */ - ESD_PROTO_STREAM_FILT, /* filter mixed buffer output as a stream */ - - /* esd remote management */ - ESD_PROTO_SERVER_INFO, /* get server info (ver, sample rate, format) */ - ESD_PROTO_ALL_INFO, /* get all info (server info, players, samples) */ - ESD_PROTO_SUBSCRIBE, /* track new and removed players and samples */ - ESD_PROTO_UNSUBSCRIBE, /* stop tracking updates */ - - /* esd remote control */ - ESD_PROTO_STREAM_PAN, /* set stream panning */ - ESD_PROTO_SAMPLE_PAN, /* set default sample panning */ - - /* esd status */ - ESD_PROTO_STANDBY_MODE, /* see if server is in standby, autostandby, etc */ - - /* esd latency */ - ESD_PROTO_LATENCY, /* retrieve latency between write()'s and output */ - - ESD_PROTO_MAX /* for bounds checking */ -}; - -/******************/ -/* The EsounD api */ - -/* the properties of a sound buffer are logically or'd */ - -/* bits of stream/sample data */ -#define ESD_MASK_BITS ( 0x000F ) -#define ESD_BITS8 ( 0x0000 ) -#define ESD_BITS16 ( 0x0001 ) - -/* how many interleaved channels of data */ -#define ESD_MASK_CHAN ( 0x00F0 ) -#define ESD_MONO ( 0x0010 ) -#define ESD_STEREO ( 0x0020 ) - -/* whether it's a stream or a sample */ -#define ESD_MASK_MODE ( 0x0F00 ) -#define ESD_STREAM ( 0x0000 ) -#define ESD_SAMPLE ( 0x0100 ) -#define ESD_ADPCM ( 0x0200 ) /* TODO: anyone up for this? =P */ - -/* the function of the stream/sample, and common functions */ -#define ESD_MASK_FUNC ( 0xF000 ) -#define ESD_PLAY ( 0x1000 ) -/* functions for streams only */ -#define ESD_MONITOR ( 0x0000 ) -#define ESD_RECORD ( 0x2000 ) -/* functions for samples only */ -#define ESD_STOP ( 0x0000 ) -#define ESD_LOOP ( 0x2000 ) - -typedef int esd_format_t; -typedef int esd_proto_t; - -/*******************************************************************/ -/* esdmgr.c - functions to implement a "sound manager" for esd */ - -/* structures to retrieve information about streams/samples from the server */ -typedef struct esd_server_info { - - int version; /* server version encoded as an int */ - esd_format_t format; /* magic int with the format info */ - int rate; /* sample rate */ - -} esd_server_info_t; - -typedef struct esd_player_info { - - struct esd_player_info *next; /* point to next entry in list */ - esd_server_info_t *server; /* the server that contains this stream */ - - int source_id; /* either a stream fd or sample id */ - char name[ ESD_NAME_MAX ]; /* name of stream for remote control */ - int rate; /* sample rate */ - int left_vol_scale; /* volume scaling */ - int right_vol_scale; - - esd_format_t format; /* magic int with the format info */ - -} esd_player_info_t; - -typedef struct esd_sample_info { - - struct esd_sample_info *next; /* point to next entry in list */ - esd_server_info_t *server; /* the server that contains this sample */ - - int sample_id; /* either a stream fd or sample id */ - char name[ ESD_NAME_MAX ]; /* name of stream for remote control */ - int rate; /* sample rate */ - int left_vol_scale; /* volume scaling */ - int right_vol_scale; - - esd_format_t format; /* magic int with the format info */ - int length; /* total buffer length */ - -} esd_sample_info_t; - -typedef struct esd_info { - - esd_server_info_t *server; - esd_player_info_t *player_list; - esd_sample_info_t *sample_list; - -} esd_info_t; - -enum esd_standby_mode { - ESM_ERROR, ESM_ON_STANDBY, ESM_ON_AUTOSTANDBY, ESM_RUNNING -}; -typedef int esd_standby_mode_t; - -enum esd_client_state { - ESD_STREAMING_DATA, /* data from here on is streamed data */ - ESD_CACHING_SAMPLE, /* midway through caching a sample */ - ESD_NEEDS_REQDATA, /* more data needed to complere request */ - ESD_NEXT_REQUEST, /* proceed to next request */ - ESD_CLIENT_STATE_MAX /* place holder */ -}; -typedef int esd_client_state_t; - -/* switch endian order for cross platform playing */ -#define swap_endian_32(x) ((x >> 24) | ((x >> 8) & 0xFF00) | (((x & 0xFF00) << 8)) | (x << 24)) -#define maybe_swap_endian_32(c,x) ((c) ? swap_endian_32(x) : x) - -/* the endian key is transferred in binary, if it's read into int, */ -/* and matches ESD_ENDIAN_KEY (ENDN), then the endianness of the */ -/* server and the client match; if it's SWAP_ENDIAN_KEY, swap data */ -#define ESD_SWAP_ENDIAN_KEY ((uint32_t) swap_endian_32(ESD_ENDIAN_KEY)) - - -#endif diff --git a/src/hashmap.c b/src/hashmap.c deleted file mode 100644 index 2c7c92b5..00000000 --- a/src/hashmap.c +++ /dev/null @@ -1,170 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "hashmap.h" -#include "idxset.h" - -struct hashmap_entry { - struct hashmap_entry *next, *previous, *bucket_next, *bucket_previous; - unsigned hash; - const void *key; - void *value; -}; - -struct pa_hashmap { - unsigned size; - struct hashmap_entry **data; - struct hashmap_entry *first_entry; - - unsigned n_entries; - unsigned (*hash_func) (const void *p); - int (*compare_func) (const void*a, const void*b); -}; - -struct pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { - struct pa_hashmap *h; - h = malloc(sizeof(struct pa_hashmap)); - assert(h); - h->data = malloc(sizeof(struct hashmap_entry*)*(h->size = 1023)); - assert(h->data); - memset(h->data, 0, sizeof(struct hashmap_entry*)*(h->size = 1023)); - h->first_entry = NULL; - h->n_entries = 0; - h->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; - h->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; - return h; -} - -static void remove(struct pa_hashmap *h, struct hashmap_entry *e) { - assert(e); - - if (e->next) - e->next->previous = e->previous; - if (e->previous) - e->previous->next = e->next; - else - h->first_entry = e->next; - - if (e->bucket_next) - e->bucket_next->bucket_previous = e->bucket_previous; - if (e->bucket_previous) - e->bucket_previous->bucket_next = e->bucket_next; - else - h->data[e->hash] = e->bucket_next; - - free(e); - h->n_entries--; -} - -void pa_hashmap_free(struct pa_hashmap*h, void (*free_func)(void *p, void *userdata), void *userdata) { - assert(h); - - while (h->first_entry) { - if (free_func) - free_func(h->first_entry->value, userdata); - remove(h, h->first_entry); - } - - free(h->data); - free(h); -} - -static struct hashmap_entry *get(struct pa_hashmap *h, unsigned hash, const void *key) { - struct hashmap_entry *e; - - for (e = h->data[hash]; e; e = e->bucket_next) - if (h->compare_func(e->key, key) == 0) - return e; - - return NULL; -} - -int pa_hashmap_put(struct pa_hashmap *h, const void *key, void *value) { - struct hashmap_entry *e; - unsigned hash; - assert(h && key); - - hash = h->hash_func(key) % h->size; - - if ((e = get(h, hash, key))) - return -1; - - e = malloc(sizeof(struct hashmap_entry)); - assert(e); - - e->hash = hash; - e->key = key; - e->value = value; - - e->previous = NULL; - e->next = h->first_entry; - if (h->first_entry) - h->first_entry->previous = e; - h->first_entry = e; - - e->bucket_previous = NULL; - e->bucket_next = h->data[hash]; - if (h->data[hash]) - h->data[hash]->bucket_previous = e; - h->data[hash] = e; - - h->n_entries ++; - return 0; -} - -void* pa_hashmap_get(struct pa_hashmap *h, const void *key) { - unsigned hash; - struct hashmap_entry *e; - assert(h && key); - - hash = h->hash_func(key) % h->size; - - if (!(e = get(h, hash, key))) - return NULL; - - return e->value; -} - -int pa_hashmap_remove(struct pa_hashmap *h, const void *key) { - struct hashmap_entry *e; - unsigned hash; - assert(h && key); - - hash = h->hash_func(key) % h->size; - - if (!(e = get(h, hash, key))) - return 1; - - remove(h, e); - return 0; -} - -unsigned pa_hashmap_ncontents(struct pa_hashmap *h) { - return h->n_entries; -} diff --git a/src/hashmap.h b/src/hashmap.h deleted file mode 100644 index b24e74a5..00000000 --- a/src/hashmap.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef foohashmaphfoo -#define foohashmaphfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -struct pa_hashmap; - -struct pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); -void pa_hashmap_free(struct pa_hashmap*, void (*free_func)(void *p, void *userdata), void *userdata); - -int pa_hashmap_put(struct pa_hashmap *h, const void *key, void *value); -void* pa_hashmap_get(struct pa_hashmap *h, const void *key); - -int pa_hashmap_remove(struct pa_hashmap *h, const void *key); - -unsigned pa_hashmap_ncontents(struct pa_hashmap *h); - -#endif diff --git a/src/idxset.c b/src/idxset.c deleted file mode 100644 index cecda6b7..00000000 --- a/src/idxset.c +++ /dev/null @@ -1,397 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "idxset.h" - -struct idxset_entry { - void *data; - uint32_t index; - unsigned hash_value; - - struct idxset_entry *hash_prev, *hash_next; - struct idxset_entry* iterate_prev, *iterate_next; -}; - -struct pa_idxset { - unsigned (*hash_func) (const void *p); - int (*compare_func)(const void *a, const void *b); - - unsigned hash_table_size, n_entries; - struct idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail; - uint32_t index, start_index, array_size; -}; - -unsigned pa_idxset_string_hash_func(const void *p) { - unsigned hash = 0; - const char *c; - - for (c = p; *c; c++) - hash = 31 * hash + *c; - - return hash; -} - -int pa_idxset_string_compare_func(const void *a, const void *b) { - return strcmp(a, b); -} - -unsigned pa_idxset_trivial_hash_func(const void *p) { - return (unsigned) p; -} - -int pa_idxset_trivial_compare_func(const void *a, const void *b) { - return a != b; -} - -struct pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { - struct pa_idxset *s; - - s = malloc(sizeof(struct pa_idxset)); - assert(s); - s->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; - s->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; - s->hash_table_size = 1023; - s->hash_table = malloc(sizeof(struct idxset_entry*)*s->hash_table_size); - assert(s->hash_table); - memset(s->hash_table, 0, sizeof(struct idxset_entry*)*s->hash_table_size); - s->array = NULL; - s->array_size = 0; - s->index = 0; - s->start_index = 0; - s->n_entries = 0; - - s->iterate_list_head = s->iterate_list_tail = NULL; - - return s; -} - -void pa_idxset_free(struct pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata) { - assert(s); - - if (free_func) { - while (s->iterate_list_head) { - struct idxset_entry *e = s->iterate_list_head; - s->iterate_list_head = s->iterate_list_head->iterate_next; - - if (free_func) - free_func(e->data, userdata); - free(e); - } - } - - free(s->hash_table); - free(s->array); - free(s); -} - -static struct idxset_entry* hash_scan(struct pa_idxset *s, struct idxset_entry* e, void *p) { - assert(p); - - assert(s->compare_func); - for (; e; e = e->hash_next) - if (s->compare_func(e->data, p) == 0) - return e; - - return NULL; -} - -static void extend_array(struct pa_idxset *s, uint32_t index) { - uint32_t i, j, l; - struct idxset_entry** n; - assert(index >= s->start_index); - - if (index < s->start_index + s->array_size) - return; - - for (i = 0; i < s->array_size; i++) - if (s->array[i]) - break; - - l = index - s->start_index - i + 100; - n = malloc(sizeof(struct hash_table_entry*)*l); - assert(n); - memset(n, 0, sizeof(struct hash_table_entry*)*l); - - for (j = 0; j < s->array_size-i; j++) - n[j] = s->array[i+j]; - - free(s->array); - - s->array = n; - s->array_size = l; - s->start_index += i; -} - -static struct idxset_entry** array_index(struct pa_idxset*s, uint32_t index) { - if (index >= s->start_index + s->array_size) - return NULL; - - if (index < s->start_index) - return NULL; - - return s->array + (index - s->start_index); -} - -int pa_idxset_put(struct pa_idxset*s, void *p, uint32_t *index) { - unsigned h; - struct idxset_entry *e, **a; - assert(s && p); - - assert(s->hash_func); - h = s->hash_func(p) % s->hash_table_size; - - assert(s->hash_table); - if ((e = hash_scan(s, s->hash_table[h], p))) { - if (index) - *index = e->index; - - return -1; - } - - e = malloc(sizeof(struct idxset_entry)); - assert(e); - - e->data = p; - e->index = s->index++; - e->hash_value = h; - - /* Insert into hash table */ - e->hash_next = s->hash_table[h]; - e->hash_prev = NULL; - if (s->hash_table[h]) - s->hash_table[h]->hash_prev = e; - s->hash_table[h] = e; - - /* Insert into array */ - extend_array(s, e->index); - a = array_index(s, e->index); - assert(a && !*a); - *a = e; - - /* Insert into linked list */ - e->iterate_next = NULL; - e->iterate_prev = s->iterate_list_tail; - if (s->iterate_list_tail) { - assert(s->iterate_list_head); - s->iterate_list_tail->iterate_next = e; - } else { - assert(!s->iterate_list_head); - s->iterate_list_head = e; - } - s->iterate_list_tail = e; - - s->n_entries++; - assert(s->n_entries >= 1); - - if (index) - *index = e->index; - - return 0; -} - -void* pa_idxset_get_by_index(struct pa_idxset*s, uint32_t index) { - struct idxset_entry **a; - assert(s); - - if (!(a = array_index(s, index))) - return NULL; - - if (!*a) - return NULL; - - return (*a)->data; -} - -void* pa_idxset_get_by_data(struct pa_idxset*s, void *p, uint32_t *index) { - unsigned h; - struct idxset_entry *e; - assert(s && p); - - assert(s->hash_func); - h = s->hash_func(p) % s->hash_table_size; - - assert(s->hash_table); - if (!(e = hash_scan(s, s->hash_table[h], p))) - return NULL; - - if (index) - *index = e->index; - - return e->data; -} - -static void remove_entry(struct pa_idxset *s, struct idxset_entry *e) { - struct idxset_entry **a; - assert(s && e); - - /* Remove from array */ - a = array_index(s, e->index); - assert(a && *a && *a == e); - *a = NULL; - - /* Remove from linked list */ - if (e->iterate_next) - e->iterate_next->iterate_prev = e->iterate_prev; - else - s->iterate_list_tail = e->iterate_prev; - - if (e->iterate_prev) - e->iterate_prev->iterate_next = e->iterate_next; - else - s->iterate_list_head = e->iterate_next; - - /* Remove from hash table */ - if (e->hash_next) - e->hash_next->hash_prev = e->hash_prev; - - if (e->hash_prev) - e->hash_prev->hash_next = e->hash_next; - else - s->hash_table[e->hash_value] = e->hash_next; - - free(e); - - assert(s->n_entries >= 1); - s->n_entries--; -} - -void* pa_idxset_remove_by_index(struct pa_idxset*s, uint32_t index) { - struct idxset_entry **a; - void *data; - - assert(s); - - if (!(a = array_index(s, index))) - return NULL; - - data = (*a)->data; - remove_entry(s, *a); - - return data; -} - -void* pa_idxset_remove_by_data(struct pa_idxset*s, void *data, uint32_t *index) { - struct idxset_entry *e; - unsigned h; - - assert(s->hash_func); - h = s->hash_func(data) % s->hash_table_size; - - assert(s->hash_table); - if (!(e = hash_scan(s, s->hash_table[h], data))) - return NULL; - - data = e->data; - if (index) - *index = e->index; - - remove_entry(s, e); - - return data; -} - -void* pa_idxset_rrobin(struct pa_idxset *s, uint32_t *index) { - struct idxset_entry **a, *e = NULL; - assert(s && index); - - if ((a = array_index(s, *index)) && *a) - e = (*a)->iterate_next; - - if (!e) - e = s->iterate_list_head; - - if (!e) - return NULL; - - *index = e->index; - return e->data; -} - -void* pa_idxset_first(struct pa_idxset *s, uint32_t *index) { - assert(s); - - if (!s->iterate_list_head) - return NULL; - - if (index) - *index = s->iterate_list_head->index; - return s->iterate_list_head->data; -} - -void *pa_idxset_next(struct pa_idxset *s, uint32_t *index) { - struct idxset_entry **a, *e = NULL; - assert(s && index); - - if ((a = array_index(s, *index)) && *a) - e = (*a)->iterate_next; - - if (e) { - *index = e->index; - return e->data; - } else { - *index = PA_IDXSET_INVALID; - return NULL; - } -} - - -int pa_idxset_foreach(struct pa_idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata) { - struct idxset_entry *e; - assert(s && func); - - e = s->iterate_list_head; - while (e) { - int del = 0, r; - struct idxset_entry *n = e->iterate_next; - - r = func(e->data, e->index, &del, userdata); - - if (del) - remove_entry(s, e); - - if (r < 0) - return r; - - e = n; - } - - return 0; -} - -unsigned pa_idxset_ncontents(struct pa_idxset*s) { - assert(s); - return s->n_entries; -} - -int pa_idxset_isempty(struct pa_idxset *s) { - assert(s); - return s->n_entries == 0; -} - diff --git a/src/idxset.h b/src/idxset.h deleted file mode 100644 index f26b03fb..00000000 --- a/src/idxset.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef fooidxsethfoo -#define fooidxsethfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#define PA_IDXSET_INVALID ((uint32_t) -1) - -unsigned pa_idxset_trivial_hash_func(const void *p); -int pa_idxset_trivial_compare_func(const void *a, const void *b); - -unsigned pa_idxset_string_hash_func(const void *p); -int pa_idxset_string_compare_func(const void *a, const void *b); - -struct pa_idxset; - -struct pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); -void pa_idxset_free(struct pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata); - -int pa_idxset_put(struct pa_idxset*s, void *p, uint32_t *index); - -void* pa_idxset_get_by_index(struct pa_idxset*s, uint32_t index); -void* pa_idxset_get_by_data(struct pa_idxset*s, void *p, uint32_t *index); - -void* pa_idxset_remove_by_index(struct pa_idxset*s, uint32_t index); -void* pa_idxset_remove_by_data(struct pa_idxset*s, void *p, uint32_t *index); - -/* This may be used to iterate through all entries. When called with - an invalid index value it returns the first entry, otherwise the - next following. The function is best called with *index = - PA_IDXSET_VALID first. */ -void* pa_idxset_rrobin(struct pa_idxset *s, uint32_t *index); - -/* Return the oldest entry in the idxset */ -void* pa_idxset_first(struct pa_idxset *s, uint32_t *index); -void *pa_idxset_next(struct pa_idxset *s, uint32_t *index); - -int pa_idxset_foreach(struct pa_idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata); - -unsigned pa_idxset_ncontents(struct pa_idxset*s); -int pa_idxset_isempty(struct pa_idxset *s); - -#endif diff --git a/src/iochannel.c b/src/iochannel.c deleted file mode 100644 index 69d381f4..00000000 --- a/src/iochannel.c +++ /dev/null @@ -1,222 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "iochannel.h" -#include "util.h" -#include "socket-util.h" - -struct pa_iochannel { - int ifd, ofd; - struct pa_mainloop_api* mainloop; - - void (*callback)(struct pa_iochannel*io, void *userdata); - void*userdata; - - int readable; - int writable; - int hungup; - - int no_close; - - void* input_source, *output_source; -}; - -static void enable_mainloop_sources(struct pa_iochannel *io) { - assert(io); - - if (io->input_source == io->output_source) { - enum pa_mainloop_api_io_events e = PA_MAINLOOP_API_IO_EVENT_NULL; - assert(io->input_source); - - if (!io->readable) - e |= PA_MAINLOOP_API_IO_EVENT_INPUT; - if (!io->writable) - e |= PA_MAINLOOP_API_IO_EVENT_OUTPUT; - - io->mainloop->enable_io(io->mainloop, io->input_source, e); - } else { - if (io->input_source) - io->mainloop->enable_io(io->mainloop, io->input_source, io->readable ? PA_MAINLOOP_API_IO_EVENT_NULL : PA_MAINLOOP_API_IO_EVENT_INPUT); - if (io->output_source) - io->mainloop->enable_io(io->mainloop, io->output_source, io->writable ? PA_MAINLOOP_API_IO_EVENT_NULL : PA_MAINLOOP_API_IO_EVENT_OUTPUT); - } -} - -static void callback(struct pa_mainloop_api* m, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { - struct pa_iochannel *io = userdata; - int changed = 0; - assert(m && fd >= 0 && events && userdata); - - if ((events & PA_MAINLOOP_API_IO_EVENT_HUP) && !io->hungup) { - io->hungup = 1; - changed = 1; - } - - if ((events & PA_MAINLOOP_API_IO_EVENT_INPUT) && !io->readable) { - io->readable = 1; - changed = 1; - assert(id == io->input_source); - } - - if ((events & PA_MAINLOOP_API_IO_EVENT_OUTPUT) && !io->writable) { - io->writable = 1; - changed = 1; - assert(id == io->output_source); - } - - if (changed) { - enable_mainloop_sources(io); - - if (io->callback) - io->callback(io, io->userdata); - } -} - -struct pa_iochannel* pa_iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd) { - struct pa_iochannel *io; - assert(m && (ifd >= 0 || ofd >= 0)); - - io = malloc(sizeof(struct pa_iochannel)); - io->ifd = ifd; - io->ofd = ofd; - io->mainloop = m; - - io->userdata = NULL; - io->callback = NULL; - io->readable = 0; - io->writable = 0; - io->hungup = 0; - io->no_close = 0; - - if (ifd == ofd) { - assert(ifd >= 0); - pa_make_nonblock_fd(io->ifd); - io->input_source = io->output_source = m->source_io(m, ifd, PA_MAINLOOP_API_IO_EVENT_BOTH, callback, io); - } else { - - if (ifd >= 0) { - pa_make_nonblock_fd(io->ifd); - io->input_source = m->source_io(m, ifd, PA_MAINLOOP_API_IO_EVENT_INPUT, callback, io); - } else - io->input_source = NULL; - - if (ofd >= 0) { - pa_make_nonblock_fd(io->ofd); - io->output_source = m->source_io(m, ofd, PA_MAINLOOP_API_IO_EVENT_OUTPUT, callback, io); - } else - io->output_source = NULL; - } - - return io; -} - -void pa_iochannel_free(struct pa_iochannel*io) { - assert(io); - - if (!io->no_close) { - if (io->ifd >= 0) - close(io->ifd); - if (io->ofd >= 0 && io->ofd != io->ifd) - close(io->ofd); - } - - if (io->input_source) - io->mainloop->cancel_io(io->mainloop, io->input_source); - if (io->output_source && (io->output_source != io->input_source)) - io->mainloop->cancel_io(io->mainloop, io->output_source); - - free(io); -} - -int pa_iochannel_is_readable(struct pa_iochannel*io) { - assert(io); - return io->readable; -} - -int pa_iochannel_is_writable(struct pa_iochannel*io) { - assert(io); - return io->writable; -} - -int pa_iochannel_is_hungup(struct pa_iochannel*io) { - assert(io); - return io->hungup; -} - -ssize_t pa_iochannel_write(struct pa_iochannel*io, const void*data, size_t l) { - ssize_t r; - assert(io && data && l && io->ofd >= 0); - - if ((r = write(io->ofd, data, l)) >= 0) { - io->writable = 0; - enable_mainloop_sources(io); - } - - return r; -} - -ssize_t pa_iochannel_read(struct pa_iochannel*io, void*data, size_t l) { - ssize_t r; - - assert(io && data && io->ifd >= 0); - - if ((r = read(io->ifd, data, l)) >= 0) { - io->readable = 0; - enable_mainloop_sources(io); - } - - return r; -} - -void pa_iochannel_set_callback(struct pa_iochannel*io, void (*callback)(struct pa_iochannel*io, void *userdata), void *userdata) { - assert(io); - io->callback = callback; - io->userdata = userdata; -} - -void pa_iochannel_set_noclose(struct pa_iochannel*io, int b) { - assert(io); - io->no_close = b; -} - -void pa_iochannel_socket_peer_to_string(struct pa_iochannel*io, char*s, size_t l) { - assert(io && s && l); - pa_socket_peer_to_string(io->ifd, s, l); -} - -int pa_iochannel_socket_set_rcvbuf(struct pa_iochannel *io, size_t l) { - assert(io); - return pa_socket_set_rcvbuf(io->ifd, l); -} - -int pa_iochannel_socket_set_sndbuf(struct pa_iochannel *io, size_t l) { - assert(io); - return pa_socket_set_sndbuf(io->ofd, l); -} diff --git a/src/iochannel.h b/src/iochannel.h deleted file mode 100644 index 6f5f351c..00000000 --- a/src/iochannel.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef fooiochannelhfoo -#define fooiochannelhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include "mainloop-api.h" - -/* It is safe to destroy the calling iochannel object from the callback */ - -struct pa_iochannel; - -struct pa_iochannel* pa_iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd); -void pa_iochannel_free(struct pa_iochannel*io); - -ssize_t pa_iochannel_write(struct pa_iochannel*io, const void*data, size_t l); -ssize_t pa_iochannel_read(struct pa_iochannel*io, void*data, size_t l); - -int pa_iochannel_is_readable(struct pa_iochannel*io); -int pa_iochannel_is_writable(struct pa_iochannel*io); -int pa_iochannel_is_hungup(struct pa_iochannel*io); - -void pa_iochannel_set_noclose(struct pa_iochannel*io, int b); - -void pa_iochannel_set_callback(struct pa_iochannel*io, void (*callback)(struct pa_iochannel*io, void *userdata), void *userdata); - -void pa_iochannel_socket_peer_to_string(struct pa_iochannel*io, char*s, size_t l); -int pa_iochannel_socket_set_rcvbuf(struct pa_iochannel*io, size_t l); -int pa_iochannel_socket_set_sndbuf(struct pa_iochannel*io, size_t l); - -#endif diff --git a/src/ioline.c b/src/ioline.c deleted file mode 100644 index ff9a03c2..00000000 --- a/src/ioline.c +++ /dev/null @@ -1,220 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "ioline.h" - -#define BUFFER_LIMIT (64*1024) -#define READ_SIZE (1024) - -struct pa_ioline { - struct pa_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 pa_ioline*io, const char *s, void *userdata); - void *userdata; -}; - -static void io_callback(struct pa_iochannel*io, void *userdata); -static int do_write(struct pa_ioline *l); - -struct pa_ioline* pa_ioline_new(struct pa_iochannel *io) { - struct pa_ioline *l; - assert(io); - - l = malloc(sizeof(struct pa_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; - - pa_iochannel_set_callback(io, io_callback, l); - - return l; -} - -void pa_ioline_free(struct pa_ioline *l) { - assert(l); - pa_iochannel_free(l->io); - free(l->wbuf); - free(l->rbuf); - free(l); -} - -void pa_ioline_puts(struct pa_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 pa_ioline_set_callback(struct pa_ioline*l, void (*callback)(struct pa_ioline*io, const char *s, void *userdata), void *userdata) { - assert(l && callback); - l->callback = callback; - l->userdata = userdata; -} - -static int do_read(struct pa_ioline *l) { - ssize_t r; - size_t m, len; - char *e; - assert(l); - - if (!pa_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 = pa_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; - - if (e) { - char *p; - - *e = 0; - - p = l->rbuf+l->rbuf_index; - m = strlen(p); - - 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; -} - -static int do_write(struct pa_ioline *l) { - ssize_t r; - assert(l); - - if (!l->wbuf_valid_length || !pa_iochannel_is_writable(l->io)) - return 0; - - if ((r = pa_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 pa_iochannel*io, void *userdata) { - struct pa_ioline *l = userdata; - assert(io && l); - - if (!l->dead && do_write(l) < 0) - goto fail; - - if (!l->dead && do_read(l) < 0) - goto fail; - - return; - -fail: - l->dead = 1; - if (l->callback) - l->callback(l, NULL, l->userdata); -} diff --git a/src/ioline.h b/src/ioline.h deleted file mode 100644 index 5f29a16b..00000000 --- a/src/ioline.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef fooiolinehfoo -#define fooiolinehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "iochannel.h" - -struct pa_ioline; - -struct pa_ioline* pa_ioline_new(struct pa_iochannel *io); -void pa_ioline_free(struct pa_ioline *l); - -void pa_ioline_puts(struct pa_ioline *s, const char *c); -void pa_ioline_set_callback(struct pa_ioline*io, void (*callback)(struct pa_ioline*io, const char *s, void *userdata), void *userdata); - -#endif diff --git a/src/main.c b/src/main.c deleted file mode 100644 index d9967cef..00000000 --- a/src/main.c +++ /dev/null @@ -1,182 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "core.h" -#include "mainloop.h" -#include "module.h" -#include "mainloop-signal.h" -#include "cmdline.h" -#include "cli-command.h" -#include "util.h" -#include "sioman.h" - -static struct pa_mainloop *mainloop; - -static void exit_signal_callback(void *id, int sig, void *userdata) { - struct pa_mainloop_api* m = pa_mainloop_get_api(mainloop); - m->quit(m, 1); - fprintf(stderr, __FILE__": got signal.\n"); -} - -static void aux_signal_callback(void *id, int sig, void *userdata) { - struct pa_core *c = userdata; - assert(c); - pa_module_load(c, sig == SIGUSR1 ? "module-cli" : "module-cli-protocol-unix", NULL); -} - -static void close_pipe(int p[2]) { - if (p[0] != -1) - close(p[0]); - if (p[1] != -1) - close(p[1]); - p[0] = p[1] = -1; -} - -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 = 1; - int daemon_pipe[2] = { -1, -1 }; - - if (!(cmdline = pa_cmdline_parse(argc, argv))) { - fprintf(stderr, __FILE__": failed to parse command line.\n"); - goto finish; - } - - if (cmdline->help) { - pa_cmdline_help(argv[0]); - retval = 0; - goto finish; - } - - if (cmdline->daemonize) { - pid_t child; - - if (pa_stdio_acquire() < 0) { - fprintf(stderr, __FILE__": failed to acquire stdio.\n"); - goto finish; - } - - if (pipe(daemon_pipe) < 0) { - fprintf(stderr, __FILE__": failed to create pipe.\n"); - goto finish; - } - - if ((child = fork()) < 0) { - fprintf(stderr, __FILE__": fork() failed: %s\n", strerror(errno)); - goto finish; - } - - if (child != 0) { - /* Father */ - - close(daemon_pipe[1]); - daemon_pipe[1] = -1; - - if (pa_loop_read(daemon_pipe[0], &retval, sizeof(retval)) != sizeof(retval)) { - fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno)); - retval = 1; - } - - goto finish; - } - - close(daemon_pipe[0]); - daemon_pipe[0] = -1; - - setsid(); - setpgrp(); - } - - r = lt_dlinit(); - assert(r == 0); - - mainloop = pa_mainloop_new(); - assert(mainloop); - - r = pa_signal_init(pa_mainloop_get_api(mainloop)); - assert(r == 0); - pa_signal_register(SIGINT, exit_signal_callback, NULL); - signal(SIGPIPE, SIG_IGN); - - c = pa_core_new(pa_mainloop_get_api(mainloop)); - assert(c); - - 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); - - if (r < 0 && cmdline->fail) { - fprintf(stderr, __FILE__": failed to initialize daemon.\n"); - if (cmdline->daemonize) - pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); - } else if (!c->modules || pa_idxset_ncontents(c->modules) == 0) { - fprintf(stderr, __FILE__": daemon startup without any loaded modules, refusing to work.\n"); - if (cmdline->daemonize) - pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); - } else { - retval = 0; - if (cmdline->daemonize) - pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); - 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); - - lt_dlexit(); - -finish: - - if (cmdline) - pa_cmdline_free(cmdline); - - close_pipe(daemon_pipe); - - return retval; -} diff --git a/src/mainloop-api.c b/src/mainloop-api.c deleted file mode 100644 index cce49c06..00000000 --- a/src/mainloop-api.c +++ /dev/null @@ -1,60 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include "mainloop-api.h" - -struct once_info { - void (*callback)(void *userdata); - void *userdata; -}; - -static void once_callback(struct pa_mainloop_api *api, void *id, void *userdata) { - struct once_info *i = userdata; - assert(api && i && i->callback); - i->callback(i->userdata); - assert(api->cancel_fixed); - api->cancel_fixed(api, id); - free(i); -} - -void pa_mainloop_api_once(struct pa_mainloop_api* api, void (*callback)(void *userdata), void *userdata) { - struct once_info *i; - void *id; - assert(api && callback); - - i = malloc(sizeof(struct once_info)); - assert(i); - i->callback = callback; - i->userdata = userdata; - - assert(api->source_fixed); - id = api->source_fixed(api, once_callback, i); - assert(id); - - /* Note: if the mainloop is destroyed before once_callback() was called, some memory is leaked. */ -} - diff --git a/src/mainloop-api.h b/src/mainloop-api.h deleted file mode 100644 index 0228f580..00000000 --- a/src/mainloop-api.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef foomainloopapihfoo -#define foomainloopapihfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -enum pa_mainloop_api_io_events { - PA_MAINLOOP_API_IO_EVENT_NULL = 0, - PA_MAINLOOP_API_IO_EVENT_INPUT = 1, - PA_MAINLOOP_API_IO_EVENT_OUTPUT = 2, - PA_MAINLOOP_API_IO_EVENT_BOTH = 3, - PA_MAINLOOP_API_IO_EVENT_HUP = 4 -}; - -struct pa_mainloop_api { - void *userdata; - - /* IO sources */ - void* (*source_io)(struct pa_mainloop_api*a, int fd, enum pa_mainloop_api_io_events events, void (*callback) (struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata), void *userdata); - void (*enable_io)(struct pa_mainloop_api*a, void* id, enum pa_mainloop_api_io_events events); - void (*cancel_io)(struct pa_mainloop_api*a, void* id); - - /* Fixed sources */ - void* (*source_fixed)(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, void *id, void *userdata), void *userdata); - void (*enable_fixed)(struct pa_mainloop_api*a, void* id, int b); - void (*cancel_fixed)(struct pa_mainloop_api*a, void* id); - - /* Idle sources */ - void* (*source_idle)(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, void *id, void *userdata), void *userdata); - void (*enable_idle)(struct pa_mainloop_api*a, void* id, int b); - void (*cancel_idle)(struct pa_mainloop_api*a, void* id); - - /* Time sources */ - void* (*source_time)(struct pa_mainloop_api*a, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*a, void *id, const struct timeval *tv, void *userdata), void *userdata); - void (*enable_time)(struct pa_mainloop_api*a, void *id, const struct timeval *tv); - void (*cancel_time)(struct pa_mainloop_api*a, void* id); - - /* Exit mainloop */ - void (*quit)(struct pa_mainloop_api*a, int retval); -}; - -void pa_mainloop_api_once(struct pa_mainloop_api*m, void (*callback)(void *userdata), void *userdata); - -#endif diff --git a/src/mainloop-signal.c b/src/mainloop-signal.c deleted file mode 100644 index 642ca5e0..00000000 --- a/src/mainloop-signal.c +++ /dev/null @@ -1,163 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "mainloop-signal.h" -#include "util.h" - -struct signal_info { - int sig; - struct sigaction saved_sigaction; - void (*callback) (void *id, int signal, void *userdata); - void *userdata; - struct signal_info *previous, *next; -}; - -static struct pa_mainloop_api *api = NULL; -static int signal_pipe[2] = { -1, -1 }; -static void* mainloop_source = NULL; -static struct signal_info *signals = NULL; - -static void signal_handler(int sig) { - write(signal_pipe[1], &sig, sizeof(sig)); -} - -static void callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { - assert(a && id && events == PA_MAINLOOP_API_IO_EVENT_INPUT && id == mainloop_source && fd == signal_pipe[0]); - - for (;;) { - ssize_t r; - int sig; - struct signal_info*s; - - if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) { - if (errno == EAGAIN) - return; - - fprintf(stderr, "signal.c: read(): %s\n", strerror(errno)); - return; - } - - if (r != sizeof(sig)) { - fprintf(stderr, "signal.c: short read()\n"); - return; - } - - for (s = signals; s; s = s->next) - if (s->sig == sig) { - assert(s->callback); - s->callback(s, sig, s->userdata); - break; - } - } -} - -int pa_signal_init(struct pa_mainloop_api *a) { - assert(a); - if (pipe(signal_pipe) < 0) { - fprintf(stderr, "pipe() failed: %s\n", strerror(errno)); - return -1; - } - - pa_make_nonblock_fd(signal_pipe[0]); - pa_make_nonblock_fd(signal_pipe[1]); - - api = a; - mainloop_source = api->source_io(api, signal_pipe[0], PA_MAINLOOP_API_IO_EVENT_INPUT, callback, NULL); - assert(mainloop_source); - return 0; -} - -void pa_signal_done(void) { - assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && mainloop_source); - - api->cancel_io(api, mainloop_source); - mainloop_source = NULL; - - close(signal_pipe[0]); - close(signal_pipe[1]); - signal_pipe[0] = signal_pipe[1] = -1; - - while (signals) - pa_signal_unregister(signals); - - api = NULL; -} - -void* pa_signal_register(int sig, void (*callback) (void *id, int signal, void *userdata), void *userdata) { - struct signal_info *s = NULL; - struct sigaction sa; - assert(sig > 0 && callback); - - for (s = signals; s; s = s->next) - if (s->sig == sig) - goto fail; - - s = malloc(sizeof(struct signal_info)); - assert(s); - s->sig = sig; - s->callback = callback; - s->userdata = userdata; - - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = signal_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - - if (sigaction(sig, &sa, &s->saved_sigaction) < 0) - goto fail; - - s->previous = NULL; - s->next = signals; - signals = s; - - return s; -fail: - if (s) - free(s); - return NULL; -} - -void pa_signal_unregister(void *id) { - struct signal_info *s = id; - assert(s); - - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; - else - signals = s->next; - - sigaction(s->sig, &s->saved_sigaction, NULL); - free(s); -} diff --git a/src/mainloop-signal.h b/src/mainloop-signal.h deleted file mode 100644 index 8afe9c8d..00000000 --- a/src/mainloop-signal.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef foomainloopsignalhfoo -#define foomainloopsignalhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "mainloop-api.h" - -int pa_signal_init(struct pa_mainloop_api *api); -void pa_signal_done(void); - -void* pa_signal_register(int signal, void (*callback) (void *id, int signal, void *userdata), void *userdata); -void pa_signal_unregister(void *id); - -#endif diff --git a/src/mainloop.c b/src/mainloop.c deleted file mode 100644 index b9eee86d..00000000 --- a/src/mainloop.c +++ /dev/null @@ -1,553 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mainloop.h" -#include "util.h" -#include "idxset.h" - -struct mainloop_source_header { - struct pa_mainloop *mainloop; - int dead; -}; - -struct mainloop_source_io { - struct mainloop_source_header header; - - int fd; - enum pa_mainloop_api_io_events events; - void (*callback) (struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata); - void *userdata; - - struct pollfd *pollfd; -}; - -struct mainloop_source_fixed_or_idle { - struct mainloop_source_header header; - int enabled; - - void (*callback)(struct pa_mainloop_api*a, void *id, void *userdata); - void *userdata; -}; - -struct mainloop_source_time { - struct mainloop_source_header header; - int enabled; - - struct timeval timeval; - void (*callback)(struct pa_mainloop_api*a, void *id, const struct timeval*tv, void *userdata); - void *userdata; -}; - -struct pa_mainloop { - struct pa_idxset *io_sources, *fixed_sources, *idle_sources, *time_sources; - int io_sources_scan_dead, fixed_sources_scan_dead, idle_sources_scan_dead, time_sources_scan_dead; - - struct pollfd *pollfds; - unsigned max_pollfds, n_pollfds; - int rebuild_pollfds; - - int quit, running, retval; - struct pa_mainloop_api api; -}; - -static void setup_api(struct pa_mainloop *m); - -struct pa_mainloop *pa_mainloop_new(void) { - struct pa_mainloop *m; - - m = malloc(sizeof(struct pa_mainloop)); - assert(m); - - m->io_sources = pa_idxset_new(NULL, NULL); - m->fixed_sources = pa_idxset_new(NULL, NULL); - m->idle_sources = pa_idxset_new(NULL, NULL); - m->time_sources = pa_idxset_new(NULL, NULL); - - assert(m->io_sources && m->fixed_sources && m->idle_sources && m->time_sources); - - m->io_sources_scan_dead = m->fixed_sources_scan_dead = m->idle_sources_scan_dead = m->time_sources_scan_dead = 0; - - m->pollfds = NULL; - m->max_pollfds = m->n_pollfds = m->rebuild_pollfds = 0; - - m->quit = m->running = m->retval = 0; - - setup_api(m); - - return m; -} - -static int foreach(void *p, uint32_t index, int *del, void*userdata) { - struct mainloop_source_header *h = p; - int *all = userdata; - assert(p && del && all); - - if (*all || h->dead) { - free(h); - *del = 1; - } - - return 0; -}; - -void pa_mainloop_free(struct pa_mainloop* m) { - int all = 1; - assert(m); - pa_idxset_foreach(m->io_sources, foreach, &all); - pa_idxset_foreach(m->fixed_sources, foreach, &all); - pa_idxset_foreach(m->idle_sources, foreach, &all); - pa_idxset_foreach(m->time_sources, foreach, &all); - - pa_idxset_free(m->io_sources, NULL, NULL); - pa_idxset_free(m->fixed_sources, NULL, NULL); - pa_idxset_free(m->idle_sources, NULL, NULL); - pa_idxset_free(m->time_sources, NULL, NULL); - - free(m->pollfds); - free(m); -} - -static void scan_dead(struct pa_mainloop *m) { - int all = 0; - assert(m); - if (m->io_sources_scan_dead) - pa_idxset_foreach(m->io_sources, foreach, &all); - if (m->fixed_sources_scan_dead) - pa_idxset_foreach(m->fixed_sources, foreach, &all); - if (m->idle_sources_scan_dead) - pa_idxset_foreach(m->idle_sources, foreach, &all); - if (m->time_sources_scan_dead) - pa_idxset_foreach(m->time_sources, foreach, &all); -} - -static void rebuild_pollfds(struct pa_mainloop *m) { - struct mainloop_source_io*s; - struct pollfd *p; - uint32_t index = PA_IDXSET_INVALID; - unsigned l; - - l = pa_idxset_ncontents(m->io_sources); - if (m->max_pollfds < l) { - m->pollfds = realloc(m->pollfds, sizeof(struct pollfd)*l); - m->max_pollfds = l; - } - - m->n_pollfds = 0; - p = m->pollfds; - for (s = pa_idxset_first(m->io_sources, &index); s; s = pa_idxset_next(m->io_sources, &index)) { - if (s->header.dead) { - s->pollfd = NULL; - continue; - } - - s->pollfd = p; - p->fd = s->fd; - p->events = ((s->events & PA_MAINLOOP_API_IO_EVENT_INPUT) ? POLLIN : 0) | ((s->events & PA_MAINLOOP_API_IO_EVENT_OUTPUT) ? POLLOUT : 0); - p->revents = 0; - - p++; - m->n_pollfds++; - } -} - -static void dispatch_pollfds(struct pa_mainloop *m) { - uint32_t index = PA_IDXSET_INVALID; - struct mainloop_source_io *s; - - for (s = pa_idxset_first(m->io_sources, &index); s; s = pa_idxset_next(m->io_sources, &index)) { - if (s->header.dead || !s->pollfd || !s->pollfd->revents) - continue; - - assert(s->pollfd->fd == s->fd && s->callback); - s->callback(&m->api, s, s->fd, - ((s->pollfd->revents & POLLHUP) ? PA_MAINLOOP_API_IO_EVENT_HUP : 0) | - ((s->pollfd->revents & POLLIN) ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | - ((s->pollfd->revents & POLLOUT) ? PA_MAINLOOP_API_IO_EVENT_OUTPUT : 0), s->userdata); - s->pollfd->revents = 0; - } -} - -static void run_fixed_or_idle(struct pa_mainloop *m, struct pa_idxset *i) { - uint32_t index = PA_IDXSET_INVALID; - struct mainloop_source_fixed_or_idle *s; - - for (s = pa_idxset_first(i, &index); s; s = pa_idxset_next(i, &index)) { - if (s->header.dead || !s->enabled) - continue; - - assert(s->callback); - s->callback(&m->api, s, s->userdata); - } -} - -static int calc_next_timeout(struct pa_mainloop *m) { - uint32_t index = PA_IDXSET_INVALID; - struct mainloop_source_time *s; - struct timeval now; - int t = -1; - - if (pa_idxset_isempty(m->time_sources)) - return -1; - - gettimeofday(&now, NULL); - - for (s = pa_idxset_first(m->time_sources, &index); s; s = pa_idxset_next(m->time_sources, &index)) { - int tmp; - - if (s->header.dead || !s->enabled) - continue; - - if (s->timeval.tv_sec < now.tv_sec || (s->timeval.tv_sec == now.tv_sec && s->timeval.tv_usec <= now.tv_usec)) - return 0; - - tmp = (s->timeval.tv_sec - now.tv_sec)*1000; - - if (s->timeval.tv_usec > now.tv_usec) - tmp += (s->timeval.tv_usec - now.tv_usec)/1000; - else - tmp -= (now.tv_usec - s->timeval.tv_usec)/1000; - - if (tmp == 0) - return 0; - else if (t == -1 || tmp < t) - t = tmp; - } - - return t; -} - -static void dispatch_timeout(struct pa_mainloop *m) { - uint32_t index = PA_IDXSET_INVALID; - struct mainloop_source_time *s; - struct timeval now; - assert(m); - - if (pa_idxset_isempty(m->time_sources)) - return; - - gettimeofday(&now, NULL); - for (s = pa_idxset_first(m->time_sources, &index); s; s = pa_idxset_next(m->time_sources, &index)) { - - if (s->header.dead || !s->enabled) - continue; - - if (s->timeval.tv_sec < now.tv_sec || (s->timeval.tv_sec == now.tv_sec && s->timeval.tv_usec <= now.tv_usec)) { - assert(s->callback); - - s->enabled = 0; - s->callback(&m->api, s, &s->timeval, s->userdata); - } - } -} - -static int any_idle_sources(struct pa_mainloop *m) { - struct mainloop_source_fixed_or_idle *s; - uint32_t index; - assert(m); - - for (s = pa_idxset_first(m->idle_sources, &index); s; s = pa_idxset_next(m->idle_sources, &index)) - if (!s->header.dead && s->enabled) - return 1; - - return 0; -} - -int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval) { - int r, idle; - assert(m && !m->running); - - if(m->quit) { - if (retval) - *retval = m->retval; - return 1; - } - - m->running = 1; - - scan_dead(m); - run_fixed_or_idle(m, m->fixed_sources); - - if (m->rebuild_pollfds) { - rebuild_pollfds(m); - m->rebuild_pollfds = 0; - } - - idle = any_idle_sources(m); - - do { - int t; - - if (!block || idle) - t = 0; - else - t = calc_next_timeout(m); - - r = poll(m->pollfds, m->n_pollfds, t); - } while (r < 0 && errno == EINTR); - - dispatch_timeout(m); - - if (r > 0) - dispatch_pollfds(m); - else if (r == 0 && idle) - run_fixed_or_idle(m, m->idle_sources); - else if (r < 0) - fprintf(stderr, "select(): %s\n", strerror(errno)); - - m->running = 0; - return r < 0 ? -1 : 0; -} - -int pa_mainloop_run(struct pa_mainloop *m, int *retval) { - int r; - while ((r = pa_mainloop_iterate(m, 1, retval)) == 0); - return r; -} - -void pa_mainloop_quit(struct pa_mainloop *m, int r) { - assert(m); - m->quit = r; -} - -/* IO sources */ -static void* mainloop_source_io(struct pa_mainloop_api*a, int fd, enum pa_mainloop_api_io_events events, void (*callback) (struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata), void *userdata) { - struct pa_mainloop *m; - struct mainloop_source_io *s; - assert(a && a->userdata && fd >= 0 && callback); - m = a->userdata; - assert(a == &m->api); - - s = malloc(sizeof(struct mainloop_source_io)); - assert(s); - s->header.mainloop = m; - s->header.dead = 0; - - s->fd = fd; - s->events = events; - s->callback = callback; - s->userdata = userdata; - s->pollfd = NULL; - - pa_idxset_put(m->io_sources, s, NULL); - m->rebuild_pollfds = 1; - return s; -} - -static void mainloop_enable_io(struct pa_mainloop_api*a, void* id, enum pa_mainloop_api_io_events events) { - struct pa_mainloop *m; - struct mainloop_source_io *s = id; - assert(a && a->userdata && s && !s->header.dead); - m = a->userdata; - assert(a == &m->api && s->header.mainloop == m); - - s->events = events; - if (s->pollfd) - s->pollfd->events = ((s->events & PA_MAINLOOP_API_IO_EVENT_INPUT) ? POLLIN : 0) | ((s->events & PA_MAINLOOP_API_IO_EVENT_OUTPUT) ? POLLOUT : 0); -} - -static void mainloop_cancel_io(struct pa_mainloop_api*a, void* id) { - struct pa_mainloop *m; - struct mainloop_source_io *s = id; - assert(a && a->userdata && s && !s->header.dead); - m = a->userdata; - assert(a == &m->api && s->header.mainloop == m); - - s->header.dead = 1; - m->io_sources_scan_dead = 1; - m->rebuild_pollfds = 1; -} - -/* Fixed sources */ -static void* mainloop_source_fixed(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, void *id, void *userdata), void *userdata) { - struct pa_mainloop *m; - struct mainloop_source_fixed_or_idle *s; - assert(a && a->userdata && callback); - m = a->userdata; - assert(a == &m->api); - - s = malloc(sizeof(struct mainloop_source_fixed_or_idle)); - assert(s); - s->header.mainloop = m; - s->header.dead = 0; - - s->enabled = 1; - s->callback = callback; - s->userdata = userdata; - - pa_idxset_put(m->fixed_sources, s, NULL); - return s; -} - -static void mainloop_enable_fixed(struct pa_mainloop_api*a, void* id, int b) { - struct pa_mainloop *m; - struct mainloop_source_fixed_or_idle *s = id; - assert(a && a->userdata && s && !s->header.dead); - m = a->userdata; - assert(a == &m->api); - - s->enabled = b; -} - -static void mainloop_cancel_fixed(struct pa_mainloop_api*a, void* id) { - struct pa_mainloop *m; - struct mainloop_source_fixed_or_idle *s = id; - assert(a && a->userdata && s && !s->header.dead); - m = a->userdata; - assert(a == &m->api); - - s->header.dead = 1; - m->fixed_sources_scan_dead = 1; -} - -/* Idle sources */ -static void* mainloop_source_idle(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, void *id, void *userdata), void *userdata) { - struct pa_mainloop *m; - struct mainloop_source_fixed_or_idle *s; - assert(a && a->userdata && callback); - m = a->userdata; - assert(a == &m->api); - - s = malloc(sizeof(struct mainloop_source_fixed_or_idle)); - assert(s); - s->header.mainloop = m; - s->header.dead = 0; - - s->enabled = 1; - s->callback = callback; - s->userdata = userdata; - - pa_idxset_put(m->idle_sources, s, NULL); - return s; -} - -static void mainloop_cancel_idle(struct pa_mainloop_api*a, void* id) { - struct pa_mainloop *m; - struct mainloop_source_fixed_or_idle *s = id; - assert(a && a->userdata && s && !s->header.dead); - m = a->userdata; - assert(a == &m->api); - - s->header.dead = 1; - m->idle_sources_scan_dead = 1; -} - -/* Time sources */ -static void* mainloop_source_time(struct pa_mainloop_api*a, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*a, void *id, const struct timeval *tv, void *userdata), void *userdata) { - struct pa_mainloop *m; - struct mainloop_source_time *s; - assert(a && a->userdata && callback); - m = a->userdata; - assert(a == &m->api); - - s = malloc(sizeof(struct mainloop_source_time)); - assert(s); - s->header.mainloop = m; - s->header.dead = 0; - - s->enabled = !!tv; - if (tv) - s->timeval = *tv; - - s->callback = callback; - s->userdata = userdata; - - pa_idxset_put(m->time_sources, s, NULL); - return s; -} - -static void mainloop_enable_time(struct pa_mainloop_api*a, void *id, const struct timeval *tv) { - struct pa_mainloop *m; - struct mainloop_source_time *s = id; - assert(a && a->userdata && s && !s->header.dead); - m = a->userdata; - assert(a == &m->api); - - if (tv) { - s->enabled = 1; - s->timeval = *tv; - } else - s->enabled = 0; -} - -static void mainloop_cancel_time(struct pa_mainloop_api*a, void* id) { - struct pa_mainloop *m; - struct mainloop_source_time *s = id; - assert(a && a->userdata && s && !s->header.dead); - m = a->userdata; - assert(a == &m->api); - - s->header.dead = 1; - m->time_sources_scan_dead = 1; - -} - -static void mainloop_quit(struct pa_mainloop_api*a, int retval) { - struct pa_mainloop *m; - assert(a && a->userdata); - m = a->userdata; - assert(a == &m->api); - - m->quit = 1; - m->retval = retval; -} - -static void setup_api(struct pa_mainloop *m) { - assert(m); - - m->api.userdata = m; - m->api.source_io = mainloop_source_io; - m->api.enable_io = mainloop_enable_io; - m->api.cancel_io = mainloop_cancel_io; - - m->api.source_fixed = mainloop_source_fixed; - m->api.enable_fixed = mainloop_enable_fixed; - m->api.cancel_fixed = mainloop_cancel_fixed; - - m->api.source_idle = mainloop_source_idle; - m->api.enable_idle = mainloop_enable_fixed; /* (!) */ - m->api.cancel_idle = mainloop_cancel_idle; - - m->api.source_time = mainloop_source_time; - m->api.enable_time = mainloop_enable_time; - m->api.cancel_time = mainloop_cancel_time; - - m->api.quit = mainloop_quit; -} - -struct pa_mainloop_api* pa_mainloop_get_api(struct pa_mainloop*m) { - assert(m); - return &m->api; -} - diff --git a/src/mainloop.h b/src/mainloop.h deleted file mode 100644 index 58448c3e..00000000 --- a/src/mainloop.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef foomainloophfoo -#define foomainloophfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "mainloop-api.h" - -struct pa_mainloop; - -struct pa_mainloop *pa_mainloop_new(void); -void pa_mainloop_free(struct pa_mainloop* m); - -int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval); -int pa_mainloop_run(struct pa_mainloop *m, int *retval); - -struct pa_mainloop_api* pa_mainloop_get_api(struct pa_mainloop*m); - -#endif diff --git a/src/memblock.c b/src/memblock.c deleted file mode 100644 index 8f24ff22..00000000 --- a/src/memblock.c +++ /dev/null @@ -1,113 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "memblock.h" - -static unsigned memblock_count = 0, memblock_total = 0; - -struct pa_memblock *pa_memblock_new(size_t length) { - struct pa_memblock *b = malloc(sizeof(struct pa_memblock)+length); - b->type = PA_MEMBLOCK_APPENDED; - b->ref = 1; - b->length = length; - b->data = b+1; - memblock_count++; - memblock_total += length; - return b; -} - -struct pa_memblock *pa_memblock_new_fixed(void *d, size_t length) { - struct pa_memblock *b = malloc(sizeof(struct pa_memblock)); - b->type = PA_MEMBLOCK_FIXED; - b->ref = 1; - b->length = length; - b->data = d; - memblock_count++; - memblock_total += length; - return b; -} - -struct pa_memblock *pa_memblock_new_dynamic(void *d, size_t length) { - struct pa_memblock *b = malloc(sizeof(struct pa_memblock)); - b->type = PA_MEMBLOCK_DYNAMIC; - b->ref = 1; - b->length = length; - b->data = d; - memblock_count++; - memblock_total += length; - return b; -} - -struct pa_memblock* pa_memblock_ref(struct pa_memblock*b) { - assert(b && b->ref >= 1); - b->ref++; - return b; -} - -void pa_memblock_unref(struct pa_memblock*b) { - assert(b && b->ref >= 1); - b->ref--; - - if (b->ref == 0) { - if (b->type == PA_MEMBLOCK_DYNAMIC) - free(b->data); - - memblock_count--; - memblock_total -= b->length; - - free(b); - } -} - -void pa_memblock_unref_fixed(struct pa_memblock *b) { - void *d; - - assert(b && b->ref >= 1); - - if (b->ref == 1) { - pa_memblock_unref(b); - return; - } else { - d = malloc(b->length); - assert(d); - memcpy(d, b->data, b->length); - b->data = d; - b->type = PA_MEMBLOCK_DYNAMIC; - b->ref--; - } -} - -unsigned pa_memblock_get_count(void) { - return memblock_count; -} - -unsigned pa_memblock_get_total(void) { - return memblock_total; -} diff --git a/src/memblock.h b/src/memblock.h deleted file mode 100644 index 4bb02977..00000000 --- a/src/memblock.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef foomemblockhfoo -#define foomemblockhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -enum pa_memblock_type { PA_MEMBLOCK_FIXED, PA_MEMBLOCK_APPENDED, PA_MEMBLOCK_DYNAMIC }; - -struct pa_memblock { - enum pa_memblock_type type; - unsigned ref; - size_t length; - void *data; -}; - -struct pa_memblock *pa_memblock_new(size_t length); -struct pa_memblock *pa_memblock_new_fixed(void *data, size_t length); -struct pa_memblock *pa_memblock_new_dynamic(void *data, size_t length); - -void pa_memblock_unref(struct pa_memblock*b); -struct pa_memblock* pa_memblock_ref(struct pa_memblock*b); - -void pa_memblock_unref_fixed(struct pa_memblock*b); - -unsigned pa_memblock_get_count(void); -unsigned pa_memblock_get_total(void); - -#endif diff --git a/src/memblockq.c b/src/memblockq.c deleted file mode 100644 index eff923b9..00000000 --- a/src/memblockq.c +++ /dev/null @@ -1,326 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "memblockq.h" - -struct memblock_list { - struct memblock_list *next; - struct pa_memchunk chunk; - struct timeval stamp; -}; - -struct pa_memblockq { - struct memblock_list *blocks, *blocks_tail; - unsigned n_blocks; - size_t current_length, maxlength, tlength, base, prebuf, minreq; - int measure_delay; - uint32_t delay; - struct pa_mcalign *mcalign; -}; - -struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t base, size_t prebuf, size_t minreq) { - struct pa_memblockq* bq; - assert(maxlength && base && maxlength); - - bq = malloc(sizeof(struct pa_memblockq)); - assert(bq); - bq->blocks = bq->blocks_tail = 0; - bq->n_blocks = 0; - - bq->current_length = 0; - - fprintf(stderr, "memblockq requested: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", maxlength, tlength, base, prebuf, minreq); - - bq->base = base; - - bq->maxlength = ((maxlength+base-1)/base)*base; - assert(bq->maxlength >= base); - - bq->tlength = ((tlength+base-1)/base)*base; - if (bq->tlength == 0 || bq->tlength >= bq->maxlength) - bq->tlength = bq->maxlength; - - bq->prebuf = (prebuf == (size_t) -1) ? bq->maxlength/2 : prebuf; - bq->prebuf = (bq->prebuf/base)*base; - if (bq->prebuf > bq->maxlength) - bq->prebuf = bq->maxlength; - - bq->minreq = (minreq/base)*base; - if (bq->minreq == 0) - bq->minreq = 1; - - fprintf(stderr, "memblockq sanitized: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", bq->maxlength, bq->tlength, bq->base, bq->prebuf, bq->minreq); - - bq->measure_delay = 0; - bq->delay = 0; - - bq->mcalign = NULL; - - return bq; -} - -void pa_memblockq_free(struct pa_memblockq* bq) { - struct memblock_list *l; - assert(bq); - - if (bq->mcalign) - pa_mcalign_free(bq->mcalign); - - while ((l = bq->blocks)) { - bq->blocks = l->next; - pa_memblock_unref(l->chunk.memblock); - free(l); - } - - free(bq); -} - -void pa_memblockq_push(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta) { - struct memblock_list *q; - assert(bq && chunk && chunk->memblock && chunk->length && (chunk->length % bq->base) == 0); - - if (bq->blocks_tail && bq->blocks_tail->chunk.memblock == chunk->memblock) { - /* Try to merge memory chunks */ - - if (bq->blocks_tail->chunk.index+bq->blocks_tail->chunk.length == chunk->index) { - bq->blocks_tail->chunk.length += chunk->length; - bq->current_length += chunk->length; - - /* fprintf(stderr, __FILE__": merge succeeded: %u\n", chunk->length);*/ - return; - } - } - - q = malloc(sizeof(struct memblock_list)); - assert(q); - - if (bq->measure_delay) - gettimeofday(&q->stamp, NULL); - else - timerclear(&q->stamp); - - q->chunk = *chunk; - pa_memblock_ref(q->chunk.memblock); - assert(q->chunk.index+q->chunk.length <= q->chunk.memblock->length); - q->next = NULL; - - if (bq->blocks_tail) - bq->blocks_tail->next = q; - else - bq->blocks = q; - - bq->blocks_tail = q; - - bq->n_blocks++; - bq->current_length += chunk->length; - - pa_memblockq_shorten(bq, bq->maxlength); -} - -int pa_memblockq_peek(struct pa_memblockq* bq, struct pa_memchunk *chunk) { - assert(bq && chunk); - - if (!bq->blocks || bq->current_length < bq->prebuf) - return -1; - - bq->prebuf = 0; - - *chunk = bq->blocks->chunk; - pa_memblock_ref(chunk->memblock); - -/* if (chunk->memblock->ref != 2) */ -/* fprintf(stderr, "block %p with ref %u peeked.\n", chunk->memblock, chunk->memblock->ref); */ - - return 0; -} - -/* -int memblockq_pop(struct memblockq* bq, struct pa_memchunk *chunk) { - struct memblock_list *q; - - assert(bq && chunk); - - if (!bq->blocks || bq->current_length < bq->prebuf) - return -1; - - bq->prebuf = 0; - - q = bq->blocks; - bq->blocks = bq->blocks->next; - - *chunk = q->chunk; - - bq->n_blocks--; - bq->current_length -= chunk->length; - - free(q); - return 0; -} -*/ - -static uint32_t age(struct timeval *tv) { - assert(tv); - struct timeval now; - uint32_t r; - - if (tv->tv_sec == 0) - return 0; - - gettimeofday(&now, NULL); - - r = (now.tv_sec-tv->tv_sec) * 1000000; - - if (now.tv_usec >= tv->tv_usec) - r += now.tv_usec - tv->tv_usec; - else - r -= tv->tv_usec - now.tv_usec; - - return r; -} - -void pa_memblockq_drop(struct pa_memblockq *bq, size_t length) { - assert(bq && length && (length % bq->base) == 0); - - while (length > 0) { - size_t l = length; - assert(bq->blocks && bq->current_length >= length); - - if (l > bq->blocks->chunk.length) - l = bq->blocks->chunk.length; - - if (bq->measure_delay) - bq->delay = age(&bq->blocks->stamp); - - bq->blocks->chunk.index += l; - bq->blocks->chunk.length -= l; - bq->current_length -= l; - - if (bq->blocks->chunk.length == 0) { - struct memblock_list *q; - - q = bq->blocks; - bq->blocks = bq->blocks->next; - if (bq->blocks == NULL) - bq->blocks_tail = NULL; - pa_memblock_unref(q->chunk.memblock); - free(q); - - bq->n_blocks--; - } - - length -= l; - } -} - -void pa_memblockq_shorten(struct pa_memblockq *bq, size_t length) { - size_t l; - assert(bq); - - if (bq->current_length <= length) - return; - - fprintf(stderr, "Warning! pa_memblockq_shorten()\n"); - - l = bq->current_length - length; - l /= bq->base; - l *= bq->base; - - pa_memblockq_drop(bq, l); -} - - -void pa_memblockq_empty(struct pa_memblockq *bq) { - assert(bq); - pa_memblockq_shorten(bq, 0); -} - -int pa_memblockq_is_readable(struct pa_memblockq *bq) { - assert(bq); - - return bq->current_length && (bq->current_length >= bq->prebuf); -} - -int pa_memblockq_is_writable(struct pa_memblockq *bq, size_t length) { - assert(bq); - - return bq->current_length + length <= bq->tlength; -} - -uint32_t pa_memblockq_get_delay(struct pa_memblockq *bq) { - assert(bq); - return bq->delay; -} - -uint32_t pa_memblockq_get_length(struct pa_memblockq *bq) { - assert(bq); - return bq->current_length; -} - -uint32_t pa_memblockq_missing(struct pa_memblockq *bq) { - size_t l; - assert(bq); - - if (bq->current_length >= bq->tlength) - return 0; - - l = bq->tlength - bq->current_length; - assert(l); - - return (l >= bq->minreq) ? l : 0; -} - -void pa_memblockq_push_align(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta) { - struct pa_memchunk rchunk; - assert(bq && chunk && bq->base); - - if (bq->base == 1) { - pa_memblockq_push(bq, chunk, delta); - return; - } - - if (!bq->mcalign) { - bq->mcalign = pa_mcalign_new(bq->base); - assert(bq->mcalign); - } - - pa_mcalign_push(bq->mcalign, chunk); - - while (pa_mcalign_pop(bq->mcalign, &rchunk) >= 0) { - pa_memblockq_push(bq, &rchunk, delta); - pa_memblock_unref(rchunk.memblock); - delta = 0; - } -} - -uint32_t pa_memblockq_get_minreq(struct pa_memblockq *bq) { - assert(bq); - return bq->minreq; -} diff --git a/src/memblockq.h b/src/memblockq.h deleted file mode 100644 index e6ad01db..00000000 --- a/src/memblockq.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef foomemblockqhfoo -#define foomemblockqhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "memblock.h" -#include "memchunk.h" - -struct pa_memblockq; - -/* Parameters: - - maxlength: maximum length of queue. If more data is pushed into the queue, data from the front is dropped - - length: the target length of the queue. - - base: a base value for all metrics. Only multiples of this value are popped from the queue - - prebuf: before passing the first byte out, make sure that enough bytes are in the queue - - minreq: pa_memblockq_missing() will only return values greater than this value -*/ -struct pa_memblockq* pa_memblockq_new(size_t maxlength, - size_t tlength, - size_t base, - size_t prebuf, - size_t minreq); -void pa_memblockq_free(struct pa_memblockq*bq); - -/* Push a new memory chunk into the queue. Optionally specify a value for future cancellation. This is currently not implemented, however! */ -void pa_memblockq_push(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta); - -/* Same as pa_memblockq_push(), however chunks are filtered through a mcalign object, and thus aligned to multiples of base */ -void pa_memblockq_push_align(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta); - -/* Return a copy of the next memory chunk in the queue. It is not removed from the queue */ -int pa_memblockq_peek(struct pa_memblockq* bq, struct pa_memchunk *chunk); - -/* Drop the specified bytes from the queue */ -void pa_memblockq_drop(struct pa_memblockq *bq, size_t length); - -/* Shorten the pa_memblockq to the specified length by dropping data at the end of the queue */ -void pa_memblockq_shorten(struct pa_memblockq *bq, size_t length); - -/* Empty the pa_memblockq */ -void pa_memblockq_empty(struct pa_memblockq *bq); - -/* Test if the pa_memblockq is currently readable, that is, more data than base */ -int pa_memblockq_is_readable(struct pa_memblockq *bq); - -/* Test if the pa_memblockq is currently writable for the specified amount of bytes */ -int pa_memblockq_is_writable(struct pa_memblockq *bq, size_t length); - -/* The time memory chunks stay in the queue until they are removed completely in usecs */ -uint32_t pa_memblockq_get_delay(struct pa_memblockq *bq); - -/* Return the length of the queue in bytes */ -uint32_t pa_memblockq_get_length(struct pa_memblockq *bq); - -/* Return how many bytes are missing in queue to the specified fill amount */ -uint32_t pa_memblockq_missing(struct pa_memblockq *bq); - - -uint32_t pa_memblockq_get_minreq(struct pa_memblockq *bq); - -#endif diff --git a/src/memchunk.c b/src/memchunk.c deleted file mode 100644 index d27ca61a..00000000 --- a/src/memchunk.c +++ /dev/null @@ -1,149 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "memchunk.h" - -void pa_memchunk_make_writable(struct pa_memchunk *c) { - struct pa_memblock *n; - assert(c && c->memblock && c->memblock->ref >= 1); - - if (c->memblock->ref == 1) - return; - - n = pa_memblock_new(c->length); - assert(n); - memcpy(n->data, c->memblock->data+c->index, c->length); - pa_memblock_unref(c->memblock); - c->memblock = n; - c->index = 0; -} - - -struct pa_mcalign { - size_t base; - struct pa_memchunk chunk; - uint8_t *buffer; - size_t buffer_fill; -}; - -struct pa_mcalign *pa_mcalign_new(size_t base) { - struct pa_mcalign *m; - assert(base); - - m = malloc(sizeof(struct pa_mcalign)); - assert(m); - m->base = base; - m->chunk.memblock = NULL; - m->chunk.length = m->chunk.index = 0; - m->buffer = NULL; - m->buffer_fill = 0; - return m; -} - -void pa_mcalign_free(struct pa_mcalign *m) { - assert(m); - - free(m->buffer); - - if (m->chunk.memblock) - pa_memblock_unref(m->chunk.memblock); - - free(m); -} - -void pa_mcalign_push(struct pa_mcalign *m, const struct pa_memchunk *c) { - assert(m && c && !m->chunk.memblock && c->memblock && c->length); - - m->chunk = *c; - pa_memblock_ref(m->chunk.memblock); -} - -int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c) { - assert(m && c && m->base > m->buffer_fill); - int ret; - - if (!m->chunk.memblock) - return -1; - - if (m->buffer_fill) { - size_t l = m->base - m->buffer_fill; - if (l > m->chunk.length) - l = m->chunk.length; - assert(m->buffer && l); - - memcpy(m->buffer + m->buffer_fill, m->chunk.memblock->data + m->chunk.index, l); - m->buffer_fill += l; - m->chunk.index += l; - m->chunk.length -= l; - - if (m->chunk.length == 0) { - m->chunk.length = m->chunk.index = 0; - pa_memblock_unref(m->chunk.memblock); - m->chunk.memblock = NULL; - } - - assert(m->buffer_fill <= m->base); - if (m->buffer_fill == m->base) { - c->memblock = pa_memblock_new_dynamic(m->buffer, m->base); - assert(c->memblock); - c->index = 0; - c->length = m->base; - m->buffer = NULL; - m->buffer_fill = 0; - - return 0; - } - - return -1; - } - - m->buffer_fill = m->chunk.length % m->base; - - if (m->buffer_fill) { - assert(!m->buffer); - m->buffer = malloc(m->base); - assert(m->buffer); - m->chunk.length -= m->buffer_fill; - memcpy(m->buffer, m->chunk.memblock->data + m->chunk.index + m->chunk.length, m->buffer_fill); - } - - if (m->chunk.length) { - *c = m->chunk; - pa_memblock_ref(c->memblock); - ret = 0; - } else - ret = -1; - - m->chunk.length = m->chunk.index = 0; - pa_memblock_unref(m->chunk.memblock); - m->chunk.memblock = NULL; - - return ret; -} diff --git a/src/memchunk.h b/src/memchunk.h deleted file mode 100644 index 341c145c..00000000 --- a/src/memchunk.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef foomemchunkhfoo -#define foomemchunkhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "memblock.h" - -struct pa_memchunk { - struct pa_memblock *memblock; - size_t index, length; -}; - -void pa_memchunk_make_writable(struct pa_memchunk *c); - -struct pa_mcalign; - -struct pa_mcalign *pa_mcalign_new(size_t base); -void pa_mcalign_free(struct pa_mcalign *m); -void pa_mcalign_push(struct pa_mcalign *m, const struct pa_memchunk *c); -int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c); - -#endif diff --git a/src/modargs.c b/src/modargs.c deleted file mode 100644 index 280a546d..00000000 --- a/src/modargs.c +++ /dev/null @@ -1,288 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "hashmap.h" -#include "modargs.h" -#include "idxset.h" -#include "sample-util.h" -#include "namereg.h" -#include "sink.h" -#include "source.h" - -struct pa_modargs; - -struct entry { - char *key, *value; -}; - -static int add_key_value(struct pa_hashmap *map, char *key, char *value, const char* const* valid_keys) { - struct entry *e; - assert(map && key && value); - - if (valid_keys) { - const char*const* v; - for (v = valid_keys; *v; v++) - if (strcmp(*v, key) == 0) - break; - - if (!*v) { - free(key); - free(value); - return -1; - } - } - - e = malloc(sizeof(struct entry)); - assert(e); - e->key = key; - e->value = value; - pa_hashmap_put(map, key, e); - return 0; -} - -struct pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) { - struct pa_hashmap *map = NULL; - - map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - assert(map); - - if (args) { - enum { WHITESPACE, KEY, VALUE_START, VALUE_SIMPLE, VALUE_DOUBLE_QUOTES, VALUE_TICKS } state; - const char *p, *key, *value; - size_t key_len, value_len; - - key = value = NULL; - state = WHITESPACE; - for (p = args; *p; p++) { - switch (state) { - case WHITESPACE: - if (*p == '=') - goto fail; - else if (!isspace(*p)) { - key = p; - state = KEY; - key_len = 1; - } - break; - case KEY: - if (*p == '=') - state = VALUE_START; - else - key_len++; - break; - case VALUE_START: - if (*p == '\'') { - state = VALUE_TICKS; - value = p+1; - value_len = 0; - } else if (*p == '"') { - state = VALUE_DOUBLE_QUOTES; - value = p+1; - value_len = 0; - } else if (isspace(*p)) { - if (add_key_value(map, strndup(key, key_len), strdup(""), valid_keys) < 0) - goto fail; - state = WHITESPACE; - } else { - state = VALUE_SIMPLE; - value = p; - value_len = 1; - } - break; - case VALUE_SIMPLE: - if (isspace(*p)) { - if (add_key_value(map, strndup(key, key_len), strndup(value, value_len), valid_keys) < 0) - goto fail; - state = WHITESPACE; - } else - value_len++; - break; - case VALUE_DOUBLE_QUOTES: - if (*p == '"') { - if (add_key_value(map, strndup(key, key_len), strndup(value, value_len), valid_keys) < 0) - goto fail; - state = WHITESPACE; - } else - value_len++; - break; - case VALUE_TICKS: - if (*p == '\'') { - if (add_key_value(map, strndup(key, key_len), strndup(value, value_len), valid_keys) < 0) - goto fail; - state = WHITESPACE; - } else - value_len++; - break; - } - } - - if (state == VALUE_START) { - if (add_key_value(map, strndup(key, key_len), strdup(""), valid_keys) < 0) - goto fail; - } else if (state == VALUE_SIMPLE) { - if (add_key_value(map, strndup(key, key_len), strdup(value), valid_keys) < 0) - goto fail; - } else if (state != WHITESPACE) - goto fail; - } - - return (struct pa_modargs*) map; - -fail: - - if (map) - pa_modargs_free((struct pa_modargs*) map); - - return NULL; -} - - -static void free_func(void *p, void*userdata) { - struct entry *e = p; - assert(e); - free(e->key); - free(e->value); - free(e); -} - -void pa_modargs_free(struct pa_modargs*ma) { - struct pa_hashmap *map = (struct pa_hashmap*) ma; - pa_hashmap_free(map, free_func, NULL); -} - -const char *pa_modargs_get_value(struct pa_modargs *ma, const char *key, const char *def) { - struct pa_hashmap *map = (struct pa_hashmap*) ma; - struct entry*e; - - if (!(e = pa_hashmap_get(map, key))) - return def; - - return e->value; -} - -int pa_modargs_get_value_u32(struct pa_modargs *ma, const char *key, uint32_t *value) { - const char *v; - char *e; - unsigned long l; - assert(ma && key && value); - - if (!(v = pa_modargs_get_value(ma, key, NULL))) - return 0; - - if (!*v) - return -1; - - l = strtoul(v, &e, 0); - if (*e) - return -1; - - *value = (uint32_t) l; - return 0; -} - -int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *rss) { - const char *format; - uint32_t channels; - struct pa_sample_spec ss; - assert(ma && rss); - - ss = *rss; - if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0) - return -1; - - channels = ss.channels; - if ((pa_modargs_get_value_u32(ma, "channels", &channels)) < 0) - return -1; - ss.channels = (uint8_t) channels; - - if ((format = pa_modargs_get_value(ma, "format", NULL))) { - if (strcmp(format, "s16le") == 0) - ss.format = PA_SAMPLE_S16LE; - else if (strcmp(format, "s16be") == 0) - ss.format = PA_SAMPLE_S16BE; - else if (strcmp(format, "s16ne") == 0 || strcmp(format, "s16") == 0 || strcmp(format, "16") == 0) - ss.format = PA_SAMPLE_S16NE; - else if (strcmp(format, "u8") == 0 || strcmp(format, "8") == 0) - ss.format = PA_SAMPLE_U8; - else if (strcmp(format, "float32") == 0 || strcmp(format, "float32ne") == 0) - ss.format = PA_SAMPLE_FLOAT32; - else if (strcmp(format, "float32le") == 0) - ss.format = PA_SAMPLE_FLOAT32LE; - else if (strcmp(format, "float32be") == 0) - ss.format = PA_SAMPLE_FLOAT32BE; - else if (strcmp(format, "ulaw") == 0) - ss.format = PA_SAMPLE_ULAW; - else if (strcmp(format, "alaw") == 0) - ss.format = PA_SAMPLE_ALAW; - else - return -1; - } - - if (!pa_sample_spec_valid(&ss)) - return -1; - - *rss = ss; - - return 0; -} - -int pa_modargs_get_source_index(struct pa_modargs *ma, struct pa_core *c, uint32_t *index) { - const char *t; - assert(ma && index); - - if (!(t = pa_modargs_get_value(ma, "source", NULL))) - *index = PA_IDXSET_INVALID; - else { - struct pa_source *source; - if (!(source = pa_namereg_get(c, t, PA_NAMEREG_SOURCE))) - return -1; - - *index = source->index; - } - - return 0; -} - -int pa_modargs_get_sink_index(struct pa_modargs *ma, struct pa_core *c, uint32_t *index) { - const char *t; - assert(ma && index); - - if (!(t = pa_modargs_get_value(ma, "sink", NULL))) - *index = PA_IDXSET_INVALID; - else { - struct pa_sink *sink; - if (!(sink = pa_namereg_get(c, t, PA_NAMEREG_SINK))) - return -1; - - *index = sink->index; - } - - return 0; -} diff --git a/src/modargs.h b/src/modargs.h deleted file mode 100644 index 301dc297..00000000 --- a/src/modargs.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef foomodargshfoo -#define foomodargshfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include "sample.h" -#include "core.h" - -struct pa_modargs; - -struct pa_modargs *pa_modargs_new(const char *args, const char* const* keys); -void pa_modargs_free(struct pa_modargs*ma); - -const char *pa_modargs_get_value(struct pa_modargs *ma, const char *key, const char *def); -int pa_modargs_get_value_u32(struct pa_modargs *ma, const char *key, uint32_t *value); - -int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *ss); - -int pa_modargs_get_source_index(struct pa_modargs *ma, struct pa_core *c, uint32_t *index); -int pa_modargs_get_sink_index(struct pa_modargs *ma, struct pa_core *c, uint32_t *index); - -#endif diff --git a/src/module-alsa-sink.c b/src/module-alsa-sink.c deleted file mode 100644 index 8a3388af..00000000 --- a/src/module-alsa-sink.c +++ /dev/null @@ -1,259 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include - -#include "module.h" -#include "core.h" -#include "memchunk.h" -#include "sink.h" -#include "modargs.h" -#include "util.h" -#include "sample-util.h" -#include "alsa-util.h" - -struct userdata { - snd_pcm_t *pcm_handle; - struct pa_sink *sink; - void **io_sources; - unsigned n_io_sources; - - size_t frame_size, fragment_size; - struct pa_memchunk memchunk, silence; -}; - -static const char* const valid_modargs[] = { - "device", - "sink_name", - "format", - "channels", - "rate", - "fragments", - "fragment_size", - NULL -}; - -#define DEFAULT_SINK_NAME "alsa_output" -#define DEFAULT_DEVICE "plughw:0,0" - -static void xrun_recovery(struct userdata *u) { - assert(u); - - fprintf(stderr, "*** ALSA-XRUN (playback) ***\n"); - - if (snd_pcm_prepare(u->pcm_handle) < 0) - fprintf(stderr, "snd_pcm_prepare() failed\n"); -} - -static void do_write(struct userdata *u) { - assert(u); - - for (;;) { - struct pa_memchunk *memchunk = NULL; - snd_pcm_sframes_t frames; - - if (u->memchunk.memblock) - memchunk = &u->memchunk; - else { - if (pa_sink_render(u->sink, u->fragment_size, &u->memchunk) < 0) - memchunk = &u->silence; - else - memchunk = &u->memchunk; - } - - assert(memchunk->memblock && memchunk->memblock->data && memchunk->length && memchunk->memblock->length && (memchunk->length % u->frame_size) == 0); - - if ((frames = snd_pcm_writei(u->pcm_handle, memchunk->memblock->data + memchunk->index, memchunk->length / u->frame_size)) < 0) { - if (frames == -EAGAIN) - return; - - if (frames == -EPIPE) { - xrun_recovery(u); - continue; - } - - fprintf(stderr, "snd_pcm_writei() failed\n"); - return; - } - - if (memchunk == &u->memchunk) { - size_t l = frames * u->frame_size; - memchunk->index += l; - memchunk->length -= l; - - if (memchunk->length == 0) { - pa_memblock_unref(memchunk->memblock); - memchunk->memblock = NULL; - memchunk->index = memchunk->length = 0; - } - } - - break; - } -} - -static void io_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { - struct userdata *u = userdata; - assert(u && a && id); - - if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) - xrun_recovery(u); - - do_write(u); -} - -static uint32_t sink_get_latency_cb(struct pa_sink *s) { - struct userdata *u = s->userdata; - snd_pcm_sframes_t frames; - assert(s && u && u->sink); - - if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { - fprintf(stderr, __FILE__": failed to get delay\n"); - s->get_latency = NULL; - return 0; - } - - if (frames < 0) - frames = 0; - - return pa_samples_usec(frames * u->frame_size, &s->sample_spec); -} - -int pa_module_init(struct pa_core *c, struct pa_module*m) { - struct pa_modargs *ma = NULL; - int ret = -1; - struct userdata *u = NULL; - const char *dev; - struct pa_sample_spec ss; - unsigned periods, fragsize; - snd_pcm_uframes_t buffer_size; - size_t frame_size; - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - fprintf(stderr, __FILE__": failed to parse module arguments\n"); - goto fail; - } - - ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - fprintf(stderr, __FILE__": failed to parse sample specification\n"); - goto fail; - } - frame_size = pa_sample_size(&ss); - - periods = 12; - fragsize = 1024; - if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { - fprintf(stderr, __FILE__": failed to parse buffer metrics\n"); - goto fail; - } - buffer_size = fragsize/frame_size*periods; - - u = malloc(sizeof(struct userdata)); - assert(u); - memset(u, 0, sizeof(struct userdata)); - m->userdata = u; - - if (snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) { - fprintf(stderr, __FILE__": Error opening PCM device %s\n", dev); - goto fail; - } - - if (pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &buffer_size) < 0) { - fprintf(stderr, __FILE__": Failed to set hardware parameters\n"); - goto fail; - } - - u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); - assert(u->sink); - - u->sink->get_latency = sink_get_latency_cb; - u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); - - if (pa_create_io_sources(u->pcm_handle, c->mainloop, &u->io_sources, &u->n_io_sources, io_callback, u) < 0) { - fprintf(stderr, __FILE__": failed to obtain file descriptors\n"); - goto fail; - } - - u->frame_size = frame_size; - u->fragment_size = buffer_size*u->frame_size/periods; - - fprintf(stderr, __FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); - - u->silence.memblock = pa_memblock_new(u->silence.length = u->fragment_size); - assert(u->silence.memblock); - pa_silence_memblock(u->silence.memblock, &ss); - u->silence.index = 0; - - u->memchunk.memblock = NULL; - u->memchunk.index = u->memchunk.length = 0; - - ret = 0; - -finish: - if (ma) - pa_modargs_free(ma); - - return ret; - -fail: - - if (u) - pa_module_done(c, m); - - goto finish; -} - -void pa_module_done(struct pa_core *c, struct pa_module*m) { - struct userdata *u; - assert(c && m); - - if ((u = m->userdata)) { - if (u->sink) - pa_sink_free(u->sink); - - if (u->io_sources) - pa_free_io_sources(c->mainloop, u->io_sources, u->n_io_sources); - - if (u->pcm_handle) { - snd_pcm_drop(u->pcm_handle); - snd_pcm_close(u->pcm_handle); - } - - if (u->memchunk.memblock) - pa_memblock_unref(u->memchunk.memblock); - if (u->silence.memblock) - pa_memblock_unref(u->silence.memblock); - - free(u); - } -} - diff --git a/src/module-alsa-source.c b/src/module-alsa-source.c deleted file mode 100644 index 287a0350..00000000 --- a/src/module-alsa-source.c +++ /dev/null @@ -1,237 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include - -#include "module.h" -#include "core.h" -#include "memchunk.h" -#include "sink.h" -#include "modargs.h" -#include "util.h" -#include "sample-util.h" -#include "alsa-util.h" - -struct userdata { - snd_pcm_t *pcm_handle; - struct pa_source *source; - void **io_sources; - unsigned n_io_sources; - - size_t frame_size, fragment_size; - struct pa_memchunk memchunk; -}; - -static const char* const valid_modargs[] = { - "device", - "source_name", - "format", - "channels", - "rate", - "fragments", - "fragment_size", - NULL -}; - -#define DEFAULT_SOURCE_NAME "alsa_input" -#define DEFAULT_DEVICE "hw:0,0" - -static void xrun_recovery(struct userdata *u) { - assert(u); - - fprintf(stderr, "*** ALSA-XRUN (capture) ***\n"); - - if (snd_pcm_prepare(u->pcm_handle) < 0) - fprintf(stderr, "snd_pcm_prepare() failed\n"); -} - -static void do_read(struct userdata *u) { - assert(u); - - for (;;) { - struct pa_memchunk post_memchunk; - snd_pcm_sframes_t frames; - size_t l; - - if (!u->memchunk.memblock) { - u->memchunk.memblock = pa_memblock_new(u->memchunk.length = u->fragment_size); - u->memchunk.index = 0; - } - - assert(u->memchunk.memblock && u->memchunk.memblock->data && u->memchunk.length && u->memchunk.memblock->length && (u->memchunk.length % u->frame_size) == 0); - - if ((frames = snd_pcm_readi(u->pcm_handle, u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { - if (frames == -EAGAIN) - return; - - if (frames == -EPIPE) { - xrun_recovery(u); - continue; - } - - fprintf(stderr, "snd_pcm_readi() failed: %s\n", strerror(-frames)); - return; - } - - l = frames * u->frame_size; - - post_memchunk = u->memchunk; - post_memchunk.length = l; - - pa_source_post(u->source, &post_memchunk); - - u->memchunk.index += l; - u->memchunk.length -= l; - - if (u->memchunk.length == 0) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - u->memchunk.index = u->memchunk.length = 0; - } - - break; - } -} - -static void io_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { - struct userdata *u = userdata; - assert(u && a && id); - - if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) - xrun_recovery(u); - - do_read(u); -} - -int pa_module_init(struct pa_core *c, struct pa_module*m) { - struct pa_modargs *ma = NULL; - int ret = -1; - struct userdata *u = NULL; - const char *dev; - struct pa_sample_spec ss; - unsigned periods, fragsize; - snd_pcm_uframes_t buffer_size; - size_t frame_size; - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - fprintf(stderr, __FILE__": failed to parse module arguments\n"); - goto fail; - } - - ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - fprintf(stderr, __FILE__": failed to parse sample specification\n"); - goto fail; - } - frame_size = pa_sample_size(&ss); - - periods = 12; - fragsize = 1024; - if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { - fprintf(stderr, __FILE__": failed to parse buffer metrics\n"); - goto fail; - } - buffer_size = fragsize/frame_size*periods; - - u = malloc(sizeof(struct userdata)); - assert(u); - memset(u, 0, sizeof(struct userdata)); - m->userdata = u; - - if (snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK) < 0) { - fprintf(stderr, __FILE__": Error opening PCM device %s\n", dev); - goto fail; - } - - if (pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &buffer_size) < 0) { - fprintf(stderr, __FILE__": Failed to set hardware parameters\n"); - goto fail; - } - - u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); - assert(u->source); - - u->source->userdata = u; - pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); - - if (pa_create_io_sources(u->pcm_handle, c->mainloop, &u->io_sources, &u->n_io_sources, io_callback, u) < 0) { - fprintf(stderr, __FILE__": failed to obtain file descriptors\n"); - goto fail; - } - - u->frame_size = frame_size; - u->fragment_size = buffer_size*u->frame_size/periods; - - fprintf(stderr, __FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); - - u->memchunk.memblock = NULL; - u->memchunk.index = u->memchunk.length = 0; - - snd_pcm_start(u->pcm_handle); - - ret = 0; - -finish: - if (ma) - pa_modargs_free(ma); - - return ret; - -fail: - - if (u) - pa_module_done(c, m); - - goto finish; -} - -void pa_module_done(struct pa_core *c, struct pa_module*m) { - struct userdata *u; - assert(c && m); - - if ((u = m->userdata)) { - if (u->source) - pa_source_free(u->source); - - if (u->io_sources) - pa_free_io_sources(c->mainloop, u->io_sources, u->n_io_sources); - - if (u->pcm_handle) { - snd_pcm_drop(u->pcm_handle); - snd_pcm_close(u->pcm_handle); - } - - if (u->memchunk.memblock) - pa_memblock_unref(u->memchunk.memblock); - - free(u); - } -} - diff --git a/src/module-cli.c b/src/module-cli.c deleted file mode 100644 index 8897c9c6..00000000 --- a/src/module-cli.c +++ /dev/null @@ -1,73 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#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 pa_module_init(struct pa_core *c, struct pa_module*m) { - struct pa_iochannel *io; - assert(c && m); - - if (m->argument) { - fprintf(stderr, __FILE__": module doesn't accept arguments.\n"); - return -1; - } - - if (pa_stdio_acquire() < 0) { - fprintf(stderr, __FILE__": STDIN/STDUSE already in use.\n"); - return -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, m); - assert(m->userdata); - - pa_cli_set_eof_callback(m->userdata, eof_cb, m); - - return 0; -} - -void pa_module_done(struct pa_core *c, struct pa_module*m) { - assert(c && m); - - pa_cli_free(m->userdata); - pa_stdio_release(); -} diff --git a/src/module-oss-mmap.c b/src/module-oss-mmap.c deleted file mode 100644 index 800eaf25..00000000 --- a/src/module-oss-mmap.c +++ /dev/null @@ -1,404 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "iochannel.h" -#include "sink.h" -#include "source.h" -#include "module.h" -#include "oss-util.h" -#include "sample-util.h" -#include "util.h" -#include "modargs.h" - -struct userdata { - struct pa_sink *sink; - struct pa_source *source; - struct pa_core *core; - struct pa_sample_spec sample_spec; - - size_t in_fragment_size, out_fragment_size, in_fragments, out_fragments, out_fill; - - int fd; - - void *in_mmap, *out_mmap; - size_t in_mmap_length, out_mmap_length; - - void *mainloop_source; - - struct pa_memblock **in_memblocks, **out_memblocks; - unsigned out_current, in_current; -}; - -static const char* const valid_modargs[] = { - "sink_name", - "source_name", - "device", - "record", - "playback", - "fragments", - "fragment_size", - "format", - "rate", - "channels", - NULL -}; - -#define DEFAULT_SINK_NAME "oss_output" -#define DEFAULT_SOURCE_NAME "oss_input" -#define DEFAULT_DEVICE "/dev/dsp" - -static void out_fill_memblocks(struct userdata *u, unsigned n) { - assert(u && u->out_memblocks); - - while (n > 0) { - struct pa_memchunk chunk; - - if (u->out_memblocks[u->out_current]) - pa_memblock_unref_fixed(u->out_memblocks[u->out_current]); - - chunk.memblock = u->out_memblocks[u->out_current] = pa_memblock_new_fixed(u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size); - assert(chunk.memblock); - chunk.length = chunk.memblock->length; - chunk.index = 0; - - pa_sink_render_into_full(u->sink, &chunk); - - u->out_current++; - while (u->out_current >= u->out_fragments) - u->out_current -= u->out_fragments; - - n--; - } -} - -static void do_write(struct userdata *u) { - struct count_info info; - assert(u && u->sink); - - if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { - fprintf(stderr, "SNDCTL_DSP_GETOPTR: %s\n", strerror(errno)); - return; - } - - u->out_fill = (u->out_fragment_size * u->out_fragments) - (info.ptr % u->out_fragment_size); - - if (!info.blocks) - return; - - out_fill_memblocks(u, info.blocks); -} - -static void in_post_memblocks(struct userdata *u, unsigned n) { - assert(u && u->in_memblocks); - - while (n > 0) { - struct pa_memchunk chunk; - - if (!u->in_memblocks[u->in_current]) { - chunk.memblock = u->in_memblocks[u->in_current] = pa_memblock_new_fixed(u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size); - chunk.length = chunk.memblock->length; - chunk.index = 0; - - pa_source_post(u->source, &chunk); - } - - u->in_current++; - while (u->in_current >= u->in_fragments) - u->in_current -= u->in_fragments; - - n--; - } -} - -static void in_clear_memblocks(struct userdata*u, unsigned n) { - unsigned i = u->in_current; - assert(u && u->in_memblocks); - - if (n > u->in_fragments) - n = u->in_fragments; - - while (n > 0) { - if (u->in_memblocks[i]) { - pa_memblock_unref_fixed(u->in_memblocks[i]); - u->in_memblocks[i] = NULL; - } - - i++; - while (i >= u->in_fragments) - i -= u->in_fragments; - - n--; - } -} - -static void do_read(struct userdata *u) { - struct count_info info; - assert(u && u->source); - - if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { - fprintf(stderr, "SNDCTL_DSP_GETIPTR: %s\n", strerror(errno)); - return; - } - - if (!info.blocks) - return; - - in_post_memblocks(u, info.blocks); - in_clear_memblocks(u, u->in_fragments/2); -}; - -static void io_callback(struct pa_mainloop_api *m, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { - struct userdata *u = userdata; - - assert (u && u->core->mainloop == m && u->mainloop_source == id); - - if (events & PA_MAINLOOP_API_IO_EVENT_INPUT) - do_read(u); - if (events & PA_MAINLOOP_API_IO_EVENT_OUTPUT) - do_write(u); -} - -static uint32_t sink_get_latency_cb(struct pa_sink *s) { - struct userdata *u = s->userdata; - assert(s && u); - - do_write(u); - return pa_samples_usec(u->out_fill, &s->sample_spec); -} - -int pa_module_init(struct pa_core *c, struct pa_module*m) { - struct audio_buf_info info; - struct userdata *u = NULL; - const char *p; - int nfrags, frag_size; - int mode, caps; - int enable_bits = 0, zero = 0; - int playback = 1, record = 1; - struct pa_modargs *ma = NULL; - assert(c && m); - - m->userdata = u = malloc(sizeof(struct userdata)); - assert(u); - memset(u, 0, sizeof(struct userdata)); - u->fd = -1; - u->core = c; - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - fprintf(stderr, __FILE__": failed to parse module arguments.\n"); - goto fail; - } - - if (pa_modargs_get_value_u32(ma, "record", &record) < 0 || pa_modargs_get_value_u32(ma, "playback", &playback) < 0) { - fprintf(stderr, __FILE__": record= and playback= expect numeric arguments.\n"); - goto fail; - } - - mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); - if (mode == 0) { - fprintf(stderr, __FILE__": neither playback nor record enabled for device.\n"); - goto fail; - } - - nfrags = 12; - frag_size = 1024; - if (pa_modargs_get_value_u32(ma, "fragments", &nfrags) < 0 || nfrags < 2 || pa_modargs_get_value_u32(ma, "fragment_size", &frag_size) < 0 || frag_size < 1) { - fprintf(stderr, __FILE__": failed to parse fragments arguments\n"); - goto fail; - } - - u->sample_spec = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &u->sample_spec) < 0) { - fprintf(stderr, __FILE__": failed to parse sample specification\n"); - goto fail; - } - - if ((u->fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0) - goto fail; - - if (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_REALTIME) || !(caps & DSP_CAP_TRIGGER)) { - fprintf(stderr, "OSS device not mmap capable.\n"); - goto fail; - } - - fprintf(stderr, "module-oss: device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); - - if (pa_oss_set_fragments(u->fd, nfrags, frag_size) < 0) - goto fail; - - if (pa_oss_auto_format(u->fd, &u->sample_spec) < 0) - goto fail; - - if (mode != O_WRONLY) { - if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { - fprintf(stderr, "SNDCTL_DSP_GETISPACE: %s\n", strerror(errno)); - goto fail; - } - - fprintf(stderr, "module-oss-mmap: input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); - u->in_mmap_length = (u->in_fragment_size = info.fragsize) * (u->in_fragments = info.fragstotal); - - if ((u->in_mmap = mmap(NULL, u->in_mmap_length, PROT_READ, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { - if (mode == O_RDWR) { - fprintf(stderr, "module-oss-mmap: mmap failed for input. Changing to O_WRONLY mode.\n"); - mode = O_WRONLY; - } else { - fprintf(stderr, "modeule-oss-mmap: mmap(): %s\n", strerror(errno)); - goto fail; - } - } else { - - u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec); - assert(u->source); - u->source->userdata = u; - pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'", p); - - - u->in_memblocks = malloc(sizeof(struct pa_memblock *)*u->in_fragments); - memset(u->in_memblocks, 0, sizeof(struct pa_memblock *)*u->in_fragments); - - enable_bits |= PCM_ENABLE_INPUT; - } - } - - if (mode != O_RDONLY) { - if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { - fprintf(stderr, "SNDCTL_DSP_GETOSPACE: %s\n", strerror(errno)); - goto fail; - } - - fprintf(stderr, "module-oss: output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); - u->out_mmap_length = (u->out_fragment_size = info.fragsize) * (u->out_fragments = info.fragstotal); - - if ((u->out_mmap = mmap(NULL, u->out_mmap_length, PROT_WRITE, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { - if (mode == O_RDWR) { - fprintf(stderr, "module-oss-mmap: mmap filed for output. Changing to O_RDONLY mode.\n"); - mode = O_RDONLY; - } else { - fprintf(stderr, "module-oss-mmap: mmap(): %s\n", strerror(errno)); - goto fail; - } - } else { - pa_silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec); - - u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec); - assert(u->sink); - u->sink->get_latency = sink_get_latency_cb; - u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'", p); - - u->out_memblocks = malloc(sizeof(struct memblock *)*u->out_fragments); - memset(u->out_memblocks, 0, sizeof(struct pa_memblock *)*u->out_fragments); - - enable_bits |= PCM_ENABLE_OUTPUT; - } - } - - zero = 0; - if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero) < 0) { - fprintf(stderr, "SNDCTL_DSP_SETTRIGGER: %s\n", strerror(errno)); - goto fail; - } - - if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0) { - fprintf(stderr, "SNDCTL_DSP_SETTRIGGER: %s\n", strerror(errno)); - goto fail; - } - - assert(u->source || u->sink); - - u->mainloop_source = c->mainloop->source_io(c->mainloop, u->fd, (u->source ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | (u->sink ? PA_MAINLOOP_API_IO_EVENT_OUTPUT : 0), io_callback, u); - assert(u->mainloop_source); - - pa_modargs_free(ma); - - return 0; - -fail: - pa_module_done(c, m); - - if (ma) - pa_modargs_free(ma); - - return -1; -} - -void pa_module_done(struct pa_core *c, struct pa_module*m) { - struct userdata *u; - assert(c && m); - - u = m->userdata; - assert(u); - - if (u->out_memblocks) { - unsigned i; - for (i = 0; i < u->out_fragments; i++) - if (u->out_memblocks[i]) - pa_memblock_unref_fixed(u->out_memblocks[i]); - free(u->out_memblocks); - } - - if (u->in_memblocks) { - unsigned i; - for (i = 0; i < u->in_fragments; i++) - if (u->in_memblocks[i]) - pa_memblock_unref_fixed(u->in_memblocks[i]); - free(u->in_memblocks); - } - - if (u->in_mmap && u->in_mmap != MAP_FAILED) - munmap(u->in_mmap, u->in_mmap_length); - - if (u->out_mmap && u->out_mmap != MAP_FAILED) - munmap(u->out_mmap, u->out_mmap_length); - - if (u->sink) - pa_sink_free(u->sink); - - if (u->source) - pa_source_free(u->source); - - if (u->mainloop_source) - u->core->mainloop->cancel_io(u->core->mainloop, u->mainloop_source); - - if (u->fd >= 0) - close(u->fd); - - free(u); -} diff --git a/src/module-oss.c b/src/module-oss.c deleted file mode 100644 index d727534a..00000000 --- a/src/module-oss.c +++ /dev/null @@ -1,304 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "iochannel.h" -#include "sink.h" -#include "source.h" -#include "module.h" -#include "oss-util.h" -#include "sample-util.h" -#include "util.h" -#include "modargs.h" - -struct userdata { - struct pa_sink *sink; - struct pa_source *source; - struct pa_iochannel *io; - struct pa_core *core; - - struct pa_memchunk memchunk, silence; - - uint32_t in_fragment_size, out_fragment_size, sample_size; - - int fd; -}; - -static const char* const valid_modargs[] = { - "sink_name", - "source_name", - "device", - "record", - "playback", - "fragments", - "fragment_size", - "format", - "rate", - "channels", - NULL -}; - -#define DEFAULT_SINK_NAME "oss_output" -#define DEFAULT_SOURCE_NAME "oss_input" -#define DEFAULT_DEVICE "/dev/dsp" - -static void do_write(struct userdata *u) { - struct pa_memchunk *memchunk; - ssize_t r; - assert(u); - - if (!u->sink || !pa_iochannel_is_writable(u->io)) - return; - - if (!u->memchunk.length) { - if (pa_sink_render(u->sink, u->out_fragment_size, &u->memchunk) < 0) - memchunk = &u->silence; - else - memchunk = &u->memchunk; - } - - assert(memchunk->memblock && memchunk->length); - - if ((r = pa_iochannel_write(u->io, memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { - fprintf(stderr, "write() failed: %s\n", strerror(errno)); - return; - } - - if (memchunk == &u->silence) - assert(r % u->sample_size == 0); - else { - u->memchunk.index += r; - u->memchunk.length -= r; - - if (u->memchunk.length <= 0) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - } - } -} - -static void do_read(struct userdata *u) { - struct pa_memchunk memchunk; - ssize_t r; - assert(u); - - if (!u->source || !pa_iochannel_is_readable(u->io)) - return; - - memchunk.memblock = pa_memblock_new(u->in_fragment_size); - assert(memchunk.memblock); - if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { - pa_memblock_unref(memchunk.memblock); - if (errno != EAGAIN) - fprintf(stderr, "read() failed: %s\n", strerror(errno)); - return; - } - - assert(r <= (ssize_t) memchunk.memblock->length); - memchunk.length = memchunk.memblock->length = r; - memchunk.index = 0; - - pa_source_post(u->source, &memchunk); - pa_memblock_unref(memchunk.memblock); -}; - -static void io_callback(struct pa_iochannel *io, void*userdata) { - struct userdata *u = userdata; - assert(u); - do_write(u); - do_read(u); -} - -static uint32_t sink_get_latency_cb(struct pa_sink *s) { - int arg; - struct userdata *u = s->userdata; - assert(s && u && u->sink); - - if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { - fprintf(stderr, "module-oss: device doesn't support SNDCTL_DSP_GETODELAY.\n"); - s->get_latency = NULL; - return 0; - } - - return pa_samples_usec(arg, &s->sample_spec); -} - -int pa_module_init(struct pa_core *c, struct pa_module*m) { - struct audio_buf_info info; - struct userdata *u = NULL; - const char *p; - int fd = -1; - int nfrags, frag_size, in_frag_size, out_frag_size; - int mode; - uint32_t record = 1, playback = 1; - struct pa_sample_spec ss; - struct pa_modargs *ma = NULL; - assert(c && m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - fprintf(stderr, __FILE__": failed to parse module arguments.\n"); - goto fail; - } - - if (pa_modargs_get_value_u32(ma, "record", &record) < 0 || pa_modargs_get_value_u32(ma, "playback", &playback) < 0) { - fprintf(stderr, __FILE__": record= and playback= expect numeric argument.\n"); - goto fail; - } - - mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); - if (mode == 0) { - fprintf(stderr, __FILE__": neither playback nor record enabled for device.\n"); - goto fail; - } - - nfrags = 12; - frag_size = 1024; - if (pa_modargs_get_value_u32(ma, "fragments", &nfrags) < 0 || nfrags < 2 || pa_modargs_get_value_u32(ma, "fragment_size", &frag_size) < 0 || frag_size < 1) { - fprintf(stderr, __FILE__": failed to parse fragments arguments\n"); - goto fail; - } - - ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - fprintf(stderr, __FILE__": failed to parse sample specification\n"); - goto fail; - } - - if ((fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, NULL)) < 0) - goto fail; - - fprintf(stderr, "module-oss: device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); - - if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) - goto fail; - - if (pa_oss_auto_format(fd, &ss) < 0) - goto fail; - - if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) { - fprintf(stderr, "SNDCTL_DSP_GETBLKSIZE: %s\n", strerror(errno)); - goto fail; - } - assert(frag_size); - in_frag_size = out_frag_size = frag_size; - - if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { - fprintf(stderr, "module-oss: input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); - in_frag_size = info.fragsize; - } - - if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) { - fprintf(stderr, "module-oss: output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); - out_frag_size = info.fragsize; - } - - u = malloc(sizeof(struct userdata)); - assert(u); - - u->core = c; - - if (mode != O_WRONLY) { - u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); - assert(u->source); - u->source->userdata = u; - pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); - } else - u->source = NULL; - - if (mode != O_RDONLY) { - u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); - assert(u->sink); - u->sink->get_latency = sink_get_latency_cb; - u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); - } else - u->sink = NULL; - - assert(u->source || u->sink); - - u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : 0); - assert(u->io); - pa_iochannel_set_callback(u->io, io_callback, u); - u->fd = fd; - - u->memchunk.memblock = NULL; - u->memchunk.length = 0; - u->sample_size = pa_sample_size(&ss); - - u->out_fragment_size = out_frag_size; - u->in_fragment_size = in_frag_size; - u->silence.memblock = pa_memblock_new(u->silence.length = u->out_fragment_size); - assert(u->silence.memblock); - pa_silence_memblock(u->silence.memblock, &ss); - u->silence.index = 0; - - m->userdata = u; - - pa_modargs_free(ma); - - return 0; - -fail: - if (fd >= 0) - close(fd); - - if (ma) - pa_modargs_free(ma); - - return -1; -} - -void pa_module_done(struct pa_core *c, struct pa_module*m) { - struct userdata *u; - assert(c && m); - - u = m->userdata; - assert(u); - - if (u->memchunk.memblock) - pa_memblock_unref(u->memchunk.memblock); - if (u->silence.memblock) - pa_memblock_unref(u->silence.memblock); - - if (u->sink) - pa_sink_free(u->sink); - if (u->source) - pa_source_free(u->source); - pa_iochannel_free(u->io); - free(u); -} diff --git a/src/module-pipe-sink.c b/src/module-pipe-sink.c deleted file mode 100644 index df34f73a..00000000 --- a/src/module-pipe-sink.c +++ /dev/null @@ -1,218 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "iochannel.h" -#include "sink.h" -#include "module.h" -#include "util.h" -#include "modargs.h" - -#define DEFAULT_FIFO_NAME "/tmp/musicfifo" -#define DEFAULT_SINK_NAME "fifo_output" - -struct userdata { - struct pa_core *core; - - char *filename; - - struct pa_sink *sink; - struct pa_iochannel *io; - void *mainloop_source; - - struct pa_memchunk memchunk; -}; - -static const char* const valid_modargs[] = { - "file", - "rate", - "channels", - "format", - "sink_name", - NULL -}; - -static void do_write(struct userdata *u) { - ssize_t r; - assert(u); - - u->core->mainloop->enable_fixed(u->core->mainloop, u->mainloop_source, 0); - - if (!pa_iochannel_is_writable(u->io)) - return; - - if (!u->memchunk.length) - if (pa_sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0) - return; - - assert(u->memchunk.memblock && u->memchunk.length); - - if ((r = pa_iochannel_write(u->io, u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { - fprintf(stderr, "write() failed: %s\n", strerror(errno)); - return; - } - - u->memchunk.index += r; - u->memchunk.length -= r; - - if (u->memchunk.length <= 0) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - } -} - -static void notify_cb(struct pa_sink*s) { - struct userdata *u = s->userdata; - assert(s && u); - - if (pa_iochannel_is_writable(u->io)) - u->core->mainloop->enable_fixed(u->core->mainloop, u->mainloop_source, 1); -} - -static void fixed_callback(struct pa_mainloop_api *m, void *id, void *userdata) { - struct userdata *u = userdata; - assert(u); - do_write(u); -} - -static void io_callback(struct pa_iochannel *io, void*userdata) { - struct userdata *u = userdata; - assert(u); - do_write(u); -} - -int pa_module_init(struct pa_core *c, struct pa_module*m) { - struct userdata *u = NULL; - struct stat st; - const char *p; - int fd = -1; - struct pa_sample_spec ss; - struct pa_modargs *ma = NULL; - assert(c && m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - fprintf(stderr, __FILE__": failed to parse module arguments\n"); - goto fail; - } - - ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - fprintf(stderr, __FILE__": invalid sample format specification\n"); - goto fail; - } - - mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777); - - if ((fd = open(p, O_RDWR)) < 0) { - fprintf(stderr, __FILE__": open('%s'): %s\n", p, strerror(errno)); - goto fail; - } - - if (fstat(fd, &st) < 0) { - fprintf(stderr, __FILE__": fstat('%s'): %s\n", p, strerror(errno)); - goto fail; - } - - if (!S_ISFIFO(st.st_mode)) { - fprintf(stderr, __FILE__": '%s' is not a FIFO.\n", p); - goto fail; - } - - u = malloc(sizeof(struct userdata)); - assert(u); - memset(u, 0, sizeof(struct userdata)); - - u->filename = strdup(p); - assert(u->filename); - u->core = c; - - if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { - fprintf(stderr, __FILE__": failed to create sink.\n"); - goto fail; - } - u->sink->notify = notify_cb; - u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Unix FIFO sink '%s'", p); - assert(u->sink->description); - - u->io = pa_iochannel_new(c->mainloop, -1, fd); - assert(u->io); - pa_iochannel_set_callback(u->io, io_callback, u); - - u->memchunk.memblock = NULL; - u->memchunk.length = 0; - - u->mainloop_source = c->mainloop->source_fixed(c->mainloop, fixed_callback, u); - assert(u->mainloop_source); - c->mainloop->enable_fixed(c->mainloop, u->mainloop_source, 0); - - m->userdata = u; - - pa_modargs_free(ma); - - return 0; - -fail: - if (ma) - pa_modargs_free(ma); - - if (fd >= 0) - close(fd); - - pa_module_done(c, m); - - return -1; -} - -void pa_module_done(struct pa_core *c, struct pa_module*m) { - struct userdata *u; - assert(c && m); - - if (!(u = m->userdata)) - return; - - if (u->memchunk.memblock) - pa_memblock_unref(u->memchunk.memblock); - - pa_sink_free(u->sink); - pa_iochannel_free(u->io); - u->core->mainloop->cancel_fixed(u->core->mainloop, u->mainloop_source); - - assert(u->filename); - unlink(u->filename); - free(u->filename); - - free(u); -} diff --git a/src/module-protocol-stub.c b/src/module-protocol-stub.c deleted file mode 100644 index 3ce18c31..00000000 --- a/src/module-protocol-stub.c +++ /dev/null @@ -1,165 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "module.h" -#include "socket-server.h" -#include "socket-util.h" -#include "util.h" -#include "modargs.h" - -#ifdef USE_PROTOCOL_SIMPLE - #include "protocol-simple.h" - #define protocol_new pa_protocol_simple_new - #define protocol_free pa_protocol_simple_free - #define IPV4_PORT 4711 - #define UNIX_SOCKET "/tmp/polypaudio/simple" - #define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record", -#else - #ifdef USE_PROTOCOL_CLI - #include "protocol-cli.h" - #define protocol_new pa_protocol_cli_new - #define protocol_free pa_protocol_cli_free - #define IPV4_PORT 4712 - #define UNIX_SOCKET "/tmp/polypaudio/cli" - #define MODULE_ARGUMENTS - #else - #ifdef USE_PROTOCOL_NATIVE - #include "protocol-native.h" - #define protocol_new pa_protocol_native_new - #define protocol_free pa_protocol_native_free - #define IPV4_PORT 4713 - #define UNIX_SOCKET "/tmp/polypaudio/native" - #define MODULE_ARGUMENTS "public", "cookie", - #else - #ifdef USE_PROTOCOL_ESOUND - #include "protocol-esound.h" - #include "esound.h" - #define protocol_new pa_protocol_esound_new - #define protocol_free pa_protocol_esound_free - #define IPV4_PORT ESD_DEFAULT_PORT - #define UNIX_SOCKET ESD_UNIX_SOCKET_NAME - #define MODULE_ARGUMENTS "sink", "source", "public", "cookie", - #else - #error "Broken build system" - #endif - #endif - #endif -#endif - -static const char* const valid_modargs[] = { - MODULE_ARGUMENTS -#ifdef USE_TCP_SOCKETS - "port", - "loopback", -#else - "socket", -#endif - NULL -}; - -static struct pa_socket_server *create_socket_server(struct pa_core *c, struct pa_modargs *ma) { - struct pa_socket_server *s; -#ifdef USE_TCP_SOCKETS - uint32_t loopback = 1, port = IPV4_PORT; - - if (pa_modargs_get_value_u32(ma, "loopback", &loopback) < 0) { - fprintf(stderr, "loopback= expects a numerical argument.\n"); - return NULL; - } - - if (pa_modargs_get_value_u32(ma, "port", &port) < 0) { - fprintf(stderr, "port= expects a numerical argument.\n"); - return NULL; - } - - if (!(s = pa_socket_server_new_ipv4(c->mainloop, loopback ? INADDR_LOOPBACK : INADDR_ANY, port))) - return NULL; -#else - int r; - const char *p; - - p = pa_modargs_get_value(ma, "socket", UNIX_SOCKET); - assert(p); - - if (pa_unix_socket_make_secure_dir(p) < 0) { - fprintf(stderr, "Failed to create secure socket directory.\n"); - return NULL; - } - - if ((r = pa_unix_socket_remove_stale(p)) < 0) { - fprintf(stderr, "Failed to remove stale UNIX socket '%s': %s\n", p, strerror(errno)); - return NULL; - } - - if (r) - fprintf(stderr, "Removed stale UNIX socket '%s'.", p); - - if (!(s = pa_socket_server_new_unix(c->mainloop, p))) - return NULL; - -#endif - return s; -} - -int pa_module_init(struct pa_core *c, struct pa_module*m) { - struct pa_socket_server *s; - struct pa_modargs *ma = NULL; - int ret = -1; - assert(c && m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - fprintf(stderr, "Failed to parse module arguments\n"); - goto finish; - } - - if (!(s = create_socket_server(c, ma))) - goto finish; - - if (!(m->userdata = protocol_new(c, s, m, ma))) { - pa_socket_server_free(s); - goto finish; - } - - ret = 0; - -finish: - if (ma) - pa_modargs_free(ma); - - return ret; -} - -void pa_module_done(struct pa_core *c, struct pa_module*m) { - assert(c && m); - - protocol_free(m->userdata); -} diff --git a/src/module.c b/src/module.c deleted file mode 100644 index 5c6f0fb6..00000000 --- a/src/module.c +++ /dev/null @@ -1,161 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "module.h" - -struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char *argument) { - struct pa_module *m = NULL; - int r; - - assert(c && name); - - m = malloc(sizeof(struct pa_module)); - assert(m); - - m->name = strdup(name); - m->argument = argument ? strdup(argument) : NULL; - - if (!(m->dl = lt_dlopenext(name))) - goto fail; - - if (!(m->init = lt_dlsym(m->dl, "pa_module_init"))) - goto fail; - - if (!(m->done = lt_dlsym(m->dl, "pa_module_done"))) - goto fail; - - m->userdata = NULL; - m->core = c; - - assert(m->init); - if (m->init(c, m) < 0) - goto fail; - - if (!c->modules) - c->modules = pa_idxset_new(NULL, NULL); - - assert(c->modules); - r = pa_idxset_put(c->modules, m, &m->index); - assert(r >= 0 && m->index != PA_IDXSET_INVALID); - - fprintf(stderr, "module: loaded %u \"%s\" with argument \"%s\".\n", m->index, m->name, m->argument); - - return m; - -fail: - if (m) { - free(m->argument); - free(m->name); - - if (m->dl) - lt_dlclose(m->dl); - - free(m); - } - - return NULL; -} - -static void pa_module_free(struct pa_module *m) { - assert(m && m->done && m->core); - m->done(m->core, m); - - lt_dlclose(m->dl); - - fprintf(stderr, "module: unloaded %u \"%s\".\n", m->index, m->name); - - free(m->name); - free(m->argument); - free(m); -} - - -void pa_module_unload(struct pa_core *c, struct pa_module *m) { - assert(c && m); - - assert(c->modules); - if (!(m = pa_idxset_remove_by_data(c->modules, m, NULL))) - return; - - pa_module_free(m); -} - -void pa_module_unload_by_index(struct pa_core *c, uint32_t index) { - struct pa_module *m; - assert(c && index != PA_IDXSET_INVALID); - - assert(c->modules); - if (!(m = pa_idxset_remove_by_index(c->modules, index))) - return; - - pa_module_free(m); -} - -static void free_callback(void *p, void *userdata) { - struct pa_module *m = p; - assert(m); - pa_module_free(m); -} - -void pa_module_unload_all(struct pa_core *c) { - assert(c); - - if (!c->modules) - return; - - pa_idxset_free(c->modules, free_callback, NULL); - c->modules = NULL; -} - -struct once_info { - struct pa_core *core; - uint32_t index; -}; - - -static void module_unload_once_callback(void *userdata) { - struct once_info *i = userdata; - assert(i); - pa_module_unload_by_index(i->core, i->index); - free(i); -} - -void pa_module_unload_request(struct pa_core *c, struct pa_module *m) { - struct once_info *i; - assert(c && m); - - i = malloc(sizeof(struct once_info)); - assert(i); - i->core = c; - i->index = m->index; - pa_mainloop_api_once(c->mainloop, module_unload_once_callback, i); -} diff --git a/src/module.h b/src/module.h deleted file mode 100644 index af2d8552..00000000 --- a/src/module.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef foomodulehfoo -#define foomodulehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -#include "core.h" - -struct pa_module { - struct pa_core *core; - char *name, *argument; - uint32_t index; - - lt_dlhandle dl; - - int (*init)(struct pa_core *c, struct pa_module*m); - void (*done)(struct pa_core *c, struct pa_module*m); - - void *userdata; -}; - -struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char*argument); -void pa_module_unload(struct pa_core *c, struct pa_module *m); -void pa_module_unload_by_index(struct pa_core *c, uint32_t index); - -void pa_module_unload_all(struct pa_core *c); - -void pa_module_unload_request(struct pa_core *c, struct pa_module *m); - -/* These to following prototypes are for module entrypoints and not implemented by the core */ -int pa_module_init(struct pa_core *c, struct pa_module*m); -void pa_module_done(struct pa_core *c, struct pa_module*m); - -#endif diff --git a/src/namereg.c b/src/namereg.c deleted file mode 100644 index 2349436f..00000000 --- a/src/namereg.c +++ /dev/null @@ -1,136 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "namereg.h" - -struct namereg_entry { - enum pa_namereg_type type; - char *name; - void *data; -}; - -void pa_namereg_free(struct pa_core *c) { - assert(c); - if (!c->namereg) - return; - assert(pa_hashmap_ncontents(c->namereg) == 0); - pa_hashmap_free(c->namereg, NULL, NULL); -} - -const char *pa_namereg_register(struct pa_core *c, const char *name, enum pa_namereg_type type, void *data, int fail) { - struct namereg_entry *e; - char *n = NULL; - int r; - - assert(c && name && data); - - if (!c->namereg) { - c->namereg = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - assert(c->namereg); - } - - if ((e = pa_hashmap_get(c->namereg, name)) && fail) - return NULL; - - if (!e) - n = strdup(name); - else { - unsigned i; - size_t l = strlen(name); - n = malloc(l+3); - assert(n); - - for (i = 1; i <= 99; i++) { - snprintf(n, l+2, "%s%u", name, i); - - if (!(e = pa_hashmap_get(c->namereg, n))) - break; - } - - if (e) { - free(n); - return NULL; - } - } - - assert(n); - e = malloc(sizeof(struct namereg_entry)); - assert(e); - e->type = type; - e->name = n; - e->data = data; - - r = pa_hashmap_put(c->namereg, e->name, e); - assert (r >= 0); - - return e->name; - -} - -void pa_namereg_unregister(struct pa_core *c, const char *name) { - struct namereg_entry *e; - int r; - assert(c && name); - - e = pa_hashmap_get(c->namereg, name); - assert(e); - - r = pa_hashmap_remove(c->namereg, name); - assert(r >= 0); - - free(e->name); - free(e); -} - -void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type type) { - struct namereg_entry *e; - uint32_t index; - char *x = NULL; - void *d = NULL; - assert(c && name); - - if ((e = pa_hashmap_get(c->namereg, name))) - if (e->type == e->type) - return e->data; - - index = (uint32_t) strtol(name, &x, 0); - - if (!x || *x != 0) - return NULL; - - if (type == PA_NAMEREG_SINK) - d = pa_idxset_get_by_index(c->sinks, index); - else if (type == PA_NAMEREG_SOURCE) - d = pa_idxset_get_by_index(c->sources, index); - - return d; -} diff --git a/src/namereg.h b/src/namereg.h deleted file mode 100644 index 0af83cd8..00000000 --- a/src/namereg.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef foonamereghfoo -#define foonamereghfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "core.h" - -enum pa_namereg_type { - PA_NAMEREG_SINK, - PA_NAMEREG_SOURCE -}; - -void pa_namereg_free(struct pa_core *c); - -const char *pa_namereg_register(struct pa_core *c, const char *name, enum pa_namereg_type type, void *data, int fail); -void pa_namereg_unregister(struct pa_core *c, const char *name); -void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type type); - -#endif diff --git a/src/native-common.h b/src/native-common.h deleted file mode 100644 index 2acbae8e..00000000 --- a/src/native-common.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef foonativecommonhfoo -#define foonativecommonhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -enum { - PA_COMMAND_ERROR, - PA_COMMAND_TIMEOUT, /* pseudo command */ - PA_COMMAND_REPLY, - PA_COMMAND_CREATE_PLAYBACK_STREAM, - PA_COMMAND_DELETE_PLAYBACK_STREAM, - PA_COMMAND_CREATE_RECORD_STREAM, - PA_COMMAND_DELETE_RECORD_STREAM, - PA_COMMAND_EXIT, - PA_COMMAND_REQUEST, - PA_COMMAND_AUTH, - PA_COMMAND_SET_NAME, - PA_COMMAND_LOOKUP_SINK, - PA_COMMAND_LOOKUP_SOURCE, - PA_COMMAND_DRAIN_PLAYBACK_STREAM, - PA_COMMAND_PLAYBACK_STREAM_KILLED, - PA_COMMAND_RECORD_STREAM_KILLED, - PA_COMMAND_STAT, - PA_COMMAND_GET_PLAYBACK_LATENCY, - PA_COMMAND_MAX -}; - -enum { - PA_ERROR_OK, - PA_ERROR_ACCESS, - PA_ERROR_COMMAND, - PA_ERROR_INVALID, - PA_ERROR_EXIST, - PA_ERROR_NOENTITY, - PA_ERROR_CONNECTIONREFUSED, - PA_ERROR_PROTOCOL, - PA_ERROR_TIMEOUT, - PA_ERROR_AUTHKEY, - PA_ERROR_INTERNAL, - PA_ERROR_CONNECTIONTERMINATED, - PA_ERROR_KILLED, - PA_ERROR_INVALIDSERVER, - PA_ERROR_MAX -}; - -#define PA_NATIVE_COOKIE_LENGTH 256 -#define PA_NATIVE_COOKIE_FILE ".polypaudio-cookie" - -#endif diff --git a/src/oss-util.c b/src/oss-util.c deleted file mode 100644 index cf55a6ee..00000000 --- a/src/oss-util.c +++ /dev/null @@ -1,163 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "oss-util.h" - -int pa_oss_open(const char *device, int *mode, int* pcaps) { - int fd = -1; - assert(device && mode && (*mode == O_RDWR || *mode == O_RDONLY || *mode == O_WRONLY)); - - if (*mode == O_RDWR) { - if ((fd = open(device, O_RDWR|O_NDELAY)) >= 0) { - int dcaps, *tcaps; - ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0); - - tcaps = pcaps ? pcaps : &dcaps; - - if (ioctl(fd, SNDCTL_DSP_GETCAPS, tcaps) < 0) { - fprintf(stderr, __FILE__": SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); - goto fail; - } - - if (*tcaps & DSP_CAP_DUPLEX) - return fd; - - close(fd); - } - - if ((fd = open(device, (*mode = O_WRONLY)|O_NDELAY)) < 0) { - if ((fd = open(device, (*mode = O_RDONLY)|O_NDELAY)) < 0) { - fprintf(stderr, __FILE__": open('%s'): %s\n", device, strerror(errno)); - goto fail; - } - } - } else { - if ((fd = open(device, *mode|O_NDELAY)) < 0) { - fprintf(stderr, __FILE__": open('%s'): %s\n", device, strerror(errno)); - goto fail; - } - } - - if (pcaps) { - if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { - fprintf(stderr, "SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); - goto fail; - } - } - - return fd; - -fail: - if (fd >= 0) - close(fd); - return fd; -} - -int pa_oss_auto_format(int fd, struct pa_sample_spec *ss) { - int format, channels, speed, reqformat; - static const int format_trans[] = { - [PA_SAMPLE_U8] = AFMT_U8, - [PA_SAMPLE_ALAW] = AFMT_A_LAW, - [PA_SAMPLE_ULAW] = AFMT_MU_LAW, - [PA_SAMPLE_S16LE] = AFMT_S16_LE, - [PA_SAMPLE_S16BE] = AFMT_S16_BE, - [PA_SAMPLE_FLOAT32LE] = AFMT_QUERY, /* not supported */ - [PA_SAMPLE_FLOAT32BE] = AFMT_QUERY, /* not supported */ - }; - - assert(fd >= 0 && ss); - - reqformat = format = format_trans[ss->format]; - if (reqformat == AFMT_QUERY || ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != reqformat) { - format = AFMT_S16_NE; - if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_S16_NE) { - int f = AFMT_S16_NE == AFMT_S16_LE ? AFMT_S16_BE : AFMT_S16_LE; - format = f; - if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != f) { - format = AFMT_U8; - if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_U8) { - fprintf(stderr, "SNDCTL_DSP_SETFMT: %s\n", format != AFMT_U8 ? "No supported sample format" : strerror(errno)); - return -1; - } else - ss->format = PA_SAMPLE_U8; - } else - ss->format = f == AFMT_S16_LE ? PA_SAMPLE_S16LE : PA_SAMPLE_S16BE; - } else - ss->format = PA_SAMPLE_S16NE; - } - - channels = ss->channels; - if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) { - fprintf(stderr, "SNDCTL_DSP_CHANNELS: %s\n", strerror(errno)); - return -1; - } - assert(channels); - ss->channels = channels; - - speed = ss->rate; - if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) { - fprintf(stderr, "SNDCTL_DSP_SPEED: %s\n", strerror(errno)); - return -1; - } - assert(speed); - ss->rate = speed; - - return 0; -} - -static int log2(int v) { - int k = 0; - - for (;;) { - v >>= 1; - if (!v) break; - k++; - } - - return k; -} - -int pa_oss_set_fragments(int fd, int nfrags, int frag_size) { - int arg; - arg = ((int) nfrags << 16) | log2(frag_size); - - if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &arg) < 0) { - fprintf(stderr, "SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno)); - return -1; - } - - return 0; -} diff --git a/src/oss-util.h b/src/oss-util.h deleted file mode 100644 index cb2ce33c..00000000 --- a/src/oss-util.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef fooossutilhfoo -#define fooossutilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "sample.h" - -int pa_oss_open(const char *device, int *mode, int* pcaps); -int pa_oss_auto_format(int fd, struct pa_sample_spec *ss); - -int pa_oss_set_fragments(int fd, int frags, int frag_size); - -#endif diff --git a/src/pacat-simple.c b/src/pacat-simple.c deleted file mode 100644 index 5018aa5f..00000000 --- a/src/pacat-simple.c +++ /dev/null @@ -1,83 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "polyplib-simple.h" -#include "polyplib-error.h" - -#define BUFSIZE 1024 - -int main(int argc, char*argv[]) { - static const struct pa_sample_spec ss = { - .format = PA_SAMPLE_S16LE, - .rate = 44100, - .channels = 2 - }; - struct pa_simple *s = NULL; - int ret = 1; - int error; - - if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, &error))) { - fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); - goto finish; - } - - for (;;) { - uint8_t buf[BUFSIZE]; - ssize_t r; - - if ((r = read(STDIN_FILENO, buf, sizeof(buf))) <= 0) { - if (r == 0) /* eof */ - break; - - fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno)); - goto finish; - } - - if (pa_simple_write(s, buf, r, &error) < 0) { - fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error)); - goto finish; - } - } - - /* Make sure that every single sample way played */ - if (pa_simple_drain(s, &error) < 0) { - fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(error)); - goto finish; - } - - ret = 0; - -finish: - - if (s) - pa_simple_free(s); - - return ret; -} diff --git a/src/pacat.c b/src/pacat.c deleted file mode 100644 index 1d1cc3d5..00000000 --- a/src/pacat.c +++ /dev/null @@ -1,336 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "polyplib.h" -#include "polyplib-error.h" -#include "mainloop.h" -#include "mainloop-signal.h" - -static enum { RECORD, PLAYBACK } mode = PLAYBACK; - -static struct pa_context *context = NULL; -static struct pa_stream *stream = NULL; -static struct pa_mainloop_api *mainloop_api = NULL; - -static void *buffer = NULL; -static size_t buffer_length = 0, buffer_index = 0; - -static void* stdio_source = NULL; - -static void quit(int ret) { - assert(mainloop_api); - mainloop_api->quit(mainloop_api, ret); -} - -static void context_die_callback(struct pa_context *c, void *userdata) { - assert(c); - fprintf(stderr, "Connection to server shut down, exiting.\n"); - quit(1); -} - -static void stream_die_callback(struct pa_stream *s, void *userdata) { - assert(s); - fprintf(stderr, "Stream deleted, exiting.\n"); - quit(1); -} - -static void do_stream_write(size_t length) { - size_t l; - assert(length); - - if (!buffer || !buffer_length) - return; - - l = length; - if (l > buffer_length) - l = buffer_length; - - pa_stream_write(stream, buffer+buffer_index, l); - buffer_length -= l; - buffer_index += l; - - if (!buffer_length) { - free(buffer); - buffer = NULL; - buffer_index = buffer_length = 0; - } -} - -static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) { - assert(s && length); - - if (stdio_source) - mainloop_api->enable_io(mainloop_api, stdio_source, PA_MAINLOOP_API_IO_EVENT_INPUT); - - if (!buffer) - return; - - do_stream_write(length); -} - -static void stream_read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata) { - assert(s && data && length); - - if (stdio_source) - mainloop_api->enable_io(mainloop_api, stdio_source, PA_MAINLOOP_API_IO_EVENT_OUTPUT); - - if (buffer) { - fprintf(stderr, "Buffer overrrun, dropping incoming data\n"); - return; - } - - buffer = malloc(buffer_length = length); - assert(buffer); - memcpy(buffer, data, length); - buffer_index = 0; -} - -static void stream_complete_callback(struct pa_stream*s, int success, void *userdata) { - assert(s); - - if (!success) { - fprintf(stderr, "Stream creation failed: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); - quit(1); - return; - } - - fprintf(stderr, "Stream created.\n"); -} - -static void context_complete_callback(struct pa_context *c, int success, void *userdata) { - static const struct pa_sample_spec ss = { - .format = PA_SAMPLE_S16LE, - .rate = 44100, - .channels = 2 - }; - - assert(c && !stream); - - if (!success) { - fprintf(stderr, "Connection failed: %s\n", pa_strerror(pa_context_errno(c))); - goto fail; - } - - fprintf(stderr, "Connection established.\n"); - - if (!(stream = pa_stream_new(c, mode == PLAYBACK ? PA_STREAM_PLAYBACK : PA_STREAM_RECORD, NULL, "pacat", &ss, NULL, stream_complete_callback, NULL))) { - fprintf(stderr, "pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(c))); - goto fail; - } - - pa_stream_set_die_callback(stream, stream_die_callback, NULL); - pa_stream_set_write_callback(stream, stream_write_callback, NULL); - pa_stream_set_read_callback(stream, stream_read_callback, NULL); - - return; - -fail: - quit(1); -} - -static void context_drain_complete(struct pa_context*c, void *userdata) { - quit(0); -} - -static void stream_drain_complete(struct pa_stream*s, void *userdata) { - fprintf(stderr, "Playback stream drained.\n"); - - pa_stream_free(stream); - stream = NULL; - - if (pa_context_drain(context, context_drain_complete, NULL) < 0) - quit(0); - else - fprintf(stderr, "Draining connection to server.\n"); -} - -static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { - size_t l, w = 0; - ssize_t r; - assert(a == mainloop_api && id && stdio_source == id); - - if (buffer) { - mainloop_api->enable_io(mainloop_api, stdio_source, PA_MAINLOOP_API_IO_EVENT_NULL); - return; - } - - if (!stream || !pa_stream_is_ready(stream) || !(l = w = pa_stream_writable_size(stream))) - l = 4096; - - buffer = malloc(l); - assert(buffer); - if ((r = read(fd, buffer, l)) <= 0) { - if (r == 0) { - fprintf(stderr, "Got EOF.\n"); - pa_stream_drain(stream, stream_drain_complete, NULL); - } else { - fprintf(stderr, "read() failed: %s\n", strerror(errno)); - quit(1); - } - - mainloop_api->cancel_io(mainloop_api, stdio_source); - stdio_source = NULL; - return; - } - - buffer_length = r; - buffer_index = 0; - - if (w) - do_stream_write(w); -} - -static void stdout_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { - ssize_t r; - assert(a == mainloop_api && id && stdio_source == id); - - if (!buffer) { - mainloop_api->enable_io(mainloop_api, stdio_source, PA_MAINLOOP_API_IO_EVENT_NULL); - return; - } - - assert(buffer_length); - - if ((r = write(fd, buffer+buffer_index, buffer_length)) <= 0) { - fprintf(stderr, "write() failed: %s\n", strerror(errno)); - quit(1); - - mainloop_api->cancel_io(mainloop_api, stdio_source); - stdio_source = NULL; - return; - } - - buffer_length -= r; - buffer_index += r; - - if (!buffer_length) { - free(buffer); - buffer = NULL; - buffer_length = buffer_index = 0; - } -} - -static void exit_signal_callback(void *id, int sig, void *userdata) { - fprintf(stderr, "Got SIGINT, exiting.\n"); - quit(0); - -} - -static void stream_get_latency_callback(struct pa_stream *s, uint32_t latency, void *userdata) { - assert(s); - - if (latency == (uint32_t) -1) { - fprintf(stderr, "Failed to get latency: %s\n", strerror(errno)); - quit(1); - return; - } - - fprintf(stderr, "Current latency is %u usecs.\n", latency); -} - -static void sigusr1_signal_callback(void *id, int sig, void *userdata) { - if (mode == PLAYBACK) { - fprintf(stderr, "Got SIGUSR1, requesting latency.\n"); - pa_stream_get_latency(stream, stream_get_latency_callback, NULL); - } -} - -int main(int argc, char *argv[]) { - struct pa_mainloop* m = NULL; - int ret = 1, r; - char *bn; - - if (!(bn = strrchr(argv[0], '/'))) - bn = argv[0]; - - if (strstr(bn, "rec") || strstr(bn, "mon")) - mode = RECORD; - else if (strstr(bn, "cat") || strstr(bn, "play")) - mode = PLAYBACK; - - fprintf(stderr, "Opening a %s stream.\n", mode == RECORD ? "recording" : "playback"); - - if (!(m = pa_mainloop_new())) { - fprintf(stderr, "pa_mainloop_new() failed.\n"); - goto quit; - } - - mainloop_api = pa_mainloop_get_api(m); - - r = pa_signal_init(mainloop_api); - assert(r == 0); - pa_signal_register(SIGINT, exit_signal_callback, NULL); - pa_signal_register(SIGUSR1, sigusr1_signal_callback, NULL); - signal(SIGPIPE, SIG_IGN); - - if (!(stdio_source = mainloop_api->source_io(mainloop_api, - mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO, - mode == PLAYBACK ? PA_MAINLOOP_API_IO_EVENT_INPUT : PA_MAINLOOP_API_IO_EVENT_OUTPUT, - mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) { - fprintf(stderr, "source_io() failed.\n"); - goto quit; - } - - if (!(context = pa_context_new(mainloop_api, argv[0]))) { - fprintf(stderr, "pa_context_new() failed.\n"); - goto quit; - } - - if (pa_context_connect(context, NULL, context_complete_callback, NULL) < 0) { - fprintf(stderr, "pa_context_connext() failed.\n"); - goto quit; - } - - pa_context_set_die_callback(context, context_die_callback, NULL); - - if (pa_mainloop_run(m, &ret) < 0) { - fprintf(stderr, "pa_mainloop_run() failed.\n"); - goto quit; - } - -quit: - if (stream) - pa_stream_free(stream); - if (context) - pa_context_free(context); - - if (m) { - pa_signal_done(); - pa_mainloop_free(m); - } - - if (buffer) - free(buffer); - - return ret; -} diff --git a/src/packet.c b/src/packet.c deleted file mode 100644 index e94df057..00000000 --- a/src/packet.c +++ /dev/null @@ -1,72 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "packet.h" - -struct pa_packet* pa_packet_new(size_t length) { - struct pa_packet *p; - assert(length); - p = malloc(sizeof(struct pa_packet)+length); - assert(p); - - p->ref = 1; - p->length = length; - p->data = (uint8_t*) (p+1); - p->type = PA_PACKET_APPENDED; - return p; -} - -struct pa_packet* pa_packet_new_dynamic(uint8_t* data, size_t length) { - struct pa_packet *p; - assert(data && length); - p = malloc(sizeof(struct pa_packet)); - assert(p); - - p->ref = 1; - p->length = length; - p->data = data; - p->type = PA_PACKET_DYNAMIC; - return p; -} - -struct pa_packet* pa_packet_ref(struct pa_packet *p) { - assert(p && p->ref >= 1); - p->ref++; - return p; -} - -void pa_packet_unref(struct pa_packet *p) { - assert(p && p->ref >= 1); - p->ref--; - - if (p->ref == 0) { - if (p->type == PA_PACKET_DYNAMIC) - free(p->data); - free(p); - } -} diff --git a/src/packet.h b/src/packet.h deleted file mode 100644 index 8bea07e1..00000000 --- a/src/packet.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef foopackethfoo -#define foopackethfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -struct pa_packet { - enum { PA_PACKET_APPENDED, PA_PACKET_DYNAMIC } type; - unsigned ref; - size_t length; - uint8_t *data; -}; - -struct pa_packet* pa_packet_new(size_t length); -struct pa_packet* pa_packet_new_dynamic(uint8_t* data, size_t length); - -struct pa_packet* pa_packet_ref(struct pa_packet *p); -void pa_packet_unref(struct pa_packet *p); - -#endif diff --git a/src/pactl.c b/src/pactl.c deleted file mode 100644 index 2b1ed2c1..00000000 --- a/src/pactl.c +++ /dev/null @@ -1,166 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "polyplib.h" -#include "polyplib-error.h" -#include "mainloop.h" -#include "mainloop-signal.h" - -static struct pa_context *context = NULL; -static struct pa_mainloop_api *mainloop_api = NULL; - -static enum { - NONE, - EXIT, - STAT -} action = NONE; - -static void quit(int ret) { - assert(mainloop_api); - mainloop_api->quit(mainloop_api, ret); -} - -static void context_die_callback(struct pa_context *c, void *userdata) { - assert(c); - fprintf(stderr, "Connection to server shut down, exiting.\n"); - quit(1); -} - -static void context_drain_complete(struct pa_context *c, void *userdata) { - assert(c); - fprintf(stderr, "Connection to server shut down, exiting.\n"); - quit(0); -} - -static void drain(void) { - if (pa_context_drain(context, context_drain_complete, NULL) < 0) - quit(0); -} - -static void stat_callback(struct pa_context *c, uint32_t blocks, uint32_t total, void *userdata) { - if (blocks == (uint32_t) -1) { - fprintf(stderr, "Failed to get statistics: %s\n", pa_strerror(pa_context_errno(c))); - quit(1); - return; - } - - fprintf(stderr, "Currently in use: %u blocks containing %u bytes total.\n", blocks, total); - drain(); -} - -static void context_complete_callback(struct pa_context *c, int success, void *userdata) { - assert(c); - - if (!success) { - fprintf(stderr, "Connection failed: %s\n", pa_strerror(pa_context_errno(c))); - goto fail; - } - - fprintf(stderr, "Connection established.\n"); - - if (action == STAT) - pa_context_stat(c, stat_callback, NULL); - else { - assert(action == EXIT); - pa_context_exit(c); - drain(); - } - - return; - -fail: - quit(1); -} - -static void exit_signal_callback(void *id, int sig, void *userdata) { - fprintf(stderr, "Got SIGINT, exiting.\n"); - quit(0); - -} - -int main(int argc, char *argv[]) { - struct pa_mainloop* m = NULL; - int ret = 1, r; - - if (argc >= 2) { - if (!strcmp(argv[1], "stat")) - action = STAT; - else if (!strcmp(argv[1], "exit")) - action = EXIT; - } - - if (action == NONE) { - fprintf(stderr, "No valid action specified. Use one of: stat, exit\n"); - goto quit; - } - - if (!(m = pa_mainloop_new())) { - fprintf(stderr, "pa_mainloop_new() failed.\n"); - goto quit; - } - - mainloop_api = pa_mainloop_get_api(m); - - r = pa_signal_init(mainloop_api); - assert(r == 0); - pa_signal_register(SIGINT, exit_signal_callback, NULL); - signal(SIGPIPE, SIG_IGN); - - if (!(context = pa_context_new(mainloop_api, argv[0]))) { - fprintf(stderr, "pa_context_new() failed.\n"); - goto quit; - } - - if (pa_context_connect(context, NULL, context_complete_callback, NULL) < 0) { - fprintf(stderr, "pa_context_connext() failed.\n"); - goto quit; - } - - pa_context_set_die_callback(context, context_die_callback, NULL); - - if (pa_mainloop_run(m, &ret) < 0) { - fprintf(stderr, "pa_mainloop_run() failed.\n"); - goto quit; - } - -quit: - if (context) - pa_context_free(context); - - if (m) { - pa_signal_done(); - pa_mainloop_free(m); - } - - return ret; -} diff --git a/src/parec-simple.c b/src/parec-simple.c deleted file mode 100644 index c4196a14..00000000 --- a/src/parec-simple.c +++ /dev/null @@ -1,94 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "polyplib-simple.h" -#include "polyplib-error.h" - -#define BUFSIZE 1024 - -static ssize_t loop_write(int fd, const void*data, size_t size) { - ssize_t ret = 0; - - while (size > 0) { - ssize_t r; - - if ((r = write(fd, data, size)) < 0) - return r; - - if (r == 0) - break; - - ret += r; - data += r; - size -= r; - } - - return ret; -} - -int main(int argc, char*argv[]) { - static const struct pa_sample_spec ss = { - .format = PA_SAMPLE_S16LE, - .rate = 44100, - .channels = 2 - }; - struct pa_simple *s = NULL; - int ret = 1; - int error; - - if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, &error))) { - fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); - goto finish; - } - - for (;;) { - uint8_t buf[BUFSIZE]; - ssize_t r; - - if (pa_simple_read(s, buf, sizeof(buf), &error) < 0) { - fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error)); - goto finish; - } - - if ((r = loop_write(STDOUT_FILENO, buf, sizeof(buf))) <= 0) { - fprintf(stderr, __FILE__": write() failed: %s\n", strerror(errno)); - goto finish; - } - } - - ret = 0; - -finish: - - if (s) - pa_simple_free(s); - - return ret; -} diff --git a/src/pdispatch.c b/src/pdispatch.c deleted file mode 100644 index a28458a4..00000000 --- a/src/pdispatch.c +++ /dev/null @@ -1,247 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "pdispatch.h" -#include "native-common.h" - -#ifdef DEBUG_OPCODES - -static const char *command_names[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = "ERROR", - [PA_COMMAND_TIMEOUT] = "TIMEOUT", - [PA_COMMAND_REPLY] = "REPLY", - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = "CREATE_PLAYBACK_STREAM", - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = "DELETE_PLAYBACK_STREAM", - [PA_COMMAND_CREATE_RECORD_STREAM] = "CREATE_RECORD_STREAM", - [PA_COMMAND_DELETE_RECORD_STREAM] = "DELETE_RECORD_STREAM", - [PA_COMMAND_AUTH] = "AUTH", - [PA_COMMAND_REQUEST] = "REQUEST", - [PA_COMMAND_EXIT] = "EXIT", - [PA_COMMAND_SET_NAME] = "SET_NAME", - [PA_COMMAND_LOOKUP_SINK] = "LOOKUP_SINK", - [PA_COMMAND_LOOKUP_SOURCE] = "LOOKUP_SOURCE", - [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = "DRAIN_PLAYBACK_STREAM", - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = "PLAYBACK_STREAM_KILLED", - [PA_COMMAND_RECORD_STREAM_KILLED] = "RECORD_STREAM_KILLED", - [PA_COMMAND_STAT] = "STAT", - [PA_COMMAND_GET_PLAYBACK_LATENCY] = "PLAYBACK_LATENCY", -}; - -#endif - -struct reply_info { - struct pa_pdispatch *pdispatch; - struct reply_info *next, *previous; - void (*callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - void *userdata; - uint32_t tag; - void *mainloop_timeout; - int callback_is_running; -}; - -struct pa_pdispatch { - struct pa_mainloop_api *mainloop; - const struct pa_pdispatch_command *command_table; - unsigned n_commands; - struct reply_info *replies; - void (*drain_callback)(struct pa_pdispatch *pd, void *userdata); - void *drain_userdata; - int in_use, shall_free; -}; - -static void reply_info_free(struct reply_info *r) { - assert(r && r->pdispatch && r->pdispatch->mainloop); - - if (r->pdispatch) - r->pdispatch->mainloop->cancel_time(r->pdispatch->mainloop, r->mainloop_timeout); - - if (r->previous) - r->previous->next = r->next; - else - r->pdispatch->replies = r->next; - - if (r->next) - r->next->previous = r->previous; - - free(r); -} - -struct pa_pdispatch* pa_pdispatch_new(struct pa_mainloop_api *mainloop, const struct pa_pdispatch_command*table, unsigned entries) { - struct pa_pdispatch *pd; - assert(mainloop); - - assert((entries && table) || (!entries && !table)); - - pd = malloc(sizeof(struct pa_pdispatch)); - assert(pd); - pd->mainloop = mainloop; - pd->command_table = table; - pd->n_commands = entries; - pd->replies = NULL; - pd->drain_callback = NULL; - pd->drain_userdata = NULL; - - pd->in_use = pd->shall_free = 0; - return pd; -} - -void pa_pdispatch_free(struct pa_pdispatch *pd) { - assert(pd); - - if (pd->in_use) { - pd->shall_free = 1; - return; - } - - while (pd->replies) - reply_info_free(pd->replies); - free(pd); -} - -int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *userdata) { - uint32_t tag, command; - struct pa_tagstruct *ts = NULL; - int ret = -1; - assert(pd && packet && packet->data && !pd->in_use); - - if (packet->length <= 8) - goto finish; - - ts = pa_tagstruct_new(packet->data, packet->length); - assert(ts); - - if (pa_tagstruct_getu32(ts, &command) < 0 || - pa_tagstruct_getu32(ts, &tag) < 0) - goto finish; - -#ifdef DEBUG_OPCODES - fprintf(stderr, __FILE__": Recieved opcode <%s>\n", command_names[command]); -#endif - - if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) { - struct reply_info *r; - - for (r = pd->replies; r; r = r->next) - if (r->tag == tag) - break; - - if (r) { - pd->in_use = r->callback_is_running = 1; - assert(r->callback); - r->callback(r->pdispatch, command, tag, ts, r->userdata); - pd->in_use = r->callback_is_running = 0; - reply_info_free(r); - - if (pd->shall_free) - pa_pdispatch_free(pd); - else { - if (pd->drain_callback && !pa_pdispatch_is_pending(pd)) - pd->drain_callback(pd, pd->drain_userdata); - } - } - - } else if (pd->command_table && command < pd->n_commands) { - const struct pa_pdispatch_command *c = pd->command_table+command; - - if (c->proc) - c->proc(pd, command, tag, ts, userdata); - } else - goto finish; - - ret = 0; - -finish: - if (ts) - pa_tagstruct_free(ts); - - return ret; -} - -static void timeout_callback(struct pa_mainloop_api*m, void *id, const struct timeval *tv, void *userdata) { - struct reply_info*r = userdata; - assert (r && r->mainloop_timeout == id && r->pdispatch && r->pdispatch->mainloop == m && r->callback); - - r->callback(r->pdispatch, PA_COMMAND_TIMEOUT, r->tag, NULL, r->userdata); - reply_info_free(r); - - if (r->pdispatch->drain_callback && !pa_pdispatch_is_pending(r->pdispatch)) - r->pdispatch->drain_callback(r->pdispatch, r->pdispatch->drain_userdata); -} - -void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int timeout, void (*cb)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void *userdata) { - struct reply_info *r; - struct timeval tv; - assert(pd && cb); - - r = malloc(sizeof(struct reply_info)); - assert(r); - r->pdispatch = pd; - r->callback = cb; - r->userdata = userdata; - r->tag = tag; - r->callback_is_running = 0; - - gettimeofday(&tv, NULL); - tv.tv_sec += timeout; - - r->mainloop_timeout = pd->mainloop->source_time(pd->mainloop, &tv, timeout_callback, r); - assert(r->mainloop_timeout); - - r->previous = NULL; - r->next = pd->replies; - if (r->next) - r->next->previous = r; - pd->replies = r; -} - -int pa_pdispatch_is_pending(struct pa_pdispatch *pd) { - assert(pd); - - return !!pd->replies; -} - -void pa_pdispatch_set_drain_callback(struct pa_pdispatch *pd, void (*cb)(struct pa_pdispatch *pd, void *userdata), void *userdata) { - assert(pd); - assert(!cb || pa_pdispatch_is_pending(pd)); - - pd->drain_callback = cb; - pd->drain_userdata = userdata; -} - -void pa_pdispatch_unregister_reply(struct pa_pdispatch *pd, void *userdata) { - struct reply_info *r, *n; - assert(pd); - - for (r = pd->replies; r; r = n) { - n = r->next; - - if (!r->callback_is_running && r->userdata == userdata) /* when this item's callback is currently running it is destroyed anyway in the very near future */ - reply_info_free(r); - } -} diff --git a/src/pdispatch.h b/src/pdispatch.h deleted file mode 100644 index 796c1e03..00000000 --- a/src/pdispatch.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef foopdispatchhfoo -#define foopdispatchhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include "tagstruct.h" -#include "packet.h" -#include "mainloop-api.h" - -struct pa_pdispatch; - -/* It is safe to destroy the calling pdispatch object from all callbacks */ - -struct pa_pdispatch_command { - void (*proc)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -}; - -struct pa_pdispatch* pa_pdispatch_new(struct pa_mainloop_api *m, const struct pa_pdispatch_command*table, unsigned entries); -void pa_pdispatch_free(struct pa_pdispatch *pd); - -int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*p, void *userdata); - -void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int timeout, void (*cb)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void *userdata); - -int pa_pdispatch_is_pending(struct pa_pdispatch *pd); - -void pa_pdispatch_set_drain_callback(struct pa_pdispatch *pd, void (*cb)(struct pa_pdispatch *pd, void *userdata), void *userdata); - -/* Remove all reply slots with the give userdata parameter */ -void pa_pdispatch_unregister_reply(struct pa_pdispatch *pd, void *userdata); - -#endif diff --git a/src/polypaudio.pa b/src/polypaudio.pa deleted file mode 100755 index 177707ba..00000000 --- a/src/polypaudio.pa +++ /dev/null @@ -1,41 +0,0 @@ -#!./polypaudio -F - -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with polypaudio; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - - -# Load audio drivers -load module-alsa-sink -load module-alsa-source device=plughw:1,0 -#load module-oss device="/dev/dsp" -#load module-oss-mmap device="/dev/dsp" - -# Load several protocols -load module-esound-protocol-tcp -load module-simple-protocol-tcp -load module-native-protocol-unix -load module-cli-protocol-unix - -# Load the CLI module -load module-cli - -.nofail - -# Make some devices default -sink_default alsa_output -source_default alsa_input - diff --git a/src/polyplib-def.h b/src/polyplib-def.h deleted file mode 100644 index e43f4b35..00000000 --- a/src/polyplib-def.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef foopolyplibdefhfoo -#define foopolyplibdefhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -enum pa_stream_direction { - PA_STREAM_PLAYBACK, - PA_STREAM_RECORD -}; - -struct pa_buffer_attr { - uint32_t maxlength; - uint32_t tlength; - uint32_t prebuf; - uint32_t minreq; - uint32_t fragsize; -}; - -#endif diff --git a/src/polyplib-error.c b/src/polyplib-error.c deleted file mode 100644 index 10b637c4..00000000 --- a/src/polyplib-error.c +++ /dev/null @@ -1,53 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "polyplib-error.h" -#include "native-common.h" - -static const char* const errortab[PA_ERROR_MAX] = { - [PA_ERROR_OK] = "OK", - [PA_ERROR_ACCESS] = "Access denied", - [PA_ERROR_COMMAND] = "Unknown command", - [PA_ERROR_INVALID] = "Invalid argument", - [PA_ERROR_EXIST] = "Entity exists", - [PA_ERROR_NOENTITY] = "No such entity", - [PA_ERROR_CONNECTIONREFUSED] = "Connection refused", - [PA_ERROR_PROTOCOL] = "Protocol corrupt", - [PA_ERROR_TIMEOUT] = "Timeout", - [PA_ERROR_AUTHKEY] = "Not authorization key", - [PA_ERROR_INTERNAL] = "Internal error", - [PA_ERROR_CONNECTIONTERMINATED] = "Connection terminated", - [PA_ERROR_KILLED] = "Entity killed", -}; - -const char*pa_strerror(uint32_t error) { - if (error >= PA_ERROR_MAX) - return NULL; - - return errortab[error]; -} diff --git a/src/polyplib-error.h b/src/polyplib-error.h deleted file mode 100644 index cb86864a..00000000 --- a/src/polyplib-error.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef foopolypliberrorhfoo -#define foopolypliberrorhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -const char* pa_strerror(uint32_t error); - -#endif diff --git a/src/polyplib-simple.c b/src/polyplib-simple.c deleted file mode 100644 index 024cb18a..00000000 --- a/src/polyplib-simple.c +++ /dev/null @@ -1,259 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "polyplib-simple.h" -#include "polyplib.h" -#include "mainloop.h" -#include "native-common.h" -/*#include "polyp-error.h"*/ - -struct pa_simple { - struct pa_mainloop *mainloop; - struct pa_context *context; - struct pa_stream *stream; - enum pa_stream_direction direction; - - int dead, drained; - - void *read_data; - size_t read_index, read_length; -}; - -static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata); - -static int check_error(struct pa_simple *p, int *perror) { - assert(p); - - if (pa_context_is_dead(p->context) || (p->stream && pa_stream_is_dead(p->stream))) { - if (perror) - *perror = pa_context_errno(p->context); - return -1; - } - - return 0; -} - -static int iterate(struct pa_simple *p, int block, int *perror) { - assert(p && p->context && p->mainloop); - - if (check_error(p, perror) < 0) - return -1; - - if (!block && !pa_context_is_pending(p->context)) - return 0; - - do { - if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) { - if (perror) - *perror = PA_ERROR_INTERNAL; - return -1; - } - - if (check_error(p, perror) < 0) - return -1; - - } while (pa_context_is_pending(p->context)); - - return 0; -} - -struct pa_simple* pa_simple_new( - const char *server, - const char *name, - enum pa_stream_direction dir, - const char *dev, - const char *stream_name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - int *perror) { - - struct pa_simple *p; - int error = PA_ERROR_INTERNAL; - assert(ss); - - p = malloc(sizeof(struct pa_simple)); - assert(p); - p->context = NULL; - p->stream = NULL; - p->mainloop = pa_mainloop_new(); - assert(p->mainloop); - p->dead = 0; - p->direction = dir; - p->read_data = NULL; - p->read_index = p->read_length = 0; - - if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name))) - goto fail; - - if (pa_context_connect(p->context, server, NULL, NULL) < 0) { - error = pa_context_errno(p->context); - goto fail; - } - - /* Wait until the context is ready */ - while (!pa_context_is_ready(p->context)) { - if (iterate(p, 1, &error) < 0) - goto fail; - } - - if (!(p->stream = pa_stream_new(p->context, dir, dev, stream_name, ss, attr, NULL, NULL))) - goto fail; - - /* Wait until the stream is ready */ - while (!pa_stream_is_ready(p->stream)) { - if (iterate(p, 1, &error) < 0) - goto fail; - } - - pa_stream_set_read_callback(p->stream, read_callback, p); - - return p; - -fail: - if (perror) - *perror = error; - pa_simple_free(p); - return NULL; -} - -void pa_simple_free(struct pa_simple *s) { - assert(s); - - free(s->read_data); - - if (s->stream) - pa_stream_free(s->stream); - - if (s->context) - pa_context_free(s->context); - - if (s->mainloop) - pa_mainloop_free(s->mainloop); - - free(s); -} - -int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *perror) { - assert(p && data && p->direction == PA_STREAM_PLAYBACK); - - while (length > 0) { - size_t l; - - while (!(l = pa_stream_writable_size(p->stream))) - if (iterate(p, 1, perror) < 0) - return -1; - - if (l > length) - l = length; - - pa_stream_write(p->stream, data, l); - data += l; - length -= l; - } - - /* Make sure that no data is pending for write */ - if (iterate(p, 0, perror) < 0) - return -1; - - return 0; -} - -static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata) { - struct pa_simple *p = userdata; - assert(s && data && length && p); - - if (p->read_data) { - fprintf(stderr, __FILE__": Buffer overflow, dropping incoming memory blocks.\n"); - free(p->read_data); - } - - p->read_data = malloc(p->read_length = length); - assert(p->read_data); - memcpy(p->read_data, data, length); - p->read_index = 0; -} - -int pa_simple_read(struct pa_simple *p, void*data, size_t length, int *perror) { - assert(p && data && p->direction == PA_STREAM_RECORD); - - while (length > 0) { - if (p->read_data) { - size_t l = length; - - if (p->read_length <= l) - l = p->read_length; - - memcpy(data, p->read_data+p->read_index, l); - - data += l; - length -= l; - - p->read_index += l; - p->read_length -= l; - - if (!p->read_length) { - free(p->read_data); - p->read_data = NULL; - p->read_index = 0; - } - - if (!length) - return 0; - - assert(!p->read_data); - } - - if (iterate(p, 1, perror) < 0) - return -1; - } - - return 0; -} - -static void drain_complete(struct pa_stream *s, void *userdata) { - struct pa_simple *p = userdata; - assert(s && p); - p->drained = 1; -} - -int pa_simple_drain(struct pa_simple *p, int *perror) { - assert(p && p->direction == PA_STREAM_PLAYBACK); - p->drained = 0; - pa_stream_drain(p->stream, drain_complete, p); - - while (!p->drained) { - if (iterate(p, 1, perror) < 0) { - pa_stream_drain(p->stream, NULL, NULL); - return -1; - } - } - - return 0; -} diff --git a/src/polyplib-simple.h b/src/polyplib-simple.h deleted file mode 100644 index 0544410c..00000000 --- a/src/polyplib-simple.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef foopolyplibsimplehfoo -#define foopolyplibsimplehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "sample.h" -#include "polyplib-def.h" - -struct pa_simple; - -struct pa_simple* pa_simple_new( - const char *server, - const char *name, - enum pa_stream_direction dir, - const char *dev, - const char *stream_name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - int *error); - -void pa_simple_free(struct pa_simple *s); - -int pa_simple_write(struct pa_simple *s, const void*data, size_t length, int *error); -int pa_simple_drain(struct pa_simple *s, int *error); - -int pa_simple_read(struct pa_simple *s, void*data, size_t length, int *error); - -#endif diff --git a/src/polyplib.c b/src/polyplib.c deleted file mode 100644 index ea5003b4..00000000 --- a/src/polyplib.c +++ /dev/null @@ -1,973 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "polyplib.h" -#include "native-common.h" -#include "pdispatch.h" -#include "pstream.h" -#include "dynarray.h" -#include "socket-client.h" -#include "pstream-util.h" -#include "authkey.h" -#include "util.h" - -#define DEFAULT_MAXLENGTH 204800 -#define DEFAULT_TLENGTH 10240 -#define DEFAULT_PREBUF 4096 -#define DEFAULT_MINREQ 1024 -#define DEFAULT_FRAGSIZE 1024 - -#define DEFAULT_TIMEOUT (5*60) -#define DEFAULT_SERVER "/tmp/polypaudio/native" -#define DEFAULT_PORT "4713" - -struct pa_context { - char *name; - struct pa_mainloop_api* mainloop; - struct pa_socket_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; - struct pa_dynarray *record_streams, *playback_streams; - struct pa_stream *first_stream; - uint32_t ctag; - uint32_t error; - enum { - CONTEXT_UNCONNECTED, - CONTEXT_CONNECTING, - CONTEXT_AUTHORIZING, - CONTEXT_SETTING_NAME, - CONTEXT_READY, - CONTEXT_DEAD - } state; - - void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); - void *connect_complete_userdata; - - void (*drain_complete_callback)(struct pa_context*c, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_context*c, void *userdata); - void *die_userdata; - - void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); - void *stat_userdata; - - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; -}; - -struct pa_stream { - struct pa_context *context; - struct pa_stream *next, *previous; - - char *name; - struct pa_buffer_attr buffer_attr; - struct pa_sample_spec sample_spec; - uint32_t device_index; - uint32_t channel; - int channel_valid; - enum pa_stream_direction direction; - - enum { STREAM_LOOKING_UP, STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; - uint32_t requested_bytes; - - void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); - void *read_userdata; - - void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); - void *write_userdata; - - void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); - void *create_complete_userdata; - - void (*drain_complete_callback)(struct pa_stream *s, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_stream*c, void *userdata); - void *die_userdata; - - void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); - void *get_latency_userdata; -}; - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_EXIT] = { NULL }, - [PA_COMMAND_REQUEST] = { command_request }, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, -}; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { - struct pa_context *c; - assert(mainloop && name); - - c = malloc(sizeof(struct pa_context)); - assert(c); - c->name = strdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - assert(c->playback_streams); - c->record_streams = pa_dynarray_new(); - assert(c->record_streams); - c->first_stream = NULL; - c->error = PA_ERROR_OK; - c->state = CONTEXT_UNCONNECTED; - c->ctag = 0; - - c->connect_complete_callback = NULL; - c->connect_complete_userdata = NULL; - - c->drain_complete_callback = NULL; - c->drain_complete_userdata = NULL; - - c->die_callback = NULL; - c->die_userdata = NULL; - - c->stat_callback = NULL; - c->stat_userdata = NULL; - - pa_check_for_sigpipe(); - return c; -} - -void pa_context_free(struct pa_context *c) { - assert(c); - - while (c->first_stream) - pa_stream_free(c->first_stream); - - if (c->client) - pa_socket_client_free(c->client); - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - if (c->pstream) - pa_pstream_free(c->pstream); - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - free(c->name); - free(c); -} - -static void stream_dead(struct pa_stream *s) { - assert(s); - - if (s->state == STREAM_DEAD) - return; - - if (s->state == STREAM_READY) { - s->state = STREAM_DEAD; - if (s->die_callback) - s->die_callback(s, s->die_userdata); - } else - s->state = STREAM_DEAD; -} - -static void context_dead(struct pa_context *c) { - struct pa_stream *s; - assert(c); - - if (c->state == CONTEXT_DEAD) - return; - - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) - pa_pstream_free(c->pstream); - c->pstream = NULL; - - if (c->client) - pa_socket_client_free(c->client); - c->client = NULL; - - for (s = c->first_stream; s; s = s->next) - stream_dead(s); - - if (c->state == CONTEXT_READY) { - c->state = CONTEXT_DEAD; - if (c->die_callback) - c->die_callback(c, c->die_userdata); - } else - c->state = CONTEXT_DEAD; -} - -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { - struct pa_context *c = userdata; - assert(p && c); - c->error = PA_ERROR_CONNECTIONTERMINATED; - context_dead(c); -} - -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { - struct pa_context *c = userdata; - assert(p && packet && c); - - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - fprintf(stderr, "polyp.c: invalid packet.\n"); - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - } -} - -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - - if (!(s = pa_dynarray_get(c->record_streams, channel))) - return; - - if (s->read_callback) - s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); -} - -static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { - assert(c && t); - - if (command == PA_COMMAND_ERROR) { - if (pa_tagstruct_getu32(t, &c->error) < 0) { - c->error = PA_ERROR_PROTOCOL; - return -1; - } - - return 0; - } - - c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; - return -1; -} - -static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); - - if (command != PA_COMMAND_REPLY) { - handle_error(c, command, t); - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - if (c->state == CONTEXT_AUTHORIZING) { - struct pa_tagstruct *t; - c->state = CONTEXT_SETTING_NAME; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, c->name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - } else { - assert(c->state == CONTEXT_SETTING_NAME); - - c->state = CONTEXT_READY; - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 1, c->connect_complete_userdata); - } - - return; -} - -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { - struct pa_context *c = userdata; - struct pa_tagstruct *t; - uint32_t tag; - assert(client && c && c->state == CONTEXT_CONNECTING); - - pa_socket_client_free(client); - c->client = NULL; - - if (!io) { - c->error = PA_ERROR_CONNECTIONREFUSED; - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - c->pstream = pa_pstream_new(c->mainloop, io); - assert(c->pstream); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - c->state = CONTEXT_AUTHORIZING; -} - -static struct sockaddr *resolve_server(const char *server, size_t *len) { - struct sockaddr *sa; - struct addrinfo hints, *result = NULL; - char *port; - assert(server && len); - - if ((port = strrchr(server, ':'))) - port++; - if (!port) - port = DEFAULT_PORT; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(server, port, &hints, &result) != 0) - return NULL; - assert(result); - - sa = malloc(*len = result->ai_addrlen); - assert(sa); - memcpy(sa, result->ai_addr, *len); - - freeaddrinfo(result); - - return sa; - -} - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { - assert(c && c->state == CONTEXT_UNCONNECTED); - - if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { - c->error = PA_ERROR_AUTHKEY; - return -1; - } - - if (!server) - if (!(server = getenv("POLYP_SERVER"))) - server = DEFAULT_SERVER; - - assert(!c->client); - - if (*server == '/') { - if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } else { - struct sockaddr* sa; - size_t sa_len; - - if (!(sa = resolve_server(server, &sa_len))) { - c->error = PA_ERROR_INVALIDSERVER; - return -1; - } - - c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); - free(sa); - - if (!c->client) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } - - c->connect_complete_callback = complete; - c->connect_complete_userdata = userdata; - - pa_socket_client_set_callback(c->client, on_connection, c); - c->state = CONTEXT_CONNECTING; - - return 0; -} - -int pa_context_is_dead(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_DEAD; -} - -int pa_context_is_ready(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_READY; -} - -int pa_context_errno(struct pa_context *c) { - assert(c); - return c->error; -} - -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { - assert(c); - c->die_callback = cb; - c->die_userdata = userdata; -} - -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - uint32_t channel; - assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - return; - - c->error = PA_ERROR_KILLED; - stream_dead(s); -} - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s; - struct pa_context *c = userdata; - uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - return; - - if (s->state != STREAM_READY) - return; - - s->requested_bytes += bytes; - - if (s->requested_bytes && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); -} - -static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s && s->state == STREAM_CREATING); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - - return; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - pa_tagstruct_getu32(t, &s->device_index) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, s); - - s->state = STREAM_READY; - if (s->create_complete_callback) - s->create_complete_callback(s, 1, s->create_complete_userdata); -} - -static void create_stream(struct pa_stream *s, uint32_t tdev_index) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s); - - s->state = STREAM_CREATING; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, tdev_index); - pa_tagstruct_putu32(t, s->buffer_attr.maxlength); - if (s->direction == PA_STREAM_PLAYBACK) { - pa_tagstruct_putu32(t, s->buffer_attr.tlength); - pa_tagstruct_putu32(t, s->buffer_attr.prebuf); - pa_tagstruct_putu32(t, s->buffer_attr.minreq); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); -} - -static void lookup_device_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t tdev; - assert(pd && s && s->state == STREAM_LOOKING_UP); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &tdev) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - create_stream(s, tdev); -} - -static void lookup_device(struct pa_stream *s, const char *tdev) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s); - - s->state = STREAM_LOOKING_UP; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_LOOKUP_SINK : PA_COMMAND_LOOKUP_SOURCE); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, tdev); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, lookup_device_callback, s); -} - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata) { - - struct pa_stream *s; - - assert(c && name && ss && c->state == CONTEXT_READY); - - s = malloc(sizeof(struct pa_stream)); - assert(s); - s->context = c; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->die_callback = NULL; - s->die_userdata = NULL; - s->create_complete_callback = complete; - s->create_complete_userdata = NULL; - s->get_latency_callback = NULL; - s->get_latency_userdata = NULL; - - s->name = strdup(name); - s->state = STREAM_CREATING; - s->requested_bytes = 0; - s->channel = 0; - s->channel_valid = 0; - s->device_index = (uint32_t) -1; - s->direction = dir; - s->sample_spec = *ss; - if (attr) - s->buffer_attr = *attr; - else { - s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; - s->buffer_attr.tlength = DEFAULT_TLENGTH; - s->buffer_attr.prebuf = DEFAULT_PREBUF; - s->buffer_attr.minreq = DEFAULT_MINREQ; - s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; - } - - s->next = c->first_stream; - if (s->next) - s->next->previous = s; - s->previous = NULL; - c->first_stream = s; - - if (dev) - lookup_device(s, dev); - else - create_stream(s, (uint32_t) -1); - - return s; -} - -void pa_stream_free(struct pa_stream *s) { - assert(s && s->context); - - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - free(s->name); - - if (s->channel_valid && s->context->state == CONTEXT_READY) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, PA_COMMAND_DELETE_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - } - - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; - else - s->context->first_stream = s->next; - - free(s); -} - -void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { - struct pa_memchunk chunk; - assert(s && s->context && data && length && s->state == STREAM_READY); - - chunk.memblock = pa_memblock_new(length); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); - pa_memblock_unref(chunk.memblock); - - /*fprintf(stderr, "Sent %u bytes\n", length);*/ - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; -} - -size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s && s->state == STREAM_READY); - return s->requested_bytes; -} - -void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->read_callback = cb; - s->read_userdata = userdata; -} - -int pa_stream_is_dead(struct pa_stream *s) { - return s->state == STREAM_DEAD; -} - -int pa_stream_is_ready(struct pa_stream*s) { - return s->state == STREAM_READY; -} - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { - assert(s); - s->die_callback = cb; - s->die_userdata = userdata; -} - -int pa_context_is_pending(struct pa_context *c) { - assert(c); - - if (c->state != CONTEXT_READY) - return 0; - - return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); -} - -struct pa_context* pa_stream_get_context(struct pa_stream *p) { - assert(p); - return p->context; -} - -static void set_dispatch_callbacks(struct pa_context *c); - -static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void set_dispatch_callbacks(struct pa_context *c) { - assert(c && c->state == CONTEXT_READY); - - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(c->pdispatch)) { - pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); - return; - } - - if (pa_pstream_is_pending(c->pstream)) { - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - return; - } - - assert(c->drain_complete_callback); - c->drain_complete_callback(c, c->drain_complete_userdata); -} - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata) { - - assert(c && c->state == CONTEXT_READY); - - if (complete == NULL) { - c->drain_complete_callback = NULL; - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - return 0; - } - - if (!pa_context_is_pending(c)) - return -1; - - c->drain_complete_callback = complete; - c->drain_complete_userdata = userdata; - - set_dispatch_callbacks(c); - - return 0; -} - -static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - return; - } - - if (s->state != STREAM_READY) - return; - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->drain_complete_callback) { - void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; - s->drain_complete_callback = NULL; - temp(s, s->drain_complete_userdata); - } -} - - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s && s->state == STREAM_READY); - - if (!complete) { - s->drain_complete_callback = NULL; - return; - } - - s->drain_complete_callback = complete; - s->drain_complete_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); -} - -void pa_context_exit(struct pa_context *c) { - struct pa_tagstruct *t; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - uint32_t total, count; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &count) < 0 || - pa_tagstruct_getu32(t, &total) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, count, total, c->stat_userdata); -} - -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - c->stat_callback = cb; - c->stat_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_STAT); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); -} - -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t latency; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &latency) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, latency, s->get_latency_userdata); -} - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - p->get_latency_callback = cb; - p->get_latency_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); -} diff --git a/src/polyplib.h b/src/polyplib.h deleted file mode 100644 index 440b9658..00000000 --- a/src/polyplib.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "sample.h" -#include "polyplib-def.h" -#include "mainloop-api.h" - -struct pa_context; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); - -int pa_context_connect( - struct pa_context *c, - const char *server, - void (*complete) (struct pa_context*c, int success, void *userdata), - void *userdata); - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata); - -void pa_context_free(struct pa_context *c); - -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); - -int pa_context_is_dead(struct pa_context *c); -int pa_context_is_ready(struct pa_context *c); -int pa_context_errno(struct pa_context *c); - -int pa_context_is_pending(struct pa_context *c); - -void pa_context_exit(struct pa_context *c); -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); - -struct pa_stream; - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata); - -void pa_stream_free(struct pa_stream *p); - -void pa_stream_drain( - struct pa_stream *s, - void (*complete) (struct pa_stream*s, void *userdata), - void *userdata); - - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); - -void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); -void pa_stream_write(struct pa_stream *p, const void *data, size_t length); -size_t pa_stream_writable_size(struct pa_stream *p); - -void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); - -int pa_stream_is_dead(struct pa_stream *p); -int pa_stream_is_ready(struct pa_stream*p); - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); - -struct pa_context* pa_stream_get_context(struct pa_stream *p); - -#endif diff --git a/src/protocol-cli.c b/src/protocol-cli.c deleted file mode 100644 index d6e69b54..00000000 --- a/src/protocol-cli.c +++ /dev/null @@ -1,85 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "protocol-cli.h" -#include "cli.h" - -struct pa_protocol_cli { - struct pa_module *module; - struct pa_core *core; - struct pa_socket_server*server; - struct pa_idxset *connections; -}; - -static void cli_eof_cb(struct pa_cli*c, void*userdata) { - struct pa_protocol_cli *p = userdata; - assert(p); - pa_idxset_remove_by_data(p->connections, c, NULL); - pa_cli_free(c); -} - -static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { - struct pa_protocol_cli *p = userdata; - struct pa_cli *c; - assert(s && io && p); - - c = pa_cli_new(p->core, io, p->module); - assert(c); - pa_cli_set_eof_callback(c, cli_eof_cb, p); - - pa_idxset_put(p->connections, c, NULL); -} - -struct pa_protocol_cli* pa_protocol_cli_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { - struct pa_protocol_cli* p; - assert(core && server); - - p = malloc(sizeof(struct pa_protocol_cli)); - assert(p); - p->module = m; - p->core = core; - p->server = server; - p->connections = pa_idxset_new(NULL, NULL); - - pa_socket_server_set_callback(p->server, on_connection, p); - - return p; -} - -static void free_connection(void *p, void *userdata) { - assert(p); - pa_cli_free(p); -} - -void pa_protocol_cli_free(struct pa_protocol_cli *p) { - assert(p); - - pa_idxset_free(p->connections, free_connection, NULL); - pa_socket_server_free(p->server); - free(p); -} diff --git a/src/protocol-cli.h b/src/protocol-cli.h deleted file mode 100644 index 7ad2db75..00000000 --- a/src/protocol-cli.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef fooprotocolclihfoo -#define fooprotocolclihfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "core.h" -#include "socket-server.h" -#include "module.h" -#include "modargs.h" - -struct pa_protocol_cli; - -struct pa_protocol_cli* pa_protocol_cli_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma); -void pa_protocol_cli_free(struct pa_protocol_cli *n); - -#endif diff --git a/src/protocol-esound.c b/src/protocol-esound.c deleted file mode 100644 index 8a7c4bcb..00000000 --- a/src/protocol-esound.c +++ /dev/null @@ -1,847 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "protocol-esound.h" -#include "esound.h" -#include "memblock.h" -#include "client.h" -#include "sink-input.h" -#include "sink.h" -#include "source-output.h" -#include "source.h" -#include "sample.h" - -#include "authkey.h" - -#define DEFAULT_COOKIE_FILE ".esd_auth" - -#define PLAYBACK_BUFFER_SECONDS (.5) -#define PLAYBACK_BUFFER_FRAGMENTS (10) -#define RECORD_BUFFER_SECONDS (5) -#define RECORD_BUFFER_FRAGMENTS (100) - -/* This is heavily based on esound's code */ - -struct connection { - uint32_t index; - struct pa_protocol_esound *protocol; - struct pa_iochannel *io; - struct pa_client *client; - int authorized, swap_byte_order; - void *write_data; - size_t write_data_alloc, write_data_index, write_data_length; - void *read_data; - size_t read_data_alloc, read_data_length; - esd_proto_t request; - esd_client_state_t state; - struct pa_sink_input *sink_input; - struct pa_source_output *source_output; - struct pa_memblockq *input_memblockq, *output_memblockq; - void *fixed_source; - struct { - struct pa_memblock *current_memblock; - size_t memblock_index, fragment_size; - } playback; -}; - -struct pa_protocol_esound { - int public; - struct pa_module *module; - struct pa_core *core; - struct pa_socket_server *server; - struct pa_idxset *connections; - uint32_t sink_index, source_index; - unsigned n_player; - uint8_t esd_key[ESD_KEY_LEN]; -}; - -typedef struct proto_handler { - size_t data_length; - int (*proc)(struct connection *c, esd_proto_t request, const void *data, size_t length); - const char *description; -} esd_proto_handler_info_t; - -static void sink_input_drop_cb(struct pa_sink_input *i, size_t length); -static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk); -static void sink_input_kill_cb(struct pa_sink_input *i); -static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i); - -static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk); -static void source_output_kill_cb(struct pa_source_output *o); - -static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_stream_play(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_get_latency(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_server_info(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const void *data, size_t length); - -/* the big map of protocol handler info */ -static struct proto_handler proto_map[ESD_PROTO_MAX] = { - { ESD_KEY_LEN + sizeof(int), esd_proto_connect, "connect" }, - { ESD_KEY_LEN + sizeof(int), NULL, "lock" }, - { ESD_KEY_LEN + sizeof(int), NULL, "unlock" }, - - { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_play, "stream play" }, - { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream rec" }, - { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream mon" }, - - { ESD_NAME_MAX + 3 * sizeof(int), NULL, "sample cache" }, - { sizeof(int), NULL, "sample free" }, - { sizeof(int), NULL, "sample play" }, - { sizeof(int), NULL, "sample loop" }, - { sizeof(int), NULL, "sample stop" }, - { -1, NULL, "TODO: sample kill" }, - - { ESD_KEY_LEN + sizeof(int), NULL, "standby" }, - { ESD_KEY_LEN + sizeof(int), NULL, "resume" }, - - { ESD_NAME_MAX, NULL, "sample getid" }, - { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" }, - - { sizeof(int), esd_proto_server_info, "server info" }, - { sizeof(int), esd_proto_all_info, "all info" }, - { -1, NULL, "TODO: subscribe" }, - { -1, NULL, "TODO: unsubscribe" }, - - { 3 * sizeof(int), esd_proto_stream_pan, "stream pan"}, - { 3 * sizeof(int), NULL, "sample pan" }, - - { sizeof(int), NULL, "standby mode" }, - { 0, esd_proto_get_latency, "get latency" } -}; - - -static void connection_free(struct connection *c) { - assert(c); - pa_idxset_remove_by_data(c->protocol->connections, c, NULL); - - if (c->state == ESD_STREAMING_DATA) - c->protocol->n_player--; - - pa_client_free(c->client); - - if (c->sink_input) - pa_sink_input_free(c->sink_input); - if (c->source_output) - pa_source_output_free(c->source_output); - if (c->input_memblockq) - pa_memblockq_free(c->input_memblockq); - if (c->output_memblockq) - pa_memblockq_free(c->output_memblockq); - - if (c->playback.current_memblock) - pa_memblock_unref(c->playback.current_memblock); - - free(c->read_data); - free(c->write_data); - - pa_iochannel_free(c->io); - - if (c->fixed_source) - c->protocol->core->mainloop->cancel_fixed(c->protocol->core->mainloop, c->fixed_source); - - free(c); -} - -static struct pa_sink* get_output_sink(struct pa_protocol_esound *p) { - struct pa_sink *s; - assert(p); - - if (!(s = pa_idxset_get_by_index(p->core->sinks, p->sink_index))) - s = pa_sink_get_default(p->core); - - p->sink_index = s ? s->index : PA_IDXSET_INVALID; - return s; -} - -static struct pa_source* get_input_source(struct pa_protocol_esound *p) { - struct pa_source *s; - assert(p); - - if (!(s = pa_idxset_get_by_index(p->core->sources, p->sink_index))) - s = pa_source_get_default(p->core); - - p->source_index = s ? s->index : PA_IDXSET_INVALID; - return s; -} - -static void* connection_write(struct connection *c, size_t length) { - size_t t, i; - assert(c); - - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); - c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); - - t = c->write_data_length+length; - - if (c->write_data_alloc < t) - c->write_data = realloc(c->write_data, c->write_data_alloc = t); - - assert(c->write_data); - - i = c->write_data_length; - c->write_data_length += length; - - return c->write_data+i; -} - -/*** esound commands ***/ - -static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length) { - uint32_t ekey; - int *ok; - assert(length == (ESD_KEY_LEN + sizeof(uint32_t))); - - if (!c->authorized) { - if (memcmp(data, c->protocol->esd_key, ESD_KEY_LEN) != 0) { - fprintf(stderr, __FILE__": kicked client with invalid authorization key.\n"); - return -1; - } - - c->authorized = 1; - } - - ekey = *(uint32_t*)(data+ESD_KEY_LEN); - if (ekey == ESD_ENDIAN_KEY) - c->swap_byte_order = 0; - else if (ekey == ESD_SWAP_ENDIAN_KEY) - c->swap_byte_order = 1; - else { - fprintf(stderr, __FILE__": client sent invalid endian key\n"); - return -1; - } - - ok = connection_write(c, sizeof(int)); - assert(ok); - *ok = 1; - return 0; -} - -static int esd_proto_stream_play(struct connection *c, esd_proto_t request, const void *data, size_t length) { - char name[ESD_NAME_MAX]; - int format, rate; - struct pa_sink *sink; - struct pa_sample_spec ss; - size_t l; - assert(c && length == (sizeof(int)*2+ESD_NAME_MAX)); - - format = maybe_swap_endian_32(c->swap_byte_order, *(int*)data); - rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); - - ss.rate = rate; - ss.channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; - ss.format = ((format & ESD_MASK_BITS) == ESD_BITS16) ? PA_SAMPLE_S16NE : PA_SAMPLE_U8; - - if (!pa_sample_spec_valid(&ss)) - return -1; - - if (!(sink = get_output_sink(c->protocol))) - return -1; - - strncpy(name, data + sizeof(int)*2, sizeof(name)); - name[sizeof(name)-1] = 0; - - pa_client_rename(c->client, name); - - assert(!c->input_memblockq); - - l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); - c->input_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&ss), l/2, l/PLAYBACK_BUFFER_FRAGMENTS); - assert(c->input_memblockq); - pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2); - c->playback.fragment_size = l/10; - - assert(!c->sink_input); - c->sink_input = pa_sink_input_new(sink, name, &ss); - assert(c->sink_input); - - c->sink_input->owner = c->protocol->module; - c->sink_input->client = c->client; - c->sink_input->peek = sink_input_peek_cb; - c->sink_input->drop = sink_input_drop_cb; - c->sink_input->kill = sink_input_kill_cb; - c->sink_input->get_latency = sink_input_get_latency_cb; - c->sink_input->userdata = c; - - c->state = ESD_STREAMING_DATA; - - c->protocol->n_player++; - - return 0; -} - -static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length) { - char name[ESD_NAME_MAX]; - int format, rate; - struct pa_source *source; - struct pa_sample_spec ss; - size_t l; - assert(c && length == (sizeof(int)*2+ESD_NAME_MAX)); - - format = maybe_swap_endian_32(c->swap_byte_order, *(int*)data); - rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); - - ss.rate = rate; - ss.channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; - ss.format = ((format & ESD_MASK_BITS) == ESD_BITS16) ? PA_SAMPLE_S16NE : PA_SAMPLE_U8; - - if (!pa_sample_spec_valid(&ss)) - return -1; - - if (request == ESD_PROTO_STREAM_MON) { - struct pa_sink* sink; - - if (!(sink = get_output_sink(c->protocol))) - return -1; - - if (!(source = sink->monitor_source)) - return -1; - } else { - assert(request == ESD_PROTO_STREAM_REC); - - if (!(source = get_input_source(c->protocol))) - return -1; - } - - strncpy(name, data + sizeof(int)*2, sizeof(name)); - name[sizeof(name)-1] = 0; - - pa_client_rename(c->client, name); - - assert(!c->output_memblockq); - - l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); - c->output_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&ss), 0, 0); - assert(c->output_memblockq); - pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); - - assert(!c->source_output); - c->source_output = pa_source_output_new(source, name, &ss); - assert(c->source_output); - - c->source_output->owner = c->protocol->module; - c->source_output->client = c->client; - c->source_output->push = source_output_push_cb; - c->source_output->kill = source_output_kill_cb; - c->source_output->userdata = c; - - c->state = ESD_STREAMING_DATA; - - c->protocol->n_player++; - - return 0; -} - -static int esd_proto_get_latency(struct connection *c, esd_proto_t request, const void *data, size_t length) { - struct pa_sink *sink; - int latency, *lag; - assert(c && !data && length == 0); - - if (!(sink = get_output_sink(c->protocol))) - latency = 0; - else { - float usec = pa_sink_get_latency(sink); - usec += PLAYBACK_BUFFER_SECONDS*1000000; /* A better estimation would be a good idea! */ - latency = (int) ((usec*44100)/1000000); - } - - lag = connection_write(c, sizeof(int)); - assert(lag); - *lag = c->swap_byte_order ? swap_endian_32(latency) : latency; - return 0; -} - -static int esd_proto_server_info(struct connection *c, esd_proto_t request, const void *data, size_t length) { - int rate = 44100, format = ESD_STEREO|ESD_BITS16; - int *response; - struct pa_sink *sink; - assert(c && data && length == sizeof(int)); - - if ((sink = get_output_sink(c->protocol))) { - rate = sink->sample_spec.rate; - format = (sink->sample_spec.format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16; - format |= (sink->sample_spec.channels >= 2) ? ESD_STEREO : ESD_MONO; - } - - response = connection_write(c, sizeof(int)*3); - assert(response); - *(response++) = 0; - *(response++) = maybe_swap_endian_32(c->swap_byte_order, rate); - *(response++) = maybe_swap_endian_32(c->swap_byte_order, format); - return 0; -} - -static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length) { - void *response; - size_t t, k, s; - struct connection *conn; - size_t index = PA_IDXSET_INVALID; - assert(c && data && length == sizeof(int)); - - if (esd_proto_server_info(c, request, data, length) < 0) - return -1; - - k = sizeof(int)*5+ESD_NAME_MAX; - s = sizeof(int)*6+ESD_NAME_MAX; - response = connection_write(c, (t = s+k*(c->protocol->n_player+1))); - assert(k); - - for (conn = pa_idxset_first(c->protocol->connections, &index); conn; conn = pa_idxset_next(c->protocol->connections, &index)) { - int format = ESD_BITS16 | ESD_STEREO, rate = 44100, volume = 0xFF; - - if (conn->state != ESD_STREAMING_DATA) - continue; - - assert(t >= s+k+k); - - if (conn->sink_input) { - rate = conn->sink_input->sample_spec.rate; - volume = (conn->sink_input->volume*0xFF)/0x100; - format = (conn->sink_input->sample_spec.format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16; - format |= (conn->sink_input->sample_spec.channels >= 2) ? ESD_STEREO : ESD_MONO; - } - - /* id */ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (int) conn->index); - response += sizeof(int); - - /* name */ - assert(conn->client); - strncpy(response, conn->client->name, ESD_NAME_MAX); - response += ESD_NAME_MAX; - - /* rate */ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, rate); - response += sizeof(int); - - /* left */ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, volume); - response += sizeof(int); - - /*right*/ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, volume); - response += sizeof(int); - - /*format*/ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, format); - response += sizeof(int); - - t-= k; - } - - assert(t == s+k); - memset(response, 0, t); - return 0; -} - -static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const void *data, size_t length) { - int *ok; - uint32_t index, volume; - struct connection *conn; - assert(c && data && length == sizeof(int)*3); - - index = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *(int*)data); - volume = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); - volume = (volume*0x100)/0xFF; - - ok = connection_write(c, sizeof(int)); - assert(ok); - - if ((conn = pa_idxset_get_by_index(c->protocol->connections, index))) { - assert(conn->sink_input); - conn->sink_input->volume = volume; - *ok = 1; - } else - *ok = 0; - - return 0; -} - -/*** client callbacks ***/ - -static void client_kill_cb(struct pa_client *c) { - assert(c && c->userdata); - connection_free(c->userdata); -} - -/*** pa_iochannel callbacks ***/ - -static int do_read(struct connection *c) { - assert(c && c->io); - - if (c->state == ESD_NEXT_REQUEST) { - ssize_t r; - assert(c->read_data_length < sizeof(c->request)); - - if ((r = pa_iochannel_read(c->io, ((void*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { - fprintf(stderr, "protocol-esound.c: read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); - return -1; - } - - if ((c->read_data_length+= r) >= sizeof(c->request)) { - struct proto_handler *handler; - - if (c->swap_byte_order) - c->request = swap_endian_32(c->request); - - if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) { - fprintf(stderr, "protocol-esound.c: recieved invalid request.\n"); - return -1; - } - - handler = proto_map+c->request; - - if (!handler->proc) { - fprintf(stderr, "protocol-sound.c: recieved unimplemented request.\n"); - return -1; - } - - if (handler->data_length == 0) { - c->read_data_length = 0; - - if (handler->proc(c, c->request, NULL, 0) < 0) - return -1; - - } else { - if (c->read_data_alloc < handler->data_length) - c->read_data = realloc(c->read_data, c->read_data_alloc = handler->data_length); - assert(c->read_data); - - c->state = ESD_NEEDS_REQDATA; - c->read_data_length = 0; - } - } - - } else if (c->state == ESD_NEEDS_REQDATA) { - ssize_t r; - struct proto_handler *handler = proto_map+c->request; - - assert(handler->proc); - - assert(c->read_data && c->read_data_length < handler->data_length); - - if ((r = pa_iochannel_read(c->io, c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { - fprintf(stderr, "protocol-esound.c: read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); - return -1; - } - - if ((c->read_data_length+= r) >= handler->data_length) { - size_t l = c->read_data_length; - assert(handler->proc); - - c->state = ESD_NEXT_REQUEST; - c->read_data_length = 0; - - if (handler->proc(c, c->request, c->read_data, l) < 0) - return -1; - } - } else if (c->state == ESD_STREAMING_DATA && c->sink_input) { - struct pa_memchunk chunk; - ssize_t r; - size_t l; - - assert(c->input_memblockq); - - if (!(l = pa_memblockq_missing(c->input_memblockq))) - return 0; - - if (l > c->playback.fragment_size) - l = c->playback.fragment_size; - - if (c->playback.current_memblock) - if (c->playback.current_memblock->length - c->playback.memblock_index < l) { - pa_memblock_unref(c->playback.current_memblock); - c->playback.current_memblock = NULL; - c->playback.memblock_index = 0; - } - - if (!c->playback.current_memblock) { - c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2); - assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); - c->playback.memblock_index = 0; - } - - if ((r = pa_iochannel_read(c->io, c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { - fprintf(stderr, __FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); - return -1; - } - - chunk.memblock = c->playback.current_memblock; - chunk.index = c->playback.memblock_index; - chunk.length = r; - assert(chunk.memblock); - - c->playback.memblock_index += r; - - assert(c->input_memblockq); - pa_memblockq_push_align(c->input_memblockq, &chunk, 0); - assert(c->sink_input); - pa_sink_notify(c->sink_input->sink); - - } - - return 0; -} - -static int do_write(struct connection *c) { - assert(c && c->io); - - if (c->write_data_length) { - ssize_t r; - - assert(c->write_data_index < c->write_data_length); - if ((r = pa_iochannel_write(c->io, c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { - fprintf(stderr, __FILE__": write() failed: %s\n", strerror(errno)); - return -1; - } - - if ((c->write_data_index +=r) >= c->write_data_length) - c->write_data_length = c->write_data_index = 0; - - } else if (c->state == ESD_STREAMING_DATA && c->source_output) { - struct pa_memchunk chunk; - ssize_t r; - - assert(c->output_memblockq); - if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) - return 0; - - assert(chunk.memblock && chunk.length); - - if ((r = pa_iochannel_write(c->io, chunk.memblock->data+chunk.index, chunk.length)) < 0) { - pa_memblock_unref(chunk.memblock); - fprintf(stderr, __FILE__": write(): %s\n", strerror(errno)); - return -1; - } - - pa_memblockq_drop(c->output_memblockq, r); - pa_memblock_unref(chunk.memblock); - } - - return 0; -} - -static void do_work(struct connection *c) { - assert(c); - - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); - c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 0); - - if (pa_iochannel_is_hungup(c->io)) - goto fail; - - if (pa_iochannel_is_writable(c->io)) - if (do_write(c) < 0) - goto fail; - - if (pa_iochannel_is_readable(c->io)) - if (do_read(c) < 0) - goto fail; - - return; - -fail: - connection_free(c); -} - -static void io_callback(struct pa_iochannel*io, void *userdata) { - struct connection *c = userdata; - assert(io && c && c->io == io); - - do_work(c); -} - -/*** fixed callback ***/ - -static void fixed_callback(struct pa_mainloop_api*a, void *id, void *userdata) { - struct connection *c = userdata; - assert(a && c && c->fixed_source == id); - - do_work(c); -} - -/*** sink_input callbacks ***/ - -static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk) { - struct connection*c; - assert(i && i->userdata && chunk); - c = i->userdata; - - if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) - return -1; - - return 0; -} - -static void sink_input_drop_cb(struct pa_sink_input *i, size_t length) { - struct connection*c = i->userdata; - assert(i && c && length); - - pa_memblockq_drop(c->input_memblockq, length); - - /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); - c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); -} - -static void sink_input_kill_cb(struct pa_sink_input *i) { - assert(i && i->userdata); - connection_free((struct connection *) i->userdata); -} - - -static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { - struct connection*c = i->userdata; - assert(i && c); - return pa_samples_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); -} - -/*** source_output callbacks ***/ - -static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk) { - struct connection *c = o->userdata; - assert(o && c && chunk); - - pa_memblockq_push(c->output_memblockq, chunk, 0); - - /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); - c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); -} - -static void source_output_kill_cb(struct pa_source_output *o) { - assert(o && o->userdata); - connection_free((struct connection *) o->userdata); -} - -/*** socket server callback ***/ - -static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { - struct connection *c; - char cname[256]; - assert(s && io && userdata); - - c = malloc(sizeof(struct connection)); - assert(c); - c->protocol = userdata; - c->io = io; - pa_iochannel_set_callback(c->io, io_callback, c); - - pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); - assert(c->protocol->core); - c->client = pa_client_new(c->protocol->core, "ESOUND", cname); - assert(c->client); - c->client->owner = c->protocol->module; - c->client->kill = client_kill_cb; - c->client->userdata = c; - - c->authorized = c->protocol->public; - c->swap_byte_order = 0; - - c->read_data_length = 0; - c->read_data = malloc(c->read_data_alloc = proto_map[ESD_PROTO_CONNECT].data_length); - assert(c->read_data); - - c->write_data_length = c->write_data_index = c->write_data_alloc = 0; - c->write_data = NULL; - - c->state = ESD_NEEDS_REQDATA; - c->request = ESD_PROTO_CONNECT; - - c->sink_input = NULL; - c->input_memblockq = NULL; - - c->source_output = NULL; - c->output_memblockq = NULL; - - c->playback.current_memblock = NULL; - c->playback.memblock_index = 0; - c->playback.fragment_size = 0; - - c->fixed_source = c->protocol->core->mainloop->source_fixed(c->protocol->core->mainloop, fixed_callback, c); - assert(c->fixed_source); - c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 0); - - pa_idxset_put(c->protocol->connections, c, &c->index); -} - -/*** entry points ***/ - -struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { - uint32_t source_index, sink_index; - struct pa_protocol_esound *p; - assert(core && server && ma); - - if (pa_modargs_get_source_index(ma, core, &source_index) < 0) { - fprintf(stderr, __FILE__": source does not exist.\n"); - return NULL; - } - - if (pa_modargs_get_sink_index(ma, core, &sink_index) < 0) { - fprintf(stderr, __FILE__": sink does not exist.\n"); - return NULL; - } - p = malloc(sizeof(struct pa_protocol_esound)); - assert(p); - - if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", DEFAULT_COOKIE_FILE), p->esd_key, sizeof(p->esd_key)) < 0) { - free(p); - return NULL; - } - - p->module = m; - p->public = 0; - p->server = server; - pa_socket_server_set_callback(p->server, on_connection, p); - p->core = core; - p->connections = pa_idxset_new(NULL, NULL); - assert(p->connections); - p->sink_index = sink_index; - p->source_index = source_index; - p->n_player = 0; - - return p; -} - -void pa_protocol_esound_free(struct pa_protocol_esound *p) { - struct connection *c; - assert(p); - - while ((c = pa_idxset_first(p->connections, NULL))) - connection_free(c); - - pa_idxset_free(p->connections, NULL, NULL); - pa_socket_server_free(p->server); - free(p); -} diff --git a/src/protocol-esound.h b/src/protocol-esound.h deleted file mode 100644 index b2bdd31b..00000000 --- a/src/protocol-esound.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef fooprotocolesoundhfoo -#define fooprotocolesoundhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "core.h" -#include "socket-server.h" -#include "module.h" -#include "modargs.h" - -struct pa_protocol_esound; - -struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma); -void pa_protocol_esound_free(struct pa_protocol_esound *p); - -#endif diff --git a/src/protocol-native.c b/src/protocol-native.c deleted file mode 100644 index 83c910d1..00000000 --- a/src/protocol-native.c +++ /dev/null @@ -1,863 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "protocol-native.h" -#include "native-common.h" -#include "packet.h" -#include "client.h" -#include "source-output.h" -#include "sink-input.h" -#include "pstream.h" -#include "tagstruct.h" -#include "pdispatch.h" -#include "pstream-util.h" -#include "authkey.h" -#include "namereg.h" - -struct connection; -struct pa_protocol_native; - -struct record_stream { - struct connection *connection; - uint32_t index; - struct pa_source_output *source_output; - struct pa_memblockq *memblockq; - size_t fragment_size; -}; - -struct playback_stream { - struct connection *connection; - uint32_t index; - struct pa_sink_input *sink_input; - struct pa_memblockq *memblockq; - size_t requested_bytes; - int drain_request; - uint32_t drain_tag; -}; - -struct connection { - int authorized; - struct pa_protocol_native *protocol; - struct pa_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; - struct pa_idxset *record_streams, *playback_streams; - uint32_t rrobin_index; -}; - -struct pa_protocol_native { - struct pa_module *module; - int public; - struct pa_core *core; - struct pa_socket_server *server; - struct pa_idxset *connections; - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; -}; - -static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk); -static void sink_input_drop_cb(struct pa_sink_input *i, size_t length); -static void sink_input_kill_cb(struct pa_sink_input *i); -static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i); - -static void request_bytes(struct playback_stream*s); - -static void source_output_kill_cb(struct pa_source_output *o); -static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk); - -static void command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_delete_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_delete_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_TIMEOUT] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { command_create_playback_stream }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { command_delete_playback_stream }, - [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = { command_drain_playback_stream }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { command_create_record_stream }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { command_delete_record_stream }, - [PA_COMMAND_AUTH] = { command_auth }, - [PA_COMMAND_REQUEST] = { NULL }, - [PA_COMMAND_EXIT] = { command_exit }, - [PA_COMMAND_SET_NAME] = { command_set_name }, - [PA_COMMAND_LOOKUP_SINK] = { command_lookup }, - [PA_COMMAND_LOOKUP_SOURCE] = { command_lookup }, - [PA_COMMAND_STAT] = { command_stat }, - [PA_COMMAND_GET_PLAYBACK_LATENCY] = { command_get_playback_latency }, -}; - -/* structure management */ - -static struct record_stream* record_stream_new(struct connection *c, struct pa_source *source, struct pa_sample_spec *ss, const char *name, size_t maxlength, size_t fragment_size) { - struct record_stream *s; - struct pa_source_output *source_output; - size_t base; - assert(c && source && ss && name && maxlength); - - if (!(source_output = pa_source_output_new(source, name, ss))) - return NULL; - - s = malloc(sizeof(struct record_stream)); - assert(s); - s->connection = c; - s->source_output = source_output; - s->source_output->push = source_output_push_cb; - s->source_output->kill = source_output_kill_cb; - s->source_output->userdata = s; - s->source_output->owner = c->protocol->module; - s->source_output->client = c->client; - - s->memblockq = pa_memblockq_new(maxlength, 0, base = pa_sample_size(ss), 0, 0); - assert(s->memblockq); - - s->fragment_size = (fragment_size/base)*base; - if (!s->fragment_size) - s->fragment_size = base; - - pa_idxset_put(c->record_streams, s, &s->index); - return s; -} - -static void record_stream_free(struct record_stream* r) { - assert(r && r->connection); - - pa_idxset_remove_by_data(r->connection->record_streams, r, NULL); - pa_source_output_free(r->source_output); - pa_memblockq_free(r->memblockq); - free(r); -} - -static struct playback_stream* playback_stream_new(struct connection *c, struct pa_sink *sink, struct pa_sample_spec *ss, const char *name, - size_t maxlength, - size_t tlength, - size_t prebuf, - size_t minreq) { - struct playback_stream *s; - struct pa_sink_input *sink_input; - assert(c && sink && ss && name && maxlength); - - if (!(sink_input = pa_sink_input_new(sink, name, ss))) - return NULL; - - s = malloc(sizeof(struct playback_stream)); - assert (s); - s->connection = c; - s->sink_input = sink_input; - - s->sink_input->peek = sink_input_peek_cb; - s->sink_input->drop = sink_input_drop_cb; - s->sink_input->kill = sink_input_kill_cb; - s->sink_input->get_latency = sink_input_get_latency_cb; - s->sink_input->userdata = s; - s->sink_input->owner = c->protocol->module; - s->sink_input->client = c->client; - - s->memblockq = pa_memblockq_new(maxlength, tlength, pa_sample_size(ss), prebuf, minreq); - assert(s->memblockq); - - s->requested_bytes = 0; - s->drain_request = 0; - - pa_idxset_put(c->playback_streams, s, &s->index); - return s; -} - -static void playback_stream_free(struct playback_stream* p) { - assert(p && p->connection); - - if (p->drain_request) - pa_pstream_send_error(p->connection->pstream, p->drain_tag, PA_ERROR_NOENTITY); - - pa_idxset_remove_by_data(p->connection->playback_streams, p, NULL); - pa_sink_input_free(p->sink_input); - pa_memblockq_free(p->memblockq); - free(p); -} - -static void connection_free(struct connection *c) { - struct record_stream *r; - struct playback_stream *p; - assert(c && c->protocol); - - pa_idxset_remove_by_data(c->protocol->connections, c, NULL); - while ((r = pa_idxset_first(c->record_streams, NULL))) - record_stream_free(r); - pa_idxset_free(c->record_streams, NULL, NULL); - - while ((p = pa_idxset_first(c->playback_streams, NULL))) - playback_stream_free(p); - pa_idxset_free(c->playback_streams, NULL, NULL); - - pa_pdispatch_free(c->pdispatch); - pa_pstream_free(c->pstream); - pa_client_free(c->client); - free(c); -} - -static void request_bytes(struct playback_stream *s) { - struct pa_tagstruct *t; - size_t l; - assert(s); - - if (!(l = pa_memblockq_missing(s->memblockq))) - return; - - if (l <= s->requested_bytes) - return; - - l -= s->requested_bytes; - - if (l < pa_memblockq_get_minreq(s->memblockq)) - return; - - s->requested_bytes += l; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REQUEST); - pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ - pa_tagstruct_putu32(t, s->index); - pa_tagstruct_putu32(t, l); - pa_pstream_send_tagstruct(s->connection->pstream, t); - - /*fprintf(stderr, "Requesting %u bytes\n", l);*/ -} - -static void send_memblock(struct connection *c) { - uint32_t start; - struct record_stream *r; - - start = PA_IDXSET_INVALID; - for (;;) { - struct pa_memchunk chunk; - - if (!(r = pa_idxset_rrobin(c->record_streams, &c->rrobin_index))) - return; - - if (start == PA_IDXSET_INVALID) - start = c->rrobin_index; - else if (start == c->rrobin_index) - return; - - if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) { - if (chunk.length > r->fragment_size) - chunk.length = r->fragment_size; - - pa_pstream_send_memblock(c->pstream, r->index, 0, &chunk); - pa_memblockq_drop(r->memblockq, chunk.length); - pa_memblock_unref(chunk.memblock); - - return; - } - } -} - -static void send_playback_stream_killed(struct playback_stream *p) { - struct pa_tagstruct *t; - assert(p); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED); - pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ - pa_tagstruct_putu32(t, p->index); - pa_pstream_send_tagstruct(p->connection->pstream, t); -} - -static void send_record_stream_killed(struct record_stream *r) { - struct pa_tagstruct *t; - assert(r); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED); - pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ - pa_tagstruct_putu32(t, r->index); - pa_pstream_send_tagstruct(r->connection->pstream, t); -} - - -/*** sinkinput callbacks ***/ - -static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk) { - struct playback_stream *s; - assert(i && i->userdata && chunk); - s = i->userdata; - - if (pa_memblockq_peek(s->memblockq, chunk) < 0) - return -1; - - return 0; -} - -static void sink_input_drop_cb(struct pa_sink_input *i, size_t length) { - struct playback_stream *s; - assert(i && i->userdata && length); - s = i->userdata; - - pa_memblockq_drop(s->memblockq, length); - request_bytes(s); - - if (s->drain_request && !pa_memblockq_is_readable(s->memblockq)) { - pa_pstream_send_simple_ack(s->connection->pstream, s->drain_tag); - s->drain_request = 0; - } -} - -static void sink_input_kill_cb(struct pa_sink_input *i) { - assert(i && i->userdata); - send_playback_stream_killed((struct playback_stream *) i->userdata); - playback_stream_free((struct playback_stream *) i->userdata); -} - -static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { - struct playback_stream *s; - assert(i && i->userdata); - s = i->userdata; - - return pa_samples_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec); -} - -/*** source_output callbacks ***/ - -static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk) { - struct record_stream *s; - assert(o && o->userdata && chunk); - s = o->userdata; - - pa_memblockq_push(s->memblockq, chunk, 0); - if (!pa_pstream_is_pending(s->connection->pstream)) - send_memblock(s->connection); -} - -static void source_output_kill_cb(struct pa_source_output *o) { - assert(o && o->userdata); - send_record_stream_killed((struct record_stream *) o->userdata); - record_stream_free((struct record_stream *) o->userdata); -} - -/*** pdispatch callbacks ***/ - -static void protocol_error(struct connection *c) { - fprintf(stderr, __FILE__": protocol error, kicking client\n"); - connection_free(c); -} - -static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - struct playback_stream *s; - size_t maxlength, tlength, prebuf, minreq; - uint32_t sink_index; - const char *name; - struct pa_sample_spec ss; - struct pa_tagstruct *reply; - struct pa_sink *sink; - assert(c && t && c->protocol && c->protocol->core); - - if (pa_tagstruct_gets(t, &name) < 0 || - pa_tagstruct_get_sample_spec(t, &ss) < 0 || - pa_tagstruct_getu32(t, &sink_index) < 0 || - pa_tagstruct_getu32(t, &maxlength) < 0 || - pa_tagstruct_getu32(t, &tlength) < 0 || - pa_tagstruct_getu32(t, &prebuf) < 0 || - pa_tagstruct_getu32(t, &minreq) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (sink_index == (uint32_t) -1) - sink = pa_sink_get_default(c->protocol->core); - else - sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); - - if (!sink) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - if (!(s = playback_stream_new(c, sink, &ss, name, maxlength, tlength, prebuf, minreq))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); - return; - } - - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - pa_tagstruct_putu32(reply, s->index); - assert(s->sink_input); - pa_tagstruct_putu32(reply, s->sink_input->index); - pa_pstream_send_tagstruct(c->pstream, reply); - request_bytes(s); -} - -static void command_delete_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t channel; - struct playback_stream *s; - assert(c && t); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->playback_streams, channel))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); - return; - } - - playback_stream_free(s); - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - struct record_stream *s; - size_t maxlength, fragment_size; - uint32_t source_index; - const char *name; - struct pa_sample_spec ss; - struct pa_tagstruct *reply; - struct pa_source *source; - assert(c && t && c->protocol && c->protocol->core); - - if (pa_tagstruct_gets(t, &name) < 0 || - pa_tagstruct_get_sample_spec(t, &ss) < 0 || - pa_tagstruct_getu32(t, &source_index) < 0 || - pa_tagstruct_getu32(t, &maxlength) < 0 || - pa_tagstruct_getu32(t, &fragment_size) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (source_index == (uint32_t) -1) - source = pa_source_get_default(c->protocol->core); - else - source = pa_idxset_get_by_index(c->protocol->core->sources, source_index); - - if (!source) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - if (!(s = record_stream_new(c, source, &ss, name, maxlength, fragment_size))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); - return; - } - - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - pa_tagstruct_putu32(reply, s->index); - assert(s->source_output); - pa_tagstruct_putu32(reply, s->source_output->index); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_delete_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t channel; - struct record_stream *s; - assert(c && t); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); - return; - } - - record_stream_free(s); - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - assert(c && t); - - if (!pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop); - c->protocol->core->mainloop->quit(c->protocol->core->mainloop, 0); - pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */ - return; -} - -static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - const void*cookie; - assert(c && t); - - if (pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) != 0) { - fprintf(stderr, "protocol-native.c: Denied access to client with invalid authorization key.\n"); - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - c->authorized = 1; - pa_pstream_send_simple_ack(c->pstream, tag); - return; -} - -static void command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - const char *name; - assert(c && t); - - if (pa_tagstruct_gets(t, &name) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - pa_client_rename(c->client, name); - pa_pstream_send_simple_ack(c->pstream, tag); - return; -} - -static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - const char *name; - uint32_t index = PA_IDXSET_INVALID; - assert(c && t); - - if (pa_tagstruct_gets(t, &name) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (command == PA_COMMAND_LOOKUP_SINK) { - struct pa_sink *sink; - if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK))) - index = sink->index; - } else { - struct pa_source *source; - assert(command == PA_COMMAND_LOOKUP_SOURCE); - if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE))) - index = source->index; - } - - if (index == PA_IDXSET_INVALID) - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - else { - struct pa_tagstruct *reply; - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - pa_tagstruct_putu32(reply, index); - pa_pstream_send_tagstruct(c->pstream, reply); - } -} - -static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t index; - struct playback_stream *s; - assert(c && t); - - if (pa_tagstruct_getu32(t, &index) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->playback_streams, index))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - s->drain_request = 0; - - if (!pa_memblockq_is_readable(s->memblockq)) - pa_pstream_send_simple_ack(c->pstream, tag); - else { - s->drain_request = 1; - s->drain_tag = tag; - } -} - -static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - assert(c && t); - struct pa_tagstruct *reply; - - if (!pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - pa_tagstruct_putu32(reply, pa_memblock_get_count()); - pa_tagstruct_putu32(reply, pa_memblock_get_total()); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - assert(c && t); - struct pa_tagstruct *reply; - struct playback_stream *s; - uint32_t index, latency; - - if (pa_tagstruct_getu32(t, &index) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->playback_streams, index))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - latency = pa_sink_input_get_latency(s->sink_input); - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - pa_tagstruct_putu32(reply, latency); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -/*** pstream callbacks ***/ - -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { - struct connection *c = userdata; - assert(p && packet && packet->data && c); - - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - fprintf(stderr, "protocol-native: invalid packet.\n"); - connection_free(c); - } -} - -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { - struct connection *c = userdata; - struct playback_stream *stream; - assert(p && chunk && userdata); - - if (!(stream = pa_idxset_get_by_index(c->playback_streams, channel))) { - fprintf(stderr, "protocol-native: client sent block for invalid stream.\n"); - connection_free(c); - return; - } - - if (chunk->length >= stream->requested_bytes) - stream->requested_bytes = 0; - else - stream->requested_bytes -= chunk->length; - - pa_memblockq_push_align(stream->memblockq, chunk, delta); - assert(stream->sink_input); - pa_sink_notify(stream->sink_input->sink); - - /*fprintf(stderr, "Recieved %u bytes.\n", chunk->length);*/ -} - -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { - struct connection *c = userdata; - assert(p && c); - connection_free(c); - - fprintf(stderr, "protocol-native: connection died.\n"); -} - - -static void pstream_drain_callback(struct pa_pstream *p, void *userdata) { - struct connection *c = userdata; - assert(p && c); - - send_memblock(c); -} - -/*** client callbacks ***/ - -static void client_kill_cb(struct pa_client *c) { - assert(c && c->userdata); - connection_free(c->userdata); -} - -/*** socket server callbacks ***/ - -static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { - struct pa_protocol_native *p = userdata; - struct connection *c; - assert(s && io && p); - - c = malloc(sizeof(struct connection)); - assert(c); - c->authorized = p->public; - c->protocol = p; - assert(p->core); - c->client = pa_client_new(p->core, "NATIVE", "Client"); - assert(c->client); - c->client->kill = client_kill_cb; - c->client->userdata = c; - c->client->owner = p->module; - - c->pstream = pa_pstream_new(p->core->mainloop, io); - assert(c->pstream); - - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - - c->pdispatch = pa_pdispatch_new(p->core->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); - - c->record_streams = pa_idxset_new(NULL, NULL); - c->playback_streams = pa_idxset_new(NULL, NULL); - assert(c->record_streams && c->playback_streams); - - c->rrobin_index = PA_IDXSET_INVALID; - - pa_idxset_put(p->connections, c, NULL); -} - -/*** module entry points ***/ - -struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { - struct pa_protocol_native *p; - uint32_t public; - assert(core && server && ma); - - if (pa_modargs_get_value_u32(ma, "public", &public) < 0) { - fprintf(stderr, __FILE__": public= expects numeric argument.\n"); - return NULL; - } - - p = malloc(sizeof(struct pa_protocol_native)); - assert(p); - - if (pa_authkey_load_from_home(pa_modargs_get_value(ma, "cookie", PA_NATIVE_COOKIE_FILE), p->auth_cookie, sizeof(p->auth_cookie)) < 0) { - free(p); - return NULL; - } - - p->module = m; - p->public = public; - p->server = server; - p->core = core; - p->connections = pa_idxset_new(NULL, NULL); - assert(p->connections); - - pa_socket_server_set_callback(p->server, on_connection, p); - - return p; -} - -void pa_protocol_native_free(struct pa_protocol_native *p) { - struct connection *c; - assert(p); - - while ((c = pa_idxset_first(p->connections, NULL))) - connection_free(c); - pa_idxset_free(p->connections, NULL, NULL); - pa_socket_server_free(p->server); - free(p); -} diff --git a/src/protocol-native.h b/src/protocol-native.h deleted file mode 100644 index 3d9fdde1..00000000 --- a/src/protocol-native.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef fooprotocolnativehfoo -#define fooprotocolnativehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "core.h" -#include "socket-server.h" -#include "module.h" -#include "modargs.h" - -struct pa_protocol_native; - -struct pa_protocol_native* pa_protocol_native_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma); -void pa_protocol_native_free(struct pa_protocol_native *n); - -#endif diff --git a/src/protocol-simple.c b/src/protocol-simple.c deleted file mode 100644 index 3a52e311..00000000 --- a/src/protocol-simple.c +++ /dev/null @@ -1,444 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "sink-input.h" -#include "source-output.h" -#include "protocol-simple.h" -#include "client.h" -#include "sample-util.h" -#include "namereg.h" - -struct connection { - struct pa_protocol_simple *protocol; - struct pa_iochannel *io; - struct pa_sink_input *sink_input; - struct pa_source_output *source_output; - struct pa_client *client; - struct pa_memblockq *input_memblockq, *output_memblockq; - void *fixed_source; - - struct { - struct pa_memblock *current_memblock; - size_t memblock_index, fragment_size; - } playback; -}; - -struct pa_protocol_simple { - struct pa_module *module; - struct pa_core *core; - struct pa_socket_server*server; - struct pa_idxset *connections; - enum { - RECORD = 1, - PLAYBACK = 2, - DUPLEX = 3 - } mode; - struct pa_sample_spec sample_spec; - uint32_t sink_index, source_index; -}; - -#define PLAYBACK_BUFFER_SECONDS (.5) -#define PLAYBACK_BUFFER_FRAGMENTS (10) -#define RECORD_BUFFER_SECONDS (5) -#define RECORD_BUFFER_FRAGMENTS (100) - -static void connection_free(struct connection *c) { - assert(c); - - pa_idxset_remove_by_data(c->protocol->connections, c, NULL); - - if (c->playback.current_memblock) - pa_memblock_unref(c->playback.current_memblock); - if (c->sink_input) - pa_sink_input_free(c->sink_input); - if (c->source_output) - pa_source_output_free(c->source_output); - if (c->client) - pa_client_free(c->client); - if (c->io) - pa_iochannel_free(c->io); - if (c->input_memblockq) - pa_memblockq_free(c->input_memblockq); - if (c->output_memblockq) - pa_memblockq_free(c->output_memblockq); - if (c->fixed_source) - c->protocol->core->mainloop->cancel_fixed(c->protocol->core->mainloop, c->fixed_source); - free(c); -} - -static int do_read(struct connection *c) { - struct pa_memchunk chunk; - ssize_t r; - size_t l; - - if (!c->sink_input || !(l = pa_memblockq_missing(c->input_memblockq))) - return 0; - - if (l > c->playback.fragment_size) - l = c->playback.fragment_size; - - if (c->playback.current_memblock) - if (c->playback.current_memblock->length - c->playback.memblock_index < l) { - pa_memblock_unref(c->playback.current_memblock); - c->playback.current_memblock = NULL; - c->playback.memblock_index = 0; - } - - if (!c->playback.current_memblock) { - c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2); - assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); - c->playback.memblock_index = 0; - } - - if ((r = pa_iochannel_read(c->io, c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { - fprintf(stderr, __FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); - return -1; - } - - chunk.memblock = c->playback.current_memblock; - chunk.index = c->playback.memblock_index; - chunk.length = r; - assert(chunk.memblock); - - c->playback.memblock_index += r; - - assert(c->input_memblockq); - pa_memblockq_push_align(c->input_memblockq, &chunk, 0); - assert(c->sink_input); - pa_sink_notify(c->sink_input->sink); - - return 0; -} - -static int do_write(struct connection *c) { - struct pa_memchunk chunk; - ssize_t r; - - if (!c->source_output) - return 0; - - assert(c->output_memblockq); - if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) - return 0; - - assert(chunk.memblock && chunk.length); - - if ((r = pa_iochannel_write(c->io, chunk.memblock->data+chunk.index, chunk.length)) < 0) { - pa_memblock_unref(chunk.memblock); - fprintf(stderr, "write(): %s\n", strerror(errno)); - return -1; - } - - pa_memblockq_drop(c->output_memblockq, r); - pa_memblock_unref(chunk.memblock); - - return 0; -} - - -static void do_work(struct connection *c) { - assert(c); - - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); - c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 0); - - if (pa_iochannel_is_hungup(c->io)) - goto fail; - - if (pa_iochannel_is_writable(c->io)) - if (do_write(c) < 0) - goto fail; - - if (pa_iochannel_is_readable(c->io)) - if (do_read(c) < 0) - goto fail; - - return; - -fail: - connection_free(c); -} - -/*** sink_input callbacks ***/ - -static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk) { - struct connection*c; - assert(i && i->userdata && chunk); - c = i->userdata; - - if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) - return -1; - - return 0; -} - -static void sink_input_drop_cb(struct pa_sink_input *i, size_t length) { - struct connection*c = i->userdata; - assert(i && c && length); - - pa_memblockq_drop(c->input_memblockq, length); - - /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); - c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); -} - -static void sink_input_kill_cb(struct pa_sink_input *i) { - assert(i && i->userdata); - connection_free((struct connection *) i->userdata); -} - - -static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { - struct connection*c = i->userdata; - assert(i && c); - return pa_samples_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); -} - -/*** source_output callbacks ***/ - -static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk) { - struct connection *c = o->userdata; - assert(o && c && chunk); - - pa_memblockq_push(c->output_memblockq, chunk, 0); - - /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); - c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); -} - -static void source_output_kill_cb(struct pa_source_output *o) { - assert(o && o->userdata); - connection_free((struct connection *) o->userdata); -} - -/*** client callbacks ***/ - -static void client_kill_cb(struct pa_client *c) { - assert(c && c->userdata); - connection_free((struct connection *) c->userdata); -} - -/*** pa_iochannel callbacks ***/ - -static void io_callback(struct pa_iochannel*io, void *userdata) { - struct connection *c = userdata; - assert(io && c && c->io == io); - - do_work(c); -} - -/*** fixed callback ***/ - -static void fixed_callback(struct pa_mainloop_api*a, void *id, void *userdata) { - struct connection *c = userdata; - assert(a && c && c->fixed_source == id); - - do_work(c); -} - -/*** socket_server callbacks ***/ - -static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { - struct pa_protocol_simple *p = userdata; - struct connection *c = NULL; - char cname[256]; - assert(s && io && p); - - c = malloc(sizeof(struct connection)); - assert(c); - c->io = io; - c->sink_input = NULL; - c->source_output = NULL; - c->fixed_source = NULL; - c->input_memblockq = c->output_memblockq = NULL; - c->protocol = p; - c->playback.current_memblock = NULL; - c->playback.memblock_index = 0; - c->playback.fragment_size = 0; - - pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); - c->client = pa_client_new(p->core, "SIMPLE", cname); - assert(c->client); - c->client->owner = p->module; - c->client->kill = client_kill_cb; - c->client->userdata = c; - - if (p->mode & PLAYBACK) { - struct pa_sink *sink; - size_t l; - - if (!(sink = pa_idxset_get_by_index(p->core->sinks, p->sink_index))) - if (!(sink = pa_sink_get_default(p->core))) { - fprintf(stderr, "Failed to get sink.\n"); - goto fail; - } - - c->sink_input = pa_sink_input_new(sink, c->client->name, &p->sample_spec); - if (!c->sink_input) { - fprintf(stderr, "Failed to create sink input.\n"); - goto fail; - } - c->sink_input->owner = p->module; - c->sink_input->client = c->client; - - c->sink_input->peek = sink_input_peek_cb; - c->sink_input->drop = sink_input_drop_cb; - c->sink_input->kill = sink_input_kill_cb; - c->sink_input->get_latency = sink_input_get_latency_cb; - c->sink_input->userdata = c; - - l = (size_t) (pa_bytes_per_second(&p->sample_spec)*PLAYBACK_BUFFER_SECONDS); - c->input_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&p->sample_spec), l/2, l/PLAYBACK_BUFFER_FRAGMENTS); - assert(c->input_memblockq); - pa_iochannel_socket_set_rcvbuf(io, l/PLAYBACK_BUFFER_FRAGMENTS*5); - c->playback.fragment_size = l/10; - } - - if (p->mode & RECORD) { - struct pa_source *source; - size_t l; - - if (!(source = pa_idxset_get_by_index(p->core->sources, p->source_index))) - if (!(source = pa_source_get_default(p->core))) { - fprintf(stderr, "Failed to get source.\n"); - goto fail; - } - - c->source_output = pa_source_output_new(source, c->client->name, &p->sample_spec); - if (!c->source_output) { - fprintf(stderr, "Failed to create source output.\n"); - goto fail; - } - c->source_output->owner = p->module; - c->source_output->client = c->client; - - c->source_output->push = source_output_push_cb; - c->source_output->kill = source_output_kill_cb; - c->source_output->userdata = c; - - l = (size_t) (pa_bytes_per_second(&p->sample_spec)*RECORD_BUFFER_SECONDS); - c->output_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&p->sample_spec), 0, 0); - pa_iochannel_socket_set_sndbuf(io, l/RECORD_BUFFER_FRAGMENTS*2); - } - - pa_iochannel_set_callback(c->io, io_callback, c); - pa_idxset_put(p->connections, c, NULL); - - c->fixed_source = p->core->mainloop->source_fixed(p->core->mainloop, fixed_callback, c); - assert(c->fixed_source); - p->core->mainloop->enable_fixed(p->core->mainloop, c->fixed_source, 0); - - return; - -fail: - if (c) - connection_free(c); -} - -struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { - struct pa_protocol_simple* p = NULL; - uint32_t enable; - assert(core && server && ma); - - p = malloc(sizeof(struct pa_protocol_simple)); - assert(p); - memset(p, 0, sizeof(struct pa_protocol_simple)); - - p->module = m; - p->core = core; - p->server = server; - p->connections = pa_idxset_new(NULL, NULL); - - p->sample_spec = core->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &p->sample_spec) < 0) { - fprintf(stderr, "Failed to parse sample type specification.\n"); - goto fail; - } - - if (pa_modargs_get_source_index(ma, core, &p->source_index) < 0) { - fprintf(stderr, __FILE__": source does not exist.\n"); - goto fail; - } - - if (pa_modargs_get_sink_index(ma, core, &p->sink_index) < 0) { - fprintf(stderr, __FILE__": sink does not exist.\n"); - goto fail; - } - - enable = 0; - if (pa_modargs_get_value_u32(ma, "record", &enable) < 0) { - fprintf(stderr, __FILE__": record= expects a numeric argument.\n"); - goto fail; - } - p->mode = enable ? RECORD : 0; - - enable = 1; - if (pa_modargs_get_value_u32(ma, "playback", &enable) < 0) { - fprintf(stderr, __FILE__": playback= expects a numeric argument.\n"); - goto fail; - } - p->mode |= enable ? PLAYBACK : 0; - - if ((p->mode & (RECORD|PLAYBACK)) == 0) { - fprintf(stderr, __FILE__": neither playback nor recording enabled for protocol.\n"); - goto fail; - } - - pa_socket_server_set_callback(p->server, on_connection, p); - - return p; - -fail: - if (p) - pa_protocol_simple_free(p); - return NULL; -} - - -void pa_protocol_simple_free(struct pa_protocol_simple *p) { - struct connection *c; - assert(p); - - if (p->connections) { - while((c = pa_idxset_first(p->connections, NULL))) - connection_free(c); - - pa_idxset_free(p->connections, NULL, NULL); - } - - if (p->server) - pa_socket_server_free(p->server); - free(p); -} - diff --git a/src/protocol-simple.h b/src/protocol-simple.h deleted file mode 100644 index 0fc1e19d..00000000 --- a/src/protocol-simple.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef fooprotocolsimplehfoo -#define fooprotocolsimplehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "socket-server.h" -#include "module.h" -#include "core.h" -#include "modargs.h" - -struct pa_protocol_simple; - -struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma); -void pa_protocol_simple_free(struct pa_protocol_simple *n); - -#endif diff --git a/src/pstream-util.c b/src/pstream-util.c deleted file mode 100644 index 3957e643..00000000 --- a/src/pstream-util.c +++ /dev/null @@ -1,60 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "native-common.h" -#include "pstream-util.h" - -void pa_pstream_send_tagstruct(struct pa_pstream *p, struct pa_tagstruct *t) { - size_t length; - uint8_t *data; - struct pa_packet *packet; - assert(p && t); - - data = pa_tagstruct_free_data(t, &length); - assert(data && length); - packet = pa_packet_new_dynamic(data, length); - assert(packet); - pa_pstream_send_packet(p, packet); - pa_packet_unref(packet); -} - -void pa_pstream_send_error(struct pa_pstream *p, uint32_t tag, uint32_t error) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_ERROR); - pa_tagstruct_putu32(t, tag); - pa_tagstruct_putu32(t, error); - pa_pstream_send_tagstruct(p, t); -} - -void pa_pstream_send_simple_ack(struct pa_pstream *p, uint32_t tag) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REPLY); - pa_tagstruct_putu32(t, tag); - pa_pstream_send_tagstruct(p, t); -} diff --git a/src/pstream-util.h b/src/pstream-util.h deleted file mode 100644 index b3c89eb0..00000000 --- a/src/pstream-util.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef foopstreamutilhfoo -#define foopstreamutilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include "pstream.h" -#include "tagstruct.h" - -/* The tagstruct is freed!*/ -void pa_pstream_send_tagstruct(struct pa_pstream *p, struct pa_tagstruct *t); - -void pa_pstream_send_error(struct pa_pstream *p, uint32_t tag, uint32_t error); -void pa_pstream_send_simple_ack(struct pa_pstream *p, uint32_t tag); - -#endif diff --git a/src/pstream.c b/src/pstream.c deleted file mode 100644 index 3076b776..00000000 --- a/src/pstream.c +++ /dev/null @@ -1,457 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "pstream.h" -#include "queue.h" - -enum pa_pstream_descriptor_index { - PA_PSTREAM_DESCRIPTOR_LENGTH, - PA_PSTREAM_DESCRIPTOR_CHANNEL, - PA_PSTREAM_DESCRIPTOR_DELTA, - PA_PSTREAM_DESCRIPTOR_MAX -}; - -typedef uint32_t pa_pstream_descriptor[PA_PSTREAM_DESCRIPTOR_MAX]; - -#define PA_PSTREAM_DESCRIPTOR_SIZE (PA_PSTREAM_DESCRIPTOR_MAX*sizeof(uint32_t)) -#define FRAME_SIZE_MAX (1024*64) - -struct item_info { - enum { PA_PSTREAM_ITEM_PACKET, PA_PSTREAM_ITEM_MEMBLOCK } type; - - /* memblock info */ - struct pa_memchunk chunk; - uint32_t channel; - int32_t delta; - - /* packet info */ - struct pa_packet *packet; -}; - -struct pa_pstream { - struct pa_mainloop_api *mainloop; - struct mainloop_source *mainloop_source; - struct pa_iochannel *io; - struct pa_queue *send_queue; - - int in_use, shall_free; - - int dead; - void (*die_callback) (struct pa_pstream *p, void *userdata); - void *die_callback_userdata; - - struct { - struct item_info* current; - pa_pstream_descriptor descriptor; - void *data; - size_t index; - } write; - - struct { - struct pa_memblock *memblock; - struct pa_packet *packet; - pa_pstream_descriptor descriptor; - void *data; - size_t index; - } read; - - void (*recieve_packet_callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata); - void *recieve_packet_callback_userdata; - - void (*recieve_memblock_callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata); - void *recieve_memblock_callback_userdata; - - void (*drain_callback)(struct pa_pstream *p, void *userdata); - void *drain_userdata; -}; - -static void do_write(struct pa_pstream *p); -static void do_read(struct pa_pstream *p); - -static void do_something(struct pa_pstream *p) { - assert(p && !p->shall_free); - p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 0); - - if (p->dead) - return; - - if (pa_iochannel_is_hungup(p->io)) { - p->dead = 1; - if (p->die_callback) - p->die_callback(p, p->die_callback_userdata); - - return; - } - - if (pa_iochannel_is_writable(p->io)) { - p->in_use = 1; - do_write(p); - p->in_use = 0; - - if (p->shall_free) { - pa_pstream_free(p); - return; - } - } - - if (pa_iochannel_is_readable(p->io)) { - p->in_use = 1; - do_read(p); - p->in_use = 0; - if (p->shall_free) { - pa_pstream_free(p); - return; - } - } -} - -static void io_callback(struct pa_iochannel*io, void *userdata) { - struct pa_pstream *p = userdata; - assert(p && p->io == io); - do_something(p); -} - -static void fixed_callback(struct pa_mainloop_api *m, void *id, void*userdata) { - struct pa_pstream *p = userdata; - assert(p && p->mainloop_source == id && p->mainloop == m); - do_something(p); -} - -struct pa_pstream *pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel *io) { - struct pa_pstream *p; - assert(io); - - p = malloc(sizeof(struct pa_pstream)); - assert(p); - - p->io = io; - pa_iochannel_set_callback(io, io_callback, p); - - p->dead = 0; - p->die_callback = NULL; - p->die_callback_userdata = NULL; - - p->mainloop = m; - p->mainloop_source = m->source_fixed(m, fixed_callback, p); - m->enable_fixed(m, p->mainloop_source, 0); - - p->send_queue = pa_queue_new(); - assert(p->send_queue); - - p->write.current = NULL; - p->write.index = 0; - - p->read.memblock = NULL; - p->read.packet = NULL; - p->read.index = 0; - - p->recieve_packet_callback = NULL; - p->recieve_packet_callback_userdata = NULL; - - p->recieve_memblock_callback = NULL; - p->recieve_memblock_callback_userdata = NULL; - - p->drain_callback = NULL; - p->drain_userdata = NULL; - - p->in_use = p->shall_free = 0; - - return p; -} - -static void item_free(void *item, void *p) { - struct item_info *i = item; - assert(i); - - if (i->type == PA_PSTREAM_ITEM_MEMBLOCK) { - assert(i->chunk.memblock); - pa_memblock_unref(i->chunk.memblock); - } else { - assert(i->type == PA_PSTREAM_ITEM_PACKET); - assert(i->packet); - pa_packet_unref(i->packet); - } - - free(i); -} - -void pa_pstream_free(struct pa_pstream *p) { - assert(p); - - if (p->in_use) { - /* If this pstream object is used by someone else on the call stack, we have to postpone the freeing */ - p->dead = p->shall_free = 1; - return; - } - - pa_iochannel_free(p->io); - pa_queue_free(p->send_queue, item_free, NULL); - - if (p->write.current) - item_free(p->write.current, NULL); - - if (p->read.memblock) - pa_memblock_unref(p->read.memblock); - - if (p->read.packet) - pa_packet_unref(p->read.packet); - - p->mainloop->cancel_fixed(p->mainloop, p->mainloop_source); - free(p); -} - -void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet) { - struct item_info *i; - assert(p && packet); - - i = malloc(sizeof(struct item_info)); - assert(i); - i->type = PA_PSTREAM_ITEM_PACKET; - i->packet = pa_packet_ref(packet); - - pa_queue_push(p->send_queue, i); - p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 1); -} - -void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk) { - struct item_info *i; - assert(p && channel != (uint32_t) -1 && chunk); - - i = malloc(sizeof(struct item_info)); - assert(i); - i->type = PA_PSTREAM_ITEM_MEMBLOCK; - i->chunk = *chunk; - i->channel = channel; - i->delta = delta; - - pa_memblock_ref(i->chunk.memblock); - - pa_queue_push(p->send_queue, i); - p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 1); -} - -void pa_pstream_set_recieve_packet_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata), void *userdata) { - assert(p && callback); - - p->recieve_packet_callback = callback; - p->recieve_packet_callback_userdata = userdata; -} - -void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata), void *userdata) { - assert(p && callback); - - p->recieve_memblock_callback = callback; - p->recieve_memblock_callback_userdata = userdata; -} - -static void prepare_next_write_item(struct pa_pstream *p) { - assert(p); - - if (!(p->write.current = pa_queue_pop(p->send_queue))) - return; - - p->write.index = 0; - - if (p->write.current->type == PA_PSTREAM_ITEM_PACKET) { - assert(p->write.current->packet); - p->write.data = p->write.current->packet->data; - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->packet->length); - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl((uint32_t) -1); - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA] = 0; - } else { - assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK && p->write.current->chunk.memblock); - p->write.data = p->write.current->chunk.memblock->data + p->write.current->chunk.index; - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length); - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl(p->write.current->channel); - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA] = htonl(p->write.current->delta); - } -} - -static void do_write(struct pa_pstream *p) { - void *d; - size_t l; - ssize_t r; - assert(p); - - if (!p->write.current) - prepare_next_write_item(p); - - if (!p->write.current) - return; - - assert(p->write.data); - - if (p->write.index < PA_PSTREAM_DESCRIPTOR_SIZE) { - d = (void*) p->write.descriptor + p->write.index; - l = PA_PSTREAM_DESCRIPTOR_SIZE - p->write.index; - } else { - d = (void*) p->write.data + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE; - l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE); - } - - if ((r = pa_iochannel_write(p->io, d, l)) < 0) - goto die; - - p->write.index += r; - - if (p->write.index >= PA_PSTREAM_DESCRIPTOR_SIZE+ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])) { - assert(p->write.current); - item_free(p->write.current, (void *) 1); - p->write.current = NULL; - - if (p->drain_callback && !pa_pstream_is_pending(p)) - p->drain_callback(p, p->drain_userdata); - } - - return; - -die: - p->dead = 1; - if (p->die_callback) - p->die_callback(p, p->die_callback_userdata); -} - -static void do_read(struct pa_pstream *p) { - void *d; - size_t l; - ssize_t r; - assert(p); - - if (p->read.index < PA_PSTREAM_DESCRIPTOR_SIZE) { - d = (void*) p->read.descriptor + p->read.index; - l = PA_PSTREAM_DESCRIPTOR_SIZE - p->read.index; - } else { - assert(p->read.data); - d = (void*) p->read.data + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE; - l = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE); - } - - if ((r = pa_iochannel_read(p->io, d, l)) <= 0) - goto die; - - p->read.index += r; - - if (p->read.index == PA_PSTREAM_DESCRIPTOR_SIZE) { - /* Reading of frame descriptor complete */ - - /* Frame size too large */ - if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) > FRAME_SIZE_MAX) - goto die; - - assert(!p->read.packet && !p->read.memblock); - - if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]) == (uint32_t) -1) { - /* Frame is a packet frame */ - p->read.packet = pa_packet_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])); - assert(p->read.packet); - p->read.data = p->read.packet->data; - } else { - /* Frame is a memblock frame */ - p->read.memblock = pa_memblock_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])); - assert(p->read.memblock); - p->read.data = p->read.memblock->data; - } - - } else if (p->read.index > PA_PSTREAM_DESCRIPTOR_SIZE) { - /* Frame payload available */ - - if (p->read.memblock && p->recieve_memblock_callback) { /* Is this memblock data? Than pass it to the user */ - size_t l; - - l = (p->read.index - r) < PA_PSTREAM_DESCRIPTOR_SIZE ? p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE : (size_t) r; - - if (l > 0) { - struct pa_memchunk chunk; - - chunk.memblock = p->read.memblock; - chunk.index = p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE - l; - chunk.length = l; - - if (p->recieve_memblock_callback) - p->recieve_memblock_callback( - p, - ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]), - (int32_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA]), - &chunk, - p->recieve_memblock_callback_userdata); - } - } - - /* Frame complete */ - if (p->read.index >= ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) + PA_PSTREAM_DESCRIPTOR_SIZE) { - if (p->read.memblock) { - assert(!p->read.packet); - - pa_memblock_unref(p->read.memblock); - p->read.memblock = NULL; - } else { - assert(p->read.packet); - - if (p->recieve_packet_callback) - p->recieve_packet_callback(p, p->read.packet, p->recieve_packet_callback_userdata); - - pa_packet_unref(p->read.packet); - p->read.packet = NULL; - } - - p->read.index = 0; - } - } - - return; - -die: - p->dead = 1; - if (p->die_callback) - p->die_callback(p, p->die_callback_userdata); - -} - -void pa_pstream_set_die_callback(struct pa_pstream *p, void (*callback)(struct pa_pstream *p, void *userdata), void *userdata) { - assert(p && callback); - p->die_callback = callback; - p->die_callback_userdata = userdata; -} - -int pa_pstream_is_pending(struct pa_pstream *p) { - assert(p); - - if (p->dead) - return 0; - - return p->write.current || !pa_queue_is_empty(p->send_queue); -} - -void pa_pstream_set_drain_callback(struct pa_pstream *p, void (*cb)(struct pa_pstream *p, void *userdata), void *userdata) { - assert(p); - - p->drain_callback = cb; - p->drain_userdata = userdata; -} - diff --git a/src/pstream.h b/src/pstream.h deleted file mode 100644 index 6b91aeb0..00000000 --- a/src/pstream.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef foopstreamhfoo -#define foopstreamhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "packet.h" -#include "memblock.h" -#include "iochannel.h" -#include "mainloop-api.h" -#include "memchunk.h" - -/* It is safe to destroy the calling pstream object from all callbacks */ - -struct pa_pstream; - -struct pa_pstream* pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel *io); -void pa_pstream_free(struct pa_pstream*p); - -void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet); -void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk); - -void pa_pstream_set_recieve_packet_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata), void *userdata); -void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata), void *userdata); -void pa_pstream_set_drain_callback(struct pa_pstream *p, void (*cb)(struct pa_pstream *p, void *userdata), void *userdata); - -void pa_pstream_set_die_callback(struct pa_pstream *p, void (*callback)(struct pa_pstream *p, void *userdata), void *userdata); - -int pa_pstream_is_pending(struct pa_pstream *p); - -#endif diff --git a/src/queue.c b/src/queue.c deleted file mode 100644 index 9befd475..00000000 --- a/src/queue.c +++ /dev/null @@ -1,109 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "queue.h" - -struct queue_entry { - struct queue_entry *next; - void *data; -}; - -struct pa_queue { - struct queue_entry *front, *back; - unsigned length; -}; - -struct pa_queue* pa_queue_new(void) { - struct pa_queue *q = malloc(sizeof(struct pa_queue)); - assert(q); - q->front = q->back = NULL; - q->length = 0; - return q; -} - -void pa_queue_free(struct pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata) { - struct queue_entry *e; - assert(q); - - e = q->front; - while (e) { - struct queue_entry *n = e->next; - - if (destroy) - destroy(e->data, userdata); - - free(e); - e = n; - } - - free(q); -} - -void pa_queue_push(struct pa_queue *q, void *p) { - struct queue_entry *e; - - e = malloc(sizeof(struct queue_entry)); - - e->data = p; - e->next = NULL; - - if (q->back) - q->back->next = e; - else { - assert(!q->front); - q->front = e; - } - - q->back = e; - q->length++; -} - -void* pa_queue_pop(struct pa_queue *q) { - void *p; - struct queue_entry *e; - assert(q); - - if (!(e = q->front)) - return NULL; - - q->front = e->next; - if (q->back == e) - q->back = NULL; - - p = e->data; - free(e); - - q->length--; - - return p; -} - -int pa_queue_is_empty(struct pa_queue *q) { - assert(q); - return q->length == 0; -} diff --git a/src/queue.h b/src/queue.h deleted file mode 100644 index 3ec13734..00000000 --- a/src/queue.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef fooqueuehfoo -#define fooqueuehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -struct pa_queue; - -struct pa_queue* pa_queue_new(void); -void pa_queue_free(struct pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata); -void pa_queue_push(struct pa_queue *q, void *p); -void* pa_queue_pop(struct pa_queue *q); - -int pa_queue_is_empty(struct pa_queue *q); - -#endif diff --git a/src/resampler.c b/src/resampler.c deleted file mode 100644 index 4f5f6be3..00000000 --- a/src/resampler.c +++ /dev/null @@ -1,180 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include - -#include "resampler.h" -#include "sconv.h" - -struct pa_resampler { - struct pa_sample_spec i_ss, o_ss; - float* i_buf, *o_buf; - unsigned i_alloc, o_alloc; - size_t i_sz, o_sz; - - int channels; - - pa_convert_to_float32_func_t to_float32_func; - pa_convert_from_float32_func_t from_float32_func; - SRC_STATE *src_state; -}; - -struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b) { - struct pa_resampler *r; - int err; - assert(a && b && pa_sample_spec_valid(a) && pa_sample_spec_valid(b)); - - if (a->channels != b->channels && a->channels != 1 && b->channels != 1) - goto fail; - - if (a->format == PA_SAMPLE_ALAW || a->format == PA_SAMPLE_ULAW || b->format == PA_SAMPLE_ALAW || b->format == PA_SAMPLE_ULAW) - goto fail; - - r = malloc(sizeof(struct pa_resampler)); - assert(r); - - r->channels = a->channels; - if (b->channels < r->channels) - r->channels = b->channels; - - r->i_buf = r->o_buf = NULL; - r->i_alloc = r->o_alloc = 0; - - if (a->rate != b->rate) { - r->src_state = src_new(SRC_SINC_FASTEST, r->channels, &err); - if (err != 0 || !r->src_state) - goto fail; - } else - r->src_state = NULL; - - r->i_ss = *a; - r->o_ss = *b; - - r->i_sz = pa_sample_size(a); - r->o_sz = pa_sample_size(b); - - r->to_float32_func = pa_get_convert_to_float32_function(a->format); - r->from_float32_func = pa_get_convert_from_float32_function(b->format); - - assert(r->to_float32_func && r->from_float32_func); - - return r; - -fail: - if (r) - free(r); - - return NULL; -} - -void pa_resampler_free(struct pa_resampler *r) { - assert(r); - if (r->src_state) - src_delete(r->src_state); - free(r->i_buf); - free(r->o_buf); - free(r); -} - -size_t pa_resampler_request(struct pa_resampler *r, size_t out_length) { - assert(r && (out_length % r->o_sz) == 0); - - return (((out_length / r->o_sz)*r->i_ss.rate)/r->o_ss.rate) * r->i_sz; -} - - -void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out) { - unsigned i_nchannels, o_nchannels, ins, ons, eff_ins, eff_ons; - float *cbuf; - assert(r && in && out && in->length && in->memblock && (in->length % r->i_sz) == 0); - - /* How many input samples? */ - ins = in->length/r->i_sz; - - /* How much space for output samples? */ - if (r->src_state) - ons = (ins*r->o_ss.rate/r->i_ss.rate)+1024; - else - ons = ins; - - /* How many channels? */ - if (r->i_ss.channels == r->o_ss.channels) { - i_nchannels = o_nchannels = 1; - eff_ins = ins*r->i_ss.channels; /* effective samples */ - eff_ons = ons*r->o_ss.channels; - } else { - i_nchannels = r->i_ss.channels; - o_nchannels = r->o_ss.channels; - eff_ins = ins; - eff_ons = ons; - } - - out->memblock = pa_memblock_new(out->length = (ons*r->o_sz)); - out->index = 0; - assert(out->memblock); - - if (r->i_alloc < eff_ins) - r->i_buf = realloc(r->i_buf, sizeof(float) * (r->i_alloc = eff_ins)); - assert(r->i_buf); - - r->to_float32_func(eff_ins, in->memblock->data+in->index, i_nchannels, r->i_buf); - - if (r->src_state) { - int ret; - SRC_DATA data; - - if (r->o_alloc < eff_ons) - r->o_buf = realloc(r->o_buf, sizeof(float) * (r->o_alloc = eff_ons)); - assert(r->o_buf); - - data.data_in = r->i_buf; - data.input_frames = ins; - - data.data_out = r->o_buf; - data.output_frames = ons; - - data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate; - data.end_of_input = 0; - - ret = src_process(r->src_state, &data); - assert(ret == 0); - assert((unsigned) data.input_frames_used == ins); - - cbuf = r->o_buf; - ons = data.output_frames_gen; - - if (r->i_ss.channels == r->o_ss.channels) - eff_ons = ons*r->o_ss.channels; - else - eff_ons = ons; - } else - cbuf = r->i_buf; - - r->from_float32_func(eff_ons, cbuf, out->memblock->data+out->index, o_nchannels); - out->length = ons*r->o_sz; -} diff --git a/src/resampler.h b/src/resampler.h deleted file mode 100644 index 8e979478..00000000 --- a/src/resampler.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef fooresamplerhfoo -#define fooresamplerhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "sample.h" -#include "memblock.h" -#include "memchunk.h" - -struct pa_resampler; - -struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b); -void pa_resampler_free(struct pa_resampler *r); - -size_t pa_resampler_request(struct pa_resampler *r, size_t out_length); -void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out); - -#endif diff --git a/src/sample-util.c b/src/sample-util.c deleted file mode 100644 index d608ce1b..00000000 --- a/src/sample-util.c +++ /dev/null @@ -1,144 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "sample-util.h" - -struct pa_memblock *pa_silence_memblock(struct pa_memblock* b, const struct pa_sample_spec *spec) { - assert(b && b->data && spec); - pa_silence_memory(b->data, b->length, spec); - return b; -} - -void pa_silence_memchunk(struct pa_memchunk *c, const struct pa_sample_spec *spec) { - assert(c && c->memblock && c->memblock->data && spec && c->length); - pa_silence_memory(c->memblock->data+c->index, c->length, spec); -} - -void pa_silence_memory(void *p, size_t length, const struct pa_sample_spec *spec) { - char c = 0; - assert(p && length && spec); - - switch (spec->format) { - case PA_SAMPLE_U8: - c = 127; - break; - case PA_SAMPLE_S16LE: - case PA_SAMPLE_S16BE: - case PA_SAMPLE_FLOAT32: - c = 0; - break; - case PA_SAMPLE_ALAW: - case PA_SAMPLE_ULAW: - c = 80; - break; - default: - assert(0); - } - - memset(p, c, length); -} - -size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const struct pa_sample_spec *spec, uint32_t volume) { - unsigned c, d; - assert(channels && data && length && spec); - assert(spec->format == PA_SAMPLE_S16NE); - - for (d = 0;; d += sizeof(int16_t)) { - int32_t sum = 0; - - if (d >= length) - return d; - - for (c = 0; c < nchannels; c++) { - int32_t v; - uint32_t volume = channels[c].volume; - - if (d >= channels[c].chunk.length) - return d; - - if (volume == PA_VOLUME_MUTE) - v = 0; - else { - v = *((int16_t*) (channels[c].chunk.memblock->data + channels[c].chunk.index + d)); - - if (volume != PA_VOLUME_NORM) - v = (int32_t) ((float)v*volume/PA_VOLUME_NORM); - } - - sum += v; - } - - if (volume == PA_VOLUME_MUTE) - sum = 0; - else if (volume != PA_VOLUME_NORM) - sum = (int32_t) ((float) sum*volume/PA_VOLUME_NORM); - - if (sum < -0x8000) sum = -0x8000; - if (sum > 0x7FFF) sum = 0x7FFF; - - *((int16_t*) data) = sum; - data += sizeof(int16_t); - } -} - - -void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, uint32_t volume) { - int16_t *d; - size_t n; - assert(c && spec && (c->length % pa_sample_size(spec) == 0)); - assert(spec->format == PA_SAMPLE_S16NE); - - if (volume == PA_VOLUME_NORM) - return; - - if (volume == PA_VOLUME_MUTE) { - pa_silence_memchunk(c, spec); - return; - } - - for (d = (c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { - int32_t t = (int32_t)(*d); - - t *= volume; - t /= PA_VOLUME_NORM; - - if (t < -0x8000) t = -0x8000; - if (t > 0x7FFF) t = 0x7FFF; - - *d = (int16_t) t; - } -} - -uint32_t pa_volume_multiply(uint32_t a, uint32_t b) { - uint64_t p = a; - p *= b; - p /= PA_VOLUME_NORM; - - return (uint32_t) p; -} diff --git a/src/sample-util.h b/src/sample-util.h deleted file mode 100644 index 73101ab4..00000000 --- a/src/sample-util.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef foosampleutilhfoo -#define foosampleutilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "sample.h" -#include "memblock.h" -#include "memchunk.h" - -#define PA_VOLUME_NORM (0x100) -#define PA_VOLUME_MUTE (0) - -struct pa_memblock *pa_silence_memblock(struct pa_memblock* b, const struct pa_sample_spec *spec); -void pa_silence_memchunk(struct pa_memchunk *c, const struct pa_sample_spec *spec); -void pa_silence_memory(void *p, size_t length, const struct pa_sample_spec *spec); - -struct pa_mix_info { - struct pa_memchunk chunk; - uint32_t volume; - void *userdata; -}; - -size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const struct pa_sample_spec *spec, uint32_t volume); - -void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, uint32_t volume); - -uint32_t pa_volume_multiply(uint32_t a, uint32_t b); - -#endif diff --git a/src/sample.c b/src/sample.c deleted file mode 100644 index 8179475d..00000000 --- a/src/sample.c +++ /dev/null @@ -1,99 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "sample.h" - -size_t pa_sample_size(const struct pa_sample_spec *spec) { - assert(spec); - size_t b = 1; - - switch (spec->format) { - case PA_SAMPLE_U8: - case PA_SAMPLE_ULAW: - case PA_SAMPLE_ALAW: - b = 1; - break; - case PA_SAMPLE_S16LE: - case PA_SAMPLE_S16BE: - b = 2; - break; - case PA_SAMPLE_FLOAT32LE: - case PA_SAMPLE_FLOAT32BE: - b = 4; - break; - default: - assert(0); - } - - return b * spec->channels; -} - -size_t pa_bytes_per_second(const struct pa_sample_spec *spec) { - assert(spec); - return spec->rate*pa_sample_size(spec); -} - - -uint32_t pa_samples_usec(size_t length, const struct pa_sample_spec *spec) { - assert(spec); - - return (uint32_t) (((double) length /pa_sample_size(spec))/spec->rate*1000000); -} - -int pa_sample_spec_valid(const struct pa_sample_spec *spec) { - assert(spec); - - if (!spec->rate || !spec->channels) - return 0; - - if (spec->format >= PA_SAMPLE_MAX) - return 0; - - return 1; -} - -int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b) { - assert(a && b); - - return (a->format == b->format) && (a->rate == b->rate) && (a->channels == b->channels); -} - -void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec) { - static const char* const table[]= { - [PA_SAMPLE_U8] = "U8", - [PA_SAMPLE_ALAW] = "ALAW", - [PA_SAMPLE_ULAW] = "ULAW", - [PA_SAMPLE_S16LE] = "S16LE", - [PA_SAMPLE_S16BE] = "S16BE", - [PA_SAMPLE_FLOAT32LE] = "FLOAT32LE", - [PA_SAMPLE_FLOAT32BE] = "FLOAT32BE", - }; - - assert(pa_sample_spec_valid(spec)); - snprintf(s, l, "%s %uch %uHz", table[spec->format], spec->channels, spec->rate); -} diff --git a/src/sample.h b/src/sample.h deleted file mode 100644 index 825441f2..00000000 --- a/src/sample.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef foosamplehfoo -#define foosamplehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -enum pa_sample_format { - PA_SAMPLE_U8, - PA_SAMPLE_ALAW, - PA_SAMPLE_ULAW, - PA_SAMPLE_S16LE, - PA_SAMPLE_S16BE, - PA_SAMPLE_FLOAT32LE, - PA_SAMPLE_FLOAT32BE, - PA_SAMPLE_MAX -}; - -#ifdef WORDS_BIGENDIAN -#define PA_SAMPLE_S16NE PA_SAMPLE_S16BE -#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32BE -#else -#define PA_SAMPLE_S16NE PA_SAMPLE_S16LE -#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32LE -#endif -#define PA_SAMPLE_FLOAT32 PA_SAMPLE_FLOAT32NE - -struct pa_sample_spec { - enum pa_sample_format format; - uint32_t rate; - uint8_t channels; -}; - -size_t pa_bytes_per_second(const struct pa_sample_spec *spec); -size_t pa_sample_size(const struct pa_sample_spec *spec); -uint32_t pa_samples_usec(size_t length, const struct pa_sample_spec *spec); -int pa_sample_spec_valid(const struct pa_sample_spec *spec); -int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b); - - -#define PA_SAMPLE_SNPRINT_MAX_LENGTH 32 -void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec); - -#endif diff --git a/src/sconv-s16be.c b/src/sconv-s16be.c deleted file mode 100644 index a4c25cde..00000000 --- a/src/sconv-s16be.c +++ /dev/null @@ -1,34 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "sconv-s16be.h" - -#define INT16_FROM INT16_FROM_BE -#define INT16_TO INT16_TO_BE - -#define pa_sconv_s16le_to_float32 pa_sconv_s16be_to_float32 -#define pa_sconv_s16le_from_float32 pa_sconv_s16be_from_float32 - -#include "sconv-s16le.c" diff --git a/src/sconv-s16be.h b/src/sconv-s16be.h deleted file mode 100644 index d112d9f2..00000000 --- a/src/sconv-s16be.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef foosconv_s16befoo -#define foosconv_s16befoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -void pa_sconv_s16be_to_float32(unsigned n, const void *a, unsigned an, float *b); -void pa_sconv_s16be_from_float32(unsigned n, const float *a, void *b, unsigned bn); - -#endif diff --git a/src/sconv-s16le.c b/src/sconv-s16le.c deleted file mode 100644 index 45b28bdb..00000000 --- a/src/sconv-s16le.c +++ /dev/null @@ -1,82 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "endianmacros.h" -#include "sconv.h" - -#ifndef INT16_FROM -#define INT16_FROM INT16_FROM_LE -#endif - -#ifndef INT16_TO -#define INT16_TO INT16_TO_LE -#endif - -void pa_sconv_s16le_to_float32(unsigned n, const void *a, unsigned an, float *b) { - const int16_t *ca = a; - assert(n && a && an && b); - - for (; n > 0; n--) { - unsigned i; - float sum = 0; - - for (i = 0; i < an; i++) { - int16_t s = *(ca++); - sum += ((float) INT16_FROM(s))/0x7FFF; - } - - if (sum > 1) - sum = 1; - if (sum < -1) - sum = -1; - - *(b++) = sum; - } -} - -void pa_sconv_s16le_from_float32(unsigned n, const float *a, void *b, unsigned bn) { - int16_t *cb = b; - assert(n && a && b && bn); - - for (; n > 0; n--) { - unsigned i; - int16_t s; - float v = *(a++); - - if (v > 1) - v = 1; - if (v < -1) - v = -1; - - s = (int16_t) (v * 0x7FFF); - s = INT16_TO(s); - - for (i = 0; i < bn; i++) - *(cb++) = s; - } -} diff --git a/src/sconv-s16le.h b/src/sconv-s16le.h deleted file mode 100644 index 0f206ec3..00000000 --- a/src/sconv-s16le.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef foosconv_s16lefoo -#define foosconv_s16lefoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -void pa_sconv_s16le_to_float32(unsigned n, const void *a, unsigned an, float *b); -void pa_sconv_s16le_from_float32(unsigned n, const float *a, void *b, unsigned bn); - -#endif diff --git a/src/sconv.c b/src/sconv.c deleted file mode 100644 index dd9dd241..00000000 --- a/src/sconv.c +++ /dev/null @@ -1,137 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include "endianmacros.h" -#include "sconv.h" - -#include "sconv-s16le.h" -#include "sconv-s16be.h" - -static void u8_to_float32(unsigned n, const void *a, unsigned an, float *b) { - unsigned i; - const uint8_t *ca = a; - assert(n && a && an && b); - - for (; n > 0; n--) { - float sum = 0; - - for (i = 0; i < an; i++) { - uint8_t v = *(ca++); - sum += (((float) v)-127)/127; - } - - if (sum > 1) - sum = 1; - if (sum < -1) - sum = -1; - - *(b++) = sum; - } -} - -static void u8_from_float32(unsigned n, const float *a, void *b, unsigned bn) { - unsigned i; - uint8_t *cb = b; - - assert(n && a && b && bn); - for (; n > 0; n--) { - float v = *(a++); - uint8_t u; - - if (v > 1) - v = 1; - - if (v < -1) - v = -1; - - u = (uint8_t) (v*127+127); - - for (i = 0; i < bn; i++) - *(cb++) = u; - } -} - -static void float32_to_float32(unsigned n, const void *a, unsigned an, float *b) { - unsigned i; - const float *ca = a; - assert(n && a && an && b); - for (; n > 0; n--) { - float sum = 0; - - for (i = 0; i < an; i++) - sum += *(ca++); - - if (sum > 1) - sum = 1; - if (sum < -1) - sum = -1; - - *(b++) = sum; - } -} - -static void float32_from_float32(unsigned n, const float *a, void *b, unsigned bn) { - unsigned i; - float *cb = b; - assert(n && a && b && bn); - for (; n > 0; n--) { - float v = *(a++); - for (i = 0; i < bn; i++) - *(cb++) = v; - } -} - -pa_convert_to_float32_func_t pa_get_convert_to_float32_function(enum pa_sample_format f) { - switch(f) { - case PA_SAMPLE_U8: - return u8_to_float32; - case PA_SAMPLE_S16LE: - return pa_sconv_s16le_to_float32; - case PA_SAMPLE_S16BE: - return pa_sconv_s16be_to_float32; - case PA_SAMPLE_FLOAT32: - return float32_to_float32; - default: - return NULL; - } -} - -pa_convert_from_float32_func_t pa_get_convert_from_float32_function(enum pa_sample_format f) { - switch(f) { - case PA_SAMPLE_U8: - return u8_from_float32; - case PA_SAMPLE_S16LE: - return pa_sconv_s16le_from_float32; - case PA_SAMPLE_S16BE: - return pa_sconv_s16be_from_float32; - case PA_SAMPLE_FLOAT32: - return float32_from_float32; - default: - return NULL; - } -} diff --git a/src/sconv.h b/src/sconv.h deleted file mode 100644 index 1a62ed20..00000000 --- a/src/sconv.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef foosconvhfoo -#define foosconvhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "sample.h" - -typedef void (*pa_convert_to_float32_func_t)(unsigned n, const void *a, unsigned an, float *b); -typedef void (*pa_convert_from_float32_func_t)(unsigned n, const float *a, void *b, unsigned bn); - -pa_convert_to_float32_func_t pa_get_convert_to_float32_function(enum pa_sample_format f); -pa_convert_from_float32_func_t pa_get_convert_from_float32_function(enum pa_sample_format f); - -#endif diff --git a/src/sink-input.c b/src/sink-input.c deleted file mode 100644 index 5c2d3a13..00000000 --- a/src/sink-input.c +++ /dev/null @@ -1,163 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "sink-input.h" -#include "sample-util.h" - -#define CONVERT_BUFFER_LENGTH 4096 - -struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec) { - struct pa_sink_input *i; - struct pa_resampler *resampler = NULL; - int r; - char st[256]; - assert(s && spec); - - if (!pa_sample_spec_equal(spec, &s->sample_spec)) - if (!(resampler = pa_resampler_new(spec, &s->sample_spec))) - return NULL; - - i = malloc(sizeof(struct pa_sink_input)); - assert(i); - i->name = name ? strdup(name) : NULL; - i->client = NULL; - i->owner = NULL; - i->sink = s; - i->sample_spec = *spec; - - i->peek = NULL; - i->drop = NULL; - i->kill = NULL; - i->get_latency = NULL; - i->userdata = NULL; - - i->volume = PA_VOLUME_NORM; - - i->resampled_chunk.memblock = NULL; - i->resampled_chunk.index = i->resampled_chunk.length = 0; - i->resampler = resampler; - - assert(s->core); - r = pa_idxset_put(s->core->sink_inputs, i, &i->index); - assert(r == 0 && i->index != PA_IDXSET_INVALID); - r = pa_idxset_put(s->inputs, i, NULL); - assert(r == 0); - - pa_sample_snprint(st, sizeof(st), spec); - fprintf(stderr, "sink-input: created %u \"%s\" on %u with sample spec \"%s\"\n", i->index, i->name, s->index, st); - - return i; -} - -void pa_sink_input_free(struct pa_sink_input* i) { - assert(i); - - assert(i->sink && i->sink->core); - pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); - pa_idxset_remove_by_data(i->sink->inputs, i, NULL); - - if (i->resampled_chunk.memblock) - pa_memblock_unref(i->resampled_chunk.memblock); - if (i->resampler) - pa_resampler_free(i->resampler); - - free(i->name); - free(i); -} - -void pa_sink_input_kill(struct pa_sink_input*i) { - assert(i); - - if (i->kill) - i->kill(i); -} - -uint32_t pa_sink_input_get_latency(struct pa_sink_input *i) { - uint32_t l = 0; - - assert(i); - if (i->get_latency) - l += i->get_latency(i); - - assert(i->sink); - l += pa_sink_get_latency(i->sink); - - return l; -} - -int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { - assert(i && chunk && i->peek && i->drop); - - if (!i->resampler) - return i->peek(i, chunk); - - if (!i->resampled_chunk.memblock) { - struct pa_memchunk tchunk; - size_t l; - int ret; - - if ((ret = i->peek(i, &tchunk)) < 0) - return ret; - - l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); - if (tchunk.length > l) - tchunk.length = l; - - i->drop(i, tchunk.length); - - pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk); - pa_memblock_unref(tchunk.memblock); - } - - assert(i->resampled_chunk.memblock && i->resampled_chunk.length); - *chunk = i->resampled_chunk; - pa_memblock_ref(i->resampled_chunk.memblock); - return 0; -} - -void pa_sink_input_drop(struct pa_sink_input *i, size_t length) { - assert(i && length); - - if (!i->resampler) { - i->drop(i, length); - return; - } - - assert(i->resampled_chunk.memblock && i->resampled_chunk.length >= length); - - i->resampled_chunk.index += length; - i->resampled_chunk.length -= length; - - if (!i->resampled_chunk.length) { - pa_memblock_unref(i->resampled_chunk.memblock); - i->resampled_chunk.memblock = NULL; - i->resampled_chunk.index = i->resampled_chunk.length = 0; - } -} diff --git a/src/sink-input.h b/src/sink-input.h deleted file mode 100644 index 63dce71d..00000000 --- a/src/sink-input.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef foosinkinputhfoo -#define foosinkinputhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "sink.h" -#include "sample.h" -#include "memblockq.h" -#include "resampler.h" -#include "module.h" -#include "client.h" - -struct pa_sink_input { - uint32_t index; - - char *name; - struct pa_module *owner; - struct pa_client *client; - struct pa_sink *sink; - struct pa_sample_spec sample_spec; - uint32_t volume; - - int (*peek) (struct pa_sink_input *i, struct pa_memchunk *chunk); - void (*drop) (struct pa_sink_input *i, size_t length); - void (*kill) (struct pa_sink_input *i); - uint32_t (*get_latency) (struct pa_sink_input *i); - - void *userdata; - - struct pa_memchunk resampled_chunk; - struct pa_resampler *resampler; -}; - -struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec); -void pa_sink_input_free(struct pa_sink_input* i); - -/* Code that didn't create the input stream should call this function to - * request destruction of it */ -void pa_sink_input_kill(struct pa_sink_input *i); - -uint32_t pa_sink_input_get_latency(struct pa_sink_input *i); - -int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk); -void pa_sink_input_drop(struct pa_sink_input *i, size_t length); - -#endif diff --git a/src/sink.c b/src/sink.c deleted file mode 100644 index 20fa76a6..00000000 --- a/src/sink.c +++ /dev/null @@ -1,292 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "sink.h" -#include "sink-input.h" -#include "namereg.h" -#include "util.h" -#include "sample-util.h" - -#define MAX_MIX_CHANNELS 32 - -struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec) { - struct pa_sink *s; - char *n = NULL; - char st[256]; - int r; - assert(core && name && spec); - - s = malloc(sizeof(struct pa_sink)); - assert(s); - - if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) { - free(s); - return NULL; - } - - s->name = strdup(name); - s->description = NULL; - - s->owner = NULL; - s->core = core; - s->sample_spec = *spec; - s->inputs = pa_idxset_new(NULL, NULL); - - n = pa_sprintf_malloc("%s_monitor", name); - 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; - - s->notify = NULL; - s->get_latency = NULL; - s->userdata = NULL; - - r = pa_idxset_put(core->sinks, s, &s->index); - assert(s->index != PA_IDXSET_INVALID && r >= 0); - - pa_sample_snprint(st, sizeof(st), spec); - fprintf(stderr, "sink: created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); - - return s; -} - -void pa_sink_free(struct pa_sink *s) { - struct pa_sink_input *i, *j = NULL; - assert(s); - - pa_namereg_unregister(s->core, s->name); - - while ((i = pa_idxset_first(s->inputs, NULL))) { - assert(i != j); - pa_sink_input_kill(i); - j = i; - } - pa_idxset_free(s->inputs, NULL, NULL); - - pa_source_free(s->monitor_source); - pa_idxset_remove_by_data(s->core->sinks, s, NULL); - - fprintf(stderr, "sink: freed %u \"%s\"\n", s->index, s->name); - - free(s->name); - free(s->description); - free(s); -} - -void pa_sink_notify(struct pa_sink*s) { - assert(s); - - if (s->notify) - s->notify(s); -} - -static unsigned fill_mix_info(struct pa_sink *s, struct pa_mix_info *info, unsigned maxinfo) { - uint32_t index = PA_IDXSET_INVALID; - struct pa_sink_input *i; - unsigned n = 0; - - assert(s && info); - - for (i = pa_idxset_first(s->inputs, &index); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &index)) { - if (pa_sink_input_peek(i, &info->chunk) < 0) - continue; - - info->volume = i->volume; - - assert(info->chunk.memblock && info->chunk.memblock->data && info->chunk.length); - info->userdata = i; - - info++; - maxinfo--; - n++; - } - - return n; -} - -static void inputs_drop(struct pa_sink *s, struct pa_mix_info *info, unsigned maxinfo, size_t length) { - assert(s && info); - - for (; maxinfo > 0; maxinfo--, info++) { - struct pa_sink_input *i = info->userdata; - assert(i && info->chunk.memblock); - - pa_memblock_unref(info->chunk.memblock); - pa_sink_input_drop(i, length); - } -} - -int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result) { - struct pa_mix_info info[MAX_MIX_CHANNELS]; - unsigned n; - size_t l; - assert(s && length && result); - - n = fill_mix_info(s, info, MAX_MIX_CHANNELS); - - if (n <= 0) - return -1; - - if (n == 1) { - uint32_t volume = PA_VOLUME_NORM; - struct pa_sink_input *i = info[0].userdata; - assert(i); - *result = info[0].chunk; - pa_memblock_ref(result->memblock); - - if (result->length > length) - result->length = length; - - l = result->length; - - if (s->volume != PA_VOLUME_NORM || info[0].volume != PA_VOLUME_NORM) - volume = pa_volume_multiply(s->volume, info[0].volume); - - if (volume != PA_VOLUME_NORM) { - pa_memchunk_make_writable(result); - pa_volume_memchunk(result, &s->sample_spec, volume); - } - } else { - result->memblock = pa_memblock_new(length); - assert(result->memblock); - - result->length = l = pa_mix(info, n, result->memblock->data, length, &s->sample_spec, s->volume); - result->index = 0; - - assert(l); - } - - inputs_drop(s, info, n, l); - - assert(s->monitor_source); - pa_source_post(s->monitor_source, result); - - return 0; -} - -int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target) { - struct pa_mix_info info[MAX_MIX_CHANNELS]; - unsigned n; - size_t l; - assert(s && target && target->length && target->memblock && target->memblock->data); - - n = fill_mix_info(s, info, MAX_MIX_CHANNELS); - - if (n <= 0) - return -1; - - if (n == 1) { - uint32_t volume = PA_VOLUME_NORM; - struct pa_sink_info *i = info[0].userdata; - assert(i); - - l = target->length; - if (l > info[0].chunk.length) - l = info[0].chunk.length; - - memcpy(target->memblock->data+target->index, info[0].chunk.memblock->data + info[0].chunk.index, l); - target->length = l; - - if (s->volume != PA_VOLUME_NORM || info[0].volume != PA_VOLUME_NORM) - volume = pa_volume_multiply(s->volume, info[0].volume); - - if (volume != PA_VOLUME_NORM) - pa_volume_memchunk(target, &s->sample_spec, volume); - } else - target->length = l = pa_mix(info, n, target->memblock->data+target->index, target->length, &s->sample_spec, s->volume); - - assert(l); - inputs_drop(s, info, n, l); - - assert(s->monitor_source); - pa_source_post(s->monitor_source, target); - - return 0; -} - -void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target) { - struct pa_memchunk chunk; - size_t l, d; - assert(s && target && target->memblock && target->length && target->memblock->data); - - l = target->length; - d = 0; - while (l > 0) { - chunk = *target; - chunk.index += d; - chunk.length -= d; - - if (pa_sink_render_into(s, &chunk) < 0) - break; - - d += chunk.length; - l -= chunk.length; - } - - if (l > 0) { - chunk = *target; - chunk.index += d; - chunk.length -= d; - pa_silence_memchunk(&chunk, &s->sample_spec); - } -} - -uint32_t pa_sink_get_latency(struct pa_sink *s) { - assert(s); - - if (!s->get_latency) - return 0; - - return s->get_latency(s); -} - -struct pa_sink* pa_sink_get_default(struct pa_core *c) { - struct pa_sink *sink; - assert(c); - - if ((sink = pa_idxset_get_by_index(c->sinks, c->default_sink_index))) - return sink; - - if (!(sink = pa_idxset_first(c->sinks, &c->default_sink_index))) - return NULL; - - fprintf(stderr, "core: default sink vanished, setting to %u.\n", sink->index); - return sink; -} - -void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m) { - sink->owner = m; - - if (sink->monitor_source) - pa_source_set_owner(sink->monitor_source, m); -} diff --git a/src/sink.h b/src/sink.h deleted file mode 100644 index 2b5d9495..00000000 --- a/src/sink.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef foosinkhfoo -#define foosinkhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -struct pa_sink; - -#include - -#include "core.h" -#include "sample.h" -#include "idxset.h" -#include "source.h" - -struct pa_sink { - uint32_t index; - - char *name, *description; - struct pa_module *owner; - struct pa_core *core; - struct pa_sample_spec sample_spec; - struct pa_idxset *inputs; - - struct pa_source *monitor_source; - - uint32_t volume; - - void (*notify)(struct pa_sink*sink); - uint32_t (*get_latency)(struct pa_sink *s); - void *userdata; -}; - -struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec); -void pa_sink_free(struct pa_sink* s); - -int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result); -int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target); -void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target); - -uint32_t pa_sink_get_latency(struct pa_sink *s); - -void pa_sink_notify(struct pa_sink*s); - -struct pa_sink* pa_sink_get_default(struct pa_core *c); - -void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m); - -#endif diff --git a/src/sioman.c b/src/sioman.c deleted file mode 100644 index 999b8a5c..00000000 --- a/src/sioman.c +++ /dev/null @@ -1,42 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#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 deleted file mode 100644 index 1b60d4a9..00000000 --- a/src/sioman.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef foosiomanhfoo -#define foosiomanhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -int pa_stdio_acquire(void); -void pa_stdio_release(void); - -#endif diff --git a/src/socket-client.c b/src/socket-client.c deleted file mode 100644 index a2187e6a..00000000 --- a/src/socket-client.c +++ /dev/null @@ -1,236 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "socket-client.h" -#include "socket-util.h" -#include "util.h" - -struct pa_socket_client { - struct pa_mainloop_api *mainloop; - int fd; - - void *io_source, *fixed_source; - void (*callback)(struct pa_socket_client*c, struct pa_iochannel *io, void *userdata); - void *userdata; -}; - -static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) { - struct pa_socket_client *c; - assert(m); - - c = malloc(sizeof(struct pa_socket_client)); - assert(c); - c->mainloop = m; - c->fd = -1; - c->io_source = c->fixed_source = NULL; - c->callback = NULL; - c->userdata = NULL; - return c; -} - -static void do_call(struct pa_socket_client *c) { - struct pa_iochannel *io; - int error, lerror; - assert(c && c->callback); - - lerror = sizeof(error); - if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &error, &lerror) < 0) { - fprintf(stderr, "getsockopt(): %s\n", strerror(errno)); - goto failed; - } - - if (lerror != sizeof(error)) { - fprintf(stderr, "getsocktop() returned invalid size.\n"); - goto failed; - } - - if (error != 0) { - fprintf(stderr, "connect(): %s\n", strerror(error)); - goto failed; - } - - io = pa_iochannel_new(c->mainloop, c->fd, c->fd); - assert(io); - c->fd = -1; - c->callback(c, io, c->userdata); - - return; - -failed: - close(c->fd); - c->fd = -1; - c->callback(c, NULL, c->userdata); - return; -} - -static void connect_fixed_cb(struct pa_mainloop_api *m, void *id, void *userdata) { - struct pa_socket_client *c = userdata; - assert(m && c && c->fixed_source == id); - m->cancel_fixed(m, c->fixed_source); - c->fixed_source = NULL; - do_call(c); -} - -static void connect_io_cb(struct pa_mainloop_api*m, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { - struct pa_socket_client *c = userdata; - assert(m && c && c->io_source == id && fd >= 0); - m->cancel_io(m, c->io_source); - c->io_source = NULL; - do_call(c); -} - -static int do_connect(struct pa_socket_client *c, const struct sockaddr *sa, socklen_t len) { - int r; - assert(c && sa && len); - - pa_make_nonblock_fd(c->fd); - - if ((r = connect(c->fd, sa, len)) < 0) { - if (errno != EINPROGRESS) { - fprintf(stderr, "connect(): %s\n", strerror(errno)); - return -1; - } - - c->io_source = c->mainloop->source_io(c->mainloop, c->fd, PA_MAINLOOP_API_IO_EVENT_OUTPUT, connect_io_cb, c); - assert(c->io_source); - } else { - c->fixed_source = c->mainloop->source_fixed(c->mainloop, connect_fixed_cb, c); - assert(c->fixed_source); - } - - return 0; -} - -struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port) { - struct pa_socket_client *c; - struct sockaddr_in sa; - assert(m && address && port); - - c = pa_socket_client_new(m); - assert(c); - - if ((c->fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - fprintf(stderr, "socket(): %s\n", strerror(errno)); - goto fail; - } - - pa_socket_tcp_low_delay(c->fd); - - sa.sin_family = AF_INET; - sa.sin_port = htons(port); - sa.sin_addr.s_addr = htonl(address); - - if (do_connect(c, (struct sockaddr*) &sa, sizeof(sa)) < 0) - goto fail; - - return c; - -fail: - pa_socket_client_free(c); - return NULL; -} - -struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename) { - struct pa_socket_client *c; - struct sockaddr_un sa; - assert(m && filename); - - c = pa_socket_client_new(m); - assert(c); - - if ((c->fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { - fprintf(stderr, "socket(): %s\n", strerror(errno)); - goto fail; - } - - pa_socket_low_delay(c->fd); - - sa.sun_family = AF_LOCAL; - strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); - sa.sun_path[sizeof(sa.sun_path) - 1] = 0; - - if (do_connect(c, (struct sockaddr*) &sa, sizeof(sa)) < 0) - goto fail; - - return c; - -fail: - pa_socket_client_free(c); - return NULL; -} - -struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) { - struct pa_socket_client *c; - assert(m && sa); - c = pa_socket_client_new(m); - assert(c); - - if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) { - fprintf(stderr, "socket(): %s\n", strerror(errno)); - goto fail; - } - - if (sa->sa_family == AF_INET) - pa_socket_tcp_low_delay(c->fd); - else - pa_socket_low_delay(c->fd); - - if (do_connect(c, sa, salen) < 0) - goto fail; - - return c; - -fail: - pa_socket_client_free(c); - return NULL; - -} - -void pa_socket_client_free(struct pa_socket_client *c) { - assert(c && c->mainloop); - if (c->io_source) - c->mainloop->cancel_io(c->mainloop, c->io_source); - if (c->fixed_source) - c->mainloop->cancel_fixed(c->mainloop, c->fixed_source); - if (c->fd >= 0) - close(c->fd); - free(c); -} - -void pa_socket_client_set_callback(struct pa_socket_client *c, void (*on_connection)(struct pa_socket_client *c, struct pa_iochannel*io, void *userdata), void *userdata) { - assert(c); - c->callback = on_connection; - c->userdata = userdata; -} diff --git a/src/socket-client.h b/src/socket-client.h deleted file mode 100644 index 2a89210e..00000000 --- a/src/socket-client.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef foosocketclienthfoo -#define foosocketclienthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include "mainloop-api.h" -#include "iochannel.h" - -/* It is safe to destroy the calling socket_client object from the callback */ - -struct pa_socket_client; - -struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port); -struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename); -struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m, const struct sockaddr *sa, size_t salen); - -void pa_socket_client_free(struct pa_socket_client *c); - -void pa_socket_client_set_callback(struct pa_socket_client *c, void (*on_connection)(struct pa_socket_client *c, struct pa_iochannel*io, void *userdata), void *userdata); - -#endif diff --git a/src/socket-server.c b/src/socket-server.c deleted file mode 100644 index 0f497377..00000000 --- a/src/socket-server.c +++ /dev/null @@ -1,209 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "socket-server.h" -#include "socket-util.h" - -struct pa_socket_server { - int fd; - char *filename; - - void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata); - void *userdata; - - void *mainloop_source; - struct pa_mainloop_api *mainloop; - enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX } type; -}; - -static void callback(struct pa_mainloop_api *mainloop, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { - struct pa_socket_server *s = userdata; - struct pa_iochannel *io; - int nfd; - assert(s && s->mainloop == mainloop && s->mainloop_source == id && id && fd >= 0 && fd == s->fd && events == PA_MAINLOOP_API_IO_EVENT_INPUT); - - if ((nfd = accept(fd, NULL, NULL)) < 0) { - fprintf(stderr, "accept(): %s\n", strerror(errno)); - return; - } - - if (!s->on_connection) { - close(nfd); - return; - } - - /* There should be a check for socket type here */ - if (s->type == SOCKET_SERVER_IPV4) - pa_socket_tcp_low_delay(fd); - else - pa_socket_low_delay(fd); - - io = pa_iochannel_new(s->mainloop, nfd, nfd); - assert(io); - s->on_connection(s, io, s->userdata); -} - -struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd) { - struct pa_socket_server *s; - assert(m && fd >= 0); - - s = malloc(sizeof(struct pa_socket_server)); - assert(s); - s->fd = fd; - s->filename = NULL; - s->on_connection = NULL; - s->userdata = NULL; - - s->mainloop = m; - s->mainloop_source = m->source_io(m, fd, PA_MAINLOOP_API_IO_EVENT_INPUT, callback, s); - assert(s->mainloop_source); - - s->type = SOCKET_SERVER_GENERIC; - - return s; -} - -struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename) { - int fd = -1; - struct sockaddr_un sa; - struct pa_socket_server *s; - - assert(m && filename); - - if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { - fprintf(stderr, "socket(): %s\n", strerror(errno)); - goto fail; - } - - sa.sun_family = AF_LOCAL; - strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); - sa.sun_path[sizeof(sa.sun_path) - 1] = 0; - - pa_socket_low_delay(fd); - - if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) { - fprintf(stderr, "bind(): %s\n", strerror(errno)); - goto fail; - } - - if (listen(fd, 5) < 0) { - fprintf(stderr, "listen(): %s\n", strerror(errno)); - goto fail; - } - - s = pa_socket_server_new(m, fd); - assert(s); - - s->filename = strdup(filename); - assert(s->filename); - - s->type = SOCKET_SERVER_UNIX; - - return s; - -fail: - if (fd >= 0) - close(fd); - - return NULL; -} - -struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port) { - struct pa_socket_server *ss; - int fd = -1; - struct sockaddr_in sa; - int on = 1; - - assert(m && port); - - if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - fprintf(stderr, "socket(): %s\n", strerror(errno)); - goto fail; - } - - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) - fprintf(stderr, "setsockopt(): %s\n", strerror(errno)); - - pa_socket_tcp_low_delay(fd); - - sa.sin_family = AF_INET; - sa.sin_port = htons(port); - sa.sin_addr.s_addr = htonl(address); - - if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { - fprintf(stderr, "bind(): %s\n", strerror(errno)); - goto fail; - } - - if (listen(fd, 5) < 0) { - fprintf(stderr, "listen(): %s\n", strerror(errno)); - goto fail; - } - - if ((ss = pa_socket_server_new(m, fd))) - ss->type = SOCKET_SERVER_IPV4; - - return ss; - -fail: - if (fd >= 0) - close(fd); - - return NULL; -} - -void pa_socket_server_free(struct pa_socket_server*s) { - assert(s); - close(s->fd); - - if (s->filename) { - unlink(s->filename); - free(s->filename); - } - - - s->mainloop->cancel_io(s->mainloop, s->mainloop_source); - - free(s); -} - -void pa_socket_server_set_callback(struct pa_socket_server*s, void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata), void *userdata) { - assert(s); - - s->on_connection = on_connection; - s->userdata = userdata; -} diff --git a/src/socket-server.h b/src/socket-server.h deleted file mode 100644 index 6661a66e..00000000 --- a/src/socket-server.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef foosocketserverhfoo -#define foosocketserverhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include "mainloop-api.h" -#include "iochannel.h" - -/* It is safe to destroy the calling socket_server object from the callback */ - -struct pa_socket_server; - -struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd); -struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename); -struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port); - -void pa_socket_server_free(struct pa_socket_server*s); - -void pa_socket_server_set_callback(struct pa_socket_server*s, void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata), void *userdata); - -#endif diff --git a/src/socket-util.c b/src/socket-util.c deleted file mode 100644 index e0a3c28d..00000000 --- a/src/socket-util.c +++ /dev/null @@ -1,216 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "socket-util.h" -#include "util.h" - -void pa_socket_peer_to_string(int fd, char *c, size_t l) { - struct stat st; - - assert(c && l && fd >= 0); - - if (fstat(fd, &st) < 0) { - snprintf(c, l, "Invalid client fd"); - return; - } - - if (S_ISSOCK(st.st_mode)) { - union { - struct sockaddr sa; - struct sockaddr_in in; - struct sockaddr_un un; - } sa; - socklen_t sa_len = sizeof(sa); - - if (getpeername(fd, &sa.sa, &sa_len) >= 0) { - - if (sa.sa.sa_family == AF_INET) { - uint32_t ip = ntohl(sa.in.sin_addr.s_addr); - - snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u", - ip >> 24, - (ip >> 16) & 0xFF, - (ip >> 8) & 0xFF, - ip & 0xFF, - ntohs(sa.in.sin_port)); - return; - } else if (sa.sa.sa_family == AF_LOCAL) { - snprintf(c, l, "UNIX socket client"); - return; - } - - } - snprintf(c, l, "Unknown network client"); - return; - } else if (S_ISCHR(st.st_mode) && (fd == 0 || fd == 1)) { - snprintf(c, l, "STDIN/STDOUT client"); - return; - } - - snprintf(c, l, "Unknown client"); -} - -int pa_socket_low_delay(int fd) { - int priority; - assert(fd >= 0); - - priority = 7; - if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) - return -1; - - return 0; -} - -int pa_socket_tcp_low_delay(int fd) { - int ret, tos; - - assert(fd >= 0); - - ret = pa_socket_low_delay(fd); - -/* on = 1; */ -/* if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) */ -/* ret = -1; */ - - tos = IPTOS_LOWDELAY; - if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0) - ret = -1; - - return ret; - -} - -int pa_socket_set_rcvbuf(int fd, size_t l) { - assert(fd >= 0); - - if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &l, sizeof(l)) < 0) - return -1; - - return 0; -} - -int pa_socket_set_sndbuf(int fd, size_t l) { - assert(fd >= 0); - - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &l, sizeof(l)) < 0) - return -1; - - return 0; -} - -int pa_unix_socket_is_stale(const char *fn) { - struct sockaddr_un sa; - int fd = -1, ret = -1; - - if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { - fprintf(stderr, "socket(): %s\n", strerror(errno)); - goto finish; - } - - sa.sun_family = AF_LOCAL; - strncpy(sa.sun_path, fn, sizeof(sa.sun_path)-1); - sa.sun_path[sizeof(sa.sun_path) - 1] = 0; - - if (connect(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) { - if (errno == ECONNREFUSED) - ret = 1; - } else - ret = 0; - -finish: - if (fd >= 0) - close(fd); - - return ret; -} - -int pa_unix_socket_remove_stale(const char *fn) { - int r; - - if ((r = pa_unix_socket_is_stale(fn)) < 0) - return errno != ENOENT ? -1 : 0; - - if (!r) - return 0; - - /* Yes, here is a race condition. But who cares? */ - if (unlink(fn) < 0) - return -1; - - return 0; -} - -int pa_unix_socket_make_secure_dir(const char *fn) { - int ret = -1; - char *slash, *dir = strdup(fn); - assert(dir); - - if (!(slash = strrchr(dir, '/'))) - goto finish; - *slash = 0; - - if (pa_make_secure_dir(dir) < 0) - goto finish; - - ret = 0; - -finish: - free(dir); - return ret; -} - -int pa_unix_socket_remove_secure_dir(const char *fn) { - int ret = -1; - char *slash, *dir = strdup(fn); - assert(dir); - - if (!(slash = strrchr(dir, '/'))) - goto finish; - *slash = 0; - - if (rmdir(dir) < 0) - goto finish; - - ret = 0; - -finish: - free(dir); - return ret; -} diff --git a/src/socket-util.h b/src/socket-util.h deleted file mode 100644 index 85133feb..00000000 --- a/src/socket-util.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef foosocketutilhfoo -#define foosocketutilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -void pa_socket_peer_to_string(int fd, char *c, size_t l); - -int pa_socket_low_delay(int fd); -int pa_socket_tcp_low_delay(int fd); - -int pa_socket_set_sndbuf(int fd, size_t l); -int pa_socket_set_rcvbuf(int fd, size_t l); - -int pa_unix_socket_is_stale(const char *fn); -int pa_unix_socket_remove_stale(const char *fn); - -int pa_unix_socket_make_secure_dir(const char *fn); -int pa_unix_socket_remove_secure_dir(const char *fn); - -#endif diff --git a/src/source-output.c b/src/source-output.c deleted file mode 100644 index 2705fdb3..00000000 --- a/src/source-output.c +++ /dev/null @@ -1,101 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "source-output.h" - -struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec) { - struct pa_source_output *o; - struct pa_resampler *resampler = NULL; - int r; - assert(s && spec); - - if (!pa_sample_spec_equal(&s->sample_spec, spec)) - if (!(resampler = pa_resampler_new(&s->sample_spec, spec))) - return NULL; - - o = malloc(sizeof(struct pa_source_output)); - assert(o); - o->name = name ? strdup(name) : NULL; - o->client = NULL; - o->owner = NULL; - o->source = s; - o->sample_spec = *spec; - - o->push = NULL; - o->kill = NULL; - o->userdata = NULL; - o->resampler = resampler; - - assert(s->core); - r = pa_idxset_put(s->core->source_outputs, o, &o->index); - assert(r == 0 && o->index != PA_IDXSET_INVALID); - r = pa_idxset_put(s->outputs, o, NULL); - assert(r == 0); - - return o; -} - -void pa_source_output_free(struct pa_source_output* o) { - assert(o); - - assert(o->source && o->source->core); - pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); - pa_idxset_remove_by_data(o->source->outputs, o, NULL); - - if (o->resampler) - pa_resampler_free(o->resampler); - - free(o->name); - free(o); -} - -void pa_source_output_kill(struct pa_source_output*i) { - assert(i); - - if (i->kill) - i->kill(i); -} - -void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk *chunk) { - struct pa_memchunk rchunk; - assert(o && chunk && chunk->length && o->push); - - if (!o->resampler) { - o->push(o, chunk); - return; - } - - pa_resampler_run(o->resampler, chunk, &rchunk); - if (!rchunk.length) - return; - - assert(rchunk.memblock); - o->push(o, &rchunk); - pa_memblock_unref(rchunk.memblock); -} diff --git a/src/source-output.h b/src/source-output.h deleted file mode 100644 index 0e6e2cfd..00000000 --- a/src/source-output.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef foosourceoutputhfoo -#define foosourceoutputhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "source.h" -#include "sample.h" -#include "memblockq.h" -#include "resampler.h" -#include "module.h" -#include "client.h" - -struct pa_source_output { - uint32_t index; - - char *name; - struct pa_module *owner; - struct pa_client *client; - struct pa_source *source; - struct pa_sample_spec sample_spec; - - void (*push)(struct pa_source_output *o, const struct pa_memchunk *chunk); - void (*kill)(struct pa_source_output* o); - - struct pa_resampler* resampler; - - void *userdata; -}; - -struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec); -void pa_source_output_free(struct pa_source_output* o); - -void pa_source_output_kill(struct pa_source_output*o); - -void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk *chunk); - -#endif diff --git a/src/source.c b/src/source.c deleted file mode 100644 index ccde0e2f..00000000 --- a/src/source.c +++ /dev/null @@ -1,131 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "source.h" -#include "source-output.h" -#include "namereg.h" - -struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec) { - struct pa_source *s; - char st[256]; - int r; - assert(core && spec && name); - - s = malloc(sizeof(struct pa_source)); - assert(s); - - if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SOURCE, s, fail))) { - free(s); - return NULL; - } - - s->name = strdup(name); - s->description = NULL; - - s->owner = NULL; - s->core = core; - s->sample_spec = *spec; - s->outputs = pa_idxset_new(NULL, NULL); - s->monitor_of = NULL; - - s->notify = NULL; - s->userdata = NULL; - - r = pa_idxset_put(core->sources, s, &s->index); - assert(s->index != PA_IDXSET_INVALID && r >= 0); - - pa_sample_snprint(st, sizeof(st), spec); - fprintf(stderr, "source: created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); - - return s; -} - -void pa_source_free(struct pa_source *s) { - struct pa_source_output *o, *j = NULL; - assert(s); - - pa_namereg_unregister(s->core, s->name); - - while ((o = pa_idxset_first(s->outputs, NULL))) { - assert(o != j); - pa_source_output_kill(o); - j = o; - } - pa_idxset_free(s->outputs, NULL, NULL); - - pa_idxset_remove_by_data(s->core->sources, s, NULL); - - fprintf(stderr, "source: freed %u \"%s\"\n", s->index, s->name); - - free(s->name); - free(s->description); - free(s); -} - -void pa_source_notify(struct pa_source*s) { - assert(s); - - if (s->notify) - s->notify(s); -} - -static int do_post(void *p, uint32_t index, int *del, void*userdata) { - struct pa_memchunk *chunk = userdata; - struct pa_source_output *o = p; - assert(o && o->push && del && chunk); - - pa_source_output_push(o, chunk); - return 0; -} - -void pa_source_post(struct pa_source*s, struct pa_memchunk *chunk) { - assert(s && chunk); - - pa_idxset_foreach(s->outputs, do_post, chunk); -} - -struct pa_source* pa_source_get_default(struct pa_core *c) { - struct pa_source *source; - assert(c); - - if ((source = pa_idxset_get_by_index(c->sources, c->default_source_index))) - return source; - - if (!(source = pa_idxset_first(c->sources, &c->default_source_index))) - return NULL; - - fprintf(stderr, "core: default source vanished, setting to %u.\n", source->index); - return source; -} - -void pa_source_set_owner(struct pa_source *s, struct pa_module *m) { - assert(s); - s->owner = m; -} diff --git a/src/source.h b/src/source.h deleted file mode 100644 index 9c584a6d..00000000 --- a/src/source.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef foosourcehfoo -#define foosourcehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -struct pa_source; - -#include -#include "core.h" -#include "sample.h" -#include "idxset.h" -#include "memblock.h" -#include "memchunk.h" -#include "sink.h" - -struct pa_source { - uint32_t index; - - char *name, *description; - struct pa_module *owner; - 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; -}; - -struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec); -void pa_source_free(struct pa_source *s); - -/* Pass a new memory block to all output streams */ -void pa_source_post(struct pa_source*s, struct pa_memchunk *b); - -void pa_source_notify(struct pa_source *s); - -struct pa_source* pa_source_get_default(struct pa_core *c); - -void pa_source_set_owner(struct pa_source *s, struct pa_module *m); - -#endif diff --git a/src/strbuf.c b/src/strbuf.c deleted file mode 100644 index c6a3772d..00000000 --- a/src/strbuf.c +++ /dev/null @@ -1,164 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "strbuf.h" - -struct chunk { - struct chunk *next; - size_t length; - char text[]; -}; - -struct pa_strbuf { - size_t length; - struct chunk *head, *tail; -}; - -struct pa_strbuf *pa_strbuf_new(void) { - struct pa_strbuf *sb = malloc(sizeof(struct pa_strbuf)); - assert(sb); - sb->length = 0; - sb->head = sb->tail = NULL; - return sb; -} - -void pa_strbuf_free(struct pa_strbuf *sb) { - assert(sb); - while (sb->head) { - struct chunk *c = sb->head; - sb->head = sb->head->next; - free(c); - } - - free(sb); -} - -char *pa_strbuf_tostring(struct pa_strbuf *sb) { - char *t, *e; - struct chunk *c; - assert(sb); - - t = malloc(sb->length+1); - assert(t); - - e = t; - for (c = sb->head; c; c = c->next) { - memcpy(e, c->text, c->length); - e += c->length; - } - - *e = 0; - - return t; -} - -char *pa_strbuf_tostring_free(struct pa_strbuf *sb) { - char *t; - assert(sb); - t = pa_strbuf_tostring(sb); - pa_strbuf_free(sb); - return t; -} - -void pa_strbuf_puts(struct pa_strbuf *sb, const char *t) { - assert(sb && t); - pa_strbuf_putsn(sb, t, 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); - - c->next = NULL; - c->length = l; - memcpy(c->text, t, l); - - if (sb->tail) { - assert(sb->head); - sb->tail->next = c; - } else { - assert(!sb->head); - sb->head = c; - } - - sb->tail = c; - sb->length += l; -} - -/* The following is based on an example from the GNU libc documentation */ - -int pa_strbuf_printf(struct pa_strbuf *sb, const char *format, ...) { - int r, size = 100; - struct chunk *c = NULL; - - assert(sb); - - for(;;) { - va_list ap; - - c = realloc(c, sizeof(struct chunk)+size); - assert(c); - - va_start(ap, format); - r = vsnprintf(c->text, size, format, ap); - va_end(ap); - - if (r > -1 && r < size) { - c->length = r; - c->next = NULL; - - if (sb->tail) { - assert(sb->head); - sb->tail->next = c; - } else { - assert(!sb->head); - sb->head = c; - } - - sb->tail = c; - sb->length += r; - - return r; - } - - if (r > -1) /* glibc 2.1 */ - size = r+1; - else /* glibc 2.0 */ - size *= 2; - } -} diff --git a/src/strbuf.h b/src/strbuf.h deleted file mode 100644 index d672c42a..00000000 --- a/src/strbuf.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef foostrbufhfoo -#define foostrbufhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -struct pa_strbuf; - -struct pa_strbuf *pa_strbuf_new(void); -void pa_strbuf_free(struct pa_strbuf *sb); -char *pa_strbuf_tostring(struct pa_strbuf *sb); -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 diff --git a/src/tagstruct.c b/src/tagstruct.c deleted file mode 100644 index 0d93c1e9..00000000 --- a/src/tagstruct.c +++ /dev/null @@ -1,241 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "tagstruct.h" - -enum tags { - TAG_STRING = 't', - TAG_U32 = 'L', - TAG_S32 = 'l', - TAG_U16 = 'S', - TAG_S16 = 's', - TAG_U8 = 'B', - TAG_S8 = 'b', - TAG_SAMPLE_SPEC = 'a', - TAG_ARBITRARY = 'x' -}; - -struct pa_tagstruct { - uint8_t *data; - size_t length, allocated; - size_t rindex; - - int dynamic; -}; - -struct pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) { - struct pa_tagstruct*t; - - assert(!data || (data && length)); - - t = malloc(sizeof(struct pa_tagstruct)); - assert(t); - t->data = (uint8_t*) data; - t->allocated = t->length = data ? length : 0; - t->rindex = 0; - t->dynamic = !data; - return t; -} - -void pa_tagstruct_free(struct pa_tagstruct*t) { - assert(t); - if (t->dynamic) - free(t->data); - free(t); -} - -uint8_t* pa_tagstruct_free_data(struct pa_tagstruct*t, size_t *l) { - uint8_t *p; - assert(t && t->dynamic && l); - p = t->data; - *l = t->length; - free(t); - return p; -} - -static void extend(struct pa_tagstruct*t, size_t l) { - assert(t && t->dynamic); - - if (l <= t->allocated) - return; - - t->data = realloc(t->data, t->allocated = l+100); - assert(t->data); -} - -void pa_tagstruct_puts(struct pa_tagstruct*t, const char *s) { - size_t l; - assert(t && s); - l = strlen(s)+2; - extend(t, l); - t->data[t->length] = TAG_STRING; - strcpy(t->data+t->length+1, s); - t->length += l; -} - -void pa_tagstruct_putu32(struct pa_tagstruct*t, uint32_t i) { - assert(t); - extend(t, 5); - t->data[t->length] = TAG_U32; - *((uint32_t*) (t->data+t->length+1)) = htonl(i); - t->length += 5; -} - -void pa_tagstruct_putu8(struct pa_tagstruct*t, uint8_t c) { - assert(t); - extend(t, 2); - t->data[t->length] = TAG_U8; - *(t->data+t->length+1) = c; - t->length += 2; -} - -void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample_spec *ss) { - assert(t && ss); - extend(t, 7); - t->data[t->length] = TAG_SAMPLE_SPEC; - t->data[t->length+1] = (uint8_t) ss->format; - t->data[t->length+2] = ss->channels; - *(uint32_t*) (t->data+t->length+3) = htonl(ss->rate); - t->length += 7; -} - - -void pa_tagstruct_put_arbitrary(struct pa_tagstruct *t, const void *p, size_t length) { - assert(t && p); - - extend(t, 5+length); - t->data[t->length] = TAG_ARBITRARY; - *((uint32_t*) (t->data+t->length+1)) = htonl(length); - if (length) - memcpy(t->data+t->length+5, p, length); - t->length += 5+length; -} - -int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s) { - int error = 0; - size_t n; - char *c; - assert(t && s); - - if (t->rindex+2 > t->length) - return -1; - - if (t->data[t->rindex] != TAG_STRING) - return -1; - - error = 1; - for (n = 0, c = (char*) (t->data+t->rindex+1); t->rindex+1+n < t->length; n++, c++) - if (!*c) { - error = 0; - break; - } - - if (error) - return -1; - - *s = (char*) (t->data+t->rindex+1); - - t->rindex += n+2; - return 0; -} - -int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i) { - assert(t && i); - - if (t->rindex+5 > t->length) - return -1; - - if (t->data[t->rindex] != TAG_U32) - return -1; - - *i = ntohl(*((uint32_t*) (t->data+t->rindex+1))); - t->rindex += 5; - return 0; -} - -int pa_tagstruct_getu8(struct pa_tagstruct*t, uint8_t *c) { - assert(t && c); - - if (t->rindex+2 > t->length) - return -1; - - if (t->data[t->rindex] != TAG_U8) - return -1; - - *c = t->data[t->rindex+1]; - t->rindex +=2; - return 0; -} - -int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec *ss) { - assert(t && ss); - - if (t->rindex+7 > t->length) - return -1; - - if (t->data[t->rindex] != TAG_SAMPLE_SPEC) - return -1; - - ss->format = t->data[t->rindex+1]; - ss->channels = t->data[t->rindex+2]; - ss->rate = ntohl(*(uint32_t*) (t->data+t->rindex+3)); - - t->rindex += 7; - return 0; -} - -int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t length) { - assert(t && p); - - if (t->rindex+5+length > t->length) - return -1; - - if (t->data[t->rindex] != TAG_ARBITRARY) - return -1; - - if (ntohl(*((uint32_t*) (t->data+t->rindex+1))) != length) - return -1; - - *p = t->data+t->rindex+5; - t->rindex += 5+length; - return 0; -} - -int pa_tagstruct_eof(struct pa_tagstruct*t) { - assert(t); - return t->rindex >= t->length; -} - -const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l) { - assert(t && t->dynamic && l); - *l = t->length; - return t->data; -} - diff --git a/src/tagstruct.h b/src/tagstruct.h deleted file mode 100644 index aefd03c4..00000000 --- a/src/tagstruct.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef footagstructhfoo -#define footagstructhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -#include "sample.h" - -struct pa_tagstruct; - -struct pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length); -void pa_tagstruct_free(struct pa_tagstruct*t); -uint8_t* pa_tagstruct_free_data(struct pa_tagstruct*t, size_t *l); - -void pa_tagstruct_puts(struct pa_tagstruct*t, const char *s); -void pa_tagstruct_putu32(struct pa_tagstruct*t, uint32_t i); -void pa_tagstruct_putu8(struct pa_tagstruct*t, uint8_t c); -void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample_spec *ss); -void pa_tagstruct_put_arbitrary(struct pa_tagstruct*t, const void *p, size_t length); - -int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s); -int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i); -int pa_tagstruct_getu8(struct pa_tagstruct*t, uint8_t *c); -int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec *ss); -int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t length); - -int pa_tagstruct_eof(struct pa_tagstruct*t); -const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l); - - - -#endif diff --git a/src/tokenizer.c b/src/tokenizer.c deleted file mode 100644 index c7f18d26..00000000 --- a/src/tokenizer.c +++ /dev/null @@ -1,89 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "tokenizer.h" -#include "dynarray.h" - -struct pa_tokenizer { - struct pa_dynarray *dynarray; -}; - -static void token_free(void *p, void *userdata) { - free(p); -} - -static void parse(struct pa_dynarray*a, const char *s, unsigned args) { - int infty = 0; - const char delimiter[] = " \t\n\r"; - const char *p; - assert(a && s); - - if (args == 0) - infty = 1; - - p = s+strspn(s, delimiter); - while (*p && (infty || args >= 2)) { - size_t l = strcspn(p, delimiter); - char *n = strndup(p, l); - assert(n); - pa_dynarray_append(a, n); - p += l; - p += strspn(p, delimiter); - args--; - } - - if (args && *p) { - char *n = strdup(p); - assert(n); - pa_dynarray_append(a, n); - } -} - -struct pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args) { - struct pa_tokenizer *t; - - t = malloc(sizeof(struct pa_tokenizer)); - assert(t); - t->dynarray = pa_dynarray_new(); - assert(t->dynarray); - - parse(t->dynarray, s, args); - return t; -} - -void pa_tokenizer_free(struct pa_tokenizer *t) { - assert(t); - pa_dynarray_free(t->dynarray, token_free, NULL); - free(t); -} - -const char *pa_tokenizer_get(struct pa_tokenizer *t, unsigned i) { - assert(t); - return pa_dynarray_get(t->dynarray, i); -} diff --git a/src/tokenizer.h b/src/tokenizer.h deleted file mode 100644 index 7d1cf9b5..00000000 --- a/src/tokenizer.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef footokenizerhfoo -#define footokenizerhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -struct pa_tokenizer; - -struct pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args); -void pa_tokenizer_free(struct pa_tokenizer *t); - -const char *pa_tokenizer_get(struct pa_tokenizer *t, unsigned i); - -#endif diff --git a/src/util.c b/src/util.c deleted file mode 100644 index 6e75c240..00000000 --- a/src/util.c +++ /dev/null @@ -1,147 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "util.h" - -void pa_make_nonblock_fd(int fd) { - int v; - - if ((v = fcntl(fd, F_GETFL)) >= 0) - if (!(v & O_NONBLOCK)) - fcntl(fd, F_SETFL, v|O_NONBLOCK); -} - -int pa_make_secure_dir(const char* dir) { - struct stat st; - - if (mkdir(dir, 0700) < 0) - if (errno != EEXIST) - return -1; - - if (lstat(dir, &st) < 0) - goto fail; - - if (!S_ISDIR(st.st_mode) || (st.st_uid != getuid()) || ((st.st_mode & 0777) != 0700)) - goto fail; - - return 0; - -fail: - rmdir(dir); - return -1; -} - -ssize_t pa_loop_read(int fd, void*data, size_t size) { - ssize_t ret = 0; - assert(fd >= 0 && data && size); - - while (size > 0) { - ssize_t r; - - if ((r = read(fd, data, size)) < 0) - return r; - - if (r == 0) - break; - - ret += r; - data += r; - size -= r; - } - - return ret; -} - -ssize_t pa_loop_write(int fd, const void*data, size_t size) { - ssize_t ret = 0; - assert(fd >= 0 && data && size); - - while (size > 0) { - ssize_t r; - - if ((r = write(fd, data, size)) < 0) - return r; - - if (r == 0) - break; - - ret += r; - data += r; - size -= r; - } - - return ret; -} - -void pa_check_for_sigpipe(void) { - struct sigaction sa; - - if (sigaction(SIGPIPE, NULL, &sa) < 0) { - fprintf(stderr, __FILE__": sigaction() failed: %s\n", strerror(errno)); - return; - } - - if (sa.sa_handler == SIG_DFL) - fprintf(stderr, "polypaudio: WARNING: SIGPIPE is not trapped. This might cause malfunction!\n"); -} - -/* The following is based on an example from the GNU libc documentation */ -char *pa_sprintf_malloc(const char *format, ...) { - int size = 100; - char *c = NULL; - - assert(format); - - for(;;) { - int r; - va_list ap; - - c = realloc(c, size); - assert(c); - - va_start(ap, format); - r = vsnprintf(c, size, format, ap); - va_end(ap); - - if (r > -1 && r < size) - return c; - - if (r > -1) /* glibc 2.1 */ - size = r+1; - else /* glibc 2.0 */ - size *= 2; - } -} diff --git a/src/util.h b/src/util.h deleted file mode 100644 index 96fde11c..00000000 --- a/src/util.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef fooutilhfoo -#define fooutilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -void pa_make_nonblock_fd(int fd); - -int pa_make_secure_dir(const char* dir); - -ssize_t pa_loop_read(int fd, void*data, size_t size); -ssize_t pa_loop_write(int fd, const void*data, size_t size); - -void pa_check_for_sigpipe(void); - -char *pa_sprintf_malloc(const char *format, ...) __attribute__ ((format (printf, 1, 2))); - -#endif -- cgit From 6601d958bfa16acef7da5eafde23161a3b2cca41 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 17 Jul 2004 14:14:41 +0000 Subject: fix Makefile.am and configure.ac to match directory renaming git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@91 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- configure.ac | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index 43009b44..1fec1ced 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,7 +18,7 @@ # USA. EXTRA_DIST = bootstrap.sh README LICENSE -SUBDIRS=src doc +SUBDIRS=polyp doc MAINTAINERCLEANFILES=README noinst_DATA = README diff --git a/configure.ac b/configure.ac index 86398f4d..3028228a 100644 --- a/configure.ac +++ b/configure.ac @@ -21,7 +21,7 @@ AC_PREREQ(2.57) AC_INIT([polypaudio],[0.1],[mzcbylcnhqvb (at) 0pointer (dot) de]) -AC_CONFIG_SRCDIR([src/main.c]) +AC_CONFIG_SRCDIR([polyp/main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) @@ -76,5 +76,5 @@ AM_CONDITIONAL([USE_LYNX], [test "x$lynx" = xyes]) AM_CONDITIONAL(BUILD_LIBPOLYPCORE, false) -AC_CONFIG_FILES([Makefile src/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html]) +AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html]) AC_OUTPUT -- cgit From 141ab85bb76c3d2a8f6f2eee91801597c98e4154 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 17 Jul 2004 15:00:31 +0000 Subject: make polypaudio run when installed update docs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@92 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 25 ++++++++++++++++++++++++- polyp/Makefile.am | 2 +- polyp/main.c | 5 ++++- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/doc/README.html.in b/doc/README.html.in index a9b07d60..b523e3dc 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -78,7 +78,10 @@ available.

Version @PACKAGE_VERSION@ is quite usable. polypaudio does not yet match all ESOUND features: currently a sample cache and -automatic releasing of unused sound drivers are missing. Have a look on the more extensive TODO list.

+automatic releasing of unused sound drivers are missing. Have a look +on the more extensive TODO +list.

Documentation

@@ -90,6 +93,26 @@ href="daemon.html">daemeon.html.

Documentation for developing with polypaudio is not yet available. Read the source, Luke!

+

First Steps

+ +

Simply start the polypaudio daemon with the argument -C

+ +
polypaudio -C
+ +

This will present you a screen like this:

+ +
Welcome to polypaudio! Use "help" for usage information.
+>>> 
+ +

Now you can issue CLI commands as described in cli.html. Another way to start +polypaudio is by specifying a configuration script on the +command line like that one included in the distribution:

+ +
polypaudio -F polypaudio.pa
+ +

This will load some drivers and protocols automatically.

+

Requirements

Currently, polypaudio is tested on Linux only. It requires an OSS or ALSA compatible soundcard.

diff --git a/polyp/Makefile.am b/polyp/Makefile.am index c4da7342..4edeeeba 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -17,7 +17,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -AM_CFLAGS=-ansi -D_GNU_SOURCE +AM_CFLAGS=-ansi -D_GNU_SOURCE -DDLSEARCHDIR=\"$(pkglibdir)\" EXTRA_DIST = polypaudio.run depmod.py bin_PROGRAMS = polypaudio pacat pactl diff --git a/polyp/main.c b/polyp/main.c index d9967cef..bcc1fada 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -125,7 +125,10 @@ int main(int argc, char *argv[]) { r = lt_dlinit(); assert(r == 0); - +#ifdef DLSEARCHDIR + lt_dladdsearchdir(DLSEARCHDIR); +#endif + mainloop = pa_mainloop_new(); assert(mainloop); -- cgit From 78a799e649b644f4c2f43bf1a1bd71cfd0f5ef45 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 17 Jul 2004 15:22:12 +0000 Subject: make distcheck clean git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@93 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 11 ++++++++--- doc/todo | 20 ++++++++++++-------- polyp/Makefile.am | 4 ++-- polyp/pacat-simple.c | 4 ++-- polyp/pacat.c | 8 ++++---- polyp/pactl.c | 8 ++++---- polyp/parec-simple.c | 4 ++-- 7 files changed, 34 insertions(+), 25 deletions(-) diff --git a/doc/README.html.in b/doc/README.html.in index b523e3dc..ad8832c6 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -10,7 +10,7 @@

polypaudio @PACKAGE_VERSION@

-

Copyright 2002-2004 Lennart Poettering <@PACKAGE_BUGREPORT@>

+

Copyright 2004 Lennart Poettering <@PACKAGE_BUGREPORT@>

  • License
  • @@ -72,7 +72,7 @@ integration with asynchronous applications using the glib/gtk mainloop. Since the asynchronous API available through polyplib is quite difficult to use there is a simplified synchronous API wrapper polyplib-simple -available.

    +available. A simple main loop implementation is available as well.

    Status

    @@ -91,7 +91,12 @@ href="cli.html">cli.html, daemeon.html.

    Documentation for developing with polypaudio is not yet -available. Read the source, Luke!

    +available. Read the source, Luke! There are some example application +available: for the asynchronous +API and for the simple, +synchronous API.

    First Steps

    diff --git a/doc/todo b/doc/todo index 5b944a36..5142c013 100644 --- a/doc/todo +++ b/doc/todo @@ -1,27 +1,31 @@ *** $Id$ *** -- documentation - -*** post 0.1 *** +*** 0.2 *** - future cancellation -- client-ui - clip cache - autoloading/autounloading -- slp/rendezvous - doxygen - make mcalign merge chunks -- modinfo + +*** 0.3 *** +- client-ui - move the global memblock statistics variables to the core - unix socket directories include user name -- more complete pactl - native library/protocol: get server layout subscription module load/unload kill client/... +- more complete pactl + +** later *** +- slp/rendezvous +- modinfo - make alsa modules use mmap -drivers: +*********** + +backends for: - libao - xmms - portaudio diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 4edeeeba..02227476 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -17,9 +17,9 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -AM_CFLAGS=-ansi -D_GNU_SOURCE -DDLSEARCHDIR=\"$(pkglibdir)\" +AM_CFLAGS=-ansi -D_GNU_SOURCE -DDLSEARCHDIR=\"$(pkglibdir)\" -I$(srcdir)/.. -EXTRA_DIST = polypaudio.run depmod.py +EXTRA_DIST = polypaudio.pa depmod.py bin_PROGRAMS = polypaudio pacat pactl noinst_PROGRAMS = pacat-simple parec-simple diff --git a/polyp/pacat-simple.c b/polyp/pacat-simple.c index 5018aa5f..f2aae2e4 100644 --- a/polyp/pacat-simple.c +++ b/polyp/pacat-simple.c @@ -28,8 +28,8 @@ #include #include -#include "polyplib-simple.h" -#include "polyplib-error.h" +#include +#include #define BUFSIZE 1024 diff --git a/polyp/pacat.c b/polyp/pacat.c index 1d1cc3d5..55a0f6b9 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -31,10 +31,10 @@ #include #include -#include "polyplib.h" -#include "polyplib-error.h" -#include "mainloop.h" -#include "mainloop-signal.h" +#include +#include +#include +#include static enum { RECORD, PLAYBACK } mode = PLAYBACK; diff --git a/polyp/pactl.c b/polyp/pactl.c index 2b1ed2c1..61060c46 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -31,10 +31,10 @@ #include #include -#include "polyplib.h" -#include "polyplib-error.h" -#include "mainloop.h" -#include "mainloop-signal.h" +#include +#include +#include +#include static struct pa_context *context = NULL; static struct pa_mainloop_api *mainloop_api = NULL; diff --git a/polyp/parec-simple.c b/polyp/parec-simple.c index c4196a14..e12b8e00 100644 --- a/polyp/parec-simple.c +++ b/polyp/parec-simple.c @@ -28,8 +28,8 @@ #include #include -#include "polyplib-simple.h" -#include "polyplib-error.h" +#include +#include #define BUFSIZE 1024 -- cgit From d6d50b0eab254d664c7998b08b84b7bce0a82b32 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 17 Jul 2004 15:44:49 +0000 Subject: some makefile fixes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@94 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 68 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 02227476..94edf616 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -18,6 +18,8 @@ # USA. AM_CFLAGS=-ansi -D_GNU_SOURCE -DDLSEARCHDIR=\"$(pkglibdir)\" -I$(srcdir)/.. +AM_LDADD=-L. +AM_LIBADD=-L. EXTRA_DIST = polypaudio.pa depmod.py bin_PROGRAMS = polypaudio pacat pactl @@ -107,36 +109,36 @@ polypaudio_SOURCES = idxset.c idxset.h \ polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) -polypaudio_LDADD = $(LIBLTDL) $(LIBSAMPLERATE_LIBS) +polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) polypaudio_LDFLAGS=-export-dynamic libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h libprotocol_simple_la_LDFLAGS = -avoid-version -libprotocol_simple_la_LIBADD = libsocket-server.la libiochannel.la +libprotocol_simple_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libsocket_server_la_SOURCES = socket-server.c socket-server.h libsocket_server_la_LDFLAGS = -avoid-version -libsocket_server_la_LIBADD = libiochannel.la libsocket-util.la +libsocket_server_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la libsocket_client_la_SOURCES = socket-client.c socket-client.h libsocket_client_la_LDFLAGS = -avoid-version -libsocket_client_la_LIBADD = libiochannel.la libsocket-util.la +libsocket_client_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la libpstream_la_SOURCES = pstream.c pstream.h libpstream_la_LDFLAGS = -avoid-version -libpstream_la_LIBADD = libpacket.la libiochannel.la +libpstream_la_LIBADD = $(AM_LIBADD) libpacket.la libiochannel.la libpstream_util_la_SOURCES = pstream-util.c pstream-util.h libpstream_util_la_LDFLAGS = -avoid-version -libpstream_util_la_LIBADD = libpacket.la libpstream.la libtagstruct.la +libpstream_util_la_LIBADD = $(AM_LIBADD) libpacket.la libpstream.la libtagstruct.la libpdispatch_la_SOURCES = pdispatch.c pdispatch.h libpdispatch_la_LDFLAGS = -avoid-version -libpdispatch_la_LIBADD = libtagstruct.la +libpdispatch_la_LIBADD = $(AM_LIBADD) libtagstruct.la libiochannel_la_SOURCES = iochannel.c iochannel.h libiochannel_la_LDFLAGS = -avoid-version -libiochannel_la_LIBADD = libsocket-util.la +libiochannel_la_LIBADD = $(AM_LIBADD) libsocket-util.la libpacket_la_SOURCES = packet.c packet.h libpacket_la_LDFLAGS = -avoid-version @@ -146,31 +148,31 @@ liboss_util_la_LDFLAGS = -avoid-version libalsa_util_la_SOURCES = alsa-util.c alsa-util.h libalsa_util_la_LDFLAGS = -avoid-version -libalsa_util_la_LIBADD = $(ASOUNDLIB_LIBS) +libalsa_util_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) libioline_la_SOURCES = ioline.c ioline.h libioline_la_LDFLAGS = -avoid-version -libioline_la_LIBADD = libiochannel.la +libioline_la_LIBADD = $(AM_LIBADD) libiochannel.la libcli_la_SOURCES = cli.c cli.h libcli_la_LDFLAGS = -avoid-version -libcli_la_LIBADD = libiochannel.la libioline.la +libcli_la_LIBADD = $(AM_LIBADD) libiochannel.la libioline.la libprotocol_cli_la_SOURCES = protocol-cli.c protocol-cli.h libprotocol_cli_la_LDFLAGS = -avoid-version -libprotocol_cli_la_LIBADD = libsocket-server.la libiochannel.la libcli.la +libprotocol_cli_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libcli.la libprotocol_native_la_SOURCES = protocol-native.c protocol-native.h native-common.h libprotocol_native_la_LDFLAGS = -avoid-version -libprotocol_native_la_LIBADD = libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la +libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libtagstruct_la_SOURCES = tagstruct.c tagstruct.h libtagstruct_la_LDFLAGS = -avoid-version libprotocol_esound_la_SOURCES = protocol-esound.c protocol-esound.h esound.h libprotocol_esound_la_LDFLAGS = -avoid-version -libprotocol_esound_la_LIBADD = libsocket-server.la libiochannel.la libauthkey.la +libprotocol_esound_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libauthkey.la libauthkey_la_SOURCES = authkey.c authkey.h libauthkey_la_LDFLAGS = -avoid-version @@ -181,68 +183,68 @@ libsocket_util_la_LDFLAGS = -avoid-version module_simple_protocol_tcp_la_SOURCES = module-protocol-stub.c module_simple_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) module_simple_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_simple_protocol_tcp_la_LIBADD = libprotocol-simple.la libsocket-server.la +module_simple_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-simple.la libsocket-server.la module_simple_protocol_unix_la_SOURCES = module-protocol-stub.c module_simple_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) module_simple_protocol_unix_la_LDFLAGS = -module -avoid-version -module_simple_protocol_unix_la_LIBADD = libprotocol-simple.la libsocket-server.la libsocket-util.la +module_simple_protocol_unix_la_LIBADD = $(AM_LIBADD) libprotocol-simple.la libsocket-server.la libsocket-util.la module_cli_protocol_tcp_la_SOURCES = module-protocol-stub.c module_cli_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) module_cli_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_cli_protocol_tcp_la_LIBADD = libprotocol-cli.la libsocket-server.la +module_cli_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-cli.la libsocket-server.la module_cli_protocol_unix_la_SOURCES = module-protocol-stub.c module_cli_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) module_cli_protocol_unix_la_LDFLAGS = -module -avoid-version -module_cli_protocol_unix_la_LIBADD = libprotocol-cli.la libsocket-server.la libsocket-util.la +module_cli_protocol_unix_la_LIBADD = $(AM_LIBADD) libprotocol-cli.la libsocket-server.la libsocket-util.la module_native_protocol_tcp_la_SOURCES = module-protocol-stub.c module_native_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) module_native_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_native_protocol_tcp_la_LIBADD = libprotocol-native.la libsocket-server.la +module_native_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-native.la libsocket-server.la module_native_protocol_unix_la_SOURCES = module-protocol-stub.c module_native_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) module_native_protocol_unix_la_LDFLAGS = -module -avoid-version -module_native_protocol_unix_la_LIBADD = libprotocol-native.la libsocket-server.la libsocket-util.la +module_native_protocol_unix_la_LIBADD = $(AM_LIBADD) libprotocol-native.la libsocket-server.la libsocket-util.la module_esound_protocol_tcp_la_SOURCES = module-protocol-stub.c module_esound_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) module_esound_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_esound_protocol_tcp_la_LIBADD = libprotocol-esound.la libsocket-server.la +module_esound_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-esound.la libsocket-server.la module_esound_protocol_unix_la_SOURCES = module-protocol-stub.c module_esound_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) module_esound_protocol_unix_la_LDFLAGS = -module -avoid-version -module_esound_protocol_unix_la_LIBADD = libprotocol-esound.la libsocket-server.la libsocket-util.la +module_esound_protocol_unix_la_LIBADD = $(AM_LIBADD) libprotocol-esound.la libsocket-server.la libsocket-util.la module_pipe_sink_la_SOURCES = module-pipe-sink.c module_pipe_sink_la_LDFLAGS = -module -avoid-version -module_pipe_sink_la_LIBADD = libiochannel.la +module_pipe_sink_la_LIBADD = $(AM_LIBADD) libiochannel.la module_alsa_sink_la_SOURCES = module-alsa-sink.c module_alsa_sink_la_LDFLAGS = -module -avoid-version -module_alsa_sink_la_LIBADD = $(ASOUNDLIB_LIBS) libalsa-util.la +module_alsa_sink_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la module_alsa_sink_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) module_alsa_source_la_SOURCES = module-alsa-source.c module_alsa_source_la_LDFLAGS = -module -avoid-version -module_alsa_source_la_LIBADD = $(ASOUNDLIB_LIBS) libalsa-util.la +module_alsa_source_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la module_alsa_source_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) module_oss_la_SOURCES = module-oss.c module_oss_la_LDFLAGS = -module -avoid-version -module_oss_la_LIBADD = libiochannel.la liboss-util.la +module_oss_la_LIBADD = $(AM_LIBADD) libiochannel.la liboss-util.la module_oss_mmap_la_SOURCES = module-oss-mmap.c module_oss_mmap_la_LDFLAGS = -module -avoid-version -module_oss_mmap_la_LIBADD = liboss-util.la +module_oss_mmap_la_LIBADD = $(AM_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 +module_cli_la_LIBADD = $(AM_LIBADD) libcli.la libiochannel.la libpolyp_la_SOURCES = polyplib.c polyplib.h \ polyplib-def.h \ @@ -275,22 +277,22 @@ libpolyp_error_la_CFLAGS = $(AM_CFLAGS) libpolyp_simple_la_SOURCES = polyplib-simple.c polyplib-simple.h libpolyp_simple_la_CFLAGS = $(AM_CFLAGS) -libpolyp_simple_la_LIBADD = libpolyp.la libpolyp-mainloop.la +libpolyp_simple_la_LIBADD = $(AM_LIBADD) libpolyp.la libpolyp-mainloop.la pacat_SOURCES = pacat.c -pacat_LDADD = libpolyp.la libpolyp-error.la libpolyp-mainloop.la +pacat_LDADD = $(AM_LDADD) libpolyp.la libpolyp-error.la libpolyp-mainloop.la pacat_CFLAGS = $(AM_CFLAGS) pactl_SOURCES = pactl.c -pactl_LDADD = libpolyp.la libpolyp-error.la libpolyp-mainloop.la +pactl_LDADD = $(AM_LDADD) libpolyp.la libpolyp-error.la libpolyp-mainloop.la pactl_CFLAGS = $(AM_CFLAGS) pacat_simple_SOURCES = pacat-simple.c -pacat_simple_LDADD = libpolyp-simple.la libpolyp-error.la +pacat_simple_LDADD = $(AM_LDADD) libpolyp-simple.la libpolyp-error.la pacat_simple_CFLAGS = $(AM_CFLAGS) parec_simple_SOURCES = parec-simple.c -parec_simple_LDADD = libpolyp-simple.la libpolyp-error.la +parec_simple_LDADD = $(AM_LDADD) libpolyp-simple.la libpolyp-error.la parec_simple_CFLAGS = $(AM_CFLAGS) if BUILD_LIBPOLYPCORE -- cgit From 765d2f70c798a4781b497fce4b4db5e5e9ab007c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 17 Jul 2004 15:48:28 +0000 Subject: two simple fixes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@95 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/modargs.c | 2 +- polyp/resampler.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/polyp/modargs.c b/polyp/modargs.c index 280a546d..ea104761 100644 --- a/polyp/modargs.c +++ b/polyp/modargs.c @@ -76,7 +76,7 @@ struct pa_modargs *pa_modargs_new(const char *args, const char* const* valid_key if (args) { enum { WHITESPACE, KEY, VALUE_START, VALUE_SIMPLE, VALUE_DOUBLE_QUOTES, VALUE_TICKS } state; const char *p, *key, *value; - size_t key_len, value_len; + size_t key_len = 0, value_len = 0; key = value = NULL; state = WHITESPACE; diff --git a/polyp/resampler.c b/polyp/resampler.c index 4f5f6be3..320d7119 100644 --- a/polyp/resampler.c +++ b/polyp/resampler.c @@ -45,7 +45,7 @@ struct pa_resampler { }; struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b) { - struct pa_resampler *r; + struct pa_resampler *r = NULL; int err; assert(a && b && pa_sample_spec_valid(a) && pa_sample_spec_valid(b)); -- cgit From 854071844fbaa5ea8d17e9e82d818c3c7cab6667 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 17 Jul 2004 16:00:46 +0000 Subject: readme update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@96 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/Makefile.am | 2 +- doc/README.html.in | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/Makefile.am b/doc/Makefile.am index d88451f5..6101521c 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -32,8 +32,8 @@ endif tidy: README.html cli.html modules.html daemon.html tidy -e < README.html tidy -e < cli.html - tidy -e < modules.html tidy -e < daemon.html + tidy -e < modules.html .PHONY: tidy diff --git a/doc/README.html.in b/doc/README.html.in index ad8832c6..296d4506 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -73,7 +73,9 @@ integration with asynchronous applications using the available through polyplib is quite difficult to use there is a simplified synchronous API wrapper polyplib-simple available. A simple main loop implementation is available as well.

    - + +

    polypaudio is the successor of my previous, ill-fated attempt to write a sound server asd.

    +

    Status

    Version @PACKAGE_VERSION@ is quite usable. polypaudio does @@ -98,7 +100,7 @@ API and for the simple, synchronous API.

    -

    First Steps

    +

    First Steps

    Simply start the polypaudio daemon with the argument -C

    -- cgit From 527faf01d0605a6ced9a73017cc8155adba59d24 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 18 Jul 2004 14:19:28 +0000 Subject: minor fixes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@97 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 1fec1ced..a54fd606 100644 --- a/Makefile.am +++ b/Makefile.am @@ -35,7 +35,7 @@ homepage: all dist test -d $$HOME/homepage/private mkdir -p $$HOME/homepage/private/projects/polypaudio cp *.tar.gz $$HOME/homepage/private/projects/polypaudio - cp doc/README.html doc/cli.html doc/daemon.html doc/modules.html doc/style.css doc/NEWS $$HOME/homepage/private/projects/polypaudio + cp doc/README.html doc/cli.html doc/daemon.html doc/modules.html doc/style.css $$HOME/homepage/private/projects/polypaudio cp $$HOME/homepage/private/projects/polypaudio/README.html $$HOME/homepage/private/projects/polypaudio/index.html distcleancheck: -- cgit From bb0b105b83c0f4ee56b4c7e9a179606aee296aa9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 20 Jul 2004 01:07:06 +0000 Subject: sample cache work git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@98 fefdeb5f-60dc-0310-8127-8f9354f1896f --- bootstrap.sh | 14 +++- doc/todo | 9 ++- polyp/Makefile.am | 3 +- polyp/cli-command.c | 59 ++++++++++++++ polyp/clitext.c | 35 +++++++++ polyp/clitext.h | 1 + polyp/core.c | 4 + polyp/core.h | 4 +- polyp/debug.h | 8 ++ polyp/hashmap.c | 14 ++++ polyp/hashmap.h | 5 ++ polyp/main.c | 2 +- polyp/modargs.c | 4 + polyp/module-alsa-sink.c | 2 +- polyp/protocol-esound.c | 194 +++++++++++++++++++++++++++++++++++++++++++---- polyp/scache.c | 181 +++++++++++++++++++++++++++++++++++++++++++ polyp/scache.h | 24 ++++++ 17 files changed, 539 insertions(+), 24 deletions(-) create mode 100644 polyp/debug.h create mode 100644 polyp/scache.c create mode 100644 polyp/scache.h diff --git a/bootstrap.sh b/bootstrap.sh index c9880d85..3592ce75 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -17,9 +17,17 @@ # along with polypaudio; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +run_versioned() { + local P + type -p "$1-$2" &> /dev/null && P="$1-$2" || local P="$1" + + shift 2 + "$P" "$@" +} + if [ "x$1" = "xam" ] ; then set -ex - automake -a -c --foreign + run_versioned automake 1.7 -a -c --foreign ./config.status else set -ex @@ -27,10 +35,10 @@ else rm -rf autom4te.cache rm -f config.cache - aclocal + run_versioned aclocal 1.7 libtoolize -c --force autoheader - automake -a -c + run_versioned automake 1.7 -a -c --foreign autoconf -Wall CFLAGS="-g -O0" ./configure --sysconfdir=/etc "$@" diff --git a/doc/todo b/doc/todo index 5142c013..76b0d312 100644 --- a/doc/todo +++ b/doc/todo @@ -1,11 +1,18 @@ *** $Id$ *** *** 0.2 *** + +- scache memory leak +- scache remove() +- scache in native protocol +- scache/debug.h copyright + - future cancellation -- clip cache - autoloading/autounloading - doxygen - make mcalign merge chunks +- autoscan +- rename clitext.[ch] to cli-text.[ch] *** 0.3 *** - client-ui diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 94edf616..d1615585 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -105,7 +105,8 @@ polypaudio_SOURCES = idxset.c idxset.h \ cli-command.c cli-command.h \ clitext.c clitext.h \ tokenizer.c tokenizer.h \ - dynarray.c dynarray.h + dynarray.c dynarray.h \ + scache.c scache.h polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) diff --git a/polyp/cli-command.c b/polyp/cli-command.c index f3a2f8a0..03bd125b 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -40,6 +40,8 @@ #include "strbuf.h" #include "namereg.h" #include "clitext.h" +#include "scache.h" +#include "sample-util.h" struct command { const char *name; @@ -67,6 +69,9 @@ static int pa_cli_command_source_default(struct pa_core *c, struct pa_tokenizer 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 int pa_cli_command_scache_play(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_scache_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_scache_list(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 }, @@ -90,6 +95,9 @@ static const struct command commands[] = { { "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}, + { "scache_list", pa_cli_command_scache_list, "List all entries in the sample cache", 2}, + { "scache_play", pa_cli_command_scache_play, "Play a sample from the sample cache (args: name, sink|index)", 3}, + { "scache_remove", pa_cli_command_scache_remove, "Remove a sample from the sample cache (args: name)", 2}, { NULL, NULL, NULL, 0 } }; @@ -199,6 +207,7 @@ static int pa_cli_command_info(struct pa_core *c, struct pa_tokenizer *t, struct 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); + pa_cli_command_scache_list(c, t, buf, fail, verbose); return 0; } @@ -429,6 +438,56 @@ static int pa_cli_command_kill_source_output(struct pa_core *c, struct pa_tokeni return 0; } +static int pa_cli_command_scache_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + char *s; + assert(c && t); + s = pa_scache_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + free(s); + return 0; +} + +static int pa_cli_command_scache_play(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + const char *n, *sink_name; + struct pa_sink *sink; + assert(c && t && buf && fail && verbose); + + if (!(n = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a sample name and a sink name.\n"); + return -1; + } + + if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK))) { + pa_strbuf_puts(buf, "No sink by that name.\n"); + return -1; + } + + if (pa_scache_play_item(c, n, sink, PA_VOLUME_NORM) < 0) { + pa_strbuf_puts(buf, "Failed to play sample.\n"); + return -1; + } + + return 0; +} + +static int pa_cli_command_scache_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + const char *n; + assert(c && t && buf && fail && verbose); + + if (!(n = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a sample name.\n"); + return -1; + } + + if (pa_scache_remove_item(c, n) < 0) { + pa_strbuf_puts(buf, "Failed to remove sample.\n"); + return -1; + } + + 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; diff --git a/polyp/clitext.c b/polyp/clitext.c index c1b9953b..d0c3f9a7 100644 --- a/polyp/clitext.c +++ b/polyp/clitext.c @@ -24,6 +24,7 @@ #endif #include +#include #include "clitext.h" #include "module.h" @@ -34,6 +35,7 @@ #include "source-output.h" #include "strbuf.h" #include "sample-util.h" +#include "scache.h" char *pa_module_list_to_string(struct pa_core *c) { struct pa_strbuf *s; @@ -201,3 +203,36 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { return pa_strbuf_tostring_free(s); } + +char *pa_scache_list_to_string(struct pa_core *c) { + struct pa_scache_entry *e; + void *state = NULL; + struct pa_strbuf *s; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u cache entries available.\n", c->scache_hashmap ? pa_hashmap_ncontents(c->scache_hashmap) : 0); + + if (c->scache_hashmap) { + + while ((e = pa_hashmap_iterate(c->scache_hashmap, &state))) { + double l; + char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + pa_sample_snprint(ss, sizeof(ss), &e->sample_spec); + + l = (double) e->memchunk.length / pa_bytes_per_second(&e->sample_spec); + + pa_strbuf_printf( + s, " name: <%s>\n\tindex: <%i>\n\tsample_spec: <%s>\n\tlength: <%u>\n\tduration: <%0.1fs>\n", + e->name, + e->index, + ss, + e->memchunk.length, + l); + } + } + + return pa_strbuf_tostring_free(s); +} diff --git a/polyp/clitext.h b/polyp/clitext.h index b1718cb5..4e5252fe 100644 --- a/polyp/clitext.h +++ b/polyp/clitext.h @@ -30,6 +30,7 @@ char *pa_sink_list_to_string(struct pa_core *core); char *pa_source_list_to_string(struct pa_core *c); char *pa_client_list_to_string(struct pa_core *c); char *pa_module_list_to_string(struct pa_core *c); +char *pa_scache_list_to_string(struct pa_core *c); #endif diff --git a/polyp/core.c b/polyp/core.c index dc9525a8..1c69f914 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -33,6 +33,7 @@ #include "source.h" #include "namereg.h" #include "util.h" +#include "scache.h" struct pa_core* pa_core_new(struct pa_mainloop_api *m) { struct pa_core* c; @@ -50,6 +51,8 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->modules = NULL; c->namereg = NULL; + c->scache_idxset = NULL; + c->scache_hashmap = NULL; c->default_sample_spec.format = PA_SAMPLE_S16NE; c->default_sample_spec.rate = 44100; @@ -82,6 +85,7 @@ void pa_core_free(struct pa_core *c) { pa_idxset_free(c->sink_inputs, NULL, NULL); pa_namereg_free(c); + pa_scache_free(c); free(c); }; diff --git a/polyp/core.h b/polyp/core.h index 99d7d76a..03b8671a 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -30,9 +30,9 @@ struct pa_core { struct pa_mainloop_api *mainloop; - struct pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules; + struct pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache_idxset; - struct pa_hashmap *namereg; + struct pa_hashmap *namereg, *scache_hashmap; uint32_t default_source_index, default_sink_index; diff --git a/polyp/debug.h b/polyp/debug.h new file mode 100644 index 00000000..fb2b889e --- /dev/null +++ b/polyp/debug.h @@ -0,0 +1,8 @@ +#ifndef foodebughfoo +#define foodebughfoo + +/* A nice trick for debuggers, working on x86 only */ + +#define DEBUG_TRAP __asm__("int $3") + +#endif diff --git a/polyp/hashmap.c b/polyp/hashmap.c index 2c7c92b5..51e3879b 100644 --- a/polyp/hashmap.c +++ b/polyp/hashmap.c @@ -168,3 +168,17 @@ int pa_hashmap_remove(struct pa_hashmap *h, const void *key) { unsigned pa_hashmap_ncontents(struct pa_hashmap *h) { return h->n_entries; } + +void *pa_hashmap_iterate(struct pa_hashmap *h, void **state) { + assert(h && state); + + if (!*state) { + *state = h->first_entry; + } else + *state = ((struct hashmap_entry*) *state)->next; + + if (!*state) + return NULL; + + return ((struct hashmap_entry*) *state)->value; +} diff --git a/polyp/hashmap.h b/polyp/hashmap.h index b24e74a5..3b79d7ae 100644 --- a/polyp/hashmap.h +++ b/polyp/hashmap.h @@ -34,4 +34,9 @@ int pa_hashmap_remove(struct pa_hashmap *h, const void *key); unsigned pa_hashmap_ncontents(struct pa_hashmap *h); +/* Maybe used to iterate through the hashmap. Initial state should + point to a NULL pointer. The hashmap may not be modified during + iteration */ +void *pa_hashmap_iterate(struct pa_hashmap *h, void **state); + #endif diff --git a/polyp/main.c b/polyp/main.c index bcc1fada..0c6104a4 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -126,7 +126,7 @@ int main(int argc, char *argv[]) { r = lt_dlinit(); assert(r == 0); #ifdef DLSEARCHDIR - lt_dladdsearchdir(DLSEARCHDIR); +/* lt_dladdsearchdir(DLSEARCHDIR);*/ #endif mainloop = pa_mainloop_new(); diff --git a/polyp/modargs.c b/polyp/modargs.c index ea104761..3841a9ec 100644 --- a/polyp/modargs.c +++ b/polyp/modargs.c @@ -36,6 +36,8 @@ #include "sink.h" #include "source.h" +#include "debug.h" + struct pa_modargs; struct entry { @@ -213,6 +215,8 @@ int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *rss struct pa_sample_spec ss; assert(ma && rss); +/* DEBUG_TRAP;*/ + ss = *rss; if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0) return -1; diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index 8a3388af..c250d1cf 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -154,7 +154,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { unsigned periods, fragsize; snd_pcm_uframes_t buffer_size; size_t frame_size; - + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { fprintf(stderr, __FILE__": failed to parse module arguments\n"); goto fail; diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 8a7c4bcb..91e6b7d6 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -39,8 +39,10 @@ #include "source-output.h" #include "source.h" #include "sample.h" - +#include "scache.h" +#include "sample-util.h" #include "authkey.h" +#include "debug.h" #define DEFAULT_COOKIE_FILE ".esd_auth" @@ -49,6 +51,10 @@ #define RECORD_BUFFER_SECONDS (5) #define RECORD_BUFFER_FRAGMENTS (100) +#define MAX_CACHE_SAMPLE_SIZE (1024000) + +#define SCACHE_PREFIX "esound~" + /* This is heavily based on esound's code */ struct connection { @@ -71,6 +77,11 @@ struct connection { struct pa_memblock *current_memblock; size_t memblock_index, fragment_size; } playback; + + + struct pa_memchunk scache_memchunk; + char *scache_name; + struct pa_sample_spec scache_sample_spec; }; struct pa_protocol_esound { @@ -105,6 +116,9 @@ static int esd_proto_get_latency(struct connection *c, esd_proto_t request, cons static int esd_proto_server_info(struct connection *c, esd_proto_t request, const void *data, size_t length); static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length); static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_sample_get_id(struct connection *c, esd_proto_t request, const void *data, size_t length); /* the big map of protocol handler info */ static struct proto_handler proto_map[ESD_PROTO_MAX] = { @@ -116,9 +130,9 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = { { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream rec" }, { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream mon" }, - { ESD_NAME_MAX + 3 * sizeof(int), NULL, "sample cache" }, - { sizeof(int), NULL, "sample free" }, - { sizeof(int), NULL, "sample play" }, + { ESD_NAME_MAX + 3 * sizeof(int), esd_proto_sample_cache, "sample cache" }, + { sizeof(int), esd_proto_sample_free_or_play, "sample free" }, + { sizeof(int), esd_proto_sample_free_or_play, "sample play" }, { sizeof(int), NULL, "sample loop" }, { sizeof(int), NULL, "sample stop" }, { -1, NULL, "TODO: sample kill" }, @@ -126,7 +140,7 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = { { ESD_KEY_LEN + sizeof(int), NULL, "standby" }, { ESD_KEY_LEN + sizeof(int), NULL, "resume" }, - { ESD_NAME_MAX, NULL, "sample getid" }, + { ESD_NAME_MAX, esd_proto_sample_get_id, "sample getid" }, { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" }, { sizeof(int), esd_proto_server_info, "server info" }, @@ -170,6 +184,10 @@ static void connection_free(struct connection *c) { if (c->fixed_source) c->protocol->core->mainloop->cancel_fixed(c->protocol->core->mainloop, c->fixed_source); + + if (c->scache_memchunk.memblock) + pa_memblock_unref(c->scache_memchunk.memblock); + free(c->scache_name); free(c); } @@ -216,6 +234,22 @@ static void* connection_write(struct connection *c, size_t length) { return c->write_data+i; } +static void format_esd2native(int format, struct pa_sample_spec *ss) { + assert(ss); + + ss->channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; + ss->format = ((format & ESD_MASK_BITS) == ESD_BITS16) ? PA_SAMPLE_S16NE : PA_SAMPLE_U8; +} + +static int format_native2esd(struct pa_sample_spec *ss) { + int format = 0; + + format = (ss->format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16; + format |= (ss->channels >= 2) ? ESD_STEREO : ESD_MONO; + + return format; +} + /*** esound commands ***/ static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length) { @@ -260,8 +294,7 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); ss.rate = rate; - ss.channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; - ss.format = ((format & ESD_MASK_BITS) == ESD_BITS16) ? PA_SAMPLE_S16NE : PA_SAMPLE_U8; + format_esd2native(format, &ss); if (!pa_sample_spec_valid(&ss)) return -1; @@ -313,8 +346,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); ss.rate = rate; - ss.channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; - ss.format = ((format & ESD_MASK_BITS) == ESD_BITS16) ? PA_SAMPLE_S16NE : PA_SAMPLE_U8; + format_esd2native(format, &ss); if (!pa_sample_spec_valid(&ss)) return -1; @@ -390,8 +422,7 @@ static int esd_proto_server_info(struct connection *c, esd_proto_t request, cons if ((sink = get_output_sink(c->protocol))) { rate = sink->sample_spec.rate; - format = (sink->sample_spec.format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16; - format |= (sink->sample_spec.channels >= 2) ? ESD_STEREO : ESD_MONO; + format = format_native2esd(&sink->sample_spec); } response = connection_write(c, sizeof(int)*3); @@ -428,8 +459,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v if (conn->sink_input) { rate = conn->sink_input->sample_spec.rate; volume = (conn->sink_input->volume*0xFF)/0x100; - format = (conn->sink_input->sample_spec.format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16; - format |= (conn->sink_input->sample_spec.channels >= 2) ? ESD_STEREO : ESD_MONO; + format = format_native2esd(&conn->sink_input->sample_spec); } /* id */ @@ -488,6 +518,103 @@ static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const return 0; } +static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, const void *data, size_t length) { + struct pa_sample_spec ss; + int format, rate; + size_t sc_length; + uint32_t index; + int *ok; + char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; + assert(c && data && length == (ESD_NAME_MAX+3*sizeof(int))); + + format = maybe_swap_endian_32(c->swap_byte_order, *(int*)data); + rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); + + ss.rate = rate; + format_esd2native(format, &ss); + + sc_length = (size_t) maybe_swap_endian_32(c->swap_byte_order, (*((int*)data + 2))); + + if (sc_length >= MAX_CACHE_SAMPLE_SIZE) + return -1; + + strcpy(name, SCACHE_PREFIX); + strncpy(name+sizeof(SCACHE_PREFIX)-1, data+3*sizeof(int), ESD_NAME_MAX); + name[sizeof(name)-1] = 0; + + assert(!c->scache_memchunk.memblock); + c->scache_memchunk.memblock = pa_memblock_new(sc_length); + c->scache_memchunk.index = 0; + c->scache_memchunk.length = sc_length; + c->scache_sample_spec = ss; + assert(!c->scache_name); + c->scache_name = strdup(name); + assert(c->scache_name); + + c->state = ESD_CACHING_SAMPLE; + + pa_scache_add_item(c->protocol->core, c->scache_name, NULL, NULL, &index); + + ok = connection_write(c, sizeof(int)); + assert(ok); + + *ok = index+1; + + return 0; +} + +static int esd_proto_sample_get_id(struct connection *c, esd_proto_t request, const void *data, size_t length) { + int *ok; + uint32_t index; + char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; + assert(c && data && length == ESD_NAME_MAX); + + ok = connection_write(c, sizeof(int)); + assert(ok); + + *ok = -1; + + strcpy(name, SCACHE_PREFIX); + strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX); + name[sizeof(name)-1] = 0; + + if ((index = pa_scache_get_id_by_name(c->protocol->core, name)) != PA_IDXSET_INVALID) + *ok = (int) index +1; + + return 0; +} + +static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length) { + int *ok; + const char *name; + uint32_t index; + assert(c && data && length == sizeof(int)); + + index = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *(int*)data)-1; + + ok = connection_write(c, sizeof(int)); + assert(ok); + + *ok = 0; + + if ((name = pa_scache_get_name_by_id(c->protocol->core, index))) { + if (request == ESD_PROTO_SAMPLE_PLAY) { + struct pa_sink *sink; + + if ((sink = get_output_sink(c->protocol))) + if (pa_scache_play_item(c->protocol->core, name, sink, PA_VOLUME_NORM) >= 0) + *ok = (int) index+1; + } else { + assert(request == ESD_PROTO_SAMPLE_FREE); + + if (pa_scache_remove_item(c->protocol->core, name) >= 0) + *ok = (int) index+1; + } + } + + return 0; +} + /*** client callbacks ***/ static void client_kill_cb(struct pa_client *c) { @@ -566,6 +693,40 @@ static int do_read(struct connection *c) { if (handler->proc(c, c->request, c->read_data, l) < 0) return -1; } + } else if (c->state == ESD_CACHING_SAMPLE) { + ssize_t r; + + assert(c->scache_memchunk.memblock && c->scache_name && c->scache_memchunk.index < c->scache_memchunk.length); + + if ((r = pa_iochannel_read(c->io, c->scache_memchunk.memblock->data+c->scache_memchunk.index, c->scache_memchunk.length-c->scache_memchunk.index)) <= 0) { + fprintf(stderr, __FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + return -1; + } + + c->scache_memchunk.index += r; + assert(c->scache_memchunk.index <= c->scache_memchunk.length); + + if (c->scache_memchunk.index == c->scache_memchunk.length) { + uint32_t index; + int *ok; + + c->scache_memchunk.index = 0; + pa_scache_add_item(c->protocol->core, c->scache_name, &c->scache_sample_spec, &c->scache_memchunk, &index); + + pa_memblock_unref(c->scache_memchunk.memblock); + c->scache_memchunk.memblock = NULL; + c->scache_memchunk.index = c->scache_memchunk.length = 0; + + free(c->scache_name); + c->scache_name = NULL; + + c->state = ESD_NEXT_REQUEST; + + ok = connection_write(c, sizeof(int)); + assert(ok); + *ok = index+1; + } + } else if (c->state == ESD_STREAMING_DATA && c->sink_input) { struct pa_memchunk chunk; ssize_t r; @@ -608,7 +769,6 @@ static int do_read(struct connection *c) { pa_memblockq_push_align(c->input_memblockq, &chunk, 0); assert(c->sink_input); pa_sink_notify(c->sink_input->sink); - } return 0; @@ -789,10 +949,14 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->playback.memblock_index = 0; c->playback.fragment_size = 0; + c->scache_memchunk.length = c->scache_memchunk.index = 0; + c->scache_memchunk.memblock = NULL; + c->scache_name = NULL; + c->fixed_source = c->protocol->core->mainloop->source_fixed(c->protocol->core->mainloop, fixed_callback, c); assert(c->fixed_source); c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 0); - + pa_idxset_put(c->protocol->connections, c, &c->index); } diff --git a/polyp/scache.c b/polyp/scache.c new file mode 100644 index 00000000..d2a84827 --- /dev/null +++ b/polyp/scache.c @@ -0,0 +1,181 @@ +#include +#include +#include + +#include "scache.h" +#include "sink-input.h" + +static void free_entry(struct pa_scache_entry *e) { + assert(e); + free(e->name); + if (e->memchunk.memblock) + pa_memblock_unref(e->memchunk.memblock); + free(e); +} + +void pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index) { + struct pa_scache_entry *e; + int put; + assert(c && name); + + if (c->scache_hashmap && (e = pa_hashmap_get(c->scache_hashmap, name))) { + put = 0; + if (e->memchunk.memblock) + pa_memblock_unref(e->memchunk.memblock); + } else { + put = 1; + e = malloc(sizeof(struct pa_scache_entry)); + assert(e); + e->name = strdup(name); + assert(e->name); + } + + if (ss) + e->sample_spec = *ss; + else + memset(&e->sample_spec, 0, sizeof(struct pa_sample_spec)); + + if (chunk) { + e->memchunk = *chunk; + pa_memblock_ref(e->memchunk.memblock); + } else { + e->memchunk.memblock = NULL; + e->memchunk.index = e->memchunk.length = 0; + } + + if (put) { + if (!c->scache_hashmap) { + c->scache_hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + assert(c->scache_hashmap); + } + + if (!c->scache_idxset) { + c->scache_idxset = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + assert(c->scache_idxset); + } + + pa_idxset_put(c->scache_idxset, e, &e->index); + pa_hashmap_put(c->scache_hashmap, e->name, e); + } + + if (index) + *index = e->index; +} + +int pa_scache_remove_item(struct pa_core *c, const char *name) { + struct pa_scache_entry *e; + assert(c && name); + + if (!c->scache_hashmap || !(e = pa_hashmap_get(c->scache_hashmap, name))) + return -1; + + pa_hashmap_remove(c->scache_hashmap, name); + pa_idxset_remove_by_index(c->scache_idxset, e->index); + free_entry(e); + return 0; +} + +static void free_cb(void *p, void *userdata) { + struct pa_scache_entry *e = p; + assert(e); + free_entry(e); +} + +void pa_scache_free(struct pa_core *c) { + assert(c); + + if (c->scache_hashmap) { + pa_hashmap_free(c->scache_hashmap, free_cb, NULL); + c->scache_hashmap = NULL; + } + + if (c->scache_idxset) { + pa_idxset_free(c->scache_idxset, NULL, NULL); + c->scache_idxset = NULL; + } +} + +static void sink_input_kill(struct pa_sink_input *i) { + struct pa_memchunk *c; + assert(i && i->userdata); + c = i->userdata; + + pa_memblock_unref(c->memblock); + free(c); + pa_sink_input_free(i); +} + +static int sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { + struct pa_memchunk *c; + assert(i && chunk && i->userdata); + c = i->userdata; + + assert(c->length && c->memblock && c->memblock->length); + *chunk = *c; + pa_memblock_ref(c->memblock); + + return 0; +} + +static void sink_input_drop(struct pa_sink_input *i, size_t length) { + struct pa_memchunk *c; + assert(i && length && i->userdata); + c = i->userdata; + + assert(length <= c->length); + + c->length -= length; + c->index += length; + + if (c->length <= 0) + sink_input_kill(i); +} + +int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sink, uint32_t volume) { + struct pa_sink_input *si; + struct pa_scache_entry *e; + struct pa_memchunk *chunk; + assert(c && name && sink); + + if (!c->scache_hashmap || !(e = pa_hashmap_get(c->scache_hashmap, name))) + return -1; + + if (!e->memchunk.memblock) + return -1; + + if (!(si = pa_sink_input_new(sink, name, &e->sample_spec))) + return -1; + + si->volume = volume; + + si->peek = sink_input_peek; + si->drop = sink_input_drop; + si->kill = sink_input_kill; + si->userdata = chunk = malloc(sizeof(struct pa_memchunk)); + assert(chunk); + *chunk = e->memchunk; + pa_memblock_ref(chunk->memblock); + + return 0; +} + +const char * pa_scache_get_name_by_id(struct pa_core *c, uint32_t id) { + struct pa_scache_entry *e; + assert(c && id != PA_IDXSET_INVALID); + + if (!c->scache_idxset || !(e = pa_idxset_get_by_index(c->scache_idxset, id))) + return NULL; + + return e->name; + +} + +uint32_t pa_scache_get_id_by_name(struct pa_core *c, const char *name) { + struct pa_scache_entry *e; + assert(c && name); + + if (!c->scache_hashmap || !(e = pa_hashmap_get(c->scache_hashmap, name))) + return PA_IDXSET_INVALID; + + return e->index; +} diff --git a/polyp/scache.h b/polyp/scache.h new file mode 100644 index 00000000..73759b81 --- /dev/null +++ b/polyp/scache.h @@ -0,0 +1,24 @@ +#ifndef fooscachehfoo +#define fooscachehfoo + +#include "core.h" +#include "memchunk.h" +#include "sink.h" + +struct pa_scache_entry { + uint32_t index; + char *name; + struct pa_sample_spec sample_spec; + struct pa_memchunk memchunk; +}; + +void pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index); + +int pa_scache_remove_item(struct pa_core *c, const char *name); +int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sink, uint32_t volume); +void pa_scache_free(struct pa_core *c); + +const char *pa_scache_get_name_by_id(struct pa_core *c, uint32_t id); +uint32_t pa_scache_get_id_by_name(struct pa_core *c, const char *name); + +#endif -- cgit From 5a694fd508d3b5d9b2433f041aa24feb5a9ebc40 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 20 Jul 2004 01:08:07 +0000 Subject: add a todo item git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@99 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/todo b/doc/todo index 76b0d312..326a64b0 100644 --- a/doc/todo +++ b/doc/todo @@ -2,6 +2,8 @@ *** 0.2 *** +- enable searchdir + - scache memory leak - scache remove() - scache in native protocol -- cgit From 8705af792b0c95ec94822b1727addb54389db674 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 2 Aug 2004 16:24:14 +0000 Subject: add new module "module-x11-bell" fix scache memory leak git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@100 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 7 +- polyp/idxset.c | 16 ++--- polyp/module-x11-bell.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++ polyp/protocol-esound.c | 2 +- polyp/scache.c | 13 +++- polyp/sink-input.c | 4 +- 6 files changed, 204 insertions(+), 15 deletions(-) create mode 100644 polyp/module-x11-bell.c diff --git a/polyp/Makefile.am b/polyp/Makefile.am index d1615585..abe1d074 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -65,7 +65,8 @@ pkglib_LTLIBRARIES=libiochannel.la \ module-esound-protocol-tcp.la \ module-esound-protocol-unix.la \ module-native-protocol-tcp.la \ - module-native-protocol-unix.la + module-native-protocol-unix.la \ + module-x11-bell.la lib_LTLIBRARIES=libpolyp.la \ libpolyp-simple.la \ @@ -247,6 +248,10 @@ module_cli_la_SOURCES = module-cli.c module_cli_la_LDFLAGS = -module -avoid-version module_cli_la_LIBADD = $(AM_LIBADD) libcli.la libiochannel.la +module_x11_bell_la_SOURCES = module-x11-bell.c +module_x11_bell_la_LDFLAGS = -module -avoid-version +module_x11_bell_la_LIBADD = $(AM_LIBADD) -lX11 -L/usr/X11R6/lib + libpolyp_la_SOURCES = polyplib.c polyplib.h \ polyplib-def.h \ tagstruct.c tagstruct.h \ diff --git a/polyp/idxset.c b/polyp/idxset.c index cecda6b7..0072e3cd 100644 --- a/polyp/idxset.c +++ b/polyp/idxset.c @@ -95,15 +95,13 @@ struct pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*com void pa_idxset_free(struct pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata) { assert(s); - if (free_func) { - while (s->iterate_list_head) { - struct idxset_entry *e = s->iterate_list_head; - s->iterate_list_head = s->iterate_list_head->iterate_next; - - if (free_func) - free_func(e->data, userdata); - free(e); - } + while (s->iterate_list_head) { + struct idxset_entry *e = s->iterate_list_head; + s->iterate_list_head = s->iterate_list_head->iterate_next; + + if (free_func) + free_func(e->data, userdata); + free(e); } free(s->hash_table); diff --git a/polyp/module-x11-bell.c b/polyp/module-x11-bell.c new file mode 100644 index 00000000..29663134 --- /dev/null +++ b/polyp/module-x11-bell.c @@ -0,0 +1,177 @@ +#include +#include +#include +#include + +#include +#include + +#include "module.h" +#include "sink.h" +#include "scache.h" +#include "modargs.h" + +struct x11_source { + void *io_source; + struct x11_source *next; +}; + +struct userdata { + struct pa_core *core; + Display *display; + struct x11_source *x11_sources; + int xkb_event_base; + + int sink_index; + char *scache_item; +}; + +static const char* const valid_modargs[] = { + "sink", + "sample", + "display", + NULL +}; + +static struct pa_sink* get_output_sink(struct userdata *u) { + struct pa_sink *s; + assert(u); + + if (!(s = pa_idxset_get_by_index(u->core->sinks, u->sink_index))) + s = pa_sink_get_default(u->core); + + u->sink_index = s ? s->index : PA_IDXSET_INVALID; + return s; +} + +static int ring_bell(struct userdata *u, int percent) { + struct pa_sink *s; + assert(u); + + if (!(s = get_output_sink(u))) { + fprintf(stderr, __FILE__": Invalid sink\n"); + return -1; + } + + if (pa_scache_play_item(u->core, u->scache_item, s, percent*2) < 0) { + fprintf(stderr, __FILE__": Failed to play sample\n"); + return -1; + } + + return 0; +} + +static void io_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { + struct userdata *u = userdata; + assert(u); + + while (XPending(u->display)) { + XEvent e; + XkbBellNotifyEvent *bne; + XNextEvent(u->display, &e); + + if (((XkbEvent*) &e)->any.xkb_type != XkbBellNotify) + continue; + + bne = ((XkbBellNotifyEvent*) &e); + + if (ring_bell(u, bne->percent) < 0) { + fprintf(stderr, __FILE__": Ringing bell failed, reverting to X11 device bell.\n"); + XkbForceDeviceBell(u->display, bne->device, bne->bell_class, bne->bell_id, bne->percent); + } + } +} + +static void new_io_source(struct userdata *u, int fd) { + struct x11_source *s; + + s = malloc(sizeof(struct x11_source)); + assert(s); + s->io_source = u->core->mainloop->source_io(u->core->mainloop, fd, PA_MAINLOOP_API_IO_EVENT_INPUT, io_callback, u); + assert(s->io_source); + s->next = u->x11_sources; + u->x11_sources = s; +} + +int pa_module_init(struct pa_core *c, struct pa_module*m) { + struct userdata *u = NULL; + struct pa_modargs *ma = NULL; + int major, minor; + unsigned int auto_ctrls, auto_values; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + fprintf(stderr, __FILE__": failed to parse module arguments\n"); + goto fail; + } + + m->userdata = u = malloc(sizeof(struct userdata)); + assert(u); + u->core = c; + u->display = NULL; + u->x11_sources = NULL; + u->scache_item = strdup(pa_modargs_get_value(ma, "sample", "bell")); + assert(u->scache_item); + + if (pa_modargs_get_sink_index(ma, c, &u->sink_index) < 0) { + fprintf(stderr, __FILE__": Invalid sink specified\n"); + goto fail; + } + + if (!(u->display = XOpenDisplay(pa_modargs_get_value(ma, "display", NULL)))) { + fprintf(stderr, __FILE__": XOpenDisplay() failed\n"); + goto fail; + } + + new_io_source(u, ConnectionNumber(u->display)); + + major = XkbMajorVersion; + minor = XkbMinorVersion; + + if (!XkbLibraryVersion(&major, &minor)) { + fprintf(stderr, __FILE__": XkbLibraryVersion() failed\n"); + goto fail; + } + + major = XkbMajorVersion; + minor = XkbMinorVersion; + + if (!XkbQueryExtension(u->display, NULL, &u->xkb_event_base, NULL, &major, &minor)) { + fprintf(stderr, __FILE__": XkbQueryExtension() failed\n"); + goto fail; + } + + XkbSelectEvents(u->display, XkbUseCoreKbd, XkbBellNotifyMask, XkbBellNotifyMask); + auto_ctrls = auto_values = XkbAudibleBellMask; + XkbSetAutoResetControls(u->display, XkbAudibleBellMask, &auto_ctrls, &auto_values); + XkbChangeEnabledControls(u->display, XkbUseCoreKbd, XkbAudibleBellMask, 0); + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + if (m->userdata) + pa_module_done(c, m); + return -1; +} + +void pa_module_done(struct pa_core *c, struct pa_module*m) { + struct userdata *u = m->userdata; + assert(c && m && u); + + while (u->x11_sources) { + struct x11_source *s = u->x11_sources; + u->x11_sources = u->x11_sources->next; + c->mainloop->cancel_io(c->mainloop, s->io_source); + free(s); + } + + free(u->scache_item); + + if (u->display) + XCloseDisplay(u->display); + free(u); +} diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 91e6b7d6..7a141d3a 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -202,7 +202,7 @@ static struct pa_sink* get_output_sink(struct pa_protocol_esound *p) { p->sink_index = s ? s->index : PA_IDXSET_INVALID; return s; } - + static struct pa_source* get_input_source(struct pa_protocol_esound *p) { struct pa_source *s; assert(p); diff --git a/polyp/scache.c b/polyp/scache.c index d2a84827..c1505046 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -1,9 +1,11 @@ #include #include #include +#include #include "scache.h" #include "sink-input.h" +#include "mainloop.h" static void free_entry(struct pa_scache_entry *e) { assert(e); @@ -70,7 +72,8 @@ int pa_scache_remove_item(struct pa_core *c, const char *name) { return -1; pa_hashmap_remove(c->scache_hashmap, name); - pa_idxset_remove_by_index(c->scache_idxset, e->index); + if (pa_idxset_remove_by_data(c->scache_idxset, e, NULL) != e) + assert(0); free_entry(e); return 0; } @@ -113,10 +116,14 @@ static int sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { assert(c->length && c->memblock && c->memblock->length); *chunk = *c; pa_memblock_ref(c->memblock); - + return 0; } +static void si_kill(void *i) { + sink_input_kill(i); +} + static void sink_input_drop(struct pa_sink_input *i, size_t length) { struct pa_memchunk *c; assert(i && length && i->userdata); @@ -128,7 +135,7 @@ static void sink_input_drop(struct pa_sink_input *i, size_t length) { c->index += length; if (c->length <= 0) - sink_input_kill(i); + pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i); } int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sink, uint32_t volume) { diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 5c2d3a13..25d8022f 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -126,12 +126,14 @@ int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { if ((ret = i->peek(i, &tchunk)) < 0) return ret; + assert(tchunk.length); + l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); if (tchunk.length > l) tchunk.length = l; i->drop(i, tchunk.length); - + pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk); pa_memblock_unref(tchunk.memblock); } -- cgit From e10b918009446186c80584273d2e3f5e84a6670b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 2 Aug 2004 19:45:02 +0000 Subject: add support for querying sample ist with esound protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@101 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - polyp/polypaudio.pa | 13 ++++++---- polyp/protocol-esound.c | 68 +++++++++++++++++++++++++++++++++++++++++++------ polyp/scache.c | 2 ++ polyp/scache.h | 1 + 5 files changed, 71 insertions(+), 14 deletions(-) diff --git a/doc/todo b/doc/todo index 326a64b0..73401e7a 100644 --- a/doc/todo +++ b/doc/todo @@ -4,7 +4,6 @@ - enable searchdir -- scache memory leak - scache remove() - scache in native protocol - scache/debug.h copyright diff --git a/polyp/polypaudio.pa b/polyp/polypaudio.pa index 177707ba..79ca83ea 100755 --- a/polyp/polypaudio.pa +++ b/polyp/polypaudio.pa @@ -19,9 +19,9 @@ # Load audio drivers -load module-alsa-sink -load module-alsa-source device=plughw:1,0 -#load module-oss device="/dev/dsp" +#load module-alsa-sink +#load module-alsa-source device=plughw:1,0 +load module-oss device="/dev/dsp" #load module-oss-mmap device="/dev/dsp" # Load several protocols @@ -30,12 +30,15 @@ load module-simple-protocol-tcp load module-native-protocol-unix load module-cli-protocol-unix +# Load X11 bell module +load module-x11-bell + # Load the CLI module load module-cli .nofail # Make some devices default -sink_default alsa_output -source_default alsa_input +sink_default oss_output +source_default oss_input diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 7a141d3a..5db0442f 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -53,7 +53,7 @@ #define MAX_CACHE_SAMPLE_SIZE (1024000) -#define SCACHE_PREFIX "esound~" +#define SCACHE_PREFIX "esound." /* This is heavily based on esound's code */ @@ -299,8 +299,10 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons if (!pa_sample_spec_valid(&ss)) return -1; - if (!(sink = get_output_sink(c->protocol))) + if (!(sink = get_output_sink(c->protocol))) { + fprintf(stderr, __FILE__": No output sink\n"); return -1; + } strncpy(name, data + sizeof(int)*2, sizeof(name)); name[sizeof(name)-1] = 0; @@ -438,6 +440,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v size_t t, k, s; struct connection *conn; size_t index = PA_IDXSET_INVALID; + unsigned nsamples; assert(c && data && length == sizeof(int)); if (esd_proto_server_info(c, request, data, length) < 0) @@ -445,7 +448,8 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v k = sizeof(int)*5+ESD_NAME_MAX; s = sizeof(int)*6+ESD_NAME_MAX; - response = connection_write(c, (t = s+k*(c->protocol->n_player+1))); + nsamples = c->protocol->core->scache_idxset ? pa_idxset_ncontents(c->protocol->core->scache_idxset) : 0; + response = connection_write(c, (t = s*(nsamples+1) + k*(c->protocol->n_player+1))); assert(k); for (conn = pa_idxset_first(c->protocol->connections, &index); conn; conn = pa_idxset_next(c->protocol->connections, &index)) { @@ -455,7 +459,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v continue; assert(t >= s+k+k); - + if (conn->sink_input) { rate = conn->sink_input->sample_spec.rate; volume = (conn->sink_input->volume*0xFF)/0x100; @@ -463,7 +467,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v } /* id */ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (int) conn->index); + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (int) (conn->index+1)); response += sizeof(int); /* name */ @@ -490,8 +494,56 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v t-= k; } - assert(t == s+k); - memset(response, 0, t); + assert(t == s*(nsamples+1)+k); + memset(response, 0, k); + response += k; + t -= k; + + if (nsamples) { + struct pa_scache_entry *ce; + + index = PA_IDXSET_INVALID; + for (ce = pa_idxset_first(c->protocol->core->scache_idxset, &index); ce; ce = pa_idxset_next(c->protocol->core->scache_idxset, &index)) { + assert(t >= s*2); + + /* id */ + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (int) (ce->index+1)); + response += sizeof(int); + + /* name */ + if (strncmp(ce->name, SCACHE_PREFIX, sizeof(SCACHE_PREFIX)-1) == 0) + strncpy(response, ce->name+sizeof(SCACHE_PREFIX)-1, ESD_NAME_MAX); + else + snprintf(response, ESD_NAME_MAX, "native.%s", ce->name); + response += ESD_NAME_MAX; + + /* rate */ + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, ce->sample_spec.rate); + response += sizeof(int); + + /* left */ + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (ce->volume*0xFF)/0x100); + response += sizeof(int); + + /*right*/ + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (ce->volume*0xFF)/0x100); + response += sizeof(int); + + /*format*/ + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, format_native2esd(&ce->sample_spec)); + response += sizeof(int); + + /*length*/ + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (int) ce->memchunk.length); + response += sizeof(int); + + t -= s; + } + } + + assert(t == s); + memset(response, 0, s); + return 0; } @@ -501,7 +553,7 @@ static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const struct connection *conn; assert(c && data && length == sizeof(int)*3); - index = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *(int*)data); + index = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *(int*)data)-1; volume = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); volume = (volume*0x100)/0xFF; diff --git a/polyp/scache.c b/polyp/scache.c index c1505046..f1f7ec5a 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -32,6 +32,8 @@ void pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_sp assert(e->name); } + e->volume = 0x100; + if (ss) e->sample_spec = *ss; else diff --git a/polyp/scache.h b/polyp/scache.h index 73759b81..a1454cea 100644 --- a/polyp/scache.h +++ b/polyp/scache.h @@ -8,6 +8,7 @@ struct pa_scache_entry { uint32_t index; char *name; + uint32_t volume; struct pa_sample_spec sample_spec; struct pa_memchunk memchunk; }; -- cgit From 24291aff27c671c11619684cb10d3b36fdf87c0d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 3 Aug 2004 19:26:56 +0000 Subject: sample cache work git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@102 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 4 + doc/todo | 12 +- polyp/Makefile.am | 15 +- polyp/cli-command.c | 55 +++++++ polyp/clitext.c | 5 +- polyp/module-alsa-sink.c | 4 +- polyp/module-alsa-source.c | 2 +- polyp/module-oss-mmap.c | 2 +- polyp/module-oss.c | 4 +- polyp/module-x11-bell.c | 2 +- polyp/native-common.h | 18 +++ polyp/pactl.c | 162 ++++++++++++++++++- polyp/pdispatch.c | 10 +- polyp/polyplib-def.h | 3 +- polyp/polyplib.c | 294 +++++++++++++++++++++++++--------- polyp/polyplib.h | 6 + polyp/protocol-esound.c | 6 +- polyp/protocol-native.c | 383 ++++++++++++++++++++++++++++++++++++--------- polyp/protocol-simple.c | 6 +- polyp/pstream.c | 7 +- polyp/resampler.c | 4 +- polyp/sample-util.c | 2 +- polyp/sample.c | 9 +- polyp/sample.h | 5 +- polyp/scache.c | 60 +------ polyp/sink.c | 2 +- polyp/source.c | 2 +- 27 files changed, 834 insertions(+), 250 deletions(-) diff --git a/configure.ac b/configure.ac index 3028228a..9e5352a5 100644 --- a/configure.ac +++ b/configure.ac @@ -46,6 +46,10 @@ PKG_CHECK_MODULES(LIBSAMPLERATE, [ samplerate >= 0.1.0 ]) AC_SUBST(LIBSAMPLERATE_CFLAGS) AC_SUBST(LIBSAMPLERATE_LIBS) +PKG_CHECK_MODULES(LIBSNDFILE, [ sndfile >= 1.0.0 ]) +AC_SUBST(LIBSNDFILE_CFLAGS) +AC_SUBST(LIBSNDFILE_LIBS) + PKG_CHECK_MODULES(ASOUNDLIB, [ alsa >= 1.0.0 ]) AC_SUBST(ASOUNDLIB_CFLAGS) AC_SUBST(ASOUNDLIB_LIBS) diff --git a/doc/todo b/doc/todo index 73401e7a..3f04bfca 100644 --- a/doc/todo +++ b/doc/todo @@ -2,16 +2,14 @@ *** 0.2 *** -- enable searchdir - -- scache remove() -- scache in native protocol -- scache/debug.h copyright - - future cancellation - autoloading/autounloading -- doxygen - make mcalign merge chunks + +- doxygen + +- scache.[ch]/module-x11-bell.c/debug.h copyright +- enable searchdir - autoscan - rename clitext.[ch] to cli-text.[ch] diff --git a/polyp/Makefile.am b/polyp/Makefile.am index abe1d074..48b984f8 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -107,11 +107,13 @@ polypaudio_SOURCES = idxset.c idxset.h \ clitext.c clitext.h \ tokenizer.c tokenizer.h \ dynarray.c dynarray.h \ - scache.c scache.h + scache.c scache.h \ + sound-file.c sound-file.h \ + play-memchunk.c play-memchunk.h -polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) +polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) -polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) +polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) polypaudio_LDFLAGS=-export-dynamic libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h @@ -270,7 +272,8 @@ libpolyp_la_SOURCES = polyplib.c polyplib.h \ memchunk.c memchunk.h \ authkey.c authkey.h \ socket-util.c socket-util.h \ - native-common.h + native-common.h \ + sample.c sample.h libpolyp_la_CFLAGS = $(AM_CFLAGS) libpolyp_mainloop_la_SOURCES = mainloop-api.h mainloop-api.c \ @@ -290,8 +293,8 @@ pacat_LDADD = $(AM_LDADD) libpolyp.la libpolyp-error.la libpolyp-mainloop.la pacat_CFLAGS = $(AM_CFLAGS) pactl_SOURCES = pactl.c -pactl_LDADD = $(AM_LDADD) libpolyp.la libpolyp-error.la libpolyp-mainloop.la -pactl_CFLAGS = $(AM_CFLAGS) +pactl_LDADD = $(AM_LDADD) libpolyp.la libpolyp-error.la libpolyp-mainloop.la $(LIBSNDFILE_LIBS) +pactl_CFLAGS = $(AM_CFLAGS) $(LIBSDNFILE_CFLAGS) pacat_simple_SOURCES = pacat-simple.c pacat_simple_LDADD = $(AM_LDADD) libpolyp-simple.la libpolyp-error.la diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 03bd125b..826789ce 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -42,6 +42,8 @@ #include "clitext.h" #include "scache.h" #include "sample-util.h" +#include "sound-file.h" +#include "play-memchunk.h" struct command { const char *name; @@ -72,6 +74,8 @@ static int pa_cli_command_kill_source_output(struct pa_core *c, struct pa_tokeni static int pa_cli_command_scache_play(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); static int pa_cli_command_scache_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); static int pa_cli_command_scache_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_play_file(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 }, @@ -98,6 +102,8 @@ static const struct command commands[] = { { "scache_list", pa_cli_command_scache_list, "List all entries in the sample cache", 2}, { "scache_play", pa_cli_command_scache_play, "Play a sample from the sample cache (args: name, sink|index)", 3}, { "scache_remove", pa_cli_command_scache_remove, "Remove a sample from the sample cache (args: name)", 2}, + { "scache_load", pa_cli_command_scache_load, "Load a sound file into the sample cache (args: filename,name)", 3}, + { "play_file", pa_cli_command_play_file, "Play a sound file (args: filename, sink|index)", 3}, { NULL, NULL, NULL, 0 } }; @@ -488,6 +494,55 @@ static int pa_cli_command_scache_remove(struct pa_core *c, struct pa_tokenizer * return 0; } +static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + const char *fname, *n; + struct pa_memchunk chunk; + struct pa_sample_spec ss; + assert(c && t && buf && fail && verbose); + + if (!(fname = pa_tokenizer_get(t, 1)) || !(n = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a file name and a sample name.\n"); + return -1; + } + + if (pa_sound_file_load(fname, &ss, &chunk) < 0) { + pa_strbuf_puts(buf, "Failed to load sound file.\n"); + return -1; + } + + pa_scache_add_item(c, n, &ss, &chunk, NULL); + pa_memblock_unref(chunk.memblock); + return 0; +} + +static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + const char *fname, *sink_name; + struct pa_memchunk chunk; + struct pa_sample_spec ss; + struct pa_sink *sink; + int ret; + assert(c && t && buf && fail && verbose); + + if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a file name and a sink name.\n"); + return -1; + } + + if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK))) { + pa_strbuf_puts(buf, "No sink by that name.\n"); + return -1; + } + + if (pa_sound_file_load(fname, &ss, &chunk) < 0) { + pa_strbuf_puts(buf, "Failed to load sound file.\n"); + return -1; + } + + ret = pa_play_memchunk(sink, fname, &ss, &chunk, PA_VOLUME_NORM); + pa_memblock_unref(chunk.memblock); + return ret; +} + int pa_cli_command_execute_line(struct pa_core *c, const char *s, struct pa_strbuf *buf, int *fail, int *verbose) { const char *cs; diff --git a/polyp/clitext.c b/polyp/clitext.c index d0c3f9a7..fbce2223 100644 --- a/polyp/clitext.c +++ b/polyp/clitext.c @@ -225,12 +225,13 @@ char *pa_scache_list_to_string(struct pa_core *c) { l = (double) e->memchunk.length / pa_bytes_per_second(&e->sample_spec); pa_strbuf_printf( - s, " name: <%s>\n\tindex: <%i>\n\tsample_spec: <%s>\n\tlength: <%u>\n\tduration: <%0.1fs>\n", + s, " name: <%s>\n\tindex: <%i>\n\tsample_spec: <%s>\n\tlength: <%u>\n\tduration: <%0.1fs>\n\tvolume: <0x%04x>\n", e->name, e->index, ss, e->memchunk.length, - l); + l, + e->volume); } } diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index c250d1cf..c1958227 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -142,7 +142,7 @@ static uint32_t sink_get_latency_cb(struct pa_sink *s) { if (frames < 0) frames = 0; - return pa_samples_usec(frames * u->frame_size, &s->sample_spec); + return pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec); } int pa_module_init(struct pa_core *c, struct pa_module*m) { @@ -165,7 +165,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { fprintf(stderr, __FILE__": failed to parse sample specification\n"); goto fail; } - frame_size = pa_sample_size(&ss); + frame_size = pa_frame_size(&ss); periods = 12; fragsize = 1024; diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index 287a0350..a453944e 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -149,7 +149,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { fprintf(stderr, __FILE__": failed to parse sample specification\n"); goto fail; } - frame_size = pa_sample_size(&ss); + frame_size = pa_frame_size(&ss); periods = 12; fragsize = 1024; diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index 800eaf25..30ff3ce6 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -198,7 +198,7 @@ static uint32_t sink_get_latency_cb(struct pa_sink *s) { assert(s && u); do_write(u); - return pa_samples_usec(u->out_fill, &s->sample_spec); + return pa_bytes_to_usec(u->out_fill, &s->sample_spec); } int pa_module_init(struct pa_core *c, struct pa_module*m) { diff --git a/polyp/module-oss.c b/polyp/module-oss.c index d727534a..51585ca9 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -153,7 +153,7 @@ static uint32_t sink_get_latency_cb(struct pa_sink *s) { return 0; } - return pa_samples_usec(arg, &s->sample_spec); + return pa_bytes_to_usec(arg, &s->sample_spec); } int pa_module_init(struct pa_core *c, struct pa_module*m) { @@ -258,7 +258,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { u->memchunk.memblock = NULL; u->memchunk.length = 0; - u->sample_size = pa_sample_size(&ss); + u->sample_size = pa_frame_size(&ss); u->out_fragment_size = out_frag_size; u->in_fragment_size = in_frag_size; diff --git a/polyp/module-x11-bell.c b/polyp/module-x11-bell.c index 29663134..4da3c880 100644 --- a/polyp/module-x11-bell.c +++ b/polyp/module-x11-bell.c @@ -110,7 +110,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { u->core = c; u->display = NULL; u->x11_sources = NULL; - u->scache_item = strdup(pa_modargs_get_value(ma, "sample", "bell")); + u->scache_item = strdup(pa_modargs_get_value(ma, "sample", "x11-bell")); assert(u->scache_item); if (pa_modargs_get_sink_index(ma, c, &u->sink_index) < 0) { diff --git a/polyp/native-common.h b/polyp/native-common.h index 2acbae8e..dc730e4b 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -41,6 +41,24 @@ enum { PA_COMMAND_RECORD_STREAM_KILLED, PA_COMMAND_STAT, PA_COMMAND_GET_PLAYBACK_LATENCY, + + PA_COMMAND_CREATE_UPLOAD_STREAM, + PA_COMMAND_DELETE_UPLOAD_STREAM, + PA_COMMAND_FINISH_UPLOAD_STREAM, + PA_COMMAND_PLAY_SAMPLE, + PA_COMMAND_REMOVE_SAMPLE, + + PA_COMMAND_GET_SINK, + PA_COMMAND_GET_SOURCE, + PA_COMMAND_GET_MODULE, + PA_COMMAND_GET_CLIENT, + PA_COMMAND_GET_SINK_INPUT, + PA_COMMAND_GET_SOURCE_OUTPUT, + PA_COMMAND_GET_SAMPLE, + + PA_COMMAND_SUBSCRIBE, + PA_COMMAND_SUBSCRIBE_EVENT, + PA_COMMAND_MAX }; diff --git a/polyp/pactl.c b/polyp/pactl.c index 61060c46..28b187b0 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -30,19 +30,37 @@ #include #include #include +#include + +#include #include #include #include #include +#include + +#define BUFSIZE 1024 static struct pa_context *context = NULL; static struct pa_mainloop_api *mainloop_api = NULL; +static char **process_argv = NULL; + +static SNDFILE *sndfile = NULL; +static struct pa_stream *sample_stream = NULL; +static struct pa_sample_spec sample_spec; +static size_t sample_length = 0; + +static char *sample_name = NULL; + static enum { NONE, EXIT, - STAT + STAT, + UPLOAD_SAMPLE, + PLAY_SAMPLE, + REMOVE_SAMPLE } action = NONE; static void quit(int ret) { @@ -78,6 +96,79 @@ static void stat_callback(struct pa_context *c, uint32_t blocks, uint32_t total, drain(); } +static void play_sample_callback(struct pa_context *c, int success, void *userdata) { + if (!success) { + fprintf(stderr, "Failed to play sample: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + drain(); +} + +static void remove_sample_callback(struct pa_context *c, int success, void *userdata) { + if (!success) { + fprintf(stderr, "Failed to remove sample: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + drain(); +} + +static void stream_die_callback(struct pa_stream *s, void *userdata) { + assert(s); + fprintf(stderr, "Stream deleted, exiting.\n"); + quit(1); +} + +static void finish_sample_callback(struct pa_stream *s, int success, void *userdata) { + assert(s); + + if (!success) { + fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(context))); + quit(1); + return; + } + + drain(); +} + +static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) { + sf_count_t l; + float *d; + assert(s && length && sndfile); + + d = malloc(length); + assert(d); + + assert(sample_length >= length); + l = length/pa_frame_size(&sample_spec); + + if ((sf_readf_float(sndfile, d, l)) != l) { + free(d); + fprintf(stderr, "Premature end of file\n"); + quit(1); + } + + pa_stream_write(s, d, length); + free(d); + + sample_length -= length; + + if (sample_length <= 0) { + pa_stream_set_write_callback(sample_stream, NULL, NULL); + pa_stream_finish_sample(sample_stream, finish_sample_callback, NULL); + } +} + +static void upload_callback(struct pa_stream *s, int success, void *userdata) { + if (!success) { + fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(context))); + quit(1); + } +} + static void context_complete_callback(struct pa_context *c, int success, void *userdata) { assert(c); @@ -90,7 +181,19 @@ static void context_complete_callback(struct pa_context *c, int success, void *u if (action == STAT) pa_context_stat(c, stat_callback, NULL); - else { + else if (action == PLAY_SAMPLE) + pa_context_play_sample(c, process_argv[2], NULL, 0x100, play_sample_callback, NULL); + else if (action == REMOVE_SAMPLE) + pa_context_remove_sample(c, process_argv[2], remove_sample_callback, NULL); + else if (action == UPLOAD_SAMPLE) { + if (!(sample_stream = pa_context_upload_sample(c, sample_name, &sample_spec, sample_length, upload_callback, NULL))) { + fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(c))); + goto fail; + } + + pa_stream_set_die_callback(sample_stream, stream_die_callback, NULL); + pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL); + } else { assert(action == EXIT); pa_context_exit(c); drain(); @@ -105,11 +208,12 @@ fail: static void exit_signal_callback(void *id, int sig, void *userdata) { fprintf(stderr, "Got SIGINT, exiting.\n"); quit(0); - } int main(int argc, char *argv[]) { struct pa_mainloop* m = NULL; + char tmp[PATH_MAX]; + int ret = 1, r; if (argc >= 2) { @@ -117,13 +221,60 @@ int main(int argc, char *argv[]) { action = STAT; else if (!strcmp(argv[1], "exit")) action = EXIT; + else if (!strcmp(argv[1], "scache_upload")) { + struct SF_INFO sfinfo; + action = UPLOAD_SAMPLE; + + if (argc < 3) { + fprintf(stderr, "Please specify a sample file to load\n"); + goto quit; + } + + if (argc >= 4) + sample_name = argv[3]; + else { + char *f = strrchr(argv[2], '/'); + if (f) + f++; + else + f = argv[2]; + + strncpy(sample_name = tmp, f, strcspn(f, ".")); + } + + memset(&sfinfo, 0, sizeof(sfinfo)); + if (!(sndfile = sf_open(argv[2], SFM_READ, &sfinfo))) { + fprintf(stderr, "Failed to open sound file.\n"); + goto quit; + } + + sample_spec.format = PA_SAMPLE_FLOAT32; + sample_spec.rate = sfinfo.samplerate; + sample_spec.channels = sfinfo.channels; + + sample_length = sfinfo.frames*pa_frame_size(&sample_spec); + } else if (!strcmp(argv[1], "scache_play")) { + action = PLAY_SAMPLE; + if (argc < 3) { + fprintf(stderr, "You have to specify a sample name to play\n"); + goto quit; + } + } else if (!strcmp(argv[1], "scache_remove")) { + action = REMOVE_SAMPLE; + if (argc < 3) { + fprintf(stderr, "You have to specify a sample name to remove\n"); + goto quit; + } + } } if (action == NONE) { - fprintf(stderr, "No valid action specified. Use one of: stat, exit\n"); + fprintf(stderr, "No valid action specified. Use one of: stat, exit, scache_upload, scache_play, scache_remove\n"); goto quit; } + process_argv = argv; + if (!(m = pa_mainloop_new())) { fprintf(stderr, "pa_mainloop_new() failed.\n"); goto quit; @@ -162,5 +313,8 @@ quit: pa_mainloop_free(m); } + if (sndfile) + sf_close(sndfile); + return ret; } diff --git a/polyp/pdispatch.c b/polyp/pdispatch.c index a28458a4..2ab98b52 100644 --- a/polyp/pdispatch.c +++ b/polyp/pdispatch.c @@ -30,6 +30,8 @@ #include "pdispatch.h" #include "native-common.h" +/*#define DEBUG_OPCODES*/ + #ifdef DEBUG_OPCODES static const char *command_names[PA_COMMAND_MAX] = { @@ -51,6 +53,11 @@ static const char *command_names[PA_COMMAND_MAX] = { [PA_COMMAND_RECORD_STREAM_KILLED] = "RECORD_STREAM_KILLED", [PA_COMMAND_STAT] = "STAT", [PA_COMMAND_GET_PLAYBACK_LATENCY] = "PLAYBACK_LATENCY", + [PA_COMMAND_CREATE_UPLOAD_STREAM] = "CREATE_UPLOAD_STREAM", + [PA_COMMAND_DELETE_UPLOAD_STREAM] = "DELETE_UPLOAD_STREAM", + [PA_COMMAND_FINISH_UPLOAD_STREAM] = "FINISH_UPLOAD_STREAM", + [PA_COMMAND_PLAY_SAMPLE] = "PLAY_SAMPLE", + [PA_COMMAND_REMOVE_SAMPLE] = "REMOVE_SAMPLE", }; #endif @@ -108,12 +115,13 @@ struct pa_pdispatch* pa_pdispatch_new(struct pa_mainloop_api *mainloop, const st pd->drain_userdata = NULL; pd->in_use = pd->shall_free = 0; + return pd; } void pa_pdispatch_free(struct pa_pdispatch *pd) { assert(pd); - + if (pd->in_use) { pd->shall_free = 1; return; diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index e43f4b35..ec2d528b 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -26,7 +26,8 @@ enum pa_stream_direction { PA_STREAM_PLAYBACK, - PA_STREAM_RECORD + PA_STREAM_RECORD, + PA_STREAM_UPLOAD }; struct pa_buffer_attr { diff --git a/polyp/polyplib.c b/polyp/polyplib.c index ea5003b4..b1052a8d 100644 --- a/polyp/polyplib.c +++ b/polyp/polyplib.c @@ -81,6 +81,12 @@ struct pa_context { void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); void *stat_userdata; + + void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); + void *play_sample_userdata; + + void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); + void *remove_sample_userdata; uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; }; @@ -92,12 +98,12 @@ struct pa_stream { char *name; struct pa_buffer_attr buffer_attr; struct pa_sample_spec sample_spec; - uint32_t device_index; uint32_t channel; int channel_valid; + uint32_t device_index; enum pa_stream_direction direction; - enum { STREAM_LOOKING_UP, STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; + enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; uint32_t requested_bytes; void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); @@ -117,6 +123,9 @@ struct pa_stream { void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); void *get_latency_userdata; + + void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); + void *finish_sample_userdata; }; static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); @@ -167,6 +176,12 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * c->stat_callback = NULL; c->stat_userdata = NULL; + c->play_sample_callback = NULL; + c->play_sample_userdata = NULL; + + c->remove_sample_callback = NULL; + c->remove_sample_userdata = NULL; + pa_check_for_sigpipe(); return c; } @@ -494,7 +509,7 @@ static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t return; s->requested_bytes += bytes; - + if (s->requested_bytes && s->write_callback) s->write_callback(s, s->requested_bytes, s->write_userdata); } @@ -517,7 +532,7 @@ static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, ui } if (pa_tagstruct_getu32(t, &s->channel) < 0 || - pa_tagstruct_getu32(t, &s->device_index) < 0 || + ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || !pa_tagstruct_eof(t)) { s->context->error = PA_ERROR_PROTOCOL; context_dead(s->context); @@ -525,14 +540,14 @@ static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, ui } s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, s); + pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); s->state = STREAM_READY; if (s->create_complete_callback) s->create_complete_callback(s, 1, s->create_complete_userdata); } -static void create_stream(struct pa_stream *s, uint32_t tdev_index) { +static void create_stream(struct pa_stream *s, const char *dev) { struct pa_tagstruct *t; uint32_t tag; assert(s); @@ -546,7 +561,8 @@ static void create_stream(struct pa_stream *s, uint32_t tdev_index) { pa_tagstruct_putu32(t, tag = s->context->ctag++); pa_tagstruct_puts(t, s->name); pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, tdev_index); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_puts(t, dev ? dev : ""); pa_tagstruct_putu32(t, s->buffer_attr.maxlength); if (s->direction == PA_STREAM_PLAYBACK) { pa_tagstruct_putu32(t, s->buffer_attr.tlength); @@ -559,49 +575,42 @@ static void create_stream(struct pa_stream *s, uint32_t tdev_index) { pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); } -static void lookup_device_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t tdev; - assert(pd && s && s->state == STREAM_LOOKING_UP); +static struct pa_stream *internal_stream_new(struct pa_context *c) { + struct pa_stream *s; - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } + s = malloc(sizeof(struct pa_stream)); + assert(s); + s->context = c; - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - return; - } + s->read_callback = NULL; + s->read_userdata = NULL; + s->write_callback = NULL; + s->write_userdata = NULL; + s->die_callback = NULL; + s->die_userdata = NULL; + s->create_complete_callback = NULL; + s->create_complete_userdata = NULL; + s->get_latency_callback = NULL; + s->get_latency_userdata = NULL; + s->finish_sample_callback = NULL; + s->finish_sample_userdata = NULL; - if (pa_tagstruct_getu32(t, &tdev) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - create_stream(s, tdev); -} + s->name = NULL; + s->state = STREAM_CREATING; + s->requested_bytes = 0; + s->channel = 0; + s->channel_valid = 0; + s->device_index = (uint32_t) -1; -static void lookup_device(struct pa_stream *s, const char *tdev) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s); + memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - s->state = STREAM_LOOKING_UP; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_LOOKUP_SINK : PA_COMMAND_LOOKUP_SOURCE); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, tdev); + s->next = c->first_stream; + if (s->next) + s->next->previous = s; + s->previous = NULL; + c->first_stream = s; - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, lookup_device_callback, s); + return s; } struct pa_stream* pa_stream_new( @@ -616,29 +625,15 @@ struct pa_stream* pa_stream_new( struct pa_stream *s; - assert(c && name && ss && c->state == CONTEXT_READY); - - s = malloc(sizeof(struct pa_stream)); + assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); + + s = internal_stream_new(c); assert(s); - s->context = c; - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->die_callback = NULL; - s->die_userdata = NULL; s->create_complete_callback = complete; - s->create_complete_userdata = NULL; - s->get_latency_callback = NULL; - s->get_latency_userdata = NULL; - + s->create_complete_userdata = userdata; s->name = strdup(name); s->state = STREAM_CREATING; - s->requested_bytes = 0; - s->channel = 0; - s->channel_valid = 0; - s->device_index = (uint32_t) -1; s->direction = dir; s->sample_spec = *ss; if (attr) @@ -651,16 +646,7 @@ struct pa_stream* pa_stream_new( s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; } - s->next = c->first_stream; - if (s->next) - s->next->previous = s; - s->previous = NULL; - c->first_stream = s; - - if (dev) - lookup_device(s, dev); - else - create_stream(s, (uint32_t) -1); + create_stream(s, dev); return s; } @@ -677,7 +663,8 @@ void pa_stream_free(struct pa_stream *s) { struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_DELETE_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : + (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); pa_tagstruct_putu32(t, s->context->ctag++); pa_tagstruct_putu32(t, s->channel); pa_pstream_send_tagstruct(s->context->pstream, t); @@ -697,7 +684,6 @@ void pa_stream_free(struct pa_stream *s) { } void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { - assert(s && cb); s->write_callback = cb; s->write_userdata = userdata; } @@ -971,3 +957,163 @@ void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, pa_pstream_send_tagstruct(p->context->pstream, t); pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); } + +struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { + struct pa_stream *s; + struct pa_tagstruct *t; + uint32_t tag; + + s = internal_stream_new(c); + assert(s); + + s->create_complete_callback = cb; + s->create_complete_userdata = userdata; + s->name = strdup(name); + s->state = STREAM_CREATING; + s->direction = PA_STREAM_UPLOAD; + s->sample_spec = *ss; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_put_sample_spec(t, ss); + pa_tagstruct_putu32(t, length); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); + + return s; +} + +static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + if (s->finish_sample_callback) + s->finish_sample_callback(s, 0, s->finish_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->finish_sample_callback) + s->finish_sample_callback(s, 1, s->finish_sample_userdata); +} + +void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(p); + + p->finish_sample_callback = cb; + p->finish_sample_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = p->context->ctag++); + pa_tagstruct_putu32(t, p->channel); + pa_pstream_send_tagstruct(p->context->pstream, t); + pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); +} + +static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->play_sample_callback) + c->play_sample_callback(c, 0, c->play_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->play_sample_callback) + c->play_sample_callback(c, 1, c->play_sample_userdata); +} + +void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c && name && *name && (!dev || *dev)); + + if (!volume) + return; + + c->play_sample_callback = cb; + c->play_sample_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_puts(t, dev ? dev : ""); + pa_tagstruct_putu32(t, volume); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); +} + +static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->remove_sample_callback) + c->remove_sample_callback(c, 0, c->remove_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->remove_sample_callback) + c->remove_sample_callback(c, 1, c->remove_sample_userdata); +} + +void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c && name); + + c->remove_sample_callback = cb; + c->remove_sample_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); +} diff --git a/polyp/polyplib.h b/polyp/polyplib.h index 440b9658..391cb0c8 100644 --- a/polyp/polyplib.h +++ b/polyp/polyplib.h @@ -91,4 +91,10 @@ void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, struct pa_context* pa_stream_get_context(struct pa_stream *p); +struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); +void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); + +void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + #endif diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 5db0442f..d80445de 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -312,7 +312,7 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons assert(!c->input_memblockq); l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); - c->input_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&ss), l/2, l/PLAYBACK_BUFFER_FRAGMENTS); + c->input_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&ss), l/2, l/PLAYBACK_BUFFER_FRAGMENTS); assert(c->input_memblockq); pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2); c->playback.fragment_size = l/10; @@ -376,7 +376,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co assert(!c->output_memblockq); l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); - c->output_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&ss), 0, 0); + c->output_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&ss), 0, 0); assert(c->output_memblockq); pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); @@ -936,7 +936,7 @@ static void sink_input_kill_cb(struct pa_sink_input *i) { static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { struct connection*c = i->userdata; assert(i && c); - return pa_samples_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); + return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); } /*** source_output callbacks ***/ diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 83c910d1..a2332a12 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -40,6 +40,7 @@ #include "pstream-util.h" #include "authkey.h" #include "namereg.h" +#include "scache.h" struct connection; struct pa_protocol_native; @@ -53,6 +54,7 @@ struct record_stream { }; struct playback_stream { + int type; struct connection *connection; uint32_t index; struct pa_sink_input *sink_input; @@ -62,13 +64,32 @@ struct playback_stream { uint32_t drain_tag; }; +struct upload_stream { + int type; + struct connection *connection; + uint32_t index; + struct pa_memchunk memchunk; + size_t length; + char *name; + struct pa_sample_spec sample_spec; +}; + +struct output_stream { + int type; +}; + +enum { + UPLOAD_STREAM, + PLAYBACK_STREAM +}; + struct connection { int authorized; struct pa_protocol_native *protocol; struct pa_client *client; struct pa_pstream *pstream; struct pa_pdispatch *pdispatch; - struct pa_idxset *record_streams, *playback_streams; + struct pa_idxset *record_streams, *output_streams; uint32_t rrobin_index; }; @@ -93,25 +114,28 @@ static void source_output_push_cb(struct pa_source_output *o, const struct pa_me static void command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_delete_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_delete_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_delete_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_create_upload_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_finish_upload_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_play_sample(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_remove_sample(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = { NULL }, [PA_COMMAND_TIMEOUT] = { NULL }, [PA_COMMAND_REPLY] = { NULL }, [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { command_create_playback_stream }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { command_delete_playback_stream }, + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { command_delete_stream }, [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = { command_drain_playback_stream }, [PA_COMMAND_CREATE_RECORD_STREAM] = { command_create_record_stream }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { command_delete_record_stream }, + [PA_COMMAND_DELETE_RECORD_STREAM] = { command_delete_stream }, [PA_COMMAND_AUTH] = { command_auth }, [PA_COMMAND_REQUEST] = { NULL }, [PA_COMMAND_EXIT] = { command_exit }, @@ -120,11 +144,51 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_LOOKUP_SOURCE] = { command_lookup }, [PA_COMMAND_STAT] = { command_stat }, [PA_COMMAND_GET_PLAYBACK_LATENCY] = { command_get_playback_latency }, + [PA_COMMAND_CREATE_UPLOAD_STREAM] = { command_create_upload_stream }, + [PA_COMMAND_DELETE_UPLOAD_STREAM] = { command_delete_stream }, + [PA_COMMAND_FINISH_UPLOAD_STREAM] = { command_finish_upload_stream }, + [PA_COMMAND_PLAY_SAMPLE] = { command_play_sample }, + [PA_COMMAND_REMOVE_SAMPLE] = { command_remove_sample }, }; /* structure management */ -static struct record_stream* record_stream_new(struct connection *c, struct pa_source *source, struct pa_sample_spec *ss, const char *name, size_t maxlength, size_t fragment_size) { +static struct upload_stream* upload_stream_new(struct connection *c, const struct pa_sample_spec *ss, const char *name, size_t length) { + struct upload_stream *s; + assert(c && ss && name && length); + + s = malloc(sizeof(struct upload_stream)); + assert (s); + s->type = UPLOAD_STREAM; + s->connection = c; + s->sample_spec = *ss; + s->name = strdup(name); + assert(s->name); + + s->memchunk.memblock = NULL; + s->memchunk.index = 0; + s->memchunk.length = 0; + + s->length = length; + + pa_idxset_put(c->output_streams, s, &s->index); + return s; +} + +static void upload_stream_free(struct upload_stream *o) { + assert(o && o->connection); + + pa_idxset_remove_by_data(o->connection->output_streams, o, NULL); + + free(o->name); + + if (o->memchunk.memblock) + pa_memblock_unref(o->memchunk.memblock); + + free(o); +} + +static struct record_stream* record_stream_new(struct connection *c, struct pa_source *source, const struct pa_sample_spec *ss, const char *name, size_t maxlength, size_t fragment_size) { struct record_stream *s; struct pa_source_output *source_output; size_t base; @@ -143,7 +207,7 @@ static struct record_stream* record_stream_new(struct connection *c, struct pa_s s->source_output->owner = c->protocol->module; s->source_output->client = c->client; - s->memblockq = pa_memblockq_new(maxlength, 0, base = pa_sample_size(ss), 0, 0); + s->memblockq = pa_memblockq_new(maxlength, 0, base = pa_frame_size(ss), 0, 0); assert(s->memblockq); s->fragment_size = (fragment_size/base)*base; @@ -163,7 +227,7 @@ static void record_stream_free(struct record_stream* r) { free(r); } -static struct playback_stream* playback_stream_new(struct connection *c, struct pa_sink *sink, struct pa_sample_spec *ss, const char *name, +static struct playback_stream* playback_stream_new(struct connection *c, struct pa_sink *sink, const struct pa_sample_spec *ss, const char *name, size_t maxlength, size_t tlength, size_t prebuf, @@ -177,6 +241,7 @@ static struct playback_stream* playback_stream_new(struct connection *c, struct s = malloc(sizeof(struct playback_stream)); assert (s); + s->type = PLAYBACK_STREAM; s->connection = c; s->sink_input = sink_input; @@ -188,13 +253,13 @@ static struct playback_stream* playback_stream_new(struct connection *c, struct s->sink_input->owner = c->protocol->module; s->sink_input->client = c->client; - s->memblockq = pa_memblockq_new(maxlength, tlength, pa_sample_size(ss), prebuf, minreq); + s->memblockq = pa_memblockq_new(maxlength, tlength, pa_frame_size(ss), prebuf, minreq); assert(s->memblockq); s->requested_bytes = 0; s->drain_request = 0; - pa_idxset_put(c->playback_streams, s, &s->index); + pa_idxset_put(c->output_streams, s, &s->index); return s; } @@ -204,7 +269,7 @@ static void playback_stream_free(struct playback_stream* p) { if (p->drain_request) pa_pstream_send_error(p->connection->pstream, p->drain_tag, PA_ERROR_NOENTITY); - pa_idxset_remove_by_data(p->connection->playback_streams, p, NULL); + pa_idxset_remove_by_data(p->connection->output_streams, p, NULL); pa_sink_input_free(p->sink_input); pa_memblockq_free(p->memblockq); free(p); @@ -212,7 +277,7 @@ static void playback_stream_free(struct playback_stream* p) { static void connection_free(struct connection *c) { struct record_stream *r; - struct playback_stream *p; + struct output_stream *o; assert(c && c->protocol); pa_idxset_remove_by_data(c->protocol->connections, c, NULL); @@ -220,9 +285,12 @@ static void connection_free(struct connection *c) { record_stream_free(r); pa_idxset_free(c->record_streams, NULL, NULL); - while ((p = pa_idxset_first(c->playback_streams, NULL))) - playback_stream_free(p); - pa_idxset_free(c->playback_streams, NULL, NULL); + while ((o = pa_idxset_first(c->output_streams, NULL))) + if (o->type == PLAYBACK_STREAM) + playback_stream_free((struct playback_stream*) o); + else + upload_stream_free((struct upload_stream*) o); + pa_idxset_free(c->output_streams, NULL, NULL); pa_pdispatch_free(c->pdispatch); pa_pstream_free(c->pstream); @@ -351,7 +419,7 @@ static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { assert(i && i->userdata); s = i->userdata; - return pa_samples_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec); + return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec); } /*** source_output callbacks ***/ @@ -384,7 +452,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com struct playback_stream *s; size_t maxlength, tlength, prebuf, minreq; uint32_t sink_index; - const char *name; + const char *name, *sink_name; struct pa_sample_spec ss; struct pa_tagstruct *reply; struct pa_sink *sink; @@ -393,6 +461,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com if (pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_get_sample_spec(t, &ss) < 0 || pa_tagstruct_getu32(t, &sink_index) < 0 || + pa_tagstruct_gets(t, &sink_name) < 0 || pa_tagstruct_getu32(t, &maxlength) < 0 || pa_tagstruct_getu32(t, &tlength) < 0 || pa_tagstruct_getu32(t, &prebuf) < 0 || @@ -407,10 +476,12 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com return; } - if (sink_index == (uint32_t) -1) + if (!*sink_name || sink_index == (uint32_t) -1) sink = pa_sink_get_default(c->protocol->core); - else + else if (sink_index != (uint32_t) -1) sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); + else + sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK); if (!sink) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); @@ -433,10 +504,9 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com request_bytes(s); } -static void command_delete_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_delete_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; uint32_t channel; - struct playback_stream *s; assert(c && t); if (pa_tagstruct_getu32(t, &channel) < 0 || @@ -449,13 +519,34 @@ static void command_delete_playback_stream(struct pa_pdispatch *pd, uint32_t com pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); return; } - - if (!(s = pa_idxset_get_by_index(c->playback_streams, channel))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); - return; - } - playback_stream_free(s); + if (command == PA_COMMAND_DELETE_PLAYBACK_STREAM) { + struct playback_stream *s; + if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != PLAYBACK_STREAM)) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + return; + } + + playback_stream_free(s); + } else if (command == PA_COMMAND_DELETE_RECORD_STREAM) { + struct record_stream *s; + if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + return; + } + + record_stream_free(s); + } else { + struct upload_stream *s; + assert(command == PA_COMMAND_DELETE_UPLOAD_STREAM); + if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != UPLOAD_STREAM)) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + return; + } + + upload_stream_free(s); + } + pa_pstream_send_simple_ack(c->pstream, tag); } @@ -464,7 +555,7 @@ static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t comma struct record_stream *s; size_t maxlength, fragment_size; uint32_t source_index; - const char *name; + const char *name, *source_name; struct pa_sample_spec ss; struct pa_tagstruct *reply; struct pa_source *source; @@ -473,6 +564,7 @@ static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t comma if (pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_get_sample_spec(t, &ss) < 0 || pa_tagstruct_getu32(t, &source_index) < 0 || + pa_tagstruct_gets(t, &source_name) < 0 || pa_tagstruct_getu32(t, &maxlength) < 0 || pa_tagstruct_getu32(t, &fragment_size) < 0 || !pa_tagstruct_eof(t)) { @@ -485,10 +577,12 @@ static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t comma return; } - if (source_index == (uint32_t) -1) + if (!*source_name || source_index == (uint32_t) -1) source = pa_source_get_default(c->protocol->core); - else + else if (source_index != (uint32_t) -1) source = pa_idxset_get_by_index(c->protocol->core->sources, source_index); + else + source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE); if (!source) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); @@ -510,32 +604,6 @@ static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t comma pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_delete_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t channel; - struct record_stream *s; - assert(c && t); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); - return; - } - - record_stream_free(s); - pa_pstream_send_simple_ack(c->pstream, tag); -} - static void command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; assert(c && t); @@ -652,7 +720,7 @@ static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t comm return; } - if (!(s = pa_idxset_get_by_index(c->playback_streams, index))) { + if (!(s = pa_idxset_get_by_index(c->output_streams, index)) || s->type != PLAYBACK_STREAM) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -709,7 +777,7 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma return; } - if (!(s = pa_idxset_get_by_index(c->playback_streams, index))) { + if (!(s = pa_idxset_get_by_index(c->output_streams, index)) || s->type != PLAYBACK_STREAM) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -723,6 +791,147 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma pa_pstream_send_tagstruct(c->pstream, reply); } +static void command_create_upload_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + struct upload_stream *s; + size_t length; + const char *name; + struct pa_sample_spec ss; + struct pa_tagstruct *reply; + assert(c && t && c->protocol && c->protocol->core); + + if (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_getu32(t, &length) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if ((length % pa_frame_size(&ss)) != 0 || length <= 0 || !*name) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); + return; + } + + if (!(s = upload_stream_new(c, &ss, name, length))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, s->index); + pa_pstream_send_tagstruct(c->pstream, reply); + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REQUEST); + pa_tagstruct_putu32(reply, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(reply, s->index); + pa_tagstruct_putu32(reply, length); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_finish_upload_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t channel; + struct upload_stream *s; + uint32_t index; + assert(c && t); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != UPLOAD_STREAM)) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + return; + } + + pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->memchunk, &index); + pa_pstream_send_simple_ack(c->pstream, tag); + upload_stream_free(s); +} + +static void command_play_sample(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t sink_index, volume; + struct pa_sink *sink; + const char *name, *sink_name; + assert(c && t); + + if (pa_tagstruct_getu32(t, &sink_index) < 0 || + pa_tagstruct_gets(t, &sink_name) < 0 || + pa_tagstruct_getu32(t, &volume) < 0 || + pa_tagstruct_gets(t, &name) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!*sink_name && sink_index == (uint32_t) -1) + sink = pa_sink_get_default(c->protocol->core); + else if (sink_index != (uint32_t) -1) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); + else + sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK); + + if (!sink) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + if (pa_scache_play_item(c->protocol->core, name, sink, volume) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_remove_sample(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const char *name; + assert(c && t); + + if (pa_tagstruct_gets(t, &name) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (pa_scache_remove_item(c->protocol->core, name) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + /*** pstream callbacks ***/ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { @@ -737,25 +946,55 @@ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *pack static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { struct connection *c = userdata; - struct playback_stream *stream; + struct output_stream *stream; assert(p && chunk && userdata); - if (!(stream = pa_idxset_get_by_index(c->playback_streams, channel))) { + if (!(stream = pa_idxset_get_by_index(c->output_streams, channel))) { fprintf(stderr, "protocol-native: client sent block for invalid stream.\n"); connection_free(c); return; } - if (chunk->length >= stream->requested_bytes) - stream->requested_bytes = 0; - else - stream->requested_bytes -= chunk->length; - - pa_memblockq_push_align(stream->memblockq, chunk, delta); - assert(stream->sink_input); - pa_sink_notify(stream->sink_input->sink); - - /*fprintf(stderr, "Recieved %u bytes.\n", chunk->length);*/ + if (stream->type == PLAYBACK_STREAM) { + struct playback_stream *p = (struct playback_stream*) stream; + if (chunk->length >= p->requested_bytes) + p->requested_bytes = 0; + else + p->requested_bytes -= chunk->length; + + pa_memblockq_push_align(p->memblockq, chunk, delta); + assert(p->sink_input); + pa_sink_notify(p->sink_input->sink); + /*fprintf(stderr, "Recieved %u bytes.\n", chunk->length);*/ + } else { + struct upload_stream *u = (struct upload_stream*) stream; + size_t l; + assert(u->type == UPLOAD_STREAM); + + if (!u->memchunk.memblock) { + if (u->length == chunk->length) { + u->memchunk = *chunk; + pa_memblock_ref(u->memchunk.memblock); + u->length = 0; + fprintf(stderr, "COPY\n"); + } else { + u->memchunk.memblock = pa_memblock_new(u->length); + u->memchunk.index = u->memchunk.length = 0; + } + } + + assert(u->memchunk.memblock); + + l = u->length; + if (l > chunk->length) + l = chunk->length; + + if (l > 0) { + memcpy(u->memchunk.memblock->data + u->memchunk.index + u->memchunk.length, chunk->memblock->data+chunk->index, l); + u->memchunk.length += l; + u->length -= l; + } + } } static void pstream_die_callback(struct pa_pstream *p, void *userdata) { @@ -811,8 +1050,8 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo assert(c->pdispatch); c->record_streams = pa_idxset_new(NULL, NULL); - c->playback_streams = pa_idxset_new(NULL, NULL); - assert(c->record_streams && c->playback_streams); + c->output_streams = pa_idxset_new(NULL, NULL); + assert(c->record_streams && c->output_streams); c->rrobin_index = PA_IDXSET_INVALID; diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index 3a52e311..037d4f9a 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -221,7 +221,7 @@ static void sink_input_kill_cb(struct pa_sink_input *i) { static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { struct connection*c = i->userdata; assert(i && c); - return pa_samples_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); + return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); } /*** source_output callbacks ***/ @@ -319,7 +319,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->sink_input->userdata = c; l = (size_t) (pa_bytes_per_second(&p->sample_spec)*PLAYBACK_BUFFER_SECONDS); - c->input_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&p->sample_spec), l/2, l/PLAYBACK_BUFFER_FRAGMENTS); + c->input_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&p->sample_spec), l/2, l/PLAYBACK_BUFFER_FRAGMENTS); assert(c->input_memblockq); pa_iochannel_socket_set_rcvbuf(io, l/PLAYBACK_BUFFER_FRAGMENTS*5); c->playback.fragment_size = l/10; @@ -348,7 +348,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->source_output->userdata = c; l = (size_t) (pa_bytes_per_second(&p->sample_spec)*RECORD_BUFFER_SECONDS); - c->output_memblockq = pa_memblockq_new(l, 0, pa_sample_size(&p->sample_spec), 0, 0); + c->output_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&p->sample_spec), 0, 0); pa_iochannel_socket_set_sndbuf(io, l/RECORD_BUFFER_FRAGMENTS*2); } diff --git a/polyp/pstream.c b/polyp/pstream.c index 3076b776..7d576a16 100644 --- a/polyp/pstream.c +++ b/polyp/pstream.c @@ -23,6 +23,7 @@ #include #endif +#include #include #include #include @@ -40,7 +41,7 @@ enum pa_pstream_descriptor_index { typedef uint32_t pa_pstream_descriptor[PA_PSTREAM_DESCRIPTOR_MAX]; #define PA_PSTREAM_DESCRIPTOR_SIZE (PA_PSTREAM_DESCRIPTOR_MAX*sizeof(uint32_t)) -#define FRAME_SIZE_MAX (1024*64) +#define FRAME_SIZE_MAX (1024*500) /* half a megabyte */ struct item_info { enum { PA_PSTREAM_ITEM_PACKET, PA_PSTREAM_ITEM_MEMBLOCK } type; @@ -361,8 +362,10 @@ static void do_read(struct pa_pstream *p) { /* Reading of frame descriptor complete */ /* Frame size too large */ - if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) > FRAME_SIZE_MAX) + if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) > FRAME_SIZE_MAX) { + fprintf(stderr, "frame size too large\n"); goto die; + } assert(!p->read.packet && !p->read.memblock); diff --git a/polyp/resampler.c b/polyp/resampler.c index 320d7119..adf08e80 100644 --- a/polyp/resampler.c +++ b/polyp/resampler.c @@ -75,8 +75,8 @@ struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const stru r->i_ss = *a; r->o_ss = *b; - r->i_sz = pa_sample_size(a); - r->o_sz = pa_sample_size(b); + r->i_sz = pa_frame_size(a); + r->o_sz = pa_frame_size(b); r->to_float32_func = pa_get_convert_to_float32_function(a->format); r->from_float32_func = pa_get_convert_from_float32_function(b->format); diff --git a/polyp/sample-util.c b/polyp/sample-util.c index d608ce1b..5b1cd626 100644 --- a/polyp/sample-util.c +++ b/polyp/sample-util.c @@ -111,7 +111,7 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, uint32_t volume) { int16_t *d; size_t n; - assert(c && spec && (c->length % pa_sample_size(spec) == 0)); + assert(c && spec && (c->length % pa_frame_size(spec) == 0)); assert(spec->format == PA_SAMPLE_S16NE); if (volume == PA_VOLUME_NORM) diff --git a/polyp/sample.c b/polyp/sample.c index 8179475d..e4c4bd52 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -28,7 +28,7 @@ #include "sample.h" -size_t pa_sample_size(const struct pa_sample_spec *spec) { +size_t pa_frame_size(const struct pa_sample_spec *spec) { assert(spec); size_t b = 1; @@ -55,14 +55,13 @@ size_t pa_sample_size(const struct pa_sample_spec *spec) { size_t pa_bytes_per_second(const struct pa_sample_spec *spec) { assert(spec); - return spec->rate*pa_sample_size(spec); + return spec->rate*pa_frame_size(spec); } - -uint32_t pa_samples_usec(size_t length, const struct pa_sample_spec *spec) { +uint32_t pa_bytes_to_usec(size_t length, const struct pa_sample_spec *spec) { assert(spec); - return (uint32_t) (((double) length /pa_sample_size(spec))/spec->rate*1000000); + return (uint32_t) (((double) length /pa_frame_size(spec))/spec->rate*1000000); } int pa_sample_spec_valid(const struct pa_sample_spec *spec) { diff --git a/polyp/sample.h b/polyp/sample.h index 825441f2..01a4efcf 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -52,12 +52,11 @@ struct pa_sample_spec { }; size_t pa_bytes_per_second(const struct pa_sample_spec *spec); -size_t pa_sample_size(const struct pa_sample_spec *spec); -uint32_t pa_samples_usec(size_t length, const struct pa_sample_spec *spec); +size_t pa_frame_size(const struct pa_sample_spec *spec); +uint32_t pa_bytes_to_usec(size_t length, const struct pa_sample_spec *spec); int pa_sample_spec_valid(const struct pa_sample_spec *spec); int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b); - #define PA_SAMPLE_SNPRINT_MAX_LENGTH 32 void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec); diff --git a/polyp/scache.c b/polyp/scache.c index f1f7ec5a..21af0e22 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -6,6 +6,8 @@ #include "scache.h" #include "sink-input.h" #include "mainloop.h" +#include "sample-util.h" +#include "play-memchunk.h" static void free_entry(struct pa_scache_entry *e) { assert(e); @@ -100,50 +102,8 @@ void pa_scache_free(struct pa_core *c) { } } -static void sink_input_kill(struct pa_sink_input *i) { - struct pa_memchunk *c; - assert(i && i->userdata); - c = i->userdata; - - pa_memblock_unref(c->memblock); - free(c); - pa_sink_input_free(i); -} - -static int sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { - struct pa_memchunk *c; - assert(i && chunk && i->userdata); - c = i->userdata; - - assert(c->length && c->memblock && c->memblock->length); - *chunk = *c; - pa_memblock_ref(c->memblock); - - return 0; -} - -static void si_kill(void *i) { - sink_input_kill(i); -} - -static void sink_input_drop(struct pa_sink_input *i, size_t length) { - struct pa_memchunk *c; - assert(i && length && i->userdata); - c = i->userdata; - - assert(length <= c->length); - - c->length -= length; - c->index += length; - - if (c->length <= 0) - pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i); -} - int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sink, uint32_t volume) { - struct pa_sink_input *si; struct pa_scache_entry *e; - struct pa_memchunk *chunk; assert(c && name && sink); if (!c->scache_hashmap || !(e = pa_hashmap_get(c->scache_hashmap, name))) @@ -151,20 +111,10 @@ int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sin if (!e->memchunk.memblock) return -1; - - if (!(si = pa_sink_input_new(sink, name, &e->sample_spec))) - return -1; - - si->volume = volume; - - si->peek = sink_input_peek; - si->drop = sink_input_drop; - si->kill = sink_input_kill; - si->userdata = chunk = malloc(sizeof(struct pa_memchunk)); - assert(chunk); - *chunk = e->memchunk; - pa_memblock_ref(chunk->memblock); + if (pa_play_memchunk(sink, name, &e->sample_spec, &e->memchunk, pa_volume_multiply(volume, e->volume)) < 0) + return -1; + return 0; } diff --git a/polyp/sink.c b/polyp/sink.c index 20fa76a6..c2c873c6 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -41,7 +41,7 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co char *n = NULL; char st[256]; int r; - assert(core && name && spec); + assert(core && name && *name && spec); s = malloc(sizeof(struct pa_sink)); assert(s); diff --git a/polyp/source.c b/polyp/source.c index ccde0e2f..13635414 100644 --- a/polyp/source.c +++ b/polyp/source.c @@ -36,7 +36,7 @@ struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail struct pa_source *s; char st[256]; int r; - assert(core && spec && name); + assert(core && spec && name && *name); s = malloc(sizeof(struct pa_source)); assert(s); -- cgit From 46091a9237f17f4295dca7140d8d70b4fce8b357 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 Aug 2004 16:39:30 +0000 Subject: introduce pa_xmalloc() and friends implement module auto loading git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@103 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 +- polyp/Makefile.am | 7 +++- polyp/alsa-util.c | 13 +++---- polyp/cli-command.c | 96 ++++++++++++++++++++++++++++++++-------------- polyp/cli.c | 8 ++-- polyp/client.c | 14 +++---- polyp/clitext.c | 49 +++++++++++++++++------ polyp/clitext.h | 1 + polyp/cmdline.c | 8 ++-- polyp/core.c | 19 ++++++--- polyp/core.h | 8 ++-- polyp/dynarray.c | 10 ++--- polyp/hashmap.c | 18 ++++----- polyp/idxset.c | 28 ++++++-------- polyp/iochannel.c | 5 ++- polyp/ioline.c | 18 ++++----- polyp/main.c | 3 +- polyp/mainloop-api.c | 7 ++-- polyp/mainloop-signal.c | 8 ++-- polyp/mainloop.c | 24 +++++------- polyp/memblock.c | 14 +++---- polyp/memblockq.c | 15 ++++---- polyp/memchunk.c | 11 +++--- polyp/modargs.c | 62 +++++++----------------------- polyp/modargs.h | 3 -- polyp/module-alsa-sink.c | 52 +++++++++++++++---------- polyp/module-alsa-source.c | 47 ++++++++++++++--------- polyp/module-oss-mmap.c | 35 ++++++++++------- polyp/module-oss.c | 27 +++++++++---- polyp/module-pipe-sink.c | 18 +++++---- polyp/module-x11-bell.c | 38 ++++++------------ polyp/module.c | 88 +++++++++++++++++++++++++++++++++++------- polyp/module.h | 8 ++++ polyp/namereg.c | 78 +++++++++++++++++++++++++++++++------ polyp/namereg.h | 3 +- polyp/packet.c | 13 +++---- polyp/pdispatch.c | 11 +++--- polyp/polypaudio.pa | 10 ++++- polyp/polyplib-simple.c | 16 ++++---- polyp/polyplib.c | 27 ++++++------- polyp/protocol-cli.c | 6 +-- polyp/protocol-esound.c | 85 ++++++++++++---------------------------- polyp/protocol-native.c | 55 +++++++++++--------------- polyp/protocol-simple.c | 48 +++++++++-------------- polyp/pstream.c | 14 +++---- polyp/queue.c | 13 +++---- polyp/resampler.c | 16 ++++---- polyp/scache.c | 11 +++--- polyp/sink-input.c | 10 ++--- polyp/sink.c | 29 ++++---------- polyp/sink.h | 2 - polyp/socket-client.c | 6 +-- polyp/socket-server.c | 14 +++---- polyp/socket-util.c | 11 +++--- polyp/source-output.c | 10 ++--- polyp/source.c | 28 ++++---------- polyp/source.h | 2 - polyp/strbuf.c | 17 ++++---- polyp/tagstruct.c | 13 +++---- polyp/tokenizer.c | 14 +++---- polyp/util.c | 4 +- 61 files changed, 700 insertions(+), 631 deletions(-) diff --git a/doc/todo b/doc/todo index 3f04bfca..7cf36b08 100644 --- a/doc/todo +++ b/doc/todo @@ -3,12 +3,11 @@ *** 0.2 *** - future cancellation -- autoloading/autounloading - make mcalign merge chunks - doxygen -- scache.[ch]/module-x11-bell.c/debug.h copyright +- several files: copyright and config.h - enable searchdir - autoscan - rename clitext.[ch] to cli-text.[ch] diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 48b984f8..0af99110 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -109,7 +109,9 @@ polypaudio_SOURCES = idxset.c idxset.h \ dynarray.c dynarray.h \ scache.c scache.h \ sound-file.c sound-file.h \ - play-memchunk.c play-memchunk.h + play-memchunk.c play-memchunk.h \ + autoload.c autoload.h \ + xmalloc.c xmalloc.h polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) @@ -273,7 +275,8 @@ libpolyp_la_SOURCES = polyplib.c polyplib.h \ authkey.c authkey.h \ socket-util.c socket-util.h \ native-common.h \ - sample.c sample.h + sample.c sample.h \ + xmalloc.c xmalloc.h libpolyp_la_CFLAGS = $(AM_CFLAGS) libpolyp_mainloop_la_SOURCES = mainloop-api.h mainloop-api.c \ diff --git a/polyp/alsa-util.c b/polyp/alsa-util.c index 7f266df5..43562378 100644 --- a/polyp/alsa-util.c +++ b/polyp/alsa-util.c @@ -27,6 +27,7 @@ #include "alsa-util.h" #include "sample.h" +#include "xmalloc.h" int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, struct pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *buffer_size) { int ret = 0; @@ -66,15 +67,13 @@ int pa_create_io_sources(snd_pcm_t *pcm_handle, struct pa_mainloop_api* m, void *n_io_sources = snd_pcm_poll_descriptors_count(pcm_handle); - pfds = malloc(sizeof(struct pollfd) * *n_io_sources); - assert(pfds); + pfds = pa_xmalloc(sizeof(struct pollfd) * *n_io_sources); if (snd_pcm_poll_descriptors(pcm_handle, pfds, *n_io_sources) < 0) { - free(pfds); + pa_xfree(pfds); return -1; } - *io_sources = malloc(sizeof(void*) * *n_io_sources); - assert(io_sources); + *io_sources = pa_xmalloc(sizeof(void*) * *n_io_sources); for (i = 0, ios = *io_sources, ppfd = pfds; i < *n_io_sources; i++, ios++, ppfd++) { *ios = m->source_io(m, ppfd->fd, @@ -83,7 +82,7 @@ int pa_create_io_sources(snd_pcm_t *pcm_handle, struct pa_mainloop_api* m, void assert(*ios); } - free(pfds); + pa_xfree(pfds); return 0; } @@ -94,5 +93,5 @@ void pa_free_io_sources(struct pa_mainloop_api* m, void **io_sources, unsigned n for (ios = io_sources, i = 0; i < n_io_sources; i++, ios++) m->cancel_io(m, *ios); - free(io_sources); + pa_xfree(io_sources); } diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 826789ce..6386d4e4 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -44,6 +44,8 @@ #include "sample-util.h" #include "sound-file.h" #include "play-memchunk.h" +#include "autoload.h" +#include "xmalloc.h" struct command { const char *name; @@ -76,6 +78,9 @@ static int pa_cli_command_scache_remove(struct pa_core *c, struct pa_tokenizer * static int pa_cli_command_scache_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_autoload_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_autoload_add(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_autoload_remove(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 }, @@ -99,11 +104,16 @@ static const struct command commands[] = { { "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}, - { "scache_list", pa_cli_command_scache_list, "List all entries in the sample cache", 2}, + { "scache_list", pa_cli_command_scache_list, "List all entries in the sample cache", 1}, { "scache_play", pa_cli_command_scache_play, "Play a sample from the sample cache (args: name, sink|index)", 3}, { "scache_remove", pa_cli_command_scache_remove, "Remove a sample from the sample cache (args: name)", 2}, { "scache_load", pa_cli_command_scache_load, "Load a sound file into the sample cache (args: filename,name)", 3}, { "play_file", pa_cli_command_play_file, "Play a sound file (args: filename, sink|index)", 3}, + { "autoload_list", pa_cli_command_autoload_list, "List autoload entries", 1}, + { "autoload_sink_add", pa_cli_command_autoload_add, "Add autoload entry for a sink (args: sink, name, arguments)", 4}, + { "autoload_source_add", pa_cli_command_autoload_add, "Add autoload entry for a source (args: source, name, arguments)", 4}, + { "autoload_sink_remove", pa_cli_command_autoload_remove, "Remove autoload entry for a sink (args: sink)", 2}, + { "autoload_source_remove", pa_cli_command_autoload_remove, "Remove autoload entry for a source (args: source)", 2}, { NULL, NULL, NULL, 0 } }; @@ -144,7 +154,7 @@ static int pa_cli_command_modules(struct pa_core *c, struct pa_tokenizer *t, str s = pa_module_list_to_string(c); assert(s); pa_strbuf_puts(buf, s); - free(s); + pa_xfree(s); return 0; } @@ -154,7 +164,7 @@ static int pa_cli_command_clients(struct pa_core *c, struct pa_tokenizer *t, str s = pa_client_list_to_string(c); assert(s); pa_strbuf_puts(buf, s); - free(s); + pa_xfree(s); return 0; } @@ -164,7 +174,7 @@ static int pa_cli_command_sinks(struct pa_core *c, struct pa_tokenizer *t, struc s = pa_sink_list_to_string(c); assert(s); pa_strbuf_puts(buf, s); - free(s); + pa_xfree(s); return 0; } @@ -174,7 +184,7 @@ static int pa_cli_command_sources(struct pa_core *c, struct pa_tokenizer *t, str s = pa_source_list_to_string(c); assert(s); pa_strbuf_puts(buf, s); - free(s); + pa_xfree(s); return 0; } @@ -184,7 +194,7 @@ static int pa_cli_command_sink_inputs(struct pa_core *c, struct pa_tokenizer *t, s = pa_sink_input_list_to_string(c); assert(s); pa_strbuf_puts(buf, s); - free(s); + pa_xfree(s); return 0; } @@ -194,7 +204,7 @@ static int pa_cli_command_source_outputs(struct pa_core *c, struct pa_tokenizer s = pa_source_output_list_to_string(c); assert(s); pa_strbuf_puts(buf, s); - free(s); + pa_xfree(s); return 0; } @@ -214,6 +224,7 @@ static int pa_cli_command_info(struct pa_core *c, struct pa_tokenizer *t, struct pa_cli_command_sink_inputs(c, t, buf, fail, verbose); pa_cli_command_source_outputs(c, t, buf, fail, verbose); pa_cli_command_scache_list(c, t, buf, fail, verbose); + pa_cli_command_autoload_list(c, t, buf, fail, verbose); return 0; } @@ -284,7 +295,7 @@ static int pa_cli_command_sink_volume(struct pa_core *c, struct pa_tokenizer *t, return -1; } - if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) { + if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) { pa_strbuf_puts(buf, "No sink found by this name or index.\n"); return -1; } @@ -333,7 +344,6 @@ static int pa_cli_command_sink_input_volume(struct pa_core *c, struct pa_tokeniz 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))) { @@ -341,18 +351,12 @@ static int pa_cli_command_sink_default(struct pa_core *c, struct pa_tokenizer *t 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; + pa_namereg_set_default(c, n, PA_NAMEREG_SINK); 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))) { @@ -360,12 +364,7 @@ static int pa_cli_command_source_default(struct pa_core *c, struct pa_tokenizer 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; + pa_namereg_set_default(c, n, PA_NAMEREG_SOURCE); return 0; } @@ -450,7 +449,7 @@ static int pa_cli_command_scache_list(struct pa_core *c, struct pa_tokenizer *t, s = pa_scache_list_to_string(c); assert(s); pa_strbuf_puts(buf, s); - free(s); + pa_xfree(s); return 0; } @@ -464,7 +463,7 @@ static int pa_cli_command_scache_play(struct pa_core *c, struct pa_tokenizer *t, return -1; } - if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK))) { + if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) { pa_strbuf_puts(buf, "No sink by that name.\n"); return -1; } @@ -528,7 +527,7 @@ static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, s return -1; } - if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK))) { + if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) { pa_strbuf_puts(buf, "No sink by that name.\n"); return -1; } @@ -543,6 +542,46 @@ static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, s return ret; } +static int pa_cli_command_autoload_add(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + const char *devname, *module; + assert(c && t && buf && fail && verbose); + + if (!(devname = pa_tokenizer_get(t, 1)) || !(module = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a device name, a module name and optionally module arguments\n"); + return -1; + } + + pa_autoload_add(c, devname, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, module, pa_tokenizer_get(t, 3)); + return 0; +} + +static int pa_cli_command_autoload_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + const char *devname; + assert(c && t && buf && fail && verbose); + + if (!(devname = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a device name\n"); + return -1; + } + + if (pa_autoload_remove(c, devname, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE) < 0) { + pa_strbuf_puts(buf, "Failed to remove autload entry\n"); + return -1; + } + + return 0; +} + +static int pa_cli_command_autoload_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + char *s; + assert(c && t); + s = pa_autoload_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + pa_xfree(s); + 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; @@ -654,14 +693,13 @@ int pa_cli_command_execute(struct pa_core *c, const char *s, struct pa_strbuf *b p = s; while (*p) { size_t l = strcspn(p, linebreak); - char *line = strndup(p, l); - assert(line); + char *line = pa_xstrndup(p, l); if (pa_cli_command_execute_line(c, line, buf, fail, verbose) < 0&& *fail) { - free(line); + pa_xfree(line); return -1; } - free(line); + pa_xfree(line); p += l; p += strspn(p, linebreak); diff --git a/polyp/cli.c b/polyp/cli.c index f2aa5a65..f0ad4830 100644 --- a/polyp/cli.c +++ b/polyp/cli.c @@ -41,6 +41,7 @@ #include "namereg.h" #include "clitext.h" #include "cli-command.h" +#include "xmalloc.h" struct pa_cli { struct pa_core *core; @@ -65,8 +66,7 @@ struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io, struct struct pa_cli *c; assert(io); - c = malloc(sizeof(struct pa_cli)); - assert(c); + c = pa_xmalloc(sizeof(struct pa_cli)); c->core = core; c->line = pa_ioline_new(io); assert(c->line); @@ -95,7 +95,7 @@ void pa_cli_free(struct pa_cli *c) { assert(c); pa_ioline_free(c->line); pa_client_free(c->client); - free(c); + pa_xfree(c); } static void client_kill(struct pa_client *client) { @@ -132,7 +132,7 @@ static void line_callback(struct pa_ioline *line, const char *s, void *userdata) 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); + pa_xfree(p); if (c->kill_requested) { if (c->eof_callback) diff --git a/polyp/client.c b/polyp/client.c index 0294c9e2..83a6264d 100644 --- a/polyp/client.c +++ b/polyp/client.c @@ -29,15 +29,15 @@ #include #include "client.h" +#include "xmalloc.h" struct pa_client *pa_client_new(struct pa_core *core, const char *protocol_name, char *name) { struct pa_client *c; int r; assert(core); - c = malloc(sizeof(struct pa_client)); - assert(c); - c->name = name ? strdup(name) : NULL; + c = pa_xmalloc(sizeof(struct pa_client)); + c->name = pa_xstrdup(name); c->owner = NULL; c->core = core; c->protocol_name = protocol_name; @@ -58,8 +58,8 @@ void pa_client_free(struct pa_client *c) { pa_idxset_remove_by_data(c->core->clients, c, NULL); fprintf(stderr, "client: freed %u \"%s\"\n", c->index, c->name); - free(c->name); - free(c); + pa_xfree(c->name); + pa_xfree(c); } void pa_client_kill(struct pa_client *c) { @@ -74,6 +74,6 @@ void pa_client_kill(struct pa_client *c) { void pa_client_rename(struct pa_client *c, const char *name) { assert(c); - free(c->name); - c->name = name ? strdup(name) : NULL; + pa_xfree(c->name); + c->name = pa_xstrdup(name); } diff --git a/polyp/clitext.c b/polyp/clitext.c index fbce2223..6d2d6253 100644 --- a/polyp/clitext.c +++ b/polyp/clitext.c @@ -36,6 +36,7 @@ #include "strbuf.h" #include "sample-util.h" #include "scache.h" +#include "autoload.h" char *pa_module_list_to_string(struct pa_core *c) { struct pa_strbuf *s; @@ -49,7 +50,7 @@ char *pa_module_list_to_string(struct pa_core *c) { pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_ncontents(c->modules)); for (m = pa_idxset_first(c->modules, &index); m; m = pa_idxset_next(c->modules, &index)) - pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\targument: <%s>\n", m->index, m->name, m->argument); + pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\targument: <%s>\n\tused: %i\n\tauto unload: %s\n", m->index, m->name, m->argument, m->n_used, m->auto_unload ? "yes" : "no"); return pa_strbuf_tostring_free(s); } @@ -77,7 +78,7 @@ char *pa_client_list_to_string(struct pa_core *c) { char *pa_sink_list_to_string(struct pa_core *c) { struct pa_strbuf *s; - struct pa_sink *sink, *default_sink; + struct pa_sink *sink; uint32_t index = PA_IDXSET_INVALID; assert(c); @@ -86,8 +87,6 @@ char *pa_sink_list_to_string(struct pa_core *c) { pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_ncontents(c->sinks)); - default_sink = pa_sink_get_default(c); - for (sink = pa_idxset_first(c->sinks, &index); sink; sink = pa_idxset_next(c->sinks, &index)) { char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; pa_sample_snprint(ss, sizeof(ss), &sink->sample_spec); @@ -95,7 +94,7 @@ char *pa_sink_list_to_string(struct pa_core *c) { pa_strbuf_printf( s, " %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", - sink == default_sink ? '*' : ' ', + !strcmp(sink->name, c->default_sink_name) ? '*' : ' ', sink->index, sink->name, (unsigned) sink->volume, pa_sink_get_latency(sink), @@ -113,7 +112,7 @@ char *pa_sink_list_to_string(struct pa_core *c) { char *pa_source_list_to_string(struct pa_core *c) { struct pa_strbuf *s; - struct pa_source *source, *default_source; + struct pa_source *source; uint32_t index = PA_IDXSET_INVALID; assert(c); @@ -122,12 +121,14 @@ char *pa_source_list_to_string(struct pa_core *c) { pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_ncontents(c->sources)); - default_source = pa_source_get_default(c); - for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) { char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; pa_sample_snprint(ss, sizeof(ss), &source->sample_spec); - pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\tsample_spec: <%s>\n", source == default_source ? '*' : ' ', source->index, source->name, ss); + pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\tsample_spec: <%s>\n", + !strcmp(source->name, c->default_source_name) ? '*' : ' ', + source->index, + source->name, + ss); if (source->monitor_of) pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index); @@ -205,8 +206,6 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { } char *pa_scache_list_to_string(struct pa_core *c) { - struct pa_scache_entry *e; - void *state = NULL; struct pa_strbuf *s; assert(c); @@ -216,6 +215,8 @@ char *pa_scache_list_to_string(struct pa_core *c) { pa_strbuf_printf(s, "%u cache entries available.\n", c->scache_hashmap ? pa_hashmap_ncontents(c->scache_hashmap) : 0); if (c->scache_hashmap) { + struct pa_scache_entry *e; + void *state = NULL; while ((e = pa_hashmap_iterate(c->scache_hashmap, &state))) { double l; @@ -237,3 +238,29 @@ char *pa_scache_list_to_string(struct pa_core *c) { return pa_strbuf_tostring_free(s); } + +char *pa_autoload_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u autoload entries available.\n", c->autoload_hashmap ? pa_hashmap_ncontents(c->autoload_hashmap) : 0); + + if (c->autoload_hashmap) { + struct pa_autoload_entry *e; + void *state = NULL; + + while ((e = pa_hashmap_iterate(c->autoload_hashmap, &state))) { + pa_strbuf_printf( + s, " name: <%s>\n\ttype: <%s>\n\tmodule_name: <%s>\n\targuments: <%s>\n", + e->name, + e->type == PA_NAMEREG_SOURCE ? "source" : "sink", + e->module, + e->argument); + } + } + + return pa_strbuf_tostring_free(s); +} diff --git a/polyp/clitext.h b/polyp/clitext.h index 4e5252fe..121f2a5d 100644 --- a/polyp/clitext.h +++ b/polyp/clitext.h @@ -31,6 +31,7 @@ char *pa_source_list_to_string(struct pa_core *c); char *pa_client_list_to_string(struct pa_core *c); char *pa_module_list_to_string(struct pa_core *c); char *pa_scache_list_to_string(struct pa_core *c); +char *pa_autoload_list_to_string(struct pa_core *c); #endif diff --git a/polyp/cmdline.c b/polyp/cmdline.c index a3330145..8acdde6f 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -32,6 +32,7 @@ #include "cmdline.h" #include "util.h" #include "strbuf.h" +#include "xmalloc.h" void pa_cmdline_help(const char *argv0) { const char *e; @@ -57,8 +58,7 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { struct pa_strbuf *buf = NULL; assert(argc && argv); - cmdline = malloc(sizeof(struct pa_cmdline)); - assert(cmdline); + cmdline = pa_xmalloc(sizeof(struct pa_cmdline)); cmdline->daemonize = cmdline->help = cmdline->verbose = 0; cmdline->fail = 1; @@ -106,6 +106,6 @@ fail: void pa_cmdline_free(struct pa_cmdline *cmd) { assert(cmd); - free(cmd->cli_commands); - free(cmd); + pa_xfree(cmd->cli_commands); + pa_xfree(cmd); } diff --git a/polyp/core.c b/polyp/core.c index 1c69f914..ffc11cec 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -34,11 +34,12 @@ #include "namereg.h" #include "util.h" #include "scache.h" +#include "autoload.h" +#include "xmalloc.h" struct pa_core* pa_core_new(struct pa_mainloop_api *m) { struct pa_core* c; - c = malloc(sizeof(struct pa_core)); - assert(c); + c = pa_xmalloc(sizeof(struct pa_core)); c->mainloop = m; c->clients = pa_idxset_new(NULL, NULL); @@ -47,16 +48,20 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->source_outputs = pa_idxset_new(NULL, NULL); c->sink_inputs = pa_idxset_new(NULL, NULL); - c->default_source_index = c->default_sink_index = PA_IDXSET_INVALID; + c->default_source_name = c->default_sink_name = NULL; c->modules = NULL; c->namereg = NULL; c->scache_idxset = NULL; c->scache_hashmap = NULL; + c->autoload_hashmap = NULL; + c->default_sample_spec.format = PA_SAMPLE_S16NE; c->default_sample_spec.rate = 44100; c->default_sample_spec.channels = 2; + + c->auto_unload_time = 20; pa_check_for_sigpipe(); @@ -68,7 +73,7 @@ void pa_core_free(struct pa_core *c) { pa_module_unload_all(c); assert(!c->modules); - + assert(pa_idxset_isempty(c->clients)); pa_idxset_free(c->clients, NULL, NULL); @@ -86,7 +91,11 @@ void pa_core_free(struct pa_core *c) { pa_namereg_free(c); pa_scache_free(c); + pa_autoload_free(c); + + pa_xfree(c->default_source_name); + pa_xfree(c->default_sink_name); - free(c); + pa_xfree(c); }; diff --git a/polyp/core.h b/polyp/core.h index 03b8671a..b125083d 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -32,11 +32,13 @@ struct pa_core { struct pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache_idxset; - struct pa_hashmap *namereg, *scache_hashmap; - - uint32_t default_source_index, default_sink_index; + struct pa_hashmap *namereg, *scache_hashmap, *autoload_hashmap; + + char *default_source_name, *default_sink_name; struct pa_sample_spec default_sample_spec; + int auto_unload_time; + void *auto_unload_mainloop_source; }; struct pa_core* pa_core_new(struct pa_mainloop_api *m); diff --git a/polyp/dynarray.c b/polyp/dynarray.c index 24306964..23adb581 100644 --- a/polyp/dynarray.c +++ b/polyp/dynarray.c @@ -28,6 +28,7 @@ #include #include "dynarray.h" +#include "xmalloc.h" struct pa_dynarray { void **data; @@ -36,8 +37,7 @@ struct pa_dynarray { struct pa_dynarray* pa_dynarray_new(void) { struct pa_dynarray *a; - a = malloc(sizeof(struct pa_dynarray)); - assert(a); + a = pa_xmalloc(sizeof(struct pa_dynarray)); a->data = NULL; a->n_entries = 0; a->n_allocated = 0; @@ -53,8 +53,8 @@ void pa_dynarray_free(struct pa_dynarray* a, void (*func)(void *p, void *userdat if (a->data[i]) func(a->data[i], userdata); - free(a->data); - free(a); + pa_xfree(a->data); + pa_xfree(a); } void pa_dynarray_put(struct pa_dynarray*a, unsigned i, void *p) { @@ -67,7 +67,7 @@ void pa_dynarray_put(struct pa_dynarray*a, unsigned i, void *p) { return; n = i+100; - a->data = realloc(a->data, sizeof(void*)*n); + a->data = pa_xrealloc(a->data, sizeof(void*)*n); memset(a->data+a->n_allocated, 0, sizeof(void*)*(n-a->n_allocated)); a->n_allocated = n; } diff --git a/polyp/hashmap.c b/polyp/hashmap.c index 51e3879b..2b9550fd 100644 --- a/polyp/hashmap.c +++ b/polyp/hashmap.c @@ -29,6 +29,7 @@ #include "hashmap.h" #include "idxset.h" +#include "xmalloc.h" struct hashmap_entry { struct hashmap_entry *next, *previous, *bucket_next, *bucket_previous; @@ -49,11 +50,8 @@ struct pa_hashmap { struct pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { struct pa_hashmap *h; - h = malloc(sizeof(struct pa_hashmap)); - assert(h); - h->data = malloc(sizeof(struct hashmap_entry*)*(h->size = 1023)); - assert(h->data); - memset(h->data, 0, sizeof(struct hashmap_entry*)*(h->size = 1023)); + h = pa_xmalloc(sizeof(struct pa_hashmap)); + h->data = pa_xmalloc0(sizeof(struct hashmap_entry*)*(h->size = 1023)); h->first_entry = NULL; h->n_entries = 0; h->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; @@ -78,7 +76,7 @@ static void remove(struct pa_hashmap *h, struct hashmap_entry *e) { else h->data[e->hash] = e->bucket_next; - free(e); + pa_xfree(e); h->n_entries--; } @@ -91,8 +89,8 @@ void pa_hashmap_free(struct pa_hashmap*h, void (*free_func)(void *p, void *userd remove(h, h->first_entry); } - free(h->data); - free(h); + pa_xfree(h->data); + pa_xfree(h); } static struct hashmap_entry *get(struct pa_hashmap *h, unsigned hash, const void *key) { @@ -115,9 +113,7 @@ int pa_hashmap_put(struct pa_hashmap *h, const void *key, void *value) { if ((e = get(h, hash, key))) return -1; - e = malloc(sizeof(struct hashmap_entry)); - assert(e); - + e = pa_xmalloc(sizeof(struct hashmap_entry)); e->hash = hash; e->key = key; e->value = value; diff --git a/polyp/idxset.c b/polyp/idxset.c index 0072e3cd..83565193 100644 --- a/polyp/idxset.c +++ b/polyp/idxset.c @@ -29,6 +29,7 @@ #include #include "idxset.h" +#include "xmalloc.h" struct idxset_entry { void *data; @@ -73,14 +74,11 @@ int pa_idxset_trivial_compare_func(const void *a, const void *b) { struct pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { struct pa_idxset *s; - s = malloc(sizeof(struct pa_idxset)); - assert(s); + s = pa_xmalloc(sizeof(struct pa_idxset)); s->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; s->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; s->hash_table_size = 1023; - s->hash_table = malloc(sizeof(struct idxset_entry*)*s->hash_table_size); - assert(s->hash_table); - memset(s->hash_table, 0, sizeof(struct idxset_entry*)*s->hash_table_size); + s->hash_table = pa_xmalloc0(sizeof(struct idxset_entry*)*s->hash_table_size); s->array = NULL; s->array_size = 0; s->index = 0; @@ -101,12 +99,12 @@ void pa_idxset_free(struct pa_idxset *s, void (*free_func) (void *p, void *userd if (free_func) free_func(e->data, userdata); - free(e); + pa_xfree(e); } - free(s->hash_table); - free(s->array); - free(s); + pa_xfree(s->hash_table); + pa_xfree(s->array); + pa_xfree(s); } static struct idxset_entry* hash_scan(struct pa_idxset *s, struct idxset_entry* e, void *p) { @@ -133,14 +131,12 @@ static void extend_array(struct pa_idxset *s, uint32_t index) { break; l = index - s->start_index - i + 100; - n = malloc(sizeof(struct hash_table_entry*)*l); - assert(n); - memset(n, 0, sizeof(struct hash_table_entry*)*l); + n = pa_xmalloc0(sizeof(struct hash_table_entry*)*l); for (j = 0; j < s->array_size-i; j++) n[j] = s->array[i+j]; - free(s->array); + pa_xfree(s->array); s->array = n; s->array_size = l; @@ -173,9 +169,7 @@ int pa_idxset_put(struct pa_idxset*s, void *p, uint32_t *index) { return -1; } - e = malloc(sizeof(struct idxset_entry)); - assert(e); - + e = pa_xmalloc(sizeof(struct idxset_entry)); e->data = p; e->index = s->index++; e->hash_value = h; @@ -274,7 +268,7 @@ static void remove_entry(struct pa_idxset *s, struct idxset_entry *e) { else s->hash_table[e->hash_value] = e->hash_next; - free(e); + pa_xfree(e); assert(s->n_entries >= 1); s->n_entries--; diff --git a/polyp/iochannel.c b/polyp/iochannel.c index 69d381f4..77f8fb08 100644 --- a/polyp/iochannel.c +++ b/polyp/iochannel.c @@ -31,6 +31,7 @@ #include "iochannel.h" #include "util.h" #include "socket-util.h" +#include "xmalloc.h" struct pa_iochannel { int ifd, ofd; @@ -103,7 +104,7 @@ struct pa_iochannel* pa_iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd struct pa_iochannel *io; assert(m && (ifd >= 0 || ofd >= 0)); - io = malloc(sizeof(struct pa_iochannel)); + io = pa_xmalloc(sizeof(struct pa_iochannel)); io->ifd = ifd; io->ofd = ofd; io->mainloop = m; @@ -152,7 +153,7 @@ void pa_iochannel_free(struct pa_iochannel*io) { if (io->output_source && (io->output_source != io->input_source)) io->mainloop->cancel_io(io->mainloop, io->output_source); - free(io); + pa_xfree(io); } int pa_iochannel_is_readable(struct pa_iochannel*io) { diff --git a/polyp/ioline.c b/polyp/ioline.c index ff9a03c2..dfa92ab7 100644 --- a/polyp/ioline.c +++ b/polyp/ioline.c @@ -30,6 +30,7 @@ #include #include "ioline.h" +#include "xmalloc.h" #define BUFFER_LIMIT (64*1024) #define READ_SIZE (1024) @@ -55,8 +56,7 @@ struct pa_ioline* pa_ioline_new(struct pa_iochannel *io) { struct pa_ioline *l; assert(io); - l = malloc(sizeof(struct pa_ioline)); - assert(l); + l = pa_xmalloc(sizeof(struct pa_ioline)); l->io = io; l->dead = 0; @@ -77,9 +77,9 @@ struct pa_ioline* pa_ioline_new(struct pa_iochannel *io) { void pa_ioline_free(struct pa_ioline *l) { assert(l); pa_iochannel_free(l->io); - free(l->wbuf); - free(l->rbuf); - free(l); + pa_xfree(l->wbuf); + pa_xfree(l->rbuf); + pa_xfree(l); } void pa_ioline_puts(struct pa_ioline *l, const char *c) { @@ -95,10 +95,10 @@ void pa_ioline_puts(struct pa_ioline *l, const char *c) { if (len > l->wbuf_length - l->wbuf_valid_length) { size_t n = l->wbuf_valid_length+len; - char *new = malloc(n); + char *new = pa_xmalloc(n); if (l->wbuf) { memcpy(new, l->wbuf+l->wbuf_index, l->wbuf_valid_length); - free(l->wbuf); + pa_xfree(l->wbuf); } l->wbuf = new; l->wbuf_length = n; @@ -141,10 +141,10 @@ static int do_read(struct pa_ioline *l) { if (l->rbuf_valid_length) memmove(l->rbuf, l->rbuf+l->rbuf_index, l->rbuf_valid_length); } else { - char *new = malloc(n); + char *new = pa_xmalloc(n); if (l->rbuf_valid_length) memcpy(new, l->rbuf+l->rbuf_index, l->rbuf_valid_length); - free(l->rbuf); + pa_xfree(l->rbuf); l->rbuf = new; l->rbuf_length = n; } diff --git a/polyp/main.c b/polyp/main.c index 0c6104a4..de66f1c8 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -42,6 +42,7 @@ #include "cli-command.h" #include "util.h" #include "sioman.h" +#include "xmalloc.h" static struct pa_mainloop *mainloop; @@ -147,7 +148,7 @@ int main(int argc, char *argv[]) { 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); + pa_xfree(s); if (r < 0 && cmdline->fail) { fprintf(stderr, __FILE__": failed to initialize daemon.\n"); diff --git a/polyp/mainloop-api.c b/polyp/mainloop-api.c index cce49c06..8b4e09ac 100644 --- a/polyp/mainloop-api.c +++ b/polyp/mainloop-api.c @@ -25,7 +25,9 @@ #include #include + #include "mainloop-api.h" +#include "xmalloc.h" struct once_info { void (*callback)(void *userdata); @@ -38,7 +40,7 @@ static void once_callback(struct pa_mainloop_api *api, void *id, void *userdata) i->callback(i->userdata); assert(api->cancel_fixed); api->cancel_fixed(api, id); - free(i); + pa_xfree(i); } void pa_mainloop_api_once(struct pa_mainloop_api* api, void (*callback)(void *userdata), void *userdata) { @@ -46,8 +48,7 @@ void pa_mainloop_api_once(struct pa_mainloop_api* api, void (*callback)(void *us void *id; assert(api && callback); - i = malloc(sizeof(struct once_info)); - assert(i); + i = pa_xmalloc(sizeof(struct once_info)); i->callback = callback; i->userdata = userdata; diff --git a/polyp/mainloop-signal.c b/polyp/mainloop-signal.c index 642ca5e0..6e79767a 100644 --- a/polyp/mainloop-signal.c +++ b/polyp/mainloop-signal.c @@ -33,6 +33,7 @@ #include "mainloop-signal.h" #include "util.h" +#include "xmalloc.h" struct signal_info { int sig; @@ -122,8 +123,7 @@ void* pa_signal_register(int sig, void (*callback) (void *id, int signal, void * if (s->sig == sig) goto fail; - s = malloc(sizeof(struct signal_info)); - assert(s); + s = pa_xmalloc(sizeof(struct signal_info)); s->sig = sig; s->callback = callback; s->userdata = userdata; @@ -143,7 +143,7 @@ void* pa_signal_register(int sig, void (*callback) (void *id, int signal, void * return s; fail: if (s) - free(s); + pa_xfree(s); return NULL; } @@ -159,5 +159,5 @@ void pa_signal_unregister(void *id) { signals = s->next; sigaction(s->sig, &s->saved_sigaction, NULL); - free(s); + pa_xfree(s); } diff --git a/polyp/mainloop.c b/polyp/mainloop.c index b9eee86d..f3d8e781 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -36,6 +36,7 @@ #include "mainloop.h" #include "util.h" #include "idxset.h" +#include "xmalloc.h" struct mainloop_source_header { struct pa_mainloop *mainloop; @@ -87,8 +88,7 @@ static void setup_api(struct pa_mainloop *m); struct pa_mainloop *pa_mainloop_new(void) { struct pa_mainloop *m; - m = malloc(sizeof(struct pa_mainloop)); - assert(m); + m = pa_xmalloc(sizeof(struct pa_mainloop)); m->io_sources = pa_idxset_new(NULL, NULL); m->fixed_sources = pa_idxset_new(NULL, NULL); @@ -115,7 +115,7 @@ static int foreach(void *p, uint32_t index, int *del, void*userdata) { assert(p && del && all); if (*all || h->dead) { - free(h); + pa_xfree(h); *del = 1; } @@ -135,8 +135,8 @@ void pa_mainloop_free(struct pa_mainloop* m) { pa_idxset_free(m->idle_sources, NULL, NULL); pa_idxset_free(m->time_sources, NULL, NULL); - free(m->pollfds); - free(m); + pa_xfree(m->pollfds); + pa_xfree(m); } static void scan_dead(struct pa_mainloop *m) { @@ -160,7 +160,7 @@ static void rebuild_pollfds(struct pa_mainloop *m) { l = pa_idxset_ncontents(m->io_sources); if (m->max_pollfds < l) { - m->pollfds = realloc(m->pollfds, sizeof(struct pollfd)*l); + m->pollfds = pa_xrealloc(m->pollfds, sizeof(struct pollfd)*l); m->max_pollfds = l; } @@ -349,8 +349,7 @@ static void* mainloop_source_io(struct pa_mainloop_api*a, int fd, enum pa_mainlo m = a->userdata; assert(a == &m->api); - s = malloc(sizeof(struct mainloop_source_io)); - assert(s); + s = pa_xmalloc(sizeof(struct mainloop_source_io)); s->header.mainloop = m; s->header.dead = 0; @@ -397,8 +396,7 @@ static void* mainloop_source_fixed(struct pa_mainloop_api*a, void (*callback) (s m = a->userdata; assert(a == &m->api); - s = malloc(sizeof(struct mainloop_source_fixed_or_idle)); - assert(s); + s = pa_xmalloc(sizeof(struct mainloop_source_fixed_or_idle)); s->header.mainloop = m; s->header.dead = 0; @@ -439,8 +437,7 @@ static void* mainloop_source_idle(struct pa_mainloop_api*a, void (*callback) (st m = a->userdata; assert(a == &m->api); - s = malloc(sizeof(struct mainloop_source_fixed_or_idle)); - assert(s); + s = pa_xmalloc(sizeof(struct mainloop_source_fixed_or_idle)); s->header.mainloop = m; s->header.dead = 0; @@ -471,8 +468,7 @@ static void* mainloop_source_time(struct pa_mainloop_api*a, const struct timeval m = a->userdata; assert(a == &m->api); - s = malloc(sizeof(struct mainloop_source_time)); - assert(s); + s = pa_xmalloc(sizeof(struct mainloop_source_time)); s->header.mainloop = m; s->header.dead = 0; diff --git a/polyp/memblock.c b/polyp/memblock.c index 8f24ff22..0571f5da 100644 --- a/polyp/memblock.c +++ b/polyp/memblock.c @@ -29,11 +29,12 @@ #include #include "memblock.h" +#include "xmalloc.h" static unsigned memblock_count = 0, memblock_total = 0; struct pa_memblock *pa_memblock_new(size_t length) { - struct pa_memblock *b = malloc(sizeof(struct pa_memblock)+length); + struct pa_memblock *b = pa_xmalloc(sizeof(struct pa_memblock)+length); b->type = PA_MEMBLOCK_APPENDED; b->ref = 1; b->length = length; @@ -44,7 +45,7 @@ struct pa_memblock *pa_memblock_new(size_t length) { } struct pa_memblock *pa_memblock_new_fixed(void *d, size_t length) { - struct pa_memblock *b = malloc(sizeof(struct pa_memblock)); + struct pa_memblock *b = pa_xmalloc(sizeof(struct pa_memblock)); b->type = PA_MEMBLOCK_FIXED; b->ref = 1; b->length = length; @@ -55,7 +56,7 @@ struct pa_memblock *pa_memblock_new_fixed(void *d, size_t length) { } struct pa_memblock *pa_memblock_new_dynamic(void *d, size_t length) { - struct pa_memblock *b = malloc(sizeof(struct pa_memblock)); + struct pa_memblock *b = pa_xmalloc(sizeof(struct pa_memblock)); b->type = PA_MEMBLOCK_DYNAMIC; b->ref = 1; b->length = length; @@ -77,12 +78,12 @@ void pa_memblock_unref(struct pa_memblock*b) { if (b->ref == 0) { if (b->type == PA_MEMBLOCK_DYNAMIC) - free(b->data); + pa_xfree(b->data); memblock_count--; memblock_total -= b->length; - free(b); + pa_xfree(b); } } @@ -95,8 +96,7 @@ void pa_memblock_unref_fixed(struct pa_memblock *b) { pa_memblock_unref(b); return; } else { - d = malloc(b->length); - assert(d); + d = pa_xmalloc(b->length); memcpy(d, b->data, b->length); b->data = d; b->type = PA_MEMBLOCK_DYNAMIC; diff --git a/polyp/memblockq.c b/polyp/memblockq.c index eff923b9..4019c893 100644 --- a/polyp/memblockq.c +++ b/polyp/memblockq.c @@ -30,6 +30,7 @@ #include #include "memblockq.h" +#include "xmalloc.h" struct memblock_list { struct memblock_list *next; @@ -50,8 +51,7 @@ struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t b struct pa_memblockq* bq; assert(maxlength && base && maxlength); - bq = malloc(sizeof(struct pa_memblockq)); - assert(bq); + bq = pa_xmalloc(sizeof(struct pa_memblockq)); bq->blocks = bq->blocks_tail = 0; bq->n_blocks = 0; @@ -97,10 +97,10 @@ void pa_memblockq_free(struct pa_memblockq* bq) { while ((l = bq->blocks)) { bq->blocks = l->next; pa_memblock_unref(l->chunk.memblock); - free(l); + pa_xfree(l); } - free(bq); + pa_xfree(bq); } void pa_memblockq_push(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta) { @@ -119,8 +119,7 @@ void pa_memblockq_push(struct pa_memblockq* bq, const struct pa_memchunk *chunk, } } - q = malloc(sizeof(struct memblock_list)); - assert(q); + q = pa_xmalloc(sizeof(struct memblock_list)); if (bq->measure_delay) gettimeofday(&q->stamp, NULL); @@ -181,7 +180,7 @@ int memblockq_pop(struct memblockq* bq, struct pa_memchunk *chunk) { bq->n_blocks--; bq->current_length -= chunk->length; - free(q); + pa_xfree(q); return 0; } */ @@ -231,7 +230,7 @@ void pa_memblockq_drop(struct pa_memblockq *bq, size_t length) { if (bq->blocks == NULL) bq->blocks_tail = NULL; pa_memblock_unref(q->chunk.memblock); - free(q); + pa_xfree(q); bq->n_blocks--; } diff --git a/polyp/memchunk.c b/polyp/memchunk.c index d27ca61a..77e1b7dd 100644 --- a/polyp/memchunk.c +++ b/polyp/memchunk.c @@ -29,6 +29,7 @@ #include #include "memchunk.h" +#include "xmalloc.h" void pa_memchunk_make_writable(struct pa_memchunk *c) { struct pa_memblock *n; @@ -57,8 +58,7 @@ struct pa_mcalign *pa_mcalign_new(size_t base) { struct pa_mcalign *m; assert(base); - m = malloc(sizeof(struct pa_mcalign)); - assert(m); + m = pa_xmalloc(sizeof(struct pa_mcalign)); m->base = base; m->chunk.memblock = NULL; m->chunk.length = m->chunk.index = 0; @@ -70,12 +70,12 @@ struct pa_mcalign *pa_mcalign_new(size_t base) { void pa_mcalign_free(struct pa_mcalign *m) { assert(m); - free(m->buffer); + pa_xfree(m->buffer); if (m->chunk.memblock) pa_memblock_unref(m->chunk.memblock); - free(m); + pa_xfree(m); } void pa_mcalign_push(struct pa_mcalign *m, const struct pa_memchunk *c) { @@ -128,8 +128,7 @@ int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c) { if (m->buffer_fill) { assert(!m->buffer); - m->buffer = malloc(m->base); - assert(m->buffer); + m->buffer = pa_xmalloc(m->base); m->chunk.length -= m->buffer_fill; memcpy(m->buffer, m->chunk.memblock->data + m->chunk.index + m->chunk.length, m->buffer_fill); } diff --git a/polyp/modargs.c b/polyp/modargs.c index 3841a9ec..87d99ad2 100644 --- a/polyp/modargs.c +++ b/polyp/modargs.c @@ -35,8 +35,7 @@ #include "namereg.h" #include "sink.h" #include "source.h" - -#include "debug.h" +#include "xmalloc.h" struct pa_modargs; @@ -55,14 +54,13 @@ static int add_key_value(struct pa_hashmap *map, char *key, char *value, const c break; if (!*v) { - free(key); - free(value); + pa_xfree(key); + pa_xfree(value); return -1; } } - e = malloc(sizeof(struct entry)); - assert(e); + e = pa_xmalloc(sizeof(struct entry)); e->key = key; e->value = value; pa_hashmap_put(map, key, e); @@ -109,7 +107,7 @@ struct pa_modargs *pa_modargs_new(const char *args, const char* const* valid_key value = p+1; value_len = 0; } else if (isspace(*p)) { - if (add_key_value(map, strndup(key, key_len), strdup(""), valid_keys) < 0) + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0) goto fail; state = WHITESPACE; } else { @@ -120,7 +118,7 @@ struct pa_modargs *pa_modargs_new(const char *args, const char* const* valid_key break; case VALUE_SIMPLE: if (isspace(*p)) { - if (add_key_value(map, strndup(key, key_len), strndup(value, value_len), valid_keys) < 0) + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) goto fail; state = WHITESPACE; } else @@ -128,7 +126,7 @@ struct pa_modargs *pa_modargs_new(const char *args, const char* const* valid_key break; case VALUE_DOUBLE_QUOTES: if (*p == '"') { - if (add_key_value(map, strndup(key, key_len), strndup(value, value_len), valid_keys) < 0) + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) goto fail; state = WHITESPACE; } else @@ -136,7 +134,7 @@ struct pa_modargs *pa_modargs_new(const char *args, const char* const* valid_key break; case VALUE_TICKS: if (*p == '\'') { - if (add_key_value(map, strndup(key, key_len), strndup(value, value_len), valid_keys) < 0) + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) goto fail; state = WHITESPACE; } else @@ -146,10 +144,10 @@ struct pa_modargs *pa_modargs_new(const char *args, const char* const* valid_key } if (state == VALUE_START) { - if (add_key_value(map, strndup(key, key_len), strdup(""), valid_keys) < 0) + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0) goto fail; } else if (state == VALUE_SIMPLE) { - if (add_key_value(map, strndup(key, key_len), strdup(value), valid_keys) < 0) + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(value), valid_keys) < 0) goto fail; } else if (state != WHITESPACE) goto fail; @@ -169,9 +167,9 @@ fail: static void free_func(void *p, void*userdata) { struct entry *e = p; assert(e); - free(e->key); - free(e->value); - free(e); + pa_xfree(e->key); + pa_xfree(e->value); + pa_xfree(e); } void pa_modargs_free(struct pa_modargs*ma) { @@ -256,37 +254,3 @@ int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *rss return 0; } - -int pa_modargs_get_source_index(struct pa_modargs *ma, struct pa_core *c, uint32_t *index) { - const char *t; - assert(ma && index); - - if (!(t = pa_modargs_get_value(ma, "source", NULL))) - *index = PA_IDXSET_INVALID; - else { - struct pa_source *source; - if (!(source = pa_namereg_get(c, t, PA_NAMEREG_SOURCE))) - return -1; - - *index = source->index; - } - - return 0; -} - -int pa_modargs_get_sink_index(struct pa_modargs *ma, struct pa_core *c, uint32_t *index) { - const char *t; - assert(ma && index); - - if (!(t = pa_modargs_get_value(ma, "sink", NULL))) - *index = PA_IDXSET_INVALID; - else { - struct pa_sink *sink; - if (!(sink = pa_namereg_get(c, t, PA_NAMEREG_SINK))) - return -1; - - *index = sink->index; - } - - return 0; -} diff --git a/polyp/modargs.h b/polyp/modargs.h index 301dc297..872fb14f 100644 --- a/polyp/modargs.h +++ b/polyp/modargs.h @@ -36,7 +36,4 @@ int pa_modargs_get_value_u32(struct pa_modargs *ma, const char *key, uint32_t *v int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *ss); -int pa_modargs_get_source_index(struct pa_modargs *ma, struct pa_core *c, uint32_t *index); -int pa_modargs_get_sink_index(struct pa_modargs *ma, struct pa_core *c, uint32_t *index); - #endif diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index c1958227..a0fa52db 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -37,6 +37,7 @@ #include "util.h" #include "sample-util.h" #include "alsa-util.h" +#include "xmalloc.h" struct userdata { snd_pcm_t *pcm_handle; @@ -46,6 +47,7 @@ struct userdata { size_t frame_size, fragment_size; struct pa_memchunk memchunk, silence; + struct pa_module *module; }; static const char* const valid_modargs[] = { @@ -62,6 +64,12 @@ static const char* const valid_modargs[] = { #define DEFAULT_SINK_NAME "alsa_output" #define DEFAULT_DEVICE "plughw:0,0" +static void update_usage(struct userdata *u) { + pa_module_set_used(u->module, + (u->sink ? pa_idxset_ncontents(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_ncontents(u->sink->monitor_source->outputs) : 0)); +} + static void xrun_recovery(struct userdata *u) { assert(u); @@ -74,6 +82,8 @@ static void xrun_recovery(struct userdata *u) { static void do_write(struct userdata *u) { assert(u); + update_usage(u); + for (;;) { struct pa_memchunk *memchunk = NULL; snd_pcm_sframes_t frames; @@ -175,10 +185,9 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { } buffer_size = fragsize/frame_size*periods; - u = malloc(sizeof(struct userdata)); - assert(u); - memset(u, 0, sizeof(struct userdata)); + u = pa_xmalloc0(sizeof(struct userdata)); m->userdata = u; + u->module = m; if (snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) { fprintf(stderr, __FILE__": Error opening PCM device %s\n", dev); @@ -236,24 +245,25 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { struct userdata *u; assert(c && m); - if ((u = m->userdata)) { - if (u->sink) - pa_sink_free(u->sink); - - if (u->io_sources) - pa_free_io_sources(c->mainloop, u->io_sources, u->n_io_sources); - - if (u->pcm_handle) { - snd_pcm_drop(u->pcm_handle); - snd_pcm_close(u->pcm_handle); - } - - if (u->memchunk.memblock) - pa_memblock_unref(u->memchunk.memblock); - if (u->silence.memblock) - pa_memblock_unref(u->silence.memblock); - - free(u); + if (!(u = m->userdata)) + return; + + if (u->sink) + pa_sink_free(u->sink); + + if (u->io_sources) + pa_free_io_sources(c->mainloop, u->io_sources, u->n_io_sources); + + if (u->pcm_handle) { + snd_pcm_drop(u->pcm_handle); + snd_pcm_close(u->pcm_handle); } + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + if (u->silence.memblock) + pa_memblock_unref(u->silence.memblock); + + pa_xfree(u); } diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index a453944e..8207d462 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -37,6 +37,7 @@ #include "util.h" #include "sample-util.h" #include "alsa-util.h" +#include "xmalloc.h" struct userdata { snd_pcm_t *pcm_handle; @@ -46,6 +47,7 @@ struct userdata { size_t frame_size, fragment_size; struct pa_memchunk memchunk; + struct pa_module *module; }; static const char* const valid_modargs[] = { @@ -62,6 +64,11 @@ static const char* const valid_modargs[] = { #define DEFAULT_SOURCE_NAME "alsa_input" #define DEFAULT_DEVICE "hw:0,0" +static void update_usage(struct userdata *u) { + pa_module_set_used(u->module, + (u->source ? pa_idxset_ncontents(u->source->outputs) : 0)); +} + static void xrun_recovery(struct userdata *u) { assert(u); @@ -74,6 +81,8 @@ static void xrun_recovery(struct userdata *u) { static void do_read(struct userdata *u) { assert(u); + update_usage(u); + for (;;) { struct pa_memchunk post_memchunk; snd_pcm_sframes_t frames; @@ -159,10 +168,9 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { } buffer_size = fragsize/frame_size*periods; - u = malloc(sizeof(struct userdata)); - assert(u); - memset(u, 0, sizeof(struct userdata)); + u = pa_xmalloc0(sizeof(struct userdata)); m->userdata = u; + u->module = m; if (snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK) < 0) { fprintf(stderr, __FILE__": Error opening PCM device %s\n", dev); @@ -216,22 +224,23 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { struct userdata *u; assert(c && m); - if ((u = m->userdata)) { - if (u->source) - pa_source_free(u->source); - - if (u->io_sources) - pa_free_io_sources(c->mainloop, u->io_sources, u->n_io_sources); - - if (u->pcm_handle) { - snd_pcm_drop(u->pcm_handle); - snd_pcm_close(u->pcm_handle); - } - - if (u->memchunk.memblock) - pa_memblock_unref(u->memchunk.memblock); - - free(u); + if (!(u = m->userdata)) + return; + + if (u->source) + pa_source_free(u->source); + + if (u->io_sources) + pa_free_io_sources(c->mainloop, u->io_sources, u->n_io_sources); + + if (u->pcm_handle) { + snd_pcm_drop(u->pcm_handle); + snd_pcm_close(u->pcm_handle); } + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + + pa_xfree(u); } diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index 30ff3ce6..37710fc5 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -44,6 +44,7 @@ #include "sample-util.h" #include "util.h" #include "modargs.h" +#include "xmalloc.h" struct userdata { struct pa_sink *sink; @@ -62,6 +63,7 @@ struct userdata { struct pa_memblock **in_memblocks, **out_memblocks; unsigned out_current, in_current; + struct pa_module *module; }; static const char* const valid_modargs[] = { @@ -82,6 +84,13 @@ static const char* const valid_modargs[] = { #define DEFAULT_SOURCE_NAME "oss_input" #define DEFAULT_DEVICE "/dev/dsp" +static void update_usage(struct userdata *u) { + pa_module_set_used(u->module, + (u->sink ? pa_idxset_ncontents(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_ncontents(u->sink->monitor_source->outputs) : 0) + + (u->source ? pa_idxset_ncontents(u->source->outputs) : 0)); +} + static void out_fill_memblocks(struct userdata *u, unsigned n) { assert(u && u->out_memblocks); @@ -110,6 +119,8 @@ static void do_write(struct userdata *u) { struct count_info info; assert(u && u->sink); + update_usage(u); + if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { fprintf(stderr, "SNDCTL_DSP_GETOPTR: %s\n", strerror(errno)); return; @@ -170,6 +181,8 @@ static void do_read(struct userdata *u) { struct count_info info; assert(u && u->source); + update_usage(u); + if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { fprintf(stderr, "SNDCTL_DSP_GETIPTR: %s\n", strerror(errno)); return; @@ -212,9 +225,8 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { struct pa_modargs *ma = NULL; assert(c && m); - m->userdata = u = malloc(sizeof(struct userdata)); - assert(u); - memset(u, 0, sizeof(struct userdata)); + m->userdata = u = pa_xmalloc0(sizeof(struct userdata)); + u->module = m; u->fd = -1; u->core = c; @@ -288,9 +300,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { pa_source_set_owner(u->source, m); u->source->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'", p); - - u->in_memblocks = malloc(sizeof(struct pa_memblock *)*u->in_fragments); - memset(u->in_memblocks, 0, sizeof(struct pa_memblock *)*u->in_fragments); + u->in_memblocks = pa_xmalloc0(sizeof(struct pa_memblock *)*u->in_fragments); enable_bits |= PCM_ENABLE_INPUT; } @@ -323,8 +333,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { pa_sink_set_owner(u->sink, m); u->sink->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'", p); - u->out_memblocks = malloc(sizeof(struct memblock *)*u->out_fragments); - memset(u->out_memblocks, 0, sizeof(struct pa_memblock *)*u->out_fragments); + u->out_memblocks = pa_xmalloc0(sizeof(struct memblock *)*u->out_fragments); enable_bits |= PCM_ENABLE_OUTPUT; } @@ -363,15 +372,15 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { struct userdata *u; assert(c && m); - u = m->userdata; - assert(u); + if (!(u = m->userdata)) + return; if (u->out_memblocks) { unsigned i; for (i = 0; i < u->out_fragments; i++) if (u->out_memblocks[i]) pa_memblock_unref_fixed(u->out_memblocks[i]); - free(u->out_memblocks); + pa_xfree(u->out_memblocks); } if (u->in_memblocks) { @@ -379,7 +388,7 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { for (i = 0; i < u->in_fragments; i++) if (u->in_memblocks[i]) pa_memblock_unref_fixed(u->in_memblocks[i]); - free(u->in_memblocks); + pa_xfree(u->in_memblocks); } if (u->in_mmap && u->in_mmap != MAP_FAILED) @@ -400,5 +409,5 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { if (u->fd >= 0) close(u->fd); - free(u); + pa_xfree(u); } diff --git a/polyp/module-oss.c b/polyp/module-oss.c index 51585ca9..a8db4a33 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -43,6 +43,7 @@ #include "sample-util.h" #include "util.h" #include "modargs.h" +#include "xmalloc.h" struct userdata { struct pa_sink *sink; @@ -55,6 +56,7 @@ struct userdata { uint32_t in_fragment_size, out_fragment_size, sample_size; int fd; + struct pa_module *module; }; static const char* const valid_modargs[] = { @@ -75,6 +77,13 @@ static const char* const valid_modargs[] = { #define DEFAULT_SOURCE_NAME "oss_input" #define DEFAULT_DEVICE "/dev/dsp" +static void update_usage(struct userdata *u) { + pa_module_set_used(u->module, + (u->sink ? pa_idxset_ncontents(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_ncontents(u->sink->monitor_source->outputs) : 0) + + (u->source ? pa_idxset_ncontents(u->source->outputs) : 0)); +} + static void do_write(struct userdata *u) { struct pa_memchunk *memchunk; ssize_t r; @@ -83,6 +92,8 @@ static void do_write(struct userdata *u) { if (!u->sink || !pa_iochannel_is_writable(u->io)) return; + update_usage(u); + if (!u->memchunk.length) { if (pa_sink_render(u->sink, u->out_fragment_size, &u->memchunk) < 0) memchunk = &u->silence; @@ -118,6 +129,8 @@ static void do_read(struct userdata *u) { if (!u->source || !pa_iochannel_is_readable(u->io)) return; + update_usage(u); + memchunk.memblock = pa_memblock_new(u->in_fragment_size); assert(memchunk.memblock); if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { @@ -225,9 +238,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { out_frag_size = info.fragsize; } - u = malloc(sizeof(struct userdata)); - assert(u); - + u = pa_xmalloc(sizeof(struct userdata)); u->core = c; if (mode != O_WRONLY) { @@ -266,7 +277,8 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { assert(u->silence.memblock); pa_silence_memblock(u->silence.memblock, &ss); u->silence.index = 0; - + + u->module = m; m->userdata = u; pa_modargs_free(ma); @@ -287,8 +299,8 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { struct userdata *u; assert(c && m); - u = m->userdata; - assert(u); + if (!(u = m->userdata)) + return; if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); @@ -299,6 +311,7 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { pa_sink_free(u->sink); if (u->source) pa_source_free(u->source); + pa_iochannel_free(u->io); - free(u); + pa_xfree(u); } diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c index df34f73a..dc2bc633 100644 --- a/polyp/module-pipe-sink.c +++ b/polyp/module-pipe-sink.c @@ -38,6 +38,7 @@ #include "module.h" #include "util.h" #include "modargs.h" +#include "xmalloc.h" #define DEFAULT_FIFO_NAME "/tmp/musicfifo" #define DEFAULT_SINK_NAME "fifo_output" @@ -52,6 +53,7 @@ struct userdata { void *mainloop_source; struct pa_memchunk memchunk; + struct pa_module *module; }; static const char* const valid_modargs[] = { @@ -72,6 +74,8 @@ static void do_write(struct userdata *u) { if (!pa_iochannel_is_writable(u->io)) return; + pa_module_set_used(u->module, pa_idxset_ncontents(u->sink->inputs) + pa_idxset_ncontents(u->sink->monitor_source->outputs)); + if (!u->memchunk.length) if (pa_sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0) return; @@ -149,12 +153,9 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { goto fail; } - u = malloc(sizeof(struct userdata)); - assert(u); - memset(u, 0, sizeof(struct userdata)); + u = pa_xmalloc0(sizeof(struct userdata)); - u->filename = strdup(p); - assert(u->filename); + u->filename = pa_xstrdup(p); u->core = c; if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { @@ -177,7 +178,8 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { u->mainloop_source = c->mainloop->source_fixed(c->mainloop, fixed_callback, u); assert(u->mainloop_source); c->mainloop->enable_fixed(c->mainloop, u->mainloop_source, 0); - + + u->module = m; m->userdata = u; pa_modargs_free(ma); @@ -212,7 +214,7 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { assert(u->filename); unlink(u->filename); - free(u->filename); + pa_xfree(u->filename); - free(u); + pa_xfree(u); } diff --git a/polyp/module-x11-bell.c b/polyp/module-x11-bell.c index 4da3c880..2cf76099 100644 --- a/polyp/module-x11-bell.c +++ b/polyp/module-x11-bell.c @@ -10,6 +10,8 @@ #include "sink.h" #include "scache.h" #include "modargs.h" +#include "xmalloc.h" +#include "namereg.h" struct x11_source { void *io_source; @@ -22,7 +24,7 @@ struct userdata { struct x11_source *x11_sources; int xkb_event_base; - int sink_index; + char *sink_name; char *scache_item; }; @@ -33,22 +35,11 @@ static const char* const valid_modargs[] = { NULL }; -static struct pa_sink* get_output_sink(struct userdata *u) { - struct pa_sink *s; - assert(u); - - if (!(s = pa_idxset_get_by_index(u->core->sinks, u->sink_index))) - s = pa_sink_get_default(u->core); - - u->sink_index = s ? s->index : PA_IDXSET_INVALID; - return s; -} - static int ring_bell(struct userdata *u, int percent) { struct pa_sink *s; assert(u); - if (!(s = get_output_sink(u))) { + if (!(s = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) { fprintf(stderr, __FILE__": Invalid sink\n"); return -1; } @@ -85,8 +76,7 @@ static void io_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_main static void new_io_source(struct userdata *u, int fd) { struct x11_source *s; - s = malloc(sizeof(struct x11_source)); - assert(s); + s = pa_xmalloc(sizeof(struct x11_source)); s->io_source = u->core->mainloop->source_io(u->core->mainloop, fd, PA_MAINLOOP_API_IO_EVENT_INPUT, io_callback, u); assert(s->io_source); s->next = u->x11_sources; @@ -105,18 +95,12 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { goto fail; } - m->userdata = u = malloc(sizeof(struct userdata)); - assert(u); + m->userdata = u = pa_xmalloc(sizeof(struct userdata)); u->core = c; u->display = NULL; u->x11_sources = NULL; - u->scache_item = strdup(pa_modargs_get_value(ma, "sample", "x11-bell")); - assert(u->scache_item); - - if (pa_modargs_get_sink_index(ma, c, &u->sink_index) < 0) { - fprintf(stderr, __FILE__": Invalid sink specified\n"); - goto fail; - } + u->scache_item = pa_xstrdup(pa_modargs_get_value(ma, "sample", "x11-bell")); + u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); if (!(u->display = XOpenDisplay(pa_modargs_get_value(ma, "display", NULL)))) { fprintf(stderr, __FILE__": XOpenDisplay() failed\n"); @@ -166,12 +150,12 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { struct x11_source *s = u->x11_sources; u->x11_sources = u->x11_sources->next; c->mainloop->cancel_io(c->mainloop, s->io_source); - free(s); + pa_xfree(s); } - free(u->scache_item); + pa_xfree(u->scache_item); if (u->display) XCloseDisplay(u->display); - free(u); + pa_xfree(u); } diff --git a/polyp/module.c b/polyp/module.c index 5c6f0fb6..8c5e318f 100644 --- a/polyp/module.c +++ b/polyp/module.c @@ -31,6 +31,21 @@ #include #include "module.h" +#include "xmalloc.h" + +#define UNLOAD_POLL_TIME 10 + +static void timeout_callback(struct pa_mainloop_api *m, void *id, const struct timeval *tv, void *userdata) { + struct pa_core *c = userdata; + struct timeval ntv; + assert(c && c->mainloop == m && c->auto_unload_mainloop_source == id); + + pa_module_unload_unused(c); + + gettimeofday(&ntv, NULL); + ntv.tv_sec += UNLOAD_POLL_TIME; + m->enable_time(m, id, &ntv); +} struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char *argument) { struct pa_module *m = NULL; @@ -38,11 +53,10 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char assert(c && name); - m = malloc(sizeof(struct pa_module)); - assert(m); + m = pa_xmalloc(sizeof(struct pa_module)); - m->name = strdup(name); - m->argument = argument ? strdup(argument) : NULL; + m->name = pa_xstrdup(name); + m->argument = pa_xstrdup(argument); if (!(m->dl = lt_dlopenext(name))) goto fail; @@ -55,6 +69,8 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char m->userdata = NULL; m->core = c; + m->n_used = -1; + m->auto_unload = 0; assert(m->init); if (m->init(c, m) < 0) @@ -62,6 +78,14 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char if (!c->modules) c->modules = pa_idxset_new(NULL, NULL); + + if (!c->auto_unload_mainloop_source) { + struct timeval ntv; + gettimeofday(&ntv, NULL); + ntv.tv_sec += UNLOAD_POLL_TIME; + c->auto_unload_mainloop_source = c->mainloop->source_time(c->mainloop, &ntv, timeout_callback, c); + } + assert(c->auto_unload_mainloop_source); assert(c->modules); r = pa_idxset_put(c->modules, m, &m->index); @@ -73,13 +97,13 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char fail: if (m) { - free(m->argument); - free(m->name); + pa_xfree(m->argument); + pa_xfree(m->name); if (m->dl) lt_dlclose(m->dl); - free(m); + pa_xfree(m); } return NULL; @@ -93,9 +117,9 @@ static void pa_module_free(struct pa_module *m) { fprintf(stderr, "module: unloaded %u \"%s\".\n", m->index, m->name); - free(m->name); - free(m->argument); - free(m); + pa_xfree(m->name); + pa_xfree(m->argument); + pa_xfree(m); } @@ -134,6 +158,34 @@ void pa_module_unload_all(struct pa_core *c) { pa_idxset_free(c->modules, free_callback, NULL); c->modules = NULL; + + if (c->auto_unload_mainloop_source) + c->mainloop->cancel_time(c->mainloop, c->auto_unload_mainloop_source); + c->auto_unload_mainloop_source = NULL; +} + +static int unused_callback(void *p, uint32_t index, int *del, void *userdata) { + struct pa_module *m = p; + time_t *now = userdata; + assert(p && del && now); + + if (m->n_used == 0 && m->auto_unload && m->last_used_time+m->core->auto_unload_time <= *now) { + pa_module_free(m); + *del = 1; + } + + return 0; +} + +void pa_module_unload_unused(struct pa_core *c) { + time_t now; + assert(c); + + if (!c->modules) + return; + + time(&now); + pa_idxset_foreach(c->modules, unused_callback, &now); } struct once_info { @@ -141,21 +193,29 @@ struct once_info { uint32_t index; }; - static void module_unload_once_callback(void *userdata) { struct once_info *i = userdata; assert(i); pa_module_unload_by_index(i->core, i->index); - free(i); + pa_xfree(i); } void pa_module_unload_request(struct pa_core *c, struct pa_module *m) { struct once_info *i; assert(c && m); - i = malloc(sizeof(struct once_info)); - assert(i); + i = pa_xmalloc(sizeof(struct once_info)); i->core = c; i->index = m->index; pa_mainloop_api_once(c->mainloop, module_unload_once_callback, i); } + +void pa_module_set_used(struct pa_module*m, int used) { + assert(m); + + if (m->n_used != used && used == 0) + time(&m->last_used_time); + + m->n_used = used; +} + diff --git a/polyp/module.h b/polyp/module.h index af2d8552..de195a4b 100644 --- a/polyp/module.h +++ b/polyp/module.h @@ -38,6 +38,10 @@ struct pa_module { void (*done)(struct pa_core *c, struct pa_module*m); void *userdata; + + int n_used; + int auto_unload; + time_t last_used_time; }; struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char*argument); @@ -45,6 +49,7 @@ void pa_module_unload(struct pa_core *c, struct pa_module *m); void pa_module_unload_by_index(struct pa_core *c, uint32_t index); void pa_module_unload_all(struct pa_core *c); +void pa_module_unload_unused(struct pa_core *c); void pa_module_unload_request(struct pa_core *c, struct pa_module *m); @@ -52,4 +57,7 @@ void pa_module_unload_request(struct pa_core *c, struct pa_module *m); int pa_module_init(struct pa_core *c, struct pa_module*m); void pa_module_done(struct pa_core *c, struct pa_module*m); +void pa_module_set_used(struct pa_module*m, int used); + + #endif diff --git a/polyp/namereg.c b/polyp/namereg.c index 2349436f..b6a8c23f 100644 --- a/polyp/namereg.c +++ b/polyp/namereg.c @@ -31,6 +31,10 @@ #include #include "namereg.h" +#include "autoload.h" +#include "source.h" +#include "sink.h" +#include "xmalloc.h" struct namereg_entry { enum pa_namereg_type type; @@ -62,12 +66,11 @@ const char *pa_namereg_register(struct pa_core *c, const char *name, enum pa_nam return NULL; if (!e) - n = strdup(name); + n = pa_xstrdup(name); else { unsigned i; size_t l = strlen(name); - n = malloc(l+3); - assert(n); + n = pa_xmalloc(l+3); for (i = 1; i <= 99; i++) { snprintf(n, l+2, "%s%u", name, i); @@ -77,14 +80,13 @@ const char *pa_namereg_register(struct pa_core *c, const char *name, enum pa_nam } if (e) { - free(n); + pa_xfree(n); return NULL; } } assert(n); - e = malloc(sizeof(struct namereg_entry)); - assert(e); + e = pa_xmalloc(sizeof(struct namereg_entry)); e->type = type; e->name = n; e->data = data; @@ -107,25 +109,66 @@ void pa_namereg_unregister(struct pa_core *c, const char *name) { r = pa_hashmap_remove(c->namereg, name); assert(r >= 0); - free(e->name); - free(e); + pa_xfree(e->name); + pa_xfree(e); } -void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type type) { +void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type type, int autoload) { struct namereg_entry *e; uint32_t index; char *x = NULL; void *d = NULL; - assert(c && name); + assert(c); + + if (!name) { + if (type == PA_NAMEREG_SOURCE) { + if (!c->default_source_name) { + struct pa_source *s; + + for (s = pa_idxset_first(c->sources, &index); s; s = pa_idxset_next(c->sources, &index)) + if (!s->monitor_of) { + pa_namereg_set_default(c, s->name, PA_NAMEREG_SOURCE); + break; + } + } + + name = c->default_source_name; + + } else { + assert(type == PA_NAMEREG_SINK); + + if (!c->default_sink_name) { + struct pa_sink *s; + + if ((s = pa_idxset_first(c->sinks, NULL))) + pa_namereg_set_default(c, s->name, PA_NAMEREG_SINK); + } + + name = c->default_sink_name; + } + } - if ((e = pa_hashmap_get(c->namereg, name))) + if (!name) + return NULL; + + if (c->namereg && (e = pa_hashmap_get(c->namereg, name))) if (e->type == e->type) return e->data; index = (uint32_t) strtol(name, &x, 0); - if (!x || *x != 0) + if (!x || *x != 0) { + + if (autoload) { + pa_autoload_request(c, name, type); + + if (c->namereg && (e = pa_hashmap_get(c->namereg, name))) + if (e->type == e->type) + return e->data; + } + return NULL; + } if (type == PA_NAMEREG_SINK) d = pa_idxset_get_by_index(c->sinks, index); @@ -134,3 +177,14 @@ void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type t return d; } + +void pa_namereg_set_default(struct pa_core*c, const char *name, enum pa_namereg_type type) { + char **s; + assert(c); + + s = type == PA_NAMEREG_SINK ? &c->default_sink_name : &c->default_source_name; + assert(s); + + pa_xfree(*s); + *s = pa_xstrdup(name); +} diff --git a/polyp/namereg.h b/polyp/namereg.h index 0af83cd8..5bc92693 100644 --- a/polyp/namereg.h +++ b/polyp/namereg.h @@ -33,6 +33,7 @@ void pa_namereg_free(struct pa_core *c); const char *pa_namereg_register(struct pa_core *c, const char *name, enum pa_namereg_type type, void *data, int fail); void pa_namereg_unregister(struct pa_core *c, const char *name); -void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type type); +void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type type, int autoload); +void pa_namereg_set_default(struct pa_core*c, const char *name, enum pa_namereg_type type); #endif diff --git a/polyp/packet.c b/polyp/packet.c index e94df057..955feeb1 100644 --- a/polyp/packet.c +++ b/polyp/packet.c @@ -27,13 +27,12 @@ #include #include "packet.h" +#include "xmalloc.h" struct pa_packet* pa_packet_new(size_t length) { struct pa_packet *p; assert(length); - p = malloc(sizeof(struct pa_packet)+length); - assert(p); - + p = pa_xmalloc(sizeof(struct pa_packet)+length); p->ref = 1; p->length = length; p->data = (uint8_t*) (p+1); @@ -44,9 +43,7 @@ struct pa_packet* pa_packet_new(size_t length) { struct pa_packet* pa_packet_new_dynamic(uint8_t* data, size_t length) { struct pa_packet *p; assert(data && length); - p = malloc(sizeof(struct pa_packet)); - assert(p); - + p = pa_xmalloc(sizeof(struct pa_packet)); p->ref = 1; p->length = length; p->data = data; @@ -66,7 +63,7 @@ void pa_packet_unref(struct pa_packet *p) { if (p->ref == 0) { if (p->type == PA_PACKET_DYNAMIC) - free(p->data); - free(p); + pa_xfree(p->data); + pa_xfree(p); } } diff --git a/polyp/pdispatch.c b/polyp/pdispatch.c index 2ab98b52..c34c6e0a 100644 --- a/polyp/pdispatch.c +++ b/polyp/pdispatch.c @@ -29,6 +29,7 @@ #include "pdispatch.h" #include "native-common.h" +#include "xmalloc.h" /*#define DEBUG_OPCODES*/ @@ -96,7 +97,7 @@ static void reply_info_free(struct reply_info *r) { if (r->next) r->next->previous = r->previous; - free(r); + pa_xfree(r); } struct pa_pdispatch* pa_pdispatch_new(struct pa_mainloop_api *mainloop, const struct pa_pdispatch_command*table, unsigned entries) { @@ -105,8 +106,7 @@ struct pa_pdispatch* pa_pdispatch_new(struct pa_mainloop_api *mainloop, const st assert((entries && table) || (!entries && !table)); - pd = malloc(sizeof(struct pa_pdispatch)); - assert(pd); + pd = pa_xmalloc(sizeof(struct pa_pdispatch)); pd->mainloop = mainloop; pd->command_table = table; pd->n_commands = entries; @@ -129,7 +129,7 @@ void pa_pdispatch_free(struct pa_pdispatch *pd) { while (pd->replies) reply_info_free(pd->replies); - free(pd); + pa_xfree(pd); } int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *userdata) { @@ -207,8 +207,7 @@ void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int time struct timeval tv; assert(pd && cb); - r = malloc(sizeof(struct reply_info)); - assert(r); + r = pa_xmalloc(sizeof(struct reply_info)); r->pdispatch = pd; r->callback = cb; r->userdata = userdata; diff --git a/polyp/polypaudio.pa b/polyp/polypaudio.pa index 79ca83ea..0989a78d 100755 --- a/polyp/polypaudio.pa +++ b/polyp/polypaudio.pa @@ -21,7 +21,7 @@ # Load audio drivers #load module-alsa-sink #load module-alsa-source device=plughw:1,0 -load module-oss device="/dev/dsp" +#load module-oss device="/dev/dsp" #load module-oss-mmap device="/dev/dsp" # Load several protocols @@ -36,9 +36,15 @@ load module-x11-bell # Load the CLI module load module-cli -.nofail +autoload_sink_add oss_output module-oss device="/dev/dsp" sink_name=oss_output source_name=oss_input +autoload_source_add oss_input module-oss device="/dev/dsp" sink_name=oss_output source_name=oss_input # Make some devices default sink_default oss_output source_default oss_input +.nofail + +# Load something to the sample cache +scache_load /usr/share/sounds/KDE_Notify.wav x11-bell +scache_play x11-bell oss_output diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c index 024cb18a..1f5ea553 100644 --- a/polyp/polyplib-simple.c +++ b/polyp/polyplib-simple.c @@ -32,7 +32,7 @@ #include "polyplib.h" #include "mainloop.h" #include "native-common.h" -/*#include "polyp-error.h"*/ +#include "xmalloc.h" struct pa_simple { struct pa_mainloop *mainloop; @@ -98,8 +98,7 @@ struct pa_simple* pa_simple_new( int error = PA_ERROR_INTERNAL; assert(ss); - p = malloc(sizeof(struct pa_simple)); - assert(p); + p = pa_xmalloc(sizeof(struct pa_simple)); p->context = NULL; p->stream = NULL; p->mainloop = pa_mainloop_new(); @@ -146,7 +145,7 @@ fail: void pa_simple_free(struct pa_simple *s) { assert(s); - free(s->read_data); + pa_xfree(s->read_data); if (s->stream) pa_stream_free(s->stream); @@ -157,7 +156,7 @@ void pa_simple_free(struct pa_simple *s) { if (s->mainloop) pa_mainloop_free(s->mainloop); - free(s); + pa_xfree(s); } int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *perror) { @@ -191,11 +190,10 @@ static void read_callback(struct pa_stream *s, const void*data, size_t length, v if (p->read_data) { fprintf(stderr, __FILE__": Buffer overflow, dropping incoming memory blocks.\n"); - free(p->read_data); + pa_xfree(p->read_data); } - p->read_data = malloc(p->read_length = length); - assert(p->read_data); + p->read_data = pa_xmalloc(p->read_length = length); memcpy(p->read_data, data, length); p->read_index = 0; } @@ -219,7 +217,7 @@ int pa_simple_read(struct pa_simple *p, void*data, size_t length, int *perror) { p->read_length -= l; if (!p->read_length) { - free(p->read_data); + pa_xfree(p->read_data); p->read_data = NULL; p->read_index = 0; } diff --git a/polyp/polyplib.c b/polyp/polyplib.c index b1052a8d..4d87fdb5 100644 --- a/polyp/polyplib.c +++ b/polyp/polyplib.c @@ -40,6 +40,7 @@ #include "pstream-util.h" #include "authkey.h" #include "util.h" +#include "xmalloc.h" #define DEFAULT_MAXLENGTH 204800 #define DEFAULT_TLENGTH 10240 @@ -148,9 +149,8 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * struct pa_context *c; assert(mainloop && name); - c = malloc(sizeof(struct pa_context)); - assert(c); - c->name = strdup(name); + c = pa_xmalloc(sizeof(struct pa_context)); + c->name = pa_xstrdup(name); c->mainloop = mainloop; c->client = NULL; c->pstream = NULL; @@ -203,8 +203,8 @@ void pa_context_free(struct pa_context *c) { if (c->playback_streams) pa_dynarray_free(c->playback_streams, NULL, NULL); - free(c->name); - free(c); + pa_xfree(c->name); + pa_xfree(c); } static void stream_dead(struct pa_stream *s) { @@ -391,14 +391,12 @@ static struct sockaddr *resolve_server(const char *server, size_t *len) { return NULL; assert(result); - sa = malloc(*len = result->ai_addrlen); - assert(sa); + sa = pa_xmalloc(*len = result->ai_addrlen); memcpy(sa, result->ai_addr, *len); freeaddrinfo(result); return sa; - } int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { @@ -430,7 +428,7 @@ int pa_context_connect(struct pa_context *c, const char *server, void (*complete } c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); - free(sa); + pa_xfree(sa); if (!c->client) { c->error = PA_ERROR_CONNECTIONREFUSED; @@ -578,8 +576,7 @@ static void create_stream(struct pa_stream *s, const char *dev) { static struct pa_stream *internal_stream_new(struct pa_context *c) { struct pa_stream *s; - s = malloc(sizeof(struct pa_stream)); - assert(s); + s = pa_xmalloc(sizeof(struct pa_stream)); s->context = c; s->read_callback = NULL; @@ -632,7 +629,7 @@ struct pa_stream* pa_stream_new( s->create_complete_callback = complete; s->create_complete_userdata = userdata; - s->name = strdup(name); + s->name = pa_xstrdup(name); s->state = STREAM_CREATING; s->direction = dir; s->sample_spec = *ss; @@ -657,7 +654,7 @@ void pa_stream_free(struct pa_stream *s) { if (s->context->pdispatch) pa_pdispatch_unregister_reply(s->context->pdispatch, s); - free(s->name); + pa_xfree(s->name); if (s->channel_valid && s->context->state == CONTEXT_READY) { struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); @@ -680,7 +677,7 @@ void pa_stream_free(struct pa_stream *s) { else s->context->first_stream = s->next; - free(s); + pa_xfree(s); } void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { @@ -968,7 +965,7 @@ struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *nam s->create_complete_callback = cb; s->create_complete_userdata = userdata; - s->name = strdup(name); + s->name = pa_xstrdup(name); s->state = STREAM_CREATING; s->direction = PA_STREAM_UPLOAD; s->sample_spec = *ss; diff --git a/polyp/protocol-cli.c b/polyp/protocol-cli.c index d6e69b54..11aeabe0 100644 --- a/polyp/protocol-cli.c +++ b/polyp/protocol-cli.c @@ -28,6 +28,7 @@ #include "protocol-cli.h" #include "cli.h" +#include "xmalloc.h" struct pa_protocol_cli { struct pa_module *module; @@ -59,8 +60,7 @@ struct pa_protocol_cli* pa_protocol_cli_new(struct pa_core *core, struct pa_sock struct pa_protocol_cli* p; assert(core && server); - p = malloc(sizeof(struct pa_protocol_cli)); - assert(p); + p = pa_xmalloc(sizeof(struct pa_protocol_cli)); p->module = m; p->core = core; p->server = server; @@ -81,5 +81,5 @@ void pa_protocol_cli_free(struct pa_protocol_cli *p) { pa_idxset_free(p->connections, free_connection, NULL); pa_socket_server_free(p->server); - free(p); + pa_xfree(p); } diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index d80445de..5f6f02fa 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -43,6 +43,8 @@ #include "sample-util.h" #include "authkey.h" #include "debug.h" +#include "namereg.h" +#include "xmalloc.h" #define DEFAULT_COOKIE_FILE ".esd_auth" @@ -78,7 +80,6 @@ struct connection { size_t memblock_index, fragment_size; } playback; - struct pa_memchunk scache_memchunk; char *scache_name; struct pa_sample_spec scache_sample_spec; @@ -90,7 +91,7 @@ struct pa_protocol_esound { struct pa_core *core; struct pa_socket_server *server; struct pa_idxset *connections; - uint32_t sink_index, source_index; + char *sink_name, *source_name; unsigned n_player; uint8_t esd_key[ESD_KEY_LEN]; }; @@ -177,8 +178,8 @@ static void connection_free(struct connection *c) { if (c->playback.current_memblock) pa_memblock_unref(c->playback.current_memblock); - free(c->read_data); - free(c->write_data); + pa_xfree(c->read_data); + pa_xfree(c->write_data); pa_iochannel_free(c->io); @@ -187,31 +188,9 @@ static void connection_free(struct connection *c) { if (c->scache_memchunk.memblock) pa_memblock_unref(c->scache_memchunk.memblock); - free(c->scache_name); + pa_xfree(c->scache_name); - free(c); -} - -static struct pa_sink* get_output_sink(struct pa_protocol_esound *p) { - struct pa_sink *s; - assert(p); - - if (!(s = pa_idxset_get_by_index(p->core->sinks, p->sink_index))) - s = pa_sink_get_default(p->core); - - p->sink_index = s ? s->index : PA_IDXSET_INVALID; - return s; -} - -static struct pa_source* get_input_source(struct pa_protocol_esound *p) { - struct pa_source *s; - assert(p); - - if (!(s = pa_idxset_get_by_index(p->core->sources, p->sink_index))) - s = pa_source_get_default(p->core); - - p->source_index = s ? s->index : PA_IDXSET_INVALID; - return s; + pa_xfree(c); } static void* connection_write(struct connection *c, size_t length) { @@ -224,7 +203,7 @@ static void* connection_write(struct connection *c, size_t length) { t = c->write_data_length+length; if (c->write_data_alloc < t) - c->write_data = realloc(c->write_data, c->write_data_alloc = t); + c->write_data = pa_xrealloc(c->write_data, c->write_data_alloc = t); assert(c->write_data); @@ -299,7 +278,7 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons if (!pa_sample_spec_valid(&ss)) return -1; - if (!(sink = get_output_sink(c->protocol))) { + if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { fprintf(stderr, __FILE__": No output sink\n"); return -1; } @@ -356,7 +335,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co if (request == ESD_PROTO_STREAM_MON) { struct pa_sink* sink; - if (!(sink = get_output_sink(c->protocol))) + if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) return -1; if (!(source = sink->monitor_source)) @@ -364,7 +343,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co } else { assert(request == ESD_PROTO_STREAM_REC); - if (!(source = get_input_source(c->protocol))) + if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) return -1; } @@ -402,7 +381,7 @@ static int esd_proto_get_latency(struct connection *c, esd_proto_t request, cons int latency, *lag; assert(c && !data && length == 0); - if (!(sink = get_output_sink(c->protocol))) + if (!(sink = pa_namereg(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) latency = 0; else { float usec = pa_sink_get_latency(sink); @@ -422,7 +401,7 @@ static int esd_proto_server_info(struct connection *c, esd_proto_t request, cons struct pa_sink *sink; assert(c && data && length == sizeof(int)); - if ((sink = get_output_sink(c->protocol))) { + if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { rate = sink->sample_spec.rate; format = format_native2esd(&sink->sample_spec); } @@ -600,8 +579,7 @@ static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, con c->scache_memchunk.length = sc_length; c->scache_sample_spec = ss; assert(!c->scache_name); - c->scache_name = strdup(name); - assert(c->scache_name); + c->scache_name = pa_xstrdup(name); c->state = ESD_CACHING_SAMPLE; @@ -653,7 +631,7 @@ static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t reque if (request == ESD_PROTO_SAMPLE_PLAY) { struct pa_sink *sink; - if ((sink = get_output_sink(c->protocol))) + if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) if (pa_scache_play_item(c->protocol->core, name, sink, PA_VOLUME_NORM) >= 0) *ok = (int) index+1; } else { @@ -714,7 +692,7 @@ static int do_read(struct connection *c) { } else { if (c->read_data_alloc < handler->data_length) - c->read_data = realloc(c->read_data, c->read_data_alloc = handler->data_length); + c->read_data = pa_xrealloc(c->read_data, c->read_data_alloc = handler->data_length); assert(c->read_data); c->state = ESD_NEEDS_REQDATA; @@ -769,7 +747,7 @@ static int do_read(struct connection *c) { c->scache_memchunk.memblock = NULL; c->scache_memchunk.index = c->scache_memchunk.length = 0; - free(c->scache_name); + pa_xfree(c->scache_name); c->scache_name = NULL; c->state = ESD_NEXT_REQUEST; @@ -964,8 +942,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo char cname[256]; assert(s && io && userdata); - c = malloc(sizeof(struct connection)); - assert(c); + c = pa_xmalloc(sizeof(struct connection)); c->protocol = userdata; c->io = io; pa_iochannel_set_callback(c->io, io_callback, c); @@ -982,8 +959,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->swap_byte_order = 0; c->read_data_length = 0; - c->read_data = malloc(c->read_data_alloc = proto_map[ESD_PROTO_CONNECT].data_length); - assert(c->read_data); + c->read_data = pa_xmalloc(c->read_data_alloc = proto_map[ESD_PROTO_CONNECT].data_length); c->write_data_length = c->write_data_index = c->write_data_alloc = 0; c->write_data = NULL; @@ -1006,7 +982,6 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->scache_name = NULL; c->fixed_source = c->protocol->core->mainloop->source_fixed(c->protocol->core->mainloop, fixed_callback, c); - assert(c->fixed_source); c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 0); pa_idxset_put(c->protocol->connections, c, &c->index); @@ -1015,24 +990,13 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo /*** entry points ***/ struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { - uint32_t source_index, sink_index; struct pa_protocol_esound *p; assert(core && server && ma); - if (pa_modargs_get_source_index(ma, core, &source_index) < 0) { - fprintf(stderr, __FILE__": source does not exist.\n"); - return NULL; - } - - if (pa_modargs_get_sink_index(ma, core, &sink_index) < 0) { - fprintf(stderr, __FILE__": sink does not exist.\n"); - return NULL; - } - p = malloc(sizeof(struct pa_protocol_esound)); - assert(p); + p = pa_xmalloc(sizeof(struct pa_protocol_esound)); if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", DEFAULT_COOKIE_FILE), p->esd_key, sizeof(p->esd_key)) < 0) { - free(p); + pa_xfree(p); return NULL; } @@ -1043,8 +1007,9 @@ struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa p->core = core; p->connections = pa_idxset_new(NULL, NULL); assert(p->connections); - p->sink_index = sink_index; - p->source_index = source_index; + + p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); + p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL)); p->n_player = 0; return p; @@ -1059,5 +1024,5 @@ void pa_protocol_esound_free(struct pa_protocol_esound *p) { pa_idxset_free(p->connections, NULL, NULL); pa_socket_server_free(p->server); - free(p); + pa_xfree(p); } diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index a2332a12..c0aef180 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -41,6 +41,7 @@ #include "authkey.h" #include "namereg.h" #include "scache.h" +#include "xmalloc.h" struct connection; struct pa_protocol_native; @@ -157,13 +158,11 @@ static struct upload_stream* upload_stream_new(struct connection *c, const struc struct upload_stream *s; assert(c && ss && name && length); - s = malloc(sizeof(struct upload_stream)); - assert (s); + s = pa_xmalloc(sizeof(struct upload_stream)); s->type = UPLOAD_STREAM; s->connection = c; s->sample_spec = *ss; - s->name = strdup(name); - assert(s->name); + s->name = pa_xstrdup(name); s->memchunk.memblock = NULL; s->memchunk.index = 0; @@ -180,12 +179,12 @@ static void upload_stream_free(struct upload_stream *o) { pa_idxset_remove_by_data(o->connection->output_streams, o, NULL); - free(o->name); + pa_xfree(o->name); if (o->memchunk.memblock) pa_memblock_unref(o->memchunk.memblock); - free(o); + pa_xfree(o); } static struct record_stream* record_stream_new(struct connection *c, struct pa_source *source, const struct pa_sample_spec *ss, const char *name, size_t maxlength, size_t fragment_size) { @@ -197,8 +196,7 @@ static struct record_stream* record_stream_new(struct connection *c, struct pa_s if (!(source_output = pa_source_output_new(source, name, ss))) return NULL; - s = malloc(sizeof(struct record_stream)); - assert(s); + s = pa_xmalloc(sizeof(struct record_stream)); s->connection = c; s->source_output = source_output; s->source_output->push = source_output_push_cb; @@ -224,7 +222,7 @@ static void record_stream_free(struct record_stream* r) { pa_idxset_remove_by_data(r->connection->record_streams, r, NULL); pa_source_output_free(r->source_output); pa_memblockq_free(r->memblockq); - free(r); + pa_xfree(r); } static struct playback_stream* playback_stream_new(struct connection *c, struct pa_sink *sink, const struct pa_sample_spec *ss, const char *name, @@ -239,8 +237,7 @@ static struct playback_stream* playback_stream_new(struct connection *c, struct if (!(sink_input = pa_sink_input_new(sink, name, ss))) return NULL; - s = malloc(sizeof(struct playback_stream)); - assert (s); + s = pa_xmalloc(sizeof(struct playback_stream)); s->type = PLAYBACK_STREAM; s->connection = c; s->sink_input = sink_input; @@ -272,7 +269,7 @@ static void playback_stream_free(struct playback_stream* p) { pa_idxset_remove_by_data(p->connection->output_streams, p, NULL); pa_sink_input_free(p->sink_input); pa_memblockq_free(p->memblockq); - free(p); + pa_xfree(p); } static void connection_free(struct connection *c) { @@ -295,7 +292,7 @@ static void connection_free(struct connection *c) { pa_pdispatch_free(c->pdispatch); pa_pstream_free(c->pstream); pa_client_free(c->client); - free(c); + pa_xfree(c); } static void request_bytes(struct playback_stream *s) { @@ -476,12 +473,10 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com return; } - if (!*sink_name || sink_index == (uint32_t) -1) - sink = pa_sink_get_default(c->protocol->core); - else if (sink_index != (uint32_t) -1) + if (sink_index != (uint32_t) -1) sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); else - sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK); + sink = pa_namereg_get(c->protocol->core, *sink_name ? sink_name : NULL, PA_NAMEREG_SINK, 1); if (!sink) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); @@ -577,12 +572,10 @@ static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t comma return; } - if (!*source_name || source_index == (uint32_t) -1) - source = pa_source_get_default(c->protocol->core); - else if (source_index != (uint32_t) -1) + if (source_index != (uint32_t) -1) source = pa_idxset_get_by_index(c->protocol->core->sources, source_index); else - source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE); + source = pa_namereg_get(c->protocol->core, *source_name ? source_name : NULL, PA_NAMEREG_SOURCE, 1); if (!source) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); @@ -681,12 +674,12 @@ static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t t if (command == PA_COMMAND_LOOKUP_SINK) { struct pa_sink *sink; - if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK))) + if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1))) index = sink->index; } else { struct pa_source *source; assert(command == PA_COMMAND_LOOKUP_SOURCE); - if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE))) + if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1))) index = source->index; } @@ -888,12 +881,10 @@ static void command_play_sample(struct pa_pdispatch *pd, uint32_t command, uint3 return; } - if (!*sink_name && sink_index == (uint32_t) -1) - sink = pa_sink_get_default(c->protocol->core); - else if (sink_index != (uint32_t) -1) + if (sink_index != (uint32_t) -1) sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); else - sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK); + sink = pa_namereg_get(c->protocol->core, *sink_name ? sink_name : NULL, PA_NAMEREG_SINK, 1); if (!sink) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); @@ -1027,8 +1018,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo struct connection *c; assert(s && io && p); - c = malloc(sizeof(struct connection)); - assert(c); + c = pa_xmalloc(sizeof(struct connection)); c->authorized = p->public; c->protocol = p; assert(p->core); @@ -1070,11 +1060,10 @@ struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct p return NULL; } - p = malloc(sizeof(struct pa_protocol_native)); - assert(p); + p = pa_xmalloc(sizeof(struct pa_protocol_native)); if (pa_authkey_load_from_home(pa_modargs_get_value(ma, "cookie", PA_NATIVE_COOKIE_FILE), p->auth_cookie, sizeof(p->auth_cookie)) < 0) { - free(p); + pa_xfree(p); return NULL; } @@ -1098,5 +1087,5 @@ void pa_protocol_native_free(struct pa_protocol_native *p) { connection_free(c); pa_idxset_free(p->connections, NULL, NULL); pa_socket_server_free(p->server); - free(p); + pa_xfree(p); } diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index 037d4f9a..4b3b1513 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -36,6 +36,7 @@ #include "client.h" #include "sample-util.h" #include "namereg.h" +#include "xmalloc.h" struct connection { struct pa_protocol_simple *protocol; @@ -63,7 +64,7 @@ struct pa_protocol_simple { DUPLEX = 3 } mode; struct pa_sample_spec sample_spec; - uint32_t sink_index, source_index; + char *source_name, *sink_name; }; #define PLAYBACK_BUFFER_SECONDS (.5) @@ -92,7 +93,7 @@ static void connection_free(struct connection *c) { pa_memblockq_free(c->output_memblockq); if (c->fixed_source) c->protocol->core->mainloop->cancel_fixed(c->protocol->core->mainloop, c->fixed_source); - free(c); + pa_xfree(c); } static int do_read(struct connection *c) { @@ -275,8 +276,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo char cname[256]; assert(s && io && p); - c = malloc(sizeof(struct connection)); - assert(c); + c = pa_xmalloc(sizeof(struct connection)); c->io = io; c->sink_input = NULL; c->source_output = NULL; @@ -298,17 +298,16 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo struct pa_sink *sink; size_t l; - if (!(sink = pa_idxset_get_by_index(p->core->sinks, p->sink_index))) - if (!(sink = pa_sink_get_default(p->core))) { - fprintf(stderr, "Failed to get sink.\n"); - goto fail; - } + if (!(sink = pa_namereg_get(p->core, p->sink_name, PA_NAMEREG_SINK, 1))) { + fprintf(stderr, "Failed to get sink.\n"); + goto fail; + } - c->sink_input = pa_sink_input_new(sink, c->client->name, &p->sample_spec); - if (!c->sink_input) { + if (!(c->sink_input = pa_sink_input_new(sink, c->client->name, &p->sample_spec))) { fprintf(stderr, "Failed to create sink input.\n"); goto fail; } + c->sink_input->owner = p->module; c->sink_input->client = c->client; @@ -329,11 +328,10 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo struct pa_source *source; size_t l; - if (!(source = pa_idxset_get_by_index(p->core->sources, p->source_index))) - if (!(source = pa_source_get_default(p->core))) { - fprintf(stderr, "Failed to get source.\n"); - goto fail; - } + if (!(source = pa_namereg_get(p->core, p->source_name, PA_NAMEREG_SOURCE, 1))) { + fprintf(stderr, "Failed to get source.\n"); + goto fail; + } c->source_output = pa_source_output_new(source, c->client->name, &p->sample_spec); if (!c->source_output) { @@ -371,10 +369,7 @@ struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct p uint32_t enable; assert(core && server && ma); - p = malloc(sizeof(struct pa_protocol_simple)); - assert(p); - memset(p, 0, sizeof(struct pa_protocol_simple)); - + p = pa_xmalloc0(sizeof(struct pa_protocol_simple)); p->module = m; p->core = core; p->server = server; @@ -386,15 +381,8 @@ struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct p goto fail; } - if (pa_modargs_get_source_index(ma, core, &p->source_index) < 0) { - fprintf(stderr, __FILE__": source does not exist.\n"); - goto fail; - } - - if (pa_modargs_get_sink_index(ma, core, &p->sink_index) < 0) { - fprintf(stderr, __FILE__": sink does not exist.\n"); - goto fail; - } + p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL)); + p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); enable = 0; if (pa_modargs_get_value_u32(ma, "record", &enable) < 0) { @@ -439,6 +427,6 @@ void pa_protocol_simple_free(struct pa_protocol_simple *p) { if (p->server) pa_socket_server_free(p->server); - free(p); + pa_xfree(p); } diff --git a/polyp/pstream.c b/polyp/pstream.c index 7d576a16..e7441b24 100644 --- a/polyp/pstream.c +++ b/polyp/pstream.c @@ -30,6 +30,7 @@ #include "pstream.h" #include "queue.h" +#include "xmalloc.h" enum pa_pstream_descriptor_index { PA_PSTREAM_DESCRIPTOR_LENGTH, @@ -148,8 +149,7 @@ struct pa_pstream *pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel struct pa_pstream *p; assert(io); - p = malloc(sizeof(struct pa_pstream)); - assert(p); + p = pa_xmalloc(sizeof(struct pa_pstream)); p->io = io; pa_iochannel_set_callback(io, io_callback, p); @@ -199,7 +199,7 @@ static void item_free(void *item, void *p) { pa_packet_unref(i->packet); } - free(i); + pa_xfree(i); } void pa_pstream_free(struct pa_pstream *p) { @@ -224,15 +224,14 @@ void pa_pstream_free(struct pa_pstream *p) { pa_packet_unref(p->read.packet); p->mainloop->cancel_fixed(p->mainloop, p->mainloop_source); - free(p); + pa_xfree(p); } void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet) { struct item_info *i; assert(p && packet); - i = malloc(sizeof(struct item_info)); - assert(i); + i = pa_xmalloc(sizeof(struct item_info)); i->type = PA_PSTREAM_ITEM_PACKET; i->packet = pa_packet_ref(packet); @@ -244,8 +243,7 @@ void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, int32_t del struct item_info *i; assert(p && channel != (uint32_t) -1 && chunk); - i = malloc(sizeof(struct item_info)); - assert(i); + i = pa_xmalloc(sizeof(struct item_info)); i->type = PA_PSTREAM_ITEM_MEMBLOCK; i->chunk = *chunk; i->channel = channel; diff --git a/polyp/queue.c b/polyp/queue.c index 9befd475..9488f433 100644 --- a/polyp/queue.c +++ b/polyp/queue.c @@ -27,6 +27,7 @@ #include #include "queue.h" +#include "xmalloc.h" struct queue_entry { struct queue_entry *next; @@ -39,8 +40,7 @@ struct pa_queue { }; struct pa_queue* pa_queue_new(void) { - struct pa_queue *q = malloc(sizeof(struct pa_queue)); - assert(q); + struct pa_queue *q = pa_xmalloc(sizeof(struct pa_queue)); q->front = q->back = NULL; q->length = 0; return q; @@ -57,18 +57,17 @@ void pa_queue_free(struct pa_queue* q, void (*destroy)(void *p, void *userdata), if (destroy) destroy(e->data, userdata); - free(e); + pa_xfree(e); e = n; } - free(q); + pa_xfree(q); } void pa_queue_push(struct pa_queue *q, void *p) { struct queue_entry *e; - e = malloc(sizeof(struct queue_entry)); - + e = pa_xmalloc(sizeof(struct queue_entry)); e->data = p; e->next = NULL; @@ -96,7 +95,7 @@ void* pa_queue_pop(struct pa_queue *q) { q->back = NULL; p = e->data; - free(e); + pa_xfree(e); q->length--; diff --git a/polyp/resampler.c b/polyp/resampler.c index adf08e80..241f97c4 100644 --- a/polyp/resampler.c +++ b/polyp/resampler.c @@ -30,6 +30,7 @@ #include "resampler.h" #include "sconv.h" +#include "xmalloc.h" struct pa_resampler { struct pa_sample_spec i_ss, o_ss; @@ -55,8 +56,7 @@ struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const stru if (a->format == PA_SAMPLE_ALAW || a->format == PA_SAMPLE_ULAW || b->format == PA_SAMPLE_ALAW || b->format == PA_SAMPLE_ULAW) goto fail; - r = malloc(sizeof(struct pa_resampler)); - assert(r); + r = pa_xmalloc(sizeof(struct pa_resampler)); r->channels = a->channels; if (b->channels < r->channels) @@ -87,7 +87,7 @@ struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const stru fail: if (r) - free(r); + pa_xfree(r); return NULL; } @@ -96,9 +96,9 @@ void pa_resampler_free(struct pa_resampler *r) { assert(r); if (r->src_state) src_delete(r->src_state); - free(r->i_buf); - free(r->o_buf); - free(r); + pa_xfree(r->i_buf); + pa_xfree(r->o_buf); + pa_xfree(r); } size_t pa_resampler_request(struct pa_resampler *r, size_t out_length) { @@ -139,7 +139,7 @@ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, stru assert(out->memblock); if (r->i_alloc < eff_ins) - r->i_buf = realloc(r->i_buf, sizeof(float) * (r->i_alloc = eff_ins)); + r->i_buf = pa_xrealloc(r->i_buf, sizeof(float) * (r->i_alloc = eff_ins)); assert(r->i_buf); r->to_float32_func(eff_ins, in->memblock->data+in->index, i_nchannels, r->i_buf); @@ -149,7 +149,7 @@ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, stru SRC_DATA data; if (r->o_alloc < eff_ons) - r->o_buf = realloc(r->o_buf, sizeof(float) * (r->o_alloc = eff_ons)); + r->o_buf = pa_xrealloc(r->o_buf, sizeof(float) * (r->o_alloc = eff_ons)); assert(r->o_buf); data.data_in = r->i_buf; diff --git a/polyp/scache.c b/polyp/scache.c index 21af0e22..fd7b74e5 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -8,13 +8,14 @@ #include "mainloop.h" #include "sample-util.h" #include "play-memchunk.h" +#include "xmalloc.h" static void free_entry(struct pa_scache_entry *e) { assert(e); - free(e->name); + pa_xfree(e->name); if (e->memchunk.memblock) pa_memblock_unref(e->memchunk.memblock); - free(e); + pa_xfree(e); } void pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index) { @@ -28,10 +29,8 @@ void pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_sp pa_memblock_unref(e->memchunk.memblock); } else { put = 1; - e = malloc(sizeof(struct pa_scache_entry)); - assert(e); - e->name = strdup(name); - assert(e->name); + e = pa_xmalloc(sizeof(struct pa_scache_entry)); + e->name = pa_xstrdup(name); } e->volume = 0x100; diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 25d8022f..04a2f020 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -30,6 +30,7 @@ #include "sink-input.h" #include "sample-util.h" +#include "xmalloc.h" #define CONVERT_BUFFER_LENGTH 4096 @@ -44,9 +45,8 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con if (!(resampler = pa_resampler_new(spec, &s->sample_spec))) return NULL; - i = malloc(sizeof(struct pa_sink_input)); - assert(i); - i->name = name ? strdup(name) : NULL; + i = pa_xmalloc(sizeof(struct pa_sink_input)); + i->name = pa_xstrdup(name); i->client = NULL; i->owner = NULL; i->sink = s; @@ -88,8 +88,8 @@ void pa_sink_input_free(struct pa_sink_input* i) { if (i->resampler) pa_resampler_free(i->resampler); - free(i->name); - free(i); + pa_xfree(i->name); + pa_xfree(i); } void pa_sink_input_kill(struct pa_sink_input*i) { diff --git a/polyp/sink.c b/polyp/sink.c index c2c873c6..6df92e76 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -33,6 +33,7 @@ #include "namereg.h" #include "util.h" #include "sample-util.h" +#include "xmalloc.h" #define MAX_MIX_CHANNELS 32 @@ -43,15 +44,14 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co int r; assert(core && name && *name && spec); - s = malloc(sizeof(struct pa_sink)); - assert(s); + s = pa_xmalloc(sizeof(struct pa_sink)); if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) { - free(s); + pa_xfree(s); return NULL; } - s->name = strdup(name); + s->name = pa_xstrdup(name); s->description = NULL; s->owner = NULL; @@ -62,7 +62,7 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co n = pa_sprintf_malloc("%s_monitor", name); s->monitor_source = pa_source_new(core, n, 0, spec); assert(s->monitor_source); - free(n); + pa_xfree(n); s->monitor_source->monitor_of = s; s->volume = PA_VOLUME_NORM; @@ -98,9 +98,9 @@ void pa_sink_free(struct pa_sink *s) { fprintf(stderr, "sink: freed %u \"%s\"\n", s->index, s->name); - free(s->name); - free(s->description); - free(s); + pa_xfree(s->name); + pa_xfree(s->description); + pa_xfree(s); } void pa_sink_notify(struct pa_sink*s) { @@ -270,19 +270,6 @@ uint32_t pa_sink_get_latency(struct pa_sink *s) { return s->get_latency(s); } -struct pa_sink* pa_sink_get_default(struct pa_core *c) { - struct pa_sink *sink; - assert(c); - - if ((sink = pa_idxset_get_by_index(c->sinks, c->default_sink_index))) - return sink; - - if (!(sink = pa_idxset_first(c->sinks, &c->default_sink_index))) - return NULL; - - fprintf(stderr, "core: default sink vanished, setting to %u.\n", sink->index); - return sink; -} void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m) { sink->owner = m; diff --git a/polyp/sink.h b/polyp/sink.h index 2b5d9495..400d5d04 100644 --- a/polyp/sink.h +++ b/polyp/sink.h @@ -60,8 +60,6 @@ uint32_t pa_sink_get_latency(struct pa_sink *s); void pa_sink_notify(struct pa_sink*s); -struct pa_sink* pa_sink_get_default(struct pa_core *c); - void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m); #endif diff --git a/polyp/socket-client.c b/polyp/socket-client.c index a2187e6a..c0c355de 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -36,6 +36,7 @@ #include "socket-client.h" #include "socket-util.h" #include "util.h" +#include "xmalloc.h" struct pa_socket_client { struct pa_mainloop_api *mainloop; @@ -50,8 +51,7 @@ static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) { struct pa_socket_client *c; assert(m); - c = malloc(sizeof(struct pa_socket_client)); - assert(c); + c = pa_xmalloc(sizeof(struct pa_socket_client)); c->mainloop = m; c->fd = -1; c->io_source = c->fixed_source = NULL; @@ -226,7 +226,7 @@ void pa_socket_client_free(struct pa_socket_client *c) { c->mainloop->cancel_fixed(c->mainloop, c->fixed_source); if (c->fd >= 0) close(c->fd); - free(c); + pa_xfree(c); } void pa_socket_client_set_callback(struct pa_socket_client *c, void (*on_connection)(struct pa_socket_client *c, struct pa_iochannel*io, void *userdata), void *userdata) { diff --git a/polyp/socket-server.c b/polyp/socket-server.c index 0f497377..5f332f0c 100644 --- a/polyp/socket-server.c +++ b/polyp/socket-server.c @@ -37,6 +37,7 @@ #include "socket-server.h" #include "socket-util.h" +#include "xmalloc.h" struct pa_socket_server { int fd; @@ -81,8 +82,7 @@ struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd) struct pa_socket_server *s; assert(m && fd >= 0); - s = malloc(sizeof(struct pa_socket_server)); - assert(s); + s = pa_xmalloc(sizeof(struct pa_socket_server)); s->fd = fd; s->filename = NULL; s->on_connection = NULL; @@ -128,9 +128,7 @@ struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, co s = pa_socket_server_new(m, fd); assert(s); - s->filename = strdup(filename); - assert(s->filename); - + s->filename = pa_xstrdup(filename); s->type = SOCKET_SERVER_UNIX; return s; @@ -192,13 +190,11 @@ void pa_socket_server_free(struct pa_socket_server*s) { if (s->filename) { unlink(s->filename); - free(s->filename); + pa_xfree(s->filename); } - s->mainloop->cancel_io(s->mainloop, s->mainloop_source); - - free(s); + pa_xfree(s); } void pa_socket_server_set_callback(struct pa_socket_server*s, void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata), void *userdata) { diff --git a/polyp/socket-util.c b/polyp/socket-util.c index e0a3c28d..904381b7 100644 --- a/polyp/socket-util.c +++ b/polyp/socket-util.c @@ -40,6 +40,7 @@ #include "socket-util.h" #include "util.h" +#include "xmalloc.h" void pa_socket_peer_to_string(int fd, char *c, size_t l) { struct stat st; @@ -179,8 +180,7 @@ int pa_unix_socket_remove_stale(const char *fn) { int pa_unix_socket_make_secure_dir(const char *fn) { int ret = -1; - char *slash, *dir = strdup(fn); - assert(dir); + char *slash, *dir = pa_xstrdup(fn); if (!(slash = strrchr(dir, '/'))) goto finish; @@ -192,14 +192,13 @@ int pa_unix_socket_make_secure_dir(const char *fn) { ret = 0; finish: - free(dir); + pa_xfree(dir); return ret; } int pa_unix_socket_remove_secure_dir(const char *fn) { int ret = -1; - char *slash, *dir = strdup(fn); - assert(dir); + char *slash, *dir = pa_xstrdup(fn); if (!(slash = strrchr(dir, '/'))) goto finish; @@ -211,6 +210,6 @@ int pa_unix_socket_remove_secure_dir(const char *fn) { ret = 0; finish: - free(dir); + pa_xfree(dir); return ret; } diff --git a/polyp/source-output.c b/polyp/source-output.c index 2705fdb3..07901fa8 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -28,6 +28,7 @@ #include #include "source-output.h" +#include "xmalloc.h" struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec) { struct pa_source_output *o; @@ -39,9 +40,8 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n if (!(resampler = pa_resampler_new(&s->sample_spec, spec))) return NULL; - o = malloc(sizeof(struct pa_source_output)); - assert(o); - o->name = name ? strdup(name) : NULL; + o = pa_xmalloc(sizeof(struct pa_source_output)); + o->name = pa_xstrdup(name); o->client = NULL; o->owner = NULL; o->source = s; @@ -71,8 +71,8 @@ void pa_source_output_free(struct pa_source_output* o) { if (o->resampler) pa_resampler_free(o->resampler); - free(o->name); - free(o); + pa_xfree(o->name); + pa_xfree(o); } void pa_source_output_kill(struct pa_source_output*i) { diff --git a/polyp/source.c b/polyp/source.c index 13635414..65c90e9a 100644 --- a/polyp/source.c +++ b/polyp/source.c @@ -31,6 +31,7 @@ #include "source.h" #include "source-output.h" #include "namereg.h" +#include "xmalloc.h" struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec) { struct pa_source *s; @@ -38,15 +39,14 @@ struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail int r; assert(core && spec && name && *name); - s = malloc(sizeof(struct pa_source)); - assert(s); + s = pa_xmalloc(sizeof(struct pa_source)); if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SOURCE, s, fail))) { - free(s); + pa_xfree(s); return NULL; } - s->name = strdup(name); + s->name = pa_xstrdup(name); s->description = NULL; s->owner = NULL; @@ -84,9 +84,9 @@ void pa_source_free(struct pa_source *s) { fprintf(stderr, "source: freed %u \"%s\"\n", s->index, s->name); - free(s->name); - free(s->description); - free(s); + pa_xfree(s->name); + pa_xfree(s->description); + pa_xfree(s); } void pa_source_notify(struct pa_source*s) { @@ -111,20 +111,6 @@ void pa_source_post(struct pa_source*s, struct pa_memchunk *chunk) { pa_idxset_foreach(s->outputs, do_post, chunk); } -struct pa_source* pa_source_get_default(struct pa_core *c) { - struct pa_source *source; - assert(c); - - if ((source = pa_idxset_get_by_index(c->sources, c->default_source_index))) - return source; - - if (!(source = pa_idxset_first(c->sources, &c->default_source_index))) - return NULL; - - fprintf(stderr, "core: default source vanished, setting to %u.\n", source->index); - return source; -} - void pa_source_set_owner(struct pa_source *s, struct pa_module *m) { assert(s); s->owner = m; diff --git a/polyp/source.h b/polyp/source.h index 9c584a6d..32ef14e6 100644 --- a/polyp/source.h +++ b/polyp/source.h @@ -54,8 +54,6 @@ void pa_source_post(struct pa_source*s, struct pa_memchunk *b); void pa_source_notify(struct pa_source *s); -struct pa_source* pa_source_get_default(struct pa_core *c); - void pa_source_set_owner(struct pa_source *s, struct pa_module *m); #endif diff --git a/polyp/strbuf.c b/polyp/strbuf.c index c6a3772d..169604e8 100644 --- a/polyp/strbuf.c +++ b/polyp/strbuf.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "strbuf.h" @@ -44,8 +45,7 @@ struct pa_strbuf { }; struct pa_strbuf *pa_strbuf_new(void) { - struct pa_strbuf *sb = malloc(sizeof(struct pa_strbuf)); - assert(sb); + struct pa_strbuf *sb = pa_xmalloc(sizeof(struct pa_strbuf)); sb->length = 0; sb->head = sb->tail = NULL; return sb; @@ -56,10 +56,10 @@ void pa_strbuf_free(struct pa_strbuf *sb) { while (sb->head) { struct chunk *c = sb->head; sb->head = sb->head->next; - free(c); + pa_xfree(c); } - free(sb); + pa_xfree(sb); } char *pa_strbuf_tostring(struct pa_strbuf *sb) { @@ -67,8 +67,7 @@ char *pa_strbuf_tostring(struct pa_strbuf *sb) { struct chunk *c; assert(sb); - t = malloc(sb->length+1); - assert(t); + t = pa_xmalloc(sb->length+1); e = t; for (c = sb->head; c; c = c->next) { @@ -101,8 +100,7 @@ void pa_strbuf_putsn(struct pa_strbuf *sb, const char *t, size_t l) { if (!l) return; - c = malloc(sizeof(struct chunk)+l); - assert(c); + c = pa_xmalloc(sizeof(struct chunk)+l); c->next = NULL; c->length = l; @@ -131,8 +129,7 @@ int pa_strbuf_printf(struct pa_strbuf *sb, const char *format, ...) { for(;;) { va_list ap; - c = realloc(c, sizeof(struct chunk)+size); - assert(c); + c = pa_xrealloc(c, sizeof(struct chunk)+size); va_start(ap, format); r = vsnprintf(c->text, size, format, ap); diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c index 0d93c1e9..cb93a9c4 100644 --- a/polyp/tagstruct.c +++ b/polyp/tagstruct.c @@ -29,6 +29,7 @@ #include #include "tagstruct.h" +#include "xmalloc.h" enum tags { TAG_STRING = 't', @@ -55,8 +56,7 @@ struct pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) { assert(!data || (data && length)); - t = malloc(sizeof(struct pa_tagstruct)); - assert(t); + t = pa_xmalloc(sizeof(struct pa_tagstruct)); t->data = (uint8_t*) data; t->allocated = t->length = data ? length : 0; t->rindex = 0; @@ -67,8 +67,8 @@ struct pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) { void pa_tagstruct_free(struct pa_tagstruct*t) { assert(t); if (t->dynamic) - free(t->data); - free(t); + pa_xfree(t->data); + pa_xfree(t); } uint8_t* pa_tagstruct_free_data(struct pa_tagstruct*t, size_t *l) { @@ -76,7 +76,7 @@ uint8_t* pa_tagstruct_free_data(struct pa_tagstruct*t, size_t *l) { assert(t && t->dynamic && l); p = t->data; *l = t->length; - free(t); + pa_xfree(t); return p; } @@ -86,8 +86,7 @@ static void extend(struct pa_tagstruct*t, size_t l) { if (l <= t->allocated) return; - t->data = realloc(t->data, t->allocated = l+100); - assert(t->data); + t->data = pa_xrealloc(t->data, t->allocated = l+100); } void pa_tagstruct_puts(struct pa_tagstruct*t, const char *s) { diff --git a/polyp/tokenizer.c b/polyp/tokenizer.c index c7f18d26..43d695bd 100644 --- a/polyp/tokenizer.c +++ b/polyp/tokenizer.c @@ -29,13 +29,14 @@ #include "tokenizer.h" #include "dynarray.h" +#include "xmalloc.h" struct pa_tokenizer { struct pa_dynarray *dynarray; }; static void token_free(void *p, void *userdata) { - free(p); + pa_xfree(p); } static void parse(struct pa_dynarray*a, const char *s, unsigned args) { @@ -50,8 +51,7 @@ static void parse(struct pa_dynarray*a, const char *s, unsigned args) { p = s+strspn(s, delimiter); while (*p && (infty || args >= 2)) { size_t l = strcspn(p, delimiter); - char *n = strndup(p, l); - assert(n); + char *n = pa_xstrndup(p, l); pa_dynarray_append(a, n); p += l; p += strspn(p, delimiter); @@ -59,8 +59,7 @@ static void parse(struct pa_dynarray*a, const char *s, unsigned args) { } if (args && *p) { - char *n = strdup(p); - assert(n); + char *n = pa_xstrdup(p); pa_dynarray_append(a, n); } } @@ -68,8 +67,7 @@ static void parse(struct pa_dynarray*a, const char *s, unsigned args) { struct pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args) { struct pa_tokenizer *t; - t = malloc(sizeof(struct pa_tokenizer)); - assert(t); + t = pa_xmalloc(sizeof(struct pa_tokenizer)); t->dynarray = pa_dynarray_new(); assert(t->dynarray); @@ -80,7 +78,7 @@ struct pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args) { void pa_tokenizer_free(struct pa_tokenizer *t) { assert(t); pa_dynarray_free(t->dynarray, token_free, NULL); - free(t); + pa_xfree(t); } const char *pa_tokenizer_get(struct pa_tokenizer *t, unsigned i) { diff --git a/polyp/util.c b/polyp/util.c index 6e75c240..98d91075 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -35,6 +35,7 @@ #include #include "util.h" +#include "xmalloc.h" void pa_make_nonblock_fd(int fd) { int v; @@ -129,8 +130,7 @@ char *pa_sprintf_malloc(const char *format, ...) { int r; va_list ap; - c = realloc(c, size); - assert(c); + c = pa_xrealloc(c, size); va_start(ap, format); r = vsnprintf(c, size, format, ap); -- cgit From 839f99ffbf5b01e585845a061830a6fa5f0743dc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 Aug 2004 16:42:37 +0000 Subject: forgot some files git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@104 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/autoload.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ polyp/autoload.h | 17 ++++++++++++ polyp/play-memchunk.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++ polyp/play-memchunk.h | 8 ++++++ polyp/sound-file.c | 64 +++++++++++++++++++++++++++++++++++++++++++ polyp/sound-file.h | 9 ++++++ polyp/xmalloc.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++ polyp/xmalloc.h | 14 ++++++++++ 8 files changed, 338 insertions(+) create mode 100644 polyp/autoload.c create mode 100644 polyp/autoload.h create mode 100644 polyp/play-memchunk.c create mode 100644 polyp/play-memchunk.h create mode 100644 polyp/sound-file.c create mode 100644 polyp/sound-file.h create mode 100644 polyp/xmalloc.c create mode 100644 polyp/xmalloc.h diff --git a/polyp/autoload.c b/polyp/autoload.c new file mode 100644 index 00000000..f0d70d2d --- /dev/null +++ b/polyp/autoload.c @@ -0,0 +1,74 @@ +#include +#include +#include + +#include "autoload.h" +#include "module.h" +#include "xmalloc.h" + +static void entry_free(struct pa_autoload_entry *e) { + assert(e); + pa_xfree(e->name); + pa_xfree(e->module); + pa_xfree(e->argument); + pa_xfree(e); +} + +void pa_autoload_add(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*module, const char *argument) { + struct pa_autoload_entry *e = NULL; + assert(c && name && module); + + if (c->autoload_hashmap && (e = pa_hashmap_get(c->autoload_hashmap, name))) { + pa_xfree(e->module); + pa_xfree(e->argument); + } else { + e = pa_xmalloc(sizeof(struct pa_autoload_entry)); + e->name = pa_xstrdup(name); + + if (!c->autoload_hashmap) + c->autoload_hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + assert(c->autoload_hashmap); + + pa_hashmap_put(c->autoload_hashmap, e->name, e); + } + + e->module = pa_xstrdup(module); + e->argument = pa_xstrdup(argument); + e->type = type; +} + +int pa_autoload_remove(struct pa_core *c, const char*name, enum pa_namereg_type type) { + struct pa_autoload_entry *e; + assert(c && name && type); + + if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name))) + return -1; + + pa_hashmap_remove(c->autoload_hashmap, e->name); + entry_free(e); + return 0; +} + +void pa_autoload_request(struct pa_core *c, const char *name, enum pa_namereg_type type) { + struct pa_autoload_entry *e; + struct pa_module *m; + assert(c && name); + + if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || (e->type != type)) + return; + + if ((m = pa_module_load(c, e->module, e->argument))) + m->auto_unload = 1; +} + +static void free_func(void *p, void *userdata) { + struct pa_autoload_entry *e = p; + entry_free(e); +} + +void pa_autoload_free(struct pa_core *c) { + if (!c->autoload_hashmap) + return; + + pa_hashmap_free(c->autoload_hashmap, free_func, NULL); +} diff --git a/polyp/autoload.h b/polyp/autoload.h new file mode 100644 index 00000000..f1862e77 --- /dev/null +++ b/polyp/autoload.h @@ -0,0 +1,17 @@ +#ifndef fooautoloadhfoo +#define fooautoloadhfoo + +#include "namereg.h" + +struct pa_autoload_entry { + char *name; + enum pa_namereg_type type; + char *module, *argument; +}; + +void pa_autoload_add(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*module, const char *argument); +void pa_autoload_free(struct pa_core *c); +int pa_autoload_remove(struct pa_core *c, const char*name, enum pa_namereg_type type); +void pa_autoload_request(struct pa_core *c, const char *name, enum pa_namereg_type type); + +#endif diff --git a/polyp/play-memchunk.c b/polyp/play-memchunk.c new file mode 100644 index 00000000..5c448a75 --- /dev/null +++ b/polyp/play-memchunk.c @@ -0,0 +1,76 @@ +#include +#include + +#include "play-memchunk.h" +#include "sink-input.h" +#include "xmalloc.h" + +static void sink_input_kill(struct pa_sink_input *i) { + struct pa_memchunk *c; + assert(i && i->userdata); + c = i->userdata; + + pa_memblock_unref(c->memblock); + pa_xfree(c); + pa_sink_input_free(i); +} + +static int sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { + struct pa_memchunk *c; + assert(i && chunk && i->userdata); + c = i->userdata; + + if (c->length <= 0) + return -1; + + assert(c->memblock && c->memblock->length); + *chunk = *c; + pa_memblock_ref(c->memblock); + + return 0; +} + +static void si_kill(void *i) { + sink_input_kill(i); +} + +static void sink_input_drop(struct pa_sink_input *i, size_t length) { + struct pa_memchunk *c; + assert(i && length && i->userdata); + c = i->userdata; + + assert(length <= c->length); + + c->length -= length; + c->index += length; + + if (c->length <= 0) + pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i); +} + +int pa_play_memchunk(struct pa_sink *sink, const char *name, const struct pa_sample_spec *ss, const struct pa_memchunk *chunk, uint32_t volume) { + struct pa_sink_input *si; + struct pa_memchunk *nchunk; + + assert(sink && chunk); + + if (volume <= 0) + return 0; + + if (!(si = pa_sink_input_new(sink, name, ss))) + return -1; + + si->volume = volume; + si->peek = sink_input_peek; + si->drop = sink_input_drop; + si->kill = sink_input_kill; + + si->userdata = nchunk = pa_xmalloc(sizeof(struct pa_memchunk)); + *nchunk = *chunk; + + pa_memblock_ref(chunk->memblock); + + pa_sink_notify(sink); + + return 0; +} diff --git a/polyp/play-memchunk.h b/polyp/play-memchunk.h new file mode 100644 index 00000000..76f9dbd0 --- /dev/null +++ b/polyp/play-memchunk.h @@ -0,0 +1,8 @@ +#ifndef fooplaychunkhfoo +#define fooplaychunkhfoo + +#include "sink.h" + +int pa_play_memchunk(struct pa_sink *sink, const char *name, const struct pa_sample_spec *ss, const struct pa_memchunk *chunk, uint32_t volume); + +#endif diff --git a/polyp/sound-file.c b/polyp/sound-file.c new file mode 100644 index 00000000..b0df7185 --- /dev/null +++ b/polyp/sound-file.c @@ -0,0 +1,64 @@ +#include +#include + +#include + +#include "sound-file.h" +#include "sample.h" + +#define MAX_FILE_SIZE (1024*1024) + +int pa_sound_file_load(const char *fname, struct pa_sample_spec *ss, struct pa_memchunk *chunk) { + SNDFILE*sf = NULL; + SF_INFO sfinfo; + int ret = -1; + size_t l; + assert(fname && ss && chunk); + + memset(&sfinfo, 0, sizeof(sfinfo)); + + chunk->memblock = NULL; + chunk->index = chunk->length = 0; + + if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) { + fprintf(stderr, __FILE__": Failed to open file %s\n", fname); + goto finish; + } + + ss->format = PA_SAMPLE_FLOAT32; + ss->rate = sfinfo.samplerate; + ss->channels = sfinfo.channels; + + if (!pa_sample_spec_valid(ss)) { + fprintf(stderr, __FILE__": Unsupported sample format in file %s\n", fname); + goto finish; + } + + if ((l = pa_frame_size(ss)*sfinfo.frames) > MAX_FILE_SIZE) { + fprintf(stderr, __FILE__": File to large\n"); + goto finish; + } + + chunk->memblock = pa_memblock_new(l); + assert(chunk->memblock); + chunk->index = 0; + chunk->length = l; + + if (sf_readf_float(sf, chunk->memblock->data, sfinfo.frames) != sfinfo.frames) { + fprintf(stderr, __FILE__": Premature file end\n"); + goto finish; + } + + ret = 0; + +finish: + + if (sf) + sf_close(sf); + + if (ret != 0 && chunk->memblock) + pa_memblock_unref(chunk->memblock); + + return ret; + +} diff --git a/polyp/sound-file.h b/polyp/sound-file.h new file mode 100644 index 00000000..3a6fa415 --- /dev/null +++ b/polyp/sound-file.h @@ -0,0 +1,9 @@ +#ifndef soundfilehfoo +#define soundfilehfoo + +#include "memchunk.h" +#include "sample.h" + +int pa_sound_file_load(const char *fname, struct pa_sample_spec *ss, struct pa_memchunk *chunk); + +#endif diff --git a/polyp/xmalloc.c b/polyp/xmalloc.c new file mode 100644 index 00000000..8ff3054d --- /dev/null +++ b/polyp/xmalloc.c @@ -0,0 +1,76 @@ +#include +#include +#include + +#include "memory.h" +#include "util.h" + +#define MAX_ALLOC_SIZE (1024*1024*20) + +#undef malloc +#undef free +#undef realloc +#undef strndup +#undef strdup + +static void oom(void) { + static const char e[] = "Not enough memory\n"; + pa_loop_write(2, e, sizeof(e)-1); + raise(SIGQUIT); + exit(1); +} + +void* pa_xmalloc(size_t size) { + void *p; + assert(size > 0); + assert(size < MAX_ALLOC_SIZE); + + if (!(p = malloc(size))) + oom(); + + return p; +} + +void* pa_xmalloc0(size_t size) { + void *p; + assert(size > 0); + assert(size < MAX_ALLOC_SIZE); + + if (!(p = calloc(1, size))) + oom(); + + return p; +} + +void *pa_xrealloc(void *ptr, size_t size) { + void *p; + assert(size > 0); + assert(size < MAX_ALLOC_SIZE); + + if (!(p = realloc(ptr, size))) + oom(); + return p; +} + +char *pa_xstrdup(const char *s) { + if (!s) + return NULL; + else { + char *r = strdup(s); + if (!r) + oom(); + + return r; + } +} + +char *pa_xstrndup(const char *s, size_t l) { + if (!s) + return NULL; + else { + char *r = strndup(s, l); + if (!r) + oom(); + return r; + } +} diff --git a/polyp/xmalloc.h b/polyp/xmalloc.h new file mode 100644 index 00000000..5f58a8ad --- /dev/null +++ b/polyp/xmalloc.h @@ -0,0 +1,14 @@ +#ifndef foomemoryhfoo +#define foomemoryhfoo + +#include + +void* pa_xmalloc(size_t l); +void *pa_xmalloc0(size_t l); +void *pa_xrealloc(void *ptr, size_t size); +#define pa_xfree free + +char *pa_xstrdup(const char *s); +char *pa_xstrndup(const char *s, size_t l); + +#endif -- cgit From 964bdfd1e8255b57e9d22cd22b3784e2fc79b905 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 5 Aug 2004 19:53:57 +0000 Subject: add initial glib mainloop adapter clean up mainloop API git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@105 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 4 + polyp/Makefile.am | 7 +- polyp/alsa-util.c | 34 +-- polyp/alsa-util.h | 4 +- polyp/core.c | 1 + polyp/core.h | 2 +- polyp/glib-mainloop.c | 503 ++++++++++++++++++++++++++++++++++++ polyp/glib-mainloop.h | 14 ++ polyp/iochannel.c | 60 ++--- polyp/main.c | 11 +- polyp/mainloop-api.c | 34 +-- polyp/mainloop-api.h | 48 ++-- polyp/mainloop-signal.c | 99 ++++---- polyp/mainloop-signal.h | 8 +- polyp/mainloop.c | 616 ++++++++++++++++++++++----------------------- polyp/module-alsa-sink.c | 14 +- polyp/module-alsa-source.c | 14 +- polyp/module-oss-mmap.c | 19 +- polyp/module-pipe-sink.c | 16 +- polyp/module-x11-bell.c | 10 +- polyp/module.c | 20 +- polyp/module.h | 1 - polyp/native-common.h | 16 +- polyp/pacat.c | 46 ++-- polyp/pactl.c | 4 +- polyp/pdispatch.c | 12 +- polyp/play-memchunk.c | 2 +- polyp/polypaudio.pa | 30 ++- polyp/polyplib.h | 30 +++ polyp/protocol-esound.c | 35 +-- polyp/protocol-native.c | 122 +++++++++ polyp/protocol-simple.c | 30 +-- polyp/pstream.c | 18 +- polyp/socket-client.c | 39 +-- polyp/socket-server.c | 12 +- polyp/xmalloc.h | 1 + 36 files changed, 1310 insertions(+), 626 deletions(-) create mode 100644 polyp/glib-mainloop.c create mode 100644 polyp/glib-mainloop.h diff --git a/configure.ac b/configure.ac index 9e5352a5..3183d174 100644 --- a/configure.ac +++ b/configure.ac @@ -54,6 +54,10 @@ PKG_CHECK_MODULES(ASOUNDLIB, [ alsa >= 1.0.0 ]) AC_SUBST(ASOUNDLIB_CFLAGS) AC_SUBST(ASOUNDLIB_LIBS) +PKG_CHECK_MODULES(GLIB20, [ glib-2.0 >= 2.4.0 ]) +AC_SUBST(GLIB20_CFLAGS) +AC_SUBST(GLIB20_LIBS) + # If using GCC specifiy some additional parameters if test "x$GCC" = "xyes" ; then CFLAGS="$CFLAGS -pipe -Wall -W -Wno-unused-parameter" diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 0af99110..c0be8ce0 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -71,7 +71,8 @@ pkglib_LTLIBRARIES=libiochannel.la \ lib_LTLIBRARIES=libpolyp.la \ libpolyp-simple.la \ libpolyp-error.la \ - libpolyp-mainloop.la + libpolyp-mainloop.la \ + libpolyp-mainloop-glib.la polypaudio_SOURCES = idxset.c idxset.h \ queue.c queue.h \ @@ -307,6 +308,10 @@ parec_simple_SOURCES = parec-simple.c parec_simple_LDADD = $(AM_LDADD) libpolyp-simple.la libpolyp-error.la parec_simple_CFLAGS = $(AM_CFLAGS) +libpolyp_mainloop_glib_la_SOURCES = glib-mainloop.h glib-mainloop.c +libpolyp_mainloop_glib_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) +libpolyp_mainloop_glib_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop.la $(GLIB20_LIBS) + if BUILD_LIBPOLYPCORE pkginclude_HEADERS+=cli-command.h\ diff --git a/polyp/alsa-util.c b/polyp/alsa-util.c index 43562378..70e2e072 100644 --- a/polyp/alsa-util.c +++ b/polyp/alsa-util.c @@ -59,26 +59,26 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, struct pa_sample_spec *ss, uint return ret; } -int pa_create_io_sources(snd_pcm_t *pcm_handle, struct pa_mainloop_api* m, void ***io_sources, unsigned *n_io_sources, void (*cb)(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata), void *userdata) { +int pa_create_io_events(snd_pcm_t *pcm_handle, struct pa_mainloop_api* m, struct pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags events, void *userdata), void *userdata) { unsigned i; struct pollfd *pfds, *ppfd; - void **ios; - assert(pcm_handle && m && io_sources && n_io_sources && cb); + struct pa_io_event **ios; + assert(pcm_handle && m && io_events && n_io_events && cb); - *n_io_sources = snd_pcm_poll_descriptors_count(pcm_handle); + *n_io_events = snd_pcm_poll_descriptors_count(pcm_handle); - pfds = pa_xmalloc(sizeof(struct pollfd) * *n_io_sources); - if (snd_pcm_poll_descriptors(pcm_handle, pfds, *n_io_sources) < 0) { + pfds = pa_xmalloc(sizeof(struct pollfd) * *n_io_events); + if (snd_pcm_poll_descriptors(pcm_handle, pfds, *n_io_events) < 0) { pa_xfree(pfds); return -1; } - *io_sources = pa_xmalloc(sizeof(void*) * *n_io_sources); + *io_events = pa_xmalloc(sizeof(void*) * *n_io_events); - for (i = 0, ios = *io_sources, ppfd = pfds; i < *n_io_sources; i++, ios++, ppfd++) { - *ios = m->source_io(m, ppfd->fd, - ((ppfd->events & POLLIN) ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | - ((ppfd->events & POLLOUT) ? PA_MAINLOOP_API_IO_EVENT_OUTPUT : 0), cb, userdata); + for (i = 0, ios = *io_events, ppfd = pfds; i < *n_io_events; i++, ios++, ppfd++) { + *ios = m->io_new(m, ppfd->fd, + ((ppfd->events & POLLIN) ? PA_IO_EVENT_INPUT : 0) | + ((ppfd->events & POLLOUT) ? PA_IO_EVENT_OUTPUT : 0), cb, userdata); assert(*ios); } @@ -86,12 +86,12 @@ int pa_create_io_sources(snd_pcm_t *pcm_handle, struct pa_mainloop_api* m, void return 0; } -void pa_free_io_sources(struct pa_mainloop_api* m, void **io_sources, unsigned n_io_sources) { +void pa_free_io_events(struct pa_mainloop_api* m, struct pa_io_event **io_events, unsigned n_io_events) { unsigned i; - void **ios; - assert(m && io_sources); + struct pa_io_event **ios; + assert(m && io_events); - for (ios = io_sources, i = 0; i < n_io_sources; i++, ios++) - m->cancel_io(m, *ios); - pa_xfree(io_sources); + for (ios = io_events, i = 0; i < n_io_events; i++, ios++) + m->io_free(*ios); + pa_xfree(io_events); } diff --git a/polyp/alsa-util.h b/polyp/alsa-util.h index 03e427d9..2627a75c 100644 --- a/polyp/alsa-util.h +++ b/polyp/alsa-util.h @@ -29,7 +29,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, struct pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *buffer_size); -int pa_create_io_sources(snd_pcm_t *pcm_handle, struct pa_mainloop_api *m, void ***io_sources, unsigned *n_io_sources, void (*cb)(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata), void *userdata); -void pa_free_io_sources(struct pa_mainloop_api* m, void **io_sources, unsigned n_io_sources); +int pa_create_io_events(snd_pcm_t *pcm_handle, struct pa_mainloop_api *m, struct pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags events, void *userdata), void *userdata); +void pa_free_io_events(struct pa_mainloop_api* m, struct pa_io_event **io_sources, unsigned n_io_sources); #endif diff --git a/polyp/core.c b/polyp/core.c index ffc11cec..0444fa96 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -62,6 +62,7 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->default_sample_spec.channels = 2; c->auto_unload_time = 20; + c->auto_unload_event = NULL; pa_check_for_sigpipe(); diff --git a/polyp/core.h b/polyp/core.h index b125083d..e1e48cbc 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -38,7 +38,7 @@ struct pa_core { struct pa_sample_spec default_sample_spec; int auto_unload_time; - void *auto_unload_mainloop_source; + struct pa_time_event *auto_unload_event; }; struct pa_core* pa_core_new(struct pa_mainloop_api *m); diff --git a/polyp/glib-mainloop.c b/polyp/glib-mainloop.c new file mode 100644 index 00000000..978cad07 --- /dev/null +++ b/polyp/glib-mainloop.c @@ -0,0 +1,503 @@ +#include + +#include "glib-mainloop.h" +#include "idxset.h" +#include "xmalloc.h" + +struct pa_io_event { + GSource source; + int dead; + struct pa_glib_mainloop *mainloop; + int fd; + GPollFD pollfd; + void (*callback) (struct pa_mainloop_api*m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata); + void *userdata; + void (*destroy_callback) (struct pa_mainloop_api *m, struct pa_io_event*e, void *userdata); + struct pa_io_event *next, *prev; +}; + +struct pa_time_event { + struct pa_glib_mainloop *mainloop; + int dead; + GSource *source; + struct timeval timeval; + void (*callback) (struct pa_mainloop_api*m, struct pa_time_event *e, const struct timeval *tv, void *userdata); + void *userdata; + void (*destroy_callback) (struct pa_mainloop_api *m, struct pa_time_event*e, void *userdata); + struct pa_time_event *next, *prev; +}; + +struct pa_defer_event { + struct pa_glib_mainloop *mainloop; + int dead; + GSource *source; + void (*callback) (struct pa_mainloop_api*m, struct pa_defer_event *e, void *userdata); + void *userdata; + void (*destroy_callback) (struct pa_mainloop_api *m, struct pa_defer_event*e, void *userdata); + struct pa_defer_event *next, *prev; +}; + +struct pa_glib_mainloop { + GMainLoop *glib_mainloop; + struct pa_mainloop_api api; + GSource *cleanup_source; + struct pa_io_event *io_events, *dead_io_events; + struct pa_time_event *time_events, *dead_time_events; + struct pa_defer_event *defer_events, *dead_defer_events; +}; + +static void schedule_free_dead_events(struct pa_glib_mainloop *g); + +static gboolean glib_source_prepare(GSource *source, gint *timeout) { + return FALSE; +} + +static gboolean glib_source_check(GSource *source) { + struct pa_io_event *e = (struct pa_io_event*) source; + assert(e); + return !!e->pollfd.revents; +} + +static gboolean glib_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) { + struct pa_io_event *e = (struct pa_io_event*) source; + assert(e); + + if (e->pollfd.revents) { + int f = + (e->pollfd.revents ? G_IO_IN : PA_IO_EVENT_INPUT) | + (e->pollfd.revents ? G_IO_OUT : PA_IO_EVENT_OUTPUT) | + (e->pollfd.revents ? G_IO_HUP : PA_IO_EVENT_HANGUP) | + (e->pollfd.revents ? G_IO_ERR : PA_IO_EVENT_ERROR); + e->pollfd.revents = 0; + + assert(e->callback); + e->callback(&e->mainloop->api, e, e->fd, f, e->userdata); + } + + return TRUE; +} + +static void glib_io_enable(struct pa_io_event*e, enum pa_io_event_flags f); + +static struct pa_io_event* glib_io_new(struct pa_mainloop_api*m, int fd, enum pa_io_event_flags f, void (*callback) (struct pa_mainloop_api*m, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata), void *userdata) { + struct pa_io_event *e; + struct pa_glib_mainloop *g; + + GSourceFuncs io_source_funcs = { + prepare: glib_source_prepare, + check: glib_source_check, + dispatch: glib_source_dispatch, + finalize: NULL, + closure_callback: NULL, + closure_marshal : NULL, + }; + + assert(m && m->userdata && fd >= 0 && callback); + g = m->userdata; + + e = (struct pa_io_event*) g_source_new(&io_source_funcs, sizeof(struct pa_io_event)); + assert(e); + e->mainloop = m->userdata; + e->dead = 0; + e->fd = fd; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + + e->pollfd.fd = fd; + e->pollfd.events = e->pollfd.revents = 0; + + g_source_attach(&e->source, g_main_loop_get_context(g->glib_mainloop)); + + glib_io_enable(e, f); + + e->next = g->io_events; + if (e->next) e->next->prev = e; + g->io_events = e; + e->prev = NULL; + + return e; +} + +static void glib_io_enable(struct pa_io_event*e, enum pa_io_event_flags f) { + int o; + assert(e && !e->dead); + + o = e->pollfd.events; + e->pollfd.events = (f & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | (f & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0) | G_IO_HUP | G_IO_ERR; + + if (!o && e->pollfd.events) + g_source_add_poll(&e->source, &e->pollfd); + else if (o && !e->pollfd.events) + g_source_remove_poll(&e->source, &e->pollfd); +} + +static void glib_io_free(struct pa_io_event*e) { + assert(e && !e->dead); + + g_source_destroy(&e->source); + + if (e->prev) + e->prev->next = e->next; + else + e->mainloop->io_events = e->next; + + if (e->next) + e->next->prev = e->prev; + + if ((e->next = e->mainloop->dead_io_events)) + e->next->prev = e; + + e->mainloop->dead_io_events = e; + e->prev = NULL; + + e->dead = 1; + schedule_free_dead_events(e->mainloop); +} + +static void glib_io_set_destroy(struct pa_io_event*e, void (*callback)(struct pa_mainloop_api*m, struct pa_io_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* Time sources */ + +static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv); + +static struct pa_time_event* glib_time_new(struct pa_mainloop_api*m, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*m, struct pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { + struct pa_glib_mainloop *g; + struct pa_time_event *e; + + assert(m && m->userdata && tv && callback); + g = m->userdata; + + e = pa_xmalloc(sizeof(struct pa_time_event)); + e->mainloop = g; + e->dead = 0; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + e->source = NULL; + + glib_time_restart(e, tv); + + e->next = g->time_events; + if (e->next) e->next->prev = e; + g->time_events = e; + e->prev = NULL; + + return e; +} + +static guint msec_diff(const struct timeval *a, const struct timeval *b) { + guint r; + assert(a && b); + + if (a->tv_sec < b->tv_sec) + return 0; + + if (a->tv_sec == b->tv_sec && a->tv_sec <= b->tv_sec) + return 0; + + r = (a->tv_sec-b->tv_sec)*1000; + + if (a->tv_usec >= b->tv_usec) + r += (a->tv_usec - b->tv_usec) / 1000; + else + r -= (b->tv_usec - a->tv_usec) / 1000; + + return r; +} + +static gboolean time_cb(gpointer data) { + struct pa_time_event* e = data; + assert(e && e->mainloop && e->source); + + g_source_unref(e->source); + e->source = NULL; + + e->callback(&e->mainloop->api, e, &e->timeval, e->userdata); + return FALSE; +} + +static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv) { + struct timeval now; + assert(e && e->mainloop); + + gettimeofday(&now, NULL); + if (e->source) { + g_source_destroy(e->source); + g_source_unref(e->source); + } + + if (tv) { + e->timeval = *tv; + e->source = g_timeout_source_new(msec_diff(tv, &now)); + assert(e->source); + g_source_set_callback(e->source, time_cb, e, NULL); + g_source_attach(e->source, g_main_loop_get_context(e->mainloop->glib_mainloop)); + } else + e->source = NULL; + } + +static void glib_time_free(struct pa_time_event *e) { + assert(e && e->mainloop); + + if (e->source) { + g_source_destroy(e->source); + g_source_unref(e->source); + e->source = NULL; + } + + if (e->prev) + e->prev->next = e->next; + else + e->mainloop->time_events = e->next; + + if (e->next) + e->next->prev = e->prev; + + if ((e->next = e->mainloop->dead_time_events)) + e->next->prev = e; + + e->mainloop->dead_time_events = e; + e->prev = NULL; + + e->dead = 1; + schedule_free_dead_events(e->mainloop); +} + +static void glib_time_set_destroy(struct pa_time_event *e, void (*callback)(struct pa_mainloop_api*m, struct pa_time_event*e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* Deferred sources */ + +static void glib_defer_enable(struct pa_defer_event *e, int b); + +static struct pa_defer_event* glib_defer_new(struct pa_mainloop_api*m, void (*callback) (struct pa_mainloop_api*m, struct pa_defer_event *e, void *userdata), void *userdata) { + struct pa_defer_event *e; + struct pa_glib_mainloop *g; + + assert(m && m->userdata && callback); + g = m->userdata; + + e = pa_xmalloc(sizeof(struct pa_defer_event)); + e->mainloop = g; + e->dead = 0; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + e->source = NULL; + + glib_defer_enable(e, 1); + + e->next = g->defer_events; + if (e->next) e->next->prev = e; + g->defer_events = e; + e->prev = NULL; + return e; +} + +static gboolean idle_cb(gpointer data) { + struct pa_defer_event* e = data; + assert(e && e->mainloop && e->source); + + e->callback(&e->mainloop->api, e, e->userdata); + return TRUE; +} + +static void glib_defer_enable(struct pa_defer_event *e, int b) { + assert(e && e->mainloop); + + if (e->source && !b) { + g_source_destroy(e->source); + g_source_unref(e->source); + e->source = NULL; + } else if (!e->source && b) { + e->source = g_idle_source_new(); + assert(e->source); + g_source_set_callback(e->source, idle_cb, e, NULL); + g_source_attach(e->source, g_main_loop_get_context(e->mainloop->glib_mainloop)); + g_source_set_priority(e->source, G_PRIORITY_HIGH_IDLE); + } +} + +static void glib_defer_free(struct pa_defer_event *e) { + assert(e && e->mainloop); + + if (e->source) { + g_source_destroy(e->source); + g_source_unref(e->source); + e->source = NULL; + } + + if (e->prev) + e->prev->next = e->next; + else + e->mainloop->defer_events = e->next; + + if (e->next) + e->next->prev = e->prev; + + if ((e->next = e->mainloop->dead_defer_events)) + e->next->prev = e; + + e->mainloop->dead_defer_events = e; + e->prev = NULL; + + e->dead = 1; + schedule_free_dead_events(e->mainloop); +} + +static void glib_defer_set_destroy(struct pa_defer_event *e, void (*callback)(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* quit() */ + +static void glib_quit(struct pa_mainloop_api*a, int retval) { + struct pa_glib_mainloop *g; + assert(a && a->userdata); + g = a->userdata; + + g_main_loop_quit(g->glib_mainloop); +} + +static const struct pa_mainloop_api vtable = { + userdata: NULL, + + io_new: glib_io_new, + io_enable: glib_io_enable, + io_free: glib_io_free, + io_set_destroy: glib_io_set_destroy, + + time_new : glib_time_new, + time_restart : glib_time_restart, + time_free : glib_time_free, + time_set_destroy : glib_time_set_destroy, + + defer_new : glib_defer_new, + defer_enable : glib_defer_enable, + defer_free : glib_defer_free, + defer_set_destroy : glib_defer_set_destroy, + + quit : glib_quit, +}; + +struct pa_glib_mainloop *pa_glib_mainloop_new(GMainLoop *ml) { + struct pa_glib_mainloop *g; + assert(ml); + + g = pa_xmalloc(sizeof(struct pa_glib_mainloop)); + g->glib_mainloop = g_main_loop_ref(ml); + g->api = vtable; + g->api.userdata = g; + + g->io_events = g->dead_io_events = NULL; + g->time_events = g->dead_time_events = NULL; + g->defer_events = g->dead_defer_events = NULL; + + g->cleanup_source = NULL; + return g; +} + +static void free_io_events(struct pa_io_event *e) { + while (e) { + struct pa_io_event *r = e; + e = r->next; + + if (r->pollfd.events) + g_source_remove_poll(&r->source, &r->pollfd); + + if (!r->dead) + g_source_destroy(&r->source); + + if (r->destroy_callback) + r->destroy_callback(&r->mainloop->api, r, r->userdata); + + g_source_unref(&r->source); + } +} + +static void free_time_events(struct pa_time_event *e) { + while (e) { + struct pa_time_event *r = e; + e = r->next; + + if (r->source) { + g_source_destroy(r->source); + g_source_unref(r->source); + } + + if (r->destroy_callback) + r->destroy_callback(&r->mainloop->api, r, r->userdata); + + pa_xfree(r); + } +} + +static void free_defer_events(struct pa_defer_event *e) { + while (e) { + struct pa_defer_event *r = e; + e = r->next; + + if (r->source) { + g_source_destroy(r->source); + g_source_unref(r->source); + } + + if (r->destroy_callback) + r->destroy_callback(&r->mainloop->api, r, r->userdata); + + pa_xfree(r); + } +} + +void pa_glib_mainloop_free(struct pa_glib_mainloop* g) { + assert(g); + + free_io_events(g->io_events); + free_io_events(g->dead_io_events); + free_defer_events(g->defer_events); + free_defer_events(g->dead_defer_events); + free_time_events(g->time_events); + free_time_events(g->dead_time_events); + + g_main_loop_unref(g->glib_mainloop); + pa_xfree(g); +} + +struct pa_mainloop_api* pa_glib_mainloop_get_api(struct pa_glib_mainloop *g) { + assert(g); + return &g->api; +} + +static gboolean free_dead_events(gpointer p) { + struct pa_glib_mainloop *g = p; + assert(g); + + free_io_events(g->dead_io_events); + free_defer_events(g->dead_defer_events); + free_time_events(g->dead_time_events); + + g_source_destroy(g->cleanup_source); + g_source_unref(g->cleanup_source); + g->cleanup_source = NULL; + + return FALSE; +} + +static void schedule_free_dead_events(struct pa_glib_mainloop *g) { + assert(g && g->glib_mainloop); + + if (g->cleanup_source) + return; + + g->cleanup_source = g_idle_source_new(); + assert(g->cleanup_source); + g_source_set_callback(g->cleanup_source, free_dead_events, g, NULL); + g_source_attach(g->cleanup_source, g_main_loop_get_context(g->glib_mainloop)); +} diff --git a/polyp/glib-mainloop.h b/polyp/glib-mainloop.h new file mode 100644 index 00000000..50fe8b9c --- /dev/null +++ b/polyp/glib-mainloop.h @@ -0,0 +1,14 @@ +#ifndef fooglibmainloophfoo +#define fooglibmainloophfoo + +#include + +#include "mainloop-api.h" + +struct pa_glib_mainloop; + +struct pa_glib_mainloop *pa_glib_mainloop_new(GMainLoop *ml); +void pa_glib_mainloop_free(struct pa_glib_mainloop* g); +struct pa_mainloop_api* pa_glib_mainloop_get_api(struct pa_glib_mainloop *g); + +#endif diff --git a/polyp/iochannel.c b/polyp/iochannel.c index 77f8fb08..813347d4 100644 --- a/polyp/iochannel.c +++ b/polyp/iochannel.c @@ -46,50 +46,50 @@ struct pa_iochannel { int no_close; - void* input_source, *output_source; + struct pa_io_event* input_event, *output_event; }; static void enable_mainloop_sources(struct pa_iochannel *io) { assert(io); - if (io->input_source == io->output_source) { - enum pa_mainloop_api_io_events e = PA_MAINLOOP_API_IO_EVENT_NULL; - assert(io->input_source); + if (io->input_event == io->output_event) { + enum pa_io_event_flags f = PA_IO_EVENT_NULL; + assert(io->input_event); if (!io->readable) - e |= PA_MAINLOOP_API_IO_EVENT_INPUT; + f |= PA_IO_EVENT_INPUT; if (!io->writable) - e |= PA_MAINLOOP_API_IO_EVENT_OUTPUT; + f |= PA_IO_EVENT_OUTPUT; - io->mainloop->enable_io(io->mainloop, io->input_source, e); + io->mainloop->io_enable(io->input_event, f); } else { - if (io->input_source) - io->mainloop->enable_io(io->mainloop, io->input_source, io->readable ? PA_MAINLOOP_API_IO_EVENT_NULL : PA_MAINLOOP_API_IO_EVENT_INPUT); - if (io->output_source) - io->mainloop->enable_io(io->mainloop, io->output_source, io->writable ? PA_MAINLOOP_API_IO_EVENT_NULL : PA_MAINLOOP_API_IO_EVENT_OUTPUT); + if (io->input_event) + io->mainloop->io_enable(io->input_event, io->readable ? PA_IO_EVENT_NULL : PA_IO_EVENT_INPUT); + if (io->output_event) + io->mainloop->io_enable(io->output_event, io->writable ? PA_IO_EVENT_NULL : PA_IO_EVENT_OUTPUT); } } -static void callback(struct pa_mainloop_api* m, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { +static void callback(struct pa_mainloop_api* m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { struct pa_iochannel *io = userdata; int changed = 0; - assert(m && fd >= 0 && events && userdata); + assert(m && e && fd >= 0 && userdata); - if ((events & PA_MAINLOOP_API_IO_EVENT_HUP) && !io->hungup) { + if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) { io->hungup = 1; changed = 1; } - if ((events & PA_MAINLOOP_API_IO_EVENT_INPUT) && !io->readable) { + if ((f & PA_IO_EVENT_INPUT) && !io->readable) { io->readable = 1; changed = 1; - assert(id == io->input_source); + assert(e == io->input_event); } - if ((events & PA_MAINLOOP_API_IO_EVENT_OUTPUT) && !io->writable) { + if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) { io->writable = 1; changed = 1; - assert(id == io->output_source); + assert(e == io->output_event); } if (changed) { @@ -116,23 +116,23 @@ struct pa_iochannel* pa_iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd io->hungup = 0; io->no_close = 0; + io->input_event = io->output_event = NULL; + if (ifd == ofd) { assert(ifd >= 0); pa_make_nonblock_fd(io->ifd); - io->input_source = io->output_source = m->source_io(m, ifd, PA_MAINLOOP_API_IO_EVENT_BOTH, callback, io); + io->input_event = io->output_event = m->io_new(m, ifd, PA_IO_EVENT_INPUT|PA_IO_EVENT_OUTPUT, callback, io); } else { if (ifd >= 0) { pa_make_nonblock_fd(io->ifd); - io->input_source = m->source_io(m, ifd, PA_MAINLOOP_API_IO_EVENT_INPUT, callback, io); - } else - io->input_source = NULL; + io->input_event = m->io_new(m, ifd, PA_IO_EVENT_INPUT, callback, io); + } if (ofd >= 0) { pa_make_nonblock_fd(io->ofd); - io->output_source = m->source_io(m, ofd, PA_MAINLOOP_API_IO_EVENT_OUTPUT, callback, io); - } else - io->output_source = NULL; + io->output_event = m->io_new(m, ofd, PA_IO_EVENT_OUTPUT, callback, io); + } } return io; @@ -141,17 +141,17 @@ struct pa_iochannel* pa_iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd void pa_iochannel_free(struct pa_iochannel*io) { assert(io); + if (io->input_event) + io->mainloop->io_free(io->input_event); + if (io->output_event && (io->output_event != io->input_event)) + io->mainloop->io_free(io->output_event); + if (!io->no_close) { if (io->ifd >= 0) close(io->ifd); if (io->ofd >= 0 && io->ofd != io->ifd) close(io->ofd); } - - if (io->input_source) - io->mainloop->cancel_io(io->mainloop, io->input_source); - if (io->output_source && (io->output_source != io->input_source)) - io->mainloop->cancel_io(io->mainloop, io->output_source); pa_xfree(io); } diff --git a/polyp/main.c b/polyp/main.c index de66f1c8..9f3d3406 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -46,13 +46,12 @@ static struct pa_mainloop *mainloop; -static void exit_signal_callback(void *id, int sig, void *userdata) { - struct pa_mainloop_api* m = pa_mainloop_get_api(mainloop); +static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { m->quit(m, 1); fprintf(stderr, __FILE__": got signal.\n"); } -static void aux_signal_callback(void *id, int sig, void *userdata) { +static void aux_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { struct pa_core *c = userdata; assert(c); pa_module_load(c, sig == SIGUSR1 ? "module-cli" : "module-cli-protocol-unix", NULL); @@ -135,14 +134,14 @@ int main(int argc, char *argv[]) { r = pa_signal_init(pa_mainloop_get_api(mainloop)); assert(r == 0); - pa_signal_register(SIGINT, exit_signal_callback, NULL); + pa_signal_new(SIGINT, exit_signal_callback, NULL); signal(SIGPIPE, SIG_IGN); c = pa_core_new(pa_mainloop_get_api(mainloop)); assert(c); - pa_signal_register(SIGUSR1, aux_signal_callback, c); - pa_signal_register(SIGUSR2, aux_signal_callback, c); + pa_signal_new(SIGUSR1, aux_signal_callback, c); + pa_signal_new(SIGUSR2, aux_signal_callback, c); buf = pa_strbuf_new(); assert(buf); diff --git a/polyp/mainloop-api.c b/polyp/mainloop-api.c index 8b4e09ac..952fce0a 100644 --- a/polyp/mainloop-api.c +++ b/polyp/mainloop-api.c @@ -30,32 +30,38 @@ #include "xmalloc.h" struct once_info { - void (*callback)(void *userdata); + void (*callback)(struct pa_mainloop_api*m, void *userdata); void *userdata; }; -static void once_callback(struct pa_mainloop_api *api, void *id, void *userdata) { +static void once_callback(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) { struct once_info *i = userdata; - assert(api && i && i->callback); - i->callback(i->userdata); - assert(api->cancel_fixed); - api->cancel_fixed(api, id); + assert(m && i && i->callback); + + i->callback(m, i->userdata); + + assert(m->defer_free); + m->defer_free(e); +} + +static void free_callback(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) { + struct once_info *i = userdata; + assert(m && i); pa_xfree(i); } -void pa_mainloop_api_once(struct pa_mainloop_api* api, void (*callback)(void *userdata), void *userdata) { +void pa_mainloop_api_once(struct pa_mainloop_api* m, void (*callback)(struct pa_mainloop_api *m, void *userdata), void *userdata) { struct once_info *i; - void *id; - assert(api && callback); + struct pa_defer_event *e; + assert(m && callback); i = pa_xmalloc(sizeof(struct once_info)); i->callback = callback; i->userdata = userdata; - assert(api->source_fixed); - id = api->source_fixed(api, once_callback, i); - assert(id); - - /* Note: if the mainloop is destroyed before once_callback() was called, some memory is leaked. */ + assert(m->defer_new); + e = m->defer_new(m, once_callback, i); + assert(e); + m->defer_set_destroy(e, free_callback); } diff --git a/polyp/mainloop-api.h b/polyp/mainloop-api.h index 0228f580..4c8e379b 100644 --- a/polyp/mainloop-api.h +++ b/polyp/mainloop-api.h @@ -25,41 +25,43 @@ #include #include -enum pa_mainloop_api_io_events { - PA_MAINLOOP_API_IO_EVENT_NULL = 0, - PA_MAINLOOP_API_IO_EVENT_INPUT = 1, - PA_MAINLOOP_API_IO_EVENT_OUTPUT = 2, - PA_MAINLOOP_API_IO_EVENT_BOTH = 3, - PA_MAINLOOP_API_IO_EVENT_HUP = 4 +enum pa_io_event_flags { + PA_IO_EVENT_NULL = 0, + PA_IO_EVENT_INPUT = 1, + PA_IO_EVENT_OUTPUT = 2, + PA_IO_EVENT_HANGUP = 4, + PA_IO_EVENT_ERROR = 8, }; +struct pa_io_event; +struct pa_defer_event; +struct pa_time_event; + struct pa_mainloop_api { void *userdata; /* IO sources */ - void* (*source_io)(struct pa_mainloop_api*a, int fd, enum pa_mainloop_api_io_events events, void (*callback) (struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata), void *userdata); - void (*enable_io)(struct pa_mainloop_api*a, void* id, enum pa_mainloop_api_io_events events); - void (*cancel_io)(struct pa_mainloop_api*a, void* id); - - /* Fixed sources */ - void* (*source_fixed)(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, void *id, void *userdata), void *userdata); - void (*enable_fixed)(struct pa_mainloop_api*a, void* id, int b); - void (*cancel_fixed)(struct pa_mainloop_api*a, void* id); + struct pa_io_event* (*io_new)(struct pa_mainloop_api*a, int fd, enum pa_io_event_flags events, void (*callback) (struct pa_mainloop_api*a, struct pa_io_event* e, int fd, enum pa_io_event_flags events, void *userdata), void *userdata); + void (*io_enable)(struct pa_io_event* e, enum pa_io_event_flags events); + void (*io_free)(struct pa_io_event* e); + void (*io_set_destroy)(struct pa_io_event *e, void (*callback) (struct pa_mainloop_api*a, struct pa_io_event *e, void *userdata)); - /* Idle sources */ - void* (*source_idle)(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, void *id, void *userdata), void *userdata); - void (*enable_idle)(struct pa_mainloop_api*a, void* id, int b); - void (*cancel_idle)(struct pa_mainloop_api*a, void* id); - /* Time sources */ - void* (*source_time)(struct pa_mainloop_api*a, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*a, void *id, const struct timeval *tv, void *userdata), void *userdata); - void (*enable_time)(struct pa_mainloop_api*a, void *id, const struct timeval *tv); - void (*cancel_time)(struct pa_mainloop_api*a, void* id); + struct pa_time_event* (*time_new)(struct pa_mainloop_api*a, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*a, struct pa_time_event* e, const struct timeval *tv, void *userdata), void *userdata); + void (*time_restart)(struct pa_time_event* e, const struct timeval *tv); + void (*time_free)(struct pa_time_event* e); + void (*time_set_destroy)(struct pa_time_event *e, void (*callback) (struct pa_mainloop_api*a, struct pa_time_event *e, void *userdata)); + + /* Deferred sources */ + struct pa_defer_event* (*defer_new)(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, struct pa_defer_event* e, void *userdata), void *userdata); + void (*defer_enable)(struct pa_defer_event* e, int b); + void (*defer_free)(struct pa_defer_event* e); + void (*defer_set_destroy)(struct pa_defer_event *e, void (*callback) (struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata)); /* Exit mainloop */ void (*quit)(struct pa_mainloop_api*a, int retval); }; -void pa_mainloop_api_once(struct pa_mainloop_api*m, void (*callback)(void *userdata), void *userdata); +void pa_mainloop_api_once(struct pa_mainloop_api*m, void (*callback)(struct pa_mainloop_api*m, void *userdata), void *userdata); #endif diff --git a/polyp/mainloop-signal.c b/polyp/mainloop-signal.c index 6e79767a..f7ff7e93 100644 --- a/polyp/mainloop-signal.c +++ b/polyp/mainloop-signal.c @@ -35,30 +35,31 @@ #include "util.h" #include "xmalloc.h" -struct signal_info { +struct pa_signal_event { int sig; struct sigaction saved_sigaction; - void (*callback) (void *id, int signal, void *userdata); + void (*callback) (struct pa_mainloop_api*a, struct pa_signal_event *e, int signal, void *userdata); void *userdata; - struct signal_info *previous, *next; + void (*destroy_callback) (struct pa_mainloop_api*a, struct pa_signal_event*e, void *userdata); + struct pa_signal_event *previous, *next; }; static struct pa_mainloop_api *api = NULL; static int signal_pipe[2] = { -1, -1 }; -static void* mainloop_source = NULL; -static struct signal_info *signals = NULL; +static struct pa_io_event* io_event = NULL; +static struct pa_signal_event *signals = NULL; static void signal_handler(int sig) { write(signal_pipe[1], &sig, sizeof(sig)); } -static void callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { - assert(a && id && events == PA_MAINLOOP_API_IO_EVENT_INPUT && id == mainloop_source && fd == signal_pipe[0]); +static void callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata) { + assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]); for (;;) { ssize_t r; int sig; - struct signal_info*s; + struct pa_signal_event*s; if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) { if (errno == EAGAIN) @@ -76,14 +77,15 @@ static void callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloo for (s = signals; s; s = s->next) if (s->sig == sig) { assert(s->callback); - s->callback(s, sig, s->userdata); + s->callback(a, s, sig, s->userdata); break; } } } int pa_signal_init(struct pa_mainloop_api *a) { - assert(a); + assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event); + if (pipe(signal_pipe) < 0) { fprintf(stderr, "pipe() failed: %s\n", strerror(errno)); return -1; @@ -93,71 +95,80 @@ int pa_signal_init(struct pa_mainloop_api *a) { pa_make_nonblock_fd(signal_pipe[1]); api = a; - mainloop_source = api->source_io(api, signal_pipe[0], PA_MAINLOOP_API_IO_EVENT_INPUT, callback, NULL); - assert(mainloop_source); + io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL); + assert(io_event); return 0; } void pa_signal_done(void) { - assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && mainloop_source); + assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && io_event); + + while (signals) + pa_signal_free(signals); - api->cancel_io(api, mainloop_source); - mainloop_source = NULL; + api->io_free(io_event); + io_event = NULL; close(signal_pipe[0]); close(signal_pipe[1]); signal_pipe[0] = signal_pipe[1] = -1; - while (signals) - pa_signal_unregister(signals); - api = NULL; } -void* pa_signal_register(int sig, void (*callback) (void *id, int signal, void *userdata), void *userdata) { - struct signal_info *s = NULL; +struct pa_signal_event* pa_signal_new(int sig, void (*callback) (struct pa_mainloop_api *api, struct pa_signal_event*e, int sig, void *userdata), void *userdata) { + struct pa_signal_event *e = NULL; struct sigaction sa; assert(sig > 0 && callback); - - for (s = signals; s; s = s->next) - if (s->sig == sig) + + for (e = signals; e; e = e->next) + if (e->sig == sig) goto fail; - s = pa_xmalloc(sizeof(struct signal_info)); - s->sig = sig; - s->callback = callback; - s->userdata = userdata; + e = pa_xmalloc(sizeof(struct pa_signal_event)); + e->sig = sig; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; memset(&sa, 0, sizeof(sa)); sa.sa_handler = signal_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; - if (sigaction(sig, &sa, &s->saved_sigaction) < 0) + if (sigaction(sig, &sa, &e->saved_sigaction) < 0) goto fail; - s->previous = NULL; - s->next = signals; - signals = s; + e->previous = NULL; + e->next = signals; + signals = e; - return s; + return e; fail: - if (s) - pa_xfree(s); + if (e) + pa_xfree(e); return NULL; } -void pa_signal_unregister(void *id) { - struct signal_info *s = id; - assert(s); +void pa_signal_free(struct pa_signal_event *e) { + assert(e); - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; + if (e->next) + e->next->previous = e->previous; + if (e->previous) + e->previous->next = e->next; else - signals = s->next; + signals = e->next; + + sigaction(e->sig, &e->saved_sigaction, NULL); + + if (e->destroy_callback) + e->destroy_callback(api, e, e->userdata); + + pa_xfree(e); +} - sigaction(s->sig, &s->saved_sigaction, NULL); - pa_xfree(s); +void pa_signal_set_destroy(struct pa_signal_event *e, void (*callback) (struct pa_mainloop_api *api, struct pa_signal_event*e, void *userdata)) { + assert(e); + e->destroy_callback = callback; } diff --git a/polyp/mainloop-signal.h b/polyp/mainloop-signal.h index 8afe9c8d..dacbc153 100644 --- a/polyp/mainloop-signal.h +++ b/polyp/mainloop-signal.h @@ -27,7 +27,11 @@ int pa_signal_init(struct pa_mainloop_api *api); void pa_signal_done(void); -void* pa_signal_register(int signal, void (*callback) (void *id, int signal, void *userdata), void *userdata); -void pa_signal_unregister(void *id); +struct pa_signal_event; + +struct pa_signal_event* pa_signal_new(int signal, void (*callback) (struct pa_mainloop_api *api, struct pa_signal_event*e, int signal, void *userdata), void *userdata); +void pa_signal_free(struct pa_signal_event *e); + +void pa_signal_set_destroy(struct pa_signal_event *e, void (*callback) (struct pa_mainloop_api *api, struct pa_signal_event*e, void *userdata)); #endif diff --git a/polyp/mainloop.c b/polyp/mainloop.c index f3d8e781..c678537e 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -38,42 +38,42 @@ #include "idxset.h" #include "xmalloc.h" -struct mainloop_source_header { +struct pa_base_event { +}; + +struct pa_io_event { struct pa_mainloop *mainloop; int dead; -}; - -struct mainloop_source_io { - struct mainloop_source_header header; - int fd; - enum pa_mainloop_api_io_events events; - void (*callback) (struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata); - void *userdata; - + enum pa_io_event_flags events; + void (*callback) (struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata); struct pollfd *pollfd; + void *userdata; + void (*destroy_callback) (struct pa_mainloop_api*a, struct pa_io_event *e, void *userdata); }; -struct mainloop_source_fixed_or_idle { - struct mainloop_source_header header; +struct pa_time_event { + struct pa_mainloop *mainloop; + int dead; int enabled; - - void (*callback)(struct pa_mainloop_api*a, void *id, void *userdata); + struct timeval timeval; + void (*callback)(struct pa_mainloop_api*a, struct pa_time_event *e, const struct timeval*tv, void *userdata); void *userdata; + void (*destroy_callback) (struct pa_mainloop_api*a, struct pa_time_event *e, void *userdata); }; -struct mainloop_source_time { - struct mainloop_source_header header; +struct pa_defer_event { + struct pa_mainloop *mainloop; + int dead; int enabled; - - struct timeval timeval; - void (*callback)(struct pa_mainloop_api*a, void *id, const struct timeval*tv, void *userdata); + void (*callback)(struct pa_mainloop_api*a, struct pa_defer_event*e, void *userdata); void *userdata; + void (*destroy_callback) (struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata); }; struct pa_mainloop { - struct pa_idxset *io_sources, *fixed_sources, *idle_sources, *time_sources; - int io_sources_scan_dead, fixed_sources_scan_dead, idle_sources_scan_dead, time_sources_scan_dead; + struct pa_idxset *io_events, *time_events, *defer_events; + int io_events_scan_dead, defer_events_scan_dead, time_events_scan_dead; struct pollfd *pollfds; unsigned max_pollfds, n_pollfds; @@ -83,57 +83,248 @@ struct pa_mainloop { struct pa_mainloop_api api; }; -static void setup_api(struct pa_mainloop *m); +/* IO events */ +static struct pa_io_event* mainloop_io_new(struct pa_mainloop_api*a, int fd, enum pa_io_event_flags events, void (*callback) (struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags events, void *userdata), void *userdata) { + struct pa_mainloop *m; + struct pa_io_event *e; + + assert(a && a->userdata && fd >= 0 && callback); + m = a->userdata; + assert(a == &m->api); + + e = pa_xmalloc(sizeof(struct pa_io_event)); + e->mainloop = m; + e->dead = 0; + + e->fd = fd; + e->events = events; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + e->pollfd = NULL; + + pa_idxset_put(m->io_events, e, NULL); + m->rebuild_pollfds = 1; + return e; +} + +static void mainloop_io_enable(struct pa_io_event *e, enum pa_io_event_flags events) { + assert(e && e->mainloop); + + e->events = events; + if (e->pollfd) + e->pollfd->events = + (events & PA_IO_EVENT_INPUT ? POLLIN : 0) | + (events & PA_IO_EVENT_OUTPUT ? POLLOUT : 0) | + POLLHUP | + POLLERR; +} + +static void mainloop_io_free(struct pa_io_event *e) { + assert(e && e->mainloop); + e->dead = e->mainloop->io_events_scan_dead = e->mainloop->rebuild_pollfds = 1; +} + +static void mainloop_io_set_destroy(struct pa_io_event *e, void (*callback)(struct pa_mainloop_api*a, struct pa_io_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* Defer events */ +struct pa_defer_event* mainloop_defer_new(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata), void *userdata) { + struct pa_mainloop *m; + struct pa_defer_event *e; + + assert(a && a->userdata && callback); + m = a->userdata; + assert(a == &m->api); + + e = pa_xmalloc(sizeof(struct pa_defer_event)); + e->mainloop = m; + e->dead = 0; + + e->enabled = 1; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + + pa_idxset_put(m->defer_events, e, NULL); + return e; +} + +static void mainloop_defer_enable(struct pa_defer_event *e, int b) { + assert(e); + e->enabled = b; +} + +static void mainloop_defer_free(struct pa_defer_event *e) { + assert(e); + e->dead = e->mainloop->defer_events_scan_dead = 1; +} + +static void mainloop_defer_set_destroy(struct pa_defer_event *e, void (*callback)(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* Time events */ +static struct pa_time_event* mainloop_time_new(struct pa_mainloop_api*a, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*a, struct pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { + struct pa_mainloop *m; + struct pa_time_event *e; + + assert(a && a->userdata && callback); + m = a->userdata; + assert(a == &m->api); + + e = pa_xmalloc(sizeof(struct pa_time_event)); + e->mainloop = m; + e->dead = 0; + + e->enabled = !!tv; + if (tv) + e->timeval = *tv; + + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + + pa_idxset_put(m->time_events, e, NULL); + return e; +} + +static void mainloop_time_restart(struct pa_time_event *e, const struct timeval *tv) { + assert(e); + + if (tv) { + e->enabled = 1; + e->timeval = *tv; + } else + e->enabled = 0; +} + +static void mainloop_time_free(struct pa_time_event *e) { + assert(e); + e->dead = e->mainloop->time_events_scan_dead = 1; +} + +static void mainloop_time_set_destroy(struct pa_time_event *e, void (*callback)(struct pa_mainloop_api*a, struct pa_time_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* quit() */ + +static void mainloop_quit(struct pa_mainloop_api*a, int retval) { + struct pa_mainloop *m; + assert(a && a->userdata); + m = a->userdata; + assert(a == &m->api); + + m->quit = 1; + m->retval = retval; +} + +static const struct pa_mainloop_api vtable = { + userdata: NULL, + + io_new: mainloop_io_new, + io_enable: mainloop_io_enable, + io_free: mainloop_io_free, + io_set_destroy: mainloop_io_set_destroy, + + time_new : mainloop_time_new, + time_restart : mainloop_time_restart, + time_free : mainloop_time_free, + time_set_destroy : mainloop_time_set_destroy, + + defer_new : mainloop_defer_new, + defer_enable : mainloop_defer_enable, + defer_free : mainloop_defer_free, + defer_set_destroy : mainloop_defer_set_destroy, + + quit : mainloop_quit, +}; struct pa_mainloop *pa_mainloop_new(void) { struct pa_mainloop *m; m = pa_xmalloc(sizeof(struct pa_mainloop)); - m->io_sources = pa_idxset_new(NULL, NULL); - m->fixed_sources = pa_idxset_new(NULL, NULL); - m->idle_sources = pa_idxset_new(NULL, NULL); - m->time_sources = pa_idxset_new(NULL, NULL); + m->io_events = pa_idxset_new(NULL, NULL); + m->defer_events = pa_idxset_new(NULL, NULL); + m->time_events = pa_idxset_new(NULL, NULL); - assert(m->io_sources && m->fixed_sources && m->idle_sources && m->time_sources); + assert(m->io_events && m->defer_events && m->time_events); - m->io_sources_scan_dead = m->fixed_sources_scan_dead = m->idle_sources_scan_dead = m->time_sources_scan_dead = 0; + m->io_events_scan_dead = m->defer_events_scan_dead = m->time_events_scan_dead = 0; m->pollfds = NULL; m->max_pollfds = m->n_pollfds = m->rebuild_pollfds = 0; m->quit = m->running = m->retval = 0; - setup_api(m); + m->api = vtable; + m->api.userdata = m; return m; } -static int foreach(void *p, uint32_t index, int *del, void*userdata) { - struct mainloop_source_header *h = p; +static int io_foreach(void *p, uint32_t index, int *del, void*userdata) { + struct pa_io_event *e = p; int *all = userdata; - assert(p && del && all); + assert(e && del && all); - if (*all || h->dead) { - pa_xfree(h); - *del = 1; - } + if (!*all || !e->dead) + return 0; + + if (e->destroy_callback) + e->destroy_callback(&e->mainloop->api, e, e->userdata); + pa_xfree(e); + *del = 1; + return 0; +}; +static int time_foreach(void *p, uint32_t index, int *del, void*userdata) { + struct pa_time_event *e = p; + int *all = userdata; + assert(e && del && all); + + if (!*all || !e->dead) + return 0; + + if (e->destroy_callback) + e->destroy_callback(&e->mainloop->api, e, e->userdata); + pa_xfree(e); + *del = 1; + return 0; +}; + +static int defer_foreach(void *p, uint32_t index, int *del, void*userdata) { + struct pa_defer_event *e = p; + int *all = userdata; + assert(e && del && all); + + if (!*all || !e->dead) + return 0; + + if (e->destroy_callback) + e->destroy_callback(&e->mainloop->api, e, e->userdata); + pa_xfree(e); + *del = 1; return 0; }; void pa_mainloop_free(struct pa_mainloop* m) { int all = 1; assert(m); - pa_idxset_foreach(m->io_sources, foreach, &all); - pa_idxset_foreach(m->fixed_sources, foreach, &all); - pa_idxset_foreach(m->idle_sources, foreach, &all); - pa_idxset_foreach(m->time_sources, foreach, &all); - pa_idxset_free(m->io_sources, NULL, NULL); - pa_idxset_free(m->fixed_sources, NULL, NULL); - pa_idxset_free(m->idle_sources, NULL, NULL); - pa_idxset_free(m->time_sources, NULL, NULL); + pa_idxset_foreach(m->io_events, io_foreach, &all); + pa_idxset_foreach(m->time_events, time_foreach, &all); + pa_idxset_foreach(m->defer_events, defer_foreach, &all); + + pa_idxset_free(m->io_events, NULL, NULL); + pa_idxset_free(m->time_events, NULL, NULL); + pa_idxset_free(m->defer_events, NULL, NULL); pa_xfree(m->pollfds); pa_xfree(m); @@ -142,23 +333,21 @@ void pa_mainloop_free(struct pa_mainloop* m) { static void scan_dead(struct pa_mainloop *m) { int all = 0; assert(m); - if (m->io_sources_scan_dead) - pa_idxset_foreach(m->io_sources, foreach, &all); - if (m->fixed_sources_scan_dead) - pa_idxset_foreach(m->fixed_sources, foreach, &all); - if (m->idle_sources_scan_dead) - pa_idxset_foreach(m->idle_sources, foreach, &all); - if (m->time_sources_scan_dead) - pa_idxset_foreach(m->time_sources, foreach, &all); + if (m->io_events_scan_dead) + pa_idxset_foreach(m->io_events, io_foreach, &all); + if (m->time_events_scan_dead) + pa_idxset_foreach(m->time_events, time_foreach, &all); + if (m->defer_events_scan_dead) + pa_idxset_foreach(m->defer_events, defer_foreach, &all); } static void rebuild_pollfds(struct pa_mainloop *m) { - struct mainloop_source_io*s; + struct pa_io_event*e; struct pollfd *p; uint32_t index = PA_IDXSET_INVALID; unsigned l; - l = pa_idxset_ncontents(m->io_sources); + l = pa_idxset_ncontents(m->io_events); if (m->max_pollfds < l) { m->pollfds = pa_xrealloc(m->pollfds, sizeof(struct pollfd)*l); m->max_pollfds = l; @@ -166,15 +355,19 @@ static void rebuild_pollfds(struct pa_mainloop *m) { m->n_pollfds = 0; p = m->pollfds; - for (s = pa_idxset_first(m->io_sources, &index); s; s = pa_idxset_next(m->io_sources, &index)) { - if (s->header.dead) { - s->pollfd = NULL; + for (e = pa_idxset_first(m->io_events, &index); e; e = pa_idxset_next(m->io_events, &index)) { + if (e->dead) { + e->pollfd = NULL; continue; } - s->pollfd = p; - p->fd = s->fd; - p->events = ((s->events & PA_MAINLOOP_API_IO_EVENT_INPUT) ? POLLIN : 0) | ((s->events & PA_MAINLOOP_API_IO_EVENT_OUTPUT) ? POLLOUT : 0); + e->pollfd = p; + p->fd = e->fd; + p->events = + ((e->events & PA_IO_EVENT_INPUT) ? POLLIN : 0) | + ((e->events & PA_IO_EVENT_OUTPUT) ? POLLOUT : 0) | + POLLHUP | + POLLERR; p->revents = 0; p++; @@ -184,60 +377,62 @@ static void rebuild_pollfds(struct pa_mainloop *m) { static void dispatch_pollfds(struct pa_mainloop *m) { uint32_t index = PA_IDXSET_INVALID; - struct mainloop_source_io *s; + struct pa_io_event *e; - for (s = pa_idxset_first(m->io_sources, &index); s; s = pa_idxset_next(m->io_sources, &index)) { - if (s->header.dead || !s->pollfd || !s->pollfd->revents) + for (e = pa_idxset_first(m->io_events, &index); e; e = pa_idxset_next(m->io_events, &index)) { + if (e->dead || !e->pollfd || !e->pollfd->revents) continue; - assert(s->pollfd->fd == s->fd && s->callback); - s->callback(&m->api, s, s->fd, - ((s->pollfd->revents & POLLHUP) ? PA_MAINLOOP_API_IO_EVENT_HUP : 0) | - ((s->pollfd->revents & POLLIN) ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | - ((s->pollfd->revents & POLLOUT) ? PA_MAINLOOP_API_IO_EVENT_OUTPUT : 0), s->userdata); - s->pollfd->revents = 0; + assert(e->pollfd->fd == e->fd && e->callback); + e->callback(&m->api, e, e->fd, + (e->pollfd->revents & POLLHUP ? PA_IO_EVENT_HANGUP : 0) | + (e->pollfd->revents & POLLIN ? PA_IO_EVENT_INPUT : 0) | + (e->pollfd->revents & POLLOUT ? PA_IO_EVENT_OUTPUT : 0) | + (e->pollfd->revents & POLLERR ? PA_IO_EVENT_ERROR : 0), + e->userdata); + e->pollfd->revents = 0; } } -static void run_fixed_or_idle(struct pa_mainloop *m, struct pa_idxset *i) { - uint32_t index = PA_IDXSET_INVALID; - struct mainloop_source_fixed_or_idle *s; +static void dispatch_defer(struct pa_mainloop *m) { + uint32_t index; + struct pa_defer_event *e; - for (s = pa_idxset_first(i, &index); s; s = pa_idxset_next(i, &index)) { - if (s->header.dead || !s->enabled) + for (e = pa_idxset_first(m->defer_events, &index); e; e = pa_idxset_next(m->defer_events, &index)) { + if (e->dead || !e->enabled) continue; - assert(s->callback); - s->callback(&m->api, s, s->userdata); + assert(e->callback); + e->callback(&m->api, e, e->userdata); } } static int calc_next_timeout(struct pa_mainloop *m) { - uint32_t index = PA_IDXSET_INVALID; - struct mainloop_source_time *s; + uint32_t index; + struct pa_time_event *e; struct timeval now; int t = -1; - if (pa_idxset_isempty(m->time_sources)) + if (pa_idxset_isempty(m->time_events)) return -1; gettimeofday(&now, NULL); - for (s = pa_idxset_first(m->time_sources, &index); s; s = pa_idxset_next(m->time_sources, &index)) { + for (e = pa_idxset_first(m->time_events, &index); e; e = pa_idxset_next(m->time_events, &index)) { int tmp; - if (s->header.dead || !s->enabled) + if (e->dead || !e->enabled) continue; - if (s->timeval.tv_sec < now.tv_sec || (s->timeval.tv_sec == now.tv_sec && s->timeval.tv_usec <= now.tv_usec)) + if (e->timeval.tv_sec < now.tv_sec || (e->timeval.tv_sec == now.tv_sec && e->timeval.tv_usec <= now.tv_usec)) return 0; - tmp = (s->timeval.tv_sec - now.tv_sec)*1000; + tmp = (e->timeval.tv_sec - now.tv_sec)*1000; - if (s->timeval.tv_usec > now.tv_usec) - tmp += (s->timeval.tv_usec - now.tv_usec)/1000; + if (e->timeval.tv_usec > now.tv_usec) + tmp += (e->timeval.tv_usec - now.tv_usec)/1000; else - tmp -= (now.tv_usec - s->timeval.tv_usec)/1000; + tmp -= (now.tv_usec - e->timeval.tv_usec)/1000; if (tmp == 0) return 0; @@ -249,43 +444,31 @@ static int calc_next_timeout(struct pa_mainloop *m) { } static void dispatch_timeout(struct pa_mainloop *m) { - uint32_t index = PA_IDXSET_INVALID; - struct mainloop_source_time *s; + uint32_t index; + struct pa_time_event *e; struct timeval now; assert(m); - if (pa_idxset_isempty(m->time_sources)) + if (pa_idxset_isempty(m->time_events)) return; gettimeofday(&now, NULL); - for (s = pa_idxset_first(m->time_sources, &index); s; s = pa_idxset_next(m->time_sources, &index)) { + for (e = pa_idxset_first(m->time_events, &index); e; e = pa_idxset_next(m->time_events, &index)) { - if (s->header.dead || !s->enabled) + if (e->dead || !e->enabled) continue; - if (s->timeval.tv_sec < now.tv_sec || (s->timeval.tv_sec == now.tv_sec && s->timeval.tv_usec <= now.tv_usec)) { - assert(s->callback); + if (e->timeval.tv_sec < now.tv_sec || (e->timeval.tv_sec == now.tv_sec && e->timeval.tv_usec <= now.tv_usec)) { + assert(e->callback); - s->enabled = 0; - s->callback(&m->api, s, &s->timeval, s->userdata); + e->enabled = 0; + e->callback(&m->api, e, &e->timeval, e->userdata); } } } -static int any_idle_sources(struct pa_mainloop *m) { - struct mainloop_source_fixed_or_idle *s; - uint32_t index; - assert(m); - - for (s = pa_idxset_first(m->idle_sources, &index); s; s = pa_idxset_next(m->idle_sources, &index)) - if (!s->header.dead && s->enabled) - return 1; - - return 0; -} - int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval) { - int r, idle; + int r; assert(m && !m->running); if(m->quit) { @@ -297,23 +480,16 @@ int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval) { m->running = 1; scan_dead(m); - run_fixed_or_idle(m, m->fixed_sources); + dispatch_defer(m); if (m->rebuild_pollfds) { rebuild_pollfds(m); m->rebuild_pollfds = 0; } - idle = any_idle_sources(m); - do { - int t; - - if (!block || idle) - t = 0; - else - t = calc_next_timeout(m); - + int t = block ? calc_next_timeout(m) : 0; + /*fprintf(stderr, "%u\n", t);*/ r = poll(m->pollfds, m->n_pollfds, t); } while (r < 0 && errno == EINTR); @@ -321,8 +497,6 @@ int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval) { if (r > 0) dispatch_pollfds(m); - else if (r == 0 && idle) - run_fixed_or_idle(m, m->idle_sources); else if (r < 0) fprintf(stderr, "select(): %s\n", strerror(errno)); @@ -341,209 +515,7 @@ void pa_mainloop_quit(struct pa_mainloop *m, int r) { m->quit = r; } -/* IO sources */ -static void* mainloop_source_io(struct pa_mainloop_api*a, int fd, enum pa_mainloop_api_io_events events, void (*callback) (struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata), void *userdata) { - struct pa_mainloop *m; - struct mainloop_source_io *s; - assert(a && a->userdata && fd >= 0 && callback); - m = a->userdata; - assert(a == &m->api); - - s = pa_xmalloc(sizeof(struct mainloop_source_io)); - s->header.mainloop = m; - s->header.dead = 0; - - s->fd = fd; - s->events = events; - s->callback = callback; - s->userdata = userdata; - s->pollfd = NULL; - - pa_idxset_put(m->io_sources, s, NULL); - m->rebuild_pollfds = 1; - return s; -} - -static void mainloop_enable_io(struct pa_mainloop_api*a, void* id, enum pa_mainloop_api_io_events events) { - struct pa_mainloop *m; - struct mainloop_source_io *s = id; - assert(a && a->userdata && s && !s->header.dead); - m = a->userdata; - assert(a == &m->api && s->header.mainloop == m); - - s->events = events; - if (s->pollfd) - s->pollfd->events = ((s->events & PA_MAINLOOP_API_IO_EVENT_INPUT) ? POLLIN : 0) | ((s->events & PA_MAINLOOP_API_IO_EVENT_OUTPUT) ? POLLOUT : 0); -} - -static void mainloop_cancel_io(struct pa_mainloop_api*a, void* id) { - struct pa_mainloop *m; - struct mainloop_source_io *s = id; - assert(a && a->userdata && s && !s->header.dead); - m = a->userdata; - assert(a == &m->api && s->header.mainloop == m); - - s->header.dead = 1; - m->io_sources_scan_dead = 1; - m->rebuild_pollfds = 1; -} - -/* Fixed sources */ -static void* mainloop_source_fixed(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, void *id, void *userdata), void *userdata) { - struct pa_mainloop *m; - struct mainloop_source_fixed_or_idle *s; - assert(a && a->userdata && callback); - m = a->userdata; - assert(a == &m->api); - - s = pa_xmalloc(sizeof(struct mainloop_source_fixed_or_idle)); - s->header.mainloop = m; - s->header.dead = 0; - - s->enabled = 1; - s->callback = callback; - s->userdata = userdata; - - pa_idxset_put(m->fixed_sources, s, NULL); - return s; -} - -static void mainloop_enable_fixed(struct pa_mainloop_api*a, void* id, int b) { - struct pa_mainloop *m; - struct mainloop_source_fixed_or_idle *s = id; - assert(a && a->userdata && s && !s->header.dead); - m = a->userdata; - assert(a == &m->api); - - s->enabled = b; -} - -static void mainloop_cancel_fixed(struct pa_mainloop_api*a, void* id) { - struct pa_mainloop *m; - struct mainloop_source_fixed_or_idle *s = id; - assert(a && a->userdata && s && !s->header.dead); - m = a->userdata; - assert(a == &m->api); - - s->header.dead = 1; - m->fixed_sources_scan_dead = 1; -} - -/* Idle sources */ -static void* mainloop_source_idle(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, void *id, void *userdata), void *userdata) { - struct pa_mainloop *m; - struct mainloop_source_fixed_or_idle *s; - assert(a && a->userdata && callback); - m = a->userdata; - assert(a == &m->api); - - s = pa_xmalloc(sizeof(struct mainloop_source_fixed_or_idle)); - s->header.mainloop = m; - s->header.dead = 0; - - s->enabled = 1; - s->callback = callback; - s->userdata = userdata; - - pa_idxset_put(m->idle_sources, s, NULL); - return s; -} - -static void mainloop_cancel_idle(struct pa_mainloop_api*a, void* id) { - struct pa_mainloop *m; - struct mainloop_source_fixed_or_idle *s = id; - assert(a && a->userdata && s && !s->header.dead); - m = a->userdata; - assert(a == &m->api); - - s->header.dead = 1; - m->idle_sources_scan_dead = 1; -} - -/* Time sources */ -static void* mainloop_source_time(struct pa_mainloop_api*a, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*a, void *id, const struct timeval *tv, void *userdata), void *userdata) { - struct pa_mainloop *m; - struct mainloop_source_time *s; - assert(a && a->userdata && callback); - m = a->userdata; - assert(a == &m->api); - - s = pa_xmalloc(sizeof(struct mainloop_source_time)); - s->header.mainloop = m; - s->header.dead = 0; - - s->enabled = !!tv; - if (tv) - s->timeval = *tv; - - s->callback = callback; - s->userdata = userdata; - - pa_idxset_put(m->time_sources, s, NULL); - return s; -} - -static void mainloop_enable_time(struct pa_mainloop_api*a, void *id, const struct timeval *tv) { - struct pa_mainloop *m; - struct mainloop_source_time *s = id; - assert(a && a->userdata && s && !s->header.dead); - m = a->userdata; - assert(a == &m->api); - - if (tv) { - s->enabled = 1; - s->timeval = *tv; - } else - s->enabled = 0; -} - -static void mainloop_cancel_time(struct pa_mainloop_api*a, void* id) { - struct pa_mainloop *m; - struct mainloop_source_time *s = id; - assert(a && a->userdata && s && !s->header.dead); - m = a->userdata; - assert(a == &m->api); - - s->header.dead = 1; - m->time_sources_scan_dead = 1; - -} - -static void mainloop_quit(struct pa_mainloop_api*a, int retval) { - struct pa_mainloop *m; - assert(a && a->userdata); - m = a->userdata; - assert(a == &m->api); - - m->quit = 1; - m->retval = retval; -} - -static void setup_api(struct pa_mainloop *m) { - assert(m); - - m->api.userdata = m; - m->api.source_io = mainloop_source_io; - m->api.enable_io = mainloop_enable_io; - m->api.cancel_io = mainloop_cancel_io; - - m->api.source_fixed = mainloop_source_fixed; - m->api.enable_fixed = mainloop_enable_fixed; - m->api.cancel_fixed = mainloop_cancel_fixed; - - m->api.source_idle = mainloop_source_idle; - m->api.enable_idle = mainloop_enable_fixed; /* (!) */ - m->api.cancel_idle = mainloop_cancel_idle; - - m->api.source_time = mainloop_source_time; - m->api.enable_time = mainloop_enable_time; - m->api.cancel_time = mainloop_cancel_time; - - m->api.quit = mainloop_quit; -} - struct pa_mainloop_api* pa_mainloop_get_api(struct pa_mainloop*m) { assert(m); return &m->api; } - diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index a0fa52db..5b4a7b73 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -42,8 +42,8 @@ struct userdata { snd_pcm_t *pcm_handle; struct pa_sink *sink; - void **io_sources; - unsigned n_io_sources; + struct pa_io_event **io_events; + unsigned n_io_events; size_t frame_size, fragment_size; struct pa_memchunk memchunk, silence; @@ -128,9 +128,9 @@ static void do_write(struct userdata *u) { } } -static void io_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { +static void io_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { struct userdata *u = userdata; - assert(u && a && id); + assert(u && a && e); if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) xrun_recovery(u); @@ -207,7 +207,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { pa_sink_set_owner(u->sink, m); u->sink->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); - if (pa_create_io_sources(u->pcm_handle, c->mainloop, &u->io_sources, &u->n_io_sources, io_callback, u) < 0) { + if (pa_create_io_events(u->pcm_handle, c->mainloop, &u->io_events, &u->n_io_events, io_callback, u) < 0) { fprintf(stderr, __FILE__": failed to obtain file descriptors\n"); goto fail; } @@ -251,8 +251,8 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { if (u->sink) pa_sink_free(u->sink); - if (u->io_sources) - pa_free_io_sources(c->mainloop, u->io_sources, u->n_io_sources); + if (u->io_events) + pa_free_io_events(c->mainloop, u->io_events, u->n_io_events); if (u->pcm_handle) { snd_pcm_drop(u->pcm_handle); diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index 8207d462..df716f73 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -42,8 +42,8 @@ struct userdata { snd_pcm_t *pcm_handle; struct pa_source *source; - void **io_sources; - unsigned n_io_sources; + struct pa_io_event **io_events; + unsigned n_io_events; size_t frame_size, fragment_size; struct pa_memchunk memchunk; @@ -128,9 +128,9 @@ static void do_read(struct userdata *u) { } } -static void io_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { +static void io_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { struct userdata *u = userdata; - assert(u && a && id); + assert(u && a && e); if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) xrun_recovery(u); @@ -189,7 +189,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { pa_source_set_owner(u->source, m); u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); - if (pa_create_io_sources(u->pcm_handle, c->mainloop, &u->io_sources, &u->n_io_sources, io_callback, u) < 0) { + if (pa_create_io_events(u->pcm_handle, c->mainloop, &u->io_events, &u->n_io_events, io_callback, u) < 0) { fprintf(stderr, __FILE__": failed to obtain file descriptors\n"); goto fail; } @@ -230,8 +230,8 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { if (u->source) pa_source_free(u->source); - if (u->io_sources) - pa_free_io_sources(c->mainloop, u->io_sources, u->n_io_sources); + if (u->io_events) + pa_free_io_events(c->mainloop, u->io_events, u->n_io_events); if (u->pcm_handle) { snd_pcm_drop(u->pcm_handle); diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index 37710fc5..ea768a98 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -59,7 +59,7 @@ struct userdata { void *in_mmap, *out_mmap; size_t in_mmap_length, out_mmap_length; - void *mainloop_source; + struct pa_io_event *io_event; struct pa_memblock **in_memblocks, **out_memblocks; unsigned out_current, in_current; @@ -195,14 +195,13 @@ static void do_read(struct userdata *u) { in_clear_memblocks(u, u->in_fragments/2); }; -static void io_callback(struct pa_mainloop_api *m, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { +static void io_callback(struct pa_mainloop_api *m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { struct userdata *u = userdata; + assert (u && u->core->mainloop == m && u->io_event == e); - assert (u && u->core->mainloop == m && u->mainloop_source == id); - - if (events & PA_MAINLOOP_API_IO_EVENT_INPUT) + if (f & PA_IO_EVENT_INPUT) do_read(u); - if (events & PA_MAINLOOP_API_IO_EVENT_OUTPUT) + if (f & PA_IO_EVENT_OUTPUT) do_write(u); } @@ -352,8 +351,8 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { assert(u->source || u->sink); - u->mainloop_source = c->mainloop->source_io(c->mainloop, u->fd, (u->source ? PA_MAINLOOP_API_IO_EVENT_INPUT : 0) | (u->sink ? PA_MAINLOOP_API_IO_EVENT_OUTPUT : 0), io_callback, u); - assert(u->mainloop_source); + u->io_event = c->mainloop->io_new(c->mainloop, u->fd, (u->source ? PA_IO_EVENT_INPUT : 0) | (u->sink ? PA_IO_EVENT_OUTPUT : 0), io_callback, u); + assert(u->io_event); pa_modargs_free(ma); @@ -403,8 +402,8 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { if (u->source) pa_source_free(u->source); - if (u->mainloop_source) - u->core->mainloop->cancel_io(u->core->mainloop, u->mainloop_source); + if (u->io_event) + u->core->mainloop->io_free(u->io_event); if (u->fd >= 0) close(u->fd); diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c index dc2bc633..22d9f676 100644 --- a/polyp/module-pipe-sink.c +++ b/polyp/module-pipe-sink.c @@ -50,7 +50,7 @@ struct userdata { struct pa_sink *sink; struct pa_iochannel *io; - void *mainloop_source; + struct pa_defer_event *defer_event; struct pa_memchunk memchunk; struct pa_module *module; @@ -69,7 +69,7 @@ static void do_write(struct userdata *u) { ssize_t r; assert(u); - u->core->mainloop->enable_fixed(u->core->mainloop, u->mainloop_source, 0); + u->core->mainloop->defer_enable(u->defer_event, 0); if (!pa_iochannel_is_writable(u->io)) return; @@ -101,10 +101,10 @@ static void notify_cb(struct pa_sink*s) { assert(s && u); if (pa_iochannel_is_writable(u->io)) - u->core->mainloop->enable_fixed(u->core->mainloop, u->mainloop_source, 1); + u->core->mainloop->defer_enable(u->defer_event, 1); } -static void fixed_callback(struct pa_mainloop_api *m, void *id, void *userdata) { +static void defer_callback(struct pa_mainloop_api *m, struct pa_defer_event*e, void *userdata) { struct userdata *u = userdata; assert(u); do_write(u); @@ -175,9 +175,9 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { u->memchunk.memblock = NULL; u->memchunk.length = 0; - u->mainloop_source = c->mainloop->source_fixed(c->mainloop, fixed_callback, u); - assert(u->mainloop_source); - c->mainloop->enable_fixed(c->mainloop, u->mainloop_source, 0); + u->defer_event = c->mainloop->defer_new(c->mainloop, defer_callback, u); + assert(u->defer_event); + c->mainloop->defer_enable(u->defer_event, 0); u->module = m; m->userdata = u; @@ -210,7 +210,7 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { pa_sink_free(u->sink); pa_iochannel_free(u->io); - u->core->mainloop->cancel_fixed(u->core->mainloop, u->mainloop_source); + u->core->mainloop->defer_free(u->defer_event); assert(u->filename); unlink(u->filename); diff --git a/polyp/module-x11-bell.c b/polyp/module-x11-bell.c index 2cf76099..5449e944 100644 --- a/polyp/module-x11-bell.c +++ b/polyp/module-x11-bell.c @@ -14,7 +14,7 @@ #include "namereg.h" struct x11_source { - void *io_source; + struct pa_io_event *io_event; struct x11_source *next; }; @@ -52,7 +52,7 @@ static int ring_bell(struct userdata *u, int percent) { return 0; } -static void io_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { +static void io_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { struct userdata *u = userdata; assert(u); @@ -77,8 +77,8 @@ static void new_io_source(struct userdata *u, int fd) { struct x11_source *s; s = pa_xmalloc(sizeof(struct x11_source)); - s->io_source = u->core->mainloop->source_io(u->core->mainloop, fd, PA_MAINLOOP_API_IO_EVENT_INPUT, io_callback, u); - assert(s->io_source); + s->io_event = u->core->mainloop->io_new(u->core->mainloop, fd, PA_IO_EVENT_INPUT, io_callback, u); + assert(s->io_event); s->next = u->x11_sources; u->x11_sources = s; } @@ -149,7 +149,7 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { while (u->x11_sources) { struct x11_source *s = u->x11_sources; u->x11_sources = u->x11_sources->next; - c->mainloop->cancel_io(c->mainloop, s->io_source); + c->mainloop->io_free(s->io_event); pa_xfree(s); } diff --git a/polyp/module.c b/polyp/module.c index 8c5e318f..83bfa800 100644 --- a/polyp/module.c +++ b/polyp/module.c @@ -35,16 +35,16 @@ #define UNLOAD_POLL_TIME 10 -static void timeout_callback(struct pa_mainloop_api *m, void *id, const struct timeval *tv, void *userdata) { +static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, const struct timeval *tv, void *userdata) { struct pa_core *c = userdata; struct timeval ntv; - assert(c && c->mainloop == m && c->auto_unload_mainloop_source == id); + assert(c && c->mainloop == m && c->auto_unload_event == e); pa_module_unload_unused(c); gettimeofday(&ntv, NULL); ntv.tv_sec += UNLOAD_POLL_TIME; - m->enable_time(m, id, &ntv); + m->time_restart(e, &ntv); } struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char *argument) { @@ -79,13 +79,13 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char if (!c->modules) c->modules = pa_idxset_new(NULL, NULL); - if (!c->auto_unload_mainloop_source) { + if (!c->auto_unload_event) { struct timeval ntv; gettimeofday(&ntv, NULL); ntv.tv_sec += UNLOAD_POLL_TIME; - c->auto_unload_mainloop_source = c->mainloop->source_time(c->mainloop, &ntv, timeout_callback, c); + c->auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); } - assert(c->auto_unload_mainloop_source); + assert(c->auto_unload_event); assert(c->modules); r = pa_idxset_put(c->modules, m, &m->index); @@ -159,9 +159,9 @@ void pa_module_unload_all(struct pa_core *c) { pa_idxset_free(c->modules, free_callback, NULL); c->modules = NULL; - if (c->auto_unload_mainloop_source) - c->mainloop->cancel_time(c->mainloop, c->auto_unload_mainloop_source); - c->auto_unload_mainloop_source = NULL; + if (c->auto_unload_event) + c->mainloop->time_free(c->auto_unload_event); + c->auto_unload_event = NULL; } static int unused_callback(void *p, uint32_t index, int *del, void *userdata) { @@ -193,7 +193,7 @@ struct once_info { uint32_t index; }; -static void module_unload_once_callback(void *userdata) { +static void module_unload_once_callback(struct pa_mainloop_api *m, void *userdata) { struct once_info *i = userdata; assert(i); pa_module_unload_by_index(i->core, i->index); diff --git a/polyp/module.h b/polyp/module.h index de195a4b..acc08c3e 100644 --- a/polyp/module.h +++ b/polyp/module.h @@ -59,5 +59,4 @@ void pa_module_done(struct pa_core *c, struct pa_module*m); void pa_module_set_used(struct pa_module*m, int used); - #endif diff --git a/polyp/native-common.h b/polyp/native-common.h index dc730e4b..d8a2a5ab 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -48,13 +48,15 @@ enum { PA_COMMAND_PLAY_SAMPLE, PA_COMMAND_REMOVE_SAMPLE, - PA_COMMAND_GET_SINK, - PA_COMMAND_GET_SOURCE, - PA_COMMAND_GET_MODULE, - PA_COMMAND_GET_CLIENT, - PA_COMMAND_GET_SINK_INPUT, - PA_COMMAND_GET_SOURCE_OUTPUT, - PA_COMMAND_GET_SAMPLE, + PA_COMMAND_GET_SINK_INFO, + PA_COMMAND_GET_SINK_INFO_LIST, + PA_COMMAND_GET_SOURCE_INFO, + PA_COMMAND_GET_SOURCE_INFO_LIST, + PA_COMMAND_GET_MODULE_INFO, + PA_COMMAND_GET_CLIENT_INFO, + PA_COMMAND_GET_SINK_INPUT_INFO, + PA_COMMAND_GET_SOURCE_OUTPUT_INFO, + PA_COMMAND_GET_SAMPLE_INFO, PA_COMMAND_SUBSCRIBE, PA_COMMAND_SUBSCRIBE_EVENT, diff --git a/polyp/pacat.c b/polyp/pacat.c index 55a0f6b9..4d8605c7 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -45,7 +45,7 @@ static struct pa_mainloop_api *mainloop_api = NULL; static void *buffer = NULL; static size_t buffer_length = 0, buffer_index = 0; -static void* stdio_source = NULL; +static struct pa_io_event* stdio_event = NULL; static void quit(int ret) { assert(mainloop_api); @@ -89,8 +89,8 @@ static void do_stream_write(size_t length) { static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) { assert(s && length); - if (stdio_source) - mainloop_api->enable_io(mainloop_api, stdio_source, PA_MAINLOOP_API_IO_EVENT_INPUT); + if (stdio_event) + mainloop_api->io_enable(stdio_event, PA_IO_EVENT_INPUT); if (!buffer) return; @@ -101,8 +101,8 @@ static void stream_write_callback(struct pa_stream *s, size_t length, void *user static void stream_read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata) { assert(s && data && length); - if (stdio_source) - mainloop_api->enable_io(mainloop_api, stdio_source, PA_MAINLOOP_API_IO_EVENT_OUTPUT); + if (stdio_event) + mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT); if (buffer) { fprintf(stderr, "Buffer overrrun, dropping incoming data\n"); @@ -174,13 +174,13 @@ static void stream_drain_complete(struct pa_stream*s, void *userdata) { fprintf(stderr, "Draining connection to server.\n"); } -static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { +static void stdin_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { size_t l, w = 0; ssize_t r; - assert(a == mainloop_api && id && stdio_source == id); + assert(a == mainloop_api && e && stdio_event == e); if (buffer) { - mainloop_api->enable_io(mainloop_api, stdio_source, PA_MAINLOOP_API_IO_EVENT_NULL); + mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL); return; } @@ -198,8 +198,8 @@ static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_m quit(1); } - mainloop_api->cancel_io(mainloop_api, stdio_source); - stdio_source = NULL; + mainloop_api->io_free(stdio_event); + stdio_event = NULL; return; } @@ -210,12 +210,12 @@ static void stdin_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_m do_stream_write(w); } -static void stdout_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { +static void stdout_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { ssize_t r; - assert(a == mainloop_api && id && stdio_source == id); + assert(a == mainloop_api && e && stdio_event == e); if (!buffer) { - mainloop_api->enable_io(mainloop_api, stdio_source, PA_MAINLOOP_API_IO_EVENT_NULL); + mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL); return; } @@ -225,8 +225,8 @@ static void stdout_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_ fprintf(stderr, "write() failed: %s\n", strerror(errno)); quit(1); - mainloop_api->cancel_io(mainloop_api, stdio_source); - stdio_source = NULL; + mainloop_api->io_free(stdio_event); + stdio_event = NULL; return; } @@ -240,7 +240,7 @@ static void stdout_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_ } } -static void exit_signal_callback(void *id, int sig, void *userdata) { +static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { fprintf(stderr, "Got SIGINT, exiting.\n"); quit(0); @@ -258,7 +258,7 @@ static void stream_get_latency_callback(struct pa_stream *s, uint32_t latency, v fprintf(stderr, "Current latency is %u usecs.\n", latency); } -static void sigusr1_signal_callback(void *id, int sig, void *userdata) { +static void sigusr1_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { if (mode == PLAYBACK) { fprintf(stderr, "Got SIGUSR1, requesting latency.\n"); pa_stream_get_latency(stream, stream_get_latency_callback, NULL); @@ -289,14 +289,14 @@ int main(int argc, char *argv[]) { r = pa_signal_init(mainloop_api); assert(r == 0); - pa_signal_register(SIGINT, exit_signal_callback, NULL); - pa_signal_register(SIGUSR1, sigusr1_signal_callback, NULL); + pa_signal_new(SIGINT, exit_signal_callback, NULL); + pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL); signal(SIGPIPE, SIG_IGN); - if (!(stdio_source = mainloop_api->source_io(mainloop_api, - mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO, - mode == PLAYBACK ? PA_MAINLOOP_API_IO_EVENT_INPUT : PA_MAINLOOP_API_IO_EVENT_OUTPUT, - mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) { + if (!(stdio_event = mainloop_api->io_new(mainloop_api, + mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO, + mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT, + mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) { fprintf(stderr, "source_io() failed.\n"); goto quit; } diff --git a/polyp/pactl.c b/polyp/pactl.c index 28b187b0..2f3a4833 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -205,7 +205,7 @@ fail: quit(1); } -static void exit_signal_callback(void *id, int sig, void *userdata) { +static void exit_signal_callback(struct pa_mainloop_api *m, struct pa_signal_event *e, int sig, void *userdata) { fprintf(stderr, "Got SIGINT, exiting.\n"); quit(0); } @@ -284,7 +284,7 @@ int main(int argc, char *argv[]) { r = pa_signal_init(mainloop_api); assert(r == 0); - pa_signal_register(SIGINT, exit_signal_callback, NULL); + pa_signal_new(SIGINT, exit_signal_callback, NULL); signal(SIGPIPE, SIG_IGN); if (!(context = pa_context_new(mainloop_api, argv[0]))) { diff --git a/polyp/pdispatch.c b/polyp/pdispatch.c index c34c6e0a..2d4c4d64 100644 --- a/polyp/pdispatch.c +++ b/polyp/pdispatch.c @@ -69,7 +69,7 @@ struct reply_info { void (*callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); void *userdata; uint32_t tag; - void *mainloop_timeout; + struct pa_time_event *time_event; int callback_is_running; }; @@ -87,7 +87,7 @@ static void reply_info_free(struct reply_info *r) { assert(r && r->pdispatch && r->pdispatch->mainloop); if (r->pdispatch) - r->pdispatch->mainloop->cancel_time(r->pdispatch->mainloop, r->mainloop_timeout); + r->pdispatch->mainloop->time_free(r->time_event); if (r->previous) r->previous->next = r->next; @@ -191,9 +191,9 @@ finish: return ret; } -static void timeout_callback(struct pa_mainloop_api*m, void *id, const struct timeval *tv, void *userdata) { +static void timeout_callback(struct pa_mainloop_api*m, struct pa_time_event*e, const struct timeval *tv, void *userdata) { struct reply_info*r = userdata; - assert (r && r->mainloop_timeout == id && r->pdispatch && r->pdispatch->mainloop == m && r->callback); + assert (r && r->time_event == e && r->pdispatch && r->pdispatch->mainloop == m && r->callback); r->callback(r->pdispatch, PA_COMMAND_TIMEOUT, r->tag, NULL, r->userdata); reply_info_free(r); @@ -217,8 +217,8 @@ void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int time gettimeofday(&tv, NULL); tv.tv_sec += timeout; - r->mainloop_timeout = pd->mainloop->source_time(pd->mainloop, &tv, timeout_callback, r); - assert(r->mainloop_timeout); + r->time_event = pd->mainloop->time_new(pd->mainloop, &tv, timeout_callback, r); + assert(r->time_event); r->previous = NULL; r->next = pd->replies; diff --git a/polyp/play-memchunk.c b/polyp/play-memchunk.c index 5c448a75..86634407 100644 --- a/polyp/play-memchunk.c +++ b/polyp/play-memchunk.c @@ -30,7 +30,7 @@ static int sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { return 0; } -static void si_kill(void *i) { +static void si_kill(struct pa_mainloop_api *m, void *i) { sink_input_kill(i); } diff --git a/polyp/polypaudio.pa b/polyp/polypaudio.pa index 0989a78d..71513565 100755 --- a/polyp/polypaudio.pa +++ b/polyp/polypaudio.pa @@ -18,33 +18,41 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -# Load audio drivers +# Load audio drivers statically + #load module-alsa-sink #load module-alsa-source device=plughw:1,0 -#load module-oss device="/dev/dsp" +#load module-oss device="/dev/dsp" sink_name=output source_name=input #load module-oss-mmap device="/dev/dsp" +# Load audio drivers automatically on access + +#autoload_sink_add output module-oss device="/dev/dsp" sink_name=output source_name=input +#autoload_source_add input module-oss device="/dev/dsp" sink_name=output source_name=input +autoload_sink_add output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +autoload_source_add input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#autoload_sink_add output module-alsa-sink sink_name=output +#autoload_source_add input module-alsa-source source_name=input + # Load several protocols load module-esound-protocol-tcp load module-simple-protocol-tcp load module-native-protocol-unix load module-cli-protocol-unix -# Load X11 bell module -load module-x11-bell - # Load the CLI module load module-cli -autoload_sink_add oss_output module-oss device="/dev/dsp" sink_name=oss_output source_name=oss_input -autoload_source_add oss_input module-oss device="/dev/dsp" sink_name=oss_output source_name=oss_input - # Make some devices default -sink_default oss_output -source_default oss_input +sink_default output +source_default input .nofail # Load something to the sample cache scache_load /usr/share/sounds/KDE_Notify.wav x11-bell -scache_play x11-bell oss_output +scache_play x11-bell output + +# Load X11 bell module +load module-x11-bell sample=x11-bell sink=output + diff --git a/polyp/polyplib.h b/polyp/polyplib.h index 391cb0c8..08e6a5a5 100644 --- a/polyp/polyplib.h +++ b/polyp/polyplib.h @@ -97,4 +97,34 @@ void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +struct pa_sink_info { + const char *name; + uint32_t index; + const char *description; + struct pa_sample_spec *sample_spec; + uint32_t owner_module; + uint32_t volume; + uint32_t monitor_source; + const char *monitor_source_name; + uint32_t latency; +}; + +void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, void *userdata), void *userdata); +void pa_context_get_sink_info_by_id(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, void *userdata), void *userdata); +void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, void *userdata), void *userdata); + +struct pa_source_info { + const char *name; + uint32_t index; + const char *description; + struct pa_sample_spec *sample_spec; + uint32_t owner_module; + uint32_t monitor_of_sink; + const char *monitor_of_sink_name; +}; + +void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, void *userdata), void *userdata); +void pa_context_get_source_info_by_id(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, void *userdata), void *userdata); +void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, void *userdata), void *userdata); + #endif diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 5f6f02fa..b11e1992 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -74,7 +74,7 @@ struct connection { struct pa_sink_input *sink_input; struct pa_source_output *source_output; struct pa_memblockq *input_memblockq, *output_memblockq; - void *fixed_source; + struct pa_defer_event *defer_event; struct { struct pa_memblock *current_memblock; size_t memblock_index, fragment_size; @@ -183,8 +183,8 @@ static void connection_free(struct connection *c) { pa_iochannel_free(c->io); - if (c->fixed_source) - c->protocol->core->mainloop->cancel_fixed(c->protocol->core->mainloop, c->fixed_source); + if (c->defer_event) + c->protocol->core->mainloop->defer_free(c->defer_event); if (c->scache_memchunk.memblock) pa_memblock_unref(c->scache_memchunk.memblock); @@ -197,8 +197,8 @@ static void* connection_write(struct connection *c, size_t length) { size_t t, i; assert(c); - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); - c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); t = c->write_data_length+length; @@ -381,7 +381,7 @@ static int esd_proto_get_latency(struct connection *c, esd_proto_t request, cons int latency, *lag; assert(c && !data && length == 0); - if (!(sink = pa_namereg(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) + if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) latency = 0; else { float usec = pa_sink_get_latency(sink); @@ -845,8 +845,8 @@ static int do_write(struct connection *c) { static void do_work(struct connection *c) { assert(c); - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); - c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 0); + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 0); if (pa_iochannel_is_hungup(c->io)) goto fail; @@ -872,11 +872,11 @@ static void io_callback(struct pa_iochannel*io, void *userdata) { do_work(c); } -/*** fixed callback ***/ +/*** defer callback ***/ -static void fixed_callback(struct pa_mainloop_api*a, void *id, void *userdata) { +static void defer_callback(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata) { struct connection *c = userdata; - assert(a && c && c->fixed_source == id); + assert(a && c && c->defer_event == e); do_work(c); } @@ -901,8 +901,8 @@ static void sink_input_drop_cb(struct pa_sink_input *i, size_t length) { pa_memblockq_drop(c->input_memblockq, length); /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); - c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); } static void sink_input_kill_cb(struct pa_sink_input *i) { @@ -926,8 +926,8 @@ static void source_output_push_cb(struct pa_source_output *o, const struct pa_me pa_memblockq_push(c->output_memblockq, chunk, 0); /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); - c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); } static void source_output_kill_cb(struct pa_source_output *o) { @@ -981,8 +981,9 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->scache_memchunk.memblock = NULL; c->scache_name = NULL; - c->fixed_source = c->protocol->core->mainloop->source_fixed(c->protocol->core->mainloop, fixed_callback, c); - c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 0); + c->defer_event = c->protocol->core->mainloop->defer_new(c->protocol->core->mainloop, defer_callback, c); + assert(c->defer_event); + c->protocol->core->mainloop->defer_enable(c->defer_event, 0); pa_idxset_put(c->protocol->connections, c, &c->index); } diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index c0aef180..778677b3 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -127,6 +127,8 @@ static void command_create_upload_stream(struct pa_pdispatch *pd, uint32_t comma static void command_finish_upload_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_play_sample(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_remove_sample(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = { NULL }, @@ -150,6 +152,10 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_FINISH_UPLOAD_STREAM] = { command_finish_upload_stream }, [PA_COMMAND_PLAY_SAMPLE] = { command_play_sample }, [PA_COMMAND_REMOVE_SAMPLE] = { command_remove_sample }, + [PA_COMMAND_GET_SINK_INFO] = { command_get_info }, + [PA_COMMAND_GET_SOURCE_INFO] = { command_get_info }, + [PA_COMMAND_GET_SINK_INFO_LIST] = { command_get_info_list }, + [PA_COMMAND_GET_SOURCE_INFO_LIST] = { command_get_info_list }, }; /* structure management */ @@ -923,6 +929,122 @@ static void command_remove_sample(struct pa_pdispatch *pd, uint32_t command, uin pa_pstream_send_simple_ack(c->pstream, tag); } +static void sink_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink *sink) { + assert(t && sink); + pa_tagstruct_putu32(t, sink->index); + pa_tagstruct_puts(t, sink->name); + pa_tagstruct_puts(t, sink->description); + pa_tagstruct_put_sample_spec(t, &sink->sample_spec); + pa_tagstruct_putu32(t, sink->owner ? sink->owner->index : (uint32_t) -1); + pa_tagstruct_putu32(t, sink->volume); + pa_tagstruct_putu32(t, sink->monitor_source->index); + pa_tagstruct_puts(t, sink->monitor_source->name); + pa_tagstruct_putu32(t, pa_sink_get_latency(sink)); +} + +static void source_fill_tagstruct(struct pa_tagstruct *t, struct pa_source *source) { + assert(t && source); + pa_tagstruct_putu32(t, source->index); + pa_tagstruct_puts(t, source->name); + pa_tagstruct_puts(t, source->description); + pa_tagstruct_put_sample_spec(t, &source->sample_spec); + pa_tagstruct_putu32(t, source->owner ? source->owner->index : (uint32_t) -1); + pa_tagstruct_putu32(t, source->monitor_of ? source->monitor_of->index : (uint32_t) -1); + pa_tagstruct_puts(t, source->monitor_of ? source->monitor_of->name : ""); +} + +static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t index; + struct pa_sink *sink = NULL; + struct pa_source *source = NULL; + const char *name; + struct pa_tagstruct *reply; + assert(c && t); + + if (pa_tagstruct_getu32(t, &index) < 0 || + pa_tagstruct_gets(t, &name) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (command == PA_COMMAND_GET_SINK_INFO) { + if (index != (uint32_t) -1) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, index); + else + sink = pa_namereg_get(c->protocol->core, *name ? name : NULL, PA_NAMEREG_SINK, 1); + } else { + assert(command == PA_COMMAND_GET_SOURCE_INFO); + if (index != (uint32_t) -1) + source = pa_idxset_get_by_index(c->protocol->core->sources, index); + else + source = pa_namereg_get(c->protocol->core, *name ? name : NULL, PA_NAMEREG_SOURCE, 1); + } + + if (!sink && !source) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + if (sink) + sink_fill_tagstruct(reply, sink); + else + source_fill_tagstruct(reply, source); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + struct pa_idxset *i; + uint32_t index; + void *p; + struct pa_tagstruct *reply; + assert(c && t); + + if (!pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + + if (command == PA_COMMAND_GET_SINK_INFO_LIST) + i = c->protocol->core->sinks; + else { + assert(command == PA_COMMAND_GET_SOURCE_INFO_LIST); + i = c->protocol->core->sources; + } + + for (p = pa_idxset_first(i, &index); p; p = pa_idxset_next(i, &index)) { + if (command == PA_COMMAND_GET_SINK_INFO_LIST) + sink_fill_tagstruct(reply, p); + else { + assert(command == PA_COMMAND_GET_SOURCE_INFO_LIST); + source_fill_tagstruct(reply, p); + } + } + + pa_pstream_send_tagstruct(c->pstream, reply); +} + /*** pstream callbacks ***/ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index 4b3b1513..a95b356c 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -45,7 +45,7 @@ struct connection { struct pa_source_output *source_output; struct pa_client *client; struct pa_memblockq *input_memblockq, *output_memblockq; - void *fixed_source; + struct pa_defer_event *defer_event; struct { struct pa_memblock *current_memblock; @@ -91,8 +91,8 @@ static void connection_free(struct connection *c) { pa_memblockq_free(c->input_memblockq); if (c->output_memblockq) pa_memblockq_free(c->output_memblockq); - if (c->fixed_source) - c->protocol->core->mainloop->cancel_fixed(c->protocol->core->mainloop, c->fixed_source); + if (c->defer_event) + c->protocol->core->mainloop->defer_free(c->defer_event); pa_xfree(c); } @@ -169,8 +169,8 @@ static int do_write(struct connection *c) { static void do_work(struct connection *c) { assert(c); - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); - c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 0); + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 0); if (pa_iochannel_is_hungup(c->io)) goto fail; @@ -209,8 +209,8 @@ static void sink_input_drop_cb(struct pa_sink_input *i, size_t length) { pa_memblockq_drop(c->input_memblockq, length); /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); - c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); } static void sink_input_kill_cb(struct pa_sink_input *i) { @@ -234,8 +234,8 @@ static void source_output_push_cb(struct pa_source_output *o, const struct pa_me pa_memblockq_push(c->output_memblockq, chunk, 0); /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->enable_fixed); - c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 1); + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); } static void source_output_kill_cb(struct pa_source_output *o) { @@ -261,9 +261,9 @@ static void io_callback(struct pa_iochannel*io, void *userdata) { /*** fixed callback ***/ -static void fixed_callback(struct pa_mainloop_api*a, void *id, void *userdata) { +static void defer_callback(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata) { struct connection *c = userdata; - assert(a && c && c->fixed_source == id); + assert(a && c && c->defer_event == e); do_work(c); } @@ -280,7 +280,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->io = io; c->sink_input = NULL; c->source_output = NULL; - c->fixed_source = NULL; + c->defer_event = NULL; c->input_memblockq = c->output_memblockq = NULL; c->protocol = p; c->playback.current_memblock = NULL; @@ -353,9 +353,9 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo pa_iochannel_set_callback(c->io, io_callback, c); pa_idxset_put(p->connections, c, NULL); - c->fixed_source = p->core->mainloop->source_fixed(p->core->mainloop, fixed_callback, c); - assert(c->fixed_source); - p->core->mainloop->enable_fixed(p->core->mainloop, c->fixed_source, 0); + c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c); + assert(c->defer_event); + p->core->mainloop->defer_enable(c->defer_event, 0); return; diff --git a/polyp/pstream.c b/polyp/pstream.c index e7441b24..4f071e4a 100644 --- a/polyp/pstream.c +++ b/polyp/pstream.c @@ -58,7 +58,7 @@ struct item_info { struct pa_pstream { struct pa_mainloop_api *mainloop; - struct mainloop_source *mainloop_source; + struct pa_defer_event *defer_event; struct pa_iochannel *io; struct pa_queue *send_queue; @@ -98,7 +98,7 @@ static void do_read(struct pa_pstream *p); static void do_something(struct pa_pstream *p) { assert(p && !p->shall_free); - p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 0); + p->mainloop->defer_enable(p->defer_event, 0); if (p->dead) return; @@ -139,9 +139,9 @@ static void io_callback(struct pa_iochannel*io, void *userdata) { do_something(p); } -static void fixed_callback(struct pa_mainloop_api *m, void *id, void*userdata) { +static void defer_callback(struct pa_mainloop_api *m, struct pa_defer_event *e, void*userdata) { struct pa_pstream *p = userdata; - assert(p && p->mainloop_source == id && p->mainloop == m); + assert(p && p->defer_event == e && p->mainloop == m); do_something(p); } @@ -159,8 +159,8 @@ struct pa_pstream *pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel p->die_callback_userdata = NULL; p->mainloop = m; - p->mainloop_source = m->source_fixed(m, fixed_callback, p); - m->enable_fixed(m, p->mainloop_source, 0); + p->defer_event = m->defer_new(m, defer_callback, p); + m->defer_enable(p->defer_event, 0); p->send_queue = pa_queue_new(); assert(p->send_queue); @@ -223,7 +223,7 @@ void pa_pstream_free(struct pa_pstream *p) { if (p->read.packet) pa_packet_unref(p->read.packet); - p->mainloop->cancel_fixed(p->mainloop, p->mainloop_source); + p->mainloop->defer_free(p->defer_event); pa_xfree(p); } @@ -236,7 +236,7 @@ void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet) { i->packet = pa_packet_ref(packet); pa_queue_push(p->send_queue, i); - p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 1); + p->mainloop->defer_enable(p->defer_event, 1); } void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk) { @@ -252,7 +252,7 @@ void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, int32_t del pa_memblock_ref(i->chunk.memblock); pa_queue_push(p->send_queue, i); - p->mainloop->enable_fixed(p->mainloop, p->mainloop_source, 1); + p->mainloop->defer_enable(p->defer_event, 1); } void pa_pstream_set_recieve_packet_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata), void *userdata) { diff --git a/polyp/socket-client.c b/polyp/socket-client.c index c0c355de..e8cb2f92 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -41,8 +41,8 @@ struct pa_socket_client { struct pa_mainloop_api *mainloop; int fd; - - void *io_source, *fixed_source; + struct pa_io_event *io_event; + struct pa_defer_event *defer_event; void (*callback)(struct pa_socket_client*c, struct pa_iochannel *io, void *userdata); void *userdata; }; @@ -54,7 +54,8 @@ static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) { c = pa_xmalloc(sizeof(struct pa_socket_client)); c->mainloop = m; c->fd = -1; - c->io_source = c->fixed_source = NULL; + c->io_event = NULL; + c->defer_event = NULL; c->callback = NULL; c->userdata = NULL; return c; @@ -95,19 +96,19 @@ failed: return; } -static void connect_fixed_cb(struct pa_mainloop_api *m, void *id, void *userdata) { +static void connect_fixed_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) { struct pa_socket_client *c = userdata; - assert(m && c && c->fixed_source == id); - m->cancel_fixed(m, c->fixed_source); - c->fixed_source = NULL; + assert(m && c && c->defer_event == e); + m->defer_free(c->defer_event); + c->defer_event = NULL; do_call(c); } -static void connect_io_cb(struct pa_mainloop_api*m, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { +static void connect_io_cb(struct pa_mainloop_api*m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { struct pa_socket_client *c = userdata; - assert(m && c && c->io_source == id && fd >= 0); - m->cancel_io(m, c->io_source); - c->io_source = NULL; + assert(m && c && c->io_event == e && fd >= 0); + m->io_free(c->io_event); + c->io_event = NULL; do_call(c); } @@ -123,11 +124,11 @@ static int do_connect(struct pa_socket_client *c, const struct sockaddr *sa, soc return -1; } - c->io_source = c->mainloop->source_io(c->mainloop, c->fd, PA_MAINLOOP_API_IO_EVENT_OUTPUT, connect_io_cb, c); - assert(c->io_source); + c->io_event = c->mainloop->io_new(c->mainloop, c->fd, PA_IO_EVENT_OUTPUT, connect_io_cb, c); + assert(c->io_event); } else { - c->fixed_source = c->mainloop->source_fixed(c->mainloop, connect_fixed_cb, c); - assert(c->fixed_source); + c->defer_event = c->mainloop->defer_new(c->mainloop, connect_fixed_cb, c); + assert(c->defer_event); } return 0; @@ -220,10 +221,10 @@ fail: void pa_socket_client_free(struct pa_socket_client *c) { assert(c && c->mainloop); - if (c->io_source) - c->mainloop->cancel_io(c->mainloop, c->io_source); - if (c->fixed_source) - c->mainloop->cancel_fixed(c->mainloop, c->fixed_source); + if (c->io_event) + c->mainloop->io_free(c->io_event); + if (c->defer_event) + c->mainloop->defer_free(c->defer_event); if (c->fd >= 0) close(c->fd); pa_xfree(c); diff --git a/polyp/socket-server.c b/polyp/socket-server.c index 5f332f0c..6af2c286 100644 --- a/polyp/socket-server.c +++ b/polyp/socket-server.c @@ -46,16 +46,16 @@ struct pa_socket_server { void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata); void *userdata; - void *mainloop_source; + struct pa_io_event *io_event; struct pa_mainloop_api *mainloop; enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX } type; }; -static void callback(struct pa_mainloop_api *mainloop, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { +static void callback(struct pa_mainloop_api *mainloop, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { struct pa_socket_server *s = userdata; struct pa_iochannel *io; int nfd; - assert(s && s->mainloop == mainloop && s->mainloop_source == id && id && fd >= 0 && fd == s->fd && events == PA_MAINLOOP_API_IO_EVENT_INPUT); + assert(s && s->mainloop == mainloop && s->io_event == e && e && fd >= 0 && fd == s->fd); if ((nfd = accept(fd, NULL, NULL)) < 0) { fprintf(stderr, "accept(): %s\n", strerror(errno)); @@ -89,8 +89,8 @@ struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd) s->userdata = NULL; s->mainloop = m; - s->mainloop_source = m->source_io(m, fd, PA_MAINLOOP_API_IO_EVENT_INPUT, callback, s); - assert(s->mainloop_source); + s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s); + assert(s->io_event); s->type = SOCKET_SERVER_GENERIC; @@ -193,7 +193,7 @@ void pa_socket_server_free(struct pa_socket_server*s) { pa_xfree(s->filename); } - s->mainloop->cancel_io(s->mainloop, s->mainloop_source); + s->mainloop->io_free(s->io_event); pa_xfree(s); } diff --git a/polyp/xmalloc.h b/polyp/xmalloc.h index 5f58a8ad..45209b05 100644 --- a/polyp/xmalloc.h +++ b/polyp/xmalloc.h @@ -2,6 +2,7 @@ #define foomemoryhfoo #include +#include void* pa_xmalloc(size_t l); void *pa_xmalloc0(size_t l); -- cgit From 68eb5dd2486611d08d1d14e02ff1624ec27997c7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 6 Aug 2004 23:07:48 +0000 Subject: add mainloop test utility fix glib mainloop support git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@106 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 16 ++++-- polyp/glib-mainloop.c | 147 +++++++++++++++++++++++++------------------------- polyp/glib-mainloop.h | 11 +++- polyp/glib-test.c | 92 +++++++++++++++++++++++++++++++ polyp/mainloop-api.h | 8 +++ polyp/polyplib-def.h | 8 +++ polyp/polyplib.h | 8 +++ polyp/sample.h | 8 +++ 8 files changed, 221 insertions(+), 77 deletions(-) create mode 100644 polyp/glib-test.c diff --git a/polyp/Makefile.am b/polyp/Makefile.am index c0be8ce0..1be04f41 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -21,18 +21,21 @@ AM_CFLAGS=-ansi -D_GNU_SOURCE -DDLSEARCHDIR=\"$(pkglibdir)\" -I$(srcdir)/.. AM_LDADD=-L. AM_LIBADD=-L. +polypincludedir=$(includedir)/polyp + EXTRA_DIST = polypaudio.pa depmod.py bin_PROGRAMS = polypaudio pacat pactl -noinst_PROGRAMS = pacat-simple parec-simple +noinst_PROGRAMS = pacat-simple parec-simple glib-test -pkginclude_HEADERS=polyplib.h \ +polypinclude_HEADERS=polyplib.h \ polyplib-def.h \ polyplib-simple.h \ polyplib-error.h \ mainloop-api.h \ mainloop.h \ mainloop-signal.h \ - sample.h + sample.h \ + glib-mainloop.h pkglib_LTLIBRARIES=libiochannel.la \ libsocket-server.la \ @@ -312,9 +315,13 @@ libpolyp_mainloop_glib_la_SOURCES = glib-mainloop.h glib-mainloop.c libpolyp_mainloop_glib_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) libpolyp_mainloop_glib_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop.la $(GLIB20_LIBS) +glib_test_SOURCES = glib-test.c +glib_test_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) +glib_test_LDADD = $(AM_LDADD) $(GLIB20_LIBS) libpolyp.la libpolyp-mainloop-glib.la + if BUILD_LIBPOLYPCORE -pkginclude_HEADERS+=cli-command.h\ +polypinclude_HEADERS+=cli-command.h\ client.h \ core.h \ dynarray.h \ @@ -380,3 +387,4 @@ libpolypcore_la_SOURCES = idxset.c idxset.h \ dynarray.c dynarray.h endif + diff --git a/polyp/glib-mainloop.c b/polyp/glib-mainloop.c index 978cad07..3b9feaad 100644 --- a/polyp/glib-mainloop.c +++ b/polyp/glib-mainloop.c @@ -5,11 +5,12 @@ #include "xmalloc.h" struct pa_io_event { - GSource source; - int dead; struct pa_glib_mainloop *mainloop; + int dead; + GIOChannel *io_channel; + GSource *source; + GIOCondition io_condition; int fd; - GPollFD pollfd; void (*callback) (struct pa_mainloop_api*m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata); void *userdata; void (*destroy_callback) (struct pa_mainloop_api *m, struct pa_io_event*e, void *userdata); @@ -38,7 +39,7 @@ struct pa_defer_event { }; struct pa_glib_mainloop { - GMainLoop *glib_mainloop; + GMainContext *glib_main_context; struct pa_mainloop_api api; GSource *cleanup_source; struct pa_io_event *io_events, *dead_io_events; @@ -48,55 +49,16 @@ struct pa_glib_mainloop { static void schedule_free_dead_events(struct pa_glib_mainloop *g); -static gboolean glib_source_prepare(GSource *source, gint *timeout) { - return FALSE; -} - -static gboolean glib_source_check(GSource *source) { - struct pa_io_event *e = (struct pa_io_event*) source; - assert(e); - return !!e->pollfd.revents; -} - -static gboolean glib_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) { - struct pa_io_event *e = (struct pa_io_event*) source; - assert(e); - - if (e->pollfd.revents) { - int f = - (e->pollfd.revents ? G_IO_IN : PA_IO_EVENT_INPUT) | - (e->pollfd.revents ? G_IO_OUT : PA_IO_EVENT_OUTPUT) | - (e->pollfd.revents ? G_IO_HUP : PA_IO_EVENT_HANGUP) | - (e->pollfd.revents ? G_IO_ERR : PA_IO_EVENT_ERROR); - e->pollfd.revents = 0; - - assert(e->callback); - e->callback(&e->mainloop->api, e, e->fd, f, e->userdata); - } - - return TRUE; -} - static void glib_io_enable(struct pa_io_event*e, enum pa_io_event_flags f); static struct pa_io_event* glib_io_new(struct pa_mainloop_api*m, int fd, enum pa_io_event_flags f, void (*callback) (struct pa_mainloop_api*m, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata), void *userdata) { struct pa_io_event *e; struct pa_glib_mainloop *g; - GSourceFuncs io_source_funcs = { - prepare: glib_source_prepare, - check: glib_source_check, - dispatch: glib_source_dispatch, - finalize: NULL, - closure_callback: NULL, - closure_marshal : NULL, - }; - assert(m && m->userdata && fd >= 0 && callback); g = m->userdata; - e = (struct pa_io_event*) g_source_new(&io_source_funcs, sizeof(struct pa_io_event)); - assert(e); + e = pa_xmalloc(sizeof(struct pa_io_event)); e->mainloop = m->userdata; e->dead = 0; e->fd = fd; @@ -104,10 +66,10 @@ static struct pa_io_event* glib_io_new(struct pa_mainloop_api*m, int fd, enum pa e->userdata = userdata; e->destroy_callback = NULL; - e->pollfd.fd = fd; - e->pollfd.events = e->pollfd.revents = 0; - - g_source_attach(&e->source, g_main_loop_get_context(g->glib_mainloop)); + e->io_channel = g_io_channel_unix_new(e->fd); + assert(e->io_channel); + e->source = NULL; + e->io_condition = 0; glib_io_enable(e, f); @@ -119,23 +81,52 @@ static struct pa_io_event* glib_io_new(struct pa_mainloop_api*m, int fd, enum pa return e; } +static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { + struct pa_io_event *e = data; + enum pa_io_event_flags f; + assert(source && e && e->io_channel == source); + + f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | + (condition & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) | + (condition & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) | + (condition & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0); + + e->callback(&e->mainloop->api, e, e->fd, f, e->userdata); + return TRUE; +} + static void glib_io_enable(struct pa_io_event*e, enum pa_io_event_flags f) { - int o; + GIOCondition c; assert(e && !e->dead); - o = e->pollfd.events; - e->pollfd.events = (f & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | (f & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0) | G_IO_HUP | G_IO_ERR; - - if (!o && e->pollfd.events) - g_source_add_poll(&e->source, &e->pollfd); - else if (o && !e->pollfd.events) - g_source_remove_poll(&e->source, &e->pollfd); + c = (f & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | (f & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0); + + if (c == e->io_condition) + return; + + if (e->source) { + g_source_destroy(e->source); + g_source_unref(e->source); + } + + e->source = g_io_create_watch(e->io_channel, c | G_IO_ERR | G_IO_HUP); + assert(e->source); + + g_source_set_callback(e->source, (GSourceFunc) io_cb, e, NULL); + g_source_attach(e->source, e->mainloop->glib_main_context); + g_source_set_priority(e->source, G_PRIORITY_DEFAULT); + + e->io_condition = c; } static void glib_io_free(struct pa_io_event*e) { assert(e && !e->dead); - g_source_destroy(&e->source); + if (e->source) { + g_source_destroy(e->source); + g_source_unref(e->source); + e->source = NULL; + } if (e->prev) e->prev->next = e->next; @@ -235,7 +226,8 @@ static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv) e->source = g_timeout_source_new(msec_diff(tv, &now)); assert(e->source); g_source_set_callback(e->source, time_cb, e, NULL); - g_source_attach(e->source, g_main_loop_get_context(e->mainloop->glib_mainloop)); + g_source_set_priority(e->source, G_PRIORITY_HIGH); + g_source_attach(e->source, e->mainloop->glib_main_context); } else e->source = NULL; } @@ -319,7 +311,7 @@ static void glib_defer_enable(struct pa_defer_event *e, int b) { e->source = g_idle_source_new(); assert(e->source); g_source_set_callback(e->source, idle_cb, e, NULL); - g_source_attach(e->source, g_main_loop_get_context(e->mainloop->glib_mainloop)); + g_source_attach(e->source, e->mainloop->glib_main_context); g_source_set_priority(e->source, G_PRIORITY_HIGH_IDLE); } } @@ -362,8 +354,8 @@ static void glib_quit(struct pa_mainloop_api*a, int retval) { struct pa_glib_mainloop *g; assert(a && a->userdata); g = a->userdata; - - g_main_loop_quit(g->glib_mainloop); + + /* NOOP */ } static const struct pa_mainloop_api vtable = { @@ -387,12 +379,16 @@ static const struct pa_mainloop_api vtable = { quit : glib_quit, }; -struct pa_glib_mainloop *pa_glib_mainloop_new(GMainLoop *ml) { +struct pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) { struct pa_glib_mainloop *g; - assert(ml); g = pa_xmalloc(sizeof(struct pa_glib_mainloop)); - g->glib_mainloop = g_main_loop_ref(ml); + if (c) { + g->glib_main_context = c; + g_main_context_ref(c); + } else + g->glib_main_context = g_main_context_default(); + g->api = vtable; g->api.userdata = g; @@ -409,16 +405,18 @@ static void free_io_events(struct pa_io_event *e) { struct pa_io_event *r = e; e = r->next; - if (r->pollfd.events) - g_source_remove_poll(&r->source, &r->pollfd); + if (r->source) { + g_source_destroy(r->source); + g_source_unref(r->source); + } - if (!r->dead) - g_source_destroy(&r->source); + if (r->io_channel) + g_io_channel_unref(r->io_channel); if (r->destroy_callback) r->destroy_callback(&r->mainloop->api, r, r->userdata); - g_source_unref(&r->source); + pa_xfree(r); } } @@ -466,7 +464,12 @@ void pa_glib_mainloop_free(struct pa_glib_mainloop* g) { free_time_events(g->time_events); free_time_events(g->dead_time_events); - g_main_loop_unref(g->glib_mainloop); + if (g->cleanup_source) { + g_source_destroy(g->cleanup_source); + g_source_unref(g->cleanup_source); + } + + g_main_context_unref(g->glib_main_context); pa_xfree(g); } @@ -491,7 +494,7 @@ static gboolean free_dead_events(gpointer p) { } static void schedule_free_dead_events(struct pa_glib_mainloop *g) { - assert(g && g->glib_mainloop); + assert(g && g->glib_main_context); if (g->cleanup_source) return; @@ -499,5 +502,5 @@ static void schedule_free_dead_events(struct pa_glib_mainloop *g) { g->cleanup_source = g_idle_source_new(); assert(g->cleanup_source); g_source_set_callback(g->cleanup_source, free_dead_events, g, NULL); - g_source_attach(g->cleanup_source, g_main_loop_get_context(g->glib_mainloop)); + g_source_attach(g->cleanup_source, g->glib_main_context); } diff --git a/polyp/glib-mainloop.h b/polyp/glib-mainloop.h index 50fe8b9c..7655108a 100644 --- a/polyp/glib-mainloop.h +++ b/polyp/glib-mainloop.h @@ -5,10 +5,19 @@ #include "mainloop-api.h" +#ifdef __cplusplus +extern "C" { +#endif + struct pa_glib_mainloop; -struct pa_glib_mainloop *pa_glib_mainloop_new(GMainLoop *ml); +struct pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c); void pa_glib_mainloop_free(struct pa_glib_mainloop* g); struct pa_mainloop_api* pa_glib_mainloop_get_api(struct pa_glib_mainloop *g); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/polyp/glib-test.c b/polyp/glib-test.c new file mode 100644 index 00000000..99196c4a --- /dev/null +++ b/polyp/glib-test.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include + +/*#define GLIB_MAIN_LOOP*/ + +#ifdef GLIB_MAIN_LOOP +#include +#include "glib-mainloop.h" +static GMainLoop* glib_main_loop = NULL; +#else +#include "mainloop.h" +#endif + +static void iocb(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { + unsigned char c; + read(fd, &c, sizeof(c)); + fprintf(stderr, "IO EVENT: %c\n", c < 32 ? '.' : c); +} + +static void dcb(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata) { + fprintf(stderr, "DEFER EVENT\n"); + a->defer_enable(e, 0); +} + +static void tcb(struct pa_mainloop_api*a, struct pa_time_event *e, const struct timeval *tv, void *userdata) { + fprintf(stderr, "TIME EVENT\n"); + +#ifdef GLIB_MAIN_LOOP + g_main_loop_quit(glib_main_loop); +#else + a->quit(a, 0); +#endif +} + +int main(int argc, char *argv[]) { + struct pa_mainloop_api *a; + struct pa_io_event *ioe; + struct pa_defer_event *de; + struct pa_time_event *te; + struct timeval tv; + +#ifdef GLIB_MAIN_LOOP + struct pa_glib_mainloop *g; + glib_main_loop = g_main_loop_new(NULL, FALSE); + assert(glib_main_loop); + + g = pa_glib_mainloop_new(NULL); + assert(g); + + a = pa_glib_mainloop_get_api(g); + assert(a); +#else + struct pa_mainloop *m; + + m = pa_mainloop_new(); + assert(m); + + a = pa_mainloop_get_api(m); + assert(a); +#endif + + ioe = a->io_new(a, 0, PA_IO_EVENT_INPUT, iocb, NULL); + assert(ioe); + + de = a->defer_new(a, dcb, NULL); + assert(de); + + gettimeofday(&tv, NULL); + tv.tv_sec += 10; + te = a->time_new(a, &tv, tcb, NULL); + +#ifdef GLIB_MAIN_LOOP + g_main_loop_run(glib_main_loop); +#else + pa_mainloop_run(m, NULL); +#endif + + a->time_free(te); + a->defer_free(de); + a->io_free(ioe); + +#ifdef GLIB_MAIN_LOOP + pa_glib_mainloop_free(g); + g_main_loop_unref(glib_main_loop); +#else + pa_mainloop_free(m); +#endif + + return 0; +} diff --git a/polyp/mainloop-api.h b/polyp/mainloop-api.h index 4c8e379b..1b9e2783 100644 --- a/polyp/mainloop-api.h +++ b/polyp/mainloop-api.h @@ -25,6 +25,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + enum pa_io_event_flags { PA_IO_EVENT_NULL = 0, PA_IO_EVENT_INPUT = 1, @@ -64,4 +68,8 @@ struct pa_mainloop_api { void pa_mainloop_api_once(struct pa_mainloop_api*m, void (*callback)(struct pa_mainloop_api*m, void *userdata), void *userdata); +#ifdef __cplusplus +} +#endif + #endif diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index ec2d528b..e5c786f2 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -24,6 +24,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + enum pa_stream_direction { PA_STREAM_PLAYBACK, PA_STREAM_RECORD, @@ -38,4 +42,8 @@ struct pa_buffer_attr { uint32_t fragsize; }; +#ifdef __cplusplus +} +#endif + #endif diff --git a/polyp/polyplib.h b/polyp/polyplib.h index 08e6a5a5..9741fc93 100644 --- a/polyp/polyplib.h +++ b/polyp/polyplib.h @@ -28,6 +28,10 @@ #include "polyplib-def.h" #include "mainloop-api.h" +#ifdef __cplusplus +extern "C" { +#endif + struct pa_context; struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); @@ -127,4 +131,8 @@ void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void pa_context_get_source_info_by_id(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, void *userdata), void *userdata); void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, void *userdata), void *userdata); +#ifdef __cplusplus +} +#endif + #endif diff --git a/polyp/sample.h b/polyp/sample.h index 01a4efcf..25027879 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -25,6 +25,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + enum pa_sample_format { PA_SAMPLE_U8, PA_SAMPLE_ALAW, @@ -60,4 +64,8 @@ int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_s #define PA_SAMPLE_SNPRINT_MAX_LENGTH 32 void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec); +#ifdef __cplusplus +} +#endif + #endif -- cgit From 6f0936f6d0b4d415653c50760caaa65fa9bf78a3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 7 Aug 2004 10:42:39 +0000 Subject: cleanup priority management in main loop git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@107 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/glib-mainloop.c | 4 ++-- polyp/glib-test.c | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/polyp/glib-mainloop.c b/polyp/glib-mainloop.c index 3b9feaad..0c46ab0c 100644 --- a/polyp/glib-mainloop.c +++ b/polyp/glib-mainloop.c @@ -226,7 +226,7 @@ static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv) e->source = g_timeout_source_new(msec_diff(tv, &now)); assert(e->source); g_source_set_callback(e->source, time_cb, e, NULL); - g_source_set_priority(e->source, G_PRIORITY_HIGH); + g_source_set_priority(e->source, G_PRIORITY_DEFAULT); g_source_attach(e->source, e->mainloop->glib_main_context); } else e->source = NULL; @@ -312,7 +312,7 @@ static void glib_defer_enable(struct pa_defer_event *e, int b) { assert(e->source); g_source_set_callback(e->source, idle_cb, e, NULL); g_source_attach(e->source, e->mainloop->glib_main_context); - g_source_set_priority(e->source, G_PRIORITY_HIGH_IDLE); + g_source_set_priority(e->source, G_PRIORITY_HIGH); } } diff --git a/polyp/glib-test.c b/polyp/glib-test.c index 99196c4a..a03387e7 100644 --- a/polyp/glib-test.c +++ b/polyp/glib-test.c @@ -3,7 +3,7 @@ #include #include -/*#define GLIB_MAIN_LOOP*/ +#define GLIB_MAIN_LOOP #ifdef GLIB_MAIN_LOOP #include @@ -13,10 +13,13 @@ static GMainLoop* glib_main_loop = NULL; #include "mainloop.h" #endif +static struct pa_defer_event *de; + static void iocb(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { unsigned char c; read(fd, &c, sizeof(c)); fprintf(stderr, "IO EVENT: %c\n", c < 32 ? '.' : c); + a->defer_enable(de, 1); } static void dcb(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata) { @@ -37,7 +40,6 @@ static void tcb(struct pa_mainloop_api*a, struct pa_time_event *e, const struct int main(int argc, char *argv[]) { struct pa_mainloop_api *a; struct pa_io_event *ioe; - struct pa_defer_event *de; struct pa_time_event *te; struct timeval tv; -- cgit From 209c9dd88294be7aa9e7b552e69f98a5b0263aa8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 7 Aug 2004 10:43:33 +0000 Subject: rename mainloop testing tool git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@108 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/glib-test.c | 94 --------------------------------------------------- polyp/mainloop-test.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 94 deletions(-) delete mode 100644 polyp/glib-test.c create mode 100644 polyp/mainloop-test.c diff --git a/polyp/glib-test.c b/polyp/glib-test.c deleted file mode 100644 index a03387e7..00000000 --- a/polyp/glib-test.c +++ /dev/null @@ -1,94 +0,0 @@ -#include -#include -#include -#include - -#define GLIB_MAIN_LOOP - -#ifdef GLIB_MAIN_LOOP -#include -#include "glib-mainloop.h" -static GMainLoop* glib_main_loop = NULL; -#else -#include "mainloop.h" -#endif - -static struct pa_defer_event *de; - -static void iocb(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { - unsigned char c; - read(fd, &c, sizeof(c)); - fprintf(stderr, "IO EVENT: %c\n", c < 32 ? '.' : c); - a->defer_enable(de, 1); -} - -static void dcb(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata) { - fprintf(stderr, "DEFER EVENT\n"); - a->defer_enable(e, 0); -} - -static void tcb(struct pa_mainloop_api*a, struct pa_time_event *e, const struct timeval *tv, void *userdata) { - fprintf(stderr, "TIME EVENT\n"); - -#ifdef GLIB_MAIN_LOOP - g_main_loop_quit(glib_main_loop); -#else - a->quit(a, 0); -#endif -} - -int main(int argc, char *argv[]) { - struct pa_mainloop_api *a; - struct pa_io_event *ioe; - struct pa_time_event *te; - struct timeval tv; - -#ifdef GLIB_MAIN_LOOP - struct pa_glib_mainloop *g; - glib_main_loop = g_main_loop_new(NULL, FALSE); - assert(glib_main_loop); - - g = pa_glib_mainloop_new(NULL); - assert(g); - - a = pa_glib_mainloop_get_api(g); - assert(a); -#else - struct pa_mainloop *m; - - m = pa_mainloop_new(); - assert(m); - - a = pa_mainloop_get_api(m); - assert(a); -#endif - - ioe = a->io_new(a, 0, PA_IO_EVENT_INPUT, iocb, NULL); - assert(ioe); - - de = a->defer_new(a, dcb, NULL); - assert(de); - - gettimeofday(&tv, NULL); - tv.tv_sec += 10; - te = a->time_new(a, &tv, tcb, NULL); - -#ifdef GLIB_MAIN_LOOP - g_main_loop_run(glib_main_loop); -#else - pa_mainloop_run(m, NULL); -#endif - - a->time_free(te); - a->defer_free(de); - a->io_free(ioe); - -#ifdef GLIB_MAIN_LOOP - pa_glib_mainloop_free(g); - g_main_loop_unref(glib_main_loop); -#else - pa_mainloop_free(m); -#endif - - return 0; -} diff --git a/polyp/mainloop-test.c b/polyp/mainloop-test.c new file mode 100644 index 00000000..a03387e7 --- /dev/null +++ b/polyp/mainloop-test.c @@ -0,0 +1,94 @@ +#include +#include +#include +#include + +#define GLIB_MAIN_LOOP + +#ifdef GLIB_MAIN_LOOP +#include +#include "glib-mainloop.h" +static GMainLoop* glib_main_loop = NULL; +#else +#include "mainloop.h" +#endif + +static struct pa_defer_event *de; + +static void iocb(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { + unsigned char c; + read(fd, &c, sizeof(c)); + fprintf(stderr, "IO EVENT: %c\n", c < 32 ? '.' : c); + a->defer_enable(de, 1); +} + +static void dcb(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata) { + fprintf(stderr, "DEFER EVENT\n"); + a->defer_enable(e, 0); +} + +static void tcb(struct pa_mainloop_api*a, struct pa_time_event *e, const struct timeval *tv, void *userdata) { + fprintf(stderr, "TIME EVENT\n"); + +#ifdef GLIB_MAIN_LOOP + g_main_loop_quit(glib_main_loop); +#else + a->quit(a, 0); +#endif +} + +int main(int argc, char *argv[]) { + struct pa_mainloop_api *a; + struct pa_io_event *ioe; + struct pa_time_event *te; + struct timeval tv; + +#ifdef GLIB_MAIN_LOOP + struct pa_glib_mainloop *g; + glib_main_loop = g_main_loop_new(NULL, FALSE); + assert(glib_main_loop); + + g = pa_glib_mainloop_new(NULL); + assert(g); + + a = pa_glib_mainloop_get_api(g); + assert(a); +#else + struct pa_mainloop *m; + + m = pa_mainloop_new(); + assert(m); + + a = pa_mainloop_get_api(m); + assert(a); +#endif + + ioe = a->io_new(a, 0, PA_IO_EVENT_INPUT, iocb, NULL); + assert(ioe); + + de = a->defer_new(a, dcb, NULL); + assert(de); + + gettimeofday(&tv, NULL); + tv.tv_sec += 10; + te = a->time_new(a, &tv, tcb, NULL); + +#ifdef GLIB_MAIN_LOOP + g_main_loop_run(glib_main_loop); +#else + pa_mainloop_run(m, NULL); +#endif + + a->time_free(te); + a->defer_free(de); + a->io_free(ioe); + +#ifdef GLIB_MAIN_LOOP + pa_glib_mainloop_free(g); + g_main_loop_unref(glib_main_loop); +#else + pa_mainloop_free(m); +#endif + + return 0; +} -- cgit From e9bed206d22c6985bce66d09867dc1256b9fc2e6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 7 Aug 2004 10:52:43 +0000 Subject: better mainloop test build system git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@109 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 13 +++++++++---- polyp/mainloop-test.c | 2 -- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 1be04f41..b1c911a4 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -25,7 +25,7 @@ polypincludedir=$(includedir)/polyp EXTRA_DIST = polypaudio.pa depmod.py bin_PROGRAMS = polypaudio pacat pactl -noinst_PROGRAMS = pacat-simple parec-simple glib-test +noinst_PROGRAMS = pacat-simple parec-simple mainloop-test mainloop-test-glib polypinclude_HEADERS=polyplib.h \ polyplib-def.h \ @@ -287,6 +287,7 @@ libpolyp_mainloop_la_SOURCES = mainloop-api.h mainloop-api.c \ mainloop.c mainloop.h \ mainloop-signal.c mainloop-signal.h libpolyp_mainloop_la_CFLAGS = $(AM_CFLAGS) +libpolyp_mainloop_la_LIBADD = $(AM_LIBADD) libpolyp.la libpolyp_error_la_SOURCES = polyplib-error.c polyplib-error.h libpolyp_error_la_CFLAGS = $(AM_CFLAGS) @@ -315,9 +316,13 @@ libpolyp_mainloop_glib_la_SOURCES = glib-mainloop.h glib-mainloop.c libpolyp_mainloop_glib_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) libpolyp_mainloop_glib_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop.la $(GLIB20_LIBS) -glib_test_SOURCES = glib-test.c -glib_test_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) -glib_test_LDADD = $(AM_LDADD) $(GLIB20_LIBS) libpolyp.la libpolyp-mainloop-glib.la +mainloop_test_SOURCES = mainloop-test.c +mainloop_test_CFLAGS = $(AM_CFLAGS) +mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop.la + +mainloop_test_glib_SOURCES = $(mainloop_test_SOURCES) +mainloop_test_glib_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB20_CFLAGS) -DGLIB_MAIN_LOOP +mainloop_test_glib_LDADD = $(mainloop_test_LDADD) $(GLIB20_LIBS) libpolyp-mainloop-glib.la if BUILD_LIBPOLYPCORE diff --git a/polyp/mainloop-test.c b/polyp/mainloop-test.c index a03387e7..31caaa03 100644 --- a/polyp/mainloop-test.c +++ b/polyp/mainloop-test.c @@ -3,8 +3,6 @@ #include #include -#define GLIB_MAIN_LOOP - #ifdef GLIB_MAIN_LOOP #include #include "glib-mainloop.h" -- cgit From 37d930ac4afa9642b7b918b60ca0e0cb42b50682 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 10 Aug 2004 13:00:12 +0000 Subject: glib mainloop fix implement server status command support for sink_list/source_list in polyplib git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@110 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 4 +- polyp/clitext.c | 4 +- polyp/glib-mainloop.c | 12 ++- polyp/native-common.h | 2 + polyp/polypaudio.pa | 7 +- polyp/polyplib-error.h | 8 ++ polyp/polyplib.c | 195 +++++++++++++++++++++++++++++++++++++++++++++++- polyp/polyplib.h | 26 +++++-- polyp/protocol-native.c | 35 ++++++++- polyp/sink.c | 1 + polyp/tagstruct.c | 4 +- polyp/util.c | 47 +++++++++++- polyp/util.h | 3 + 13 files changed, 319 insertions(+), 29 deletions(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index b1c911a4..8206bcf6 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -18,8 +18,8 @@ # USA. AM_CFLAGS=-ansi -D_GNU_SOURCE -DDLSEARCHDIR=\"$(pkglibdir)\" -I$(srcdir)/.. -AM_LDADD=-L. -AM_LIBADD=-L. +AM_LDADD=-L. -lpthread +AM_LIBADD=-L. -lpthread polypincludedir=$(includedir)/polyp diff --git a/polyp/clitext.c b/polyp/clitext.c index 6d2d6253..a530238f 100644 --- a/polyp/clitext.c +++ b/polyp/clitext.c @@ -94,7 +94,7 @@ char *pa_sink_list_to_string(struct pa_core *c) { pa_strbuf_printf( s, " %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", - !strcmp(sink->name, c->default_sink_name) ? '*' : ' ', + c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ', sink->index, sink->name, (unsigned) sink->volume, pa_sink_get_latency(sink), @@ -125,7 +125,7 @@ char *pa_source_list_to_string(struct pa_core *c) { char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; pa_sample_snprint(ss, sizeof(ss), &source->sample_spec); pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\tsample_spec: <%s>\n", - !strcmp(source->name, c->default_source_name) ? '*' : ' ', + c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ', source->index, source->name, ss); diff --git a/polyp/glib-mainloop.c b/polyp/glib-mainloop.c index 0c46ab0c..9abb1e47 100644 --- a/polyp/glib-mainloop.c +++ b/polyp/glib-mainloop.c @@ -213,7 +213,7 @@ static gboolean time_cb(gpointer data) { static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv) { struct timeval now; - assert(e && e->mainloop); + assert(e && e->mainloop && !e->dead); gettimeofday(&now, NULL); if (e->source) { @@ -233,7 +233,7 @@ static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv) } static void glib_time_free(struct pa_time_event *e) { - assert(e && e->mainloop); + assert(e && e->mainloop && !e->dead); if (e->source) { g_source_destroy(e->source); @@ -317,8 +317,8 @@ static void glib_defer_enable(struct pa_defer_event *e, int b) { } static void glib_defer_free(struct pa_defer_event *e) { - assert(e && e->mainloop); - + assert(e && e->mainloop && !e->dead); + if (e->source) { g_source_destroy(e->source); g_source_unref(e->source); @@ -486,6 +486,10 @@ static gboolean free_dead_events(gpointer p) { free_defer_events(g->dead_defer_events); free_time_events(g->dead_time_events); + g->dead_io_events = NULL; + g->dead_defer_events = NULL; + g->dead_time_events = NULL; + g_source_destroy(g->cleanup_source); g_source_unref(g->cleanup_source); g->cleanup_source = NULL; diff --git a/polyp/native-common.h b/polyp/native-common.h index d8a2a5ab..4a74ac44 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -47,6 +47,8 @@ enum { PA_COMMAND_FINISH_UPLOAD_STREAM, PA_COMMAND_PLAY_SAMPLE, PA_COMMAND_REMOVE_SAMPLE, + + PA_COMMAND_GET_SERVER_INFO, PA_COMMAND_GET_SINK_INFO, PA_COMMAND_GET_SINK_INFO_LIST, diff --git a/polyp/polypaudio.pa b/polyp/polypaudio.pa index 71513565..8da20c62 100755 --- a/polyp/polypaudio.pa +++ b/polyp/polypaudio.pa @@ -23,14 +23,15 @@ #load module-alsa-sink #load module-alsa-source device=plughw:1,0 #load module-oss device="/dev/dsp" sink_name=output source_name=input -#load module-oss-mmap device="/dev/dsp" +load module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +load module-pipe-sink # Load audio drivers automatically on access #autoload_sink_add output module-oss device="/dev/dsp" sink_name=output source_name=input #autoload_source_add input module-oss device="/dev/dsp" sink_name=output source_name=input -autoload_sink_add output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -autoload_source_add input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#autoload_sink_add output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#autoload_source_add input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input #autoload_sink_add output module-alsa-sink sink_name=output #autoload_source_add input module-alsa-source source_name=input diff --git a/polyp/polyplib-error.h b/polyp/polyplib-error.h index cb86864a..d76ce6ff 100644 --- a/polyp/polyplib-error.h +++ b/polyp/polyplib-error.h @@ -24,6 +24,14 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + const char* pa_strerror(uint32_t error); +#ifdef __cplusplus +} +#endif + #endif diff --git a/polyp/polyplib.c b/polyp/polyplib.c index 4d87fdb5..e14f8cf9 100644 --- a/polyp/polyplib.c +++ b/polyp/polyplib.c @@ -88,7 +88,16 @@ struct pa_context { void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); void *remove_sample_userdata; - + + void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); + void *get_server_info_userdata; + + void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); + void *get_sink_info_userdata; + + void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); + void *get_source_info_userdata; + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; }; @@ -182,6 +191,15 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * c->remove_sample_callback = NULL; c->remove_sample_userdata = NULL; + c->get_server_info_callback = NULL; + c->get_server_info_userdata = NULL; + + c->get_sink_info_callback = NULL; + c->get_sink_info_userdata = NULL; + + c->get_source_info_callback = NULL; + c->get_source_info_userdata = NULL; + pa_check_for_sigpipe(); return c; } @@ -1055,12 +1073,12 @@ void pa_context_play_sample(struct pa_context *c, const char *name, const char * uint32_t tag; assert(c && name && *name && (!dev || *dev)); - if (!volume) - return; - c->play_sample_callback = cb; c->play_sample_userdata = userdata; + if (!cb) + return; + t = pa_tagstruct_new(NULL, 0); assert(t); pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); @@ -1106,6 +1124,9 @@ void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb) c->remove_sample_callback = cb; c->remove_sample_userdata = userdata; + if (!cb) + return; + t = pa_tagstruct_new(NULL, 0); assert(t); pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); @@ -1114,3 +1135,169 @@ void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb) pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); } + +static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + struct pa_server_info i; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_server_info_callback) + c->get_server_info_callback(c, NULL, c->get_server_info_userdata); + return; + } + + if (pa_tagstruct_gets(t, &i.server_name) < 0 || + pa_tagstruct_gets(t, &i.server_version) < 0 || + pa_tagstruct_gets(t, &i.user_name) < 0 || + pa_tagstruct_gets(t, &i.host_name) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_server_info_callback) + c->get_server_info_callback(c, &i, c->get_server_info_userdata); +} + +void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_server_info_callback = cb; + c->get_server_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); +} + +static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_sink_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.volume) < 0 || + pa_tagstruct_getu32(t, &i.monitor_source) < 0 || + pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || + pa_tagstruct_getu32(t, &i.latency) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); +} + +void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_sink_info_callback = cb; + c->get_sink_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); +} + +static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_source_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || + pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); +} + +void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_source_info_callback = cb; + c->get_source_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); +} diff --git a/polyp/polyplib.h b/polyp/polyplib.h index 9741fc93..cc1251e2 100644 --- a/polyp/polyplib.h +++ b/polyp/polyplib.h @@ -105,7 +105,7 @@ struct pa_sink_info { const char *name; uint32_t index; const char *description; - struct pa_sample_spec *sample_spec; + struct pa_sample_spec sample_spec; uint32_t owner_module; uint32_t volume; uint32_t monitor_source; @@ -113,24 +113,34 @@ struct pa_sink_info { uint32_t latency; }; -void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, void *userdata), void *userdata); -void pa_context_get_sink_info_by_id(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, void *userdata), void *userdata); -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, void *userdata), void *userdata); +void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_info_by_id(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); struct pa_source_info { const char *name; uint32_t index; const char *description; - struct pa_sample_spec *sample_spec; + struct pa_sample_spec sample_spec; uint32_t owner_module; uint32_t monitor_of_sink; const char *monitor_of_sink_name; }; -void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, void *userdata), void *userdata); -void pa_context_get_source_info_by_id(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, void *userdata), void *userdata); -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, void *userdata), void *userdata); +void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_info_by_id(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +struct pa_server_info { + const char *user_name; + const char *host_name; + const char *server_version; + const char *server_name; + struct pa_sample_spec sample_spec; +}; + +void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); + #ifdef __cplusplus } #endif diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 778677b3..abe6c8b7 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -42,6 +42,7 @@ #include "namereg.h" #include "scache.h" #include "xmalloc.h" +#include "util.h" struct connection; struct pa_protocol_native; @@ -129,6 +130,7 @@ static void command_play_sample(struct pa_pdispatch *pd, uint32_t command, uint3 static void command_remove_sample(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = { NULL }, @@ -156,6 +158,7 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_GET_SOURCE_INFO] = { command_get_info }, [PA_COMMAND_GET_SINK_INFO_LIST] = { command_get_info_list }, [PA_COMMAND_GET_SOURCE_INFO_LIST] = { command_get_info_list }, + [PA_COMMAND_GET_SERVER_INFO] = { command_get_server_info }, }; /* structure management */ @@ -933,7 +936,7 @@ static void sink_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink *sink) { assert(t && sink); pa_tagstruct_putu32(t, sink->index); pa_tagstruct_puts(t, sink->name); - pa_tagstruct_puts(t, sink->description); + pa_tagstruct_puts(t, sink->description ? sink->description : ""); pa_tagstruct_put_sample_spec(t, &sink->sample_spec); pa_tagstruct_putu32(t, sink->owner ? sink->owner->index : (uint32_t) -1); pa_tagstruct_putu32(t, sink->volume); @@ -946,7 +949,7 @@ static void source_fill_tagstruct(struct pa_tagstruct *t, struct pa_source *sour assert(t && source); pa_tagstruct_putu32(t, source->index); pa_tagstruct_puts(t, source->name); - pa_tagstruct_puts(t, source->description); + pa_tagstruct_puts(t, source->description ? source->description : ""); pa_tagstruct_put_sample_spec(t, &source->sample_spec); pa_tagstruct_putu32(t, source->owner ? source->owner->index : (uint32_t) -1); pa_tagstruct_putu32(t, source->monitor_of ? source->monitor_of->index : (uint32_t) -1); @@ -1045,6 +1048,34 @@ static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uin pa_pstream_send_tagstruct(c->pstream, reply); } +static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + struct pa_tagstruct *reply; + char txt[256]; + assert(c && t); + + if (!pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_puts(reply, PACKAGE_NAME); + pa_tagstruct_puts(reply, PACKAGE_VERSION); + pa_tagstruct_puts(reply, pa_get_user_name(txt, sizeof(txt))); + pa_tagstruct_puts(reply, pa_get_host_name(txt, sizeof(txt))); + pa_tagstruct_put_sample_spec(reply, &c->protocol->core->default_sample_spec); + pa_pstream_send_tagstruct(c->pstream, reply); +} + /*** pstream callbacks ***/ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { diff --git a/polyp/sink.c b/polyp/sink.c index 6df92e76..9628d8bd 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -64,6 +64,7 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co assert(s->monitor_source); pa_xfree(n); s->monitor_source->monitor_of = s; + s->monitor_source->description = pa_sprintf_malloc("Monitor source of sink '%s'", s->name); s->volume = PA_VOLUME_NORM; diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c index cb93a9c4..9578a9eb 100644 --- a/polyp/tagstruct.c +++ b/polyp/tagstruct.c @@ -83,10 +83,10 @@ uint8_t* pa_tagstruct_free_data(struct pa_tagstruct*t, size_t *l) { static void extend(struct pa_tagstruct*t, size_t l) { assert(t && t->dynamic); - if (l <= t->allocated) + if (t->length+l <= t->allocated) return; - t->data = pa_xrealloc(t->data, t->allocated = l+100); + t->data = pa_xrealloc(t->data, t->allocated = t->length+l+100); } void pa_tagstruct_puts(struct pa_tagstruct*t, const char *s) { diff --git a/polyp/util.c b/polyp/util.c index 98d91075..70766a06 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -33,6 +33,9 @@ #include #include #include +#include +#include +#include #include "util.h" #include "xmalloc.h" @@ -109,14 +112,27 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size) { void pa_check_for_sigpipe(void) { struct sigaction sa; + sigset_t set; + + if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) { + if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) { + fprintf(stderr, __FILE__": sigprocmask() failed: %s\n", strerror(errno)); + return; + } + } + if (sigismember(&set, SIGPIPE)) + return; + if (sigaction(SIGPIPE, NULL, &sa) < 0) { fprintf(stderr, __FILE__": sigaction() failed: %s\n", strerror(errno)); return; } - if (sa.sa_handler == SIG_DFL) - fprintf(stderr, "polypaudio: WARNING: SIGPIPE is not trapped. This might cause malfunction!\n"); + if (sa.sa_handler != SIG_DFL) + return; + + fprintf(stderr, "polypaudio: WARNING: SIGPIPE is not trapped. This might cause malfunction!\n"); } /* The following is based on an example from the GNU libc documentation */ @@ -145,3 +161,30 @@ char *pa_sprintf_malloc(const char *format, ...) { size *= 2; } } + +char *pa_get_user_name(char *s, size_t l) { + struct passwd pw, *r; + char buf[1024]; + char *p; + + if (!(p = getenv("USER"))) + if (!(p = getenv("LOGNAME"))) + if (!(p = getenv("USERNAME"))) { + + if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { + snprintf(s, l, "%lu", (unsigned long) getuid()); + return s; + } + + p = r->pw_name; + } + + snprintf(s, l, "%s", p); + return s; +} + +char *pa_get_host_name(char *s, size_t l) { + gethostname(s, l); + s[l-1] = 0; + return s; +} diff --git a/polyp/util.h b/polyp/util.h index 96fde11c..7dd7b7de 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -35,4 +35,7 @@ void pa_check_for_sigpipe(void); char *pa_sprintf_malloc(const char *format, ...) __attribute__ ((format (printf, 1, 2))); +char *pa_get_user_name(char *s, size_t l); +char *pa_get_host_name(char *s, size_t l); + #endif -- cgit From fc618e9f316a1ec2b48a7981db41a121c79f0c27 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 10 Aug 2004 15:11:37 +0000 Subject: compile fix git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@111 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 8206bcf6..254af28a 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -291,6 +291,7 @@ libpolyp_mainloop_la_LIBADD = $(AM_LIBADD) libpolyp.la libpolyp_error_la_SOURCES = polyplib-error.c polyplib-error.h libpolyp_error_la_CFLAGS = $(AM_CFLAGS) +libpolyp_error_la_LIBADD = $(AM_LIBADD) libpolyp.la libpolyp_simple_la_SOURCES = polyplib-simple.c polyplib-simple.h libpolyp_simple_la_CFLAGS = $(AM_CFLAGS) @@ -305,11 +306,11 @@ pactl_LDADD = $(AM_LDADD) libpolyp.la libpolyp-error.la libpolyp-mainloop.la $(L pactl_CFLAGS = $(AM_CFLAGS) $(LIBSDNFILE_CFLAGS) pacat_simple_SOURCES = pacat-simple.c -pacat_simple_LDADD = $(AM_LDADD) libpolyp-simple.la libpolyp-error.la +pacat_simple_LDADD = $(AM_LDADD) libpolyp.la libpolyp-simple.la libpolyp-error.la pacat_simple_CFLAGS = $(AM_CFLAGS) parec_simple_SOURCES = parec-simple.c -parec_simple_LDADD = $(AM_LDADD) libpolyp-simple.la libpolyp-error.la +parec_simple_LDADD = $(AM_LDADD) libpolyp.la libpolyp-simple.la libpolyp-error.la parec_simple_CFLAGS = $(AM_CFLAGS) libpolyp_mainloop_glib_la_SOURCES = glib-mainloop.h glib-mainloop.c @@ -318,7 +319,7 @@ libpolyp_mainloop_glib_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop.la $(GLIB20_LI mainloop_test_SOURCES = mainloop-test.c mainloop_test_CFLAGS = $(AM_CFLAGS) -mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop.la +mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop.la libpolyp.la mainloop_test_glib_SOURCES = $(mainloop_test_SOURCES) mainloop_test_glib_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB20_CFLAGS) -DGLIB_MAIN_LOOP -- cgit From 3d374e9f678133638e661cadf73d4ef7ddcfe6eb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 11 Aug 2004 00:11:12 +0000 Subject: add subscription subsystem git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@112 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 3 +- polyp/client.c | 3 + polyp/core.c | 8 ++- polyp/core.h | 4 ++ polyp/module.c | 5 ++ polyp/sink-input.c | 5 ++ polyp/sink.c | 5 ++ polyp/source-output.c | 5 ++ polyp/source.c | 5 ++ polyp/subscribe.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++ polyp/subscribe.h | 43 ++++++++++++++ 11 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 polyp/subscribe.c create mode 100644 polyp/subscribe.h diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 254af28a..ce753da4 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -115,7 +115,8 @@ polypaudio_SOURCES = idxset.c idxset.h \ sound-file.c sound-file.h \ play-memchunk.c play-memchunk.h \ autoload.c autoload.h \ - xmalloc.c xmalloc.h + xmalloc.c xmalloc.h \ + subscribe.h subscribe.c polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) diff --git a/polyp/client.c b/polyp/client.c index 83a6264d..809f9761 100644 --- a/polyp/client.c +++ b/polyp/client.c @@ -30,6 +30,7 @@ #include "client.h" #include "xmalloc.h" +#include "subscribe.h" struct pa_client *pa_client_new(struct pa_core *core, const char *protocol_name, char *name) { struct pa_client *c; @@ -49,6 +50,7 @@ struct pa_client *pa_client_new(struct pa_core *core, const char *protocol_name, assert(c->index != PA_IDXSET_INVALID && r >= 0); fprintf(stderr, "client: created %u \"%s\"\n", c->index, c->name); + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index); return c; } @@ -58,6 +60,7 @@ void pa_client_free(struct pa_client *c) { pa_idxset_remove_by_data(c->core->clients, c, NULL); fprintf(stderr, "client: freed %u \"%s\"\n", c->index, c->name); + pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index); pa_xfree(c->name); pa_xfree(c); } diff --git a/polyp/core.c b/polyp/core.c index 0444fa96..55944aad 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -36,6 +36,7 @@ #include "scache.h" #include "autoload.h" #include "xmalloc.h" +#include "subscribe.h" struct pa_core* pa_core_new(struct pa_mainloop_api *m) { struct pa_core* c; @@ -63,6 +64,10 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->auto_unload_time = 20; c->auto_unload_event = NULL; + + c->subscription_defer_event = NULL; + c->subscription_event_queue = NULL; + c->subscriptions = NULL; pa_check_for_sigpipe(); @@ -93,7 +98,8 @@ void pa_core_free(struct pa_core *c) { pa_namereg_free(c); pa_scache_free(c); pa_autoload_free(c); - + pa_subscription_free_all(c); + pa_xfree(c->default_source_name); pa_xfree(c->default_sink_name); diff --git a/polyp/core.h b/polyp/core.h index e1e48cbc..43691771 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -39,6 +39,10 @@ struct pa_core { struct pa_sample_spec default_sample_spec; int auto_unload_time; struct pa_time_event *auto_unload_event; + + struct pa_defer_event *subscription_defer_event; + struct pa_queue *subscription_event_queue; + struct pa_subscription *subscriptions; }; struct pa_core* pa_core_new(struct pa_mainloop_api *m); diff --git a/polyp/module.c b/polyp/module.c index 83bfa800..849afca4 100644 --- a/polyp/module.c +++ b/polyp/module.c @@ -32,6 +32,7 @@ #include "module.h" #include "xmalloc.h" +#include "subscribe.h" #define UNLOAD_POLL_TIME 10 @@ -92,6 +93,8 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char assert(r >= 0 && m->index != PA_IDXSET_INVALID); fprintf(stderr, "module: loaded %u \"%s\" with argument \"%s\".\n", m->index, m->name, m->argument); + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_NEW, m->index); return m; @@ -117,6 +120,8 @@ static void pa_module_free(struct pa_module *m) { fprintf(stderr, "module: unloaded %u \"%s\".\n", m->index, m->name); + pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_REMOVE, m->index); + pa_xfree(m->name); pa_xfree(m->argument); pa_xfree(m); diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 04a2f020..dd7469e0 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -31,6 +31,7 @@ #include "sink-input.h" #include "sample-util.h" #include "xmalloc.h" +#include "subscribe.h" #define CONVERT_BUFFER_LENGTH 4096 @@ -72,6 +73,8 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con pa_sample_snprint(st, sizeof(st), spec); fprintf(stderr, "sink-input: created %u \"%s\" on %u with sample spec \"%s\"\n", i->index, i->name, s->index, st); + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index); return i; } @@ -87,6 +90,8 @@ void pa_sink_input_free(struct pa_sink_input* i) { pa_memblock_unref(i->resampled_chunk.memblock); if (i->resampler) pa_resampler_free(i->resampler); + + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index); pa_xfree(i->name); pa_xfree(i); diff --git a/polyp/sink.c b/polyp/sink.c index 9628d8bd..7e0e15cd 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -34,6 +34,7 @@ #include "util.h" #include "sample-util.h" #include "xmalloc.h" +#include "subscribe.h" #define MAX_MIX_CHANNELS 32 @@ -77,6 +78,8 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co pa_sample_snprint(st, sizeof(st), spec); fprintf(stderr, "sink: created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); + + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index); return s; } @@ -98,6 +101,8 @@ void pa_sink_free(struct pa_sink *s) { pa_idxset_remove_by_data(s->core->sinks, s, NULL); fprintf(stderr, "sink: freed %u \"%s\"\n", s->index, s->name); + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); pa_xfree(s->name); pa_xfree(s->description); diff --git a/polyp/source-output.c b/polyp/source-output.c index 07901fa8..c53831c7 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -29,6 +29,7 @@ #include "source-output.h" #include "xmalloc.h" +#include "subscribe.h" struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec) { struct pa_source_output *o; @@ -57,6 +58,8 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n assert(r == 0 && o->index != PA_IDXSET_INVALID); r = pa_idxset_put(s->outputs, o, NULL); assert(r == 0); + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); return o; } @@ -70,6 +73,8 @@ void pa_source_output_free(struct pa_source_output* o) { if (o->resampler) pa_resampler_free(o->resampler); + + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); pa_xfree(o->name); pa_xfree(o); diff --git a/polyp/source.c b/polyp/source.c index 65c90e9a..2c611651 100644 --- a/polyp/source.c +++ b/polyp/source.c @@ -32,6 +32,7 @@ #include "source-output.h" #include "namereg.h" #include "xmalloc.h" +#include "subscribe.h" struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec) { struct pa_source *s; @@ -63,6 +64,8 @@ struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail pa_sample_snprint(st, sizeof(st), spec); fprintf(stderr, "source: created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); + + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index); return s; } @@ -84,6 +87,8 @@ void pa_source_free(struct pa_source *s) { fprintf(stderr, "source: freed %u \"%s\"\n", s->index, s->name); + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); + pa_xfree(s->name); pa_xfree(s->description); pa_xfree(s); diff --git a/polyp/subscribe.c b/polyp/subscribe.c new file mode 100644 index 00000000..541657ae --- /dev/null +++ b/polyp/subscribe.c @@ -0,0 +1,152 @@ +#include +#include + +#include "queue.h" +#include "subscribe.h" +#include "xmalloc.h" + +struct pa_subscription { + struct pa_core *core; + int dead; + void (*callback)(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); + void *userdata; + enum pa_subscription_mask mask; + + struct pa_subscription *prev, *next; +}; + +struct pa_subscription_event { + enum pa_subscription_event_type type; + uint32_t index; +}; + +static void sched_event(struct pa_core *c); + +struct pa_subscription* pa_subscription_new(struct pa_core *c, enum pa_subscription_mask m, void (*callback)(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { + struct pa_subscription *s; + assert(c); + + s = pa_xmalloc(sizeof(struct pa_subscription)); + s->core = c; + s->dead = 0; + s->callback = callback; + s->userdata = userdata; + s->mask = m; + + if ((s->next = c->subscriptions)) + s->next->prev = s; + s->prev = NULL; + c->subscriptions = s; + return NULL; +} + +void pa_subscription_free(struct pa_subscription*s) { + assert(s && !s->dead); + s->dead = 1; + sched_event(s->core); +} + +static void free_item(struct pa_subscription *s) { + assert(s && s->core); + + if (s->prev) + s->prev->next = s->next; + else + s->core->subscriptions = s->next; + + if (s->next) + s->next->prev = s->prev; + + pa_xfree(s); +} + +void pa_subscription_free_all(struct pa_core *c) { + struct pa_subscription_event *e; + assert(c); + + while (c->subscriptions) + free_item(c->subscriptions); + + if (c->subscription_event_queue) { + while ((e = pa_queue_pop(c->subscription_event_queue))) + pa_xfree(e); + + pa_queue_free(c->subscription_event_queue, NULL, NULL); + c->subscription_event_queue = NULL; + } + + if (c->subscription_defer_event) { + c->mainloop->defer_free(c->subscription_defer_event); + c->subscription_defer_event = NULL; + } +} + +static void defer_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) { + struct pa_core *c = userdata; + struct pa_subscription *s; + assert(c && c->subscription_defer_event == e && c->mainloop == m); + + c->mainloop->defer_enable(c->subscription_defer_event, 0); + + + /* Dispatch queued events */ + + if (c->subscription_event_queue) { + struct pa_subscription_event *e; + + while ((e = pa_queue_pop(c->subscription_event_queue))) { + struct pa_subscription *s; + + for (s = c->subscriptions; s; s = s->next) { + if (!s->dead && pa_subscription_match_flags(s->mask, e->type)) + s->callback(c, e->type, e->index, s->userdata); + } + + pa_xfree(e); + } + } + + /* Remove dead subscriptions */ + + s = c->subscriptions; + while (s) { + struct pa_subscription *n = s->next; + if (s->dead) + free_item(s); + s = n; + } +} + +static void sched_event(struct pa_core *c) { + assert(c); + + if (!c->subscription_defer_event) { + c->subscription_defer_event = c->mainloop->defer_new(c->mainloop, defer_cb, c); + assert(c->subscription_defer_event); + } + + c->mainloop->defer_enable(c->subscription_defer_event, 1); +} + + +void pa_subscription_post(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index) { + struct pa_subscription_event *e; + assert(c); + + e = pa_xmalloc(sizeof(struct pa_subscription_event)); + e->type = t; + e->index = index; + + if (!c->subscription_event_queue) { + c->subscription_event_queue = pa_queue_new(); + assert(c->subscription_event_queue); + } + + pa_queue_push(c->subscription_event_queue, e); + sched_event(c); +} + + +int pa_subscription_match_flags(enum pa_subscription_mask m, enum pa_subscription_event_type t) { + return !!(m & (1 >> (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK))); +} diff --git a/polyp/subscribe.h b/polyp/subscribe.h new file mode 100644 index 00000000..1561249f --- /dev/null +++ b/polyp/subscribe.h @@ -0,0 +1,43 @@ +#ifndef foosubscribehfoo +#define foosubscribehfoo + +#include "core.h" + +enum pa_subscription_mask { + PA_SUBSCRIPTION_FACILITY_SINK = 1, + PA_SUBSCRIPTION_FACILITY_SOURCE = 2, + PA_SUBSCRIPTION_FACILITY_SINK_INPUT = 4, + PA_SUBSCRIPTION_FACILITY_SOURCE_OUTPUT = 8, + PA_SUBSCRIPTION_FACILITY_MODULE = 16, + PA_SUBSCRIPTION_FACILITY_CLIENT = 32, + PA_SUBSCRIPTION_FACILITY_SAMPLE_CACHE = 64, +}; + +enum pa_subscription_event_type { + PA_SUBSCRIPTION_EVENT_SINK = 0, + PA_SUBSCRIPTION_EVENT_SOURCE = 1, + PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2, + PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 3, + PA_SUBSCRIPTION_EVENT_MODULE = 4, + PA_SUBSCRIPTION_EVENT_CLIENT = 5, + PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, + PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 7, + + PA_SUBSCRIPTION_EVENT_NEW = 0, + PA_SUBSCRIPTION_EVENT_CHANGE = 16, + PA_SUBSCRIPTION_EVENT_REMOVE = 32, + PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32, +}; + +struct pa_subscription; +struct pa_subscription_event; + +struct pa_subscription* pa_subscription_new(struct pa_core *c, enum pa_subscription_mask m, void (*callback)(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); +void pa_subscription_free(struct pa_subscription*s); +void pa_subscription_free_all(struct pa_core *c); + +void pa_subscription_post(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index); + +int pa_subscription_match_flags(enum pa_subscription_mask m, enum pa_subscription_event_type e); + +#endif -- cgit From b297d0b59a7d44f14073daf96a6206763a0c307b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 11 Aug 2004 00:12:04 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@113 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/todo b/doc/todo index 7cf36b08..276cccfc 100644 --- a/doc/todo +++ b/doc/todo @@ -4,6 +4,7 @@ - future cancellation - make mcalign merge chunks +- ref counting foo - doxygen -- cgit From cbfaf40b45f712c1cdcc6b7cb694f907ce0e7f8f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 11 Aug 2004 15:11:26 +0000 Subject: info and subscription work git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@114 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/native-common.h | 28 ++++++++++++++++ polyp/polypaudio.pa | 8 ++--- polyp/polyplib-def.h | 4 ++- polyp/polyplib.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ polyp/polyplib.h | 8 +++-- polyp/protocol-native.c | 52 ++++++++++++++++++++++++++++++ polyp/scache.c | 7 ++++ polyp/scache.h | 1 + polyp/subscribe.c | 51 ++++++++++++++++++++++++++--- polyp/subscribe.h | 29 +---------------- 10 files changed, 232 insertions(+), 41 deletions(-) diff --git a/polyp/native-common.h b/polyp/native-common.h index 4a74ac44..5e69c805 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -87,4 +87,32 @@ enum { #define PA_NATIVE_COOKIE_LENGTH 256 #define PA_NATIVE_COOKIE_FILE ".polypaudio-cookie" +enum pa_subscription_mask { + PA_SUBSCRIPTION_FACILITY_SINK = 1, + PA_SUBSCRIPTION_FACILITY_SOURCE = 2, + PA_SUBSCRIPTION_FACILITY_SINK_INPUT = 4, + PA_SUBSCRIPTION_FACILITY_SOURCE_OUTPUT = 8, + PA_SUBSCRIPTION_FACILITY_MODULE = 16, + PA_SUBSCRIPTION_FACILITY_CLIENT = 32, + PA_SUBSCRIPTION_FACILITY_SAMPLE_CACHE = 64, +}; + +enum pa_subscription_event_type { + PA_SUBSCRIPTION_EVENT_SINK = 0, + PA_SUBSCRIPTION_EVENT_SOURCE = 1, + PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2, + PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 3, + PA_SUBSCRIPTION_EVENT_MODULE = 4, + PA_SUBSCRIPTION_EVENT_CLIENT = 5, + PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, + PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 7, + + PA_SUBSCRIPTION_EVENT_NEW = 0, + PA_SUBSCRIPTION_EVENT_CHANGE = 16, + PA_SUBSCRIPTION_EVENT_REMOVE = 32, + PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32, +}; + +#define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) + #endif diff --git a/polyp/polypaudio.pa b/polyp/polypaudio.pa index 8da20c62..d57f8127 100755 --- a/polyp/polypaudio.pa +++ b/polyp/polypaudio.pa @@ -23,8 +23,8 @@ #load module-alsa-sink #load module-alsa-source device=plughw:1,0 #load module-oss device="/dev/dsp" sink_name=output source_name=input -load module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -load module-pipe-sink +#load module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#load module-pipe-sink # Load audio drivers automatically on access @@ -32,8 +32,8 @@ load module-pipe-sink #autoload_source_add input module-oss device="/dev/dsp" sink_name=output source_name=input #autoload_sink_add output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input #autoload_source_add input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#autoload_sink_add output module-alsa-sink sink_name=output -#autoload_source_add input module-alsa-source source_name=input +autoload_sink_add output module-alsa-sink sink_name=output +autoload_source_add input module-alsa-source source_name=input # Load several protocols load module-esound-protocol-tcp diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index e5c786f2..d96c6899 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -28,6 +28,8 @@ extern "C" { #endif +#include "native-common.h" + enum pa_stream_direction { PA_STREAM_PLAYBACK, PA_STREAM_RECORD, @@ -41,7 +43,7 @@ struct pa_buffer_attr { uint32_t minreq; uint32_t fragsize; }; - + #ifdef __cplusplus } #endif diff --git a/polyp/polyplib.c b/polyp/polyplib.c index e14f8cf9..b77d24ea 100644 --- a/polyp/polyplib.c +++ b/polyp/polyplib.c @@ -98,6 +98,10 @@ struct pa_context { void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); void *get_source_info_userdata; + void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); + void *subscribe_userdata; + enum pa_subscription_mask subscribe_mask; + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; }; @@ -140,6 +144,7 @@ struct pa_stream { static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = { NULL }, @@ -152,6 +157,7 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_REQUEST] = { command_request }, [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, + [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, }; struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { @@ -200,6 +206,9 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * c->get_source_info_callback = NULL; c->get_source_info_userdata = NULL; + c->subscribe_callback = NULL; + c->subscribe_userdata = NULL; + pa_check_for_sigpipe(); return c; } @@ -1301,3 +1310,79 @@ void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_ pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); } + +void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { + struct pa_tagstruct *t; + assert(c); + + c->subscribe_callback = cb; + c->subscribe_userdata = userdata; + c->subscribe_mask = m; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); + pa_tagstruct_putu32(t, c->ctag++); + pa_tagstruct_putu32(t, cb ? m : 0); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + enum pa_subscription_event_type e; + uint32_t index; + assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); + + if (pa_tagstruct_getu32(t, &e) < 0 || + pa_tagstruct_getu32(t, &index) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) + c->subscribe_callback(c, e, index, c->subscribe_userdata); +} + +void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_sink_info_callback = cb; + c->get_sink_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); +} + +void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_source_info_callback = cb; + c->get_source_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); +} diff --git a/polyp/polyplib.h b/polyp/polyplib.h index cc1251e2..8708cd72 100644 --- a/polyp/polyplib.h +++ b/polyp/polyplib.h @@ -114,7 +114,7 @@ struct pa_sink_info { }; void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_by_id(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); struct pa_source_info { @@ -128,7 +128,7 @@ struct pa_source_info { }; void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_by_id(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); struct pa_server_info { @@ -140,7 +140,9 @@ struct pa_server_info { }; void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); - + +void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); + #ifdef __cplusplus } #endif diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index abe6c8b7..caaa1396 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -43,6 +43,7 @@ #include "scache.h" #include "xmalloc.h" #include "util.h" +#include "subscribe.h" struct connection; struct pa_protocol_native; @@ -93,6 +94,7 @@ struct connection { struct pa_pdispatch *pdispatch; struct pa_idxset *record_streams, *output_streams; uint32_t rrobin_index; + struct pa_subscription *subscription; }; struct pa_protocol_native { @@ -131,6 +133,7 @@ static void command_remove_sample(struct pa_pdispatch *pd, uint32_t command, uin static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_subscribe(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = { NULL }, @@ -159,6 +162,7 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_GET_SINK_INFO_LIST] = { command_get_info_list }, [PA_COMMAND_GET_SOURCE_INFO_LIST] = { command_get_info_list }, [PA_COMMAND_GET_SERVER_INFO] = { command_get_server_info }, + [PA_COMMAND_SUBSCRIBE] = { command_subscribe }, }; /* structure management */ @@ -301,6 +305,10 @@ static void connection_free(struct connection *c) { pa_pdispatch_free(c->pdispatch); pa_pstream_free(c->pstream); pa_client_free(c->client); + + if (c->subscription) + pa_subscription_free(c->subscription); + pa_xfree(c); } @@ -1076,6 +1084,49 @@ static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, u pa_pstream_send_tagstruct(c->pstream, reply); } +static void subscription_cb(struct pa_core *core, enum pa_subscription_event_type e, uint32_t index, void *userdata) { + struct pa_tagstruct *t; + struct connection *c = userdata; + assert(c && core); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_putu32(t, e); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void command_subscribe(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + enum pa_subscription_mask m; + assert(c && t); + + if (pa_tagstruct_getu32(t, &m) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (c->subscription) + pa_subscription_free(c->subscription); + + if (m != 0) { + c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c); + assert(c->subscription); + } else + c->subscription = NULL; + + pa_pstream_send_simple_ack(c->pstream, tag); + +} + /*** pstream callbacks ***/ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { @@ -1197,6 +1248,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo assert(c->record_streams && c->output_streams); c->rrobin_index = PA_IDXSET_INVALID; + c->subscription = NULL; pa_idxset_put(p->connections, c, NULL); } diff --git a/polyp/scache.c b/polyp/scache.c index fd7b74e5..9485a2b6 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -9,9 +9,11 @@ #include "sample-util.h" #include "play-memchunk.h" #include "xmalloc.h" +#include "subscribe.h" static void free_entry(struct pa_scache_entry *e) { assert(e); + pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_REMOVE, e->index); pa_xfree(e->name); if (e->memchunk.memblock) pa_memblock_unref(e->memchunk.memblock); @@ -27,10 +29,12 @@ void pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_sp put = 0; if (e->memchunk.memblock) pa_memblock_unref(e->memchunk.memblock); + assert(e->core == c); } else { put = 1; e = pa_xmalloc(sizeof(struct pa_scache_entry)); e->name = pa_xstrdup(name); + e->core = c; } e->volume = 0x100; @@ -61,6 +65,8 @@ void pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_sp pa_idxset_put(c->scache_idxset, e, &e->index); pa_hashmap_put(c->scache_hashmap, e->name, e); + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_NEW, e->index); } if (index) @@ -77,6 +83,7 @@ int pa_scache_remove_item(struct pa_core *c, const char *name) { pa_hashmap_remove(c->scache_hashmap, name); if (pa_idxset_remove_by_data(c->scache_idxset, e, NULL) != e) assert(0); + free_entry(e); return 0; } diff --git a/polyp/scache.h b/polyp/scache.h index a1454cea..15cd5d48 100644 --- a/polyp/scache.h +++ b/polyp/scache.h @@ -6,6 +6,7 @@ #include "sink.h" struct pa_scache_entry { + struct pa_core *core; uint32_t index; char *name; uint32_t volume; diff --git a/polyp/subscribe.c b/polyp/subscribe.c index 541657ae..104566d1 100644 --- a/polyp/subscribe.c +++ b/polyp/subscribe.c @@ -37,7 +37,7 @@ struct pa_subscription* pa_subscription_new(struct pa_core *c, enum pa_subscript s->next->prev = s; s->prev = NULL; c->subscriptions = s; - return NULL; + return s; } void pa_subscription_free(struct pa_subscription*s) { @@ -81,6 +81,49 @@ void pa_subscription_free_all(struct pa_core *c) { } } +/*static void dump_event(struct pa_subscription_event*e) { + switch (e->type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { + case PA_SUBSCRIPTION_EVENT_SINK: + fprintf(stderr, "SINK_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_SOURCE: + fprintf(stderr, "SOURCE_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_SINK_INPUT: + fprintf(stderr, "SINK_INPUT_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: + fprintf(stderr, "SOURCE_OUTPUT_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_MODULE: + fprintf(stderr, "MODULE_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_CLIENT: + fprintf(stderr, "CLIENT_EVENT"); + break; + default: + fprintf(stderr, "OTHER"); + break; + } + + switch (e->type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) { + case PA_SUBSCRIPTION_EVENT_NEW: + fprintf(stderr, " NEW"); + break; + case PA_SUBSCRIPTION_EVENT_CHANGE: + fprintf(stderr, " CHANGE"); + break; + case PA_SUBSCRIPTION_EVENT_REMOVE: + fprintf(stderr, " REMOVE"); + break; + default: + fprintf(stderr, " OTHER"); + break; + } + + fprintf(stderr, " %u\n", e->index); +}*/ + static void defer_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) { struct pa_core *c = userdata; struct pa_subscription *s; @@ -98,6 +141,7 @@ static void defer_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void * struct pa_subscription *s; for (s = c->subscriptions; s; s = s->next) { + if (!s->dead && pa_subscription_match_flags(s->mask, e->type)) s->callback(c, e->type, e->index, s->userdata); } @@ -119,7 +163,7 @@ static void defer_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void * static void sched_event(struct pa_core *c) { assert(c); - + if (!c->subscription_defer_event) { c->subscription_defer_event = c->mainloop->defer_new(c->mainloop, defer_cb, c); assert(c->subscription_defer_event); @@ -147,6 +191,3 @@ void pa_subscription_post(struct pa_core *c, enum pa_subscription_event_type t, } -int pa_subscription_match_flags(enum pa_subscription_mask m, enum pa_subscription_event_type t) { - return !!(m & (1 >> (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK))); -} diff --git a/polyp/subscribe.h b/polyp/subscribe.h index 1561249f..a88677d2 100644 --- a/polyp/subscribe.h +++ b/polyp/subscribe.h @@ -2,33 +2,8 @@ #define foosubscribehfoo #include "core.h" +#include "native-common.h" -enum pa_subscription_mask { - PA_SUBSCRIPTION_FACILITY_SINK = 1, - PA_SUBSCRIPTION_FACILITY_SOURCE = 2, - PA_SUBSCRIPTION_FACILITY_SINK_INPUT = 4, - PA_SUBSCRIPTION_FACILITY_SOURCE_OUTPUT = 8, - PA_SUBSCRIPTION_FACILITY_MODULE = 16, - PA_SUBSCRIPTION_FACILITY_CLIENT = 32, - PA_SUBSCRIPTION_FACILITY_SAMPLE_CACHE = 64, -}; - -enum pa_subscription_event_type { - PA_SUBSCRIPTION_EVENT_SINK = 0, - PA_SUBSCRIPTION_EVENT_SOURCE = 1, - PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2, - PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 3, - PA_SUBSCRIPTION_EVENT_MODULE = 4, - PA_SUBSCRIPTION_EVENT_CLIENT = 5, - PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, - PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 7, - - PA_SUBSCRIPTION_EVENT_NEW = 0, - PA_SUBSCRIPTION_EVENT_CHANGE = 16, - PA_SUBSCRIPTION_EVENT_REMOVE = 32, - PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32, -}; - struct pa_subscription; struct pa_subscription_event; @@ -38,6 +13,4 @@ void pa_subscription_free_all(struct pa_core *c); void pa_subscription_post(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index); -int pa_subscription_match_flags(enum pa_subscription_mask m, enum pa_subscription_event_type e); - #endif -- cgit From 886041aab88930108953af0e9e14b39ec9d03809 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 12 Aug 2004 23:25:28 +0000 Subject: add more subscription events add support for clients/modules in native protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@115 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/cli-command.c | 2 +- polyp/module.c | 3 + polyp/native-common.h | 2 + polyp/polypaudio.pa | 6 +- polyp/polyplib.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++++ polyp/polyplib.h | 19 ++++++ polyp/protocol-native.c | 57 ++++++++++++++--- polyp/sink.c | 9 ++- polyp/sink.h | 2 + 9 files changed, 248 insertions(+), 14 deletions(-) diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 6386d4e4..1d454f2a 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -300,7 +300,7 @@ static int pa_cli_command_sink_volume(struct pa_core *c, struct pa_tokenizer *t, return -1; } - sink->volume = (uint32_t) volume; + pa_sink_set_volume(sink, (uint32_t) volume); return 0; } diff --git a/polyp/module.c b/polyp/module.c index 849afca4..1deb7cde 100644 --- a/polyp/module.c +++ b/polyp/module.c @@ -218,6 +218,9 @@ void pa_module_unload_request(struct pa_core *c, struct pa_module *m) { void pa_module_set_used(struct pa_module*m, int used) { assert(m); + if (m->n_used != used) + pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_CHANGE, m->index); + if (m->n_used != used && used == 0) time(&m->last_used_time); diff --git a/polyp/native-common.h b/polyp/native-common.h index 5e69c805..4d5ab53d 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -55,7 +55,9 @@ enum { PA_COMMAND_GET_SOURCE_INFO, PA_COMMAND_GET_SOURCE_INFO_LIST, PA_COMMAND_GET_MODULE_INFO, + PA_COMMAND_GET_MODULE_INFO_LIST, PA_COMMAND_GET_CLIENT_INFO, + PA_COMMAND_GET_CLIENT_INFO_LIST, PA_COMMAND_GET_SINK_INPUT_INFO, PA_COMMAND_GET_SOURCE_OUTPUT_INFO, PA_COMMAND_GET_SAMPLE_INFO, diff --git a/polyp/polypaudio.pa b/polyp/polypaudio.pa index d57f8127..9f8cf860 100755 --- a/polyp/polypaudio.pa +++ b/polyp/polypaudio.pa @@ -24,7 +24,7 @@ #load module-alsa-source device=plughw:1,0 #load module-oss device="/dev/dsp" sink_name=output source_name=input #load module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#load module-pipe-sink +load module-pipe-sink # Load audio drivers automatically on access @@ -32,8 +32,8 @@ #autoload_source_add input module-oss device="/dev/dsp" sink_name=output source_name=input #autoload_sink_add output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input #autoload_source_add input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -autoload_sink_add output module-alsa-sink sink_name=output -autoload_source_add input module-alsa-source source_name=input +#autoload_sink_add output module-alsa-sink sink_name=output +#autoload_source_add input module-alsa-source source_name=input # Load several protocols load module-esound-protocol-tcp diff --git a/polyp/polyplib.c b/polyp/polyplib.c index b77d24ea..35001d3d 100644 --- a/polyp/polyplib.c +++ b/polyp/polyplib.c @@ -102,6 +102,12 @@ struct pa_context { void *subscribe_userdata; enum pa_subscription_mask subscribe_mask; + void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); + void *get_client_info_userdata; + + void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); + void *get_module_info_userdata; + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; }; @@ -209,6 +215,12 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * c->subscribe_callback = NULL; c->subscribe_userdata = NULL; + c->get_client_info_callback = NULL; + c->get_client_info_userdata = NULL; + + c->get_module_info_callback = NULL; + c->get_module_info_userdata = NULL; + pa_check_for_sigpipe(); return c; } @@ -1386,3 +1398,153 @@ void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, v pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); } + +static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_client_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.protocol_name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); +} + + +void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_client_info_callback = cb; + c->get_client_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +} + +void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_client_info_callback = cb; + c->get_client_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +} + +static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_module_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.argument) < 0 || + pa_tagstruct_getu32(t, &i.n_used) < 0 || + pa_tagstruct_getu32(t, &i.auto_unload) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); +} + +void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_module_info_callback = cb; + c->get_module_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); +} + +void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_module_info_callback = cb; + c->get_module_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); +} diff --git a/polyp/polyplib.h b/polyp/polyplib.h index 8708cd72..590b978f 100644 --- a/polyp/polyplib.h +++ b/polyp/polyplib.h @@ -141,6 +141,25 @@ struct pa_server_info { void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); +struct pa_module_info { + uint32_t index; + const char*name, *argument; + uint32_t n_used, auto_unload; +}; + +void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); + +struct pa_client_info { + uint32_t index; + const char *name; + uint32_t owner_module; + const char *protocol_name; +}; + +void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); + void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); #ifdef __cplusplus diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index caaa1396..247851fc 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -159,8 +159,12 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_REMOVE_SAMPLE] = { command_remove_sample }, [PA_COMMAND_GET_SINK_INFO] = { command_get_info }, [PA_COMMAND_GET_SOURCE_INFO] = { command_get_info }, + [PA_COMMAND_GET_CLIENT_INFO] = { command_get_info }, + [PA_COMMAND_GET_MODULE_INFO] = { command_get_info }, [PA_COMMAND_GET_SINK_INFO_LIST] = { command_get_info_list }, [PA_COMMAND_GET_SOURCE_INFO_LIST] = { command_get_info_list }, + [PA_COMMAND_GET_MODULE_INFO_LIST] = { command_get_info_list }, + [PA_COMMAND_GET_CLIENT_INFO_LIST] = { command_get_info_list }, [PA_COMMAND_GET_SERVER_INFO] = { command_get_server_info }, [PA_COMMAND_SUBSCRIBE] = { command_subscribe }, }; @@ -964,11 +968,30 @@ static void source_fill_tagstruct(struct pa_tagstruct *t, struct pa_source *sour pa_tagstruct_puts(t, source->monitor_of ? source->monitor_of->name : ""); } +static void client_fill_tagstruct(struct pa_tagstruct *t, struct pa_client *client) { + assert(t && client); + pa_tagstruct_putu32(t, client->index); + pa_tagstruct_puts(t, client->name); + pa_tagstruct_puts(t, client->protocol_name); + pa_tagstruct_putu32(t, client->owner ? client->owner->index : (uint32_t) -1); +} + +static void module_fill_tagstruct(struct pa_tagstruct *t, struct pa_module *module) { + assert(t && module); + pa_tagstruct_putu32(t, module->index); + pa_tagstruct_puts(t, module->name); + pa_tagstruct_puts(t, module->argument ? module->argument : ""); + pa_tagstruct_putu32(t, module->n_used); + pa_tagstruct_putu32(t, module->auto_unload); +} + static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; uint32_t index; struct pa_sink *sink = NULL; struct pa_source *source = NULL; + struct pa_client *client = NULL; + struct pa_module *module = NULL; const char *name; struct pa_tagstruct *reply; assert(c && t); @@ -990,15 +1013,19 @@ static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t sink = pa_idxset_get_by_index(c->protocol->core->sinks, index); else sink = pa_namereg_get(c->protocol->core, *name ? name : NULL, PA_NAMEREG_SINK, 1); - } else { - assert(command == PA_COMMAND_GET_SOURCE_INFO); + } else if (command == PA_COMMAND_GET_SOURCE_INFO) { if (index != (uint32_t) -1) source = pa_idxset_get_by_index(c->protocol->core->sources, index); else source = pa_namereg_get(c->protocol->core, *name ? name : NULL, PA_NAMEREG_SOURCE, 1); + } else if (command == PA_COMMAND_GET_CLIENT_INFO) + client = pa_idxset_get_by_index(c->protocol->core->clients, index); + else { + assert(command == PA_COMMAND_GET_MODULE_INFO); + module = pa_idxset_get_by_index(c->protocol->core->modules, index); } - - if (!sink && !source) { + + if (!sink && !source && !client && !module) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -1009,8 +1036,12 @@ static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t pa_tagstruct_putu32(reply, tag); if (sink) sink_fill_tagstruct(reply, sink); - else + else if (source) source_fill_tagstruct(reply, source); + else if (client) + client_fill_tagstruct(reply, client); + else + module_fill_tagstruct(reply, module); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -1039,17 +1070,25 @@ static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uin if (command == PA_COMMAND_GET_SINK_INFO_LIST) i = c->protocol->core->sinks; - else { - assert(command == PA_COMMAND_GET_SOURCE_INFO_LIST); + else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST) i = c->protocol->core->sources; + else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST) + i = c->protocol->core->clients; + else { + assert(command == PA_COMMAND_GET_MODULE_INFO_LIST); + i = c->protocol->core->modules; } for (p = pa_idxset_first(i, &index); p; p = pa_idxset_next(i, &index)) { if (command == PA_COMMAND_GET_SINK_INFO_LIST) sink_fill_tagstruct(reply, p); - else { - assert(command == PA_COMMAND_GET_SOURCE_INFO_LIST); + else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST) source_fill_tagstruct(reply, p); + else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST) + client_fill_tagstruct(reply, p); + else { + assert(command == PA_COMMAND_GET_MODULE_INFO_LIST); + module_fill_tagstruct(reply, p); } } diff --git a/polyp/sink.c b/polyp/sink.c index 7e0e15cd..d9a3ae86 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -276,10 +276,17 @@ uint32_t pa_sink_get_latency(struct pa_sink *s) { return s->get_latency(s); } - void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m) { sink->owner = m; if (sink->monitor_source) pa_source_set_owner(sink->monitor_source, m); } + +void pa_sink_set_volume(struct pa_sink *sink, uint32_t volume) { + assert(sink); + if (sink->volume != volume) { + pa_subscription_post(sink->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, sink->index); + sink->volume = volume; + } +} diff --git a/polyp/sink.h b/polyp/sink.h index 400d5d04..2aa5d611 100644 --- a/polyp/sink.h +++ b/polyp/sink.h @@ -62,4 +62,6 @@ void pa_sink_notify(struct pa_sink*s); void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m); +void pa_sink_set_volume(struct pa_sink *sink, uint32_t volume); + #endif -- cgit From cd5809ca97e40fa1603474f034f034c705cb4d23 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 12 Aug 2004 23:27:57 +0000 Subject: todo fix git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@116 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/todo b/doc/todo index 276cccfc..943fab0d 100644 --- a/doc/todo +++ b/doc/todo @@ -22,6 +22,7 @@ subscription module load/unload kill client/... + set volume - more complete pactl ** later *** -- cgit From 7b52d5d02bf107491388fbcfe6ffbd354596cfdd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 13 Aug 2004 13:14:22 +0000 Subject: some preliminary cleanup git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@117 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/polyplib.h | 79 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/polyp/polyplib.h b/polyp/polyplib.h index 590b978f..a0dd9f9c 100644 --- a/polyp/polyplib.h +++ b/polyp/polyplib.h @@ -29,26 +29,18 @@ #include "mainloop-api.h" #ifdef __cplusplus -extern "C" { +//extern "C" { #endif struct pa_context; +struct pa_stream; struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); +void pa_context_unref(struct pa_context *c); +struct pa_context* pa_context_ref(struct pa_context *c); -int pa_context_connect( - struct pa_context *c, - const char *server, - void (*complete) (struct pa_context*c, int success, void *userdata), - void *userdata); - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata); - -void pa_context_free(struct pa_context *c); - +int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); +int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); int pa_context_is_dead(struct pa_context *c); @@ -57,28 +49,11 @@ int pa_context_errno(struct pa_context *c); int pa_context_is_pending(struct pa_context *c); -void pa_context_exit(struct pa_context *c); -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); - -struct pa_stream; - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata); - -void pa_stream_free(struct pa_stream *p); - -void pa_stream_drain( - struct pa_stream *s, - void (*complete) (struct pa_stream*s, void *userdata), - void *userdata); +struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); +void pa_stream_unref(struct pa_stream *s); +struct pa_stream *pa_stream_ref(struct pa_stream *s); +void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); @@ -95,6 +70,8 @@ void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, struct pa_context* pa_stream_get_context(struct pa_stream *p); +uint32_t pa_stream_get_index(struct pa_stream *s); + struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); @@ -160,6 +137,38 @@ struct pa_client_info { void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); +struct pa_sink_input_info { + uint32_t index; + const char *name; + uint32_t owner_module; + uint32_t owner_client; + uint32_t sink; + struct pa_sample_spec sample_spec; + uint32_t volume; + uint32_t latency; +}; + +void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); + +struct pa_source_output_info { + uint32_t index; + const char *name; + uint32_t owner_module; + uint32_t owner_client; + uint32_t source; + struct pa_sample_spec sample_spec; +}; + +void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); + +void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +void pa_context_exit(struct pa_context *c); +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); + void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); #ifdef __cplusplus -- cgit From 79a4e75e3ac61c3412d5c785215283e99d8b52bf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 13 Aug 2004 13:22:44 +0000 Subject: split polyplib.h git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@118 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/polyplib-context.c | 1550 +++++++++++++++++++++++++++++++++++++++++++ polyp/polyplib-context.h | 178 +++++ polyp/polyplib-introspect.c | 1550 +++++++++++++++++++++++++++++++++++++++++++ polyp/polyplib-introspect.h | 178 +++++ polyp/polyplib-stream.c | 1550 +++++++++++++++++++++++++++++++++++++++++++ polyp/polyplib-stream.h | 178 +++++ polyp/polyplib-subscribe.c | 1550 +++++++++++++++++++++++++++++++++++++++++++ polyp/polyplib-subscribe.h | 178 +++++ 8 files changed, 6912 insertions(+) create mode 100644 polyp/polyplib-context.c create mode 100644 polyp/polyplib-context.h create mode 100644 polyp/polyplib-introspect.c create mode 100644 polyp/polyplib-introspect.h create mode 100644 polyp/polyplib-stream.c create mode 100644 polyp/polyplib-stream.h create mode 100644 polyp/polyplib-subscribe.c create mode 100644 polyp/polyplib-subscribe.h diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c new file mode 100644 index 00000000..35001d3d --- /dev/null +++ b/polyp/polyplib-context.c @@ -0,0 +1,1550 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "polyplib.h" +#include "native-common.h" +#include "pdispatch.h" +#include "pstream.h" +#include "dynarray.h" +#include "socket-client.h" +#include "pstream-util.h" +#include "authkey.h" +#include "util.h" +#include "xmalloc.h" + +#define DEFAULT_MAXLENGTH 204800 +#define DEFAULT_TLENGTH 10240 +#define DEFAULT_PREBUF 4096 +#define DEFAULT_MINREQ 1024 +#define DEFAULT_FRAGSIZE 1024 + +#define DEFAULT_TIMEOUT (5*60) +#define DEFAULT_SERVER "/tmp/polypaudio/native" +#define DEFAULT_PORT "4713" + +struct pa_context { + char *name; + struct pa_mainloop_api* mainloop; + struct pa_socket_client *client; + struct pa_pstream *pstream; + struct pa_pdispatch *pdispatch; + struct pa_dynarray *record_streams, *playback_streams; + struct pa_stream *first_stream; + uint32_t ctag; + uint32_t error; + enum { + CONTEXT_UNCONNECTED, + CONTEXT_CONNECTING, + CONTEXT_AUTHORIZING, + CONTEXT_SETTING_NAME, + CONTEXT_READY, + CONTEXT_DEAD + } state; + + void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); + void *connect_complete_userdata; + + void (*drain_complete_callback)(struct pa_context*c, void *userdata); + void *drain_complete_userdata; + + void (*die_callback)(struct pa_context*c, void *userdata); + void *die_userdata; + + void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); + void *stat_userdata; + + void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); + void *play_sample_userdata; + + void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); + void *remove_sample_userdata; + + void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); + void *get_server_info_userdata; + + void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); + void *get_sink_info_userdata; + + void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); + void *get_source_info_userdata; + + void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); + void *subscribe_userdata; + enum pa_subscription_mask subscribe_mask; + + void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); + void *get_client_info_userdata; + + void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); + void *get_module_info_userdata; + + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; +}; + +struct pa_stream { + struct pa_context *context; + struct pa_stream *next, *previous; + + char *name; + struct pa_buffer_attr buffer_attr; + struct pa_sample_spec sample_spec; + uint32_t channel; + int channel_valid; + uint32_t device_index; + enum pa_stream_direction direction; + + enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; + uint32_t requested_bytes; + + void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); + void *read_userdata; + + void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); + void *write_userdata; + + void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); + void *create_complete_userdata; + + void (*drain_complete_callback)(struct pa_stream *s, void *userdata); + void *drain_complete_userdata; + + void (*die_callback)(struct pa_stream*c, void *userdata); + void *die_userdata; + + void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); + void *get_latency_userdata; + + void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); + void *finish_sample_userdata; +}; + +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); + +static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = { NULL }, + [PA_COMMAND_REPLY] = { NULL }, + [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_EXIT] = { NULL }, + [PA_COMMAND_REQUEST] = { command_request }, + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, + [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, + [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, +}; + +struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { + struct pa_context *c; + assert(mainloop && name); + + c = pa_xmalloc(sizeof(struct pa_context)); + c->name = pa_xstrdup(name); + c->mainloop = mainloop; + c->client = NULL; + c->pstream = NULL; + c->pdispatch = NULL; + c->playback_streams = pa_dynarray_new(); + assert(c->playback_streams); + c->record_streams = pa_dynarray_new(); + assert(c->record_streams); + c->first_stream = NULL; + c->error = PA_ERROR_OK; + c->state = CONTEXT_UNCONNECTED; + c->ctag = 0; + + c->connect_complete_callback = NULL; + c->connect_complete_userdata = NULL; + + c->drain_complete_callback = NULL; + c->drain_complete_userdata = NULL; + + c->die_callback = NULL; + c->die_userdata = NULL; + + c->stat_callback = NULL; + c->stat_userdata = NULL; + + c->play_sample_callback = NULL; + c->play_sample_userdata = NULL; + + c->remove_sample_callback = NULL; + c->remove_sample_userdata = NULL; + + c->get_server_info_callback = NULL; + c->get_server_info_userdata = NULL; + + c->get_sink_info_callback = NULL; + c->get_sink_info_userdata = NULL; + + c->get_source_info_callback = NULL; + c->get_source_info_userdata = NULL; + + c->subscribe_callback = NULL; + c->subscribe_userdata = NULL; + + c->get_client_info_callback = NULL; + c->get_client_info_userdata = NULL; + + c->get_module_info_callback = NULL; + c->get_module_info_userdata = NULL; + + pa_check_for_sigpipe(); + return c; +} + +void pa_context_free(struct pa_context *c) { + assert(c); + + while (c->first_stream) + pa_stream_free(c->first_stream); + + if (c->client) + pa_socket_client_free(c->client); + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + if (c->pstream) + pa_pstream_free(c->pstream); + if (c->record_streams) + pa_dynarray_free(c->record_streams, NULL, NULL); + if (c->playback_streams) + pa_dynarray_free(c->playback_streams, NULL, NULL); + + pa_xfree(c->name); + pa_xfree(c); +} + +static void stream_dead(struct pa_stream *s) { + assert(s); + + if (s->state == STREAM_DEAD) + return; + + if (s->state == STREAM_READY) { + s->state = STREAM_DEAD; + if (s->die_callback) + s->die_callback(s, s->die_userdata); + } else + s->state = STREAM_DEAD; +} + +static void context_dead(struct pa_context *c) { + struct pa_stream *s; + assert(c); + + if (c->state == CONTEXT_DEAD) + return; + + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + c->pdispatch = NULL; + + if (c->pstream) + pa_pstream_free(c->pstream); + c->pstream = NULL; + + if (c->client) + pa_socket_client_free(c->client); + c->client = NULL; + + for (s = c->first_stream; s; s = s->next) + stream_dead(s); + + if (c->state == CONTEXT_READY) { + c->state = CONTEXT_DEAD; + if (c->die_callback) + c->die_callback(c, c->die_userdata); + } else + c->state = CONTEXT_DEAD; +} + +static void pstream_die_callback(struct pa_pstream *p, void *userdata) { + struct pa_context *c = userdata; + assert(p && c); + c->error = PA_ERROR_CONNECTIONTERMINATED; + context_dead(c); +} + +static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { + struct pa_context *c = userdata; + assert(p && packet && c); + + if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { + fprintf(stderr, "polyp.c: invalid packet.\n"); + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + } +} + +static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + assert(p && chunk && c && chunk->memblock && chunk->memblock->data); + + if (!(s = pa_dynarray_get(c->record_streams, channel))) + return; + + if (s->read_callback) + s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); +} + +static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { + assert(c && t); + + if (command == PA_COMMAND_ERROR) { + if (pa_tagstruct_getu32(t, &c->error) < 0) { + c->error = PA_ERROR_PROTOCOL; + return -1; + } + + return 0; + } + + c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; + return -1; +} + +static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); + + if (command != PA_COMMAND_REPLY) { + handle_error(c, command, t); + context_dead(c); + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return; + } + + if (c->state == CONTEXT_AUTHORIZING) { + struct pa_tagstruct *t; + c->state = CONTEXT_SETTING_NAME; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, c->name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + } else { + assert(c->state == CONTEXT_SETTING_NAME); + + c->state = CONTEXT_READY; + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 1, c->connect_complete_userdata); + } + + return; +} + +static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { + struct pa_context *c = userdata; + struct pa_tagstruct *t; + uint32_t tag; + assert(client && c && c->state == CONTEXT_CONNECTING); + + pa_socket_client_free(client); + c->client = NULL; + + if (!io) { + c->error = PA_ERROR_CONNECTIONREFUSED; + context_dead(c); + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return; + } + + c->pstream = pa_pstream_new(c->mainloop, io); + assert(c->pstream); + pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); + pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); + pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); + + c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); + assert(c->pdispatch); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_AUTH); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + c->state = CONTEXT_AUTHORIZING; +} + +static struct sockaddr *resolve_server(const char *server, size_t *len) { + struct sockaddr *sa; + struct addrinfo hints, *result = NULL; + char *port; + assert(server && len); + + if ((port = strrchr(server, ':'))) + port++; + if (!port) + port = DEFAULT_PORT; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + if (getaddrinfo(server, port, &hints, &result) != 0) + return NULL; + assert(result); + + sa = pa_xmalloc(*len = result->ai_addrlen); + memcpy(sa, result->ai_addr, *len); + + freeaddrinfo(result); + + return sa; +} + +int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { + assert(c && c->state == CONTEXT_UNCONNECTED); + + if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { + c->error = PA_ERROR_AUTHKEY; + return -1; + } + + if (!server) + if (!(server = getenv("POLYP_SERVER"))) + server = DEFAULT_SERVER; + + assert(!c->client); + + if (*server == '/') { + if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + } else { + struct sockaddr* sa; + size_t sa_len; + + if (!(sa = resolve_server(server, &sa_len))) { + c->error = PA_ERROR_INVALIDSERVER; + return -1; + } + + c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); + pa_xfree(sa); + + if (!c->client) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + } + + c->connect_complete_callback = complete; + c->connect_complete_userdata = userdata; + + pa_socket_client_set_callback(c->client, on_connection, c); + c->state = CONTEXT_CONNECTING; + + return 0; +} + +int pa_context_is_dead(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_DEAD; +} + +int pa_context_is_ready(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_READY; +} + +int pa_context_errno(struct pa_context *c) { + assert(c); + return c->error; +} + +void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { + assert(c); + c->die_callback = cb; + c->die_userdata = userdata; +} + +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + uint32_t channel; + assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) + return; + + c->error = PA_ERROR_KILLED; + stream_dead(s); +} + +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s; + struct pa_context *c = userdata; + uint32_t bytes, channel; + assert(pd && command == PA_COMMAND_REQUEST && t && c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + pa_tagstruct_getu32(t, &bytes) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (!(s = pa_dynarray_get(c->playback_streams, channel))) + return; + + if (s->state != STREAM_READY) + return; + + s->requested_bytes += bytes; + + if (s->requested_bytes && s->write_callback) + s->write_callback(s, s->requested_bytes, s->write_userdata); +} + +static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s && s->state == STREAM_CREATING); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + if (s->create_complete_callback) + s->create_complete_callback(s, 0, s->create_complete_userdata); + + return; + } + + if (pa_tagstruct_getu32(t, &s->channel) < 0 || + ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + s->channel_valid = 1; + pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); + + s->state = STREAM_READY; + if (s->create_complete_callback) + s->create_complete_callback(s, 1, s->create_complete_userdata); +} + +static void create_stream(struct pa_stream *s, const char *dev) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s); + + s->state = STREAM_CREATING; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_puts(t, s->name); + pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_puts(t, dev ? dev : ""); + pa_tagstruct_putu32(t, s->buffer_attr.maxlength); + if (s->direction == PA_STREAM_PLAYBACK) { + pa_tagstruct_putu32(t, s->buffer_attr.tlength); + pa_tagstruct_putu32(t, s->buffer_attr.prebuf); + pa_tagstruct_putu32(t, s->buffer_attr.minreq); + } else + pa_tagstruct_putu32(t, s->buffer_attr.fragsize); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); +} + +static struct pa_stream *internal_stream_new(struct pa_context *c) { + struct pa_stream *s; + + s = pa_xmalloc(sizeof(struct pa_stream)); + s->context = c; + + s->read_callback = NULL; + s->read_userdata = NULL; + s->write_callback = NULL; + s->write_userdata = NULL; + s->die_callback = NULL; + s->die_userdata = NULL; + s->create_complete_callback = NULL; + s->create_complete_userdata = NULL; + s->get_latency_callback = NULL; + s->get_latency_userdata = NULL; + s->finish_sample_callback = NULL; + s->finish_sample_userdata = NULL; + + s->name = NULL; + s->state = STREAM_CREATING; + s->requested_bytes = 0; + s->channel = 0; + s->channel_valid = 0; + s->device_index = (uint32_t) -1; + + memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); + + s->next = c->first_stream; + if (s->next) + s->next->previous = s; + s->previous = NULL; + c->first_stream = s; + + return s; +} + +struct pa_stream* pa_stream_new( + struct pa_context *c, + enum pa_stream_direction dir, + const char *dev, + const char *name, + const struct pa_sample_spec *ss, + const struct pa_buffer_attr *attr, + void (*complete) (struct pa_stream*s, int success, void *userdata), + void *userdata) { + + struct pa_stream *s; + + assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); + + s = internal_stream_new(c); + assert(s); + + s->create_complete_callback = complete; + s->create_complete_userdata = userdata; + s->name = pa_xstrdup(name); + s->state = STREAM_CREATING; + s->direction = dir; + s->sample_spec = *ss; + if (attr) + s->buffer_attr = *attr; + else { + s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; + s->buffer_attr.tlength = DEFAULT_TLENGTH; + s->buffer_attr.prebuf = DEFAULT_PREBUF; + s->buffer_attr.minreq = DEFAULT_MINREQ; + s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; + } + + create_stream(s, dev); + + return s; +} + +void pa_stream_free(struct pa_stream *s) { + assert(s && s->context); + + if (s->context->pdispatch) + pa_pdispatch_unregister_reply(s->context->pdispatch, s); + + pa_xfree(s->name); + + if (s->channel_valid && s->context->state == CONTEXT_READY) { + struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : + (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); + pa_tagstruct_putu32(t, s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + } + + if (s->channel_valid) + pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); + + if (s->next) + s->next->previous = s->previous; + if (s->previous) + s->previous->next = s->next; + else + s->context->first_stream = s->next; + + pa_xfree(s); +} + +void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { + s->write_callback = cb; + s->write_userdata = userdata; +} + +void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { + struct pa_memchunk chunk; + assert(s && s->context && data && length && s->state == STREAM_READY); + + chunk.memblock = pa_memblock_new(length); + assert(chunk.memblock && chunk.memblock->data); + memcpy(chunk.memblock->data, data, length); + chunk.index = 0; + chunk.length = length; + + pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); + pa_memblock_unref(chunk.memblock); + + /*fprintf(stderr, "Sent %u bytes\n", length);*/ + + if (length < s->requested_bytes) + s->requested_bytes -= length; + else + s->requested_bytes = 0; +} + +size_t pa_stream_writable_size(struct pa_stream *s) { + assert(s && s->state == STREAM_READY); + return s->requested_bytes; +} + +void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { + assert(s && cb); + s->read_callback = cb; + s->read_userdata = userdata; +} + +int pa_stream_is_dead(struct pa_stream *s) { + return s->state == STREAM_DEAD; +} + +int pa_stream_is_ready(struct pa_stream*s) { + return s->state == STREAM_READY; +} + +void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { + assert(s); + s->die_callback = cb; + s->die_userdata = userdata; +} + +int pa_context_is_pending(struct pa_context *c) { + assert(c); + + if (c->state != CONTEXT_READY) + return 0; + + return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); +} + +struct pa_context* pa_stream_get_context(struct pa_stream *p) { + assert(p); + return p->context; +} + +static void set_dispatch_callbacks(struct pa_context *c); + +static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void set_dispatch_callbacks(struct pa_context *c) { + assert(c && c->state == CONTEXT_READY); + + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + + if (pa_pdispatch_is_pending(c->pdispatch)) { + pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); + return; + } + + if (pa_pstream_is_pending(c->pstream)) { + pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); + return; + } + + assert(c->drain_complete_callback); + c->drain_complete_callback(c, c->drain_complete_userdata); +} + +int pa_context_drain( + struct pa_context *c, + void (*complete) (struct pa_context*c, void *userdata), + void *userdata) { + + assert(c && c->state == CONTEXT_READY); + + if (complete == NULL) { + c->drain_complete_callback = NULL; + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + return 0; + } + + if (!pa_context_is_pending(c)) + return -1; + + c->drain_complete_callback = complete; + c->drain_complete_userdata = userdata; + + set_dispatch_callbacks(c); + + return 0; +} + +static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + return; + } + + if (s->state != STREAM_READY) + return; + + if (!pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->drain_complete_callback) { + void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; + s->drain_complete_callback = NULL; + temp(s, s->drain_complete_userdata); + } +} + + +void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s && s->state == STREAM_READY); + + if (!complete) { + s->drain_complete_callback = NULL; + return; + } + + s->drain_complete_callback = complete; + s->drain_complete_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); +} + +void pa_context_exit(struct pa_context *c) { + struct pa_tagstruct *t; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_EXIT); + pa_tagstruct_putu32(t, c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + uint32_t total, count; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &count) < 0 || + pa_tagstruct_getu32(t, &total) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, count, total, c->stat_userdata); +} + +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + c->stat_callback = cb; + c->stat_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_STAT); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); +} + +static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + uint32_t latency; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &latency) < 0 || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, latency, s->get_latency_userdata); +} + +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + p->get_latency_callback = cb; + p->get_latency_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); + pa_tagstruct_putu32(t, tag = p->context->ctag++); + pa_tagstruct_putu32(t, p->channel); + pa_pstream_send_tagstruct(p->context->pstream, t); + pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); +} + +struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { + struct pa_stream *s; + struct pa_tagstruct *t; + uint32_t tag; + + s = internal_stream_new(c); + assert(s); + + s->create_complete_callback = cb; + s->create_complete_userdata = userdata; + s->name = pa_xstrdup(name); + s->state = STREAM_CREATING; + s->direction = PA_STREAM_UPLOAD; + s->sample_spec = *ss; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_put_sample_spec(t, ss); + pa_tagstruct_putu32(t, length); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); + + return s; +} + +static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + if (s->finish_sample_callback) + s->finish_sample_callback(s, 0, s->finish_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->finish_sample_callback) + s->finish_sample_callback(s, 1, s->finish_sample_userdata); +} + +void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(p); + + p->finish_sample_callback = cb; + p->finish_sample_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = p->context->ctag++); + pa_tagstruct_putu32(t, p->channel); + pa_pstream_send_tagstruct(p->context->pstream, t); + pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); +} + +static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->play_sample_callback) + c->play_sample_callback(c, 0, c->play_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->play_sample_callback) + c->play_sample_callback(c, 1, c->play_sample_userdata); +} + +void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c && name && *name && (!dev || *dev)); + + c->play_sample_callback = cb; + c->play_sample_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_puts(t, dev ? dev : ""); + pa_tagstruct_putu32(t, volume); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); +} + +static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->remove_sample_callback) + c->remove_sample_callback(c, 0, c->remove_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->remove_sample_callback) + c->remove_sample_callback(c, 1, c->remove_sample_userdata); +} + +void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c && name); + + c->remove_sample_callback = cb; + c->remove_sample_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); +} + +static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + struct pa_server_info i; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_server_info_callback) + c->get_server_info_callback(c, NULL, c->get_server_info_userdata); + return; + } + + if (pa_tagstruct_gets(t, &i.server_name) < 0 || + pa_tagstruct_gets(t, &i.server_version) < 0 || + pa_tagstruct_gets(t, &i.user_name) < 0 || + pa_tagstruct_gets(t, &i.host_name) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_server_info_callback) + c->get_server_info_callback(c, &i, c->get_server_info_userdata); +} + +void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_server_info_callback = cb; + c->get_server_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); +} + +static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_sink_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.volume) < 0 || + pa_tagstruct_getu32(t, &i.monitor_source) < 0 || + pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || + pa_tagstruct_getu32(t, &i.latency) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); +} + +void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_sink_info_callback = cb; + c->get_sink_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); +} + +static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_source_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || + pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); +} + +void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_source_info_callback = cb; + c->get_source_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); +} + +void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { + struct pa_tagstruct *t; + assert(c); + + c->subscribe_callback = cb; + c->subscribe_userdata = userdata; + c->subscribe_mask = m; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); + pa_tagstruct_putu32(t, c->ctag++); + pa_tagstruct_putu32(t, cb ? m : 0); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + enum pa_subscription_event_type e; + uint32_t index; + assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); + + if (pa_tagstruct_getu32(t, &e) < 0 || + pa_tagstruct_getu32(t, &index) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) + c->subscribe_callback(c, e, index, c->subscribe_userdata); +} + +void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_sink_info_callback = cb; + c->get_sink_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); +} + +void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_source_info_callback = cb; + c->get_source_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); +} + +static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_client_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.protocol_name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); +} + + +void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_client_info_callback = cb; + c->get_client_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +} + +void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_client_info_callback = cb; + c->get_client_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +} + +static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_module_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.argument) < 0 || + pa_tagstruct_getu32(t, &i.n_used) < 0 || + pa_tagstruct_getu32(t, &i.auto_unload) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); +} + +void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_module_info_callback = cb; + c->get_module_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); +} + +void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_module_info_callback = cb; + c->get_module_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); +} diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h new file mode 100644 index 00000000..a0dd9f9c --- /dev/null +++ b/polyp/polyplib-context.h @@ -0,0 +1,178 @@ +#ifndef foopolyplibhfoo +#define foopolyplibhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "sample.h" +#include "polyplib-def.h" +#include "mainloop-api.h" + +#ifdef __cplusplus +//extern "C" { +#endif + +struct pa_context; +struct pa_stream; + +struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); +void pa_context_unref(struct pa_context *c); +struct pa_context* pa_context_ref(struct pa_context *c); + +int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); +int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); +void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); + +int pa_context_is_dead(struct pa_context *c); +int pa_context_is_ready(struct pa_context *c); +int pa_context_errno(struct pa_context *c); + +int pa_context_is_pending(struct pa_context *c); + +struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); +void pa_stream_unref(struct pa_stream *s); +struct pa_stream *pa_stream_ref(struct pa_stream *s); + +void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); + +void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); + +void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); +void pa_stream_write(struct pa_stream *p, const void *data, size_t length); +size_t pa_stream_writable_size(struct pa_stream *p); + +void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); + +int pa_stream_is_dead(struct pa_stream *p); +int pa_stream_is_ready(struct pa_stream*p); + +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); + +struct pa_context* pa_stream_get_context(struct pa_stream *p); + +uint32_t pa_stream_get_index(struct pa_stream *s); + +struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); +void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); + +void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +struct pa_sink_info { + const char *name; + uint32_t index; + const char *description; + struct pa_sample_spec sample_spec; + uint32_t owner_module; + uint32_t volume; + uint32_t monitor_source; + const char *monitor_source_name; + uint32_t latency; +}; + +void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); + +struct pa_source_info { + const char *name; + uint32_t index; + const char *description; + struct pa_sample_spec sample_spec; + uint32_t owner_module; + uint32_t monitor_of_sink; + const char *monitor_of_sink_name; +}; + +void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); + +struct pa_server_info { + const char *user_name; + const char *host_name; + const char *server_version; + const char *server_name; + struct pa_sample_spec sample_spec; +}; + +void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); + +struct pa_module_info { + uint32_t index; + const char*name, *argument; + uint32_t n_used, auto_unload; +}; + +void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); + +struct pa_client_info { + uint32_t index; + const char *name; + uint32_t owner_module; + const char *protocol_name; +}; + +void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); + +struct pa_sink_input_info { + uint32_t index; + const char *name; + uint32_t owner_module; + uint32_t owner_client; + uint32_t sink; + struct pa_sample_spec sample_spec; + uint32_t volume; + uint32_t latency; +}; + +void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); + +struct pa_source_output_info { + uint32_t index; + const char *name; + uint32_t owner_module; + uint32_t owner_client; + uint32_t source; + struct pa_sample_spec sample_spec; +}; + +void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); + +void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +void pa_context_exit(struct pa_context *c); +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); + +void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c new file mode 100644 index 00000000..35001d3d --- /dev/null +++ b/polyp/polyplib-introspect.c @@ -0,0 +1,1550 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "polyplib.h" +#include "native-common.h" +#include "pdispatch.h" +#include "pstream.h" +#include "dynarray.h" +#include "socket-client.h" +#include "pstream-util.h" +#include "authkey.h" +#include "util.h" +#include "xmalloc.h" + +#define DEFAULT_MAXLENGTH 204800 +#define DEFAULT_TLENGTH 10240 +#define DEFAULT_PREBUF 4096 +#define DEFAULT_MINREQ 1024 +#define DEFAULT_FRAGSIZE 1024 + +#define DEFAULT_TIMEOUT (5*60) +#define DEFAULT_SERVER "/tmp/polypaudio/native" +#define DEFAULT_PORT "4713" + +struct pa_context { + char *name; + struct pa_mainloop_api* mainloop; + struct pa_socket_client *client; + struct pa_pstream *pstream; + struct pa_pdispatch *pdispatch; + struct pa_dynarray *record_streams, *playback_streams; + struct pa_stream *first_stream; + uint32_t ctag; + uint32_t error; + enum { + CONTEXT_UNCONNECTED, + CONTEXT_CONNECTING, + CONTEXT_AUTHORIZING, + CONTEXT_SETTING_NAME, + CONTEXT_READY, + CONTEXT_DEAD + } state; + + void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); + void *connect_complete_userdata; + + void (*drain_complete_callback)(struct pa_context*c, void *userdata); + void *drain_complete_userdata; + + void (*die_callback)(struct pa_context*c, void *userdata); + void *die_userdata; + + void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); + void *stat_userdata; + + void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); + void *play_sample_userdata; + + void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); + void *remove_sample_userdata; + + void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); + void *get_server_info_userdata; + + void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); + void *get_sink_info_userdata; + + void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); + void *get_source_info_userdata; + + void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); + void *subscribe_userdata; + enum pa_subscription_mask subscribe_mask; + + void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); + void *get_client_info_userdata; + + void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); + void *get_module_info_userdata; + + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; +}; + +struct pa_stream { + struct pa_context *context; + struct pa_stream *next, *previous; + + char *name; + struct pa_buffer_attr buffer_attr; + struct pa_sample_spec sample_spec; + uint32_t channel; + int channel_valid; + uint32_t device_index; + enum pa_stream_direction direction; + + enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; + uint32_t requested_bytes; + + void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); + void *read_userdata; + + void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); + void *write_userdata; + + void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); + void *create_complete_userdata; + + void (*drain_complete_callback)(struct pa_stream *s, void *userdata); + void *drain_complete_userdata; + + void (*die_callback)(struct pa_stream*c, void *userdata); + void *die_userdata; + + void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); + void *get_latency_userdata; + + void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); + void *finish_sample_userdata; +}; + +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); + +static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = { NULL }, + [PA_COMMAND_REPLY] = { NULL }, + [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_EXIT] = { NULL }, + [PA_COMMAND_REQUEST] = { command_request }, + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, + [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, + [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, +}; + +struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { + struct pa_context *c; + assert(mainloop && name); + + c = pa_xmalloc(sizeof(struct pa_context)); + c->name = pa_xstrdup(name); + c->mainloop = mainloop; + c->client = NULL; + c->pstream = NULL; + c->pdispatch = NULL; + c->playback_streams = pa_dynarray_new(); + assert(c->playback_streams); + c->record_streams = pa_dynarray_new(); + assert(c->record_streams); + c->first_stream = NULL; + c->error = PA_ERROR_OK; + c->state = CONTEXT_UNCONNECTED; + c->ctag = 0; + + c->connect_complete_callback = NULL; + c->connect_complete_userdata = NULL; + + c->drain_complete_callback = NULL; + c->drain_complete_userdata = NULL; + + c->die_callback = NULL; + c->die_userdata = NULL; + + c->stat_callback = NULL; + c->stat_userdata = NULL; + + c->play_sample_callback = NULL; + c->play_sample_userdata = NULL; + + c->remove_sample_callback = NULL; + c->remove_sample_userdata = NULL; + + c->get_server_info_callback = NULL; + c->get_server_info_userdata = NULL; + + c->get_sink_info_callback = NULL; + c->get_sink_info_userdata = NULL; + + c->get_source_info_callback = NULL; + c->get_source_info_userdata = NULL; + + c->subscribe_callback = NULL; + c->subscribe_userdata = NULL; + + c->get_client_info_callback = NULL; + c->get_client_info_userdata = NULL; + + c->get_module_info_callback = NULL; + c->get_module_info_userdata = NULL; + + pa_check_for_sigpipe(); + return c; +} + +void pa_context_free(struct pa_context *c) { + assert(c); + + while (c->first_stream) + pa_stream_free(c->first_stream); + + if (c->client) + pa_socket_client_free(c->client); + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + if (c->pstream) + pa_pstream_free(c->pstream); + if (c->record_streams) + pa_dynarray_free(c->record_streams, NULL, NULL); + if (c->playback_streams) + pa_dynarray_free(c->playback_streams, NULL, NULL); + + pa_xfree(c->name); + pa_xfree(c); +} + +static void stream_dead(struct pa_stream *s) { + assert(s); + + if (s->state == STREAM_DEAD) + return; + + if (s->state == STREAM_READY) { + s->state = STREAM_DEAD; + if (s->die_callback) + s->die_callback(s, s->die_userdata); + } else + s->state = STREAM_DEAD; +} + +static void context_dead(struct pa_context *c) { + struct pa_stream *s; + assert(c); + + if (c->state == CONTEXT_DEAD) + return; + + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + c->pdispatch = NULL; + + if (c->pstream) + pa_pstream_free(c->pstream); + c->pstream = NULL; + + if (c->client) + pa_socket_client_free(c->client); + c->client = NULL; + + for (s = c->first_stream; s; s = s->next) + stream_dead(s); + + if (c->state == CONTEXT_READY) { + c->state = CONTEXT_DEAD; + if (c->die_callback) + c->die_callback(c, c->die_userdata); + } else + c->state = CONTEXT_DEAD; +} + +static void pstream_die_callback(struct pa_pstream *p, void *userdata) { + struct pa_context *c = userdata; + assert(p && c); + c->error = PA_ERROR_CONNECTIONTERMINATED; + context_dead(c); +} + +static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { + struct pa_context *c = userdata; + assert(p && packet && c); + + if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { + fprintf(stderr, "polyp.c: invalid packet.\n"); + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + } +} + +static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + assert(p && chunk && c && chunk->memblock && chunk->memblock->data); + + if (!(s = pa_dynarray_get(c->record_streams, channel))) + return; + + if (s->read_callback) + s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); +} + +static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { + assert(c && t); + + if (command == PA_COMMAND_ERROR) { + if (pa_tagstruct_getu32(t, &c->error) < 0) { + c->error = PA_ERROR_PROTOCOL; + return -1; + } + + return 0; + } + + c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; + return -1; +} + +static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); + + if (command != PA_COMMAND_REPLY) { + handle_error(c, command, t); + context_dead(c); + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return; + } + + if (c->state == CONTEXT_AUTHORIZING) { + struct pa_tagstruct *t; + c->state = CONTEXT_SETTING_NAME; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, c->name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + } else { + assert(c->state == CONTEXT_SETTING_NAME); + + c->state = CONTEXT_READY; + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 1, c->connect_complete_userdata); + } + + return; +} + +static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { + struct pa_context *c = userdata; + struct pa_tagstruct *t; + uint32_t tag; + assert(client && c && c->state == CONTEXT_CONNECTING); + + pa_socket_client_free(client); + c->client = NULL; + + if (!io) { + c->error = PA_ERROR_CONNECTIONREFUSED; + context_dead(c); + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return; + } + + c->pstream = pa_pstream_new(c->mainloop, io); + assert(c->pstream); + pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); + pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); + pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); + + c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); + assert(c->pdispatch); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_AUTH); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + c->state = CONTEXT_AUTHORIZING; +} + +static struct sockaddr *resolve_server(const char *server, size_t *len) { + struct sockaddr *sa; + struct addrinfo hints, *result = NULL; + char *port; + assert(server && len); + + if ((port = strrchr(server, ':'))) + port++; + if (!port) + port = DEFAULT_PORT; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + if (getaddrinfo(server, port, &hints, &result) != 0) + return NULL; + assert(result); + + sa = pa_xmalloc(*len = result->ai_addrlen); + memcpy(sa, result->ai_addr, *len); + + freeaddrinfo(result); + + return sa; +} + +int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { + assert(c && c->state == CONTEXT_UNCONNECTED); + + if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { + c->error = PA_ERROR_AUTHKEY; + return -1; + } + + if (!server) + if (!(server = getenv("POLYP_SERVER"))) + server = DEFAULT_SERVER; + + assert(!c->client); + + if (*server == '/') { + if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + } else { + struct sockaddr* sa; + size_t sa_len; + + if (!(sa = resolve_server(server, &sa_len))) { + c->error = PA_ERROR_INVALIDSERVER; + return -1; + } + + c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); + pa_xfree(sa); + + if (!c->client) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + } + + c->connect_complete_callback = complete; + c->connect_complete_userdata = userdata; + + pa_socket_client_set_callback(c->client, on_connection, c); + c->state = CONTEXT_CONNECTING; + + return 0; +} + +int pa_context_is_dead(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_DEAD; +} + +int pa_context_is_ready(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_READY; +} + +int pa_context_errno(struct pa_context *c) { + assert(c); + return c->error; +} + +void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { + assert(c); + c->die_callback = cb; + c->die_userdata = userdata; +} + +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + uint32_t channel; + assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) + return; + + c->error = PA_ERROR_KILLED; + stream_dead(s); +} + +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s; + struct pa_context *c = userdata; + uint32_t bytes, channel; + assert(pd && command == PA_COMMAND_REQUEST && t && c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + pa_tagstruct_getu32(t, &bytes) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (!(s = pa_dynarray_get(c->playback_streams, channel))) + return; + + if (s->state != STREAM_READY) + return; + + s->requested_bytes += bytes; + + if (s->requested_bytes && s->write_callback) + s->write_callback(s, s->requested_bytes, s->write_userdata); +} + +static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s && s->state == STREAM_CREATING); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + if (s->create_complete_callback) + s->create_complete_callback(s, 0, s->create_complete_userdata); + + return; + } + + if (pa_tagstruct_getu32(t, &s->channel) < 0 || + ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + s->channel_valid = 1; + pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); + + s->state = STREAM_READY; + if (s->create_complete_callback) + s->create_complete_callback(s, 1, s->create_complete_userdata); +} + +static void create_stream(struct pa_stream *s, const char *dev) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s); + + s->state = STREAM_CREATING; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_puts(t, s->name); + pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_puts(t, dev ? dev : ""); + pa_tagstruct_putu32(t, s->buffer_attr.maxlength); + if (s->direction == PA_STREAM_PLAYBACK) { + pa_tagstruct_putu32(t, s->buffer_attr.tlength); + pa_tagstruct_putu32(t, s->buffer_attr.prebuf); + pa_tagstruct_putu32(t, s->buffer_attr.minreq); + } else + pa_tagstruct_putu32(t, s->buffer_attr.fragsize); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); +} + +static struct pa_stream *internal_stream_new(struct pa_context *c) { + struct pa_stream *s; + + s = pa_xmalloc(sizeof(struct pa_stream)); + s->context = c; + + s->read_callback = NULL; + s->read_userdata = NULL; + s->write_callback = NULL; + s->write_userdata = NULL; + s->die_callback = NULL; + s->die_userdata = NULL; + s->create_complete_callback = NULL; + s->create_complete_userdata = NULL; + s->get_latency_callback = NULL; + s->get_latency_userdata = NULL; + s->finish_sample_callback = NULL; + s->finish_sample_userdata = NULL; + + s->name = NULL; + s->state = STREAM_CREATING; + s->requested_bytes = 0; + s->channel = 0; + s->channel_valid = 0; + s->device_index = (uint32_t) -1; + + memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); + + s->next = c->first_stream; + if (s->next) + s->next->previous = s; + s->previous = NULL; + c->first_stream = s; + + return s; +} + +struct pa_stream* pa_stream_new( + struct pa_context *c, + enum pa_stream_direction dir, + const char *dev, + const char *name, + const struct pa_sample_spec *ss, + const struct pa_buffer_attr *attr, + void (*complete) (struct pa_stream*s, int success, void *userdata), + void *userdata) { + + struct pa_stream *s; + + assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); + + s = internal_stream_new(c); + assert(s); + + s->create_complete_callback = complete; + s->create_complete_userdata = userdata; + s->name = pa_xstrdup(name); + s->state = STREAM_CREATING; + s->direction = dir; + s->sample_spec = *ss; + if (attr) + s->buffer_attr = *attr; + else { + s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; + s->buffer_attr.tlength = DEFAULT_TLENGTH; + s->buffer_attr.prebuf = DEFAULT_PREBUF; + s->buffer_attr.minreq = DEFAULT_MINREQ; + s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; + } + + create_stream(s, dev); + + return s; +} + +void pa_stream_free(struct pa_stream *s) { + assert(s && s->context); + + if (s->context->pdispatch) + pa_pdispatch_unregister_reply(s->context->pdispatch, s); + + pa_xfree(s->name); + + if (s->channel_valid && s->context->state == CONTEXT_READY) { + struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : + (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); + pa_tagstruct_putu32(t, s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + } + + if (s->channel_valid) + pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); + + if (s->next) + s->next->previous = s->previous; + if (s->previous) + s->previous->next = s->next; + else + s->context->first_stream = s->next; + + pa_xfree(s); +} + +void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { + s->write_callback = cb; + s->write_userdata = userdata; +} + +void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { + struct pa_memchunk chunk; + assert(s && s->context && data && length && s->state == STREAM_READY); + + chunk.memblock = pa_memblock_new(length); + assert(chunk.memblock && chunk.memblock->data); + memcpy(chunk.memblock->data, data, length); + chunk.index = 0; + chunk.length = length; + + pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); + pa_memblock_unref(chunk.memblock); + + /*fprintf(stderr, "Sent %u bytes\n", length);*/ + + if (length < s->requested_bytes) + s->requested_bytes -= length; + else + s->requested_bytes = 0; +} + +size_t pa_stream_writable_size(struct pa_stream *s) { + assert(s && s->state == STREAM_READY); + return s->requested_bytes; +} + +void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { + assert(s && cb); + s->read_callback = cb; + s->read_userdata = userdata; +} + +int pa_stream_is_dead(struct pa_stream *s) { + return s->state == STREAM_DEAD; +} + +int pa_stream_is_ready(struct pa_stream*s) { + return s->state == STREAM_READY; +} + +void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { + assert(s); + s->die_callback = cb; + s->die_userdata = userdata; +} + +int pa_context_is_pending(struct pa_context *c) { + assert(c); + + if (c->state != CONTEXT_READY) + return 0; + + return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); +} + +struct pa_context* pa_stream_get_context(struct pa_stream *p) { + assert(p); + return p->context; +} + +static void set_dispatch_callbacks(struct pa_context *c); + +static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void set_dispatch_callbacks(struct pa_context *c) { + assert(c && c->state == CONTEXT_READY); + + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + + if (pa_pdispatch_is_pending(c->pdispatch)) { + pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); + return; + } + + if (pa_pstream_is_pending(c->pstream)) { + pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); + return; + } + + assert(c->drain_complete_callback); + c->drain_complete_callback(c, c->drain_complete_userdata); +} + +int pa_context_drain( + struct pa_context *c, + void (*complete) (struct pa_context*c, void *userdata), + void *userdata) { + + assert(c && c->state == CONTEXT_READY); + + if (complete == NULL) { + c->drain_complete_callback = NULL; + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + return 0; + } + + if (!pa_context_is_pending(c)) + return -1; + + c->drain_complete_callback = complete; + c->drain_complete_userdata = userdata; + + set_dispatch_callbacks(c); + + return 0; +} + +static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + return; + } + + if (s->state != STREAM_READY) + return; + + if (!pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->drain_complete_callback) { + void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; + s->drain_complete_callback = NULL; + temp(s, s->drain_complete_userdata); + } +} + + +void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s && s->state == STREAM_READY); + + if (!complete) { + s->drain_complete_callback = NULL; + return; + } + + s->drain_complete_callback = complete; + s->drain_complete_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); +} + +void pa_context_exit(struct pa_context *c) { + struct pa_tagstruct *t; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_EXIT); + pa_tagstruct_putu32(t, c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + uint32_t total, count; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &count) < 0 || + pa_tagstruct_getu32(t, &total) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, count, total, c->stat_userdata); +} + +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + c->stat_callback = cb; + c->stat_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_STAT); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); +} + +static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + uint32_t latency; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &latency) < 0 || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, latency, s->get_latency_userdata); +} + +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + p->get_latency_callback = cb; + p->get_latency_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); + pa_tagstruct_putu32(t, tag = p->context->ctag++); + pa_tagstruct_putu32(t, p->channel); + pa_pstream_send_tagstruct(p->context->pstream, t); + pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); +} + +struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { + struct pa_stream *s; + struct pa_tagstruct *t; + uint32_t tag; + + s = internal_stream_new(c); + assert(s); + + s->create_complete_callback = cb; + s->create_complete_userdata = userdata; + s->name = pa_xstrdup(name); + s->state = STREAM_CREATING; + s->direction = PA_STREAM_UPLOAD; + s->sample_spec = *ss; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_put_sample_spec(t, ss); + pa_tagstruct_putu32(t, length); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); + + return s; +} + +static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + if (s->finish_sample_callback) + s->finish_sample_callback(s, 0, s->finish_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->finish_sample_callback) + s->finish_sample_callback(s, 1, s->finish_sample_userdata); +} + +void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(p); + + p->finish_sample_callback = cb; + p->finish_sample_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = p->context->ctag++); + pa_tagstruct_putu32(t, p->channel); + pa_pstream_send_tagstruct(p->context->pstream, t); + pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); +} + +static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->play_sample_callback) + c->play_sample_callback(c, 0, c->play_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->play_sample_callback) + c->play_sample_callback(c, 1, c->play_sample_userdata); +} + +void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c && name && *name && (!dev || *dev)); + + c->play_sample_callback = cb; + c->play_sample_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_puts(t, dev ? dev : ""); + pa_tagstruct_putu32(t, volume); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); +} + +static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->remove_sample_callback) + c->remove_sample_callback(c, 0, c->remove_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->remove_sample_callback) + c->remove_sample_callback(c, 1, c->remove_sample_userdata); +} + +void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c && name); + + c->remove_sample_callback = cb; + c->remove_sample_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); +} + +static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + struct pa_server_info i; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_server_info_callback) + c->get_server_info_callback(c, NULL, c->get_server_info_userdata); + return; + } + + if (pa_tagstruct_gets(t, &i.server_name) < 0 || + pa_tagstruct_gets(t, &i.server_version) < 0 || + pa_tagstruct_gets(t, &i.user_name) < 0 || + pa_tagstruct_gets(t, &i.host_name) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_server_info_callback) + c->get_server_info_callback(c, &i, c->get_server_info_userdata); +} + +void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_server_info_callback = cb; + c->get_server_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); +} + +static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_sink_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.volume) < 0 || + pa_tagstruct_getu32(t, &i.monitor_source) < 0 || + pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || + pa_tagstruct_getu32(t, &i.latency) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); +} + +void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_sink_info_callback = cb; + c->get_sink_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); +} + +static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_source_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || + pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); +} + +void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_source_info_callback = cb; + c->get_source_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); +} + +void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { + struct pa_tagstruct *t; + assert(c); + + c->subscribe_callback = cb; + c->subscribe_userdata = userdata; + c->subscribe_mask = m; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); + pa_tagstruct_putu32(t, c->ctag++); + pa_tagstruct_putu32(t, cb ? m : 0); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + enum pa_subscription_event_type e; + uint32_t index; + assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); + + if (pa_tagstruct_getu32(t, &e) < 0 || + pa_tagstruct_getu32(t, &index) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) + c->subscribe_callback(c, e, index, c->subscribe_userdata); +} + +void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_sink_info_callback = cb; + c->get_sink_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); +} + +void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_source_info_callback = cb; + c->get_source_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); +} + +static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_client_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.protocol_name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); +} + + +void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_client_info_callback = cb; + c->get_client_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +} + +void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_client_info_callback = cb; + c->get_client_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +} + +static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_module_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.argument) < 0 || + pa_tagstruct_getu32(t, &i.n_used) < 0 || + pa_tagstruct_getu32(t, &i.auto_unload) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); +} + +void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_module_info_callback = cb; + c->get_module_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); +} + +void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_module_info_callback = cb; + c->get_module_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); +} diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h new file mode 100644 index 00000000..a0dd9f9c --- /dev/null +++ b/polyp/polyplib-introspect.h @@ -0,0 +1,178 @@ +#ifndef foopolyplibhfoo +#define foopolyplibhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "sample.h" +#include "polyplib-def.h" +#include "mainloop-api.h" + +#ifdef __cplusplus +//extern "C" { +#endif + +struct pa_context; +struct pa_stream; + +struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); +void pa_context_unref(struct pa_context *c); +struct pa_context* pa_context_ref(struct pa_context *c); + +int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); +int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); +void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); + +int pa_context_is_dead(struct pa_context *c); +int pa_context_is_ready(struct pa_context *c); +int pa_context_errno(struct pa_context *c); + +int pa_context_is_pending(struct pa_context *c); + +struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); +void pa_stream_unref(struct pa_stream *s); +struct pa_stream *pa_stream_ref(struct pa_stream *s); + +void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); + +void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); + +void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); +void pa_stream_write(struct pa_stream *p, const void *data, size_t length); +size_t pa_stream_writable_size(struct pa_stream *p); + +void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); + +int pa_stream_is_dead(struct pa_stream *p); +int pa_stream_is_ready(struct pa_stream*p); + +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); + +struct pa_context* pa_stream_get_context(struct pa_stream *p); + +uint32_t pa_stream_get_index(struct pa_stream *s); + +struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); +void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); + +void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +struct pa_sink_info { + const char *name; + uint32_t index; + const char *description; + struct pa_sample_spec sample_spec; + uint32_t owner_module; + uint32_t volume; + uint32_t monitor_source; + const char *monitor_source_name; + uint32_t latency; +}; + +void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); + +struct pa_source_info { + const char *name; + uint32_t index; + const char *description; + struct pa_sample_spec sample_spec; + uint32_t owner_module; + uint32_t monitor_of_sink; + const char *monitor_of_sink_name; +}; + +void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); + +struct pa_server_info { + const char *user_name; + const char *host_name; + const char *server_version; + const char *server_name; + struct pa_sample_spec sample_spec; +}; + +void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); + +struct pa_module_info { + uint32_t index; + const char*name, *argument; + uint32_t n_used, auto_unload; +}; + +void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); + +struct pa_client_info { + uint32_t index; + const char *name; + uint32_t owner_module; + const char *protocol_name; +}; + +void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); + +struct pa_sink_input_info { + uint32_t index; + const char *name; + uint32_t owner_module; + uint32_t owner_client; + uint32_t sink; + struct pa_sample_spec sample_spec; + uint32_t volume; + uint32_t latency; +}; + +void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); + +struct pa_source_output_info { + uint32_t index; + const char *name; + uint32_t owner_module; + uint32_t owner_client; + uint32_t source; + struct pa_sample_spec sample_spec; +}; + +void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); + +void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +void pa_context_exit(struct pa_context *c); +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); + +void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c new file mode 100644 index 00000000..35001d3d --- /dev/null +++ b/polyp/polyplib-stream.c @@ -0,0 +1,1550 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "polyplib.h" +#include "native-common.h" +#include "pdispatch.h" +#include "pstream.h" +#include "dynarray.h" +#include "socket-client.h" +#include "pstream-util.h" +#include "authkey.h" +#include "util.h" +#include "xmalloc.h" + +#define DEFAULT_MAXLENGTH 204800 +#define DEFAULT_TLENGTH 10240 +#define DEFAULT_PREBUF 4096 +#define DEFAULT_MINREQ 1024 +#define DEFAULT_FRAGSIZE 1024 + +#define DEFAULT_TIMEOUT (5*60) +#define DEFAULT_SERVER "/tmp/polypaudio/native" +#define DEFAULT_PORT "4713" + +struct pa_context { + char *name; + struct pa_mainloop_api* mainloop; + struct pa_socket_client *client; + struct pa_pstream *pstream; + struct pa_pdispatch *pdispatch; + struct pa_dynarray *record_streams, *playback_streams; + struct pa_stream *first_stream; + uint32_t ctag; + uint32_t error; + enum { + CONTEXT_UNCONNECTED, + CONTEXT_CONNECTING, + CONTEXT_AUTHORIZING, + CONTEXT_SETTING_NAME, + CONTEXT_READY, + CONTEXT_DEAD + } state; + + void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); + void *connect_complete_userdata; + + void (*drain_complete_callback)(struct pa_context*c, void *userdata); + void *drain_complete_userdata; + + void (*die_callback)(struct pa_context*c, void *userdata); + void *die_userdata; + + void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); + void *stat_userdata; + + void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); + void *play_sample_userdata; + + void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); + void *remove_sample_userdata; + + void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); + void *get_server_info_userdata; + + void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); + void *get_sink_info_userdata; + + void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); + void *get_source_info_userdata; + + void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); + void *subscribe_userdata; + enum pa_subscription_mask subscribe_mask; + + void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); + void *get_client_info_userdata; + + void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); + void *get_module_info_userdata; + + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; +}; + +struct pa_stream { + struct pa_context *context; + struct pa_stream *next, *previous; + + char *name; + struct pa_buffer_attr buffer_attr; + struct pa_sample_spec sample_spec; + uint32_t channel; + int channel_valid; + uint32_t device_index; + enum pa_stream_direction direction; + + enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; + uint32_t requested_bytes; + + void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); + void *read_userdata; + + void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); + void *write_userdata; + + void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); + void *create_complete_userdata; + + void (*drain_complete_callback)(struct pa_stream *s, void *userdata); + void *drain_complete_userdata; + + void (*die_callback)(struct pa_stream*c, void *userdata); + void *die_userdata; + + void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); + void *get_latency_userdata; + + void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); + void *finish_sample_userdata; +}; + +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); + +static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = { NULL }, + [PA_COMMAND_REPLY] = { NULL }, + [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_EXIT] = { NULL }, + [PA_COMMAND_REQUEST] = { command_request }, + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, + [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, + [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, +}; + +struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { + struct pa_context *c; + assert(mainloop && name); + + c = pa_xmalloc(sizeof(struct pa_context)); + c->name = pa_xstrdup(name); + c->mainloop = mainloop; + c->client = NULL; + c->pstream = NULL; + c->pdispatch = NULL; + c->playback_streams = pa_dynarray_new(); + assert(c->playback_streams); + c->record_streams = pa_dynarray_new(); + assert(c->record_streams); + c->first_stream = NULL; + c->error = PA_ERROR_OK; + c->state = CONTEXT_UNCONNECTED; + c->ctag = 0; + + c->connect_complete_callback = NULL; + c->connect_complete_userdata = NULL; + + c->drain_complete_callback = NULL; + c->drain_complete_userdata = NULL; + + c->die_callback = NULL; + c->die_userdata = NULL; + + c->stat_callback = NULL; + c->stat_userdata = NULL; + + c->play_sample_callback = NULL; + c->play_sample_userdata = NULL; + + c->remove_sample_callback = NULL; + c->remove_sample_userdata = NULL; + + c->get_server_info_callback = NULL; + c->get_server_info_userdata = NULL; + + c->get_sink_info_callback = NULL; + c->get_sink_info_userdata = NULL; + + c->get_source_info_callback = NULL; + c->get_source_info_userdata = NULL; + + c->subscribe_callback = NULL; + c->subscribe_userdata = NULL; + + c->get_client_info_callback = NULL; + c->get_client_info_userdata = NULL; + + c->get_module_info_callback = NULL; + c->get_module_info_userdata = NULL; + + pa_check_for_sigpipe(); + return c; +} + +void pa_context_free(struct pa_context *c) { + assert(c); + + while (c->first_stream) + pa_stream_free(c->first_stream); + + if (c->client) + pa_socket_client_free(c->client); + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + if (c->pstream) + pa_pstream_free(c->pstream); + if (c->record_streams) + pa_dynarray_free(c->record_streams, NULL, NULL); + if (c->playback_streams) + pa_dynarray_free(c->playback_streams, NULL, NULL); + + pa_xfree(c->name); + pa_xfree(c); +} + +static void stream_dead(struct pa_stream *s) { + assert(s); + + if (s->state == STREAM_DEAD) + return; + + if (s->state == STREAM_READY) { + s->state = STREAM_DEAD; + if (s->die_callback) + s->die_callback(s, s->die_userdata); + } else + s->state = STREAM_DEAD; +} + +static void context_dead(struct pa_context *c) { + struct pa_stream *s; + assert(c); + + if (c->state == CONTEXT_DEAD) + return; + + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + c->pdispatch = NULL; + + if (c->pstream) + pa_pstream_free(c->pstream); + c->pstream = NULL; + + if (c->client) + pa_socket_client_free(c->client); + c->client = NULL; + + for (s = c->first_stream; s; s = s->next) + stream_dead(s); + + if (c->state == CONTEXT_READY) { + c->state = CONTEXT_DEAD; + if (c->die_callback) + c->die_callback(c, c->die_userdata); + } else + c->state = CONTEXT_DEAD; +} + +static void pstream_die_callback(struct pa_pstream *p, void *userdata) { + struct pa_context *c = userdata; + assert(p && c); + c->error = PA_ERROR_CONNECTIONTERMINATED; + context_dead(c); +} + +static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { + struct pa_context *c = userdata; + assert(p && packet && c); + + if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { + fprintf(stderr, "polyp.c: invalid packet.\n"); + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + } +} + +static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + assert(p && chunk && c && chunk->memblock && chunk->memblock->data); + + if (!(s = pa_dynarray_get(c->record_streams, channel))) + return; + + if (s->read_callback) + s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); +} + +static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { + assert(c && t); + + if (command == PA_COMMAND_ERROR) { + if (pa_tagstruct_getu32(t, &c->error) < 0) { + c->error = PA_ERROR_PROTOCOL; + return -1; + } + + return 0; + } + + c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; + return -1; +} + +static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); + + if (command != PA_COMMAND_REPLY) { + handle_error(c, command, t); + context_dead(c); + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return; + } + + if (c->state == CONTEXT_AUTHORIZING) { + struct pa_tagstruct *t; + c->state = CONTEXT_SETTING_NAME; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, c->name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + } else { + assert(c->state == CONTEXT_SETTING_NAME); + + c->state = CONTEXT_READY; + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 1, c->connect_complete_userdata); + } + + return; +} + +static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { + struct pa_context *c = userdata; + struct pa_tagstruct *t; + uint32_t tag; + assert(client && c && c->state == CONTEXT_CONNECTING); + + pa_socket_client_free(client); + c->client = NULL; + + if (!io) { + c->error = PA_ERROR_CONNECTIONREFUSED; + context_dead(c); + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return; + } + + c->pstream = pa_pstream_new(c->mainloop, io); + assert(c->pstream); + pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); + pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); + pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); + + c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); + assert(c->pdispatch); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_AUTH); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + c->state = CONTEXT_AUTHORIZING; +} + +static struct sockaddr *resolve_server(const char *server, size_t *len) { + struct sockaddr *sa; + struct addrinfo hints, *result = NULL; + char *port; + assert(server && len); + + if ((port = strrchr(server, ':'))) + port++; + if (!port) + port = DEFAULT_PORT; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + if (getaddrinfo(server, port, &hints, &result) != 0) + return NULL; + assert(result); + + sa = pa_xmalloc(*len = result->ai_addrlen); + memcpy(sa, result->ai_addr, *len); + + freeaddrinfo(result); + + return sa; +} + +int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { + assert(c && c->state == CONTEXT_UNCONNECTED); + + if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { + c->error = PA_ERROR_AUTHKEY; + return -1; + } + + if (!server) + if (!(server = getenv("POLYP_SERVER"))) + server = DEFAULT_SERVER; + + assert(!c->client); + + if (*server == '/') { + if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + } else { + struct sockaddr* sa; + size_t sa_len; + + if (!(sa = resolve_server(server, &sa_len))) { + c->error = PA_ERROR_INVALIDSERVER; + return -1; + } + + c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); + pa_xfree(sa); + + if (!c->client) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + } + + c->connect_complete_callback = complete; + c->connect_complete_userdata = userdata; + + pa_socket_client_set_callback(c->client, on_connection, c); + c->state = CONTEXT_CONNECTING; + + return 0; +} + +int pa_context_is_dead(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_DEAD; +} + +int pa_context_is_ready(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_READY; +} + +int pa_context_errno(struct pa_context *c) { + assert(c); + return c->error; +} + +void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { + assert(c); + c->die_callback = cb; + c->die_userdata = userdata; +} + +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + uint32_t channel; + assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) + return; + + c->error = PA_ERROR_KILLED; + stream_dead(s); +} + +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s; + struct pa_context *c = userdata; + uint32_t bytes, channel; + assert(pd && command == PA_COMMAND_REQUEST && t && c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + pa_tagstruct_getu32(t, &bytes) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (!(s = pa_dynarray_get(c->playback_streams, channel))) + return; + + if (s->state != STREAM_READY) + return; + + s->requested_bytes += bytes; + + if (s->requested_bytes && s->write_callback) + s->write_callback(s, s->requested_bytes, s->write_userdata); +} + +static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s && s->state == STREAM_CREATING); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + if (s->create_complete_callback) + s->create_complete_callback(s, 0, s->create_complete_userdata); + + return; + } + + if (pa_tagstruct_getu32(t, &s->channel) < 0 || + ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + s->channel_valid = 1; + pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); + + s->state = STREAM_READY; + if (s->create_complete_callback) + s->create_complete_callback(s, 1, s->create_complete_userdata); +} + +static void create_stream(struct pa_stream *s, const char *dev) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s); + + s->state = STREAM_CREATING; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_puts(t, s->name); + pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_puts(t, dev ? dev : ""); + pa_tagstruct_putu32(t, s->buffer_attr.maxlength); + if (s->direction == PA_STREAM_PLAYBACK) { + pa_tagstruct_putu32(t, s->buffer_attr.tlength); + pa_tagstruct_putu32(t, s->buffer_attr.prebuf); + pa_tagstruct_putu32(t, s->buffer_attr.minreq); + } else + pa_tagstruct_putu32(t, s->buffer_attr.fragsize); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); +} + +static struct pa_stream *internal_stream_new(struct pa_context *c) { + struct pa_stream *s; + + s = pa_xmalloc(sizeof(struct pa_stream)); + s->context = c; + + s->read_callback = NULL; + s->read_userdata = NULL; + s->write_callback = NULL; + s->write_userdata = NULL; + s->die_callback = NULL; + s->die_userdata = NULL; + s->create_complete_callback = NULL; + s->create_complete_userdata = NULL; + s->get_latency_callback = NULL; + s->get_latency_userdata = NULL; + s->finish_sample_callback = NULL; + s->finish_sample_userdata = NULL; + + s->name = NULL; + s->state = STREAM_CREATING; + s->requested_bytes = 0; + s->channel = 0; + s->channel_valid = 0; + s->device_index = (uint32_t) -1; + + memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); + + s->next = c->first_stream; + if (s->next) + s->next->previous = s; + s->previous = NULL; + c->first_stream = s; + + return s; +} + +struct pa_stream* pa_stream_new( + struct pa_context *c, + enum pa_stream_direction dir, + const char *dev, + const char *name, + const struct pa_sample_spec *ss, + const struct pa_buffer_attr *attr, + void (*complete) (struct pa_stream*s, int success, void *userdata), + void *userdata) { + + struct pa_stream *s; + + assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); + + s = internal_stream_new(c); + assert(s); + + s->create_complete_callback = complete; + s->create_complete_userdata = userdata; + s->name = pa_xstrdup(name); + s->state = STREAM_CREATING; + s->direction = dir; + s->sample_spec = *ss; + if (attr) + s->buffer_attr = *attr; + else { + s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; + s->buffer_attr.tlength = DEFAULT_TLENGTH; + s->buffer_attr.prebuf = DEFAULT_PREBUF; + s->buffer_attr.minreq = DEFAULT_MINREQ; + s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; + } + + create_stream(s, dev); + + return s; +} + +void pa_stream_free(struct pa_stream *s) { + assert(s && s->context); + + if (s->context->pdispatch) + pa_pdispatch_unregister_reply(s->context->pdispatch, s); + + pa_xfree(s->name); + + if (s->channel_valid && s->context->state == CONTEXT_READY) { + struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : + (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); + pa_tagstruct_putu32(t, s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + } + + if (s->channel_valid) + pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); + + if (s->next) + s->next->previous = s->previous; + if (s->previous) + s->previous->next = s->next; + else + s->context->first_stream = s->next; + + pa_xfree(s); +} + +void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { + s->write_callback = cb; + s->write_userdata = userdata; +} + +void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { + struct pa_memchunk chunk; + assert(s && s->context && data && length && s->state == STREAM_READY); + + chunk.memblock = pa_memblock_new(length); + assert(chunk.memblock && chunk.memblock->data); + memcpy(chunk.memblock->data, data, length); + chunk.index = 0; + chunk.length = length; + + pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); + pa_memblock_unref(chunk.memblock); + + /*fprintf(stderr, "Sent %u bytes\n", length);*/ + + if (length < s->requested_bytes) + s->requested_bytes -= length; + else + s->requested_bytes = 0; +} + +size_t pa_stream_writable_size(struct pa_stream *s) { + assert(s && s->state == STREAM_READY); + return s->requested_bytes; +} + +void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { + assert(s && cb); + s->read_callback = cb; + s->read_userdata = userdata; +} + +int pa_stream_is_dead(struct pa_stream *s) { + return s->state == STREAM_DEAD; +} + +int pa_stream_is_ready(struct pa_stream*s) { + return s->state == STREAM_READY; +} + +void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { + assert(s); + s->die_callback = cb; + s->die_userdata = userdata; +} + +int pa_context_is_pending(struct pa_context *c) { + assert(c); + + if (c->state != CONTEXT_READY) + return 0; + + return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); +} + +struct pa_context* pa_stream_get_context(struct pa_stream *p) { + assert(p); + return p->context; +} + +static void set_dispatch_callbacks(struct pa_context *c); + +static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void set_dispatch_callbacks(struct pa_context *c) { + assert(c && c->state == CONTEXT_READY); + + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + + if (pa_pdispatch_is_pending(c->pdispatch)) { + pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); + return; + } + + if (pa_pstream_is_pending(c->pstream)) { + pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); + return; + } + + assert(c->drain_complete_callback); + c->drain_complete_callback(c, c->drain_complete_userdata); +} + +int pa_context_drain( + struct pa_context *c, + void (*complete) (struct pa_context*c, void *userdata), + void *userdata) { + + assert(c && c->state == CONTEXT_READY); + + if (complete == NULL) { + c->drain_complete_callback = NULL; + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + return 0; + } + + if (!pa_context_is_pending(c)) + return -1; + + c->drain_complete_callback = complete; + c->drain_complete_userdata = userdata; + + set_dispatch_callbacks(c); + + return 0; +} + +static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + return; + } + + if (s->state != STREAM_READY) + return; + + if (!pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->drain_complete_callback) { + void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; + s->drain_complete_callback = NULL; + temp(s, s->drain_complete_userdata); + } +} + + +void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s && s->state == STREAM_READY); + + if (!complete) { + s->drain_complete_callback = NULL; + return; + } + + s->drain_complete_callback = complete; + s->drain_complete_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); +} + +void pa_context_exit(struct pa_context *c) { + struct pa_tagstruct *t; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_EXIT); + pa_tagstruct_putu32(t, c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + uint32_t total, count; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &count) < 0 || + pa_tagstruct_getu32(t, &total) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, count, total, c->stat_userdata); +} + +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + c->stat_callback = cb; + c->stat_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_STAT); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); +} + +static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + uint32_t latency; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &latency) < 0 || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, latency, s->get_latency_userdata); +} + +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + p->get_latency_callback = cb; + p->get_latency_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); + pa_tagstruct_putu32(t, tag = p->context->ctag++); + pa_tagstruct_putu32(t, p->channel); + pa_pstream_send_tagstruct(p->context->pstream, t); + pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); +} + +struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { + struct pa_stream *s; + struct pa_tagstruct *t; + uint32_t tag; + + s = internal_stream_new(c); + assert(s); + + s->create_complete_callback = cb; + s->create_complete_userdata = userdata; + s->name = pa_xstrdup(name); + s->state = STREAM_CREATING; + s->direction = PA_STREAM_UPLOAD; + s->sample_spec = *ss; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_put_sample_spec(t, ss); + pa_tagstruct_putu32(t, length); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); + + return s; +} + +static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + if (s->finish_sample_callback) + s->finish_sample_callback(s, 0, s->finish_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->finish_sample_callback) + s->finish_sample_callback(s, 1, s->finish_sample_userdata); +} + +void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(p); + + p->finish_sample_callback = cb; + p->finish_sample_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = p->context->ctag++); + pa_tagstruct_putu32(t, p->channel); + pa_pstream_send_tagstruct(p->context->pstream, t); + pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); +} + +static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->play_sample_callback) + c->play_sample_callback(c, 0, c->play_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->play_sample_callback) + c->play_sample_callback(c, 1, c->play_sample_userdata); +} + +void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c && name && *name && (!dev || *dev)); + + c->play_sample_callback = cb; + c->play_sample_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_puts(t, dev ? dev : ""); + pa_tagstruct_putu32(t, volume); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); +} + +static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->remove_sample_callback) + c->remove_sample_callback(c, 0, c->remove_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->remove_sample_callback) + c->remove_sample_callback(c, 1, c->remove_sample_userdata); +} + +void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c && name); + + c->remove_sample_callback = cb; + c->remove_sample_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); +} + +static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + struct pa_server_info i; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_server_info_callback) + c->get_server_info_callback(c, NULL, c->get_server_info_userdata); + return; + } + + if (pa_tagstruct_gets(t, &i.server_name) < 0 || + pa_tagstruct_gets(t, &i.server_version) < 0 || + pa_tagstruct_gets(t, &i.user_name) < 0 || + pa_tagstruct_gets(t, &i.host_name) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_server_info_callback) + c->get_server_info_callback(c, &i, c->get_server_info_userdata); +} + +void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_server_info_callback = cb; + c->get_server_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); +} + +static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_sink_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.volume) < 0 || + pa_tagstruct_getu32(t, &i.monitor_source) < 0 || + pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || + pa_tagstruct_getu32(t, &i.latency) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); +} + +void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_sink_info_callback = cb; + c->get_sink_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); +} + +static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_source_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || + pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); +} + +void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_source_info_callback = cb; + c->get_source_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); +} + +void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { + struct pa_tagstruct *t; + assert(c); + + c->subscribe_callback = cb; + c->subscribe_userdata = userdata; + c->subscribe_mask = m; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); + pa_tagstruct_putu32(t, c->ctag++); + pa_tagstruct_putu32(t, cb ? m : 0); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + enum pa_subscription_event_type e; + uint32_t index; + assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); + + if (pa_tagstruct_getu32(t, &e) < 0 || + pa_tagstruct_getu32(t, &index) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) + c->subscribe_callback(c, e, index, c->subscribe_userdata); +} + +void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_sink_info_callback = cb; + c->get_sink_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); +} + +void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_source_info_callback = cb; + c->get_source_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); +} + +static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_client_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.protocol_name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); +} + + +void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_client_info_callback = cb; + c->get_client_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +} + +void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_client_info_callback = cb; + c->get_client_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +} + +static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_module_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.argument) < 0 || + pa_tagstruct_getu32(t, &i.n_used) < 0 || + pa_tagstruct_getu32(t, &i.auto_unload) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); +} + +void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_module_info_callback = cb; + c->get_module_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); +} + +void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_module_info_callback = cb; + c->get_module_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); +} diff --git a/polyp/polyplib-stream.h b/polyp/polyplib-stream.h new file mode 100644 index 00000000..a0dd9f9c --- /dev/null +++ b/polyp/polyplib-stream.h @@ -0,0 +1,178 @@ +#ifndef foopolyplibhfoo +#define foopolyplibhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "sample.h" +#include "polyplib-def.h" +#include "mainloop-api.h" + +#ifdef __cplusplus +//extern "C" { +#endif + +struct pa_context; +struct pa_stream; + +struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); +void pa_context_unref(struct pa_context *c); +struct pa_context* pa_context_ref(struct pa_context *c); + +int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); +int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); +void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); + +int pa_context_is_dead(struct pa_context *c); +int pa_context_is_ready(struct pa_context *c); +int pa_context_errno(struct pa_context *c); + +int pa_context_is_pending(struct pa_context *c); + +struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); +void pa_stream_unref(struct pa_stream *s); +struct pa_stream *pa_stream_ref(struct pa_stream *s); + +void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); + +void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); + +void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); +void pa_stream_write(struct pa_stream *p, const void *data, size_t length); +size_t pa_stream_writable_size(struct pa_stream *p); + +void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); + +int pa_stream_is_dead(struct pa_stream *p); +int pa_stream_is_ready(struct pa_stream*p); + +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); + +struct pa_context* pa_stream_get_context(struct pa_stream *p); + +uint32_t pa_stream_get_index(struct pa_stream *s); + +struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); +void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); + +void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +struct pa_sink_info { + const char *name; + uint32_t index; + const char *description; + struct pa_sample_spec sample_spec; + uint32_t owner_module; + uint32_t volume; + uint32_t monitor_source; + const char *monitor_source_name; + uint32_t latency; +}; + +void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); + +struct pa_source_info { + const char *name; + uint32_t index; + const char *description; + struct pa_sample_spec sample_spec; + uint32_t owner_module; + uint32_t monitor_of_sink; + const char *monitor_of_sink_name; +}; + +void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); + +struct pa_server_info { + const char *user_name; + const char *host_name; + const char *server_version; + const char *server_name; + struct pa_sample_spec sample_spec; +}; + +void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); + +struct pa_module_info { + uint32_t index; + const char*name, *argument; + uint32_t n_used, auto_unload; +}; + +void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); + +struct pa_client_info { + uint32_t index; + const char *name; + uint32_t owner_module; + const char *protocol_name; +}; + +void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); + +struct pa_sink_input_info { + uint32_t index; + const char *name; + uint32_t owner_module; + uint32_t owner_client; + uint32_t sink; + struct pa_sample_spec sample_spec; + uint32_t volume; + uint32_t latency; +}; + +void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); + +struct pa_source_output_info { + uint32_t index; + const char *name; + uint32_t owner_module; + uint32_t owner_client; + uint32_t source; + struct pa_sample_spec sample_spec; +}; + +void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); + +void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +void pa_context_exit(struct pa_context *c); +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); + +void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/polyp/polyplib-subscribe.c b/polyp/polyplib-subscribe.c new file mode 100644 index 00000000..35001d3d --- /dev/null +++ b/polyp/polyplib-subscribe.c @@ -0,0 +1,1550 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "polyplib.h" +#include "native-common.h" +#include "pdispatch.h" +#include "pstream.h" +#include "dynarray.h" +#include "socket-client.h" +#include "pstream-util.h" +#include "authkey.h" +#include "util.h" +#include "xmalloc.h" + +#define DEFAULT_MAXLENGTH 204800 +#define DEFAULT_TLENGTH 10240 +#define DEFAULT_PREBUF 4096 +#define DEFAULT_MINREQ 1024 +#define DEFAULT_FRAGSIZE 1024 + +#define DEFAULT_TIMEOUT (5*60) +#define DEFAULT_SERVER "/tmp/polypaudio/native" +#define DEFAULT_PORT "4713" + +struct pa_context { + char *name; + struct pa_mainloop_api* mainloop; + struct pa_socket_client *client; + struct pa_pstream *pstream; + struct pa_pdispatch *pdispatch; + struct pa_dynarray *record_streams, *playback_streams; + struct pa_stream *first_stream; + uint32_t ctag; + uint32_t error; + enum { + CONTEXT_UNCONNECTED, + CONTEXT_CONNECTING, + CONTEXT_AUTHORIZING, + CONTEXT_SETTING_NAME, + CONTEXT_READY, + CONTEXT_DEAD + } state; + + void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); + void *connect_complete_userdata; + + void (*drain_complete_callback)(struct pa_context*c, void *userdata); + void *drain_complete_userdata; + + void (*die_callback)(struct pa_context*c, void *userdata); + void *die_userdata; + + void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); + void *stat_userdata; + + void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); + void *play_sample_userdata; + + void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); + void *remove_sample_userdata; + + void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); + void *get_server_info_userdata; + + void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); + void *get_sink_info_userdata; + + void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); + void *get_source_info_userdata; + + void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); + void *subscribe_userdata; + enum pa_subscription_mask subscribe_mask; + + void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); + void *get_client_info_userdata; + + void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); + void *get_module_info_userdata; + + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; +}; + +struct pa_stream { + struct pa_context *context; + struct pa_stream *next, *previous; + + char *name; + struct pa_buffer_attr buffer_attr; + struct pa_sample_spec sample_spec; + uint32_t channel; + int channel_valid; + uint32_t device_index; + enum pa_stream_direction direction; + + enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; + uint32_t requested_bytes; + + void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); + void *read_userdata; + + void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); + void *write_userdata; + + void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); + void *create_complete_userdata; + + void (*drain_complete_callback)(struct pa_stream *s, void *userdata); + void *drain_complete_userdata; + + void (*die_callback)(struct pa_stream*c, void *userdata); + void *die_userdata; + + void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); + void *get_latency_userdata; + + void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); + void *finish_sample_userdata; +}; + +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); + +static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = { NULL }, + [PA_COMMAND_REPLY] = { NULL }, + [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_EXIT] = { NULL }, + [PA_COMMAND_REQUEST] = { command_request }, + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, + [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, + [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, +}; + +struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { + struct pa_context *c; + assert(mainloop && name); + + c = pa_xmalloc(sizeof(struct pa_context)); + c->name = pa_xstrdup(name); + c->mainloop = mainloop; + c->client = NULL; + c->pstream = NULL; + c->pdispatch = NULL; + c->playback_streams = pa_dynarray_new(); + assert(c->playback_streams); + c->record_streams = pa_dynarray_new(); + assert(c->record_streams); + c->first_stream = NULL; + c->error = PA_ERROR_OK; + c->state = CONTEXT_UNCONNECTED; + c->ctag = 0; + + c->connect_complete_callback = NULL; + c->connect_complete_userdata = NULL; + + c->drain_complete_callback = NULL; + c->drain_complete_userdata = NULL; + + c->die_callback = NULL; + c->die_userdata = NULL; + + c->stat_callback = NULL; + c->stat_userdata = NULL; + + c->play_sample_callback = NULL; + c->play_sample_userdata = NULL; + + c->remove_sample_callback = NULL; + c->remove_sample_userdata = NULL; + + c->get_server_info_callback = NULL; + c->get_server_info_userdata = NULL; + + c->get_sink_info_callback = NULL; + c->get_sink_info_userdata = NULL; + + c->get_source_info_callback = NULL; + c->get_source_info_userdata = NULL; + + c->subscribe_callback = NULL; + c->subscribe_userdata = NULL; + + c->get_client_info_callback = NULL; + c->get_client_info_userdata = NULL; + + c->get_module_info_callback = NULL; + c->get_module_info_userdata = NULL; + + pa_check_for_sigpipe(); + return c; +} + +void pa_context_free(struct pa_context *c) { + assert(c); + + while (c->first_stream) + pa_stream_free(c->first_stream); + + if (c->client) + pa_socket_client_free(c->client); + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + if (c->pstream) + pa_pstream_free(c->pstream); + if (c->record_streams) + pa_dynarray_free(c->record_streams, NULL, NULL); + if (c->playback_streams) + pa_dynarray_free(c->playback_streams, NULL, NULL); + + pa_xfree(c->name); + pa_xfree(c); +} + +static void stream_dead(struct pa_stream *s) { + assert(s); + + if (s->state == STREAM_DEAD) + return; + + if (s->state == STREAM_READY) { + s->state = STREAM_DEAD; + if (s->die_callback) + s->die_callback(s, s->die_userdata); + } else + s->state = STREAM_DEAD; +} + +static void context_dead(struct pa_context *c) { + struct pa_stream *s; + assert(c); + + if (c->state == CONTEXT_DEAD) + return; + + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + c->pdispatch = NULL; + + if (c->pstream) + pa_pstream_free(c->pstream); + c->pstream = NULL; + + if (c->client) + pa_socket_client_free(c->client); + c->client = NULL; + + for (s = c->first_stream; s; s = s->next) + stream_dead(s); + + if (c->state == CONTEXT_READY) { + c->state = CONTEXT_DEAD; + if (c->die_callback) + c->die_callback(c, c->die_userdata); + } else + c->state = CONTEXT_DEAD; +} + +static void pstream_die_callback(struct pa_pstream *p, void *userdata) { + struct pa_context *c = userdata; + assert(p && c); + c->error = PA_ERROR_CONNECTIONTERMINATED; + context_dead(c); +} + +static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { + struct pa_context *c = userdata; + assert(p && packet && c); + + if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { + fprintf(stderr, "polyp.c: invalid packet.\n"); + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + } +} + +static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + assert(p && chunk && c && chunk->memblock && chunk->memblock->data); + + if (!(s = pa_dynarray_get(c->record_streams, channel))) + return; + + if (s->read_callback) + s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); +} + +static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { + assert(c && t); + + if (command == PA_COMMAND_ERROR) { + if (pa_tagstruct_getu32(t, &c->error) < 0) { + c->error = PA_ERROR_PROTOCOL; + return -1; + } + + return 0; + } + + c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; + return -1; +} + +static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); + + if (command != PA_COMMAND_REPLY) { + handle_error(c, command, t); + context_dead(c); + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return; + } + + if (c->state == CONTEXT_AUTHORIZING) { + struct pa_tagstruct *t; + c->state = CONTEXT_SETTING_NAME; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, c->name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + } else { + assert(c->state == CONTEXT_SETTING_NAME); + + c->state = CONTEXT_READY; + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 1, c->connect_complete_userdata); + } + + return; +} + +static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { + struct pa_context *c = userdata; + struct pa_tagstruct *t; + uint32_t tag; + assert(client && c && c->state == CONTEXT_CONNECTING); + + pa_socket_client_free(client); + c->client = NULL; + + if (!io) { + c->error = PA_ERROR_CONNECTIONREFUSED; + context_dead(c); + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return; + } + + c->pstream = pa_pstream_new(c->mainloop, io); + assert(c->pstream); + pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); + pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); + pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); + + c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); + assert(c->pdispatch); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_AUTH); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + c->state = CONTEXT_AUTHORIZING; +} + +static struct sockaddr *resolve_server(const char *server, size_t *len) { + struct sockaddr *sa; + struct addrinfo hints, *result = NULL; + char *port; + assert(server && len); + + if ((port = strrchr(server, ':'))) + port++; + if (!port) + port = DEFAULT_PORT; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + if (getaddrinfo(server, port, &hints, &result) != 0) + return NULL; + assert(result); + + sa = pa_xmalloc(*len = result->ai_addrlen); + memcpy(sa, result->ai_addr, *len); + + freeaddrinfo(result); + + return sa; +} + +int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { + assert(c && c->state == CONTEXT_UNCONNECTED); + + if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { + c->error = PA_ERROR_AUTHKEY; + return -1; + } + + if (!server) + if (!(server = getenv("POLYP_SERVER"))) + server = DEFAULT_SERVER; + + assert(!c->client); + + if (*server == '/') { + if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + } else { + struct sockaddr* sa; + size_t sa_len; + + if (!(sa = resolve_server(server, &sa_len))) { + c->error = PA_ERROR_INVALIDSERVER; + return -1; + } + + c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); + pa_xfree(sa); + + if (!c->client) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + } + + c->connect_complete_callback = complete; + c->connect_complete_userdata = userdata; + + pa_socket_client_set_callback(c->client, on_connection, c); + c->state = CONTEXT_CONNECTING; + + return 0; +} + +int pa_context_is_dead(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_DEAD; +} + +int pa_context_is_ready(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_READY; +} + +int pa_context_errno(struct pa_context *c) { + assert(c); + return c->error; +} + +void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { + assert(c); + c->die_callback = cb; + c->die_userdata = userdata; +} + +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + uint32_t channel; + assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) + return; + + c->error = PA_ERROR_KILLED; + stream_dead(s); +} + +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s; + struct pa_context *c = userdata; + uint32_t bytes, channel; + assert(pd && command == PA_COMMAND_REQUEST && t && c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + pa_tagstruct_getu32(t, &bytes) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (!(s = pa_dynarray_get(c->playback_streams, channel))) + return; + + if (s->state != STREAM_READY) + return; + + s->requested_bytes += bytes; + + if (s->requested_bytes && s->write_callback) + s->write_callback(s, s->requested_bytes, s->write_userdata); +} + +static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s && s->state == STREAM_CREATING); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + if (s->create_complete_callback) + s->create_complete_callback(s, 0, s->create_complete_userdata); + + return; + } + + if (pa_tagstruct_getu32(t, &s->channel) < 0 || + ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + s->channel_valid = 1; + pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); + + s->state = STREAM_READY; + if (s->create_complete_callback) + s->create_complete_callback(s, 1, s->create_complete_userdata); +} + +static void create_stream(struct pa_stream *s, const char *dev) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s); + + s->state = STREAM_CREATING; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_puts(t, s->name); + pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_puts(t, dev ? dev : ""); + pa_tagstruct_putu32(t, s->buffer_attr.maxlength); + if (s->direction == PA_STREAM_PLAYBACK) { + pa_tagstruct_putu32(t, s->buffer_attr.tlength); + pa_tagstruct_putu32(t, s->buffer_attr.prebuf); + pa_tagstruct_putu32(t, s->buffer_attr.minreq); + } else + pa_tagstruct_putu32(t, s->buffer_attr.fragsize); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); +} + +static struct pa_stream *internal_stream_new(struct pa_context *c) { + struct pa_stream *s; + + s = pa_xmalloc(sizeof(struct pa_stream)); + s->context = c; + + s->read_callback = NULL; + s->read_userdata = NULL; + s->write_callback = NULL; + s->write_userdata = NULL; + s->die_callback = NULL; + s->die_userdata = NULL; + s->create_complete_callback = NULL; + s->create_complete_userdata = NULL; + s->get_latency_callback = NULL; + s->get_latency_userdata = NULL; + s->finish_sample_callback = NULL; + s->finish_sample_userdata = NULL; + + s->name = NULL; + s->state = STREAM_CREATING; + s->requested_bytes = 0; + s->channel = 0; + s->channel_valid = 0; + s->device_index = (uint32_t) -1; + + memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); + + s->next = c->first_stream; + if (s->next) + s->next->previous = s; + s->previous = NULL; + c->first_stream = s; + + return s; +} + +struct pa_stream* pa_stream_new( + struct pa_context *c, + enum pa_stream_direction dir, + const char *dev, + const char *name, + const struct pa_sample_spec *ss, + const struct pa_buffer_attr *attr, + void (*complete) (struct pa_stream*s, int success, void *userdata), + void *userdata) { + + struct pa_stream *s; + + assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); + + s = internal_stream_new(c); + assert(s); + + s->create_complete_callback = complete; + s->create_complete_userdata = userdata; + s->name = pa_xstrdup(name); + s->state = STREAM_CREATING; + s->direction = dir; + s->sample_spec = *ss; + if (attr) + s->buffer_attr = *attr; + else { + s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; + s->buffer_attr.tlength = DEFAULT_TLENGTH; + s->buffer_attr.prebuf = DEFAULT_PREBUF; + s->buffer_attr.minreq = DEFAULT_MINREQ; + s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; + } + + create_stream(s, dev); + + return s; +} + +void pa_stream_free(struct pa_stream *s) { + assert(s && s->context); + + if (s->context->pdispatch) + pa_pdispatch_unregister_reply(s->context->pdispatch, s); + + pa_xfree(s->name); + + if (s->channel_valid && s->context->state == CONTEXT_READY) { + struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : + (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); + pa_tagstruct_putu32(t, s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + } + + if (s->channel_valid) + pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); + + if (s->next) + s->next->previous = s->previous; + if (s->previous) + s->previous->next = s->next; + else + s->context->first_stream = s->next; + + pa_xfree(s); +} + +void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { + s->write_callback = cb; + s->write_userdata = userdata; +} + +void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { + struct pa_memchunk chunk; + assert(s && s->context && data && length && s->state == STREAM_READY); + + chunk.memblock = pa_memblock_new(length); + assert(chunk.memblock && chunk.memblock->data); + memcpy(chunk.memblock->data, data, length); + chunk.index = 0; + chunk.length = length; + + pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); + pa_memblock_unref(chunk.memblock); + + /*fprintf(stderr, "Sent %u bytes\n", length);*/ + + if (length < s->requested_bytes) + s->requested_bytes -= length; + else + s->requested_bytes = 0; +} + +size_t pa_stream_writable_size(struct pa_stream *s) { + assert(s && s->state == STREAM_READY); + return s->requested_bytes; +} + +void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { + assert(s && cb); + s->read_callback = cb; + s->read_userdata = userdata; +} + +int pa_stream_is_dead(struct pa_stream *s) { + return s->state == STREAM_DEAD; +} + +int pa_stream_is_ready(struct pa_stream*s) { + return s->state == STREAM_READY; +} + +void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { + assert(s); + s->die_callback = cb; + s->die_userdata = userdata; +} + +int pa_context_is_pending(struct pa_context *c) { + assert(c); + + if (c->state != CONTEXT_READY) + return 0; + + return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); +} + +struct pa_context* pa_stream_get_context(struct pa_stream *p) { + assert(p); + return p->context; +} + +static void set_dispatch_callbacks(struct pa_context *c); + +static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void set_dispatch_callbacks(struct pa_context *c) { + assert(c && c->state == CONTEXT_READY); + + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + + if (pa_pdispatch_is_pending(c->pdispatch)) { + pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); + return; + } + + if (pa_pstream_is_pending(c->pstream)) { + pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); + return; + } + + assert(c->drain_complete_callback); + c->drain_complete_callback(c, c->drain_complete_userdata); +} + +int pa_context_drain( + struct pa_context *c, + void (*complete) (struct pa_context*c, void *userdata), + void *userdata) { + + assert(c && c->state == CONTEXT_READY); + + if (complete == NULL) { + c->drain_complete_callback = NULL; + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + return 0; + } + + if (!pa_context_is_pending(c)) + return -1; + + c->drain_complete_callback = complete; + c->drain_complete_userdata = userdata; + + set_dispatch_callbacks(c); + + return 0; +} + +static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + return; + } + + if (s->state != STREAM_READY) + return; + + if (!pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->drain_complete_callback) { + void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; + s->drain_complete_callback = NULL; + temp(s, s->drain_complete_userdata); + } +} + + +void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s && s->state == STREAM_READY); + + if (!complete) { + s->drain_complete_callback = NULL; + return; + } + + s->drain_complete_callback = complete; + s->drain_complete_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); +} + +void pa_context_exit(struct pa_context *c) { + struct pa_tagstruct *t; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_EXIT); + pa_tagstruct_putu32(t, c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + uint32_t total, count; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &count) < 0 || + pa_tagstruct_getu32(t, &total) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, count, total, c->stat_userdata); +} + +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + c->stat_callback = cb; + c->stat_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_STAT); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); +} + +static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + uint32_t latency; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &latency) < 0 || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, latency, s->get_latency_userdata); +} + +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + p->get_latency_callback = cb; + p->get_latency_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); + pa_tagstruct_putu32(t, tag = p->context->ctag++); + pa_tagstruct_putu32(t, p->channel); + pa_pstream_send_tagstruct(p->context->pstream, t); + pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); +} + +struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { + struct pa_stream *s; + struct pa_tagstruct *t; + uint32_t tag; + + s = internal_stream_new(c); + assert(s); + + s->create_complete_callback = cb; + s->create_complete_userdata = userdata; + s->name = pa_xstrdup(name); + s->state = STREAM_CREATING; + s->direction = PA_STREAM_UPLOAD; + s->sample_spec = *ss; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_put_sample_spec(t, ss); + pa_tagstruct_putu32(t, length); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); + + return s; +} + +static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + if (s->finish_sample_callback) + s->finish_sample_callback(s, 0, s->finish_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->finish_sample_callback) + s->finish_sample_callback(s, 1, s->finish_sample_userdata); +} + +void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(p); + + p->finish_sample_callback = cb; + p->finish_sample_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = p->context->ctag++); + pa_tagstruct_putu32(t, p->channel); + pa_pstream_send_tagstruct(p->context->pstream, t); + pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); +} + +static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->play_sample_callback) + c->play_sample_callback(c, 0, c->play_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->play_sample_callback) + c->play_sample_callback(c, 1, c->play_sample_userdata); +} + +void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c && name && *name && (!dev || *dev)); + + c->play_sample_callback = cb; + c->play_sample_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_puts(t, dev ? dev : ""); + pa_tagstruct_putu32(t, volume); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); +} + +static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->remove_sample_callback) + c->remove_sample_callback(c, 0, c->remove_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->remove_sample_callback) + c->remove_sample_callback(c, 1, c->remove_sample_userdata); +} + +void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c && name); + + c->remove_sample_callback = cb; + c->remove_sample_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); +} + +static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + struct pa_server_info i; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_server_info_callback) + c->get_server_info_callback(c, NULL, c->get_server_info_userdata); + return; + } + + if (pa_tagstruct_gets(t, &i.server_name) < 0 || + pa_tagstruct_gets(t, &i.server_version) < 0 || + pa_tagstruct_gets(t, &i.user_name) < 0 || + pa_tagstruct_gets(t, &i.host_name) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_server_info_callback) + c->get_server_info_callback(c, &i, c->get_server_info_userdata); +} + +void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_server_info_callback = cb; + c->get_server_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); +} + +static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_sink_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.volume) < 0 || + pa_tagstruct_getu32(t, &i.monitor_source) < 0 || + pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || + pa_tagstruct_getu32(t, &i.latency) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); +} + +void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_sink_info_callback = cb; + c->get_sink_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); +} + +static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_source_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || + pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); +} + +void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_source_info_callback = cb; + c->get_source_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); +} + +void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { + struct pa_tagstruct *t; + assert(c); + + c->subscribe_callback = cb; + c->subscribe_userdata = userdata; + c->subscribe_mask = m; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); + pa_tagstruct_putu32(t, c->ctag++); + pa_tagstruct_putu32(t, cb ? m : 0); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + enum pa_subscription_event_type e; + uint32_t index; + assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); + + if (pa_tagstruct_getu32(t, &e) < 0 || + pa_tagstruct_getu32(t, &index) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) + c->subscribe_callback(c, e, index, c->subscribe_userdata); +} + +void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_sink_info_callback = cb; + c->get_sink_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); +} + +void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_source_info_callback = cb; + c->get_source_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); +} + +static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_client_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.protocol_name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); +} + + +void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_client_info_callback = cb; + c->get_client_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +} + +void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_client_info_callback = cb; + c->get_client_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +} + +static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_module_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.argument) < 0 || + pa_tagstruct_getu32(t, &i.n_used) < 0 || + pa_tagstruct_getu32(t, &i.auto_unload) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); +} + +void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_module_info_callback = cb; + c->get_module_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); +} + +void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_module_info_callback = cb; + c->get_module_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); +} diff --git a/polyp/polyplib-subscribe.h b/polyp/polyplib-subscribe.h new file mode 100644 index 00000000..a0dd9f9c --- /dev/null +++ b/polyp/polyplib-subscribe.h @@ -0,0 +1,178 @@ +#ifndef foopolyplibhfoo +#define foopolyplibhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "sample.h" +#include "polyplib-def.h" +#include "mainloop-api.h" + +#ifdef __cplusplus +//extern "C" { +#endif + +struct pa_context; +struct pa_stream; + +struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); +void pa_context_unref(struct pa_context *c); +struct pa_context* pa_context_ref(struct pa_context *c); + +int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); +int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); +void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); + +int pa_context_is_dead(struct pa_context *c); +int pa_context_is_ready(struct pa_context *c); +int pa_context_errno(struct pa_context *c); + +int pa_context_is_pending(struct pa_context *c); + +struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); +void pa_stream_unref(struct pa_stream *s); +struct pa_stream *pa_stream_ref(struct pa_stream *s); + +void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); + +void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); + +void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); +void pa_stream_write(struct pa_stream *p, const void *data, size_t length); +size_t pa_stream_writable_size(struct pa_stream *p); + +void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); + +int pa_stream_is_dead(struct pa_stream *p); +int pa_stream_is_ready(struct pa_stream*p); + +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); + +struct pa_context* pa_stream_get_context(struct pa_stream *p); + +uint32_t pa_stream_get_index(struct pa_stream *s); + +struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); +void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); + +void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +struct pa_sink_info { + const char *name; + uint32_t index; + const char *description; + struct pa_sample_spec sample_spec; + uint32_t owner_module; + uint32_t volume; + uint32_t monitor_source; + const char *monitor_source_name; + uint32_t latency; +}; + +void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); + +struct pa_source_info { + const char *name; + uint32_t index; + const char *description; + struct pa_sample_spec sample_spec; + uint32_t owner_module; + uint32_t monitor_of_sink; + const char *monitor_of_sink_name; +}; + +void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); + +struct pa_server_info { + const char *user_name; + const char *host_name; + const char *server_version; + const char *server_name; + struct pa_sample_spec sample_spec; +}; + +void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); + +struct pa_module_info { + uint32_t index; + const char*name, *argument; + uint32_t n_used, auto_unload; +}; + +void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); + +struct pa_client_info { + uint32_t index; + const char *name; + uint32_t owner_module; + const char *protocol_name; +}; + +void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); + +struct pa_sink_input_info { + uint32_t index; + const char *name; + uint32_t owner_module; + uint32_t owner_client; + uint32_t sink; + struct pa_sample_spec sample_spec; + uint32_t volume; + uint32_t latency; +}; + +void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); + +struct pa_source_output_info { + uint32_t index; + const char *name; + uint32_t owner_module; + uint32_t owner_client; + uint32_t source; + struct pa_sample_spec sample_spec; +}; + +void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); + +void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +void pa_context_exit(struct pa_context *c); +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); + +void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); + +#ifdef __cplusplus +} +#endif + +#endif -- cgit From 821afd66b0598aaa6851796ee27ca506302a21cd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 13 Aug 2004 13:24:48 +0000 Subject: add internal header file for polyplib git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@119 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/polyplib-internal.h | 1550 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1550 insertions(+) create mode 100644 polyp/polyplib-internal.h diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h new file mode 100644 index 00000000..35001d3d --- /dev/null +++ b/polyp/polyplib-internal.h @@ -0,0 +1,1550 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "polyplib.h" +#include "native-common.h" +#include "pdispatch.h" +#include "pstream.h" +#include "dynarray.h" +#include "socket-client.h" +#include "pstream-util.h" +#include "authkey.h" +#include "util.h" +#include "xmalloc.h" + +#define DEFAULT_MAXLENGTH 204800 +#define DEFAULT_TLENGTH 10240 +#define DEFAULT_PREBUF 4096 +#define DEFAULT_MINREQ 1024 +#define DEFAULT_FRAGSIZE 1024 + +#define DEFAULT_TIMEOUT (5*60) +#define DEFAULT_SERVER "/tmp/polypaudio/native" +#define DEFAULT_PORT "4713" + +struct pa_context { + char *name; + struct pa_mainloop_api* mainloop; + struct pa_socket_client *client; + struct pa_pstream *pstream; + struct pa_pdispatch *pdispatch; + struct pa_dynarray *record_streams, *playback_streams; + struct pa_stream *first_stream; + uint32_t ctag; + uint32_t error; + enum { + CONTEXT_UNCONNECTED, + CONTEXT_CONNECTING, + CONTEXT_AUTHORIZING, + CONTEXT_SETTING_NAME, + CONTEXT_READY, + CONTEXT_DEAD + } state; + + void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); + void *connect_complete_userdata; + + void (*drain_complete_callback)(struct pa_context*c, void *userdata); + void *drain_complete_userdata; + + void (*die_callback)(struct pa_context*c, void *userdata); + void *die_userdata; + + void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); + void *stat_userdata; + + void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); + void *play_sample_userdata; + + void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); + void *remove_sample_userdata; + + void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); + void *get_server_info_userdata; + + void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); + void *get_sink_info_userdata; + + void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); + void *get_source_info_userdata; + + void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); + void *subscribe_userdata; + enum pa_subscription_mask subscribe_mask; + + void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); + void *get_client_info_userdata; + + void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); + void *get_module_info_userdata; + + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; +}; + +struct pa_stream { + struct pa_context *context; + struct pa_stream *next, *previous; + + char *name; + struct pa_buffer_attr buffer_attr; + struct pa_sample_spec sample_spec; + uint32_t channel; + int channel_valid; + uint32_t device_index; + enum pa_stream_direction direction; + + enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; + uint32_t requested_bytes; + + void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); + void *read_userdata; + + void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); + void *write_userdata; + + void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); + void *create_complete_userdata; + + void (*drain_complete_callback)(struct pa_stream *s, void *userdata); + void *drain_complete_userdata; + + void (*die_callback)(struct pa_stream*c, void *userdata); + void *die_userdata; + + void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); + void *get_latency_userdata; + + void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); + void *finish_sample_userdata; +}; + +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); + +static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = { NULL }, + [PA_COMMAND_REPLY] = { NULL }, + [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_EXIT] = { NULL }, + [PA_COMMAND_REQUEST] = { command_request }, + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, + [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, + [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, +}; + +struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { + struct pa_context *c; + assert(mainloop && name); + + c = pa_xmalloc(sizeof(struct pa_context)); + c->name = pa_xstrdup(name); + c->mainloop = mainloop; + c->client = NULL; + c->pstream = NULL; + c->pdispatch = NULL; + c->playback_streams = pa_dynarray_new(); + assert(c->playback_streams); + c->record_streams = pa_dynarray_new(); + assert(c->record_streams); + c->first_stream = NULL; + c->error = PA_ERROR_OK; + c->state = CONTEXT_UNCONNECTED; + c->ctag = 0; + + c->connect_complete_callback = NULL; + c->connect_complete_userdata = NULL; + + c->drain_complete_callback = NULL; + c->drain_complete_userdata = NULL; + + c->die_callback = NULL; + c->die_userdata = NULL; + + c->stat_callback = NULL; + c->stat_userdata = NULL; + + c->play_sample_callback = NULL; + c->play_sample_userdata = NULL; + + c->remove_sample_callback = NULL; + c->remove_sample_userdata = NULL; + + c->get_server_info_callback = NULL; + c->get_server_info_userdata = NULL; + + c->get_sink_info_callback = NULL; + c->get_sink_info_userdata = NULL; + + c->get_source_info_callback = NULL; + c->get_source_info_userdata = NULL; + + c->subscribe_callback = NULL; + c->subscribe_userdata = NULL; + + c->get_client_info_callback = NULL; + c->get_client_info_userdata = NULL; + + c->get_module_info_callback = NULL; + c->get_module_info_userdata = NULL; + + pa_check_for_sigpipe(); + return c; +} + +void pa_context_free(struct pa_context *c) { + assert(c); + + while (c->first_stream) + pa_stream_free(c->first_stream); + + if (c->client) + pa_socket_client_free(c->client); + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + if (c->pstream) + pa_pstream_free(c->pstream); + if (c->record_streams) + pa_dynarray_free(c->record_streams, NULL, NULL); + if (c->playback_streams) + pa_dynarray_free(c->playback_streams, NULL, NULL); + + pa_xfree(c->name); + pa_xfree(c); +} + +static void stream_dead(struct pa_stream *s) { + assert(s); + + if (s->state == STREAM_DEAD) + return; + + if (s->state == STREAM_READY) { + s->state = STREAM_DEAD; + if (s->die_callback) + s->die_callback(s, s->die_userdata); + } else + s->state = STREAM_DEAD; +} + +static void context_dead(struct pa_context *c) { + struct pa_stream *s; + assert(c); + + if (c->state == CONTEXT_DEAD) + return; + + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + c->pdispatch = NULL; + + if (c->pstream) + pa_pstream_free(c->pstream); + c->pstream = NULL; + + if (c->client) + pa_socket_client_free(c->client); + c->client = NULL; + + for (s = c->first_stream; s; s = s->next) + stream_dead(s); + + if (c->state == CONTEXT_READY) { + c->state = CONTEXT_DEAD; + if (c->die_callback) + c->die_callback(c, c->die_userdata); + } else + c->state = CONTEXT_DEAD; +} + +static void pstream_die_callback(struct pa_pstream *p, void *userdata) { + struct pa_context *c = userdata; + assert(p && c); + c->error = PA_ERROR_CONNECTIONTERMINATED; + context_dead(c); +} + +static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { + struct pa_context *c = userdata; + assert(p && packet && c); + + if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { + fprintf(stderr, "polyp.c: invalid packet.\n"); + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + } +} + +static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + assert(p && chunk && c && chunk->memblock && chunk->memblock->data); + + if (!(s = pa_dynarray_get(c->record_streams, channel))) + return; + + if (s->read_callback) + s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); +} + +static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { + assert(c && t); + + if (command == PA_COMMAND_ERROR) { + if (pa_tagstruct_getu32(t, &c->error) < 0) { + c->error = PA_ERROR_PROTOCOL; + return -1; + } + + return 0; + } + + c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; + return -1; +} + +static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); + + if (command != PA_COMMAND_REPLY) { + handle_error(c, command, t); + context_dead(c); + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return; + } + + if (c->state == CONTEXT_AUTHORIZING) { + struct pa_tagstruct *t; + c->state = CONTEXT_SETTING_NAME; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, c->name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + } else { + assert(c->state == CONTEXT_SETTING_NAME); + + c->state = CONTEXT_READY; + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 1, c->connect_complete_userdata); + } + + return; +} + +static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { + struct pa_context *c = userdata; + struct pa_tagstruct *t; + uint32_t tag; + assert(client && c && c->state == CONTEXT_CONNECTING); + + pa_socket_client_free(client); + c->client = NULL; + + if (!io) { + c->error = PA_ERROR_CONNECTIONREFUSED; + context_dead(c); + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return; + } + + c->pstream = pa_pstream_new(c->mainloop, io); + assert(c->pstream); + pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); + pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); + pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); + + c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); + assert(c->pdispatch); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_AUTH); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + c->state = CONTEXT_AUTHORIZING; +} + +static struct sockaddr *resolve_server(const char *server, size_t *len) { + struct sockaddr *sa; + struct addrinfo hints, *result = NULL; + char *port; + assert(server && len); + + if ((port = strrchr(server, ':'))) + port++; + if (!port) + port = DEFAULT_PORT; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + if (getaddrinfo(server, port, &hints, &result) != 0) + return NULL; + assert(result); + + sa = pa_xmalloc(*len = result->ai_addrlen); + memcpy(sa, result->ai_addr, *len); + + freeaddrinfo(result); + + return sa; +} + +int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { + assert(c && c->state == CONTEXT_UNCONNECTED); + + if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { + c->error = PA_ERROR_AUTHKEY; + return -1; + } + + if (!server) + if (!(server = getenv("POLYP_SERVER"))) + server = DEFAULT_SERVER; + + assert(!c->client); + + if (*server == '/') { + if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + } else { + struct sockaddr* sa; + size_t sa_len; + + if (!(sa = resolve_server(server, &sa_len))) { + c->error = PA_ERROR_INVALIDSERVER; + return -1; + } + + c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); + pa_xfree(sa); + + if (!c->client) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + } + + c->connect_complete_callback = complete; + c->connect_complete_userdata = userdata; + + pa_socket_client_set_callback(c->client, on_connection, c); + c->state = CONTEXT_CONNECTING; + + return 0; +} + +int pa_context_is_dead(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_DEAD; +} + +int pa_context_is_ready(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_READY; +} + +int pa_context_errno(struct pa_context *c) { + assert(c); + return c->error; +} + +void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { + assert(c); + c->die_callback = cb; + c->die_userdata = userdata; +} + +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + uint32_t channel; + assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) + return; + + c->error = PA_ERROR_KILLED; + stream_dead(s); +} + +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s; + struct pa_context *c = userdata; + uint32_t bytes, channel; + assert(pd && command == PA_COMMAND_REQUEST && t && c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + pa_tagstruct_getu32(t, &bytes) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (!(s = pa_dynarray_get(c->playback_streams, channel))) + return; + + if (s->state != STREAM_READY) + return; + + s->requested_bytes += bytes; + + if (s->requested_bytes && s->write_callback) + s->write_callback(s, s->requested_bytes, s->write_userdata); +} + +static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s && s->state == STREAM_CREATING); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + if (s->create_complete_callback) + s->create_complete_callback(s, 0, s->create_complete_userdata); + + return; + } + + if (pa_tagstruct_getu32(t, &s->channel) < 0 || + ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + s->channel_valid = 1; + pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); + + s->state = STREAM_READY; + if (s->create_complete_callback) + s->create_complete_callback(s, 1, s->create_complete_userdata); +} + +static void create_stream(struct pa_stream *s, const char *dev) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s); + + s->state = STREAM_CREATING; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_puts(t, s->name); + pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_puts(t, dev ? dev : ""); + pa_tagstruct_putu32(t, s->buffer_attr.maxlength); + if (s->direction == PA_STREAM_PLAYBACK) { + pa_tagstruct_putu32(t, s->buffer_attr.tlength); + pa_tagstruct_putu32(t, s->buffer_attr.prebuf); + pa_tagstruct_putu32(t, s->buffer_attr.minreq); + } else + pa_tagstruct_putu32(t, s->buffer_attr.fragsize); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); +} + +static struct pa_stream *internal_stream_new(struct pa_context *c) { + struct pa_stream *s; + + s = pa_xmalloc(sizeof(struct pa_stream)); + s->context = c; + + s->read_callback = NULL; + s->read_userdata = NULL; + s->write_callback = NULL; + s->write_userdata = NULL; + s->die_callback = NULL; + s->die_userdata = NULL; + s->create_complete_callback = NULL; + s->create_complete_userdata = NULL; + s->get_latency_callback = NULL; + s->get_latency_userdata = NULL; + s->finish_sample_callback = NULL; + s->finish_sample_userdata = NULL; + + s->name = NULL; + s->state = STREAM_CREATING; + s->requested_bytes = 0; + s->channel = 0; + s->channel_valid = 0; + s->device_index = (uint32_t) -1; + + memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); + + s->next = c->first_stream; + if (s->next) + s->next->previous = s; + s->previous = NULL; + c->first_stream = s; + + return s; +} + +struct pa_stream* pa_stream_new( + struct pa_context *c, + enum pa_stream_direction dir, + const char *dev, + const char *name, + const struct pa_sample_spec *ss, + const struct pa_buffer_attr *attr, + void (*complete) (struct pa_stream*s, int success, void *userdata), + void *userdata) { + + struct pa_stream *s; + + assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); + + s = internal_stream_new(c); + assert(s); + + s->create_complete_callback = complete; + s->create_complete_userdata = userdata; + s->name = pa_xstrdup(name); + s->state = STREAM_CREATING; + s->direction = dir; + s->sample_spec = *ss; + if (attr) + s->buffer_attr = *attr; + else { + s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; + s->buffer_attr.tlength = DEFAULT_TLENGTH; + s->buffer_attr.prebuf = DEFAULT_PREBUF; + s->buffer_attr.minreq = DEFAULT_MINREQ; + s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; + } + + create_stream(s, dev); + + return s; +} + +void pa_stream_free(struct pa_stream *s) { + assert(s && s->context); + + if (s->context->pdispatch) + pa_pdispatch_unregister_reply(s->context->pdispatch, s); + + pa_xfree(s->name); + + if (s->channel_valid && s->context->state == CONTEXT_READY) { + struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : + (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); + pa_tagstruct_putu32(t, s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + } + + if (s->channel_valid) + pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); + + if (s->next) + s->next->previous = s->previous; + if (s->previous) + s->previous->next = s->next; + else + s->context->first_stream = s->next; + + pa_xfree(s); +} + +void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { + s->write_callback = cb; + s->write_userdata = userdata; +} + +void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { + struct pa_memchunk chunk; + assert(s && s->context && data && length && s->state == STREAM_READY); + + chunk.memblock = pa_memblock_new(length); + assert(chunk.memblock && chunk.memblock->data); + memcpy(chunk.memblock->data, data, length); + chunk.index = 0; + chunk.length = length; + + pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); + pa_memblock_unref(chunk.memblock); + + /*fprintf(stderr, "Sent %u bytes\n", length);*/ + + if (length < s->requested_bytes) + s->requested_bytes -= length; + else + s->requested_bytes = 0; +} + +size_t pa_stream_writable_size(struct pa_stream *s) { + assert(s && s->state == STREAM_READY); + return s->requested_bytes; +} + +void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { + assert(s && cb); + s->read_callback = cb; + s->read_userdata = userdata; +} + +int pa_stream_is_dead(struct pa_stream *s) { + return s->state == STREAM_DEAD; +} + +int pa_stream_is_ready(struct pa_stream*s) { + return s->state == STREAM_READY; +} + +void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { + assert(s); + s->die_callback = cb; + s->die_userdata = userdata; +} + +int pa_context_is_pending(struct pa_context *c) { + assert(c); + + if (c->state != CONTEXT_READY) + return 0; + + return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); +} + +struct pa_context* pa_stream_get_context(struct pa_stream *p) { + assert(p); + return p->context; +} + +static void set_dispatch_callbacks(struct pa_context *c); + +static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void set_dispatch_callbacks(struct pa_context *c) { + assert(c && c->state == CONTEXT_READY); + + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + + if (pa_pdispatch_is_pending(c->pdispatch)) { + pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); + return; + } + + if (pa_pstream_is_pending(c->pstream)) { + pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); + return; + } + + assert(c->drain_complete_callback); + c->drain_complete_callback(c, c->drain_complete_userdata); +} + +int pa_context_drain( + struct pa_context *c, + void (*complete) (struct pa_context*c, void *userdata), + void *userdata) { + + assert(c && c->state == CONTEXT_READY); + + if (complete == NULL) { + c->drain_complete_callback = NULL; + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + return 0; + } + + if (!pa_context_is_pending(c)) + return -1; + + c->drain_complete_callback = complete; + c->drain_complete_userdata = userdata; + + set_dispatch_callbacks(c); + + return 0; +} + +static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + return; + } + + if (s->state != STREAM_READY) + return; + + if (!pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->drain_complete_callback) { + void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; + s->drain_complete_callback = NULL; + temp(s, s->drain_complete_userdata); + } +} + + +void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s && s->state == STREAM_READY); + + if (!complete) { + s->drain_complete_callback = NULL; + return; + } + + s->drain_complete_callback = complete; + s->drain_complete_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); +} + +void pa_context_exit(struct pa_context *c) { + struct pa_tagstruct *t; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_EXIT); + pa_tagstruct_putu32(t, c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + uint32_t total, count; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &count) < 0 || + pa_tagstruct_getu32(t, &total) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, count, total, c->stat_userdata); +} + +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + c->stat_callback = cb; + c->stat_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_STAT); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); +} + +static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + uint32_t latency; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &latency) < 0 || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, latency, s->get_latency_userdata); +} + +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + p->get_latency_callback = cb; + p->get_latency_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); + pa_tagstruct_putu32(t, tag = p->context->ctag++); + pa_tagstruct_putu32(t, p->channel); + pa_pstream_send_tagstruct(p->context->pstream, t); + pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); +} + +struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { + struct pa_stream *s; + struct pa_tagstruct *t; + uint32_t tag; + + s = internal_stream_new(c); + assert(s); + + s->create_complete_callback = cb; + s->create_complete_userdata = userdata; + s->name = pa_xstrdup(name); + s->state = STREAM_CREATING; + s->direction = PA_STREAM_UPLOAD; + s->sample_spec = *ss; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_put_sample_spec(t, ss); + pa_tagstruct_putu32(t, length); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); + + return s; +} + +static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + if (s->finish_sample_callback) + s->finish_sample_callback(s, 0, s->finish_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->finish_sample_callback) + s->finish_sample_callback(s, 1, s->finish_sample_userdata); +} + +void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(p); + + p->finish_sample_callback = cb; + p->finish_sample_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = p->context->ctag++); + pa_tagstruct_putu32(t, p->channel); + pa_pstream_send_tagstruct(p->context->pstream, t); + pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); +} + +static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->play_sample_callback) + c->play_sample_callback(c, 0, c->play_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->play_sample_callback) + c->play_sample_callback(c, 1, c->play_sample_userdata); +} + +void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c && name && *name && (!dev || *dev)); + + c->play_sample_callback = cb; + c->play_sample_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_puts(t, dev ? dev : ""); + pa_tagstruct_putu32(t, volume); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); +} + +static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->remove_sample_callback) + c->remove_sample_callback(c, 0, c->remove_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->remove_sample_callback) + c->remove_sample_callback(c, 1, c->remove_sample_userdata); +} + +void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c && name); + + c->remove_sample_callback = cb; + c->remove_sample_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); +} + +static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + struct pa_server_info i; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_server_info_callback) + c->get_server_info_callback(c, NULL, c->get_server_info_userdata); + return; + } + + if (pa_tagstruct_gets(t, &i.server_name) < 0 || + pa_tagstruct_gets(t, &i.server_version) < 0 || + pa_tagstruct_gets(t, &i.user_name) < 0 || + pa_tagstruct_gets(t, &i.host_name) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_server_info_callback) + c->get_server_info_callback(c, &i, c->get_server_info_userdata); +} + +void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_server_info_callback = cb; + c->get_server_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); +} + +static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_sink_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.volume) < 0 || + pa_tagstruct_getu32(t, &i.monitor_source) < 0 || + pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || + pa_tagstruct_getu32(t, &i.latency) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); +} + +void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_sink_info_callback = cb; + c->get_sink_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); +} + +static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_source_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || + pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); +} + +void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_source_info_callback = cb; + c->get_source_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); +} + +void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { + struct pa_tagstruct *t; + assert(c); + + c->subscribe_callback = cb; + c->subscribe_userdata = userdata; + c->subscribe_mask = m; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); + pa_tagstruct_putu32(t, c->ctag++); + pa_tagstruct_putu32(t, cb ? m : 0); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + enum pa_subscription_event_type e; + uint32_t index; + assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); + + if (pa_tagstruct_getu32(t, &e) < 0 || + pa_tagstruct_getu32(t, &index) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) + c->subscribe_callback(c, e, index, c->subscribe_userdata); +} + +void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_sink_info_callback = cb; + c->get_sink_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); +} + +void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_source_info_callback = cb; + c->get_source_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); +} + +static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_client_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.protocol_name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); +} + + +void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_client_info_callback = cb; + c->get_client_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +} + +void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_client_info_callback = cb; + c->get_client_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +} + +static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_module_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.argument) < 0 || + pa_tagstruct_getu32(t, &i.n_used) < 0 || + pa_tagstruct_getu32(t, &i.auto_unload) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); +} + +void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_module_info_callback = cb; + c->get_module_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); +} + +void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_module_info_callback = cb; + c->get_module_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); +} -- cgit From 56bcba9559279701eaa8860642c835484651ebdb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 13 Aug 2004 13:26:34 +0000 Subject: add polyplib-sample git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@120 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/polyplib-sample.h | 178 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 polyp/polyplib-sample.h diff --git a/polyp/polyplib-sample.h b/polyp/polyplib-sample.h new file mode 100644 index 00000000..a0dd9f9c --- /dev/null +++ b/polyp/polyplib-sample.h @@ -0,0 +1,178 @@ +#ifndef foopolyplibhfoo +#define foopolyplibhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "sample.h" +#include "polyplib-def.h" +#include "mainloop-api.h" + +#ifdef __cplusplus +//extern "C" { +#endif + +struct pa_context; +struct pa_stream; + +struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); +void pa_context_unref(struct pa_context *c); +struct pa_context* pa_context_ref(struct pa_context *c); + +int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); +int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); +void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); + +int pa_context_is_dead(struct pa_context *c); +int pa_context_is_ready(struct pa_context *c); +int pa_context_errno(struct pa_context *c); + +int pa_context_is_pending(struct pa_context *c); + +struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); +void pa_stream_unref(struct pa_stream *s); +struct pa_stream *pa_stream_ref(struct pa_stream *s); + +void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); + +void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); + +void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); +void pa_stream_write(struct pa_stream *p, const void *data, size_t length); +size_t pa_stream_writable_size(struct pa_stream *p); + +void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); + +int pa_stream_is_dead(struct pa_stream *p); +int pa_stream_is_ready(struct pa_stream*p); + +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); + +struct pa_context* pa_stream_get_context(struct pa_stream *p); + +uint32_t pa_stream_get_index(struct pa_stream *s); + +struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); +void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); + +void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +struct pa_sink_info { + const char *name; + uint32_t index; + const char *description; + struct pa_sample_spec sample_spec; + uint32_t owner_module; + uint32_t volume; + uint32_t monitor_source; + const char *monitor_source_name; + uint32_t latency; +}; + +void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); + +struct pa_source_info { + const char *name; + uint32_t index; + const char *description; + struct pa_sample_spec sample_spec; + uint32_t owner_module; + uint32_t monitor_of_sink; + const char *monitor_of_sink_name; +}; + +void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); + +struct pa_server_info { + const char *user_name; + const char *host_name; + const char *server_version; + const char *server_name; + struct pa_sample_spec sample_spec; +}; + +void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); + +struct pa_module_info { + uint32_t index; + const char*name, *argument; + uint32_t n_used, auto_unload; +}; + +void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); + +struct pa_client_info { + uint32_t index; + const char *name; + uint32_t owner_module; + const char *protocol_name; +}; + +void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); + +struct pa_sink_input_info { + uint32_t index; + const char *name; + uint32_t owner_module; + uint32_t owner_client; + uint32_t sink; + struct pa_sample_spec sample_spec; + uint32_t volume; + uint32_t latency; +}; + +void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); + +struct pa_source_output_info { + uint32_t index; + const char *name; + uint32_t owner_module; + uint32_t owner_client; + uint32_t source; + struct pa_sample_spec sample_spec; +}; + +void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); + +void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +void pa_context_exit(struct pa_context *c); +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); + +void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); + +#ifdef __cplusplus +} +#endif + +#endif -- cgit From 50b9fc2031cacf597813bb84d56f20e29fe0c93d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 13 Aug 2004 13:27:23 +0000 Subject: add polyplib-sample.c git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@121 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/polyplib-sample.c | 1550 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1550 insertions(+) create mode 100644 polyp/polyplib-sample.c diff --git a/polyp/polyplib-sample.c b/polyp/polyplib-sample.c new file mode 100644 index 00000000..35001d3d --- /dev/null +++ b/polyp/polyplib-sample.c @@ -0,0 +1,1550 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "polyplib.h" +#include "native-common.h" +#include "pdispatch.h" +#include "pstream.h" +#include "dynarray.h" +#include "socket-client.h" +#include "pstream-util.h" +#include "authkey.h" +#include "util.h" +#include "xmalloc.h" + +#define DEFAULT_MAXLENGTH 204800 +#define DEFAULT_TLENGTH 10240 +#define DEFAULT_PREBUF 4096 +#define DEFAULT_MINREQ 1024 +#define DEFAULT_FRAGSIZE 1024 + +#define DEFAULT_TIMEOUT (5*60) +#define DEFAULT_SERVER "/tmp/polypaudio/native" +#define DEFAULT_PORT "4713" + +struct pa_context { + char *name; + struct pa_mainloop_api* mainloop; + struct pa_socket_client *client; + struct pa_pstream *pstream; + struct pa_pdispatch *pdispatch; + struct pa_dynarray *record_streams, *playback_streams; + struct pa_stream *first_stream; + uint32_t ctag; + uint32_t error; + enum { + CONTEXT_UNCONNECTED, + CONTEXT_CONNECTING, + CONTEXT_AUTHORIZING, + CONTEXT_SETTING_NAME, + CONTEXT_READY, + CONTEXT_DEAD + } state; + + void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); + void *connect_complete_userdata; + + void (*drain_complete_callback)(struct pa_context*c, void *userdata); + void *drain_complete_userdata; + + void (*die_callback)(struct pa_context*c, void *userdata); + void *die_userdata; + + void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); + void *stat_userdata; + + void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); + void *play_sample_userdata; + + void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); + void *remove_sample_userdata; + + void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); + void *get_server_info_userdata; + + void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); + void *get_sink_info_userdata; + + void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); + void *get_source_info_userdata; + + void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); + void *subscribe_userdata; + enum pa_subscription_mask subscribe_mask; + + void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); + void *get_client_info_userdata; + + void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); + void *get_module_info_userdata; + + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; +}; + +struct pa_stream { + struct pa_context *context; + struct pa_stream *next, *previous; + + char *name; + struct pa_buffer_attr buffer_attr; + struct pa_sample_spec sample_spec; + uint32_t channel; + int channel_valid; + uint32_t device_index; + enum pa_stream_direction direction; + + enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; + uint32_t requested_bytes; + + void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); + void *read_userdata; + + void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); + void *write_userdata; + + void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); + void *create_complete_userdata; + + void (*drain_complete_callback)(struct pa_stream *s, void *userdata); + void *drain_complete_userdata; + + void (*die_callback)(struct pa_stream*c, void *userdata); + void *die_userdata; + + void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); + void *get_latency_userdata; + + void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); + void *finish_sample_userdata; +}; + +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); + +static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = { NULL }, + [PA_COMMAND_REPLY] = { NULL }, + [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_EXIT] = { NULL }, + [PA_COMMAND_REQUEST] = { command_request }, + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, + [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, + [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, +}; + +struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { + struct pa_context *c; + assert(mainloop && name); + + c = pa_xmalloc(sizeof(struct pa_context)); + c->name = pa_xstrdup(name); + c->mainloop = mainloop; + c->client = NULL; + c->pstream = NULL; + c->pdispatch = NULL; + c->playback_streams = pa_dynarray_new(); + assert(c->playback_streams); + c->record_streams = pa_dynarray_new(); + assert(c->record_streams); + c->first_stream = NULL; + c->error = PA_ERROR_OK; + c->state = CONTEXT_UNCONNECTED; + c->ctag = 0; + + c->connect_complete_callback = NULL; + c->connect_complete_userdata = NULL; + + c->drain_complete_callback = NULL; + c->drain_complete_userdata = NULL; + + c->die_callback = NULL; + c->die_userdata = NULL; + + c->stat_callback = NULL; + c->stat_userdata = NULL; + + c->play_sample_callback = NULL; + c->play_sample_userdata = NULL; + + c->remove_sample_callback = NULL; + c->remove_sample_userdata = NULL; + + c->get_server_info_callback = NULL; + c->get_server_info_userdata = NULL; + + c->get_sink_info_callback = NULL; + c->get_sink_info_userdata = NULL; + + c->get_source_info_callback = NULL; + c->get_source_info_userdata = NULL; + + c->subscribe_callback = NULL; + c->subscribe_userdata = NULL; + + c->get_client_info_callback = NULL; + c->get_client_info_userdata = NULL; + + c->get_module_info_callback = NULL; + c->get_module_info_userdata = NULL; + + pa_check_for_sigpipe(); + return c; +} + +void pa_context_free(struct pa_context *c) { + assert(c); + + while (c->first_stream) + pa_stream_free(c->first_stream); + + if (c->client) + pa_socket_client_free(c->client); + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + if (c->pstream) + pa_pstream_free(c->pstream); + if (c->record_streams) + pa_dynarray_free(c->record_streams, NULL, NULL); + if (c->playback_streams) + pa_dynarray_free(c->playback_streams, NULL, NULL); + + pa_xfree(c->name); + pa_xfree(c); +} + +static void stream_dead(struct pa_stream *s) { + assert(s); + + if (s->state == STREAM_DEAD) + return; + + if (s->state == STREAM_READY) { + s->state = STREAM_DEAD; + if (s->die_callback) + s->die_callback(s, s->die_userdata); + } else + s->state = STREAM_DEAD; +} + +static void context_dead(struct pa_context *c) { + struct pa_stream *s; + assert(c); + + if (c->state == CONTEXT_DEAD) + return; + + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + c->pdispatch = NULL; + + if (c->pstream) + pa_pstream_free(c->pstream); + c->pstream = NULL; + + if (c->client) + pa_socket_client_free(c->client); + c->client = NULL; + + for (s = c->first_stream; s; s = s->next) + stream_dead(s); + + if (c->state == CONTEXT_READY) { + c->state = CONTEXT_DEAD; + if (c->die_callback) + c->die_callback(c, c->die_userdata); + } else + c->state = CONTEXT_DEAD; +} + +static void pstream_die_callback(struct pa_pstream *p, void *userdata) { + struct pa_context *c = userdata; + assert(p && c); + c->error = PA_ERROR_CONNECTIONTERMINATED; + context_dead(c); +} + +static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { + struct pa_context *c = userdata; + assert(p && packet && c); + + if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { + fprintf(stderr, "polyp.c: invalid packet.\n"); + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + } +} + +static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + assert(p && chunk && c && chunk->memblock && chunk->memblock->data); + + if (!(s = pa_dynarray_get(c->record_streams, channel))) + return; + + if (s->read_callback) + s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); +} + +static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { + assert(c && t); + + if (command == PA_COMMAND_ERROR) { + if (pa_tagstruct_getu32(t, &c->error) < 0) { + c->error = PA_ERROR_PROTOCOL; + return -1; + } + + return 0; + } + + c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; + return -1; +} + +static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); + + if (command != PA_COMMAND_REPLY) { + handle_error(c, command, t); + context_dead(c); + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return; + } + + if (c->state == CONTEXT_AUTHORIZING) { + struct pa_tagstruct *t; + c->state = CONTEXT_SETTING_NAME; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, c->name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + } else { + assert(c->state == CONTEXT_SETTING_NAME); + + c->state = CONTEXT_READY; + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 1, c->connect_complete_userdata); + } + + return; +} + +static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { + struct pa_context *c = userdata; + struct pa_tagstruct *t; + uint32_t tag; + assert(client && c && c->state == CONTEXT_CONNECTING); + + pa_socket_client_free(client); + c->client = NULL; + + if (!io) { + c->error = PA_ERROR_CONNECTIONREFUSED; + context_dead(c); + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return; + } + + c->pstream = pa_pstream_new(c->mainloop, io); + assert(c->pstream); + pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); + pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); + pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); + + c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); + assert(c->pdispatch); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_AUTH); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + c->state = CONTEXT_AUTHORIZING; +} + +static struct sockaddr *resolve_server(const char *server, size_t *len) { + struct sockaddr *sa; + struct addrinfo hints, *result = NULL; + char *port; + assert(server && len); + + if ((port = strrchr(server, ':'))) + port++; + if (!port) + port = DEFAULT_PORT; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + if (getaddrinfo(server, port, &hints, &result) != 0) + return NULL; + assert(result); + + sa = pa_xmalloc(*len = result->ai_addrlen); + memcpy(sa, result->ai_addr, *len); + + freeaddrinfo(result); + + return sa; +} + +int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { + assert(c && c->state == CONTEXT_UNCONNECTED); + + if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { + c->error = PA_ERROR_AUTHKEY; + return -1; + } + + if (!server) + if (!(server = getenv("POLYP_SERVER"))) + server = DEFAULT_SERVER; + + assert(!c->client); + + if (*server == '/') { + if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + } else { + struct sockaddr* sa; + size_t sa_len; + + if (!(sa = resolve_server(server, &sa_len))) { + c->error = PA_ERROR_INVALIDSERVER; + return -1; + } + + c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); + pa_xfree(sa); + + if (!c->client) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + } + + c->connect_complete_callback = complete; + c->connect_complete_userdata = userdata; + + pa_socket_client_set_callback(c->client, on_connection, c); + c->state = CONTEXT_CONNECTING; + + return 0; +} + +int pa_context_is_dead(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_DEAD; +} + +int pa_context_is_ready(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_READY; +} + +int pa_context_errno(struct pa_context *c) { + assert(c); + return c->error; +} + +void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { + assert(c); + c->die_callback = cb; + c->die_userdata = userdata; +} + +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + uint32_t channel; + assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) + return; + + c->error = PA_ERROR_KILLED; + stream_dead(s); +} + +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s; + struct pa_context *c = userdata; + uint32_t bytes, channel; + assert(pd && command == PA_COMMAND_REQUEST && t && c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + pa_tagstruct_getu32(t, &bytes) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (!(s = pa_dynarray_get(c->playback_streams, channel))) + return; + + if (s->state != STREAM_READY) + return; + + s->requested_bytes += bytes; + + if (s->requested_bytes && s->write_callback) + s->write_callback(s, s->requested_bytes, s->write_userdata); +} + +static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s && s->state == STREAM_CREATING); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + if (s->create_complete_callback) + s->create_complete_callback(s, 0, s->create_complete_userdata); + + return; + } + + if (pa_tagstruct_getu32(t, &s->channel) < 0 || + ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + s->channel_valid = 1; + pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); + + s->state = STREAM_READY; + if (s->create_complete_callback) + s->create_complete_callback(s, 1, s->create_complete_userdata); +} + +static void create_stream(struct pa_stream *s, const char *dev) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s); + + s->state = STREAM_CREATING; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_puts(t, s->name); + pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_puts(t, dev ? dev : ""); + pa_tagstruct_putu32(t, s->buffer_attr.maxlength); + if (s->direction == PA_STREAM_PLAYBACK) { + pa_tagstruct_putu32(t, s->buffer_attr.tlength); + pa_tagstruct_putu32(t, s->buffer_attr.prebuf); + pa_tagstruct_putu32(t, s->buffer_attr.minreq); + } else + pa_tagstruct_putu32(t, s->buffer_attr.fragsize); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); +} + +static struct pa_stream *internal_stream_new(struct pa_context *c) { + struct pa_stream *s; + + s = pa_xmalloc(sizeof(struct pa_stream)); + s->context = c; + + s->read_callback = NULL; + s->read_userdata = NULL; + s->write_callback = NULL; + s->write_userdata = NULL; + s->die_callback = NULL; + s->die_userdata = NULL; + s->create_complete_callback = NULL; + s->create_complete_userdata = NULL; + s->get_latency_callback = NULL; + s->get_latency_userdata = NULL; + s->finish_sample_callback = NULL; + s->finish_sample_userdata = NULL; + + s->name = NULL; + s->state = STREAM_CREATING; + s->requested_bytes = 0; + s->channel = 0; + s->channel_valid = 0; + s->device_index = (uint32_t) -1; + + memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); + + s->next = c->first_stream; + if (s->next) + s->next->previous = s; + s->previous = NULL; + c->first_stream = s; + + return s; +} + +struct pa_stream* pa_stream_new( + struct pa_context *c, + enum pa_stream_direction dir, + const char *dev, + const char *name, + const struct pa_sample_spec *ss, + const struct pa_buffer_attr *attr, + void (*complete) (struct pa_stream*s, int success, void *userdata), + void *userdata) { + + struct pa_stream *s; + + assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); + + s = internal_stream_new(c); + assert(s); + + s->create_complete_callback = complete; + s->create_complete_userdata = userdata; + s->name = pa_xstrdup(name); + s->state = STREAM_CREATING; + s->direction = dir; + s->sample_spec = *ss; + if (attr) + s->buffer_attr = *attr; + else { + s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; + s->buffer_attr.tlength = DEFAULT_TLENGTH; + s->buffer_attr.prebuf = DEFAULT_PREBUF; + s->buffer_attr.minreq = DEFAULT_MINREQ; + s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; + } + + create_stream(s, dev); + + return s; +} + +void pa_stream_free(struct pa_stream *s) { + assert(s && s->context); + + if (s->context->pdispatch) + pa_pdispatch_unregister_reply(s->context->pdispatch, s); + + pa_xfree(s->name); + + if (s->channel_valid && s->context->state == CONTEXT_READY) { + struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : + (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); + pa_tagstruct_putu32(t, s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + } + + if (s->channel_valid) + pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); + + if (s->next) + s->next->previous = s->previous; + if (s->previous) + s->previous->next = s->next; + else + s->context->first_stream = s->next; + + pa_xfree(s); +} + +void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { + s->write_callback = cb; + s->write_userdata = userdata; +} + +void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { + struct pa_memchunk chunk; + assert(s && s->context && data && length && s->state == STREAM_READY); + + chunk.memblock = pa_memblock_new(length); + assert(chunk.memblock && chunk.memblock->data); + memcpy(chunk.memblock->data, data, length); + chunk.index = 0; + chunk.length = length; + + pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); + pa_memblock_unref(chunk.memblock); + + /*fprintf(stderr, "Sent %u bytes\n", length);*/ + + if (length < s->requested_bytes) + s->requested_bytes -= length; + else + s->requested_bytes = 0; +} + +size_t pa_stream_writable_size(struct pa_stream *s) { + assert(s && s->state == STREAM_READY); + return s->requested_bytes; +} + +void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { + assert(s && cb); + s->read_callback = cb; + s->read_userdata = userdata; +} + +int pa_stream_is_dead(struct pa_stream *s) { + return s->state == STREAM_DEAD; +} + +int pa_stream_is_ready(struct pa_stream*s) { + return s->state == STREAM_READY; +} + +void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { + assert(s); + s->die_callback = cb; + s->die_userdata = userdata; +} + +int pa_context_is_pending(struct pa_context *c) { + assert(c); + + if (c->state != CONTEXT_READY) + return 0; + + return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); +} + +struct pa_context* pa_stream_get_context(struct pa_stream *p) { + assert(p); + return p->context; +} + +static void set_dispatch_callbacks(struct pa_context *c); + +static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void set_dispatch_callbacks(struct pa_context *c) { + assert(c && c->state == CONTEXT_READY); + + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + + if (pa_pdispatch_is_pending(c->pdispatch)) { + pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); + return; + } + + if (pa_pstream_is_pending(c->pstream)) { + pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); + return; + } + + assert(c->drain_complete_callback); + c->drain_complete_callback(c, c->drain_complete_userdata); +} + +int pa_context_drain( + struct pa_context *c, + void (*complete) (struct pa_context*c, void *userdata), + void *userdata) { + + assert(c && c->state == CONTEXT_READY); + + if (complete == NULL) { + c->drain_complete_callback = NULL; + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + return 0; + } + + if (!pa_context_is_pending(c)) + return -1; + + c->drain_complete_callback = complete; + c->drain_complete_userdata = userdata; + + set_dispatch_callbacks(c); + + return 0; +} + +static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + return; + } + + if (s->state != STREAM_READY) + return; + + if (!pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->drain_complete_callback) { + void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; + s->drain_complete_callback = NULL; + temp(s, s->drain_complete_userdata); + } +} + + +void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s && s->state == STREAM_READY); + + if (!complete) { + s->drain_complete_callback = NULL; + return; + } + + s->drain_complete_callback = complete; + s->drain_complete_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); +} + +void pa_context_exit(struct pa_context *c) { + struct pa_tagstruct *t; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_EXIT); + pa_tagstruct_putu32(t, c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + uint32_t total, count; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &count) < 0 || + pa_tagstruct_getu32(t, &total) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, count, total, c->stat_userdata); +} + +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + c->stat_callback = cb; + c->stat_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_STAT); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); +} + +static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + uint32_t latency; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &latency) < 0 || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, latency, s->get_latency_userdata); +} + +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + p->get_latency_callback = cb; + p->get_latency_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); + pa_tagstruct_putu32(t, tag = p->context->ctag++); + pa_tagstruct_putu32(t, p->channel); + pa_pstream_send_tagstruct(p->context->pstream, t); + pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); +} + +struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { + struct pa_stream *s; + struct pa_tagstruct *t; + uint32_t tag; + + s = internal_stream_new(c); + assert(s); + + s->create_complete_callback = cb; + s->create_complete_userdata = userdata; + s->name = pa_xstrdup(name); + s->state = STREAM_CREATING; + s->direction = PA_STREAM_UPLOAD; + s->sample_spec = *ss; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_put_sample_spec(t, ss); + pa_tagstruct_putu32(t, length); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); + + return s; +} + +static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + if (s->finish_sample_callback) + s->finish_sample_callback(s, 0, s->finish_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->finish_sample_callback) + s->finish_sample_callback(s, 1, s->finish_sample_userdata); +} + +void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(p); + + p->finish_sample_callback = cb; + p->finish_sample_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = p->context->ctag++); + pa_tagstruct_putu32(t, p->channel); + pa_pstream_send_tagstruct(p->context->pstream, t); + pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); +} + +static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->play_sample_callback) + c->play_sample_callback(c, 0, c->play_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->play_sample_callback) + c->play_sample_callback(c, 1, c->play_sample_userdata); +} + +void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c && name && *name && (!dev || *dev)); + + c->play_sample_callback = cb; + c->play_sample_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_puts(t, dev ? dev : ""); + pa_tagstruct_putu32(t, volume); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); +} + +static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->remove_sample_callback) + c->remove_sample_callback(c, 0, c->remove_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->remove_sample_callback) + c->remove_sample_callback(c, 1, c->remove_sample_userdata); +} + +void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c && name); + + c->remove_sample_callback = cb; + c->remove_sample_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); +} + +static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + struct pa_server_info i; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_server_info_callback) + c->get_server_info_callback(c, NULL, c->get_server_info_userdata); + return; + } + + if (pa_tagstruct_gets(t, &i.server_name) < 0 || + pa_tagstruct_gets(t, &i.server_version) < 0 || + pa_tagstruct_gets(t, &i.user_name) < 0 || + pa_tagstruct_gets(t, &i.host_name) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_server_info_callback) + c->get_server_info_callback(c, &i, c->get_server_info_userdata); +} + +void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_server_info_callback = cb; + c->get_server_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); +} + +static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_sink_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.volume) < 0 || + pa_tagstruct_getu32(t, &i.monitor_source) < 0 || + pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || + pa_tagstruct_getu32(t, &i.latency) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); +} + +void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_sink_info_callback = cb; + c->get_sink_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); +} + +static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_source_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || + pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); +} + +void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_source_info_callback = cb; + c->get_source_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); +} + +void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { + struct pa_tagstruct *t; + assert(c); + + c->subscribe_callback = cb; + c->subscribe_userdata = userdata; + c->subscribe_mask = m; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); + pa_tagstruct_putu32(t, c->ctag++); + pa_tagstruct_putu32(t, cb ? m : 0); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + enum pa_subscription_event_type e; + uint32_t index; + assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); + + if (pa_tagstruct_getu32(t, &e) < 0 || + pa_tagstruct_getu32(t, &index) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) + c->subscribe_callback(c, e, index, c->subscribe_userdata); +} + +void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_sink_info_callback = cb; + c->get_sink_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); +} + +void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_source_info_callback = cb; + c->get_source_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); +} + +static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_client_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.protocol_name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); +} + + +void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_client_info_callback = cb; + c->get_client_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +} + +void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_client_info_callback = cb; + c->get_client_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +} + +static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_module_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.argument) < 0 || + pa_tagstruct_getu32(t, &i.n_used) < 0 || + pa_tagstruct_getu32(t, &i.auto_unload) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); +} + +void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_module_info_callback = cb; + c->get_module_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); +} + +void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_module_info_callback = cb; + c->get_module_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); +} -- cgit From 1c2ec47cf1506ad1c75c088d476ae382170df62c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 13 Aug 2004 16:05:03 +0000 Subject: rename polyplib-sample to polyplib-scache git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@122 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/polyplib-scache.c | 1550 +++++++++++++++++++++++++++++++++++++++++++++++ polyp/polyplib-scache.h | 178 ++++++ 2 files changed, 1728 insertions(+) create mode 100644 polyp/polyplib-scache.c create mode 100644 polyp/polyplib-scache.h diff --git a/polyp/polyplib-scache.c b/polyp/polyplib-scache.c new file mode 100644 index 00000000..35001d3d --- /dev/null +++ b/polyp/polyplib-scache.c @@ -0,0 +1,1550 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "polyplib.h" +#include "native-common.h" +#include "pdispatch.h" +#include "pstream.h" +#include "dynarray.h" +#include "socket-client.h" +#include "pstream-util.h" +#include "authkey.h" +#include "util.h" +#include "xmalloc.h" + +#define DEFAULT_MAXLENGTH 204800 +#define DEFAULT_TLENGTH 10240 +#define DEFAULT_PREBUF 4096 +#define DEFAULT_MINREQ 1024 +#define DEFAULT_FRAGSIZE 1024 + +#define DEFAULT_TIMEOUT (5*60) +#define DEFAULT_SERVER "/tmp/polypaudio/native" +#define DEFAULT_PORT "4713" + +struct pa_context { + char *name; + struct pa_mainloop_api* mainloop; + struct pa_socket_client *client; + struct pa_pstream *pstream; + struct pa_pdispatch *pdispatch; + struct pa_dynarray *record_streams, *playback_streams; + struct pa_stream *first_stream; + uint32_t ctag; + uint32_t error; + enum { + CONTEXT_UNCONNECTED, + CONTEXT_CONNECTING, + CONTEXT_AUTHORIZING, + CONTEXT_SETTING_NAME, + CONTEXT_READY, + CONTEXT_DEAD + } state; + + void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); + void *connect_complete_userdata; + + void (*drain_complete_callback)(struct pa_context*c, void *userdata); + void *drain_complete_userdata; + + void (*die_callback)(struct pa_context*c, void *userdata); + void *die_userdata; + + void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); + void *stat_userdata; + + void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); + void *play_sample_userdata; + + void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); + void *remove_sample_userdata; + + void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); + void *get_server_info_userdata; + + void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); + void *get_sink_info_userdata; + + void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); + void *get_source_info_userdata; + + void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); + void *subscribe_userdata; + enum pa_subscription_mask subscribe_mask; + + void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); + void *get_client_info_userdata; + + void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); + void *get_module_info_userdata; + + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; +}; + +struct pa_stream { + struct pa_context *context; + struct pa_stream *next, *previous; + + char *name; + struct pa_buffer_attr buffer_attr; + struct pa_sample_spec sample_spec; + uint32_t channel; + int channel_valid; + uint32_t device_index; + enum pa_stream_direction direction; + + enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; + uint32_t requested_bytes; + + void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); + void *read_userdata; + + void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); + void *write_userdata; + + void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); + void *create_complete_userdata; + + void (*drain_complete_callback)(struct pa_stream *s, void *userdata); + void *drain_complete_userdata; + + void (*die_callback)(struct pa_stream*c, void *userdata); + void *die_userdata; + + void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); + void *get_latency_userdata; + + void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); + void *finish_sample_userdata; +}; + +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); + +static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = { NULL }, + [PA_COMMAND_REPLY] = { NULL }, + [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, + [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, + [PA_COMMAND_EXIT] = { NULL }, + [PA_COMMAND_REQUEST] = { command_request }, + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, + [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, + [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, +}; + +struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { + struct pa_context *c; + assert(mainloop && name); + + c = pa_xmalloc(sizeof(struct pa_context)); + c->name = pa_xstrdup(name); + c->mainloop = mainloop; + c->client = NULL; + c->pstream = NULL; + c->pdispatch = NULL; + c->playback_streams = pa_dynarray_new(); + assert(c->playback_streams); + c->record_streams = pa_dynarray_new(); + assert(c->record_streams); + c->first_stream = NULL; + c->error = PA_ERROR_OK; + c->state = CONTEXT_UNCONNECTED; + c->ctag = 0; + + c->connect_complete_callback = NULL; + c->connect_complete_userdata = NULL; + + c->drain_complete_callback = NULL; + c->drain_complete_userdata = NULL; + + c->die_callback = NULL; + c->die_userdata = NULL; + + c->stat_callback = NULL; + c->stat_userdata = NULL; + + c->play_sample_callback = NULL; + c->play_sample_userdata = NULL; + + c->remove_sample_callback = NULL; + c->remove_sample_userdata = NULL; + + c->get_server_info_callback = NULL; + c->get_server_info_userdata = NULL; + + c->get_sink_info_callback = NULL; + c->get_sink_info_userdata = NULL; + + c->get_source_info_callback = NULL; + c->get_source_info_userdata = NULL; + + c->subscribe_callback = NULL; + c->subscribe_userdata = NULL; + + c->get_client_info_callback = NULL; + c->get_client_info_userdata = NULL; + + c->get_module_info_callback = NULL; + c->get_module_info_userdata = NULL; + + pa_check_for_sigpipe(); + return c; +} + +void pa_context_free(struct pa_context *c) { + assert(c); + + while (c->first_stream) + pa_stream_free(c->first_stream); + + if (c->client) + pa_socket_client_free(c->client); + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + if (c->pstream) + pa_pstream_free(c->pstream); + if (c->record_streams) + pa_dynarray_free(c->record_streams, NULL, NULL); + if (c->playback_streams) + pa_dynarray_free(c->playback_streams, NULL, NULL); + + pa_xfree(c->name); + pa_xfree(c); +} + +static void stream_dead(struct pa_stream *s) { + assert(s); + + if (s->state == STREAM_DEAD) + return; + + if (s->state == STREAM_READY) { + s->state = STREAM_DEAD; + if (s->die_callback) + s->die_callback(s, s->die_userdata); + } else + s->state = STREAM_DEAD; +} + +static void context_dead(struct pa_context *c) { + struct pa_stream *s; + assert(c); + + if (c->state == CONTEXT_DEAD) + return; + + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + c->pdispatch = NULL; + + if (c->pstream) + pa_pstream_free(c->pstream); + c->pstream = NULL; + + if (c->client) + pa_socket_client_free(c->client); + c->client = NULL; + + for (s = c->first_stream; s; s = s->next) + stream_dead(s); + + if (c->state == CONTEXT_READY) { + c->state = CONTEXT_DEAD; + if (c->die_callback) + c->die_callback(c, c->die_userdata); + } else + c->state = CONTEXT_DEAD; +} + +static void pstream_die_callback(struct pa_pstream *p, void *userdata) { + struct pa_context *c = userdata; + assert(p && c); + c->error = PA_ERROR_CONNECTIONTERMINATED; + context_dead(c); +} + +static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { + struct pa_context *c = userdata; + assert(p && packet && c); + + if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { + fprintf(stderr, "polyp.c: invalid packet.\n"); + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + } +} + +static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + assert(p && chunk && c && chunk->memblock && chunk->memblock->data); + + if (!(s = pa_dynarray_get(c->record_streams, channel))) + return; + + if (s->read_callback) + s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); +} + +static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { + assert(c && t); + + if (command == PA_COMMAND_ERROR) { + if (pa_tagstruct_getu32(t, &c->error) < 0) { + c->error = PA_ERROR_PROTOCOL; + return -1; + } + + return 0; + } + + c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; + return -1; +} + +static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); + + if (command != PA_COMMAND_REPLY) { + handle_error(c, command, t); + context_dead(c); + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return; + } + + if (c->state == CONTEXT_AUTHORIZING) { + struct pa_tagstruct *t; + c->state = CONTEXT_SETTING_NAME; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, c->name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + } else { + assert(c->state == CONTEXT_SETTING_NAME); + + c->state = CONTEXT_READY; + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 1, c->connect_complete_userdata); + } + + return; +} + +static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { + struct pa_context *c = userdata; + struct pa_tagstruct *t; + uint32_t tag; + assert(client && c && c->state == CONTEXT_CONNECTING); + + pa_socket_client_free(client); + c->client = NULL; + + if (!io) { + c->error = PA_ERROR_CONNECTIONREFUSED; + context_dead(c); + + if (c->connect_complete_callback) + c->connect_complete_callback(c, 0, c->connect_complete_userdata); + + return; + } + + c->pstream = pa_pstream_new(c->mainloop, io); + assert(c->pstream); + pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); + pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); + pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); + + c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); + assert(c->pdispatch); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_AUTH); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + c->state = CONTEXT_AUTHORIZING; +} + +static struct sockaddr *resolve_server(const char *server, size_t *len) { + struct sockaddr *sa; + struct addrinfo hints, *result = NULL; + char *port; + assert(server && len); + + if ((port = strrchr(server, ':'))) + port++; + if (!port) + port = DEFAULT_PORT; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + if (getaddrinfo(server, port, &hints, &result) != 0) + return NULL; + assert(result); + + sa = pa_xmalloc(*len = result->ai_addrlen); + memcpy(sa, result->ai_addr, *len); + + freeaddrinfo(result); + + return sa; +} + +int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { + assert(c && c->state == CONTEXT_UNCONNECTED); + + if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { + c->error = PA_ERROR_AUTHKEY; + return -1; + } + + if (!server) + if (!(server = getenv("POLYP_SERVER"))) + server = DEFAULT_SERVER; + + assert(!c->client); + + if (*server == '/') { + if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + } else { + struct sockaddr* sa; + size_t sa_len; + + if (!(sa = resolve_server(server, &sa_len))) { + c->error = PA_ERROR_INVALIDSERVER; + return -1; + } + + c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); + pa_xfree(sa); + + if (!c->client) { + c->error = PA_ERROR_CONNECTIONREFUSED; + return -1; + } + } + + c->connect_complete_callback = complete; + c->connect_complete_userdata = userdata; + + pa_socket_client_set_callback(c->client, on_connection, c); + c->state = CONTEXT_CONNECTING; + + return 0; +} + +int pa_context_is_dead(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_DEAD; +} + +int pa_context_is_ready(struct pa_context *c) { + assert(c); + return c->state == CONTEXT_READY; +} + +int pa_context_errno(struct pa_context *c) { + assert(c); + return c->error; +} + +void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { + assert(c); + c->die_callback = cb; + c->die_userdata = userdata; +} + +static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + struct pa_stream *s; + uint32_t channel; + assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) + return; + + c->error = PA_ERROR_KILLED; + stream_dead(s); +} + +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s; + struct pa_context *c = userdata; + uint32_t bytes, channel; + assert(pd && command == PA_COMMAND_REQUEST && t && c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + pa_tagstruct_getu32(t, &bytes) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (!(s = pa_dynarray_get(c->playback_streams, channel))) + return; + + if (s->state != STREAM_READY) + return; + + s->requested_bytes += bytes; + + if (s->requested_bytes && s->write_callback) + s->write_callback(s, s->requested_bytes, s->write_userdata); +} + +static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s && s->state == STREAM_CREATING); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + if (s->create_complete_callback) + s->create_complete_callback(s, 0, s->create_complete_userdata); + + return; + } + + if (pa_tagstruct_getu32(t, &s->channel) < 0 || + ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + s->channel_valid = 1; + pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); + + s->state = STREAM_READY; + if (s->create_complete_callback) + s->create_complete_callback(s, 1, s->create_complete_userdata); +} + +static void create_stream(struct pa_stream *s, const char *dev) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s); + + s->state = STREAM_CREATING; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_puts(t, s->name); + pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_puts(t, dev ? dev : ""); + pa_tagstruct_putu32(t, s->buffer_attr.maxlength); + if (s->direction == PA_STREAM_PLAYBACK) { + pa_tagstruct_putu32(t, s->buffer_attr.tlength); + pa_tagstruct_putu32(t, s->buffer_attr.prebuf); + pa_tagstruct_putu32(t, s->buffer_attr.minreq); + } else + pa_tagstruct_putu32(t, s->buffer_attr.fragsize); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); +} + +static struct pa_stream *internal_stream_new(struct pa_context *c) { + struct pa_stream *s; + + s = pa_xmalloc(sizeof(struct pa_stream)); + s->context = c; + + s->read_callback = NULL; + s->read_userdata = NULL; + s->write_callback = NULL; + s->write_userdata = NULL; + s->die_callback = NULL; + s->die_userdata = NULL; + s->create_complete_callback = NULL; + s->create_complete_userdata = NULL; + s->get_latency_callback = NULL; + s->get_latency_userdata = NULL; + s->finish_sample_callback = NULL; + s->finish_sample_userdata = NULL; + + s->name = NULL; + s->state = STREAM_CREATING; + s->requested_bytes = 0; + s->channel = 0; + s->channel_valid = 0; + s->device_index = (uint32_t) -1; + + memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); + + s->next = c->first_stream; + if (s->next) + s->next->previous = s; + s->previous = NULL; + c->first_stream = s; + + return s; +} + +struct pa_stream* pa_stream_new( + struct pa_context *c, + enum pa_stream_direction dir, + const char *dev, + const char *name, + const struct pa_sample_spec *ss, + const struct pa_buffer_attr *attr, + void (*complete) (struct pa_stream*s, int success, void *userdata), + void *userdata) { + + struct pa_stream *s; + + assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); + + s = internal_stream_new(c); + assert(s); + + s->create_complete_callback = complete; + s->create_complete_userdata = userdata; + s->name = pa_xstrdup(name); + s->state = STREAM_CREATING; + s->direction = dir; + s->sample_spec = *ss; + if (attr) + s->buffer_attr = *attr; + else { + s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; + s->buffer_attr.tlength = DEFAULT_TLENGTH; + s->buffer_attr.prebuf = DEFAULT_PREBUF; + s->buffer_attr.minreq = DEFAULT_MINREQ; + s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; + } + + create_stream(s, dev); + + return s; +} + +void pa_stream_free(struct pa_stream *s) { + assert(s && s->context); + + if (s->context->pdispatch) + pa_pdispatch_unregister_reply(s->context->pdispatch, s); + + pa_xfree(s->name); + + if (s->channel_valid && s->context->state == CONTEXT_READY) { + struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : + (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); + pa_tagstruct_putu32(t, s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + } + + if (s->channel_valid) + pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); + + if (s->next) + s->next->previous = s->previous; + if (s->previous) + s->previous->next = s->next; + else + s->context->first_stream = s->next; + + pa_xfree(s); +} + +void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { + s->write_callback = cb; + s->write_userdata = userdata; +} + +void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { + struct pa_memchunk chunk; + assert(s && s->context && data && length && s->state == STREAM_READY); + + chunk.memblock = pa_memblock_new(length); + assert(chunk.memblock && chunk.memblock->data); + memcpy(chunk.memblock->data, data, length); + chunk.index = 0; + chunk.length = length; + + pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); + pa_memblock_unref(chunk.memblock); + + /*fprintf(stderr, "Sent %u bytes\n", length);*/ + + if (length < s->requested_bytes) + s->requested_bytes -= length; + else + s->requested_bytes = 0; +} + +size_t pa_stream_writable_size(struct pa_stream *s) { + assert(s && s->state == STREAM_READY); + return s->requested_bytes; +} + +void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { + assert(s && cb); + s->read_callback = cb; + s->read_userdata = userdata; +} + +int pa_stream_is_dead(struct pa_stream *s) { + return s->state == STREAM_DEAD; +} + +int pa_stream_is_ready(struct pa_stream*s) { + return s->state == STREAM_READY; +} + +void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { + assert(s); + s->die_callback = cb; + s->die_userdata = userdata; +} + +int pa_context_is_pending(struct pa_context *c) { + assert(c); + + if (c->state != CONTEXT_READY) + return 0; + + return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); +} + +struct pa_context* pa_stream_get_context(struct pa_stream *p) { + assert(p); + return p->context; +} + +static void set_dispatch_callbacks(struct pa_context *c); + +static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void set_dispatch_callbacks(struct pa_context *c) { + assert(c && c->state == CONTEXT_READY); + + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + + if (pa_pdispatch_is_pending(c->pdispatch)) { + pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); + return; + } + + if (pa_pstream_is_pending(c->pstream)) { + pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); + return; + } + + assert(c->drain_complete_callback); + c->drain_complete_callback(c, c->drain_complete_userdata); +} + +int pa_context_drain( + struct pa_context *c, + void (*complete) (struct pa_context*c, void *userdata), + void *userdata) { + + assert(c && c->state == CONTEXT_READY); + + if (complete == NULL) { + c->drain_complete_callback = NULL; + pa_pstream_set_drain_callback(c->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + return 0; + } + + if (!pa_context_is_pending(c)) + return -1; + + c->drain_complete_callback = complete; + c->drain_complete_userdata = userdata; + + set_dispatch_callbacks(c); + + return 0; +} + +static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + stream_dead(s); + return; + } + + if (s->state != STREAM_READY) + return; + + if (!pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->drain_complete_callback) { + void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; + s->drain_complete_callback = NULL; + temp(s, s->drain_complete_userdata); + } +} + + +void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(s && s->state == STREAM_READY); + + if (!complete) { + s->drain_complete_callback = NULL; + return; + } + + s->drain_complete_callback = complete; + s->drain_complete_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); +} + +void pa_context_exit(struct pa_context *c) { + struct pa_tagstruct *t; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_EXIT); + pa_tagstruct_putu32(t, c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + uint32_t total, count; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &count) < 0 || + pa_tagstruct_getu32(t, &total) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->stat_callback) + c->stat_callback(c, count, total, c->stat_userdata); +} + +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + c->stat_callback = cb; + c->stat_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_STAT); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); +} + +static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + uint32_t latency; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &latency) < 0 || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, latency, s->get_latency_userdata); +} + +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + p->get_latency_callback = cb; + p->get_latency_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); + pa_tagstruct_putu32(t, tag = p->context->ctag++); + pa_tagstruct_putu32(t, p->channel); + pa_pstream_send_tagstruct(p->context->pstream, t); + pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); +} + +struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { + struct pa_stream *s; + struct pa_tagstruct *t; + uint32_t tag; + + s = internal_stream_new(c); + assert(s); + + s->create_complete_callback = cb; + s->create_complete_userdata = userdata; + s->name = pa_xstrdup(name); + s->state = STREAM_CREATING; + s->direction = PA_STREAM_UPLOAD; + s->sample_spec = *ss; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_put_sample_spec(t, ss); + pa_tagstruct_putu32(t, length); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); + + return s; +} + +static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + if (s->finish_sample_callback) + s->finish_sample_callback(s, 0, s->finish_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->finish_sample_callback) + s->finish_sample_callback(s, 1, s->finish_sample_userdata); +} + +void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(p); + + p->finish_sample_callback = cb; + p->finish_sample_userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = p->context->ctag++); + pa_tagstruct_putu32(t, p->channel); + pa_pstream_send_tagstruct(p->context->pstream, t); + pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); +} + +static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->play_sample_callback) + c->play_sample_callback(c, 0, c->play_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->play_sample_callback) + c->play_sample_callback(c, 1, c->play_sample_userdata); +} + +void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c && name && *name && (!dev || *dev)); + + c->play_sample_callback = cb; + c->play_sample_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_puts(t, dev ? dev : ""); + pa_tagstruct_putu32(t, volume); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); +} + +static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->remove_sample_callback) + c->remove_sample_callback(c, 0, c->remove_sample_userdata); + return; + } + + if (!pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->remove_sample_callback) + c->remove_sample_callback(c, 1, c->remove_sample_userdata); +} + +void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c && name); + + c->remove_sample_callback = cb; + c->remove_sample_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); +} + +static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + struct pa_server_info i; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_server_info_callback) + c->get_server_info_callback(c, NULL, c->get_server_info_userdata); + return; + } + + if (pa_tagstruct_gets(t, &i.server_name) < 0 || + pa_tagstruct_gets(t, &i.server_version) < 0 || + pa_tagstruct_gets(t, &i.user_name) < 0 || + pa_tagstruct_gets(t, &i.host_name) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_server_info_callback) + c->get_server_info_callback(c, &i, c->get_server_info_userdata); +} + +void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_server_info_callback = cb; + c->get_server_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); +} + +static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_sink_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.volume) < 0 || + pa_tagstruct_getu32(t, &i.monitor_source) < 0 || + pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || + pa_tagstruct_getu32(t, &i.latency) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); + } + + if (c->get_sink_info_callback) + c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); +} + +void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_sink_info_callback = cb; + c->get_sink_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); +} + +static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_source_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || + pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); + } + + if (c->get_source_info_callback) + c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); +} + +void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_source_info_callback = cb; + c->get_source_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); +} + +void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { + struct pa_tagstruct *t; + assert(c); + + c->subscribe_callback = cb; + c->subscribe_userdata = userdata; + c->subscribe_mask = m; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); + pa_tagstruct_putu32(t, c->ctag++); + pa_tagstruct_putu32(t, cb ? m : 0); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + enum pa_subscription_event_type e; + uint32_t index; + assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); + + if (pa_tagstruct_getu32(t, &e) < 0 || + pa_tagstruct_getu32(t, &index) < 0 || + !pa_tagstruct_eof(t)) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) + c->subscribe_callback(c, e, index, c->subscribe_userdata); +} + +void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_sink_info_callback = cb; + c->get_sink_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); +} + +void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_source_info_callback = cb; + c->get_source_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); +} + +static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_client_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.protocol_name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); + } + + if (c->get_client_info_callback) + c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); +} + + +void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_client_info_callback = cb; + c->get_client_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +} + +void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_client_info_callback = cb; + c->get_client_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +} + +static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_context *c = userdata; + assert(pd && c); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(c, command, t) < 0) { + context_dead(c); + return; + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); + return; + } + + while (!pa_tagstruct_eof(t)) { + struct pa_module_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.argument) < 0 || + pa_tagstruct_getu32(t, &i.n_used) < 0 || + pa_tagstruct_getu32(t, &i.auto_unload) < 0) { + c->error = PA_ERROR_PROTOCOL; + context_dead(c); + return; + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); + } + + if (c->get_module_info_callback) + c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); +} + +void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_module_info_callback = cb; + c->get_module_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); +} + +void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + uint32_t tag; + assert(c); + + c->get_module_info_callback = cb; + c->get_module_info_userdata = userdata; + + if (!cb) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); +} diff --git a/polyp/polyplib-scache.h b/polyp/polyplib-scache.h new file mode 100644 index 00000000..a0dd9f9c --- /dev/null +++ b/polyp/polyplib-scache.h @@ -0,0 +1,178 @@ +#ifndef foopolyplibhfoo +#define foopolyplibhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "sample.h" +#include "polyplib-def.h" +#include "mainloop-api.h" + +#ifdef __cplusplus +//extern "C" { +#endif + +struct pa_context; +struct pa_stream; + +struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); +void pa_context_unref(struct pa_context *c); +struct pa_context* pa_context_ref(struct pa_context *c); + +int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); +int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); +void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); + +int pa_context_is_dead(struct pa_context *c); +int pa_context_is_ready(struct pa_context *c); +int pa_context_errno(struct pa_context *c); + +int pa_context_is_pending(struct pa_context *c); + +struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); +void pa_stream_unref(struct pa_stream *s); +struct pa_stream *pa_stream_ref(struct pa_stream *s); + +void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); + +void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); + +void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); +void pa_stream_write(struct pa_stream *p, const void *data, size_t length); +size_t pa_stream_writable_size(struct pa_stream *p); + +void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); + +int pa_stream_is_dead(struct pa_stream *p); +int pa_stream_is_ready(struct pa_stream*p); + +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); + +struct pa_context* pa_stream_get_context(struct pa_stream *p); + +uint32_t pa_stream_get_index(struct pa_stream *s); + +struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); +void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); + +void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +struct pa_sink_info { + const char *name; + uint32_t index; + const char *description; + struct pa_sample_spec sample_spec; + uint32_t owner_module; + uint32_t volume; + uint32_t monitor_source; + const char *monitor_source_name; + uint32_t latency; +}; + +void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); + +struct pa_source_info { + const char *name; + uint32_t index; + const char *description; + struct pa_sample_spec sample_spec; + uint32_t owner_module; + uint32_t monitor_of_sink; + const char *monitor_of_sink_name; +}; + +void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); + +struct pa_server_info { + const char *user_name; + const char *host_name; + const char *server_version; + const char *server_name; + struct pa_sample_spec sample_spec; +}; + +void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); + +struct pa_module_info { + uint32_t index; + const char*name, *argument; + uint32_t n_used, auto_unload; +}; + +void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); + +struct pa_client_info { + uint32_t index; + const char *name; + uint32_t owner_module; + const char *protocol_name; +}; + +void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); + +struct pa_sink_input_info { + uint32_t index; + const char *name; + uint32_t owner_module; + uint32_t owner_client; + uint32_t sink; + struct pa_sample_spec sample_spec; + uint32_t volume; + uint32_t latency; +}; + +void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); + +struct pa_source_output_info { + uint32_t index; + const char *name; + uint32_t owner_module; + uint32_t owner_client; + uint32_t source; + struct pa_sample_spec sample_spec; +}; + +void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); +void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); + +void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +void pa_context_exit(struct pa_context *c); +void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); + +void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); + +#ifdef __cplusplus +} +#endif + +#endif -- cgit From 22cb23eedb2eae7c79dc8fcf395be08bfc666256 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 14 Aug 2004 20:25:32 +0000 Subject: implement proper refcounting in polyplib split polyplib to multiple modules add some prelimenary documentation add doxygen support git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@123 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 5 +- configure.ac | 2 +- doxygen/Makefile.am | 11 + doxygen/doxygen.conf.in | 1153 ++++++++++++++++++++++++++++++ polyp/Makefile.am | 25 +- polyp/cdecl.h | 21 + polyp/glib-mainloop.h | 20 +- polyp/llist.h | 39 + polyp/mainloop-api.h | 44 +- polyp/mainloop.h | 5 + polyp/memblock.c | 42 +- polyp/memblock.h | 4 +- polyp/native-common.h | 18 +- polyp/pacat.c | 150 ++-- polyp/pactl.c | 146 ++-- polyp/polyplib-context.c | 1490 ++++++-------------------------------- polyp/polyplib-context.h | 182 ++--- polyp/polyplib-def.h | 17 +- polyp/polyplib-error.h | 12 +- polyp/polyplib-internal.h | 1528 ++------------------------------------- polyp/polyplib-introspect.c | 1651 +++++++------------------------------------ polyp/polyplib-introspect.h | 109 +-- polyp/polyplib-operation.c | 78 ++ polyp/polyplib-operation.h | 56 ++ polyp/polyplib-sample.c | 1550 ---------------------------------------- polyp/polyplib-sample.h | 178 ----- polyp/polyplib-scache.c | 1495 +-------------------------------------- polyp/polyplib-scache.h | 162 +---- polyp/polyplib-simple.c | 68 +- polyp/polyplib-simple.h | 33 +- polyp/polyplib-stream.c | 1594 +++++++---------------------------------- polyp/polyplib-stream.h | 178 ++--- polyp/polyplib-subscribe.c | 1514 +-------------------------------------- polyp/polyplib-subscribe.h | 158 +---- polyp/polyplib.c | 1550 ---------------------------------------- polyp/polyplib.h | 156 +--- polyp/sample-util.c | 7 - polyp/sample-util.h | 4 - polyp/sample.c | 8 + polyp/sample.h | 21 +- polyp/socket-client.c | 2 +- polyp/socket-client.h | 2 + polyp/tagstruct.h | 2 - polyp/xmalloc.c | 29 +- polyp/xmalloc.h | 2 + 45 files changed, 2787 insertions(+), 12734 deletions(-) create mode 100644 doxygen/Makefile.am create mode 100644 doxygen/doxygen.conf.in create mode 100644 polyp/cdecl.h create mode 100644 polyp/llist.h create mode 100644 polyp/polyplib-operation.c create mode 100644 polyp/polyplib-operation.h delete mode 100644 polyp/polyplib-sample.c delete mode 100644 polyp/polyplib-sample.h delete mode 100644 polyp/polyplib.c diff --git a/Makefile.am b/Makefile.am index a54fd606..3fc81b40 100644 --- a/Makefile.am +++ b/Makefile.am @@ -41,4 +41,7 @@ homepage: all dist distcleancheck: @: -.PHONY: homepage distcleancheck +doxygen: + $(MAKE) -C doxygen + +.PHONY: homepage distcleancheck doxygen diff --git a/configure.ac b/configure.ac index 3183d174..b7766e4a 100644 --- a/configure.ac +++ b/configure.ac @@ -84,5 +84,5 @@ AM_CONDITIONAL([USE_LYNX], [test "x$lynx" = xyes]) AM_CONDITIONAL(BUILD_LIBPOLYPCORE, false) -AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html]) +AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf]) AC_OUTPUT diff --git a/doxygen/Makefile.am b/doxygen/Makefile.am new file mode 100644 index 00000000..d2f508c7 --- /dev/null +++ b/doxygen/Makefile.am @@ -0,0 +1,11 @@ +# $Id$ + +noinst_DATA=html + +html: doxygen.conf + doxygen $< + +clean-local: + rm -rf html + +.PHONY: all html diff --git a/doxygen/doxygen.conf.in b/doxygen/doxygen.conf.in new file mode 100644 index 00000000..78a43685 --- /dev/null +++ b/doxygen/doxygen.conf.in @@ -0,0 +1,1153 @@ +# Doxyfile 1.3.8 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = @PACKAGE_NAME@ + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = @PACKAGE_VERSION@ + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of source +# files, where putting all generated files in the same directory would otherwise +# cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, +# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, +# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, +# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, +# Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is used +# as the annotated text. Otherwise, the brief description is used as-is. If left +# blank, the following values are used ("$name" is automatically replaced with the +# name of the entity): "The $name class" "The $name widget" "The $name file" +# "is" "provides" "specifies" "contains" "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited +# members of a class in the documentation of that class as if those members were +# ordinary class members. Constructors, destructors and assignment operators of +# the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = YES + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = NO + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = NO + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = NO + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= NO + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../polyp/polyplib-context.h ../polyp/polyplib-stream.h ../polyp/polyplib.h ../polyp/sample.h ../polyp/polyplib-def.h ../polyp/polyplib-subscribe.h ../polyp/polyplib-introspect.h ../polyp/polyplib-scache.h ../polyp/mainloop-api.h ../polyp/cdecl.h ../polyp/glib-mainloop.h ../polyp/mainloop.h ../polyp/mainloop-signal.h ../polyp/native-common.h ../polyp/polyplib-error.h ../polyp/polyplib-operation.h ../polyp/polyplib-simple.h + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp +# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories +# that are symbolic links (a Unix filesystem feature) are excluded from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = YES + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = PA_C_DECL_BEGIN=,PA_C_DECL_END + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = PA_C_DECL_BEGIN, PA_C_DECL_END + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse the +# parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. Note that this +# option is superseded by the HAVE_DOT option below. This is only a fallback. It is +# recommended to install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes that +# lay further from the root node will be omitted. Note that setting this option to +# 1 or 2 may greatly reduce the computation time needed for large code bases. Also +# note that a graph may be further truncated if the graph's image dimensions are +# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). +# If 0 is used for the depth value (the default), the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/polyp/Makefile.am b/polyp/Makefile.am index ce753da4..7f70ec9d 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -25,12 +25,19 @@ polypincludedir=$(includedir)/polyp EXTRA_DIST = polypaudio.pa depmod.py bin_PROGRAMS = polypaudio pacat pactl -noinst_PROGRAMS = pacat-simple parec-simple mainloop-test mainloop-test-glib +noinst_PROGRAMS = mainloop-test mainloop-test-glib pacat-simple parec-simple polypinclude_HEADERS=polyplib.h \ polyplib-def.h \ polyplib-simple.h \ polyplib-error.h \ + polyplib-stream.h \ + polyplib-context.h \ + polyplib-introspect.h \ + polyplib-subscribe.h \ + polyplib-operation.h \ + polyplib-scache.h \ + cdecl.h \ mainloop-api.h \ mainloop.h \ mainloop-signal.h \ @@ -72,10 +79,11 @@ pkglib_LTLIBRARIES=libiochannel.la \ module-x11-bell.la lib_LTLIBRARIES=libpolyp.la \ - libpolyp-simple.la \ libpolyp-error.la \ libpolyp-mainloop.la \ - libpolyp-mainloop-glib.la + libpolyp-mainloop-glib.la \ + libpolyp-simple.la + polypaudio_SOURCES = idxset.c idxset.h \ queue.c queue.h \ @@ -261,7 +269,7 @@ module_x11_bell_la_SOURCES = module-x11-bell.c module_x11_bell_la_LDFLAGS = -module -avoid-version module_x11_bell_la_LIBADD = $(AM_LIBADD) -lX11 -L/usr/X11R6/lib -libpolyp_la_SOURCES = polyplib.c polyplib.h \ +libpolyp_la_SOURCES = polyplib.h \ polyplib-def.h \ tagstruct.c tagstruct.h \ iochannel.c iochannel.h \ @@ -281,7 +289,14 @@ libpolyp_la_SOURCES = polyplib.c polyplib.h \ socket-util.c socket-util.h \ native-common.h \ sample.c sample.h \ - xmalloc.c xmalloc.h + xmalloc.c xmalloc.h \ + polyplib-operation.c polyplib-operation.h \ + polyplib-context.c polyplib-context.h \ + polyplib-stream.c polyplib-stream.h \ + polyplib-introspect.c polyplib-introspect.h \ + polyplib-scache.c polyplib-scache.h \ + polyplib-subscribe.c polyplib-subscribe.h \ + cdecl.h libpolyp_la_CFLAGS = $(AM_CFLAGS) libpolyp_mainloop_la_SOURCES = mainloop-api.h mainloop-api.c \ diff --git a/polyp/cdecl.h b/polyp/cdecl.h new file mode 100644 index 00000000..39880a47 --- /dev/null +++ b/polyp/cdecl.h @@ -0,0 +1,21 @@ +#ifndef foocdeclhfoo +#define foocdeclhfoo + +/** \file + * C++ compatibility support */ + +#ifdef __cplusplus +/** If using C++ this macro enables C mode, otherwise does nothing */ +#define PA_C_DECL_BEGIN extern "C" { +/** If using C++ this macros switches back to C++ mode, otherwise does nothing */ +#define PA_C_DECL_END } + +#else +/** If using C++ this macro enables C mode, otherwise does nothing */ +#define PA_C_DECL_BEGIN +/** If using C++ this macros switches back to C++ mode, otherwise does nothing */ +#define PA_C_DECL_END + +#endif + +#endif diff --git a/polyp/glib-mainloop.h b/polyp/glib-mainloop.h index 7655108a..c67e72bd 100644 --- a/polyp/glib-mainloop.h +++ b/polyp/glib-mainloop.h @@ -4,20 +4,26 @@ #include #include "mainloop-api.h" +#include "cdecl.h" -#ifdef __cplusplus -extern "C" { -#endif +/** \file + * GLIB main loop support */ + +PA_C_DECL_BEGIN +/** \struct pa_glib_mainloop + * A GLIB main loop object */ struct pa_glib_mainloop; +/** Create a new GLIB main loop object for the specified GLIB main loop context. If c is NULL the default context is used. */ struct pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c); + +/** Free the GLIB main loop object */ void pa_glib_mainloop_free(struct pa_glib_mainloop* g); + +/** Return the abstract main loop API vtable for the GLIB main loop object */ struct pa_mainloop_api* pa_glib_mainloop_get_api(struct pa_glib_mainloop *g); - -#ifdef __cplusplus -} -#endif +PA_C_DECL_BEGIN #endif diff --git a/polyp/llist.h b/polyp/llist.h new file mode 100644 index 00000000..1f145de2 --- /dev/null +++ b/polyp/llist.h @@ -0,0 +1,39 @@ +#ifndef foollistfoo +#define foollistfoo + +#define PA_LLIST_HEAD(t,name) t *name + +#define PA_LLIST_FIELDS(t) t *next, *prev; + +#define PA_LLIST_HEAD_INIT(t,item) do { (item) = NULL; } while(0) + +#define PA_LLIST_INIT(t,item) do { \ + t *_item = (item); \ + assert(_item); \ + _item->prev = _item->next = NULL; \ + } while(0) + +#define PA_LLIST_PREPEND(t,head,item) do { \ + t **_head = &(head), *_item = (item); \ + assert(_item); \ + if ((_item->next = *_head)) \ + _item->next->prev = _item; \ + _item->prev = NULL; \ + *_head = _item; \ + } while (0) + +#define PA_LLIST_REMOVE(t,head,item) do { \ + t **_head = &(head), *_item = (item); \ + assert(_item); \ + if (_item->next) \ + _item->next->prev = _item->prev; \ + if (_item->prev) \ + _item->prev->next = _item->next; \ + else {\ + assert(*_head == _item); \ + *_head = _item->next; \ + } \ + _item->next = _item->prev = NULL; \ + } while(0) + +#endif diff --git a/polyp/mainloop-api.h b/polyp/mainloop-api.h index 1b9e2783..97ab6a68 100644 --- a/polyp/mainloop-api.h +++ b/polyp/mainloop-api.h @@ -22,26 +22,37 @@ USA. ***/ -#include #include +#include -#ifdef __cplusplus -extern "C" { -#endif +#include "cdecl.h" +PA_C_DECL_BEGIN + +/** A bitmask for IO events */ enum pa_io_event_flags { - PA_IO_EVENT_NULL = 0, - PA_IO_EVENT_INPUT = 1, - PA_IO_EVENT_OUTPUT = 2, - PA_IO_EVENT_HANGUP = 4, - PA_IO_EVENT_ERROR = 8, + PA_IO_EVENT_NULL = 0, /**< No event */ + PA_IO_EVENT_INPUT = 1, /**< Input event */ + PA_IO_EVENT_OUTPUT = 2, /**< Output event */ + PA_IO_EVENT_HANGUP = 4, /**< Hangup event */ + PA_IO_EVENT_ERROR = 8, /**< Error event */ }; +/** \struct pa_io_event + * An IO event source object */ struct pa_io_event; + +/** \struct pa_defer_event + * A deferred event source object. Events of this type are triggered once in every main loop iteration */ struct pa_defer_event; + +/** \struct pa_time_event + * A timer event source object */ struct pa_time_event; +/** An abstract mainloop API vtable */ struct pa_mainloop_api { + /** A pointer to some private, arbitrary data of the main loop implementation */ void *userdata; /* IO sources */ @@ -56,20 +67,25 @@ struct pa_mainloop_api { void (*time_free)(struct pa_time_event* e); void (*time_set_destroy)(struct pa_time_event *e, void (*callback) (struct pa_mainloop_api*a, struct pa_time_event *e, void *userdata)); - /* Deferred sources */ + /** Create a new deferred event source object */ struct pa_defer_event* (*defer_new)(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, struct pa_defer_event* e, void *userdata), void *userdata); + + /** Enable or disable a deferred event source temporarily */ void (*defer_enable)(struct pa_defer_event* e, int b); + + /** Free a deferred event source object */ void (*defer_free)(struct pa_defer_event* e); + + /** Set a function that is called when the deferred event source is destroyed. Use this to free the userdata argument if required */ void (*defer_set_destroy)(struct pa_defer_event *e, void (*callback) (struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata)); - /* Exit mainloop */ + /** Exit the main loop and return the specfied retval*/ void (*quit)(struct pa_mainloop_api*a, int retval); }; +/** Run the specified callback function once from the main loop using an anonymous defer event. */ void pa_mainloop_api_once(struct pa_mainloop_api*m, void (*callback)(struct pa_mainloop_api*m, void *userdata), void *userdata); -#ifdef __cplusplus -} -#endif +PA_C_DECL_END #endif diff --git a/polyp/mainloop.h b/polyp/mainloop.h index 58448c3e..4a4c85df 100644 --- a/polyp/mainloop.h +++ b/polyp/mainloop.h @@ -23,6 +23,9 @@ ***/ #include "mainloop-api.h" +#include "cdecl.h" + +PA_C_DECL_BEGIN struct pa_mainloop; @@ -34,4 +37,6 @@ int pa_mainloop_run(struct pa_mainloop *m, int *retval); struct pa_mainloop_api* pa_mainloop_get_api(struct pa_mainloop*m); +PA_C_DECL_END + #endif diff --git a/polyp/memblock.c b/polyp/memblock.c index 0571f5da..a4452efa 100644 --- a/polyp/memblock.c +++ b/polyp/memblock.c @@ -39,6 +39,7 @@ struct pa_memblock *pa_memblock_new(size_t length) { b->ref = 1; b->length = length; b->data = b+1; + b->free_cb = NULL; memblock_count++; memblock_total += length; return b; @@ -50,6 +51,7 @@ struct pa_memblock *pa_memblock_new_fixed(void *d, size_t length) { b->ref = 1; b->length = length; b->data = d; + b->free_cb = NULL; memblock_count++; memblock_total += length; return b; @@ -61,6 +63,21 @@ struct pa_memblock *pa_memblock_new_dynamic(void *d, size_t length) { b->ref = 1; b->length = length; b->data = d; + b->free_cb = NULL; + memblock_count++; + memblock_total += length; + return b; +} + +struct pa_memblock *pa_memblock_new_user(void *d, size_t length, void (*free_cb)(void *p)) { + struct pa_memblock *b; + assert(d && length && free_cb); + b = pa_xmalloc(sizeof(struct pa_memblock)); + b->type = PA_MEMBLOCK_USER; + b->ref = 1; + b->length = length; + b->data = d; + b->free_cb = free_cb; memblock_count++; memblock_total += length; return b; @@ -74,31 +91,28 @@ struct pa_memblock* pa_memblock_ref(struct pa_memblock*b) { void pa_memblock_unref(struct pa_memblock*b) { assert(b && b->ref >= 1); - b->ref--; - - if (b->ref == 0) { - if (b->type == PA_MEMBLOCK_DYNAMIC) - pa_xfree(b->data); + if ((--(b->ref)) == 0) { memblock_count--; memblock_total -= b->length; + if (b->type == PA_MEMBLOCK_USER) { + assert(b->free_cb); + b->free_cb(b->data); + } else if (b->type == PA_MEMBLOCK_DYNAMIC) + pa_xfree(b->data); + pa_xfree(b); } } void pa_memblock_unref_fixed(struct pa_memblock *b) { - void *d; - - assert(b && b->ref >= 1); + assert(b && b->ref >= 1 && b->type == PA_MEMBLOCK_FIXED); - if (b->ref == 1) { + if (b->ref == 1) pa_memblock_unref(b); - return; - } else { - d = pa_xmalloc(b->length); - memcpy(d, b->data, b->length); - b->data = d; + else { + b->data = pa_xmemdup(b->data, b->length); b->type = PA_MEMBLOCK_DYNAMIC; b->ref--; } diff --git a/polyp/memblock.h b/polyp/memblock.h index 4bb02977..6e79aa3e 100644 --- a/polyp/memblock.h +++ b/polyp/memblock.h @@ -25,18 +25,20 @@ #include #include -enum pa_memblock_type { PA_MEMBLOCK_FIXED, PA_MEMBLOCK_APPENDED, PA_MEMBLOCK_DYNAMIC }; +enum pa_memblock_type { PA_MEMBLOCK_FIXED, PA_MEMBLOCK_APPENDED, PA_MEMBLOCK_DYNAMIC, PA_MEMBLOCK_USER }; struct pa_memblock { enum pa_memblock_type type; unsigned ref; size_t length; void *data; + void (*free_cb)(void *p); }; struct pa_memblock *pa_memblock_new(size_t length); struct pa_memblock *pa_memblock_new_fixed(void *data, size_t length); struct pa_memblock *pa_memblock_new_dynamic(void *data, size_t length); +struct pa_memblock *pa_memblock_new_user(void *data, size_t length, void (*free_cb)(void *p)); void pa_memblock_unref(struct pa_memblock*b); struct pa_memblock* pa_memblock_ref(struct pa_memblock*b); diff --git a/polyp/native-common.h b/polyp/native-common.h index 4d5ab53d..fa3213d0 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -64,6 +64,9 @@ enum { PA_COMMAND_SUBSCRIBE, PA_COMMAND_SUBSCRIBE_EVENT, + + PA_COMMAND_SET_SINK_VOLUME, + PA_COMMAND_SET_SINK_INPUT_VOLUME, PA_COMMAND_MAX }; @@ -90,13 +93,14 @@ enum { #define PA_NATIVE_COOKIE_FILE ".polypaudio-cookie" enum pa_subscription_mask { - PA_SUBSCRIPTION_FACILITY_SINK = 1, - PA_SUBSCRIPTION_FACILITY_SOURCE = 2, - PA_SUBSCRIPTION_FACILITY_SINK_INPUT = 4, - PA_SUBSCRIPTION_FACILITY_SOURCE_OUTPUT = 8, - PA_SUBSCRIPTION_FACILITY_MODULE = 16, - PA_SUBSCRIPTION_FACILITY_CLIENT = 32, - PA_SUBSCRIPTION_FACILITY_SAMPLE_CACHE = 64, + PA_SUBSCRIPTION_MASK_NULL = 0, + PA_SUBSCRIPTION_MASK_SINK = 1, + PA_SUBSCRIPTION_MASK_SOURCE = 2, + PA_SUBSCRIPTION_MASK_SINK_INPUT = 4, + PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8, + PA_SUBSCRIPTION_MASK_MODULE = 16, + PA_SUBSCRIPTION_MASK_CLIENT = 32, + PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, }; enum pa_subscription_event_type { diff --git a/polyp/pacat.c b/polyp/pacat.c index 4d8605c7..5d29451a 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -52,18 +52,6 @@ static void quit(int ret) { mainloop_api->quit(mainloop_api, ret); } -static void context_die_callback(struct pa_context *c, void *userdata) { - assert(c); - fprintf(stderr, "Connection to server shut down, exiting.\n"); - quit(1); -} - -static void stream_die_callback(struct pa_stream *s, void *userdata) { - assert(s); - fprintf(stderr, "Stream deleted, exiting.\n"); - quit(1); -} - static void do_stream_write(size_t length) { size_t l; assert(length); @@ -75,7 +63,7 @@ static void do_stream_write(size_t length) { if (l > buffer_length) l = buffer_length; - pa_stream_write(stream, buffer+buffer_index, l); + pa_stream_write(stream, buffer+buffer_index, l, NULL); buffer_length -= l; buffer_index += l; @@ -115,63 +103,97 @@ static void stream_read_callback(struct pa_stream *s, const void*data, size_t le buffer_index = 0; } -static void stream_complete_callback(struct pa_stream*s, int success, void *userdata) { +static void stream_state_callback(struct pa_stream *s, void *userdata) { assert(s); - if (!success) { - fprintf(stderr, "Stream creation failed: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); - quit(1); - return; + switch (pa_stream_get_state(s)) { + case PA_STREAM_CREATING: + break; + + case PA_STREAM_READY: + fprintf(stderr, "Stream successfully created\n"); + break; + + case PA_STREAM_TERMINATED: + quit(0); + break; + + case PA_STREAM_FAILED: + default: + fprintf(stderr, "Stream errror: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + quit(1); } - - fprintf(stderr, "Stream created.\n"); } -static void context_complete_callback(struct pa_context *c, int success, void *userdata) { +static void context_state_callback(struct pa_context *c, void *userdata) { static const struct pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2 }; - - assert(c && !stream); - if (!success) { - fprintf(stderr, "Connection failed: %s\n", pa_strerror(pa_context_errno(c))); - goto fail; - } + assert(c); - fprintf(stderr, "Connection established.\n"); - - if (!(stream = pa_stream_new(c, mode == PLAYBACK ? PA_STREAM_PLAYBACK : PA_STREAM_RECORD, NULL, "pacat", &ss, NULL, stream_complete_callback, NULL))) { - fprintf(stderr, "pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(c))); - goto fail; + switch (pa_context_get_state(c)) { + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + + case PA_CONTEXT_READY: + + assert(c && !stream); + fprintf(stderr, "Connection established.\n"); + + stream = pa_stream_new(c, "pacat", &ss); + assert(stream); + + pa_stream_set_state_callback(stream, stream_state_callback, NULL); + pa_stream_set_write_callback(stream, stream_write_callback, NULL); + pa_stream_set_read_callback(stream, stream_read_callback, NULL); + + if (mode == PLAYBACK) + pa_stream_connect_playback(stream, NULL, NULL); + else + pa_stream_connect_record(stream, NULL, NULL); + + break; + + case PA_CONTEXT_TERMINATED: + quit(0); + break; + + case PA_CONTEXT_FAILED: + default: + fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); } - - pa_stream_set_die_callback(stream, stream_die_callback, NULL); - pa_stream_set_write_callback(stream, stream_write_callback, NULL); - pa_stream_set_read_callback(stream, stream_read_callback, NULL); - - return; - -fail: - quit(1); } static void context_drain_complete(struct pa_context*c, void *userdata) { - quit(0); + pa_context_disconnect(c); } -static void stream_drain_complete(struct pa_stream*s, void *userdata) { +static void stream_drain_complete(struct pa_stream*s, int success, void *userdata) { + struct pa_operation *o; + + if (!success) { + fprintf(stderr, "Failed to drain stream: %s\n", pa_strerror(pa_context_errno(context))); + quit(1); + } + fprintf(stderr, "Playback stream drained.\n"); - pa_stream_free(stream); + pa_stream_disconnect(stream); + pa_stream_unref(stream); stream = NULL; - if (pa_context_drain(context, context_drain_complete, NULL) < 0) - quit(0); - else + if (!(o = pa_context_drain(context, context_drain_complete, NULL))) + pa_context_disconnect(context); + else { + pa_operation_unref(o); fprintf(stderr, "Draining connection to server.\n"); + } } static void stdin_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { @@ -184,7 +206,7 @@ static void stdin_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int return; } - if (!stream || !pa_stream_is_ready(stream) || !(l = w = pa_stream_writable_size(stream))) + if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY || !(l = w = pa_stream_writable_size(stream))) l = 4096; buffer = malloc(l); @@ -192,7 +214,7 @@ static void stdin_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int if ((r = read(fd, buffer, l)) <= 0) { if (r == 0) { fprintf(stderr, "Got EOF.\n"); - pa_stream_drain(stream, stream_drain_complete, NULL); + pa_operation_unref(pa_stream_drain(stream, stream_drain_complete, NULL)); } else { fprintf(stderr, "read() failed: %s\n", strerror(errno)); quit(1); @@ -259,10 +281,11 @@ static void stream_get_latency_callback(struct pa_stream *s, uint32_t latency, v } static void sigusr1_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { - if (mode == PLAYBACK) { - fprintf(stderr, "Got SIGUSR1, requesting latency.\n"); - pa_stream_get_latency(stream, stream_get_latency_callback, NULL); - } + if (mode != PLAYBACK) + return; + + fprintf(stderr, "Got SIGUSR1, requesting latency.\n"); + pa_operation_unref(pa_stream_get_latency(stream, stream_get_latency_callback, NULL)); } int main(int argc, char *argv[]) { @@ -306,12 +329,9 @@ int main(int argc, char *argv[]) { goto quit; } - if (pa_context_connect(context, NULL, context_complete_callback, NULL) < 0) { - fprintf(stderr, "pa_context_connext() failed.\n"); - goto quit; - } - - pa_context_set_die_callback(context, context_die_callback, NULL); + pa_context_set_state_callback(context, context_state_callback, NULL); + + pa_context_connect(context, NULL); if (pa_mainloop_run(m, &ret) < 0) { fprintf(stderr, "pa_mainloop_run() failed.\n"); @@ -320,15 +340,21 @@ int main(int argc, char *argv[]) { quit: if (stream) - pa_stream_free(stream); + pa_stream_unref(stream); + if (context) - pa_context_free(context); + pa_context_unref(context); + if (stdio_event) { + assert(mainloop_api); + mainloop_api->io_free(stdio_event); + } + if (m) { pa_signal_done(); pa_mainloop_free(m); } - + if (buffer) free(buffer); diff --git a/polyp/pactl.c b/polyp/pactl.c index 2f3a4833..0ff2aa90 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -68,31 +68,27 @@ static void quit(int ret) { mainloop_api->quit(mainloop_api, ret); } -static void context_die_callback(struct pa_context *c, void *userdata) { - assert(c); - fprintf(stderr, "Connection to server shut down, exiting.\n"); - quit(1); -} static void context_drain_complete(struct pa_context *c, void *userdata) { - assert(c); - fprintf(stderr, "Connection to server shut down, exiting.\n"); - quit(0); + pa_context_disconnect(c); } static void drain(void) { - if (pa_context_drain(context, context_drain_complete, NULL) < 0) - quit(0); + struct pa_operation *o; + if (!(o = pa_context_drain(context, context_drain_complete, NULL))) + pa_context_disconnect(context); + else + pa_operation_unref(o); } -static void stat_callback(struct pa_context *c, uint32_t blocks, uint32_t total, void *userdata) { - if (blocks == (uint32_t) -1) { +static void stat_callback(struct pa_context *c, const struct pa_stat_info *i, void *userdata) { + if (!i) { fprintf(stderr, "Failed to get statistics: %s\n", pa_strerror(pa_context_errno(c))); quit(1); return; } - fprintf(stderr, "Currently in use: %u blocks containing %u bytes total.\n", blocks, total); + fprintf(stderr, "Currently in use: %u blocks containing %u bytes total.\n", i->memblock_count, i->memblock_total); drain(); } @@ -116,22 +112,23 @@ static void remove_sample_callback(struct pa_context *c, int success, void *user drain(); } -static void stream_die_callback(struct pa_stream *s, void *userdata) { - assert(s); - fprintf(stderr, "Stream deleted, exiting.\n"); - quit(1); -} - -static void finish_sample_callback(struct pa_stream *s, int success, void *userdata) { +static void stream_state_callback(struct pa_stream *s, void *userdata) { assert(s); - if (!success) { - fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(context))); - quit(1); - return; + switch (pa_stream_get_state(s)) { + case PA_STREAM_CREATING: + case PA_STREAM_READY: + break; + + case PA_STREAM_TERMINATED: + drain(); + break; + + case PA_STREAM_FAILED: + default: + fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + quit(1); } - - drain(); } static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) { @@ -151,58 +148,55 @@ static void stream_write_callback(struct pa_stream *s, size_t length, void *user quit(1); } - pa_stream_write(s, d, length); - free(d); + pa_stream_write(s, d, length, free); sample_length -= length; if (sample_length <= 0) { pa_stream_set_write_callback(sample_stream, NULL, NULL); - pa_stream_finish_sample(sample_stream, finish_sample_callback, NULL); - } -} - -static void upload_callback(struct pa_stream *s, int success, void *userdata) { - if (!success) { - fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(context))); - quit(1); + pa_stream_finish_upload(sample_stream); } } -static void context_complete_callback(struct pa_context *c, int success, void *userdata) { +static void context_state_callback(struct pa_context *c, void *userdata) { assert(c); + switch (pa_context_get_state(c)) { + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + + case PA_CONTEXT_READY: + if (action == STAT) + pa_operation_unref(pa_context_stat(c, stat_callback, NULL)); + else if (action == PLAY_SAMPLE) + pa_operation_unref(pa_context_play_sample(c, process_argv[2], NULL, 0x100, play_sample_callback, NULL)); + else if (action == REMOVE_SAMPLE) + pa_operation_unref(pa_context_remove_sample(c, process_argv[2], remove_sample_callback, NULL)); + else if (action == UPLOAD_SAMPLE) { + + sample_stream = pa_stream_new(c, sample_name, &sample_spec); + assert(sample_stream); + + pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL); + pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL); + pa_stream_connect_upload(sample_stream, sample_length); + } else { + assert(action == EXIT); + pa_context_exit_daemon(c); + drain(); + } + break; - if (!success) { - fprintf(stderr, "Connection failed: %s\n", pa_strerror(pa_context_errno(c))); - goto fail; - } + case PA_CONTEXT_TERMINATED: + quit(0); + break; - fprintf(stderr, "Connection established.\n"); - - if (action == STAT) - pa_context_stat(c, stat_callback, NULL); - else if (action == PLAY_SAMPLE) - pa_context_play_sample(c, process_argv[2], NULL, 0x100, play_sample_callback, NULL); - else if (action == REMOVE_SAMPLE) - pa_context_remove_sample(c, process_argv[2], remove_sample_callback, NULL); - else if (action == UPLOAD_SAMPLE) { - if (!(sample_stream = pa_context_upload_sample(c, sample_name, &sample_spec, sample_length, upload_callback, NULL))) { - fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(c))); - goto fail; - } - - pa_stream_set_die_callback(sample_stream, stream_die_callback, NULL); - pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL); - } else { - assert(action == EXIT); - pa_context_exit(c); - drain(); + case PA_CONTEXT_FAILED: + default: + fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); } - - return; - -fail: - quit(1); } static void exit_signal_callback(struct pa_mainloop_api *m, struct pa_signal_event *e, int sig, void *userdata) { @@ -234,12 +228,15 @@ int main(int argc, char *argv[]) { sample_name = argv[3]; else { char *f = strrchr(argv[2], '/'); + size_t n; if (f) f++; else f = argv[2]; - strncpy(sample_name = tmp, f, strcspn(f, ".")); + n = strcspn(f, "."); + strncpy(sample_name = tmp, f, n); + tmp[n] = 0; } memset(&sfinfo, 0, sizeof(sfinfo)); @@ -292,12 +289,8 @@ int main(int argc, char *argv[]) { goto quit; } - if (pa_context_connect(context, NULL, context_complete_callback, NULL) < 0) { - fprintf(stderr, "pa_context_connext() failed.\n"); - goto quit; - } - - pa_context_set_die_callback(context, context_die_callback, NULL); + pa_context_set_state_callback(context, context_state_callback, NULL); + pa_context_connect(context, NULL); if (pa_mainloop_run(m, &ret) < 0) { fprintf(stderr, "pa_mainloop_run() failed.\n"); @@ -305,8 +298,11 @@ int main(int argc, char *argv[]) { } quit: + if (sample_stream) + pa_stream_unref(sample_stream); + if (context) - pa_context_free(context); + pa_context_unref(context); if (m) { pa_signal_done(); @@ -315,6 +311,6 @@ quit: if (sndfile) sf_close(sndfile); - + return ret; } diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 35001d3d..5f849e24 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -31,7 +31,8 @@ #include #include -#include "polyplib.h" +#include "polyplib-internal.h" +#include "polyplib-context.h" #include "native-common.h" #include "pdispatch.h" #include "pstream.h" @@ -42,128 +43,11 @@ #include "util.h" #include "xmalloc.h" -#define DEFAULT_MAXLENGTH 204800 -#define DEFAULT_TLENGTH 10240 -#define DEFAULT_PREBUF 4096 -#define DEFAULT_MINREQ 1024 -#define DEFAULT_FRAGSIZE 1024 - -#define DEFAULT_TIMEOUT (5*60) -#define DEFAULT_SERVER "/tmp/polypaudio/native" -#define DEFAULT_PORT "4713" - -struct pa_context { - char *name; - struct pa_mainloop_api* mainloop; - struct pa_socket_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; - struct pa_dynarray *record_streams, *playback_streams; - struct pa_stream *first_stream; - uint32_t ctag; - uint32_t error; - enum { - CONTEXT_UNCONNECTED, - CONTEXT_CONNECTING, - CONTEXT_AUTHORIZING, - CONTEXT_SETTING_NAME, - CONTEXT_READY, - CONTEXT_DEAD - } state; - - void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); - void *connect_complete_userdata; - - void (*drain_complete_callback)(struct pa_context*c, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_context*c, void *userdata); - void *die_userdata; - - void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); - void *stat_userdata; - - void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); - void *play_sample_userdata; - - void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); - void *remove_sample_userdata; - - void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); - void *get_server_info_userdata; - - void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); - void *get_sink_info_userdata; - - void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); - void *get_source_info_userdata; - - void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); - void *subscribe_userdata; - enum pa_subscription_mask subscribe_mask; - - void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); - void *get_client_info_userdata; - - void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); - void *get_module_info_userdata; - - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; -}; - -struct pa_stream { - struct pa_context *context; - struct pa_stream *next, *previous; - - char *name; - struct pa_buffer_attr buffer_attr; - struct pa_sample_spec sample_spec; - uint32_t channel; - int channel_valid; - uint32_t device_index; - enum pa_stream_direction direction; - - enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; - uint32_t requested_bytes; - - void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); - void *read_userdata; - - void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); - void *write_userdata; - - void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); - void *create_complete_userdata; - - void (*drain_complete_callback)(struct pa_stream *s, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_stream*c, void *userdata); - void *die_userdata; - - void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); - void *get_latency_userdata; - - void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); - void *finish_sample_userdata; -}; - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_EXIT] = { NULL }, - [PA_COMMAND_REQUEST] = { command_request }, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, + [PA_COMMAND_REQUEST] = { pa_command_request }, + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { pa_command_stream_killed }, + [PA_COMMAND_RECORD_STREAM_KILLED] = { pa_command_stream_killed }, + [PA_COMMAND_SUBSCRIBE_EVENT] = { pa_command_subscribe_event }, }; struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { @@ -171,65 +55,41 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * assert(mainloop && name); c = pa_xmalloc(sizeof(struct pa_context)); + c->ref = 1; c->name = pa_xstrdup(name); c->mainloop = mainloop; c->client = NULL; c->pstream = NULL; c->pdispatch = NULL; c->playback_streams = pa_dynarray_new(); - assert(c->playback_streams); c->record_streams = pa_dynarray_new(); - assert(c->record_streams); - c->first_stream = NULL; + assert(c->playback_streams && c->record_streams); + + PA_LLIST_HEAD_INIT(struct pa_stream, c->streams); + PA_LLIST_HEAD_INIT(struct pa_operation, c->operations); + c->error = PA_ERROR_OK; - c->state = CONTEXT_UNCONNECTED; + c->state = PA_CONTEXT_UNCONNECTED; c->ctag = 0; - c->connect_complete_callback = NULL; - c->connect_complete_userdata = NULL; - - c->drain_complete_callback = NULL; - c->drain_complete_userdata = NULL; - - c->die_callback = NULL; - c->die_userdata = NULL; - - c->stat_callback = NULL; - c->stat_userdata = NULL; - - c->play_sample_callback = NULL; - c->play_sample_userdata = NULL; - - c->remove_sample_callback = NULL; - c->remove_sample_userdata = NULL; - - c->get_server_info_callback = NULL; - c->get_server_info_userdata = NULL; - - c->get_sink_info_callback = NULL; - c->get_sink_info_userdata = NULL; - - c->get_source_info_callback = NULL; - c->get_source_info_userdata = NULL; + c->state_callback = NULL; + c->state_userdata = NULL; c->subscribe_callback = NULL; c->subscribe_userdata = NULL; - c->get_client_info_callback = NULL; - c->get_client_info_userdata = NULL; - - c->get_module_info_callback = NULL; - c->get_module_info_userdata = NULL; - pa_check_for_sigpipe(); return c; } -void pa_context_free(struct pa_context *c) { +static void context_free(struct pa_context *c) { assert(c); - while (c->first_stream) - pa_stream_free(c->first_stream); + while (c->operations) + pa_operation_cancel(c->operations); + + while (c->streams) + pa_stream_set_state(c->streams, PA_STREAM_TERMINATED); if (c->client) pa_socket_client_free(c->client); @@ -237,6 +97,7 @@ void pa_context_free(struct pa_context *c) { pa_pdispatch_free(c->pdispatch); if (c->pstream) pa_pstream_free(c->pstream); + if (c->record_streams) pa_dynarray_free(c->record_streams, NULL, NULL); if (c->playback_streams) @@ -246,66 +107,82 @@ void pa_context_free(struct pa_context *c) { pa_xfree(c); } -static void stream_dead(struct pa_stream *s) { - assert(s); - - if (s->state == STREAM_DEAD) - return; - - if (s->state == STREAM_READY) { - s->state = STREAM_DEAD; - if (s->die_callback) - s->die_callback(s, s->die_userdata); - } else - s->state = STREAM_DEAD; +struct pa_context* pa_context_ref(struct pa_context *c) { + assert(c && c->ref >= 1); + c->ref++; + return c; } -static void context_dead(struct pa_context *c) { - struct pa_stream *s; +void pa_context_unref(struct pa_context *c) { + assert(c && c->ref >= 1); + + if ((--(c->ref)) == 0) + context_free(c); +} + +void pa_context_set_state(struct pa_context *c, enum pa_context_state st) { assert(c); - if (c->state == CONTEXT_DEAD) + if (c->state == st) return; - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) - pa_pstream_free(c->pstream); - c->pstream = NULL; + pa_context_ref(c); + + if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) { + struct pa_stream *s; + + s = c->streams ? pa_stream_ref(c->streams) : NULL; + while (s) { + struct pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL; + pa_stream_set_state(s, st == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED); + pa_stream_unref(s); + s = n; + } + + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + c->pdispatch = NULL; - if (c->client) - pa_socket_client_free(c->client); - c->client = NULL; + if (c->pstream) + pa_pstream_free(c->pstream); + c->pstream = NULL; - for (s = c->first_stream; s; s = s->next) - stream_dead(s); - - if (c->state == CONTEXT_READY) { - c->state = CONTEXT_DEAD; - if (c->die_callback) - c->die_callback(c, c->die_userdata); - } else - c->state = CONTEXT_DEAD; + if (c->client) + pa_socket_client_free(c->client); + c->client = NULL; + } + + c->state = st; + if (c->state_callback) + c->state_callback(c, c->state_userdata); + + pa_context_unref(c); +} + +void pa_context_fail(struct pa_context *c, int error) { + assert(c); + c->error = error; + pa_context_set_state(c, PA_CONTEXT_FAILED); } static void pstream_die_callback(struct pa_pstream *p, void *userdata) { struct pa_context *c = userdata; assert(p && c); - c->error = PA_ERROR_CONNECTIONTERMINATED; - context_dead(c); + pa_context_fail(c, PA_ERROR_CONNECTIONTERMINATED); } static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { struct pa_context *c = userdata; assert(p && packet && c); + pa_context_ref(c); + if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { fprintf(stderr, "polyp.c: invalid packet.\n"); - c->error = PA_ERROR_PROTOCOL; - context_dead(c); + pa_context_fail(c, PA_ERROR_PROTOCOL); } + + pa_context_unref(c); } static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { @@ -313,90 +190,100 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, in struct pa_stream *s; assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - if (!(s = pa_dynarray_get(c->record_streams, channel))) - return; + pa_context_ref(c); + + if ((s = pa_dynarray_get(c->record_streams, channel))) { + if (s->read_callback) + s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); + } - if (s->read_callback) - s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); + pa_context_unref(c); } -static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { +int pa_context_handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { assert(c && t); - + if (command == PA_COMMAND_ERROR) { if (pa_tagstruct_getu32(t, &c->error) < 0) { - c->error = PA_ERROR_PROTOCOL; + pa_context_fail(c, PA_ERROR_PROTOCOL); return -1; + } - - return 0; + } else if (command == PA_COMMAND_TIMEOUT) + c->error = PA_ERROR_TIMEOUT; + else { + pa_context_fail(c, PA_ERROR_PROTOCOL); + return -1; } - c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; - return -1; + return 0; } static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_context *c = userdata; - assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); + assert(pd && c && (c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME)); + pa_context_ref(c); + if (command != PA_COMMAND_REPLY) { - handle_error(c, command, t); - context_dead(c); + if (pa_context_handle_error(c, command, t) < 0) + pa_context_fail(c, PA_ERROR_PROTOCOL); - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; + goto finish; } - if (c->state == CONTEXT_AUTHORIZING) { - struct pa_tagstruct *t; - c->state = CONTEXT_SETTING_NAME; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, c->name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - } else { - assert(c->state == CONTEXT_SETTING_NAME); - - c->state = CONTEXT_READY; + switch(c->state) { + case PA_CONTEXT_AUTHORIZING: { + struct pa_tagstruct *t; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, c->name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + + pa_context_set_state(c, PA_CONTEXT_SETTING_NAME); + break; + } - if (c->connect_complete_callback) - c->connect_complete_callback(c, 1, c->connect_complete_userdata); + case PA_CONTEXT_SETTING_NAME : + pa_context_set_state(c, PA_CONTEXT_READY); + break; + + default: + assert(0); } - return; +finish: + pa_context_unref(c); } static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { struct pa_context *c = userdata; struct pa_tagstruct *t; uint32_t tag; - assert(client && c && c->state == CONTEXT_CONNECTING); + assert(client && c && c->state == PA_CONTEXT_CONNECTING); + pa_context_ref(c); + pa_socket_client_free(client); c->client = NULL; if (!io) { - c->error = PA_ERROR_CONNECTIONREFUSED; - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; + pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + goto finish; } - + + assert(!c->pstream); c->pstream = pa_pstream_new(c->mainloop, io); assert(c->pstream); + pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - + + assert(!c->pdispatch); c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); assert(c->pdispatch); @@ -407,7 +294,11 @@ static void on_connection(struct pa_socket_client *client, struct pa_iochannel*i pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - c->state = CONTEXT_AUTHORIZING; + + pa_context_set_state(c, PA_CONTEXT_AUTHORIZING); + +finish: + pa_context_unref(c); } static struct sockaddr *resolve_server(const char *server, size_t *len) { @@ -438,353 +329,89 @@ static struct sockaddr *resolve_server(const char *server, size_t *len) { return sa; } -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { - assert(c && c->state == CONTEXT_UNCONNECTED); +int pa_context_connect(struct pa_context *c, const char *server) { + int r = -1; + assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED); + pa_context_ref(c); + if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { - c->error = PA_ERROR_AUTHKEY; - return -1; + pa_context_fail(c, PA_ERROR_AUTHKEY); + goto finish; } if (!server) - if (!(server = getenv("POLYP_SERVER"))) + if (!(server = getenv(ENV_DEFAULT_SERVER))) server = DEFAULT_SERVER; assert(!c->client); if (*server == '/') { if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; + pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + goto finish; } } else { struct sockaddr* sa; size_t sa_len; if (!(sa = resolve_server(server, &sa_len))) { - c->error = PA_ERROR_INVALIDSERVER; - return -1; + pa_context_fail(c, PA_ERROR_INVALIDSERVER); + goto finish; } c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); pa_xfree(sa); if (!c->client) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; + pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + goto finish; } } - c->connect_complete_callback = complete; - c->connect_complete_userdata = userdata; - pa_socket_client_set_callback(c->client, on_connection, c); - c->state = CONTEXT_CONNECTING; + pa_context_set_state(c, PA_CONTEXT_CONNECTING); - return 0; + r = 0; + +finish: + pa_context_unref(c); + + return r; } -int pa_context_is_dead(struct pa_context *c) { +void pa_context_disconnect(struct pa_context *c) { assert(c); - return c->state == CONTEXT_DEAD; + pa_context_set_state(c, PA_CONTEXT_TERMINATED); } -int pa_context_is_ready(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_READY; +enum pa_context_state pa_context_get_state(struct pa_context *c) { + assert(c && c->ref >= 1); + return c->state; } int pa_context_errno(struct pa_context *c) { - assert(c); + assert(c && c->ref >= 1); return c->error; } -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { - assert(c); - c->die_callback = cb; - c->die_userdata = userdata; -} - -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - uint32_t channel; - assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - return; - - c->error = PA_ERROR_KILLED; - stream_dead(s); -} - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s; - struct pa_context *c = userdata; - uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - return; - - if (s->state != STREAM_READY) - return; - - s->requested_bytes += bytes; - - if (s->requested_bytes && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); -} - -static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s && s->state == STREAM_CREATING); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - - return; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - - s->state = STREAM_READY; - if (s->create_complete_callback) - s->create_complete_callback(s, 1, s->create_complete_userdata); -} - -static void create_stream(struct pa_stream *s, const char *dev) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s); - - s->state = STREAM_CREATING; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, s->buffer_attr.maxlength); - if (s->direction == PA_STREAM_PLAYBACK) { - pa_tagstruct_putu32(t, s->buffer_attr.tlength); - pa_tagstruct_putu32(t, s->buffer_attr.prebuf); - pa_tagstruct_putu32(t, s->buffer_attr.minreq); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); -} - -static struct pa_stream *internal_stream_new(struct pa_context *c) { - struct pa_stream *s; - - s = pa_xmalloc(sizeof(struct pa_stream)); - s->context = c; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->die_callback = NULL; - s->die_userdata = NULL; - s->create_complete_callback = NULL; - s->create_complete_userdata = NULL; - s->get_latency_callback = NULL; - s->get_latency_userdata = NULL; - s->finish_sample_callback = NULL; - s->finish_sample_userdata = NULL; - - s->name = NULL; - s->state = STREAM_CREATING; - s->requested_bytes = 0; - s->channel = 0; - s->channel_valid = 0; - s->device_index = (uint32_t) -1; - - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->next = c->first_stream; - if (s->next) - s->next->previous = s; - s->previous = NULL; - c->first_stream = s; - - return s; -} - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata) { - - struct pa_stream *s; - - assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = complete; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = dir; - s->sample_spec = *ss; - if (attr) - s->buffer_attr = *attr; - else { - s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; - s->buffer_attr.tlength = DEFAULT_TLENGTH; - s->buffer_attr.prebuf = DEFAULT_PREBUF; - s->buffer_attr.minreq = DEFAULT_MINREQ; - s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; - } - - create_stream(s, dev); - - return s; -} - -void pa_stream_free(struct pa_stream *s) { - assert(s && s->context); - - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - pa_xfree(s->name); - - if (s->channel_valid && s->context->state == CONTEXT_READY) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); - pa_tagstruct_putu32(t, s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - } - - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; - else - s->context->first_stream = s->next; - - pa_xfree(s); -} - -void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { - struct pa_memchunk chunk; - assert(s && s->context && data && length && s->state == STREAM_READY); - - chunk.memblock = pa_memblock_new(length); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); - pa_memblock_unref(chunk.memblock); - - /*fprintf(stderr, "Sent %u bytes\n", length);*/ - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; -} - -size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s && s->state == STREAM_READY); - return s->requested_bytes; -} - -void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->read_callback = cb; - s->read_userdata = userdata; -} - -int pa_stream_is_dead(struct pa_stream *s) { - return s->state == STREAM_DEAD; -} - -int pa_stream_is_ready(struct pa_stream*s) { - return s->state == STREAM_READY; -} - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { - assert(s); - s->die_callback = cb; - s->die_userdata = userdata; +void pa_context_set_state_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { + assert(c && c->ref >= 1); + c->state_callback = cb; + c->state_userdata = userdata; } int pa_context_is_pending(struct pa_context *c) { - assert(c); + assert(c && c->ref >= 1); - if (c->state != CONTEXT_READY) + if (c->state != PA_CONTEXT_READY) return 0; + assert(c->pstream && c->pdispatch); return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); } -struct pa_context* pa_stream_get_context(struct pa_stream *p) { - assert(p); - return p->context; -} - -static void set_dispatch_callbacks(struct pa_context *c); +static void set_dispatch_callbacks(struct pa_operation *o); static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { set_dispatch_callbacks(userdata); @@ -794,107 +421,59 @@ static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { set_dispatch_callbacks(userdata); } -static void set_dispatch_callbacks(struct pa_context *c) { - assert(c && c->state == CONTEXT_READY); +static void set_dispatch_callbacks(struct pa_operation *o) { + int done = 1; + assert(o && o->context && o->context->ref >= 1 && o->ref >= 1 && o->context->state == PA_CONTEXT_READY); - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL); - if (pa_pdispatch_is_pending(c->pdispatch)) { - pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); - return; - } - - if (pa_pstream_is_pending(c->pstream)) { - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - return; + if (pa_pdispatch_is_pending(o->context->pdispatch)) { + pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o); + done = 0; } - assert(c->drain_complete_callback); - c->drain_complete_callback(c, c->drain_complete_userdata); -} - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata) { - - assert(c && c->state == CONTEXT_READY); - - if (complete == NULL) { - c->drain_complete_callback = NULL; - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - return 0; + if (pa_pstream_is_pending(o->context->pstream)) { + pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o); + done = 0; } - - if (!pa_context_is_pending(c)) - return -1; - - c->drain_complete_callback = complete; - c->drain_complete_userdata = userdata; - - set_dispatch_callbacks(c); - - return 0; -} -static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; + if (!done) + pa_operation_ref(o); + else { + if (o->callback) { + void (*cb)(struct pa_context *c, void *userdata); + cb = (void*) o->callback; + cb(o->context, o->userdata); } + + pa_operation_done(o); + } - stream_dead(s); - return; - } - - if (s->state != STREAM_READY) - return; - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->drain_complete_callback) { - void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; - s->drain_complete_callback = NULL; - temp(s, s->drain_complete_userdata); - } + pa_operation_unref(o); } +struct pa_operation* pa_context_drain(struct pa_context *c, void (*cb) (struct pa_context*c, void *userdata), void *userdata) { + struct pa_operation *o; + assert(c && c->ref >= 1 && c->state == PA_CONTEXT_READY); -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s && s->state == STREAM_READY); + if (!pa_context_is_pending(c)) + return NULL; - if (!complete) { - s->drain_complete_callback = NULL; - return; - } + o = pa_operation_new(c, NULL); + assert(o); + o->callback = cb; + o->userdata = userdata; - s->drain_complete_callback = complete; - s->drain_complete_userdata = userdata; + set_dispatch_callbacks(pa_operation_ref(o)); - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); + return o; } -void pa_context_exit(struct pa_context *c) { +void pa_context_exit_daemon(struct pa_context *c) { struct pa_tagstruct *t; + assert(c && c->ref >= 1); + t = pa_tagstruct_new(NULL, 0); assert(t); pa_tagstruct_putu32(t, PA_COMMAND_EXIT); @@ -902,649 +481,46 @@ void pa_context_exit(struct pa_context *c) { pa_pstream_send_tagstruct(c->pstream, t); } -static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - uint32_t total, count; - assert(pd && c); +void pa_context_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + int success = 1; + assert(pd && o && o->context && o->ref >= 1); if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; - if (c->stat_callback) - c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); - return; + success = 0; + } else if (!pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; } - if (pa_tagstruct_getu32(t, &count) < 0 || - pa_tagstruct_getu32(t, &total) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; + if (o->callback) { + void (*cb)(struct pa_context *c, int success, void *userdata) = o->callback; + cb(o->context, success, o->userdata); } - if (c->stat_callback) - c->stat_callback(c, count, total, c->stat_userdata); +finish: + pa_operation_done(o); + pa_operation_unref(o); } -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { - uint32_t tag; +struct pa_operation* pa_context_send_simple_command(struct pa_context *c, uint32_t command, void (*internal_callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void (*cb)(), void *userdata) { struct pa_tagstruct *t; + struct pa_operation *o; + uint32_t tag; + assert(c && cb); - c->stat_callback = cb; - c->stat_userdata = userdata; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; - if (cb == NULL) - return; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_STAT); + pa_tagstruct_putu32(t, command); pa_tagstruct_putu32(t, tag = c->ctag++); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); -} - -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t latency; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_callback, o); - if (s->get_latency_callback) - s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &latency) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, latency, s->get_latency_userdata); -} - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - p->get_latency_callback = cb; - p->get_latency_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); -} - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_stream *s; - struct pa_tagstruct *t; - uint32_t tag; - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = cb; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = PA_STREAM_UPLOAD; - s->sample_spec = *ss; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_sample_spec(t, ss); - pa_tagstruct_putu32(t, length); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); - - return s; -} - -static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 0, s->finish_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 1, s->finish_sample_userdata); -} - -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(p); - - p->finish_sample_callback = cb; - p->finish_sample_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); -} - -static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 0, c->play_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 1, c->play_sample_userdata); -} - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name && *name && (!dev || *dev)); - - c->play_sample_callback = cb; - c->play_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, volume); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); -} - -static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 0, c->remove_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 1, c->remove_sample_userdata); -} - -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name); - - c->remove_sample_callback = cb; - c->remove_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); -} - -static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_server_info i; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, NULL, c->get_server_info_userdata); - return; - } - - if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, &i, c->get_server_info_userdata); -} - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_server_info_callback = cb; - c->get_server_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); -} - -static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_sink_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.volume) < 0 || - pa_tagstruct_getu32(t, &i.monitor_source) < 0 || - pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || - pa_tagstruct_getu32(t, &i.latency) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); -} - -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_source_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || - pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); -} - -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { - struct pa_tagstruct *t; - assert(c); - - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; - c->subscribe_mask = m; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, c->ctag++); - pa_tagstruct_putu32(t, cb ? m : 0); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - enum pa_subscription_event_type e; - uint32_t index; - assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); - - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &index) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) - c->subscribe_callback(c, e, index, c->subscribe_userdata); -} - -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_client_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.protocol_name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); -} - - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_module_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_getu32(t, &i.auto_unload) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); -} - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} - -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); + return pa_operation_ref(o); } diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h index a0dd9f9c..6a1cc8bd 100644 --- a/polyp/polyplib-context.h +++ b/polyp/polyplib-context.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo +#ifndef foopolyplibcontexthfoo +#define foopolyplibcontexthfoo /* $Id$ */ @@ -22,157 +22,71 @@ USA. ***/ -#include - #include "sample.h" #include "polyplib-def.h" #include "mainloop-api.h" +#include "cdecl.h" +#include "polyplib-operation.h" + +/** \file + * Connection contexts */ + +PA_C_DECL_BEGIN + +/** The state of a connection context */ +enum pa_context_state { + PA_CONTEXT_UNCONNECTED, /**< The context hasn't been connected yet */ + PA_CONTEXT_CONNECTING, /**< A connection is being established */ + PA_CONTEXT_AUTHORIZING, /**< The client is authorizing itself to the daemon */ + PA_CONTEXT_SETTING_NAME, /**< The client is passing its application name to the daemon */ + PA_CONTEXT_READY, /**< The connection is established, the context is ready to execute operations */ + PA_CONTEXT_FAILED, /**< The connection failed or was disconnected */ + PA_CONTEXT_TERMINATED /**< The connect was terminated cleanly */ +}; -#ifdef __cplusplus -//extern "C" { -#endif - +/** \struct pa_context + * A connection context to a daemon */ struct pa_context; -struct pa_stream; +/** Instantiate a new connection context with an abstract mainloop API + * and an application name */ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); + +/** Decrease the reference counter of the context by one */ void pa_context_unref(struct pa_context *c); + +/** Increase the reference counter of the context by one */ struct pa_context* pa_context_ref(struct pa_context *c); -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); -int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); +/** Set a callback function that is called whenever the context status changes */ +void pa_context_set_state_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); -int pa_context_is_dead(struct pa_context *c); -int pa_context_is_ready(struct pa_context *c); +/** Return the error number of the last failed operation */ int pa_context_errno(struct pa_context *c); +/** Return non-zero if some data is pending to be written to the connection */ int pa_context_is_pending(struct pa_context *c); -struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_unref(struct pa_stream *s); -struct pa_stream *pa_stream_ref(struct pa_stream *s); - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); - -void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); -void pa_stream_write(struct pa_stream *p, const void *data, size_t length); -size_t pa_stream_writable_size(struct pa_stream *p); +/** Return the current context status */ +enum pa_context_state pa_context_get_state(struct pa_context *c); -void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); +/** Connect the context to the specified server. If server is NULL, +connect to the default server. This routine may but will not always +return synchronously on error. Use pa_context_set_state_callback() to +be notified when the connection is established */ +int pa_context_connect(struct pa_context *c, const char *server); -int pa_stream_is_dead(struct pa_stream *p); -int pa_stream_is_ready(struct pa_stream*p); +/** Terminate the context connection immediately */ +void pa_context_disconnect(struct pa_context *c); -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); +/** Drain the context. If there is nothing to drain, the function returns NULL */ +struct pa_operation* pa_context_drain(struct pa_context *c, void (*cb) (struct pa_context*c, void *userdata), void *userdata); -struct pa_context* pa_stream_get_context(struct pa_stream *p); +/** Tell the daemon to exit. No operation object is returned as the + * connection is terminated when the daemon quits, thus this operation + * would never complete. */ +void pa_context_exit_daemon(struct pa_context *c); -uint32_t pa_stream_get_index(struct pa_stream *s); - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); - -struct pa_sink_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t volume; - uint32_t monitor_source; - const char *monitor_source_name; - uint32_t latency; -}; - -void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); - -struct pa_source_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t monitor_of_sink; - const char *monitor_of_sink_name; -}; - -void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); - -struct pa_server_info { - const char *user_name; - const char *host_name; - const char *server_version; - const char *server_name; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); - -struct pa_module_info { - uint32_t index; - const char*name, *argument; - uint32_t n_used, auto_unload; -}; - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); - -struct pa_client_info { - uint32_t index; - const char *name; - uint32_t owner_module; - const char *protocol_name; -}; - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); - -struct pa_sink_input_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t sink; - struct pa_sample_spec sample_spec; - uint32_t volume; - uint32_t latency; -}; - -void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); - -struct pa_source_output_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t source; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); - -void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); - -void pa_context_exit(struct pa_context *c); -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); - -#ifdef __cplusplus -} -#endif +PA_C_DECL_END #endif diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index d96c6899..fc19be69 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -23,14 +23,13 @@ ***/ #include - -#ifdef __cplusplus -extern "C" { -#endif - #include "native-common.h" +#include "cdecl.h" + +PA_C_DECL_BEGIN enum pa_stream_direction { + PA_STREAM_NODIRECTION, PA_STREAM_PLAYBACK, PA_STREAM_RECORD, PA_STREAM_UPLOAD @@ -43,9 +42,9 @@ struct pa_buffer_attr { uint32_t minreq; uint32_t fragsize; }; - -#ifdef __cplusplus -} -#endif + +#define PA_INVALID_INDEX ((uint32_t) -1) + +PA_C_DECL_END #endif diff --git a/polyp/polyplib-error.h b/polyp/polyplib-error.h index d76ce6ff..d7519af4 100644 --- a/polyp/polyplib-error.h +++ b/polyp/polyplib-error.h @@ -23,15 +23,13 @@ ***/ #include +#include "cdecl.h" -#ifdef __cplusplus -extern "C" { -#endif +PA_C_DECL_BEGIN; +/** Return a human readable error message for the specified numeric error code */ const char* pa_strerror(uint32_t error); -#ifdef __cplusplus -} -#endif - +PA_C_DECL_END; + #endif diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 35001d3d..0b6b3887 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -1,3 +1,6 @@ +#ifndef foopolyplibinternalhfoo +#define foopolyplibinternalhfoo + /* $Id$ */ /*** @@ -19,28 +22,16 @@ USA. ***/ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "polyplib.h" -#include "native-common.h" -#include "pdispatch.h" +#include "mainloop-api.h" +#include "socket-client.h" #include "pstream.h" +#include "pdispatch.h" #include "dynarray.h" -#include "socket-client.h" -#include "pstream-util.h" -#include "authkey.h" -#include "util.h" -#include "xmalloc.h" + +#include "polyplib-context.h" +#include "polyplib-stream.h" +#include "polyplib-operation.h" +#include "llist.h" #define DEFAULT_MAXLENGTH 204800 #define DEFAULT_TLENGTH 10240 @@ -52,68 +43,41 @@ #define DEFAULT_SERVER "/tmp/polypaudio/native" #define DEFAULT_PORT "4713" +#define ENV_DEFAULT_SINK "POLYP_SINK" +#define ENV_DEFAULT_SOURCE "POLYP_SOURCE" +#define ENV_DEFAULT_SERVER "POLYP_SERVER" + struct pa_context { + int ref; + char *name; struct pa_mainloop_api* mainloop; + struct pa_socket_client *client; struct pa_pstream *pstream; struct pa_pdispatch *pdispatch; + struct pa_dynarray *record_streams, *playback_streams; - struct pa_stream *first_stream; + PA_LLIST_HEAD(struct pa_stream, streams); + PA_LLIST_HEAD(struct pa_operation, operations); + uint32_t ctag; uint32_t error; - enum { - CONTEXT_UNCONNECTED, - CONTEXT_CONNECTING, - CONTEXT_AUTHORIZING, - CONTEXT_SETTING_NAME, - CONTEXT_READY, - CONTEXT_DEAD - } state; - - void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); - void *connect_complete_userdata; - - void (*drain_complete_callback)(struct pa_context*c, void *userdata); - void *drain_complete_userdata; + enum pa_context_state state; - void (*die_callback)(struct pa_context*c, void *userdata); - void *die_userdata; - - void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); - void *stat_userdata; - - void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); - void *play_sample_userdata; + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; - void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); - void *remove_sample_userdata; - - void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); - void *get_server_info_userdata; - - void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); - void *get_sink_info_userdata; - - void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); - void *get_source_info_userdata; + void (*state_callback)(struct pa_context*c, void *userdata); + void *state_userdata; void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); void *subscribe_userdata; - enum pa_subscription_mask subscribe_mask; - - void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); - void *get_client_info_userdata; - - void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); - void *get_module_info_userdata; - - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; }; struct pa_stream { + int ref; struct pa_context *context; - struct pa_stream *next, *previous; + PA_LLIST_FIELDS(struct pa_stream); char *name; struct pa_buffer_attr buffer_attr; @@ -122,1429 +86,47 @@ struct pa_stream { int channel_valid; uint32_t device_index; enum pa_stream_direction direction; - - enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; uint32_t requested_bytes; + enum pa_stream_state state; + + void (*state_callback)(struct pa_stream*c, void *userdata); + void *state_userdata; void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); void *read_userdata; void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); void *write_userdata; - - void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); - void *create_complete_userdata; - - void (*drain_complete_callback)(struct pa_stream *s, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_stream*c, void *userdata); - void *die_userdata; - - void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); - void *get_latency_userdata; - - void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); - void *finish_sample_userdata; }; -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +struct pa_operation { + int ref; + struct pa_context *context; + struct pa_stream *stream; + PA_LLIST_FIELDS(struct pa_operation); -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_EXIT] = { NULL }, - [PA_COMMAND_REQUEST] = { command_request }, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, + enum pa_operation_state state; + void *userdata; + void (*callback)(); }; -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { - struct pa_context *c; - assert(mainloop && name); - - c = pa_xmalloc(sizeof(struct pa_context)); - c->name = pa_xstrdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - assert(c->playback_streams); - c->record_streams = pa_dynarray_new(); - assert(c->record_streams); - c->first_stream = NULL; - c->error = PA_ERROR_OK; - c->state = CONTEXT_UNCONNECTED; - c->ctag = 0; - - c->connect_complete_callback = NULL; - c->connect_complete_userdata = NULL; - - c->drain_complete_callback = NULL; - c->drain_complete_userdata = NULL; - - c->die_callback = NULL; - c->die_userdata = NULL; - - c->stat_callback = NULL; - c->stat_userdata = NULL; - - c->play_sample_callback = NULL; - c->play_sample_userdata = NULL; - - c->remove_sample_callback = NULL; - c->remove_sample_userdata = NULL; - - c->get_server_info_callback = NULL; - c->get_server_info_userdata = NULL; - - c->get_sink_info_callback = NULL; - c->get_sink_info_userdata = NULL; - - c->get_source_info_callback = NULL; - c->get_source_info_userdata = NULL; - - c->subscribe_callback = NULL; - c->subscribe_userdata = NULL; - - c->get_client_info_callback = NULL; - c->get_client_info_userdata = NULL; - - c->get_module_info_callback = NULL; - c->get_module_info_userdata = NULL; - - pa_check_for_sigpipe(); - return c; -} - -void pa_context_free(struct pa_context *c) { - assert(c); - - while (c->first_stream) - pa_stream_free(c->first_stream); - - if (c->client) - pa_socket_client_free(c->client); - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - if (c->pstream) - pa_pstream_free(c->pstream); - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - pa_xfree(c->name); - pa_xfree(c); -} - -static void stream_dead(struct pa_stream *s) { - assert(s); - - if (s->state == STREAM_DEAD) - return; - - if (s->state == STREAM_READY) { - s->state = STREAM_DEAD; - if (s->die_callback) - s->die_callback(s, s->die_userdata); - } else - s->state = STREAM_DEAD; -} - -static void context_dead(struct pa_context *c) { - struct pa_stream *s; - assert(c); - - if (c->state == CONTEXT_DEAD) - return; - - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) - pa_pstream_free(c->pstream); - c->pstream = NULL; - - if (c->client) - pa_socket_client_free(c->client); - c->client = NULL; - - for (s = c->first_stream; s; s = s->next) - stream_dead(s); - - if (c->state == CONTEXT_READY) { - c->state = CONTEXT_DEAD; - if (c->die_callback) - c->die_callback(c, c->die_userdata); - } else - c->state = CONTEXT_DEAD; -} - -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { - struct pa_context *c = userdata; - assert(p && c); - c->error = PA_ERROR_CONNECTIONTERMINATED; - context_dead(c); -} - -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { - struct pa_context *c = userdata; - assert(p && packet && c); - - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - fprintf(stderr, "polyp.c: invalid packet.\n"); - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - } -} - -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - - if (!(s = pa_dynarray_get(c->record_streams, channel))) - return; - - if (s->read_callback) - s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); -} - -static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { - assert(c && t); - - if (command == PA_COMMAND_ERROR) { - if (pa_tagstruct_getu32(t, &c->error) < 0) { - c->error = PA_ERROR_PROTOCOL; - return -1; - } - - return 0; - } - - c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; - return -1; -} - -static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); - - if (command != PA_COMMAND_REPLY) { - handle_error(c, command, t); - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - if (c->state == CONTEXT_AUTHORIZING) { - struct pa_tagstruct *t; - c->state = CONTEXT_SETTING_NAME; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, c->name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - } else { - assert(c->state == CONTEXT_SETTING_NAME); - - c->state = CONTEXT_READY; - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 1, c->connect_complete_userdata); - } - - return; -} - -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { - struct pa_context *c = userdata; - struct pa_tagstruct *t; - uint32_t tag; - assert(client && c && c->state == CONTEXT_CONNECTING); +void pa_command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +void pa_command_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +void pa_command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - pa_socket_client_free(client); - c->client = NULL; +struct pa_operation *pa_operation_new(struct pa_context *c, struct pa_stream *s); +void pa_operation_done(struct pa_operation *o); - if (!io) { - c->error = PA_ERROR_CONNECTIONREFUSED; - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - c->pstream = pa_pstream_new(c->mainloop, io); - assert(c->pstream); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - c->state = CONTEXT_AUTHORIZING; -} - -static struct sockaddr *resolve_server(const char *server, size_t *len) { - struct sockaddr *sa; - struct addrinfo hints, *result = NULL; - char *port; - assert(server && len); - - if ((port = strrchr(server, ':'))) - port++; - if (!port) - port = DEFAULT_PORT; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(server, port, &hints, &result) != 0) - return NULL; - assert(result); - - sa = pa_xmalloc(*len = result->ai_addrlen); - memcpy(sa, result->ai_addr, *len); - - freeaddrinfo(result); - - return sa; -} - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { - assert(c && c->state == CONTEXT_UNCONNECTED); - - if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { - c->error = PA_ERROR_AUTHKEY; - return -1; - } - - if (!server) - if (!(server = getenv("POLYP_SERVER"))) - server = DEFAULT_SERVER; - - assert(!c->client); - - if (*server == '/') { - if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } else { - struct sockaddr* sa; - size_t sa_len; - - if (!(sa = resolve_server(server, &sa_len))) { - c->error = PA_ERROR_INVALIDSERVER; - return -1; - } - - c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); - pa_xfree(sa); - - if (!c->client) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } - - c->connect_complete_callback = complete; - c->connect_complete_userdata = userdata; - - pa_socket_client_set_callback(c->client, on_connection, c); - c->state = CONTEXT_CONNECTING; - - return 0; -} - -int pa_context_is_dead(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_DEAD; -} - -int pa_context_is_ready(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_READY; -} - -int pa_context_errno(struct pa_context *c) { - assert(c); - return c->error; -} - -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { - assert(c); - c->die_callback = cb; - c->die_userdata = userdata; -} - -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - uint32_t channel; - assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - return; - - c->error = PA_ERROR_KILLED; - stream_dead(s); -} - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s; - struct pa_context *c = userdata; - uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - return; - - if (s->state != STREAM_READY) - return; - - s->requested_bytes += bytes; - - if (s->requested_bytes && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); -} - -static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s && s->state == STREAM_CREATING); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - - return; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - - s->state = STREAM_READY; - if (s->create_complete_callback) - s->create_complete_callback(s, 1, s->create_complete_userdata); -} - -static void create_stream(struct pa_stream *s, const char *dev) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s); - - s->state = STREAM_CREATING; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, s->buffer_attr.maxlength); - if (s->direction == PA_STREAM_PLAYBACK) { - pa_tagstruct_putu32(t, s->buffer_attr.tlength); - pa_tagstruct_putu32(t, s->buffer_attr.prebuf); - pa_tagstruct_putu32(t, s->buffer_attr.minreq); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); -} - -static struct pa_stream *internal_stream_new(struct pa_context *c) { - struct pa_stream *s; - - s = pa_xmalloc(sizeof(struct pa_stream)); - s->context = c; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->die_callback = NULL; - s->die_userdata = NULL; - s->create_complete_callback = NULL; - s->create_complete_userdata = NULL; - s->get_latency_callback = NULL; - s->get_latency_userdata = NULL; - s->finish_sample_callback = NULL; - s->finish_sample_userdata = NULL; - - s->name = NULL; - s->state = STREAM_CREATING; - s->requested_bytes = 0; - s->channel = 0; - s->channel_valid = 0; - s->device_index = (uint32_t) -1; - - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->next = c->first_stream; - if (s->next) - s->next->previous = s; - s->previous = NULL; - c->first_stream = s; - - return s; -} - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata) { - - struct pa_stream *s; - - assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = complete; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = dir; - s->sample_spec = *ss; - if (attr) - s->buffer_attr = *attr; - else { - s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; - s->buffer_attr.tlength = DEFAULT_TLENGTH; - s->buffer_attr.prebuf = DEFAULT_PREBUF; - s->buffer_attr.minreq = DEFAULT_MINREQ; - s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; - } - - create_stream(s, dev); - - return s; -} - -void pa_stream_free(struct pa_stream *s) { - assert(s && s->context); - - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - pa_xfree(s->name); - - if (s->channel_valid && s->context->state == CONTEXT_READY) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); - pa_tagstruct_putu32(t, s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - } - - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; - else - s->context->first_stream = s->next; - - pa_xfree(s); -} - -void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { - struct pa_memchunk chunk; - assert(s && s->context && data && length && s->state == STREAM_READY); - - chunk.memblock = pa_memblock_new(length); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); - pa_memblock_unref(chunk.memblock); - - /*fprintf(stderr, "Sent %u bytes\n", length);*/ - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; -} +void pa_create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +void pa_stream_disconnect_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +void pa_context_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +void pa_stream_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s && s->state == STREAM_READY); - return s->requested_bytes; -} +void pa_context_fail(struct pa_context *c, int error); +void pa_context_set_state(struct pa_context *c, enum pa_context_state st); +int pa_context_handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t); +struct pa_operation* pa_context_send_simple_command(struct pa_context *c, uint32_t command, void (*internal_callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void (*cb)(), void *userdata); -void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->read_callback = cb; - s->read_userdata = userdata; -} +void pa_stream_set_state(struct pa_stream *s, enum pa_stream_state st); -int pa_stream_is_dead(struct pa_stream *s) { - return s->state == STREAM_DEAD; -} - -int pa_stream_is_ready(struct pa_stream*s) { - return s->state == STREAM_READY; -} - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { - assert(s); - s->die_callback = cb; - s->die_userdata = userdata; -} - -int pa_context_is_pending(struct pa_context *c) { - assert(c); - - if (c->state != CONTEXT_READY) - return 0; - - return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); -} - -struct pa_context* pa_stream_get_context(struct pa_stream *p) { - assert(p); - return p->context; -} - -static void set_dispatch_callbacks(struct pa_context *c); - -static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void set_dispatch_callbacks(struct pa_context *c) { - assert(c && c->state == CONTEXT_READY); - - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(c->pdispatch)) { - pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); - return; - } - - if (pa_pstream_is_pending(c->pstream)) { - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - return; - } - - assert(c->drain_complete_callback); - c->drain_complete_callback(c, c->drain_complete_userdata); -} - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata) { - - assert(c && c->state == CONTEXT_READY); - - if (complete == NULL) { - c->drain_complete_callback = NULL; - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - return 0; - } - - if (!pa_context_is_pending(c)) - return -1; - - c->drain_complete_callback = complete; - c->drain_complete_userdata = userdata; - - set_dispatch_callbacks(c); - - return 0; -} - -static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - return; - } - - if (s->state != STREAM_READY) - return; - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->drain_complete_callback) { - void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; - s->drain_complete_callback = NULL; - temp(s, s->drain_complete_userdata); - } -} - - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s && s->state == STREAM_READY); - - if (!complete) { - s->drain_complete_callback = NULL; - return; - } - - s->drain_complete_callback = complete; - s->drain_complete_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); -} - -void pa_context_exit(struct pa_context *c) { - struct pa_tagstruct *t; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - uint32_t total, count; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &count) < 0 || - pa_tagstruct_getu32(t, &total) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, count, total, c->stat_userdata); -} - -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - c->stat_callback = cb; - c->stat_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_STAT); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); -} - -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t latency; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &latency) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, latency, s->get_latency_userdata); -} - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - p->get_latency_callback = cb; - p->get_latency_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); -} - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_stream *s; - struct pa_tagstruct *t; - uint32_t tag; - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = cb; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = PA_STREAM_UPLOAD; - s->sample_spec = *ss; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_sample_spec(t, ss); - pa_tagstruct_putu32(t, length); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); - - return s; -} - -static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 0, s->finish_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 1, s->finish_sample_userdata); -} - -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(p); - - p->finish_sample_callback = cb; - p->finish_sample_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); -} - -static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 0, c->play_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 1, c->play_sample_userdata); -} - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name && *name && (!dev || *dev)); - - c->play_sample_callback = cb; - c->play_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, volume); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); -} - -static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 0, c->remove_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 1, c->remove_sample_userdata); -} - -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name); - - c->remove_sample_callback = cb; - c->remove_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); -} - -static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_server_info i; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, NULL, c->get_server_info_userdata); - return; - } - - if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, &i, c->get_server_info_userdata); -} - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_server_info_callback = cb; - c->get_server_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); -} - -static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_sink_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.volume) < 0 || - pa_tagstruct_getu32(t, &i.monitor_source) < 0 || - pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || - pa_tagstruct_getu32(t, &i.latency) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); -} - -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_source_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || - pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); -} - -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { - struct pa_tagstruct *t; - assert(c); - - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; - c->subscribe_mask = m; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, c->ctag++); - pa_tagstruct_putu32(t, cb ? m : 0); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - enum pa_subscription_event_type e; - uint32_t index; - assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); - - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &index) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) - c->subscribe_callback(c, e, index, c->subscribe_userdata); -} - -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_client_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.protocol_name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); -} - - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_module_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_getu32(t, &i.auto_unload) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); -} - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} - -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} +#endif diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index 35001d3d..345a9cd5 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -23,1528 +23,421 @@ #include #endif -#include #include -#include -#include -#include -#include -#include - -#include "polyplib.h" -#include "native-common.h" -#include "pdispatch.h" -#include "pstream.h" -#include "dynarray.h" -#include "socket-client.h" -#include "pstream-util.h" -#include "authkey.h" -#include "util.h" -#include "xmalloc.h" - -#define DEFAULT_MAXLENGTH 204800 -#define DEFAULT_TLENGTH 10240 -#define DEFAULT_PREBUF 4096 -#define DEFAULT_MINREQ 1024 -#define DEFAULT_FRAGSIZE 1024 - -#define DEFAULT_TIMEOUT (5*60) -#define DEFAULT_SERVER "/tmp/polypaudio/native" -#define DEFAULT_PORT "4713" - -struct pa_context { - char *name; - struct pa_mainloop_api* mainloop; - struct pa_socket_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; - struct pa_dynarray *record_streams, *playback_streams; - struct pa_stream *first_stream; - uint32_t ctag; - uint32_t error; - enum { - CONTEXT_UNCONNECTED, - CONTEXT_CONNECTING, - CONTEXT_AUTHORIZING, - CONTEXT_SETTING_NAME, - CONTEXT_READY, - CONTEXT_DEAD - } state; - - void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); - void *connect_complete_userdata; - - void (*drain_complete_callback)(struct pa_context*c, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_context*c, void *userdata); - void *die_userdata; - - void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); - void *stat_userdata; - - void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); - void *play_sample_userdata; - - void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); - void *remove_sample_userdata; - - void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); - void *get_server_info_userdata; - - void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); - void *get_sink_info_userdata; - - void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); - void *get_source_info_userdata; - - void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); - void *subscribe_userdata; - enum pa_subscription_mask subscribe_mask; - - void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); - void *get_client_info_userdata; - - void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); - void *get_module_info_userdata; - - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; -}; - -struct pa_stream { - struct pa_context *context; - struct pa_stream *next, *previous; - - char *name; - struct pa_buffer_attr buffer_attr; - struct pa_sample_spec sample_spec; - uint32_t channel; - int channel_valid; - uint32_t device_index; - enum pa_stream_direction direction; - - enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; - uint32_t requested_bytes; - - void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); - void *read_userdata; - - void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); - void *write_userdata; - - void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); - void *create_complete_userdata; - - void (*drain_complete_callback)(struct pa_stream *s, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_stream*c, void *userdata); - void *die_userdata; - - void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); - void *get_latency_userdata; - - void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); - void *finish_sample_userdata; -}; - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_EXIT] = { NULL }, - [PA_COMMAND_REQUEST] = { command_request }, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, -}; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { - struct pa_context *c; - assert(mainloop && name); - - c = pa_xmalloc(sizeof(struct pa_context)); - c->name = pa_xstrdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - assert(c->playback_streams); - c->record_streams = pa_dynarray_new(); - assert(c->record_streams); - c->first_stream = NULL; - c->error = PA_ERROR_OK; - c->state = CONTEXT_UNCONNECTED; - c->ctag = 0; - - c->connect_complete_callback = NULL; - c->connect_complete_userdata = NULL; - - c->drain_complete_callback = NULL; - c->drain_complete_userdata = NULL; - - c->die_callback = NULL; - c->die_userdata = NULL; - - c->stat_callback = NULL; - c->stat_userdata = NULL; - - c->play_sample_callback = NULL; - c->play_sample_userdata = NULL; - - c->remove_sample_callback = NULL; - c->remove_sample_userdata = NULL; - - c->get_server_info_callback = NULL; - c->get_server_info_userdata = NULL; - c->get_sink_info_callback = NULL; - c->get_sink_info_userdata = NULL; - - c->get_source_info_callback = NULL; - c->get_source_info_userdata = NULL; - - c->subscribe_callback = NULL; - c->subscribe_userdata = NULL; - - c->get_client_info_callback = NULL; - c->get_client_info_userdata = NULL; - - c->get_module_info_callback = NULL; - c->get_module_info_userdata = NULL; - - pa_check_for_sigpipe(); - return c; -} - -void pa_context_free(struct pa_context *c) { - assert(c); - - while (c->first_stream) - pa_stream_free(c->first_stream); - - if (c->client) - pa_socket_client_free(c->client); - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - if (c->pstream) - pa_pstream_free(c->pstream); - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - pa_xfree(c->name); - pa_xfree(c); -} - -static void stream_dead(struct pa_stream *s) { - assert(s); - - if (s->state == STREAM_DEAD) - return; - - if (s->state == STREAM_READY) { - s->state = STREAM_DEAD; - if (s->die_callback) - s->die_callback(s, s->die_userdata); - } else - s->state = STREAM_DEAD; -} - -static void context_dead(struct pa_context *c) { - struct pa_stream *s; - assert(c); - - if (c->state == CONTEXT_DEAD) - return; - - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) - pa_pstream_free(c->pstream); - c->pstream = NULL; - - if (c->client) - pa_socket_client_free(c->client); - c->client = NULL; - - for (s = c->first_stream; s; s = s->next) - stream_dead(s); - - if (c->state == CONTEXT_READY) { - c->state = CONTEXT_DEAD; - if (c->die_callback) - c->die_callback(c, c->die_userdata); - } else - c->state = CONTEXT_DEAD; -} - -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { - struct pa_context *c = userdata; - assert(p && c); - c->error = PA_ERROR_CONNECTIONTERMINATED; - context_dead(c); -} - -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { - struct pa_context *c = userdata; - assert(p && packet && c); - - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - fprintf(stderr, "polyp.c: invalid packet.\n"); - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - } -} - -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - - if (!(s = pa_dynarray_get(c->record_streams, channel))) - return; - - if (s->read_callback) - s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); -} - -static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { - assert(c && t); - - if (command == PA_COMMAND_ERROR) { - if (pa_tagstruct_getu32(t, &c->error) < 0) { - c->error = PA_ERROR_PROTOCOL; - return -1; - } +#include "polyplib-introspect.h" +#include "polyplib-context.h" +#include "polyplib-internal.h" +#include "pstream-util.h" - return 0; - } +/*** Statistics ***/ - c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; - return -1; -} - -static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); +static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + struct pa_stat_info i, *p = &i; + assert(pd && o && o->context && o->ref >= 1); if (command != PA_COMMAND_REPLY) { - handle_error(c, command, t); - context_dead(c); + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; + p = NULL; + } else if (pa_tagstruct_getu32(t, &i.memblock_count) < 0 || + pa_tagstruct_getu32(t, &i.memblock_total) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; } - if (c->state == CONTEXT_AUTHORIZING) { - struct pa_tagstruct *t; - c->state = CONTEXT_SETTING_NAME; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, c->name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - } else { - assert(c->state == CONTEXT_SETTING_NAME); - - c->state = CONTEXT_READY; - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 1, c->connect_complete_userdata); + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_stat_info*i, void *userdata) = o->callback; + cb(o->context, p, o->userdata); } - return; +finish: + pa_operation_done(o); + pa_operation_unref(o); } -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { - struct pa_context *c = userdata; - struct pa_tagstruct *t; - uint32_t tag; - assert(client && c && c->state == CONTEXT_CONNECTING); - - pa_socket_client_free(client); - c->client = NULL; - - if (!io) { - c->error = PA_ERROR_CONNECTIONREFUSED; - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - c->pstream = pa_pstream_new(c->mainloop, io); - assert(c->pstream); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - c->state = CONTEXT_AUTHORIZING; +struct pa_operation* pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_stat_info*i, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_STAT, context_stat_callback, cb, userdata); } -static struct sockaddr *resolve_server(const char *server, size_t *len) { - struct sockaddr *sa; - struct addrinfo hints, *result = NULL; - char *port; - assert(server && len); - - if ((port = strrchr(server, ':'))) - port++; - if (!port) - port = DEFAULT_PORT; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(server, port, &hints, &result) != 0) - return NULL; - assert(result); - - sa = pa_xmalloc(*len = result->ai_addrlen); - memcpy(sa, result->ai_addr, *len); +/*** Server Info ***/ - freeaddrinfo(result); - - return sa; -} +static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + struct pa_server_info i, *p = &i; + assert(pd && o && o->context && o->ref >= 1); -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { - assert(c && c->state == CONTEXT_UNCONNECTED); + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; - if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { - c->error = PA_ERROR_AUTHKEY; - return -1; + p = NULL; + } else if (pa_tagstruct_gets(t, &i.server_name) < 0 || + pa_tagstruct_gets(t, &i.server_version) < 0 || + pa_tagstruct_gets(t, &i.user_name) < 0 || + pa_tagstruct_gets(t, &i.host_name) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; } - - if (!server) - if (!(server = getenv("POLYP_SERVER"))) - server = DEFAULT_SERVER; - - assert(!c->client); - if (*server == '/') { - if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } else { - struct sockaddr* sa; - size_t sa_len; - - if (!(sa = resolve_server(server, &sa_len))) { - c->error = PA_ERROR_INVALIDSERVER; - return -1; - } - - c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); - pa_xfree(sa); - - if (!c->client) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_server_info*i, void *userdata) = o->callback; + cb(o->context, p, o->userdata); } - c->connect_complete_callback = complete; - c->connect_complete_userdata = userdata; - - pa_socket_client_set_callback(c->client, on_connection, c); - c->state = CONTEXT_CONNECTING; - - return 0; -} - -int pa_context_is_dead(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_DEAD; +finish: + pa_operation_done(o); + pa_operation_unref(o); } -int pa_context_is_ready(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_READY; +struct pa_operation* pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SERVER_INFO, context_get_server_info_callback, cb, userdata); } -int pa_context_errno(struct pa_context *c) { - assert(c); - return c->error; -} - -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { - assert(c); - c->die_callback = cb; - c->die_userdata = userdata; -} - -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - uint32_t channel; - assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - return; +/*** Sink Info ***/ - c->error = PA_ERROR_KILLED; - stream_dead(s); -} - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s; - struct pa_context *c = userdata; - uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - return; - - if (s->state != STREAM_READY) - return; - - s->requested_bytes += bytes; - - if (s->requested_bytes && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); -} - -static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s && s->state == STREAM_CREATING); +static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - - return; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - - s->state = STREAM_READY; - if (s->create_complete_callback) - s->create_complete_callback(s, 1, s->create_complete_userdata); -} - -static void create_stream(struct pa_stream *s, const char *dev) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s); - - s->state = STREAM_CREATING; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, s->buffer_attr.maxlength); - if (s->direction == PA_STREAM_PLAYBACK) { - pa_tagstruct_putu32(t, s->buffer_attr.tlength); - pa_tagstruct_putu32(t, s->buffer_attr.prebuf); - pa_tagstruct_putu32(t, s->buffer_attr.minreq); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); -} + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; -static struct pa_stream *internal_stream_new(struct pa_context *c) { - struct pa_stream *s; - - s = pa_xmalloc(sizeof(struct pa_stream)); - s->context = c; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->die_callback = NULL; - s->die_userdata = NULL; - s->create_complete_callback = NULL; - s->create_complete_userdata = NULL; - s->get_latency_callback = NULL; - s->get_latency_userdata = NULL; - s->finish_sample_callback = NULL; - s->finish_sample_userdata = NULL; - - s->name = NULL; - s->state = STREAM_CREATING; - s->requested_bytes = 0; - s->channel = 0; - s->channel_valid = 0; - s->device_index = (uint32_t) -1; - - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->next = c->first_stream; - if (s->next) - s->next->previous = s; - s->previous = NULL; - c->first_stream = s; - - return s; -} - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata) { - - struct pa_stream *s; - - assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = complete; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = dir; - s->sample_spec = *ss; - if (attr) - s->buffer_attr = *attr; - else { - s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; - s->buffer_attr.tlength = DEFAULT_TLENGTH; - s->buffer_attr.prebuf = DEFAULT_PREBUF; - s->buffer_attr.minreq = DEFAULT_MINREQ; - s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; - } - - create_stream(s, dev); - - return s; -} - -void pa_stream_free(struct pa_stream *s) { - assert(s && s->context); - - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - pa_xfree(s->name); - - if (s->channel_valid && s->context->state == CONTEXT_READY) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); - pa_tagstruct_putu32(t, s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + struct pa_sink_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.volume) < 0 || + pa_tagstruct_getu32(t, &i.monitor_source) < 0 || + pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || + pa_tagstruct_getu32(t, &i.latency) < 0) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_sink_info*i, int eof, void *userdata) = o->callback; + cb(o->context, &i, 0, o->userdata); + } + } } - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; - else - s->context->first_stream = s->next; - - pa_xfree(s); -} - -void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { - struct pa_memchunk chunk; - assert(s && s->context && data && length && s->state == STREAM_READY); - - chunk.memblock = pa_memblock_new(length); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); - pa_memblock_unref(chunk.memblock); - - /*fprintf(stderr, "Sent %u bytes\n", length);*/ - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; -} - -size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s && s->state == STREAM_READY); - return s->requested_bytes; -} - -void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->read_callback = cb; - s->read_userdata = userdata; -} - -int pa_stream_is_dead(struct pa_stream *s) { - return s->state == STREAM_DEAD; -} - -int pa_stream_is_ready(struct pa_stream*s) { - return s->state == STREAM_READY; -} - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { - assert(s); - s->die_callback = cb; - s->die_userdata = userdata; -} - -int pa_context_is_pending(struct pa_context *c) { - assert(c); - - if (c->state != CONTEXT_READY) - return 0; - - return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); -} - -struct pa_context* pa_stream_get_context(struct pa_stream *p) { - assert(p); - return p->context; -} - -static void set_dispatch_callbacks(struct pa_context *c); - -static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void set_dispatch_callbacks(struct pa_context *c) { - assert(c && c->state == CONTEXT_READY); - - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(c->pdispatch)) { - pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); - return; - } - - if (pa_pstream_is_pending(c->pstream)) { - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - return; - } - - assert(c->drain_complete_callback); - c->drain_complete_callback(c, c->drain_complete_userdata); -} - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata) { - - assert(c && c->state == CONTEXT_READY); - - if (complete == NULL) { - c->drain_complete_callback = NULL; - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - return 0; + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_sink_info*i, int eof, void *userdata) = o->callback; + cb(o->context, NULL, eof, o->userdata); } - - if (!pa_context_is_pending(c)) - return -1; - - c->drain_complete_callback = complete; - c->drain_complete_userdata = userdata; - set_dispatch_callbacks(c); - - return 0; +finish: + pa_operation_done(o); + pa_operation_unref(o); } -static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - return; - } - - if (s->state != STREAM_READY) - return; - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->drain_complete_callback) { - void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; - s->drain_complete_callback = NULL; - temp(s, s->drain_complete_userdata); - } +struct pa_operation* pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INFO_LIST, context_get_sink_info_callback, cb, userdata); } - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { +struct pa_operation* pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { struct pa_tagstruct *t; + struct pa_operation *o; uint32_t tag; - assert(s && s->state == STREAM_READY); - - if (!complete) { - s->drain_complete_callback = NULL; - return; - } + assert(c && cb); - s->drain_complete_callback = complete; - s->drain_complete_userdata = userdata; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); -} - -void pa_context_exit(struct pa_context *c) { - struct pa_tagstruct *t; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, c->ctag++); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); pa_pstream_send_tagstruct(c->pstream, t); -} - -static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - uint32_t total, count; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); - return; - } + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, o); - if (pa_tagstruct_getu32(t, &count) < 0 || - pa_tagstruct_getu32(t, &total) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, count, total, c->stat_userdata); + return pa_operation_ref(o); } -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - c->stat_callback = cb; - c->stat_userdata = userdata; +/*** Source info ***/ - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_STAT); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); -} - -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t latency; - assert(pd && s); +static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; - if (s->get_latency_callback) - s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); - return; + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + struct pa_source_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || + pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_source_info*i, int eof, void *userdata) = o->callback; + cb(o->context, &i, 0, o->userdata); + } + } } - - if (pa_tagstruct_getu32(t, &latency) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_source_info*i, int eof, void *userdata) = o->callback; + cb(o->context, NULL, eof, o->userdata); } - if (s->get_latency_callback) - s->get_latency_callback(s, latency, s->get_latency_userdata); +finish: + pa_operation_done(o); + pa_operation_unref(o); } -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - p->get_latency_callback = cb; - p->get_latency_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); +struct pa_operation* pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_INFO_LIST, context_get_source_info_callback, cb, userdata); } -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_stream *s; +struct pa_operation* pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { struct pa_tagstruct *t; + struct pa_operation *o; uint32_t tag; - - s = internal_stream_new(c); - assert(s); + assert(c && cb); - s->create_complete_callback = cb; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = PA_STREAM_UPLOAD; - s->sample_spec = *ss; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_sample_spec(t, ss); - pa_tagstruct_putu32(t, length); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, o); - return s; + return pa_operation_ref(o); } -static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 0, s->finish_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 1, s->finish_sample_userdata); -} - -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(p); - - p->finish_sample_callback = cb; - p->finish_sample_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); -} +/*** Client info ***/ -static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); +static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; - if (c->play_sample_callback) - c->play_sample_callback(c, 0, c->play_sample_userdata); - return; + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + struct pa_client_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.protocol_name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_client_info*i, int eof, void *userdata) = o->callback; + cb(o->context, &i, 0, o->userdata); + } + } } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_client_info*i, int eof, void *userdata) = o->callback; + cb(o->context, NULL, eof, o->userdata); } - if (c->play_sample_callback) - c->play_sample_callback(c, 1, c->play_sample_userdata); +finish: + pa_operation_done(o); + pa_operation_unref(o); } -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { +struct pa_operation* pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { struct pa_tagstruct *t; + struct pa_operation *o; uint32_t tag; - assert(c && name && *name && (!dev || *dev)); + assert(c && cb); - c->play_sample_callback = cb; - c->play_sample_userdata = userdata; - - if (!cb) - return; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, volume); - pa_tagstruct_puts(t, name); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); -} - -static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 0, c->remove_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 1, c->remove_sample_userdata); -} - -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, o); - c->remove_sample_callback = cb; - c->remove_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); + return pa_operation_ref(o); } -static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_server_info i; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, NULL, c->get_server_info_userdata); - return; - } - - if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, &i, c->get_server_info_userdata); +struct pa_operation* pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_CLIENT_INFO_LIST, context_get_client_info_callback, cb, userdata); } -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_server_info_callback = cb; - c->get_server_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); -} +/*** Module info ***/ -static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); +static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_sink_info i; + eof = -1; + } else { - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.volume) < 0 || - pa_tagstruct_getu32(t, &i.monitor_source) < 0 || - pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || - pa_tagstruct_getu32(t, &i.latency) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; + while (!pa_tagstruct_eof(t)) { + struct pa_module_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.argument) < 0 || + pa_tagstruct_getu32(t, &i.n_used) < 0 || + pa_tagstruct_getu32(t, &i.auto_unload) < 0) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_module_info*i, int eof, void *userdata) = o->callback; + cb(o->context, &i, 0, o->userdata); + } } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); -} - -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_source_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || - pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_module_info*i, int eof, void *userdata) = o->callback; + cb(o->context, NULL, eof, o->userdata); } - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); +finish: + pa_operation_done(o); + pa_operation_unref(o); } -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { +struct pa_operation* pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { struct pa_tagstruct *t; + struct pa_operation *o; uint32_t tag; - assert(c); + assert(c && cb); - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; - if (!cb) - return; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { - struct pa_tagstruct *t; - assert(c); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, o); - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; - c->subscribe_mask = m; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, c->ctag++); - pa_tagstruct_putu32(t, cb ? m : 0); - pa_pstream_send_tagstruct(c->pstream, t); + return pa_operation_ref(o); } -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - enum pa_subscription_event_type e; - uint32_t index; - assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); - - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &index) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) - c->subscribe_callback(c, e, index, c->subscribe_userdata); +struct pa_operation* pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_MODULE_INFO_LIST, context_get_module_info_callback, cb, userdata); } -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); +/*** Volume manipulation ***/ - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { +struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_operation *o; struct pa_tagstruct *t; uint32_t tag; - assert(c); + assert(c && index != PA_INVALID_INDEX); - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; - if (!cb) - return; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, index); pa_tagstruct_puts(t, ""); + pa_tagstruct_putu32(t, volume); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_client_info i; + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.protocol_name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); + return pa_operation_ref(o); } - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { +struct pa_operation* pa_context_set_sink_volume_by_name(struct pa_context *c, const char *name, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_operation *o; struct pa_tagstruct *t; uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); + assert(c && name); - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; - if (!cb) - return; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_tagstruct_putu32(t, volume); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); - return; - } + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - while (!pa_tagstruct_eof(t)) { - struct pa_module_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_getu32(t, &i.auto_unload) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); + return pa_operation_ref(o); } -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { +struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_operation *o; struct pa_tagstruct *t; uint32_t tag; - assert(c); + assert(c && index != PA_INVALID_INDEX); - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; - if (!cb) - return; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, index); + pa_tagstruct_putu32(t, volume); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); + return pa_operation_ref(o); } diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index a0dd9f9c..bca752e2 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo +#ifndef foopolyplibintrospecthfoo +#define foopolyplibintrospecthfoo /* $Id$ */ @@ -22,61 +22,13 @@ USA. ***/ -#include +#include -#include "sample.h" -#include "polyplib-def.h" -#include "mainloop-api.h" +#include "polyplib-operation.h" +#include "polyplib-context.h" +#include "cdecl.h" -#ifdef __cplusplus -//extern "C" { -#endif - -struct pa_context; -struct pa_stream; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); -void pa_context_unref(struct pa_context *c); -struct pa_context* pa_context_ref(struct pa_context *c); - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); -int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); - -int pa_context_is_dead(struct pa_context *c); -int pa_context_is_ready(struct pa_context *c); -int pa_context_errno(struct pa_context *c); - -int pa_context_is_pending(struct pa_context *c); - -struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_unref(struct pa_stream *s); -struct pa_stream *pa_stream_ref(struct pa_stream *s); - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); - -void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); -void pa_stream_write(struct pa_stream *p, const void *data, size_t length); -size_t pa_stream_writable_size(struct pa_stream *p); - -void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); - -int pa_stream_is_dead(struct pa_stream *p); -int pa_stream_is_ready(struct pa_stream*p); - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); - -struct pa_context* pa_stream_get_context(struct pa_stream *p); - -uint32_t pa_stream_get_index(struct pa_stream *s); - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +PA_C_DECL_BEGIN struct pa_sink_info { const char *name; @@ -90,9 +42,9 @@ struct pa_sink_info { uint32_t latency; }; -void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); struct pa_source_info { const char *name; @@ -104,9 +56,9 @@ struct pa_source_info { const char *monitor_of_sink_name; }; -void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); struct pa_server_info { const char *user_name; @@ -116,7 +68,7 @@ struct pa_server_info { struct pa_sample_spec sample_spec; }; -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); +struct pa_operation* pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); struct pa_module_info { uint32_t index; @@ -124,8 +76,8 @@ struct pa_module_info { uint32_t n_used, auto_unload; }; -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); struct pa_client_info { uint32_t index; @@ -134,8 +86,8 @@ struct pa_client_info { const char *protocol_name; }; -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); struct pa_sink_input_info { uint32_t index; @@ -148,8 +100,8 @@ struct pa_sink_input_info { uint32_t latency; }; -void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); struct pa_source_output_info { uint32_t index; @@ -160,19 +112,20 @@ struct pa_source_output_info { struct pa_sample_spec sample_spec; }; -void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); -void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +struct pa_operation* pa_context_set_sink_volume_by_name(struct pa_context *c, const char *name, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_exit(struct pa_context *c); -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); +struct pa_stat_info { + uint32_t memblock_count; + uint32_t memblock_total; +}; -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); +struct pa_operation* pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_stat_info *i, void *userdata), void *userdata); -#ifdef __cplusplus -} -#endif +PA_C_DECL_END #endif diff --git a/polyp/polyplib-operation.c b/polyp/polyplib-operation.c new file mode 100644 index 00000000..994ac016 --- /dev/null +++ b/polyp/polyplib-operation.c @@ -0,0 +1,78 @@ +#include + +#include "xmalloc.h" +#include "polyplib-internal.h" +#include "polyplib-operation.h" + +struct pa_operation *pa_operation_new(struct pa_context *c, struct pa_stream *s) { + struct pa_operation *o; + assert(c); + + o = pa_xmalloc(sizeof(struct pa_operation)); + o->ref = 1; + o->context = pa_context_ref(c); + o->stream = s ? pa_stream_ref(s) : NULL; + + o->state = PA_OPERATION_RUNNING; + o->userdata = NULL; + o->callback = NULL; + + PA_LLIST_PREPEND(struct pa_operation, o->context->operations, o); + return pa_operation_ref(o); +} + +struct pa_operation *pa_operation_ref(struct pa_operation *o) { + assert(o && o->ref >= 1); + o->ref++; + return o; +} + +void pa_operation_unref(struct pa_operation *o) { + assert(o && o->ref >= 1); + + if ((--(o->ref)) == 0) { + assert(!o->context); + assert(!o->stream); + free(o); + } +} + +static void operation_set_state(struct pa_operation *o, enum pa_operation_state st) { + assert(o && o->ref >= 1); + + if (st == o->state) + return; + + if (!o->context) + return; + + o->state = st; + + if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) { + PA_LLIST_REMOVE(struct pa_operation, o->context->operations, o); + pa_context_unref(o->context); + if (o->stream) + pa_stream_unref(o->stream); + o->context = NULL; + o->stream = NULL; + o->callback = NULL; + o->userdata = NULL; + + pa_operation_unref(o); + } +} + +void pa_operation_cancel(struct pa_operation *o) { + assert(o && o->ref >= 1); + operation_set_state(o, PA_OPERATION_CANCELED); +} + +void pa_operation_done(struct pa_operation *o) { + assert(o && o->ref >= 1); + operation_set_state(o, PA_OPERATION_DONE); +} + +enum pa_operation_state pa_operation_get_state(struct pa_operation *o) { + assert(o && o->ref >= 1); + return o->state; +} diff --git a/polyp/polyplib-operation.h b/polyp/polyplib-operation.h new file mode 100644 index 00000000..7d0adc26 --- /dev/null +++ b/polyp/polyplib-operation.h @@ -0,0 +1,56 @@ +#ifndef foopolypliboperationhfoo +#define foopolypliboperationhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "cdecl.h" + +/** \file + * Asynchronous operations */ + +PA_C_DECL_BEGIN + +enum pa_operation_state { + PA_OPERATION_RUNNING, /**< The operation is still running */ + PA_OPERATION_DONE, /**< The operation has been completed */ + PA_OPERATION_CANCELED, /**< The operation has been canceled */ +}; + +/** \struct pa_operation + * An asynchronous operation object */ +struct pa_operation; + +/** Increase the reference count by one */ +struct pa_operation *pa_operation_ref(struct pa_operation *o); + +/** Decrease the reference count by one */ +void pa_operation_unref(struct pa_operation *o); + +/** Cancel the operation. Beware! This will not necessarily cancel the execution of the operation on the server side. */ +void pa_operation_cancel(struct pa_operation *o); + +/** Return the current status of the operation */ +enum pa_operation_state pa_operation_get_state(struct pa_operation *o); + +PA_C_DECL_END + +#endif diff --git a/polyp/polyplib-sample.c b/polyp/polyplib-sample.c deleted file mode 100644 index 35001d3d..00000000 --- a/polyp/polyplib-sample.c +++ /dev/null @@ -1,1550 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "polyplib.h" -#include "native-common.h" -#include "pdispatch.h" -#include "pstream.h" -#include "dynarray.h" -#include "socket-client.h" -#include "pstream-util.h" -#include "authkey.h" -#include "util.h" -#include "xmalloc.h" - -#define DEFAULT_MAXLENGTH 204800 -#define DEFAULT_TLENGTH 10240 -#define DEFAULT_PREBUF 4096 -#define DEFAULT_MINREQ 1024 -#define DEFAULT_FRAGSIZE 1024 - -#define DEFAULT_TIMEOUT (5*60) -#define DEFAULT_SERVER "/tmp/polypaudio/native" -#define DEFAULT_PORT "4713" - -struct pa_context { - char *name; - struct pa_mainloop_api* mainloop; - struct pa_socket_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; - struct pa_dynarray *record_streams, *playback_streams; - struct pa_stream *first_stream; - uint32_t ctag; - uint32_t error; - enum { - CONTEXT_UNCONNECTED, - CONTEXT_CONNECTING, - CONTEXT_AUTHORIZING, - CONTEXT_SETTING_NAME, - CONTEXT_READY, - CONTEXT_DEAD - } state; - - void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); - void *connect_complete_userdata; - - void (*drain_complete_callback)(struct pa_context*c, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_context*c, void *userdata); - void *die_userdata; - - void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); - void *stat_userdata; - - void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); - void *play_sample_userdata; - - void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); - void *remove_sample_userdata; - - void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); - void *get_server_info_userdata; - - void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); - void *get_sink_info_userdata; - - void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); - void *get_source_info_userdata; - - void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); - void *subscribe_userdata; - enum pa_subscription_mask subscribe_mask; - - void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); - void *get_client_info_userdata; - - void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); - void *get_module_info_userdata; - - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; -}; - -struct pa_stream { - struct pa_context *context; - struct pa_stream *next, *previous; - - char *name; - struct pa_buffer_attr buffer_attr; - struct pa_sample_spec sample_spec; - uint32_t channel; - int channel_valid; - uint32_t device_index; - enum pa_stream_direction direction; - - enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; - uint32_t requested_bytes; - - void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); - void *read_userdata; - - void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); - void *write_userdata; - - void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); - void *create_complete_userdata; - - void (*drain_complete_callback)(struct pa_stream *s, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_stream*c, void *userdata); - void *die_userdata; - - void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); - void *get_latency_userdata; - - void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); - void *finish_sample_userdata; -}; - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_EXIT] = { NULL }, - [PA_COMMAND_REQUEST] = { command_request }, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, -}; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { - struct pa_context *c; - assert(mainloop && name); - - c = pa_xmalloc(sizeof(struct pa_context)); - c->name = pa_xstrdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - assert(c->playback_streams); - c->record_streams = pa_dynarray_new(); - assert(c->record_streams); - c->first_stream = NULL; - c->error = PA_ERROR_OK; - c->state = CONTEXT_UNCONNECTED; - c->ctag = 0; - - c->connect_complete_callback = NULL; - c->connect_complete_userdata = NULL; - - c->drain_complete_callback = NULL; - c->drain_complete_userdata = NULL; - - c->die_callback = NULL; - c->die_userdata = NULL; - - c->stat_callback = NULL; - c->stat_userdata = NULL; - - c->play_sample_callback = NULL; - c->play_sample_userdata = NULL; - - c->remove_sample_callback = NULL; - c->remove_sample_userdata = NULL; - - c->get_server_info_callback = NULL; - c->get_server_info_userdata = NULL; - - c->get_sink_info_callback = NULL; - c->get_sink_info_userdata = NULL; - - c->get_source_info_callback = NULL; - c->get_source_info_userdata = NULL; - - c->subscribe_callback = NULL; - c->subscribe_userdata = NULL; - - c->get_client_info_callback = NULL; - c->get_client_info_userdata = NULL; - - c->get_module_info_callback = NULL; - c->get_module_info_userdata = NULL; - - pa_check_for_sigpipe(); - return c; -} - -void pa_context_free(struct pa_context *c) { - assert(c); - - while (c->first_stream) - pa_stream_free(c->first_stream); - - if (c->client) - pa_socket_client_free(c->client); - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - if (c->pstream) - pa_pstream_free(c->pstream); - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - pa_xfree(c->name); - pa_xfree(c); -} - -static void stream_dead(struct pa_stream *s) { - assert(s); - - if (s->state == STREAM_DEAD) - return; - - if (s->state == STREAM_READY) { - s->state = STREAM_DEAD; - if (s->die_callback) - s->die_callback(s, s->die_userdata); - } else - s->state = STREAM_DEAD; -} - -static void context_dead(struct pa_context *c) { - struct pa_stream *s; - assert(c); - - if (c->state == CONTEXT_DEAD) - return; - - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) - pa_pstream_free(c->pstream); - c->pstream = NULL; - - if (c->client) - pa_socket_client_free(c->client); - c->client = NULL; - - for (s = c->first_stream; s; s = s->next) - stream_dead(s); - - if (c->state == CONTEXT_READY) { - c->state = CONTEXT_DEAD; - if (c->die_callback) - c->die_callback(c, c->die_userdata); - } else - c->state = CONTEXT_DEAD; -} - -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { - struct pa_context *c = userdata; - assert(p && c); - c->error = PA_ERROR_CONNECTIONTERMINATED; - context_dead(c); -} - -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { - struct pa_context *c = userdata; - assert(p && packet && c); - - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - fprintf(stderr, "polyp.c: invalid packet.\n"); - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - } -} - -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - - if (!(s = pa_dynarray_get(c->record_streams, channel))) - return; - - if (s->read_callback) - s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); -} - -static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { - assert(c && t); - - if (command == PA_COMMAND_ERROR) { - if (pa_tagstruct_getu32(t, &c->error) < 0) { - c->error = PA_ERROR_PROTOCOL; - return -1; - } - - return 0; - } - - c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; - return -1; -} - -static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); - - if (command != PA_COMMAND_REPLY) { - handle_error(c, command, t); - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - if (c->state == CONTEXT_AUTHORIZING) { - struct pa_tagstruct *t; - c->state = CONTEXT_SETTING_NAME; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, c->name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - } else { - assert(c->state == CONTEXT_SETTING_NAME); - - c->state = CONTEXT_READY; - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 1, c->connect_complete_userdata); - } - - return; -} - -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { - struct pa_context *c = userdata; - struct pa_tagstruct *t; - uint32_t tag; - assert(client && c && c->state == CONTEXT_CONNECTING); - - pa_socket_client_free(client); - c->client = NULL; - - if (!io) { - c->error = PA_ERROR_CONNECTIONREFUSED; - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - c->pstream = pa_pstream_new(c->mainloop, io); - assert(c->pstream); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - c->state = CONTEXT_AUTHORIZING; -} - -static struct sockaddr *resolve_server(const char *server, size_t *len) { - struct sockaddr *sa; - struct addrinfo hints, *result = NULL; - char *port; - assert(server && len); - - if ((port = strrchr(server, ':'))) - port++; - if (!port) - port = DEFAULT_PORT; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(server, port, &hints, &result) != 0) - return NULL; - assert(result); - - sa = pa_xmalloc(*len = result->ai_addrlen); - memcpy(sa, result->ai_addr, *len); - - freeaddrinfo(result); - - return sa; -} - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { - assert(c && c->state == CONTEXT_UNCONNECTED); - - if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { - c->error = PA_ERROR_AUTHKEY; - return -1; - } - - if (!server) - if (!(server = getenv("POLYP_SERVER"))) - server = DEFAULT_SERVER; - - assert(!c->client); - - if (*server == '/') { - if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } else { - struct sockaddr* sa; - size_t sa_len; - - if (!(sa = resolve_server(server, &sa_len))) { - c->error = PA_ERROR_INVALIDSERVER; - return -1; - } - - c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); - pa_xfree(sa); - - if (!c->client) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } - - c->connect_complete_callback = complete; - c->connect_complete_userdata = userdata; - - pa_socket_client_set_callback(c->client, on_connection, c); - c->state = CONTEXT_CONNECTING; - - return 0; -} - -int pa_context_is_dead(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_DEAD; -} - -int pa_context_is_ready(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_READY; -} - -int pa_context_errno(struct pa_context *c) { - assert(c); - return c->error; -} - -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { - assert(c); - c->die_callback = cb; - c->die_userdata = userdata; -} - -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - uint32_t channel; - assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - return; - - c->error = PA_ERROR_KILLED; - stream_dead(s); -} - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s; - struct pa_context *c = userdata; - uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - return; - - if (s->state != STREAM_READY) - return; - - s->requested_bytes += bytes; - - if (s->requested_bytes && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); -} - -static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s && s->state == STREAM_CREATING); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - - return; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - - s->state = STREAM_READY; - if (s->create_complete_callback) - s->create_complete_callback(s, 1, s->create_complete_userdata); -} - -static void create_stream(struct pa_stream *s, const char *dev) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s); - - s->state = STREAM_CREATING; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, s->buffer_attr.maxlength); - if (s->direction == PA_STREAM_PLAYBACK) { - pa_tagstruct_putu32(t, s->buffer_attr.tlength); - pa_tagstruct_putu32(t, s->buffer_attr.prebuf); - pa_tagstruct_putu32(t, s->buffer_attr.minreq); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); -} - -static struct pa_stream *internal_stream_new(struct pa_context *c) { - struct pa_stream *s; - - s = pa_xmalloc(sizeof(struct pa_stream)); - s->context = c; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->die_callback = NULL; - s->die_userdata = NULL; - s->create_complete_callback = NULL; - s->create_complete_userdata = NULL; - s->get_latency_callback = NULL; - s->get_latency_userdata = NULL; - s->finish_sample_callback = NULL; - s->finish_sample_userdata = NULL; - - s->name = NULL; - s->state = STREAM_CREATING; - s->requested_bytes = 0; - s->channel = 0; - s->channel_valid = 0; - s->device_index = (uint32_t) -1; - - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->next = c->first_stream; - if (s->next) - s->next->previous = s; - s->previous = NULL; - c->first_stream = s; - - return s; -} - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata) { - - struct pa_stream *s; - - assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = complete; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = dir; - s->sample_spec = *ss; - if (attr) - s->buffer_attr = *attr; - else { - s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; - s->buffer_attr.tlength = DEFAULT_TLENGTH; - s->buffer_attr.prebuf = DEFAULT_PREBUF; - s->buffer_attr.minreq = DEFAULT_MINREQ; - s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; - } - - create_stream(s, dev); - - return s; -} - -void pa_stream_free(struct pa_stream *s) { - assert(s && s->context); - - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - pa_xfree(s->name); - - if (s->channel_valid && s->context->state == CONTEXT_READY) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); - pa_tagstruct_putu32(t, s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - } - - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; - else - s->context->first_stream = s->next; - - pa_xfree(s); -} - -void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { - struct pa_memchunk chunk; - assert(s && s->context && data && length && s->state == STREAM_READY); - - chunk.memblock = pa_memblock_new(length); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); - pa_memblock_unref(chunk.memblock); - - /*fprintf(stderr, "Sent %u bytes\n", length);*/ - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; -} - -size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s && s->state == STREAM_READY); - return s->requested_bytes; -} - -void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->read_callback = cb; - s->read_userdata = userdata; -} - -int pa_stream_is_dead(struct pa_stream *s) { - return s->state == STREAM_DEAD; -} - -int pa_stream_is_ready(struct pa_stream*s) { - return s->state == STREAM_READY; -} - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { - assert(s); - s->die_callback = cb; - s->die_userdata = userdata; -} - -int pa_context_is_pending(struct pa_context *c) { - assert(c); - - if (c->state != CONTEXT_READY) - return 0; - - return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); -} - -struct pa_context* pa_stream_get_context(struct pa_stream *p) { - assert(p); - return p->context; -} - -static void set_dispatch_callbacks(struct pa_context *c); - -static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void set_dispatch_callbacks(struct pa_context *c) { - assert(c && c->state == CONTEXT_READY); - - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(c->pdispatch)) { - pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); - return; - } - - if (pa_pstream_is_pending(c->pstream)) { - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - return; - } - - assert(c->drain_complete_callback); - c->drain_complete_callback(c, c->drain_complete_userdata); -} - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata) { - - assert(c && c->state == CONTEXT_READY); - - if (complete == NULL) { - c->drain_complete_callback = NULL; - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - return 0; - } - - if (!pa_context_is_pending(c)) - return -1; - - c->drain_complete_callback = complete; - c->drain_complete_userdata = userdata; - - set_dispatch_callbacks(c); - - return 0; -} - -static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - return; - } - - if (s->state != STREAM_READY) - return; - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->drain_complete_callback) { - void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; - s->drain_complete_callback = NULL; - temp(s, s->drain_complete_userdata); - } -} - - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s && s->state == STREAM_READY); - - if (!complete) { - s->drain_complete_callback = NULL; - return; - } - - s->drain_complete_callback = complete; - s->drain_complete_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); -} - -void pa_context_exit(struct pa_context *c) { - struct pa_tagstruct *t; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - uint32_t total, count; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &count) < 0 || - pa_tagstruct_getu32(t, &total) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, count, total, c->stat_userdata); -} - -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - c->stat_callback = cb; - c->stat_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_STAT); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); -} - -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t latency; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &latency) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, latency, s->get_latency_userdata); -} - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - p->get_latency_callback = cb; - p->get_latency_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); -} - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_stream *s; - struct pa_tagstruct *t; - uint32_t tag; - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = cb; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = PA_STREAM_UPLOAD; - s->sample_spec = *ss; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_sample_spec(t, ss); - pa_tagstruct_putu32(t, length); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); - - return s; -} - -static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 0, s->finish_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 1, s->finish_sample_userdata); -} - -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(p); - - p->finish_sample_callback = cb; - p->finish_sample_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); -} - -static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 0, c->play_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 1, c->play_sample_userdata); -} - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name && *name && (!dev || *dev)); - - c->play_sample_callback = cb; - c->play_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, volume); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); -} - -static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 0, c->remove_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 1, c->remove_sample_userdata); -} - -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name); - - c->remove_sample_callback = cb; - c->remove_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); -} - -static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_server_info i; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, NULL, c->get_server_info_userdata); - return; - } - - if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, &i, c->get_server_info_userdata); -} - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_server_info_callback = cb; - c->get_server_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); -} - -static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_sink_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.volume) < 0 || - pa_tagstruct_getu32(t, &i.monitor_source) < 0 || - pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || - pa_tagstruct_getu32(t, &i.latency) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); -} - -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_source_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || - pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); -} - -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { - struct pa_tagstruct *t; - assert(c); - - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; - c->subscribe_mask = m; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, c->ctag++); - pa_tagstruct_putu32(t, cb ? m : 0); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - enum pa_subscription_event_type e; - uint32_t index; - assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); - - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &index) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) - c->subscribe_callback(c, e, index, c->subscribe_userdata); -} - -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_client_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.protocol_name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); -} - - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_module_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_getu32(t, &i.auto_unload) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); -} - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} - -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} diff --git a/polyp/polyplib-sample.h b/polyp/polyplib-sample.h deleted file mode 100644 index a0dd9f9c..00000000 --- a/polyp/polyplib-sample.h +++ /dev/null @@ -1,178 +0,0 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "sample.h" -#include "polyplib-def.h" -#include "mainloop-api.h" - -#ifdef __cplusplus -//extern "C" { -#endif - -struct pa_context; -struct pa_stream; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); -void pa_context_unref(struct pa_context *c); -struct pa_context* pa_context_ref(struct pa_context *c); - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); -int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); - -int pa_context_is_dead(struct pa_context *c); -int pa_context_is_ready(struct pa_context *c); -int pa_context_errno(struct pa_context *c); - -int pa_context_is_pending(struct pa_context *c); - -struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_unref(struct pa_stream *s); -struct pa_stream *pa_stream_ref(struct pa_stream *s); - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); - -void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); -void pa_stream_write(struct pa_stream *p, const void *data, size_t length); -size_t pa_stream_writable_size(struct pa_stream *p); - -void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); - -int pa_stream_is_dead(struct pa_stream *p); -int pa_stream_is_ready(struct pa_stream*p); - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); - -struct pa_context* pa_stream_get_context(struct pa_stream *p); - -uint32_t pa_stream_get_index(struct pa_stream *s); - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); - -struct pa_sink_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t volume; - uint32_t monitor_source; - const char *monitor_source_name; - uint32_t latency; -}; - -void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); - -struct pa_source_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t monitor_of_sink; - const char *monitor_of_sink_name; -}; - -void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); - -struct pa_server_info { - const char *user_name; - const char *host_name; - const char *server_version; - const char *server_name; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); - -struct pa_module_info { - uint32_t index; - const char*name, *argument; - uint32_t n_used, auto_unload; -}; - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); - -struct pa_client_info { - uint32_t index; - const char *name; - uint32_t owner_module; - const char *protocol_name; -}; - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); - -struct pa_sink_input_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t sink; - struct pa_sample_spec sample_spec; - uint32_t volume; - uint32_t latency; -}; - -void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); - -struct pa_source_output_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t source; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); - -void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); - -void pa_context_exit(struct pa_context *c); -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/polyp/polyplib-scache.c b/polyp/polyplib-scache.c index 35001d3d..8215eaec 100644 --- a/polyp/polyplib-scache.c +++ b/polyp/polyplib-scache.c @@ -23,1083 +23,73 @@ #include #endif -#include #include #include +#include #include -#include -#include -#include -#include "polyplib.h" -#include "native-common.h" -#include "pdispatch.h" -#include "pstream.h" -#include "dynarray.h" -#include "socket-client.h" +#include "polyplib-scache.h" +#include "polyplib-internal.h" #include "pstream-util.h" -#include "authkey.h" -#include "util.h" -#include "xmalloc.h" - -#define DEFAULT_MAXLENGTH 204800 -#define DEFAULT_TLENGTH 10240 -#define DEFAULT_PREBUF 4096 -#define DEFAULT_MINREQ 1024 -#define DEFAULT_FRAGSIZE 1024 - -#define DEFAULT_TIMEOUT (5*60) -#define DEFAULT_SERVER "/tmp/polypaudio/native" -#define DEFAULT_PORT "4713" - -struct pa_context { - char *name; - struct pa_mainloop_api* mainloop; - struct pa_socket_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; - struct pa_dynarray *record_streams, *playback_streams; - struct pa_stream *first_stream; - uint32_t ctag; - uint32_t error; - enum { - CONTEXT_UNCONNECTED, - CONTEXT_CONNECTING, - CONTEXT_AUTHORIZING, - CONTEXT_SETTING_NAME, - CONTEXT_READY, - CONTEXT_DEAD - } state; - - void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); - void *connect_complete_userdata; - - void (*drain_complete_callback)(struct pa_context*c, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_context*c, void *userdata); - void *die_userdata; - - void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); - void *stat_userdata; - - void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); - void *play_sample_userdata; - - void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); - void *remove_sample_userdata; - - void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); - void *get_server_info_userdata; - - void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); - void *get_sink_info_userdata; - - void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); - void *get_source_info_userdata; - - void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); - void *subscribe_userdata; - enum pa_subscription_mask subscribe_mask; - - void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); - void *get_client_info_userdata; - - void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); - void *get_module_info_userdata; - - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; -}; - -struct pa_stream { - struct pa_context *context; - struct pa_stream *next, *previous; - - char *name; - struct pa_buffer_attr buffer_attr; - struct pa_sample_spec sample_spec; - uint32_t channel; - int channel_valid; - uint32_t device_index; - enum pa_stream_direction direction; - - enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; - uint32_t requested_bytes; - - void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); - void *read_userdata; - - void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); - void *write_userdata; - - void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); - void *create_complete_userdata; - - void (*drain_complete_callback)(struct pa_stream *s, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_stream*c, void *userdata); - void *die_userdata; - - void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); - void *get_latency_userdata; - - void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); - void *finish_sample_userdata; -}; - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_EXIT] = { NULL }, - [PA_COMMAND_REQUEST] = { command_request }, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, -}; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { - struct pa_context *c; - assert(mainloop && name); - - c = pa_xmalloc(sizeof(struct pa_context)); - c->name = pa_xstrdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - assert(c->playback_streams); - c->record_streams = pa_dynarray_new(); - assert(c->record_streams); - c->first_stream = NULL; - c->error = PA_ERROR_OK; - c->state = CONTEXT_UNCONNECTED; - c->ctag = 0; - c->connect_complete_callback = NULL; - c->connect_complete_userdata = NULL; - - c->drain_complete_callback = NULL; - c->drain_complete_userdata = NULL; - - c->die_callback = NULL; - c->die_userdata = NULL; - - c->stat_callback = NULL; - c->stat_userdata = NULL; - - c->play_sample_callback = NULL; - c->play_sample_userdata = NULL; - - c->remove_sample_callback = NULL; - c->remove_sample_userdata = NULL; - - c->get_server_info_callback = NULL; - c->get_server_info_userdata = NULL; - - c->get_sink_info_callback = NULL; - c->get_sink_info_userdata = NULL; - - c->get_source_info_callback = NULL; - c->get_source_info_userdata = NULL; - - c->subscribe_callback = NULL; - c->subscribe_userdata = NULL; - - c->get_client_info_callback = NULL; - c->get_client_info_userdata = NULL; - - c->get_module_info_callback = NULL; - c->get_module_info_userdata = NULL; - - pa_check_for_sigpipe(); - return c; -} - -void pa_context_free(struct pa_context *c) { - assert(c); - - while (c->first_stream) - pa_stream_free(c->first_stream); - - if (c->client) - pa_socket_client_free(c->client); - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - if (c->pstream) - pa_pstream_free(c->pstream); - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - pa_xfree(c->name); - pa_xfree(c); -} - -static void stream_dead(struct pa_stream *s) { - assert(s); - - if (s->state == STREAM_DEAD) - return; - - if (s->state == STREAM_READY) { - s->state = STREAM_DEAD; - if (s->die_callback) - s->die_callback(s, s->die_userdata); - } else - s->state = STREAM_DEAD; -} - -static void context_dead(struct pa_context *c) { - struct pa_stream *s; - assert(c); - - if (c->state == CONTEXT_DEAD) - return; - - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) - pa_pstream_free(c->pstream); - c->pstream = NULL; - - if (c->client) - pa_socket_client_free(c->client); - c->client = NULL; - - for (s = c->first_stream; s; s = s->next) - stream_dead(s); - - if (c->state == CONTEXT_READY) { - c->state = CONTEXT_DEAD; - if (c->die_callback) - c->die_callback(c, c->die_userdata); - } else - c->state = CONTEXT_DEAD; -} - -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { - struct pa_context *c = userdata; - assert(p && c); - c->error = PA_ERROR_CONNECTIONTERMINATED; - context_dead(c); -} - -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { - struct pa_context *c = userdata; - assert(p && packet && c); - - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - fprintf(stderr, "polyp.c: invalid packet.\n"); - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - } -} - -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - - if (!(s = pa_dynarray_get(c->record_streams, channel))) - return; - - if (s->read_callback) - s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); -} - -static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { - assert(c && t); - - if (command == PA_COMMAND_ERROR) { - if (pa_tagstruct_getu32(t, &c->error) < 0) { - c->error = PA_ERROR_PROTOCOL; - return -1; - } - - return 0; - } - - c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; - return -1; -} - -static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); - - if (command != PA_COMMAND_REPLY) { - handle_error(c, command, t); - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - if (c->state == CONTEXT_AUTHORIZING) { - struct pa_tagstruct *t; - c->state = CONTEXT_SETTING_NAME; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, c->name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - } else { - assert(c->state == CONTEXT_SETTING_NAME); - - c->state = CONTEXT_READY; - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 1, c->connect_complete_userdata); - } - - return; -} - -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { - struct pa_context *c = userdata; +void pa_stream_connect_upload(struct pa_stream *s, size_t length) { struct pa_tagstruct *t; uint32_t tag; - assert(client && c && c->state == CONTEXT_CONNECTING); - - pa_socket_client_free(client); - c->client = NULL; - - if (!io) { - c->error = PA_ERROR_CONNECTIONREFUSED; - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - c->pstream = pa_pstream_new(c->mainloop, io); - assert(c->pstream); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); + assert(s && length); - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - c->state = CONTEXT_AUTHORIZING; -} - -static struct sockaddr *resolve_server(const char *server, size_t *len) { - struct sockaddr *sa; - struct addrinfo hints, *result = NULL; - char *port; - assert(server && len); - - if ((port = strrchr(server, ':'))) - port++; - if (!port) - port = DEFAULT_PORT; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(server, port, &hints, &result) != 0) - return NULL; - assert(result); - - sa = pa_xmalloc(*len = result->ai_addrlen); - memcpy(sa, result->ai_addr, *len); - - freeaddrinfo(result); - - return sa; -} - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { - assert(c && c->state == CONTEXT_UNCONNECTED); - - if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { - c->error = PA_ERROR_AUTHKEY; - return -1; - } - - if (!server) - if (!(server = getenv("POLYP_SERVER"))) - server = DEFAULT_SERVER; - - assert(!c->client); + pa_stream_ref(s); - if (*server == '/') { - if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } else { - struct sockaddr* sa; - size_t sa_len; - - if (!(sa = resolve_server(server, &sa_len))) { - c->error = PA_ERROR_INVALIDSERVER; - return -1; - } - - c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); - pa_xfree(sa); - - if (!c->client) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } - - c->connect_complete_callback = complete; - c->connect_complete_userdata = userdata; - - pa_socket_client_set_callback(c->client, on_connection, c); - c->state = CONTEXT_CONNECTING; - - return 0; -} - -int pa_context_is_dead(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_DEAD; -} - -int pa_context_is_ready(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_READY; -} - -int pa_context_errno(struct pa_context *c) { - assert(c); - return c->error; -} - -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { - assert(c); - c->die_callback = cb; - c->die_userdata = userdata; -} - -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - uint32_t channel; - assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - return; - - c->error = PA_ERROR_KILLED; - stream_dead(s); -} - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s; - struct pa_context *c = userdata; - uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - return; - - if (s->state != STREAM_READY) - return; - - s->requested_bytes += bytes; - - if (s->requested_bytes && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); -} - -static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s && s->state == STREAM_CREATING); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - - return; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - - s->state = STREAM_READY; - if (s->create_complete_callback) - s->create_complete_callback(s, 1, s->create_complete_userdata); -} - -static void create_stream(struct pa_stream *s, const char *dev) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s); + s->state = PA_STREAM_CREATING; + s->direction = PA_STREAM_UPLOAD; - s->state = STREAM_CREATING; - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); + pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); pa_tagstruct_putu32(t, tag = s->context->ctag++); pa_tagstruct_puts(t, s->name); pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, s->buffer_attr.maxlength); - if (s->direction == PA_STREAM_PLAYBACK) { - pa_tagstruct_putu32(t, s->buffer_attr.tlength); - pa_tagstruct_putu32(t, s->buffer_attr.prebuf); - pa_tagstruct_putu32(t, s->buffer_attr.minreq); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - + pa_tagstruct_putu32(t, length); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); -} - -static struct pa_stream *internal_stream_new(struct pa_context *c) { - struct pa_stream *s; - - s = pa_xmalloc(sizeof(struct pa_stream)); - s->context = c; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->die_callback = NULL; - s->die_userdata = NULL; - s->create_complete_callback = NULL; - s->create_complete_userdata = NULL; - s->get_latency_callback = NULL; - s->get_latency_userdata = NULL; - s->finish_sample_callback = NULL; - s->finish_sample_userdata = NULL; - - s->name = NULL; - s->state = STREAM_CREATING; - s->requested_bytes = 0; - s->channel = 0; - s->channel_valid = 0; - s->device_index = (uint32_t) -1; - - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->next = c->first_stream; - if (s->next) - s->next->previous = s; - s->previous = NULL; - c->first_stream = s; - - return s; -} - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata) { - - struct pa_stream *s; - - assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = complete; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = dir; - s->sample_spec = *ss; - if (attr) - s->buffer_attr = *attr; - else { - s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; - s->buffer_attr.tlength = DEFAULT_TLENGTH; - s->buffer_attr.prebuf = DEFAULT_PREBUF; - s->buffer_attr.minreq = DEFAULT_MINREQ; - s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; - } - - create_stream(s, dev); - - return s; -} - -void pa_stream_free(struct pa_stream *s) { - assert(s && s->context); - - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - pa_xfree(s->name); - - if (s->channel_valid && s->context->state == CONTEXT_READY) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); - pa_tagstruct_putu32(t, s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - } - - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s); - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; - else - s->context->first_stream = s->next; - - pa_xfree(s); -} - -void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { - struct pa_memchunk chunk; - assert(s && s->context && data && length && s->state == STREAM_READY); - - chunk.memblock = pa_memblock_new(length); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); - pa_memblock_unref(chunk.memblock); - - /*fprintf(stderr, "Sent %u bytes\n", length);*/ - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; -} - -size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s && s->state == STREAM_READY); - return s->requested_bytes; -} - -void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->read_callback = cb; - s->read_userdata = userdata; -} - -int pa_stream_is_dead(struct pa_stream *s) { - return s->state == STREAM_DEAD; -} - -int pa_stream_is_ready(struct pa_stream*s) { - return s->state == STREAM_READY; -} - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { - assert(s); - s->die_callback = cb; - s->die_userdata = userdata; -} - -int pa_context_is_pending(struct pa_context *c) { - assert(c); - - if (c->state != CONTEXT_READY) - return 0; - - return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); + pa_stream_unref(s); } -struct pa_context* pa_stream_get_context(struct pa_stream *p) { - assert(p); - return p->context; -} - -static void set_dispatch_callbacks(struct pa_context *c); - -static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void set_dispatch_callbacks(struct pa_context *c) { - assert(c && c->state == CONTEXT_READY); - - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(c->pdispatch)) { - pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); - return; - } - - if (pa_pstream_is_pending(c->pstream)) { - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - return; - } - - assert(c->drain_complete_callback); - c->drain_complete_callback(c, c->drain_complete_userdata); -} - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata) { - - assert(c && c->state == CONTEXT_READY); - - if (complete == NULL) { - c->drain_complete_callback = NULL; - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - return 0; - } - - if (!pa_context_is_pending(c)) - return -1; - - c->drain_complete_callback = complete; - c->drain_complete_userdata = userdata; - - set_dispatch_callbacks(c); - - return 0; -} - -static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - return; - } - - if (s->state != STREAM_READY) - return; - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->drain_complete_callback) { - void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; - s->drain_complete_callback = NULL; - temp(s, s->drain_complete_userdata); - } -} - - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { +void pa_stream_finish_upload(struct pa_stream *s) { struct pa_tagstruct *t; uint32_t tag; - assert(s && s->state == STREAM_READY); + assert(s); - if (!complete) { - s->drain_complete_callback = NULL; + if (!s->channel_valid || !s->context->state == PA_CONTEXT_READY) return; - } - s->drain_complete_callback = complete; - s->drain_complete_userdata = userdata; + pa_stream_ref(s); t = pa_tagstruct_new(NULL, 0); assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); pa_tagstruct_putu32(t, tag = s->context->ctag++); pa_tagstruct_putu32(t, s->channel); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); -} - -void pa_context_exit(struct pa_context *c) { - struct pa_tagstruct *t; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - uint32_t total, count; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &count) < 0 || - pa_tagstruct_getu32(t, &total) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, count, total, c->stat_userdata); -} - -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - c->stat_callback = cb; - c->stat_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_STAT); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); -} - -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t latency; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &latency) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, latency, s->get_latency_userdata); -} + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s); -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - p->get_latency_callback = cb; - p->get_latency_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); + pa_stream_unref(s); } -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_stream *s; - struct pa_tagstruct *t; - uint32_t tag; - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = cb; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = PA_STREAM_UPLOAD; - s->sample_spec = *ss; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_sample_spec(t, ss); - pa_tagstruct_putu32(t, length); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); - - return s; -} - -static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 0, s->finish_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 1, s->finish_sample_userdata); -} - -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(p); - - p->finish_sample_callback = cb; - p->finish_sample_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); -} - -static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 0, c->play_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 1, c->play_sample_userdata); -} - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { +struct pa_operation * pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_operation *o; struct pa_tagstruct *t; uint32_t tag; assert(c && name && *name && (!dev || *dev)); - c->play_sample_callback = cb; - c->play_sample_userdata = userdata; - - if (!cb) - return; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + if (!dev) + dev = getenv(ENV_DEFAULT_SINK); + t = pa_tagstruct_new(NULL, 0); assert(t); pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); @@ -1109,44 +99,20 @@ void pa_context_play_sample(struct pa_context *c, const char *name, const char * pa_tagstruct_putu32(t, volume); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); -} - -static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - if (c->remove_sample_callback) - c->remove_sample_callback(c, 0, c->remove_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 1, c->remove_sample_userdata); + return pa_operation_ref(o); } -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { +struct pa_operation* pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_operation *o; struct pa_tagstruct *t; uint32_t tag; assert(c && name); - c->remove_sample_callback = cb; - c->remove_sample_userdata = userdata; - - if (!cb) - return; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); assert(t); @@ -1154,397 +120,8 @@ void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb) pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); -} - -static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_server_info i; - assert(pd && c); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, NULL, c->get_server_info_userdata); - return; - } - - if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, &i, c->get_server_info_userdata); + return pa_operation_ref(o); } -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_server_info_callback = cb; - c->get_server_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); -} - -static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_sink_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.volume) < 0 || - pa_tagstruct_getu32(t, &i.monitor_source) < 0 || - pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || - pa_tagstruct_getu32(t, &i.latency) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); -} - -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_source_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || - pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); -} - -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { - struct pa_tagstruct *t; - assert(c); - - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; - c->subscribe_mask = m; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, c->ctag++); - pa_tagstruct_putu32(t, cb ? m : 0); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - enum pa_subscription_event_type e; - uint32_t index; - assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); - - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &index) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) - c->subscribe_callback(c, e, index, c->subscribe_userdata); -} - -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_client_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.protocol_name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); -} - - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_module_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_getu32(t, &i.auto_unload) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); -} - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} - -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} diff --git a/polyp/polyplib-scache.h b/polyp/polyplib-scache.h index a0dd9f9c..ce74bef0 100644 --- a/polyp/polyplib-scache.h +++ b/polyp/polyplib-scache.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo +#ifndef foopolyplibscachehfoo +#define foopolyplibscachehfoo /* $Id$ */ @@ -24,155 +24,27 @@ #include -#include "sample.h" -#include "polyplib-def.h" -#include "mainloop-api.h" +#include "polyplib-context.h" +#include "polyplib-stream.h" +#include "cdecl.h" -#ifdef __cplusplus -//extern "C" { -#endif - -struct pa_context; -struct pa_stream; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); -void pa_context_unref(struct pa_context *c); -struct pa_context* pa_context_ref(struct pa_context *c); - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); -int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); - -int pa_context_is_dead(struct pa_context *c); -int pa_context_is_ready(struct pa_context *c); -int pa_context_errno(struct pa_context *c); - -int pa_context_is_pending(struct pa_context *c); - -struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_unref(struct pa_stream *s); -struct pa_stream *pa_stream_ref(struct pa_stream *s); - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); - -void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); -void pa_stream_write(struct pa_stream *p, const void *data, size_t length); -size_t pa_stream_writable_size(struct pa_stream *p); - -void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); - -int pa_stream_is_dead(struct pa_stream *p); -int pa_stream_is_ready(struct pa_stream*p); - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); - -struct pa_context* pa_stream_get_context(struct pa_stream *p); - -uint32_t pa_stream_get_index(struct pa_stream *s); +/** \file + * All sample cache related routines */ -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); +PA_C_DECL_BEGIN -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +/** Make this stream a sample upload stream */ +void pa_stream_connect_upload(struct pa_stream *s, size_t length); -struct pa_sink_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t volume; - uint32_t monitor_source; - const char *monitor_source_name; - uint32_t latency; -}; +/** Finish the sample upload, the stream name will become the sample name. You cancel a sample upload by issuing pa_stream_disconnect() */ +void pa_stream_finish_upload(struct pa_stream *s); -void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +/** Play a sample from the sample cache to the specified device. If the latter is NULL use the default sink. Returns an operation object */ +struct pa_operation* pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -struct pa_source_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t monitor_of_sink; - const char *monitor_of_sink_name; -}; +/** Remove a sample from the sample cache. Returns an operation object which may be used to cancel the operation while it is running */ +struct pa_operation* pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); - -struct pa_server_info { - const char *user_name; - const char *host_name; - const char *server_version; - const char *server_name; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); - -struct pa_module_info { - uint32_t index; - const char*name, *argument; - uint32_t n_used, auto_unload; -}; - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); - -struct pa_client_info { - uint32_t index; - const char *name; - uint32_t owner_module; - const char *protocol_name; -}; - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); - -struct pa_sink_input_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t sink; - struct pa_sample_spec sample_spec; - uint32_t volume; - uint32_t latency; -}; - -void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); - -struct pa_source_output_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t source; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); - -void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); - -void pa_context_exit(struct pa_context *c); -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); - -#ifdef __cplusplus -} -#endif +PA_C_DECL_END #endif diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c index 1f5ea553..66ee5995 100644 --- a/polyp/polyplib-simple.c +++ b/polyp/polyplib-simple.c @@ -49,15 +49,28 @@ struct pa_simple { static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata); static int check_error(struct pa_simple *p, int *perror) { + enum pa_context_state cst; + enum pa_stream_state sst; assert(p); - if (pa_context_is_dead(p->context) || (p->stream && pa_stream_is_dead(p->stream))) { - if (perror) - *perror = pa_context_errno(p->context); - return -1; - } + if ((cst = pa_context_get_state(p->context)) == PA_CONTEXT_FAILED) + goto fail; + assert(cst != PA_CONTEXT_TERMINATED); + + if (p->stream) { + if ((sst = pa_stream_get_state(p->stream)) == PA_STREAM_FAILED) + goto fail; + + assert(sst != PA_STREAM_TERMINATED); + } + return 0; + +fail: + if (perror) + *perror = pa_context_errno(p->context); + return -1; } static int iterate(struct pa_simple *p, int block, int *perror) { @@ -96,7 +109,7 @@ struct pa_simple* pa_simple_new( struct pa_simple *p; int error = PA_ERROR_INTERNAL; - assert(ss); + assert(ss && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); p = pa_xmalloc(sizeof(struct pa_simple)); p->context = NULL; @@ -110,23 +123,25 @@ struct pa_simple* pa_simple_new( if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name))) goto fail; - - if (pa_context_connect(p->context, server, NULL, NULL) < 0) { - error = pa_context_errno(p->context); - goto fail; - } + + pa_context_connect(p->context, server); /* Wait until the context is ready */ - while (!pa_context_is_ready(p->context)) { + while (pa_context_get_state(p->context) != PA_CONTEXT_READY) { if (iterate(p, 1, &error) < 0) goto fail; } - if (!(p->stream = pa_stream_new(p->context, dir, dev, stream_name, ss, attr, NULL, NULL))) + if (!(p->stream = pa_stream_new(p->context, stream_name, ss))) goto fail; + if (dir == PA_STREAM_PLAYBACK) + pa_stream_connect_playback(p->stream, dev, attr); + else + pa_stream_connect_record(p->stream, dev, attr); + /* Wait until the stream is ready */ - while (!pa_stream_is_ready(p->stream)) { + while (pa_stream_get_state(p->stream) != PA_STREAM_READY) { if (iterate(p, 1, &error) < 0) goto fail; } @@ -148,10 +163,10 @@ void pa_simple_free(struct pa_simple *s) { pa_xfree(s->read_data); if (s->stream) - pa_stream_free(s->stream); + pa_stream_unref(s->stream); if (s->context) - pa_context_free(s->context); + pa_context_unref(s->context); if (s->mainloop) pa_mainloop_free(s->mainloop); @@ -172,7 +187,7 @@ int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *pe if (l > length) l = length; - pa_stream_write(p->stream, data, l); + pa_stream_write(p->stream, data, l, NULL); data += l; length -= l; } @@ -193,8 +208,7 @@ static void read_callback(struct pa_stream *s, const void*data, size_t length, v pa_xfree(p->read_data); } - p->read_data = pa_xmalloc(p->read_length = length); - memcpy(p->read_data, data, length); + p->read_data = pa_xmemdup(data, p->read_length = length); p->read_index = 0; } @@ -235,23 +249,31 @@ int pa_simple_read(struct pa_simple *p, void*data, size_t length, int *perror) { return 0; } -static void drain_complete(struct pa_stream *s, void *userdata) { +static void drain_complete(struct pa_stream *s, int success, void *userdata) { struct pa_simple *p = userdata; assert(s && p); - p->drained = 1; + p->drained = success ? 1 : -1; } int pa_simple_drain(struct pa_simple *p, int *perror) { + struct pa_operation *o; + assert(p && p->direction == PA_STREAM_PLAYBACK); p->drained = 0; - pa_stream_drain(p->stream, drain_complete, p); + o = pa_stream_drain(p->stream, drain_complete, p); while (!p->drained) { if (iterate(p, 1, perror) < 0) { - pa_stream_drain(p->stream, NULL, NULL); + pa_operation_cancel(o); + pa_operation_unref(o); return -1; } } + pa_operation_unref(o); + + if (p->drained < 0 && perror) + *perror = pa_context_errno(p->context); + return 0; } diff --git a/polyp/polyplib-simple.h b/polyp/polyplib-simple.h index 0544410c..ee2e27e3 100644 --- a/polyp/polyplib-simple.h +++ b/polyp/polyplib-simple.h @@ -26,24 +26,41 @@ #include "sample.h" #include "polyplib-def.h" +#include "cdecl.h" +/** \file + * A simple but limited synchronous playback and recording API. */ + +PA_C_DECL_BEGIN + +/** \struct pa_simple + * A simple connection object */ struct pa_simple; +/** Create a new connection to the server */ struct pa_simple* pa_simple_new( - const char *server, - const char *name, - enum pa_stream_direction dir, - const char *dev, - const char *stream_name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - int *error); + const char *server, /**< Server name, or NULL for default */ + const char *name, /**< A descriptive name for this client (application name, ...) */ + enum pa_stream_direction dir, /**< Open this stream for recording or playback? */ + const char *dev, /**< Sink (resp. source) name, or NULL for default */ + const char *stream_name, /**< A descriptive name for this client (application name, song title, ...) */ + const struct pa_sample_spec *ss, /**< The sample type to use */ + const struct pa_buffer_attr *attr, /**< Buffering attributes, or NULL for default */ + int *error /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */ + ); +/** Close and free the connection to the server. The connection objects becomes invalid when this is called. */ void pa_simple_free(struct pa_simple *s); +/** Write some data to the server */ int pa_simple_write(struct pa_simple *s, const void*data, size_t length, int *error); + +/** Wait until all data already written is played by the daemon */ int pa_simple_drain(struct pa_simple *s, int *error); +/** Read some data from the server */ int pa_simple_read(struct pa_simple *s, void*data, size_t length, int *error); +PA_C_DECL_END + #endif diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 35001d3d..362dbad1 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -23,576 +23,217 @@ #include #endif -#include #include -#include #include -#include -#include -#include - -#include "polyplib.h" -#include "native-common.h" -#include "pdispatch.h" -#include "pstream.h" -#include "dynarray.h" -#include "socket-client.h" -#include "pstream-util.h" -#include "authkey.h" -#include "util.h" -#include "xmalloc.h" - -#define DEFAULT_MAXLENGTH 204800 -#define DEFAULT_TLENGTH 10240 -#define DEFAULT_PREBUF 4096 -#define DEFAULT_MINREQ 1024 -#define DEFAULT_FRAGSIZE 1024 - -#define DEFAULT_TIMEOUT (5*60) -#define DEFAULT_SERVER "/tmp/polypaudio/native" -#define DEFAULT_PORT "4713" - -struct pa_context { - char *name; - struct pa_mainloop_api* mainloop; - struct pa_socket_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; - struct pa_dynarray *record_streams, *playback_streams; - struct pa_stream *first_stream; - uint32_t ctag; - uint32_t error; - enum { - CONTEXT_UNCONNECTED, - CONTEXT_CONNECTING, - CONTEXT_AUTHORIZING, - CONTEXT_SETTING_NAME, - CONTEXT_READY, - CONTEXT_DEAD - } state; - - void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); - void *connect_complete_userdata; - - void (*drain_complete_callback)(struct pa_context*c, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_context*c, void *userdata); - void *die_userdata; - - void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); - void *stat_userdata; - - void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); - void *play_sample_userdata; - - void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); - void *remove_sample_userdata; - - void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); - void *get_server_info_userdata; - - void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); - void *get_sink_info_userdata; - - void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); - void *get_source_info_userdata; - - void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); - void *subscribe_userdata; - enum pa_subscription_mask subscribe_mask; - - void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); - void *get_client_info_userdata; - - void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); - void *get_module_info_userdata; - - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; -}; - -struct pa_stream { - struct pa_context *context; - struct pa_stream *next, *previous; - - char *name; - struct pa_buffer_attr buffer_attr; - struct pa_sample_spec sample_spec; - uint32_t channel; - int channel_valid; - uint32_t device_index; - enum pa_stream_direction direction; - - enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; - uint32_t requested_bytes; - - void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); - void *read_userdata; - - void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); - void *write_userdata; - - void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); - void *create_complete_userdata; - - void (*drain_complete_callback)(struct pa_stream *s, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_stream*c, void *userdata); - void *die_userdata; - - void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); - void *get_latency_userdata; - - void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); - void *finish_sample_userdata; -}; - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_EXIT] = { NULL }, - [PA_COMMAND_REQUEST] = { command_request }, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, -}; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { - struct pa_context *c; - assert(mainloop && name); - - c = pa_xmalloc(sizeof(struct pa_context)); - c->name = pa_xstrdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - assert(c->playback_streams); - c->record_streams = pa_dynarray_new(); - assert(c->record_streams); - c->first_stream = NULL; - c->error = PA_ERROR_OK; - c->state = CONTEXT_UNCONNECTED; - c->ctag = 0; - - c->connect_complete_callback = NULL; - c->connect_complete_userdata = NULL; - - c->drain_complete_callback = NULL; - c->drain_complete_userdata = NULL; - - c->die_callback = NULL; - c->die_userdata = NULL; - - c->stat_callback = NULL; - c->stat_userdata = NULL; - - c->play_sample_callback = NULL; - c->play_sample_userdata = NULL; - - c->remove_sample_callback = NULL; - c->remove_sample_userdata = NULL; +#include - c->get_server_info_callback = NULL; - c->get_server_info_userdata = NULL; +#include "polyplib-internal.h" +#include "xmalloc.h" +#include "pstream-util.h" - c->get_sink_info_callback = NULL; - c->get_sink_info_userdata = NULL; +struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const struct pa_sample_spec *ss) { + assert(c && ss); + struct pa_stream *s; - c->get_source_info_callback = NULL; - c->get_source_info_userdata = NULL; + s = pa_xmalloc(sizeof(struct pa_stream)); + s->ref = 1; + s->context = c; - c->subscribe_callback = NULL; - c->subscribe_userdata = NULL; + s->read_callback = NULL; + s->read_userdata = NULL; + s->write_callback = NULL; + s->write_userdata = NULL; + s->state_callback = NULL; + s->state_userdata = NULL; - c->get_client_info_callback = NULL; - c->get_client_info_userdata = NULL; - - c->get_module_info_callback = NULL; - c->get_module_info_userdata = NULL; - - pa_check_for_sigpipe(); - return c; -} + s->state = PA_STREAM_NODIRECTION; + s->name = pa_xstrdup(name); + s->sample_spec = *ss; + s->channel = 0; + s->channel_valid = 0; + s->device_index = PA_INVALID_INDEX; + s->requested_bytes = 0; + s->state = PA_STREAM_DISCONNECTED; + memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); -void pa_context_free(struct pa_context *c) { - assert(c); + PA_LLIST_PREPEND(struct pa_stream, c->streams, s); - while (c->first_stream) - pa_stream_free(c->first_stream); - - if (c->client) - pa_socket_client_free(c->client); - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - if (c->pstream) - pa_pstream_free(c->pstream); - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - pa_xfree(c->name); - pa_xfree(c); + return pa_stream_ref(s); } -static void stream_dead(struct pa_stream *s) { +static void stream_free(struct pa_stream *s) { assert(s); - - if (s->state == STREAM_DEAD) - return; - - if (s->state == STREAM_READY) { - s->state = STREAM_DEAD; - if (s->die_callback) - s->die_callback(s, s->die_userdata); - } else - s->state = STREAM_DEAD; -} - -static void context_dead(struct pa_context *c) { - struct pa_stream *s; - assert(c); - - if (c->state == CONTEXT_DEAD) - return; - - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) - pa_pstream_free(c->pstream); - c->pstream = NULL; - - if (c->client) - pa_socket_client_free(c->client); - c->client = NULL; - - for (s = c->first_stream; s; s = s->next) - stream_dead(s); - - if (c->state == CONTEXT_READY) { - c->state = CONTEXT_DEAD; - if (c->die_callback) - c->die_callback(c, c->die_userdata); - } else - c->state = CONTEXT_DEAD; -} - -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { - struct pa_context *c = userdata; - assert(p && c); - c->error = PA_ERROR_CONNECTIONTERMINATED; - context_dead(c); + pa_xfree(s->name); + pa_xfree(s); } -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { - struct pa_context *c = userdata; - assert(p && packet && c); +void pa_stream_unref(struct pa_stream *s) { + assert(s && s->ref >= 1); - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - fprintf(stderr, "polyp.c: invalid packet.\n"); - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - } + if (--(s->ref) == 0) + stream_free(s); } -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - - if (!(s = pa_dynarray_get(c->record_streams, channel))) - return; - - if (s->read_callback) - s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); +struct pa_stream* pa_stream_ref(struct pa_stream *s) { + assert(s && s->ref >= 1); + s->ref++; + return s; } -static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { - assert(c && t); - - if (command == PA_COMMAND_ERROR) { - if (pa_tagstruct_getu32(t, &c->error) < 0) { - c->error = PA_ERROR_PROTOCOL; - return -1; - } - - return 0; - } - - c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; - return -1; +enum pa_stream_state pa_stream_get_state(struct pa_stream *s) { + assert(s && s->ref >= 1); + return s->state; } -static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); - - if (command != PA_COMMAND_REPLY) { - handle_error(c, command, t); - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - if (c->state == CONTEXT_AUTHORIZING) { - struct pa_tagstruct *t; - c->state = CONTEXT_SETTING_NAME; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, c->name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - } else { - assert(c->state == CONTEXT_SETTING_NAME); - - c->state = CONTEXT_READY; - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 1, c->connect_complete_userdata); - } - - return; +struct pa_context* pa_stream_get_context(struct pa_stream *s) { + assert(s && s->ref >= 1); + return s->context; } -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { - struct pa_context *c = userdata; - struct pa_tagstruct *t; - uint32_t tag; - assert(client && c && c->state == CONTEXT_CONNECTING); - - pa_socket_client_free(client); - c->client = NULL; - - if (!io) { - c->error = PA_ERROR_CONNECTIONREFUSED; - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - c->pstream = pa_pstream_new(c->mainloop, io); - assert(c->pstream); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - c->state = CONTEXT_AUTHORIZING; +uint32_t pa_stream_get_index(struct pa_stream *s) { + assert(s && s->ref >= 1); + return s->device_index; } - -static struct sockaddr *resolve_server(const char *server, size_t *len) { - struct sockaddr *sa; - struct addrinfo hints, *result = NULL; - char *port; - assert(server && len); - - if ((port = strrchr(server, ':'))) - port++; - if (!port) - port = DEFAULT_PORT; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(server, port, &hints, &result) != 0) - return NULL; - assert(result); - sa = pa_xmalloc(*len = result->ai_addrlen); - memcpy(sa, result->ai_addr, *len); +void pa_stream_set_state(struct pa_stream *s, enum pa_stream_state st) { + assert(s && s->ref >= 1); - freeaddrinfo(result); + if (s->state == st) + return; - return sa; -} - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { - assert(c && c->state == CONTEXT_UNCONNECTED); - - if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { - c->error = PA_ERROR_AUTHKEY; - return -1; - } - - if (!server) - if (!(server = getenv("POLYP_SERVER"))) - server = DEFAULT_SERVER; + pa_stream_ref(s); - assert(!c->client); + s->state = st; - if (*server == '/') { - if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } else { - struct sockaddr* sa; - size_t sa_len; - - if (!(sa = resolve_server(server, &sa_len))) { - c->error = PA_ERROR_INVALIDSERVER; - return -1; - } + if ((st == PA_STREAM_FAILED || st == PA_STREAM_TERMINATED) && s->context) { + if (s->channel_valid) + pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); - pa_xfree(sa); - - if (!c->client) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } + PA_LLIST_REMOVE(struct pa_stream, s->context->streams, s); + pa_stream_unref(s); } - c->connect_complete_callback = complete; - c->connect_complete_userdata = userdata; - - pa_socket_client_set_callback(c->client, on_connection, c); - c->state = CONTEXT_CONNECTING; - - return 0; -} - -int pa_context_is_dead(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_DEAD; -} - -int pa_context_is_ready(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_READY; -} - -int pa_context_errno(struct pa_context *c) { - assert(c); - return c->error; -} + if (s->state_callback) + s->state_callback(s, s->state_userdata); -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { - assert(c); - c->die_callback = cb; - c->die_userdata = userdata; + pa_stream_unref(s); } -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +void pa_command_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_context *c = userdata; struct pa_stream *s; uint32_t channel; assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); + pa_context_ref(c); + if (pa_tagstruct_getu32(t, &channel) < 0 || !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; + pa_context_fail(c, PA_ERROR_PROTOCOL); + goto finish; } if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - return; + goto finish; c->error = PA_ERROR_KILLED; - stream_dead(s); + pa_stream_set_state(s, PA_STREAM_FAILED); + +finish: + pa_context_unref(c); } -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +void pa_command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_stream *s; struct pa_context *c = userdata; uint32_t bytes, channel; assert(pd && command == PA_COMMAND_REQUEST && t && c); + pa_context_ref(c); + if (pa_tagstruct_getu32(t, &channel) < 0 || pa_tagstruct_getu32(t, &bytes) < 0 || !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; + pa_context_fail(c, PA_ERROR_PROTOCOL); + goto finish; } if (!(s = pa_dynarray_get(c->playback_streams, channel))) - return; + goto finish; - if (s->state != STREAM_READY) - return; + if (s->state != PA_STREAM_READY) + goto finish; + + pa_stream_ref(s); s->requested_bytes += bytes; if (s->requested_bytes && s->write_callback) s->write_callback(s, s->requested_bytes, s->write_userdata); + + pa_stream_unref(s); + +finish: + pa_context_unref(c); } -static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +void pa_create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_stream *s = userdata; - assert(pd && s && s->state == STREAM_CREATING); + assert(pd && s && s->state == PA_STREAM_CREATING); + pa_stream_ref(s); + if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - - return; + if (pa_context_handle_error(s->context, command, t) < 0) + goto finish; + + pa_stream_set_state(s, PA_STREAM_FAILED); + goto finish; } if (pa_tagstruct_getu32(t, &s->channel) < 0 || ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; + pa_context_fail(s->context, PA_ERROR_PROTOCOL); + goto finish; } s->channel_valid = 1; pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - - s->state = STREAM_READY; - if (s->create_complete_callback) - s->create_complete_callback(s, 1, s->create_complete_userdata); + pa_stream_set_state(s, PA_STREAM_READY); + +finish: + pa_stream_unref(s); } -static void create_stream(struct pa_stream *s, const char *dev) { +static void create_stream(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr) { struct pa_tagstruct *t; uint32_t tag; - assert(s); + assert(s && s->ref >= 1 && s->state == PA_STREAM_DISCONNECTED); + + pa_stream_ref(s); + + if (attr) + s->buffer_attr = *attr; + else { + s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; + s->buffer_attr.tlength = DEFAULT_TLENGTH; + s->buffer_attr.prebuf = DEFAULT_PREBUF; + s->buffer_attr.minreq = DEFAULT_MINREQ; + s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; + } - s->state = STREAM_CREATING; + pa_stream_set_state(s, PA_STREAM_CREATING); t = pa_tagstruct_new(NULL, 0); assert(t); + + if (!dev) { + if (s->direction == PA_STREAM_PLAYBACK) + dev = getenv(ENV_DEFAULT_SINK); + else + dev = getenv(ENV_DEFAULT_SOURCE); + } pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); pa_tagstruct_putu32(t, tag = s->context->ctag++); @@ -609,135 +250,40 @@ static void create_stream(struct pa_stream *s, const char *dev) { pa_tagstruct_putu32(t, s->buffer_attr.fragsize); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); -} - -static struct pa_stream *internal_stream_new(struct pa_context *c) { - struct pa_stream *s; - - s = pa_xmalloc(sizeof(struct pa_stream)); - s->context = c; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->die_callback = NULL; - s->die_userdata = NULL; - s->create_complete_callback = NULL; - s->create_complete_userdata = NULL; - s->get_latency_callback = NULL; - s->get_latency_userdata = NULL; - s->finish_sample_callback = NULL; - s->finish_sample_userdata = NULL; - - s->name = NULL; - s->state = STREAM_CREATING; - s->requested_bytes = 0; - s->channel = 0; - s->channel_valid = 0; - s->device_index = (uint32_t) -1; - - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->next = c->first_stream; - if (s->next) - s->next->previous = s; - s->previous = NULL; - c->first_stream = s; - - return s; -} - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata) { - - struct pa_stream *s; - - assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = complete; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = dir; - s->sample_spec = *ss; - if (attr) - s->buffer_attr = *attr; - else { - s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; - s->buffer_attr.tlength = DEFAULT_TLENGTH; - s->buffer_attr.prebuf = DEFAULT_PREBUF; - s->buffer_attr.minreq = DEFAULT_MINREQ; - s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; - } + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s); - create_stream(s, dev); - - return s; + pa_stream_unref(s); } -void pa_stream_free(struct pa_stream *s) { - assert(s && s->context); - - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - pa_xfree(s->name); - - if (s->channel_valid && s->context->state == CONTEXT_READY) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); - pa_tagstruct_putu32(t, s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - } - - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; - else - s->context->first_stream = s->next; - - pa_xfree(s); +void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr) { + assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); + s->direction = PA_STREAM_PLAYBACK; + create_stream(s, dev, attr); } -void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { - s->write_callback = cb; - s->write_userdata = userdata; +void pa_stream_connect_record(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr) { + assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); + s->direction = PA_STREAM_RECORD; + create_stream(s, dev, attr); } -void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { +void pa_stream_write(struct pa_stream *s, const void *data, size_t length, void (*free_cb)(void *p)) { struct pa_memchunk chunk; - assert(s && s->context && data && length && s->state == STREAM_READY); + assert(s && s->context && data && length && s->state == PA_STREAM_READY && s->ref >= 1); - chunk.memblock = pa_memblock_new(length); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); + if (free_cb) { + chunk.memblock = pa_memblock_new_user((void*) data, length, free_cb); + assert(chunk.memblock && chunk.memblock->data); + } else { + chunk.memblock = pa_memblock_new(length); + assert(chunk.memblock && chunk.memblock->data); + memcpy(chunk.memblock->data, data, length); + } chunk.index = 0; chunk.length = length; pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); pa_memblock_unref(chunk.memblock); - - /*fprintf(stderr, "Sent %u bytes\n", length);*/ if (length < s->requested_bytes) s->requested_bytes -= length; @@ -746,805 +292,163 @@ void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { } size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s && s->state == STREAM_READY); + assert(s && s->state == PA_STREAM_READY && s->ref >= 1); return s->requested_bytes; } -void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->read_callback = cb; - s->read_userdata = userdata; -} +struct pa_operation * pa_stream_drain(struct pa_stream *s, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { + struct pa_operation *o; + struct pa_tagstruct *t; + uint32_t tag; + assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); -int pa_stream_is_dead(struct pa_stream *s) { - return s->state == STREAM_DEAD; -} + o = pa_operation_new(s->context, s); + assert(o); + o->callback = cb; + o->userdata = userdata; -int pa_stream_is_ready(struct pa_stream*s) { - return s->state == STREAM_READY; -} + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { - assert(s); - s->die_callback = cb; - s->die_userdata = userdata; + return pa_operation_ref(o); } -int pa_context_is_pending(struct pa_context *c) { - assert(c); +static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + uint32_t latency; + assert(pd && o && o->stream && o->context); - if (c->state != CONTEXT_READY) - return 0; + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; - return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); -} + latency = (uint32_t) -1; + } else if (pa_tagstruct_getu32(t, &latency) < 0 || !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } -struct pa_context* pa_stream_get_context(struct pa_stream *p) { - assert(p); - return p->context; + if (o->callback) { + void (*cb)(struct pa_stream *s, uint32_t latency, void *userdata) = o->callback; + cb(o->stream, latency, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); } -static void set_dispatch_callbacks(struct pa_context *c); +struct pa_operation* pa_stream_get_latency(struct pa_stream *s, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { + uint32_t tag; + struct pa_operation *o; + struct pa_tagstruct *t; + + o = pa_operation_new(s->context, s); + assert(o); + o->callback = cb; + o->userdata = userdata; -static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, o); -static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); + return pa_operation_ref(o); } -static void set_dispatch_callbacks(struct pa_context *c) { - assert(c && c->state == CONTEXT_READY); +void pa_stream_disconnect_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s && s->ref >= 1); - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(c->pdispatch)) { - pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); - return; - } + pa_stream_ref(s); - if (pa_pstream_is_pending(c->pstream)) { - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - return; - } - - assert(c->drain_complete_callback); - c->drain_complete_callback(c, c->drain_complete_userdata); -} - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata) { - - assert(c && c->state == CONTEXT_READY); - - if (complete == NULL) { - c->drain_complete_callback = NULL; - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - return 0; - } - - if (!pa_context_is_pending(c)) - return -1; - - c->drain_complete_callback = complete; - c->drain_complete_userdata = userdata; - - set_dispatch_callbacks(c); - - return 0; -} - -static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } + if (pa_context_handle_error(s->context, command, t) < 0) + goto finish; - stream_dead(s); - return; + pa_stream_set_state(s, PA_STREAM_FAILED); + goto finish; + } else if (!pa_tagstruct_eof(t)) { + pa_context_fail(s->context, PA_ERROR_PROTOCOL); + goto finish; } - if (s->state != STREAM_READY) - return; - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } + pa_stream_set_state(s, PA_STREAM_TERMINATED); - if (s->drain_complete_callback) { - void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; - s->drain_complete_callback = NULL; - temp(s, s->drain_complete_userdata); - } +finish: + pa_stream_unref(s); } - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { +void pa_stream_disconnect(struct pa_stream *s) { struct pa_tagstruct *t; uint32_t tag; - assert(s && s->state == STREAM_READY); - - if (!complete) { - s->drain_complete_callback = NULL; + assert(s && s->ref >= 1); + + if (!s->channel_valid || !s->context->state == PA_CONTEXT_READY) return; - } - s->drain_complete_callback = complete; - s->drain_complete_userdata = userdata; + pa_stream_ref(s); t = pa_tagstruct_new(NULL, 0); assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : + (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); pa_tagstruct_putu32(t, tag = s->context->ctag++); pa_tagstruct_putu32(t, s->channel); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); -} - -void pa_context_exit(struct pa_context *c) { - struct pa_tagstruct *t; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - uint32_t total, count; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &count) < 0 || - pa_tagstruct_getu32(t, &total) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, count, total, c->stat_userdata); -} - -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - c->stat_callback = cb; - c->stat_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_STAT); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); -} - -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t latency; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &latency) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, latency, s->get_latency_userdata); -} - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - p->get_latency_callback = cb; - p->get_latency_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); -} - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_stream *s; - struct pa_tagstruct *t; - uint32_t tag; - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = cb; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = PA_STREAM_UPLOAD; - s->sample_spec = *ss; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_sample_spec(t, ss); - pa_tagstruct_putu32(t, length); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); - - return s; -} - -static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 0, s->finish_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 1, s->finish_sample_userdata); -} - -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(p); - - p->finish_sample_callback = cb; - p->finish_sample_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); -} - -static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 0, c->play_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 1, c->play_sample_userdata); -} - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name && *name && (!dev || *dev)); - - c->play_sample_callback = cb; - c->play_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, volume); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); -} - -static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 0, c->remove_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 1, c->remove_sample_userdata); -} - -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name); - - c->remove_sample_callback = cb; - c->remove_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); -} - -static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_server_info i; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, NULL, c->get_server_info_userdata); - return; - } - - if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, &i, c->get_server_info_userdata); -} - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_server_info_callback = cb; - c->get_server_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); -} - -static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_sink_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.volume) < 0 || - pa_tagstruct_getu32(t, &i.monitor_source) < 0 || - pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || - pa_tagstruct_getu32(t, &i.latency) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); -} - -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_source_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || - pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); -} - -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { - struct pa_tagstruct *t; - assert(c); - - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; - c->subscribe_mask = m; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, c->ctag++); - pa_tagstruct_putu32(t, cb ? m : 0); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - enum pa_subscription_event_type e; - uint32_t index; - assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s); - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &index) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) - c->subscribe_callback(c, e, index, c->subscribe_userdata); -} - -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); + pa_stream_unref(s); } -static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_client_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.protocol_name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); +void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { + assert(s && s->ref >= 1); + s->read_callback = cb; + s->read_userdata = userdata; } - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { + assert(s && s->ref >= 1); + s->write_callback = cb; + s->write_userdata = userdata; } -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +void pa_stream_set_state_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { + assert(s && s->ref >= 1); + s->state_callback = cb; + s->state_userdata = userdata; } -static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); +void pa_stream_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + int success = 1; + assert(pd && o && o->context && o->ref >= 1); if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); - return; + success = 0; + } else if (!pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; } - while (!pa_tagstruct_eof(t)) { - struct pa_module_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_getu32(t, &i.auto_unload) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); + if (o->callback) { + void (*cb)(struct pa_stream *s, int success, void *userdata) = o->callback; + cb(o->stream, success, o->userdata); } - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); -} - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} - -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); +finish: + pa_operation_done(o); + pa_operation_unref(o); } diff --git a/polyp/polyplib-stream.h b/polyp/polyplib-stream.h index a0dd9f9c..41801c6c 100644 --- a/polyp/polyplib-stream.h +++ b/polyp/polyplib-stream.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo +#ifndef foopolyplibstreamhfoo +#define foopolyplibstreamhfoo /* $Id$ */ @@ -26,153 +26,79 @@ #include "sample.h" #include "polyplib-def.h" -#include "mainloop-api.h" +#include "cdecl.h" +#include "polyplib-operation.h" -#ifdef __cplusplus -//extern "C" { -#endif - -struct pa_context; -struct pa_stream; +/** \file + * Audio streams for input, output and sample upload */ -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); -void pa_context_unref(struct pa_context *c); -struct pa_context* pa_context_ref(struct pa_context *c); +PA_C_DECL_BEGIN -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); -int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); +/** The state of a stream */ +enum pa_stream_state { + PA_STREAM_DISCONNECTED, /**< The stream is not yet connected to any sink or source */ + PA_STREAM_CREATING, /**< The stream is being created */ + PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */ + PA_STREAM_FAILED, /**< An error occured that made the stream invalid */ + PA_STREAM_TERMINATED, /**< The stream has been terminated cleanly */ +}; -int pa_context_is_dead(struct pa_context *c); -int pa_context_is_ready(struct pa_context *c); -int pa_context_errno(struct pa_context *c); +/** \struct pa_stream + * A stream for playback or recording */ +struct pa_stream; -int pa_context_is_pending(struct pa_context *c); +/** Create a new, unconnected stream with the specified name and sample type */ +struct pa_stream* pa_stream_new(struct pa_context *c, const char *name, const struct pa_sample_spec *ss); -struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); +/** Decrease the reference counter by one */ void pa_stream_unref(struct pa_stream *s); -struct pa_stream *pa_stream_ref(struct pa_stream *s); - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); -void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); -void pa_stream_write(struct pa_stream *p, const void *data, size_t length); -size_t pa_stream_writable_size(struct pa_stream *p); - -void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); - -int pa_stream_is_dead(struct pa_stream *p); -int pa_stream_is_ready(struct pa_stream*p); +/** Increase the reference counter by one */ +struct pa_stream *pa_stream_ref(struct pa_stream *s); -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); +/** Return the current state of the stream */ +enum pa_stream_state pa_stream_get_state(struct pa_stream *p); +/** Return the context this stream is attached to */ struct pa_context* pa_stream_get_context(struct pa_stream *p); +/** Return the device (sink input or source output) index this stream is connected to */ uint32_t pa_stream_get_index(struct pa_stream *s); -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); - -struct pa_sink_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t volume; - uint32_t monitor_source; - const char *monitor_source_name; - uint32_t latency; -}; - -void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); - -struct pa_source_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t monitor_of_sink; - const char *monitor_of_sink_name; -}; - -void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); - -struct pa_server_info { - const char *user_name; - const char *host_name; - const char *server_version; - const char *server_name; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); +/** Connect the stream to a sink */ +void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr); -struct pa_module_info { - uint32_t index; - const char*name, *argument; - uint32_t n_used, auto_unload; -}; +/** Connect the stream to a source */ +void pa_stream_connect_record(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr); -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); +/** Disconnect a stream from a source/sink */ +void pa_stream_disconnect(struct pa_stream *s); -struct pa_client_info { - uint32_t index; - const char *name; - uint32_t owner_module; - const char *protocol_name; -}; +/** Write some data to the server (for playback sinks), if free_cb is + * non-NULL this routine is called when all data has been written out + * and an internal reference to the specified data is kept, the data + * is not copied. If NULL, the data is copied into an internal + * buffer. */ +void pa_stream_write(struct pa_stream *p, const void *data, size_t length, void (*free_cb)(void *p)); -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); - -struct pa_sink_input_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t sink; - struct pa_sample_spec sample_spec; - uint32_t volume; - uint32_t latency; -}; - -void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); +/** Return the amount of bytes that may be written using pa_stream_write() */ +size_t pa_stream_writable_size(struct pa_stream *p); -struct pa_source_output_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t source; - struct pa_sample_spec sample_spec; -}; +/** Drain a playback stream */ +struct pa_operation* pa_stream_drain(struct pa_stream *s, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); +/** Get the playback latency of a stream */ +struct pa_operation* pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); -void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +/** Set the callback function that is called whenever the state of the stream changes */ +void pa_stream_set_state_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); -void pa_context_exit(struct pa_context *c); -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); +/** Set the callback function that is called when new data may be written to the stream */ +void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); +/** Set the callback function that is called when new data is available from the stream */ +void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); -#ifdef __cplusplus -} -#endif +PA_C_DECL_END #endif diff --git a/polyp/polyplib-subscribe.c b/polyp/polyplib-subscribe.c index 35001d3d..a14d0b06 100644 --- a/polyp/polyplib-subscribe.c +++ b/polyp/polyplib-subscribe.c @@ -23,1528 +23,52 @@ #include #endif -#include #include -#include -#include -#include -#include -#include -#include "polyplib.h" -#include "native-common.h" -#include "pdispatch.h" -#include "pstream.h" -#include "dynarray.h" -#include "socket-client.h" +#include "polyplib-subscribe.h" +#include "polyplib-internal.h" #include "pstream-util.h" -#include "authkey.h" -#include "util.h" -#include "xmalloc.h" -#define DEFAULT_MAXLENGTH 204800 -#define DEFAULT_TLENGTH 10240 -#define DEFAULT_PREBUF 4096 -#define DEFAULT_MINREQ 1024 -#define DEFAULT_FRAGSIZE 1024 - -#define DEFAULT_TIMEOUT (5*60) -#define DEFAULT_SERVER "/tmp/polypaudio/native" -#define DEFAULT_PORT "4713" - -struct pa_context { - char *name; - struct pa_mainloop_api* mainloop; - struct pa_socket_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; - struct pa_dynarray *record_streams, *playback_streams; - struct pa_stream *first_stream; - uint32_t ctag; - uint32_t error; - enum { - CONTEXT_UNCONNECTED, - CONTEXT_CONNECTING, - CONTEXT_AUTHORIZING, - CONTEXT_SETTING_NAME, - CONTEXT_READY, - CONTEXT_DEAD - } state; - - void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); - void *connect_complete_userdata; - - void (*drain_complete_callback)(struct pa_context*c, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_context*c, void *userdata); - void *die_userdata; - - void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); - void *stat_userdata; - - void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); - void *play_sample_userdata; - - void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); - void *remove_sample_userdata; - - void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); - void *get_server_info_userdata; - - void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); - void *get_sink_info_userdata; - - void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); - void *get_source_info_userdata; - - void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); - void *subscribe_userdata; - enum pa_subscription_mask subscribe_mask; - - void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); - void *get_client_info_userdata; - - void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); - void *get_module_info_userdata; - - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; -}; - -struct pa_stream { - struct pa_context *context; - struct pa_stream *next, *previous; - - char *name; - struct pa_buffer_attr buffer_attr; - struct pa_sample_spec sample_spec; - uint32_t channel; - int channel_valid; - uint32_t device_index; - enum pa_stream_direction direction; - - enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; - uint32_t requested_bytes; - - void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); - void *read_userdata; - - void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); - void *write_userdata; - - void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); - void *create_complete_userdata; - - void (*drain_complete_callback)(struct pa_stream *s, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_stream*c, void *userdata); - void *die_userdata; - - void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); - void *get_latency_userdata; - - void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); - void *finish_sample_userdata; -}; - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_EXIT] = { NULL }, - [PA_COMMAND_REQUEST] = { command_request }, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, -}; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { - struct pa_context *c; - assert(mainloop && name); - - c = pa_xmalloc(sizeof(struct pa_context)); - c->name = pa_xstrdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - assert(c->playback_streams); - c->record_streams = pa_dynarray_new(); - assert(c->record_streams); - c->first_stream = NULL; - c->error = PA_ERROR_OK; - c->state = CONTEXT_UNCONNECTED; - c->ctag = 0; - - c->connect_complete_callback = NULL; - c->connect_complete_userdata = NULL; - - c->drain_complete_callback = NULL; - c->drain_complete_userdata = NULL; - - c->die_callback = NULL; - c->die_userdata = NULL; - - c->stat_callback = NULL; - c->stat_userdata = NULL; - - c->play_sample_callback = NULL; - c->play_sample_userdata = NULL; - - c->remove_sample_callback = NULL; - c->remove_sample_userdata = NULL; - - c->get_server_info_callback = NULL; - c->get_server_info_userdata = NULL; - - c->get_sink_info_callback = NULL; - c->get_sink_info_userdata = NULL; - - c->get_source_info_callback = NULL; - c->get_source_info_userdata = NULL; - - c->subscribe_callback = NULL; - c->subscribe_userdata = NULL; - - c->get_client_info_callback = NULL; - c->get_client_info_userdata = NULL; - - c->get_module_info_callback = NULL; - c->get_module_info_userdata = NULL; - - pa_check_for_sigpipe(); - return c; -} - -void pa_context_free(struct pa_context *c) { - assert(c); - - while (c->first_stream) - pa_stream_free(c->first_stream); - - if (c->client) - pa_socket_client_free(c->client); - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - if (c->pstream) - pa_pstream_free(c->pstream); - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - pa_xfree(c->name); - pa_xfree(c); -} - -static void stream_dead(struct pa_stream *s) { - assert(s); - - if (s->state == STREAM_DEAD) - return; - - if (s->state == STREAM_READY) { - s->state = STREAM_DEAD; - if (s->die_callback) - s->die_callback(s, s->die_userdata); - } else - s->state = STREAM_DEAD; -} - -static void context_dead(struct pa_context *c) { - struct pa_stream *s; - assert(c); - - if (c->state == CONTEXT_DEAD) - return; - - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) - pa_pstream_free(c->pstream); - c->pstream = NULL; - - if (c->client) - pa_socket_client_free(c->client); - c->client = NULL; - - for (s = c->first_stream; s; s = s->next) - stream_dead(s); - - if (c->state == CONTEXT_READY) { - c->state = CONTEXT_DEAD; - if (c->die_callback) - c->die_callback(c, c->die_userdata); - } else - c->state = CONTEXT_DEAD; -} - -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { - struct pa_context *c = userdata; - assert(p && c); - c->error = PA_ERROR_CONNECTIONTERMINATED; - context_dead(c); -} - -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { - struct pa_context *c = userdata; - assert(p && packet && c); - - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - fprintf(stderr, "polyp.c: invalid packet.\n"); - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - } -} - -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - - if (!(s = pa_dynarray_get(c->record_streams, channel))) - return; - - if (s->read_callback) - s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); -} - -static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { - assert(c && t); - - if (command == PA_COMMAND_ERROR) { - if (pa_tagstruct_getu32(t, &c->error) < 0) { - c->error = PA_ERROR_PROTOCOL; - return -1; - } - - return 0; - } - - c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; - return -1; -} - -static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); - - if (command != PA_COMMAND_REPLY) { - handle_error(c, command, t); - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - if (c->state == CONTEXT_AUTHORIZING) { - struct pa_tagstruct *t; - c->state = CONTEXT_SETTING_NAME; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, c->name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - } else { - assert(c->state == CONTEXT_SETTING_NAME); - - c->state = CONTEXT_READY; - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 1, c->connect_complete_userdata); - } - - return; -} - -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { - struct pa_context *c = userdata; - struct pa_tagstruct *t; - uint32_t tag; - assert(client && c && c->state == CONTEXT_CONNECTING); - - pa_socket_client_free(client); - c->client = NULL; - - if (!io) { - c->error = PA_ERROR_CONNECTIONREFUSED; - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - c->pstream = pa_pstream_new(c->mainloop, io); - assert(c->pstream); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - c->state = CONTEXT_AUTHORIZING; -} - -static struct sockaddr *resolve_server(const char *server, size_t *len) { - struct sockaddr *sa; - struct addrinfo hints, *result = NULL; - char *port; - assert(server && len); - - if ((port = strrchr(server, ':'))) - port++; - if (!port) - port = DEFAULT_PORT; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(server, port, &hints, &result) != 0) - return NULL; - assert(result); - - sa = pa_xmalloc(*len = result->ai_addrlen); - memcpy(sa, result->ai_addr, *len); - - freeaddrinfo(result); - - return sa; -} - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { - assert(c && c->state == CONTEXT_UNCONNECTED); - - if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { - c->error = PA_ERROR_AUTHKEY; - return -1; - } - - if (!server) - if (!(server = getenv("POLYP_SERVER"))) - server = DEFAULT_SERVER; - - assert(!c->client); - - if (*server == '/') { - if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } else { - struct sockaddr* sa; - size_t sa_len; - - if (!(sa = resolve_server(server, &sa_len))) { - c->error = PA_ERROR_INVALIDSERVER; - return -1; - } - - c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); - pa_xfree(sa); - - if (!c->client) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } - - c->connect_complete_callback = complete; - c->connect_complete_userdata = userdata; - - pa_socket_client_set_callback(c->client, on_connection, c); - c->state = CONTEXT_CONNECTING; - - return 0; -} - -int pa_context_is_dead(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_DEAD; -} - -int pa_context_is_ready(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_READY; -} - -int pa_context_errno(struct pa_context *c) { - assert(c); - return c->error; -} - -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { - assert(c); - c->die_callback = cb; - c->die_userdata = userdata; -} - -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - uint32_t channel; - assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - return; - - c->error = PA_ERROR_KILLED; - stream_dead(s); -} - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s; - struct pa_context *c = userdata; - uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - return; - - if (s->state != STREAM_READY) - return; - - s->requested_bytes += bytes; - - if (s->requested_bytes && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); -} - -static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s && s->state == STREAM_CREATING); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - - return; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - - s->state = STREAM_READY; - if (s->create_complete_callback) - s->create_complete_callback(s, 1, s->create_complete_userdata); -} - -static void create_stream(struct pa_stream *s, const char *dev) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s); - - s->state = STREAM_CREATING; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, s->buffer_attr.maxlength); - if (s->direction == PA_STREAM_PLAYBACK) { - pa_tagstruct_putu32(t, s->buffer_attr.tlength); - pa_tagstruct_putu32(t, s->buffer_attr.prebuf); - pa_tagstruct_putu32(t, s->buffer_attr.minreq); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); -} - -static struct pa_stream *internal_stream_new(struct pa_context *c) { - struct pa_stream *s; - - s = pa_xmalloc(sizeof(struct pa_stream)); - s->context = c; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->die_callback = NULL; - s->die_userdata = NULL; - s->create_complete_callback = NULL; - s->create_complete_userdata = NULL; - s->get_latency_callback = NULL; - s->get_latency_userdata = NULL; - s->finish_sample_callback = NULL; - s->finish_sample_userdata = NULL; - - s->name = NULL; - s->state = STREAM_CREATING; - s->requested_bytes = 0; - s->channel = 0; - s->channel_valid = 0; - s->device_index = (uint32_t) -1; - - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->next = c->first_stream; - if (s->next) - s->next->previous = s; - s->previous = NULL; - c->first_stream = s; - - return s; -} - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata) { - - struct pa_stream *s; - - assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = complete; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = dir; - s->sample_spec = *ss; - if (attr) - s->buffer_attr = *attr; - else { - s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; - s->buffer_attr.tlength = DEFAULT_TLENGTH; - s->buffer_attr.prebuf = DEFAULT_PREBUF; - s->buffer_attr.minreq = DEFAULT_MINREQ; - s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; - } - - create_stream(s, dev); - - return s; -} - -void pa_stream_free(struct pa_stream *s) { - assert(s && s->context); - - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - pa_xfree(s->name); - - if (s->channel_valid && s->context->state == CONTEXT_READY) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); - pa_tagstruct_putu32(t, s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - } - - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; - else - s->context->first_stream = s->next; - - pa_xfree(s); -} - -void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { - struct pa_memchunk chunk; - assert(s && s->context && data && length && s->state == STREAM_READY); - - chunk.memblock = pa_memblock_new(length); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); - pa_memblock_unref(chunk.memblock); - - /*fprintf(stderr, "Sent %u bytes\n", length);*/ - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; -} - -size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s && s->state == STREAM_READY); - return s->requested_bytes; -} - -void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->read_callback = cb; - s->read_userdata = userdata; -} - -int pa_stream_is_dead(struct pa_stream *s) { - return s->state == STREAM_DEAD; -} - -int pa_stream_is_ready(struct pa_stream*s) { - return s->state == STREAM_READY; -} - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { - assert(s); - s->die_callback = cb; - s->die_userdata = userdata; -} - -int pa_context_is_pending(struct pa_context *c) { - assert(c); - - if (c->state != CONTEXT_READY) - return 0; - - return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); -} - -struct pa_context* pa_stream_get_context(struct pa_stream *p) { - assert(p); - return p->context; -} - -static void set_dispatch_callbacks(struct pa_context *c); - -static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void set_dispatch_callbacks(struct pa_context *c) { - assert(c && c->state == CONTEXT_READY); - - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(c->pdispatch)) { - pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); - return; - } - - if (pa_pstream_is_pending(c->pstream)) { - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - return; - } - - assert(c->drain_complete_callback); - c->drain_complete_callback(c, c->drain_complete_userdata); -} - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata) { - - assert(c && c->state == CONTEXT_READY); - - if (complete == NULL) { - c->drain_complete_callback = NULL; - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - return 0; - } - - if (!pa_context_is_pending(c)) - return -1; - - c->drain_complete_callback = complete; - c->drain_complete_userdata = userdata; - - set_dispatch_callbacks(c); - - return 0; -} - -static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - return; - } - - if (s->state != STREAM_READY) - return; - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->drain_complete_callback) { - void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; - s->drain_complete_callback = NULL; - temp(s, s->drain_complete_userdata); - } -} - - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s && s->state == STREAM_READY); - - if (!complete) { - s->drain_complete_callback = NULL; - return; - } - - s->drain_complete_callback = complete; - s->drain_complete_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); -} - -void pa_context_exit(struct pa_context *c) { - struct pa_tagstruct *t; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - uint32_t total, count; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &count) < 0 || - pa_tagstruct_getu32(t, &total) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, count, total, c->stat_userdata); -} - -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - c->stat_callback = cb; - c->stat_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_STAT); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); -} - -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t latency; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &latency) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, latency, s->get_latency_userdata); -} - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - p->get_latency_callback = cb; - p->get_latency_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); -} - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_stream *s; - struct pa_tagstruct *t; - uint32_t tag; - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = cb; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = PA_STREAM_UPLOAD; - s->sample_spec = *ss; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_sample_spec(t, ss); - pa_tagstruct_putu32(t, length); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); - - return s; -} - -static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 0, s->finish_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 1, s->finish_sample_userdata); -} - -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(p); - - p->finish_sample_callback = cb; - p->finish_sample_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); -} - -static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 0, c->play_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 1, c->play_sample_userdata); -} - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name && *name && (!dev || *dev)); - - c->play_sample_callback = cb; - c->play_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, volume); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); -} - -static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 0, c->remove_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 1, c->remove_sample_userdata); -} - -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name); - - c->remove_sample_callback = cb; - c->remove_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); -} - -static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_server_info i; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, NULL, c->get_server_info_userdata); - return; - } - - if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, &i, c->get_server_info_userdata); -} - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_server_info_callback = cb; - c->get_server_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); -} - -static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_sink_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.volume) < 0 || - pa_tagstruct_getu32(t, &i.monitor_source) < 0 || - pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || - pa_tagstruct_getu32(t, &i.latency) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); -} - -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_source_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || - pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); -} - -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { - struct pa_tagstruct *t; - assert(c); - - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; - c->subscribe_mask = m; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, c->ctag++); - pa_tagstruct_putu32(t, cb ? m : 0); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +void pa_command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_context *c = userdata; enum pa_subscription_event_type e; uint32_t index; assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); + pa_context_ref(c); + if (pa_tagstruct_getu32(t, &e) < 0 || pa_tagstruct_getu32(t, &index) < 0 || !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; + pa_context_fail(c, PA_ERROR_PROTOCOL); + goto finish; } - if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) + if (c->subscribe_callback) c->subscribe_callback(c, e, index, c->subscribe_userdata); -} - -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_client_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.protocol_name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); - } - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); +finish: + pa_context_unref(c); } -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { +struct pa_operation* pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_operation *o; struct pa_tagstruct *t; uint32_t tag; assert(c); - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; - if (!cb) - return; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); + pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, cb ? m : 0); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_module_info i; + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_getu32(t, &i.auto_unload) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); + return pa_operation_ref(o); } -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} - -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} diff --git a/polyp/polyplib-subscribe.h b/polyp/polyplib-subscribe.h index a0dd9f9c..56384915 100644 --- a/polyp/polyplib-subscribe.h +++ b/polyp/polyplib-subscribe.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo +#ifndef foopolyplibsubscribehfoo +#define foopolyplibsubscribehfoo /* $Id$ */ @@ -22,157 +22,17 @@ USA. ***/ -#include +#include -#include "sample.h" #include "polyplib-def.h" -#include "mainloop-api.h" +#include "polyplib-context.h" +#include "cdecl.h" -#ifdef __cplusplus -//extern "C" { -#endif - -struct pa_context; -struct pa_stream; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); -void pa_context_unref(struct pa_context *c); -struct pa_context* pa_context_ref(struct pa_context *c); - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); -int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); - -int pa_context_is_dead(struct pa_context *c); -int pa_context_is_ready(struct pa_context *c); -int pa_context_errno(struct pa_context *c); - -int pa_context_is_pending(struct pa_context *c); - -struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_unref(struct pa_stream *s); -struct pa_stream *pa_stream_ref(struct pa_stream *s); - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); - -void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); -void pa_stream_write(struct pa_stream *p, const void *data, size_t length); -size_t pa_stream_writable_size(struct pa_stream *p); - -void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); - -int pa_stream_is_dead(struct pa_stream *p); -int pa_stream_is_ready(struct pa_stream*p); - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); - -struct pa_context* pa_stream_get_context(struct pa_stream *p); - -uint32_t pa_stream_get_index(struct pa_stream *s); - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +PA_C_DECL_BEGIN -struct pa_sink_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t volume; - uint32_t monitor_source; - const char *monitor_source_name; - uint32_t latency; -}; +struct pa_operation* pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +void pa_context_set_subscribe_callback(struct pa_context *c, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); -void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); - -struct pa_source_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t monitor_of_sink; - const char *monitor_of_sink_name; -}; - -void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); - -struct pa_server_info { - const char *user_name; - const char *host_name; - const char *server_version; - const char *server_name; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); - -struct pa_module_info { - uint32_t index; - const char*name, *argument; - uint32_t n_used, auto_unload; -}; - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); - -struct pa_client_info { - uint32_t index; - const char *name; - uint32_t owner_module; - const char *protocol_name; -}; - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); - -struct pa_sink_input_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t sink; - struct pa_sample_spec sample_spec; - uint32_t volume; - uint32_t latency; -}; - -void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); - -struct pa_source_output_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t source; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); - -void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); - -void pa_context_exit(struct pa_context *c); -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); - -#ifdef __cplusplus -} -#endif +PA_C_DECL_END #endif diff --git a/polyp/polyplib.c b/polyp/polyplib.c deleted file mode 100644 index 35001d3d..00000000 --- a/polyp/polyplib.c +++ /dev/null @@ -1,1550 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "polyplib.h" -#include "native-common.h" -#include "pdispatch.h" -#include "pstream.h" -#include "dynarray.h" -#include "socket-client.h" -#include "pstream-util.h" -#include "authkey.h" -#include "util.h" -#include "xmalloc.h" - -#define DEFAULT_MAXLENGTH 204800 -#define DEFAULT_TLENGTH 10240 -#define DEFAULT_PREBUF 4096 -#define DEFAULT_MINREQ 1024 -#define DEFAULT_FRAGSIZE 1024 - -#define DEFAULT_TIMEOUT (5*60) -#define DEFAULT_SERVER "/tmp/polypaudio/native" -#define DEFAULT_PORT "4713" - -struct pa_context { - char *name; - struct pa_mainloop_api* mainloop; - struct pa_socket_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; - struct pa_dynarray *record_streams, *playback_streams; - struct pa_stream *first_stream; - uint32_t ctag; - uint32_t error; - enum { - CONTEXT_UNCONNECTED, - CONTEXT_CONNECTING, - CONTEXT_AUTHORIZING, - CONTEXT_SETTING_NAME, - CONTEXT_READY, - CONTEXT_DEAD - } state; - - void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); - void *connect_complete_userdata; - - void (*drain_complete_callback)(struct pa_context*c, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_context*c, void *userdata); - void *die_userdata; - - void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); - void *stat_userdata; - - void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); - void *play_sample_userdata; - - void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); - void *remove_sample_userdata; - - void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); - void *get_server_info_userdata; - - void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); - void *get_sink_info_userdata; - - void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); - void *get_source_info_userdata; - - void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); - void *subscribe_userdata; - enum pa_subscription_mask subscribe_mask; - - void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); - void *get_client_info_userdata; - - void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); - void *get_module_info_userdata; - - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; -}; - -struct pa_stream { - struct pa_context *context; - struct pa_stream *next, *previous; - - char *name; - struct pa_buffer_attr buffer_attr; - struct pa_sample_spec sample_spec; - uint32_t channel; - int channel_valid; - uint32_t device_index; - enum pa_stream_direction direction; - - enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; - uint32_t requested_bytes; - - void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); - void *read_userdata; - - void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); - void *write_userdata; - - void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); - void *create_complete_userdata; - - void (*drain_complete_callback)(struct pa_stream *s, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_stream*c, void *userdata); - void *die_userdata; - - void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); - void *get_latency_userdata; - - void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); - void *finish_sample_userdata; -}; - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_EXIT] = { NULL }, - [PA_COMMAND_REQUEST] = { command_request }, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, -}; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { - struct pa_context *c; - assert(mainloop && name); - - c = pa_xmalloc(sizeof(struct pa_context)); - c->name = pa_xstrdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - assert(c->playback_streams); - c->record_streams = pa_dynarray_new(); - assert(c->record_streams); - c->first_stream = NULL; - c->error = PA_ERROR_OK; - c->state = CONTEXT_UNCONNECTED; - c->ctag = 0; - - c->connect_complete_callback = NULL; - c->connect_complete_userdata = NULL; - - c->drain_complete_callback = NULL; - c->drain_complete_userdata = NULL; - - c->die_callback = NULL; - c->die_userdata = NULL; - - c->stat_callback = NULL; - c->stat_userdata = NULL; - - c->play_sample_callback = NULL; - c->play_sample_userdata = NULL; - - c->remove_sample_callback = NULL; - c->remove_sample_userdata = NULL; - - c->get_server_info_callback = NULL; - c->get_server_info_userdata = NULL; - - c->get_sink_info_callback = NULL; - c->get_sink_info_userdata = NULL; - - c->get_source_info_callback = NULL; - c->get_source_info_userdata = NULL; - - c->subscribe_callback = NULL; - c->subscribe_userdata = NULL; - - c->get_client_info_callback = NULL; - c->get_client_info_userdata = NULL; - - c->get_module_info_callback = NULL; - c->get_module_info_userdata = NULL; - - pa_check_for_sigpipe(); - return c; -} - -void pa_context_free(struct pa_context *c) { - assert(c); - - while (c->first_stream) - pa_stream_free(c->first_stream); - - if (c->client) - pa_socket_client_free(c->client); - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - if (c->pstream) - pa_pstream_free(c->pstream); - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - pa_xfree(c->name); - pa_xfree(c); -} - -static void stream_dead(struct pa_stream *s) { - assert(s); - - if (s->state == STREAM_DEAD) - return; - - if (s->state == STREAM_READY) { - s->state = STREAM_DEAD; - if (s->die_callback) - s->die_callback(s, s->die_userdata); - } else - s->state = STREAM_DEAD; -} - -static void context_dead(struct pa_context *c) { - struct pa_stream *s; - assert(c); - - if (c->state == CONTEXT_DEAD) - return; - - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) - pa_pstream_free(c->pstream); - c->pstream = NULL; - - if (c->client) - pa_socket_client_free(c->client); - c->client = NULL; - - for (s = c->first_stream; s; s = s->next) - stream_dead(s); - - if (c->state == CONTEXT_READY) { - c->state = CONTEXT_DEAD; - if (c->die_callback) - c->die_callback(c, c->die_userdata); - } else - c->state = CONTEXT_DEAD; -} - -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { - struct pa_context *c = userdata; - assert(p && c); - c->error = PA_ERROR_CONNECTIONTERMINATED; - context_dead(c); -} - -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { - struct pa_context *c = userdata; - assert(p && packet && c); - - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - fprintf(stderr, "polyp.c: invalid packet.\n"); - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - } -} - -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - - if (!(s = pa_dynarray_get(c->record_streams, channel))) - return; - - if (s->read_callback) - s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); -} - -static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { - assert(c && t); - - if (command == PA_COMMAND_ERROR) { - if (pa_tagstruct_getu32(t, &c->error) < 0) { - c->error = PA_ERROR_PROTOCOL; - return -1; - } - - return 0; - } - - c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; - return -1; -} - -static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); - - if (command != PA_COMMAND_REPLY) { - handle_error(c, command, t); - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - if (c->state == CONTEXT_AUTHORIZING) { - struct pa_tagstruct *t; - c->state = CONTEXT_SETTING_NAME; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, c->name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - } else { - assert(c->state == CONTEXT_SETTING_NAME); - - c->state = CONTEXT_READY; - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 1, c->connect_complete_userdata); - } - - return; -} - -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { - struct pa_context *c = userdata; - struct pa_tagstruct *t; - uint32_t tag; - assert(client && c && c->state == CONTEXT_CONNECTING); - - pa_socket_client_free(client); - c->client = NULL; - - if (!io) { - c->error = PA_ERROR_CONNECTIONREFUSED; - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - c->pstream = pa_pstream_new(c->mainloop, io); - assert(c->pstream); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - c->state = CONTEXT_AUTHORIZING; -} - -static struct sockaddr *resolve_server(const char *server, size_t *len) { - struct sockaddr *sa; - struct addrinfo hints, *result = NULL; - char *port; - assert(server && len); - - if ((port = strrchr(server, ':'))) - port++; - if (!port) - port = DEFAULT_PORT; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(server, port, &hints, &result) != 0) - return NULL; - assert(result); - - sa = pa_xmalloc(*len = result->ai_addrlen); - memcpy(sa, result->ai_addr, *len); - - freeaddrinfo(result); - - return sa; -} - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { - assert(c && c->state == CONTEXT_UNCONNECTED); - - if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { - c->error = PA_ERROR_AUTHKEY; - return -1; - } - - if (!server) - if (!(server = getenv("POLYP_SERVER"))) - server = DEFAULT_SERVER; - - assert(!c->client); - - if (*server == '/') { - if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } else { - struct sockaddr* sa; - size_t sa_len; - - if (!(sa = resolve_server(server, &sa_len))) { - c->error = PA_ERROR_INVALIDSERVER; - return -1; - } - - c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); - pa_xfree(sa); - - if (!c->client) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } - - c->connect_complete_callback = complete; - c->connect_complete_userdata = userdata; - - pa_socket_client_set_callback(c->client, on_connection, c); - c->state = CONTEXT_CONNECTING; - - return 0; -} - -int pa_context_is_dead(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_DEAD; -} - -int pa_context_is_ready(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_READY; -} - -int pa_context_errno(struct pa_context *c) { - assert(c); - return c->error; -} - -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { - assert(c); - c->die_callback = cb; - c->die_userdata = userdata; -} - -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - uint32_t channel; - assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - return; - - c->error = PA_ERROR_KILLED; - stream_dead(s); -} - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s; - struct pa_context *c = userdata; - uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - return; - - if (s->state != STREAM_READY) - return; - - s->requested_bytes += bytes; - - if (s->requested_bytes && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); -} - -static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s && s->state == STREAM_CREATING); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - - return; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - - s->state = STREAM_READY; - if (s->create_complete_callback) - s->create_complete_callback(s, 1, s->create_complete_userdata); -} - -static void create_stream(struct pa_stream *s, const char *dev) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s); - - s->state = STREAM_CREATING; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, s->buffer_attr.maxlength); - if (s->direction == PA_STREAM_PLAYBACK) { - pa_tagstruct_putu32(t, s->buffer_attr.tlength); - pa_tagstruct_putu32(t, s->buffer_attr.prebuf); - pa_tagstruct_putu32(t, s->buffer_attr.minreq); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); -} - -static struct pa_stream *internal_stream_new(struct pa_context *c) { - struct pa_stream *s; - - s = pa_xmalloc(sizeof(struct pa_stream)); - s->context = c; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->die_callback = NULL; - s->die_userdata = NULL; - s->create_complete_callback = NULL; - s->create_complete_userdata = NULL; - s->get_latency_callback = NULL; - s->get_latency_userdata = NULL; - s->finish_sample_callback = NULL; - s->finish_sample_userdata = NULL; - - s->name = NULL; - s->state = STREAM_CREATING; - s->requested_bytes = 0; - s->channel = 0; - s->channel_valid = 0; - s->device_index = (uint32_t) -1; - - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->next = c->first_stream; - if (s->next) - s->next->previous = s; - s->previous = NULL; - c->first_stream = s; - - return s; -} - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata) { - - struct pa_stream *s; - - assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = complete; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = dir; - s->sample_spec = *ss; - if (attr) - s->buffer_attr = *attr; - else { - s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; - s->buffer_attr.tlength = DEFAULT_TLENGTH; - s->buffer_attr.prebuf = DEFAULT_PREBUF; - s->buffer_attr.minreq = DEFAULT_MINREQ; - s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; - } - - create_stream(s, dev); - - return s; -} - -void pa_stream_free(struct pa_stream *s) { - assert(s && s->context); - - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - pa_xfree(s->name); - - if (s->channel_valid && s->context->state == CONTEXT_READY) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); - pa_tagstruct_putu32(t, s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - } - - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; - else - s->context->first_stream = s->next; - - pa_xfree(s); -} - -void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { - struct pa_memchunk chunk; - assert(s && s->context && data && length && s->state == STREAM_READY); - - chunk.memblock = pa_memblock_new(length); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); - pa_memblock_unref(chunk.memblock); - - /*fprintf(stderr, "Sent %u bytes\n", length);*/ - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; -} - -size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s && s->state == STREAM_READY); - return s->requested_bytes; -} - -void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->read_callback = cb; - s->read_userdata = userdata; -} - -int pa_stream_is_dead(struct pa_stream *s) { - return s->state == STREAM_DEAD; -} - -int pa_stream_is_ready(struct pa_stream*s) { - return s->state == STREAM_READY; -} - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { - assert(s); - s->die_callback = cb; - s->die_userdata = userdata; -} - -int pa_context_is_pending(struct pa_context *c) { - assert(c); - - if (c->state != CONTEXT_READY) - return 0; - - return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); -} - -struct pa_context* pa_stream_get_context(struct pa_stream *p) { - assert(p); - return p->context; -} - -static void set_dispatch_callbacks(struct pa_context *c); - -static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void set_dispatch_callbacks(struct pa_context *c) { - assert(c && c->state == CONTEXT_READY); - - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(c->pdispatch)) { - pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); - return; - } - - if (pa_pstream_is_pending(c->pstream)) { - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - return; - } - - assert(c->drain_complete_callback); - c->drain_complete_callback(c, c->drain_complete_userdata); -} - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata) { - - assert(c && c->state == CONTEXT_READY); - - if (complete == NULL) { - c->drain_complete_callback = NULL; - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - return 0; - } - - if (!pa_context_is_pending(c)) - return -1; - - c->drain_complete_callback = complete; - c->drain_complete_userdata = userdata; - - set_dispatch_callbacks(c); - - return 0; -} - -static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - return; - } - - if (s->state != STREAM_READY) - return; - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->drain_complete_callback) { - void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; - s->drain_complete_callback = NULL; - temp(s, s->drain_complete_userdata); - } -} - - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s && s->state == STREAM_READY); - - if (!complete) { - s->drain_complete_callback = NULL; - return; - } - - s->drain_complete_callback = complete; - s->drain_complete_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); -} - -void pa_context_exit(struct pa_context *c) { - struct pa_tagstruct *t; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - uint32_t total, count; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &count) < 0 || - pa_tagstruct_getu32(t, &total) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, count, total, c->stat_userdata); -} - -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - c->stat_callback = cb; - c->stat_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_STAT); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); -} - -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t latency; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &latency) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, latency, s->get_latency_userdata); -} - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - p->get_latency_callback = cb; - p->get_latency_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); -} - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_stream *s; - struct pa_tagstruct *t; - uint32_t tag; - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = cb; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = PA_STREAM_UPLOAD; - s->sample_spec = *ss; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_sample_spec(t, ss); - pa_tagstruct_putu32(t, length); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); - - return s; -} - -static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 0, s->finish_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 1, s->finish_sample_userdata); -} - -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(p); - - p->finish_sample_callback = cb; - p->finish_sample_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); -} - -static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 0, c->play_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 1, c->play_sample_userdata); -} - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name && *name && (!dev || *dev)); - - c->play_sample_callback = cb; - c->play_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, volume); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); -} - -static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 0, c->remove_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 1, c->remove_sample_userdata); -} - -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name); - - c->remove_sample_callback = cb; - c->remove_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); -} - -static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_server_info i; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, NULL, c->get_server_info_userdata); - return; - } - - if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, &i, c->get_server_info_userdata); -} - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_server_info_callback = cb; - c->get_server_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); -} - -static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_sink_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.volume) < 0 || - pa_tagstruct_getu32(t, &i.monitor_source) < 0 || - pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || - pa_tagstruct_getu32(t, &i.latency) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); -} - -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_source_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || - pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); -} - -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { - struct pa_tagstruct *t; - assert(c); - - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; - c->subscribe_mask = m; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, c->ctag++); - pa_tagstruct_putu32(t, cb ? m : 0); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - enum pa_subscription_event_type e; - uint32_t index; - assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); - - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &index) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) - c->subscribe_callback(c, e, index, c->subscribe_userdata); -} - -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_client_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.protocol_name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); -} - - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_module_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_getu32(t, &i.auto_unload) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); -} - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} - -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} diff --git a/polyp/polyplib.h b/polyp/polyplib.h index a0dd9f9c..b9e5637c 100644 --- a/polyp/polyplib.h +++ b/polyp/polyplib.h @@ -22,157 +22,13 @@ USA. ***/ -#include - +#include "mainloop-api.h" #include "sample.h" #include "polyplib-def.h" -#include "mainloop-api.h" - -#ifdef __cplusplus -//extern "C" { -#endif - -struct pa_context; -struct pa_stream; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); -void pa_context_unref(struct pa_context *c); -struct pa_context* pa_context_ref(struct pa_context *c); - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); -int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); - -int pa_context_is_dead(struct pa_context *c); -int pa_context_is_ready(struct pa_context *c); -int pa_context_errno(struct pa_context *c); - -int pa_context_is_pending(struct pa_context *c); - -struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_unref(struct pa_stream *s); -struct pa_stream *pa_stream_ref(struct pa_stream *s); - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); - -void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); -void pa_stream_write(struct pa_stream *p, const void *data, size_t length); -size_t pa_stream_writable_size(struct pa_stream *p); - -void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); - -int pa_stream_is_dead(struct pa_stream *p); -int pa_stream_is_ready(struct pa_stream*p); - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); - -struct pa_context* pa_stream_get_context(struct pa_stream *p); - -uint32_t pa_stream_get_index(struct pa_stream *s); - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); - -struct pa_sink_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t volume; - uint32_t monitor_source; - const char *monitor_source_name; - uint32_t latency; -}; - -void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); - -struct pa_source_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t monitor_of_sink; - const char *monitor_of_sink_name; -}; - -void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); - -struct pa_server_info { - const char *user_name; - const char *host_name; - const char *server_version; - const char *server_name; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); - -struct pa_module_info { - uint32_t index; - const char*name, *argument; - uint32_t n_used, auto_unload; -}; - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); - -struct pa_client_info { - uint32_t index; - const char *name; - uint32_t owner_module; - const char *protocol_name; -}; - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); - -struct pa_sink_input_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t sink; - struct pa_sample_spec sample_spec; - uint32_t volume; - uint32_t latency; -}; - -void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); - -struct pa_source_output_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t source; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); - -void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); - -void pa_context_exit(struct pa_context *c); -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); - -#ifdef __cplusplus -} -#endif +#include "polyplib-context.h" +#include "polyplib-stream.h" +#include "polyplib-introspect.h" +#include "polyplib-subscribe.h" +#include "polyplib-scache.h" #endif diff --git a/polyp/sample-util.c b/polyp/sample-util.c index 5b1cd626..8f5558a4 100644 --- a/polyp/sample-util.c +++ b/polyp/sample-util.c @@ -135,10 +135,3 @@ void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, } } -uint32_t pa_volume_multiply(uint32_t a, uint32_t b) { - uint64_t p = a; - p *= b; - p /= PA_VOLUME_NORM; - - return (uint32_t) p; -} diff --git a/polyp/sample-util.h b/polyp/sample-util.h index 73101ab4..66f40a16 100644 --- a/polyp/sample-util.h +++ b/polyp/sample-util.h @@ -26,8 +26,6 @@ #include "memblock.h" #include "memchunk.h" -#define PA_VOLUME_NORM (0x100) -#define PA_VOLUME_MUTE (0) struct pa_memblock *pa_silence_memblock(struct pa_memblock* b, const struct pa_sample_spec *spec); void pa_silence_memchunk(struct pa_memchunk *c, const struct pa_sample_spec *spec); @@ -43,6 +41,4 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, uint32_t volume); -uint32_t pa_volume_multiply(uint32_t a, uint32_t b); - #endif diff --git a/polyp/sample.c b/polyp/sample.c index e4c4bd52..4f93f2b7 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -96,3 +96,11 @@ void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec) { assert(pa_sample_spec_valid(spec)); snprintf(s, l, "%s %uch %uHz", table[spec->format], spec->channels, spec->rate); } + +uint32_t pa_volume_multiply(uint32_t a, uint32_t b) { + uint64_t p = a; + p *= b; + p /= PA_VOLUME_NORM; + + return (uint32_t) p; +} diff --git a/polyp/sample.h b/polyp/sample.h index 25027879..a7cde093 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -25,9 +25,9 @@ #include #include -#ifdef __cplusplus -extern "C" { -#endif +#include "cdecl.h" + +PA_C_DECL_BEGIN enum pa_sample_format { PA_SAMPLE_U8, @@ -49,10 +49,11 @@ enum pa_sample_format { #endif #define PA_SAMPLE_FLOAT32 PA_SAMPLE_FLOAT32NE +/** A sample format and attribute specification */ struct pa_sample_spec { - enum pa_sample_format format; - uint32_t rate; - uint8_t channels; + enum pa_sample_format format; /**< The sample format */ + uint32_t rate; /**< The sample rate. (e.g. 44100) */ + uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */ }; size_t pa_bytes_per_second(const struct pa_sample_spec *spec); @@ -64,8 +65,10 @@ int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_s #define PA_SAMPLE_SNPRINT_MAX_LENGTH 32 void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec); -#ifdef __cplusplus -} -#endif +#define PA_VOLUME_NORM (0x100) +#define PA_VOLUME_MUTE (0) +uint32_t pa_volume_multiply(uint32_t a, uint32_t b); + +PA_C_DECL_END #endif diff --git a/polyp/socket-client.c b/polyp/socket-client.c index e8cb2f92..dffbfe7d 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -120,7 +120,7 @@ static int do_connect(struct pa_socket_client *c, const struct sockaddr *sa, soc if ((r = connect(c->fd, sa, len)) < 0) { if (errno != EINPROGRESS) { - fprintf(stderr, "connect(): %s\n", strerror(errno)); + /*fprintf(stderr, "connect(): %s\n", strerror(errno));*/ return -1; } diff --git a/polyp/socket-client.h b/polyp/socket-client.h index 2a89210e..7b9e2a72 100644 --- a/polyp/socket-client.h +++ b/polyp/socket-client.h @@ -23,6 +23,8 @@ ***/ #include +#include + #include "mainloop-api.h" #include "iochannel.h" diff --git a/polyp/tagstruct.h b/polyp/tagstruct.h index aefd03c4..bcd7f456 100644 --- a/polyp/tagstruct.h +++ b/polyp/tagstruct.h @@ -48,6 +48,4 @@ int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t le int pa_tagstruct_eof(struct pa_tagstruct*t); const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l); - - #endif diff --git a/polyp/xmalloc.c b/polyp/xmalloc.c index 8ff3054d..7d8b4821 100644 --- a/polyp/xmalloc.c +++ b/polyp/xmalloc.c @@ -52,25 +52,36 @@ void *pa_xrealloc(void *ptr, size_t size) { return p; } -char *pa_xstrdup(const char *s) { - if (!s) +void* pa_xmemdup(const void *p, size_t l) { + if (!p) return NULL; else { - char *r = strdup(s); - if (!r) - oom(); - + char *r = pa_xmalloc(l); + memcpy(r, p, l); return r; } } +char *pa_xstrdup(const char *s) { + if (!s) + return NULL; + + return pa_xmemdup(s, strlen(s)+1); +} + char *pa_xstrndup(const char *s, size_t l) { if (!s) return NULL; else { - char *r = strndup(s, l); - if (!r) - oom(); + char *r; + size_t t = strlen(s); + + if (t > l) + t = l; + + r = pa_xmemdup(s, t+1); + r[t] = 0; return r; } } + diff --git a/polyp/xmalloc.h b/polyp/xmalloc.h index 45209b05..eaf8f708 100644 --- a/polyp/xmalloc.h +++ b/polyp/xmalloc.h @@ -12,4 +12,6 @@ void *pa_xrealloc(void *ptr, size_t size); char *pa_xstrdup(const char *s); char *pa_xstrndup(const char *s, size_t l); +void* pa_xmemdup(const void *p, size_t l); + #endif -- cgit From c17545108b33162fb186f797b8a408511e9252f4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 15 Aug 2004 00:02:26 +0000 Subject: proper ref counting for more objects some documentation update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@124 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doxygen/doxygen.conf.in | 2 +- polyp/Makefile.am | 6 ++- polyp/client.c | 2 + polyp/glib-mainloop.h | 2 +- polyp/mainloop-api.h | 30 +++++++++++- polyp/mainloop-signal.h | 5 ++ polyp/module-protocol-stub.c | 2 +- polyp/module-x11-bell.c | 1 + polyp/native-common.h | 6 +++ polyp/pdispatch.c | 111 +++++++++++++++++++++++-------------------- polyp/pdispatch.h | 5 +- polyp/polyplib-context.c | 22 +++++---- polyp/polyplib-error.h | 4 +- polyp/polyplib-subscribe.c | 8 +++- polyp/protocol-cli.c | 2 +- polyp/protocol-esound.c | 2 +- polyp/protocol-native.c | 7 +-- polyp/protocol-simple.c | 2 +- polyp/pstream.c | 85 ++++++++++++++++++--------------- polyp/pstream.h | 7 +-- polyp/socket-client.c | 47 ++++++++++++------ polyp/socket-client.h | 3 +- polyp/socket-server.c | 28 +++++++++-- polyp/socket-server.h | 3 +- 24 files changed, 250 insertions(+), 142 deletions(-) diff --git a/doxygen/doxygen.conf.in b/doxygen/doxygen.conf.in index 78a43685..7fd00c60 100644 --- a/doxygen/doxygen.conf.in +++ b/doxygen/doxygen.conf.in @@ -291,7 +291,7 @@ HIDE_SCOPE_NAMES = NO # will put a list of the files that are included by a file in the documentation # of that file. -SHOW_INCLUDE_FILES = YES +SHOW_INCLUDE_FILES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 7f70ec9d..f2d61f7c 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -124,7 +124,8 @@ polypaudio_SOURCES = idxset.c idxset.h \ play-memchunk.c play-memchunk.h \ autoload.c autoload.h \ xmalloc.c xmalloc.h \ - subscribe.h subscribe.c + subscribe.h subscribe.c \ + debug.h polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) @@ -296,7 +297,8 @@ libpolyp_la_SOURCES = polyplib.h \ polyplib-introspect.c polyplib-introspect.h \ polyplib-scache.c polyplib-scache.h \ polyplib-subscribe.c polyplib-subscribe.h \ - cdecl.h + cdecl.h \ + llist.h libpolyp_la_CFLAGS = $(AM_CFLAGS) libpolyp_mainloop_la_SOURCES = mainloop-api.h mainloop-api.c \ diff --git a/polyp/client.c b/polyp/client.c index 809f9761..0cb42466 100644 --- a/polyp/client.c +++ b/polyp/client.c @@ -79,4 +79,6 @@ void pa_client_rename(struct pa_client *c, const char *name) { assert(c); pa_xfree(c->name); c->name = pa_xstrdup(name); + + pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->index); } diff --git a/polyp/glib-mainloop.h b/polyp/glib-mainloop.h index c67e72bd..1ba663fd 100644 --- a/polyp/glib-mainloop.h +++ b/polyp/glib-mainloop.h @@ -24,6 +24,6 @@ void pa_glib_mainloop_free(struct pa_glib_mainloop* g); /** Return the abstract main loop API vtable for the GLIB main loop object */ struct pa_mainloop_api* pa_glib_mainloop_get_api(struct pa_glib_mainloop *g); -PA_C_DECL_BEGIN +PA_C_DECL_END #endif diff --git a/polyp/mainloop-api.h b/polyp/mainloop-api.h index 97ab6a68..c1f40eae 100644 --- a/polyp/mainloop-api.h +++ b/polyp/mainloop-api.h @@ -27,6 +27,20 @@ #include "cdecl.h" +/** \file + * + * Main loop abstraction layer. Both the polypaudio core and the + * polypaudio client library use a main loop abstraction layer. Due to + * this it is possible to embed polypaudio into other + * applications easily. Two main loop implemenations are + * currently available: + * \li A minimal implementation based on the C library's poll() function (See \ref mainloop.h) + * \li A wrapper around the GLIB main loop. Use this to embed polypaudio into your GLIB/GTK+/GNOME programs (See \ref glib-mainloop.h) + * + * The structure pa_mainloop_api is used as vtable for the main loop abstraction. + * */ + + PA_C_DECL_BEGIN /** A bitmask for IO events */ @@ -55,16 +69,28 @@ struct pa_mainloop_api { /** A pointer to some private, arbitrary data of the main loop implementation */ void *userdata; - /* IO sources */ + /** Create a new IO event source object */ struct pa_io_event* (*io_new)(struct pa_mainloop_api*a, int fd, enum pa_io_event_flags events, void (*callback) (struct pa_mainloop_api*a, struct pa_io_event* e, int fd, enum pa_io_event_flags events, void *userdata), void *userdata); + + /** Enable or disable IO events on this object */ void (*io_enable)(struct pa_io_event* e, enum pa_io_event_flags events); + + /** Free a IO event source object */ void (*io_free)(struct pa_io_event* e); + + /** Set a function that is called when the IO event source is destroyed. Use this to free the userdata argument if required */ void (*io_set_destroy)(struct pa_io_event *e, void (*callback) (struct pa_mainloop_api*a, struct pa_io_event *e, void *userdata)); - /* Time sources */ + /** Create a new timer event source object for the specified Unix time */ struct pa_time_event* (*time_new)(struct pa_mainloop_api*a, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*a, struct pa_time_event* e, const struct timeval *tv, void *userdata), void *userdata); + + /** Restart a running or expired timer event source with a new Unix time */ void (*time_restart)(struct pa_time_event* e, const struct timeval *tv); + + /** Free a deferred timer event source object */ void (*time_free)(struct pa_time_event* e); + + /** Set a function that is called when the timer event source is destroyed. Use this to free the userdata argument if required */ void (*time_set_destroy)(struct pa_time_event *e, void (*callback) (struct pa_mainloop_api*a, struct pa_time_event *e, void *userdata)); /** Create a new deferred event source object */ diff --git a/polyp/mainloop-signal.h b/polyp/mainloop-signal.h index dacbc153..4dd6c552 100644 --- a/polyp/mainloop-signal.h +++ b/polyp/mainloop-signal.h @@ -23,6 +23,9 @@ ***/ #include "mainloop-api.h" +#include "cdecl.h" + +PA_C_DECL_BEGIN int pa_signal_init(struct pa_mainloop_api *api); void pa_signal_done(void); @@ -34,4 +37,6 @@ void pa_signal_free(struct pa_signal_event *e); void pa_signal_set_destroy(struct pa_signal_event *e, void (*callback) (struct pa_mainloop_api *api, struct pa_signal_event*e, void *userdata)); +PA_C_DECL_END + #endif diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index 3ce18c31..3b1a0270 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -145,7 +145,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { goto finish; if (!(m->userdata = protocol_new(c, s, m, ma))) { - pa_socket_server_free(s); + pa_socket_server_unref(s); goto finish; } diff --git a/polyp/module-x11-bell.c b/polyp/module-x11-bell.c index 5449e944..2414e36b 100644 --- a/polyp/module-x11-bell.c +++ b/polyp/module-x11-bell.c @@ -154,6 +154,7 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { } pa_xfree(u->scache_item); + pa_xfree(u->sink_name); if (u->display) XCloseDisplay(u->display); diff --git a/polyp/native-common.h b/polyp/native-common.h index fa3213d0..0fc44165 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -22,6 +22,10 @@ USA. ***/ +#include "cdecl.h" + +PA_C_DECL_BEGIN + enum { PA_COMMAND_ERROR, PA_COMMAND_TIMEOUT, /* pseudo command */ @@ -121,4 +125,6 @@ enum pa_subscription_event_type { #define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) +PA_C_DECL_END + #endif diff --git a/polyp/pdispatch.c b/polyp/pdispatch.c index 2d4c4d64..9ed91fc5 100644 --- a/polyp/pdispatch.c +++ b/polyp/pdispatch.c @@ -30,6 +30,7 @@ #include "pdispatch.h" #include "native-common.h" #include "xmalloc.h" +#include "llist.h" /*#define DEBUG_OPCODES*/ @@ -65,37 +66,30 @@ static const char *command_names[PA_COMMAND_MAX] = { struct reply_info { struct pa_pdispatch *pdispatch; - struct reply_info *next, *previous; + PA_LLIST_FIELDS(struct reply_info); void (*callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); void *userdata; uint32_t tag; struct pa_time_event *time_event; - int callback_is_running; }; struct pa_pdispatch { + int ref; struct pa_mainloop_api *mainloop; const struct pa_pdispatch_command *command_table; unsigned n_commands; - struct reply_info *replies; + PA_LLIST_HEAD(struct reply_info, replies); void (*drain_callback)(struct pa_pdispatch *pd, void *userdata); void *drain_userdata; - int in_use, shall_free; }; static void reply_info_free(struct reply_info *r) { assert(r && r->pdispatch && r->pdispatch->mainloop); - if (r->pdispatch) + if (r->time_event) r->pdispatch->mainloop->time_free(r->time_event); - - if (r->previous) - r->previous->next = r->next; - else - r->pdispatch->replies = r->next; - - if (r->next) - r->next->previous = r->previous; + + PA_LLIST_REMOVE(struct reply_info, r->pdispatch->replies, r); pa_xfree(r); } @@ -107,37 +101,56 @@ struct pa_pdispatch* pa_pdispatch_new(struct pa_mainloop_api *mainloop, const st assert((entries && table) || (!entries && !table)); pd = pa_xmalloc(sizeof(struct pa_pdispatch)); + pd->ref = 1; pd->mainloop = mainloop; pd->command_table = table; pd->n_commands = entries; - pd->replies = NULL; + PA_LLIST_HEAD_INIT(struct pa_reply_info, pd->replies); pd->drain_callback = NULL; pd->drain_userdata = NULL; - pd->in_use = pd->shall_free = 0; - return pd; } -void pa_pdispatch_free(struct pa_pdispatch *pd) { +void pdispatch_free(struct pa_pdispatch *pd) { assert(pd); - if (pd->in_use) { - pd->shall_free = 1; - return; - } - while (pd->replies) reply_info_free(pd->replies); + pa_xfree(pd); } +static void run_action(struct pa_pdispatch *pd, struct reply_info *r, uint32_t command, struct pa_tagstruct *ts) { + void (*callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); + void *userdata; + uint32_t tag; + assert(r); + + pa_pdispatch_ref(pd); + + callback = r->callback; + userdata = r->userdata; + tag = r->tag; + + reply_info_free(r); + + callback(pd, command, tag, ts, userdata); + + if (pd->drain_callback && !pa_pdispatch_is_pending(pd)) + pd->drain_callback(pd, pd->drain_userdata); + + pa_pdispatch_unref(pd); +} + int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *userdata) { uint32_t tag, command; struct pa_tagstruct *ts = NULL; int ret = -1; - assert(pd && packet && packet->data && !pd->in_use); + assert(pd && packet && packet->data); + pa_pdispatch_ref(pd); + if (packet->length <= 8) goto finish; @@ -159,20 +172,8 @@ int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *use if (r->tag == tag) break; - if (r) { - pd->in_use = r->callback_is_running = 1; - assert(r->callback); - r->callback(r->pdispatch, command, tag, ts, r->userdata); - pd->in_use = r->callback_is_running = 0; - reply_info_free(r); - - if (pd->shall_free) - pa_pdispatch_free(pd); - else { - if (pd->drain_callback && !pa_pdispatch_is_pending(pd)) - pd->drain_callback(pd, pd->drain_userdata); - } - } + if (r) + run_action(pd, r, command, ts); } else if (pd->command_table && command < pd->n_commands) { const struct pa_pdispatch_command *c = pd->command_table+command; @@ -186,33 +187,30 @@ int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *use finish: if (ts) - pa_tagstruct_free(ts); + pa_tagstruct_free(ts); + + pa_pdispatch_unref(pd); return ret; } static void timeout_callback(struct pa_mainloop_api*m, struct pa_time_event*e, const struct timeval *tv, void *userdata) { struct reply_info*r = userdata; - assert (r && r->time_event == e && r->pdispatch && r->pdispatch->mainloop == m && r->callback); + assert(r && r->time_event == e && r->pdispatch && r->pdispatch->mainloop == m && r->callback); - r->callback(r->pdispatch, PA_COMMAND_TIMEOUT, r->tag, NULL, r->userdata); - reply_info_free(r); - - if (r->pdispatch->drain_callback && !pa_pdispatch_is_pending(r->pdispatch)) - r->pdispatch->drain_callback(r->pdispatch, r->pdispatch->drain_userdata); + run_action(r->pdispatch, r, PA_COMMAND_TIMEOUT, NULL); } void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int timeout, void (*cb)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void *userdata) { struct reply_info *r; struct timeval tv; - assert(pd && cb); + assert(pd && pd->ref >= 1 && cb); r = pa_xmalloc(sizeof(struct reply_info)); r->pdispatch = pd; r->callback = cb; r->userdata = userdata; r->tag = tag; - r->callback_is_running = 0; gettimeofday(&tv, NULL); tv.tv_sec += timeout; @@ -220,11 +218,7 @@ void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int time r->time_event = pd->mainloop->time_new(pd->mainloop, &tv, timeout_callback, r); assert(r->time_event); - r->previous = NULL; - r->next = pd->replies; - if (r->next) - r->next->previous = r; - pd->replies = r; + PA_LLIST_PREPEND(struct reply_info, pd->replies, r); } int pa_pdispatch_is_pending(struct pa_pdispatch *pd) { @@ -248,7 +242,20 @@ void pa_pdispatch_unregister_reply(struct pa_pdispatch *pd, void *userdata) { for (r = pd->replies; r; r = n) { n = r->next; - if (!r->callback_is_running && r->userdata == userdata) /* when this item's callback is currently running it is destroyed anyway in the very near future */ + if (r->userdata == userdata) reply_info_free(r); } } + +void pa_pdispatch_unref(struct pa_pdispatch *pd) { + assert(pd && pd->ref >= 1); + + if (!(--(pd->ref))) + pdispatch_free(pd); +} + +struct pa_pdispatch* pa_pdispatch_ref(struct pa_pdispatch *pd) { + assert(pd && pd->ref >= 1); + pd->ref++; + return pd; +} diff --git a/polyp/pdispatch.h b/polyp/pdispatch.h index 796c1e03..ff99b184 100644 --- a/polyp/pdispatch.h +++ b/polyp/pdispatch.h @@ -29,14 +29,13 @@ struct pa_pdispatch; -/* It is safe to destroy the calling pdispatch object from all callbacks */ - struct pa_pdispatch_command { void (*proc)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); }; struct pa_pdispatch* pa_pdispatch_new(struct pa_mainloop_api *m, const struct pa_pdispatch_command*table, unsigned entries); -void pa_pdispatch_free(struct pa_pdispatch *pd); +void pa_pdispatch_unref(struct pa_pdispatch *pd); +struct pa_pdispatch* pa_pdispatch_ref(struct pa_pdispatch *pd); int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*p, void *userdata); diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 5f849e24..2a0c24a5 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -92,11 +92,13 @@ static void context_free(struct pa_context *c) { pa_stream_set_state(c->streams, PA_STREAM_TERMINATED); if (c->client) - pa_socket_client_free(c->client); + pa_socket_client_unref(c->client); if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - if (c->pstream) - pa_pstream_free(c->pstream); + pa_pdispatch_unref(c->pdispatch); + if (c->pstream) { + pa_pstream_close(c->pstream); + pa_pstream_unref(c->pstream); + } if (c->record_streams) pa_dynarray_free(c->record_streams, NULL, NULL); @@ -140,15 +142,17 @@ void pa_context_set_state(struct pa_context *c, enum pa_context_state st) { } if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); + pa_pdispatch_unref(c->pdispatch); c->pdispatch = NULL; - if (c->pstream) - pa_pstream_free(c->pstream); + if (c->pstream) { + pa_pstream_close(c->pstream); + pa_pstream_unref(c->pstream); + } c->pstream = NULL; if (c->client) - pa_socket_client_free(c->client); + pa_socket_client_unref(c->client); c->client = NULL; } @@ -267,7 +271,7 @@ static void on_connection(struct pa_socket_client *client, struct pa_iochannel*i pa_context_ref(c); - pa_socket_client_free(client); + pa_socket_client_unref(client); c->client = NULL; if (!io) { diff --git a/polyp/polyplib-error.h b/polyp/polyplib-error.h index d7519af4..437d618e 100644 --- a/polyp/polyplib-error.h +++ b/polyp/polyplib-error.h @@ -25,11 +25,11 @@ #include #include "cdecl.h" -PA_C_DECL_BEGIN; +PA_C_DECL_BEGIN /** Return a human readable error message for the specified numeric error code */ const char* pa_strerror(uint32_t error); -PA_C_DECL_END; +PA_C_DECL_END #endif diff --git a/polyp/polyplib-subscribe.c b/polyp/polyplib-subscribe.c index a14d0b06..9536bbc6 100644 --- a/polyp/polyplib-subscribe.c +++ b/polyp/polyplib-subscribe.c @@ -24,6 +24,7 @@ #endif #include +#include #include "polyplib-subscribe.h" #include "polyplib-internal.h" @@ -65,10 +66,15 @@ struct pa_operation* pa_context_subscribe(struct pa_context *c, enum pa_subscrip t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, cb ? m : 0); + pa_tagstruct_putu32(t, m); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); return pa_operation_ref(o); } +void pa_context_set_subscribe_callback(struct pa_context *c, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { + assert(c); + c->subscribe_callback = cb; + c->subscribe_userdata = userdata; +} diff --git a/polyp/protocol-cli.c b/polyp/protocol-cli.c index 11aeabe0..266d4969 100644 --- a/polyp/protocol-cli.c +++ b/polyp/protocol-cli.c @@ -80,6 +80,6 @@ void pa_protocol_cli_free(struct pa_protocol_cli *p) { assert(p); pa_idxset_free(p->connections, free_connection, NULL); - pa_socket_server_free(p->server); + pa_socket_server_unref(p->server); pa_xfree(p); } diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index b11e1992..fb639b7f 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -1024,6 +1024,6 @@ void pa_protocol_esound_free(struct pa_protocol_esound *p) { connection_free(c); pa_idxset_free(p->connections, NULL, NULL); - pa_socket_server_free(p->server); + pa_socket_server_unref(p->server); pa_xfree(p); } diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 247851fc..0d265e33 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -306,8 +306,9 @@ static void connection_free(struct connection *c) { upload_stream_free((struct upload_stream*) o); pa_idxset_free(c->output_streams, NULL, NULL); - pa_pdispatch_free(c->pdispatch); - pa_pstream_free(c->pstream); + pa_pdispatch_unref(c->pdispatch); + pa_pstream_close(c->pstream); + pa_pstream_unref(c->pstream); pa_client_free(c->client); if (c->subscription) @@ -1330,6 +1331,6 @@ void pa_protocol_native_free(struct pa_protocol_native *p) { while ((c = pa_idxset_first(p->connections, NULL))) connection_free(c); pa_idxset_free(p->connections, NULL, NULL); - pa_socket_server_free(p->server); + pa_socket_server_unref(p->server); pa_xfree(p); } diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index a95b356c..bd0e1488 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -426,7 +426,7 @@ void pa_protocol_simple_free(struct pa_protocol_simple *p) { } if (p->server) - pa_socket_server_free(p->server); + pa_socket_server_unref(p->server); pa_xfree(p); } diff --git a/polyp/pstream.c b/polyp/pstream.c index 4f071e4a..2d147e03 100644 --- a/polyp/pstream.c +++ b/polyp/pstream.c @@ -57,13 +57,13 @@ struct item_info { }; struct pa_pstream { + int ref; + struct pa_mainloop_api *mainloop; struct pa_defer_event *defer_event; struct pa_iochannel *io; struct pa_queue *send_queue; - int in_use, shall_free; - int dead; void (*die_callback) (struct pa_pstream *p, void *userdata); void *die_callback_userdata; @@ -97,40 +97,24 @@ static void do_write(struct pa_pstream *p); static void do_read(struct pa_pstream *p); static void do_something(struct pa_pstream *p) { - assert(p && !p->shall_free); + assert(p); p->mainloop->defer_enable(p->defer_event, 0); - if (p->dead) - return; - - if (pa_iochannel_is_hungup(p->io)) { + pa_pstream_ref(p); + + if (!p->dead && pa_iochannel_is_hungup(p->io)) { p->dead = 1; if (p->die_callback) p->die_callback(p, p->die_callback_userdata); - - return; } - if (pa_iochannel_is_writable(p->io)) { - p->in_use = 1; + if (!p->dead && pa_iochannel_is_writable(p->io)) do_write(p); - p->in_use = 0; - - if (p->shall_free) { - pa_pstream_free(p); - return; - } - } - if (pa_iochannel_is_readable(p->io)) { - p->in_use = 1; + if (!p->dead && pa_iochannel_is_readable(p->io)) do_read(p); - p->in_use = 0; - if (p->shall_free) { - pa_pstream_free(p); - return; - } - } + + pa_pstream_unref(p); } static void io_callback(struct pa_iochannel*io, void *userdata) { @@ -150,7 +134,7 @@ struct pa_pstream *pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel assert(io); p = pa_xmalloc(sizeof(struct pa_pstream)); - + p->ref = 1; p->io = io; pa_iochannel_set_callback(io, io_callback, p); @@ -181,8 +165,6 @@ struct pa_pstream *pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel p->drain_callback = NULL; p->drain_userdata = NULL; - p->in_use = p->shall_free = 0; - return p; } @@ -202,16 +184,11 @@ static void item_free(void *item, void *p) { pa_xfree(i); } -void pa_pstream_free(struct pa_pstream *p) { +static void pstream_free(struct pa_pstream *p) { assert(p); - if (p->in_use) { - /* If this pstream object is used by someone else on the call stack, we have to postpone the freeing */ - p->dead = p->shall_free = 1; - return; - } - - pa_iochannel_free(p->io); + pa_pstream_close(p); + pa_queue_free(p->send_queue, item_free, NULL); if (p->write.current) @@ -223,7 +200,6 @@ void pa_pstream_free(struct pa_pstream *p) { if (p->read.packet) pa_packet_unref(p->read.packet); - p->mainloop->defer_free(p->defer_event); pa_xfree(p); } @@ -456,3 +432,36 @@ void pa_pstream_set_drain_callback(struct pa_pstream *p, void (*cb)(struct pa_ps p->drain_userdata = userdata; } +void pa_pstream_unref(struct pa_pstream*p) { + assert(p && p->ref >= 1); + + if (!(--(p->ref))) + pstream_free(p); +} + +struct pa_pstream* pa_pstream_ref(struct pa_pstream*p) { + assert(p && p->ref >= 1); + p->ref++; + return p; +} + +void pa_pstream_close(struct pa_pstream *p) { + assert(p); + + p->dead = 1; + + if (p->io) { + pa_iochannel_free(p->io); + p->io = NULL; + } + + if (p->defer_event) { + p->mainloop->defer_free(p->defer_event); + p->defer_event = NULL; + } + + p->die_callback = NULL; + p->drain_callback = NULL; + p->recieve_packet_callback = NULL; + p->recieve_memblock_callback = NULL; +} diff --git a/polyp/pstream.h b/polyp/pstream.h index 6b91aeb0..ff70a855 100644 --- a/polyp/pstream.h +++ b/polyp/pstream.h @@ -30,12 +30,11 @@ #include "mainloop-api.h" #include "memchunk.h" -/* It is safe to destroy the calling pstream object from all callbacks */ - struct pa_pstream; struct pa_pstream* pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel *io); -void pa_pstream_free(struct pa_pstream*p); +void pa_pstream_unref(struct pa_pstream*p); +struct pa_pstream* pa_pstream_ref(struct pa_pstream*p); void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet); void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk); @@ -48,4 +47,6 @@ void pa_pstream_set_die_callback(struct pa_pstream *p, void (*callback)(struct p int pa_pstream_is_pending(struct pa_pstream *p); +void pa_pstream_close(struct pa_pstream *p); + #endif diff --git a/polyp/socket-client.c b/polyp/socket-client.c index dffbfe7d..3852c1ad 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -39,6 +39,7 @@ #include "xmalloc.h" struct pa_socket_client { + int ref; struct pa_mainloop_api *mainloop; int fd; struct pa_io_event *io_event; @@ -52,6 +53,7 @@ static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) { assert(m); c = pa_xmalloc(sizeof(struct pa_socket_client)); + c->ref = 1; c->mainloop = m; c->fd = -1; c->io_event = NULL; @@ -62,38 +64,40 @@ static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) { } static void do_call(struct pa_socket_client *c) { - struct pa_iochannel *io; + struct pa_iochannel *io = NULL; int error, lerror; assert(c && c->callback); + pa_socket_client_ref(c); + lerror = sizeof(error); if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &error, &lerror) < 0) { fprintf(stderr, "getsockopt(): %s\n", strerror(errno)); - goto failed; + goto finish; } if (lerror != sizeof(error)) { fprintf(stderr, "getsocktop() returned invalid size.\n"); - goto failed; + goto finish; } if (error != 0) { fprintf(stderr, "connect(): %s\n", strerror(error)); - goto failed; + goto finish; } io = pa_iochannel_new(c->mainloop, c->fd, c->fd); assert(io); + +finish: + if (!io) + close(c->fd); c->fd = -1; + + assert(c->callback); c->callback(c, io, c->userdata); - - return; -failed: - close(c->fd); - c->fd = -1; - c->callback(c, NULL, c->userdata); - return; + pa_socket_client_unref(c); } static void connect_fixed_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) { @@ -159,7 +163,7 @@ struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, ui return c; fail: - pa_socket_client_free(c); + pa_socket_client_unref(c); return NULL; } @@ -188,7 +192,7 @@ struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, co return c; fail: - pa_socket_client_free(c); + pa_socket_client_unref(c); return NULL; } @@ -214,12 +218,12 @@ struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m return c; fail: - pa_socket_client_free(c); + pa_socket_client_unref(c); return NULL; } -void pa_socket_client_free(struct pa_socket_client *c) { +void socket_client_free(struct pa_socket_client *c) { assert(c && c->mainloop); if (c->io_event) c->mainloop->io_free(c->io_event); @@ -230,6 +234,19 @@ void pa_socket_client_free(struct pa_socket_client *c) { pa_xfree(c); } +void pa_socket_client_unref(struct pa_socket_client *c) { + assert(c && c->ref >= 1); + + if (!(--(c->ref))) + socket_client_free(c); +} + +struct pa_socket_client* pa_socket_client_ref(struct pa_socket_client *c) { + assert(c && c->ref >= 1); + c->ref++; + return c; +} + void pa_socket_client_set_callback(struct pa_socket_client *c, void (*on_connection)(struct pa_socket_client *c, struct pa_iochannel*io, void *userdata), void *userdata) { assert(c); c->callback = on_connection; diff --git a/polyp/socket-client.h b/polyp/socket-client.h index 7b9e2a72..1957355c 100644 --- a/polyp/socket-client.h +++ b/polyp/socket-client.h @@ -36,7 +36,8 @@ struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, ui struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename); struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m, const struct sockaddr *sa, size_t salen); -void pa_socket_client_free(struct pa_socket_client *c); +void pa_socket_client_unref(struct pa_socket_client *c); +struct pa_socket_client* pa_socket_client_ref(struct pa_socket_client *c); void pa_socket_client_set_callback(struct pa_socket_client *c, void (*on_connection)(struct pa_socket_client *c, struct pa_iochannel*io, void *userdata), void *userdata); diff --git a/polyp/socket-server.c b/polyp/socket-server.c index 6af2c286..f01e417c 100644 --- a/polyp/socket-server.c +++ b/polyp/socket-server.c @@ -40,6 +40,7 @@ #include "xmalloc.h" struct pa_socket_server { + int ref; int fd; char *filename; @@ -57,14 +58,16 @@ static void callback(struct pa_mainloop_api *mainloop, struct pa_io_event *e, in int nfd; assert(s && s->mainloop == mainloop && s->io_event == e && e && fd >= 0 && fd == s->fd); + pa_socket_server_ref(s); + if ((nfd = accept(fd, NULL, NULL)) < 0) { fprintf(stderr, "accept(): %s\n", strerror(errno)); - return; + goto finish; } if (!s->on_connection) { close(nfd); - return; + goto finish; } /* There should be a check for socket type here */ @@ -76,6 +79,9 @@ static void callback(struct pa_mainloop_api *mainloop, struct pa_io_event *e, in io = pa_iochannel_new(s->mainloop, nfd, nfd); assert(io); s->on_connection(s, io, s->userdata); + +finish: + pa_socket_server_unref(s); } struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd) { @@ -83,6 +89,7 @@ struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd) assert(m && fd >= 0); s = pa_xmalloc(sizeof(struct pa_socket_server)); + s->ref = 1; s->fd = fd; s->filename = NULL; s->on_connection = NULL; @@ -97,6 +104,12 @@ struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd) return s; } +struct pa_socket_server* pa_socket_server_ref(struct pa_socket_server *s) { + assert(s && s->ref >= 1); + s->ref++; + return s; +} + struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename) { int fd = -1; struct sockaddr_un sa; @@ -184,7 +197,7 @@ fail: return NULL; } -void pa_socket_server_free(struct pa_socket_server*s) { +static void socket_server_free(struct pa_socket_server*s) { assert(s); close(s->fd); @@ -197,8 +210,15 @@ void pa_socket_server_free(struct pa_socket_server*s) { pa_xfree(s); } +void pa_socket_server_unref(struct pa_socket_server *s) { + assert(s && s->ref >= 1); + + if (!(--(s->ref))) + socket_server_free(s); +} + void pa_socket_server_set_callback(struct pa_socket_server*s, void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata), void *userdata) { - assert(s); + assert(s && s->ref >= 1); s->on_connection = on_connection; s->userdata = userdata; diff --git a/polyp/socket-server.h b/polyp/socket-server.h index 6661a66e..c9d9193d 100644 --- a/polyp/socket-server.h +++ b/polyp/socket-server.h @@ -34,7 +34,8 @@ struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd) struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename); struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port); -void pa_socket_server_free(struct pa_socket_server*s); +void pa_socket_server_unref(struct pa_socket_server*s); +struct pa_socket_server* pa_socket_server_ref(struct pa_socket_server *s); void pa_socket_server_set_callback(struct pa_socket_server*s, void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata), void *userdata); -- cgit From efc3491f1f1ca42cd776f96ccfb006c53717d2e8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 15 Aug 2004 13:15:51 +0000 Subject: add support for volume manipulation git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@125 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/cli-command.c | 2 +- polyp/pdispatch.c | 9 +++++---- polyp/protocol-native.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ polyp/sample.h | 5 +++++ polyp/sink-input.c | 9 +++++++++ polyp/sink-input.h | 2 ++ polyp/sink.c | 3 ++- 7 files changed, 70 insertions(+), 6 deletions(-) diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 1d454f2a..aa61b10e 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -338,7 +338,7 @@ static int pa_cli_command_sink_input_volume(struct pa_core *c, struct pa_tokeniz return -1; } - si->volume = (uint32_t) volume; + pa_sink_input_set_volume(si, (uint32_t) volume); return 0; } diff --git a/polyp/pdispatch.c b/polyp/pdispatch.c index 9ed91fc5..c46d4f77 100644 --- a/polyp/pdispatch.c +++ b/polyp/pdispatch.c @@ -175,13 +175,14 @@ int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *use if (r) run_action(pd, r, command, ts); - } else if (pd->command_table && command < pd->n_commands) { + } else if (pd->command_table && (command < pd->n_commands) && pd->command_table[command].proc) { const struct pa_pdispatch_command *c = pd->command_table+command; - if (c->proc) - c->proc(pd, command, tag, ts, userdata); - } else + c->proc(pd, command, tag, ts, userdata); + } else { + fprintf(stderr, "Recieved unsupported command %u\n", command); goto finish; + } ret = 0; diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 0d265e33..7df39fe3 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -134,6 +134,7 @@ static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_subscribe(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_set_volume(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = { NULL }, @@ -167,6 +168,7 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_GET_CLIENT_INFO_LIST] = { command_get_info_list }, [PA_COMMAND_GET_SERVER_INFO] = { command_get_server_info }, [PA_COMMAND_SUBSCRIBE] = { command_subscribe }, + [PA_COMMAND_SET_SINK_VOLUME] = { command_set_volume }, }; /* structure management */ @@ -1164,9 +1166,53 @@ static void command_subscribe(struct pa_pdispatch *pd, uint32_t command, uint32_ c->subscription = NULL; pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_set_volume(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t index, volume; + struct pa_sink *sink = NULL; + struct pa_sink_input *si = NULL; + const char *name = NULL; + assert(c && t); + + if (pa_tagstruct_getu32(t, &index) < 0 || + (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) || + pa_tagstruct_getu32(t, &volume) || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (command == PA_COMMAND_SET_SINK_VOLUME) { + if (index != (uint32_t) -1) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, index); + else + sink = pa_namereg_get(c->protocol->core, *name ? name : NULL, PA_NAMEREG_SINK, 1); + } else { + assert(command == PA_COMMAND_SET_SINK_INPUT_VOLUME); + si = pa_idxset_get_by_index(c->protocol->core->sinks, index); + } + + if (!si && !sink) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + if (sink) + pa_sink_set_volume(sink, volume); + else if (si) + pa_sink_input_set_volume(si, volume); + + pa_pstream_send_simple_ack(c->pstream, tag); } + /*** pstream callbacks ***/ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { diff --git a/polyp/sample.h b/polyp/sample.h index a7cde093..e397a1df 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -65,8 +65,13 @@ int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_s #define PA_SAMPLE_SNPRINT_MAX_LENGTH 32 void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec); +/** Normal volume (100%) */ #define PA_VOLUME_NORM (0x100) + +/** Muted volume (0%) */ #define PA_VOLUME_MUTE (0) + +/** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. */ uint32_t pa_volume_multiply(uint32_t a, uint32_t b); PA_C_DECL_END diff --git a/polyp/sink-input.c b/polyp/sink-input.c index dd7469e0..cf255a07 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -168,3 +168,12 @@ void pa_sink_input_drop(struct pa_sink_input *i, size_t length) { i->resampled_chunk.index = i->resampled_chunk.length = 0; } } + +void pa_sink_input_set_volume(struct pa_sink_input *i, uint32_t volume) { + assert(i); + + if (i->volume != volume) { + i->volume = volume; + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); + } +} diff --git a/polyp/sink-input.h b/polyp/sink-input.h index 63dce71d..b21dbf4d 100644 --- a/polyp/sink-input.h +++ b/polyp/sink-input.h @@ -64,4 +64,6 @@ uint32_t pa_sink_input_get_latency(struct pa_sink_input *i); int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk); void pa_sink_input_drop(struct pa_sink_input *i, size_t length); +void pa_sink_input_set_volume(struct pa_sink_input *i, uint32_t volume); + #endif diff --git a/polyp/sink.c b/polyp/sink.c index d9a3ae86..b8617ae1 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -285,8 +285,9 @@ void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m) { void pa_sink_set_volume(struct pa_sink *sink, uint32_t volume) { assert(sink); + if (sink->volume != volume) { - pa_subscription_post(sink->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, sink->index); sink->volume = volume; + pa_subscription_post(sink->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, sink->index); } } -- cgit From 369a908db761e7f59481000a68bffb476aa6e056 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 16 Aug 2004 19:55:02 +0000 Subject: add sink input/source output support to the native protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@126 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/native-common.h | 3 + polyp/polyplib-introspect.c | 139 +++++++++++++++++++++++++++++++++++++++++++- polyp/polyplib-introspect.h | 4 +- polyp/protocol-native.c | 70 ++++++++++++++++++---- 4 files changed, 203 insertions(+), 13 deletions(-) diff --git a/polyp/native-common.h b/polyp/native-common.h index 0fc44165..debb9bba 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -63,8 +63,11 @@ enum { PA_COMMAND_GET_CLIENT_INFO, PA_COMMAND_GET_CLIENT_INFO_LIST, PA_COMMAND_GET_SINK_INPUT_INFO, + PA_COMMAND_GET_SINK_INPUT_INFO_LIST, PA_COMMAND_GET_SOURCE_OUTPUT_INFO, + PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, PA_COMMAND_GET_SAMPLE_INFO, + PA_COMMAND_GET_SAMPLE_INFO_LIST, PA_COMMAND_SUBSCRIBE, PA_COMMAND_SUBSCRIBE_EVENT, diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index 345a9cd5..aa70a111 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -297,7 +297,6 @@ struct pa_operation* pa_context_get_client_info(struct pa_context *c, uint32_t i pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, o); @@ -375,6 +374,144 @@ struct pa_operation* pa_context_get_module_info_list(struct pa_context *c, void return pa_context_send_simple_command(c, PA_COMMAND_GET_MODULE_INFO_LIST, context_get_module_info_callback, cb, userdata); } +/*** Sink input info ***/ + +static void context_get_sink_input_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + struct pa_sink_input_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.client) < 0 || + pa_tagstruct_getu32(t, &i.sink) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.volume) < 0 || + pa_tagstruct_getu32(t, &i.latency) < 0) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_sink_input_info*i, int eof, void *userdata) = o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_sink_input_info*i, int eof, void *userdata) = o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +struct pa_operation* pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + struct pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INPUT_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_input_info_callback, o); + + return pa_operation_ref(o); +} + +struct pa_operation* pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INPUT_INFO_LIST, context_get_sink_input_info_callback, cb, userdata); +} + +/*** Source output info ***/ + +static void context_get_source_output_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + struct pa_source_output_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.client) < 0 || + pa_tagstruct_getu32(t, &i.source) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_source_output_info*i, int eof, void *userdata) = o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_source_output_info*i, int eof, void *userdata) = o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +struct pa_operation* pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + struct pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_OUTPUT_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_output_info_callback, o); + + return pa_operation_ref(o); +} + +struct pa_operation* pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, context_get_source_output_info_callback, cb, userdata); +} + /*** Volume manipulation ***/ struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index bca752e2..e83ba73b 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -93,7 +93,7 @@ struct pa_sink_input_info { uint32_t index; const char *name; uint32_t owner_module; - uint32_t owner_client; + uint32_t client; uint32_t sink; struct pa_sample_spec sample_spec; uint32_t volume; @@ -107,7 +107,7 @@ struct pa_source_output_info { uint32_t index; const char *name; uint32_t owner_module; - uint32_t owner_client; + uint32_t client; uint32_t source; struct pa_sample_spec sample_spec; }; diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 7df39fe3..35c78f61 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -162,13 +162,18 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_GET_SOURCE_INFO] = { command_get_info }, [PA_COMMAND_GET_CLIENT_INFO] = { command_get_info }, [PA_COMMAND_GET_MODULE_INFO] = { command_get_info }, + [PA_COMMAND_GET_SINK_INPUT_INFO] = { command_get_info }, + [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = { command_get_info }, [PA_COMMAND_GET_SINK_INFO_LIST] = { command_get_info_list }, [PA_COMMAND_GET_SOURCE_INFO_LIST] = { command_get_info_list }, [PA_COMMAND_GET_MODULE_INFO_LIST] = { command_get_info_list }, [PA_COMMAND_GET_CLIENT_INFO_LIST] = { command_get_info_list }, + [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = { command_get_info_list }, + [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = { command_get_info_list }, [PA_COMMAND_GET_SERVER_INFO] = { command_get_server_info }, [PA_COMMAND_SUBSCRIBE] = { command_subscribe }, [PA_COMMAND_SET_SINK_VOLUME] = { command_set_volume }, + [PA_COMMAND_SET_SINK_INPUT_VOLUME] = { command_set_volume }, }; /* structure management */ @@ -988,6 +993,28 @@ static void module_fill_tagstruct(struct pa_tagstruct *t, struct pa_module *modu pa_tagstruct_putu32(t, module->auto_unload); } +static void sink_input_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink_input *s) { + assert(t && s); + pa_tagstruct_putu32(t, s->index); + pa_tagstruct_puts(t, s->name ? s->name : ""); + pa_tagstruct_putu32(t, s->owner ? s->owner->index : (uint32_t) -1); + pa_tagstruct_putu32(t, s->client ? s->client->index : (uint32_t) -1); + pa_tagstruct_putu32(t, s->sink->index); + pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_putu32(t, s->volume); + pa_tagstruct_putu32(t, pa_sink_input_get_latency(s)); +} + +static void source_output_fill_tagstruct(struct pa_tagstruct *t, struct pa_source_output *s) { + assert(t && s); + pa_tagstruct_putu32(t, s->index); + pa_tagstruct_puts(t, s->name ? s->name : ""); + pa_tagstruct_putu32(t, s->owner ? s->owner->index : (uint32_t) -1); + pa_tagstruct_putu32(t, s->client ? s->client->index : (uint32_t) -1); + pa_tagstruct_putu32(t, s->source->index); + pa_tagstruct_put_sample_spec(t, &s->sample_spec); +} + static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; uint32_t index; @@ -995,12 +1022,19 @@ static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t struct pa_source *source = NULL; struct pa_client *client = NULL; struct pa_module *module = NULL; + struct pa_sink_input *si = NULL; + struct pa_source_output *so = NULL; const char *name; struct pa_tagstruct *reply; assert(c && t); + if (pa_tagstruct_getu32(t, &index) < 0 || - pa_tagstruct_gets(t, &name) < 0 || + (command != PA_COMMAND_GET_CLIENT_INFO && + command != PA_COMMAND_GET_MODULE_INFO && + command != PA_COMMAND_GET_SINK_INPUT_INFO && + command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO && + pa_tagstruct_gets(t, &name) < 0) || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1023,12 +1057,16 @@ static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t source = pa_namereg_get(c->protocol->core, *name ? name : NULL, PA_NAMEREG_SOURCE, 1); } else if (command == PA_COMMAND_GET_CLIENT_INFO) client = pa_idxset_get_by_index(c->protocol->core->clients, index); - else { - assert(command == PA_COMMAND_GET_MODULE_INFO); + else if (command == PA_COMMAND_GET_MODULE_INFO) module = pa_idxset_get_by_index(c->protocol->core->modules, index); + else if (command == PA_COMMAND_GET_SINK_INPUT_INFO) + si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, index); + else { + assert(command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO); + so = pa_idxset_get_by_index(c->protocol->core->source_outputs, index); } - - if (!sink && !source && !client && !module) { + + if (!sink && !source && !client && !module && !si && !so) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -1043,8 +1081,12 @@ static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t source_fill_tagstruct(reply, source); else if (client) client_fill_tagstruct(reply, client); - else + else if (module) module_fill_tagstruct(reply, module); + else if (si) + sink_input_fill_tagstruct(reply, si); + else + source_output_fill_tagstruct(reply, so); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -1077,9 +1119,13 @@ static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uin i = c->protocol->core->sources; else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST) i = c->protocol->core->clients; - else { - assert(command == PA_COMMAND_GET_MODULE_INFO_LIST); + else if (command == PA_COMMAND_GET_MODULE_INFO_LIST) i = c->protocol->core->modules; + else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) + i = c->protocol->core->sink_inputs; + else { + assert(command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST); + i = c->protocol->core->source_outputs; } for (p = pa_idxset_first(i, &index); p; p = pa_idxset_next(i, &index)) { @@ -1089,9 +1135,13 @@ static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uin source_fill_tagstruct(reply, p); else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST) client_fill_tagstruct(reply, p); - else { - assert(command == PA_COMMAND_GET_MODULE_INFO_LIST); + else if (command == PA_COMMAND_GET_MODULE_INFO_LIST) module_fill_tagstruct(reply, p); + else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) + sink_input_fill_tagstruct(reply, p); + else { + assert(command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST); + source_output_fill_tagstruct(reply, p); } } -- cgit From 126fedea31b346c0c16ce2e3211768036675e46f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 16 Aug 2004 20:16:37 +0000 Subject: fix sink iunput and source output stuff git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@127 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/protocol-native.c | 2 +- polyp/sink-input.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 35c78f61..1fafc984 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -1246,7 +1246,7 @@ static void command_set_volume(struct pa_pdispatch *pd, uint32_t command, uint32 sink = pa_namereg_get(c->protocol->core, *name ? name : NULL, PA_NAMEREG_SINK, 1); } else { assert(command == PA_COMMAND_SET_SINK_INPUT_VOLUME); - si = pa_idxset_get_by_index(c->protocol->core->sinks, index); + si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, index); } if (!si && !sink) { diff --git a/polyp/sink-input.c b/polyp/sink-input.c index cf255a07..99ff8fe6 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -170,7 +170,7 @@ void pa_sink_input_drop(struct pa_sink_input *i, size_t length) { } void pa_sink_input_set_volume(struct pa_sink_input *i, uint32_t volume) { - assert(i); + assert(i && i->sink && i->sink->core); if (i->volume != volume) { i->volume = volume; -- cgit From e4be61675ea192391d2e9d586275b618544fa664 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 17 Aug 2004 12:49:23 +0000 Subject: rename clitext to cli-text git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@128 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/cli-text.c | 266 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ polyp/cli-text.h | 37 ++++++++ polyp/clitext.c | 266 ------------------------------------------------------- polyp/clitext.h | 37 -------- 4 files changed, 303 insertions(+), 303 deletions(-) create mode 100644 polyp/cli-text.c create mode 100644 polyp/cli-text.h delete mode 100644 polyp/clitext.c delete mode 100644 polyp/clitext.h diff --git a/polyp/cli-text.c b/polyp/cli-text.c new file mode 100644 index 00000000..a530238f --- /dev/null +++ b/polyp/cli-text.c @@ -0,0 +1,266 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "clitext.h" +#include "module.h" +#include "client.h" +#include "sink.h" +#include "source.h" +#include "sink-input.h" +#include "source-output.h" +#include "strbuf.h" +#include "sample-util.h" +#include "scache.h" +#include "autoload.h" + +char *pa_module_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_module *m; + uint32_t index = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_ncontents(c->modules)); + + for (m = pa_idxset_first(c->modules, &index); m; m = pa_idxset_next(c->modules, &index)) + pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\targument: <%s>\n\tused: %i\n\tauto unload: %s\n", m->index, m->name, m->argument, m->n_used, m->auto_unload ? "yes" : "no"); + + return pa_strbuf_tostring_free(s); +} + +char *pa_client_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_client *client; + uint32_t index = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u client(s).\n", pa_idxset_ncontents(c->clients)); + + for (client = pa_idxset_first(c->clients, &index); client; client = pa_idxset_next(c->clients, &index)) { + pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\tprotocol_name: <%s>\n", client->index, client->name, client->protocol_name); + + if (client->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", client->owner->index); + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_sink_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_sink *sink; + uint32_t index = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_ncontents(c->sinks)); + + for (sink = pa_idxset_first(c->sinks, &index); sink; sink = pa_idxset_next(c->sinks, &index)) { + char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + pa_sample_snprint(ss, sizeof(ss), &sink->sample_spec); + assert(sink->monitor_source); + pa_strbuf_printf( + s, + " %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", + c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ', + sink->index, sink->name, + (unsigned) sink->volume, + pa_sink_get_latency(sink), + sink->monitor_source->index, + ss); + + if (sink->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", sink->owner->index); + if (sink->description) + pa_strbuf_printf(s, "\tdescription: <%s>\n", sink->description); + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_source_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_source *source; + uint32_t index = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_ncontents(c->sources)); + + for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) { + char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + pa_sample_snprint(ss, sizeof(ss), &source->sample_spec); + pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\tsample_spec: <%s>\n", + c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ', + source->index, + source->name, + ss); + + if (source->monitor_of) + pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index); + if (source->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", source->owner->index); + if (source->description) + pa_strbuf_printf(s, "\tdescription: <%s>\n", source->description); + } + + return pa_strbuf_tostring_free(s); +} + + +char *pa_source_output_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_source_output *o; + uint32_t index = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_ncontents(c->source_outputs)); + + for (o = pa_idxset_first(c->source_outputs, &index); o; o = pa_idxset_next(c->source_outputs, &index)) { + char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + pa_sample_snprint(ss, sizeof(ss), &o->sample_spec); + assert(o->source); + pa_strbuf_printf( + s, " index: %u\n\tname: <%s>\n\tsource: <%u>\n\tsample_spec: <%s>\n", + o->index, + o->name, + o->source->index, + ss); + if (o->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", o->owner->index); + if (o->client) + pa_strbuf_printf(s, "\tclient: <%u>\n", o->client->index); + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_sink_input_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + struct pa_sink_input *i; + uint32_t index = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_ncontents(c->sink_inputs)); + + for (i = pa_idxset_first(c->sink_inputs, &index); i; i = pa_idxset_next(c->sink_inputs, &index)) { + char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + pa_sample_snprint(ss, sizeof(ss), &i->sample_spec); + assert(i->sink); + pa_strbuf_printf( + s, " index: %u\n\tname: <%s>\n\tsink: <%u>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tsample_spec: <%s>\n", + i->index, + i->name, + i->sink->index, + (unsigned) i->volume, + pa_sink_input_get_latency(i), + ss); + + if (i->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", i->owner->index); + if (i->client) + pa_strbuf_printf(s, "\tclient: <%u>\n", i->client->index); + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_scache_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u cache entries available.\n", c->scache_hashmap ? pa_hashmap_ncontents(c->scache_hashmap) : 0); + + if (c->scache_hashmap) { + struct pa_scache_entry *e; + void *state = NULL; + + while ((e = pa_hashmap_iterate(c->scache_hashmap, &state))) { + double l; + char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + pa_sample_snprint(ss, sizeof(ss), &e->sample_spec); + + l = (double) e->memchunk.length / pa_bytes_per_second(&e->sample_spec); + + pa_strbuf_printf( + s, " name: <%s>\n\tindex: <%i>\n\tsample_spec: <%s>\n\tlength: <%u>\n\tduration: <%0.1fs>\n\tvolume: <0x%04x>\n", + e->name, + e->index, + ss, + e->memchunk.length, + l, + e->volume); + } + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_autoload_list_to_string(struct pa_core *c) { + struct pa_strbuf *s; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u autoload entries available.\n", c->autoload_hashmap ? pa_hashmap_ncontents(c->autoload_hashmap) : 0); + + if (c->autoload_hashmap) { + struct pa_autoload_entry *e; + void *state = NULL; + + while ((e = pa_hashmap_iterate(c->autoload_hashmap, &state))) { + pa_strbuf_printf( + s, " name: <%s>\n\ttype: <%s>\n\tmodule_name: <%s>\n\targuments: <%s>\n", + e->name, + e->type == PA_NAMEREG_SOURCE ? "source" : "sink", + e->module, + e->argument); + } + } + + return pa_strbuf_tostring_free(s); +} diff --git a/polyp/cli-text.h b/polyp/cli-text.h new file mode 100644 index 00000000..121f2a5d --- /dev/null +++ b/polyp/cli-text.h @@ -0,0 +1,37 @@ +#ifndef fooclitexthfoo +#define fooclitexthfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" + +char *pa_sink_input_list_to_string(struct pa_core *c); +char *pa_source_output_list_to_string(struct pa_core *c); +char *pa_sink_list_to_string(struct pa_core *core); +char *pa_source_list_to_string(struct pa_core *c); +char *pa_client_list_to_string(struct pa_core *c); +char *pa_module_list_to_string(struct pa_core *c); +char *pa_scache_list_to_string(struct pa_core *c); +char *pa_autoload_list_to_string(struct pa_core *c); + +#endif + diff --git a/polyp/clitext.c b/polyp/clitext.c deleted file mode 100644 index a530238f..00000000 --- a/polyp/clitext.c +++ /dev/null @@ -1,266 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "clitext.h" -#include "module.h" -#include "client.h" -#include "sink.h" -#include "source.h" -#include "sink-input.h" -#include "source-output.h" -#include "strbuf.h" -#include "sample-util.h" -#include "scache.h" -#include "autoload.h" - -char *pa_module_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_module *m; - uint32_t index = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_ncontents(c->modules)); - - for (m = pa_idxset_first(c->modules, &index); m; m = pa_idxset_next(c->modules, &index)) - pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\targument: <%s>\n\tused: %i\n\tauto unload: %s\n", m->index, m->name, m->argument, m->n_used, m->auto_unload ? "yes" : "no"); - - return pa_strbuf_tostring_free(s); -} - -char *pa_client_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_client *client; - uint32_t index = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u client(s).\n", pa_idxset_ncontents(c->clients)); - - for (client = pa_idxset_first(c->clients, &index); client; client = pa_idxset_next(c->clients, &index)) { - pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\tprotocol_name: <%s>\n", client->index, client->name, client->protocol_name); - - if (client->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", client->owner->index); - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_sink_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_sink *sink; - uint32_t index = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_ncontents(c->sinks)); - - for (sink = pa_idxset_first(c->sinks, &index); sink; sink = pa_idxset_next(c->sinks, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - pa_sample_snprint(ss, sizeof(ss), &sink->sample_spec); - assert(sink->monitor_source); - pa_strbuf_printf( - s, - " %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", - c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ', - sink->index, sink->name, - (unsigned) sink->volume, - pa_sink_get_latency(sink), - sink->monitor_source->index, - ss); - - if (sink->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", sink->owner->index); - if (sink->description) - pa_strbuf_printf(s, "\tdescription: <%s>\n", sink->description); - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_source_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_source *source; - uint32_t index = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_ncontents(c->sources)); - - for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - pa_sample_snprint(ss, sizeof(ss), &source->sample_spec); - pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\tsample_spec: <%s>\n", - c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ', - source->index, - source->name, - ss); - - if (source->monitor_of) - pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index); - if (source->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", source->owner->index); - if (source->description) - pa_strbuf_printf(s, "\tdescription: <%s>\n", source->description); - } - - return pa_strbuf_tostring_free(s); -} - - -char *pa_source_output_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_source_output *o; - uint32_t index = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_ncontents(c->source_outputs)); - - for (o = pa_idxset_first(c->source_outputs, &index); o; o = pa_idxset_next(c->source_outputs, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - pa_sample_snprint(ss, sizeof(ss), &o->sample_spec); - assert(o->source); - pa_strbuf_printf( - s, " index: %u\n\tname: <%s>\n\tsource: <%u>\n\tsample_spec: <%s>\n", - o->index, - o->name, - o->source->index, - ss); - if (o->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", o->owner->index); - if (o->client) - pa_strbuf_printf(s, "\tclient: <%u>\n", o->client->index); - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_sink_input_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_sink_input *i; - uint32_t index = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_ncontents(c->sink_inputs)); - - for (i = pa_idxset_first(c->sink_inputs, &index); i; i = pa_idxset_next(c->sink_inputs, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - pa_sample_snprint(ss, sizeof(ss), &i->sample_spec); - assert(i->sink); - pa_strbuf_printf( - s, " index: %u\n\tname: <%s>\n\tsink: <%u>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tsample_spec: <%s>\n", - i->index, - i->name, - i->sink->index, - (unsigned) i->volume, - pa_sink_input_get_latency(i), - ss); - - if (i->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", i->owner->index); - if (i->client) - pa_strbuf_printf(s, "\tclient: <%u>\n", i->client->index); - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_scache_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u cache entries available.\n", c->scache_hashmap ? pa_hashmap_ncontents(c->scache_hashmap) : 0); - - if (c->scache_hashmap) { - struct pa_scache_entry *e; - void *state = NULL; - - while ((e = pa_hashmap_iterate(c->scache_hashmap, &state))) { - double l; - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - pa_sample_snprint(ss, sizeof(ss), &e->sample_spec); - - l = (double) e->memchunk.length / pa_bytes_per_second(&e->sample_spec); - - pa_strbuf_printf( - s, " name: <%s>\n\tindex: <%i>\n\tsample_spec: <%s>\n\tlength: <%u>\n\tduration: <%0.1fs>\n\tvolume: <0x%04x>\n", - e->name, - e->index, - ss, - e->memchunk.length, - l, - e->volume); - } - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_autoload_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u autoload entries available.\n", c->autoload_hashmap ? pa_hashmap_ncontents(c->autoload_hashmap) : 0); - - if (c->autoload_hashmap) { - struct pa_autoload_entry *e; - void *state = NULL; - - while ((e = pa_hashmap_iterate(c->autoload_hashmap, &state))) { - pa_strbuf_printf( - s, " name: <%s>\n\ttype: <%s>\n\tmodule_name: <%s>\n\targuments: <%s>\n", - e->name, - e->type == PA_NAMEREG_SOURCE ? "source" : "sink", - e->module, - e->argument); - } - } - - return pa_strbuf_tostring_free(s); -} diff --git a/polyp/clitext.h b/polyp/clitext.h deleted file mode 100644 index 121f2a5d..00000000 --- a/polyp/clitext.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef fooclitexthfoo -#define fooclitexthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "core.h" - -char *pa_sink_input_list_to_string(struct pa_core *c); -char *pa_source_output_list_to_string(struct pa_core *c); -char *pa_sink_list_to_string(struct pa_core *core); -char *pa_source_list_to_string(struct pa_core *c); -char *pa_client_list_to_string(struct pa_core *c); -char *pa_module_list_to_string(struct pa_core *c); -char *pa_scache_list_to_string(struct pa_core *c); -char *pa_autoload_list_to_string(struct pa_core *c); - -#endif - -- cgit From a0d54ddb8bf9c03d1916140730260abb6e3f053b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 17 Aug 2004 13:00:01 +0000 Subject: make clitext to cli-text renaming complete git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@129 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 4 ++-- polyp/cli-command.c | 2 +- polyp/cli-text.c | 2 +- polyp/cli.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index f2d61f7c..100cd4ff 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -116,7 +116,7 @@ polypaudio_SOURCES = idxset.c idxset.h \ modargs.c modargs.h \ cmdline.c cmdline.h \ cli-command.c cli-command.h \ - clitext.c clitext.h \ + cli-text.c cli-text.h \ tokenizer.c tokenizer.h \ dynarray.c dynarray.h \ scache.c scache.h \ @@ -406,7 +406,7 @@ libpolypcore_la_SOURCES = idxset.c idxset.h \ sioman.c sioman.h \ modargs.c modargs.h \ cli-command.c cli-command.h \ - clitext.c clitext.h \ + cli-text.c cli-text.h \ tokenizer.c tokenizer.h \ dynarray.c dynarray.h diff --git a/polyp/cli-command.c b/polyp/cli-command.c index aa61b10e..8459d71b 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -39,7 +39,7 @@ #include "tokenizer.h" #include "strbuf.h" #include "namereg.h" -#include "clitext.h" +#include "cli-text.h" #include "scache.h" #include "sample-util.h" #include "sound-file.h" diff --git a/polyp/cli-text.c b/polyp/cli-text.c index a530238f..558b53ca 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -26,7 +26,7 @@ #include #include -#include "clitext.h" +#include "cli-text.h" #include "module.h" #include "client.h" #include "sink.h" diff --git a/polyp/cli.c b/polyp/cli.c index f0ad4830..6fd2c238 100644 --- a/polyp/cli.c +++ b/polyp/cli.c @@ -39,7 +39,7 @@ #include "tokenizer.h" #include "strbuf.h" #include "namereg.h" -#include "clitext.h" +#include "cli-text.h" #include "cli-command.h" #include "xmalloc.h" -- cgit From aff43ddabb87903823805ec49533cb99fb1aa771 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 17 Aug 2004 13:00:45 +0000 Subject: update todo file git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@130 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 5 ----- 1 file changed, 5 deletions(-) diff --git a/doc/todo b/doc/todo index 943fab0d..db89e612 100644 --- a/doc/todo +++ b/doc/todo @@ -11,18 +11,13 @@ - several files: copyright and config.h - enable searchdir - autoscan -- rename clitext.[ch] to cli-text.[ch] *** 0.3 *** -- client-ui - move the global memblock statistics variables to the core - unix socket directories include user name - native library/protocol: - get server layout - subscription module load/unload kill client/... - set volume - more complete pactl ** later *** -- cgit From bee750bbb3d9d7a64fa7f344ab42cdcfcb280a7e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 17 Aug 2004 13:28:52 +0000 Subject: create native-common-internal.h git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@131 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/mainloop-api.h | 3 +- polyp/mainloop-signal.h | 18 ++++++ polyp/mainloop.h | 22 +++++++ polyp/native-common-internal.h | 133 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 polyp/native-common-internal.h diff --git a/polyp/mainloop-api.h b/polyp/mainloop-api.h index c1f40eae..3d5ad24a 100644 --- a/polyp/mainloop-api.h +++ b/polyp/mainloop-api.h @@ -38,9 +38,10 @@ * \li A wrapper around the GLIB main loop. Use this to embed polypaudio into your GLIB/GTK+/GNOME programs (See \ref glib-mainloop.h) * * The structure pa_mainloop_api is used as vtable for the main loop abstraction. + * + * This mainloop abstraction layer has no direct support for UNIX signals. Generic, mainloop implementation agnostic support is available throught \ref mainloop-signal.h. * */ - PA_C_DECL_BEGIN /** A bitmask for IO events */ diff --git a/polyp/mainloop-signal.h b/polyp/mainloop-signal.h index 4dd6c552..0ff20827 100644 --- a/polyp/mainloop-signal.h +++ b/polyp/mainloop-signal.h @@ -27,14 +27,32 @@ PA_C_DECL_BEGIN +/** \file + * UNIX signal support for main loops. In contrast to other + * main loop event sources such as timer and IO events, UNIX signal + * support requires modification of the global process + * environment. Due to this the generic main loop abstraction layer as + * defined in \ref mainloop-api.h doesn't have direct support for UNIX + * signals. However, you may hook signal support into an abstract main loop via the routines defined herein. + */ + +/** Initialize the UNIX signal subsystem and bind it to the specified main loop */ int pa_signal_init(struct pa_mainloop_api *api); + +/** Cleanup the signal subsystem */ void pa_signal_done(void); +/** \struct pa_signal_event + * A UNIX signal event source object */ struct pa_signal_event; +/** Create a new UNIX signal event source object */ struct pa_signal_event* pa_signal_new(int signal, void (*callback) (struct pa_mainloop_api *api, struct pa_signal_event*e, int signal, void *userdata), void *userdata); + +/** Free a UNIX signal event source object */ void pa_signal_free(struct pa_signal_event *e); +/** Set a function that is called when the signal event source is destroyed. Use this to free the userdata argument if required */ void pa_signal_set_destroy(struct pa_signal_event *e, void (*callback) (struct pa_mainloop_api *api, struct pa_signal_event*e, void *userdata)); PA_C_DECL_END diff --git a/polyp/mainloop.h b/polyp/mainloop.h index 4a4c85df..b51f4226 100644 --- a/polyp/mainloop.h +++ b/polyp/mainloop.h @@ -27,14 +27,36 @@ PA_C_DECL_BEGIN +/** \file + * + * A minimal main loop implementation based on the C library's poll() + * function. Using the routines defined herein you may create a simple + * main loop supporting the generic main loop abstraction layer as + * defined in \ref mainloop-api.h. This implementation is thread safe + * as long as you access the main loop object from a single thread only.*/ + +/** \struct pa_mainloop + * A main loop object + */ struct pa_mainloop; +/** Allocate a new main loop object */ struct pa_mainloop *pa_mainloop_new(void); + +/** Free a main loop object */ void pa_mainloop_free(struct pa_mainloop* m); +/** Run a single iteration of the main loop. Returns a negative value +on error or exit request. If block is nonzero, block for events if +none are queued. Optionally return the return value as specified with +the main loop's quit() routine in the integer variable retval points +to */ int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval); + +/** Run unlimited iterations of the main loop object until the main loop's quit() routine is called. */ int pa_mainloop_run(struct pa_mainloop *m, int *retval); +/** Return the abstract main loop abstraction layer vtable for this main loop. This calls pa_mainloop_iterate() iteratively.*/ struct pa_mainloop_api* pa_mainloop_get_api(struct pa_mainloop*m); PA_C_DECL_END diff --git a/polyp/native-common-internal.h b/polyp/native-common-internal.h new file mode 100644 index 00000000..debb9bba --- /dev/null +++ b/polyp/native-common-internal.h @@ -0,0 +1,133 @@ +#ifndef foonativecommonhfoo +#define foonativecommonhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "cdecl.h" + +PA_C_DECL_BEGIN + +enum { + PA_COMMAND_ERROR, + PA_COMMAND_TIMEOUT, /* pseudo command */ + PA_COMMAND_REPLY, + PA_COMMAND_CREATE_PLAYBACK_STREAM, + PA_COMMAND_DELETE_PLAYBACK_STREAM, + PA_COMMAND_CREATE_RECORD_STREAM, + PA_COMMAND_DELETE_RECORD_STREAM, + PA_COMMAND_EXIT, + PA_COMMAND_REQUEST, + PA_COMMAND_AUTH, + PA_COMMAND_SET_NAME, + PA_COMMAND_LOOKUP_SINK, + PA_COMMAND_LOOKUP_SOURCE, + PA_COMMAND_DRAIN_PLAYBACK_STREAM, + PA_COMMAND_PLAYBACK_STREAM_KILLED, + PA_COMMAND_RECORD_STREAM_KILLED, + PA_COMMAND_STAT, + PA_COMMAND_GET_PLAYBACK_LATENCY, + + PA_COMMAND_CREATE_UPLOAD_STREAM, + PA_COMMAND_DELETE_UPLOAD_STREAM, + PA_COMMAND_FINISH_UPLOAD_STREAM, + PA_COMMAND_PLAY_SAMPLE, + PA_COMMAND_REMOVE_SAMPLE, + + PA_COMMAND_GET_SERVER_INFO, + + PA_COMMAND_GET_SINK_INFO, + PA_COMMAND_GET_SINK_INFO_LIST, + PA_COMMAND_GET_SOURCE_INFO, + PA_COMMAND_GET_SOURCE_INFO_LIST, + PA_COMMAND_GET_MODULE_INFO, + PA_COMMAND_GET_MODULE_INFO_LIST, + PA_COMMAND_GET_CLIENT_INFO, + PA_COMMAND_GET_CLIENT_INFO_LIST, + PA_COMMAND_GET_SINK_INPUT_INFO, + PA_COMMAND_GET_SINK_INPUT_INFO_LIST, + PA_COMMAND_GET_SOURCE_OUTPUT_INFO, + PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, + PA_COMMAND_GET_SAMPLE_INFO, + PA_COMMAND_GET_SAMPLE_INFO_LIST, + + PA_COMMAND_SUBSCRIBE, + PA_COMMAND_SUBSCRIBE_EVENT, + + PA_COMMAND_SET_SINK_VOLUME, + PA_COMMAND_SET_SINK_INPUT_VOLUME, + + PA_COMMAND_MAX +}; + +enum { + PA_ERROR_OK, + PA_ERROR_ACCESS, + PA_ERROR_COMMAND, + PA_ERROR_INVALID, + PA_ERROR_EXIST, + PA_ERROR_NOENTITY, + PA_ERROR_CONNECTIONREFUSED, + PA_ERROR_PROTOCOL, + PA_ERROR_TIMEOUT, + PA_ERROR_AUTHKEY, + PA_ERROR_INTERNAL, + PA_ERROR_CONNECTIONTERMINATED, + PA_ERROR_KILLED, + PA_ERROR_INVALIDSERVER, + PA_ERROR_MAX +}; + +#define PA_NATIVE_COOKIE_LENGTH 256 +#define PA_NATIVE_COOKIE_FILE ".polypaudio-cookie" + +enum pa_subscription_mask { + PA_SUBSCRIPTION_MASK_NULL = 0, + PA_SUBSCRIPTION_MASK_SINK = 1, + PA_SUBSCRIPTION_MASK_SOURCE = 2, + PA_SUBSCRIPTION_MASK_SINK_INPUT = 4, + PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8, + PA_SUBSCRIPTION_MASK_MODULE = 16, + PA_SUBSCRIPTION_MASK_CLIENT = 32, + PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, +}; + +enum pa_subscription_event_type { + PA_SUBSCRIPTION_EVENT_SINK = 0, + PA_SUBSCRIPTION_EVENT_SOURCE = 1, + PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2, + PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 3, + PA_SUBSCRIPTION_EVENT_MODULE = 4, + PA_SUBSCRIPTION_EVENT_CLIENT = 5, + PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, + PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 7, + + PA_SUBSCRIPTION_EVENT_NEW = 0, + PA_SUBSCRIPTION_EVENT_CHANGE = 16, + PA_SUBSCRIPTION_EVENT_REMOVE = 32, + PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32, +}; + +#define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) + +PA_C_DECL_END + +#endif -- cgit From f693aa4c8811b67377a4fcc55887d03876fb48be Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 17 Aug 2004 13:30:26 +0000 Subject: remove native-common-internal git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@132 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/native-common-internal.h | 133 ----------------------------------------- 1 file changed, 133 deletions(-) delete mode 100644 polyp/native-common-internal.h diff --git a/polyp/native-common-internal.h b/polyp/native-common-internal.h deleted file mode 100644 index debb9bba..00000000 --- a/polyp/native-common-internal.h +++ /dev/null @@ -1,133 +0,0 @@ -#ifndef foonativecommonhfoo -#define foonativecommonhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "cdecl.h" - -PA_C_DECL_BEGIN - -enum { - PA_COMMAND_ERROR, - PA_COMMAND_TIMEOUT, /* pseudo command */ - PA_COMMAND_REPLY, - PA_COMMAND_CREATE_PLAYBACK_STREAM, - PA_COMMAND_DELETE_PLAYBACK_STREAM, - PA_COMMAND_CREATE_RECORD_STREAM, - PA_COMMAND_DELETE_RECORD_STREAM, - PA_COMMAND_EXIT, - PA_COMMAND_REQUEST, - PA_COMMAND_AUTH, - PA_COMMAND_SET_NAME, - PA_COMMAND_LOOKUP_SINK, - PA_COMMAND_LOOKUP_SOURCE, - PA_COMMAND_DRAIN_PLAYBACK_STREAM, - PA_COMMAND_PLAYBACK_STREAM_KILLED, - PA_COMMAND_RECORD_STREAM_KILLED, - PA_COMMAND_STAT, - PA_COMMAND_GET_PLAYBACK_LATENCY, - - PA_COMMAND_CREATE_UPLOAD_STREAM, - PA_COMMAND_DELETE_UPLOAD_STREAM, - PA_COMMAND_FINISH_UPLOAD_STREAM, - PA_COMMAND_PLAY_SAMPLE, - PA_COMMAND_REMOVE_SAMPLE, - - PA_COMMAND_GET_SERVER_INFO, - - PA_COMMAND_GET_SINK_INFO, - PA_COMMAND_GET_SINK_INFO_LIST, - PA_COMMAND_GET_SOURCE_INFO, - PA_COMMAND_GET_SOURCE_INFO_LIST, - PA_COMMAND_GET_MODULE_INFO, - PA_COMMAND_GET_MODULE_INFO_LIST, - PA_COMMAND_GET_CLIENT_INFO, - PA_COMMAND_GET_CLIENT_INFO_LIST, - PA_COMMAND_GET_SINK_INPUT_INFO, - PA_COMMAND_GET_SINK_INPUT_INFO_LIST, - PA_COMMAND_GET_SOURCE_OUTPUT_INFO, - PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, - PA_COMMAND_GET_SAMPLE_INFO, - PA_COMMAND_GET_SAMPLE_INFO_LIST, - - PA_COMMAND_SUBSCRIBE, - PA_COMMAND_SUBSCRIBE_EVENT, - - PA_COMMAND_SET_SINK_VOLUME, - PA_COMMAND_SET_SINK_INPUT_VOLUME, - - PA_COMMAND_MAX -}; - -enum { - PA_ERROR_OK, - PA_ERROR_ACCESS, - PA_ERROR_COMMAND, - PA_ERROR_INVALID, - PA_ERROR_EXIST, - PA_ERROR_NOENTITY, - PA_ERROR_CONNECTIONREFUSED, - PA_ERROR_PROTOCOL, - PA_ERROR_TIMEOUT, - PA_ERROR_AUTHKEY, - PA_ERROR_INTERNAL, - PA_ERROR_CONNECTIONTERMINATED, - PA_ERROR_KILLED, - PA_ERROR_INVALIDSERVER, - PA_ERROR_MAX -}; - -#define PA_NATIVE_COOKIE_LENGTH 256 -#define PA_NATIVE_COOKIE_FILE ".polypaudio-cookie" - -enum pa_subscription_mask { - PA_SUBSCRIPTION_MASK_NULL = 0, - PA_SUBSCRIPTION_MASK_SINK = 1, - PA_SUBSCRIPTION_MASK_SOURCE = 2, - PA_SUBSCRIPTION_MASK_SINK_INPUT = 4, - PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8, - PA_SUBSCRIPTION_MASK_MODULE = 16, - PA_SUBSCRIPTION_MASK_CLIENT = 32, - PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, -}; - -enum pa_subscription_event_type { - PA_SUBSCRIPTION_EVENT_SINK = 0, - PA_SUBSCRIPTION_EVENT_SOURCE = 1, - PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2, - PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 3, - PA_SUBSCRIPTION_EVENT_MODULE = 4, - PA_SUBSCRIPTION_EVENT_CLIENT = 5, - PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, - PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 7, - - PA_SUBSCRIPTION_EVENT_NEW = 0, - PA_SUBSCRIPTION_EVENT_CHANGE = 16, - PA_SUBSCRIPTION_EVENT_REMOVE = 32, - PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32, -}; - -#define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) - -PA_C_DECL_END - -#endif -- cgit From ca2265f37277081b4fe82e375923483c2e03931d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 17 Aug 2004 17:17:22 +0000 Subject: Documentation work add pkg-config support for GLIB main loop git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@133 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- configure.ac | 4 +- doc/todo | 1 + doxygen/doxygen.conf.in | 4 +- polyp/Makefile.am | 1 - polyp/glib-mainloop.h | 2 +- polyp/mainloop-api.h | 6 +-- polyp/mainloop-signal.h | 2 +- polyp/mainloop.h | 2 +- polyp/native-common.h | 48 +------------------ polyp/pacat-simple.c | 12 +++-- polyp/pacat.c | 25 ++++++++-- polyp/parec-simple.c | 7 ++- polyp/polyplib-context.h | 28 +++++------ polyp/polyplib-def.h | 107 ++++++++++++++++++++++++++++++++++++++----- polyp/polyplib-error.c | 5 +- polyp/polyplib-error.h | 3 ++ polyp/polyplib-internal.h | 1 + polyp/polyplib-introspect.c | 6 +-- polyp/polyplib-introspect.h | 35 +++++++++----- polyp/polyplib-operation.h | 6 --- polyp/polyplib-simple.h | 12 ++++- polyp/polyplib-stream.h | 11 +---- polyp/polyplib-subscribe.h | 9 ++++ polyp/polyplib.h | 50 ++++++++++++++++++++ polyp/sample-util.h | 6 +-- polyp/sample.c | 6 +-- polyp/sample.h | 47 ++++++++++++++----- polyp/sink-input.c | 2 +- polyp/sink-input.h | 2 +- polyp/sink.c | 2 +- polyp/sink.h | 4 +- polyplib-glib-mainloop.pc.in | 11 +++++ polyplib-mainloop.pc.in | 2 +- polyplib-simple.pc.in | 3 +- polyplib.pc.in | 3 +- 36 files changed, 326 insertions(+), 151 deletions(-) create mode 100644 polyplib-glib-mainloop.pc.in diff --git a/Makefile.am b/Makefile.am index 3fc81b40..13a06362 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,7 +24,7 @@ MAINTAINERCLEANFILES=README noinst_DATA = README pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc +pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc polyplib-glib-mainloop.pc README: rm -f README diff --git a/configure.ac b/configure.ac index b7766e4a..e6194d9f 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. AC_PREREQ(2.57) -AC_INIT([polypaudio],[0.1],[mzcbylcnhqvb (at) 0pointer (dot) de]) +AC_INIT([polypaudio],[0.2],[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([polyp/main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) @@ -84,5 +84,5 @@ AM_CONDITIONAL([USE_LYNX], [test "x$lynx" = xyes]) AM_CONDITIONAL(BUILD_LIBPOLYPCORE, false) -AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf]) +AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc polyplib-glib-mainloop.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf]) AC_OUTPUT diff --git a/doc/todo b/doc/todo index db89e612..aa65d339 100644 --- a/doc/todo +++ b/doc/todo @@ -5,6 +5,7 @@ - future cancellation - make mcalign merge chunks - ref counting foo +- pacat quit() ? - doxygen diff --git a/doxygen/doxygen.conf.in b/doxygen/doxygen.conf.in index 7fd00c60..7d4c44c9 100644 --- a/doxygen/doxygen.conf.in +++ b/doxygen/doxygen.conf.in @@ -417,7 +417,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = ../polyp/polyplib-context.h ../polyp/polyplib-stream.h ../polyp/polyplib.h ../polyp/sample.h ../polyp/polyplib-def.h ../polyp/polyplib-subscribe.h ../polyp/polyplib-introspect.h ../polyp/polyplib-scache.h ../polyp/mainloop-api.h ../polyp/cdecl.h ../polyp/glib-mainloop.h ../polyp/mainloop.h ../polyp/mainloop-signal.h ../polyp/native-common.h ../polyp/polyplib-error.h ../polyp/polyplib-operation.h ../polyp/polyplib-simple.h +INPUT = ../polyp/polyplib-context.h ../polyp/polyplib-stream.h ../polyp/polyplib.h ../polyp/sample.h ../polyp/polyplib-def.h ../polyp/polyplib-subscribe.h ../polyp/polyplib-introspect.h ../polyp/polyplib-scache.h ../polyp/mainloop-api.h ../polyp/cdecl.h ../polyp/glib-mainloop.h ../polyp/mainloop.h ../polyp/mainloop-signal.h ../polyp/polyplib-error.h ../polyp/polyplib-operation.h ../polyp/polyplib-simple.h # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp @@ -455,7 +455,7 @@ EXCLUDE_PATTERNS = # directories that contain example code fragments that are included (see # the \include command). -EXAMPLE_PATH = +EXAMPLE_PATH = ../polyp/ # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 100cd4ff..791abf0e 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -84,7 +84,6 @@ lib_LTLIBRARIES=libpolyp.la \ libpolyp-mainloop-glib.la \ libpolyp-simple.la - polypaudio_SOURCES = idxset.c idxset.h \ queue.c queue.h \ strbuf.c strbuf.h \ diff --git a/polyp/glib-mainloop.h b/polyp/glib-mainloop.h index 1ba663fd..dbbf2a62 100644 --- a/polyp/glib-mainloop.h +++ b/polyp/glib-mainloop.h @@ -12,7 +12,7 @@ PA_C_DECL_BEGIN /** \struct pa_glib_mainloop - * A GLIB main loop object */ + * An opaque GLIB main loop object */ struct pa_glib_mainloop; /** Create a new GLIB main loop object for the specified GLIB main loop context. If c is NULL the default context is used. */ diff --git a/polyp/mainloop-api.h b/polyp/mainloop-api.h index 3d5ad24a..e631c7ac 100644 --- a/polyp/mainloop-api.h +++ b/polyp/mainloop-api.h @@ -54,15 +54,15 @@ enum pa_io_event_flags { }; /** \struct pa_io_event - * An IO event source object */ + * An opaque IO event source object */ struct pa_io_event; /** \struct pa_defer_event - * A deferred event source object. Events of this type are triggered once in every main loop iteration */ + * An opaque deferred event source object. Events of this type are triggered once in every main loop iteration */ struct pa_defer_event; /** \struct pa_time_event - * A timer event source object */ + * An opaque timer event source object */ struct pa_time_event; /** An abstract mainloop API vtable */ diff --git a/polyp/mainloop-signal.h b/polyp/mainloop-signal.h index 0ff20827..fa5ce718 100644 --- a/polyp/mainloop-signal.h +++ b/polyp/mainloop-signal.h @@ -43,7 +43,7 @@ int pa_signal_init(struct pa_mainloop_api *api); void pa_signal_done(void); /** \struct pa_signal_event - * A UNIX signal event source object */ + * An opaque UNIX signal event source object */ struct pa_signal_event; /** Create a new UNIX signal event source object */ diff --git a/polyp/mainloop.h b/polyp/mainloop.h index b51f4226..5d4fd990 100644 --- a/polyp/mainloop.h +++ b/polyp/mainloop.h @@ -36,7 +36,7 @@ PA_C_DECL_BEGIN * as long as you access the main loop object from a single thread only.*/ /** \struct pa_mainloop - * A main loop object + * An opaque main loop object */ struct pa_mainloop; diff --git a/polyp/native-common.h b/polyp/native-common.h index debb9bba..b921ccc2 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -23,6 +23,7 @@ ***/ #include "cdecl.h" +#include "polyplib-def.h" PA_C_DECL_BEGIN @@ -78,56 +79,9 @@ enum { PA_COMMAND_MAX }; -enum { - PA_ERROR_OK, - PA_ERROR_ACCESS, - PA_ERROR_COMMAND, - PA_ERROR_INVALID, - PA_ERROR_EXIST, - PA_ERROR_NOENTITY, - PA_ERROR_CONNECTIONREFUSED, - PA_ERROR_PROTOCOL, - PA_ERROR_TIMEOUT, - PA_ERROR_AUTHKEY, - PA_ERROR_INTERNAL, - PA_ERROR_CONNECTIONTERMINATED, - PA_ERROR_KILLED, - PA_ERROR_INVALIDSERVER, - PA_ERROR_MAX -}; - #define PA_NATIVE_COOKIE_LENGTH 256 #define PA_NATIVE_COOKIE_FILE ".polypaudio-cookie" -enum pa_subscription_mask { - PA_SUBSCRIPTION_MASK_NULL = 0, - PA_SUBSCRIPTION_MASK_SINK = 1, - PA_SUBSCRIPTION_MASK_SOURCE = 2, - PA_SUBSCRIPTION_MASK_SINK_INPUT = 4, - PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8, - PA_SUBSCRIPTION_MASK_MODULE = 16, - PA_SUBSCRIPTION_MASK_CLIENT = 32, - PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, -}; - -enum pa_subscription_event_type { - PA_SUBSCRIPTION_EVENT_SINK = 0, - PA_SUBSCRIPTION_EVENT_SOURCE = 1, - PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2, - PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 3, - PA_SUBSCRIPTION_EVENT_MODULE = 4, - PA_SUBSCRIPTION_EVENT_CLIENT = 5, - PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, - PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 7, - - PA_SUBSCRIPTION_EVENT_NEW = 0, - PA_SUBSCRIPTION_EVENT_CHANGE = 16, - PA_SUBSCRIPTION_EVENT_REMOVE = 32, - PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32, -}; - -#define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) - PA_C_DECL_END #endif diff --git a/polyp/pacat-simple.c b/polyp/pacat-simple.c index f2aae2e4..f5b696a8 100644 --- a/polyp/pacat-simple.c +++ b/polyp/pacat-simple.c @@ -34,15 +34,19 @@ #define BUFSIZE 1024 int main(int argc, char*argv[]) { + + /* The Sample format to use */ static const struct pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2 }; + struct pa_simple *s = NULL; int ret = 1; int error; + /* Create a new playback stream */ if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, &error))) { fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); goto finish; @@ -51,22 +55,24 @@ int main(int argc, char*argv[]) { for (;;) { uint8_t buf[BUFSIZE]; ssize_t r; - + + /* Read some data ... */ if ((r = read(STDIN_FILENO, buf, sizeof(buf))) <= 0) { - if (r == 0) /* eof */ + if (r == 0) /* EOF */ break; fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno)); goto finish; } + /* ... and play it */ if (pa_simple_write(s, buf, r, &error) < 0) { fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error)); goto finish; } } - /* Make sure that every single sample way played */ + /* Make sure that every single sample was played */ if (pa_simple_drain(s, &error) < 0) { fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(error)); goto finish; diff --git a/polyp/pacat.c b/polyp/pacat.c index 5d29451a..4f3bf001 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -47,11 +47,13 @@ static size_t buffer_length = 0, buffer_index = 0; static struct pa_io_event* stdio_event = NULL; +/* A shortcut for terminating the application */ static void quit(int ret) { assert(mainloop_api); mainloop_api->quit(mainloop_api, ret); } +/* Write some data to the stream */ static void do_stream_write(size_t length) { size_t l; assert(length); @@ -74,6 +76,7 @@ static void do_stream_write(size_t length) { } } +/* This is called whenever new data may be written to the stream */ static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) { assert(s && length); @@ -86,6 +89,7 @@ static void stream_write_callback(struct pa_stream *s, size_t length, void *user do_stream_write(length); } +/* This is called whenever new data may is available */ static void stream_read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata) { assert(s && data && length); @@ -103,6 +107,7 @@ static void stream_read_callback(struct pa_stream *s, const void*data, size_t le buffer_index = 0; } +/* This routine is called whenever the stream state changes */ static void stream_state_callback(struct pa_stream *s, void *userdata) { assert(s); @@ -125,6 +130,7 @@ static void stream_state_callback(struct pa_stream *s, void *userdata) { } } +/* This is called whenever the context status changes */ static void context_state_callback(struct pa_context *c, void *userdata) { static const struct pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, @@ -170,10 +176,12 @@ static void context_state_callback(struct pa_context *c, void *userdata) { } } +/* Connection draining complete */ static void context_drain_complete(struct pa_context*c, void *userdata) { pa_context_disconnect(c); } +/* Stream draining complete */ static void stream_drain_complete(struct pa_stream*s, int success, void *userdata) { struct pa_operation *o; @@ -196,6 +204,7 @@ static void stream_drain_complete(struct pa_stream*s, int success, void *userdat } } +/* New data on STDIN **/ static void stdin_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { size_t l, w = 0; ssize_t r; @@ -232,6 +241,7 @@ static void stdin_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int do_stream_write(w); } +/* Some data may be written to STDOUT */ static void stdout_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { ssize_t r; assert(a == mainloop_api && e && stdio_event == e); @@ -262,12 +272,14 @@ static void stdout_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int } } +/* UNIX signal to quit recieved */ static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { fprintf(stderr, "Got SIGINT, exiting.\n"); quit(0); } +/* Show the current playback latency */ static void stream_get_latency_callback(struct pa_stream *s, uint32_t latency, void *userdata) { assert(s); @@ -280,6 +292,7 @@ static void stream_get_latency_callback(struct pa_stream *s, uint32_t latency, v fprintf(stderr, "Current latency is %u usecs.\n", latency); } +/* Someone requested that the latency is shown */ static void sigusr1_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { if (mode != PLAYBACK) return; @@ -295,6 +308,8 @@ int main(int argc, char *argv[]) { if (!(bn = strrchr(argv[0], '/'))) bn = argv[0]; + else + bn++; if (strstr(bn, "rec") || strstr(bn, "mon")) mode = RECORD; @@ -302,7 +317,8 @@ int main(int argc, char *argv[]) { mode = PLAYBACK; fprintf(stderr, "Opening a %s stream.\n", mode == RECORD ? "recording" : "playback"); - + + /* Set up a new main loop */ if (!(m = pa_mainloop_new())) { fprintf(stderr, "pa_mainloop_new() failed.\n"); goto quit; @@ -323,16 +339,19 @@ int main(int argc, char *argv[]) { fprintf(stderr, "source_io() failed.\n"); goto quit; } - - if (!(context = pa_context_new(mainloop_api, argv[0]))) { + + /* Create a new connection context */ + if (!(context = pa_context_new(mainloop_api, bn))) { fprintf(stderr, "pa_context_new() failed.\n"); goto quit; } pa_context_set_state_callback(context, context_state_callback, NULL); + /* Connect the context */ pa_context_connect(context, NULL); + /* Run the main loop */ if (pa_mainloop_run(m, &ret) < 0) { fprintf(stderr, "pa_mainloop_run() failed.\n"); goto quit; diff --git a/polyp/parec-simple.c b/polyp/parec-simple.c index e12b8e00..74f0a0f7 100644 --- a/polyp/parec-simple.c +++ b/polyp/parec-simple.c @@ -33,6 +33,7 @@ #define BUFSIZE 1024 +/* A simple routine calling UNIX write() in a loop */ static ssize_t loop_write(int fd, const void*data, size_t size) { ssize_t ret = 0; @@ -54,6 +55,7 @@ static ssize_t loop_write(int fd, const void*data, size_t size) { } int main(int argc, char*argv[]) { + /* The sample type to use */ static const struct pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 44100, @@ -63,6 +65,7 @@ int main(int argc, char*argv[]) { int ret = 1; int error; + /* Create the recording stream */ if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, &error))) { fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); goto finish; @@ -72,11 +75,13 @@ int main(int argc, char*argv[]) { uint8_t buf[BUFSIZE]; ssize_t r; + /* Record some data ... */ if (pa_simple_read(s, buf, sizeof(buf), &error) < 0) { fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error)); goto finish; } - + + /* And write it to STDOUT */ if ((r = loop_write(STDOUT_FILENO, buf, sizeof(buf))) <= 0) { fprintf(stderr, __FILE__": write() failed: %s\n", strerror(errno)); goto finish; diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h index 6a1cc8bd..9614ce69 100644 --- a/polyp/polyplib-context.h +++ b/polyp/polyplib-context.h @@ -29,23 +29,25 @@ #include "polyplib-operation.h" /** \file - * Connection contexts */ + * Connection contexts for asynchrononous communication with a + * server. A pa_context object wraps a connection to a polypaudio + * server using its native protocol. A context may be used to issue + * commands on the server or to create playback or recording + * streams. Multiple playback streams may be piped through a single + * connection context. Operations on the contect involving + * communication with the server are executed asynchronously: i.e. the + * client function do not implicitely wait for completion of the + * operation on the server. Instead the caller specifies a call back + * function that is called when the operation is completed. Currently + * running operations may be canceled using pa_operation_cancel(). */ + +/** \example pacat.c + * A playback and recording tool using the asynchronous API */ PA_C_DECL_BEGIN -/** The state of a connection context */ -enum pa_context_state { - PA_CONTEXT_UNCONNECTED, /**< The context hasn't been connected yet */ - PA_CONTEXT_CONNECTING, /**< A connection is being established */ - PA_CONTEXT_AUTHORIZING, /**< The client is authorizing itself to the daemon */ - PA_CONTEXT_SETTING_NAME, /**< The client is passing its application name to the daemon */ - PA_CONTEXT_READY, /**< The connection is established, the context is ready to execute operations */ - PA_CONTEXT_FAILED, /**< The connection failed or was disconnected */ - PA_CONTEXT_TERMINATED /**< The connect was terminated cleanly */ -}; - /** \struct pa_context - * A connection context to a daemon */ + * An opaque connection context to a daemon */ struct pa_context; /** Instantiate a new connection context with an abstract mainloop API diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index fc19be69..8a506c8d 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -23,28 +23,111 @@ ***/ #include -#include "native-common.h" #include "cdecl.h" +/** \file + * Global definitions */ + PA_C_DECL_BEGIN -enum pa_stream_direction { - PA_STREAM_NODIRECTION, - PA_STREAM_PLAYBACK, - PA_STREAM_RECORD, - PA_STREAM_UPLOAD +/** The state of a connection context */ +enum pa_context_state { + PA_CONTEXT_UNCONNECTED, /**< The context hasn't been connected yet */ + PA_CONTEXT_CONNECTING, /**< A connection is being established */ + PA_CONTEXT_AUTHORIZING, /**< The client is authorizing itself to the daemon */ + PA_CONTEXT_SETTING_NAME, /**< The client is passing its application name to the daemon */ + PA_CONTEXT_READY, /**< The connection is established, the context is ready to execute operations */ + PA_CONTEXT_FAILED, /**< The connection failed or was disconnected */ + PA_CONTEXT_TERMINATED /**< The connection was terminated cleanly */ }; -struct pa_buffer_attr { - uint32_t maxlength; - uint32_t tlength; - uint32_t prebuf; - uint32_t minreq; - uint32_t fragsize; +/** The state of a stream */ +enum pa_stream_state { + PA_STREAM_DISCONNECTED, /**< The stream is not yet connected to any sink or source */ + PA_STREAM_CREATING, /**< The stream is being created */ + PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */ + PA_STREAM_FAILED, /**< An error occured that made the stream invalid */ + PA_STREAM_TERMINATED, /**< The stream has been terminated cleanly */ }; +/** The state of an operation */ +enum pa_operation_state { + PA_OPERATION_RUNNING, /**< The operation is still running */ + PA_OPERATION_DONE, /**< The operation has been completed */ + PA_OPERATION_CANCELED, /**< The operation has been canceled */ +}; + +/** An invalid index */ #define PA_INVALID_INDEX ((uint32_t) -1) +/** The direction of a pa_stream object */ +enum pa_stream_direction { + PA_STREAM_NODIRECTION, /**< Invalid direction */ + PA_STREAM_PLAYBACK, /**< Playback stream */ + PA_STREAM_RECORD, /**< Record stream */ + PA_STREAM_UPLOAD /**< Sample upload stream */ +}; + +/** Playback and record buffer metrics */ +struct pa_buffer_attr{ + uint32_t maxlength; /**< Maximum length of the buffer */ + uint32_t tlength; /**< Playback only: target length of the buffer. The server tries to assure that at least tlength bytes are always available in the buffer */ + uint32_t prebuf; /**< Playback only: pre-buffering. The server does not start with playback before at least prebug bytes are available in the buffer */ + uint32_t minreq; /**< Playback only: minimum request. The server does not request less than minreq bytes from the client, instead waints until the buffer is free enough to request more bytes at once */ + uint32_t fragsize; /**< Recording only: fragment size. The server sends data in blocks of fragsize bytes size. Large values deminish interactivity with other operations on the connection context but decrease control overhead. */ +}; + +/** Error values as used by pa_context_errno(). Use pa_strerror() to convert these values to human readable strings */ +enum { + PA_ERROR_OK, /**< No error */ + PA_ERROR_ACCESS, /**< Access failure */ + PA_ERROR_COMMAND, /**< Unknown command */ + PA_ERROR_INVALID, /**< Invalid argument */ + PA_ERROR_EXIST, /**< Entity exists */ + PA_ERROR_NOENTITY, /**< No such entity */ + PA_ERROR_CONNECTIONREFUSED, /**< Connection refused */ + PA_ERROR_PROTOCOL, /**< Protocol error */ + PA_ERROR_TIMEOUT, /**< Timeout */ + PA_ERROR_AUTHKEY, /**< No authorization key */ + PA_ERROR_INTERNAL, /**< Internal error */ + PA_ERROR_CONNECTIONTERMINATED, /**< Connection terminated */ + PA_ERROR_KILLED, /**< Entity killed */ + PA_ERROR_INVALIDSERVER, /**< Invalid server */ + PA_ERROR_MAX /**< Not really an error but the first invalid error code */ +}; + +/** Subscription event mask, as used by pa_context_subscribe() */ +enum pa_subscription_mask { + PA_SUBSCRIPTION_MASK_NULL = 0, /**< No events */ + PA_SUBSCRIPTION_MASK_SINK = 1, /**< Sink events */ + PA_SUBSCRIPTION_MASK_SOURCE = 2, /**< Source events */ + PA_SUBSCRIPTION_MASK_SINK_INPUT = 4, /**< Sink input events */ + PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8, /**< Source output events */ + PA_SUBSCRIPTION_MASK_MODULE = 16, /**< Module events */ + PA_SUBSCRIPTION_MASK_CLIENT = 32, /**< Client events */ + PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, /**< Sample cache events */ +}; + +/** Subscription event types, as used by pa_context_subscribe() */ +enum pa_subscription_event_type { + PA_SUBSCRIPTION_EVENT_SINK = 0, /**< Event type: Sink */ + PA_SUBSCRIPTION_EVENT_SOURCE = 1, /**< Event type: Source */ + PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2, /**< Event type: Sink input */ + PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 3, /**< Event type: Source output */ + PA_SUBSCRIPTION_EVENT_MODULE = 4, /**< Event type: Module */ + PA_SUBSCRIPTION_EVENT_CLIENT = 5, /**< Event type: Client */ + PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, /**< Event type: Sample cache item */ + PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 7, /**< A mask to extract the event type from an event value */ + + PA_SUBSCRIPTION_EVENT_NEW = 0, /**< A new object was created */ + PA_SUBSCRIPTION_EVENT_CHANGE = 16, /**< A property of the object was modified */ + PA_SUBSCRIPTION_EVENT_REMOVE = 32, /**< An object was removed */ + PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32, /**< A mask to extract the event operation from an event value */ +}; + +/** Return one if an event type t matches an event mask bitfield */ +#define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) + PA_C_DECL_END #endif diff --git a/polyp/polyplib-error.c b/polyp/polyplib-error.c index 10b637c4..24054f2e 100644 --- a/polyp/polyplib-error.c +++ b/polyp/polyplib-error.c @@ -37,12 +37,13 @@ static const char* const errortab[PA_ERROR_MAX] = { [PA_ERROR_EXIST] = "Entity exists", [PA_ERROR_NOENTITY] = "No such entity", [PA_ERROR_CONNECTIONREFUSED] = "Connection refused", - [PA_ERROR_PROTOCOL] = "Protocol corrupt", + [PA_ERROR_PROTOCOL] = "Protocol error", [PA_ERROR_TIMEOUT] = "Timeout", - [PA_ERROR_AUTHKEY] = "Not authorization key", + [PA_ERROR_AUTHKEY] = "No authorization key", [PA_ERROR_INTERNAL] = "Internal error", [PA_ERROR_CONNECTIONTERMINATED] = "Connection terminated", [PA_ERROR_KILLED] = "Entity killed", + [PA_ERROR_INVALIDSERVER] = "Invalid server", }; const char*pa_strerror(uint32_t error) { diff --git a/polyp/polyplib-error.h b/polyp/polyplib-error.h index 437d618e..8b5cd910 100644 --- a/polyp/polyplib-error.h +++ b/polyp/polyplib-error.h @@ -25,6 +25,9 @@ #include #include "cdecl.h" +/** \file + * Error management */ + PA_C_DECL_BEGIN /** Return a human readable error message for the specified numeric error code */ diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 0b6b3887..c8228a86 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -32,6 +32,7 @@ #include "polyplib-stream.h" #include "polyplib-operation.h" #include "llist.h" +#include "native-common.h" #define DEFAULT_MAXLENGTH 204800 #define DEFAULT_TLENGTH 10240 diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index aa70a111..9a7ec157 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -514,7 +514,7 @@ struct pa_operation* pa_context_get_source_output_info_list(struct pa_context *c /*** Volume manipulation ***/ -struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { +struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, uint32_t index, pa_volume_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { struct pa_operation *o; struct pa_tagstruct *t; uint32_t tag; @@ -536,7 +536,7 @@ struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, u return pa_operation_ref(o); } -struct pa_operation* pa_context_set_sink_volume_by_name(struct pa_context *c, const char *name, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { +struct pa_operation* pa_context_set_sink_volume_by_name(struct pa_context *c, const char *name, pa_volume_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { struct pa_operation *o; struct pa_tagstruct *t; uint32_t tag; @@ -558,7 +558,7 @@ struct pa_operation* pa_context_set_sink_volume_by_name(struct pa_context *c, co return pa_operation_ref(o); } -struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { +struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, pa_volume_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { struct pa_operation *o; struct pa_tagstruct *t; uint32_t tag; diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index e83ba73b..dfa24ed5 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -28,6 +28,9 @@ #include "polyplib-context.h" #include "cdecl.h" +/** \file + * Routines for daemon introspection. */ + PA_C_DECL_BEGIN struct pa_sink_info { @@ -36,7 +39,7 @@ struct pa_sink_info { const char *description; struct pa_sample_spec sample_spec; uint32_t owner_module; - uint32_t volume; + pa_volume_t volume; uint32_t monitor_source; const char *monitor_source_name; uint32_t latency; @@ -60,12 +63,13 @@ struct pa_operation* pa_context_get_source_info_by_name(struct pa_context *c, co struct pa_operation* pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); struct pa_operation* pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +/** Server information */ struct pa_server_info { - const char *user_name; - const char *host_name; - const char *server_version; - const char *server_name; - struct pa_sample_spec sample_spec; + const char *user_name; /**< User name of the daemon process */ + const char *host_name; /**< Host name the daemon is running on */ + const char *server_version; /**< Version string of the daemon */ + const char *server_name; /**< Server package name (usually "polypaudio") */ + struct pa_sample_spec sample_spec; /**< Default sample specification */ }; struct pa_operation* pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); @@ -96,7 +100,7 @@ struct pa_sink_input_info { uint32_t client; uint32_t sink; struct pa_sample_spec sample_spec; - uint32_t volume; + pa_volume_t volume; uint32_t latency; }; @@ -115,15 +119,22 @@ struct pa_source_output_info { struct pa_operation* pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); struct pa_operation* pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); -struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -struct pa_operation* pa_context_set_sink_volume_by_name(struct pa_context *c, const char *name, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +/** Set the volume of a sink device specified by its index */ +struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, uint32_t index, pa_volume_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +/** Set the volume of a sink device specified by its name */ +struct pa_operation* pa_context_set_sink_volume_by_name(struct pa_context *c, const char *name, pa_volume_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +/** Set the volume of a sink input stream */ +struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, pa_volume_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +/** Memory block statistics */ struct pa_stat_info { - uint32_t memblock_count; - uint32_t memblock_total; + uint32_t memblock_count; /**< Allocated memory blocks */ + uint32_t memblock_total; /**< Total size of allocated memory blocks */ }; +/** Get daemon memory block statistics */ struct pa_operation* pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_stat_info *i, void *userdata), void *userdata); PA_C_DECL_END diff --git a/polyp/polyplib-operation.h b/polyp/polyplib-operation.h index 7d0adc26..ce2756ef 100644 --- a/polyp/polyplib-operation.h +++ b/polyp/polyplib-operation.h @@ -29,12 +29,6 @@ PA_C_DECL_BEGIN -enum pa_operation_state { - PA_OPERATION_RUNNING, /**< The operation is still running */ - PA_OPERATION_DONE, /**< The operation has been completed */ - PA_OPERATION_CANCELED, /**< The operation has been canceled */ -}; - /** \struct pa_operation * An asynchronous operation object */ struct pa_operation; diff --git a/polyp/polyplib-simple.h b/polyp/polyplib-simple.h index ee2e27e3..ed552cb4 100644 --- a/polyp/polyplib-simple.h +++ b/polyp/polyplib-simple.h @@ -29,12 +29,20 @@ #include "cdecl.h" /** \file - * A simple but limited synchronous playback and recording API. */ + * A simple but limited synchronous playback and recording + * API. This is synchronouse, simplified wrapper around the standard + * asynchronous API. */ + +/** \example pacat-simple.c + * A simple playback tool using the simple API */ + +/** \example parec-simple.c + * A simple recording tool using the simple API */ PA_C_DECL_BEGIN /** \struct pa_simple - * A simple connection object */ + * An opaque simple connection object */ struct pa_simple; /** Create a new connection to the server */ diff --git a/polyp/polyplib-stream.h b/polyp/polyplib-stream.h index 41801c6c..1a9d58dd 100644 --- a/polyp/polyplib-stream.h +++ b/polyp/polyplib-stream.h @@ -34,17 +34,8 @@ PA_C_DECL_BEGIN -/** The state of a stream */ -enum pa_stream_state { - PA_STREAM_DISCONNECTED, /**< The stream is not yet connected to any sink or source */ - PA_STREAM_CREATING, /**< The stream is being created */ - PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */ - PA_STREAM_FAILED, /**< An error occured that made the stream invalid */ - PA_STREAM_TERMINATED, /**< The stream has been terminated cleanly */ -}; - /** \struct pa_stream - * A stream for playback or recording */ + * An opaque stream for playback or recording */ struct pa_stream; /** Create a new, unconnected stream with the specified name and sample type */ diff --git a/polyp/polyplib-subscribe.h b/polyp/polyplib-subscribe.h index 56384915..bd0e0399 100644 --- a/polyp/polyplib-subscribe.h +++ b/polyp/polyplib-subscribe.h @@ -28,9 +28,18 @@ #include "polyplib-context.h" #include "cdecl.h" +/** \file + * Daemon introspection event subscription subsystem. Use this + * to be notified whenever the internal layout of daemon changes: + * i.e. entities such as sinks or sources are create, removed or + * modified. */ + PA_C_DECL_BEGIN +/** Enable event notification */ struct pa_operation* pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +/** Set the context specific call back function that is called whenever the state of the daemon changes */ void pa_context_set_subscribe_callback(struct pa_context *c, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); PA_C_DECL_END diff --git a/polyp/polyplib.h b/polyp/polyplib.h index b9e5637c..daaed649 100644 --- a/polyp/polyplib.h +++ b/polyp/polyplib.h @@ -31,4 +31,54 @@ #include "polyplib-subscribe.h" #include "polyplib-scache.h" +/** \file + * Include all polyplib header file at once. The following files are included: \ref mainloop-api.h, \ref sample.h, + * \ref polyplib-def.h, \ref polyplib-context.h, \ref polyplib-stream.h, + * \ref polyplib-introspect.h, \ref polyplib-subscribe.h and \ref polyplib-scache.h + * at once */ + +/** \mainpage + * + * \section intro_sec Introduction + * + * This document describes the client API for the polypaudio sound + * server. The API comes in two flavours: + * + * \li The complete but somewhat complicated to use asynchronous API + * \li And the simplified, easy to use, but limited synchronous API + * + * The polypaudio client libraries are thread safe as long as all + * objects created by any library function are accessed from the thread + * that created them only. + * + * \section simple_sec Simple API + * + * Use this if you develop your program in synchronous style and just + * need a way to play or record data on the sound server. See + * \ref polyplib-simple.h for more details. + * + * \section async_api Asynchronous API + * + * Use this if you develop your programs in asynchronous, main loop + * based style or want to use advanced features of the polypaudio + * API. A good starting point is \ref polyplib-context.h + * + * The asynchronous API relies on an abstract main loop API that is + * described in \ref mainloop-api.h. Two distinct implementations are + * available: + * + * \li \ref mainloop.h: a minimal but fast implementation based on poll() + * \li \ref glib-mainloop.h: a wrapper around GLIB's main loop + * + * UNIX signals may be hooked to a main loop using the functions from + * \ref mainloop-signal.h + * + * \section pkgconfig pkg-config + * + * The polypaudio libraries provide pkg-config snippets for the different modules. To use the + * asynchronous API use "polyplib" as pkg-config file. GLIB main loop + * support is available as "polyplib-glib-mainloop". The simple + * synchronous API is available as "polyplib-simple". + */ + #endif diff --git a/polyp/sample-util.h b/polyp/sample-util.h index 66f40a16..9f3fced1 100644 --- a/polyp/sample-util.h +++ b/polyp/sample-util.h @@ -33,12 +33,12 @@ void pa_silence_memory(void *p, size_t length, const struct pa_sample_spec *spec struct pa_mix_info { struct pa_memchunk chunk; - uint32_t volume; + pa_volume_t volume; void *userdata; }; -size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const struct pa_sample_spec *spec, uint32_t volume); +size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const struct pa_sample_spec *spec, pa_volume_t volume); -void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, uint32_t volume); +void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, pa_volume_t volume); #endif diff --git a/polyp/sample.c b/polyp/sample.c index 4f93f2b7..173de9c1 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -82,7 +82,7 @@ int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_s return (a->format == b->format) && (a->rate == b->rate) && (a->channels == b->channels); } -void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec) { +void pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spec) { static const char* const table[]= { [PA_SAMPLE_U8] = "U8", [PA_SAMPLE_ALAW] = "ALAW", @@ -97,10 +97,10 @@ void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec) { snprintf(s, l, "%s %uch %uHz", table[spec->format], spec->channels, spec->rate); } -uint32_t pa_volume_multiply(uint32_t a, uint32_t b) { +pa_volume_t pa_volume_multiply(pa_volume_t a, pa_volume_t b) { uint64_t p = a; p *= b; p /= PA_VOLUME_NORM; - return (uint32_t) p; + return (pa_volume_t) p; } diff --git a/polyp/sample.h b/polyp/sample.h index e397a1df..459f8a30 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -27,26 +27,36 @@ #include "cdecl.h" +/** \file + * Constants and routines for sample type handling */ + PA_C_DECL_BEGIN +/** Sample format */ enum pa_sample_format { - PA_SAMPLE_U8, - PA_SAMPLE_ALAW, - PA_SAMPLE_ULAW, - PA_SAMPLE_S16LE, - PA_SAMPLE_S16BE, - PA_SAMPLE_FLOAT32LE, - PA_SAMPLE_FLOAT32BE, - PA_SAMPLE_MAX + PA_SAMPLE_U8, /**< Unsigned 8 Bit PCM */ + PA_SAMPLE_ALAW, /**< 8 Bit a-Law */ + PA_SAMPLE_ULAW, /**< 8 Bit mu-Law */ + PA_SAMPLE_S16LE, /**< Signed 16 Bit PCM, little endian (PC) */ + PA_SAMPLE_S16BE, /**< Signed 16 Bit PCM, big endian */ + PA_SAMPLE_FLOAT32LE, /**< 32 Bit IEEE floating point, little endian, range -1..1 */ + PA_SAMPLE_FLOAT32BE, /**< 32 Bit IEEE floating point, big endian, range -1..1 */ + PA_SAMPLE_MAX /**< Upper limit of valid sample types */ }; #ifdef WORDS_BIGENDIAN +/** Signed 16 Bit PCM, native endian */ #define PA_SAMPLE_S16NE PA_SAMPLE_S16BE +/** 32 Bit IEEE floating point, native endian */ #define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32BE #else +/** Signed 16 Bit PCM, native endian */ #define PA_SAMPLE_S16NE PA_SAMPLE_S16LE +/** 32 Bit IEEE floating point, native endian */ #define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32LE #endif + +/** A Shortcut for PA_SAMPLE_FLOAT32NE */ #define PA_SAMPLE_FLOAT32 PA_SAMPLE_FLOAT32NE /** A sample format and attribute specification */ @@ -56,23 +66,38 @@ struct pa_sample_spec { uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */ }; +/** Return the amount of bytes playback of a second of audio with the speicified sample type takes */ size_t pa_bytes_per_second(const struct pa_sample_spec *spec); + +/** Return the size of a frame with the specific sample type */ size_t pa_frame_size(const struct pa_sample_spec *spec); + +/** Calculate the time the specified bytes take to play with the specified sample type */ uint32_t pa_bytes_to_usec(size_t length, const struct pa_sample_spec *spec); + +/** Return non-zero when the sample type specification is valid */ int pa_sample_spec_valid(const struct pa_sample_spec *spec); + +/** Return non-zero when the two sample type specifications match */ int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b); +/** Maximum required string length for pa_sample_spec_snprint() */ #define PA_SAMPLE_SNPRINT_MAX_LENGTH 32 -void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec); + +/** Pretty print a sample type specification to a string */ +void pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spec); + +/** Volume specification: 0: silence; < 256: diminished volume; 256: normal volume; > 256 amplified volume */ +typedef uint32_t pa_volume_t; /** Normal volume (100%) */ #define PA_VOLUME_NORM (0x100) /** Muted volume (0%) */ -#define PA_VOLUME_MUTE (0) +#define PA_VOLUME_MUTED (0) /** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. */ -uint32_t pa_volume_multiply(uint32_t a, uint32_t b); +pa_volume_t pa_volume_multiply(pa_volume_t a, pa_volume_t b); PA_C_DECL_END diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 99ff8fe6..7629bfb9 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -169,7 +169,7 @@ void pa_sink_input_drop(struct pa_sink_input *i, size_t length) { } } -void pa_sink_input_set_volume(struct pa_sink_input *i, uint32_t volume) { +void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume) { assert(i && i->sink && i->sink->core); if (i->volume != volume) { diff --git a/polyp/sink-input.h b/polyp/sink-input.h index b21dbf4d..8d7788d8 100644 --- a/polyp/sink-input.h +++ b/polyp/sink-input.h @@ -64,6 +64,6 @@ uint32_t pa_sink_input_get_latency(struct pa_sink_input *i); int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk); void pa_sink_input_drop(struct pa_sink_input *i, size_t length); -void pa_sink_input_set_volume(struct pa_sink_input *i, uint32_t volume); +void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume); #endif diff --git a/polyp/sink.c b/polyp/sink.c index b8617ae1..eb3133ac 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -283,7 +283,7 @@ void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m) { pa_source_set_owner(sink->monitor_source, m); } -void pa_sink_set_volume(struct pa_sink *sink, uint32_t volume) { +void pa_sink_set_volume(struct pa_sink *sink, pa_volume_t volume) { assert(sink); if (sink->volume != volume) { diff --git a/polyp/sink.h b/polyp/sink.h index 2aa5d611..8248d00c 100644 --- a/polyp/sink.h +++ b/polyp/sink.h @@ -42,7 +42,7 @@ struct pa_sink { struct pa_source *monitor_source; - uint32_t volume; + pa_volume_t volume; void (*notify)(struct pa_sink*sink); uint32_t (*get_latency)(struct pa_sink *s); @@ -62,6 +62,6 @@ void pa_sink_notify(struct pa_sink*s); void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m); -void pa_sink_set_volume(struct pa_sink *sink, uint32_t volume); +void pa_sink_set_volume(struct pa_sink *sink, pa_volume_t volume); #endif diff --git a/polyplib-glib-mainloop.pc.in b/polyplib-glib-mainloop.pc.in new file mode 100644 index 00000000..f4c09330 --- /dev/null +++ b/polyplib-glib-mainloop.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: polyplib-glib-mainloop +Description: GLIB main loop wrapper for polypaudio +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lpolyp-mainloop-glib +Cflags: -D_REENTRANT -I${includedir} +Requires: polyplib-mainloop diff --git a/polyplib-mainloop.pc.in b/polyplib-mainloop.pc.in index f4bdba5b..73e579a3 100644 --- a/polyplib-mainloop.pc.in +++ b/polyplib-mainloop.pc.in @@ -4,7 +4,7 @@ libdir=${exec_prefix}/lib includedir=${prefix}/include Name: polyplib-mainloop -Description: Mainloop API of the polypaudio sound daemon +Description: Main loop support for polypaudio Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lpolyp-mainloop Cflags: -D_REENTRANT -I${includedir} diff --git a/polyplib-simple.pc.in b/polyplib-simple.pc.in index efae9410..e5dcaa9e 100644 --- a/polyplib-simple.pc.in +++ b/polyplib-simple.pc.in @@ -4,7 +4,8 @@ libdir=${exec_prefix}/lib includedir=${prefix}/include Name: polyplib-simple -Description: Simplistic client interface to polypaudio sound daemon +Description: Simplified synchronous client interface to polypaudio Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lpolyp-simple Cflags: -D_REENTRANT -I${includedir} +Requires: polyplib polyplib-mainloop polyplib-error diff --git a/polyplib.pc.in b/polyplib.pc.in index 8a554cb1..b06c6e51 100644 --- a/polyplib.pc.in +++ b/polyplib.pc.in @@ -4,7 +4,8 @@ libdir=${exec_prefix}/lib includedir=${prefix}/include Name: polyplib -Description: Client interface to polypaudio sound daemon +Description: Client interface to polypaudio Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lpolyp Cflags: -D_REENTRANT -I${includedir} +Requires: polyplib-error polyplib-mainloop -- cgit From 711de8df9b78a46d4e12b810c26d26e9ead294e6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 17 Aug 2004 17:56:09 +0000 Subject: autoconf beefup build fixes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@134 fefdeb5f-60dc-0310-8127-8f9354f1896f --- acinclude.m4 | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 27 +++++++ polyp/Makefile.am | 31 +++++--- polyp/cli-text.c | 10 +-- polyp/sample-util.c | 10 +-- polyp/sink-input.c | 2 +- polyp/sink.c | 2 +- polyp/source.c | 2 +- polyp/util.c | 4 ++ 9 files changed, 264 insertions(+), 23 deletions(-) create mode 100644 acinclude.m4 diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 00000000..bedf51c3 --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,199 @@ +dnl Available from the GNU Autoconf Macro Archive at: +dnl http://www.gnu.org/software/ac-archive/htmldoc/acx_pthread.html +dnl +AC_DEFUN([ACX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_LANG_SAVE +AC_LANG_C +acx_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on True64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) + AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) + AC_MSG_RESULT($acx_pthread_ok) + if test x"$acx_pthread_ok" = xno; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all, and "pthread-config" +# which is a program returning the flags for the Pth emulation library. + +acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) +# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) +# -pthreads: Solaris/gcc +# -mthreads: Mingw32/gcc, Lynx/gcc +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads too; +# also defines -D_REENTRANT) +# pthread: Linux, etcetera +# --thread-safe: KAI C++ +# pthread-config: use pthread-config program (for GNU Pth library) + +case "${host_cpu}-${host_os}" in + *solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthread or + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + + acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags" + ;; +esac + +if test x"$acx_pthread_ok" = xno; then +for flag in $acx_pthread_flags; do + + case $flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $flag]) + PTHREAD_CFLAGS="$flag" + ;; + + pthread-config) + AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) + if test x"$acx_pthread_config" = xno; then continue; fi + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$flag]) + PTHREAD_LIBS="-l$flag" + ;; + esac + + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [acx_pthread_ok=yes]) + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + AC_MSG_RESULT($acx_pthread_ok) + if test "x$acx_pthread_ok" = xyes; then + break; + fi + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$acx_pthread_ok" = xyes; then + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Detect AIX lossage: threads are created detached by default + # and the JOINABLE attribute has a nonstandard name (UNDETACHED). + AC_MSG_CHECKING([for joinable pthread attribute]) + AC_TRY_LINK([#include ], + [int attr=PTHREAD_CREATE_JOINABLE;], + ok=PTHREAD_CREATE_JOINABLE, ok=unknown) + if test x"$ok" = xunknown; then + AC_TRY_LINK([#include ], + [int attr=PTHREAD_CREATE_UNDETACHED;], + ok=PTHREAD_CREATE_UNDETACHED, ok=unknown) + fi + if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then + AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok, + [Define to the necessary symbol if this constant + uses a non-standard name on your system.]) + fi + AC_MSG_RESULT(${ok}) + if test x"$ok" = xunknown; then + AC_MSG_WARN([we do not know how to create joinable pthreads]) + fi + + AC_MSG_CHECKING([if more special flags are required for pthreads]) + flag=no + case "${host_cpu}-${host_os}" in + *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; + *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; + esac + AC_MSG_RESULT(${flag}) + if test "x$flag" != xno; then + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" + fi + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + # More AIX lossage: must compile with cc_r + AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC}) +else + PTHREAD_CC="$CC" +fi + +AC_SUBST(PTHREAD_LIBS) +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_CC) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x"$acx_pthread_ok" = xyes; then + ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) + : +else + acx_pthread_ok=no + $2 +fi +AC_LANG_RESTORE +])dnl ACX_PTHREAD diff --git a/configure.ac b/configure.ac index e6194d9f..4e4bf3aa 100644 --- a/configure.ac +++ b/configure.ac @@ -40,6 +40,33 @@ AC_SUBST(LIBLTDL) AC_LIBTOOL_DLOPEN AC_PROG_LIBTOOL +# Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h limits.h malloc.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h]) + +ACX_PTHREAD +AC_PATH_XTRA +AM_CONDITIONAL(X_DISPLAY_MISSING, test "x$X_DISPLAY_MISSING" != "x") + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_HEADER_TIME + +# Checks for library functions. +AC_FUNC_FORK +AC_PROG_GCC_TRADITIONAL +AC_FUNC_LSTAT +AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK +AC_FUNC_MALLOC +AC_FUNC_MEMCMP +AC_FUNC_MMAP +AC_FUNC_REALLOC +AC_FUNC_SETPGRP +AC_TYPE_SIGNAL +AC_CHECK_FUNCS([gethostname gettimeofday memchr memmove memset mkdir mkfifo munmap rmdir socket strcspn strerror strrchr strspn strstr strtol strtoul]) + AC_C_BIGENDIAN PKG_CHECK_MODULES(LIBSAMPLERATE, [ samplerate >= 0.1.0 ]) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 791abf0e..1f982515 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -17,9 +17,9 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -AM_CFLAGS=-ansi -D_GNU_SOURCE -DDLSEARCHDIR=\"$(pkglibdir)\" -I$(srcdir)/.. -AM_LDADD=-L. -lpthread -AM_LIBADD=-L. -lpthread +AM_CFLAGS=-ansi -D_GNU_SOURCE -DDLSEARCHDIR=\"$(pkglibdir)\" -I$(srcdir)/.. $(PTHREAD_CFLAGS) +AM_LDADD=$(PTHREAD_LIBS) +AM_LIBADD=$(PTHREAD_LIBS) polypincludedir=$(includedir)/polyp @@ -75,8 +75,11 @@ pkglib_LTLIBRARIES=libiochannel.la \ module-esound-protocol-tcp.la \ module-esound-protocol-unix.la \ module-native-protocol-tcp.la \ - module-native-protocol-unix.la \ - module-x11-bell.la + module-native-protocol-unix.la + +if !X_DISPLAY_MISSING +pkglib_LTLIBRARIES+=module-x11-bell.la +endif lib_LTLIBRARIES=libpolyp.la \ libpolyp-error.la \ @@ -265,9 +268,12 @@ module_cli_la_SOURCES = module-cli.c module_cli_la_LDFLAGS = -module -avoid-version module_cli_la_LIBADD = $(AM_LIBADD) libcli.la libiochannel.la +if !X_DISPLAY_MISSING module_x11_bell_la_SOURCES = module-x11-bell.c +module_x11_bell_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) module_x11_bell_la_LDFLAGS = -module -avoid-version -module_x11_bell_la_LIBADD = $(AM_LIBADD) -lX11 -L/usr/X11R6/lib +module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) $(X_LIBS) $(X_EXTRA_LIB) +endif libpolyp_la_SOURCES = polyplib.h \ polyplib-def.h \ @@ -299,20 +305,29 @@ libpolyp_la_SOURCES = polyplib.h \ cdecl.h \ llist.h libpolyp_la_CFLAGS = $(AM_CFLAGS) +libpolyp_la_LDFLAGS = -version-info 0:0:0 libpolyp_mainloop_la_SOURCES = mainloop-api.h mainloop-api.c \ mainloop.c mainloop.h \ mainloop-signal.c mainloop-signal.h libpolyp_mainloop_la_CFLAGS = $(AM_CFLAGS) libpolyp_mainloop_la_LIBADD = $(AM_LIBADD) libpolyp.la +libpolyp_mainloop_la_LDFLAGS = -version-info 0:0:0 libpolyp_error_la_SOURCES = polyplib-error.c polyplib-error.h libpolyp_error_la_CFLAGS = $(AM_CFLAGS) libpolyp_error_la_LIBADD = $(AM_LIBADD) libpolyp.la +libpolyp_error_la_LDFLAGS = -version-info 0:0:0 libpolyp_simple_la_SOURCES = polyplib-simple.c polyplib-simple.h libpolyp_simple_la_CFLAGS = $(AM_CFLAGS) libpolyp_simple_la_LIBADD = $(AM_LIBADD) libpolyp.la libpolyp-mainloop.la +libpolyp_simple_la_LDFLAGS = -version-info 0:0:0 + +libpolyp_mainloop_glib_la_SOURCES = glib-mainloop.h glib-mainloop.c +libpolyp_mainloop_glib_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) +libpolyp_mainloop_glib_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop.la $(GLIB20_LIBS) +libpolyp_mainloop_glib_la_LDFLAGS = -version-info 0:0:0 pacat_SOURCES = pacat.c pacat_LDADD = $(AM_LDADD) libpolyp.la libpolyp-error.la libpolyp-mainloop.la @@ -330,10 +345,6 @@ parec_simple_SOURCES = parec-simple.c parec_simple_LDADD = $(AM_LDADD) libpolyp.la libpolyp-simple.la libpolyp-error.la parec_simple_CFLAGS = $(AM_CFLAGS) -libpolyp_mainloop_glib_la_SOURCES = glib-mainloop.h glib-mainloop.c -libpolyp_mainloop_glib_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) -libpolyp_mainloop_glib_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop.la $(GLIB20_LIBS) - mainloop_test_SOURCES = mainloop-test.c mainloop_test_CFLAGS = $(AM_CFLAGS) mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop.la libpolyp.la diff --git a/polyp/cli-text.c b/polyp/cli-text.c index 558b53ca..000d6d34 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -89,7 +89,7 @@ char *pa_sink_list_to_string(struct pa_core *c) { for (sink = pa_idxset_first(c->sinks, &index); sink; sink = pa_idxset_next(c->sinks, &index)) { char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - pa_sample_snprint(ss, sizeof(ss), &sink->sample_spec); + pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec); assert(sink->monitor_source); pa_strbuf_printf( s, @@ -123,7 +123,7 @@ char *pa_source_list_to_string(struct pa_core *c) { for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) { char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - pa_sample_snprint(ss, sizeof(ss), &source->sample_spec); + pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec); pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\tsample_spec: <%s>\n", c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ', source->index, @@ -155,7 +155,7 @@ char *pa_source_output_list_to_string(struct pa_core *c) { for (o = pa_idxset_first(c->source_outputs, &index); o; o = pa_idxset_next(c->source_outputs, &index)) { char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - pa_sample_snprint(ss, sizeof(ss), &o->sample_spec); + pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec); assert(o->source); pa_strbuf_printf( s, " index: %u\n\tname: <%s>\n\tsource: <%u>\n\tsample_spec: <%s>\n", @@ -185,7 +185,7 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { for (i = pa_idxset_first(c->sink_inputs, &index); i; i = pa_idxset_next(c->sink_inputs, &index)) { char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - pa_sample_snprint(ss, sizeof(ss), &i->sample_spec); + pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec); assert(i->sink); pa_strbuf_printf( s, " index: %u\n\tname: <%s>\n\tsink: <%u>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tsample_spec: <%s>\n", @@ -221,7 +221,7 @@ char *pa_scache_list_to_string(struct pa_core *c) { while ((e = pa_hashmap_iterate(c->scache_hashmap, &state))) { double l; char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - pa_sample_snprint(ss, sizeof(ss), &e->sample_spec); + pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec); l = (double) e->memchunk.length / pa_bytes_per_second(&e->sample_spec); diff --git a/polyp/sample-util.c b/polyp/sample-util.c index 8f5558a4..6a09478f 100644 --- a/polyp/sample-util.c +++ b/polyp/sample-util.c @@ -64,7 +64,7 @@ void pa_silence_memory(void *p, size_t length, const struct pa_sample_spec *spec memset(p, c, length); } -size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const struct pa_sample_spec *spec, uint32_t volume) { +size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const struct pa_sample_spec *spec, pa_volume_t volume) { unsigned c, d; assert(channels && data && length && spec); assert(spec->format == PA_SAMPLE_S16NE); @@ -82,7 +82,7 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz if (d >= channels[c].chunk.length) return d; - if (volume == PA_VOLUME_MUTE) + if (volume == PA_VOLUME_MUTED) v = 0; else { v = *((int16_t*) (channels[c].chunk.memblock->data + channels[c].chunk.index + d)); @@ -94,7 +94,7 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz sum += v; } - if (volume == PA_VOLUME_MUTE) + if (volume == PA_VOLUME_MUTED) sum = 0; else if (volume != PA_VOLUME_NORM) sum = (int32_t) ((float) sum*volume/PA_VOLUME_NORM); @@ -108,7 +108,7 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz } -void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, uint32_t volume) { +void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, pa_volume_t volume) { int16_t *d; size_t n; assert(c && spec && (c->length % pa_frame_size(spec) == 0)); @@ -117,7 +117,7 @@ void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, if (volume == PA_VOLUME_NORM) return; - if (volume == PA_VOLUME_MUTE) { + if (volume == PA_VOLUME_MUTED) { pa_silence_memchunk(c, spec); return; } diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 7629bfb9..efa8c551 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -71,7 +71,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con r = pa_idxset_put(s->inputs, i, NULL); assert(r == 0); - pa_sample_snprint(st, sizeof(st), spec); + pa_sample_spec_snprint(st, sizeof(st), spec); fprintf(stderr, "sink-input: created %u \"%s\" on %u with sample spec \"%s\"\n", i->index, i->name, s->index, st); pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index); diff --git a/polyp/sink.c b/polyp/sink.c index eb3133ac..becaef9e 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -76,7 +76,7 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co r = pa_idxset_put(core->sinks, s, &s->index); assert(s->index != PA_IDXSET_INVALID && r >= 0); - pa_sample_snprint(st, sizeof(st), spec); + pa_sample_spec_snprint(st, sizeof(st), spec); fprintf(stderr, "sink: created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index); diff --git a/polyp/source.c b/polyp/source.c index 2c611651..6ab439d6 100644 --- a/polyp/source.c +++ b/polyp/source.c @@ -62,7 +62,7 @@ struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail r = pa_idxset_put(core->sources, s, &s->index); assert(s->index != PA_IDXSET_INVALID && r >= 0); - pa_sample_snprint(st, sizeof(st), spec); + pa_sample_spec_snprint(st, sizeof(st), spec); fprintf(stderr, "source: created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index); diff --git a/polyp/util.c b/polyp/util.c index 70766a06..2878c546 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -114,12 +114,16 @@ void pa_check_for_sigpipe(void) { struct sigaction sa; sigset_t set; +#ifdef HAVE_PTHREAD if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) { +#endif if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) { fprintf(stderr, __FILE__": sigprocmask() failed: %s\n", strerror(errno)); return; } +#ifdef HAVE_PTHREAD } +#endif if (sigismember(&set, SIGPIPE)) return; -- cgit From 2d6d3e5c474544fd8dc4e59695a20f8cbab976fe Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 17 Aug 2004 17:57:09 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@135 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/doc/todo b/doc/todo index aa65d339..887b8043 100644 --- a/doc/todo +++ b/doc/todo @@ -2,18 +2,14 @@ *** 0.2 *** -- future cancellation -- make mcalign merge chunks -- ref counting foo - pacat quit() ? - -- doxygen - - several files: copyright and config.h - enable searchdir -- autoscan *** 0.3 *** +- future cancellation +- make mcalign merge chunks +- use ref counting in more objects - move the global memblock statistics variables to the core - unix socket directories include user name - native library/protocol: -- cgit From 81822a751929fbc153282de3af447b9430d5c474 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 17 Aug 2004 18:53:42 +0000 Subject: fix x11 build disable prebuf on drain git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@136 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 2 +- polyp/memblockq.c | 5 +++++ polyp/memblockq.h | 5 ++++- polyp/pacat.c | 5 +---- polyp/protocol-native.c | 4 ++++ 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 1f982515..5a49201a 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -272,7 +272,7 @@ if !X_DISPLAY_MISSING module_x11_bell_la_SOURCES = module-x11-bell.c module_x11_bell_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) module_x11_bell_la_LDFLAGS = -module -avoid-version -module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) $(X_LIBS) $(X_EXTRA_LIB) +module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) endif libpolyp_la_SOURCES = polyplib.h \ diff --git a/polyp/memblockq.c b/polyp/memblockq.c index 4019c893..8f499df0 100644 --- a/polyp/memblockq.c +++ b/polyp/memblockq.c @@ -323,3 +323,8 @@ uint32_t pa_memblockq_get_minreq(struct pa_memblockq *bq) { assert(bq); return bq->minreq; } + +void pa_memblockq_prebuf_disable(struct pa_memblockq *bq) { + assert(bq); + bq->prebuf = 0; +} diff --git a/polyp/memblockq.h b/polyp/memblockq.h index e6ad01db..40184703 100644 --- a/polyp/memblockq.h +++ b/polyp/memblockq.h @@ -76,7 +76,10 @@ uint32_t pa_memblockq_get_length(struct pa_memblockq *bq); /* Return how many bytes are missing in queue to the specified fill amount */ uint32_t pa_memblockq_missing(struct pa_memblockq *bq); - +/* Returns the minimal request value */ uint32_t pa_memblockq_get_minreq(struct pa_memblockq *bq); +/* Force disabling of pre-buf even when the pre-buffer is not yet filled */ +void pa_memblockq_prebuf_disable(struct pa_memblockq *bq); + #endif diff --git a/polyp/pacat.c b/polyp/pacat.c index 4f3bf001..2c7044b8 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -113,16 +113,13 @@ static void stream_state_callback(struct pa_stream *s, void *userdata) { switch (pa_stream_get_state(s)) { case PA_STREAM_CREATING: + case PA_STREAM_TERMINATED: break; case PA_STREAM_READY: fprintf(stderr, "Stream successfully created\n"); break; - case PA_STREAM_TERMINATED: - quit(0); - break; - case PA_STREAM_FAILED: default: fprintf(stderr, "Stream errror: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 1fafc984..e86c78f0 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -748,12 +748,16 @@ static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t comm } s->drain_request = 0; + + pa_memblockq_prebuf_disable(s->memblockq); if (!pa_memblockq_is_readable(s->memblockq)) pa_pstream_send_simple_ack(c->pstream, tag); else { s->drain_request = 1; s->drain_tag = tag; + + pa_sink_notify(s->sink_input->sink); } } -- cgit From e75b65715b2fc9a3363bd4ac598fe02888b7ed21 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 17 Aug 2004 19:37:29 +0000 Subject: remove global memblock statistic variables in favor of memblock_stat objects git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@137 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 -- polyp/cli-command.c | 6 ++-- polyp/core.c | 4 +++ polyp/core.h | 3 ++ polyp/memblock.c | 71 +++++++++++++++++++++++++++++++++------------ polyp/memblock.h | 24 +++++++++++---- polyp/memblockq.c | 7 +++-- polyp/memblockq.h | 3 +- polyp/memchunk.c | 10 ++++--- polyp/memchunk.h | 4 +-- polyp/module-alsa-sink.c | 2 +- polyp/module-alsa-source.c | 2 +- polyp/module-oss-mmap.c | 4 +-- polyp/module-oss.c | 4 +-- polyp/pactl.c | 4 ++- polyp/polyplib-context.c | 8 +++-- polyp/polyplib-internal.h | 2 ++ polyp/polyplib-introspect.c | 6 ++-- polyp/polyplib-introspect.h | 6 ++-- polyp/polyplib-stream.c | 4 +-- polyp/protocol-esound.c | 8 ++--- polyp/protocol-native.c | 14 +++++---- polyp/protocol-simple.c | 6 ++-- polyp/pstream.c | 8 +++-- polyp/pstream.h | 2 +- polyp/resampler.c | 8 +++-- polyp/resampler.h | 2 +- polyp/sink-input.c | 2 +- polyp/sink.c | 4 +-- polyp/sound-file.c | 4 +-- polyp/sound-file.h | 2 +- polyp/source-output.c | 2 +- 32 files changed, 158 insertions(+), 80 deletions(-) diff --git a/doc/todo b/doc/todo index 887b8043..7814321d 100644 --- a/doc/todo +++ b/doc/todo @@ -2,7 +2,6 @@ *** 0.2 *** -- pacat quit() ? - several files: copyright and config.h - enable searchdir @@ -10,7 +9,6 @@ - future cancellation - make mcalign merge chunks - use ref counting in more objects -- move the global memblock statistics variables to the core - unix socket directories include user name - native library/protocol: module load/unload diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 8459d71b..5a8ff177 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -210,7 +210,7 @@ static int pa_cli_command_source_outputs(struct pa_core *c, struct pa_tokenizer 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_get_count(), pa_memblock_get_total()); + pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %u bytes.\nMemory blocks allocated during the whole lifetime: %u, size: %u bytes.\n", c->memblock_stat->total, c->memblock_stat->total_size, c->memblock_stat->allocated, c->memblock_stat->allocated_size); return 0; } @@ -504,7 +504,7 @@ static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t, return -1; } - if (pa_sound_file_load(fname, &ss, &chunk) < 0) { + if (pa_sound_file_load(fname, &ss, &chunk, c->memblock_stat) < 0) { pa_strbuf_puts(buf, "Failed to load sound file.\n"); return -1; } @@ -532,7 +532,7 @@ static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, s return -1; } - if (pa_sound_file_load(fname, &ss, &chunk) < 0) { + if (pa_sound_file_load(fname, &ss, &chunk, c->memblock_stat) < 0) { pa_strbuf_puts(buf, "Failed to load sound file.\n"); return -1; } diff --git a/polyp/core.c b/polyp/core.c index 55944aad..b43eb639 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -68,6 +68,8 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->subscription_defer_event = NULL; c->subscription_event_queue = NULL; c->subscriptions = NULL; + + c->memblock_stat = pa_memblock_stat_new(); pa_check_for_sigpipe(); @@ -102,6 +104,8 @@ void pa_core_free(struct pa_core *c) { pa_xfree(c->default_source_name); pa_xfree(c->default_sink_name); + + pa_memblock_stat_unref(c->memblock_stat); pa_xfree(c); }; diff --git a/polyp/core.h b/polyp/core.h index 43691771..c0a2d6d8 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -26,6 +26,7 @@ #include "hashmap.h" #include "mainloop-api.h" #include "sample.h" +#include "memblock.h" struct pa_core { struct pa_mainloop_api *mainloop; @@ -43,6 +44,8 @@ struct pa_core { struct pa_defer_event *subscription_defer_event; struct pa_queue *subscription_event_queue; struct pa_subscription *subscriptions; + + struct pa_memblock_stat *memblock_stat; }; struct pa_core* pa_core_new(struct pa_mainloop_api *m); diff --git a/polyp/memblock.c b/polyp/memblock.c index a4452efa..500d8b20 100644 --- a/polyp/memblock.c +++ b/polyp/memblock.c @@ -31,45 +31,63 @@ #include "memblock.h" #include "xmalloc.h" -static unsigned memblock_count = 0, memblock_total = 0; +static void stat_add(struct pa_memblock*m, struct pa_memblock_stat *s) { + assert(m); + + m->stat = pa_memblock_stat_ref(s); + s->total++; + s->allocated++; + s->total_size += m->length; + s->allocated_size += m->length; +} + +static void stat_remove(struct pa_memblock *m) { + assert(m); + + if (!m->stat) + return; -struct pa_memblock *pa_memblock_new(size_t length) { + m->stat->total--; + m->stat->total_size -= m->length; + + pa_memblock_stat_unref(m->stat); + m->stat = NULL; +} + +struct pa_memblock *pa_memblock_new(size_t length, struct pa_memblock_stat*s) { struct pa_memblock *b = pa_xmalloc(sizeof(struct pa_memblock)+length); b->type = PA_MEMBLOCK_APPENDED; b->ref = 1; b->length = length; b->data = b+1; b->free_cb = NULL; - memblock_count++; - memblock_total += length; + stat_add(b, s); return b; } -struct pa_memblock *pa_memblock_new_fixed(void *d, size_t length) { +struct pa_memblock *pa_memblock_new_fixed(void *d, size_t length, struct pa_memblock_stat*s) { struct pa_memblock *b = pa_xmalloc(sizeof(struct pa_memblock)); b->type = PA_MEMBLOCK_FIXED; b->ref = 1; b->length = length; b->data = d; b->free_cb = NULL; - memblock_count++; - memblock_total += length; + stat_add(b, s); return b; } -struct pa_memblock *pa_memblock_new_dynamic(void *d, size_t length) { +struct pa_memblock *pa_memblock_new_dynamic(void *d, size_t length, struct pa_memblock_stat*s) { struct pa_memblock *b = pa_xmalloc(sizeof(struct pa_memblock)); b->type = PA_MEMBLOCK_DYNAMIC; b->ref = 1; b->length = length; b->data = d; b->free_cb = NULL; - memblock_count++; - memblock_total += length; + stat_add(b, s); return b; } -struct pa_memblock *pa_memblock_new_user(void *d, size_t length, void (*free_cb)(void *p)) { +struct pa_memblock *pa_memblock_new_user(void *d, size_t length, void (*free_cb)(void *p), struct pa_memblock_stat*s) { struct pa_memblock *b; assert(d && length && free_cb); b = pa_xmalloc(sizeof(struct pa_memblock)); @@ -78,8 +96,7 @@ struct pa_memblock *pa_memblock_new_user(void *d, size_t length, void (*free_cb) b->length = length; b->data = d; b->free_cb = free_cb; - memblock_count++; - memblock_total += length; + stat_add(b, s); return b; } @@ -93,8 +110,7 @@ void pa_memblock_unref(struct pa_memblock*b) { assert(b && b->ref >= 1); if ((--(b->ref)) == 0) { - memblock_count--; - memblock_total -= b->length; + stat_remove(b); if (b->type == PA_MEMBLOCK_USER) { assert(b->free_cb); @@ -118,10 +134,27 @@ void pa_memblock_unref_fixed(struct pa_memblock *b) { } } -unsigned pa_memblock_get_count(void) { - return memblock_count; +struct pa_memblock_stat* pa_memblock_stat_new(void) { + struct pa_memblock_stat *s; + + s = pa_xmalloc(sizeof(struct pa_memblock_stat)); + s->ref = 1; + s->total = s->total_size = s->allocated = s->allocated_size = 0; + + return s; +} + +void pa_memblock_stat_unref(struct pa_memblock_stat *s) { + assert(s && s->ref >= 1); + + if (!(--(s->ref))) { + assert(!s->total); + pa_xfree(s); + } } -unsigned pa_memblock_get_total(void) { - return memblock_total; +struct pa_memblock_stat * pa_memblock_stat_ref(struct pa_memblock_stat *s) { + assert(s); + s->ref++; + return s; } diff --git a/polyp/memblock.h b/polyp/memblock.h index 6e79aa3e..949a0a08 100644 --- a/polyp/memblock.h +++ b/polyp/memblock.h @@ -27,25 +27,37 @@ enum pa_memblock_type { PA_MEMBLOCK_FIXED, PA_MEMBLOCK_APPENDED, PA_MEMBLOCK_DYNAMIC, PA_MEMBLOCK_USER }; +struct pa_memblock_stat; + struct pa_memblock { enum pa_memblock_type type; unsigned ref; size_t length; void *data; void (*free_cb)(void *p); + struct pa_memblock_stat *stat; }; -struct pa_memblock *pa_memblock_new(size_t length); -struct pa_memblock *pa_memblock_new_fixed(void *data, size_t length); -struct pa_memblock *pa_memblock_new_dynamic(void *data, size_t length); -struct pa_memblock *pa_memblock_new_user(void *data, size_t length, void (*free_cb)(void *p)); +struct pa_memblock *pa_memblock_new(size_t length, struct pa_memblock_stat*s); +struct pa_memblock *pa_memblock_new_fixed(void *data, size_t length, struct pa_memblock_stat*s); +struct pa_memblock *pa_memblock_new_dynamic(void *data, size_t length, struct pa_memblock_stat*s); +struct pa_memblock *pa_memblock_new_user(void *data, size_t length, void (*free_cb)(void *p), struct pa_memblock_stat*s); void pa_memblock_unref(struct pa_memblock*b); struct pa_memblock* pa_memblock_ref(struct pa_memblock*b); void pa_memblock_unref_fixed(struct pa_memblock*b); -unsigned pa_memblock_get_count(void); -unsigned pa_memblock_get_total(void); +struct pa_memblock_stat { + int ref; + unsigned total; + unsigned total_size; + unsigned allocated; + unsigned allocated_size; +}; + +struct pa_memblock_stat* pa_memblock_stat_new(void); +void pa_memblock_stat_unref(struct pa_memblock_stat *s); +struct pa_memblock_stat * pa_memblock_stat_ref(struct pa_memblock_stat *s); #endif diff --git a/polyp/memblockq.c b/polyp/memblockq.c index 8f499df0..bc5d7437 100644 --- a/polyp/memblockq.c +++ b/polyp/memblockq.c @@ -45,9 +45,10 @@ struct pa_memblockq { int measure_delay; uint32_t delay; struct pa_mcalign *mcalign; + struct pa_memblock_stat *memblock_stat; }; -struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t base, size_t prebuf, size_t minreq) { +struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t base, size_t prebuf, size_t minreq, struct pa_memblock_stat *s) { struct pa_memblockq* bq; assert(maxlength && base && maxlength); @@ -83,6 +84,8 @@ struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t b bq->delay = 0; bq->mcalign = NULL; + + bq->memblock_stat = s; return bq; } @@ -306,7 +309,7 @@ void pa_memblockq_push_align(struct pa_memblockq* bq, const struct pa_memchunk * } if (!bq->mcalign) { - bq->mcalign = pa_mcalign_new(bq->base); + bq->mcalign = pa_mcalign_new(bq->base, bq->memblock_stat); assert(bq->mcalign); } diff --git a/polyp/memblockq.h b/polyp/memblockq.h index 40184703..af8fa374 100644 --- a/polyp/memblockq.h +++ b/polyp/memblockq.h @@ -40,7 +40,8 @@ struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t base, size_t prebuf, - size_t minreq); + size_t minreq, + struct pa_memblock_stat *s); void pa_memblockq_free(struct pa_memblockq*bq); /* Push a new memory chunk into the queue. Optionally specify a value for future cancellation. This is currently not implemented, however! */ diff --git a/polyp/memchunk.c b/polyp/memchunk.c index 77e1b7dd..5913c6e3 100644 --- a/polyp/memchunk.c +++ b/polyp/memchunk.c @@ -31,14 +31,14 @@ #include "memchunk.h" #include "xmalloc.h" -void pa_memchunk_make_writable(struct pa_memchunk *c) { +void pa_memchunk_make_writable(struct pa_memchunk *c, struct pa_memblock_stat *s) { struct pa_memblock *n; assert(c && c->memblock && c->memblock->ref >= 1); if (c->memblock->ref == 1) return; - n = pa_memblock_new(c->length); + n = pa_memblock_new(c->length, s); assert(n); memcpy(n->data, c->memblock->data+c->index, c->length); pa_memblock_unref(c->memblock); @@ -52,9 +52,10 @@ struct pa_mcalign { struct pa_memchunk chunk; uint8_t *buffer; size_t buffer_fill; + struct pa_memblock_stat *memblock_stat; }; -struct pa_mcalign *pa_mcalign_new(size_t base) { +struct pa_mcalign *pa_mcalign_new(size_t base, struct pa_memblock_stat *s) { struct pa_mcalign *m; assert(base); @@ -64,6 +65,7 @@ struct pa_mcalign *pa_mcalign_new(size_t base) { m->chunk.length = m->chunk.index = 0; m->buffer = NULL; m->buffer_fill = 0; + m->memblock_stat = s; return m; } @@ -111,7 +113,7 @@ int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c) { assert(m->buffer_fill <= m->base); if (m->buffer_fill == m->base) { - c->memblock = pa_memblock_new_dynamic(m->buffer, m->base); + c->memblock = pa_memblock_new_dynamic(m->buffer, m->base, m->memblock_stat); assert(c->memblock); c->index = 0; c->length = m->base; diff --git a/polyp/memchunk.h b/polyp/memchunk.h index 341c145c..3a592f04 100644 --- a/polyp/memchunk.h +++ b/polyp/memchunk.h @@ -29,11 +29,11 @@ struct pa_memchunk { size_t index, length; }; -void pa_memchunk_make_writable(struct pa_memchunk *c); +void pa_memchunk_make_writable(struct pa_memchunk *c, struct pa_memblock_stat *s); struct pa_mcalign; -struct pa_mcalign *pa_mcalign_new(size_t base); +struct pa_mcalign *pa_mcalign_new(size_t base, struct pa_memblock_stat *s); void pa_mcalign_free(struct pa_mcalign *m); void pa_mcalign_push(struct pa_mcalign *m, const struct pa_memchunk *c); int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c); diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index 5b4a7b73..06b07f33 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -217,7 +217,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { fprintf(stderr, __FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); - u->silence.memblock = pa_memblock_new(u->silence.length = u->fragment_size); + u->silence.memblock = pa_memblock_new(u->silence.length = u->fragment_size, c->memblock_stat); assert(u->silence.memblock); pa_silence_memblock(u->silence.memblock, &ss); u->silence.index = 0; diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index df716f73..9dc623d4 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -89,7 +89,7 @@ static void do_read(struct userdata *u) { size_t l; if (!u->memchunk.memblock) { - u->memchunk.memblock = pa_memblock_new(u->memchunk.length = u->fragment_size); + u->memchunk.memblock = pa_memblock_new(u->memchunk.length = u->fragment_size, u->source->core->memblock_stat); u->memchunk.index = 0; } diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index ea768a98..7c7750d1 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -100,7 +100,7 @@ static void out_fill_memblocks(struct userdata *u, unsigned n) { if (u->out_memblocks[u->out_current]) pa_memblock_unref_fixed(u->out_memblocks[u->out_current]); - chunk.memblock = u->out_memblocks[u->out_current] = pa_memblock_new_fixed(u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size); + chunk.memblock = u->out_memblocks[u->out_current] = pa_memblock_new_fixed(u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size, u->core->memblock_stat); assert(chunk.memblock); chunk.length = chunk.memblock->length; chunk.index = 0; @@ -141,7 +141,7 @@ static void in_post_memblocks(struct userdata *u, unsigned n) { struct pa_memchunk chunk; if (!u->in_memblocks[u->in_current]) { - chunk.memblock = u->in_memblocks[u->in_current] = pa_memblock_new_fixed(u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size); + chunk.memblock = u->in_memblocks[u->in_current] = pa_memblock_new_fixed(u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size, u->core->memblock_stat); chunk.length = chunk.memblock->length; chunk.index = 0; diff --git a/polyp/module-oss.c b/polyp/module-oss.c index a8db4a33..d5517b5e 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -131,7 +131,7 @@ static void do_read(struct userdata *u) { update_usage(u); - memchunk.memblock = pa_memblock_new(u->in_fragment_size); + memchunk.memblock = pa_memblock_new(u->in_fragment_size, u->core->memblock_stat); assert(memchunk.memblock); if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); @@ -273,7 +273,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { u->out_fragment_size = out_frag_size; u->in_fragment_size = in_frag_size; - u->silence.memblock = pa_memblock_new(u->silence.length = u->out_fragment_size); + u->silence.memblock = pa_memblock_new(u->silence.length = u->out_fragment_size, u->core->memblock_stat); assert(u->silence.memblock); pa_silence_memblock(u->silence.memblock, &ss); u->silence.index = 0; diff --git a/polyp/pactl.c b/polyp/pactl.c index 0ff2aa90..f2556706 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -88,7 +88,9 @@ static void stat_callback(struct pa_context *c, const struct pa_stat_info *i, vo return; } - fprintf(stderr, "Currently in use: %u blocks containing %u bytes total.\n", i->memblock_count, i->memblock_total); + fprintf(stderr, "Currently in use: %u blocks containing %u bytes total.\n" + "Allocated during whole lifetime: %u blocks containing %u bytes total.\n", + i->memblock_total, i->memblock_total_size, i->memblock_allocated, i->memblock_allocated_size); drain(); } diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 2a0c24a5..fcf3f6b9 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -78,6 +78,8 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * c->subscribe_callback = NULL; c->subscribe_userdata = NULL; + c->memblock_stat = pa_memblock_stat_new(); + pa_check_for_sigpipe(); return c; } @@ -104,7 +106,9 @@ static void context_free(struct pa_context *c) { pa_dynarray_free(c->record_streams, NULL, NULL); if (c->playback_streams) pa_dynarray_free(c->playback_streams, NULL, NULL); - + + pa_memblock_stat_unref(c->memblock_stat); + pa_xfree(c->name); pa_xfree(c); } @@ -280,7 +284,7 @@ static void on_connection(struct pa_socket_client *client, struct pa_iochannel*i } assert(!c->pstream); - c->pstream = pa_pstream_new(c->mainloop, io); + c->pstream = pa_pstream_new(c->mainloop, io, c->memblock_stat); assert(c->pstream); pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index c8228a86..fd6cd38f 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -73,6 +73,8 @@ struct pa_context { void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); void *subscribe_userdata; + + struct pa_memblock_stat *memblock_stat; }; struct pa_stream { diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index 9a7ec157..0efc599d 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -42,8 +42,10 @@ static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uin goto finish; p = NULL; - } else if (pa_tagstruct_getu32(t, &i.memblock_count) < 0 || - pa_tagstruct_getu32(t, &i.memblock_total) < 0 || + } else if (pa_tagstruct_getu32(t, &i.memblock_total) < 0 || + pa_tagstruct_getu32(t, &i.memblock_total_size) < 0 || + pa_tagstruct_getu32(t, &i.memblock_allocated) < 0 || + pa_tagstruct_getu32(t, &i.memblock_allocated_size) < 0 || !pa_tagstruct_eof(t)) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index dfa24ed5..c453eb2f 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -130,8 +130,10 @@ struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint /** Memory block statistics */ struct pa_stat_info { - uint32_t memblock_count; /**< Allocated memory blocks */ - uint32_t memblock_total; /**< Total size of allocated memory blocks */ + uint32_t memblock_total; /**< Currently allocated memory blocks */ + uint32_t memblock_total_size; /**< Currentl total size of allocated memory blocks */ + uint32_t memblock_allocated; /**< Allocated memory blocks during the whole lifetime of the daemon */ + uint32_t memblock_allocated_size; /**< Total size of all memory blocks allocated during the whole lifetime of the daemon */ }; /** Get daemon memory block statistics */ diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 362dbad1..2b591f36 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -272,10 +272,10 @@ void pa_stream_write(struct pa_stream *s, const void *data, size_t length, void assert(s && s->context && data && length && s->state == PA_STREAM_READY && s->ref >= 1); if (free_cb) { - chunk.memblock = pa_memblock_new_user((void*) data, length, free_cb); + chunk.memblock = pa_memblock_new_user((void*) data, length, free_cb, s->context->memblock_stat); assert(chunk.memblock && chunk.memblock->data); } else { - chunk.memblock = pa_memblock_new(length); + chunk.memblock = pa_memblock_new(length, s->context->memblock_stat); assert(chunk.memblock && chunk.memblock->data); memcpy(chunk.memblock->data, data, length); } diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index fb639b7f..f5efa419 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -291,7 +291,7 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons assert(!c->input_memblockq); l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); - c->input_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&ss), l/2, l/PLAYBACK_BUFFER_FRAGMENTS); + c->input_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&ss), l/2, l/PLAYBACK_BUFFER_FRAGMENTS, c->protocol->core->memblock_stat); assert(c->input_memblockq); pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2); c->playback.fragment_size = l/10; @@ -355,7 +355,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co assert(!c->output_memblockq); l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); - c->output_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&ss), 0, 0); + c->output_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&ss), 0, 0, c->protocol->core->memblock_stat); assert(c->output_memblockq); pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); @@ -574,7 +574,7 @@ static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, con name[sizeof(name)-1] = 0; assert(!c->scache_memchunk.memblock); - c->scache_memchunk.memblock = pa_memblock_new(sc_length); + c->scache_memchunk.memblock = pa_memblock_new(sc_length, c->protocol->core->memblock_stat); c->scache_memchunk.index = 0; c->scache_memchunk.length = sc_length; c->scache_sample_spec = ss; @@ -778,7 +778,7 @@ static int do_read(struct connection *c) { } if (!c->playback.current_memblock) { - c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2); + c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2, c->protocol->core->memblock_stat); assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); c->playback.memblock_index = 0; } diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index e86c78f0..060b4241 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -229,7 +229,7 @@ static struct record_stream* record_stream_new(struct connection *c, struct pa_s s->source_output->owner = c->protocol->module; s->source_output->client = c->client; - s->memblockq = pa_memblockq_new(maxlength, 0, base = pa_frame_size(ss), 0, 0); + s->memblockq = pa_memblockq_new(maxlength, 0, base = pa_frame_size(ss), 0, 0, c->protocol->core->memblock_stat); assert(s->memblockq); s->fragment_size = (fragment_size/base)*base; @@ -274,7 +274,7 @@ static struct playback_stream* playback_stream_new(struct connection *c, struct s->sink_input->owner = c->protocol->module; s->sink_input->client = c->client; - s->memblockq = pa_memblockq_new(maxlength, tlength, pa_frame_size(ss), prebuf, minreq); + s->memblockq = pa_memblockq_new(maxlength, tlength, pa_frame_size(ss), prebuf, minreq, c->protocol->core->memblock_stat); assert(s->memblockq); s->requested_bytes = 0; @@ -780,8 +780,10 @@ static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag assert(reply); pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); pa_tagstruct_putu32(reply, tag); - pa_tagstruct_putu32(reply, pa_memblock_get_count()); - pa_tagstruct_putu32(reply, pa_memblock_get_total()); + pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->total); + pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->total_size); + pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->allocated); + pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->allocated_size); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -1313,7 +1315,7 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, in u->length = 0; fprintf(stderr, "COPY\n"); } else { - u->memchunk.memblock = pa_memblock_new(u->length); + u->memchunk.memblock = pa_memblock_new(u->length, c->protocol->core->memblock_stat); u->memchunk.index = u->memchunk.length = 0; } } @@ -1372,7 +1374,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->client->userdata = c; c->client->owner = p->module; - c->pstream = pa_pstream_new(p->core->mainloop, io); + c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->memblock_stat); assert(c->pstream); pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index bd0e1488..58343486 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -115,7 +115,7 @@ static int do_read(struct connection *c) { } if (!c->playback.current_memblock) { - c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2); + c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2, c->protocol->core->memblock_stat); assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); c->playback.memblock_index = 0; } @@ -318,7 +318,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->sink_input->userdata = c; l = (size_t) (pa_bytes_per_second(&p->sample_spec)*PLAYBACK_BUFFER_SECONDS); - c->input_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&p->sample_spec), l/2, l/PLAYBACK_BUFFER_FRAGMENTS); + c->input_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&p->sample_spec), l/2, l/PLAYBACK_BUFFER_FRAGMENTS, p->core->memblock_stat); assert(c->input_memblockq); pa_iochannel_socket_set_rcvbuf(io, l/PLAYBACK_BUFFER_FRAGMENTS*5); c->playback.fragment_size = l/10; @@ -346,7 +346,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->source_output->userdata = c; l = (size_t) (pa_bytes_per_second(&p->sample_spec)*RECORD_BUFFER_SECONDS); - c->output_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&p->sample_spec), 0, 0); + c->output_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&p->sample_spec), 0, 0, p->core->memblock_stat); pa_iochannel_socket_set_sndbuf(io, l/RECORD_BUFFER_FRAGMENTS*2); } diff --git a/polyp/pstream.c b/polyp/pstream.c index 2d147e03..5664e18a 100644 --- a/polyp/pstream.c +++ b/polyp/pstream.c @@ -91,6 +91,8 @@ struct pa_pstream { void (*drain_callback)(struct pa_pstream *p, void *userdata); void *drain_userdata; + + struct pa_memblock_stat *memblock_stat; }; static void do_write(struct pa_pstream *p); @@ -129,7 +131,7 @@ static void defer_callback(struct pa_mainloop_api *m, struct pa_defer_event *e, do_something(p); } -struct pa_pstream *pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel *io) { +struct pa_pstream *pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel *io, struct pa_memblock_stat *s) { struct pa_pstream *p; assert(io); @@ -165,6 +167,8 @@ struct pa_pstream *pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel p->drain_callback = NULL; p->drain_userdata = NULL; + p->memblock_stat = s; + return p; } @@ -350,7 +354,7 @@ static void do_read(struct pa_pstream *p) { p->read.data = p->read.packet->data; } else { /* Frame is a memblock frame */ - p->read.memblock = pa_memblock_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])); + p->read.memblock = pa_memblock_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]), p->memblock_stat); assert(p->read.memblock); p->read.data = p->read.memblock->data; } diff --git a/polyp/pstream.h b/polyp/pstream.h index ff70a855..9a289507 100644 --- a/polyp/pstream.h +++ b/polyp/pstream.h @@ -32,7 +32,7 @@ struct pa_pstream; -struct pa_pstream* pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel *io); +struct pa_pstream* pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel *io, struct pa_memblock_stat *s); void pa_pstream_unref(struct pa_pstream*p); struct pa_pstream* pa_pstream_ref(struct pa_pstream*p); diff --git a/polyp/resampler.c b/polyp/resampler.c index 241f97c4..ed44cbb7 100644 --- a/polyp/resampler.c +++ b/polyp/resampler.c @@ -43,9 +43,11 @@ struct pa_resampler { pa_convert_to_float32_func_t to_float32_func; pa_convert_from_float32_func_t from_float32_func; SRC_STATE *src_state; + + struct pa_memblock_stat *memblock_stat; }; -struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b) { +struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b, struct pa_memblock_stat *s) { struct pa_resampler *r = NULL; int err; assert(a && b && pa_sample_spec_valid(a) && pa_sample_spec_valid(b)); @@ -82,6 +84,8 @@ struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const stru r->from_float32_func = pa_get_convert_from_float32_function(b->format); assert(r->to_float32_func && r->from_float32_func); + + r->memblock_stat = s; return r; @@ -134,7 +138,7 @@ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, stru eff_ons = ons; } - out->memblock = pa_memblock_new(out->length = (ons*r->o_sz)); + out->memblock = pa_memblock_new(out->length = (ons*r->o_sz), r->memblock_stat); out->index = 0; assert(out->memblock); diff --git a/polyp/resampler.h b/polyp/resampler.h index 8e979478..e23d145d 100644 --- a/polyp/resampler.h +++ b/polyp/resampler.h @@ -28,7 +28,7 @@ struct pa_resampler; -struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b); +struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b, struct pa_memblock_stat *s); void pa_resampler_free(struct pa_resampler *r); size_t pa_resampler_request(struct pa_resampler *r, size_t out_length); diff --git a/polyp/sink-input.c b/polyp/sink-input.c index efa8c551..c57dd8e0 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -43,7 +43,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con assert(s && spec); if (!pa_sample_spec_equal(spec, &s->sample_spec)) - if (!(resampler = pa_resampler_new(spec, &s->sample_spec))) + if (!(resampler = pa_resampler_new(spec, &s->sample_spec, s->core->memblock_stat))) return NULL; i = pa_xmalloc(sizeof(struct pa_sink_input)); diff --git a/polyp/sink.c b/polyp/sink.c index becaef9e..62b9a7af 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -179,11 +179,11 @@ int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result) volume = pa_volume_multiply(s->volume, info[0].volume); if (volume != PA_VOLUME_NORM) { - pa_memchunk_make_writable(result); + pa_memchunk_make_writable(result, s->core->memblock_stat); pa_volume_memchunk(result, &s->sample_spec, volume); } } else { - result->memblock = pa_memblock_new(length); + result->memblock = pa_memblock_new(length, s->core->memblock_stat); assert(result->memblock); result->length = l = pa_mix(info, n, result->memblock->data, length, &s->sample_spec, s->volume); diff --git a/polyp/sound-file.c b/polyp/sound-file.c index b0df7185..bf635fa0 100644 --- a/polyp/sound-file.c +++ b/polyp/sound-file.c @@ -8,7 +8,7 @@ #define MAX_FILE_SIZE (1024*1024) -int pa_sound_file_load(const char *fname, struct pa_sample_spec *ss, struct pa_memchunk *chunk) { +int pa_sound_file_load(const char *fname, struct pa_sample_spec *ss, struct pa_memchunk *chunk, struct pa_memblock_stat *s) { SNDFILE*sf = NULL; SF_INFO sfinfo; int ret = -1; @@ -39,7 +39,7 @@ int pa_sound_file_load(const char *fname, struct pa_sample_spec *ss, struct pa_m goto finish; } - chunk->memblock = pa_memblock_new(l); + chunk->memblock = pa_memblock_new(l, s); assert(chunk->memblock); chunk->index = 0; chunk->length = l; diff --git a/polyp/sound-file.h b/polyp/sound-file.h index 3a6fa415..62a4a371 100644 --- a/polyp/sound-file.h +++ b/polyp/sound-file.h @@ -4,6 +4,6 @@ #include "memchunk.h" #include "sample.h" -int pa_sound_file_load(const char *fname, struct pa_sample_spec *ss, struct pa_memchunk *chunk); +int pa_sound_file_load(const char *fname, struct pa_sample_spec *ss, struct pa_memchunk *chunk, struct pa_memblock_stat *s); #endif diff --git a/polyp/source-output.c b/polyp/source-output.c index c53831c7..b8083a79 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -38,7 +38,7 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n assert(s && spec); if (!pa_sample_spec_equal(&s->sample_spec, spec)) - if (!(resampler = pa_resampler_new(&s->sample_spec, spec))) + if (!(resampler = pa_resampler_new(&s->sample_spec, spec, s->core->memblock_stat))) return NULL; o = pa_xmalloc(sizeof(struct pa_source_output)); -- cgit From ac595189fdc311ae30fa8061cd5bbaeb72fc0ef1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 17 Aug 2004 19:47:42 +0000 Subject: add missing copyright headers git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@138 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 ++- polyp/autoload.c | 25 +++++++++++++++++++++++++ polyp/autoload.h | 21 +++++++++++++++++++++ polyp/cdecl.h | 21 +++++++++++++++++++++ polyp/debug.h | 23 ++++++++++++++++++++++- polyp/glib-mainloop.c | 25 +++++++++++++++++++++++++ polyp/glib-mainloop.h | 21 +++++++++++++++++++++ polyp/llist.h | 21 +++++++++++++++++++++ polyp/mainloop-test.c | 25 +++++++++++++++++++++++++ polyp/module-x11-bell.c | 25 +++++++++++++++++++++++++ polyp/play-memchunk.c | 25 +++++++++++++++++++++++++ polyp/play-memchunk.h | 22 ++++++++++++++++++++++ polyp/polyplib-operation.c | 25 +++++++++++++++++++++++++ polyp/scache.c | 25 +++++++++++++++++++++++++ polyp/scache.h | 21 +++++++++++++++++++++ polyp/sound-file.c | 25 +++++++++++++++++++++++++ polyp/sound-file.h | 21 +++++++++++++++++++++ polyp/subscribe.c | 25 +++++++++++++++++++++++++ polyp/subscribe.h | 21 +++++++++++++++++++++ polyp/xmalloc.c | 25 +++++++++++++++++++++++++ polyp/xmalloc.h | 21 +++++++++++++++++++++ 21 files changed, 464 insertions(+), 2 deletions(-) diff --git a/doc/todo b/doc/todo index 7814321d..c4b390de 100644 --- a/doc/todo +++ b/doc/todo @@ -2,8 +2,9 @@ *** 0.2 *** -- several files: copyright and config.h - enable searchdir +- run dep script +- version routines *** 0.3 *** - future cancellation diff --git a/polyp/autoload.c b/polyp/autoload.c index f0d70d2d..988b0921 100644 --- a/polyp/autoload.c +++ b/polyp/autoload.c @@ -1,3 +1,28 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/polyp/autoload.h b/polyp/autoload.h index f1862e77..004dae26 100644 --- a/polyp/autoload.h +++ b/polyp/autoload.h @@ -1,6 +1,27 @@ #ifndef fooautoloadhfoo #define fooautoloadhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "namereg.h" struct pa_autoload_entry { diff --git a/polyp/cdecl.h b/polyp/cdecl.h index 39880a47..7102f649 100644 --- a/polyp/cdecl.h +++ b/polyp/cdecl.h @@ -1,6 +1,27 @@ #ifndef foocdeclhfoo #define foocdeclhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + /** \file * C++ compatibility support */ diff --git a/polyp/debug.h b/polyp/debug.h index fb2b889e..c6ec5c7e 100644 --- a/polyp/debug.h +++ b/polyp/debug.h @@ -1,7 +1,28 @@ #ifndef foodebughfoo #define foodebughfoo -/* A nice trick for debuggers, working on x86 only */ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* A nice trick for debuggers, working on x86 with GCC only */ #define DEBUG_TRAP __asm__("int $3") diff --git a/polyp/glib-mainloop.c b/polyp/glib-mainloop.c index 9abb1e47..a91f48ec 100644 --- a/polyp/glib-mainloop.c +++ b/polyp/glib-mainloop.c @@ -1,3 +1,28 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include "glib-mainloop.h" diff --git a/polyp/glib-mainloop.h b/polyp/glib-mainloop.h index dbbf2a62..1fc7f64a 100644 --- a/polyp/glib-mainloop.h +++ b/polyp/glib-mainloop.h @@ -1,6 +1,27 @@ #ifndef fooglibmainloophfoo #define fooglibmainloophfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include "mainloop-api.h" diff --git a/polyp/llist.h b/polyp/llist.h index 1f145de2..12a33e90 100644 --- a/polyp/llist.h +++ b/polyp/llist.h @@ -1,6 +1,27 @@ #ifndef foollistfoo #define foollistfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #define PA_LLIST_HEAD(t,name) t *name #define PA_LLIST_FIELDS(t) t *next, *prev; diff --git a/polyp/mainloop-test.c b/polyp/mainloop-test.c index 31caaa03..c2517065 100644 --- a/polyp/mainloop-test.c +++ b/polyp/mainloop-test.c @@ -1,3 +1,28 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/polyp/module-x11-bell.c b/polyp/module-x11-bell.c index 2414e36b..3ed9b068 100644 --- a/polyp/module-x11-bell.c +++ b/polyp/module-x11-bell.c @@ -1,3 +1,28 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/polyp/play-memchunk.c b/polyp/play-memchunk.c index 86634407..5c423567 100644 --- a/polyp/play-memchunk.c +++ b/polyp/play-memchunk.c @@ -1,3 +1,28 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include diff --git a/polyp/play-memchunk.h b/polyp/play-memchunk.h index 76f9dbd0..edd327c5 100644 --- a/polyp/play-memchunk.h +++ b/polyp/play-memchunk.h @@ -1,7 +1,29 @@ #ifndef fooplaychunkhfoo #define fooplaychunkhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "sink.h" +#include "memchunk.h" int pa_play_memchunk(struct pa_sink *sink, const char *name, const struct pa_sample_spec *ss, const struct pa_memchunk *chunk, uint32_t volume); diff --git a/polyp/polyplib-operation.c b/polyp/polyplib-operation.c index 994ac016..cdc5394e 100644 --- a/polyp/polyplib-operation.c +++ b/polyp/polyplib-operation.c @@ -1,3 +1,28 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include "xmalloc.h" diff --git a/polyp/scache.c b/polyp/scache.c index 9485a2b6..f0d261f6 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -1,3 +1,28 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/polyp/scache.h b/polyp/scache.h index 15cd5d48..8ccca156 100644 --- a/polyp/scache.h +++ b/polyp/scache.h @@ -1,6 +1,27 @@ #ifndef fooscachehfoo #define fooscachehfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "core.h" #include "memchunk.h" #include "sink.h" diff --git a/polyp/sound-file.c b/polyp/sound-file.c index bf635fa0..01fda78e 100644 --- a/polyp/sound-file.c +++ b/polyp/sound-file.c @@ -1,3 +1,28 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include diff --git a/polyp/sound-file.h b/polyp/sound-file.h index 62a4a371..4d0cf670 100644 --- a/polyp/sound-file.h +++ b/polyp/sound-file.h @@ -1,6 +1,27 @@ #ifndef soundfilehfoo #define soundfilehfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "memchunk.h" #include "sample.h" diff --git a/polyp/subscribe.c b/polyp/subscribe.c index 104566d1..5f7651fd 100644 --- a/polyp/subscribe.c +++ b/polyp/subscribe.c @@ -1,3 +1,28 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include diff --git a/polyp/subscribe.h b/polyp/subscribe.h index a88677d2..8d5e971d 100644 --- a/polyp/subscribe.h +++ b/polyp/subscribe.h @@ -1,6 +1,27 @@ #ifndef foosubscribehfoo #define foosubscribehfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "core.h" #include "native-common.h" diff --git a/polyp/xmalloc.c b/polyp/xmalloc.c index 7d8b4821..47f46bbe 100644 --- a/polyp/xmalloc.c +++ b/polyp/xmalloc.c @@ -1,3 +1,28 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/polyp/xmalloc.h b/polyp/xmalloc.h index eaf8f708..35eda622 100644 --- a/polyp/xmalloc.h +++ b/polyp/xmalloc.h @@ -1,6 +1,27 @@ #ifndef foomemoryhfoo #define foomemoryhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include #include -- cgit From befd734aac2c925df9c5701d1ddfb3063b45ac76 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 18 Aug 2004 01:00:18 +0000 Subject: add version routines to polyplib git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@139 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 2 ++ polyp/module-protocol-stub.c | 54 ++++++++++++++++++++------------------------ polyp/polyplib-context.c | 4 ++++ polyp/polyplib-version.h.in | 33 +++++++++++++++++++++++++++ polyp/polyplib.h | 11 ++++++++- 5 files changed, 73 insertions(+), 31 deletions(-) create mode 100644 polyp/polyplib-version.h.in diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 5a49201a..ac98e86e 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -27,6 +27,8 @@ EXTRA_DIST = polypaudio.pa depmod.py bin_PROGRAMS = polypaudio pacat pactl noinst_PROGRAMS = mainloop-test mainloop-test-glib pacat-simple parec-simple +BUILT_SOURCES=polyplib-version.h + polypinclude_HEADERS=polyplib.h \ polyplib-def.h \ polyplib-simple.h \ diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index 3b1a0270..e681732f 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -36,43 +36,37 @@ #include "util.h" #include "modargs.h" -#ifdef USE_PROTOCOL_SIMPLE +#if defined(USE_PROTOCOL_SIMPLE) #include "protocol-simple.h" #define protocol_new pa_protocol_simple_new #define protocol_free pa_protocol_simple_free #define IPV4_PORT 4711 #define UNIX_SOCKET "/tmp/polypaudio/simple" #define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record", +#elif defined(USE_PROTOCOL_CLI) + #include "protocol-cli.h" + #define protocol_new pa_protocol_cli_new + #define protocol_free pa_protocol_cli_free + #define IPV4_PORT 4712 + #define UNIX_SOCKET "/tmp/polypaudio/cli" + #define MODULE_ARGUMENTS +#elif defined(USE_PROTOCOL_NATIVE) + #include "protocol-native.h" + #define protocol_new pa_protocol_native_new + #define protocol_free pa_protocol_native_free + #define IPV4_PORT 4713 + #define UNIX_SOCKET "/tmp/polypaudio/native" + #define MODULE_ARGUMENTS "public", "cookie", +#elif defined(USE_PROTOCOL_ESOUND) + #include "protocol-esound.h" + #include "esound.h" + #define protocol_new pa_protocol_esound_new + #define protocol_free pa_protocol_esound_free + #define IPV4_PORT ESD_DEFAULT_PORT + #define UNIX_SOCKET ESD_UNIX_SOCKET_NAME + #define MODULE_ARGUMENTS "sink", "source", "public", "cookie", #else - #ifdef USE_PROTOCOL_CLI - #include "protocol-cli.h" - #define protocol_new pa_protocol_cli_new - #define protocol_free pa_protocol_cli_free - #define IPV4_PORT 4712 - #define UNIX_SOCKET "/tmp/polypaudio/cli" - #define MODULE_ARGUMENTS - #else - #ifdef USE_PROTOCOL_NATIVE - #include "protocol-native.h" - #define protocol_new pa_protocol_native_new - #define protocol_free pa_protocol_native_free - #define IPV4_PORT 4713 - #define UNIX_SOCKET "/tmp/polypaudio/native" - #define MODULE_ARGUMENTS "public", "cookie", - #else - #ifdef USE_PROTOCOL_ESOUND - #include "protocol-esound.h" - #include "esound.h" - #define protocol_new pa_protocol_esound_new - #define protocol_free pa_protocol_esound_free - #define IPV4_PORT ESD_DEFAULT_PORT - #define UNIX_SOCKET ESD_UNIX_SOCKET_NAME - #define MODULE_ARGUMENTS "sink", "source", "public", "cookie", - #else - #error "Broken build system" - #endif - #endif - #endif + #error "Broken build system" #endif static const char* const valid_modargs[] = { diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index fcf3f6b9..d048cda9 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -532,3 +532,7 @@ struct pa_operation* pa_context_send_simple_command(struct pa_context *c, uint32 return pa_operation_ref(o); } + +const char* pa_get_library_version(void) { + return PACKAGE_VERSION; +} diff --git a/polyp/polyplib-version.h.in b/polyp/polyplib-version.h.in new file mode 100644 index 00000000..b44dc008 --- /dev/null +++ b/polyp/polyplib-version.h.in @@ -0,0 +1,33 @@ +#ifndef foopolyplibversionhfoo /*-*-C-*-*/ +#define foopolyplibversionhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/** \file + * Define header version */ + +/** Return the version of the header files. Keep in mind that this is +a macro and not a function, so it is impossible to get the pointer of +it. */ +#define pa_get_headers_version() ("@PACKAGE_VERSION@") + +#endif diff --git a/polyp/polyplib.h b/polyp/polyplib.h index daaed649..f4e41934 100644 --- a/polyp/polyplib.h +++ b/polyp/polyplib.h @@ -22,6 +22,7 @@ USA. ***/ +#include "cdecl.h" #include "mainloop-api.h" #include "sample.h" #include "polyplib-def.h" @@ -30,11 +31,12 @@ #include "polyplib-introspect.h" #include "polyplib-subscribe.h" #include "polyplib-scache.h" +#include "polyplib-version.h" /** \file * Include all polyplib header file at once. The following files are included: \ref mainloop-api.h, \ref sample.h, * \ref polyplib-def.h, \ref polyplib-context.h, \ref polyplib-stream.h, - * \ref polyplib-introspect.h, \ref polyplib-subscribe.h and \ref polyplib-scache.h + * \ref polyplib-introspect.h, \ref polyplib-subscribe.h and \ref polyplib-scache.h \ref polyplib-version.h * at once */ /** \mainpage @@ -81,4 +83,11 @@ * synchronous API is available as "polyplib-simple". */ +PA_C_DECL_BEGIN + +/** Return the version of the library the current application is linked to */ +const char* pa_get_library_version(void); + +PA_C_DECL_END + #endif -- cgit From e0fe68a2d4e967c2b3d7afd300c854d173dcd95b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 19 Aug 2004 06:24:40 +0000 Subject: minor stuff git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@140 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- doc/todo | 4 ++-- doxygen/Makefile.am | 17 +++++++++++++++++ doxygen/doxygen.conf.in | 2 +- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 4e4bf3aa..a8c45269 100644 --- a/configure.ac +++ b/configure.ac @@ -111,5 +111,5 @@ AM_CONDITIONAL([USE_LYNX], [test "x$lynx" = xyes]) AM_CONDITIONAL(BUILD_LIBPOLYPCORE, false) -AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc polyplib-glib-mainloop.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf]) +AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc polyplib-glib-mainloop.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf polyp/polyplib-version.h]) AC_OUTPUT diff --git a/doc/todo b/doc/todo index c4b390de..9085d7fd 100644 --- a/doc/todo +++ b/doc/todo @@ -3,8 +3,8 @@ *** 0.2 *** - enable searchdir -- run dep script -- version routines +- update docs +- pacat drain *** 0.3 *** - future cancellation diff --git a/doxygen/Makefile.am b/doxygen/Makefile.am index d2f508c7..007a37d6 100644 --- a/doxygen/Makefile.am +++ b/doxygen/Makefile.am @@ -1,4 +1,21 @@ # $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. noinst_DATA=html diff --git a/doxygen/doxygen.conf.in b/doxygen/doxygen.conf.in index 7d4c44c9..51b2a113 100644 --- a/doxygen/doxygen.conf.in +++ b/doxygen/doxygen.conf.in @@ -417,7 +417,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = ../polyp/polyplib-context.h ../polyp/polyplib-stream.h ../polyp/polyplib.h ../polyp/sample.h ../polyp/polyplib-def.h ../polyp/polyplib-subscribe.h ../polyp/polyplib-introspect.h ../polyp/polyplib-scache.h ../polyp/mainloop-api.h ../polyp/cdecl.h ../polyp/glib-mainloop.h ../polyp/mainloop.h ../polyp/mainloop-signal.h ../polyp/polyplib-error.h ../polyp/polyplib-operation.h ../polyp/polyplib-simple.h +INPUT = ../polyp/polyplib-context.h ../polyp/polyplib-stream.h ../polyp/polyplib.h ../polyp/sample.h ../polyp/polyplib-def.h ../polyp/polyplib-subscribe.h ../polyp/polyplib-introspect.h ../polyp/polyplib-scache.h ../polyp/mainloop-api.h ../polyp/cdecl.h ../polyp/glib-mainloop.h ../polyp/mainloop.h ../polyp/mainloop-signal.h ../polyp/polyplib-error.h ../polyp/polyplib-operation.h ../polyp/polyplib-simple.h ../polyp/polyplib-version.h # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -- cgit From f9b58fb0eafdc332e500a0851b0506146c2b14cd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 19 Aug 2004 23:14:59 +0000 Subject: move sample cache to namereg documentation git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@141 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- doc/README.html.in | 41 +++++++++++---------- polyp/cli-text.c | 8 ++-- polyp/core.c | 9 ++--- polyp/core.h | 4 +- polyp/glib-mainloop.c | 28 +++++++------- polyp/llist.h | 2 +- polyp/mainloop-api.h | 2 +- polyp/mainloop.c | 37 +++++++++---------- polyp/memblockq.c | 2 +- polyp/memchunk.c | 2 +- polyp/module-oss-mmap.c | 2 +- polyp/module-oss.c | 2 +- polyp/namereg.c | 9 +++-- polyp/namereg.h | 3 +- polyp/polyplib-def.h | 8 ++-- polyp/polyplib-introspect.c | 89 +++++++++++++++++++++++++++++++++++++++++++++ polyp/polyplib-introspect.h | 12 ++++++ polyp/polyplib-operation.h | 1 + polyp/polyplib-stream.c | 2 +- polyp/protocol-esound.c | 4 +- polyp/protocol-native.c | 45 +++++++++++++++++------ polyp/sample.c | 2 +- polyp/scache.c | 66 ++++++++++++++------------------- polyp/scache.h | 2 +- polyp/strbuf.c | 2 +- polyp/strbuf.h | 2 +- 27 files changed, 252 insertions(+), 136 deletions(-) diff --git a/configure.ac b/configure.ac index a8c45269..96b4cf3a 100644 --- a/configure.ac +++ b/configure.ac @@ -87,7 +87,7 @@ AC_SUBST(GLIB20_LIBS) # If using GCC specifiy some additional parameters if test "x$GCC" = "xyes" ; then - CFLAGS="$CFLAGS -pipe -Wall -W -Wno-unused-parameter" + CFLAGS="$CFLAGS -pipe -W -Wall -Wno-unused-parameter -pedantic -std=c99" fi # LYNX documentation generation diff --git a/doc/README.html.in b/doc/README.html.in index 296d4506..4972c194 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -42,6 +42,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    News

    +
    Fri Aug 20 2004:

    Version 0.2 released; +changes include: added sample cache, introspection API, client API +documentation, module autoloading, glib support, a module for intercepting X11 bell events, and much more.

    Sat Jul 17 2004:

    Version 0.1 released

    @@ -56,7 +60,7 @@ Daemon (ESOUND). In addition to the features ESOUND provides polypaudio has:

      -
    • Extensible plugin architecture (dlopen())
    • +
    • Extensible plugin architecture (by loading dynamic loadable modules with dlopen())
    • Support for more than one sink/source
    • Better low latency behaviour
    • Embedabble into other software (the core is available as C library)
    • @@ -64,6 +68,7 @@ Daemon (ESOUND). In addition to the features ESOUND provides
    • Simple command line interface for reconfiguring the daemon while running
    • Flexible, implicit sample type conversion and resampling
    • "Zero-Copy" architecture
    • +
    • Module autoloading

    Both the core and the client API are completely asynchronous making @@ -74,31 +79,27 @@ available through polyplib is quite difficult to use there is a simplified synchronous API wrapper polyplib-simple available. A simple main loop implementation is available as well.

    -

    polypaudio is the successor of my previous, ill-fated attempt to write a sound server asd.

    +

    polypaudio is the successor of my previous, ill-fated +attempt to write a sound server asd.

    + +

    A GTK GUI manager application for polypaudio is the Polypaudio Manager.

    Status

    -

    Version @PACKAGE_VERSION@ is quite usable. polypaudio does -not yet match all ESOUND features: currently a sample cache and -automatic releasing of unused sound drivers are missing. Have a look -on the more extensive TODO -list.

    +

    Version @PACKAGE_VERSION@ is quite usable. It matches and supersedes ESOUND's feature set in nearly all areas.

    Documentation

    -

    There is some prelimenary documentation available: There is some preliminary documentation available: modules.html, cli.html, daemeon.html.

    +href="daemon.html">daemon.html.

    -

    Documentation for developing with polypaudio is not yet -available. Read the source, Luke! There are some example application -available: for the asynchronous -API and for the simple, -synchronous API.

    +

    You may browser the Doxygen generated programing +documentation for the client API. (Run make doxygen to generate this documentation from the source tree)

    First Steps

    @@ -131,7 +132,9 @@ GNU libtool for source code configuration and shared library management.

    polypaudio needs Secret Rabbit Code (aka libsamplerate) and alsa-lib.

    +href="http://www.mega-nerd.com/SRC/">Secret Rabbit Code (aka +libsamplerate), libsndfile and alsa-lib.

    Installation

    @@ -156,7 +159,7 @@ compilation and make install (as root) for installation of

    If you want to be notified whenever I release a new version of this software use the subscription feature of Freshmeat.


    -
    Lennart Poettering <@PACKAGE_BUGREPORT@>, July 2004
    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, August 2004
    $Id$
    diff --git a/polyp/cli-text.c b/polyp/cli-text.c index 000d6d34..fa1ccdf9 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -212,13 +212,13 @@ char *pa_scache_list_to_string(struct pa_core *c) { s = pa_strbuf_new(); assert(s); - pa_strbuf_printf(s, "%u cache entries available.\n", c->scache_hashmap ? pa_hashmap_ncontents(c->scache_hashmap) : 0); + pa_strbuf_printf(s, "%u cache entries available.\n", c->scache ? pa_idxset_ncontents(c->scache) : 0); - if (c->scache_hashmap) { + if (c->scache) { struct pa_scache_entry *e; - void *state = NULL; + uint32_t index = PA_IDXSET_INVALID; - while ((e = pa_hashmap_iterate(c->scache_hashmap, &state))) { + for (e = pa_idxset_first(c->scache, &index); e; e = pa_idxset_next(c->scache, &index)) { double l; char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec); diff --git a/polyp/core.c b/polyp/core.c index b43eb639..908564c1 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -53,8 +53,7 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->modules = NULL; c->namereg = NULL; - c->scache_idxset = NULL; - c->scache_hashmap = NULL; + c->scache = NULL; c->autoload_hashmap = NULL; @@ -74,7 +73,7 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { pa_check_for_sigpipe(); return c; -}; +} void pa_core_free(struct pa_core *c) { assert(c); @@ -97,8 +96,8 @@ void pa_core_free(struct pa_core *c) { assert(pa_idxset_isempty(c->sink_inputs)); pa_idxset_free(c->sink_inputs, NULL, NULL); - pa_namereg_free(c); pa_scache_free(c); + pa_namereg_free(c); pa_autoload_free(c); pa_subscription_free_all(c); @@ -108,5 +107,5 @@ void pa_core_free(struct pa_core *c) { pa_memblock_stat_unref(c->memblock_stat); pa_xfree(c); -}; +} diff --git a/polyp/core.h b/polyp/core.h index c0a2d6d8..a297d4e0 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -31,9 +31,9 @@ struct pa_core { struct pa_mainloop_api *mainloop; - struct pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache_idxset; + struct pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache; - struct pa_hashmap *namereg, *scache_hashmap, *autoload_hashmap; + struct pa_hashmap *namereg, *autoload_hashmap; char *default_source_name, *default_sink_name; diff --git a/polyp/glib-mainloop.c b/polyp/glib-mainloop.c index a91f48ec..4fee0a4a 100644 --- a/polyp/glib-mainloop.c +++ b/polyp/glib-mainloop.c @@ -384,24 +384,24 @@ static void glib_quit(struct pa_mainloop_api*a, int retval) { } static const struct pa_mainloop_api vtable = { - userdata: NULL, + .userdata = NULL, - io_new: glib_io_new, - io_enable: glib_io_enable, - io_free: glib_io_free, - io_set_destroy: glib_io_set_destroy, + .io_new = glib_io_new, + .io_enable = glib_io_enable, + .io_free = glib_io_free, + .io_set_destroy= glib_io_set_destroy, - time_new : glib_time_new, - time_restart : glib_time_restart, - time_free : glib_time_free, - time_set_destroy : glib_time_set_destroy, + .time_new = glib_time_new, + .time_restart = glib_time_restart, + .time_free = glib_time_free, + .time_set_destroy = glib_time_set_destroy, - defer_new : glib_defer_new, - defer_enable : glib_defer_enable, - defer_free : glib_defer_free, - defer_set_destroy : glib_defer_set_destroy, + .defer_new = glib_defer_new, + .defer_enable = glib_defer_enable, + .defer_free = glib_defer_free, + .defer_set_destroy = glib_defer_set_destroy, - quit : glib_quit, + .quit = glib_quit, }; struct pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) { diff --git a/polyp/llist.h b/polyp/llist.h index 12a33e90..ec8e0299 100644 --- a/polyp/llist.h +++ b/polyp/llist.h @@ -24,7 +24,7 @@ #define PA_LLIST_HEAD(t,name) t *name -#define PA_LLIST_FIELDS(t) t *next, *prev; +#define PA_LLIST_FIELDS(t) t *next, *prev #define PA_LLIST_HEAD_INIT(t,item) do { (item) = NULL; } while(0) diff --git a/polyp/mainloop-api.h b/polyp/mainloop-api.h index e631c7ac..43d150e4 100644 --- a/polyp/mainloop-api.h +++ b/polyp/mainloop-api.h @@ -50,7 +50,7 @@ enum pa_io_event_flags { PA_IO_EVENT_INPUT = 1, /**< Input event */ PA_IO_EVENT_OUTPUT = 2, /**< Output event */ PA_IO_EVENT_HANGUP = 4, /**< Hangup event */ - PA_IO_EVENT_ERROR = 8, /**< Error event */ + PA_IO_EVENT_ERROR = 8 /**< Error event */ }; /** \struct pa_io_event diff --git a/polyp/mainloop.c b/polyp/mainloop.c index c678537e..84505bb6 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -38,9 +38,6 @@ #include "idxset.h" #include "xmalloc.h" -struct pa_base_event { -}; - struct pa_io_event { struct pa_mainloop *mainloop; int dead; @@ -225,24 +222,24 @@ static void mainloop_quit(struct pa_mainloop_api*a, int retval) { } static const struct pa_mainloop_api vtable = { - userdata: NULL, + .userdata = NULL, - io_new: mainloop_io_new, - io_enable: mainloop_io_enable, - io_free: mainloop_io_free, - io_set_destroy: mainloop_io_set_destroy, + .io_new= mainloop_io_new, + .io_enable= mainloop_io_enable, + .io_free= mainloop_io_free, + .io_set_destroy= mainloop_io_set_destroy, - time_new : mainloop_time_new, - time_restart : mainloop_time_restart, - time_free : mainloop_time_free, - time_set_destroy : mainloop_time_set_destroy, + .time_new = mainloop_time_new, + .time_restart = mainloop_time_restart, + .time_free = mainloop_time_free, + .time_set_destroy = mainloop_time_set_destroy, - defer_new : mainloop_defer_new, - defer_enable : mainloop_defer_enable, - defer_free : mainloop_defer_free, - defer_set_destroy : mainloop_defer_set_destroy, + .defer_new = mainloop_defer_new, + .defer_enable = mainloop_defer_enable, + .defer_free = mainloop_defer_free, + .defer_set_destroy = mainloop_defer_set_destroy, - quit : mainloop_quit, + .quit = mainloop_quit, }; struct pa_mainloop *pa_mainloop_new(void) { @@ -282,7 +279,7 @@ static int io_foreach(void *p, uint32_t index, int *del, void*userdata) { pa_xfree(e); *del = 1; return 0; -}; +} static int time_foreach(void *p, uint32_t index, int *del, void*userdata) { struct pa_time_event *e = p; @@ -297,7 +294,7 @@ static int time_foreach(void *p, uint32_t index, int *del, void*userdata) { pa_xfree(e); *del = 1; return 0; -}; +} static int defer_foreach(void *p, uint32_t index, int *del, void*userdata) { struct pa_defer_event *e = p; @@ -312,7 +309,7 @@ static int defer_foreach(void *p, uint32_t index, int *del, void*userdata) { pa_xfree(e); *del = 1; return 0; -}; +} void pa_mainloop_free(struct pa_mainloop* m) { int all = 1; diff --git a/polyp/memblockq.c b/polyp/memblockq.c index bc5d7437..085c0510 100644 --- a/polyp/memblockq.c +++ b/polyp/memblockq.c @@ -189,9 +189,9 @@ int memblockq_pop(struct memblockq* bq, struct pa_memchunk *chunk) { */ static uint32_t age(struct timeval *tv) { - assert(tv); struct timeval now; uint32_t r; + assert(tv); if (tv->tv_sec == 0) return 0; diff --git a/polyp/memchunk.c b/polyp/memchunk.c index 5913c6e3..920189e2 100644 --- a/polyp/memchunk.c +++ b/polyp/memchunk.c @@ -88,8 +88,8 @@ void pa_mcalign_push(struct pa_mcalign *m, const struct pa_memchunk *c) { } int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c) { - assert(m && c && m->base > m->buffer_fill); int ret; + assert(m && c && m->base > m->buffer_fill); if (!m->chunk.memblock) return -1; diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index 7c7750d1..05e06178 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -193,7 +193,7 @@ static void do_read(struct userdata *u) { in_post_memblocks(u, info.blocks); in_clear_memblocks(u, u->in_fragments/2); -}; +} static void io_callback(struct pa_mainloop_api *m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { struct userdata *u = userdata; diff --git a/polyp/module-oss.c b/polyp/module-oss.c index d5517b5e..3fa3d1e3 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -146,7 +146,7 @@ static void do_read(struct userdata *u) { pa_source_post(u->source, &memchunk); pa_memblock_unref(memchunk.memblock); -}; +} static void io_callback(struct pa_iochannel *io, void*userdata) { struct userdata *u = userdata; diff --git a/polyp/namereg.c b/polyp/namereg.c index b6a8c23f..72a4c648 100644 --- a/polyp/namereg.c +++ b/polyp/namereg.c @@ -134,8 +134,7 @@ void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type t name = c->default_source_name; - } else { - assert(type == PA_NAMEREG_SINK); + } else if (type == PA_NAMEREG_SINK) { if (!c->default_sink_name) { struct pa_sink *s; @@ -174,13 +173,15 @@ void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type t d = pa_idxset_get_by_index(c->sinks, index); else if (type == PA_NAMEREG_SOURCE) d = pa_idxset_get_by_index(c->sources, index); - + else if (type == PA_NAMEREG_SAMPLE && c->scache) + d = pa_idxset_get_by_index(c->scache, index); + return d; } void pa_namereg_set_default(struct pa_core*c, const char *name, enum pa_namereg_type type) { char **s; - assert(c); + assert(c && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); s = type == PA_NAMEREG_SINK ? &c->default_sink_name : &c->default_source_name; assert(s); diff --git a/polyp/namereg.h b/polyp/namereg.h index 5bc92693..b8db1105 100644 --- a/polyp/namereg.h +++ b/polyp/namereg.h @@ -26,7 +26,8 @@ enum pa_namereg_type { PA_NAMEREG_SINK, - PA_NAMEREG_SOURCE + PA_NAMEREG_SOURCE, + PA_NAMEREG_SAMPLE }; void pa_namereg_free(struct pa_core *c); diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index 8a506c8d..6420e87e 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -47,14 +47,14 @@ enum pa_stream_state { PA_STREAM_CREATING, /**< The stream is being created */ PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */ PA_STREAM_FAILED, /**< An error occured that made the stream invalid */ - PA_STREAM_TERMINATED, /**< The stream has been terminated cleanly */ + PA_STREAM_TERMINATED /**< The stream has been terminated cleanly */ }; /** The state of an operation */ enum pa_operation_state { PA_OPERATION_RUNNING, /**< The operation is still running */ PA_OPERATION_DONE, /**< The operation has been completed */ - PA_OPERATION_CANCELED, /**< The operation has been canceled */ + PA_OPERATION_CANCELED /**< The operation has been canceled */ }; /** An invalid index */ @@ -105,7 +105,7 @@ enum pa_subscription_mask { PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8, /**< Source output events */ PA_SUBSCRIPTION_MASK_MODULE = 16, /**< Module events */ PA_SUBSCRIPTION_MASK_CLIENT = 32, /**< Client events */ - PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, /**< Sample cache events */ + PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64 /**< Sample cache events */ }; /** Subscription event types, as used by pa_context_subscribe() */ @@ -122,7 +122,7 @@ enum pa_subscription_event_type { PA_SUBSCRIPTION_EVENT_NEW = 0, /**< A new object was created */ PA_SUBSCRIPTION_EVENT_CHANGE = 16, /**< A property of the object was modified */ PA_SUBSCRIPTION_EVENT_REMOVE = 32, /**< An object was removed */ - PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32, /**< A mask to extract the event operation from an event value */ + PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32 /**< A mask to extract the event operation from an event value */ }; /** Return one if an event type t matches an event mask bitfield */ diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index 0efc599d..63422383 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -580,3 +580,92 @@ struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint return pa_operation_ref(o); } + +/** Sample Cache **/ + +static void context_get_sample_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + struct pa_sample_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_getu32(t, &i.volume) < 0 || + pa_tagstruct_getu32(t, &i.duration) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_sample_info*i, int eof, void *userdata) = o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_sample_info*i, int eof, void *userdata) = o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +struct pa_operation* pa_context_get_sample_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + struct pa_operation *o; + uint32_t tag; + assert(c && cb && name); + + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SAMPLE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, o); + + return pa_operation_ref(o); +} + +struct pa_operation* pa_context_get_sample_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + struct pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SAMPLE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, o); + + return pa_operation_ref(o); +} + +struct pa_operation* pa_context_get_sample_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SAMPLE_INFO_LIST, context_get_sample_info_callback, cb, userdata); +} diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index c453eb2f..0cc52549 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -139,6 +139,18 @@ struct pa_stat_info { /** Get daemon memory block statistics */ struct pa_operation* pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_stat_info *i, void *userdata), void *userdata); +struct pa_sample_info { + uint32_t index; + const char *name; + uint32_t volume; + struct pa_sample_spec sample_spec; + uint32_t duration; +}; + +struct pa_operation* pa_context_get_sample_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_sample_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_sample_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata); + PA_C_DECL_END #endif diff --git a/polyp/polyplib-operation.h b/polyp/polyplib-operation.h index ce2756ef..42d5c8e1 100644 --- a/polyp/polyplib-operation.h +++ b/polyp/polyplib-operation.h @@ -23,6 +23,7 @@ ***/ #include "cdecl.h" +#include "polyplib-def.h" /** \file * Asynchronous operations */ diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 2b591f36..451dd046 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -32,8 +32,8 @@ #include "pstream-util.h" struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const struct pa_sample_spec *ss) { - assert(c && ss); struct pa_stream *s; + assert(c && ss); s = pa_xmalloc(sizeof(struct pa_stream)); s->ref = 1; diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index f5efa419..be2ef2b9 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -427,7 +427,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v k = sizeof(int)*5+ESD_NAME_MAX; s = sizeof(int)*6+ESD_NAME_MAX; - nsamples = c->protocol->core->scache_idxset ? pa_idxset_ncontents(c->protocol->core->scache_idxset) : 0; + nsamples = c->protocol->core->scache ? pa_idxset_ncontents(c->protocol->core->scache) : 0; response = connection_write(c, (t = s*(nsamples+1) + k*(c->protocol->n_player+1))); assert(k); @@ -482,7 +482,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v struct pa_scache_entry *ce; index = PA_IDXSET_INVALID; - for (ce = pa_idxset_first(c->protocol->core->scache_idxset, &index); ce; ce = pa_idxset_next(c->protocol->core->scache_idxset, &index)) { + for (ce = pa_idxset_first(c->protocol->core->scache, &index); ce; ce = pa_idxset_next(c->protocol->core->scache, &index)) { assert(t >= s*2); /* id */ diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 060b4241..d633c265 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -164,12 +164,14 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_GET_MODULE_INFO] = { command_get_info }, [PA_COMMAND_GET_SINK_INPUT_INFO] = { command_get_info }, [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = { command_get_info }, + [PA_COMMAND_GET_SAMPLE_INFO] = { command_get_info }, [PA_COMMAND_GET_SINK_INFO_LIST] = { command_get_info_list }, [PA_COMMAND_GET_SOURCE_INFO_LIST] = { command_get_info_list }, [PA_COMMAND_GET_MODULE_INFO_LIST] = { command_get_info_list }, [PA_COMMAND_GET_CLIENT_INFO_LIST] = { command_get_info_list }, [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = { command_get_info_list }, [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = { command_get_info_list }, + [PA_COMMAND_GET_SAMPLE_INFO_LIST] = { command_get_info_list }, [PA_COMMAND_GET_SERVER_INFO] = { command_get_server_info }, [PA_COMMAND_SUBSCRIBE] = { command_subscribe }, [PA_COMMAND_SET_SINK_VOLUME] = { command_set_volume }, @@ -763,8 +765,8 @@ static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t comm static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - assert(c && t); struct pa_tagstruct *reply; + assert(c && t); if (!pa_tagstruct_eof(t)) { protocol_error(c); @@ -789,10 +791,10 @@ static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - assert(c && t); struct pa_tagstruct *reply; struct playback_stream *s; uint32_t index, latency; + assert(c && t); if (pa_tagstruct_getu32(t, &index) < 0 || !pa_tagstruct_eof(t)) { @@ -1021,6 +1023,15 @@ static void source_output_fill_tagstruct(struct pa_tagstruct *t, struct pa_sourc pa_tagstruct_put_sample_spec(t, &s->sample_spec); } +static void scache_fill_tagstruct(struct pa_tagstruct *t, struct pa_scache_entry *e) { + assert(t && e); + pa_tagstruct_putu32(t, e->index); + pa_tagstruct_puts(t, e->name); + pa_tagstruct_putu32(t, e->volume); + pa_tagstruct_putu32(t, pa_bytes_to_usec(e->memchunk.length, &e->sample_spec)); + pa_tagstruct_put_sample_spec(t, &e->sample_spec); +} + static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; uint32_t index; @@ -1030,6 +1041,7 @@ static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t struct pa_module *module = NULL; struct pa_sink_input *si = NULL; struct pa_source_output *so = NULL; + struct pa_scache_entry *sce = NULL; const char *name; struct pa_tagstruct *reply; assert(c && t); @@ -1067,12 +1079,17 @@ static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t module = pa_idxset_get_by_index(c->protocol->core->modules, index); else if (command == PA_COMMAND_GET_SINK_INPUT_INFO) si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, index); - else { - assert(command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO); + else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO) so = pa_idxset_get_by_index(c->protocol->core->source_outputs, index); + else { + assert(command == PA_COMMAND_GET_SAMPLE_INFO && name); + if (index != (uint32_t) -1) + sce = pa_idxset_get_by_index(c->protocol->core->scache, index); + else + sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE, 0); } - if (!sink && !source && !client && !module && !si && !so) { + if (!sink && !source && !client && !module && !si && !so && !sce) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -1091,8 +1108,10 @@ static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t module_fill_tagstruct(reply, module); else if (si) sink_input_fill_tagstruct(reply, si); - else + else if (so) source_output_fill_tagstruct(reply, so); + else + scache_fill_tagstruct(reply, sce); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -1129,11 +1148,13 @@ static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uin i = c->protocol->core->modules; else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) i = c->protocol->core->sink_inputs; - else { - assert(command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST); + else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST) i = c->protocol->core->source_outputs; + else { + assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); + i = c->protocol->core->scache; } - + for (p = pa_idxset_first(i, &index); p; p = pa_idxset_next(i, &index)) { if (command == PA_COMMAND_GET_SINK_INFO_LIST) sink_fill_tagstruct(reply, p); @@ -1145,9 +1166,11 @@ static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uin module_fill_tagstruct(reply, p); else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) sink_input_fill_tagstruct(reply, p); - else { - assert(command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST); + else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST) source_output_fill_tagstruct(reply, p); + else { + assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); + scache_fill_tagstruct(reply, p); } } diff --git a/polyp/sample.c b/polyp/sample.c index 173de9c1..f4a80861 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -29,8 +29,8 @@ #include "sample.h" size_t pa_frame_size(const struct pa_sample_spec *spec) { - assert(spec); size_t b = 1; + assert(spec); switch (spec->format) { case PA_SAMPLE_U8: diff --git a/polyp/scache.c b/polyp/scache.c index f0d261f6..f3c15934 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -35,9 +35,11 @@ #include "play-memchunk.h" #include "xmalloc.h" #include "subscribe.h" +#include "namereg.h" static void free_entry(struct pa_scache_entry *e) { assert(e); + pa_namereg_unregister(e->core, e->name); pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_REMOVE, e->index); pa_xfree(e->name); if (e->memchunk.memblock) @@ -45,25 +47,32 @@ static void free_entry(struct pa_scache_entry *e) { pa_xfree(e); } -void pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index) { +int pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index) { struct pa_scache_entry *e; int put; assert(c && name); - if (c->scache_hashmap && (e = pa_hashmap_get(c->scache_hashmap, name))) { + if ((e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) { put = 0; if (e->memchunk.memblock) pa_memblock_unref(e->memchunk.memblock); assert(e->core == c); } else { + put = 1; e = pa_xmalloc(sizeof(struct pa_scache_entry)); + + if (!pa_namereg_register(c, name, PA_NAMEREG_SAMPLE, e, 1)) { + pa_xfree(e); + return -1; + } + e->name = pa_xstrdup(name); e->core = c; } - e->volume = 0x100; - + e->volume = PA_VOLUME_NORM; + if (ss) e->sample_spec = *ss; else @@ -78,35 +87,31 @@ void pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_sp } if (put) { - if (!c->scache_hashmap) { - c->scache_hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - assert(c->scache_hashmap); - } - - if (!c->scache_idxset) { - c->scache_idxset = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - assert(c->scache_idxset); + if (!c->scache) { + c->scache = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + assert(c->scache); } - pa_idxset_put(c->scache_idxset, e, &e->index); - pa_hashmap_put(c->scache_hashmap, e->name, e); + pa_idxset_put(c->scache, e, &e->index); pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_NEW, e->index); - } + } else + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); if (index) *index = e->index; + + return 0; } int pa_scache_remove_item(struct pa_core *c, const char *name) { struct pa_scache_entry *e; assert(c && name); - if (!c->scache_hashmap || !(e = pa_hashmap_get(c->scache_hashmap, name))) + if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) return -1; - pa_hashmap_remove(c->scache_hashmap, name); - if (pa_idxset_remove_by_data(c->scache_idxset, e, NULL) != e) + if (pa_idxset_remove_by_data(c->scache, e, NULL) != e) assert(0); free_entry(e); @@ -122,14 +127,9 @@ static void free_cb(void *p, void *userdata) { void pa_scache_free(struct pa_core *c) { assert(c); - if (c->scache_hashmap) { - pa_hashmap_free(c->scache_hashmap, free_cb, NULL); - c->scache_hashmap = NULL; - } - - if (c->scache_idxset) { - pa_idxset_free(c->scache_idxset, NULL, NULL); - c->scache_idxset = NULL; + if (c->scache) { + pa_idxset_free(c->scache, free_cb, NULL); + c->scache = NULL; } } @@ -137,7 +137,7 @@ int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sin struct pa_scache_entry *e; assert(c && name && sink); - if (!c->scache_hashmap || !(e = pa_hashmap_get(c->scache_hashmap, name))) + if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) return -1; if (!e->memchunk.memblock) @@ -153,19 +153,9 @@ const char * pa_scache_get_name_by_id(struct pa_core *c, uint32_t id) { struct pa_scache_entry *e; assert(c && id != PA_IDXSET_INVALID); - if (!c->scache_idxset || !(e = pa_idxset_get_by_index(c->scache_idxset, id))) + if (!c->scache || !(e = pa_idxset_get_by_index(c->scache, id))) return NULL; return e->name; } - -uint32_t pa_scache_get_id_by_name(struct pa_core *c, const char *name) { - struct pa_scache_entry *e; - assert(c && name); - - if (!c->scache_hashmap || !(e = pa_hashmap_get(c->scache_hashmap, name))) - return PA_IDXSET_INVALID; - - return e->index; -} diff --git a/polyp/scache.h b/polyp/scache.h index 8ccca156..959067f3 100644 --- a/polyp/scache.h +++ b/polyp/scache.h @@ -35,7 +35,7 @@ struct pa_scache_entry { struct pa_memchunk memchunk; }; -void pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index); +int pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index); int pa_scache_remove_item(struct pa_core *c, const char *name); int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sink, uint32_t volume); diff --git a/polyp/strbuf.c b/polyp/strbuf.c index 169604e8..ef48a3fb 100644 --- a/polyp/strbuf.c +++ b/polyp/strbuf.c @@ -36,7 +36,7 @@ struct chunk { struct chunk *next; size_t length; - char text[]; + char text[0]; }; struct pa_strbuf { diff --git a/polyp/strbuf.h b/polyp/strbuf.h index d672c42a..8ca51624 100644 --- a/polyp/strbuf.h +++ b/polyp/strbuf.h @@ -29,7 +29,7 @@ void pa_strbuf_free(struct pa_strbuf *sb); char *pa_strbuf_tostring(struct pa_strbuf *sb); 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)));; +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); -- cgit From 6bc53405011e815b95e47a078f89b1a7c0419e56 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Aug 2004 10:54:31 +0000 Subject: build fixes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@142 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- doc/README.html.in | 4 ++-- doc/todo | 7 +------ polyp/Makefile.am | 4 +++- polyp/main.c | 2 +- polyp/protocol-native.c | 38 ++++++++++++++++++++------------------ 6 files changed, 28 insertions(+), 29 deletions(-) diff --git a/Makefile.am b/Makefile.am index 13a06362..0df5fac1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,7 +17,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -EXTRA_DIST = bootstrap.sh README LICENSE +EXTRA_DIST = bootstrap.sh README LICENSE doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in SUBDIRS=polyp doc MAINTAINERCLEANFILES=README diff --git a/doc/README.html.in b/doc/README.html.in index 4972c194..602787d4 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -133,8 +133,8 @@ management.

    polypaudio needs Secret Rabbit Code (aka -libsamplerate), libsndfile and alsa-lib.

    +libsamplerate), libsndfile, alsa-lib and GLIB. (The latter is required for building the GLIB main loop integration module only.)

    Installation

    diff --git a/doc/todo b/doc/todo index 9085d7fd..43d7bc6f 100644 --- a/doc/todo +++ b/doc/todo @@ -1,12 +1,7 @@ *** $Id$ *** -*** 0.2 *** - -- enable searchdir -- update docs -- pacat drain - *** 0.3 *** +- pacat drain fix - future cancellation - make mcalign merge chunks - use ref counting in more objects diff --git a/polyp/Makefile.am b/polyp/Makefile.am index ac98e86e..f9f6b6ab 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -17,7 +17,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -AM_CFLAGS=-ansi -D_GNU_SOURCE -DDLSEARCHDIR=\"$(pkglibdir)\" -I$(srcdir)/.. $(PTHREAD_CFLAGS) +AM_CFLAGS=-D_GNU_SOURCE -DDLSEARCHDIR=\"$(pkglibdir)\" -I$(top_srcdir) $(PTHREAD_CFLAGS) AM_LDADD=$(PTHREAD_LIBS) AM_LIBADD=$(PTHREAD_LIBS) @@ -39,6 +39,7 @@ polypinclude_HEADERS=polyplib.h \ polyplib-subscribe.h \ polyplib-operation.h \ polyplib-scache.h \ + polyplib-version.h \ cdecl.h \ mainloop-api.h \ mainloop.h \ @@ -304,6 +305,7 @@ libpolyp_la_SOURCES = polyplib.h \ polyplib-introspect.c polyplib-introspect.h \ polyplib-scache.c polyplib-scache.h \ polyplib-subscribe.c polyplib-subscribe.h \ + polyplib-internal.h \ cdecl.h \ llist.h libpolyp_la_CFLAGS = $(AM_CFLAGS) diff --git a/polyp/main.c b/polyp/main.c index 9f3d3406..de02a110 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -126,7 +126,7 @@ int main(int argc, char *argv[]) { r = lt_dlinit(); assert(r == 0); #ifdef DLSEARCHDIR -/* lt_dladdsearchdir(DLSEARCHDIR);*/ + lt_dladdsearchdir(DLSEARCHDIR); #endif mainloop = pa_mainloop_new(); diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index d633c265..c8e5137e 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -1154,25 +1154,27 @@ static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uin assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); i = c->protocol->core->scache; } - - for (p = pa_idxset_first(i, &index); p; p = pa_idxset_next(i, &index)) { - if (command == PA_COMMAND_GET_SINK_INFO_LIST) - sink_fill_tagstruct(reply, p); - else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST) - source_fill_tagstruct(reply, p); - else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST) - client_fill_tagstruct(reply, p); - else if (command == PA_COMMAND_GET_MODULE_INFO_LIST) - module_fill_tagstruct(reply, p); - else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) - sink_input_fill_tagstruct(reply, p); - else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST) - source_output_fill_tagstruct(reply, p); - else { - assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); - scache_fill_tagstruct(reply, p); + + if (i) { + for (p = pa_idxset_first(i, &index); p; p = pa_idxset_next(i, &index)) { + if (command == PA_COMMAND_GET_SINK_INFO_LIST) + sink_fill_tagstruct(reply, p); + else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST) + source_fill_tagstruct(reply, p); + else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST) + client_fill_tagstruct(reply, p); + else if (command == PA_COMMAND_GET_MODULE_INFO_LIST) + module_fill_tagstruct(reply, p); + else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) + sink_input_fill_tagstruct(reply, p); + else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST) + source_output_fill_tagstruct(reply, p); + else { + assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); + scache_fill_tagstruct(reply, p); + } } - } + } pa_pstream_send_tagstruct(c->pstream, reply); } -- cgit From 8f90450ee26117c5950d05c7dcb9ff93fad158a5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Aug 2004 11:04:25 +0000 Subject: Doxygen stuff git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@143 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 0df5fac1..7372129a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -31,11 +31,12 @@ README: $(MAKE) -C doc README cd $(srcdir) && ln -s doc/README README -homepage: all dist +homepage: all dist doxygen test -d $$HOME/homepage/private mkdir -p $$HOME/homepage/private/projects/polypaudio cp *.tar.gz $$HOME/homepage/private/projects/polypaudio cp doc/README.html doc/cli.html doc/daemon.html doc/modules.html doc/style.css $$HOME/homepage/private/projects/polypaudio + cp -a doxygen/html $$HOME/homepage/private/projects/polypaudio/doxygen cp $$HOME/homepage/private/projects/polypaudio/README.html $$HOME/homepage/private/projects/polypaudio/index.html distcleancheck: -- cgit From 0b9f91dca59dc5833ddc393c98b2ce7e2f8e1491 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Aug 2004 11:05:53 +0000 Subject: readme update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@144 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/README.html.in b/doc/README.html.in index 602787d4..f3be2b57 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -97,7 +97,7 @@ href="modules.html">modules.html, cli.html, daemon.html.

    -

    You may browser the Doxygen generated You may browse the Doxygen generated programing documentation for the client API. (Run make doxygen to generate this documentation from the source tree)

    -- cgit From 9b5ba2bc481bf67237f6ccb098495da13d350ca2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Aug 2004 11:08:19 +0000 Subject: doxygen fix git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@145 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 7372129a..632d226f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,10 +33,10 @@ README: homepage: all dist doxygen test -d $$HOME/homepage/private - mkdir -p $$HOME/homepage/private/projects/polypaudio + mkdir -p $$HOME/homepage/private/projects/polypaudio $$HOME/homepage/private/projects/polypaudio/doxygen cp *.tar.gz $$HOME/homepage/private/projects/polypaudio cp doc/README.html doc/cli.html doc/daemon.html doc/modules.html doc/style.css $$HOME/homepage/private/projects/polypaudio - cp -a doxygen/html $$HOME/homepage/private/projects/polypaudio/doxygen + cp -a doxygen/html/* $$HOME/homepage/private/projects/polypaudio/doxygen cp $$HOME/homepage/private/projects/polypaudio/README.html $$HOME/homepage/private/projects/polypaudio/index.html distcleancheck: -- cgit From 8c756d55da58779388cb07a2e135ba3f8ef3988c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Aug 2004 13:06:55 +0000 Subject: documentation update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@146 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 31 ++++++++++++++++++++----- doc/cli.html.in | 65 ++++++++++++++++++++++++++++++++++++++++++++--------- doc/modules.html.in | 11 ++++++++- 3 files changed, 90 insertions(+), 17 deletions(-) diff --git a/doc/README.html.in b/doc/README.html.in index f3be2b57..e3736c86 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -97,10 +97,6 @@ href="modules.html">modules.html, cli.html, daemon.html.

    -

    You may browse the Doxygen generated programing -documentation for the client API. (Run make doxygen to generate this documentation from the source tree)

    -

    First Steps

    Simply start the polypaudio daemon with the argument -C

    @@ -114,13 +110,36 @@ documentation for the client API. (Run make doxygen to generate thi

    Now you can issue CLI commands as described in cli.html. Another way to start -polypaudio is by specifying a configuration script on the -command line like that one included in the distribution:

    +polypaudio is by specifying a configuration script like that one included in the distribution on the +command line :

    polypaudio -F polypaudio.pa

    This will load some drivers and protocols automatically.

    +

    Developing polypaudio Clients

    + +

    You may browse the Doxygen generated programing +documentation for the client API. (Run make doxygen to generate this documentation from the source tree)

    + +

    Developing polypaudio Modules

    + +

    There are several reasons for writing loadable modules for polypaudio:

    + +
      +
    • Device driver support in addition to ALSA/OSS
    • +
    • Protocol support beyond ESOUND's protocol and the native protocol. (such as NAS or a subset of aRts)
    • +
    • New programming interfaces such as XMLRPC or DBUS for controlling the daemon.
    • +
    • Hooking audio event sources directly into polypaudio (similar to module-x11-bell)
    • +
    • For low latency applications such as VOIP: load the VOIP core directly into polypaudio and have a slim GUI frontend to control it.
    • +
    + +

    There is currently no documentation how to write loadable modules +for polypaudio. Read the source, Luke! If you are interested in +writing new modules feel free to contact the author in case you have any +questions.

    +

    Requirements

    Currently, polypaudio is tested on Linux only. It requires an OSS or ALSA compatible soundcard.

    diff --git a/doc/cli.html.in b/doc/cli.html.in index c67d78db..01c04cc9 100644 --- a/doc/cli.html.in +++ b/doc/cli.html.in @@ -87,7 +87,45 @@ input list. The same volume rules apply as with sink_volume.

    (resp. ssource) by its index in the sink (resp. source) list or by its name.

    -

    Killing clients/streams

    +

    Sample Cache

    + +

    scache_list

    + +

    Lists the contents of the sample cache.

    + +

    scache_play

    + +

    Play a sample cache entry to a sink. Expects the sample name and the sink name as arguments.

    + +

    sache_remove

    + +

    Remove an entry from the sample cache. Expects the sample name as argument.

    + +

    sache_load

    + +

    Load an audio file to the sample cache. Expects the file name to load and the desired sample name as arguments.

    + +

    Module Autoloading

    + +

    autoload_list

    + +

    Lists all currently defined autoloading entries.

    + +

    autoload_sink_add/autoload_source_add

    + +

    Adds an autoloading entry for a sink (resp. source). Expects the sink name (resp. source name), the module name and the module arguments as arguments.

    + +

    autoload_sink_remove/autoload_source_remove

    + +

    Remove an autoloading entry. Expects the sink name (resp. source name) as argument.

    + +

    Miscellaneous Commands

    + +

    play_file

    + +

    Play an audio file to a sink. Expects the file name and the sink name as argumens.

    + +

    Killing Clients/Streams

    kill_client

    @@ -120,12 +158,14 @@ on the interactive command line.

    Example Configuration Script

    +

    Mark the following script as executable (chmod +x) and run it for a sensible polypaudio configuration.

    +
     #!/usr/bin/polaudio -F
     
    -# Load audio drivers
    -load module-alsa-sink device=plughw:0,0 rate=48000
    -load module-alsa-source device=hw:1,0
    +# Create autoload entries for the device drivers
    +autoload_sink_add output module-alsa-sink device=plughw:0,0 rate=48000 sink_name=output
    +autoload_source_add input load module-alsa-source device=hw:1,0 source_name=input
     
     # Load several protocols
     load module-esound-protocol-tcp
    @@ -136,17 +176,22 @@ load module-cli-protocol-unix
     # Load the CLI module (This is similar to passing "-C" on the command line of polypaudio)
     load module-cli
     
    +# Make some devices default
    +sink_default output
    +source_default input
    +
    +# Don't fail if the audio files referred to below don't exist
     .nofail
     
    -# Make some devices default
    -sink_default alsa_output
    -source_default alsa_input
    +# Load an audio to the sample cache for usage with module-x11-bell
    +scache_load /usr/share/sounds/KDE_Notify.wav x11-bell
    +load module-x11-bell
     
    -# Use digital amplification
    -sink_volume alsa_output 0x200
    +# Play a welcome sound
    +play_file /usr/share/sounds/startup3.wav output
     

    -
    Lennart Poettering <@PACKAGE_BUGREPORT@>, July 2004
    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, August 2004
    $Id$
    diff --git a/doc/modules.html.in b/doc/modules.html.in index 6954418f..fe202989 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -184,8 +184,17 @@ about the two possible suffixes of this module.

    cookie=Name of the cookie file for authentication purposes +

    module-x11-bell

    + +

    Intercepts X11 bell events and plays a sample from the sample cache on each occurence.

    + + + + + +
    display=X11 display to connect to. If ommited defaults to the value of $DISPLAY
    sample=The sample to play. If ommited defaults to x11-bell.
    sink=Name of the sink to play the sample on. If ommited defaults to the default sink.

    -
    Lennart Poettering <@PACKAGE_BUGREPORT@>, July 2004
    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, August 2004
    $Id$
    -- cgit From 669452e4e59add411023aa3ae1ef1e67d380026c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Aug 2004 13:18:07 +0000 Subject: documentation update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@147 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/README.html.in b/doc/README.html.in index e3736c86..8972fe1b 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -84,7 +84,7 @@ attempt to write a sound server asd.

    A GTK GUI manager application for polypaudio is the Polypaudio Manager.

    +href="http://0pointer.de/lennart/projects/paman/">Polypaudio Manager.

    Status

    @@ -152,7 +152,7 @@ management.

    polypaudio needs Secret Rabbit Code (aka -libsamplerate), libsndfile, libsamplerate), libsndfile, alsa-lib and GLIB. (The latter is required for building the GLIB main loop integration module only.)

    Installation

    -- cgit From 5e8bb1410e422e144538f1bf6e56dcf47ff0b99d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Aug 2004 20:20:20 +0000 Subject: add support for glib12 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@150 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 4 + polyp/Makefile.am | 15 +- polyp/glib-mainloop.h | 5 + polyp/glib12-mainloop.c | 497 ++++++++++++++++++++++++++++++++++++++++++++++++ polyp/mainloop-test.c | 35 +++- polyp/polypaudio.pa | 5 +- 6 files changed, 551 insertions(+), 10 deletions(-) create mode 100644 polyp/glib12-mainloop.c diff --git a/configure.ac b/configure.ac index 96b4cf3a..8307bea5 100644 --- a/configure.ac +++ b/configure.ac @@ -85,6 +85,10 @@ PKG_CHECK_MODULES(GLIB20, [ glib-2.0 >= 2.4.0 ]) AC_SUBST(GLIB20_CFLAGS) AC_SUBST(GLIB20_LIBS) +PKG_CHECK_MODULES(GLIB12, [ glib >= 1.2.0 ]) +AC_SUBST(GLIB12_CFLAGS) +AC_SUBST(GLIB12_LIBS) + # If using GCC specifiy some additional parameters if test "x$GCC" = "xyes" ; then CFLAGS="$CFLAGS -pipe -W -Wall -Wno-unused-parameter -pedantic -std=c99" diff --git a/polyp/Makefile.am b/polyp/Makefile.am index f9f6b6ab..8acbc012 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -17,7 +17,8 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -AM_CFLAGS=-D_GNU_SOURCE -DDLSEARCHDIR=\"$(pkglibdir)\" -I$(top_srcdir) $(PTHREAD_CFLAGS) +AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) +#AM_CFLAGS+= -DDLSEARCHDIR=\"$(pkglibdir)\" AM_LDADD=$(PTHREAD_LIBS) AM_LIBADD=$(PTHREAD_LIBS) @@ -25,7 +26,7 @@ polypincludedir=$(includedir)/polyp EXTRA_DIST = polypaudio.pa depmod.py bin_PROGRAMS = polypaudio pacat pactl -noinst_PROGRAMS = mainloop-test mainloop-test-glib pacat-simple parec-simple +noinst_PROGRAMS = mainloop-test mainloop-test-glib mainloop-test-glib12 pacat-simple parec-simple BUILT_SOURCES=polyplib-version.h @@ -88,6 +89,7 @@ lib_LTLIBRARIES=libpolyp.la \ libpolyp-error.la \ libpolyp-mainloop.la \ libpolyp-mainloop-glib.la \ + libpolyp-mainloop-glib12.la \ libpolyp-simple.la polypaudio_SOURCES = idxset.c idxset.h \ @@ -333,6 +335,11 @@ libpolyp_mainloop_glib_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) libpolyp_mainloop_glib_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop.la $(GLIB20_LIBS) libpolyp_mainloop_glib_la_LDFLAGS = -version-info 0:0:0 +libpolyp_mainloop_glib12_la_SOURCES = glib-mainloop.h glib12-mainloop.c +libpolyp_mainloop_glib12_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS) +libpolyp_mainloop_glib12_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop.la $(GLIB12_LIBS) +libpolyp_mainloop_glib12_la_LDFLAGS = -version-info 0:0:0 + pacat_SOURCES = pacat.c pacat_LDADD = $(AM_LDADD) libpolyp.la libpolyp-error.la libpolyp-mainloop.la pacat_CFLAGS = $(AM_CFLAGS) @@ -357,6 +364,10 @@ mainloop_test_glib_SOURCES = $(mainloop_test_SOURCES) mainloop_test_glib_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB20_CFLAGS) -DGLIB_MAIN_LOOP mainloop_test_glib_LDADD = $(mainloop_test_LDADD) $(GLIB20_LIBS) libpolyp-mainloop-glib.la +mainloop_test_glib12_SOURCES = $(mainloop_test_SOURCES) +mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MAIN_LOOP +mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12.la + if BUILD_LIBPOLYPCORE polypinclude_HEADERS+=cli-command.h\ diff --git a/polyp/glib-mainloop.h b/polyp/glib-mainloop.h index 1fc7f64a..afc83be2 100644 --- a/polyp/glib-mainloop.h +++ b/polyp/glib-mainloop.h @@ -37,7 +37,12 @@ PA_C_DECL_BEGIN struct pa_glib_mainloop; /** Create a new GLIB main loop object for the specified GLIB main loop context. If c is NULL the default context is used. */ +#if GLIB_MAJOR_VERSION >= 2 struct pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c); +#else +struct pa_glib_mainloop *pa_glib_mainloop_new(void); +#endif + /** Free the GLIB main loop object */ void pa_glib_mainloop_free(struct pa_glib_mainloop* g); diff --git a/polyp/glib12-mainloop.c b/polyp/glib12-mainloop.c new file mode 100644 index 00000000..c7085cc9 --- /dev/null +++ b/polyp/glib12-mainloop.c @@ -0,0 +1,497 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "glib-mainloop.h" +#include "idxset.h" +#include "xmalloc.h" + +struct pa_io_event { + struct pa_glib_mainloop *mainloop; + int dead; + GIOChannel *io_channel; + guint source; + GIOCondition io_condition; + int fd; + void (*callback) (struct pa_mainloop_api*m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata); + void *userdata; + void (*destroy_callback) (struct pa_mainloop_api *m, struct pa_io_event*e, void *userdata); + struct pa_io_event *next, *prev; +}; + +struct pa_time_event { + struct pa_glib_mainloop *mainloop; + int dead; + guint source; + struct timeval timeval; + void (*callback) (struct pa_mainloop_api*m, struct pa_time_event *e, const struct timeval *tv, void *userdata); + void *userdata; + void (*destroy_callback) (struct pa_mainloop_api *m, struct pa_time_event*e, void *userdata); + struct pa_time_event *next, *prev; +}; + +struct pa_defer_event { + struct pa_glib_mainloop *mainloop; + int dead; + guint source; + void (*callback) (struct pa_mainloop_api*m, struct pa_defer_event *e, void *userdata); + void *userdata; + void (*destroy_callback) (struct pa_mainloop_api *m, struct pa_defer_event*e, void *userdata); + struct pa_defer_event *next, *prev; +}; + +struct pa_glib_mainloop { + struct pa_mainloop_api api; + guint cleanup_source; + struct pa_io_event *io_events, *dead_io_events; + struct pa_time_event *time_events, *dead_time_events; + struct pa_defer_event *defer_events, *dead_defer_events; +}; + +static void schedule_free_dead_events(struct pa_glib_mainloop *g); + +static void glib_io_enable(struct pa_io_event*e, enum pa_io_event_flags f); + +static struct pa_io_event* glib_io_new(struct pa_mainloop_api*m, int fd, enum pa_io_event_flags f, void (*callback) (struct pa_mainloop_api*m, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata), void *userdata) { + struct pa_io_event *e; + struct pa_glib_mainloop *g; + + assert(m && m->userdata && fd >= 0 && callback); + g = m->userdata; + + e = pa_xmalloc(sizeof(struct pa_io_event)); + e->mainloop = m->userdata; + e->dead = 0; + e->fd = fd; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + + e->io_channel = g_io_channel_unix_new(e->fd); + assert(e->io_channel); + e->source = (guint) -1; + e->io_condition = 0; + + glib_io_enable(e, f); + + e->next = g->io_events; + if (e->next) e->next->prev = e; + g->io_events = e; + e->prev = NULL; + + return e; +} + +static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { + struct pa_io_event *e = data; + enum pa_io_event_flags f; + assert(source && e && e->io_channel == source); + + f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | + (condition & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) | + (condition & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) | + (condition & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0); + + e->callback(&e->mainloop->api, e, e->fd, f, e->userdata); + return TRUE; +} + +static void glib_io_enable(struct pa_io_event*e, enum pa_io_event_flags f) { + GIOCondition c; + assert(e && !e->dead); + + c = (f & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | (f & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0); + + if (c == e->io_condition) + return; + + if (e->source != (guint) -1) + g_source_remove(e->source); + + e->source = g_io_add_watch_full(e->io_channel, G_PRIORITY_DEFAULT, c | G_IO_ERR | G_IO_HUP, io_cb, e, NULL); + assert(e->source != (guint) -1); + e->io_condition = c; +} + +static void glib_io_free(struct pa_io_event*e) { + assert(e && !e->dead); + + if (e->source != (guint) -1) { + g_source_remove(e->source); + e->source = (guint) -1; + } + + if (e->prev) + e->prev->next = e->next; + else + e->mainloop->io_events = e->next; + + if (e->next) + e->next->prev = e->prev; + + if ((e->next = e->mainloop->dead_io_events)) + e->next->prev = e; + + e->mainloop->dead_io_events = e; + e->prev = NULL; + + e->dead = 1; + schedule_free_dead_events(e->mainloop); +} + +static void glib_io_set_destroy(struct pa_io_event*e, void (*callback)(struct pa_mainloop_api*m, struct pa_io_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* Time sources */ + +static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv); + +static struct pa_time_event* glib_time_new(struct pa_mainloop_api*m, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*m, struct pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { + struct pa_glib_mainloop *g; + struct pa_time_event *e; + + assert(m && m->userdata && tv && callback); + g = m->userdata; + + e = pa_xmalloc(sizeof(struct pa_time_event)); + e->mainloop = g; + e->dead = 0; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + e->source = (guint) -1; + + glib_time_restart(e, tv); + + e->next = g->time_events; + if (e->next) e->next->prev = e; + g->time_events = e; + e->prev = NULL; + + return e; +} + +static guint msec_diff(const struct timeval *a, const struct timeval *b) { + guint r; + assert(a && b); + + if (a->tv_sec < b->tv_sec) + return 0; + + if (a->tv_sec == b->tv_sec && a->tv_sec <= b->tv_sec) + return 0; + + r = (a->tv_sec-b->tv_sec)*1000; + + if (a->tv_usec >= b->tv_usec) + r += (a->tv_usec - b->tv_usec) / 1000; + else + r -= (b->tv_usec - a->tv_usec) / 1000; + + return r; +} + +static gboolean time_cb(gpointer data) { + struct pa_time_event* e = data; + assert(e && e->mainloop && e->source != (guint) -1); + + g_source_remove(e->source); + e->source = (guint) -1; + + e->callback(&e->mainloop->api, e, &e->timeval, e->userdata); + return FALSE; +} + +static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv) { + struct timeval now; + assert(e && e->mainloop && !e->dead); + + gettimeofday(&now, NULL); + if (e->source != (guint) -1) + g_source_remove(e->source); + + if (tv) { + e->timeval = *tv; + e->source = g_timeout_add_full(G_PRIORITY_DEFAULT, msec_diff(tv, &now), time_cb, e, NULL); + assert(e->source != (guint) -1); + } else + e->source = (guint) -1; + } + +static void glib_time_free(struct pa_time_event *e) { + assert(e && e->mainloop && !e->dead); + + if (e->source != (guint) -1) { + g_source_remove(e->source); + e->source = (guint) -1; + } + + if (e->prev) + e->prev->next = e->next; + else + e->mainloop->time_events = e->next; + + if (e->next) + e->next->prev = e->prev; + + if ((e->next = e->mainloop->dead_time_events)) + e->next->prev = e; + + e->mainloop->dead_time_events = e; + e->prev = NULL; + + e->dead = 1; + schedule_free_dead_events(e->mainloop); +} + +static void glib_time_set_destroy(struct pa_time_event *e, void (*callback)(struct pa_mainloop_api*m, struct pa_time_event*e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* Deferred sources */ + +static void glib_defer_enable(struct pa_defer_event *e, int b); + +static struct pa_defer_event* glib_defer_new(struct pa_mainloop_api*m, void (*callback) (struct pa_mainloop_api*m, struct pa_defer_event *e, void *userdata), void *userdata) { + struct pa_defer_event *e; + struct pa_glib_mainloop *g; + + assert(m && m->userdata && callback); + g = m->userdata; + + e = pa_xmalloc(sizeof(struct pa_defer_event)); + e->mainloop = g; + e->dead = 0; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + e->source = (guint) -1; + + glib_defer_enable(e, 1); + + e->next = g->defer_events; + if (e->next) e->next->prev = e; + g->defer_events = e; + e->prev = NULL; + return e; +} + +static gboolean idle_cb(gpointer data) { + struct pa_defer_event* e = data; + assert(e && e->mainloop && e->source != (guint) -1); + + e->callback(&e->mainloop->api, e, e->userdata); + return TRUE; +} + +static void glib_defer_enable(struct pa_defer_event *e, int b) { + assert(e && e->mainloop); + + if (e->source != (guint) -1 && !b) { + g_source_remove(e->source); + e->source = (guint) -1; + } else if (e->source == (guint) -1 && b) { + e->source = g_idle_add_full(G_PRIORITY_HIGH, idle_cb, e, NULL); + assert(e->source != (guint) -1); + } +} + +static void glib_defer_free(struct pa_defer_event *e) { + assert(e && e->mainloop && !e->dead); + + if (e->source != (guint) -1) { + g_source_remove(e->source); + e->source = (guint) -1; + } + + if (e->prev) + e->prev->next = e->next; + else + e->mainloop->defer_events = e->next; + + if (e->next) + e->next->prev = e->prev; + + if ((e->next = e->mainloop->dead_defer_events)) + e->next->prev = e; + + e->mainloop->dead_defer_events = e; + e->prev = NULL; + + e->dead = 1; + schedule_free_dead_events(e->mainloop); +} + +static void glib_defer_set_destroy(struct pa_defer_event *e, void (*callback)(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* quit() */ + +static void glib_quit(struct pa_mainloop_api*a, int retval) { + struct pa_glib_mainloop *g; + assert(a && a->userdata); + g = a->userdata; + + /* NOOP */ +} + +static const struct pa_mainloop_api vtable = { + .userdata = NULL, + + .io_new = glib_io_new, + .io_enable = glib_io_enable, + .io_free = glib_io_free, + .io_set_destroy= glib_io_set_destroy, + + .time_new = glib_time_new, + .time_restart = glib_time_restart, + .time_free = glib_time_free, + .time_set_destroy = glib_time_set_destroy, + + .defer_new = glib_defer_new, + .defer_enable = glib_defer_enable, + .defer_free = glib_defer_free, + .defer_set_destroy = glib_defer_set_destroy, + + .quit = glib_quit, +}; + +struct pa_glib_mainloop *pa_glib_mainloop_new(void) { + struct pa_glib_mainloop *g; + + g = pa_xmalloc(sizeof(struct pa_glib_mainloop)); + + g->api = vtable; + g->api.userdata = g; + + g->io_events = g->dead_io_events = NULL; + g->time_events = g->dead_time_events = NULL; + g->defer_events = g->dead_defer_events = NULL; + + g->cleanup_source = (guint) -1; + return g; +} + +static void free_io_events(struct pa_io_event *e) { + while (e) { + struct pa_io_event *r = e; + e = r->next; + + if (r->source != (guint) -1) + g_source_remove(r->source); + + if (r->io_channel) + g_io_channel_unref(r->io_channel); + + if (r->destroy_callback) + r->destroy_callback(&r->mainloop->api, r, r->userdata); + + pa_xfree(r); + } +} + +static void free_time_events(struct pa_time_event *e) { + while (e) { + struct pa_time_event *r = e; + e = r->next; + + if (r->source != (guint) -1) + g_source_remove(r->source); + + if (r->destroy_callback) + r->destroy_callback(&r->mainloop->api, r, r->userdata); + + pa_xfree(r); + } +} + +static void free_defer_events(struct pa_defer_event *e) { + while (e) { + struct pa_defer_event *r = e; + e = r->next; + + if (r->source != (guint) -1) + g_source_remove(r->source); + + if (r->destroy_callback) + r->destroy_callback(&r->mainloop->api, r, r->userdata); + + pa_xfree(r); + } +} + +void pa_glib_mainloop_free(struct pa_glib_mainloop* g) { + assert(g); + + free_io_events(g->io_events); + free_io_events(g->dead_io_events); + free_defer_events(g->defer_events); + free_defer_events(g->dead_defer_events); + free_time_events(g->time_events); + free_time_events(g->dead_time_events); + + if (g->cleanup_source != (guint) -1) + g_source_remove(g->cleanup_source); + + pa_xfree(g); +} + +struct pa_mainloop_api* pa_glib_mainloop_get_api(struct pa_glib_mainloop *g) { + assert(g); + return &g->api; +} + +static gboolean free_dead_events(gpointer p) { + struct pa_glib_mainloop *g = p; + assert(g); + + free_io_events(g->dead_io_events); + free_defer_events(g->dead_defer_events); + free_time_events(g->dead_time_events); + + g->dead_io_events = NULL; + g->dead_defer_events = NULL; + g->dead_time_events = NULL; + + g_source_remove(g->cleanup_source); + g->cleanup_source = (guint) -1; + + return FALSE; +} + +static void schedule_free_dead_events(struct pa_glib_mainloop *g) { + assert(g); + + if (g->cleanup_source != (guint) -1) + return; + + g->cleanup_source = g_idle_add_full(G_PRIORITY_HIGH, free_dead_events, g, NULL); +} diff --git a/polyp/mainloop-test.c b/polyp/mainloop-test.c index c2517065..92b83c14 100644 --- a/polyp/mainloop-test.c +++ b/polyp/mainloop-test.c @@ -29,12 +29,21 @@ #include #ifdef GLIB_MAIN_LOOP + #include #include "glib-mainloop.h" static GMainLoop* glib_main_loop = NULL; + +#if GLIB_MAJOR_VERSION >= 2 +#define GLIB20 #else +#undef GLIB20 +#endif + + +#else /* GLIB_MAIN_LOOP */ #include "mainloop.h" -#endif +#endif /* GLIB_MAIN_LOOP */ static struct pa_defer_event *de; @@ -53,8 +62,10 @@ static void dcb(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userda static void tcb(struct pa_mainloop_api*a, struct pa_time_event *e, const struct timeval *tv, void *userdata) { fprintf(stderr, "TIME EVENT\n"); -#ifdef GLIB_MAIN_LOOP +#if defined(GLIB_MAIN_LOOP) && defined(GLIB20) g_main_loop_quit(glib_main_loop); +#elif defined(GLIB_MAIN_LOOP) + g_main_quit(glib_main_loop); #else a->quit(a, 0); #endif @@ -68,15 +79,23 @@ int main(int argc, char *argv[]) { #ifdef GLIB_MAIN_LOOP struct pa_glib_mainloop *g; + +#ifdef GLIB20 glib_main_loop = g_main_loop_new(NULL, FALSE); assert(glib_main_loop); g = pa_glib_mainloop_new(NULL); +#else /* GLIB20 */ + glib_main_loop = g_main_new(FALSE); + assert(glib_main_loop); + + g = pa_glib_mainloop_new(); +#endif /* GLIB20 */ assert(g); a = pa_glib_mainloop_get_api(g); assert(a); -#else +#else /* GLIB_MAIN_LOOP */ struct pa_mainloop *m; m = pa_mainloop_new(); @@ -84,7 +103,7 @@ int main(int argc, char *argv[]) { a = pa_mainloop_get_api(m); assert(a); -#endif +#endif /* GLIB_MAIN_LOOP */ ioe = a->io_new(a, 0, PA_IO_EVENT_INPUT, iocb, NULL); assert(ioe); @@ -96,8 +115,10 @@ int main(int argc, char *argv[]) { tv.tv_sec += 10; te = a->time_new(a, &tv, tcb, NULL); -#ifdef GLIB_MAIN_LOOP +#if defined(GLIB_MAIN_LOOP) && defined(GLIB20) g_main_loop_run(glib_main_loop); +#elif defined(GLIB_MAIN_LOOP) + g_main_run(glib_main_loop); #else pa_mainloop_run(m, NULL); #endif @@ -108,7 +129,11 @@ int main(int argc, char *argv[]) { #ifdef GLIB_MAIN_LOOP pa_glib_mainloop_free(g); +#ifdef GLIB20 g_main_loop_unref(glib_main_loop); +#else + g_main_destroy(glib_main_loop); +#endif #else pa_mainloop_free(m); #endif diff --git a/polyp/polypaudio.pa b/polyp/polypaudio.pa index 9f8cf860..c63e1479 100755 --- a/polyp/polypaudio.pa +++ b/polyp/polypaudio.pa @@ -30,8 +30,8 @@ load module-pipe-sink #autoload_sink_add output module-oss device="/dev/dsp" sink_name=output source_name=input #autoload_source_add input module-oss device="/dev/dsp" sink_name=output source_name=input -#autoload_sink_add output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#autoload_source_add input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +autoload_sink_add output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +autoload_source_add input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input #autoload_sink_add output module-alsa-sink sink_name=output #autoload_source_add input module-alsa-source source_name=input @@ -52,7 +52,6 @@ source_default input # Load something to the sample cache scache_load /usr/share/sounds/KDE_Notify.wav x11-bell -scache_play x11-bell output # Load X11 bell module load module-x11-bell sample=x11-bell sink=output -- cgit From ea4805a0fd4aea6db4c99e1187aca8e013e4dc24 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 Aug 2004 20:30:06 +0000 Subject: add pkg config file glib12-mainloop git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@151 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- configure.ac | 2 +- polyplib-glib12-mainloop.pc.in | 11 +++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 polyplib-glib12-mainloop.pc.in diff --git a/Makefile.am b/Makefile.am index 632d226f..3eeef956 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,7 +24,7 @@ MAINTAINERCLEANFILES=README noinst_DATA = README pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc polyplib-glib-mainloop.pc +pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc polyplib-glib-mainloop.pc polyplib-glib12-mainloop.pc README: rm -f README diff --git a/configure.ac b/configure.ac index 8307bea5..7e0b3c21 100644 --- a/configure.ac +++ b/configure.ac @@ -115,5 +115,5 @@ AM_CONDITIONAL([USE_LYNX], [test "x$lynx" = xyes]) AM_CONDITIONAL(BUILD_LIBPOLYPCORE, false) -AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc polyplib-glib-mainloop.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf polyp/polyplib-version.h]) +AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc polyplib-glib-mainloop.pc polyplib-glib12-mainloop.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf polyp/polyplib-version.h]) AC_OUTPUT diff --git a/polyplib-glib12-mainloop.pc.in b/polyplib-glib12-mainloop.pc.in new file mode 100644 index 00000000..3afed38e --- /dev/null +++ b/polyplib-glib12-mainloop.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: polyplib-glib-mainloop +Description: GLIB main loop wrapper for polypaudio +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lpolyp-mainloop-glib12 +Cflags: -D_REENTRANT -I${includedir} +Requires: polyplib-mainloop -- cgit From 41295bbf56ef6df0a0e705149475d91c8d83ff3f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 22 Aug 2004 21:13:58 +0000 Subject: new features: future cancellation corking flushing for playback streams in native protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@152 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/memblockq.c | 165 +++++++++++++++++++++++------------------------ polyp/memblockq.h | 16 +++-- polyp/native-common.h | 3 + polyp/pacat.c | 2 +- polyp/pactl.c | 2 +- polyp/play-memchunk.c | 3 +- polyp/polyplib-context.c | 2 +- polyp/polyplib-simple.c | 2 +- polyp/polyplib-stream.c | 49 +++++++++++++- polyp/polyplib-stream.h | 35 +++++++++- polyp/protocol-esound.c | 8 +-- polyp/protocol-native.c | 68 +++++++++++++++++-- polyp/protocol-simple.c | 6 +- polyp/pstream.c | 10 +-- polyp/pstream.h | 4 +- polyp/sink-input.c | 23 +++++-- polyp/sink-input.h | 8 ++- polyp/sink.c | 2 +- polyp/util.c | 21 ++++++ polyp/util.h | 3 + 20 files changed, 306 insertions(+), 126 deletions(-) diff --git a/polyp/memblockq.c b/polyp/memblockq.c index 085c0510..b6dcca3f 100644 --- a/polyp/memblockq.c +++ b/polyp/memblockq.c @@ -28,22 +28,20 @@ #include #include #include +#include #include "memblockq.h" #include "xmalloc.h" struct memblock_list { - struct memblock_list *next; + struct memblock_list *next, *prev; struct pa_memchunk chunk; - struct timeval stamp; }; struct pa_memblockq { struct memblock_list *blocks, *blocks_tail; unsigned n_blocks; size_t current_length, maxlength, tlength, base, prebuf, minreq; - int measure_delay; - uint32_t delay; struct pa_mcalign *mcalign; struct pa_memblock_stat *memblock_stat; }; @@ -66,7 +64,7 @@ struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t b assert(bq->maxlength >= base); bq->tlength = ((tlength+base-1)/base)*base; - if (bq->tlength == 0 || bq->tlength >= bq->maxlength) + if (!bq->tlength || bq->tlength >= bq->maxlength) bq->tlength = bq->maxlength; bq->prebuf = (prebuf == (size_t) -1) ? bq->maxlength/2 : prebuf; @@ -80,29 +78,21 @@ struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t b fprintf(stderr, "memblockq sanitized: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", bq->maxlength, bq->tlength, bq->base, bq->prebuf, bq->minreq); - bq->measure_delay = 0; - bq->delay = 0; - bq->mcalign = NULL; bq->memblock_stat = s; - + return bq; } void pa_memblockq_free(struct pa_memblockq* bq) { - struct memblock_list *l; assert(bq); + pa_memblockq_flush(bq); + if (bq->mcalign) pa_mcalign_free(bq->mcalign); - while ((l = bq->blocks)) { - bq->blocks = l->next; - pa_memblock_unref(l->chunk.memblock); - pa_xfree(l); - } - pa_xfree(bq); } @@ -110,31 +100,25 @@ void pa_memblockq_push(struct pa_memblockq* bq, const struct pa_memchunk *chunk, struct memblock_list *q; assert(bq && chunk && chunk->memblock && chunk->length && (chunk->length % bq->base) == 0); + pa_memblockq_seek(bq, delta); + if (bq->blocks_tail && bq->blocks_tail->chunk.memblock == chunk->memblock) { /* Try to merge memory chunks */ if (bq->blocks_tail->chunk.index+bq->blocks_tail->chunk.length == chunk->index) { bq->blocks_tail->chunk.length += chunk->length; bq->current_length += chunk->length; - - /* fprintf(stderr, __FILE__": merge succeeded: %u\n", chunk->length);*/ return; } } q = pa_xmalloc(sizeof(struct memblock_list)); - if (bq->measure_delay) - gettimeofday(&q->stamp, NULL); - else - timerclear(&q->stamp); - q->chunk = *chunk; pa_memblock_ref(q->chunk.memblock); assert(q->chunk.index+q->chunk.length <= q->chunk.memblock->length); q->next = NULL; - - if (bq->blocks_tail) + if ((q->prev = bq->blocks_tail)) bq->blocks_tail->next = q; else bq->blocks = q; @@ -158,57 +142,43 @@ int pa_memblockq_peek(struct pa_memblockq* bq, struct pa_memchunk *chunk) { *chunk = bq->blocks->chunk; pa_memblock_ref(chunk->memblock); -/* if (chunk->memblock->ref != 2) */ -/* fprintf(stderr, "block %p with ref %u peeked.\n", chunk->memblock, chunk->memblock->ref); */ - return 0; } -/* -int memblockq_pop(struct memblockq* bq, struct pa_memchunk *chunk) { - struct memblock_list *q; - - assert(bq && chunk); - - if (!bq->blocks || bq->current_length < bq->prebuf) - return -1; - - bq->prebuf = 0; - - q = bq->blocks; - bq->blocks = bq->blocks->next; - - *chunk = q->chunk; +void pa_memblockq_drop(struct pa_memblockq *bq, const struct pa_memchunk *chunk, size_t length) { + assert(bq && chunk && length); - bq->n_blocks--; - bq->current_length -= chunk->length; + if (!bq->blocks || memcmp(&bq->blocks->chunk, chunk, sizeof(struct pa_memchunk))) + return; - pa_xfree(q); - return 0; + assert(length <= bq->blocks->chunk.length); + pa_memblockq_skip(bq, length); } -*/ -static uint32_t age(struct timeval *tv) { - struct timeval now; - uint32_t r; - assert(tv); +static void remove_block(struct pa_memblockq *bq, struct memblock_list *q) { + assert(bq && q); - if (tv->tv_sec == 0) - return 0; - - gettimeofday(&now, NULL); + if (q->prev) + q->prev->next = q->next; + else { + assert(bq->blocks == q); + bq->blocks = q->next; + } - r = (now.tv_sec-tv->tv_sec) * 1000000; - - if (now.tv_usec >= tv->tv_usec) - r += now.tv_usec - tv->tv_usec; - else - r -= tv->tv_usec - now.tv_usec; - - return r; + if (q->next) + q->next->prev = q->prev; + else { + assert(bq->blocks_tail == q); + bq->blocks_tail = q->prev; + } + + pa_memblock_unref(q->chunk.memblock); + pa_xfree(q); + + bq->n_blocks--; } -void pa_memblockq_drop(struct pa_memblockq *bq, size_t length) { +void pa_memblockq_skip(struct pa_memblockq *bq, size_t length) { assert(bq && length && (length % bq->base) == 0); while (length > 0) { @@ -218,25 +188,12 @@ void pa_memblockq_drop(struct pa_memblockq *bq, size_t length) { if (l > bq->blocks->chunk.length) l = bq->blocks->chunk.length; - if (bq->measure_delay) - bq->delay = age(&bq->blocks->stamp); - bq->blocks->chunk.index += l; bq->blocks->chunk.length -= l; bq->current_length -= l; - if (bq->blocks->chunk.length == 0) { - struct memblock_list *q; - - q = bq->blocks; - bq->blocks = bq->blocks->next; - if (bq->blocks == NULL) - bq->blocks_tail = NULL; - pa_memblock_unref(q->chunk.memblock); - pa_xfree(q); - - bq->n_blocks--; - } + if (!bq->blocks->chunk.length) + remove_block(bq, bq->blocks); length -= l; } @@ -255,7 +212,7 @@ void pa_memblockq_shorten(struct pa_memblockq *bq, size_t length) { l /= bq->base; l *= bq->base; - pa_memblockq_drop(bq, l); + pa_memblockq_skip(bq, l); } @@ -276,11 +233,6 @@ int pa_memblockq_is_writable(struct pa_memblockq *bq, size_t length) { return bq->current_length + length <= bq->tlength; } -uint32_t pa_memblockq_get_delay(struct pa_memblockq *bq) { - assert(bq); - return bq->delay; -} - uint32_t pa_memblockq_get_length(struct pa_memblockq *bq) { assert(bq); return bq->current_length; @@ -331,3 +283,44 @@ void pa_memblockq_prebuf_disable(struct pa_memblockq *bq) { assert(bq); bq->prebuf = 0; } + +void pa_memblockq_seek(struct pa_memblockq *bq, size_t length) { + assert(bq); + + if (!length) + return; + + while (length >= bq->base) { + size_t l = length; + if (!bq->current_length) + return; + + assert(bq->blocks_tail); + + if (l > bq->blocks_tail->chunk.length) + l = bq->blocks_tail->chunk.length; + + bq->blocks_tail->chunk.length -= l; + bq->current_length -= l; + + if (bq->blocks_tail->chunk.length == 0) + remove_block(bq, bq->blocks); + + length -= l; + } +} + +void pa_memblockq_flush(struct pa_memblockq *bq) { + struct memblock_list *l; + assert(bq); + + while ((l = bq->blocks)) { + bq->blocks = l->next; + pa_memblock_unref(l->chunk.memblock); + pa_xfree(l); + } + + bq->blocks_tail = NULL; + bq->n_blocks = 0; + bq->current_length = 0; +} diff --git a/polyp/memblockq.h b/polyp/memblockq.h index af8fa374..277beb55 100644 --- a/polyp/memblockq.h +++ b/polyp/memblockq.h @@ -44,7 +44,7 @@ struct pa_memblockq* pa_memblockq_new(size_t maxlength, struct pa_memblock_stat *s); void pa_memblockq_free(struct pa_memblockq*bq); -/* Push a new memory chunk into the queue. Optionally specify a value for future cancellation. This is currently not implemented, however! */ +/* Push a new memory chunk into the queue. Optionally specify a value for future cancellation. */ void pa_memblockq_push(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta); /* Same as pa_memblockq_push(), however chunks are filtered through a mcalign object, and thus aligned to multiples of base */ @@ -53,8 +53,11 @@ void pa_memblockq_push_align(struct pa_memblockq* bq, const struct pa_memchunk * /* Return a copy of the next memory chunk in the queue. It is not removed from the queue */ int pa_memblockq_peek(struct pa_memblockq* bq, struct pa_memchunk *chunk); +/* Drop the specified bytes from the queue, only valid aufter pa_memblockq_peek() */ +void pa_memblockq_drop(struct pa_memblockq *bq, const struct pa_memchunk *chunk, size_t length); + /* Drop the specified bytes from the queue */ -void pa_memblockq_drop(struct pa_memblockq *bq, size_t length); +void pa_memblockq_skip(struct pa_memblockq *bq, size_t length); /* Shorten the pa_memblockq to the specified length by dropping data at the end of the queue */ void pa_memblockq_shorten(struct pa_memblockq *bq, size_t length); @@ -68,9 +71,6 @@ int pa_memblockq_is_readable(struct pa_memblockq *bq); /* Test if the pa_memblockq is currently writable for the specified amount of bytes */ int pa_memblockq_is_writable(struct pa_memblockq *bq, size_t length); -/* The time memory chunks stay in the queue until they are removed completely in usecs */ -uint32_t pa_memblockq_get_delay(struct pa_memblockq *bq); - /* Return the length of the queue in bytes */ uint32_t pa_memblockq_get_length(struct pa_memblockq *bq); @@ -83,4 +83,10 @@ uint32_t pa_memblockq_get_minreq(struct pa_memblockq *bq); /* Force disabling of pre-buf even when the pre-buffer is not yet filled */ void pa_memblockq_prebuf_disable(struct pa_memblockq *bq); +/* Manipulate the write pointer */ +void pa_memblockq_seek(struct pa_memblockq *bq, size_t delta); + +/* Flush the queue */ +void pa_memblockq_flush(struct pa_memblockq *bq); + #endif diff --git a/polyp/native-common.h b/polyp/native-common.h index b921ccc2..d826837a 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -75,6 +75,9 @@ enum { PA_COMMAND_SET_SINK_VOLUME, PA_COMMAND_SET_SINK_INPUT_VOLUME, + + PA_COMMAND_CORK_PLAYBACK_STREAM, + PA_COMMAND_FLUSH_PLAYBACK_STREAM, PA_COMMAND_MAX }; diff --git a/polyp/pacat.c b/polyp/pacat.c index 2c7044b8..198776d3 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -65,7 +65,7 @@ static void do_stream_write(size_t length) { if (l > buffer_length) l = buffer_length; - pa_stream_write(stream, buffer+buffer_index, l, NULL); + pa_stream_write(stream, buffer+buffer_index, l, NULL, 0); buffer_length -= l; buffer_index += l; diff --git a/polyp/pactl.c b/polyp/pactl.c index f2556706..dfa11b70 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -150,7 +150,7 @@ static void stream_write_callback(struct pa_stream *s, size_t length, void *user quit(1); } - pa_stream_write(s, d, length, free); + pa_stream_write(s, d, length, free, 0); sample_length -= length; diff --git a/polyp/play-memchunk.c b/polyp/play-memchunk.c index 5c423567..b94a0524 100644 --- a/polyp/play-memchunk.c +++ b/polyp/play-memchunk.c @@ -59,11 +59,12 @@ static void si_kill(struct pa_mainloop_api *m, void *i) { sink_input_kill(i); } -static void sink_input_drop(struct pa_sink_input *i, size_t length) { +static void sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk*chunk, size_t length) { struct pa_memchunk *c; assert(i && length && i->userdata); c = i->userdata; + assert(chunk == c); assert(length <= c->length); c->length -= length; diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index d048cda9..9acb2d70 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -193,7 +193,7 @@ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *pack pa_context_unref(c); } -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { +static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk, void *userdata) { struct pa_context *c = userdata; struct pa_stream *s; assert(p && chunk && c && chunk->memblock && chunk->memblock->data); diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c index 66ee5995..c71d59a4 100644 --- a/polyp/polyplib-simple.c +++ b/polyp/polyplib-simple.c @@ -187,7 +187,7 @@ int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *pe if (l > length) l = length; - pa_stream_write(p->stream, data, l, NULL); + pa_stream_write(p->stream, data, l, NULL, 0); data += l; length -= l; } diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 451dd046..c0ec9e7e 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -267,7 +267,7 @@ void pa_stream_connect_record(struct pa_stream *s, const char *dev, const struct create_stream(s, dev, attr); } -void pa_stream_write(struct pa_stream *s, const void *data, size_t length, void (*free_cb)(void *p)) { +void pa_stream_write(struct pa_stream *s, const void *data, size_t length, void (*free_cb)(void *p), size_t delta) { struct pa_memchunk chunk; assert(s && s->context && data && length && s->state == PA_STREAM_READY && s->ref >= 1); @@ -282,7 +282,7 @@ void pa_stream_write(struct pa_stream *s, const void *data, size_t length, void chunk.index = 0; chunk.length = length; - pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); + pa_pstream_send_memblock(s->context->pstream, s->channel, delta, &chunk); pa_memblock_unref(chunk.memblock); if (length < s->requested_bytes) @@ -452,3 +452,48 @@ finish: pa_operation_done(o); pa_operation_unref(o); } + +struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { + struct pa_operation *o; + struct pa_tagstruct *t; + uint32_t tag; + assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); + + o = pa_operation_new(s->context, s); + assert(o); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_CORK_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_tagstruct_putu32(t, !!b); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +struct pa_operation* pa_stream_flush(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { + struct pa_operation *o; + struct pa_tagstruct *t; + uint32_t tag; + assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); + + o = pa_operation_new(s->context, s); + assert(o); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_FLUSH_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); + + return pa_operation_ref(o); +} diff --git a/polyp/polyplib-stream.h b/polyp/polyplib-stream.h index 1a9d58dd..ff313326 100644 --- a/polyp/polyplib-stream.h +++ b/polyp/polyplib-stream.h @@ -70,7 +70,30 @@ void pa_stream_disconnect(struct pa_stream *s); * and an internal reference to the specified data is kept, the data * is not copied. If NULL, the data is copied into an internal * buffer. */ -void pa_stream_write(struct pa_stream *p, const void *data, size_t length, void (*free_cb)(void *p)); +void pa_stream_write(struct pa_stream *p /**< The stream to use */, + const void *data /**< The data to write */, + size_t length /**< The length of the data to write */, + void (*free_cb)(void *p) /**< A cleanup routine for the data or NULL to request an internal copy */, + size_t delta /**< Drop this many + bytes in the playback + buffer before writing + this data. Use + (size_t) -1 for + clearing the whole + playback + buffer. Normally you + will specify 0 here, + .i.e. append to the + playback buffer. If + the value given here + is greater than the + buffered data length + the buffer is cleared + and the data is + written to the + buffer's start. This + value is ignored on + upload streams. */); /** Return the amount of bytes that may be written using pa_stream_write() */ size_t pa_stream_writable_size(struct pa_stream *p); @@ -90,6 +113,16 @@ void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stre /** Set the callback function that is called when new data is available from the stream */ void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); +/** Pause (or resume) playback of this stream temporarily + * \since 0.3 */ +struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); + +/** Flush the playback buffer of this stream. Most of the time you're + * better off using the delta of pa_stream_write() instead of this + * function. + * \since 0.3*/ +struct pa_operation* pa_stream_flush(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata); + PA_C_DECL_END #endif diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index be2ef2b9..5102540b 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -102,7 +102,7 @@ typedef struct proto_handler { const char *description; } esd_proto_handler_info_t; -static void sink_input_drop_cb(struct pa_sink_input *i, size_t length); +static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length); static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk); static void sink_input_kill_cb(struct pa_sink_input *i); static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i); @@ -835,7 +835,7 @@ static int do_write(struct connection *c) { return -1; } - pa_memblockq_drop(c->output_memblockq, r); + pa_memblockq_drop(c->output_memblockq, &chunk, r); pa_memblock_unref(chunk.memblock); } @@ -894,11 +894,11 @@ static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk return 0; } -static void sink_input_drop_cb(struct pa_sink_input *i, size_t length) { +static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length) { struct connection*c = i->userdata; assert(i && c && length); - pa_memblockq_drop(c->input_memblockq, length); + pa_memblockq_drop(c->input_memblockq, chunk, length); /* do something */ assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index c8e5137e..8b39482c 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -107,7 +107,7 @@ struct pa_protocol_native { }; static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk); -static void sink_input_drop_cb(struct pa_sink_input *i, size_t length); +static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length); static void sink_input_kill_cb(struct pa_sink_input *i); static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i); @@ -135,6 +135,8 @@ static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uin static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_subscribe(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_set_volume(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_cork_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_flush_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = { NULL }, @@ -176,6 +178,8 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_SUBSCRIBE] = { command_subscribe }, [PA_COMMAND_SET_SINK_VOLUME] = { command_set_volume }, [PA_COMMAND_SET_SINK_INPUT_VOLUME] = { command_set_volume }, + [PA_COMMAND_CORK_PLAYBACK_STREAM] = { command_cork_playback_stream }, + [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = { command_flush_playback_stream }, }; /* structure management */ @@ -376,7 +380,7 @@ static void send_memblock(struct connection *c) { chunk.length = r->fragment_size; pa_pstream_send_memblock(c->pstream, r->index, 0, &chunk); - pa_memblockq_drop(r->memblockq, chunk.length); + pa_memblockq_drop(r->memblockq, &chunk, chunk.length); pa_memblock_unref(chunk.memblock); return; @@ -422,12 +426,12 @@ static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk return 0; } -static void sink_input_drop_cb(struct pa_sink_input *i, size_t length) { +static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length) { struct playback_stream *s; assert(i && i->userdata && length); s = i->userdata; - pa_memblockq_drop(s->memblockq, length); + pa_memblockq_drop(s->memblockq, chunk, length); request_bytes(s); if (s->drain_request && !pa_memblockq_is_readable(s->memblockq)) { @@ -1293,6 +1297,59 @@ static void command_set_volume(struct pa_pdispatch *pd, uint32_t command, uint32 pa_pstream_send_simple_ack(c->pstream, tag); } +static void command_cork_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t index; + uint32_t b; + struct playback_stream *s; + assert(c && t); + + if (pa_tagstruct_getu32(t, &index) < 0 || + pa_tagstruct_getu32(t, &b) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->output_streams, index)) || s->type != PLAYBACK_STREAM) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_sink_input_cork(s->sink_input, b); + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_flush_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t index; + struct playback_stream *s; + assert(c && t); + + if (pa_tagstruct_getu32(t, &index) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->output_streams, index)) || s->type != PLAYBACK_STREAM) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_memblockq_flush(s->memblockq); + pa_pstream_send_simple_ack(c->pstream, tag); +} /*** pstream callbacks ***/ @@ -1306,7 +1363,7 @@ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *pack } } -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { +static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk, void *userdata) { struct connection *c = userdata; struct output_stream *stream; assert(p && chunk && userdata); @@ -1338,7 +1395,6 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, in u->memchunk = *chunk; pa_memblock_ref(u->memchunk.memblock); u->length = 0; - fprintf(stderr, "COPY\n"); } else { u->memchunk.memblock = pa_memblock_new(u->length, c->protocol->core->memblock_stat); u->memchunk.index = u->memchunk.length = 0; diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index 58343486..b03c2e54 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -159,7 +159,7 @@ static int do_write(struct connection *c) { return -1; } - pa_memblockq_drop(c->output_memblockq, r); + pa_memblockq_drop(c->output_memblockq, &chunk, r); pa_memblock_unref(chunk.memblock); return 0; @@ -202,11 +202,11 @@ static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk return 0; } -static void sink_input_drop_cb(struct pa_sink_input *i, size_t length) { +static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length) { struct connection*c = i->userdata; assert(i && c && length); - pa_memblockq_drop(c->input_memblockq, length); + pa_memblockq_drop(c->input_memblockq, chunk, length); /* do something */ assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); diff --git a/polyp/pstream.c b/polyp/pstream.c index 5664e18a..ad3dd0e0 100644 --- a/polyp/pstream.c +++ b/polyp/pstream.c @@ -50,7 +50,7 @@ struct item_info { /* memblock info */ struct pa_memchunk chunk; uint32_t channel; - int32_t delta; + uint32_t delta; /* packet info */ struct pa_packet *packet; @@ -86,7 +86,7 @@ struct pa_pstream { void (*recieve_packet_callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata); void *recieve_packet_callback_userdata; - void (*recieve_memblock_callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata); + void (*recieve_memblock_callback) (struct pa_pstream *p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk, void *userdata); void *recieve_memblock_callback_userdata; void (*drain_callback)(struct pa_pstream *p, void *userdata); @@ -219,7 +219,7 @@ void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet) { p->mainloop->defer_enable(p->defer_event, 1); } -void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk) { +void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk) { struct item_info *i; assert(p && channel != (uint32_t) -1 && chunk); @@ -242,7 +242,7 @@ void pa_pstream_set_recieve_packet_callback(struct pa_pstream *p, void (*callbac p->recieve_packet_callback_userdata = userdata; } -void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata), void *userdata) { +void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk, void *userdata), void *userdata) { assert(p && callback); p->recieve_memblock_callback = callback; @@ -378,7 +378,7 @@ static void do_read(struct pa_pstream *p) { p->recieve_memblock_callback( p, ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]), - (int32_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA]), + ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA]), &chunk, p->recieve_memblock_callback_userdata); } diff --git a/polyp/pstream.h b/polyp/pstream.h index 9a289507..dfd29983 100644 --- a/polyp/pstream.h +++ b/polyp/pstream.h @@ -37,10 +37,10 @@ void pa_pstream_unref(struct pa_pstream*p); struct pa_pstream* pa_pstream_ref(struct pa_pstream*p); void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet); -void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk); +void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk); void pa_pstream_set_recieve_packet_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata), void *userdata); -void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata), void *userdata); +void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk, void *userdata), void *userdata); void pa_pstream_set_drain_callback(struct pa_pstream *p, void (*cb)(struct pa_pstream *p, void *userdata), void *userdata); void pa_pstream_set_die_callback(struct pa_pstream *p, void (*callback)(struct pa_pstream *p, void *userdata), void *userdata); diff --git a/polyp/sink-input.c b/polyp/sink-input.c index c57dd8e0..5009033f 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -59,6 +59,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con i->get_latency = NULL; i->userdata = NULL; + i->corked = 0; i->volume = PA_VOLUME_NORM; i->resampled_chunk.memblock = NULL; @@ -120,6 +121,9 @@ uint32_t pa_sink_input_get_latency(struct pa_sink_input *i) { int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { assert(i && chunk && i->peek && i->drop); + if (i->corked == 0) + return -1; + if (!i->resampler) return i->peek(i, chunk); @@ -134,11 +138,12 @@ int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { assert(tchunk.length); l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); + + i->drop(i, &tchunk, l); + if (tchunk.length > l) tchunk.length = l; - i->drop(i, tchunk.length); - pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk); pa_memblock_unref(tchunk.memblock); } @@ -149,11 +154,11 @@ int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { return 0; } -void pa_sink_input_drop(struct pa_sink_input *i, size_t length) { +void pa_sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length) { assert(i && length); if (!i->resampler) { - i->drop(i, length); + i->drop(i, chunk, length); return; } @@ -177,3 +182,13 @@ void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume) { pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); } } + +void pa_sink_input_cork(struct pa_sink_input *i, int b) { + int n; + assert(i); + n = i->corked && !b; + i->corked = b; + + if (n) + pa_sink_notify(i->sink); +} diff --git a/polyp/sink-input.h b/polyp/sink-input.h index 8d7788d8..b0644540 100644 --- a/polyp/sink-input.h +++ b/polyp/sink-input.h @@ -34,6 +34,8 @@ struct pa_sink_input { uint32_t index; + int corked; + char *name; struct pa_module *owner; struct pa_client *client; @@ -42,7 +44,7 @@ struct pa_sink_input { uint32_t volume; int (*peek) (struct pa_sink_input *i, struct pa_memchunk *chunk); - void (*drop) (struct pa_sink_input *i, size_t length); + void (*drop) (struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length); void (*kill) (struct pa_sink_input *i); uint32_t (*get_latency) (struct pa_sink_input *i); @@ -62,8 +64,10 @@ void pa_sink_input_kill(struct pa_sink_input *i); uint32_t pa_sink_input_get_latency(struct pa_sink_input *i); int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk); -void pa_sink_input_drop(struct pa_sink_input *i, size_t length); +void pa_sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length); void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume); +void pa_sink_input_cork(struct pa_sink_input *i, int b); + #endif diff --git a/polyp/sink.c b/polyp/sink.c index 62b9a7af..43fd351c 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -147,8 +147,8 @@ static void inputs_drop(struct pa_sink *s, struct pa_mix_info *info, unsigned ma struct pa_sink_input *i = info->userdata; assert(i && info->chunk.memblock); + pa_sink_input_drop(i, &info->chunk, length); pa_memblock_unref(info->chunk.memblock); - pa_sink_input_drop(i, length); } } diff --git a/polyp/util.c b/polyp/util.c index 2878c546..6c8febb6 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "util.h" #include "xmalloc.h" @@ -192,3 +193,23 @@ char *pa_get_host_name(char *s, size_t l) { s[l-1] = 0; return s; } + +uint32_t pa_age(struct timeval *tv) { + struct timeval now; + uint32_t r; + assert(tv); + + if (tv->tv_sec == 0) + return 0; + + gettimeofday(&now, NULL); + + r = (now.tv_sec-tv->tv_sec) * 1000000; + + if (now.tv_usec >= tv->tv_usec) + r += now.tv_usec - tv->tv_usec; + else + r -= tv->tv_usec - now.tv_usec; + + return r; +} diff --git a/polyp/util.h b/polyp/util.h index 7dd7b7de..9dab45d2 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -23,6 +23,7 @@ ***/ #include +#include void pa_make_nonblock_fd(int fd); @@ -38,4 +39,6 @@ char *pa_sprintf_malloc(const char *format, ...) __attribute__ ((format (printf, char *pa_get_user_name(char *s, size_t l); char *pa_get_host_name(char *s, size_t l); +uint32_t pa_age(struct timeval *tv); + #endif -- cgit From b6b428e5cbfc2440f5950c0744e15bc4d84e6b31 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 23 Aug 2004 18:48:34 +0000 Subject: minor documentation update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@153 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 4 +--- polyp/polyplib-stream.h | 10 ++++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/doc/todo b/doc/todo index 43d7bc6f..a317b4f3 100644 --- a/doc/todo +++ b/doc/todo @@ -2,7 +2,6 @@ *** 0.3 *** - pacat drain fix -- future cancellation - make mcalign merge chunks - use ref counting in more objects - unix socket directories include user name @@ -19,10 +18,9 @@ *********** backends for: -- libao - xmms -- portaudio - mplayer +- portaudio - python modules: diff --git a/polyp/polyplib-stream.h b/polyp/polyplib-stream.h index ff313326..a0cbe521 100644 --- a/polyp/polyplib-stream.h +++ b/polyp/polyplib-stream.h @@ -83,7 +83,7 @@ void pa_stream_write(struct pa_stream *p /**< The stream to use */, playback buffer. Normally you will specify 0 here, - .i.e. append to the + i.e. append to the playback buffer. If the value given here is greater than the @@ -113,14 +113,12 @@ void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stre /** Set the callback function that is called when new data is available from the stream */ void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); -/** Pause (or resume) playback of this stream temporarily - * \since 0.3 */ +/** Pause (or resume) playback of this stream temporarily. \since 0.3 */ struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); /** Flush the playback buffer of this stream. Most of the time you're - * better off using the delta of pa_stream_write() instead of this - * function. - * \since 0.3*/ + * better off using the parameter delta of pa_stream_write() instead of this + * function. \since 0.3 */ struct pa_operation* pa_stream_flush(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata); PA_C_DECL_END -- cgit From 92bf0a365a3a8390bb3f023458a9e62c31849628 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 27 Aug 2004 01:29:49 +0000 Subject: latency work major main loop bugfix git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@154 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/mainloop.c | 10 +++++++--- polyp/module.c | 4 ++-- polyp/native-common.h | 4 +--- polyp/pacat.c | 6 +++--- polyp/pdispatch.c | 11 +++++++++++ polyp/play-memchunk.c | 4 +++- polyp/polypaudio.pa | 8 ++++---- polyp/polyplib-context.c | 5 ++++- polyp/polyplib-def.h | 9 +++++++++ polyp/polyplib-internal.h | 6 +++--- polyp/polyplib-introspect.h | 4 ++-- polyp/polyplib-stream.c | 41 +++++++++++++++++++++++++++-------------- polyp/polyplib-stream.h | 7 ++++++- polyp/protocol-native.c | 31 ++++++++++++++++++++++++------- polyp/pstream.c | 4 ++++ polyp/sample.c | 2 +- polyp/sample.h | 5 ++++- polyp/sink-input.c | 18 +++++++----------- polyp/sink-input.h | 2 +- polyp/sink.c | 4 ++-- polyp/sink.h | 2 +- 21 files changed, 126 insertions(+), 61 deletions(-) diff --git a/polyp/mainloop.c b/polyp/mainloop.c index 84505bb6..20d14e51 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -186,6 +186,7 @@ static struct pa_time_event* mainloop_time_new(struct pa_mainloop_api*a, const s e->destroy_callback = NULL; pa_idxset_put(m->time_events, e, NULL); + return e; } @@ -201,6 +202,7 @@ static void mainloop_time_restart(struct pa_time_event *e, const struct timeval static void mainloop_time_free(struct pa_time_event *e) { assert(e); + e->dead = e->mainloop->time_events_scan_dead = 1; } @@ -271,7 +273,7 @@ static int io_foreach(void *p, uint32_t index, int *del, void*userdata) { int *all = userdata; assert(e && del && all); - if (!*all || !e->dead) + if (!*all && !e->dead) return 0; if (e->destroy_callback) @@ -286,7 +288,7 @@ static int time_foreach(void *p, uint32_t index, int *del, void*userdata) { int *all = userdata; assert(e && del && all); - if (!*all || !e->dead) + if (!*all && !e->dead) return 0; if (e->destroy_callback) @@ -301,7 +303,7 @@ static int defer_foreach(void *p, uint32_t index, int *del, void*userdata) { int *all = userdata; assert(e && del && all); - if (!*all || !e->dead) + if (!*all && !e->dead) return 0; if (e->destroy_callback) @@ -336,6 +338,8 @@ static void scan_dead(struct pa_mainloop *m) { pa_idxset_foreach(m->time_events, time_foreach, &all); if (m->defer_events_scan_dead) pa_idxset_foreach(m->defer_events, defer_foreach, &all); + + m->io_events_scan_dead = m->time_events_scan_dead = m->defer_events_scan_dead = 0; } static void rebuild_pollfds(struct pa_mainloop *m) { diff --git a/polyp/module.c b/polyp/module.c index 1deb7cde..eb8a8acd 100644 --- a/polyp/module.c +++ b/polyp/module.c @@ -62,10 +62,10 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char if (!(m->dl = lt_dlopenext(name))) goto fail; - if (!(m->init = lt_dlsym(m->dl, "pa_module_init"))) + if (!(m->init = (int (*)(struct pa_core *c, struct pa_module*m)) lt_dlsym(m->dl, "pa_module_init"))) goto fail; - if (!(m->done = lt_dlsym(m->dl, "pa_module_done"))) + if (!(m->done = (void (*)(struct pa_core *c, struct pa_module*m)) lt_dlsym(m->dl, "pa_module_done"))) goto fail; m->userdata = NULL; diff --git a/polyp/native-common.h b/polyp/native-common.h index d826837a..5250532e 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -46,15 +46,12 @@ enum { PA_COMMAND_RECORD_STREAM_KILLED, PA_COMMAND_STAT, PA_COMMAND_GET_PLAYBACK_LATENCY, - PA_COMMAND_CREATE_UPLOAD_STREAM, PA_COMMAND_DELETE_UPLOAD_STREAM, PA_COMMAND_FINISH_UPLOAD_STREAM, PA_COMMAND_PLAY_SAMPLE, PA_COMMAND_REMOVE_SAMPLE, - PA_COMMAND_GET_SERVER_INFO, - PA_COMMAND_GET_SINK_INFO, PA_COMMAND_GET_SINK_INFO_LIST, PA_COMMAND_GET_SOURCE_INFO, @@ -78,6 +75,7 @@ enum { PA_COMMAND_CORK_PLAYBACK_STREAM, PA_COMMAND_FLUSH_PLAYBACK_STREAM, + PA_COMMAND_TRIGGER_PLAYBACK_STREAM, PA_COMMAND_MAX }; diff --git a/polyp/pacat.c b/polyp/pacat.c index 198776d3..9efa552a 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -277,16 +277,16 @@ static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_even } /* Show the current playback latency */ -static void stream_get_latency_callback(struct pa_stream *s, uint32_t latency, void *userdata) { +static void stream_get_latency_callback(struct pa_stream *s, const struct pa_latency_info *i, void *userdata) { assert(s); - if (latency == (uint32_t) -1) { + if (!i) { fprintf(stderr, "Failed to get latency: %s\n", strerror(errno)); quit(1); return; } - fprintf(stderr, "Current latency is %u usecs.\n", latency); + fprintf(stderr, "Current latency is %u usecs.\n", i->buffer_usec+i->sink_usec); } /* Someone requested that the latency is shown */ diff --git a/polyp/pdispatch.c b/polyp/pdispatch.c index c46d4f77..22f5da09 100644 --- a/polyp/pdispatch.c +++ b/polyp/pdispatch.c @@ -60,6 +60,17 @@ static const char *command_names[PA_COMMAND_MAX] = { [PA_COMMAND_FINISH_UPLOAD_STREAM] = "FINISH_UPLOAD_STREAM", [PA_COMMAND_PLAY_SAMPLE] = "PLAY_SAMPLE", [PA_COMMAND_REMOVE_SAMPLE] = "REMOVE_SAMPLE", + [PA_COMMAND_GET_SERVER_INFO] = "GET_SERVER_INFO", + [PA_COMMAND_GET_SINK_INFO] = "GET_SET_INFO", + [PA_COMMAND_GET_SINK_INPUT_INFO] = "GET_SINK_INPUT_INFO", + [PA_COMMAND_SUBSCRIBE] = "SUBSCRIBE", + [PA_COMMAND_SUBSCRIBE_EVENT] = "SUBSCRIBE_EVENT", + [PA_COMMAND_SET_SINK_VOLUME] = "SET_SINK_VOLUME", + [PA_COMMAND_SET_SINK_INPUT_VOLUME] = "SET_SINK_INPUT_VOLUME", + [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = "TRIGGER_PLAYBACK_STREAM", + [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = "FLUSH_PLAYBACK_STREAM", + [PA_COMMAND_CORK_PLAYBACK_STREAM] = "CORK_PLAYBACK_STREAM", + }; #endif diff --git a/polyp/play-memchunk.c b/polyp/play-memchunk.c index b94a0524..486f0cf6 100644 --- a/polyp/play-memchunk.c +++ b/polyp/play-memchunk.c @@ -25,6 +25,8 @@ #include #include +#include +#include #include "play-memchunk.h" #include "sink-input.h" @@ -64,7 +66,7 @@ static void sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk*ch assert(i && length && i->userdata); c = i->userdata; - assert(chunk == c); + assert(!memcmp(chunk, c, sizeof(chunk))); assert(length <= c->length); c->length -= length; diff --git a/polyp/polypaudio.pa b/polyp/polypaudio.pa index c63e1479..7c31634d 100755 --- a/polyp/polypaudio.pa +++ b/polyp/polypaudio.pa @@ -30,10 +30,10 @@ load module-pipe-sink #autoload_sink_add output module-oss device="/dev/dsp" sink_name=output source_name=input #autoload_source_add input module-oss device="/dev/dsp" sink_name=output source_name=input -autoload_sink_add output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -autoload_source_add input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#autoload_sink_add output module-alsa-sink sink_name=output -#autoload_source_add input module-alsa-source source_name=input +#autoload_sink_add output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#autoload_source_add input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +autoload_sink_add output module-alsa-sink sink_name=output +autoload_source_add input module-alsa-source source_name=input # Load several protocols load module-esound-protocol-tcp diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 9acb2d70..7542dd9b 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -463,7 +463,10 @@ static void set_dispatch_callbacks(struct pa_operation *o) { struct pa_operation* pa_context_drain(struct pa_context *c, void (*cb) (struct pa_context*c, void *userdata), void *userdata) { struct pa_operation *o; - assert(c && c->ref >= 1 && c->state == PA_CONTEXT_READY); + assert(c && c->ref >= 1); + + if (c->state != PA_CONTEXT_READY) + return NULL; if (!pa_context_is_pending(c)) return NULL; diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index 6420e87e..02f5e526 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -24,6 +24,7 @@ #include #include "cdecl.h" +#include "sample.h" /** \file * Global definitions */ @@ -128,6 +129,14 @@ enum pa_subscription_event_type { /** Return one if an event type t matches an event mask bitfield */ #define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) +/** A structure for latency info. See pa_stream_get_latency(). */ +struct pa_latency_info { + pa_usec_t buffer_usec; /**< Time in usecs the current buffer takes to play */ + pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. The total latency is buffer_usec+sink_usec. */ + int playing; /**< Non-zero when the stream is currently playing */ + int queue_length; /**< Queue size in bytes. */ +}; + PA_C_DECL_END #endif diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index fd6cd38f..8c5d3166 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -34,9 +34,9 @@ #include "llist.h" #include "native-common.h" -#define DEFAULT_MAXLENGTH 204800 -#define DEFAULT_TLENGTH 10240 -#define DEFAULT_PREBUF 4096 +#define DEFAULT_TLENGTH (10240*2) +#define DEFAULT_MAXLENGTH (DEFAULT_TLENGTH*2) +#define DEFAULT_PREBUF DEFAULT_TLENGTH #define DEFAULT_MINREQ 1024 #define DEFAULT_FRAGSIZE 1024 diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index 0cc52549..0c305184 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -42,7 +42,7 @@ struct pa_sink_info { pa_volume_t volume; uint32_t monitor_source; const char *monitor_source_name; - uint32_t latency; + pa_usec_t latency; }; struct pa_operation* pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); @@ -101,7 +101,7 @@ struct pa_sink_input_info { uint32_t sink; struct pa_sample_spec sample_spec; pa_volume_t volume; - uint32_t latency; + pa_usec_t latency; }; struct pa_operation* pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index c0ec9e7e..f45e1e7c 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -168,6 +168,8 @@ void pa_command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, s->requested_bytes += bytes; + fprintf(stderr, "total req: %u (%u)\n", s->requested_bytes, bytes); + if (s->requested_bytes && s->write_callback) s->write_callback(s, s->requested_bytes, s->write_userdata); @@ -320,22 +322,26 @@ struct pa_operation * pa_stream_drain(struct pa_stream *s, void (*cb) (struct pa static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_operation *o = userdata; - uint32_t latency; + struct pa_latency_info i, *p = NULL; assert(pd && o && o->stream && o->context); if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; - latency = (uint32_t) -1; - } else if (pa_tagstruct_getu32(t, &latency) < 0 || !pa_tagstruct_eof(t)) { + } else if (pa_tagstruct_getu32(t, &i.buffer_usec) < 0 || + pa_tagstruct_getu32(t, &i.sink_usec) < 0 || + pa_tagstruct_getu32(t, &i.playing) < 0 || + pa_tagstruct_getu32(t, &i.queue_length) < 0 || + !pa_tagstruct_eof(t)) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; - } + } else + p = &i; if (o->callback) { - void (*cb)(struct pa_stream *s, uint32_t latency, void *userdata) = o->callback; - cb(o->stream, latency, o->userdata); + void (*cb)(struct pa_stream *s, const struct pa_latency_info *i, void *userdata) = o->callback; + cb(o->stream, p, o->userdata); } finish: @@ -343,7 +349,7 @@ finish: pa_operation_unref(o); } -struct pa_operation* pa_stream_get_latency(struct pa_stream *s, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { +struct pa_operation* pa_stream_get_latency(struct pa_stream *s, void (*cb)(struct pa_stream *p, const struct pa_latency_info*i, void *userdata), void *userdata) { uint32_t tag; struct pa_operation *o; struct pa_tagstruct *t; @@ -476,24 +482,31 @@ struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (stru return pa_operation_ref(o); } -struct pa_operation* pa_stream_flush(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { - struct pa_operation *o; +struct pa_operation* pa_stream_send_simple_command(struct pa_stream *s, uint32_t command, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { struct pa_tagstruct *t; + struct pa_operation *o; uint32_t tag; assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); - + o = pa_operation_new(s->context, s); - assert(o); o->callback = cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_FLUSH_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, command); pa_tagstruct_putu32(t, tag = s->context->ctag++); pa_tagstruct_putu32(t, s->channel); pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); - return pa_operation_ref(o); + return pa_operation_ref(o); +} + + +struct pa_operation* pa_stream_flush(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { + return pa_stream_send_simple_command(s, PA_COMMAND_FLUSH_PLAYBACK_STREAM, cb, userdata); +} + +struct pa_operation* pa_stream_trigger(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { + return pa_stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata); } diff --git a/polyp/polyplib-stream.h b/polyp/polyplib-stream.h index a0cbe521..d74c3cb2 100644 --- a/polyp/polyplib-stream.h +++ b/polyp/polyplib-stream.h @@ -102,7 +102,7 @@ size_t pa_stream_writable_size(struct pa_stream *p); struct pa_operation* pa_stream_drain(struct pa_stream *s, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); /** Get the playback latency of a stream */ -struct pa_operation* pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); +struct pa_operation* pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, const struct pa_latency_info *i, void *userdata), void *userdata); /** Set the callback function that is called whenever the state of the stream changes */ void pa_stream_set_state_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); @@ -121,6 +121,11 @@ struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (stru * function. \since 0.3 */ struct pa_operation* pa_stream_flush(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata); +/** Request immediate start of playback on this stream. This disables + * prebuffering as specified in the pa_buffer_attr structure. \since + * 0.3 */ +struct pa_operation* pa_stream_trigger(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata); + PA_C_DECL_END #endif diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 8b39482c..7b7dfef6 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -136,7 +136,7 @@ static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, u static void command_subscribe(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_set_volume(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_cork_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_flush_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_flush_or_trigger_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = { NULL }, @@ -179,7 +179,8 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_SET_SINK_VOLUME] = { command_set_volume }, [PA_COMMAND_SET_SINK_INPUT_VOLUME] = { command_set_volume }, [PA_COMMAND_CORK_PLAYBACK_STREAM] = { command_cork_playback_stream }, - [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = { command_flush_playback_stream }, + [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = { command_flush_or_trigger_playback_stream }, + [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = { command_flush_or_trigger_playback_stream }, }; /* structure management */ @@ -438,6 +439,8 @@ static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk pa_pstream_send_simple_ack(s->connection->pstream, s->drain_tag); s->drain_request = 0; } + + /*fprintf(stderr, "after_drop: %u\n", pa_memblockq_get_length(s->memblockq));*/ } static void sink_input_kill_cb(struct pa_sink_input *i) { @@ -451,6 +454,8 @@ static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { assert(i && i->userdata); s = i->userdata; + /*fprintf(stderr, "get_latency: %u\n", pa_memblockq_get_length(s->memblockq));*/ + return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec); } @@ -797,7 +802,7 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma struct connection *c = userdata; struct pa_tagstruct *reply; struct playback_stream *s; - uint32_t index, latency; + uint32_t index; assert(c && t); if (pa_tagstruct_getu32(t, &index) < 0 || @@ -816,12 +821,14 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma return; } - latency = pa_sink_input_get_latency(s->sink_input); reply = pa_tagstruct_new(NULL, 0); assert(reply); pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); pa_tagstruct_putu32(reply, tag); - pa_tagstruct_putu32(reply, latency); + pa_tagstruct_putu32(reply, pa_sink_input_get_latency(s->sink_input)); + pa_tagstruct_putu32(reply, pa_sink_get_latency(s->sink_input->sink)); + pa_tagstruct_putu32(reply, pa_memblockq_is_readable(s->memblockq)); + pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq)); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -1325,7 +1332,7 @@ static void command_cork_playback_stream(struct pa_pdispatch *pd, uint32_t comma pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_flush_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_flush_or_trigger_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; uint32_t index; struct playback_stream *s; @@ -1347,7 +1354,14 @@ static void command_flush_playback_stream(struct pa_pdispatch *pd, uint32_t comm return; } - pa_memblockq_flush(s->memblockq); + if (command == PA_COMMAND_TRIGGER_PLAYBACK_STREAM) + pa_memblockq_prebuf_disable(s->memblockq); + else { + assert(command == PA_COMMAND_FLUSH_PLAYBACK_STREAM); + pa_memblockq_flush(s->memblockq); + } + + pa_sink_notify(s->sink_input->sink); pa_pstream_send_simple_ack(c->pstream, tag); } @@ -1383,8 +1397,11 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, ui pa_memblockq_push_align(p->memblockq, chunk, delta); assert(p->sink_input); + /*fprintf(stderr, "after_recv: %u\n", pa_memblockq_get_length(p->memblockq));*/ + pa_sink_notify(p->sink_input->sink); /*fprintf(stderr, "Recieved %u bytes.\n", chunk->length);*/ + } else { struct upload_stream *u = (struct upload_stream*) stream; size_t l; diff --git a/polyp/pstream.c b/polyp/pstream.c index ad3dd0e0..81ee0b43 100644 --- a/polyp/pstream.c +++ b/polyp/pstream.c @@ -211,6 +211,8 @@ void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet) { struct item_info *i; assert(p && packet); + /*fprintf(stderr, "push-packet %p\n", packet);*/ + i = pa_xmalloc(sizeof(struct item_info)); i->type = PA_PSTREAM_ITEM_PACKET; i->packet = pa_packet_ref(packet); @@ -258,6 +260,8 @@ static void prepare_next_write_item(struct pa_pstream *p) { p->write.index = 0; if (p->write.current->type == PA_PSTREAM_ITEM_PACKET) { + /*fprintf(stderr, "pop-packet %p\n", p->write.current->packet);*/ + assert(p->write.current->packet); p->write.data = p->write.current->packet->data; p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->packet->length); diff --git a/polyp/sample.c b/polyp/sample.c index f4a80861..edfe1959 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -61,7 +61,7 @@ size_t pa_bytes_per_second(const struct pa_sample_spec *spec) { uint32_t pa_bytes_to_usec(size_t length, const struct pa_sample_spec *spec) { assert(spec); - return (uint32_t) (((double) length /pa_frame_size(spec))/spec->rate*1000000); + return (uint32_t) (((double) length/pa_frame_size(spec)*1000000)/spec->rate); } int pa_sample_spec_valid(const struct pa_sample_spec *spec) { diff --git a/polyp/sample.h b/polyp/sample.h index 459f8a30..28ae51ea 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -66,6 +66,9 @@ struct pa_sample_spec { uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */ }; +/** Type for usec specifications */ +typedef uint32_t pa_usec_t; + /** Return the amount of bytes playback of a second of audio with the speicified sample type takes */ size_t pa_bytes_per_second(const struct pa_sample_spec *spec); @@ -73,7 +76,7 @@ size_t pa_bytes_per_second(const struct pa_sample_spec *spec); size_t pa_frame_size(const struct pa_sample_spec *spec); /** Calculate the time the specified bytes take to play with the specified sample type */ -uint32_t pa_bytes_to_usec(size_t length, const struct pa_sample_spec *spec); +pa_usec_t pa_bytes_to_usec(size_t length, const struct pa_sample_spec *spec); /** Return non-zero when the sample type specification is valid */ int pa_sample_spec_valid(const struct pa_sample_spec *spec); diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 5009033f..9238fac0 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -105,23 +105,19 @@ void pa_sink_input_kill(struct pa_sink_input*i) { i->kill(i); } -uint32_t pa_sink_input_get_latency(struct pa_sink_input *i) { - uint32_t l = 0; - +pa_usec_t pa_sink_input_get_latency(struct pa_sink_input *i) { assert(i); + if (i->get_latency) - l += i->get_latency(i); - - assert(i->sink); - l += pa_sink_get_latency(i->sink); + return i->get_latency(i); - return l; + return 0; } int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { assert(i && chunk && i->peek && i->drop); - if (i->corked == 0) + if (i->corked) return -1; if (!i->resampler) @@ -139,11 +135,11 @@ int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); - i->drop(i, &tchunk, l); - if (tchunk.length > l) tchunk.length = l; + i->drop(i, &tchunk, tchunk.length); + pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk); pa_memblock_unref(tchunk.memblock); } diff --git a/polyp/sink-input.h b/polyp/sink-input.h index b0644540..df6ead6b 100644 --- a/polyp/sink-input.h +++ b/polyp/sink-input.h @@ -61,7 +61,7 @@ void pa_sink_input_free(struct pa_sink_input* i); * request destruction of it */ void pa_sink_input_kill(struct pa_sink_input *i); -uint32_t pa_sink_input_get_latency(struct pa_sink_input *i); +pa_usec_t pa_sink_input_get_latency(struct pa_sink_input *i); int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk); void pa_sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length); diff --git a/polyp/sink.c b/polyp/sink.c index 43fd351c..b520dd8a 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -142,7 +142,7 @@ static unsigned fill_mix_info(struct pa_sink *s, struct pa_mix_info *info, unsig static void inputs_drop(struct pa_sink *s, struct pa_mix_info *info, unsigned maxinfo, size_t length) { assert(s && info); - + for (; maxinfo > 0; maxinfo--, info++) { struct pa_sink_input *i = info->userdata; assert(i && info->chunk.memblock); @@ -267,7 +267,7 @@ void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target) { } } -uint32_t pa_sink_get_latency(struct pa_sink *s) { +pa_usec_t pa_sink_get_latency(struct pa_sink *s) { assert(s); if (!s->get_latency) diff --git a/polyp/sink.h b/polyp/sink.h index 8248d00c..9c91692e 100644 --- a/polyp/sink.h +++ b/polyp/sink.h @@ -56,7 +56,7 @@ int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result); int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target); void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target); -uint32_t pa_sink_get_latency(struct pa_sink *s); +pa_usec_t pa_sink_get_latency(struct pa_sink *s); void pa_sink_notify(struct pa_sink*s); -- cgit From 761a895d1f8ac3c20710a884560bc77f3789d3af Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 27 Aug 2004 16:24:22 +0000 Subject: minor cleanups git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@155 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- doc/todo | 6 ++++++ polyp/polyplib-def.h | 10 ++++++++-- polyp/polyplib-introspect.c | 3 ++- polyp/polyplib-introspect.h | 18 ++++++++++-------- polyp/polyplib-stream.c | 2 -- polyp/protocol-native.c | 2 ++ polyp/tagstruct.c | 2 +- 8 files changed, 30 insertions(+), 15 deletions(-) diff --git a/configure.ac b/configure.ac index 7e0b3c21..7aa6c5d4 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. AC_PREREQ(2.57) -AC_INIT([polypaudio],[0.2],[mzcbylcnhqvb (at) 0pointer (dot) de]) +AC_INIT([polypaudio],[0.3],[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([polyp/main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) diff --git a/doc/todo b/doc/todo index a317b4f3..c225dd53 100644 --- a/doc/todo +++ b/doc/todo @@ -8,7 +8,13 @@ - native library/protocol: module load/unload kill client/... + autoload management - more complete pactl +- daemon autostart +- cleanup tagstruct (add s32, pa_volume_t, pa_usec_t) +- xmlrpc +- remove all gcc warnings +- complete doxygen coverage ** later *** - slp/rendezvous diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index 02f5e526..6c3cd825 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -129,10 +129,16 @@ enum pa_subscription_event_type { /** Return one if an event type t matches an event mask bitfield */ #define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) -/** A structure for latency info. See pa_stream_get_latency(). */ +/** A structure for latency info. See pa_stream_get_latency(). The + * total latency a sample that is written with pa_stream_write() takes + * to be played is buffer_usec+sink_usec. The buffer to which + * buffer_usec relates may be manipulated freely (with + * pa_stream_write()'s delta argument, pa_stream_flush() and friends), + * the playback buffer sink_usec relates to is a FIFO which cannot be + * flushed or manipulated in any way. */ struct pa_latency_info { pa_usec_t buffer_usec; /**< Time in usecs the current buffer takes to play */ - pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. The total latency is buffer_usec+sink_usec. */ + pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. */ int playing; /**< Non-zero when the stream is currently playing */ int queue_length; /**< Queue size in bytes. */ }; diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index 63422383..e650fb9f 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -400,7 +400,8 @@ static void context_get_sink_input_info_callback(struct pa_pdispatch *pd, uint32 pa_tagstruct_getu32(t, &i.sink) < 0 || pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || pa_tagstruct_getu32(t, &i.volume) < 0 || - pa_tagstruct_getu32(t, &i.latency) < 0) { + pa_tagstruct_getu32(t, &i.buffer_usec) < 0 || + pa_tagstruct_getu32(t, &i.sink_usec) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index 0c305184..fc7aa123 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -93,15 +93,17 @@ struct pa_client_info { struct pa_operation* pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); struct pa_operation* pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); +/** Stores information about sink inputs */ struct pa_sink_input_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t client; - uint32_t sink; - struct pa_sample_spec sample_spec; - pa_volume_t volume; - pa_usec_t latency; + uint32_t index; /**< Name of this index */ + const char *name; /**< Name of the sink input */ + uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ + uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ + uint32_t sink; /**< Index of the connected sink */ + struct pa_sample_spec sample_spec; /**< The sample specification of the sink input */ + pa_volume_t volume; /**< The volume of this sink input */ + pa_usec_t buffer_usec; /**< Latency due to buffering in sink input, see pa_latency_info for details */ + pa_usec_t sink_usec; /**< Latency of the sink device, see pa_latency_info for details */ }; struct pa_operation* pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index f45e1e7c..220e4a14 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -168,8 +168,6 @@ void pa_command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, s->requested_bytes += bytes; - fprintf(stderr, "total req: %u (%u)\n", s->requested_bytes, bytes); - if (s->requested_bytes && s->write_callback) s->write_callback(s, s->requested_bytes, s->write_userdata); diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 7b7dfef6..213568a0 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -1022,6 +1022,7 @@ static void sink_input_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink_inp pa_tagstruct_put_sample_spec(t, &s->sample_spec); pa_tagstruct_putu32(t, s->volume); pa_tagstruct_putu32(t, pa_sink_input_get_latency(s)); + pa_tagstruct_putu32(t, pa_sink_get_latency(s->sink)); } static void source_output_fill_tagstruct(struct pa_tagstruct *t, struct pa_source_output *s) { @@ -1363,6 +1364,7 @@ static void command_flush_or_trigger_playback_stream(struct pa_pdispatch *pd, ui pa_sink_notify(s->sink_input->sink); pa_pstream_send_simple_ack(c->pstream, tag); + request_bytes(s); } /*** pstream callbacks ***/ diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c index 9578a9eb..742f6b9c 100644 --- a/polyp/tagstruct.c +++ b/polyp/tagstruct.c @@ -95,7 +95,7 @@ void pa_tagstruct_puts(struct pa_tagstruct*t, const char *s) { l = strlen(s)+2; extend(t, l); t->data[t->length] = TAG_STRING; - strcpy(t->data+t->length+1, s); + strcpy((char*) (t->data+t->length+1), s); t->length += l; } -- cgit From 8cb1cabfc9a2ffb689f7f4998b81c2c7e18c6f73 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 27 Aug 2004 17:03:38 +0000 Subject: document every polyplib function git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@156 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 12 ++++- doc/todo | 4 +- polyp/polyplib-introspect.h | 124 +++++++++++++++++++++++++++++++------------- 3 files changed, 99 insertions(+), 41 deletions(-) diff --git a/doc/README.html.in b/doc/README.html.in index 8972fe1b..91edbd64 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -42,6 +42,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    News

    +
    Fri Aug 27 2004:

    Version 0.3 released; +changes include: support for both glib 2.0 and glib 1.2, future cancellation, API updates, many fixes.

    +
    Fri Aug 20 2004:

    Version 0.2 released; changes include: added sample cache, introspection API, client API @@ -84,12 +88,16 @@ attempt to write a sound server asd.

    A GTK GUI manager application for polypaudio is the Polypaudio Manager.

    +href="http://0pointer.de/lennart/projects/paman/">Polypaudio Manager. There are output plugins for XMMS and libao.

    Status

    Version @PACKAGE_VERSION@ is quite usable. It matches and supersedes ESOUND's feature set in nearly all areas.

    - + +

    Warning: polypaudio's client API and protocol are not stable +yet. The client interface is still a moving target and changes from +release to release. The client API's library version number is currently fixed to 0.0.0.

    +

    Documentation

    There is some preliminary documentation available: Date: Fri, 27 Aug 2004 18:38:23 +0000 Subject: relicense client library to LGPL git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@157 fefdeb5f-60dc-0310-8127-8f9354f1896f --- GPL | 340 +++++++++++++++++++++++++++++++++++ LGPL | 510 +++++++++++++++++++++++++++++++++++++++++++++++++++++ LICENSE | 342 +---------------------------------- doc/README.html.in | 2 +- 4 files changed, 854 insertions(+), 340 deletions(-) create mode 100644 GPL create mode 100644 LGPL diff --git a/GPL b/GPL new file mode 100644 index 00000000..d60c31a9 --- /dev/null +++ b/GPL @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/LGPL b/LGPL new file mode 100644 index 00000000..b124cf58 --- /dev/null +++ b/LGPL @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/LICENSE b/LICENSE index d60c31a9..b042db50 100644 --- a/LICENSE +++ b/LICENSE @@ -1,340 +1,4 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 +The client libraries are licensed under LGPL +The daemon itself and all plugings are licensed under GPL - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. +Lennart Poettering, 2004 diff --git a/doc/README.html.in b/doc/README.html.in index 91edbd64..fea38ce3 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -44,7 +44,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    Fri Aug 27 2004:

    Version 0.3 released; -changes include: support for both glib 2.0 and glib 1.2, future cancellation, API updates, many fixes.

    +changes include: support for both glib 2.0 and glib 1.2, future cancellation, API updates, many fixes; relicense client library to LGPL.

    Fri Aug 20 2004:

    Version 0.2 released; -- cgit From 4efa9d1cbec96bdc63585dc040ef73c4702e22bb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 27 Aug 2004 18:38:52 +0000 Subject: add LGPL/GPL to dist package git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@158 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 3eeef956..720059ed 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,7 +17,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -EXTRA_DIST = bootstrap.sh README LICENSE doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in +EXTRA_DIST = bootstrap.sh README LICENSE GPL LGPL doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in SUBDIRS=polyp doc MAINTAINERCLEANFILES=README -- cgit From b0143403bf8e510f380888c7f6065e156436f684 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 27 Aug 2004 18:41:40 +0000 Subject: readme update (licensing) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@159 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/README.html.in b/doc/README.html.in index fea38ce3..f3454632 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -40,6 +40,8 @@ General Public License for more details.

    along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    +

    Exception: The client libraries are licensed under LGPL, the Lesser GNU General Plublic License.

    +

    News

    Fri Aug 27 2004:

    Date: Fri, 27 Aug 2004 18:52:50 +0000 Subject: minor fixes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@160 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- doc/todo | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index 720059ed..0c78c154 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,7 +34,7 @@ README: homepage: all dist doxygen test -d $$HOME/homepage/private mkdir -p $$HOME/homepage/private/projects/polypaudio $$HOME/homepage/private/projects/polypaudio/doxygen - cp *.tar.gz $$HOME/homepage/private/projects/polypaudio + cp polypaudio-$(PACKAGE_VERSION).tar.gz $$HOME/homepage/private/projects/polypaudio cp doc/README.html doc/cli.html doc/daemon.html doc/modules.html doc/style.css $$HOME/homepage/private/projects/polypaudio cp -a doxygen/html/* $$HOME/homepage/private/projects/polypaudio/doxygen cp $$HOME/homepage/private/projects/polypaudio/README.html $$HOME/homepage/private/projects/polypaudio/index.html diff --git a/doc/todo b/doc/todo index aa302298..e7b91682 100644 --- a/doc/todo +++ b/doc/todo @@ -1,7 +1,6 @@ *** $Id$ *** -*** 0.3 *** -- pacat drain fix +*** 0.4 *** - make mcalign merge chunks - use ref counting in more objects - unix socket directories include user name -- cgit From 8c887ab8020ca45ad1781bff928908562bdecada Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 27 Aug 2004 18:55:24 +0000 Subject: fix homepage script git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@161 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 0c78c154..e27204f6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,7 +34,7 @@ README: homepage: all dist doxygen test -d $$HOME/homepage/private mkdir -p $$HOME/homepage/private/projects/polypaudio $$HOME/homepage/private/projects/polypaudio/doxygen - cp polypaudio-$(PACKAGE_VERSION).tar.gz $$HOME/homepage/private/projects/polypaudio + cp polypaudio-@PACKAGE_VERSION@.tar.gz $$HOME/homepage/private/projects/polypaudio cp doc/README.html doc/cli.html doc/daemon.html doc/modules.html doc/style.css $$HOME/homepage/private/projects/polypaudio cp -a doxygen/html/* $$HOME/homepage/private/projects/polypaudio/doxygen cp $$HOME/homepage/private/projects/polypaudio/README.html $$HOME/homepage/private/projects/polypaudio/index.html -- cgit From 9618aea5df5bf2c5069575f28a935c2039fc55e0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 27 Aug 2004 19:06:29 +0000 Subject: fix module path git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@162 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 8acbc012..31bfbdee 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -18,7 +18,7 @@ # USA. AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) -#AM_CFLAGS+= -DDLSEARCHDIR=\"$(pkglibdir)\" +AM_CFLAGS+= -DDLSEARCHDIR=\"$(pkglibdir)\" AM_LDADD=$(PTHREAD_LIBS) AM_LIBADD=$(PTHREAD_LIBS) -- cgit From 34fe8bd893ed9c7531bc4898b934ef9d4cdf3e68 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 1 Sep 2004 00:23:51 +0000 Subject: add support for SCHED_FIFO git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@163 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + polyp/Makefile.am | 6 +++++- polyp/cmdline.c | 21 +++++++++++++++++---- polyp/cmdline.h | 2 +- polyp/iochannel.c | 8 ++++++++ polyp/main.c | 20 ++++++++++++++++++++ polyp/mainloop.c | 20 ++++++++++++++++---- polyp/memblockq.c | 7 ++++++- polyp/memblockq.h | 3 +++ polyp/module-alsa-sink.c | 2 +- polyp/module-alsa-source.c | 2 +- polyp/module-oss.c | 25 +++++++++++++------------ polyp/module-pipe-sink.c | 2 +- polyp/polypaudio.pa | 19 ++++++++++--------- polyp/polyplib-context.c | 4 ++-- polyp/polyplib-internal.h | 6 +++--- polyp/protocol-esound.c | 2 ++ polyp/protocol-native.c | 8 ++++++-- polyp/pstream.c | 3 +++ polyp/sink.c | 15 +++++++++++++-- polyp/sink.h | 3 ++- polyp/socket-util.c | 8 ++++++-- polyp/util.c | 40 ++++++++++++++++++++++++++++++++++++++-- polyp/util.h | 3 +++ 24 files changed, 181 insertions(+), 49 deletions(-) diff --git a/doc/todo b/doc/todo index e7b91682..f8ebd9bb 100644 --- a/doc/todo +++ b/doc/todo @@ -13,6 +13,7 @@ - cleanup tagstruct (add s32, pa_volume_t, pa_usec_t) - xmlrpc - remove all gcc warnings +- esd compatible startup script or personality ** later *** - slp/rendezvous diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 31bfbdee..73e80621 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -18,7 +18,7 @@ # USA. AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) -AM_CFLAGS+= -DDLSEARCHDIR=\"$(pkglibdir)\" +#AM_CFLAGS+= -DDLSEARCHDIR=\"$(pkglibdir)\" AM_LDADD=$(PTHREAD_LIBS) AM_LIBADD=$(PTHREAD_LIBS) @@ -437,3 +437,7 @@ libpolypcore_la_SOURCES = idxset.c idxset.h \ endif + +suid: polypaudio + chown root:root $< + chmod u+s $< diff --git a/polyp/cmdline.c b/polyp/cmdline.c index 8acdde6f..9935e7b6 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -43,13 +43,16 @@ void pa_cmdline_help(const char *argv0) { e = argv0; printf("%s [options]\n" + " -r Try to set high process priority (only available as root)\n" + " -R Don't drop root if SETUID root\n" " -L MODULE Load the specified plugin module with the specified argument\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); + " -h Show this help\n" + " -V Show version\n", e); } struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { @@ -59,13 +62,13 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { assert(argc && argv); cmdline = pa_xmalloc(sizeof(struct pa_cmdline)); - cmdline->daemonize = cmdline->help = cmdline->verbose = 0; + cmdline->daemonize = cmdline->help = cmdline->verbose = cmdline->high_priority = cmdline->stay_root = cmdline->version = 0; cmdline->fail = 1; buf = pa_strbuf_new(); assert(buf); - while ((c = getopt(argc, argv, "L:F:CDhfv")) != -1) { + while ((c = getopt(argc, argv, "L:F:CDhfvrRV")) != -1) { switch (c) { case 'L': pa_strbuf_printf(buf, "load %s\n", optarg); @@ -86,8 +89,18 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { cmdline->fail = 0; break; case 'v': - cmdline->verbose = 0; + cmdline->verbose = 1; break; + case 'r': + cmdline->high_priority = 1; + break; + case 'R': + cmdline->stay_root = 1; + break; + case 'V': + cmdline->version = 1; + break; + default: goto fail; } diff --git a/polyp/cmdline.h b/polyp/cmdline.h index 95ce91de..6a7f4dd7 100644 --- a/polyp/cmdline.h +++ b/polyp/cmdline.h @@ -24,7 +24,7 @@ struct pa_cmdline { - int daemonize, help, fail, verbose; + int daemonize, help, fail, verbose, high_priority, stay_root, version; char *cli_commands; }; diff --git a/polyp/iochannel.c b/polyp/iochannel.c index 813347d4..1aa70b93 100644 --- a/polyp/iochannel.c +++ b/polyp/iochannel.c @@ -173,8 +173,16 @@ int pa_iochannel_is_hungup(struct pa_iochannel*io) { ssize_t pa_iochannel_write(struct pa_iochannel*io, const void*data, size_t l) { ssize_t r; + assert(io); + assert(data); + assert(l); + assert(io->ofd >= 0); + + assert(io && data && l && io->ofd >= 0); + + if ((r = write(io->ofd, data, l)) >= 0) { io->writable = 0; enable_mainloop_sources(io); diff --git a/polyp/main.c b/polyp/main.c index de02a110..526bf744 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -46,6 +46,14 @@ static struct pa_mainloop *mainloop; +static void drop_root(void) { + if (getuid() != 0 && geteuid() == 0) { + fprintf(stderr, __FILE__": started SUID root, dropping root rights.\n"); + setuid(getuid()); + seteuid(getuid()); + } +} + static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { m->quit(m, 1); fprintf(stderr, __FILE__": got signal.\n"); @@ -84,6 +92,18 @@ int main(int argc, char *argv[]) { goto finish; } + if (cmdline->version) { + printf(PACKAGE_NAME" "PACKAGE_VERSION"\n"); + retval = 0; + goto finish; + } + + if (cmdline->high_priority) + pa_raise_priority(); + + if (!cmdline->stay_root) + drop_root(); + if (cmdline->daemonize) { pid_t child; diff --git a/polyp/mainloop.c b/polyp/mainloop.c index 20d14e51..83f0b1e8 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -332,6 +332,7 @@ void pa_mainloop_free(struct pa_mainloop* m) { static void scan_dead(struct pa_mainloop *m) { int all = 0; assert(m); + if (m->io_events_scan_dead) pa_idxset_foreach(m->io_events, io_foreach, &all); if (m->time_events_scan_dead) @@ -402,7 +403,7 @@ static void dispatch_defer(struct pa_mainloop *m) { for (e = pa_idxset_first(m->defer_events, &index); e; e = pa_idxset_next(m->defer_events, &index)) { if (e->dead || !e->enabled) continue; - + assert(e->callback); e->callback(&m->api, e, e->userdata); } @@ -413,18 +414,23 @@ static int calc_next_timeout(struct pa_mainloop *m) { struct pa_time_event *e; struct timeval now; int t = -1; + int got_time = 0; if (pa_idxset_isempty(m->time_events)) return -1; - gettimeofday(&now, NULL); - for (e = pa_idxset_first(m->time_events, &index); e; e = pa_idxset_next(m->time_events, &index)) { int tmp; if (e->dead || !e->enabled) continue; + /* Let's save a system call */ + if (!got_time) { + gettimeofday(&now, NULL); + got_time = 1; + } + if (e->timeval.tv_sec < now.tv_sec || (e->timeval.tv_sec == now.tv_sec && e->timeval.tv_usec <= now.tv_usec)) return 0; @@ -448,17 +454,23 @@ static void dispatch_timeout(struct pa_mainloop *m) { uint32_t index; struct pa_time_event *e; struct timeval now; + int got_time = 0; assert(m); if (pa_idxset_isempty(m->time_events)) return; - gettimeofday(&now, NULL); for (e = pa_idxset_first(m->time_events, &index); e; e = pa_idxset_next(m->time_events, &index)) { if (e->dead || !e->enabled) continue; + /* Let's save a system call */ + if (!got_time) { + gettimeofday(&now, NULL); + got_time = 1; + } + if (e->timeval.tv_sec < now.tv_sec || (e->timeval.tv_sec == now.tv_sec && e->timeval.tv_usec <= now.tv_usec)) { assert(e->callback); diff --git a/polyp/memblockq.c b/polyp/memblockq.c index b6dcca3f..7feb4685 100644 --- a/polyp/memblockq.c +++ b/polyp/memblockq.c @@ -56,7 +56,7 @@ struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t b bq->current_length = 0; - fprintf(stderr, "memblockq requested: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", maxlength, tlength, base, prebuf, minreq); + /*fprintf(stderr, "memblockq requested: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", maxlength, tlength, base, prebuf, minreq);*/ bq->base = base; @@ -324,3 +324,8 @@ void pa_memblockq_flush(struct pa_memblockq *bq) { bq->n_blocks = 0; bq->current_length = 0; } + +uint32_t pa_memblockq_get_tlength(struct pa_memblockq *bq) { + assert(bq); + return bq->tlength; +} diff --git a/polyp/memblockq.h b/polyp/memblockq.h index 277beb55..16b51d7a 100644 --- a/polyp/memblockq.h +++ b/polyp/memblockq.h @@ -89,4 +89,7 @@ void pa_memblockq_seek(struct pa_memblockq *bq, size_t delta); /* Flush the queue */ void pa_memblockq_flush(struct pa_memblockq *bq); +/* Get Target length */ +uint32_t pa_memblockq_get_tlength(struct pa_memblockq *bq); + #endif diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index 06b07f33..0c9d77b8 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -99,7 +99,7 @@ static void do_write(struct userdata *u) { assert(memchunk->memblock && memchunk->memblock->data && memchunk->length && memchunk->memblock->length && (memchunk->length % u->frame_size) == 0); - if ((frames = snd_pcm_writei(u->pcm_handle, memchunk->memblock->data + memchunk->index, memchunk->length / u->frame_size)) < 0) { + if ((frames = snd_pcm_writei(u->pcm_handle, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length / u->frame_size)) < 0) { if (frames == -EAGAIN) return; diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index 9dc623d4..13df9f96 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -95,7 +95,7 @@ static void do_read(struct userdata *u) { assert(u->memchunk.memblock && u->memchunk.memblock->data && u->memchunk.length && u->memchunk.memblock->length && (u->memchunk.length % u->frame_size) == 0); - if ((frames = snd_pcm_readi(u->pcm_handle, u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { + if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { if (frames == -EAGAIN) return; diff --git a/polyp/module-oss.c b/polyp/module-oss.c index 3fa3d1e3..403716fd 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -93,21 +93,22 @@ static void do_write(struct userdata *u) { return; update_usage(u); - - if (!u->memchunk.length) { - if (pa_sink_render(u->sink, u->out_fragment_size, &u->memchunk) < 0) - memchunk = &u->silence; - else - memchunk = &u->memchunk; - } - assert(memchunk->memblock && memchunk->length); + memchunk = &u->memchunk; + + if (!memchunk->length) + if (pa_sink_render(u->sink, u->out_fragment_size, memchunk) < 0) + memchunk = &u->silence; - if ((r = pa_iochannel_write(u->io, memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { + assert(memchunk->memblock); + assert(memchunk->memblock->data); + assert(memchunk->length); + + if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { fprintf(stderr, "write() failed: %s\n", strerror(errno)); return; } - + if (memchunk == &u->silence) assert(r % u->sample_size == 0); else { @@ -215,8 +216,8 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { fprintf(stderr, "module-oss: device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); - if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) - goto fail; + if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) + goto fail; if (pa_oss_auto_format(fd, &ss) < 0) goto fail; diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c index 22d9f676..32a2c722 100644 --- a/polyp/module-pipe-sink.c +++ b/polyp/module-pipe-sink.c @@ -82,7 +82,7 @@ static void do_write(struct userdata *u) { assert(u->memchunk.memblock && u->memchunk.length); - if ((r = pa_iochannel_write(u->io, u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { + if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { fprintf(stderr, "write() failed: %s\n", strerror(errno)); return; } diff --git a/polyp/polypaudio.pa b/polyp/polypaudio.pa index 7c31634d..b683e627 100755 --- a/polyp/polypaudio.pa +++ b/polyp/polypaudio.pa @@ -1,4 +1,4 @@ -#!./polypaudio -F +#!./polypaudio -rF # # This file is part of polypaudio. @@ -24,22 +24,23 @@ #load module-alsa-source device=plughw:1,0 #load module-oss device="/dev/dsp" sink_name=output source_name=input #load module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -load module-pipe-sink +#load module-pipe-sink # Load audio drivers automatically on access -#autoload_sink_add output module-oss device="/dev/dsp" sink_name=output source_name=input -#autoload_source_add input module-oss device="/dev/dsp" sink_name=output source_name=input +autoload_sink_add output module-oss device="/dev/adsp" sink_name=output source_name=input +autoload_source_add input module-oss device="/dev/adsp" sink_name=output source_name=input #autoload_sink_add output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input #autoload_source_add input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -autoload_sink_add output module-alsa-sink sink_name=output -autoload_source_add input module-alsa-source source_name=input +#autoload_sink_add output module-alsa-sink sink_name=output +#autoload_source_add input module-alsa-source source_name=input # Load several protocols -load module-esound-protocol-tcp -load module-simple-protocol-tcp +#load module-esound-protocol-tcp +#load module-simple-protocol-tcp load module-native-protocol-unix -load module-cli-protocol-unix +#load module-cli-protocol-unix +load module-esound-protocol-unix # Load the CLI module load module-cli diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 7542dd9b..2ead4004 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -202,7 +202,7 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, ui if ((s = pa_dynarray_get(c->record_streams, channel))) { if (s->read_callback) - s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); + s->read_callback(s, (uint8_t*) chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); } pa_context_unref(c); @@ -451,7 +451,7 @@ static void set_dispatch_callbacks(struct pa_operation *o) { else { if (o->callback) { void (*cb)(struct pa_context *c, void *userdata); - cb = (void*) o->callback; + cb = (void (*)(struct pa_context*, void*)) o->callback; cb(o->context, o->userdata); } diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 8c5d3166..8f1a4942 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -34,10 +34,10 @@ #include "llist.h" #include "native-common.h" -#define DEFAULT_TLENGTH (10240*2) -#define DEFAULT_MAXLENGTH (DEFAULT_TLENGTH*2) +#define DEFAULT_TLENGTH (10240*4) +#define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2) #define DEFAULT_PREBUF DEFAULT_TLENGTH -#define DEFAULT_MINREQ 1024 +#define DEFAULT_MINREQ 512 #define DEFAULT_FRAGSIZE 1024 #define DEFAULT_TIMEOUT (5*60) diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 5102540b..2059dab8 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -903,6 +903,8 @@ static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk /* do something */ assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + + assert(pa_memblockq_get_length(c->input_memblockq) > 2048); } static void sink_input_kill_cb(struct pa_sink_input *i) { diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 213568a0..9c6996be 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -421,6 +421,8 @@ static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk assert(i && i->userdata && chunk); s = i->userdata; + /*fprintf(stderr, "%3.0f \r", (double) pa_memblockq_get_length(s->memblockq)/pa_memblockq_get_tlength(s->memblockq)*100);*/ + if (pa_memblockq_peek(s->memblockq, chunk) < 0) return -1; @@ -1360,6 +1362,7 @@ static void command_flush_or_trigger_playback_stream(struct pa_pdispatch *pd, ui else { assert(command == PA_COMMAND_FLUSH_PLAYBACK_STREAM); pa_memblockq_flush(s->memblockq); + /*fprintf(stderr, "flush: %u\n", pa_memblockq_get_length(s->memblockq));*/ } pa_sink_notify(s->sink_input->sink); @@ -1427,7 +1430,8 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, ui l = chunk->length; if (l > 0) { - memcpy(u->memchunk.memblock->data + u->memchunk.index + u->memchunk.length, chunk->memblock->data+chunk->index, l); + memcpy((uint8_t*) u->memchunk.memblock->data + u->memchunk.index + u->memchunk.length, + (uint8_t*) chunk->memblock->data+chunk->index, l); u->memchunk.length += l; u->length -= l; } @@ -1439,7 +1443,7 @@ static void pstream_die_callback(struct pa_pstream *p, void *userdata) { assert(p && c); connection_free(c); - fprintf(stderr, "protocol-native: connection died.\n"); +/* fprintf(stderr, "protocol-native: connection died.\n");*/ } diff --git a/polyp/pstream.c b/polyp/pstream.c index 81ee0b43..02dba72d 100644 --- a/polyp/pstream.c +++ b/polyp/pstream.c @@ -169,6 +169,9 @@ struct pa_pstream *pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel p->memblock_stat = s; + pa_iochannel_socket_set_rcvbuf(io, 1024*8); + pa_iochannel_socket_set_sndbuf(io, 1024*8); + return p; } diff --git a/polyp/sink.c b/polyp/sink.c index b520dd8a..104248a9 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -220,7 +220,7 @@ int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target) { if (l > info[0].chunk.length) l = info[0].chunk.length; - memcpy(target->memblock->data+target->index, info[0].chunk.memblock->data + info[0].chunk.index, l); + memcpy((uint8_t*) target->memblock->data+target->index, (uint8_t*) info[0].chunk.memblock->data + info[0].chunk.index, l); target->length = l; if (s->volume != PA_VOLUME_NORM || info[0].volume != PA_VOLUME_NORM) @@ -229,7 +229,7 @@ int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target) { if (volume != PA_VOLUME_NORM) pa_volume_memchunk(target, &s->sample_spec, volume); } else - target->length = l = pa_mix(info, n, target->memblock->data+target->index, target->length, &s->sample_spec, s->volume); + target->length = l = pa_mix(info, n, (uint8_t*) target->memblock->data+target->index, target->length, &s->sample_spec, s->volume); assert(l); inputs_drop(s, info, n, l); @@ -267,6 +267,17 @@ void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target) { } } +void pa_sink_render_full(struct pa_sink *s, size_t length, struct pa_memchunk *result) { + assert(s && length && result); + + /*** This needs optimization ***/ + + result->memblock = pa_memblock_new(result->length = length, s->core->memblock_stat); + result->index = 0; + + pa_sink_render_into_full(s, result); +} + pa_usec_t pa_sink_get_latency(struct pa_sink *s) { assert(s); diff --git a/polyp/sink.h b/polyp/sink.h index 9c91692e..940d1618 100644 --- a/polyp/sink.h +++ b/polyp/sink.h @@ -53,9 +53,10 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co void pa_sink_free(struct pa_sink* s); int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result); +void pa_sink_render_full(struct pa_sink *s, size_t length, struct pa_memchunk *result); int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target); void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target); - + pa_usec_t pa_sink_get_latency(struct pa_sink *s); void pa_sink_notify(struct pa_sink*s); diff --git a/polyp/socket-util.c b/polyp/socket-util.c index 904381b7..f9d0febf 100644 --- a/polyp/socket-util.c +++ b/polyp/socket-util.c @@ -121,8 +121,10 @@ int pa_socket_tcp_low_delay(int fd) { int pa_socket_set_rcvbuf(int fd, size_t l) { assert(fd >= 0); - if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &l, sizeof(l)) < 0) + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &l, sizeof(l)) < 0) { + fprintf(stderr, "SO_RCVBUF: %s\n", strerror(errno)); return -1; + } return 0; } @@ -130,8 +132,10 @@ int pa_socket_set_rcvbuf(int fd, size_t l) { int pa_socket_set_sndbuf(int fd, size_t l) { assert(fd >= 0); - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &l, sizeof(l)) < 0) + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &l, sizeof(l)) < 0) { + fprintf(stderr, "SO_SNDBUF: %s\n", strerror(errno)); return -1; + } return 0; } diff --git a/polyp/util.c b/polyp/util.c index 6c8febb6..0d930118 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include "util.h" #include "xmalloc.h" @@ -83,7 +85,7 @@ ssize_t pa_loop_read(int fd, void*data, size_t size) { break; ret += r; - data += r; + data = (uint8_t*) data + r; size -= r; } @@ -104,7 +106,7 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size) { break; ret += r; - data += r; + data = (uint8_t*) data + r; size -= r; } @@ -213,3 +215,37 @@ uint32_t pa_age(struct timeval *tv) { return r; } + +#define NICE_LEVEL (-15) + +void pa_raise_priority(void) { + if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) + fprintf(stderr, __FILE__": setpriority() failed: %s\n", strerror(errno)); + else + fprintf(stderr, __FILE__": Successfully gained nice level %i.\n", NICE_LEVEL); + +#ifdef _POSIX_PRIORITY_SCHEDULING + { + struct sched_param sp; + sched_getparam(0, &sp); + sp.sched_priority = 1; + if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) + fprintf(stderr, __FILE__": sched_setscheduler() failed: %s\n", strerror(errno)); + else + fprintf(stderr, __FILE__": Successfully gained SCHED_FIFO scheduling.\n"); + } +#endif +} + +void pa_reset_priority(void) { +#ifdef _POSIX_PRIORITY_SCHEDULING + { + struct sched_param sp; + sched_getparam(0, &sp); + sp.sched_priority = 0; + sched_setscheduler(0, SCHED_OTHER, &sp); + } +#endif + + setpriority(PRIO_PROCESS, 0, 0); +} diff --git a/polyp/util.h b/polyp/util.h index 9dab45d2..89505cde 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -41,4 +41,7 @@ char *pa_get_host_name(char *s, size_t l); uint32_t pa_age(struct timeval *tv); +void pa_raise_priority(void); +void pa_reset_priority(void); + #endif -- cgit From 36550f4a66ae28e1b81b9b818c38cd0fcd1302a1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 1 Sep 2004 00:46:56 +0000 Subject: remove most -W compiler warnings git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@164 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 8 +++----- polyp/memchunk.c | 6 +++--- polyp/module-oss-mmap.c | 4 ++-- polyp/pacat.c | 4 ++-- polyp/parec-simple.c | 2 +- polyp/polyplib-internal.h | 2 +- polyp/polyplib-simple.c | 6 +++--- polyp/protocol-esound.c | 30 +++++++++++++++--------------- polyp/protocol-simple.c | 4 ++-- polyp/pstream.c | 10 +++++----- polyp/resampler.c | 4 ++-- polyp/sample-util.c | 8 ++++---- polyp/socket-client.c | 3 ++- polyp/strbuf.c | 2 +- 14 files changed, 46 insertions(+), 47 deletions(-) diff --git a/doc/todo b/doc/todo index f8ebd9bb..d3baff16 100644 --- a/doc/todo +++ b/doc/todo @@ -10,12 +10,13 @@ autoload management - more complete pactl - daemon autostart -- cleanup tagstruct (add s32, pa_volume_t, pa_usec_t) -- xmlrpc +- cleanup tagstruct and modargs (add s32, pa_volume_t, pa_usec_t) - remove all gcc warnings - esd compatible startup script or personality +- limit number of concurrent streams ** later *** +- xmlrpc/http - slp/rendezvous - modinfo - make alsa modules use mmap @@ -28,6 +29,3 @@ backends for: - gstreamer - portaudio - python - -modules: -- http? diff --git a/polyp/memchunk.c b/polyp/memchunk.c index 920189e2..87b9c1bd 100644 --- a/polyp/memchunk.c +++ b/polyp/memchunk.c @@ -40,7 +40,7 @@ void pa_memchunk_make_writable(struct pa_memchunk *c, struct pa_memblock_stat *s n = pa_memblock_new(c->length, s); assert(n); - memcpy(n->data, c->memblock->data+c->index, c->length); + memcpy(n->data, (uint8_t*) c->memblock->data+c->index, c->length); pa_memblock_unref(c->memblock); c->memblock = n; c->index = 0; @@ -100,7 +100,7 @@ int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c) { l = m->chunk.length; assert(m->buffer && l); - memcpy(m->buffer + m->buffer_fill, m->chunk.memblock->data + m->chunk.index, l); + memcpy((uint8_t*) m->buffer + m->buffer_fill, (uint8_t*) m->chunk.memblock->data + m->chunk.index, l); m->buffer_fill += l; m->chunk.index += l; m->chunk.length -= l; @@ -132,7 +132,7 @@ int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c) { assert(!m->buffer); m->buffer = pa_xmalloc(m->base); m->chunk.length -= m->buffer_fill; - memcpy(m->buffer, m->chunk.memblock->data + m->chunk.index + m->chunk.length, m->buffer_fill); + memcpy(m->buffer, (uint8_t*) m->chunk.memblock->data + m->chunk.index + m->chunk.length, m->buffer_fill); } if (m->chunk.length) { diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index 05e06178..5c3be1ad 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -100,7 +100,7 @@ static void out_fill_memblocks(struct userdata *u, unsigned n) { if (u->out_memblocks[u->out_current]) pa_memblock_unref_fixed(u->out_memblocks[u->out_current]); - chunk.memblock = u->out_memblocks[u->out_current] = pa_memblock_new_fixed(u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size, u->core->memblock_stat); + chunk.memblock = u->out_memblocks[u->out_current] = pa_memblock_new_fixed((uint8_t*)u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size, u->core->memblock_stat); assert(chunk.memblock); chunk.length = chunk.memblock->length; chunk.index = 0; @@ -141,7 +141,7 @@ static void in_post_memblocks(struct userdata *u, unsigned n) { struct pa_memchunk chunk; if (!u->in_memblocks[u->in_current]) { - chunk.memblock = u->in_memblocks[u->in_current] = pa_memblock_new_fixed(u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size, u->core->memblock_stat); + chunk.memblock = u->in_memblocks[u->in_current] = pa_memblock_new_fixed((uint8_t*) u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size, u->core->memblock_stat); chunk.length = chunk.memblock->length; chunk.index = 0; diff --git a/polyp/pacat.c b/polyp/pacat.c index 9efa552a..b251cc35 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -65,7 +65,7 @@ static void do_stream_write(size_t length) { if (l > buffer_length) l = buffer_length; - pa_stream_write(stream, buffer+buffer_index, l, NULL, 0); + pa_stream_write(stream, (uint8_t*) buffer + buffer_index, l, NULL, 0); buffer_length -= l; buffer_index += l; @@ -250,7 +250,7 @@ static void stdout_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int assert(buffer_length); - if ((r = write(fd, buffer+buffer_index, buffer_length)) <= 0) { + if ((r = write(fd, (uint8_t*) buffer+buffer_index, buffer_length)) <= 0) { fprintf(stderr, "write() failed: %s\n", strerror(errno)); quit(1); diff --git a/polyp/parec-simple.c b/polyp/parec-simple.c index 74f0a0f7..7e0931ae 100644 --- a/polyp/parec-simple.c +++ b/polyp/parec-simple.c @@ -47,7 +47,7 @@ static ssize_t loop_write(int fd, const void*data, size_t size) { break; ret += r; - data += r; + data = (uint8_t*) data + r; size -= r; } diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 8f1a4942..813bb04e 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -34,7 +34,7 @@ #include "llist.h" #include "native-common.h" -#define DEFAULT_TLENGTH (10240*4) +#define DEFAULT_TLENGTH (10240*8) #define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2) #define DEFAULT_PREBUF DEFAULT_TLENGTH #define DEFAULT_MINREQ 512 diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c index c71d59a4..ccd39c2a 100644 --- a/polyp/polyplib-simple.c +++ b/polyp/polyplib-simple.c @@ -188,7 +188,7 @@ int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *pe l = length; pa_stream_write(p->stream, data, l, NULL, 0); - data += l; + data = (uint8_t*) data + l; length -= l; } @@ -222,9 +222,9 @@ int pa_simple_read(struct pa_simple *p, void*data, size_t length, int *perror) { if (p->read_length <= l) l = p->read_length; - memcpy(data, p->read_data+p->read_index, l); + memcpy(data, (uint8_t*) p->read_data+p->read_index, l); - data += l; + data = (uint8_t*) data + l; length -= l; p->read_index += l; diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 2059dab8..d6e2bf6b 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -210,7 +210,7 @@ static void* connection_write(struct connection *c, size_t length) { i = c->write_data_length; c->write_data_length += length; - return c->write_data+i; + return (uint8_t*) c->write_data+i; } static void format_esd2native(int format, struct pa_sample_spec *ss) { @@ -245,7 +245,7 @@ static int esd_proto_connect(struct connection *c, esd_proto_t request, const vo c->authorized = 1; } - ekey = *(uint32_t*)(data+ESD_KEY_LEN); + ekey = *(uint32_t*)((uint8_t*) data+ESD_KEY_LEN); if (ekey == ESD_ENDIAN_KEY) c->swap_byte_order = 0; else if (ekey == ESD_SWAP_ENDIAN_KEY) @@ -283,7 +283,7 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons return -1; } - strncpy(name, data + sizeof(int)*2, sizeof(name)); + strncpy(name, (char*) data + sizeof(int)*2, sizeof(name)); name[sizeof(name)-1] = 0; pa_client_rename(c->client, name); @@ -347,7 +347,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co return -1; } - strncpy(name, data + sizeof(int)*2, sizeof(name)); + strncpy(name, (char*) data + sizeof(int)*2, sizeof(name)); name[sizeof(name)-1] = 0; pa_client_rename(c->client, name); @@ -415,7 +415,7 @@ static int esd_proto_server_info(struct connection *c, esd_proto_t request, cons } static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length) { - void *response; + uint8_t *response; size_t t, k, s; struct connection *conn; size_t index = PA_IDXSET_INVALID; @@ -451,7 +451,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v /* name */ assert(conn->client); - strncpy(response, conn->client->name, ESD_NAME_MAX); + strncpy((char*) response, conn->client->name, ESD_NAME_MAX); response += ESD_NAME_MAX; /* rate */ @@ -491,9 +491,9 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v /* name */ if (strncmp(ce->name, SCACHE_PREFIX, sizeof(SCACHE_PREFIX)-1) == 0) - strncpy(response, ce->name+sizeof(SCACHE_PREFIX)-1, ESD_NAME_MAX); + strncpy((char*) response, ce->name+sizeof(SCACHE_PREFIX)-1, ESD_NAME_MAX); else - snprintf(response, ESD_NAME_MAX, "native.%s", ce->name); + snprintf((char*) response, ESD_NAME_MAX, "native.%s", ce->name); response += ESD_NAME_MAX; /* rate */ @@ -570,7 +570,7 @@ static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, con return -1; strcpy(name, SCACHE_PREFIX); - strncpy(name+sizeof(SCACHE_PREFIX)-1, data+3*sizeof(int), ESD_NAME_MAX); + strncpy(name+sizeof(SCACHE_PREFIX)-1, (char*) data+3*sizeof(int), ESD_NAME_MAX); name[sizeof(name)-1] = 0; assert(!c->scache_memchunk.memblock); @@ -661,7 +661,7 @@ static int do_read(struct connection *c) { ssize_t r; assert(c->read_data_length < sizeof(c->request)); - if ((r = pa_iochannel_read(c->io, ((void*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { + if ((r = pa_iochannel_read(c->io, ((uint8_t*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { fprintf(stderr, "protocol-esound.c: read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } @@ -708,7 +708,7 @@ static int do_read(struct connection *c) { assert(c->read_data && c->read_data_length < handler->data_length); - if ((r = pa_iochannel_read(c->io, c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { fprintf(stderr, "protocol-esound.c: read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } @@ -728,7 +728,7 @@ static int do_read(struct connection *c) { assert(c->scache_memchunk.memblock && c->scache_name && c->scache_memchunk.index < c->scache_memchunk.length); - if ((r = pa_iochannel_read(c->io, c->scache_memchunk.memblock->data+c->scache_memchunk.index, c->scache_memchunk.length-c->scache_memchunk.index)) <= 0) { + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache_memchunk.memblock->data+c->scache_memchunk.index, c->scache_memchunk.length-c->scache_memchunk.index)) <= 0) { fprintf(stderr, __FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } @@ -783,7 +783,7 @@ static int do_read(struct connection *c) { c->playback.memblock_index = 0; } - if ((r = pa_iochannel_read(c->io, c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { fprintf(stderr, __FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } @@ -811,7 +811,7 @@ static int do_write(struct connection *c) { ssize_t r; assert(c->write_data_index < c->write_data_length); - if ((r = pa_iochannel_write(c->io, c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { + if ((r = pa_iochannel_write(c->io, (uint8_t*) c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { fprintf(stderr, __FILE__": write() failed: %s\n", strerror(errno)); return -1; } @@ -829,7 +829,7 @@ static int do_write(struct connection *c) { assert(chunk.memblock && chunk.length); - if ((r = pa_iochannel_write(c->io, chunk.memblock->data+chunk.index, chunk.length)) < 0) { + if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { pa_memblock_unref(chunk.memblock); fprintf(stderr, __FILE__": write(): %s\n", strerror(errno)); return -1; diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index b03c2e54..41c1f484 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -120,7 +120,7 @@ static int do_read(struct connection *c) { c->playback.memblock_index = 0; } - if ((r = pa_iochannel_read(c->io, c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { fprintf(stderr, __FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } @@ -153,7 +153,7 @@ static int do_write(struct connection *c) { assert(chunk.memblock && chunk.length); - if ((r = pa_iochannel_write(c->io, chunk.memblock->data+chunk.index, chunk.length)) < 0) { + if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { pa_memblock_unref(chunk.memblock); fprintf(stderr, "write(): %s\n", strerror(errno)); return -1; diff --git a/polyp/pstream.c b/polyp/pstream.c index 02dba72d..438dccc7 100644 --- a/polyp/pstream.c +++ b/polyp/pstream.c @@ -272,7 +272,7 @@ static void prepare_next_write_item(struct pa_pstream *p) { p->write.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA] = 0; } else { assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK && p->write.current->chunk.memblock); - p->write.data = p->write.current->chunk.memblock->data + p->write.current->chunk.index; + p->write.data = (uint8_t*) p->write.current->chunk.memblock->data + p->write.current->chunk.index; p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length); p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl(p->write.current->channel); p->write.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA] = htonl(p->write.current->delta); @@ -294,10 +294,10 @@ static void do_write(struct pa_pstream *p) { assert(p->write.data); if (p->write.index < PA_PSTREAM_DESCRIPTOR_SIZE) { - d = (void*) p->write.descriptor + p->write.index; + d = (uint8_t*) p->write.descriptor + p->write.index; l = PA_PSTREAM_DESCRIPTOR_SIZE - p->write.index; } else { - d = (void*) p->write.data + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE; + d = (uint8_t*) p->write.data + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE; l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE); } @@ -330,11 +330,11 @@ static void do_read(struct pa_pstream *p) { assert(p); if (p->read.index < PA_PSTREAM_DESCRIPTOR_SIZE) { - d = (void*) p->read.descriptor + p->read.index; + d = (uint8_t*) p->read.descriptor + p->read.index; l = PA_PSTREAM_DESCRIPTOR_SIZE - p->read.index; } else { assert(p->read.data); - d = (void*) p->read.data + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE; + d = (uint8_t*) p->read.data + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE; l = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE); } diff --git a/polyp/resampler.c b/polyp/resampler.c index ed44cbb7..b6b87607 100644 --- a/polyp/resampler.c +++ b/polyp/resampler.c @@ -146,7 +146,7 @@ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, stru r->i_buf = pa_xrealloc(r->i_buf, sizeof(float) * (r->i_alloc = eff_ins)); assert(r->i_buf); - r->to_float32_func(eff_ins, in->memblock->data+in->index, i_nchannels, r->i_buf); + r->to_float32_func(eff_ins, (uint8_t*) in->memblock->data+in->index, i_nchannels, r->i_buf); if (r->src_state) { int ret; @@ -179,6 +179,6 @@ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, stru } else cbuf = r->i_buf; - r->from_float32_func(eff_ons, cbuf, out->memblock->data+out->index, o_nchannels); + r->from_float32_func(eff_ons, cbuf, (uint8_t*)out->memblock->data+out->index, o_nchannels); out->length = ons*r->o_sz; } diff --git a/polyp/sample-util.c b/polyp/sample-util.c index 6a09478f..51b22fbe 100644 --- a/polyp/sample-util.c +++ b/polyp/sample-util.c @@ -37,7 +37,7 @@ struct pa_memblock *pa_silence_memblock(struct pa_memblock* b, const struct pa_s void pa_silence_memchunk(struct pa_memchunk *c, const struct pa_sample_spec *spec) { assert(c && c->memblock && c->memblock->data && spec && c->length); - pa_silence_memory(c->memblock->data+c->index, c->length, spec); + pa_silence_memory((uint8_t*) c->memblock->data+c->index, c->length, spec); } void pa_silence_memory(void *p, size_t length, const struct pa_sample_spec *spec) { @@ -85,7 +85,7 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz if (volume == PA_VOLUME_MUTED) v = 0; else { - v = *((int16_t*) (channels[c].chunk.memblock->data + channels[c].chunk.index + d)); + v = *((int16_t*) ((uint8_t*) channels[c].chunk.memblock->data + channels[c].chunk.index + d)); if (volume != PA_VOLUME_NORM) v = (int32_t) ((float)v*volume/PA_VOLUME_NORM); @@ -103,7 +103,7 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz if (sum > 0x7FFF) sum = 0x7FFF; *((int16_t*) data) = sum; - data += sizeof(int16_t); + data = (uint8_t*) data + sizeof(int16_t); } } @@ -122,7 +122,7 @@ void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, return; } - for (d = (c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { + for (d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { int32_t t = (int32_t)(*d); t *= volume; diff --git a/polyp/socket-client.c b/polyp/socket-client.c index 3852c1ad..25940122 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -65,7 +65,8 @@ static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) { static void do_call(struct pa_socket_client *c) { struct pa_iochannel *io = NULL; - int error, lerror; + int error; + socklen_t lerror; assert(c && c->callback); pa_socket_client_ref(c); diff --git a/polyp/strbuf.c b/polyp/strbuf.c index ef48a3fb..169604e8 100644 --- a/polyp/strbuf.c +++ b/polyp/strbuf.c @@ -36,7 +36,7 @@ struct chunk { struct chunk *next; size_t length; - char text[0]; + char text[]; }; struct pa_strbuf { -- cgit From fa19d6ab7e2df69902d94a38cc03a183f6d97670 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 1 Sep 2004 12:21:06 +0000 Subject: implement missing scache_get_id_by_name add some more consts to idxset add module-sine, a sine generating sink_input module git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@165 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 4 +- polyp/Makefile.am | 7 ++- polyp/idxset.c | 11 ++-- polyp/idxset.h | 4 +- polyp/module-sine.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++++ polyp/polypaudio.pa | 8 +-- polyp/scache.c | 11 +++- 7 files changed, 195 insertions(+), 15 deletions(-) create mode 100644 polyp/module-sine.c diff --git a/doc/todo b/doc/todo index d3baff16..cc9c333d 100644 --- a/doc/todo +++ b/doc/todo @@ -2,7 +2,7 @@ *** 0.4 *** - make mcalign merge chunks -- use ref counting in more objects +- use ref counting in more objects (i.e. sink, source, sink_input, source_output) - unix socket directories include user name - native library/protocol: module load/unload @@ -14,6 +14,7 @@ - remove all gcc warnings - esd compatible startup script or personality - limit number of concurrent streams +- decibel macros ** later *** - xmlrpc/http @@ -28,4 +29,3 @@ backends for: - sdl - gstreamer - portaudio -- python diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 73e80621..bd71f550 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -79,7 +79,8 @@ pkglib_LTLIBRARIES=libiochannel.la \ module-esound-protocol-tcp.la \ module-esound-protocol-unix.la \ module-native-protocol-tcp.la \ - module-native-protocol-unix.la + module-native-protocol-unix.la \ + module-sine.la if !X_DISPLAY_MISSING pkglib_LTLIBRARIES+=module-x11-bell.la @@ -273,6 +274,10 @@ module_cli_la_SOURCES = module-cli.c module_cli_la_LDFLAGS = -module -avoid-version module_cli_la_LIBADD = $(AM_LIBADD) libcli.la libiochannel.la +module_sine_la_SOURCES = module-sine.c +module_sine_la_LDFLAGS = -module -avoid-version +module_sine_la_LIBADD = $(AM_LIBADD) -lm + if !X_DISPLAY_MISSING module_x11_bell_la_SOURCES = module-x11-bell.c module_x11_bell_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) diff --git a/polyp/idxset.c b/polyp/idxset.c index 83565193..92cde13f 100644 --- a/polyp/idxset.c +++ b/polyp/idxset.c @@ -107,7 +107,7 @@ void pa_idxset_free(struct pa_idxset *s, void (*free_func) (void *p, void *userd pa_xfree(s); } -static struct idxset_entry* hash_scan(struct pa_idxset *s, struct idxset_entry* e, void *p) { +static struct idxset_entry* hash_scan(struct pa_idxset *s, struct idxset_entry* e, const void *p) { assert(p); assert(s->compare_func); @@ -221,7 +221,7 @@ void* pa_idxset_get_by_index(struct pa_idxset*s, uint32_t index) { return (*a)->data; } -void* pa_idxset_get_by_data(struct pa_idxset*s, void *p, uint32_t *index) { +void* pa_idxset_get_by_data(struct pa_idxset*s, const void *p, uint32_t *index) { unsigned h; struct idxset_entry *e; assert(s && p); @@ -289,9 +289,10 @@ void* pa_idxset_remove_by_index(struct pa_idxset*s, uint32_t index) { return data; } -void* pa_idxset_remove_by_data(struct pa_idxset*s, void *data, uint32_t *index) { +void* pa_idxset_remove_by_data(struct pa_idxset*s, const void *data, uint32_t *index) { struct idxset_entry *e; unsigned h; + void *r; assert(s->hash_func); h = s->hash_func(data) % s->hash_table_size; @@ -300,13 +301,13 @@ void* pa_idxset_remove_by_data(struct pa_idxset*s, void *data, uint32_t *index) if (!(e = hash_scan(s, s->hash_table[h], data))) return NULL; - data = e->data; + r = e->data; if (index) *index = e->index; remove_entry(s, e); - return data; + return r; } void* pa_idxset_rrobin(struct pa_idxset *s, uint32_t *index) { diff --git a/polyp/idxset.h b/polyp/idxset.h index f26b03fb..e9a6fb9a 100644 --- a/polyp/idxset.h +++ b/polyp/idxset.h @@ -40,10 +40,10 @@ void pa_idxset_free(struct pa_idxset *s, void (*free_func) (void *p, void *userd int pa_idxset_put(struct pa_idxset*s, void *p, uint32_t *index); void* pa_idxset_get_by_index(struct pa_idxset*s, uint32_t index); -void* pa_idxset_get_by_data(struct pa_idxset*s, void *p, uint32_t *index); +void* pa_idxset_get_by_data(struct pa_idxset*s, const void *p, uint32_t *index); void* pa_idxset_remove_by_index(struct pa_idxset*s, uint32_t index); -void* pa_idxset_remove_by_data(struct pa_idxset*s, void *p, uint32_t *index); +void* pa_idxset_remove_by_data(struct pa_idxset*s, const void *p, uint32_t *index); /* This may be used to iterate through all entries. When called with an invalid index value it returns the first entry, otherwise the diff --git a/polyp/module-sine.c b/polyp/module-sine.c new file mode 100644 index 00000000..364cc64c --- /dev/null +++ b/polyp/module-sine.c @@ -0,0 +1,165 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "sink-input.h" +#include "module.h" +#include "modargs.h" +#include "xmalloc.h" +#include "namereg.h" + +struct userdata { + struct pa_core *core; + struct pa_sink_input *sink_input; + struct pa_memblock *memblock; + size_t peek_index; +}; + +static const char* const valid_modargs[] = { + "sink", + "frequency", + NULL, +}; + +static int sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { + struct userdata *u; + assert(i && chunk && i->userdata); + u = i->userdata; + + chunk->memblock = pa_memblock_ref(u->memblock); + chunk->index = u->peek_index; + chunk->length = u->memblock->length - u->peek_index; + return 0; +} + +static void sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length) { + struct userdata *u; + assert(i && chunk && length && i->userdata); + u = i->userdata; + + assert(chunk->memblock == u->memblock && length <= u->memblock->length-u->peek_index); + + u->peek_index += length; + + if (u->peek_index >= u->memblock->length) + u->peek_index = 0; +} + +static void sink_input_kill(struct pa_sink_input *i) { + struct userdata *u; + assert(i && i->userdata); + u = i->userdata; + + pa_sink_input_free(u->sink_input); + u->sink_input = NULL; +} + +static void calc_sine(float *f, size_t l, float freq) { + size_t i; + + l /= sizeof(float); + + for (i = 0; i < l; i++) + f[i] = (float) sin((double) i/l*M_PI*2*freq)/2; +} + +int pa_module_init(struct pa_core *c, struct pa_module*m) { + struct pa_modargs *ma = NULL; + struct userdata *u; + struct pa_sink *sink; + const char *sink_name; + struct pa_sample_spec ss; + uint32_t frequency; + char t[256]; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + fprintf(stderr, __FILE__": Failed to parse module arguments\n"); + goto fail; + } + + m->userdata = u = pa_xmalloc(sizeof(struct userdata)); + u->core = c; + u->sink_input = NULL; + u->memblock = NULL; + + sink_name = pa_modargs_get_value(ma, "sink", NULL); + + if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) { + fprintf(stderr, __FILE__": No such sink\n"); + goto fail; + } + + ss.format = PA_SAMPLE_FLOAT32; + ss.rate = sink->sample_spec.rate; + ss.channels = 1; + + frequency = 440; + if (pa_modargs_get_value_u32(ma, "frequency", &frequency) < 0 || frequency < 1 || frequency > ss.rate/2) { + fprintf(stderr, __FILE__": Invalid frequency specification\n"); + goto fail; + } + + u->memblock = pa_memblock_new(pa_bytes_per_second(&ss), c->memblock_stat); + calc_sine(u->memblock->data, u->memblock->length, frequency); + + snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency); + if (!(u->sink_input = pa_sink_input_new(sink, t, &ss))) + goto fail; + + u->sink_input->peek = sink_input_peek; + u->sink_input->drop = sink_input_drop; + u->sink_input->kill = sink_input_kill; + u->sink_input->userdata = u; + u->sink_input->owner = m; + + u->peek_index = 0; + + pa_modargs_free(ma); + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + pa_module_done(c, m); + return -1; +} + +void pa_module_done(struct pa_core *c, struct pa_module*m) { + struct userdata *u = m->userdata; + assert(c && m); + + if (!u) + return; + + if (u->sink_input) + pa_sink_input_free(u->sink_input); + if (u->memblock) + pa_memblock_unref(u->memblock); + pa_xfree(u); +} diff --git a/polyp/polypaudio.pa b/polyp/polypaudio.pa index b683e627..8c5157a1 100755 --- a/polyp/polypaudio.pa +++ b/polyp/polypaudio.pa @@ -28,12 +28,12 @@ # Load audio drivers automatically on access -autoload_sink_add output module-oss device="/dev/adsp" sink_name=output source_name=input -autoload_source_add input module-oss device="/dev/adsp" sink_name=output source_name=input +#autoload_sink_add output module-oss device="/dev/adsp" sink_name=output source_name=input +#autoload_source_add input module-oss device="/dev/adsp" sink_name=output source_name=input #autoload_sink_add output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input #autoload_source_add input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#autoload_sink_add output module-alsa-sink sink_name=output -#autoload_source_add input module-alsa-source source_name=input +autoload_sink_add output module-alsa-sink sink_name=output +autoload_source_add input module-alsa-source source_name=input # Load several protocols #load module-esound-protocol-tcp diff --git a/polyp/scache.c b/polyp/scache.c index f3c15934..311d68a4 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -157,5 +157,14 @@ const char * pa_scache_get_name_by_id(struct pa_core *c, uint32_t id) { return NULL; return e->name; - +} + +uint32_t pa_scache_get_id_by_name(struct pa_core *c, const char *name) { + struct pa_scache_entry *e; + assert(c && name); + + if (!c->scache || !(e = pa_idxset_get_by_data(c->scache, name, NULL))) + return PA_IDXSET_INVALID; + + return e->index; } -- cgit From 9c4fd2a2c75b958c22442d2b83e75021bd096be5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 1 Sep 2004 12:48:47 +0000 Subject: add support for dB volumes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@166 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - polyp/Makefile.am | 6 +++--- polyp/cli-text.c | 6 ++++-- polyp/sample.c | 15 +++++++++++++++ polyp/sample.h | 6 ++++++ 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/doc/todo b/doc/todo index cc9c333d..107fc443 100644 --- a/doc/todo +++ b/doc/todo @@ -14,7 +14,6 @@ - remove all gcc warnings - esd compatible startup script or personality - limit number of concurrent streams -- decibel macros ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index bd71f550..6fb7a583 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -19,8 +19,8 @@ AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) #AM_CFLAGS+= -DDLSEARCHDIR=\"$(pkglibdir)\" -AM_LDADD=$(PTHREAD_LIBS) -AM_LIBADD=$(PTHREAD_LIBS) +AM_LDADD=$(PTHREAD_LIBS) -lm +AM_LIBADD=$(PTHREAD_LIBS) -lm polypincludedir=$(includedir)/polyp @@ -276,7 +276,7 @@ module_cli_la_LIBADD = $(AM_LIBADD) libcli.la libiochannel.la module_sine_la_SOURCES = module-sine.c module_sine_la_LDFLAGS = -module -avoid-version -module_sine_la_LIBADD = $(AM_LIBADD) -lm +module_sine_la_LIBADD = $(AM_LIBADD) if !X_DISPLAY_MISSING module_x11_bell_la_SOURCES = module-x11-bell.c diff --git a/polyp/cli-text.c b/polyp/cli-text.c index fa1ccdf9..18a99cfa 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -93,10 +93,11 @@ char *pa_sink_list_to_string(struct pa_core *c) { assert(sink->monitor_source); pa_strbuf_printf( s, - " %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", + " %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%u usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ', sink->index, sink->name, (unsigned) sink->volume, + pa_volume_to_dB(sink->volume), pa_sink_get_latency(sink), sink->monitor_source->index, ss); @@ -188,11 +189,12 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec); assert(i->sink); pa_strbuf_printf( - s, " index: %u\n\tname: <%s>\n\tsink: <%u>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tsample_spec: <%s>\n", + s, " index: %u\n\tname: <%s>\n\tsink: <%u>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%u usec>\n\tsample_spec: <%s>\n", i->index, i->name, i->sink->index, (unsigned) i->volume, + pa_volume_to_dB(i->volume), pa_sink_input_get_latency(i), ss); diff --git a/polyp/sample.c b/polyp/sample.c index edfe1959..3019f93b 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -25,6 +25,7 @@ #include #include +#include #include "sample.h" @@ -104,3 +105,17 @@ pa_volume_t pa_volume_multiply(pa_volume_t a, pa_volume_t b) { return (pa_volume_t) p; } + +pa_volume_t pa_volume_from_dB(double f) { + if (f <= -200) + return PA_VOLUME_MUTED; + + return (pa_volume_t) (pow(10, f/20)*PA_VOLUME_NORM); +} + +double pa_volume_to_dB(pa_volume_t v) { + if (v == PA_VOLUME_MUTED) + return -200; + + return 20*log10((double) v/PA_VOLUME_NORM); +} diff --git a/polyp/sample.h b/polyp/sample.h index 28ae51ea..ca462071 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -102,6 +102,12 @@ typedef uint32_t pa_volume_t; /** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. */ pa_volume_t pa_volume_multiply(pa_volume_t a, pa_volume_t b); +/** Convert volume from decibel to linear level */ +pa_volume_t pa_volume_from_dB(double f); + +/** Convert volume from linear level to decibel */ +double pa_volume_to_dB(pa_volume_t v); + PA_C_DECL_END #endif -- cgit From 9939fba7f5d2e2f39a7156e90f171aa01176f313 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 1 Sep 2004 12:49:39 +0000 Subject: add \since to dB functions git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@167 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/sample.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/polyp/sample.h b/polyp/sample.h index ca462071..0a6c306e 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -102,10 +102,12 @@ typedef uint32_t pa_volume_t; /** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. */ pa_volume_t pa_volume_multiply(pa_volume_t a, pa_volume_t b); -/** Convert volume from decibel to linear level */ +/** Convert volume from decibel to linear level + * \since 0.4 */ pa_volume_t pa_volume_from_dB(double f); -/** Convert volume from linear level to decibel */ +/** Convert volume from linear level to decibel + * \since 0.4 */ double pa_volume_to_dB(pa_volume_t v); PA_C_DECL_END -- cgit From 63c76bd0691a4b4b1d505ad6eac87af7c296cdab Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 1 Sep 2004 12:51:08 +0000 Subject: cleanup comment git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@168 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/sample.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/polyp/sample.h b/polyp/sample.h index 0a6c306e..95844301 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -102,12 +102,10 @@ typedef uint32_t pa_volume_t; /** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. */ pa_volume_t pa_volume_multiply(pa_volume_t a, pa_volume_t b); -/** Convert volume from decibel to linear level - * \since 0.4 */ +/** Convert volume from decibel to linear level. \since 0.4 */ pa_volume_t pa_volume_from_dB(double f); -/** Convert volume from linear level to decibel - * \since 0.4 */ +/** Convert volume from linear level to decibel. \since 0.4 */ double pa_volume_to_dB(pa_volume_t v); PA_C_DECL_END -- cgit From 0205fc57bbfdf03e5cdd5eb3c908f5531c4fdbf1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 1 Sep 2004 13:04:03 +0000 Subject: add PA_MININFTY git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@169 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/oss-util.c | 4 ++-- polyp/sample.c | 4 ++-- polyp/sample.h | 8 ++++++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/polyp/oss-util.c b/polyp/oss-util.c index cf55a6ee..4fb2b929 100644 --- a/polyp/oss-util.c +++ b/polyp/oss-util.c @@ -138,7 +138,7 @@ int pa_oss_auto_format(int fd, struct pa_sample_spec *ss) { return 0; } -static int log2(int v) { +static int simple_log2(int v) { int k = 0; for (;;) { @@ -152,7 +152,7 @@ static int log2(int v) { int pa_oss_set_fragments(int fd, int nfrags, int frag_size) { int arg; - arg = ((int) nfrags << 16) | log2(frag_size); + arg = ((int) nfrags << 16) | simple_log2(frag_size); if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &arg) < 0) { fprintf(stderr, "SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno)); diff --git a/polyp/sample.c b/polyp/sample.c index 3019f93b..6ec56000 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -107,7 +107,7 @@ pa_volume_t pa_volume_multiply(pa_volume_t a, pa_volume_t b) { } pa_volume_t pa_volume_from_dB(double f) { - if (f <= -200) + if (f <= PA_DECIBEL_MININFTY) return PA_VOLUME_MUTED; return (pa_volume_t) (pow(10, f/20)*PA_VOLUME_NORM); @@ -115,7 +115,7 @@ pa_volume_t pa_volume_from_dB(double f) { double pa_volume_to_dB(pa_volume_t v) { if (v == PA_VOLUME_MUTED) - return -200; + return PA_DECIBEL_MININFTY; return 20*log10((double) v/PA_VOLUME_NORM); } diff --git a/polyp/sample.h b/polyp/sample.h index 95844301..4b28780d 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -24,6 +24,7 @@ #include #include +#include #include "cdecl.h" @@ -108,6 +109,13 @@ pa_volume_t pa_volume_from_dB(double f); /** Convert volume from linear level to decibel. \since 0.4 */ double pa_volume_to_dB(pa_volume_t v); +#ifdef INFINITY +#define PA_DECIBEL_MININFTY -INFINITY +#else +/** This value is used as minus infinity when using pa_volume_{to,from}_dB(). \since 0.4 */ +#define PA_DECIBEL_MININFTY -200 +#endif + PA_C_DECL_END #endif -- cgit From 50f592b67c9d7364ab0d7ac447c565db4ab83d2a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 1 Sep 2004 15:00:44 +0000 Subject: introduce sink input and source output limits git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@170 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 ++- polyp/module-x11-bell.c | 6 +----- polyp/sample.h | 4 ++-- polyp/sink-input.c | 5 +++++ polyp/sink.h | 2 ++ polyp/source-output.c | 6 ++++++ polyp/source.h | 2 ++ 7 files changed, 20 insertions(+), 8 deletions(-) diff --git a/doc/todo b/doc/todo index 107fc443..6aacd3a5 100644 --- a/doc/todo +++ b/doc/todo @@ -13,7 +13,8 @@ - cleanup tagstruct and modargs (add s32, pa_volume_t, pa_usec_t) - remove all gcc warnings - esd compatible startup script or personality -- limit number of concurrent streams +- add total sample size to stat +- implement streamed file playbacj ** later *** - xmlrpc/http diff --git a/polyp/module-x11-bell.c b/polyp/module-x11-bell.c index 3ed9b068..ae889b22 100644 --- a/polyp/module-x11-bell.c +++ b/polyp/module-x11-bell.c @@ -69,11 +69,7 @@ static int ring_bell(struct userdata *u, int percent) { return -1; } - if (pa_scache_play_item(u->core, u->scache_item, s, percent*2) < 0) { - fprintf(stderr, __FILE__": Failed to play sample\n"); - return -1; - } - + pa_scache_play_item(u->core, u->scache_item, s, percent*2); return 0; } diff --git a/polyp/sample.h b/polyp/sample.h index 4b28780d..a5479562 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -110,10 +110,10 @@ pa_volume_t pa_volume_from_dB(double f); double pa_volume_to_dB(pa_volume_t v); #ifdef INFINITY -#define PA_DECIBEL_MININFTY -INFINITY +#define PA_DECIBEL_MININFTY (-INFINITY) #else /** This value is used as minus infinity when using pa_volume_{to,from}_dB(). \since 0.4 */ -#define PA_DECIBEL_MININFTY -200 +#define PA_DECIBEL_MININFTY (-200) #endif PA_C_DECL_END diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 9238fac0..95dc5577 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -42,6 +42,11 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con char st[256]; assert(s && spec); + if (pa_idxset_ncontents(s->inputs) >= PA_MAX_INPUTS_PER_SINK) { + fprintf(stderr, __FILE__": Failed to create sink input: too many inputs per sink.\n"); + return NULL; + } + if (!pa_sample_spec_equal(spec, &s->sample_spec)) if (!(resampler = pa_resampler_new(spec, &s->sample_spec, s->core->memblock_stat))) return NULL; diff --git a/polyp/sink.h b/polyp/sink.h index 940d1618..85addf76 100644 --- a/polyp/sink.h +++ b/polyp/sink.h @@ -31,6 +31,8 @@ struct pa_sink; #include "idxset.h" #include "source.h" +#define PA_MAX_INPUTS_PER_SINK 6 + struct pa_sink { uint32_t index; diff --git a/polyp/source-output.c b/polyp/source-output.c index b8083a79..9d124f07 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -23,6 +23,7 @@ #include #endif +#include #include #include #include @@ -37,6 +38,11 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n int r; assert(s && spec); + if (pa_idxset_ncontents(s->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { + fprintf(stderr, __FILE__": Failed to create source output: too many outputs per source.\n"); + return NULL; + } + if (!pa_sample_spec_equal(&s->sample_spec, spec)) if (!(resampler = pa_resampler_new(&s->sample_spec, spec, s->core->memblock_stat))) return NULL; diff --git a/polyp/source.h b/polyp/source.h index 32ef14e6..309b87e7 100644 --- a/polyp/source.h +++ b/polyp/source.h @@ -32,6 +32,8 @@ struct pa_source; #include "memchunk.h" #include "sink.h" +#define PA_MAX_OUTPUTS_PER_SOURCE 16 + struct pa_source { uint32_t index; -- cgit From dfd440bd5db50d3da6146a7f559e3a4f873f8810 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 1 Sep 2004 15:55:48 +0000 Subject: add sound file streaming git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@171 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 +- polyp/Makefile.am | 3 +- polyp/cli-command.c | 12 +--- polyp/play-memchunk.c | 2 +- polyp/play-memchunk.h | 2 +- polyp/sound-file-stream.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++ polyp/sound-file-stream.h | 29 +++++++++ 7 files changed, 198 insertions(+), 15 deletions(-) create mode 100644 polyp/sound-file-stream.c create mode 100644 polyp/sound-file-stream.h diff --git a/doc/todo b/doc/todo index 6aacd3a5..8ad59f1b 100644 --- a/doc/todo +++ b/doc/todo @@ -13,8 +13,7 @@ - cleanup tagstruct and modargs (add s32, pa_volume_t, pa_usec_t) - remove all gcc warnings - esd compatible startup script or personality -- add total sample size to stat -- implement streamed file playbacj +- add total sample cache size to stat ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 6fb7a583..cd369657 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -133,7 +133,8 @@ polypaudio_SOURCES = idxset.c idxset.h \ autoload.c autoload.h \ xmalloc.c xmalloc.h \ subscribe.h subscribe.c \ - debug.h + debug.h \ + sound-file-stream.c sound-file-stream.h polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 5a8ff177..1d2788fa 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -46,6 +46,7 @@ #include "play-memchunk.h" #include "autoload.h" #include "xmalloc.h" +#include "sound-file-stream.h" struct command { const char *name; @@ -516,10 +517,7 @@ static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t, static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { const char *fname, *sink_name; - struct pa_memchunk chunk; - struct pa_sample_spec ss; struct pa_sink *sink; - int ret; assert(c && t && buf && fail && verbose); if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) { @@ -532,14 +530,8 @@ static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, s return -1; } - if (pa_sound_file_load(fname, &ss, &chunk, c->memblock_stat) < 0) { - pa_strbuf_puts(buf, "Failed to load sound file.\n"); - return -1; - } - ret = pa_play_memchunk(sink, fname, &ss, &chunk, PA_VOLUME_NORM); - pa_memblock_unref(chunk.memblock); - return ret; + return pa_play_file(sink, fname, PA_VOLUME_NORM); } static int pa_cli_command_autoload_add(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { diff --git a/polyp/play-memchunk.c b/polyp/play-memchunk.c index 486f0cf6..e3f0c006 100644 --- a/polyp/play-memchunk.c +++ b/polyp/play-memchunk.c @@ -76,7 +76,7 @@ static void sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk*ch pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i); } -int pa_play_memchunk(struct pa_sink *sink, const char *name, const struct pa_sample_spec *ss, const struct pa_memchunk *chunk, uint32_t volume) { +int pa_play_memchunk(struct pa_sink *sink, const char *name, const struct pa_sample_spec *ss, const struct pa_memchunk *chunk, pa_volume_t volume) { struct pa_sink_input *si; struct pa_memchunk *nchunk; diff --git a/polyp/play-memchunk.h b/polyp/play-memchunk.h index edd327c5..0e6a1d8e 100644 --- a/polyp/play-memchunk.h +++ b/polyp/play-memchunk.h @@ -25,6 +25,6 @@ #include "sink.h" #include "memchunk.h" -int pa_play_memchunk(struct pa_sink *sink, const char *name, const struct pa_sample_spec *ss, const struct pa_memchunk *chunk, uint32_t volume); +int pa_play_memchunk(struct pa_sink *sink, const char *name, const struct pa_sample_spec *ss, const struct pa_memchunk *chunk, pa_volume_t volume); #endif diff --git a/polyp/sound-file-stream.c b/polyp/sound-file-stream.c new file mode 100644 index 00000000..a77b5813 --- /dev/null +++ b/polyp/sound-file-stream.c @@ -0,0 +1,162 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include "sound-file-stream.h" +#include "sink-input.h" +#include "xmalloc.h" + +#define BUF_SIZE (1024*10) + +struct userdata { + SNDFILE *sndfile; + struct pa_sink_input *sink_input; + struct pa_memchunk memchunk; +}; + +static void free_userdata(struct userdata *u) { + assert(u); + if (u->sink_input) + pa_sink_input_free(u->sink_input); + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + if (u->sndfile) + sf_close(u->sndfile); + + pa_xfree(u); +} + +static void sink_input_kill(struct pa_sink_input *i) { + assert(i && i->userdata); + free_userdata(i->userdata); +} + +static void si_kill(struct pa_mainloop_api *m, void *i) { + sink_input_kill(i); +} + +static int sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { + struct userdata *u; + assert(i && chunk && i->userdata); + u = i->userdata; + + if (!u->memchunk.memblock) { + uint32_t fs = pa_frame_size(&i->sample_spec); + sf_count_t samples = BUF_SIZE/fs; + + u->memchunk.memblock = pa_memblock_new(BUF_SIZE, i->sink->core->memblock_stat); + u->memchunk.index = 0; + samples = sf_readf_float(u->sndfile, u->memchunk.memblock->data, samples); + u->memchunk.length = samples*fs; + + if (!u->memchunk.length) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + u->memchunk.index = u->memchunk.length = 0; + pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i); + return -1; + } + } + + *chunk = u->memchunk; + pa_memblock_ref(chunk->memblock); + assert(chunk->length); + return 0; +} + +static void sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk*chunk, size_t length) { + struct userdata *u; + assert(i && chunk && length && i->userdata); + u = i->userdata; + + assert(!memcmp(chunk, &u->memchunk, sizeof(chunk))); + assert(length <= u->memchunk.length); + + u->memchunk.index += length; + u->memchunk.length -= length; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + u->memchunk.index = u->memchunk.length = 0; + } +} + +int pa_play_file(struct pa_sink *sink, const char *fname, pa_volume_t volume) { + struct userdata *u = NULL; + SF_INFO sfinfo; + struct pa_sample_spec ss; + assert(sink && fname); + + if (volume <= 0) + goto fail; + + u = pa_xmalloc(sizeof(struct userdata)); + u->sink_input = NULL; + u->memchunk.memblock = NULL; + u->memchunk.index = u->memchunk.length = 0; + u->sndfile = NULL; + + memset(&sfinfo, 0, sizeof(sfinfo)); + + if (!(u->sndfile = sf_open(fname, SFM_READ, &sfinfo))) { + fprintf(stderr, __FILE__": Failed to open file %s\n", fname); + goto fail; + } + + ss.format = PA_SAMPLE_FLOAT32; + ss.rate = sfinfo.samplerate; + ss.channels = sfinfo.channels; + + if (!pa_sample_spec_valid(&ss)) { + fprintf(stderr, __FILE__": Unsupported sample format in file %s\n", fname); + goto fail; + } + + if (!(u->sink_input = pa_sink_input_new(sink, fname, &ss))) + goto fail; + + u->sink_input->volume = volume; + u->sink_input->peek = sink_input_peek; + u->sink_input->drop = sink_input_drop; + u->sink_input->kill = sink_input_kill; + u->sink_input->userdata = u; + + pa_sink_notify(sink); + + return 0; + +fail: + if (u) + free_userdata(u); + + return -1; +} diff --git a/polyp/sound-file-stream.h b/polyp/sound-file-stream.h new file mode 100644 index 00000000..9cf88cce --- /dev/null +++ b/polyp/sound-file-stream.h @@ -0,0 +1,29 @@ +#ifndef foosoundfilestreamhfoo +#define foosoundfilestreamhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "sink.h" + +int pa_play_file(struct pa_sink *sink, const char *fname, pa_volume_t volume); + +#endif -- cgit From ee91cb6c9ded44d7f3ddb23b681df49fe5c8146b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 1 Sep 2004 17:36:46 +0000 Subject: add esd compatible startup script add default configuration script git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@172 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 5 +++- doc/todo | 2 +- polyp/Makefile.am | 9 ++++-- polyp/cmdline.c | 11 ++++++- polyp/esdcompat.sh.in | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++ polyp/main.c | 4 +-- polyp/polypaudio.pa | 2 +- 7 files changed, 108 insertions(+), 8 deletions(-) create mode 100755 polyp/esdcompat.sh.in diff --git a/configure.ac b/configure.ac index 7aa6c5d4..2c470435 100644 --- a/configure.ac +++ b/configure.ac @@ -115,5 +115,8 @@ AM_CONDITIONAL([USE_LYNX], [test "x$lynx" = xyes]) AM_CONDITIONAL(BUILD_LIBPOLYPCORE, false) -AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc polyplib-glib-mainloop.pc polyplib-glib12-mainloop.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf polyp/polyplib-version.h]) +ESDCOMPAT_BINARY=$(bindir)/polypaudio +AC_SUBST(ESDCOMPAT_BINARY) + +AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc polyplib-glib-mainloop.pc polyplib-glib12-mainloop.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf polyp/polyplib-version.h polyp/esdcompat.sh]) AC_OUTPUT diff --git a/doc/todo b/doc/todo index 8ad59f1b..e9c82562 100644 --- a/doc/todo +++ b/doc/todo @@ -12,8 +12,8 @@ - daemon autostart - cleanup tagstruct and modargs (add s32, pa_volume_t, pa_usec_t) - remove all gcc warnings -- esd compatible startup script or personality - add total sample cache size to stat +- make fragments settings runtime configurable ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index cd369657..7d6d9bb3 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -17,17 +17,22 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. +polypincludedir=$(includedir)/polyp +polypconfdir=$(sysconfdir)/polyp + AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) -#AM_CFLAGS+= -DDLSEARCHDIR=\"$(pkglibdir)\" +#AM_CFLAGS+= -DPA_DLSEARCHDIR=\"$(pkglibdir)\" +AM_CFLAGS+= -DPA_DEFAULT_CONFIG_FILE=\"$(polypconfdir)/polypaudio.pa\" AM_LDADD=$(PTHREAD_LIBS) -lm AM_LIBADD=$(PTHREAD_LIBS) -lm -polypincludedir=$(includedir)/polyp EXTRA_DIST = polypaudio.pa depmod.py bin_PROGRAMS = polypaudio pacat pactl noinst_PROGRAMS = mainloop-test mainloop-test-glib mainloop-test-glib12 pacat-simple parec-simple +polypconf_DATA=polypaudio.pa + BUILT_SOURCES=polyplib-version.h polypinclude_HEADERS=polyplib.h \ diff --git a/polyp/cmdline.c b/polyp/cmdline.c index 9935e7b6..6538b930 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -48,6 +48,7 @@ void pa_cmdline_help(const char *argv0) { " -L MODULE Load the specified plugin module with the specified argument\n" " -F FILE Run the specified script\n" " -C Open a command line on the running TTY\n" + " -n Don't load configuration file ("PA_DEFAULT_CONFIG_FILE")\n" " -D Daemonize after loading the modules\n" " -f Dont quit when the startup fails\n" " -v Verbose startup\n" @@ -59,6 +60,7 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { char c; struct pa_cmdline *cmdline = NULL; struct pa_strbuf *buf = NULL; + int no_default_config_file = 0; assert(argc && argv); cmdline = pa_xmalloc(sizeof(struct pa_cmdline)); @@ -68,7 +70,7 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { buf = pa_strbuf_new(); assert(buf); - while ((c = getopt(argc, argv, "L:F:CDhfvrRV")) != -1) { + while ((c = getopt(argc, argv, "L:F:CDhfvrRVn")) != -1) { switch (c) { case 'L': pa_strbuf_printf(buf, "load %s\n", optarg); @@ -100,12 +102,19 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { case 'V': cmdline->version = 1; break; + case 'n': + no_default_config_file =1; + break; default: goto fail; } } + if (!no_default_config_file) + pa_strbuf_puts(buf, ".include "PA_DEFAULT_CONFIG_FILE"\n"); + + cmdline->cli_commands = pa_strbuf_tostring_free(buf); return cmdline; diff --git a/polyp/esdcompat.sh.in b/polyp/esdcompat.sh.in new file mode 100755 index 00000000..1033930e --- /dev/null +++ b/polyp/esdcompat.sh.in @@ -0,0 +1,83 @@ +#!/bin/sh + +# $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +VERSION_STRING="@PACKAGE_NAME@ esd wrapper @PACKAGE_VERSION@" + +fail() { + echo "$1" > /dev/stderr + exit 1 +} + +for N in $(seq $#) ; do + + case "$1" in + + -v|--version) + echo "$VERSION_STRING" + exit 0 + ;; + + -h|--help) + cat < Date: Wed, 1 Sep 2004 21:12:27 +0000 Subject: daemon auto spawn git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@173 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 5 +- doc/todo | 5 +- polyp/Makefile.am | 21 +++++-- polyp/cmdline.c | 38 ++++++++++-- polyp/esdcompat.sh.in | 2 +- polyp/main.c | 8 ++- polyp/module-native-protocol-fd.c | 78 ++++++++++++++++++++++++ polyp/pacat.c | 2 +- polyp/polypaudio.pa | 2 +- polyp/polyplib-context.c | 125 +++++++++++++++++++++++++++++++++----- polyp/polyplib-context.h | 9 +++ polyp/polyplib-internal.h | 1 + polyp/protocol-native.c | 36 +++++++++-- polyp/protocol-native.h | 2 + 14 files changed, 292 insertions(+), 42 deletions(-) create mode 100644 polyp/module-native-protocol-fd.c diff --git a/configure.ac b/configure.ac index 2c470435..7aa6c5d4 100644 --- a/configure.ac +++ b/configure.ac @@ -115,8 +115,5 @@ AM_CONDITIONAL([USE_LYNX], [test "x$lynx" = xyes]) AM_CONDITIONAL(BUILD_LIBPOLYPCORE, false) -ESDCOMPAT_BINARY=$(bindir)/polypaudio -AC_SUBST(ESDCOMPAT_BINARY) - -AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc polyplib-glib-mainloop.pc polyplib-glib12-mainloop.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf polyp/polyplib-version.h polyp/esdcompat.sh]) +AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc polyplib-glib-mainloop.pc polyplib-glib12-mainloop.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf polyp/polyplib-version.h]) AC_OUTPUT diff --git a/doc/todo b/doc/todo index e9c82562..19afa7fa 100644 --- a/doc/todo +++ b/doc/todo @@ -9,11 +9,14 @@ kill client/... autoload management - more complete pactl -- daemon autostart - cleanup tagstruct and modargs (add s32, pa_volume_t, pa_usec_t) - remove all gcc warnings - add total sample cache size to stat - make fragments settings runtime configurable +- CLOEXEC +- logging +- automatic termination of daemon if unused +- add sample directory ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 7d6d9bb3..923a3522 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -21,14 +21,16 @@ polypincludedir=$(includedir)/polyp polypconfdir=$(sysconfdir)/polyp AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) -#AM_CFLAGS+= -DPA_DLSEARCHDIR=\"$(pkglibdir)\" -AM_CFLAGS+= -DPA_DEFAULT_CONFIG_FILE=\"$(polypconfdir)/polypaudio.pa\" +#AM_CFLAGS+= -DDLSEARCHDIR=\"$(pkglibdir)\" +AM_CFLAGS+="-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/polypaudio.pa\"" +AM_CFLAGS+="-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\"" + AM_LDADD=$(PTHREAD_LIBS) -lm AM_LIBADD=$(PTHREAD_LIBS) -lm - -EXTRA_DIST = polypaudio.pa depmod.py +EXTRA_DIST = polypaudio.pa depmod.py esdcompat.sh.in bin_PROGRAMS = polypaudio pacat pactl +bin_SCRIPTS = esdcompat.sh noinst_PROGRAMS = mainloop-test mainloop-test-glib mainloop-test-glib12 pacat-simple parec-simple polypconf_DATA=polypaudio.pa @@ -85,6 +87,7 @@ pkglib_LTLIBRARIES=libiochannel.la \ module-esound-protocol-unix.la \ module-native-protocol-tcp.la \ module-native-protocol-unix.la \ + module-native-protocol-fd.la \ module-sine.la if !X_DISPLAY_MISSING @@ -244,6 +247,11 @@ module_native_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_NATIVE module_native_protocol_unix_la_LDFLAGS = -module -avoid-version module_native_protocol_unix_la_LIBADD = $(AM_LIBADD) libprotocol-native.la libsocket-server.la libsocket-util.la +module_native_protocol_fd_la_SOURCES = module-native-protocol-fd.c +module_native_protocol_fd_la_CFLAGS = $(AM_CFLAGS) +module_native_protocol_fd_la_LDFLAGS = -module -avoid-version +module_native_protocol_fd_la_LIBADD = $(AM_LIBADD) libprotocol-native.la libsocket-server.la libsocket-util.la + module_esound_protocol_tcp_la_SOURCES = module-protocol-stub.c module_esound_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) module_esound_protocol_tcp_la_LDFLAGS = -module -avoid-version @@ -452,3 +460,8 @@ endif suid: polypaudio chown root:root $< chmod u+s $< + +esdcompat.sh: esdcompat.sh.in Makefile + sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ + -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ + -e 's,@POLYPAUDIO_BINARY\@,$(bindir)/polypaudio,g' < $< > $@ diff --git a/polyp/cmdline.c b/polyp/cmdline.c index 6538b930..c07e7bdc 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -28,14 +28,36 @@ #include #include #include +#include #include "cmdline.h" #include "util.h" #include "strbuf.h" #include "xmalloc.h" +#define ENV_CONFIG_FILE "POLYP_CONFIG" + +char* config_file(void) { + char *p, *h; + + if ((p = getenv(ENV_CONFIG_FILE))) + return pa_xstrdup(p); + + if ((h = getenv("HOME"))) { + struct stat st; + p = pa_sprintf_malloc("%s/.polypaudio", h); + if (stat(p, &st) >= 0) + return p; + + pa_xfree(p); + } + + return pa_xstrdup(DEFAULT_CONFIG_FILE); +} + void pa_cmdline_help(const char *argv0) { const char *e; + char *cfg = config_file(); if ((e = strrchr(argv0, '/'))) e++; @@ -48,16 +70,18 @@ void pa_cmdline_help(const char *argv0) { " -L MODULE Load the specified plugin module with the specified argument\n" " -F FILE Run the specified script\n" " -C Open a command line on the running TTY\n" - " -n Don't load configuration file ("PA_DEFAULT_CONFIG_FILE")\n" + " -n Don't load configuration file (%s)\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" - " -V Show version\n", e); + " -V Show version\n", e, cfg); + + pa_xfree(cfg); } struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { - char c; + char c, *cfg; struct pa_cmdline *cmdline = NULL; struct pa_strbuf *buf = NULL; int no_default_config_file = 0; @@ -111,9 +135,11 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { } } - if (!no_default_config_file) - pa_strbuf_puts(buf, ".include "PA_DEFAULT_CONFIG_FILE"\n"); - + if (!no_default_config_file) { + cfg = config_file(); + pa_strbuf_printf(buf, ".include %s\n", cfg); + pa_xfree(cfg); + } cmdline->cli_commands = pa_strbuf_tostring_free(buf); return cmdline; diff --git a/polyp/esdcompat.sh.in b/polyp/esdcompat.sh.in index 1033930e..88ff447f 100755 --- a/polyp/esdcompat.sh.in +++ b/polyp/esdcompat.sh.in @@ -80,4 +80,4 @@ EOF shift done -exec "@ESDCOMPAT_BINARY@" -r +exec "@POLYPAUDIO_BINARY@" -r diff --git a/polyp/main.c b/polyp/main.c index e41a106f..87265da6 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -141,12 +141,15 @@ int main(int argc, char *argv[]) { setsid(); setpgrp(); + + close(0); + close(1); } r = lt_dlinit(); assert(r == 0); -#ifdef PA_DLSEARCHDIR - lt_dladdsearchdir(PA_DLSEARCHDIR); +#ifdef DLSEARCHDIR + lt_dladdsearchdir(DLSEARCHDIR); #endif mainloop = pa_mainloop_new(); @@ -155,6 +158,7 @@ int main(int argc, char *argv[]) { r = pa_signal_init(pa_mainloop_get_api(mainloop)); assert(r == 0); pa_signal_new(SIGINT, exit_signal_callback, NULL); + pa_signal_new(SIGTERM, exit_signal_callback, NULL); signal(SIGPIPE, SIG_IGN); c = pa_core_new(pa_mainloop_get_api(mainloop)); diff --git a/polyp/module-native-protocol-fd.c b/polyp/module-native-protocol-fd.c new file mode 100644 index 00000000..58d09ffe --- /dev/null +++ b/polyp/module-native-protocol-fd.c @@ -0,0 +1,78 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "module.h" +#include "iochannel.h" +#include "modargs.h" +#include "protocol-native.h" + +static const char* const valid_modargs[] = { + "fd", + "public", + "cookie", + NULL, +}; + +int pa_module_init(struct pa_core *c, struct pa_module*m) { + struct pa_iochannel *io; + struct pa_modargs *ma; + int fd, r = -1; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + fprintf(stderr, __FILE__": failed to parse module arguments.\n"); + goto finish; + } + + if (pa_modargs_get_value_u32(ma, "fd", &fd) < 0) { + fprintf(stderr, __FILE__": invalid file descriptor.\n"); + goto finish; + } + + io = pa_iochannel_new(c->mainloop, fd, fd); + + if (!(m->userdata = pa_protocol_native_new_iochannel(c, io, m, ma))) { + pa_iochannel_free(io); + goto finish; + } + + r = 0; + +finish: + if (ma) + pa_modargs_free(ma); + + return r; +} + +void pa_module_done(struct pa_core *c, struct pa_module*m) { + assert(c && m); + + pa_protocol_native_free(m->userdata); +} diff --git a/polyp/pacat.c b/polyp/pacat.c index b251cc35..fd6e90e1 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -346,7 +346,7 @@ int main(int argc, char *argv[]) { pa_context_set_state_callback(context, context_state_callback, NULL); /* Connect the context */ - pa_context_connect(context, NULL); + pa_context_connect_spawn(context, NULL); /* Run the main loop */ if (pa_mainloop_run(m, &ret) < 0) { diff --git a/polyp/polypaudio.pa b/polyp/polypaudio.pa index 0c69893a..715e23b6 100755 --- a/polyp/polypaudio.pa +++ b/polyp/polypaudio.pa @@ -43,7 +43,7 @@ load module-native-protocol-unix load module-esound-protocol-unix # Load the CLI module -load module-cli +#load module-cli # Make some devices default sink_default output diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 2ead4004..fb6eadf4 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -30,6 +30,10 @@ #include #include #include +#include +#include +#include +#include #include "polyplib-internal.h" #include "polyplib-context.h" @@ -234,9 +238,11 @@ static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, u pa_context_ref(c); if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(c, command, t) < 0) pa_context_fail(c, PA_ERROR_PROTOCOL); + pa_context_fail(c, c->error); goto finish; } @@ -267,22 +273,13 @@ finish: pa_context_unref(c); } -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { - struct pa_context *c = userdata; +static void setup_context(struct pa_context *c, struct pa_iochannel *io) { struct pa_tagstruct *t; uint32_t tag; - assert(client && c && c->state == PA_CONTEXT_CONNECTING); + assert(c && io); pa_context_ref(c); - pa_socket_client_unref(client); - c->client = NULL; - - if (!io) { - pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); - goto finish; - } - assert(!c->pstream); c->pstream = pa_pstream_new(c->mainloop, io, c->memblock_stat); assert(c->pstream); @@ -295,6 +292,11 @@ static void on_connection(struct pa_socket_client *client, struct pa_iochannel*i c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); assert(c->pdispatch); + if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { + pa_context_fail(c, PA_ERROR_AUTHKEY); + goto finish; + } + t = pa_tagstruct_new(NULL, 0); assert(t); pa_tagstruct_putu32(t, PA_COMMAND_AUTH); @@ -305,6 +307,27 @@ static void on_connection(struct pa_socket_client *client, struct pa_iochannel*i pa_context_set_state(c, PA_CONTEXT_AUTHORIZING); +finish: + + pa_context_unref(c); +} + +static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { + struct pa_context *c = userdata; + assert(client && c && c->state == PA_CONTEXT_CONNECTING); + + pa_context_ref(c); + + pa_socket_client_unref(client); + c->client = NULL; + + if (!io) { + pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + goto finish; + } + + setup_context(c, io); + finish: pa_context_unref(c); } @@ -343,11 +366,6 @@ int pa_context_connect(struct pa_context *c, const char *server) { pa_context_ref(c); - if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { - pa_context_fail(c, PA_ERROR_AUTHKEY); - goto finish; - } - if (!server) if (!(server = getenv(ENV_DEFAULT_SERVER))) server = DEFAULT_SERVER; @@ -539,3 +557,78 @@ struct pa_operation* pa_context_send_simple_command(struct pa_context *c, uint32 const char* pa_get_library_version(void) { return PACKAGE_VERSION; } + +static int is_running(void) { + struct stat st; + + if (DEFAULT_SERVER[0] != '/') + return 1; + + if (stat(DEFAULT_SERVER, &st) < 0) + return 0; + + return 1; +} + +int pa_context_connect_spawn(struct pa_context *c, void (*atfork)(void)) { + pid_t pid; + int status; + int fds[2] = { -1, -1} ; + struct pa_iochannel *io; + + if (getenv(ENV_DEFAULT_SERVER) || is_running()) + return pa_context_connect(c, NULL); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { + fprintf(stderr, __FILE__": socketpair() failed: %s\n", strerror(errno)); + pa_context_fail(c, PA_ERROR_INTERNAL); + goto fail; + } + + if ((pid = fork()) < 0) { + fprintf(stderr, __FILE__": fork() failed: %s\n", strerror(errno)); + pa_context_fail(c, PA_ERROR_INTERNAL); + goto fail; + } else if (!pid) { + char t[64]; + char *p; + /* Child */ + + close(fds[0]); + + if (atfork) + atfork(); + + if (!(p = getenv(ENV_DEFAULT_BINARY))) + p = POLYPAUDIO_BINARY; + + snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]); + execl(p, p, "-r", "-D", t, NULL); + + exit(1); + } + + /* Parent */ + if (waitpid(pid, &status, 0) < 0) { + fprintf(stderr, __FILE__": waitpid() failed: %s\n", strerror(errno)); + pa_context_fail(c, PA_ERROR_INTERNAL); + goto fail; + } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + goto fail; + } + + close(fds[1]); + + io = pa_iochannel_new(c->mainloop, fds[0], fds[0]); + setup_context(c, io); + return 0; + +fail: + if (fds[0] != -1) + close(fds[0]); + if (fds[1] != -1) + close(fds[1]); + + return -1; +} diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h index 9614ce69..c7d20703 100644 --- a/polyp/polyplib-context.h +++ b/polyp/polyplib-context.h @@ -1,3 +1,4 @@ + #ifndef foopolyplibcontexthfoo #define foopolyplibcontexthfoo @@ -78,6 +79,14 @@ return synchronously on error. Use pa_context_set_state_callback() to be notified when the connection is established */ int pa_context_connect(struct pa_context *c, const char *server); +/** Connect the context to a server. If the default server is local + * but not accessible, spawn a new daemon. If atfork is not NULL it is + * run after the fork() in the child process. It may be used to close + * file descriptors or to do any other cleanups. Make sure that + * SIGCHLD is handled when calling this function. The function will + * waitpid() on the daemon's PID. \since 0.4 */ +int pa_context_connect_spawn(struct pa_context *c, void (*atfork)(void)); + /** Terminate the context connection immediately */ void pa_context_disconnect(struct pa_context *c); diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 813bb04e..de63b1ba 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -47,6 +47,7 @@ #define ENV_DEFAULT_SINK "POLYP_SINK" #define ENV_DEFAULT_SOURCE "POLYP_SOURCE" #define ENV_DEFAULT_SERVER "POLYP_SERVER" +#define ENV_DEFAULT_BINARY "POLYP_BINARY" struct pa_context { int ref; diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 9c6996be..9dddf9a1 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -1466,7 +1466,7 @@ static void client_kill_cb(struct pa_client *c) { static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { struct pa_protocol_native *p = userdata; struct connection *c; - assert(s && io && p); + assert(io && p); c = pa_xmalloc(sizeof(struct connection)); c->authorized = p->public; @@ -1501,10 +1501,10 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo /*** module entry points ***/ -struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { +static struct pa_protocol_native* protocol_new_internal(struct pa_core *c, struct pa_module *m, struct pa_modargs *ma) { struct pa_protocol_native *p; uint32_t public; - assert(core && server && ma); + assert(c && ma); if (pa_modargs_get_value_u32(ma, "public", &public) < 0) { fprintf(stderr, __FILE__": public= expects numeric argument.\n"); @@ -1520,11 +1520,21 @@ struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct p p->module = m; p->public = public; - p->server = server; - p->core = core; + p->server = NULL; + p->core = c; p->connections = pa_idxset_new(NULL, NULL); assert(p->connections); + return p; +} + +struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { + struct pa_protocol_native *p; + + if (!(p = protocol_new_internal(core, m, ma))) + return NULL; + + p->server = server; pa_socket_server_set_callback(p->server, on_connection, p); return p; @@ -1537,6 +1547,20 @@ void pa_protocol_native_free(struct pa_protocol_native *p) { while ((c = pa_idxset_first(p->connections, NULL))) connection_free(c); pa_idxset_free(p->connections, NULL, NULL); - pa_socket_server_unref(p->server); + + if (p->server) + pa_socket_server_unref(p->server); + pa_xfree(p); } + +struct pa_protocol_native* pa_protocol_native_new_iochannel(struct pa_core*core, struct pa_iochannel *io, struct pa_module *m, struct pa_modargs *ma) { + struct pa_protocol_native *p; + + if (!(p = protocol_new_internal(core, m, ma))) + return NULL; + + on_connection(NULL, io, p); + + return p; +} diff --git a/polyp/protocol-native.h b/polyp/protocol-native.h index 3d9fdde1..edc6acbc 100644 --- a/polyp/protocol-native.h +++ b/polyp/protocol-native.h @@ -32,4 +32,6 @@ struct pa_protocol_native; struct pa_protocol_native* pa_protocol_native_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma); void pa_protocol_native_free(struct pa_protocol_native *n); +struct pa_protocol_native* pa_protocol_native_new_iochannel(struct pa_core*core, struct pa_iochannel *io, struct pa_module *m, struct pa_modargs *ma); + #endif -- cgit From 5f52999c016495be1c34effdacd230a79cb52d0b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 1 Sep 2004 22:36:49 +0000 Subject: make use F_CLOEXEC wherever useful git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@174 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - polyp/mainloop-signal.c | 2 ++ polyp/module-pipe-sink.c | 2 ++ polyp/oss-util.c | 3 +++ polyp/socket-client.c | 3 +++ polyp/socket-server.c | 7 +++++++ polyp/socket-util.c | 1 + polyp/util.c | 15 +++++++++++++++ polyp/util.h | 2 ++ 9 files changed, 35 insertions(+), 1 deletion(-) diff --git a/doc/todo b/doc/todo index 19afa7fa..7c1cf71e 100644 --- a/doc/todo +++ b/doc/todo @@ -13,7 +13,6 @@ - remove all gcc warnings - add total sample cache size to stat - make fragments settings runtime configurable -- CLOEXEC - logging - automatic termination of daemon if unused - add sample directory diff --git a/polyp/mainloop-signal.c b/polyp/mainloop-signal.c index f7ff7e93..a16d8457 100644 --- a/polyp/mainloop-signal.c +++ b/polyp/mainloop-signal.c @@ -93,6 +93,8 @@ int pa_signal_init(struct pa_mainloop_api *a) { pa_make_nonblock_fd(signal_pipe[0]); pa_make_nonblock_fd(signal_pipe[1]); + pa_fd_set_cloexec(signal_pipe[0], 1); + pa_fd_set_cloexec(signal_pipe[1], 1); api = a; io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL); diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c index 32a2c722..088ed405 100644 --- a/polyp/module-pipe-sink.c +++ b/polyp/module-pipe-sink.c @@ -143,6 +143,8 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { goto fail; } + pa_fd_set_cloexec(fd, 1); + if (fstat(fd, &st) < 0) { fprintf(stderr, __FILE__": fstat('%s'): %s\n", p, strerror(errno)); goto fail; diff --git a/polyp/oss-util.c b/polyp/oss-util.c index 4fb2b929..b28c3dc9 100644 --- a/polyp/oss-util.c +++ b/polyp/oss-util.c @@ -35,6 +35,7 @@ #include #include "oss-util.h" +#include "util.h" int pa_oss_open(const char *device, int *mode, int* pcaps) { int fd = -1; @@ -77,6 +78,8 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { goto fail; } } + + pa_fd_set_cloexec(fd, 1); return fd; diff --git a/polyp/socket-client.c b/polyp/socket-client.c index 25940122..f697cbdb 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -152,6 +152,7 @@ struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, ui goto fail; } + pa_fd_set_cloexec(c->fd, 1); pa_socket_tcp_low_delay(c->fd); sa.sin_family = AF_INET; @@ -181,6 +182,7 @@ struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, co goto fail; } + pa_fd_set_cloexec(c->fd, 1); pa_socket_low_delay(c->fd); sa.sun_family = AF_LOCAL; @@ -208,6 +210,7 @@ struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m goto fail; } + pa_fd_set_cloexec(c->fd, 1); if (sa->sa_family == AF_INET) pa_socket_tcp_low_delay(c->fd); else diff --git a/polyp/socket-server.c b/polyp/socket-server.c index f01e417c..131339ed 100644 --- a/polyp/socket-server.c +++ b/polyp/socket-server.c @@ -38,6 +38,7 @@ #include "socket-server.h" #include "socket-util.h" #include "xmalloc.h" +#include "util.h" struct pa_socket_server { int ref; @@ -65,6 +66,8 @@ static void callback(struct pa_mainloop_api *mainloop, struct pa_io_event *e, in goto finish; } + pa_fd_set_cloexec(nfd, 1); + if (!s->on_connection) { close(nfd); goto finish; @@ -122,6 +125,8 @@ struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, co goto fail; } + pa_fd_set_cloexec(fd, 1); + sa.sun_family = AF_LOCAL; strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); sa.sun_path[sizeof(sa.sun_path) - 1] = 0; @@ -166,6 +171,8 @@ struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, ui goto fail; } + pa_fd_set_cloexec(fd, 1); + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) fprintf(stderr, "setsockopt(): %s\n", strerror(errno)); diff --git a/polyp/socket-util.c b/polyp/socket-util.c index f9d0febf..1f93ef88 100644 --- a/polyp/socket-util.c +++ b/polyp/socket-util.c @@ -217,3 +217,4 @@ finish: pa_xfree(dir); return ret; } + diff --git a/polyp/util.c b/polyp/util.c index 0d930118..a3276fdf 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -249,3 +249,18 @@ void pa_reset_priority(void) { setpriority(PRIO_PROCESS, 0, 0); } + +int pa_fd_set_cloexec(int fd, int b) { + int v; + assert(fd >= 0); + + if ((v = fcntl(fd, F_GETFD, 0)) < 0) + return -1; + + v = (v & ~FD_CLOEXEC) | (b ? FD_CLOEXEC : 0); + + if (fcntl(fd, F_SETFD, v) < 0) + return -1; + + return 0; +} diff --git a/polyp/util.h b/polyp/util.h index 89505cde..f8dd3f04 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -44,4 +44,6 @@ uint32_t pa_age(struct timeval *tv); void pa_raise_priority(void); void pa_reset_priority(void); +int pa_fd_set_cloexec(int fd, int b); + #endif -- cgit From c73a298f8887e5c96bc53dc1b2aad2fdbb674f64 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 1 Sep 2004 22:46:27 +0000 Subject: add total sample cache size to statistics add size to sample cache entry info git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@175 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 +- polyp/polyplib-introspect.c | 4 +++- polyp/polyplib-introspect.h | 2 ++ polyp/protocol-native.c | 2 ++ polyp/scache.c | 15 +++++++++++++++ polyp/scache.h | 2 ++ 6 files changed, 25 insertions(+), 2 deletions(-) diff --git a/doc/todo b/doc/todo index 7c1cf71e..49e9a88d 100644 --- a/doc/todo +++ b/doc/todo @@ -11,11 +11,11 @@ - more complete pactl - cleanup tagstruct and modargs (add s32, pa_volume_t, pa_usec_t) - remove all gcc warnings -- add total sample cache size to stat - make fragments settings runtime configurable - logging - automatic termination of daemon if unused - add sample directory +- paman: show scache and sample size ** later *** - xmlrpc/http diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index e650fb9f..a4ecf5ee 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -46,6 +46,7 @@ static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uin pa_tagstruct_getu32(t, &i.memblock_total_size) < 0 || pa_tagstruct_getu32(t, &i.memblock_allocated) < 0 || pa_tagstruct_getu32(t, &i.memblock_allocated_size) < 0 || + pa_tagstruct_getu32(t, &i.scache_size) < 0 || !pa_tagstruct_eof(t)) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; @@ -603,7 +604,8 @@ static void context_get_sample_info_callback(struct pa_pdispatch *pd, uint32_t c pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_getu32(t, &i.volume) < 0 || pa_tagstruct_getu32(t, &i.duration) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0) { + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.bytes) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index 25a2db5e..1cc79d0f 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -180,6 +180,7 @@ struct pa_stat_info { uint32_t memblock_total_size; /**< Currentl total size of allocated memory blocks */ uint32_t memblock_allocated; /**< Allocated memory blocks during the whole lifetime of the daemon */ uint32_t memblock_allocated_size; /**< Total size of all memory blocks allocated during the whole lifetime of the daemon */ + uint32_t scache_size; /**< Total size of all sample cache entries. \since 0.4 */ }; /** Get daemon memory block statistics */ @@ -192,6 +193,7 @@ struct pa_sample_info { pa_volume_t volume; /**< Default volume of this entry */ struct pa_sample_spec sample_spec; /**< Sample specification of the sampel */ pa_usec_t duration; /**< Duration of this entry */ + uint32_t bytes; /**< Length of this sample in bytes. \since 0.4 */ }; /** Get information about a sample by its name */ diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 9dddf9a1..cce6cc6c 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -797,6 +797,7 @@ static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->total_size); pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->allocated); pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->allocated_size); + pa_tagstruct_putu32(reply, pa_scache_total_size(c->protocol->core)); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -1044,6 +1045,7 @@ static void scache_fill_tagstruct(struct pa_tagstruct *t, struct pa_scache_entry pa_tagstruct_putu32(t, e->volume); pa_tagstruct_putu32(t, pa_bytes_to_usec(e->memchunk.length, &e->sample_spec)); pa_tagstruct_put_sample_spec(t, &e->sample_spec); + pa_tagstruct_putu32(t, e->memchunk.length); } static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { diff --git a/polyp/scache.c b/polyp/scache.c index 311d68a4..b7a8ff02 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -168,3 +168,18 @@ uint32_t pa_scache_get_id_by_name(struct pa_core *c, const char *name) { return e->index; } + +uint32_t pa_scache_total_size(struct pa_core *c) { + struct pa_scache_entry *e; + uint32_t index; + uint32_t sum; + + if (!c->scache) + return 0; + + for (e = pa_idxset_first(c->scache, &index); e; e = pa_idxset_next(c->scache, &index)) + sum += e->memchunk.length; + + + return sum; +} diff --git a/polyp/scache.h b/polyp/scache.h index 959067f3..cfd479b5 100644 --- a/polyp/scache.h +++ b/polyp/scache.h @@ -44,4 +44,6 @@ void pa_scache_free(struct pa_core *c); const char *pa_scache_get_name_by_id(struct pa_core *c, uint32_t id); uint32_t pa_scache_get_id_by_name(struct pa_core *c, const char *name); +uint32_t pa_scache_total_size(struct pa_core *c); + #endif -- cgit From 4a9239f808b08cf391ded6052bab9cc499e4b505 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 3 Sep 2004 20:14:23 +0000 Subject: add CPU load limiter git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@176 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 + polyp/Makefile.am | 14 +++- polyp/cpulimit-test.c | 84 +++++++++++++++++++++++ polyp/cpulimit.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++ polyp/cpulimit.h | 34 ++++++++++ polyp/main.c | 49 +++++++++++--- polyp/mainloop-signal.c | 43 ++++++------ polyp/sample.c | 11 +++ polyp/sample.h | 3 + polyp/util.c | 17 +++-- 10 files changed, 392 insertions(+), 40 deletions(-) create mode 100644 polyp/cpulimit-test.c create mode 100644 polyp/cpulimit.c create mode 100644 polyp/cpulimit.h diff --git a/doc/todo b/doc/todo index 49e9a88d..0da2a2e0 100644 --- a/doc/todo +++ b/doc/todo @@ -16,6 +16,8 @@ - automatic termination of daemon if unused - add sample directory - paman: show scache and sample size +- add timing parameter to write callback of stream in client API +- add option for disabling module loading ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 923a3522..33b052f3 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -31,7 +31,7 @@ AM_LIBADD=$(PTHREAD_LIBS) -lm EXTRA_DIST = polypaudio.pa depmod.py esdcompat.sh.in bin_PROGRAMS = polypaudio pacat pactl bin_SCRIPTS = esdcompat.sh -noinst_PROGRAMS = mainloop-test mainloop-test-glib mainloop-test-glib12 pacat-simple parec-simple +noinst_PROGRAMS = mainloop-test mainloop-test-glib mainloop-test-glib12 pacat-simple parec-simple cpulimit-test cpulimit-test2 polypconf_DATA=polypaudio.pa @@ -142,7 +142,8 @@ polypaudio_SOURCES = idxset.c idxset.h \ xmalloc.c xmalloc.h \ subscribe.h subscribe.c \ debug.h \ - sound-file-stream.c sound-file-stream.h + sound-file-stream.c sound-file-stream.h \ + cpulimit.c cpulimit.h polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) @@ -387,6 +388,15 @@ mainloop_test_glib12_SOURCES = $(mainloop_test_SOURCES) mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MAIN_LOOP mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12.la +cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c +cpulimit_test_CFLAGS = $(AM_CFLAGS) +cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop.la + +cpulimit_test2_SOURCES = cpulimit-test.c cpulimit.c util.c +cpulimit_test2_CFLAGS = $(AM_CFLAGS) -DTEST2 +cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop.la + + if BUILD_LIBPOLYPCORE polypinclude_HEADERS+=cli-command.h\ diff --git a/polyp/cpulimit-test.c b/polyp/cpulimit-test.c new file mode 100644 index 00000000..71c06ef7 --- /dev/null +++ b/polyp/cpulimit-test.c @@ -0,0 +1,84 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include +#include + +#include "cpulimit.h" +#include "mainloop.h" + +#ifdef TEST2 +#include "mainloop-signal.h" +#endif + +static time_t start; + +#ifdef TEST2 + +static void func(struct pa_mainloop_api *m, struct pa_signal_event *e, int sig, void *userdata) { + time_t now; + time(&now); + + if ((now - start) >= 30) { + m->quit(m, 1); + fprintf(stderr, "Test failed\n"); + } else + raise(SIGUSR1); +} + +#endif + +int main() { + struct pa_mainloop *m; + + m = pa_mainloop_new(); + assert(m); + + pa_cpu_limit_init(pa_mainloop_get_api(m)); + + time(&start); + +#ifdef TEST2 + pa_signal_init(pa_mainloop_get_api(m)); + pa_signal_new(SIGUSR1, func, NULL); + raise(SIGUSR1); + pa_mainloop_run(m, NULL); + pa_signal_done(); +#else + for (;;) { + time_t now; + time(&now); + + if ((now - start) >= 30) { + fprintf(stderr, "Test failed\n"); + break; + } + } +#endif + + pa_cpu_limit_done(); + + pa_mainloop_free(m); + +} diff --git a/polyp/cpulimit.c b/polyp/cpulimit.c new file mode 100644 index 00000000..822e1f33 --- /dev/null +++ b/polyp/cpulimit.c @@ -0,0 +1,175 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpulimit.h" +#include "util.h" + +/* Utilize this much CPU time at most */ +#define CPUTIME_PERCENT 70 + +#define CPUTIME_INTERVAL_SOFT (5) +#define CPUTIME_INTERVAL_HARD (2) + +static time_t last_time = 0; +static int the_pipe[2] = {-1, -1}; +static struct pa_mainloop_api *api = NULL; +static struct pa_io_event *io_event = NULL; +static struct sigaction sigaction_prev; +static int installed = 0; + +static enum { + PHASE_IDLE, + PHASE_SOFT +} phase = PHASE_IDLE; + +static void reset_cpu_time(int t) { + int r; + long n; + struct rlimit rl; + struct rusage ru; + + r = getrusage(RUSAGE_SELF, &ru); + assert(r >= 0); + + n = ru.ru_utime.tv_sec + ru.ru_stime.tv_sec + t; + + r = getrlimit(RLIMIT_CPU, &rl); + assert(r >= 0); + + rl.rlim_cur = n; + r = setrlimit(RLIMIT_CPU, &rl); + assert(r >= 0); +} + +static void write_err(const char *p) { + pa_loop_write(2, p, strlen(p)); +} + +static void signal_handler(int sig) { + assert(sig == SIGXCPU); + + if (phase == PHASE_IDLE) { + time_t now; + char t[256]; + + time(&now); + + snprintf(t, sizeof(t), "Using %0.1f%% CPU\n", (double)CPUTIME_INTERVAL_SOFT/(now-last_time)*100); + write_err(t); + + if (CPUTIME_INTERVAL_SOFT >= ((now-last_time)*(double)CPUTIME_PERCENT/100)) { + static const char c = 'X'; + + write_err("Soft CPU time limit exhausted, terminating.\n"); + + /* Try a soft cleanup */ + write(the_pipe[1], &c, sizeof(c)); + phase = PHASE_SOFT; + reset_cpu_time(CPUTIME_INTERVAL_HARD); + + } else { + + /* Everything's fine */ + reset_cpu_time(CPUTIME_INTERVAL_SOFT); + last_time = now; + } + + } else if (phase == PHASE_SOFT) { + write_err("Hard CPU time limit exhausted, terminating forcibly.\n"); + _exit(1); + } +} + +static void callback(struct pa_mainloop_api*m, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata) { + char c; + assert(m && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == the_pipe[0]); + read(the_pipe[0], &c, sizeof(c)); + m->quit(m, 1); +} + +int pa_cpu_limit_init(struct pa_mainloop_api *m) { + int r; + struct sigaction sa; + assert(m && !api && !io_event && the_pipe[0] == -1 && the_pipe[1] == -1); + + time(&last_time); + + if (pipe(the_pipe) < 0) { + fprintf(stderr, "pipe() failed: %s\n", strerror(errno)); + return -1; + } + + pa_make_nonblock_fd(the_pipe[0]); + pa_make_nonblock_fd(the_pipe[1]); + pa_fd_set_cloexec(the_pipe[0], 1); + pa_fd_set_cloexec(the_pipe[1], 1); + + api = m; + io_event = api->io_new(m, the_pipe[0], PA_IO_EVENT_INPUT, callback, NULL); + + phase = PHASE_IDLE; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = signal_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + + r = sigaction(SIGXCPU, &sa, &sigaction_prev); + assert(r >= 0); + + installed = 1; + + reset_cpu_time(CPUTIME_INTERVAL_SOFT); + + return 0; +} + +void pa_cpu_limit_done(void) { + int r; + + if (io_event) { + assert(api); + api->io_free(io_event); + io_event = NULL; + api = NULL; + } + + if (the_pipe[0] >= 0) + close(the_pipe[0]); + if (the_pipe[1] >= 0) + close(the_pipe[1]); + the_pipe[0] = the_pipe[1] = -1; + + if (installed) { + r = sigaction(SIGXCPU, &sigaction_prev, NULL); + assert(r >= 0); + installed = 0; + } +} diff --git a/polyp/cpulimit.h b/polyp/cpulimit.h new file mode 100644 index 00000000..6d13b6e5 --- /dev/null +++ b/polyp/cpulimit.h @@ -0,0 +1,34 @@ +#ifndef foocpulimithfoo +#define foocpulimithfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "mainloop-api.h" + +/* This kills the polypaudio process if it eats more than 70% of the + * CPU time. This is build around setrlimit() and SIGXCPU. It is handy + * in case of using SCHED_FIFO which may freeze the whole machine */ + +int pa_cpu_limit_init(struct pa_mainloop_api *m); +void pa_cpu_limit_done(void); + +#endif diff --git a/polyp/main.c b/polyp/main.c index 87265da6..eba15c35 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -43,6 +43,7 @@ #include "util.h" #include "sioman.h" #include "xmalloc.h" +#include "cpulimit.h" static struct pa_mainloop *mainloop; @@ -54,15 +55,37 @@ static void drop_root(void) { } } -static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { - m->quit(m, 1); - fprintf(stderr, __FILE__": got signal.\n"); +static const char* signal_name(int s) { + switch(s) { + case SIGINT: return "SIGINT"; + case SIGTERM: return "SIGTERM"; + case SIGUSR1: return "SIGUSR1"; + case SIGUSR2: return "SIGUSR2"; + case SIGXCPU: return "SIGXCPU"; + case SIGPIPE: return "SIGPIPE"; + default: return "UNKNOWN SIGNAL"; + } } -static void aux_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { - struct pa_core *c = userdata; - assert(c); - pa_module_load(c, sig == SIGUSR1 ? "module-cli" : "module-cli-protocol-unix", NULL); +static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { + fprintf(stderr, __FILE__": got signal %s.\n", signal_name(sig)); + + switch (sig) { + case SIGUSR1: + pa_module_load(userdata, "module-cli", NULL); + return; + + case SIGUSR2: + pa_module_load(userdata, "module-cli-protocol-unix", NULL); + return; + + case SIGINT: + case SIGTERM: + default: + fprintf(stderr, "Exiting.\n"); + m->quit(m, 1); + return; + } } static void close_pipe(int p[2]) { @@ -157,16 +180,19 @@ int main(int argc, char *argv[]) { r = pa_signal_init(pa_mainloop_get_api(mainloop)); assert(r == 0); - pa_signal_new(SIGINT, exit_signal_callback, NULL); - pa_signal_new(SIGTERM, exit_signal_callback, NULL); + pa_signal_new(SIGINT, signal_callback, c); + pa_signal_new(SIGTERM, signal_callback, c); signal(SIGPIPE, SIG_IGN); c = pa_core_new(pa_mainloop_get_api(mainloop)); assert(c); - pa_signal_new(SIGUSR1, aux_signal_callback, c); - pa_signal_new(SIGUSR2, aux_signal_callback, c); + pa_signal_new(SIGUSR1, signal_callback, c); + pa_signal_new(SIGUSR2, signal_callback, c); + r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop)); + assert(r == 0); + buf = pa_strbuf_new(); assert(buf); r = pa_cli_command_execute(c, cmdline->cli_commands, buf, &cmdline->fail, &cmdline->verbose); @@ -193,6 +219,7 @@ int main(int argc, char *argv[]) { pa_core_free(c); + pa_cpu_limit_done(); pa_signal_done(); pa_mainloop_free(mainloop); diff --git a/polyp/mainloop-signal.c b/polyp/mainloop-signal.c index a16d8457..4746837b 100644 --- a/polyp/mainloop-signal.c +++ b/polyp/mainloop-signal.c @@ -54,33 +54,31 @@ static void signal_handler(int sig) { } static void callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata) { + ssize_t r; + int sig; + struct pa_signal_event*s; assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]); - for (;;) { - ssize_t r; - int sig; - struct pa_signal_event*s; - if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) { - if (errno == EAGAIN) - return; - - fprintf(stderr, "signal.c: read(): %s\n", strerror(errno)); - return; - } - - if (r != sizeof(sig)) { - fprintf(stderr, "signal.c: short read()\n"); + if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) { + if (errno == EAGAIN) return; - } - for (s = signals; s; s = s->next) - if (s->sig == sig) { - assert(s->callback); - s->callback(a, s, sig, s->userdata); - break; - } + fprintf(stderr, "signal.c: read(): %s\n", strerror(errno)); + return; } + + if (r != sizeof(sig)) { + fprintf(stderr, "signal.c: short read()\n"); + return; + } + + for (s = signals; s; s = s->next) + if (s->sig == sig) { + assert(s->callback); + s->callback(a, s, sig, s->userdata); + break; + } } int pa_signal_init(struct pa_mainloop_api *a) { @@ -108,7 +106,8 @@ void pa_signal_done(void) { while (signals) pa_signal_free(signals); - api->io_free(io_event); + + api->io_free(io_event); io_event = NULL; close(signal_pipe[0]); diff --git a/polyp/sample.c b/polyp/sample.c index 6ec56000..747acf18 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -119,3 +119,14 @@ double pa_volume_to_dB(pa_volume_t v) { return 20*log10((double) v/PA_VOLUME_NORM); } + +void pa_bytes_snprint(char *s, size_t l, off_t v) { + if (v >= 1024*1024*1024) + snprintf(s, l, "%0.1f GB", (double) v/1024/1024/1024); + else if (v >= 1024*1024) + snprintf(s, l, "%0.1f MB", (double) v/1024/1024); + else if (v >= 1024) + snprintf(s, l, "%0.1f KB", (double) v/1024); + else + snprintf(s, l, "%u B", (unsigned) v); +} diff --git a/polyp/sample.h b/polyp/sample.h index a5479562..0141a7cd 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -116,6 +116,9 @@ double pa_volume_to_dB(pa_volume_t v); #define PA_DECIBEL_MININFTY (-200) #endif +/** Pretty print a byte size value. (i.e. "2.5 MB") */ +void pa_bytes_snprint(char *s, size_t l, off_t v); + PA_C_DECL_END #endif diff --git a/polyp/util.c b/polyp/util.c index a3276fdf..061d5710 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -223,16 +223,23 @@ void pa_raise_priority(void) { fprintf(stderr, __FILE__": setpriority() failed: %s\n", strerror(errno)); else fprintf(stderr, __FILE__": Successfully gained nice level %i.\n", NICE_LEVEL); - + #ifdef _POSIX_PRIORITY_SCHEDULING { struct sched_param sp; - sched_getparam(0, &sp); + + if (sched_getparam(0, &sp) < 0) { + fprintf(stderr, __FILE__": sched_getparam() failed: %s\n", strerror(errno)); + return; + } + sp.sched_priority = 1; - if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) + if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) { fprintf(stderr, __FILE__": sched_setscheduler() failed: %s\n", strerror(errno)); - else - fprintf(stderr, __FILE__": Successfully gained SCHED_FIFO scheduling.\n"); + return; + } + + fprintf(stderr, __FILE__": Successfully enabled SCHED_FIFO scheduling.\n"); } #endif } -- cgit From fb962b67dbeb54d1cdd453c6f902b7c679b9197f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 3 Sep 2004 22:44:55 +0000 Subject: add option to disallow module loading after startup git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@177 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - polyp/cmdline.c | 17 +++++++++++++---- polyp/cmdline.h | 2 +- polyp/core.c | 2 ++ polyp/core.h | 2 ++ polyp/cpulimit.c | 14 ++++++++++---- polyp/main.c | 3 +++ polyp/module.c | 3 +++ 8 files changed, 34 insertions(+), 10 deletions(-) diff --git a/doc/todo b/doc/todo index 0da2a2e0..bfc29fab 100644 --- a/doc/todo +++ b/doc/todo @@ -17,7 +17,6 @@ - add sample directory - paman: show scache and sample size - add timing parameter to write callback of stream in client API -- add option for disabling module loading ** later *** - xmlrpc/http diff --git a/polyp/cmdline.c b/polyp/cmdline.c index c07e7bdc..265e0ec8 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -72,6 +72,7 @@ void pa_cmdline_help(const char *argv0) { " -C Open a command line on the running TTY\n" " -n Don't load configuration file (%s)\n" " -D Daemonize after loading the modules\n" + " -d Disallow module loading after startup\n" " -f Dont quit when the startup fails\n" " -v Verbose startup\n" " -h Show this help\n" @@ -88,13 +89,19 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { assert(argc && argv); cmdline = pa_xmalloc(sizeof(struct pa_cmdline)); - cmdline->daemonize = cmdline->help = cmdline->verbose = cmdline->high_priority = cmdline->stay_root = cmdline->version = 0; + cmdline->daemonize = + cmdline->help = + cmdline->verbose = + cmdline->high_priority = + cmdline->stay_root = + cmdline->version = + cmdline->disallow_module_loading = 0; cmdline->fail = 1; buf = pa_strbuf_new(); assert(buf); - while ((c = getopt(argc, argv, "L:F:CDhfvrRVn")) != -1) { + while ((c = getopt(argc, argv, "L:F:CDhfvrRVnd")) != -1) { switch (c) { case 'L': pa_strbuf_printf(buf, "load %s\n", optarg); @@ -127,9 +134,11 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { cmdline->version = 1; break; case 'n': - no_default_config_file =1; + no_default_config_file = 1; + break; + case 'd': + cmdline->disallow_module_loading = 1; break; - default: goto fail; } diff --git a/polyp/cmdline.h b/polyp/cmdline.h index 6a7f4dd7..7330a716 100644 --- a/polyp/cmdline.h +++ b/polyp/cmdline.h @@ -24,7 +24,7 @@ struct pa_cmdline { - int daemonize, help, fail, verbose, high_priority, stay_root, version; + int daemonize, help, fail, verbose, high_priority, stay_root, version, disallow_module_loading; char *cli_commands; }; diff --git a/polyp/core.c b/polyp/core.c index 908564c1..da6ace6a 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -69,6 +69,8 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->subscriptions = NULL; c->memblock_stat = pa_memblock_stat_new(); + + c->disallow_module_loading = 0; pa_check_for_sigpipe(); diff --git a/polyp/core.h b/polyp/core.h index a297d4e0..ffcd018b 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -46,6 +46,8 @@ struct pa_core { struct pa_subscription *subscriptions; struct pa_memblock_stat *memblock_stat; + + int disallow_module_loading; }; struct pa_core* pa_core_new(struct pa_mainloop_api *m); diff --git a/polyp/cpulimit.c b/polyp/cpulimit.c index 822e1f33..7d6fa861 100644 --- a/polyp/cpulimit.c +++ b/polyp/cpulimit.c @@ -31,7 +31,7 @@ #include "cpulimit.h" #include "util.h" -/* Utilize this much CPU time at most */ +/* Utilize this much CPU time at maximum */ #define CPUTIME_PERCENT 70 #define CPUTIME_INTERVAL_SOFT (5) @@ -77,12 +77,17 @@ static void signal_handler(int sig) { if (phase == PHASE_IDLE) { time_t now; + +#ifdef PRINT_CPU_LOAD char t[256]; +#endif time(&now); +#ifdef PRINT_CPU_LOAD snprintf(t, sizeof(t), "Using %0.1f%% CPU\n", (double)CPUTIME_INTERVAL_SOFT/(now-last_time)*100); write_err(t); +#endif if (CPUTIME_INTERVAL_SOFT >= ((now-last_time)*(double)CPUTIME_PERCENT/100)) { static const char c = 'X'; @@ -115,7 +120,6 @@ static void callback(struct pa_mainloop_api*m, struct pa_io_event*e, int fd, enu } int pa_cpu_limit_init(struct pa_mainloop_api *m) { - int r; struct sigaction sa; assert(m && !api && !io_event && the_pipe[0] == -1 && the_pipe[1] == -1); @@ -141,8 +145,10 @@ int pa_cpu_limit_init(struct pa_mainloop_api *m) { sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; - r = sigaction(SIGXCPU, &sa, &sigaction_prev); - assert(r >= 0); + if (sigaction(SIGXCPU, &sa, &sigaction_prev) < 0) { + pa_cpu_limit_done(); + return -1; + } installed = 1; diff --git a/polyp/main.c b/polyp/main.c index eba15c35..1c09276e 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -211,6 +211,9 @@ int main(int argc, char *argv[]) { retval = 0; if (cmdline->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); + + c->disallow_module_loading = cmdline->disallow_module_loading; + fprintf(stderr, __FILE__": mainloop entry.\n"); if (pa_mainloop_run(mainloop, &retval) < 0) retval = 1; diff --git a/polyp/module.c b/polyp/module.c index eb8a8acd..fc714953 100644 --- a/polyp/module.c +++ b/polyp/module.c @@ -54,6 +54,9 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char assert(c && name); + if (c->disallow_module_loading) + goto fail; + m = pa_xmalloc(sizeof(struct pa_module)); m->name = pa_xstrdup(name); -- cgit From 57e473b61cf373f8d9befb03d359b999eca4262b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 4 Sep 2004 00:27:36 +0000 Subject: add support for automatic termination of the daemon after the last client quit remove all gcc warnings add boolean types for tagstruct and modargs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@178 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 6 +----- polyp/client.c | 6 ++++++ polyp/cmdline.c | 7 ++++++- polyp/cmdline.h | 2 +- polyp/core.c | 28 +++++++++++++++++++++++++++ polyp/core.h | 6 ++++++ polyp/main.c | 1 + polyp/modargs.c | 40 +++++++++++++++++++++++++++++++++++++++ polyp/modargs.h | 2 ++ polyp/module-native-protocol-fd.c | 2 +- polyp/module-oss-mmap.c | 9 +++++---- polyp/module-oss.c | 11 ++++++----- polyp/module-protocol-stub.c | 9 +++++---- polyp/module.c | 5 ++++- polyp/polyplib-def.h | 2 +- polyp/polyplib-introspect.c | 2 +- polyp/polyplib-introspect.h | 4 ++-- polyp/polyplib-stream.c | 2 +- polyp/protocol-native.c | 8 ++++---- polyp/protocol-simple.c | 6 +++--- polyp/scache.c | 2 +- polyp/tagstruct.c | 30 +++++++++++++++++++++++++++-- polyp/tagstruct.h | 2 ++ 23 files changed, 155 insertions(+), 37 deletions(-) diff --git a/doc/todo b/doc/todo index bfc29fab..5a1a247c 100644 --- a/doc/todo +++ b/doc/todo @@ -9,17 +9,13 @@ kill client/... autoload management - more complete pactl -- cleanup tagstruct and modargs (add s32, pa_volume_t, pa_usec_t) -- remove all gcc warnings -- make fragments settings runtime configurable - logging -- automatic termination of daemon if unused - add sample directory -- paman: show scache and sample size - add timing parameter to write callback of stream in client API ** later *** - xmlrpc/http +- dbus - slp/rendezvous - modinfo - make alsa modules use mmap diff --git a/polyp/client.c b/polyp/client.c index 0cb42466..c7fb1e07 100644 --- a/polyp/client.c +++ b/polyp/client.c @@ -51,6 +51,8 @@ struct pa_client *pa_client_new(struct pa_core *core, const char *protocol_name, fprintf(stderr, "client: created %u \"%s\"\n", c->index, c->name); pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index); + + pa_core_check_quit(core); return c; } @@ -59,10 +61,14 @@ void pa_client_free(struct pa_client *c) { assert(c && c->core); pa_idxset_remove_by_data(c->core->clients, c, NULL); + + pa_core_check_quit(c->core); + fprintf(stderr, "client: freed %u \"%s\"\n", c->index, c->name); pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index); pa_xfree(c->name); pa_xfree(c); + } void pa_client_kill(struct pa_client *c) { diff --git a/polyp/cmdline.c b/polyp/cmdline.c index 265e0ec8..aba20af1 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -75,6 +75,7 @@ void pa_cmdline_help(const char *argv0) { " -d Disallow module loading after startup\n" " -f Dont quit when the startup fails\n" " -v Verbose startup\n" + " -X SECS Terminate the daemon after the last client quit and this time passed\n" " -h Show this help\n" " -V Show version\n", e, cfg); @@ -97,11 +98,12 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { cmdline->version = cmdline->disallow_module_loading = 0; cmdline->fail = 1; + cmdline->quit_after_last_client_time = -1; buf = pa_strbuf_new(); assert(buf); - while ((c = getopt(argc, argv, "L:F:CDhfvrRVnd")) != -1) { + while ((c = getopt(argc, argv, "L:F:CDhfvrRVndX:")) != -1) { switch (c) { case 'L': pa_strbuf_printf(buf, "load %s\n", optarg); @@ -139,6 +141,9 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { case 'd': cmdline->disallow_module_loading = 1; break; + case 'X': + cmdline->quit_after_last_client_time = atoi(optarg); + break; default: goto fail; } diff --git a/polyp/cmdline.h b/polyp/cmdline.h index 7330a716..d1c438d1 100644 --- a/polyp/cmdline.h +++ b/polyp/cmdline.h @@ -24,7 +24,7 @@ struct pa_cmdline { - int daemonize, help, fail, verbose, high_priority, stay_root, version, disallow_module_loading; + int daemonize, help, fail, verbose, high_priority, stay_root, version, disallow_module_loading, quit_after_last_client_time; char *cli_commands; }; diff --git a/polyp/core.c b/polyp/core.c index da6ace6a..4362f0cb 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -71,6 +71,9 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->memblock_stat = pa_memblock_stat_new(); c->disallow_module_loading = 0; + + c->quit_event = NULL; + c->quit_after_last_client_time = -1; pa_check_for_sigpipe(); @@ -102,6 +105,11 @@ void pa_core_free(struct pa_core *c) { pa_namereg_free(c); pa_autoload_free(c); pa_subscription_free_all(c); + + if (c->quit_event) { + c->mainloop->time_free(c->quit_event); + c->quit_event = NULL; + } pa_xfree(c->default_source_name); pa_xfree(c->default_sink_name); @@ -111,3 +119,23 @@ void pa_core_free(struct pa_core *c) { pa_xfree(c); } +static void quit_callback(struct pa_mainloop_api*m, struct pa_time_event *e, const struct timeval *tv, void *userdata) { + struct pa_core *c = userdata; + assert(c->quit_event = e); + + m->quit(m, 0); +} + +void pa_core_check_quit(struct pa_core *c) { + assert(c); + + if (!c->quit_event && c->quit_after_last_client_time >= 0 && pa_idxset_ncontents(c->clients) == 0) { + struct timeval tv; + gettimeofday(&tv, NULL); + tv.tv_sec+= c->quit_after_last_client_time; + c->quit_event = c->mainloop->time_new(c->mainloop, &tv, quit_callback, c); + } else if (c->quit_event && pa_idxset_ncontents(c->clients) > 0) { + c->mainloop->time_free(c->quit_event); + c->quit_event = NULL; + } +} diff --git a/polyp/core.h b/polyp/core.h index ffcd018b..513d8172 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -48,9 +48,15 @@ struct pa_core { struct pa_memblock_stat *memblock_stat; int disallow_module_loading; + int quit_after_last_client_time; + + struct pa_time_event *quit_event; + }; struct pa_core* pa_core_new(struct pa_mainloop_api *m); void pa_core_free(struct pa_core*c); +void pa_core_check_quit(struct pa_core *c); + #endif diff --git a/polyp/main.c b/polyp/main.c index 1c09276e..0f88a76e 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -213,6 +213,7 @@ int main(int argc, char *argv[]) { pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); c->disallow_module_loading = cmdline->disallow_module_loading; + c->quit_after_last_client_time = cmdline->quit_after_last_client_time; fprintf(stderr, __FILE__": mainloop entry.\n"); if (pa_mainloop_run(mainloop, &retval) < 0) diff --git a/polyp/modargs.c b/polyp/modargs.c index 87d99ad2..4874d808 100644 --- a/polyp/modargs.c +++ b/polyp/modargs.c @@ -207,6 +207,46 @@ int pa_modargs_get_value_u32(struct pa_modargs *ma, const char *key, uint32_t *v return 0; } +int pa_modargs_get_value_s32(struct pa_modargs *ma, const char *key, int32_t *value) { + const char *v; + char *e; + signed long l; + assert(ma && key && value); + + if (!(v = pa_modargs_get_value(ma, key, NULL))) + return 0; + + if (!*v) + return -1; + + l = strtol(v, &e, 0); + if (*e) + return -1; + + *value = (int32_t) l; + return 0; +} + +int pa_modargs_get_value_boolean(struct pa_modargs *ma, const char *key, int *value) { + const char *v; + assert(ma && key && value); + + if (!(v = pa_modargs_get_value(ma, key, NULL))) + return 0; + + if (!*v) + return -1; + + if (!strcmp(v, "1") || !strcasecmp(v, "yes") || !strcasecmp(v, "y") || !strcasecmp(v, "on")) + *value = 1; + else if (!strcmp(v, "0") || !strcasecmp(v, "no") || !strcasecmp(v, "n") || !strcasecmp(v, "off")) + *value = 0; + else + return -1; + + return 0; +} + int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *rss) { const char *format; uint32_t channels; diff --git a/polyp/modargs.h b/polyp/modargs.h index 872fb14f..705d9f43 100644 --- a/polyp/modargs.h +++ b/polyp/modargs.h @@ -33,6 +33,8 @@ void pa_modargs_free(struct pa_modargs*ma); const char *pa_modargs_get_value(struct pa_modargs *ma, const char *key, const char *def); int pa_modargs_get_value_u32(struct pa_modargs *ma, const char *key, uint32_t *value); +int pa_modargs_get_value_s32(struct pa_modargs *ma, const char *key, int32_t *value); +int pa_modargs_get_value_boolean(struct pa_modargs *ma, const char *key, int *value); int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *ss); diff --git a/polyp/module-native-protocol-fd.c b/polyp/module-native-protocol-fd.c index 58d09ffe..213e291e 100644 --- a/polyp/module-native-protocol-fd.c +++ b/polyp/module-native-protocol-fd.c @@ -50,7 +50,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { goto finish; } - if (pa_modargs_get_value_u32(ma, "fd", &fd) < 0) { + if (pa_modargs_get_value_s32(ma, "fd", &fd) < 0) { fprintf(stderr, __FILE__": invalid file descriptor.\n"); goto finish; } diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index 5c3be1ad..8a0dd9a4 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -234,20 +234,21 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { goto fail; } - if (pa_modargs_get_value_u32(ma, "record", &record) < 0 || pa_modargs_get_value_u32(ma, "playback", &playback) < 0) { + if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { fprintf(stderr, __FILE__": record= and playback= expect numeric arguments.\n"); goto fail; } - mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); - if (mode == 0) { + if (!playback && !record) { fprintf(stderr, __FILE__": neither playback nor record enabled for device.\n"); goto fail; } + mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); + nfrags = 12; frag_size = 1024; - if (pa_modargs_get_value_u32(ma, "fragments", &nfrags) < 0 || nfrags < 2 || pa_modargs_get_value_u32(ma, "fragment_size", &frag_size) < 0 || frag_size < 1) { + if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || nfrags < 2 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0 || frag_size < 1) { fprintf(stderr, __FILE__": failed to parse fragments arguments\n"); goto fail; } diff --git a/polyp/module-oss.c b/polyp/module-oss.c index 403716fd..4fd79624 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -177,7 +177,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { int fd = -1; int nfrags, frag_size, in_frag_size, out_frag_size; int mode; - uint32_t record = 1, playback = 1; + int record = 1, playback = 1; struct pa_sample_spec ss; struct pa_modargs *ma = NULL; assert(c && m); @@ -187,20 +187,21 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { goto fail; } - if (pa_modargs_get_value_u32(ma, "record", &record) < 0 || pa_modargs_get_value_u32(ma, "playback", &playback) < 0) { + if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { fprintf(stderr, __FILE__": record= and playback= expect numeric argument.\n"); goto fail; } - mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); - if (mode == 0) { + if (!playback && !record) { fprintf(stderr, __FILE__": neither playback nor record enabled for device.\n"); goto fail; } + mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); + nfrags = 12; frag_size = 1024; - if (pa_modargs_get_value_u32(ma, "fragments", &nfrags) < 0 || nfrags < 2 || pa_modargs_get_value_u32(ma, "fragment_size", &frag_size) < 0 || frag_size < 1) { + if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || nfrags < 2 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0 || frag_size < 1) { fprintf(stderr, __FILE__": failed to parse fragments arguments\n"); goto fail; } diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index e681732f..4d86c28e 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -83,15 +83,16 @@ static const char* const valid_modargs[] = { static struct pa_socket_server *create_socket_server(struct pa_core *c, struct pa_modargs *ma) { struct pa_socket_server *s; #ifdef USE_TCP_SOCKETS - uint32_t loopback = 1, port = IPV4_PORT; + int loopback = 1; + uint32_t port = IPV4_PORT; - if (pa_modargs_get_value_u32(ma, "loopback", &loopback) < 0) { + if (pa_modargs_get_value_boolean(ma, "loopback", &loopback) < 0) { fprintf(stderr, "loopback= expects a numerical argument.\n"); return NULL; } - if (pa_modargs_get_value_u32(ma, "port", &port) < 0) { - fprintf(stderr, "port= expects a numerical argument.\n"); + if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) { + fprintf(stderr, "port= expects a numerical argument between 1 and 65535.\n"); return NULL; } diff --git a/polyp/module.c b/polyp/module.c index fc714953..a06b2754 100644 --- a/polyp/module.c +++ b/polyp/module.c @@ -117,6 +117,10 @@ fail: static void pa_module_free(struct pa_module *m) { assert(m && m->done && m->core); + + if (m->core->disallow_module_loading) + return; + m->done(m->core, m); lt_dlclose(m->dl); @@ -130,7 +134,6 @@ static void pa_module_free(struct pa_module *m) { pa_xfree(m); } - void pa_module_unload(struct pa_core *c, struct pa_module *m) { assert(c && m); diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index 6c3cd825..f0ecc5c4 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -140,7 +140,7 @@ struct pa_latency_info { pa_usec_t buffer_usec; /**< Time in usecs the current buffer takes to play */ pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. */ int playing; /**< Non-zero when the stream is currently playing */ - int queue_length; /**< Queue size in bytes. */ + uint32_t queue_length; /**< Queue size in bytes. */ }; PA_C_DECL_END diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index a4ecf5ee..b31a40c7 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -331,7 +331,7 @@ static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t c pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_gets(t, &i.argument) < 0 || pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_getu32(t, &i.auto_unload) < 0) { + pa_tagstruct_get_boolean(t, &i.auto_unload) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index 1cc79d0f..0a14fad0 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -106,8 +106,8 @@ struct pa_module_info { uint32_t index; /**< Index of the module */ const char*name, /**< Name of the module */ *argument; /**< Argument string of the module */ - uint32_t n_used, /**< Usage counter or PA_INVALID_INDEX */ - auto_unload; /**< Non-zero if this is an autoloaded module */ + uint32_t n_used; /**< Usage counter or PA_INVALID_INDEX */ + int auto_unload; /**< Non-zero if this is an autoloaded module */ }; /** Get some information about a module by its index */ diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 220e4a14..7170a32e 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -329,7 +329,7 @@ static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t comman } else if (pa_tagstruct_getu32(t, &i.buffer_usec) < 0 || pa_tagstruct_getu32(t, &i.sink_usec) < 0 || - pa_tagstruct_getu32(t, &i.playing) < 0 || + pa_tagstruct_get_boolean(t, &i.playing) < 0 || pa_tagstruct_getu32(t, &i.queue_length) < 0 || !pa_tagstruct_eof(t)) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index cce6cc6c..2572810f 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -830,7 +830,7 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma pa_tagstruct_putu32(reply, tag); pa_tagstruct_putu32(reply, pa_sink_input_get_latency(s->sink_input)); pa_tagstruct_putu32(reply, pa_sink_get_latency(s->sink_input->sink)); - pa_tagstruct_putu32(reply, pa_memblockq_is_readable(s->memblockq)); + pa_tagstruct_put_boolean(reply, pa_memblockq_is_readable(s->memblockq)); pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq)); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -1012,7 +1012,7 @@ static void module_fill_tagstruct(struct pa_tagstruct *t, struct pa_module *modu pa_tagstruct_puts(t, module->name); pa_tagstruct_puts(t, module->argument ? module->argument : ""); pa_tagstruct_putu32(t, module->n_used); - pa_tagstruct_putu32(t, module->auto_unload); + pa_tagstruct_put_boolean(t, module->auto_unload); } static void sink_input_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink_input *s) { @@ -1505,10 +1505,10 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo static struct pa_protocol_native* protocol_new_internal(struct pa_core *c, struct pa_module *m, struct pa_modargs *ma) { struct pa_protocol_native *p; - uint32_t public; + int public; assert(c && ma); - if (pa_modargs_get_value_u32(ma, "public", &public) < 0) { + if (pa_modargs_get_value_boolean(ma, "public", &public) < 0) { fprintf(stderr, __FILE__": public= expects numeric argument.\n"); return NULL; } diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index 41c1f484..3ccb3068 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -366,7 +366,7 @@ fail: struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { struct pa_protocol_simple* p = NULL; - uint32_t enable; + int enable; assert(core && server && ma); p = pa_xmalloc0(sizeof(struct pa_protocol_simple)); @@ -385,14 +385,14 @@ struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct p p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); enable = 0; - if (pa_modargs_get_value_u32(ma, "record", &enable) < 0) { + if (pa_modargs_get_value_boolean(ma, "record", &enable) < 0) { fprintf(stderr, __FILE__": record= expects a numeric argument.\n"); goto fail; } p->mode = enable ? RECORD : 0; enable = 1; - if (pa_modargs_get_value_u32(ma, "playback", &enable) < 0) { + if (pa_modargs_get_value_boolean(ma, "playback", &enable) < 0) { fprintf(stderr, __FILE__": playback= expects a numeric argument.\n"); goto fail; } diff --git a/polyp/scache.c b/polyp/scache.c index b7a8ff02..53e8a3fe 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -172,7 +172,7 @@ uint32_t pa_scache_get_id_by_name(struct pa_core *c, const char *name) { uint32_t pa_scache_total_size(struct pa_core *c) { struct pa_scache_entry *e; uint32_t index; - uint32_t sum; + uint32_t sum = 0; if (!c->scache) return 0; diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c index 742f6b9c..5aa79e6c 100644 --- a/polyp/tagstruct.c +++ b/polyp/tagstruct.c @@ -40,7 +40,9 @@ enum tags { TAG_U8 = 'B', TAG_S8 = 'b', TAG_SAMPLE_SPEC = 'a', - TAG_ARBITRARY = 'x' + TAG_ARBITRARY = 'x', + TAG_BOOLEAN_TRUE = '1', + TAG_BOOLEAN_FALSE = '0', }; struct pa_tagstruct { @@ -125,7 +127,6 @@ void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample t->length += 7; } - void pa_tagstruct_put_arbitrary(struct pa_tagstruct *t, const void *p, size_t length) { assert(t && p); @@ -137,6 +138,13 @@ void pa_tagstruct_put_arbitrary(struct pa_tagstruct *t, const void *p, size_t le t->length += 5+length; } +void pa_tagstruct_put_boolean(struct pa_tagstruct*t, int b) { + assert(t); + extend(t, 1); + t->data[t->length] = b ? TAG_BOOLEAN_TRUE : TAG_BOOLEAN_FALSE; + t->length += 1; +} + int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s) { int error = 0; size_t n; @@ -238,3 +246,21 @@ const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l) { return t->data; } +int pa_tagstruct_get_boolean(struct pa_tagstruct*t, int *b) { + assert(t && b); + + if (t->rindex+1 > t->length) + return -1; + + if (t->data[t->rindex] == TAG_BOOLEAN_TRUE) + *b = 1; + else if (t->data[t->rindex] == TAG_BOOLEAN_FALSE) + *b = 0; + else + return -1; + + t->rindex +=1; + return 0; +} + + diff --git a/polyp/tagstruct.h b/polyp/tagstruct.h index bcd7f456..9a91ee96 100644 --- a/polyp/tagstruct.h +++ b/polyp/tagstruct.h @@ -38,12 +38,14 @@ void pa_tagstruct_putu32(struct pa_tagstruct*t, uint32_t i); void pa_tagstruct_putu8(struct pa_tagstruct*t, uint8_t c); void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample_spec *ss); void pa_tagstruct_put_arbitrary(struct pa_tagstruct*t, const void *p, size_t length); +void pa_tagstruct_put_boolean(struct pa_tagstruct*t, int b); int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s); int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i); int pa_tagstruct_getu8(struct pa_tagstruct*t, uint8_t *c); int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec *ss); int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t length); +int pa_tagstruct_get_boolean(struct pa_tagstruct *t, int *b); int pa_tagstruct_eof(struct pa_tagstruct*t); const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l); -- cgit From 6c4fd620408b3f14a1d4164d58db70df7a252674 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 5 Sep 2004 00:03:16 +0000 Subject: implement proper logging git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@179 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 5 +++- doc/todo | 1 - polyp/Makefile.am | 9 ++++++-- polyp/authkey.c | 5 ++-- polyp/cli.c | 5 ++-- polyp/client.c | 7 +++--- polyp/cmdline.c | 20 ++++++++++++++-- polyp/cmdline.h | 13 ++++++++++- polyp/core.h | 1 - polyp/cpulimit.c | 3 ++- polyp/gcc-printf.h | 10 ++++++++ polyp/log.c | 48 +++++++++++++++++++++++++++++++++++++++ polyp/log.h | 17 ++++++++++++++ polyp/main.c | 39 +++++++++++++++++++------------ polyp/mainloop-signal.c | 7 +++--- polyp/mainloop.c | 5 ++-- polyp/memblockq.c | 7 +++--- polyp/module-alsa-sink.c | 23 ++++++++++--------- polyp/module-alsa-source.c | 21 +++++++++-------- polyp/module-cli.c | 5 ++-- polyp/module-native-protocol-fd.c | 5 ++-- polyp/module-oss-mmap.c | 39 +++++++++++++++---------------- polyp/module-oss.c | 25 ++++++++++---------- polyp/module-pipe-sink.c | 15 ++++++------ polyp/module-protocol-stub.c | 13 ++++++----- polyp/module-sine.c | 7 +++--- polyp/module-x11-bell.c | 13 ++++++----- polyp/module.c | 10 ++++++-- polyp/oss-util.c | 17 +++++++------- polyp/pdispatch.c | 5 ++-- polyp/polypaudio.pa | 2 +- polyp/polyplib-context.c | 11 +++++---- polyp/polyplib-simple.c | 3 ++- polyp/protocol-esound.c | 23 ++++++++++--------- polyp/protocol-native.c | 27 +++++++++++----------- polyp/protocol-simple.c | 21 +++++++++-------- polyp/pstream.c | 7 +++--- polyp/sink-input.c | 5 ++-- polyp/sink.c | 5 ++-- polyp/socket-client.c | 15 ++++++------ polyp/socket-server.c | 17 +++++++------- polyp/socket-util.c | 7 +++--- polyp/sound-file-stream.c | 5 ++-- polyp/sound-file.c | 9 ++++---- polyp/source-output.c | 3 ++- polyp/source.c | 5 ++-- polyp/strbuf.h | 4 +++- polyp/subscribe.c | 25 ++++++++++---------- polyp/util.c | 41 ++++++++++++++++++++++++++------- polyp/util.h | 6 ++++- 50 files changed, 416 insertions(+), 225 deletions(-) create mode 100644 polyp/gcc-printf.h create mode 100644 polyp/log.c create mode 100644 polyp/log.h diff --git a/configure.ac b/configure.ac index 7aa6c5d4..f221689d 100644 --- a/configure.ac +++ b/configure.ac @@ -52,6 +52,7 @@ AM_CONDITIONAL(X_DISPLAY_MISSING, test "x$X_DISPLAY_MISSING" != "x") AC_C_CONST AC_TYPE_PID_T AC_TYPE_SIZE_T +AC_TYPE_OFF_T AC_HEADER_TIME # Checks for library functions. @@ -65,7 +66,9 @@ AC_FUNC_MMAP AC_FUNC_REALLOC AC_FUNC_SETPGRP AC_TYPE_SIGNAL -AC_CHECK_FUNCS([gethostname gettimeofday memchr memmove memset mkdir mkfifo munmap rmdir socket strcspn strerror strrchr strspn strstr strtol strtoul]) +AC_CHECK_FUNCS([gethostname gettimeofday memchr memmove memset mkdir mkfifo munmap rmdir socket strcspn strerror strrchr strspn strstr strtol strtoul pow strcasecmp]) +AC_FUNC_STAT +AC_HEADER_SYS_WAIT AC_C_BIGENDIAN diff --git a/doc/todo b/doc/todo index 5a1a247c..8ae9e739 100644 --- a/doc/todo +++ b/doc/todo @@ -9,7 +9,6 @@ kill client/... autoload management - more complete pactl -- logging - add sample directory - add timing parameter to write callback of stream in client API diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 33b052f3..335fa99a 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -143,7 +143,9 @@ polypaudio_SOURCES = idxset.c idxset.h \ subscribe.h subscribe.c \ debug.h \ sound-file-stream.c sound-file-stream.h \ - cpulimit.c cpulimit.h + cpulimit.c cpulimit.h \ + log.c log.h \ + gcc-printf.h polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) @@ -329,7 +331,10 @@ libpolyp_la_SOURCES = polyplib.h \ polyplib-subscribe.c polyplib-subscribe.h \ polyplib-internal.h \ cdecl.h \ - llist.h + llist.h \ + log.c log.h \ + gcc-printf.h + libpolyp_la_CFLAGS = $(AM_CFLAGS) libpolyp_la_LDFLAGS = -version-info 0:0:0 diff --git a/polyp/authkey.c b/polyp/authkey.c index 3180b8fd..bbc45c37 100644 --- a/polyp/authkey.c +++ b/polyp/authkey.c @@ -36,6 +36,7 @@ #include "authkey.h" #include "util.h" +#include "log.h" #define RANDOM_DEVICE "/dev/urandom" @@ -80,7 +81,7 @@ static int generate(const char *fn, void *data, size_t length) { } else { uint8_t *p; size_t l; - fprintf(stderr, "WARNING: Failed to open entropy device '"RANDOM_DEVICE"': %s, falling back to unsecure pseudo RNG.\n", strerror(errno)); + pa_log(__FILE__": WARNING: Failed to open entropy device '"RANDOM_DEVICE"': %s, falling back to unsecure pseudo RNG.\n", strerror(errno)); srandom(time(NULL)); @@ -122,7 +123,7 @@ int pa_authkey_load(const char *path, void *data, size_t length) { } if (ret < 0) - fprintf(stderr, "Failed to load authorization key '%s': %s\n", path, (ret == -1) ? strerror(errno) : "file corrupt"); + pa_log(__FILE__": Failed to load authorization key '%s': %s\n", path, (ret == -1) ? strerror(errno) : "file corrupt"); return ret; } diff --git a/polyp/cli.c b/polyp/cli.c index 6fd2c238..09e9855d 100644 --- a/polyp/cli.c +++ b/polyp/cli.c @@ -42,6 +42,7 @@ #include "cli-text.h" #include "cli-command.h" #include "xmalloc.h" +#include "log.h" struct pa_cli { struct pa_core *core; @@ -103,7 +104,7 @@ static void client_kill(struct pa_client *client) { assert(client && client->userdata); c = client->userdata; - fprintf(stderr, "CLI client killed.\n"); + pa_log(__FILE__": CLI client killed.\n"); if (c->defer_kill) c->kill_requested = 1; else { @@ -119,7 +120,7 @@ static void line_callback(struct pa_ioline *line, const char *s, void *userdata) assert(line && c); if (!s) { - fprintf(stderr, "CLI got EOF from user.\n"); + pa_log(__FILE__": CLI got EOF from user.\n"); if (c->eof_callback) c->eof_callback(c, c->userdata); diff --git a/polyp/client.c b/polyp/client.c index c7fb1e07..a544b4fe 100644 --- a/polyp/client.c +++ b/polyp/client.c @@ -31,6 +31,7 @@ #include "client.h" #include "xmalloc.h" #include "subscribe.h" +#include "log.h" struct pa_client *pa_client_new(struct pa_core *core, const char *protocol_name, char *name) { struct pa_client *c; @@ -49,7 +50,7 @@ struct pa_client *pa_client_new(struct pa_core *core, const char *protocol_name, r = pa_idxset_put(core->clients, c, &c->index); assert(c->index != PA_IDXSET_INVALID && r >= 0); - fprintf(stderr, "client: created %u \"%s\"\n", c->index, c->name); + pa_log(__FILE__": created %u \"%s\"\n", c->index, c->name); pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index); pa_core_check_quit(core); @@ -64,7 +65,7 @@ void pa_client_free(struct pa_client *c) { pa_core_check_quit(c->core); - fprintf(stderr, "client: freed %u \"%s\"\n", c->index, c->name); + pa_log(__FILE__": freed %u \"%s\"\n", c->index, c->name); pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index); pa_xfree(c->name); pa_xfree(c); @@ -74,7 +75,7 @@ void pa_client_free(struct pa_client *c) { void pa_client_kill(struct pa_client *c) { assert(c); if (!c->kill) { - fprintf(stderr, "kill() operation not implemented for client %u\n", c->index); + pa_log(__FILE__": kill() operation not implemented for client %u\n", c->index); return; } diff --git a/polyp/cmdline.c b/polyp/cmdline.c index aba20af1..1d650185 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -77,6 +77,7 @@ void pa_cmdline_help(const char *argv0) { " -v Verbose startup\n" " -X SECS Terminate the daemon after the last client quit and this time passed\n" " -h Show this help\n" + " -l TARGET Specify the log target (syslog, stderr, auto)\n" " -V Show version\n", e, cfg); pa_xfree(cfg); @@ -97,13 +98,14 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { cmdline->stay_root = cmdline->version = cmdline->disallow_module_loading = 0; - cmdline->fail = 1; + cmdline->fail = cmdline->auto_log_target = 1; cmdline->quit_after_last_client_time = -1; + cmdline->log_target = -1; buf = pa_strbuf_new(); assert(buf); - while ((c = getopt(argc, argv, "L:F:CDhfvrRVndX:")) != -1) { + while ((c = getopt(argc, argv, "L:F:CDhfvrRVndX:l:")) != -1) { switch (c) { case 'L': pa_strbuf_printf(buf, "load %s\n", optarg); @@ -144,6 +146,20 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { case 'X': cmdline->quit_after_last_client_time = atoi(optarg); break; + case 'l': + if (!strcmp(optarg, "syslog")) { + cmdline->auto_log_target = 0; + cmdline->log_target = PA_LOG_SYSLOG; + } else if (!strcmp(optarg, "stderr")) { + cmdline->auto_log_target = 0; + cmdline->log_target = PA_LOG_STDERR; + } else if (!strcmp(optarg, "auto")) + cmdline->auto_log_target = 1; + else { + pa_log(__FILE__": Invalid log target: use either 'syslog', 'stderr' or 'auto'.\n"); + goto fail; + } + break; default: goto fail; } diff --git a/polyp/cmdline.h b/polyp/cmdline.h index d1c438d1..d49b65fb 100644 --- a/polyp/cmdline.h +++ b/polyp/cmdline.h @@ -22,10 +22,21 @@ USA. ***/ +#include "log.h" struct pa_cmdline { - int daemonize, help, fail, verbose, high_priority, stay_root, version, disallow_module_loading, quit_after_last_client_time; + int daemonize, + help, + fail, + verbose, + high_priority, + stay_root, + version, + disallow_module_loading, + quit_after_last_client_time, + auto_log_target; char *cli_commands; + enum pa_log_target log_target; }; struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []); diff --git a/polyp/core.h b/polyp/core.h index 513d8172..ca37507c 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -51,7 +51,6 @@ struct pa_core { int quit_after_last_client_time; struct pa_time_event *quit_event; - }; struct pa_core* pa_core_new(struct pa_mainloop_api *m); diff --git a/polyp/cpulimit.c b/polyp/cpulimit.c index 7d6fa861..fc49f5bb 100644 --- a/polyp/cpulimit.c +++ b/polyp/cpulimit.c @@ -30,6 +30,7 @@ #include "cpulimit.h" #include "util.h" +#include "log.h" /* Utilize this much CPU time at maximum */ #define CPUTIME_PERCENT 70 @@ -126,7 +127,7 @@ int pa_cpu_limit_init(struct pa_mainloop_api *m) { time(&last_time); if (pipe(the_pipe) < 0) { - fprintf(stderr, "pipe() failed: %s\n", strerror(errno)); + pa_log(__FILE__": pipe() failed: %s\n", strerror(errno)); return -1; } diff --git a/polyp/gcc-printf.h b/polyp/gcc-printf.h new file mode 100644 index 00000000..224552af --- /dev/null +++ b/polyp/gcc-printf.h @@ -0,0 +1,10 @@ +#ifndef foogccprintfhfoo +#define foogccprintfhfoo + +#ifdef __GNUC__ +#define PA_GCC_PRINTF_ATTR(a,b) __attribute__ ((format (printf, a, b))) +#else +#define PA_GCC_PRINTF_ATTR(a,b) +#endif + +#endif diff --git a/polyp/log.c b/polyp/log.c new file mode 100644 index 00000000..413266df --- /dev/null +++ b/polyp/log.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include + +#include "log.h" +#include "xmalloc.h" +#include "util.h" + +static char *log_ident = NULL; +static enum pa_log_target log_target = PA_LOG_STDERR; +static void (*user_log_func)(const char *s) = NULL; + +void pa_log_set_ident(const char *p) { + if (log_ident) + pa_xfree(log_ident); + + log_ident = pa_xstrdup(p); +} + +void pa_log_set_target(enum pa_log_target t, void (*func)(const char*s)) { + assert(t == PA_LOG_USER || !func); + log_target = t; + user_log_func = func; +} + +void pa_log(const char *format, ...) { + va_list ap; + va_start(ap, format); + + switch (log_target) { + case PA_LOG_STDERR: + vfprintf(stderr, format, ap); + break; + case PA_LOG_SYSLOG: + openlog(log_ident ? log_ident : "???", LOG_PID, LOG_USER); + vsyslog(LOG_INFO, format, ap); + closelog(); + break; + case PA_LOG_USER: { + char *t = pa_vsprintf_malloc(format, ap); + assert(user_log_func); + user_log_func(t); + } + } + + va_end(ap); +} diff --git a/polyp/log.h b/polyp/log.h new file mode 100644 index 00000000..1f2c74ef --- /dev/null +++ b/polyp/log.h @@ -0,0 +1,17 @@ +#ifndef foologhfoo +#define foologhfoo + +#include "gcc-printf.h" + +enum pa_log_target { + PA_LOG_SYSLOG, + PA_LOG_STDERR, + PA_LOG_USER, +}; + +void pa_log_set_ident(const char *p); +void pa_log_set_target(enum pa_log_target t, void (*func)(const char*s)); + +void pa_log(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); + +#endif diff --git a/polyp/main.c b/polyp/main.c index 0f88a76e..29a7b548 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -44,12 +44,13 @@ #include "sioman.h" #include "xmalloc.h" #include "cpulimit.h" +#include "log.h" static struct pa_mainloop *mainloop; static void drop_root(void) { if (getuid() != 0 && geteuid() == 0) { - fprintf(stderr, __FILE__": started SUID root, dropping root rights.\n"); + pa_log(__FILE__": Started SUID root, dropping root rights.\n"); setuid(getuid()); seteuid(getuid()); } @@ -68,7 +69,7 @@ static const char* signal_name(int s) { } static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { - fprintf(stderr, __FILE__": got signal %s.\n", signal_name(sig)); + pa_log(__FILE__": Got signal %s.\n", signal_name(sig)); switch (sig) { case SIGUSR1: @@ -82,7 +83,7 @@ static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, case SIGINT: case SIGTERM: default: - fprintf(stderr, "Exiting.\n"); + pa_log(__FILE__": Exiting.\n"); m->quit(m, 1); return; } @@ -104,11 +105,15 @@ int main(int argc, char *argv[]) { int r, retval = 1; int daemon_pipe[2] = { -1, -1 }; + pa_log_set_ident("polypaudio"); + if (!(cmdline = pa_cmdline_parse(argc, argv))) { - fprintf(stderr, __FILE__": failed to parse command line.\n"); + pa_log(__FILE__": failed to parse command line.\n"); goto finish; } + pa_log_set_target(cmdline->auto_log_target ? PA_LOG_STDERR : cmdline->log_target, NULL); + if (cmdline->help) { pa_cmdline_help(argv[0]); retval = 0; @@ -131,17 +136,17 @@ int main(int argc, char *argv[]) { pid_t child; if (pa_stdio_acquire() < 0) { - fprintf(stderr, __FILE__": failed to acquire stdio.\n"); + pa_log(__FILE__": failed to acquire stdio.\n"); goto finish; } if (pipe(daemon_pipe) < 0) { - fprintf(stderr, __FILE__": failed to create pipe.\n"); + pa_log(__FILE__": failed to create pipe.\n"); goto finish; } if ((child = fork()) < 0) { - fprintf(stderr, __FILE__": fork() failed: %s\n", strerror(errno)); + pa_log(__FILE__": fork() failed: %s\n", strerror(errno)); goto finish; } @@ -152,7 +157,7 @@ int main(int argc, char *argv[]) { daemon_pipe[1] = -1; if (pa_loop_read(daemon_pipe[0], &retval, sizeof(retval)) != sizeof(retval)) { - fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno)); + pa_log(__FILE__": read() failed: %s\n", strerror(errno)); retval = 1; } @@ -162,6 +167,10 @@ int main(int argc, char *argv[]) { close(daemon_pipe[0]); daemon_pipe[0] = -1; + + if (cmdline->auto_log_target) + pa_log_set_target(PA_LOG_SYSLOG, NULL); + setsid(); setpgrp(); @@ -196,15 +205,15 @@ int main(int argc, char *argv[]) { 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)); + pa_log(s = pa_strbuf_tostring_free(buf)); pa_xfree(s); if (r < 0 && cmdline->fail) { - fprintf(stderr, __FILE__": failed to initialize daemon.\n"); + pa_log(__FILE__": failed to initialize daemon.\n"); if (cmdline->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); } else if (!c->modules || pa_idxset_ncontents(c->modules) == 0) { - fprintf(stderr, __FILE__": daemon startup without any loaded modules, refusing to work.\n"); + pa_log(__FILE__": daemon startup without any loaded modules, refusing to work.\n"); if (cmdline->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); } else { @@ -215,10 +224,10 @@ int main(int argc, char *argv[]) { c->disallow_module_loading = cmdline->disallow_module_loading; c->quit_after_last_client_time = cmdline->quit_after_last_client_time; - fprintf(stderr, __FILE__": mainloop entry.\n"); + pa_log(__FILE__": Daemon startup complete.\n"); if (pa_mainloop_run(mainloop, &retval) < 0) retval = 1; - fprintf(stderr, __FILE__": mainloop exit.\n"); + pa_log(__FILE__": Daemon shutdown initiated.\n"); } pa_core_free(c); @@ -229,12 +238,14 @@ int main(int argc, char *argv[]) { lt_dlexit(); + pa_log(__FILE__": Daemon terminated.\n"); + finish: if (cmdline) pa_cmdline_free(cmdline); close_pipe(daemon_pipe); - + return retval; } diff --git a/polyp/mainloop-signal.c b/polyp/mainloop-signal.c index 4746837b..d7ee5010 100644 --- a/polyp/mainloop-signal.c +++ b/polyp/mainloop-signal.c @@ -34,6 +34,7 @@ #include "mainloop-signal.h" #include "util.h" #include "xmalloc.h" +#include "log.h" struct pa_signal_event { int sig; @@ -64,12 +65,12 @@ static void callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enu if (errno == EAGAIN) return; - fprintf(stderr, "signal.c: read(): %s\n", strerror(errno)); + pa_log(__FILE__": read(): %s\n", strerror(errno)); return; } if (r != sizeof(sig)) { - fprintf(stderr, "signal.c: short read()\n"); + pa_log(__FILE__": short read()\n"); return; } @@ -85,7 +86,7 @@ int pa_signal_init(struct pa_mainloop_api *a) { assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event); if (pipe(signal_pipe) < 0) { - fprintf(stderr, "pipe() failed: %s\n", strerror(errno)); + pa_log(__FILE__": pipe() failed: %s\n", strerror(errno)); return -1; } diff --git a/polyp/mainloop.c b/polyp/mainloop.c index 83f0b1e8..22cd85c8 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -37,6 +37,7 @@ #include "util.h" #include "idxset.h" #include "xmalloc.h" +#include "log.h" struct pa_io_event { struct pa_mainloop *mainloop; @@ -502,7 +503,7 @@ int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval) { do { int t = block ? calc_next_timeout(m) : 0; - /*fprintf(stderr, "%u\n", t);*/ + /*pa_log(__FILE__": %u\n", t);*/ r = poll(m->pollfds, m->n_pollfds, t); } while (r < 0 && errno == EINTR); @@ -511,7 +512,7 @@ int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval) { if (r > 0) dispatch_pollfds(m); else if (r < 0) - fprintf(stderr, "select(): %s\n", strerror(errno)); + pa_log(__FILE__": select(): %s\n", strerror(errno)); m->running = 0; return r < 0 ? -1 : 0; diff --git a/polyp/memblockq.c b/polyp/memblockq.c index 7feb4685..0bba6581 100644 --- a/polyp/memblockq.c +++ b/polyp/memblockq.c @@ -32,6 +32,7 @@ #include "memblockq.h" #include "xmalloc.h" +#include "log.h" struct memblock_list { struct memblock_list *next, *prev; @@ -56,7 +57,7 @@ struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t b bq->current_length = 0; - /*fprintf(stderr, "memblockq requested: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", maxlength, tlength, base, prebuf, minreq);*/ + /*pa_log(__FILE__": memblockq requested: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", maxlength, tlength, base, prebuf, minreq);*/ bq->base = base; @@ -76,7 +77,7 @@ struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t b if (bq->minreq == 0) bq->minreq = 1; - fprintf(stderr, "memblockq sanitized: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", bq->maxlength, bq->tlength, bq->base, bq->prebuf, bq->minreq); + pa_log(__FILE__": memblockq sanitized: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", bq->maxlength, bq->tlength, bq->base, bq->prebuf, bq->minreq); bq->mcalign = NULL; @@ -206,7 +207,7 @@ void pa_memblockq_shorten(struct pa_memblockq *bq, size_t length) { if (bq->current_length <= length) return; - fprintf(stderr, "Warning! pa_memblockq_shorten()\n"); + pa_log(__FILE__": Warning! pa_memblockq_shorten()\n"); l = bq->current_length - length; l /= bq->base; diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index 0c9d77b8..9c75ff98 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -38,6 +38,7 @@ #include "sample-util.h" #include "alsa-util.h" #include "xmalloc.h" +#include "log.h" struct userdata { snd_pcm_t *pcm_handle; @@ -73,10 +74,10 @@ static void update_usage(struct userdata *u) { static void xrun_recovery(struct userdata *u) { assert(u); - fprintf(stderr, "*** ALSA-XRUN (playback) ***\n"); + pa_log(__FILE__": *** ALSA-XRUN (playback) ***\n"); if (snd_pcm_prepare(u->pcm_handle) < 0) - fprintf(stderr, "snd_pcm_prepare() failed\n"); + pa_log(__FILE__": snd_pcm_prepare() failed\n"); } static void do_write(struct userdata *u) { @@ -108,7 +109,7 @@ static void do_write(struct userdata *u) { continue; } - fprintf(stderr, "snd_pcm_writei() failed\n"); + pa_log(__FILE__": snd_pcm_writei() failed\n"); return; } @@ -144,7 +145,7 @@ static uint32_t sink_get_latency_cb(struct pa_sink *s) { assert(s && u && u->sink); if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { - fprintf(stderr, __FILE__": failed to get delay\n"); + pa_log(__FILE__": failed to get delay\n"); s->get_latency = NULL; return 0; } @@ -166,13 +167,13 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { size_t frame_size; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - fprintf(stderr, __FILE__": failed to parse module arguments\n"); + pa_log(__FILE__": failed to parse module arguments\n"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - fprintf(stderr, __FILE__": failed to parse sample specification\n"); + pa_log(__FILE__": failed to parse sample specification\n"); goto fail; } frame_size = pa_frame_size(&ss); @@ -180,7 +181,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { periods = 12; fragsize = 1024; if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { - fprintf(stderr, __FILE__": failed to parse buffer metrics\n"); + pa_log(__FILE__": failed to parse buffer metrics\n"); goto fail; } buffer_size = fragsize/frame_size*periods; @@ -190,12 +191,12 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { u->module = m; if (snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) { - fprintf(stderr, __FILE__": Error opening PCM device %s\n", dev); + pa_log(__FILE__": Error opening PCM device %s\n", dev); goto fail; } if (pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &buffer_size) < 0) { - fprintf(stderr, __FILE__": Failed to set hardware parameters\n"); + pa_log(__FILE__": Failed to set hardware parameters\n"); goto fail; } @@ -208,14 +209,14 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { u->sink->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); if (pa_create_io_events(u->pcm_handle, c->mainloop, &u->io_events, &u->n_io_events, io_callback, u) < 0) { - fprintf(stderr, __FILE__": failed to obtain file descriptors\n"); + pa_log(__FILE__": failed to obtain file descriptors\n"); goto fail; } u->frame_size = frame_size; u->fragment_size = buffer_size*u->frame_size/periods; - fprintf(stderr, __FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); + pa_log(__FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); u->silence.memblock = pa_memblock_new(u->silence.length = u->fragment_size, c->memblock_stat); assert(u->silence.memblock); diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index 13df9f96..520b6830 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -38,6 +38,7 @@ #include "sample-util.h" #include "alsa-util.h" #include "xmalloc.h" +#include "log.h" struct userdata { snd_pcm_t *pcm_handle; @@ -72,10 +73,10 @@ static void update_usage(struct userdata *u) { static void xrun_recovery(struct userdata *u) { assert(u); - fprintf(stderr, "*** ALSA-XRUN (capture) ***\n"); + pa_log(__FILE__": *** ALSA-XRUN (capture) ***\n"); if (snd_pcm_prepare(u->pcm_handle) < 0) - fprintf(stderr, "snd_pcm_prepare() failed\n"); + pa_log(__FILE__": snd_pcm_prepare() failed\n"); } static void do_read(struct userdata *u) { @@ -104,7 +105,7 @@ static void do_read(struct userdata *u) { continue; } - fprintf(stderr, "snd_pcm_readi() failed: %s\n", strerror(-frames)); + pa_log(__FILE__": snd_pcm_readi() failed: %s\n", strerror(-frames)); return; } @@ -149,13 +150,13 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { size_t frame_size; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - fprintf(stderr, __FILE__": failed to parse module arguments\n"); + pa_log(__FILE__": failed to parse module arguments\n"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - fprintf(stderr, __FILE__": failed to parse sample specification\n"); + pa_log(__FILE__": failed to parse sample specification\n"); goto fail; } frame_size = pa_frame_size(&ss); @@ -163,7 +164,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { periods = 12; fragsize = 1024; if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { - fprintf(stderr, __FILE__": failed to parse buffer metrics\n"); + pa_log(__FILE__": failed to parse buffer metrics\n"); goto fail; } buffer_size = fragsize/frame_size*periods; @@ -173,12 +174,12 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { u->module = m; if (snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK) < 0) { - fprintf(stderr, __FILE__": Error opening PCM device %s\n", dev); + pa_log(__FILE__": Error opening PCM device %s\n", dev); goto fail; } if (pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &buffer_size) < 0) { - fprintf(stderr, __FILE__": Failed to set hardware parameters\n"); + pa_log(__FILE__": Failed to set hardware parameters\n"); goto fail; } @@ -190,14 +191,14 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); if (pa_create_io_events(u->pcm_handle, c->mainloop, &u->io_events, &u->n_io_events, io_callback, u) < 0) { - fprintf(stderr, __FILE__": failed to obtain file descriptors\n"); + pa_log(__FILE__": failed to obtain file descriptors\n"); goto fail; } u->frame_size = frame_size; u->fragment_size = buffer_size*u->frame_size/periods; - fprintf(stderr, __FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); + pa_log(__FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); u->memchunk.memblock = NULL; u->memchunk.index = u->memchunk.length = 0; diff --git a/polyp/module-cli.c b/polyp/module-cli.c index 8897c9c6..9a08a00d 100644 --- a/polyp/module-cli.c +++ b/polyp/module-cli.c @@ -31,6 +31,7 @@ #include "iochannel.h" #include "cli.h" #include "sioman.h" +#include "log.h" static void eof_cb(struct pa_cli*c, void *userdata) { struct pa_module *m = userdata; @@ -44,12 +45,12 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { assert(c && m); if (m->argument) { - fprintf(stderr, __FILE__": module doesn't accept arguments.\n"); + pa_log(__FILE__": module doesn't accept arguments.\n"); return -1; } if (pa_stdio_acquire() < 0) { - fprintf(stderr, __FILE__": STDIN/STDUSE already in use.\n"); + pa_log(__FILE__": STDIN/STDUSE already in use.\n"); return -1; } diff --git a/polyp/module-native-protocol-fd.c b/polyp/module-native-protocol-fd.c index 213e291e..632a3d71 100644 --- a/polyp/module-native-protocol-fd.c +++ b/polyp/module-native-protocol-fd.c @@ -31,6 +31,7 @@ #include "iochannel.h" #include "modargs.h" #include "protocol-native.h" +#include "log.h" static const char* const valid_modargs[] = { "fd", @@ -46,12 +47,12 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - fprintf(stderr, __FILE__": failed to parse module arguments.\n"); + pa_log(__FILE__": failed to parse module arguments.\n"); goto finish; } if (pa_modargs_get_value_s32(ma, "fd", &fd) < 0) { - fprintf(stderr, __FILE__": invalid file descriptor.\n"); + pa_log(__FILE__": invalid file descriptor.\n"); goto finish; } diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index 8a0dd9a4..8151a13a 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -45,6 +45,7 @@ #include "util.h" #include "modargs.h" #include "xmalloc.h" +#include "log.h" struct userdata { struct pa_sink *sink; @@ -122,7 +123,7 @@ static void do_write(struct userdata *u) { update_usage(u); if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { - fprintf(stderr, "SNDCTL_DSP_GETOPTR: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETOPTR: %s\n", strerror(errno)); return; } @@ -184,7 +185,7 @@ static void do_read(struct userdata *u) { update_usage(u); if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { - fprintf(stderr, "SNDCTL_DSP_GETIPTR: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETIPTR: %s\n", strerror(errno)); return; } @@ -230,17 +231,17 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { u->core = c; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - fprintf(stderr, __FILE__": failed to parse module arguments.\n"); + pa_log(__FILE__": failed to parse module arguments.\n"); goto fail; } if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { - fprintf(stderr, __FILE__": record= and playback= expect numeric arguments.\n"); + pa_log(__FILE__": record= and playback= expect numeric arguments.\n"); goto fail; } if (!playback && !record) { - fprintf(stderr, __FILE__": neither playback nor record enabled for device.\n"); + pa_log(__FILE__": neither playback nor record enabled for device.\n"); goto fail; } @@ -249,13 +250,13 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { nfrags = 12; frag_size = 1024; if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || nfrags < 2 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0 || frag_size < 1) { - fprintf(stderr, __FILE__": failed to parse fragments arguments\n"); + pa_log(__FILE__": failed to parse fragments arguments\n"); goto fail; } u->sample_spec = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &u->sample_spec) < 0) { - fprintf(stderr, __FILE__": failed to parse sample specification\n"); + pa_log(__FILE__": failed to parse sample specification\n"); goto fail; } @@ -263,11 +264,11 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { goto fail; if (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_REALTIME) || !(caps & DSP_CAP_TRIGGER)) { - fprintf(stderr, "OSS device not mmap capable.\n"); + pa_log(__FILE__": OSS device not mmap capable.\n"); goto fail; } - fprintf(stderr, "module-oss: device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + pa_log(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); if (pa_oss_set_fragments(u->fd, nfrags, frag_size) < 0) goto fail; @@ -277,19 +278,19 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { if (mode != O_WRONLY) { if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { - fprintf(stderr, "SNDCTL_DSP_GETISPACE: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETISPACE: %s\n", strerror(errno)); goto fail; } - fprintf(stderr, "module-oss-mmap: input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + pa_log(__FILE__": input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); u->in_mmap_length = (u->in_fragment_size = info.fragsize) * (u->in_fragments = info.fragstotal); if ((u->in_mmap = mmap(NULL, u->in_mmap_length, PROT_READ, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { if (mode == O_RDWR) { - fprintf(stderr, "module-oss-mmap: mmap failed for input. Changing to O_WRONLY mode.\n"); + pa_log(__FILE__": mmap failed for input. Changing to O_WRONLY mode.\n"); mode = O_WRONLY; } else { - fprintf(stderr, "modeule-oss-mmap: mmap(): %s\n", strerror(errno)); + pa_log(__FILE__": mmap(): %s\n", strerror(errno)); goto fail; } } else { @@ -308,19 +309,19 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { if (mode != O_RDONLY) { if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { - fprintf(stderr, "SNDCTL_DSP_GETOSPACE: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETOSPACE: %s\n", strerror(errno)); goto fail; } - fprintf(stderr, "module-oss: output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + pa_log(__FILE__": output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); u->out_mmap_length = (u->out_fragment_size = info.fragsize) * (u->out_fragments = info.fragstotal); if ((u->out_mmap = mmap(NULL, u->out_mmap_length, PROT_WRITE, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { if (mode == O_RDWR) { - fprintf(stderr, "module-oss-mmap: mmap filed for output. Changing to O_RDONLY mode.\n"); + pa_log(__FILE__": mmap filed for output. Changing to O_RDONLY mode.\n"); mode = O_RDONLY; } else { - fprintf(stderr, "module-oss-mmap: mmap(): %s\n", strerror(errno)); + pa_log(__FILE__": mmap(): %s\n", strerror(errno)); goto fail; } } else { @@ -341,12 +342,12 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { zero = 0; if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero) < 0) { - fprintf(stderr, "SNDCTL_DSP_SETTRIGGER: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s\n", strerror(errno)); goto fail; } if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0) { - fprintf(stderr, "SNDCTL_DSP_SETTRIGGER: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s\n", strerror(errno)); goto fail; } diff --git a/polyp/module-oss.c b/polyp/module-oss.c index 4fd79624..53f1f994 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -44,6 +44,7 @@ #include "util.h" #include "modargs.h" #include "xmalloc.h" +#include "log.h" struct userdata { struct pa_sink *sink; @@ -105,7 +106,7 @@ static void do_write(struct userdata *u) { assert(memchunk->length); if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { - fprintf(stderr, "write() failed: %s\n", strerror(errno)); + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); return; } @@ -137,7 +138,7 @@ static void do_read(struct userdata *u) { if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); if (errno != EAGAIN) - fprintf(stderr, "read() failed: %s\n", strerror(errno)); + pa_log(__FILE__": read() failed: %s\n", strerror(errno)); return; } @@ -162,7 +163,7 @@ static uint32_t sink_get_latency_cb(struct pa_sink *s) { assert(s && u && u->sink); if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { - fprintf(stderr, "module-oss: device doesn't support SNDCTL_DSP_GETODELAY.\n"); + pa_log(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY.\n"); s->get_latency = NULL; return 0; } @@ -183,17 +184,17 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - fprintf(stderr, __FILE__": failed to parse module arguments.\n"); + pa_log(__FILE__": failed to parse module arguments.\n"); goto fail; } if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { - fprintf(stderr, __FILE__": record= and playback= expect numeric argument.\n"); + pa_log(__FILE__": record= and playback= expect numeric argument.\n"); goto fail; } if (!playback && !record) { - fprintf(stderr, __FILE__": neither playback nor record enabled for device.\n"); + pa_log(__FILE__": neither playback nor record enabled for device.\n"); goto fail; } @@ -202,20 +203,20 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { nfrags = 12; frag_size = 1024; if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || nfrags < 2 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0 || frag_size < 1) { - fprintf(stderr, __FILE__": failed to parse fragments arguments\n"); + pa_log(__FILE__": failed to parse fragments arguments\n"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - fprintf(stderr, __FILE__": failed to parse sample specification\n"); + pa_log(__FILE__": failed to parse sample specification\n"); goto fail; } if ((fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, NULL)) < 0) goto fail; - fprintf(stderr, "module-oss: device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + pa_log(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) goto fail; @@ -224,19 +225,19 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { goto fail; if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) { - fprintf(stderr, "SNDCTL_DSP_GETBLKSIZE: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETBLKSIZE: %s\n", strerror(errno)); goto fail; } assert(frag_size); in_frag_size = out_frag_size = frag_size; if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { - fprintf(stderr, "module-oss: input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + pa_log(__FILE__": input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); in_frag_size = info.fragsize; } if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) { - fprintf(stderr, "module-oss: output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + pa_log(__FILE__": output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); out_frag_size = info.fragsize; } diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c index 088ed405..5f1ced03 100644 --- a/polyp/module-pipe-sink.c +++ b/polyp/module-pipe-sink.c @@ -39,6 +39,7 @@ #include "util.h" #include "modargs.h" #include "xmalloc.h" +#include "log.h" #define DEFAULT_FIFO_NAME "/tmp/musicfifo" #define DEFAULT_SINK_NAME "fifo_output" @@ -83,7 +84,7 @@ static void do_write(struct userdata *u) { assert(u->memchunk.memblock && u->memchunk.length); if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { - fprintf(stderr, "write() failed: %s\n", strerror(errno)); + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); return; } @@ -126,32 +127,32 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - fprintf(stderr, __FILE__": failed to parse module arguments\n"); + pa_log(__FILE__": failed to parse module arguments\n"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - fprintf(stderr, __FILE__": invalid sample format specification\n"); + pa_log(__FILE__": invalid sample format specification\n"); goto fail; } mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777); if ((fd = open(p, O_RDWR)) < 0) { - fprintf(stderr, __FILE__": open('%s'): %s\n", p, strerror(errno)); + pa_log(__FILE__": open('%s'): %s\n", p, strerror(errno)); goto fail; } pa_fd_set_cloexec(fd, 1); if (fstat(fd, &st) < 0) { - fprintf(stderr, __FILE__": fstat('%s'): %s\n", p, strerror(errno)); + pa_log(__FILE__": fstat('%s'): %s\n", p, strerror(errno)); goto fail; } if (!S_ISFIFO(st.st_mode)) { - fprintf(stderr, __FILE__": '%s' is not a FIFO.\n", p); + pa_log(__FILE__": '%s' is not a FIFO.\n", p); goto fail; } @@ -161,7 +162,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { u->core = c; if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { - fprintf(stderr, __FILE__": failed to create sink.\n"); + pa_log(__FILE__": failed to create sink.\n"); goto fail; } u->sink->notify = notify_cb; diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index 4d86c28e..686e2129 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -35,6 +35,7 @@ #include "socket-util.h" #include "util.h" #include "modargs.h" +#include "log.h" #if defined(USE_PROTOCOL_SIMPLE) #include "protocol-simple.h" @@ -87,12 +88,12 @@ static struct pa_socket_server *create_socket_server(struct pa_core *c, struct p uint32_t port = IPV4_PORT; if (pa_modargs_get_value_boolean(ma, "loopback", &loopback) < 0) { - fprintf(stderr, "loopback= expects a numerical argument.\n"); + pa_log(__FILE__": loopback= expects a numerical argument.\n"); return NULL; } if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) { - fprintf(stderr, "port= expects a numerical argument between 1 and 65535.\n"); + pa_log(__FILE__": port= expects a numerical argument between 1 and 65535.\n"); return NULL; } @@ -106,17 +107,17 @@ static struct pa_socket_server *create_socket_server(struct pa_core *c, struct p assert(p); if (pa_unix_socket_make_secure_dir(p) < 0) { - fprintf(stderr, "Failed to create secure socket directory.\n"); + pa_log(__FILE__": Failed to create secure socket directory.\n"); return NULL; } if ((r = pa_unix_socket_remove_stale(p)) < 0) { - fprintf(stderr, "Failed to remove stale UNIX socket '%s': %s\n", p, strerror(errno)); + pa_log(__FILE__": Failed to remove stale UNIX socket '%s': %s\n", p, strerror(errno)); return NULL; } if (r) - fprintf(stderr, "Removed stale UNIX socket '%s'.", p); + pa_log(__FILE__": Removed stale UNIX socket '%s'.", p); if (!(s = pa_socket_server_new_unix(c->mainloop, p))) return NULL; @@ -132,7 +133,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - fprintf(stderr, "Failed to parse module arguments\n"); + pa_log(__FILE__": Failed to parse module arguments\n"); goto finish; } diff --git a/polyp/module-sine.c b/polyp/module-sine.c index 364cc64c..868f63c6 100644 --- a/polyp/module-sine.c +++ b/polyp/module-sine.c @@ -32,6 +32,7 @@ #include "modargs.h" #include "xmalloc.h" #include "namereg.h" +#include "log.h" struct userdata { struct pa_core *core; @@ -98,7 +99,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { char t[256]; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - fprintf(stderr, __FILE__": Failed to parse module arguments\n"); + pa_log(__FILE__": Failed to parse module arguments\n"); goto fail; } @@ -110,7 +111,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { sink_name = pa_modargs_get_value(ma, "sink", NULL); if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) { - fprintf(stderr, __FILE__": No such sink\n"); + pa_log(__FILE__": No such sink.\n"); goto fail; } @@ -120,7 +121,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { frequency = 440; if (pa_modargs_get_value_u32(ma, "frequency", &frequency) < 0 || frequency < 1 || frequency > ss.rate/2) { - fprintf(stderr, __FILE__": Invalid frequency specification\n"); + pa_log(__FILE__": Invalid frequency specification\n"); goto fail; } diff --git a/polyp/module-x11-bell.c b/polyp/module-x11-bell.c index ae889b22..d8ec978b 100644 --- a/polyp/module-x11-bell.c +++ b/polyp/module-x11-bell.c @@ -37,6 +37,7 @@ #include "modargs.h" #include "xmalloc.h" #include "namereg.h" +#include "log.h" struct x11_source { struct pa_io_event *io_event; @@ -65,7 +66,7 @@ static int ring_bell(struct userdata *u, int percent) { assert(u); if (!(s = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) { - fprintf(stderr, __FILE__": Invalid sink\n"); + pa_log(__FILE__": Invalid sink\n"); return -1; } @@ -88,7 +89,7 @@ static void io_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, bne = ((XkbBellNotifyEvent*) &e); if (ring_bell(u, bne->percent) < 0) { - fprintf(stderr, __FILE__": Ringing bell failed, reverting to X11 device bell.\n"); + pa_log(__FILE__": Ringing bell failed, reverting to X11 device bell.\n"); XkbForceDeviceBell(u->display, bne->device, bne->bell_class, bne->bell_id, bne->percent); } } @@ -112,7 +113,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - fprintf(stderr, __FILE__": failed to parse module arguments\n"); + pa_log(__FILE__": failed to parse module arguments\n"); goto fail; } @@ -124,7 +125,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); if (!(u->display = XOpenDisplay(pa_modargs_get_value(ma, "display", NULL)))) { - fprintf(stderr, __FILE__": XOpenDisplay() failed\n"); + pa_log(__FILE__": XOpenDisplay() failed\n"); goto fail; } @@ -134,7 +135,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { minor = XkbMinorVersion; if (!XkbLibraryVersion(&major, &minor)) { - fprintf(stderr, __FILE__": XkbLibraryVersion() failed\n"); + pa_log(__FILE__": XkbLibraryVersion() failed\n"); goto fail; } @@ -142,7 +143,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { minor = XkbMinorVersion; if (!XkbQueryExtension(u->display, NULL, &u->xkb_event_base, NULL, &major, &minor)) { - fprintf(stderr, __FILE__": XkbQueryExtension() failed\n"); + pa_log(__FILE__": XkbQueryExtension() failed\n"); goto fail; } diff --git a/polyp/module.c b/polyp/module.c index a06b2754..6eec499b 100644 --- a/polyp/module.c +++ b/polyp/module.c @@ -33,6 +33,7 @@ #include "module.h" #include "xmalloc.h" #include "subscribe.h" +#include "log.h" #define UNLOAD_POLL_TIME 10 @@ -56,6 +57,8 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char if (c->disallow_module_loading) goto fail; + + pa_log(__FILE__": Trying to load \"%s\" with argument \"%s\".\n", name, argument); m = pa_xmalloc(sizeof(struct pa_module)); @@ -95,13 +98,16 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char r = pa_idxset_put(c->modules, m, &m->index); assert(r >= 0 && m->index != PA_IDXSET_INVALID); - fprintf(stderr, "module: loaded %u \"%s\" with argument \"%s\".\n", m->index, m->name, m->argument); + pa_log(__FILE__": Loaded \"%s\" (index: #%u) with argument \"%s\".\n", m->name, m->index, m->argument); pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_NEW, m->index); return m; fail: + + pa_log(__FILE__": Failed to load \"%s\" with argument \"%s\".\n", name, argument); + if (m) { pa_xfree(m->argument); pa_xfree(m->name); @@ -125,7 +131,7 @@ static void pa_module_free(struct pa_module *m) { lt_dlclose(m->dl); - fprintf(stderr, "module: unloaded %u \"%s\".\n", m->index, m->name); + pa_log(__FILE__": Unloaded \"%s\" (index: #%u).\n", m->name, m->index); pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_REMOVE, m->index); diff --git a/polyp/oss-util.c b/polyp/oss-util.c index b28c3dc9..613cda47 100644 --- a/polyp/oss-util.c +++ b/polyp/oss-util.c @@ -36,6 +36,7 @@ #include "oss-util.h" #include "util.h" +#include "log.h" int pa_oss_open(const char *device, int *mode, int* pcaps) { int fd = -1; @@ -49,7 +50,7 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { tcaps = pcaps ? pcaps : &dcaps; if (ioctl(fd, SNDCTL_DSP_GETCAPS, tcaps) < 0) { - fprintf(stderr, __FILE__": SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); goto fail; } @@ -61,20 +62,20 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { if ((fd = open(device, (*mode = O_WRONLY)|O_NDELAY)) < 0) { if ((fd = open(device, (*mode = O_RDONLY)|O_NDELAY)) < 0) { - fprintf(stderr, __FILE__": open('%s'): %s\n", device, strerror(errno)); + pa_log(__FILE__": open('%s'): %s\n", device, strerror(errno)); goto fail; } } } else { if ((fd = open(device, *mode|O_NDELAY)) < 0) { - fprintf(stderr, __FILE__": open('%s'): %s\n", device, strerror(errno)); + pa_log(__FILE__": open('%s'): %s\n", device, strerror(errno)); goto fail; } } if (pcaps) { if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { - fprintf(stderr, "SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); goto fail; } } @@ -112,7 +113,7 @@ int pa_oss_auto_format(int fd, struct pa_sample_spec *ss) { if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != f) { format = AFMT_U8; if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_U8) { - fprintf(stderr, "SNDCTL_DSP_SETFMT: %s\n", format != AFMT_U8 ? "No supported sample format" : strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_SETFMT: %s\n", format != AFMT_U8 ? "No supported sample format" : strerror(errno)); return -1; } else ss->format = PA_SAMPLE_U8; @@ -124,7 +125,7 @@ int pa_oss_auto_format(int fd, struct pa_sample_spec *ss) { channels = ss->channels; if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) { - fprintf(stderr, "SNDCTL_DSP_CHANNELS: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_CHANNELS: %s\n", strerror(errno)); return -1; } assert(channels); @@ -132,7 +133,7 @@ int pa_oss_auto_format(int fd, struct pa_sample_spec *ss) { speed = ss->rate; if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) { - fprintf(stderr, "SNDCTL_DSP_SPEED: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_SPEED: %s\n", strerror(errno)); return -1; } assert(speed); @@ -158,7 +159,7 @@ int pa_oss_set_fragments(int fd, int nfrags, int frag_size) { arg = ((int) nfrags << 16) | simple_log2(frag_size); if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &arg) < 0) { - fprintf(stderr, "SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno)); return -1; } diff --git a/polyp/pdispatch.c b/polyp/pdispatch.c index 22f5da09..23bdf68b 100644 --- a/polyp/pdispatch.c +++ b/polyp/pdispatch.c @@ -31,6 +31,7 @@ #include "native-common.h" #include "xmalloc.h" #include "llist.h" +#include "log.h" /*#define DEBUG_OPCODES*/ @@ -173,7 +174,7 @@ int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *use goto finish; #ifdef DEBUG_OPCODES - fprintf(stderr, __FILE__": Recieved opcode <%s>\n", command_names[command]); + pa_log(__FILE__": Recieved opcode <%s>\n", command_names[command]); #endif if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) { @@ -191,7 +192,7 @@ int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *use c->proc(pd, command, tag, ts, userdata); } else { - fprintf(stderr, "Recieved unsupported command %u\n", command); + pa_log(__FILE__": Recieved unsupported command %u\n", command); goto finish; } diff --git a/polyp/polypaudio.pa b/polyp/polypaudio.pa index 715e23b6..a31712f5 100755 --- a/polyp/polypaudio.pa +++ b/polyp/polypaudio.pa @@ -40,7 +40,7 @@ autoload_source_add input module-alsa-source source_name=input #load module-simple-protocol-tcp load module-native-protocol-unix #load module-cli-protocol-unix -load module-esound-protocol-unix +#load module-esound-protocol-unix # Load the CLI module #load module-cli diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index fb6eadf4..94df7ec0 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -46,6 +46,7 @@ #include "authkey.h" #include "util.h" #include "xmalloc.h" +#include "log.h" static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_REQUEST] = { pa_command_request }, @@ -190,7 +191,7 @@ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *pack pa_context_ref(c); if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - fprintf(stderr, "polyp.c: invalid packet.\n"); + pa_log(__FILE__": invalid packet.\n"); pa_context_fail(c, PA_ERROR_PROTOCOL); } @@ -580,13 +581,13 @@ int pa_context_connect_spawn(struct pa_context *c, void (*atfork)(void)) { return pa_context_connect(c, NULL); if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { - fprintf(stderr, __FILE__": socketpair() failed: %s\n", strerror(errno)); + pa_log(__FILE__": socketpair() failed: %s\n", strerror(errno)); pa_context_fail(c, PA_ERROR_INTERNAL); goto fail; } if ((pid = fork()) < 0) { - fprintf(stderr, __FILE__": fork() failed: %s\n", strerror(errno)); + pa_log(__FILE__": fork() failed: %s\n", strerror(errno)); pa_context_fail(c, PA_ERROR_INTERNAL); goto fail; } else if (!pid) { @@ -603,14 +604,14 @@ int pa_context_connect_spawn(struct pa_context *c, void (*atfork)(void)) { p = POLYPAUDIO_BINARY; snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]); - execl(p, p, "-r", "-D", t, NULL); + execl(p, p, "-r", "-D", "-lsyslog", "-X 5", t, NULL); exit(1); } /* Parent */ if (waitpid(pid, &status, 0) < 0) { - fprintf(stderr, __FILE__": waitpid() failed: %s\n", strerror(errno)); + pa_log(__FILE__": waitpid() failed: %s\n", strerror(errno)); pa_context_fail(c, PA_ERROR_INTERNAL); goto fail; } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c index ccd39c2a..8caae87e 100644 --- a/polyp/polyplib-simple.c +++ b/polyp/polyplib-simple.c @@ -33,6 +33,7 @@ #include "mainloop.h" #include "native-common.h" #include "xmalloc.h" +#include "log.h" struct pa_simple { struct pa_mainloop *mainloop; @@ -204,7 +205,7 @@ static void read_callback(struct pa_stream *s, const void*data, size_t length, v assert(s && data && length && p); if (p->read_data) { - fprintf(stderr, __FILE__": Buffer overflow, dropping incoming memory blocks.\n"); + pa_log(__FILE__": Buffer overflow, dropping incoming memory blocks.\n"); pa_xfree(p->read_data); } diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index d6e2bf6b..3f87d4d0 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -45,6 +45,7 @@ #include "debug.h" #include "namereg.h" #include "xmalloc.h" +#include "log.h" #define DEFAULT_COOKIE_FILE ".esd_auth" @@ -238,7 +239,7 @@ static int esd_proto_connect(struct connection *c, esd_proto_t request, const vo if (!c->authorized) { if (memcmp(data, c->protocol->esd_key, ESD_KEY_LEN) != 0) { - fprintf(stderr, __FILE__": kicked client with invalid authorization key.\n"); + pa_log(__FILE__": kicked client with invalid authorization key.\n"); return -1; } @@ -251,7 +252,7 @@ static int esd_proto_connect(struct connection *c, esd_proto_t request, const vo else if (ekey == ESD_SWAP_ENDIAN_KEY) c->swap_byte_order = 1; else { - fprintf(stderr, __FILE__": client sent invalid endian key\n"); + pa_log(__FILE__": client sent invalid endian key\n"); return -1; } @@ -279,7 +280,7 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons return -1; if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { - fprintf(stderr, __FILE__": No output sink\n"); + pa_log(__FILE__": No output sink\n"); return -1; } @@ -662,7 +663,7 @@ static int do_read(struct connection *c) { assert(c->read_data_length < sizeof(c->request)); if ((r = pa_iochannel_read(c->io, ((uint8_t*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { - fprintf(stderr, "protocol-esound.c: read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + pa_log(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } @@ -673,14 +674,14 @@ static int do_read(struct connection *c) { c->request = swap_endian_32(c->request); if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) { - fprintf(stderr, "protocol-esound.c: recieved invalid request.\n"); + pa_log(__FILE__": recieved invalid request.\n"); return -1; } handler = proto_map+c->request; if (!handler->proc) { - fprintf(stderr, "protocol-sound.c: recieved unimplemented request.\n"); + pa_log(__FILE__": recieved unimplemented request.\n"); return -1; } @@ -709,7 +710,7 @@ static int do_read(struct connection *c) { assert(c->read_data && c->read_data_length < handler->data_length); if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { - fprintf(stderr, "protocol-esound.c: read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + pa_log(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } @@ -729,7 +730,7 @@ static int do_read(struct connection *c) { assert(c->scache_memchunk.memblock && c->scache_name && c->scache_memchunk.index < c->scache_memchunk.length); if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache_memchunk.memblock->data+c->scache_memchunk.index, c->scache_memchunk.length-c->scache_memchunk.index)) <= 0) { - fprintf(stderr, __FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + pa_log(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } @@ -784,7 +785,7 @@ static int do_read(struct connection *c) { } if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { - fprintf(stderr, __FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + pa_log(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } @@ -812,7 +813,7 @@ static int do_write(struct connection *c) { assert(c->write_data_index < c->write_data_length); if ((r = pa_iochannel_write(c->io, (uint8_t*) c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { - fprintf(stderr, __FILE__": write() failed: %s\n", strerror(errno)); + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); return -1; } @@ -831,7 +832,7 @@ static int do_write(struct connection *c) { if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { pa_memblock_unref(chunk.memblock); - fprintf(stderr, __FILE__": write(): %s\n", strerror(errno)); + pa_log(__FILE__": write(): %s\n", strerror(errno)); return -1; } diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 2572810f..4c99d5fe 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -44,6 +44,7 @@ #include "xmalloc.h" #include "util.h" #include "subscribe.h" +#include "log.h" struct connection; struct pa_protocol_native; @@ -357,7 +358,7 @@ static void request_bytes(struct playback_stream *s) { pa_tagstruct_putu32(t, l); pa_pstream_send_tagstruct(s->connection->pstream, t); - /*fprintf(stderr, "Requesting %u bytes\n", l);*/ + /*pa_log(__FILE__": Requesting %u bytes\n", l);*/ } static void send_memblock(struct connection *c) { @@ -421,7 +422,7 @@ static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk assert(i && i->userdata && chunk); s = i->userdata; - /*fprintf(stderr, "%3.0f \r", (double) pa_memblockq_get_length(s->memblockq)/pa_memblockq_get_tlength(s->memblockq)*100);*/ + /*pa_log(__FILE__": %3.0f \r", (double) pa_memblockq_get_length(s->memblockq)/pa_memblockq_get_tlength(s->memblockq)*100);*/ if (pa_memblockq_peek(s->memblockq, chunk) < 0) return -1; @@ -442,7 +443,7 @@ static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk s->drain_request = 0; } - /*fprintf(stderr, "after_drop: %u\n", pa_memblockq_get_length(s->memblockq));*/ + /*pa_log(__FILE__": after_drop: %u\n", pa_memblockq_get_length(s->memblockq));*/ } static void sink_input_kill_cb(struct pa_sink_input *i) { @@ -456,7 +457,7 @@ static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { assert(i && i->userdata); s = i->userdata; - /*fprintf(stderr, "get_latency: %u\n", pa_memblockq_get_length(s->memblockq));*/ + /*pa_log(__FILE__": get_latency: %u\n", pa_memblockq_get_length(s->memblockq));*/ return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec); } @@ -482,7 +483,7 @@ static void source_output_kill_cb(struct pa_source_output *o) { /*** pdispatch callbacks ***/ static void protocol_error(struct connection *c) { - fprintf(stderr, __FILE__": protocol error, kicking client\n"); + pa_log(__FILE__": protocol error, kicking client\n"); connection_free(c); } @@ -671,7 +672,7 @@ static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag } if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) != 0) { - fprintf(stderr, "protocol-native.c: Denied access to client with invalid authorization key.\n"); + pa_log(__FILE__": Denied access to client with invalid authorization key.\n"); pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); return; } @@ -1364,7 +1365,7 @@ static void command_flush_or_trigger_playback_stream(struct pa_pdispatch *pd, ui else { assert(command == PA_COMMAND_FLUSH_PLAYBACK_STREAM); pa_memblockq_flush(s->memblockq); - /*fprintf(stderr, "flush: %u\n", pa_memblockq_get_length(s->memblockq));*/ + /*pa_log(__FILE__": flush: %u\n", pa_memblockq_get_length(s->memblockq));*/ } pa_sink_notify(s->sink_input->sink); @@ -1379,7 +1380,7 @@ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *pack assert(p && packet && packet->data && c); if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - fprintf(stderr, "protocol-native: invalid packet.\n"); + pa_log(__FILE__": invalid packet.\n"); connection_free(c); } } @@ -1390,7 +1391,7 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, ui assert(p && chunk && userdata); if (!(stream = pa_idxset_get_by_index(c->output_streams, channel))) { - fprintf(stderr, "protocol-native: client sent block for invalid stream.\n"); + pa_log(__FILE__": client sent block for invalid stream.\n"); connection_free(c); return; } @@ -1404,10 +1405,10 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, ui pa_memblockq_push_align(p->memblockq, chunk, delta); assert(p->sink_input); - /*fprintf(stderr, "after_recv: %u\n", pa_memblockq_get_length(p->memblockq));*/ + /*pa_log(__FILE__": after_recv: %u\n", pa_memblockq_get_length(p->memblockq));*/ pa_sink_notify(p->sink_input->sink); - /*fprintf(stderr, "Recieved %u bytes.\n", chunk->length);*/ + /*pa_log(__FILE__": Recieved %u bytes.\n", chunk->length);*/ } else { struct upload_stream *u = (struct upload_stream*) stream; @@ -1445,7 +1446,7 @@ static void pstream_die_callback(struct pa_pstream *p, void *userdata) { assert(p && c); connection_free(c); -/* fprintf(stderr, "protocol-native: connection died.\n");*/ +/* pa_log(__FILE__": connection died.\n");*/ } @@ -1509,7 +1510,7 @@ static struct pa_protocol_native* protocol_new_internal(struct pa_core *c, struc assert(c && ma); if (pa_modargs_get_value_boolean(ma, "public", &public) < 0) { - fprintf(stderr, __FILE__": public= expects numeric argument.\n"); + pa_log(__FILE__": public= expects numeric argument.\n"); return NULL; } diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index 3ccb3068..f6240462 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -37,6 +37,7 @@ #include "sample-util.h" #include "namereg.h" #include "xmalloc.h" +#include "log.h" struct connection { struct pa_protocol_simple *protocol; @@ -121,7 +122,7 @@ static int do_read(struct connection *c) { } if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { - fprintf(stderr, __FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + pa_log(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } @@ -155,7 +156,7 @@ static int do_write(struct connection *c) { if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { pa_memblock_unref(chunk.memblock); - fprintf(stderr, "write(): %s\n", strerror(errno)); + pa_log(__FILE__": write(): %s\n", strerror(errno)); return -1; } @@ -299,12 +300,12 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo size_t l; if (!(sink = pa_namereg_get(p->core, p->sink_name, PA_NAMEREG_SINK, 1))) { - fprintf(stderr, "Failed to get sink.\n"); + pa_log(__FILE__": Failed to get sink.\n"); goto fail; } if (!(c->sink_input = pa_sink_input_new(sink, c->client->name, &p->sample_spec))) { - fprintf(stderr, "Failed to create sink input.\n"); + pa_log(__FILE__": Failed to create sink input.\n"); goto fail; } @@ -329,13 +330,13 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo size_t l; if (!(source = pa_namereg_get(p->core, p->source_name, PA_NAMEREG_SOURCE, 1))) { - fprintf(stderr, "Failed to get source.\n"); + pa_log(__FILE__": Failed to get source.\n"); goto fail; } c->source_output = pa_source_output_new(source, c->client->name, &p->sample_spec); if (!c->source_output) { - fprintf(stderr, "Failed to create source output.\n"); + pa_log(__FILE__": Failed to create source output.\n"); goto fail; } c->source_output->owner = p->module; @@ -377,7 +378,7 @@ struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct p p->sample_spec = core->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &p->sample_spec) < 0) { - fprintf(stderr, "Failed to parse sample type specification.\n"); + pa_log(__FILE__": Failed to parse sample type specification.\n"); goto fail; } @@ -386,20 +387,20 @@ struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct p enable = 0; if (pa_modargs_get_value_boolean(ma, "record", &enable) < 0) { - fprintf(stderr, __FILE__": record= expects a numeric argument.\n"); + pa_log(__FILE__": record= expects a numeric argument.\n"); goto fail; } p->mode = enable ? RECORD : 0; enable = 1; if (pa_modargs_get_value_boolean(ma, "playback", &enable) < 0) { - fprintf(stderr, __FILE__": playback= expects a numeric argument.\n"); + pa_log(__FILE__": playback= expects a numeric argument.\n"); goto fail; } p->mode |= enable ? PLAYBACK : 0; if ((p->mode & (RECORD|PLAYBACK)) == 0) { - fprintf(stderr, __FILE__": neither playback nor recording enabled for protocol.\n"); + pa_log(__FILE__": neither playback nor recording enabled for protocol.\n"); goto fail; } diff --git a/polyp/pstream.c b/polyp/pstream.c index 438dccc7..1883c95d 100644 --- a/polyp/pstream.c +++ b/polyp/pstream.c @@ -31,6 +31,7 @@ #include "pstream.h" #include "queue.h" #include "xmalloc.h" +#include "log.h" enum pa_pstream_descriptor_index { PA_PSTREAM_DESCRIPTOR_LENGTH, @@ -214,7 +215,7 @@ void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet) { struct item_info *i; assert(p && packet); - /*fprintf(stderr, "push-packet %p\n", packet);*/ + /*pa_log(__FILE__": push-packet %p\n", packet);*/ i = pa_xmalloc(sizeof(struct item_info)); i->type = PA_PSTREAM_ITEM_PACKET; @@ -263,7 +264,7 @@ static void prepare_next_write_item(struct pa_pstream *p) { p->write.index = 0; if (p->write.current->type == PA_PSTREAM_ITEM_PACKET) { - /*fprintf(stderr, "pop-packet %p\n", p->write.current->packet);*/ + /*pa_log(__FILE__": pop-packet %p\n", p->write.current->packet);*/ assert(p->write.current->packet); p->write.data = p->write.current->packet->data; @@ -348,7 +349,7 @@ static void do_read(struct pa_pstream *p) { /* Frame size too large */ if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) > FRAME_SIZE_MAX) { - fprintf(stderr, "frame size too large\n"); + pa_log(__FILE__": Frame size too large\n"); goto die; } diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 95dc5577..f4f57343 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -32,6 +32,7 @@ #include "sample-util.h" #include "xmalloc.h" #include "subscribe.h" +#include "log.h" #define CONVERT_BUFFER_LENGTH 4096 @@ -43,7 +44,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con assert(s && spec); if (pa_idxset_ncontents(s->inputs) >= PA_MAX_INPUTS_PER_SINK) { - fprintf(stderr, __FILE__": Failed to create sink input: too many inputs per sink.\n"); + pa_log(__FILE__": Failed to create sink input: too many inputs per sink.\n"); return NULL; } @@ -78,7 +79,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con assert(r == 0); pa_sample_spec_snprint(st, sizeof(st), spec); - fprintf(stderr, "sink-input: created %u \"%s\" on %u with sample spec \"%s\"\n", i->index, i->name, s->index, st); + pa_log(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"\n", i->index, i->name, s->index, st); pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index); diff --git a/polyp/sink.c b/polyp/sink.c index 104248a9..9b8a6492 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -35,6 +35,7 @@ #include "sample-util.h" #include "xmalloc.h" #include "subscribe.h" +#include "log.h" #define MAX_MIX_CHANNELS 32 @@ -77,7 +78,7 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co assert(s->index != PA_IDXSET_INVALID && r >= 0); pa_sample_spec_snprint(st, sizeof(st), spec); - fprintf(stderr, "sink: created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); + pa_log(__FILE__": created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index); @@ -100,7 +101,7 @@ void pa_sink_free(struct pa_sink *s) { pa_source_free(s->monitor_source); pa_idxset_remove_by_data(s->core->sinks, s, NULL); - fprintf(stderr, "sink: freed %u \"%s\"\n", s->index, s->name); + pa_log(__FILE__": freed %u \"%s\"\n", s->index, s->name); pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); diff --git a/polyp/socket-client.c b/polyp/socket-client.c index f697cbdb..773e922c 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -37,6 +37,7 @@ #include "socket-util.h" #include "util.h" #include "xmalloc.h" +#include "log.h" struct pa_socket_client { int ref; @@ -73,17 +74,17 @@ static void do_call(struct pa_socket_client *c) { lerror = sizeof(error); if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &error, &lerror) < 0) { - fprintf(stderr, "getsockopt(): %s\n", strerror(errno)); + pa_log(__FILE__": getsockopt(): %s\n", strerror(errno)); goto finish; } if (lerror != sizeof(error)) { - fprintf(stderr, "getsocktop() returned invalid size.\n"); + pa_log(__FILE__": getsockopt() returned invalid size.\n"); goto finish; } if (error != 0) { - fprintf(stderr, "connect(): %s\n", strerror(error)); + pa_log(__FILE__": connect(): %s\n", strerror(error)); goto finish; } @@ -125,7 +126,7 @@ static int do_connect(struct pa_socket_client *c, const struct sockaddr *sa, soc if ((r = connect(c->fd, sa, len)) < 0) { if (errno != EINPROGRESS) { - /*fprintf(stderr, "connect(): %s\n", strerror(errno));*/ + /*pa_log(__FILE__": connect(): %s\n", strerror(errno));*/ return -1; } @@ -148,7 +149,7 @@ struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, ui assert(c); if ((c->fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - fprintf(stderr, "socket(): %s\n", strerror(errno)); + pa_log(__FILE__": socket(): %s\n", strerror(errno)); goto fail; } @@ -178,7 +179,7 @@ struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, co assert(c); if ((c->fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { - fprintf(stderr, "socket(): %s\n", strerror(errno)); + pa_log(__FILE__": socket(): %s\n", strerror(errno)); goto fail; } @@ -206,7 +207,7 @@ struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m assert(c); if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) { - fprintf(stderr, "socket(): %s\n", strerror(errno)); + pa_log(__FILE__": socket(): %s\n", strerror(errno)); goto fail; } diff --git a/polyp/socket-server.c b/polyp/socket-server.c index 131339ed..9f943dc0 100644 --- a/polyp/socket-server.c +++ b/polyp/socket-server.c @@ -39,6 +39,7 @@ #include "socket-util.h" #include "xmalloc.h" #include "util.h" +#include "log.h" struct pa_socket_server { int ref; @@ -62,7 +63,7 @@ static void callback(struct pa_mainloop_api *mainloop, struct pa_io_event *e, in pa_socket_server_ref(s); if ((nfd = accept(fd, NULL, NULL)) < 0) { - fprintf(stderr, "accept(): %s\n", strerror(errno)); + pa_log(__FILE__": accept(): %s\n", strerror(errno)); goto finish; } @@ -121,7 +122,7 @@ struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, co assert(m && filename); if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { - fprintf(stderr, "socket(): %s\n", strerror(errno)); + pa_log(__FILE__": socket(): %s\n", strerror(errno)); goto fail; } @@ -134,12 +135,12 @@ struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, co pa_socket_low_delay(fd); if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) { - fprintf(stderr, "bind(): %s\n", strerror(errno)); + pa_log(__FILE__": bind(): %s\n", strerror(errno)); goto fail; } if (listen(fd, 5) < 0) { - fprintf(stderr, "listen(): %s\n", strerror(errno)); + pa_log(__FILE__": listen(): %s\n", strerror(errno)); goto fail; } @@ -167,14 +168,14 @@ struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, ui assert(m && port); if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - fprintf(stderr, "socket(): %s\n", strerror(errno)); + pa_log(__FILE__": socket(): %s\n", strerror(errno)); goto fail; } pa_fd_set_cloexec(fd, 1); if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) - fprintf(stderr, "setsockopt(): %s\n", strerror(errno)); + pa_log(__FILE__": setsockopt(): %s\n", strerror(errno)); pa_socket_tcp_low_delay(fd); @@ -183,12 +184,12 @@ struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, ui sa.sin_addr.s_addr = htonl(address); if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { - fprintf(stderr, "bind(): %s\n", strerror(errno)); + pa_log(__FILE__": bind(): %s\n", strerror(errno)); goto fail; } if (listen(fd, 5) < 0) { - fprintf(stderr, "listen(): %s\n", strerror(errno)); + pa_log(__FILE__": listen(): %s\n", strerror(errno)); goto fail; } diff --git a/polyp/socket-util.c b/polyp/socket-util.c index 1f93ef88..2f082bfb 100644 --- a/polyp/socket-util.c +++ b/polyp/socket-util.c @@ -41,6 +41,7 @@ #include "socket-util.h" #include "util.h" #include "xmalloc.h" +#include "log.h" void pa_socket_peer_to_string(int fd, char *c, size_t l) { struct stat st; @@ -122,7 +123,7 @@ int pa_socket_set_rcvbuf(int fd, size_t l) { assert(fd >= 0); if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &l, sizeof(l)) < 0) { - fprintf(stderr, "SO_RCVBUF: %s\n", strerror(errno)); + pa_log(__FILE__": SO_RCVBUF: %s\n", strerror(errno)); return -1; } @@ -133,7 +134,7 @@ int pa_socket_set_sndbuf(int fd, size_t l) { assert(fd >= 0); if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &l, sizeof(l)) < 0) { - fprintf(stderr, "SO_SNDBUF: %s\n", strerror(errno)); + pa_log(__FILE__": SO_SNDBUF: %s\n", strerror(errno)); return -1; } @@ -145,7 +146,7 @@ int pa_unix_socket_is_stale(const char *fn) { int fd = -1, ret = -1; if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { - fprintf(stderr, "socket(): %s\n", strerror(errno)); + pa_log(__FILE__": socket(): %s\n", strerror(errno)); goto finish; } diff --git a/polyp/sound-file-stream.c b/polyp/sound-file-stream.c index a77b5813..c667f5ff 100644 --- a/polyp/sound-file-stream.c +++ b/polyp/sound-file-stream.c @@ -33,6 +33,7 @@ #include "sound-file-stream.h" #include "sink-input.h" #include "xmalloc.h" +#include "log.h" #define BUF_SIZE (1024*10) @@ -128,7 +129,7 @@ int pa_play_file(struct pa_sink *sink, const char *fname, pa_volume_t volume) { memset(&sfinfo, 0, sizeof(sfinfo)); if (!(u->sndfile = sf_open(fname, SFM_READ, &sfinfo))) { - fprintf(stderr, __FILE__": Failed to open file %s\n", fname); + pa_log(__FILE__": Failed to open file %s\n", fname); goto fail; } @@ -137,7 +138,7 @@ int pa_play_file(struct pa_sink *sink, const char *fname, pa_volume_t volume) { ss.channels = sfinfo.channels; if (!pa_sample_spec_valid(&ss)) { - fprintf(stderr, __FILE__": Unsupported sample format in file %s\n", fname); + pa_log(__FILE__": Unsupported sample format in file %s\n", fname); goto fail; } diff --git a/polyp/sound-file.c b/polyp/sound-file.c index 01fda78e..d1f7e0f7 100644 --- a/polyp/sound-file.c +++ b/polyp/sound-file.c @@ -30,6 +30,7 @@ #include "sound-file.h" #include "sample.h" +#include "log.h" #define MAX_FILE_SIZE (1024*1024) @@ -46,7 +47,7 @@ int pa_sound_file_load(const char *fname, struct pa_sample_spec *ss, struct pa_m chunk->index = chunk->length = 0; if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) { - fprintf(stderr, __FILE__": Failed to open file %s\n", fname); + pa_log(__FILE__": Failed to open file %s\n", fname); goto finish; } @@ -55,12 +56,12 @@ int pa_sound_file_load(const char *fname, struct pa_sample_spec *ss, struct pa_m ss->channels = sfinfo.channels; if (!pa_sample_spec_valid(ss)) { - fprintf(stderr, __FILE__": Unsupported sample format in file %s\n", fname); + pa_log(__FILE__": Unsupported sample format in file %s\n", fname); goto finish; } if ((l = pa_frame_size(ss)*sfinfo.frames) > MAX_FILE_SIZE) { - fprintf(stderr, __FILE__": File to large\n"); + pa_log(__FILE__": File to large\n"); goto finish; } @@ -70,7 +71,7 @@ int pa_sound_file_load(const char *fname, struct pa_sample_spec *ss, struct pa_m chunk->length = l; if (sf_readf_float(sf, chunk->memblock->data, sfinfo.frames) != sfinfo.frames) { - fprintf(stderr, __FILE__": Premature file end\n"); + pa_log(__FILE__": Premature file end\n"); goto finish; } diff --git a/polyp/source-output.c b/polyp/source-output.c index 9d124f07..55448b5c 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -31,6 +31,7 @@ #include "source-output.h" #include "xmalloc.h" #include "subscribe.h" +#include "log.h" struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec) { struct pa_source_output *o; @@ -39,7 +40,7 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n assert(s && spec); if (pa_idxset_ncontents(s->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { - fprintf(stderr, __FILE__": Failed to create source output: too many outputs per source.\n"); + pa_log(__FILE__": Failed to create source output: too many outputs per source.\n"); return NULL; } diff --git a/polyp/source.c b/polyp/source.c index 6ab439d6..5cdfdb55 100644 --- a/polyp/source.c +++ b/polyp/source.c @@ -33,6 +33,7 @@ #include "namereg.h" #include "xmalloc.h" #include "subscribe.h" +#include "log.h" struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec) { struct pa_source *s; @@ -63,7 +64,7 @@ struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail assert(s->index != PA_IDXSET_INVALID && r >= 0); pa_sample_spec_snprint(st, sizeof(st), spec); - fprintf(stderr, "source: created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); + pa_log(__FILE__": created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index); @@ -85,7 +86,7 @@ void pa_source_free(struct pa_source *s) { pa_idxset_remove_by_data(s->core->sources, s, NULL); - fprintf(stderr, "source: freed %u \"%s\"\n", s->index, s->name); + pa_log(__FILE__": freed %u \"%s\"\n", s->index, s->name); pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); diff --git a/polyp/strbuf.h b/polyp/strbuf.h index 8ca51624..1622d3a0 100644 --- a/polyp/strbuf.h +++ b/polyp/strbuf.h @@ -22,6 +22,8 @@ USA. ***/ +#include "gcc-printf.h" + struct pa_strbuf; struct pa_strbuf *pa_strbuf_new(void); @@ -29,7 +31,7 @@ void pa_strbuf_free(struct pa_strbuf *sb); char *pa_strbuf_tostring(struct pa_strbuf *sb); 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))); +int pa_strbuf_printf(struct pa_strbuf *sb, const char *format, ...) PA_GCC_PRINTF_ATTR(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); diff --git a/polyp/subscribe.c b/polyp/subscribe.c index 5f7651fd..d3b97de7 100644 --- a/polyp/subscribe.c +++ b/polyp/subscribe.c @@ -29,6 +29,7 @@ #include "queue.h" #include "subscribe.h" #include "xmalloc.h" +#include "log.h" struct pa_subscription { struct pa_core *core; @@ -109,44 +110,44 @@ void pa_subscription_free_all(struct pa_core *c) { /*static void dump_event(struct pa_subscription_event*e) { switch (e->type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { case PA_SUBSCRIPTION_EVENT_SINK: - fprintf(stderr, "SINK_EVENT"); + pa_log(__FILE__": SINK_EVENT"); break; case PA_SUBSCRIPTION_EVENT_SOURCE: - fprintf(stderr, "SOURCE_EVENT"); + pa_log(__FILE__": SOURCE_EVENT"); break; case PA_SUBSCRIPTION_EVENT_SINK_INPUT: - fprintf(stderr, "SINK_INPUT_EVENT"); + pa_log(__FILE__": SINK_INPUT_EVENT"); break; case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: - fprintf(stderr, "SOURCE_OUTPUT_EVENT"); + pa_log(__FILE__": SOURCE_OUTPUT_EVENT"); break; case PA_SUBSCRIPTION_EVENT_MODULE: - fprintf(stderr, "MODULE_EVENT"); + pa_log(__FILE__": MODULE_EVENT"); break; case PA_SUBSCRIPTION_EVENT_CLIENT: - fprintf(stderr, "CLIENT_EVENT"); + pa_log(__FILE__": CLIENT_EVENT"); break; default: - fprintf(stderr, "OTHER"); + pa_log(__FILE__": OTHER"); break; } switch (e->type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) { case PA_SUBSCRIPTION_EVENT_NEW: - fprintf(stderr, " NEW"); + pa_log(__FILE__": NEW"); break; case PA_SUBSCRIPTION_EVENT_CHANGE: - fprintf(stderr, " CHANGE"); + pa_log(__FILE__": CHANGE"); break; case PA_SUBSCRIPTION_EVENT_REMOVE: - fprintf(stderr, " REMOVE"); + pa_log(__FILE__": REMOVE"); break; default: - fprintf(stderr, " OTHER"); + pa_log(__FILE__": OTHER"); break; } - fprintf(stderr, " %u\n", e->index); + pa_log(__FILE__": %u\n", e->index); }*/ static void defer_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) { diff --git a/polyp/util.c b/polyp/util.c index 061d5710..408e60e9 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -42,6 +42,7 @@ #include "util.h" #include "xmalloc.h" +#include "log.h" void pa_make_nonblock_fd(int fd) { int v; @@ -121,7 +122,7 @@ void pa_check_for_sigpipe(void) { if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) { #endif if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) { - fprintf(stderr, __FILE__": sigprocmask() failed: %s\n", strerror(errno)); + pa_log(__FILE__": sigprocmask() failed: %s\n", strerror(errno)); return; } #ifdef HAVE_PTHREAD @@ -132,14 +133,14 @@ void pa_check_for_sigpipe(void) { return; if (sigaction(SIGPIPE, NULL, &sa) < 0) { - fprintf(stderr, __FILE__": sigaction() failed: %s\n", strerror(errno)); + pa_log(__FILE__": sigaction() failed: %s\n", strerror(errno)); return; } if (sa.sa_handler != SIG_DFL) return; - fprintf(stderr, "polypaudio: WARNING: SIGPIPE is not trapped. This might cause malfunction!\n"); + pa_log(__FILE__": WARNING: SIGPIPE is not trapped. This might cause malfunction!\n"); } /* The following is based on an example from the GNU libc documentation */ @@ -169,6 +170,30 @@ char *pa_sprintf_malloc(const char *format, ...) { } } +char *pa_vsprintf_malloc(const char *format, va_list ap) { + int size = 100; + char *c = NULL; + + assert(format); + + for(;;) { + int r; + va_list ap; + + c = pa_xrealloc(c, size); + r = vsnprintf(c, size, format, ap); + + if (r > -1 && r < size) + return c; + + if (r > -1) /* glibc 2.1 */ + size = r+1; + else /* glibc 2.0 */ + size *= 2; + } +} + + char *pa_get_user_name(char *s, size_t l) { struct passwd pw, *r; char buf[1024]; @@ -220,26 +245,26 @@ uint32_t pa_age(struct timeval *tv) { void pa_raise_priority(void) { if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) - fprintf(stderr, __FILE__": setpriority() failed: %s\n", strerror(errno)); + pa_log(__FILE__": setpriority() failed: %s\n", strerror(errno)); else - fprintf(stderr, __FILE__": Successfully gained nice level %i.\n", NICE_LEVEL); + pa_log(__FILE__": Successfully gained nice level %i.\n", NICE_LEVEL); #ifdef _POSIX_PRIORITY_SCHEDULING { struct sched_param sp; if (sched_getparam(0, &sp) < 0) { - fprintf(stderr, __FILE__": sched_getparam() failed: %s\n", strerror(errno)); + pa_log(__FILE__": sched_getparam() failed: %s\n", strerror(errno)); return; } sp.sched_priority = 1; if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) { - fprintf(stderr, __FILE__": sched_setscheduler() failed: %s\n", strerror(errno)); + pa_log(__FILE__": sched_setscheduler() failed: %s\n", strerror(errno)); return; } - fprintf(stderr, __FILE__": Successfully enabled SCHED_FIFO scheduling.\n"); + pa_log(__FILE__": Successfully enabled SCHED_FIFO scheduling.\n"); } #endif } diff --git a/polyp/util.h b/polyp/util.h index f8dd3f04..18f883f0 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -24,6 +24,9 @@ #include #include +#include + +#include "gcc-printf.h" void pa_make_nonblock_fd(int fd); @@ -34,7 +37,8 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size); void pa_check_for_sigpipe(void); -char *pa_sprintf_malloc(const char *format, ...) __attribute__ ((format (printf, 1, 2))); +char *pa_sprintf_malloc(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +char *pa_vsprintf_malloc(const char *format, va_list ap); char *pa_get_user_name(char *s, size_t l); char *pa_get_host_name(char *s, size_t l); -- cgit From 566e469bbe570be88a7122009e5128697d931700 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 6 Sep 2004 17:47:04 +0000 Subject: add module-pipe-source git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@180 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 + polyp/Makefile.am | 5 ++ polyp/memblockq.c | 2 +- polyp/module-pipe-sink.c | 2 +- polyp/module-pipe-source.c | 202 +++++++++++++++++++++++++++++++++++++++++++++ polyp/pacat.c | 11 +++ polyp/polypaudio.pa | 11 ++- polyp/protocol-native.c | 8 +- 8 files changed, 233 insertions(+), 11 deletions(-) create mode 100644 polyp/module-pipe-source.c diff --git a/doc/todo b/doc/todo index 8ae9e739..62debb6e 100644 --- a/doc/todo +++ b/doc/todo @@ -11,6 +11,9 @@ - more complete pactl - add sample directory - add timing parameter to write callback of stream in client API +- config file for command line arguments +- vumeter +- add FAQ ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 335fa99a..27ada2e1 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -77,6 +77,7 @@ pkglib_LTLIBRARIES=libiochannel.la \ module-cli-protocol-tcp.la \ module-cli-protocol-unix.la \ module-pipe-sink.la \ + module-pipe-source.la \ module-alsa-sink.la \ module-alsa-source.la \ module-oss.la \ @@ -269,6 +270,10 @@ module_pipe_sink_la_SOURCES = module-pipe-sink.c module_pipe_sink_la_LDFLAGS = -module -avoid-version module_pipe_sink_la_LIBADD = $(AM_LIBADD) libiochannel.la +module_pipe_source_la_SOURCES = module-pipe-source.c +module_pipe_source_la_LDFLAGS = -module -avoid-version +module_pipe_source_la_LIBADD = $(AM_LIBADD) libiochannel.la + module_alsa_sink_la_SOURCES = module-alsa-sink.c module_alsa_sink_la_LDFLAGS = -module -avoid-version module_alsa_sink_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la diff --git a/polyp/memblockq.c b/polyp/memblockq.c index 0bba6581..a79814be 100644 --- a/polyp/memblockq.c +++ b/polyp/memblockq.c @@ -207,7 +207,7 @@ void pa_memblockq_shorten(struct pa_memblockq *bq, size_t length) { if (bq->current_length <= length) return; - pa_log(__FILE__": Warning! pa_memblockq_shorten()\n"); + /*pa_log(__FILE__": Warning! pa_memblockq_shorten()\n");*/ l = bq->current_length - length; l /= bq->base; diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c index 5f1ced03..a5a7877f 100644 --- a/polyp/module-pipe-sink.c +++ b/polyp/module-pipe-sink.c @@ -41,7 +41,7 @@ #include "xmalloc.h" #include "log.h" -#define DEFAULT_FIFO_NAME "/tmp/musicfifo" +#define DEFAULT_FIFO_NAME "/tmp/music.output" #define DEFAULT_SINK_NAME "fifo_output" struct userdata { diff --git a/polyp/module-pipe-source.c b/polyp/module-pipe-source.c new file mode 100644 index 00000000..baed06a5 --- /dev/null +++ b/polyp/module-pipe-source.c @@ -0,0 +1,202 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iochannel.h" +#include "source.h" +#include "module.h" +#include "util.h" +#include "modargs.h" +#include "xmalloc.h" +#include "log.h" + +#define DEFAULT_FIFO_NAME "/tmp/music.input" +#define DEFAULT_SOURCE_NAME "fifo_input" + +struct userdata { + struct pa_core *core; + + char *filename; + + struct pa_source *source; + struct pa_iochannel *io; + struct pa_module *module; + struct pa_memchunk chunk; +}; + +static const char* const valid_modargs[] = { + "file", + "rate", + "channels", + "format", + "source_name", + NULL +}; + +static void do_read(struct userdata *u) { + ssize_t r; + struct pa_memchunk chunk; + assert(u); + + if (!pa_iochannel_is_readable(u->io)) + return; + + pa_module_set_used(u->module, pa_idxset_ncontents(u->source->outputs)); + + if (!u->chunk.memblock) { + u->chunk.memblock = pa_memblock_new(1024, u->core->memblock_stat); + u->chunk.index = chunk.length = 0; + } + + assert(u->chunk.memblock && u->chunk.memblock->length > u->chunk.index); + if ((r = pa_iochannel_read(u->io, (uint8_t*) u->chunk.memblock->data + u->chunk.index, u->chunk.memblock->length - u->chunk.index)) <= 0) { + pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + return; + } + + u->chunk.length = r; + pa_source_post(u->source, &u->chunk); + u->chunk.index += r; + + if (u->chunk.index >= u->chunk.memblock->length) { + u->chunk.index = u->chunk.length = 0; + pa_memblock_unref(u->chunk.memblock); + u->chunk.memblock = NULL; + } +} + +static void io_callback(struct pa_iochannel *io, void*userdata) { + struct userdata *u = userdata; + assert(u); + do_read(u); +} + +int pa_module_init(struct pa_core *c, struct pa_module*m) { + struct userdata *u = NULL; + struct stat st; + const char *p; + int fd = -1; + struct pa_sample_spec ss; + struct pa_modargs *ma = NULL; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": invalid sample format specification\n"); + goto fail; + } + + mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777); + + if ((fd = open(p, O_RDWR)) < 0) { + pa_log(__FILE__": open('%s'): %s\n", p, strerror(errno)); + goto fail; + } + + pa_fd_set_cloexec(fd, 1); + + if (fstat(fd, &st) < 0) { + pa_log(__FILE__": fstat('%s'): %s\n", p, strerror(errno)); + goto fail; + } + + if (!S_ISFIFO(st.st_mode)) { + pa_log(__FILE__": '%s' is not a FIFO.\n", p); + goto fail; + } + + u = pa_xmalloc0(sizeof(struct userdata)); + + u->filename = pa_xstrdup(p); + u->core = c; + + if (!(u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss))) { + pa_log(__FILE__": failed to create source.\n"); + goto fail; + } + u->source->userdata = u; + pa_source_set_owner(u->source, m); + u->source->description = pa_sprintf_malloc("Unix FIFO source '%s'", p); + assert(u->source->description); + + u->io = pa_iochannel_new(c->mainloop, fd, -1); + assert(u->io); + pa_iochannel_set_callback(u->io, io_callback, u); + + u->chunk.memblock = NULL; + u->chunk.index = u->chunk.length = 0; + + u->module = m; + m->userdata = u; + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + if (fd >= 0) + close(fd); + + pa_module_done(c, m); + + return -1; +} + +void pa_module_done(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->chunk.memblock) + pa_memblock_unref(u->chunk.memblock); + + pa_source_free(u->source); + pa_iochannel_free(u->io); + + assert(u->filename); + unlink(u->filename); + pa_xfree(u->filename); + + pa_xfree(u); +} diff --git a/polyp/pacat.c b/polyp/pacat.c index fd6e90e1..40301be8 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -313,6 +313,17 @@ int main(int argc, char *argv[]) { else if (strstr(bn, "cat") || strstr(bn, "play")) mode = PLAYBACK; + if (argc >= 2) { + if (!strcmp(argv[1], "-r")) + mode = RECORD; + else if (!strcmp(argv[1], "-p")) + mode = PLAYBACK; + else { + fprintf(stderr, "Invalid argument\n"); + goto quit; + } + } + fprintf(stderr, "Opening a %s stream.\n", mode == RECORD ? "recording" : "playback"); /* Set up a new main loop */ diff --git a/polyp/polypaudio.pa b/polyp/polypaudio.pa index a31712f5..87b4114a 100755 --- a/polyp/polypaudio.pa +++ b/polyp/polypaudio.pa @@ -32,8 +32,8 @@ #autoload_source_add input module-oss device="/dev/adsp" sink_name=output source_name=input #autoload_sink_add output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input #autoload_source_add input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -autoload_sink_add output module-alsa-sink sink_name=output -autoload_source_add input module-alsa-source source_name=input +#autoload_sink_add output module-alsa-sink sink_name=output +#autoload_source_add input module-alsa-source source_name=input # Load several protocols #load module-esound-protocol-tcp @@ -43,7 +43,7 @@ load module-native-protocol-unix #load module-esound-protocol-unix # Load the CLI module -#load module-cli +load module-cli # Make some devices default sink_default output @@ -55,5 +55,8 @@ source_default input scache_load /usr/share/sounds/KDE_Notify.wav x11-bell # Load X11 bell module -load module-x11-bell sample=x11-bell sink=output +#load module-x11-bell sample=x11-bell sink=output + +load module-pipe-source +load module-pipe-sink diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 4c99d5fe..67352b3f 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -422,8 +422,6 @@ static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk assert(i && i->userdata && chunk); s = i->userdata; - /*pa_log(__FILE__": %3.0f \r", (double) pa_memblockq_get_length(s->memblockq)/pa_memblockq_get_tlength(s->memblockq)*100);*/ - if (pa_memblockq_peek(s->memblockq, chunk) < 0) return -1; @@ -469,7 +467,7 @@ static void source_output_push_cb(struct pa_source_output *o, const struct pa_me assert(o && o->userdata && chunk); s = o->userdata; - pa_memblockq_push(s->memblockq, chunk, 0); + pa_memblockq_push_align(s->memblockq, chunk, 0); if (!pa_pstream_is_pending(s->connection->pstream)) send_memblock(s->connection); } @@ -765,9 +763,9 @@ static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t comm pa_memblockq_prebuf_disable(s->memblockq); - if (!pa_memblockq_is_readable(s->memblockq)) + if (!pa_memblockq_is_readable(s->memblockq)) { pa_pstream_send_simple_ack(c->pstream, tag); - else { + } else { s->drain_request = 1; s->drain_tag = tag; -- cgit From 3536be420cf9ec6f4f8fbe1dc60b2da0cefba86c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 6 Sep 2004 18:55:47 +0000 Subject: correct a recording bug in native protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@181 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + polyp/Makefile.am | 4 ++-- polyp/protocol-native.c | 12 +++++++----- polyp/sink.c | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/doc/todo b/doc/todo index 62debb6e..f48859e0 100644 --- a/doc/todo +++ b/doc/todo @@ -14,6 +14,7 @@ - config file for command line arguments - vumeter - add FAQ +- pa_context_connect_spawn() change function to fork+exec+waitpid-like function ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 27ada2e1..39215497 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -398,11 +398,11 @@ mainloop_test_glib12_SOURCES = $(mainloop_test_SOURCES) mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MAIN_LOOP mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12.la -cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c +cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit_test_CFLAGS = $(AM_CFLAGS) cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop.la -cpulimit_test2_SOURCES = cpulimit-test.c cpulimit.c util.c +cpulimit_test2_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit_test2_CFLAGS = $(AM_CFLAGS) -DTEST2 cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop.la diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 67352b3f..1ec1b608 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -378,12 +378,14 @@ static void send_memblock(struct connection *c) { return; if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) { - if (chunk.length > r->fragment_size) - chunk.length = r->fragment_size; + struct pa_memchunk schunk = chunk; + + if (schunk.length > r->fragment_size) + schunk.length = r->fragment_size; - pa_pstream_send_memblock(c->pstream, r->index, 0, &chunk); - pa_memblockq_drop(r->memblockq, &chunk, chunk.length); - pa_memblock_unref(chunk.memblock); + pa_pstream_send_memblock(c->pstream, r->index, 0, &schunk); + pa_memblockq_drop(r->memblockq, &chunk, schunk.length); + pa_memblock_unref(schunk.memblock); return; } diff --git a/polyp/sink.c b/polyp/sink.c index 9b8a6492..1fe38e9f 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -158,7 +158,7 @@ int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result) unsigned n; size_t l; assert(s && length && result); - + n = fill_mix_info(s, info, MAX_MIX_CHANNELS); if (n <= 0) -- cgit From 0fa499db56dc9111ddd866080606cb8b0379280e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 6 Sep 2004 21:55:09 +0000 Subject: add support for setting/getting default sink/source via native protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@182 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 4 ++-- polyp/namereg.c | 8 ++++++++ polyp/native-common.h | 6 ++---- polyp/pdispatch.c | 24 +++++++++++++++++++++--- polyp/polypaudio.pa | 10 +++++----- polyp/polyplib-context.c | 40 ++++++++++++++++++++++++++++++++++++++++ polyp/polyplib-context.h | 6 ++++++ polyp/polyplib-def.h | 4 +++- polyp/polyplib-introspect.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ polyp/polyplib-introspect.h | 2 ++ polyp/protocol-native.c | 27 +++++++++++++++++++++++++++ 11 files changed, 161 insertions(+), 15 deletions(-) diff --git a/doc/todo b/doc/todo index f48859e0..9ef5f9c4 100644 --- a/doc/todo +++ b/doc/todo @@ -12,9 +12,9 @@ - add sample directory - add timing parameter to write callback of stream in client API - config file for command line arguments -- vumeter - add FAQ -- pa_context_connect_spawn() change function to fork+exec+waitpid-like function +- pa_context_connect_spawn(): change function to fork+exec+waitpid-like function +- on delete event in paman ** later *** - xmlrpc/http diff --git a/polyp/namereg.c b/polyp/namereg.c index 72a4c648..44a9cdc6 100644 --- a/polyp/namereg.c +++ b/polyp/namereg.c @@ -35,6 +35,7 @@ #include "source.h" #include "sink.h" #include "xmalloc.h" +#include "subscribe.h" struct namereg_entry { enum pa_namereg_type type; @@ -186,6 +187,13 @@ void pa_namereg_set_default(struct pa_core*c, const char *name, enum pa_namereg_ s = type == PA_NAMEREG_SINK ? &c->default_sink_name : &c->default_source_name; assert(s); + if (!name && !*s) + return; + + if (name && *s && !strcmp(name, *s)) + return; + pa_xfree(*s); *s = pa_xstrdup(name); + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); } diff --git a/polyp/native-common.h b/polyp/native-common.h index 5250532e..c5192cec 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -66,17 +66,15 @@ enum { PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, PA_COMMAND_GET_SAMPLE_INFO, PA_COMMAND_GET_SAMPLE_INFO_LIST, - PA_COMMAND_SUBSCRIBE, PA_COMMAND_SUBSCRIBE_EVENT, - PA_COMMAND_SET_SINK_VOLUME, PA_COMMAND_SET_SINK_INPUT_VOLUME, - PA_COMMAND_CORK_PLAYBACK_STREAM, PA_COMMAND_FLUSH_PLAYBACK_STREAM, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, - + PA_COMMAND_SET_DEFAULT_SINK, + PA_COMMAND_SET_DEFAULT_SOURCE, PA_COMMAND_MAX }; diff --git a/polyp/pdispatch.c b/polyp/pdispatch.c index 23bdf68b..88f85e02 100644 --- a/polyp/pdispatch.c +++ b/polyp/pdispatch.c @@ -62,8 +62,20 @@ static const char *command_names[PA_COMMAND_MAX] = { [PA_COMMAND_PLAY_SAMPLE] = "PLAY_SAMPLE", [PA_COMMAND_REMOVE_SAMPLE] = "REMOVE_SAMPLE", [PA_COMMAND_GET_SERVER_INFO] = "GET_SERVER_INFO", - [PA_COMMAND_GET_SINK_INFO] = "GET_SET_INFO", + [PA_COMMAND_GET_SINK_INFO] = "GET_SINK_INFO", + [PA_COMMAND_GET_SINK_INFO_LIST] = "GET_SINK_INFO_LIST", + [PA_COMMAND_GET_SOURCE_INFO] = "GET_SOURCE_INFO", + [PA_COMMAND_GET_SOURCE_INFO_LIST] = "GET_SOURCE_INFO_LIST", + [PA_COMMAND_GET_MODULE_INFO] = "GET_MODULE_INFO", + [PA_COMMAND_GET_MODULE_INFO_LIST] = "GET_MODULE_INFO_LIST", + [PA_COMMAND_GET_CLIENT_INFO] = "GET_CLIENT_INFO", + [PA_COMMAND_GET_CLIENT_INFO_LIST] = "GET_CLIENT_INFO_LIST", + [PA_COMMAND_GET_SAMPLE_INFO] = "GET_SAMPLE_INFO", + [PA_COMMAND_GET_SAMPLE_INFO_LIST] = "GET_SAMPLE_INFO_LIST", [PA_COMMAND_GET_SINK_INPUT_INFO] = "GET_SINK_INPUT_INFO", + [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = "GET_SINK_INPUT_INFO_LIST", + [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = "GET_SOURCE_OUTPUT_INFO", + [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = "GET_SOURCE_OUTPUT_INFO_LIST", [PA_COMMAND_SUBSCRIBE] = "SUBSCRIBE", [PA_COMMAND_SUBSCRIBE_EVENT] = "SUBSCRIBE_EVENT", [PA_COMMAND_SET_SINK_VOLUME] = "SET_SINK_VOLUME", @@ -71,7 +83,6 @@ static const char *command_names[PA_COMMAND_MAX] = { [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = "TRIGGER_PLAYBACK_STREAM", [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = "FLUSH_PLAYBACK_STREAM", [PA_COMMAND_CORK_PLAYBACK_STREAM] = "CORK_PLAYBACK_STREAM", - }; #endif @@ -174,7 +185,14 @@ int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *use goto finish; #ifdef DEBUG_OPCODES - pa_log(__FILE__": Recieved opcode <%s>\n", command_names[command]); +{ + char t[256]; + char const *p; + if (!(p = command_names[command])) + snprintf((char*) (p = t), sizeof(t), "%u", command); + + pa_log(__FILE__": Recieved opcode <%s>\n", p); +} #endif if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) { diff --git a/polyp/polypaudio.pa b/polyp/polypaudio.pa index 87b4114a..9e18abfd 100755 --- a/polyp/polypaudio.pa +++ b/polyp/polypaudio.pa @@ -22,7 +22,7 @@ #load module-alsa-sink #load module-alsa-source device=plughw:1,0 -#load module-oss device="/dev/dsp" sink_name=output source_name=input +load module-oss device="/dev/dsp" sink_name=output source_name=input record=0 #load module-oss-mmap device="/dev/dsp" sink_name=output source_name=input #load module-pipe-sink @@ -46,8 +46,8 @@ load module-native-protocol-unix load module-cli # Make some devices default -sink_default output -source_default input +#isink_default output +#source_default input .nofail @@ -57,6 +57,6 @@ scache_load /usr/share/sounds/KDE_Notify.wav x11-bell # Load X11 bell module #load module-x11-bell sample=x11-bell sink=output -load module-pipe-source -load module-pipe-sink +#load module-pipe-source +#load module-pipe-sink diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 94df7ec0..a810bd98 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -633,3 +633,43 @@ fail: return -1; } + +struct pa_operation* pa_context_set_default_sink(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + struct pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_DEFAULT_SINK); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +struct pa_operation* pa_context_set_default_source(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + struct pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_DEFAULT_SOURCE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h index c7d20703..65befbb3 100644 --- a/polyp/polyplib-context.h +++ b/polyp/polyplib-context.h @@ -98,6 +98,12 @@ struct pa_operation* pa_context_drain(struct pa_context *c, void (*cb) (struct p * would never complete. */ void pa_context_exit_daemon(struct pa_context *c); +/** Set the name of the default sink. \since 0.4 */ +struct pa_operation* pa_context_set_default_sink(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata); + +/** Set the name of the default source. \since 0.4 */ +struct pa_operation* pa_context_set_default_source(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata); + PA_C_DECL_END #endif diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index f0ecc5c4..067ebf89 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -106,7 +106,8 @@ enum pa_subscription_mask { PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8, /**< Source output events */ PA_SUBSCRIPTION_MASK_MODULE = 16, /**< Module events */ PA_SUBSCRIPTION_MASK_CLIENT = 32, /**< Client events */ - PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64 /**< Sample cache events */ + PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, /**< Sample cache events */ + PA_SUBSCRIPTION_MASK_SERVER = 128 /**< Other global server changes. \since 0.4 */ }; /** Subscription event types, as used by pa_context_subscribe() */ @@ -118,6 +119,7 @@ enum pa_subscription_event_type { PA_SUBSCRIPTION_EVENT_MODULE = 4, /**< Event type: Module */ PA_SUBSCRIPTION_EVENT_CLIENT = 5, /**< Event type: Client */ PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, /**< Event type: Sample cache item */ + PA_SUBSCRIPTION_EVENT_SERVER = 7, /**< Event type: Global server change, only occuring with PA_SUBSCRIPTION_EVENT_CHANGE. \since 0.4 */ PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 7, /**< A mask to extract the event type from an event value */ PA_SUBSCRIPTION_EVENT_NEW = 0, /**< A new object was created */ diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index b31a40c7..2baeb540 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -83,7 +83,10 @@ static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t c pa_tagstruct_gets(t, &i.user_name) < 0 || pa_tagstruct_gets(t, &i.host_name) < 0 || pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_gets(t, &i.default_sink_name) < 0 || + pa_tagstruct_gets(t, &i.default_source_name) < 0 || !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } @@ -174,6 +177,27 @@ struct pa_operation* pa_context_get_sink_info_by_index(struct pa_context *c, uin return pa_operation_ref(o); } +struct pa_operation* pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + struct pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, o); + + return pa_operation_ref(o); +} + /*** Source info ***/ static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { @@ -244,6 +268,27 @@ struct pa_operation* pa_context_get_source_info_by_index(struct pa_context *c, u return pa_operation_ref(o); } +struct pa_operation* pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + struct pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, o); + + return pa_operation_ref(o); +} + /*** Client info ***/ static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index 0a14fad0..3da71b80 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -96,6 +96,8 @@ struct pa_server_info { const char *server_version; /**< Version string of the daemon */ const char *server_name; /**< Server package name (usually "polypaudio") */ struct pa_sample_spec sample_spec; /**< Default sample specification */ + const char *default_sink_name; /**< Name of default sink. \since 0.4 */ + const char *default_source_name; /**< Name of default sink. \since 0.4*/ }; /** Get some information about the server */ diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 1ec1b608..3d6114cf 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -138,6 +138,7 @@ static void command_subscribe(struct pa_pdispatch *pd, uint32_t command, uint32_ static void command_set_volume(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_cork_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_flush_or_trigger_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_set_default_sink_or_source(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = { NULL }, @@ -182,6 +183,8 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_CORK_PLAYBACK_STREAM] = { command_cork_playback_stream }, [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = { command_flush_or_trigger_playback_stream }, [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = { command_flush_or_trigger_playback_stream }, + [PA_COMMAND_SET_DEFAULT_SINK] = { command_set_default_sink_or_source }, + [PA_COMMAND_SET_DEFAULT_SOURCE] = { command_set_default_sink_or_source }, }; /* structure management */ @@ -1221,6 +1224,8 @@ static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, u pa_tagstruct_puts(reply, pa_get_user_name(txt, sizeof(txt))); pa_tagstruct_puts(reply, pa_get_host_name(txt, sizeof(txt))); pa_tagstruct_put_sample_spec(reply, &c->protocol->core->default_sample_spec); + pa_tagstruct_puts(reply, c->protocol->core->default_sink_name ? c->protocol->core->default_sink_name : ""); + pa_tagstruct_puts(reply, c->protocol->core->default_source_name ? c->protocol->core->default_source_name : ""); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -1373,6 +1378,28 @@ static void command_flush_or_trigger_playback_stream(struct pa_pdispatch *pd, ui request_bytes(s); } +static void command_set_default_sink_or_source(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t index; + const char *s; + assert(c && t); + + if (pa_tagstruct_getu32(t, &index) < 0 || + pa_tagstruct_gets(t, &s) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + pa_namereg_set_default(c->protocol->core, s, command == PA_COMMAND_SET_DEFAULT_SOURCE ? PA_NAMEREG_SOURCE : PA_NAMEREG_SINK); + pa_pstream_send_simple_ack(c->pstream, tag); +} + /*** pstream callbacks ***/ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { -- cgit From 93c8fe6577b59176ed6a54a1ae98f8749f122dc8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Sep 2004 14:58:42 +0000 Subject: change the way the default sink/source is selected git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@183 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 ++- polyp/cli-command.c | 24 ++++++++++++++++- polyp/core.c | 1 + polyp/core.h | 1 - polyp/namereg.c | 69 ++++++++++++++++++++++++++++++++----------------- polyp/namereg.h | 5 ++++ polyp/polypaudio.pa | 2 +- polyp/polyplib-stream.c | 2 +- polyp/protocol-native.c | 8 ++++-- 9 files changed, 84 insertions(+), 31 deletions(-) diff --git a/doc/todo b/doc/todo index 9ef5f9c4..f8a5ce86 100644 --- a/doc/todo +++ b/doc/todo @@ -10,11 +10,12 @@ autoload management - more complete pactl - add sample directory -- add timing parameter to write callback of stream in client API - config file for command line arguments + - add FAQ - pa_context_connect_spawn(): change function to fork+exec+waitpid-like function - on delete event in paman +- add feature to dump config file ** later *** - xmlrpc/http diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 1d2788fa..4c4f566b 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -210,8 +210,30 @@ static int pa_cli_command_source_outputs(struct pa_core *c, struct pa_tokenizer } static int pa_cli_command_stat(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + char s[256]; assert(c && t); - pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %u bytes.\nMemory blocks allocated during the whole lifetime: %u, size: %u bytes.\n", c->memblock_stat->total, c->memblock_stat->total_size, c->memblock_stat->allocated, c->memblock_stat->allocated_size); + + pa_bytes_snprint(s, sizeof(s), c->memblock_stat->total_size); + pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n", + c->memblock_stat->total, + s); + + pa_bytes_snprint(s, sizeof(s), c->memblock_stat->allocated_size); + pa_strbuf_printf(buf, "Memory blocks allocated during the whole lifetime: %u, size: %s.\n", + c->memblock_stat->allocated, + s); + + pa_bytes_snprint(s, sizeof(s), pa_scache_total_size(c)); + pa_strbuf_printf(buf, "Total sample cache size: %s.\n", s); + + pa_sample_spec_snprint(s, sizeof(s), &c->default_sample_spec); + pa_strbuf_printf(buf, "Default sample spec: %s\n", s); + + pa_strbuf_printf(buf, "Default sink name: %s\n" + "Default source name: %s\n", + pa_namereg_get_default_sink_name(c), + pa_namereg_get_default_source_name(c)); + return 0; } diff --git a/polyp/core.c b/polyp/core.c index 4362f0cb..5d79a365 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -139,3 +139,4 @@ void pa_core_check_quit(struct pa_core *c) { c->quit_event = NULL; } } + diff --git a/polyp/core.h b/polyp/core.h index ca37507c..ddba6a83 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -55,7 +55,6 @@ struct pa_core { struct pa_core* pa_core_new(struct pa_mainloop_api *m); void pa_core_free(struct pa_core*c); - void pa_core_check_quit(struct pa_core *c); #endif diff --git a/polyp/namereg.c b/polyp/namereg.c index 44a9cdc6..5791a3e4 100644 --- a/polyp/namereg.c +++ b/polyp/namereg.c @@ -122,30 +122,10 @@ void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type t assert(c); if (!name) { - if (type == PA_NAMEREG_SOURCE) { - if (!c->default_source_name) { - struct pa_source *s; - - for (s = pa_idxset_first(c->sources, &index); s; s = pa_idxset_next(c->sources, &index)) - if (!s->monitor_of) { - pa_namereg_set_default(c, s->name, PA_NAMEREG_SOURCE); - break; - } - } - - name = c->default_source_name; - - } else if (type == PA_NAMEREG_SINK) { - - if (!c->default_sink_name) { - struct pa_sink *s; - - if ((s = pa_idxset_first(c->sinks, NULL))) - pa_namereg_set_default(c, s->name, PA_NAMEREG_SINK); - } - - name = c->default_sink_name; - } + if (type == PA_NAMEREG_SOURCE) + name = pa_namereg_get_default_source_name(c); + else if (type == PA_NAMEREG_SINK) + name = pa_namereg_get_default_sink_name(c); } if (!name) @@ -197,3 +177,44 @@ void pa_namereg_set_default(struct pa_core*c, const char *name, enum pa_namereg_ *s = pa_xstrdup(name); pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); } + +const char *pa_namereg_get_default_sink_name(struct pa_core *c) { + struct pa_sink *s; + assert(c); + + if (c->default_sink_name) + return c->default_sink_name; + + if ((s = pa_idxset_first(c->sinks, NULL))) + pa_namereg_set_default(c, s->name, PA_NAMEREG_SINK); + + if (c->default_sink_name) + return c->default_sink_name; + + return NULL; +} + +const char *pa_namereg_get_default_source_name(struct pa_core *c) { + struct pa_source *s; + uint32_t index; + + assert(c); + + if (c->default_source_name) + return c->default_source_name; + + for (s = pa_idxset_first(c->sources, &index); s; s = pa_idxset_next(c->sources, &index)) + if (!s->monitor_of) { + pa_namereg_set_default(c, s->name, PA_NAMEREG_SOURCE); + break; + } + + if (!c->default_source_name) + if ((s = pa_idxset_first(c->sources, NULL))) + pa_namereg_set_default(c, s->name, PA_NAMEREG_SOURCE); + + if (c->default_source_name) + return c->default_source_name; + + return NULL; +} diff --git a/polyp/namereg.h b/polyp/namereg.h index b8db1105..f1be3958 100644 --- a/polyp/namereg.h +++ b/polyp/namereg.h @@ -37,4 +37,9 @@ void pa_namereg_unregister(struct pa_core *c, const char *name); void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type type, int autoload); void pa_namereg_set_default(struct pa_core*c, const char *name, enum pa_namereg_type type); + +const char *pa_namereg_get_default_sink_name(struct pa_core *c); +const char *pa_namereg_get_default_source_name(struct pa_core *c); + + #endif diff --git a/polyp/polypaudio.pa b/polyp/polypaudio.pa index 9e18abfd..40012fd6 100755 --- a/polyp/polypaudio.pa +++ b/polyp/polypaudio.pa @@ -21,7 +21,7 @@ # Load audio drivers statically #load module-alsa-sink -#load module-alsa-source device=plughw:1,0 +load module-alsa-source device=plughw:1,0 load module-oss device="/dev/dsp" sink_name=output source_name=input record=0 #load module-oss-mmap device="/dev/dsp" sink_name=output source_name=input #load module-pipe-sink diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 7170a32e..a66a0fc6 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -239,7 +239,7 @@ static void create_stream(struct pa_stream *s, const char *dev, const struct pa_ pa_tagstruct_putu32(t, tag = s->context->ctag++); pa_tagstruct_puts(t, s->name); pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, dev ? dev : ""); pa_tagstruct_putu32(t, s->buffer_attr.maxlength); if (s->direction == PA_STREAM_PLAYBACK) { diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 3d6114cf..943d6b22 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -1203,6 +1203,7 @@ static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, u struct connection *c = userdata; struct pa_tagstruct *reply; char txt[256]; + const char *n; assert(c && t); if (!pa_tagstruct_eof(t)) { @@ -1224,8 +1225,11 @@ static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, u pa_tagstruct_puts(reply, pa_get_user_name(txt, sizeof(txt))); pa_tagstruct_puts(reply, pa_get_host_name(txt, sizeof(txt))); pa_tagstruct_put_sample_spec(reply, &c->protocol->core->default_sample_spec); - pa_tagstruct_puts(reply, c->protocol->core->default_sink_name ? c->protocol->core->default_sink_name : ""); - pa_tagstruct_puts(reply, c->protocol->core->default_source_name ? c->protocol->core->default_source_name : ""); + + n = pa_namereg_get_default_sink_name(c->protocol->core); + pa_tagstruct_puts(reply, n ? n : ""); + n = pa_namereg_get_default_source_name(c->protocol->core); + pa_tagstruct_puts(reply, n ? n : ""); pa_pstream_send_tagstruct(c->pstream, reply); } -- cgit From 70007175d28cf4c7323e772683bbe084e62df024 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Sep 2004 17:06:54 +0000 Subject: implemented new CLI command: dump add prefork() and postfork() arguments to pa_context_connect_spawn() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@184 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 9 ++--- polyp/cli-command.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++ polyp/pacat.c | 2 +- polyp/polypaudio.pa | 12 +++---- polyp/polyplib-context.c | 19 ++++++++-- polyp/polyplib-context.h | 14 +++++--- 6 files changed, 130 insertions(+), 20 deletions(-) diff --git a/doc/todo b/doc/todo index f8a5ce86..4232a4d4 100644 --- a/doc/todo +++ b/doc/todo @@ -1,6 +1,8 @@ *** $Id$ *** -*** 0.4 *** +- add FAQ + +*** 0.5 *** - make mcalign merge chunks - use ref counting in more objects (i.e. sink, source, sink_input, source_output) - unix socket directories include user name @@ -12,11 +14,6 @@ - add sample directory - config file for command line arguments -- add FAQ -- pa_context_connect_spawn(): change function to fork+exec+waitpid-like function -- on delete event in paman -- add feature to dump config file - ** later *** - xmlrpc/http - dbus diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 4c4f566b..52926199 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -82,6 +82,7 @@ static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, s static int pa_cli_command_autoload_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); static int pa_cli_command_autoload_add(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); static int pa_cli_command_autoload_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_dump(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 }, @@ -115,6 +116,7 @@ static const struct command commands[] = { { "autoload_source_add", pa_cli_command_autoload_add, "Add autoload entry for a source (args: source, name, arguments)", 4}, { "autoload_sink_remove", pa_cli_command_autoload_remove, "Remove autoload entry for a sink (args: sink)", 2}, { "autoload_source_remove", pa_cli_command_autoload_remove, "Remove autoload entry for a source (args: source)", 2}, + { "dump", pa_cli_command_dump, "Dump daemon configuration", 1}, { NULL, NULL, NULL, 0 } }; @@ -596,6 +598,98 @@ static int pa_cli_command_autoload_list(struct pa_core *c, struct pa_tokenizer * return 0; } +static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + struct pa_module *m; + struct pa_sink *s; + int nl; + const char *p; + uint32_t index; + char txt[256]; + time_t now; + void *i; + struct pa_autoload_entry *a; + + assert(c && t); + + time(&now); + + pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime_r(&now, txt)); + + + for (m = pa_idxset_first(c->modules, &index); m; m = pa_idxset_next(c->modules, &index)) { + if (m->auto_unload) + continue; + + pa_strbuf_printf(buf, "load %s", m->name); + + if (m->argument) + pa_strbuf_printf(buf, " %s", m->argument); + + pa_strbuf_puts(buf, "\n"); + } + + nl = 0; + + for (s = pa_idxset_first(c->sinks, &index); s; s = pa_idxset_next(c->sinks, &index)) { + if (s->volume == PA_VOLUME_NORM) + continue; + + if (s->owner && s->owner->auto_unload) + continue; + + if (!nl) { + pa_strbuf_puts(buf, "\n"); + nl = 1; + } + + pa_strbuf_printf(buf, "sink_volume %s 0x%03x\n", s->name, s->volume); + } + + + if (c->autoload_hashmap) { + nl = 0; + + i = NULL; + while ((a = pa_hashmap_iterate(c->autoload_hashmap, &i))) { + + if (!nl) { + pa_strbuf_puts(buf, "\n"); + nl = 1; + } + + pa_strbuf_printf(buf, "autoload_%s_add %s %s", a->type == PA_NAMEREG_SINK ? "sink" : "source", a->name, a->module); + + if (a->argument) + pa_strbuf_printf(buf, " %s", a->argument); + + pa_strbuf_puts(buf, "\n"); + } + } + + nl = 0; + + if ((p = pa_namereg_get_default_sink_name(c))) { + if (!nl) { + pa_strbuf_puts(buf, "\n"); + nl = 1; + } + pa_strbuf_printf(buf, "sink_default %s\n", p); + } + + if ((p = pa_namereg_get_default_source_name(c))) { + if (!nl) { + pa_strbuf_puts(buf, "\n"); + nl = 1; + } + pa_strbuf_printf(buf, "source_default %s\n", p); + } + + pa_strbuf_puts(buf, "\n### EOF\n"); + + 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; diff --git a/polyp/pacat.c b/polyp/pacat.c index 40301be8..0ad5fa52 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -357,7 +357,7 @@ int main(int argc, char *argv[]) { pa_context_set_state_callback(context, context_state_callback, NULL); /* Connect the context */ - pa_context_connect_spawn(context, NULL); + pa_context_connect_spawn(context, NULL, NULL, NULL); /* Run the main loop */ if (pa_mainloop_run(m, &ret) < 0) { diff --git a/polyp/polypaudio.pa b/polyp/polypaudio.pa index 40012fd6..15434627 100755 --- a/polyp/polypaudio.pa +++ b/polyp/polypaudio.pa @@ -28,15 +28,15 @@ load module-oss device="/dev/dsp" sink_name=output source_name=input record=0 # Load audio drivers automatically on access -#autoload_sink_add output module-oss device="/dev/adsp" sink_name=output source_name=input -#autoload_source_add input module-oss device="/dev/adsp" sink_name=output source_name=input +#autoload_sink_add output module-oss device="/dev/dsp" sink_name=output source_name=input +#autoload_source_add input module-oss device="/dev/dsp" sink_name=output source_name=input #autoload_sink_add output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input #autoload_source_add input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input #autoload_sink_add output module-alsa-sink sink_name=output #autoload_source_add input module-alsa-source source_name=input # Load several protocols -#load module-esound-protocol-tcp +load module-esound-protocol-tcp #load module-simple-protocol-tcp load module-native-protocol-unix #load module-cli-protocol-unix @@ -46,8 +46,8 @@ load module-native-protocol-unix load module-cli # Make some devices default -#isink_default output -#source_default input +sink_default output +source_default input .nofail @@ -55,7 +55,7 @@ load module-cli scache_load /usr/share/sounds/KDE_Notify.wav x11-bell # Load X11 bell module -#load module-x11-bell sample=x11-bell sink=output +load module-x11-bell sample=x11-bell sink=output #load module-pipe-source #load module-pipe-sink diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index a810bd98..caaa1dbb 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -571,9 +571,9 @@ static int is_running(void) { return 1; } -int pa_context_connect_spawn(struct pa_context *c, void (*atfork)(void)) { +int pa_context_connect_spawn(struct pa_context *c, void (*atfork)(void), void (*prefork)(void), void (*postfork)(void)) { pid_t pid; - int status; + int status, r; int fds[2] = { -1, -1} ; struct pa_iochannel *io; @@ -586,9 +586,16 @@ int pa_context_connect_spawn(struct pa_context *c, void (*atfork)(void)) { goto fail; } + if (prefork) + prefork(); + if ((pid = fork()) < 0) { pa_log(__FILE__": fork() failed: %s\n", strerror(errno)); pa_context_fail(c, PA_ERROR_INTERNAL); + + if (postfork) + postfork(); + goto fail; } else if (!pid) { char t[64]; @@ -610,7 +617,13 @@ int pa_context_connect_spawn(struct pa_context *c, void (*atfork)(void)) { } /* Parent */ - if (waitpid(pid, &status, 0) < 0) { + + r = waitpid(pid, &status, 0); + + if (postfork) + postfork(); + + if (r < 0) { pa_log(__FILE__": waitpid() failed: %s\n", strerror(errno)); pa_context_fail(c, PA_ERROR_INTERNAL); goto fail; diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h index 65befbb3..4b199751 100644 --- a/polyp/polyplib-context.h +++ b/polyp/polyplib-context.h @@ -82,10 +82,16 @@ int pa_context_connect(struct pa_context *c, const char *server); /** Connect the context to a server. If the default server is local * but not accessible, spawn a new daemon. If atfork is not NULL it is * run after the fork() in the child process. It may be used to close - * file descriptors or to do any other cleanups. Make sure that - * SIGCHLD is handled when calling this function. The function will - * waitpid() on the daemon's PID. \since 0.4 */ -int pa_context_connect_spawn(struct pa_context *c, void (*atfork)(void)); + * file descriptors or to do any other cleanups. (It is not safe to + * close all file descriptors unconditionally, since a UNIX socket is + * passed to the new process.) if prefork is not NULL it is run just + * before forking in the parent process. Use this to block SIGCHLD + * handling if required. If postfork is not NULL it is run just after + * forking in the parent process. Use this to unblock SIGCHLD if + * required. The function will waitpid() on the daemon's PID, but + * will not block or ignore SIGCHLD signals, since this cannot be done + * in a thread compatible way. \since 0.4 */ +int pa_context_connect_spawn(struct pa_context *c, void (*atfork)(void), void (*prefork)(void), void (*postfork)(void)); /** Terminate the context connection immediately */ void pa_context_disconnect(struct pa_context *c); -- cgit From 13248fd8e6cb44e489bd2d77d5ec3491287a1f4d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Sep 2004 22:40:43 +0000 Subject: documentation update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@185 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 4 +-- doc/FAQ.html.in | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ doc/Makefile.am | 5 ++-- doc/README.html.in | 13 +++++++-- doc/cli.html.in | 6 +++- doc/daemon.html.in | 13 +++++++-- doc/modules.html.in | 30 +++++++++++++++++-- doc/todo | 3 +- polyp/Makefile.am | 2 +- polyp/module-oss-mmap.c | 9 +++--- polyp/module-oss.c | 8 +++-- 11 files changed, 147 insertions(+), 23 deletions(-) create mode 100644 doc/FAQ.html.in diff --git a/configure.ac b/configure.ac index f221689d..d278ff8e 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. AC_PREREQ(2.57) -AC_INIT([polypaudio],[0.3],[mzcbylcnhqvb (at) 0pointer (dot) de]) +AC_INIT([polypaudio],[0.4],[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([polyp/main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) @@ -118,5 +118,5 @@ AM_CONDITIONAL([USE_LYNX], [test "x$lynx" = xyes]) AM_CONDITIONAL(BUILD_LIBPOLYPCORE, false) -AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc polyplib-glib-mainloop.pc polyplib-glib12-mainloop.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf polyp/polyplib-version.h]) +AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc polyplib-glib-mainloop.pc polyplib-glib12-mainloop.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf polyp/polyplib-version.h doc/FAQ.html]) AC_OUTPUT diff --git a/doc/FAQ.html.in b/doc/FAQ.html.in new file mode 100644 index 00000000..074561c1 --- /dev/null +++ b/doc/FAQ.html.in @@ -0,0 +1,77 @@ + + + + +polypaudio: FAQ + + + + + + +

    Frequently Asked Questions

    + +
      +
    1. How does Polypaudio compare with ESOUND/aRts/NAS?

      + +

      Polypaudio is sound daemon similar to ESOUND and NAS, but much more + powerful. aRts is a realtime-synthesizer-cum-sound-server, i.e. it + does much more than Polypaudio. However, I believe that Polypaudio + does what it does much better than any other free sound server.

      +
    2. + +
    3. What about ESOUND compatibility?

      +

      Polypaudio is a drop in replacement for ESOUND. That means: you can + load a esound compatibility module which implements an ESOUND + compatible protocol which allows you to use most of the classic ESOUND + compatible programs (including the command line programs like + esdcat).

      +
    4. + +
    5. Is Polypaudio a GNOME program?

      +

      No, Polypaudio has no dependency on GNOME/GTK/GLIB. All it requires + is a UNIX-like operating system and very few dependency + libraries. However, the accompanying GUI tools are writen with + gtkmm, i.e. require both GLIB and GTK.

    6. + +
    7. Can I integrate Polypaudio in my GLIB/GTK/GNOME application?

      +

      Yes! Polypaudio comes with a GLIB main loop adapter. You can embed + both the client library and the daemon (!) into your GLIB based + application.

    8. + +
    9. Can I integrate Polypaudio in my Qt/KDE application?

      +

      Yes! Polypaudio uses a main loop abstraction layer that allows you + to integrate Polypaudio in any program that supports main + loops. Unfortunately there is no adapter for Qt publicly available yet.

    10. + +
    11. I want to write a new driver for Polypaudio, are there any docs?

      +

      Currently, only the client API is documented with doxygen. Read + the source and base your work on a simple module like + module-pipe-sink.

    12. + +
    13. What about compatibility with NAS?

      +

      Is not available (yet?). It is doable, but noone has implemented it yet.

    14. + +
    15. What about compatibility with aRts?

      +

      Is not available. Since aRts is as synthesizer application you'd have to + reimplement very much code for Polypaudio. It should be easy to + implement limited support for libartsc based + applications. Noone has done this yet. It is probably a better idea to + run arts on top of Polypaudio (through a polypaudio driver + for aRts, which nobody has written yet). Another solution would be to + embed Polypaudio in the aRts process.

    16. + +
    17. I often hear noises when playing back with Polypaudio, what can I do?

      +

      There are to possible solutions: either make the polypaudio + binary SUID root (chmod u+s /usr/bin/polypaudio) and run it + with argument -r or increase the fragment sizes of the audio + drivers. The former will allow Polypaudio to activate + SCHED_FIFO high priority scheduling (root rights are dropped + immediately after this).

    18. + +
    + +
    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, September 2004
    +
    $Id$
    + diff --git a/doc/Makefile.am b/doc/Makefile.am index 6101521c..723a92c8 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -17,9 +17,9 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. noinst_DATA = README.html cli.html modules.html daemon.html README -EXTRA_DIST = $(noinst_DATA) style.css README.html.in cli.html.in modules.html.in daemon.html.in todo +EXTRA_DIST = $(noinst_DATA) style.css README.html.in cli.html.in modules.html.in daemon.html.in todo FAQ.html.in -MAINTAINERCLEANFILES = README README.html cli.html modules.html daemon.html +MAINTAINERCLEANFILES = README README.html cli.html modules.html daemon.html FAQ.html CLEANFILES = if USE_LYNX @@ -34,6 +34,7 @@ tidy: README.html cli.html modules.html daemon.html tidy -e < cli.html tidy -e < daemon.html tidy -e < modules.html + tidy -e < FAQ.html .PHONY: tidy diff --git a/doc/README.html.in b/doc/README.html.in index f3454632..5af5c443 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -44,9 +44,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    News

    +
    Wed Sep 8 2004:

    Version 0.4 released; +changes include: daemon auto spawning, support for SCHED_FIFO scheduling, three new modules, proper logging, CPU load watchdog, many fixes.

    +
    Fri Aug 27 2004:

    Version 0.3 released; -changes include: support for both glib 2.0 and glib 1.2, future cancellation, API updates, many fixes; relicense client library to LGPL.

    +changes include: support for both glib 2.0 and glib 1.2, future cancellation, API updates, many fixes, relicense client library to LGPL.

    Fri Aug 20 2004:

    Version 0.2 released; @@ -90,7 +94,10 @@ attempt to write a sound server asd.

    A GTK GUI manager application for polypaudio is the Polypaudio Manager. There are output plugins for XMMS and libao.

    +href="http://0pointer.de/lennart/projects/paman/">Polypaudio +Manager. Another GTK GUI tool for Polypaudio is the Polypaudio Volume Meter. There are output plugins for XMMS and libao.

    Status

    @@ -105,7 +112,7 @@ release to release. The client API's library version number is currently fixed t

    There is some preliminary documentation available: modules.html, cli.html, daemon.html.

    +href="daemon.html">daemon.html, FAQ.html, .

    First Steps

    diff --git a/doc/cli.html.in b/doc/cli.html.in index 01c04cc9..6f84a07d 100644 --- a/doc/cli.html.in +++ b/doc/cli.html.in @@ -125,6 +125,10 @@ name.

    Play an audio file to a sink. Expects the file name and the sink name as argumens.

    +

    dump

    + +

    Dump the daemon's current configuration in CLI commands.

    +

    Killing Clients/Streams

    kill_client

    @@ -192,6 +196,6 @@ play_file /usr/share/sounds/startup3.wav output
    -
    Lennart Poettering <@PACKAGE_BUGREPORT@>, August 2004
    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, September 2004
    $Id$
    diff --git a/doc/daemon.html.in b/doc/daemon.html.in index a5d933db..e4903a8b 100644 --- a/doc/daemon.html.in +++ b/doc/daemon.html.in @@ -13,21 +13,28 @@ The polypaudio daemon accepts several command line arguments: +

    -r: Set low nice value (high priority) and SCHED_FIFO scheduling if available. Works only when started as root or SUID root.

    +

    -R: Don't drop root rights if started SUID root.

    -L MODULE: Load the specified module. This option may be specified more than once.

    -F FILE: Run the specified script. This option may be specified more than once.

    -C: Load the module module-cli after startup.

    +

    -n: Don't load the default configuration file. Normally ~/.polypaudio or /etc/polyp/polypaudio.pa are loaded on startup.

    -D: Daemonize after successfully executing all scripts and loading all modules.

    +

    -d: Disallow module load and unload after startup.

    -f: Unless this option is given the daemon will terminate if any of the specified modules failed to load or the script didn't execute successfully.

    -v: Increase the verbosity of the daemon.

    +

    -X SECS: Terminate the daemon after the last client exited an SECS seconds passed.

    -h: Show a quick help.

    +

    -l TARGET: Specify the log target (syslog, stderr, auto). Defaults to auto, which means stderr when run without -D and syslog when run with -D.

    +

    -V: Show version.

    Example

    It is a good idea to run the daemon like this:

    -
    polypaudio -D -F /etc/polypaudio/polypaudio.pa
    +
    polypaudio -rD
    -

    /etc/polypaudio/polypaudio.pa should be a script written in the CLI language described in cli.html +

    This will run /etc/polypaudio/polypaudio.pa after startup. This should be a script written in the CLI language described in cli.html.

    Signals

    @@ -46,6 +53,6 @@ The polypaudio daemon accepts several command line arguments:

    The daemon tries to load the module module-cli-protocol-unix, effectively providing a command line interface on a special UNIX domain socket.


    -
    Lennart Poettering <@PACKAGE_BUGREPORT@>, July 2004
    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, September 2004
    $Id$
    diff --git a/doc/modules.html.in b/doc/modules.html.in index fe202989..22a565d6 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -30,7 +30,18 @@ special file in the file system. The sink name defaults to pipe_output.

    The following option is supported:

    - + +
    file=The name of the FIFO special file to use
    file=The name of the FIFO special file to use. (defaults to: /tmp/music.output)
    + +

    module-pipe-source

    + +

    Provides a simple test source that reads the audio data from a FIFO +special file in the file system. The source name defaults to pipe_input.

    + +

    The following option is supported:

    + + +
    file=The name of the FIFO special file to use. (defaults to: /tmp/music.input)
    @@ -184,6 +195,12 @@ about the two possible suffixes of this module.

    cookie=Name of the cookie file for authentication purposes +

    module-native-protocol-fd

    + +

    This is used internally when auto spawning a new daemon.

    + +

    Miscellaneous

    +

    module-x11-bell

    Intercepts X11 bell events and plays a sample from the sample cache on each occurence.

    @@ -194,7 +211,16 @@ about the two possible suffixes of this module.

    sink=Name of the sink to play the sample on. If ommited defaults to the default sink. +

    module-sine

    + +

    Creates a sink input and generates a sine waveform stream.

    + + + + +
    sink=The sink to connect to. If ommited defaults to the default sink.
    frequency=The frequency to generate in Hertz. Defaults to 440.
    +
    -
    Lennart Poettering <@PACKAGE_BUGREPORT@>, August 2004
    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, September 2004
    $Id$
    diff --git a/doc/todo b/doc/todo index 4232a4d4..daed6864 100644 --- a/doc/todo +++ b/doc/todo @@ -1,7 +1,5 @@ *** $Id$ *** -- add FAQ - *** 0.5 *** - make mcalign merge chunks - use ref counting in more objects (i.e. sink, source, sink_input, source_output) @@ -13,6 +11,7 @@ - more complete pactl - add sample directory - config file for command line arguments +- option to use default fragment size on alsa drivers ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 39215497..b5acb3fc 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -21,7 +21,7 @@ polypincludedir=$(includedir)/polyp polypconfdir=$(sysconfdir)/polyp AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) -#AM_CFLAGS+= -DDLSEARCHDIR=\"$(pkglibdir)\" +AM_CFLAGS+= -DDLSEARCHDIR=\"$(pkglibdir)\" AM_CFLAGS+="-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/polypaudio.pa\"" AM_CFLAGS+="-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\"" diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index 8151a13a..953871d1 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -249,7 +249,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { nfrags = 12; frag_size = 1024; - if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || nfrags < 2 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0 || frag_size < 1) { + if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { pa_log(__FILE__": failed to parse fragments arguments\n"); goto fail; } @@ -269,9 +269,10 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { } pa_log(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); - - if (pa_oss_set_fragments(u->fd, nfrags, frag_size) < 0) - goto fail; + + if (nfrags >= 2 && frag_size >= 1) + if (pa_oss_set_fragments(u->fd, nfrags, frag_size) < 0) + goto fail; if (pa_oss_auto_format(u->fd, &u->sample_spec) < 0) goto fail; diff --git a/polyp/module-oss.c b/polyp/module-oss.c index 53f1f994..95deca9c 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -202,7 +202,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { nfrags = 12; frag_size = 1024; - if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || nfrags < 2 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0 || frag_size < 1) { + if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { pa_log(__FILE__": failed to parse fragments arguments\n"); goto fail; } @@ -218,8 +218,10 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { pa_log(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); - if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) - goto fail; + + if (nfrags >= 2 && frag_size >= 1) + if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) + goto fail; if (pa_oss_auto_format(fd, &ss) < 0) goto fail; -- cgit From 5fc0cf2308fb38ffdb9ffaf9d5eccd33f21e9aa3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Sep 2004 23:01:14 +0000 Subject: date fix git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@186 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/README.html.in b/doc/README.html.in index 5af5c443..837cb012 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -195,7 +195,7 @@ compilation and make install (as root) for installation of

    If you want to be notified whenever I release a new version of this software use the subscription feature of Freshmeat.


    -
    Lennart Poettering <@PACKAGE_BUGREPORT@>, August 2004
    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, September 2004
    $Id$
    -- cgit From 0c99fb31826fba0ed4f904d04dd56f1df3663a3e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 8 Sep 2004 00:08:12 +0000 Subject: add FAQ to homepage git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@187 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index e27204f6..c8592f86 100644 --- a/Makefile.am +++ b/Makefile.am @@ -35,7 +35,7 @@ homepage: all dist doxygen test -d $$HOME/homepage/private mkdir -p $$HOME/homepage/private/projects/polypaudio $$HOME/homepage/private/projects/polypaudio/doxygen cp polypaudio-@PACKAGE_VERSION@.tar.gz $$HOME/homepage/private/projects/polypaudio - cp doc/README.html doc/cli.html doc/daemon.html doc/modules.html doc/style.css $$HOME/homepage/private/projects/polypaudio + cp doc/README.html doc/FAQ.html doc/cli.html doc/daemon.html doc/modules.html doc/style.css $$HOME/homepage/private/projects/polypaudio cp -a doxygen/html/* $$HOME/homepage/private/projects/polypaudio/doxygen cp $$HOME/homepage/private/projects/polypaudio/README.html $$HOME/homepage/private/projects/polypaudio/index.html -- cgit From 25123469d53e2ef555549984ea4e8b028c1632fb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 10 Sep 2004 22:35:12 +0000 Subject: add support for module search path as command line argument protocol-native: move first data request into ack of stream creation improve mainloop API: return the number of dispatched sources on iterate() fix a resampling bug introduce network latency measurement WARNING: all these changes together may break some applications git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@189 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- doc/todo | 14 +++++++--- polyp/cmdline.c | 10 +++++++- polyp/cmdline.h | 1 + polyp/main.c | 4 +++ polyp/mainloop.c | 66 +++++++++++++++++++++++++++++++++--------------- polyp/mainloop.h | 2 +- polyp/memblockq.c | 4 +-- polyp/polyplib-context.c | 9 +++---- polyp/polyplib-def.h | 4 ++- polyp/polyplib-stream.c | 22 ++++++++++++++++ polyp/protocol-native.c | 12 ++++++--- polyp/pstream.c | 4 ++- polyp/resampler.c | 20 ++++++++++++--- polyp/sconv-s16le.c | 4 +++ polyp/sink-input.c | 9 ++++--- polyp/tagstruct.c | 24 ++++++++++++++++++ polyp/tagstruct.h | 2 ++ polyp/util.c | 54 +++++++++++++++++++++++++++++---------- polyp/util.h | 5 +++- 20 files changed, 211 insertions(+), 61 deletions(-) diff --git a/configure.ac b/configure.ac index d278ff8e..3b12b72b 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. AC_PREREQ(2.57) -AC_INIT([polypaudio],[0.4],[mzcbylcnhqvb (at) 0pointer (dot) de]) +AC_INIT([polypaudio],[0.5],[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([polyp/main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) diff --git a/doc/todo b/doc/todo index daed6864..35e0b224 100644 --- a/doc/todo +++ b/doc/todo @@ -12,6 +12,13 @@ - add sample directory - config file for command line arguments - option to use default fragment size on alsa drivers +- keep volume in xmms-polyp (and allow volume changing when not playing) +- lazy sample cache +- per-channel volume +- add version number to library names +- extend pa_usec_t to 64 bit +- make use of network latency in all apps +- rename streams/contexts ** later *** - xmlrpc/http @@ -23,7 +30,8 @@ *********** backends for: -- mplayer -- sdl -- gstreamer - portaudio +- sdl +- gstreamer (semi-done) +- alsa-lib +- OSS (esddsp style) diff --git a/polyp/cmdline.c b/polyp/cmdline.c index 1d650185..e6f4101d 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -78,6 +78,7 @@ void pa_cmdline_help(const char *argv0) { " -X SECS Terminate the daemon after the last client quit and this time passed\n" " -h Show this help\n" " -l TARGET Specify the log target (syslog, stderr, auto)\n" + " -p DIR Append a directory to the search path for dynamic modules\n" " -V Show version\n", e, cfg); pa_xfree(cfg); @@ -101,11 +102,12 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { cmdline->fail = cmdline->auto_log_target = 1; cmdline->quit_after_last_client_time = -1; cmdline->log_target = -1; + cmdline->dl_searchdir = NULL; buf = pa_strbuf_new(); assert(buf); - while ((c = getopt(argc, argv, "L:F:CDhfvrRVndX:l:")) != -1) { + while ((c = getopt(argc, argv, "L:F:CDhfvrRVndX:l:p:")) != -1) { switch (c) { case 'L': pa_strbuf_printf(buf, "load %s\n", optarg); @@ -146,6 +148,11 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { case 'X': cmdline->quit_after_last_client_time = atoi(optarg); break; + case 'p': + if (cmdline->dl_searchdir) + pa_xfree(cmdline->dl_searchdir); + cmdline->dl_searchdir = pa_xstrdup(optarg); + break; case 'l': if (!strcmp(optarg, "syslog")) { cmdline->auto_log_target = 0; @@ -185,5 +192,6 @@ fail: void pa_cmdline_free(struct pa_cmdline *cmd) { assert(cmd); pa_xfree(cmd->cli_commands); + pa_xfree(cmd->dl_searchdir); pa_xfree(cmd); } diff --git a/polyp/cmdline.h b/polyp/cmdline.h index d49b65fb..bf909c84 100644 --- a/polyp/cmdline.h +++ b/polyp/cmdline.h @@ -36,6 +36,7 @@ struct pa_cmdline { quit_after_last_client_time, auto_log_target; char *cli_commands; + char *dl_searchdir; enum pa_log_target log_target; }; diff --git a/polyp/main.c b/polyp/main.c index 29a7b548..2131877d 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -180,6 +180,10 @@ int main(int argc, char *argv[]) { r = lt_dlinit(); assert(r == 0); + + if (cmdline->dl_searchdir) + lt_dladdsearchdir(cmdline->dl_searchdir); + #ifdef DLSEARCHDIR lt_dladdsearchdir(DLSEARCHDIR); #endif diff --git a/polyp/mainloop.c b/polyp/mainloop.c index 22cd85c8..c4e12ac1 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -378,9 +378,10 @@ static void rebuild_pollfds(struct pa_mainloop *m) { } } -static void dispatch_pollfds(struct pa_mainloop *m) { +static int dispatch_pollfds(struct pa_mainloop *m) { uint32_t index = PA_IDXSET_INVALID; struct pa_io_event *e; + int r = 0; for (e = pa_idxset_first(m->io_events, &index); e; e = pa_idxset_next(m->io_events, &index)) { if (e->dead || !e->pollfd || !e->pollfd->revents) @@ -394,12 +395,16 @@ static void dispatch_pollfds(struct pa_mainloop *m) { (e->pollfd->revents & POLLERR ? PA_IO_EVENT_ERROR : 0), e->userdata); e->pollfd->revents = 0; + r++; } + + return r; } -static void dispatch_defer(struct pa_mainloop *m) { +static int dispatch_defer(struct pa_mainloop *m) { uint32_t index; struct pa_defer_event *e; + int r = 0; for (e = pa_idxset_first(m->defer_events, &index); e; e = pa_idxset_next(m->defer_events, &index)) { if (e->dead || !e->enabled) @@ -407,7 +412,10 @@ static void dispatch_defer(struct pa_mainloop *m) { assert(e->callback); e->callback(&m->api, e, e->userdata); + r++; } + + return r; } static int calc_next_timeout(struct pa_mainloop *m) { @@ -451,15 +459,16 @@ static int calc_next_timeout(struct pa_mainloop *m) { return t; } -static void dispatch_timeout(struct pa_mainloop *m) { +static int dispatch_timeout(struct pa_mainloop *m) { uint32_t index; struct pa_time_event *e; struct timeval now; int got_time = 0; + int r = 0; assert(m); if (pa_idxset_isempty(m->time_events)) - return; + return 0; for (e = pa_idxset_first(m->time_events, &index); e; e = pa_idxset_next(m->time_events, &index)) { @@ -477,51 +486,66 @@ static void dispatch_timeout(struct pa_mainloop *m) { e->enabled = 0; e->callback(&m->api, e, &e->timeval, e->userdata); + + r++; } } + + return r; } int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval) { - int r; + int r, t, dispatched = 0; assert(m && !m->running); if(m->quit) { if (retval) *retval = m->retval; - return 1; + return -2; } m->running = 1; scan_dead(m); - dispatch_defer(m); + dispatched += dispatch_defer(m); if (m->rebuild_pollfds) { rebuild_pollfds(m); m->rebuild_pollfds = 0; } - do { - int t = block ? calc_next_timeout(m) : 0; - /*pa_log(__FILE__": %u\n", t);*/ - r = poll(m->pollfds, m->n_pollfds, t); - } while (r < 0 && errno == EINTR); + t = block ? calc_next_timeout(m) : 0; + r = poll(m->pollfds, m->n_pollfds, t); - dispatch_timeout(m); - - if (r > 0) - dispatch_pollfds(m); - else if (r < 0) - pa_log(__FILE__": select(): %s\n", strerror(errno)); + if (r < 0) { + if (errno == EINTR) + r = 0; + else + pa_log(__FILE__": select(): %s\n", strerror(errno)); + } else { + dispatched += dispatch_timeout(m); + + if (r > 0) + dispatched += dispatch_pollfds(m); + } m->running = 0; - return r < 0 ? -1 : 0; + +/* pa_log("dispatched: %i\n", dispatched); */ + + return r < 0 ? -1 : dispatched; } int pa_mainloop_run(struct pa_mainloop *m, int *retval) { int r; - while ((r = pa_mainloop_iterate(m, 1, retval)) == 0); - return r; + while ((r = pa_mainloop_iterate(m, 1, retval)) >= 0); + + if (r == -2) + return 1; + else if (r < 0) + return -1; + else + return 0; } void pa_mainloop_quit(struct pa_mainloop *m, int r) { diff --git a/polyp/mainloop.h b/polyp/mainloop.h index 5d4fd990..a0fe126f 100644 --- a/polyp/mainloop.h +++ b/polyp/mainloop.h @@ -50,7 +50,7 @@ void pa_mainloop_free(struct pa_mainloop* m); on error or exit request. If block is nonzero, block for events if none are queued. Optionally return the return value as specified with the main loop's quit() routine in the integer variable retval points -to */ +to. On success returns the number of source dispatched in this iteration. */ int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval); /** Run unlimited iterations of the main loop object until the main loop's quit() routine is called. */ diff --git a/polyp/memblockq.c b/polyp/memblockq.c index a79814be..59794d6c 100644 --- a/polyp/memblockq.c +++ b/polyp/memblockq.c @@ -149,9 +149,9 @@ int pa_memblockq_peek(struct pa_memblockq* bq, struct pa_memchunk *chunk) { void pa_memblockq_drop(struct pa_memblockq *bq, const struct pa_memchunk *chunk, size_t length) { assert(bq && chunk && length); - if (!bq->blocks || memcmp(&bq->blocks->chunk, chunk, sizeof(struct pa_memchunk))) + if (!bq->blocks || memcmp(&bq->blocks->chunk, chunk, sizeof(struct pa_memchunk))) return; - + assert(length <= bq->blocks->chunk.length); pa_memblockq_skip(bq, length); } diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index caaa1dbb..a15e4257 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -431,11 +431,10 @@ void pa_context_set_state_callback(struct pa_context *c, void (*cb)(struct pa_co int pa_context_is_pending(struct pa_context *c) { assert(c && c->ref >= 1); - if (c->state != PA_CONTEXT_READY) - return 0; - - assert(c->pstream && c->pdispatch); - return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); +/* pa_log("pstream: %i\n", pa_pstream_is_pending(c->pstream)); */ +/* pa_log("pdispatch: %i\n", pa_pdispatch_is_pending(c->pdispatch)); */ + + return (c->pstream && pa_pstream_is_pending(c->pstream)) || (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) || c->client; } static void set_dispatch_callbacks(struct pa_operation *o); diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index 067ebf89..176e1d3b 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -133,7 +133,8 @@ enum pa_subscription_event_type { /** A structure for latency info. See pa_stream_get_latency(). The * total latency a sample that is written with pa_stream_write() takes - * to be played is buffer_usec+sink_usec. The buffer to which + * to be played may be estimated by + * buffer_usec+sink_usec+transport_usec. The buffer to which * buffer_usec relates may be manipulated freely (with * pa_stream_write()'s delta argument, pa_stream_flush() and friends), * the playback buffer sink_usec relates to is a FIFO which cannot be @@ -141,6 +142,7 @@ enum pa_subscription_event_type { struct pa_latency_info { pa_usec_t buffer_usec; /**< Time in usecs the current buffer takes to play */ pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. */ + pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to the daemon. \since 0.5 */ int playing; /**< Non-zero when the stream is currently playing */ uint32_t queue_length; /**< Queue size in bytes. */ }; diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index a66a0fc6..e128a773 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -30,6 +30,7 @@ #include "polyplib-internal.h" #include "xmalloc.h" #include "pstream-util.h" +#include "util.h" struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const struct pa_sample_spec *ss) { struct pa_stream *s; @@ -193,6 +194,7 @@ void pa_create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32 if (pa_tagstruct_getu32(t, &s->channel) < 0 || ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || + ((s->direction == PA_STREAM_PLAYBACK) && pa_tagstruct_getu32(t, &s->requested_bytes) < 0) || !pa_tagstruct_eof(t)) { pa_context_fail(s->context, PA_ERROR_PROTOCOL); goto finish; @@ -202,6 +204,9 @@ void pa_create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32 pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); pa_stream_set_state(s, PA_STREAM_READY); + if (s->requested_bytes && s->ref > 1 && s->write_callback) + s->write_callback(s, s->requested_bytes, s->write_userdata); + finish: pa_stream_unref(s); } @@ -321,6 +326,7 @@ struct pa_operation * pa_stream_drain(struct pa_stream *s, void (*cb) (struct pa static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_operation *o = userdata; struct pa_latency_info i, *p = NULL; + struct timeval local, remote, now; assert(pd && o && o->stream && o->context); if (command != PA_COMMAND_REPLY) { @@ -331,12 +337,23 @@ static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t comman pa_tagstruct_getu32(t, &i.sink_usec) < 0 || pa_tagstruct_get_boolean(t, &i.playing) < 0 || pa_tagstruct_getu32(t, &i.queue_length) < 0 || + pa_tagstruct_get_timeval(t, &local) < 0 || + pa_tagstruct_get_timeval(t, &remote) < 0 || !pa_tagstruct_eof(t)) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } else p = &i; + gettimeofday(&now, NULL); + + if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) + /* local and remote seem to have synchronized clocks */ + i.transport_usec = pa_timeval_diff(&remote, &local); + else + /* clocks are not synchronized, let's estimate latency then */ + i.transport_usec = pa_timeval_diff(&now, &local)/2; + if (o->callback) { void (*cb)(struct pa_stream *s, const struct pa_latency_info *i, void *userdata) = o->callback; cb(o->stream, p, o->userdata); @@ -351,6 +368,7 @@ struct pa_operation* pa_stream_get_latency(struct pa_stream *s, void (*cb)(struc uint32_t tag; struct pa_operation *o; struct pa_tagstruct *t; + struct timeval now; o = pa_operation_new(s->context, s); assert(o); @@ -362,6 +380,10 @@ struct pa_operation* pa_stream_get_latency(struct pa_stream *s, void (*cb)(struc pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); pa_tagstruct_putu32(t, tag = s->context->ctag++); pa_tagstruct_putu32(t, s->channel); + + gettimeofday(&now, NULL); + pa_tagstruct_put_timeval(t, &now); + pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, o); diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 943d6b22..058ba9cc 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -342,7 +342,7 @@ static void request_bytes(struct playback_stream *s) { if (!(l = pa_memblockq_missing(s->memblockq))) return; - + if (l <= s->requested_bytes) return; @@ -361,7 +361,7 @@ static void request_bytes(struct playback_stream *s) { pa_tagstruct_putu32(t, l); pa_pstream_send_tagstruct(s->connection->pstream, t); - /*pa_log(__FILE__": Requesting %u bytes\n", l);*/ +/* pa_log(__FILE__": Requesting %u bytes\n", l); */ } static void send_memblock(struct connection *c) { @@ -541,6 +541,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com pa_tagstruct_putu32(reply, s->index); assert(s->sink_input); pa_tagstruct_putu32(reply, s->sink_input->index); + pa_tagstruct_putu32(reply, s->requested_bytes = pa_memblockq_missing(s->memblockq)); pa_pstream_send_tagstruct(c->pstream, reply); request_bytes(s); } @@ -809,10 +810,12 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma struct connection *c = userdata; struct pa_tagstruct *reply; struct playback_stream *s; + struct timeval tv, now; uint32_t index; assert(c && t); if (pa_tagstruct_getu32(t, &index) < 0 || + pa_tagstruct_get_timeval(t, &tv) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -836,6 +839,9 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma pa_tagstruct_putu32(reply, pa_sink_get_latency(s->sink_input->sink)); pa_tagstruct_put_boolean(reply, pa_memblockq_is_readable(s->memblockq)); pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq)); + pa_tagstruct_put_timeval(reply, &tv); + gettimeofday(&now, NULL); + pa_tagstruct_put_timeval(reply, &now); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -1439,7 +1445,7 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, ui /*pa_log(__FILE__": after_recv: %u\n", pa_memblockq_get_length(p->memblockq));*/ pa_sink_notify(p->sink_input->sink); - /*pa_log(__FILE__": Recieved %u bytes.\n", chunk->length);*/ +/* pa_log(__FILE__": Recieved %u bytes.\n", chunk->length); */ } else { struct upload_stream *u = (struct upload_stream*) stream; diff --git a/polyp/pstream.c b/polyp/pstream.c index 1883c95d..4ee296ce 100644 --- a/polyp/pstream.c +++ b/polyp/pstream.c @@ -215,7 +215,7 @@ void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet) { struct item_info *i; assert(p && packet); - /*pa_log(__FILE__": push-packet %p\n", packet);*/ +/* pa_log(__FILE__": push-packet %p\n", packet); */ i = pa_xmalloc(sizeof(struct item_info)); i->type = PA_PSTREAM_ITEM_PACKET; @@ -228,6 +228,8 @@ void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet) { void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk) { struct item_info *i; assert(p && channel != (uint32_t) -1 && chunk); + +/* pa_log(__FILE__": push-memblock %p\n", chunk); */ i = pa_xmalloc(sizeof(struct item_info)); i->type = PA_PSTREAM_ITEM_MEMBLOCK; diff --git a/polyp/resampler.c b/polyp/resampler.c index b6b87607..173c0987 100644 --- a/polyp/resampler.c +++ b/polyp/resampler.c @@ -23,7 +23,6 @@ #include #endif -#include #include #include @@ -31,6 +30,7 @@ #include "resampler.h" #include "sconv.h" #include "xmalloc.h" +#include "log.h" struct pa_resampler { struct pa_sample_spec i_ss, o_ss; @@ -120,6 +120,8 @@ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, stru /* How many input samples? */ ins = in->length/r->i_sz; +/* pa_log("%u / %u = %u\n", in->length, r->i_sz, ins); */ + /* How much space for output samples? */ if (r->src_state) ons = (ins*r->o_ss.rate/r->i_ss.rate)+1024; @@ -137,6 +139,9 @@ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, stru eff_ins = ins; eff_ons = ons; } + +/* pa_log("eff_ins = %u \n", eff_ins); */ + out->memblock = pa_memblock_new(out->length = (ons*r->o_sz), r->memblock_stat); out->index = 0; @@ -145,7 +150,9 @@ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, stru if (r->i_alloc < eff_ins) r->i_buf = pa_xrealloc(r->i_buf, sizeof(float) * (r->i_alloc = eff_ins)); assert(r->i_buf); - + +/* pa_log("eff_ins = %u \n", eff_ins); */ + r->to_float32_func(eff_ins, (uint8_t*) in->memblock->data+in->index, i_nchannels, r->i_buf); if (r->src_state) { @@ -179,6 +186,13 @@ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, stru } else cbuf = r->i_buf; - r->from_float32_func(eff_ons, cbuf, (uint8_t*)out->memblock->data+out->index, o_nchannels); + if (eff_ons) + r->from_float32_func(eff_ons, cbuf, (uint8_t*)out->memblock->data+out->index, o_nchannels); out->length = ons*r->o_sz; + + + if (!out->length) { + pa_memblock_unref(out->memblock); + out->memblock = NULL; + } } diff --git a/polyp/sconv-s16le.c b/polyp/sconv-s16le.c index 45b28bdb..40376b52 100644 --- a/polyp/sconv-s16le.c +++ b/polyp/sconv-s16le.c @@ -28,6 +28,7 @@ #include "endianmacros.h" #include "sconv.h" +#include "log.h" #ifndef INT16_FROM #define INT16_FROM INT16_FROM_LE @@ -61,6 +62,9 @@ void pa_sconv_s16le_to_float32(unsigned n, const void *a, unsigned an, float *b) void pa_sconv_s16le_from_float32(unsigned n, const float *a, void *b, unsigned bn) { int16_t *cb = b; + +/* pa_log("%u %p %p %u\n", n, a, b, bn); */ + assert(n && a && b && bn); for (; n > 0; n--) { diff --git a/polyp/sink-input.c b/polyp/sink-input.c index f4f57343..b0096182 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -129,7 +129,7 @@ int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { if (!i->resampler) return i->peek(i, chunk); - if (!i->resampled_chunk.memblock) { + while (!i->resampled_chunk.memblock) { struct pa_memchunk tchunk; size_t l; int ret; @@ -141,10 +141,11 @@ int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); - if (tchunk.length > l) - tchunk.length = l; + if (l > tchunk.length) + l = tchunk.length; - i->drop(i, &tchunk, tchunk.length); + i->drop(i, &tchunk, l); + tchunk.length = l; pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk); pa_memblock_unref(tchunk.memblock); diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c index 5aa79e6c..55132cae 100644 --- a/polyp/tagstruct.c +++ b/polyp/tagstruct.c @@ -43,6 +43,7 @@ enum tags { TAG_ARBITRARY = 'x', TAG_BOOLEAN_TRUE = '1', TAG_BOOLEAN_FALSE = '0', + TAG_TIMEVAL = 'T', }; struct pa_tagstruct { @@ -145,6 +146,15 @@ void pa_tagstruct_put_boolean(struct pa_tagstruct*t, int b) { t->length += 1; } +void pa_tagstruct_put_timeval(struct pa_tagstruct*t, const struct timeval *tv) { + assert(t); + extend(t, 9); + t->data[t->length] = TAG_TIMEVAL; + *((uint32_t*) (t->data+t->length+1)) = htonl(tv->tv_sec); + *((uint32_t*) (t->data+t->length+5)) = htonl(tv->tv_usec); + t->length += 9; +} + int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s) { int error = 0; size_t n; @@ -263,4 +273,18 @@ int pa_tagstruct_get_boolean(struct pa_tagstruct*t, int *b) { return 0; } +int pa_tagstruct_get_timeval(struct pa_tagstruct*t, struct timeval *tv) { + + if (t->rindex+9 > t->length) + return -1; + + if (t->data[t->rindex] != TAG_TIMEVAL) + return -1; + + tv->tv_sec = ntohl(*((uint32_t*) (t->data+t->rindex+1))); + tv->tv_usec = ntohl(*((uint32_t*) (t->data+t->rindex+5))); + t->rindex += 9; + return 0; + +} diff --git a/polyp/tagstruct.h b/polyp/tagstruct.h index 9a91ee96..915a9a65 100644 --- a/polyp/tagstruct.h +++ b/polyp/tagstruct.h @@ -39,6 +39,7 @@ void pa_tagstruct_putu8(struct pa_tagstruct*t, uint8_t c); void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample_spec *ss); void pa_tagstruct_put_arbitrary(struct pa_tagstruct*t, const void *p, size_t length); void pa_tagstruct_put_boolean(struct pa_tagstruct*t, int b); +void pa_tagstruct_put_timeval(struct pa_tagstruct*t, const struct timeval *tv); int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s); int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i); @@ -46,6 +47,7 @@ int pa_tagstruct_getu8(struct pa_tagstruct*t, uint8_t *c); int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec *ss); int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t length); int pa_tagstruct_get_boolean(struct pa_tagstruct *t, int *b); +int pa_tagstruct_get_timeval(struct pa_tagstruct*t, struct timeval *tv); int pa_tagstruct_eof(struct pa_tagstruct*t); const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l); diff --git a/polyp/util.c b/polyp/util.c index 408e60e9..eeb1d192 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -221,26 +221,52 @@ char *pa_get_host_name(char *s, size_t l) { return s; } -uint32_t pa_age(struct timeval *tv) { - struct timeval now; - uint32_t r; - assert(tv); +pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { + pa_usec_t r; + assert(a && b); + + if (pa_timeval_cmp(a, b) < 0) { + const struct timeval *c; + c = a; + a = b; + b = c; + } - if (tv->tv_sec == 0) - return 0; + r = (a->tv_sec - b->tv_sec)* 1000000; - gettimeofday(&now, NULL); - - r = (now.tv_sec-tv->tv_sec) * 1000000; - - if (now.tv_usec >= tv->tv_usec) - r += now.tv_usec - tv->tv_usec; - else - r -= tv->tv_usec - now.tv_usec; + if (a->tv_usec > b->tv_usec) + r += (a->tv_usec - b->tv_usec); + else if (a->tv_usec < b->tv_usec) + r -= (b->tv_usec - a->tv_usec); return r; } +int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { + assert(a && b); + + if (a->tv_sec < b->tv_sec) + return -1; + + if (a->tv_sec > b->tv_sec) + return 1; + + if (a->tv_usec < b->tv_usec) + return -1; + + if (a->tv_usec > b->tv_usec) + return 1; + + return 0; +} + +pa_usec_t pa_age(const struct timeval *tv) { + struct timeval now; + assert(tv); + gettimeofday(&now, NULL); + return pa_timeval_diff(&now, tv); +} + #define NICE_LEVEL (-15) void pa_raise_priority(void) { diff --git a/polyp/util.h b/polyp/util.h index 18f883f0..adc4429b 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -27,6 +27,7 @@ #include #include "gcc-printf.h" +#include "sample.h" void pa_make_nonblock_fd(int fd); @@ -43,7 +44,9 @@ char *pa_vsprintf_malloc(const char *format, va_list ap); char *pa_get_user_name(char *s, size_t l); char *pa_get_host_name(char *s, size_t l); -uint32_t pa_age(struct timeval *tv); +pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); +int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); +pa_usec_t pa_age(const struct timeval *tv); void pa_raise_priority(void); void pa_reset_priority(void); -- cgit From 11f0aae5d6d087295594a095c889c9c5d956520f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 11 Sep 2004 00:03:00 +0000 Subject: add version number to library names git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@190 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 1 + doc/todo | 1 - polyp/Makefile.am | 96 +++++++++++++++++++++--------------------- polyplib-error.pc.in | 2 +- polyplib-glib-mainloop.pc.in | 2 +- polyplib-glib12-mainloop.pc.in | 4 +- polyplib-mainloop.pc.in | 2 +- polyplib-simple.pc.in | 2 +- polyplib.pc.in | 2 +- 9 files changed, 57 insertions(+), 55 deletions(-) diff --git a/configure.ac b/configure.ac index 3b12b72b..08b1f324 100644 --- a/configure.ac +++ b/configure.ac @@ -25,6 +25,7 @@ AC_CONFIG_SRCDIR([polyp/main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) +AC_SUBST(PA_MAJORMINOR, "$PACKAGE_VERSION") AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/polypaudio/]) if type -p stow > /dev/null && test -d /usr/local/stow ; then diff --git a/doc/todo b/doc/todo index 35e0b224..a6e3dd90 100644 --- a/doc/todo +++ b/doc/todo @@ -15,7 +15,6 @@ - keep volume in xmms-polyp (and allow volume changing when not playing) - lazy sample cache - per-channel volume -- add version number to library names - extend pa_usec_t to 64 bit - make use of network latency in all apps - rename streams/contexts diff --git a/polyp/Makefile.am b/polyp/Makefile.am index b5acb3fc..448eb277 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -20,10 +20,12 @@ polypincludedir=$(includedir)/polyp polypconfdir=$(sysconfdir)/polyp +modlibdir=$(libdir)/polypaudio-@PA_MAJORMINOR@ + AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) -AM_CFLAGS+= -DDLSEARCHDIR=\"$(pkglibdir)\" -AM_CFLAGS+="-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/polypaudio.pa\"" -AM_CFLAGS+="-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\"" +AM_CFLAGS+=-DDLSEARCHDIR=\"$(modlibdir)\" +AM_CFLAGS+=-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/polypaudio.pa\" +AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\" AM_LDADD=$(PTHREAD_LIBS) -lm AM_LIBADD=$(PTHREAD_LIBS) -lm @@ -55,7 +57,7 @@ polypinclude_HEADERS=polyplib.h \ sample.h \ glib-mainloop.h -pkglib_LTLIBRARIES=libiochannel.la \ +modlib_LTLIBRARIES=libiochannel.la \ libsocket-server.la \ libsocket-client.la \ libpstream.la \ @@ -92,15 +94,15 @@ pkglib_LTLIBRARIES=libiochannel.la \ module-sine.la if !X_DISPLAY_MISSING -pkglib_LTLIBRARIES+=module-x11-bell.la +modlib_LTLIBRARIES+=module-x11-bell.la endif -lib_LTLIBRARIES=libpolyp.la \ - libpolyp-error.la \ - libpolyp-mainloop.la \ - libpolyp-mainloop-glib.la \ - libpolyp-mainloop-glib12.la \ - libpolyp-simple.la +lib_LTLIBRARIES=libpolyp-@PA_MAJORMINOR@.la \ + libpolyp-error-@PA_MAJORMINOR@.la \ + libpolyp-mainloop-@PA_MAJORMINOR@.la \ + libpolyp-mainloop-glib-@PA_MAJORMINOR@.la \ + libpolyp-mainloop-glib12-@PA_MAJORMINOR@.la \ + libpolyp-simple-@PA_MAJORMINOR@.la polypaudio_SOURCES = idxset.c idxset.h \ queue.c queue.h \ @@ -307,7 +309,7 @@ module_x11_bell_la_LDFLAGS = -module -avoid-version module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) endif -libpolyp_la_SOURCES = polyplib.h \ +libpolyp_@PA_MAJORMINOR@_la_SOURCES = polyplib.h \ polyplib-def.h \ tagstruct.c tagstruct.h \ iochannel.c iochannel.h \ @@ -340,71 +342,71 @@ libpolyp_la_SOURCES = polyplib.h \ log.c log.h \ gcc-printf.h -libpolyp_la_CFLAGS = $(AM_CFLAGS) -libpolyp_la_LDFLAGS = -version-info 0:0:0 +libpolyp_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) +libpolyp_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 -libpolyp_mainloop_la_SOURCES = mainloop-api.h mainloop-api.c \ +libpolyp_mainloop_@PA_MAJORMINOR@_la_SOURCES = mainloop-api.h mainloop-api.c \ mainloop.c mainloop.h \ mainloop-signal.c mainloop-signal.h -libpolyp_mainloop_la_CFLAGS = $(AM_CFLAGS) -libpolyp_mainloop_la_LIBADD = $(AM_LIBADD) libpolyp.la -libpolyp_mainloop_la_LDFLAGS = -version-info 0:0:0 - -libpolyp_error_la_SOURCES = polyplib-error.c polyplib-error.h -libpolyp_error_la_CFLAGS = $(AM_CFLAGS) -libpolyp_error_la_LIBADD = $(AM_LIBADD) libpolyp.la -libpolyp_error_la_LDFLAGS = -version-info 0:0:0 - -libpolyp_simple_la_SOURCES = polyplib-simple.c polyplib-simple.h -libpolyp_simple_la_CFLAGS = $(AM_CFLAGS) -libpolyp_simple_la_LIBADD = $(AM_LIBADD) libpolyp.la libpolyp-mainloop.la -libpolyp_simple_la_LDFLAGS = -version-info 0:0:0 - -libpolyp_mainloop_glib_la_SOURCES = glib-mainloop.h glib-mainloop.c -libpolyp_mainloop_glib_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) -libpolyp_mainloop_glib_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop.la $(GLIB20_LIBS) -libpolyp_mainloop_glib_la_LDFLAGS = -version-info 0:0:0 - -libpolyp_mainloop_glib12_la_SOURCES = glib-mainloop.h glib12-mainloop.c -libpolyp_mainloop_glib12_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS) -libpolyp_mainloop_glib12_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop.la $(GLIB12_LIBS) -libpolyp_mainloop_glib12_la_LDFLAGS = -version-info 0:0:0 +libpolyp_mainloop_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) +libpolyp_mainloop_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la +libpolyp_mainloop_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 + +libpolyp_error_@PA_MAJORMINOR@_la_SOURCES = polyplib-error.c polyplib-error.h +libpolyp_error_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) +libpolyp_error_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la +libpolyp_error_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 + +libpolyp_simple_@PA_MAJORMINOR@_la_SOURCES = polyplib-simple.c polyplib-simple.h +libpolyp_simple_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) +libpolyp_simple_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la +libpolyp_simple_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 + +libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_SOURCES = glib-mainloop.h glib-mainloop.c +libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) +libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop-@PA_MAJORMINOR@.la $(GLIB20_LIBS) +libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 + +libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_SOURCES = glib-mainloop.h glib12-mainloop.c +libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS) +libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop-@PA_MAJORMINOR@.la $(GLIB12_LIBS) +libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 pacat_SOURCES = pacat.c -pacat_LDADD = $(AM_LDADD) libpolyp.la libpolyp-error.la libpolyp-mainloop.la +pacat_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la pacat_CFLAGS = $(AM_CFLAGS) pactl_SOURCES = pactl.c -pactl_LDADD = $(AM_LDADD) libpolyp.la libpolyp-error.la libpolyp-mainloop.la $(LIBSNDFILE_LIBS) +pactl_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) pactl_CFLAGS = $(AM_CFLAGS) $(LIBSDNFILE_CFLAGS) pacat_simple_SOURCES = pacat-simple.c -pacat_simple_LDADD = $(AM_LDADD) libpolyp.la libpolyp-simple.la libpolyp-error.la +pacat_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la pacat_simple_CFLAGS = $(AM_CFLAGS) parec_simple_SOURCES = parec-simple.c -parec_simple_LDADD = $(AM_LDADD) libpolyp.la libpolyp-simple.la libpolyp-error.la +parec_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la parec_simple_CFLAGS = $(AM_CFLAGS) mainloop_test_SOURCES = mainloop-test.c mainloop_test_CFLAGS = $(AM_CFLAGS) -mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop.la libpolyp.la +mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-@PA_MAJORMINOR@.la mainloop_test_glib_SOURCES = $(mainloop_test_SOURCES) mainloop_test_glib_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB20_CFLAGS) -DGLIB_MAIN_LOOP -mainloop_test_glib_LDADD = $(mainloop_test_LDADD) $(GLIB20_LIBS) libpolyp-mainloop-glib.la +mainloop_test_glib_LDADD = $(mainloop_test_LDADD) $(GLIB20_LIBS) libpolyp-mainloop-glib-@PA_MAJORMINOR@.la mainloop_test_glib12_SOURCES = $(mainloop_test_SOURCES) mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MAIN_LOOP -mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12.la +mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12-@PA_MAJORMINOR@.la cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit_test_CFLAGS = $(AM_CFLAGS) -cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop.la +cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la cpulimit_test2_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit_test2_CFLAGS = $(AM_CFLAGS) -DTEST2 -cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop.la +cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la if BUILD_LIBPOLYPCORE diff --git a/polyplib-error.pc.in b/polyplib-error.pc.in index b5289959..45f69dbc 100644 --- a/polyplib-error.pc.in +++ b/polyplib-error.pc.in @@ -6,5 +6,5 @@ includedir=${prefix}/include Name: polyplib-error Description: Error library for the polypaudio sound daemon Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpolyp-error +Libs: -L${libdir} -lpolyp-error-@PA_MAJORMINOR@ Cflags: -D_REENTRANT -I${includedir} diff --git a/polyplib-glib-mainloop.pc.in b/polyplib-glib-mainloop.pc.in index f4c09330..431354e8 100644 --- a/polyplib-glib-mainloop.pc.in +++ b/polyplib-glib-mainloop.pc.in @@ -6,6 +6,6 @@ includedir=${prefix}/include Name: polyplib-glib-mainloop Description: GLIB main loop wrapper for polypaudio Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpolyp-mainloop-glib +Libs: -L${libdir} -lpolyp-mainloop-glib-@PA_MAJORMINOR@ Cflags: -D_REENTRANT -I${includedir} Requires: polyplib-mainloop diff --git a/polyplib-glib12-mainloop.pc.in b/polyplib-glib12-mainloop.pc.in index 3afed38e..5c5f4089 100644 --- a/polyplib-glib12-mainloop.pc.in +++ b/polyplib-glib12-mainloop.pc.in @@ -3,9 +3,9 @@ exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include -Name: polyplib-glib-mainloop +Name: polyplib-glib12-mainloop Description: GLIB main loop wrapper for polypaudio Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpolyp-mainloop-glib12 +Libs: -L${libdir} -lpolyp-mainloop-glib12-@PA_MAJORMINOR@ Cflags: -D_REENTRANT -I${includedir} Requires: polyplib-mainloop diff --git a/polyplib-mainloop.pc.in b/polyplib-mainloop.pc.in index 73e579a3..ab9b3e69 100644 --- a/polyplib-mainloop.pc.in +++ b/polyplib-mainloop.pc.in @@ -6,5 +6,5 @@ includedir=${prefix}/include Name: polyplib-mainloop Description: Main loop support for polypaudio Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpolyp-mainloop +Libs: -L${libdir} -lpolyp-mainloop-@PA_MAJORMINOR@ Cflags: -D_REENTRANT -I${includedir} diff --git a/polyplib-simple.pc.in b/polyplib-simple.pc.in index e5dcaa9e..a2850349 100644 --- a/polyplib-simple.pc.in +++ b/polyplib-simple.pc.in @@ -6,6 +6,6 @@ includedir=${prefix}/include Name: polyplib-simple Description: Simplified synchronous client interface to polypaudio Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpolyp-simple +Libs: -L${libdir} -lpolyp-simple-@PA_MAJORMINOR@ Cflags: -D_REENTRANT -I${includedir} Requires: polyplib polyplib-mainloop polyplib-error diff --git a/polyplib.pc.in b/polyplib.pc.in index b06c6e51..c79d98d4 100644 --- a/polyplib.pc.in +++ b/polyplib.pc.in @@ -6,6 +6,6 @@ includedir=${prefix}/include Name: polyplib Description: Client interface to polypaudio Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpolyp +Libs: -L${libdir} -lpolyp-@PA_MAJORMINOR@ Cflags: -D_REENTRANT -I${includedir} Requires: polyplib-error polyplib-mainloop -- cgit From a9ca9c4a3bd8c3c03fe5d30cd2694cf891f5bbc1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 11 Sep 2004 23:17:38 +0000 Subject: add modinfo support git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@191 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 4 +- polyp/Makefile.am | 13 +++- polyp/cmdline.c | 10 +-- polyp/cmdline.h | 2 +- polyp/main.c | 10 +-- polyp/modinfo.c | 84 +++++++++++++++++++++++++ polyp/modinfo.h | 37 +++++++++++ polyp/module-alsa-sink.c | 10 ++- polyp/module-alsa-source.c | 10 ++- polyp/module-cli.c | 8 ++- polyp/module-native-protocol-fd.c | 8 ++- polyp/module-oss-mmap.c | 10 ++- polyp/module-oss.c | 8 ++- polyp/module-pipe-sink.c | 10 ++- polyp/module-pipe-source.c | 10 ++- polyp/module-protocol-stub.c | 18 +++++- polyp/module-sine.c | 12 +++- polyp/module-x11-bell.c | 11 +++- polyp/module.c | 30 ++++++--- polyp/module.h | 16 +++-- polyp/pamodinfo.c | 126 ++++++++++++++++++++++++++++++++++++++ 21 files changed, 390 insertions(+), 57 deletions(-) create mode 100644 polyp/modinfo.c create mode 100644 polyp/modinfo.h create mode 100644 polyp/pamodinfo.c diff --git a/doc/todo b/doc/todo index a6e3dd90..c9be66ab 100644 --- a/doc/todo +++ b/doc/todo @@ -8,6 +8,7 @@ module load/unload kill client/... autoload management + rename streams/contexts - more complete pactl - add sample directory - config file for command line arguments @@ -17,7 +18,8 @@ - per-channel volume - extend pa_usec_t to 64 bit - make use of network latency in all apps -- rename streams/contexts +- fix or work around libtool bug +- merge pa_context_connect_* ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 448eb277..9cb8c4ba 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -23,7 +23,7 @@ polypconfdir=$(sysconfdir)/polyp modlibdir=$(libdir)/polypaudio-@PA_MAJORMINOR@ AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) -AM_CFLAGS+=-DDLSEARCHDIR=\"$(modlibdir)\" +AM_CFLAGS+=-DDLSEARCHPATH=\"$(modlibdir)\" AM_CFLAGS+=-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/polypaudio.pa\" AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\" @@ -31,7 +31,7 @@ AM_LDADD=$(PTHREAD_LIBS) -lm AM_LIBADD=$(PTHREAD_LIBS) -lm EXTRA_DIST = polypaudio.pa depmod.py esdcompat.sh.in -bin_PROGRAMS = polypaudio pacat pactl +bin_PROGRAMS = polypaudio pacat pactl pamodinfo bin_SCRIPTS = esdcompat.sh noinst_PROGRAMS = mainloop-test mainloop-test-glib mainloop-test-glib12 pacat-simple parec-simple cpulimit-test cpulimit-test2 @@ -148,13 +148,20 @@ polypaudio_SOURCES = idxset.c idxset.h \ sound-file-stream.c sound-file-stream.h \ cpulimit.c cpulimit.h \ log.c log.h \ - gcc-printf.h + gcc-printf.h \ + modinfo.c modinfo.h polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) polypaudio_LDFLAGS=-export-dynamic +pamodinfo_SOURCES = log.c log.h pamodinfo.c pamodinfo.h modinfo.c modinfo.h util.c util.h xmalloc.c xmalloc.h +pamodinfo_CFLAGS = $(AM_CFLAGS) +pamodinfo_INCLUDES = $(INCLTDL) +pamodinfo_LDADD = $(AM_LDADD) $(LIBLTDL) +pamodinfo_LDFLAGS=-export-dynamic + libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h libprotocol_simple_la_LDFLAGS = -avoid-version libprotocol_simple_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la diff --git a/polyp/cmdline.c b/polyp/cmdline.c index e6f4101d..b4d58f1f 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -102,7 +102,7 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { cmdline->fail = cmdline->auto_log_target = 1; cmdline->quit_after_last_client_time = -1; cmdline->log_target = -1; - cmdline->dl_searchdir = NULL; + cmdline->dl_search_path = NULL; buf = pa_strbuf_new(); assert(buf); @@ -149,9 +149,9 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { cmdline->quit_after_last_client_time = atoi(optarg); break; case 'p': - if (cmdline->dl_searchdir) - pa_xfree(cmdline->dl_searchdir); - cmdline->dl_searchdir = pa_xstrdup(optarg); + if (cmdline->dl_search_path) + pa_xfree(cmdline->dl_search_path); + cmdline->dl_search_path = pa_xstrdup(optarg); break; case 'l': if (!strcmp(optarg, "syslog")) { @@ -192,6 +192,6 @@ fail: void pa_cmdline_free(struct pa_cmdline *cmd) { assert(cmd); pa_xfree(cmd->cli_commands); - pa_xfree(cmd->dl_searchdir); + pa_xfree(cmd->dl_search_path); pa_xfree(cmd); } diff --git a/polyp/cmdline.h b/polyp/cmdline.h index bf909c84..5dfe2e0d 100644 --- a/polyp/cmdline.h +++ b/polyp/cmdline.h @@ -36,7 +36,7 @@ struct pa_cmdline { quit_after_last_client_time, auto_log_target; char *cli_commands; - char *dl_searchdir; + char *dl_search_path; enum pa_log_target log_target; }; diff --git a/polyp/main.c b/polyp/main.c index 2131877d..0218f396 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -181,11 +181,11 @@ int main(int argc, char *argv[]) { r = lt_dlinit(); assert(r == 0); - if (cmdline->dl_searchdir) - lt_dladdsearchdir(cmdline->dl_searchdir); - -#ifdef DLSEARCHDIR - lt_dladdsearchdir(DLSEARCHDIR); + if (cmdline->dl_search_path) + lt_dlsetsearchpath(cmdline->dl_search_path); +#ifdef DLSEARCHPATH + else + lt_dlsetsearchpath(DLSEARCHPATH); #endif mainloop = pa_mainloop_new(); diff --git a/polyp/modinfo.c b/polyp/modinfo.c new file mode 100644 index 00000000..2847c63c --- /dev/null +++ b/polyp/modinfo.c @@ -0,0 +1,84 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "xmalloc.h" +#include "util.h" +#include "modinfo.h" +#include "log.h" + +#define PA_SYMBOL_AUTHOR "pa__get_author" +#define PA_SYMBOL_DESCRIPTION "pa__get_description" +#define PA_SYMBOL_USAGE "pa__get_usage" +#define PA_SYMBOL_VERSION "pa__get_version" + +struct pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl) { + struct pa_modinfo *i; + const char* (*func)(void); + assert(dl); + + i = pa_xmalloc0(sizeof(struct pa_modinfo)); + + if ((func = (const char* (*)(void)) lt_dlsym(dl, PA_SYMBOL_AUTHOR))) + i->author = pa_xstrdup(func()); + + if ((func = (const char* (*)(void)) lt_dlsym(dl, PA_SYMBOL_DESCRIPTION))) + i->description = pa_xstrdup(func()); + + if ((func = (const char* (*)(void)) lt_dlsym(dl, PA_SYMBOL_USAGE))) + i->usage = pa_xstrdup(func()); + + if ((func = (const char* (*)(void)) lt_dlsym(dl, PA_SYMBOL_VERSION))) + i->version = pa_xstrdup(func()); + + return i; +} + +struct pa_modinfo *pa_modinfo_get_by_name(const char *name) { + lt_dlhandle dl; + struct pa_modinfo *i; + assert(name); + + if (!(dl = lt_dlopenext(name))) { + pa_log(__FILE__": Failed to open module \"%s\": %s\n", name, lt_dlerror()); + return NULL; + } + + i = pa_modinfo_get_by_handle(dl); + lt_dlclose(dl); + + return i; +} + +void pa_modinfo_free(struct pa_modinfo *i) { + assert(i); + pa_xfree(i->author); + pa_xfree(i->description); + pa_xfree(i->usage); + pa_xfree(i->version); + pa_xfree(i); +} diff --git a/polyp/modinfo.h b/polyp/modinfo.h new file mode 100644 index 00000000..40b535ce --- /dev/null +++ b/polyp/modinfo.h @@ -0,0 +1,37 @@ +#ifndef foomodinfohfoo +#define foomodinfohfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +struct pa_modinfo { + char *author; + char *description; + char *usage; + char *version; +}; + +struct pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl); +struct pa_modinfo *pa_modinfo_get_by_name(const char *name); + +void pa_modinfo_free(struct pa_modinfo *i); + +#endif diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index 9c75ff98..73c46ea0 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -40,6 +40,10 @@ #include "xmalloc.h" #include "log.h" +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("ALSA Sink") +PA_MODULE_VERSION(PACKAGE_VERSION) + struct userdata { snd_pcm_t *pcm_handle; struct pa_sink *sink; @@ -156,7 +160,7 @@ static uint32_t sink_get_latency_cb(struct pa_sink *s) { return pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec); } -int pa_module_init(struct pa_core *c, struct pa_module*m) { +int pa__init(struct pa_core *c, struct pa_module*m) { struct pa_modargs *ma = NULL; int ret = -1; struct userdata *u = NULL; @@ -237,12 +241,12 @@ finish: fail: if (u) - pa_module_done(c, m); + pa__done(c, m); goto finish; } -void pa_module_done(struct pa_core *c, struct pa_module*m) { +void pa__done(struct pa_core *c, struct pa_module*m) { struct userdata *u; assert(c && m); diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index 520b6830..3ef54b17 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -40,6 +40,10 @@ #include "xmalloc.h" #include "log.h" +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("ALSA Source") +PA_MODULE_VERSION(PACKAGE_VERSION) + struct userdata { snd_pcm_t *pcm_handle; struct pa_source *source; @@ -139,7 +143,7 @@ static void io_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, do_read(u); } -int pa_module_init(struct pa_core *c, struct pa_module*m) { +int pa__init(struct pa_core *c, struct pa_module*m) { struct pa_modargs *ma = NULL; int ret = -1; struct userdata *u = NULL; @@ -216,12 +220,12 @@ finish: fail: if (u) - pa_module_done(c, m); + pa__done(c, m); goto finish; } -void pa_module_done(struct pa_core *c, struct pa_module*m) { +void pa__done(struct pa_core *c, struct pa_module*m) { struct userdata *u; assert(c && m); diff --git a/polyp/module-cli.c b/polyp/module-cli.c index 9a08a00d..35b69cb6 100644 --- a/polyp/module-cli.c +++ b/polyp/module-cli.c @@ -33,6 +33,10 @@ #include "sioman.h" #include "log.h" +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Command line interface") +PA_MODULE_VERSION(PACKAGE_VERSION) + static void eof_cb(struct pa_cli*c, void *userdata) { struct pa_module *m = userdata; assert(c && m); @@ -40,7 +44,7 @@ static void eof_cb(struct pa_cli*c, void *userdata) { pa_module_unload_request(m->core, m); } -int pa_module_init(struct pa_core *c, struct pa_module*m) { +int pa__init(struct pa_core *c, struct pa_module*m) { struct pa_iochannel *io; assert(c && m); @@ -66,7 +70,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { return 0; } -void pa_module_done(struct pa_core *c, struct pa_module*m) { +void pa__done(struct pa_core *c, struct pa_module*m) { assert(c && m); pa_cli_free(m->userdata); diff --git a/polyp/module-native-protocol-fd.c b/polyp/module-native-protocol-fd.c index 632a3d71..c1ea6975 100644 --- a/polyp/module-native-protocol-fd.c +++ b/polyp/module-native-protocol-fd.c @@ -33,6 +33,10 @@ #include "protocol-native.h" #include "log.h" +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Native protocol autospawn helper") +PA_MODULE_VERSION(PACKAGE_VERSION) + static const char* const valid_modargs[] = { "fd", "public", @@ -40,7 +44,7 @@ static const char* const valid_modargs[] = { NULL, }; -int pa_module_init(struct pa_core *c, struct pa_module*m) { +int pa__init(struct pa_core *c, struct pa_module*m) { struct pa_iochannel *io; struct pa_modargs *ma; int fd, r = -1; @@ -72,7 +76,7 @@ finish: return r; } -void pa_module_done(struct pa_core *c, struct pa_module*m) { +void pa__done(struct pa_core *c, struct pa_module*m) { assert(c && m); pa_protocol_native_free(m->userdata); diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index 953871d1..4ffc56ef 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -47,6 +47,10 @@ #include "xmalloc.h" #include "log.h" +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("OSS Sink/Source (mmap)") +PA_MODULE_VERSION(PACKAGE_VERSION) + struct userdata { struct pa_sink *sink; struct pa_source *source; @@ -214,7 +218,7 @@ static uint32_t sink_get_latency_cb(struct pa_sink *s) { return pa_bytes_to_usec(u->out_fill, &s->sample_spec); } -int pa_module_init(struct pa_core *c, struct pa_module*m) { +int pa__init(struct pa_core *c, struct pa_module*m) { struct audio_buf_info info; struct userdata *u = NULL; const char *p; @@ -362,7 +366,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { return 0; fail: - pa_module_done(c, m); + pa__done(c, m); if (ma) pa_modargs_free(ma); @@ -370,7 +374,7 @@ fail: return -1; } -void pa_module_done(struct pa_core *c, struct pa_module*m) { +void pa__done(struct pa_core *c, struct pa_module*m) { struct userdata *u; assert(c && m); diff --git a/polyp/module-oss.c b/polyp/module-oss.c index 95deca9c..75d72e50 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -46,6 +46,10 @@ #include "xmalloc.h" #include "log.h" +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("OSS Sink/Source") +PA_MODULE_VERSION(PACKAGE_VERSION) + struct userdata { struct pa_sink *sink; struct pa_source *source; @@ -171,7 +175,7 @@ static uint32_t sink_get_latency_cb(struct pa_sink *s) { return pa_bytes_to_usec(arg, &s->sample_spec); } -int pa_module_init(struct pa_core *c, struct pa_module*m) { +int pa__init(struct pa_core *c, struct pa_module*m) { struct audio_buf_info info; struct userdata *u = NULL; const char *p; @@ -300,7 +304,7 @@ fail: return -1; } -void pa_module_done(struct pa_core *c, struct pa_module*m) { +void pa__done(struct pa_core *c, struct pa_module*m) { struct userdata *u; assert(c && m); diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c index a5a7877f..1aaf3b6a 100644 --- a/polyp/module-pipe-sink.c +++ b/polyp/module-pipe-sink.c @@ -41,6 +41,10 @@ #include "xmalloc.h" #include "log.h" +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("UNIX pipe sink") +PA_MODULE_VERSION(PACKAGE_VERSION) + #define DEFAULT_FIFO_NAME "/tmp/music.output" #define DEFAULT_SINK_NAME "fifo_output" @@ -117,7 +121,7 @@ static void io_callback(struct pa_iochannel *io, void*userdata) { do_write(u); } -int pa_module_init(struct pa_core *c, struct pa_module*m) { +int pa__init(struct pa_core *c, struct pa_module*m) { struct userdata *u = NULL; struct stat st; const char *p; @@ -196,12 +200,12 @@ fail: if (fd >= 0) close(fd); - pa_module_done(c, m); + pa__done(c, m); return -1; } -void pa_module_done(struct pa_core *c, struct pa_module*m) { +void pa__done(struct pa_core *c, struct pa_module*m) { struct userdata *u; assert(c && m); diff --git a/polyp/module-pipe-source.c b/polyp/module-pipe-source.c index baed06a5..a226d44e 100644 --- a/polyp/module-pipe-source.c +++ b/polyp/module-pipe-source.c @@ -41,6 +41,10 @@ #include "xmalloc.h" #include "log.h" +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("UNIX pipe source") +PA_MODULE_VERSION(PACKAGE_VERSION) + #define DEFAULT_FIFO_NAME "/tmp/music.input" #define DEFAULT_SOURCE_NAME "fifo_input" @@ -102,7 +106,7 @@ static void io_callback(struct pa_iochannel *io, void*userdata) { do_read(u); } -int pa_module_init(struct pa_core *c, struct pa_module*m) { +int pa__init(struct pa_core *c, struct pa_module*m) { struct userdata *u = NULL; struct stat st; const char *p; @@ -176,12 +180,12 @@ fail: if (fd >= 0) close(fd); - pa_module_done(c, m); + pa__done(c, m); return -1; } -void pa_module_done(struct pa_core *c, struct pa_module*m) { +void pa__done(struct pa_core *c, struct pa_module*m) { struct userdata *u; assert(c && m); diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index 686e2129..fe9e12a1 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -37,6 +37,16 @@ #include "modargs.h" #include "log.h" +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_VERSION(PACKAGE_VERSION) + +#ifdef USE_TCP_SOCKETS +#define SOCKET_DESCRIPTION "(TCP sockets)" +#else +#define SOCKET_DESCRIPTION "(UNIX sockets)" +#endif + + #if defined(USE_PROTOCOL_SIMPLE) #include "protocol-simple.h" #define protocol_new pa_protocol_simple_new @@ -44,6 +54,7 @@ #define IPV4_PORT 4711 #define UNIX_SOCKET "/tmp/polypaudio/simple" #define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record", + PA_MODULE_DESCRIPTION("Simple protocol "SOCKET_DESCRIPTION) #elif defined(USE_PROTOCOL_CLI) #include "protocol-cli.h" #define protocol_new pa_protocol_cli_new @@ -51,6 +62,7 @@ #define IPV4_PORT 4712 #define UNIX_SOCKET "/tmp/polypaudio/cli" #define MODULE_ARGUMENTS + PA_MODULE_DESCRIPTION("Command line interface protocol "SOCKET_DESCRIPTION) #elif defined(USE_PROTOCOL_NATIVE) #include "protocol-native.h" #define protocol_new pa_protocol_native_new @@ -58,6 +70,7 @@ #define IPV4_PORT 4713 #define UNIX_SOCKET "/tmp/polypaudio/native" #define MODULE_ARGUMENTS "public", "cookie", + PA_MODULE_DESCRIPTION("Native protocol "SOCKET_DESCRIPTION) #elif defined(USE_PROTOCOL_ESOUND) #include "protocol-esound.h" #include "esound.h" @@ -66,6 +79,7 @@ #define IPV4_PORT ESD_DEFAULT_PORT #define UNIX_SOCKET ESD_UNIX_SOCKET_NAME #define MODULE_ARGUMENTS "sink", "source", "public", "cookie", + PA_MODULE_DESCRIPTION("EsounD protocol "SOCKET_DESCRIPTION) #else #error "Broken build system" #endif @@ -126,7 +140,7 @@ static struct pa_socket_server *create_socket_server(struct pa_core *c, struct p return s; } -int pa_module_init(struct pa_core *c, struct pa_module*m) { +int pa__init(struct pa_core *c, struct pa_module*m) { struct pa_socket_server *s; struct pa_modargs *ma = NULL; int ret = -1; @@ -154,7 +168,7 @@ finish: return ret; } -void pa_module_done(struct pa_core *c, struct pa_module*m) { +void pa__done(struct pa_core *c, struct pa_module*m) { assert(c && m); protocol_free(m->userdata); diff --git a/polyp/module-sine.c b/polyp/module-sine.c index 868f63c6..98e0dc28 100644 --- a/polyp/module-sine.c +++ b/polyp/module-sine.c @@ -34,6 +34,11 @@ #include "namereg.h" #include "log.h" +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Sine wave generator") +PA_MODULE_USAGE("sink= frequency=") +PA_MODULE_VERSION(PACKAGE_VERSION) + struct userdata { struct pa_core *core; struct pa_sink_input *sink_input; @@ -89,7 +94,7 @@ static void calc_sine(float *f, size_t l, float freq) { f[i] = (float) sin((double) i/l*M_PI*2*freq)/2; } -int pa_module_init(struct pa_core *c, struct pa_module*m) { +int pa__init(struct pa_core *c, struct pa_module*m) { struct pa_modargs *ma = NULL; struct userdata *u; struct pa_sink *sink; @@ -147,11 +152,11 @@ fail: if (ma) pa_modargs_free(ma); - pa_module_done(c, m); + pa__done(c, m); return -1; } -void pa_module_done(struct pa_core *c, struct pa_module*m) { +void pa__done(struct pa_core *c, struct pa_module*m) { struct userdata *u = m->userdata; assert(c && m); @@ -164,3 +169,4 @@ void pa_module_done(struct pa_core *c, struct pa_module*m) { pa_memblock_unref(u->memblock); pa_xfree(u); } + diff --git a/polyp/module-x11-bell.c b/polyp/module-x11-bell.c index d8ec978b..ae69f9cb 100644 --- a/polyp/module-x11-bell.c +++ b/polyp/module-x11-bell.c @@ -39,6 +39,11 @@ #include "namereg.h" #include "log.h" +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("X11 Bell interceptor") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink= sample= display=") + struct x11_source { struct pa_io_event *io_event; struct x11_source *next; @@ -105,7 +110,7 @@ static void new_io_source(struct userdata *u, int fd) { u->x11_sources = s; } -int pa_module_init(struct pa_core *c, struct pa_module*m) { +int pa__init(struct pa_core *c, struct pa_module*m) { struct userdata *u = NULL; struct pa_modargs *ma = NULL; int major, minor; @@ -160,11 +165,11 @@ fail: if (ma) pa_modargs_free(ma); if (m->userdata) - pa_module_done(c, m); + pa__done(c, m); return -1; } -void pa_module_done(struct pa_core *c, struct pa_module*m) { +void pa__done(struct pa_core *c, struct pa_module*m) { struct userdata *u = m->userdata; assert(c && m && u); diff --git a/polyp/module.c b/polyp/module.c index 6eec499b..c66faeb8 100644 --- a/polyp/module.c +++ b/polyp/module.c @@ -35,6 +35,9 @@ #include "subscribe.h" #include "log.h" +#define PA_SYMBOL_INIT "pa__init" +#define PA_SYMBOL_DONE "pa__done" + #define UNLOAD_POLL_TIME 10 static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, const struct timeval *tv, void *userdata) { @@ -58,21 +61,25 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char if (c->disallow_module_loading) goto fail; - pa_log(__FILE__": Trying to load \"%s\" with argument \"%s\".\n", name, argument); - m = pa_xmalloc(sizeof(struct pa_module)); m->name = pa_xstrdup(name); m->argument = pa_xstrdup(argument); - if (!(m->dl = lt_dlopenext(name))) + if (!(m->dl = lt_dlopenext(name))) { + pa_log(__FILE__": Failed to open module \"%s\": %s\n", name, lt_dlerror()); goto fail; + } - if (!(m->init = (int (*)(struct pa_core *c, struct pa_module*m)) lt_dlsym(m->dl, "pa_module_init"))) + if (!(m->init = (int (*)(struct pa_core *c, struct pa_module*m)) lt_dlsym(m->dl, PA_SYMBOL_INIT))) { + pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.\n", name); goto fail; + } - if (!(m->done = (void (*)(struct pa_core *c, struct pa_module*m)) lt_dlsym(m->dl, "pa_module_done"))) + if (!(m->done = (void (*)(struct pa_core *c, struct pa_module*m)) lt_dlsym(m->dl, PA_SYMBOL_DONE))) { + pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_DONE"\" not found.\n", name); goto fail; + } m->userdata = NULL; m->core = c; @@ -80,8 +87,10 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char m->auto_unload = 0; assert(m->init); - if (m->init(c, m) < 0) + if (m->init(c, m) < 0) { + pa_log(__FILE__": Failed to load module \"%s\" (argument: \"%s\"): initialization failed.\n", name, argument ? argument : ""); goto fail; + } if (!c->modules) c->modules = pa_idxset_new(NULL, NULL); @@ -98,7 +107,7 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char r = pa_idxset_put(c->modules, m, &m->index); assert(r >= 0 && m->index != PA_IDXSET_INVALID); - pa_log(__FILE__": Loaded \"%s\" (index: #%u) with argument \"%s\".\n", m->name, m->index, m->argument); + pa_log(__FILE__": Loaded \"%s\" (index: #%u; argument: \"%s\").\n", m->name, m->index, m->argument ? m->argument : ""); pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_NEW, m->index); @@ -106,8 +115,6 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char fail: - pa_log(__FILE__": Failed to load \"%s\" with argument \"%s\".\n", name, argument); - if (m) { pa_xfree(m->argument); pa_xfree(m->name); @@ -239,3 +246,8 @@ void pa_module_set_used(struct pa_module*m, int used) { m->n_used = used; } +struct pa_modinfo *pa_module_get_info(struct pa_module *m) { + assert(m); + + return pa_modinfo_get_by_handle(m->dl); +} diff --git a/polyp/module.h b/polyp/module.h index acc08c3e..663e0246 100644 --- a/polyp/module.h +++ b/polyp/module.h @@ -26,6 +26,7 @@ #include #include "core.h" +#include "modinfo.h" struct pa_module { struct pa_core *core; @@ -53,10 +54,17 @@ void pa_module_unload_unused(struct pa_core *c); void pa_module_unload_request(struct pa_core *c, struct pa_module *m); -/* These to following prototypes are for module entrypoints and not implemented by the core */ -int pa_module_init(struct pa_core *c, struct pa_module*m); -void pa_module_done(struct pa_core *c, struct pa_module*m); - void pa_module_set_used(struct pa_module*m, int used); +/* prototypes for the module's entry points */ +int pa__init(struct pa_core *c, struct pa_module*m); +void pa__done(struct pa_core *c, struct pa_module*m); + +#define PA_MODULE_AUTHOR(s) const char *pa__get_author(void) { return s; } +#define PA_MODULE_DESCRIPTION(s) const char *pa__get_description(void) { return s; } +#define PA_MODULE_USAGE(s) const char *pa__get_usage(void) { return s; } +#define PA_MODULE_VERSION(s) const char *pa__get_version(void) { return s; } + +struct pa_modinfo *pa_module_get_info(struct pa_module *m); + #endif diff --git a/polyp/pamodinfo.c b/polyp/pamodinfo.c new file mode 100644 index 00000000..6eb147f0 --- /dev/null +++ b/polyp/pamodinfo.c @@ -0,0 +1,126 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "modinfo.h" + +#define PREFIX "module-" + +static int verbose = 0; + +static void short_info(const char *name, const char *path, struct pa_modinfo *i) { + assert(name && i); + printf("%-40s%s\n", name, i->description ? i->description : "n/a"); +} + +static void long_info(const char *name, const char *path, struct pa_modinfo *i) { + assert(name && i); + static int nl = 0; + + if (nl) + printf("\n"); + + nl = 1; + + printf("Name: %s\n", name); + + if (!i->description && !i->version && !i->author && !i->usage) + printf("No module information available\n"); + else { + if (i->version) + printf("Version: %s\n", i->version); + if (i->description) + printf("Description: %s\n", i->description); + if (i->author) + printf("Author: %s\n", i->author); + if (i->usage) + printf("Usage: %s\n", i->usage); + } + + if (path) + printf("Path: %s\n", path); +} + +static void show_info(const char *name, const char *path, void (*info)(const char *name, const char *path, struct pa_modinfo*i)) { + struct pa_modinfo *i; + + if ((i = pa_modinfo_get_by_name(path ? path : name))) { + info(name, path, i); + pa_modinfo_free(i); + } +} + +static int callback(const char *path, lt_ptr data) { + const char *e; + + if ((e = (const char*) strrchr(path, '/'))) + e++; + else + e = path; + + if (strlen(e) > sizeof(PREFIX)-1 && !strncmp(e, PREFIX, sizeof(PREFIX)-1)) + show_info(e, path, verbose ? long_info : short_info); + + return 0; +} + +int main(int argc, char *argv[]) { + int r = lt_dlinit(); + char *path = NULL; + int c; + assert(r == 0); + + while ((c = getopt(argc, argv, "p:v")) != -1) { + switch (c) { + case 'p': + path = optarg; + break; + case 'v': + verbose = 1; + break; + default: + return 1; + } + } + + if (path) + lt_dlsetsearchpath(path); +#ifdef DLSEARCHPATH + else + lt_dlsetsearchpath(DLSEARCHPATH); +#endif + + if (argc > optind) + show_info(argv[optind], NULL, long_info); + else + lt_dlforeachfile(NULL, callback, NULL); + + lt_dlexit(); +} -- cgit From f05a4ac806d8d44ab1377ea2069abb1da7ab9d16 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 12 Sep 2004 13:14:49 +0000 Subject: extend pa_usec_t to 64 bit git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@192 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 4 +--- polyp/cli-text.c | 8 ++++---- polyp/main.c | 2 ++ polyp/module-alsa-sink.c | 2 +- polyp/module-oss-mmap.c | 2 +- polyp/module-oss.c | 2 +- polyp/pacat.c | 2 +- polyp/polyplib-introspect.c | 8 ++++---- polyp/polyplib-stream.c | 4 ++-- polyp/protocol-esound.c | 6 +++--- polyp/protocol-native.c | 16 ++++++++-------- polyp/protocol-simple.c | 2 +- polyp/sample.c | 4 ++-- polyp/sample.h | 4 ++-- polyp/sink-input.h | 2 +- polyp/sink.h | 2 +- polyp/tagstruct.c | 26 ++++++++++++++++++++++++++ polyp/tagstruct.h | 2 ++ polyp/util.c | 6 +++--- 19 files changed, 66 insertions(+), 38 deletions(-) diff --git a/doc/todo b/doc/todo index c9be66ab..af54c692 100644 --- a/doc/todo +++ b/doc/todo @@ -13,13 +13,11 @@ - add sample directory - config file for command line arguments - option to use default fragment size on alsa drivers -- keep volume in xmms-polyp (and allow volume changing when not playing) - lazy sample cache - per-channel volume -- extend pa_usec_t to 64 bit -- make use of network latency in all apps - fix or work around libtool bug - merge pa_context_connect_* +- input latency ** later *** - xmlrpc/http diff --git a/polyp/cli-text.c b/polyp/cli-text.c index 18a99cfa..1d6711df 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -93,12 +93,12 @@ char *pa_sink_list_to_string(struct pa_core *c) { assert(sink->monitor_source); pa_strbuf_printf( s, - " %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%u usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", + " %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%f usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ', sink->index, sink->name, (unsigned) sink->volume, pa_volume_to_dB(sink->volume), - pa_sink_get_latency(sink), + (float) pa_sink_get_latency(sink), sink->monitor_source->index, ss); @@ -189,13 +189,13 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec); assert(i->sink); pa_strbuf_printf( - s, " index: %u\n\tname: <%s>\n\tsink: <%u>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%u usec>\n\tsample_spec: <%s>\n", + s, " index: %u\n\tname: <%s>\n\tsink: <%u>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%f usec>\n\tsample_spec: <%s>\n", i->index, i->name, i->sink->index, (unsigned) i->volume, pa_volume_to_dB(i->volume), - pa_sink_input_get_latency(i), + (float) pa_sink_input_get_latency(i), ss); if (i->owner) diff --git a/polyp/main.c b/polyp/main.c index 0218f396..a2b3d4c7 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -188,6 +188,8 @@ int main(int argc, char *argv[]) { lt_dlsetsearchpath(DLSEARCHPATH); #endif + pa_log(__FILE__": sizeof(pa_usec_t) = %u\n", sizeof(pa_usec_t)); + mainloop = pa_mainloop_new(); assert(mainloop); diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index 73c46ea0..95bb81f1 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -143,7 +143,7 @@ static void io_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, do_write(u); } -static uint32_t sink_get_latency_cb(struct pa_sink *s) { +static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { struct userdata *u = s->userdata; snd_pcm_sframes_t frames; assert(s && u && u->sink); diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index 4ffc56ef..8e165218 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -210,7 +210,7 @@ static void io_callback(struct pa_mainloop_api *m, struct pa_io_event *e, int fd do_write(u); } -static uint32_t sink_get_latency_cb(struct pa_sink *s) { +static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { struct userdata *u = s->userdata; assert(s && u); diff --git a/polyp/module-oss.c b/polyp/module-oss.c index 75d72e50..51cc42ef 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -161,7 +161,7 @@ static void io_callback(struct pa_iochannel *io, void*userdata) { do_read(u); } -static uint32_t sink_get_latency_cb(struct pa_sink *s) { +static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { int arg; struct userdata *u = s->userdata; assert(s && u && u->sink); diff --git a/polyp/pacat.c b/polyp/pacat.c index 0ad5fa52..ed95c2ca 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -286,7 +286,7 @@ static void stream_get_latency_callback(struct pa_stream *s, const struct pa_lat return; } - fprintf(stderr, "Current latency is %u usecs.\n", i->buffer_usec+i->sink_usec); + fprintf(stderr, "Current latency is %f usecs.\n", (float) (i->buffer_usec+i->sink_usec+i->transport_usec)); } /* Someone requested that the latency is shown */ diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index 2baeb540..e742c2db 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -130,7 +130,7 @@ static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t com pa_tagstruct_getu32(t, &i.volume) < 0 || pa_tagstruct_getu32(t, &i.monitor_source) < 0 || pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || - pa_tagstruct_getu32(t, &i.latency) < 0) { + pa_tagstruct_get_usec(t, &i.latency) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } @@ -446,8 +446,8 @@ static void context_get_sink_input_info_callback(struct pa_pdispatch *pd, uint32 pa_tagstruct_getu32(t, &i.sink) < 0 || pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || pa_tagstruct_getu32(t, &i.volume) < 0 || - pa_tagstruct_getu32(t, &i.buffer_usec) < 0 || - pa_tagstruct_getu32(t, &i.sink_usec) < 0) { + pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || + pa_tagstruct_get_usec(t, &i.sink_usec) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } @@ -648,7 +648,7 @@ static void context_get_sample_info_callback(struct pa_pdispatch *pd, uint32_t c if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_getu32(t, &i.volume) < 0 || - pa_tagstruct_getu32(t, &i.duration) < 0 || + pa_tagstruct_get_usec(t, &i.duration) < 0 || pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || pa_tagstruct_getu32(t, &i.bytes) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index e128a773..98610d61 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -333,8 +333,8 @@ static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t comman if (pa_context_handle_error(o->context, command, t) < 0) goto finish; - } else if (pa_tagstruct_getu32(t, &i.buffer_usec) < 0 || - pa_tagstruct_getu32(t, &i.sink_usec) < 0 || + } else if (pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || + pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || pa_tagstruct_get_boolean(t, &i.playing) < 0 || pa_tagstruct_getu32(t, &i.queue_length) < 0 || pa_tagstruct_get_timeval(t, &local) < 0 || diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 3f87d4d0..178ba009 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -106,7 +106,7 @@ typedef struct proto_handler { static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length); static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk); static void sink_input_kill_cb(struct pa_sink_input *i); -static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i); +static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i); static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk); static void source_output_kill_cb(struct pa_source_output *o); @@ -385,7 +385,7 @@ static int esd_proto_get_latency(struct connection *c, esd_proto_t request, cons if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) latency = 0; else { - float usec = pa_sink_get_latency(sink); + double usec = pa_sink_get_latency(sink); usec += PLAYBACK_BUFFER_SECONDS*1000000; /* A better estimation would be a good idea! */ latency = (int) ((usec*44100)/1000000); } @@ -914,7 +914,7 @@ static void sink_input_kill_cb(struct pa_sink_input *i) { } -static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { +static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i) { struct connection*c = i->userdata; assert(i && c); return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 058ba9cc..3056f7c4 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -110,7 +110,7 @@ struct pa_protocol_native { static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk); static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length); static void sink_input_kill_cb(struct pa_sink_input *i); -static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i); +static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i); static void request_bytes(struct playback_stream*s); @@ -455,7 +455,7 @@ static void sink_input_kill_cb(struct pa_sink_input *i) { playback_stream_free((struct playback_stream *) i->userdata); } -static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { +static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i) { struct playback_stream *s; assert(i && i->userdata); s = i->userdata; @@ -835,8 +835,8 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma assert(reply); pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); pa_tagstruct_putu32(reply, tag); - pa_tagstruct_putu32(reply, pa_sink_input_get_latency(s->sink_input)); - pa_tagstruct_putu32(reply, pa_sink_get_latency(s->sink_input->sink)); + pa_tagstruct_put_usec(reply, pa_sink_input_get_latency(s->sink_input)); + pa_tagstruct_put_usec(reply, pa_sink_get_latency(s->sink_input->sink)); pa_tagstruct_put_boolean(reply, pa_memblockq_is_readable(s->memblockq)); pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq)); pa_tagstruct_put_timeval(reply, &tv); @@ -994,7 +994,7 @@ static void sink_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink *sink) { pa_tagstruct_putu32(t, sink->volume); pa_tagstruct_putu32(t, sink->monitor_source->index); pa_tagstruct_puts(t, sink->monitor_source->name); - pa_tagstruct_putu32(t, pa_sink_get_latency(sink)); + pa_tagstruct_put_usec(t, pa_sink_get_latency(sink)); } static void source_fill_tagstruct(struct pa_tagstruct *t, struct pa_source *source) { @@ -1034,8 +1034,8 @@ static void sink_input_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink_inp pa_tagstruct_putu32(t, s->sink->index); pa_tagstruct_put_sample_spec(t, &s->sample_spec); pa_tagstruct_putu32(t, s->volume); - pa_tagstruct_putu32(t, pa_sink_input_get_latency(s)); - pa_tagstruct_putu32(t, pa_sink_get_latency(s->sink)); + pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s)); + pa_tagstruct_put_usec(t, pa_sink_get_latency(s->sink)); } static void source_output_fill_tagstruct(struct pa_tagstruct *t, struct pa_source_output *s) { @@ -1053,7 +1053,7 @@ static void scache_fill_tagstruct(struct pa_tagstruct *t, struct pa_scache_entry pa_tagstruct_putu32(t, e->index); pa_tagstruct_puts(t, e->name); pa_tagstruct_putu32(t, e->volume); - pa_tagstruct_putu32(t, pa_bytes_to_usec(e->memchunk.length, &e->sample_spec)); + pa_tagstruct_put_usec(t, pa_bytes_to_usec(e->memchunk.length, &e->sample_spec)); pa_tagstruct_put_sample_spec(t, &e->sample_spec); pa_tagstruct_putu32(t, e->memchunk.length); } diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index f6240462..00db0aa0 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -220,7 +220,7 @@ static void sink_input_kill_cb(struct pa_sink_input *i) { } -static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { +static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i) { struct connection*c = i->userdata; assert(i && c); return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); diff --git a/polyp/sample.c b/polyp/sample.c index 747acf18..dfe98e3f 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -59,10 +59,10 @@ size_t pa_bytes_per_second(const struct pa_sample_spec *spec) { return spec->rate*pa_frame_size(spec); } -uint32_t pa_bytes_to_usec(size_t length, const struct pa_sample_spec *spec) { +pa_usec_t pa_bytes_to_usec(size_t length, const struct pa_sample_spec *spec) { assert(spec); - return (uint32_t) (((double) length/pa_frame_size(spec)*1000000)/spec->rate); + return (pa_usec_t) (((double) length/pa_frame_size(spec)*1000000)/spec->rate); } int pa_sample_spec_valid(const struct pa_sample_spec *spec) { diff --git a/polyp/sample.h b/polyp/sample.h index 0141a7cd..1e42a260 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -67,8 +67,8 @@ struct pa_sample_spec { uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */ }; -/** Type for usec specifications */ -typedef uint32_t pa_usec_t; +/** Type for usec specifications. May be either 32 or 64 bit, depending on the architecture */ +typedef uint64_t pa_usec_t; /** Return the amount of bytes playback of a second of audio with the speicified sample type takes */ size_t pa_bytes_per_second(const struct pa_sample_spec *spec); diff --git a/polyp/sink-input.h b/polyp/sink-input.h index df6ead6b..e2478ed6 100644 --- a/polyp/sink-input.h +++ b/polyp/sink-input.h @@ -46,7 +46,7 @@ struct pa_sink_input { int (*peek) (struct pa_sink_input *i, struct pa_memchunk *chunk); void (*drop) (struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length); void (*kill) (struct pa_sink_input *i); - uint32_t (*get_latency) (struct pa_sink_input *i); + pa_usec_t (*get_latency) (struct pa_sink_input *i); void *userdata; diff --git a/polyp/sink.h b/polyp/sink.h index 85addf76..881e75d3 100644 --- a/polyp/sink.h +++ b/polyp/sink.h @@ -47,7 +47,7 @@ struct pa_sink { pa_volume_t volume; void (*notify)(struct pa_sink*sink); - uint32_t (*get_latency)(struct pa_sink *s); + pa_usec_t (*get_latency)(struct pa_sink *s); void *userdata; }; diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c index 55132cae..52db0fe3 100644 --- a/polyp/tagstruct.c +++ b/polyp/tagstruct.c @@ -39,11 +39,14 @@ enum tags { TAG_S16 = 's', TAG_U8 = 'B', TAG_S8 = 'b', + TAG_U64 = 'R', + TAG_S64 = 'r', TAG_SAMPLE_SPEC = 'a', TAG_ARBITRARY = 'x', TAG_BOOLEAN_TRUE = '1', TAG_BOOLEAN_FALSE = '0', TAG_TIMEVAL = 'T', + TAG_USEC = 'U', /* 64bit unsigned */ }; struct pa_tagstruct { @@ -155,6 +158,15 @@ void pa_tagstruct_put_timeval(struct pa_tagstruct*t, const struct timeval *tv) { t->length += 9; } +void pa_tagstruct_put_usec(struct pa_tagstruct*t, pa_usec_t u) { + assert(t); + extend(t, 9); + t->data[t->length] = TAG_USEC; + *((uint32_t*) (t->data+t->length+1)) = htonl((uint32_t) (u >> 32)); + *((uint32_t*) (t->data+t->length+5)) = htonl((uint32_t) u); + t->length += 9; +} + int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s) { int error = 0; size_t n; @@ -288,3 +300,17 @@ int pa_tagstruct_get_timeval(struct pa_tagstruct*t, struct timeval *tv) { } +int pa_tagstruct_get_usec(struct pa_tagstruct*t, pa_usec_t *u) { + assert(t && u); + + if (t->rindex+9 > t->length) + return -1; + + if (t->data[t->rindex] != TAG_USEC) + return -1; + + *u = (pa_usec_t) ntohl(*((uint32_t*) (t->data+t->rindex+1))) << 32; + *u |= (pa_usec_t) ntohl(*((uint32_t*) (t->data+t->rindex+5))); + t->rindex +=9; + return 0; +} diff --git a/polyp/tagstruct.h b/polyp/tagstruct.h index 915a9a65..02df74e4 100644 --- a/polyp/tagstruct.h +++ b/polyp/tagstruct.h @@ -40,6 +40,7 @@ void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample void pa_tagstruct_put_arbitrary(struct pa_tagstruct*t, const void *p, size_t length); void pa_tagstruct_put_boolean(struct pa_tagstruct*t, int b); void pa_tagstruct_put_timeval(struct pa_tagstruct*t, const struct timeval *tv); +void pa_tagstruct_put_usec(struct pa_tagstruct*t, pa_usec_t u); int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s); int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i); @@ -48,6 +49,7 @@ int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec * int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t length); int pa_tagstruct_get_boolean(struct pa_tagstruct *t, int *b); int pa_tagstruct_get_timeval(struct pa_tagstruct*t, struct timeval *tv); +int pa_tagstruct_get_usec(struct pa_tagstruct*t, pa_usec_t *u); int pa_tagstruct_eof(struct pa_tagstruct*t); const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l); diff --git a/polyp/util.c b/polyp/util.c index eeb1d192..45e1b605 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -232,12 +232,12 @@ pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { b = c; } - r = (a->tv_sec - b->tv_sec)* 1000000; + r = ((pa_usec_t) a->tv_sec - b->tv_sec)* 1000000; if (a->tv_usec > b->tv_usec) - r += (a->tv_usec - b->tv_usec); + r += ((pa_usec_t) a->tv_usec - b->tv_usec); else if (a->tv_usec < b->tv_usec) - r -= (b->tv_usec - a->tv_usec); + r -= ((pa_usec_t) b->tv_usec - a->tv_usec); return r; } -- cgit From b772564a4eeab6d32ba9b7be9fb9beed1c12c999 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 12 Sep 2004 19:37:04 +0000 Subject: update simple API git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@193 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + polyp/cli-text.c | 4 +- polyp/pacat-simple.c | 11 +++++ polyp/polyplib-simple.c | 112 ++++++++++++++++++++++++++++++++++++++++++++---- polyp/polyplib-simple.h | 6 +++ polyp/util.c | 25 +++++++++++ polyp/util.h | 3 ++ 7 files changed, 152 insertions(+), 10 deletions(-) diff --git a/doc/todo b/doc/todo index af54c692..2509f76b 100644 --- a/doc/todo +++ b/doc/todo @@ -18,6 +18,7 @@ - fix or work around libtool bug - merge pa_context_connect_* - input latency +- check if all mainloop stuff works still ** later *** - xmlrpc/http diff --git a/polyp/cli-text.c b/polyp/cli-text.c index 1d6711df..2a48d576 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -93,7 +93,7 @@ char *pa_sink_list_to_string(struct pa_core *c) { assert(sink->monitor_source); pa_strbuf_printf( s, - " %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%f usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", + " %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ', sink->index, sink->name, (unsigned) sink->volume, @@ -189,7 +189,7 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec); assert(i->sink); pa_strbuf_printf( - s, " index: %u\n\tname: <%s>\n\tsink: <%u>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%f usec>\n\tsample_spec: <%s>\n", + s, " index: %u\n\tname: <%s>\n\tsink: <%u>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n", i->index, i->name, i->sink->index, diff --git a/polyp/pacat-simple.c b/polyp/pacat-simple.c index f5b696a8..956728fb 100644 --- a/polyp/pacat-simple.c +++ b/polyp/pacat-simple.c @@ -56,6 +56,17 @@ int main(int argc, char*argv[]) { uint8_t buf[BUFSIZE]; ssize_t r; +#if 0 + pa_usec_t latency; + + if ((latency = pa_simple_get_playback_latency(s, &error)) == (pa_usec_t) -1) { + fprintf(stderr, __FILE__": pa_simple_get_playback_latency() failed: %s\n", pa_strerror(error)); + goto finish; + } + + fprintf(stderr, "%0.0f usec \r", (float)latency); +#endif + /* Read some data ... */ if ((r = read(STDIN_FILENO, buf, sizeof(buf))) <= 0) { if (r == 0) /* EOF */ diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c index 8caae87e..1ac08869 100644 --- a/polyp/polyplib-simple.c +++ b/polyp/polyplib-simple.c @@ -41,10 +41,11 @@ struct pa_simple { struct pa_stream *stream; enum pa_stream_direction direction; - int dead, drained; + int dead; void *read_data; size_t read_index, read_length; + pa_usec_t latency; }; static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata); @@ -71,6 +72,9 @@ static int check_error(struct pa_simple *p, int *perror) { fail: if (perror) *perror = pa_context_errno(p->context); + + p->dead = 1; + return -1; } @@ -121,6 +125,7 @@ struct pa_simple* pa_simple_new( p->direction = dir; p->read_data = NULL; p->read_index = p->read_length = 0; + p->latency = 0; if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name))) goto fail; @@ -178,6 +183,13 @@ void pa_simple_free(struct pa_simple *s) { int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *perror) { assert(p && data && p->direction == PA_STREAM_PLAYBACK); + if (p->dead) { + if (perror) + *perror = pa_context_errno(p->context); + + return -1; + } + while (length > 0) { size_t l; @@ -216,6 +228,13 @@ static void read_callback(struct pa_stream *s, const void*data, size_t length, v int pa_simple_read(struct pa_simple *p, void*data, size_t length, int *perror) { assert(p && data && p->direction == PA_STREAM_RECORD); + if (p->dead) { + if (perror) + *perror = pa_context_errno(p->context); + + return -1; + } + while (length > 0) { if (p->read_data) { size_t l = length; @@ -250,20 +269,97 @@ int pa_simple_read(struct pa_simple *p, void*data, size_t length, int *perror) { return 0; } -static void drain_complete(struct pa_stream *s, int success, void *userdata) { +static void drain_or_flush_complete(struct pa_stream *s, int success, void *userdata) { struct pa_simple *p = userdata; assert(s && p); - p->drained = success ? 1 : -1; + if (!success) + p->dead = 1; } int pa_simple_drain(struct pa_simple *p, int *perror) { struct pa_operation *o; + assert(p && p->direction == PA_STREAM_PLAYBACK); + + if (p->dead) { + if (perror) + *perror = pa_context_errno(p->context); + + return -1; + } + + o = pa_stream_drain(p->stream, drain_or_flush_complete, p); + + while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { + if (iterate(p, 1, perror) < 0) { + pa_operation_cancel(o); + pa_operation_unref(o); + return -1; + } + } + + pa_operation_unref(o); + + if (p->dead && perror) + *perror = pa_context_errno(p->context); + + return p->dead ? -1 : 0; +} + +static void latency_complete(struct pa_stream *s, const struct pa_latency_info *l, void *userdata) { + struct pa_simple *p = userdata; + assert(s && p); + + if (!l) + p->dead = 1; + else + p->latency = l->buffer_usec + l->sink_usec + l->transport_usec; +} + +pa_usec_t pa_simple_get_playback_latency(struct pa_simple *p, int *perror) { + struct pa_operation *o; + assert(p && p->direction == PA_STREAM_PLAYBACK); + + if (p->dead) { + if (perror) + *perror = pa_context_errno(p->context); + + return (pa_usec_t) -1; + } + + p->latency = 0; + o = pa_stream_get_latency(p->stream, latency_complete, p); + while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { + + if (iterate(p, 1, perror) < 0) { + pa_operation_cancel(o); + pa_operation_unref(o); + return -1; + } + } + + pa_operation_unref(o); + + if (p->dead && perror) + *perror = pa_context_errno(p->context); + + return p->dead ? (pa_usec_t) -1 : p->latency; +} + +int pa_simple_flush(struct pa_simple *p, int *perror) { + struct pa_operation *o; assert(p && p->direction == PA_STREAM_PLAYBACK); - p->drained = 0; - o = pa_stream_drain(p->stream, drain_complete, p); - while (!p->drained) { + if (p->dead) { + if (perror) + *perror = pa_context_errno(p->context); + + return -1; + } + + o = pa_stream_flush(p->stream, drain_or_flush_complete, p); + + while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { if (iterate(p, 1, perror) < 0) { pa_operation_cancel(o); pa_operation_unref(o); @@ -273,8 +369,8 @@ int pa_simple_drain(struct pa_simple *p, int *perror) { pa_operation_unref(o); - if (p->drained < 0 && perror) + if (p->dead && perror) *perror = pa_context_errno(p->context); - return 0; + return p->dead ? -1 : 0; } diff --git a/polyp/polyplib-simple.h b/polyp/polyplib-simple.h index ed552cb4..b37bdec6 100644 --- a/polyp/polyplib-simple.h +++ b/polyp/polyplib-simple.h @@ -69,6 +69,12 @@ int pa_simple_drain(struct pa_simple *s, int *error); /** Read some data from the server */ int pa_simple_read(struct pa_simple *s, void*data, size_t length, int *error); +/** Return the playback latency. \since 0.5 */ +pa_usec_t pa_simple_get_playback_latency(struct pa_simple *s, int *perror); + +/** Flush the playback buffer. \since 0.5 */ +int pa_simple_flush(struct pa_simple *s, int *perror); + PA_C_DECL_END #endif diff --git a/polyp/util.c b/polyp/util.c index 45e1b605..1dbb8697 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "util.h" #include "xmalloc.h" @@ -322,3 +323,27 @@ int pa_fd_set_cloexec(int fd, int b) { return 0; } + +char *pa_get_binary_name(char *s, size_t l) { + char path[PATH_MAX]; + int i; + assert(s && l); + + /* This works on Linux only */ + + snprintf(path, sizeof(path), "/proc/%u/exe", (unsigned) getpid()); + if ((i = readlink(path, s, l-1)) < 0) + return NULL; + + s[i] = 0; + return s; +} + +char *pa_path_get_filename(const char *p) { + char *fn; + + if ((fn = strrchr(p, '/'))) + return fn+1; + + return (char*) p; +} diff --git a/polyp/util.h b/polyp/util.h index adc4429b..f34ba4c0 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -43,6 +43,9 @@ char *pa_vsprintf_malloc(const char *format, va_list ap); char *pa_get_user_name(char *s, size_t l); char *pa_get_host_name(char *s, size_t l); +char *pa_get_binary_name(char *s, size_t l); + +char *pa_path_get_filename(const char *p); pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); -- cgit From b681622b17e23878cdd0683fdf57dcc35c562c43 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 12 Sep 2004 23:29:54 +0000 Subject: build system update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@194 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 20 +++++-- doc/todo | 4 +- polyp/Makefile.am | 144 ++++++++++++++++++++++++++++++------------------ polyp/protocol-esound.c | 2 +- 4 files changed, 109 insertions(+), 61 deletions(-) diff --git a/configure.ac b/configure.ac index 08b1f324..62dc37d4 100644 --- a/configure.ac +++ b/configure.ac @@ -47,7 +47,11 @@ AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h limits.h malloc.h netdb.h netin ACX_PTHREAD AC_PATH_XTRA -AM_CONDITIONAL(X_DISPLAY_MISSING, test "x$X_DISPLAY_MISSING" != "x") + +HAVE_X11=0 +test "x$no_x" != "xyes" && HAVE_X11=1 +AC_SUBST(HAVE_X11) +AM_CONDITIONAL(HAVE_X11, test "x$no_x" != "xyes") # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST @@ -81,17 +85,23 @@ PKG_CHECK_MODULES(LIBSNDFILE, [ sndfile >= 1.0.0 ]) AC_SUBST(LIBSNDFILE_CFLAGS) AC_SUBST(LIBSNDFILE_LIBS) -PKG_CHECK_MODULES(ASOUNDLIB, [ alsa >= 1.0.0 ]) +PKG_CHECK_MODULES(ASOUNDLIB, [ alsa >= 1.0.0 ], [HAVE_ALSA=1], [HAVE_ALSA=0]) AC_SUBST(ASOUNDLIB_CFLAGS) -AC_SUBST(ASOUNDLIB_LIBS) +AC_SUBST(ASOUNDLIB_LIBS) +AC_SUBST(HAVE_ALSA) +AM_CONDITIONAL([HAVE_ALSA], [test "x$HAVE_ALSA" = x1]) -PKG_CHECK_MODULES(GLIB20, [ glib-2.0 >= 2.4.0 ]) +PKG_CHECK_MODULES(GLIB20, [ glib-2.0 >= 2.4.0 ], HAVE_GLIB20=1, HAVE_GLIB20=0) AC_SUBST(GLIB20_CFLAGS) AC_SUBST(GLIB20_LIBS) +AC_SUBST(HAVE_GLIB20) +AM_CONDITIONAL([HAVE_GLIB20], [test "x$HAVE_GLIB20" = x1]) -PKG_CHECK_MODULES(GLIB12, [ glib >= 1.2.0 ]) +PKG_CHECK_MODULES(GLIB12, [ glib >= 1.2.0 ], HAVE_GLIB12=1, HAVE_GLIB12=0) AC_SUBST(GLIB12_CFLAGS) AC_SUBST(GLIB12_LIBS) +AC_SUBST(HAVE_GLIB12) +AM_CONDITIONAL([HAVE_GLIB12], [test "x$HAVE_GLIB12" = x1]) # If using GCC specifiy some additional parameters if test "x$GCC" = "xyes" ; then diff --git a/doc/todo b/doc/todo index 2509f76b..f0afd106 100644 --- a/doc/todo +++ b/doc/todo @@ -18,7 +18,9 @@ - fix or work around libtool bug - merge pa_context_connect_* - input latency -- check if all mainloop stuff works still +- fix public= +- fix POLYP_SERVER=foo:4711 +- fix tcp/native ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 9cb8c4ba..3f94c052 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -33,13 +33,19 @@ AM_LIBADD=$(PTHREAD_LIBS) -lm EXTRA_DIST = polypaudio.pa depmod.py esdcompat.sh.in bin_PROGRAMS = polypaudio pacat pactl pamodinfo bin_SCRIPTS = esdcompat.sh -noinst_PROGRAMS = mainloop-test mainloop-test-glib mainloop-test-glib12 pacat-simple parec-simple cpulimit-test cpulimit-test2 +noinst_PROGRAMS = \ + mainloop-test \ + pacat-simple \ + parec-simple \ + cpulimit-test \ + cpulimit-test2 polypconf_DATA=polypaudio.pa BUILT_SOURCES=polyplib-version.h -polypinclude_HEADERS=polyplib.h \ +polypinclude_HEADERS= \ + polyplib.h \ polyplib-def.h \ polyplib-simple.h \ polyplib-error.h \ @@ -57,13 +63,14 @@ polypinclude_HEADERS=polyplib.h \ sample.h \ glib-mainloop.h -modlib_LTLIBRARIES=libiochannel.la \ +modlib_LTLIBRARIES= \ + libsocket-util.la \ + libiochannel.la \ libsocket-server.la \ libsocket-client.la \ - libpstream.la \ libpacket.la \ + libpstream.la \ liboss-util.la \ - libalsa-util.la \ libioline.la \ libcli.la \ libprotocol-cli.la \ @@ -71,7 +78,6 @@ modlib_LTLIBRARIES=libiochannel.la \ libpstream-util.la \ libpdispatch.la \ libauthkey.la \ - libsocket-util.la \ libprotocol-simple.la \ libprotocol-esound.la \ libprotocol-native.la \ @@ -80,8 +86,6 @@ modlib_LTLIBRARIES=libiochannel.la \ module-cli-protocol-unix.la \ module-pipe-sink.la \ module-pipe-source.la \ - module-alsa-sink.la \ - module-alsa-source.la \ module-oss.la \ module-oss-mmap.la \ module-simple-protocol-tcp.la \ @@ -93,15 +97,10 @@ modlib_LTLIBRARIES=libiochannel.la \ module-native-protocol-fd.la \ module-sine.la -if !X_DISPLAY_MISSING -modlib_LTLIBRARIES+=module-x11-bell.la -endif - -lib_LTLIBRARIES=libpolyp-@PA_MAJORMINOR@.la \ +lib_LTLIBRARIES= \ + libpolyp-@PA_MAJORMINOR@.la \ libpolyp-error-@PA_MAJORMINOR@.la \ libpolyp-mainloop-@PA_MAJORMINOR@.la \ - libpolyp-mainloop-glib-@PA_MAJORMINOR@.la \ - libpolyp-mainloop-glib12-@PA_MAJORMINOR@.la \ libpolyp-simple-@PA_MAJORMINOR@.la polypaudio_SOURCES = idxset.c idxset.h \ @@ -196,11 +195,6 @@ libpacket_la_LDFLAGS = -avoid-version liboss_util_la_SOURCES = oss-util.c oss-util.h liboss_util_la_LDFLAGS = -avoid-version -libalsa_util_la_SOURCES = alsa-util.c alsa-util.h -libalsa_util_la_LDFLAGS = -avoid-version -libalsa_util_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) -libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) - libioline_la_SOURCES = ioline.c ioline.h libioline_la_LDFLAGS = -avoid-version libioline_la_LIBADD = $(AM_LIBADD) libiochannel.la @@ -283,16 +277,6 @@ module_pipe_source_la_SOURCES = module-pipe-source.c module_pipe_source_la_LDFLAGS = -module -avoid-version module_pipe_source_la_LIBADD = $(AM_LIBADD) libiochannel.la -module_alsa_sink_la_SOURCES = module-alsa-sink.c -module_alsa_sink_la_LDFLAGS = -module -avoid-version -module_alsa_sink_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la -module_alsa_sink_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) - -module_alsa_source_la_SOURCES = module-alsa-source.c -module_alsa_source_la_LDFLAGS = -module -avoid-version -module_alsa_source_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la -module_alsa_source_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) - module_oss_la_SOURCES = module-oss.c module_oss_la_LDFLAGS = -module -avoid-version module_oss_la_LIBADD = $(AM_LIBADD) libiochannel.la liboss-util.la @@ -309,13 +293,6 @@ module_sine_la_SOURCES = module-sine.c module_sine_la_LDFLAGS = -module -avoid-version module_sine_la_LIBADD = $(AM_LIBADD) -if !X_DISPLAY_MISSING -module_x11_bell_la_SOURCES = module-x11-bell.c -module_x11_bell_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) -module_x11_bell_la_LDFLAGS = -module -avoid-version -module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) -endif - libpolyp_@PA_MAJORMINOR@_la_SOURCES = polyplib.h \ polyplib-def.h \ tagstruct.c tagstruct.h \ @@ -369,16 +346,6 @@ libpolyp_simple_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) libpolyp_simple_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp_simple_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 -libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_SOURCES = glib-mainloop.h glib-mainloop.c -libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) -libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop-@PA_MAJORMINOR@.la $(GLIB20_LIBS) -libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 - -libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_SOURCES = glib-mainloop.h glib12-mainloop.c -libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS) -libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop-@PA_MAJORMINOR@.la $(GLIB12_LIBS) -libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 - pacat_SOURCES = pacat.c pacat_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la pacat_CFLAGS = $(AM_CFLAGS) @@ -399,22 +366,90 @@ mainloop_test_SOURCES = mainloop-test.c mainloop_test_CFLAGS = $(AM_CFLAGS) mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-@PA_MAJORMINOR@.la +cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c log.c +cpulimit_test_CFLAGS = $(AM_CFLAGS) +cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la + +cpulimit_test2_SOURCES = cpulimit-test.c cpulimit.c util.c log.c +cpulimit_test2_CFLAGS = $(AM_CFLAGS) -DTEST2 +cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la + +### X11 stuff + +if HAVE_X11 +modlib_LTLIBRARIES+= \ + module-x11-bell.la + +module_x11_bell_la_SOURCES = module-x11-bell.c +module_x11_bell_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) +module_x11_bell_la_LDFLAGS = -module -avoid-version +module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) +endif + +### ALSA modules + +if HAVE_ALSA +modlib_LTLIBRARIES+= \ + libalsa-util.la \ + module-alsa-sink.la \ + module-alsa-source.la + +libalsa_util_la_SOURCES = alsa-util.c alsa-util.h +libalsa_util_la_LDFLAGS = -avoid-version +libalsa_util_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) +libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) + +module_alsa_sink_la_SOURCES = module-alsa-sink.c +module_alsa_sink_la_LDFLAGS = -module -avoid-version +module_alsa_sink_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la +module_alsa_sink_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) + +module_alsa_source_la_SOURCES = module-alsa-source.c +module_alsa_source_la_LDFLAGS = -module -avoid-version +module_alsa_source_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la +module_alsa_source_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) +endif + +### GLIB 2.0 support + +if HAVE_GLIB20 +lib_LTLIBRARIES+= \ + libpolyp-mainloop-glib-@PA_MAJORMINOR@.la + +noinst_PROGRAMS+= \ + mainloop-test-glib12 + +libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_SOURCES = glib-mainloop.h glib-mainloop.c +libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) +libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop-@PA_MAJORMINOR@.la $(GLIB20_LIBS) +libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 + mainloop_test_glib_SOURCES = $(mainloop_test_SOURCES) mainloop_test_glib_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB20_CFLAGS) -DGLIB_MAIN_LOOP mainloop_test_glib_LDADD = $(mainloop_test_LDADD) $(GLIB20_LIBS) libpolyp-mainloop-glib-@PA_MAJORMINOR@.la +endif + +### GLIB 1.2 support + +if HAVE_GLIB12 + +lib_LTLIBRARIES+= \ + libpolyp-mainloop-glib12-@PA_MAJORMINOR@.la + +noinst_PROGRAMS+= \ + mainloop-test-glib +libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_SOURCES = glib-mainloop.h glib12-mainloop.c +libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS) +libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop-@PA_MAJORMINOR@.la $(GLIB12_LIBS) +libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 mainloop_test_glib12_SOURCES = $(mainloop_test_SOURCES) mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MAIN_LOOP mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12-@PA_MAJORMINOR@.la -cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c log.c -cpulimit_test_CFLAGS = $(AM_CFLAGS) -cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la - -cpulimit_test2_SOURCES = cpulimit-test.c cpulimit.c util.c log.c -cpulimit_test2_CFLAGS = $(AM_CFLAGS) -DTEST2 -cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la +endif +### libpolypcore (needs to be updated) if BUILD_LIBPOLYPCORE @@ -485,6 +520,7 @@ libpolypcore_la_SOURCES = idxset.c idxset.h \ endif +### Some minor stuff suid: polypaudio chown root:root $< diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 178ba009..755ec21d 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -905,7 +905,7 @@ static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); c->protocol->core->mainloop->defer_enable(c->defer_event, 1); - assert(pa_memblockq_get_length(c->input_memblockq) > 2048); +/* assert(pa_memblockq_get_length(c->input_memblockq) > 2048); */ } static void sink_input_kill_cb(struct pa_sink_input *i) { -- cgit From b1ab6869fbe705f06faa12310c76b7d856030d81 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 12 Sep 2004 23:40:53 +0000 Subject: fix public= on native and esound protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@195 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + polyp/protocol-esound.c | 8 +++++++- polyp/protocol-native.c | 17 ++++++++++------- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/doc/todo b/doc/todo index f0afd106..f9d9bedc 100644 --- a/doc/todo +++ b/doc/todo @@ -21,6 +21,7 @@ - fix public= - fix POLYP_SERVER=foo:4711 - fix tcp/native +- suid ** later *** - xmlrpc/http diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 755ec21d..ee64c484 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -995,17 +995,23 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { struct pa_protocol_esound *p; + int public; assert(core && server && ma); p = pa_xmalloc(sizeof(struct pa_protocol_esound)); + if (pa_modargs_get_value_boolean(ma, "public", &public) < 0) { + pa_log(__FILE__": public= expects a boolean argument.\n"); + return NULL; + } + if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", DEFAULT_COOKIE_FILE), p->esd_key, sizeof(p->esd_key)) < 0) { pa_xfree(p); return NULL; } p->module = m; - p->public = 0; + p->public = public; p->server = server; pa_socket_server_set_callback(p->server, on_connection, p); p->core = core; diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 3056f7c4..2d26c2f5 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -674,14 +674,17 @@ static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag protocol_error(c); return; } + + if (!c->authorized) { + if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) != 0) { + pa_log(__FILE__": Denied access to client with invalid authorization key.\n"); + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } - if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) != 0) { - pa_log(__FILE__": Denied access to client with invalid authorization key.\n"); - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; + c->authorized = 1; } - - c->authorized = 1; + pa_pstream_send_simple_ack(c->pstream, tag); return; } @@ -1547,7 +1550,7 @@ static struct pa_protocol_native* protocol_new_internal(struct pa_core *c, struc assert(c && ma); if (pa_modargs_get_value_boolean(ma, "public", &public) < 0) { - pa_log(__FILE__": public= expects numeric argument.\n"); + pa_log(__FILE__": public= expects a boolean argument.\n"); return NULL; } -- cgit From 12315982066ee1044840b598624920f8028c7924 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 13 Sep 2004 00:28:16 +0000 Subject: fix parsing of POLYP_SERVER environment variable git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@196 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 --- polyp/Makefile.am | 5 +++++ polyp/polyplib-context.c | 8 ++++++-- polyp/socket-client.c | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/doc/todo b/doc/todo index f9d9bedc..c09d423a 100644 --- a/doc/todo +++ b/doc/todo @@ -15,11 +15,8 @@ - option to use default fragment size on alsa drivers - lazy sample cache - per-channel volume -- fix or work around libtool bug - merge pa_context_connect_* - input latency -- fix public= -- fix POLYP_SERVER=foo:4711 - fix tcp/native - suid diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 3f94c052..99c89491 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -63,6 +63,11 @@ polypinclude_HEADERS= \ sample.h \ glib-mainloop.h +### Warning! Due to an obscure bug in libtool/automake it is required +### that the libraries in modlib_LTLIBRARIES are specified in-order, +### i.e. libraries near the end of the list depend on libraries near +### the head, and not the other way! + modlib_LTLIBRARIES= \ libsocket-util.la \ libiochannel.la \ diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index a15e4257..63b42eb3 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -336,11 +336,15 @@ finish: static struct sockaddr *resolve_server(const char *server, size_t *len) { struct sockaddr *sa; struct addrinfo hints, *result = NULL; - char *port; + char *port, host[256]; assert(server && len); + snprintf(host, sizeof(host), "%s", server); + host[strcspn(host, ":")] = 0; + if ((port = strrchr(server, ':'))) port++; + if (!port) port = DEFAULT_PORT; @@ -349,7 +353,7 @@ static struct sockaddr *resolve_server(const char *server, size_t *len) { hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; - if (getaddrinfo(server, port, &hints, &result) != 0) + if (getaddrinfo(host, port, &hints, &result) != 0) return NULL; assert(result); diff --git a/polyp/socket-client.c b/polyp/socket-client.c index 773e922c..fbc259ff 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -84,7 +84,7 @@ static void do_call(struct pa_socket_client *c) { } if (error != 0) { - pa_log(__FILE__": connect(): %s\n", strerror(error)); +/* pa_log(__FILE__": connect(): %s\n", strerror(error)); */ goto finish; } -- cgit From fbefe67d52eb89a429505c653d1ea4ce73d4f4e7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 13 Sep 2004 13:26:44 +0000 Subject: correct latency calculation git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@197 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + polyp/module-alsa-sink.c | 8 +++++++- polyp/module-oss.c | 8 +++++++- polyp/sink-input.c | 8 ++++++-- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/doc/todo b/doc/todo index c09d423a..61cee844 100644 --- a/doc/todo +++ b/doc/todo @@ -19,6 +19,7 @@ - input latency - fix tcp/native - suid +- add volume to create_stream command in native protocol ** later *** - xmlrpc/http diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index 95bb81f1..55e719c9 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -144,6 +144,7 @@ static void io_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, } static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { + pa_usec_t r = 0; struct userdata *u = s->userdata; snd_pcm_sframes_t frames; assert(s && u && u->sink); @@ -157,7 +158,12 @@ static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { if (frames < 0) frames = 0; - return pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec); + r += pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec); + + if (u->memchunk.memblock) + r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec); + + return r; } int pa__init(struct pa_core *c, struct pa_module*m) { diff --git a/polyp/module-oss.c b/polyp/module-oss.c index 51cc42ef..b4e011d8 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -162,6 +162,7 @@ static void io_callback(struct pa_iochannel *io, void*userdata) { } static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { + pa_usec_t r = 0; int arg; struct userdata *u = s->userdata; assert(s && u && u->sink); @@ -172,7 +173,12 @@ static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { return 0; } - return pa_bytes_to_usec(arg, &s->sample_spec); + r += pa_bytes_to_usec(arg, &s->sample_spec); + + if (u->memchunk.memblock) + r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec); + + return r; } int pa__init(struct pa_core *c, struct pa_module*m) { diff --git a/polyp/sink-input.c b/polyp/sink-input.c index b0096182..7763f261 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -112,12 +112,16 @@ void pa_sink_input_kill(struct pa_sink_input*i) { } pa_usec_t pa_sink_input_get_latency(struct pa_sink_input *i) { + pa_usec_t r = 0; assert(i); if (i->get_latency) - return i->get_latency(i); + r += i->get_latency(i); - return 0; + if (i->resampled_chunk.memblock) + r += pa_bytes_to_usec(i->resampled_chunk.length, &i->sample_spec); + + return r; } int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { -- cgit From 829656c5fcd7169e4c2f86f4ad5098ea9aaa5643 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 13 Sep 2004 23:28:30 +0000 Subject: new configuration subsystem git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@198 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 12 +- configure.ac | 5 +- doc/todo | 3 +- polyp/Makefile.am | 27 ++--- polyp/cmdline.c | 260 ++++++++++++++++++++++++++----------------- polyp/cmdline.h | 21 +--- polyp/conf.c | 285 ++++++++++++++++++++++++++++++++++++++++++++++++ polyp/conf.h | 51 +++++++++ polyp/config | 61 +++++++++++ polyp/core.c | 9 +- polyp/core.h | 3 +- polyp/default.pa | 62 +++++++++++ polyp/dumpmodules.c | 101 +++++++++++++++++ polyp/dumpmodules.h | 29 +++++ polyp/main.c | 85 ++++++++++----- polyp/modargs.c | 9 +- polyp/module.c | 4 +- polyp/pacat.c | 5 +- polyp/pamodinfo.c | 126 --------------------- polyp/polypaudio.pa | 62 ----------- polyp/polyplib-def.h | 11 +- polyp/polyplib-stream.c | 10 +- polyp/socket-util.c | 24 ++-- polyp/util.c | 26 +++++ polyp/util.h | 3 + 25 files changed, 909 insertions(+), 385 deletions(-) create mode 100644 polyp/conf.c create mode 100644 polyp/conf.h create mode 100644 polyp/config create mode 100755 polyp/default.pa create mode 100644 polyp/dumpmodules.c create mode 100644 polyp/dumpmodules.h delete mode 100644 polyp/pamodinfo.c delete mode 100755 polyp/polypaudio.pa diff --git a/Makefile.am b/Makefile.am index c8592f86..b15fbac6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,7 +24,17 @@ MAINTAINERCLEANFILES=README noinst_DATA = README pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc polyplib-glib-mainloop.pc polyplib-glib12-mainloop.pc +pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc + +if HAVE_GLIB20 +pkgconfig_DATA += \ + polyplib-glib-mainloop.pc +endif + +if HAVE_GLIB12 +pkgconfig_DATA += \ + polyplib-glib12-mainloop.pc +endif README: rm -f README diff --git a/configure.ac b/configure.ac index 62dc37d4..07b2b96c 100644 --- a/configure.ac +++ b/configure.ac @@ -40,10 +40,12 @@ AC_SUBST(INCLTDL) AC_SUBST(LIBLTDL) AC_LIBTOOL_DLOPEN AC_PROG_LIBTOOL +AC_PROG_LEX +AC_PROG_YACC # Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h limits.h malloc.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h]) +AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h limits.h malloc.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h syslog.h]) ACX_PTHREAD AC_PATH_XTRA @@ -70,6 +72,7 @@ AC_FUNC_MEMCMP AC_FUNC_MMAP AC_FUNC_REALLOC AC_FUNC_SETPGRP +AC_FUNC_VPRINTF AC_TYPE_SIGNAL AC_CHECK_FUNCS([gethostname gettimeofday memchr memmove memset mkdir mkfifo munmap rmdir socket strcspn strerror strrchr strspn strstr strtol strtoul pow strcasecmp]) AC_FUNC_STAT diff --git a/doc/todo b/doc/todo index 61cee844..135a336d 100644 --- a/doc/todo +++ b/doc/todo @@ -11,15 +11,14 @@ rename streams/contexts - more complete pactl - add sample directory -- config file for command line arguments - option to use default fragment size on alsa drivers - lazy sample cache - per-channel volume - merge pa_context_connect_* - input latency - fix tcp/native -- suid - add volume to create_stream command in native protocol +- udp based protocol ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 99c89491..e9e1c295 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -24,23 +24,24 @@ modlibdir=$(libdir)/polypaudio-@PA_MAJORMINOR@ AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) AM_CFLAGS+=-DDLSEARCHPATH=\"$(modlibdir)\" -AM_CFLAGS+=-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/polypaudio.pa\" +AM_CFLAGS+=-DDEFAULT_SCRIPT_FILE=\"$(polypconfdir)/default.pa\" +AM_CFLAGS+=-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/config\" AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\" AM_LDADD=$(PTHREAD_LIBS) -lm AM_LIBADD=$(PTHREAD_LIBS) -lm -EXTRA_DIST = polypaudio.pa depmod.py esdcompat.sh.in -bin_PROGRAMS = polypaudio pacat pactl pamodinfo +EXTRA_DIST = default.pa config depmod.py esdcompat.sh.in +bin_PROGRAMS = polypaudio pacat pactl bin_SCRIPTS = esdcompat.sh noinst_PROGRAMS = \ mainloop-test \ pacat-simple \ parec-simple \ cpulimit-test \ - cpulimit-test2 + cpulimit-test2 -polypconf_DATA=polypaudio.pa +polypconf_DATA=default.pa config BUILT_SOURCES=polyplib-version.h @@ -153,19 +154,15 @@ polypaudio_SOURCES = idxset.c idxset.h \ cpulimit.c cpulimit.h \ log.c log.h \ gcc-printf.h \ - modinfo.c modinfo.h + modinfo.c modinfo.h \ + conf.c conf.h \ + dumpmodules.c dumpmodules.h polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) -polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) +polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(LEXLIB) polypaudio_LDFLAGS=-export-dynamic -pamodinfo_SOURCES = log.c log.h pamodinfo.c pamodinfo.h modinfo.c modinfo.h util.c util.h xmalloc.c xmalloc.h -pamodinfo_CFLAGS = $(AM_CFLAGS) -pamodinfo_INCLUDES = $(INCLTDL) -pamodinfo_LDADD = $(AM_LDADD) $(LIBLTDL) -pamodinfo_LDFLAGS=-export-dynamic - libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h libprotocol_simple_la_LDFLAGS = -avoid-version libprotocol_simple_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la @@ -535,3 +532,7 @@ esdcompat.sh: esdcompat.sh.in Makefile sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ -e 's,@POLYPAUDIO_BINARY\@,$(bindir)/polypaudio,g' < $< > $@ + +install-exec-hook: + chown root:root $(DESTDIR)$(bindir)/polypaudio + chmod u+s $(DESTDIR)$(bindir)/polypaudio diff --git a/polyp/cmdline.c b/polyp/cmdline.c index b4d58f1f..4e7cde48 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -35,29 +35,48 @@ #include "strbuf.h" #include "xmalloc.h" -#define ENV_CONFIG_FILE "POLYP_CONFIG" +enum { + ARG_HELP = 256, + ARG_VERSION, + ARG_DUMP_CONF, + ARG_DUMP_MODULES, + ARG_DAEMONIZE, + ARG_FAIL, + ARG_VERBOSE, + ARG_HIGH_PRIORITY, + ARG_STAY_ROOT, + ARG_DISALLOW_MODULE_LOADING, + ARG_EXIT_IDLE_TIME, + ARG_MODULE_IDLE_TIME, + ARG_LOG_TARGET, + ARG_LOAD, + ARG_FILE, + ARG_DL_SEARCH_PATH, +}; + +static struct option long_options[] = { + {"help", 0, 0, ARG_HELP}, + {"version", 0, 0, ARG_VERSION}, + {"dump-conf", 0, 0, ARG_DUMP_CONF}, + {"dump-modules", 0, 0, ARG_DUMP_MODULES}, + {"daemonize", 2, 0, ARG_DAEMONIZE}, + {"fail", 2, 0, ARG_FAIL}, + {"verbose", 2, 0, ARG_VERBOSE}, + {"high-priority", 2, 0, ARG_HIGH_PRIORITY}, + {"stay-root", 2, 0, ARG_STAY_ROOT}, + {"disallow-module-loading", 2, 0, ARG_DISALLOW_MODULE_LOADING}, + {"exit-idle-time", 2, 0, ARG_EXIT_IDLE_TIME}, + {"module-idle-time", 2, 0, ARG_MODULE_IDLE_TIME}, + {"log-target", 1, 0, ARG_LOG_TARGET}, + {"load", 1, 0, ARG_LOAD}, + {"file", 1, 0, ARG_FILE}, + {"dl-search-path", 1, 0, ARG_DL_SEARCH_PATH}, + {NULL, 0, 0, 0} +}; -char* config_file(void) { - char *p, *h; - - if ((p = getenv(ENV_CONFIG_FILE))) - return pa_xstrdup(p); - - if ((h = getenv("HOME"))) { - struct stat st; - p = pa_sprintf_malloc("%s/.polypaudio", h); - if (stat(p, &st) >= 0) - return p; - - pa_xfree(p); - } - - return pa_xstrdup(DEFAULT_CONFIG_FILE); -} void pa_cmdline_help(const char *argv0) { const char *e; - char *cfg = config_file(); if ((e = strrchr(argv0, '/'))) e++; @@ -65,133 +84,170 @@ void pa_cmdline_help(const char *argv0) { e = argv0; printf("%s [options]\n" - " -r Try to set high process priority (only available as root)\n" - " -R Don't drop root if SETUID root\n" - " -L MODULE Load the specified plugin module with the specified argument\n" - " -F FILE Run the specified script\n" - " -C Open a command line on the running TTY\n" - " -n Don't load configuration file (%s)\n" - " -D Daemonize after loading the modules\n" - " -d Disallow module loading after startup\n" - " -f Dont quit when the startup fails\n" - " -v Verbose startup\n" - " -X SECS Terminate the daemon after the last client quit and this time passed\n" - " -h Show this help\n" - " -l TARGET Specify the log target (syslog, stderr, auto)\n" - " -p DIR Append a directory to the search path for dynamic modules\n" - " -V Show version\n", e, cfg); - - pa_xfree(cfg); + " -h, --help Show this help\n" + " --version Show version\n" + " --dump-conf Dump default configuration\n" + " --dump-modules Dump list of available modules\n\n" + + " -D, --daemonize[=BOOL] Daemonize after startup\n" + " --fail[=BOOL] Quit when startup fails\n" + " --verbose[=BOOL] Be slightly more verbose\n" + " --high-priority[=BOOL] Try to set high process priority (only available as root)\n" + " --stay-root[=BOOL] Don't drop root if SETUID root\n" + " --disallow-module-loading[=BOOL] Disallow module loading after startup\n" + " --exit-idle-time=SECS Terminate the daemon when idle and this time passed\n" + " --module-idle-time=SECS Unload autoloaded modules when idle and this time passed\n" + " --log-target={auto,syslog,stderr} Specify the log target\n" + " -p, --dl-search-path=PATH Set the search path for dynamic shared objects (plugins)\n\n" + + " -L, --load=\"MODULE ARGUMENTS\" Load the specified plugin module with the specified argument\n" + " -F, --file=FILENAME Run the specified script\n" + " -C Open a command line on the running TTY after startup\n\n" + + " -n Don't load default script file\n", e); } -struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { - char c, *cfg; - struct pa_cmdline *cmdline = NULL; +int pa_cmdline_parse(struct pa_conf *conf, int argc, char *const argv [], int *d) { struct pa_strbuf *buf = NULL; - int no_default_config_file = 0; - assert(argc && argv); - - cmdline = pa_xmalloc(sizeof(struct pa_cmdline)); - cmdline->daemonize = - cmdline->help = - cmdline->verbose = - cmdline->high_priority = - cmdline->stay_root = - cmdline->version = - cmdline->disallow_module_loading = 0; - cmdline->fail = cmdline->auto_log_target = 1; - cmdline->quit_after_last_client_time = -1; - cmdline->log_target = -1; - cmdline->dl_search_path = NULL; + int c; + assert(conf && argc && argv); buf = pa_strbuf_new(); assert(buf); + + if (conf->script_commands) + pa_strbuf_puts(buf, conf->script_commands); - while ((c = getopt(argc, argv, "L:F:CDhfvrRVndX:l:p:")) != -1) { + while ((c = getopt_long(argc, argv, "L:F:ChDnp:", long_options, NULL)) != -1) { switch (c) { + case ARG_HELP: + case 'h': + conf->help = 1; + break; + + case ARG_VERSION: + conf->version = 1; + break; + + case ARG_DUMP_CONF: + conf->dump_conf = 1; + break; + + case ARG_DUMP_MODULES: + conf->dump_modules = 1; + break; + + case ARG_LOAD: case 'L': pa_strbuf_printf(buf, "load %s\n", optarg); break; + + case ARG_FILE: case 'F': pa_strbuf_printf(buf, ".include %s\n", optarg); break; + case 'C': pa_strbuf_puts(buf, "load module-cli\n"); break; + + case ARG_DAEMONIZE: case 'D': - cmdline->daemonize = 1; + if ((conf->daemonize = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + pa_log(__FILE__": --daemonize expects boolean argument\n"); + goto fail; + } break; - case 'h': - cmdline->help = 1; + + case ARG_FAIL: + if ((conf->fail = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + pa_log(__FILE__": --fail expects boolean argument\n"); + goto fail; + } break; - case 'f': - cmdline->fail = 0; + + case ARG_VERBOSE: + if ((conf->verbose = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + pa_log(__FILE__": --verbose expects boolean argument\n"); + goto fail; + } break; - case 'v': - cmdline->verbose = 1; + + case ARG_HIGH_PRIORITY: + if ((conf->high_priority = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + pa_log(__FILE__": --high-priority expects boolean argument\n"); + goto fail; + } break; - case 'r': - cmdline->high_priority = 1; + + case ARG_STAY_ROOT: + if ((conf->stay_root = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + pa_log(__FILE__": --stay-root expects boolean argument\n"); + goto fail; + } break; - case 'R': - cmdline->stay_root = 1; + + case ARG_DISALLOW_MODULE_LOADING: + if ((conf->disallow_module_loading = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + pa_log(__FILE__": --disallow-module-loading expects boolean argument\n"); + goto fail; + } break; - case 'V': - cmdline->version = 1; + + case 'p': + case ARG_DL_SEARCH_PATH: + pa_xfree(conf->dl_search_path); + conf->dl_search_path = *optarg ? pa_xstrdup(optarg) : NULL; break; + case 'n': - no_default_config_file = 1; - break; - case 'd': - cmdline->disallow_module_loading = 1; - break; - case 'X': - cmdline->quit_after_last_client_time = atoi(optarg); + pa_xfree(conf->default_script_file); + conf->default_script_file = NULL; break; - case 'p': - if (cmdline->dl_search_path) - pa_xfree(cmdline->dl_search_path); - cmdline->dl_search_path = pa_xstrdup(optarg); - break; - case 'l': + + case ARG_LOG_TARGET: if (!strcmp(optarg, "syslog")) { - cmdline->auto_log_target = 0; - cmdline->log_target = PA_LOG_SYSLOG; + conf->auto_log_target = 0; + conf->log_target = PA_LOG_SYSLOG; } else if (!strcmp(optarg, "stderr")) { - cmdline->auto_log_target = 0; - cmdline->log_target = PA_LOG_STDERR; + conf->auto_log_target = 0; + conf->log_target = PA_LOG_STDERR; } else if (!strcmp(optarg, "auto")) - cmdline->auto_log_target = 1; + conf->auto_log_target = 1; else { pa_log(__FILE__": Invalid log target: use either 'syslog', 'stderr' or 'auto'.\n"); goto fail; } break; + + case ARG_EXIT_IDLE_TIME: + conf->exit_idle_time = atoi(optarg); + break; + + case ARG_MODULE_IDLE_TIME: + conf->module_idle_time = atoi(optarg); + break; + default: goto fail; } } - if (!no_default_config_file) { - cfg = config_file(); - pa_strbuf_printf(buf, ".include %s\n", cfg); - pa_xfree(cfg); + pa_xfree(conf->script_commands); + conf->script_commands = pa_strbuf_tostring_free(buf); + + if (!conf->script_commands) { + pa_xfree(conf->script_commands); + conf->script_commands = NULL; } - cmdline->cli_commands = pa_strbuf_tostring_free(buf); - return cmdline; + *d = optind; + + return 0; fail: - if (cmdline) - pa_cmdline_free(cmdline); if (buf) pa_strbuf_free(buf); - return NULL; -} - -void pa_cmdline_free(struct pa_cmdline *cmd) { - assert(cmd); - pa_xfree(cmd->cli_commands); - pa_xfree(cmd->dl_search_path); - pa_xfree(cmd); + + return -1; } diff --git a/polyp/cmdline.h b/polyp/cmdline.h index 5dfe2e0d..e4bd8af6 100644 --- a/polyp/cmdline.h +++ b/polyp/cmdline.h @@ -22,26 +22,9 @@ USA. ***/ -#include "log.h" +#include "conf.h" -struct pa_cmdline { - int daemonize, - help, - fail, - verbose, - high_priority, - stay_root, - version, - disallow_module_loading, - quit_after_last_client_time, - auto_log_target; - char *cli_commands; - char *dl_search_path; - enum pa_log_target log_target; -}; - -struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []); -void pa_cmdline_free(struct pa_cmdline *cmd); +int pa_cmdline_parse(struct pa_conf*c, int argc, char *const argv [], int *d); void pa_cmdline_help(const char *argv0); diff --git a/polyp/conf.c b/polyp/conf.c new file mode 100644 index 00000000..4a11c480 --- /dev/null +++ b/polyp/conf.c @@ -0,0 +1,285 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "conf.h" +#include "util.h" +#include "xmalloc.h" +#include "strbuf.h" + +static const struct pa_conf default_conf = { + .help = 0, + .daemonize = 0, + .dump_conf = 0, + .dump_modules = 0, + .fail = 1, + .verbose = 0, + .high_priority = 0, + .stay_root = 0, + .version = 0, + .disallow_module_loading = 0, + .exit_idle_time = -1, + .module_idle_time = 20, + .auto_log_target = 1, + .script_commands = NULL, + .dl_search_path = NULL, + .default_script_file = NULL, + .log_target = PA_LOG_SYSLOG, +}; + +#define ENV_SCRIPT_FILE "POLYP_SCRIPT" +#define ENV_CONFIG_FILE "POLYP_CONFIG" + +#ifndef DEFAULT_SCRIPT_FILE +#define DEFAULT_SCRIPT_FILE "/etc/polypaudio/default.pa" +#endif + +#ifndef DEFAULT_CONFIG_FILE +#define DEFAULT_CONFIG_FILE "/etc/polypaudio/config" +#endif + +#define DEFAULT_SCRIPT_FILE_LOCAL ".polypaudio.pa" +#define DEFAULT_CONFIG_FILE_LOCAL ".polypaudio.conf" + +char* default_file(const char *envvar, const char *global, const char *local) { + char *p, *h; + + assert(envvar && global && local); + + if ((p = getenv(envvar))) + return pa_xstrdup(p); + + if ((h = getenv("HOME"))) { + struct stat st; + p = pa_sprintf_malloc("%s/%s", h, local); + if (stat(p, &st) >= 0) + return p; + + pa_xfree(p); + } + + return pa_xstrdup(global); +} + + +struct pa_conf* pa_conf_new(void) { + struct pa_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); + c->default_script_file = default_file(ENV_SCRIPT_FILE, DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_LOCAL); + return c; +} + +void pa_conf_free(struct pa_conf *c) { + assert(c); + pa_xfree(c->script_commands); + pa_xfree(c->dl_search_path); + pa_xfree(c->default_script_file); + pa_xfree(c); +} + +#define WHITESPACE " \t\n" +#define COMMENTS "#;\n" + +#define PARSE_BOOLEAN(t, v) \ + do { \ + if (!strcmp(lvalue, t)) { \ + int b; \ + if ((b = pa_parse_boolean(rvalue)) < 0) \ + goto fail; \ + c->v = b; \ + return 0; \ + } \ + } while (0) + +#define PARSE_STRING(t, v) \ + do { \ + if (!strcmp(lvalue, t)) { \ + pa_xfree(c->v); \ + c->v = *rvalue ? pa_xstrdup(rvalue) : NULL; \ + return 0; \ + } \ + } while (0) + +#define PARSE_INTEGER(t, v) \ + do { \ + if (!strcmp(lvalue, t)) { \ + char *x = NULL; \ + int i = strtol(rvalue, &x, 0); \ + if (!x || *x) \ + goto fail; \ + c->v = i; \ + return 0; \ + } \ + } while(0) + +static int next_assignment(struct pa_conf *c, char *lvalue, char *rvalue, unsigned n) { + PARSE_BOOLEAN("daemonize", daemonize); + PARSE_BOOLEAN("fail", fail); + PARSE_BOOLEAN("verbose", verbose); + PARSE_BOOLEAN("high-priority", high_priority); + PARSE_BOOLEAN("stay-root", stay_root); + PARSE_BOOLEAN("disallow-module-loading", disallow_module_loading); + + PARSE_INTEGER("exit-idle-time", exit_idle_time); + PARSE_INTEGER("module-idle-time", module_idle_time); + + PARSE_STRING("dl-search-path", dl_search_path); + PARSE_STRING("default-script-file", default_script_file); + + if (!strcmp(lvalue, "log-target")) { + if (!strcmp(rvalue, "auto")) + c->auto_log_target = 1; + else if (!strcmp(rvalue, "syslog")) { + c->auto_log_target = 0; + c->log_target = PA_LOG_SYSLOG; + } else if (!strcmp(rvalue, "stderr")) { + c->auto_log_target = 0; + c->log_target = PA_LOG_STDERR; + } else + goto fail; + + return 0; + } + +fail: + pa_log(__FILE__": line %u: parse error.\n", n); + return -1; +} + +#undef PARSE_STRING +#undef PARSE_BOOLEAN + +static int in_string(char c, const char *s) { + for (; *s; s++) + if (*s == c) + return 1; + + return 0; +} + +static char *strip(char *s) { + char *b = s+strspn(s, WHITESPACE); + char *e, *l = NULL; + + for (e = b; *e; e++) + if (!in_string(*e, WHITESPACE)) + l = e; + + if (l) + *(l+1) = 0; + + return b; +} + +static int parse_line(struct pa_conf *conf, char *l, unsigned n) { + char *e, *c, *b = l+strspn(l, WHITESPACE); + + if ((c = strpbrk(b, COMMENTS))) + *c = 0; + + if (!*b) + return 0; + + if (!(e = strchr(b, '='))) { + pa_log(__FILE__": line %u: missing '='.\n", n); + return -1; + } + + *e = 0; + e++; + + return next_assignment(conf, strip(b), strip(e), n); +} + + +int pa_conf_load(struct pa_conf *c, const char *filename) { + FILE *f; + int r = 0; + unsigned n = 0; + char *def = NULL; + assert(c); + + if (!filename) + filename = def = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_LOCAL); + + if (!(f = fopen(filename, "r"))) { + if (errno != ENOENT) + pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno)); + + goto finish; + } + + while (!feof(f)) { + char l[256]; + if (!fgets(l, sizeof(l), f)) { + if (!feof(f)) + pa_log(__FILE__": WARNING: failed to read configuration file '%s': %s\n", filename, strerror(errno)); + + break; + } + + if (parse_line(c, l, ++n) < 0) + r = -1; + } + +finish: + + if (f) + fclose(f); + + pa_xfree(def); + + return r; +} + +char *pa_conf_dump(struct pa_conf *c) { + struct pa_strbuf *s = pa_strbuf_new(); + char *d; + + d = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_LOCAL); + pa_strbuf_printf(s, "### Default configuration file: %s ###\n\n", d); + + pa_strbuf_printf(s, "verbose = %i\n", !!c->verbose); + pa_strbuf_printf(s, "daemonize = %i\n", !!c->daemonize); + pa_strbuf_printf(s, "fail = %i\n", !!c->fail); + pa_strbuf_printf(s, "high-priority = %i\n", !!c->high_priority); + pa_strbuf_printf(s, "stay-root = %i\n", !!c->stay_root); + pa_strbuf_printf(s, "disallow-module-loading = %i\n", !!c->disallow_module_loading); + pa_strbuf_printf(s, "exit-idle-time = %i\n", c->exit_idle_time); + pa_strbuf_printf(s, "module-idle-time = %i\n", c->module_idle_time); + pa_strbuf_printf(s, "dl-search-path = %s\n", c->dl_search_path ? c->dl_search_path : ""); + pa_strbuf_printf(s, "default-script-file = %s\n", c->default_script_file); + pa_strbuf_printf(s, "log-target = %s\n", c->auto_log_target ? "auto" : (c->log_target == PA_LOG_SYSLOG ? "syslog" : "stderr")); + + pa_strbuf_printf(s, "\n### EOF ###\n"); + + pa_xfree(d); + + return pa_strbuf_tostring_free(s); +} diff --git a/polyp/conf.h b/polyp/conf.h new file mode 100644 index 00000000..bbe253c2 --- /dev/null +++ b/polyp/conf.h @@ -0,0 +1,51 @@ +#ifndef fooconfhfoo +#define fooconfhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "log.h" + +struct pa_conf { + int help, + version, + dump_conf, + dump_modules, + daemonize, + fail, + verbose, + high_priority, + stay_root, + disallow_module_loading, + exit_idle_time, + module_idle_time, + auto_log_target; + char *script_commands, *dl_search_path, *default_script_file; + enum pa_log_target log_target; +}; + +struct pa_conf* pa_conf_new(void); +void pa_conf_free(struct pa_conf*c); + +int pa_conf_load(struct pa_conf *c, const char *filename); +char *pa_conf_dump(struct pa_conf *c); + +#endif diff --git a/polyp/config b/polyp/config new file mode 100644 index 00000000..e0f8de50 --- /dev/null +++ b/polyp/config @@ -0,0 +1,61 @@ +# $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +## Configuration file for polypaudio. Default values are commented out. +## Use either ; or # for commenting + +# Extra verbositiy +; verbose = 0 + +## Daemonize after startup +; daemonize = 0 + +## Quit if startup fails +; fail = 1 + +## Renice the daemon to level -15 and try to get SCHED_FIFO +## scheduling. This a good idea if you hear annyoing noise in the +## playback. However, this is a certain security issue. +; high-priority = 0 + +## Don't drop root rights on startup if called SUID root. +; stay-root = 0 + +## Disallow module loading after startup +; disallow-module-loading = 0 + +## Terminate the daemon after the last client quit and this time +## passed. Use a negative value to disable this feature. +; exit-idle-time = -1 + +## Unload autoloaded modules after being idle for this time +module-idle-time = 20 + +## The path were to look for dynamic shared objects (DSOs aka plugins). +## Specify an empty string for the default search path. +; dl-search-path = + +## The default script file to load. Specify an empty string for not +## loading a default script file +; default-script-file = /etc/polyp/default.pa + +## The default log target. Use either "stderr", "syslog" or +## "auto". The latter is equivalent to "sylog" in case daemonize is +## true, otherwise to "stderr". +; log-target = auto diff --git a/polyp/core.c b/polyp/core.c index 5d79a365..0b33c107 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -61,7 +61,6 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->default_sample_spec.rate = 44100; c->default_sample_spec.channels = 2; - c->auto_unload_time = 20; c->auto_unload_event = NULL; c->subscription_defer_event = NULL; @@ -73,7 +72,9 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->disallow_module_loading = 0; c->quit_event = NULL; - c->quit_after_last_client_time = -1; + + c->exit_idle_time = -1; + c->module_idle_time = 20; pa_check_for_sigpipe(); @@ -129,10 +130,10 @@ static void quit_callback(struct pa_mainloop_api*m, struct pa_time_event *e, con void pa_core_check_quit(struct pa_core *c) { assert(c); - if (!c->quit_event && c->quit_after_last_client_time >= 0 && pa_idxset_ncontents(c->clients) == 0) { + if (!c->quit_event && c->exit_idle_time >= 0 && pa_idxset_ncontents(c->clients) == 0) { struct timeval tv; gettimeofday(&tv, NULL); - tv.tv_sec+= c->quit_after_last_client_time; + tv.tv_sec+= c->exit_idle_time; c->quit_event = c->mainloop->time_new(c->mainloop, &tv, quit_callback, c); } else if (c->quit_event && pa_idxset_ncontents(c->clients) > 0) { c->mainloop->time_free(c->quit_event); diff --git a/polyp/core.h b/polyp/core.h index ddba6a83..a85dafd4 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -38,7 +38,6 @@ struct pa_core { char *default_source_name, *default_sink_name; struct pa_sample_spec default_sample_spec; - int auto_unload_time; struct pa_time_event *auto_unload_event; struct pa_defer_event *subscription_defer_event; @@ -48,7 +47,7 @@ struct pa_core { struct pa_memblock_stat *memblock_stat; int disallow_module_loading; - int quit_after_last_client_time; + int exit_idle_time, module_idle_time; struct pa_time_event *quit_event; }; diff --git a/polyp/default.pa b/polyp/default.pa new file mode 100755 index 00000000..15434627 --- /dev/null +++ b/polyp/default.pa @@ -0,0 +1,62 @@ +#!./polypaudio -rnF + +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + + +# Load audio drivers statically + +#load module-alsa-sink +load module-alsa-source device=plughw:1,0 +load module-oss device="/dev/dsp" sink_name=output source_name=input record=0 +#load module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#load module-pipe-sink + +# Load audio drivers automatically on access + +#autoload_sink_add output module-oss device="/dev/dsp" sink_name=output source_name=input +#autoload_source_add input module-oss device="/dev/dsp" sink_name=output source_name=input +#autoload_sink_add output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#autoload_source_add input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#autoload_sink_add output module-alsa-sink sink_name=output +#autoload_source_add input module-alsa-source source_name=input + +# Load several protocols +load module-esound-protocol-tcp +#load module-simple-protocol-tcp +load module-native-protocol-unix +#load module-cli-protocol-unix +#load module-esound-protocol-unix + +# Load the CLI module +load module-cli + +# Make some devices default +sink_default output +source_default input + +.nofail + +# Load something to the sample cache +scache_load /usr/share/sounds/KDE_Notify.wav x11-bell + +# Load X11 bell module +load module-x11-bell sample=x11-bell sink=output + +#load module-pipe-source +#load module-pipe-sink + diff --git a/polyp/dumpmodules.c b/polyp/dumpmodules.c new file mode 100644 index 00000000..9ed89692 --- /dev/null +++ b/polyp/dumpmodules.c @@ -0,0 +1,101 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "dumpmodules.h" +#include "modinfo.h" + +#define PREFIX "module-" + +static void short_info(const char *name, const char *path, struct pa_modinfo *i) { + assert(name && i); + printf("%-40s%s\n", name, i->description ? i->description : "n/a"); +} + +static void long_info(const char *name, const char *path, struct pa_modinfo *i) { + assert(name && i); + static int nl = 0; + + if (nl) + printf("\n"); + + nl = 1; + + printf("Name: %s\n", name); + + if (!i->description && !i->version && !i->author && !i->usage) + printf("No module information available\n"); + else { + if (i->version) + printf("Version: %s\n", i->version); + if (i->description) + printf("Description: %s\n", i->description); + if (i->author) + printf("Author: %s\n", i->author); + if (i->usage) + printf("Usage: %s\n", i->usage); + } + + if (path) + printf("Path: %s\n", path); +} + +static void show_info(const char *name, const char *path, void (*info)(const char *name, const char *path, struct pa_modinfo*i)) { + struct pa_modinfo *i; + + if ((i = pa_modinfo_get_by_name(path ? path : name))) { + info(name, path, i); + pa_modinfo_free(i); + } +} + +static int callback(const char *path, lt_ptr data) { + const char *e; + struct pa_conf *c = (data); + + if ((e = (const char*) strrchr(path, '/'))) + e++; + else + e = path; + + if (strlen(e) > sizeof(PREFIX)-1 && !strncmp(e, PREFIX, sizeof(PREFIX)-1)) + show_info(e, path, c->verbose ? long_info : short_info); + + return 0; +} + +void pa_dump_modules(struct pa_conf *c, int argc, char * const argv[]) { + if (argc > 0) { + int i; + for (i = 0; i < argc; i++) + show_info(argv[i], NULL, long_info); + } else + lt_dlforeachfile(NULL, callback, c); +} diff --git a/polyp/dumpmodules.h b/polyp/dumpmodules.h new file mode 100644 index 00000000..6b1bd858 --- /dev/null +++ b/polyp/dumpmodules.h @@ -0,0 +1,29 @@ +#ifndef foodumpmoduleshfoo +#define foodumpmoduleshfoo + +/* $Id*/ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "conf.h" + +void pa_dump_modules(struct pa_conf *c, int argc, char * const argv[]); + +#endif diff --git a/polyp/main.c b/polyp/main.c index a2b3d4c7..148dfac2 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -45,6 +45,8 @@ #include "xmalloc.h" #include "cpulimit.h" #include "log.h" +#include "conf.h" +#include "dumpmodules.h" static struct pa_mainloop *mainloop; @@ -99,40 +101,69 @@ static void close_pipe(int p[2]) { int main(int argc, char *argv[]) { struct pa_core *c; - struct pa_cmdline *cmdline = NULL; struct pa_strbuf *buf = NULL; + struct pa_conf *conf; char *s; - int r, retval = 1; + int r, retval = 1, d = 0; int daemon_pipe[2] = { -1, -1 }; + r = lt_dlinit(); + assert(r == 0); + pa_log_set_ident("polypaudio"); - if (!(cmdline = pa_cmdline_parse(argc, argv))) { + conf = pa_conf_new(); + + if (pa_conf_load(conf, NULL) < 0) + goto finish; + + if (pa_cmdline_parse(conf, argc, argv, &d) < 0) { pa_log(__FILE__": failed to parse command line.\n"); goto finish; } - pa_log_set_target(cmdline->auto_log_target ? PA_LOG_STDERR : cmdline->log_target, NULL); + pa_log_set_target(conf->auto_log_target ? PA_LOG_STDERR : conf->log_target, NULL); + + if (conf->dl_search_path) + lt_dlsetsearchpath(conf->dl_search_path); +#ifdef DLSEARCHPATH + else + lt_dlsetsearchpath(DLSEARCHPATH); +#endif + + if (conf->dump_modules) { + pa_dump_modules(conf, argc-d, argv+d); + retval = 0; + goto finish; + } + + if (conf->dump_conf) { + char *s = pa_conf_dump(conf); + fputs(s, stdout); + pa_xfree(s); + retval = 0; + goto finish; + } - if (cmdline->help) { + if (conf->help) { pa_cmdline_help(argv[0]); retval = 0; goto finish; } - if (cmdline->version) { + if (conf->version) { printf(PACKAGE_NAME" "PACKAGE_VERSION"\n"); retval = 0; goto finish; } - if (cmdline->high_priority) + if (conf->high_priority) pa_raise_priority(); - if (!cmdline->stay_root) + if (!conf->stay_root) drop_root(); - if (cmdline->daemonize) { + if (conf->daemonize) { pid_t child; if (pa_stdio_acquire() < 0) { @@ -168,7 +199,7 @@ int main(int argc, char *argv[]) { daemon_pipe[0] = -1; - if (cmdline->auto_log_target) + if (conf->auto_log_target) pa_log_set_target(PA_LOG_SYSLOG, NULL); setsid(); @@ -178,15 +209,6 @@ int main(int argc, char *argv[]) { close(1); } - r = lt_dlinit(); - assert(r == 0); - - if (cmdline->dl_search_path) - lt_dlsetsearchpath(cmdline->dl_search_path); -#ifdef DLSEARCHPATH - else - lt_dlsetsearchpath(DLSEARCHPATH); -#endif pa_log(__FILE__": sizeof(pa_usec_t) = %u\n", sizeof(pa_usec_t)); @@ -210,25 +232,28 @@ int main(int argc, char *argv[]) { buf = pa_strbuf_new(); assert(buf); - r = pa_cli_command_execute(c, cmdline->cli_commands, buf, &cmdline->fail, &cmdline->verbose); + if (conf->default_script_file) + pa_cli_command_execute_file(c, conf->default_script_file, buf, &conf->fail, &conf->verbose); + r = pa_cli_command_execute(c, conf->script_commands, buf, &conf->fail, &conf->verbose); pa_log(s = pa_strbuf_tostring_free(buf)); pa_xfree(s); - if (r < 0 && cmdline->fail) { + if (r < 0 && conf->fail) { pa_log(__FILE__": failed to initialize daemon.\n"); - if (cmdline->daemonize) + if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); } else if (!c->modules || pa_idxset_ncontents(c->modules) == 0) { pa_log(__FILE__": daemon startup without any loaded modules, refusing to work.\n"); - if (cmdline->daemonize) + if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); } else { retval = 0; - if (cmdline->daemonize) + if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); - c->disallow_module_loading = cmdline->disallow_module_loading; - c->quit_after_last_client_time = cmdline->quit_after_last_client_time; + c->disallow_module_loading = conf->disallow_module_loading; + c->exit_idle_time = conf->exit_idle_time; + c->module_idle_time = conf->module_idle_time; pa_log(__FILE__": Daemon startup complete.\n"); if (pa_mainloop_run(mainloop, &retval) < 0) @@ -242,16 +267,16 @@ int main(int argc, char *argv[]) { pa_signal_done(); pa_mainloop_free(mainloop); - lt_dlexit(); - pa_log(__FILE__": Daemon terminated.\n"); finish: - if (cmdline) - pa_cmdline_free(cmdline); + if (conf) + pa_conf_free(conf); close_pipe(daemon_pipe); + lt_dlexit(); + return retval; } diff --git a/polyp/modargs.c b/polyp/modargs.c index 4874d808..e1c2c9b8 100644 --- a/polyp/modargs.c +++ b/polyp/modargs.c @@ -36,6 +36,7 @@ #include "sink.h" #include "source.h" #include "xmalloc.h" +#include "util.h" struct pa_modargs; @@ -229,6 +230,7 @@ int pa_modargs_get_value_s32(struct pa_modargs *ma, const char *key, int32_t *va int pa_modargs_get_value_boolean(struct pa_modargs *ma, const char *key, int *value) { const char *v; + int r; assert(ma && key && value); if (!(v = pa_modargs_get_value(ma, key, NULL))) @@ -237,13 +239,10 @@ int pa_modargs_get_value_boolean(struct pa_modargs *ma, const char *key, int *va if (!*v) return -1; - if (!strcmp(v, "1") || !strcasecmp(v, "yes") || !strcasecmp(v, "y") || !strcasecmp(v, "on")) - *value = 1; - else if (!strcmp(v, "0") || !strcasecmp(v, "no") || !strcasecmp(v, "n") || !strcasecmp(v, "off")) - *value = 0; - else + if ((r = pa_parse_boolean(v)) < 0) return -1; + *value = r; return 0; } diff --git a/polyp/module.c b/polyp/module.c index c66faeb8..db21f790 100644 --- a/polyp/module.c +++ b/polyp/module.c @@ -38,7 +38,7 @@ #define PA_SYMBOL_INIT "pa__init" #define PA_SYMBOL_DONE "pa__done" -#define UNLOAD_POLL_TIME 10 +#define UNLOAD_POLL_TIME 2 static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, const struct timeval *tv, void *userdata) { struct pa_core *c = userdata; @@ -193,7 +193,7 @@ static int unused_callback(void *p, uint32_t index, int *del, void *userdata) { time_t *now = userdata; assert(p && del && now); - if (m->n_used == 0 && m->auto_unload && m->last_used_time+m->core->auto_unload_time <= *now) { + if (m->n_used == 0 && m->auto_unload && m->last_used_time+m->core->module_idle_time <= *now) { pa_module_free(m); *del = 1; } diff --git a/polyp/pacat.c b/polyp/pacat.c index ed95c2ca..b499f71a 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -286,7 +286,10 @@ static void stream_get_latency_callback(struct pa_stream *s, const struct pa_lat return; } - fprintf(stderr, "Current latency is %f usecs.\n", (float) (i->buffer_usec+i->sink_usec+i->transport_usec)); + fprintf(stderr, "Latency: buffer: %0.0f usec; sink: %0.0f usec; transport: %0.0f usec; total: %0.0f usec; synchronized clocks: %s.\n", + (float) i->buffer_usec, (float) i->sink_usec, (float) i->transport_usec, + (float) (i->buffer_usec+i->sink_usec+i->transport_usec), + i->synchronized_clocks ? "yes" : "no"); } /* Someone requested that the latency is shown */ diff --git a/polyp/pamodinfo.c b/polyp/pamodinfo.c deleted file mode 100644 index 6eb147f0..00000000 --- a/polyp/pamodinfo.c +++ /dev/null @@ -1,126 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "modinfo.h" - -#define PREFIX "module-" - -static int verbose = 0; - -static void short_info(const char *name, const char *path, struct pa_modinfo *i) { - assert(name && i); - printf("%-40s%s\n", name, i->description ? i->description : "n/a"); -} - -static void long_info(const char *name, const char *path, struct pa_modinfo *i) { - assert(name && i); - static int nl = 0; - - if (nl) - printf("\n"); - - nl = 1; - - printf("Name: %s\n", name); - - if (!i->description && !i->version && !i->author && !i->usage) - printf("No module information available\n"); - else { - if (i->version) - printf("Version: %s\n", i->version); - if (i->description) - printf("Description: %s\n", i->description); - if (i->author) - printf("Author: %s\n", i->author); - if (i->usage) - printf("Usage: %s\n", i->usage); - } - - if (path) - printf("Path: %s\n", path); -} - -static void show_info(const char *name, const char *path, void (*info)(const char *name, const char *path, struct pa_modinfo*i)) { - struct pa_modinfo *i; - - if ((i = pa_modinfo_get_by_name(path ? path : name))) { - info(name, path, i); - pa_modinfo_free(i); - } -} - -static int callback(const char *path, lt_ptr data) { - const char *e; - - if ((e = (const char*) strrchr(path, '/'))) - e++; - else - e = path; - - if (strlen(e) > sizeof(PREFIX)-1 && !strncmp(e, PREFIX, sizeof(PREFIX)-1)) - show_info(e, path, verbose ? long_info : short_info); - - return 0; -} - -int main(int argc, char *argv[]) { - int r = lt_dlinit(); - char *path = NULL; - int c; - assert(r == 0); - - while ((c = getopt(argc, argv, "p:v")) != -1) { - switch (c) { - case 'p': - path = optarg; - break; - case 'v': - verbose = 1; - break; - default: - return 1; - } - } - - if (path) - lt_dlsetsearchpath(path); -#ifdef DLSEARCHPATH - else - lt_dlsetsearchpath(DLSEARCHPATH); -#endif - - if (argc > optind) - show_info(argv[optind], NULL, long_info); - else - lt_dlforeachfile(NULL, callback, NULL); - - lt_dlexit(); -} diff --git a/polyp/polypaudio.pa b/polyp/polypaudio.pa deleted file mode 100755 index 15434627..00000000 --- a/polyp/polypaudio.pa +++ /dev/null @@ -1,62 +0,0 @@ -#!./polypaudio -rnF - -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with polypaudio; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - - -# Load audio drivers statically - -#load module-alsa-sink -load module-alsa-source device=plughw:1,0 -load module-oss device="/dev/dsp" sink_name=output source_name=input record=0 -#load module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#load module-pipe-sink - -# Load audio drivers automatically on access - -#autoload_sink_add output module-oss device="/dev/dsp" sink_name=output source_name=input -#autoload_source_add input module-oss device="/dev/dsp" sink_name=output source_name=input -#autoload_sink_add output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#autoload_source_add input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#autoload_sink_add output module-alsa-sink sink_name=output -#autoload_source_add input module-alsa-source source_name=input - -# Load several protocols -load module-esound-protocol-tcp -#load module-simple-protocol-tcp -load module-native-protocol-unix -#load module-cli-protocol-unix -#load module-esound-protocol-unix - -# Load the CLI module -load module-cli - -# Make some devices default -sink_default output -source_default input - -.nofail - -# Load something to the sample cache -scache_load /usr/share/sounds/KDE_Notify.wav x11-bell - -# Load X11 bell module -load module-x11-bell sample=x11-bell sink=output - -#load module-pipe-source -#load module-pipe-sink - diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index 176e1d3b..4a49a1f8 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -144,7 +144,16 @@ struct pa_latency_info { pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. */ pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to the daemon. \since 0.5 */ int playing; /**< Non-zero when the stream is currently playing */ - uint32_t queue_length; /**< Queue size in bytes. */ + uint32_t queue_length; /**< Queue size in bytes. */ + int synchronized_clocks; /**< Non-zero if the local and the + * remote machine have synchronized + * clocks. If synchronized clocks are + * detected transport_usec becomes much + * more reliable. However, the code that + * detects synchronized clocks is very + * limited und unreliable itself. \since + * 0.5 */ + struct timeval timestamp; /**< The time when this latency info was current */ }; PA_C_DECL_END diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 98610d61..b40b7f69 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -347,12 +347,18 @@ static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t comman gettimeofday(&now, NULL); - if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) + if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) { /* local and remote seem to have synchronized clocks */ i.transport_usec = pa_timeval_diff(&remote, &local); - else + i.synchronized_clocks = 1; + i.timestamp = remote; + } else { /* clocks are not synchronized, let's estimate latency then */ i.transport_usec = pa_timeval_diff(&now, &local)/2; + i.synchronized_clocks = 0; + i.timestamp = local; + pa_timeval_add(&i.timestamp, i.transport_usec); + } if (o->callback) { void (*cb)(struct pa_stream *s, const struct pa_latency_info *i, void *userdata) = o->callback; diff --git a/polyp/socket-util.c b/polyp/socket-util.c index 2f082bfb..20380653 100644 --- a/polyp/socket-util.c +++ b/polyp/socket-util.c @@ -101,15 +101,15 @@ int pa_socket_low_delay(int fd) { } int pa_socket_tcp_low_delay(int fd) { - int ret, tos; + int ret, tos, on; assert(fd >= 0); ret = pa_socket_low_delay(fd); -/* on = 1; */ -/* if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) */ -/* ret = -1; */ + on = 1; + if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) + ret = -1; tos = IPTOS_LOWDELAY; if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0) @@ -122,10 +122,10 @@ int pa_socket_tcp_low_delay(int fd) { int pa_socket_set_rcvbuf(int fd, size_t l) { assert(fd >= 0); - if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &l, sizeof(l)) < 0) { - pa_log(__FILE__": SO_RCVBUF: %s\n", strerror(errno)); - return -1; - } +/* if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &l, sizeof(l)) < 0) { */ +/* pa_log(__FILE__": SO_RCVBUF: %s\n", strerror(errno)); */ +/* return -1; */ +/* } */ return 0; } @@ -133,10 +133,10 @@ int pa_socket_set_rcvbuf(int fd, size_t l) { int pa_socket_set_sndbuf(int fd, size_t l) { assert(fd >= 0); - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &l, sizeof(l)) < 0) { - pa_log(__FILE__": SO_SNDBUF: %s\n", strerror(errno)); - return -1; - } +/* if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &l, sizeof(l)) < 0) { */ +/* pa_log(__FILE__": SO_SNDBUF: %s\n", strerror(errno)); */ +/* return -1; */ +/* } */ return 0; } diff --git a/polyp/util.c b/polyp/util.c index 1dbb8697..039ec264 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -268,6 +268,22 @@ pa_usec_t pa_age(const struct timeval *tv) { return pa_timeval_diff(&now, tv); } +void pa_timeval_add(struct timeval *tv, pa_usec_t v) { + unsigned long secs; + assert(tv); + + secs = (v/1000000); + tv->tv_sec += (unsigned long) secs; + v -= secs*1000000; + + tv->tv_usec += v; + + while (tv->tv_usec >= 1000000) { + tv->tv_sec++; + tv->tv_usec -= 1000000; + } +} + #define NICE_LEVEL (-15) void pa_raise_priority(void) { @@ -347,3 +363,13 @@ char *pa_path_get_filename(const char *p) { return (char*) p; } + +int pa_parse_boolean(const char *v) { + + if (!strcmp(v, "1") || !strcasecmp(v, "yes") || !strcasecmp(v, "y") || !strcasecmp(v, "on")) + return 1; + else if (!strcmp(v, "0") || !strcasecmp(v, "no") || !strcasecmp(v, "n") || !strcasecmp(v, "off")) + return 0; + + return -1; +} diff --git a/polyp/util.h b/polyp/util.h index f34ba4c0..42e0b22b 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -50,10 +50,13 @@ char *pa_path_get_filename(const char *p); pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); pa_usec_t pa_age(const struct timeval *tv); +void pa_timeval_add(struct timeval *tv, pa_usec_t v); void pa_raise_priority(void); void pa_reset_priority(void); int pa_fd_set_cloexec(int fd, int b); +int pa_parse_boolean(const char *s); + #endif -- cgit From 8c6593dabf3253e20fead143855267570a403c9a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 14 Sep 2004 17:52:11 +0000 Subject: add module-combine remove option "stay-root" clean up pa_conf git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@199 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 9 +- polyp/Makefile.am | 7 +- polyp/cmdline.c | 19 +-- polyp/conf.c | 8 +- polyp/conf.h | 16 ++- polyp/config | 12 +- polyp/log.c | 1 + polyp/main.c | 57 ++++---- polyp/module-combine.c | 353 ++++++++++++++++++++++++++++++++++++++++++++++ polyp/module-sine.c | 2 +- polyp/play-memchunk.c | 2 +- polyp/protocol-esound.c | 2 +- polyp/protocol-native.c | 2 +- polyp/protocol-simple.c | 2 +- polyp/resampler.c | 18 ++- polyp/resampler.h | 2 + polyp/sink-input.c | 14 +- polyp/sink-input.h | 4 +- polyp/sound-file-stream.c | 2 +- polyp/util.c | 16 +++ polyp/util.h | 2 + 21 files changed, 469 insertions(+), 81 deletions(-) create mode 100644 polyp/module-combine.c diff --git a/doc/todo b/doc/todo index 135a336d..8daabc33 100644 --- a/doc/todo +++ b/doc/todo @@ -3,22 +3,25 @@ *** 0.5 *** - make mcalign merge chunks - use ref counting in more objects (i.e. sink, source, sink_input, source_output) -- unix socket directories include user name - native library/protocol: module load/unload kill client/... autoload management rename streams/contexts - more complete pactl -- add sample directory - option to use default fragment size on alsa drivers - lazy sample cache -- per-channel volume - merge pa_context_connect_* - input latency - fix tcp/native - add volume to create_stream command in native protocol - udp based protocol +- make sure not to allow recursive auto load + +*** 0.6 **** +- per-channel volume +- unix socket directories include user name +- add sample directory ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index e9e1c295..9c672a3b 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -101,7 +101,8 @@ modlib_LTLIBRARIES= \ module-native-protocol-tcp.la \ module-native-protocol-unix.la \ module-native-protocol-fd.la \ - module-sine.la + module-sine.la \ + module-combine.la lib_LTLIBRARIES= \ libpolyp-@PA_MAJORMINOR@.la \ @@ -295,6 +296,10 @@ module_sine_la_SOURCES = module-sine.c module_sine_la_LDFLAGS = -module -avoid-version module_sine_la_LIBADD = $(AM_LIBADD) +module_combine_la_SOURCES = module-combine.c +module_combine_la_LDFLAGS = -module -avoid-version +module_combine_la_LIBADD = $(AM_LIBADD) + libpolyp_@PA_MAJORMINOR@_la_SOURCES = polyplib.h \ polyplib-def.h \ tagstruct.c tagstruct.h \ diff --git a/polyp/cmdline.c b/polyp/cmdline.c index 4e7cde48..47685ca9 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -44,7 +44,6 @@ enum { ARG_FAIL, ARG_VERBOSE, ARG_HIGH_PRIORITY, - ARG_STAY_ROOT, ARG_DISALLOW_MODULE_LOADING, ARG_EXIT_IDLE_TIME, ARG_MODULE_IDLE_TIME, @@ -63,7 +62,6 @@ static struct option long_options[] = { {"fail", 2, 0, ARG_FAIL}, {"verbose", 2, 0, ARG_VERBOSE}, {"high-priority", 2, 0, ARG_HIGH_PRIORITY}, - {"stay-root", 2, 0, ARG_STAY_ROOT}, {"disallow-module-loading", 2, 0, ARG_DISALLOW_MODULE_LOADING}, {"exit-idle-time", 2, 0, ARG_EXIT_IDLE_TIME}, {"module-idle-time", 2, 0, ARG_MODULE_IDLE_TIME}, @@ -93,7 +91,6 @@ void pa_cmdline_help(const char *argv0) { " --fail[=BOOL] Quit when startup fails\n" " --verbose[=BOOL] Be slightly more verbose\n" " --high-priority[=BOOL] Try to set high process priority (only available as root)\n" - " --stay-root[=BOOL] Don't drop root if SETUID root\n" " --disallow-module-loading[=BOOL] Disallow module loading after startup\n" " --exit-idle-time=SECS Terminate the daemon when idle and this time passed\n" " --module-idle-time=SECS Unload autoloaded modules when idle and this time passed\n" @@ -113,7 +110,6 @@ int pa_cmdline_parse(struct pa_conf *conf, int argc, char *const argv [], int *d assert(conf && argc && argv); buf = pa_strbuf_new(); - assert(buf); if (conf->script_commands) pa_strbuf_puts(buf, conf->script_commands); @@ -122,19 +118,19 @@ int pa_cmdline_parse(struct pa_conf *conf, int argc, char *const argv [], int *d switch (c) { case ARG_HELP: case 'h': - conf->help = 1; + conf->cmd = PA_CMD_HELP; break; case ARG_VERSION: - conf->version = 1; + conf->cmd = PA_CMD_VERSION; break; case ARG_DUMP_CONF: - conf->dump_conf = 1; + conf->cmd = PA_CMD_DUMP_CONF; break; case ARG_DUMP_MODULES: - conf->dump_modules = 1; + conf->cmd = PA_CMD_DUMP_MODULES; break; case ARG_LOAD: @@ -180,13 +176,6 @@ int pa_cmdline_parse(struct pa_conf *conf, int argc, char *const argv [], int *d } break; - case ARG_STAY_ROOT: - if ((conf->stay_root = optarg ? pa_parse_boolean(optarg) : 1) < 0) { - pa_log(__FILE__": --stay-root expects boolean argument\n"); - goto fail; - } - break; - case ARG_DISALLOW_MODULE_LOADING: if ((conf->disallow_module_loading = optarg ? pa_parse_boolean(optarg) : 1) < 0) { pa_log(__FILE__": --disallow-module-loading expects boolean argument\n"); diff --git a/polyp/conf.c b/polyp/conf.c index 4a11c480..9f1f6ba2 100644 --- a/polyp/conf.c +++ b/polyp/conf.c @@ -35,15 +35,11 @@ #include "strbuf.h" static const struct pa_conf default_conf = { - .help = 0, + .cmd = PA_CMD_DAEMON, .daemonize = 0, - .dump_conf = 0, - .dump_modules = 0, .fail = 1, .verbose = 0, .high_priority = 0, - .stay_root = 0, - .version = 0, .disallow_module_loading = 0, .exit_idle_time = -1, .module_idle_time = 20, @@ -143,7 +139,6 @@ static int next_assignment(struct pa_conf *c, char *lvalue, char *rvalue, unsign PARSE_BOOLEAN("fail", fail); PARSE_BOOLEAN("verbose", verbose); PARSE_BOOLEAN("high-priority", high_priority); - PARSE_BOOLEAN("stay-root", stay_root); PARSE_BOOLEAN("disallow-module-loading", disallow_module_loading); PARSE_INTEGER("exit-idle-time", exit_idle_time); @@ -269,7 +264,6 @@ char *pa_conf_dump(struct pa_conf *c) { pa_strbuf_printf(s, "daemonize = %i\n", !!c->daemonize); pa_strbuf_printf(s, "fail = %i\n", !!c->fail); pa_strbuf_printf(s, "high-priority = %i\n", !!c->high_priority); - pa_strbuf_printf(s, "stay-root = %i\n", !!c->stay_root); pa_strbuf_printf(s, "disallow-module-loading = %i\n", !!c->disallow_module_loading); pa_strbuf_printf(s, "exit-idle-time = %i\n", c->exit_idle_time); pa_strbuf_printf(s, "module-idle-time = %i\n", c->module_idle_time); diff --git a/polyp/conf.h b/polyp/conf.h index bbe253c2..da61be33 100644 --- a/polyp/conf.h +++ b/polyp/conf.h @@ -24,16 +24,20 @@ #include "log.h" +enum pa_conf_cmd { + PA_CMD_DAEMON, + PA_CMD_HELP, + PA_CMD_VERSION, + PA_CMD_DUMP_CONF, + PA_CMD_DUMP_MODULES +}; + struct pa_conf { - int help, - version, - dump_conf, - dump_modules, - daemonize, + enum pa_conf_cmd cmd; + int daemonize, fail, verbose, high_priority, - stay_root, disallow_module_loading, exit_idle_time, module_idle_time, diff --git a/polyp/config b/polyp/config index e0f8de50..b404bc40 100644 --- a/polyp/config +++ b/polyp/config @@ -31,11 +31,10 @@ ## Renice the daemon to level -15 and try to get SCHED_FIFO ## scheduling. This a good idea if you hear annyoing noise in the -## playback. However, this is a certain security issue. -; high-priority = 0 - -## Don't drop root rights on startup if called SUID root. -; stay-root = 0 +## playback. However, this is a certain security issue, since it works +## when called SUID root only. root is dropped immediately after gaining +## the nice level and SCHED_FIFO scheduling on startup. +high-priority = 0 ## Disallow module loading after startup ; disallow-module-loading = 0 @@ -48,7 +47,8 @@ module-idle-time = 20 ## The path were to look for dynamic shared objects (DSOs aka plugins). -## Specify an empty string for the default search path. +## Specify an empty string for the default search path. You may specify +## more than one path seperated by colons. ; dl-search-path = ## The default script file to load. Specify an empty string for not diff --git a/polyp/log.c b/polyp/log.c index 413266df..516cd2b0 100644 --- a/polyp/log.c +++ b/polyp/log.c @@ -41,6 +41,7 @@ void pa_log(const char *format, ...) { char *t = pa_vsprintf_malloc(format, ap); assert(user_log_func); user_log_func(t); + pa_xfree(t); } } diff --git a/polyp/main.c b/polyp/main.c index 148dfac2..9de69ca6 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -124,6 +124,11 @@ int main(int argc, char *argv[]) { pa_log_set_target(conf->auto_log_target ? PA_LOG_STDERR : conf->log_target, NULL); + if (conf->high_priority && conf->cmd == PA_CMD_DAEMON) + pa_raise_priority(); + + drop_root(); + if (conf->dl_search_path) lt_dlsetsearchpath(conf->dl_search_path); #ifdef DLSEARCHPATH @@ -131,37 +136,33 @@ int main(int argc, char *argv[]) { lt_dlsetsearchpath(DLSEARCHPATH); #endif - if (conf->dump_modules) { - pa_dump_modules(conf, argc-d, argv+d); - retval = 0; - goto finish; - } - - if (conf->dump_conf) { - char *s = pa_conf_dump(conf); - fputs(s, stdout); - pa_xfree(s); - retval = 0; - goto finish; - } + switch (conf->cmd) { + case PA_CMD_DUMP_MODULES: + pa_dump_modules(conf, argc-d, argv+d); + retval = 0; + goto finish; - if (conf->help) { - pa_cmdline_help(argv[0]); - retval = 0; - goto finish; - } + case PA_CMD_DUMP_CONF: { + char *s = pa_conf_dump(conf); + fputs(s, stdout); + pa_xfree(s); + retval = 0; + goto finish; + } - if (conf->version) { - printf(PACKAGE_NAME" "PACKAGE_VERSION"\n"); - retval = 0; - goto finish; - } + case PA_CMD_HELP : + pa_cmdline_help(argv[0]); + retval = 0; + goto finish; - if (conf->high_priority) - pa_raise_priority(); - - if (!conf->stay_root) - drop_root(); + case PA_CMD_VERSION : + printf(PACKAGE_NAME" "PACKAGE_VERSION"\n"); + retval = 0; + goto finish; + + default: + assert(conf->cmd == PA_CMD_DAEMON); + } if (conf->daemonize) { pid_t child; diff --git a/polyp/module-combine.c b/polyp/module-combine.c new file mode 100644 index 00000000..0ab9d9ec --- /dev/null +++ b/polyp/module-combine.c @@ -0,0 +1,353 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "module.h" +#include "llist.h" +#include "sink.h" +#include "sink-input.h" +#include "memblockq.h" +#include "log.h" +#include "util.h" +#include "xmalloc.h" +#include "modargs.h" +#include "namereg.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Makes one playback device out of many") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink_name= master= slave=") + +#define DEFAULT_SINK_NAME "combine" +#define MEMBLOCKQ_MAXLENGTH (1024*170) +#define RENDER_SIZE (1024*10) + +#define ADJUST_TIME 5 + +static const char* const valid_modargs[] = { + "sink_name", + "master", + "slaves", + NULL +}; + +struct output { + struct userdata *userdata; + struct pa_sink_input *sink_input; + size_t counter; + struct pa_memblockq *memblockq; + pa_usec_t sink_latency; + PA_LLIST_FIELDS(struct output); +}; + +struct userdata { + struct pa_module *module; + struct pa_core *core; + struct pa_sink *sink; + unsigned n_outputs; + struct output *master; + struct pa_time_event *time_event; + + PA_LLIST_HEAD(struct output, outputs); +}; + +static void output_free(struct output *o); +static void clear_up(struct userdata *u); + +static void adjust_rates(struct userdata *u) { + struct output *o; + pa_usec_t max = 0; + uint32_t base_rate; + assert(u && u->sink); + + for (o = u->outputs; o; o = o->next) { + o->sink_latency = pa_sink_get_latency(o->sink_input->sink); + + if (o->sink_latency > max) + max = o->sink_latency; + } + + pa_log(__FILE__": [%s] maximum latency is %0.0f usec.\n", u->sink->name, (float) max); + + base_rate = u->sink->sample_spec.rate; + + for (o = u->outputs; o; o = o->next) { + pa_usec_t l; + uint32_t r = base_rate; + + l = o->sink_latency + pa_sink_input_get_latency(o->sink_input); + + if (l < max) + r -= (uint32_t) (((((double) max-l))/ADJUST_TIME)*r/ 1000000); + else if (l > max) + r += (uint32_t) (((((double) l-max))/ADJUST_TIME)*r/ 1000000); + + if (r < (uint32_t) (base_rate*0.9) || r > (uint32_t) (base_rate*1.1)) + pa_log(__FILE__": [%s] sample rates too different, not adjusting (%u vs. %u).\n", o->sink_input->name, base_rate, r); + else + pa_log(__FILE__": [%s] new rate is %u Hz; ratio is %0.3f; latency is %0.0f usec.\n", o->sink_input->name, r, (double) r / base_rate, (float) l); + + pa_sink_input_set_rate(o->sink_input, r); + } +} + +static void request_memblock(struct userdata *u) { + struct pa_memchunk chunk; + struct output *o; + assert(u && u->sink); + + if (pa_sink_render(u->sink, RENDER_SIZE, &chunk) < 0) + return; + + for (o = u->outputs; o; o = o->next) + pa_memblockq_push_align(o->memblockq, &chunk, 0); + + pa_memblock_unref(chunk.memblock); +} + +static void time_callback(struct pa_mainloop_api*a, struct pa_time_event* e, const struct timeval *tv, void *userdata) { + struct userdata *u = userdata; + struct timeval n; + assert(u && a && u->time_event == e); + + adjust_rates(u); + + gettimeofday(&n, NULL); + n.tv_sec += ADJUST_TIME; + u->sink->core->mainloop->time_restart(e, &n); +} + +static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk) { + struct output *o = i->userdata; + assert(i && o && o->sink_input && chunk); + + if (pa_memblockq_peek(o->memblockq, chunk) >= 0) + return 0; + + /* Try harder */ + request_memblock(o->userdata); + + return pa_memblockq_peek(o->memblockq, chunk); +} + +static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length) { + struct output *o = i->userdata; + assert(i && o && o->sink_input && chunk && length); + + pa_memblockq_drop(o->memblockq, chunk, length); + o->counter += length; +} + +static void sink_input_kill_cb(struct pa_sink_input *i) { + struct output *o = i->userdata; + assert(i && o && o->sink_input); + clear_up(o->userdata); +} + +static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i) { + struct output *o = i->userdata; + assert(i && o && o->sink_input); + + return pa_bytes_to_usec(pa_memblockq_get_length(o->memblockq), &i->sample_spec); +} + +static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { + struct userdata *u = s->userdata; + assert(s && u && u->sink && u->master); + + return pa_sink_input_get_latency(u->master->sink_input); +} + +static struct output *output_new(struct userdata *u, struct pa_sink *sink) { + struct output *o = NULL; + char t[256]; + assert(u && sink && u->sink); + + o = pa_xmalloc(sizeof(struct output)); + o->userdata = u; + + o->counter = 0; + o->memblockq = pa_memblockq_new(MEMBLOCKQ_MAXLENGTH, MEMBLOCKQ_MAXLENGTH, pa_frame_size(&u->sink->sample_spec), 0, 0, sink->core->memblock_stat); + + snprintf(t, sizeof(t), "%s: output #%u", u->sink->name, u->n_outputs+1); + if (!(o->sink_input = pa_sink_input_new(sink, t, &u->sink->sample_spec, 1))) + goto fail; + + o->sink_input->get_latency = sink_input_get_latency_cb; + o->sink_input->peek = sink_input_peek_cb; + o->sink_input->drop = sink_input_drop_cb; + o->sink_input->kill = sink_input_kill_cb; + o->sink_input->userdata = o; + o->sink_input->owner = u->module; + + PA_LLIST_PREPEND(struct output, u->outputs, o); + u->n_outputs++; + return o; + +fail: + + if (o) { + if (o->sink_input) + pa_sink_input_free(o->sink_input); + + if (o->memblockq) + pa_memblockq_free(o->memblockq); + + pa_xfree(o); + } + + return NULL; +} + +static void output_free(struct output *o) { + assert(o); + PA_LLIST_REMOVE(struct output, o->userdata->outputs, o); + o->userdata->n_outputs--; + pa_memblockq_free(o->memblockq); + pa_sink_input_free(o->sink_input); + pa_xfree(o); +} + +static void clear_up(struct userdata *u) { + struct output *o; + assert(u); + + if (u->time_event) { + u->core->mainloop->time_free(u->time_event); + u->time_event = NULL; + } + + while ((o = u->outputs)) + output_free(o); + + u->master = NULL; + + if (u->sink) { + pa_sink_free(u->sink); + u->sink = NULL; + } +} + +int pa__init(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + struct pa_modargs *ma = NULL; + const char *master_name, *slaves; + struct pa_sink *master_sink; + char *n = NULL; + const char*split_state; + struct timeval tv; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments\n"); + goto fail; + } + + u = pa_xmalloc(sizeof(struct userdata)); + m->userdata = u; + u->sink = NULL; + u->n_outputs = 0; + u->master = NULL; + u->module = m; + u->core = c; + u->time_event = NULL; + PA_LLIST_HEAD_INIT(struct output, u->outputs); + + if (!(master_name = pa_modargs_get_value(ma, "master", NULL)) || !(slaves = pa_modargs_get_value(ma, "slaves", NULL))) { + pa_log(__FILE__": no master or slave sinks specified\n"); + goto fail; + } + + if (!(master_sink = pa_namereg_get(c, master_name, PA_NAMEREG_SINK, 1))) { + pa_log(__FILE__": invalid master sink '%s'\n", master_name); + goto fail; + } + + if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &master_sink->sample_spec))) { + pa_log(__FILE__": failed to create sink\n"); + goto fail; + } + + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Combined sink"); + u->sink->get_latency = sink_get_latency_cb; + u->sink->userdata = u; + + if (!(u->master = output_new(u, master_sink))) { + pa_log(__FILE__": failed to create master sink input on sink '%s'.\n", u->sink->name); + goto fail; + } + + split_state = NULL; + while ((n = pa_split(slaves, ",", &split_state))) { + struct pa_sink *slave_sink; + + if (!(slave_sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) { + pa_log(__FILE__": invalid slave sink '%s'\n", n); + goto fail; + } + + pa_xfree(n); + + if (!output_new(u, slave_sink)) { + pa_log(__FILE__": failed to create slave sink input on sink '%s'.\n", slave_sink->name); + goto fail; + } + } + + if (u->n_outputs <= 1) + pa_log(__FILE__": WARNING: no slave sinks specified.\n"); + + gettimeofday(&tv, NULL); + tv.tv_sec += ADJUST_TIME; + u->time_event = c->mainloop->time_new(c->mainloop, &tv, time_callback, u); + + pa_modargs_free(ma); + return 0; + +fail: + pa_xfree(n); + + if (ma) + pa_modargs_free(ma); + + pa__done(c, m); + return -1; +} + +void pa__done(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + clear_up(u); + pa_xfree(u); +} + + diff --git a/polyp/module-sine.c b/polyp/module-sine.c index 98e0dc28..b537452a 100644 --- a/polyp/module-sine.c +++ b/polyp/module-sine.c @@ -134,7 +134,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { calc_sine(u->memblock->data, u->memblock->length, frequency); snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency); - if (!(u->sink_input = pa_sink_input_new(sink, t, &ss))) + if (!(u->sink_input = pa_sink_input_new(sink, t, &ss, 0))) goto fail; u->sink_input->peek = sink_input_peek; diff --git a/polyp/play-memchunk.c b/polyp/play-memchunk.c index e3f0c006..ace8ca69 100644 --- a/polyp/play-memchunk.c +++ b/polyp/play-memchunk.c @@ -85,7 +85,7 @@ int pa_play_memchunk(struct pa_sink *sink, const char *name, const struct pa_sam if (volume <= 0) return 0; - if (!(si = pa_sink_input_new(sink, name, ss))) + if (!(si = pa_sink_input_new(sink, name, ss, 0))) return -1; si->volume = volume; diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index ee64c484..103b17a3 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -298,7 +298,7 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons c->playback.fragment_size = l/10; assert(!c->sink_input); - c->sink_input = pa_sink_input_new(sink, name, &ss); + c->sink_input = pa_sink_input_new(sink, name, &ss, 0); assert(c->sink_input); c->sink_input->owner = c->protocol->module; diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 2d26c2f5..c1b19760 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -269,7 +269,7 @@ static struct playback_stream* playback_stream_new(struct connection *c, struct struct pa_sink_input *sink_input; assert(c && sink && ss && name && maxlength); - if (!(sink_input = pa_sink_input_new(sink, name, ss))) + if (!(sink_input = pa_sink_input_new(sink, name, ss, 0))) return NULL; s = pa_xmalloc(sizeof(struct playback_stream)); diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index 00db0aa0..96444f82 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -304,7 +304,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo goto fail; } - if (!(c->sink_input = pa_sink_input_new(sink, c->client->name, &p->sample_spec))) { + if (!(c->sink_input = pa_sink_input_new(sink, c->client->name, &p->sample_spec, 0))) { pa_log(__FILE__": Failed to create sink input.\n"); goto fail; } diff --git a/polyp/resampler.c b/polyp/resampler.c index 173c0987..4742ce21 100644 --- a/polyp/resampler.c +++ b/polyp/resampler.c @@ -67,12 +67,9 @@ struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const stru r->i_buf = r->o_buf = NULL; r->i_alloc = r->o_alloc = 0; - if (a->rate != b->rate) { - r->src_state = src_new(SRC_SINC_FASTEST, r->channels, &err); - if (err != 0 || !r->src_state) - goto fail; - } else - r->src_state = NULL; + r->src_state = src_new(SRC_SINC_FASTEST, r->channels, &err); + if (err != 0 || !r->src_state) + goto fail; r->i_ss = *a; r->o_ss = *b; @@ -196,3 +193,12 @@ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, stru out->memblock = NULL; } } + +void pa_resampler_set_input_rate(struct pa_resampler *r, uint32_t rate) { + int ret; + assert(r); + + r->i_ss.rate = rate; + ret = src_set_ratio(r->src_state, (double) r->o_ss.rate / r->i_ss.rate); + assert(ret == 0); +} diff --git a/polyp/resampler.h b/polyp/resampler.h index e23d145d..a6ef30df 100644 --- a/polyp/resampler.h +++ b/polyp/resampler.h @@ -34,4 +34,6 @@ void pa_resampler_free(struct pa_resampler *r); size_t pa_resampler_request(struct pa_resampler *r, size_t out_length); void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out); +void pa_resampler_set_input_rate(struct pa_resampler *r, uint32_t rate); + #endif diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 7763f261..0d59062d 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -36,7 +36,7 @@ #define CONVERT_BUFFER_LENGTH 4096 -struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec) { +struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec, int variable_rate) { struct pa_sink_input *i; struct pa_resampler *resampler = NULL; int r; @@ -48,7 +48,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con return NULL; } - if (!pa_sample_spec_equal(spec, &s->sample_spec)) + if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec)) if (!(resampler = pa_resampler_new(spec, &s->sample_spec, s->core->memblock_stat))) return NULL; @@ -199,3 +199,13 @@ void pa_sink_input_cork(struct pa_sink_input *i, int b) { if (n) pa_sink_notify(i->sink); } + +void pa_sink_input_set_rate(struct pa_sink_input *i, uint32_t rate) { + assert(i && i->resampler); + + if (i->sample_spec.rate == rate) + return; + + i->sample_spec.rate = rate; + pa_resampler_set_input_rate(i->resampler, rate); +} diff --git a/polyp/sink-input.h b/polyp/sink-input.h index e2478ed6..e5b06387 100644 --- a/polyp/sink-input.h +++ b/polyp/sink-input.h @@ -54,7 +54,7 @@ struct pa_sink_input { struct pa_resampler *resampler; }; -struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec); +struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec, int variable_rate); void pa_sink_input_free(struct pa_sink_input* i); /* Code that didn't create the input stream should call this function to @@ -70,4 +70,6 @@ void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume); void pa_sink_input_cork(struct pa_sink_input *i, int b); +void pa_sink_input_set_rate(struct pa_sink_input *i, uint32_t rate); + #endif diff --git a/polyp/sound-file-stream.c b/polyp/sound-file-stream.c index c667f5ff..e77ff119 100644 --- a/polyp/sound-file-stream.c +++ b/polyp/sound-file-stream.c @@ -142,7 +142,7 @@ int pa_play_file(struct pa_sink *sink, const char *fname, pa_volume_t volume) { goto fail; } - if (!(u->sink_input = pa_sink_input_new(sink, fname, &ss))) + if (!(u->sink_input = pa_sink_input_new(sink, fname, &ss, 0))) goto fail; u->sink_input->volume = volume; diff --git a/polyp/util.c b/polyp/util.c index 039ec264..3ab6d51a 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -373,3 +373,19 @@ int pa_parse_boolean(const char *v) { return -1; } + +char *pa_split(const char *c, const char *delimiter, const char**state) { + const char *current = *state ? *state : c; + size_t l; + + if (!*current) + return NULL; + + l = strcspn(current, delimiter); + *state = current+l; + + if (**state) + *state++; + + return pa_xstrndup(current, l); +} diff --git a/polyp/util.h b/polyp/util.h index 42e0b22b..eae98e6e 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -59,4 +59,6 @@ int pa_fd_set_cloexec(int fd, int b); int pa_parse_boolean(const char *s); +char *pa_split(const char *c, const char*delimiters, const char **state); + #endif -- cgit From 6e019795bff589ef0a867772975e34da78fffefb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 14 Sep 2004 20:53:25 +0000 Subject: add refernce counting for sinks, sources, sink-inputs and source-outputs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@200 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/cli-command.c | 2 +- polyp/core.c | 1 + polyp/core.h | 1 + polyp/module-alsa-sink.c | 6 ++- polyp/module-alsa-source.c | 6 ++- polyp/module-cli.c | 2 +- polyp/module-combine.c | 17 ++++--- polyp/module-oss-mmap.c | 12 +++-- polyp/module-oss.c | 13 +++-- polyp/module-pipe-sink.c | 3 +- polyp/module-pipe-source.c | 3 +- polyp/module-sine.c | 14 ++++-- polyp/module.c | 57 ++++++++++++++-------- polyp/module.h | 8 +-- polyp/play-memchunk.c | 5 +- polyp/protocol-esound.c | 14 ++++-- polyp/protocol-native.c | 6 ++- polyp/protocol-simple.c | 12 +++-- polyp/sink-input.c | 84 +++++++++++++++++++++++++------- polyp/sink-input.h | 21 ++++++-- polyp/sink.c | 119 ++++++++++++++++++++++++++++++++++----------- polyp/sink.h | 13 ++++- polyp/sound-file-stream.c | 7 ++- polyp/source-output.c | 56 +++++++++++++++++---- polyp/source-output.h | 17 ++++++- polyp/source.c | 45 ++++++++++++++--- polyp/source.h | 12 ++++- 27 files changed, 425 insertions(+), 131 deletions(-) diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 52926199..b44fbf4a 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -294,7 +294,7 @@ static int pa_cli_command_unload(struct pa_core *c, struct pa_tokenizer *t, stru return -1; } - pa_module_unload_request(c, m); + pa_module_unload_request(m); return 0; } diff --git a/polyp/core.c b/polyp/core.c index 0b33c107..0b0bbb56 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -62,6 +62,7 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->default_sample_spec.channels = 2; c->auto_unload_event = NULL; + c->defer_unload_event = NULL; c->subscription_defer_event = NULL; c->subscription_event_queue = NULL; diff --git a/polyp/core.h b/polyp/core.h index a85dafd4..b4470577 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -39,6 +39,7 @@ struct pa_core { struct pa_sample_spec default_sample_spec; struct pa_time_event *auto_unload_event; + struct pa_defer_event *defer_unload_event; struct pa_defer_event *subscription_defer_event; struct pa_queue *subscription_event_queue; diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index 55e719c9..c31b73f0 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -259,8 +259,10 @@ void pa__done(struct pa_core *c, struct pa_module*m) { if (!(u = m->userdata)) return; - if (u->sink) - pa_sink_free(u->sink); + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + } if (u->io_events) pa_free_io_events(c->mainloop, u->io_events, u->n_io_events); diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index 3ef54b17..cf828eb0 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -232,8 +232,10 @@ void pa__done(struct pa_core *c, struct pa_module*m) { if (!(u = m->userdata)) return; - if (u->source) - pa_source_free(u->source); + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + } if (u->io_events) pa_free_io_events(c->mainloop, u->io_events, u->n_io_events); diff --git a/polyp/module-cli.c b/polyp/module-cli.c index 35b69cb6..94c65d07 100644 --- a/polyp/module-cli.c +++ b/polyp/module-cli.c @@ -41,7 +41,7 @@ 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); + pa_module_unload_request(m); } int pa__init(struct pa_core *c, struct pa_module*m) { diff --git a/polyp/module-combine.c b/polyp/module-combine.c index 0ab9d9ec..28e3b39d 100644 --- a/polyp/module-combine.c +++ b/polyp/module-combine.c @@ -38,7 +38,7 @@ #include "namereg.h" PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Makes one playback device out of many") +PA_MODULE_DESCRIPTION("Combine multiple sinks to one") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink_name= master= slave=") @@ -85,7 +85,7 @@ static void adjust_rates(struct userdata *u) { assert(u && u->sink); for (o = u->outputs; o; o = o->next) { - o->sink_latency = pa_sink_get_latency(o->sink_input->sink); + o->sink_latency = o->sink_input->sink ? pa_sink_get_latency(o->sink_input->sink) : 0; if (o->sink_latency > max) max = o->sink_latency; @@ -165,6 +165,7 @@ static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk static void sink_input_kill_cb(struct pa_sink_input *i) { struct output *o = i->userdata; assert(i && o && o->sink_input); + pa_module_unload_request(o->userdata->module); clear_up(o->userdata); } @@ -211,8 +212,10 @@ static struct output *output_new(struct userdata *u, struct pa_sink *sink) { fail: if (o) { - if (o->sink_input) - pa_sink_input_free(o->sink_input); + if (o->sink_input) { + pa_sink_input_disconnect(o->sink_input); + pa_sink_input_unref(o->sink_input); + } if (o->memblockq) pa_memblockq_free(o->memblockq); @@ -228,7 +231,8 @@ static void output_free(struct output *o) { PA_LLIST_REMOVE(struct output, o->userdata->outputs, o); o->userdata->n_outputs--; pa_memblockq_free(o->memblockq); - pa_sink_input_free(o->sink_input); + pa_sink_input_disconnect(o->sink_input); + pa_sink_input_unref(o->sink_input); pa_xfree(o); } @@ -247,7 +251,8 @@ static void clear_up(struct userdata *u) { u->master = NULL; if (u->sink) { - pa_sink_free(u->sink); + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); u->sink = NULL; } } diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index 8e165218..015f4c6c 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -403,11 +403,15 @@ void pa__done(struct pa_core *c, struct pa_module*m) { if (u->out_mmap && u->out_mmap != MAP_FAILED) munmap(u->out_mmap, u->out_mmap_length); - if (u->sink) - pa_sink_free(u->sink); + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + } - if (u->source) - pa_source_free(u->source); + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + } if (u->io_event) u->core->mainloop->io_free(u->io_event); diff --git a/polyp/module-oss.c b/polyp/module-oss.c index b4e011d8..a45f72b8 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -322,10 +322,15 @@ void pa__done(struct pa_core *c, struct pa_module*m) { if (u->silence.memblock) pa_memblock_unref(u->silence.memblock); - if (u->sink) - pa_sink_free(u->sink); - if (u->source) - pa_source_free(u->source); + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + } + + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + } pa_iochannel_free(u->io); pa_xfree(u); diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c index 1aaf3b6a..57e7425b 100644 --- a/polyp/module-pipe-sink.c +++ b/polyp/module-pipe-sink.c @@ -215,7 +215,8 @@ void pa__done(struct pa_core *c, struct pa_module*m) { if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); - pa_sink_free(u->sink); + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); pa_iochannel_free(u->io); u->core->mainloop->defer_free(u->defer_event); diff --git a/polyp/module-pipe-source.c b/polyp/module-pipe-source.c index a226d44e..61fcdce8 100644 --- a/polyp/module-pipe-source.c +++ b/polyp/module-pipe-source.c @@ -195,7 +195,8 @@ void pa__done(struct pa_core *c, struct pa_module*m) { if (u->chunk.memblock) pa_memblock_unref(u->chunk.memblock); - pa_source_free(u->source); + pa_source_disconnect(u->source); + pa_source_unref(u->source); pa_iochannel_free(u->io); assert(u->filename); diff --git a/polyp/module-sine.c b/polyp/module-sine.c index b537452a..2fa7759c 100644 --- a/polyp/module-sine.c +++ b/polyp/module-sine.c @@ -41,6 +41,7 @@ PA_MODULE_VERSION(PACKAGE_VERSION) struct userdata { struct pa_core *core; + struct pa_module *module; struct pa_sink_input *sink_input; struct pa_memblock *memblock; size_t peek_index; @@ -81,8 +82,11 @@ static void sink_input_kill(struct pa_sink_input *i) { assert(i && i->userdata); u = i->userdata; - pa_sink_input_free(u->sink_input); + pa_sink_input_disconnect(u->sink_input); + pa_sink_input_unref(u->sink_input); u->sink_input = NULL; + + pa_module_unload_request(u->module); } static void calc_sine(float *f, size_t l, float freq) { @@ -110,6 +114,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { m->userdata = u = pa_xmalloc(sizeof(struct userdata)); u->core = c; + u->module = m; u->sink_input = NULL; u->memblock = NULL; @@ -163,8 +168,11 @@ void pa__done(struct pa_core *c, struct pa_module*m) { if (!u) return; - if (u->sink_input) - pa_sink_input_free(u->sink_input); + if (u->sink_input) { + pa_sink_input_disconnect(u->sink_input); + pa_sink_input_unref(u->sink_input); + } + if (u->memblock) pa_memblock_unref(u->memblock); pa_xfree(u); diff --git a/polyp/module.c b/polyp/module.c index db21f790..73f5468c 100644 --- a/polyp/module.c +++ b/polyp/module.c @@ -85,6 +85,7 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char m->core = c; m->n_used = -1; m->auto_unload = 0; + m->unload_requested = 0; assert(m->init); if (m->init(c, m) < 0) { @@ -183,9 +184,15 @@ void pa_module_unload_all(struct pa_core *c) { pa_idxset_free(c->modules, free_callback, NULL); c->modules = NULL; - if (c->auto_unload_event) + if (c->auto_unload_event) { c->mainloop->time_free(c->auto_unload_event); - c->auto_unload_event = NULL; + c->auto_unload_event = NULL; + } + + if (c->defer_unload_event) { + c->mainloop->defer_free(c->defer_unload_event); + c->defer_unload_event = NULL; + } } static int unused_callback(void *p, uint32_t index, int *del, void *userdata) { @@ -212,26 +219,38 @@ void pa_module_unload_unused(struct pa_core *c) { pa_idxset_foreach(c->modules, unused_callback, &now); } -struct once_info { - struct pa_core *core; - uint32_t index; -}; - -static void module_unload_once_callback(struct pa_mainloop_api *m, void *userdata) { - struct once_info *i = userdata; - assert(i); - pa_module_unload_by_index(i->core, i->index); - pa_xfree(i); +static int unload_callback(void *p, uint32_t index, int *del, void *userdata) { + struct pa_module *m = p; + assert(m); + + if (m->unload_requested) { + pa_module_free(m); + *del = 1; + } + + return 0; } -void pa_module_unload_request(struct pa_core *c, struct pa_module *m) { - struct once_info *i; - assert(c && m); +static void defer_cb(struct pa_mainloop_api*api, struct pa_defer_event *e, void *userdata) { + struct pa_core *core = userdata; + api->defer_enable(e, 0); + + if (!core->modules) + return; + + pa_idxset_foreach(core->modules, unload_callback, NULL); + +} + +void pa_module_unload_request(struct pa_module *m) { + assert(m); + + m->unload_requested = 1; + + if (!m->core->defer_unload_event) + m->core->defer_unload_event = m->core->mainloop->defer_new(m->core->mainloop, defer_cb, m->core); - i = pa_xmalloc(sizeof(struct once_info)); - i->core = c; - i->index = m->index; - pa_mainloop_api_once(c->mainloop, module_unload_once_callback, i); + m->core->mainloop->defer_enable(m->core->defer_unload_event, 1); } void pa_module_set_used(struct pa_module*m, int used) { diff --git a/polyp/module.h b/polyp/module.h index 663e0246..f422132a 100644 --- a/polyp/module.h +++ b/polyp/module.h @@ -43,16 +43,18 @@ struct pa_module { int n_used; int auto_unload; time_t last_used_time; + + int unload_requested; }; struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char*argument); -void pa_module_unload(struct pa_core *c, struct pa_module *m); -void pa_module_unload_by_index(struct pa_core *c, uint32_t index); +/* void pa_module_unload(struct pa_core *c, struct pa_module *m); */ +/* void pa_module_unload_by_index(struct pa_core *c, uint32_t index); */ void pa_module_unload_all(struct pa_core *c); void pa_module_unload_unused(struct pa_core *c); -void pa_module_unload_request(struct pa_core *c, struct pa_module *m); +void pa_module_unload_request(struct pa_module *m); void pa_module_set_used(struct pa_module*m, int used); diff --git a/polyp/play-memchunk.c b/polyp/play-memchunk.c index ace8ca69..6490547e 100644 --- a/polyp/play-memchunk.c +++ b/polyp/play-memchunk.c @@ -37,9 +37,12 @@ static void sink_input_kill(struct pa_sink_input *i) { assert(i && i->userdata); c = i->userdata; + pa_sink_input_disconnect(i); + pa_sink_input_unref(i); + pa_memblock_unref(c->memblock); pa_xfree(c); - pa_sink_input_free(i); + } static int sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 103b17a3..8ec48a34 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -167,10 +167,16 @@ static void connection_free(struct connection *c) { pa_client_free(c->client); - if (c->sink_input) - pa_sink_input_free(c->sink_input); - if (c->source_output) - pa_source_output_free(c->source_output); + if (c->sink_input) { + pa_sink_input_disconnect(c->sink_input); + pa_sink_input_unref(c->sink_input); + } + + if (c->source_output) { + pa_source_output_disconnect(c->source_output); + pa_source_output_unref(c->source_output); + } + if (c->input_memblockq) pa_memblockq_free(c->input_memblockq); if (c->output_memblockq) diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index c1b19760..29821b6c 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -255,7 +255,8 @@ static void record_stream_free(struct record_stream* r) { assert(r && r->connection); pa_idxset_remove_by_data(r->connection->record_streams, r, NULL); - pa_source_output_free(r->source_output); + pa_source_output_disconnect(r->source_output); + pa_source_output_unref(r->source_output); pa_memblockq_free(r->memblockq); pa_xfree(r); } @@ -302,7 +303,8 @@ static void playback_stream_free(struct playback_stream* p) { pa_pstream_send_error(p->connection->pstream, p->drain_tag, PA_ERROR_NOENTITY); pa_idxset_remove_by_data(p->connection->output_streams, p, NULL); - pa_sink_input_free(p->sink_input); + pa_sink_input_disconnect(p->sink_input); + pa_sink_input_unref(p->sink_input); pa_memblockq_free(p->memblockq); pa_xfree(p); } diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index 96444f82..58156329 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -80,10 +80,14 @@ static void connection_free(struct connection *c) { if (c->playback.current_memblock) pa_memblock_unref(c->playback.current_memblock); - if (c->sink_input) - pa_sink_input_free(c->sink_input); - if (c->source_output) - pa_source_output_free(c->source_output); + if (c->sink_input) { + pa_sink_input_disconnect(c->sink_input); + pa_sink_input_unref(c->sink_input); + } + if (c->source_output) { + pa_source_output_disconnect(c->source_output); + pa_source_output_unref(c->source_output); + } if (c->client) pa_client_free(c->client); if (c->io) diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 0d59062d..e2b9e0cf 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -41,7 +41,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con struct pa_resampler *resampler = NULL; int r; char st[256]; - assert(s && spec); + assert(s && spec && s->state == PA_SINK_RUNNING); if (pa_idxset_ncontents(s->inputs) >= PA_MAX_INPUTS_PER_SINK) { pa_log(__FILE__": Failed to create sink input: too many inputs per sink.\n"); @@ -53,6 +53,8 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con return NULL; i = pa_xmalloc(sizeof(struct pa_sink_input)); + i->ref = 1; + i->state = PA_SINK_INPUT_RUNNING; i->name = pa_xstrdup(name); i->client = NULL; i->owner = NULL; @@ -86,26 +88,53 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con return i; } -void pa_sink_input_free(struct pa_sink_input* i) { - assert(i); +void pa_sink_input_disconnect(struct pa_sink_input *i) { + assert(i && i->state == PA_SINK_INPUT_RUNNING && i->sink && i->sink->core); - assert(i->sink && i->sink->core); pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); pa_idxset_remove_by_data(i->sink->inputs, i, NULL); + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index); + i->sink = NULL; + + i->peek = NULL; + i->drop = NULL; + i->kill = NULL; + i->get_latency = NULL; + + i->state = PA_SINK_INPUT_DISCONNECTED; +} + +static void sink_input_free(struct pa_sink_input* i) { + assert(i); + + if (i->state != PA_SINK_INPUT_DISCONNECTED) + pa_sink_input_disconnect(i); + if (i->resampled_chunk.memblock) pa_memblock_unref(i->resampled_chunk.memblock); if (i->resampler) pa_resampler_free(i->resampler); - pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index); - pa_xfree(i->name); pa_xfree(i); } +void pa_sink_input_unref(struct pa_sink_input *i) { + assert(i && i->ref >= 1); + + if (!(--i->ref)) + sink_input_free(i); +} + +struct pa_sink_input* pa_sink_input_ref(struct pa_sink_input *i) { + assert(i && i->ref >= 1); + i->ref++; + return i; +} + void pa_sink_input_kill(struct pa_sink_input*i) { - assert(i); + assert(i && i->ref >= 1); if (i->kill) i->kill(i); @@ -113,7 +142,7 @@ void pa_sink_input_kill(struct pa_sink_input*i) { pa_usec_t pa_sink_input_get_latency(struct pa_sink_input *i) { pa_usec_t r = 0; - assert(i); + assert(i && i->ref >= 1); if (i->get_latency) r += i->get_latency(i); @@ -125,7 +154,11 @@ pa_usec_t pa_sink_input_get_latency(struct pa_sink_input *i) { } int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { - assert(i && chunk && i->peek && i->drop); + int ret = 0; + assert(i && chunk && i->ref >= 1); + + if (!i->peek || !i->drop) + return -1; if (i->corked) return -1; @@ -133,13 +166,14 @@ int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { if (!i->resampler) return i->peek(i, chunk); + pa_sink_input_ref(i); + while (!i->resampled_chunk.memblock) { struct pa_memchunk tchunk; size_t l; - int ret; if ((ret = i->peek(i, &tchunk)) < 0) - return ret; + goto finish; assert(tchunk.length); @@ -158,14 +192,22 @@ int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { assert(i->resampled_chunk.memblock && i->resampled_chunk.length); *chunk = i->resampled_chunk; pa_memblock_ref(i->resampled_chunk.memblock); - return 0; + + ret = 0; + +finish: + + pa_sink_input_unref(i); + + return ret; } void pa_sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length) { - assert(i && length); + assert(i && length && i->ref >= 1); if (!i->resampler) { - i->drop(i, chunk, length); + if (i->drop) + i->drop(i, chunk, length); return; } @@ -182,7 +224,7 @@ void pa_sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk *chunk } void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume) { - assert(i && i->sink && i->sink->core); + assert(i && i->sink && i->sink->core && i->ref >= 1); if (i->volume != volume) { i->volume = volume; @@ -192,7 +234,8 @@ void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume) { void pa_sink_input_cork(struct pa_sink_input *i, int b) { int n; - assert(i); + assert(i && i->ref >= 1); + n = i->corked && !b; i->corked = b; @@ -201,7 +244,7 @@ void pa_sink_input_cork(struct pa_sink_input *i, int b) { } void pa_sink_input_set_rate(struct pa_sink_input *i, uint32_t rate) { - assert(i && i->resampler); + assert(i && i->resampler && i->ref >= 1); if (i->sample_spec.rate == rate) return; @@ -209,3 +252,10 @@ void pa_sink_input_set_rate(struct pa_sink_input *i, uint32_t rate) { i->sample_spec.rate = rate; pa_resampler_set_input_rate(i->resampler, rate); } + +void pa_sink_input_set_name(struct pa_sink_input *i, const char *name) { + assert(i && i->ref >= 1); + + pa_xfree(i->name); + i->name = pa_xstrdup(name); +} diff --git a/polyp/sink-input.h b/polyp/sink-input.h index e5b06387..37678300 100644 --- a/polyp/sink-input.h +++ b/polyp/sink-input.h @@ -31,7 +31,15 @@ #include "module.h" #include "client.h" +enum pa_sink_input_state { + PA_SINK_INPUT_RUNNING, + PA_SINK_INPUT_DISCONNECTED +}; + struct pa_sink_input { + int ref; + enum pa_sink_input_state state; + uint32_t index; int corked; @@ -55,11 +63,14 @@ struct pa_sink_input { }; struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec, int variable_rate); -void pa_sink_input_free(struct pa_sink_input* i); +void pa_sink_input_unref(struct pa_sink_input* i); +struct pa_sink_input* pa_sink_input_ref(struct pa_sink_input* i); -/* Code that didn't create the input stream should call this function to - * request destruction of it */ -void pa_sink_input_kill(struct pa_sink_input *i); +/* To be called by the implementing module only */ +void pa_sink_input_disconnect(struct pa_sink_input* i); + +/* External code may request disconnection with this funcion */ +void pa_sink_input_kill(struct pa_sink_input*i); pa_usec_t pa_sink_input_get_latency(struct pa_sink_input *i); @@ -72,4 +83,6 @@ void pa_sink_input_cork(struct pa_sink_input *i, int b); void pa_sink_input_set_rate(struct pa_sink_input *i, uint32_t rate); +void pa_sink_input_set_name(struct pa_sink_input *i, const char *name); + #endif diff --git a/polyp/sink.c b/polyp/sink.c index 1fe38e9f..6d3b59c7 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -52,9 +52,12 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co pa_xfree(s); return NULL; } - + s->name = pa_xstrdup(name); s->description = NULL; + + s->ref = 1; + s->state = PA_SINK_RUNNING; s->owner = NULL; s->core = core; @@ -85,9 +88,9 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co return s; } -void pa_sink_free(struct pa_sink *s) { +void pa_sink_disconnect(struct pa_sink* s) { struct pa_sink_input *i, *j = NULL; - assert(s); + assert(s && s->state == PA_SINK_RUNNING); pa_namereg_unregister(s->core, s->name); @@ -96,22 +99,51 @@ void pa_sink_free(struct pa_sink *s) { pa_sink_input_kill(i); j = i; } - pa_idxset_free(s->inputs, NULL, NULL); - pa_source_free(s->monitor_source); + pa_source_disconnect(s->monitor_source); + pa_idxset_remove_by_data(s->core->sinks, s, NULL); + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); + + s->notify = NULL; + s->get_latency = NULL; + + s->state = PA_SINK_DISCONNECTED; +} + +static void sink_free(struct pa_sink *s) { + assert(s && s->ref == 0); + + if (s->state != PA_SINK_DISCONNECTED) + pa_sink_disconnect(s); pa_log(__FILE__": freed %u \"%s\"\n", s->index, s->name); - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); + pa_source_unref(s->monitor_source); + s->monitor_source = NULL; + pa_idxset_free(s->inputs, NULL, NULL); + pa_xfree(s->name); pa_xfree(s->description); pa_xfree(s); } +void pa_sink_unref(struct pa_sink*s) { + assert(s && s->ref >= 1); + + if (!(--s->ref)) + sink_free(s); +} + +struct pa_sink* pa_sink_ref(struct pa_sink *s) { + assert(s && s->ref >= 1); + s->ref++; + return s; +} + void pa_sink_notify(struct pa_sink*s) { - assert(s); + assert(s && s->ref >= 1); if (s->notify) s->notify(s); @@ -122,16 +154,20 @@ static unsigned fill_mix_info(struct pa_sink *s, struct pa_mix_info *info, unsig struct pa_sink_input *i; unsigned n = 0; - assert(s && info); + assert(s && s->ref >= 1 && info); for (i = pa_idxset_first(s->inputs, &index); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &index)) { - if (pa_sink_input_peek(i, &info->chunk) < 0) + pa_sink_input_ref(i); + + if (pa_sink_input_peek(i, &info->chunk) < 0) { + pa_sink_input_unref(i); continue; + } info->volume = i->volume; + info->userdata = i; assert(info->chunk.memblock && info->chunk.memblock->data && info->chunk.length); - info->userdata = i; info++; maxinfo--; @@ -142,7 +178,7 @@ static unsigned fill_mix_info(struct pa_sink *s, struct pa_mix_info *info, unsig } static void inputs_drop(struct pa_sink *s, struct pa_mix_info *info, unsigned maxinfo, size_t length) { - assert(s && info); + assert(s && s->ref >= 1 && info); for (; maxinfo > 0; maxinfo--, info++) { struct pa_sink_input *i = info->userdata; @@ -150,6 +186,9 @@ static void inputs_drop(struct pa_sink *s, struct pa_mix_info *info, unsigned ma pa_sink_input_drop(i, &info->chunk, length); pa_memblock_unref(info->chunk.memblock); + + pa_sink_input_unref(i); + info->userdata = NULL; } } @@ -157,12 +196,15 @@ int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result) struct pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; size_t l; - assert(s && length && result); + int r = -1; + assert(s && s->ref >= 1 && length && result); + pa_sink_ref(s); + n = fill_mix_info(s, info, MAX_MIX_CHANNELS); if (n <= 0) - return -1; + goto finish; if (n == 1) { uint32_t volume = PA_VOLUME_NORM; @@ -198,19 +240,27 @@ int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result) assert(s->monitor_source); pa_source_post(s->monitor_source, result); - return 0; + r = 0; + +finish: + pa_sink_unref(s); + + return r; } int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target) { struct pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; size_t l; - assert(s && target && target->length && target->memblock && target->memblock->data); + int r = -1; + assert(s && s->ref >= 1 && target && target->length && target->memblock && target->memblock->data); + + pa_sink_ref(s); n = fill_mix_info(s, info, MAX_MIX_CHANNELS); if (n <= 0) - return -1; + goto finish; if (n == 1) { uint32_t volume = PA_VOLUME_NORM; @@ -238,14 +288,21 @@ int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target) { assert(s->monitor_source); pa_source_post(s->monitor_source, target); - return 0; + r = 0; + +finish: + pa_sink_unref(s); + + return r; } void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target) { struct pa_memchunk chunk; size_t l, d; - assert(s && target && target->memblock && target->length && target->memblock->data); + assert(s && s->ref >= 1 && target && target->memblock && target->length && target->memblock->data); + pa_sink_ref(s); + l = target->length; d = 0; while (l > 0) { @@ -266,10 +323,12 @@ void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target) { chunk.length -= d; pa_silence_memchunk(&chunk, &s->sample_spec); } + + pa_sink_unref(s); } void pa_sink_render_full(struct pa_sink *s, size_t length, struct pa_memchunk *result) { - assert(s && length && result); + assert(s && s->ref >= 1 && length && result); /*** This needs optimization ***/ @@ -280,7 +339,7 @@ void pa_sink_render_full(struct pa_sink *s, size_t length, struct pa_memchunk *r } pa_usec_t pa_sink_get_latency(struct pa_sink *s) { - assert(s); + assert(s && s->ref >= 1); if (!s->get_latency) return 0; @@ -288,18 +347,20 @@ pa_usec_t pa_sink_get_latency(struct pa_sink *s) { return s->get_latency(s); } -void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m) { - sink->owner = m; +void pa_sink_set_owner(struct pa_sink *s, struct pa_module *m) { + assert(s && s->ref >= 1); + + s->owner = m; - if (sink->monitor_source) - pa_source_set_owner(sink->monitor_source, m); + if (s->monitor_source) + pa_source_set_owner(s->monitor_source, m); } -void pa_sink_set_volume(struct pa_sink *sink, pa_volume_t volume) { - assert(sink); +void pa_sink_set_volume(struct pa_sink *s, pa_volume_t volume) { + assert(s && s->ref >= 1); - if (sink->volume != volume) { - sink->volume = volume; - pa_subscription_post(sink->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, sink->index); + if (s->volume != volume) { + s->volume = volume; + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } } diff --git a/polyp/sink.h b/polyp/sink.h index 881e75d3..b34a736c 100644 --- a/polyp/sink.h +++ b/polyp/sink.h @@ -33,7 +33,15 @@ struct pa_sink; #define PA_MAX_INPUTS_PER_SINK 6 +enum pa_sink_state { + PA_SINK_RUNNING, + PA_SINK_DISCONNECTED +}; + struct pa_sink { + int ref; + enum pa_sink_state state; + uint32_t index; char *name, *description; @@ -52,7 +60,10 @@ struct pa_sink { }; struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec); -void pa_sink_free(struct pa_sink* s); +void pa_sink_disconnect(struct pa_sink* s); +void pa_sink_unref(struct pa_sink*s); +struct pa_sink* pa_sink_ref(struct pa_sink *s); + int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result); void pa_sink_render_full(struct pa_sink *s, size_t length, struct pa_memchunk *result); diff --git a/polyp/sound-file-stream.c b/polyp/sound-file-stream.c index e77ff119..60a58f47 100644 --- a/polyp/sound-file-stream.c +++ b/polyp/sound-file-stream.c @@ -45,8 +45,11 @@ struct userdata { static void free_userdata(struct userdata *u) { assert(u); - if (u->sink_input) - pa_sink_input_free(u->sink_input); + if (u->sink_input) { + pa_sink_input_disconnect(u->sink_input); + pa_sink_input_unref(u->sink_input); + } + if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); if (u->sndfile) diff --git a/polyp/source-output.c b/polyp/source-output.c index 55448b5c..3abf9c18 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -49,6 +49,8 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n return NULL; o = pa_xmalloc(sizeof(struct pa_source_output)); + o->ref = 1; + o->state = PA_SOURCE_OUTPUT_RUNNING; o->name = pa_xstrdup(name); o->client = NULL; o->owner = NULL; @@ -71,27 +73,55 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n return o; } -void pa_source_output_free(struct pa_source_output* o) { - assert(o); - - assert(o->source && o->source->core); +void pa_source_output_disconnect(struct pa_source_output*o) { + assert(o && o->state == PA_SOURCE_OUTPUT_RUNNING && o->source && o->source->core); + pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); pa_idxset_remove_by_data(o->source->outputs, o, NULL); + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); + o->source = NULL; + + o->push = NULL; + o->kill = NULL; + + + o->state = PA_SOURCE_OUTPUT_DISCONNECTED; +} + +static void source_output_free(struct pa_source_output* o) { + assert(o); + + if (o->state != PA_SOURCE_OUTPUT_DISCONNECTED) + pa_source_output_disconnect(o); + if (o->resampler) pa_resampler_free(o->resampler); - pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); - pa_xfree(o->name); pa_xfree(o); } -void pa_source_output_kill(struct pa_source_output*i) { - assert(i); - if (i->kill) - i->kill(i); +void pa_source_output_unref(struct pa_source_output* o) { + assert(o && o->ref >= 1); + + if (!(--o->ref)) + source_output_free(o); +} + +struct pa_source_output* pa_source_output_ref(struct pa_source_output *o) { + assert(o && o->ref >= 1); + o->ref++; + return o; +} + + +void pa_source_output_kill(struct pa_source_output*o) { + assert(o && o->ref >= 1); + + if (o->kill) + o->kill(o); } void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk *chunk) { @@ -111,3 +141,9 @@ void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk o->push(o, &rchunk); pa_memblock_unref(rchunk.memblock); } + +void pa_source_output_set_name(struct pa_source_output *o, const char *name) { + assert(o && o->ref >= 1); + pa_xfree(o->name); + o->name = pa_xstrdup(name); +} diff --git a/polyp/source-output.h b/polyp/source-output.h index 0e6e2cfd..709d65ad 100644 --- a/polyp/source-output.h +++ b/polyp/source-output.h @@ -31,7 +31,15 @@ #include "module.h" #include "client.h" +enum pa_source_output_state { + PA_SOURCE_OUTPUT_RUNNING, + PA_SOURCE_OUTPUT_DISCONNECTED +}; + struct pa_source_output { + int ref; + enum pa_source_output_state state; + uint32_t index; char *name; @@ -49,10 +57,17 @@ struct pa_source_output { }; struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec); -void pa_source_output_free(struct pa_source_output* o); +void pa_source_output_unref(struct pa_source_output* o); +struct pa_source_output* pa_source_output_ref(struct pa_source_output *o); +/* To be called by the implementing module only */ +void pa_source_output_disconnect(struct pa_source_output*o); + +/* External code may request disconnection with this funcion */ void pa_source_output_kill(struct pa_source_output*o); void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk *chunk); +void pa_source_output_set_name(struct pa_source_output *i, const char *name); + #endif diff --git a/polyp/source.c b/polyp/source.c index 5cdfdb55..2c0caca0 100644 --- a/polyp/source.c +++ b/polyp/source.c @@ -48,6 +48,9 @@ struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail return NULL; } + s->ref = 1; + s->state = PA_SOURCE_RUNNING; + s->name = pa_xstrdup(name); s->description = NULL; @@ -71,9 +74,9 @@ struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail return s; } -void pa_source_free(struct pa_source *s) { +void pa_source_disconnect(struct pa_source *s) { struct pa_source_output *o, *j = NULL; - assert(s); + assert(s && s->state == PA_SOURCE_RUNNING); pa_namereg_unregister(s->core, s->name); @@ -82,21 +85,45 @@ void pa_source_free(struct pa_source *s) { pa_source_output_kill(o); j = o; } - pa_idxset_free(s->outputs, NULL, NULL); - + pa_idxset_remove_by_data(s->core->sources, s, NULL); + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); - pa_log(__FILE__": freed %u \"%s\"\n", s->index, s->name); + s->notify = NULL; + + s->state = PA_SOURCE_DISCONNECTED; +} - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); +static void source_free(struct pa_source *s) { + assert(s && !s->ref); + + if (s->state != PA_SOURCE_DISCONNECTED) + pa_source_disconnect(s); + pa_log(__FILE__": freed %u \"%s\"\n", s->index, s->name); + + pa_idxset_free(s->outputs, NULL, NULL); + pa_xfree(s->name); pa_xfree(s->description); pa_xfree(s); } +void pa_source_unref(struct pa_source *s) { + assert(s && s->ref >= 1); + + if (!(--s->ref)) + source_free(s); +} + +struct pa_source* pa_source_ref(struct pa_source *s) { + assert(s && s->ref >= 1); + s->ref++; + return s; +} + void pa_source_notify(struct pa_source*s) { - assert(s); + assert(s && s->ref >= 1); if (s->notify) s->notify(s); @@ -112,9 +139,11 @@ static int do_post(void *p, uint32_t index, int *del, void*userdata) { } void pa_source_post(struct pa_source*s, struct pa_memchunk *chunk) { - assert(s && chunk); + assert(s && s->ref >= 1 && chunk); + pa_source_ref(s); pa_idxset_foreach(s->outputs, do_post, chunk); + pa_source_unref(s); } void pa_source_set_owner(struct pa_source *s, struct pa_module *m) { diff --git a/polyp/source.h b/polyp/source.h index 309b87e7..8b03c0d5 100644 --- a/polyp/source.h +++ b/polyp/source.h @@ -34,7 +34,15 @@ struct pa_source; #define PA_MAX_OUTPUTS_PER_SOURCE 16 +enum pa_source_state { + PA_SOURCE_RUNNING, + PA_SOURCE_DISCONNECTED, +}; + struct pa_source { + int ref; + enum pa_source_state state; + uint32_t index; char *name, *description; @@ -49,7 +57,9 @@ struct pa_source { }; struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec); -void pa_source_free(struct pa_source *s); +void pa_source_disconnect(struct pa_source *s); +void pa_source_unref(struct pa_source *s); +struct pa_source* pa_source_ref(struct pa_source *c); /* Pass a new memory block to all output streams */ void pa_source_post(struct pa_source*s, struct pa_memchunk *b); -- cgit From 935826f4f318a89a0a570f766deb54808a4f9683 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 14 Sep 2004 23:08:39 +0000 Subject: make module-combine autoloadable clean up cli language introduce lazy sample cache git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@201 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 -- polyp/autoload.c | 79 ++++++++++++++++++++++++++++++++++-------- polyp/autoload.h | 7 ++-- polyp/cli-command.c | 91 ++++++++++++++++++++++++++----------------------- polyp/cli-text.c | 21 ++++++++---- polyp/cmdline.c | 11 ++++-- polyp/conf.c | 7 ++-- polyp/conf.h | 1 + polyp/core.c | 12 +++---- polyp/core.h | 8 +++-- polyp/default.pa | 46 ++++++++++++------------- polyp/main.c | 6 ++-- polyp/module-combine.c | 11 +++++- polyp/module.c | 26 +++++++------- polyp/protocol-esound.c | 4 +-- polyp/protocol-native.c | 7 ++-- polyp/scache.c | 64 +++++++++++++++++++++++++++++++--- polyp/scache.h | 7 +++- 18 files changed, 280 insertions(+), 131 deletions(-) diff --git a/doc/todo b/doc/todo index 8daabc33..fedfa545 100644 --- a/doc/todo +++ b/doc/todo @@ -2,7 +2,6 @@ *** 0.5 *** - make mcalign merge chunks -- use ref counting in more objects (i.e. sink, source, sink_input, source_output) - native library/protocol: module load/unload kill client/... @@ -10,13 +9,11 @@ rename streams/contexts - more complete pactl - option to use default fragment size on alsa drivers -- lazy sample cache - merge pa_context_connect_* - input latency - fix tcp/native - add volume to create_stream command in native protocol - udp based protocol -- make sure not to allow recursive auto load *** 0.6 **** - per-channel volume diff --git a/polyp/autoload.c b/polyp/autoload.c index 988b0921..8eb5bbf5 100644 --- a/polyp/autoload.c +++ b/polyp/autoload.c @@ -30,36 +30,64 @@ #include "autoload.h" #include "module.h" #include "xmalloc.h" +#include "memchunk.h" +#include "sound-file.h" +#include "log.h" +#include "scache.h" static void entry_free(struct pa_autoload_entry *e) { assert(e); pa_xfree(e->name); pa_xfree(e->module); pa_xfree(e->argument); + pa_xfree(e->filename); pa_xfree(e); } -void pa_autoload_add(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*module, const char *argument) { +static struct pa_autoload_entry* entry_new(struct pa_core *c, const char *name) { struct pa_autoload_entry *e = NULL; - assert(c && name && module); + assert(c && name); - if (c->autoload_hashmap && (e = pa_hashmap_get(c->autoload_hashmap, name))) { - pa_xfree(e->module); - pa_xfree(e->argument); - } else { - e = pa_xmalloc(sizeof(struct pa_autoload_entry)); - e->name = pa_xstrdup(name); + if (c->autoload_hashmap && (e = pa_hashmap_get(c->autoload_hashmap, name))) + return NULL; + + e = pa_xmalloc(sizeof(struct pa_autoload_entry)); + e->name = pa_xstrdup(name); + e->module = e->argument = e->filename = NULL; + e->in_action = 0; + + if (!c->autoload_hashmap) + c->autoload_hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + assert(c->autoload_hashmap); + + pa_hashmap_put(c->autoload_hashmap, e->name, e); - if (!c->autoload_hashmap) - c->autoload_hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - assert(c->autoload_hashmap); + return e; +} - pa_hashmap_put(c->autoload_hashmap, e->name, e); - } +int pa_autoload_add_module(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*module, const char *argument) { + struct pa_autoload_entry *e = NULL; + assert(c && name && module); + if (!(e = entry_new(c, name))) + return -1; + e->module = pa_xstrdup(module); e->argument = pa_xstrdup(argument); e->type = type; + return 0; +} + +int pa_autoload_add_sample(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*filename) { + struct pa_autoload_entry *e = NULL; + assert(c && name && filename); + + if (!(e = entry_new(c, name))) + return -1; + + e->filename = pa_xstrdup(filename); + e->type = PA_NAMEREG_SAMPLE; + return 0; } int pa_autoload_remove(struct pa_core *c, const char*name, enum pa_namereg_type type) { @@ -82,8 +110,29 @@ void pa_autoload_request(struct pa_core *c, const char *name, enum pa_namereg_ty if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || (e->type != type)) return; - if ((m = pa_module_load(c, e->module, e->argument))) - m->auto_unload = 1; + if (e->in_action) + return; + + e->in_action = 1; + + if (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE) { + if ((m = pa_module_load(c, e->module, e->argument))) + m->auto_unload = 1; + + } else { + struct pa_sample_spec ss; + struct pa_memchunk chunk; + assert(type == PA_NAMEREG_SAMPLE); + + if (pa_sound_file_load(e->filename, &ss, &chunk, c->memblock_stat) < 0) + pa_log(__FILE__": failed to load sound file '%s' for autoload entry '%s'.\n", e->filename, e->name); + else { + pa_scache_add_item(c, e->name, &ss, &chunk, NULL, 1); + pa_memblock_unref(chunk.memblock); + } + } + + e->in_action = 0; } static void free_func(void *p, void *userdata) { diff --git a/polyp/autoload.h b/polyp/autoload.h index 004dae26..3d3101b9 100644 --- a/polyp/autoload.h +++ b/polyp/autoload.h @@ -27,10 +27,13 @@ struct pa_autoload_entry { char *name; enum pa_namereg_type type; - char *module, *argument; + int in_action; + char *module, *argument; /* for module autoloading */ + char *filename; /* for sample autoloading */ }; -void pa_autoload_add(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*module, const char *argument); +int pa_autoload_add_module(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*module, const char *argument); +int pa_autoload_add_sample(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*filename); void pa_autoload_free(struct pa_core *c); int pa_autoload_remove(struct pa_core *c, const char*name, enum pa_namereg_type type); void pa_autoload_request(struct pa_core *c, const char *name, enum pa_namereg_type type); diff --git a/polyp/cli-command.c b/polyp/cli-command.c index b44fbf4a..574af9db 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -87,35 +87,37 @@ static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct 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 }, + { "list-modules", pa_cli_command_modules, "List loaded modules", 1 }, + { "list-sinks", pa_cli_command_sinks, "List loaded sinks", 1 }, + { "list-sources", pa_cli_command_sources, "List loaded sources", 1 }, + { "list-clients", pa_cli_command_clients, "List loaded clients", 1 }, + { "list-sink-inputs", pa_cli_command_sink_inputs, "List sink inputs", 1 }, + { "list-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}, - { "scache_list", pa_cli_command_scache_list, "List all entries in the sample cache", 1}, - { "scache_play", pa_cli_command_scache_play, "Play a sample from the sample cache (args: name, sink|index)", 3}, - { "scache_remove", pa_cli_command_scache_remove, "Remove a sample from the sample cache (args: name)", 2}, - { "scache_load", pa_cli_command_scache_load, "Load a sound file into the sample cache (args: filename,name)", 3}, - { "play_file", pa_cli_command_play_file, "Play a sound file (args: filename, sink|index)", 3}, - { "autoload_list", pa_cli_command_autoload_list, "List autoload entries", 1}, - { "autoload_sink_add", pa_cli_command_autoload_add, "Add autoload entry for a sink (args: sink, name, arguments)", 4}, - { "autoload_source_add", pa_cli_command_autoload_add, "Add autoload entry for a source (args: source, name, arguments)", 4}, - { "autoload_sink_remove", pa_cli_command_autoload_remove, "Remove autoload entry for a sink (args: sink)", 2}, - { "autoload_source_remove", pa_cli_command_autoload_remove, "Remove autoload entry for a source (args: source)", 2}, + { "load-module", pa_cli_command_load, "Load a module (args: name, arguments)", 3}, + { "unload-module", pa_cli_command_unload, "Unload a module (args: index)", 2}, + { "set-sink-volume", pa_cli_command_sink_volume, "Set the volume of a sink (args: index|name, volume)", 3}, + { "set-sink-input-volume", pa_cli_command_sink_input_volume, "Set the volume of a sink input (args: index|name, volume)", 3}, + { "set-default-sink", pa_cli_command_sink_default, "Set the default sink (args: index|name)", 2}, + { "set-default-source", 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}, + { "list-samples", pa_cli_command_scache_list, "List all entries in the sample cache", 1}, + { "play-sample", pa_cli_command_scache_play, "Play a sample from the sample cache (args: name, sink|index)", 3}, + { "remove-sample", pa_cli_command_scache_remove, "Remove a sample from the sample cache (args: name)", 2}, + { "load-sample", pa_cli_command_scache_load, "Load a sound file into the sample cache (args: name, filename)", 3}, + { "play-file", pa_cli_command_play_file, "Play a sound file (args: filename, sink|index)", 3}, + { "list-autoload", pa_cli_command_autoload_list, "List autoload entries", 1}, + { "add-autoload-sink", pa_cli_command_autoload_add, "Add autoload entry for a sink (args: sink, module name, arguments)", 4}, + { "add-autoload-source", pa_cli_command_autoload_add, "Add autoload entry for a source (args: source, module name, arguments)", 4}, + { "add-autoload-sample", pa_cli_command_autoload_add, "Add autoload entry for a smple (args: name, filename)", 3}, + { "remove-autoload-sink", pa_cli_command_autoload_remove, "Remove autoload entry for a sink (args: name)", 2}, + { "remove-autoload-source", pa_cli_command_autoload_remove, "Remove autoload entry for a source (args: name)", 2}, + { "remove-autoload-sample", pa_cli_command_autoload_remove, "Remove autoload entry for a sample (args: name)", 2}, { "dump", pa_cli_command_dump, "Dump daemon configuration", 1}, { NULL, NULL, NULL, 0 } }; @@ -147,7 +149,7 @@ static int pa_cli_command_help(struct pa_core *c, struct pa_tokenizer *t, struct for (command = commands; command->name; command++) if (command->help) - pa_strbuf_printf(buf, " %-20s %s\n", command->name, command->help); + pa_strbuf_printf(buf, " %-25s %s\n", command->name, command->help); return 0; } @@ -524,7 +526,7 @@ static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_sample_spec ss; assert(c && t && buf && fail && verbose); - if (!(fname = pa_tokenizer_get(t, 1)) || !(n = pa_tokenizer_get(t, 2))) { + if (!(fname = pa_tokenizer_get(t, 2)) || !(n = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify a file name and a sample name.\n"); return -1; } @@ -534,7 +536,7 @@ static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t, return -1; } - pa_scache_add_item(c, n, &ss, &chunk, NULL); + pa_scache_add_item(c, n, &ss, &chunk, NULL, 0); pa_memblock_unref(chunk.memblock); return 0; } @@ -559,28 +561,33 @@ static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, s } static int pa_cli_command_autoload_add(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { - const char *devname, *module; + const char *a, *b; assert(c && t && buf && fail && verbose); - if (!(devname = pa_tokenizer_get(t, 1)) || !(module = pa_tokenizer_get(t, 2))) { - pa_strbuf_puts(buf, "You need to specify a device name, a module name and optionally module arguments\n"); + if (!(a = pa_tokenizer_get(t, 1)) || !(b = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a device name, a filename or a module name and optionally module arguments\n"); return -1; } + + if (strstr(pa_tokenizer_get(t, 0), "sample")) + pa_autoload_add_sample(c, a, PA_NAMEREG_SAMPLE, b); + else + pa_autoload_add_module(c, a, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, b, pa_tokenizer_get(t, 3)); - pa_autoload_add(c, devname, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, module, pa_tokenizer_get(t, 3)); return 0; } static int pa_cli_command_autoload_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { - const char *devname; + const char *name; assert(c && t && buf && fail && verbose); - - if (!(devname = pa_tokenizer_get(t, 1))) { + + if (!(name = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify a device name\n"); return -1; } - if (pa_autoload_remove(c, devname, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE) < 0) { + if (pa_autoload_remove(c, name, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : + (strstr(pa_tokenizer_get(t, 0), "source") ? PA_NAMEREG_SOURCE : PA_NAMEREG_SAMPLE)) < 0) { pa_strbuf_puts(buf, "Failed to remove autload entry\n"); return -1; } @@ -620,7 +627,7 @@ static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct if (m->auto_unload) continue; - pa_strbuf_printf(buf, "load %s", m->name); + pa_strbuf_printf(buf, "load-module %s", m->name); if (m->argument) pa_strbuf_printf(buf, " %s", m->argument); @@ -642,7 +649,7 @@ static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct nl = 1; } - pa_strbuf_printf(buf, "sink_volume %s 0x%03x\n", s->name, s->volume); + pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", s->name, s->volume); } @@ -651,13 +658,13 @@ static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct i = NULL; while ((a = pa_hashmap_iterate(c->autoload_hashmap, &i))) { - + if (!nl) { pa_strbuf_puts(buf, "\n"); nl = 1; } - pa_strbuf_printf(buf, "autoload_%s_add %s %s", a->type == PA_NAMEREG_SINK ? "sink" : "source", a->name, a->module); + pa_strbuf_printf(buf, "add-autoload-%s %s %s", a->type == PA_NAMEREG_SINK ? "sink" : (a->type == PA_NAMEREG_SOURCE ? "source" : "sample"), a->name, a->type == PA_NAMEREG_SAMPLE ? a->filename : a->module); if (a->argument) pa_strbuf_printf(buf, " %s", a->argument); @@ -673,7 +680,7 @@ static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf_puts(buf, "\n"); nl = 1; } - pa_strbuf_printf(buf, "sink_default %s\n", p); + pa_strbuf_printf(buf, "set-default-sink %s\n", p); } if ((p = pa_namereg_get_default_source_name(c))) { @@ -681,7 +688,7 @@ static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf_puts(buf, "\n"); nl = 1; } - pa_strbuf_printf(buf, "source_default %s\n", p); + pa_strbuf_printf(buf, "set-default-source %s\n", p); } pa_strbuf_puts(buf, "\n### EOF\n"); diff --git a/polyp/cli-text.c b/polyp/cli-text.c index 2a48d576..dbc14fda 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -228,13 +228,14 @@ char *pa_scache_list_to_string(struct pa_core *c) { l = (double) e->memchunk.length / pa_bytes_per_second(&e->sample_spec); pa_strbuf_printf( - s, " name: <%s>\n\tindex: <%i>\n\tsample_spec: <%s>\n\tlength: <%u>\n\tduration: <%0.1fs>\n\tvolume: <0x%04x>\n", + s, " name: <%s>\n\tindex: <%i>\n\tsample_spec: <%s>\n\tlength: <%u>\n\tduration: <%0.1fs>\n\tvolume: <0x%04x>\n\tauto unload: %s\n", e->name, e->index, ss, e->memchunk.length, l, - e->volume); + e->volume, + e->auto_unload ? "yes" : "no"); } } @@ -256,11 +257,19 @@ char *pa_autoload_list_to_string(struct pa_core *c) { while ((e = pa_hashmap_iterate(c->autoload_hashmap, &state))) { pa_strbuf_printf( - s, " name: <%s>\n\ttype: <%s>\n\tmodule_name: <%s>\n\targuments: <%s>\n", + s, " name: <%s>\n\ttype: <%s>\n", e->name, - e->type == PA_NAMEREG_SOURCE ? "source" : "sink", - e->module, - e->argument); + e->type == PA_NAMEREG_SOURCE ? "source" : (e->type == PA_NAMEREG_SINK ? "sink" : "sample")); + + if (e->type != PA_NAMEREG_SAMPLE) + pa_strbuf_printf( + s, "\tmodule_name: <%s>\n\targuments: <%s>\n", + e->module, + e->argument); + else + pa_strbuf_printf( + s, "\tfilename: <%s>\n", + e->filename); } } diff --git a/polyp/cmdline.c b/polyp/cmdline.c index 47685ca9..d429256f 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -47,6 +47,7 @@ enum { ARG_DISALLOW_MODULE_LOADING, ARG_EXIT_IDLE_TIME, ARG_MODULE_IDLE_TIME, + ARG_SCACHE_IDLE_TIME, ARG_LOG_TARGET, ARG_LOAD, ARG_FILE, @@ -65,6 +66,7 @@ static struct option long_options[] = { {"disallow-module-loading", 2, 0, ARG_DISALLOW_MODULE_LOADING}, {"exit-idle-time", 2, 0, ARG_EXIT_IDLE_TIME}, {"module-idle-time", 2, 0, ARG_MODULE_IDLE_TIME}, + {"scache-idle-time", 2, 0, ARG_SCACHE_IDLE_TIME}, {"log-target", 1, 0, ARG_LOG_TARGET}, {"load", 1, 0, ARG_LOAD}, {"file", 1, 0, ARG_FILE}, @@ -94,6 +96,7 @@ void pa_cmdline_help(const char *argv0) { " --disallow-module-loading[=BOOL] Disallow module loading after startup\n" " --exit-idle-time=SECS Terminate the daemon when idle and this time passed\n" " --module-idle-time=SECS Unload autoloaded modules when idle and this time passed\n" + " --scache-idle-time=SECS Unload autoloaded samples when idle and this time passed\n" " --log-target={auto,syslog,stderr} Specify the log target\n" " -p, --dl-search-path=PATH Set the search path for dynamic shared objects (plugins)\n\n" @@ -135,7 +138,7 @@ int pa_cmdline_parse(struct pa_conf *conf, int argc, char *const argv [], int *d case ARG_LOAD: case 'L': - pa_strbuf_printf(buf, "load %s\n", optarg); + pa_strbuf_printf(buf, "load-module %s\n", optarg); break; case ARG_FILE: @@ -144,7 +147,7 @@ int pa_cmdline_parse(struct pa_conf *conf, int argc, char *const argv [], int *d break; case 'C': - pa_strbuf_puts(buf, "load module-cli\n"); + pa_strbuf_puts(buf, "load-module module-cli\n"); break; case ARG_DAEMONIZE: @@ -216,6 +219,10 @@ int pa_cmdline_parse(struct pa_conf *conf, int argc, char *const argv [], int *d case ARG_MODULE_IDLE_TIME: conf->module_idle_time = atoi(optarg); break; + + case ARG_SCACHE_IDLE_TIME: + conf->scache_idle_time = atoi(optarg); + break; default: goto fail; diff --git a/polyp/conf.c b/polyp/conf.c index 9f1f6ba2..3a894a9b 100644 --- a/polyp/conf.c +++ b/polyp/conf.c @@ -43,6 +43,7 @@ static const struct pa_conf default_conf = { .disallow_module_loading = 0, .exit_idle_time = -1, .module_idle_time = 20, + .scache_idle_time = 20, .auto_log_target = 1, .script_commands = NULL, .dl_search_path = NULL, @@ -143,6 +144,7 @@ static int next_assignment(struct pa_conf *c, char *lvalue, char *rvalue, unsign PARSE_INTEGER("exit-idle-time", exit_idle_time); PARSE_INTEGER("module-idle-time", module_idle_time); + PARSE_INTEGER("scache-idle-time", scache_idle_time); PARSE_STRING("dl-search-path", dl_search_path); PARSE_STRING("default-script-file", default_script_file); @@ -258,7 +260,7 @@ char *pa_conf_dump(struct pa_conf *c) { char *d; d = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_LOCAL); - pa_strbuf_printf(s, "### Default configuration file: %s ###\n\n", d); + pa_strbuf_printf(s, "### Default configuration file: %s ###\n", d); pa_strbuf_printf(s, "verbose = %i\n", !!c->verbose); pa_strbuf_printf(s, "daemonize = %i\n", !!c->daemonize); @@ -267,11 +269,10 @@ char *pa_conf_dump(struct pa_conf *c) { pa_strbuf_printf(s, "disallow-module-loading = %i\n", !!c->disallow_module_loading); pa_strbuf_printf(s, "exit-idle-time = %i\n", c->exit_idle_time); pa_strbuf_printf(s, "module-idle-time = %i\n", c->module_idle_time); + pa_strbuf_printf(s, "scache-idle-time = %i\n", c->scache_idle_time); pa_strbuf_printf(s, "dl-search-path = %s\n", c->dl_search_path ? c->dl_search_path : ""); pa_strbuf_printf(s, "default-script-file = %s\n", c->default_script_file); pa_strbuf_printf(s, "log-target = %s\n", c->auto_log_target ? "auto" : (c->log_target == PA_LOG_SYSLOG ? "syslog" : "stderr")); - - pa_strbuf_printf(s, "\n### EOF ###\n"); pa_xfree(d); diff --git a/polyp/conf.h b/polyp/conf.h index da61be33..dafb3797 100644 --- a/polyp/conf.h +++ b/polyp/conf.h @@ -41,6 +41,7 @@ struct pa_conf { disallow_module_loading, exit_idle_time, module_idle_time, + scache_idle_time, auto_log_target; char *script_commands, *dl_search_path, *default_script_file; enum pa_log_target log_target; diff --git a/polyp/core.c b/polyp/core.c index 0b0bbb56..80abe9fe 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -61,8 +61,9 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->default_sample_spec.rate = 44100; c->default_sample_spec.channels = 2; - c->auto_unload_event = NULL; - c->defer_unload_event = NULL; + c->module_auto_unload_event = NULL; + c->module_defer_unload_event = NULL; + c->scache_auto_unload_event = NULL; c->subscription_defer_event = NULL; c->subscription_event_queue = NULL; @@ -76,6 +77,7 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->exit_idle_time = -1; c->module_idle_time = 20; + c->scache_idle_time = 20; pa_check_for_sigpipe(); @@ -108,11 +110,9 @@ void pa_core_free(struct pa_core *c) { pa_autoload_free(c); pa_subscription_free_all(c); - if (c->quit_event) { + if (c->quit_event) c->mainloop->time_free(c->quit_event); - c->quit_event = NULL; - } - + pa_xfree(c->default_source_name); pa_xfree(c->default_sink_name); diff --git a/polyp/core.h b/polyp/core.h index b4470577..980888f6 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -38,8 +38,8 @@ struct pa_core { char *default_source_name, *default_sink_name; struct pa_sample_spec default_sample_spec; - struct pa_time_event *auto_unload_event; - struct pa_defer_event *defer_unload_event; + struct pa_time_event *module_auto_unload_event; + struct pa_defer_event *module_defer_unload_event; struct pa_defer_event *subscription_defer_event; struct pa_queue *subscription_event_queue; @@ -48,9 +48,11 @@ struct pa_core { struct pa_memblock_stat *memblock_stat; int disallow_module_loading; - int exit_idle_time, module_idle_time; + int exit_idle_time, module_idle_time, scache_idle_time; struct pa_time_event *quit_event; + + struct pa_time_event *scache_auto_unload_event; }; struct pa_core* pa_core_new(struct pa_mainloop_api *m); diff --git a/polyp/default.pa b/polyp/default.pa index 15434627..ae1fbfcb 100755 --- a/polyp/default.pa +++ b/polyp/default.pa @@ -20,43 +20,43 @@ # Load audio drivers statically -#load module-alsa-sink -load module-alsa-source device=plughw:1,0 -load module-oss device="/dev/dsp" sink_name=output source_name=input record=0 -#load module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#load module-pipe-sink +#load-module module-alsa-sink +load-module module-alsa-source device=plughw:1,0 +load-module module-oss device="/dev/dsp" sink_name=output source_name=input record=0 +#load-module module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#load-module module-pipe-sink # Load audio drivers automatically on access -#autoload_sink_add output module-oss device="/dev/dsp" sink_name=output source_name=input -#autoload_source_add input module-oss device="/dev/dsp" sink_name=output source_name=input -#autoload_sink_add output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#autoload_source_add input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#autoload_sink_add output module-alsa-sink sink_name=output -#autoload_source_add input module-alsa-source source_name=input +#add-autoload_sink output module-oss device="/dev/dsp" sink_name=output source_name=input +#add-autoload_source input module-oss device="/dev/dsp" sink_name=output source_name=input +#add-autoload_sink output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#add-autoload_source input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#add-autoload_sink output module-alsa-sink sink_name=output +#add-autoload_source input module-alsa-source source_name=input # Load several protocols -load module-esound-protocol-tcp -#load module-simple-protocol-tcp -load module-native-protocol-unix -#load module-cli-protocol-unix -#load module-esound-protocol-unix +load-module module-esound-protocol-tcp +#load-module module-simple-protocol-tcp +load-module module-native-protocol-unix +#load-module module-cli-protocol-unix +#load-module module-esound-protocol-unix # Load the CLI module -load module-cli +load-module module-cli # Make some devices default -sink_default output -source_default input +set-default-sink output +set-default-source input .nofail # Load something to the sample cache -scache_load /usr/share/sounds/KDE_Notify.wav x11-bell +load-sample /usr/share/sounds/KDE_Notify.wav x11-bell # Load X11 bell module -load module-x11-bell sample=x11-bell sink=output +load-module module-x11-bell sample=x11-bell sink=output -#load module-pipe-source -#load module-pipe-sink +#load-module module-pipe-source +#load-module module-pipe-sink diff --git a/polyp/main.c b/polyp/main.c index 9de69ca6..04bcceef 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -234,8 +234,10 @@ int main(int argc, char *argv[]) { buf = pa_strbuf_new(); assert(buf); if (conf->default_script_file) - pa_cli_command_execute_file(c, conf->default_script_file, buf, &conf->fail, &conf->verbose); - r = pa_cli_command_execute(c, conf->script_commands, buf, &conf->fail, &conf->verbose); + r = pa_cli_command_execute_file(c, conf->default_script_file, buf, &conf->fail, &conf->verbose); + + if (r >= 0) + r = pa_cli_command_execute(c, conf->script_commands, buf, &conf->fail, &conf->verbose); pa_log(s = pa_strbuf_tostring_free(buf)); pa_xfree(s); diff --git a/polyp/module-combine.c b/polyp/module-combine.c index 28e3b39d..49a6951e 100644 --- a/polyp/module-combine.c +++ b/polyp/module-combine.c @@ -42,7 +42,7 @@ PA_MODULE_DESCRIPTION("Combine multiple sinks to one") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink_name= master= slave=") -#define DEFAULT_SINK_NAME "combine" +#define DEFAULT_SINK_NAME "combined" #define MEMBLOCKQ_MAXLENGTH (1024*170) #define RENDER_SIZE (1024*10) @@ -78,6 +78,13 @@ struct userdata { static void output_free(struct output *o); static void clear_up(struct userdata *u); +static void update_usage(struct userdata *u) { + pa_module_set_used(u->module, + (u->sink ? pa_idxset_ncontents(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_ncontents(u->sink->monitor_source->outputs) : 0)); +} + + static void adjust_rates(struct userdata *u) { struct output *o; pa_usec_t max = 0; @@ -120,6 +127,8 @@ static void request_memblock(struct userdata *u) { struct output *o; assert(u && u->sink); + update_usage(u); + if (pa_sink_render(u->sink, RENDER_SIZE, &chunk) < 0) return; diff --git a/polyp/module.c b/polyp/module.c index 73f5468c..3fb42d87 100644 --- a/polyp/module.c +++ b/polyp/module.c @@ -43,7 +43,7 @@ static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, const struct timeval *tv, void *userdata) { struct pa_core *c = userdata; struct timeval ntv; - assert(c && c->mainloop == m && c->auto_unload_event == e); + assert(c && c->mainloop == m && c->module_auto_unload_event == e); pa_module_unload_unused(c); @@ -96,13 +96,13 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char if (!c->modules) c->modules = pa_idxset_new(NULL, NULL); - if (!c->auto_unload_event) { + if (!c->module_auto_unload_event) { struct timeval ntv; gettimeofday(&ntv, NULL); ntv.tv_sec += UNLOAD_POLL_TIME; - c->auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); + c->module_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); } - assert(c->auto_unload_event); + assert(c->module_auto_unload_event); assert(c->modules); r = pa_idxset_put(c->modules, m, &m->index); @@ -184,14 +184,14 @@ void pa_module_unload_all(struct pa_core *c) { pa_idxset_free(c->modules, free_callback, NULL); c->modules = NULL; - if (c->auto_unload_event) { - c->mainloop->time_free(c->auto_unload_event); - c->auto_unload_event = NULL; + if (c->module_auto_unload_event) { + c->mainloop->time_free(c->module_auto_unload_event); + c->module_auto_unload_event = NULL; } - if (c->defer_unload_event) { - c->mainloop->defer_free(c->defer_unload_event); - c->defer_unload_event = NULL; + if (c->module_defer_unload_event) { + c->mainloop->defer_free(c->module_defer_unload_event); + c->module_defer_unload_event = NULL; } } @@ -247,10 +247,10 @@ void pa_module_unload_request(struct pa_module *m) { m->unload_requested = 1; - if (!m->core->defer_unload_event) - m->core->defer_unload_event = m->core->mainloop->defer_new(m->core->mainloop, defer_cb, m->core); + if (!m->core->module_defer_unload_event) + m->core->module_defer_unload_event = m->core->mainloop->defer_new(m->core->mainloop, defer_cb, m->core); - m->core->mainloop->defer_enable(m->core->defer_unload_event, 1); + m->core->mainloop->defer_enable(m->core->module_defer_unload_event, 1); } void pa_module_set_used(struct pa_module*m, int used) { diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 8ec48a34..6944a111 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -590,7 +590,7 @@ static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, con c->state = ESD_CACHING_SAMPLE; - pa_scache_add_item(c->protocol->core, c->scache_name, NULL, NULL, &index); + pa_scache_add_item(c->protocol->core, c->scache_name, NULL, NULL, &index, 0); ok = connection_write(c, sizeof(int)); assert(ok); @@ -748,7 +748,7 @@ static int do_read(struct connection *c) { int *ok; c->scache_memchunk.index = 0; - pa_scache_add_item(c->protocol->core, c->scache_name, &c->scache_sample_spec, &c->scache_memchunk, &index); + pa_scache_add_item(c->protocol->core, c->scache_name, &c->scache_sample_spec, &c->scache_memchunk, &index, 0); pa_memblock_unref(c->scache_memchunk.memblock); c->scache_memchunk.memblock = NULL; diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 29821b6c..e132d237 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -921,7 +921,7 @@ static void command_finish_upload_stream(struct pa_pdispatch *pd, uint32_t comma return; } - pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->memchunk, &index); + pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->memchunk, &index, 0); pa_pstream_send_simple_ack(c->pstream, tag); upload_stream_free(s); } @@ -1514,7 +1514,8 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo assert(io && p); c = pa_xmalloc(sizeof(struct connection)); - c->authorized = p->public; + + c->authorized =!! p->public; c->protocol = p; assert(p->core); c->client = pa_client_new(p->core, "NATIVE", "Client"); @@ -1548,7 +1549,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo static struct pa_protocol_native* protocol_new_internal(struct pa_core *c, struct pa_module *m, struct pa_modargs *ma) { struct pa_protocol_native *p; - int public; + int public = 0; assert(c && ma); if (pa_modargs_get_value_boolean(ma, "public", &public) < 0) { diff --git a/polyp/scache.c b/polyp/scache.c index 53e8a3fe..5725e128 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -37,6 +37,20 @@ #include "subscribe.h" #include "namereg.h" +#define UNLOAD_POLL_TIME 2 + +static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, const struct timeval *tv, void *userdata) { + struct pa_core *c = userdata; + struct timeval ntv; + assert(c && c->mainloop == m && c->scache_auto_unload_event == e); + + pa_scache_unload_unused(c); + + gettimeofday(&ntv, NULL); + ntv.tv_sec += UNLOAD_POLL_TIME; + m->time_restart(e, &ntv); +} + static void free_entry(struct pa_scache_entry *e) { assert(e); pa_namereg_unregister(e->core, e->name); @@ -47,7 +61,7 @@ static void free_entry(struct pa_scache_entry *e) { pa_xfree(e); } -int pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index) { +int pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index, int auto_unload) { struct pa_scache_entry *e; int put; assert(c && name); @@ -72,6 +86,8 @@ int pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spe } e->volume = PA_VOLUME_NORM; + e->auto_unload = auto_unload; + e->last_used_time = 0; if (ss) e->sample_spec = *ss; @@ -101,6 +117,13 @@ int pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spe if (index) *index = e->index; + if (!c->scache_auto_unload_event) { + struct timeval ntv; + gettimeofday(&ntv, NULL); + ntv.tv_sec += UNLOAD_POLL_TIME; + c->scache_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); + } + return 0; } @@ -131,13 +154,16 @@ void pa_scache_free(struct pa_core *c) { pa_idxset_free(c->scache, free_cb, NULL); c->scache = NULL; } + + if (c->scache_auto_unload_event) + c->mainloop->time_free(c->scache_auto_unload_event); } int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sink, uint32_t volume) { struct pa_scache_entry *e; assert(c && name && sink); - if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) + if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1))) return -1; if (!e->memchunk.memblock) @@ -145,6 +171,9 @@ int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sin if (pa_play_memchunk(sink, name, &e->sample_spec, &e->memchunk, pa_volume_multiply(volume, e->volume)) < 0) return -1; + + if (e->auto_unload) + time(&e->last_used_time); return 0; } @@ -163,7 +192,7 @@ uint32_t pa_scache_get_id_by_name(struct pa_core *c, const char *name) { struct pa_scache_entry *e; assert(c && name); - if (!c->scache || !(e = pa_idxset_get_by_data(c->scache, name, NULL))) + if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1))) return PA_IDXSET_INVALID; return e->index; @@ -180,6 +209,33 @@ uint32_t pa_scache_total_size(struct pa_core *c) { for (e = pa_idxset_first(c->scache, &index); e; e = pa_idxset_next(c->scache, &index)) sum += e->memchunk.length; - return sum; } + +static int unload_func(void *p, uint32_t index, int *del, void *userdata) { + struct pa_scache_entry *e = p; + time_t *now = userdata; + assert(e); + + if (!e->auto_unload) + return 0; + + if (e->last_used_time + e->core->scache_idle_time > *now) + return 0; + + free_entry(e); + *del = 1; + return 0; +} + +void pa_scache_unload_unused(struct pa_core *c) { + time_t now; + assert(c); + + if (!c->scache) + return; + + time(&now); + + pa_idxset_foreach(c->scache, unload_func, &now); +} diff --git a/polyp/scache.h b/polyp/scache.h index cfd479b5..e0574409 100644 --- a/polyp/scache.h +++ b/polyp/scache.h @@ -33,9 +33,12 @@ struct pa_scache_entry { uint32_t volume; struct pa_sample_spec sample_spec; struct pa_memchunk memchunk; + + int auto_unload; + time_t last_used_time; }; -int pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index); +int pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index, int auto_unload); int pa_scache_remove_item(struct pa_core *c, const char *name); int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sink, uint32_t volume); @@ -46,4 +49,6 @@ uint32_t pa_scache_get_id_by_name(struct pa_core *c, const char *name); uint32_t pa_scache_total_size(struct pa_core *c); +void pa_scache_unload_unused(struct pa_core *c); + #endif -- cgit From 8c110d904ddf30ce35c9a0c18449436af18a5095 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Sep 2004 13:03:25 +0000 Subject: correct autospawning git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@202 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 3 +- polyp/conf.c | 30 ++++++- polyp/core.c | 3 +- polyp/main.c | 14 +--- polyp/pacat.c | 2 +- polyp/pactl.c | 2 +- polyp/polyplib-context.c | 199 ++++++++++++++++++++++++---------------------- polyp/polyplib-context.h | 21 ++--- polyp/polyplib-def.h | 19 +++++ polyp/polyplib-internal.h | 2 + polyp/polyplib-simple.c | 2 +- polyp/util.c | 22 ++++- polyp/util.h | 4 +- 13 files changed, 187 insertions(+), 136 deletions(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 9c672a3b..fc3fb18d 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -25,7 +25,8 @@ modlibdir=$(libdir)/polypaudio-@PA_MAJORMINOR@ AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) AM_CFLAGS+=-DDLSEARCHPATH=\"$(modlibdir)\" AM_CFLAGS+=-DDEFAULT_SCRIPT_FILE=\"$(polypconfdir)/default.pa\" -AM_CFLAGS+=-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/config\" +AM_CFLAGS+=-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/default.conf\" +AM_CFLAGS+=-DAUTOSPAWN_CONFIG_FILE=\"$(polypconfdir)/autospawn.conf\" AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\" AM_LDADD=$(PTHREAD_LIBS) -lm diff --git a/polyp/conf.c b/polyp/conf.c index 3a894a9b..b74a5ede 100644 --- a/polyp/conf.c +++ b/polyp/conf.c @@ -53,17 +53,23 @@ static const struct pa_conf default_conf = { #define ENV_SCRIPT_FILE "POLYP_SCRIPT" #define ENV_CONFIG_FILE "POLYP_CONFIG" +#define ENV_AUTOSPAWNED "POLYP_AUTOSPAWNED" #ifndef DEFAULT_SCRIPT_FILE #define DEFAULT_SCRIPT_FILE "/etc/polypaudio/default.pa" #endif #ifndef DEFAULT_CONFIG_FILE -#define DEFAULT_CONFIG_FILE "/etc/polypaudio/config" +#define DEFAULT_CONFIG_FILE "/etc/polypaudio/default.conf" +#endif + +#ifndef AUTOSPAWN_CONFIG_FILE +#define AUTOSPAWN_CONFIG_FILE "/etc/polypaudio/autospawn.conf" #endif #define DEFAULT_SCRIPT_FILE_LOCAL ".polypaudio.pa" #define DEFAULT_CONFIG_FILE_LOCAL ".polypaudio.conf" +#define AUTOSPAWN_CONFIG_FILE_LOCAL ".polypaudio-autospawn.conf" char* default_file(const char *envvar, const char *global, const char *local) { char *p, *h; @@ -85,10 +91,26 @@ char* default_file(const char *envvar, const char *global, const char *local) { return pa_xstrdup(global); } +char *default_config_file(void) { + char *b; + int autospawned = 0; + + if ((b = getenv(ENV_AUTOSPAWNED))) + autospawned = pa_parse_boolean(b) > 0; + + return default_file(ENV_CONFIG_FILE, + autospawned ? AUTOSPAWN_CONFIG_FILE : DEFAULT_CONFIG_FILE, + autospawned ? AUTOSPAWN_CONFIG_FILE_LOCAL : DEFAULT_CONFIG_FILE_LOCAL); + +} + +char *default_script_file(void) { + return default_file(ENV_SCRIPT_FILE, DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_LOCAL); +} struct pa_conf* pa_conf_new(void) { struct pa_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); - c->default_script_file = default_file(ENV_SCRIPT_FILE, DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_LOCAL); + c->default_script_file = default_script_file(); return c; } @@ -223,7 +245,7 @@ int pa_conf_load(struct pa_conf *c, const char *filename) { assert(c); if (!filename) - filename = def = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_LOCAL); + filename = def = default_config_file(); if (!(f = fopen(filename, "r"))) { if (errno != ENOENT) @@ -259,7 +281,7 @@ char *pa_conf_dump(struct pa_conf *c) { struct pa_strbuf *s = pa_strbuf_new(); char *d; - d = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_LOCAL); + d = default_config_file(); pa_strbuf_printf(s, "### Default configuration file: %s ###\n", d); pa_strbuf_printf(s, "verbose = %i\n", !!c->verbose); diff --git a/polyp/core.c b/polyp/core.c index 80abe9fe..58035087 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "core.h" #include "module.h" @@ -79,7 +80,7 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->module_idle_time = 20; c->scache_idle_time = 20; - pa_check_for_sigpipe(); + pa_check_signal_is_blocked(SIGPIPE); return c; } diff --git a/polyp/main.c b/polyp/main.c index 04bcceef..e44fc013 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -58,20 +58,8 @@ static void drop_root(void) { } } -static const char* signal_name(int s) { - switch(s) { - case SIGINT: return "SIGINT"; - case SIGTERM: return "SIGTERM"; - case SIGUSR1: return "SIGUSR1"; - case SIGUSR2: return "SIGUSR2"; - case SIGXCPU: return "SIGXCPU"; - case SIGPIPE: return "SIGPIPE"; - default: return "UNKNOWN SIGNAL"; - } -} - static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { - pa_log(__FILE__": Got signal %s.\n", signal_name(sig)); + pa_log(__FILE__": Got signal %s.\n", pa_strsignal(sig)); switch (sig) { case SIGUSR1: diff --git a/polyp/pacat.c b/polyp/pacat.c index b499f71a..f4597714 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -360,7 +360,7 @@ int main(int argc, char *argv[]) { pa_context_set_state_callback(context, context_state_callback, NULL); /* Connect the context */ - pa_context_connect_spawn(context, NULL, NULL, NULL); + pa_context_connect(context, NULL, 1, NULL); /* Run the main loop */ if (pa_mainloop_run(m, &ret) < 0) { diff --git a/polyp/pactl.c b/polyp/pactl.c index dfa11b70..c93fd235 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -292,7 +292,7 @@ int main(int argc, char *argv[]) { } pa_context_set_state_callback(context, context_state_callback, NULL); - pa_context_connect(context, NULL); + pa_context_connect(context, NULL, 1, NULL); if (pa_mainloop_run(m, &ret) < 0) { fprintf(stderr, "pa_mainloop_run() failed.\n"); diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 63b42eb3..7fef6b12 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -85,7 +85,7 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * c->memblock_stat = pa_memblock_stat_new(); - pa_check_for_sigpipe(); + pa_check_signal_is_blocked(SIGPIPE); return c; } @@ -365,15 +365,116 @@ static struct sockaddr *resolve_server(const char *server, size_t *len) { return sa; } -int pa_context_connect(struct pa_context *c, const char *server) { +static int is_running(void) { + struct stat st; + + if (DEFAULT_SERVER[0] != '/') + return 1; + + if (stat(DEFAULT_SERVER, &st) < 0) + return 0; + + return 1; +} + +static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api *api) { + pid_t pid; + int status, r; + int fds[2] = { -1, -1} ; + struct pa_iochannel *io; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { + pa_log(__FILE__": socketpair() failed: %s\n", strerror(errno)); + pa_context_fail(c, PA_ERROR_INTERNAL); + goto fail; + } + + if (api && api->prefork) + api->prefork(); + + if ((pid = fork()) < 0) { + pa_log(__FILE__": fork() failed: %s\n", strerror(errno)); + pa_context_fail(c, PA_ERROR_INTERNAL); + + if (api && api->postfork) + api->postfork(); + + goto fail; + } else if (!pid) { + char t[128]; + char *p; + /* Child */ + + close(fds[0]); + + if (api && api->atfork) + api->atfork(); + + if (!(p = getenv(ENV_DEFAULT_BINARY))) + p = POLYPAUDIO_BINARY; + + snprintf(t, sizeof(t), "%s=1", ENV_AUTOSPAWNED); + putenv(t); + + snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]); + execl(p, p, t, NULL); + + exit(1); + } + + /* Parent */ + + r = waitpid(pid, &status, 0); + + if (api && api->postfork) + api->postfork(); + + if (r < 0) { + pa_log(__FILE__": waitpid() failed: %s\n", strerror(errno)); + pa_context_fail(c, PA_ERROR_INTERNAL); + goto fail; + } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + goto fail; + } + + close(fds[1]); + + io = pa_iochannel_new(c->mainloop, fds[0], fds[0]); + setup_context(c, io); + return 0; + +fail: + if (fds[0] != -1) + close(fds[0]); + if (fds[1] != -1) + close(fds[1]); + + return -1; +} + + + +int pa_context_connect(struct pa_context *c, const char *server, int spawn, const struct pa_spawn_api *api) { int r = -1; assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED); - pa_context_ref(c); - if (!server) - if (!(server = getenv(ENV_DEFAULT_SERVER))) + if (!(server = getenv(ENV_DEFAULT_SERVER))) { + if (spawn && !is_running()) { + char *b; + + if ((b = getenv(ENV_DISABLE_AUTOSPAWN))) + if (pa_parse_boolean(b) > 1) + return -1; + + return context_connect_spawn(c, api); + } + server = DEFAULT_SERVER; + } + + pa_context_ref(c); assert(!c->client); @@ -562,94 +663,6 @@ const char* pa_get_library_version(void) { return PACKAGE_VERSION; } -static int is_running(void) { - struct stat st; - - if (DEFAULT_SERVER[0] != '/') - return 1; - - if (stat(DEFAULT_SERVER, &st) < 0) - return 0; - - return 1; -} - -int pa_context_connect_spawn(struct pa_context *c, void (*atfork)(void), void (*prefork)(void), void (*postfork)(void)) { - pid_t pid; - int status, r; - int fds[2] = { -1, -1} ; - struct pa_iochannel *io; - - if (getenv(ENV_DEFAULT_SERVER) || is_running()) - return pa_context_connect(c, NULL); - - if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { - pa_log(__FILE__": socketpair() failed: %s\n", strerror(errno)); - pa_context_fail(c, PA_ERROR_INTERNAL); - goto fail; - } - - if (prefork) - prefork(); - - if ((pid = fork()) < 0) { - pa_log(__FILE__": fork() failed: %s\n", strerror(errno)); - pa_context_fail(c, PA_ERROR_INTERNAL); - - if (postfork) - postfork(); - - goto fail; - } else if (!pid) { - char t[64]; - char *p; - /* Child */ - - close(fds[0]); - - if (atfork) - atfork(); - - if (!(p = getenv(ENV_DEFAULT_BINARY))) - p = POLYPAUDIO_BINARY; - - snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]); - execl(p, p, "-r", "-D", "-lsyslog", "-X 5", t, NULL); - - exit(1); - } - - /* Parent */ - - r = waitpid(pid, &status, 0); - - if (postfork) - postfork(); - - if (r < 0) { - pa_log(__FILE__": waitpid() failed: %s\n", strerror(errno)); - pa_context_fail(c, PA_ERROR_INTERNAL); - goto fail; - } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); - goto fail; - } - - close(fds[1]); - - io = pa_iochannel_new(c->mainloop, fds[0], fds[0]); - setup_context(c, io); - return 0; - -fail: - if (fds[0] != -1) - close(fds[0]); - if (fds[1] != -1) - close(fds[1]); - - return -1; -} - struct pa_operation* pa_context_set_default_sink(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata) { struct pa_tagstruct *t; struct pa_operation *o; diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h index 4b199751..84e47b64 100644 --- a/polyp/polyplib-context.h +++ b/polyp/polyplib-context.h @@ -76,22 +76,11 @@ enum pa_context_state pa_context_get_state(struct pa_context *c); /** Connect the context to the specified server. If server is NULL, connect to the default server. This routine may but will not always return synchronously on error. Use pa_context_set_state_callback() to -be notified when the connection is established */ -int pa_context_connect(struct pa_context *c, const char *server); - -/** Connect the context to a server. If the default server is local - * but not accessible, spawn a new daemon. If atfork is not NULL it is - * run after the fork() in the child process. It may be used to close - * file descriptors or to do any other cleanups. (It is not safe to - * close all file descriptors unconditionally, since a UNIX socket is - * passed to the new process.) if prefork is not NULL it is run just - * before forking in the parent process. Use this to block SIGCHLD - * handling if required. If postfork is not NULL it is run just after - * forking in the parent process. Use this to unblock SIGCHLD if - * required. The function will waitpid() on the daemon's PID, but - * will not block or ignore SIGCHLD signals, since this cannot be done - * in a thread compatible way. \since 0.4 */ -int pa_context_connect_spawn(struct pa_context *c, void (*atfork)(void), void (*prefork)(void), void (*postfork)(void)); +be notified when the connection is established. If spawn is non-zero +and no specific server is specified or accessible a new daemon is +spawned. If api is non-NULL, the functions specified in the structure +are used when forking a new child process. */ +int pa_context_connect(struct pa_context *c, const char *server, int spawn, const struct pa_spawn_api *api); /** Terminate the context connection immediately */ void pa_context_disconnect(struct pa_context *c); diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index 4a49a1f8..2aa33338 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -156,6 +156,25 @@ struct pa_latency_info { struct timeval timestamp; /**< The time when this latency info was current */ }; +/** A structure for the spawn api. This may be used to integrate auto + * spawned daemons into your application. For more information see + * pa_context_connect(). When spawning a new child process the + * waitpid() is used on the child's PID. The spawn routine will not + * block or ignore SIGCHLD signals, since this cannot be done in a + * thread compatible way. You might have to do this in + * prefork/postfork. \since 0.4 */ +struct pa_spawn_api { + void (*prefork)(void); /**< Is called just before the fork in the parent process. May be NULL. */ + void (*postfork)(void); /**< Is called immediately after the fork in the parent process. May be NULL.*/ + void (*atfork)(void); /**< Is called immediately after the + * fork in the child process. May be + * NULL. It is not safe to close all + * file descriptors in this function + * unconditionally, since a UNIX socket + * (created using socketpair()) is + * passed to the new process. */ +}; + PA_C_DECL_END #endif diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index de63b1ba..98fd7924 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -48,6 +48,8 @@ #define ENV_DEFAULT_SOURCE "POLYP_SOURCE" #define ENV_DEFAULT_SERVER "POLYP_SERVER" #define ENV_DEFAULT_BINARY "POLYP_BINARY" +#define ENV_DISABLE_AUTOSPAWN "POLYP_NOAUTOSPAWN" +#define ENV_AUTOSPAWNED "POLYP_AUTOSPAWNED" struct pa_context { int ref; diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c index 1ac08869..36e6e757 100644 --- a/polyp/polyplib-simple.c +++ b/polyp/polyplib-simple.c @@ -130,7 +130,7 @@ struct pa_simple* pa_simple_new( if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name))) goto fail; - pa_context_connect(p->context, server); + pa_context_connect(p->context, server, 1, NULL); /* Wait until the context is ready */ while (pa_context_get_state(p->context) != PA_CONTEXT_READY) { diff --git a/polyp/util.c b/polyp/util.c index 3ab6d51a..bb71bbf9 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -115,7 +115,7 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size) { return ret; } -void pa_check_for_sigpipe(void) { +void pa_check_signal_is_blocked(int sig) { struct sigaction sa; sigset_t set; @@ -130,10 +130,10 @@ void pa_check_for_sigpipe(void) { } #endif - if (sigismember(&set, SIGPIPE)) + if (sigismember(&set, sig)) return; - if (sigaction(SIGPIPE, NULL, &sa) < 0) { + if (sigaction(sig, NULL, &sa) < 0) { pa_log(__FILE__": sigaction() failed: %s\n", strerror(errno)); return; } @@ -141,7 +141,7 @@ void pa_check_for_sigpipe(void) { if (sa.sa_handler != SIG_DFL) return; - pa_log(__FILE__": WARNING: SIGPIPE is not trapped. This might cause malfunction!\n"); + pa_log(__FILE__": WARNING: %s is not trapped. This might cause malfunction!\n", pa_strsignal(sig)); } /* The following is based on an example from the GNU libc documentation */ @@ -389,3 +389,17 @@ char *pa_split(const char *c, const char *delimiter, const char**state) { return pa_xstrndup(current, l); } + +const char *pa_strsignal(int sig) { + switch(sig) { + case SIGINT: return "SIGINT"; + case SIGTERM: return "SIGTERM"; + case SIGUSR1: return "SIGUSR1"; + case SIGUSR2: return "SIGUSR2"; + case SIGXCPU: return "SIGXCPU"; + case SIGPIPE: return "SIGPIPE"; + case SIGCHLD: return "SIGCHLD"; + default: return "UNKNOWN SIGNAL"; + } +} + diff --git a/polyp/util.h b/polyp/util.h index eae98e6e..f5cda200 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -36,7 +36,7 @@ int pa_make_secure_dir(const char* dir); ssize_t pa_loop_read(int fd, void*data, size_t size); ssize_t pa_loop_write(int fd, const void*data, size_t size); -void pa_check_for_sigpipe(void); +void pa_check_signal_is_blocked(int sig); char *pa_sprintf_malloc(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); char *pa_vsprintf_malloc(const char *format, va_list ap); @@ -61,4 +61,6 @@ int pa_parse_boolean(const char *s); char *pa_split(const char *c, const char*delimiters, const char **state); +const char *pa_strsignal(int sig); + #endif -- cgit From 9ca72dce0bda4e279ff82a01847ee09a72434b33 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Sep 2004 14:05:28 +0000 Subject: remove auto-load-sample stuff introduce "lazy samples" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@203 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 + polyp/autoload.c | 35 ++----------- polyp/autoload.h | 6 +-- polyp/cli-command.c | 27 ++++------ polyp/cli-text.c | 34 ++++++------ polyp/module-combine.c | 26 ++++++--- polyp/namereg.h | 2 - polyp/protocol-esound.c | 4 +- polyp/protocol-native.c | 2 +- polyp/scache.c | 137 +++++++++++++++++++++++++++++++----------------- polyp/scache.h | 9 +++- 11 files changed, 151 insertions(+), 133 deletions(-) diff --git a/doc/todo b/doc/todo index fedfa545..91a2f92f 100644 --- a/doc/todo +++ b/doc/todo @@ -14,6 +14,8 @@ - fix tcp/native - add volume to create_stream command in native protocol - udp based protocol +- add client config file +- beefup sample_info stuff in native protocol *** 0.6 **** - per-channel volume diff --git a/polyp/autoload.c b/polyp/autoload.c index 8eb5bbf5..344d26e2 100644 --- a/polyp/autoload.c +++ b/polyp/autoload.c @@ -40,7 +40,6 @@ static void entry_free(struct pa_autoload_entry *e) { pa_xfree(e->name); pa_xfree(e->module); pa_xfree(e->argument); - pa_xfree(e->filename); pa_xfree(e); } @@ -53,7 +52,7 @@ static struct pa_autoload_entry* entry_new(struct pa_core *c, const char *name) e = pa_xmalloc(sizeof(struct pa_autoload_entry)); e->name = pa_xstrdup(name); - e->module = e->argument = e->filename = NULL; + e->module = e->argument = NULL; e->in_action = 0; if (!c->autoload_hashmap) @@ -65,10 +64,10 @@ static struct pa_autoload_entry* entry_new(struct pa_core *c, const char *name) return e; } -int pa_autoload_add_module(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*module, const char *argument) { +int pa_autoload_add(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*module, const char *argument) { struct pa_autoload_entry *e = NULL; - assert(c && name && module); - + assert(c && name && module && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); + if (!(e = entry_new(c, name))) return -1; @@ -78,18 +77,6 @@ int pa_autoload_add_module(struct pa_core *c, const char*name, enum pa_namereg_t return 0; } -int pa_autoload_add_sample(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*filename) { - struct pa_autoload_entry *e = NULL; - assert(c && name && filename); - - if (!(e = entry_new(c, name))) - return -1; - - e->filename = pa_xstrdup(filename); - e->type = PA_NAMEREG_SAMPLE; - return 0; -} - int pa_autoload_remove(struct pa_core *c, const char*name, enum pa_namereg_type type) { struct pa_autoload_entry *e; assert(c && name && type); @@ -118,20 +105,8 @@ void pa_autoload_request(struct pa_core *c, const char *name, enum pa_namereg_ty if (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE) { if ((m = pa_module_load(c, e->module, e->argument))) m->auto_unload = 1; - - } else { - struct pa_sample_spec ss; - struct pa_memchunk chunk; - assert(type == PA_NAMEREG_SAMPLE); - - if (pa_sound_file_load(e->filename, &ss, &chunk, c->memblock_stat) < 0) - pa_log(__FILE__": failed to load sound file '%s' for autoload entry '%s'.\n", e->filename, e->name); - else { - pa_scache_add_item(c, e->name, &ss, &chunk, NULL, 1); - pa_memblock_unref(chunk.memblock); - } } - + e->in_action = 0; } diff --git a/polyp/autoload.h b/polyp/autoload.h index 3d3101b9..cdf76239 100644 --- a/polyp/autoload.h +++ b/polyp/autoload.h @@ -28,12 +28,10 @@ struct pa_autoload_entry { char *name; enum pa_namereg_type type; int in_action; - char *module, *argument; /* for module autoloading */ - char *filename; /* for sample autoloading */ + char *module, *argument; }; -int pa_autoload_add_module(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*module, const char *argument); -int pa_autoload_add_sample(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*filename); +int pa_autoload_add(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*module, const char *argument); void pa_autoload_free(struct pa_core *c); int pa_autoload_remove(struct pa_core *c, const char*name, enum pa_namereg_type type); void pa_autoload_request(struct pa_core *c, const char *name, enum pa_namereg_type type); diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 574af9db..750d67ea 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -110,14 +110,13 @@ static const struct command commands[] = { { "play-sample", pa_cli_command_scache_play, "Play a sample from the sample cache (args: name, sink|index)", 3}, { "remove-sample", pa_cli_command_scache_remove, "Remove a sample from the sample cache (args: name)", 2}, { "load-sample", pa_cli_command_scache_load, "Load a sound file into the sample cache (args: name, filename)", 3}, + { "load-sample-lazy", pa_cli_command_scache_load, "Lazy load a sound file into the sample cache (args: name, filename)", 3}, { "play-file", pa_cli_command_play_file, "Play a sound file (args: filename, sink|index)", 3}, { "list-autoload", pa_cli_command_autoload_list, "List autoload entries", 1}, { "add-autoload-sink", pa_cli_command_autoload_add, "Add autoload entry for a sink (args: sink, module name, arguments)", 4}, { "add-autoload-source", pa_cli_command_autoload_add, "Add autoload entry for a source (args: source, module name, arguments)", 4}, - { "add-autoload-sample", pa_cli_command_autoload_add, "Add autoload entry for a smple (args: name, filename)", 3}, { "remove-autoload-sink", pa_cli_command_autoload_remove, "Remove autoload entry for a sink (args: name)", 2}, { "remove-autoload-source", pa_cli_command_autoload_remove, "Remove autoload entry for a source (args: name)", 2}, - { "remove-autoload-sample", pa_cli_command_autoload_remove, "Remove autoload entry for a sample (args: name)", 2}, { "dump", pa_cli_command_dump, "Dump daemon configuration", 1}, { NULL, NULL, NULL, 0 } }; @@ -522,8 +521,7 @@ static int pa_cli_command_scache_remove(struct pa_core *c, struct pa_tokenizer * static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { const char *fname, *n; - struct pa_memchunk chunk; - struct pa_sample_spec ss; + int r; assert(c && t && buf && fail && verbose); if (!(fname = pa_tokenizer_get(t, 2)) || !(n = pa_tokenizer_get(t, 1))) { @@ -531,13 +529,14 @@ static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t, return -1; } - if (pa_sound_file_load(fname, &ss, &chunk, c->memblock_stat) < 0) { + if (strstr(pa_tokenizer_get(t, 0), "lazy")) + r = pa_scache_add_file_lazy(c, n, fname, NULL); + else + r = pa_scache_add_file(c, n, fname, NULL); + + if (r < 0) pa_strbuf_puts(buf, "Failed to load sound file.\n"); - return -1; - } - pa_scache_add_item(c, n, &ss, &chunk, NULL, 0); - pa_memblock_unref(chunk.memblock); return 0; } @@ -569,10 +568,7 @@ static int pa_cli_command_autoload_add(struct pa_core *c, struct pa_tokenizer *t return -1; } - if (strstr(pa_tokenizer_get(t, 0), "sample")) - pa_autoload_add_sample(c, a, PA_NAMEREG_SAMPLE, b); - else - pa_autoload_add_module(c, a, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, b, pa_tokenizer_get(t, 3)); + pa_autoload_add(c, a, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, b, pa_tokenizer_get(t, 3)); return 0; } @@ -586,8 +582,7 @@ static int pa_cli_command_autoload_remove(struct pa_core *c, struct pa_tokenizer return -1; } - if (pa_autoload_remove(c, name, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : - (strstr(pa_tokenizer_get(t, 0), "source") ? PA_NAMEREG_SOURCE : PA_NAMEREG_SAMPLE)) < 0) { + if (pa_autoload_remove(c, name, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE) < 0) { pa_strbuf_puts(buf, "Failed to remove autload entry\n"); return -1; } @@ -664,7 +659,7 @@ static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct nl = 1; } - pa_strbuf_printf(buf, "add-autoload-%s %s %s", a->type == PA_NAMEREG_SINK ? "sink" : (a->type == PA_NAMEREG_SOURCE ? "source" : "sample"), a->name, a->type == PA_NAMEREG_SAMPLE ? a->filename : a->module); + pa_strbuf_printf(buf, "add-autoload-%s %s %s", a->type == PA_NAMEREG_SINK ? "sink" : "source", a->name, a->module); if (a->argument) pa_strbuf_printf(buf, " %s", a->argument); diff --git a/polyp/cli-text.c b/polyp/cli-text.c index dbc14fda..0915be8b 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -221,21 +221,24 @@ char *pa_scache_list_to_string(struct pa_core *c) { uint32_t index = PA_IDXSET_INVALID; for (e = pa_idxset_first(c->scache, &index); e; e = pa_idxset_next(c->scache, &index)) { - double l; - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; - pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec); + double l = 0; + char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH] = "n/a"; - l = (double) e->memchunk.length / pa_bytes_per_second(&e->sample_spec); + if (e->memchunk.memblock) { + pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec); + l = (double) e->memchunk.length / pa_bytes_per_second(&e->sample_spec); + } pa_strbuf_printf( - s, " name: <%s>\n\tindex: <%i>\n\tsample_spec: <%s>\n\tlength: <%u>\n\tduration: <%0.1fs>\n\tvolume: <0x%04x>\n\tauto unload: %s\n", + s, " name: <%s>\n\tindex: <%i>\n\tsample_spec: <%s>\n\tlength: <%u>\n\tduration: <%0.1fs>\n\tvolume: <0x%04x>\n\tlazy: %s\n\tfilename: %s\n", e->name, e->index, ss, - e->memchunk.length, + e->memchunk.memblock ? e->memchunk.length : 0, l, e->volume, - e->auto_unload ? "yes" : "no"); + e->lazy ? "yes" : "no", + e->filename ? e->filename : "n/a"); } } @@ -257,19 +260,12 @@ char *pa_autoload_list_to_string(struct pa_core *c) { while ((e = pa_hashmap_iterate(c->autoload_hashmap, &state))) { pa_strbuf_printf( - s, " name: <%s>\n\ttype: <%s>\n", + s, " name: <%s>\n\ttype: <%s>\n\tmodule_name: <%s>\n\targuments: <%s>\n", e->name, - e->type == PA_NAMEREG_SOURCE ? "source" : (e->type == PA_NAMEREG_SINK ? "sink" : "sample")); - - if (e->type != PA_NAMEREG_SAMPLE) - pa_strbuf_printf( - s, "\tmodule_name: <%s>\n\targuments: <%s>\n", - e->module, - e->argument); - else - pa_strbuf_printf( - s, "\tfilename: <%s>\n", - e->filename); + e->type == PA_NAMEREG_SOURCE ? "source" : "sink", + e->module, + e->argument); + } } diff --git a/polyp/module-combine.c b/polyp/module-combine.c index 49a6951e..8535e514 100644 --- a/polyp/module-combine.c +++ b/polyp/module-combine.c @@ -40,18 +40,19 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Combine multiple sinks to one") PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= master= slave=") +PA_MODULE_USAGE("sink_name= master= slave= adjust_time") #define DEFAULT_SINK_NAME "combined" #define MEMBLOCKQ_MAXLENGTH (1024*170) #define RENDER_SIZE (1024*10) -#define ADJUST_TIME 5 +#define DEFAULT_ADJUST_TIME 20 static const char* const valid_modargs[] = { "sink_name", "master", "slaves", + "adjust_time", NULL }; @@ -71,6 +72,7 @@ struct userdata { unsigned n_outputs; struct output *master; struct pa_time_event *time_event; + uint32_t adjust_time; PA_LLIST_HEAD(struct output, outputs); }; @@ -109,9 +111,9 @@ static void adjust_rates(struct userdata *u) { l = o->sink_latency + pa_sink_input_get_latency(o->sink_input); if (l < max) - r -= (uint32_t) (((((double) max-l))/ADJUST_TIME)*r/ 1000000); + r -= (uint32_t) (((((double) max-l))/u->adjust_time)*r/ 1000000); else if (l > max) - r += (uint32_t) (((((double) l-max))/ADJUST_TIME)*r/ 1000000); + r += (uint32_t) (((((double) l-max))/u->adjust_time)*r/ 1000000); if (r < (uint32_t) (base_rate*0.9) || r > (uint32_t) (base_rate*1.1)) pa_log(__FILE__": [%s] sample rates too different, not adjusting (%u vs. %u).\n", o->sink_input->name, base_rate, r); @@ -146,7 +148,7 @@ static void time_callback(struct pa_mainloop_api*a, struct pa_time_event* e, con adjust_rates(u); gettimeofday(&n, NULL); - n.tv_sec += ADJUST_TIME; + n.tv_sec += u->adjust_time; u->sink->core->mainloop->time_restart(e, &n); } @@ -289,8 +291,14 @@ int pa__init(struct pa_core *c, struct pa_module*m) { u->module = m; u->core = c; u->time_event = NULL; + u->adjust_time = DEFAULT_ADJUST_TIME; PA_LLIST_HEAD_INIT(struct output, u->outputs); + if (pa_modargs_get_value_u32(ma, "adjust_time", &u->adjust_time) < 0) { + pa_log(__FILE__": failed to parse adjust_time value\n"); + goto fail; + } + if (!(master_name = pa_modargs_get_value(ma, "master", NULL)) || !(slaves = pa_modargs_get_value(ma, "slaves", NULL))) { pa_log(__FILE__": no master or slave sinks specified\n"); goto fail; @@ -336,9 +344,11 @@ int pa__init(struct pa_core *c, struct pa_module*m) { if (u->n_outputs <= 1) pa_log(__FILE__": WARNING: no slave sinks specified.\n"); - gettimeofday(&tv, NULL); - tv.tv_sec += ADJUST_TIME; - u->time_event = c->mainloop->time_new(c->mainloop, &tv, time_callback, u); + if (u->adjust_time > 0) { + gettimeofday(&tv, NULL); + tv.tv_sec += u->adjust_time; + u->time_event = c->mainloop->time_new(c->mainloop, &tv, time_callback, u); + } pa_modargs_free(ma); return 0; diff --git a/polyp/namereg.h b/polyp/namereg.h index f1be3958..b383d9ed 100644 --- a/polyp/namereg.h +++ b/polyp/namereg.h @@ -37,9 +37,7 @@ void pa_namereg_unregister(struct pa_core *c, const char *name); void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type type, int autoload); void pa_namereg_set_default(struct pa_core*c, const char *name, enum pa_namereg_type type); - const char *pa_namereg_get_default_sink_name(struct pa_core *c); const char *pa_namereg_get_default_source_name(struct pa_core *c); - #endif diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 6944a111..8ec48a34 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -590,7 +590,7 @@ static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, con c->state = ESD_CACHING_SAMPLE; - pa_scache_add_item(c->protocol->core, c->scache_name, NULL, NULL, &index, 0); + pa_scache_add_item(c->protocol->core, c->scache_name, NULL, NULL, &index); ok = connection_write(c, sizeof(int)); assert(ok); @@ -748,7 +748,7 @@ static int do_read(struct connection *c) { int *ok; c->scache_memchunk.index = 0; - pa_scache_add_item(c->protocol->core, c->scache_name, &c->scache_sample_spec, &c->scache_memchunk, &index, 0); + pa_scache_add_item(c->protocol->core, c->scache_name, &c->scache_sample_spec, &c->scache_memchunk, &index); pa_memblock_unref(c->scache_memchunk.memblock); c->scache_memchunk.memblock = NULL; diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index e132d237..55b98fd4 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -921,7 +921,7 @@ static void command_finish_upload_stream(struct pa_pdispatch *pd, uint32_t comma return; } - pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->memchunk, &index, 0); + pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->memchunk, &index); pa_pstream_send_simple_ack(c->pstream, tag); upload_stream_free(s); } diff --git a/polyp/scache.c b/polyp/scache.c index 5725e128..026f4b17 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -36,6 +36,7 @@ #include "xmalloc.h" #include "subscribe.h" #include "namereg.h" +#include "sound-file.h" #define UNLOAD_POLL_TIME 2 @@ -56,74 +57,110 @@ static void free_entry(struct pa_scache_entry *e) { pa_namereg_unregister(e->core, e->name); pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_REMOVE, e->index); pa_xfree(e->name); + pa_xfree(e->filename); if (e->memchunk.memblock) pa_memblock_unref(e->memchunk.memblock); pa_xfree(e); } -int pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index, int auto_unload) { +static struct pa_scache_entry* scache_add_item(struct pa_core *c, const char *name) { struct pa_scache_entry *e; - int put; assert(c && name); if ((e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) { - put = 0; if (e->memchunk.memblock) pa_memblock_unref(e->memchunk.memblock); + + pa_xfree(e->filename); + assert(e->core == c); - } else { - put = 1; + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); + } else { e = pa_xmalloc(sizeof(struct pa_scache_entry)); if (!pa_namereg_register(c, name, PA_NAMEREG_SAMPLE, e, 1)) { pa_xfree(e); - return -1; + return NULL; } - + e->name = pa_xstrdup(name); e->core = c; + + if (!c->scache) { + c->scache = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + assert(c->scache); + } + + pa_idxset_put(c->scache, e, &e->index); + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_NEW, e->index); } e->volume = PA_VOLUME_NORM; - e->auto_unload = auto_unload; e->last_used_time = 0; + e->memchunk.memblock = NULL; + e->memchunk.index = e->memchunk.length = 0; + e->filename = NULL; + e->lazy = 0; + e->last_used_time = 0; + + memset(&e->sample_spec, 0, sizeof(struct pa_sample_spec)); + + return e; +} + +int pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index) { + struct pa_scache_entry *e; + assert(c && name); + + if (!(e = scache_add_item(c, name))) + return -1; if (ss) e->sample_spec = *ss; - else - memset(&e->sample_spec, 0, sizeof(struct pa_sample_spec)); if (chunk) { e->memchunk = *chunk; pa_memblock_ref(e->memchunk.memblock); - } else { - e->memchunk.memblock = NULL; - e->memchunk.index = e->memchunk.length = 0; } - if (put) { - if (!c->scache) { - c->scache = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - assert(c->scache); - } - - pa_idxset_put(c->scache, e, &e->index); - - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_NEW, e->index); - } else - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); - if (index) *index = e->index; + return 0; +} + +int pa_scache_add_file(struct pa_core *c, const char *name, const char *filename, uint32_t *index) { + struct pa_sample_spec ss; + struct pa_memchunk chunk; + int r; + + if (pa_sound_file_load(filename, &ss, &chunk, c->memblock_stat) < 0) + return -1; + + r = pa_scache_add_item(c, name, &ss, &chunk, index); + pa_memblock_unref(chunk.memblock); + return r; +} + +int pa_scache_add_file_lazy(struct pa_core *c, const char *name, const char *filename, uint32_t *index) { + struct pa_scache_entry *e; + assert(c && name); + + if (!(e = scache_add_item(c, name))) + return -1; + + e->lazy = 1; + e->filename = pa_xstrdup(filename); + if (!c->scache_auto_unload_event) { struct timeval ntv; gettimeofday(&ntv, NULL); ntv.tv_sec += UNLOAD_POLL_TIME; c->scache_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); } - + return 0; } @@ -166,13 +203,17 @@ int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sin if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1))) return -1; + if (e->lazy && !e->memchunk.memblock) + if (pa_sound_file_load(e->filename, &e->sample_spec, &e->memchunk, c->memblock_stat) < 0) + return -1; + if (!e->memchunk.memblock) return -1; if (pa_play_memchunk(sink, name, &e->sample_spec, &e->memchunk, pa_volume_multiply(volume, e->volume)) < 0) return -1; - if (e->auto_unload) + if (e->lazy) time(&e->last_used_time); return 0; @@ -200,42 +241,40 @@ uint32_t pa_scache_get_id_by_name(struct pa_core *c, const char *name) { uint32_t pa_scache_total_size(struct pa_core *c) { struct pa_scache_entry *e; - uint32_t index; - uint32_t sum = 0; + uint32_t index, sum = 0; + assert(c); - if (!c->scache) + if (!c->scache || !pa_idxset_ncontents(c->scache)) return 0; for (e = pa_idxset_first(c->scache, &index); e; e = pa_idxset_next(c->scache, &index)) - sum += e->memchunk.length; + if (e->memchunk.memblock) + sum += e->memchunk.length; return sum; } -static int unload_func(void *p, uint32_t index, int *del, void *userdata) { - struct pa_scache_entry *e = p; - time_t *now = userdata; - assert(e); - - if (!e->auto_unload) - return 0; - - if (e->last_used_time + e->core->scache_idle_time > *now) - return 0; - - free_entry(e); - *del = 1; - return 0; -} - void pa_scache_unload_unused(struct pa_core *c) { + struct pa_scache_entry *e; time_t now; + uint32_t index; assert(c); - if (!c->scache) + if (!c->scache || !pa_idxset_ncontents(c->scache)) return; time(&now); - pa_idxset_foreach(c->scache, unload_func, &now); + for (e = pa_idxset_first(c->scache, &index); e; e = pa_idxset_next(c->scache, &index)) { + + if (!e->lazy || !e->memchunk.memblock) + continue; + + if (e->last_used_time + c->scache_idle_time > now) + continue; + + pa_memblock_unref(e->memchunk.memblock); + e->memchunk.memblock = NULL; + e->memchunk.index = e->memchunk.length = 0; + } } diff --git a/polyp/scache.h b/polyp/scache.h index e0574409..4fb3dc8e 100644 --- a/polyp/scache.h +++ b/polyp/scache.h @@ -30,15 +30,20 @@ struct pa_scache_entry { struct pa_core *core; uint32_t index; char *name; + uint32_t volume; struct pa_sample_spec sample_spec; struct pa_memchunk memchunk; - int auto_unload; + char *filename; + + int lazy; time_t last_used_time; }; -int pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index, int auto_unload); +int pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index); +int pa_scache_add_file(struct pa_core *c, const char *name, const char *filename, uint32_t *index); +int pa_scache_add_file_lazy(struct pa_core *c, const char *name, const char *filename, uint32_t *index); int pa_scache_remove_item(struct pa_core *c, const char *name); int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sink, uint32_t volume); -- cgit From f5d47a293aa32a8273ef02c597cb263527726465 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Sep 2004 19:16:57 +0000 Subject: work around C99/GCC incompatibility native protocol: add "local" field to pa_context add volume paramter to pa_stream_connect_playback add support for renaming streams/clients support lazy samples add functions to kill clients/source inputs/sink outputs add functions for loading/unloading modules add autoload management API git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@204 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 16 +-- polyp/client.c | 2 +- polyp/client.h | 2 +- polyp/native-common.h | 13 +- polyp/pacat-simple.c | 2 +- polyp/pacat.c | 2 +- polyp/parec-simple.c | 2 +- polyp/polyplib-context.c | 45 ++++++- polyp/polyplib-context.h | 6 + polyp/polyplib-def.h | 1 + polyp/polyplib-internal.h | 2 + polyp/polyplib-introspect.c | 197 +++++++++++++++++++++++++++- polyp/polyplib-introspect.h | 46 ++++++- polyp/polyplib-simple.c | 3 +- polyp/polyplib-simple.h | 3 +- polyp/polyplib-stream.c | 32 ++++- polyp/polyplib-stream.h | 5 +- polyp/protocol-esound.c | 4 +- polyp/protocol-native.c | 313 +++++++++++++++++++++++++++++++++++++++++++- polyp/scache.c | 8 +- polyp/sink-input.c | 2 + polyp/source-output.c | 2 + polyp/strbuf.c | 12 ++ 23 files changed, 680 insertions(+), 40 deletions(-) diff --git a/doc/todo b/doc/todo index 91a2f92f..22fa4421 100644 --- a/doc/todo +++ b/doc/todo @@ -1,26 +1,20 @@ *** $Id$ *** *** 0.5 *** -- make mcalign merge chunks -- native library/protocol: - module load/unload - kill client/... - autoload management - rename streams/contexts - more complete pactl -- option to use default fragment size on alsa drivers -- merge pa_context_connect_* - input latency - fix tcp/native -- add volume to create_stream command in native protocol -- udp based protocol +- paman: add support for killing sink inputs, source outputs, clients - add client config file -- beefup sample_info stuff in native protocol +- remove autospawn stuff in conf.c *** 0.6 **** - per-channel volume - unix socket directories include user name - add sample directory +- udp based protocol +- make mcalign merge chunks +- option to use default fragment size on alsa drivers ** later *** - xmlrpc/http diff --git a/polyp/client.c b/polyp/client.c index a544b4fe..7aee2edd 100644 --- a/polyp/client.c +++ b/polyp/client.c @@ -82,7 +82,7 @@ void pa_client_kill(struct pa_client *c) { c->kill(c); } -void pa_client_rename(struct pa_client *c, const char *name) { +void pa_client_set_name(struct pa_client *c, const char *name) { assert(c); pa_xfree(c->name); c->name = pa_xstrdup(name); diff --git a/polyp/client.h b/polyp/client.h index c926208e..25a4b166 100644 --- a/polyp/client.h +++ b/polyp/client.h @@ -46,6 +46,6 @@ void pa_client_free(struct pa_client *c); * request destruction of the client */ void pa_client_kill(struct pa_client *c); -void pa_client_rename(struct pa_client *c, const char *name); +void pa_client_set_name(struct pa_client *c, const char *name); #endif diff --git a/polyp/native-common.h b/polyp/native-common.h index c5192cec..45e0b1d3 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -38,7 +38,7 @@ enum { PA_COMMAND_EXIT, PA_COMMAND_REQUEST, PA_COMMAND_AUTH, - PA_COMMAND_SET_NAME, + PA_COMMAND_SET_CLIENT_NAME, PA_COMMAND_LOOKUP_SINK, PA_COMMAND_LOOKUP_SOURCE, PA_COMMAND_DRAIN_PLAYBACK_STREAM, @@ -75,6 +75,17 @@ enum { PA_COMMAND_TRIGGER_PLAYBACK_STREAM, PA_COMMAND_SET_DEFAULT_SINK, PA_COMMAND_SET_DEFAULT_SOURCE, + PA_COMMAND_SET_PLAYBACK_STREAM_NAME, + PA_COMMAND_SET_RECORD_STREAM_NAME, + PA_COMMAND_KILL_CLIENT, + PA_COMMAND_KILL_SINK_INPUT, + PA_COMMAND_KILL_SOURCE_OUTPUT, + PA_COMMAND_LOAD_MODULE, + PA_COMMAND_UNLOAD_MODULE, + PA_COMMAND_ADD_AUTOLOAD, + PA_COMMAND_REMOVE_AUTOLOAD, + PA_COMMAND_GET_AUTOLOAD_INFO, + PA_COMMAND_GET_AUTOLOAD_INFO_LIST, PA_COMMAND_MAX }; diff --git a/polyp/pacat-simple.c b/polyp/pacat-simple.c index 956728fb..2b8ffa08 100644 --- a/polyp/pacat-simple.c +++ b/polyp/pacat-simple.c @@ -47,7 +47,7 @@ int main(int argc, char*argv[]) { int error; /* Create a new playback stream */ - if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, &error))) { + if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, PA_VOLUME_NORM, &error))) { fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); goto finish; } diff --git a/polyp/pacat.c b/polyp/pacat.c index f4597714..cc7d55f4 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -156,7 +156,7 @@ static void context_state_callback(struct pa_context *c, void *userdata) { pa_stream_set_read_callback(stream, stream_read_callback, NULL); if (mode == PLAYBACK) - pa_stream_connect_playback(stream, NULL, NULL); + pa_stream_connect_playback(stream, NULL, NULL, PA_VOLUME_NORM); else pa_stream_connect_record(stream, NULL, NULL); diff --git a/polyp/parec-simple.c b/polyp/parec-simple.c index 7e0931ae..cae6ff92 100644 --- a/polyp/parec-simple.c +++ b/polyp/parec-simple.c @@ -66,7 +66,7 @@ int main(int argc, char*argv[]) { int error; /* Create the recording stream */ - if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, &error))) { + if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, 0, &error))) { fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); goto finish; } diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 7fef6b12..64f9074c 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -84,6 +84,7 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * c->subscribe_userdata = NULL; c->memblock_stat = pa_memblock_stat_new(); + c->local = -1; pa_check_signal_is_blocked(SIGPIPE); return c; @@ -252,7 +253,7 @@ static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, u struct pa_tagstruct *t; t = pa_tagstruct_new(NULL, 0); assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); + pa_tagstruct_putu32(t, PA_COMMAND_SET_CLIENT_NAME); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_puts(t, c->name); pa_pstream_send_tagstruct(c->pstream, t); @@ -383,6 +384,8 @@ static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api int fds[2] = { -1, -1} ; struct pa_iochannel *io; + pa_context_ref(c); + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { pa_log(__FILE__": socketpair() failed: %s\n", strerror(errno)); pa_context_fail(c, PA_ERROR_INTERNAL); @@ -417,7 +420,7 @@ static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api putenv(t); snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]); - execl(p, p, t, NULL); + execl(p, p, "--daemonize=yes", "--log-target=syslog", t, NULL); exit(1); } @@ -439,9 +442,14 @@ static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api } close(fds[1]); + + c->local = 1; io = pa_iochannel_new(c->mainloop, fds[0], fds[0]); setup_context(c, io); + + pa_context_unref(c); + return 0; fail: @@ -450,11 +458,11 @@ fail: if (fds[1] != -1) close(fds[1]); + pa_context_unref(c); + return -1; } - - int pa_context_connect(struct pa_context *c, const char *server, int spawn, const struct pa_spawn_api *api) { int r = -1; assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED); @@ -483,6 +491,8 @@ int pa_context_connect(struct pa_context *c, const char *server, int spawn, cons pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); goto finish; } + + c->local = 1; } else { struct sockaddr* sa; size_t sa_len; @@ -499,6 +509,8 @@ int pa_context_connect(struct pa_context *c, const char *server, int spawn, cons pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); goto finish; } + + c->local = 0; } pa_socket_client_set_callback(c->client, on_connection, c); @@ -702,3 +714,28 @@ struct pa_operation* pa_context_set_default_source(struct pa_context *c, const c return pa_operation_ref(o); } + +int pa_context_is_local(struct pa_context *c) { + assert(c); + return c->local; +} + +struct pa_operation* pa_context_set_name(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata) { + struct pa_tagstruct *t; + struct pa_operation *o; + uint32_t tag; + assert(c && name && cb); + + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_CLIENT_NAME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h index 84e47b64..548a39dd 100644 --- a/polyp/polyplib-context.h +++ b/polyp/polyplib-context.h @@ -99,6 +99,12 @@ struct pa_operation* pa_context_set_default_sink(struct pa_context *c, const cha /** Set the name of the default source. \since 0.4 */ struct pa_operation* pa_context_set_default_source(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata); +/** Returns 1 when the connection is to a local daemon. Returns negative when no connection has been made yet. \since 0.5 */ +int pa_context_is_local(struct pa_context *c); + +/** Set a different application name for context on the server. \since 0.5 */ +struct pa_operation* pa_context_set_name(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata); + PA_C_DECL_END #endif diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index 2aa33338..9bba3f32 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -94,6 +94,7 @@ enum { PA_ERROR_CONNECTIONTERMINATED, /**< Connection terminated */ PA_ERROR_KILLED, /**< Entity killed */ PA_ERROR_INVALIDSERVER, /**< Invalid server */ + PA_ERROR_INITFAILED, /**< Module initialization failed */ PA_ERROR_MAX /**< Not really an error but the first invalid error code */ }; diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 98fd7924..4c44ee98 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -78,6 +78,8 @@ struct pa_context { void *subscribe_userdata; struct pa_memblock_stat *memblock_stat; + + int local; }; struct pa_stream { diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index e742c2db..919adb9c 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -650,7 +650,9 @@ static void context_get_sample_info_callback(struct pa_pdispatch *pd, uint32_t c pa_tagstruct_getu32(t, &i.volume) < 0 || pa_tagstruct_get_usec(t, &i.duration) < 0 || pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.bytes) < 0) { + pa_tagstruct_getu32(t, &i.bytes) < 0 || + pa_tagstruct_get_boolean(t, &i.lazy) < 0 || + pa_tagstruct_gets(t, &i.filename) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } @@ -717,3 +719,196 @@ struct pa_operation* pa_context_get_sample_info_by_index(struct pa_context *c, u struct pa_operation* pa_context_get_sample_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata) { return pa_context_send_simple_command(c, PA_COMMAND_GET_SAMPLE_INFO_LIST, context_get_sample_info_callback, cb, userdata); } + +static struct pa_operation* command_kill(struct pa_context *c, uint32_t command, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_operation *o; + struct pa_tagstruct *t; + uint32_t tag; + assert(c && index != PA_INVALID_INDEX); + + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, command); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +struct pa_operation* pa_context_kill_client(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + return command_kill(c, PA_COMMAND_KILL_CLIENT, index, cb, userdata); +} + +struct pa_operation* pa_context_kill_sink_input(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + return command_kill(c, PA_COMMAND_KILL_SINK_INPUT, index, cb, userdata); +} + +struct pa_operation* pa_context_kill_source_output(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + return command_kill(c, PA_COMMAND_KILL_SOURCE_OUTPUT, index, cb, userdata); +} + +static void load_module_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + uint32_t index = -1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + } else if (pa_tagstruct_getu32(t, &index) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(struct pa_context *c, uint32_t index, void *userdata) = o->callback; + cb(o->context, index, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +struct pa_operation* pa_context_load_module(struct pa_context *c, const char*name, const char *argument, void (*cb)(struct pa_context *c, uint32_t index, void *userdata), void *userdata) { + struct pa_operation *o; + struct pa_tagstruct *t; + uint32_t tag; + assert(c && name && argument); + + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_LOAD_MODULE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_puts(t, argument); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, load_module_callback, o); + + return pa_operation_ref(o); +} + +struct pa_operation* pa_context_unload_module(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + return command_kill(c, PA_COMMAND_UNLOAD_MODULE, index, cb, userdata); +} + +/*** Autoload stuff ***/ + +static void context_get_autoload_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + struct pa_autoload_info i; + + if (pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_getu32(t, &i.type) < 0 || + pa_tagstruct_gets(t, &i.module) < 0 || + pa_tagstruct_gets(t, &i.argument) < 0) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_autoload_info*i, int eof, void *userdata) = o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_autoload_info*i, int eof, void *userdata) = o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +struct pa_operation* pa_context_get_autoload_info(struct pa_context *c, const char *name, enum pa_autoload_type type, void (*cb)(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + struct pa_operation *o; + uint32_t tag; + assert(c && cb && name); + + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_AUTOLOAD_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_putu32(t, type); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, o); + + return pa_operation_ref(o); +} + +struct pa_operation* pa_context_get_autoload_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, context_get_autoload_info_callback, cb, userdata); +} + +struct pa_operation* pa_context_add_autoload(struct pa_context *c, const char *name, enum pa_autoload_type type, const char *module, const char*argument, void (*cb)(struct pa_context *c, int success, void *userdata), void* userdata) { + struct pa_operation *o; + struct pa_tagstruct *t; + uint32_t tag; + assert(c && name && module && argument); + + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_ADD_AUTOLOAD); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_putu32(t, type); + pa_tagstruct_puts(t, module); + pa_tagstruct_puts(t, argument); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +struct pa_operation* pa_context_remove_autoload(struct pa_context *c, const char *name, enum pa_autoload_type type, void (*cb)(struct pa_context *c, int success, void *userdata), void* userdata) { + struct pa_operation *o; + struct pa_tagstruct *t; + uint32_t tag; + assert(c && name); + + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_AUTOLOAD); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_putu32(t, type); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index 3da71b80..51210457 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -38,8 +38,7 @@ * and the structures themselves point to internal memory that may not * be modified. That memory is only valid during the call to the * callback function. A deep copy is required if you need this data - * outside the callback functions. An error is signalled by a call to - * the callback function with i=NULL and is_last=0. + * outside the callback functions. An error is signalled by a call to * the callback function with i=NULL and is_last=0. * * When using the routines that ask fo a single entry only, a callback * with the same signature is used. However, no finishing call to the @@ -196,6 +195,8 @@ struct pa_sample_info { struct pa_sample_spec sample_spec; /**< Sample specification of the sampel */ pa_usec_t duration; /**< Duration of this entry */ uint32_t bytes; /**< Length of this sample in bytes. \since 0.4 */ + int lazy; /**< Non-zero when this is a lazy cache entry. \since 0.5 */ + const char *filename; /**< In case this is a lazy cache entry, the filename for the sound file to be loaded on demand. \since 0.5 */ }; /** Get information about a sample by its name */ @@ -207,6 +208,47 @@ struct pa_operation* pa_context_get_sample_info_by_index(struct pa_context *c, u /** Get the complete list of samples stored in the daemon. */ struct pa_operation* pa_context_get_sample_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata); +/** Kill a client. \since 0.5 */ +struct pa_operation* pa_context_kill_client(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +/** Kill a sink input. \since 0.5 */ +struct pa_operation* pa_context_kill_sink_input(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +/** Kill a source output. \since 0.5 */ +struct pa_operation* pa_context_kill_source_output(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +/** Load a module. \since 0.5 */ +struct pa_operation* pa_context_load_module(struct pa_context *c, const char*name, const char *argument, void (*cb)(struct pa_context *c, uint32_t index, void *userdata), void *userdata); + +/** Unload a module. \since 0.5 */ +struct pa_operation* pa_context_unload_module(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); + +/** Type of an autoload entry. \since 0.5 */ +enum pa_autoload_type { + PA_AUTOLOAD_SINK = 0, + PA_AUTOLOAD_SOURCE = 1, +}; + +/** Stores information about autoload entries. \since 0.5 */ +struct pa_autoload_info { + const char *name; /**< Name of the sink or source */ + enum pa_autoload_type type; /**< Type of the autoload entry */ + const char *module; /**< Module name to load */ + const char *argument; /**< Argument string for module */ +}; + +/** Get info about a specific autoload entry. \since 0.5 */ +struct pa_operation* pa_context_get_autoload_info(struct pa_context *c, const char *name, enum pa_autoload_type type, void (*cb)(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata), void *userdata); + +/** Get the complete list of autoload entries. \since 0.5 */ +struct pa_operation* pa_context_get_autoload_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata), void *userdata); + +/** Add a new autoload entry. \since 0.5 */ +struct pa_operation* pa_context_add_autoload(struct pa_context *c, const char *name, enum pa_autoload_type type, const char *module, const char*argument, void (*cb)(struct pa_context *c, int success, void *userdata), void* userdata); + +/** Remove an autoload entry. \since 0.5 */ +struct pa_operation* pa_context_remove_autoload(struct pa_context *c, const char *name, enum pa_autoload_type type, void (*cb)(struct pa_context *c, int success, void *userdata), void* userdata); + PA_C_DECL_END #endif diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c index 36e6e757..5cf52d06 100644 --- a/polyp/polyplib-simple.c +++ b/polyp/polyplib-simple.c @@ -110,6 +110,7 @@ struct pa_simple* pa_simple_new( const char *stream_name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, + pa_volume_t volume, int *perror) { struct pa_simple *p; @@ -142,7 +143,7 @@ struct pa_simple* pa_simple_new( goto fail; if (dir == PA_STREAM_PLAYBACK) - pa_stream_connect_playback(p->stream, dev, attr); + pa_stream_connect_playback(p->stream, dev, attr, volume); else pa_stream_connect_record(p->stream, dev, attr); diff --git a/polyp/polyplib-simple.h b/polyp/polyplib-simple.h index b37bdec6..1bd46dc6 100644 --- a/polyp/polyplib-simple.h +++ b/polyp/polyplib-simple.h @@ -54,7 +54,8 @@ struct pa_simple* pa_simple_new( const char *stream_name, /**< A descriptive name for this client (application name, song title, ...) */ const struct pa_sample_spec *ss, /**< The sample type to use */ const struct pa_buffer_attr *attr, /**< Buffering attributes, or NULL for default */ - int *error /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */ + pa_volume_t volume, /**< Initial volume. Only for playback streams. \since 0.5 */ + int *error /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */ ); /** Close and free the connection to the server. The connection objects becomes invalid when this is called. */ diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index b40b7f69..89a8d338 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -211,7 +211,7 @@ finish: pa_stream_unref(s); } -static void create_stream(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr) { +static void create_stream(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, pa_volume_t volume) { struct pa_tagstruct *t; uint32_t tag; assert(s && s->ref >= 1 && s->state == PA_STREAM_DISCONNECTED); @@ -251,6 +251,7 @@ static void create_stream(struct pa_stream *s, const char *dev, const struct pa_ pa_tagstruct_putu32(t, s->buffer_attr.tlength); pa_tagstruct_putu32(t, s->buffer_attr.prebuf); pa_tagstruct_putu32(t, s->buffer_attr.minreq); + pa_tagstruct_putu32(t, volume); } else pa_tagstruct_putu32(t, s->buffer_attr.fragsize); @@ -260,16 +261,16 @@ static void create_stream(struct pa_stream *s, const char *dev, const struct pa_ pa_stream_unref(s); } -void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr) { +void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, pa_volume_t volume) { assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); s->direction = PA_STREAM_PLAYBACK; - create_stream(s, dev, attr); + create_stream(s, dev, attr, volume); } void pa_stream_connect_record(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr) { assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); s->direction = PA_STREAM_RECORD; - create_stream(s, dev, attr); + create_stream(s, dev, attr, 0); } void pa_stream_write(struct pa_stream *s, const void *data, size_t length, void (*free_cb)(void *p), size_t delta) { @@ -536,3 +537,26 @@ struct pa_operation* pa_stream_flush(struct pa_stream *s, void (*cb)(struct pa_s struct pa_operation* pa_stream_trigger(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { return pa_stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata); } + +struct pa_operation* pa_stream_set_name(struct pa_stream *s, const char *name, void(*cb)(struct pa_stream*c, int success, void *userdata), void *userdata) { + struct pa_operation *o; + struct pa_tagstruct *t; + uint32_t tag; + assert(s && s->ref >= 1 && s->state == PA_STREAM_READY && name && s->direction != PA_STREAM_UPLOAD); + + o = pa_operation_new(s->context, s); + assert(o); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, s->direction == PA_STREAM_RECORD ? PA_COMMAND_SET_RECORD_STREAM_NAME : PA_COMMAND_SET_PLAYBACK_STREAM_NAME); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); + + return pa_operation_ref(o); +} diff --git a/polyp/polyplib-stream.h b/polyp/polyplib-stream.h index d74c3cb2..257f2b99 100644 --- a/polyp/polyplib-stream.h +++ b/polyp/polyplib-stream.h @@ -57,7 +57,7 @@ struct pa_context* pa_stream_get_context(struct pa_stream *p); uint32_t pa_stream_get_index(struct pa_stream *s); /** Connect the stream to a sink */ -void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr); +void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, pa_volume_t volume); /** Connect the stream to a source */ void pa_stream_connect_record(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr); @@ -126,6 +126,9 @@ struct pa_operation* pa_stream_flush(struct pa_stream *s, void (*cb)(struct pa_s * 0.3 */ struct pa_operation* pa_stream_trigger(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata); +/** Rename the stream. \since 0.5 */ +struct pa_operation* pa_stream_set_name(struct pa_stream *s, const char *name, void(*cb)(struct pa_stream*c, int success, void *userdata), void *userdata); + PA_C_DECL_END #endif diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 8ec48a34..5abe474d 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -293,7 +293,7 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons strncpy(name, (char*) data + sizeof(int)*2, sizeof(name)); name[sizeof(name)-1] = 0; - pa_client_rename(c->client, name); + pa_client_set_name(c->client, name); assert(!c->input_memblockq); @@ -357,7 +357,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co strncpy(name, (char*) data + sizeof(int)*2, sizeof(name)); name[sizeof(name)-1] = 0; - pa_client_rename(c->client, name); + pa_client_set_name(c->client, name); assert(!c->output_memblockq); diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 55b98fd4..be7b76f6 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -45,6 +45,7 @@ #include "util.h" #include "subscribe.h" #include "log.h" +#include "autoload.h" struct connection; struct pa_protocol_native; @@ -123,7 +124,7 @@ static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t comm static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_delete_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_set_client_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); @@ -139,6 +140,14 @@ static void command_set_volume(struct pa_pdispatch *pd, uint32_t command, uint32 static void command_cork_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_flush_or_trigger_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_set_default_sink_or_source(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_set_stream_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_kill(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_load_module(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_unload_module(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_add_autoload(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_remove_autoload(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_get_autoload_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_get_autoload_info_list(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = { NULL }, @@ -152,7 +161,7 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_AUTH] = { command_auth }, [PA_COMMAND_REQUEST] = { NULL }, [PA_COMMAND_EXIT] = { command_exit }, - [PA_COMMAND_SET_NAME] = { command_set_name }, + [PA_COMMAND_SET_CLIENT_NAME] = { command_set_client_name }, [PA_COMMAND_LOOKUP_SINK] = { command_lookup }, [PA_COMMAND_LOOKUP_SOURCE] = { command_lookup }, [PA_COMMAND_STAT] = { command_stat }, @@ -185,6 +194,17 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = { command_flush_or_trigger_playback_stream }, [PA_COMMAND_SET_DEFAULT_SINK] = { command_set_default_sink_or_source }, [PA_COMMAND_SET_DEFAULT_SOURCE] = { command_set_default_sink_or_source }, + [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = { command_set_stream_name }, + [PA_COMMAND_SET_RECORD_STREAM_NAME] = { command_set_stream_name }, + [PA_COMMAND_KILL_CLIENT] = { command_kill }, + [PA_COMMAND_KILL_SINK_INPUT] = { command_kill }, + [PA_COMMAND_KILL_SOURCE_OUTPUT] = { command_kill }, + [PA_COMMAND_LOAD_MODULE] = { command_load_module }, + [PA_COMMAND_UNLOAD_MODULE] = { command_unload_module }, + [PA_COMMAND_GET_AUTOLOAD_INFO] = { command_get_autoload_info }, + [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = { command_get_autoload_info_list }, + [PA_COMMAND_ADD_AUTOLOAD] = { command_add_autoload }, + [PA_COMMAND_REMOVE_AUTOLOAD] = { command_remove_autoload }, }; /* structure management */ @@ -265,7 +285,8 @@ static struct playback_stream* playback_stream_new(struct connection *c, struct size_t maxlength, size_t tlength, size_t prebuf, - size_t minreq) { + size_t minreq, + pa_volume_t volume) { struct playback_stream *s; struct pa_sink_input *sink_input; assert(c && sink && ss && name && maxlength); @@ -291,6 +312,8 @@ static struct playback_stream* playback_stream_new(struct connection *c, struct s->requested_bytes = 0; s->drain_request = 0; + + s->sink_input->volume = volume; pa_idxset_put(c->output_streams, s, &s->index); return s; @@ -501,6 +524,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com struct pa_sample_spec ss; struct pa_tagstruct *reply; struct pa_sink *sink; + pa_volume_t volume; assert(c && t && c->protocol && c->protocol->core); if (pa_tagstruct_gets(t, &name) < 0 || @@ -511,6 +535,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com pa_tagstruct_getu32(t, &tlength) < 0 || pa_tagstruct_getu32(t, &prebuf) < 0 || pa_tagstruct_getu32(t, &minreq) < 0 || + pa_tagstruct_getu32(t, &volume) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -531,7 +556,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com return; } - if (!(s = playback_stream_new(c, sink, &ss, name, maxlength, tlength, prebuf, minreq))) { + if (!(s = playback_stream_new(c, sink, &ss, name, maxlength, tlength, prebuf, minreq, volume))) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); return; } @@ -691,7 +716,7 @@ static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag return; } -static void command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_set_client_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; const char *name; assert(c && t); @@ -702,7 +727,7 @@ static void command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t return; } - pa_client_rename(c->client, name); + pa_client_set_name(c->client, name); pa_pstream_send_simple_ack(c->pstream, tag); return; } @@ -1061,6 +1086,8 @@ static void scache_fill_tagstruct(struct pa_tagstruct *t, struct pa_scache_entry pa_tagstruct_put_usec(t, pa_bytes_to_usec(e->memchunk.length, &e->sample_spec)); pa_tagstruct_put_sample_spec(t, &e->sample_spec); pa_tagstruct_putu32(t, e->memchunk.length); + pa_tagstruct_put_boolean(t, e->lazy); + pa_tagstruct_puts(t, e->filename); } static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { @@ -1415,6 +1442,280 @@ static void command_set_default_sink_or_source(struct pa_pdispatch *pd, uint32_t pa_pstream_send_simple_ack(c->pstream, tag); } +static void command_set_stream_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t index; + const char *name; + assert(c && t); + + if (pa_tagstruct_getu32(t, &index) < 0 || + pa_tagstruct_gets(t, &name) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) { + struct playback_stream *s; + + if (!(s = pa_idxset_get_by_index(c->output_streams, index)) || s->type != PLAYBACK_STREAM) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_sink_input_set_name(s->sink_input, name); + + } else { + struct record_stream *s; + + if (!(s = pa_idxset_get_by_index(c->record_streams, index))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_source_output_set_name(s->source_output, name); + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_kill(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t index; + assert(c && t); + + if (pa_tagstruct_getu32(t, &index) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (command == PA_COMMAND_KILL_CLIENT) { + struct pa_client *client; + + if (!(client = pa_idxset_get_by_index(c->protocol->core->clients, index))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_client_kill(client); + } else if (command == PA_COMMAND_KILL_SINK_INPUT) { + struct pa_sink_input *s; + + if (!(s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, index))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_sink_input_kill(s); + } else { + struct pa_source_output *s; + + assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT); + + if (!(s = pa_idxset_get_by_index(c->protocol->core->source_outputs, index))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_source_output_kill(s); + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_load_module(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + struct pa_module *m; + const char *name, *argument; + struct pa_tagstruct *reply; + assert(c && t); + + if (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_gets(t, &argument) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(m = pa_module_load(c->protocol->core, name, argument))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_INITFAILED); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, m->index); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_unload_module(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t index; + struct pa_module *m; + assert(c && t); + + if (pa_tagstruct_getu32(t, &index) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(m = pa_idxset_get_by_index(c->protocol->core->modules, index))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_module_unload_request(m); + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_add_autoload(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const char *name, *module, *argument; + uint32_t type; + assert(c && t); + + if (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_getu32(t, &type) < 0 || type > 1 || + pa_tagstruct_gets(t, &module) < 0 || + pa_tagstruct_gets(t, &argument) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (pa_autoload_add(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, module, argument) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + return; + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_remove_autoload(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const char *name; + uint32_t type; + assert(c && t); + + if (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_getu32(t, &type) < 0 || type > 1 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (pa_autoload_remove(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void autoload_fill_tagstruct(struct pa_tagstruct *t, struct pa_autoload_entry *e) { + assert(t && e); + pa_tagstruct_puts(t, e->name); + pa_tagstruct_putu32(t, e->type == PA_NAMEREG_SINK ? 0 : 1); + pa_tagstruct_puts(t, e->module); + pa_tagstruct_puts(t, e->argument); +} + +static void command_get_autoload_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + struct pa_autoload_entry *a = NULL; + uint32_t type; + const char *name; + struct pa_tagstruct *reply; + assert(c && t); + + if (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_getu32(t, &type) < 0 || type > 1 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!c->protocol->core->autoload_hashmap || !(a = pa_hashmap_get(c->protocol->core->autoload_hashmap, name)) || (a->type == PA_NAMEREG_SINK && type != 0) || (a->type == PA_NAMEREG_SOURCE && type != 1)) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + autoload_fill_tagstruct(reply, a); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_get_autoload_info_list(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + struct pa_tagstruct *reply; + assert(c && t); + + if (!pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + + if (c->protocol->core->autoload_hashmap) { + struct pa_autoload_entry *a; + void *state = NULL; + + while ((a = pa_hashmap_iterate(c->protocol->core->autoload_hashmap, &state))) + autoload_fill_tagstruct(reply, a); + } + + pa_pstream_send_tagstruct(c->pstream, reply); +} + /*** pstream callbacks ***/ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { diff --git a/polyp/scache.c b/polyp/scache.c index 026f4b17..963a4f86 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -141,6 +141,7 @@ int pa_scache_add_file(struct pa_core *c, const char *name, const char *filename r = pa_scache_add_item(c, name, &ss, &chunk, index); pa_memblock_unref(chunk.memblock); + return r; } @@ -203,9 +204,12 @@ int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sin if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1))) return -1; - if (e->lazy && !e->memchunk.memblock) + if (e->lazy && !e->memchunk.memblock) { if (pa_sound_file_load(e->filename, &e->sample_spec, &e->memchunk, c->memblock_stat) < 0) return -1; + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); + } if (!e->memchunk.memblock) return -1; @@ -276,5 +280,7 @@ void pa_scache_unload_unused(struct pa_core *c) { pa_memblock_unref(e->memchunk.memblock); e->memchunk.memblock = NULL; e->memchunk.index = e->memchunk.length = 0; + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); } } diff --git a/polyp/sink-input.c b/polyp/sink-input.c index e2b9e0cf..2541c821 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -258,4 +258,6 @@ void pa_sink_input_set_name(struct pa_sink_input *i, const char *name) { pa_xfree(i->name); i->name = pa_xstrdup(name); + + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); } diff --git a/polyp/source-output.c b/polyp/source-output.c index 3abf9c18..2566ec87 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -146,4 +146,6 @@ void pa_source_output_set_name(struct pa_source_output *o, const char *name) { assert(o && o->ref >= 1); pa_xfree(o->name); o->name = pa_xstrdup(name); + + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); } diff --git a/polyp/strbuf.c b/polyp/strbuf.c index 169604e8..44cae2ce 100644 --- a/polyp/strbuf.c +++ b/polyp/strbuf.c @@ -33,10 +33,22 @@ #include "strbuf.h" +#ifdef __STDC_VERSION__ +#if __STDC_VERSION__ >= 199901L +#ifndef STDC99 +#define STDC99 +#endif +#endif +#endif + struct chunk { struct chunk *next; size_t length; +#ifdef STDC99 char text[]; +#else + char text[0]; +#endif }; struct pa_strbuf { -- cgit From f9e2058820c2a51994708ad11d1ed8e09b12b8b1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Sep 2004 00:05:56 +0000 Subject: add input latency measurement add GETOSPACE support to module-oss git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@205 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 4 +- polyp/cli-text.c | 3 +- polyp/iochannel.c | 11 ++++ polyp/iochannel.h | 3 + polyp/module-alsa-source.c | 15 +++++ polyp/module-oss.c | 141 ++++++++++++++++++++++++++++++++------------ polyp/native-common.h | 1 + polyp/pacat.c | 18 +++--- polyp/polyplib-def.h | 28 +++++---- polyp/polyplib-introspect.c | 8 ++- polyp/polyplib-introspect.h | 5 +- polyp/polyplib-stream.c | 11 +++- polyp/protocol-esound.c | 9 ++- polyp/protocol-native.c | 62 ++++++++++++++++++- polyp/protocol-simple.c | 7 +++ polyp/sink.c | 5 +- polyp/source-output.c | 11 ++++ polyp/source-output.h | 4 ++ polyp/source.c | 11 ++++ polyp/source.h | 3 + 20 files changed, 292 insertions(+), 68 deletions(-) diff --git a/doc/todo b/doc/todo index 22fa4421..675e8ca3 100644 --- a/doc/todo +++ b/doc/todo @@ -2,7 +2,6 @@ *** 0.5 *** - more complete pactl -- input latency - fix tcp/native - paman: add support for killing sink inputs, source outputs, clients - add client config file @@ -15,6 +14,7 @@ - udp based protocol - make mcalign merge chunks - option to use default fragment size on alsa drivers +- improve module-oss-mmap latency measurement ** later *** - xmlrpc/http @@ -27,7 +27,7 @@ backends for: - portaudio +- alsa-lib - sdl - gstreamer (semi-done) -- alsa-lib - OSS (esddsp style) diff --git a/polyp/cli-text.c b/polyp/cli-text.c index 0915be8b..9932e568 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -125,10 +125,11 @@ char *pa_source_list_to_string(struct pa_core *c) { for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) { char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec); - pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\tsample_spec: <%s>\n", + pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n", c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ', source->index, source->name, + (float) pa_source_get_latency(source), ss); if (source->monitor_of) diff --git a/polyp/iochannel.c b/polyp/iochannel.c index 1aa70b93..72bdac20 100644 --- a/polyp/iochannel.c +++ b/polyp/iochannel.c @@ -229,3 +229,14 @@ int pa_iochannel_socket_set_sndbuf(struct pa_iochannel *io, size_t l) { assert(io); return pa_socket_set_sndbuf(io->ofd, l); } + +void pa_iochannel_force_unreadable(struct pa_iochannel *io) { + assert(io); + io->readable = 0; + enable_mainloop_sources(io); +} + +void pa_iochannel_force_unwritable(struct pa_iochannel *io) { + io->writable = 0; + enable_mainloop_sources(io); +} diff --git a/polyp/iochannel.h b/polyp/iochannel.h index 6f5f351c..a4edbfad 100644 --- a/polyp/iochannel.h +++ b/polyp/iochannel.h @@ -39,6 +39,9 @@ int pa_iochannel_is_readable(struct pa_iochannel*io); int pa_iochannel_is_writable(struct pa_iochannel*io); int pa_iochannel_is_hungup(struct pa_iochannel*io); +void pa_iochannel_force_unreadable(struct pa_iochannel *io); +void pa_iochannel_force_unwritable(struct pa_iochannel *io); + void pa_iochannel_set_noclose(struct pa_iochannel*io, int b); void pa_iochannel_set_callback(struct pa_iochannel*io, void (*callback)(struct pa_iochannel*io, void *userdata), void *userdata); diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index cf828eb0..41a17691 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -143,6 +143,20 @@ static void io_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, do_read(u); } +static pa_usec_t source_get_latency_cb(struct pa_source *s) { + struct userdata *u = s->userdata; + snd_pcm_sframes_t frames; + assert(s && u && u->source); + + if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { + pa_log(__FILE__": failed to get delay\n"); + s->get_latency = NULL; + return 0; + } + + return pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec); +} + int pa__init(struct pa_core *c, struct pa_module*m) { struct pa_modargs *ma = NULL; int ret = -1; @@ -191,6 +205,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { assert(u->source); u->source->userdata = u; + u->source->get_latency = source_get_latency_cb; pa_source_set_owner(u->source, m); u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); diff --git a/polyp/module-oss.c b/polyp/module-oss.c index a45f72b8..68918604 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -59,6 +59,7 @@ struct userdata { struct pa_memchunk memchunk, silence; uint32_t in_fragment_size, out_fragment_size, sample_size; + int use_getospace, use_getispace; int fd; struct pa_module *module; @@ -92,6 +93,9 @@ static void update_usage(struct userdata *u) { static void do_write(struct userdata *u) { struct pa_memchunk *memchunk; ssize_t r; + size_t l; + int loop = 0; + assert(u); if (!u->sink || !pa_iochannel_is_writable(u->io)) @@ -99,37 +103,58 @@ static void do_write(struct userdata *u) { update_usage(u); - memchunk = &u->memchunk; - - if (!memchunk->length) - if (pa_sink_render(u->sink, u->out_fragment_size, memchunk) < 0) - memchunk = &u->silence; - - assert(memchunk->memblock); - assert(memchunk->memblock->data); - assert(memchunk->length); + l = u->out_fragment_size; - if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); - return; + if (u->use_getospace) { + audio_buf_info info; + + if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) + u->use_getospace = 0; + else { + if (info.bytes/l > 0) { + l = (info.bytes/l)*l; + loop = 1; + } + } } + + do { + memchunk = &u->memchunk; + + if (!memchunk->length) + if (pa_sink_render(u->sink, l, memchunk) < 0) + memchunk = &u->silence; - if (memchunk == &u->silence) - assert(r % u->sample_size == 0); - else { - u->memchunk.index += r; - u->memchunk.length -= r; + assert(memchunk->memblock); + assert(memchunk->memblock->data); + assert(memchunk->length); - if (u->memchunk.length <= 0) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; + if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + break; } - } + + if (memchunk == &u->silence) + assert(r % u->sample_size == 0); + else { + u->memchunk.index += r; + u->memchunk.length -= r; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + } + } + + l = l > (size_t) r ? l - r : 0; + } while (loop && l > 0); } static void do_read(struct userdata *u) { struct pa_memchunk memchunk; ssize_t r; + size_t l; + int loop = 0; assert(u); if (!u->source || !pa_iochannel_is_readable(u->io)) @@ -137,21 +162,40 @@ static void do_read(struct userdata *u) { update_usage(u); - memchunk.memblock = pa_memblock_new(u->in_fragment_size, u->core->memblock_stat); - assert(memchunk.memblock); - if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { - pa_memblock_unref(memchunk.memblock); - if (errno != EAGAIN) - pa_log(__FILE__": read() failed: %s\n", strerror(errno)); - return; - } + l = u->in_fragment_size; - assert(r <= (ssize_t) memchunk.memblock->length); - memchunk.length = memchunk.memblock->length = r; - memchunk.index = 0; + if (u->use_getispace) { + audio_buf_info info; + + if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) + u->use_getispace = 0; + else { + if (info.bytes/l > 0) { + l = (info.bytes/l)*l; + loop = 1; + } + } + } + + do { + memchunk.memblock = pa_memblock_new(l, u->core->memblock_stat); + assert(memchunk.memblock); + if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { + pa_memblock_unref(memchunk.memblock); + if (errno != EAGAIN) + pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + break; + } + + assert(r <= (ssize_t) memchunk.memblock->length); + memchunk.length = memchunk.memblock->length = r; + memchunk.index = 0; + + pa_source_post(u->source, &memchunk); + pa_memblock_unref(memchunk.memblock); - pa_source_post(u->source, &memchunk); - pa_memblock_unref(memchunk.memblock); + l = l > (size_t) r ? l - r : 0; + } while (loop && l > 0); } static void io_callback(struct pa_iochannel *io, void*userdata) { @@ -181,6 +225,25 @@ static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { return r; } +static pa_usec_t source_get_latency_cb(struct pa_source *s) { + struct userdata *u = s->userdata; + audio_buf_info info; + assert(s && u && u->sink); + + if (!u->use_getispace) + return 0; + + if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { + u->use_getispace = 0; + return 0; + } + + if (info.bytes <= 0) + return 0; + + return pa_bytes_to_usec(info.bytes, &s->sample_spec); +} + int pa__init(struct pa_core *c, struct pa_module*m) { struct audio_buf_info info; struct userdata *u = NULL; @@ -243,23 +306,27 @@ int pa__init(struct pa_core *c, struct pa_module*m) { assert(frag_size); in_frag_size = out_frag_size = frag_size; + u = pa_xmalloc(sizeof(struct userdata)); + u->core = c; + u->use_getospace = u->use_getispace = 0; + if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { pa_log(__FILE__": input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); in_frag_size = info.fragsize; + u->use_getispace = 1; } if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) { pa_log(__FILE__": output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); out_frag_size = info.fragsize; + u->use_getospace = 1; } - u = pa_xmalloc(sizeof(struct userdata)); - u->core = c; - if (mode != O_WRONLY) { u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); assert(u->source); u->source->userdata = u; + u->source->get_latency = source_get_latency_cb; pa_source_set_owner(u->source, m); u->source->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); } else diff --git a/polyp/native-common.h b/polyp/native-common.h index 45e0b1d3..a052fca2 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -86,6 +86,7 @@ enum { PA_COMMAND_REMOVE_AUTOLOAD, PA_COMMAND_GET_AUTOLOAD_INFO, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, + PA_COMMAND_GET_RECORD_LATENCY, PA_COMMAND_MAX }; diff --git a/polyp/pacat.c b/polyp/pacat.c index cc7d55f4..933b0c3a 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -276,27 +276,29 @@ static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_even } -/* Show the current playback latency */ +/* Show the current latency */ static void stream_get_latency_callback(struct pa_stream *s, const struct pa_latency_info *i, void *userdata) { + double total; assert(s); if (!i) { - fprintf(stderr, "Failed to get latency: %s\n", strerror(errno)); + fprintf(stderr, "Failed to get latency: %s\n", pa_strerror(pa_context_errno(context))); quit(1); return; } - fprintf(stderr, "Latency: buffer: %0.0f usec; sink: %0.0f usec; transport: %0.0f usec; total: %0.0f usec; synchronized clocks: %s.\n", - (float) i->buffer_usec, (float) i->sink_usec, (float) i->transport_usec, - (float) (i->buffer_usec+i->sink_usec+i->transport_usec), + if (mode == PLAYBACK) + total = (double) i->sink_usec + i->buffer_usec + i->transport_usec; + else + total = (double) i->source_usec + i->buffer_usec + i->transport_usec - i->sink_usec; + + fprintf(stderr, "Latency: buffer: %0.0f usec; sink: %0.0f usec; source: %0.0f usec; transport: %0.0f usec; total: %0.0f usec; synchronized clocks: %s.\n", + (float) i->buffer_usec, (float) i->sink_usec, (float) i->source_usec, (float) i->transport_usec, total, i->synchronized_clocks ? "yes" : "no"); } /* Someone requested that the latency is shown */ static void sigusr1_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { - if (mode != PLAYBACK) - return; - fprintf(stderr, "Got SIGUSR1, requesting latency.\n"); pa_operation_unref(pa_stream_get_latency(stream, stream_get_latency_callback, NULL)); } diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index 9bba3f32..29f5eb43 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -132,20 +132,26 @@ enum pa_subscription_event_type { /** Return one if an event type t matches an event mask bitfield */ #define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) -/** A structure for latency info. See pa_stream_get_latency(). The - * total latency a sample that is written with pa_stream_write() takes - * to be played may be estimated by - * buffer_usec+sink_usec+transport_usec. The buffer to which +/** A structure for latency info. See pa_stream_get_latency(). The + * total output latency a sample that is written with + * pa_stream_write() takes to be played may be estimated by + * sink_usec+buffer_usec+transport_usec. The output buffer to which * buffer_usec relates may be manipulated freely (with * pa_stream_write()'s delta argument, pa_stream_flush() and friends), - * the playback buffer sink_usec relates to is a FIFO which cannot be - * flushed or manipulated in any way. */ + * the buffers sink_usec/source_usec relates to is a first-in + * first-out buffer which cannot be flushed or manipulated in any + * way. The total input latency a sample that is recorded takes to be + * delivered to the application is: + * source_usec+buffer_usec+transport_usec-sink_usec. (Take care of + * sign issues!) When connected to a monitor source sink_usec contains + * the latency of the owning sink.*/ struct pa_latency_info { - pa_usec_t buffer_usec; /**< Time in usecs the current buffer takes to play */ - pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. */ - pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to the daemon. \since 0.5 */ - int playing; /**< Non-zero when the stream is currently playing */ - uint32_t queue_length; /**< Queue size in bytes. */ + pa_usec_t buffer_usec; /**< Time in usecs the current buffer takes to play. For both playback and record streams. */ + pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. For playback streams and record streams connected to a monitor source. */ + pa_usec_t source_usec; /**< Time in usecs a sample takes from being recorded to being delivered to the application. Only for record streams. \since 0.5*/ + pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to/from the daemon. For both playback and record streams. \since 0.5 */ + int playing; /**< Non-zero when the stream is currently playing. Only for playback streams. */ + uint32_t queue_length; /**< Queue size in bytes. For both playback and recrd streams. */ int synchronized_clocks; /**< Non-zero if the local and the * remote machine have synchronized * clocks. If synchronized clocks are diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index 919adb9c..1673be9b 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -221,7 +221,9 @@ static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t c pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || pa_tagstruct_getu32(t, &i.owner_module) < 0 || pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || - pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) { + pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 || + pa_tagstruct_get_usec(t, &i.latency) < 0) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } @@ -515,7 +517,9 @@ static void context_get_source_output_info_callback(struct pa_pdispatch *pd, uin pa_tagstruct_getu32(t, &i.owner_module) < 0 || pa_tagstruct_getu32(t, &i.client) < 0 || pa_tagstruct_getu32(t, &i.source) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0) { + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || + pa_tagstruct_get_usec(t, &i.source_usec) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index 51210457..28c51fed 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -56,7 +56,7 @@ struct pa_sink_info { pa_volume_t volume; /**< Volume of the sink */ uint32_t monitor_source; /**< Index of the monitor source connected to this sink */ const char *monitor_source_name; /**< The name of the monitor source */ - pa_usec_t latency; /**< Length of the playback buffer of this sink */ + pa_usec_t latency; /**< Length of filled playback buffer of this sink */ }; /** Get information about a sink by its name */ @@ -77,6 +77,7 @@ struct pa_source_info { uint32_t owner_module; /**< Owning module index, or PA_INVALID_INDEX */ uint32_t monitor_of_sink; /**< If this is a monitor source the index of the owning sink, otherwise PA_INVALID_INDEX */ const char *monitor_of_sink_name; /**< Name of the owning sink, or PA_INVALID_INDEX */ + pa_usec_t latency; /**< Length of filled record buffer of this source. \since 0.5 */ }; /** Get information about a source by its name */ @@ -158,6 +159,8 @@ struct pa_source_output_info { uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ uint32_t source; /**< Index of the connected source */ struct pa_sample_spec sample_spec; /**< The sample specification of the source output */ + pa_usec_t buffer_usec; /**< Latency due to buffering in the source output, see pa_latency_info for details. \since 0.5 */ + pa_usec_t source_usec; /**< Latency of the source device, see pa_latency_info for details. \since 0.5 */ }; /** Get information about a source output by its index */ diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 89a8d338..532d1700 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -336,6 +336,7 @@ static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t comman } else if (pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || + pa_tagstruct_get_usec(t, &i.source_usec) < 0 || pa_tagstruct_get_boolean(t, &i.playing) < 0 || pa_tagstruct_getu32(t, &i.queue_length) < 0 || pa_tagstruct_get_timeval(t, &local) < 0 || @@ -350,7 +351,12 @@ static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t comman if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) { /* local and remote seem to have synchronized clocks */ - i.transport_usec = pa_timeval_diff(&remote, &local); + + if (o->stream->direction == PA_STREAM_PLAYBACK) + i.transport_usec = pa_timeval_diff(&remote, &local); + else + i.transport_usec = pa_timeval_diff(&now, &remote); + i.synchronized_clocks = 1; i.timestamp = remote; } else { @@ -376,6 +382,7 @@ struct pa_operation* pa_stream_get_latency(struct pa_stream *s, void (*cb)(struc struct pa_operation *o; struct pa_tagstruct *t; struct timeval now; + assert(s && s->direction != PA_STREAM_UPLOAD); o = pa_operation_new(s->context, s); assert(o); @@ -384,7 +391,7 @@ struct pa_operation* pa_stream_get_latency(struct pa_stream *s, void (*cb)(struc t = pa_tagstruct_new(NULL, 0); assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_GET_PLAYBACK_LATENCY : PA_COMMAND_GET_RECORD_LATENCY); pa_tagstruct_putu32(t, tag = s->context->ctag++); pa_tagstruct_putu32(t, s->channel); diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 5abe474d..aff45099 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -107,6 +107,7 @@ static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk); static void sink_input_kill_cb(struct pa_sink_input *i); static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i); +static pa_usec_t source_output_get_latency_cb(struct pa_source_output *o); static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk); static void source_output_kill_cb(struct pa_source_output *o); @@ -374,6 +375,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co c->source_output->client = c->client; c->source_output->push = source_output_push_cb; c->source_output->kill = source_output_kill_cb; + c->source_output->get_latency = source_output_get_latency_cb; c->source_output->userdata = c; c->state = ESD_STREAMING_DATA; @@ -919,7 +921,6 @@ static void sink_input_kill_cb(struct pa_sink_input *i) { connection_free((struct connection *) i->userdata); } - static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i) { struct connection*c = i->userdata; assert(i && c); @@ -944,6 +945,12 @@ static void source_output_kill_cb(struct pa_source_output *o) { connection_free((struct connection *) o->userdata); } +static pa_usec_t source_output_get_latency_cb(struct pa_source_output *o) { + struct connection*c = o->userdata; + assert(o && c); + return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec); +} + /*** socket server callback ***/ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index be7b76f6..e197d1e2 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -117,6 +117,7 @@ static void request_bytes(struct playback_stream*s); static void source_output_kill_cb(struct pa_source_output *o); static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk); +static pa_usec_t source_output_get_latency_cb(struct pa_source_output *o); static void command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); @@ -128,6 +129,7 @@ static void command_set_client_name(struct pa_pdispatch *pd, uint32_t command, u static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_get_record_latency(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_create_upload_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_finish_upload_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_play_sample(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); @@ -166,6 +168,7 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_LOOKUP_SOURCE] = { command_lookup }, [PA_COMMAND_STAT] = { command_stat }, [PA_COMMAND_GET_PLAYBACK_LATENCY] = { command_get_playback_latency }, + [PA_COMMAND_GET_RECORD_LATENCY] = { command_get_record_latency }, [PA_COMMAND_CREATE_UPLOAD_STREAM] = { command_create_upload_stream }, [PA_COMMAND_DELETE_UPLOAD_STREAM] = { command_delete_stream }, [PA_COMMAND_FINISH_UPLOAD_STREAM] = { command_finish_upload_stream }, @@ -256,6 +259,7 @@ static struct record_stream* record_stream_new(struct connection *c, struct pa_s s->source_output = source_output; s->source_output->push = source_output_push_cb; s->source_output->kill = source_output_kill_cb; + s->source_output->get_latency = source_output_get_latency_cb; s->source_output->userdata = s; s->source_output->owner = c->protocol->module; s->source_output->client = c->client; @@ -444,7 +448,6 @@ static void send_record_stream_killed(struct record_stream *r) { pa_pstream_send_tagstruct(r->connection->pstream, t); } - /*** sinkinput callbacks ***/ static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk) { @@ -508,6 +511,16 @@ static void source_output_kill_cb(struct pa_source_output *o) { record_stream_free((struct record_stream *) o->userdata); } +static pa_usec_t source_output_get_latency_cb(struct pa_source_output *o) { + struct record_stream *s; + assert(o && o->userdata); + s = o->userdata; + + /*pa_log(__FILE__": get_latency: %u\n", pa_memblockq_get_length(s->memblockq));*/ + + return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec); +} + /*** pdispatch callbacks ***/ static void protocol_error(struct connection *c) { @@ -843,7 +856,7 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma struct timeval tv, now; uint32_t index; assert(c && t); - + if (pa_tagstruct_getu32(t, &index) < 0 || pa_tagstruct_get_timeval(t, &tv) < 0 || !pa_tagstruct_eof(t)) { @@ -867,6 +880,7 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma pa_tagstruct_putu32(reply, tag); pa_tagstruct_put_usec(reply, pa_sink_input_get_latency(s->sink_input)); pa_tagstruct_put_usec(reply, pa_sink_get_latency(s->sink_input->sink)); + pa_tagstruct_put_usec(reply, 0); pa_tagstruct_put_boolean(reply, pa_memblockq_is_readable(s->memblockq)); pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq)); pa_tagstruct_put_timeval(reply, &tv); @@ -875,6 +889,47 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma pa_pstream_send_tagstruct(c->pstream, reply); } +static void command_get_record_latency(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + struct pa_tagstruct *reply; + struct record_stream *s; + struct timeval tv, now; + uint32_t index; + assert(c && t); + + if (pa_tagstruct_getu32(t, &index) < 0 || + pa_tagstruct_get_timeval(t, &tv) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->record_streams, index))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_put_usec(reply, pa_source_output_get_latency(s->source_output)); + pa_tagstruct_put_usec(reply, s->source_output->source->monitor_of ? pa_sink_get_latency(s->source_output->source->monitor_of) : 0); + pa_tagstruct_put_usec(reply, pa_source_get_latency(s->source_output->source)); + pa_tagstruct_put_boolean(reply, 0); + pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq)); + pa_tagstruct_put_timeval(reply, &tv); + gettimeofday(&now, NULL); + pa_tagstruct_put_timeval(reply, &now); + pa_pstream_send_tagstruct(c->pstream, reply); +} + + static void command_create_upload_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; struct upload_stream *s; @@ -1036,6 +1091,7 @@ static void source_fill_tagstruct(struct pa_tagstruct *t, struct pa_source *sour pa_tagstruct_putu32(t, source->owner ? source->owner->index : (uint32_t) -1); pa_tagstruct_putu32(t, source->monitor_of ? source->monitor_of->index : (uint32_t) -1); pa_tagstruct_puts(t, source->monitor_of ? source->monitor_of->name : ""); + pa_tagstruct_put_usec(t, pa_source_get_latency(source)); } static void client_fill_tagstruct(struct pa_tagstruct *t, struct pa_client *client) { @@ -1076,6 +1132,8 @@ static void source_output_fill_tagstruct(struct pa_tagstruct *t, struct pa_sourc pa_tagstruct_putu32(t, s->client ? s->client->index : (uint32_t) -1); pa_tagstruct_putu32(t, s->source->index); pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_put_usec(t, pa_source_output_get_latency(s)); + pa_tagstruct_put_usec(t, pa_source_get_latency(s->source)); } static void scache_fill_tagstruct(struct pa_tagstruct *t, struct pa_scache_entry *e) { diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index 58156329..a7bd76fb 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -248,6 +248,12 @@ static void source_output_kill_cb(struct pa_source_output *o) { connection_free((struct connection *) o->userdata); } +static pa_usec_t source_output_get_latency_cb(struct pa_source_output *o) { + struct connection*c = o->userdata; + assert(o && c); + return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec); +} + /*** client callbacks ***/ static void client_kill_cb(struct pa_client *c) { @@ -348,6 +354,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->source_output->push = source_output_push_cb; c->source_output->kill = source_output_kill_cb; + c->source_output->get_latency = source_output_get_latency_cb; c->source_output->userdata = c; l = (size_t) (pa_bytes_per_second(&p->sample_spec)*RECORD_BUFFER_SECONDS); diff --git a/polyp/sink.c b/polyp/sink.c index 6d3b59c7..8133d65a 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -197,7 +197,10 @@ int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result) unsigned n; size_t l; int r = -1; - assert(s && s->ref >= 1 && length && result); + assert(s); + assert(s->ref >= 1); + assert(length); + assert(result); pa_sink_ref(s); diff --git a/polyp/source-output.c b/polyp/source-output.c index 2566ec87..1db88d3c 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -60,6 +60,8 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n o->push = NULL; o->kill = NULL; o->userdata = NULL; + o->get_latency = NULL; + o->resampler = resampler; assert(s->core); @@ -149,3 +151,12 @@ void pa_source_output_set_name(struct pa_source_output *o, const char *name) { pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); } + +pa_usec_t pa_source_output_get_latency(struct pa_source_output *o) { + assert(o && o->ref >= 1); + + if (o->get_latency) + return o->get_latency(o); + + return 0; +} diff --git a/polyp/source-output.h b/polyp/source-output.h index 709d65ad..ed09b537 100644 --- a/polyp/source-output.h +++ b/polyp/source-output.h @@ -50,6 +50,7 @@ struct pa_source_output { void (*push)(struct pa_source_output *o, const struct pa_memchunk *chunk); void (*kill)(struct pa_source_output* o); + pa_usec_t (*get_latency) (struct pa_source_output *i); struct pa_resampler* resampler; @@ -70,4 +71,7 @@ void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk void pa_source_output_set_name(struct pa_source_output *i, const char *name); +pa_usec_t pa_source_output_get_latency(struct pa_source_output *i); + + #endif diff --git a/polyp/source.c b/polyp/source.c index 2c0caca0..23b8bf8a 100644 --- a/polyp/source.c +++ b/polyp/source.c @@ -60,6 +60,7 @@ struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail s->outputs = pa_idxset_new(NULL, NULL); s->monitor_of = NULL; + s->get_latency = NULL; s->notify = NULL; s->userdata = NULL; @@ -150,3 +151,13 @@ void pa_source_set_owner(struct pa_source *s, struct pa_module *m) { assert(s); s->owner = m; } + +pa_usec_t pa_source_get_latency(struct pa_source *s) { + assert(s && s->ref >= 1); + + if (!s->get_latency) + return 0; + + return s->get_latency(s); +} + diff --git a/polyp/source.h b/polyp/source.h index 8b03c0d5..b6262835 100644 --- a/polyp/source.h +++ b/polyp/source.h @@ -53,6 +53,7 @@ struct pa_source { struct pa_sink *monitor_of; void (*notify)(struct pa_source*source); + pa_usec_t (*get_latency)(struct pa_source *s); void *userdata; }; @@ -68,4 +69,6 @@ void pa_source_notify(struct pa_source *s); void pa_source_set_owner(struct pa_source *s, struct pa_module *m); +pa_usec_t pa_source_get_latency(struct pa_source *s); + #endif -- cgit From daf3938a9e5b50c3e52c0ae889e4d02b548fa78a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Sep 2004 22:07:41 +0000 Subject: add support for subscribing to autoload table changes fix module-combine so that the sample rate of at least one streams is not changed from the original git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@206 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 5 ++--- polyp/autoload.c | 5 +++++ polyp/autoload.h | 1 + polyp/module-combine.c | 42 ++++++++++++++++++++++++------------------ polyp/polyplib-def.h | 6 ++++-- polyp/pstream.c | 14 ++++++++++++-- polyp/sample.c | 6 +++--- 7 files changed, 51 insertions(+), 28 deletions(-) diff --git a/doc/todo b/doc/todo index 675e8ca3..bcc78f51 100644 --- a/doc/todo +++ b/doc/todo @@ -1,9 +1,8 @@ *** $Id$ *** *** 0.5 *** -- more complete pactl -- fix tcp/native -- paman: add support for killing sink inputs, source outputs, clients +- more complete pactl/parec +- fix tcp/native in regard to latencies - add client config file - remove autospawn stuff in conf.c diff --git a/polyp/autoload.c b/polyp/autoload.c index 344d26e2..12cd1f91 100644 --- a/polyp/autoload.c +++ b/polyp/autoload.c @@ -34,9 +34,11 @@ #include "sound-file.h" #include "log.h" #include "scache.h" +#include "subscribe.h" static void entry_free(struct pa_autoload_entry *e) { assert(e); + pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_AUTOLOAD|PA_SUBSCRIPTION_EVENT_REMOVE, PA_INVALID_INDEX); pa_xfree(e->name); pa_xfree(e->module); pa_xfree(e->argument); @@ -51,6 +53,7 @@ static struct pa_autoload_entry* entry_new(struct pa_core *c, const char *name) return NULL; e = pa_xmalloc(sizeof(struct pa_autoload_entry)); + e->core = c; e->name = pa_xstrdup(name); e->module = e->argument = NULL; e->in_action = 0; @@ -61,6 +64,8 @@ static struct pa_autoload_entry* entry_new(struct pa_core *c, const char *name) pa_hashmap_put(c->autoload_hashmap, e->name, e); + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_AUTOLOAD|PA_SUBSCRIPTION_EVENT_NEW, PA_INVALID_INDEX); + return e; } diff --git a/polyp/autoload.h b/polyp/autoload.h index cdf76239..f80b1f0d 100644 --- a/polyp/autoload.h +++ b/polyp/autoload.h @@ -25,6 +25,7 @@ #include "namereg.h" struct pa_autoload_entry { + struct pa_core *core; char *name; enum pa_namereg_type type; int in_action; diff --git a/polyp/module-combine.c b/polyp/module-combine.c index 8535e514..177d7d18 100644 --- a/polyp/module-combine.c +++ b/polyp/module-combine.c @@ -40,7 +40,7 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Combine multiple sinks to one") PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= master= slave= adjust_time") +PA_MODULE_USAGE("sink_name= master= slave= adjust_time=") #define DEFAULT_SINK_NAME "combined" #define MEMBLOCKQ_MAXLENGTH (1024*170) @@ -61,7 +61,7 @@ struct output { struct pa_sink_input *sink_input; size_t counter; struct pa_memblockq *memblockq; - pa_usec_t sink_latency; + pa_usec_t total_latency; PA_LLIST_FIELDS(struct output); }; @@ -89,38 +89,44 @@ static void update_usage(struct userdata *u) { static void adjust_rates(struct userdata *u) { struct output *o; - pa_usec_t max = 0; + pa_usec_t max_sink_latency = 0, min_total_latency = (pa_usec_t) -1, target_latency; uint32_t base_rate; assert(u && u->sink); for (o = u->outputs; o; o = o->next) { - o->sink_latency = o->sink_input->sink ? pa_sink_get_latency(o->sink_input->sink) : 0; + uint32_t sink_latency = o->sink_input->sink ? pa_sink_get_latency(o->sink_input->sink) : 0; + + o->total_latency = sink_latency + pa_sink_input_get_latency(o->sink_input); + + if (sink_latency > max_sink_latency) + max_sink_latency = sink_latency; - if (o->sink_latency > max) - max = o->sink_latency; + if (o->total_latency < min_total_latency) + min_total_latency = o->total_latency; } - pa_log(__FILE__": [%s] maximum latency is %0.0f usec.\n", u->sink->name, (float) max); + assert(max_sink_latency > 0 && min_total_latency != (pa_usec_t) -1); + + target_latency = max_sink_latency > min_total_latency ? max_sink_latency : min_total_latency; + + pa_log(__FILE__": [%s] target latency is %0.0f usec.\n", u->sink->name, (float) target_latency); base_rate = u->sink->sample_spec.rate; for (o = u->outputs; o; o = o->next) { - pa_usec_t l; uint32_t r = base_rate; - l = o->sink_latency + pa_sink_input_get_latency(o->sink_input); - - if (l < max) - r -= (uint32_t) (((((double) max-l))/u->adjust_time)*r/ 1000000); - else if (l > max) - r += (uint32_t) (((((double) l-max))/u->adjust_time)*r/ 1000000); + if (o->total_latency < target_latency) + r -= (uint32_t) (((((double) target_latency - o->total_latency))/u->adjust_time)*r/ 1000000); + else if (o->total_latency > target_latency) + r += (uint32_t) (((((double) o->total_latency - target_latency))/u->adjust_time)*r/ 1000000); if (r < (uint32_t) (base_rate*0.9) || r > (uint32_t) (base_rate*1.1)) pa_log(__FILE__": [%s] sample rates too different, not adjusting (%u vs. %u).\n", o->sink_input->name, base_rate, r); - else - pa_log(__FILE__": [%s] new rate is %u Hz; ratio is %0.3f; latency is %0.0f usec.\n", o->sink_input->name, r, (double) r / base_rate, (float) l); - - pa_sink_input_set_rate(o->sink_input, r); + else { + pa_log(__FILE__": [%s] new rate is %u Hz; ratio is %0.3f; latency is %0.0f usec.\n", o->sink_input->name, r, (double) r / base_rate, (float) o->total_latency); + pa_sink_input_set_rate(o->sink_input, r); + } } } diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index 29f5eb43..591d237d 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -108,7 +108,8 @@ enum pa_subscription_mask { PA_SUBSCRIPTION_MASK_MODULE = 16, /**< Module events */ PA_SUBSCRIPTION_MASK_CLIENT = 32, /**< Client events */ PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, /**< Sample cache events */ - PA_SUBSCRIPTION_MASK_SERVER = 128 /**< Other global server changes. \since 0.4 */ + PA_SUBSCRIPTION_MASK_SERVER = 128, /**< Other global server changes. \since 0.4 */ + PA_SUBSCRIPTION_MASK_AUTOLOAD = 256 /**< Autoload table events. \since 0.5 */ }; /** Subscription event types, as used by pa_context_subscribe() */ @@ -121,7 +122,8 @@ enum pa_subscription_event_type { PA_SUBSCRIPTION_EVENT_CLIENT = 5, /**< Event type: Client */ PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, /**< Event type: Sample cache item */ PA_SUBSCRIPTION_EVENT_SERVER = 7, /**< Event type: Global server change, only occuring with PA_SUBSCRIPTION_EVENT_CHANGE. \since 0.4 */ - PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 7, /**< A mask to extract the event type from an event value */ + PA_SUBSCRIPTION_EVENT_AUTOLOAD = 8, /**< Event type: Autoload table changes. \since 0.5 */ + PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 15, /**< A mask to extract the event type from an event value */ PA_SUBSCRIPTION_EVENT_NEW = 0, /**< A new object was created */ PA_SUBSCRIPTION_EVENT_CHANGE = 16, /**< A property of the object was modified */ diff --git a/polyp/pstream.c b/polyp/pstream.c index 4ee296ce..b0de9e8c 100644 --- a/polyp/pstream.c +++ b/polyp/pstream.c @@ -101,6 +101,10 @@ static void do_read(struct pa_pstream *p); static void do_something(struct pa_pstream *p) { assert(p); + + if (p->dead) + return; + p->mainloop->defer_enable(p->defer_event, 0); pa_pstream_ref(p); @@ -213,8 +217,11 @@ static void pstream_free(struct pa_pstream *p) { void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet) { struct item_info *i; - assert(p && packet); + assert(p && packet && p->ref >= 1); + if (p->dead) + return; + /* pa_log(__FILE__": push-packet %p\n", packet); */ i = pa_xmalloc(sizeof(struct item_info)); @@ -227,8 +234,11 @@ void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet) { void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk) { struct item_info *i; - assert(p && channel != (uint32_t) -1 && chunk); + assert(p && channel != (uint32_t) -1 && chunk && p->ref >= 1); + if (p->dead) + return; + /* pa_log(__FILE__": push-memblock %p\n", chunk); */ i = pa_xmalloc(sizeof(struct item_info)); diff --git a/polyp/sample.c b/polyp/sample.c index dfe98e3f..397e57a2 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -121,11 +121,11 @@ double pa_volume_to_dB(pa_volume_t v) { } void pa_bytes_snprint(char *s, size_t l, off_t v) { - if (v >= 1024*1024*1024) + if (v >= (off_t) 1024*1024*1024) snprintf(s, l, "%0.1f GB", (double) v/1024/1024/1024); - else if (v >= 1024*1024) + else if (v >= (off_t) 1024*1024) snprintf(s, l, "%0.1f MB", (double) v/1024/1024); - else if (v >= 1024) + else if (v >= (off_t) 1024) snprintf(s, l, "%0.1f KB", (double) v/1024); else snprintf(s, l, "%u B", (unsigned) v); -- cgit From 19294e4b388571ba45162b3704f8aacd38e72158 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Sep 2004 22:44:40 +0000 Subject: fix two gcc 2.95 incompatibilities git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@207 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 7 ++++--- polyp/dumpmodules.c | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 07b2b96c..8b5a72ab 100644 --- a/configure.ac +++ b/configure.ac @@ -40,8 +40,6 @@ AC_SUBST(INCLTDL) AC_SUBST(LIBLTDL) AC_LIBTOOL_DLOPEN AC_PROG_LIBTOOL -AC_PROG_LEX -AC_PROG_YACC # Checks for header files. AC_HEADER_STDC @@ -108,7 +106,10 @@ AM_CONDITIONAL([HAVE_GLIB12], [test "x$HAVE_GLIB12" = x1]) # If using GCC specifiy some additional parameters if test "x$GCC" = "xyes" ; then - CFLAGS="$CFLAGS -pipe -W -Wall -Wno-unused-parameter -pedantic -std=c99" + CFLAGS="$CFLAGS -pipe -W -Wall -pedantic" + + AC_LANG_CONFTEST([int main()]) + $CC -std=c99 -Wno-unused-parameter -E conftest.c -o - > /dev/null 2>&1 && CFLAGS="$CFLAGS -std=c99 -Wno-unused-parameter" fi # LYNX documentation generation diff --git a/polyp/dumpmodules.c b/polyp/dumpmodules.c index 9ed89692..ae42d36e 100644 --- a/polyp/dumpmodules.c +++ b/polyp/dumpmodules.c @@ -40,8 +40,8 @@ static void short_info(const char *name, const char *path, struct pa_modinfo *i) } static void long_info(const char *name, const char *path, struct pa_modinfo *i) { - assert(name && i); static int nl = 0; + assert(name && i); if (nl) printf("\n"); -- cgit From 078f2aa860cc0e0063dd6b4e8ff6ca1cbf5fd45b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Sep 2004 23:34:25 +0000 Subject: gcc 2.95 compatibility, take 2 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@208 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 7 ++++--- polyp/cpulimit-test.c | 3 ++- polyp/log.h | 2 +- polyp/polyplib-introspect.h | 2 +- polyp/source.h | 2 +- polyp/tagstruct.c | 2 +- polyp/util.c | 2 +- 7 files changed, 11 insertions(+), 9 deletions(-) diff --git a/configure.ac b/configure.ac index 8b5a72ab..5239db1d 100644 --- a/configure.ac +++ b/configure.ac @@ -104,12 +104,13 @@ AC_SUBST(GLIB12_LIBS) AC_SUBST(HAVE_GLIB12) AM_CONDITIONAL([HAVE_GLIB12], [test "x$HAVE_GLIB12" = x1]) -# If using GCC specifiy some additional parameters +# If using GCC specify some additional parameters if test "x$GCC" = "xyes" ; then CFLAGS="$CFLAGS -pipe -W -Wall -pedantic" - AC_LANG_CONFTEST([int main()]) - $CC -std=c99 -Wno-unused-parameter -E conftest.c -o - > /dev/null 2>&1 && CFLAGS="$CFLAGS -std=c99 -Wno-unused-parameter" + AC_LANG_CONFTEST([int main() {}]) + $CC -c conftest.c -std=c99 -Wno-unused-parameter $CFLAGS > /dev/null 2> /dev/null && CFLAGS="$CFLAGS -std=c99 -Wno-unused-parameter" + rm -f conftest.o fi # LYNX documentation generation diff --git a/polyp/cpulimit-test.c b/polyp/cpulimit-test.c index 71c06ef7..d1faf92b 100644 --- a/polyp/cpulimit-test.c +++ b/polyp/cpulimit-test.c @@ -80,5 +80,6 @@ int main() { pa_cpu_limit_done(); pa_mainloop_free(m); - + + return 0; } diff --git a/polyp/log.h b/polyp/log.h index 1f2c74ef..46a86491 100644 --- a/polyp/log.h +++ b/polyp/log.h @@ -6,7 +6,7 @@ enum pa_log_target { PA_LOG_SYSLOG, PA_LOG_STDERR, - PA_LOG_USER, + PA_LOG_USER }; void pa_log_set_ident(const char *p); diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index 28c51fed..9e6c31b2 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -229,7 +229,7 @@ struct pa_operation* pa_context_unload_module(struct pa_context *c, uint32_t ind /** Type of an autoload entry. \since 0.5 */ enum pa_autoload_type { PA_AUTOLOAD_SINK = 0, - PA_AUTOLOAD_SOURCE = 1, + PA_AUTOLOAD_SOURCE = 1 }; /** Stores information about autoload entries. \since 0.5 */ diff --git a/polyp/source.h b/polyp/source.h index b6262835..cda9e698 100644 --- a/polyp/source.h +++ b/polyp/source.h @@ -36,7 +36,7 @@ struct pa_source; enum pa_source_state { PA_SOURCE_RUNNING, - PA_SOURCE_DISCONNECTED, + PA_SOURCE_DISCONNECTED }; struct pa_source { diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c index 52db0fe3..d571b713 100644 --- a/polyp/tagstruct.c +++ b/polyp/tagstruct.c @@ -46,7 +46,7 @@ enum tags { TAG_BOOLEAN_TRUE = '1', TAG_BOOLEAN_FALSE = '0', TAG_TIMEVAL = 'T', - TAG_USEC = 'U', /* 64bit unsigned */ + TAG_USEC = 'U' /* 64bit unsigned */ }; struct pa_tagstruct { diff --git a/polyp/util.c b/polyp/util.c index bb71bbf9..24773a7b 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -385,7 +385,7 @@ char *pa_split(const char *c, const char *delimiter, const char**state) { *state = current+l; if (**state) - *state++; + (*state)++; return pa_xstrndup(current, l); } -- cgit From 07d563d6c304166bd5bd47731a337387316991f6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Sep 2004 23:43:19 +0000 Subject: update according to autoscan git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@209 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 5239db1d..f422ff68 100644 --- a/configure.ac +++ b/configure.ac @@ -72,7 +72,7 @@ AC_FUNC_REALLOC AC_FUNC_SETPGRP AC_FUNC_VPRINTF AC_TYPE_SIGNAL -AC_CHECK_FUNCS([gethostname gettimeofday memchr memmove memset mkdir mkfifo munmap rmdir socket strcspn strerror strrchr strspn strstr strtol strtoul pow strcasecmp]) +AC_CHECK_FUNCS([gethostname gettimeofday memchr memmove memset mkdir mkfifo munmap rmdir socket strcspn strerror strrchr strspn strstr strtol strtoul pow strcasecmp putenv strchr strpbrk]) AC_FUNC_STAT AC_HEADER_SYS_WAIT -- cgit From 63b35d002aa6902618235e1a30dca37de52ff65e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 17 Sep 2004 19:45:44 +0000 Subject: new configuration subsystem git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@210 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + polyp/Makefile.am | 15 ++- polyp/client.conf | 39 +++++++ polyp/conf.c | 279 +++++++++++++++++----------------------------- polyp/conf.h | 1 + polyp/config | 61 ---------- polyp/config-client.c | 138 +++++++++++++++++++++++ polyp/config-client.h | 36 ++++++ polyp/confparser.c | 168 ++++++++++++++++++++++++++++ polyp/confparser.h | 37 ++++++ polyp/core.c | 3 + polyp/core.h | 2 + polyp/daemon.conf | 67 +++++++++++ polyp/main.c | 6 +- polyp/polyplib-context.c | 63 +++++++---- polyp/polyplib-internal.h | 9 +- polyp/polyplib-scache.c | 2 +- polyp/polyplib-stream.c | 6 +- polyp/resampler.c | 4 +- polyp/resampler.h | 2 +- polyp/sink-input.c | 2 +- polyp/source-output.c | 2 +- polyp/util.c | 17 +++ polyp/util.h | 1 + 24 files changed, 678 insertions(+), 283 deletions(-) create mode 100644 polyp/client.conf delete mode 100644 polyp/config create mode 100644 polyp/config-client.c create mode 100644 polyp/config-client.h create mode 100644 polyp/confparser.c create mode 100644 polyp/confparser.h create mode 100644 polyp/daemon.conf diff --git a/doc/todo b/doc/todo index bcc78f51..fe06df78 100644 --- a/doc/todo +++ b/doc/todo @@ -5,6 +5,7 @@ - fix tcp/native in regard to latencies - add client config file - remove autospawn stuff in conf.c +- make resampler configurable *** 0.6 **** - per-channel volume diff --git a/polyp/Makefile.am b/polyp/Makefile.am index fc3fb18d..d49c7c48 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -25,14 +25,14 @@ modlibdir=$(libdir)/polypaudio-@PA_MAJORMINOR@ AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) AM_CFLAGS+=-DDLSEARCHPATH=\"$(modlibdir)\" AM_CFLAGS+=-DDEFAULT_SCRIPT_FILE=\"$(polypconfdir)/default.pa\" -AM_CFLAGS+=-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/default.conf\" -AM_CFLAGS+=-DAUTOSPAWN_CONFIG_FILE=\"$(polypconfdir)/autospawn.conf\" +AM_CFLAGS+=-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/daemon.conf\" +AM_CFLAGS+=-DDEFAULT_CLIENT_CONFIG_FILE=\"$(polypconfdir)/client.conf\" AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\" AM_LDADD=$(PTHREAD_LIBS) -lm AM_LIBADD=$(PTHREAD_LIBS) -lm -EXTRA_DIST = default.pa config depmod.py esdcompat.sh.in +EXTRA_DIST = default.pa daemon.conf client.conf config depmod.py esdcompat.sh.in bin_PROGRAMS = polypaudio pacat pactl bin_SCRIPTS = esdcompat.sh noinst_PROGRAMS = \ @@ -42,7 +42,7 @@ noinst_PROGRAMS = \ cpulimit-test \ cpulimit-test2 -polypconf_DATA=default.pa config +polypconf_DATA=default.pa daemon.conf client.conf BUILT_SOURCES=polyplib-version.h @@ -158,7 +158,8 @@ polypaudio_SOURCES = idxset.c idxset.h \ gcc-printf.h \ modinfo.c modinfo.h \ conf.c conf.h \ - dumpmodules.c dumpmodules.h + dumpmodules.c dumpmodules.h \ + conparser.h confparser.c polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) @@ -332,7 +333,9 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = polyplib.h \ cdecl.h \ llist.h \ log.c log.h \ - gcc-printf.h + gcc-printf.h \ + config-client.c config-client.h \ + confparser.c confparser.h libpolyp_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) libpolyp_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 diff --git a/polyp/client.conf b/polyp/client.conf new file mode 100644 index 00000000..070d75bd --- /dev/null +++ b/polyp/client.conf @@ -0,0 +1,39 @@ +# $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +## Configuration file for polypaudio clients. Default values are +## commented out. Use either ; or # for commenting + +## Path to the polypaudio daemon to run when autospawning. +; daemon_binary = @POLYPAUDIO_BINARY + +## Extra arguments to pass to the polypaudio daemon +; extra_arguments = --daemonize=yes --log-target=syslog + +## The default sink to connect to +; default_sink = + +## The default source to connect to +; default_source = + +## The default sever to connect to +; default_server = + +## Autospawn daemons? +; autospawn = 0 diff --git a/polyp/conf.c b/polyp/conf.c index b74a5ede..efc471af 100644 --- a/polyp/conf.c +++ b/polyp/conf.c @@ -27,12 +27,34 @@ #include #include #include -#include +#include +#include #include "conf.h" #include "util.h" #include "xmalloc.h" #include "strbuf.h" +#include "confparser.h" + +#ifndef DEFAULT_SCRIPT_FILE +#define DEFAULT_SCRIPT_FILE "/etc/polypaudio/default.pa" +#endif + +#ifndef DEFAULT_SCRIPT_FILE_USER +#define DEFAULT_SCRIPT_FILE_USER ".polypaudio/default.pa" +#endif + +#ifndef DEFAULT_CONFIG_FILE +#define DEFAULT_CONFIG_FILE "/etc/polypaudio/daemon.conf" +#endif + +#ifndef DEFAULT_CONFIG_FILE_USER +#define DEFAULT_CONFIG_FILE_USER ".polypaudio/daemon.conf" +#endif + +#define ENV_SCRIPT_FILE "POLYP_SCRIPT" +#define ENV_CONFIG_FILE "POLYP_CONFIG" +#define ENV_DL_SEARCH_PATH "POLYP_DLPATH" static const struct pa_conf default_conf = { .cmd = PA_CMD_DAEMON, @@ -49,28 +71,9 @@ static const struct pa_conf default_conf = { .dl_search_path = NULL, .default_script_file = NULL, .log_target = PA_LOG_SYSLOG, + .resample_method = SRC_SINC_FASTEST }; -#define ENV_SCRIPT_FILE "POLYP_SCRIPT" -#define ENV_CONFIG_FILE "POLYP_CONFIG" -#define ENV_AUTOSPAWNED "POLYP_AUTOSPAWNED" - -#ifndef DEFAULT_SCRIPT_FILE -#define DEFAULT_SCRIPT_FILE "/etc/polypaudio/default.pa" -#endif - -#ifndef DEFAULT_CONFIG_FILE -#define DEFAULT_CONFIG_FILE "/etc/polypaudio/default.conf" -#endif - -#ifndef AUTOSPAWN_CONFIG_FILE -#define AUTOSPAWN_CONFIG_FILE "/etc/polypaudio/autospawn.conf" -#endif - -#define DEFAULT_SCRIPT_FILE_LOCAL ".polypaudio.pa" -#define DEFAULT_CONFIG_FILE_LOCAL ".polypaudio.conf" -#define AUTOSPAWN_CONFIG_FILE_LOCAL ".polypaudio-autospawn.conf" - char* default_file(const char *envvar, const char *global, const char *local) { char *p, *h; @@ -80,9 +83,8 @@ char* default_file(const char *envvar, const char *global, const char *local) { return pa_xstrdup(p); if ((h = getenv("HOME"))) { - struct stat st; p = pa_sprintf_malloc("%s/%s", h, local); - if (stat(p, &st) >= 0) + if (!access(p, F_OK)) return p; pa_xfree(p); @@ -91,26 +93,12 @@ char* default_file(const char *envvar, const char *global, const char *local) { return pa_xstrdup(global); } -char *default_config_file(void) { - char *b; - int autospawned = 0; - - if ((b = getenv(ENV_AUTOSPAWNED))) - autospawned = pa_parse_boolean(b) > 0; - - return default_file(ENV_CONFIG_FILE, - autospawned ? AUTOSPAWN_CONFIG_FILE : DEFAULT_CONFIG_FILE, - autospawned ? AUTOSPAWN_CONFIG_FILE_LOCAL : DEFAULT_CONFIG_FILE_LOCAL); - -} - -char *default_script_file(void) { - return default_file(ENV_SCRIPT_FILE, DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_LOCAL); -} - struct pa_conf* pa_conf_new(void) { struct pa_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); - c->default_script_file = default_script_file(); + c->default_script_file = default_file(ENV_SCRIPT_FILE, DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER); +#ifdef DLSEARCHPATH + c->dl_search_path = pa_xstrdup(DLSEARCHPATH); +#endif return c; } @@ -122,166 +110,104 @@ void pa_conf_free(struct pa_conf *c) { pa_xfree(c); } -#define WHITESPACE " \t\n" -#define COMMENTS "#;\n" - -#define PARSE_BOOLEAN(t, v) \ - do { \ - if (!strcmp(lvalue, t)) { \ - int b; \ - if ((b = pa_parse_boolean(rvalue)) < 0) \ - goto fail; \ - c->v = b; \ - return 0; \ - } \ - } while (0) - -#define PARSE_STRING(t, v) \ - do { \ - if (!strcmp(lvalue, t)) { \ - pa_xfree(c->v); \ - c->v = *rvalue ? pa_xstrdup(rvalue) : NULL; \ - return 0; \ - } \ - } while (0) - -#define PARSE_INTEGER(t, v) \ - do { \ - if (!strcmp(lvalue, t)) { \ - char *x = NULL; \ - int i = strtol(rvalue, &x, 0); \ - if (!x || *x) \ - goto fail; \ - c->v = i; \ - return 0; \ - } \ - } while(0) - -static int next_assignment(struct pa_conf *c, char *lvalue, char *rvalue, unsigned n) { - PARSE_BOOLEAN("daemonize", daemonize); - PARSE_BOOLEAN("fail", fail); - PARSE_BOOLEAN("verbose", verbose); - PARSE_BOOLEAN("high-priority", high_priority); - PARSE_BOOLEAN("disallow-module-loading", disallow_module_loading); - - PARSE_INTEGER("exit-idle-time", exit_idle_time); - PARSE_INTEGER("module-idle-time", module_idle_time); - PARSE_INTEGER("scache-idle-time", scache_idle_time); +int parse_log_target(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { + struct pa_conf *c = data; + assert(filename && lvalue && rvalue && data); - PARSE_STRING("dl-search-path", dl_search_path); - PARSE_STRING("default-script-file", default_script_file); - - if (!strcmp(lvalue, "log-target")) { - if (!strcmp(rvalue, "auto")) - c->auto_log_target = 1; - else if (!strcmp(rvalue, "syslog")) { - c->auto_log_target = 0; - c->log_target = PA_LOG_SYSLOG; - } else if (!strcmp(rvalue, "stderr")) { - c->auto_log_target = 0; - c->log_target = PA_LOG_STDERR; - } else - goto fail; - - return 0; + if (!strcmp(rvalue, "auto")) + c->auto_log_target = 1; + else if (!strcmp(rvalue, "syslog")) { + c->auto_log_target = 0; + c->log_target = PA_LOG_SYSLOG; + } else if (!strcmp(rvalue, "stderr")) { + c->auto_log_target = 0; + c->log_target = PA_LOG_STDERR; + } else { + pa_log(__FILE__": [%s:%u] Invalid log target '%s'.\n", filename, line, rvalue); + return -1; } - -fail: - pa_log(__FILE__": line %u: parse error.\n", n); - return -1; -} - -#undef PARSE_STRING -#undef PARSE_BOOLEAN - -static int in_string(char c, const char *s) { - for (; *s; s++) - if (*s == c) - return 1; return 0; } -static char *strip(char *s) { - char *b = s+strspn(s, WHITESPACE); - char *e, *l = NULL; - - for (e = b; *e; e++) - if (!in_string(*e, WHITESPACE)) - l = e; - - if (l) - *(l+1) = 0; - - return b; -} - -static int parse_line(struct pa_conf *conf, char *l, unsigned n) { - char *e, *c, *b = l+strspn(l, WHITESPACE); - - if ((c = strpbrk(b, COMMENTS))) - *c = 0; - - if (!*b) - return 0; - - if (!(e = strchr(b, '='))) { - pa_log(__FILE__": line %u: missing '='.\n", n); +int parse_resample_method(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { + struct pa_conf *c = data; + assert(filename && lvalue && rvalue && data); + + if (!strcmp(rvalue, "sinc-best-quality")) + c->resample_method = SRC_SINC_BEST_QUALITY; + else if (!strcmp(rvalue, "sinc-medium-quality")) + c->resample_method = SRC_SINC_MEDIUM_QUALITY; + else if (!strcmp(rvalue, "sinc-fastest")) + c->resample_method = SRC_SINC_FASTEST; + else if (!strcmp(rvalue, "zero-order-hold")) + c->resample_method = SRC_ZERO_ORDER_HOLD; + else if (!strcmp(rvalue, "linear")) + c->resample_method = SRC_LINEAR; + else { + pa_log(__FILE__": [%s:%u] Inavalid resample method '%s'.\n", filename, line, rvalue); return -1; } - *e = 0; - e++; - - return next_assignment(conf, strip(b), strip(e), n); + return 0; } - int pa_conf_load(struct pa_conf *c, const char *filename) { - FILE *f; - int r = 0; - unsigned n = 0; char *def = NULL; - assert(c); + int r; + const struct pa_config_item table[] = { + { "verbose", pa_config_parse_bool, &c->verbose }, + { "daemonize", pa_config_parse_bool, &c->daemonize }, + { "fail", pa_config_parse_bool, &c->fail }, + { "high-priority", pa_config_parse_bool, &c->high_priority }, + { "disallow-module-loading", pa_config_parse_bool, &c->disallow_module_loading }, + { "exit-idle-time", pa_config_parse_int, &c->exit_idle_time }, + { "module-idle-time", pa_config_parse_int, &c->module_idle_time }, + { "scache-idle-time", pa_config_parse_int, &c->scache_idle_time }, + { "dl-search-path", pa_config_parse_string, &c->dl_search_path }, + { "default-script-file", pa_config_parse_string, &c->default_script_file }, + { "log-target", parse_log_target, c }, + { "resample-method", parse_resample_method, c }, + { NULL, NULL, NULL }, + }; + if (!filename) - filename = def = default_config_file(); + filename = def = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER); + + r = pa_config_parse(filename, table, NULL); + pa_xfree(def); + return r; +} - if (!(f = fopen(filename, "r"))) { - if (errno != ENOENT) - pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno)); +int pa_conf_env(struct pa_conf *c) { + char *e; - goto finish; + if ((e = getenv(ENV_DL_SEARCH_PATH))) { + pa_xfree(c->dl_search_path); + c->dl_search_path = pa_xstrdup(e); } - - while (!feof(f)) { - char l[256]; - if (!fgets(l, sizeof(l), f)) { - if (!feof(f)) - pa_log(__FILE__": WARNING: failed to read configuration file '%s': %s\n", filename, strerror(errno)); - - break; - } - - if (parse_line(c, l, ++n) < 0) - r = -1; + if ((e = getenv(ENV_SCRIPT_FILE))) { + pa_xfree(c->default_script_file); + c->default_script_file = pa_xstrdup(e); } - -finish: - if (f) - fclose(f); - - pa_xfree(def); - - return r; + return 0; } char *pa_conf_dump(struct pa_conf *c) { struct pa_strbuf *s = pa_strbuf_new(); char *d; - d = default_config_file(); + static const char const* resample_methods[] = { + "sinc-best-quality", + "sinc-medium-quality", + "sinc-fastest", + "zero-order-hold", + "linear" + }; + + d = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER); pa_strbuf_printf(s, "### Default configuration file: %s ###\n", d); pa_strbuf_printf(s, "verbose = %i\n", !!c->verbose); @@ -295,6 +221,9 @@ char *pa_conf_dump(struct pa_conf *c) { pa_strbuf_printf(s, "dl-search-path = %s\n", c->dl_search_path ? c->dl_search_path : ""); pa_strbuf_printf(s, "default-script-file = %s\n", c->default_script_file); pa_strbuf_printf(s, "log-target = %s\n", c->auto_log_target ? "auto" : (c->log_target == PA_LOG_SYSLOG ? "syslog" : "stderr")); + + assert(c->resample_method <= 4 && c->resample_method >= 0); + pa_strbuf_printf(s, "resample-method = %s\n", resample_methods[c->resample_method]); pa_xfree(d); diff --git a/polyp/conf.h b/polyp/conf.h index dafb3797..ace5396d 100644 --- a/polyp/conf.h +++ b/polyp/conf.h @@ -45,6 +45,7 @@ struct pa_conf { auto_log_target; char *script_commands, *dl_search_path, *default_script_file; enum pa_log_target log_target; + int resample_method; }; struct pa_conf* pa_conf_new(void); diff --git a/polyp/config b/polyp/config deleted file mode 100644 index b404bc40..00000000 --- a/polyp/config +++ /dev/null @@ -1,61 +0,0 @@ -# $Id$ -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with polypaudio; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -## Configuration file for polypaudio. Default values are commented out. -## Use either ; or # for commenting - -# Extra verbositiy -; verbose = 0 - -## Daemonize after startup -; daemonize = 0 - -## Quit if startup fails -; fail = 1 - -## Renice the daemon to level -15 and try to get SCHED_FIFO -## scheduling. This a good idea if you hear annyoing noise in the -## playback. However, this is a certain security issue, since it works -## when called SUID root only. root is dropped immediately after gaining -## the nice level and SCHED_FIFO scheduling on startup. -high-priority = 0 - -## Disallow module loading after startup -; disallow-module-loading = 0 - -## Terminate the daemon after the last client quit and this time -## passed. Use a negative value to disable this feature. -; exit-idle-time = -1 - -## Unload autoloaded modules after being idle for this time -module-idle-time = 20 - -## The path were to look for dynamic shared objects (DSOs aka plugins). -## Specify an empty string for the default search path. You may specify -## more than one path seperated by colons. -; dl-search-path = - -## The default script file to load. Specify an empty string for not -## loading a default script file -; default-script-file = /etc/polyp/default.pa - -## The default log target. Use either "stderr", "syslog" or -## "auto". The latter is equivalent to "sylog" in case daemonize is -## true, otherwise to "stderr". -; log-target = auto diff --git a/polyp/config-client.c b/polyp/config-client.c new file mode 100644 index 00000000..758927f3 --- /dev/null +++ b/polyp/config-client.c @@ -0,0 +1,138 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include + +#include "config-client.h" +#include "xmalloc.h" +#include "log.h" +#include "confparser.h" +#include "util.h" + +#ifndef DEFAULT_CLIENT_CONFIG_FILE +#define DEFAULT_CLIENT_CONFIG_FILE "/etc/polypaudio/client.conf" +#endif + +#ifndef DEFAULT_CLIENT_CONFIG_FILE_USER +#define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio/client.conf" +#endif + +#define ENV_CLIENT_CONFIG_FILE "POLYP_CLIENTCONFIG" +#define ENV_DEFAULT_SINK "POLYP_SINK" +#define ENV_DEFAULT_SOURCE "POLYP_SOURCE" +#define ENV_DEFAULT_SERVER "POLYP_SERVER" +#define ENV_DAEMON_BINARY "POLYP_BINARY" + + +static const struct pa_client_conf default_conf = { + .daemon_binary = NULL, + .extra_arguments = NULL, + .default_sink = NULL, + .default_source = NULL, + .default_server = NULL, + .autospawn = 0 +}; + +struct pa_client_conf *pa_client_conf_new(void) { + struct pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); + + c->daemon_binary = pa_xstrdup(POLYPAUDIO_BINARY); + c->extra_arguments = pa_xstrdup("--daemonize=yes --log-target=syslog"); + + return c; +} + +void pa_client_conf_free(struct pa_client_conf *c) { + assert(c); + pa_xfree(c->daemon_binary); + pa_xfree(c->extra_arguments); + pa_xfree(c->default_sink); + pa_xfree(c->default_source); + pa_xfree(c->default_server); + pa_xfree(c); +} +int pa_client_conf_load(struct pa_client_conf *c, const char *filename) { + char *def = NULL; + int r; + + const struct pa_config_item table[] = { + { "daemon-binary", pa_config_parse_string, &c->daemon_binary }, + { "extra-arguments", pa_config_parse_string, &c->extra_arguments }, + { "default-sink", pa_config_parse_string, &c->default_sink }, + { "default-source", pa_config_parse_string, &c->default_source }, + { "default-server", pa_config_parse_string, &c->default_server }, + { "autospawn", pa_config_parse_bool, &c->autospawn }, + { NULL, NULL, NULL }, + }; + + if (!filename) + filename = getenv(ENV_CLIENT_CONFIG_FILE); + + if (!filename) { + char *h; + + if ((h = getenv("HOME"))) { + def = pa_sprintf_malloc("%s/%s", h, DEFAULT_CLIENT_CONFIG_FILE_USER); + + if (!access(def, F_OK)) + filename = def; + else { + pa_xfree(def); + def = NULL; + } + } + } + + if (!filename) + filename = DEFAULT_CLIENT_CONFIG_FILE; + + r = pa_config_parse(filename, table, NULL); + pa_xfree(def); + return r; +} + +int pa_client_conf_env(struct pa_client_conf *c) { + char *e; + + if ((e = getenv(ENV_DEFAULT_SINK))) { + pa_xfree(c->default_sink); + c->default_sink = pa_xstrdup(e); + } + + if ((e = getenv(ENV_DEFAULT_SOURCE))) { + pa_xfree(c->default_source); + c->default_source = pa_xstrdup(e); + } + + if ((e = getenv(ENV_DEFAULT_SERVER))) { + pa_xfree(c->default_server); + c->default_server = pa_xstrdup(e); + } + + if ((e = getenv(ENV_DAEMON_BINARY))) { + pa_xfree(c->daemon_binary); + c->daemon_binary = pa_xstrdup(e); + } + + return 0; +} diff --git a/polyp/config-client.h b/polyp/config-client.h new file mode 100644 index 00000000..1b1c519d --- /dev/null +++ b/polyp/config-client.h @@ -0,0 +1,36 @@ +#ifndef fooconfigclienthfoo +#define fooconfigclienthfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +struct pa_client_conf { + char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server; + int autospawn; +}; + +struct pa_client_conf *pa_client_conf_new(void); +void pa_client_conf_free(struct pa_client_conf *c); + +int pa_client_conf_load(struct pa_client_conf *c, const char *filename); +int pa_client_conf_env(struct pa_client_conf *c); + +#endif diff --git a/polyp/confparser.c b/polyp/confparser.c new file mode 100644 index 00000000..8f551b95 --- /dev/null +++ b/polyp/confparser.c @@ -0,0 +1,168 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +#include "confparser.h" +#include "log.h" +#include "util.h" +#include "xmalloc.h" + +#define WHITESPACE " \t\n" +#define COMMENTS "#;\n" + +static int next_assignment(const char *filename, unsigned line, const struct pa_config_item *t, const char *lvalue, const char *rvalue, void *userdata) { + assert(filename && t && lvalue && rvalue); + + for (; t->parse; t++) + if (!strcmp(lvalue, t->lvalue)) + return t->parse(filename, line, lvalue, rvalue, t->data, userdata); + + pa_log(__FILE__": [%s:%u] Unknown lvalue '%s'.\n", filename, line, lvalue); + + return -1; +} + +static int in_string(char c, const char *s) { + assert(s); + + for (; *s; s++) + if (*s == c) + return 1; + + return 0; +} + +static char *strip(char *s) { + char *b = s+strspn(s, WHITESPACE); + char *e, *l = NULL; + + for (e = b; *e; e++) + if (!in_string(*e, WHITESPACE)) + l = e; + + if (l) + *(l+1) = 0; + + return b; +} + +static int parse_line(const char *filename, unsigned line, const struct pa_config_item *t, char *l, void *userdata) { + char *e, *c, *b = l+strspn(l, WHITESPACE); + + if ((c = strpbrk(b, COMMENTS))) + *c = 0; + + if (!*b) + return 0; + + if (!(e = strchr(b, '='))) { + pa_log(__FILE__": [%s:%u] Missing '='.\n", filename, line); + return -1; + } + + *e = 0; + e++; + + return next_assignment(filename, line, t, strip(b), strip(e), userdata); +} + + +int pa_config_parse(const char *filename, const struct pa_config_item *t, void *userdata) { + FILE *f; + int r = -1; + unsigned line = 0; + assert(filename && t); + + if (!(f = fopen(filename, "r"))) { + if (errno == ENOENT) { + r = 0; + goto finish; + } + + pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno)); + goto finish; + } + + while (!feof(f)) { + char l[256]; + if (!fgets(l, sizeof(l), f)) { + if (feof(f)) + break; + + pa_log(__FILE__": WARNING: failed to read configuration file '%s': %s\n", filename, strerror(errno)); + goto finish; + } + + if (parse_line(filename, ++line, t, l, userdata) < 0) + goto finish; + } + + r = 0; + +finish: + + if (f) + fclose(f); + + return r; +} + +int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { + int *i = data, k; + char *x = NULL; + assert(filename && lvalue && rvalue && data); + + k = strtol(rvalue, &x, 0); + if (!*rvalue || !x || *x) { + pa_log(__FILE__": [%s:%u] Failed to parse numeric value: %s\n", filename, line, rvalue); + return -1; + } + + *i = k; + return 0; +} + +int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { + int *b = data, k; + assert(filename && lvalue && rvalue && data); + + if ((k = pa_parse_boolean(rvalue)) < 0) { + pa_log(__FILE__": [%s:%u] Failed to parse boolean value: %s\n", filename, line, rvalue); + return -1; + } + + *b = k; + + return 0; +} + +int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { + char **s = data; + assert(filename && lvalue && rvalue && data); + + pa_xfree(*s); + *s = *rvalue ? pa_xstrdup(rvalue) : NULL; + return 0; +} diff --git a/polyp/confparser.h b/polyp/confparser.h new file mode 100644 index 00000000..a0eb52d0 --- /dev/null +++ b/polyp/confparser.h @@ -0,0 +1,37 @@ +#ifndef fooconfparserhfoo +#define fooconfparserhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +struct pa_config_item { + const char *lvalue; + int (*parse)(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); + void *data; +}; + +int pa_config_parse(const char *filename, const struct pa_config_item *t, void *userdata); + +int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); +int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); +int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); + +#endif diff --git a/polyp/core.c b/polyp/core.c index 58035087..cf2d383c 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "core.h" #include "module.h" @@ -79,6 +80,8 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->exit_idle_time = -1; c->module_idle_time = 20; c->scache_idle_time = 20; + + c->resample_method = SRC_SINC_FASTEST; pa_check_signal_is_blocked(SIGPIPE); diff --git a/polyp/core.h b/polyp/core.h index 980888f6..62959d0a 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -53,6 +53,8 @@ struct pa_core { struct pa_time_event *quit_event; struct pa_time_event *scache_auto_unload_event; + + int resample_method; }; struct pa_core* pa_core_new(struct pa_mainloop_api *m); diff --git a/polyp/daemon.conf b/polyp/daemon.conf new file mode 100644 index 00000000..a277bb4f --- /dev/null +++ b/polyp/daemon.conf @@ -0,0 +1,67 @@ +# $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +## Configuration file for the polypaudio daemon. Default values are +## commented out. Use either ; or # for commenting + +# Extra verbositiy +; verbose = 0 + +## Daemonize after startup +; daemonize = 0 + +## Quit if startup fails +; fail = 1 + +## Renice the daemon to level -15 and try to get SCHED_FIFO +## scheduling. This a good idea if you hear annyoing noise in the +## playback. However, this is a certain security issue, since it works +## when called SUID root only. root is dropped immediately after gaining +## the nice level and SCHED_FIFO scheduling on startup. +high-priority = 0 + +## Disallow module loading after startup +; disallow-module-loading = 0 + +## Terminate the daemon after the last client quit and this time +## passed. Use a negative value to disable this feature. +; exit-idle-time = -1 + +## Unload autoloaded modules after being idle for this time +module-idle-time = 20 + +## The path were to look for dynamic shared objects (DSOs aka +## plugins). You may specify more than one path seperated by +## colons. +; dl-search-path = @DLSEARCHPATH@ + +## The default script file to load. Specify an empty string for not +## loading a default script file. The +; default-script-file = @DEFAULT_CONFIG_FILE@ + +## The default log target. Use either "stderr", "syslog" or +## "auto". The latter is equivalent to "sylog" in case daemonize is +## true, otherwise to "stderr". +; log-target = auto + +## The resampling algorithm to use. Use one of sinc-best-quality, +## sinc-medium-quality, sinc-fastest, zero-order-hold, linear. See +## the documentation of libsamplerate for an explanation fot the +## different methods. +; resample-method = sinc-fastest diff --git a/polyp/main.c b/polyp/main.c index e44fc013..3b25a030 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -119,10 +119,6 @@ int main(int argc, char *argv[]) { if (conf->dl_search_path) lt_dlsetsearchpath(conf->dl_search_path); -#ifdef DLSEARCHPATH - else - lt_dlsetsearchpath(DLSEARCHPATH); -#endif switch (conf->cmd) { case PA_CMD_DUMP_MODULES: @@ -245,6 +241,8 @@ int main(int argc, char *argv[]) { c->disallow_module_loading = conf->disallow_module_loading; c->exit_idle_time = conf->exit_idle_time; c->module_idle_time = conf->module_idle_time; + c->scache_idle_time = conf->scache_idle_time; + c->resample_method = conf->resample_method; pa_log(__FILE__": Daemon startup complete.\n"); if (pa_mainloop_run(mainloop, &retval) < 0) diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 64f9074c..04ee3d89 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -47,6 +47,9 @@ #include "util.h" #include "xmalloc.h" #include "log.h" +#include "config-client.h" + +#define DEFAULT_SERVER "/tmp/polypaudio/native" static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_REQUEST] = { pa_command_request }, @@ -87,6 +90,11 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * c->local = -1; pa_check_signal_is_blocked(SIGPIPE); + + c->conf = pa_client_conf_new(); + pa_client_conf_load(c->conf, NULL); + pa_client_conf_env(c->conf); + return c; } @@ -114,6 +122,9 @@ static void context_free(struct pa_context *c) { pa_dynarray_free(c->playback_streams, NULL, NULL); pa_memblock_stat_unref(c->memblock_stat); + + if (c->conf) + pa_client_conf_free(c->conf); pa_xfree(c->name); pa_xfree(c); @@ -366,7 +377,7 @@ static struct sockaddr *resolve_server(const char *server, size_t *len) { return sa; } -static int is_running(void) { +static int default_server_is_running(void) { struct stat st; if (DEFAULT_SERVER[0] != '/') @@ -404,24 +415,39 @@ static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api goto fail; } else if (!pid) { - char t[128]; - char *p; /* Child */ + + char t[128]; + const char *state = NULL; +#define MAX_ARGS 64 + char *argv[MAX_ARGS+1]; + int n = 0; close(fds[0]); if (api && api->atfork) api->atfork(); - if (!(p = getenv(ENV_DEFAULT_BINARY))) - p = POLYPAUDIO_BINARY; - snprintf(t, sizeof(t), "%s=1", ENV_AUTOSPAWNED); - putenv(t); - + putenv(t); + + argv[n++] = c->conf->daemon_binary; + snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]); - execl(p, p, "--daemonize=yes", "--log-target=syslog", t, NULL); - + argv[n++] = pa_xstrdup(t); + + while (n < MAX_ARGS) { + char *a; + + if (!(a = pa_split_spaces(c->conf->extra_arguments, &state))) + break; + + argv[n++] = a; + } + + argv[n++] = NULL; + + execv(argv[0], argv); exit(1); } @@ -468,19 +494,12 @@ int pa_context_connect(struct pa_context *c, const char *server, int spawn, cons assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED); if (!server) - if (!(server = getenv(ENV_DEFAULT_SERVER))) { - if (spawn && !is_running()) { - char *b; - - if ((b = getenv(ENV_DISABLE_AUTOSPAWN))) - if (pa_parse_boolean(b) > 1) - return -1; - - return context_connect_spawn(c, api); - } + server = c->conf->default_server; - server = DEFAULT_SERVER; - } + if (!server && spawn && c->conf->autospawn && !default_server_is_running()) + return context_connect_spawn(c, api); + + server = DEFAULT_SERVER; pa_context_ref(c); diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 4c44ee98..1d0e41d8 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -33,6 +33,7 @@ #include "polyplib-operation.h" #include "llist.h" #include "native-common.h" +#include "config-client.h" #define DEFAULT_TLENGTH (10240*8) #define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2) @@ -41,14 +42,8 @@ #define DEFAULT_FRAGSIZE 1024 #define DEFAULT_TIMEOUT (5*60) -#define DEFAULT_SERVER "/tmp/polypaudio/native" #define DEFAULT_PORT "4713" -#define ENV_DEFAULT_SINK "POLYP_SINK" -#define ENV_DEFAULT_SOURCE "POLYP_SOURCE" -#define ENV_DEFAULT_SERVER "POLYP_SERVER" -#define ENV_DEFAULT_BINARY "POLYP_BINARY" -#define ENV_DISABLE_AUTOSPAWN "POLYP_NOAUTOSPAWN" #define ENV_AUTOSPAWNED "POLYP_AUTOSPAWNED" struct pa_context { @@ -80,6 +75,8 @@ struct pa_context { struct pa_memblock_stat *memblock_stat; int local; + + struct pa_client_conf *conf; }; struct pa_stream { diff --git a/polyp/polyplib-scache.c b/polyp/polyplib-scache.c index 8215eaec..7221420c 100644 --- a/polyp/polyplib-scache.c +++ b/polyp/polyplib-scache.c @@ -88,7 +88,7 @@ struct pa_operation * pa_context_play_sample(struct pa_context *c, const char *n o->userdata = userdata; if (!dev) - dev = getenv(ENV_DEFAULT_SINK); + dev = c->conf->default_sink; t = pa_tagstruct_new(NULL, 0); assert(t); diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 532d1700..6055a220 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -217,7 +217,7 @@ static void create_stream(struct pa_stream *s, const char *dev, const struct pa_ assert(s && s->ref >= 1 && s->state == PA_STREAM_DISCONNECTED); pa_stream_ref(s); - + if (attr) s->buffer_attr = *attr; else { @@ -235,9 +235,9 @@ static void create_stream(struct pa_stream *s, const char *dev, const struct pa_ if (!dev) { if (s->direction == PA_STREAM_PLAYBACK) - dev = getenv(ENV_DEFAULT_SINK); + dev = s->context->conf->default_sink; else - dev = getenv(ENV_DEFAULT_SOURCE); + dev = s->context->conf->default_source; } pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); diff --git a/polyp/resampler.c b/polyp/resampler.c index 4742ce21..e8dd01b9 100644 --- a/polyp/resampler.c +++ b/polyp/resampler.c @@ -47,7 +47,7 @@ struct pa_resampler { struct pa_memblock_stat *memblock_stat; }; -struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b, struct pa_memblock_stat *s) { +struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b, struct pa_memblock_stat *s, int resample_method) { struct pa_resampler *r = NULL; int err; assert(a && b && pa_sample_spec_valid(a) && pa_sample_spec_valid(b)); @@ -67,7 +67,7 @@ struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const stru r->i_buf = r->o_buf = NULL; r->i_alloc = r->o_alloc = 0; - r->src_state = src_new(SRC_SINC_FASTEST, r->channels, &err); + r->src_state = src_new(resample_method, r->channels, &err); if (err != 0 || !r->src_state) goto fail; diff --git a/polyp/resampler.h b/polyp/resampler.h index a6ef30df..b984a4f6 100644 --- a/polyp/resampler.h +++ b/polyp/resampler.h @@ -28,7 +28,7 @@ struct pa_resampler; -struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b, struct pa_memblock_stat *s); +struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b, struct pa_memblock_stat *s, int resample_method); void pa_resampler_free(struct pa_resampler *r); size_t pa_resampler_request(struct pa_resampler *r, size_t out_length); diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 2541c821..486a2044 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -49,7 +49,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con } if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec)) - if (!(resampler = pa_resampler_new(spec, &s->sample_spec, s->core->memblock_stat))) + if (!(resampler = pa_resampler_new(spec, &s->sample_spec, s->core->memblock_stat, s->core->resample_method))) return NULL; i = pa_xmalloc(sizeof(struct pa_sink_input)); diff --git a/polyp/source-output.c b/polyp/source-output.c index 1db88d3c..252c155c 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -45,7 +45,7 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n } if (!pa_sample_spec_equal(&s->sample_spec, spec)) - if (!(resampler = pa_resampler_new(&s->sample_spec, spec, s->core->memblock_stat))) + if (!(resampler = pa_resampler_new(&s->sample_spec, spec, s->core->memblock_stat, s->core->resample_method))) return NULL; o = pa_xmalloc(sizeof(struct pa_source_output)); diff --git a/polyp/util.c b/polyp/util.c index 24773a7b..86f18f25 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -390,6 +390,23 @@ char *pa_split(const char *c, const char *delimiter, const char**state) { return pa_xstrndup(current, l); } +#define WHITESPACE " \t\n" + +char *pa_split_spaces(const char *c, const char **state) { + const char *current = *state ? *state : c; + size_t l; + + if (*current) + return NULL; + + current += strspn(current, WHITESPACE); + l = strcspn(current, WHITESPACE); + + *state = current+l; + + return pa_xstrndup(current, l); +} + const char *pa_strsignal(int sig) { switch(sig) { case SIGINT: return "SIGINT"; diff --git a/polyp/util.h b/polyp/util.h index f5cda200..07072df6 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -60,6 +60,7 @@ int pa_fd_set_cloexec(int fd, int b); int pa_parse_boolean(const char *s); char *pa_split(const char *c, const char*delimiters, const char **state); +char *pa_split_spaces(const char *c, const char **state); const char *pa_strsignal(int sig); -- cgit From 24f378150766faf50445427d6eb02f363a9afc24 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 17 Sep 2004 19:52:38 +0000 Subject: make daemon.conf/client.conf autogenerated git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@211 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 9 ++++++- polyp/client.conf | 39 ------------------------------ polyp/client.conf.in | 39 ++++++++++++++++++++++++++++++ polyp/daemon.conf | 67 ---------------------------------------------------- polyp/daemon.conf.in | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 114 insertions(+), 107 deletions(-) delete mode 100644 polyp/client.conf create mode 100644 polyp/client.conf.in delete mode 100644 polyp/daemon.conf create mode 100644 polyp/daemon.conf.in diff --git a/polyp/Makefile.am b/polyp/Makefile.am index d49c7c48..76f4f2c7 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -32,7 +32,7 @@ AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\" AM_LDADD=$(PTHREAD_LIBS) -lm AM_LIBADD=$(PTHREAD_LIBS) -lm -EXTRA_DIST = default.pa daemon.conf client.conf config depmod.py esdcompat.sh.in +EXTRA_DIST = default.pa daemon.conf.in client.conf.in config depmod.py esdcompat.sh.in bin_PROGRAMS = polypaudio pacat pactl bin_SCRIPTS = esdcompat.sh noinst_PROGRAMS = \ @@ -541,6 +541,13 @@ esdcompat.sh: esdcompat.sh.in Makefile sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ -e 's,@POLYPAUDIO_BINARY\@,$(bindir)/polypaudio,g' < $< > $@ + +client.conf: client.conf.in Makefile + sed -e 's,@POLYPAUDIO_BINARY\@,$(bindir)/polypaudio,g' < $< > $@ + +daemon.conf: daemon.conf.in Makefile + sed -e 's,@DLSEARCHPATH\@,$(modlibdir),g' \ + -e 's,@DEFAULT_CONFIG_FILE\@,$(polypconfdir)/daemon.conf,g' < $< > $@ install-exec-hook: chown root:root $(DESTDIR)$(bindir)/polypaudio diff --git a/polyp/client.conf b/polyp/client.conf deleted file mode 100644 index 070d75bd..00000000 --- a/polyp/client.conf +++ /dev/null @@ -1,39 +0,0 @@ -# $Id$ -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with polypaudio; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -## Configuration file for polypaudio clients. Default values are -## commented out. Use either ; or # for commenting - -## Path to the polypaudio daemon to run when autospawning. -; daemon_binary = @POLYPAUDIO_BINARY - -## Extra arguments to pass to the polypaudio daemon -; extra_arguments = --daemonize=yes --log-target=syslog - -## The default sink to connect to -; default_sink = - -## The default source to connect to -; default_source = - -## The default sever to connect to -; default_server = - -## Autospawn daemons? -; autospawn = 0 diff --git a/polyp/client.conf.in b/polyp/client.conf.in new file mode 100644 index 00000000..7ba6549b --- /dev/null +++ b/polyp/client.conf.in @@ -0,0 +1,39 @@ +# $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +## Configuration file for polypaudio clients. Default values are +## commented out. Use either ; or # for commenting + +## Path to the polypaudio daemon to run when autospawning. +; daemon_binary = @POLYPAUDIO_BINARY@ + +## Extra arguments to pass to the polypaudio daemon +; extra_arguments = --daemonize=yes --log-target=syslog + +## The default sink to connect to +; default_sink = + +## The default source to connect to +; default_source = + +## The default sever to connect to +; default_server = + +## Autospawn daemons? +; autospawn = 0 diff --git a/polyp/daemon.conf b/polyp/daemon.conf deleted file mode 100644 index a277bb4f..00000000 --- a/polyp/daemon.conf +++ /dev/null @@ -1,67 +0,0 @@ -# $Id$ -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with polypaudio; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -## Configuration file for the polypaudio daemon. Default values are -## commented out. Use either ; or # for commenting - -# Extra verbositiy -; verbose = 0 - -## Daemonize after startup -; daemonize = 0 - -## Quit if startup fails -; fail = 1 - -## Renice the daemon to level -15 and try to get SCHED_FIFO -## scheduling. This a good idea if you hear annyoing noise in the -## playback. However, this is a certain security issue, since it works -## when called SUID root only. root is dropped immediately after gaining -## the nice level and SCHED_FIFO scheduling on startup. -high-priority = 0 - -## Disallow module loading after startup -; disallow-module-loading = 0 - -## Terminate the daemon after the last client quit and this time -## passed. Use a negative value to disable this feature. -; exit-idle-time = -1 - -## Unload autoloaded modules after being idle for this time -module-idle-time = 20 - -## The path were to look for dynamic shared objects (DSOs aka -## plugins). You may specify more than one path seperated by -## colons. -; dl-search-path = @DLSEARCHPATH@ - -## The default script file to load. Specify an empty string for not -## loading a default script file. The -; default-script-file = @DEFAULT_CONFIG_FILE@ - -## The default log target. Use either "stderr", "syslog" or -## "auto". The latter is equivalent to "sylog" in case daemonize is -## true, otherwise to "stderr". -; log-target = auto - -## The resampling algorithm to use. Use one of sinc-best-quality, -## sinc-medium-quality, sinc-fastest, zero-order-hold, linear. See -## the documentation of libsamplerate for an explanation fot the -## different methods. -; resample-method = sinc-fastest diff --git a/polyp/daemon.conf.in b/polyp/daemon.conf.in new file mode 100644 index 00000000..a277bb4f --- /dev/null +++ b/polyp/daemon.conf.in @@ -0,0 +1,67 @@ +# $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +## Configuration file for the polypaudio daemon. Default values are +## commented out. Use either ; or # for commenting + +# Extra verbositiy +; verbose = 0 + +## Daemonize after startup +; daemonize = 0 + +## Quit if startup fails +; fail = 1 + +## Renice the daemon to level -15 and try to get SCHED_FIFO +## scheduling. This a good idea if you hear annyoing noise in the +## playback. However, this is a certain security issue, since it works +## when called SUID root only. root is dropped immediately after gaining +## the nice level and SCHED_FIFO scheduling on startup. +high-priority = 0 + +## Disallow module loading after startup +; disallow-module-loading = 0 + +## Terminate the daemon after the last client quit and this time +## passed. Use a negative value to disable this feature. +; exit-idle-time = -1 + +## Unload autoloaded modules after being idle for this time +module-idle-time = 20 + +## The path were to look for dynamic shared objects (DSOs aka +## plugins). You may specify more than one path seperated by +## colons. +; dl-search-path = @DLSEARCHPATH@ + +## The default script file to load. Specify an empty string for not +## loading a default script file. The +; default-script-file = @DEFAULT_CONFIG_FILE@ + +## The default log target. Use either "stderr", "syslog" or +## "auto". The latter is equivalent to "sylog" in case daemonize is +## true, otherwise to "stderr". +; log-target = auto + +## The resampling algorithm to use. Use one of sinc-best-quality, +## sinc-medium-quality, sinc-fastest, zero-order-hold, linear. See +## the documentation of libsamplerate for an explanation fot the +## different methods. +; resample-method = sinc-fastest -- cgit From f0779587478f5c4012dc5c9debc8dc562c81f967 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 17 Sep 2004 20:06:17 +0000 Subject: rename some stuff git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@212 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 4 +- polyp/client-conf.c | 138 +++++++++++++++++++++++++++ polyp/client-conf.h | 36 ++++++++ polyp/cmdline.c | 2 +- polyp/cmdline.h | 4 +- polyp/conf.c | 231 ---------------------------------------------- polyp/conf.h | 57 ------------ polyp/config-client.c | 138 --------------------------- polyp/config-client.h | 36 -------- polyp/daemon-conf.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++ polyp/daemon-conf.h | 58 ++++++++++++ polyp/dumpmodules.c | 4 +- polyp/dumpmodules.h | 4 +- polyp/main.c | 15 +-- polyp/polyplib-context.c | 2 +- polyp/polyplib-internal.h | 2 +- 16 files changed, 483 insertions(+), 479 deletions(-) create mode 100644 polyp/client-conf.c create mode 100644 polyp/client-conf.h delete mode 100644 polyp/conf.c delete mode 100644 polyp/conf.h delete mode 100644 polyp/config-client.c delete mode 100644 polyp/config-client.h create mode 100644 polyp/daemon-conf.c create mode 100644 polyp/daemon-conf.h diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 76f4f2c7..9dde211d 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -157,7 +157,7 @@ polypaudio_SOURCES = idxset.c idxset.h \ log.c log.h \ gcc-printf.h \ modinfo.c modinfo.h \ - conf.c conf.h \ + daemon-conf.c daemon-conf.h \ dumpmodules.c dumpmodules.h \ conparser.h confparser.c @@ -334,7 +334,7 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = polyplib.h \ llist.h \ log.c log.h \ gcc-printf.h \ - config-client.c config-client.h \ + client-conf.c client-conf.h \ confparser.c confparser.h libpolyp_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) diff --git a/polyp/client-conf.c b/polyp/client-conf.c new file mode 100644 index 00000000..cfc257c6 --- /dev/null +++ b/polyp/client-conf.c @@ -0,0 +1,138 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include + +#include "client-conf.h" +#include "xmalloc.h" +#include "log.h" +#include "confparser.h" +#include "util.h" + +#ifndef DEFAULT_CLIENT_CONFIG_FILE +#define DEFAULT_CLIENT_CONFIG_FILE "/etc/polypaudio/client.conf" +#endif + +#ifndef DEFAULT_CLIENT_CONFIG_FILE_USER +#define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio/client.conf" +#endif + +#define ENV_CLIENT_CONFIG_FILE "POLYP_CLIENTCONFIG" +#define ENV_DEFAULT_SINK "POLYP_SINK" +#define ENV_DEFAULT_SOURCE "POLYP_SOURCE" +#define ENV_DEFAULT_SERVER "POLYP_SERVER" +#define ENV_DAEMON_BINARY "POLYP_BINARY" + + +static const struct pa_client_conf default_conf = { + .daemon_binary = NULL, + .extra_arguments = NULL, + .default_sink = NULL, + .default_source = NULL, + .default_server = NULL, + .autospawn = 0 +}; + +struct pa_client_conf *pa_client_conf_new(void) { + struct pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); + + c->daemon_binary = pa_xstrdup(POLYPAUDIO_BINARY); + c->extra_arguments = pa_xstrdup("--daemonize=yes --log-target=syslog"); + + return c; +} + +void pa_client_conf_free(struct pa_client_conf *c) { + assert(c); + pa_xfree(c->daemon_binary); + pa_xfree(c->extra_arguments); + pa_xfree(c->default_sink); + pa_xfree(c->default_source); + pa_xfree(c->default_server); + pa_xfree(c); +} +int pa_client_conf_load(struct pa_client_conf *c, const char *filename) { + char *def = NULL; + int r; + + const struct pa_config_item table[] = { + { "daemon-binary", pa_config_parse_string, &c->daemon_binary }, + { "extra-arguments", pa_config_parse_string, &c->extra_arguments }, + { "default-sink", pa_config_parse_string, &c->default_sink }, + { "default-source", pa_config_parse_string, &c->default_source }, + { "default-server", pa_config_parse_string, &c->default_server }, + { "autospawn", pa_config_parse_bool, &c->autospawn }, + { NULL, NULL, NULL }, + }; + + if (!filename) + filename = getenv(ENV_CLIENT_CONFIG_FILE); + + if (!filename) { + char *h; + + if ((h = getenv("HOME"))) { + def = pa_sprintf_malloc("%s/%s", h, DEFAULT_CLIENT_CONFIG_FILE_USER); + + if (!access(def, F_OK)) + filename = def; + else { + pa_xfree(def); + def = NULL; + } + } + } + + if (!filename) + filename = DEFAULT_CLIENT_CONFIG_FILE; + + r = pa_config_parse(filename, table, NULL); + pa_xfree(def); + return r; +} + +int pa_client_conf_env(struct pa_client_conf *c) { + char *e; + + if ((e = getenv(ENV_DEFAULT_SINK))) { + pa_xfree(c->default_sink); + c->default_sink = pa_xstrdup(e); + } + + if ((e = getenv(ENV_DEFAULT_SOURCE))) { + pa_xfree(c->default_source); + c->default_source = pa_xstrdup(e); + } + + if ((e = getenv(ENV_DEFAULT_SERVER))) { + pa_xfree(c->default_server); + c->default_server = pa_xstrdup(e); + } + + if ((e = getenv(ENV_DAEMON_BINARY))) { + pa_xfree(c->daemon_binary); + c->daemon_binary = pa_xstrdup(e); + } + + return 0; +} diff --git a/polyp/client-conf.h b/polyp/client-conf.h new file mode 100644 index 00000000..6fd4a20d --- /dev/null +++ b/polyp/client-conf.h @@ -0,0 +1,36 @@ +#ifndef fooclientconfhfoo +#define fooclientconfhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +struct pa_client_conf { + char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server; + int autospawn; +}; + +struct pa_client_conf *pa_client_conf_new(void); +void pa_client_conf_free(struct pa_client_conf *c); + +int pa_client_conf_load(struct pa_client_conf *c, const char *filename); +int pa_client_conf_env(struct pa_client_conf *c); + +#endif diff --git a/polyp/cmdline.c b/polyp/cmdline.c index d429256f..7f8a947b 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -107,7 +107,7 @@ void pa_cmdline_help(const char *argv0) { " -n Don't load default script file\n", e); } -int pa_cmdline_parse(struct pa_conf *conf, int argc, char *const argv [], int *d) { +int pa_cmdline_parse(struct pa_daemon_conf *conf, int argc, char *const argv [], int *d) { struct pa_strbuf *buf = NULL; int c; assert(conf && argc && argv); diff --git a/polyp/cmdline.h b/polyp/cmdline.h index e4bd8af6..bfbae470 100644 --- a/polyp/cmdline.h +++ b/polyp/cmdline.h @@ -22,9 +22,9 @@ USA. ***/ -#include "conf.h" +#include "daemon-conf.h" -int pa_cmdline_parse(struct pa_conf*c, int argc, char *const argv [], int *d); +int pa_cmdline_parse(struct pa_daemon_conf*c, int argc, char *const argv [], int *d); void pa_cmdline_help(const char *argv0); diff --git a/polyp/conf.c b/polyp/conf.c deleted file mode 100644 index efc471af..00000000 --- a/polyp/conf.c +++ /dev/null @@ -1,231 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "conf.h" -#include "util.h" -#include "xmalloc.h" -#include "strbuf.h" -#include "confparser.h" - -#ifndef DEFAULT_SCRIPT_FILE -#define DEFAULT_SCRIPT_FILE "/etc/polypaudio/default.pa" -#endif - -#ifndef DEFAULT_SCRIPT_FILE_USER -#define DEFAULT_SCRIPT_FILE_USER ".polypaudio/default.pa" -#endif - -#ifndef DEFAULT_CONFIG_FILE -#define DEFAULT_CONFIG_FILE "/etc/polypaudio/daemon.conf" -#endif - -#ifndef DEFAULT_CONFIG_FILE_USER -#define DEFAULT_CONFIG_FILE_USER ".polypaudio/daemon.conf" -#endif - -#define ENV_SCRIPT_FILE "POLYP_SCRIPT" -#define ENV_CONFIG_FILE "POLYP_CONFIG" -#define ENV_DL_SEARCH_PATH "POLYP_DLPATH" - -static const struct pa_conf default_conf = { - .cmd = PA_CMD_DAEMON, - .daemonize = 0, - .fail = 1, - .verbose = 0, - .high_priority = 0, - .disallow_module_loading = 0, - .exit_idle_time = -1, - .module_idle_time = 20, - .scache_idle_time = 20, - .auto_log_target = 1, - .script_commands = NULL, - .dl_search_path = NULL, - .default_script_file = NULL, - .log_target = PA_LOG_SYSLOG, - .resample_method = SRC_SINC_FASTEST -}; - -char* default_file(const char *envvar, const char *global, const char *local) { - char *p, *h; - - assert(envvar && global && local); - - if ((p = getenv(envvar))) - return pa_xstrdup(p); - - if ((h = getenv("HOME"))) { - p = pa_sprintf_malloc("%s/%s", h, local); - if (!access(p, F_OK)) - return p; - - pa_xfree(p); - } - - return pa_xstrdup(global); -} - -struct pa_conf* pa_conf_new(void) { - struct pa_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); - c->default_script_file = default_file(ENV_SCRIPT_FILE, DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER); -#ifdef DLSEARCHPATH - c->dl_search_path = pa_xstrdup(DLSEARCHPATH); -#endif - return c; -} - -void pa_conf_free(struct pa_conf *c) { - assert(c); - pa_xfree(c->script_commands); - pa_xfree(c->dl_search_path); - pa_xfree(c->default_script_file); - pa_xfree(c); -} - -int parse_log_target(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { - struct pa_conf *c = data; - assert(filename && lvalue && rvalue && data); - - if (!strcmp(rvalue, "auto")) - c->auto_log_target = 1; - else if (!strcmp(rvalue, "syslog")) { - c->auto_log_target = 0; - c->log_target = PA_LOG_SYSLOG; - } else if (!strcmp(rvalue, "stderr")) { - c->auto_log_target = 0; - c->log_target = PA_LOG_STDERR; - } else { - pa_log(__FILE__": [%s:%u] Invalid log target '%s'.\n", filename, line, rvalue); - return -1; - } - - return 0; -} - -int parse_resample_method(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { - struct pa_conf *c = data; - assert(filename && lvalue && rvalue && data); - - if (!strcmp(rvalue, "sinc-best-quality")) - c->resample_method = SRC_SINC_BEST_QUALITY; - else if (!strcmp(rvalue, "sinc-medium-quality")) - c->resample_method = SRC_SINC_MEDIUM_QUALITY; - else if (!strcmp(rvalue, "sinc-fastest")) - c->resample_method = SRC_SINC_FASTEST; - else if (!strcmp(rvalue, "zero-order-hold")) - c->resample_method = SRC_ZERO_ORDER_HOLD; - else if (!strcmp(rvalue, "linear")) - c->resample_method = SRC_LINEAR; - else { - pa_log(__FILE__": [%s:%u] Inavalid resample method '%s'.\n", filename, line, rvalue); - return -1; - } - - return 0; -} - -int pa_conf_load(struct pa_conf *c, const char *filename) { - char *def = NULL; - int r; - - const struct pa_config_item table[] = { - { "verbose", pa_config_parse_bool, &c->verbose }, - { "daemonize", pa_config_parse_bool, &c->daemonize }, - { "fail", pa_config_parse_bool, &c->fail }, - { "high-priority", pa_config_parse_bool, &c->high_priority }, - { "disallow-module-loading", pa_config_parse_bool, &c->disallow_module_loading }, - { "exit-idle-time", pa_config_parse_int, &c->exit_idle_time }, - { "module-idle-time", pa_config_parse_int, &c->module_idle_time }, - { "scache-idle-time", pa_config_parse_int, &c->scache_idle_time }, - { "dl-search-path", pa_config_parse_string, &c->dl_search_path }, - { "default-script-file", pa_config_parse_string, &c->default_script_file }, - { "log-target", parse_log_target, c }, - { "resample-method", parse_resample_method, c }, - { NULL, NULL, NULL }, - }; - - if (!filename) - filename = def = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER); - - r = pa_config_parse(filename, table, NULL); - pa_xfree(def); - return r; -} - -int pa_conf_env(struct pa_conf *c) { - char *e; - - if ((e = getenv(ENV_DL_SEARCH_PATH))) { - pa_xfree(c->dl_search_path); - c->dl_search_path = pa_xstrdup(e); - } - if ((e = getenv(ENV_SCRIPT_FILE))) { - pa_xfree(c->default_script_file); - c->default_script_file = pa_xstrdup(e); - } - - return 0; -} - -char *pa_conf_dump(struct pa_conf *c) { - struct pa_strbuf *s = pa_strbuf_new(); - char *d; - - static const char const* resample_methods[] = { - "sinc-best-quality", - "sinc-medium-quality", - "sinc-fastest", - "zero-order-hold", - "linear" - }; - - d = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER); - pa_strbuf_printf(s, "### Default configuration file: %s ###\n", d); - - pa_strbuf_printf(s, "verbose = %i\n", !!c->verbose); - pa_strbuf_printf(s, "daemonize = %i\n", !!c->daemonize); - pa_strbuf_printf(s, "fail = %i\n", !!c->fail); - pa_strbuf_printf(s, "high-priority = %i\n", !!c->high_priority); - pa_strbuf_printf(s, "disallow-module-loading = %i\n", !!c->disallow_module_loading); - pa_strbuf_printf(s, "exit-idle-time = %i\n", c->exit_idle_time); - pa_strbuf_printf(s, "module-idle-time = %i\n", c->module_idle_time); - pa_strbuf_printf(s, "scache-idle-time = %i\n", c->scache_idle_time); - pa_strbuf_printf(s, "dl-search-path = %s\n", c->dl_search_path ? c->dl_search_path : ""); - pa_strbuf_printf(s, "default-script-file = %s\n", c->default_script_file); - pa_strbuf_printf(s, "log-target = %s\n", c->auto_log_target ? "auto" : (c->log_target == PA_LOG_SYSLOG ? "syslog" : "stderr")); - - assert(c->resample_method <= 4 && c->resample_method >= 0); - pa_strbuf_printf(s, "resample-method = %s\n", resample_methods[c->resample_method]); - - pa_xfree(d); - - return pa_strbuf_tostring_free(s); -} diff --git a/polyp/conf.h b/polyp/conf.h deleted file mode 100644 index ace5396d..00000000 --- a/polyp/conf.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef fooconfhfoo -#define fooconfhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "log.h" - -enum pa_conf_cmd { - PA_CMD_DAEMON, - PA_CMD_HELP, - PA_CMD_VERSION, - PA_CMD_DUMP_CONF, - PA_CMD_DUMP_MODULES -}; - -struct pa_conf { - enum pa_conf_cmd cmd; - int daemonize, - fail, - verbose, - high_priority, - disallow_module_loading, - exit_idle_time, - module_idle_time, - scache_idle_time, - auto_log_target; - char *script_commands, *dl_search_path, *default_script_file; - enum pa_log_target log_target; - int resample_method; -}; - -struct pa_conf* pa_conf_new(void); -void pa_conf_free(struct pa_conf*c); - -int pa_conf_load(struct pa_conf *c, const char *filename); -char *pa_conf_dump(struct pa_conf *c); - -#endif diff --git a/polyp/config-client.c b/polyp/config-client.c deleted file mode 100644 index 758927f3..00000000 --- a/polyp/config-client.c +++ /dev/null @@ -1,138 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include - -#include "config-client.h" -#include "xmalloc.h" -#include "log.h" -#include "confparser.h" -#include "util.h" - -#ifndef DEFAULT_CLIENT_CONFIG_FILE -#define DEFAULT_CLIENT_CONFIG_FILE "/etc/polypaudio/client.conf" -#endif - -#ifndef DEFAULT_CLIENT_CONFIG_FILE_USER -#define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio/client.conf" -#endif - -#define ENV_CLIENT_CONFIG_FILE "POLYP_CLIENTCONFIG" -#define ENV_DEFAULT_SINK "POLYP_SINK" -#define ENV_DEFAULT_SOURCE "POLYP_SOURCE" -#define ENV_DEFAULT_SERVER "POLYP_SERVER" -#define ENV_DAEMON_BINARY "POLYP_BINARY" - - -static const struct pa_client_conf default_conf = { - .daemon_binary = NULL, - .extra_arguments = NULL, - .default_sink = NULL, - .default_source = NULL, - .default_server = NULL, - .autospawn = 0 -}; - -struct pa_client_conf *pa_client_conf_new(void) { - struct pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); - - c->daemon_binary = pa_xstrdup(POLYPAUDIO_BINARY); - c->extra_arguments = pa_xstrdup("--daemonize=yes --log-target=syslog"); - - return c; -} - -void pa_client_conf_free(struct pa_client_conf *c) { - assert(c); - pa_xfree(c->daemon_binary); - pa_xfree(c->extra_arguments); - pa_xfree(c->default_sink); - pa_xfree(c->default_source); - pa_xfree(c->default_server); - pa_xfree(c); -} -int pa_client_conf_load(struct pa_client_conf *c, const char *filename) { - char *def = NULL; - int r; - - const struct pa_config_item table[] = { - { "daemon-binary", pa_config_parse_string, &c->daemon_binary }, - { "extra-arguments", pa_config_parse_string, &c->extra_arguments }, - { "default-sink", pa_config_parse_string, &c->default_sink }, - { "default-source", pa_config_parse_string, &c->default_source }, - { "default-server", pa_config_parse_string, &c->default_server }, - { "autospawn", pa_config_parse_bool, &c->autospawn }, - { NULL, NULL, NULL }, - }; - - if (!filename) - filename = getenv(ENV_CLIENT_CONFIG_FILE); - - if (!filename) { - char *h; - - if ((h = getenv("HOME"))) { - def = pa_sprintf_malloc("%s/%s", h, DEFAULT_CLIENT_CONFIG_FILE_USER); - - if (!access(def, F_OK)) - filename = def; - else { - pa_xfree(def); - def = NULL; - } - } - } - - if (!filename) - filename = DEFAULT_CLIENT_CONFIG_FILE; - - r = pa_config_parse(filename, table, NULL); - pa_xfree(def); - return r; -} - -int pa_client_conf_env(struct pa_client_conf *c) { - char *e; - - if ((e = getenv(ENV_DEFAULT_SINK))) { - pa_xfree(c->default_sink); - c->default_sink = pa_xstrdup(e); - } - - if ((e = getenv(ENV_DEFAULT_SOURCE))) { - pa_xfree(c->default_source); - c->default_source = pa_xstrdup(e); - } - - if ((e = getenv(ENV_DEFAULT_SERVER))) { - pa_xfree(c->default_server); - c->default_server = pa_xstrdup(e); - } - - if ((e = getenv(ENV_DAEMON_BINARY))) { - pa_xfree(c->daemon_binary); - c->daemon_binary = pa_xstrdup(e); - } - - return 0; -} diff --git a/polyp/config-client.h b/polyp/config-client.h deleted file mode 100644 index 1b1c519d..00000000 --- a/polyp/config-client.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef fooconfigclienthfoo -#define fooconfigclienthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -struct pa_client_conf { - char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server; - int autospawn; -}; - -struct pa_client_conf *pa_client_conf_new(void); -void pa_client_conf_free(struct pa_client_conf *c); - -int pa_client_conf_load(struct pa_client_conf *c, const char *filename); -int pa_client_conf_env(struct pa_client_conf *c); - -#endif diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c new file mode 100644 index 00000000..72ded989 --- /dev/null +++ b/polyp/daemon-conf.c @@ -0,0 +1,231 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "daemon-conf.h" +#include "util.h" +#include "xmalloc.h" +#include "strbuf.h" +#include "confparser.h" + +#ifndef DEFAULT_SCRIPT_FILE +#define DEFAULT_SCRIPT_FILE "/etc/polypaudio/default.pa" +#endif + +#ifndef DEFAULT_SCRIPT_FILE_USER +#define DEFAULT_SCRIPT_FILE_USER ".polypaudio/default.pa" +#endif + +#ifndef DEFAULT_CONFIG_FILE +#define DEFAULT_CONFIG_FILE "/etc/polypaudio/daemon.conf" +#endif + +#ifndef DEFAULT_CONFIG_FILE_USER +#define DEFAULT_CONFIG_FILE_USER ".polypaudio/daemon.conf" +#endif + +#define ENV_SCRIPT_FILE "POLYP_SCRIPT" +#define ENV_CONFIG_FILE "POLYP_CONFIG" +#define ENV_DL_SEARCH_PATH "POLYP_DLPATH" + +static const struct pa_daemon_conf default_conf = { + .cmd = PA_CMD_DAEMON, + .daemonize = 0, + .fail = 1, + .verbose = 0, + .high_priority = 0, + .disallow_module_loading = 0, + .exit_idle_time = -1, + .module_idle_time = 20, + .scache_idle_time = 20, + .auto_log_target = 1, + .script_commands = NULL, + .dl_search_path = NULL, + .default_script_file = NULL, + .log_target = PA_LOG_SYSLOG, + .resample_method = SRC_SINC_FASTEST +}; + +char* default_file(const char *envvar, const char *global, const char *local) { + char *p, *h; + + assert(envvar && global && local); + + if ((p = getenv(envvar))) + return pa_xstrdup(p); + + if ((h = getenv("HOME"))) { + p = pa_sprintf_malloc("%s/%s", h, local); + if (!access(p, F_OK)) + return p; + + pa_xfree(p); + } + + return pa_xstrdup(global); +} + +struct pa_daemon_conf* pa_daemon_conf_new(void) { + struct pa_daemon_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); + c->default_script_file = default_file(ENV_SCRIPT_FILE, DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER); +#ifdef DLSEARCHPATH + c->dl_search_path = pa_xstrdup(DLSEARCHPATH); +#endif + return c; +} + +void pa_daemon_conf_free(struct pa_daemon_conf *c) { + assert(c); + pa_xfree(c->script_commands); + pa_xfree(c->dl_search_path); + pa_xfree(c->default_script_file); + pa_xfree(c); +} + +int parse_log_target(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { + struct pa_daemon_conf *c = data; + assert(filename && lvalue && rvalue && data); + + if (!strcmp(rvalue, "auto")) + c->auto_log_target = 1; + else if (!strcmp(rvalue, "syslog")) { + c->auto_log_target = 0; + c->log_target = PA_LOG_SYSLOG; + } else if (!strcmp(rvalue, "stderr")) { + c->auto_log_target = 0; + c->log_target = PA_LOG_STDERR; + } else { + pa_log(__FILE__": [%s:%u] Invalid log target '%s'.\n", filename, line, rvalue); + return -1; + } + + return 0; +} + +int parse_resample_method(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { + struct pa_daemon_conf *c = data; + assert(filename && lvalue && rvalue && data); + + if (!strcmp(rvalue, "sinc-best-quality")) + c->resample_method = SRC_SINC_BEST_QUALITY; + else if (!strcmp(rvalue, "sinc-medium-quality")) + c->resample_method = SRC_SINC_MEDIUM_QUALITY; + else if (!strcmp(rvalue, "sinc-fastest")) + c->resample_method = SRC_SINC_FASTEST; + else if (!strcmp(rvalue, "zero-order-hold")) + c->resample_method = SRC_ZERO_ORDER_HOLD; + else if (!strcmp(rvalue, "linear")) + c->resample_method = SRC_LINEAR; + else { + pa_log(__FILE__": [%s:%u] Inavalid resample method '%s'.\n", filename, line, rvalue); + return -1; + } + + return 0; +} + +int pa_daemon_conf_load(struct pa_daemon_conf *c, const char *filename) { + char *def = NULL; + int r; + + const struct pa_config_item table[] = { + { "verbose", pa_config_parse_bool, &c->verbose }, + { "daemonize", pa_config_parse_bool, &c->daemonize }, + { "fail", pa_config_parse_bool, &c->fail }, + { "high-priority", pa_config_parse_bool, &c->high_priority }, + { "disallow-module-loading", pa_config_parse_bool, &c->disallow_module_loading }, + { "exit-idle-time", pa_config_parse_int, &c->exit_idle_time }, + { "module-idle-time", pa_config_parse_int, &c->module_idle_time }, + { "scache-idle-time", pa_config_parse_int, &c->scache_idle_time }, + { "dl-search-path", pa_config_parse_string, &c->dl_search_path }, + { "default-script-file", pa_config_parse_string, &c->default_script_file }, + { "log-target", parse_log_target, c }, + { "resample-method", parse_resample_method, c }, + { NULL, NULL, NULL }, + }; + + if (!filename) + filename = def = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER); + + r = pa_config_parse(filename, table, NULL); + pa_xfree(def); + return r; +} + +int pa_daemon_conf_env(struct pa_daemon_conf *c) { + char *e; + + if ((e = getenv(ENV_DL_SEARCH_PATH))) { + pa_xfree(c->dl_search_path); + c->dl_search_path = pa_xstrdup(e); + } + if ((e = getenv(ENV_SCRIPT_FILE))) { + pa_xfree(c->default_script_file); + c->default_script_file = pa_xstrdup(e); + } + + return 0; +} + +char *pa_daemon_conf_dump(struct pa_daemon_conf *c) { + struct pa_strbuf *s = pa_strbuf_new(); + char *d; + + static const char const* resample_methods[] = { + "sinc-best-quality", + "sinc-medium-quality", + "sinc-fastest", + "zero-order-hold", + "linear" + }; + + d = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER); + pa_strbuf_printf(s, "### Default configuration file: %s ###\n", d); + + pa_strbuf_printf(s, "verbose = %i\n", !!c->verbose); + pa_strbuf_printf(s, "daemonize = %i\n", !!c->daemonize); + pa_strbuf_printf(s, "fail = %i\n", !!c->fail); + pa_strbuf_printf(s, "high-priority = %i\n", !!c->high_priority); + pa_strbuf_printf(s, "disallow-module-loading = %i\n", !!c->disallow_module_loading); + pa_strbuf_printf(s, "exit-idle-time = %i\n", c->exit_idle_time); + pa_strbuf_printf(s, "module-idle-time = %i\n", c->module_idle_time); + pa_strbuf_printf(s, "scache-idle-time = %i\n", c->scache_idle_time); + pa_strbuf_printf(s, "dl-search-path = %s\n", c->dl_search_path ? c->dl_search_path : ""); + pa_strbuf_printf(s, "default-script-file = %s\n", c->default_script_file); + pa_strbuf_printf(s, "log-target = %s\n", c->auto_log_target ? "auto" : (c->log_target == PA_LOG_SYSLOG ? "syslog" : "stderr")); + + assert(c->resample_method <= 4 && c->resample_method >= 0); + pa_strbuf_printf(s, "resample-method = %s\n", resample_methods[c->resample_method]); + + pa_xfree(d); + + return pa_strbuf_tostring_free(s); +} diff --git a/polyp/daemon-conf.h b/polyp/daemon-conf.h new file mode 100644 index 00000000..c987a6d5 --- /dev/null +++ b/polyp/daemon-conf.h @@ -0,0 +1,58 @@ +#ifndef foodaemonconfhfoo +#define foodaemonconfhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "log.h" + +enum pa_daemon_conf_cmd { + PA_CMD_DAEMON, + PA_CMD_HELP, + PA_CMD_VERSION, + PA_CMD_DUMP_CONF, + PA_CMD_DUMP_MODULES +}; + +struct pa_daemon_conf { + enum pa_daemon_conf_cmd cmd; + int daemonize, + fail, + verbose, + high_priority, + disallow_module_loading, + exit_idle_time, + module_idle_time, + scache_idle_time, + auto_log_target; + char *script_commands, *dl_search_path, *default_script_file; + enum pa_log_target log_target; + int resample_method; +}; + +struct pa_daemon_conf* pa_daemon_conf_new(void); +void pa_daemon_conf_free(struct pa_daemon_conf*c); + +int pa_daemon_conf_load(struct pa_daemon_conf *c, const char *filename); +char *pa_daemon_conf_dump(struct pa_daemon_conf *c); +int pa_daemon_conf_env(struct pa_daemon_conf *c); + +#endif diff --git a/polyp/dumpmodules.c b/polyp/dumpmodules.c index ae42d36e..a9c02825 100644 --- a/polyp/dumpmodules.c +++ b/polyp/dumpmodules.c @@ -78,7 +78,7 @@ static void show_info(const char *name, const char *path, void (*info)(const cha static int callback(const char *path, lt_ptr data) { const char *e; - struct pa_conf *c = (data); + struct pa_daemon_conf *c = (data); if ((e = (const char*) strrchr(path, '/'))) e++; @@ -91,7 +91,7 @@ static int callback(const char *path, lt_ptr data) { return 0; } -void pa_dump_modules(struct pa_conf *c, int argc, char * const argv[]) { +void pa_dump_modules(struct pa_daemon_conf *c, int argc, char * const argv[]) { if (argc > 0) { int i; for (i = 0; i < argc; i++) diff --git a/polyp/dumpmodules.h b/polyp/dumpmodules.h index 6b1bd858..544c55d2 100644 --- a/polyp/dumpmodules.h +++ b/polyp/dumpmodules.h @@ -22,8 +22,8 @@ USA. ***/ -#include "conf.h" +#include "daemon-conf.h" -void pa_dump_modules(struct pa_conf *c, int argc, char * const argv[]); +void pa_dump_modules(struct pa_daemon_conf *c, int argc, char * const argv[]); #endif diff --git a/polyp/main.c b/polyp/main.c index 3b25a030..10774388 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -45,7 +45,7 @@ #include "xmalloc.h" #include "cpulimit.h" #include "log.h" -#include "conf.h" +#include "daemon-conf.h" #include "dumpmodules.h" static struct pa_mainloop *mainloop; @@ -90,7 +90,7 @@ static void close_pipe(int p[2]) { int main(int argc, char *argv[]) { struct pa_core *c; struct pa_strbuf *buf = NULL; - struct pa_conf *conf; + struct pa_daemon_conf *conf; char *s; int r, retval = 1, d = 0; int daemon_pipe[2] = { -1, -1 }; @@ -100,11 +100,14 @@ int main(int argc, char *argv[]) { pa_log_set_ident("polypaudio"); - conf = pa_conf_new(); + conf = pa_daemon_conf_new(); - if (pa_conf_load(conf, NULL) < 0) + if (pa_daemon_conf_load(conf, NULL) < 0) goto finish; + if (pa_daemon_conf_env(conf) < 0) + goto finish; + if (pa_cmdline_parse(conf, argc, argv, &d) < 0) { pa_log(__FILE__": failed to parse command line.\n"); goto finish; @@ -127,7 +130,7 @@ int main(int argc, char *argv[]) { goto finish; case PA_CMD_DUMP_CONF: { - char *s = pa_conf_dump(conf); + char *s = pa_daemon_conf_dump(conf); fputs(s, stdout); pa_xfree(s); retval = 0; @@ -261,7 +264,7 @@ int main(int argc, char *argv[]) { finish: if (conf) - pa_conf_free(conf); + pa_daemon_conf_free(conf); close_pipe(daemon_pipe); diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 04ee3d89..4ed15c4b 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -47,7 +47,7 @@ #include "util.h" #include "xmalloc.h" #include "log.h" -#include "config-client.h" +#include "client-conf.h" #define DEFAULT_SERVER "/tmp/polypaudio/native" diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 1d0e41d8..6e64755d 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -33,7 +33,7 @@ #include "polyplib-operation.h" #include "llist.h" #include "native-common.h" -#include "config-client.h" +#include "client-conf.h" #define DEFAULT_TLENGTH (10240*8) #define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2) -- cgit From 95612b6b1c01ab62b1dd8d51a9d62d4e502cef11 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 17 Sep 2004 20:08:52 +0000 Subject: rename some more git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@213 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 6 +- polyp/client-conf.c | 2 +- polyp/conf-parser.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++ polyp/conf-parser.h | 37 ++++++++++++ polyp/confparser.c | 168 ---------------------------------------------------- polyp/confparser.h | 37 ------------ polyp/daemon-conf.c | 2 +- 7 files changed, 210 insertions(+), 210 deletions(-) create mode 100644 polyp/conf-parser.c create mode 100644 polyp/conf-parser.h delete mode 100644 polyp/confparser.c delete mode 100644 polyp/confparser.h diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 9dde211d..7efb46c7 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -159,7 +159,7 @@ polypaudio_SOURCES = idxset.c idxset.h \ modinfo.c modinfo.h \ daemon-conf.c daemon-conf.h \ dumpmodules.c dumpmodules.h \ - conparser.h confparser.c + conf-parser.h conf-parser.c polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) @@ -334,8 +334,8 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = polyplib.h \ llist.h \ log.c log.h \ gcc-printf.h \ - client-conf.c client-conf.h \ - confparser.c confparser.h + client-conf.c client-conf.h \ + conf-parser.c conf-parser.h libpolyp_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) libpolyp_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 diff --git a/polyp/client-conf.c b/polyp/client-conf.c index cfc257c6..d904cb49 100644 --- a/polyp/client-conf.c +++ b/polyp/client-conf.c @@ -26,7 +26,7 @@ #include "client-conf.h" #include "xmalloc.h" #include "log.h" -#include "confparser.h" +#include "conf-parser.h" #include "util.h" #ifndef DEFAULT_CLIENT_CONFIG_FILE diff --git a/polyp/conf-parser.c b/polyp/conf-parser.c new file mode 100644 index 00000000..20e8e723 --- /dev/null +++ b/polyp/conf-parser.c @@ -0,0 +1,168 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +#include "conf-parser.h" +#include "log.h" +#include "util.h" +#include "xmalloc.h" + +#define WHITESPACE " \t\n" +#define COMMENTS "#;\n" + +static int next_assignment(const char *filename, unsigned line, const struct pa_config_item *t, const char *lvalue, const char *rvalue, void *userdata) { + assert(filename && t && lvalue && rvalue); + + for (; t->parse; t++) + if (!strcmp(lvalue, t->lvalue)) + return t->parse(filename, line, lvalue, rvalue, t->data, userdata); + + pa_log(__FILE__": [%s:%u] Unknown lvalue '%s'.\n", filename, line, lvalue); + + return -1; +} + +static int in_string(char c, const char *s) { + assert(s); + + for (; *s; s++) + if (*s == c) + return 1; + + return 0; +} + +static char *strip(char *s) { + char *b = s+strspn(s, WHITESPACE); + char *e, *l = NULL; + + for (e = b; *e; e++) + if (!in_string(*e, WHITESPACE)) + l = e; + + if (l) + *(l+1) = 0; + + return b; +} + +static int parse_line(const char *filename, unsigned line, const struct pa_config_item *t, char *l, void *userdata) { + char *e, *c, *b = l+strspn(l, WHITESPACE); + + if ((c = strpbrk(b, COMMENTS))) + *c = 0; + + if (!*b) + return 0; + + if (!(e = strchr(b, '='))) { + pa_log(__FILE__": [%s:%u] Missing '='.\n", filename, line); + return -1; + } + + *e = 0; + e++; + + return next_assignment(filename, line, t, strip(b), strip(e), userdata); +} + + +int pa_config_parse(const char *filename, const struct pa_config_item *t, void *userdata) { + FILE *f; + int r = -1; + unsigned line = 0; + assert(filename && t); + + if (!(f = fopen(filename, "r"))) { + if (errno == ENOENT) { + r = 0; + goto finish; + } + + pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno)); + goto finish; + } + + while (!feof(f)) { + char l[256]; + if (!fgets(l, sizeof(l), f)) { + if (feof(f)) + break; + + pa_log(__FILE__": WARNING: failed to read configuration file '%s': %s\n", filename, strerror(errno)); + goto finish; + } + + if (parse_line(filename, ++line, t, l, userdata) < 0) + goto finish; + } + + r = 0; + +finish: + + if (f) + fclose(f); + + return r; +} + +int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { + int *i = data, k; + char *x = NULL; + assert(filename && lvalue && rvalue && data); + + k = strtol(rvalue, &x, 0); + if (!*rvalue || !x || *x) { + pa_log(__FILE__": [%s:%u] Failed to parse numeric value: %s\n", filename, line, rvalue); + return -1; + } + + *i = k; + return 0; +} + +int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { + int *b = data, k; + assert(filename && lvalue && rvalue && data); + + if ((k = pa_parse_boolean(rvalue)) < 0) { + pa_log(__FILE__": [%s:%u] Failed to parse boolean value: %s\n", filename, line, rvalue); + return -1; + } + + *b = k; + + return 0; +} + +int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { + char **s = data; + assert(filename && lvalue && rvalue && data); + + pa_xfree(*s); + *s = *rvalue ? pa_xstrdup(rvalue) : NULL; + return 0; +} diff --git a/polyp/conf-parser.h b/polyp/conf-parser.h new file mode 100644 index 00000000..a0eb52d0 --- /dev/null +++ b/polyp/conf-parser.h @@ -0,0 +1,37 @@ +#ifndef fooconfparserhfoo +#define fooconfparserhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +struct pa_config_item { + const char *lvalue; + int (*parse)(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); + void *data; +}; + +int pa_config_parse(const char *filename, const struct pa_config_item *t, void *userdata); + +int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); +int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); +int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); + +#endif diff --git a/polyp/confparser.c b/polyp/confparser.c deleted file mode 100644 index 8f551b95..00000000 --- a/polyp/confparser.c +++ /dev/null @@ -1,168 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include - -#include "confparser.h" -#include "log.h" -#include "util.h" -#include "xmalloc.h" - -#define WHITESPACE " \t\n" -#define COMMENTS "#;\n" - -static int next_assignment(const char *filename, unsigned line, const struct pa_config_item *t, const char *lvalue, const char *rvalue, void *userdata) { - assert(filename && t && lvalue && rvalue); - - for (; t->parse; t++) - if (!strcmp(lvalue, t->lvalue)) - return t->parse(filename, line, lvalue, rvalue, t->data, userdata); - - pa_log(__FILE__": [%s:%u] Unknown lvalue '%s'.\n", filename, line, lvalue); - - return -1; -} - -static int in_string(char c, const char *s) { - assert(s); - - for (; *s; s++) - if (*s == c) - return 1; - - return 0; -} - -static char *strip(char *s) { - char *b = s+strspn(s, WHITESPACE); - char *e, *l = NULL; - - for (e = b; *e; e++) - if (!in_string(*e, WHITESPACE)) - l = e; - - if (l) - *(l+1) = 0; - - return b; -} - -static int parse_line(const char *filename, unsigned line, const struct pa_config_item *t, char *l, void *userdata) { - char *e, *c, *b = l+strspn(l, WHITESPACE); - - if ((c = strpbrk(b, COMMENTS))) - *c = 0; - - if (!*b) - return 0; - - if (!(e = strchr(b, '='))) { - pa_log(__FILE__": [%s:%u] Missing '='.\n", filename, line); - return -1; - } - - *e = 0; - e++; - - return next_assignment(filename, line, t, strip(b), strip(e), userdata); -} - - -int pa_config_parse(const char *filename, const struct pa_config_item *t, void *userdata) { - FILE *f; - int r = -1; - unsigned line = 0; - assert(filename && t); - - if (!(f = fopen(filename, "r"))) { - if (errno == ENOENT) { - r = 0; - goto finish; - } - - pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno)); - goto finish; - } - - while (!feof(f)) { - char l[256]; - if (!fgets(l, sizeof(l), f)) { - if (feof(f)) - break; - - pa_log(__FILE__": WARNING: failed to read configuration file '%s': %s\n", filename, strerror(errno)); - goto finish; - } - - if (parse_line(filename, ++line, t, l, userdata) < 0) - goto finish; - } - - r = 0; - -finish: - - if (f) - fclose(f); - - return r; -} - -int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { - int *i = data, k; - char *x = NULL; - assert(filename && lvalue && rvalue && data); - - k = strtol(rvalue, &x, 0); - if (!*rvalue || !x || *x) { - pa_log(__FILE__": [%s:%u] Failed to parse numeric value: %s\n", filename, line, rvalue); - return -1; - } - - *i = k; - return 0; -} - -int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { - int *b = data, k; - assert(filename && lvalue && rvalue && data); - - if ((k = pa_parse_boolean(rvalue)) < 0) { - pa_log(__FILE__": [%s:%u] Failed to parse boolean value: %s\n", filename, line, rvalue); - return -1; - } - - *b = k; - - return 0; -} - -int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { - char **s = data; - assert(filename && lvalue && rvalue && data); - - pa_xfree(*s); - *s = *rvalue ? pa_xstrdup(rvalue) : NULL; - return 0; -} diff --git a/polyp/confparser.h b/polyp/confparser.h deleted file mode 100644 index a0eb52d0..00000000 --- a/polyp/confparser.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef fooconfparserhfoo -#define fooconfparserhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -struct pa_config_item { - const char *lvalue; - int (*parse)(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); - void *data; -}; - -int pa_config_parse(const char *filename, const struct pa_config_item *t, void *userdata); - -int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); -int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); -int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); - -#endif diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c index 72ded989..a3185364 100644 --- a/polyp/daemon-conf.c +++ b/polyp/daemon-conf.c @@ -34,7 +34,7 @@ #include "util.h" #include "xmalloc.h" #include "strbuf.h" -#include "confparser.h" +#include "conf-parser.h" #ifndef DEFAULT_SCRIPT_FILE #define DEFAULT_SCRIPT_FILE "/etc/polypaudio/default.pa" -- cgit From 08953564bb85356869a1f043b82d1f365c8729a1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 17 Sep 2004 20:43:40 +0000 Subject: add --resample-method argument git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@214 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 5 +---- polyp/client-conf.c | 2 +- polyp/client.conf.in | 10 ++++----- polyp/cmdline.c | 22 ++++++++++--------- polyp/daemon-conf.c | 57 ++++++++++++++++++++++++++++++++---------------- polyp/daemon-conf.h | 3 +++ polyp/polyplib-context.c | 7 +++--- polyp/util.c | 2 +- 8 files changed, 65 insertions(+), 43 deletions(-) diff --git a/doc/todo b/doc/todo index fe06df78..53d4ca56 100644 --- a/doc/todo +++ b/doc/todo @@ -2,10 +2,7 @@ *** 0.5 *** - more complete pactl/parec -- fix tcp/native in regard to latencies -- add client config file -- remove autospawn stuff in conf.c -- make resampler configurable +- fix tcp/native in regard to latencies (i.e. latency interpolation) *** 0.6 **** - per-channel volume diff --git a/polyp/client-conf.c b/polyp/client-conf.c index d904cb49..c43788fe 100644 --- a/polyp/client-conf.c +++ b/polyp/client-conf.c @@ -57,7 +57,7 @@ struct pa_client_conf *pa_client_conf_new(void) { struct pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); c->daemon_binary = pa_xstrdup(POLYPAUDIO_BINARY); - c->extra_arguments = pa_xstrdup("--daemonize=yes --log-target=syslog"); + c->extra_arguments = pa_xstrdup("--log-target=syslog --exit-idle-time=5"); return c; } diff --git a/polyp/client.conf.in b/polyp/client.conf.in index 7ba6549b..640e2690 100644 --- a/polyp/client.conf.in +++ b/polyp/client.conf.in @@ -21,19 +21,19 @@ ## commented out. Use either ; or # for commenting ## Path to the polypaudio daemon to run when autospawning. -; daemon_binary = @POLYPAUDIO_BINARY@ +; daemon-binary = @POLYPAUDIO_BINARY@ ## Extra arguments to pass to the polypaudio daemon -; extra_arguments = --daemonize=yes --log-target=syslog +; extra-arguments = --log-target=syslog --exit-idle-time=5 ## The default sink to connect to -; default_sink = +; default-sink = ## The default source to connect to -; default_source = +; default-source = ## The default sever to connect to -; default_server = +; default-server = ## Autospawn daemons? ; autospawn = 0 diff --git a/polyp/cmdline.c b/polyp/cmdline.c index 7f8a947b..a5bb8101 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -52,6 +52,7 @@ enum { ARG_LOAD, ARG_FILE, ARG_DL_SEARCH_PATH, + ARG_RESAMPLE_METHOD }; static struct option long_options[] = { @@ -71,6 +72,7 @@ static struct option long_options[] = { {"load", 1, 0, ARG_LOAD}, {"file", 1, 0, ARG_FILE}, {"dl-search-path", 1, 0, ARG_DL_SEARCH_PATH}, + {"resample-method", 1, 0, ARG_RESAMPLE_METHOD}, {NULL, 0, 0, 0} }; @@ -98,7 +100,8 @@ void pa_cmdline_help(const char *argv0) { " --module-idle-time=SECS Unload autoloaded modules when idle and this time passed\n" " --scache-idle-time=SECS Unload autoloaded samples when idle and this time passed\n" " --log-target={auto,syslog,stderr} Specify the log target\n" - " -p, --dl-search-path=PATH Set the search path for dynamic shared objects (plugins)\n\n" + " -p, --dl-search-path=PATH Set the search path for dynamic shared objects (plugins)\n" + " --resample-method=[METHOD] Use the specified resampling method\n\n" " -L, --load=\"MODULE ARGUMENTS\" Load the specified plugin module with the specified argument\n" " -F, --file=FILENAME Run the specified script\n" @@ -198,15 +201,7 @@ int pa_cmdline_parse(struct pa_daemon_conf *conf, int argc, char *const argv [], break; case ARG_LOG_TARGET: - if (!strcmp(optarg, "syslog")) { - conf->auto_log_target = 0; - conf->log_target = PA_LOG_SYSLOG; - } else if (!strcmp(optarg, "stderr")) { - conf->auto_log_target = 0; - conf->log_target = PA_LOG_STDERR; - } else if (!strcmp(optarg, "auto")) - conf->auto_log_target = 1; - else { + if (pa_daemon_conf_set_log_target(conf, optarg) < 0) { pa_log(__FILE__": Invalid log target: use either 'syslog', 'stderr' or 'auto'.\n"); goto fail; } @@ -223,6 +218,13 @@ int pa_cmdline_parse(struct pa_daemon_conf *conf, int argc, char *const argv [], case ARG_SCACHE_IDLE_TIME: conf->scache_idle_time = atoi(optarg); break; + + case ARG_RESAMPLE_METHOD: + if (pa_daemon_conf_set_resample_method(conf, optarg) < 0) { + pa_log(__FILE__": Invalid resample method '%s'.\n", optarg); + goto fail; + } + break; default: goto fail; diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c index a3185364..6dcd540d 100644 --- a/polyp/daemon-conf.c +++ b/polyp/daemon-conf.c @@ -110,41 +110,60 @@ void pa_daemon_conf_free(struct pa_daemon_conf *c) { pa_xfree(c); } -int parse_log_target(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { - struct pa_daemon_conf *c = data; - assert(filename && lvalue && rvalue && data); - - if (!strcmp(rvalue, "auto")) +int pa_daemon_conf_set_log_target(struct pa_daemon_conf *c, const char *string) { + assert(c && string); + + if (!strcmp(string, "auto")) c->auto_log_target = 1; - else if (!strcmp(rvalue, "syslog")) { + else if (!strcmp(string, "syslog")) { c->auto_log_target = 0; c->log_target = PA_LOG_SYSLOG; - } else if (!strcmp(rvalue, "stderr")) { + } else if (!strcmp(string, "stderr")) { c->auto_log_target = 0; c->log_target = PA_LOG_STDERR; - } else { - pa_log(__FILE__": [%s:%u] Invalid log target '%s'.\n", filename, line, rvalue); + } else return -1; - } return 0; + } -int parse_resample_method(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { - struct pa_daemon_conf *c = data; - assert(filename && lvalue && rvalue && data); +int pa_daemon_conf_set_resample_method(struct pa_daemon_conf *c, const char *string) { + assert(c && string); - if (!strcmp(rvalue, "sinc-best-quality")) + if (!strcmp(string, "sinc-best-quality")) c->resample_method = SRC_SINC_BEST_QUALITY; - else if (!strcmp(rvalue, "sinc-medium-quality")) + else if (!strcmp(string, "sinc-medium-quality")) c->resample_method = SRC_SINC_MEDIUM_QUALITY; - else if (!strcmp(rvalue, "sinc-fastest")) + else if (!strcmp(string, "sinc-fastest")) c->resample_method = SRC_SINC_FASTEST; - else if (!strcmp(rvalue, "zero-order-hold")) + else if (!strcmp(string, "zero-order-hold")) c->resample_method = SRC_ZERO_ORDER_HOLD; - else if (!strcmp(rvalue, "linear")) + else if (!strcmp(string, "linear")) c->resample_method = SRC_LINEAR; - else { + else + return -1; + + return 0; +} + +int parse_log_target(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { + struct pa_daemon_conf *c = data; + assert(filename && lvalue && rvalue && data); + + if (pa_daemon_conf_set_log_target(c, rvalue) < 0) { + pa_log(__FILE__": [%s:%u] Invalid log target '%s'.\n", filename, line, rvalue); + return -1; + } + + return 0; +} + +int parse_resample_method(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { + struct pa_daemon_conf *c = data; + assert(filename && lvalue && rvalue && data); + + if (pa_daemon_conf_set_resample_method(c, rvalue) < 0) { pa_log(__FILE__": [%s:%u] Inavalid resample method '%s'.\n", filename, line, rvalue); return -1; } diff --git a/polyp/daemon-conf.h b/polyp/daemon-conf.h index c987a6d5..8be989da 100644 --- a/polyp/daemon-conf.h +++ b/polyp/daemon-conf.h @@ -55,4 +55,7 @@ int pa_daemon_conf_load(struct pa_daemon_conf *c, const char *filename); char *pa_daemon_conf_dump(struct pa_daemon_conf *c); int pa_daemon_conf_env(struct pa_daemon_conf *c); +int pa_daemon_conf_set_log_target(struct pa_daemon_conf *c, const char *string); +int pa_daemon_conf_set_resample_method(struct pa_daemon_conf *c, const char *string); + #endif diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 4ed15c4b..8f6ce6a8 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -432,16 +432,17 @@ static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api putenv(t); argv[n++] = c->conf->daemon_binary; - + argv[n++] = "--daemonize=yes"; + snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]); - argv[n++] = pa_xstrdup(t); + argv[n++] = t; while (n < MAX_ARGS) { char *a; if (!(a = pa_split_spaces(c->conf->extra_arguments, &state))) break; - + argv[n++] = a; } diff --git a/polyp/util.c b/polyp/util.c index 86f18f25..e4dcd1c9 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -396,7 +396,7 @@ char *pa_split_spaces(const char *c, const char **state) { const char *current = *state ? *state : c; size_t l; - if (*current) + if (!*current) return NULL; current += strspn(current, WHITESPACE); -- cgit From 61ec86c90f1964ab9663b7a72a0885078d372683 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 17 Sep 2004 21:10:05 +0000 Subject: add resample_method option module-combine git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@215 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/daemon-conf.c | 15 +++------------ polyp/module-combine.c | 21 +++++++++++++++------ polyp/module-sine.c | 2 +- polyp/play-memchunk.c | 2 +- polyp/protocol-esound.c | 4 ++-- polyp/protocol-native.c | 4 ++-- polyp/protocol-simple.c | 4 ++-- polyp/sink-input.c | 7 +++++-- polyp/sink-input.h | 2 +- polyp/sound-file-stream.c | 2 +- polyp/source-output.c | 7 +++++-- polyp/source-output.h | 2 +- polyp/util.c | 18 ++++++++++++++++++ polyp/util.h | 2 ++ 14 files changed, 59 insertions(+), 33 deletions(-) diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c index 6dcd540d..befb9602 100644 --- a/polyp/daemon-conf.c +++ b/polyp/daemon-conf.c @@ -125,25 +125,16 @@ int pa_daemon_conf_set_log_target(struct pa_daemon_conf *c, const char *string) return -1; return 0; - } int pa_daemon_conf_set_resample_method(struct pa_daemon_conf *c, const char *string) { + int m; assert(c && string); - if (!strcmp(string, "sinc-best-quality")) - c->resample_method = SRC_SINC_BEST_QUALITY; - else if (!strcmp(string, "sinc-medium-quality")) - c->resample_method = SRC_SINC_MEDIUM_QUALITY; - else if (!strcmp(string, "sinc-fastest")) - c->resample_method = SRC_SINC_FASTEST; - else if (!strcmp(string, "zero-order-hold")) - c->resample_method = SRC_ZERO_ORDER_HOLD; - else if (!strcmp(string, "linear")) - c->resample_method = SRC_LINEAR; - else + if ((m = pa_parse_resample_method(string)) < 0) return -1; + c->resample_method = m; return 0; } diff --git a/polyp/module-combine.c b/polyp/module-combine.c index 177d7d18..f6d596bc 100644 --- a/polyp/module-combine.c +++ b/polyp/module-combine.c @@ -40,7 +40,7 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Combine multiple sinks to one") PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= master= slave= adjust_time=") +PA_MODULE_USAGE("sink_name= master= slave= adjust_time= resample_method=") #define DEFAULT_SINK_NAME "combined" #define MEMBLOCKQ_MAXLENGTH (1024*170) @@ -53,6 +53,7 @@ static const char* const valid_modargs[] = { "master", "slaves", "adjust_time", + "resample_method", NULL }; @@ -200,7 +201,7 @@ static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { return pa_sink_input_get_latency(u->master->sink_input); } -static struct output *output_new(struct userdata *u, struct pa_sink *sink) { +static struct output *output_new(struct userdata *u, struct pa_sink *sink, int resample_method) { struct output *o = NULL; char t[256]; assert(u && sink && u->sink); @@ -212,7 +213,7 @@ static struct output *output_new(struct userdata *u, struct pa_sink *sink) { o->memblockq = pa_memblockq_new(MEMBLOCKQ_MAXLENGTH, MEMBLOCKQ_MAXLENGTH, pa_frame_size(&u->sink->sample_spec), 0, 0, sink->core->memblock_stat); snprintf(t, sizeof(t), "%s: output #%u", u->sink->name, u->n_outputs+1); - if (!(o->sink_input = pa_sink_input_new(sink, t, &u->sink->sample_spec, 1))) + if (!(o->sink_input = pa_sink_input_new(sink, t, &u->sink->sample_spec, 1, resample_method))) goto fail; o->sink_input->get_latency = sink_input_get_latency_cb; @@ -277,17 +278,25 @@ static void clear_up(struct userdata *u) { int pa__init(struct pa_core *c, struct pa_module*m) { struct userdata *u; struct pa_modargs *ma = NULL; - const char *master_name, *slaves; + const char *master_name, *slaves, *rm; struct pa_sink *master_sink; char *n = NULL; const char*split_state; struct timeval tv; + int resample_method = -1; assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": failed to parse module arguments\n"); goto fail; } + + if ((rm = pa_modargs_get_value(ma, "resample_method", NULL))) { + if ((resample_method = pa_parse_resample_method(rm)) < 0) { + pa_log(__FILE__": invalid resample method '%s'\n", rm); + goto fail; + } + } u = pa_xmalloc(sizeof(struct userdata)); m->userdata = u; @@ -325,7 +334,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { u->sink->get_latency = sink_get_latency_cb; u->sink->userdata = u; - if (!(u->master = output_new(u, master_sink))) { + if (!(u->master = output_new(u, master_sink, resample_method))) { pa_log(__FILE__": failed to create master sink input on sink '%s'.\n", u->sink->name); goto fail; } @@ -341,7 +350,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { pa_xfree(n); - if (!output_new(u, slave_sink)) { + if (!output_new(u, slave_sink, resample_method)) { pa_log(__FILE__": failed to create slave sink input on sink '%s'.\n", slave_sink->name); goto fail; } diff --git a/polyp/module-sine.c b/polyp/module-sine.c index 2fa7759c..458b8788 100644 --- a/polyp/module-sine.c +++ b/polyp/module-sine.c @@ -139,7 +139,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { calc_sine(u->memblock->data, u->memblock->length, frequency); snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency); - if (!(u->sink_input = pa_sink_input_new(sink, t, &ss, 0))) + if (!(u->sink_input = pa_sink_input_new(sink, t, &ss, 0, -1))) goto fail; u->sink_input->peek = sink_input_peek; diff --git a/polyp/play-memchunk.c b/polyp/play-memchunk.c index 6490547e..aa6d30e9 100644 --- a/polyp/play-memchunk.c +++ b/polyp/play-memchunk.c @@ -88,7 +88,7 @@ int pa_play_memchunk(struct pa_sink *sink, const char *name, const struct pa_sam if (volume <= 0) return 0; - if (!(si = pa_sink_input_new(sink, name, ss, 0))) + if (!(si = pa_sink_input_new(sink, name, ss, 0, -1))) return -1; si->volume = volume; diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index aff45099..293d123a 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -305,7 +305,7 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons c->playback.fragment_size = l/10; assert(!c->sink_input); - c->sink_input = pa_sink_input_new(sink, name, &ss, 0); + c->sink_input = pa_sink_input_new(sink, name, &ss, 0, -1); assert(c->sink_input); c->sink_input->owner = c->protocol->module; @@ -368,7 +368,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); assert(!c->source_output); - c->source_output = pa_source_output_new(source, name, &ss); + c->source_output = pa_source_output_new(source, name, &ss, -1); assert(c->source_output); c->source_output->owner = c->protocol->module; diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index e197d1e2..021c1a60 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -251,7 +251,7 @@ static struct record_stream* record_stream_new(struct connection *c, struct pa_s size_t base; assert(c && source && ss && name && maxlength); - if (!(source_output = pa_source_output_new(source, name, ss))) + if (!(source_output = pa_source_output_new(source, name, ss, -1))) return NULL; s = pa_xmalloc(sizeof(struct record_stream)); @@ -295,7 +295,7 @@ static struct playback_stream* playback_stream_new(struct connection *c, struct struct pa_sink_input *sink_input; assert(c && sink && ss && name && maxlength); - if (!(sink_input = pa_sink_input_new(sink, name, ss, 0))) + if (!(sink_input = pa_sink_input_new(sink, name, ss, 0, -1))) return NULL; s = pa_xmalloc(sizeof(struct playback_stream)); diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index a7bd76fb..ee3bf9d3 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -314,7 +314,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo goto fail; } - if (!(c->sink_input = pa_sink_input_new(sink, c->client->name, &p->sample_spec, 0))) { + if (!(c->sink_input = pa_sink_input_new(sink, c->client->name, &p->sample_spec, 0, -1))) { pa_log(__FILE__": Failed to create sink input.\n"); goto fail; } @@ -344,7 +344,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo goto fail; } - c->source_output = pa_source_output_new(source, c->client->name, &p->sample_spec); + c->source_output = pa_source_output_new(source, c->client->name, &p->sample_spec, -1); if (!c->source_output) { pa_log(__FILE__": Failed to create source output.\n"); goto fail; diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 486a2044..94930231 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -36,7 +36,7 @@ #define CONVERT_BUFFER_LENGTH 4096 -struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec, int variable_rate) { +struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec, int variable_rate, int resample_method) { struct pa_sink_input *i; struct pa_resampler *resampler = NULL; int r; @@ -47,9 +47,12 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con pa_log(__FILE__": Failed to create sink input: too many inputs per sink.\n"); return NULL; } + + if (resample_method < 0) + resample_method = s->core->resample_method; if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec)) - if (!(resampler = pa_resampler_new(spec, &s->sample_spec, s->core->memblock_stat, s->core->resample_method))) + if (!(resampler = pa_resampler_new(spec, &s->sample_spec, s->core->memblock_stat, resample_method))) return NULL; i = pa_xmalloc(sizeof(struct pa_sink_input)); diff --git a/polyp/sink-input.h b/polyp/sink-input.h index 37678300..7c648ac1 100644 --- a/polyp/sink-input.h +++ b/polyp/sink-input.h @@ -62,7 +62,7 @@ struct pa_sink_input { struct pa_resampler *resampler; }; -struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec, int variable_rate); +struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec, int variable_rate, int resample_method); void pa_sink_input_unref(struct pa_sink_input* i); struct pa_sink_input* pa_sink_input_ref(struct pa_sink_input* i); diff --git a/polyp/sound-file-stream.c b/polyp/sound-file-stream.c index 60a58f47..b77d6d61 100644 --- a/polyp/sound-file-stream.c +++ b/polyp/sound-file-stream.c @@ -145,7 +145,7 @@ int pa_play_file(struct pa_sink *sink, const char *fname, pa_volume_t volume) { goto fail; } - if (!(u->sink_input = pa_sink_input_new(sink, fname, &ss, 0))) + if (!(u->sink_input = pa_sink_input_new(sink, fname, &ss, 0, -1))) goto fail; u->sink_input->volume = volume; diff --git a/polyp/source-output.c b/polyp/source-output.c index 252c155c..13b39658 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -33,7 +33,7 @@ #include "subscribe.h" #include "log.h" -struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec) { +struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec, int resample_method) { struct pa_source_output *o; struct pa_resampler *resampler = NULL; int r; @@ -44,8 +44,11 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n return NULL; } + if (resample_method < 0) + resample_method = s->core->resample_method; + if (!pa_sample_spec_equal(&s->sample_spec, spec)) - if (!(resampler = pa_resampler_new(&s->sample_spec, spec, s->core->memblock_stat, s->core->resample_method))) + if (!(resampler = pa_resampler_new(&s->sample_spec, spec, s->core->memblock_stat, resample_method))) return NULL; o = pa_xmalloc(sizeof(struct pa_source_output)); diff --git a/polyp/source-output.h b/polyp/source-output.h index ed09b537..51d5936b 100644 --- a/polyp/source-output.h +++ b/polyp/source-output.h @@ -57,7 +57,7 @@ struct pa_source_output { void *userdata; }; -struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec); +struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec, int resample_method); void pa_source_output_unref(struct pa_source_output* o); struct pa_source_output* pa_source_output_ref(struct pa_source_output *o); diff --git a/polyp/util.c b/polyp/util.c index e4dcd1c9..b9bf9f82 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -41,6 +41,8 @@ #include #include +#include + #include "util.h" #include "xmalloc.h" #include "log.h" @@ -420,3 +422,19 @@ const char *pa_strsignal(int sig) { } } +int pa_parse_resample_method(const char *string) { + assert(string); + + if (!strcmp(string, "sinc-best-quality")) + return SRC_SINC_BEST_QUALITY; + else if (!strcmp(string, "sinc-medium-quality")) + return SRC_SINC_MEDIUM_QUALITY; + else if (!strcmp(string, "sinc-fastest")) + return SRC_SINC_FASTEST; + else if (!strcmp(string, "zero-order-hold")) + return SRC_ZERO_ORDER_HOLD; + else if (!strcmp(string, "linear")) + return SRC_LINEAR; + else + return -1; +} diff --git a/polyp/util.h b/polyp/util.h index 07072df6..c842a1c3 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -64,4 +64,6 @@ char *pa_split_spaces(const char *c, const char **state); const char *pa_strsignal(int sig); +int pa_parse_resample_method(const char *string); + #endif -- cgit From 0b9bc039f63fb6173fd1b442a22e12c40797bc92 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 17 Sep 2004 21:17:29 +0000 Subject: change sysconf path git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@216 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 7efb46c7..e7574447 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -18,7 +18,7 @@ # USA. polypincludedir=$(includedir)/polyp -polypconfdir=$(sysconfdir)/polyp +polypconfdir=$(sysconfdir)/polypaudio modlibdir=$(libdir)/polypaudio-@PA_MAJORMINOR@ -- cgit From 9ad4aa387ebcae2ec2b9f67f1f04eea89eddc241 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 17 Sep 2004 23:45:28 +0000 Subject: minor stuff git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@217 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 +- polyp/client-conf.c | 1 - polyp/daemon.conf.in | 4 ++-- polyp/polyplib-context.c | 3 ++- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/todo b/doc/todo index 53d4ca56..300f8d0a 100644 --- a/doc/todo +++ b/doc/todo @@ -2,7 +2,6 @@ *** 0.5 *** - more complete pactl/parec -- fix tcp/native in regard to latencies (i.e. latency interpolation) *** 0.6 **** - per-channel volume @@ -12,6 +11,7 @@ - make mcalign merge chunks - option to use default fragment size on alsa drivers - improve module-oss-mmap latency measurement +- new mainloop method: defer_pending() ** later *** - xmlrpc/http diff --git a/polyp/client-conf.c b/polyp/client-conf.c index c43788fe..efaae837 100644 --- a/polyp/client-conf.c +++ b/polyp/client-conf.c @@ -43,7 +43,6 @@ #define ENV_DEFAULT_SERVER "POLYP_SERVER" #define ENV_DAEMON_BINARY "POLYP_BINARY" - static const struct pa_client_conf default_conf = { .daemon_binary = NULL, .extra_arguments = NULL, diff --git a/polyp/daemon.conf.in b/polyp/daemon.conf.in index a277bb4f..e6d82db1 100644 --- a/polyp/daemon.conf.in +++ b/polyp/daemon.conf.in @@ -34,7 +34,7 @@ ## playback. However, this is a certain security issue, since it works ## when called SUID root only. root is dropped immediately after gaining ## the nice level and SCHED_FIFO scheduling on startup. -high-priority = 0 +; high-priority = 0 ## Disallow module loading after startup ; disallow-module-loading = 0 @@ -44,7 +44,7 @@ high-priority = 0 ; exit-idle-time = -1 ## Unload autoloaded modules after being idle for this time -module-idle-time = 20 +; module-idle-time = 20 ## The path were to look for dynamic shared objects (DSOs aka ## plugins). You may specify more than one path seperated by diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 8f6ce6a8..8a7c719c 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -500,7 +500,8 @@ int pa_context_connect(struct pa_context *c, const char *server, int spawn, cons if (!server && spawn && c->conf->autospawn && !default_server_is_running()) return context_connect_spawn(c, api); - server = DEFAULT_SERVER; + if (!server) + server = DEFAULT_SERVER; pa_context_ref(c); -- cgit From 4e31feb4345c617adb2ba44b9be724989b63d093 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 18 Sep 2004 12:28:29 +0000 Subject: work around gcc 2.95 limitation git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@218 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/client-conf.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/polyp/client-conf.c b/polyp/client-conf.c index efaae837..b8a4c778 100644 --- a/polyp/client-conf.c +++ b/polyp/client-conf.c @@ -74,16 +74,23 @@ int pa_client_conf_load(struct pa_client_conf *c, const char *filename) { char *def = NULL; int r; - const struct pa_config_item table[] = { - { "daemon-binary", pa_config_parse_string, &c->daemon_binary }, - { "extra-arguments", pa_config_parse_string, &c->extra_arguments }, - { "default-sink", pa_config_parse_string, &c->default_sink }, - { "default-source", pa_config_parse_string, &c->default_source }, - { "default-server", pa_config_parse_string, &c->default_server }, - { "autospawn", pa_config_parse_bool, &c->autospawn }, + struct pa_config_item table[] = { + { "daemon-binary", pa_config_parse_string, NULL }, + { "extra-arguments", pa_config_parse_string, NULL }, + { "default-sink", pa_config_parse_string, NULL }, + { "default-source", pa_config_parse_string, NULL }, + { "default-server", pa_config_parse_string, NULL }, + { "autospawn", pa_config_parse_bool, NULL }, { NULL, NULL, NULL }, }; + table[0].data = &c->daemon_binary; + table[1].data = &c->extra_arguments; + table[2].data = &c->default_sink; + table[3].data = &c->default_source; + table[4].data = &c->default_server; + table[5].data = &c->autospawn; + if (!filename) filename = getenv(ENV_CLIENT_CONFIG_FILE); -- cgit From 73125ada06ee7adf75dfbb7518d2334abc606459 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 18 Sep 2004 12:38:37 +0000 Subject: work around gcc 2.95 limitation git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@219 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/daemon-conf.c | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c index befb9602..8a0f94ac 100644 --- a/polyp/daemon-conf.c +++ b/polyp/daemon-conf.c @@ -166,22 +166,35 @@ int pa_daemon_conf_load(struct pa_daemon_conf *c, const char *filename) { char *def = NULL; int r; - const struct pa_config_item table[] = { - { "verbose", pa_config_parse_bool, &c->verbose }, - { "daemonize", pa_config_parse_bool, &c->daemonize }, - { "fail", pa_config_parse_bool, &c->fail }, - { "high-priority", pa_config_parse_bool, &c->high_priority }, - { "disallow-module-loading", pa_config_parse_bool, &c->disallow_module_loading }, - { "exit-idle-time", pa_config_parse_int, &c->exit_idle_time }, - { "module-idle-time", pa_config_parse_int, &c->module_idle_time }, - { "scache-idle-time", pa_config_parse_int, &c->scache_idle_time }, - { "dl-search-path", pa_config_parse_string, &c->dl_search_path }, - { "default-script-file", pa_config_parse_string, &c->default_script_file }, - { "log-target", parse_log_target, c }, - { "resample-method", parse_resample_method, c }, + struct pa_config_item table[] = { + { "verbose", pa_config_parse_bool, NULL }, + { "daemonize", pa_config_parse_bool, NULL }, + { "fail", pa_config_parse_bool, NULL }, + { "high-priority", pa_config_parse_bool, NULL }, + { "disallow-module-loading", pa_config_parse_bool, NULL }, + { "exit-idle-time", pa_config_parse_int, NULL }, + { "module-idle-time", pa_config_parse_int, NULL }, + { "scache-idle-time", pa_config_parse_int, NULL }, + { "dl-search-path", pa_config_parse_string, NULL }, + { "default-script-file", pa_config_parse_string, NULL }, + { "log-target", parse_log_target, NULL }, + { "resample-method", parse_resample_method, NULL }, { NULL, NULL, NULL }, }; - + + table[0].data = &c->verbose; + table[1].data = &c->daemonize; + table[2].data = &c->fail; + table[3].data = &c->high_priority; + table[4].data = &c->disallow_module_loading; + table[5].data = &c->exit_idle_time; + table[6].data = &c->module_idle_time; + table[7].data = &c->scache_idle_time; + table[8].data = &c->dl_search_path; + table[9].data = &c->default_script_file; + table[10].data = c; + table[11].data = c; + if (!filename) filename = def = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER); -- cgit From 29653ab83b999f545207a007f35e8a52b34bd576 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 18 Sep 2004 23:40:42 +0000 Subject: add pacat command line parsing git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@220 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + polyp/cmdline.c | 1 - polyp/pacat.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 133 insertions(+), 26 deletions(-) diff --git a/doc/todo b/doc/todo index 300f8d0a..adf305c2 100644 --- a/doc/todo +++ b/doc/todo @@ -2,6 +2,7 @@ *** 0.5 *** - more complete pactl/parec +- xmms segfault when daemon not executable *** 0.6 **** - per-channel volume diff --git a/polyp/cmdline.c b/polyp/cmdline.c index a5bb8101..82ac6183 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -76,7 +76,6 @@ static struct option long_options[] = { {NULL, 0, 0, 0} }; - void pa_cmdline_help(const char *argv0) { const char *e; diff --git a/polyp/pacat.c b/polyp/pacat.c index 933b0c3a..a0db7594 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,11 @@ static size_t buffer_length = 0, buffer_index = 0; static struct pa_io_event* stdio_event = NULL; +static char *stream_name = NULL, *client_name = NULL, *device = NULL; + +static int verbose = 0; +static pa_volume_t volume = PA_VOLUME_NORM; + /* A shortcut for terminating the application */ static void quit(int ret) { assert(mainloop_api); @@ -117,7 +123,8 @@ static void stream_state_callback(struct pa_stream *s, void *userdata) { break; case PA_STREAM_READY: - fprintf(stderr, "Stream successfully created\n"); + if (verbose) + fprintf(stderr, "Stream successfully created\n"); break; case PA_STREAM_FAILED: @@ -146,9 +153,11 @@ static void context_state_callback(struct pa_context *c, void *userdata) { case PA_CONTEXT_READY: assert(c && !stream); - fprintf(stderr, "Connection established.\n"); - stream = pa_stream_new(c, "pacat", &ss); + if (verbose) + fprintf(stderr, "Connection established.\n"); + + stream = pa_stream_new(c, stream_name, &ss); assert(stream); pa_stream_set_state_callback(stream, stream_state_callback, NULL); @@ -156,9 +165,9 @@ static void context_state_callback(struct pa_context *c, void *userdata) { pa_stream_set_read_callback(stream, stream_read_callback, NULL); if (mode == PLAYBACK) - pa_stream_connect_playback(stream, NULL, NULL, PA_VOLUME_NORM); + pa_stream_connect_playback(stream, device, NULL, volume); else - pa_stream_connect_record(stream, NULL, NULL); + pa_stream_connect_record(stream, device, NULL); break; @@ -186,8 +195,9 @@ static void stream_drain_complete(struct pa_stream*s, int success, void *userdat fprintf(stderr, "Failed to drain stream: %s\n", pa_strerror(pa_context_errno(context))); quit(1); } - - fprintf(stderr, "Playback stream drained.\n"); + + if (verbose) + fprintf(stderr, "Playback stream drained.\n"); pa_stream_disconnect(stream); pa_stream_unref(stream); @@ -197,7 +207,9 @@ static void stream_drain_complete(struct pa_stream*s, int success, void *userdat pa_context_disconnect(context); else { pa_operation_unref(o); - fprintf(stderr, "Draining connection to server.\n"); + + if (verbose) + fprintf(stderr, "Draining connection to server.\n"); } } @@ -219,7 +231,8 @@ static void stdin_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int assert(buffer); if ((r = read(fd, buffer, l)) <= 0) { if (r == 0) { - fprintf(stderr, "Got EOF.\n"); + if (verbose) + fprintf(stderr, "Got EOF.\n"); pa_operation_unref(pa_stream_drain(stream, stream_drain_complete, NULL)); } else { fprintf(stderr, "read() failed: %s\n", strerror(errno)); @@ -271,7 +284,8 @@ static void stdout_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int /* UNIX signal to quit recieved */ static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { - fprintf(stderr, "Got SIGINT, exiting.\n"); + if (verbose) + fprintf(stderr, "Got SIGINT, exiting.\n"); quit(0); } @@ -303,10 +317,47 @@ static void sigusr1_signal_callback(struct pa_mainloop_api*m, struct pa_signal_e pa_operation_unref(pa_stream_get_latency(stream, stream_get_latency_callback, NULL)); } + +static void help(const char *argv0) { + + printf("%s [options]\n" + " -h, --help Show this help\n" + " --version Show version\n\n" + " -r, --record Create a connection for recording\n" + " -p, --playback Create a connection for playback\n\n" + " -v, --verbose Enable verbose operations\n\n" + " -s, --server=SERVER The name of the server to connect to\n" + " -d, --device=DEVICE The name of the sink/source to connect to\n" + " -n, --client-name=NAME How to call this client on the server\n" + " --stream-name=NAME How to call this stream on the server\n" + " --volume=VOLUME Specify the initial (linear) volume in range 0...256\n", + argv0); +} + +enum { + ARG_VERSION = 256, + ARG_STREAM_NAME, + ARG_VOLUME +}; + int main(int argc, char *argv[]) { struct pa_mainloop* m = NULL; - int ret = 1, r; - char *bn; + int ret = 1, r, c; + char *bn, *server = NULL; + + static const struct option long_options[] = { + {"record", 0, NULL, 'r'}, + {"playback", 0, NULL, 'p'}, + {"device", 1, NULL, 'd'}, + {"server", 1, NULL, 's'}, + {"client-name", 1, NULL, 'n'}, + {"stream-name", 1, NULL, ARG_STREAM_NAME}, + {"version", 0, NULL, ARG_VERSION}, + {"help", 0, NULL, 'h'}, + {"verbose", 0, NULL, 'v'}, + {"volume", 1, NULL, ARG_VOLUME}, + {NULL, 0, NULL, 0} + }; if (!(bn = strrchr(argv[0], '/'))) bn = argv[0]; @@ -318,18 +369,70 @@ int main(int argc, char *argv[]) { else if (strstr(bn, "cat") || strstr(bn, "play")) mode = PLAYBACK; - if (argc >= 2) { - if (!strcmp(argv[1], "-r")) - mode = RECORD; - else if (!strcmp(argv[1], "-p")) - mode = PLAYBACK; - else { - fprintf(stderr, "Invalid argument\n"); - goto quit; + while ((c = getopt_long(argc, argv, "rpd:s:n:hv", long_options, NULL)) != -1) { + + switch (c) { + case 'h' : + help(bn); + ret = 0; + goto quit; + + case ARG_VERSION: + printf("pacat "PACKAGE_VERSION"\n"); + ret = 0; + goto quit; + + case 'r': + mode = RECORD; + break; + + case 'p': + mode = PLAYBACK; + break; + + case 'd': + free(device); + device = strdup(optarg); + break; + + case 's': + free(server); + server = strdup(optarg); + break; + + case 'n': + free(client_name); + client_name = strdup(optarg); + break; + + case ARG_STREAM_NAME: + free(stream_name); + stream_name = strdup(optarg); + break; + + case 'v': + verbose = 1; + break; + + case ARG_VOLUME: { + int v = atoi(optarg); + volume = v < 0 ? 0 : v; + break; + } + + default: + goto quit; } } - fprintf(stderr, "Opening a %s stream.\n", mode == RECORD ? "recording" : "playback"); + if (!client_name) + client_name = strdup(bn); + + if (!stream_name) + stream_name = strdup(client_name); + + if (verbose) + fprintf(stderr, "Opening a %s stream.\n", mode == RECORD ? "recording" : "playback"); /* Set up a new main loop */ if (!(m = pa_mainloop_new())) { @@ -354,7 +457,7 @@ int main(int argc, char *argv[]) { } /* Create a new connection context */ - if (!(context = pa_context_new(mainloop_api, bn))) { + if (!(context = pa_context_new(mainloop_api, client_name))) { fprintf(stderr, "pa_context_new() failed.\n"); goto quit; } @@ -362,7 +465,7 @@ int main(int argc, char *argv[]) { pa_context_set_state_callback(context, context_state_callback, NULL); /* Connect the context */ - pa_context_connect(context, NULL, 1, NULL); + pa_context_connect(context, server, 1, NULL); /* Run the main loop */ if (pa_mainloop_run(m, &ret) < 0) { @@ -387,8 +490,12 @@ quit: pa_mainloop_free(m); } - if (buffer) - free(buffer); + free(buffer); + + free(server); + free(device); + free(client_name); + free(stream_name); return ret; } -- cgit From 70a30530e03ed4c43639575a479d77e38fea56ea Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 19 Sep 2004 00:03:12 +0000 Subject: add new function pa_mainloop_deferred_pending() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@221 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - polyp/Makefile.am | 8 +++---- polyp/mainloop.c | 60 ++++++++++++++++++++++++++++++++++++++++--------- polyp/mainloop.h | 3 +++ polyp/polyplib-simple.c | 13 +++++++++++ 5 files changed, 70 insertions(+), 15 deletions(-) diff --git a/doc/todo b/doc/todo index adf305c2..22d59e68 100644 --- a/doc/todo +++ b/doc/todo @@ -12,7 +12,6 @@ - make mcalign merge chunks - option to use default fragment size on alsa drivers - improve module-oss-mmap latency measurement -- new mainloop method: defer_pending() ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index e7574447..4adc8add 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -334,7 +334,7 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = polyplib.h \ llist.h \ log.c log.h \ gcc-printf.h \ - client-conf.c client-conf.h \ + client-conf.c client-conf.h \ conf-parser.c conf-parser.h libpolyp_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) @@ -366,11 +366,11 @@ pactl_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMI pactl_CFLAGS = $(AM_CFLAGS) $(LIBSDNFILE_CFLAGS) pacat_simple_SOURCES = pacat-simple.c -pacat_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la +pacat_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la pacat_simple_CFLAGS = $(AM_CFLAGS) parec_simple_SOURCES = parec-simple.c -parec_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la +parec_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la parec_simple_CFLAGS = $(AM_CFLAGS) mainloop_test_SOURCES = mainloop-test.c @@ -541,7 +541,7 @@ esdcompat.sh: esdcompat.sh.in Makefile sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ -e 's,@POLYPAUDIO_BINARY\@,$(bindir)/polypaudio,g' < $< > $@ - + client.conf: client.conf.in Makefile sed -e 's,@POLYPAUDIO_BINARY\@,$(bindir)/polypaudio,g' < $< > $@ diff --git a/polyp/mainloop.c b/polyp/mainloop.c index c4e12ac1..80bcb125 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -79,6 +79,8 @@ struct pa_mainloop { int quit, running, retval; struct pa_mainloop_api api; + + int deferred_pending; }; /* IO events */ @@ -147,17 +149,32 @@ struct pa_defer_event* mainloop_defer_new(struct pa_mainloop_api*a, void (*callb e->destroy_callback = NULL; pa_idxset_put(m->defer_events, e, NULL); + + m->deferred_pending++; return e; } static void mainloop_defer_enable(struct pa_defer_event *e, int b) { assert(e); + + if (e->enabled && !b) { + assert(e->mainloop->deferred_pending > 0); + e->mainloop->deferred_pending--; + } else if (!e->enabled && b) + e->mainloop->deferred_pending++; + e->enabled = b; } static void mainloop_defer_free(struct pa_defer_event *e) { assert(e); e->dead = e->mainloop->defer_events_scan_dead = 1; + + if (e->enabled) { + e->enabled = 0; + assert(e->mainloop->deferred_pending > 0); + e->mainloop->deferred_pending--; + } } static void mainloop_defer_set_destroy(struct pa_defer_event *e, void (*callback)(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata)) { @@ -265,6 +282,8 @@ struct pa_mainloop *pa_mainloop_new(void) { m->api = vtable; m->api.userdata = m; + + m->deferred_pending = 0; return m; } @@ -383,7 +402,7 @@ static int dispatch_pollfds(struct pa_mainloop *m) { struct pa_io_event *e; int r = 0; - for (e = pa_idxset_first(m->io_events, &index); e; e = pa_idxset_next(m->io_events, &index)) { + for (e = pa_idxset_first(m->io_events, &index); e && !m->quit; e = pa_idxset_next(m->io_events, &index)) { if (e->dead || !e->pollfd || !e->pollfd->revents) continue; @@ -406,7 +425,7 @@ static int dispatch_defer(struct pa_mainloop *m) { struct pa_defer_event *e; int r = 0; - for (e = pa_idxset_first(m->defer_events, &index); e; e = pa_idxset_next(m->defer_events, &index)) { + for (e = pa_idxset_first(m->defer_events, &index); e && !m->quit; e = pa_idxset_next(m->defer_events, &index)) { if (e->dead || !e->enabled) continue; @@ -470,7 +489,7 @@ static int dispatch_timeout(struct pa_mainloop *m) { if (pa_idxset_isempty(m->time_events)) return 0; - for (e = pa_idxset_first(m->time_events, &index); e; e = pa_idxset_next(m->time_events, &index)) { + for (e = pa_idxset_first(m->time_events, &index); e && !m->quit; e = pa_idxset_next(m->time_events, &index)) { if (e->dead || !e->enabled) continue; @@ -498,17 +517,17 @@ int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval) { int r, t, dispatched = 0; assert(m && !m->running); - if(m->quit) { - if (retval) - *retval = m->retval; - return -2; - } - m->running = 1; + if(m->quit) + goto quit; + scan_dead(m); dispatched += dispatch_defer(m); + if(m->quit) + goto quit; + if (m->rebuild_pollfds) { rebuild_pollfds(m); m->rebuild_pollfds = 0; @@ -524,9 +543,16 @@ int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval) { pa_log(__FILE__": select(): %s\n", strerror(errno)); } else { dispatched += dispatch_timeout(m); + + if(m->quit) + goto quit; - if (r > 0) + if (r > 0) { dispatched += dispatch_pollfds(m); + + if(m->quit) + goto quit; + } } m->running = 0; @@ -534,6 +560,15 @@ int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval) { /* pa_log("dispatched: %i\n", dispatched); */ return r < 0 ? -1 : dispatched; + +quit: + + m->running = 0; + + if (retval) + *retval = m->retval; + + return -2; } int pa_mainloop_run(struct pa_mainloop *m, int *retval) { @@ -557,3 +592,8 @@ struct pa_mainloop_api* pa_mainloop_get_api(struct pa_mainloop*m) { assert(m); return &m->api; } + +int pa_mainloop_deferred_pending(struct pa_mainloop *m) { + assert(m); + return m->deferred_pending > 0; +} diff --git a/polyp/mainloop.h b/polyp/mainloop.h index a0fe126f..4a64d98f 100644 --- a/polyp/mainloop.h +++ b/polyp/mainloop.h @@ -59,6 +59,9 @@ int pa_mainloop_run(struct pa_mainloop *m, int *retval); /** Return the abstract main loop abstraction layer vtable for this main loop. This calls pa_mainloop_iterate() iteratively.*/ struct pa_mainloop_api* pa_mainloop_get_api(struct pa_mainloop*m); +/** Return non-zero when there are any deferred events pending. \since 0.5 */ +int pa_mainloop_deferred_pending(struct pa_mainloop *m); + PA_C_DECL_END #endif diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c index 5cf52d06..aa6c88f5 100644 --- a/polyp/polyplib-simple.c +++ b/polyp/polyplib-simple.c @@ -99,6 +99,19 @@ static int iterate(struct pa_simple *p, int block, int *perror) { } while (pa_context_is_pending(p->context)); + + while (pa_mainloop_deferred_pending(p->mainloop)) { + + if (pa_mainloop_iterate(p->mainloop, 0, NULL) < 0) { + if (perror) + *perror = PA_ERROR_INTERNAL; + return -1; + } + + if (check_error(p, perror) < 0) + return -1; + } + return 0; } -- cgit From b118982674effa44aa1687e8bd0d2bc0eb6254b2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 19 Sep 2004 23:12:41 +0000 Subject: remove obnoxious assert from module-combine tagstruct: add support for NULL strings improve pactl correct pa_bytes_snprint() pa_sample_spec_snprint(): don't fail on invalid sample spec rename PA_SAMPLE_SNPRINT_MAX_LENGTH to PA_SAMPLE_SPEC_SNPRINT_MAX git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@222 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 +- polyp/cli-command.c | 2 + polyp/cli-text.c | 10 +- polyp/cmdline.c | 2 +- polyp/module-combine.c | 2 +- polyp/pacat.c | 4 +- polyp/pactl.c | 545 +++++++++++++++++++++++++++++++++++++++----- polyp/pdispatch.c | 6 +- polyp/polyplib-introspect.c | 8 +- polyp/polyplib-scache.c | 2 +- polyp/polyplib-stream.c | 5 +- polyp/protocol-native.c | 66 +++--- polyp/sample.c | 20 +- polyp/sample.h | 4 +- polyp/tagstruct.c | 28 ++- 15 files changed, 580 insertions(+), 126 deletions(-) diff --git a/doc/todo b/doc/todo index 22d59e68..ec9e462e 100644 --- a/doc/todo +++ b/doc/todo @@ -1,8 +1,8 @@ *** $Id$ *** *** 0.5 *** -- more complete pactl/parec - xmms segfault when daemon not executable +- update modinfo *** 0.6 **** - per-channel volume diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 750d67ea..39ea9cc1 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -236,6 +236,8 @@ static int pa_cli_command_stat(struct pa_core *c, struct pa_tokenizer *t, struct "Default source name: %s\n", pa_namereg_get_default_sink_name(c), pa_namereg_get_default_source_name(c)); + + return 0; } diff --git a/polyp/cli-text.c b/polyp/cli-text.c index 9932e568..3cedf920 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -88,7 +88,7 @@ char *pa_sink_list_to_string(struct pa_core *c) { pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_ncontents(c->sinks)); for (sink = pa_idxset_first(c->sinks, &index); sink; sink = pa_idxset_next(c->sinks, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec); assert(sink->monitor_source); pa_strbuf_printf( @@ -123,7 +123,7 @@ char *pa_source_list_to_string(struct pa_core *c) { pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_ncontents(c->sources)); for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec); pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n", c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ', @@ -156,7 +156,7 @@ char *pa_source_output_list_to_string(struct pa_core *c) { pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_ncontents(c->source_outputs)); for (o = pa_idxset_first(c->source_outputs, &index); o; o = pa_idxset_next(c->source_outputs, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec); assert(o->source); pa_strbuf_printf( @@ -186,7 +186,7 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_ncontents(c->sink_inputs)); for (i = pa_idxset_first(c->sink_inputs, &index); i; i = pa_idxset_next(c->sink_inputs, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec); assert(i->sink); pa_strbuf_printf( @@ -223,7 +223,7 @@ char *pa_scache_list_to_string(struct pa_core *c) { for (e = pa_idxset_first(c->scache, &index); e; e = pa_idxset_next(c->scache, &index)) { double l = 0; - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH] = "n/a"; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = "n/a"; if (e->memchunk.memblock) { pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec); diff --git a/polyp/cmdline.c b/polyp/cmdline.c index 82ac6183..c32d9a0f 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -84,7 +84,7 @@ void pa_cmdline_help(const char *argv0) { else e = argv0; - printf("%s [options]\n" + printf("%s [options]\n\n" " -h, --help Show this help\n" " --version Show version\n" " --dump-conf Dump default configuration\n" diff --git a/polyp/module-combine.c b/polyp/module-combine.c index f6d596bc..1bb183ec 100644 --- a/polyp/module-combine.c +++ b/polyp/module-combine.c @@ -106,7 +106,7 @@ static void adjust_rates(struct userdata *u) { min_total_latency = o->total_latency; } - assert(max_sink_latency > 0 && min_total_latency != (pa_usec_t) -1); + assert(min_total_latency != (pa_usec_t) -1); target_latency = max_sink_latency > min_total_latency ? max_sink_latency : min_total_latency; diff --git a/polyp/pacat.c b/polyp/pacat.c index a0db7594..b9cb047a 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -320,7 +320,7 @@ static void sigusr1_signal_callback(struct pa_mainloop_api*m, struct pa_signal_e static void help(const char *argv0) { - printf("%s [options]\n" + printf("%s [options]\n\n" " -h, --help Show this help\n" " --version Show version\n\n" " -r, --record Create a connection for recording\n" @@ -378,7 +378,7 @@ int main(int argc, char *argv[]) { goto quit; case ARG_VERSION: - printf("pacat "PACKAGE_VERSION"\n"); + printf("pacat "PACKAGE_VERSION"\nCompiled with libpolyp %s\nLinked with libpolyp %s\n", pa_get_headers_version(), pa_get_library_version()); ret = 0; goto quit; diff --git a/polyp/pactl.c b/polyp/pactl.c index c93fd235..2a466b39 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -45,14 +46,16 @@ static struct pa_context *context = NULL; static struct pa_mainloop_api *mainloop_api = NULL; -static char **process_argv = NULL; +static char *device = NULL, *sample_name = NULL; static SNDFILE *sndfile = NULL; static struct pa_stream *sample_stream = NULL; static struct pa_sample_spec sample_spec; static size_t sample_length = 0; -static char *sample_name = NULL; +static int actions = 1; + +static int nl = 0; static enum { NONE, @@ -60,7 +63,8 @@ static enum { STAT, UPLOAD_SAMPLE, PLAY_SAMPLE, - REMOVE_SAMPLE + REMOVE_SAMPLE, + LIST } action = NONE; static void quit(int ret) { @@ -81,37 +85,373 @@ static void drain(void) { pa_operation_unref(o); } + +static void complete_action(void) { + assert(actions > 0); + + if (!(--actions)) + drain(); +} + static void stat_callback(struct pa_context *c, const struct pa_stat_info *i, void *userdata) { + char s[128]; if (!i) { fprintf(stderr, "Failed to get statistics: %s\n", pa_strerror(pa_context_errno(c))); quit(1); return; } + + pa_bytes_snprint(s, sizeof(s), i->memblock_total_size); + printf("Currently in use: %u blocks containing %s bytes total.\n", i->memblock_total, s); + + pa_bytes_snprint(s, sizeof(s), i->memblock_allocated_size); + printf("Allocated during whole lifetime: %u blocks containing %s bytes total.\n", i->memblock_allocated, s); + + pa_bytes_snprint(s, sizeof(s), i->scache_size); + printf("Sample cache size: %s\n", s); - fprintf(stderr, "Currently in use: %u blocks containing %u bytes total.\n" - "Allocated during whole lifetime: %u blocks containing %u bytes total.\n", - i->memblock_total, i->memblock_total_size, i->memblock_allocated, i->memblock_allocated_size); - drain(); + complete_action(); } -static void play_sample_callback(struct pa_context *c, int success, void *userdata) { - if (!success) { - fprintf(stderr, "Failed to play sample: %s\n", pa_strerror(pa_context_errno(c))); +static void get_server_info_callback(struct pa_context *c, const struct pa_server_info *i, void *useerdata) { + char s[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + if (!i) { + fprintf(stderr, "Failed to get server information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); + + printf("User name: %s\n" + "Host Name: %s\n" + "Server Name: %s\n" + "Server Version: %s\n" + "Default Sample Specification: %s\n" + "Default Sink: %s\n" + "Default Source: %s\n", + i->user_name, + i->host_name, + i->server_name, + i->server_version, + s, + i->default_sink_name, + i->default_source_name); + + complete_action(); +} + +static void get_sink_info_callback(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata) { + char s[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get sink information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); + + printf("*** Sink #%u ***\n" + "Name: %s\n" + "Description: %s\n" + "Sample Specification: %s\n" + "Owner Module: %u\n" + "Volume: 0x%03x (%0.2f dB)\n" + "Monitor Source: %u\n" + "Latency: %0.0f usec\n", + i->index, + i->name, + i->description, + s, + i->owner_module, + i->volume, pa_volume_to_dB(i->volume), + i->monitor_source, + (double) i->latency); +} + +static void get_source_info_callback(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata) { + char s[PA_SAMPLE_SPEC_SNPRINT_MAX], t[32]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get source information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + snprintf(t, sizeof(t), "%u", i->monitor_of_sink); + + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); + + printf("*** Source #%u ***\n" + "Name: %s\n" + "Description: %s\n" + "Sample Specification: %s\n" + "Owner Module: %u\n" + "Monitor of Sink: %s\n" + "Latency: %0.0f usec\n", + i->index, + i->name, + i->description, + s, + i->owner_module, + i->monitor_of_sink != PA_INVALID_INDEX ? t : "no", + (double) i->latency); +} + +static void get_module_info_callback(struct pa_context *c, const struct pa_module_info *i, int is_last, void *userdata) { + char t[32]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get module information: %s\n", pa_strerror(pa_context_errno(c))); quit(1); return; } - drain(); + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + snprintf(t, sizeof(t), "%u", i->n_used); + + printf("*** Module #%u ***\n" + "Name: %s\n" + "Argument: %s\n" + "Usage counter: %s\n" + "Auto unload: %s\n", + i->index, + i->name, + i->argument, + i->n_used != PA_INVALID_INDEX ? t : "n/a", + i->auto_unload ? "yes" : "no"); +} + +static void get_client_info_callback(struct pa_context *c, const struct pa_client_info *i, int is_last, void *userdata) { + char t[32]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get client information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + snprintf(t, sizeof(t), "%u", i->owner_module); + + printf("*** Client #%u ***\n" + "Name: %s\n" + "Owner Module: %s\n" + "Protocol Name: %s\n", + i->index, + i->name, + i->owner_module != PA_INVALID_INDEX ? t : "n/a", + i->protocol_name); } -static void remove_sample_callback(struct pa_context *c, int success, void *userdata) { +static void get_sink_input_info_callback(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata) { + char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get sink input information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); + snprintf(t, sizeof(t), "%u", i->owner_module); + snprintf(k, sizeof(k), "%u", i->client); + + printf("*** Sink Input #%u ***\n" + "Name: %s\n" + "Owner Module: %s\n" + "Client: %s\n" + "Sink: %u\n" + "Sample Specification: %s\n" + "Volume: 0x%03x (%0.2f dB)\n" + "Buffer Latency: %0.0f usec\n" + "Sink Latency: %0.0f usec\n", + i->index, + i->name, + i->owner_module != PA_INVALID_INDEX ? t : "n/a", + i->client != PA_INVALID_INDEX ? k : "n/a", + i->sink, + s, + i->volume, pa_volume_to_dB(i->volume), + (double) i->buffer_usec, + (double) i->sink_usec); +} + +static void get_source_output_info_callback(struct pa_context *c, const struct pa_source_output_info *i, int is_last, void *userdata) { + char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get source output information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); + snprintf(t, sizeof(t), "%u", i->owner_module); + snprintf(k, sizeof(k), "%u", i->client); + + printf("*** Source Output #%u ***\n" + "Name: %s\n" + "Owner Module: %s\n" + "Client: %s\n" + "Source: %u\n" + "Sample Specification: %s\n" + "Buffer Latency: %0.0f usec\n" + "Source Latency: %0.0f usec\n", + i->index, + i->name, + i->owner_module != PA_INVALID_INDEX ? t : "n/a", + i->client != PA_INVALID_INDEX ? k : "n/a", + i->source, + s, + (double) i->buffer_usec, + (double) i->source_usec); +} + +static void get_sample_info_callback(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata) { + char t[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get sample information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); + pa_bytes_snprint(t, sizeof(t), i->bytes); + + printf("*** Sample #%u ***\n" + "Name: %s\n" + "Volume: 0x%03x (%0.2f dB)\n" + "Sample Specification: %s\n" + "Duration: %0.1fs\n" + "Size: %s\n" + "Lazy: %s\n" + "Filename: %s\n", + i->index, + i->name, + i->volume, pa_volume_to_dB(i->volume), + pa_sample_spec_valid(&i->sample_spec) ? s : "n/a", + (double) i->duration/1000000, + t, + i->lazy ? "yes" : "no", + i->filename ? i->filename : "n/a"); +} + +static void get_autoload_info_callback(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata) { + if (is_last < 0) { + fprintf(stderr, "Failed to get autoload information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + printf("*** Autoload Entry ***\n" + "Name: %s\n" + "Type: %s\n" + "Module: %s\n" + "Argument: %s\n", + i->name, + i->type == PA_AUTOLOAD_SINK ? "sink" : "source", + i->module, + i->argument); +} + +static void simple_callback(struct pa_context *c, int success, void *userdata) { if (!success) { - fprintf(stderr, "Failed to remove sample: %s\n", pa_strerror(pa_context_errno(c))); + fprintf(stderr, "Failure: %s\n", pa_strerror(pa_context_errno(c))); quit(1); return; } - drain(); + complete_action(); } static void stream_state_callback(struct pa_stream *s, void *userdata) { @@ -169,24 +509,48 @@ static void context_state_callback(struct pa_context *c, void *userdata) { break; case PA_CONTEXT_READY: - if (action == STAT) - pa_operation_unref(pa_context_stat(c, stat_callback, NULL)); - else if (action == PLAY_SAMPLE) - pa_operation_unref(pa_context_play_sample(c, process_argv[2], NULL, 0x100, play_sample_callback, NULL)); - else if (action == REMOVE_SAMPLE) - pa_operation_unref(pa_context_remove_sample(c, process_argv[2], remove_sample_callback, NULL)); - else if (action == UPLOAD_SAMPLE) { - - sample_stream = pa_stream_new(c, sample_name, &sample_spec); - assert(sample_stream); - - pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL); - pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL); - pa_stream_connect_upload(sample_stream, sample_length); - } else { - assert(action == EXIT); - pa_context_exit_daemon(c); - drain(); + switch (action) { + case STAT: + actions = 2; + pa_operation_unref(pa_context_stat(c, stat_callback, NULL)); + pa_operation_unref(pa_context_get_server_info(c, get_server_info_callback, NULL)); + break; + + case PLAY_SAMPLE: + pa_operation_unref(pa_context_play_sample(c, sample_name, device, PA_VOLUME_NORM, simple_callback, NULL)); + break; + + case REMOVE_SAMPLE: + pa_operation_unref(pa_context_remove_sample(c, sample_name, simple_callback, NULL)); + break; + + case UPLOAD_SAMPLE: + sample_stream = pa_stream_new(c, sample_name, &sample_spec); + assert(sample_stream); + + pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL); + pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL); + pa_stream_connect_upload(sample_stream, sample_length); + break; + + case EXIT: + pa_context_exit_daemon(c); + drain(); + + case LIST: + actions = 8; + pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL)); + pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL)); + pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL)); + pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL)); + pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL)); + pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL)); + pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL)); + pa_operation_unref(pa_context_get_autoload_info_list(c, get_autoload_info_callback, NULL)); + break; + + default: + assert(0); } break; @@ -206,43 +570,106 @@ static void exit_signal_callback(struct pa_mainloop_api *m, struct pa_signal_eve quit(0); } +static void help(const char *argv0) { + + printf("%s [options] stat\n" + "%s [options] list\n" + "%s [options] exit\n" + "%s [options] upload-sample FILENAME [NAME]\n" + "%s [options] play-sample NAME [SINK]\n" + "%s [options] remove-sample NAME\n\n" + " -h, --help Show this help\n" + " --version Show version\n\n" + " -s, --server=SERVER The name of the server to connect to\n" + " -n, --client-name=NAME How to call this client on the server\n", + argv0, argv0, argv0, argv0, argv0, argv0); +} + +enum { ARG_VERSION = 256 }; + int main(int argc, char *argv[]) { struct pa_mainloop* m = NULL; char tmp[PATH_MAX]; + int ret = 1, r, c; + char *server = NULL, *client_name = NULL, *bn; + + static const struct option long_options[] = { + {"server", 1, NULL, 's'}, + {"client-name", 1, NULL, 'n'}, + {"version", 0, NULL, ARG_VERSION}, + {"help", 0, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + if (!(bn = strrchr(argv[0], '/'))) + bn = argv[0]; + else + bn++; - int ret = 1, r; + while ((c = getopt_long(argc, argv, "s:n:h", long_options, NULL)) != -1) { + switch (c) { + case 'h' : + help(bn); + ret = 0; + goto quit; + + case ARG_VERSION: + printf("pactl "PACKAGE_VERSION"\nCompiled with libpolyp %s\nLinked with libpolyp %s\n", pa_get_headers_version(), pa_get_library_version()); + ret = 0; + goto quit; + + case 's': + free(server); + server = strdup(optarg); + break; + + case 'n': + free(client_name); + client_name = strdup(optarg); + break; + + default: + goto quit; + } + } - if (argc >= 2) { - if (!strcmp(argv[1], "stat")) + if (!client_name) + client_name = strdup(bn); + + if (optind < argc) { + if (!strcmp(argv[optind], "stat")) action = STAT; - else if (!strcmp(argv[1], "exit")) + else if (!strcmp(argv[optind], "exit")) action = EXIT; - else if (!strcmp(argv[1], "scache_upload")) { + else if (!strcmp(argv[optind], "list")) + action = LIST; + else if (!strcmp(argv[optind], "upload-sample")) { struct SF_INFO sfinfo; action = UPLOAD_SAMPLE; - if (argc < 3) { + if (optind+1 >= argc) { fprintf(stderr, "Please specify a sample file to load\n"); goto quit; } - if (argc >= 4) - sample_name = argv[3]; + if (optind+2 < argc) + sample_name = strdup(argv[optind+2]); else { - char *f = strrchr(argv[2], '/'); + char *f = strrchr(argv[optind+1], '/'); size_t n; if (f) f++; else - f = argv[2]; + f = argv[optind]; n = strcspn(f, "."); - strncpy(sample_name = tmp, f, n); - tmp[n] = 0; + strncpy(tmp, f, n); + tmp[n] = 0; + sample_name = strdup(tmp); } memset(&sfinfo, 0, sizeof(sfinfo)); - if (!(sndfile = sf_open(argv[2], SFM_READ, &sfinfo))) { + if (!(sndfile = sf_open(argv[optind+1], SFM_READ, &sfinfo))) { fprintf(stderr, "Failed to open sound file.\n"); goto quit; } @@ -252,28 +679,34 @@ int main(int argc, char *argv[]) { sample_spec.channels = sfinfo.channels; sample_length = sfinfo.frames*pa_frame_size(&sample_spec); - } else if (!strcmp(argv[1], "scache_play")) { + } else if (!strcmp(argv[optind], "play-sample")) { action = PLAY_SAMPLE; - if (argc < 3) { + if (optind+1 >= argc) { fprintf(stderr, "You have to specify a sample name to play\n"); goto quit; } - } else if (!strcmp(argv[1], "scache_remove")) { + + sample_name = strdup(argv[optind+1]); + + if (optind+2 < argc) + device = strdup(argv[optind+2]); + + } else if (!strcmp(argv[optind], "remove-sample")) { action = REMOVE_SAMPLE; - if (argc < 3) { + if (optind+1 >= argc) { fprintf(stderr, "You have to specify a sample name to remove\n"); goto quit; } + + sample_name = strdup(argv[optind+1]); } } if (action == NONE) { - fprintf(stderr, "No valid action specified. Use one of: stat, exit, scache_upload, scache_play, scache_remove\n"); + fprintf(stderr, "No valid command specified.\n"); goto quit; } - process_argv = argv; - if (!(m = pa_mainloop_new())) { fprintf(stderr, "pa_mainloop_new() failed.\n"); goto quit; @@ -286,13 +719,13 @@ int main(int argc, char *argv[]) { pa_signal_new(SIGINT, exit_signal_callback, NULL); signal(SIGPIPE, SIG_IGN); - if (!(context = pa_context_new(mainloop_api, argv[0]))) { + if (!(context = pa_context_new(mainloop_api, client_name))) { fprintf(stderr, "pa_context_new() failed.\n"); goto quit; } pa_context_set_state_callback(context, context_state_callback, NULL); - pa_context_connect(context, NULL, 1, NULL); + pa_context_connect(context, server, 1, NULL); if (pa_mainloop_run(m, &ret) < 0) { fprintf(stderr, "pa_mainloop_run() failed.\n"); @@ -314,5 +747,9 @@ quit: if (sndfile) sf_close(sndfile); + free(server); + free(device); + free(sample_name); + return ret; } diff --git a/polyp/pdispatch.c b/polyp/pdispatch.c index 88f85e02..f6481fa0 100644 --- a/polyp/pdispatch.c +++ b/polyp/pdispatch.c @@ -33,7 +33,7 @@ #include "llist.h" #include "log.h" -/*#define DEBUG_OPCODES*/ +/* #define DEBUG_OPCODES */ #ifdef DEBUG_OPCODES @@ -48,7 +48,7 @@ static const char *command_names[PA_COMMAND_MAX] = { [PA_COMMAND_AUTH] = "AUTH", [PA_COMMAND_REQUEST] = "REQUEST", [PA_COMMAND_EXIT] = "EXIT", - [PA_COMMAND_SET_NAME] = "SET_NAME", + [PA_COMMAND_SET_CLIENT_NAME] = "SET_CLIENT_NAME", [PA_COMMAND_LOOKUP_SINK] = "LOOKUP_SINK", [PA_COMMAND_LOOKUP_SOURCE] = "LOOKUP_SOURCE", [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = "DRAIN_PLAYBACK_STREAM", @@ -83,6 +83,8 @@ static const char *command_names[PA_COMMAND_MAX] = { [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = "TRIGGER_PLAYBACK_STREAM", [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = "FLUSH_PLAYBACK_STREAM", [PA_COMMAND_CORK_PLAYBACK_STREAM] = "CORK_PLAYBACK_STREAM", + [PA_COMMAND_GET_AUTOLOAD_INFO] = "GET_AUTOLOAD_INFO", + [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = "GET_AUTOLOAD_INFO_LIST", }; #endif diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index 1673be9b..267af95b 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -170,7 +170,7 @@ struct pa_operation* pa_context_get_sink_info_by_index(struct pa_context *c, uin pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); + pa_tagstruct_puts(t, NULL); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, o); @@ -263,7 +263,7 @@ struct pa_operation* pa_context_get_source_info_by_index(struct pa_context *c, u pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); + pa_tagstruct_puts(t, NULL); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, o); @@ -581,7 +581,7 @@ struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, u pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); + pa_tagstruct_puts(t, NULL); pa_tagstruct_putu32(t, volume); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); @@ -713,7 +713,7 @@ struct pa_operation* pa_context_get_sample_info_by_index(struct pa_context *c, u pa_tagstruct_putu32(t, PA_COMMAND_GET_SAMPLE_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); + pa_tagstruct_puts(t, NULL); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, o); diff --git a/polyp/polyplib-scache.c b/polyp/polyplib-scache.c index 7221420c..45220d10 100644 --- a/polyp/polyplib-scache.c +++ b/polyp/polyplib-scache.c @@ -95,7 +95,7 @@ struct pa_operation * pa_context_play_sample(struct pa_context *c, const char *n pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); + pa_tagstruct_puts(t, dev); pa_tagstruct_putu32(t, volume); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 6055a220..8bd098d4 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -194,7 +194,7 @@ void pa_create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32 if (pa_tagstruct_getu32(t, &s->channel) < 0 || ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - ((s->direction == PA_STREAM_PLAYBACK) && pa_tagstruct_getu32(t, &s->requested_bytes) < 0) || + ((s->direction != PA_STREAM_RECORD) && pa_tagstruct_getu32(t, &s->requested_bytes) < 0) || !pa_tagstruct_eof(t)) { pa_context_fail(s->context, PA_ERROR_PROTOCOL); goto finish; @@ -245,7 +245,7 @@ static void create_stream(struct pa_stream *s, const char *dev, const struct pa_ pa_tagstruct_puts(t, s->name); pa_tagstruct_put_sample_spec(t, &s->sample_spec); pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, dev ? dev : ""); + pa_tagstruct_puts(t, dev); pa_tagstruct_putu32(t, s->buffer_attr.maxlength); if (s->direction == PA_STREAM_PLAYBACK) { pa_tagstruct_putu32(t, s->buffer_attr.tlength); @@ -536,7 +536,6 @@ struct pa_operation* pa_stream_send_simple_command(struct pa_stream *s, uint32_t return pa_operation_ref(o); } - struct pa_operation* pa_stream_flush(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { return pa_stream_send_simple_command(s, PA_COMMAND_FLUSH_PLAYBACK_STREAM, cb, userdata); } diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 021c1a60..4c1e9696 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -540,7 +540,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com pa_volume_t volume; assert(c && t && c->protocol && c->protocol->core); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || !name || pa_tagstruct_get_sample_spec(t, &ss) < 0 || pa_tagstruct_getu32(t, &sink_index) < 0 || pa_tagstruct_gets(t, &sink_name) < 0 || @@ -554,6 +554,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com return; } + if (!c->authorized) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); return; @@ -562,7 +563,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com if (sink_index != (uint32_t) -1) sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); else - sink = pa_namereg_get(c->protocol->core, *sink_name ? sink_name : NULL, PA_NAMEREG_SINK, 1); + sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1); if (!sink) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); @@ -643,7 +644,7 @@ static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t comma struct pa_source *source; assert(c && t && c->protocol && c->protocol->core); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || !name || pa_tagstruct_get_sample_spec(t, &ss) < 0 || pa_tagstruct_getu32(t, &source_index) < 0 || pa_tagstruct_gets(t, &source_name) < 0 || @@ -662,7 +663,7 @@ static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t comma if (source_index != (uint32_t) -1) source = pa_idxset_get_by_index(c->protocol->core->sources, source_index); else - source = pa_namereg_get(c->protocol->core, *source_name ? source_name : NULL, PA_NAMEREG_SOURCE, 1); + source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE, 1); if (!source) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); @@ -734,7 +735,7 @@ static void command_set_client_name(struct pa_pdispatch *pd, uint32_t command, u const char *name; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || !name || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -751,7 +752,7 @@ static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t t uint32_t index = PA_IDXSET_INVALID; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || !name || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -939,7 +940,7 @@ static void command_create_upload_stream(struct pa_pdispatch *pd, uint32_t comma struct pa_tagstruct *reply; assert(c && t && c->protocol && c->protocol->core); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || !name || pa_tagstruct_get_sample_spec(t, &ss) < 0 || pa_tagstruct_getu32(t, &length) < 0 || !pa_tagstruct_eof(t)) { @@ -967,13 +968,6 @@ static void command_create_upload_stream(struct pa_pdispatch *pd, uint32_t comma pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); pa_tagstruct_putu32(reply, tag); pa_tagstruct_putu32(reply, s->index); - pa_pstream_send_tagstruct(c->pstream, reply); - - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REQUEST); - pa_tagstruct_putu32(reply, (uint32_t) -1); /* tag */ - pa_tagstruct_putu32(reply, s->index); pa_tagstruct_putu32(reply, length); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -1016,7 +1010,7 @@ static void command_play_sample(struct pa_pdispatch *pd, uint32_t command, uint3 if (pa_tagstruct_getu32(t, &sink_index) < 0 || pa_tagstruct_gets(t, &sink_name) < 0 || pa_tagstruct_getu32(t, &volume) < 0 || - pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_gets(t, &name) < 0 || !name || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1030,7 +1024,7 @@ static void command_play_sample(struct pa_pdispatch *pd, uint32_t command, uint3 if (sink_index != (uint32_t) -1) sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); else - sink = pa_namereg_get(c->protocol->core, *sink_name ? sink_name : NULL, PA_NAMEREG_SINK, 1); + sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1); if (!sink) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); @@ -1050,7 +1044,7 @@ static void command_remove_sample(struct pa_pdispatch *pd, uint32_t command, uin const char *name; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || !name || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1073,7 +1067,7 @@ static void sink_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink *sink) { assert(t && sink); pa_tagstruct_putu32(t, sink->index); pa_tagstruct_puts(t, sink->name); - pa_tagstruct_puts(t, sink->description ? sink->description : ""); + pa_tagstruct_puts(t, sink->description); pa_tagstruct_put_sample_spec(t, &sink->sample_spec); pa_tagstruct_putu32(t, sink->owner ? sink->owner->index : (uint32_t) -1); pa_tagstruct_putu32(t, sink->volume); @@ -1086,11 +1080,11 @@ static void source_fill_tagstruct(struct pa_tagstruct *t, struct pa_source *sour assert(t && source); pa_tagstruct_putu32(t, source->index); pa_tagstruct_puts(t, source->name); - pa_tagstruct_puts(t, source->description ? source->description : ""); + pa_tagstruct_puts(t, source->description); pa_tagstruct_put_sample_spec(t, &source->sample_spec); pa_tagstruct_putu32(t, source->owner ? source->owner->index : (uint32_t) -1); pa_tagstruct_putu32(t, source->monitor_of ? source->monitor_of->index : (uint32_t) -1); - pa_tagstruct_puts(t, source->monitor_of ? source->monitor_of->name : ""); + pa_tagstruct_puts(t, source->monitor_of ? source->monitor_of->name : NULL); pa_tagstruct_put_usec(t, pa_source_get_latency(source)); } @@ -1106,7 +1100,7 @@ static void module_fill_tagstruct(struct pa_tagstruct *t, struct pa_module *modu assert(t && module); pa_tagstruct_putu32(t, module->index); pa_tagstruct_puts(t, module->name); - pa_tagstruct_puts(t, module->argument ? module->argument : ""); + pa_tagstruct_puts(t, module->argument); pa_tagstruct_putu32(t, module->n_used); pa_tagstruct_put_boolean(t, module->auto_unload); } @@ -1114,7 +1108,7 @@ static void module_fill_tagstruct(struct pa_tagstruct *t, struct pa_module *modu static void sink_input_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink_input *s) { assert(t && s); pa_tagstruct_putu32(t, s->index); - pa_tagstruct_puts(t, s->name ? s->name : ""); + pa_tagstruct_puts(t, s->name); pa_tagstruct_putu32(t, s->owner ? s->owner->index : (uint32_t) -1); pa_tagstruct_putu32(t, s->client ? s->client->index : (uint32_t) -1); pa_tagstruct_putu32(t, s->sink->index); @@ -1127,7 +1121,7 @@ static void sink_input_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink_inp static void source_output_fill_tagstruct(struct pa_tagstruct *t, struct pa_source_output *s) { assert(t && s); pa_tagstruct_putu32(t, s->index); - pa_tagstruct_puts(t, s->name ? s->name : ""); + pa_tagstruct_puts(t, s->name); pa_tagstruct_putu32(t, s->owner ? s->owner->index : (uint32_t) -1); pa_tagstruct_putu32(t, s->client ? s->client->index : (uint32_t) -1); pa_tagstruct_putu32(t, s->source->index); @@ -1183,12 +1177,12 @@ static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t if (index != (uint32_t) -1) sink = pa_idxset_get_by_index(c->protocol->core->sinks, index); else - sink = pa_namereg_get(c->protocol->core, *name ? name : NULL, PA_NAMEREG_SINK, 1); + sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); } else if (command == PA_COMMAND_GET_SOURCE_INFO) { if (index != (uint32_t) -1) source = pa_idxset_get_by_index(c->protocol->core->sources, index); else - source = pa_namereg_get(c->protocol->core, *name ? name : NULL, PA_NAMEREG_SOURCE, 1); + source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); } else if (command == PA_COMMAND_GET_CLIENT_INFO) client = pa_idxset_get_by_index(c->protocol->core->clients, index); else if (command == PA_COMMAND_GET_MODULE_INFO) @@ -1198,7 +1192,7 @@ static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO) so = pa_idxset_get_by_index(c->protocol->core->source_outputs, index); else { - assert(command == PA_COMMAND_GET_SAMPLE_INFO && name); + assert(command == PA_COMMAND_GET_SAMPLE_INFO); if (index != (uint32_t) -1) sce = pa_idxset_get_by_index(c->protocol->core->scache, index); else @@ -1323,9 +1317,9 @@ static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, u pa_tagstruct_put_sample_spec(reply, &c->protocol->core->default_sample_spec); n = pa_namereg_get_default_sink_name(c->protocol->core); - pa_tagstruct_puts(reply, n ? n : ""); + pa_tagstruct_puts(reply, n); n = pa_namereg_get_default_source_name(c->protocol->core); - pa_tagstruct_puts(reply, n ? n : ""); + pa_tagstruct_puts(reply, n); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -1396,7 +1390,7 @@ static void command_set_volume(struct pa_pdispatch *pd, uint32_t command, uint32 if (index != (uint32_t) -1) sink = pa_idxset_get_by_index(c->protocol->core->sinks, index); else - sink = pa_namereg_get(c->protocol->core, *name ? name : NULL, PA_NAMEREG_SINK, 1); + sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); } else { assert(command == PA_COMMAND_SET_SINK_INPUT_VOLUME); si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, index); @@ -1485,7 +1479,7 @@ static void command_set_default_sink_or_source(struct pa_pdispatch *pd, uint32_t assert(c && t); if (pa_tagstruct_getu32(t, &index) < 0 || - pa_tagstruct_gets(t, &s) < 0 || + pa_tagstruct_gets(t, &s) < 0 || !s || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1507,7 +1501,7 @@ static void command_set_stream_name(struct pa_pdispatch *pd, uint32_t command, u assert(c && t); if (pa_tagstruct_getu32(t, &index) < 0 || - pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_gets(t, &name) < 0 || !name || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1599,7 +1593,7 @@ static void command_load_module(struct pa_pdispatch *pd, uint32_t command, uint3 struct pa_tagstruct *reply; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || !name || pa_tagstruct_gets(t, &argument) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1655,9 +1649,9 @@ static void command_add_autoload(struct pa_pdispatch *pd, uint32_t command, uint uint32_t type; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || !name || pa_tagstruct_getu32(t, &type) < 0 || type > 1 || - pa_tagstruct_gets(t, &module) < 0 || + pa_tagstruct_gets(t, &module) < 0 || !module || pa_tagstruct_gets(t, &argument) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1683,7 +1677,7 @@ static void command_remove_autoload(struct pa_pdispatch *pd, uint32_t command, u uint32_t type; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || !name || pa_tagstruct_getu32(t, &type) < 0 || type > 1 || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1719,7 +1713,7 @@ static void command_get_autoload_info(struct pa_pdispatch *pd, uint32_t command, struct pa_tagstruct *reply; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || name || pa_tagstruct_getu32(t, &type) < 0 || type > 1 || !pa_tagstruct_eof(t)) { protocol_error(c); diff --git a/polyp/sample.c b/polyp/sample.c index 397e57a2..143e1e41 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -94,7 +94,11 @@ void pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spec [PA_SAMPLE_FLOAT32BE] = "FLOAT32BE", }; - assert(pa_sample_spec_valid(spec)); + if (!pa_sample_spec_valid(spec)) { + snprintf(s, l, "Invalid"); + return; + } + snprintf(s, l, "%s %uch %uHz", table[spec->format], spec->channels, spec->rate); } @@ -120,13 +124,13 @@ double pa_volume_to_dB(pa_volume_t v) { return 20*log10((double) v/PA_VOLUME_NORM); } -void pa_bytes_snprint(char *s, size_t l, off_t v) { - if (v >= (off_t) 1024*1024*1024) - snprintf(s, l, "%0.1f GB", (double) v/1024/1024/1024); - else if (v >= (off_t) 1024*1024) - snprintf(s, l, "%0.1f MB", (double) v/1024/1024); - else if (v >= (off_t) 1024) - snprintf(s, l, "%0.1f KB", (double) v/1024); +void pa_bytes_snprint(char *s, size_t l, unsigned v) { + if (v >= ((unsigned) 1024)*1024*1024) + snprintf(s, l, "%0.1f GB", ((double) v)/1024/1024/1024); + else if (v >= ((unsigned) 1024)*1024) + snprintf(s, l, "%0.1f MB", ((double) v)/1024/1024); + else if (v >= (unsigned) 1024) + snprintf(s, l, "%0.1f KB", ((double) v)/1024); else snprintf(s, l, "%u B", (unsigned) v); } diff --git a/polyp/sample.h b/polyp/sample.h index 1e42a260..501172a8 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -86,7 +86,7 @@ int pa_sample_spec_valid(const struct pa_sample_spec *spec); int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b); /** Maximum required string length for pa_sample_spec_snprint() */ -#define PA_SAMPLE_SNPRINT_MAX_LENGTH 32 +#define PA_SAMPLE_SPEC_SNPRINT_MAX 32 /** Pretty print a sample type specification to a string */ void pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spec); @@ -117,7 +117,7 @@ double pa_volume_to_dB(pa_volume_t v); #endif /** Pretty print a byte size value. (i.e. "2.5 MB") */ -void pa_bytes_snprint(char *s, size_t l, off_t v); +void pa_bytes_snprint(char *s, size_t l, unsigned v); PA_C_DECL_END diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c index d571b713..39ae87b5 100644 --- a/polyp/tagstruct.c +++ b/polyp/tagstruct.c @@ -33,6 +33,7 @@ enum tags { TAG_STRING = 't', + TAG_NULL_STRING = 'N', TAG_U32 = 'L', TAG_S32 = 'l', TAG_U16 = 'S', @@ -97,12 +98,18 @@ static void extend(struct pa_tagstruct*t, size_t l) { void pa_tagstruct_puts(struct pa_tagstruct*t, const char *s) { size_t l; - assert(t && s); - l = strlen(s)+2; - extend(t, l); - t->data[t->length] = TAG_STRING; - strcpy((char*) (t->data+t->length+1), s); - t->length += l; + assert(t); + if (s) { + l = strlen(s)+2; + extend(t, l); + t->data[t->length] = TAG_STRING; + strcpy((char*) (t->data+t->length+1), s); + t->length += l; + } else { + extend(t, 1); + t->data[t->length] = TAG_NULL_STRING; + t->length += 1; + } } void pa_tagstruct_putu32(struct pa_tagstruct*t, uint32_t i) { @@ -173,6 +180,15 @@ int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s) { char *c; assert(t && s); + if (t->rindex+1 > t->length) + return -1; + + if (t->data[t->rindex] == TAG_NULL_STRING) { + t->rindex++; + *s = NULL; + return 0; + } + if (t->rindex+2 > t->length) return -1; -- cgit From 42bba491a897c996219c8aa01897f5b3cba6e33e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Sep 2004 17:19:35 +0000 Subject: update module descriptions git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@223 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + polyp/module-alsa-sink.c | 1 + polyp/module-alsa-source.c | 3 ++- polyp/module-cli.c | 1 + polyp/module-oss-mmap.c | 1 + polyp/module-oss.c | 1 + polyp/module-pipe-sink.c | 3 ++- polyp/module-pipe-source.c | 1 + polyp/module-protocol-stub.c | 8 +++++++- polyp/util.c | 4 ++-- 10 files changed, 19 insertions(+), 5 deletions(-) diff --git a/doc/todo b/doc/todo index ec9e462e..b857075f 100644 --- a/doc/todo +++ b/doc/todo @@ -12,6 +12,7 @@ - make mcalign merge chunks - option to use default fragment size on alsa drivers - improve module-oss-mmap latency measurement +- proper locking around native protocol socket ** later *** - xmlrpc/http diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index c31b73f0..528fe8d3 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -43,6 +43,7 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ALSA Sink") PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink_name= device= format= channels= rate= fragments= fragment_size=") struct userdata { snd_pcm_t *pcm_handle; diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index 41a17691..c0a18d2b 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -43,6 +43,7 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ALSA Source") PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("source_name= device= format= channels= rate= fragments= fragment_size=") struct userdata { snd_pcm_t *pcm_handle; @@ -58,9 +59,9 @@ struct userdata { static const char* const valid_modargs[] = { "device", "source_name", - "format", "channels", "rate", + "format", "fragments", "fragment_size", NULL diff --git a/polyp/module-cli.c b/polyp/module-cli.c index 94c65d07..6444194c 100644 --- a/polyp/module-cli.c +++ b/polyp/module-cli.c @@ -36,6 +36,7 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Command line interface") PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("No arguments") static void eof_cb(struct pa_cli*c, void *userdata) { struct pa_module *m = userdata; diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index 015f4c6c..f7fcbd3b 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -50,6 +50,7 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("OSS Sink/Source (mmap)") PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= fragments= fragment_size=") struct userdata { struct pa_sink *sink; diff --git a/polyp/module-oss.c b/polyp/module-oss.c index 68918604..c0c6be8e 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -49,6 +49,7 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("OSS Sink/Source") PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= fragments= fragment_size=") struct userdata { struct pa_sink *sink; diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c index 57e7425b..c5097fb7 100644 --- a/polyp/module-pipe-sink.c +++ b/polyp/module-pipe-sink.c @@ -44,6 +44,7 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("UNIX pipe sink") PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink_name= file= format= channels= rate=") #define DEFAULT_FIFO_NAME "/tmp/music.output" #define DEFAULT_SINK_NAME "fifo_output" @@ -64,8 +65,8 @@ struct userdata { static const char* const valid_modargs[] = { "file", "rate", - "channels", "format", + "channels", "sink_name", NULL }; diff --git a/polyp/module-pipe-source.c b/polyp/module-pipe-source.c index 61fcdce8..3decc415 100644 --- a/polyp/module-pipe-source.c +++ b/polyp/module-pipe-source.c @@ -44,6 +44,7 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("UNIX pipe source") PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("source_name= file= format= channels= rate=") #define DEFAULT_FIFO_NAME "/tmp/music.input" #define DEFAULT_SOURCE_NAME "fifo_input" diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index fe9e12a1..46522d9b 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -42,11 +42,12 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #ifdef USE_TCP_SOCKETS #define SOCKET_DESCRIPTION "(TCP sockets)" +#define SOCKET_USAGE "port= loopback=" #else #define SOCKET_DESCRIPTION "(UNIX sockets)" +#define SOCKET_USAGE "socket=" #endif - #if defined(USE_PROTOCOL_SIMPLE) #include "protocol-simple.h" #define protocol_new pa_protocol_simple_new @@ -55,6 +56,8 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define UNIX_SOCKET "/tmp/polypaudio/simple" #define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record", PA_MODULE_DESCRIPTION("Simple protocol "SOCKET_DESCRIPTION) + PA_MODULE_USAGE("rate= format= channels= sink= source= playback= record= "SOCKET_USAGE) + #elif defined(USE_PROTOCOL_CLI) #include "protocol-cli.h" #define protocol_new pa_protocol_cli_new @@ -63,6 +66,7 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define UNIX_SOCKET "/tmp/polypaudio/cli" #define MODULE_ARGUMENTS PA_MODULE_DESCRIPTION("Command line interface protocol "SOCKET_DESCRIPTION) + PA_MODULE_USAGE(SOCKET_USAGE) #elif defined(USE_PROTOCOL_NATIVE) #include "protocol-native.h" #define protocol_new pa_protocol_native_new @@ -71,6 +75,7 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define UNIX_SOCKET "/tmp/polypaudio/native" #define MODULE_ARGUMENTS "public", "cookie", PA_MODULE_DESCRIPTION("Native protocol "SOCKET_DESCRIPTION) + PA_MODULE_USAGE("public= cookie= "SOCKET_USAGE) #elif defined(USE_PROTOCOL_ESOUND) #include "protocol-esound.h" #include "esound.h" @@ -80,6 +85,7 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define UNIX_SOCKET ESD_UNIX_SOCKET_NAME #define MODULE_ARGUMENTS "sink", "source", "public", "cookie", PA_MODULE_DESCRIPTION("EsounD protocol "SOCKET_DESCRIPTION) + PA_MODULE_USAGE("sink= source= public= cookie= "SOCKET_USAGE) #else #error "Broken build system" #endif diff --git a/polyp/util.c b/polyp/util.c index b9bf9f82..9b74ee75 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -368,9 +368,9 @@ char *pa_path_get_filename(const char *p) { int pa_parse_boolean(const char *v) { - if (!strcmp(v, "1") || !strcasecmp(v, "yes") || !strcasecmp(v, "y") || !strcasecmp(v, "on")) + if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on")) return 1; - else if (!strcmp(v, "0") || !strcasecmp(v, "no") || !strcasecmp(v, "n") || !strcasecmp(v, "off")) + else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off")) return 0; return -1; -- cgit From bb31eda80647dd0f5ec85b5eb26c14ebd0e9d4d1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Sep 2004 19:37:28 +0000 Subject: fix xmms spawn bug git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@224 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 4 ---- polyp/polyplib-context.c | 14 +++++++------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/doc/todo b/doc/todo index b857075f..6665de96 100644 --- a/doc/todo +++ b/doc/todo @@ -1,9 +1,5 @@ *** $Id$ *** -*** 0.5 *** -- xmms segfault when daemon not executable -- update modinfo - *** 0.6 **** - per-channel volume - unix socket directories include user name diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 8a7c719c..32ce3888 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -388,7 +388,6 @@ static int default_server_is_running(void) { return 1; } - static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api *api) { pid_t pid; int status, r; @@ -416,26 +415,27 @@ static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api goto fail; } else if (!pid) { /* Child */ - + char t[128]; const char *state = NULL; #define MAX_ARGS 64 char *argv[MAX_ARGS+1]; - int n = 0; + int n; close(fds[0]); if (api && api->atfork) api->atfork(); - snprintf(t, sizeof(t), "%s=1", ENV_AUTOSPAWNED); - putenv(t); + /* Setup argv */ + n = 0; + argv[n++] = c->conf->daemon_binary; argv[n++] = "--daemonize=yes"; snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]); - argv[n++] = t; + argv[n++] = strdup(t); while (n < MAX_ARGS) { char *a; @@ -449,7 +449,7 @@ static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api argv[n++] = NULL; execv(argv[0], argv); - exit(1); + _exit(1); } /* Parent */ -- cgit From 2d87bd2d2f088220ccf98af93073cfd807dc2d1b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Sep 2004 20:52:35 +0000 Subject: documentation update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@225 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/FAQ.html.in | 22 +++++++++++++-- doc/README.html.in | 46 ++++++++++++++++++++++++++----- doc/cli.html.in | 75 +++++++++++++++++++++++++++----------------------- doc/daemon.html.in | 42 +++++++++++++++++----------- doc/modules.html.in | 23 ++++++++++++++++ polyp/default.pa | 14 +++++----- polyp/main.c | 4 ++- polyp/module-combine.c | 2 +- 8 files changed, 160 insertions(+), 68 deletions(-) diff --git a/doc/FAQ.html.in b/doc/FAQ.html.in index 074561c1..ac9bc466 100644 --- a/doc/FAQ.html.in +++ b/doc/FAQ.html.in @@ -64,11 +64,29 @@
  • I often hear noises when playing back with Polypaudio, what can I do?

    There are to possible solutions: either make the polypaudio binary SUID root (chmod u+s /usr/bin/polypaudio) and run it - with argument -r or increase the fragment sizes of the audio + with argument --high-priority=1 or increase the fragment sizes of the audio drivers. The former will allow Polypaudio to activate SCHED_FIFO high priority scheduling (root rights are dropped - immediately after this).

  • + immediately after this) Keep in mind that is a potential security hole!

    +
  • I only want to run polypaudio when it is needed, how do I do this?

    + +

    Set autospawn = yes in client.conf. That +configuration file may be found either in /etc/polypaudio/ or +in ~/.polypaudio/.

  • + +
  • How do I list all polypaudio modules installed?

    + +

    polypaudio --dump-modules

    + +

    Add -v for terse usage instructions.

    + +
  • What environment does polypaudio care about?

    + +

    The client honors: POLYP_SINK (default sink to connect to), POLYP_SOURCE (default source to connect to), POLYP_SERVER (default server to connect to, like ESPEAKER), POLYP_BINARY (the binary to start when autospawning a daemon), POLYP_CLIENTCONFIG (path to the client configuration file).

    + +

    The daemon honors: POLYP_SCRIPT (default CLI script file run after startup), POLYP_CONFIG (default daemon configuration file), POLYP_DLPATH (colon separated list of paths where to look for modules)

  • +
    diff --git a/doc/README.html.in b/doc/README.html.in index 837cb012..0a33d6f0 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -44,6 +44,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    News

    +
    Mon Sep 20 2004:

    Version 0.5 released; +changes include: extensive API improvements, new module +module-combine for combining multiple sound cards into one, +gcc 2.95 compatibility, configuration files, add "lazy" samples, +support for source and network latency measurements, add +module-pipe-source, many other fixes and improvements.

    +
    Wed Sep 8 2004:

    Version 0.4 released; changes include: daemon auto spawning, support for SCHED_FIFO scheduling, three new modules, proper logging, CPU load watchdog, many fixes.

    @@ -79,6 +87,8 @@ Daemon (ESOUND). In addition to the features ESOUND provides
  • Flexible, implicit sample type conversion and resampling
  • "Zero-Copy" architecture
  • Module autoloading
  • +
  • Very accurate latency measurement for playback and recordin.
  • +
  • May be used to combine multiple sound cards to one (with sample rate adjustment)

Both the core and the client API are completely asynchronous making @@ -89,15 +99,35 @@ available through polyplib is quite difficult to use there is a simplified synchronous API wrapper polyplib-simple available. A simple main loop implementation is available as well.

+

The following modules are currently available:

+ +
    +
  • module-oss: driver for Open Sound System audio sinks and sources.
  • +
  • module-oss-mmap: same as above, but uses mmap() access to the audio buffer. Not as compatible
  • +
  • module-alsa-sink, module-alsa-source: drivers for ALSA sinks and sources
  • +
  • module-pipe-sink, module-pipe-source: demonstration module providing UNIX fifos backed sinks/sources
  • +
  • module-combine: combine multiple sinks into one.
  • +
  • module-sine: a sine generate sink input.
  • +
  • module-x11-bell: play a sample from the sample cache on every X11 bell event.
  • +
  • module-esound-protocol-tcp, module-esound-protocol-unix: ESOUND compatibility modules (for TCP/IP resp. UNIX domain sockets)
  • +
  • module-native-protocol-tcp, module-native-protocol-unix: Native polypaudio protocol (for TCP/IP resp. UNIX domain sockets)
  • +
  • module-simple-protocol-tcp, module-simple-protocol-unix: Simplistic protocol for playback/capture for usage with tools like netcat (for TCP/IP resp. UNIX domain sockets)
  • +
  • module-cli-protocol-tcp, module-cli-protocol-unix, module-cli: Expose polypaudio's internals whith a simple command line interface. (for TCP/IP resp. UNIX domain sockets resp. STDIN/STDOUT)
  • +
+

polypaudio is the successor of my previous, ill-fated -attempt to write a sound server asd.

A GTK GUI manager application for polypaudio is the Polypaudio -Manager. Another GTK GUI tool for Polypaudio is the Polypaudio Volume Meter. There are output plugins for . Another GTK GUI tool for Polypaudio is the Polypaudio Volume +Meter. There are output plugins for XMMS and libao.

+href="http://0pointer.de/lennart/projects/libao-polyp/">libao. Drivers +for gstreamer and MPlayer will be released shortly.

Status

@@ -116,9 +146,9 @@ href="daemon.html">daemon.html, FAQ.htmlFirst Steps -

Simply start the polypaudio daemon with the argument -C

+

Simply start the polypaudio daemon with the argument -nC

-
polypaudio -C
+
polypaudio -nC

This will present you a screen like this:

@@ -130,10 +160,12 @@ href="cli.html">cli.html
. Another way to start polypaudio is by specifying a configuration script like that one included in the distribution on the command line :

-
polypaudio -F polypaudio.pa
+
polypaudio -nF polypaudio.pa

This will load some drivers and protocols automatically.

+

The best idea is to configure your daemon in /etc/polypaudio/daemon.conf and /etc/polypaudio/default.pa and to run polypaudio without any arguments.

+

Developing polypaudio Clients

You may browse the Doxygen generated for the client API. (Run make doxygen to generate thi

  • Protocol support beyond ESOUND's protocol and the native protocol. (such as NAS or a subset of aRts)
  • New programming interfaces such as XMLRPC or DBUS for controlling the daemon.
  • Hooking audio event sources directly into polypaudio (similar to module-x11-bell)
  • -
  • For low latency applications such as VOIP: load the VOIP core directly into polypaudio and have a slim GUI frontend to control it.
  • +
  • For low latency applications such as VOIP: load the VOIP core directly into polypaudio and have a slim GUI frontend to control it.
  • There is currently no documentation how to write loadable modules diff --git a/doc/cli.html.in b/doc/cli.html.in index 6f84a07d..49e568f8 100644 --- a/doc/cli.html.in +++ b/doc/cli.html.in @@ -28,19 +28,19 @@ commands are supported:

    Status Commands

    -

    modules

    +

    list-modules

    Show all currently loaded modules with their arguments.

    -

    sinks/sources

    +

    list-sinks/list-sources

    Show all currently registered sinks (resp. sources).

    -

    clients

    +

    list-clients

    Show all currently active clients.

    -

    sink_inputs/sink_outputs

    +

    list-sink-inputs/list-sink-outputs

    Show all currently active inputs to sinks (resp. outputs of sources).

    @@ -56,19 +56,19 @@ and list are synonyms for info.

    Module Management

    -

    load

    +

    load-module

    Load a module specified by its name and arguments. For most modules it is OK to be loaded more than once.

    -

    unload

    +

    unload-module

    Unload a module specified by its index in the module list as returned by modules.

    Configuration Commands

    -

    sink_volume

    +

    set-sink-volume

    Set the volume of the specified sink. You may specify the sink either by its index in the sink list or by its name. The volume should be an @@ -76,12 +76,12 @@ integer value greater or equal than 0 (= muted). Volume 256 (0x100) is normal volume, values greater than this amplify the audio signal with clipping.

    -

    sink_input_volume

    +

    set-sink-input-volume

    Set the volume of a sink input specified by its index the the sink input list. The same volume rules apply as with sink_volume.

    -

    sink_default/source_default

    +

    set-default-sink/set-default-source

    Make a sink (resp. source) the default. You may specify the sink (resp. ssource) by its index in the sink (resp. source) list or by its @@ -89,39 +89,46 @@ name.

    Sample Cache

    -

    scache_list

    +

    list-samples

    Lists the contents of the sample cache.

    -

    scache_play

    +

    play-sample

    Play a sample cache entry to a sink. Expects the sample name and the sink name as arguments.

    -

    sache_remove

    +

    remove-sample

    Remove an entry from the sample cache. Expects the sample name as argument.

    -

    sache_load

    +

    load-sample

    Load an audio file to the sample cache. Expects the file name to load and the desired sample name as arguments.

    +

    load-sample-lazy

    + +

    Create a new entry in the sample cache, but don't load the sample +immediately. The sample is loaded only when it is first used. After a +certain idle time it is freed again. Expects the the desired sample +name and file name to load as arguments.

    +

    Module Autoloading

    -

    autoload_list

    +

    list-autoload

    Lists all currently defined autoloading entries.

    -

    autoload_sink_add/autoload_source_add

    +

    add-autoload-sink/add-autoload-source

    Adds an autoloading entry for a sink (resp. source). Expects the sink name (resp. source name), the module name and the module arguments as arguments.

    -

    autoload_sink_remove/autoload_source_remove

    +

    remove-autoload-sink/remove-autoload-source

    Remove an autoloading entry. Expects the sink name (resp. source name) as argument.

    Miscellaneous Commands

    -

    play_file

    +

    play-file

    Play an audio file to a sink. Expects the file name and the sink name as argumens.

    @@ -131,12 +138,12 @@ name.

    Killing Clients/Streams

    -

    kill_client

    +

    kill-client

    Remove a client forcibly from the server. There is no protection that the client reconnects immediately.

    -

    kill_sink_input/kill_source_output

    +

    kill-sink-input/kill-source-output

    Remove a sink input (resp. source output) forcibly from the server. This will not remove the owning client or any other streams @@ -165,34 +172,34 @@ on the interactive command line.

    Mark the following script as executable (chmod +x) and run it for a sensible polypaudio configuration.

    -#!/usr/bin/polaudio -F
    +#!/usr/bin/polaudio -nF
     
     # Create autoload entries for the device drivers
    -autoload_sink_add output module-alsa-sink device=plughw:0,0 rate=48000 sink_name=output
    -autoload_source_add input load module-alsa-source device=hw:1,0 source_name=input
    +add-autoload-sink output module-alsa-sink device=plughw:0,0 rate=48000 sink_name=output
    +add-autoload-sink output2 module-oss device=/dev/dsp1 record=0 sink_name=output2
    +add-autoload-sink combined module-combine master=output slaves=output2 sink_name=combined
     
    -# Load several protocols
    -load module-esound-protocol-tcp
    -load module-simple-protocol-tcp
    -load module-native-protocol-unix
    -load module-cli-protocol-unix
    +add-autoload-source input module-alsa-source device=hw:1,0 source_name=input
     
    -# Load the CLI module (This is similar to passing "-C" on the command line of polypaudio)
    -load module-cli
    +# Load several protocols
    +load-module module-esound-protocol-unix
    +load-module module-simple-protocol-tcp
    +load-module module-native-protocol-unix
    +load-module module-cli-protocol-unix
     
     # Make some devices default
    -sink_default output
    -source_default input
    +set-default-sink combined
    +set-default-source input
     
     # Don't fail if the audio files referred to below don't exist
     .nofail
     
     # Load an audio to the sample cache for usage with module-x11-bell
    -scache_load /usr/share/sounds/KDE_Notify.wav x11-bell
    -load module-x11-bell
    +load-sample-lazy  /usr/share/sounds/KDE_Notify.wav x11-bell
    +load-module module-x11-bell sample=x11-bell
     
     # Play a welcome sound
    -play_file /usr/share/sounds/startup3.wav output
    +play-file /usr/share/sounds/startup3.wav combined
     

    diff --git a/doc/daemon.html.in b/doc/daemon.html.in index e4903a8b..147ee551 100644 --- a/doc/daemon.html.in +++ b/doc/daemon.html.in @@ -13,28 +13,38 @@ The polypaudio daemon accepts several command line arguments: -

    -r: Set low nice value (high priority) and SCHED_FIFO scheduling if available. Works only when started as root or SUID root.

    -

    -R: Don't drop root rights if started SUID root.

    -

    -L MODULE: Load the specified module. This option may be specified more than once.

    -

    -F FILE: Run the specified script. This option may be specified more than once.

    -

    -C: Load the module module-cli after startup.

    -

    -n: Don't load the default configuration file. Normally ~/.polypaudio or /etc/polyp/polypaudio.pa are loaded on startup.

    -

    -D: Daemonize after successfully executing all scripts and loading all modules.

    -

    -d: Disallow module load and unload after startup.

    -

    -f: Unless this option is given the daemon will terminate if any of the specified modules failed to load or the script didn't execute successfully.

    -

    -v: Increase the verbosity of the daemon.

    -

    -X SECS: Terminate the daemon after the last client exited an SECS seconds passed.

    -

    -h: Show a quick help.

    -

    -l TARGET: Specify the log target (syslog, stderr, auto). Defaults to auto, which means stderr when run without -D and syslog when run with -D.

    -

    -V: Show version.

    +
    +  -h, --help                            Show this help
    +      --version                         Show version
    +      --dump-conf                       Dump default configuration
    +      --dump-modules                    Dump list of available modules
    +
    +  -D, --daemonize[=BOOL]                Daemonize after startup
    +      --fail[=BOOL]                     Quit when startup fails
    +      --verbose[=BOOL]                  Be slightly more verbose
    +      --high-priority[=BOOL]            Try to set high process priority (only available as root)
    +      --disallow-module-loading[=BOOL]  Disallow module loading after startup
    +      --exit-idle-time=SECS             Terminate the daemon when idle and this time passed
    +      --module-idle-time=SECS           Unload autoloaded modules when idle and this time passed
    +      --scache-idle-time=SECS           Unload autoloaded samples when idle and this time passed
    +      --log-target={auto,syslog,stderr} Specify the log target
    +  -p, --dl-search-path=PATH             Set the search path for dynamic shared objects (plugins)
    +      --resample-method=[METHOD]        Use the specified resampling method
    +
    +  -L, --load="MODULE ARGUMENTS"         Load the specified plugin module with the specified argument
    +  -F, --file=FILENAME                   Run the specified script
    +  -C                                    Open a command line on the running TTY after startup (identical to -Lmodule-cli)
    +
    +  -n                                    Don't load default script file
    +

    Example

    It is a good idea to run the daemon like this:

    -
    polypaudio -rD
    +
    polypaudio -D
    -

    This will run /etc/polypaudio/polypaudio.pa after startup. This should be a script written in the CLI language described in cli.html.

    +

    This will run /etc/polypaudio/default.pa after startup. This should be a script written in the CLI language described in cli.html.

    Signals

    diff --git a/doc/modules.html.in b/doc/modules.html.in index 22a565d6..6967b2a1 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -93,6 +93,29 @@ compatible as module-oss.

    This module accepts exactly the same arguments as module-oss.

    +

    module-combine

    + +

    This combines two or more sinks into one. A new virtual sink is +allocated. All data written to it is forwarded to all connected +sinks. In aequidistant intervals the sample rates of the output sinks +is recalculated: i.e. even when the sink's crystals deviate (which is +normally the case) output appears synchronously to the human ear. The +resampling required for this may be very CPU intensive.

    + + + + + + +
    sink_name=The name for the combined sink. (defaults to combined)
    master=The name of the first sink to link into the combined think. The sample rate/type is taken from this sink.
    slaves=Name of additional sinks to link into the combined think, seperated by commas.
    adjust_time=Time in seconds when to readjust the sample rate of all sinks. (defaults to 20)
    resample_method=Resampling algorithm to +use. See libsamplerate's documentation for more +information. Use one of sinc-best-quality, +sinc-medium-quality, sinc-fastest, +zero-order-hold, linear. If the default happens to +be to slow on your machine try using zero-order-hold. This +will decrease output quality however. (defaults to +sinc-fastest)
    +

    Protocols

    diff --git a/polyp/default.pa b/polyp/default.pa index ae1fbfcb..a3aaa7c8 100755 --- a/polyp/default.pa +++ b/polyp/default.pa @@ -1,4 +1,4 @@ -#!./polypaudio -rnF +#!./polypaudio -nF # # This file is part of polypaudio. @@ -28,12 +28,12 @@ load-module module-oss device="/dev/dsp" sink_name=output source_name=input reco # Load audio drivers automatically on access -#add-autoload_sink output module-oss device="/dev/dsp" sink_name=output source_name=input -#add-autoload_source input module-oss device="/dev/dsp" sink_name=output source_name=input -#add-autoload_sink output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#add-autoload_source input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#add-autoload_sink output module-alsa-sink sink_name=output -#add-autoload_source input module-alsa-source source_name=input +#add-autoload-sink output module-oss device="/dev/dsp" sink_name=output source_name=input +#add-autoload-source input module-oss device="/dev/dsp" sink_name=output source_name=input +#add-autoload-sink output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#add-autoload-source input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#add-autoload-sink output module-alsa-sink sink_name=output +#add-autoload-source input module-alsa-source source_name=input # Load several protocols load-module module-esound-protocol-tcp diff --git a/polyp/main.c b/polyp/main.c index 10774388..dfbd1e4b 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -180,12 +180,14 @@ int main(int argc, char *argv[]) { retval = 1; } + if (conf->verbose) + pa_log(__FILE__": daemon startup %s.\n", retval ? "failed" : "succeeded"); + goto finish; } close(daemon_pipe[0]); daemon_pipe[0] = -1; - if (conf->auto_log_target) pa_log_set_target(PA_LOG_SYSLOG, NULL); diff --git a/polyp/module-combine.c b/polyp/module-combine.c index 1bb183ec..6952ce6c 100644 --- a/polyp/module-combine.c +++ b/polyp/module-combine.c @@ -40,7 +40,7 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Combine multiple sinks to one") PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= master= slave= adjust_time= resample_method=") +PA_MODULE_USAGE("sink_name= master= slaves= adjust_time= resample_method=") #define DEFAULT_SINK_NAME "combined" #define MEMBLOCKQ_MAXLENGTH (1024*170) -- cgit From 4d9af54e8c8b57a21ad7ad37570cc2cbc747cf89 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Sep 2004 21:03:52 +0000 Subject: build updates git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@226 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- polyp/Makefile.am | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index f422ff68..e74cc64b 100644 --- a/configure.ac +++ b/configure.ac @@ -72,7 +72,7 @@ AC_FUNC_REALLOC AC_FUNC_SETPGRP AC_FUNC_VPRINTF AC_TYPE_SIGNAL -AC_CHECK_FUNCS([gethostname gettimeofday memchr memmove memset mkdir mkfifo munmap rmdir socket strcspn strerror strrchr strspn strstr strtol strtoul pow strcasecmp putenv strchr strpbrk]) +AC_CHECK_FUNCS([gethostname gettimeofday memchr memmove memset mkdir mkfifo munmap rmdir socket strcspn strerror strrchr strspn strstr strtol strtoul pow strcasecmp putenv strchr strpbrk strdup]) AC_FUNC_STAT AC_HEADER_SYS_WAIT diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 4adc8add..6e435156 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -32,7 +32,7 @@ AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\" AM_LDADD=$(PTHREAD_LIBS) -lm AM_LIBADD=$(PTHREAD_LIBS) -lm -EXTRA_DIST = default.pa daemon.conf.in client.conf.in config depmod.py esdcompat.sh.in +EXTRA_DIST = default.pa daemon.conf.in client.conf.in depmod.py esdcompat.sh.in bin_PROGRAMS = polypaudio pacat pactl bin_SCRIPTS = esdcompat.sh noinst_PROGRAMS = \ -- cgit From 766841870a1b1c54398ab168f005393ac76684a7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Sep 2004 22:22:28 +0000 Subject: add link to mailing list git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@227 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/README.html.in b/doc/README.html.in index 0a33d6f0..34caa78c 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -226,6 +226,8 @@ compilation and make install (as root) for installation of

    If you want to be notified whenever I release a new version of this software use the subscription feature of Freshmeat.

    +

    New! There is a general discussion mailing list for polypaudio available.

    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, September 2004
    $Id$
    -- cgit From df953a11c98d6b8213aa66c6433340d9bb7927f3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Sep 2004 18:43:01 +0000 Subject: show which command is unknown in esound protocol fix esdcompat.sh git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@229 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/esdcompat.sh.in | 2 +- polyp/protocol-esound.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/polyp/esdcompat.sh.in b/polyp/esdcompat.sh.in index 88ff447f..32f8d864 100755 --- a/polyp/esdcompat.sh.in +++ b/polyp/esdcompat.sh.in @@ -80,4 +80,4 @@ EOF shift done -exec "@POLYPAUDIO_BINARY@" -r +exec "@POLYPAUDIO_BINARY@" diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 293d123a..69008364 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -689,7 +689,7 @@ static int do_read(struct connection *c) { handler = proto_map+c->request; if (!handler->proc) { - pa_log(__FILE__": recieved unimplemented request.\n"); + pa_log(__FILE__": recieved unimplemented request #%u.\n", c->request); return -1; } -- cgit From 3e1bdacd4fcd3779141c53008b983fe78e639b30 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Sep 2004 19:00:03 +0000 Subject: add noop implementation of standby/resume ESOUND commands git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@230 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/esdcompat.sh.in | 2 +- polyp/protocol-esound.c | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/polyp/esdcompat.sh.in b/polyp/esdcompat.sh.in index 32f8d864..8b9cbf94 100755 --- a/polyp/esdcompat.sh.in +++ b/polyp/esdcompat.sh.in @@ -22,7 +22,7 @@ VERSION_STRING="@PACKAGE_NAME@ esd wrapper @PACKAGE_VERSION@" fail() { - echo "$1" > /dev/stderr + echo "ERROR: $1" exit 1 } diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 69008364..ccbc61be 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -122,6 +122,7 @@ static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, const void *data, size_t length); static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length); static int esd_proto_sample_get_id(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_noop(struct connection *c, esd_proto_t request, const void *data, size_t length); /* the big map of protocol handler info */ static struct proto_handler proto_map[ESD_PROTO_MAX] = { @@ -140,8 +141,8 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = { { sizeof(int), NULL, "sample stop" }, { -1, NULL, "TODO: sample kill" }, - { ESD_KEY_LEN + sizeof(int), NULL, "standby" }, - { ESD_KEY_LEN + sizeof(int), NULL, "resume" }, + { ESD_KEY_LEN + sizeof(int), esd_proto_noop, "standby" }, /* NOOP! */ + { ESD_KEY_LEN + sizeof(int), esd_proto_noop, "resume" }, /* NOOP! */ { ESD_NAME_MAX, esd_proto_sample_get_id, "sample getid" }, { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" }, @@ -654,6 +655,14 @@ static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t reque return 0; } +static int esd_proto_noop(struct connection *c, esd_proto_t request, const void *data, size_t length) { + int *ok; + ok = connection_write(c, sizeof(int)); + assert(ok); + *ok = 1; + return 0; +} + /*** client callbacks ***/ static void client_kill_cb(struct pa_client *c) { -- cgit From 12949d0a65bcbc9550899a6ec7b0f504a4f571b5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Sep 2004 19:40:55 +0000 Subject: support for esd arguments: -spawnpid and -spawnfd git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@231 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 12 +++++- polyp/esdcompat.sh.in | 17 +++++++- polyp/module-esound-compat-spawnfd.c | 79 +++++++++++++++++++++++++++++++++++ polyp/module-esound-compat-spawnpid.c | 77 ++++++++++++++++++++++++++++++++++ 4 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 polyp/module-esound-compat-spawnfd.c create mode 100644 polyp/module-esound-compat-spawnpid.c diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 6e435156..af324dd3 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -103,7 +103,9 @@ modlib_LTLIBRARIES= \ module-native-protocol-unix.la \ module-native-protocol-fd.la \ module-sine.la \ - module-combine.la + module-combine.la \ + module-esound-compat-spawnfd.la \ + module-esound-compat-spawnpid.la lib_LTLIBRARIES= \ libpolyp-@PA_MAJORMINOR@.la \ @@ -302,6 +304,14 @@ module_combine_la_SOURCES = module-combine.c module_combine_la_LDFLAGS = -module -avoid-version module_combine_la_LIBADD = $(AM_LIBADD) +module_esound_compat_spawnfd_la_SOURCES = module-esound-compat-spawnfd.c +module_esound_compat_spawnfd_la_LDFLAGS = -module -avoid-version +module_esound_compat_spawnfd_la_LIBADD = $(AM_LIBADD) + +module_esound_compat_spawnpid_la_SOURCES = module-esound-compat-spawnpid.c +module_esound_compat_spawnpid_la_LDFLAGS = -module -avoid-version +module_esound_compat_spawnpid_la_LIBADD = $(AM_LIBADD) + libpolyp_@PA_MAJORMINOR@_la_SOURCES = polyplib.h \ polyplib-def.h \ tagstruct.c tagstruct.h \ diff --git a/polyp/esdcompat.sh.in b/polyp/esdcompat.sh.in index 8b9cbf94..d222e1ba 100755 --- a/polyp/esdcompat.sh.in +++ b/polyp/esdcompat.sh.in @@ -26,9 +26,13 @@ fail() { exit 1 } +ARGS="" + for N in $(seq $#) ; do case "$1" in + "") + ;; -v|--version) echo "$VERSION_STRING" @@ -62,6 +66,16 @@ Ignored directives: EOF exit 0 ;; + + -spawnpid) + shift + ARGS="$ARGS '-Lmodule-esound-compat-spawnpid pid=$1'" + ;; + + -spawnfd) + shift + ARGS="$ARGS '-Lmodule-esound-compat-spawnfd fd=$1'" + ;; -unix|-b|-public|-terminate|-nobeeps|-trust|-tcp|-promiscuous) # Ignore these commands @@ -70,6 +84,7 @@ EOF -d|-r|-as|-port|-bind) # Ignore these commands and their arguments shift + ;; *) @@ -80,4 +95,4 @@ EOF shift done -exec "@POLYPAUDIO_BINARY@" +eval "exec '@POLYPAUDIO_BINARY@'$ARGS" diff --git a/polyp/module-esound-compat-spawnfd.c b/polyp/module-esound-compat-spawnfd.c new file mode 100644 index 00000000..514159fc --- /dev/null +++ b/polyp/module-esound-compat-spawnfd.c @@ -0,0 +1,79 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "module.h" +#include "util.h" +#include "modargs.h" +#include "log.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("ESOUND compatibility module: -spawnfd emulation") +PA_MODULE_USAGE("fd=") +PA_MODULE_VERSION(PACKAGE_VERSION) + +static const char* const valid_modargs[] = { + "fd", + NULL, +}; + +int pa__init(struct pa_core *c, struct pa_module*m) { + struct pa_modargs *ma = NULL; + int ret = -1, fd = -1; + char x = 1; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs)) || + pa_modargs_get_value_s32(ma, "fd", &fd) < 0 || + fd < 0) { + pa_log(__FILE__": Failed to parse module arguments\n"); + goto finish; + } + + if (pa_loop_write(fd, &x, sizeof(x)) != sizeof(x)) + pa_log(__FILE__": WARNING: write(%u, 1, 1) failed: %s\n", fd, strerror(errno)); + + close(fd); + + pa_module_unload_request(m); + + ret = 0; + +finish: + if (ma) + pa_modargs_free(ma); + + return ret; +} + +void pa__done(struct pa_core *c, struct pa_module*m) { + assert(c && m); +} + + diff --git a/polyp/module-esound-compat-spawnpid.c b/polyp/module-esound-compat-spawnpid.c new file mode 100644 index 00000000..5583f071 --- /dev/null +++ b/polyp/module-esound-compat-spawnpid.c @@ -0,0 +1,77 @@ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "module.h" +#include "util.h" +#include "modargs.h" +#include "log.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("ESOUND compatibility module: -spawnpid emulation") +PA_MODULE_USAGE("pid=") +PA_MODULE_VERSION(PACKAGE_VERSION) + +static const char* const valid_modargs[] = { + "pid", + NULL, +}; + +int pa__init(struct pa_core *c, struct pa_module*m) { + struct pa_modargs *ma = NULL; + int ret = -1; + uint32_t pid = 0; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs)) || + pa_modargs_get_value_u32(ma, "pid", &pid) < 0 || + !pid) { + pa_log(__FILE__": Failed to parse module arguments\n"); + goto finish; + } + + if (kill(pid, SIGUSR1) < 0) + pa_log(__FILE__": WARNING: kill(%u) failed: %s\n", pid, strerror(errno)); + + pa_module_unload_request(m); + + ret = 0; + +finish: + if (ma) + pa_modargs_free(ma); + + return ret; +} + +void pa__done(struct pa_core *c, struct pa_module*m) { + assert(c && m); +} + + -- cgit From 370ff1d7cd2468c0d776bd43aa81d2d3c3a63e4a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Sep 2004 20:46:14 +0000 Subject: improve esound module git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@232 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/protocol-esound.c | 21 ++++++++++++--------- polyp/scache.c | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index ccbc61be..797263f6 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -122,7 +122,7 @@ static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, const void *data, size_t length); static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length); static int esd_proto_sample_get_id(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_noop(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_standby_or_resume(struct connection *c, esd_proto_t request, const void *data, size_t length); /* the big map of protocol handler info */ static struct proto_handler proto_map[ESD_PROTO_MAX] = { @@ -134,17 +134,17 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = { { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream rec" }, { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream mon" }, - { ESD_NAME_MAX + 3 * sizeof(int), esd_proto_sample_cache, "sample cache" }, + { ESD_NAME_MAX + 3 * sizeof(int), esd_proto_sample_cache, "sample cache" }, /* 6 */ { sizeof(int), esd_proto_sample_free_or_play, "sample free" }, - { sizeof(int), esd_proto_sample_free_or_play, "sample play" }, + { sizeof(int), esd_proto_sample_free_or_play, "sample play" }, /* 8 */ { sizeof(int), NULL, "sample loop" }, { sizeof(int), NULL, "sample stop" }, { -1, NULL, "TODO: sample kill" }, - { ESD_KEY_LEN + sizeof(int), esd_proto_noop, "standby" }, /* NOOP! */ - { ESD_KEY_LEN + sizeof(int), esd_proto_noop, "resume" }, /* NOOP! */ + { ESD_KEY_LEN + sizeof(int), esd_proto_standby_or_resume, "standby" }, /* NOOP! */ + { ESD_KEY_LEN + sizeof(int), esd_proto_standby_or_resume, "resume" }, /* NOOP! */ /* 13 */ - { ESD_NAME_MAX, esd_proto_sample_get_id, "sample getid" }, + { ESD_NAME_MAX, esd_proto_sample_get_id, "sample getid" }, /* 14 */ { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" }, { sizeof(int), esd_proto_server_info, "server info" }, @@ -655,11 +655,12 @@ static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t reque return 0; } -static int esd_proto_noop(struct connection *c, esd_proto_t request, const void *data, size_t length) { +static int esd_proto_standby_or_resume(struct connection *c, esd_proto_t request, const void *data, size_t length) { int *ok; - ok = connection_write(c, sizeof(int)); + ok = connection_write(c, sizeof(int)*2); assert(ok); - *ok = 1; + ok[0] = 1; + ok[1] = 1; return 0; } @@ -697,6 +698,8 @@ static int do_read(struct connection *c) { handler = proto_map+c->request; + pa_log(__FILE__": executing request #%u\n", c->request); + if (!handler->proc) { pa_log(__FILE__": recieved unimplemented request #%u.\n", c->request); return -1; diff --git a/polyp/scache.c b/polyp/scache.c index 963a4f86..b17f3242 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -237,7 +237,7 @@ uint32_t pa_scache_get_id_by_name(struct pa_core *c, const char *name) { struct pa_scache_entry *e; assert(c && name); - if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1))) + if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) return PA_IDXSET_INVALID; return e->index; -- cgit From 03ee5e2b445becf823dc4dd3db1599849e8c6c06 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Sep 2004 15:47:11 +0000 Subject: add support for capabilities git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@233 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 5 +++ doc/modules.html.in | 4 +- polyp/Makefile.am | 7 ++-- polyp/caps.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++ polyp/caps.h | 29 ++++++++++++++ polyp/main.c | 13 ++----- polyp/polyplib-def.h | 3 ++ polyp/tagstruct.h | 2 + polyp/util.c | 5 +++ polyp/util.h | 1 + 10 files changed, 161 insertions(+), 14 deletions(-) create mode 100644 polyp/caps.c create mode 100644 polyp/caps.h diff --git a/configure.ac b/configure.ac index e74cc64b..5e63d1e0 100644 --- a/configure.ac +++ b/configure.ac @@ -78,6 +78,11 @@ AC_HEADER_SYS_WAIT AC_C_BIGENDIAN +AC_CHECK_LIB(cap, cap_init, [CAP_LIBS='-lcap'], [CAP_LIBS='']) +AC_SUBST(CAP_LIBS) + +AC_CHECK_HEADERS(sys/capability.h) + PKG_CHECK_MODULES(LIBSAMPLERATE, [ samplerate >= 0.1.0 ]) AC_SUBST(LIBSAMPLERATE_CFLAGS) AC_SUBST(LIBSAMPLERATE_LIBS) diff --git a/doc/modules.html.in b/doc/modules.html.in index 6967b2a1..00fe3388 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -106,8 +106,8 @@ resampling required for this may be very CPU intensive.

    sink_name=The name for the combined sink. (defaults to combined) master=The name of the first sink to link into the combined think. The sample rate/type is taken from this sink. slaves=Name of additional sinks to link into the combined think, seperated by commas. - adjust_time=Time in seconds when to readjust the sample rate of all sinks. (defaults to 20) - resample_method=Resampling algorithm to + adjust_time=Time in seconds when to readjust the sample rate of all sinks. (defaults to 20) + resample_method=Resampling algorithm to use. See libsamplerate's documentation for more information. Use one of sinc-best-quality, sinc-medium-quality, sinc-fastest, diff --git a/polyp/Makefile.am b/polyp/Makefile.am index af324dd3..e52d9ab8 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -22,7 +22,7 @@ polypconfdir=$(sysconfdir)/polypaudio modlibdir=$(libdir)/polypaudio-@PA_MAJORMINOR@ -AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) +AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) AM_CFLAGS+=-DDLSEARCHPATH=\"$(modlibdir)\" AM_CFLAGS+=-DDEFAULT_SCRIPT_FILE=\"$(polypconfdir)/default.pa\" AM_CFLAGS+=-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/daemon.conf\" @@ -161,11 +161,12 @@ polypaudio_SOURCES = idxset.c idxset.h \ modinfo.c modinfo.h \ daemon-conf.c daemon-conf.h \ dumpmodules.c dumpmodules.h \ - conf-parser.h conf-parser.c + conf-parser.h conf-parser.c \ + caps.h caps.c polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) -polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(LEXLIB) +polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) polypaudio_LDFLAGS=-export-dynamic libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h diff --git a/polyp/caps.c b/polyp/caps.c new file mode 100644 index 00000000..db00c604 --- /dev/null +++ b/polyp/caps.c @@ -0,0 +1,106 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_SYS_CAPABILITY_H +#include +#endif + +#include "log.h" +#include "caps.h" + +void pa_drop_root(void) { + if (getuid() != 0 && geteuid() == 0) { + pa_log(__FILE__": Started SUID root, dropping root rights.\n"); + setuid(getuid()); + seteuid(getuid()); + } +} + +#ifdef HAVE_SYS_CAPABILITY_H +int pa_limit_caps(void) { + int r = -1; + cap_t caps; + cap_value_t nice_cap = CAP_SYS_NICE; + + caps = cap_init(); + assert(caps); + + cap_clear(caps); + cap_set_flag(caps, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET); + cap_set_flag(caps, CAP_PERMITTED, 1, &nice_cap, CAP_SET); + + if (cap_set_proc(caps) < 0) + goto fail; + + pa_log(__FILE__": Started SUID root, capabilities limited.\n"); + + r = 0; + +fail: + cap_free (caps); + + return r; +} + +int pa_drop_caps(void) { + cap_t caps; + int r = -1; + + caps = cap_init(); + assert(caps); + + cap_clear(caps); + + if (cap_set_proc(caps) < 0) + goto fail; + + pa_drop_root(); + + r = 0; + +fail: + cap_free (caps); + + return r; +} + +#else + +int pa_limit_caps(void) { + return 0; +} + +int pa_drop_caps(void) { + pa_drop_root(); + return 0; +} + +#endif + diff --git a/polyp/caps.h b/polyp/caps.h new file mode 100644 index 00000000..473462fb --- /dev/null +++ b/polyp/caps.h @@ -0,0 +1,29 @@ +#ifndef foocapshfoo +#define foocapshfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +void pa_drop_root(void); +int pa_limit_caps(void); +int pa_drop_caps(void); + +#endif diff --git a/polyp/main.c b/polyp/main.c index dfbd1e4b..2a45ad37 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -47,17 +47,10 @@ #include "log.h" #include "daemon-conf.h" #include "dumpmodules.h" +#include "caps.h" static struct pa_mainloop *mainloop; -static void drop_root(void) { - if (getuid() != 0 && geteuid() == 0) { - pa_log(__FILE__": Started SUID root, dropping root rights.\n"); - setuid(getuid()); - seteuid(getuid()); - } -} - static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { pa_log(__FILE__": Got signal %s.\n", pa_strsignal(sig)); @@ -95,6 +88,8 @@ int main(int argc, char *argv[]) { int r, retval = 1, d = 0; int daemon_pipe[2] = { -1, -1 }; + pa_limit_caps(); + r = lt_dlinit(); assert(r == 0); @@ -118,7 +113,7 @@ int main(int argc, char *argv[]) { if (conf->high_priority && conf->cmd == PA_CMD_DAEMON) pa_raise_priority(); - drop_root(); + pa_drop_caps(); if (conf->dl_search_path) lt_dlsetsearchpath(conf->dl_search_path); diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index 591d237d..bab23e47 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -23,6 +23,9 @@ ***/ #include +#include +#include + #include "cdecl.h" #include "sample.h" diff --git a/polyp/tagstruct.h b/polyp/tagstruct.h index 02df74e4..e50551c4 100644 --- a/polyp/tagstruct.h +++ b/polyp/tagstruct.h @@ -24,6 +24,8 @@ #include #include +#include +#include #include "sample.h" diff --git a/polyp/util.c b/polyp/util.c index 9b74ee75..cc132dbb 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -40,6 +40,11 @@ #include #include #include +#include +#include +#include +#include + #include diff --git a/polyp/util.h b/polyp/util.h index c842a1c3..4a387cef 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -66,4 +66,5 @@ const char *pa_strsignal(int sig); int pa_parse_resample_method(const char *string); + #endif -- cgit From 9e3890abb4c8427d69b0be751d516b4c1ff6118d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Sep 2004 15:57:15 +0000 Subject: OSX protability patches from Conrad Parker git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@234 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/authkey.c | 1 + polyp/main.c | 2 +- polyp/module-protocol-stub.c | 1 + polyp/namereg.c | 1 - polyp/pstream.c | 1 + polyp/tagstruct.c | 2 ++ polyp/util.c | 1 + 7 files changed, 7 insertions(+), 2 deletions(-) diff --git a/polyp/authkey.c b/polyp/authkey.c index bbc45c37..9b60506f 100644 --- a/polyp/authkey.c +++ b/polyp/authkey.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "authkey.h" #include "util.h" diff --git a/polyp/main.c b/polyp/main.c index 2a45ad37..0e55528d 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -188,7 +188,7 @@ int main(int argc, char *argv[]) { pa_log_set_target(PA_LOG_SYSLOG, NULL); setsid(); - setpgrp(); + setpgid(0,0); close(0); close(1); diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index 46522d9b..17c491de 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "module.h" #include "socket-server.h" diff --git a/polyp/namereg.c b/polyp/namereg.c index 5791a3e4..e2f65efd 100644 --- a/polyp/namereg.c +++ b/polyp/namereg.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include "namereg.h" diff --git a/polyp/pstream.c b/polyp/pstream.c index b0de9e8c..5fe2b4e7 100644 --- a/polyp/pstream.c +++ b/polyp/pstream.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "pstream.h" diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c index 39ae87b5..bbebdab3 100644 --- a/polyp/tagstruct.c +++ b/polyp/tagstruct.c @@ -25,6 +25,8 @@ #include #include +#include +#include #include #include diff --git a/polyp/util.c b/polyp/util.c index cc132dbb..7148654a 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include -- cgit From dfcd161a52285649b6ff63ae5c191f37a494884d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Sep 2004 16:33:38 +0000 Subject: Fix a bug in the build system reported by Iain Fothergill git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@235 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index e52d9ab8..c5391311 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -439,7 +439,7 @@ lib_LTLIBRARIES+= \ libpolyp-mainloop-glib-@PA_MAJORMINOR@.la noinst_PROGRAMS+= \ - mainloop-test-glib12 + mainloop-test-glib libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_SOURCES = glib-mainloop.h glib-mainloop.c libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) @@ -459,7 +459,8 @@ lib_LTLIBRARIES+= \ libpolyp-mainloop-glib12-@PA_MAJORMINOR@.la noinst_PROGRAMS+= \ - mainloop-test-glib + mainloop-test-glib12 + libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_SOURCES = glib-mainloop.h glib12-mainloop.c libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS) libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop-@PA_MAJORMINOR@.la $(GLIB12_LIBS) -- cgit From 6d2054458ed8bbdcdc4bdf0c57e4294fdc8a7676 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Sep 2004 20:41:49 +0000 Subject: place full binary path in default.pa's shebang line git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@236 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 5 ++++- polyp/default.pa | 62 ----------------------------------------------------- polyp/default.pa.in | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 63 deletions(-) delete mode 100755 polyp/default.pa create mode 100755 polyp/default.pa.in diff --git a/polyp/Makefile.am b/polyp/Makefile.am index c5391311..4e075468 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -32,7 +32,7 @@ AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\" AM_LDADD=$(PTHREAD_LIBS) -lm AM_LIBADD=$(PTHREAD_LIBS) -lm -EXTRA_DIST = default.pa daemon.conf.in client.conf.in depmod.py esdcompat.sh.in +EXTRA_DIST = default.pa.in daemon.conf.in client.conf.in depmod.py esdcompat.sh.in bin_PROGRAMS = polypaudio pacat pactl bin_SCRIPTS = esdcompat.sh noinst_PROGRAMS = \ @@ -557,6 +557,9 @@ esdcompat.sh: esdcompat.sh.in Makefile client.conf: client.conf.in Makefile sed -e 's,@POLYPAUDIO_BINARY\@,$(bindir)/polypaudio,g' < $< > $@ +default.pa: default.pa.in Makefile + sed -e 's,@POLYPAUDIO_BINARY\@,$(bindir)/polypaudio,g' < $< > $@ + daemon.conf: daemon.conf.in Makefile sed -e 's,@DLSEARCHPATH\@,$(modlibdir),g' \ -e 's,@DEFAULT_CONFIG_FILE\@,$(polypconfdir)/daemon.conf,g' < $< > $@ diff --git a/polyp/default.pa b/polyp/default.pa deleted file mode 100755 index a3aaa7c8..00000000 --- a/polyp/default.pa +++ /dev/null @@ -1,62 +0,0 @@ -#!./polypaudio -nF - -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with polypaudio; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - - -# Load audio drivers statically - -#load-module module-alsa-sink -load-module module-alsa-source device=plughw:1,0 -load-module module-oss device="/dev/dsp" sink_name=output source_name=input record=0 -#load-module module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#load-module module-pipe-sink - -# Load audio drivers automatically on access - -#add-autoload-sink output module-oss device="/dev/dsp" sink_name=output source_name=input -#add-autoload-source input module-oss device="/dev/dsp" sink_name=output source_name=input -#add-autoload-sink output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#add-autoload-source input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#add-autoload-sink output module-alsa-sink sink_name=output -#add-autoload-source input module-alsa-source source_name=input - -# Load several protocols -load-module module-esound-protocol-tcp -#load-module module-simple-protocol-tcp -load-module module-native-protocol-unix -#load-module module-cli-protocol-unix -#load-module module-esound-protocol-unix - -# Load the CLI module -load-module module-cli - -# Make some devices default -set-default-sink output -set-default-source input - -.nofail - -# Load something to the sample cache -load-sample /usr/share/sounds/KDE_Notify.wav x11-bell - -# Load X11 bell module -load-module module-x11-bell sample=x11-bell sink=output - -#load-module module-pipe-source -#load-module module-pipe-sink - diff --git a/polyp/default.pa.in b/polyp/default.pa.in new file mode 100755 index 00000000..54feb5ef --- /dev/null +++ b/polyp/default.pa.in @@ -0,0 +1,62 @@ +#!@POLYPAUDIO_BINARY@ -nF + +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with polypaudio; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + + +# Load audio drivers statically + +#load-module module-alsa-sink +load-module module-alsa-source device=plughw:1,0 +load-module module-oss device="/dev/dsp" sink_name=output source_name=input record=0 +#load-module module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#load-module module-pipe-sink + +# Load audio drivers automatically on access + +#add-autoload-sink output module-oss device="/dev/dsp" sink_name=output source_name=input +#add-autoload-source input module-oss device="/dev/dsp" sink_name=output source_name=input +#add-autoload-sink output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#add-autoload-source input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#add-autoload-sink output module-alsa-sink sink_name=output +#add-autoload-source input module-alsa-source source_name=input + +# Load several protocols +load-module module-esound-protocol-tcp +#load-module module-simple-protocol-tcp +load-module module-native-protocol-unix +#load-module module-cli-protocol-unix +#load-module module-esound-protocol-unix + +# Load the CLI module +load-module module-cli + +# Make some devices default +set-default-sink output +set-default-source input + +.nofail + +# Load something to the sample cache +load-sample /usr/share/sounds/KDE_Notify.wav x11-bell + +# Load X11 bell module +load-module module-x11-bell sample=x11-bell sink=output + +#load-module module-pipe-source +#load-module module-pipe-sink + -- cgit -- cgit From ed36241085da8f797adf7d70ab702fee10e8cba0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Sep 2004 22:42:49 +0000 Subject: allow high priority scheduling only for users in group "realtime" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@238 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/caps.c | 26 ++++++++++++++---------- polyp/main.c | 26 +++++++++++++++++------- polyp/util.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- polyp/util.h | 1 + 4 files changed, 96 insertions(+), 21 deletions(-) diff --git a/polyp/caps.c b/polyp/caps.c index db00c604..258e13e4 100644 --- a/polyp/caps.c +++ b/polyp/caps.c @@ -36,14 +36,19 @@ #include "caps.h" void pa_drop_root(void) { - if (getuid() != 0 && geteuid() == 0) { - pa_log(__FILE__": Started SUID root, dropping root rights.\n"); - setuid(getuid()); - seteuid(getuid()); - } + uid_t uid = getuid(); + + if (uid == 0 || geteuid() != 0) + return; + + pa_log(__FILE__": dropping root rights.\n"); + + setuid(uid); + seteuid(uid); } #ifdef HAVE_SYS_CAPABILITY_H + int pa_limit_caps(void) { int r = -1; cap_t caps; @@ -53,14 +58,15 @@ int pa_limit_caps(void) { assert(caps); cap_clear(caps); + cap_set_flag(caps, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET); cap_set_flag(caps, CAP_PERMITTED, 1, &nice_cap, CAP_SET); if (cap_set_proc(caps) < 0) goto fail; - pa_log(__FILE__": Started SUID root, capabilities limited.\n"); - + pa_log(__FILE__": dropped capabilities successfully.\n"); + r = 0; fail: @@ -78,10 +84,10 @@ int pa_drop_caps(void) { cap_clear(caps); - if (cap_set_proc(caps) < 0) + if (cap_set_proc(caps) < 0) { + pa_log(__FILE__": failed to drop capabilities: %s\n", strerror(errno)); goto fail; - - pa_drop_root(); + } r = 0; diff --git a/polyp/main.c b/polyp/main.c index 0e55528d..08677f7f 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -49,8 +49,6 @@ #include "dumpmodules.h" #include "caps.h" -static struct pa_mainloop *mainloop; - static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { pa_log(__FILE__": Got signal %s.\n", pa_strsignal(sig)); @@ -84,22 +82,33 @@ int main(int argc, char *argv[]) { struct pa_core *c; struct pa_strbuf *buf = NULL; struct pa_daemon_conf *conf; + struct pa_mainloop *mainloop; + char *s; int r, retval = 1, d = 0; int daemon_pipe[2] = { -1, -1 }; + gid_t gid = (gid_t) -1; + int suid_root; pa_limit_caps(); + + suid_root = getuid() != 0 && geteuid() == 0; + + if (suid_root && (pa_uid_in_group("realtime", &gid) <= 0 || gid >= 1000)) { + pa_log(__FILE__": WARNING: called SUID root, but not in group 'realtime'.\n"); + pa_drop_root(); + } r = lt_dlinit(); assert(r == 0); pa_log_set_ident("polypaudio"); - + conf = pa_daemon_conf_new(); - + if (pa_daemon_conf_load(conf, NULL) < 0) goto finish; - + if (pa_daemon_conf_env(conf) < 0) goto finish; @@ -107,13 +116,16 @@ int main(int argc, char *argv[]) { pa_log(__FILE__": failed to parse command line.\n"); goto finish; } - + pa_log_set_target(conf->auto_log_target ? PA_LOG_STDERR : conf->log_target, NULL); if (conf->high_priority && conf->cmd == PA_CMD_DAEMON) pa_raise_priority(); - + pa_drop_caps(); + + if (suid_root) + pa_drop_root(); if (conf->dl_search_path) lt_dlsetsearchpath(conf->dl_search_path); diff --git a/polyp/util.c b/polyp/util.c index 7148654a..1246bbb5 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -41,11 +41,8 @@ #include #include #include -#include -#include -#include #include - +#include #include @@ -444,3 +441,62 @@ int pa_parse_resample_method(const char *string) { else return -1; } + +static int is_group(gid_t gid, const char *name) { + struct group group, *result = NULL; + long n = sysconf(_SC_GETGR_R_SIZE_MAX); + void *data; + int r = -1; + + assert(n > 0); + data = pa_xmalloc(n); + + if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) { + pa_log(__FILE__ ": getgrgid_r(%u) failed: %s\n", gid, strerror(errno)); + goto finish; + } + + + r = strcmp(name, result->gr_name) == 0; + +finish: + pa_xfree(data); + + return r; +} + +int pa_uid_in_group(const char *name, gid_t *gid) { + gid_t *gids, tgid; + long n = sysconf(_SC_NGROUPS_MAX); + int r = -1, i; + + assert(n > 0); + + gids = pa_xmalloc(sizeof(gid_t)*n); + + if ((n = getgroups(n, gids)) < 0) { + pa_log(__FILE__": getgroups() failed: %s\n", strerror(errno)); + goto finish; + } + + for (i = 0; i < n; i++) { + if (is_group(gids[i], name) > 0) { + *gid = gids[i]; + r = 1; + goto finish; + } + } + + if (is_group(tgid = getgid(), name) > 0) { + *gid = tgid; + r = 1; + goto finish; + } + + r = 0; + +finish: + + pa_xfree(gids); + return r; +} diff --git a/polyp/util.h b/polyp/util.h index 4a387cef..8f4323f6 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -66,5 +66,6 @@ const char *pa_strsignal(int sig); int pa_parse_resample_method(const char *string); +int pa_uid_in_group(const char *name, gid_t *gid); #endif -- cgit From 405fac5ea7070fa7b50a77952fa8042f87f588a8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Sep 2004 23:26:15 +0000 Subject: bump version number and update documentation git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@239 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- doc/FAQ.html.in | 59 +++++++++++++++++++++++++++++++++++++++++++++-------- doc/README.html.in | 11 +++++++++- doc/modules.html.in | 10 ++++++++- 4 files changed, 71 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index 5e63d1e0..24a7e985 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. AC_PREREQ(2.57) -AC_INIT([polypaudio],[0.5],[mzcbylcnhqvb (at) 0pointer (dot) de]) +AC_INIT([polypaudio],[0.5.1],[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([polyp/main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) diff --git a/doc/FAQ.html.in b/doc/FAQ.html.in index ac9bc466..f1bf2414 100644 --- a/doc/FAQ.html.in +++ b/doc/FAQ.html.in @@ -62,14 +62,34 @@ embed Polypaudio in the aRts process.

  • I often hear noises when playing back with Polypaudio, what can I do?

    -

    There are to possible solutions: either make the polypaudio - binary SUID root (chmod u+s /usr/bin/polypaudio) and run it - with argument --high-priority=1 or increase the fragment sizes of the audio +

    There are to possible solutions: run polypaudio with argument +--high-priority=1 and make yourself member of the group +realtime, or increase the fragment sizes of the audio drivers. The former will allow Polypaudio to activate SCHED_FIFO high priority scheduling (root rights are dropped - immediately after this) Keep in mind that is a potential security hole!

  • - -
  • I only want to run polypaudio when it is needed, how do I do this?

    + immediately after this) Keep in mind that this is a potential security hole!

  • + +
  • The polypaudio executable is installed SUID root by default. Why this? Isn't this a potential security hole?

    + +

    Polypaudio activates SCHED_FIFO scheduling if the user +passes --high-priority=1. This will only succeed when +executed as root, therefore the binary is marked SUID root by +default. Yes, this is a potential security hole. However, polypaudio +tries its best to minimize the security threat: immediately after +startup polypaudio drops all capabilities except +CAP_SYS_NICE (At least on systems that support it, like Linux; see man 7 +capabilities for more information). If the calling user is not a +member of the group realtime (which is required to have a GID +< 1000), root rights are dropped immediately. This means, you can +install polypaudio SUID root, but only a subset of your users (the +members of the group realtime) may make use of realtime +scheduling. Keep in mind that these users might load their own binary +modules into the polypaudio daemon which may freeze the machine. The +daemon has a minimal protection against CPU hogging (the daemon is +killed after hogging more than 70% CPU for 5 seconds), but this may +be circumvented easily by evildoers.

  • + +
  • I want to run polypaudio only when it is needed, how do I do this?

    Set autospawn = yes in client.conf. That configuration file may be found either in /etc/polypaudio/ or @@ -81,12 +101,35 @@ in ~/.polypaudio/.

  • Add -v for terse usage instructions.

    -
  • What environment does polypaudio care about?

    +
  • How do I use polypaudio over the network?

    + +

    Just set $POLYP_SERVER to the host name of the polypaudio server.

    + +
  • Is polypaudio capable of providing synchronized audio playback over the network for movie players like mplayer?

    + +

    Yes! Unless your network is congested in some way (i.e. transfer latencies vary strongly) it works perfectly. Drop me an email for experimental patches for MPlayer.

    + +
  • What environment variables does polypaudio care about?

    The client honors: POLYP_SINK (default sink to connect to), POLYP_SOURCE (default source to connect to), POLYP_SERVER (default server to connect to, like ESPEAKER), POLYP_BINARY (the binary to start when autospawning a daemon), POLYP_CLIENTCONFIG (path to the client configuration file).

    The daemon honors: POLYP_SCRIPT (default CLI script file run after startup), POLYP_CONFIG (default daemon configuration file), POLYP_DLPATH (colon separated list of paths where to look for modules)

  • - + + +
  • I saw that SIGUSR2 provokes loading of the module module-cli-protocol-unix. But how do I make use of that?

    + +

    A brilliant guy named Lennart Poettering once wrote a nifty tool +for that purpose: bidilink. To +connect to a running polypaudio daemon try using the following commands:

    + +
    killall -USR2 polypaudio
    +bidilink unix-client:/tmp/polypaudio/cli
    + +

    BTW: Someone should package that great tool for Debian!

    + +
  • +
    diff --git a/doc/README.html.in b/doc/README.html.in index 34caa78c..a0b3e641 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -44,6 +44,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    News

    +
    Mon Sep 24 2004:

    Version 0.5.1 released; +changes include: improve esound protocol compatibility; fix +autospawning via libesd; make use of POSIX capabilities; +allow SCHED_FIFO scheduling only for users in group +realtime; minor build system fix.

    +
    Mon Sep 20 2004:

    Version 0.5 released; changes include: extensive API improvements, new module @@ -222,7 +229,9 @@ compilation and make install (as root) for installation of

    The current release is @PACKAGE_VERSION@

    -

    Get polypaudio's development sources from the Subversion repository. (viewcvs)

    +

    Get polypaudio's development sources from the Subversion repository (viewcvs):

    + +
    svn checkout svn://seth.intheinter.net/polypaudio/trunk polypaudio

    If you want to be notified whenever I release a new version of this software use the subscription feature of Freshmeat.

    diff --git a/doc/modules.html.in b/doc/modules.html.in index 00fe3388..4bf6044b 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -220,7 +220,7 @@ about the two possible suffixes of this module.

    module-native-protocol-fd

    -

    This is used internally when auto spawning a new daemon.

    +

    This is used internally when auto spawning a new daemon. Don't use it directly.

    Miscellaneous

    @@ -243,6 +243,14 @@ about the two possible suffixes of this module.

    frequency=The frequency to generate in Hertz. Defaults to 440. +

    module-esound-compat-spawnfd

    + +

    This is a compatibility module for libesd based autospawning of polypaudio. Don't use it directly.

    + +

    module-esound-compat-spawnpid

    + +

    This is a compatibility module for libesd based autospawning of polypaudio. Don't use it directly.

    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, September 2004
    $Id$
    -- cgit From 5bac3c3ce515cb588f3928431db4fe1c396d53e7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 26 Sep 2004 17:02:26 +0000 Subject: bum version number add new macro PA_API_VERSION for preprocessor level conditional compiling add new native APIs: - counter - cork & flush for record streams - add flags parameters to pa_stream_connect_xx() - new prebuf command - time api, and total latency calculator - return sample spec ability to cork source output streams dump server status on SIGHUP to syslog show sink input/source outputs status in cli-text.c don't flush esound output buffer when client disconnects move version api to polyplib-version.h git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@240 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- doc/todo | 12 ++++-- polyp/cli-text.c | 28 +++++++++---- polyp/cpulimit.c | 2 +- polyp/main.c | 47 ++++++++++++++++++++- polyp/memblockq.c | 9 +++- polyp/memblockq.h | 3 ++ polyp/native-common.h | 3 ++ polyp/pacat.c | 8 +++- polyp/pactl.c | 4 ++ polyp/polyplib-context.c | 4 +- polyp/polyplib-def.h | 5 +++ polyp/polyplib-internal.h | 2 + polyp/polyplib-simple.c | 4 +- polyp/polyplib-stream.c | 102 ++++++++++++++++++++++++++++++++++++++++++---- polyp/polyplib-stream.h | 40 +++++++++++++++--- polyp/polyplib.h | 7 ---- polyp/protocol-esound.c | 89 +++++++++++++++++++++++----------------- polyp/protocol-native.c | 76 ++++++++++++++++++++++++++++++++-- polyp/sample.c | 2 +- polyp/sample.h | 2 +- polyp/sink-input.c | 14 ++++--- polyp/sink-input.h | 3 +- polyp/source-output.c | 14 ++++++- polyp/source-output.h | 3 ++ polyp/util.c | 1 + 26 files changed, 392 insertions(+), 94 deletions(-) diff --git a/configure.ac b/configure.ac index 24a7e985..3a0675c3 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. AC_PREREQ(2.57) -AC_INIT([polypaudio],[0.5.1],[mzcbylcnhqvb (at) 0pointer (dot) de]) +AC_INIT([polypaudio],[0.6],[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([polyp/main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) diff --git a/doc/todo b/doc/todo index 6665de96..6bbd70ad 100644 --- a/doc/todo +++ b/doc/todo @@ -4,23 +4,29 @@ - per-channel volume - unix socket directories include user name - add sample directory -- udp based protocol - make mcalign merge chunks - option to use default fragment size on alsa drivers - improve module-oss-mmap latency measurement - proper locking around native protocol socket +- pacat sample type args +- filter capture data in client through alignment +- paplay +- check module-combine algo +- add redirection module +- add matching module +- add radio module +- make autoload list use idxset ** later *** - xmlrpc/http - dbus - slp/rendezvous -- modinfo - make alsa modules use mmap *********** backends for: -- portaudio +- portaudio (semi-done) - alsa-lib - sdl - gstreamer (semi-done) diff --git a/polyp/cli-text.c b/polyp/cli-text.c index 3cedf920..f9bc6c7a 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -64,7 +64,7 @@ char *pa_client_list_to_string(struct pa_core *c) { s = pa_strbuf_new(); assert(s); - pa_strbuf_printf(s, "%u client(s).\n", pa_idxset_ncontents(c->clients)); + pa_strbuf_printf(s, "%u client(s) logged in.\n", pa_idxset_ncontents(c->clients)); for (client = pa_idxset_first(c->clients, &index); client; client = pa_idxset_next(c->clients, &index)) { pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\tprotocol_name: <%s>\n", client->index, client->name, client->protocol_name); @@ -148,6 +148,11 @@ char *pa_source_output_list_to_string(struct pa_core *c) { struct pa_strbuf *s; struct pa_source_output *o; uint32_t index = PA_IDXSET_INVALID; + static const char* const state_table[] = { + "RUNNING", + "CORKED", + "DISCONNECTED" + }; assert(c); s = pa_strbuf_new(); @@ -160,15 +165,16 @@ char *pa_source_output_list_to_string(struct pa_core *c) { pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec); assert(o->source); pa_strbuf_printf( - s, " index: %u\n\tname: <%s>\n\tsource: <%u>\n\tsample_spec: <%s>\n", + s, " index: %u\n\tname: '%s'\n\tstate: %s\n\tsource: <%u> '%s'\n\tsample_spec: <%s>\n", o->index, o->name, - o->source->index, + state_table[o->state], + o->source->index, o->source->name, ss); if (o->owner) pa_strbuf_printf(s, "\towner module: <%u>\n", o->owner->index); if (o->client) - pa_strbuf_printf(s, "\tclient: <%u>\n", o->client->index); + pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", o->client->index, o->client->name); } return pa_strbuf_tostring_free(s); @@ -178,8 +184,13 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { struct pa_strbuf *s; struct pa_sink_input *i; uint32_t index = PA_IDXSET_INVALID; - assert(c); + static const char* const state_table[] = { + "RUNNING", + "CORKED", + "DISCONNECTED" + }; + assert(c); s = pa_strbuf_new(); assert(s); @@ -190,10 +201,11 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec); assert(i->sink); pa_strbuf_printf( - s, " index: %u\n\tname: <%s>\n\tsink: <%u>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n", + s, " index: %u\n\tname: <%s>\n\tstate: %s\n\tsink: <%u> '%s'\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n", i->index, i->name, - i->sink->index, + state_table[i->state], + i->sink->index, i->sink->name, (unsigned) i->volume, pa_volume_to_dB(i->volume), (float) pa_sink_input_get_latency(i), @@ -202,7 +214,7 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { if (i->owner) pa_strbuf_printf(s, "\towner module: <%u>\n", i->owner->index); if (i->client) - pa_strbuf_printf(s, "\tclient: <%u>\n", i->client->index); + pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", i->client->index, i->client->name); } return pa_strbuf_tostring_free(s); diff --git a/polyp/cpulimit.c b/polyp/cpulimit.c index fc49f5bb..a60c03d7 100644 --- a/polyp/cpulimit.c +++ b/polyp/cpulimit.c @@ -35,7 +35,7 @@ /* Utilize this much CPU time at maximum */ #define CPUTIME_PERCENT 70 -#define CPUTIME_INTERVAL_SOFT (5) +#define CPUTIME_INTERVAL_SOFT (10) #define CPUTIME_INTERVAL_HARD (2) static time_t last_time = 0; diff --git a/polyp/main.c b/polyp/main.c index 08677f7f..0837e58d 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -48,6 +48,7 @@ #include "daemon-conf.h" #include "dumpmodules.h" #include "caps.h" +#include "cli-text.h" static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { pa_log(__FILE__": Got signal %s.\n", pa_strsignal(sig)); @@ -60,7 +61,47 @@ static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, case SIGUSR2: pa_module_load(userdata, "module-cli-protocol-unix", NULL); return; - + + case SIGHUP: { + int i; + + for (i = 0;; i++) { + char *c; + switch (i) { + case 0: + c = pa_sink_list_to_string(userdata); + break; + case 1: + c = pa_source_list_to_string(userdata); + break; + case 2: + c = pa_sink_input_list_to_string(userdata); + break; + case 3: + c = pa_source_output_list_to_string(userdata); + break; + case 4: + c = pa_client_list_to_string(userdata); + break; + case 5: + c = pa_module_list_to_string(userdata); + break; + case 6: + c = pa_scache_list_to_string(userdata); + break; + case 7: + c = pa_autoload_list_to_string(userdata); + break; + default: + return; + } + pa_log(c); + pa_xfree(c); + } + + return; + } + case SIGINT: case SIGTERM: default: @@ -70,7 +111,8 @@ static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, } } -static void close_pipe(int p[2]) { + + static void close_pipe(int p[2]) { if (p[0] != -1) close(p[0]); if (p[1] != -1) @@ -223,6 +265,7 @@ int main(int argc, char *argv[]) { pa_signal_new(SIGUSR1, signal_callback, c); pa_signal_new(SIGUSR2, signal_callback, c); + pa_signal_new(SIGHUP, signal_callback, c); r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop)); assert(r == 0); diff --git a/polyp/memblockq.c b/polyp/memblockq.c index 59794d6c..0e71fa8c 100644 --- a/polyp/memblockq.c +++ b/polyp/memblockq.c @@ -42,7 +42,7 @@ struct memblock_list { struct pa_memblockq { struct memblock_list *blocks, *blocks_tail; unsigned n_blocks; - size_t current_length, maxlength, tlength, base, prebuf, minreq; + size_t current_length, maxlength, tlength, base, prebuf, orig_prebuf, minreq; struct pa_mcalign *mcalign; struct pa_memblock_stat *memblock_stat; }; @@ -72,6 +72,8 @@ struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t b bq->prebuf = (bq->prebuf/base)*base; if (bq->prebuf > bq->maxlength) bq->prebuf = bq->maxlength; + + bq->orig_prebuf = bq->prebuf; bq->minreq = (minreq/base)*base; if (bq->minreq == 0) @@ -285,6 +287,11 @@ void pa_memblockq_prebuf_disable(struct pa_memblockq *bq) { bq->prebuf = 0; } +void pa_memblockq_prebuf_reenable(struct pa_memblockq *bq) { + assert(bq); + bq->prebuf = bq->orig_prebuf; +} + void pa_memblockq_seek(struct pa_memblockq *bq, size_t length) { assert(bq); diff --git a/polyp/memblockq.h b/polyp/memblockq.h index 16b51d7a..aeed4193 100644 --- a/polyp/memblockq.h +++ b/polyp/memblockq.h @@ -83,6 +83,9 @@ uint32_t pa_memblockq_get_minreq(struct pa_memblockq *bq); /* Force disabling of pre-buf even when the pre-buffer is not yet filled */ void pa_memblockq_prebuf_disable(struct pa_memblockq *bq); +/* Reenable pre-buf to the initial level */ +void pa_memblockq_prebuf_reenable(struct pa_memblockq *bq); + /* Manipulate the write pointer */ void pa_memblockq_seek(struct pa_memblockq *bq, size_t delta); diff --git a/polyp/native-common.h b/polyp/native-common.h index a052fca2..5ecb26c0 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -87,6 +87,9 @@ enum { PA_COMMAND_GET_AUTOLOAD_INFO, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, PA_COMMAND_GET_RECORD_LATENCY, + PA_COMMAND_CORK_RECORD_STREAM, + PA_COMMAND_FLUSH_RECORD_STREAM, + PA_COMMAND_PREBUF_PLAYBACK_STREAM, PA_COMMAND_MAX }; diff --git a/polyp/pacat.c b/polyp/pacat.c index b9cb047a..1eb37d4d 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -37,6 +37,10 @@ #include #include +#if PA_API_VERSION != PA_API_VERSION_0_6 +#error Invalid Polypaudio API version +#endif + static enum { RECORD, PLAYBACK } mode = PLAYBACK; static struct pa_context *context = NULL; @@ -165,9 +169,9 @@ static void context_state_callback(struct pa_context *c, void *userdata) { pa_stream_set_read_callback(stream, stream_read_callback, NULL); if (mode == PLAYBACK) - pa_stream_connect_playback(stream, device, NULL, volume); + pa_stream_connect_playback(stream, device, NULL, 0, volume); else - pa_stream_connect_record(stream, device, NULL); + pa_stream_connect_record(stream, device, NULL, 0); break; diff --git a/polyp/pactl.c b/polyp/pactl.c index 2a466b39..cf2f51c3 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -41,6 +41,10 @@ #include #include +#if PA_API_VERSION != PA_API_VERSION_0_6 +#error Invalid Polypaudio API version +#endif + #define BUFSIZE 1024 static struct pa_context *context = NULL; diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 32ce3888..d793c186 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -218,8 +218,10 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, ui pa_context_ref(c); if ((s = pa_dynarray_get(c->record_streams, channel))) { - if (s->read_callback) + if (s->read_callback) { s->read_callback(s, (uint8_t*) chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); + s->counter += chunk->length; + } } pa_context_unref(c); diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index bab23e47..cd0662dd 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -72,6 +72,11 @@ enum pa_stream_direction { PA_STREAM_UPLOAD /**< Sample upload stream */ }; +/** Some special flags for stream connections. \since 0.6 */ +enum pa_stream_flags { + PA_STREAM_START_CORKED = 1, /**< Create the stream corked, requiring an explicit pa_stream_cork() call to uncork it. */ +}; + /** Playback and record buffer metrics */ struct pa_buffer_attr{ uint32_t maxlength; /**< Maximum length of the buffer */ diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 6e64755d..656d07db 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -92,6 +92,8 @@ struct pa_stream { uint32_t device_index; enum pa_stream_direction direction; uint32_t requested_bytes; + uint64_t counter; + pa_usec_t previous_time; enum pa_stream_state state; void (*state_callback)(struct pa_stream*c, void *userdata); diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c index aa6c88f5..9e111e2a 100644 --- a/polyp/polyplib-simple.c +++ b/polyp/polyplib-simple.c @@ -156,9 +156,9 @@ struct pa_simple* pa_simple_new( goto fail; if (dir == PA_STREAM_PLAYBACK) - pa_stream_connect_playback(p->stream, dev, attr, volume); + pa_stream_connect_playback(p->stream, dev, attr, 0, volume); else - pa_stream_connect_record(p->stream, dev, attr); + pa_stream_connect_record(p->stream, dev, attr, 0); /* Wait until the stream is ready */ while (pa_stream_get_state(p->stream) != PA_STREAM_READY) { diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 8bd098d4..291c3cd3 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -47,7 +47,7 @@ struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const st s->state_callback = NULL; s->state_userdata = NULL; - s->state = PA_STREAM_NODIRECTION; + s->direction = PA_STREAM_NODIRECTION; s->name = pa_xstrdup(name); s->sample_spec = *ss; s->channel = 0; @@ -57,6 +57,9 @@ struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const st s->state = PA_STREAM_DISCONNECTED; memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); + s->counter = 0; + s->previous_time = 0; + PA_LLIST_PREPEND(struct pa_stream, c->streams, s); return pa_stream_ref(s); @@ -211,7 +214,7 @@ finish: pa_stream_unref(s); } -static void create_stream(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, pa_volume_t volume) { +static void create_stream(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, enum pa_stream_flags flags, pa_volume_t volume) { struct pa_tagstruct *t; uint32_t tag; assert(s && s->ref >= 1 && s->state == PA_STREAM_DISCONNECTED); @@ -247,6 +250,7 @@ static void create_stream(struct pa_stream *s, const char *dev, const struct pa_ pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, dev); pa_tagstruct_putu32(t, s->buffer_attr.maxlength); + pa_tagstruct_put_boolean(t, !!(flags & PA_STREAM_START_CORKED)); if (s->direction == PA_STREAM_PLAYBACK) { pa_tagstruct_putu32(t, s->buffer_attr.tlength); pa_tagstruct_putu32(t, s->buffer_attr.prebuf); @@ -261,16 +265,16 @@ static void create_stream(struct pa_stream *s, const char *dev, const struct pa_ pa_stream_unref(s); } -void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, pa_volume_t volume) { +void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, enum pa_stream_flags flags, pa_volume_t volume) { assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); s->direction = PA_STREAM_PLAYBACK; - create_stream(s, dev, attr, volume); + create_stream(s, dev, attr, flags, volume); } -void pa_stream_connect_record(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr) { +void pa_stream_connect_record(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, enum pa_stream_flags flags) { assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); s->direction = PA_STREAM_RECORD; - create_stream(s, dev, attr, 0); + create_stream(s, dev, attr, flags, 0); } void pa_stream_write(struct pa_stream *s, const void *data, size_t length, void (*free_cb)(void *p), size_t delta) { @@ -295,6 +299,8 @@ void pa_stream_write(struct pa_stream *s, const void *data, size_t length, void s->requested_bytes -= length; else s->requested_bytes = 0; + + s->counter += length; } size_t pa_stream_writable_size(struct pa_stream *s) { @@ -506,10 +512,10 @@ struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (stru t = pa_tagstruct_new(NULL, 0); assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_CORK_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CORK_PLAYBACK_STREAM : PA_COMMAND_CORK_RECORD_STREAM); pa_tagstruct_putu32(t, tag = s->context->ctag++); pa_tagstruct_putu32(t, s->channel); - pa_tagstruct_putu32(t, !!b); + pa_tagstruct_put_boolean(t, !!b); pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); @@ -537,7 +543,11 @@ struct pa_operation* pa_stream_send_simple_command(struct pa_stream *s, uint32_t } struct pa_operation* pa_stream_flush(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { - return pa_stream_send_simple_command(s, PA_COMMAND_FLUSH_PLAYBACK_STREAM, cb, userdata); + return pa_stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata); +} + +struct pa_operation* pa_stream_prebuf(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { + return pa_stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata); } struct pa_operation* pa_stream_trigger(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { @@ -566,3 +576,77 @@ struct pa_operation* pa_stream_set_name(struct pa_stream *s, const char *name, v return pa_operation_ref(o); } + +uint64_t pa_stream_get_counter(struct pa_stream *s) { + assert(s); + return s->counter; +} + +void pa_stream_reset_counter(struct pa_stream *s) { + assert(s); + s->counter = 0; + s->previous_time = 0; +} + +pa_usec_t pa_stream_get_time(struct pa_stream *s, const struct pa_latency_info *i) { + pa_usec_t usec; + assert(s); + + usec = pa_bytes_to_usec(s->counter, &s->sample_spec); + + if (i) { + if (s->direction == PA_STREAM_PLAYBACK) { + pa_usec_t latency = i->transport_usec + i->buffer_usec + i->sink_usec; + if (usec < latency) + usec = 0; + else + usec -= latency; + + } else if (s->direction == PA_STREAM_RECORD) { + usec += i->source_usec + i->buffer_usec + i->transport_usec; + + if (usec > i->sink_usec) + usec -= i->sink_usec; + else + usec = 0; + } + } + + if (usec < s->previous_time) + usec = s->previous_time; + + s->previous_time = usec; + + return usec; +} + +pa_usec_t pa_stream_get_total_latency(struct pa_stream *s, const struct pa_latency_info *i, int *negative) { + assert(s && i); + + if (s->direction == PA_STREAM_PLAYBACK) { + if (negative) + *negative = 0; + + return i->transport_usec + i->buffer_usec + i->sink_usec; + } else if (s->direction == PA_STREAM_RECORD) { + pa_usec_t usec = i->source_usec + i->buffer_usec + i->transport_usec; + + if (usec >= i->sink_usec) { + if (negative) + *negative = 0; + return usec - i->sink_usec; + } else { + if (negative) + *negative = 1; + + return i->sink_usec - usec; + } + } + + return 0; +} + +const struct pa_sample_spec* pa_stream_get_sample_spec(struct pa_stream *s) { + assert(s); + return &s->sample_spec; +} diff --git a/polyp/polyplib-stream.h b/polyp/polyplib-stream.h index 257f2b99..e095d7fa 100644 --- a/polyp/polyplib-stream.h +++ b/polyp/polyplib-stream.h @@ -57,10 +57,10 @@ struct pa_context* pa_stream_get_context(struct pa_stream *p); uint32_t pa_stream_get_index(struct pa_stream *s); /** Connect the stream to a sink */ -void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, pa_volume_t volume); +void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, enum pa_stream_flags flags, pa_volume_t volume); /** Connect the stream to a source */ -void pa_stream_connect_record(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr); +void pa_stream_connect_record(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, enum pa_stream_flags flags); /** Disconnect a stream from a source/sink */ void pa_stream_disconnect(struct pa_stream *s); @@ -107,28 +107,56 @@ struct pa_operation* pa_stream_get_latency(struct pa_stream *p, void (*cb)(struc /** Set the callback function that is called whenever the state of the stream changes */ void pa_stream_set_state_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); -/** Set the callback function that is called when new data may be written to the stream */ +/** Set the callback function that is called when new data may be + * written to the stream. */ void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); /** Set the callback function that is called when new data is available from the stream */ void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); -/** Pause (or resume) playback of this stream temporarily. \since 0.3 */ +/** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. \since 0.3 */ struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); /** Flush the playback buffer of this stream. Most of the time you're * better off using the parameter delta of pa_stream_write() instead of this - * function. \since 0.3 */ + * function. Available on both playback and recording streams. \since 0.3 */ struct pa_operation* pa_stream_flush(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata); +/** Reenable prebuffering. Available for playback streams only. \since 0.6 */ +struct pa_operation* pa_stream_prebuf(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata); + /** Request immediate start of playback on this stream. This disables - * prebuffering as specified in the pa_buffer_attr structure. \since + * prebuffering as specified in the pa_buffer_attr structure. Available for playback streams only. \since * 0.3 */ struct pa_operation* pa_stream_trigger(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata); /** Rename the stream. \since 0.5 */ struct pa_operation* pa_stream_set_name(struct pa_stream *s, const char *name, void(*cb)(struct pa_stream*c, int success, void *userdata), void *userdata); +/** Return the total number of bytes written to/read from the + * stream. This counter is not reset on pa_stream_flush(), you may do + * this yourself using pa_stream_reset_counter(). \since 0.6 */ +uint64_t pa_stream_get_counter(struct pa_stream *s); + +/** Reset the total byte count to 0. \since 0.6 */ +void pa_stream_reset_counter(struct pa_stream *s); + +/** Return the current playback/recording time. This is based on the + * counter accessible with pa_stream_get_counter(). This function + * requires a pa_latency_info structure as argument, which should be + * acquired using pa_stream_get_latency(). \since 0.6 */ +pa_usec_t pa_stream_get_time(struct pa_stream *s, const struct pa_latency_info *i); + +/** Return the total stream latency. Thus function requires a + * pa_latency_info structure as argument, which should be aquired + * using pa_stream_get_latency(). In case the stream is a monitoring + * stream the result can be negative, i.e. the captured samples are + * not yet played. In this case *negative is set to 1. \since 0.6 */ +pa_usec_t pa_stream_get_total_latency(struct pa_stream *s, const struct pa_latency_info *i, int *negative); + +/** Return a pointer to the streams sample specification. \since 0.6 */ +const struct pa_sample_spec* pa_stream_get_sample_spec(struct pa_stream *s); + PA_C_DECL_END #endif diff --git a/polyp/polyplib.h b/polyp/polyplib.h index f4e41934..3921e2ba 100644 --- a/polyp/polyplib.h +++ b/polyp/polyplib.h @@ -83,11 +83,4 @@ * synchronous API is available as "polyplib-simple". */ -PA_C_DECL_BEGIN - -/** Return the version of the library the current application is linked to */ -const char* pa_get_library_version(void); - -PA_C_DECL_END - #endif diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 797263f6..79978740 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -62,6 +62,7 @@ struct connection { uint32_t index; + int dead; struct pa_protocol_esound *protocol; struct pa_iochannel *io; struct pa_client *client; @@ -76,14 +77,17 @@ struct connection { struct pa_source_output *source_output; struct pa_memblockq *input_memblockq, *output_memblockq; struct pa_defer_event *defer_event; + struct { struct pa_memblock *current_memblock; size_t memblock_index, fragment_size; } playback; - struct pa_memchunk scache_memchunk; - char *scache_name; - struct pa_sample_spec scache_sample_spec; + struct { + struct pa_memchunk memchunk; + char *name; + struct pa_sample_spec sample_spec; + } scache; }; struct pa_protocol_esound { @@ -195,9 +199,9 @@ static void connection_free(struct connection *c) { if (c->defer_event) c->protocol->core->mainloop->defer_free(c->defer_event); - if (c->scache_memchunk.memblock) - pa_memblock_unref(c->scache_memchunk.memblock); - pa_xfree(c->scache_name); + if (c->scache.memchunk.memblock) + pa_memblock_unref(c->scache.memchunk.memblock); + pa_xfree(c->scache.name); pa_xfree(c); } @@ -583,17 +587,17 @@ static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, con strncpy(name+sizeof(SCACHE_PREFIX)-1, (char*) data+3*sizeof(int), ESD_NAME_MAX); name[sizeof(name)-1] = 0; - assert(!c->scache_memchunk.memblock); - c->scache_memchunk.memblock = pa_memblock_new(sc_length, c->protocol->core->memblock_stat); - c->scache_memchunk.index = 0; - c->scache_memchunk.length = sc_length; - c->scache_sample_spec = ss; - assert(!c->scache_name); - c->scache_name = pa_xstrdup(name); + assert(!c->scache.memchunk.memblock); + c->scache.memchunk.memblock = pa_memblock_new(sc_length, c->protocol->core->memblock_stat); + c->scache.memchunk.index = 0; + c->scache.memchunk.length = sc_length; + c->scache.sample_spec = ss; + assert(!c->scache.name); + c->scache.name = pa_xstrdup(name); c->state = ESD_CACHING_SAMPLE; - pa_scache_add_item(c->protocol->core, c->scache_name, NULL, NULL, &index); + pa_scache_add_item(c->protocol->core, c->scache.name, NULL, NULL, &index); ok = connection_write(c, sizeof(int)); assert(ok); @@ -747,29 +751,29 @@ static int do_read(struct connection *c) { } else if (c->state == ESD_CACHING_SAMPLE) { ssize_t r; - assert(c->scache_memchunk.memblock && c->scache_name && c->scache_memchunk.index < c->scache_memchunk.length); + assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); - if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache_memchunk.memblock->data+c->scache_memchunk.index, c->scache_memchunk.length-c->scache_memchunk.index)) <= 0) { + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { pa_log(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } - c->scache_memchunk.index += r; - assert(c->scache_memchunk.index <= c->scache_memchunk.length); + c->scache.memchunk.index += r; + assert(c->scache.memchunk.index <= c->scache.memchunk.length); - if (c->scache_memchunk.index == c->scache_memchunk.length) { + if (c->scache.memchunk.index == c->scache.memchunk.length) { uint32_t index; int *ok; - c->scache_memchunk.index = 0; - pa_scache_add_item(c->protocol->core, c->scache_name, &c->scache_sample_spec, &c->scache_memchunk, &index); + c->scache.memchunk.index = 0; + pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, &c->scache.memchunk, &index); - pa_memblock_unref(c->scache_memchunk.memblock); - c->scache_memchunk.memblock = NULL; - c->scache_memchunk.index = c->scache_memchunk.length = 0; + pa_memblock_unref(c->scache.memchunk.memblock); + c->scache.memchunk.memblock = NULL; + c->scache.memchunk.index = c->scache.memchunk.length = 0; - pa_xfree(c->scache_name); - c->scache_name = NULL; + pa_xfree(c->scache.name); + c->scache.name = NULL; c->state = ESD_NEXT_REQUEST; @@ -869,21 +873,26 @@ static void do_work(struct connection *c) { assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); c->protocol->core->mainloop->defer_enable(c->defer_event, 0); - if (pa_iochannel_is_hungup(c->io)) - goto fail; + if (c->dead) + return; + + if (pa_iochannel_is_readable(c->io)) + if (do_read(c) < 0) + goto fail; if (pa_iochannel_is_writable(c->io)) if (do_write(c) < 0) goto fail; - if (pa_iochannel_is_readable(c->io)) - if (do_read(c) < 0) - goto fail; - return; fail: - connection_free(c); + + if (c->state == ESD_STREAMING_DATA && c->sink_input) { + c->dead = 1; + pa_memblockq_prebuf_disable(c->input_memblockq); + } else + connection_free(c); } static void io_callback(struct pa_iochannel*io, void *userdata) { @@ -909,8 +918,13 @@ static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk assert(i && i->userdata && chunk); c = i->userdata; - if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) + if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) { + + if (c->dead) + connection_free(c); + return -1; + } return 0; } @@ -985,6 +999,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->authorized = c->protocol->public; c->swap_byte_order = 0; + c->dead = 0; c->read_data_length = 0; c->read_data = pa_xmalloc(c->read_data_alloc = proto_map[ESD_PROTO_CONNECT].data_length); @@ -1005,9 +1020,9 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->playback.memblock_index = 0; c->playback.fragment_size = 0; - c->scache_memchunk.length = c->scache_memchunk.index = 0; - c->scache_memchunk.memblock = NULL; - c->scache_name = NULL; + c->scache.memchunk.length = c->scache.memchunk.index = 0; + c->scache.memchunk.memblock = NULL; + c->scache.name = NULL; c->defer_event = c->protocol->core->mainloop->defer_new(c->protocol->core->mainloop, defer_callback, c); assert(c->defer_event); diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 4c1e9696..f36bbd71 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -150,6 +150,8 @@ static void command_add_autoload(struct pa_pdispatch *pd, uint32_t command, uint static void command_remove_autoload(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_get_autoload_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_get_autoload_info_list(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_cork_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_flush_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = { NULL }, @@ -190,11 +192,18 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_GET_SAMPLE_INFO_LIST] = { command_get_info_list }, [PA_COMMAND_GET_SERVER_INFO] = { command_get_server_info }, [PA_COMMAND_SUBSCRIBE] = { command_subscribe }, + [PA_COMMAND_SET_SINK_VOLUME] = { command_set_volume }, [PA_COMMAND_SET_SINK_INPUT_VOLUME] = { command_set_volume }, + [PA_COMMAND_CORK_PLAYBACK_STREAM] = { command_cork_playback_stream }, [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = { command_flush_or_trigger_playback_stream }, [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = { command_flush_or_trigger_playback_stream }, + [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = { command_flush_or_trigger_playback_stream }, + + [PA_COMMAND_CORK_RECORD_STREAM] = { command_cork_record_stream }, + [PA_COMMAND_FLUSH_RECORD_STREAM] = { command_flush_record_stream }, + [PA_COMMAND_SET_DEFAULT_SINK] = { command_set_default_sink_or_source }, [PA_COMMAND_SET_DEFAULT_SOURCE] = { command_set_default_sink_or_source }, [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = { command_set_stream_name }, @@ -208,6 +217,7 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = { command_get_autoload_info_list }, [PA_COMMAND_ADD_AUTOLOAD] = { command_add_autoload }, [PA_COMMAND_REMOVE_AUTOLOAD] = { command_remove_autoload }, + }; /* structure management */ @@ -538,6 +548,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com struct pa_tagstruct *reply; struct pa_sink *sink; pa_volume_t volume; + int corked; assert(c && t && c->protocol && c->protocol->core); if (pa_tagstruct_gets(t, &name) < 0 || !name || @@ -545,6 +556,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com pa_tagstruct_getu32(t, &sink_index) < 0 || pa_tagstruct_gets(t, &sink_name) < 0 || pa_tagstruct_getu32(t, &maxlength) < 0 || + pa_tagstruct_get_boolean(t, &corked) < 0 || pa_tagstruct_getu32(t, &tlength) < 0 || pa_tagstruct_getu32(t, &prebuf) < 0 || pa_tagstruct_getu32(t, &minreq) < 0 || @@ -574,6 +586,8 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); return; } + + pa_sink_input_cork(s->sink_input, corked); reply = pa_tagstruct_new(NULL, 0); assert(reply); @@ -1412,12 +1426,12 @@ static void command_set_volume(struct pa_pdispatch *pd, uint32_t command, uint32 static void command_cork_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; uint32_t index; - uint32_t b; + int b; struct playback_stream *s; assert(c && t); if (pa_tagstruct_getu32(t, &index) < 0 || - pa_tagstruct_getu32(t, &b) < 0 || + pa_tagstruct_get_boolean(t, &b) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1459,7 +1473,9 @@ static void command_flush_or_trigger_playback_stream(struct pa_pdispatch *pd, ui return; } - if (command == PA_COMMAND_TRIGGER_PLAYBACK_STREAM) + if (command == PA_COMMAND_PREBUF_PLAYBACK_STREAM) + pa_memblockq_prebuf_reenable(s->memblockq); + else if (command == PA_COMMAND_TRIGGER_PLAYBACK_STREAM) pa_memblockq_prebuf_disable(s->memblockq); else { assert(command == PA_COMMAND_FLUSH_PLAYBACK_STREAM); @@ -1472,6 +1488,60 @@ static void command_flush_or_trigger_playback_stream(struct pa_pdispatch *pd, ui request_bytes(s); } +static void command_cork_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t index; + struct record_stream *s; + int b; + assert(c && t); + + if (pa_tagstruct_getu32(t, &index) < 0 || + pa_tagstruct_get_boolean(t, &b) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->record_streams, index))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_source_output_cork(s->source_output, b); + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_flush_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t index; + struct record_stream *s; + assert(c && t); + + if (pa_tagstruct_getu32(t, &index) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->record_streams, index))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_memblockq_flush(s->memblockq); + pa_pstream_send_simple_ack(c->pstream, tag); +} + static void command_set_default_sink_or_source(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; uint32_t index; diff --git a/polyp/sample.c b/polyp/sample.c index 143e1e41..65ae8ff3 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -59,7 +59,7 @@ size_t pa_bytes_per_second(const struct pa_sample_spec *spec) { return spec->rate*pa_frame_size(spec); } -pa_usec_t pa_bytes_to_usec(size_t length, const struct pa_sample_spec *spec) { +pa_usec_t pa_bytes_to_usec(uint64_t length, const struct pa_sample_spec *spec) { assert(spec); return (pa_usec_t) (((double) length/pa_frame_size(spec)*1000000)/spec->rate); diff --git a/polyp/sample.h b/polyp/sample.h index 501172a8..912cdaa0 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -77,7 +77,7 @@ size_t pa_bytes_per_second(const struct pa_sample_spec *spec); size_t pa_frame_size(const struct pa_sample_spec *spec); /** Calculate the time the specified bytes take to play with the specified sample type */ -pa_usec_t pa_bytes_to_usec(size_t length, const struct pa_sample_spec *spec); +pa_usec_t pa_bytes_to_usec(uint64_t length, const struct pa_sample_spec *spec); /** Return non-zero when the sample type specification is valid */ int pa_sample_spec_valid(const struct pa_sample_spec *spec); diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 94930231..5c8675de 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -70,7 +70,6 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con i->get_latency = NULL; i->userdata = NULL; - i->corked = 0; i->volume = PA_VOLUME_NORM; i->resampled_chunk.memblock = NULL; @@ -92,7 +91,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con } void pa_sink_input_disconnect(struct pa_sink_input *i) { - assert(i && i->state == PA_SINK_INPUT_RUNNING && i->sink && i->sink->core); + assert(i && i->state != PA_SINK_INPUT_DISCONNECTED && i->sink && i->sink->core); pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); pa_idxset_remove_by_data(i->sink->inputs, i, NULL); @@ -163,7 +162,7 @@ int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { if (!i->peek || !i->drop) return -1; - if (i->corked) + if (i->state == PA_SINK_INPUT_CORKED) return -1; if (!i->resampler) @@ -238,9 +237,12 @@ void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume) { void pa_sink_input_cork(struct pa_sink_input *i, int b) { int n; assert(i && i->ref >= 1); - - n = i->corked && !b; - i->corked = b; + + if (i->state == PA_SINK_INPUT_DISCONNECTED) + return; + + n = i->state == PA_SINK_INPUT_CORKED && !b; + i->state = b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING; if (n) pa_sink_notify(i->sink); diff --git a/polyp/sink-input.h b/polyp/sink-input.h index 7c648ac1..aed5f521 100644 --- a/polyp/sink-input.h +++ b/polyp/sink-input.h @@ -33,6 +33,7 @@ enum pa_sink_input_state { PA_SINK_INPUT_RUNNING, + PA_SINK_INPUT_CORKED, PA_SINK_INPUT_DISCONNECTED }; @@ -42,8 +43,6 @@ struct pa_sink_input { uint32_t index; - int corked; - char *name; struct pa_module *owner; struct pa_client *client; diff --git a/polyp/source-output.c b/polyp/source-output.c index 13b39658..5a40fa42 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -79,7 +79,7 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n } void pa_source_output_disconnect(struct pa_source_output*o) { - assert(o && o->state == PA_SOURCE_OUTPUT_RUNNING && o->source && o->source->core); + assert(o && o->state != PA_SOURCE_OUTPUT_DISCONNECTED && o->source && o->source->core); pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); pa_idxset_remove_by_data(o->source->outputs, o, NULL); @@ -133,6 +133,9 @@ void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk struct pa_memchunk rchunk; assert(o && chunk && chunk->length && o->push); + if (o->state == PA_SOURCE_OUTPUT_CORKED) + return; + if (!o->resampler) { o->push(o, chunk); return; @@ -163,3 +166,12 @@ pa_usec_t pa_source_output_get_latency(struct pa_source_output *o) { return 0; } + +void pa_source_output_cork(struct pa_source_output *o, int b) { + assert(o && o->ref >= 1); + + if (o->state == PA_SOURCE_OUTPUT_DISCONNECTED) + return; + + o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; +} diff --git a/polyp/source-output.h b/polyp/source-output.h index 51d5936b..a535782e 100644 --- a/polyp/source-output.h +++ b/polyp/source-output.h @@ -33,6 +33,7 @@ enum pa_source_output_state { PA_SOURCE_OUTPUT_RUNNING, + PA_SOURCE_OUTPUT_CORKED, PA_SOURCE_OUTPUT_DISCONNECTED }; @@ -73,5 +74,7 @@ void pa_source_output_set_name(struct pa_source_output *i, const char *name); pa_usec_t pa_source_output_get_latency(struct pa_source_output *i); +void pa_source_output_cork(struct pa_source_output *i, int b); + #endif diff --git a/polyp/util.c b/polyp/util.c index 1246bbb5..6be6ffe4 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -421,6 +421,7 @@ const char *pa_strsignal(int sig) { case SIGXCPU: return "SIGXCPU"; case SIGPIPE: return "SIGPIPE"; case SIGCHLD: return "SIGCHLD"; + case SIGHUP: return "SIGHUP"; default: return "UNKNOWN SIGNAL"; } } -- cgit From 949014e154dec912e080335630818ed016b45394 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 26 Sep 2004 22:27:04 +0000 Subject: add new tool paplay git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@241 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 +- polyp/Makefile.am | 10 +- polyp/module-combine.c | 4 +- polyp/paplay.c | 377 +++++++++++++++++++++++++++++++++++++++++++++++ polyp/polyplib-context.h | 3 + polyp/protocol-native.c | 10 +- 6 files changed, 396 insertions(+), 11 deletions(-) create mode 100644 polyp/paplay.c diff --git a/doc/todo b/doc/todo index 6bbd70ad..b5ae1446 100644 --- a/doc/todo +++ b/doc/todo @@ -10,12 +10,11 @@ - proper locking around native protocol socket - pacat sample type args - filter capture data in client through alignment -- paplay -- check module-combine algo - add redirection module - add matching module - add radio module - make autoload list use idxset +- improve file load to note force sample typ to PA_SAMPLE_FLOAT32 ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 4e075468..2d14b420 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -33,7 +33,7 @@ AM_LDADD=$(PTHREAD_LIBS) -lm AM_LIBADD=$(PTHREAD_LIBS) -lm EXTRA_DIST = default.pa.in daemon.conf.in client.conf.in depmod.py esdcompat.sh.in -bin_PROGRAMS = polypaudio pacat pactl +bin_PROGRAMS = polypaudio pacat pactl paplay bin_SCRIPTS = esdcompat.sh noinst_PROGRAMS = \ mainloop-test \ @@ -372,9 +372,13 @@ pacat_SOURCES = pacat.c pacat_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la pacat_CFLAGS = $(AM_CFLAGS) +paplay_SOURCES = paplay.c +paplay_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) +paplay_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) + pactl_SOURCES = pactl.c pactl_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) -pactl_CFLAGS = $(AM_CFLAGS) $(LIBSDNFILE_CFLAGS) +pactl_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) pacat_simple_SOURCES = pacat-simple.c pacat_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la @@ -460,7 +464,7 @@ lib_LTLIBRARIES+= \ noinst_PROGRAMS+= \ mainloop-test-glib12 - + libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_SOURCES = glib-mainloop.h glib12-mainloop.c libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS) libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop-@PA_MAJORMINOR@.la $(GLIB12_LIBS) diff --git a/polyp/module-combine.c b/polyp/module-combine.c index 6952ce6c..1a909087 100644 --- a/polyp/module-combine.c +++ b/polyp/module-combine.c @@ -115,8 +115,8 @@ static void adjust_rates(struct userdata *u) { base_rate = u->sink->sample_spec.rate; for (o = u->outputs; o; o = o->next) { - uint32_t r = base_rate; - + uint32_t r = base_rate; + if (o->total_latency < target_latency) r -= (uint32_t) (((((double) target_latency - o->total_latency))/u->adjust_time)*r/ 1000000); else if (o->total_latency > target_latency) diff --git a/polyp/paplay.c b/polyp/paplay.c new file mode 100644 index 00000000..cc973a7d --- /dev/null +++ b/polyp/paplay.c @@ -0,0 +1,377 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#if PA_API_VERSION != PA_API_VERSION_0_6 +#error Invalid Polypaudio API version +#endif + +static struct pa_context *context = NULL; +static struct pa_stream *stream = NULL; +static struct pa_mainloop_api *mainloop_api = NULL; + +static char *stream_name = NULL, *client_name = NULL, *device = NULL; + +static int verbose = 0; +static pa_volume_t volume = PA_VOLUME_NORM; + +static SNDFILE* sndfile = NULL; + +static struct pa_sample_spec sample_spec = { 0, 0, 0 }; + +static sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames); + +/* A shortcut for terminating the application */ +static void quit(int ret) { + assert(mainloop_api); + mainloop_api->quit(mainloop_api, ret); +} + +/* Connection draining complete */ +static void context_drain_complete(struct pa_context*c, void *userdata) { + pa_context_disconnect(c); +} + +/* Stream draining complete */ +static void stream_drain_complete(struct pa_stream*s, int success, void *userdata) { + struct pa_operation *o; + + if (!success) { + fprintf(stderr, "Failed to drain stream: %s\n", pa_strerror(pa_context_errno(context))); + quit(1); + } + + if (verbose) + fprintf(stderr, "Playback stream drained.\n"); + + pa_stream_disconnect(stream); + pa_stream_unref(stream); + stream = NULL; + + if (!(o = pa_context_drain(context, context_drain_complete, NULL))) + pa_context_disconnect(context); + else { + pa_operation_unref(o); + + if (verbose) + fprintf(stderr, "Draining connection to server.\n"); + } +} + +/* This is called whenever new data may be written to the stream */ +static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) { + size_t k; + sf_count_t f, n; + void *data; + assert(s && length); + + if (!sndfile) + return; + + k = pa_frame_size(&sample_spec); + + data = malloc(length); + + n = length/k; + + f = readf_function(sndfile, data, n); + + if (f > 0) + pa_stream_write(s, data, f*k, free, 0); + + if (f < n) { + sf_close(sndfile); + sndfile = NULL; + pa_operation_unref(pa_stream_drain(s, stream_drain_complete, NULL)); + } +} + +/* This routine is called whenever the stream state changes */ +static void stream_state_callback(struct pa_stream *s, void *userdata) { + assert(s); + + switch (pa_stream_get_state(s)) { + case PA_STREAM_CREATING: + case PA_STREAM_TERMINATED: + break; + + case PA_STREAM_READY: + if (verbose) + fprintf(stderr, "Stream successfully created\n"); + break; + + case PA_STREAM_FAILED: + default: + fprintf(stderr, "Stream errror: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + quit(1); + } +} + +/* This is called whenever the context status changes */ +static void context_state_callback(struct pa_context *c, void *userdata) { + assert(c); + + switch (pa_context_get_state(c)) { + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + + case PA_CONTEXT_READY: + + assert(c && !stream); + + if (verbose) + fprintf(stderr, "Connection established.\n"); + + stream = pa_stream_new(c, stream_name, &sample_spec); + assert(stream); + + pa_stream_set_state_callback(stream, stream_state_callback, NULL); + pa_stream_set_write_callback(stream, stream_write_callback, NULL); + pa_stream_connect_playback(stream, device, NULL, 0, volume); + + break; + + case PA_CONTEXT_TERMINATED: + quit(0); + break; + + case PA_CONTEXT_FAILED: + default: + fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + } +} + +/* UNIX signal to quit recieved */ +static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { + if (verbose) + fprintf(stderr, "Got SIGINT, exiting.\n"); + quit(0); + +} + +static void help(const char *argv0) { + + printf("%s [options] FILE\n\n" + " -h, --help Show this help\n" + " --version Show version\n\n" + " -v, --verbose Enable verbose operations\n\n" + " -s, --server=SERVER The name of the server to connect to\n" + " -d, --device=DEVICE The name of the sink/source to connect to\n" + " -n, --client-name=NAME How to call this client on the server\n" + " --stream-name=NAME How to call this stream on the server\n" + " --volume=VOLUME Specify the initial (linear) volume in range 0...256\n", + argv0); +} + +enum { + ARG_VERSION = 256, + ARG_STREAM_NAME, + ARG_VOLUME +}; + +int main(int argc, char *argv[]) { + struct pa_mainloop* m = NULL; + int ret = 1, r, c; + char *bn, *server = NULL; + SF_INFO sfinfo; + + static const struct option long_options[] = { + {"device", 1, NULL, 'd'}, + {"server", 1, NULL, 's'}, + {"client-name", 1, NULL, 'n'}, + {"stream-name", 1, NULL, ARG_STREAM_NAME}, + {"version", 0, NULL, ARG_VERSION}, + {"help", 0, NULL, 'h'}, + {"verbose", 0, NULL, 'v'}, + {"volume", 1, NULL, ARG_VOLUME}, + {NULL, 0, NULL, 0} + }; + + if (!(bn = strrchr(argv[0], '/'))) + bn = argv[0]; + else + bn++; + + while ((c = getopt_long(argc, argv, "d:s:n:hv", long_options, NULL)) != -1) { + + switch (c) { + case 'h' : + help(bn); + ret = 0; + goto quit; + + case ARG_VERSION: + printf("paplay "PACKAGE_VERSION"\nCompiled with libpolyp %s\nLinked with libpolyp %s\n", pa_get_headers_version(), pa_get_library_version()); + ret = 0; + goto quit; + + case 'd': + free(device); + device = strdup(optarg); + break; + + case 's': + free(server); + server = strdup(optarg); + break; + + case 'n': + free(client_name); + client_name = strdup(optarg); + break; + + case ARG_STREAM_NAME: + free(stream_name); + stream_name = strdup(optarg); + break; + + case 'v': + verbose = 1; + break; + + case ARG_VOLUME: { + int v = atoi(optarg); + volume = v < 0 ? 0 : v; + break; + } + + default: + goto quit; + } + } + + if (optind >= argc) { + fprintf(stderr, "Missing file name.\n"); + goto quit; + } + + if (!client_name) + client_name = strdup(bn); + + if (!stream_name) + stream_name = strdup(argv[optind]); + + memset(&sfinfo, 0, sizeof(sfinfo)); + + if (!(sndfile = sf_open(argv[optind], SFM_READ, &sfinfo))) { + fprintf(stderr, "Faile to open file '%s'\n", argv[optind]); + goto quit; + } + + sample_spec.rate = sfinfo.samplerate; + sample_spec.channels = sfinfo.channels; + + switch (sfinfo.format & 0xFF) { + case SF_FORMAT_PCM_16: + case SF_FORMAT_PCM_U8: + case SF_FORMAT_ULAW: + case SF_FORMAT_ALAW: + sample_spec.format = PA_SAMPLE_S16NE; + readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_short; + break; + case SF_FORMAT_FLOAT: + default: + sample_spec.format = PA_SAMPLE_FLOAT32NE; + readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_float; + break; + } + + if (verbose) { + char t[PA_SAMPLE_SPEC_SNPRINT_MAX]; + pa_sample_spec_snprint(t, sizeof(t), &sample_spec); + fprintf(stderr, "Using sample spec '%s'\n", t); + } + + /* Set up a new main loop */ + if (!(m = pa_mainloop_new())) { + fprintf(stderr, "pa_mainloop_new() failed.\n"); + goto quit; + } + + mainloop_api = pa_mainloop_get_api(m); + + r = pa_signal_init(mainloop_api); + assert(r == 0); + pa_signal_new(SIGINT, exit_signal_callback, NULL); + signal(SIGPIPE, SIG_IGN); + + /* Create a new connection context */ + if (!(context = pa_context_new(mainloop_api, client_name))) { + fprintf(stderr, "pa_context_new() failed.\n"); + goto quit; + } + + pa_context_set_state_callback(context, context_state_callback, NULL); + + /* Connect the context */ + pa_context_connect(context, server, 1, NULL); + + /* Run the main loop */ + if (pa_mainloop_run(m, &ret) < 0) { + fprintf(stderr, "pa_mainloop_run() failed.\n"); + goto quit; + } + +quit: + if (stream) + pa_stream_unref(stream); + + if (context) + pa_context_unref(context); + + if (m) { + pa_signal_done(); + pa_mainloop_free(m); + } + + free(server); + free(device); + free(client_name); + free(stream_name); + + if (sndfile) + sf_close(sndfile); + + return ret; +} diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h index 548a39dd..75be5930 100644 --- a/polyp/polyplib-context.h +++ b/polyp/polyplib-context.h @@ -45,6 +45,9 @@ /** \example pacat.c * A playback and recording tool using the asynchronous API */ +/** \example paplay.c + * A sound file playback tool using the asynchronous API, based on libsndfile */ + PA_C_DECL_BEGIN /** \struct pa_context diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index f36bbd71..aeccd504 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -484,7 +484,7 @@ static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk s->drain_request = 0; } - /*pa_log(__FILE__": after_drop: %u\n", pa_memblockq_get_length(s->memblockq));*/ +/* pa_log(__FILE__": after_drop: %u\n", pa_memblockq_get_length(s->memblockq)); */ } static void sink_input_kill_cb(struct pa_sink_input *i) { @@ -828,8 +828,10 @@ static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t comm pa_memblockq_prebuf_disable(s->memblockq); if (!pa_memblockq_is_readable(s->memblockq)) { +/* pa_log("immediate drain: %u\n", pa_memblockq_get_length(s->memblockq)); */ pa_pstream_send_simple_ack(c->pstream, tag); } else { +/* pa_log("slow drain triggered\n"); */ s->drain_request = 1; s->drain_tag = tag; @@ -1854,7 +1856,7 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, ui struct connection *c = userdata; struct output_stream *stream; assert(p && chunk && userdata); - + if (!(stream = pa_idxset_get_by_index(c->output_streams, channel))) { pa_log(__FILE__": client sent block for invalid stream.\n"); connection_free(c); @@ -1870,10 +1872,10 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, ui pa_memblockq_push_align(p->memblockq, chunk, delta); assert(p->sink_input); - /*pa_log(__FILE__": after_recv: %u\n", pa_memblockq_get_length(p->memblockq));*/ +/* pa_log(__FILE__": after_recv: %u\n", pa_memblockq_get_length(p->memblockq)); */ pa_sink_notify(p->sink_input->sink); -/* pa_log(__FILE__": Recieved %u bytes.\n", chunk->length); */ +/* pa_log(__FILE__": Recieved %u bytes.\n", chunk->length); */ } else { struct upload_stream *u = (struct upload_stream*) stream; -- cgit From 35148d8c0565d9b7faafe423367c4bd750461533 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 27 Sep 2004 15:40:18 +0000 Subject: add POSIX locking to authkey.c fix esound protocol cpu consumption when finishing a stream git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@242 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/authkey.c | 109 +++++++++++++++++++++++++++--------------------- polyp/protocol-esound.c | 11 +++-- polyp/util.c | 17 ++++++++ polyp/util.h | 3 ++ 4 files changed, 90 insertions(+), 50 deletions(-) diff --git a/polyp/authkey.c b/polyp/authkey.c index 9b60506f..1e2edb07 100644 --- a/polyp/authkey.c +++ b/polyp/authkey.c @@ -41,48 +41,23 @@ #define RANDOM_DEVICE "/dev/urandom" -static int load(const char *fn, void *data, size_t length) { - int fd = -1, ret = -1; +static int generate(int fd, void *data, size_t length) { + int random_fd, ret = -1; ssize_t r; - - assert(fn && data && length); - - if ((fd = open(fn, O_RDONLY)) < 0) - goto finish; - - if ((r = pa_loop_read(fd, data, length)) < 0 || (size_t) r != length) { - ret = -2; - goto finish; - } + assert(fd >= 0 && data && length); - ret = 0; - -finish: - if (fd >= 0) - close(fd); - - return ret; -} - -static int generate(const char *fn, void *data, size_t length) { - int fd = -1, random_fd = -1, ret = -1; - ssize_t r; - assert(fn && data && length); - - if ((fd = open(fn, O_WRONLY|O_EXCL|O_CREAT, S_IRUSR | S_IWUSR)) < 0) - goto finish; - if ((random_fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) { if ((r = pa_loop_read(random_fd, data, length)) < 0 || (size_t) r != length) { - ret = -2; + pa_log(__FILE__": failed to read entropy from '%s'\n", RANDOM_DEVICE); goto finish; } } else { uint8_t *p; size_t l; - pa_log(__FILE__": WARNING: Failed to open entropy device '"RANDOM_DEVICE"': %s, falling back to unsecure pseudo RNG.\n", strerror(errno)); + pa_log(__FILE__": WARNING: Failed to open entropy device '"RANDOM_DEVICE"': %s" + ", falling back to unsecure pseudo RNG.\n", strerror(errno)); srandom(time(NULL)); @@ -90,41 +65,81 @@ static int generate(const char *fn, void *data, size_t length) { *p = (uint8_t) random(); } + lseek(fd, 0, SEEK_SET); + if ((r = pa_loop_write(fd, data, length)) < 0 || (size_t) r != length) { - ret = -2; + pa_log(__FILE__": failed to write cookie file\n"); goto finish; } ret = 0; finish: + + if (random_fd >= 0) + close(random_fd); + + return ret; +} + +static int load(const char *fn, void *data, size_t length) { + int fd = -1; + int writable = 1; + assert(fn && data && length); + int unlock = 0, ret; + ssize_t r; + + if ((fd = open(fn, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { + if (errno != EACCES || (fd = open(fn, O_RDONLY)) < 0) { + pa_log(__FILE__": failed to open cookie file '%s'\n", fn); + goto finish; + } else + writable = 0; + } + + unlock = pa_lock_file(fd, 1) >= 0; + + if ((r = pa_loop_read(fd, data, length)) < 0) { + pa_log(__FILE__": failed to read cookie file '%s'\n", fn); + goto finish; + } + + if ((size_t) r != length) { + + if (!writable) { + pa_log(__FILE__": unable to write cookie to read only file\n"); + goto finish; + } + + if (generate(fd, data, length) < 0) + goto finish; + } + + ret = 0; + +finish: + if (fd >= 0) { - if (ret != 0) - unlink(fn); + + if (unlock) + pa_lock_file(fd, 0); + close(fd); } - if (random_fd >= 0) - close(random_fd); return ret; } int pa_authkey_load(const char *path, void *data, size_t length) { - int ret, i; + int ret; assert(path && data && length); - - for (i = 0; i < 10; i++) { - if ((ret = load(path, data, length)) < 0) - if (ret == -1 && errno == ENOENT) - if ((ret = generate(path, data, length)) < 0) - if (ret == -1 && errno == EEXIST) - continue; - break; - } + + ret = load(path, data, length); if (ret < 0) - pa_log(__FILE__": Failed to load authorization key '%s': %s\n", path, (ret == -1) ? strerror(errno) : "file corrupt"); + pa_log(__FILE__": Failed to load authorization key '%s': %s\n", path, + (ret == -1) ? strerror(errno) : "file corrupt"); return ret; } diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 79978740..4498a750 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -872,7 +872,7 @@ static void do_work(struct connection *c) { assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); c->protocol->core->mainloop->defer_enable(c->defer_event, 0); - + if (c->dead) return; @@ -891,6 +891,7 @@ fail: if (c->state == ESD_STREAMING_DATA && c->sink_input) { c->dead = 1; pa_memblockq_prebuf_disable(c->input_memblockq); + c->protocol->core->mainloop->defer_enable(c->defer_event, 0); } else connection_free(c); } @@ -937,7 +938,9 @@ static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk /* do something */ assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + + if (!c->dead) + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); /* assert(pa_memblockq_get_length(c->input_memblockq) > 2048); */ } @@ -963,7 +966,9 @@ static void source_output_push_cb(struct pa_source_output *o, const struct pa_me /* do something */ assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + + if (!c->dead) + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); } static void source_output_kill_cb(struct pa_source_output *o) { diff --git a/polyp/util.c b/polyp/util.c index 6be6ffe4..166a9a45 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -501,3 +501,20 @@ finish: pa_xfree(gids); return r; } + +int pa_lock_file(int fd, int b) { + + struct flock flock; + + flock.l_type = b ? F_WRLCK : F_UNLCK; + flock.l_whence = SEEK_SET; + flock.l_start = 0; + flock.l_len = 0; + + if (fcntl(fd, F_SETLKW, &flock) < 0) { + pa_log(__FILE__": %slock failed: %s\n", !b ? "un" : "", strerror(errno)); + return -1; + } + + return 0; +} diff --git a/polyp/util.h b/polyp/util.h index 8f4323f6..571bb29b 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -68,4 +68,7 @@ int pa_parse_resample_method(const char *string); int pa_uid_in_group(const char *name, gid_t *gid); +int pa_lock_file(int fd, int b); + + #endif -- cgit From f014d466cd5f65b03a7a1608aa3d4cd83425a56e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 27 Sep 2004 17:21:27 +0000 Subject: really fix cpu usage when using esddsp with polypaudio git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@243 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/iochannel.c | 60 +++++++++++++++++++++---------------------------- polyp/iochannel.h | 3 --- polyp/protocol-esound.c | 36 ++++++++++++++++++++++------- 3 files changed, 54 insertions(+), 45 deletions(-) diff --git a/polyp/iochannel.c b/polyp/iochannel.c index 72bdac20..5e3e9360 100644 --- a/polyp/iochannel.c +++ b/polyp/iochannel.c @@ -52,7 +52,7 @@ struct pa_iochannel { static void enable_mainloop_sources(struct pa_iochannel *io) { assert(io); - if (io->input_event == io->output_event) { + if (io->input_event == io->output_event && io->input_event) { enum pa_io_event_flags f = PA_IO_EVENT_NULL; assert(io->input_event); @@ -78,18 +78,29 @@ static void callback(struct pa_mainloop_api* m, struct pa_io_event *e, int fd, e if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) { io->hungup = 1; changed = 1; - } - - if ((f & PA_IO_EVENT_INPUT) && !io->readable) { - io->readable = 1; - changed = 1; - assert(e == io->input_event); - } - - if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) { - io->writable = 1; - changed = 1; - assert(e == io->output_event); + + if (e == io->input_event) { + io->mainloop->io_free(io->input_event); + io->input_event = NULL; + } + + if (e == io->output_event) { + io->mainloop->io_free(io->output_event); + io->output_event = NULL; + } + } else { + + if ((f & PA_IO_EVENT_INPUT) && !io->readable) { + io->readable = 1; + changed = 1; + assert(e == io->input_event); + } + + if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) { + io->writable = 1; + changed = 1; + assert(e == io->output_event); + } } if (changed) { @@ -158,12 +169,12 @@ void pa_iochannel_free(struct pa_iochannel*io) { int pa_iochannel_is_readable(struct pa_iochannel*io) { assert(io); - return io->readable; + return io->readable || io->hungup; } int pa_iochannel_is_writable(struct pa_iochannel*io) { assert(io); - return io->writable; + return io->writable && !io->hungup; } int pa_iochannel_is_hungup(struct pa_iochannel*io) { @@ -173,16 +184,8 @@ int pa_iochannel_is_hungup(struct pa_iochannel*io) { ssize_t pa_iochannel_write(struct pa_iochannel*io, const void*data, size_t l) { ssize_t r; - assert(io); - assert(data); - assert(l); - assert(io->ofd >= 0); - - assert(io && data && l && io->ofd >= 0); - - if ((r = write(io->ofd, data, l)) >= 0) { io->writable = 0; enable_mainloop_sources(io); @@ -193,7 +196,6 @@ ssize_t pa_iochannel_write(struct pa_iochannel*io, const void*data, size_t l) { ssize_t pa_iochannel_read(struct pa_iochannel*io, void*data, size_t l) { ssize_t r; - assert(io && data && io->ifd >= 0); if ((r = read(io->ifd, data, l)) >= 0) { @@ -230,13 +232,3 @@ int pa_iochannel_socket_set_sndbuf(struct pa_iochannel *io, size_t l) { return pa_socket_set_sndbuf(io->ofd, l); } -void pa_iochannel_force_unreadable(struct pa_iochannel *io) { - assert(io); - io->readable = 0; - enable_mainloop_sources(io); -} - -void pa_iochannel_force_unwritable(struct pa_iochannel *io) { - io->writable = 0; - enable_mainloop_sources(io); -} diff --git a/polyp/iochannel.h b/polyp/iochannel.h index a4edbfad..6f5f351c 100644 --- a/polyp/iochannel.h +++ b/polyp/iochannel.h @@ -39,9 +39,6 @@ int pa_iochannel_is_readable(struct pa_iochannel*io); int pa_iochannel_is_writable(struct pa_iochannel*io); int pa_iochannel_is_hungup(struct pa_iochannel*io); -void pa_iochannel_force_unreadable(struct pa_iochannel *io); -void pa_iochannel_force_unwritable(struct pa_iochannel *io); - void pa_iochannel_set_noclose(struct pa_iochannel*io, int b); void pa_iochannel_set_callback(struct pa_iochannel*io, void (*callback)(struct pa_iochannel*io, void *userdata), void *userdata); diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 4498a750..b6caeb3d 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -193,8 +193,9 @@ static void connection_free(struct connection *c) { pa_xfree(c->read_data); pa_xfree(c->write_data); - - pa_iochannel_free(c->io); + + if (c->io) + pa_iochannel_free(c->io); if (c->defer_event) c->protocol->core->mainloop->defer_free(c->defer_event); @@ -680,6 +681,8 @@ static void client_kill_cb(struct pa_client *c) { static int do_read(struct connection *c) { assert(c && c->io); +/* pa_log("READ\n"); */ + if (c->state == ESD_NEXT_REQUEST) { ssize_t r; assert(c->read_data_length < sizeof(c->request)); @@ -702,7 +705,7 @@ static int do_read(struct connection *c) { handler = proto_map+c->request; - pa_log(__FILE__": executing request #%u\n", c->request); +/* pa_log(__FILE__": executing request #%u\n", c->request); */ if (!handler->proc) { pa_log(__FILE__": recieved unimplemented request #%u.\n", c->request); @@ -789,6 +792,8 @@ static int do_read(struct connection *c) { assert(c->input_memblockq); +/* pa_log("STREAMING_DATA\n"); */ + if (!(l = pa_memblockq_missing(c->input_memblockq))) return 0; @@ -812,6 +817,8 @@ static int do_read(struct connection *c) { pa_log(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } + +/* pa_log(__FILE__": read %u\n", r); */ chunk.memblock = c->playback.current_memblock; chunk.index = c->playback.memblock_index; @@ -832,6 +839,8 @@ static int do_read(struct connection *c) { static int do_write(struct connection *c) { assert(c && c->io); +/* pa_log("WRITE\n"); */ + if (c->write_data_length) { ssize_t r; @@ -872,18 +881,20 @@ static void do_work(struct connection *c) { assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); c->protocol->core->mainloop->defer_enable(c->defer_event, 0); + +/* pa_log("DOWORK\n"); */ - if (c->dead) + if (c->dead || !c->io) return; - + if (pa_iochannel_is_readable(c->io)) if (do_read(c) < 0) goto fail; - + if (pa_iochannel_is_writable(c->io)) if (do_write(c) < 0) goto fail; - + return; fail: @@ -891,7 +902,10 @@ fail: if (c->state == ESD_STREAMING_DATA && c->sink_input) { c->dead = 1; pa_memblockq_prebuf_disable(c->input_memblockq); - c->protocol->core->mainloop->defer_enable(c->defer_event, 0); + + pa_iochannel_free(c->io); + c->io = NULL; + } else connection_free(c); } @@ -900,6 +914,8 @@ static void io_callback(struct pa_iochannel*io, void *userdata) { struct connection *c = userdata; assert(io && c && c->io == io); +/* pa_log("IO\n"); */ + do_work(c); } @@ -909,6 +925,8 @@ static void defer_callback(struct pa_mainloop_api*a, struct pa_defer_event *e, v struct connection *c = userdata; assert(a && c && c->defer_event == e); +/* pa_log("DEFER\n"); */ + do_work(c); } @@ -934,6 +952,8 @@ static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk struct connection*c = i->userdata; assert(i && c && length); +/* pa_log("DROP\n"); */ + pa_memblockq_drop(c->input_memblockq, chunk, length); /* do something */ -- cgit From 450ad85b35bd600ed020f7ec119d51e7e7bc01a4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 27 Sep 2004 21:05:55 +0000 Subject: try to use file sample type for cache entries and play-file playback allow paplay to use STDIN add new module: module-match git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@244 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 - polyp/Makefile.am | 7 +- polyp/module-match.c | 217 ++++++++++++++++++++++++++++++++++++++++++++++ polyp/paplay.c | 26 +++--- polyp/scache.c | 9 +- polyp/sound-file-stream.c | 19 +++- polyp/sound-file.c | 25 ++++-- polyp/util.c | 7 ++ polyp/util.h | 2 + 9 files changed, 292 insertions(+), 22 deletions(-) create mode 100644 polyp/module-match.c diff --git a/doc/todo b/doc/todo index b5ae1446..eb8ebfb3 100644 --- a/doc/todo +++ b/doc/todo @@ -11,10 +11,8 @@ - pacat sample type args - filter capture data in client through alignment - add redirection module -- add matching module - add radio module - make autoload list use idxset -- improve file load to note force sample typ to PA_SAMPLE_FLOAT32 ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 2d14b420..d73c27bc 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -105,7 +105,8 @@ modlib_LTLIBRARIES= \ module-sine.la \ module-combine.la \ module-esound-compat-spawnfd.la \ - module-esound-compat-spawnpid.la + module-esound-compat-spawnpid.la \ + module-match.la lib_LTLIBRARIES= \ libpolyp-@PA_MAJORMINOR@.la \ @@ -305,6 +306,10 @@ module_combine_la_SOURCES = module-combine.c module_combine_la_LDFLAGS = -module -avoid-version module_combine_la_LIBADD = $(AM_LIBADD) +module_match_la_SOURCES = module-match.c +module_match_la_LDFLAGS = -module -avoid-version +module_match_la_LIBADD = $(AM_LIBADD) + module_esound_compat_spawnfd_la_SOURCES = module-esound-compat-spawnfd.c module_esound_compat_spawnfd_la_LDFLAGS = -module -avoid-version module_esound_compat_spawnfd_la_LIBADD = $(AM_LIBADD) diff --git a/polyp/module-match.c b/polyp/module-match.c new file mode 100644 index 00000000..964ff2fd --- /dev/null +++ b/polyp/module-match.c @@ -0,0 +1,217 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module.h" +#include "util.h" +#include "modargs.h" +#include "log.h" +#include "subscribe.h" +#include "xmalloc.h" +#include "sink-input.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Sink input matching module") +PA_MODULE_USAGE("table=") +PA_MODULE_VERSION(PACKAGE_VERSION) + +#define WHITESPACE "\n\r \t" + +static const char* const valid_modargs[] = { + "table", + NULL, +}; + +struct rule { + regex_t regex; + pa_volume_t volume; + struct rule *next; +}; + +struct userdata { + struct rule *rules; + struct pa_subscription *subscription; +}; + +static int load_rules(struct userdata *u, const char *filename) { + FILE *f; + int n = 0; + int ret = -1; + struct rule *end = NULL; + + if (!(f = fopen(filename, "r"))) { + pa_log(__FILE__": failed to open file '%s': %s\n", filename, strerror(errno)); + goto finish; + } + + while (!feof(f)) { + char *d, *v, *e = NULL; + pa_volume_t volume; + regex_t regex; + char ln[256]; + struct rule *rule; + + if (!fgets(ln, sizeof(ln), f)) + break; + + n++; + + pa_strip_nl(ln); + + if (ln[0] == '#' || !*ln ) + continue; + + d = ln+strcspn(ln, WHITESPACE); + v = d+strspn(d, WHITESPACE); + + + if (!*v) { + pa_log(__FILE__ ": [%s:%u] failed to parse line - too few words\n", filename, n); + goto finish; + } + + *d = 0; + + volume = (pa_volume_t) strtol(v, &e, 0); + + if (!e || *e) { + pa_log(__FILE__": [%s:%u] failed to parse volume\n", filename, n); + goto finish; + } + + if (regcomp(®ex, ln, REG_EXTENDED|REG_NOSUB) != 0) { + pa_log(__FILE__": [%s:%u] invalid regular expression\n", filename, n); + goto finish; + } + + rule = pa_xmalloc(sizeof(struct rule)); + rule->regex = regex; + rule->volume = volume; + rule->next = NULL; + + if (end) + end->next = rule; + else + u->rules = rule; + end = rule; + + *d = 0; + } + + ret = 0; + +finish: + if (f) + fclose(f); + + return ret; +} + +static void callback(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index, void *userdata) { + struct userdata *u = userdata; + struct pa_sink_input *si; + struct rule *r; + assert(c && u); + + if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW)) + return; + + if (!(si = pa_idxset_get_by_index(c->sink_inputs, index))) { + pa_log(__FILE__": WARNING: failed to get sink input\n"); + return; + } + + if (!si->name) + return; + + for (r = u->rules; r; r = r->next) { + if (!regexec(&r->regex, si->name, 0, NULL, 0)) { + pa_log(__FILE__": changing volume of sink input '%s' to 0x%03x\n", si->name, r->volume); + pa_sink_input_set_volume(si, r->volume); + } + } +} + +int pa__init(struct pa_core *c, struct pa_module*m) { + struct pa_modargs *ma = NULL; + int ret = -1; + const char *table_file; + struct userdata *u; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs)) || + !(table_file = pa_modargs_get_value(ma, "table", NULL))) { + pa_log(__FILE__": Failed to parse module arguments\n"); + goto finish; + } + + u = pa_xmalloc(sizeof(struct userdata)); + u->rules = NULL; + u->subscription = NULL; + + if (load_rules(u, table_file) < 0) + goto finish; + + u->subscription = pa_subscription_new(c, PA_SUBSCRIPTION_MASK_SINK_INPUT, callback, u); + + ret = 0; + +finish: + if (ma) + pa_modargs_free(ma); + + return ret; +} + +void pa__done(struct pa_core *c, struct pa_module*m) { + struct userdata* u; + struct rule *r, *n; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->subscription) + pa_subscription_free(u->subscription); + + for (r = u->rules; r; r = n) { + n = r->next; + + regfree(&r->regex); + pa_xfree(r); + } + + pa_xfree(u); +} + + diff --git a/polyp/paplay.c b/polyp/paplay.c index cc973a7d..89358a51 100644 --- a/polyp/paplay.c +++ b/polyp/paplay.c @@ -192,7 +192,7 @@ static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_even static void help(const char *argv0) { - printf("%s [options] FILE\n\n" + printf("%s [options] [FILE]\n\n" " -h, --help Show this help\n" " --version Show version\n\n" " -v, --verbose Enable verbose operations\n\n" @@ -213,7 +213,7 @@ enum { int main(int argc, char *argv[]) { struct pa_mainloop* m = NULL; int ret = 1, r, c; - char *bn, *server = NULL; + char *bn, *server = NULL, *filename; SF_INFO sfinfo; static const struct option long_options[] = { @@ -281,24 +281,28 @@ int main(int argc, char *argv[]) { } } - if (optind >= argc) { - fprintf(stderr, "Missing file name.\n"); - goto quit; - } + filename = optind < argc ? argv[optind] : "STDIN"; + + if (!client_name) client_name = strdup(bn); if (!stream_name) - stream_name = strdup(argv[optind]); + stream_name = strdup(filename); memset(&sfinfo, 0, sizeof(sfinfo)); - - if (!(sndfile = sf_open(argv[optind], SFM_READ, &sfinfo))) { - fprintf(stderr, "Faile to open file '%s'\n", argv[optind]); + + if (optind < argc) + sndfile = sf_open(filename, SFM_READ, &sfinfo); + else + sndfile = sf_open_fd(STDIN_FILENO, SFM_READ, &sfinfo, 0); + + if (!sndfile) { + fprintf(stderr, "Failed to open file '%s'\n", filename); goto quit; } - + sample_spec.rate = sfinfo.samplerate; sample_spec.channels = sfinfo.channels; diff --git a/polyp/scache.c b/polyp/scache.c index b17f3242..32977854 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -37,6 +37,7 @@ #include "subscribe.h" #include "namereg.h" #include "sound-file.h" +#include "util.h" #define UNLOAD_POLL_TIME 2 @@ -199,6 +200,7 @@ void pa_scache_free(struct pa_core *c) { int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sink, uint32_t volume) { struct pa_scache_entry *e; + char *t; assert(c && name && sink); if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1))) @@ -214,8 +216,13 @@ int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sin if (!e->memchunk.memblock) return -1; - if (pa_play_memchunk(sink, name, &e->sample_spec, &e->memchunk, pa_volume_multiply(volume, e->volume)) < 0) + t = pa_sprintf_malloc("sample:%s", name); + if (pa_play_memchunk(sink, t, &e->sample_spec, &e->memchunk, pa_volume_multiply(volume, e->volume)) < 0) { + free(t); return -1; + } + + free(t); if (e->lazy) time(&e->last_used_time); diff --git a/polyp/sound-file-stream.c b/polyp/sound-file-stream.c index b77d6d61..347d45a7 100644 --- a/polyp/sound-file-stream.c +++ b/polyp/sound-file-stream.c @@ -41,6 +41,7 @@ struct userdata { SNDFILE *sndfile; struct pa_sink_input *sink_input; struct pa_memchunk memchunk; + sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames); }; static void free_userdata(struct userdata *u) { @@ -78,7 +79,7 @@ static int sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { u->memchunk.memblock = pa_memblock_new(BUF_SIZE, i->sink->core->memblock_stat); u->memchunk.index = 0; - samples = sf_readf_float(u->sndfile, u->memchunk.memblock->data, samples); + samples = u->readf_function(u->sndfile, u->memchunk.memblock->data, samples); u->memchunk.length = samples*fs; if (!u->memchunk.length) { @@ -136,7 +137,21 @@ int pa_play_file(struct pa_sink *sink, const char *fname, pa_volume_t volume) { goto fail; } - ss.format = PA_SAMPLE_FLOAT32; + switch (sfinfo.format & 0xFF) { + case SF_FORMAT_PCM_16: + case SF_FORMAT_PCM_U8: + case SF_FORMAT_ULAW: + case SF_FORMAT_ALAW: + ss.format = PA_SAMPLE_S16NE; + u->readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_short; + break; + case SF_FORMAT_FLOAT: + default: + ss.format = PA_SAMPLE_FLOAT32NE; + u->readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_float; + break; + } + ss.rate = sfinfo.samplerate; ss.channels = sfinfo.channels; diff --git a/polyp/sound-file.c b/polyp/sound-file.c index d1f7e0f7..c63aa628 100644 --- a/polyp/sound-file.c +++ b/polyp/sound-file.c @@ -39,19 +39,34 @@ int pa_sound_file_load(const char *fname, struct pa_sample_spec *ss, struct pa_m SF_INFO sfinfo; int ret = -1; size_t l; + sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames); assert(fname && ss && chunk); - memset(&sfinfo, 0, sizeof(sfinfo)); - chunk->memblock = NULL; chunk->index = chunk->length = 0; - + + memset(&sfinfo, 0, sizeof(sfinfo)); + if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) { pa_log(__FILE__": Failed to open file %s\n", fname); goto finish; } - ss->format = PA_SAMPLE_FLOAT32; + switch (sfinfo.format & 0xFF) { + case SF_FORMAT_PCM_16: + case SF_FORMAT_PCM_U8: + case SF_FORMAT_ULAW: + case SF_FORMAT_ALAW: + ss->format = PA_SAMPLE_S16NE; + readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_short; + break; + case SF_FORMAT_FLOAT: + default: + ss->format = PA_SAMPLE_FLOAT32NE; + readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_float; + break; + } + ss->rate = sfinfo.samplerate; ss->channels = sfinfo.channels; @@ -70,7 +85,7 @@ int pa_sound_file_load(const char *fname, struct pa_sample_spec *ss, struct pa_m chunk->index = 0; chunk->length = l; - if (sf_readf_float(sf, chunk->memblock->data, sfinfo.frames) != sfinfo.frames) { + if (readf_function(sf, chunk->memblock->data, sfinfo.frames) != sfinfo.frames) { pa_log(__FILE__": Premature file end\n"); goto finish; } diff --git a/polyp/util.c b/polyp/util.c index 166a9a45..fa33ffff 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -518,3 +518,10 @@ int pa_lock_file(int fd, int b) { return 0; } + +char* pa_strip_nl(char *s) { + assert(s); + + s[strcspn(s, "\r\n")] = 0; + return s; +} diff --git a/polyp/util.h b/polyp/util.h index 571bb29b..e1910c83 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -62,6 +62,8 @@ int pa_parse_boolean(const char *s); char *pa_split(const char *c, const char*delimiters, const char **state); char *pa_split_spaces(const char *c, const char **state); +char *pa_strip_nl(char *s); + const char *pa_strsignal(int sig); int pa_parse_resample_method(const char *string); -- cgit From 6f59ae1763ee48f27448a7de9d635f61886052e1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 28 Sep 2004 22:47:48 +0000 Subject: Add module-tunnel add proper locking when autospawning a daemon git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@245 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 +- polyp/Makefile.am | 7 +- polyp/authkey.c | 20 +- polyp/module-match.c | 18 +- polyp/module-protocol-stub.c | 3 +- polyp/module-tunnel.c | 423 +++++++++++++++++++++++++++++++++++++++++++ polyp/native-common.h | 2 + polyp/polyplib-context.c | 52 ++---- polyp/polyplib-internal.h | 3 +- polyp/sink.h | 1 - polyp/socket-util.c | 33 ++++ polyp/socket-util.h | 2 + polyp/util.c | 43 ++++- polyp/util.h | 4 +- 14 files changed, 554 insertions(+), 59 deletions(-) create mode 100644 polyp/module-tunnel.c diff --git a/doc/todo b/doc/todo index eb8ebfb3..ad272ae4 100644 --- a/doc/todo +++ b/doc/todo @@ -7,12 +7,12 @@ - make mcalign merge chunks - option to use default fragment size on alsa drivers - improve module-oss-mmap latency measurement -- proper locking around native protocol socket - pacat sample type args - filter capture data in client through alignment - add redirection module - add radio module - make autoload list use idxset +- libwrap ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index d73c27bc..9f6fa1d5 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -106,7 +106,8 @@ modlib_LTLIBRARIES= \ module-combine.la \ module-esound-compat-spawnfd.la \ module-esound-compat-spawnpid.la \ - module-match.la + module-match.la \ + module-tunnel.la lib_LTLIBRARIES= \ libpolyp-@PA_MAJORMINOR@.la \ @@ -310,6 +311,10 @@ module_match_la_SOURCES = module-match.c module_match_la_LDFLAGS = -module -avoid-version module_match_la_LIBADD = $(AM_LIBADD) +module_tunnel_la_SOURCES = module-tunnel.c +module_tunnel_la_LDFLAGS = -module -avoid-version +module_tunnel_la_LIBADD = $(AM_LIBADD) libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la + module_esound_compat_spawnfd_la_SOURCES = module-esound-compat-spawnfd.c module_esound_compat_spawnfd_la_LDFLAGS = -module -avoid-version module_esound_compat_spawnfd_la_LIBADD = $(AM_LIBADD) diff --git a/polyp/authkey.c b/polyp/authkey.c index 1e2edb07..c8d8576b 100644 --- a/polyp/authkey.c +++ b/polyp/authkey.c @@ -97,7 +97,7 @@ static int load(const char *fn, void *data, size_t length) { writable = 0; } - unlock = pa_lock_file(fd, 1) >= 0; + unlock = pa_lock_fd(fd, 1) >= 0; if ((r = pa_loop_read(fd, data, length)) < 0) { pa_log(__FILE__": failed to read cookie file '%s'\n", fn); @@ -122,7 +122,7 @@ finish: if (fd >= 0) { if (unlock) - pa_lock_file(fd, 0); + pa_lock_fd(fd, 0); close(fd); } @@ -147,15 +147,19 @@ int pa_authkey_load(const char *path, void *data, size_t length) { int pa_authkey_load_from_home(const char *fn, void *data, size_t length) { char *home; char path[PATH_MAX]; + char *p; assert(fn && data && length); - - if (!(home = getenv("HOME"))) - return -2; - - snprintf(path, sizeof(path), "%s/%s", home, fn); - return pa_authkey_load(path, data, length); + if (fn[0] != '/') { + if (!(home = getenv("HOME"))) + return -2; + + snprintf(p = path, sizeof(path), "%s/%s", home, fn); + } else + p = fn; + + return pa_authkey_load(p, data, length); } int pa_authkey_load_auto(const char *fn, void *data, size_t length) { diff --git a/polyp/module-match.c b/polyp/module-match.c index 964ff2fd..380c6011 100644 --- a/polyp/module-match.c +++ b/polyp/module-match.c @@ -164,7 +164,6 @@ static void callback(struct pa_core *c, enum pa_subscription_event_type t, uint3 int pa__init(struct pa_core *c, struct pa_module*m) { struct pa_modargs *ma = NULL; - int ret = -1; const char *table_file; struct userdata *u; assert(c && m); @@ -172,25 +171,28 @@ int pa__init(struct pa_core *c, struct pa_module*m) { if (!(ma = pa_modargs_new(m->argument, valid_modargs)) || !(table_file = pa_modargs_get_value(ma, "table", NULL))) { pa_log(__FILE__": Failed to parse module arguments\n"); - goto finish; + goto fail; } u = pa_xmalloc(sizeof(struct userdata)); u->rules = NULL; u->subscription = NULL; + m->userdata = u; if (load_rules(u, table_file) < 0) - goto finish; + goto fail; u->subscription = pa_subscription_new(c, PA_SUBSCRIPTION_MASK_SINK_INPUT, callback, u); - - ret = 0; -finish: + pa_modargs_free(ma); + return 0; + +fail: + pa__done(c, m); + if (ma) pa_modargs_free(ma); - - return ret; + return -1; } void pa__done(struct pa_core *c, struct pa_module*m) { diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index 17c491de..fc1e9fd9 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -37,6 +37,7 @@ #include "util.h" #include "modargs.h" #include "log.h" +#include "native-common.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_VERSION(PACKAGE_VERSION) @@ -72,7 +73,7 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #include "protocol-native.h" #define protocol_new pa_protocol_native_new #define protocol_free pa_protocol_native_free - #define IPV4_PORT 4713 + #define IPV4_PORT PA_NATIVE_DEFAULT_PORT #define UNIX_SOCKET "/tmp/polypaudio/native" #define MODULE_ARGUMENTS "public", "cookie", PA_MODULE_DESCRIPTION("Native protocol "SOCKET_DESCRIPTION) diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c new file mode 100644 index 00000000..0c78b138 --- /dev/null +++ b/polyp/module-tunnel.c @@ -0,0 +1,423 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module.h" +#include "util.h" +#include "modargs.h" +#include "log.h" +#include "subscribe.h" +#include "xmalloc.h" +#include "sink-input.h" +#include "pdispatch.h" +#include "pstream.h" +#include "pstream-util.h" +#include "authkey.h" +#include "socket-client.h" +#include "socket-util.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Tunnel module") +PA_MODULE_USAGE("server= sink= cookie= format= channels= rate= sink_name=") +PA_MODULE_VERSION(PACKAGE_VERSION) + +#define DEFAULT_SINK_NAME "tunnel" + +#define DEFAULT_TLENGTH (10240*8) +#define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2) +#define DEFAULT_PREBUF DEFAULT_TLENGTH +#define DEFAULT_MINREQ 512 +#define DEFAULT_FRAGSIZE 1024 + +#define DEFAULT_TIMEOUT 5 + +static const char* const valid_modargs[] = { + "server", + "sink", + "cookie", + "format", + "channels", + "rate", + "sink_name", + NULL, +}; + +static void command_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); + +static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_REQUEST] = { command_request }, + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_stream_killed }, + [PA_COMMAND_RECORD_STREAM_KILLED] = { command_stream_killed }, +}; + +struct userdata { + struct pa_socket_client *client; + struct pa_pstream *pstream; + struct pa_pdispatch *pdispatch; + + char *server_name, *sink_name; + + struct pa_sink *sink; + struct pa_module *module; + struct pa_core *core; + + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; + + uint32_t ctag; + uint32_t device_index; + uint32_t requested_bytes; + uint32_t channel; +}; + + +static void close_stuff(struct userdata *u) { + if (u->pstream) { + pa_pstream_close(u->pstream); + pa_pstream_unref(u->pstream); + u->pstream = NULL; + } + + if (u->pdispatch) { + pa_pdispatch_unref(u->pdispatch); + u->pdispatch = NULL; + } + + if (u->client) { + pa_socket_client_unref(u->client); + u->client = NULL; + } + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + u->sink = NULL; + } +} + +static void die(struct userdata *u) { + assert(u); + close_stuff(u); + pa_module_unload_request(u->module); +} + +static void request_bytes(struct userdata *u) { + assert(u); + + if (!u->pstream) + return; + + while (u->requested_bytes > 0) { + struct pa_memchunk chunk; + if (pa_sink_render(u->sink, u->requested_bytes, &chunk) < 0) + return; + + pa_pstream_send_memblock(u->pstream, u->channel, 0, &chunk); + pa_memblock_unref(chunk.memblock); + + if (chunk.length > u->requested_bytes) + u->requested_bytes = 0; + else + u->requested_bytes -= chunk.length; + } +} + +static void command_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + assert(pd && t && u && u->pdispatch == pd); + + pa_log(__FILE__": stream killed\n"); + die(u); +} + +static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + uint32_t bytes, channel; + assert(pd && command == PA_COMMAND_REQUEST && t && u && u->pdispatch == pd); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + pa_tagstruct_getu32(t, &bytes) < 0 || + !pa_tagstruct_eof(t)) { + pa_log(__FILE__": invalid protocol reply\n"); + die(u); + return; + } + + if (channel != u->channel) { + pa_log(__FILE__": recieved data for invalid channel\n"); + die(u); + return; + } + + u->requested_bytes += bytes; + request_bytes(u); +} + + +static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + assert(pd && u && u->pdispatch == pd); + + if (command != PA_COMMAND_REPLY) { + if (command == PA_COMMAND_ERROR) + pa_log(__FILE__": failed to create stream.\n"); + else + pa_log(__FILE__": protocol error.\n"); + die(u); + return; + } + + if (pa_tagstruct_getu32(t, &u->channel) < 0 || + pa_tagstruct_getu32(t, &u->device_index) < 0 || + pa_tagstruct_getu32(t, &u->requested_bytes) < 0 || + !pa_tagstruct_eof(t)) { + pa_log(__FILE__": invalid reply.\n"); + die(u); + return; + } + + request_bytes(u); +} + +static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + struct pa_tagstruct *reply; + char name[256], un[128], hn[128]; + assert(pd && u && u->pdispatch == pd); + + if (command != PA_COMMAND_REPLY || !pa_tagstruct_eof(t)) { + if (command == PA_COMMAND_ERROR) + pa_log(__FILE__": failed to authenticate\n"); + else + pa_log(__FILE__": protocol error.\n"); + die(u); + return; + } + + snprintf(name, sizeof(name), "Tunnel from host '%s', user '%s', sink '%s'", + pa_get_host_name(hn, sizeof(hn)), + pa_get_user_name(un, sizeof(un)), + u->sink->name); + + reply = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME); + pa_tagstruct_putu32(reply, tag = u->ctag++); + pa_tagstruct_puts(reply, name); + pa_pstream_send_tagstruct(u->pstream, reply); + /* We ignore the server's reply here */ + + reply = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_PLAYBACK_STREAM); + pa_tagstruct_putu32(reply, tag = u->ctag++); + pa_tagstruct_puts(reply, name); + pa_tagstruct_put_sample_spec(reply, &u->sink->sample_spec); + pa_tagstruct_putu32(reply, PA_INVALID_INDEX); + pa_tagstruct_puts(reply, u->sink_name); + pa_tagstruct_putu32(reply, DEFAULT_MAXLENGTH); + pa_tagstruct_put_boolean(reply, 0); + pa_tagstruct_putu32(reply, DEFAULT_TLENGTH); + pa_tagstruct_putu32(reply, DEFAULT_PREBUF); + pa_tagstruct_putu32(reply, DEFAULT_MINREQ); + pa_tagstruct_putu32(reply, PA_VOLUME_NORM); + + pa_pstream_send_tagstruct(u->pstream, reply); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, u); +} + +static void pstream_die_callback(struct pa_pstream *p, void *userdata) { + struct userdata *u = userdata; + assert(p && u); + + pa_log(__FILE__": stream died.\n"); + die(u); +} + + +static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { + struct userdata *u = userdata; + assert(p && packet && u); + + if (pa_pdispatch_run(u->pdispatch, packet, u) < 0) { + pa_log(__FILE__": invalid packet\n"); + die(u); + } +} + +static void on_connection(struct pa_socket_client *sc, struct pa_iochannel *io, void *userdata) { + struct userdata *u = userdata; + struct pa_tagstruct *t; + uint32_t tag; + assert(sc && io && u && u->client == sc); + + pa_socket_client_unref(u->client); + u->client = NULL; + + if (!io) { + pa_log(__FILE__": connection failed.\n"); + pa_module_unload_request(u->module); + return; + } + + u->pstream = pa_pstream_new(u->core->mainloop, io, u->core->memblock_stat); + u->pdispatch = pa_pdispatch_new(u->core->mainloop, command_table, PA_COMMAND_MAX); + + pa_pstream_set_die_callback(u->pstream, pstream_die_callback, u); + pa_pstream_set_recieve_packet_callback(u->pstream, pstream_packet_callback, u); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_AUTH); + pa_tagstruct_putu32(t, tag = u->ctag++); + pa_tagstruct_put_arbitrary(t, u->auth_cookie, sizeof(u->auth_cookie)); + pa_pstream_send_tagstruct(u->pstream, t); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, u); + +} + +static void sink_notify(struct pa_sink*sink) { + struct userdata *u; + assert(sink && sink->userdata); + u = sink->userdata; + + request_bytes(u); +} + +static pa_usec_t sink_get_latency(struct pa_sink *sink) { + struct userdata *u; + assert(sink && sink->userdata); + u = sink->userdata; + + return 0; +} + +int pa__init(struct pa_core *c, struct pa_module*m) { + struct pa_modargs *ma = NULL; + struct userdata *u = NULL; + struct pa_sample_spec ss; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments\n"); + + } + + u = pa_xmalloc(sizeof(struct userdata)); + m->userdata = u; + u->module = m; + u->core = c; + u->client = NULL; + u->pdispatch = NULL; + u->pstream = NULL; + u->server_name = u->sink_name = NULL; + u->sink = NULL; + u->ctag = 1; + u->device_index = u->channel = PA_INVALID_INDEX; + u->requested_bytes = 0; + + if (pa_authkey_load_from_home(pa_modargs_get_value(ma, "cookie", PA_NATIVE_COOKIE_FILE), u->auth_cookie, sizeof(u->auth_cookie)) < 0) { + pa_log(__FILE__": failed to load cookie.\n"); + goto fail; + } + + if (!(u->server_name = pa_xstrdup(pa_modargs_get_value(ma, "server", NULL)))) { + pa_log(__FILE__": no server specified.\n"); + goto fail; + } + + u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": invalid sample format specification\n"); + goto fail; + } + + if (u->server_name[0] == '/') + u->client = pa_socket_client_new_unix(c->mainloop, u->server_name); + else { + size_t len; + struct sockaddr *sa; + + if (!(sa = pa_resolve_server(u->server_name, &len, PA_NATIVE_DEFAULT_PORT))) { + pa_log(__FILE__": failed to resolve server '%s'\n", u->server_name); + goto fail; + } + + u->client = pa_socket_client_new_sockaddr(c->mainloop, sa, len); + pa_xfree(sa); + } + + if (!u->client) + goto fail; + + pa_socket_client_set_callback(u->client, on_connection, u); + + if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { + pa_log(__FILE__": failed to create sink.\n"); + goto fail; + } + + u->sink->notify = sink_notify; + u->sink->get_latency = sink_get_latency; + u->sink->userdata = u; + u->sink->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->sink_name ? u->sink_name : "", u->sink_name ? "@" : "", u->server_name); + + pa_sink_set_owner(u->sink, m); + + pa_modargs_free(ma); + + return 0; + +fail: + pa__done(c, m); + + if (ma) + pa_modargs_free(ma); + return -1; +} + +void pa__done(struct pa_core *c, struct pa_module*m) { + struct userdata* u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + close_stuff(u); + + pa_xfree(u->sink_name); + pa_xfree(u->server_name); + + pa_xfree(u); +} + + diff --git a/polyp/native-common.h b/polyp/native-common.h index 5ecb26c0..33ecdc76 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -96,6 +96,8 @@ enum { #define PA_NATIVE_COOKIE_LENGTH 256 #define PA_NATIVE_COOKIE_FILE ".polypaudio-cookie" +#define PA_NATIVE_DEFAULT_PORT 4713 + PA_C_DECL_END #endif diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index d793c186..d2fae0af 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -48,8 +48,10 @@ #include "xmalloc.h" #include "log.h" #include "client-conf.h" +#include "socket-util.h" #define DEFAULT_SERVER "/tmp/polypaudio/native" +#define AUTOSPAWN_LOCK "/tmp/polypaudio/autospawn.lock" static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_REQUEST] = { pa_command_request }, @@ -347,38 +349,6 @@ finish: pa_context_unref(c); } -static struct sockaddr *resolve_server(const char *server, size_t *len) { - struct sockaddr *sa; - struct addrinfo hints, *result = NULL; - char *port, host[256]; - assert(server && len); - - snprintf(host, sizeof(host), "%s", server); - host[strcspn(host, ":")] = 0; - - if ((port = strrchr(server, ':'))) - port++; - - if (!port) - port = DEFAULT_PORT; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(host, port, &hints, &result) != 0) - return NULL; - assert(result); - - sa = pa_xmalloc(*len = result->ai_addrlen); - memcpy(sa, result->ai_addr, *len); - - freeaddrinfo(result); - - return sa; -} - static int default_server_is_running(void) { struct stat st; @@ -499,9 +469,21 @@ int pa_context_connect(struct pa_context *c, const char *server, int spawn, cons if (!server) server = c->conf->default_server; - if (!server && spawn && c->conf->autospawn && !default_server_is_running()) - return context_connect_spawn(c, api); + if (!server && spawn && c->conf->autospawn) { + int lock_fd = pa_lock_lockfile(AUTOSPAWN_LOCK); + + if (!default_server_is_running()) { + int r = context_connect_spawn(c, api); + + if (lock_fd >= 0) + pa_unlock_lockfile(lock_fd); + return r; + } + if (lock_fd >= 0) + pa_unlock_lockfile(lock_fd); + } + if (!server) server = DEFAULT_SERVER; @@ -520,7 +502,7 @@ int pa_context_connect(struct pa_context *c, const char *server, int spawn, cons struct sockaddr* sa; size_t sa_len; - if (!(sa = resolve_server(server, &sa_len))) { + if (!(sa = pa_resolve_server(server, &sa_len, PA_NATIVE_DEFAULT_PORT))) { pa_context_fail(c, PA_ERROR_INVALIDSERVER); goto finish; } diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 656d07db..c10ca515 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -41,8 +41,7 @@ #define DEFAULT_MINREQ 512 #define DEFAULT_FRAGSIZE 1024 -#define DEFAULT_TIMEOUT (5*60) -#define DEFAULT_PORT "4713" +#define DEFAULT_TIMEOUT (10) #define ENV_AUTOSPAWNED "POLYP_AUTOSPAWNED" diff --git a/polyp/sink.h b/polyp/sink.h index b34a736c..a2d34ee5 100644 --- a/polyp/sink.h +++ b/polyp/sink.h @@ -64,7 +64,6 @@ void pa_sink_disconnect(struct pa_sink* s); void pa_sink_unref(struct pa_sink*s); struct pa_sink* pa_sink_ref(struct pa_sink *s); - int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result); void pa_sink_render_full(struct pa_sink *s, size_t length, struct pa_memchunk *result); int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target); diff --git a/polyp/socket-util.c b/polyp/socket-util.c index 20380653..499739bd 100644 --- a/polyp/socket-util.c +++ b/polyp/socket-util.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "socket-util.h" #include "util.h" @@ -219,3 +220,35 @@ finish: return ret; } +struct sockaddr *pa_resolve_server(const char *server, size_t *len, uint16_t nport) { + struct sockaddr *sa; + struct addrinfo hints, *result = NULL; + char *port, host[256], tmp[16]; + assert(server && len); + + snprintf(host, sizeof(host), "%s", server); + host[strcspn(host, ":")] = 0; + + if ((port = strrchr(server, ':'))) + port++; + + if (!port) + snprintf(port = tmp, sizeof(tmp), "%u", nport); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + if (getaddrinfo(host, port, &hints, &result) != 0) + return NULL; + assert(result); + + sa = pa_xmalloc(*len = result->ai_addrlen); + memcpy(sa, result->ai_addr, *len); + + freeaddrinfo(result); + + return sa; +} + diff --git a/polyp/socket-util.h b/polyp/socket-util.h index 85133feb..46fcfdc9 100644 --- a/polyp/socket-util.h +++ b/polyp/socket-util.h @@ -38,4 +38,6 @@ int pa_unix_socket_remove_stale(const char *fn); int pa_unix_socket_make_secure_dir(const char *fn); int pa_unix_socket_remove_secure_dir(const char *fn); +struct sockaddr *pa_resolve_server(const char *server, size_t *len, uint16_t port); + #endif diff --git a/polyp/util.c b/polyp/util.c index fa33ffff..70ec120d 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -502,7 +502,7 @@ finish: return r; } -int pa_lock_file(int fd, int b) { +int pa_lock_fd(int fd, int b) { struct flock flock; @@ -525,3 +525,44 @@ char* pa_strip_nl(char *s) { s[strcspn(s, "\r\n")] = 0; return s; } + +int pa_lock_lockfile(const char *fn) { + int fd; + assert(fn); + + if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { + pa_log(__FILE__": failed to create lock file '%s'\n", fn); + goto fail; + } + + if (pa_lock_fd(fd, 1) < 0) + goto fail; + + return fd; + +fail: + + if (fd >= 0) + close(fd); + + return -1; +} + + +int pa_unlock_lockfile(int fd) { + int r = 0; + assert(fd >= 0); + + if (pa_lock_fd(fd, 0) < 0) { + pa_log(__FILE__": WARNING: failed to unlock file.\n"); + r = -1; + } + + if (close(fd) < 0) { + pa_log(__FILE__": WARNING: failed to close lock file.\n"); + r = -1; + } + + return r; +} + diff --git a/polyp/util.h b/polyp/util.h index e1910c83..b0a1a033 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -70,7 +70,9 @@ int pa_parse_resample_method(const char *string); int pa_uid_in_group(const char *name, gid_t *gid); -int pa_lock_file(int fd, int b); +int pa_lock_fd(int fd, int b); +int pa_lock_lockfile(const char *fn); +int pa_unlock_lockfile(int fd); #endif -- cgit From 33c85aec01f625b4d62eabb5f0e88d5a5ae3d17f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 28 Sep 2004 23:49:54 +0000 Subject: add latency measurement support to tunnel module git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@246 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 +- polyp/module-tunnel.c | 137 ++++++++++++++++++++++++++++++++++++++++++---- polyp/polyplib-internal.h | 4 +- 3 files changed, 130 insertions(+), 13 deletions(-) diff --git a/doc/todo b/doc/todo index ad272ae4..439eb770 100644 --- a/doc/todo +++ b/doc/todo @@ -9,7 +9,7 @@ - improve module-oss-mmap latency measurement - pacat sample type args - filter capture data in client through alignment -- add redirection module +- add tunnel module for sources - add radio module - make autoload list use idxset - libwrap diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c index 0c78b138..03029921 100644 --- a/polyp/module-tunnel.c +++ b/polyp/module-tunnel.c @@ -53,14 +53,16 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define DEFAULT_SINK_NAME "tunnel" -#define DEFAULT_TLENGTH (10240*8) +#define DEFAULT_TLENGTH (44100*2*2/10) //(10240*8) #define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2) -#define DEFAULT_PREBUF DEFAULT_TLENGTH #define DEFAULT_MINREQ 512 +#define DEFAULT_PREBUF (DEFAULT_TLENGTH-DEFAULT_MINREQ) #define DEFAULT_FRAGSIZE 1024 #define DEFAULT_TIMEOUT 5 +#define LATENCY_INTERVAL 10 + static const char* const valid_modargs[] = { "server", "sink", @@ -98,6 +100,10 @@ struct userdata { uint32_t device_index; uint32_t requested_bytes; uint32_t channel; + + pa_usec_t host_latency; + + struct pa_time_event *time_event; }; @@ -123,6 +129,11 @@ static void close_stuff(struct userdata *u) { pa_sink_unref(u->sink); u->sink = NULL; } + + if (u->time_event) { + u->core->mainloop->time_free(u->time_event); + u->time_event = NULL; + } } static void die(struct userdata *u) { @@ -131,16 +142,32 @@ static void die(struct userdata *u) { pa_module_unload_request(u->module); } -static void request_bytes(struct userdata *u) { +static void send_prebuf_request(struct userdata *u) { + struct pa_tagstruct *t; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_PREBUF_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, u->ctag++); + pa_tagstruct_putu32(t, u->channel); + pa_pstream_send_tagstruct(u->pstream, t); +} + +static void send_bytes(struct userdata *u) { assert(u); if (!u->pstream) return; - + while (u->requested_bytes > 0) { struct pa_memchunk chunk; - if (pa_sink_render(u->sink, u->requested_bytes, &chunk) < 0) + if (pa_sink_render(u->sink, u->requested_bytes, &chunk) < 0) { + + + if (u->requested_bytes >= DEFAULT_TLENGTH-DEFAULT_PREBUF) + send_prebuf_request(u); + return; + } pa_pstream_send_memblock(u->pstream, u->channel, 0, &chunk); pa_memblock_unref(chunk.memblock); @@ -180,9 +207,69 @@ static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t } u->requested_bytes += bytes; - request_bytes(u); + send_bytes(u); +} + +static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + pa_usec_t buffer_usec, sink_usec, source_usec, transport_usec; + int playing; + uint32_t queue_length; + struct timeval local, remote, now; + assert(pd && u && t); + + if (command != PA_COMMAND_REPLY) { + if (command == PA_COMMAND_ERROR) + pa_log(__FILE__": failed to get latency.\n"); + else + pa_log(__FILE__": protocol error.\n"); + die(u); + return; + } + + if (pa_tagstruct_get_usec(t, &buffer_usec) < 0 || + pa_tagstruct_get_usec(t, &sink_usec) < 0 || + pa_tagstruct_get_usec(t, &source_usec) < 0 || + pa_tagstruct_get_boolean(t, &playing) < 0 || + pa_tagstruct_getu32(t, &queue_length) < 0 || + pa_tagstruct_get_timeval(t, &local) < 0 || + pa_tagstruct_get_timeval(t, &remote) < 0 || + !pa_tagstruct_eof(t)) { + pa_log(__FILE__": invalid reply.\n"); + die(u); + return; + } + + gettimeofday(&now, NULL); + + if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) + /* local and remote seem to have synchronized clocks */ + transport_usec = pa_timeval_diff(&remote, &local); + else + transport_usec = pa_timeval_diff(&now, &local)/2; + + u->host_latency = sink_usec + transport_usec; + +/* pa_log(__FILE__": estimated host latency: %0.0f usec\n", (double) u->host_latency); */ } +static void request_latency(struct userdata *u) { + struct pa_tagstruct *t; + struct timeval now; + uint32_t tag; + assert(u); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); + pa_tagstruct_putu32(t, tag = u->ctag++); + pa_tagstruct_putu32(t, u->channel); + + gettimeofday(&now, NULL); + pa_tagstruct_put_timeval(t, &now); + + pa_pstream_send_tagstruct(u->pstream, t); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u); +} static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; @@ -206,7 +293,8 @@ static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, ui return; } - request_bytes(u); + request_latency(u); + send_bytes(u); } static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { @@ -308,26 +396,50 @@ static void sink_notify(struct pa_sink*sink) { assert(sink && sink->userdata); u = sink->userdata; - request_bytes(u); + send_bytes(u); } static pa_usec_t sink_get_latency(struct pa_sink *sink) { struct userdata *u; + uint32_t l; + pa_usec_t usec = 0; assert(sink && sink->userdata); u = sink->userdata; - return 0; + l = DEFAULT_TLENGTH; + + if (l > u->requested_bytes) { + l -= u->requested_bytes; + usec += pa_bytes_to_usec(l, &u->sink->sample_spec); + } + + usec += u->host_latency; + + return usec; +} + +static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, const struct timeval *tv, void *userdata) { + struct userdata *u = userdata; + struct timeval ntv; + assert(m && e && u); + + request_latency(u); + + gettimeofday(&ntv, NULL); + ntv.tv_sec += LATENCY_INTERVAL; + m->time_restart(e, &ntv); } int pa__init(struct pa_core *c, struct pa_module*m) { struct pa_modargs *ma = NULL; struct userdata *u = NULL; struct pa_sample_spec ss; + struct timeval ntv; assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": failed to parse module arguments\n"); - + goto fail; } u = pa_xmalloc(sizeof(struct userdata)); @@ -342,6 +454,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { u->ctag = 1; u->device_index = u->channel = PA_INVALID_INDEX; u->requested_bytes = 0; + u->host_latency = 0; if (pa_authkey_load_from_home(pa_modargs_get_value(ma, "cookie", PA_NATIVE_COOKIE_FILE), u->auth_cookie, sizeof(u->auth_cookie)) < 0) { pa_log(__FILE__": failed to load cookie.\n"); @@ -391,6 +504,10 @@ int pa__init(struct pa_core *c, struct pa_module*m) { u->sink->userdata = u; u->sink->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->sink_name ? u->sink_name : "", u->sink_name ? "@" : "", u->server_name); + gettimeofday(&ntv, NULL); + ntv.tv_sec += LATENCY_INTERVAL; + u->time_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, u); + pa_sink_set_owner(u->sink, m); pa_modargs_free(ma); diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index c10ca515..58c617e4 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -35,10 +35,10 @@ #include "native-common.h" #include "client-conf.h" -#define DEFAULT_TLENGTH (10240*8) +#define DEFAULT_TLENGTH (44100*2*2/10) //(10240*8) #define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2) -#define DEFAULT_PREBUF DEFAULT_TLENGTH #define DEFAULT_MINREQ 512 +#define DEFAULT_PREBUF (DEFAULT_TLENGTH-DEFAULT_MINREQ) #define DEFAULT_FRAGSIZE 1024 #define DEFAULT_TIMEOUT (10) -- cgit From d8f700e5395610a83a944502fc82f7cd24f22614 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 28 Sep 2004 23:52:50 +0000 Subject: fix module-tunnel for to aborting when connection fails git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@247 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-tunnel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c index 03029921..a151b52a 100644 --- a/polyp/module-tunnel.c +++ b/polyp/module-tunnel.c @@ -365,7 +365,7 @@ static void on_connection(struct pa_socket_client *sc, struct pa_iochannel *io, struct userdata *u = userdata; struct pa_tagstruct *t; uint32_t tag; - assert(sc && io && u && u->client == sc); + assert(sc && u && u->client == sc); pa_socket_client_unref(u->client); u->client = NULL; -- cgit From 6dfab4ec7b8d8702d425b2ec9b5f1aff5c8290cd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 29 Sep 2004 17:38:45 +0000 Subject: renamed module-tunnel to module-tunnel-sink new module module-tunnel-source fix recording git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@248 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 14 ++-- polyp/module-tunnel.c | 173 ++++++++++++++++++++++++++++++++++++++++-------- polyp/protocol-native.c | 4 ++ polyp/source.c | 4 +- polyp/source.h | 2 +- 5 files changed, 164 insertions(+), 33 deletions(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 9f6fa1d5..29b388c9 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -107,7 +107,8 @@ modlib_LTLIBRARIES= \ module-esound-compat-spawnfd.la \ module-esound-compat-spawnpid.la \ module-match.la \ - module-tunnel.la + module-tunnel-sink.la \ + module-tunnel-source.la lib_LTLIBRARIES= \ libpolyp-@PA_MAJORMINOR@.la \ @@ -311,9 +312,14 @@ module_match_la_SOURCES = module-match.c module_match_la_LDFLAGS = -module -avoid-version module_match_la_LIBADD = $(AM_LIBADD) -module_tunnel_la_SOURCES = module-tunnel.c -module_tunnel_la_LDFLAGS = -module -avoid-version -module_tunnel_la_LIBADD = $(AM_LIBADD) libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la +module_tunnel_sink_la_SOURCES = module-tunnel.c +module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS) +module_tunnel_sink_la_LDFLAGS = -module -avoid-version +module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la + +module_tunnel_source_la_SOURCES = module-tunnel.c +module_tunnel_source_la_LDFLAGS = -module -avoid-version +module_tunnel_source_la_LIBADD = $(AM_LIBADD) libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la module_esound_compat_spawnfd_la_SOURCES = module-esound-compat-spawnfd.c module_esound_compat_spawnfd_la_LDFLAGS = -module -avoid-version diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c index a151b52a..1a720f3b 100644 --- a/polyp/module-tunnel.c +++ b/polyp/module-tunnel.c @@ -47,11 +47,18 @@ #include "socket-util.h" PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Tunnel module") -PA_MODULE_USAGE("server= sink= cookie= format= channels= rate= sink_name=") PA_MODULE_VERSION(PACKAGE_VERSION) +#ifdef TUNNEL_SINK +PA_MODULE_DESCRIPTION("Tunnel module for sinks") +PA_MODULE_USAGE("server= sink= cookie= format= channels= rate= sink_name=") +#else +PA_MODULE_DESCRIPTION("Tunnel module for sources") +PA_MODULE_USAGE("server= source= cookie= format= channels= rate= source_name=") +#endif + #define DEFAULT_SINK_NAME "tunnel" +#define DEFAULT_SOURCE_NAME "tunnel" #define DEFAULT_TLENGTH (44100*2*2/10) //(10240*8) #define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2) @@ -65,20 +72,30 @@ PA_MODULE_VERSION(PACKAGE_VERSION) static const char* const valid_modargs[] = { "server", - "sink", "cookie", "format", "channels", "rate", +#ifdef TUNNEL_SINK "sink_name", + "sink", +#else + "source_name", + "source", +#endif NULL, }; static void command_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); + +#ifdef TUNNEL_SINK static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +#endif static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { +#ifdef TUNNEL_SINK [PA_COMMAND_REQUEST] = { command_request }, +#endif [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_stream_killed }, [PA_COMMAND_RECORD_STREAM_KILLED] = { command_stream_killed }, }; @@ -88,9 +105,16 @@ struct userdata { struct pa_pstream *pstream; struct pa_pdispatch *pdispatch; - char *server_name, *sink_name; - + char *server_name; +#ifdef TUNNEL_SINK + char *sink_name; struct pa_sink *sink; + uint32_t requested_bytes; +#else + char *source_name; + struct pa_source *source; +#endif + struct pa_module *module; struct pa_core *core; @@ -98,9 +122,8 @@ struct userdata { uint32_t ctag; uint32_t device_index; - uint32_t requested_bytes; uint32_t channel; - + pa_usec_t host_latency; struct pa_time_event *time_event; @@ -124,11 +147,19 @@ static void close_stuff(struct userdata *u) { u->client = NULL; } +#ifdef TUNNEL_SINK if (u->sink) { pa_sink_disconnect(u->sink); pa_sink_unref(u->sink); u->sink = NULL; } +#else + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + u->source = NULL; + } +#endif if (u->time_event) { u->core->mainloop->time_free(u->time_event); @@ -142,6 +173,15 @@ static void die(struct userdata *u) { pa_module_unload_request(u->module); } +static void command_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + assert(pd && t && u && u->pdispatch == pd); + + pa_log(__FILE__": stream killed\n"); + die(u); +} + +#ifdef TUNNEL_SINK static void send_prebuf_request(struct userdata *u) { struct pa_tagstruct *t; @@ -179,14 +219,6 @@ static void send_bytes(struct userdata *u) { } } -static void command_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct userdata *u = userdata; - assert(pd && t && u && u->pdispatch == pd); - - pa_log(__FILE__": stream killed\n"); - die(u); -} - static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; uint32_t bytes, channel; @@ -210,6 +242,8 @@ static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t send_bytes(u); } +#endif + static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; pa_usec_t buffer_usec, sink_usec, source_usec, transport_usec; @@ -242,13 +276,25 @@ static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t comman gettimeofday(&now, NULL); - if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) + if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) { /* local and remote seem to have synchronized clocks */ +#ifdef TUNNEL_SINK transport_usec = pa_timeval_diff(&remote, &local); - else +#else + transport_usec = pa_timeval_diff(&now, &remote); +#endif + } else transport_usec = pa_timeval_diff(&now, &local)/2; - + +#ifdef TUNNEL_SINK u->host_latency = sink_usec + transport_usec; +#else + u->host_latency = source_usec + transport_usec; + if (u->host_latency > sink_usec) + u->host_latency -= sink_usec; + else + u->host_latency = 0; +#endif /* pa_log(__FILE__": estimated host latency: %0.0f usec\n", (double) u->host_latency); */ } @@ -260,7 +306,11 @@ static void request_latency(struct userdata *u) { assert(u); t = pa_tagstruct_new(NULL, 0); +#ifdef TUNNEL_SINK pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); +#else + pa_tagstruct_putu32(t, PA_COMMAND_GET_RECORD_LATENCY); +#endif pa_tagstruct_putu32(t, tag = u->ctag++); pa_tagstruct_putu32(t, u->channel); @@ -286,7 +336,9 @@ static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, ui if (pa_tagstruct_getu32(t, &u->channel) < 0 || pa_tagstruct_getu32(t, &u->device_index) < 0 || +#ifdef TUNNEL_SINK pa_tagstruct_getu32(t, &u->requested_bytes) < 0 || +#endif !pa_tagstruct_eof(t)) { pa_log(__FILE__": invalid reply.\n"); die(u); @@ -294,7 +346,9 @@ static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, ui } request_latency(u); +#ifdef TUNNEL_SINK send_bytes(u); +#endif } static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { @@ -311,11 +365,17 @@ static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, u die(u); return; } - +#ifdef TUNNEL_SINK snprintf(name, sizeof(name), "Tunnel from host '%s', user '%s', sink '%s'", pa_get_host_name(hn, sizeof(hn)), pa_get_user_name(un, sizeof(un)), u->sink->name); +#else + snprintf(name, sizeof(name), "Tunnel from host '%s', user '%s', source '%s'", + pa_get_host_name(hn, sizeof(hn)), + pa_get_user_name(un, sizeof(un)), + u->source->name); +#endif reply = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME); @@ -325,6 +385,7 @@ static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, u /* We ignore the server's reply here */ reply = pa_tagstruct_new(NULL, 0); +#ifdef TUNNEL_SINK pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_PLAYBACK_STREAM); pa_tagstruct_putu32(reply, tag = u->ctag++); pa_tagstruct_puts(reply, name); @@ -337,6 +398,17 @@ static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, u pa_tagstruct_putu32(reply, DEFAULT_PREBUF); pa_tagstruct_putu32(reply, DEFAULT_MINREQ); pa_tagstruct_putu32(reply, PA_VOLUME_NORM); +#else + pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_RECORD_STREAM); + pa_tagstruct_putu32(reply, tag = u->ctag++); + pa_tagstruct_puts(reply, name); + pa_tagstruct_put_sample_spec(reply, &u->source->sample_spec); + pa_tagstruct_putu32(reply, PA_INVALID_INDEX); + pa_tagstruct_puts(reply, u->source_name); + pa_tagstruct_putu32(reply, DEFAULT_MAXLENGTH); + pa_tagstruct_put_boolean(reply, 0); + pa_tagstruct_putu32(reply, DEFAULT_FRAGSIZE); +#endif pa_pstream_send_tagstruct(u->pstream, reply); pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, u); @@ -361,6 +433,21 @@ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *pack } } +#ifndef TUNNEL_SINK +static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk, void *userdata) { + struct userdata *u = userdata; + assert(p && chunk && u); + + if (channel != u->channel) { + pa_log(__FILE__": recieved memory block on bad channel.\n"); + die(u); + return; + } + + pa_source_post(u->source, chunk); +} +#endif + static void on_connection(struct pa_socket_client *sc, struct pa_iochannel *io, void *userdata) { struct userdata *u = userdata; struct pa_tagstruct *t; @@ -381,6 +468,9 @@ static void on_connection(struct pa_socket_client *sc, struct pa_iochannel *io, pa_pstream_set_die_callback(u->pstream, pstream_die_callback, u); pa_pstream_set_recieve_packet_callback(u->pstream, pstream_packet_callback, u); +#ifndef TUNNEL_SINK + pa_pstream_set_recieve_memblock_callback(u->pstream, pstream_memblock_callback, u); +#endif t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_AUTH); @@ -391,6 +481,7 @@ static void on_connection(struct pa_socket_client *sc, struct pa_iochannel *io, } +#ifdef TUNNEL_SINK static void sink_notify(struct pa_sink*sink) { struct userdata *u; assert(sink && sink->userdata); @@ -417,6 +508,15 @@ static pa_usec_t sink_get_latency(struct pa_sink *sink) { return usec; } +#else +static pa_usec_t source_get_latency(struct pa_source *source) { + struct userdata *u; + assert(source && source->userdata); + u = source->userdata; + + return u->host_latency; +} +#endif static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, const struct timeval *tv, void *userdata) { struct userdata *u = userdata; @@ -449,11 +549,17 @@ int pa__init(struct pa_core *c, struct pa_module*m) { u->client = NULL; u->pdispatch = NULL; u->pstream = NULL; - u->server_name = u->sink_name = NULL; + u->server_name = NULL; +#ifdef TUNNEL_SINK + u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));; u->sink = NULL; + u->requested_bytes = 0; +#else + u->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));; + u->source = NULL; +#endif u->ctag = 1; u->device_index = u->channel = PA_INVALID_INDEX; - u->requested_bytes = 0; u->host_latency = 0; if (pa_authkey_load_from_home(pa_modargs_get_value(ma, "cookie", PA_NATIVE_COOKIE_FILE), u->auth_cookie, sizeof(u->auth_cookie)) < 0) { @@ -466,8 +572,6 @@ int pa__init(struct pa_core *c, struct pa_module*m) { goto fail; } - u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); - ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { pa_log(__FILE__": invalid sample format specification\n"); @@ -493,7 +597,8 @@ int pa__init(struct pa_core *c, struct pa_module*m) { goto fail; pa_socket_client_set_callback(u->client, on_connection, u); - + +#ifdef TUNNEL_SINK if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { pa_log(__FILE__": failed to create sink.\n"); goto fail; @@ -504,12 +609,24 @@ int pa__init(struct pa_core *c, struct pa_module*m) { u->sink->userdata = u; u->sink->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->sink_name ? u->sink_name : "", u->sink_name ? "@" : "", u->server_name); + pa_sink_set_owner(u->sink, m); +#else + if (!(u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss))) { + pa_log(__FILE__": failed to create source.\n"); + goto fail; + } + + u->source->get_latency = source_get_latency; + u->source->userdata = u; + u->source->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->source_name ? u->source_name : "", u->source_name ? "@" : "", u->server_name); + + pa_source_set_owner(u->source, m); +#endif + gettimeofday(&ntv, NULL); ntv.tv_sec += LATENCY_INTERVAL; u->time_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, u); - pa_sink_set_owner(u->sink, m); - pa_modargs_free(ma); return 0; @@ -531,7 +648,11 @@ void pa__done(struct pa_core *c, struct pa_module*m) { close_stuff(u); +#ifdef TUNNEL_SINK pa_xfree(u->sink_name); +#else + pa_xfree(u->source_name); +#endif pa_xfree(u->server_name); pa_xfree(u); diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index aeccd504..3b816419 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -656,6 +656,7 @@ static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t comma struct pa_sample_spec ss; struct pa_tagstruct *reply; struct pa_source *source; + int corked; assert(c && t && c->protocol && c->protocol->core); if (pa_tagstruct_gets(t, &name) < 0 || !name || @@ -663,6 +664,7 @@ static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t comma pa_tagstruct_getu32(t, &source_index) < 0 || pa_tagstruct_gets(t, &source_name) < 0 || pa_tagstruct_getu32(t, &maxlength) < 0 || + pa_tagstruct_get_boolean(t, &corked) < 0 || pa_tagstruct_getu32(t, &fragment_size) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -688,6 +690,8 @@ static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t comma pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); return; } + + pa_source_output_cork(s->source_output, corked); reply = pa_tagstruct_new(NULL, 0); assert(reply); diff --git a/polyp/source.c b/polyp/source.c index 23b8bf8a..7df432d5 100644 --- a/polyp/source.c +++ b/polyp/source.c @@ -131,7 +131,7 @@ void pa_source_notify(struct pa_source*s) { } static int do_post(void *p, uint32_t index, int *del, void*userdata) { - struct pa_memchunk *chunk = userdata; + const struct pa_memchunk *chunk = userdata; struct pa_source_output *o = p; assert(o && o->push && del && chunk); @@ -139,7 +139,7 @@ static int do_post(void *p, uint32_t index, int *del, void*userdata) { return 0; } -void pa_source_post(struct pa_source*s, struct pa_memchunk *chunk) { +void pa_source_post(struct pa_source*s, const struct pa_memchunk *chunk) { assert(s && s->ref >= 1 && chunk); pa_source_ref(s); diff --git a/polyp/source.h b/polyp/source.h index cda9e698..3cac2ad1 100644 --- a/polyp/source.h +++ b/polyp/source.h @@ -63,7 +63,7 @@ void pa_source_unref(struct pa_source *s); struct pa_source* pa_source_ref(struct pa_source *c); /* Pass a new memory block to all output streams */ -void pa_source_post(struct pa_source*s, struct pa_memchunk *b); +void pa_source_post(struct pa_source*s, const struct pa_memchunk *b); void pa_source_notify(struct pa_source *s); -- cgit From d09240118ce0170c2fc5f504589646746902eb96 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 29 Sep 2004 19:13:55 +0000 Subject: really fix API version API git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@249 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 ++ doc/todo | 1 - polyp/pacat.c | 7 ++++--- polyp/pactl.c | 2 +- polyp/paplay.c | 2 +- polyp/polyplib-context.c | 9 +++++---- polyp/polyplib-version.h.in | 10 ++++++++++ 7 files changed, 23 insertions(+), 10 deletions(-) diff --git a/configure.ac b/configure.ac index 3a0675c3..af766847 100644 --- a/configure.ac +++ b/configure.ac @@ -28,6 +28,8 @@ AM_INIT_AUTOMAKE([foreign -Wall]) AC_SUBST(PA_MAJORMINOR, "$PACKAGE_VERSION") AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/polypaudio/]) +AC_SUBST(PA_API_VERSION, 6) + if type -p stow > /dev/null && test -d /usr/local/stow ; then AC_MSG_NOTICE([*** Found /usr/local/stow: default install prefix set to /usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION} ***]) ac_default_prefix="/usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION}" diff --git a/doc/todo b/doc/todo index 439eb770..bef5b82a 100644 --- a/doc/todo +++ b/doc/todo @@ -9,7 +9,6 @@ - improve module-oss-mmap latency measurement - pacat sample type args - filter capture data in client through alignment -- add tunnel module for sources - add radio module - make autoload list use idxset - libwrap diff --git a/polyp/pacat.c b/polyp/pacat.c index 1eb37d4d..67242b26 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -36,8 +36,9 @@ #include #include #include +#include -#if PA_API_VERSION != PA_API_VERSION_0_6 +#if PA_API_VERSION != 6 #error Invalid Polypaudio API version #endif @@ -107,7 +108,7 @@ static void stream_read_callback(struct pa_stream *s, const void*data, size_t le mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT); if (buffer) { - fprintf(stderr, "Buffer overrrun, dropping incoming data\n"); + fprintf(stderr, "Buffer overrun, dropping incoming data\n"); return; } @@ -133,7 +134,7 @@ static void stream_state_callback(struct pa_stream *s, void *userdata) { case PA_STREAM_FAILED: default: - fprintf(stderr, "Stream errror: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + fprintf(stderr, "Stream error: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); quit(1); } } diff --git a/polyp/pactl.c b/polyp/pactl.c index cf2f51c3..fbedc6fa 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -41,7 +41,7 @@ #include #include -#if PA_API_VERSION != PA_API_VERSION_0_6 +#if PA_API_VERSION != 6 #error Invalid Polypaudio API version #endif diff --git a/polyp/paplay.c b/polyp/paplay.c index 89358a51..cc466e12 100644 --- a/polyp/paplay.c +++ b/polyp/paplay.c @@ -40,7 +40,7 @@ #include #include -#if PA_API_VERSION != PA_API_VERSION_0_6 +#if PA_API_VERSION != 6 #error Invalid Polypaudio API version #endif diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index d2fae0af..b736daa7 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -676,10 +676,6 @@ struct pa_operation* pa_context_send_simple_command(struct pa_context *c, uint32 return pa_operation_ref(o); } -const char* pa_get_library_version(void) { - return PACKAGE_VERSION; -} - struct pa_operation* pa_context_set_default_sink(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata) { struct pa_tagstruct *t; struct pa_operation *o; @@ -744,3 +740,8 @@ struct pa_operation* pa_context_set_name(struct pa_context *c, const char *name, return pa_operation_ref(o); } + +const char* pa_get_library_version(void) { + return PACKAGE_VERSION; +} + diff --git a/polyp/polyplib-version.h.in b/polyp/polyplib-version.h.in index b44dc008..75798693 100644 --- a/polyp/polyplib-version.h.in +++ b/polyp/polyplib-version.h.in @@ -22,6 +22,8 @@ USA. ***/ +/* WARNING: Make sure to edit the real source file polyplib-version.h.in! */ + /** \file * Define header version */ @@ -30,4 +32,12 @@ a macro and not a function, so it is impossible to get the pointer of it. */ #define pa_get_headers_version() ("@PACKAGE_VERSION@") +/** Return the version of the library the current application is linked to. */ +const char* pa_get_library_version(void); + +/** The current API version. Version 6 relates to polypaudio + * 0.6. Prior versions (i.e. Polypaudio 0.5.1 and older) have + * PA_API_VERSION undefined. */ +#define PA_API_VERSION @PA_API_VERSION@ + #endif -- cgit From 66999e5adaf54256718c638c3ad53acb0d74937b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 29 Sep 2004 20:13:05 +0000 Subject: Add support for libwrap git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@250 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 19 +++++++++++++++++++ doc/todo | 1 - polyp/Makefile.am | 2 +- polyp/authkey.c | 5 +++-- polyp/main.c | 11 +++++++++++ polyp/module-protocol-stub.c | 7 +++++-- polyp/socket-server.c | 31 +++++++++++++++++++++++++++++-- polyp/socket-server.h | 2 +- polyp/source.c | 2 +- 9 files changed, 70 insertions(+), 10 deletions(-) diff --git a/configure.ac b/configure.ac index af766847..68df5b85 100644 --- a/configure.ac +++ b/configure.ac @@ -111,6 +111,25 @@ AC_SUBST(GLIB12_LIBS) AC_SUBST(HAVE_GLIB12) AM_CONDITIONAL([HAVE_GLIB12], [test "x$HAVE_GLIB12" = x1]) +AC_MSG_CHECKING([for tcpwrap library and headers]) +LIBWRAP_LIBS= +saved_LIBS="$LIBS" +LIBS="$LIBS -lwrap" +AC_LINK_IFELSE( +AC_LANG_PROGRAM( +[#include +#include +int allow_severity = LOG_INFO; +int deny_severity = LOG_WARNING;], +[struct request_info *req; +return hosts_access (req);]), +[AC_DEFINE(HAVE_LIBWRAP, [], [Have tcpwrap?]) +LIBWRAP_LIBS="-lwrap" +AC_MSG_RESULT(yes)], +[AC_MSG_RESULT(no)]) +AC_SUBST(LIBWRAP_LIBS) +LIBS="$saved_LIBS" + # If using GCC specify some additional parameters if test "x$GCC" = "xyes" ; then CFLAGS="$CFLAGS -pipe -W -Wall -pedantic" diff --git a/doc/todo b/doc/todo index bef5b82a..668f54d2 100644 --- a/doc/todo +++ b/doc/todo @@ -11,7 +11,6 @@ - filter capture data in client through alignment - add radio module - make autoload list use idxset -- libwrap ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 29b388c9..94d3373c 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -178,7 +178,7 @@ libprotocol_simple_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libsocket_server_la_SOURCES = socket-server.c socket-server.h libsocket_server_la_LDFLAGS = -avoid-version -libsocket_server_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la +libsocket_server_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la $(LIBWRAP_LIBS) libsocket_client_la_SOURCES = socket-client.c socket-client.h libsocket_client_la_LDFLAGS = -avoid-version diff --git a/polyp/authkey.c b/polyp/authkey.c index c8d8576b..09a2c1b4 100644 --- a/polyp/authkey.c +++ b/polyp/authkey.c @@ -147,7 +147,7 @@ int pa_authkey_load(const char *path, void *data, size_t length) { int pa_authkey_load_from_home(const char *fn, void *data, size_t length) { char *home; char path[PATH_MAX]; - char *p; + const char *p; assert(fn && data && length); @@ -155,7 +155,8 @@ int pa_authkey_load_from_home(const char *fn, void *data, size_t length) { if (!(home = getenv("HOME"))) return -2; - snprintf(p = path, sizeof(path), "%s/%s", home, fn); + snprintf(path, sizeof(path), "%s/%s", home, fn); + p = path; } else p = fn; diff --git a/polyp/main.c b/polyp/main.c index 0837e58d..25fb1741 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -34,6 +34,11 @@ #include #include +#ifdef HAVE_LIBWRAP +#include +#include +#endif + #include "core.h" #include "mainloop.h" #include "module.h" @@ -50,6 +55,12 @@ #include "caps.h" #include "cli-text.h" +#ifdef HAVE_LIBWRAP +/* Only one instance of these variables */ +int allow_severity = LOG_INFO; +int deny_severity = LOG_WARNING; +#endif + static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { pa_log(__FILE__": Got signal %s.\n", pa_strsignal(sig)); diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index fc1e9fd9..1ff70a1a 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -54,16 +54,17 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #include "protocol-simple.h" #define protocol_new pa_protocol_simple_new #define protocol_free pa_protocol_simple_free + #define TCPWRAP_SERVICE "polypaudio-simple" #define IPV4_PORT 4711 #define UNIX_SOCKET "/tmp/polypaudio/simple" #define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record", PA_MODULE_DESCRIPTION("Simple protocol "SOCKET_DESCRIPTION) PA_MODULE_USAGE("rate= format= channels= sink= source= playback= record= "SOCKET_USAGE) - #elif defined(USE_PROTOCOL_CLI) #include "protocol-cli.h" #define protocol_new pa_protocol_cli_new #define protocol_free pa_protocol_cli_free + #define TCPWRAP_SERVICE "polypaudio-cli" #define IPV4_PORT 4712 #define UNIX_SOCKET "/tmp/polypaudio/cli" #define MODULE_ARGUMENTS @@ -73,6 +74,7 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #include "protocol-native.h" #define protocol_new pa_protocol_native_new #define protocol_free pa_protocol_native_free + #define TCPWRAP_SERVICE "polypaudio-native" #define IPV4_PORT PA_NATIVE_DEFAULT_PORT #define UNIX_SOCKET "/tmp/polypaudio/native" #define MODULE_ARGUMENTS "public", "cookie", @@ -83,6 +85,7 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #include "esound.h" #define protocol_new pa_protocol_esound_new #define protocol_free pa_protocol_esound_free + #define TCPWRAP_SERVICE "esound" #define IPV4_PORT ESD_DEFAULT_PORT #define UNIX_SOCKET ESD_UNIX_SOCKET_NAME #define MODULE_ARGUMENTS "sink", "source", "public", "cookie", @@ -119,7 +122,7 @@ static struct pa_socket_server *create_socket_server(struct pa_core *c, struct p return NULL; } - if (!(s = pa_socket_server_new_ipv4(c->mainloop, loopback ? INADDR_LOOPBACK : INADDR_ANY, port))) + if (!(s = pa_socket_server_new_ipv4(c->mainloop, loopback ? INADDR_LOOPBACK : INADDR_ANY, port, TCPWRAP_SERVICE))) return NULL; #else int r; diff --git a/polyp/socket-server.c b/polyp/socket-server.c index 9f943dc0..c170bf6e 100644 --- a/polyp/socket-server.c +++ b/polyp/socket-server.c @@ -35,6 +35,10 @@ #include #include +#ifdef HAVE_LIBWRAP +#include +#endif + #include "socket-server.h" #include "socket-util.h" #include "xmalloc.h" @@ -45,6 +49,7 @@ struct pa_socket_server { int ref; int fd; char *filename; + char *tcpwrap_service; void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata); void *userdata; @@ -74,6 +79,23 @@ static void callback(struct pa_mainloop_api *mainloop, struct pa_io_event *e, in goto finish; } +#ifdef HAVE_LIBWRAP + + if (s->type == SOCKET_SERVER_IPV4 && s->tcpwrap_service) { + struct request_info req; + + request_init(&req, RQ_DAEMON, s->tcpwrap_service, RQ_FILE, nfd, NULL); + fromhost(&req); + if (!hosts_access(&req)) { + pa_log(__FILE__": TCP connection refused by tcpwrap.\n"); + close(nfd); + goto finish; + } + + pa_log(__FILE__": TCP connection accepted by tcpwrap.\n"); + } +#endif + /* There should be a check for socket type here */ if (s->type == SOCKET_SERVER_IPV4) pa_socket_tcp_low_delay(fd); @@ -98,6 +120,7 @@ struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd) s->filename = NULL; s->on_connection = NULL; s->userdata = NULL; + s->tcpwrap_service = NULL; s->mainloop = m; s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s); @@ -159,7 +182,7 @@ fail: return NULL; } -struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port) { +struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service) { struct pa_socket_server *ss; int fd = -1; struct sockaddr_in sa; @@ -193,8 +216,10 @@ struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, ui goto fail; } - if ((ss = pa_socket_server_new(m, fd))) + if ((ss = pa_socket_server_new(m, fd))) { ss->type = SOCKET_SERVER_IPV4; + ss->tcpwrap_service = pa_xstrdup(tcpwrap_service); + } return ss; @@ -214,6 +239,8 @@ static void socket_server_free(struct pa_socket_server*s) { pa_xfree(s->filename); } + pa_xfree(s->tcpwrap_service); + s->mainloop->io_free(s->io_event); pa_xfree(s); } diff --git a/polyp/socket-server.h b/polyp/socket-server.h index c9d9193d..f5877e55 100644 --- a/polyp/socket-server.h +++ b/polyp/socket-server.h @@ -32,7 +32,7 @@ struct pa_socket_server; struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd); struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename); -struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port); +struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service); void pa_socket_server_unref(struct pa_socket_server*s); struct pa_socket_server* pa_socket_server_ref(struct pa_socket_server *s); diff --git a/polyp/source.c b/polyp/source.c index 7df432d5..73645d49 100644 --- a/polyp/source.c +++ b/polyp/source.c @@ -143,7 +143,7 @@ void pa_source_post(struct pa_source*s, const struct pa_memchunk *chunk) { assert(s && s->ref >= 1 && chunk); pa_source_ref(s); - pa_idxset_foreach(s->outputs, do_post, chunk); + pa_idxset_foreach(s->outputs, do_post, (void*) chunk); pa_source_unref(s); } -- cgit From 68d50dc0a6cf6886d0d6e01447bf15f3411c739f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 29 Sep 2004 22:04:44 +0000 Subject: add sample spec parameters to pacat git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@251 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - polyp/modargs.c | 23 ++--------------------- polyp/pacat.c | 53 ++++++++++++++++++++++++++++++++++++++++++----------- polyp/sample.c | 29 +++++++++++++++++++++++++++-- polyp/sample.h | 6 +++++- 5 files changed, 76 insertions(+), 36 deletions(-) diff --git a/doc/todo b/doc/todo index 668f54d2..e2cb2fe6 100644 --- a/doc/todo +++ b/doc/todo @@ -7,7 +7,6 @@ - make mcalign merge chunks - option to use default fragment size on alsa drivers - improve module-oss-mmap latency measurement -- pacat sample type args - filter capture data in client through alignment - add radio module - make autoload list use idxset diff --git a/polyp/modargs.c b/polyp/modargs.c index e1c2c9b8..d58b391b 100644 --- a/polyp/modargs.c +++ b/polyp/modargs.c @@ -263,28 +263,9 @@ int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *rss return -1; ss.channels = (uint8_t) channels; - if ((format = pa_modargs_get_value(ma, "format", NULL))) { - if (strcmp(format, "s16le") == 0) - ss.format = PA_SAMPLE_S16LE; - else if (strcmp(format, "s16be") == 0) - ss.format = PA_SAMPLE_S16BE; - else if (strcmp(format, "s16ne") == 0 || strcmp(format, "s16") == 0 || strcmp(format, "16") == 0) - ss.format = PA_SAMPLE_S16NE; - else if (strcmp(format, "u8") == 0 || strcmp(format, "8") == 0) - ss.format = PA_SAMPLE_U8; - else if (strcmp(format, "float32") == 0 || strcmp(format, "float32ne") == 0) - ss.format = PA_SAMPLE_FLOAT32; - else if (strcmp(format, "float32le") == 0) - ss.format = PA_SAMPLE_FLOAT32LE; - else if (strcmp(format, "float32be") == 0) - ss.format = PA_SAMPLE_FLOAT32BE; - else if (strcmp(format, "ulaw") == 0) - ss.format = PA_SAMPLE_ULAW; - else if (strcmp(format, "alaw") == 0) - ss.format = PA_SAMPLE_ALAW; - else + if ((format = pa_modargs_get_value(ma, "format", NULL))) + if ((ss.format = pa_parse_sample_format(format)) < 0) return -1; - } if (!pa_sample_spec_valid(&ss)) return -1; diff --git a/polyp/pacat.c b/polyp/pacat.c index 67242b26..a2687116 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -58,6 +58,12 @@ static char *stream_name = NULL, *client_name = NULL, *device = NULL; static int verbose = 0; static pa_volume_t volume = PA_VOLUME_NORM; +static struct pa_sample_spec sample_spec = { + .format = PA_SAMPLE_S16LE, + .rate = 44100, + .channels = 2 +}; + /* A shortcut for terminating the application */ static void quit(int ret) { assert(mainloop_api); @@ -141,12 +147,6 @@ static void stream_state_callback(struct pa_stream *s, void *userdata) { /* This is called whenever the context status changes */ static void context_state_callback(struct pa_context *c, void *userdata) { - static const struct pa_sample_spec ss = { - .format = PA_SAMPLE_S16LE, - .rate = 44100, - .channels = 2 - }; - assert(c); switch (pa_context_get_state(c)) { @@ -162,7 +162,7 @@ static void context_state_callback(struct pa_context *c, void *userdata) { if (verbose) fprintf(stderr, "Connection established.\n"); - stream = pa_stream_new(c, stream_name, &ss); + stream = pa_stream_new(c, stream_name, &sample_spec); assert(stream); pa_stream_set_state_callback(stream, stream_state_callback, NULL); @@ -335,14 +335,22 @@ static void help(const char *argv0) { " -d, --device=DEVICE The name of the sink/source to connect to\n" " -n, --client-name=NAME How to call this client on the server\n" " --stream-name=NAME How to call this stream on the server\n" - " --volume=VOLUME Specify the initial (linear) volume in range 0...256\n", + " --volume=VOLUME Specify the initial (linear) volume in range 0...256\n" + " --rate=SAMPLERATE The sample rate in Hz (defaults to 44100)\n" + " --format=SAMPLEFORMAT The sample type, one of s16le, s16be, u8, float32le,\n" + " float32be, ulaw, alaw (defaults to s16ne)\n" + " --channels=CHANNELS The number of channels, 1 for mono, 2 for stereo\n" + " (defaults to 2)\n", argv0); } enum { ARG_VERSION = 256, ARG_STREAM_NAME, - ARG_VOLUME + ARG_VOLUME, + ARG_SAMPLERATE, + ARG_SAMPLEFORMAT, + ARG_CHANNELS }; int main(int argc, char *argv[]) { @@ -361,6 +369,9 @@ int main(int argc, char *argv[]) { {"help", 0, NULL, 'h'}, {"verbose", 0, NULL, 'v'}, {"volume", 1, NULL, ARG_VOLUME}, + {"rate", 1, NULL, ARG_SAMPLERATE}, + {"format", 1, NULL, ARG_SAMPLEFORMAT}, + {"channels", 1, NULL, ARG_CHANNELS}, {NULL, 0, NULL, 0} }; @@ -425,6 +436,18 @@ int main(int argc, char *argv[]) { break; } + case ARG_CHANNELS: + sample_spec.channels = atoi(optarg); + break; + + case ARG_SAMPLEFORMAT: + sample_spec.format = pa_parse_sample_format(optarg); + break; + + case ARG_SAMPLERATE: + sample_spec.rate = atoi(optarg); + break; + default: goto quit; } @@ -435,9 +458,17 @@ int main(int argc, char *argv[]) { if (!stream_name) stream_name = strdup(client_name); + + if (!pa_sample_spec_valid(&sample_spec)) { + fprintf(stderr, "Invalid sample specification\n"); + goto quit; + } - if (verbose) - fprintf(stderr, "Opening a %s stream.\n", mode == RECORD ? "recording" : "playback"); + if (verbose) { + char t[PA_SAMPLE_SPEC_SNPRINT_MAX]; + pa_sample_spec_snprint(t, sizeof(t), &sample_spec); + fprintf(stderr, "Opening a %s stream with sample specification '%s'.\n", mode == RECORD ? "recording" : "playback", t); + } /* Set up a new main loop */ if (!(m = pa_mainloop_new())) { diff --git a/polyp/sample.c b/polyp/sample.c index 65ae8ff3..8c30386b 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "sample.h" @@ -68,10 +69,10 @@ pa_usec_t pa_bytes_to_usec(uint64_t length, const struct pa_sample_spec *spec) { int pa_sample_spec_valid(const struct pa_sample_spec *spec) { assert(spec); - if (!spec->rate || !spec->channels) + if (spec->rate <= 0 || spec->channels <= 0) return 0; - if (spec->format >= PA_SAMPLE_MAX) + if (spec->format >= PA_SAMPLE_MAX || spec->format < 0) return 0; return 1; @@ -134,3 +135,27 @@ void pa_bytes_snprint(char *s, size_t l, unsigned v) { else snprintf(s, l, "%u B", (unsigned) v); } + +enum pa_sample_format pa_parse_sample_format(const char *format) { + + if (strcmp(format, "s16le") == 0) + return PA_SAMPLE_S16LE; + else if (strcmp(format, "s16be") == 0) + return PA_SAMPLE_S16BE; + else if (strcmp(format, "s16ne") == 0 || strcmp(format, "s16") == 0 || strcmp(format, "16") == 0) + return PA_SAMPLE_S16NE; + else if (strcmp(format, "u8") == 0 || strcmp(format, "8") == 0) + return PA_SAMPLE_U8; + else if (strcmp(format, "float32") == 0 || strcmp(format, "float32ne") == 0) + return PA_SAMPLE_FLOAT32; + else if (strcmp(format, "float32le") == 0) + return PA_SAMPLE_FLOAT32LE; + else if (strcmp(format, "float32be") == 0) + return PA_SAMPLE_FLOAT32BE; + else if (strcmp(format, "ulaw") == 0) + return PA_SAMPLE_ULAW; + else if (strcmp(format, "alaw") == 0) + return PA_SAMPLE_ALAW; + + return -1; +} diff --git a/polyp/sample.h b/polyp/sample.h index 912cdaa0..7e810386 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -42,7 +42,8 @@ enum pa_sample_format { PA_SAMPLE_S16BE, /**< Signed 16 Bit PCM, big endian */ PA_SAMPLE_FLOAT32LE, /**< 32 Bit IEEE floating point, little endian, range -1..1 */ PA_SAMPLE_FLOAT32BE, /**< 32 Bit IEEE floating point, big endian, range -1..1 */ - PA_SAMPLE_MAX /**< Upper limit of valid sample types */ + PA_SAMPLE_MAX, /**< Upper limit of valid sample types */ + PA_SAMPLE_INVALID = -1 /**< An invalid value */ }; #ifdef WORDS_BIGENDIAN @@ -119,6 +120,9 @@ double pa_volume_to_dB(pa_volume_t v); /** Pretty print a byte size value. (i.e. "2.5 MB") */ void pa_bytes_snprint(char *s, size_t l, unsigned v); +/** Parse a sample format text */ +enum pa_sample_format pa_parse_sample_format(const char *format); + PA_C_DECL_END #endif -- cgit From fde3d1333738c807ef5e43161565590b1f715077 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 1 Oct 2004 12:48:09 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@252 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/todo b/doc/todo index e2cb2fe6..4526adab 100644 --- a/doc/todo +++ b/doc/todo @@ -10,6 +10,7 @@ - filter capture data in client through alignment - add radio module - make autoload list use idxset +- enlarge mqmblockq sizes ** later *** - xmlrpc/http -- cgit From 6ede161cb94f5123e103fae45ea1918bbebb4956 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 11 Oct 2004 16:21:12 +0000 Subject: enlarge default buffers git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@253 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/polyplib-internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 58c617e4..8a7bf6fb 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -35,7 +35,7 @@ #include "native-common.h" #include "client-conf.h" -#define DEFAULT_TLENGTH (44100*2*2/10) //(10240*8) +#define DEFAULT_TLENGTH (44100*2*2/2) //(10240*8) #define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2) #define DEFAULT_MINREQ 512 #define DEFAULT_PREBUF (DEFAULT_TLENGTH-DEFAULT_MINREQ) -- cgit From a6471e26022a7eada70dd128c51f0fa593718c5d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 12 Oct 2004 21:52:50 +0000 Subject: gcc 2.95 fix default.pa fix git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@254 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/authkey.c | 2 +- polyp/default.pa.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/polyp/authkey.c b/polyp/authkey.c index 09a2c1b4..d3cb382b 100644 --- a/polyp/authkey.c +++ b/polyp/authkey.c @@ -85,9 +85,9 @@ finish: static int load(const char *fn, void *data, size_t length) { int fd = -1; int writable = 1; - assert(fn && data && length); int unlock = 0, ret; ssize_t r; + assert(fn && data && length); if ((fd = open(fn, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { if (errno != EACCES || (fd = open(fn, O_RDONLY)) < 0) { diff --git a/polyp/default.pa.in b/polyp/default.pa.in index 54feb5ef..97b20963 100755 --- a/polyp/default.pa.in +++ b/polyp/default.pa.in @@ -52,7 +52,7 @@ set-default-source input .nofail # Load something to the sample cache -load-sample /usr/share/sounds/KDE_Notify.wav x11-bell +load-sample x11-bell /usr/share/sounds/KDE_Notify.wav # Load X11 bell module load-module module-x11-bell sample=x11-bell sink=output -- cgit From da45617efc5e3be26d6410857a730c94b32fe24b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 24 Oct 2004 00:48:02 +0000 Subject: add user volume API git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@255 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 ++- polyp/Makefile.am | 6 +++++- polyp/polyplib-version.h.in | 4 ++++ polyp/sample.c | 16 ++++++++++++++++ polyp/sample.h | 6 ++++++ polyp/voltest.c | 12 ++++++++++++ 6 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 polyp/voltest.c diff --git a/doc/todo b/doc/todo index 4526adab..fde49d66 100644 --- a/doc/todo +++ b/doc/todo @@ -1,6 +1,7 @@ *** $Id$ *** *** 0.6 **** +- latency interpolation - per-channel volume - unix socket directories include user name - add sample directory @@ -22,7 +23,7 @@ backends for: - portaudio (semi-done) +- gstreamer (semi-done) - alsa-lib - sdl -- gstreamer (semi-done) - OSS (esddsp style) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 94d3373c..10e1c6cb 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -33,7 +33,7 @@ AM_LDADD=$(PTHREAD_LIBS) -lm AM_LIBADD=$(PTHREAD_LIBS) -lm EXTRA_DIST = default.pa.in daemon.conf.in client.conf.in depmod.py esdcompat.sh.in -bin_PROGRAMS = polypaudio pacat pactl paplay +bin_PROGRAMS = polypaudio pacat pactl paplay voltest bin_SCRIPTS = esdcompat.sh noinst_PROGRAMS = \ mainloop-test \ @@ -408,6 +408,10 @@ mainloop_test_SOURCES = mainloop-test.c mainloop_test_CFLAGS = $(AM_CFLAGS) mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-@PA_MAJORMINOR@.la +voltest_SOURCES = voltest.c sample.c +voltest_CFLAGS = $(AM_CFLAGS) +voltest_LDADD = $(AM_LDADD) + cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit_test_CFLAGS = $(AM_CFLAGS) cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la diff --git a/polyp/polyplib-version.h.in b/polyp/polyplib-version.h.in index 75798693..c2442b52 100644 --- a/polyp/polyplib-version.h.in +++ b/polyp/polyplib-version.h.in @@ -27,6 +27,8 @@ /** \file * Define header version */ +PA_C_DECL_BEGIN + /** Return the version of the header files. Keep in mind that this is a macro and not a function, so it is impossible to get the pointer of it. */ @@ -40,4 +42,6 @@ const char* pa_get_library_version(void); * PA_API_VERSION undefined. */ #define PA_API_VERSION @PA_API_VERSION@ +PA_C_DECL_END + #endif diff --git a/polyp/sample.c b/polyp/sample.c index 8c30386b..7048311c 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -125,6 +125,22 @@ double pa_volume_to_dB(pa_volume_t v) { return 20*log10((double) v/PA_VOLUME_NORM); } +#define USER_DECIBEL_RANGE 30 + +double pa_volume_to_user(pa_volume_t v) { + double dB = pa_volume_to_dB(v); + + return dB < -USER_DECIBEL_RANGE ? 0 : dB/USER_DECIBEL_RANGE+1; +} + +pa_volume_t pa_volume_from_user(double v) { + + if (v <= 0) + return PA_VOLUME_MUTED; + + return pa_volume_from_dB((v-1)*USER_DECIBEL_RANGE); +} + void pa_bytes_snprint(char *s, size_t l, unsigned v) { if (v >= ((unsigned) 1024)*1024*1024) snprintf(s, l, "%0.1f GB", ((double) v)/1024/1024/1024); diff --git a/polyp/sample.h b/polyp/sample.h index 7e810386..4ab0b565 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -110,6 +110,12 @@ pa_volume_t pa_volume_from_dB(double f); /** Convert volume from linear level to decibel. \since 0.4 */ double pa_volume_to_dB(pa_volume_t v); +/** Convert volume to scaled value understandable by the user (between 0 and 1). \since 0.6 */ +double pa_volume_to_user(pa_volume_t v); + +/** Convert user volume to polypaudio volume. \since 0.6 */ +pa_volume_t pa_volume_from_user(double v); + #ifdef INFINITY #define PA_DECIBEL_MININFTY (-INFINITY) #else diff --git a/polyp/voltest.c b/polyp/voltest.c new file mode 100644 index 00000000..a06d4ca2 --- /dev/null +++ b/polyp/voltest.c @@ -0,0 +1,12 @@ +#include + +#include + +int main() { + int p; + for (p = 0; p <= 200; p++) { + pa_volume_t v = pa_volume_from_user((double) p/100); + double dB = pa_volume_to_dB(v); + printf("%3i%% = %u = %0.2f dB = %u = %3i%%\n", p, v, dB, pa_volume_from_dB(dB), (int) (pa_volume_to_user(v)*100)); + } +} -- cgit From 148202d432cbb4a303b0008b9ff9d64bdab99a51 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 27 Oct 2004 00:10:12 +0000 Subject: support for latency interpolation git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@256 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 5 +- polyp/pacat.c | 12 ++- polyp/polyplib-def.h | 18 +++- polyp/polyplib-internal.h | 12 +++ polyp/polyplib-simple.c | 2 +- polyp/polyplib-stream.c | 211 +++++++++++++++++++++++++++++++++++----------- polyp/polyplib-stream.h | 18 ++-- polyp/protocol-native.c | 6 ++ polyp/sample.h | 4 +- polyp/tagstruct.c | 24 ++++++ polyp/tagstruct.h | 6 +- polyp/util.c | 2 +- polyp/util.h | 2 +- 13 files changed, 250 insertions(+), 72 deletions(-) diff --git a/doc/todo b/doc/todo index fde49d66..df710ecf 100644 --- a/doc/todo +++ b/doc/todo @@ -1,7 +1,6 @@ *** $Id$ *** *** 0.6 **** -- latency interpolation - per-channel volume - unix socket directories include user name - add sample directory @@ -11,7 +10,9 @@ - filter capture data in client through alignment - add radio module - make autoload list use idxset -- enlarge mqmblockq sizes +- enlarge memblockq sizes +- add null-sink +- add sync API ** later *** - xmlrpc/http diff --git a/polyp/pacat.c b/polyp/pacat.c index a2687116..a37f5dda 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -297,7 +297,8 @@ static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_even /* Show the current latency */ static void stream_get_latency_callback(struct pa_stream *s, const struct pa_latency_info *i, void *userdata) { - double total; + pa_usec_t total; + int negative = 0; assert(s); if (!i) { @@ -306,20 +307,17 @@ static void stream_get_latency_callback(struct pa_stream *s, const struct pa_lat return; } - if (mode == PLAYBACK) - total = (double) i->sink_usec + i->buffer_usec + i->transport_usec; - else - total = (double) i->source_usec + i->buffer_usec + i->transport_usec - i->sink_usec; + total = pa_stream_get_latency(s, i, &negative); fprintf(stderr, "Latency: buffer: %0.0f usec; sink: %0.0f usec; source: %0.0f usec; transport: %0.0f usec; total: %0.0f usec; synchronized clocks: %s.\n", - (float) i->buffer_usec, (float) i->sink_usec, (float) i->source_usec, (float) i->transport_usec, total, + (float) i->buffer_usec, (float) i->sink_usec, (float) i->source_usec, (float) i->transport_usec, (float) total * (negative?-1:1), i->synchronized_clocks ? "yes" : "no"); } /* Someone requested that the latency is shown */ static void sigusr1_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { fprintf(stderr, "Got SIGUSR1, requesting latency.\n"); - pa_operation_unref(pa_stream_get_latency(stream, stream_get_latency_callback, NULL)); + pa_operation_unref(pa_stream_get_latency_info(stream, stream_get_latency_callback, NULL)); } diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index cd0662dd..ffa44188 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -74,7 +74,22 @@ enum pa_stream_direction { /** Some special flags for stream connections. \since 0.6 */ enum pa_stream_flags { - PA_STREAM_START_CORKED = 1, /**< Create the stream corked, requiring an explicit pa_stream_cork() call to uncork it. */ + PA_STREAM_START_CORKED = 1, /**< Create the stream corked, requiring an explicit pa_stream_cork() call to uncork it. */ + PA_STREAM_INTERPOLATE_LATENCY = 2 /**< Interpolate the latency for + * this stream. When enabled, + * you can use + * pa_stream_interpolated_xxx() + * for synchronization. Using + * these functions instead of + * pa_stream_get_latency() has + * the advantage of not + * requiring a whole roundtrip + * for responses. Consider using + * this option when frequently + * requesting latency + * information. This is + * especially useful on long latency + * network connections. */ }; /** Playback and record buffer metrics */ @@ -171,6 +186,7 @@ struct pa_latency_info { * limited und unreliable itself. \since * 0.5 */ struct timeval timestamp; /**< The time when this latency info was current */ + uint64_t counter; /**< The byte counter current when the latency info was requested. \since 0.6 */ }; /** A structure for the spawn api. This may be used to integrate auto diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 8a7bf6fb..e49b25d4 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -81,6 +81,7 @@ struct pa_context { struct pa_stream { int ref; struct pa_context *context; + struct pa_mainloop_api *mainloop; PA_LLIST_FIELDS(struct pa_stream); char *name; @@ -95,6 +96,13 @@ struct pa_stream { pa_usec_t previous_time; enum pa_stream_state state; + int interpolate; + int corked; + + uint32_t ipol_usec; + struct timeval ipol_timestamp; + struct pa_time_event *ipol_event; + void (*state_callback)(struct pa_stream*c, void *userdata); void *state_userdata; @@ -103,6 +111,7 @@ struct pa_stream { void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); void *write_userdata; + }; struct pa_operation { @@ -135,4 +144,7 @@ struct pa_operation* pa_context_send_simple_command(struct pa_context *c, uint32 void pa_stream_set_state(struct pa_stream *s, enum pa_stream_state st); +void pa_stream_trash_ipol(struct pa_stream *s); + + #endif diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c index 9e111e2a..0e180af0 100644 --- a/polyp/polyplib-simple.c +++ b/polyp/polyplib-simple.c @@ -341,7 +341,7 @@ pa_usec_t pa_simple_get_playback_latency(struct pa_simple *p, int *perror) { } p->latency = 0; - o = pa_stream_get_latency(p->stream, latency_complete, p); + o = pa_stream_get_latency_info(p->stream, latency_complete, p); while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 291c3cd3..68035b0f 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -26,12 +26,15 @@ #include #include #include +#include #include "polyplib-internal.h" #include "xmalloc.h" #include "pstream-util.h" #include "util.h" +#define LATENCY_IPOL_INTERVAL_USEC (100000L) + struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const struct pa_sample_spec *ss) { struct pa_stream *s; assert(c && ss); @@ -39,6 +42,7 @@ struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const st s = pa_xmalloc(sizeof(struct pa_stream)); s->ref = 1; s->context = c; + s->mainloop = c->mainloop; s->read_callback = NULL; s->read_userdata = NULL; @@ -60,6 +64,13 @@ struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const st s->counter = 0; s->previous_time = 0; + s->corked = 0; + s->interpolate = 0; + + s->ipol_usec = 0; + memset(&s->ipol_timestamp, 0, sizeof(s->ipol_timestamp)); + s->ipol_event = NULL; + PA_LLIST_PREPEND(struct pa_stream, c->streams, s); return pa_stream_ref(s); @@ -67,6 +78,12 @@ struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const st static void stream_free(struct pa_stream *s) { assert(s); + + if (s->ipol_event) { + assert(s->mainloop); + s->mainloop->time_free(s->ipol_event); + } + pa_xfree(s->name); pa_xfree(s); } @@ -181,6 +198,22 @@ finish: pa_context_unref(c); } +static void ipol_callback(struct pa_mainloop_api *m, struct pa_time_event *e, const struct timeval *tv, void *userdata) { + struct timeval tv2; + struct pa_stream *s = userdata; + + pa_stream_ref(s); + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + + gettimeofday(&tv2, NULL); + tv2.tv_usec += LATENCY_IPOL_INTERVAL_USEC; + + m->time_restart(e, &tv2); + + pa_stream_unref(s); +} + + void pa_create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_stream *s = userdata; assert(pd && s && s->state == PA_STREAM_CREATING); @@ -207,6 +240,17 @@ void pa_create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32 pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); pa_stream_set_state(s, PA_STREAM_READY); + if (s->interpolate) { + struct timeval tv; + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + + gettimeofday(&tv, NULL); + tv.tv_usec += LATENCY_IPOL_INTERVAL_USEC; /* every 100 ms */ + + assert(!s->ipol_event); + s->ipol_event = s->mainloop->time_new(s->mainloop, &tv, &ipol_callback, s); + } + if (s->requested_bytes && s->ref > 1 && s->write_callback) s->write_callback(s, s->requested_bytes, s->write_userdata); @@ -221,6 +265,9 @@ static void create_stream(struct pa_stream *s, const char *dev, const struct pa_ pa_stream_ref(s); + s->interpolate = !!(flags & PA_STREAM_INTERPOLATE_LATENCY); + pa_stream_trash_ipol(s); + if (attr) s->buffer_attr = *attr; else { @@ -330,7 +377,7 @@ struct pa_operation * pa_stream_drain(struct pa_stream *s, void (*cb) (struct pa return pa_operation_ref(o); } -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void stream_get_latency_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_operation *o = userdata; struct pa_latency_info i, *p = NULL; struct timeval local, remote, now; @@ -347,32 +394,39 @@ static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t comman pa_tagstruct_getu32(t, &i.queue_length) < 0 || pa_tagstruct_get_timeval(t, &local) < 0 || pa_tagstruct_get_timeval(t, &remote) < 0 || + pa_tagstruct_getu64(t, &i.counter) < 0 || !pa_tagstruct_eof(t)) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; - } else - p = &i; - - gettimeofday(&now, NULL); - - if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) { - /* local and remote seem to have synchronized clocks */ - - if (o->stream->direction == PA_STREAM_PLAYBACK) - i.transport_usec = pa_timeval_diff(&remote, &local); - else - i.transport_usec = pa_timeval_diff(&now, &remote); - - i.synchronized_clocks = 1; - i.timestamp = remote; } else { - /* clocks are not synchronized, let's estimate latency then */ - i.transport_usec = pa_timeval_diff(&now, &local)/2; - i.synchronized_clocks = 0; - i.timestamp = local; - pa_timeval_add(&i.timestamp, i.transport_usec); - } + gettimeofday(&now, NULL); + + if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) { + /* local and remote seem to have synchronized clocks */ + + if (o->stream->direction == PA_STREAM_PLAYBACK) + i.transport_usec = pa_timeval_diff(&remote, &local); + else + i.transport_usec = pa_timeval_diff(&now, &remote); + + i.synchronized_clocks = 1; + i.timestamp = remote; + } else { + /* clocks are not synchronized, let's estimate latency then */ + i.transport_usec = pa_timeval_diff(&now, &local)/2; + i.synchronized_clocks = 0; + i.timestamp = local; + pa_timeval_add(&i.timestamp, i.transport_usec); + } + + if (o->stream->interpolate) { + o->stream->ipol_timestamp = now; + o->stream->ipol_usec = pa_stream_get_time(o->stream, &i); + } + p = &i; + } + if (o->callback) { void (*cb)(struct pa_stream *s, const struct pa_latency_info *i, void *userdata) = o->callback; cb(o->stream, p, o->userdata); @@ -383,7 +437,7 @@ finish: pa_operation_unref(o); } -struct pa_operation* pa_stream_get_latency(struct pa_stream *s, void (*cb)(struct pa_stream *p, const struct pa_latency_info*i, void *userdata), void *userdata) { +struct pa_operation* pa_stream_get_latency_info(struct pa_stream *s, void (*cb)(struct pa_stream *p, const struct pa_latency_info*i, void *userdata), void *userdata) { uint32_t tag; struct pa_operation *o; struct pa_tagstruct *t; @@ -403,9 +457,10 @@ struct pa_operation* pa_stream_get_latency(struct pa_stream *s, void (*cb)(struc gettimeofday(&now, NULL); pa_tagstruct_put_timeval(t, &now); + pa_tagstruct_putu64(t, s->counter); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, o); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_info_callback, o); return pa_operation_ref(o); } @@ -505,6 +560,13 @@ struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (stru uint32_t tag; assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); + if (!s->corked && b) + s->ipol_usec = pa_stream_get_interpolated_time(s); + else if (s->corked && !b) + gettimeofday(&s->ipol_timestamp, NULL); + + s->corked = b; + o = pa_operation_new(s->context, s); assert(o); o->callback = cb; @@ -519,6 +581,8 @@ struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (stru pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + return pa_operation_ref(o); } @@ -543,15 +607,24 @@ struct pa_operation* pa_stream_send_simple_command(struct pa_stream *s, uint32_t } struct pa_operation* pa_stream_flush(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { - return pa_stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata); + struct pa_operation *o; + o = pa_stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata); + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + return o; } struct pa_operation* pa_stream_prebuf(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { - return pa_stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata); + struct pa_operation *o; + o = pa_stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata); + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + return o; } struct pa_operation* pa_stream_trigger(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { - return pa_stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata); + struct pa_operation *o; + o = pa_stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata); + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + return o; } struct pa_operation* pa_stream_set_name(struct pa_stream *s, const char *name, void(*cb)(struct pa_stream*c, int success, void *userdata), void *userdata) { @@ -582,12 +655,6 @@ uint64_t pa_stream_get_counter(struct pa_stream *s) { return s->counter; } -void pa_stream_reset_counter(struct pa_stream *s) { - assert(s); - s->counter = 0; - s->previous_time = 0; -} - pa_usec_t pa_stream_get_time(struct pa_stream *s, const struct pa_latency_info *i) { pa_usec_t usec; assert(s); @@ -620,27 +687,22 @@ pa_usec_t pa_stream_get_time(struct pa_stream *s, const struct pa_latency_info * return usec; } -pa_usec_t pa_stream_get_total_latency(struct pa_stream *s, const struct pa_latency_info *i, int *negative) { +pa_usec_t pa_stream_get_latency(struct pa_stream *s, const struct pa_latency_info *i, int *negative) { + pa_usec_t t, c; assert(s && i); - if (s->direction == PA_STREAM_PLAYBACK) { + t = pa_stream_get_time(s, i); + c = pa_bytes_to_usec(s->counter, &s->sample_spec); + + if (t <= c) { if (negative) - *negative = 0; - - return i->transport_usec + i->buffer_usec + i->sink_usec; - } else if (s->direction == PA_STREAM_RECORD) { - pa_usec_t usec = i->source_usec + i->buffer_usec + i->transport_usec; - - if (usec >= i->sink_usec) { - if (negative) - *negative = 0; - return usec - i->sink_usec; - } else { - if (negative) - *negative = 1; + *negative = 1; - return i->sink_usec - usec; - } + return c-t; + } else { + if (negative) + *negative = 0; + return t-c; } return 0; @@ -650,3 +712,52 @@ const struct pa_sample_spec* pa_stream_get_sample_spec(struct pa_stream *s) { assert(s); return &s->sample_spec; } + +void pa_stream_trash_ipol(struct pa_stream *s) { + assert(s); + + if (!s->interpolate) + return; + + memset(&s->ipol_timestamp, 0, sizeof(s->ipol_timestamp)); + s->ipol_usec = 0; +} + +pa_usec_t pa_stream_get_interpolated_time(struct pa_stream *s) { + pa_usec_t usec; + assert(s && s->interpolate); + + if (s->corked) + usec = s->ipol_usec; + else { + if (s->ipol_timestamp.tv_sec == 0) + usec = 0; + else + usec = s->ipol_usec + pa_timeval_age(&s->ipol_timestamp); + } + + if (usec < s->previous_time) + usec = s->previous_time; + + s->previous_time = usec; + return usec; +} + +pa_usec_t pa_stream_get_interpolated_latency(struct pa_stream *s, int *negative) { + pa_usec_t t, c; + assert(s && s->interpolate); + + t = pa_stream_get_interpolated_time(s); + c = pa_bytes_to_usec(s->counter, &s->sample_spec); + + if (t <= c) { + if (negative) + *negative = 1; + + return c-t; + } else { + if (negative) + *negative = 0; + return t-c; + } +} diff --git a/polyp/polyplib-stream.h b/polyp/polyplib-stream.h index e095d7fa..4ccc0c23 100644 --- a/polyp/polyplib-stream.h +++ b/polyp/polyplib-stream.h @@ -102,7 +102,7 @@ size_t pa_stream_writable_size(struct pa_stream *p); struct pa_operation* pa_stream_drain(struct pa_stream *s, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); /** Get the playback latency of a stream */ -struct pa_operation* pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, const struct pa_latency_info *i, void *userdata), void *userdata); +struct pa_operation* pa_stream_get_latency_info(struct pa_stream *p, void (*cb)(struct pa_stream *p, const struct pa_latency_info *i, void *userdata), void *userdata); /** Set the callback function that is called whenever the state of the stream changes */ void pa_stream_set_state_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); @@ -138,9 +138,6 @@ struct pa_operation* pa_stream_set_name(struct pa_stream *s, const char *name, v * this yourself using pa_stream_reset_counter(). \since 0.6 */ uint64_t pa_stream_get_counter(struct pa_stream *s); -/** Reset the total byte count to 0. \since 0.6 */ -void pa_stream_reset_counter(struct pa_stream *s); - /** Return the current playback/recording time. This is based on the * counter accessible with pa_stream_get_counter(). This function * requires a pa_latency_info structure as argument, which should be @@ -152,7 +149,18 @@ pa_usec_t pa_stream_get_time(struct pa_stream *s, const struct pa_latency_info * * using pa_stream_get_latency(). In case the stream is a monitoring * stream the result can be negative, i.e. the captured samples are * not yet played. In this case *negative is set to 1. \since 0.6 */ -pa_usec_t pa_stream_get_total_latency(struct pa_stream *s, const struct pa_latency_info *i, int *negative); +pa_usec_t pa_stream_get_latency(struct pa_stream *s, const struct pa_latency_info *i, int *negative); + +/** Return the interpolated playback/recording time. Requires the + * PA_STREAM_INTERPOLATE_LATENCY bit set when creating the stream. In + * contrast to pa_stream_get_latency() this function doesn't require + * a whole roundtrip for response. \since 0.6 */ +pa_usec_t pa_stream_get_interpolated_time(struct pa_stream *s); + +/** Return the interpolated playback/recording latency. Requires the + * PA_STREAM_INTERPOLATE_LATENCY bit set when creating the + * stream. \since 0.6 */ +pa_usec_t pa_stream_get_interpolated_latency(struct pa_stream *s, int *negative); /** Return a pointer to the streams sample specification. \since 0.6 */ const struct pa_sample_spec* pa_stream_get_sample_spec(struct pa_stream *s); diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 3b816419..31ab4ab8 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -875,11 +875,13 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma struct pa_tagstruct *reply; struct playback_stream *s; struct timeval tv, now; + uint64_t counter; uint32_t index; assert(c && t); if (pa_tagstruct_getu32(t, &index) < 0 || pa_tagstruct_get_timeval(t, &tv) < 0 || + pa_tagstruct_getu64(t, &counter) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -907,6 +909,7 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma pa_tagstruct_put_timeval(reply, &tv); gettimeofday(&now, NULL); pa_tagstruct_put_timeval(reply, &now); + pa_tagstruct_putu64(reply, counter); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -915,11 +918,13 @@ static void command_get_record_latency(struct pa_pdispatch *pd, uint32_t command struct pa_tagstruct *reply; struct record_stream *s; struct timeval tv, now; + uint64_t counter; uint32_t index; assert(c && t); if (pa_tagstruct_getu32(t, &index) < 0 || pa_tagstruct_get_timeval(t, &tv) < 0 || + pa_tagstruct_getu64(t, &counter) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -947,6 +952,7 @@ static void command_get_record_latency(struct pa_pdispatch *pd, uint32_t command pa_tagstruct_put_timeval(reply, &tv); gettimeofday(&now, NULL); pa_tagstruct_put_timeval(reply, &now); + pa_tagstruct_putu64(reply, counter); pa_pstream_send_tagstruct(c->pstream, reply); } diff --git a/polyp/sample.h b/polyp/sample.h index 4ab0b565..a02a50fe 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -68,10 +68,10 @@ struct pa_sample_spec { uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */ }; -/** Type for usec specifications. May be either 32 or 64 bit, depending on the architecture */ +/** Type for usec specifications (unsigned). May be either 32 or 64 bit, depending on the architecture */ typedef uint64_t pa_usec_t; -/** Return the amount of bytes playback of a second of audio with the speicified sample type takes */ +/** Return the amount of bytes playback of a second of audio with the specified sample type takes */ size_t pa_bytes_per_second(const struct pa_sample_spec *spec); /** Return the size of a frame with the specific sample type */ diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c index bbebdab3..b9ab55f0 100644 --- a/polyp/tagstruct.c +++ b/polyp/tagstruct.c @@ -176,6 +176,15 @@ void pa_tagstruct_put_usec(struct pa_tagstruct*t, pa_usec_t u) { t->length += 9; } +void pa_tagstruct_putu64(struct pa_tagstruct*t, uint64_t u) { + assert(t); + extend(t, 9); + t->data[t->length] = TAG_U64; + *((uint32_t*) (t->data+t->length+1)) = htonl((uint32_t) (u >> 32)); + *((uint32_t*) (t->data+t->length+5)) = htonl((uint32_t) u); + t->length += 9; +} + int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s) { int error = 0; size_t n; @@ -332,3 +341,18 @@ int pa_tagstruct_get_usec(struct pa_tagstruct*t, pa_usec_t *u) { t->rindex +=9; return 0; } + +int pa_tagstruct_getu64(struct pa_tagstruct*t, uint64_t *u) { + assert(t && u); + + if (t->rindex+9 > t->length) + return -1; + + if (t->data[t->rindex] != TAG_U64) + return -1; + + *u = (uint64_t) ntohl(*((uint32_t*) (t->data+t->rindex+1))) << 32; + *u |= (uint64_t) ntohl(*((uint32_t*) (t->data+t->rindex+5))); + t->rindex +=9; + return 0; +} diff --git a/polyp/tagstruct.h b/polyp/tagstruct.h index e50551c4..b943345b 100644 --- a/polyp/tagstruct.h +++ b/polyp/tagstruct.h @@ -36,8 +36,9 @@ void pa_tagstruct_free(struct pa_tagstruct*t); uint8_t* pa_tagstruct_free_data(struct pa_tagstruct*t, size_t *l); void pa_tagstruct_puts(struct pa_tagstruct*t, const char *s); -void pa_tagstruct_putu32(struct pa_tagstruct*t, uint32_t i); void pa_tagstruct_putu8(struct pa_tagstruct*t, uint8_t c); +void pa_tagstruct_putu32(struct pa_tagstruct*t, uint32_t i); +void pa_tagstruct_putu64(struct pa_tagstruct*t, uint64_t i); void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample_spec *ss); void pa_tagstruct_put_arbitrary(struct pa_tagstruct*t, const void *p, size_t length); void pa_tagstruct_put_boolean(struct pa_tagstruct*t, int b); @@ -45,8 +46,9 @@ void pa_tagstruct_put_timeval(struct pa_tagstruct*t, const struct timeval *tv); void pa_tagstruct_put_usec(struct pa_tagstruct*t, pa_usec_t u); int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s); -int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i); int pa_tagstruct_getu8(struct pa_tagstruct*t, uint8_t *c); +int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i); +int pa_tagstruct_getu64(struct pa_tagstruct*t, uint64_t *i); int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec *ss); int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t length); int pa_tagstruct_get_boolean(struct pa_tagstruct *t, int *b); diff --git a/polyp/util.c b/polyp/util.c index 70ec120d..9697a1eb 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -266,7 +266,7 @@ int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { return 0; } -pa_usec_t pa_age(const struct timeval *tv) { +pa_usec_t pa_timeval_age(const struct timeval *tv) { struct timeval now; assert(tv); gettimeofday(&now, NULL); diff --git a/polyp/util.h b/polyp/util.h index b0a1a033..c5ffa755 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -49,7 +49,7 @@ char *pa_path_get_filename(const char *p); pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); -pa_usec_t pa_age(const struct timeval *tv); +pa_usec_t pa_timeval_age(const struct timeval *tv); void pa_timeval_add(struct timeval *tv, pa_usec_t v); void pa_raise_priority(void); -- cgit From ee452b0f06c82dd870de82fb3e6bdd4e14d29f3c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 27 Oct 2004 01:09:51 +0000 Subject: two latency interpolation fixes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@257 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/polyplib-context.c | 4 +++- polyp/polyplib-stream.c | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index b736daa7..cf1a8e60 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -230,9 +230,11 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, ui } int pa_context_handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { - assert(c && t); + assert(c); if (command == PA_COMMAND_ERROR) { + assert(t); + if (pa_tagstruct_getu32(t, &c->error) < 0) { pa_context_fail(c, PA_ERROR_PROTOCOL); return -1; diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 68035b0f..c8fef673 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -420,7 +420,7 @@ static void stream_get_latency_info_callback(struct pa_pdispatch *pd, uint32_t c } if (o->stream->interpolate) { - o->stream->ipol_timestamp = now; + o->stream->ipol_timestamp = i.timestamp; o->stream->ipol_usec = pa_stream_get_time(o->stream, &i); } @@ -659,7 +659,7 @@ pa_usec_t pa_stream_get_time(struct pa_stream *s, const struct pa_latency_info * pa_usec_t usec; assert(s); - usec = pa_bytes_to_usec(s->counter, &s->sample_spec); + usec = pa_bytes_to_usec(i->counter, &s->sample_spec); if (i) { if (s->direction == PA_STREAM_PLAYBACK) { -- cgit From 49e16ffc6c87fd879e4143730fd211560ffee0a4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 27 Oct 2004 14:14:30 +0000 Subject: latency calculation fix git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@258 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/polyplib-stream.c | 44 +++++++++++++++++++++----------------------- polyp/sink-input.c | 26 ++++++++++++++++---------- polyp/sink-input.h | 3 +++ 3 files changed, 40 insertions(+), 33 deletions(-) diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index c8fef673..286702b2 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -687,6 +687,24 @@ pa_usec_t pa_stream_get_time(struct pa_stream *s, const struct pa_latency_info * return usec; } +static pa_usec_t time_counter_diff(struct pa_stream *s, pa_usec_t t, pa_usec_t c, int *negative) { + assert(s); + + if (negative) + *negative = 0; + + if (c < t) { + if (s->direction == PA_STREAM_RECORD) { + if (negative) + *negative = 1; + + return t-c; + } else + return 0; + } else + return c-t; +} + pa_usec_t pa_stream_get_latency(struct pa_stream *s, const struct pa_latency_info *i, int *negative) { pa_usec_t t, c; assert(s && i); @@ -694,18 +712,7 @@ pa_usec_t pa_stream_get_latency(struct pa_stream *s, const struct pa_latency_inf t = pa_stream_get_time(s, i); c = pa_bytes_to_usec(s->counter, &s->sample_spec); - if (t <= c) { - if (negative) - *negative = 1; - - return c-t; - } else { - if (negative) - *negative = 0; - return t-c; - } - - return 0; + return time_counter_diff(s, t, c, negative); } const struct pa_sample_spec* pa_stream_get_sample_spec(struct pa_stream *s) { @@ -749,15 +756,6 @@ pa_usec_t pa_stream_get_interpolated_latency(struct pa_stream *s, int *negative) t = pa_stream_get_interpolated_time(s); c = pa_bytes_to_usec(s->counter, &s->sample_spec); - - if (t <= c) { - if (negative) - *negative = 1; - - return c-t; - } else { - if (negative) - *negative = 0; - return t-c; - } + + return time_counter_diff(s, t, c, negative); } diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 5c8675de..dac10953 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -69,8 +69,10 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con i->kill = NULL; i->get_latency = NULL; i->userdata = NULL; + i->underrun = NULL; i->volume = PA_VOLUME_NORM; + i->playing = 0; i->resampled_chunk.memblock = NULL; i->resampled_chunk.index = i->resampled_chunk.length = 0; @@ -156,20 +158,19 @@ pa_usec_t pa_sink_input_get_latency(struct pa_sink_input *i) { } int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { - int ret = 0; + int ret = -1; assert(i && chunk && i->ref >= 1); - if (!i->peek || !i->drop) - return -1; - - if (i->state == PA_SINK_INPUT_CORKED) - return -1; - - if (!i->resampler) - return i->peek(i, chunk); - pa_sink_input_ref(i); + if (!i->peek || !i->drop || i->state == PA_SINK_INPUT_CORKED) + goto finish; + + if (!i->resampler) { + ret = i->peek(i, chunk); + goto finish; + } + while (!i->resampled_chunk.memblock) { struct pa_memchunk tchunk; size_t l; @@ -199,6 +200,11 @@ int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { finish: + if (ret < 0 && i->playing && i->underrun) + i->underrun(i); + + i->playing = ret >= 0; + pa_sink_input_unref(i); return ret; diff --git a/polyp/sink-input.h b/polyp/sink-input.h index aed5f521..eb2cb239 100644 --- a/polyp/sink-input.h +++ b/polyp/sink-input.h @@ -54,9 +54,12 @@ struct pa_sink_input { void (*drop) (struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length); void (*kill) (struct pa_sink_input *i); pa_usec_t (*get_latency) (struct pa_sink_input *i); + void (*underrun) (struct pa_sink_input *i); void *userdata; + int playing; + struct pa_memchunk resampled_chunk; struct pa_resampler *resampler; }; -- cgit From 19f2acbd0a9d199b77ad71eaf206319f6f12e323 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 27 Oct 2004 14:42:56 +0000 Subject: add null sink git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@259 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 12 +++- polyp/module-null-sink.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++ polyp/module-pipe-sink.c | 6 +- polyp/voltest.c | 2 + 4 files changed, 161 insertions(+), 7 deletions(-) create mode 100644 polyp/module-null-sink.c diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 10e1c6cb..ae551a1b 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -33,14 +33,15 @@ AM_LDADD=$(PTHREAD_LIBS) -lm AM_LIBADD=$(PTHREAD_LIBS) -lm EXTRA_DIST = default.pa.in daemon.conf.in client.conf.in depmod.py esdcompat.sh.in -bin_PROGRAMS = polypaudio pacat pactl paplay voltest +bin_PROGRAMS = polypaudio pacat pactl paplay bin_SCRIPTS = esdcompat.sh noinst_PROGRAMS = \ mainloop-test \ pacat-simple \ parec-simple \ cpulimit-test \ - cpulimit-test2 + cpulimit-test2 \ + voltest polypconf_DATA=default.pa daemon.conf client.conf @@ -108,7 +109,8 @@ modlib_LTLIBRARIES= \ module-esound-compat-spawnpid.la \ module-match.la \ module-tunnel-sink.la \ - module-tunnel-source.la + module-tunnel-source.la \ + module-null-sink.la lib_LTLIBRARIES= \ libpolyp-@PA_MAJORMINOR@.la \ @@ -308,6 +310,10 @@ module_combine_la_SOURCES = module-combine.c module_combine_la_LDFLAGS = -module -avoid-version module_combine_la_LIBADD = $(AM_LIBADD) +module_null_sink_la_SOURCES = module-null-sink.c +module_null_sink_la_LDFLAGS = -module -avoid-version +module_null_sink_la_LIBADD = $(AM_LIBADD) + module_match_la_SOURCES = module-match.c module_match_la_LDFLAGS = -module -avoid-version module_match_la_LIBADD = $(AM_LIBADD) diff --git a/polyp/module-null-sink.c b/polyp/module-null-sink.c new file mode 100644 index 00000000..e48e9668 --- /dev/null +++ b/polyp/module-null-sink.c @@ -0,0 +1,148 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iochannel.h" +#include "sink.h" +#include "module.h" +#include "util.h" +#include "modargs.h" +#include "xmalloc.h" +#include "log.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Clocked NULL sink") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("format= channels= rate= sink_name=") + +#define DEFAULT_SINK_NAME "null" + +struct userdata { + struct pa_core *core; + struct pa_module *module; + struct pa_sink *sink; + struct pa_time_event *time_event; + size_t block_size; +}; + +static const char* const valid_modargs[] = { + "rate", + "format", + "channels", + "sink_name", + NULL +}; + +static void time_callback(struct pa_mainloop_api *m, struct pa_time_event*e, const struct timeval *tv, void *userdata) { + struct userdata *u = userdata; + struct pa_memchunk chunk; + struct timeval ntv = *tv; + size_t l; + + assert(u); + + if (pa_sink_render(u->sink, u->block_size, &chunk) >= 0) { + l = chunk.length; + pa_memblock_unref(chunk.memblock); + } else + l = u->block_size; + + pa_timeval_add(&ntv, pa_bytes_to_usec(l, &u->sink->sample_spec)); + m->time_restart(e, &ntv); +} + +int pa__init(struct pa_core *c, struct pa_module*m) { + struct userdata *u = NULL; + struct pa_sample_spec ss; + struct pa_modargs *ma = NULL; + struct timeval tv; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": invalid sample format specification\n"); + goto fail; + } + + u = pa_xmalloc0(sizeof(struct userdata)); + u->core = c; + u->module = m; + m->userdata = u; + + if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { + pa_log(__FILE__": failed to create sink.\n"); + goto fail; + } + + u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("NULL sink"); + + gettimeofday(&tv, NULL); + u->time_event = c->mainloop->time_new(c->mainloop, &tv, time_callback, u); + + u->block_size = pa_bytes_per_second(&ss) / 10; + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + pa__done(c, m); + + return -1; +} + +void pa__done(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + + u->core->mainloop->time_free(u->time_event); + + pa_xfree(u); +} diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c index c5097fb7..7c779f7d 100644 --- a/polyp/module-pipe-sink.c +++ b/polyp/module-pipe-sink.c @@ -162,9 +162,10 @@ int pa__init(struct pa_core *c, struct pa_module*m) { } u = pa_xmalloc0(sizeof(struct userdata)); - u->filename = pa_xstrdup(p); u->core = c; + u->module = m; + m->userdata = u; if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { pa_log(__FILE__": failed to create sink.\n"); @@ -187,9 +188,6 @@ int pa__init(struct pa_core *c, struct pa_module*m) { assert(u->defer_event); c->mainloop->defer_enable(u->defer_event, 0); - u->module = m; - m->userdata = u; - pa_modargs_free(ma); return 0; diff --git a/polyp/voltest.c b/polyp/voltest.c index a06d4ca2..d8d5c569 100644 --- a/polyp/voltest.c +++ b/polyp/voltest.c @@ -1,3 +1,5 @@ +/* $Id$ */ + #include #include -- cgit From 929104afd9d1a37f44999fd110c102480d9a86f5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 27 Oct 2004 14:45:04 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@260 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/todo b/doc/todo index df710ecf..fa97b4a3 100644 --- a/doc/todo +++ b/doc/todo @@ -10,9 +10,8 @@ - filter capture data in client through alignment - add radio module - make autoload list use idxset -- enlarge memblockq sizes -- add null-sink - add sync API +- make most buffer sizes dependant on the sample type ** later *** - xmlrpc/http -- cgit From f252edb7949c0114b666b1eacea5d6d2774d27a0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 27 Oct 2004 14:46:25 +0000 Subject: minor updates git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@261 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/default.pa.in | 1 + polyp/module-null-sink.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/polyp/default.pa.in b/polyp/default.pa.in index 97b20963..95d4be58 100755 --- a/polyp/default.pa.in +++ b/polyp/default.pa.in @@ -24,6 +24,7 @@ load-module module-alsa-source device=plughw:1,0 load-module module-oss device="/dev/dsp" sink_name=output source_name=input record=0 #load-module module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +load-module module-null-sink #load-module module-pipe-sink # Load audio drivers automatically on access diff --git a/polyp/module-null-sink.c b/polyp/module-null-sink.c index e48e9668..86542010 100644 --- a/polyp/module-null-sink.c +++ b/polyp/module-null-sink.c @@ -90,13 +90,13 @@ int pa__init(struct pa_core *c, struct pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); + pa_log(__FILE__": failed to parse module arguments.\n"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": invalid sample format specification\n"); + pa_log(__FILE__": invalid sample format specification.\n"); goto fail; } -- cgit From 1bcec3ef5b83ca72c7d32e553566698607bae0e2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 27 Oct 2004 16:23:23 +0000 Subject: make autoload list use idxset git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@262 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 +- polyp/autoload.c | 70 +++++++++++++++++++++++++++++++++++------ polyp/autoload.h | 9 ++++-- polyp/cli-command.c | 4 +-- polyp/cli-text.c | 5 +-- polyp/core.c | 2 +- polyp/core.h | 2 +- polyp/pactl.c | 3 +- polyp/polyplib-introspect.c | 77 ++++++++++++++++++++++++++++++++++++++++++--- polyp/polyplib-introspect.h | 18 ++++++++--- polyp/protocol-native.c | 54 ++++++++++++++++++++++--------- 11 files changed, 204 insertions(+), 43 deletions(-) diff --git a/doc/todo b/doc/todo index fa97b4a3..1ffdee49 100644 --- a/doc/todo +++ b/doc/todo @@ -1,6 +1,6 @@ *** $Id$ *** -*** 0.6 **** +*** 0.7 **** - per-channel volume - unix socket directories include user name - add sample directory @@ -9,7 +9,6 @@ - improve module-oss-mmap latency measurement - filter capture data in client through alignment - add radio module -- make autoload list use idxset - add sync API - make most buffer sizes dependant on the sample type diff --git a/polyp/autoload.c b/polyp/autoload.c index 12cd1f91..d6207962 100644 --- a/polyp/autoload.c +++ b/polyp/autoload.c @@ -45,6 +45,14 @@ static void entry_free(struct pa_autoload_entry *e) { pa_xfree(e); } +static void entry_remove_and_free(struct pa_autoload_entry *e) { + assert(e && e->core); + + pa_idxset_remove_by_data(e->core->autoload_idxset, e, NULL); + pa_hashmap_remove(e->core->autoload_hashmap, e->name); + entry_free(e); +} + static struct pa_autoload_entry* entry_new(struct pa_core *c, const char *name) { struct pa_autoload_entry *e = NULL; assert(c && name); @@ -64,12 +72,16 @@ static struct pa_autoload_entry* entry_new(struct pa_core *c, const char *name) pa_hashmap_put(c->autoload_hashmap, e->name, e); - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_AUTOLOAD|PA_SUBSCRIPTION_EVENT_NEW, PA_INVALID_INDEX); + if (!c->autoload_idxset) + c->autoload_idxset = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + pa_idxset_put(c->autoload_idxset, e, &e->index); + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_AUTOLOAD|PA_SUBSCRIPTION_EVENT_NEW, e->index); return e; } -int pa_autoload_add(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*module, const char *argument) { +int pa_autoload_add(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*module, const char *argument, uint32_t *index) { struct pa_autoload_entry *e = NULL; assert(c && name && module && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); @@ -79,18 +91,32 @@ int pa_autoload_add(struct pa_core *c, const char*name, enum pa_namereg_type typ e->module = pa_xstrdup(module); e->argument = pa_xstrdup(argument); e->type = type; + + if (index) + *index = e->index; + return 0; } -int pa_autoload_remove(struct pa_core *c, const char*name, enum pa_namereg_type type) { +int pa_autoload_remove_by_name(struct pa_core *c, const char*name, enum pa_namereg_type type) { struct pa_autoload_entry *e; assert(c && name && type); - if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name))) + if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type) return -1; - pa_hashmap_remove(c->autoload_hashmap, e->name); - entry_free(e); + entry_remove_and_free(e); + return 0; +} + +int pa_autoload_remove_by_index(struct pa_core *c, uint32_t index) { + struct pa_autoload_entry *e; + assert(c && index != PA_IDXSET_INVALID); + + if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, index))) + return -1; + + entry_remove_and_free(e); return 0; } @@ -117,12 +143,38 @@ void pa_autoload_request(struct pa_core *c, const char *name, enum pa_namereg_ty static void free_func(void *p, void *userdata) { struct pa_autoload_entry *e = p; + pa_idxset_remove_by_data(e->core->autoload_idxset, e, NULL); entry_free(e); } void pa_autoload_free(struct pa_core *c) { - if (!c->autoload_hashmap) - return; + if (c->autoload_hashmap) { + pa_hashmap_free(c->autoload_hashmap, free_func, NULL); + c->autoload_hashmap = NULL; + } + + if (c->autoload_idxset) { + pa_idxset_free(c->autoload_idxset, NULL, NULL); + c->autoload_idxset = NULL; + } +} + +const struct pa_autoload_entry* pa_autoload_get_by_name(struct pa_core *c, const char*name, enum pa_namereg_type type) { + struct pa_autoload_entry *e; + assert(c && name); + + if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type) + return NULL; - pa_hashmap_free(c->autoload_hashmap, free_func, NULL); + return e; +} + +const struct pa_autoload_entry* pa_autoload_get_by_index(struct pa_core *c, uint32_t index) { + struct pa_autoload_entry *e; + assert(c && index != PA_IDXSET_INVALID); + + if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, index))) + return NULL; + + return e; } diff --git a/polyp/autoload.h b/polyp/autoload.h index f80b1f0d..ec7d38f1 100644 --- a/polyp/autoload.h +++ b/polyp/autoload.h @@ -26,15 +26,20 @@ struct pa_autoload_entry { struct pa_core *core; + uint32_t index; char *name; enum pa_namereg_type type; int in_action; char *module, *argument; }; -int pa_autoload_add(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*module, const char *argument); +int pa_autoload_add(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*module, const char *argument, uint32_t *index); void pa_autoload_free(struct pa_core *c); -int pa_autoload_remove(struct pa_core *c, const char*name, enum pa_namereg_type type); +int pa_autoload_remove_by_name(struct pa_core *c, const char*name, enum pa_namereg_type type); +int pa_autoload_remove_by_index(struct pa_core *c, uint32_t index); void pa_autoload_request(struct pa_core *c, const char *name, enum pa_namereg_type type); +const struct pa_autoload_entry* pa_autoload_get_by_name(struct pa_core *c, const char*name, enum pa_namereg_type type); +const struct pa_autoload_entry* pa_autoload_get_by_index(struct pa_core *c, uint32_t index); + #endif diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 39ea9cc1..62981b4d 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -570,7 +570,7 @@ static int pa_cli_command_autoload_add(struct pa_core *c, struct pa_tokenizer *t return -1; } - pa_autoload_add(c, a, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, b, pa_tokenizer_get(t, 3)); + pa_autoload_add(c, a, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, b, pa_tokenizer_get(t, 3), NULL); return 0; } @@ -584,7 +584,7 @@ static int pa_cli_command_autoload_remove(struct pa_core *c, struct pa_tokenizer return -1; } - if (pa_autoload_remove(c, name, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE) < 0) { + if (pa_autoload_remove_by_name(c, name, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE) < 0) { pa_strbuf_puts(buf, "Failed to remove autload entry\n"); return -1; } diff --git a/polyp/cli-text.c b/polyp/cli-text.c index f9bc6c7a..c08b0d9c 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -243,7 +243,7 @@ char *pa_scache_list_to_string(struct pa_core *c) { } pa_strbuf_printf( - s, " name: <%s>\n\tindex: <%i>\n\tsample_spec: <%s>\n\tlength: <%u>\n\tduration: <%0.1fs>\n\tvolume: <0x%04x>\n\tlazy: %s\n\tfilename: %s\n", + s, " name: <%s>\n\tindex: <%u>\n\tsample_spec: <%s>\n\tlength: <%u>\n\tduration: <%0.1fs>\n\tvolume: <0x%04x>\n\tlazy: %s\n\tfilename: %s\n", e->name, e->index, ss, @@ -273,9 +273,10 @@ char *pa_autoload_list_to_string(struct pa_core *c) { while ((e = pa_hashmap_iterate(c->autoload_hashmap, &state))) { pa_strbuf_printf( - s, " name: <%s>\n\ttype: <%s>\n\tmodule_name: <%s>\n\targuments: <%s>\n", + s, " name: <%s>\n\ttype: <%s>\n\tindex: <%u>\n\tmodule_name: <%s>\n\targuments: <%s>\n", e->name, e->type == PA_NAMEREG_SOURCE ? "source" : "sink", + e->index, e->module, e->argument); diff --git a/polyp/core.c b/polyp/core.c index cf2d383c..c53d2e4e 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -56,7 +56,7 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->modules = NULL; c->namereg = NULL; c->scache = NULL; - + c->autoload_idxset = NULL; c->autoload_hashmap = NULL; c->default_sample_spec.format = PA_SAMPLE_S16NE; diff --git a/polyp/core.h b/polyp/core.h index 62959d0a..c457c3fd 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -31,7 +31,7 @@ struct pa_core { struct pa_mainloop_api *mainloop; - struct pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache; + struct pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache, *autoload_idxset; struct pa_hashmap *namereg, *autoload_hashmap; diff --git a/polyp/pactl.c b/polyp/pactl.c index fbedc6fa..29c06f91 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -437,11 +437,12 @@ static void get_autoload_info_callback(struct pa_context *c, const struct pa_aut printf("\n"); nl = 1; - printf("*** Autoload Entry ***\n" + printf("*** Autoload Entry #%u ***\n" "Name: %s\n" "Type: %s\n" "Module: %s\n" "Argument: %s\n", + i->index, i->name, i->type == PA_AUTOLOAD_SINK ? "sink" : "source", i->module, diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index 267af95b..af5fd168 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -823,7 +823,8 @@ static void context_get_autoload_info_callback(struct pa_pdispatch *pd, uint32_t while (!pa_tagstruct_eof(t)) { struct pa_autoload_info i; - if (pa_tagstruct_gets(t, &i.name) < 0 || + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_getu32(t, &i.type) < 0 || pa_tagstruct_gets(t, &i.module) < 0 || pa_tagstruct_gets(t, &i.argument) < 0) { @@ -848,7 +849,7 @@ finish: pa_operation_unref(o); } -struct pa_operation* pa_context_get_autoload_info(struct pa_context *c, const char *name, enum pa_autoload_type type, void (*cb)(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata), void *userdata) { +struct pa_operation* pa_context_get_autoload_info_by_name(struct pa_context *c, const char *name, enum pa_autoload_type type, void (*cb)(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata), void *userdata) { struct pa_tagstruct *t; struct pa_operation *o; uint32_t tag; @@ -869,10 +870,58 @@ struct pa_operation* pa_context_get_autoload_info(struct pa_context *c, const ch return pa_operation_ref(o); } +struct pa_operation* pa_context_get_autoload_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata), void *userdata) { + struct pa_tagstruct *t; + struct pa_operation *o; + uint32_t tag; + assert(c && cb && index != PA_INVALID_INDEX); + + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_AUTOLOAD_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, o); + + return pa_operation_ref(o); +} + struct pa_operation* pa_context_get_autoload_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata), void *userdata) { return pa_context_send_simple_command(c, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, context_get_autoload_info_callback, cb, userdata); } +static void context_add_autoload_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + uint32_t index; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + index = PA_INVALID_INDEX; + } else if (pa_tagstruct_getu32(t, &index) || + !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(struct pa_context *s, uint32_t index, void *userdata) = o->callback; + cb(o->context, index, o->userdata); + } + + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + + struct pa_operation* pa_context_add_autoload(struct pa_context *c, const char *name, enum pa_autoload_type type, const char *module, const char*argument, void (*cb)(struct pa_context *c, int success, void *userdata), void* userdata) { struct pa_operation *o; struct pa_tagstruct *t; @@ -891,12 +940,12 @@ struct pa_operation* pa_context_add_autoload(struct pa_context *c, const char *n pa_tagstruct_puts(t, module); pa_tagstruct_puts(t, argument); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_add_autoload_callback, o); return pa_operation_ref(o); } -struct pa_operation* pa_context_remove_autoload(struct pa_context *c, const char *name, enum pa_autoload_type type, void (*cb)(struct pa_context *c, int success, void *userdata), void* userdata) { +struct pa_operation* pa_context_remove_autoload_by_name(struct pa_context *c, const char *name, enum pa_autoload_type type, void (*cb)(struct pa_context *c, int success, void *userdata), void* userdata) { struct pa_operation *o; struct pa_tagstruct *t; uint32_t tag; @@ -916,3 +965,23 @@ struct pa_operation* pa_context_remove_autoload(struct pa_context *c, const char return pa_operation_ref(o); } + +struct pa_operation* pa_context_remove_autoload_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void* userdata) { + struct pa_operation *o; + struct pa_tagstruct *t; + uint32_t tag; + assert(c && index != PA_INVALID_INDEX); + + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_AUTOLOAD); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index 9e6c31b2..f4dbd185 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -234,23 +234,31 @@ enum pa_autoload_type { /** Stores information about autoload entries. \since 0.5 */ struct pa_autoload_info { + uint32_t index; /**< Index of this autoload entry */ const char *name; /**< Name of the sink or source */ enum pa_autoload_type type; /**< Type of the autoload entry */ const char *module; /**< Module name to load */ const char *argument; /**< Argument string for module */ }; -/** Get info about a specific autoload entry. \since 0.5 */ -struct pa_operation* pa_context_get_autoload_info(struct pa_context *c, const char *name, enum pa_autoload_type type, void (*cb)(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata), void *userdata); +/** Get info about a specific autoload entry. \since 0.6 */ +struct pa_operation* pa_context_get_autoload_info_by_name(struct pa_context *c, const char *name, enum pa_autoload_type type, void (*cb)(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata), void *userdata); + +/** Get info about a specific autoload entry. \since 0.6 */ +struct pa_operation* pa_context_get_autoload_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata), void *userdata); /** Get the complete list of autoload entries. \since 0.5 */ struct pa_operation* pa_context_get_autoload_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata), void *userdata); /** Add a new autoload entry. \since 0.5 */ -struct pa_operation* pa_context_add_autoload(struct pa_context *c, const char *name, enum pa_autoload_type type, const char *module, const char*argument, void (*cb)(struct pa_context *c, int success, void *userdata), void* userdata); +struct pa_operation* pa_context_add_autoload(struct pa_context *c, const char *name, enum pa_autoload_type type, const char *module, const char*argument, void (*cb)(struct pa_context *c, int index, void *userdata), void* userdata); + +/** Remove an autoload entry. \since 0.6 */ +struct pa_operation* pa_context_remove_autoload_by_name(struct pa_context *c, const char *name, enum pa_autoload_type type, void (*cb)(struct pa_context *c, int success, void *userdata), void* userdata); + +/** Remove an autoload entry. \since 0.6 */ +struct pa_operation* pa_context_remove_autoload_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void* userdata); -/** Remove an autoload entry. \since 0.5 */ -struct pa_operation* pa_context_remove_autoload(struct pa_context *c, const char *name, enum pa_autoload_type type, void (*cb)(struct pa_context *c, int success, void *userdata), void* userdata); PA_C_DECL_END diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 31ab4ab8..7af8bdda 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -1729,6 +1729,8 @@ static void command_add_autoload(struct pa_pdispatch *pd, uint32_t command, uint struct connection *c = userdata; const char *name, *module, *argument; uint32_t type; + uint32_t index; + struct pa_tagstruct *reply; assert(c && t); if (pa_tagstruct_gets(t, &name) < 0 || !name || @@ -1745,22 +1747,30 @@ static void command_add_autoload(struct pa_pdispatch *pd, uint32_t command, uint return; } - if (pa_autoload_add(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, module, argument) < 0) { + if (pa_autoload_add(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, module, argument, &index) < 0) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); return; } - pa_pstream_send_simple_ack(c->pstream, tag); + reply = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, index); + pa_pstream_send_tagstruct(c->pstream, reply); } static void command_remove_autoload(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - const char *name; - uint32_t type; + const char *name = NULL; + uint32_t type, index = PA_IDXSET_INVALID; + int r; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || !name || - pa_tagstruct_getu32(t, &type) < 0 || type > 1 || + if ((pa_tagstruct_getu32(t, &index) < 0 && + (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_getu32(t, &type) < 0)) || + (!name && index == PA_IDXSET_INVALID) || + (name && type > 1) || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1771,7 +1781,12 @@ static void command_remove_autoload(struct pa_pdispatch *pd, uint32_t command, u return; } - if (pa_autoload_remove(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE) < 0) { + if (name) + r = pa_autoload_remove_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE); + else + r = pa_autoload_remove_by_index(c->protocol->core, index); + + if (r < 0) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -1779,8 +1794,10 @@ static void command_remove_autoload(struct pa_pdispatch *pd, uint32_t command, u pa_pstream_send_simple_ack(c->pstream, tag); } -static void autoload_fill_tagstruct(struct pa_tagstruct *t, struct pa_autoload_entry *e) { +static void autoload_fill_tagstruct(struct pa_tagstruct *t, const struct pa_autoload_entry *e) { assert(t && e); + + pa_tagstruct_putu32(t, e->index); pa_tagstruct_puts(t, e->name); pa_tagstruct_putu32(t, e->type == PA_NAMEREG_SINK ? 0 : 1); pa_tagstruct_puts(t, e->module); @@ -1789,14 +1806,17 @@ static void autoload_fill_tagstruct(struct pa_tagstruct *t, struct pa_autoload_e static void command_get_autoload_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - struct pa_autoload_entry *a = NULL; - uint32_t type; + const struct pa_autoload_entry *a = NULL; + uint32_t type, index; const char *name; struct pa_tagstruct *reply; assert(c && t); - - if (pa_tagstruct_gets(t, &name) < 0 || name || - pa_tagstruct_getu32(t, &type) < 0 || type > 1 || + + if ((pa_tagstruct_getu32(t, &index) < 0 && + (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_getu32(t, &type) < 0)) || + (!name && index == PA_IDXSET_INVALID) || + (name && type > 1) || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1807,7 +1827,13 @@ static void command_get_autoload_info(struct pa_pdispatch *pd, uint32_t command, return; } - if (!c->protocol->core->autoload_hashmap || !(a = pa_hashmap_get(c->protocol->core->autoload_hashmap, name)) || (a->type == PA_NAMEREG_SINK && type != 0) || (a->type == PA_NAMEREG_SOURCE && type != 1)) { + + if (name) + a = pa_autoload_get_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE); + else + a = pa_autoload_get_by_index(c->protocol->core, index); + + if (!a) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } -- cgit From c82105d901682fdbecd409930fdf6d747d37809c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 27 Oct 2004 22:43:36 +0000 Subject: prepare next release 0.6 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@264 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 44 ++++++++++++++++++++++++++++++++++---------- doc/daemon.html.in | 4 ++++ doc/modules.html.in | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 10 deletions(-) diff --git a/doc/README.html.in b/doc/README.html.in index a0b3e641..22a30dc2 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -44,6 +44,18 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    News

    +
    Thu Oct 28 2004:

    Version 0.6 released; +changes include: TCP wrappers support; don't load the complete sound +file into memory when playing back using pa_play_file(); +autoload API change; don't load all sound files as FLOAT32; shorten +default buffers; client-side latency interpolation; add new user +volume metrics; add module-tunnel, module-null-sink, +module-match and new tool paplay; new API version +macros; many client API improvements; correctly lock cookie file +generation; correctly lock daemon autospawning; print daemon layout to +STDERR on SIGHUP; new options for pacat: allow sample type specification.

    +
    Mon Sep 24 2004:

    Version 0.5.1 released; changes include: improve esound protocol compatibility; fix @@ -96,6 +108,7 @@ Daemon (ESOUND). In addition to the features ESOUND provides

  • Module autoloading
  • Very accurate latency measurement for playback and recordin.
  • May be used to combine multiple sound cards to one (with sample rate adjustment)
  • +
  • Client side latency interpolation
  • Both the core and the client API are completely asynchronous making @@ -120,7 +133,10 @@ available. A simple main loop implementation is available as well.

  • module-native-protocol-tcp, module-native-protocol-unix: Native polypaudio protocol (for TCP/IP resp. UNIX domain sockets)
  • module-simple-protocol-tcp, module-simple-protocol-unix: Simplistic protocol for playback/capture for usage with tools like netcat (for TCP/IP resp. UNIX domain sockets)
  • module-cli-protocol-tcp, module-cli-protocol-unix, module-cli: Expose polypaudio's internals whith a simple command line interface. (for TCP/IP resp. UNIX domain sockets resp. STDIN/STDOUT)
  • - +
  • module-tunnel-sink, module-tunnel-source: make sinks/sources from other hosts available locally.
  • +
  • module-match: adjust volume automatically for newly created playback streams based on a regular expression matching table.
  • +
  • module-null-sink: a clocked sink similar to /dev/null.
  • +

    polypaudio is the successor of my previous, ill-fated attempt to write a sound server, Polypaudio Manager. Another GTK GUI tool for Polypaudio is the Polypaudio Volume Meter. There are output plugins for XMMS and libao. Drivers -for gstreamer and MPlayer will be released shortly.

    +href="http://0pointer.de/lennart/projects/xmms-polyp/">XMMS, libao and gstreamer. Drivers +for MPlayer and PortAudio will be released shortly.

    Status

    @@ -173,6 +188,10 @@ command line :

    The best idea is to configure your daemon in /etc/polypaudio/daemon.conf and /etc/polypaudio/default.pa and to run polypaudio without any arguments.

    +

    Beware! Unless you pass the option --sysconfdir=/etc to +configure, the directory /etc/polypaudio/ is really +/usr/local/etc/polypaudio/.

    +

    Developing polypaudio Clients

    You may browse the Doxygen generated -

    polypaudio needs polypaudio needs libwrap, Secret Rabbit Code (aka -libsamplerate), libsndfile, alsa-lib and GLIB. (The latter is required for building the GLIB main loop integration module only.)

    +libsamplerate), libsndfile, alsa-lib and GLIB. (The latter is required for +building the GLIB main loop integration module only.)

    Installation

    @@ -229,7 +251,7 @@ compilation and make install (as root) for installation of

    The current release is @PACKAGE_VERSION@

    -

    Get polypaudio's development sources from the Subversion repository (viewcvs):

    +

    Get polypaudio's development sources from the Subversion repository (viewcvs):

    svn checkout svn://seth.intheinter.net/polypaudio/trunk polypaudio
    @@ -237,8 +259,10 @@ compilation and make install (as root) for installation of

    New! There is a general discussion mailing list for polypaudio available.

    +

    New! There is now a Polypaudio wiki (based on trac) available.

    +
    -
    Lennart Poettering <@PACKAGE_BUGREPORT@>, September 2004
    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, October 2004
    $Id$
    diff --git a/doc/daemon.html.in b/doc/daemon.html.in index 147ee551..8d2414c0 100644 --- a/doc/daemon.html.in +++ b/doc/daemon.html.in @@ -62,6 +62,10 @@ The polypaudio daemon accepts several command line arguments:

    The daemon tries to load the module module-cli-protocol-unix, effectively providing a command line interface on a special UNIX domain socket.

    +

    SIGHUP

    + +

    The daemon logs the current server layout.

    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, September 2004
    $Id$
    diff --git a/doc/modules.html.in b/doc/modules.html.in index 4bf6044b..5e9b8873 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -44,6 +44,13 @@ special file in the file system. The source name defaults to pipe_input file=The name of the FIFO special file to use. (defaults to: /tmp/music.input) + +

    module-null-sink

    + +

    Provides a simple null sink. All data written to this sink is silently dropped. This sink is clocked using the system time.

    + +

    This module doesn't support any special parameters

    +

    module-alsa-sink

    @@ -116,6 +123,21 @@ be to slow on your machine try using zero-order-hold. This will decrease output quality however. (defaults to sinc-fastest) +

    module-tunnel-{sink,source}

    + +

    Tunnel a remote sink/source to a local "ghost" +sink/source. Requires a running polypaudio daemon on the remote server +with module-native-protocol-tcp loaded. It's probably a +better idea to connect to the remote sink/source directly since some +buffer control is lost through this tunneling.

    + + + + + + +
    server=The server to connect to
    source=The source on the remote server. Only available for module-tunnel-source.
    sink=The sink on the remote server. Only available for module-tunnel-sink.
    cookie=The authentication cookie file to use.
    +

    Protocols

    @@ -251,6 +273,22 @@ about the two possible suffixes of this module.

    This is a compatibility module for libesd based autospawning of polypaudio. Don't use it directly.

    +

    module-match

    + +

    Adjust the volume of a playback stream automatically based on its name.

    + + + +
    table=The regular expression matching table file to use
    + +

    The table file should contain a regexp and volume on each line, seperated by spaces. An example:

    + +
    +^sample: 25
    +
    + +

    The volumes of all streams with titles starting with sample: are automatically set to 25. (FYI: All sample cache streams start with sample:)

    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, September 2004
    $Id$
    -- cgit From e34c65d0427d7efc4d21a1df877bb5e4acc73154 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Oct 2004 14:41:46 +0000 Subject: require newer libsndfile update todo file git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@265 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- doc/todo | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 68df5b85..14a6842d 100644 --- a/configure.ac +++ b/configure.ac @@ -89,7 +89,7 @@ PKG_CHECK_MODULES(LIBSAMPLERATE, [ samplerate >= 0.1.0 ]) AC_SUBST(LIBSAMPLERATE_CFLAGS) AC_SUBST(LIBSAMPLERATE_LIBS) -PKG_CHECK_MODULES(LIBSNDFILE, [ sndfile >= 1.0.0 ]) +PKG_CHECK_MODULES(LIBSNDFILE, [ sndfile >= 1.0.10 ]) AC_SUBST(LIBSNDFILE_CFLAGS) AC_SUBST(LIBSNDFILE_LIBS) diff --git a/doc/todo b/doc/todo index 1ffdee49..f2155b99 100644 --- a/doc/todo +++ b/doc/todo @@ -22,7 +22,6 @@ backends for: - portaudio (semi-done) -- gstreamer (semi-done) - alsa-lib - sdl - OSS (esddsp style) -- cgit From 4e5c44de30de40b80354820f8ac1738a9636515a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Oct 2004 13:50:25 +0000 Subject: use setreuid() instead of setuid()/seteuid() when dropping root chdir to / on daemon startup (both are suggestions by alan cox) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@267 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/caps.c | 5 +++-- polyp/main.c | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/polyp/caps.c b/polyp/caps.c index 258e13e4..d03ab14b 100644 --- a/polyp/caps.c +++ b/polyp/caps.c @@ -43,8 +43,9 @@ void pa_drop_root(void) { pa_log(__FILE__": dropping root rights.\n"); - setuid(uid); - seteuid(uid); + setreuid(uid, uid); +/* setuid(uid); + seteuid(uid);*/ } #ifdef HAVE_SYS_CAPABILITY_H diff --git a/polyp/main.c b/polyp/main.c index 25fb1741..5be4118d 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -259,6 +259,7 @@ int main(int argc, char *argv[]) { close(1); } + chdir("/"); pa_log(__FILE__": sizeof(pa_usec_t) = %u\n", sizeof(pa_usec_t)); -- cgit From 899788b4c5e23af9dabfb98c5f864c2f933804f4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 30 Oct 2004 01:55:16 +0000 Subject: some updates for pa_hashmap add property infrastructure add module module-x11-publish allow ldpreloading of all modules abstract x11wrap from module-x11-bell git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@268 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 9 ++ polyp/Makefile.am | 61 ++++++++- polyp/cli-command.c | 11 +- polyp/cli-text.c | 2 +- polyp/core.c | 5 + polyp/core.h | 2 +- polyp/hashmap.c | 19 ++- polyp/hashmap.h | 12 +- polyp/main.c | 4 +- polyp/module-alsa-sink.c | 1 + polyp/module-alsa-source.c | 1 + polyp/module-cli.c | 1 + polyp/module-combine.c | 1 + polyp/module-defs.h.m4 | 21 +++ polyp/module-esound-compat-spawnfd.c | 1 + polyp/module-esound-compat-spawnpid.c | 1 + polyp/module-match.c | 1 + polyp/module-native-protocol-fd.c | 1 + polyp/module-null-sink.c | 1 + polyp/module-oss-mmap.c | 1 + polyp/module-oss.c | 1 + polyp/module-pipe-sink.c | 1 + polyp/module-pipe-source.c | 1 + polyp/module-protocol-stub.c | 26 +++- polyp/module-sine.c | 1 + polyp/module-tunnel.c | 8 +- polyp/module-x11-bell.c | 84 +++++------- polyp/module-x11-publish.c | 167 ++++++++++++++++++++++++ polyp/module.h | 12 +- polyp/namereg.c | 6 +- polyp/polyplib-internal.h | 2 - polyp/props.c | 112 ++++++++++++++++ polyp/props.h | 55 ++++++++ polyp/protocol-native.c | 2 +- polyp/x11wrap.c | 235 ++++++++++++++++++++++++++++++++++ polyp/x11wrap.h | 52 ++++++++ 36 files changed, 829 insertions(+), 92 deletions(-) create mode 100644 polyp/module-defs.h.m4 create mode 100644 polyp/module-x11-publish.c create mode 100644 polyp/props.c create mode 100644 polyp/props.h create mode 100644 polyp/x11wrap.c create mode 100644 polyp/x11wrap.h diff --git a/doc/todo b/doc/todo index f2155b99..8212ea89 100644 --- a/doc/todo +++ b/doc/todo @@ -12,6 +12,15 @@ - add sync API - make most buffer sizes dependant on the sample type +- X11: support for the X11 synchronization extension +- X11: save auth info in root window +- pass meta info for hearing impaired +- fall back to getpwnam if $HOME doesn't exist +- module-match: look in $HOME for table +- limit all resources +- getaddrinfo +- add LGPL blurb to all concerning files + ** later *** - xmlrpc/http - dbus diff --git a/polyp/Makefile.am b/polyp/Makefile.am index ae551a1b..d90d3229 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -32,7 +32,7 @@ AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\" AM_LDADD=$(PTHREAD_LIBS) -lm AM_LIBADD=$(PTHREAD_LIBS) -lm -EXTRA_DIST = default.pa.in daemon.conf.in client.conf.in depmod.py esdcompat.sh.in +EXTRA_DIST = default.pa.in daemon.conf.in client.conf.in depmod.py esdcompat.sh.in module-defs.h.m4 bin_PROGRAMS = polypaudio pacat pactl paplay bin_SCRIPTS = esdcompat.sh noinst_PROGRAMS = \ @@ -112,6 +112,33 @@ modlib_LTLIBRARIES= \ module-tunnel-source.la \ module-null-sink.la +SYMDEF_FILES= \ + module-cli-symdef.h \ + module-cli-protocol-tcp-symdef.h \ + module-cli-protocol-unix-symdef.h \ + module-pipe-sink-symdef.h \ + module-pipe-source-symdef.h \ + module-oss-symdef.h \ + module-oss-mmap-symdef.h \ + module-simple-protocol-tcp-symdef.h \ + module-simple-protocol-unix-symdef.h \ + module-esound-protocol-tcp-symdef.h \ + module-esound-protocol-unix-symdef.h \ + module-native-protocol-tcp-symdef.h \ + module-native-protocol-unix-symdef.h \ + module-native-protocol-fd-symdef.h \ + module-sine-symdef.h \ + module-combine-symdef.h \ + module-esound-compat-spawnfd-symdef.h \ + module-esound-compat-spawnpid-symdef.h \ + module-match-symdef.h \ + module-tunnel-sink-symdef.h \ + module-tunnel-source-symdef.h \ + module-null-sink-symdef.h + +EXTRA_DIST+=$(SYMDEF_FILES) +BUILT_SOURCES+=$(SYMDEF_FILES) + lib_LTLIBRARIES= \ libpolyp-@PA_MAJORMINOR@.la \ libpolyp-error-@PA_MAJORMINOR@.la \ @@ -167,12 +194,14 @@ polypaudio_SOURCES = idxset.c idxset.h \ daemon-conf.c daemon-conf.h \ dumpmodules.c dumpmodules.h \ conf-parser.h conf-parser.c \ - caps.h caps.c + caps.h caps.c \ + props.h props.c polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) -polypaudio_LDFLAGS=-export-dynamic +polypaudio_LDFLAGS= -export-dynamic -dlopen force +#-static $(foreach f,$(modlib_LTLIBRARIES),-dlpreopen $(f)) libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h libprotocol_simple_la_LDFLAGS = -avoid-version @@ -430,12 +459,28 @@ cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la if HAVE_X11 modlib_LTLIBRARIES+= \ - module-x11-bell.la + libx11wrap.la \ + module-x11-bell.la \ + module-x11-publish.la +SYMDEF_FILES += \ + module-x11-bell-symdef.h \ + module-x11-publish-symdef.h + +libx11wrap_la_SOURCES = x11wrap.c x11wrap.h +libx11wrap_la_LDFLAGS = -avoid-version +libx11wrap_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) +libx11wrap_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) module_x11_bell_la_SOURCES = module-x11-bell.c module_x11_bell_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) module_x11_bell_la_LDFLAGS = -module -avoid-version -module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) +module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) libx11wrap.la + +module_x11_publish_la_SOURCES = module-x11-publish.c +module_x11_publish_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) +module_x11_publish_la_LDFLAGS = -module -avoid-version +module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) libx11wrap.la + endif ### ALSA modules @@ -445,6 +490,9 @@ modlib_LTLIBRARIES+= \ libalsa-util.la \ module-alsa-sink.la \ module-alsa-source.la +SYMDEF_FILES += \ + module-alsa-sink-symdef.h \ + module-alsa-source-symdef.h libalsa_util_la_SOURCES = alsa-util.c alsa-util.h libalsa_util_la_LDFLAGS = -avoid-version @@ -597,3 +645,6 @@ daemon.conf: daemon.conf.in Makefile install-exec-hook: chown root:root $(DESTDIR)$(bindir)/polypaudio chmod u+s $(DESTDIR)$(bindir)/polypaudio + +$(SYMDEF_FILES): module-defs.h.m4 + m4 -Dfname="$@" $< > $@ diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 62981b4d..d563a072 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -47,6 +47,7 @@ #include "autoload.h" #include "xmalloc.h" #include "sound-file-stream.h" +#include "props.h" struct command { const char *name; @@ -83,6 +84,7 @@ static int pa_cli_command_autoload_list(struct pa_core *c, struct pa_tokenizer * static int pa_cli_command_autoload_add(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); static int pa_cli_command_autoload_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_list_props(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 }, @@ -118,6 +120,7 @@ static const struct command commands[] = { { "remove-autoload-sink", pa_cli_command_autoload_remove, "Remove autoload entry for a sink (args: name)", 2}, { "remove-autoload-source", pa_cli_command_autoload_remove, "Remove autoload entry for a source (args: name)", 2}, { "dump", pa_cli_command_dump, "Dump daemon configuration", 1}, + { "list-props", pa_cli_command_list_props, NULL, 1}, { NULL, NULL, NULL, 0 } }; @@ -602,6 +605,12 @@ static int pa_cli_command_autoload_list(struct pa_core *c, struct pa_tokenizer * return 0; } +static int pa_cli_command_list_props(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + assert(c && t); + pa_property_dump(c, buf); + return 0; +} + static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { struct pa_module *m; struct pa_sink *s; @@ -654,7 +663,7 @@ static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct nl = 0; i = NULL; - while ((a = pa_hashmap_iterate(c->autoload_hashmap, &i))) { + while ((a = pa_hashmap_iterate(c->autoload_hashmap, &i, NULL))) { if (!nl) { pa_strbuf_puts(buf, "\n"); diff --git a/polyp/cli-text.c b/polyp/cli-text.c index c08b0d9c..39f7b6ed 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -271,7 +271,7 @@ char *pa_autoload_list_to_string(struct pa_core *c) { struct pa_autoload_entry *e; void *state = NULL; - while ((e = pa_hashmap_iterate(c->autoload_hashmap, &state))) { + while ((e = pa_hashmap_iterate(c->autoload_hashmap, &state, NULL))) { pa_strbuf_printf( s, " name: <%s>\n\ttype: <%s>\n\tindex: <%u>\n\tmodule_name: <%s>\n\targuments: <%s>\n", e->name, diff --git a/polyp/core.c b/polyp/core.c index c53d2e4e..6e155dda 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -39,6 +39,7 @@ #include "autoload.h" #include "xmalloc.h" #include "subscribe.h" +#include "props.h" struct pa_core* pa_core_new(struct pa_mainloop_api *m) { struct pa_core* c; @@ -82,6 +83,8 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->scache_idle_time = 20; c->resample_method = SRC_SINC_FASTEST; + + pa_property_init(c); pa_check_signal_is_blocked(SIGPIPE); @@ -121,6 +124,8 @@ void pa_core_free(struct pa_core *c) { pa_xfree(c->default_sink_name); pa_memblock_stat_unref(c->memblock_stat); + + pa_property_cleanup(c); pa_xfree(c); } diff --git a/polyp/core.h b/polyp/core.h index c457c3fd..1438bf72 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -33,7 +33,7 @@ struct pa_core { struct pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache, *autoload_idxset; - struct pa_hashmap *namereg, *autoload_hashmap; + struct pa_hashmap *namereg, *autoload_hashmap, *properties; char *default_source_name, *default_sink_name; diff --git a/polyp/hashmap.c b/polyp/hashmap.c index 2b9550fd..10b148dd 100644 --- a/polyp/hashmap.c +++ b/polyp/hashmap.c @@ -30,6 +30,7 @@ #include "hashmap.h" #include "idxset.h" #include "xmalloc.h" +#include "log.h" struct hashmap_entry { struct hashmap_entry *next, *previous, *bucket_next, *bucket_previous; @@ -147,25 +148,27 @@ void* pa_hashmap_get(struct pa_hashmap *h, const void *key) { return e->value; } -int pa_hashmap_remove(struct pa_hashmap *h, const void *key) { +void* pa_hashmap_remove(struct pa_hashmap *h, const void *key) { struct hashmap_entry *e; unsigned hash; + void *data; assert(h && key); hash = h->hash_func(key) % h->size; if (!(e = get(h, hash, key))) - return 1; + return NULL; + data = e->value; remove(h, e); - return 0; + return data; } unsigned pa_hashmap_ncontents(struct pa_hashmap *h) { return h->n_entries; } -void *pa_hashmap_iterate(struct pa_hashmap *h, void **state) { +void *pa_hashmap_iterate(struct pa_hashmap *h, void **state, const void **key) { assert(h && state); if (!*state) { @@ -173,8 +176,14 @@ void *pa_hashmap_iterate(struct pa_hashmap *h, void **state) { } else *state = ((struct hashmap_entry*) *state)->next; - if (!*state) + if (!*state) { + if (key) + *key = NULL; return NULL; + } + + if (key) + *key = ((struct hashmap_entry*) *state)->key; return ((struct hashmap_entry*) *state)->value; } diff --git a/polyp/hashmap.h b/polyp/hashmap.h index 3b79d7ae..739f8947 100644 --- a/polyp/hashmap.h +++ b/polyp/hashmap.h @@ -30,13 +30,15 @@ void pa_hashmap_free(struct pa_hashmap*, void (*free_func)(void *p, void *userda int pa_hashmap_put(struct pa_hashmap *h, const void *key, void *value); void* pa_hashmap_get(struct pa_hashmap *h, const void *key); -int pa_hashmap_remove(struct pa_hashmap *h, const void *key); +void* pa_hashmap_remove(struct pa_hashmap *h, const void *key); unsigned pa_hashmap_ncontents(struct pa_hashmap *h); -/* Maybe used to iterate through the hashmap. Initial state should - point to a NULL pointer. The hashmap may not be modified during - iteration */ -void *pa_hashmap_iterate(struct pa_hashmap *h, void **state); +/* May be used to iterate through the hashmap. Initially the opaque + pointer *state has to be set to NULL. The hashmap may not be + modified during iteration. The key of the entry is returned in + *key, if key is non-NULL. After the last entry in the hashmap NULL + is returned. */ +void *pa_hashmap_iterate(struct pa_hashmap *h, void **state, const void**key); #endif diff --git a/polyp/main.c b/polyp/main.c index 5be4118d..378cb8a0 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -152,9 +152,11 @@ int main(int argc, char *argv[]) { pa_drop_root(); } + LTDL_SET_PRELOADED_SYMBOLS(); + r = lt_dlinit(); assert(r == 0); - + pa_log_set_ident("polypaudio"); conf = pa_daemon_conf_new(); diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index 528fe8d3..e319f6c1 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -39,6 +39,7 @@ #include "alsa-util.h" #include "xmalloc.h" #include "log.h" +#include "module-alsa-sink-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ALSA Sink") diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index c0a18d2b..34f08f95 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -39,6 +39,7 @@ #include "alsa-util.h" #include "xmalloc.h" #include "log.h" +#include "module-alsa-source-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ALSA Source") diff --git a/polyp/module-cli.c b/polyp/module-cli.c index 6444194c..1ebc9b52 100644 --- a/polyp/module-cli.c +++ b/polyp/module-cli.c @@ -32,6 +32,7 @@ #include "cli.h" #include "sioman.h" #include "log.h" +#include "module-cli-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Command line interface") diff --git a/polyp/module-combine.c b/polyp/module-combine.c index 1a909087..5df3f158 100644 --- a/polyp/module-combine.c +++ b/polyp/module-combine.c @@ -36,6 +36,7 @@ #include "xmalloc.h" #include "modargs.h" #include "namereg.h" +#include "module-combine-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Combine multiple sinks to one") diff --git a/polyp/module-defs.h.m4 b/polyp/module-defs.h.m4 new file mode 100644 index 00000000..85eb64a2 --- /dev/null +++ b/polyp/module-defs.h.m4 @@ -0,0 +1,21 @@ +dnl $Id$ +changecom(`/*', `*/')dnl +define(`module', patsubst(patsubst(fname, `-symdef.h$'), `[^0-9a-zA-Z]', `_'))dnl +define(`c_symbol', patsubst(module, `[^0-9a-zA-Z]', `_'))dnl +define(`c_macro', patsubst(module, `[^0-9a-zA-Z]', `'))dnl +define(`incmacro', `foo'c_macro`symdeffoo')dnl +define(`gen_symbol', `#define $1 'module`_LTX_$1')dnl +#ifndef incmacro +#define incmacro + +gen_symbol(pa__init) +gen_symbol(pa__done) +gen_symbol(pa__get_author) +gen_symbol(pa__get_description) +gen_symbol(pa__get_usage) +gen_symbol(pa__get_version) + +int pa__init(struct pa_core *c, struct pa_module*m); +void pa__done(struct pa_core *c, struct pa_module*m); + +#endif diff --git a/polyp/module-esound-compat-spawnfd.c b/polyp/module-esound-compat-spawnfd.c index 514159fc..ae4f9095 100644 --- a/polyp/module-esound-compat-spawnfd.c +++ b/polyp/module-esound-compat-spawnfd.c @@ -32,6 +32,7 @@ #include "util.h" #include "modargs.h" #include "log.h" +#include "module-esound-compat-spawnfd-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ESOUND compatibility module: -spawnfd emulation") diff --git a/polyp/module-esound-compat-spawnpid.c b/polyp/module-esound-compat-spawnpid.c index 5583f071..02756cdb 100644 --- a/polyp/module-esound-compat-spawnpid.c +++ b/polyp/module-esound-compat-spawnpid.c @@ -32,6 +32,7 @@ #include "util.h" #include "modargs.h" #include "log.h" +#include "module-esound-compat-spawnpid-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ESOUND compatibility module: -spawnpid emulation") diff --git a/polyp/module-match.c b/polyp/module-match.c index 380c6011..6689cc59 100644 --- a/polyp/module-match.c +++ b/polyp/module-match.c @@ -39,6 +39,7 @@ #include "subscribe.h" #include "xmalloc.h" #include "sink-input.h" +#include "module-match-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Sink input matching module") diff --git a/polyp/module-native-protocol-fd.c b/polyp/module-native-protocol-fd.c index c1ea6975..8f41db64 100644 --- a/polyp/module-native-protocol-fd.c +++ b/polyp/module-native-protocol-fd.c @@ -32,6 +32,7 @@ #include "modargs.h" #include "protocol-native.h" #include "log.h" +#include "module-native-protocol-fd-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Native protocol autospawn helper") diff --git a/polyp/module-null-sink.c b/polyp/module-null-sink.c index 86542010..4a41b74d 100644 --- a/polyp/module-null-sink.c +++ b/polyp/module-null-sink.c @@ -40,6 +40,7 @@ #include "modargs.h" #include "xmalloc.h" #include "log.h" +#include "module-null-sink-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Clocked NULL sink") diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index f7fcbd3b..bc36d199 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -46,6 +46,7 @@ #include "modargs.h" #include "xmalloc.h" #include "log.h" +#include "module-oss-mmap-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("OSS Sink/Source (mmap)") diff --git a/polyp/module-oss.c b/polyp/module-oss.c index c0c6be8e..969761f6 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -45,6 +45,7 @@ #include "modargs.h" #include "xmalloc.h" #include "log.h" +#include "module-oss-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("OSS Sink/Source") diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c index 7c779f7d..bc8abb41 100644 --- a/polyp/module-pipe-sink.c +++ b/polyp/module-pipe-sink.c @@ -40,6 +40,7 @@ #include "modargs.h" #include "xmalloc.h" #include "log.h" +#include "module-pipe-sink-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("UNIX pipe sink") diff --git a/polyp/module-pipe-source.c b/polyp/module-pipe-source.c index 3decc415..8bc4c477 100644 --- a/polyp/module-pipe-source.c +++ b/polyp/module-pipe-source.c @@ -40,6 +40,7 @@ #include "modargs.h" #include "xmalloc.h" #include "log.h" +#include "module-pipe-source-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("UNIX pipe source") diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index 1ff70a1a..8cef3bdb 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -39,9 +39,6 @@ #include "log.h" #include "native-common.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_VERSION(PACKAGE_VERSION) - #ifdef USE_TCP_SOCKETS #define SOCKET_DESCRIPTION "(TCP sockets)" #define SOCKET_USAGE "port= loopback=" @@ -58,6 +55,11 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define IPV4_PORT 4711 #define UNIX_SOCKET "/tmp/polypaudio/simple" #define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record", + #ifdef USE_TCP_SOCKETS + #include "module-simple-protocol-tcp-symdef.h" + #else + #include "module-simple-protocol-unix-symdef.h" + #endif PA_MODULE_DESCRIPTION("Simple protocol "SOCKET_DESCRIPTION) PA_MODULE_USAGE("rate= format= channels= sink= source= playback= record= "SOCKET_USAGE) #elif defined(USE_PROTOCOL_CLI) @@ -68,6 +70,11 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define IPV4_PORT 4712 #define UNIX_SOCKET "/tmp/polypaudio/cli" #define MODULE_ARGUMENTS + #ifdef USE_TCP_SOCKETS + #include "module-cli-protocol-tcp-symdef.h" + #else + #include "module-cli-protocol-unix-symdef.h" + #endif PA_MODULE_DESCRIPTION("Command line interface protocol "SOCKET_DESCRIPTION) PA_MODULE_USAGE(SOCKET_USAGE) #elif defined(USE_PROTOCOL_NATIVE) @@ -78,6 +85,11 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define IPV4_PORT PA_NATIVE_DEFAULT_PORT #define UNIX_SOCKET "/tmp/polypaudio/native" #define MODULE_ARGUMENTS "public", "cookie", + #ifdef USE_TCP_SOCKETS + #include "module-native-protocol-tcp-symdef.h" + #else + #include "module-native-protocol-unix-symdef.h" + #endif PA_MODULE_DESCRIPTION("Native protocol "SOCKET_DESCRIPTION) PA_MODULE_USAGE("public= cookie= "SOCKET_USAGE) #elif defined(USE_PROTOCOL_ESOUND) @@ -89,12 +101,20 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define IPV4_PORT ESD_DEFAULT_PORT #define UNIX_SOCKET ESD_UNIX_SOCKET_NAME #define MODULE_ARGUMENTS "sink", "source", "public", "cookie", + #ifdef USE_TCP_SOCKETS + #include "module-esound-protocol-tcp-symdef.h" + #else + #include "module-esound-protocol-unix-symdef.h" + #endif PA_MODULE_DESCRIPTION("EsounD protocol "SOCKET_DESCRIPTION) PA_MODULE_USAGE("sink= source= public= cookie= "SOCKET_USAGE) #else #error "Broken build system" #endif +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_VERSION(PACKAGE_VERSION) + static const char* const valid_modargs[] = { MODULE_ARGUMENTS #ifdef USE_TCP_SOCKETS diff --git a/polyp/module-sine.c b/polyp/module-sine.c index 458b8788..393f929a 100644 --- a/polyp/module-sine.c +++ b/polyp/module-sine.c @@ -33,6 +33,7 @@ #include "xmalloc.h" #include "namereg.h" #include "log.h" +#include "module-sine-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Sine wave generator") diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c index 1a720f3b..2e22258a 100644 --- a/polyp/module-tunnel.c +++ b/polyp/module-tunnel.c @@ -46,17 +46,19 @@ #include "socket-client.h" #include "socket-util.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_VERSION(PACKAGE_VERSION) - #ifdef TUNNEL_SINK +#include "module-tunnel-sink-symdef.h" PA_MODULE_DESCRIPTION("Tunnel module for sinks") PA_MODULE_USAGE("server= sink= cookie= format= channels= rate= sink_name=") #else +#include "module-tunnel-source-symdef.h" PA_MODULE_DESCRIPTION("Tunnel module for sources") PA_MODULE_USAGE("server= source= cookie= format= channels= rate= source_name=") #endif +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_VERSION(PACKAGE_VERSION) + #define DEFAULT_SINK_NAME "tunnel" #define DEFAULT_SOURCE_NAME "tunnel" diff --git a/polyp/module-x11-bell.c b/polyp/module-x11-bell.c index ae69f9cb..23433c8f 100644 --- a/polyp/module-x11-bell.c +++ b/polyp/module-x11-bell.c @@ -38,25 +38,23 @@ #include "xmalloc.h" #include "namereg.h" #include "log.h" +#include "x11wrap.h" +#include "module-x11-bell-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("X11 Bell interceptor") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink= sample= display=") -struct x11_source { - struct pa_io_event *io_event; - struct x11_source *next; -}; - struct userdata { struct pa_core *core; - Display *display; - struct x11_source *x11_sources; int xkb_event_base; - char *sink_name; char *scache_item; + Display *display; + + struct pa_x11_wrapper *x11_wrapper; + struct pa_x11_client *x11_client; }; static const char* const valid_modargs[] = { @@ -79,35 +77,22 @@ static int ring_bell(struct userdata *u, int percent) { return 0; } -static void io_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { +static int x11_event_callback(struct pa_x11_wrapper *w, XEvent *e, void *userdata) { + XkbBellNotifyEvent *bne; struct userdata *u = userdata; - assert(u); - - while (XPending(u->display)) { - XEvent e; - XkbBellNotifyEvent *bne; - XNextEvent(u->display, &e); - - if (((XkbEvent*) &e)->any.xkb_type != XkbBellNotify) - continue; - - bne = ((XkbBellNotifyEvent*) &e); - - if (ring_bell(u, bne->percent) < 0) { - pa_log(__FILE__": Ringing bell failed, reverting to X11 device bell.\n"); - XkbForceDeviceBell(u->display, bne->device, bne->bell_class, bne->bell_id, bne->percent); - } - } -} + assert(w && e && u && u->x11_wrapper == w); + + if (((XkbEvent*) e)->any.xkb_type != XkbBellNotify) + return 0; + + bne = (XkbBellNotifyEvent*) e; -static void new_io_source(struct userdata *u, int fd) { - struct x11_source *s; + if (ring_bell(u, bne->percent) < 0) { + pa_log(__FILE__": Ringing bell failed, reverting to X11 device bell.\n"); + XkbForceDeviceBell(pa_x11_wrapper_get_display(w), bne->device, bne->bell_class, bne->bell_id, bne->percent); + } - s = pa_xmalloc(sizeof(struct x11_source)); - s->io_event = u->core->mainloop->io_new(u->core->mainloop, fd, PA_IO_EVENT_INPUT, io_callback, u); - assert(s->io_event); - s->next = u->x11_sources; - u->x11_sources = s; + return 1; } int pa__init(struct pa_core *c, struct pa_module*m) { @@ -124,18 +109,15 @@ int pa__init(struct pa_core *c, struct pa_module*m) { m->userdata = u = pa_xmalloc(sizeof(struct userdata)); u->core = c; - u->display = NULL; - u->x11_sources = NULL; u->scache_item = pa_xstrdup(pa_modargs_get_value(ma, "sample", "x11-bell")); u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); + u->x11_client = NULL; - if (!(u->display = XOpenDisplay(pa_modargs_get_value(ma, "display", NULL)))) { - pa_log(__FILE__": XOpenDisplay() failed\n"); + if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL)))) goto fail; - } - - new_io_source(u, ConnectionNumber(u->display)); + u->display = pa_x11_wrapper_get_display(u->x11_wrapper); + major = XkbMajorVersion; minor = XkbMinorVersion; @@ -147,6 +129,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { major = XkbMajorVersion; minor = XkbMinorVersion; + if (!XkbQueryExtension(u->display, NULL, &u->xkb_event_base, NULL, &major, &minor)) { pa_log(__FILE__": XkbQueryExtension() failed\n"); goto fail; @@ -157,6 +140,8 @@ int pa__init(struct pa_core *c, struct pa_module*m) { XkbSetAutoResetControls(u->display, XkbAudibleBellMask, &auto_ctrls, &auto_values); XkbChangeEnabledControls(u->display, XkbUseCoreKbd, XkbAudibleBellMask, 0); + u->x11_client = pa_x11_client_new(u->x11_wrapper, x11_event_callback, u); + pa_modargs_free(ma); return 0; @@ -173,17 +158,14 @@ void pa__done(struct pa_core *c, struct pa_module*m) { struct userdata *u = m->userdata; assert(c && m && u); - while (u->x11_sources) { - struct x11_source *s = u->x11_sources; - u->x11_sources = u->x11_sources->next; - c->mainloop->io_free(s->io_event); - pa_xfree(s); - } - pa_xfree(u->scache_item); pa_xfree(u->sink_name); - - if (u->display) - XCloseDisplay(u->display); + + if (u->x11_client) + pa_x11_client_free(u->x11_client); + + if (u->x11_wrapper) + pa_x11_wrapper_unref(u->x11_wrapper); + pa_xfree(u); } diff --git a/polyp/module-x11-publish.c b/polyp/module-x11-publish.c new file mode 100644 index 00000000..fd4df4ad --- /dev/null +++ b/polyp/module-x11-publish.c @@ -0,0 +1,167 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include "module.h" +#include "sink.h" +#include "scache.h" +#include "modargs.h" +#include "xmalloc.h" +#include "namereg.h" +#include "log.h" +#include "x11wrap.h" +#include "util.h" + +#include "module-x11-publish-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("X11 Credential Publisher") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("display=") + +static const char* const valid_modargs[] = { + "display", + "sink", + "source", + NULL +}; + +struct userdata { + struct pa_core *core; + struct pa_x11_wrapper *x11_wrapper; + Display *display; + char *id; +}; + +static void set_x11_prop(Display *d, const char *name, const char *data) { + Atom a = XInternAtom(d, name, False); + XChangeProperty(d, RootWindow(d, 0), a, XA_STRING, 8, PropModeReplace, (unsigned char*) data, strlen(data)+1); +} + +static void del_x11_prop(Display *d, const char *name) { + Atom a = XInternAtom(d, name, False); + XDeleteProperty(d, RootWindow(d, 0), a); +} + +static char* get_x11_prop(Display *d, const char *name, char *p, size_t l) { + Atom actual_type; + int actual_format; + unsigned long nitems; + unsigned long nbytes_after; + unsigned char *prop; + + Atom a = XInternAtom(d, name, False); + if (XGetWindowProperty(d, RootWindow(d, 0), a, 0, (l+2)/4, False, XA_STRING, &actual_type, &actual_format, &nitems, &nbytes_after, &prop) != Success) + return NULL; + + memcpy(p, prop, nitems); + p[nitems] = 0; + + XFree(prop); + return p; +} + +int pa__init(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + struct pa_modargs *ma = NULL; + char hn[256], un[128]; + const char *t; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments\n"); + goto fail; + } + + m->userdata = u = pa_xmalloc(sizeof(struct userdata)); + u->core = c; + u->id = NULL; + + if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL)))) + goto fail; + + u->display = pa_x11_wrapper_get_display(u->x11_wrapper); + + pa_get_host_name(hn, sizeof(hn)); + pa_get_user_name(un, sizeof(un)); + + u->id = pa_sprintf_malloc("%s@%s/%u", un, hn, (unsigned) getpid()); + + set_x11_prop(u->display, "POLYP_SERVER", hn); + set_x11_prop(u->display, "POLYP_ID", u->id); + + if ((t = pa_modargs_get_value(ma, "source", NULL))) + set_x11_prop(u->display, "POLYP_SOURCE", t); + + if ((t = pa_modargs_get_value(ma, "sink", NULL))) + set_x11_prop(u->display, "POLYP_SINK", t); + + pa_modargs_free(ma); + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + pa__done(c, m); + return -1; +} + +void pa__done(struct pa_core *c, struct pa_module*m) { + struct userdata*u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->x11_wrapper) { + char t[256]; + + /* Yes, here is a race condition */ + if (!get_x11_prop(u->display, "POLYP_ID", t, sizeof(t)) || strcmp(t, u->id)) + pa_log("WARNING: Polypaudio information vanished from X11!\n"); + else { + del_x11_prop(u->display, "POLYP_ID"); + del_x11_prop(u->display, "POLYP_SERVER"); + del_x11_prop(u->display, "POLYP_SINK"); + del_x11_prop(u->display, "POLYP_SOURCE"); + XSync(u->display, False); + } + } + + if (u->x11_wrapper) + pa_x11_wrapper_unref(u->x11_wrapper); + + pa_xfree(u->id); + pa_xfree(u); +} + diff --git a/polyp/module.h b/polyp/module.h index f422132a..7380f795 100644 --- a/polyp/module.h +++ b/polyp/module.h @@ -58,14 +58,10 @@ void pa_module_unload_request(struct pa_module *m); void pa_module_set_used(struct pa_module*m, int used); -/* prototypes for the module's entry points */ -int pa__init(struct pa_core *c, struct pa_module*m); -void pa__done(struct pa_core *c, struct pa_module*m); - -#define PA_MODULE_AUTHOR(s) const char *pa__get_author(void) { return s; } -#define PA_MODULE_DESCRIPTION(s) const char *pa__get_description(void) { return s; } -#define PA_MODULE_USAGE(s) const char *pa__get_usage(void) { return s; } -#define PA_MODULE_VERSION(s) const char *pa__get_version(void) { return s; } +#define PA_MODULE_AUTHOR(s) const char * pa__get_author(void) { return s; } +#define PA_MODULE_DESCRIPTION(s) const char * pa__get_description(void) { return s; } +#define PA_MODULE_USAGE(s) const char * pa__get_usage(void) { return s; } +#define PA_MODULE_VERSION(s) const char * pa__get_version(void) { return s; } struct pa_modinfo *pa_module_get_info(struct pa_module *m); diff --git a/polyp/namereg.c b/polyp/namereg.c index e2f65efd..cc25ea2b 100644 --- a/polyp/namereg.c +++ b/polyp/namereg.c @@ -100,15 +100,11 @@ const char *pa_namereg_register(struct pa_core *c, const char *name, enum pa_nam void pa_namereg_unregister(struct pa_core *c, const char *name) { struct namereg_entry *e; - int r; assert(c && name); - e = pa_hashmap_get(c->namereg, name); + e = pa_hashmap_remove(c->namereg, name); assert(e); - r = pa_hashmap_remove(c->namereg, name); - assert(r >= 0); - pa_xfree(e->name); pa_xfree(e); } diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index e49b25d4..623a89b3 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -43,8 +43,6 @@ #define DEFAULT_TIMEOUT (10) -#define ENV_AUTOSPAWNED "POLYP_AUTOSPAWNED" - struct pa_context { int ref; diff --git a/polyp/props.c b/polyp/props.c new file mode 100644 index 00000000..014059ec --- /dev/null +++ b/polyp/props.c @@ -0,0 +1,112 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "xmalloc.h" +#include "props.h" +#include "log.h" + +struct pa_property { + char *name; /* Points to memory allocated by the property subsystem */ + void *data; /* Points to memory maintained by the caller */ +}; + +/* Allocate a new property object */ +static struct pa_property* property_new(const char *name, void *data) { + struct pa_property* p; + assert(name && data); + + p = pa_xmalloc(sizeof(struct pa_property)); + p->name = pa_xstrdup(name); + p->data = data; + + return p; +} + +/* Free a property object */ +static void property_free(struct pa_property *p) { + assert(p); + + pa_xfree(p->name); + pa_xfree(p); +} + +void* pa_property_get(struct pa_core *c, const char *name) { + struct pa_property *p; + assert(c && name && c->properties); + + if (!(p = pa_hashmap_get(c->properties, name))) + return NULL; + + return p->data; +} + +int pa_property_set(struct pa_core *c, const char *name, void *data) { + struct pa_property *p; + assert(c && name && data && c->properties); + + if (pa_hashmap_get(c->properties, name)) + return -1; + + p = property_new(name, data); + pa_hashmap_put(c->properties, p->name, p); + return 0; +} + +int pa_property_remove(struct pa_core *c, const char *name) { + struct pa_property *p; + assert(c && name && c->properties); + + if (!(p = pa_hashmap_remove(c->properties, name))) + return -1; + + property_free(p); + return 0; +} + +void pa_property_init(struct pa_core *c) { + assert(c); + + c->properties = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); +} + +void pa_property_cleanup(struct pa_core *c) { + assert(c); + + if (!c->properties) + return; + + assert(!pa_hashmap_ncontents(c->properties)); + + pa_hashmap_free(c->properties, NULL, NULL); + c->properties = NULL; + +} + +void pa_property_dump(struct pa_core *c, struct pa_strbuf *s) { + void *state = NULL; + struct pa_property *p; + assert(c && s); + + while ((p = pa_hashmap_iterate(c->properties, &state, NULL))) + pa_strbuf_printf(s, "[%s] -> [%p]\n", p->name, p->data); +} diff --git a/polyp/props.h b/polyp/props.h new file mode 100644 index 00000000..f19e9260 --- /dev/null +++ b/polyp/props.h @@ -0,0 +1,55 @@ +#ifndef foopropshfoo +#define foopropshfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" +#include "strbuf.h" + +/* The property subsystem is to be used to share data between + * modules. Consider them to be kind of "global" variables for a + * core. Why not use the hashmap functions directly? The hashmap + * functions copy neither the key nor value, while this property + * system copies the key. Users of this system have to think about + * reference counting themselves. */ + +/* Return a pointer to the value of the specified property. */ +void* pa_property_get(struct pa_core *c, const char *name); + +/* Set the property 'name' to 'data'. This function fails in case a + * property by this name already exists. The property data is not + * copied or reference counted. This is the caller's job. */ +int pa_property_set(struct pa_core *c, const char *name, void *data); + +/* Remove the specified property. Return non-zero on failure */ +int pa_property_remove(struct pa_core *c, const char *name); + +/* Free all memory used by the property system */ +void pa_property_cleanup(struct pa_core *c); + +/* Initialize the properties subsystem */ +void pa_property_init(struct pa_core *c); + +/* Dump the current set of properties */ +void pa_property_dump(struct pa_core *c, struct pa_strbuf *s); + +#endif diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 7af8bdda..6f3f82be 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -1869,7 +1869,7 @@ static void command_get_autoload_info_list(struct pa_pdispatch *pd, uint32_t com struct pa_autoload_entry *a; void *state = NULL; - while ((a = pa_hashmap_iterate(c->protocol->core->autoload_hashmap, &state))) + while ((a = pa_hashmap_iterate(c->protocol->core->autoload_hashmap, &state, NULL))) autoload_fill_tagstruct(reply, a); } diff --git a/polyp/x11wrap.c b/polyp/x11wrap.c new file mode 100644 index 00000000..a1a9732a --- /dev/null +++ b/polyp/x11wrap.c @@ -0,0 +1,235 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include "llist.h" +#include "x11wrap.h" +#include "xmalloc.h" +#include "log.h" +#include "props.h" + +struct pa_x11_client; + +struct pa_x11_internal { + PA_LLIST_FIELDS(struct pa_x11_internal); + struct pa_x11_wrapper *wrapper; + struct pa_io_event* io_event; + int fd; +}; + +struct pa_x11_wrapper { + struct pa_core *core; + int ref; + + char *property_name; + Display *display; + + struct pa_defer_event* defer_event; + struct pa_io_event* io_event; + + PA_LLIST_HEAD(struct pa_x11_client, clients); + PA_LLIST_HEAD(struct pa_x11_internal, internals); +}; + +struct pa_x11_client { + PA_LLIST_FIELDS(struct pa_x11_client); + struct pa_x11_wrapper *wrapper; + int (*callback)(struct pa_x11_wrapper *w, XEvent *e, void *userdata); + void *userdata; +}; + +/* Dispatch all pending X11 events */ +static void work(struct pa_x11_wrapper *w) { + assert(w && w->ref >= 1); + + while (XPending(w->display)) { + struct pa_x11_client *c; + XEvent e; + XNextEvent(w->display, &e); + + for (c = w->clients; c; c = c->next) { + assert(c->callback); + if (c->callback(w, &e, c->userdata) != 0) + break; + } + } +} + +/* IO notification event for the X11 display connection */ +static void display_io_event(struct pa_mainloop_api *m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { + struct pa_x11_wrapper *w = userdata; + assert(m && e && fd >= 0 && w && w->ref >= 1); + work(w); +} + +/* Deferred notification event. Called once each main loop iteration */ +static void defer_event(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) { + struct pa_x11_wrapper *w = userdata; + assert(m && e && w && w->ref >= 1); + work(w); +} + +/* IO notification event for X11 internal connections */ +static void internal_io_event(struct pa_mainloop_api *m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { + struct pa_x11_wrapper *w = userdata; + assert(m && e && fd >= 0 && w && w->ref >= 1); + + XProcessInternalConnection(w->display, fd); +} + +/* Add a new IO source for the specified X11 internal connection */ +static struct pa_x11_internal* x11_internal_add(struct pa_x11_wrapper *w, int fd) { + struct pa_x11_internal *i; + assert(i && fd >= 0); + + i = pa_xmalloc(sizeof(struct pa_x11_internal)); + i->wrapper = w; + i->io_event = w->core->mainloop->io_new(w->core->mainloop, fd, PA_IO_EVENT_INPUT, internal_io_event, w); + i->fd = fd; + + PA_LLIST_PREPEND(struct pa_x11_internal, w->internals, i); + return i; +} + +/* Remove an IO source for an X11 internal connection */ +void x11_internal_remove(struct pa_x11_wrapper *w, struct pa_x11_internal *i) { + assert(i); + + PA_LLIST_REMOVE(struct pa_x11_internal, w->internals, i); + w->core->mainloop->io_free(i->io_event); + pa_xfree(i); +} + +/* Implementation of XConnectionWatchProc */ +static void x11_watch(Display *display, XPointer userdata, int fd, Bool opening, XPointer *watch_data) { + struct pa_x11_wrapper *w = (struct pa_x11_wrapper*) userdata; + assert(display && w && fd >= 0); + + if (opening) + *watch_data = (XPointer) x11_internal_add(w, fd); + else + x11_internal_remove(w, (struct pa_x11_internal*) *watch_data); +} + +static struct pa_x11_wrapper* x11_wrapper_new(struct pa_core *c, const char *name, const char *t) { + struct pa_x11_wrapper*w; + Display *d; + int r; + + if (!(d = XOpenDisplay(name))) { + pa_log(__FILE__": XOpenDisplay() failed\n"); + return NULL; + } + + w = pa_xmalloc(sizeof(struct pa_x11_wrapper)); + w->core = c; + w->ref = 1; + w->property_name = pa_xstrdup(t); + w->display = d; + + PA_LLIST_HEAD_INIT(struct pa_x11_client, w->clients); + PA_LLIST_HEAD_INIT(struct pa_x11_internal, w->internals); + + w->defer_event = c->mainloop->defer_new(c->mainloop, defer_event, w); + w->io_event = c->mainloop->io_new(c->mainloop, ConnectionNumber(d), PA_IO_EVENT_INPUT, display_io_event, w); + + XAddConnectionWatch(d, x11_watch, (XPointer) w); + + r = pa_property_set(c, w->property_name, w); + assert(r >= 0); + + return w; +} + +static void x11_wrapper_free(struct pa_x11_wrapper*w) { + int r; + assert(w); + + r = pa_property_remove(w->core, w->property_name); + assert(r >= 0); + + assert(!w->clients); + + XRemoveConnectionWatch(w->display, x11_watch, (XPointer) w); + XCloseDisplay(w->display); + + w->core->mainloop->io_free(w->io_event); + w->core->mainloop->defer_free(w->defer_event); + + while (w->internals) + x11_internal_remove(w, w->internals); + + pa_xfree(w->property_name); + pa_xfree(w); +} + +struct pa_x11_wrapper* pa_x11_wrapper_get(struct pa_core *c, const char *name) { + char t[256]; + struct pa_x11_wrapper *w; + assert(c); + + snprintf(t, sizeof(t), "x11-wrapper%s%s", name ? "-" : "", name ? name : ""); + if ((w = pa_property_get(c, t))) + return pa_x11_wrapper_ref(w); + + return x11_wrapper_new(c, name, t); +} + +struct pa_x11_wrapper* pa_x11_wrapper_ref(struct pa_x11_wrapper *w) { + assert(w && w->ref >= 1); + w->ref++; + return w; +} + +void pa_x11_wrapper_unref(struct pa_x11_wrapper* w) { + assert(w && w->ref >= 1); + + if (!(--w->ref)) + x11_wrapper_free(w); +} + +Display *pa_x11_wrapper_get_display(struct pa_x11_wrapper *w) { + assert(w && w->ref >= 1); + return w->display; +} + +struct pa_x11_client* pa_x11_client_new(struct pa_x11_wrapper *w, int (*cb)(struct pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata) { + struct pa_x11_client *c; + assert(w && w->ref >= 1); + + c = pa_xmalloc(sizeof(struct pa_x11_client)); + c->wrapper = w; + c->callback = cb; + c->userdata = userdata; + + PA_LLIST_PREPEND(struct pa_x11_client, w->clients, c); + + return c; +} + +void pa_x11_client_free(struct pa_x11_client *c) { + assert(c && c->wrapper && c->wrapper->ref >= 1); + + PA_LLIST_REMOVE(struct pa_x11_client, c->wrapper->clients, c); + pa_xfree(c); +} diff --git a/polyp/x11wrap.h b/polyp/x11wrap.h new file mode 100644 index 00000000..79c69015 --- /dev/null +++ b/polyp/x11wrap.h @@ -0,0 +1,52 @@ +#ifndef foox11wraphfoo +#define foox11wraphfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "core.h" + +struct pa_x11_wrapper; + +/* Return the X11 wrapper for this core. In case no wrapper was + existant before, allocate a new one */ +struct pa_x11_wrapper* pa_x11_wrapper_get(struct pa_core *c, const char *name); + +/* Increase the wrapper's reference count by one */ +struct pa_x11_wrapper* pa_x11_wrapper_ref(struct pa_x11_wrapper *w); + +/* Decrease the reference counter of an X11 wrapper object */ +void pa_x11_wrapper_unref(struct pa_x11_wrapper* w); + +/* Return the X11 display object for this connection */ +Display *pa_x11_wrapper_get_display(struct pa_x11_wrapper *w); + +struct pa_x11_client; + +/* Register an X11 client, that is called for each X11 event */ +struct pa_x11_client* pa_x11_client_new(struct pa_x11_wrapper *w, int (*cb)(struct pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata); + +/* Free an X11 client object */ +void pa_x11_client_free(struct pa_x11_client *c); + +#endif -- cgit From cd3ba7d0f745f8063cc018aeca320939ef3cd637 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 1 Nov 2004 23:37:36 +0000 Subject: Apply Joe Marcus Clarke's FreeBSD patches git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@269 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 6 +++++- polyp/Makefile.am | 4 ++-- polyp/packet.h | 2 +- polyp/polyplib-context.c | 1 + polyp/socket-util.c | 20 +++++++++++++++++++- polyp/util.c | 30 +++++++++++++++++++++++++++--- 6 files changed, 55 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index 14a6842d..ddf0a341 100644 --- a/configure.ac +++ b/configure.ac @@ -74,11 +74,15 @@ AC_FUNC_REALLOC AC_FUNC_SETPGRP AC_FUNC_VPRINTF AC_TYPE_SIGNAL -AC_CHECK_FUNCS([gethostname gettimeofday memchr memmove memset mkdir mkfifo munmap rmdir socket strcspn strerror strrchr strspn strstr strtol strtoul pow strcasecmp putenv strchr strpbrk strdup]) +AC_TYPE_UID_T +AC_CHECK_FUNCS([gethostname gettimeofday memchr memmove memset mkdir mkfifo munmap rmdir socket strcspn strerror strrchr strspn strstr strtol strtoul strcasecmp putenv strchr strpbrk strdup getgrgid_r getpwuid_r regcomp]) +AC_CHECK_LIB(m, pow) +AC_CHECK_FUNCS(pow) AC_FUNC_STAT AC_HEADER_SYS_WAIT AC_C_BIGENDIAN +AC_FUNC_GETGROUPS AC_CHECK_LIB(cap, cap_init, [CAP_LIBS='-lcap'], [CAP_LIBS='']) AC_SUBST(CAP_LIBS) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index d90d3229..e97ed94d 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -624,7 +624,7 @@ endif ### Some minor stuff suid: polypaudio - chown root:root $< + chown root $< chmod u+s $< esdcompat.sh: esdcompat.sh.in Makefile @@ -643,7 +643,7 @@ daemon.conf: daemon.conf.in Makefile -e 's,@DEFAULT_CONFIG_FILE\@,$(polypconfdir)/daemon.conf,g' < $< > $@ install-exec-hook: - chown root:root $(DESTDIR)$(bindir)/polypaudio + chown root $(DESTDIR)$(bindir)/polypaudio chmod u+s $(DESTDIR)$(bindir)/polypaudio $(SYMDEF_FILES): module-defs.h.m4 diff --git a/polyp/packet.h b/polyp/packet.h index 8bea07e1..8f5cb835 100644 --- a/polyp/packet.h +++ b/polyp/packet.h @@ -23,7 +23,7 @@ ***/ #include -#include +#include struct pa_packet { enum { PA_PACKET_APPENDED, PA_PACKET_DYNAMIC } type; diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index cf1a8e60..1a25523f 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "polyplib-internal.h" #include "polyplib-context.h" diff --git a/polyp/socket-util.c b/polyp/socket-util.c index 499739bd..4e1eb6ab 100644 --- a/polyp/socket-util.c +++ b/polyp/socket-util.c @@ -30,13 +30,16 @@ #include #include #include +#include #include #include #include #include -#include +#include #include #include +#include +#include #include #include "socket-util.h" @@ -94,9 +97,11 @@ int pa_socket_low_delay(int fd) { int priority; assert(fd >= 0); +#ifdef SO_PRIORITY priority = 7; if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) return -1; +#endif return 0; } @@ -109,12 +114,25 @@ int pa_socket_tcp_low_delay(int fd) { ret = pa_socket_low_delay(fd); on = 1; +#if defined(SOL_TCP) || defined(IPPROTO_TCP) +#if defined(SOL_TCP) if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) +#else + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) +#endif ret = -1; +#endif +#if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || \ + defined(IPPROTO_IP)) tos = IPTOS_LOWDELAY; +#ifdef SOL_IP if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0) +#else + if (setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) +#endif ret = -1; +#endif return ret; diff --git a/polyp/util.c b/polyp/util.c index 9697a1eb..b138266b 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -209,7 +209,13 @@ char *pa_get_user_name(char *s, size_t l) { if (!(p = getenv("LOGNAME"))) if (!(p = getenv("USERNAME"))) { +#ifdef HAVE_GETPWUID_R if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { +#else + /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) + * that do not support getpwuid_r. */ + if ((r = getpwuid(getuid())) == NULL) { +#endif snprintf(s, l, "%lu", (unsigned long) getuid()); return s; } @@ -445,11 +451,17 @@ int pa_parse_resample_method(const char *string) { static int is_group(gid_t gid, const char *name) { struct group group, *result = NULL; - long n = sysconf(_SC_GETGR_R_SIZE_MAX); + long n; void *data; int r = -1; - - assert(n > 0); + +#ifdef HAVE_GETGRGID_R +#ifdef _SC_GETGR_R_SIZE_MAX + n = sysconf(_SC_GETGR_R_SIZE_MAX); +#else + n = -1; +#endif + if (n < 0) n = 512; data = pa_xmalloc(n); if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) { @@ -462,6 +474,18 @@ static int is_group(gid_t gid, const char *name) { finish: pa_xfree(data); +#else + /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not + * support getgrgid_r. */ + if ((result = getgrgid(gid)) == NULL) { + pa_log(__FILE__ ": getgrgid(%u) failed: %s\n", gid, strerror(errno)); + goto finish; + } + + r = strcmp(name, result->gr_name) == 0; + +finish: +#endif return r; } -- cgit From 1f6a90c963356d3889cce4717a1a6b03cb039254 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 4 Nov 2004 18:56:09 +0000 Subject: fix client libaryr in case no latency interpolation is required git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@270 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/polyplib-stream.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 286702b2..312f1deb 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -560,10 +560,12 @@ struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (stru uint32_t tag; assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); - if (!s->corked && b) - s->ipol_usec = pa_stream_get_interpolated_time(s); - else if (s->corked && !b) - gettimeofday(&s->ipol_timestamp, NULL); + if (s->interpolate) { + if (!s->corked && b) + s->ipol_usec = pa_stream_get_interpolated_time(s); + else if (s->corked && !b) + gettimeofday(&s->ipol_timestamp, NULL); + } s->corked = b; -- cgit From 344ced4622ffc9d38ab0388d3ed44fe55ce5e86c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 4 Nov 2004 18:57:31 +0000 Subject: add some more comments git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@271 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/util.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++------- polyp/util.h | 3 +++ polyp/xmalloc.c | 19 ++++++++------- 3 files changed, 80 insertions(+), 16 deletions(-) diff --git a/polyp/util.c b/polyp/util.c index b138266b..794ae514 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -50,16 +50,20 @@ #include "xmalloc.h" #include "log.h" +/** Make a file descriptor nonblock. Doesn't do any error checking */ void pa_make_nonblock_fd(int fd) { int v; + assert(fd >= 0); if ((v = fcntl(fd, F_GETFL)) >= 0) if (!(v & O_NONBLOCK)) fcntl(fd, F_SETFL, v|O_NONBLOCK); } +/** Creates a directory securely */ int pa_make_secure_dir(const char* dir) { struct stat st; + assert(dir); if (mkdir(dir, 0700) < 0) if (errno != EEXIST) @@ -78,6 +82,8 @@ fail: return -1; } +/** Calls read() in a loop. Makes sure that as much as 'size' bytes, + * unless EOF is reached or an error occured */ ssize_t pa_loop_read(int fd, void*data, size_t size) { ssize_t ret = 0; assert(fd >= 0 && data && size); @@ -99,6 +105,7 @@ ssize_t pa_loop_read(int fd, void*data, size_t size) { return ret; } +/** Similar to pa_loop_read(), but wraps write() */ ssize_t pa_loop_write(int fd, const void*data, size_t size) { ssize_t ret = 0; assert(fd >= 0 && data && size); @@ -120,10 +127,16 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size) { return ret; } +/* Print a warning messages in case that the given signal is not + * blocked or trapped */ void pa_check_signal_is_blocked(int sig) { struct sigaction sa; sigset_t set; + /* If POSIX threads are supported use thread-aware + * pthread_sigmask() function, to check if the signal is + * blocked. Otherwise fall back to sigprocmask() */ + #ifdef HAVE_PTHREAD if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) { #endif @@ -137,6 +150,8 @@ void pa_check_signal_is_blocked(int sig) { if (sigismember(&set, sig)) return; + + /* Check whether the signal is trapped */ if (sigaction(sig, NULL, &sa) < 0) { pa_log(__FILE__": sigaction() failed: %s\n", strerror(errno)); @@ -149,7 +164,8 @@ void pa_check_signal_is_blocked(int sig) { pa_log(__FILE__": WARNING: %s is not trapped. This might cause malfunction!\n", pa_strsignal(sig)); } -/* The following is based on an example from the GNU libc documentation */ +/* The following function is based on an example from the GNU libc + * documentation. This function is similar to GNU's asprintf(). */ char *pa_sprintf_malloc(const char *format, ...) { int size = 100; char *c = NULL; @@ -176,6 +192,8 @@ char *pa_sprintf_malloc(const char *format, ...) { } } +/* Same as the previous function, but use a va_list instead of an + * ellipsis */ char *pa_vsprintf_malloc(const char *format, va_list ap) { int size = 100; char *c = NULL; @@ -199,11 +217,12 @@ char *pa_vsprintf_malloc(const char *format, va_list ap) { } } - +/* Return the current username in the specified string buffer. */ char *pa_get_user_name(char *s, size_t l) { struct passwd pw, *r; char buf[1024]; char *p; + assert(s && l > 0); if (!(p = getenv("USER"))) if (!(p = getenv("LOGNAME"))) @@ -222,21 +241,50 @@ char *pa_get_user_name(char *s, size_t l) { p = r->pw_name; } - - snprintf(s, l, "%s", p); - return s; + + return pa_strlcpy(s, p, l); } +/* Return the current hostname in the specified buffer. */ char *pa_get_host_name(char *s, size_t l) { + assert(s && l > 0); gethostname(s, l); s[l-1] = 0; return s; } +/* Return the home directory of the current user */ +char *pa_get_home(char *s, size_t l) { + char *e; + char buf[1024]; + struct passwd pw, *r; + assert(s && l); + + if ((e = getenv("HOME"))) + return pa_strlcpy(s, e, l); + + if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) + return NULL; + + return pa_strlcpy(s, r->pw_dir, l); +} + +/* Similar to OpenBSD's strlcpy() function */ +char *pa_strlcpy(char *b, const char *s, size_t l) { + assert(b && s && l > 0); + + strncpy(b, s, l); + b[l-1] = 0; + return b; +} + +/* Calculate the difference between the two specfified timeval + * timestamsps. */ pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { pa_usec_t r; assert(a && b); + /* Check which whan is the earlier time and swap the two arguments if reuqired. */ if (pa_timeval_cmp(a, b) < 0) { const struct timeval *c; c = a; @@ -244,8 +292,10 @@ pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { b = c; } + /* Calculate the second difference*/ r = ((pa_usec_t) a->tv_sec - b->tv_sec)* 1000000; + /* Calculate the microsecond difference */ if (a->tv_usec > b->tv_usec) r += ((pa_usec_t) a->tv_usec - b->tv_usec); else if (a->tv_usec < b->tv_usec) @@ -254,6 +304,7 @@ pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { return r; } +/* Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwse */ int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { assert(a && b); @@ -272,6 +323,7 @@ int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { return 0; } +/* Return the time difference between now and the specified timestamp */ pa_usec_t pa_timeval_age(const struct timeval *tv) { struct timeval now; assert(tv); @@ -279,6 +331,7 @@ pa_usec_t pa_timeval_age(const struct timeval *tv) { return pa_timeval_diff(&now, tv); } +/* Add the specified time inmicroseconds to the specified timeval structure */ void pa_timeval_add(struct timeval *tv, pa_usec_t v) { unsigned long secs; assert(tv); @@ -289,6 +342,7 @@ void pa_timeval_add(struct timeval *tv, pa_usec_t v) { tv->tv_usec += v; + /* Normalize */ while (tv->tv_usec >= 1000000) { tv->tv_sec++; tv->tv_usec -= 1000000; @@ -297,12 +351,16 @@ void pa_timeval_add(struct timeval *tv, pa_usec_t v) { #define NICE_LEVEL (-15) +/* Raise the priority of the current process as much as possible and +sensible: set the nice level to -15 and enable realtime scheduling if +supportted.*/ + void pa_raise_priority(void) { + if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) pa_log(__FILE__": setpriority() failed: %s\n", strerror(errno)); - else - pa_log(__FILE__": Successfully gained nice level %i.\n", NICE_LEVEL); - + else pa_log(__FILE__": Successfully gained nice level %i.\n", NICE_LEVEL); + #ifdef _POSIX_PRIORITY_SCHEDULING { struct sched_param sp; diff --git a/polyp/util.h b/polyp/util.h index c5ffa755..85da38d0 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -41,9 +41,12 @@ void pa_check_signal_is_blocked(int sig); char *pa_sprintf_malloc(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); char *pa_vsprintf_malloc(const char *format, va_list ap); +char *pa_strlcpy(char *b, const char *s, size_t l); + char *pa_get_user_name(char *s, size_t l); char *pa_get_host_name(char *s, size_t l); char *pa_get_binary_name(char *s, size_t l); +char *pa_get_home(char *s, size_t l); char *pa_path_get_filename(const char *p); diff --git a/polyp/xmalloc.c b/polyp/xmalloc.c index 47f46bbe..709e46e5 100644 --- a/polyp/xmalloc.c +++ b/polyp/xmalloc.c @@ -30,19 +30,22 @@ #include "memory.h" #include "util.h" -#define MAX_ALLOC_SIZE (1024*1024*20) +/* Make sure not to allocate more than this much memory. */ +#define MAX_ALLOC_SIZE (1024*1024*20) /* 20MB */ -#undef malloc -#undef free -#undef realloc -#undef strndup -#undef strdup +/* #undef malloc */ +/* #undef free */ +/* #undef realloc */ +/* #undef strndup */ +/* #undef strdup */ +/** called in case of an OOM situation. Prints an error message and + * exits */ static void oom(void) { static const char e[] = "Not enough memory\n"; - pa_loop_write(2, e, sizeof(e)-1); + pa_loop_write(STDERR_FILENO, e, sizeof(e)-1); raise(SIGQUIT); - exit(1); + _exit(1); } void* pa_xmalloc(size_t size) { -- cgit From 2aad9e3ae2aa53d13458faf148946cf7e7d87627 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 4 Nov 2004 20:01:13 +0000 Subject: compilation fix git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@272 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/xmalloc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/polyp/xmalloc.c b/polyp/xmalloc.c index 709e46e5..981b3c92 100644 --- a/polyp/xmalloc.c +++ b/polyp/xmalloc.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "memory.h" #include "util.h" -- cgit From 5844a33f0be1af942ee33feae38b9d46169fd61c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 4 Nov 2004 21:27:12 +0000 Subject: some commenting change alogrithm for checking for configuration files git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@273 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 4 +-- polyp/client-conf.c | 48 +++++++++++++++------------------ polyp/conf-parser.c | 8 +++--- polyp/conf-parser.h | 4 ++- polyp/daemon-conf.c | 76 +++++++++++++++++++++++----------------------------- polyp/daemon-conf.h | 1 + polyp/module-match.c | 19 +++++++++++-- polyp/util.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++--- polyp/util.h | 5 +++- 9 files changed, 156 insertions(+), 84 deletions(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index e97ed94d..1ed1b28f 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -24,9 +24,7 @@ modlibdir=$(libdir)/polypaudio-@PA_MAJORMINOR@ AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) AM_CFLAGS+=-DDLSEARCHPATH=\"$(modlibdir)\" -AM_CFLAGS+=-DDEFAULT_SCRIPT_FILE=\"$(polypconfdir)/default.pa\" -AM_CFLAGS+=-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/daemon.conf\" -AM_CFLAGS+=-DDEFAULT_CLIENT_CONFIG_FILE=\"$(polypconfdir)/client.conf\" +AM_CFLAGS+=-DDEFAULT_CONFIG_DIR=\"$(polypconfdir)\" AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\" AM_LDADD=$(PTHREAD_LIBS) -lm diff --git a/polyp/client-conf.c b/polyp/client-conf.c index b8a4c778..47c5b49c 100644 --- a/polyp/client-conf.c +++ b/polyp/client-conf.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "client-conf.h" #include "xmalloc.h" @@ -29,13 +31,12 @@ #include "conf-parser.h" #include "util.h" -#ifndef DEFAULT_CLIENT_CONFIG_FILE -#define DEFAULT_CLIENT_CONFIG_FILE "/etc/polypaudio/client.conf" +#ifndef DEFAULT_CONFIG_DIR +#define DEFAULT_CONFIG_DIR "/etc/polypaudio" #endif -#ifndef DEFAULT_CLIENT_CONFIG_FILE_USER +#define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR"/client.conf" #define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio/client.conf" -#endif #define ENV_CLIENT_CONFIG_FILE "POLYP_CLIENTCONFIG" #define ENV_DEFAULT_SINK "POLYP_SINK" @@ -71,8 +72,9 @@ void pa_client_conf_free(struct pa_client_conf *c) { pa_xfree(c); } int pa_client_conf_load(struct pa_client_conf *c, const char *filename) { - char *def = NULL; - int r; + FILE *f = NULL; + char *fn = NULL; + int r = -1; struct pa_config_item table[] = { { "daemon-binary", pa_config_parse_string, NULL }, @@ -91,29 +93,23 @@ int pa_client_conf_load(struct pa_client_conf *c, const char *filename) { table[4].data = &c->default_server; table[5].data = &c->autospawn; - if (!filename) - filename = getenv(ENV_CLIENT_CONFIG_FILE); - - if (!filename) { - char *h; - - if ((h = getenv("HOME"))) { - def = pa_sprintf_malloc("%s/%s", h, DEFAULT_CLIENT_CONFIG_FILE_USER); - - if (!access(def, F_OK)) - filename = def; - else { - pa_xfree(def); - def = NULL; - } - } + f = filename ? + fopen((fn = pa_xstrdup(filename)), "r") : + pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn); + + if (!f && errno != EINTR) { + pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno)); + goto finish; } + + r = pa_config_parse(fn, f, table, NULL); + +finish: + pa_xfree(fn); - if (!filename) - filename = DEFAULT_CLIENT_CONFIG_FILE; + if (f) + fclose(f); - r = pa_config_parse(filename, table, NULL); - pa_xfree(def); return r; } diff --git a/polyp/conf-parser.c b/polyp/conf-parser.c index 20e8e723..3d922c20 100644 --- a/polyp/conf-parser.c +++ b/polyp/conf-parser.c @@ -89,13 +89,13 @@ static int parse_line(const char *filename, unsigned line, const struct pa_confi } -int pa_config_parse(const char *filename, const struct pa_config_item *t, void *userdata) { - FILE *f; +int pa_config_parse(const char *filename, FILE *f, const struct pa_config_item *t, void *userdata) { int r = -1; unsigned line = 0; + int do_close = !f; assert(filename && t); - if (!(f = fopen(filename, "r"))) { + if (!f && !(f = fopen(filename, "r"))) { if (errno == ENOENT) { r = 0; goto finish; @@ -123,7 +123,7 @@ int pa_config_parse(const char *filename, const struct pa_config_item *t, void * finish: - if (f) + if (do_close && f) fclose(f); return r; diff --git a/polyp/conf-parser.h b/polyp/conf-parser.h index a0eb52d0..30330860 100644 --- a/polyp/conf-parser.h +++ b/polyp/conf-parser.h @@ -22,13 +22,15 @@ USA. ***/ +#include + struct pa_config_item { const char *lvalue; int (*parse)(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); void *data; }; -int pa_config_parse(const char *filename, const struct pa_config_item *t, void *userdata); +int pa_config_parse(const char *filename, FILE *f, const struct pa_config_item *t, void *userdata); int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c index 8a0f94ac..e87acd1d 100644 --- a/polyp/daemon-conf.c +++ b/polyp/daemon-conf.c @@ -36,21 +36,14 @@ #include "strbuf.h" #include "conf-parser.h" -#ifndef DEFAULT_SCRIPT_FILE -#define DEFAULT_SCRIPT_FILE "/etc/polypaudio/default.pa" +#ifndef DEFAULT_CONFIG_DIR +#define DEFAULT_CONFIG_DIR "/etc/polypaudio" #endif -#ifndef DEFAULT_SCRIPT_FILE_USER +#define DEFAULT_SCRIPT_FILE DEFAULT_CONFIG_DIR"/default.pa" #define DEFAULT_SCRIPT_FILE_USER ".polypaudio/default.pa" -#endif - -#ifndef DEFAULT_CONFIG_FILE -#define DEFAULT_CONFIG_FILE "/etc/polypaudio/daemon.conf" -#endif - -#ifndef DEFAULT_CONFIG_FILE_USER +#define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR"/daemon.conf" #define DEFAULT_CONFIG_FILE_USER ".polypaudio/daemon.conf" -#endif #define ENV_SCRIPT_FILE "POLYP_SCRIPT" #define ENV_CONFIG_FILE "POLYP_CONFIG" @@ -71,31 +64,17 @@ static const struct pa_daemon_conf default_conf = { .dl_search_path = NULL, .default_script_file = NULL, .log_target = PA_LOG_SYSLOG, - .resample_method = SRC_SINC_FASTEST + .resample_method = SRC_SINC_FASTEST, + .config_file = NULL, }; -char* default_file(const char *envvar, const char *global, const char *local) { - char *p, *h; - - assert(envvar && global && local); - - if ((p = getenv(envvar))) - return pa_xstrdup(p); - - if ((h = getenv("HOME"))) { - p = pa_sprintf_malloc("%s/%s", h, local); - if (!access(p, F_OK)) - return p; - - pa_xfree(p); - } - - return pa_xstrdup(global); -} - struct pa_daemon_conf* pa_daemon_conf_new(void) { + FILE *f; struct pa_daemon_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); - c->default_script_file = default_file(ENV_SCRIPT_FILE, DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER); + + if ((f = pa_open_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE, &c->default_script_file))) + fclose(f); + #ifdef DLSEARCHPATH c->dl_search_path = pa_xstrdup(DLSEARCHPATH); #endif @@ -107,6 +86,7 @@ void pa_daemon_conf_free(struct pa_daemon_conf *c) { pa_xfree(c->script_commands); pa_xfree(c->dl_search_path); pa_xfree(c->default_script_file); + pa_xfree(c->config_file); pa_xfree(c); } @@ -163,8 +143,8 @@ int parse_resample_method(const char *filename, unsigned line, const char *lvalu } int pa_daemon_conf_load(struct pa_daemon_conf *c, const char *filename) { - char *def = NULL; - int r; + int r = -1; + FILE *f = NULL; struct pa_config_item table[] = { { "verbose", pa_config_parse_bool, NULL }, @@ -195,11 +175,24 @@ int pa_daemon_conf_load(struct pa_daemon_conf *c, const char *filename) { table[10].data = c; table[11].data = c; - if (!filename) - filename = def = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER); + pa_xfree(c->config_file); + c->config_file = NULL; + + f = filename ? + fopen(c->config_file = pa_xstrdup(filename), "r") : + pa_open_config_file(DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file); + + if (!f && errno != EINTR) { + pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno)); + goto finish; + } + + r = pa_config_parse(c->config_file, f, table, NULL); + +finish: + if (f) + fclose(f); - r = pa_config_parse(filename, table, NULL); - pa_xfree(def); return r; } @@ -220,7 +213,6 @@ int pa_daemon_conf_env(struct pa_daemon_conf *c) { char *pa_daemon_conf_dump(struct pa_daemon_conf *c) { struct pa_strbuf *s = pa_strbuf_new(); - char *d; static const char const* resample_methods[] = { "sinc-best-quality", @@ -230,8 +222,8 @@ char *pa_daemon_conf_dump(struct pa_daemon_conf *c) { "linear" }; - d = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER); - pa_strbuf_printf(s, "### Default configuration file: %s ###\n", d); + if (c->config_file) + pa_strbuf_printf(s, "### Read from configuration file: %s ###\n", c->config_file); pa_strbuf_printf(s, "verbose = %i\n", !!c->verbose); pa_strbuf_printf(s, "daemonize = %i\n", !!c->daemonize); @@ -248,7 +240,5 @@ char *pa_daemon_conf_dump(struct pa_daemon_conf *c) { assert(c->resample_method <= 4 && c->resample_method >= 0); pa_strbuf_printf(s, "resample-method = %s\n", resample_methods[c->resample_method]); - pa_xfree(d); - return pa_strbuf_tostring_free(s); } diff --git a/polyp/daemon-conf.h b/polyp/daemon-conf.h index 8be989da..fc31117f 100644 --- a/polyp/daemon-conf.h +++ b/polyp/daemon-conf.h @@ -46,6 +46,7 @@ struct pa_daemon_conf { char *script_commands, *dl_search_path, *default_script_file; enum pa_log_target log_target; int resample_method; + char *config_file; }; struct pa_daemon_conf* pa_daemon_conf_new(void); diff --git a/polyp/module-match.c b/polyp/module-match.c index 6689cc59..176c338f 100644 --- a/polyp/module-match.c +++ b/polyp/module-match.c @@ -48,6 +48,13 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define WHITESPACE "\n\r \t" +#ifndef DEFAULT_CONFIG_DIR +#define DEFAULT_CONFIG_DIR "/etc/polypaudio" +#endif + +#define DEFAULT_MATCH_TABLE_FILE DEFAULT_CONFIG_DIR"/match.table" +#define DEFAULT_MATCH_TABLE_FILE_USER ".polypaudio/.match.table" + static const char* const valid_modargs[] = { "table", NULL, @@ -69,9 +76,14 @@ static int load_rules(struct userdata *u, const char *filename) { int n = 0; int ret = -1; struct rule *end = NULL; + char *fn = NULL; - if (!(f = fopen(filename, "r"))) { - pa_log(__FILE__": failed to open file '%s': %s\n", filename, strerror(errno)); + f = filename ? + fopen(fn = pa_xstrdup(filename), "r") : + pa_open_config_file(DEFAULT_MATCH_TABLE_FILE, DEFAULT_MATCH_TABLE_FILE_USER, NULL, &fn); + + if (!f) { + pa_log(__FILE__": failed to open file '%s': %s\n", fn, strerror(errno)); goto finish; } @@ -135,6 +147,9 @@ finish: if (f) fclose(f); + if (fn) + pa_xfree(fn); + return ret; } diff --git a/polyp/util.c b/polyp/util.c index 794ae514..6e97bae4 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -254,7 +254,7 @@ char *pa_get_host_name(char *s, size_t l) { } /* Return the home directory of the current user */ -char *pa_get_home(char *s, size_t l) { +char *pa_get_home_dir(char *s, size_t l) { char *e; char buf[1024]; struct passwd pw, *r; @@ -353,8 +353,7 @@ void pa_timeval_add(struct timeval *tv, pa_usec_t v) { /* Raise the priority of the current process as much as possible and sensible: set the nice level to -15 and enable realtime scheduling if -supportted.*/ - +supported.*/ void pa_raise_priority(void) { if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) @@ -381,6 +380,7 @@ void pa_raise_priority(void) { #endif } +/* Reset the priority to normal, inverting the changes made by pa_raise_priority() */ void pa_reset_priority(void) { #ifdef _POSIX_PRIORITY_SCHEDULING { @@ -394,6 +394,7 @@ void pa_reset_priority(void) { setpriority(PRIO_PROCESS, 0, 0); } +/* Set the FD_CLOEXEC flag for a fd */ int pa_fd_set_cloexec(int fd, int b) { int v; assert(fd >= 0); @@ -409,6 +410,9 @@ int pa_fd_set_cloexec(int fd, int b) { return 0; } +/* Return the binary file name of the current process. Works on Linux + * only. This shoul be used for eyecandy only, don't rely on return + * non-NULL! */ char *pa_get_binary_name(char *s, size_t l) { char path[PATH_MAX]; int i; @@ -424,6 +428,8 @@ char *pa_get_binary_name(char *s, size_t l) { return s; } +/* Return a pointer to the filename inside a path (which is the last + * component). */ char *pa_path_get_filename(const char *p) { char *fn; @@ -433,6 +439,7 @@ char *pa_path_get_filename(const char *p) { return (char*) p; } +/* Try to parse a boolean string value.*/ int pa_parse_boolean(const char *v) { if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on")) @@ -443,6 +450,10 @@ int pa_parse_boolean(const char *v) { return -1; } +/* Split the specified string wherever one of the strings in delimiter + * occurs. Each time it is called returns a newly allocated string + * with pa_xmalloc(). The variable state points to, should be + * initiallized to NULL before the first call. */ char *pa_split(const char *c, const char *delimiter, const char**state) { const char *current = *state ? *state : c; size_t l; @@ -459,8 +470,10 @@ char *pa_split(const char *c, const char *delimiter, const char**state) { return pa_xstrndup(current, l); } +/* What is interpreted as whitespace? */ #define WHITESPACE " \t\n" +/* Split a string into words. Otherwise similar to pa_split(). */ char *pa_split_spaces(const char *c, const char **state) { const char *current = *state ? *state : c; size_t l; @@ -476,6 +489,7 @@ char *pa_split_spaces(const char *c, const char **state) { return pa_xstrndup(current, l); } +/* Return the name of an UNIX signal. Similar to GNU's strsignal() */ const char *pa_strsignal(int sig) { switch(sig) { case SIGINT: return "SIGINT"; @@ -490,6 +504,7 @@ const char *pa_strsignal(int sig) { } } +/* Parse a libsamplrate compatible resampling implementation */ int pa_parse_resample_method(const char *string) { assert(string); @@ -507,6 +522,7 @@ int pa_parse_resample_method(const char *string) { return -1; } +/* Check whether the specified GID and the group name match */ static int is_group(gid_t gid, const char *name) { struct group group, *result = NULL; long n; @@ -548,6 +564,7 @@ finish: return r; } +/* Check the current user is member of the specified group */ int pa_uid_in_group(const char *name, gid_t *gid) { gid_t *gids, tgid; long n = sysconf(_SC_NGROUPS_MAX); @@ -584,6 +601,7 @@ finish: return r; } +/* Lock or unlock a file entirely. (advisory) */ int pa_lock_fd(int fd, int b) { struct flock flock; @@ -601,6 +619,7 @@ int pa_lock_fd(int fd, int b) { return 0; } +/* Remove trailing newlines from a string */ char* pa_strip_nl(char *s) { assert(s); @@ -608,6 +627,7 @@ char* pa_strip_nl(char *s) { return s; } +/* Create a temporary lock file and lock it. */ int pa_lock_lockfile(const char *fn) { int fd; assert(fn); @@ -630,7 +650,7 @@ fail: return -1; } - +/* Unlock a temporary lcok file */ int pa_unlock_lockfile(int fd) { int r = 0; assert(fd >= 0); @@ -648,3 +668,50 @@ int pa_unlock_lockfile(int fd) { return r; } +/* Try to open a configuration file. If "env" is specified, open the + * value of the specified environment variable. Otherwise look for a + * file "local" in the home directory or a file "global" in global + * file system. If "result" is non-NULL, a pointer to a newly + * allocated buffer containing the used configuration file is + * stored there.*/ +FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result) { + const char *e; + char h[PATH_MAX]; + + if (env && (e = getenv(env))) { + if (result) + *result = pa_xstrdup(e); + return fopen(e, "r"); + } + + if (local && pa_get_home_dir(h, sizeof(h))) { + FILE *f; + char *l; + + l = pa_sprintf_malloc("%s/%s", h, local); + f = fopen(l, "r"); + + if (f || errno != ENOENT) { + if (result) + *result = l; + else + pa_xfree(l); + return f; + } + + pa_xfree(l); + } + + if (!global) { + if (result) + *result = NULL; + errno = ENOENT; + return NULL; + } + + if (result) + *result = pa_xstrdup(global); + + return fopen(global, "r"); +} + diff --git a/polyp/util.h b/polyp/util.h index 85da38d0..0299148e 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -25,6 +25,7 @@ #include #include #include +#include #include "gcc-printf.h" #include "sample.h" @@ -46,7 +47,7 @@ char *pa_strlcpy(char *b, const char *s, size_t l); char *pa_get_user_name(char *s, size_t l); char *pa_get_host_name(char *s, size_t l); char *pa_get_binary_name(char *s, size_t l); -char *pa_get_home(char *s, size_t l); +char *pa_get_home_dir(char *s, size_t l); char *pa_path_get_filename(const char *p); @@ -78,4 +79,6 @@ int pa_lock_fd(int fd, int b); int pa_lock_lockfile(const char *fn); int pa_unlock_lockfile(int fd); +FILE *pa_open_config_file(const char *env, const char *global, const char *local, char **result); + #endif -- cgit From b55923a8d33a1c4ed2f892a0da36c9c679e7d828 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 7 Nov 2004 20:48:46 +0000 Subject: * Look for M4 in configure.ac * Share auth cookies in module-tunnel.c, module-x11-publish.c and native-protocol.c * disable TCP_NODELAY * publish auth cookie in module-x11-publish git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@274 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 5 +++ doc/todo | 6 ++-- polyp/Makefile.am | 16 +++++---- polyp/authkey-prop.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++ polyp/authkey-prop.h | 39 +++++++++++++++++++++ polyp/authkey.c | 6 ++-- polyp/module-match.c | 2 +- polyp/module-tunnel.c | 43 ++++++++++++++++++++--- polyp/module-x11-publish.c | 46 ++++++++++++++++++++++-- polyp/module.c | 2 ++ polyp/native-common.h | 2 ++ polyp/protocol-native.c | 43 +++++++++++++++++++---- polyp/socket-util.c | 2 ++ polyp/util.c | 17 +++++++++ polyp/util.h | 2 ++ 15 files changed, 292 insertions(+), 26 deletions(-) create mode 100644 polyp/authkey-prop.c create mode 100644 polyp/authkey-prop.h diff --git a/configure.ac b/configure.ac index ddf0a341..026d4d97 100644 --- a/configure.ac +++ b/configure.ac @@ -115,6 +115,11 @@ AC_SUBST(GLIB12_LIBS) AC_SUBST(HAVE_GLIB12) AM_CONDITIONAL([HAVE_GLIB12], [test "x$HAVE_GLIB12" = x1]) +AC_PATH_PROG([M4], [m4 gm4], [no]) +if test "x$M4" = xno ; then + AC_MSG_ERROR([m4 missing]) +fi + AC_MSG_CHECKING([for tcpwrap library and headers]) LIBWRAP_LIBS= saved_LIBS="$LIBS" diff --git a/doc/todo b/doc/todo index 8212ea89..cfc4b044 100644 --- a/doc/todo +++ b/doc/todo @@ -15,11 +15,11 @@ - X11: support for the X11 synchronization extension - X11: save auth info in root window - pass meta info for hearing impaired -- fall back to getpwnam if $HOME doesn't exist -- module-match: look in $HOME for table - limit all resources -- getaddrinfo +- check getaddrinfo results - add LGPL blurb to all concerning files +- non-fp mixing +- non-fp resampling ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 1ed1b28f..b0b863e5 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -84,6 +84,7 @@ modlib_LTLIBRARIES= \ libpstream-util.la \ libpdispatch.la \ libauthkey.la \ + libauthkey-prop.la \ libprotocol-simple.la \ libprotocol-esound.la \ libprotocol-native.la \ @@ -199,7 +200,7 @@ polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) polypaudio_LDFLAGS= -export-dynamic -dlopen force -#-static $(foreach f,$(modlib_LTLIBRARIES),-dlpreopen $(f)) +# -static $(foreach f,$(modlib_LTLIBRARIES),-dlpreopen $(f)) libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h libprotocol_simple_la_LDFLAGS = -avoid-version @@ -249,7 +250,7 @@ libprotocol_cli_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la lib libprotocol_native_la_SOURCES = protocol-native.c protocol-native.h native-common.h libprotocol_native_la_LDFLAGS = -avoid-version -libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la +libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libtagstruct_la_SOURCES = tagstruct.c tagstruct.h libtagstruct_la_LDFLAGS = -avoid-version @@ -261,6 +262,9 @@ libprotocol_esound_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libauthkey_la_SOURCES = authkey.c authkey.h libauthkey_la_LDFLAGS = -avoid-version +libauthkey_prop_la_SOURCES = authkey-prop.c authkey-prop.h +libauthkey_prop_la_LDFLAGS = -avoid-version + libsocket_util_la_SOURCES = socket-util.c socket-util.h libsocket_util_la_LDFLAGS = -avoid-version @@ -348,11 +352,11 @@ module_match_la_LIBADD = $(AM_LIBADD) module_tunnel_sink_la_SOURCES = module-tunnel.c module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS) module_tunnel_sink_la_LDFLAGS = -module -avoid-version -module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la +module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la module_tunnel_source_la_SOURCES = module-tunnel.c module_tunnel_source_la_LDFLAGS = -module -avoid-version -module_tunnel_source_la_LIBADD = $(AM_LIBADD) libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la +module_tunnel_source_la_LIBADD = $(AM_LIBADD) libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la module_esound_compat_spawnfd_la_SOURCES = module-esound-compat-spawnfd.c module_esound_compat_spawnfd_la_LDFLAGS = -module -avoid-version @@ -477,7 +481,7 @@ module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA module_x11_publish_la_SOURCES = module-x11-publish.c module_x11_publish_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) module_x11_publish_la_LDFLAGS = -module -avoid-version -module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) libx11wrap.la +module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) libx11wrap.la libauthkey.la libauthkey-prop.la endif @@ -645,4 +649,4 @@ install-exec-hook: chmod u+s $(DESTDIR)$(bindir)/polypaudio $(SYMDEF_FILES): module-defs.h.m4 - m4 -Dfname="$@" $< > $@ + $(M4) -Dfname="$@" $< > $@ diff --git a/polyp/authkey-prop.c b/polyp/authkey-prop.c new file mode 100644 index 00000000..13227955 --- /dev/null +++ b/polyp/authkey-prop.c @@ -0,0 +1,87 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include "xmalloc.h" +#include "authkey-prop.h" +#include "props.h" +#include "log.h" + +struct authkey_data { + int ref; + size_t length; +}; + +int pa_authkey_prop_get(struct pa_core *c, const char *name, void *data, size_t len) { + struct authkey_data *a; + assert(c && name && data && len > 0); + + if (!(a = pa_property_get(c, name))) + return -1; + + assert(a->length == len); + memcpy(data, a+1, len); + return 0; +} + +int pa_authkey_prop_put(struct pa_core *c, const char *name, const void *data, size_t len) { + struct authkey_data *a; + assert(c && name); + + if (pa_property_get(c, name)) + return -1; + + a = pa_xmalloc(sizeof(struct authkey_data) + len); + a->ref = 1; + a->length = len; + memcpy(a+1, data, len); + + pa_property_set(c, name, a); + + return 0; +} + +void pa_authkey_prop_ref(struct pa_core *c, const char *name) { + struct authkey_data *a; + assert(c && name); + + a = pa_property_get(c, name); + assert(a && a->ref >= 1); + + a->ref++; +} + +void pa_authkey_prop_unref(struct pa_core *c, const char *name) { + struct authkey_data *a; + assert(c && name); + + a = pa_property_get(c, name); + assert(a && a->ref >= 1); + + if (!(--a->ref)) { + pa_property_remove(c, name); + pa_xfree(a); + } +} + + diff --git a/polyp/authkey-prop.h b/polyp/authkey-prop.h new file mode 100644 index 00000000..d9ba5122 --- /dev/null +++ b/polyp/authkey-prop.h @@ -0,0 +1,39 @@ +#ifndef fooauthkeyprophfoo +#define fooauthkeyprophfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" + +/* Return the data of the specified authorization key property. Doesn't alter the refernce count of the key */ +int pa_authkey_prop_get(struct pa_core *c, const char *name, void *data, size_t len); + +/* Store data in the specified authorization key property. The initial reference count is set to 1 */ +int pa_authkey_prop_put(struct pa_core *c, const char *name, const void *data, size_t len); + +/* Increase the reference count of the specified authorization key */ +void pa_authkey_prop_ref(struct pa_core *c, const char *name); + +/* Decrease the reference count of the specified authorization key */ +void pa_authkey_prop_unref(struct pa_core *c, const char *name); + +#endif diff --git a/polyp/authkey.c b/polyp/authkey.c index d3cb382b..773484e9 100644 --- a/polyp/authkey.c +++ b/polyp/authkey.c @@ -145,17 +145,17 @@ int pa_authkey_load(const char *path, void *data, size_t length) { } int pa_authkey_load_from_home(const char *fn, void *data, size_t length) { - char *home; char path[PATH_MAX]; const char *p; assert(fn && data && length); if (fn[0] != '/') { - if (!(home = getenv("HOME"))) + char homedir[PATH_MAX]; + if (!pa_get_home_dir(homedir, sizeof(homedir))) return -2; - snprintf(path, sizeof(path), "%s/%s", home, fn); + snprintf(path, sizeof(path), "%s/%s", homedir, fn); p = path; } else p = fn; diff --git a/polyp/module-match.c b/polyp/module-match.c index 176c338f..0398cede 100644 --- a/polyp/module-match.c +++ b/polyp/module-match.c @@ -53,7 +53,7 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #endif #define DEFAULT_MATCH_TABLE_FILE DEFAULT_CONFIG_DIR"/match.table" -#define DEFAULT_MATCH_TABLE_FILE_USER ".polypaudio/.match.table" +#define DEFAULT_MATCH_TABLE_FILE_USER ".polypaudio/match.table" static const char* const valid_modargs[] = { "table", diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c index 2e22258a..c899929f 100644 --- a/polyp/module-tunnel.c +++ b/polyp/module-tunnel.c @@ -45,6 +45,7 @@ #include "authkey.h" #include "socket-client.h" #include "socket-util.h" +#include "authkey-prop.h" #ifdef TUNNEL_SINK #include "module-tunnel-sink-symdef.h" @@ -129,10 +130,13 @@ struct userdata { pa_usec_t host_latency; struct pa_time_event *time_event; -}; + int auth_cookie_in_property; +}; static void close_stuff(struct userdata *u) { + assert(u); + if (u->pstream) { pa_pstream_close(u->pstream); pa_pstream_unref(u->pstream); @@ -532,6 +536,32 @@ static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, m->time_restart(e, &ntv); } +static int load_key(struct userdata *u, const char*fn) { + assert(u); + + u->auth_cookie_in_property = 0; + + if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { + pa_log(__FILE__": using already loaded auth cookie.\n"); + pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); + u->auth_cookie_in_property = 1; + return 0; + } + + if (!fn) + fn = PA_NATIVE_COOKIE_FILE; + + if (pa_authkey_load_from_home(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) + return -1; + + pa_log(__FILE__": loading cookie from disk.\n"); + + if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) + u->auth_cookie_in_property = 1; + + return 0; +} + int pa__init(struct pa_core *c, struct pa_module*m) { struct pa_modargs *ma = NULL; struct userdata *u = NULL; @@ -563,11 +593,11 @@ int pa__init(struct pa_core *c, struct pa_module*m) { u->ctag = 1; u->device_index = u->channel = PA_INVALID_INDEX; u->host_latency = 0; - - if (pa_authkey_load_from_home(pa_modargs_get_value(ma, "cookie", PA_NATIVE_COOKIE_FILE), u->auth_cookie, sizeof(u->auth_cookie)) < 0) { - pa_log(__FILE__": failed to load cookie.\n"); + u->auth_cookie_in_property = 0; + u->time_event = NULL; + + if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0) goto fail; - } if (!(u->server_name = pa_xstrdup(pa_modargs_get_value(ma, "server", NULL)))) { pa_log(__FILE__": no server specified.\n"); @@ -650,6 +680,9 @@ void pa__done(struct pa_core *c, struct pa_module*m) { close_stuff(u); + if (u->auth_cookie_in_property) + pa_authkey_prop_unref(c, PA_NATIVE_COOKIE_PROPERTY_NAME); + #ifdef TUNNEL_SINK pa_xfree(u->sink_name); #else diff --git a/polyp/module-x11-publish.c b/polyp/module-x11-publish.c index fd4df4ad..a488f6d5 100644 --- a/polyp/module-x11-publish.c +++ b/polyp/module-x11-publish.c @@ -41,8 +41,10 @@ #include "log.h" #include "x11wrap.h" #include "util.h" - +#include "native-common.h" #include "module-x11-publish-symdef.h" +#include "authkey-prop.h" +#include "authkey.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("X11 Credential Publisher") @@ -53,6 +55,7 @@ static const char* const valid_modargs[] = { "display", "sink", "source", + "cookie", NULL }; @@ -61,6 +64,8 @@ struct userdata { struct pa_x11_wrapper *x11_wrapper; Display *display; char *id; + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; + int auth_cookie_in_property; }; static void set_x11_prop(Display *d, const char *name, const char *data) { @@ -91,11 +96,38 @@ static char* get_x11_prop(Display *d, const char *name, char *p, size_t l) { return p; } +static int load_key(struct userdata *u, const char*fn) { + assert(u); + + u->auth_cookie_in_property = 0; + + if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { + pa_log(__FILE__": using already loaded auth cookie.\n"); + pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); + u->auth_cookie_in_property = 1; + return 0; + } + + if (!fn) + fn = PA_NATIVE_COOKIE_FILE; + + if (pa_authkey_load_from_home(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) + return -1; + + pa_log(__FILE__": loading cookie from disk.\n"); + + if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) + u->auth_cookie_in_property = 1; + + return 0; +} + int pa__init(struct pa_core *c, struct pa_module*m) { struct userdata *u; struct pa_modargs *ma = NULL; char hn[256], un[128]; - const char *t; + char hx[PA_NATIVE_COOKIE_LENGTH*2+1]; + const char *t; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": failed to parse module arguments\n"); @@ -105,6 +137,10 @@ int pa__init(struct pa_core *c, struct pa_module*m) { m->userdata = u = pa_xmalloc(sizeof(struct userdata)); u->core = c; u->id = NULL; + u->auth_cookie_in_property = 0; + + if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0) + goto fail; if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL)))) goto fail; @@ -124,6 +160,8 @@ int pa__init(struct pa_core *c, struct pa_module*m) { if ((t = pa_modargs_get_value(ma, "sink", NULL))) set_x11_prop(u->display, "POLYP_SINK", t); + + set_x11_prop(u->display, "POLYP_COOKIE", pa_hexstr(u->auth_cookie, sizeof(u->auth_cookie), hx, sizeof(hx))); pa_modargs_free(ma); return 0; @@ -154,6 +192,7 @@ void pa__done(struct pa_core *c, struct pa_module*m) { del_x11_prop(u->display, "POLYP_SERVER"); del_x11_prop(u->display, "POLYP_SINK"); del_x11_prop(u->display, "POLYP_SOURCE"); + del_x11_prop(u->display, "POLYP_COOKIE"); XSync(u->display, False); } } @@ -161,6 +200,9 @@ void pa__done(struct pa_core *c, struct pa_module*m) { if (u->x11_wrapper) pa_x11_wrapper_unref(u->x11_wrapper); + if (u->auth_cookie_in_property) + pa_authkey_prop_unref(c, PA_NATIVE_COOKIE_PROPERTY_NAME); + pa_xfree(u->id); pa_xfree(u); } diff --git a/polyp/module.c b/polyp/module.c index 3fb42d87..9ecdfe29 100644 --- a/polyp/module.c +++ b/polyp/module.c @@ -135,6 +135,8 @@ static void pa_module_free(struct pa_module *m) { if (m->core->disallow_module_loading) return; + pa_log(__FILE__": Unloading \"%s\" (index: #%u).\n", m->name, m->index); + m->done(m->core, m); lt_dlclose(m->dl); diff --git a/polyp/native-common.h b/polyp/native-common.h index 33ecdc76..fbee74c9 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -98,6 +98,8 @@ enum { #define PA_NATIVE_DEFAULT_PORT 4713 +#define PA_NATIVE_COOKIE_PROPERTY_NAME "protocol-native-cookie" + PA_C_DECL_END #endif diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 6f3f82be..fade2a2f 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -46,6 +46,7 @@ #include "subscribe.h" #include "log.h" #include "autoload.h" +#include "authkey-prop.h" struct connection; struct pa_protocol_native; @@ -106,6 +107,7 @@ struct pa_protocol_native { struct pa_socket_server *server; struct pa_idxset *connections; uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; + int auth_cookie_in_property; }; static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk); @@ -2008,6 +2010,32 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo /*** module entry points ***/ +static int load_key(struct pa_protocol_native*p, const char*fn) { + assert(p); + + p->auth_cookie_in_property = 0; + + if (!fn && pa_authkey_prop_get(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) { + pa_log(__FILE__": using already loaded auth cookie.\n"); + pa_authkey_prop_ref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); + p->auth_cookie_in_property = 1; + return 0; + } + + if (!fn) + fn = PA_NATIVE_COOKIE_FILE; + + if (pa_authkey_load_from_home(fn, p->auth_cookie, sizeof(p->auth_cookie)) < 0) + return -1; + + pa_log(__FILE__": loading cookie from disk.\n"); + + if (pa_authkey_prop_put(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) + p->auth_cookie_in_property = 1; + + return 0; +} + static struct pa_protocol_native* protocol_new_internal(struct pa_core *c, struct pa_module *m, struct pa_modargs *ma) { struct pa_protocol_native *p; int public = 0; @@ -2019,16 +2047,16 @@ static struct pa_protocol_native* protocol_new_internal(struct pa_core *c, struc } p = pa_xmalloc(sizeof(struct pa_protocol_native)); + p->core = c; + p->module = m; + p->public = public; + p->server = NULL; - if (pa_authkey_load_from_home(pa_modargs_get_value(ma, "cookie", PA_NATIVE_COOKIE_FILE), p->auth_cookie, sizeof(p->auth_cookie)) < 0) { + if (load_key(p, pa_modargs_get_value(ma, "cookie", NULL)) < 0) { pa_xfree(p); return NULL; } - p->module = m; - p->public = public; - p->server = NULL; - p->core = c; p->connections = pa_idxset_new(NULL, NULL); assert(p->connections); @@ -2057,7 +2085,10 @@ void pa_protocol_native_free(struct pa_protocol_native *p) { if (p->server) pa_socket_server_unref(p->server); - + + if (p->auth_cookie_in_property) + pa_authkey_prop_unref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); + pa_xfree(p); } diff --git a/polyp/socket-util.c b/polyp/socket-util.c index 4e1eb6ab..96ea2c60 100644 --- a/polyp/socket-util.c +++ b/polyp/socket-util.c @@ -114,6 +114,7 @@ int pa_socket_tcp_low_delay(int fd) { ret = pa_socket_low_delay(fd); on = 1; +/* #if defined(SOL_TCP) || defined(IPPROTO_TCP) #if defined(SOL_TCP) if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) @@ -122,6 +123,7 @@ int pa_socket_tcp_low_delay(int fd) { #endif ret = -1; #endif +*/ #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || \ defined(IPPROTO_IP)) diff --git a/polyp/util.c b/polyp/util.c index 6e97bae4..97b3a26b 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -715,3 +715,20 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env return fopen(global, "r"); } +/* Format the specified data as a hexademical string */ +char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) { + size_t i = 0, j = 0; + const char hex[] = "0123456789abcdef"; + assert(d && s && slength > 0); + + while (i < dlength && j+3 <= slength) { + s[j++] = hex[*d >> 4]; + s[j++] = hex[*d & 0xF]; + + d++; + i++; + } + + s[j < slength ? j : slength] = 0; + return s; +} diff --git a/polyp/util.h b/polyp/util.h index 0299148e..2b7e6bbe 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -81,4 +81,6 @@ int pa_unlock_lockfile(int fd); FILE *pa_open_config_file(const char *env, const char *global, const char *local, char **result); +char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength); + #endif -- cgit From 4bb14837dd09777e45793bda42512d900c6b500e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 8 Nov 2004 23:48:19 +0000 Subject: implemented pax11publish.c git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@275 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/FAQ.html.in | 18 +++- polyp/Makefile.am | 6 +- polyp/authkey.c | 71 +++++++++++--- polyp/authkey.h | 2 + polyp/client-conf.c | 2 +- polyp/daemon-conf.c | 4 +- polyp/pax11publish.c | 246 ++++++++++++++++++++++++++++++++++++++++++++++++ polyp/polyplib-simple.c | 8 +- polyp/util.c | 41 ++++++++ polyp/util.h | 1 + 10 files changed, 379 insertions(+), 20 deletions(-) create mode 100644 polyp/pax11publish.c diff --git a/doc/FAQ.html.in b/doc/FAQ.html.in index f1bf2414..751ef562 100644 --- a/doc/FAQ.html.in +++ b/doc/FAQ.html.in @@ -126,7 +126,23 @@ connect to a running polypaudio daemon try using the following commands:

    killall -USR2 polypaudio
     bidilink unix-client:/tmp/polypaudio/cli
    -

    BTW: Someone should package that great tool for Debian!

    +

    BTW: Someone should package that great tool for Debian!

    + + + +
  • How do the polypaudio libraries decide where to connect to?

    +

    The following rule applies:

    +
      +
    1. If the the application using the library specifies a server to connect to it is used. If the connection fails, the library fails too.
    2. +
    3. If the environment variable POLYP_SERVER is defined the library connects to that server. If the connection fails, the library fails too.
    4. +
    5. If $DISPLAY is set, the library tries to connect to that server and looks for the root window property POYLP_SERVER for the host to connect to. If POLYP_COOKIE is set it is used as authentication cookie.
    6. +
    7. If the client configuration file (~/.polypaudio/client.conf or /etc/polypaudio/client.conf) sets the server address, the library connects to that server. If the connection fails, the library fails too.
    8. +
    9. The library tries to connect to the default local UNIX socket for polypaudio servers. If the connection fails, it proceeds with the next item.
    10. +
    11. The library tries to connect to the default local TCP socket for polypaudio servers. If the connection fails, it proceeds with the next item.
    12. +
    13. If $DISPLAY is set, the library tries to connect to the default TCP port of that host. If the connection fails, it proceeds with the next item.
    14. +
    15. The connection fails.
    16. +
    +

  • diff --git a/polyp/Makefile.am b/polyp/Makefile.am index b0b863e5..c1d81062 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -31,7 +31,7 @@ AM_LDADD=$(PTHREAD_LIBS) -lm AM_LIBADD=$(PTHREAD_LIBS) -lm EXTRA_DIST = default.pa.in daemon.conf.in client.conf.in depmod.py esdcompat.sh.in module-defs.h.m4 -bin_PROGRAMS = polypaudio pacat pactl paplay +bin_PROGRAMS = polypaudio pacat pactl paplay pax11publish bin_SCRIPTS = esdcompat.sh noinst_PROGRAMS = \ mainloop-test \ @@ -441,6 +441,10 @@ parec_simple_SOURCES = parec-simple.c parec_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la parec_simple_CFLAGS = $(AM_CFLAGS) +pax11publish_SOURCES = pax11publish.c util.c xmalloc.c log.c authkey.c client-conf.c conf-parser.c +pax11publish_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) +pax11publish_LDADD = $(AM_LDADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) + mainloop_test_SOURCES = mainloop-test.c mainloop_test_CFLAGS = $(AM_CFLAGS) mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-@PA_MAJORMINOR@.la diff --git a/polyp/authkey.c b/polyp/authkey.c index 773484e9..ef395680 100644 --- a/polyp/authkey.c +++ b/polyp/authkey.c @@ -68,7 +68,7 @@ static int generate(int fd, void *data, size_t length) { lseek(fd, 0, SEEK_SET); if ((r = pa_loop_write(fd, data, length)) < 0 || (size_t) r != length) { - pa_log(__FILE__": failed to write cookie file\n"); + pa_log(__FILE__": failed to write cookie file: %s\n", strerror(errno)); goto finish; } @@ -91,7 +91,7 @@ static int load(const char *fn, void *data, size_t length) { if ((fd = open(fn, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { if (errno != EACCES || (fd = open(fn, O_RDONLY)) < 0) { - pa_log(__FILE__": failed to open cookie file '%s'\n", fn); + pa_log(__FILE__": failed to open cookie file '%s': %s\n", fn, strerror(errno)); goto finish; } else writable = 0; @@ -100,7 +100,7 @@ static int load(const char *fn, void *data, size_t length) { unlock = pa_lock_fd(fd, 1) >= 0; if ((r = pa_loop_read(fd, data, length)) < 0) { - pa_log(__FILE__": failed to read cookie file '%s'\n", fn); + pa_log(__FILE__": failed to read cookie file '%s': %s\n", fn, strerror(errno)); goto finish; } @@ -144,21 +144,28 @@ int pa_authkey_load(const char *path, void *data, size_t length) { return ret; } -int pa_authkey_load_from_home(const char *fn, void *data, size_t length) { - char path[PATH_MAX]; - const char *p; - - assert(fn && data && length); +static const char *normalize_path(const char *fn, char *s, size_t l) { + assert(fn && s && l > 0); if (fn[0] != '/') { char homedir[PATH_MAX]; if (!pa_get_home_dir(homedir, sizeof(homedir))) - return -2; + return NULL; - snprintf(path, sizeof(path), "%s/%s", homedir, fn); - p = path; - } else - p = fn; + snprintf(s, l, "%s/%s", homedir, fn); + return s; + } + + return fn; +} + +int pa_authkey_load_from_home(const char *fn, void *data, size_t length) { + char path[PATH_MAX]; + const char *p; + assert(fn && data && length); + + if (!(p = normalize_path(fn, path, sizeof(path)))) + return -2; return pa_authkey_load(p, data, length); } @@ -171,3 +178,41 @@ int pa_authkey_load_auto(const char *fn, void *data, size_t length) { else return pa_authkey_load_from_home(fn, data, length); } + +int pa_authkey_save(const char *fn, const void *data, size_t length) { + int fd = -1; + int unlock = 0, ret = -1; + ssize_t r; + char path[PATH_MAX]; + const char *p; + assert(fn && data && length); + + if (!(p = normalize_path(fn, path, sizeof(path)))) + return -2; + + if ((fd = open(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { + pa_log(__FILE__": failed to open cookie file '%s': %s\n", fn, strerror(errno)); + goto finish; + } + + unlock = pa_lock_fd(fd, 1) >= 0; + + if ((r = pa_loop_write(fd, data, length)) < 0 || (size_t) r != length) { + pa_log(__FILE__": failed to read cookie file '%s': %s\n", fn, strerror(errno)); + goto finish; + } + + ret = 0; + +finish: + + if (fd >= 0) { + + if (unlock) + pa_lock_fd(fd, 0); + + close(fd); + } + + return ret; +} diff --git a/polyp/authkey.h b/polyp/authkey.h index acdcc24d..2bef3529 100644 --- a/polyp/authkey.h +++ b/polyp/authkey.h @@ -28,4 +28,6 @@ int pa_authkey_load(const char *path, void *data, size_t len); int pa_authkey_load_from_home(const char *fn, void *data, size_t length); int pa_authkey_load_auto(const char *fn, void *data, size_t length); +int pa_authkey_save(const char *path, const void *data, size_t length); + #endif diff --git a/polyp/client-conf.c b/polyp/client-conf.c index 47c5b49c..0f442c99 100644 --- a/polyp/client-conf.c +++ b/polyp/client-conf.c @@ -102,7 +102,7 @@ int pa_client_conf_load(struct pa_client_conf *c, const char *filename) { goto finish; } - r = pa_config_parse(fn, f, table, NULL); + r = f ? pa_config_parse(fn, f, table, NULL) : 0; finish: pa_xfree(fn); diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c index e87acd1d..1c6486b7 100644 --- a/polyp/daemon-conf.c +++ b/polyp/daemon-conf.c @@ -182,12 +182,12 @@ int pa_daemon_conf_load(struct pa_daemon_conf *c, const char *filename) { fopen(c->config_file = pa_xstrdup(filename), "r") : pa_open_config_file(DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file); - if (!f && errno != EINTR) { + if (!f && errno != ENOENT) { pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno)); goto finish; } - r = pa_config_parse(c->config_file, f, table, NULL); + r = f ? pa_config_parse(c->config_file, f, table, NULL) : 0; finish: if (f) diff --git a/polyp/pax11publish.c b/polyp/pax11publish.c new file mode 100644 index 00000000..d1391dcf --- /dev/null +++ b/polyp/pax11publish.c @@ -0,0 +1,246 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include + +#include "util.h" +#include "log.h" +#include "authkey.h" +#include "native-common.h" +#include "client-conf.h" + +static void set_x11_prop(Display *d, const char *name, const char *data) { + Atom a = XInternAtom(d, name, False); + XChangeProperty(d, RootWindow(d, 0), a, XA_STRING, 8, PropModeReplace, (unsigned char*) data, strlen(data)+1); +} + +static void del_x11_prop(Display *d, const char *name) { + Atom a = XInternAtom(d, name, False); + XDeleteProperty(d, RootWindow(d, 0), a); +} + +static char* get_x11_prop(Display *d, const char *name, char *p, size_t l) { + Atom actual_type; + int actual_format; + unsigned long nitems; + unsigned long nbytes_after; + unsigned char *prop = NULL; + char *ret = NULL; + + Atom a = XInternAtom(d, name, False); + if (XGetWindowProperty(d, RootWindow(d, 0), a, 0, (l+2)/4, False, XA_STRING, &actual_type, &actual_format, &nitems, &nbytes_after, &prop) != Success) + goto finish; + + if (actual_type != XA_STRING) + goto finish; + + memcpy(p, prop, nitems); + p[nitems] = 0; + + ret = p; + +finish: + + if (prop) + XFree(prop); + + return ret; +} + +int main(int argc, char *argv[]) { + const char *dname = NULL, *sink = NULL, *source = NULL, *server = NULL, *cookie_file = PA_NATIVE_COOKIE_FILE; + int c, ret = 1; + Display *d = NULL; + enum { DUMP, EXPORT, IMPORT, REMOVE } mode = DUMP; + + while ((c = getopt(argc, argv, "deiD:S:O:I:c:hr")) != -1) { + switch (c) { + case 'D' : + dname = optarg; + break; + case 'h': + printf("%s [-D display] [-S server] [-O sink] [-I source] [-c file] [-d|-e|-i|-r]\n", pa_path_get_filename(argv[0])); + ret = 0; + goto finish; + case 'd': + mode = DUMP; + break; + case 'e': + mode = EXPORT; + break; + case 'i': + mode = IMPORT; + break; + case 'r': + mode = REMOVE; + break; + case 'c': + cookie_file = optarg; + break; + case 'I': + source = optarg; + break; + case 'O': + sink = optarg; + break; + case 'S': + server = optarg; + break; + default: + fprintf(stderr, "Failed to parse command line.\n"); + goto finish; + } + } + + if (!(d = XOpenDisplay(dname))) { + pa_log(__FILE__": XOpenDisplay() failed\n"); + goto finish; + } + + switch (mode) { + case DUMP: { + char t[1024]; + if (!get_x11_prop(d, "POLYP_SERVER", t, sizeof(t))) + goto finish; + + printf("Server: %s\n", t); + if (get_x11_prop(d, "POLYP_SOURCE", t, sizeof(t))) + printf("Source: %s\n", t); + if (get_x11_prop(d, "POLYP_SINK", t, sizeof(t))) + printf("Sink: %s\n", t); + if (get_x11_prop(d, "POLYP_COOKIE", t, sizeof(t))) + printf("Cookie: %s\n", t); + + break; + } + + case IMPORT: { + char t[1024]; + if (!get_x11_prop(d, "POLYP_SERVER", t, sizeof(t))) + goto finish; + + printf("POLYP_SERVER='%s'\nexport POLYP_SERVER\n", t); + + if (get_x11_prop(d, "POLYP_SOURCE", t, sizeof(t))) + printf("POLYP_SOURCE='%s'\nexport POLYP_SOURCE\n", t); + if (get_x11_prop(d, "POLYP_SINK", t, sizeof(t))) + printf("POLYP_SINK='%s'\nexport POLYP_SINK\n", t); + + if (get_x11_prop(d, "POLYP_COOKIE", t, sizeof(t))) { + uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; + size_t l; + if ((l = pa_parsehex(t, cookie, sizeof(cookie))) == (size_t) -1) { + fprintf(stderr, "Failed to parse cookie data\n"); + goto finish; + } + + if (pa_authkey_save(cookie_file, cookie, l) < 0) { + fprintf(stderr, "Failed to save cookie data\n"); + goto finish; + } + } + + break; + } + + case EXPORT: { + struct pa_client_conf *c = pa_client_conf_new(); + uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; + char hx[PA_NATIVE_COOKIE_LENGTH*2+1]; + assert(c); + + if (pa_client_conf_load(c, NULL) < 0) { + fprintf(stderr, "Failed to load client configuration file.\n"); + goto finish; + } + + if (pa_client_conf_env(c) < 0) { + fprintf(stderr, "Failed to read environment configuration data.\n"); + goto finish; + } + + del_x11_prop(d, "POLYP_ID"); + + if (server) + set_x11_prop(d, "POLYP_SERVER", c->default_server); + else if (c->default_server) + set_x11_prop(d, "POLYP_SERVER", c->default_server); + else { + char hn[256]; + pa_get_host_name(hn, sizeof(hn)); + set_x11_prop(d, "POLYP_SERVER", hn); + } + + if (sink) + set_x11_prop(d, "POLYP_SINK", sink); + else if (c->default_sink) + set_x11_prop(d, "POLYP_SINK", c->default_sink); + + if (source) + set_x11_prop(d, "POLYP_SOURCE", source); + if (c->default_source) + set_x11_prop(d, "POLYP_SOURCE", c->default_source); + + pa_client_conf_free(c); + + if (pa_authkey_load_auto(cookie_file, cookie, sizeof(cookie)) < 0) { + fprintf(stderr, "Failed to load cookie data\n"); + goto finish; + } + + set_x11_prop(d, "POLYP_COOKIE", pa_hexstr(cookie, sizeof(cookie), hx, sizeof(hx))); + break; + } + + case REMOVE: + del_x11_prop(d, "POLYP_SERVER"); + del_x11_prop(d, "POLYP_SINK"); + del_x11_prop(d, "POLYP_SOURCE"); + del_x11_prop(d, "POLYP_ID"); + del_x11_prop(d, "POLYP_COOKIE"); + break; + + default: + fprintf(stderr, "No yet implemented.\n"); + goto finish; + } + + ret = 0; + +finish: + + if (d) { + XSync(d, False); + XCloseDisplay(d); + } + + return ret; +} diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c index 0e180af0..aed1ca55 100644 --- a/polyp/polyplib-simple.c +++ b/polyp/polyplib-simple.c @@ -325,8 +325,12 @@ static void latency_complete(struct pa_stream *s, const struct pa_latency_info * if (!l) p->dead = 1; - else - p->latency = l->buffer_usec + l->sink_usec + l->transport_usec; + else { + int negative = 0; + p->latency = pa_stream_get_latency(s, l, &negative); + if (negative) + p->latency = 0; + } } pa_usec_t pa_simple_get_playback_latency(struct pa_simple *p, int *perror) { diff --git a/polyp/util.c b/polyp/util.c index 97b3a26b..b4c16dbb 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -732,3 +732,44 @@ char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) { s[j < slength ? j : slength] = 0; return s; } + +/* Convert a hexadecimal digit to a number or -1 if invalid */ +static int hexc(char c) { + if (c >= '0' && c <= '9') + return c - '0'; + + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + + return -1; +} + +/* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */ +size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) { + size_t j = 0; + assert(p && d); + + while (j < dlength && *p) { + int b; + + if ((b = hexc(*(p++))) < 0) + return (size_t) -1; + + d[j] = (uint8_t) (b << 4); + + if (!*p) + return (size_t) -1; + + if ((b = hexc(*(p++))) < 0) + return (size_t) -1; + + d[j] |= (uint8_t) b; + + j++; + } + + return j; +} diff --git a/polyp/util.h b/polyp/util.h index 2b7e6bbe..2448b0fa 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -82,5 +82,6 @@ int pa_unlock_lockfile(int fd); FILE *pa_open_config_file(const char *env, const char *global, const char *local, char **result); char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength); +size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength); #endif -- cgit From 89e39f13b5b122d7dd17499b9b69fdccc196a30c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 8 Nov 2004 23:53:46 +0000 Subject: build pax11publish only when X11 is available git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@276 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index c1d81062..18aa51c1 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -31,7 +31,7 @@ AM_LDADD=$(PTHREAD_LIBS) -lm AM_LIBADD=$(PTHREAD_LIBS) -lm EXTRA_DIST = default.pa.in daemon.conf.in client.conf.in depmod.py esdcompat.sh.in module-defs.h.m4 -bin_PROGRAMS = polypaudio pacat pactl paplay pax11publish +bin_PROGRAMS = polypaudio pacat pactl paplay bin_SCRIPTS = esdcompat.sh noinst_PROGRAMS = \ mainloop-test \ @@ -441,10 +441,6 @@ parec_simple_SOURCES = parec-simple.c parec_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la parec_simple_CFLAGS = $(AM_CFLAGS) -pax11publish_SOURCES = pax11publish.c util.c xmalloc.c log.c authkey.c client-conf.c conf-parser.c -pax11publish_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) -pax11publish_LDADD = $(AM_LDADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) - mainloop_test_SOURCES = mainloop-test.c mainloop_test_CFLAGS = $(AM_CFLAGS) mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-@PA_MAJORMINOR@.la @@ -487,6 +483,13 @@ module_x11_publish_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) module_x11_publish_la_LDFLAGS = -module -avoid-version module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) libx11wrap.la libauthkey.la libauthkey-prop.la +bin_PROGRAMS+= \ + pax11publish + +pax11publish_SOURCES = pax11publish.c util.c xmalloc.c log.c authkey.c client-conf.c conf-parser.c +pax11publish_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) +pax11publish_LDADD = $(AM_LDADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) + endif ### ALSA modules -- cgit From 3916a66a87a639a1733cfe4fb33f32904eda7f59 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 9 Nov 2004 00:14:07 +0000 Subject: export FQDN instead of hostname git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@277 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/pax11publish.c | 13 +++++++++++-- polyp/util.c | 20 ++++++++++++++++++++ polyp/util.h | 1 + 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/polyp/pax11publish.c b/polyp/pax11publish.c index d1391dcf..fc1d6ab7 100644 --- a/polyp/pax11publish.c +++ b/polyp/pax11publish.c @@ -87,7 +87,12 @@ int main(int argc, char *argv[]) { dname = optarg; break; case 'h': - printf("%s [-D display] [-S server] [-O sink] [-I source] [-c file] [-d|-e|-i|-r]\n", pa_path_get_filename(argv[0])); + printf("%s [-D display] [-S server] [-O sink] [-I source] [-c file] [-d|-e|-i|-r]\n\n" + " -d Show current Polypaudio data attached to X11 display (default)\n" + " -e Export local Polypaudio data to X11 display\n" + " -i Import Polypaudio data from X11 display to local environment variables and cookie file.\n" + " -r Remove Polypaudio data from X11 display\n", + pa_path_get_filename(argv[0])); ret = 0; goto finish; case 'd': @@ -195,7 +200,11 @@ int main(int argc, char *argv[]) { set_x11_prop(d, "POLYP_SERVER", c->default_server); else { char hn[256]; - pa_get_host_name(hn, sizeof(hn)); + if (!pa_get_fqdn(hn, sizeof(hn))) { + fprintf(stderr, "Failed to get FQDN.\n"); + goto finish; + } + set_x11_prop(d, "POLYP_SERVER", hn); } diff --git a/polyp/util.c b/polyp/util.c index b4c16dbb..ad91a307 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -43,6 +43,7 @@ #include #include #include +#include #include @@ -773,3 +774,22 @@ size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) { return j; } + +char *pa_get_fqdn(char *s, size_t l) { + char hn[256]; + struct addrinfo *a, hints; + + if (!pa_get_host_name(hn, sizeof(hn))) + return NULL; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_CANONNAME; + + if (getaddrinfo(hn, NULL, &hints, &a) < 0 || !a || !a->ai_canonname || !*a->ai_canonname) + return pa_strlcpy(s, hn, l); + + pa_strlcpy(s, a->ai_canonname, l); + freeaddrinfo(a); + return s; +} diff --git a/polyp/util.h b/polyp/util.h index 2448b0fa..3f09a9a7 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -46,6 +46,7 @@ char *pa_strlcpy(char *b, const char *s, size_t l); char *pa_get_user_name(char *s, size_t l); char *pa_get_host_name(char *s, size_t l); +char *pa_get_fqdn(char *s, size_t l); char *pa_get_binary_name(char *s, size_t l); char *pa_get_home_dir(char *s, size_t l); -- cgit From 3fcd7a433c1422c52804181de6a719a527830326 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 9 Nov 2004 01:04:17 +0000 Subject: use fqdn in module-x11-publish as well git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@278 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-x11-publish.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/polyp/module-x11-publish.c b/polyp/module-x11-publish.c index a488f6d5..c862fe3a 100644 --- a/polyp/module-x11-publish.c +++ b/polyp/module-x11-publish.c @@ -147,8 +147,11 @@ int pa__init(struct pa_core *c, struct pa_module*m) { u->display = pa_x11_wrapper_get_display(u->x11_wrapper); - pa_get_host_name(hn, sizeof(hn)); - pa_get_user_name(un, sizeof(un)); + if (!pa_get_fqdn(hn, sizeof(hn))) + goto fail; + + if (!pa_get_user_name(un, sizeof(un))) + goto fail; u->id = pa_sprintf_malloc("%s@%s/%u", un, hn, (unsigned) getpid()); -- cgit From dbaa83c60730633315aa13d74907c6572985c050 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 9 Nov 2004 23:19:42 +0000 Subject: split out x11prop.[ch] add client support for auth daemon info in X display git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@279 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 1 + doc/todo | 1 + polyp/Makefile.am | 22 ++++++++--- polyp/client-conf-x11.c | 89 ++++++++++++++++++++++++++++++++++++++++++++ polyp/client-conf-x11.h | 29 +++++++++++++++ polyp/client-conf.c | 40 +++++++++++++++++++- polyp/client-conf.h | 8 +++- polyp/module-protocol-stub.c | 2 +- polyp/module-x11-publish.c | 51 ++++++------------------- polyp/native-common.h | 3 ++ polyp/pax11publish.c | 85 ++++++++++++------------------------------ polyp/polyplib-context.c | 19 ++++++---- polyp/polyplib-internal.h | 3 -- polyp/x11prop.c | 70 ++++++++++++++++++++++++++++++++++ polyp/x11prop.h | 33 ++++++++++++++++ 15 files changed, 337 insertions(+), 119 deletions(-) create mode 100644 polyp/client-conf-x11.c create mode 100644 polyp/client-conf-x11.h create mode 100644 polyp/x11prop.c create mode 100644 polyp/x11prop.h diff --git a/configure.ac b/configure.ac index 026d4d97..6eec2d81 100644 --- a/configure.ac +++ b/configure.ac @@ -54,6 +54,7 @@ HAVE_X11=0 test "x$no_x" != "xyes" && HAVE_X11=1 AC_SUBST(HAVE_X11) AM_CONDITIONAL(HAVE_X11, test "x$no_x" != "xyes") +AC_DEFINE([HAVE_X11], [], [Have X11]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST diff --git a/doc/todo b/doc/todo index cfc4b044..2ba697b8 100644 --- a/doc/todo +++ b/doc/todo @@ -20,6 +20,7 @@ - add LGPL blurb to all concerning files - non-fp mixing - non-fp resampling +- esound backend ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 18aa51c1..cc9705c2 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -27,8 +27,8 @@ AM_CFLAGS+=-DDLSEARCHPATH=\"$(modlibdir)\" AM_CFLAGS+=-DDEFAULT_CONFIG_DIR=\"$(polypconfdir)\" AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\" -AM_LDADD=$(PTHREAD_LIBS) -lm AM_LIBADD=$(PTHREAD_LIBS) -lm +AM_LDADD=$(PTHREAD_LIBS) -lm EXTRA_DIST = default.pa.in daemon.conf.in client.conf.in depmod.py esdcompat.sh.in module-defs.h.m4 bin_PROGRAMS = polypaudio pacat pactl paplay @@ -462,6 +462,7 @@ cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la if HAVE_X11 modlib_LTLIBRARIES+= \ libx11wrap.la \ + libx11prop.la \ module-x11-bell.la \ module-x11-publish.la SYMDEF_FILES += \ @@ -471,24 +472,33 @@ SYMDEF_FILES += \ libx11wrap_la_SOURCES = x11wrap.c x11wrap.h libx11wrap_la_LDFLAGS = -avoid-version libx11wrap_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) -libx11wrap_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) +libx11wrap_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) + +libx11prop_la_SOURCES = x11prop.c x11prop.h +libx11prop_la_LDFLAGS = -avoid-version +libx11prop_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) +libx11prop_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) module_x11_bell_la_SOURCES = module-x11-bell.c module_x11_bell_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) module_x11_bell_la_LDFLAGS = -module -avoid-version -module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) libx11wrap.la +module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la module_x11_publish_la_SOURCES = module-x11-publish.c module_x11_publish_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) module_x11_publish_la_LDFLAGS = -module -avoid-version -module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) libx11wrap.la libauthkey.la libauthkey-prop.la +module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la libauthkey.la libauthkey-prop.la libx11prop.la bin_PROGRAMS+= \ pax11publish -pax11publish_SOURCES = pax11publish.c util.c xmalloc.c log.c authkey.c client-conf.c conf-parser.c +pax11publish_SOURCES = pax11publish.c util.c xmalloc.c log.c authkey.c client-conf.c conf-parser.c x11prop.c pax11publish_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) -pax11publish_LDADD = $(AM_LDADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) +pax11publish_LDADD = $(AM_LDADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) + +libpolyp_@PA_MAJORMINOR@_la_CFLAGS += $(X_CFLAGS) +libpolyp_@PA_MAJORMINOR@_la_LDFLAGS += $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) +libpolyp_@PA_MAJORMINOR@_la_SOURCES += x11prop.c client-conf-x11.c endif diff --git a/polyp/client-conf-x11.c b/polyp/client-conf-x11.c new file mode 100644 index 00000000..54c3b06a --- /dev/null +++ b/polyp/client-conf-x11.c @@ -0,0 +1,89 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include + +#include "client-conf-x11.h" +#include "x11prop.h" +#include "log.h" +#include "xmalloc.h" +#include "util.h" + +int pa_client_conf_from_x11(struct pa_client_conf *c, const char *dname) { + Display *d = NULL; + int ret = -1; + char t[1024]; + + if (!(d = XOpenDisplay(dname))) { + pa_log(__FILE__": XOpenDisplay() failed\n"); + goto finish; + } + + if (!pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) + goto finish; + + pa_xfree(c->default_server); + c->default_server = pa_xstrdup(t); + + if (pa_x11_get_prop(d, "POLYP_SINK", t, sizeof(t))) { + pa_xfree(c->default_sink); + c->default_sink = pa_xstrdup(t); + } + + if (pa_x11_get_prop(d, "POLYP_SOURCE", t, sizeof(t))) { + pa_xfree(c->default_source); + c->default_source = pa_xstrdup(t); + } + + if (pa_x11_get_prop(d, "POLYP_COOKIE", t, sizeof(t))) { + uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; + + if (pa_parsehex(t, cookie, sizeof(cookie)) != sizeof(cookie)) { + pa_log(__FILE__": failed to parse cookie data\n"); + goto finish; + } + + assert(sizeof(cookie) == sizeof(c->cookie)); + memcpy(c->cookie, cookie, sizeof(cookie)); + + c->cookie_valid = 1; + + pa_xfree(c->cookie_file); + c->cookie_file = NULL; + } + + ret = 0; + +finish: + if (d) + XCloseDisplay(d); + + return ret; + +} diff --git a/polyp/client-conf-x11.h b/polyp/client-conf-x11.h new file mode 100644 index 00000000..626b4f30 --- /dev/null +++ b/polyp/client-conf-x11.h @@ -0,0 +1,29 @@ +#ifndef fooclientconfx11hfoo +#define fooclientconfx11hfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "client-conf.h" + +int pa_client_conf_from_x11(struct pa_client_conf *c, const char *display); + +#endif diff --git a/polyp/client-conf.c b/polyp/client-conf.c index 0f442c99..4a0fc629 100644 --- a/polyp/client-conf.c +++ b/polyp/client-conf.c @@ -30,6 +30,7 @@ #include "log.h" #include "conf-parser.h" #include "util.h" +#include "authkey.h" #ifndef DEFAULT_CONFIG_DIR #define DEFAULT_CONFIG_DIR "/etc/polypaudio" @@ -43,6 +44,7 @@ #define ENV_DEFAULT_SOURCE "POLYP_SOURCE" #define ENV_DEFAULT_SERVER "POLYP_SERVER" #define ENV_DAEMON_BINARY "POLYP_BINARY" +#define ENV_COOKIE_FILE "POLYP_COOKIE" static const struct pa_client_conf default_conf = { .daemon_binary = NULL, @@ -50,14 +52,20 @@ static const struct pa_client_conf default_conf = { .default_sink = NULL, .default_source = NULL, .default_server = NULL, - .autospawn = 0 + .autospawn = 0, + .cookie_file = NULL, + .cookie_valid = 0 }; struct pa_client_conf *pa_client_conf_new(void) { struct pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); + + c->daemon_binary = pa_xstrdup(POLYPAUDIO_BINARY); c->extra_arguments = pa_xstrdup("--log-target=syslog --exit-idle-time=5"); + + c->cookie_file = pa_xstrdup(PA_NATIVE_COOKIE_FILE); return c; } @@ -69,6 +77,7 @@ void pa_client_conf_free(struct pa_client_conf *c) { pa_xfree(c->default_sink); pa_xfree(c->default_source); pa_xfree(c->default_server); + pa_xfree(c->cookie_file); pa_xfree(c); } int pa_client_conf_load(struct pa_client_conf *c, const char *filename) { @@ -83,6 +92,7 @@ int pa_client_conf_load(struct pa_client_conf *c, const char *filename) { { "default-source", pa_config_parse_string, NULL }, { "default-server", pa_config_parse_string, NULL }, { "autospawn", pa_config_parse_bool, NULL }, + { "cookie-file", pa_config_parse_string, NULL }, { NULL, NULL, NULL }, }; @@ -92,6 +102,7 @@ int pa_client_conf_load(struct pa_client_conf *c, const char *filename) { table[3].data = &c->default_source; table[4].data = &c->default_server; table[5].data = &c->autospawn; + table[6].data = &c->cookie_file; f = filename ? fopen((fn = pa_xstrdup(filename)), "r") : @@ -104,6 +115,10 @@ int pa_client_conf_load(struct pa_client_conf *c, const char *filename) { r = f ? pa_config_parse(fn, f, table, NULL) : 0; + if (!r) + r = pa_client_conf_load_cookie(c); + + finish: pa_xfree(fn); @@ -136,5 +151,28 @@ int pa_client_conf_env(struct pa_client_conf *c) { c->daemon_binary = pa_xstrdup(e); } + if ((e = getenv(ENV_COOKIE_FILE))) { + pa_xfree(c->cookie_file); + c->cookie_file = pa_xstrdup(e); + + return pa_client_conf_load_cookie(c); + } + return 0; } + +int pa_client_conf_load_cookie(struct pa_client_conf* c) { + assert(c); + + c->cookie_valid = 0; + + if (!c->cookie_file) + return -1; + + if (pa_authkey_load_auto(c->cookie_file, c->cookie, sizeof(c->cookie)) < 0) + return -1; + + c->cookie_valid = 1; + return 0; +} + diff --git a/polyp/client-conf.h b/polyp/client-conf.h index 6fd4a20d..2ce056f4 100644 --- a/polyp/client-conf.h +++ b/polyp/client-conf.h @@ -22,9 +22,13 @@ USA. ***/ +#include "native-common.h" + struct pa_client_conf { - char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server; + char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server, *cookie_file; int autospawn; + uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; + int cookie_valid; }; struct pa_client_conf *pa_client_conf_new(void); @@ -33,4 +37,6 @@ void pa_client_conf_free(struct pa_client_conf *c); int pa_client_conf_load(struct pa_client_conf *c, const char *filename); int pa_client_conf_env(struct pa_client_conf *c); +int pa_client_conf_load_cookie(struct pa_client_conf* c); + #endif diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index 8cef3bdb..6ff7d774 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -83,7 +83,7 @@ #define protocol_free pa_protocol_native_free #define TCPWRAP_SERVICE "polypaudio-native" #define IPV4_PORT PA_NATIVE_DEFAULT_PORT - #define UNIX_SOCKET "/tmp/polypaudio/native" + #define UNIX_SOCKET PA_NATIVE_DEFAULT_SERVER_UNIX #define MODULE_ARGUMENTS "public", "cookie", #ifdef USE_TCP_SOCKETS #include "module-native-protocol-tcp-symdef.h" diff --git a/polyp/module-x11-publish.c b/polyp/module-x11-publish.c index c862fe3a..6e100153 100644 --- a/polyp/module-x11-publish.c +++ b/polyp/module-x11-publish.c @@ -45,6 +45,7 @@ #include "module-x11-publish-symdef.h" #include "authkey-prop.h" #include "authkey.h" +#include "x11prop.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("X11 Credential Publisher") @@ -68,34 +69,6 @@ struct userdata { int auth_cookie_in_property; }; -static void set_x11_prop(Display *d, const char *name, const char *data) { - Atom a = XInternAtom(d, name, False); - XChangeProperty(d, RootWindow(d, 0), a, XA_STRING, 8, PropModeReplace, (unsigned char*) data, strlen(data)+1); -} - -static void del_x11_prop(Display *d, const char *name) { - Atom a = XInternAtom(d, name, False); - XDeleteProperty(d, RootWindow(d, 0), a); -} - -static char* get_x11_prop(Display *d, const char *name, char *p, size_t l) { - Atom actual_type; - int actual_format; - unsigned long nitems; - unsigned long nbytes_after; - unsigned char *prop; - - Atom a = XInternAtom(d, name, False); - if (XGetWindowProperty(d, RootWindow(d, 0), a, 0, (l+2)/4, False, XA_STRING, &actual_type, &actual_format, &nitems, &nbytes_after, &prop) != Success) - return NULL; - - memcpy(p, prop, nitems); - p[nitems] = 0; - - XFree(prop); - return p; -} - static int load_key(struct userdata *u, const char*fn) { assert(u); @@ -155,16 +128,16 @@ int pa__init(struct pa_core *c, struct pa_module*m) { u->id = pa_sprintf_malloc("%s@%s/%u", un, hn, (unsigned) getpid()); - set_x11_prop(u->display, "POLYP_SERVER", hn); - set_x11_prop(u->display, "POLYP_ID", u->id); + pa_x11_set_prop(u->display, "POLYP_SERVER", hn); + pa_x11_set_prop(u->display, "POLYP_ID", u->id); if ((t = pa_modargs_get_value(ma, "source", NULL))) - set_x11_prop(u->display, "POLYP_SOURCE", t); + pa_x11_set_prop(u->display, "POLYP_SOURCE", t); if ((t = pa_modargs_get_value(ma, "sink", NULL))) - set_x11_prop(u->display, "POLYP_SINK", t); + pa_x11_set_prop(u->display, "POLYP_SINK", t); - set_x11_prop(u->display, "POLYP_COOKIE", pa_hexstr(u->auth_cookie, sizeof(u->auth_cookie), hx, sizeof(hx))); + pa_x11_set_prop(u->display, "POLYP_COOKIE", pa_hexstr(u->auth_cookie, sizeof(u->auth_cookie), hx, sizeof(hx))); pa_modargs_free(ma); return 0; @@ -188,14 +161,14 @@ void pa__done(struct pa_core *c, struct pa_module*m) { char t[256]; /* Yes, here is a race condition */ - if (!get_x11_prop(u->display, "POLYP_ID", t, sizeof(t)) || strcmp(t, u->id)) + if (!pa_x11_get_prop(u->display, "POLYP_ID", t, sizeof(t)) || strcmp(t, u->id)) pa_log("WARNING: Polypaudio information vanished from X11!\n"); else { - del_x11_prop(u->display, "POLYP_ID"); - del_x11_prop(u->display, "POLYP_SERVER"); - del_x11_prop(u->display, "POLYP_SINK"); - del_x11_prop(u->display, "POLYP_SOURCE"); - del_x11_prop(u->display, "POLYP_COOKIE"); + pa_x11_del_prop(u->display, "POLYP_ID"); + pa_x11_del_prop(u->display, "POLYP_SERVER"); + pa_x11_del_prop(u->display, "POLYP_SINK"); + pa_x11_del_prop(u->display, "POLYP_SOURCE"); + pa_x11_del_prop(u->display, "POLYP_COOKIE"); XSync(u->display, False); } } diff --git a/polyp/native-common.h b/polyp/native-common.h index fbee74c9..597bb56b 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -100,6 +100,9 @@ enum { #define PA_NATIVE_COOKIE_PROPERTY_NAME "protocol-native-cookie" +#define PA_NATIVE_DEFAULT_SERVER_UNIX "/tmp/polypaudio/native" + + PA_C_DECL_END #endif diff --git a/polyp/pax11publish.c b/polyp/pax11publish.c index fc1d6ab7..f151c197 100644 --- a/polyp/pax11publish.c +++ b/polyp/pax11publish.c @@ -36,44 +36,7 @@ #include "authkey.h" #include "native-common.h" #include "client-conf.h" - -static void set_x11_prop(Display *d, const char *name, const char *data) { - Atom a = XInternAtom(d, name, False); - XChangeProperty(d, RootWindow(d, 0), a, XA_STRING, 8, PropModeReplace, (unsigned char*) data, strlen(data)+1); -} - -static void del_x11_prop(Display *d, const char *name) { - Atom a = XInternAtom(d, name, False); - XDeleteProperty(d, RootWindow(d, 0), a); -} - -static char* get_x11_prop(Display *d, const char *name, char *p, size_t l) { - Atom actual_type; - int actual_format; - unsigned long nitems; - unsigned long nbytes_after; - unsigned char *prop = NULL; - char *ret = NULL; - - Atom a = XInternAtom(d, name, False); - if (XGetWindowProperty(d, RootWindow(d, 0), a, 0, (l+2)/4, False, XA_STRING, &actual_type, &actual_format, &nitems, &nbytes_after, &prop) != Success) - goto finish; - - if (actual_type != XA_STRING) - goto finish; - - memcpy(p, prop, nitems); - p[nitems] = 0; - - ret = p; - -finish: - - if (prop) - XFree(prop); - - return ret; -} +#include "x11prop.h" int main(int argc, char *argv[]) { const char *dname = NULL, *sink = NULL, *source = NULL, *server = NULL, *cookie_file = PA_NATIVE_COOKIE_FILE; @@ -133,15 +96,15 @@ int main(int argc, char *argv[]) { switch (mode) { case DUMP: { char t[1024]; - if (!get_x11_prop(d, "POLYP_SERVER", t, sizeof(t))) + if (!pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) goto finish; printf("Server: %s\n", t); - if (get_x11_prop(d, "POLYP_SOURCE", t, sizeof(t))) + if (pa_x11_get_prop(d, "POLYP_SOURCE", t, sizeof(t))) printf("Source: %s\n", t); - if (get_x11_prop(d, "POLYP_SINK", t, sizeof(t))) + if (pa_x11_get_prop(d, "POLYP_SINK", t, sizeof(t))) printf("Sink: %s\n", t); - if (get_x11_prop(d, "POLYP_COOKIE", t, sizeof(t))) + if (pa_x11_get_prop(d, "POLYP_COOKIE", t, sizeof(t))) printf("Cookie: %s\n", t); break; @@ -149,20 +112,20 @@ int main(int argc, char *argv[]) { case IMPORT: { char t[1024]; - if (!get_x11_prop(d, "POLYP_SERVER", t, sizeof(t))) + if (!pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) goto finish; printf("POLYP_SERVER='%s'\nexport POLYP_SERVER\n", t); - if (get_x11_prop(d, "POLYP_SOURCE", t, sizeof(t))) + if (pa_x11_get_prop(d, "POLYP_SOURCE", t, sizeof(t))) printf("POLYP_SOURCE='%s'\nexport POLYP_SOURCE\n", t); - if (get_x11_prop(d, "POLYP_SINK", t, sizeof(t))) + if (pa_x11_get_prop(d, "POLYP_SINK", t, sizeof(t))) printf("POLYP_SINK='%s'\nexport POLYP_SINK\n", t); - if (get_x11_prop(d, "POLYP_COOKIE", t, sizeof(t))) { + if (pa_x11_get_prop(d, "POLYP_COOKIE", t, sizeof(t))) { uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; size_t l; - if ((l = pa_parsehex(t, cookie, sizeof(cookie))) == (size_t) -1) { + if ((l = pa_parsehex(t, cookie, sizeof(cookie))) != sizeof(cookie)) { fprintf(stderr, "Failed to parse cookie data\n"); goto finish; } @@ -192,12 +155,12 @@ int main(int argc, char *argv[]) { goto finish; } - del_x11_prop(d, "POLYP_ID"); + pa_x11_del_prop(d, "POLYP_ID"); if (server) - set_x11_prop(d, "POLYP_SERVER", c->default_server); + pa_x11_set_prop(d, "POLYP_SERVER", c->default_server); else if (c->default_server) - set_x11_prop(d, "POLYP_SERVER", c->default_server); + pa_x11_set_prop(d, "POLYP_SERVER", c->default_server); else { char hn[256]; if (!pa_get_fqdn(hn, sizeof(hn))) { @@ -205,18 +168,18 @@ int main(int argc, char *argv[]) { goto finish; } - set_x11_prop(d, "POLYP_SERVER", hn); + pa_x11_set_prop(d, "POLYP_SERVER", hn); } if (sink) - set_x11_prop(d, "POLYP_SINK", sink); + pa_x11_set_prop(d, "POLYP_SINK", sink); else if (c->default_sink) - set_x11_prop(d, "POLYP_SINK", c->default_sink); + pa_x11_set_prop(d, "POLYP_SINK", c->default_sink); if (source) - set_x11_prop(d, "POLYP_SOURCE", source); + pa_x11_set_prop(d, "POLYP_SOURCE", source); if (c->default_source) - set_x11_prop(d, "POLYP_SOURCE", c->default_source); + pa_x11_set_prop(d, "POLYP_SOURCE", c->default_source); pa_client_conf_free(c); @@ -225,16 +188,16 @@ int main(int argc, char *argv[]) { goto finish; } - set_x11_prop(d, "POLYP_COOKIE", pa_hexstr(cookie, sizeof(cookie), hx, sizeof(hx))); + pa_x11_set_prop(d, "POLYP_COOKIE", pa_hexstr(cookie, sizeof(cookie), hx, sizeof(hx))); break; } case REMOVE: - del_x11_prop(d, "POLYP_SERVER"); - del_x11_prop(d, "POLYP_SINK"); - del_x11_prop(d, "POLYP_SOURCE"); - del_x11_prop(d, "POLYP_ID"); - del_x11_prop(d, "POLYP_COOKIE"); + pa_x11_del_prop(d, "POLYP_SERVER"); + pa_x11_del_prop(d, "POLYP_SINK"); + pa_x11_del_prop(d, "POLYP_SOURCE"); + pa_x11_del_prop(d, "POLYP_ID"); + pa_x11_del_prop(d, "POLYP_COOKIE"); break; default: diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 1a25523f..36512a8a 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -44,14 +44,16 @@ #include "dynarray.h" #include "socket-client.h" #include "pstream-util.h" -#include "authkey.h" #include "util.h" #include "xmalloc.h" #include "log.h" #include "client-conf.h" #include "socket-util.h" -#define DEFAULT_SERVER "/tmp/polypaudio/native" +#ifdef HAVE_X11 +#include "client-conf-x11.h" +#endif + #define AUTOSPAWN_LOCK "/tmp/polypaudio/autospawn.lock" static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { @@ -96,6 +98,9 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * c->conf = pa_client_conf_new(); pa_client_conf_load(c->conf, NULL); +#ifdef HAVE_X11 + pa_client_conf_from_x11(c->conf, NULL); +#endif pa_client_conf_env(c->conf); return c; @@ -312,7 +317,7 @@ static void setup_context(struct pa_context *c, struct pa_iochannel *io) { c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); assert(c->pdispatch); - if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { + if (!c->conf->cookie_valid) { pa_context_fail(c, PA_ERROR_AUTHKEY); goto finish; } @@ -321,7 +326,7 @@ static void setup_context(struct pa_context *c, struct pa_iochannel *io) { assert(t); pa_tagstruct_putu32(t, PA_COMMAND_AUTH); pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); + pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie)); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); @@ -355,10 +360,10 @@ finish: static int default_server_is_running(void) { struct stat st; - if (DEFAULT_SERVER[0] != '/') + if (PA_NATIVE_DEFAULT_SERVER_UNIX[0] != '/') return 1; - if (stat(DEFAULT_SERVER, &st) < 0) + if (stat(PA_NATIVE_DEFAULT_SERVER_UNIX, &st) < 0) return 0; return 1; @@ -488,7 +493,7 @@ int pa_context_connect(struct pa_context *c, const char *server, int spawn, cons } if (!server) - server = DEFAULT_SERVER; + server = PA_NATIVE_DEFAULT_SERVER_UNIX; pa_context_ref(c); diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 623a89b3..4e6553a8 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -61,8 +61,6 @@ struct pa_context { uint32_t error; enum pa_context_state state; - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; - void (*state_callback)(struct pa_context*c, void *userdata); void *state_userdata; @@ -109,7 +107,6 @@ struct pa_stream { void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); void *write_userdata; - }; struct pa_operation { diff --git a/polyp/x11prop.c b/polyp/x11prop.c new file mode 100644 index 00000000..6ff91ec4 --- /dev/null +++ b/polyp/x11prop.c @@ -0,0 +1,70 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include "x11prop.h" + + +void pa_x11_set_prop(Display *d, const char *name, const char *data) { + Atom a = XInternAtom(d, name, False); + XChangeProperty(d, RootWindow(d, 0), a, XA_STRING, 8, PropModeReplace, (unsigned char*) data, strlen(data)+1); +} + +void pa_x11_del_prop(Display *d, const char *name) { + Atom a = XInternAtom(d, name, False); + XDeleteProperty(d, RootWindow(d, 0), a); +} + +char* pa_x11_get_prop(Display *d, const char *name, char *p, size_t l) { + Atom actual_type; + int actual_format; + unsigned long nitems; + unsigned long nbytes_after; + unsigned char *prop = NULL; + char *ret = NULL; + + Atom a = XInternAtom(d, name, False); + if (XGetWindowProperty(d, RootWindow(d, 0), a, 0, (l+2)/4, False, XA_STRING, &actual_type, &actual_format, &nitems, &nbytes_after, &prop) != Success) + goto finish; + + if (actual_type != XA_STRING) + goto finish; + + memcpy(p, prop, nitems); + p[nitems] = 0; + + ret = p; + +finish: + + if (prop) + XFree(prop); + + return ret; +} diff --git a/polyp/x11prop.h b/polyp/x11prop.h new file mode 100644 index 00000000..22461858 --- /dev/null +++ b/polyp/x11prop.h @@ -0,0 +1,33 @@ +#ifndef foox11prophfoo +#define foox11prophfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include + +void pa_x11_set_prop(Display *d, const char *name, const char *data); +void pa_x11_del_prop(Display *d, const char *name); +char* pa_x11_get_prop(Display *d, const char *name, char *p, size_t l); + +#endif -- cgit From c005bd466651d8720aef3198d73bc0a3d459f953 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 11 Nov 2004 21:18:33 +0000 Subject: add username to runtime directory name in /tmp/ rework autospawning code and x11 credential publishing add support for IPv6 reenable LOWDELAY for tcp sockets git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@280 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 - polyp/Makefile.am | 52 +++++++++-- polyp/client-conf-x11.c | 5 +- polyp/module-protocol-stub.c | 51 ++++++++--- polyp/module-x11-publish.c | 14 ++- polyp/native-common.h | 3 +- polyp/polyplib-context.c | 212 +++++++++++++++++++++++++++---------------- polyp/polyplib-internal.h | 6 ++ polyp/props.c | 7 ++ polyp/props.h | 3 + polyp/protocol-native.c | 28 +++++- polyp/socket-client.c | 191 +++++++++++++++++++++++++++++--------- polyp/socket-client.h | 6 +- polyp/socket-server.c | 145 ++++++++++++++++++++++++++++- polyp/socket-server.h | 3 + polyp/socket-util.c | 39 +------- polyp/socket-util.h | 3 - polyp/strlist-test.c | 39 ++++++++ polyp/strlist.c | 137 ++++++++++++++++++++++++++++ polyp/strlist.h | 47 ++++++++++ polyp/util.c | 83 +++++++++++++---- polyp/util.h | 5 + 22 files changed, 870 insertions(+), 211 deletions(-) create mode 100644 polyp/strlist-test.c create mode 100644 polyp/strlist.c create mode 100644 polyp/strlist.h diff --git a/doc/todo b/doc/todo index 2ba697b8..99e06569 100644 --- a/doc/todo +++ b/doc/todo @@ -2,7 +2,6 @@ *** 0.7 **** - per-channel volume -- unix socket directories include user name - add sample directory - make mcalign merge chunks - option to use default fragment size on alsa drivers @@ -13,7 +12,6 @@ - make most buffer sizes dependant on the sample type - X11: support for the X11 synchronization extension -- X11: save auth info in root window - pass meta info for hearing impaired - limit all resources - check getaddrinfo results diff --git a/polyp/Makefile.am b/polyp/Makefile.am index cc9705c2..c4f9e2d2 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -39,7 +39,8 @@ noinst_PROGRAMS = \ parec-simple \ cpulimit-test \ cpulimit-test2 \ - voltest + voltest \ + strlist-test polypconf_DATA=default.pa daemon.conf client.conf @@ -85,21 +86,26 @@ modlib_LTLIBRARIES= \ libpdispatch.la \ libauthkey.la \ libauthkey-prop.la \ + libstrlist.la \ libprotocol-simple.la \ libprotocol-esound.la \ libprotocol-native.la \ module-cli.la \ module-cli-protocol-tcp.la \ + module-cli-protocol-tcp6.la \ module-cli-protocol-unix.la \ module-pipe-sink.la \ module-pipe-source.la \ module-oss.la \ module-oss-mmap.la \ module-simple-protocol-tcp.la \ + module-simple-protocol-tcp6.la \ module-simple-protocol-unix.la \ module-esound-protocol-tcp.la \ + module-esound-protocol-tcp6.la \ module-esound-protocol-unix.la \ module-native-protocol-tcp.la \ + module-native-protocol-tcp6.la \ module-native-protocol-unix.la \ module-native-protocol-fd.la \ module-sine.la \ @@ -114,16 +120,20 @@ modlib_LTLIBRARIES= \ SYMDEF_FILES= \ module-cli-symdef.h \ module-cli-protocol-tcp-symdef.h \ + module-cli-protocol-tcp6-symdef.h \ module-cli-protocol-unix-symdef.h \ module-pipe-sink-symdef.h \ module-pipe-source-symdef.h \ module-oss-symdef.h \ module-oss-mmap-symdef.h \ module-simple-protocol-tcp-symdef.h \ + module-simple-protocol-tcp6-symdef.h \ module-simple-protocol-unix-symdef.h \ module-esound-protocol-tcp-symdef.h \ + module-esound-protocol-tcp6-symdef.h \ module-esound-protocol-unix-symdef.h \ module-native-protocol-tcp-symdef.h \ + module-native-protocol-tcp6-symdef.h \ module-native-protocol-unix-symdef.h \ module-native-protocol-fd-symdef.h \ module-sine-symdef.h \ @@ -244,13 +254,17 @@ libcli_la_SOURCES = cli.c cli.h libcli_la_LDFLAGS = -avoid-version libcli_la_LIBADD = $(AM_LIBADD) libiochannel.la libioline.la +libstrlist_la_SOURCES = strlist.c strlist.h +libstrlist_la_LDFLAGS = -avoid-version +libstrlist_la_LIBADD = $(AM_LIBADD) + libprotocol_cli_la_SOURCES = protocol-cli.c protocol-cli.h libprotocol_cli_la_LDFLAGS = -avoid-version libprotocol_cli_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libcli.la libprotocol_native_la_SOURCES = protocol-native.c protocol-native.h native-common.h libprotocol_native_la_LDFLAGS = -avoid-version -libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la +libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libstrlist.la libtagstruct_la_SOURCES = tagstruct.c tagstruct.h libtagstruct_la_LDFLAGS = -avoid-version @@ -273,6 +287,11 @@ module_simple_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_SIMPLE $ module_simple_protocol_tcp_la_LDFLAGS = -module -avoid-version module_simple_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-simple.la libsocket-server.la +module_simple_protocol_tcp6_la_SOURCES = module-protocol-stub.c +module_simple_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) +module_simple_protocol_tcp6_la_LDFLAGS = -module -avoid-version +module_simple_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libprotocol-simple.la libsocket-server.la + module_simple_protocol_unix_la_SOURCES = module-protocol-stub.c module_simple_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) module_simple_protocol_unix_la_LDFLAGS = -module -avoid-version @@ -283,6 +302,11 @@ module_cli_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CF module_cli_protocol_tcp_la_LDFLAGS = -module -avoid-version module_cli_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-cli.la libsocket-server.la +module_cli_protocol_tcp6_la_SOURCES = module-protocol-stub.c +module_cli_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) +module_cli_protocol_tcp6_la_LDFLAGS = -module -avoid-version +module_cli_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libprotocol-cli.la libsocket-server.la + module_cli_protocol_unix_la_SOURCES = module-protocol-stub.c module_cli_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) module_cli_protocol_unix_la_LDFLAGS = -module -avoid-version @@ -293,6 +317,11 @@ module_native_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_NATIVE $ module_native_protocol_tcp_la_LDFLAGS = -module -avoid-version module_native_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-native.la libsocket-server.la +module_native_protocol_tcp6_la_SOURCES = module-protocol-stub.c +module_native_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) +module_native_protocol_tcp6_la_LDFLAGS = -module -avoid-version +module_native_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libprotocol-native.la libsocket-server.la + module_native_protocol_unix_la_SOURCES = module-protocol-stub.c module_native_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) module_native_protocol_unix_la_LDFLAGS = -module -avoid-version @@ -308,6 +337,11 @@ module_esound_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_ESOUND $ module_esound_protocol_tcp_la_LDFLAGS = -module -avoid-version module_esound_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-esound.la libsocket-server.la +module_esound_protocol_tcp6_la_SOURCES = module-protocol-stub.c +module_esound_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) +module_esound_protocol_tcp6_la_LDFLAGS = -module -avoid-version +module_esound_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libprotocol-esound.la libsocket-server.la + module_esound_protocol_unix_la_SOURCES = module-protocol-stub.c module_esound_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) module_esound_protocol_unix_la_LDFLAGS = -module -avoid-version @@ -399,7 +433,9 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = polyplib.h \ log.c log.h \ gcc-printf.h \ client-conf.c client-conf.h \ - conf-parser.c conf-parser.h + conf-parser.c conf-parser.h \ + strlist.c strlist.h \ + strbuf.c strbuf.h libpolyp_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) libpolyp_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 @@ -449,11 +485,15 @@ voltest_SOURCES = voltest.c sample.c voltest_CFLAGS = $(AM_CFLAGS) voltest_LDADD = $(AM_LDADD) -cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c log.c +strlist_test_SOURCES = strlist-test.c strlist.c strlist.h strbuf.c strbuf.h util.c util.h xmalloc.c xmalloc.h log.c log.h +strlist_test_CFLAGS = $(AM_CFLAGS) +strlist_test_LDADD = $(AM_LDADD) + +cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h cpulimit_test_CFLAGS = $(AM_CFLAGS) cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la -cpulimit_test2_SOURCES = cpulimit-test.c cpulimit.c util.c log.c +cpulimit_test2_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h cpulimit_test2_CFLAGS = $(AM_CFLAGS) -DTEST2 cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la @@ -487,7 +527,7 @@ module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA module_x11_publish_la_SOURCES = module-x11-publish.c module_x11_publish_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) module_x11_publish_la_LDFLAGS = -module -avoid-version -module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la libauthkey.la libauthkey-prop.la libx11prop.la +module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la libauthkey.la libauthkey-prop.la libx11prop.la libstrlist.la bin_PROGRAMS+= \ pax11publish diff --git a/polyp/client-conf-x11.c b/polyp/client-conf-x11.c index 54c3b06a..f667bd78 100644 --- a/polyp/client-conf-x11.c +++ b/polyp/client-conf-x11.c @@ -39,7 +39,10 @@ int pa_client_conf_from_x11(struct pa_client_conf *c, const char *dname) { Display *d = NULL; int ret = -1; char t[1024]; - + + if (!dname && !getenv("DISPLAY")) + goto finish; + if (!(d = XOpenDisplay(dname))) { pa_log(__FILE__": XOpenDisplay() failed\n"); goto finish; diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index 6ff7d774..6a0f88a2 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -38,10 +38,14 @@ #include "modargs.h" #include "log.h" #include "native-common.h" +#include "util.h" #ifdef USE_TCP_SOCKETS #define SOCKET_DESCRIPTION "(TCP sockets)" #define SOCKET_USAGE "port= loopback=" +#elif defined(USE_TCP6_SOCKETS) +#define SOCKET_DESCRIPTION "(TCP/IPv6 sockets)" +#define SOCKET_USAGE "port= loopback=" #else #define SOCKET_DESCRIPTION "(UNIX sockets)" #define SOCKET_USAGE "socket=" @@ -53,10 +57,12 @@ #define protocol_free pa_protocol_simple_free #define TCPWRAP_SERVICE "polypaudio-simple" #define IPV4_PORT 4711 - #define UNIX_SOCKET "/tmp/polypaudio/simple" + #define UNIX_SOCKET "simple" #define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record", - #ifdef USE_TCP_SOCKETS + #if defined(USE_TCP_SOCKETS) #include "module-simple-protocol-tcp-symdef.h" + #elif defined(USE_TCP6_SOCKETS) + #include "module-simple-protocol-tcp6-symdef.h" #else #include "module-simple-protocol-unix-symdef.h" #endif @@ -68,10 +74,12 @@ #define protocol_free pa_protocol_cli_free #define TCPWRAP_SERVICE "polypaudio-cli" #define IPV4_PORT 4712 - #define UNIX_SOCKET "/tmp/polypaudio/cli" + #define UNIX_SOCKET "cli" #define MODULE_ARGUMENTS #ifdef USE_TCP_SOCKETS #include "module-cli-protocol-tcp-symdef.h" + #elif defined(USE_TCP6_SOCKETS) + #include "module-cli-protocol-tcp6-symdef.h" #else #include "module-cli-protocol-unix-symdef.h" #endif @@ -83,10 +91,12 @@ #define protocol_free pa_protocol_native_free #define TCPWRAP_SERVICE "polypaudio-native" #define IPV4_PORT PA_NATIVE_DEFAULT_PORT - #define UNIX_SOCKET PA_NATIVE_DEFAULT_SERVER_UNIX + #define UNIX_SOCKET PA_NATIVE_DEFAULT_UNIX_SOCKET #define MODULE_ARGUMENTS "public", "cookie", #ifdef USE_TCP_SOCKETS #include "module-native-protocol-tcp-symdef.h" + #elif defined(USE_TCP6_SOCKETS) + #include "module-native-protocol-tcp6-symdef.h" #else #include "module-native-protocol-unix-symdef.h" #endif @@ -103,6 +113,8 @@ #define MODULE_ARGUMENTS "sink", "source", "public", "cookie", #ifdef USE_TCP_SOCKETS #include "module-esound-protocol-tcp-symdef.h" + #elif defined(USE_TCP6_SOCKETS) + #include "module-esound-protocol-tcp6-symdef.h" #else #include "module-esound-protocol-unix-symdef.h" #endif @@ -117,7 +129,7 @@ PA_MODULE_VERSION(PACKAGE_VERSION) static const char* const valid_modargs[] = { MODULE_ARGUMENTS -#ifdef USE_TCP_SOCKETS +#if defined(USE_TCP_SOCKETS) || defined(USE_TCP6_SOCKETS) "port", "loopback", #else @@ -128,7 +140,7 @@ static const char* const valid_modargs[] = { static struct pa_socket_server *create_socket_server(struct pa_core *c, struct pa_modargs *ma) { struct pa_socket_server *s; -#ifdef USE_TCP_SOCKETS +#if defined(USE_TCP_SOCKETS) || defined(USE_TCP6_SOCKETS) int loopback = 1; uint32_t port = IPV4_PORT; @@ -141,30 +153,39 @@ static struct pa_socket_server *create_socket_server(struct pa_core *c, struct p pa_log(__FILE__": port= expects a numerical argument between 1 and 65535.\n"); return NULL; } - + +#ifdef USE_TCP6_SOCKETS + if (!(s = pa_socket_server_new_ipv6(c->mainloop, loopback ? (uint8_t*) &in6addr_loopback : (uint8_t*) &in6addr_any, port))) + return NULL; +#else if (!(s = pa_socket_server_new_ipv4(c->mainloop, loopback ? INADDR_LOOPBACK : INADDR_ANY, port, TCPWRAP_SERVICE))) return NULL; +#endif + #else int r; - const char *p; + const char *v; + char tmp[PATH_MAX]; + + v = pa_modargs_get_value(ma, "socket", UNIX_SOCKET); + assert(v); - p = pa_modargs_get_value(ma, "socket", UNIX_SOCKET); - assert(p); + pa_runtime_path(v, tmp, sizeof(tmp)); - if (pa_unix_socket_make_secure_dir(p) < 0) { + if (pa_make_secure_parent_dir(tmp) < 0) { pa_log(__FILE__": Failed to create secure socket directory.\n"); return NULL; } - if ((r = pa_unix_socket_remove_stale(p)) < 0) { - pa_log(__FILE__": Failed to remove stale UNIX socket '%s': %s\n", p, strerror(errno)); + if ((r = pa_unix_socket_remove_stale(tmp)) < 0) { + pa_log(__FILE__": Failed to remove stale UNIX socket '%s': %s\n", tmp, strerror(errno)); return NULL; } if (r) - pa_log(__FILE__": Removed stale UNIX socket '%s'.", p); + pa_log(__FILE__": Removed stale UNIX socket '%s'.", tmp); - if (!(s = pa_socket_server_new_unix(c->mainloop, p))) + if (!(s = pa_socket_server_new_unix(c->mainloop, tmp))) return NULL; #endif diff --git a/polyp/module-x11-publish.c b/polyp/module-x11-publish.c index 6e100153..60284bd6 100644 --- a/polyp/module-x11-publish.c +++ b/polyp/module-x11-publish.c @@ -46,6 +46,8 @@ #include "authkey-prop.h" #include "authkey.h" #include "x11prop.h" +#include "strlist.h" +#include "props.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("X11 Credential Publisher") @@ -101,6 +103,8 @@ int pa__init(struct pa_core *c, struct pa_module*m) { char hn[256], un[128]; char hx[PA_NATIVE_COOKIE_LENGTH*2+1]; const char *t; + char *s; + struct pa_strlist *l; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": failed to parse module arguments\n"); @@ -120,15 +124,17 @@ int pa__init(struct pa_core *c, struct pa_module*m) { u->display = pa_x11_wrapper_get_display(u->x11_wrapper); - if (!pa_get_fqdn(hn, sizeof(hn))) + if (!(l = pa_property_get(c, PA_NATIVE_SERVER_PROPERTY_NAME))) goto fail; + + s = pa_strlist_tostring(l); + pa_x11_set_prop(u->display, "POLYP_SERVER", s); + pa_xfree(s); - if (!pa_get_user_name(un, sizeof(un))) + if (!pa_get_fqdn(hn, sizeof(hn)) || !pa_get_user_name(un, sizeof(un))) goto fail; u->id = pa_sprintf_malloc("%s@%s/%u", un, hn, (unsigned) getpid()); - - pa_x11_set_prop(u->display, "POLYP_SERVER", hn); pa_x11_set_prop(u->display, "POLYP_ID", u->id); if ((t = pa_modargs_get_value(ma, "source", NULL))) diff --git a/polyp/native-common.h b/polyp/native-common.h index 597bb56b..28a471d0 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -99,8 +99,9 @@ enum { #define PA_NATIVE_DEFAULT_PORT 4713 #define PA_NATIVE_COOKIE_PROPERTY_NAME "protocol-native-cookie" +#define PA_NATIVE_SERVER_PROPERTY_NAME "protocol-native-server" -#define PA_NATIVE_DEFAULT_SERVER_UNIX "/tmp/polypaudio/native" +#define PA_NATIVE_DEFAULT_UNIX_SOCKET "native" PA_C_DECL_END diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 36512a8a..a4770313 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -54,7 +54,9 @@ #include "client-conf-x11.h" #endif -#define AUTOSPAWN_LOCK "/tmp/polypaudio/autospawn.lock" +#define AUTOSPAWN_LOCK "autospawn.lock" + + static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_REQUEST] = { pa_command_request }, @@ -63,6 +65,16 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_SUBSCRIBE_EVENT] = { pa_command_subscribe_event }, }; +static void unlock_autospawn_lock_file(struct pa_context *c) { + assert(c); + + if (c->autospawn_lock_fd >= 0) { + pa_unlock_lockfile(c->autospawn_lock_fd); + c->autospawn_lock_fd = -1; + } + +} + struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { struct pa_context *c; assert(mainloop && name); @@ -93,6 +105,10 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * c->memblock_stat = pa_memblock_stat_new(); c->local = -1; + c->server_list = NULL; + c->autospawn_lock_fd = -1; + memset(&c->spawn_api, 0, sizeof(c->spawn_api)); + c->do_autospawn = 0; pa_check_signal_is_blocked(SIGPIPE); @@ -109,6 +125,8 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * static void context_free(struct pa_context *c) { assert(c); + unlock_autospawn_lock_file(c); + while (c->operations) pa_operation_cancel(c->operations); @@ -133,6 +151,8 @@ static void context_free(struct pa_context *c) { if (c->conf) pa_client_conf_free(c->conf); + + pa_strlist_free(c->server_list); pa_xfree(c->name); pa_xfree(c); @@ -337,38 +357,9 @@ finish: pa_context_unref(c); } -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { - struct pa_context *c = userdata; - assert(client && c && c->state == PA_CONTEXT_CONNECTING); - - pa_context_ref(c); - - pa_socket_client_unref(client); - c->client = NULL; - - if (!io) { - pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); - goto finish; - } - - setup_context(c, io); +static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata); -finish: - pa_context_unref(c); -} - -static int default_server_is_running(void) { - struct stat st; - - if (PA_NATIVE_DEFAULT_SERVER_UNIX[0] != '/') - return 1; - - if (stat(PA_NATIVE_DEFAULT_SERVER_UNIX, &st) < 0) - return 0; - - return 1; -} -static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api *api) { +static int context_connect_spawn(struct pa_context *c) { pid_t pid; int status, r; int fds[2] = { -1, -1} ; @@ -382,15 +373,20 @@ static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api goto fail; } - if (api && api->prefork) - api->prefork(); + pa_fd_set_cloexec(fds[0], 1); + + pa_socket_low_delay(fds[0]); + pa_socket_low_delay(fds[1]); + + if (c->spawn_api.prefork) + c->spawn_api.prefork(); if ((pid = fork()) < 0) { pa_log(__FILE__": fork() failed: %s\n", strerror(errno)); pa_context_fail(c, PA_ERROR_INTERNAL); - if (api && api->postfork) - api->postfork(); + if (c->spawn_api.postfork) + c->spawn_api.postfork(); goto fail; } else if (!pid) { @@ -402,10 +398,11 @@ static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api char *argv[MAX_ARGS+1]; int n; + /* Not required, since fds[0] has CLOEXEC enabled anyway */ close(fds[0]); - if (api && api->atfork) - api->atfork(); + if (c->spawn_api.atfork) + c->spawn_api.atfork(); /* Setup argv */ @@ -430,14 +427,15 @@ static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api execv(argv[0], argv); _exit(1); +#undef MAX_ARGS } /* Parent */ r = waitpid(pid, &status, 0); - if (api && api->postfork) - api->postfork(); + if (c->spawn_api.postfork) + c->spawn_api.postfork(); if (r < 0) { pa_log(__FILE__": waitpid() failed: %s\n", strerror(errno)); @@ -453,7 +451,9 @@ static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api c->local = 1; io = pa_iochannel_new(c->mainloop, fds[0], fds[0]); + setup_context(c, io); + unlock_autospawn_lock_file(c); pa_context_unref(c); @@ -465,71 +465,131 @@ fail: if (fds[1] != -1) close(fds[1]); + unlock_autospawn_lock_file(c); + pa_context_unref(c); return -1; } -int pa_context_connect(struct pa_context *c, const char *server, int spawn, const struct pa_spawn_api *api) { +static int try_next_connection(struct pa_context *c) { + char *u = NULL; int r = -1; - assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED); - - if (!server) - server = c->conf->default_server; + assert(c && !c->client); - if (!server && spawn && c->conf->autospawn) { - int lock_fd = pa_lock_lockfile(AUTOSPAWN_LOCK); + for (;;) { + if (u) + pa_xfree(u); + u = NULL; + + c->server_list = pa_strlist_pop(c->server_list, &u); - if (!default_server_is_running()) { - int r = context_connect_spawn(c, api); + if (!u) { - if (lock_fd >= 0) - pa_unlock_lockfile(lock_fd); - return r; + if (c->do_autospawn) { + r = context_connect_spawn(c); + goto finish; + } + + pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + goto finish; } - - if (lock_fd >= 0) - pa_unlock_lockfile(lock_fd); + +/* pa_log(__FILE__": Trying to connect to %s...\n", u); */ + + if (!(c->client = pa_socket_client_new_string(c->mainloop, u, PA_NATIVE_DEFAULT_PORT))) + continue; + + c->local = pa_socket_client_is_local(c->client); + pa_socket_client_set_callback(c->client, on_connection, c); + break; } + + r = 0; + +finish: + if (u) + pa_xfree(u); - if (!server) - server = PA_NATIVE_DEFAULT_SERVER_UNIX; + return r; +} - pa_context_ref(c); +static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { + struct pa_context *c = userdata; + assert(client && c && c->state == PA_CONTEXT_CONNECTING); - assert(!c->client); + pa_context_ref(c); - if (*server == '/') { - if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { - pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + pa_socket_client_unref(client); + c->client = NULL; + + if (!io) { + pa_log("failure: %s\n", strerror(errno)); + + /* Try the item in the list */ + if (errno == ECONNREFUSED || errno == ETIMEDOUT || errno == EHOSTUNREACH) { + try_next_connection(c); goto finish; } - c->local = 1; - } else { - struct sockaddr* sa; - size_t sa_len; + pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + goto finish; + } + + unlock_autospawn_lock_file(c); + setup_context(c, io); - if (!(sa = pa_resolve_server(server, &sa_len, PA_NATIVE_DEFAULT_PORT))) { +finish: + pa_context_unref(c); +} + +int pa_context_connect(struct pa_context *c, const char *server, int spawn, const struct pa_spawn_api *api) { + int r = -1; + assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED); + + if (!server) + server = c->conf->default_server; + + + pa_context_ref(c); + + assert(!c->server_list); + + if (server) { + if (!(c->server_list = pa_strlist_parse(server))) { pa_context_fail(c, PA_ERROR_INVALIDSERVER); goto finish; } + } else { + char *d; + char ufn[PATH_MAX]; + + /* Prepend in reverse order */ + + if ((d = getenv("DISPLAY"))) + c->server_list = pa_strlist_prepend(c->server_list, d); + + c->server_list = pa_strlist_prepend(c->server_list, "tcp6:localhost"); + c->server_list = pa_strlist_prepend(c->server_list, "localhost"); + c->server_list = pa_strlist_prepend(c->server_list, pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET, ufn, sizeof(ufn))); - c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); - pa_xfree(sa); + /* Wrap the connection attempts in a single transaction for sane autospwan locking */ + if (spawn && c->conf->autospawn) { + char lf[PATH_MAX]; - if (!c->client) { - pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); - goto finish; + pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); + assert(c->autospawn_lock_fd <= 0); + c->autospawn_lock_fd = pa_lock_lockfile(lf); + + if (api) + c->spawn_api = *api; + c->do_autospawn = 1; } - c->local = 0; } - pa_socket_client_set_callback(c->client, on_connection, c); pa_context_set_state(c, PA_CONTEXT_CONNECTING); - - r = 0; + r = try_next_connection(c); finish: pa_context_unref(c); diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 4e6553a8..589388f8 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -34,6 +34,7 @@ #include "llist.h" #include "native-common.h" #include "client-conf.h" +#include "strlist.h" #define DEFAULT_TLENGTH (44100*2*2/2) //(10240*8) #define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2) @@ -70,6 +71,11 @@ struct pa_context { struct pa_memblock_stat *memblock_stat; int local; + int do_autospawn; + int autospawn_lock_fd; + struct pa_spawn_api spawn_api; + + struct pa_strlist *server_list; struct pa_client_conf *conf; }; diff --git a/polyp/props.c b/polyp/props.c index 014059ec..596133bc 100644 --- a/polyp/props.c +++ b/polyp/props.c @@ -110,3 +110,10 @@ void pa_property_dump(struct pa_core *c, struct pa_strbuf *s) { while ((p = pa_hashmap_iterate(c->properties, &state, NULL))) pa_strbuf_printf(s, "[%s] -> [%p]\n", p->name, p->data); } + +int pa_property_replace(struct pa_core *c, const char *name, void *data) { + assert(c && name); + + pa_property_remove(c, name); + return pa_property_set(c, name, data); +} diff --git a/polyp/props.h b/polyp/props.h index f19e9260..954d2540 100644 --- a/polyp/props.h +++ b/polyp/props.h @@ -43,6 +43,9 @@ int pa_property_set(struct pa_core *c, const char *name, void *data); /* Remove the specified property. Return non-zero on failure */ int pa_property_remove(struct pa_core *c, const char *name); +/* A combination of pa_property_remove() and pa_property_set() */ +int pa_property_replace(struct pa_core *c, const char *name, void *data); + /* Free all memory used by the property system */ void pa_property_cleanup(struct pa_core *c); diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index fade2a2f..0102e0ca 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -47,6 +47,8 @@ #include "log.h" #include "autoload.h" #include "authkey-prop.h" +#include "strlist.h" +#include "props.h" struct connection; struct pa_protocol_native; @@ -2064,6 +2066,7 @@ static struct pa_protocol_native* protocol_new_internal(struct pa_core *c, struc } struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { + char t[256]; struct pa_protocol_native *p; if (!(p = protocol_new_internal(core, m, ma))) @@ -2071,6 +2074,13 @@ struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct p p->server = server; pa_socket_server_set_callback(p->server, on_connection, p); + + if (pa_socket_server_get_address(p->server, t, sizeof(t))) { + struct pa_strlist *l; + l = pa_property_get(core, PA_NATIVE_SERVER_PROPERTY_NAME); + l = pa_strlist_prepend(l, t); + pa_property_replace(core, PA_NATIVE_SERVER_PROPERTY_NAME, l); + } return p; } @@ -2083,12 +2093,26 @@ void pa_protocol_native_free(struct pa_protocol_native *p) { connection_free(c); pa_idxset_free(p->connections, NULL, NULL); - if (p->server) + if (p->server) { + char t[256]; + + if (pa_socket_server_get_address(p->server, t, sizeof(t))) { + struct pa_strlist *l; + l = pa_property_get(p->core, PA_NATIVE_SERVER_PROPERTY_NAME); + l = pa_strlist_remove(l, t); + + if (l) + pa_property_replace(p->core, PA_NATIVE_SERVER_PROPERTY_NAME, l); + else + pa_property_remove(p->core, PA_NATIVE_SERVER_PROPERTY_NAME); + } + pa_socket_server_unref(p->server); + } if (p->auth_cookie_in_property) pa_authkey_prop_unref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); - + pa_xfree(p); } diff --git a/polyp/socket-client.c b/polyp/socket-client.c index fbc259ff..9b80d809 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "socket-client.h" #include "socket-util.h" @@ -47,6 +48,7 @@ struct pa_socket_client { struct pa_defer_event *defer_event; void (*callback)(struct pa_socket_client*c, struct pa_iochannel *io, void *userdata); void *userdata; + int local; }; static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) { @@ -61,6 +63,7 @@ static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) { c->defer_event = NULL; c->callback = NULL; c->userdata = NULL; + c->local = 0; return c; } @@ -85,6 +88,7 @@ static void do_call(struct pa_socket_client *c) { if (error != 0) { /* pa_log(__FILE__": connect(): %s\n", strerror(error)); */ + errno = error; goto finish; } @@ -141,63 +145,27 @@ static int do_connect(struct pa_socket_client *c, const struct sockaddr *sa, soc } struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port) { - struct pa_socket_client *c; struct sockaddr_in sa; - assert(m && address && port); - - c = pa_socket_client_new(m); - assert(c); - - if ((c->fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s\n", strerror(errno)); - goto fail; - } - - pa_fd_set_cloexec(c->fd, 1); - pa_socket_tcp_low_delay(c->fd); + assert(m && port > 0); + memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_port = htons(port); sa.sin_addr.s_addr = htonl(address); - if (do_connect(c, (struct sockaddr*) &sa, sizeof(sa)) < 0) - goto fail; - - return c; - -fail: - pa_socket_client_unref(c); - return NULL; + return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); } struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename) { - struct pa_socket_client *c; struct sockaddr_un sa; assert(m && filename); - c = pa_socket_client_new(m); - assert(c); - - if ((c->fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s\n", strerror(errno)); - goto fail; - } - - pa_fd_set_cloexec(c->fd, 1); - pa_socket_low_delay(c->fd); - + memset(&sa, 0, sizeof(sa)); sa.sun_family = AF_LOCAL; strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); sa.sun_path[sizeof(sa.sun_path) - 1] = 0; - - if (do_connect(c, (struct sockaddr*) &sa, sizeof(sa)) < 0) - goto fail; - - return c; -fail: - pa_socket_client_unref(c); - return NULL; + return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); } struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) { @@ -206,13 +174,30 @@ struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m c = pa_socket_client_new(m); assert(c); + switch (sa->sa_family) { + case AF_UNIX: + c->local = 1; + break; + + case AF_INET: + c->local = ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK; + break; + + case AF_INET6: + c->local = memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0; + break; + + default: + c->local = 0; + } + if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) { pa_log(__FILE__": socket(): %s\n", strerror(errno)); goto fail; } pa_fd_set_cloexec(c->fd, 1); - if (sa->sa_family == AF_INET) + if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) pa_socket_tcp_low_delay(c->fd); else pa_socket_low_delay(c->fd); @@ -257,3 +242,125 @@ void pa_socket_client_set_callback(struct pa_socket_client *c, void (*on_connect c->callback = on_connection; c->userdata = userdata; } + +struct pa_socket_client* pa_socket_client_new_ipv6(struct pa_mainloop_api *m, uint8_t address[16], uint16_t port) { + struct sockaddr_in6 sa; + + memset(&sa, 0, sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons(port); + memcpy(&sa.sin6_addr, address, sizeof(sa.sin6_addr)); + + return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); +} + +/* Parse addresses in one of the following forms: + * HOSTNAME + * HOSTNAME:PORT + * [HOSTNAME] + * [HOSTNAME]:PORT + * + * Return a newly allocated string of the hostname and fill in *port if specified */ + +static char *parse_address(const char *s, uint16_t *port) { + assert(s && port); + if (*s == '[') { + char *e; + if (!(e = strchr(s+1, ']'))) + return NULL; + + if (e[1] == ':') + *port = atoi(e+2); + else if (e[1] != 0) + return NULL; + + return pa_xstrndup(s+1, e-s-1); + } else { + char *e; + + if (!(e = strrchr(s, ':'))) + return pa_xstrdup(s); + + *port = atoi(e+1); + return pa_xstrndup(s, e-s); + } +} + +struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, const char*name, uint16_t default_port) { + const char *p; + struct pa_socket_client *c = NULL; + enum { KIND_UNIX, KIND_TCP_AUTO, KIND_TCP4, KIND_TCP6 } kind = KIND_TCP_AUTO; + assert(m && name); + + if (*name == '{') { + char hn[256], *pfx; + /* The URL starts with a host specification for detecting local connections */ + + if (!pa_get_host_name(hn, sizeof(hn))) + return NULL; + + pfx = pa_sprintf_malloc("{%s}", hn); + if (!pa_startswith(name, pfx)) + /* Not local */ + return NULL; + + p = name + strlen(pfx); + } else + p = name; + + if (*p == '/') + kind = KIND_UNIX; + else if (pa_startswith(p, "unix:")) { + kind = KIND_UNIX; + p += sizeof("unix:")-1; + } else if (pa_startswith(p, "tcp:") || pa_startswith(p, "tcp4:")) { + kind = KIND_TCP4; + p += sizeof("tcp:")-1; + } else if (pa_startswith(p, "tcp6:")) { + kind = KIND_TCP6; + p += sizeof("tcp6:")-1; + } + + switch (kind) { + case KIND_UNIX: + return pa_socket_client_new_unix(m, p); + + case KIND_TCP_AUTO: /* Fallthrough */ + case KIND_TCP4: + case KIND_TCP6: { + uint16_t port = default_port; + char *h; + struct addrinfo hints, *res; + + if (!(h = parse_address(p, &port))) + return NULL; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = kind == KIND_TCP4 ? AF_INET : (kind == KIND_TCP6 ? AF_INET6 : AF_UNSPEC); + + if (getaddrinfo(h, NULL, &hints, &res) < 0 || !res) + return NULL; + + if (res->ai_addr->sa_family == AF_INET) + ((struct sockaddr_in*) res->ai_addr)->sin_port = htons(port); + else if (res->ai_addr->sa_family == AF_INET6) + ((struct sockaddr_in6*) res->ai_addr)->sin6_port = htons(port); + else + return NULL; + + c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + return c; + } + } + + /* Should never be reached */ + assert(0); + return NULL; + +} + +int pa_socket_client_is_local(struct pa_socket_client *c) { + assert(c); + return c->local; +} diff --git a/polyp/socket-client.h b/polyp/socket-client.h index 1957355c..262fbac3 100644 --- a/polyp/socket-client.h +++ b/polyp/socket-client.h @@ -28,17 +28,19 @@ #include "mainloop-api.h" #include "iochannel.h" -/* It is safe to destroy the calling socket_client object from the callback */ - struct pa_socket_client; struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port); +struct pa_socket_client* pa_socket_client_new_ipv6(struct pa_mainloop_api *m, uint8_t address[16], uint16_t port); struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename); struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m, const struct sockaddr *sa, size_t salen); +struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, const char *a, uint16_t default_port); void pa_socket_client_unref(struct pa_socket_client *c); struct pa_socket_client* pa_socket_client_ref(struct pa_socket_client *c); void pa_socket_client_set_callback(struct pa_socket_client *c, void (*on_connection)(struct pa_socket_client *c, struct pa_iochannel*io, void *userdata), void *userdata); +int pa_socket_client_is_local(struct pa_socket_client *c); + #endif diff --git a/polyp/socket-server.c b/polyp/socket-server.c index c170bf6e..a37b3e34 100644 --- a/polyp/socket-server.c +++ b/polyp/socket-server.c @@ -56,7 +56,7 @@ struct pa_socket_server { struct pa_io_event *io_event; struct pa_mainloop_api *mainloop; - enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX } type; + enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX, SOCKET_SERVER_IPV6 } type; }; static void callback(struct pa_mainloop_api *mainloop, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { @@ -202,6 +202,7 @@ struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, ui pa_socket_tcp_low_delay(fd); + memset(&sa, sizeof(sa), 0); sa.sin_family = AF_INET; sa.sin_port = htons(port); sa.sin_addr.s_addr = htonl(address); @@ -230,6 +231,53 @@ fail: return NULL; } +struct pa_socket_server* pa_socket_server_new_ipv6(struct pa_mainloop_api *m, uint8_t address[16], uint16_t port) { + struct pa_socket_server *ss; + int fd = -1; + struct sockaddr_in6 sa; + int on = 1; + + assert(m && port); + + if ((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) { + pa_log(__FILE__": socket(): %s\n", strerror(errno)); + goto fail; + } + + pa_fd_set_cloexec(fd, 1); + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) + pa_log(__FILE__": setsockopt(): %s\n", strerror(errno)); + + pa_socket_tcp_low_delay(fd); + + memset(&sa, sizeof(sa), 0); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons(port); + memcpy(sa.sin6_addr.s6_addr, address, 16); + + if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { + pa_log(__FILE__": bind(): %s\n", strerror(errno)); + goto fail; + } + + if (listen(fd, 5) < 0) { + pa_log(__FILE__": listen(): %s\n", strerror(errno)); + goto fail; + } + + if ((ss = pa_socket_server_new(m, fd))) + ss->type = SOCKET_SERVER_IPV6; + + return ss; + +fail: + if (fd >= 0) + close(fd); + + return NULL; +} + static void socket_server_free(struct pa_socket_server*s) { assert(s); close(s->fd); @@ -258,3 +306,98 @@ void pa_socket_server_set_callback(struct pa_socket_server*s, void (*on_connecti s->on_connection = on_connection; s->userdata = userdata; } + + +char *pa_socket_server_get_address(struct pa_socket_server *s, char *c, size_t l) { + assert(s && c && l > 0); + + switch (s->type) { + case SOCKET_SERVER_IPV6: { + struct sockaddr_in6 sa; + socklen_t l = sizeof(sa); + + if (getsockname(s->fd, (struct sockaddr*) &sa, &l) < 0) { + pa_log(__FILE__": getsockname() failed: %s\n", strerror(errno)); + return NULL; + } + + if (memcmp(&in6addr_any, &sa.sin6_addr, sizeof(in6addr_any)) == 0) { + char fqdn[256]; + if (!pa_get_fqdn(fqdn, sizeof(fqdn))) + return NULL; + + snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port)); + + } else if (memcmp(&in6addr_loopback, &sa.sin6_addr, sizeof(in6addr_loopback)) == 0) { + char hn[256]; + if (!pa_get_host_name(hn, sizeof(hn))) + return NULL; + + snprintf(c, l, "{%s}tcp6:localhost:%u", hn, (unsigned) ntohs(sa.sin6_port)); + } else { + char ip[INET6_ADDRSTRLEN]; + + if (!inet_ntop(AF_INET6, &sa.sin6_addr, ip, sizeof(ip))) { + pa_log(__FILE__": inet_ntop() failed: %s\n", strerror(errno)); + return NULL; + } + + snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port)); + } + + return c; + } + + case SOCKET_SERVER_IPV4: { + struct sockaddr_in sa; + socklen_t l = sizeof(sa); + + if (getsockname(s->fd, &sa, &l) < 0) { + pa_log(__FILE__": getsockname() failed: %s\n", strerror(errno)); + return NULL; + } + + if (sa.sin_addr.s_addr == INADDR_ANY) { + char fqdn[256]; + if (!pa_get_fqdn(fqdn, sizeof(fqdn))) + return NULL; + + snprintf(c, l, "tcp:%s:%u", fqdn, (unsigned) ntohs(sa.sin_port)); + } else if (sa.sin_addr.s_addr == INADDR_LOOPBACK) { + char hn[256]; + if (!pa_get_host_name(hn, sizeof(hn))) + return NULL; + + snprintf(c, l, "{%s}tcp:localhost:%u", hn, (unsigned) ntohs(sa.sin_port)); + } else { + char ip[INET_ADDRSTRLEN]; + + if (!inet_ntop(AF_INET, &sa.sin_addr, ip, sizeof(ip))) { + pa_log(__FILE__": inet_ntop() failed: %s\n", strerror(errno)); + return NULL; + } + + snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port)); + + } + + return c; + } + + case SOCKET_SERVER_UNIX: { + char hn[256]; + + if (!s->filename) + return NULL; + + if (!pa_get_host_name(hn, sizeof(hn))) + return NULL; + + snprintf(c, l, "{%s}unix:%s", hn, s->filename); + return c; + } + + default: + return NULL; + } +} diff --git a/polyp/socket-server.h b/polyp/socket-server.h index f5877e55..cc5524d1 100644 --- a/polyp/socket-server.h +++ b/polyp/socket-server.h @@ -33,10 +33,13 @@ struct pa_socket_server; struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd); struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename); struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service); +struct pa_socket_server* pa_socket_server_new_ipv6(struct pa_mainloop_api *m, uint8_t address[16], uint16_t port); void pa_socket_server_unref(struct pa_socket_server*s); struct pa_socket_server* pa_socket_server_ref(struct pa_socket_server *s); void pa_socket_server_set_callback(struct pa_socket_server*s, void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata), void *userdata); +char *pa_socket_server_get_address(struct pa_socket_server *s, char *c, size_t l); + #endif diff --git a/polyp/socket-util.c b/polyp/socket-util.c index 96ea2c60..e0540179 100644 --- a/polyp/socket-util.c +++ b/polyp/socket-util.c @@ -114,7 +114,7 @@ int pa_socket_tcp_low_delay(int fd) { ret = pa_socket_low_delay(fd); on = 1; -/* + #if defined(SOL_TCP) || defined(IPPROTO_TCP) #if defined(SOL_TCP) if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) @@ -123,7 +123,6 @@ int pa_socket_tcp_low_delay(int fd) { #endif ret = -1; #endif -*/ #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || \ defined(IPPROTO_IP)) @@ -204,42 +203,6 @@ int pa_unix_socket_remove_stale(const char *fn) { return 0; } -int pa_unix_socket_make_secure_dir(const char *fn) { - int ret = -1; - char *slash, *dir = pa_xstrdup(fn); - - if (!(slash = strrchr(dir, '/'))) - goto finish; - *slash = 0; - - if (pa_make_secure_dir(dir) < 0) - goto finish; - - ret = 0; - -finish: - pa_xfree(dir); - return ret; -} - -int pa_unix_socket_remove_secure_dir(const char *fn) { - int ret = -1; - char *slash, *dir = pa_xstrdup(fn); - - if (!(slash = strrchr(dir, '/'))) - goto finish; - *slash = 0; - - if (rmdir(dir) < 0) - goto finish; - - ret = 0; - -finish: - pa_xfree(dir); - return ret; -} - struct sockaddr *pa_resolve_server(const char *server, size_t *len, uint16_t nport) { struct sockaddr *sa; struct addrinfo hints, *result = NULL; diff --git a/polyp/socket-util.h b/polyp/socket-util.h index 46fcfdc9..aa2de8a5 100644 --- a/polyp/socket-util.h +++ b/polyp/socket-util.h @@ -35,9 +35,6 @@ int pa_socket_set_rcvbuf(int fd, size_t l); int pa_unix_socket_is_stale(const char *fn); int pa_unix_socket_remove_stale(const char *fn); -int pa_unix_socket_make_secure_dir(const char *fn); -int pa_unix_socket_remove_secure_dir(const char *fn); - struct sockaddr *pa_resolve_server(const char *server, size_t *len, uint16_t port); #endif diff --git a/polyp/strlist-test.c b/polyp/strlist-test.c new file mode 100644 index 00000000..01dcdf12 --- /dev/null +++ b/polyp/strlist-test.c @@ -0,0 +1,39 @@ +#include + +#include "strlist.h" +#include "xmalloc.h" + +int main(int argc, char* argv[]) { + char *t, *u; + struct pa_strlist *l = NULL; + + l = pa_strlist_prepend(l, "e"); + l = pa_strlist_prepend(l, "d"); + l = pa_strlist_prepend(l, "c"); + l = pa_strlist_prepend(l, "b"); + l = pa_strlist_prepend(l, "a"); + + t = pa_strlist_tostring(l); + pa_strlist_free(l); + + fprintf(stderr, "1: %s\n", t); + + l = pa_strlist_parse(t); + pa_xfree(t); + + t = pa_strlist_tostring(l); + fprintf(stderr, "2: %s\n", t); + pa_xfree(t); + + l = pa_strlist_pop(l, &u); + fprintf(stderr, "3: %s\n", u); + pa_xfree(u); + + l = pa_strlist_remove(l, "c"); + + t = pa_strlist_tostring(l); + fprintf(stderr, "4: %s\n", t); + pa_xfree(t); + + pa_strlist_free(l); +} diff --git a/polyp/strlist.c b/polyp/strlist.c new file mode 100644 index 00000000..df7278d2 --- /dev/null +++ b/polyp/strlist.c @@ -0,0 +1,137 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "strlist.h" +#include "xmalloc.h" +#include "strbuf.h" +#include "util.h" + +struct pa_strlist { + struct pa_strlist *next; + char *str; +}; + +struct pa_strlist* pa_strlist_prepend(struct pa_strlist *l, const char *s) { + struct pa_strlist *n; + assert(s); + n = pa_xmalloc(sizeof(struct pa_strlist)); + n->str = pa_xstrdup(s); + n->next = l; + return n; +} + +char *pa_strlist_tostring(struct pa_strlist *l) { + int first = 1; + struct pa_strbuf *b; + + b = pa_strbuf_new(); + for (; l; l = l->next) { + if (!first) + pa_strbuf_puts(b, " "); + first = 0; + pa_strbuf_puts(b, l->str); + } + + return pa_strbuf_tostring_free(b); +} + +struct pa_strlist* pa_strlist_remove(struct pa_strlist *l, const char *s) { + struct pa_strlist *ret = l, *prev = NULL; + assert(l && s); + + while (l) { + if (!strcmp(l->str, s)) { + struct pa_strlist *n = l->next; + + if (!prev) { + assert(ret == l); + ret = n; + } else + prev->next = n; + + pa_xfree(l->str); + pa_xfree(l); + + l = n; + + } else { + prev = l; + l = l->next; + } + } + + return ret; +} + +void pa_strlist_free(struct pa_strlist *l) { + while (l) { + struct pa_strlist *c = l; + l = l->next; + + pa_xfree(c->str); + pa_xfree(c); + } +} + +struct pa_strlist* pa_strlist_pop(struct pa_strlist *l, char **s) { + struct pa_strlist *r; + assert(s); + + if (!l) { + *s = NULL; + return NULL; + } + + *s = l->str; + r = l->next; + pa_xfree(l); + return r; +} + +struct pa_strlist* pa_strlist_parse(const char *s) { + struct pa_strlist *head = NULL, *p = NULL; + const char *state = NULL; + char *r; + + while ((r = pa_split_spaces(s, &state))) { + struct pa_strlist *n; + + n = pa_xmalloc(sizeof(struct pa_strlist)); + n->str = r; + n->next = NULL; + + if (p) + p->next = n; + else + head = n; + + p = n; + } + + return head; +} diff --git a/polyp/strlist.h b/polyp/strlist.h new file mode 100644 index 00000000..2a209dba --- /dev/null +++ b/polyp/strlist.h @@ -0,0 +1,47 @@ +#ifndef foostrlisthfoo +#define foostrlisthfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +struct pa_strlist; + +/* Add the specified server string to the list, return the new linked list head */ +struct pa_strlist* pa_strlist_prepend(struct pa_strlist *l, const char *s); + +/* Remove the specified string from the list, return the new linked list head */ +struct pa_strlist* pa_strlist_remove(struct pa_strlist *l, const char *s); + +/* Make a whitespace separated string of all server stringes. Returned memory has to be freed with pa_xfree() */ +char *pa_strlist_tostring(struct pa_strlist *l); + +/* Free the entire list */ +void pa_strlist_free(struct pa_strlist *l); + +/* Return the next entry in the list in *string and remove it from + * the list. Returns the new list head. The memory *string points to + * has to be freed with pa_xfree() */ +struct pa_strlist* pa_strlist_pop(struct pa_strlist *l, char **s); + +/* Parse a whitespace separated server list */ +struct pa_strlist* pa_strlist_parse(const char *s); + +#endif diff --git a/polyp/util.c b/polyp/util.c index ad91a307..4db92cf4 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -51,6 +51,8 @@ #include "xmalloc.h" #include "log.h" +#define PA_RUNTIME_PATH_PREFIX "/tmp/polypaudio-" + /** Make a file descriptor nonblock. Doesn't do any error checking */ void pa_make_nonblock_fd(int fd) { int v; @@ -83,6 +85,26 @@ fail: return -1; } +/* Creates a the parent directory of the specified path securely */ +int pa_make_secure_parent_dir(const char *fn) { + int ret = -1; + char *slash, *dir = pa_xstrdup(fn); + + if (!(slash = strrchr(dir, '/'))) + goto finish; + *slash = 0; + + if (pa_make_secure_dir(dir) < 0) + goto finish; + + ret = 0; + +finish: + pa_xfree(dir); + return ret; +} + + /** Calls read() in a loop. Makes sure that as much as 'size' bytes, * unless EOF is reached or an error occured */ ssize_t pa_loop_read(int fd, void*data, size_t size) { @@ -225,31 +247,32 @@ char *pa_get_user_name(char *s, size_t l) { char *p; assert(s && l > 0); - if (!(p = getenv("USER"))) - if (!(p = getenv("LOGNAME"))) - if (!(p = getenv("USERNAME"))) { - + if (!(p = getenv("USER")) && !(p = getenv("LOGNAME")) && !(p = getenv("USERNAME"))) { + #ifdef HAVE_GETPWUID_R - if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { + if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { #else - /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) - * that do not support getpwuid_r. */ - if ((r = getpwuid(getuid())) == NULL) { + /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) + * that do not support getpwuid_r. */ + if ((r = getpwuid(getuid())) == NULL) { #endif - snprintf(s, l, "%lu", (unsigned long) getuid()); - return s; - } - - p = r->pw_name; + snprintf(s, l, "%lu", (unsigned long) getuid()); + return s; } + + p = r->pw_name; + } return pa_strlcpy(s, p, l); -} + } /* Return the current hostname in the specified buffer. */ char *pa_get_host_name(char *s, size_t l) { assert(s && l > 0); - gethostname(s, l); + if (gethostname(s, l) < 0) { + pa_log(__FILE__": gethostname(): %s\n", strerror(errno)); + return NULL; + } s[l-1] = 0; return s; } @@ -264,8 +287,10 @@ char *pa_get_home_dir(char *s, size_t l) { if ((e = getenv("HOME"))) return pa_strlcpy(s, e, l); - if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) + if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { + pa_log(__FILE__": getpwuid_r() failed\n"); return NULL; + } return pa_strlcpy(s, r->pw_dir, l); } @@ -479,7 +504,7 @@ char *pa_split_spaces(const char *c, const char **state) { const char *current = *state ? *state : c; size_t l; - if (!*current) + if (!*current || *c == 0) return NULL; current += strspn(current, WHITESPACE); @@ -768,13 +793,13 @@ size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) { return (size_t) -1; d[j] |= (uint8_t) b; - j++; } return j; } +/* Return the fully qualified domain name in *s */ char *pa_get_fqdn(char *s, size_t l) { char hn[256]; struct addrinfo *a, hints; @@ -793,3 +818,25 @@ char *pa_get_fqdn(char *s, size_t l) { freeaddrinfo(a); return s; } + +/* Returns nonzero when *s starts with *pfx */ +int pa_startswith(const char *s, const char *pfx) { + size_t l; + assert(s && pfx); + l = strlen(pfx); + + return strlen(s) >= l && strncmp(s, pfx, l) == 0; +} + +/* if fn is null return the polypaudio run time path in s (/tmp/polypaudio) + * if fn is non-null and starts with / return fn in s + * otherwise append fn to the run time path and return it in s */ +char *pa_runtime_path(const char *fn, char *s, size_t l) { + char u[256]; + + if (fn && *fn == '/') + return pa_strlcpy(s, fn, l); + + snprintf(s, l, PA_RUNTIME_PATH_PREFIX"%s%s%s", pa_get_user_name(u, sizeof(u)), fn ? "/" : "", fn ? fn : ""); + return s; +} diff --git a/polyp/util.h b/polyp/util.h index 3f09a9a7..e9d938ce 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -33,6 +33,7 @@ void pa_make_nonblock_fd(int fd); int pa_make_secure_dir(const char* dir); +int pa_make_secure_parent_dir(const char *fn); ssize_t pa_loop_read(int fd, void*data, size_t size); ssize_t pa_loop_write(int fd, const void*data, size_t size); @@ -85,4 +86,8 @@ FILE *pa_open_config_file(const char *env, const char *global, const char *local char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength); size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength); +int pa_startswith(const char *s, const char *pfx); + +char *pa_runtime_path(const char *fn, char *s, size_t l); + #endif -- cgit From 6de0cdaaa9eb7d64c915bada450d3afc8746dd9c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 12 Nov 2004 00:42:34 +0000 Subject: remove a debug message git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@281 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/polyplib-context.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index a4770313..62d1ff0d 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -524,8 +524,6 @@ static void on_connection(struct pa_socket_client *client, struct pa_iochannel*i c->client = NULL; if (!io) { - pa_log("failure: %s\n", strerror(errno)); - /* Try the item in the list */ if (errno == ECONNREFUSED || errno == ETIMEDOUT || errno == EHOSTUNREACH) { try_next_connection(c); -- cgit From d7d8529c4654a6681b8e5e40dface6cd774f0231 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 14 Nov 2004 00:04:51 +0000 Subject: * remove as superfluous assert() in polyplib-stream which broke the gstreamer plugin * fix module-tunnel meta info git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@282 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-tunnel.c | 4 ++-- polyp/polyplib-stream.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c index c899929f..712ec359 100644 --- a/polyp/module-tunnel.c +++ b/polyp/module-tunnel.c @@ -50,11 +50,11 @@ #ifdef TUNNEL_SINK #include "module-tunnel-sink-symdef.h" PA_MODULE_DESCRIPTION("Tunnel module for sinks") -PA_MODULE_USAGE("server= sink= cookie= format= channels= rate= sink_name=") +PA_MODULE_USAGE("server=
    sink= cookie= format= channels= rate= sink_name=") #else #include "module-tunnel-source-symdef.h" PA_MODULE_DESCRIPTION("Tunnel module for sources") -PA_MODULE_USAGE("server= source= cookie= format= channels= rate= source_name=") +PA_MODULE_USAGE("server=
    source= cookie= format= channels= rate= source_name=") #endif PA_MODULE_AUTHOR("Lennart Poettering") diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 312f1deb..b1f19855 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -351,8 +351,8 @@ void pa_stream_write(struct pa_stream *s, const void *data, size_t length, void } size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s && s->state == PA_STREAM_READY && s->ref >= 1); - return s->requested_bytes; + assert(s && s->ref >= 1); + return s->state == PA_STREAM_READY ? s->requested_bytes : 0; } struct pa_operation * pa_stream_drain(struct pa_stream *s, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { -- cgit From be6a1c28cfa89011f2fa55defe638199e910909b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 14 Nov 2004 02:36:35 +0000 Subject: * implement module-esound-sink git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@283 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/modules.html.in | 17 +- doc/todo | 1 - polyp/Makefile.am | 10 +- polyp/module-esound-sink.c | 426 +++++++++++++++++++++++++++++++++++++++++++++ polyp/module-pipe-sink.c | 8 + 5 files changed, 456 insertions(+), 6 deletions(-) create mode 100644 polyp/module-esound-sink.c diff --git a/doc/modules.html.in b/doc/modules.html.in index 5e9b8873..14fe7278 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -138,6 +138,17 @@ buffer control is lost through this tunneling.

    cookie=The authentication cookie file to use. +

    module-esound-sink

    + +

    Create a playback sink using an ESOUND server as backend. Whenever you can, try to omit this +module since it has many disadvantages including bad latency +and even worse latency measurement.

    + + + + +
    server=The server to connect to
    cookie=The authentication cookie file to use.
    +

    Protocols

    @@ -157,7 +168,7 @@ module see cli.html. -

    module-cli-protocol-{unix,tcp}

    +

    module-cli-protocol-{unix,tcp,tcp6}

    An implemenation of a simple command line based protocol for controlling the polypaudio daemon. If loaded, the user may @@ -183,7 +194,7 @@ device, i.e. not publicly accessible. (defaults to 1) socket=(only for -unix) The UNIX socket name (defaults to /tmp/polypaudio/cli) -

    module-simple-protocol-{unix,tcp}

    +

    module-simple-protocol-{unix,tcp,tcp6}

    An implementation of a simple protocol which allows playback by using simple tools like netcat. Just connect to the listening @@ -226,7 +237,7 @@ about the two possible suffixes of this module.

    This implementation misses some features the original ESOUND has: e.g. there is no sample cache yet. However: XMMS works fine.

    -

    module-native-protocol-{unix,tcp}

    +

    module-native-protocol-{unix,tcp,tcp6}

    The native protocol of polypaudio.

    diff --git a/doc/todo b/doc/todo index 99e06569..75983e7e 100644 --- a/doc/todo +++ b/doc/todo @@ -18,7 +18,6 @@ - add LGPL blurb to all concerning files - non-fp mixing - non-fp resampling -- esound backend ** later *** - xmlrpc/http diff --git a/polyp/Makefile.am b/polyp/Makefile.am index c4f9e2d2..585b16c0 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -115,7 +115,8 @@ modlib_LTLIBRARIES= \ module-match.la \ module-tunnel-sink.la \ module-tunnel-source.la \ - module-null-sink.la + module-null-sink.la \ + module-esound-sink.la SYMDEF_FILES= \ module-cli-symdef.h \ @@ -143,7 +144,8 @@ SYMDEF_FILES= \ module-match-symdef.h \ module-tunnel-sink-symdef.h \ module-tunnel-source-symdef.h \ - module-null-sink-symdef.h + module-null-sink-symdef.h \ + module-esound-sink-symdef.h EXTRA_DIST+=$(SYMDEF_FILES) BUILT_SOURCES+=$(SYMDEF_FILES) @@ -400,6 +402,10 @@ module_esound_compat_spawnpid_la_SOURCES = module-esound-compat-spawnpid.c module_esound_compat_spawnpid_la_LDFLAGS = -module -avoid-version module_esound_compat_spawnpid_la_LIBADD = $(AM_LIBADD) +module_esound_sink_la_SOURCES = module-esound-sink.c +module_esound_sink_la_LDFLAGS = -module -avoid-version +module_esound_sink_la_LIBADD = $(AM_LIBADD) libsocket-client.la libauthkey.la + libpolyp_@PA_MAJORMINOR@_la_SOURCES = polyplib.h \ polyplib-def.h \ tagstruct.c tagstruct.h \ diff --git a/polyp/module-esound-sink.c b/polyp/module-esound-sink.c new file mode 100644 index 00000000..fadf8456 --- /dev/null +++ b/polyp/module-esound-sink.c @@ -0,0 +1,426 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iochannel.h" +#include "sink.h" +#include "module.h" +#include "util.h" +#include "modargs.h" +#include "xmalloc.h" +#include "log.h" +#include "module-esound-sink-symdef.h" +#include "socket-client.h" +#include "esound.h" +#include "authkey.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Esound ") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink_name= server=
    cookie= format= channels= rate=") + +#define DEFAULT_SINK_NAME "esound_output" + +struct userdata { + struct pa_core *core; + + struct pa_sink *sink; + struct pa_iochannel *io; + struct pa_socket_client *client; + + struct pa_defer_event *defer_event; + + struct pa_memchunk memchunk; + struct pa_module *module; + + void *write_data; + size_t write_length, write_index; + + void *read_data; + size_t read_length, read_index; + + enum { STATE_AUTH, STATE_LATENCY, STATE_RUNNING, STATE_DEAD } state; + + pa_usec_t latency; + + esd_format_t format; + int32_t rate; +}; + +static const char* const valid_modargs[] = { + "server", + "cookie", + "rate", + "format", + "channels", + "sink_name", + NULL +}; + +static void cancel(struct userdata *u) { + assert(u); + + u->state = STATE_DEAD; + + if (u->io) { + pa_iochannel_free(u->io); + u->io = NULL; + } + + if (u->defer_event) { + u->core->mainloop->defer_free(u->defer_event); + u->defer_event = NULL; + } + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + u->sink = NULL; + } + + if (u->module) { + pa_module_unload_request(u->module); + u->module = NULL; + } +} + +static int do_write(struct userdata *u) { + ssize_t r; + assert(u); + + if (!pa_iochannel_is_writable(u->io)) + return 0; + + if (u->write_data) { + assert(u->write_index < u->write_length); + + if ((r = pa_iochannel_write(u->io, (uint8_t*) u->write_data + u->write_index, u->write_length - u->write_index)) <= 0) { + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + return -1; + } + + u->write_index += r; + assert(u->write_index <= u->write_length); + + if (u->write_index == u->write_length) { + free(u->write_data); + u->write_data = NULL; + u->write_index = u->write_length = 0; + } + } else if (u->state == STATE_RUNNING) { + pa_module_set_used(u->module, pa_idxset_ncontents(u->sink->inputs) + pa_idxset_ncontents(u->sink->monitor_source->outputs)); + + if (!u->memchunk.length) + if (pa_sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0) + return 0; + + assert(u->memchunk.memblock && u->memchunk.length); + + if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + return -1; + } + + u->memchunk.index += r; + u->memchunk.length -= r; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + } + } + + return 0; +} + +static int handle_response(struct userdata *u) { + assert(u); + + switch (u->state) { + case STATE_AUTH: + assert(u->read_length == sizeof(int32_t)); + + /* Process auth data */ + if (!*(int32_t*) u->read_data) { + pa_log(__FILE__": Authentication failed: %s\n", strerror(errno)); + return -1; + } + + /* Request latency data */ + assert(!u->write_data); + *(int32_t*) (u->write_data = pa_xmalloc(u->write_length = sizeof(int32_t))) = ESD_PROTO_LATENCY; + + u->write_index = 0; + u->state = STATE_LATENCY; + + /* Space for next response */ + assert(u->read_length >= sizeof(int32_t)); + u->read_index = 0; + u->read_length = sizeof(int32_t); + + break; + + case STATE_LATENCY: { + int32_t *p; + assert(u->read_length == sizeof(int32_t)); + + /* Process latency info */ + u->latency = (pa_usec_t) ((double) (*(int32_t*) u->read_data) * 1000000 / 44100); + if (u->latency > 10000000) { + pa_log(__FILE__": WARNING! Invalid latency information received from server\n"); + u->latency = 0; + } + + /* Create stream */ + assert(!u->write_data); + p = u->write_data = pa_xmalloc0(u->write_length = sizeof(int32_t)*3+ESD_NAME_MAX); + *(p++) = ESD_PROTO_STREAM_PLAY; + *(p++) = u->format; + *(p++) = u->rate; + pa_strlcpy((char*) p, "Polypaudio Tunnel", ESD_NAME_MAX); + + u->write_index = 0; + u->state = STATE_RUNNING; + + /* Don't read any further */ + pa_xfree(u->read_data); + u->read_data = NULL; + u->read_index = u->read_length = 0; + + break; + } + + default: + abort(); + } + + return 0; +} + +static int do_read(struct userdata *u) { + assert(u); + + if (!pa_iochannel_is_readable(u->io)) + return 0; + + if (u->state == STATE_AUTH || u->state == STATE_LATENCY) { + ssize_t r; + + if (!u->read_data) + return 0; + + assert(u->read_index < u->read_length); + + if ((r = pa_iochannel_read(u->io, (uint8_t*) u->read_data + u->read_index, u->read_length - u->read_index)) <= 0) { + pa_log(__FILE__": read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); + cancel(u); + return -1; + } + + u->read_index += r; + assert(u->read_index <= u->read_length); + + if (u->read_index == u->read_length) + return handle_response(u); + } + + return 0; +} + +static void do_work(struct userdata *u) { + assert(u); + + u->core->mainloop->defer_enable(u->defer_event, 0); + + if (do_read(u) < 0 || do_write(u) < 0) + cancel(u); +} + +static void notify_cb(struct pa_sink*s) { + struct userdata *u = s->userdata; + assert(s && u); + + if (pa_iochannel_is_writable(u->io)) + u->core->mainloop->defer_enable(u->defer_event, 1); +} + +static pa_usec_t get_latency_cb(struct pa_sink *s) { + struct userdata *u = s->userdata; + assert(s && u); + + return + u->latency + + (u->memchunk.memblock ? pa_bytes_to_usec(u->memchunk.length, &s->sample_spec) : 0); +} + +static void defer_callback(struct pa_mainloop_api *m, struct pa_defer_event*e, void *userdata) { + struct userdata *u = userdata; + assert(u); + do_work(u); +} + +static void io_callback(struct pa_iochannel *io, void*userdata) { + struct userdata *u = userdata; + assert(u); + do_work(u); +} + +static void on_connection(struct pa_socket_client *c, struct pa_iochannel*io, void *userdata) { + struct userdata *u = userdata; + + pa_socket_client_unref(u->client); + u->client = NULL; + + if (!io) { + pa_log(__FILE__": connection failed: %s\n", strerror(errno)); + cancel(u); + return; + } + + u->io = io; + pa_iochannel_set_callback(u->io, io_callback, u); +} + +int pa__init(struct pa_core *c, struct pa_module*m) { + struct userdata *u = NULL; + const char *p; + struct pa_sample_spec ss; + struct pa_modargs *ma = NULL; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": invalid sample format specification\n"); + goto fail; + } + + if ((ss.format != PA_SAMPLE_U8 && ss.format != PA_SAMPLE_S16NE) || + (ss.channels > 2)) { + pa_log(__FILE__": esound sample type support is limited to mono/stereo and U8 or S16NE sample data\n"); + goto fail; + } + + u = pa_xmalloc0(sizeof(struct userdata)); + u->core = c; + u->module = m; + m->userdata = u; + u->format = + (ss.format == PA_SAMPLE_U8 ? ESD_BITS8 : ESD_BITS16) | + (ss.channels == 2 ? ESD_STEREO : ESD_MONO); + u->rate = ss.rate; + u->sink = NULL; + u->client = NULL; + u->io = NULL; + u->read_data = u->write_data = NULL; + u->read_index = u->write_index = u->read_length = u->write_length = 0; + u->state = STATE_AUTH; + u->latency = 0; + + if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { + pa_log(__FILE__": failed to create sink.\n"); + goto fail; + } + + if (!(u->client = pa_socket_client_new_string(u->core->mainloop, p = pa_modargs_get_value(ma, "server", ESD_UNIX_SOCKET_NAME), ESD_DEFAULT_PORT))) { + pa_log(__FILE__": failed to connect to server.\n"); + goto fail; + } + pa_socket_client_set_callback(u->client, on_connection, u); + + /* Prepare the initial request */ + u->write_data = pa_xmalloc(u->write_length = ESD_KEY_LEN + sizeof(int32_t)); + if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", ".esd_auth"), u->write_data, ESD_KEY_LEN) < 0) { + pa_log(__FILE__": failed to load cookie\n"); + goto fail; + } + *(int32_t*) ((uint8_t*) u->write_data + ESD_KEY_LEN) = ESD_ENDIAN_KEY; + + /* Reserve space for the response */ + u->read_data = pa_xmalloc(u->read_length = sizeof(int32_t)); + + u->sink->notify = notify_cb; + u->sink->get_latency = get_latency_cb; + u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Esound sink '%s'", p); + + u->memchunk.memblock = NULL; + u->memchunk.length = 0; + + u->defer_event = c->mainloop->defer_new(c->mainloop, defer_callback, u); + c->mainloop->defer_enable(u->defer_event, 0); + + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + pa__done(c, m); + + return -1; +} + +void pa__done(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + u->module = NULL; + cancel(u); + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + + if (u->client) + pa_socket_client_unref(u->client); + + pa_xfree(u->read_data); + pa_xfree(u->write_data); + + pa_xfree(u); +} + + + diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c index bc8abb41..e445584e 100644 --- a/polyp/module-pipe-sink.c +++ b/polyp/module-pipe-sink.c @@ -111,6 +111,13 @@ static void notify_cb(struct pa_sink*s) { u->core->mainloop->defer_enable(u->defer_event, 1); } +static pa_usec_t get_latency_cb(struct pa_sink *s) { + struct userdata *u = s->userdata; + assert(s && u); + + return u->memchunk.memblock ? pa_bytes_to_usec(u->memchunk.length, &s->sample_spec) : 0; +} + static void defer_callback(struct pa_mainloop_api *m, struct pa_defer_event*e, void *userdata) { struct userdata *u = userdata; assert(u); @@ -173,6 +180,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { goto fail; } u->sink->notify = notify_cb; + u->sink->get_latency = get_latency_cb; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); u->sink->description = pa_sprintf_malloc("Unix FIFO sink '%s'", p); -- cgit From fa499dad06ba6558111cdef64c18f2401e803cff Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 14 Nov 2004 14:58:54 +0000 Subject: Make the whole stuff LGPL only git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@284 fefdeb5f-60dc-0310-8127-8f9354f1896f --- GPL | 340 ---------------------- LGPL | 510 --------------------------------- LICENSE | 512 +++++++++++++++++++++++++++++++++- Makefile.am | 6 +- bootstrap.sh | 4 +- configure.ac | 4 +- doc/Makefile.am | 4 +- doc/README.html.in | 6 +- doc/style.css | 4 +- doc/todo | 1 + doxygen/Makefile.am | 4 +- polyp/Makefile.am | 4 +- polyp/alsa-util.c | 4 +- polyp/alsa-util.h | 4 +- polyp/authkey-prop.c | 4 +- polyp/authkey-prop.h | 4 +- polyp/authkey.c | 12 +- polyp/authkey.h | 12 +- polyp/autoload.c | 4 +- polyp/autoload.h | 4 +- polyp/caps.c | 4 +- polyp/caps.h | 4 +- polyp/cdecl.h | 4 +- polyp/cli-command.c | 4 +- polyp/cli-command.h | 4 +- polyp/cli-text.c | 4 +- polyp/cli-text.h | 4 +- polyp/cli.c | 4 +- polyp/cli.h | 4 +- polyp/client-conf-x11.c | 4 +- polyp/client-conf-x11.h | 4 +- polyp/client-conf.c | 4 +- polyp/client-conf.h | 4 +- polyp/client.c | 4 +- polyp/client.conf.in | 4 +- polyp/client.h | 4 +- polyp/cmdline.c | 4 +- polyp/cmdline.h | 4 +- polyp/conf-parser.c | 4 +- polyp/conf-parser.h | 4 +- polyp/core.c | 4 +- polyp/core.h | 4 +- polyp/cpulimit-test.c | 4 +- polyp/cpulimit.c | 4 +- polyp/cpulimit.h | 4 +- polyp/daemon-conf.c | 4 +- polyp/daemon-conf.h | 4 +- polyp/daemon.conf.in | 4 +- polyp/debug.h | 4 +- polyp/default.pa.in | 4 +- polyp/depmod.py | 4 +- polyp/dumpmodules.c | 4 +- polyp/dumpmodules.h | 4 +- polyp/dynarray.c | 12 +- polyp/dynarray.h | 12 +- polyp/endianmacros.h | 4 +- polyp/esdcompat.sh.in | 4 +- polyp/esound.h | 4 +- polyp/glib-mainloop.c | 4 +- polyp/glib-mainloop.h | 4 +- polyp/glib12-mainloop.c | 4 +- polyp/hashmap.c | 4 +- polyp/hashmap.h | 4 +- polyp/idxset.c | 12 +- polyp/idxset.h | 12 +- polyp/iochannel.c | 12 +- polyp/iochannel.h | 12 +- polyp/ioline.c | 4 +- polyp/ioline.h | 4 +- polyp/llist.h | 4 +- polyp/main.c | 4 +- polyp/mainloop-api.c | 12 +- polyp/mainloop-api.h | 12 +- polyp/mainloop-signal.c | 4 +- polyp/mainloop-signal.h | 4 +- polyp/mainloop-test.c | 4 +- polyp/mainloop.c | 4 +- polyp/mainloop.h | 4 +- polyp/memblock.c | 12 +- polyp/memblock.h | 12 +- polyp/memblockq.c | 4 +- polyp/memblockq.h | 4 +- polyp/memchunk.c | 12 +- polyp/memchunk.h | 12 +- polyp/modargs.c | 4 +- polyp/modargs.h | 4 +- polyp/modinfo.c | 4 +- polyp/modinfo.h | 4 +- polyp/module-alsa-sink.c | 4 +- polyp/module-alsa-source.c | 4 +- polyp/module-cli.c | 4 +- polyp/module-combine.c | 4 +- polyp/module-esound-compat-spawnfd.c | 4 +- polyp/module-esound-compat-spawnpid.c | 4 +- polyp/module-esound-sink.c | 4 +- polyp/module-match.c | 4 +- polyp/module-native-protocol-fd.c | 4 +- polyp/module-null-sink.c | 4 +- polyp/module-oss-mmap.c | 4 +- polyp/module-oss.c | 4 +- polyp/module-pipe-sink.c | 4 +- polyp/module-pipe-source.c | 4 +- polyp/module-protocol-stub.c | 4 +- polyp/module-sine.c | 4 +- polyp/module-tunnel.c | 4 +- polyp/module-x11-bell.c | 4 +- polyp/module-x11-publish.c | 4 +- polyp/module.c | 4 +- polyp/module.h | 4 +- polyp/namereg.c | 4 +- polyp/namereg.h | 4 +- polyp/native-common.h | 12 +- polyp/oss-util.c | 4 +- polyp/oss-util.h | 4 +- polyp/pacat-simple.c | 4 +- polyp/pacat.c | 4 +- polyp/packet.c | 12 +- polyp/packet.h | 12 +- polyp/pactl.c | 4 +- polyp/paplay.c | 4 +- polyp/parec-simple.c | 4 +- polyp/pax11publish.c | 4 +- polyp/pdispatch.c | 12 +- polyp/pdispatch.h | 12 +- polyp/play-memchunk.c | 4 +- polyp/play-memchunk.h | 4 +- polyp/polyplib-context.c | 4 +- polyp/polyplib-context.h | 4 +- polyp/polyplib-def.h | 12 +- polyp/polyplib-error.c | 4 +- polyp/polyplib-error.h | 4 +- polyp/polyplib-internal.h | 4 +- polyp/polyplib-introspect.c | 4 +- polyp/polyplib-introspect.h | 4 +- polyp/polyplib-operation.c | 4 +- polyp/polyplib-operation.h | 4 +- polyp/polyplib-scache.c | 4 +- polyp/polyplib-scache.h | 4 +- polyp/polyplib-simple.c | 4 +- polyp/polyplib-simple.h | 4 +- polyp/polyplib-stream.c | 4 +- polyp/polyplib-stream.h | 4 +- polyp/polyplib-subscribe.c | 4 +- polyp/polyplib-subscribe.h | 4 +- polyp/polyplib-version.h.in | 4 +- polyp/polyplib.h | 12 +- polyp/props.c | 4 +- polyp/props.h | 4 +- polyp/protocol-cli.c | 4 +- polyp/protocol-cli.h | 4 +- polyp/protocol-esound.c | 4 +- polyp/protocol-esound.h | 4 +- polyp/protocol-native.c | 4 +- polyp/protocol-native.h | 4 +- polyp/protocol-simple.c | 4 +- polyp/protocol-simple.h | 4 +- polyp/pstream-util.c | 12 +- polyp/pstream-util.h | 12 +- polyp/pstream.c | 12 +- polyp/pstream.h | 12 +- polyp/queue.c | 12 +- polyp/queue.h | 12 +- polyp/resampler.c | 4 +- polyp/resampler.h | 4 +- polyp/sample-util.c | 4 +- polyp/sample-util.h | 4 +- polyp/sample.c | 4 +- polyp/sample.h | 4 +- polyp/scache.c | 4 +- polyp/scache.h | 4 +- polyp/sconv-s16be.c | 4 +- polyp/sconv-s16be.h | 4 +- polyp/sconv-s16le.c | 4 +- polyp/sconv-s16le.h | 4 +- polyp/sconv.c | 4 +- polyp/sconv.h | 4 +- polyp/sink-input.c | 4 +- polyp/sink-input.h | 4 +- polyp/sink.c | 4 +- polyp/sink.h | 4 +- polyp/sioman.c | 4 +- polyp/sioman.h | 4 +- polyp/socket-client.c | 12 +- polyp/socket-client.h | 12 +- polyp/socket-server.c | 4 +- polyp/socket-server.h | 4 +- polyp/socket-util.c | 4 +- polyp/socket-util.h | 4 +- polyp/sound-file-stream.c | 4 +- polyp/sound-file-stream.h | 4 +- polyp/sound-file.c | 4 +- polyp/sound-file.h | 4 +- polyp/source-output.c | 4 +- polyp/source-output.h | 4 +- polyp/source.c | 4 +- polyp/source.h | 4 +- polyp/strbuf.c | 4 +- polyp/strbuf.h | 4 +- polyp/strlist.c | 4 +- polyp/strlist.h | 4 +- polyp/subscribe.c | 4 +- polyp/subscribe.h | 4 +- polyp/tagstruct.c | 12 +- polyp/tagstruct.h | 12 +- polyp/tokenizer.c | 4 +- polyp/tokenizer.h | 4 +- polyp/util.c | 12 +- polyp/util.h | 12 +- polyp/x11prop.c | 4 +- polyp/x11prop.h | 4 +- polyp/x11wrap.c | 4 +- polyp/x11wrap.h | 4 +- polyp/xmalloc.c | 4 +- polyp/xmalloc.h | 4 +- 214 files changed, 1064 insertions(+), 1407 deletions(-) delete mode 100644 GPL delete mode 100644 LGPL diff --git a/GPL b/GPL deleted file mode 100644 index d60c31a9..00000000 --- a/GPL +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/LGPL b/LGPL deleted file mode 100644 index b124cf58..00000000 --- a/LGPL +++ /dev/null @@ -1,510 +0,0 @@ - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations -below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it -becomes a de-facto standard. To achieve this, non-free programs must -be allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control -compilation and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at least - three years, to give the same user the materials specified in - Subsection 6a, above, for a charge no more than the cost of - performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply, and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License -may add an explicit geographical distribution limitation excluding those -countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms -of the ordinary General Public License). - - To apply these terms, attach the following notices to the library. -It is safest to attach them to the start of each source file to most -effectively convey the exclusion of warranty; and each file should -have at least the "copyright" line and a pointer to where the full -notice is found. - - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or -your school, if any, to sign a "copyright disclaimer" for the library, -if necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James - Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/LICENSE b/LICENSE index b042db50..b124cf58 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,510 @@ -The client libraries are licensed under LGPL -The daemon itself and all plugings are licensed under GPL -Lennart Poettering, 2004 + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/Makefile.am b/Makefile.am index b15fbac6..04c8f2cf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,7 +3,7 @@ # This file is part of polypaudio. # # polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by +# it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # @@ -12,12 +12,12 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # -# You should have received a copy of the GNU General Public License +# You should have received a copy of the GNU Lesser General Public License # along with polypaudio; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -EXTRA_DIST = bootstrap.sh README LICENSE GPL LGPL doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in +EXTRA_DIST = bootstrap.sh README LICENSE doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in SUBDIRS=polyp doc MAINTAINERCLEANFILES=README diff --git a/bootstrap.sh b/bootstrap.sh index 3592ce75..7dc081ae 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -4,7 +4,7 @@ # This file is part of polypaudio. # # polypaudio is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by +# under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # @@ -13,7 +13,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # -# You should have received a copy of the GNU General Public License +# You should have received a copy of the GNU Lesser General Public License # along with polypaudio; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/configure.ac b/configure.ac index 6eec2d81..45533411 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ # This file is part of polypaudio. # # polypaudio is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by +# under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # @@ -15,7 +15,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # -# You should have received a copy of the GNU General Public License +# You should have received a copy of the GNU Lesser General Public License # along with polypaudio; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/doc/Makefile.am b/doc/Makefile.am index 723a92c8..17688d3b 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -3,7 +3,7 @@ # This file is part of polypaudio. # # polypaudio is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by +# under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # @@ -12,7 +12,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # -# You should have received a copy of the GNU General Public License +# You should have received a copy of the GNU Lesser General Public License # along with polypaudio; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/doc/README.html.in b/doc/README.html.in index 22a30dc2..742ea3d1 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -27,16 +27,16 @@

    License

    This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as +modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details.

    +Lesser General Public License for more details.

    -

    You should have received a copy of the GNU General Public License +

    You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    diff --git a/doc/style.css b/doc/style.css index e54a15a3..a46592a2 100644 --- a/doc/style.css +++ b/doc/style.css @@ -4,7 +4,7 @@ * This file is part of polypaudio. * * polypaudio is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by + * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * @@ -13,7 +13,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with polypaudio; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/doc/todo b/doc/todo index 75983e7e..ad464ea4 100644 --- a/doc/todo +++ b/doc/todo @@ -18,6 +18,7 @@ - add LGPL blurb to all concerning files - non-fp mixing - non-fp resampling +- make module-tunnel use pa_socket_client_new_string() ** later *** - xmlrpc/http diff --git a/doxygen/Makefile.am b/doxygen/Makefile.am index 007a37d6..9ea724d0 100644 --- a/doxygen/Makefile.am +++ b/doxygen/Makefile.am @@ -3,7 +3,7 @@ # This file is part of polypaudio. # # polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by +# it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # @@ -12,7 +12,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # -# You should have received a copy of the GNU General Public License +# You should have received a copy of the GNU Lesser General Public License # along with polypaudio; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 585b16c0..9ea6932a 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -3,7 +3,7 @@ # This file is part of polypaudio. # # polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by +# it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # @@ -12,7 +12,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # -# You should have received a copy of the GNU General Public License +# You should have received a copy of the GNU Lesser General Public License # along with polypaudio; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. diff --git a/polyp/alsa-util.c b/polyp/alsa-util.c index 70e2e072..408bc561 100644 --- a/polyp/alsa-util.c +++ b/polyp/alsa-util.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/alsa-util.h b/polyp/alsa-util.h index 2627a75c..8add361f 100644 --- a/polyp/alsa-util.h +++ b/polyp/alsa-util.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/authkey-prop.c b/polyp/authkey-prop.c index 13227955..2adfc41f 100644 --- a/polyp/authkey-prop.c +++ b/polyp/authkey-prop.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/authkey-prop.h b/polyp/authkey-prop.h index d9ba5122..1a668117 100644 --- a/polyp/authkey-prop.h +++ b/polyp/authkey-prop.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/authkey.c b/polyp/authkey.c index ef395680..05324a61 100644 --- a/polyp/authkey.c +++ b/polyp/authkey.c @@ -4,17 +4,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/authkey.h b/polyp/authkey.h index 2bef3529..a6006dfc 100644 --- a/polyp/authkey.h +++ b/polyp/authkey.h @@ -7,17 +7,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/autoload.c b/polyp/autoload.c index d6207962..96fa750a 100644 --- a/polyp/autoload.c +++ b/polyp/autoload.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/autoload.h b/polyp/autoload.h index ec7d38f1..8537173c 100644 --- a/polyp/autoload.h +++ b/polyp/autoload.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/caps.c b/polyp/caps.c index d03ab14b..daf0b916 100644 --- a/polyp/caps.c +++ b/polyp/caps.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/caps.h b/polyp/caps.h index 473462fb..3bb861d1 100644 --- a/polyp/caps.h +++ b/polyp/caps.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/cdecl.h b/polyp/cdecl.h index 7102f649..d51ae026 100644 --- a/polyp/cdecl.h +++ b/polyp/cdecl.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/cli-command.c b/polyp/cli-command.c index d563a072..0c71260d 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/cli-command.h b/polyp/cli-command.h index b3c601ad..0f089f61 100644 --- a/polyp/cli-command.h +++ b/polyp/cli-command.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/cli-text.c b/polyp/cli-text.c index 39f7b6ed..7974275a 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/cli-text.h b/polyp/cli-text.h index 121f2a5d..1457d055 100644 --- a/polyp/cli-text.h +++ b/polyp/cli-text.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/cli.c b/polyp/cli.c index 09e9855d..15142f35 100644 --- a/polyp/cli.c +++ b/polyp/cli.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/cli.h b/polyp/cli.h index 9cfee0d8..bfe0c4f8 100644 --- a/polyp/cli.h +++ b/polyp/cli.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/client-conf-x11.c b/polyp/client-conf-x11.c index f667bd78..eb471033 100644 --- a/polyp/client-conf-x11.c +++ b/polyp/client-conf-x11.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/client-conf-x11.h b/polyp/client-conf-x11.h index 626b4f30..951ef0b1 100644 --- a/polyp/client-conf-x11.h +++ b/polyp/client-conf-x11.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/client-conf.c b/polyp/client-conf.c index 4a0fc629..2de1c57f 100644 --- a/polyp/client-conf.c +++ b/polyp/client-conf.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/client-conf.h b/polyp/client-conf.h index 2ce056f4..cf7dd095 100644 --- a/polyp/client-conf.h +++ b/polyp/client-conf.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/client.c b/polyp/client.c index 7aee2edd..b525fe6b 100644 --- a/polyp/client.c +++ b/polyp/client.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/client.conf.in b/polyp/client.conf.in index 640e2690..fbf645a4 100644 --- a/polyp/client.conf.in +++ b/polyp/client.conf.in @@ -3,7 +3,7 @@ # This file is part of polypaudio. # # polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by +# it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # @@ -12,7 +12,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # -# You should have received a copy of the GNU General Public License +# You should have received a copy of the GNU Lesser General Public License # along with polypaudio; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. diff --git a/polyp/client.h b/polyp/client.h index 25a4b166..2518011e 100644 --- a/polyp/client.h +++ b/polyp/client.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/cmdline.c b/polyp/cmdline.c index c32d9a0f..0c381f8c 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/cmdline.h b/polyp/cmdline.h index bfbae470..28e7bdbc 100644 --- a/polyp/cmdline.h +++ b/polyp/cmdline.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/conf-parser.c b/polyp/conf-parser.c index 3d922c20..40b00cda 100644 --- a/polyp/conf-parser.c +++ b/polyp/conf-parser.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/conf-parser.h b/polyp/conf-parser.h index 30330860..48cfbc14 100644 --- a/polyp/conf-parser.h +++ b/polyp/conf-parser.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/core.c b/polyp/core.c index 6e155dda..19e0425f 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/core.h b/polyp/core.h index 1438bf72..799661af 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/cpulimit-test.c b/polyp/cpulimit-test.c index d1faf92b..83d403f5 100644 --- a/polyp/cpulimit-test.c +++ b/polyp/cpulimit-test.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/cpulimit.c b/polyp/cpulimit.c index a60c03d7..fcbbaf3d 100644 --- a/polyp/cpulimit.c +++ b/polyp/cpulimit.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/cpulimit.h b/polyp/cpulimit.h index 6d13b6e5..a171da9b 100644 --- a/polyp/cpulimit.h +++ b/polyp/cpulimit.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c index 1c6486b7..c0ff02f9 100644 --- a/polyp/daemon-conf.c +++ b/polyp/daemon-conf.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/daemon-conf.h b/polyp/daemon-conf.h index fc31117f..9c278485 100644 --- a/polyp/daemon-conf.h +++ b/polyp/daemon-conf.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/daemon.conf.in b/polyp/daemon.conf.in index e6d82db1..ddc4955c 100644 --- a/polyp/daemon.conf.in +++ b/polyp/daemon.conf.in @@ -3,7 +3,7 @@ # This file is part of polypaudio. # # polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by +# it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # @@ -12,7 +12,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # -# You should have received a copy of the GNU General Public License +# You should have received a copy of the GNU Lesser General Public License # along with polypaudio; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. diff --git a/polyp/debug.h b/polyp/debug.h index c6ec5c7e..fcfa7142 100644 --- a/polyp/debug.h +++ b/polyp/debug.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/default.pa.in b/polyp/default.pa.in index 95d4be58..07ff373c 100755 --- a/polyp/default.pa.in +++ b/polyp/default.pa.in @@ -4,7 +4,7 @@ # This file is part of polypaudio. # # polypaudio is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by +# under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # @@ -13,7 +13,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # -# You should have received a copy of the GNU General Public License +# You should have received a copy of the GNU Lesser General Public License # along with polypaudio; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/depmod.py b/polyp/depmod.py index 85dc66a8..7bb223b1 100755 --- a/polyp/depmod.py +++ b/polyp/depmod.py @@ -4,7 +4,7 @@ # This file is part of polypaudio. # # polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by +# it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # @@ -13,7 +13,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # -# You should have received a copy of the GNU General Public License +# You should have received a copy of the GNU Lesser General Public License # along with polypaudio; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. diff --git a/polyp/dumpmodules.c b/polyp/dumpmodules.c index a9c02825..1903fe00 100644 --- a/polyp/dumpmodules.c +++ b/polyp/dumpmodules.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/dumpmodules.h b/polyp/dumpmodules.h index 544c55d2..c56d5abc 100644 --- a/polyp/dumpmodules.h +++ b/polyp/dumpmodules.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/dynarray.c b/polyp/dynarray.c index 23adb581..eb360b80 100644 --- a/polyp/dynarray.c +++ b/polyp/dynarray.c @@ -4,17 +4,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/dynarray.h b/polyp/dynarray.h index 56ec5386..2e9b72f6 100644 --- a/polyp/dynarray.h +++ b/polyp/dynarray.h @@ -7,17 +7,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/endianmacros.h b/polyp/endianmacros.h index cd7b7d83..75c0af0a 100644 --- a/polyp/endianmacros.h +++ b/polyp/endianmacros.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/esdcompat.sh.in b/polyp/esdcompat.sh.in index d222e1ba..dd94bfea 100755 --- a/polyp/esdcompat.sh.in +++ b/polyp/esdcompat.sh.in @@ -5,7 +5,7 @@ # This file is part of polypaudio. # # polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by +# it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # @@ -14,7 +14,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # -# You should have received a copy of the GNU General Public License +# You should have received a copy of the GNU Lesser General Public License # along with polypaudio; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. diff --git a/polyp/esound.h b/polyp/esound.h index 01a2962f..5dc2583b 100644 --- a/polyp/esound.h +++ b/polyp/esound.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/glib-mainloop.c b/polyp/glib-mainloop.c index 4fee0a4a..aa81f82d 100644 --- a/polyp/glib-mainloop.c +++ b/polyp/glib-mainloop.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/glib-mainloop.h b/polyp/glib-mainloop.h index afc83be2..d830561f 100644 --- a/polyp/glib-mainloop.h +++ b/polyp/glib-mainloop.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/glib12-mainloop.c b/polyp/glib12-mainloop.c index c7085cc9..2073c01d 100644 --- a/polyp/glib12-mainloop.c +++ b/polyp/glib12-mainloop.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/hashmap.c b/polyp/hashmap.c index 10b148dd..43e4456d 100644 --- a/polyp/hashmap.c +++ b/polyp/hashmap.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/hashmap.h b/polyp/hashmap.h index 739f8947..f858c355 100644 --- a/polyp/hashmap.h +++ b/polyp/hashmap.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/idxset.c b/polyp/idxset.c index 92cde13f..dcc38423 100644 --- a/polyp/idxset.c +++ b/polyp/idxset.c @@ -4,17 +4,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/idxset.h b/polyp/idxset.h index e9a6fb9a..1ed66154 100644 --- a/polyp/idxset.h +++ b/polyp/idxset.h @@ -7,17 +7,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/iochannel.c b/polyp/iochannel.c index 5e3e9360..b93860a5 100644 --- a/polyp/iochannel.c +++ b/polyp/iochannel.c @@ -4,17 +4,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/iochannel.h b/polyp/iochannel.h index 6f5f351c..79600f72 100644 --- a/polyp/iochannel.h +++ b/polyp/iochannel.h @@ -7,17 +7,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/ioline.c b/polyp/ioline.c index dfa92ab7..b1c980d8 100644 --- a/polyp/ioline.c +++ b/polyp/ioline.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/ioline.h b/polyp/ioline.h index 5f29a16b..c6150d4b 100644 --- a/polyp/ioline.h +++ b/polyp/ioline.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/llist.h b/polyp/llist.h index ec8e0299..c48c5c6e 100644 --- a/polyp/llist.h +++ b/polyp/llist.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/main.c b/polyp/main.c index 378cb8a0..941bf923 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/mainloop-api.c b/polyp/mainloop-api.c index 952fce0a..7b80e4fe 100644 --- a/polyp/mainloop-api.c +++ b/polyp/mainloop-api.c @@ -4,17 +4,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/mainloop-api.h b/polyp/mainloop-api.h index 43d150e4..daf71d71 100644 --- a/polyp/mainloop-api.h +++ b/polyp/mainloop-api.h @@ -7,17 +7,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/mainloop-signal.c b/polyp/mainloop-signal.c index d7ee5010..89f195ed 100644 --- a/polyp/mainloop-signal.c +++ b/polyp/mainloop-signal.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/mainloop-signal.h b/polyp/mainloop-signal.h index fa5ce718..9ba92141 100644 --- a/polyp/mainloop-signal.h +++ b/polyp/mainloop-signal.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/mainloop-test.c b/polyp/mainloop-test.c index 92b83c14..0d40e76e 100644 --- a/polyp/mainloop-test.c +++ b/polyp/mainloop-test.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/mainloop.c b/polyp/mainloop.c index 80bcb125..eb2eddc2 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/mainloop.h b/polyp/mainloop.h index 4a64d98f..06a6ccaa 100644 --- a/polyp/mainloop.h +++ b/polyp/mainloop.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/memblock.c b/polyp/memblock.c index 500d8b20..8ddfb801 100644 --- a/polyp/memblock.c +++ b/polyp/memblock.c @@ -4,17 +4,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/memblock.h b/polyp/memblock.h index 949a0a08..69a85a80 100644 --- a/polyp/memblock.h +++ b/polyp/memblock.h @@ -7,17 +7,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/memblockq.c b/polyp/memblockq.c index 0e71fa8c..0fbeaad0 100644 --- a/polyp/memblockq.c +++ b/polyp/memblockq.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/memblockq.h b/polyp/memblockq.h index aeed4193..95e5c533 100644 --- a/polyp/memblockq.h +++ b/polyp/memblockq.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/memchunk.c b/polyp/memchunk.c index 87b9c1bd..a8aeb881 100644 --- a/polyp/memchunk.c +++ b/polyp/memchunk.c @@ -4,17 +4,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/memchunk.h b/polyp/memchunk.h index 3a592f04..e73b6f6e 100644 --- a/polyp/memchunk.h +++ b/polyp/memchunk.h @@ -7,17 +7,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/modargs.c b/polyp/modargs.c index d58b391b..01a694cf 100644 --- a/polyp/modargs.c +++ b/polyp/modargs.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/modargs.h b/polyp/modargs.h index 705d9f43..53753ba7 100644 --- a/polyp/modargs.h +++ b/polyp/modargs.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/modinfo.c b/polyp/modinfo.c index 2847c63c..a1328be6 100644 --- a/polyp/modinfo.c +++ b/polyp/modinfo.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/modinfo.h b/polyp/modinfo.h index 40b535ce..d6f7c6de 100644 --- a/polyp/modinfo.h +++ b/polyp/modinfo.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index e319f6c1..a708329d 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index 34f08f95..ba09d319 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module-cli.c b/polyp/module-cli.c index 1ebc9b52..55fe8ad4 100644 --- a/polyp/module-cli.c +++ b/polyp/module-cli.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module-combine.c b/polyp/module-combine.c index 5df3f158..95bd958f 100644 --- a/polyp/module-combine.c +++ b/polyp/module-combine.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module-esound-compat-spawnfd.c b/polyp/module-esound-compat-spawnfd.c index ae4f9095..de2cf4e6 100644 --- a/polyp/module-esound-compat-spawnfd.c +++ b/polyp/module-esound-compat-spawnfd.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module-esound-compat-spawnpid.c b/polyp/module-esound-compat-spawnpid.c index 02756cdb..6f945728 100644 --- a/polyp/module-esound-compat-spawnpid.c +++ b/polyp/module-esound-compat-spawnpid.c @@ -3,7 +3,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module-esound-sink.c b/polyp/module-esound-sink.c index fadf8456..2cc61440 100644 --- a/polyp/module-esound-sink.c +++ b/polyp/module-esound-sink.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module-match.c b/polyp/module-match.c index 0398cede..6f4fc38c 100644 --- a/polyp/module-match.c +++ b/polyp/module-match.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module-native-protocol-fd.c b/polyp/module-native-protocol-fd.c index 8f41db64..11f6e572 100644 --- a/polyp/module-native-protocol-fd.c +++ b/polyp/module-native-protocol-fd.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module-null-sink.c b/polyp/module-null-sink.c index 4a41b74d..6d4ea89b 100644 --- a/polyp/module-null-sink.c +++ b/polyp/module-null-sink.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index bc36d199..8aecd560 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module-oss.c b/polyp/module-oss.c index 969761f6..fe12b0bb 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c index e445584e..6c441cc8 100644 --- a/polyp/module-pipe-sink.c +++ b/polyp/module-pipe-sink.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module-pipe-source.c b/polyp/module-pipe-source.c index 8bc4c477..e8a17b96 100644 --- a/polyp/module-pipe-source.c +++ b/polyp/module-pipe-source.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index 6a0f88a2..93e576af 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module-sine.c b/polyp/module-sine.c index 393f929a..83414821 100644 --- a/polyp/module-sine.c +++ b/polyp/module-sine.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c index 712ec359..368ae422 100644 --- a/polyp/module-tunnel.c +++ b/polyp/module-tunnel.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module-x11-bell.c b/polyp/module-x11-bell.c index 23433c8f..c3987704 100644 --- a/polyp/module-x11-bell.c +++ b/polyp/module-x11-bell.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module-x11-publish.c b/polyp/module-x11-publish.c index 60284bd6..acf37759 100644 --- a/polyp/module-x11-publish.c +++ b/polyp/module-x11-publish.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module.c b/polyp/module.c index 9ecdfe29..67d7f44e 100644 --- a/polyp/module.c +++ b/polyp/module.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/module.h b/polyp/module.h index 7380f795..f5daff95 100644 --- a/polyp/module.h +++ b/polyp/module.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/namereg.c b/polyp/namereg.c index cc25ea2b..dce8693f 100644 --- a/polyp/namereg.c +++ b/polyp/namereg.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/namereg.h b/polyp/namereg.h index b383d9ed..99032be8 100644 --- a/polyp/namereg.h +++ b/polyp/namereg.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/native-common.h b/polyp/native-common.h index 28a471d0..892629e8 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -7,17 +7,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/oss-util.c b/polyp/oss-util.c index 613cda47..8c83cbbf 100644 --- a/polyp/oss-util.c +++ b/polyp/oss-util.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/oss-util.h b/polyp/oss-util.h index cb2ce33c..c1c69632 100644 --- a/polyp/oss-util.h +++ b/polyp/oss-util.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/pacat-simple.c b/polyp/pacat-simple.c index 2b8ffa08..09cf4d1a 100644 --- a/polyp/pacat-simple.c +++ b/polyp/pacat-simple.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/pacat.c b/polyp/pacat.c index a37f5dda..e5e0b7ca 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/packet.c b/polyp/packet.c index 955feeb1..84ac6d62 100644 --- a/polyp/packet.c +++ b/polyp/packet.c @@ -4,17 +4,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/packet.h b/polyp/packet.h index 8f5cb835..5e4e92f7 100644 --- a/polyp/packet.h +++ b/polyp/packet.h @@ -7,17 +7,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/pactl.c b/polyp/pactl.c index 29c06f91..641106df 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/paplay.c b/polyp/paplay.c index cc466e12..418d40b3 100644 --- a/polyp/paplay.c +++ b/polyp/paplay.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/parec-simple.c b/polyp/parec-simple.c index cae6ff92..130627d7 100644 --- a/polyp/parec-simple.c +++ b/polyp/parec-simple.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/pax11publish.c b/polyp/pax11publish.c index f151c197..206ab1cb 100644 --- a/polyp/pax11publish.c +++ b/polyp/pax11publish.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/pdispatch.c b/polyp/pdispatch.c index f6481fa0..90de345f 100644 --- a/polyp/pdispatch.c +++ b/polyp/pdispatch.c @@ -4,17 +4,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/pdispatch.h b/polyp/pdispatch.h index ff99b184..571d0fb4 100644 --- a/polyp/pdispatch.h +++ b/polyp/pdispatch.h @@ -7,17 +7,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/play-memchunk.c b/polyp/play-memchunk.c index aa6d30e9..1b611db4 100644 --- a/polyp/play-memchunk.c +++ b/polyp/play-memchunk.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/play-memchunk.h b/polyp/play-memchunk.h index 0e6a1d8e..c69165a2 100644 --- a/polyp/play-memchunk.h +++ b/polyp/play-memchunk.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 62d1ff0d..b15dd8e7 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h index 75be5930..565701b2 100644 --- a/polyp/polyplib-context.h +++ b/polyp/polyplib-context.h @@ -8,7 +8,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -17,7 +17,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index ffa44188..e2fbaea5 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -7,17 +7,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/polyplib-error.c b/polyp/polyplib-error.c index 24054f2e..50a67270 100644 --- a/polyp/polyplib-error.c +++ b/polyp/polyplib-error.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/polyplib-error.h b/polyp/polyplib-error.h index 8b5cd910..dbbbf006 100644 --- a/polyp/polyplib-error.h +++ b/polyp/polyplib-error.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 589388f8..d1b53633 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index af5fd168..f15f59cc 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index f4dbd185..5a8f1bf3 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/polyplib-operation.c b/polyp/polyplib-operation.c index cdc5394e..77fe70fa 100644 --- a/polyp/polyplib-operation.c +++ b/polyp/polyplib-operation.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/polyplib-operation.h b/polyp/polyplib-operation.h index 42d5c8e1..bd1366d2 100644 --- a/polyp/polyplib-operation.h +++ b/polyp/polyplib-operation.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/polyplib-scache.c b/polyp/polyplib-scache.c index 45220d10..bce5d18a 100644 --- a/polyp/polyplib-scache.c +++ b/polyp/polyplib-scache.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/polyplib-scache.h b/polyp/polyplib-scache.h index ce74bef0..051bdd12 100644 --- a/polyp/polyplib-scache.h +++ b/polyp/polyplib-scache.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c index aed1ca55..a73aacfa 100644 --- a/polyp/polyplib-simple.c +++ b/polyp/polyplib-simple.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/polyplib-simple.h b/polyp/polyplib-simple.h index 1bd46dc6..9abef3fa 100644 --- a/polyp/polyplib-simple.h +++ b/polyp/polyplib-simple.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index b1f19855..a97096b4 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/polyplib-stream.h b/polyp/polyplib-stream.h index 4ccc0c23..53873491 100644 --- a/polyp/polyplib-stream.h +++ b/polyp/polyplib-stream.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/polyplib-subscribe.c b/polyp/polyplib-subscribe.c index 9536bbc6..d7e8e7c1 100644 --- a/polyp/polyplib-subscribe.c +++ b/polyp/polyplib-subscribe.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/polyplib-subscribe.h b/polyp/polyplib-subscribe.h index bd0e0399..a677bd02 100644 --- a/polyp/polyplib-subscribe.h +++ b/polyp/polyplib-subscribe.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/polyplib-version.h.in b/polyp/polyplib-version.h.in index c2442b52..89e0a0e5 100644 --- a/polyp/polyplib-version.h.in +++ b/polyp/polyplib-version.h.in @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/polyplib.h b/polyp/polyplib.h index 3921e2ba..a0c418d4 100644 --- a/polyp/polyplib.h +++ b/polyp/polyplib.h @@ -7,17 +7,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/props.c b/polyp/props.c index 596133bc..1046551b 100644 --- a/polyp/props.c +++ b/polyp/props.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/props.h b/polyp/props.h index 954d2540..9b379cf1 100644 --- a/polyp/props.h +++ b/polyp/props.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/protocol-cli.c b/polyp/protocol-cli.c index 266d4969..7ce53887 100644 --- a/polyp/protocol-cli.c +++ b/polyp/protocol-cli.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/protocol-cli.h b/polyp/protocol-cli.h index 7ad2db75..e0fe4bc1 100644 --- a/polyp/protocol-cli.h +++ b/polyp/protocol-cli.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index b6caeb3d..4da7e388 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/protocol-esound.h b/polyp/protocol-esound.h index b2bdd31b..dda6977d 100644 --- a/polyp/protocol-esound.h +++ b/polyp/protocol-esound.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 0102e0ca..7d539014 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/protocol-native.h b/polyp/protocol-native.h index edc6acbc..57c29e38 100644 --- a/polyp/protocol-native.h +++ b/polyp/protocol-native.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index ee3bf9d3..f7c69d6b 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/protocol-simple.h b/polyp/protocol-simple.h index 0fc1e19d..7b15ffcd 100644 --- a/polyp/protocol-simple.h +++ b/polyp/protocol-simple.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/pstream-util.c b/polyp/pstream-util.c index 3957e643..95a2ae89 100644 --- a/polyp/pstream-util.c +++ b/polyp/pstream-util.c @@ -4,17 +4,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/pstream-util.h b/polyp/pstream-util.h index b3c89eb0..9560bfe7 100644 --- a/polyp/pstream-util.h +++ b/polyp/pstream-util.h @@ -7,17 +7,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/pstream.c b/polyp/pstream.c index 5fe2b4e7..11ca3963 100644 --- a/polyp/pstream.c +++ b/polyp/pstream.c @@ -4,17 +4,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/pstream.h b/polyp/pstream.h index dfd29983..8fa62f06 100644 --- a/polyp/pstream.h +++ b/polyp/pstream.h @@ -7,17 +7,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/queue.c b/polyp/queue.c index 9488f433..e0a06ae1 100644 --- a/polyp/queue.c +++ b/polyp/queue.c @@ -4,17 +4,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/queue.h b/polyp/queue.h index 3ec13734..0b72f37d 100644 --- a/polyp/queue.h +++ b/polyp/queue.h @@ -7,17 +7,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/resampler.c b/polyp/resampler.c index e8dd01b9..4ddcfa40 100644 --- a/polyp/resampler.c +++ b/polyp/resampler.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/resampler.h b/polyp/resampler.h index b984a4f6..08fad809 100644 --- a/polyp/resampler.h +++ b/polyp/resampler.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sample-util.c b/polyp/sample-util.c index 51b22fbe..0d4d18d3 100644 --- a/polyp/sample-util.c +++ b/polyp/sample-util.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sample-util.h b/polyp/sample-util.h index 9f3fced1..aafdda63 100644 --- a/polyp/sample-util.h +++ b/polyp/sample-util.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sample.c b/polyp/sample.c index 7048311c..978a3d6a 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sample.h b/polyp/sample.h index a02a50fe..93025a10 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/scache.c b/polyp/scache.c index 32977854..32a36289 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/scache.h b/polyp/scache.h index 4fb3dc8e..afaba31a 100644 --- a/polyp/scache.h +++ b/polyp/scache.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sconv-s16be.c b/polyp/sconv-s16be.c index a4c25cde..0ee772c8 100644 --- a/polyp/sconv-s16be.c +++ b/polyp/sconv-s16be.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sconv-s16be.h b/polyp/sconv-s16be.h index d112d9f2..c1876dd0 100644 --- a/polyp/sconv-s16be.h +++ b/polyp/sconv-s16be.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sconv-s16le.c b/polyp/sconv-s16le.c index 40376b52..2fbcbf31 100644 --- a/polyp/sconv-s16le.c +++ b/polyp/sconv-s16le.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sconv-s16le.h b/polyp/sconv-s16le.h index 0f206ec3..8842140c 100644 --- a/polyp/sconv-s16le.h +++ b/polyp/sconv-s16le.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sconv.c b/polyp/sconv.c index dd9dd241..bd670586 100644 --- a/polyp/sconv.c +++ b/polyp/sconv.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sconv.h b/polyp/sconv.h index 1a62ed20..0a12890a 100644 --- a/polyp/sconv.h +++ b/polyp/sconv.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sink-input.c b/polyp/sink-input.c index dac10953..23b4a136 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sink-input.h b/polyp/sink-input.h index eb2cb239..1c16a9e6 100644 --- a/polyp/sink-input.h +++ b/polyp/sink-input.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sink.c b/polyp/sink.c index 8133d65a..c17af4ae 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sink.h b/polyp/sink.h index a2d34ee5..5da4ca43 100644 --- a/polyp/sink.h +++ b/polyp/sink.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sioman.c b/polyp/sioman.c index 999b8a5c..8d7b136c 100644 --- a/polyp/sioman.c +++ b/polyp/sioman.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sioman.h b/polyp/sioman.h index 1b60d4a9..840d93f2 100644 --- a/polyp/sioman.h +++ b/polyp/sioman.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/socket-client.c b/polyp/socket-client.c index 9b80d809..b77d2aeb 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -4,17 +4,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/socket-client.h b/polyp/socket-client.h index 262fbac3..9c3e0b37 100644 --- a/polyp/socket-client.h +++ b/polyp/socket-client.h @@ -7,17 +7,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/socket-server.c b/polyp/socket-server.c index a37b3e34..7268ccfa 100644 --- a/polyp/socket-server.c +++ b/polyp/socket-server.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/socket-server.h b/polyp/socket-server.h index cc5524d1..dbd82518 100644 --- a/polyp/socket-server.h +++ b/polyp/socket-server.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/socket-util.c b/polyp/socket-util.c index e0540179..1800710f 100644 --- a/polyp/socket-util.c +++ b/polyp/socket-util.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/socket-util.h b/polyp/socket-util.h index aa2de8a5..6c8ffe3b 100644 --- a/polyp/socket-util.h +++ b/polyp/socket-util.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sound-file-stream.c b/polyp/sound-file-stream.c index 347d45a7..43f93230 100644 --- a/polyp/sound-file-stream.c +++ b/polyp/sound-file-stream.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sound-file-stream.h b/polyp/sound-file-stream.h index 9cf88cce..f5ab8e2c 100644 --- a/polyp/sound-file-stream.h +++ b/polyp/sound-file-stream.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sound-file.c b/polyp/sound-file.c index c63aa628..80233da5 100644 --- a/polyp/sound-file.c +++ b/polyp/sound-file.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/sound-file.h b/polyp/sound-file.h index 4d0cf670..e5359853 100644 --- a/polyp/sound-file.h +++ b/polyp/sound-file.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/source-output.c b/polyp/source-output.c index 5a40fa42..e339d4ac 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/source-output.h b/polyp/source-output.h index a535782e..595c0870 100644 --- a/polyp/source-output.h +++ b/polyp/source-output.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/source.c b/polyp/source.c index 73645d49..026ec7a8 100644 --- a/polyp/source.c +++ b/polyp/source.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/source.h b/polyp/source.h index 3cac2ad1..1e6310b0 100644 --- a/polyp/source.h +++ b/polyp/source.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/strbuf.c b/polyp/strbuf.c index 44cae2ce..8876ba13 100644 --- a/polyp/strbuf.c +++ b/polyp/strbuf.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/strbuf.h b/polyp/strbuf.h index 1622d3a0..281eee1e 100644 --- a/polyp/strbuf.h +++ b/polyp/strbuf.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/strlist.c b/polyp/strlist.c index df7278d2..6dc865d1 100644 --- a/polyp/strlist.c +++ b/polyp/strlist.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/strlist.h b/polyp/strlist.h index 2a209dba..533f5533 100644 --- a/polyp/strlist.h +++ b/polyp/strlist.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/subscribe.c b/polyp/subscribe.c index d3b97de7..b552e4d0 100644 --- a/polyp/subscribe.c +++ b/polyp/subscribe.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/subscribe.h b/polyp/subscribe.h index 8d5e971d..38323faf 100644 --- a/polyp/subscribe.h +++ b/polyp/subscribe.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c index b9ab55f0..a6dad868 100644 --- a/polyp/tagstruct.c +++ b/polyp/tagstruct.c @@ -4,17 +4,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/tagstruct.h b/polyp/tagstruct.h index b943345b..135825e6 100644 --- a/polyp/tagstruct.h +++ b/polyp/tagstruct.h @@ -7,17 +7,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/tokenizer.c b/polyp/tokenizer.c index 43d695bd..8ccbc84f 100644 --- a/polyp/tokenizer.c +++ b/polyp/tokenizer.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/tokenizer.h b/polyp/tokenizer.h index 7d1cf9b5..0b1c5022 100644 --- a/polyp/tokenizer.h +++ b/polyp/tokenizer.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/util.c b/polyp/util.c index 4db92cf4..e8a47df0 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -4,17 +4,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/util.h b/polyp/util.h index e9d938ce..f38e6739 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -7,17 +7,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/x11prop.c b/polyp/x11prop.c index 6ff91ec4..bbe3e32c 100644 --- a/polyp/x11prop.c +++ b/polyp/x11prop.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/x11prop.h b/polyp/x11prop.h index 22461858..5531c640 100644 --- a/polyp/x11prop.h +++ b/polyp/x11prop.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/x11wrap.c b/polyp/x11wrap.c index a1a9732a..4d8d6930 100644 --- a/polyp/x11wrap.c +++ b/polyp/x11wrap.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/x11wrap.h b/polyp/x11wrap.h index 79c69015..9ed690fe 100644 --- a/polyp/x11wrap.h +++ b/polyp/x11wrap.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/xmalloc.c b/polyp/xmalloc.c index 981b3c92..7ddefa94 100644 --- a/polyp/xmalloc.c +++ b/polyp/xmalloc.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/polyp/xmalloc.h b/polyp/xmalloc.h index 35eda622..b37ece90 100644 --- a/polyp/xmalloc.h +++ b/polyp/xmalloc.h @@ -7,7 +7,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. @@ -16,7 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -- cgit From f5f6605254d17c5bc06b8c1ec98e8ee09009af10 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 14 Nov 2004 14:59:25 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@285 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index ad464ea4..95cf0f4c 100644 --- a/doc/todo +++ b/doc/todo @@ -15,7 +15,6 @@ - pass meta info for hearing impaired - limit all resources - check getaddrinfo results -- add LGPL blurb to all concerning files - non-fp mixing - non-fp resampling - make module-tunnel use pa_socket_client_new_string() -- cgit From 0a2bbc528b7865b08139155e0316738a717c4e42 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 Nov 2004 00:05:25 +0000 Subject: * some commenting work * add new field "read_only" to memory blocks * add new API function pa_context_get_server() * filter capture data through mcalign on client * make module-tunnel use pa_socket_client_new_string() instead of using pa_resolve_server() directly. * remove pa_resolve_server() * remove debug.h and replace it by a macro definition on the gcc command line * some strbuf cleanups * small fixes in pa_stream for cleanup when server dies * new CLI command "load-sample-dir-lazy" * send FQDN as part of server info * rework mcalign, this time with memory block merging * fix iochannel cleanup when connection dies * check getaddrinfo() results git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@286 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 15 ++-- polyp/Makefile.am | 17 ++++- polyp/caps.c | 4 + polyp/cli-command.c | 21 +++++- polyp/cpulimit.c | 47 ++++++++++-- polyp/debug.h | 29 ------- polyp/iochannel.c | 3 + polyp/mcalign-test.c | 68 +++++++++++++++++ polyp/mcalign.c | 188 ++++++++++++++++++++++++++++++++++++++++++++++ polyp/mcalign.h | 77 +++++++++++++++++++ polyp/memblock.c | 19 +++-- polyp/memblock.h | 5 +- polyp/memblockq.c | 1 + polyp/memchunk.c | 118 ++++------------------------- polyp/memchunk.h | 18 +++-- polyp/module-oss-mmap.c | 4 +- polyp/module-tunnel.c | 16 +--- polyp/polyplib-context.c | 37 +++++++-- polyp/polyplib-context.h | 3 + polyp/polyplib-internal.h | 4 + polyp/polyplib-stream.c | 12 ++- polyp/protocol-esound.c | 1 - polyp/protocol-native.c | 2 +- polyp/scache.c | 62 +++++++++++++++ polyp/scache.h | 2 + polyp/sink.c | 2 +- polyp/socket-client.c | 21 ++++-- polyp/socket-util.c | 33 -------- polyp/socket-util.h | 2 - polyp/strbuf.c | 60 ++++++++------- 30 files changed, 627 insertions(+), 264 deletions(-) delete mode 100644 polyp/debug.h create mode 100644 polyp/mcalign-test.c create mode 100644 polyp/mcalign.c create mode 100644 polyp/mcalign.h diff --git a/doc/todo b/doc/todo index 95cf0f4c..4f760b7c 100644 --- a/doc/todo +++ b/doc/todo @@ -2,27 +2,22 @@ *** 0.7 **** - per-channel volume -- add sample directory -- make mcalign merge chunks - option to use default fragment size on alsa drivers - improve module-oss-mmap latency measurement -- filter capture data in client through alignment - add radio module -- add sync API - make most buffer sizes dependant on the sample type - -- X11: support for the X11 synchronization extension -- pass meta info for hearing impaired - limit all resources -- check getaddrinfo results +- commenting - non-fp mixing - non-fp resampling -- make module-tunnel use pa_socket_client_new_string() ** later *** +- pass meta info for hearing impaired +- add sync API +- X11: support for the X11 synchronization extension - xmlrpc/http - dbus -- slp/rendezvous +- rendezvous - make alsa modules use mmap *********** diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 9ea6932a..506cdc34 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -27,6 +27,9 @@ AM_CFLAGS+=-DDLSEARCHPATH=\"$(modlibdir)\" AM_CFLAGS+=-DDEFAULT_CONFIG_DIR=\"$(polypconfdir)\" AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\" +# This cool debug trap works on i386/gcc only +AM_CFLAGS+='-DDEBUG_TRAP=__asm__("int $$3")' + AM_LIBADD=$(PTHREAD_LIBS) -lm AM_LDADD=$(PTHREAD_LIBS) -lm @@ -40,7 +43,8 @@ noinst_PROGRAMS = \ cpulimit-test \ cpulimit-test2 \ voltest \ - strlist-test + strlist-test \ + mcalign-test polypconf_DATA=default.pa daemon.conf client.conf @@ -196,7 +200,6 @@ polypaudio_SOURCES = idxset.c idxset.h \ autoload.c autoload.h \ xmalloc.c xmalloc.h \ subscribe.h subscribe.c \ - debug.h \ sound-file-stream.c sound-file-stream.h \ cpulimit.c cpulimit.h \ log.c log.h \ @@ -206,7 +209,8 @@ polypaudio_SOURCES = idxset.c idxset.h \ dumpmodules.c dumpmodules.h \ conf-parser.h conf-parser.c \ caps.h caps.c \ - props.h props.c + props.h props.c \ + mcalign.c mcalign.h polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) @@ -441,7 +445,8 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = polyplib.h \ client-conf.c client-conf.h \ conf-parser.c conf-parser.h \ strlist.c strlist.h \ - strbuf.c strbuf.h + strbuf.c strbuf.h \ + mcalign.c mcalign.h libpolyp_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) libpolyp_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 @@ -495,6 +500,10 @@ strlist_test_SOURCES = strlist-test.c strlist.c strlist.h strbuf.c strbuf.h util strlist_test_CFLAGS = $(AM_CFLAGS) strlist_test_LDADD = $(AM_LDADD) +mcalign_test_SOURCES = mcalign-test.c util.c util.h xmalloc.c xmalloc.h log.c log.h mcalign.c mcalign.h memchunk.c memchunk.h memblock.c memblock.h +mcalign_test_CFLAGS = $(AM_CFLAGS) +mcalign_test_LDADD = $(AM_LDADD) + cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h cpulimit_test_CFLAGS = $(AM_CFLAGS) cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la diff --git a/polyp/caps.c b/polyp/caps.c index daf0b916..d3719164 100644 --- a/polyp/caps.c +++ b/polyp/caps.c @@ -35,6 +35,7 @@ #include "log.h" #include "caps.h" +/* Drop root rights when called SUID root */ void pa_drop_root(void) { uid_t uid = getuid(); @@ -50,6 +51,7 @@ void pa_drop_root(void) { #ifdef HAVE_SYS_CAPABILITY_H +/* Limit capabilities set to CAPSYS_NICE */ int pa_limit_caps(void) { int r = -1; cap_t caps; @@ -76,6 +78,7 @@ fail: return r; } +/* Drop all capabilities, effectively becoming a normal user */ int pa_drop_caps(void) { cap_t caps; int r = -1; @@ -100,6 +103,7 @@ fail: #else +/* NOOPs in case capabilities are not available. */ int pa_limit_caps(void) { return 0; } diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 0c71260d..dec877fb 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -79,6 +79,7 @@ static int pa_cli_command_scache_play(struct pa_core *c, struct pa_tokenizer *t, static int pa_cli_command_scache_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); static int pa_cli_command_scache_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_scache_load_dir(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); static int pa_cli_command_autoload_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); static int pa_cli_command_autoload_add(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); @@ -112,7 +113,8 @@ static const struct command commands[] = { { "play-sample", pa_cli_command_scache_play, "Play a sample from the sample cache (args: name, sink|index)", 3}, { "remove-sample", pa_cli_command_scache_remove, "Remove a sample from the sample cache (args: name)", 2}, { "load-sample", pa_cli_command_scache_load, "Load a sound file into the sample cache (args: name, filename)", 3}, - { "load-sample-lazy", pa_cli_command_scache_load, "Lazy load a sound file into the sample cache (args: name, filename)", 3}, + { "load-sample-lazy", pa_cli_command_scache_load, "Lazily load a sound file into the sample cache (args: name, filename)", 3}, + { "load-sample-dir-lazy", pa_cli_command_scache_load_dir, "Lazily load all files in a directory into the sample cache (args: pathname)", 2}, { "play-file", pa_cli_command_play_file, "Play a sound file (args: filename, sink|index)", 3}, { "list-autoload", pa_cli_command_autoload_list, "List autoload entries", 1}, { "add-autoload-sink", pa_cli_command_autoload_add, "Add autoload entry for a sink (args: sink, module name, arguments)", 4}, @@ -545,6 +547,23 @@ static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t, return 0; } +static int pa_cli_command_scache_load_dir(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + const char *pname; + assert(c && t && buf && fail && verbose); + + if (!(pname = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a path name.\n"); + return -1; + } + + if (pa_scache_add_directory_lazy(c, pname) < 0) { + pa_strbuf_puts(buf, "Failed to load directory.\n"); + return -1; + } + + return 0; +} + static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { const char *fname, *sink_name; struct pa_sink *sink; diff --git a/polyp/cpulimit.c b/polyp/cpulimit.c index fcbbaf3d..78dc5e1f 100644 --- a/polyp/cpulimit.c +++ b/polyp/cpulimit.c @@ -32,30 +32,58 @@ #include "util.h" #include "log.h" + +/* This module implements a watchdog that makes sure that the current + * process doesn't consume more than 70% CPU time for 10 seconds. This + * is very useful when using SCHED_FIFO scheduling which effectively + * disables multitasking. */ + +/* Method of operation: Using SIGXCPU a signal handler is called every + * 10s process CPU time. That function checks if less than 14s system + * time have passed. In that case, it tries to contact the main event + * loop through a pipe. After two additional seconds it is checked + * whether the main event loop contact was successful. If not, the + * program is terminated forcibly. */ + /* Utilize this much CPU time at maximum */ #define CPUTIME_PERCENT 70 +/* Check every 10s */ #define CPUTIME_INTERVAL_SOFT (10) + +/* Recheck after 2s */ #define CPUTIME_INTERVAL_HARD (2) +/* Time of the last CPU load check */ static time_t last_time = 0; + +/* Pipe for communicating with the main loop */ static int the_pipe[2] = {-1, -1}; + +/* Main event loop and IO event for the FIFO */ static struct pa_mainloop_api *api = NULL; static struct pa_io_event *io_event = NULL; + +/* Saved sigaction struct for SIGXCPU */ static struct sigaction sigaction_prev; -static int installed = 0; +/* Nonzero after pa_cpu_limit_init() */ +static int installed = 0; + +/* The current state of operation */ static enum { - PHASE_IDLE, - PHASE_SOFT + PHASE_IDLE, /* Normal state */ + PHASE_SOFT /* After CPU overload has been detected */ } phase = PHASE_IDLE; +/* Reset the SIGXCPU timer to the next t seconds */ static void reset_cpu_time(int t) { int r; long n; struct rlimit rl; struct rusage ru; + /* Get the current CPU time of the current process */ r = getrusage(RUSAGE_SELF, &ru); assert(r >= 0); @@ -69,10 +97,12 @@ static void reset_cpu_time(int t) { assert(r >= 0); } +/* A simple, thread-safe puts() work-alike */ static void write_err(const char *p) { pa_loop_write(2, p, strlen(p)); } +/* The signal handler, called on every SIGXCPU */ static void signal_handler(int sig) { assert(sig == SIGXCPU); @@ -109,23 +139,26 @@ static void signal_handler(int sig) { } else if (phase == PHASE_SOFT) { write_err("Hard CPU time limit exhausted, terminating forcibly.\n"); - _exit(1); + _exit(1); /* Forced exit */ } } +/* Callback for IO events on the FIFO */ static void callback(struct pa_mainloop_api*m, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata) { char c; assert(m && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == the_pipe[0]); read(the_pipe[0], &c, sizeof(c)); - m->quit(m, 1); + m->quit(m, 1); /* Quit the main loop */ } +/* Initializes CPU load limiter */ int pa_cpu_limit_init(struct pa_mainloop_api *m) { struct sigaction sa; - assert(m && !api && !io_event && the_pipe[0] == -1 && the_pipe[1] == -1); + assert(m && !api && !io_event && the_pipe[0] == -1 && the_pipe[1] == -1 && !installed); time(&last_time); + /* Prepare the main loop pipe */ if (pipe(the_pipe) < 0) { pa_log(__FILE__": pipe() failed: %s\n", strerror(errno)); return -1; @@ -141,6 +174,7 @@ int pa_cpu_limit_init(struct pa_mainloop_api *m) { phase = PHASE_IDLE; + /* Install signal handler for SIGXCPU */ memset(&sa, 0, sizeof(sa)); sa.sa_handler = signal_handler; sigemptyset(&sa.sa_mask); @@ -158,6 +192,7 @@ int pa_cpu_limit_init(struct pa_mainloop_api *m) { return 0; } +/* Shutdown CPU load limiter */ void pa_cpu_limit_done(void) { int r; diff --git a/polyp/debug.h b/polyp/debug.h deleted file mode 100644 index fcfa7142..00000000 --- a/polyp/debug.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef foodebughfoo -#define foodebughfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -/* A nice trick for debuggers, working on x86 with GCC only */ - -#define DEBUG_TRAP __asm__("int $3") - -#endif diff --git a/polyp/iochannel.c b/polyp/iochannel.c index b93860a5..f174afd0 100644 --- a/polyp/iochannel.c +++ b/polyp/iochannel.c @@ -82,6 +82,9 @@ static void callback(struct pa_mainloop_api* m, struct pa_io_event *e, int fd, e if (e == io->input_event) { io->mainloop->io_free(io->input_event); io->input_event = NULL; + + if (io->output_event == e) + io->output_event = NULL; } if (e == io->output_event) { diff --git a/polyp/mcalign-test.c b/polyp/mcalign-test.c new file mode 100644 index 00000000..ab1f9aed --- /dev/null +++ b/polyp/mcalign-test.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "mcalign.h" + +int main(int argc, char *argv[]) { + struct pa_mcalign *a = pa_mcalign_new(11, NULL); + struct pa_memchunk c; + + pa_memchunk_reset(&c); + + srand(time(NULL)); + + for (;;) { + ssize_t r; + size_t l; + + if (!c.memblock) { + c.memblock = pa_memblock_new(2048, NULL); + c.index = c.length = 0; + } + + assert(c.index < c.memblock->length); + + l = c.memblock->length - c.index; + + l = l <= 1 ? l : rand() % (l-1) +1 ; + + if ((r = read(STDIN_FILENO, (uint8_t*) c.memblock->data + c.index, l)) <= 0) { + fprintf(stderr, "read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); + break; + } + + c.length = r; + pa_mcalign_push(a, &c); + fprintf(stderr, "Read %u bytes\n", r); + + c.index += r; + + if (c.index >= c.memblock->length) { + pa_memblock_unref(c.memblock); + pa_memchunk_reset(&c); + } + + for (;;) { + struct pa_memchunk t; + + if (pa_mcalign_pop(a, &t) < 0) + break; + + pa_loop_write(STDOUT_FILENO, (uint8_t*) t.memblock->data + t.index, t.length); + fprintf(stderr, "Wrote %u bytes.\n", t.length); + + pa_memblock_unref(t.memblock); + } + } + + pa_mcalign_free(a); + + if (c.memblock) + pa_memblock_unref(c.memblock); +} diff --git a/polyp/mcalign.c b/polyp/mcalign.c new file mode 100644 index 00000000..0b7f0db0 --- /dev/null +++ b/polyp/mcalign.c @@ -0,0 +1,188 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "mcalign.h" +#include "xmalloc.h" + +struct pa_mcalign { + size_t base; + struct pa_memchunk leftover, current; + struct pa_memblock_stat *memblock_stat; +}; + +struct pa_mcalign *pa_mcalign_new(size_t base, struct pa_memblock_stat *s) { + struct pa_mcalign *m; + assert(base); + + m = pa_xmalloc(sizeof(struct pa_mcalign)); + m->base = base; + pa_memchunk_reset(&m->leftover); + pa_memchunk_reset(&m->current); + m->memblock_stat = s; + + return m; +} + +void pa_mcalign_free(struct pa_mcalign *m) { + assert(m); + + if (m->leftover.memblock) + pa_memblock_unref(m->leftover.memblock); + + if (m->current.memblock) + pa_memblock_unref(m->current.memblock); + + pa_xfree(m); +} + +void pa_mcalign_push(struct pa_mcalign *m, const struct pa_memchunk *c) { + assert(m && c && c->memblock && c->length); + + /* Append to the leftover memory block */ + if (m->leftover.memblock) { + assert(!m->current.memblock); + + /* Try to merge */ + if (m->leftover.memblock == c->memblock && + m->leftover.index + m->leftover.length == c->index) { + + /* Merge */ + m->leftover.length += c->length; + + /* If the new chunk is larger than m->base, move it to current */ + if (m->leftover.length >= m->base) { + m->current = m->leftover; + pa_memchunk_reset(&m->leftover); + } + + } else { + size_t l; + + /* We have to copy */ + assert(m->leftover.length < m->base); + l = m->base - m->leftover.length; + + if (l > c->length) + l = c->length; + + /* Can we use the current block? */ + pa_memchunk_make_writable(&m->leftover, m->memblock_stat, m->base); + + memcpy((uint8_t*) m->leftover.memblock->data + m->leftover.index + m->leftover.length, (uint8_t*) c->memblock->data + c->index, l); + m->leftover.length += l; + + assert(m->leftover.length <= m->base && m->leftover.length <= m->leftover.memblock->length); + + if (c->length > l) { + /* Save the remainder of the memory block */ + m->current = *c; + m->current.index += l; + m->current.length -= l; + pa_memblock_ref(m->current.memblock); + } + } + } else { + assert(!m->leftover.memblock && !m->current.memblock); + + /* Nothing to merge or copy, just store it */ + + if (c->length >= m->base) + m->current = *c; + else + m->leftover = *c; + + pa_memblock_ref(c->memblock); + } +} + +int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c) { + assert(m && c); + + /* First test if there's a leftover memory block available */ + if (m->leftover.memblock) { + assert(m->leftover.length > 0 && m->leftover.length <= m->base); + + /* The leftover memory block is not yet complete */ + if (m->leftover.length < m->base) + return -1; + + /* Return the leftover memory block */ + *c = m->leftover; + pa_memchunk_reset(&m->leftover); + + /* If the current memblock is too small move it the leftover */ + if (m->current.memblock && m->current.length < m->base) { + m->leftover = m->current; + pa_memchunk_reset(&m->current); + } + + return 0; + } + + /* Now let's see if there is other data available */ + if (m->current.memblock) { + size_t l; + assert(m->current.length >= m->base); + + /* The length of the returned memory block */ + l = m->current.length; + l /= m->base; + l *= m->base; + assert(l > 0); + + /* Prepare the returned block */ + *c = m->current; + pa_memblock_ref(c->memblock); + c->length = l; + + /* Drop that from the current memory block */ + assert(l <= m->current.length); + m->current.index += l; + m->current.length -= l; + + /* In case the whole block was dropped ... */ + if (m->current.length == 0) + pa_memblock_unref(m->current.memblock); + else { + /* Move the raimainder to leftover */ + assert(m->current.length < m->base && !m->leftover.memblock); + + m->leftover = m->current; + } + + pa_memchunk_reset(&m->current); + + return 0; + } + + /* There's simply nothing */ + return -1; + +} diff --git a/polyp/mcalign.h b/polyp/mcalign.h new file mode 100644 index 00000000..925f438a --- /dev/null +++ b/polyp/mcalign.h @@ -0,0 +1,77 @@ +#ifndef foomcalignhfoo +#define foomcalignhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "memblock.h" +#include "memchunk.h" + +/* An alignment object, used for aligning memchunks to multiples of + * the frame size. */ + +/* Method of operation: the user creates a new mcalign object by + * calling pa_mcalign_new() with the appropriate aligning + * granularity. After that he may call pa_mcalign_push() for an input + * memchunk. After exactly one memchunk the user has to call + * pa_mcalign_pop() until it returns -1. If pa_mcalign_pop() returns + * 0, the memchunk *c is valid and aligned to the granularity. Some + * pseudocode illustrating this: + * + * struct pa_mcalign *a = pa_mcalign_new(4, NULL); + * + * for (;;) { + * struct pa_memchunk input; + * + * ... fill input ... + * + * pa_mcalign_push(m, &input); + * pa_memblock_unref(input.memblock); + * + * for (;;) { + * struct pa_memchunk output; + * + * if (pa_mcalign_pop(m, &output) < 0) + * break; + * + * ... consume output ... + * + * pa_memblock_unref(output.memblock); + * } + * } + * + * pa_memchunk_free(a); + * */ + +struct pa_mcalign; + +struct pa_mcalign *pa_mcalign_new(size_t base, struct pa_memblock_stat *s); +void pa_mcalign_free(struct pa_mcalign *m); + +/* Push a new memchunk into the aligner. The caller of this routine + * has to free the memchunk by himself. */ +void pa_mcalign_push(struct pa_mcalign *m, const struct pa_memchunk *c); + +/* Pop a new memchunk from the aligner. Returns 0 when sucessful, + * nonzero otherwise. */ +int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c); + +#endif diff --git a/polyp/memblock.c b/polyp/memblock.c index 8ddfb801..c070bee6 100644 --- a/polyp/memblock.c +++ b/polyp/memblock.c @@ -34,6 +34,11 @@ static void stat_add(struct pa_memblock*m, struct pa_memblock_stat *s) { assert(m); + if (!s) { + m->stat = NULL; + return; + } + m->stat = pa_memblock_stat_ref(s); s->total++; s->allocated++; @@ -61,33 +66,36 @@ struct pa_memblock *pa_memblock_new(size_t length, struct pa_memblock_stat*s) { b->length = length; b->data = b+1; b->free_cb = NULL; + b->read_only = 0; stat_add(b, s); return b; } -struct pa_memblock *pa_memblock_new_fixed(void *d, size_t length, struct pa_memblock_stat*s) { +struct pa_memblock *pa_memblock_new_dynamic(void *d, size_t length, struct pa_memblock_stat*s) { struct pa_memblock *b = pa_xmalloc(sizeof(struct pa_memblock)); - b->type = PA_MEMBLOCK_FIXED; + b->type = PA_MEMBLOCK_DYNAMIC; b->ref = 1; b->length = length; b->data = d; b->free_cb = NULL; + b->read_only = 0; stat_add(b, s); return b; } -struct pa_memblock *pa_memblock_new_dynamic(void *d, size_t length, struct pa_memblock_stat*s) { +struct pa_memblock *pa_memblock_new_fixed(void *d, size_t length, int read_only, struct pa_memblock_stat*s) { struct pa_memblock *b = pa_xmalloc(sizeof(struct pa_memblock)); - b->type = PA_MEMBLOCK_DYNAMIC; + b->type = PA_MEMBLOCK_FIXED; b->ref = 1; b->length = length; b->data = d; b->free_cb = NULL; + b->read_only = read_only; stat_add(b, s); return b; } -struct pa_memblock *pa_memblock_new_user(void *d, size_t length, void (*free_cb)(void *p), struct pa_memblock_stat*s) { +struct pa_memblock *pa_memblock_new_user(void *d, size_t length, void (*free_cb)(void *p), int read_only, struct pa_memblock_stat*s) { struct pa_memblock *b; assert(d && length && free_cb); b = pa_xmalloc(sizeof(struct pa_memblock)); @@ -96,6 +104,7 @@ struct pa_memblock *pa_memblock_new_user(void *d, size_t length, void (*free_cb) b->length = length; b->data = d; b->free_cb = free_cb; + b->read_only = read_only; stat_add(b, s); return b; } diff --git a/polyp/memblock.h b/polyp/memblock.h index 69a85a80..91612ac9 100644 --- a/polyp/memblock.h +++ b/polyp/memblock.h @@ -32,6 +32,7 @@ struct pa_memblock_stat; struct pa_memblock { enum pa_memblock_type type; unsigned ref; + int read_only; size_t length; void *data; void (*free_cb)(void *p); @@ -39,9 +40,9 @@ struct pa_memblock { }; struct pa_memblock *pa_memblock_new(size_t length, struct pa_memblock_stat*s); -struct pa_memblock *pa_memblock_new_fixed(void *data, size_t length, struct pa_memblock_stat*s); struct pa_memblock *pa_memblock_new_dynamic(void *data, size_t length, struct pa_memblock_stat*s); -struct pa_memblock *pa_memblock_new_user(void *data, size_t length, void (*free_cb)(void *p), struct pa_memblock_stat*s); +struct pa_memblock *pa_memblock_new_fixed(void *data, size_t length, int read_only, struct pa_memblock_stat*s); +struct pa_memblock *pa_memblock_new_user(void *data, size_t length, void (*free_cb)(void *p), int read_only, struct pa_memblock_stat*s); void pa_memblock_unref(struct pa_memblock*b); struct pa_memblock* pa_memblock_ref(struct pa_memblock*b); diff --git a/polyp/memblockq.c b/polyp/memblockq.c index 0fbeaad0..ff16f627 100644 --- a/polyp/memblockq.c +++ b/polyp/memblockq.c @@ -33,6 +33,7 @@ #include "memblockq.h" #include "xmalloc.h" #include "log.h" +#include "mcalign.h" struct memblock_list { struct memblock_list *next, *prev; diff --git a/polyp/memchunk.c b/polyp/memchunk.c index a8aeb881..d1c923f3 100644 --- a/polyp/memchunk.c +++ b/polyp/memchunk.c @@ -31,120 +31,28 @@ #include "memchunk.h" #include "xmalloc.h" -void pa_memchunk_make_writable(struct pa_memchunk *c, struct pa_memblock_stat *s) { +void pa_memchunk_make_writable(struct pa_memchunk *c, struct pa_memblock_stat *s, size_t min) { struct pa_memblock *n; + size_t l; assert(c && c->memblock && c->memblock->ref >= 1); - if (c->memblock->ref == 1) + if (c->memblock->ref == 1 && !c->memblock->read_only && c->memblock->length >= c->index+min) return; + + l = c->length; + if (l < min) + l = min; - n = pa_memblock_new(c->length, s); - assert(n); - memcpy(n->data, (uint8_t*) c->memblock->data+c->index, c->length); + n = pa_memblock_new(l, s); + memcpy(n->data, (uint8_t*) c->memblock->data + c->index, c->length); pa_memblock_unref(c->memblock); c->memblock = n; c->index = 0; } +void pa_memchunk_reset(struct pa_memchunk *c) { + assert(c); -struct pa_mcalign { - size_t base; - struct pa_memchunk chunk; - uint8_t *buffer; - size_t buffer_fill; - struct pa_memblock_stat *memblock_stat; -}; - -struct pa_mcalign *pa_mcalign_new(size_t base, struct pa_memblock_stat *s) { - struct pa_mcalign *m; - assert(base); - - m = pa_xmalloc(sizeof(struct pa_mcalign)); - m->base = base; - m->chunk.memblock = NULL; - m->chunk.length = m->chunk.index = 0; - m->buffer = NULL; - m->buffer_fill = 0; - m->memblock_stat = s; - return m; -} - -void pa_mcalign_free(struct pa_mcalign *m) { - assert(m); - - pa_xfree(m->buffer); - - if (m->chunk.memblock) - pa_memblock_unref(m->chunk.memblock); - - pa_xfree(m); -} - -void pa_mcalign_push(struct pa_mcalign *m, const struct pa_memchunk *c) { - assert(m && c && !m->chunk.memblock && c->memblock && c->length); - - m->chunk = *c; - pa_memblock_ref(m->chunk.memblock); -} - -int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c) { - int ret; - assert(m && c && m->base > m->buffer_fill); - - if (!m->chunk.memblock) - return -1; - - if (m->buffer_fill) { - size_t l = m->base - m->buffer_fill; - if (l > m->chunk.length) - l = m->chunk.length; - assert(m->buffer && l); - - memcpy((uint8_t*) m->buffer + m->buffer_fill, (uint8_t*) m->chunk.memblock->data + m->chunk.index, l); - m->buffer_fill += l; - m->chunk.index += l; - m->chunk.length -= l; - - if (m->chunk.length == 0) { - m->chunk.length = m->chunk.index = 0; - pa_memblock_unref(m->chunk.memblock); - m->chunk.memblock = NULL; - } - - assert(m->buffer_fill <= m->base); - if (m->buffer_fill == m->base) { - c->memblock = pa_memblock_new_dynamic(m->buffer, m->base, m->memblock_stat); - assert(c->memblock); - c->index = 0; - c->length = m->base; - m->buffer = NULL; - m->buffer_fill = 0; - - return 0; - } - - return -1; - } - - m->buffer_fill = m->chunk.length % m->base; - - if (m->buffer_fill) { - assert(!m->buffer); - m->buffer = pa_xmalloc(m->base); - m->chunk.length -= m->buffer_fill; - memcpy(m->buffer, (uint8_t*) m->chunk.memblock->data + m->chunk.index + m->chunk.length, m->buffer_fill); - } - - if (m->chunk.length) { - *c = m->chunk; - pa_memblock_ref(c->memblock); - ret = 0; - } else - ret = -1; - - m->chunk.length = m->chunk.index = 0; - pa_memblock_unref(m->chunk.memblock); - m->chunk.memblock = NULL; - - return ret; + c->memblock = NULL; + c->length = c->index = 0; } diff --git a/polyp/memchunk.h b/polyp/memchunk.h index e73b6f6e..a004c2e8 100644 --- a/polyp/memchunk.h +++ b/polyp/memchunk.h @@ -24,18 +24,22 @@ #include "memblock.h" +/* A memchunk is a part of a memblock. In contrast to the memblock, a + * memchunk is not allocated dynamically or reference counted, instead + * it is usually stored on the stack and copied around */ + struct pa_memchunk { struct pa_memblock *memblock; size_t index, length; }; -void pa_memchunk_make_writable(struct pa_memchunk *c, struct pa_memblock_stat *s); - -struct pa_mcalign; +/* Make a memchunk writable, i.e. make sure that the caller may have + * exclusive access to the memblock and it is not read_only. If needed + * the memblock in the structure is replaced by a copy. */ +void pa_memchunk_make_writable(struct pa_memchunk *c, struct pa_memblock_stat *s, size_t min); -struct pa_mcalign *pa_mcalign_new(size_t base, struct pa_memblock_stat *s); -void pa_mcalign_free(struct pa_mcalign *m); -void pa_mcalign_push(struct pa_mcalign *m, const struct pa_memchunk *c); -int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c); +/* Invalidate a memchunk. This does not free the cotaining memblock, + * but sets all members to zero. */ +void pa_memchunk_reset(struct pa_memchunk *c); #endif diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index 8aecd560..66daa77d 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -107,7 +107,7 @@ static void out_fill_memblocks(struct userdata *u, unsigned n) { if (u->out_memblocks[u->out_current]) pa_memblock_unref_fixed(u->out_memblocks[u->out_current]); - chunk.memblock = u->out_memblocks[u->out_current] = pa_memblock_new_fixed((uint8_t*)u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size, u->core->memblock_stat); + chunk.memblock = u->out_memblocks[u->out_current] = pa_memblock_new_fixed((uint8_t*)u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size, 1, u->core->memblock_stat); assert(chunk.memblock); chunk.length = chunk.memblock->length; chunk.index = 0; @@ -148,7 +148,7 @@ static void in_post_memblocks(struct userdata *u, unsigned n) { struct pa_memchunk chunk; if (!u->in_memblocks[u->in_current]) { - chunk.memblock = u->in_memblocks[u->in_current] = pa_memblock_new_fixed((uint8_t*) u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size, u->core->memblock_stat); + chunk.memblock = u->in_memblocks[u->in_current] = pa_memblock_new_fixed((uint8_t*) u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size, 1, u->core->memblock_stat); chunk.length = chunk.memblock->length; chunk.index = 0; diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c index 368ae422..7497011d 100644 --- a/polyp/module-tunnel.c +++ b/polyp/module-tunnel.c @@ -610,19 +610,9 @@ int pa__init(struct pa_core *c, struct pa_module*m) { goto fail; } - if (u->server_name[0] == '/') - u->client = pa_socket_client_new_unix(c->mainloop, u->server_name); - else { - size_t len; - struct sockaddr *sa; - - if (!(sa = pa_resolve_server(u->server_name, &len, PA_NATIVE_DEFAULT_PORT))) { - pa_log(__FILE__": failed to resolve server '%s'\n", u->server_name); - goto fail; - } - - u->client = pa_socket_client_new_sockaddr(c->mainloop, sa, len); - pa_xfree(sa); + if (!(u->client = pa_socket_client_new_string(c->mainloop, u->server_name, PA_NATIVE_DEFAULT_PORT))) { + pa_log(__FILE__": failed to connect to server '%s'\n", u->server_name); + goto fail; } if (!u->client) diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index b15dd8e7..15ef60b9 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -56,8 +56,6 @@ #define AUTOSPAWN_LOCK "autospawn.lock" - - static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_REQUEST] = { pa_command_request }, [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { pa_command_stream_killed }, @@ -72,7 +70,6 @@ static void unlock_autospawn_lock_file(struct pa_context *c) { pa_unlock_lockfile(c->autospawn_lock_fd); c->autospawn_lock_fd = -1; } - } struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { @@ -106,6 +103,7 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * c->memblock_stat = pa_memblock_stat_new(); c->local = -1; c->server_list = NULL; + c->server = NULL; c->autospawn_lock_fd = -1; memset(&c->spawn_api, 0, sizeof(c->spawn_api)); c->do_autospawn = 0; @@ -155,6 +153,7 @@ static void context_free(struct pa_context *c) { pa_strlist_free(c->server_list); pa_xfree(c->name); + pa_xfree(c->server); pa_xfree(c); } @@ -246,9 +245,20 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, ui pa_context_ref(c); if ((s = pa_dynarray_get(c->record_streams, channel))) { - if (s->read_callback) { - s->read_callback(s, (uint8_t*) chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); - s->counter += chunk->length; + pa_mcalign_push(s->mcalign, chunk); + + for (;;) { + struct pa_memchunk t; + + if (pa_mcalign_pop(s->mcalign, &t) < 0) + break; + + if (s->read_callback) { + s->read_callback(s, (uint8_t*) t.memblock->data + t.index, t.length, s->read_userdata); + s->counter += chunk->length; + } + + pa_memblock_unref(t.memblock); } } @@ -496,6 +506,9 @@ static int try_next_connection(struct pa_context *c) { } /* pa_log(__FILE__": Trying to connect to %s...\n", u); */ + + pa_xfree(c->server); + c->server = pa_xstrdup(u); if (!(c->client = pa_socket_client_new_string(c->mainloop, u, PA_NATIVE_DEFAULT_PORT))) continue; @@ -811,3 +824,15 @@ const char* pa_get_library_version(void) { return PACKAGE_VERSION; } +const char* pa_context_get_server(struct pa_context *c) { + + if (!c->server) + return NULL; + + if (*c->server == '{') { + char *e = strchr(c->server+1, '}'); + return e ? e+1 : c->server; + } + + return c->server; +} diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h index 565701b2..db4b121d 100644 --- a/polyp/polyplib-context.h +++ b/polyp/polyplib-context.h @@ -108,6 +108,9 @@ int pa_context_is_local(struct pa_context *c); /** Set a different application name for context on the server. \since 0.5 */ struct pa_operation* pa_context_set_name(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata); +/** Return the server name this context is connected to. \since 0.7 */ +const char* pa_context_get_server(struct pa_context *c); + PA_C_DECL_END #endif diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index d1b53633..68ba76a9 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -35,6 +35,7 @@ #include "native-common.h" #include "client-conf.h" #include "strlist.h" +#include "mcalign.h" #define DEFAULT_TLENGTH (44100*2*2/2) //(10240*8) #define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2) @@ -77,6 +78,8 @@ struct pa_context { struct pa_strlist *server_list; + char *server; + struct pa_client_conf *conf; }; @@ -97,6 +100,7 @@ struct pa_stream { uint64_t counter; pa_usec_t previous_time; enum pa_stream_state state; + struct pa_mcalign *mcalign; int interpolate; int corked; diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index a97096b4..7d3d3a76 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -61,6 +61,8 @@ struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const st s->state = PA_STREAM_DISCONNECTED; memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); + s->mcalign = pa_mcalign_new(pa_frame_size(ss), c->memblock_stat); + s->counter = 0; s->previous_time = 0; @@ -83,6 +85,8 @@ static void stream_free(struct pa_stream *s) { assert(s->mainloop); s->mainloop->time_free(s->ipol_event); } + + pa_mcalign_free(s->mcalign); pa_xfree(s->name); pa_xfree(s); @@ -203,11 +207,13 @@ static void ipol_callback(struct pa_mainloop_api *m, struct pa_time_event *e, co struct pa_stream *s = userdata; pa_stream_ref(s); - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + if (s->state == PA_STREAM_READY) + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + gettimeofday(&tv2, NULL); tv2.tv_usec += LATENCY_IPOL_INTERVAL_USEC; - + m->time_restart(e, &tv2); pa_stream_unref(s); @@ -329,7 +335,7 @@ void pa_stream_write(struct pa_stream *s, const void *data, size_t length, void assert(s && s->context && data && length && s->state == PA_STREAM_READY && s->ref >= 1); if (free_cb) { - chunk.memblock = pa_memblock_new_user((void*) data, length, free_cb, s->context->memblock_stat); + chunk.memblock = pa_memblock_new_user((void*) data, length, free_cb, 1, s->context->memblock_stat); assert(chunk.memblock && chunk.memblock->data); } else { chunk.memblock = pa_memblock_new(length, s->context->memblock_stat); diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 4da7e388..07c39e2a 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -42,7 +42,6 @@ #include "scache.h" #include "sample-util.h" #include "authkey.h" -#include "debug.h" #include "namereg.h" #include "xmalloc.h" #include "log.h" diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 7d539014..02d81db3 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -1343,7 +1343,7 @@ static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, u pa_tagstruct_puts(reply, PACKAGE_NAME); pa_tagstruct_puts(reply, PACKAGE_VERSION); pa_tagstruct_puts(reply, pa_get_user_name(txt, sizeof(txt))); - pa_tagstruct_puts(reply, pa_get_host_name(txt, sizeof(txt))); + pa_tagstruct_puts(reply, pa_get_fqdn(txt, sizeof(txt))); pa_tagstruct_put_sample_spec(reply, &c->protocol->core->default_sample_spec); n = pa_namereg_get_default_sink_name(c->protocol->core); diff --git a/polyp/scache.c b/polyp/scache.c index 32a36289..ccdc7185 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -27,6 +27,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include "scache.h" #include "sink-input.h" @@ -38,6 +44,7 @@ #include "namereg.h" #include "sound-file.h" #include "util.h" +#include "log.h" #define UNLOAD_POLL_TIME 2 @@ -291,3 +298,58 @@ void pa_scache_unload_unused(struct pa_core *c) { pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); } } + +static void add_file(struct pa_core *c, const char *pathname) { + struct stat st; + const char *e; + + if (!(e = strrchr(pathname, '/'))) + e = pathname; + else + e++; + + if (stat(pathname, &st) < 0) { + pa_log(__FILE__": stat('%s') failed: %s\n", pathname, strerror(errno)); + return; + } + + if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) + pa_scache_add_file_lazy(c, e, pathname, NULL); +} + +int pa_scache_add_directory_lazy(struct pa_core *c, const char *pathname) { + DIR *dir; + assert(c && pathname); + + /* First try to open this as directory */ + if (!(dir = opendir(pathname))) { + glob_t p; + unsigned int i; + /* If that fails, try to open it as shell glob */ + + if (glob(pathname, GLOB_ERR|GLOB_NOSORT, NULL, &p) < 0) { + pa_log(__FILE__": Failed to open directory: %s\n", strerror(errno)); + return -1; + } + + for (i = 0; i < p.gl_pathc; i++) + add_file(c, p.gl_pathv[i]); + + globfree(&p); + } else { + struct dirent *e; + + while ((e = readdir(dir))) { + char p[PATH_MAX]; + + if (e->d_name[0] == '.') + continue; + + snprintf(p, sizeof(p), "%s/%s", pathname, e->d_name); + add_file(c, p); + } + } + + closedir(dir); + return 0; +} diff --git a/polyp/scache.h b/polyp/scache.h index afaba31a..f7043f16 100644 --- a/polyp/scache.h +++ b/polyp/scache.h @@ -45,6 +45,8 @@ int pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spe int pa_scache_add_file(struct pa_core *c, const char *name, const char *filename, uint32_t *index); int pa_scache_add_file_lazy(struct pa_core *c, const char *name, const char *filename, uint32_t *index); +int pa_scache_add_directory_lazy(struct pa_core *c, const char *pathname); + int pa_scache_remove_item(struct pa_core *c, const char *name); int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sink, uint32_t volume); void pa_scache_free(struct pa_core *c); diff --git a/polyp/sink.c b/polyp/sink.c index c17af4ae..29aef6fb 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -225,7 +225,7 @@ int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result) volume = pa_volume_multiply(s->volume, info[0].volume); if (volume != PA_VOLUME_NORM) { - pa_memchunk_make_writable(result, s->core->memblock_stat); + pa_memchunk_make_writable(result, s->core->memblock_stat, 0); pa_volume_memchunk(result, &s->sample_spec, volume); } } else { diff --git a/polyp/socket-client.c b/polyp/socket-client.c index b77d2aeb..aea38586 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -338,16 +338,24 @@ struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, memset(&hints, 0, sizeof(hints)); hints.ai_family = kind == KIND_TCP4 ? AF_INET : (kind == KIND_TCP6 ? AF_INET6 : AF_UNSPEC); - if (getaddrinfo(h, NULL, &hints, &res) < 0 || !res) + if (getaddrinfo(h, NULL, &hints, &res) < 0 || !res || !res->ai_addr) return NULL; - if (res->ai_addr->sa_family == AF_INET) + if (res->ai_family == AF_INET) { + if (res->ai_addrlen != sizeof(struct sockaddr_in)) + return NULL; + assert(res->ai_addr->sa_family == res->ai_family); + ((struct sockaddr_in*) res->ai_addr)->sin_port = htons(port); - else if (res->ai_addr->sa_family == AF_INET6) + } else if (res->ai_family == AF_INET6) { + if (res->ai_addrlen != sizeof(struct sockaddr_in6)) + return NULL; + assert(res->ai_addr->sa_family == res->ai_family); + ((struct sockaddr_in6*) res->ai_addr)->sin6_port = htons(port); - else + } else return NULL; - + c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); return c; @@ -360,6 +368,9 @@ struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, } +/* Return non-zero when the target sockaddr is considered + local. "local" means UNIX socket or TCP socket on localhost. Other + local IP addresses are not considered local. */ int pa_socket_client_is_local(struct pa_socket_client *c) { assert(c); return c->local; diff --git a/polyp/socket-util.c b/polyp/socket-util.c index 1800710f..495ee1b0 100644 --- a/polyp/socket-util.c +++ b/polyp/socket-util.c @@ -202,36 +202,3 @@ int pa_unix_socket_remove_stale(const char *fn) { return 0; } - -struct sockaddr *pa_resolve_server(const char *server, size_t *len, uint16_t nport) { - struct sockaddr *sa; - struct addrinfo hints, *result = NULL; - char *port, host[256], tmp[16]; - assert(server && len); - - snprintf(host, sizeof(host), "%s", server); - host[strcspn(host, ":")] = 0; - - if ((port = strrchr(server, ':'))) - port++; - - if (!port) - snprintf(port = tmp, sizeof(tmp), "%u", nport); - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(host, port, &hints, &result) != 0) - return NULL; - assert(result); - - sa = pa_xmalloc(*len = result->ai_addrlen); - memcpy(sa, result->ai_addr, *len); - - freeaddrinfo(result); - - return sa; -} - diff --git a/polyp/socket-util.h b/polyp/socket-util.h index 6c8ffe3b..ae16fb16 100644 --- a/polyp/socket-util.h +++ b/polyp/socket-util.h @@ -35,6 +35,4 @@ int pa_socket_set_rcvbuf(int fd, size_t l); int pa_unix_socket_is_stale(const char *fn); int pa_unix_socket_remove_stale(const char *fn); -struct sockaddr *pa_resolve_server(const char *server, size_t *len, uint16_t port); - #endif diff --git a/polyp/strbuf.c b/polyp/strbuf.c index 8876ba13..a6521651 100644 --- a/polyp/strbuf.c +++ b/polyp/strbuf.c @@ -33,6 +33,7 @@ #include "strbuf.h" +/* Some magic for zero-length arrays */ #ifdef __STDC_VERSION__ #if __STDC_VERSION__ >= 199901L #ifndef STDC99 @@ -41,6 +42,7 @@ #endif #endif +/* A chunk of the linked list that makes up the string */ struct chunk { struct chunk *next; size_t length; @@ -74,6 +76,8 @@ void pa_strbuf_free(struct pa_strbuf *sb) { pa_xfree(sb); } +/* Make a C string from the string buffer. The caller has to free + * string with pa_xfree(). */ char *pa_strbuf_tostring(struct pa_strbuf *sb) { char *t, *e; struct chunk *c; @@ -83,15 +87,18 @@ char *pa_strbuf_tostring(struct pa_strbuf *sb) { e = t; for (c = sb->head; c; c = c->next) { + assert((size_t) (e-t) <= sb->length); memcpy(e, c->text, c->length); e += c->length; } + /* Trailing NUL */ *e = 0; return t; } +/* Combination of pa_strbuf_free() and pa_strbuf_tostring() */ char *pa_strbuf_tostring_free(struct pa_strbuf *sb) { char *t; assert(sb); @@ -100,11 +107,30 @@ char *pa_strbuf_tostring_free(struct pa_strbuf *sb) { return t; } +/* Append a string to the string buffer */ void pa_strbuf_puts(struct pa_strbuf *sb, const char *t) { assert(sb && t); pa_strbuf_putsn(sb, t, strlen(t)); -} +} + +/* Append a new chunk to the linked list */ +static void append(struct pa_strbuf *sb, struct chunk *c) { + assert(sb && c); + + if (sb->tail) { + assert(sb->head); + sb->tail->next = c; + } else { + assert(!sb->head); + sb->head = c; + } + + sb->tail = c; + sb->length += c->length; + c->next = NULL; +} +/* Append up to l bytes of a string to the string buffer */ void pa_strbuf_putsn(struct pa_strbuf *sb, const char *t, size_t l) { struct chunk *c; assert(sb && t); @@ -113,33 +139,23 @@ void pa_strbuf_putsn(struct pa_strbuf *sb, const char *t, size_t l) { return; c = pa_xmalloc(sizeof(struct chunk)+l); - - c->next = NULL; c->length = l; memcpy(c->text, t, l); - if (sb->tail) { - assert(sb->head); - sb->tail->next = c; - } else { - assert(!sb->head); - sb->head = c; - } - - sb->tail = c; - sb->length += l; + append(sb, c); } +/* Append a printf() style formatted string to the string buffer. */ /* The following is based on an example from the GNU libc documentation */ - int pa_strbuf_printf(struct pa_strbuf *sb, const char *format, ...) { - int r, size = 100; + int size = 100; struct chunk *c = NULL; assert(sb); for(;;) { va_list ap; + int r; c = pa_xrealloc(c, sizeof(struct chunk)+size); @@ -149,19 +165,7 @@ int pa_strbuf_printf(struct pa_strbuf *sb, const char *format, ...) { if (r > -1 && r < size) { c->length = r; - c->next = NULL; - - if (sb->tail) { - assert(sb->head); - sb->tail->next = c; - } else { - assert(!sb->head); - sb->head = c; - } - - sb->tail = c; - sb->length += r; - + append(sb, c); return r; } -- cgit From 5ea2783dda66ebf343f72350aaa99d22f35f6d0e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 Nov 2004 01:04:52 +0000 Subject: * fix a long standing bug in ioline.c (large prints failed) * fix a bug regarding ipv6 binding git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@287 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/cli-command.c | 2 - polyp/cli.c | 12 +++--- polyp/ioline.c | 109 +++++++++++++++++++++++++++++++------------------- polyp/socket-server.c | 4 +- polyp/strbuf.c | 27 ++++--------- 5 files changed, 83 insertions(+), 71 deletions(-) diff --git a/polyp/cli-command.c b/polyp/cli-command.c index dec877fb..c11647fc 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -242,8 +242,6 @@ static int pa_cli_command_stat(struct pa_core *c, struct pa_tokenizer *t, struct pa_namereg_get_default_sink_name(c), pa_namereg_get_default_source_name(c)); - - return 0; } diff --git a/polyp/cli.c b/polyp/cli.c index 15142f35..2ff35992 100644 --- a/polyp/cli.c +++ b/polyp/cli.c @@ -44,6 +44,8 @@ #include "xmalloc.h" #include "log.h" +#define PROMPT ">>> " + struct pa_cli { struct pa_core *core; struct pa_ioline *line; @@ -57,9 +59,6 @@ struct pa_cli { }; static void line_callback(struct pa_ioline *line, const char *s, void *userdata); - -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, struct pa_module *m) { @@ -83,8 +82,7 @@ struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io, struct c->client->owner = m; 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); + pa_ioline_puts(c->line, "Welcome to polypaudio! Use \"help\" for usage information.\n"PROMPT); c->fail = c->kill_requested = c->defer_kill = 0; c->verbose = 1; @@ -139,11 +137,11 @@ static void line_callback(struct pa_ioline *line, const char *s, void *userdata) if (c->eof_callback) c->eof_callback(c, c->userdata); } else - pa_ioline_puts(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) { - assert(c && cb); + assert(c); c->eof_callback = cb; c->userdata = userdata; } diff --git a/polyp/ioline.c b/polyp/ioline.c index b1c980d8..f3d17b58 100644 --- a/polyp/ioline.c +++ b/polyp/ioline.c @@ -92,8 +92,11 @@ void pa_ioline_puts(struct pa_ioline *l, const char *c) { if (!len) return; - - if (len > l->wbuf_length - l->wbuf_valid_length) { + + assert(l->wbuf_length >= l->wbuf_valid_length); + + /* In case the allocated buffer is too small, enlarge it. */ + if (l->wbuf_valid_length + len > l->wbuf_length) { size_t n = l->wbuf_valid_length+len; char *new = pa_xmalloc(n); if (l->wbuf) { @@ -103,27 +106,64 @@ void pa_ioline_puts(struct pa_ioline *l, const char *c) { l->wbuf = new; l->wbuf_length = n; l->wbuf_index = 0; - } else if (len > l->wbuf_length - l->wbuf_valid_length - l->wbuf_index) { + } else if (l->wbuf_index + l->wbuf_valid_length + len > l->wbuf_length) { + + /* In case the allocated buffer fits, but the current index is too far from the start, move it to the front. */ 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); + assert(l->wbuf_index + l->wbuf_valid_length + len <= l->wbuf_length); + + /* Append the new string */ + memcpy(l->wbuf + l->wbuf_index + l->wbuf_valid_length, c, len); l->wbuf_valid_length += len; do_write(l); } void pa_ioline_set_callback(struct pa_ioline*l, void (*callback)(struct pa_ioline*io, const char *s, void *userdata), void *userdata) { - assert(l && callback); + assert(l); l->callback = callback; l->userdata = userdata; } +static void scan_for_lines(struct pa_ioline *l, size_t skip) { + assert(l && skip < l->rbuf_valid_length); + + while (!l->dead && l->rbuf_valid_length > skip) { + char *e, *p; + size_t m; + + if (!(e = memchr(l->rbuf + l->rbuf_index + skip, '\n', l->rbuf_valid_length - skip))) + break; + + *e = 0; + + p = l->rbuf + l->rbuf_index; + m = strlen(p); + + l->rbuf_index += m+1; + l->rbuf_valid_length -= m+1; + + /* A shortcut for the next time */ + if (l->rbuf_valid_length == 0) + l->rbuf_index = 0; + + if (l->callback) + l->callback(l, p, l->userdata); + + skip = 0; + } + + /* If the buffer became too large and still no newline was found, drop it. */ + if (l->rbuf_valid_length >= BUFFER_LIMIT) + l->rbuf_index = l->rbuf_valid_length = 0; +} + static int do_read(struct pa_ioline *l) { ssize_t r; - size_t m, len; - char *e; + size_t len; assert(l); if (!pa_iochannel_is_readable(l->io)) @@ -131,6 +171,7 @@ static int do_read(struct pa_ioline *l) { len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length; + /* Check if we have to enlarge the read buffer */ if (len < READ_SIZE) { size_t n = l->rbuf_valid_length+READ_SIZE; @@ -138,9 +179,11 @@ static int do_read(struct pa_ioline *l) { n = BUFFER_LIMIT; if (l->rbuf_length >= n) { + /* The current buffer is large enough, let's just move the data to the front */ if (l->rbuf_valid_length) memmove(l->rbuf, l->rbuf+l->rbuf_index, l->rbuf_valid_length); } else { + /* Enlarge the buffer */ char *new = pa_xmalloc(n); if (l->rbuf_valid_length) memcpy(new, l->rbuf+l->rbuf_index, l->rbuf_valid_length); @@ -153,37 +196,22 @@ static int do_read(struct pa_ioline *l) { } len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length; - + + assert(len >= READ_SIZE); + + /* Read some data */ if ((r = pa_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; - - if (e) { - char *p; - - *e = 0; - - p = l->rbuf+l->rbuf_index; - m = strlen(p); - - 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); - } + /* Look if a line has been terminated in the newly read data */ + scan_for_lines(l, l->rbuf_valid_length - r); return 0; } +/* Try to flush the buffer */ static int do_write(struct pa_ioline *l) { ssize_t r; assert(l); @@ -194,27 +222,26 @@ static int do_write(struct pa_ioline *l) { if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0) return -1; + l->wbuf_index += r; l->wbuf_valid_length -= r; + + /* A shortcut for the next time */ if (l->wbuf_valid_length == 0) l->wbuf_index = 0; return 0; } +/* Try to flush read/write data */ static void io_callback(struct pa_iochannel*io, void *userdata) { struct pa_ioline *l = userdata; assert(io && l); - if (!l->dead && do_write(l) < 0) - goto fail; - - if (!l->dead && do_read(l) < 0) - goto fail; - - return; - -fail: - l->dead = 1; - if (l->callback) - l->callback(l, NULL, l->userdata); + if ((!l->dead && do_write(l) < 0) || + (!l->dead && do_read(l) < 0)) { + + l->dead = 1; + if (l->callback) + l->callback(l, NULL, l->userdata); + } } diff --git a/polyp/socket-server.c b/polyp/socket-server.c index 7268ccfa..e67a9daa 100644 --- a/polyp/socket-server.c +++ b/polyp/socket-server.c @@ -202,7 +202,7 @@ struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, ui pa_socket_tcp_low_delay(fd); - memset(&sa, sizeof(sa), 0); + memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_port = htons(port); sa.sin_addr.s_addr = htonl(address); @@ -251,7 +251,7 @@ struct pa_socket_server* pa_socket_server_new_ipv6(struct pa_mainloop_api *m, ui pa_socket_tcp_low_delay(fd); - memset(&sa, sizeof(sa), 0); + memset(&sa, 0, sizeof(sa)); sa.sin6_family = AF_INET6; sa.sin6_port = htons(port); memcpy(sa.sin6_addr.s6_addr, address, 16); diff --git a/polyp/strbuf.c b/polyp/strbuf.c index a6521651..1aa710ea 100644 --- a/polyp/strbuf.c +++ b/polyp/strbuf.c @@ -33,26 +33,14 @@ #include "strbuf.h" -/* Some magic for zero-length arrays */ -#ifdef __STDC_VERSION__ -#if __STDC_VERSION__ >= 199901L -#ifndef STDC99 -#define STDC99 -#endif -#endif -#endif - /* A chunk of the linked list that makes up the string */ struct chunk { struct chunk *next; size_t length; -#ifdef STDC99 - char text[]; -#else - char text[0]; -#endif }; +#define CHUNK_TO_TEXT(c) ((char*) (c) + sizeof(struct chunk)) + struct pa_strbuf { size_t length; struct chunk *head, *tail; @@ -83,17 +71,18 @@ char *pa_strbuf_tostring(struct pa_strbuf *sb) { struct chunk *c; assert(sb); - t = pa_xmalloc(sb->length+1); + e = t = pa_xmalloc(sb->length+1); - e = t; for (c = sb->head; c; c = c->next) { assert((size_t) (e-t) <= sb->length); - memcpy(e, c->text, c->length); + memcpy(e, CHUNK_TO_TEXT(c), c->length); e += c->length; } /* Trailing NUL */ *e = 0; + + assert(e == t+sb->length); return t; } @@ -140,7 +129,7 @@ void pa_strbuf_putsn(struct pa_strbuf *sb, const char *t, size_t l) { c = pa_xmalloc(sizeof(struct chunk)+l); c->length = l; - memcpy(c->text, t, l); + memcpy(CHUNK_TO_TEXT(c), t, l); append(sb, c); } @@ -160,7 +149,7 @@ int pa_strbuf_printf(struct pa_strbuf *sb, const char *format, ...) { c = pa_xrealloc(c, sizeof(struct chunk)+size); va_start(ap, format); - r = vsnprintf(c->text, size, format, ap); + r = vsnprintf(CHUNK_TO_TEXT(c), size, format, ap); va_end(ap); if (r > -1 && r < size) { -- cgit From ddf9970b8a2e8851bca90b4d36c0abc64631e2cf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 Nov 2004 01:22:14 +0000 Subject: update todo list git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@288 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/todo b/doc/todo index 4f760b7c..c61cfa7b 100644 --- a/doc/todo +++ b/doc/todo @@ -10,6 +10,7 @@ - commenting - non-fp mixing - non-fp resampling +- module-tunnel: use latency interpolation ** later *** - pass meta info for hearing impaired -- cgit From a58f248ea5116bd7716da4a247c94c41957a9696 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 Nov 2004 01:22:43 +0000 Subject: fix module-tunnel.c git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@289 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-tunnel.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c index 7497011d..2b36ce27 100644 --- a/polyp/module-tunnel.c +++ b/polyp/module-tunnel.c @@ -255,8 +255,9 @@ static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t comman pa_usec_t buffer_usec, sink_usec, source_usec, transport_usec; int playing; uint32_t queue_length; + uint64_t counter; struct timeval local, remote, now; - assert(pd && u && t); + assert(pd && u); if (command != PA_COMMAND_REPLY) { if (command == PA_COMMAND_ERROR) @@ -274,6 +275,7 @@ static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t comman pa_tagstruct_getu32(t, &queue_length) < 0 || pa_tagstruct_get_timeval(t, &local) < 0 || pa_tagstruct_get_timeval(t, &remote) < 0 || + pa_tagstruct_getu64(t, &counter) < 0 || !pa_tagstruct_eof(t)) { pa_log(__FILE__": invalid reply.\n"); die(u); @@ -322,6 +324,7 @@ static void request_latency(struct userdata *u) { gettimeofday(&now, NULL); pa_tagstruct_put_timeval(t, &now); + pa_tagstruct_putu64(t, 0); pa_pstream_send_tagstruct(u->pstream, t); pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u); -- cgit From cd3a98a2ab1b8be413d50db9baa5bf52fa3a3a45 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 Nov 2004 03:10:50 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@290 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/todo b/doc/todo index c61cfa7b..948ae65b 100644 --- a/doc/todo +++ b/doc/todo @@ -11,6 +11,7 @@ - non-fp mixing - non-fp resampling - module-tunnel: use latency interpolation +- polish for starting polypaudio as root/system-wide instance ** later *** - pass meta info for hearing impaired -- cgit From c57d5deef6ee33ab892398c7fd27400cd4ce4542 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 Nov 2004 23:11:34 +0000 Subject: minor fixes for latency interpolation git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@291 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/alsa-util.c | 1 + polyp/mainloop.c | 59 +++++++++++++++++++++++++++++++++++++++++------ polyp/polyplib-context.c | 4 +++- polyp/polyplib-def.h | 2 +- polyp/polyplib-internal.h | 1 + polyp/polyplib-stream.c | 25 +++++++++++++------- 6 files changed, 75 insertions(+), 17 deletions(-) diff --git a/polyp/alsa-util.c b/polyp/alsa-util.c index 408bc561..188ba077 100644 --- a/polyp/alsa-util.c +++ b/polyp/alsa-util.c @@ -23,6 +23,7 @@ #include #endif +#include #include #include "alsa-util.h" diff --git a/polyp/mainloop.c b/polyp/mainloop.c index eb2eddc2..e13e7b11 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -425,6 +425,9 @@ static int dispatch_defer(struct pa_mainloop *m) { struct pa_defer_event *e; int r = 0; + if (!m->deferred_pending) + return 0; + for (e = pa_idxset_first(m->defer_events, &index); e && !m->quit; e = pa_idxset_next(m->defer_events, &index)) { if (e->dead || !e->enabled) continue; @@ -516,10 +519,10 @@ static int dispatch_timeout(struct pa_mainloop *m) { int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval) { int r, t, dispatched = 0; assert(m && !m->running); - - m->running = 1; - if(m->quit) + m->running ++; + + if (m->quit) goto quit; scan_dead(m); @@ -534,6 +537,7 @@ int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval) { } t = block ? calc_next_timeout(m) : 0; + r = poll(m->pollfds, m->n_pollfds, t); if (r < 0) { @@ -555,15 +559,15 @@ int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval) { } } - m->running = 0; - + m->running--; + /* pa_log("dispatched: %i\n", dispatched); */ return r < 0 ? -1 : dispatched; quit: - - m->running = 0; + + m->running--; if (retval) *retval = m->retval; @@ -597,3 +601,44 @@ int pa_mainloop_deferred_pending(struct pa_mainloop *m) { assert(m); return m->deferred_pending > 0; } + + +void pa_mainloop_dump(struct pa_mainloop *m) { + assert(m); + + pa_log(__FILE__": Dumping mainloop sources START\n"); + + { + uint32_t index = PA_IDXSET_INVALID; + struct pa_io_event *e; + for (e = pa_idxset_first(m->io_events, &index); e; e = pa_idxset_next(m->io_events, &index)) { + if (e->dead) + continue; + + pa_log(__FILE__": kind=io fd=%i events=%i callback=%p userdata=%p\n", e->fd, (int) e->events, e->callback, e->userdata); + } + } + { + uint32_t index = PA_IDXSET_INVALID; + struct pa_defer_event *e; + for (e = pa_idxset_first(m->defer_events, &index); e; e = pa_idxset_next(m->defer_events, &index)) { + if (e->dead) + continue; + + pa_log(__FILE__": kind=defer enabled=%i callback=%p userdata=%p\n", e->enabled, e->callback, e->userdata); + } + } + { + uint32_t index = PA_IDXSET_INVALID; + struct pa_time_event *e; + for (e = pa_idxset_first(m->time_events, &index); e; e = pa_idxset_next(m->time_events, &index)) { + if (e->dead) + continue; + + pa_log(__FILE__": kind=time enabled=%i time=%u.%u callback=%p userdata=%p\n", e->enabled, e->timeval.tv_sec, e->timeval.tv_usec, e->callback, e->userdata); + } + } + + pa_log(__FILE__": Dumping mainloop sources STOP\n"); + +} diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 15ef60b9..70429583 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -635,7 +635,9 @@ int pa_context_is_pending(struct pa_context *c) { /* pa_log("pstream: %i\n", pa_pstream_is_pending(c->pstream)); */ /* pa_log("pdispatch: %i\n", pa_pdispatch_is_pending(c->pdispatch)); */ - return (c->pstream && pa_pstream_is_pending(c->pstream)) || (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) || c->client; + return (c->pstream && pa_pstream_is_pending(c->pstream)) || + (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) || + c->client; } static void set_dispatch_callbacks(struct pa_operation *o); diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index e2fbaea5..44c2034b 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -176,7 +176,7 @@ struct pa_latency_info { pa_usec_t source_usec; /**< Time in usecs a sample takes from being recorded to being delivered to the application. Only for record streams. \since 0.5*/ pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to/from the daemon. For both playback and record streams. \since 0.5 */ int playing; /**< Non-zero when the stream is currently playing. Only for playback streams. */ - uint32_t queue_length; /**< Queue size in bytes. For both playback and recrd streams. */ + uint32_t queue_length; /**< Queue size in bytes. For both playback and record streams. */ int synchronized_clocks; /**< Non-zero if the local and the * remote machine have synchronized * clocks. If synchronized clocks are diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 68ba76a9..4289b3c8 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -108,6 +108,7 @@ struct pa_stream { uint32_t ipol_usec; struct timeval ipol_timestamp; struct pa_time_event *ipol_event; + int ipol_requested; void (*state_callback)(struct pa_stream*c, void *userdata); void *state_userdata; diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 7d3d3a76..b3f1f8cd 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -32,8 +32,9 @@ #include "xmalloc.h" #include "pstream-util.h" #include "util.h" +#include "log.h" -#define LATENCY_IPOL_INTERVAL_USEC (100000L) +#define LATENCY_IPOL_INTERVAL_USEC (10000L) struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const struct pa_sample_spec *ss) { struct pa_stream *s; @@ -72,6 +73,7 @@ struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const st s->ipol_usec = 0; memset(&s->ipol_timestamp, 0, sizeof(s->ipol_timestamp)); s->ipol_event = NULL; + s->ipol_requested = 0; PA_LLIST_PREPEND(struct pa_stream, c->streams, s); @@ -208,11 +210,15 @@ static void ipol_callback(struct pa_mainloop_api *m, struct pa_time_event *e, co pa_stream_ref(s); - if (s->state == PA_STREAM_READY) +/* pa_log("requesting new ipol data\n"); */ + + if (s->state == PA_STREAM_READY && !s->ipol_requested) { pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + s->ipol_requested = 1; + } gettimeofday(&tv2, NULL); - tv2.tv_usec += LATENCY_IPOL_INTERVAL_USEC; + pa_timeval_add(&tv2, LATENCY_IPOL_INTERVAL_USEC); m->time_restart(e, &tv2); @@ -426,8 +432,10 @@ static void stream_get_latency_info_callback(struct pa_pdispatch *pd, uint32_t c } if (o->stream->interpolate) { +/* pa_log("new interpol data\n"); */ o->stream->ipol_timestamp = i.timestamp; o->stream->ipol_usec = pa_stream_get_time(o->stream, &i); + o->stream->ipol_requested = 0; } p = &i; @@ -567,10 +575,12 @@ struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (stru assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); if (s->interpolate) { - if (!s->corked && b) - s->ipol_usec = pa_stream_get_interpolated_time(s); - else if (s->corked && !b) - gettimeofday(&s->ipol_timestamp, NULL); + if (!s->corked && b) + /* Pausing */ + s->ipol_usec = pa_stream_get_interpolated_time(s); + else if (s->corked && !b) + /* Unpausing */ + gettimeofday(&s->ipol_timestamp, NULL); } s->corked = b; @@ -764,6 +774,5 @@ pa_usec_t pa_stream_get_interpolated_latency(struct pa_stream *s, int *negative) t = pa_stream_get_interpolated_time(s); c = pa_bytes_to_usec(s->counter, &s->sample_spec); - return time_counter_diff(s, t, c, negative); } -- cgit From eef235d8795df740eb63cb135bd187b7ab9ac4ea Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 18 Nov 2004 00:28:26 +0000 Subject: limit the number of concurrent connections for all four protocols kick a client if it doesn't authenticate within 5s on ESD and native protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@292 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/protocol-cli.c | 10 +++++++++ polyp/protocol-esound.c | 56 ++++++++++++++++++++++++++++++++++++++++--------- polyp/protocol-native.c | 37 ++++++++++++++++++++++++++++++++ polyp/protocol-simple.c | 9 ++++++++ 4 files changed, 102 insertions(+), 10 deletions(-) diff --git a/polyp/protocol-cli.c b/polyp/protocol-cli.c index 7ce53887..7122d23a 100644 --- a/polyp/protocol-cli.c +++ b/polyp/protocol-cli.c @@ -29,6 +29,10 @@ #include "protocol-cli.h" #include "cli.h" #include "xmalloc.h" +#include "log.h" + +/* Don't allow more than this many concurrent connections */ +#define MAX_CONNECTIONS 10 struct pa_protocol_cli { struct pa_module *module; @@ -49,6 +53,12 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo struct pa_cli *c; assert(s && io && p); + if (pa_idxset_ncontents(p->connections)+1 > MAX_CONNECTIONS) { + pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); + pa_iochannel_free(io); + return; + } + c = pa_cli_new(p->core, io, p->module); assert(c); pa_cli_set_eof_callback(c, cli_eof_cb, p); diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 07c39e2a..11a33315 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -46,6 +46,12 @@ #include "xmalloc.h" #include "log.h" +/* Don't accept more connection than this */ +#define MAX_CONNECTIONS 10 + +/* Kick a client if it doesn't authenticate within this time */ +#define AUTH_TIMEOUT 5 + #define DEFAULT_COOKIE_FILE ".esd_auth" #define PLAYBACK_BUFFER_SECONDS (.5) @@ -87,6 +93,8 @@ struct connection { char *name; struct pa_sample_spec sample_spec; } scache; + + struct pa_time_event *auth_timeout_event; }; struct pa_protocol_esound { @@ -202,6 +210,9 @@ static void connection_free(struct connection *c) { if (c->scache.memchunk.memblock) pa_memblock_unref(c->scache.memchunk.memblock); pa_xfree(c->scache.name); + + if (c->auth_timeout_event) + c->protocol->core->mainloop->time_free(c->auth_timeout_event); pa_xfree(c); } @@ -256,6 +267,8 @@ static int esd_proto_connect(struct connection *c, esd_proto_t request, const vo } c->authorized = 1; + if (c->auth_timeout_event) + c->protocol->core->mainloop->time_free(c->auth_timeout_event); } ekey = *(uint32_t*)((uint8_t*) data+ESD_KEY_LEN); @@ -1003,25 +1016,40 @@ static pa_usec_t source_output_get_latency_cb(struct pa_source_output *o) { /*** socket server callback ***/ +static void auth_timeout(struct pa_mainloop_api*m, struct pa_time_event *e, const struct timeval *tv, void *userdata) { + struct connection *c = userdata; + assert(m && tv && c && c->auth_timeout_event == e); + + if (!c->authorized) + connection_free(c); +} + static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { struct connection *c; + struct pa_protocol_esound *p = userdata; char cname[256]; - assert(s && io && userdata); + assert(s && io && p); + if (pa_idxset_ncontents(p->connections)+1 > MAX_CONNECTIONS) { + pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); + pa_iochannel_free(io); + return; + } + c = pa_xmalloc(sizeof(struct connection)); - c->protocol = userdata; + c->protocol = p; c->io = io; pa_iochannel_set_callback(c->io, io_callback, c); pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); - assert(c->protocol->core); - c->client = pa_client_new(c->protocol->core, "ESOUND", cname); + assert(p->core); + c->client = pa_client_new(p->core, "ESOUND", cname); assert(c->client); - c->client->owner = c->protocol->module; + c->client->owner = p->module; c->client->kill = client_kill_cb; c->client->userdata = c; - c->authorized = c->protocol->public; + c->authorized = p->public; c->swap_byte_order = 0; c->dead = 0; @@ -1047,19 +1075,27 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->scache.memchunk.length = c->scache.memchunk.index = 0; c->scache.memchunk.memblock = NULL; c->scache.name = NULL; + + if (!c->authorized) { + struct timeval tv; + gettimeofday(&tv, NULL); + tv.tv_sec += AUTH_TIMEOUT; + c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c); + } else + c->auth_timeout_event = NULL; - c->defer_event = c->protocol->core->mainloop->defer_new(c->protocol->core->mainloop, defer_callback, c); + c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c); assert(c->defer_event); - c->protocol->core->mainloop->defer_enable(c->defer_event, 0); + p->core->mainloop->defer_enable(c->defer_event, 0); - pa_idxset_put(c->protocol->connections, c, &c->index); + pa_idxset_put(p->connections, c, &c->index); } /*** entry points ***/ struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { struct pa_protocol_esound *p; - int public; + int public = 0; assert(core && server && ma); p = pa_xmalloc(sizeof(struct pa_protocol_esound)); diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 02d81db3..12ecfae1 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -50,6 +50,12 @@ #include "strlist.h" #include "props.h" +/* Kick a client if it doesn't authenticate within this time */ +#define AUTH_TIMEOUT 5 + +/* Don't accept more connection than this */ +#define MAX_CONNECTIONS 10 + struct connection; struct pa_protocol_native; @@ -100,6 +106,7 @@ struct connection { struct pa_idxset *record_streams, *output_streams; uint32_t rrobin_index; struct pa_subscription *subscription; + struct pa_time_event *auth_timeout_event; }; struct pa_protocol_native { @@ -374,6 +381,9 @@ static void connection_free(struct connection *c) { if (c->subscription) pa_subscription_free(c->subscription); + + if (c->auth_timeout_event) + c->protocol->core->mainloop->time_free(c->auth_timeout_event); pa_xfree(c); } @@ -746,6 +756,10 @@ static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag } c->authorized = 1; + if (c->auth_timeout_event) { + c->protocol->core->mainloop->time_free(c->auth_timeout_event); + c->auth_timeout_event = NULL; + } } pa_pstream_send_simple_ack(c->pstream, tag); @@ -1973,14 +1987,37 @@ static void client_kill_cb(struct pa_client *c) { /*** socket server callbacks ***/ +static void auth_timeout(struct pa_mainloop_api*m, struct pa_time_event *e, const struct timeval *tv, void *userdata) { + struct connection *c = userdata; + assert(m && tv && c && c->auth_timeout_event == e); + + if (!c->authorized) + connection_free(c); +} + static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { struct pa_protocol_native *p = userdata; struct connection *c; assert(io && p); + if (pa_idxset_ncontents(p->connections)+1 > MAX_CONNECTIONS) { + pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); + pa_iochannel_free(io); + return; + } + c = pa_xmalloc(sizeof(struct connection)); c->authorized =!! p->public; + + if (!c->authorized) { + struct timeval tv; + gettimeofday(&tv, NULL); + tv.tv_sec += AUTH_TIMEOUT; + c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c); + } else + c->auth_timeout_event = NULL; + c->protocol = p; assert(p->core); c->client = pa_client_new(p->core, "NATIVE", "Client"); diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index f7c69d6b..058d4b82 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -39,6 +39,9 @@ #include "xmalloc.h" #include "log.h" +/* Don't allow more than this many concurrent connections */ +#define MAX_CONNECTIONS 10 + struct connection { struct pa_protocol_simple *protocol; struct pa_iochannel *io; @@ -287,6 +290,12 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo char cname[256]; assert(s && io && p); + if (pa_idxset_ncontents(p->connections)+1 > MAX_CONNECTIONS) { + pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); + pa_iochannel_free(io); + return; + } + c = pa_xmalloc(sizeof(struct connection)); c->io = io; c->sink_input = NULL; -- cgit From 8641af3c6d11e3e6710cb946e9a93d0e9f639519 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 18 Nov 2004 20:50:44 +0000 Subject: * some iochannel fixes * introduce reference counting in ioline * fix memory leak in socket-client.c * fix double-free error in protocol-esound.c git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@293 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 3 +- polyp/cli.c | 3 +- polyp/iochannel.c | 5 + polyp/iochannel.h | 2 + polyp/ioline.c | 261 ++++++++++++++++++++++++++++++------------------ polyp/ioline.h | 4 +- polyp/mainloop.c | 3 +- polyp/protocol-esound.c | 73 ++++++++------ polyp/protocol-simple.c | 6 +- polyp/pstream.c | 19 ++-- polyp/socket-client.c | 6 +- 11 files changed, 240 insertions(+), 145 deletions(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 506cdc34..a782685a 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -215,8 +215,7 @@ polypaudio_SOURCES = idxset.c idxset.h \ polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) -polypaudio_LDFLAGS= -export-dynamic -dlopen force -# -static $(foreach f,$(modlib_LTLIBRARIES),-dlpreopen $(f)) +polypaudio_LDFLAGS= -export-dynamic -dlopen force #-static $(foreach f,$(modlib_LTLIBRARIES),-dlpreopen $(f)) libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h libprotocol_simple_la_LDFLAGS = -avoid-version diff --git a/polyp/cli.c b/polyp/cli.c index 2ff35992..7780d03d 100644 --- a/polyp/cli.c +++ b/polyp/cli.c @@ -92,7 +92,8 @@ struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io, struct void pa_cli_free(struct pa_cli *c) { assert(c); - pa_ioline_free(c->line); + pa_ioline_close(c->line); + pa_ioline_unref(c->line); pa_client_free(c->client); pa_xfree(c); } diff --git a/polyp/iochannel.c b/polyp/iochannel.c index f174afd0..0e7e8db8 100644 --- a/polyp/iochannel.c +++ b/polyp/iochannel.c @@ -235,3 +235,8 @@ int pa_iochannel_socket_set_sndbuf(struct pa_iochannel *io, size_t l) { return pa_socket_set_sndbuf(io->ofd, l); } + +struct pa_mainloop_api* pa_iochannel_get_mainloop_api(struct pa_iochannel *io) { + assert(io); + return io->mainloop; +} diff --git a/polyp/iochannel.h b/polyp/iochannel.h index 79600f72..f8efc928 100644 --- a/polyp/iochannel.h +++ b/polyp/iochannel.h @@ -47,4 +47,6 @@ void pa_iochannel_socket_peer_to_string(struct pa_iochannel*io, char*s, size_t l int pa_iochannel_socket_set_rcvbuf(struct pa_iochannel*io, size_t l); int pa_iochannel_socket_set_sndbuf(struct pa_iochannel*io, size_t l); +struct pa_mainloop_api* pa_iochannel_get_mainloop_api(struct pa_iochannel *io); + #endif diff --git a/polyp/ioline.c b/polyp/ioline.c index f3d17b58..059591b8 100644 --- a/polyp/ioline.c +++ b/polyp/ioline.c @@ -31,12 +31,16 @@ #include "ioline.h" #include "xmalloc.h" +#include "log.h" #define BUFFER_LIMIT (64*1024) #define READ_SIZE (1024) struct pa_ioline { struct pa_iochannel *io; + struct pa_defer_event *defer_event; + struct pa_mainloop_api *mainloop; + int ref; int dead; char *wbuf; @@ -50,7 +54,7 @@ struct pa_ioline { }; static void io_callback(struct pa_iochannel*io, void *userdata); -static int do_write(struct pa_ioline *l); +static void defer_callback(struct pa_mainloop_api*m, struct pa_defer_event*e, void *userdata); struct pa_ioline* pa_ioline_new(struct pa_iochannel *io) { struct pa_ioline *l; @@ -68,68 +72,112 @@ struct pa_ioline* pa_ioline_new(struct pa_iochannel *io) { l->callback = NULL; l->userdata = NULL; + l->ref = 1; + l->mainloop = pa_iochannel_get_mainloop_api(io); + + l->defer_event = l->mainloop->defer_new(l->mainloop, defer_callback, l); + l->mainloop->defer_enable(l->defer_event, 0); + pa_iochannel_set_callback(io, io_callback, l); return l; } -void pa_ioline_free(struct pa_ioline *l) { +static void ioline_free(struct pa_ioline *l) { assert(l); - pa_iochannel_free(l->io); + + if (l->io) + pa_iochannel_free(l->io); pa_xfree(l->wbuf); pa_xfree(l->rbuf); pa_xfree(l); } +void pa_ioline_unref(struct pa_ioline *l) { + assert(l && l->ref >= 1); + + if ((--l->ref) <= 0) + ioline_free(l); +} + +struct pa_ioline* pa_ioline_ref(struct pa_ioline *l) { + assert(l && l->ref >= 1); + + l->ref++; + return l; +} + +void pa_ioline_close(struct pa_ioline *l) { + assert(l && l->ref >= 1); + + l->dead = 1; + if (l->io) { + pa_iochannel_free(l->io); + l->io = NULL; + } +} + void pa_ioline_puts(struct pa_ioline *l, const char *c) { size_t len; - assert(l && c); + assert(l && c && l->ref >= 1 && !l->dead); + + pa_ioline_ref(l); len = strlen(c); if (len > BUFFER_LIMIT - l->wbuf_valid_length) len = BUFFER_LIMIT - l->wbuf_valid_length; - if (!len) - return; - - assert(l->wbuf_length >= l->wbuf_valid_length); - - /* In case the allocated buffer is too small, enlarge it. */ - if (l->wbuf_valid_length + len > l->wbuf_length) { - size_t n = l->wbuf_valid_length+len; - char *new = pa_xmalloc(n); - if (l->wbuf) { - memcpy(new, l->wbuf+l->wbuf_index, l->wbuf_valid_length); - pa_xfree(l->wbuf); + if (len) { + assert(l->wbuf_length >= l->wbuf_valid_length); + + /* In case the allocated buffer is too small, enlarge it. */ + if (l->wbuf_valid_length + len > l->wbuf_length) { + size_t n = l->wbuf_valid_length+len; + char *new = pa_xmalloc(n); + if (l->wbuf) { + memcpy(new, l->wbuf+l->wbuf_index, l->wbuf_valid_length); + pa_xfree(l->wbuf); + } + l->wbuf = new; + l->wbuf_length = n; + l->wbuf_index = 0; + } else if (l->wbuf_index + l->wbuf_valid_length + len > l->wbuf_length) { + + /* In case the allocated buffer fits, but the current index is too far from the start, move it to the front. */ + memmove(l->wbuf, l->wbuf+l->wbuf_index, l->wbuf_valid_length); + l->wbuf_index = 0; } - l->wbuf = new; - l->wbuf_length = n; - l->wbuf_index = 0; - } else if (l->wbuf_index + l->wbuf_valid_length + len > l->wbuf_length) { - - /* In case the allocated buffer fits, but the current index is too far from the start, move it to the front. */ - memmove(l->wbuf, l->wbuf+l->wbuf_index, l->wbuf_valid_length); - l->wbuf_index = 0; - } - - assert(l->wbuf_index + l->wbuf_valid_length + len <= l->wbuf_length); + + assert(l->wbuf_index + l->wbuf_valid_length + len <= l->wbuf_length); + + /* Append the new string */ + memcpy(l->wbuf + l->wbuf_index + l->wbuf_valid_length, c, len); + l->wbuf_valid_length += len; - /* Append the new string */ - memcpy(l->wbuf + l->wbuf_index + l->wbuf_valid_length, c, len); - l->wbuf_valid_length += len; + l->mainloop->defer_enable(l->defer_event, 1); + } - do_write(l); + pa_ioline_unref(l); } void pa_ioline_set_callback(struct pa_ioline*l, void (*callback)(struct pa_ioline*io, const char *s, void *userdata), void *userdata) { - assert(l); + assert(l && l->ref >= 1); l->callback = callback; l->userdata = userdata; } +static void failure(struct pa_ioline *l) { + assert(l && l->ref >= 1 && !l->dead); + + pa_ioline_close(l); + + if (l->callback) + l->callback(l, NULL, l->userdata); +} + static void scan_for_lines(struct pa_ioline *l, size_t skip) { - assert(l && skip < l->rbuf_valid_length); + assert(l && l->ref >= 1 && skip < l->rbuf_valid_length); while (!l->dead && l->rbuf_valid_length > skip) { char *e, *p; @@ -162,86 +210,109 @@ static void scan_for_lines(struct pa_ioline *l, size_t skip) { } static int do_read(struct pa_ioline *l) { - ssize_t r; - size_t len; - assert(l); - - if (!pa_iochannel_is_readable(l->io)) - return 0; + assert(l && l->ref >= 1); - len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length; + while (!l->dead && pa_iochannel_is_readable(l->io)) { + ssize_t r; + size_t len; - /* Check if we have to enlarge the read buffer */ - if (len < READ_SIZE) { - size_t n = l->rbuf_valid_length+READ_SIZE; - - if (n >= BUFFER_LIMIT) - n = BUFFER_LIMIT; + len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length; - if (l->rbuf_length >= n) { - /* The current buffer is large enough, let's just move the data to the front */ - if (l->rbuf_valid_length) - memmove(l->rbuf, l->rbuf+l->rbuf_index, l->rbuf_valid_length); - } else { - /* Enlarge the buffer */ - char *new = pa_xmalloc(n); - if (l->rbuf_valid_length) - memcpy(new, l->rbuf+l->rbuf_index, l->rbuf_valid_length); - pa_xfree(l->rbuf); - l->rbuf = new; - l->rbuf_length = n; + /* Check if we have to enlarge the read buffer */ + 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) { + /* The current buffer is large enough, let's just move the data to the front */ + if (l->rbuf_valid_length) + memmove(l->rbuf, l->rbuf+l->rbuf_index, l->rbuf_valid_length); + } else { + /* Enlarge the buffer */ + char *new = pa_xmalloc(n); + if (l->rbuf_valid_length) + memcpy(new, l->rbuf+l->rbuf_index, l->rbuf_valid_length); + pa_xfree(l->rbuf); + l->rbuf = new; + l->rbuf_length = n; + } + + l->rbuf_index = 0; + } + + len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length; + + assert(len >= READ_SIZE); + + /* Read some data */ + if ((r = pa_iochannel_read(l->io, l->rbuf+l->rbuf_index+l->rbuf_valid_length, len)) <= 0) { + pa_log(__FILE__": read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); + failure(l); + return -1; } - l->rbuf_index = 0; + l->rbuf_valid_length += r; + + /* Look if a line has been terminated in the newly read data */ + scan_for_lines(l, l->rbuf_valid_length - r); } - - len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length; - - assert(len >= READ_SIZE); - - /* Read some data */ - if ((r = pa_iochannel_read(l->io, l->rbuf+l->rbuf_index+l->rbuf_valid_length, len)) <= 0) - return -1; - - l->rbuf_valid_length += r; - - /* Look if a line has been terminated in the newly read data */ - scan_for_lines(l, l->rbuf_valid_length - r); - + return 0; } /* Try to flush the buffer */ static int do_write(struct pa_ioline *l) { ssize_t r; - assert(l); + assert(l && l->ref >= 1); - if (!l->wbuf_valid_length || !pa_iochannel_is_writable(l->io)) - return 0; - - if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0) - return -1; + while (!l->dead && pa_iochannel_is_writable(l->io) && l->wbuf_valid_length) { + + if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0) { + pa_log(__FILE__": write() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); + failure(l); + return -1; + } + + l->wbuf_index += r; + l->wbuf_valid_length -= r; + + /* A shortcut for the next time */ + if (l->wbuf_valid_length == 0) + l->wbuf_index = 0; + } + + return 0; +} - l->wbuf_index += r; - l->wbuf_valid_length -= r; +/* Try to flush read/write data */ +static void do_work(struct pa_ioline *l) { + assert(l && l->ref >= 1); - /* A shortcut for the next time */ - if (l->wbuf_valid_length == 0) - l->wbuf_index = 0; + pa_ioline_ref(l); - return 0; + l->mainloop->defer_enable(l->defer_event, 0); + + if (!l->dead) + do_write(l); + + if (!l->dead) + do_read(l); + + pa_ioline_unref(l); } -/* Try to flush read/write data */ static void io_callback(struct pa_iochannel*io, void *userdata) { struct pa_ioline *l = userdata; - assert(io && l); - - if ((!l->dead && do_write(l) < 0) || - (!l->dead && do_read(l) < 0)) { - - l->dead = 1; - if (l->callback) - l->callback(l, NULL, l->userdata); - } + assert(io && l && l->ref >= 1); + + do_work(l); +} + +static void defer_callback(struct pa_mainloop_api*m, struct pa_defer_event*e, void *userdata) { + struct pa_ioline *l = userdata; + assert(l && l->ref >= 1 && l->mainloop == m && l->defer_event == e); + + do_work(l); } diff --git a/polyp/ioline.h b/polyp/ioline.h index c6150d4b..5adc0560 100644 --- a/polyp/ioline.h +++ b/polyp/ioline.h @@ -27,7 +27,9 @@ struct pa_ioline; struct pa_ioline* pa_ioline_new(struct pa_iochannel *io); -void pa_ioline_free(struct pa_ioline *l); +void pa_ioline_unref(struct pa_ioline *l); +struct pa_ioline* pa_ioline_ref(struct pa_ioline *l); +void pa_ioline_close(struct pa_ioline *l); void pa_ioline_puts(struct pa_ioline *s, const char *c); void pa_ioline_set_callback(struct pa_ioline*io, void (*callback)(struct pa_ioline*io, const char *s, void *userdata), void *userdata); diff --git a/polyp/mainloop.c b/polyp/mainloop.c index e13e7b11..f56614ce 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -116,8 +116,7 @@ static void mainloop_io_enable(struct pa_io_event *e, enum pa_io_event_flags eve e->pollfd->events = (events & PA_IO_EVENT_INPUT ? POLLIN : 0) | (events & PA_IO_EVENT_OUTPUT ? POLLOUT : 0) | - POLLHUP | - POLLERR; + POLLERR | POLLHUP; } static void mainloop_io_free(struct pa_io_event *e) { diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 11a33315..a32a9bd8 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -267,8 +267,10 @@ static int esd_proto_connect(struct connection *c, esd_proto_t request, const vo } c->authorized = 1; - if (c->auth_timeout_event) + if (c->auth_timeout_event) { c->protocol->core->mainloop->time_free(c->auth_timeout_event); + c->auth_timeout_event = NULL; + } } ekey = *(uint32_t*)((uint8_t*) data+ESD_KEY_LEN); @@ -301,11 +303,13 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons ss.rate = rate; format_esd2native(format, &ss); - if (!pa_sample_spec_valid(&ss)) + if (!pa_sample_spec_valid(&ss)) { + pa_log(__FILE__": invalid sample specification\n"); return -1; + } if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": No output sink\n"); + pa_log(__FILE__": no such sink\n"); return -1; } @@ -314,17 +318,17 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons pa_client_set_name(c->client, name); - assert(!c->input_memblockq); + assert(!c->sink_input && !c->input_memblockq); + + if (!(c->sink_input = pa_sink_input_new(sink, name, &ss, 0, -1))) { + pa_log(__FILE__": failed to create sink input.\n"); + return -1; + } l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); c->input_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&ss), l/2, l/PLAYBACK_BUFFER_FRAGMENTS, c->protocol->core->memblock_stat); - assert(c->input_memblockq); pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2); c->playback.fragment_size = l/10; - - assert(!c->sink_input); - c->sink_input = pa_sink_input_new(sink, name, &ss, 0, -1); - assert(c->sink_input); c->sink_input->owner = c->protocol->module; c->sink_input->client = c->client; @@ -355,22 +359,30 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co ss.rate = rate; format_esd2native(format, &ss); - if (!pa_sample_spec_valid(&ss)) + if (!pa_sample_spec_valid(&ss)) { + pa_log(__FILE__": invalid sample specification.\n"); return -1; + } if (request == ESD_PROTO_STREAM_MON) { struct pa_sink* sink; - if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) + if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { + pa_log(__FILE__": no such sink.\n"); return -1; + } - if (!(source = sink->monitor_source)) + if (!(source = sink->monitor_source)) { + pa_log(__FILE__": no such monitor source.\n"); return -1; + } } else { assert(request == ESD_PROTO_STREAM_REC); - if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) + if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) { + pa_log(__FILE__": no such source.\n"); return -1; + } } strncpy(name, (char*) data + sizeof(int)*2, sizeof(name)); @@ -378,17 +390,17 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co pa_client_set_name(c->client, name); - assert(!c->output_memblockq); + assert(!c->output_memblockq && !c->source_output); + + if (!(c->source_output = pa_source_output_new(source, name, &ss, -1))) { + pa_log(__FILE__": failed to create source output\n"); + return -1; + } l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); c->output_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&ss), 0, 0, c->protocol->core->memblock_stat); - assert(c->output_memblockq); pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); - assert(!c->source_output); - c->source_output = pa_source_output_new(source, name, &ss, -1); - assert(c->source_output); - c->source_output->owner = c->protocol->module; c->source_output->client = c->client; c->source_output->push = source_output_push_cb; @@ -829,8 +841,8 @@ static int do_read(struct connection *c) { pa_log(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } - -/* pa_log(__FILE__": read %u\n", r); */ + +/* pa_log(__FILE__": read %u\n", r); */ chunk.memblock = c->playback.current_memblock; chunk.index = c->playback.memblock_index; @@ -880,7 +892,7 @@ static int do_write(struct connection *c) { pa_log(__FILE__": write(): %s\n", strerror(errno)); return -1; } - + pa_memblockq_drop(c->output_memblockq, &chunk, r); pa_memblock_unref(chunk.memblock); } @@ -894,18 +906,21 @@ static void do_work(struct connection *c) { assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); c->protocol->core->mainloop->defer_enable(c->defer_event, 0); -/* pa_log("DOWORK\n"); */ - - if (c->dead || !c->io) - return; +/* pa_log("DOWORK %i\n", pa_iochannel_is_hungup(c->io)); */ - if (pa_iochannel_is_readable(c->io)) + if (!c->dead && pa_iochannel_is_readable(c->io)) if (do_read(c) < 0) goto fail; - - if (pa_iochannel_is_writable(c->io)) + + if (!c->dead && pa_iochannel_is_writable(c->io)) if (do_write(c) < 0) goto fail; + + /* In case the line was hungup, make sure to rerun this function + as soon as possible, until all data has been read. */ + + if (!c->dead && pa_iochannel_is_hungup(c->io)) + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); return; diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index 058d4b82..3dddc474 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -180,9 +180,6 @@ static void do_work(struct connection *c) { assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); c->protocol->core->mainloop->defer_enable(c->defer_event, 0); - if (pa_iochannel_is_hungup(c->io)) - goto fail; - if (pa_iochannel_is_writable(c->io)) if (do_write(c) < 0) goto fail; @@ -191,6 +188,9 @@ static void do_work(struct connection *c) { if (do_read(c) < 0) goto fail; + if (pa_iochannel_is_hungup(c->io)) + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + return; fail: diff --git a/polyp/pstream.c b/polyp/pstream.c index 11ca3963..c081c242 100644 --- a/polyp/pstream.c +++ b/polyp/pstream.c @@ -103,25 +103,22 @@ static void do_read(struct pa_pstream *p); static void do_something(struct pa_pstream *p) { assert(p); - if (p->dead) - return; - p->mainloop->defer_enable(p->defer_event, 0); pa_pstream_ref(p); - if (!p->dead && pa_iochannel_is_hungup(p->io)) { - p->dead = 1; - if (p->die_callback) - p->die_callback(p, p->die_callback_userdata); - } + if (!p->dead && pa_iochannel_is_readable(p->io)) + do_read(p); if (!p->dead && pa_iochannel_is_writable(p->io)) do_write(p); - if (!p->dead && pa_iochannel_is_readable(p->io)) - do_read(p); - + /* In case the line was hungup, make sure to rerun this function + as soon as possible, until all data has been read. */ + + if (!p->dead && pa_iochannel_is_hungup(p->io)) + p->mainloop->defer_enable(p->defer_event, 1); + pa_pstream_unref(p); } diff --git a/polyp/socket-client.c b/polyp/socket-client.c index aea38586..c58c7bd4 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -330,6 +330,7 @@ struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, case KIND_TCP6: { uint16_t port = default_port; char *h; + int ret; struct addrinfo hints, *res; if (!(h = parse_address(p, &port))) @@ -338,7 +339,10 @@ struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, memset(&hints, 0, sizeof(hints)); hints.ai_family = kind == KIND_TCP4 ? AF_INET : (kind == KIND_TCP6 ? AF_INET6 : AF_UNSPEC); - if (getaddrinfo(h, NULL, &hints, &res) < 0 || !res || !res->ai_addr) + ret = getaddrinfo(h, NULL, &hints, &res); + pa_xfree(h); + + if (ret < 0 || !res || !res->ai_addr) return NULL; if (res->ai_family == AF_INET) { -- cgit From 5f647c8fef33f35210d550ad1477ef43520b32a3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 20 Nov 2004 16:23:53 +0000 Subject: * add µlaw/alaw support * abstracted resampler API * add integer-only resampler ("trivial") * show used resampler wherever useful * add mixing/volume adjusting for float32ne and u8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@294 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 - polyp/Makefile.am | 3 +- polyp/cli-text.c | 20 +- polyp/core.c | 3 +- polyp/core.h | 3 +- polyp/daemon-conf.c | 14 +- polyp/g711.c | 2531 +++++++++++++++++++++++++++++++++++++++++++ polyp/g711.h | 40 + polyp/pactl.c | 12 +- polyp/polyplib-introspect.c | 6 +- polyp/polyplib-introspect.h | 2 + polyp/protocol-native.c | 2 + polyp/pstream-util.c | 3 +- polyp/resampler.c | 337 ++++-- polyp/resampler.h | 26 + polyp/sample-util.c | 215 +++- polyp/sconv-s16be.c | 4 +- polyp/sconv-s16be.h | 4 +- polyp/sconv-s16le.c | 4 +- polyp/sconv-s16le.h | 4 +- polyp/sconv.c | 128 ++- polyp/sconv.h | 8 +- polyp/sink-input.c | 11 +- polyp/sink-input.h | 2 + polyp/source-output.c | 11 +- polyp/source-output.h | 1 + polyp/util.c | 17 - polyp/util.h | 2 - 28 files changed, 3230 insertions(+), 185 deletions(-) create mode 100644 polyp/g711.c create mode 100644 polyp/g711.h diff --git a/doc/todo b/doc/todo index 948ae65b..9898bc9d 100644 --- a/doc/todo +++ b/doc/todo @@ -8,8 +8,6 @@ - make most buffer sizes dependant on the sample type - limit all resources - commenting -- non-fp mixing -- non-fp resampling - module-tunnel: use latency interpolation - polish for starting polypaudio as root/system-wide instance diff --git a/polyp/Makefile.am b/polyp/Makefile.am index a782685a..dd7fb8b4 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -210,7 +210,8 @@ polypaudio_SOURCES = idxset.c idxset.h \ conf-parser.h conf-parser.c \ caps.h caps.c \ props.h props.c \ - mcalign.c mcalign.h + mcalign.c mcalign.h \ + g711.c g711.h polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) diff --git a/polyp/cli-text.c b/polyp/cli-text.c index 7974275a..629b28e2 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -162,15 +162,21 @@ char *pa_source_output_list_to_string(struct pa_core *c) { for (o = pa_idxset_first(c->source_outputs, &index); o; o = pa_idxset_next(c->source_outputs, &index)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; + const char *rm; pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec); assert(o->source); + + if (!(rm = pa_resample_method_to_string(pa_source_output_get_resample_method(o)))) + rm = "invalid"; + pa_strbuf_printf( - s, " index: %u\n\tname: '%s'\n\tstate: %s\n\tsource: <%u> '%s'\n\tsample_spec: <%s>\n", + s, " index: %u\n\tname: '%s'\n\tstate: %s\n\tsource: <%u> '%s'\n\tsample_spec: <%s>\n\tresample method: %s\n", o->index, o->name, state_table[o->state], o->source->index, o->source->name, - ss); + ss, + rm); if (o->owner) pa_strbuf_printf(s, "\towner module: <%u>\n", o->owner->index); if (o->client) @@ -198,10 +204,15 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { for (i = pa_idxset_first(c->sink_inputs, &index); i; i = pa_idxset_next(c->sink_inputs, &index)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; + const char *rm; + + if (!(rm = pa_resample_method_to_string(pa_sink_input_get_resample_method(i)))) + rm = "invalid"; + pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec); assert(i->sink); pa_strbuf_printf( - s, " index: %u\n\tname: <%s>\n\tstate: %s\n\tsink: <%u> '%s'\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n", + s, " index: %u\n\tname: <%s>\n\tstate: %s\n\tsink: <%u> '%s'\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n\tresample method: %s\n", i->index, i->name, state_table[i->state], @@ -209,7 +220,8 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { (unsigned) i->volume, pa_volume_to_dB(i->volume), (float) pa_sink_input_get_latency(i), - ss); + ss, + rm); if (i->owner) pa_strbuf_printf(s, "\towner module: <%u>\n", i->owner->index); diff --git a/polyp/core.c b/polyp/core.c index 19e0425f..03682fdc 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -27,7 +27,6 @@ #include #include #include -#include #include "core.h" #include "module.h" @@ -82,7 +81,7 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->module_idle_time = 20; c->scache_idle_time = 20; - c->resample_method = SRC_SINC_FASTEST; + c->resample_method = PA_RESAMPLER_SRC_SINC_FASTEST; pa_property_init(c); diff --git a/polyp/core.h b/polyp/core.h index 799661af..09e58b46 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -27,6 +27,7 @@ #include "mainloop-api.h" #include "sample.h" #include "memblock.h" +#include "resampler.h" struct pa_core { struct pa_mainloop_api *mainloop; @@ -54,7 +55,7 @@ struct pa_core { struct pa_time_event *scache_auto_unload_event; - int resample_method; + enum pa_resample_method resample_method; }; struct pa_core* pa_core_new(struct pa_mainloop_api *m); diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c index c0ff02f9..191e8d81 100644 --- a/polyp/daemon-conf.c +++ b/polyp/daemon-conf.c @@ -28,13 +28,13 @@ #include #include #include -#include #include "daemon-conf.h" #include "util.h" #include "xmalloc.h" #include "strbuf.h" #include "conf-parser.h" +#include "resampler.h" #ifndef DEFAULT_CONFIG_DIR #define DEFAULT_CONFIG_DIR "/etc/polypaudio" @@ -64,7 +64,7 @@ static const struct pa_daemon_conf default_conf = { .dl_search_path = NULL, .default_script_file = NULL, .log_target = PA_LOG_SYSLOG, - .resample_method = SRC_SINC_FASTEST, + .resample_method = PA_RESAMPLER_SRC_SINC_FASTEST, .config_file = NULL, }; @@ -214,14 +214,6 @@ int pa_daemon_conf_env(struct pa_daemon_conf *c) { char *pa_daemon_conf_dump(struct pa_daemon_conf *c) { struct pa_strbuf *s = pa_strbuf_new(); - static const char const* resample_methods[] = { - "sinc-best-quality", - "sinc-medium-quality", - "sinc-fastest", - "zero-order-hold", - "linear" - }; - if (c->config_file) pa_strbuf_printf(s, "### Read from configuration file: %s ###\n", c->config_file); @@ -238,7 +230,7 @@ char *pa_daemon_conf_dump(struct pa_daemon_conf *c) { pa_strbuf_printf(s, "log-target = %s\n", c->auto_log_target ? "auto" : (c->log_target == PA_LOG_SYSLOG ? "syslog" : "stderr")); assert(c->resample_method <= 4 && c->resample_method >= 0); - pa_strbuf_printf(s, "resample-method = %s\n", resample_methods[c->resample_method]); + pa_strbuf_printf(s, "resample-method = %s\n", pa_resample_method_to_string(c->resample_method)); return pa_strbuf_tostring_free(s); } diff --git a/polyp/g711.c b/polyp/g711.c new file mode 100644 index 00000000..55a82396 --- /dev/null +++ b/polyp/g711.c @@ -0,0 +1,2531 @@ +/* + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * g711.c + * + * u-law, A-law and linear PCM conversions. + */ + +/* + * December 30, 1994: + * Functions linear2alaw, linear2ulaw have been updated to correctly + * convert unquantized 16 bit values. + * Tables for direct u- to A-law and A- to u-law conversions have been + * corrected. + * Borge Lindberg, Center for PersonKommunikation, Aalborg University. + * bli@cpk.auc.dk + * + */ + +#include "g711.h" + +#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ +#define QUANT_MASK (0xf) /* Quantization field mask. */ +#define NSEGS (8) /* Number of A-law segments. */ +#define SEG_SHIFT (4) /* Left shift for segment number. */ +#define SEG_MASK (0x70) /* Segment field mask. */ + +#if !defined(FAST_ALAW_CONVERSION) || !defined(FAST_ULAW_CONVERSION) +static int16_t seg_aend[8] = {0x1F, 0x3F, 0x7F, 0xFF, + 0x1FF, 0x3FF, 0x7FF, 0xFFF}; +static int16_t seg_uend[8] = {0x3F, 0x7F, 0xFF, 0x1FF, + 0x3FF, 0x7FF, 0xFFF, 0x1FFF}; + +static int16_t search( + int16_t val, + int16_t *table, + int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (val <= *table++) + return (i); + } + return (size); +} +#endif /* !FAST_*_CONVERSION */ + +#ifndef FAST_ALAW_CONVERSION +/* + * linear2alaw() accepts an 13-bit signed integer and encodes it as A-law data + * stored in a unsigned char. This function should only be called with + * the data shifted such that it only contains information in the lower + * 13-bits. + * + * Linear Input Code Compressed Code + * ------------------------ --------------- + * 0000000wxyza 000wxyz + * 0000001wxyza 001wxyz + * 000001wxyzab 010wxyz + * 00001wxyzabc 011wxyz + * 0001wxyzabcd 100wxyz + * 001wxyzabcde 101wxyz + * 01wxyzabcdef 110wxyz + * 1wxyzabcdefg 111wxyz + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ +unsigned char st_13linear2alaw( + int16_t pcm_val) /* 2's complement (13-bit range) */ +{ + int16_t mask; + short seg; + unsigned char aval; + + /* Have calling software do it since its already doing a shift + * from 32-bits down to 16-bits. + */ + /* pcm_val = pcm_val >> 3; */ + + /* A-law using even bit inversion */ + if (pcm_val >= 0) { + mask = 0xD5; /* sign (7th) bit = 1 */ + } else { + mask = 0x55; /* sign bit = 0 */ + pcm_val = -pcm_val - 1; + } + + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_aend, 8); + + /* Combine the sign, segment, and quantization bits. */ + + if (seg >= 8) /* out of range, return maximum value. */ + return (unsigned char) (0x7F ^ mask); + else { + aval = (unsigned char) seg << SEG_SHIFT; + if (seg < 2) + aval |= (pcm_val >> 1) & QUANT_MASK; + else + aval |= (pcm_val >> seg) & QUANT_MASK; + return (aval ^ mask); + } +} + +/* + * alaw2linear() - Convert an A-law value to 16-bit signed linear PCM + * + */ +int16_t st_alaw2linear16( + unsigned char a_val) +{ + int16_t t; + int16_t seg; + + a_val ^= 0x55; + + t = (a_val & QUANT_MASK) << 4; + seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT; + switch (seg) { + case 0: + t += 8; + break; + case 1: + t += 0x108; + break; + default: + t += 0x108; + t <<= seg - 1; + } + return ((a_val & SIGN_BIT) ? t : -t); +} +#endif /* !FAST_ALAW_CONVERSION */ + +#define BIAS (0x84) /* Bias for linear code. */ +#define CLIP 8159 + +#ifndef FAST_ULAW_CONVERSION +/* + * linear2ulaw() accepts a 14-bit signed integer and encodes it as u-law data + * stored in a unsigned char. This function should only be called with + * the data shifted such that it only contains information in the lower + * 14-bits. + * + * In order to simplify the encoding process, the original linear magnitude + * is biased by adding 33 which shifts the encoding range from (0 - 8158) to + * (33 - 8191). The result can be seen in the following encoding table: + * + * Biased Linear Input Code Compressed Code + * ------------------------ --------------- + * 00000001wxyza 000wxyz + * 0000001wxyzab 001wxyz + * 000001wxyzabc 010wxyz + * 00001wxyzabcd 011wxyz + * 0001wxyzabcde 100wxyz + * 001wxyzabcdef 101wxyz + * 01wxyzabcdefg 110wxyz + * 1wxyzabcdefgh 111wxyz + * + * Each biased linear code has a leading 1 which identifies the segment + * number. The value of the segment number is equal to 7 minus the number + * of leading 0's. The quantization interval is directly available as the + * four bits wxyz. * The trailing bits (a - h) are ignored. + * + * Ordinarily the complement of the resulting code word is used for + * transmission, and so the code word is complemented before it is returned. + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ +unsigned char st_14linear2ulaw( + int16_t pcm_val) /* 2's complement (14-bit range) */ +{ + int16_t mask; + int16_t seg; + unsigned char uval; + + /* Have calling software do it since its already doing a shift + * from 32-bits down to 16-bits. + */ + /* pcm_val = pcm_val >> 2; */ + + /* u-law inverts all bits */ + /* Get the sign and the magnitude of the value. */ + if (pcm_val < 0) { + pcm_val = -pcm_val; + mask = 0x7F; + } else { + mask = 0xFF; + } + if ( pcm_val > CLIP ) pcm_val = CLIP; /* clip the magnitude */ + pcm_val += (BIAS >> 2); + + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_uend, 8); + + /* + * Combine the sign, segment, quantization bits; + * and complement the code word. + */ + if (seg >= 8) /* out of range, return maximum value. */ + return (unsigned char) (0x7F ^ mask); + else { + uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF); + return (uval ^ mask); + } + +} + +/* + * ulaw2linear() - Convert a u-law value to 16-bit linear PCM + * + * First, a biased linear code is derived from the code word. An unbiased + * output can then be obtained by subtracting 33 from the biased code. + * + * Note that this function expects to be passed the complement of the + * original code word. This is in keeping with ISDN conventions. + */ +int16_t st_ulaw2linear16( + unsigned char u_val) +{ + int16_t t; + + /* Complement to obtain normal u-law value. */ + u_val = ~u_val; + + /* + * Extract and bias the quantization bits. Then + * shift up by the segment number and subtract out the bias. + */ + t = ((u_val & QUANT_MASK) << 3) + BIAS; + t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; + + return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); +} +#endif /* !FAST_ULAW_CONVERSION */ + +#ifdef FAST_ALAW_CONVERSION + +int16_t _st_alaw2linear16[256] = { + -5504, -5248, -6016, -5760, -4480, -4224, -4992, + -4736, -7552, -7296, -8064, -7808, -6528, -6272, + -7040, -6784, -2752, -2624, -3008, -2880, -2240, + -2112, -2496, -2368, -3776, -3648, -4032, -3904, + -3264, -3136, -3520, -3392, -22016, -20992, -24064, + -23040, -17920, -16896, -19968, -18944, -30208, -29184, + -32256, -31232, -26112, -25088, -28160, -27136, -11008, + -10496, -12032, -11520, -8960, -8448, -9984, -9472, + -15104, -14592, -16128, -15616, -13056, -12544, -14080, + -13568, -344, -328, -376, -360, -280, -264, + -312, -296, -472, -456, -504, -488, -408, + -392, -440, -424, -88, -72, -120, -104, + -24, -8, -56, -40, -216, -200, -248, + -232, -152, -136, -184, -168, -1376, -1312, + -1504, -1440, -1120, -1056, -1248, -1184, -1888, + -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, + -592, -944, -912, -1008, -976, -816, -784, + -880, -848, 5504, 5248, 6016, 5760, 4480, + 4224, 4992, 4736, 7552, 7296, 8064, 7808, + 6528, 6272, 7040, 6784, 2752, 2624, 3008, + 2880, 2240, 2112, 2496, 2368, 3776, 3648, + 4032, 3904, 3264, 3136, 3520, 3392, 22016, + 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, + 27136, 11008, 10496, 12032, 11520, 8960, 8448, + 9984, 9472, 15104, 14592, 16128, 15616, 13056, + 12544, 14080, 13568, 344, 328, 376, 360, + 280, 264, 312, 296, 472, 456, 504, + 488, 408, 392, 440, 424, 88, 72, + 120, 104, 24, 8, 56, 40, 216, + 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, + 1184, 1888, 1824, 2016, 1952, 1632, 1568, + 1760, 1696, 688, 656, 752, 720, 560, + 528, 624, 592, 944, 912, 1008, 976, + 816, 784, 880, 848 +}; + +uint8_t _st_13linear2alaw[0x2000] = { + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, + 0x6b, 0x6b, 0x6b, 0x6b, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, + 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x6e, 0x6e, 0x6e, 0x6e, + 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, + 0x6d, 0x6d, 0x6d, 0x6d, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x60, 0x60, 0x60, 0x60, + 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, + 0x67, 0x67, 0x67, 0x67, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, + 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x7a, 0x7a, 0x7a, 0x7a, + 0x7b, 0x7b, 0x7b, 0x7b, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7c, 0x7c, 0x7c, 0x7c, + 0x7d, 0x7d, 0x7d, 0x7d, 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x73, + 0x70, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x71, 0x76, 0x76, 0x76, 0x76, + 0x77, 0x77, 0x77, 0x77, 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x75, + 0x4a, 0x4a, 0x4b, 0x4b, 0x48, 0x48, 0x49, 0x49, 0x4e, 0x4e, 0x4f, 0x4f, + 0x4c, 0x4c, 0x4d, 0x4d, 0x42, 0x42, 0x43, 0x43, 0x40, 0x40, 0x41, 0x41, + 0x46, 0x46, 0x47, 0x47, 0x44, 0x44, 0x45, 0x45, 0x5a, 0x5a, 0x5b, 0x5b, + 0x58, 0x58, 0x59, 0x59, 0x5e, 0x5e, 0x5f, 0x5f, 0x5c, 0x5c, 0x5d, 0x5d, + 0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51, 0x56, 0x56, 0x57, 0x57, + 0x54, 0x54, 0x55, 0x55, 0xd5, 0xd5, 0xd4, 0xd4, 0xd7, 0xd7, 0xd6, 0xd6, + 0xd1, 0xd1, 0xd0, 0xd0, 0xd3, 0xd3, 0xd2, 0xd2, 0xdd, 0xdd, 0xdc, 0xdc, + 0xdf, 0xdf, 0xde, 0xde, 0xd9, 0xd9, 0xd8, 0xd8, 0xdb, 0xdb, 0xda, 0xda, + 0xc5, 0xc5, 0xc4, 0xc4, 0xc7, 0xc7, 0xc6, 0xc6, 0xc1, 0xc1, 0xc0, 0xc0, + 0xc3, 0xc3, 0xc2, 0xc2, 0xcd, 0xcd, 0xcc, 0xcc, 0xcf, 0xcf, 0xce, 0xce, + 0xc9, 0xc9, 0xc8, 0xc8, 0xcb, 0xcb, 0xca, 0xca, 0xf5, 0xf5, 0xf5, 0xf5, + 0xf4, 0xf4, 0xf4, 0xf4, 0xf7, 0xf7, 0xf7, 0xf7, 0xf6, 0xf6, 0xf6, 0xf6, + 0xf1, 0xf1, 0xf1, 0xf1, 0xf0, 0xf0, 0xf0, 0xf0, 0xf3, 0xf3, 0xf3, 0xf3, + 0xf2, 0xf2, 0xf2, 0xf2, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xf9, 0xf9, 0xf9, 0xf9, + 0xf8, 0xf8, 0xf8, 0xf8, 0xfb, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xfa, + 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4, + 0xe4, 0xe4, 0xe4, 0xe4, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, + 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe1, 0xe1, 0xe1, 0xe1, + 0xe1, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, + 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, + 0xe2, 0xe2, 0xe2, 0xe2, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, + 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xef, 0xef, 0xef, 0xef, + 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, + 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, + 0xe8, 0xe8, 0xe8, 0xe8, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa +}; + +#endif /* FAST_ALAW_CONVERSION */ + +#ifdef FAST_ULAW_CONVERSION + +int16_t _st_ulaw2linear16[256] = { + -32124, -31100, -30076, -29052, -28028, -27004, -25980, + -24956, -23932, -22908, -21884, -20860, -19836, -18812, + -17788, -16764, -15996, -15484, -14972, -14460, -13948, + -13436, -12924, -12412, -11900, -11388, -10876, -10364, + -9852, -9340, -8828, -8316, -7932, -7676, -7420, + -7164, -6908, -6652, -6396, -6140, -5884, -5628, + -5372, -5116, -4860, -4604, -4348, -4092, -3900, + -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, + -1980, -1884, -1820, -1756, -1692, -1628, -1564, + -1500, -1436, -1372, -1308, -1244, -1180, -1116, + -1052, -988, -924, -876, -844, -812, -780, + -748, -716, -684, -652, -620, -588, -556, + -524, -492, -460, -428, -396, -372, -356, + -340, -324, -308, -292, -276, -260, -244, + -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, + -64, -56, -48, -40, -32, -24, -16, + -8, 0, 32124, 31100, 30076, 29052, 28028, + 27004, 25980, 24956, 23932, 22908, 21884, 20860, + 19836, 18812, 17788, 16764, 15996, 15484, 14972, + 14460, 13948, 13436, 12924, 12412, 11900, 11388, + 10876, 10364, 9852, 9340, 8828, 8316, 7932, + 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, + 4092, 3900, 3772, 3644, 3516, 3388, 3260, + 3132, 3004, 2876, 2748, 2620, 2492, 2364, + 2236, 2108, 1980, 1884, 1820, 1756, 1692, + 1628, 1564, 1500, 1436, 1372, 1308, 1244, + 1180, 1116, 1052, 988, 924, 876, 844, + 812, 780, 748, 716, 684, 652, 620, + 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, + 260, 244, 228, 212, 196, 180, 164, + 148, 132, 120, 112, 104, 96, 88, + 80, 72, 64, 56, 48, 40, 32, + 24, 16, 8, 0 +}; + +uint8_t _st_14linear2ulaw[0x4000] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, + 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, + 0x43, 0x43, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, + 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, + 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, + 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, + 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, + 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, + 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, + 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, + 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, + 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, + 0x52, 0x52, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, + 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x57, 0x57, + 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a, 0x5a, + 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, + 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, + 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x60, 0x60, + 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x62, 0x63, 0x63, + 0x63, 0x63, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, + 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, + 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, + 0x6f, 0x6f, 0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x74, 0x74, + 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a, + 0x7b, 0x7b, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0xff, 0xfe, 0xfe, 0xfd, + 0xfd, 0xfc, 0xfc, 0xfb, 0xfb, 0xfa, 0xfa, 0xf9, 0xf9, 0xf8, 0xf8, 0xf7, + 0xf7, 0xf6, 0xf6, 0xf5, 0xf5, 0xf4, 0xf4, 0xf3, 0xf3, 0xf2, 0xf2, 0xf1, + 0xf1, 0xf0, 0xf0, 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xed, + 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xeb, 0xeb, 0xeb, 0xeb, 0xea, + 0xea, 0xea, 0xea, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, + 0xe4, 0xe4, 0xe4, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, 0xe1, + 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, + 0xdf, 0xdf, 0xdf, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, + 0xdc, 0xdc, 0xdc, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xda, + 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, + 0xd9, 0xd9, 0xd9, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd7, + 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, + 0xd6, 0xd6, 0xd6, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd4, + 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, + 0xd3, 0xd3, 0xd3, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd1, + 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, + 0xd0, 0xd0, 0xd0, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, + 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xce, 0xce, 0xce, 0xce, 0xce, + 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, + 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xca, + 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, + 0xca, 0xca, 0xca, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, + 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, + 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc7, + 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, + 0xc7, 0xc7, 0xc7, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, + 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, + 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc1, + 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, + 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, + 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80 +}; + +#endif /* FAST_ULAW_CONVERSION */ + +/* The following code was used to generate the lookup tables */ +#if 0 +int main() +{ + int x, y, find2a = 0; + + y = 0; + printf("int16_t _st_alaw2linear16[256] = {\n "); + for (x = 0; x < 256; x++) + { + printf("%8d,", st_alaw2linear16(x)); + y++; + if (y == 7) + { + y = 0; + printf("\n "); + } + } + + printf("\n};\n\nuint8_t _st_13linear2alaw[0x2000] = {\n "); + y = 0; + for (x = 0; x < 0x2000; x++) + { + printf(" 0x%02x,", st_13linear2alaw((-0x1000)+x)); + y++; + if (y == 12) + { + y = 0; + printf("\n "); + } + } + + printf("\n};\n\nint16_t _st_ulaw2linear16[256] = {\n "); + y = 0; + for (x = 0; x < 256; x++) + { + printf("%8d,", st_ulaw2linear16(x)); + y++; + if (y == 7) + { + y = 0; + printf("\n "); + } + } + + printf("\n};\n\nuint8_t _st_14linear2ulaw[0x4000] = {\n "); + y = 0; + for (x = 0; x < 0x4000; x++) + { + printf(" 0x%02x,", st_14linear2ulaw((-0x2000)+x)); + y++; + if (y == 12) + { + y = 0; + printf("\n "); + } + } + printf("\n};\n"); + +} +#endif + +/* The following is not used by SoX but kept for reference */ +#if 0 +/* copy from CCITT G.711 specifications */ +unsigned char _u2a[128] = { /* u- to A-law conversions */ + 1, 1, 2, 2, 3, 3, 4, 4, + 5, 5, 6, 6, 7, 7, 8, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 27, 29, 31, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, + 46, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, +/* corrected: + 81, 82, 83, 84, 85, 86, 87, 88, + should be: */ + 80, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128}; + +unsigned char _a2u[128] = { /* A- to u-law conversions */ + 1, 3, 5, 7, 9, 11, 13, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 32, 33, 33, 34, 34, 35, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 48, 49, 49, + 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 64, + 65, 66, 67, 68, 69, 70, 71, 72, +/* corrected: + 73, 74, 75, 76, 77, 78, 79, 79, + should be: */ + 73, 74, 75, 76, 77, 78, 79, 80, + + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127}; + +/* A-law to u-law conversion */ +unsigned char st_alaw2ulaw( + unsigned char aval) +{ + aval &= 0xff; + return (unsigned char) ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) : + (0x7F ^ _a2u[aval ^ 0x55])); +} + +/* u-law to A-law conversion */ +unsigned char st_ulaw2alaw( + unsigned char uval) +{ + uval &= 0xff; + return (unsigned char) ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) : + (unsigned char) (0x55 ^ (_u2a[0x7F ^ uval] - 1))); +} +#endif diff --git a/polyp/g711.h b/polyp/g711.h new file mode 100644 index 00000000..97cedf81 --- /dev/null +++ b/polyp/g711.h @@ -0,0 +1,40 @@ +#ifndef foog711hfoo +#define foog711hfoo + +/* g711.h - include for G711 u-law and a-law conversion routines +** +** Copyright (C) 2001 Chris Bagwell +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +*/ + +/** Copied from sox -- Lennart Poettring*/ + +#include + +#ifdef FAST_ALAW_CONVERSION +extern uint8_t _st_13linear2alaw[0x2000]; +extern int16_t _st_alaw2linear16[256]; +#define st_13linear2alaw(sw) (_st_13linear2alaw[(sw + 0x1000)]) +#define st_alaw2linear16(uc) (_st_alaw2linear16[uc]) +#else +unsigned char st_13linear2alaw(int16_t pcm_val); +int16_t st_alaw2linear16(unsigned char); +#endif + +#ifdef FAST_ULAW_CONVERSION +extern uint8_t _st_14linear2ulaw[0x4000]; +extern int16_t _st_ulaw2linear16[256]; +#define st_14linear2ulaw(sw) (_st_14linear2ulaw[(sw + 0x2000)]) +#define st_ulaw2linear16(uc) (_st_ulaw2linear16[uc]) +#else +unsigned char st_14linear2ulaw(int16_t pcm_val); +int16_t st_ulaw2linear16(unsigned char); +#endif + +#endif diff --git a/polyp/pactl.c b/polyp/pactl.c index 641106df..d73f703c 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -324,7 +324,8 @@ static void get_sink_input_info_callback(struct pa_context *c, const struct pa_s "Sample Specification: %s\n" "Volume: 0x%03x (%0.2f dB)\n" "Buffer Latency: %0.0f usec\n" - "Sink Latency: %0.0f usec\n", + "Sink Latency: %0.0f usec\n" + "Resample method: %s\n", i->index, i->name, i->owner_module != PA_INVALID_INDEX ? t : "n/a", @@ -333,7 +334,8 @@ static void get_sink_input_info_callback(struct pa_context *c, const struct pa_s s, i->volume, pa_volume_to_dB(i->volume), (double) i->buffer_usec, - (double) i->sink_usec); + (double) i->sink_usec, + i->resample_method ? i->resample_method : "n/a"); } static void get_source_output_info_callback(struct pa_context *c, const struct pa_source_output_info *i, int is_last, void *userdata) { @@ -367,7 +369,8 @@ static void get_source_output_info_callback(struct pa_context *c, const struct p "Source: %u\n" "Sample Specification: %s\n" "Buffer Latency: %0.0f usec\n" - "Source Latency: %0.0f usec\n", + "Source Latency: %0.0f usec\n" + "Resample method: %s\n", i->index, i->name, i->owner_module != PA_INVALID_INDEX ? t : "n/a", @@ -375,7 +378,8 @@ static void get_source_output_info_callback(struct pa_context *c, const struct p i->source, s, (double) i->buffer_usec, - (double) i->source_usec); + (double) i->source_usec, + i->resample_method ? i->resample_method : "n/a"); } static void get_sample_info_callback(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata) { diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index f15f59cc..fe632c26 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -449,7 +449,8 @@ static void context_get_sink_input_info_callback(struct pa_pdispatch *pd, uint32 pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || pa_tagstruct_getu32(t, &i.volume) < 0 || pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || - pa_tagstruct_get_usec(t, &i.sink_usec) < 0) { + pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || + pa_tagstruct_gets(t, &i.resample_method) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } @@ -519,7 +520,8 @@ static void context_get_source_output_info_callback(struct pa_pdispatch *pd, uin pa_tagstruct_getu32(t, &i.source) < 0 || pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || - pa_tagstruct_get_usec(t, &i.source_usec) < 0) { + pa_tagstruct_get_usec(t, &i.source_usec) < 0 || + pa_tagstruct_gets(t, &i.resample_method) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index 5a8f1bf3..08b36f86 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -143,6 +143,7 @@ struct pa_sink_input_info { pa_volume_t volume; /**< The volume of this sink input */ pa_usec_t buffer_usec; /**< Latency due to buffering in sink input, see pa_latency_info for details */ pa_usec_t sink_usec; /**< Latency of the sink device, see pa_latency_info for details */ + const char *resample_method; /**< Thre resampling method used by this sink input. \since 0.7 */ }; /** Get some information about a sink input by its index */ @@ -161,6 +162,7 @@ struct pa_source_output_info { struct pa_sample_spec sample_spec; /**< The sample specification of the source output */ pa_usec_t buffer_usec; /**< Latency due to buffering in the source output, see pa_latency_info for details. \since 0.5 */ pa_usec_t source_usec; /**< Latency of the source device, see pa_latency_info for details. \since 0.5 */ + const char *resample_method; /**< Thre resampling method used by this source output. \since 0.7 */ }; /** Get information about a source output by its index */ diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 12ecfae1..e4831e4d 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -1160,6 +1160,7 @@ static void sink_input_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink_inp pa_tagstruct_putu32(t, s->volume); pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s)); pa_tagstruct_put_usec(t, pa_sink_get_latency(s->sink)); + pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s))); } static void source_output_fill_tagstruct(struct pa_tagstruct *t, struct pa_source_output *s) { @@ -1172,6 +1173,7 @@ static void source_output_fill_tagstruct(struct pa_tagstruct *t, struct pa_sourc pa_tagstruct_put_sample_spec(t, &s->sample_spec); pa_tagstruct_put_usec(t, pa_source_output_get_latency(s)); pa_tagstruct_put_usec(t, pa_source_get_latency(s->source)); + pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s))); } static void scache_fill_tagstruct(struct pa_tagstruct *t, struct pa_scache_entry *e) { diff --git a/polyp/pstream-util.c b/polyp/pstream-util.c index 95a2ae89..8526f29c 100644 --- a/polyp/pstream-util.c +++ b/polyp/pstream-util.c @@ -32,7 +32,8 @@ void pa_pstream_send_tagstruct(struct pa_pstream *p, struct pa_tagstruct *t) { size_t length; uint8_t *data; struct pa_packet *packet; - assert(p && t); + assert(p); + assert(t); data = pa_tagstruct_free_data(t, &length); assert(data && length); diff --git a/polyp/resampler.c b/polyp/resampler.c index 4ddcfa40..6cf51dab 100644 --- a/polyp/resampler.c +++ b/polyp/resampler.c @@ -24,6 +24,7 @@ #endif #include +#include #include @@ -34,55 +35,74 @@ struct pa_resampler { struct pa_sample_spec i_ss, o_ss; - float* i_buf, *o_buf; - unsigned i_alloc, o_alloc; - size_t i_sz, o_sz; - + size_t i_fz, o_fz; + struct pa_memblock_stat *memblock_stat; + void *impl_data; int channels; + enum pa_resample_method resample_method; - pa_convert_to_float32_func_t to_float32_func; - pa_convert_from_float32_func_t from_float32_func; + void (*impl_free)(struct pa_resampler *r); + void (*impl_set_input_rate)(struct pa_resampler *r, uint32_t rate); + void (*impl_run)(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out); +}; + +struct impl_libsamplerate { + float* i_buf, *o_buf; + unsigned i_alloc, o_alloc; + pa_convert_to_float32ne_func_t to_float32ne_func; + pa_convert_from_float32ne_func_t from_float32ne_func; SRC_STATE *src_state; +}; - struct pa_memblock_stat *memblock_stat; +struct impl_trivial { + unsigned o_counter; + unsigned i_counter; }; -struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b, struct pa_memblock_stat *s, int resample_method) { +static int libsamplerate_init(struct pa_resampler*r); +static int trivial_init(struct pa_resampler*r); + +struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b, struct pa_memblock_stat *s, enum pa_resample_method resample_method) { struct pa_resampler *r = NULL; - int err; - assert(a && b && pa_sample_spec_valid(a) && pa_sample_spec_valid(b)); + assert(a && b && pa_sample_spec_valid(a) && pa_sample_spec_valid(b) && resample_method != PA_RESAMPLER_INVALID); if (a->channels != b->channels && a->channels != 1 && b->channels != 1) goto fail; - if (a->format == PA_SAMPLE_ALAW || a->format == PA_SAMPLE_ULAW || b->format == PA_SAMPLE_ALAW || b->format == PA_SAMPLE_ULAW) - goto fail; - r = pa_xmalloc(sizeof(struct pa_resampler)); + r->impl_data = NULL; + r->memblock_stat = s; + r->resample_method = resample_method; - r->channels = a->channels; - if (b->channels < r->channels) - r->channels = b->channels; - - r->i_buf = r->o_buf = NULL; - r->i_alloc = r->o_alloc = 0; - - r->src_state = src_new(resample_method, r->channels, &err); - if (err != 0 || !r->src_state) - goto fail; + r->impl_free = NULL; + r->impl_set_input_rate = NULL; + r->impl_run = NULL; + /* Fill sample specs */ r->i_ss = *a; r->o_ss = *b; - r->i_sz = pa_frame_size(a); - r->o_sz = pa_frame_size(b); - - r->to_float32_func = pa_get_convert_to_float32_function(a->format); - r->from_float32_func = pa_get_convert_from_float32_function(b->format); - - assert(r->to_float32_func && r->from_float32_func); + r->i_fz = pa_frame_size(a); + r->o_fz = pa_frame_size(b); - r->memblock_stat = s; + r->channels = a->channels; + if (b->channels < r->channels) + r->channels = b->channels; + + /* Choose implementation */ + if (a->channels != b->channels || a->format != b->format || resample_method != PA_RESAMPLER_TRIVIAL) { + /* Use the libsamplerate based resampler for the complicated cases */ + if (resample_method == PA_RESAMPLER_TRIVIAL) + r->resample_method = PA_RESAMPLER_SRC_ZERO_ORDER_HOLD; + + if (libsamplerate_init(r) < 0) + goto fail; + + } else { + /* Use our own simple non-fp resampler for the trivial cases and when the user selects it */ + if (trivial_init(r) < 0) + goto fail; + } return r; @@ -95,32 +115,86 @@ fail: void pa_resampler_free(struct pa_resampler *r) { assert(r); - if (r->src_state) - src_delete(r->src_state); - pa_xfree(r->i_buf); - pa_xfree(r->o_buf); + + if (r->impl_free) + r->impl_free(r); + pa_xfree(r); } +void pa_resampler_set_input_rate(struct pa_resampler *r, uint32_t rate) { + assert(r && rate); + + r->i_ss.rate = rate; + if (r->impl_set_input_rate) + r->impl_set_input_rate(r, rate); +} + +void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out) { + assert(r && in && out && r->impl_run); + + r->impl_run(r, in, out); +} + size_t pa_resampler_request(struct pa_resampler *r, size_t out_length) { - assert(r && (out_length % r->o_sz) == 0); - - return (((out_length / r->o_sz)*r->i_ss.rate)/r->o_ss.rate) * r->i_sz; + assert(r && (out_length % r->o_fz) == 0); + return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz; +} + +enum pa_resample_method pa_resampler_get_method(struct pa_resampler *r) { + assert(r); + return r->resample_method; +} + +/* Parse a libsamplrate compatible resampling implementation */ +enum pa_resample_method pa_parse_resample_method(const char *string) { + assert(string); + + if (!strcmp(string, "src-sinc-best-quality")) + return PA_RESAMPLER_SRC_SINC_BEST_QUALITY; + else if (!strcmp(string, "src-sinc-medium-quality")) + return PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY; + else if (!strcmp(string, "src-sinc-fastest")) + return PA_RESAMPLER_SRC_SINC_FASTEST; + else if (!strcmp(string, "src-zero-order-hold")) + return PA_RESAMPLER_SRC_ZERO_ORDER_HOLD; + else if (!strcmp(string, "src-linear")) + return PA_RESAMPLER_SRC_LINEAR; + else if (!strcmp(string, "trivial")) + return PA_RESAMPLER_TRIVIAL; + else + return PA_RESAMPLER_INVALID; } +/*** libsamplerate based implementation ***/ -void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out) { +static void libsamplerate_free(struct pa_resampler *r) { + struct impl_libsamplerate *i; + assert(r && r->impl_data); + i = r->impl_data; + + if (i->src_state) + src_delete(i->src_state); + + pa_xfree(i->i_buf); + pa_xfree(i->o_buf); + pa_xfree(i); +} + +static void libsamplerate_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out) { unsigned i_nchannels, o_nchannels, ins, ons, eff_ins, eff_ons; float *cbuf; - assert(r && in && out && in->length && in->memblock && (in->length % r->i_sz) == 0); + struct impl_libsamplerate *i; + assert(r && in && out && in->length && in->memblock && (in->length % r->i_fz) == 0 && r->impl_data); + i = r->impl_data; /* How many input samples? */ - ins = in->length/r->i_sz; + ins = in->length/r->i_fz; -/* pa_log("%u / %u = %u\n", in->length, r->i_sz, ins); */ +/* pa_log("%u / %u = %u\n", in->length, r->i_fz, ins); */ /* How much space for output samples? */ - if (r->src_state) + if (i->src_state) ons = (ins*r->o_ss.rate/r->i_ss.rate)+1024; else ons = ins; @@ -140,40 +214,40 @@ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, stru /* pa_log("eff_ins = %u \n", eff_ins); */ - out->memblock = pa_memblock_new(out->length = (ons*r->o_sz), r->memblock_stat); + out->memblock = pa_memblock_new(out->length = (ons*r->o_fz), r->memblock_stat); out->index = 0; assert(out->memblock); - if (r->i_alloc < eff_ins) - r->i_buf = pa_xrealloc(r->i_buf, sizeof(float) * (r->i_alloc = eff_ins)); - assert(r->i_buf); + if (i->i_alloc < eff_ins) + i->i_buf = pa_xrealloc(i->i_buf, sizeof(float) * (i->i_alloc = eff_ins)); + assert(i->i_buf); /* pa_log("eff_ins = %u \n", eff_ins); */ - r->to_float32_func(eff_ins, (uint8_t*) in->memblock->data+in->index, i_nchannels, r->i_buf); + i->to_float32ne_func(eff_ins, (uint8_t*) in->memblock->data+in->index, i_nchannels, i->i_buf); - if (r->src_state) { + if (i->src_state) { int ret; SRC_DATA data; - if (r->o_alloc < eff_ons) - r->o_buf = pa_xrealloc(r->o_buf, sizeof(float) * (r->o_alloc = eff_ons)); - assert(r->o_buf); + if (i->o_alloc < eff_ons) + i->o_buf = pa_xrealloc(i->o_buf, sizeof(float) * (i->o_alloc = eff_ons)); + assert(i->o_buf); - data.data_in = r->i_buf; + data.data_in = i->i_buf; data.input_frames = ins; - data.data_out = r->o_buf; + data.data_out = i->o_buf; data.output_frames = ons; data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate; data.end_of_input = 0; - ret = src_process(r->src_state, &data); + ret = src_process(i->src_state, &data); assert(ret == 0); assert((unsigned) data.input_frames_used == ins); - cbuf = r->o_buf; + cbuf = i->o_buf; ons = data.output_frames_gen; if (r->i_ss.channels == r->o_ss.channels) @@ -181,12 +255,11 @@ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, stru else eff_ons = ons; } else - cbuf = r->i_buf; + cbuf = i->i_buf; if (eff_ons) - r->from_float32_func(eff_ons, cbuf, (uint8_t*)out->memblock->data+out->index, o_nchannels); - out->length = ons*r->o_sz; - + i->from_float32ne_func(eff_ons, cbuf, (uint8_t*)out->memblock->data+out->index, o_nchannels); + out->length = ons*r->o_fz; if (!out->length) { pa_memblock_unref(out->memblock); @@ -194,11 +267,147 @@ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, stru } } -void pa_resampler_set_input_rate(struct pa_resampler *r, uint32_t rate) { +static void libsamplerate_set_input_rate(struct pa_resampler *r, uint32_t rate) { int ret; - assert(r); + struct impl_libsamplerate *i; + assert(r && rate > 0 && r->impl_data); + i = r->impl_data; - r->i_ss.rate = rate; - ret = src_set_ratio(r->src_state, (double) r->o_ss.rate / r->i_ss.rate); + ret = src_set_ratio(i->src_state, (double) r->o_ss.rate / r->i_ss.rate); assert(ret == 0); } + +static int libsamplerate_init(struct pa_resampler *r) { + struct impl_libsamplerate *i = NULL; + int err; + + r->impl_data = i = pa_xmalloc(sizeof(struct impl_libsamplerate)); + + i->to_float32ne_func = pa_get_convert_to_float32ne_function(r->i_ss.format); + i->from_float32ne_func = pa_get_convert_from_float32ne_function(r->o_ss.format); + + if (!i->to_float32ne_func || !i->from_float32ne_func) + goto fail; + + if (!(i->src_state = src_new(r->resample_method, r->channels, &err)) || !i->src_state) + goto fail; + + i->i_buf = i->o_buf = NULL; + i->i_alloc = i->o_alloc = 0; + + r->impl_free = libsamplerate_free; + r->impl_set_input_rate = libsamplerate_set_input_rate; + r->impl_run = libsamplerate_run; + + return 0; + +fail: + pa_xfree(i); + return -1; +} + +/* Trivial implementation */ + +static void trivial_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out) { + size_t fz; + unsigned nsamples; + struct impl_trivial *i; + assert(r && in && out && r->impl_data); + i = r->impl_data; + + fz = r->i_fz; + assert(fz == r->o_fz); + + nsamples = in->length/fz; + + if (r->i_ss.rate == r->o_ss.rate) { + + /* In case there's no diefference in sample types, do nothing */ + *out = *in; + pa_memblock_ref(in->memblock); + + i->o_counter += nsamples; + } else { + /* Do real resampling */ + size_t l; + unsigned o_index; + + /* The length of the new memory block rounded up */ + l = ((nsamples * r->o_ss.rate + r->i_ss.rate - 1) / r->i_ss.rate) * fz; + + out->index = 0; + out->memblock = pa_memblock_new(l, r->memblock_stat); + + for (o_index = 0;; o_index++, i->o_counter++) { + unsigned j; + + j = (i->o_counter * r->i_ss.rate / r->o_ss.rate); + assert(j >= i->i_counter); + j = j - i->i_counter; + + if (j >= nsamples) + break; + + assert(o_index*fz < out->memblock->length); + + memcpy((uint8_t*) out->memblock->data + fz*o_index, + (uint8_t*) in->memblock->data + fz*j, fz); + + } + + out->length = o_index*fz; + } + + /* Normalize the output counter */ + while (i->o_counter >= r->o_ss.rate) + i->o_counter -= r->o_ss.rate; + + i->i_counter += nsamples; + + while (i->i_counter >= r->i_ss.rate) + i->i_counter -= r->i_ss.rate; +} + +static void trivial_free(struct pa_resampler *r) { + assert(r); + pa_xfree(r->impl_data); +} + +static void trivial_set_input_rate(struct pa_resampler *r, uint32_t rate) { + struct impl_trivial *i; + assert(r && rate > 0 && r->impl_data); + i = r->impl_data; + + i->i_counter = 0; + i->o_counter = 0; +} + +static int trivial_init(struct pa_resampler*r) { + struct impl_trivial *i; + assert(r && r->i_ss.format == r->o_ss.format && r->i_ss.channels == r->o_ss.channels); + + r->impl_data = i = pa_xmalloc(sizeof(struct impl_trivial)); + i->o_counter = i->i_counter = 0; + + r->impl_run = trivial_run; + r->impl_free = trivial_free; + r->impl_set_input_rate = trivial_set_input_rate; + + return 0; +} + +const char *pa_resample_method_to_string(enum pa_resample_method m) { + static const char const* resample_methods[] = { + "src-sinc-best-quality", + "src-sinc-medium-quality", + "src-sinc-fastest", + "src-zero-order-hold", + "src-linear", + "trivial" + }; + + if (m < 0 || m >= PA_RESAMPLER_MAX) + return NULL; + + return resample_methods[m]; +} diff --git a/polyp/resampler.h b/polyp/resampler.h index 08fad809..0109e790 100644 --- a/polyp/resampler.h +++ b/polyp/resampler.h @@ -22,18 +22,44 @@ USA. ***/ +#include + #include "sample.h" #include "memblock.h" #include "memchunk.h" struct pa_resampler; +enum pa_resample_method { + PA_RESAMPLER_INVALID = -1, + PA_RESAMPLER_SRC_SINC_BEST_QUALITY = SRC_SINC_BEST_QUALITY, + PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY = SRC_SINC_MEDIUM_QUALITY, + PA_RESAMPLER_SRC_SINC_FASTEST = SRC_SINC_FASTEST, + PA_RESAMPLER_SRC_ZERO_ORDER_HOLD = SRC_ZERO_ORDER_HOLD, + PA_RESAMPLER_SRC_LINEAR = SRC_LINEAR, + PA_RESAMPLER_TRIVIAL, + PA_RESAMPLER_MAX +}; + struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b, struct pa_memblock_stat *s, int resample_method); void pa_resampler_free(struct pa_resampler *r); +/* Returns the size of an input memory block which is required to return the specified amount of output data */ size_t pa_resampler_request(struct pa_resampler *r, size_t out_length); + +/* Pass the specified memory chunk to the resampler and return the newly resampled data */ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out); +/* Change the input rate of the resampler object */ void pa_resampler_set_input_rate(struct pa_resampler *r, uint32_t rate); +/* Return the resampling method of the resampler object */ +enum pa_resample_method pa_resampler_get_method(struct pa_resampler *r); + +/* Try to parse the resampler method */ +enum pa_resample_method pa_parse_resample_method(const char *string); + +/* return a human readable string for the specified resampling method. Inverse of pa_parse_resample_method() */ +const char *pa_resample_method_to_string(enum pa_resample_method m); + #endif diff --git a/polyp/sample-util.c b/polyp/sample-util.c index 0d4d18d3..d521afe4 100644 --- a/polyp/sample-util.c +++ b/polyp/sample-util.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "sample-util.h" @@ -41,12 +42,12 @@ void pa_silence_memchunk(struct pa_memchunk *c, const struct pa_sample_spec *spe } void pa_silence_memory(void *p, size_t length, const struct pa_sample_spec *spec) { - char c = 0; + uint8_t c = 0; assert(p && length && spec); switch (spec->format) { case PA_SAMPLE_U8: - c = 127; + c = 0x80; break; case PA_SAMPLE_S16LE: case PA_SAMPLE_S16BE: @@ -65,54 +66,145 @@ void pa_silence_memory(void *p, size_t length, const struct pa_sample_spec *spec } size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const struct pa_sample_spec *spec, pa_volume_t volume) { - unsigned c, d; assert(channels && data && length && spec); - assert(spec->format == PA_SAMPLE_S16NE); - - for (d = 0;; d += sizeof(int16_t)) { - int32_t sum = 0; - - if (d >= length) - return d; + + if (spec->format == PA_SAMPLE_S16NE) { + size_t d; - for (c = 0; c < nchannels; c++) { - int32_t v; - uint32_t volume = channels[c].volume; + for (d = 0;; d += sizeof(int16_t)) { + unsigned c; + int32_t sum = 0; - if (d >= channels[c].chunk.length) + if (d >= length) return d; - + + for (c = 0; c < nchannels; c++) { + int32_t v; + pa_volume_t cvolume = channels[c].volume; + + if (d >= channels[c].chunk.length) + return d; + + if (cvolume == PA_VOLUME_MUTED) + v = 0; + else { + v = *((int16_t*) ((uint8_t*) channels[c].chunk.memblock->data + channels[c].chunk.index + d)); + + if (cvolume != PA_VOLUME_NORM) { + v *= cvolume; + v /= PA_VOLUME_NORM; + } + } + + sum += v; + } + if (volume == PA_VOLUME_MUTED) - v = 0; - else { - v = *((int16_t*) ((uint8_t*) channels[c].chunk.memblock->data + channels[c].chunk.index + d)); - - if (volume != PA_VOLUME_NORM) - v = (int32_t) ((float)v*volume/PA_VOLUME_NORM); + sum = 0; + else if (volume != PA_VOLUME_NORM) { + sum *= volume; + sum /= PA_VOLUME_NORM; } - - sum += v; + + if (sum < -0x8000) sum = -0x8000; + if (sum > 0x7FFF) sum = 0x7FFF; + + *((int16_t*) data) = sum; + data = (uint8_t*) data + sizeof(int16_t); + } + } else if (spec->format == PA_SAMPLE_U8) { + size_t d; + + for (d = 0;; d ++) { + int32_t sum = 0; + unsigned c; + + if (d >= length) + return d; + + for (c = 0; c < nchannels; c++) { + int32_t v; + pa_volume_t cvolume = channels[c].volume; + + if (d >= channels[c].chunk.length) + return d; + + if (cvolume == PA_VOLUME_MUTED) + v = 0; + else { + v = (int32_t) *((uint8_t*) channels[c].chunk.memblock->data + channels[c].chunk.index + d) - 0x80; + + if (cvolume != PA_VOLUME_NORM) { + v *= cvolume; + v /= PA_VOLUME_NORM; + } + } + + sum += v; + } + + if (volume == PA_VOLUME_MUTED) + sum = 0; + else if (volume != PA_VOLUME_NORM) { + sum *= volume; + sum /= PA_VOLUME_NORM; + } + + if (sum < -0x80) sum = -0x80; + if (sum > 0x7F) sum = 0x7F; + + *((uint8_t*) data) = (uint8_t) (sum + 0x80); + data = (uint8_t*) data + 1; } - - if (volume == PA_VOLUME_MUTED) - sum = 0; - else if (volume != PA_VOLUME_NORM) - sum = (int32_t) ((float) sum*volume/PA_VOLUME_NORM); - if (sum < -0x8000) sum = -0x8000; - if (sum > 0x7FFF) sum = 0x7FFF; + } else if (spec->format == PA_SAMPLE_FLOAT32NE) { + size_t d; - *((int16_t*) data) = sum; - data = (uint8_t*) data + sizeof(int16_t); + for (d = 0;; d += sizeof(float)) { + float_t sum = 0; + unsigned c; + + if (d >= length) + return d; + + for (c = 0; c < nchannels; c++) { + float v; + pa_volume_t cvolume = channels[c].volume; + + if (d >= channels[c].chunk.length) + return d; + + if (cvolume == PA_VOLUME_MUTED) + v = 0; + else { + v = *((float*) ((uint8_t*) channels[c].chunk.memblock->data + channels[c].chunk.index + d)); + + if (cvolume != PA_VOLUME_NORM) + v = v*cvolume/PA_VOLUME_NORM; + } + + sum += v; + } + + if (volume == PA_VOLUME_MUTED) + sum = 0; + else if (volume != PA_VOLUME_NORM) + sum = sum*volume/PA_VOLUME_NORM; + + if (sum < -1) sum = -1; + if (sum > 1) sum = 1; + + *((float*) data) = sum; + data = (uint8_t*) data + sizeof(float); + } + } else { + abort(); } } void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, pa_volume_t volume) { - int16_t *d; - size_t n; assert(c && spec && (c->length % pa_frame_size(spec) == 0)); - assert(spec->format == PA_SAMPLE_S16NE); if (volume == PA_VOLUME_NORM) return; @@ -122,16 +214,55 @@ void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, return; } - for (d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { - int32_t t = (int32_t)(*d); + if (spec->format == PA_SAMPLE_S16NE) { + int16_t *d; + size_t n; + + for (d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { + int32_t t = (int32_t)(*d); + + t *= volume; + t /= PA_VOLUME_NORM; + + if (t < -0x8000) t = -0x8000; + if (t > 0x7FFF) t = 0x7FFF; + + *d = (int16_t) t; + } + } else if (spec->format == PA_SAMPLE_U8) { + uint8_t *d; + size_t n; - t *= volume; - t /= PA_VOLUME_NORM; + for (d = (uint8_t*) c->memblock->data + c->index, n = c->length; n > 0; d++, n--) { + int32_t t = (int32_t) *d - 0x80; - if (t < -0x8000) t = -0x8000; - if (t > 0x7FFF) t = 0x7FFF; + t *= volume; + t /= PA_VOLUME_NORM; + + if (t < -0x80) t = -0x80; + if (t > 0x7F) t = 0x7F; + + *d = (uint8_t) (t + 0x80); + + } + } else if (spec->format == PA_SAMPLE_FLOAT32NE) { + float *d; + size_t n; + + for (d = (float*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(float); n > 0; d++, n--) { + float t = *d; + + t *= volume; + t /= PA_VOLUME_NORM; + + if (t < -1) t = -1; + if (t > 1) t = 1; + + *d = t; + } - *d = (int16_t) t; + } else { + abort(); } } diff --git a/polyp/sconv-s16be.c b/polyp/sconv-s16be.c index 0ee772c8..54efc78c 100644 --- a/polyp/sconv-s16be.c +++ b/polyp/sconv-s16be.c @@ -28,7 +28,7 @@ #define INT16_FROM INT16_FROM_BE #define INT16_TO INT16_TO_BE -#define pa_sconv_s16le_to_float32 pa_sconv_s16be_to_float32 -#define pa_sconv_s16le_from_float32 pa_sconv_s16be_from_float32 +#define pa_sconv_s16le_to_float32ne pa_sconv_s16be_to_float32ne +#define pa_sconv_s16le_from_float32ne pa_sconv_s16be_from_float32ne #include "sconv-s16le.c" diff --git a/polyp/sconv-s16be.h b/polyp/sconv-s16be.h index c1876dd0..86107fb5 100644 --- a/polyp/sconv-s16be.h +++ b/polyp/sconv-s16be.h @@ -22,7 +22,7 @@ USA. ***/ -void pa_sconv_s16be_to_float32(unsigned n, const void *a, unsigned an, float *b); -void pa_sconv_s16be_from_float32(unsigned n, const float *a, void *b, unsigned bn); +void pa_sconv_s16be_to_float32ne(unsigned n, const void *a, unsigned an, float *b); +void pa_sconv_s16be_from_float32ne(unsigned n, const float *a, void *b, unsigned bn); #endif diff --git a/polyp/sconv-s16le.c b/polyp/sconv-s16le.c index 2fbcbf31..49c47461 100644 --- a/polyp/sconv-s16le.c +++ b/polyp/sconv-s16le.c @@ -38,7 +38,7 @@ #define INT16_TO INT16_TO_LE #endif -void pa_sconv_s16le_to_float32(unsigned n, const void *a, unsigned an, float *b) { +void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, unsigned an, float *b) { const int16_t *ca = a; assert(n && a && an && b); @@ -60,7 +60,7 @@ void pa_sconv_s16le_to_float32(unsigned n, const void *a, unsigned an, float *b) } } -void pa_sconv_s16le_from_float32(unsigned n, const float *a, void *b, unsigned bn) { +void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b, unsigned bn) { int16_t *cb = b; /* pa_log("%u %p %p %u\n", n, a, b, bn); */ diff --git a/polyp/sconv-s16le.h b/polyp/sconv-s16le.h index 8842140c..caed826e 100644 --- a/polyp/sconv-s16le.h +++ b/polyp/sconv-s16le.h @@ -22,7 +22,7 @@ USA. ***/ -void pa_sconv_s16le_to_float32(unsigned n, const void *a, unsigned an, float *b); -void pa_sconv_s16le_from_float32(unsigned n, const float *a, void *b, unsigned bn); +void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, unsigned an, float *b); +void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b, unsigned bn); #endif diff --git a/polyp/sconv.c b/polyp/sconv.c index bd670586..a404f432 100644 --- a/polyp/sconv.c +++ b/polyp/sconv.c @@ -28,11 +28,12 @@ #include #include "endianmacros.h" #include "sconv.h" +#include "g711.h" #include "sconv-s16le.h" #include "sconv-s16be.h" -static void u8_to_float32(unsigned n, const void *a, unsigned an, float *b) { +static void u8_to_float32ne(unsigned n, const void *a, unsigned an, float *b) { unsigned i; const uint8_t *ca = a; assert(n && a && an && b); @@ -42,7 +43,7 @@ static void u8_to_float32(unsigned n, const void *a, unsigned an, float *b) { for (i = 0; i < an; i++) { uint8_t v = *(ca++); - sum += (((float) v)-127)/127; + sum += (((float) v)-128)/127; } if (sum > 1) @@ -54,7 +55,7 @@ static void u8_to_float32(unsigned n, const void *a, unsigned an, float *b) { } } -static void u8_from_float32(unsigned n, const float *a, void *b, unsigned bn) { +static void u8_from_float32ne(unsigned n, const float *a, void *b, unsigned bn) { unsigned i; uint8_t *cb = b; @@ -69,14 +70,14 @@ static void u8_from_float32(unsigned n, const float *a, void *b, unsigned bn) { if (v < -1) v = -1; - u = (uint8_t) (v*127+127); + u = (uint8_t) (v*127+128); for (i = 0; i < bn; i++) *(cb++) = u; } } -static void float32_to_float32(unsigned n, const void *a, unsigned an, float *b) { +static void float32ne_to_float32ne(unsigned n, const void *a, unsigned an, float *b) { unsigned i; const float *ca = a; assert(n && a && an && b); @@ -95,7 +96,7 @@ static void float32_to_float32(unsigned n, const void *a, unsigned an, float *b) } } -static void float32_from_float32(unsigned n, const float *a, void *b, unsigned bn) { +static void float32ne_from_float32ne(unsigned n, const float *a, void *b, unsigned bn) { unsigned i; float *cb = b; assert(n && a && b && bn); @@ -106,31 +107,122 @@ static void float32_from_float32(unsigned n, const float *a, void *b, unsigned b } } -pa_convert_to_float32_func_t pa_get_convert_to_float32_function(enum pa_sample_format f) { +static void ulaw_to_float32ne(unsigned n, const void *a, unsigned an, float *b) { + unsigned i; + const uint8_t *ca = a; + assert(n && a && an && b); + for (; n > 0; n--) { + float sum = 0; + + for (i = 0; i < an; i++) + sum += (float) st_ulaw2linear16(*ca++) / 0x7FFF; + + if (sum > 1) + sum = 1; + if (sum < -1) + sum = -1; + + *(b++) = sum; + } +} + +static void ulaw_from_float32ne(unsigned n, const float *a, void *b, unsigned bn) { + unsigned i; + uint8_t *cb = b; + + assert(n && a && b && bn); + for (; n > 0; n--) { + float v = *(a++); + uint8_t u; + + if (v > 1) + v = 1; + + if (v < -1) + v = -1; + + u = st_14linear2ulaw((int16_t) (v * 0x1FFF)); + + for (i = 0; i < bn; i++) + *(cb++) = u; + } +} + +static void alaw_to_float32ne(unsigned n, const void *a, unsigned an, float *b) { + unsigned i; + const uint8_t *ca = a; + assert(n && a && an && b); + for (; n > 0; n--) { + float sum = 0; + + for (i = 0; i < an; i++) + sum += (float) st_alaw2linear16(*ca++) / 0x7FFF; + + if (sum > 1) + sum = 1; + if (sum < -1) + sum = -1; + + *(b++) = sum; + } +} + +static void alaw_from_float32ne(unsigned n, const float *a, void *b, unsigned bn) { + unsigned i; + uint8_t *cb = b; + + assert(n && a && b && bn); + for (; n > 0; n--) { + float v = *(a++); + uint8_t u; + + if (v > 1) + v = 1; + + if (v < -1) + v = -1; + + u = st_13linear2alaw((int16_t) (v * 0xFFF)); + + for (i = 0; i < bn; i++) + *(cb++) = u; + } +} + + +pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(enum pa_sample_format f) { switch(f) { case PA_SAMPLE_U8: - return u8_to_float32; + return u8_to_float32ne; case PA_SAMPLE_S16LE: - return pa_sconv_s16le_to_float32; + return pa_sconv_s16le_to_float32ne; case PA_SAMPLE_S16BE: - return pa_sconv_s16be_to_float32; - case PA_SAMPLE_FLOAT32: - return float32_to_float32; + return pa_sconv_s16be_to_float32ne; + case PA_SAMPLE_FLOAT32NE: + return float32ne_to_float32ne; + case PA_SAMPLE_ALAW: + return alaw_to_float32ne; + case PA_SAMPLE_ULAW: + return ulaw_to_float32ne; default: return NULL; } } -pa_convert_from_float32_func_t pa_get_convert_from_float32_function(enum pa_sample_format f) { +pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(enum pa_sample_format f) { switch(f) { case PA_SAMPLE_U8: - return u8_from_float32; + return u8_from_float32ne; case PA_SAMPLE_S16LE: - return pa_sconv_s16le_from_float32; + return pa_sconv_s16le_from_float32ne; case PA_SAMPLE_S16BE: - return pa_sconv_s16be_from_float32; - case PA_SAMPLE_FLOAT32: - return float32_from_float32; + return pa_sconv_s16be_from_float32ne; + case PA_SAMPLE_FLOAT32NE: + return float32ne_from_float32ne; + case PA_SAMPLE_ALAW: + return alaw_from_float32ne; + case PA_SAMPLE_ULAW: + return ulaw_from_float32ne; default: return NULL; } diff --git a/polyp/sconv.h b/polyp/sconv.h index 0a12890a..71517ec2 100644 --- a/polyp/sconv.h +++ b/polyp/sconv.h @@ -24,10 +24,10 @@ #include "sample.h" -typedef void (*pa_convert_to_float32_func_t)(unsigned n, const void *a, unsigned an, float *b); -typedef void (*pa_convert_from_float32_func_t)(unsigned n, const float *a, void *b, unsigned bn); +typedef void (*pa_convert_to_float32ne_func_t)(unsigned n, const void *a, unsigned an, float *b); +typedef void (*pa_convert_from_float32ne_func_t)(unsigned n, const float *a, void *b, unsigned bn); -pa_convert_to_float32_func_t pa_get_convert_to_float32_function(enum pa_sample_format f); -pa_convert_from_float32_func_t pa_get_convert_from_float32_function(enum pa_sample_format f); +pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(enum pa_sample_format f); +pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(enum pa_sample_format f); #endif diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 23b4a136..e66278ed 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -48,7 +48,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con return NULL; } - if (resample_method < 0) + if (resample_method == PA_RESAMPLER_INVALID) resample_method = s->core->resample_method; if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec)) @@ -272,3 +272,12 @@ void pa_sink_input_set_name(struct pa_sink_input *i, const char *name) { pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); } + +enum pa_resample_method pa_sink_input_get_resample_method(struct pa_sink_input *i) { + assert(i && i->ref >= 1); + + if (!i->resampler) + return PA_RESAMPLER_INVALID; + + return pa_resampler_get_method(i->resampler); +} diff --git a/polyp/sink-input.h b/polyp/sink-input.h index 1c16a9e6..5482369d 100644 --- a/polyp/sink-input.h +++ b/polyp/sink-input.h @@ -87,4 +87,6 @@ void pa_sink_input_set_rate(struct pa_sink_input *i, uint32_t rate); void pa_sink_input_set_name(struct pa_sink_input *i, const char *name); +enum pa_resample_method pa_sink_input_get_resample_method(struct pa_sink_input *i); + #endif diff --git a/polyp/source-output.c b/polyp/source-output.c index e339d4ac..fb06ff8f 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -44,7 +44,7 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n return NULL; } - if (resample_method < 0) + if (resample_method == PA_RESAMPLER_INVALID) resample_method = s->core->resample_method; if (!pa_sample_spec_equal(&s->sample_spec, spec)) @@ -175,3 +175,12 @@ void pa_source_output_cork(struct pa_source_output *o, int b) { o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; } + +enum pa_resample_method pa_source_output_get_resample_method(struct pa_source_output *o) { + assert(o && o->ref >= 1); + + if (!o->resampler) + return PA_RESAMPLER_INVALID; + + return pa_resampler_get_method(o->resampler); +} diff --git a/polyp/source-output.h b/polyp/source-output.h index 595c0870..0247a09a 100644 --- a/polyp/source-output.h +++ b/polyp/source-output.h @@ -76,5 +76,6 @@ pa_usec_t pa_source_output_get_latency(struct pa_source_output *i); void pa_source_output_cork(struct pa_source_output *i, int b); +enum pa_resample_method pa_source_output_get_resample_method(struct pa_source_output *o); #endif diff --git a/polyp/util.c b/polyp/util.c index e8a47df0..23515f03 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -530,23 +530,6 @@ const char *pa_strsignal(int sig) { } } -/* Parse a libsamplrate compatible resampling implementation */ -int pa_parse_resample_method(const char *string) { - assert(string); - - if (!strcmp(string, "sinc-best-quality")) - return SRC_SINC_BEST_QUALITY; - else if (!strcmp(string, "sinc-medium-quality")) - return SRC_SINC_MEDIUM_QUALITY; - else if (!strcmp(string, "sinc-fastest")) - return SRC_SINC_FASTEST; - else if (!strcmp(string, "zero-order-hold")) - return SRC_ZERO_ORDER_HOLD; - else if (!strcmp(string, "linear")) - return SRC_LINEAR; - else - return -1; -} /* Check whether the specified GID and the group name match */ static int is_group(gid_t gid, const char *name) { diff --git a/polyp/util.h b/polyp/util.h index f38e6739..f86c30cc 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -72,8 +72,6 @@ char *pa_strip_nl(char *s); const char *pa_strsignal(int sig); -int pa_parse_resample_method(const char *string); - int pa_uid_in_group(const char *name, gid_t *gid); int pa_lock_fd(int fd, int b); -- cgit From acc8b7890a0b3878b226f56454eeffc80843fdee Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 20 Nov 2004 22:17:31 +0000 Subject: option to use ALSA default fragment number and size git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@295 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 9 ++++----- polyp/alsa-util.c | 35 +++++++++++++++++++++++++++-------- polyp/alsa-util.h | 2 +- polyp/module-alsa-sink.c | 10 +++++----- polyp/module-alsa-source.c | 8 ++++---- 5 files changed, 41 insertions(+), 23 deletions(-) diff --git a/doc/todo b/doc/todo index 9898bc9d..c5f7dbba 100644 --- a/doc/todo +++ b/doc/todo @@ -1,17 +1,16 @@ *** $Id$ *** *** 0.7 **** -- per-channel volume -- option to use default fragment size on alsa drivers -- improve module-oss-mmap latency measurement -- add radio module - make most buffer sizes dependant on the sample type - limit all resources - commenting -- module-tunnel: use latency interpolation - polish for starting polypaudio as root/system-wide instance ** later *** +- per-channel volume +- improve module-oss-mmap latency measurement +- module-tunnel: improve latency calculation +- add radio module - pass meta info for hearing impaired - add sync API - X11: support for the X11 synchronization extension diff --git a/polyp/alsa-util.c b/polyp/alsa-util.c index 188ba077..eaa21d49 100644 --- a/polyp/alsa-util.c +++ b/polyp/alsa-util.c @@ -30,8 +30,9 @@ #include "sample.h" #include "xmalloc.h" -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, struct pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *buffer_size) { - int ret = 0; +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, struct pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { + int ret = -1; + snd_pcm_uframes_t buffer_size; snd_pcm_hw_params_t *hwparams = NULL; static const snd_pcm_format_t format_trans[] = { [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8, @@ -42,21 +43,39 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, struct pa_sample_spec *ss, uint [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE, [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, }; - + assert(pcm_handle && ss && periods && period_size); + if (snd_pcm_hw_params_malloc(&hwparams) < 0 || snd_pcm_hw_params_any(pcm_handle, hwparams) < 0 || snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0 || snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format]) < 0 || snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &ss->rate, NULL) < 0 || snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels) < 0 || - snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, periods, NULL) < 0 || - snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, buffer_size) < 0 || - snd_pcm_hw_params(pcm_handle, hwparams) < 0) { - ret = -1; - } + (*periods > 0 && snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, periods, NULL) < 0) || + (*period_size > 0 && snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL) < 0) || + snd_pcm_hw_params(pcm_handle, hwparams) < 0) + goto finish; + + if (snd_pcm_prepare(pcm_handle) < 0) + goto finish; + if (snd_pcm_hw_params_current(pcm_handle, hwparams) < 0) + goto finish; + + if (snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size) < 0 || + snd_pcm_hw_params_get_period_size(hwparams, period_size, NULL) < 0) + goto finish; + + assert(buffer_size > 0 && *period_size > 0); + *periods = buffer_size / *period_size; + assert(*periods > 0); + + ret = 0; + +finish: if (hwparams) snd_pcm_hw_params_free(hwparams); + return ret; } diff --git a/polyp/alsa-util.h b/polyp/alsa-util.h index 8add361f..c058025f 100644 --- a/polyp/alsa-util.h +++ b/polyp/alsa-util.h @@ -27,7 +27,7 @@ #include "sample.h" #include "mainloop-api.h" -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, struct pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *buffer_size); +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, struct pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size); int pa_create_io_events(snd_pcm_t *pcm_handle, struct pa_mainloop_api *m, struct pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags events, void *userdata), void *userdata); void pa_free_io_events(struct pa_mainloop_api* m, struct pa_io_event **io_sources, unsigned n_io_sources); diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index a708329d..d7a1cb53 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -174,8 +174,8 @@ int pa__init(struct pa_core *c, struct pa_module*m) { struct userdata *u = NULL; const char *dev; struct pa_sample_spec ss; - unsigned periods, fragsize; - snd_pcm_uframes_t buffer_size; + uint32_t periods, fragsize; + snd_pcm_uframes_t period_size; size_t frame_size; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -196,7 +196,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { pa_log(__FILE__": failed to parse buffer metrics\n"); goto fail; } - buffer_size = fragsize/frame_size*periods; + period_size = fragsize; u = pa_xmalloc0(sizeof(struct userdata)); m->userdata = u; @@ -207,7 +207,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { goto fail; } - if (pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &buffer_size) < 0) { + if (pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size) < 0) { pa_log(__FILE__": Failed to set hardware parameters\n"); goto fail; } @@ -226,7 +226,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { } u->frame_size = frame_size; - u->fragment_size = buffer_size*u->frame_size/periods; + u->fragment_size = period_size; pa_log(__FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index ba09d319..56eb1455 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -166,7 +166,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { const char *dev; struct pa_sample_spec ss; unsigned periods, fragsize; - snd_pcm_uframes_t buffer_size; + snd_pcm_uframes_t period_size; size_t frame_size; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -187,7 +187,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { pa_log(__FILE__": failed to parse buffer metrics\n"); goto fail; } - buffer_size = fragsize/frame_size*periods; + period_size = fragsize; u = pa_xmalloc0(sizeof(struct userdata)); m->userdata = u; @@ -198,7 +198,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { goto fail; } - if (pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &buffer_size) < 0) { + if (pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size) < 0) { pa_log(__FILE__": Failed to set hardware parameters\n"); goto fail; } @@ -217,7 +217,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { } u->frame_size = frame_size; - u->fragment_size = buffer_size*u->frame_size/periods; + u->fragment_size = period_size; pa_log(__FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); -- cgit From 3c77c6e7d3f597400b3ae10dd1228aabf1ad6280 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 20 Nov 2004 23:48:18 +0000 Subject: * remove autospawn lock file usage * fix some compiler warnings * implement PID file support git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@296 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 3 +- polyp/cmdline.c | 33 +++++++- polyp/daemon-conf.c | 6 +- polyp/daemon-conf.h | 7 +- polyp/main.c | 45 +++++++++-- polyp/mainloop.c | 6 +- polyp/pid.c | 197 +++++++++++++++++++++++++++++++++++++++++++++++ polyp/pid.h | 30 ++++++++ polyp/polyplib-context.c | 5 +- polyp/util.c | 39 +++++++--- polyp/util.h | 2 +- 11 files changed, 342 insertions(+), 31 deletions(-) create mode 100644 polyp/pid.c create mode 100644 polyp/pid.h diff --git a/polyp/Makefile.am b/polyp/Makefile.am index dd7fb8b4..13ef893c 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -211,7 +211,8 @@ polypaudio_SOURCES = idxset.c idxset.h \ caps.h caps.c \ props.h props.c \ mcalign.c mcalign.h \ - g711.c g711.h + g711.c g711.h \ + pid.c pid.h polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) diff --git a/polyp/cmdline.c b/polyp/cmdline.c index 0c381f8c..cdf25638 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -52,7 +52,10 @@ enum { ARG_LOAD, ARG_FILE, ARG_DL_SEARCH_PATH, - ARG_RESAMPLE_METHOD + ARG_RESAMPLE_METHOD, + ARG_KILL, + ARG_USE_PID_FILE, + ARG_CHECK }; static struct option long_options[] = { @@ -73,6 +76,9 @@ static struct option long_options[] = { {"file", 1, 0, ARG_FILE}, {"dl-search-path", 1, 0, ARG_DL_SEARCH_PATH}, {"resample-method", 1, 0, ARG_RESAMPLE_METHOD}, + {"kill", 0, 0, ARG_KILL}, + {"use-pid-file", 2, 0, ARG_USE_PID_FILE}, + {"check", 0, 0, ARG_CHECK}, {NULL, 0, 0, 0} }; @@ -88,7 +94,9 @@ void pa_cmdline_help(const char *argv0) { " -h, --help Show this help\n" " --version Show version\n" " --dump-conf Dump default configuration\n" - " --dump-modules Dump list of available modules\n\n" + " --dump-modules Dump list of available modules\n" + " -k --kill Kill a running daemon\n" + " --check Check for a running daemon\n\n" " -D, --daemonize[=BOOL] Daemonize after startup\n" " --fail[=BOOL] Quit when startup fails\n" @@ -100,7 +108,8 @@ void pa_cmdline_help(const char *argv0) { " --scache-idle-time=SECS Unload autoloaded samples when idle and this time passed\n" " --log-target={auto,syslog,stderr} Specify the log target\n" " -p, --dl-search-path=PATH Set the search path for dynamic shared objects (plugins)\n" - " --resample-method=[METHOD] Use the specified resampling method\n\n" + " --resample-method=[METHOD] Use the specified resampling method\n" + " --use-pid-file[=BOOL] Create a PID file\n\n" " -L, --load=\"MODULE ARGUMENTS\" Load the specified plugin module with the specified argument\n" " -F, --file=FILENAME Run the specified script\n" @@ -119,7 +128,7 @@ int pa_cmdline_parse(struct pa_daemon_conf *conf, int argc, char *const argv [], if (conf->script_commands) pa_strbuf_puts(buf, conf->script_commands); - while ((c = getopt_long(argc, argv, "L:F:ChDnp:", long_options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "L:F:ChDnp:k", long_options, NULL)) != -1) { switch (c) { case ARG_HELP: case 'h': @@ -137,6 +146,15 @@ int pa_cmdline_parse(struct pa_daemon_conf *conf, int argc, char *const argv [], case ARG_DUMP_MODULES: conf->cmd = PA_CMD_DUMP_MODULES; break; + + case 'k': + case ARG_KILL: + conf->cmd = PA_CMD_KILL; + break; + + case ARG_CHECK: + conf->cmd = PA_CMD_CHECK; + break; case ARG_LOAD: case 'L': @@ -188,6 +206,13 @@ int pa_cmdline_parse(struct pa_daemon_conf *conf, int argc, char *const argv [], } break; + case ARG_USE_PID_FILE: + if ((conf->use_pid_file = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + pa_log(__FILE__": --use-pid-file expects boolean argument\n"); + goto fail; + } + break; + case 'p': case ARG_DL_SEARCH_PATH: pa_xfree(conf->dl_search_path); diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c index 191e8d81..9728019d 100644 --- a/polyp/daemon-conf.c +++ b/polyp/daemon-conf.c @@ -66,6 +66,7 @@ static const struct pa_daemon_conf default_conf = { .log_target = PA_LOG_SYSLOG, .resample_method = PA_RESAMPLER_SRC_SINC_FASTEST, .config_file = NULL, + .use_pid_file = 1 }; struct pa_daemon_conf* pa_daemon_conf_new(void) { @@ -159,6 +160,7 @@ int pa_daemon_conf_load(struct pa_daemon_conf *c, const char *filename) { { "default-script-file", pa_config_parse_string, NULL }, { "log-target", parse_log_target, NULL }, { "resample-method", parse_resample_method, NULL }, + { "use-pid-file", pa_config_parse_bool, NULL }, { NULL, NULL, NULL }, }; @@ -174,6 +176,7 @@ int pa_daemon_conf_load(struct pa_daemon_conf *c, const char *filename) { table[9].data = &c->default_script_file; table[10].data = c; table[11].data = c; + table[12].data = &c->use_pid_file; pa_xfree(c->config_file); c->config_file = NULL; @@ -228,9 +231,8 @@ char *pa_daemon_conf_dump(struct pa_daemon_conf *c) { pa_strbuf_printf(s, "dl-search-path = %s\n", c->dl_search_path ? c->dl_search_path : ""); pa_strbuf_printf(s, "default-script-file = %s\n", c->default_script_file); pa_strbuf_printf(s, "log-target = %s\n", c->auto_log_target ? "auto" : (c->log_target == PA_LOG_SYSLOG ? "syslog" : "stderr")); - - assert(c->resample_method <= 4 && c->resample_method >= 0); pa_strbuf_printf(s, "resample-method = %s\n", pa_resample_method_to_string(c->resample_method)); + pa_strbuf_printf(s, "use-pid-file = %i\n", c->use_pid_file); return pa_strbuf_tostring_free(s); } diff --git a/polyp/daemon-conf.h b/polyp/daemon-conf.h index 9c278485..8a574272 100644 --- a/polyp/daemon-conf.h +++ b/polyp/daemon-conf.h @@ -29,7 +29,9 @@ enum pa_daemon_conf_cmd { PA_CMD_HELP, PA_CMD_VERSION, PA_CMD_DUMP_CONF, - PA_CMD_DUMP_MODULES + PA_CMD_DUMP_MODULES, + PA_CMD_KILL, + PA_CMD_CHECK }; struct pa_daemon_conf { @@ -42,7 +44,8 @@ struct pa_daemon_conf { exit_idle_time, module_idle_time, scache_idle_time, - auto_log_target; + auto_log_target, + use_pid_file; char *script_commands, *dl_search_path, *default_script_file; enum pa_log_target log_target; int resample_method; diff --git a/polyp/main.c b/polyp/main.c index 941bf923..0ba28e5a 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef HAVE_LIBWRAP #include @@ -54,6 +55,7 @@ #include "dumpmodules.h" #include "caps.h" #include "cli-text.h" +#include "pid.h" #ifdef HAVE_LIBWRAP /* Only one instance of these variables */ @@ -122,8 +124,7 @@ static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, } } - - static void close_pipe(int p[2]) { +static void close_pipe(int p[2]) { if (p[0] != -1) close(p[0]); if (p[1] != -1) @@ -142,6 +143,7 @@ int main(int argc, char *argv[]) { int daemon_pipe[2] = { -1, -1 }; gid_t gid = (gid_t) -1; int suid_root; + int valid_pid_file = 0; pa_limit_caps(); @@ -209,6 +211,30 @@ int main(int argc, char *argv[]) { retval = 0; goto finish; + case PA_CMD_CHECK: { + pid_t pid; + + if (pa_pid_file_check_running(&pid) < 0) { + if (conf->verbose) + pa_log(__FILE__": daemon not running\n"); + } else { + if (conf->verbose) + pa_log(__FILE__": daemon running as PID %u\n", pid); + retval = 0; + } + + goto finish; + + } + case PA_CMD_KILL: + + if (pa_pid_file_kill(SIGINT, NULL) < 0) + pa_log(__FILE__": failed to kill daemon.\n"); + else + retval = 0; + + goto finish; + default: assert(conf->cmd == PA_CMD_DAEMON); } @@ -260,11 +286,16 @@ int main(int argc, char *argv[]) { close(0); close(1); } - - chdir("/"); - pa_log(__FILE__": sizeof(pa_usec_t) = %u\n", sizeof(pa_usec_t)); + chdir("/"); + if (conf->use_pid_file) { + if (pa_pid_file_create() < 0) + goto finish; + + valid_pid_file = 1; + } + mainloop = pa_mainloop_new(); assert(mainloop); @@ -303,6 +334,7 @@ int main(int argc, char *argv[]) { if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); } else { + retval = 0; if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); @@ -332,6 +364,9 @@ finish: if (conf) pa_daemon_conf_free(conf); + if (valid_pid_file) + pa_pid_file_remove(); + close_pipe(daemon_pipe); lt_dlexit(); diff --git a/polyp/mainloop.c b/polyp/mainloop.c index f56614ce..d530419e 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -614,7 +614,7 @@ void pa_mainloop_dump(struct pa_mainloop *m) { if (e->dead) continue; - pa_log(__FILE__": kind=io fd=%i events=%i callback=%p userdata=%p\n", e->fd, (int) e->events, e->callback, e->userdata); + pa_log(__FILE__": kind=io fd=%i events=%i callback=%p userdata=%p\n", e->fd, (int) e->events, (void*) e->callback, (void*) e->userdata); } } { @@ -624,7 +624,7 @@ void pa_mainloop_dump(struct pa_mainloop *m) { if (e->dead) continue; - pa_log(__FILE__": kind=defer enabled=%i callback=%p userdata=%p\n", e->enabled, e->callback, e->userdata); + pa_log(__FILE__": kind=defer enabled=%i callback=%p userdata=%p\n", e->enabled, (void*) e->callback, (void*) e->userdata); } } { @@ -634,7 +634,7 @@ void pa_mainloop_dump(struct pa_mainloop *m) { if (e->dead) continue; - pa_log(__FILE__": kind=time enabled=%i time=%u.%u callback=%p userdata=%p\n", e->enabled, e->timeval.tv_sec, e->timeval.tv_usec, e->callback, e->userdata); + pa_log(__FILE__": kind=time enabled=%i time=%lu.%lu callback=%p userdata=%p\n", e->enabled, (unsigned long) e->timeval.tv_sec, (unsigned long) e->timeval.tv_usec, (void*) e->callback, (void*) e->userdata); } } diff --git a/polyp/pid.c b/polyp/pid.c new file mode 100644 index 00000000..142c4f6d --- /dev/null +++ b/polyp/pid.c @@ -0,0 +1,197 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pid.h" +#include "util.h" +#include "log.h" + +static pid_t read_pid(const char *fn, int fd) { + ssize_t r; + char t[20], *e = NULL; + long int pid; + + assert(fn && fd >= 0); + + if ((r = pa_loop_read(fd, t, sizeof(t)-1)) < 0) { + pa_log(__FILE__": WARNING: failed to read PID file '%s': %s\n", fn, strerror(errno)); + return (pid_t) -1; + } + + if (r == 0) + return (pid_t) 0; + + t[r] = 0; + + if (!t[0] || (pid = strtol(t, &e, 0)) == 0 || (*e != 0 && *e != '\n')) { + pa_log(__FILE__": WARNING: failed to parse PID file '%s'\n", fn); + return (pid_t) -1; + } + + return (pid_t) pid; +} + +int pa_pid_file_create(void) { + int fd = -1, lock = -1; + int ret = -1; + char fn[PATH_MAX]; + char t[20]; + pid_t pid; + size_t l; + + pa_runtime_path("pid", fn, sizeof(fn)); + if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { + pa_log(__FILE__": WARNING: failed to open PID file '%s': %s\n", fn, strerror(errno)); + goto fail; + } + + lock = pa_lock_fd(fd, 1); + + if ((pid = read_pid(fn, fd)) == (pid_t) -1) + pa_log(__FILE__": corrupt PID file, overwriting.\n"); + else if (pid > 0) { + if (kill(pid, 0) >= 0 || errno != ESRCH) { + pa_log(__FILE__": valid PID file.\n"); + goto fail; + } + + pa_log(__FILE__": stale PID file, overwriting.\n"); + } + + lseek(fd, 0, SEEK_SET); + + snprintf(t, sizeof(t), "%lu", (unsigned long) getpid()); + l = strlen(t); + + if (pa_loop_write(fd, t, l) != (ssize_t) l) { + pa_log(__FILE__": failed to write PID file.\n"); + goto fail; + } + + ret = 0; + +fail: + if (fd >= 0) { + if (lock >= 0) + pa_lock_fd(fd, 0); + + close(fd); + } + + return ret; +} + +int pa_pid_file_remove(void) { + int fd = -1, lock = -1; + char fn[PATH_MAX]; + int ret = -1; + pid_t pid; + + pa_runtime_path("pid", fn, sizeof(fn)); + if ((fd = open(fn, O_RDWR)) < 0) { + pa_log(__FILE__": WARNING: failed to open PID file '%s': %s\n", fn, strerror(errno)); + goto fail; + } + + lock = pa_lock_fd(fd, 1); + + if ((pid = read_pid(fn, fd)) == (pid_t) -1) + goto fail; + + if (pid != getpid()) { + pa_log(__FILE__": WARNING: PID file '%s' not mine!\n", fn); + goto fail; + } + + if (ftruncate(fd, 0) < 0) { + pa_log(__FILE__": failed to truncate PID file '%s': %s\n", fn, strerror(errno)); + goto fail; + } + + if (unlink(fn) < 0) { + pa_log(__FILE__": failed to remove PID file '%s': %s\n", fn, strerror(errno)); + goto fail; + } + + ret = 0; + +fail: + + if (fd >= 0) { + if (lock >= 0) + pa_lock_fd(fd, 0); + + close(fd); + } + + return ret; +} + +int pa_pid_file_check_running(pid_t *pid) { + return pa_pid_file_kill(0, pid); +} + +int pa_pid_file_kill(int sig, pid_t *pid) { + int fd = -1, lock = -1; + char fn[PATH_MAX]; + int ret = -1; + pid_t _pid; + + if (!pid) + pid = &_pid; + + pa_runtime_path("pid", fn, sizeof(fn)); + if ((fd = open(fn, O_RDONLY)) < 0) + goto fail; + + lock = pa_lock_fd(fd, 1); + + if ((*pid = read_pid(fn, fd)) == (pid_t) -1) + goto fail; + + ret = kill(*pid, sig); + +fail: + + if (fd >= 0) { + if (lock >= 0) + pa_lock_fd(fd, 0); + + close(fd); + } + + return ret; + +} diff --git a/polyp/pid.h b/polyp/pid.h new file mode 100644 index 00000000..906ab6da --- /dev/null +++ b/polyp/pid.h @@ -0,0 +1,30 @@ +#ifndef foopidhfoo +#define foopidhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +int pa_pid_file_create(void); +int pa_pid_file_remove(void); +int pa_pid_file_check_running(pid_t *pid); +int pa_pid_file_kill(int sig, pid_t *pid); + +#endif diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 70429583..899a8176 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -67,7 +67,10 @@ static void unlock_autospawn_lock_file(struct pa_context *c) { assert(c); if (c->autospawn_lock_fd >= 0) { - pa_unlock_lockfile(c->autospawn_lock_fd); + char lf[PATH_MAX]; + pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); + + pa_unlock_lockfile(lf, c->autospawn_lock_fd); c->autospawn_lock_fd = -1; } } diff --git a/polyp/util.c b/polyp/util.c index 23515f03..2ad26c41 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -612,20 +612,27 @@ finish: /* Lock or unlock a file entirely. (advisory) */ int pa_lock_fd(int fd, int b) { - struct flock flock; + /* Try a R/W lock first */ + flock.l_type = b ? F_WRLCK : F_UNLCK; flock.l_whence = SEEK_SET; flock.l_start = 0; flock.l_len = 0; - if (fcntl(fd, F_SETLKW, &flock) < 0) { - pa_log(__FILE__": %slock failed: %s\n", !b ? "un" : "", strerror(errno)); - return -1; - } + if (fcntl(fd, F_SETLKW, &flock) >= 0) + return 0; - return 0; + /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */ + if (b && errno == EBADF) { + flock.l_type = F_RDLCK; + if (fcntl(fd, F_SETLKW, &flock) >= 0) + return 0; + } + + pa_log(__FILE__": %slock failed: %s\n", !b ? "un" : "", strerror(errno)); + return -1; } /* Remove trailing newlines from a string */ @@ -642,35 +649,43 @@ int pa_lock_lockfile(const char *fn) { assert(fn); if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { - pa_log(__FILE__": failed to create lock file '%s'\n", fn); + pa_log(__FILE__": failed to create lock file '%s': %s\n", fn, strerror(errno)); goto fail; } if (pa_lock_fd(fd, 1) < 0) + pa_log(__FILE__": failed to lock file '%s'.\n", fn); goto fail; return fd; fail: - if (fd >= 0) + if (fd >= 0) { + unlink(fn); close(fd); + } return -1; } /* Unlock a temporary lcok file */ -int pa_unlock_lockfile(int fd) { +int pa_unlock_lockfile(const char *fn, int fd) { int r = 0; - assert(fd >= 0); + assert(fn && fd >= 0); + if (unlink(fn) < 0) { + pa_log(__FILE__": WARNING: unable to remove lock file '%s': %s\n", fn, strerror(errno)); + r = -1; + } + if (pa_lock_fd(fd, 0) < 0) { - pa_log(__FILE__": WARNING: failed to unlock file.\n"); + pa_log(__FILE__": WARNING: failed to unlock file '%s'.\n", fn); r = -1; } if (close(fd) < 0) { - pa_log(__FILE__": WARNING: failed to close lock file.\n"); + pa_log(__FILE__": WARNING: failed to close lock file '%s': %s\n", fn, strerror(errno)); r = -1; } diff --git a/polyp/util.h b/polyp/util.h index f86c30cc..ef7e4d96 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -77,7 +77,7 @@ int pa_uid_in_group(const char *name, gid_t *gid); int pa_lock_fd(int fd, int b); int pa_lock_lockfile(const char *fn); -int pa_unlock_lockfile(int fd); +int pa_unlock_lockfile(const char *fn, int fd); FILE *pa_open_config_file(const char *env, const char *global, const char *local, char **result); -- cgit From 6985eda9347730d4506de630c310a34e7844df0a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Nov 2004 00:04:17 +0000 Subject: * some minor pid file fixes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@297 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/pid.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/polyp/pid.c b/polyp/pid.c index 142c4f6d..a52bed02 100644 --- a/polyp/pid.c +++ b/polyp/pid.c @@ -90,9 +90,12 @@ int pa_pid_file_create(void) { pa_log(__FILE__": stale PID file, overwriting.\n"); } - lseek(fd, 0, SEEK_SET); + if (lseek(fd, 0, SEEK_SET) == (off_t) -1 || ftruncate(fd, 0) < 0) { + pa_log(__FILE__": failed to truncate PID fil: %s.\n", strerror(errno)); + goto fail; + } - snprintf(t, sizeof(t), "%lu", (unsigned long) getpid()); + snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid()); l = strlen(t); if (pa_loop_write(fd, t, l) != (ssize_t) l) { -- cgit From fa751e537db75108f9a1597d83a4e1093173fc28 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Nov 2004 02:43:05 +0000 Subject: some commenting git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@298 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/alsa-util.c | 10 +++++++++- polyp/alsa-util.h | 2 +- polyp/caps.c | 4 ++-- polyp/dynarray.c | 6 +++++- polyp/dynarray.h | 12 ++++++++++++ polyp/hashmap.c | 15 ++++++++++----- polyp/hashmap.h | 9 +++++++++ polyp/idxset.h | 4 ++++ polyp/pid.c | 15 ++++++++++++++- polyp/queue.h | 6 ++++++ polyp/subscribe.c | 14 +++++++++++++- polyp/util.c | 5 +++-- 12 files changed, 88 insertions(+), 14 deletions(-) diff --git a/polyp/alsa-util.c b/polyp/alsa-util.c index eaa21d49..52eaaed4 100644 --- a/polyp/alsa-util.c +++ b/polyp/alsa-util.c @@ -30,7 +30,9 @@ #include "sample.h" #include "xmalloc.h" -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, struct pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { +/* Set the hardware parameters of the given ALSA device. Returns the + * selected fragment settings in *period/*period_size */ +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const struct pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { int ret = -1; snd_pcm_uframes_t buffer_size; snd_pcm_hw_params_t *hwparams = NULL; @@ -79,6 +81,11 @@ finish: return ret; } +/* Allocate an IO event for every ALSA poll descriptor for the + * specified ALSA device. Return a pointer to such an array in + * *io_events. Store the length of that array in *n_io_events. Use the + * specified callback function and userdata. The array has to be freed + * with pa_free_io_events(). */ int pa_create_io_events(snd_pcm_t *pcm_handle, struct pa_mainloop_api* m, struct pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags events, void *userdata), void *userdata) { unsigned i; struct pollfd *pfds, *ppfd; @@ -106,6 +113,7 @@ int pa_create_io_events(snd_pcm_t *pcm_handle, struct pa_mainloop_api* m, struct return 0; } +/* Free the memory allocated by pa_create_io_events() */ void pa_free_io_events(struct pa_mainloop_api* m, struct pa_io_event **io_events, unsigned n_io_events) { unsigned i; struct pa_io_event **ios; diff --git a/polyp/alsa-util.h b/polyp/alsa-util.h index c058025f..adec143f 100644 --- a/polyp/alsa-util.h +++ b/polyp/alsa-util.h @@ -27,7 +27,7 @@ #include "sample.h" #include "mainloop-api.h" -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, struct pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size); +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const struct pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size); int pa_create_io_events(snd_pcm_t *pcm_handle, struct pa_mainloop_api *m, struct pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags events, void *userdata), void *userdata); void pa_free_io_events(struct pa_mainloop_api* m, struct pa_io_event **io_sources, unsigned n_io_sources); diff --git a/polyp/caps.c b/polyp/caps.c index d3719164..e2f4573a 100644 --- a/polyp/caps.c +++ b/polyp/caps.c @@ -42,7 +42,7 @@ void pa_drop_root(void) { if (uid == 0 || geteuid() != 0) return; - pa_log(__FILE__": dropping root rights.\n"); +/* pa_log(__FILE__": dropping root rights.\n"); */ setreuid(uid, uid); /* setuid(uid); @@ -68,7 +68,7 @@ int pa_limit_caps(void) { if (cap_set_proc(caps) < 0) goto fail; - pa_log(__FILE__": dropped capabilities successfully.\n"); +/* pa_log(__FILE__": dropped capabilities successfully.\n"); */ r = 0; diff --git a/polyp/dynarray.c b/polyp/dynarray.c index eb360b80..0e406ea1 100644 --- a/polyp/dynarray.c +++ b/polyp/dynarray.c @@ -30,6 +30,9 @@ #include "dynarray.h" #include "xmalloc.h" +/* If the array becomes to small, increase its size by 100 entries */ +#define INCREASE_BY 100 + struct pa_dynarray { void **data; unsigned n_allocated, n_entries; @@ -66,7 +69,7 @@ void pa_dynarray_put(struct pa_dynarray*a, unsigned i, void *p) { if (!p) return; - n = i+100; + n = i+INCREASE_BY; a->data = pa_xrealloc(a->data, sizeof(void*)*n); memset(a->data+a->n_allocated, 0, sizeof(void*)*(n-a->n_allocated)); a->n_allocated = n; @@ -88,6 +91,7 @@ void *pa_dynarray_get(struct pa_dynarray*a, unsigned i) { assert(a); if (i >= a->n_allocated) return NULL; + assert(a->data); return a->data[i]; } diff --git a/polyp/dynarray.h b/polyp/dynarray.h index 2e9b72f6..6733e958 100644 --- a/polyp/dynarray.h +++ b/polyp/dynarray.h @@ -24,10 +24,22 @@ struct pa_dynarray; +/* Implementation of a simple dynamically sized array. The array + * expands if required, but doesn't shrink if possible. Memory + * management of the array's entries is the user's job. */ + struct pa_dynarray* pa_dynarray_new(void); + +/* Free the array calling the specified function for every entry in + * the array. The function may be NULL. */ void pa_dynarray_free(struct pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata); +/* Store p at position i in the array */ void pa_dynarray_put(struct pa_dynarray*a, unsigned i, void *p); + +/* Store p a the first free position in the array. Returns the index + * of that entry. If entries are removed from the array their position + * are not filled any more by this function. */ unsigned pa_dynarray_append(struct pa_dynarray*a, void *p); void *pa_dynarray_get(struct pa_dynarray*a, unsigned i); diff --git a/polyp/hashmap.c b/polyp/hashmap.c index 43e4456d..3b1265c9 100644 --- a/polyp/hashmap.c +++ b/polyp/hashmap.c @@ -32,6 +32,8 @@ #include "xmalloc.h" #include "log.h" +#define BUCKETS 1023 + struct hashmap_entry { struct hashmap_entry *next, *previous, *bucket_next, *bucket_previous; unsigned hash; @@ -52,7 +54,7 @@ struct pa_hashmap { struct pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { struct pa_hashmap *h; h = pa_xmalloc(sizeof(struct pa_hashmap)); - h->data = pa_xmalloc0(sizeof(struct hashmap_entry*)*(h->size = 1023)); + h->data = pa_xmalloc0(sizeof(struct hashmap_entry*)*(h->size = BUCKETS)); h->first_entry = NULL; h->n_entries = 0; h->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; @@ -74,8 +76,10 @@ static void remove(struct pa_hashmap *h, struct hashmap_entry *e) { e->bucket_next->bucket_previous = e->bucket_previous; if (e->bucket_previous) e->bucket_previous->bucket_next = e->bucket_next; - else + else { + assert(e->hash < h->size); h->data[e->hash] = e->bucket_next; + } pa_xfree(e); h->n_entries--; @@ -96,6 +100,7 @@ void pa_hashmap_free(struct pa_hashmap*h, void (*free_func)(void *p, void *userd static struct hashmap_entry *get(struct pa_hashmap *h, unsigned hash, const void *key) { struct hashmap_entry *e; + assert(h && hash < h->size); for (e = h->data[hash]; e; e = e->bucket_next) if (h->compare_func(e->key, key) == 0) @@ -107,7 +112,7 @@ static struct hashmap_entry *get(struct pa_hashmap *h, unsigned hash, const void int pa_hashmap_put(struct pa_hashmap *h, const void *key, void *value) { struct hashmap_entry *e; unsigned hash; - assert(h && key); + assert(h); hash = h->hash_func(key) % h->size; @@ -171,9 +176,9 @@ unsigned pa_hashmap_ncontents(struct pa_hashmap *h) { void *pa_hashmap_iterate(struct pa_hashmap *h, void **state, const void **key) { assert(h && state); - if (!*state) { + if (!*state) *state = h->first_entry; - } else + else *state = ((struct hashmap_entry*) *state)->next; if (!*state) { diff --git a/polyp/hashmap.h b/polyp/hashmap.h index f858c355..d55834c1 100644 --- a/polyp/hashmap.h +++ b/polyp/hashmap.h @@ -22,14 +22,23 @@ USA. ***/ +/* Simple Implementation of a hash table. Memory management is the + * user's job. It's a good idea to have the key pointer point to a + * string in the value data. */ + struct pa_hashmap; +/* Create a new hashmap. Use the specified functions for hashing and comparing objects in the map */ struct pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); + +/* Free the hash table. Calls the specified function for every value in the table. The function may be NULL */ void pa_hashmap_free(struct pa_hashmap*, void (*free_func)(void *p, void *userdata), void *userdata); +/* Returns non-zero when the entry already exists */ int pa_hashmap_put(struct pa_hashmap *h, const void *key, void *value); void* pa_hashmap_get(struct pa_hashmap *h, const void *key); +/* Returns the data of the entry while removing */ void* pa_hashmap_remove(struct pa_hashmap *h, const void *key); unsigned pa_hashmap_ncontents(struct pa_hashmap *h); diff --git a/polyp/idxset.h b/polyp/idxset.h index 1ed66154..66689fd4 100644 --- a/polyp/idxset.h +++ b/polyp/idxset.h @@ -24,6 +24,10 @@ #include +/* A combination of a hashtable and a dynamic array. Entries are both + * indexiable through a numeric automaticly generated index and an + * opaque key. As usual, memory management is the user's job. */ + #define PA_IDXSET_INVALID ((uint32_t) -1) unsigned pa_idxset_trivial_hash_func(const void *p); diff --git a/polyp/pid.c b/polyp/pid.c index a52bed02..37a76984 100644 --- a/polyp/pid.c +++ b/polyp/pid.c @@ -38,6 +38,8 @@ #include "util.h" #include "log.h" +/* Read the PID data from the file descriptor fd, and return it. If no + * pid could be read, return 0, on failure (pid_t) -1 */ static pid_t read_pid(const char *fn, int fd) { ssize_t r; char t[20], *e = NULL; @@ -63,6 +65,7 @@ static pid_t read_pid(const char *fn, int fd) { return (pid_t) pid; } +/* Create a new PID file for the current process. */ int pa_pid_file_create(void) { int fd = -1, lock = -1; int ret = -1; @@ -77,19 +80,21 @@ int pa_pid_file_create(void) { goto fail; } + /* Try to lock the file. If that fails, go without */ lock = pa_lock_fd(fd, 1); if ((pid = read_pid(fn, fd)) == (pid_t) -1) pa_log(__FILE__": corrupt PID file, overwriting.\n"); else if (pid > 0) { if (kill(pid, 0) >= 0 || errno != ESRCH) { - pa_log(__FILE__": valid PID file.\n"); + pa_log(__FILE__": daemon already running.\n"); goto fail; } pa_log(__FILE__": stale PID file, overwriting.\n"); } + /* Overwrite the current PID file */ if (lseek(fd, 0, SEEK_SET) == (off_t) -1 || ftruncate(fd, 0) < 0) { pa_log(__FILE__": failed to truncate PID fil: %s.\n", strerror(errno)); goto fail; @@ -116,6 +121,7 @@ fail: return ret; } +/* Remove the PID file, if it is ours */ int pa_pid_file_remove(void) { int fd = -1, lock = -1; char fn[PATH_MAX]; @@ -162,10 +168,17 @@ fail: return ret; } +/* Check whether the daemon is currently running, i.e. if a PID file + * exists and the PID therein too. Returns 0 on succcess, -1 + * otherwise. If pid is non-NULL and a running daemon was found, + * return its PID therein */ int pa_pid_file_check_running(pid_t *pid) { return pa_pid_file_kill(0, pid); } +/* Kill a current running daemon. Return non-zero on success, -1 + * otherwise. If successful *pid contains the PID of the daemon + * process. */ int pa_pid_file_kill(int sig, pid_t *pid) { int fd = -1, lock = -1; char fn[PATH_MAX]; diff --git a/polyp/queue.h b/polyp/queue.h index 0b72f37d..a739ab74 100644 --- a/polyp/queue.h +++ b/polyp/queue.h @@ -24,8 +24,14 @@ struct pa_queue; +/* A simple implementation of the abstract data type queue. Stores + * pointers as members. The memory has to be managed by the caller. */ + struct pa_queue* pa_queue_new(void); + +/* Free the queue and run the specified callback function for every remaining entry. The callback function may be NULL. */ void pa_queue_free(struct pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata); + void pa_queue_push(struct pa_queue *q, void *p); void* pa_queue_pop(struct pa_queue *q); diff --git a/polyp/subscribe.c b/polyp/subscribe.c index b552e4d0..ee6ef3aa 100644 --- a/polyp/subscribe.c +++ b/polyp/subscribe.c @@ -31,6 +31,13 @@ #include "xmalloc.h" #include "log.h" +/* The subscription subsystem may be used to be notified whenever an + * entity (sink, source, ...) is created or deleted. Modules may + * register a callback function that is called whenever an event + * matching a subscription mask happens. The execution of the callback + * function is postponed to the next main loop iteration, i.e. is not + * called from within the stack frame the entity was created in. */ + struct pa_subscription { struct pa_core *core; int dead; @@ -48,6 +55,7 @@ struct pa_subscription_event { static void sched_event(struct pa_core *c); +/* Allocate a new subscription object for the given subscription mask. Use the specified callback function and user data */ struct pa_subscription* pa_subscription_new(struct pa_core *c, enum pa_subscription_mask m, void (*callback)(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { struct pa_subscription *s; assert(c); @@ -66,6 +74,7 @@ struct pa_subscription* pa_subscription_new(struct pa_core *c, enum pa_subscript return s; } +/* Free a subscription object, effectively marking it for deletion */ void pa_subscription_free(struct pa_subscription*s) { assert(s && !s->dead); s->dead = 1; @@ -86,6 +95,7 @@ static void free_item(struct pa_subscription *s) { pa_xfree(s); } +/* Free all subscription objects */ void pa_subscription_free_all(struct pa_core *c) { struct pa_subscription_event *e; assert(c); @@ -150,6 +160,7 @@ void pa_subscription_free_all(struct pa_core *c) { pa_log(__FILE__": %u\n", e->index); }*/ +/* Deferred callback for dispatching subscirption events */ static void defer_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) { struct pa_core *c = userdata; struct pa_subscription *s; @@ -187,6 +198,7 @@ static void defer_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void * } } +/* Schedule an mainloop event so that a pending subscription event is dispatched */ static void sched_event(struct pa_core *c) { assert(c); @@ -198,7 +210,7 @@ static void sched_event(struct pa_core *c) { c->mainloop->defer_enable(c->subscription_defer_event, 1); } - +/* Append a new subscription event to the subscription event queue and schedule a main loop event */ void pa_subscription_post(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index) { struct pa_subscription_event *e; assert(c); diff --git a/polyp/util.c b/polyp/util.c index 2ad26c41..b01b80a1 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -384,7 +384,8 @@ void pa_raise_priority(void) { if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) pa_log(__FILE__": setpriority() failed: %s\n", strerror(errno)); - else pa_log(__FILE__": Successfully gained nice level %i.\n", NICE_LEVEL); +/* else */ +/* pa_log(__FILE__": Successfully gained nice level %i.\n", NICE_LEVEL); */ #ifdef _POSIX_PRIORITY_SCHEDULING { @@ -401,7 +402,7 @@ void pa_raise_priority(void) { return; } - pa_log(__FILE__": Successfully enabled SCHED_FIFO scheduling.\n"); +/* pa_log(__FILE__": Successfully enabled SCHED_FIFO scheduling.\n"); */ } #endif } -- cgit From f2b11dbef8bb638ff57baf3225864ed732164fe7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Nov 2004 13:18:56 +0000 Subject: * PID and lock file fixes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@299 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/pid.c | 97 ++++++++++++++++++++++++++++++++++++++++++------------------ polyp/util.c | 46 +++++++++++++++++++++------- 2 files changed, 104 insertions(+), 39 deletions(-) diff --git a/polyp/pid.c b/polyp/pid.c index 37a76984..232de216 100644 --- a/polyp/pid.c +++ b/polyp/pid.c @@ -65,9 +65,62 @@ static pid_t read_pid(const char *fn, int fd) { return (pid_t) pid; } +static int open_pid_file(const char *fn, int mode) { + int fd = -1; + int lock = -1; + + for (;;) { + struct stat st; + + pa_make_secure_parent_dir(fn); + + if ((fd = open(fn, mode, S_IRUSR|S_IWUSR)) < 0) { + if (mode != O_RDONLY || errno != ENOENT) + pa_log(__FILE__": WARNING: failed to open PID file '%s': %s\n", fn, strerror(errno)); + goto fail; + } + + /* Try to lock the file. If that fails, go without */ + if (pa_lock_fd(fd, 1) < 0) + goto fail; + + if (fstat(fd, &st) < 0) { + pa_log(__FILE__": Failed to fstat() PID file '%s': %s\n", fn, strerror(errno)); + goto fail; + } + + /* Does the file still exist in the file system? When ye, w're done, otherwise restart */ + if (st.st_nlink >= 1) + break; + + if (pa_lock_fd(fd, 0) < 0) + goto fail; + + if (close(fd) < 0) { + pa_log(__FILE__": Failed to close file '%s': %s\n", fn, strerror(errno)); + goto fail; + } + + fd = -1; + } + + return fd; + +fail: + + if (fd < 0) { + if (lock >= 0) + pa_lock_fd(fd, 0); + + close(fd); + } + + return -1; +} + /* Create a new PID file for the current process. */ int pa_pid_file_create(void) { - int fd = -1, lock = -1; + int fd = -1; int ret = -1; char fn[PATH_MAX]; char t[20]; @@ -75,13 +128,9 @@ int pa_pid_file_create(void) { size_t l; pa_runtime_path("pid", fn, sizeof(fn)); - if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { - pa_log(__FILE__": WARNING: failed to open PID file '%s': %s\n", fn, strerror(errno)); - goto fail; - } - /* Try to lock the file. If that fails, go without */ - lock = pa_lock_fd(fd, 1); + if ((fd = open_pid_file(fn, O_CREAT|O_RDWR)) < 0) + goto fail; if ((pid = read_pid(fn, fd)) == (pid_t) -1) pa_log(__FILE__": corrupt PID file, overwriting.\n"); @@ -112,9 +161,7 @@ int pa_pid_file_create(void) { fail: if (fd >= 0) { - if (lock >= 0) - pa_lock_fd(fd, 0); - + pa_lock_fd(fd, 0); close(fd); } @@ -123,19 +170,18 @@ fail: /* Remove the PID file, if it is ours */ int pa_pid_file_remove(void) { - int fd = -1, lock = -1; + int fd = -1; char fn[PATH_MAX]; int ret = -1; pid_t pid; pa_runtime_path("pid", fn, sizeof(fn)); - if ((fd = open(fn, O_RDWR)) < 0) { + + if ((fd = open_pid_file(fn, O_RDWR)) < 0) { pa_log(__FILE__": WARNING: failed to open PID file '%s': %s\n", fn, strerror(errno)); goto fail; } - lock = pa_lock_fd(fd, 1); - if ((pid = read_pid(fn, fd)) == (pid_t) -1) goto fail; @@ -159,9 +205,7 @@ int pa_pid_file_remove(void) { fail: if (fd >= 0) { - if (lock >= 0) - pa_lock_fd(fd, 0); - + pa_lock_fd(fd, 0); close(fd); } @@ -180,31 +224,28 @@ int pa_pid_file_check_running(pid_t *pid) { * otherwise. If successful *pid contains the PID of the daemon * process. */ int pa_pid_file_kill(int sig, pid_t *pid) { - int fd = -1, lock = -1; + int fd = -1; char fn[PATH_MAX]; int ret = -1; pid_t _pid; if (!pid) pid = &_pid; - + pa_runtime_path("pid", fn, sizeof(fn)); - if ((fd = open(fn, O_RDONLY)) < 0) + + if ((fd = open_pid_file(fn, O_RDONLY)) < 0) goto fail; - - lock = pa_lock_fd(fd, 1); - + if ((*pid = read_pid(fn, fd)) == (pid_t) -1) goto fail; - + ret = kill(*pid, sig); fail: - + if (fd >= 0) { - if (lock >= 0) - pa_lock_fd(fd, 0); - + pa_lock_fd(fd, 0); close(fd); } diff --git a/polyp/util.c b/polyp/util.c index b01b80a1..87beafb3 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -646,26 +646,50 @@ char* pa_strip_nl(char *s) { /* Create a temporary lock file and lock it. */ int pa_lock_lockfile(const char *fn) { - int fd; + int fd = -1; assert(fn); - if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { - pa_log(__FILE__": failed to create lock file '%s': %s\n", fn, strerror(errno)); - goto fail; - } + for (;;) { + struct stat st; + + if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { + pa_log(__FILE__": failed to create lock file '%s': %s\n", fn, strerror(errno)); + goto fail; + } + + if (pa_lock_fd(fd, 1) < 0) { + pa_log(__FILE__": failed to lock file '%s'.\n", fn); + goto fail; + } + + if (fstat(fd, &st) < 0) { + pa_log(__FILE__": failed to fstat() file '%s'.\n", fn); + goto fail; + } - if (pa_lock_fd(fd, 1) < 0) - pa_log(__FILE__": failed to lock file '%s'.\n", fn); - goto fail; + /* Check wheter the file has been removed meanwhile. When yes, restart this loop, otherwise, we're done */ + if (st.st_nlink >= 1) + break; + + if (pa_lock_fd(fd, 0) < 0) { + pa_log(__FILE__": failed to unlock file '%s'.\n", fn); + goto fail; + } + + if (close(fd) < 0) { + pa_log(__FILE__": failed to close file '%s'.\n", fn); + goto fail; + } + fd = -1; + } + return fd; fail: - if (fd >= 0) { - unlink(fn); + if (fd >= 0) close(fd); - } return -1; } -- cgit From 92f73a741f7d439263857ea5c438a612ce24b03d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Nov 2004 15:22:59 +0000 Subject: * fix the trivial resampler git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@300 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 +- polyp/resampler.c | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/todo b/doc/todo index c5f7dbba..d5514504 100644 --- a/doc/todo +++ b/doc/todo @@ -4,9 +4,9 @@ - make most buffer sizes dependant on the sample type - limit all resources - commenting -- polish for starting polypaudio as root/system-wide instance ** later *** +- polish for starting polypaudio as root/system-wide instance - per-channel volume - improve module-oss-mmap latency measurement - module-tunnel: improve latency calculation diff --git a/polyp/resampler.c b/polyp/resampler.c index 6cf51dab..dbd748f7 100644 --- a/polyp/resampler.c +++ b/polyp/resampler.c @@ -310,7 +310,7 @@ fail: static void trivial_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out) { size_t fz; - unsigned nsamples; + unsigned nframes; struct impl_trivial *i; assert(r && in && out && r->impl_data); i = r->impl_data; @@ -318,22 +318,22 @@ static void trivial_run(struct pa_resampler *r, const struct pa_memchunk *in, st fz = r->i_fz; assert(fz == r->o_fz); - nsamples = in->length/fz; + nframes = in->length/fz; if (r->i_ss.rate == r->o_ss.rate) { /* In case there's no diefference in sample types, do nothing */ *out = *in; - pa_memblock_ref(in->memblock); + pa_memblock_ref(out->memblock); - i->o_counter += nsamples; + i->o_counter += nframes; } else { /* Do real resampling */ size_t l; unsigned o_index; /* The length of the new memory block rounded up */ - l = ((nsamples * r->o_ss.rate + r->i_ss.rate - 1) / r->i_ss.rate) * fz; + l = ((nframes * r->o_ss.rate + r->i_ss.rate - 1) / r->i_ss.rate) * fz; out->index = 0; out->memblock = pa_memblock_new(l, r->memblock_stat); @@ -345,13 +345,13 @@ static void trivial_run(struct pa_resampler *r, const struct pa_memchunk *in, st assert(j >= i->i_counter); j = j - i->i_counter; - if (j >= nsamples) + if (j >= nframes) break; assert(o_index*fz < out->memblock->length); memcpy((uint8_t*) out->memblock->data + fz*o_index, - (uint8_t*) in->memblock->data + fz*j, fz); + (uint8_t*) in->memblock->data + in->index + fz*j, fz); } @@ -362,7 +362,7 @@ static void trivial_run(struct pa_resampler *r, const struct pa_memchunk *in, st while (i->o_counter >= r->o_ss.rate) i->o_counter -= r->o_ss.rate; - i->i_counter += nsamples; + i->i_counter += nframes; while (i->i_counter >= r->i_ss.rate) i->i_counter -= r->i_ss.rate; -- cgit From 966c78ccae42f6632c742d9369aba53c11b10875 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Nov 2004 16:27:51 +0000 Subject: fixes for bugs found when compiling with gcc 2.95 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@301 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/alsa-util.c | 2 +- polyp/client-conf.c | 3 --- polyp/resampler.c | 2 +- polyp/strlist-test.c | 2 ++ polyp/util.c | 2 -- 5 files changed, 4 insertions(+), 7 deletions(-) diff --git a/polyp/alsa-util.c b/polyp/alsa-util.c index 52eaaed4..b6b9ac11 100644 --- a/polyp/alsa-util.c +++ b/polyp/alsa-util.c @@ -31,7 +31,7 @@ #include "xmalloc.h" /* Set the hardware parameters of the given ALSA device. Returns the - * selected fragment settings in *period/*period_size */ + * selected fragment settings in *period and *period_size */ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const struct pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { int ret = -1; snd_pcm_uframes_t buffer_size; diff --git a/polyp/client-conf.c b/polyp/client-conf.c index 2de1c57f..21e0acab 100644 --- a/polyp/client-conf.c +++ b/polyp/client-conf.c @@ -59,12 +59,9 @@ static const struct pa_client_conf default_conf = { struct pa_client_conf *pa_client_conf_new(void) { struct pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); - - c->daemon_binary = pa_xstrdup(POLYPAUDIO_BINARY); c->extra_arguments = pa_xstrdup("--log-target=syslog --exit-idle-time=5"); - c->cookie_file = pa_xstrdup(PA_NATIVE_COOKIE_FILE); return c; diff --git a/polyp/resampler.c b/polyp/resampler.c index dbd748f7..377aa797 100644 --- a/polyp/resampler.c +++ b/polyp/resampler.c @@ -397,7 +397,7 @@ static int trivial_init(struct pa_resampler*r) { } const char *pa_resample_method_to_string(enum pa_resample_method m) { - static const char const* resample_methods[] = { + static const char * const resample_methods[] = { "src-sinc-best-quality", "src-sinc-medium-quality", "src-sinc-fastest", diff --git a/polyp/strlist-test.c b/polyp/strlist-test.c index 01dcdf12..b68a0415 100644 --- a/polyp/strlist-test.c +++ b/polyp/strlist-test.c @@ -36,4 +36,6 @@ int main(int argc, char* argv[]) { pa_xfree(t); pa_strlist_free(l); + + return 0; } diff --git a/polyp/util.c b/polyp/util.c index 87beafb3..0b459ddc 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -225,8 +225,6 @@ char *pa_vsprintf_malloc(const char *format, va_list ap) { for(;;) { int r; - va_list ap; - c = pa_xrealloc(c, size); r = vsnprintf(c, size, format, ap); -- cgit From b03f39099f27d99158d881419ed65060d5be5643 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Nov 2004 17:02:25 +0000 Subject: * add some missing "static"s * include libltdl in distribution git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@302 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- bootstrap.sh | 2 +- configure.ac | 5 ++++- polyp/Makefile.am | 4 ++-- polyp/daemon-conf.c | 4 ++-- polyp/mainloop.c | 2 +- 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Makefile.am b/Makefile.am index 04c8f2cf..9b419d1d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,7 +18,7 @@ # USA. EXTRA_DIST = bootstrap.sh README LICENSE doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in -SUBDIRS=polyp doc +SUBDIRS=polyp doc libltdl MAINTAINERCLEANFILES=README noinst_DATA = README diff --git a/bootstrap.sh b/bootstrap.sh index 7dc081ae..4b9032b6 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -36,7 +36,7 @@ else rm -f config.cache run_versioned aclocal 1.7 - libtoolize -c --force + libtoolize -c --force --ltdl autoheader run_versioned automake 1.7 -a -c --foreign autoconf -Wall diff --git a/configure.ac b/configure.ac index 45533411..0a1ebd05 100644 --- a/configure.ac +++ b/configure.ac @@ -37,11 +37,14 @@ fi # Checks for programs. AC_PROG_CC + +# libtool stuff AC_LIBLTDL_INSTALLABLE -AC_SUBST(INCLTDL) +AC_SUBST(LTDLINCL) AC_SUBST(LIBLTDL) AC_LIBTOOL_DLOPEN AC_PROG_LIBTOOL +AC_CONFIG_SUBDIRS(libltdl) # Checks for header files. AC_HEADER_STDC diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 13ef893c..6d9962d5 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -215,9 +215,9 @@ polypaudio_SOURCES = idxset.c idxset.h \ pid.c pid.h polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) -polypaudio_INCLUDES = $(INCLTDL) +polypaudio_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL) polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) -polypaudio_LDFLAGS= -export-dynamic -dlopen force #-static $(foreach f,$(modlib_LTLIBRARIES),-dlpreopen $(f)) +polypaudio_LDFLAGS= $(AM_LDFLAGS) -export-dynamic -dlopen force #-static $(foreach f,$(modlib_LTLIBRARIES),-dlpreopen $(f)) libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h libprotocol_simple_la_LDFLAGS = -avoid-version diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c index 9728019d..7753da6a 100644 --- a/polyp/daemon-conf.c +++ b/polyp/daemon-conf.c @@ -119,7 +119,7 @@ int pa_daemon_conf_set_resample_method(struct pa_daemon_conf *c, const char *str return 0; } -int parse_log_target(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { +static int parse_log_target(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { struct pa_daemon_conf *c = data; assert(filename && lvalue && rvalue && data); @@ -131,7 +131,7 @@ int parse_log_target(const char *filename, unsigned line, const char *lvalue, co return 0; } -int parse_resample_method(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { +static int parse_resample_method(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { struct pa_daemon_conf *c = data; assert(filename && lvalue && rvalue && data); diff --git a/polyp/mainloop.c b/polyp/mainloop.c index d530419e..f6bb4145 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -130,7 +130,7 @@ static void mainloop_io_set_destroy(struct pa_io_event *e, void (*callback)(stru } /* Defer events */ -struct pa_defer_event* mainloop_defer_new(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata), void *userdata) { +static struct pa_defer_event* mainloop_defer_new(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata), void *userdata) { struct pa_mainloop *m; struct pa_defer_event *e; -- cgit From c90409e4b74d1a4a405bdf560f280694b3e0bb29 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Nov 2004 17:06:59 +0000 Subject: bump version number git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@303 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 0a1ebd05..332570dd 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. AC_PREREQ(2.57) -AC_INIT([polypaudio],[0.6],[mzcbylcnhqvb (at) 0pointer (dot) de]) +AC_INIT([polypaudio],[0.7],[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([polyp/main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) @@ -28,7 +28,7 @@ AM_INIT_AUTOMAKE([foreign -Wall]) AC_SUBST(PA_MAJORMINOR, "$PACKAGE_VERSION") AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/polypaudio/]) -AC_SUBST(PA_API_VERSION, 6) +AC_SUBST(PA_API_VERSION, 7) if type -p stow > /dev/null && test -d /usr/local/stow ; then AC_MSG_NOTICE([*** Found /usr/local/stow: default install prefix set to /usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION} ***]) -- cgit From 28d97441e7c88441c4fbc77458932af7fd61a59c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Nov 2004 18:15:33 +0000 Subject: * new tool pacmd * fix pacat/paplay/pactl for new API version * fix memory leak in pa_ioline git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@304 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 13 +++- polyp/ioline.c | 9 +++ polyp/pacat.c | 2 +- polyp/pacmd.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ polyp/pactl.c | 2 +- polyp/paplay.c | 2 +- polyp/util.c | 9 +++ polyp/util.h | 2 + 8 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 polyp/pacmd.c diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 6d9962d5..2570f7f0 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -34,8 +34,15 @@ AM_LIBADD=$(PTHREAD_LIBS) -lm AM_LDADD=$(PTHREAD_LIBS) -lm EXTRA_DIST = default.pa.in daemon.conf.in client.conf.in depmod.py esdcompat.sh.in module-defs.h.m4 -bin_PROGRAMS = polypaudio pacat pactl paplay +bin_PROGRAMS = \ + polypaudio \ + pacat \ + pactl \ + paplay \ + pacmd + bin_SCRIPTS = esdcompat.sh + noinst_PROGRAMS = \ mainloop-test \ pacat-simple \ @@ -505,6 +512,10 @@ mcalign_test_SOURCES = mcalign-test.c util.c util.h xmalloc.c xmalloc.h log.c lo mcalign_test_CFLAGS = $(AM_CFLAGS) mcalign_test_LDADD = $(AM_LDADD) +pacmd_SOURCES = pacmd.c util.c util.h xmalloc.c xmalloc.h log.c log.h pid.c pid.h +pacmd_CFLAGS = $(AM_CFLAGS) +pacmd_LDADD = $(AM_LDADD) + cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h cpulimit_test_CFLAGS = $(AM_CFLAGS) cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la diff --git a/polyp/ioline.c b/polyp/ioline.c index 059591b8..f52af2db 100644 --- a/polyp/ioline.c +++ b/polyp/ioline.c @@ -89,6 +89,10 @@ static void ioline_free(struct pa_ioline *l) { if (l->io) pa_iochannel_free(l->io); + + if (l->defer_event) + l->mainloop->defer_free(l->defer_event); + pa_xfree(l->wbuf); pa_xfree(l->rbuf); pa_xfree(l); @@ -116,6 +120,11 @@ void pa_ioline_close(struct pa_ioline *l) { pa_iochannel_free(l->io); l->io = NULL; } + + if (l->defer_event) { + l->mainloop->defer_free(l->defer_event); + l->defer_event = NULL; + } } void pa_ioline_puts(struct pa_ioline *l, const char *c) { diff --git a/polyp/pacat.c b/polyp/pacat.c index e5e0b7ca..8c3ee0ba 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -38,7 +38,7 @@ #include #include -#if PA_API_VERSION != 6 +#if PA_API_VERSION != 7 #error Invalid Polypaudio API version #endif diff --git a/polyp/pacmd.c b/polyp/pacmd.c new file mode 100644 index 00000000..741059ce --- /dev/null +++ b/polyp/pacmd.c @@ -0,0 +1,183 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "log.h" +#include "pid.h" + +int main() { + pid_t pid ; + int fd = -1; + int ret = 1, i; + struct sockaddr_un sa; + char ibuf[256], obuf[256]; + size_t ibuf_index, ibuf_length, obuf_index, obuf_length; + fd_set ifds, ofds; + + if (pa_pid_file_check_running(&pid) < 0) { + pa_log(__FILE__": no Polypaudio daemon running\n"); + goto fail; + } + + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + pa_log(__FILE__": socket(PF_UNIX, SOCK_STREAM, 0): %s\n", strerror(errno)); + goto fail; + } + + memset(&sa, 0, sizeof(sa)); + sa.sun_family = AF_UNIX; + pa_runtime_path("cli", sa.sun_path, sizeof(sa.sun_path)); + + for (i = 0; i < 5; i++) { + int r; + + if ((r = connect(fd, (struct sockaddr*) &sa, sizeof(sa))) < 0 && (errno != ECONNREFUSED && errno != ENOENT)) { + pa_log(__FILE__": connect() failed: %s\n", strerror(errno)); + goto fail; + } + + if (r >= 0) + break; + + if (pa_pid_file_kill(SIGUSR2, NULL) < 0) { + pa_log(__FILE__": failed to kill Polypaudio daemon.\n"); + goto fail; + } + + pa_msleep(10); + } + + if (i >= 5) { + pa_log(__FILE__": daemon to responding.\n"); + goto fail; + } + + ibuf_index = ibuf_length = obuf_index = obuf_length = 0; + + + FD_ZERO(&ifds); + FD_SET(0, &ifds); + FD_SET(fd, &ifds); + + FD_ZERO(&ofds); + + for (;;) { + if (select(FD_SETSIZE, &ifds, &ofds, NULL, NULL) < 0) { + pa_log(__FILE__": select() failed: %s\n", strerror(errno)); + goto fail; + } + + if (FD_ISSET(0, &ifds)) { + ssize_t r; + assert(!ibuf_length); + + if ((r = read(0, ibuf, sizeof(ibuf))) <= 0) { + if (r == 0) + break; + + pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + goto fail; + } + + ibuf_length = (size_t) r; + ibuf_index = 0; + } + + if (FD_ISSET(fd, &ifds)) { + ssize_t r; + assert(!obuf_length); + + if ((r = read(fd, obuf, sizeof(obuf))) <= 0) { + if (r == 0) + break; + + pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + goto fail; + } + + obuf_length = (size_t) r; + obuf_index = 0; + } + + if (FD_ISSET(1, &ofds)) { + ssize_t r; + assert(obuf_length); + + if ((r = write(1, obuf + obuf_index, obuf_length)) < 0) { + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + goto fail; + } + + obuf_length -= (size_t) r; + obuf_index += obuf_index; + + } + + if (FD_ISSET(fd, &ofds)) { + ssize_t r; + assert(ibuf_length); + + if ((r = write(fd, ibuf + ibuf_index, ibuf_length)) < 0) { + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + goto fail; + } + + ibuf_length -= (size_t) r; + ibuf_index += obuf_index; + + } + + FD_ZERO(&ifds); + FD_ZERO(&ofds); + + if (obuf_length <= 0) + FD_SET(fd, &ifds); + else + FD_SET(1, &ofds); + + if (ibuf_length <= 0) + FD_SET(0, &ifds); + else + FD_SET(fd, &ofds); + } + + + ret = 0; + +fail: + if (fd >= 0) + close(fd); + + return ret; +} diff --git a/polyp/pactl.c b/polyp/pactl.c index d73f703c..6300b656 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -41,7 +41,7 @@ #include #include -#if PA_API_VERSION != 6 +#if PA_API_VERSION != 7 #error Invalid Polypaudio API version #endif diff --git a/polyp/paplay.c b/polyp/paplay.c index 418d40b3..0faa0ff2 100644 --- a/polyp/paplay.c +++ b/polyp/paplay.c @@ -40,7 +40,7 @@ #include #include -#if PA_API_VERSION != 6 +#if PA_API_VERSION != 7 #error Invalid Polypaudio API version #endif diff --git a/polyp/util.c b/polyp/util.c index 0b459ddc..970ebb93 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -861,3 +861,12 @@ char *pa_runtime_path(const char *fn, char *s, size_t l) { snprintf(s, l, PA_RUNTIME_PATH_PREFIX"%s%s%s", pa_get_user_name(u, sizeof(u)), fn ? "/" : "", fn ? fn : ""); return s; } + +int pa_msleep(unsigned long t) { + struct timespec ts; + + ts.tv_sec = t/1000; + ts.tv_nsec = (t % 1000) * 1000000; + + return nanosleep(&ts, NULL); +} diff --git a/polyp/util.h b/polyp/util.h index ef7e4d96..922aa49e 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -88,4 +88,6 @@ int pa_startswith(const char *s, const char *pfx); char *pa_runtime_path(const char *fn, char *s, size_t l); +int pa_msleep(unsigned long t); + #endif -- cgit From 4583c22bfd490e2cdc7ebb151a566c85987bd791 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Nov 2004 18:41:00 +0000 Subject: * create parec as link to pacat git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@305 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 2570f7f0..1bae9afc 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -731,6 +731,7 @@ daemon.conf: daemon.conf.in Makefile install-exec-hook: chown root $(DESTDIR)$(bindir)/polypaudio chmod u+s $(DESTDIR)$(bindir)/polypaudio + ln -s pacat $(DESTDIR)$(bindir)/parec $(SYMDEF_FILES): module-defs.h.m4 $(M4) -Dfname="$@" $< > $@ -- cgit From d45abba9aa4090ebeaf09ec9ec324709e04a1bbf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Nov 2004 19:39:46 +0000 Subject: calculate buffer sizes from sample spec git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@306 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/memblockq.c | 11 +++++++---- polyp/polyplib-internal.h | 6 ------ polyp/polyplib-stream.c | 11 ++++++----- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/polyp/memblockq.c b/polyp/memblockq.c index ff16f627..16c0da8e 100644 --- a/polyp/memblockq.c +++ b/polyp/memblockq.c @@ -68,18 +68,21 @@ struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t b bq->tlength = ((tlength+base-1)/base)*base; if (!bq->tlength || bq->tlength >= bq->maxlength) bq->tlength = bq->maxlength; + + bq->minreq = (minreq/base)*base; + if (bq->minreq == 0) + bq->minreq = 1; bq->prebuf = (prebuf == (size_t) -1) ? bq->maxlength/2 : prebuf; bq->prebuf = (bq->prebuf/base)*base; if (bq->prebuf > bq->maxlength) bq->prebuf = bq->maxlength; + if (bq->prebuf > bq->tlength - bq->minreq) + bq->prebuf = bq->tlength - bq->minreq; + bq->orig_prebuf = bq->prebuf; - bq->minreq = (minreq/base)*base; - if (bq->minreq == 0) - bq->minreq = 1; - pa_log(__FILE__": memblockq sanitized: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", bq->maxlength, bq->tlength, bq->base, bq->prebuf, bq->minreq); bq->mcalign = NULL; diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 4289b3c8..d1b3a27f 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -37,12 +37,6 @@ #include "strlist.h" #include "mcalign.h" -#define DEFAULT_TLENGTH (44100*2*2/2) //(10240*8) -#define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2) -#define DEFAULT_MINREQ 512 -#define DEFAULT_PREBUF (DEFAULT_TLENGTH-DEFAULT_MINREQ) -#define DEFAULT_FRAGSIZE 1024 - #define DEFAULT_TIMEOUT (10) struct pa_context { diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index b3f1f8cd..440217e7 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -283,11 +283,12 @@ static void create_stream(struct pa_stream *s, const char *dev, const struct pa_ if (attr) s->buffer_attr = *attr; else { - s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; - s->buffer_attr.tlength = DEFAULT_TLENGTH; - s->buffer_attr.prebuf = DEFAULT_PREBUF; - s->buffer_attr.minreq = DEFAULT_MINREQ; - s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; + /* half a second */ + s->buffer_attr.tlength = pa_bytes_per_second(&s->sample_spec)/2; + s->buffer_attr.maxlength = (s->buffer_attr.tlength*3)/2; + s->buffer_attr.minreq = s->buffer_attr.tlength/100; + s->buffer_attr.prebuf = s->buffer_attr.tlength - s->buffer_attr.minreq; + s->buffer_attr.fragsize = s->buffer_attr.tlength/100; } pa_stream_set_state(s, PA_STREAM_CREATING); -- cgit From 82a362655446fdce8dd3d99d0ce41dd6aa328a16 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Nov 2004 19:40:07 +0000 Subject: * update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@307 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index d5514504..3e30af4f 100644 --- a/doc/todo +++ b/doc/todo @@ -1,7 +1,6 @@ *** $Id$ *** *** 0.7 **** -- make most buffer sizes dependant on the sample type - limit all resources - commenting -- cgit From 2fb83d13f27214476f90fe619b26f5bbc8f520c8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Nov 2004 19:47:47 +0000 Subject: * make --help fit in 80 columns terminal git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@308 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/cmdline.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/polyp/cmdline.c b/polyp/cmdline.c index cdf25638..e11d8aad 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -91,6 +91,7 @@ void pa_cmdline_help(const char *argv0) { e = argv0; printf("%s [options]\n\n" + "COMMANDS:\n" " -h, --help Show this help\n" " --version Show version\n" " --dump-conf Dump default configuration\n" @@ -98,22 +99,34 @@ void pa_cmdline_help(const char *argv0) { " -k --kill Kill a running daemon\n" " --check Check for a running daemon\n\n" + "OPTIONS:\n" " -D, --daemonize[=BOOL] Daemonize after startup\n" " --fail[=BOOL] Quit when startup fails\n" " --verbose[=BOOL] Be slightly more verbose\n" - " --high-priority[=BOOL] Try to set high process priority (only available as root)\n" + " --high-priority[=BOOL] Try to set high process priority\n" + " (only available as root)\n" " --disallow-module-loading[=BOOL] Disallow module loading after startup\n" - " --exit-idle-time=SECS Terminate the daemon when idle and this time passed\n" - " --module-idle-time=SECS Unload autoloaded modules when idle and this time passed\n" - " --scache-idle-time=SECS Unload autoloaded samples when idle and this time passed\n" + " --exit-idle-time=SECS Terminate the daemon when idle and this\n" + " time passed\n" + " --module-idle-time=SECS Unload autoloaded modules when idle and\n" + " this time passed\n" + " --scache-idle-time=SECS Unload autoloaded samples when idle and\n" + " this time passed\n" " --log-target={auto,syslog,stderr} Specify the log target\n" - " -p, --dl-search-path=PATH Set the search path for dynamic shared objects (plugins)\n" + " -p, --dl-search-path=PATH Set the search path for dynamic shared\n" + " objects (plugins)\n" " --resample-method=[METHOD] Use the specified resampling method\n" + " (one of src-sinc-medium-quality,\n" + " src-sinc-best-quality,src-sinc-fastest\n" + " src-zero-order-hold,src-linear,trivial)\n" " --use-pid-file[=BOOL] Create a PID file\n\n" - - " -L, --load=\"MODULE ARGUMENTS\" Load the specified plugin module with the specified argument\n" + + "STARTUP SCRIPT:\n" + " -L, --load=\"MODULE ARGUMENTS\" Load the specified plugin module with\n" + " the specified argument\n" " -F, --file=FILENAME Run the specified script\n" - " -C Open a command line on the running TTY after startup\n\n" + " -C Open a command line on the running TTY\n" + " after startup\n\n" " -n Don't load default script file\n", e); } -- cgit From 4763ca1376fc136158e576de94dc1cf6c6584973 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Nov 2004 21:31:28 +0000 Subject: Comment some more files git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@309 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 14 ++++++++++++-- polyp/authkey-prop.h | 4 ++++ polyp/authkey.c | 21 +++++++++++---------- polyp/authkey.h | 1 - polyp/autoload.h | 17 +++++++++++++++-- polyp/caps.c | 1 + polyp/cli-command.c | 4 ++++ polyp/cli-command.h | 9 +++++++++ polyp/cli-text.h | 3 +++ polyp/cli.h | 2 ++ polyp/client-conf-x11.h | 2 ++ polyp/client-conf.c | 1 + polyp/client-conf.h | 12 +++++++++++- polyp/client.c | 3 ++- polyp/client.h | 6 ++++++ polyp/cmdline.c | 2 ++ polyp/cmdline.h | 4 ++++ polyp/conf-parser.c | 7 ++++++- polyp/conf-parser.h | 14 +++++++++++--- polyp/core.h | 9 +++++++++ polyp/cpulimit-test.c | 16 +++++++++++----- polyp/cpulimit.c | 14 +++++++++----- polyp/daemon-conf.h | 28 +++++++++++++++++++++------- polyp/daemon.conf.in | 18 ++++++++++++++---- polyp/default.pa.in | 15 +++++++++------ polyp/dumpmodules.h | 2 ++ polyp/gcc-printf.h | 23 +++++++++++++++++++++++ polyp/glib-mainloop.c | 1 + polyp/glib12-mainloop.c | 2 ++ polyp/idxset.h | 36 +++++++++++++++++++++++++++++++----- polyp/iochannel.h | 21 ++++++++++++++++++++- polyp/ioline.h | 7 +++++++ polyp/llist.h | 19 ++++++++++++++----- polyp/log.c | 27 +++++++++++++++++++++++++++ polyp/log.h | 35 ++++++++++++++++++++++++++++++++--- polyp/mcalign-test.c | 27 +++++++++++++++++++++++++++ polyp/memblock.h | 32 ++++++++++++++++++++++++++++---- polyp/memblockq.h | 16 +++++++++++----- polyp/modargs.c | 2 +- polyp/modargs.h | 10 +++++++++- polyp/modinfo.c | 10 +++++----- polyp/modinfo.h | 6 ++++++ polyp/module-tunnel.c | 2 +- polyp/module-x11-publish.c | 2 +- polyp/protocol-native.c | 2 +- 45 files changed, 428 insertions(+), 81 deletions(-) diff --git a/doc/README.html.in b/doc/README.html.in index 742ea3d1..31511886 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -40,10 +40,20 @@ Lesser General Public License for more details.

    along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    -

    Exception: The client libraries are licensed under LGPL, the Lesser GNU General Plublic License.

    -

    News

    +
    Sun Nov 21 2004:

    Version 0.7 released; +changes include: TCP wrappers support; don't load the complete sound +file into memory when playing back using pa_play_file(); +autoload API change; don't load all sound files as FLOAT32; shorten +default buffers; client-side latency interpolation; add new user +volume metrics; add module-tunnel, module-null-sink, +module-match and new tool paplay; new API version +macros; many client API improvements; correctly lock cookie file +generation; correctly lock daemon autospawning; print daemon layout to +STDERR on SIGHUP; new options for pacat: allow sample type specification.

    +
    Thu Oct 28 2004:

    Version 0.6 released; changes include: TCP wrappers support; don't load the complete sound diff --git a/polyp/authkey-prop.h b/polyp/authkey-prop.h index 1a668117..1b1948c7 100644 --- a/polyp/authkey-prop.h +++ b/polyp/authkey-prop.h @@ -24,6 +24,10 @@ #include "core.h" +/* The authkey-prop uses a central property to store a previously + * loaded cookie in memory. Useful for sharing the same cookie between + * several modules. */ + /* Return the data of the specified authorization key property. Doesn't alter the refernce count of the key */ int pa_authkey_prop_get(struct pa_core *c, const char *name, void *data, size_t len); diff --git a/polyp/authkey.c b/polyp/authkey.c index 05324a61..1355c8d9 100644 --- a/polyp/authkey.c +++ b/polyp/authkey.c @@ -41,6 +41,7 @@ #define RANDOM_DEVICE "/dev/urandom" +/* Generate a new authorization key, store it in file fd and return it in *data */ static int generate(int fd, void *data, size_t length) { int random_fd, ret = -1; ssize_t r; @@ -66,6 +67,7 @@ static int generate(int fd, void *data, size_t length) { } lseek(fd, 0, SEEK_SET); + ftruncate(fd, 0); if ((r = pa_loop_write(fd, data, length)) < 0 || (size_t) r != length) { pa_log(__FILE__": failed to write cookie file: %s\n", strerror(errno)); @@ -82,6 +84,8 @@ finish: return ret; } +/* Load an euthorization cookie from file fn and store it in data. If + * the cookie file doesn't exist, create it */ static int load(const char *fn, void *data, size_t length) { int fd = -1; int writable = 1; @@ -130,6 +134,7 @@ finish: return ret; } +/* Load a cookie from a cookie file. If the file doesn't exist, create it. */ int pa_authkey_load(const char *path, void *data, size_t length) { int ret; @@ -144,6 +149,8 @@ int pa_authkey_load(const char *path, void *data, size_t length) { return ret; } +/* If the specified file path starts with / return it, otherwise + * return path prepended with home directory */ static const char *normalize_path(const char *fn, char *s, size_t l) { assert(fn && s && l > 0); @@ -159,7 +166,9 @@ static const char *normalize_path(const char *fn, char *s, size_t l) { return fn; } -int pa_authkey_load_from_home(const char *fn, void *data, size_t length) { +/* Load a cookie from a file in the home directory. If the specified + * path starts with /, use it as absolute path instead. */ +int pa_authkey_load_auto(const char *fn, void *data, size_t length) { char path[PATH_MAX]; const char *p; assert(fn && data && length); @@ -170,15 +179,7 @@ int pa_authkey_load_from_home(const char *fn, void *data, size_t length) { return pa_authkey_load(p, data, length); } -int pa_authkey_load_auto(const char *fn, void *data, size_t length) { - assert(fn && data && length); - - if (*fn == '/') - return pa_authkey_load(fn, data, length); - else - return pa_authkey_load_from_home(fn, data, length); -} - +/* Store the specified cookie in the speicified cookie file */ int pa_authkey_save(const char *fn, const void *data, size_t length) { int fd = -1; int unlock = 0, ret = -1; diff --git a/polyp/authkey.h b/polyp/authkey.h index a6006dfc..81b1a578 100644 --- a/polyp/authkey.h +++ b/polyp/authkey.h @@ -25,7 +25,6 @@ #include int pa_authkey_load(const char *path, void *data, size_t len); -int pa_authkey_load_from_home(const char *fn, void *data, size_t length); int pa_authkey_load_auto(const char *fn, void *data, size_t length); int pa_authkey_save(const char *path, const void *data, size_t length); diff --git a/polyp/autoload.h b/polyp/autoload.h index 8537173c..23475684 100644 --- a/polyp/autoload.h +++ b/polyp/autoload.h @@ -24,19 +24,32 @@ #include "namereg.h" +/* Using the autoloading facility, modules by be loaded on-demand and + * synchronously. The user may register a "ghost sink" or "ghost + * source". Whenever this sink/source is requested but not available a + * specified module is loaded. */ + +/* An autoload entry, or "ghost" sink/source */ struct pa_autoload_entry { struct pa_core *core; uint32_t index; char *name; - enum pa_namereg_type type; - int in_action; + enum pa_namereg_type type; /* Type of the autoload entry */ + int in_action; /* Currently loaded */ char *module, *argument; }; +/* Add a new autoload entry of the given time, with the speicified + * sink/source name, module name and argument. Return the entry's + * index in *index */ int pa_autoload_add(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*module, const char *argument, uint32_t *index); + +/* Free all autoload entries */ void pa_autoload_free(struct pa_core *c); int pa_autoload_remove_by_name(struct pa_core *c, const char*name, enum pa_namereg_type type); int pa_autoload_remove_by_index(struct pa_core *c, uint32_t index); + +/* Request an autoload entry by its name, effectively causing a module to be loaded */ void pa_autoload_request(struct pa_core *c, const char *name, enum pa_namereg_type type); const struct pa_autoload_entry* pa_autoload_get_by_name(struct pa_core *c, const char*name, enum pa_namereg_type type); diff --git a/polyp/caps.c b/polyp/caps.c index e2f4573a..34d97eb5 100644 --- a/polyp/caps.c +++ b/polyp/caps.c @@ -45,6 +45,7 @@ void pa_drop_root(void) { /* pa_log(__FILE__": dropping root rights.\n"); */ setreuid(uid, uid); + /* setuid(uid); seteuid(uid);*/ } diff --git a/polyp/cli-command.c b/polyp/cli-command.c index c11647fc..72e04bf8 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -56,6 +56,7 @@ struct command { unsigned args; }; +/* Prototypes for all available commands */ 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); @@ -87,6 +88,9 @@ static int pa_cli_command_autoload_remove(struct pa_core *c, struct pa_tokenizer static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); static int pa_cli_command_list_props(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); + +/* A method table for all available commands */ + static const struct command commands[] = { { "exit", pa_cli_command_exit, "Terminate the daemon", 1 }, { "help", pa_cli_command_help, "Show this help", 1 }, diff --git a/polyp/cli-command.h b/polyp/cli-command.h index 0f089f61..4887c55e 100644 --- a/polyp/cli-command.h +++ b/polyp/cli-command.h @@ -25,8 +25,17 @@ #include "strbuf.h" #include "core.h" +/* Execute a single CLI command. Write the results to the string + * buffer *buf. If *fail is non-zero the function will return -1 when + * one or more of the executed commands failed. If *verbose is + * non-zero the command is executed verbosely. Both *verbose and *fail + * may be modified by the function call. */ int pa_cli_command_execute_line(struct pa_core *c, const char *s, struct pa_strbuf *buf, int *fail, int *verbose); + +/* Execute a whole file of CLI commands */ int pa_cli_command_execute_file(struct pa_core *c, const char *fn, struct pa_strbuf *buf, int *fail, int *verbose); + +/* Split the specified string into lines and run pa_cli_command_execute_line() for each. */ int pa_cli_command_execute(struct pa_core *c, const char *s, struct pa_strbuf *buf, int *fail, int *verbose); #endif diff --git a/polyp/cli-text.h b/polyp/cli-text.h index 1457d055..65607e94 100644 --- a/polyp/cli-text.h +++ b/polyp/cli-text.h @@ -24,6 +24,9 @@ #include "core.h" +/* Some functions to generate pretty formatted listings of + * entities. The returned strings have to be freed manually. */ + char *pa_sink_input_list_to_string(struct pa_core *c); char *pa_source_output_list_to_string(struct pa_core *c); char *pa_sink_list_to_string(struct pa_core *core); diff --git a/polyp/cli.h b/polyp/cli.h index bfe0c4f8..44ed706c 100644 --- a/polyp/cli.h +++ b/polyp/cli.h @@ -28,9 +28,11 @@ struct pa_cli; +/* Create a new command line session on the specified io channel owned by the specified module */ struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io, struct pa_module *m); void pa_cli_free(struct pa_cli *cli); +/* Set a callback function that is called whenever the command line session is terminated */ void pa_cli_set_eof_callback(struct pa_cli *cli, void (*cb)(struct pa_cli*c, void *userdata), void *userdata); #endif diff --git a/polyp/client-conf-x11.h b/polyp/client-conf-x11.h index 951ef0b1..e65e8202 100644 --- a/polyp/client-conf-x11.h +++ b/polyp/client-conf-x11.h @@ -24,6 +24,8 @@ #include "client-conf.h" +/* Load client configuration data from the specified X11 display, + * overwriting the current settings in *c */ int pa_client_conf_from_x11(struct pa_client_conf *c, const char *display); #endif diff --git a/polyp/client-conf.c b/polyp/client-conf.c index 21e0acab..4906383d 100644 --- a/polyp/client-conf.c +++ b/polyp/client-conf.c @@ -82,6 +82,7 @@ int pa_client_conf_load(struct pa_client_conf *c, const char *filename) { char *fn = NULL; int r = -1; + /* Prepare the configuration parse table */ struct pa_config_item table[] = { { "daemon-binary", pa_config_parse_string, NULL }, { "extra-arguments", pa_config_parse_string, NULL }, diff --git a/polyp/client-conf.h b/polyp/client-conf.h index cf7dd095..b4625039 100644 --- a/polyp/client-conf.h +++ b/polyp/client-conf.h @@ -24,19 +24,29 @@ #include "native-common.h" +/* A structure containing configuration data for polypaudio clients. */ + struct pa_client_conf { char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server, *cookie_file; int autospawn; uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; - int cookie_valid; + int cookie_valid; /* non-zero, when cookie is valid */ }; +/* Create a new configuration data object and reset it to defaults */ struct pa_client_conf *pa_client_conf_new(void); void pa_client_conf_free(struct pa_client_conf *c); +/* Load the configuration data from the speicified file, overwriting + * the current settings in *c. When the filename is NULL, the + * default client configuration file name is used. */ int pa_client_conf_load(struct pa_client_conf *c, const char *filename); + +/* Load the configuration data from the environment of the current + process, overwriting the current settings in *c. */ int pa_client_conf_env(struct pa_client_conf *c); +/* Load cookie data from c->cookie_file into c->cookie */ int pa_client_conf_load_cookie(struct pa_client_conf* c); #endif diff --git a/polyp/client.c b/polyp/client.c index b525fe6b..22c7197a 100644 --- a/polyp/client.c +++ b/polyp/client.c @@ -42,7 +42,7 @@ struct pa_client *pa_client_new(struct pa_core *core, const char *protocol_name, c->name = pa_xstrdup(name); c->owner = NULL; c->core = core; - c->protocol_name = protocol_name; + c->protocol_name = pa_xstrdup(protocol_name); c->kill = NULL; c->userdata = NULL; @@ -68,6 +68,7 @@ void pa_client_free(struct pa_client *c) { pa_log(__FILE__": freed %u \"%s\"\n", c->index, c->name); pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index); pa_xfree(c->name); + pa_xfree(c->protocol_name); pa_xfree(c); } diff --git a/polyp/client.h b/polyp/client.h index 2518011e..58c5ee31 100644 --- a/polyp/client.h +++ b/polyp/client.h @@ -25,6 +25,10 @@ #include "core.h" #include "module.h" +/* Every connection to the server should have a pa_client + * attached. That way the user may generate a listing of all connected + * clients easily and kill them if he wants.*/ + struct pa_client { uint32_t index; @@ -37,6 +41,7 @@ struct pa_client { void *userdata; }; +/* Protocol name should be something like "ESOUND", "NATIVE", ... */ struct pa_client *pa_client_new(struct pa_core *c, const char *protocol_name, char *name); /* This function should be called only by the code that created the client */ @@ -46,6 +51,7 @@ void pa_client_free(struct pa_client *c); * request destruction of the client */ void pa_client_kill(struct pa_client *c); +/* Rename the client */ void pa_client_set_name(struct pa_client *c, const char *name); #endif diff --git a/polyp/cmdline.c b/polyp/cmdline.c index e11d8aad..a39f6ca6 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -35,6 +35,7 @@ #include "strbuf.h" #include "xmalloc.h" +/* Argument codes for getopt_long() */ enum { ARG_HELP = 256, ARG_VERSION, @@ -58,6 +59,7 @@ enum { ARG_CHECK }; +/* Tabel for getopt_long() */ static struct option long_options[] = { {"help", 0, 0, ARG_HELP}, {"version", 0, 0, ARG_VERSION}, diff --git a/polyp/cmdline.h b/polyp/cmdline.h index 28e7bdbc..ca100d1d 100644 --- a/polyp/cmdline.h +++ b/polyp/cmdline.h @@ -24,8 +24,12 @@ #include "daemon-conf.h" +/* Parese the command line and store its data in *c. Return the index + * of the first unparsed argument in *d. */ int pa_cmdline_parse(struct pa_daemon_conf*c, int argc, char *const argv [], int *d); +/* Show the command line help. The command name is extracted from + * argv[0] which should be passed in argv0. */ void pa_cmdline_help(const char *argv0); #endif diff --git a/polyp/conf-parser.c b/polyp/conf-parser.c index 40b00cda..35c4766e 100644 --- a/polyp/conf-parser.c +++ b/polyp/conf-parser.c @@ -32,6 +32,7 @@ #define WHITESPACE " \t\n" #define COMMENTS "#;\n" +/* Run the user supplied parser for an assignment */ static int next_assignment(const char *filename, unsigned line, const struct pa_config_item *t, const char *lvalue, const char *rvalue, void *userdata) { assert(filename && t && lvalue && rvalue); @@ -44,6 +45,7 @@ static int next_assignment(const char *filename, unsigned line, const struct pa_ return -1; } +/* Returns non-zero when c is contained in s */ static int in_string(char c, const char *s) { assert(s); @@ -54,6 +56,8 @@ static int in_string(char c, const char *s) { return 0; } +/* Remove all whitepsapce from the beginning and the end of *s. *s may + * be modified. */ static char *strip(char *s) { char *b = s+strspn(s, WHITESPACE); char *e, *l = NULL; @@ -68,6 +72,7 @@ static char *strip(char *s) { return b; } +/* Parse a variable assignment line */ static int parse_line(const char *filename, unsigned line, const struct pa_config_item *t, char *l, void *userdata) { char *e, *c, *b = l+strspn(l, WHITESPACE); @@ -88,7 +93,7 @@ static int parse_line(const char *filename, unsigned line, const struct pa_confi return next_assignment(filename, line, t, strip(b), strip(e), userdata); } - +/* Go through the file and parse each line */ int pa_config_parse(const char *filename, FILE *f, const struct pa_config_item *t, void *userdata) { int r = -1; unsigned line = 0; diff --git a/polyp/conf-parser.h b/polyp/conf-parser.h index 48cfbc14..9add0be0 100644 --- a/polyp/conf-parser.h +++ b/polyp/conf-parser.h @@ -24,14 +24,22 @@ #include +/* An abstract parser for simple, line based, shallow configuration + * files consisting of variable assignments only. */ + +/* Wraps info for parsing a specific configuration variable */ struct pa_config_item { - const char *lvalue; - int (*parse)(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); - void *data; + const char *lvalue; /* name of the variable */ + int (*parse)(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); /* Function that is called to parse the variable's value */ + void *data; /* Where to store the variable's data */ }; +/* The configuration file parsing routine. Expects a table of + * pa_config_items in *t that is terminated by an item where lvalue is + * NULL */ int pa_config_parse(const char *filename, FILE *f, const struct pa_config_item *t, void *userdata); +/* Generic parsers for integers, booleans and strings */ int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); diff --git a/polyp/core.h b/polyp/core.h index 09e58b46..6c6070b1 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -29,13 +29,20 @@ #include "memblock.h" #include "resampler.h" +/* The core structure of polypaudio. Every polypaudio daemon contains + * exactly one of these. It is used for storing kind of global + * variables for the daemon. */ + struct pa_core { struct pa_mainloop_api *mainloop; + /* idxset of all kinds of entities */ struct pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache, *autoload_idxset; + /* Some hashmaps for all sorts of entities */ struct pa_hashmap *namereg, *autoload_hashmap, *properties; + /* The name of the default sink/source */ char *default_source_name, *default_sink_name; struct pa_sample_spec default_sample_spec; @@ -60,6 +67,8 @@ struct pa_core { struct pa_core* pa_core_new(struct pa_mainloop_api *m); void pa_core_free(struct pa_core*c); + +/* Check whether noone is connected to this core */ void pa_core_check_quit(struct pa_core *c); #endif diff --git a/polyp/cpulimit-test.c b/polyp/cpulimit-test.c index 83d403f5..de5e20ad 100644 --- a/polyp/cpulimit-test.c +++ b/polyp/cpulimit-test.c @@ -4,21 +4,25 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include @@ -32,6 +36,8 @@ #include "mainloop-signal.h" #endif +/* A simple example for testing the cpulimit subsystem */ + static time_t start; #ifdef TEST2 diff --git a/polyp/cpulimit.c b/polyp/cpulimit.c index 78dc5e1f..0fab98a0 100644 --- a/polyp/cpulimit.c +++ b/polyp/cpulimit.c @@ -4,21 +4,25 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/polyp/daemon-conf.h b/polyp/daemon-conf.h index 8a574272..f163400f 100644 --- a/polyp/daemon-conf.h +++ b/polyp/daemon-conf.h @@ -24,16 +24,18 @@ #include "log.h" +/* The actual command to execute */ enum pa_daemon_conf_cmd { - PA_CMD_DAEMON, - PA_CMD_HELP, - PA_CMD_VERSION, - PA_CMD_DUMP_CONF, - PA_CMD_DUMP_MODULES, - PA_CMD_KILL, - PA_CMD_CHECK + PA_CMD_DAEMON, /* the default */ + PA_CMD_HELP, + PA_CMD_VERSION, + PA_CMD_DUMP_CONF, + PA_CMD_DUMP_MODULES, + PA_CMD_KILL, + PA_CMD_CHECK }; +/* A structure containing configuration data for the Polypaudio server . */ struct pa_daemon_conf { enum pa_daemon_conf_cmd cmd; int daemonize, @@ -52,13 +54,25 @@ struct pa_daemon_conf { char *config_file; }; +/* Allocate a new structure and fill it with sane defaults */ struct pa_daemon_conf* pa_daemon_conf_new(void); void pa_daemon_conf_free(struct pa_daemon_conf*c); +/* Load configuration data from the specified file overwriting the + * current settings in *c. If filename is NULL load the default daemon + * configuration file */ int pa_daemon_conf_load(struct pa_daemon_conf *c, const char *filename); + +/* Pretty print the current configuration data of the daemon. The + * returned string has to be freed manually. The output of this + * function may be parsed with pa_daemon_conf_load(). */ char *pa_daemon_conf_dump(struct pa_daemon_conf *c); + +/* Load the configuration data from the process' environment + * overwriting the current settings in *c. */ int pa_daemon_conf_env(struct pa_daemon_conf *c); +/* Set these configuration variables in the structure by passing a string */ int pa_daemon_conf_set_log_target(struct pa_daemon_conf *c, const char *string); int pa_daemon_conf_set_resample_method(struct pa_daemon_conf *c, const char *string); diff --git a/polyp/daemon.conf.in b/polyp/daemon.conf.in index ddc4955c..d5373018 100644 --- a/polyp/daemon.conf.in +++ b/polyp/daemon.conf.in @@ -60,8 +60,18 @@ ## true, otherwise to "stderr". ; log-target = auto -## The resampling algorithm to use. Use one of sinc-best-quality, -## sinc-medium-quality, sinc-fastest, zero-order-hold, linear. See -## the documentation of libsamplerate for an explanation fot the -## different methods. +## The resampling algorithm to use. Use one of src-sinc-best-quality, +## src-sinc-medium-quality, src-sinc-fastest, src-zero-order-hold, +## src-linear, trivial. See the documentation of libsamplerate for an +## explanation for the different methods. The method 'trivial' is the +## only algorithm implemented without usage of floating point +## numbers. If you're tight on CPU consider using this. On the other +## hand it has the worst quality of all. ; resample-method = sinc-fastest + +## Create a PID file in /tmp/polypaudio-$USER/pid. Of this is enabled +## you may use commands like "polypaudio --kill" or "polypaudio +## --check". If you are planning to start more than one polypaudio +## process per user, you better disable this option since it +## effectively disables multiple instances. +; use-pid-file = 1 diff --git a/polyp/default.pa.in b/polyp/default.pa.in index 07ff373c..3aaeeaf0 100755 --- a/polyp/default.pa.in +++ b/polyp/default.pa.in @@ -21,8 +21,8 @@ # Load audio drivers statically #load-module module-alsa-sink -load-module module-alsa-source device=plughw:1,0 -load-module module-oss device="/dev/dsp" sink_name=output source_name=input record=0 +# load-module module-alsa-source device=plughw:1,0 +load-module module-oss device="/dev/dsp" sink_name=output source_name=input #load-module module-oss-mmap device="/dev/dsp" sink_name=output source_name=input load-module module-null-sink #load-module module-pipe-sink @@ -37,11 +37,11 @@ load-module module-null-sink #add-autoload-source input module-alsa-source source_name=input # Load several protocols -load-module module-esound-protocol-tcp -#load-module module-simple-protocol-tcp +load-module module-esound-protocol-unix +#load-module module-esound-protocol-tcp load-module module-native-protocol-unix +#load-module module-simple-protocol-tcp #load-module module-cli-protocol-unix -#load-module module-esound-protocol-unix # Load the CLI module load-module module-cli @@ -54,10 +54,13 @@ set-default-source input # Load something to the sample cache load-sample x11-bell /usr/share/sounds/KDE_Notify.wav +load-sample-dir-lazy /usr/share/sounds/*.wav # Load X11 bell module load-module module-x11-bell sample=x11-bell sink=output +# Publish connection data in the X11 root window +load-module module-x11-publish + #load-module module-pipe-source #load-module module-pipe-sink - diff --git a/polyp/dumpmodules.h b/polyp/dumpmodules.h index c56d5abc..fadc571f 100644 --- a/polyp/dumpmodules.h +++ b/polyp/dumpmodules.h @@ -24,6 +24,8 @@ #include "daemon-conf.h" +/* Dump all available modules to STDOUT. If argc > 0 print information + * about the modules specified in argv[] instead. */ void pa_dump_modules(struct pa_daemon_conf *c, int argc, char * const argv[]); #endif diff --git a/polyp/gcc-printf.h b/polyp/gcc-printf.h index 224552af..70679df9 100644 --- a/polyp/gcc-printf.h +++ b/polyp/gcc-printf.h @@ -1,6 +1,29 @@ #ifndef foogccprintfhfoo #define foogccprintfhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* If we're in GNU C, use some magic for detecting invalid format strings */ + #ifdef __GNUC__ #define PA_GCC_PRINTF_ATTR(a,b) __attribute__ ((format (printf, a, b))) #else diff --git a/polyp/glib-mainloop.c b/polyp/glib-mainloop.c index aa81f82d..809c0b0f 100644 --- a/polyp/glib-mainloop.c +++ b/polyp/glib-mainloop.c @@ -106,6 +106,7 @@ static struct pa_io_event* glib_io_new(struct pa_mainloop_api*m, int fd, enum pa return e; } +/* The callback GLIB calls whenever an IO condition is met */ static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { struct pa_io_event *e = data; enum pa_io_event_flags f; diff --git a/polyp/glib12-mainloop.c b/polyp/glib12-mainloop.c index 2073c01d..5f037347 100644 --- a/polyp/glib12-mainloop.c +++ b/polyp/glib12-mainloop.c @@ -29,6 +29,8 @@ #include "idxset.h" #include "xmalloc.h" +/* A mainloop implementation based on GLIB 1.2 */ + struct pa_io_event { struct pa_glib_mainloop *mainloop; int dead; diff --git a/polyp/idxset.h b/polyp/idxset.h index 66689fd4..4c89eea1 100644 --- a/polyp/idxset.h +++ b/polyp/idxset.h @@ -24,41 +24,67 @@ #include -/* A combination of a hashtable and a dynamic array. Entries are both - * indexiable through a numeric automaticly generated index and an - * opaque key. As usual, memory management is the user's job. */ +/* A combination of a set and a dynamic array. Entries are indexable + * both through a numeric automatically generated index and the entry's + * data pointer. As usual, memory management is the user's job. */ +/* A special index value denoting the invalid index. */ #define PA_IDXSET_INVALID ((uint32_t) -1) +/* Generic implementations for hash and comparison functions. Just + * compares the pointer or calculates the hash value directly from the + * pointer value. */ unsigned pa_idxset_trivial_hash_func(const void *p); int pa_idxset_trivial_compare_func(const void *a, const void *b); +/* Generic implementations for hash and comparison functions for strings. */ unsigned pa_idxset_string_hash_func(const void *p); int pa_idxset_string_compare_func(const void *a, const void *b); struct pa_idxset; +/* Instantiate a new idxset with the specified hash and comparison functions */ struct pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); + +/* Free the idxset. When the idxset is not empty the specified function is called for every entry contained */ void pa_idxset_free(struct pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata); +/* Store a new item in the idxset. The index of the item is returned in *index */ int pa_idxset_put(struct pa_idxset*s, void *p, uint32_t *index); +/* Get the entry by its index */ void* pa_idxset_get_by_index(struct pa_idxset*s, uint32_t index); + +/* Get the entry by its data. The index is returned in *index */ void* pa_idxset_get_by_data(struct pa_idxset*s, const void *p, uint32_t *index); +/* Similar to pa_idxset_get_by_index(), but removes the entry from the idxset. */ void* pa_idxset_remove_by_index(struct pa_idxset*s, uint32_t index); + +/* Similar to pa_idxset_get_by_data(), but removes the entry from the idxset */ void* pa_idxset_remove_by_data(struct pa_idxset*s, const void *p, uint32_t *index); /* This may be used to iterate through all entries. When called with an invalid index value it returns the first entry, otherwise the next following. The function is best called with *index = - PA_IDXSET_VALID first. */ + PA_IDXSET_VALID first. It is safe to manipulate the idxset between + the calls. It is not guaranteed that all entries have already been + returned before the an entry is returned the second time.*/ void* pa_idxset_rrobin(struct pa_idxset *s, uint32_t *index); -/* Return the oldest entry in the idxset */ +/* Return the oldest entry in the idxset. Fill in its index in *index. */ void* pa_idxset_first(struct pa_idxset *s, uint32_t *index); + +/* Return the entry following the entry indexed by *index. After the + * call *index contains the index of the returned + * object. pa_idxset_first() and pa_idxset_next() may be used to + * iterate through the set.*/ void *pa_idxset_next(struct pa_idxset *s, uint32_t *index); +/* Call a function for every item in the set. If the callback function + returns -1, the loop is terminated. If *del is set to non-zero that + specific item is removed. It is not safe to call any other + functions on the idxset while pa_idxset_foreach is executed. */ int pa_idxset_foreach(struct pa_idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata); unsigned pa_idxset_ncontents(struct pa_idxset*s); diff --git a/polyp/iochannel.h b/polyp/iochannel.h index f8efc928..2a1ba370 100644 --- a/polyp/iochannel.h +++ b/polyp/iochannel.h @@ -25,10 +25,23 @@ #include #include "mainloop-api.h" -/* It is safe to destroy the calling iochannel object from the callback */ +/* A wrapper around UNIX file descriptors for attaching them to the a + main event loop. Everytime new data may be read or be written to + the channel a callback function is called. It is safe to destroy + the calling iochannel object from the callback */ + +/* When pa_iochannel_is_readable() returns non-zero, the user has to + * call this function in a loop until it is no longer set or EOF + * reached. Otherwise strange things may happen when an EOF is + * reached. */ struct pa_iochannel; +/* Create a new IO channel for the specified file descriptors for +input resp. output. It is safe to pass the same file descriptor for +both parameters (in case of full-duplex channels). For a simplex +channel specify -1 for the other direction. */ + struct pa_iochannel* pa_iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd); void pa_iochannel_free(struct pa_iochannel*io); @@ -39,11 +52,17 @@ int pa_iochannel_is_readable(struct pa_iochannel*io); int pa_iochannel_is_writable(struct pa_iochannel*io); int pa_iochannel_is_hungup(struct pa_iochannel*io); +/* Don't close the file descirptors when the io channel is freed. By + * default the file descriptors are closed. */ void pa_iochannel_set_noclose(struct pa_iochannel*io, int b); +/* Set the callback function that is called whenever data becomes available for read or write */ void pa_iochannel_set_callback(struct pa_iochannel*io, void (*callback)(struct pa_iochannel*io, void *userdata), void *userdata); +/* In case the file descriptor is a socket, return a pretty-printed string in *s which describes the peer connected */ void pa_iochannel_socket_peer_to_string(struct pa_iochannel*io, char*s, size_t l); + +/* Use setsockopt() to tune the recieve and send buffers of TCP sockets */ int pa_iochannel_socket_set_rcvbuf(struct pa_iochannel*io, size_t l); int pa_iochannel_socket_set_sndbuf(struct pa_iochannel*io, size_t l); diff --git a/polyp/ioline.h b/polyp/ioline.h index 5adc0560..f652dddb 100644 --- a/polyp/ioline.h +++ b/polyp/ioline.h @@ -24,6 +24,10 @@ #include "iochannel.h" +/* An ioline wraps an iochannel for line based communication. A + * callback function is called whenever a new line has been recieved + * from the client */ + struct pa_ioline; struct pa_ioline* pa_ioline_new(struct pa_iochannel *io); @@ -31,7 +35,10 @@ void pa_ioline_unref(struct pa_ioline *l); struct pa_ioline* pa_ioline_ref(struct pa_ioline *l); void pa_ioline_close(struct pa_ioline *l); +/* Write a string to the channel */ void pa_ioline_puts(struct pa_ioline *s, const char *c); + +/* Set the callback function that is called for every recieved line */ void pa_ioline_set_callback(struct pa_ioline*io, void (*callback)(struct pa_ioline*io, const char *s, void *userdata), void *userdata); #endif diff --git a/polyp/llist.h b/polyp/llist.h index c48c5c6e..eb8cd017 100644 --- a/polyp/llist.h +++ b/polyp/llist.h @@ -7,33 +7,41 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ +/* Some macros for maintaining doubly linked lists */ + +/* The head of the linked list. Use this in the structure that shall + * contain the head of the linked list */ #define PA_LLIST_HEAD(t,name) t *name +/* The pointers in the linked list's items. Use this in the item structure */ #define PA_LLIST_FIELDS(t) t *next, *prev +/* Initialize the list's head */ #define PA_LLIST_HEAD_INIT(t,item) do { (item) = NULL; } while(0) +/* Initialize a list item */ #define PA_LLIST_INIT(t,item) do { \ t *_item = (item); \ assert(_item); \ _item->prev = _item->next = NULL; \ } while(0) +/* Prepend an item to the list */ #define PA_LLIST_PREPEND(t,head,item) do { \ t **_head = &(head), *_item = (item); \ assert(_item); \ @@ -43,6 +51,7 @@ *_head = _item; \ } while (0) +/* Remove an item from the list */ #define PA_LLIST_REMOVE(t,head,item) do { \ t **_head = &(head), *_item = (item); \ assert(_item); \ diff --git a/polyp/log.c b/polyp/log.c index 516cd2b0..dc41dcd2 100644 --- a/polyp/log.c +++ b/polyp/log.c @@ -1,3 +1,28 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include @@ -43,6 +68,8 @@ void pa_log(const char *format, ...) { user_log_func(t); pa_xfree(t); } + case PA_LOG_NULL: + break; } va_end(ap); diff --git a/polyp/log.h b/polyp/log.h index 46a86491..cf55386c 100644 --- a/polyp/log.h +++ b/polyp/log.h @@ -1,17 +1,46 @@ #ifndef foologhfoo #define foologhfoo +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + #include "gcc-printf.h" +/* A simple logging subsystem */ + +/* Where to log to */ enum pa_log_target { + PA_LOG_STDERR, /* default */ PA_LOG_SYSLOG, - PA_LOG_STDERR, - PA_LOG_USER + PA_LOG_USER, /* to user specified function */ + PA_LOG_NULL /* to /dev/null */ }; +/* Set an identifcation for the current daemon. Used when logging to syslog. */ void pa_log_set_ident(const char *p); + +/* Set another log target. If t is PA_LOG_USER you may specify a function that is called every log string */ void pa_log_set_target(enum pa_log_target t, void (*func)(const char*s)); - + +/* Do a log line */ void pa_log(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); #endif diff --git a/polyp/mcalign-test.c b/polyp/mcalign-test.c index ab1f9aed..f8af4f9f 100644 --- a/polyp/mcalign-test.c +++ b/polyp/mcalign-test.c @@ -1,3 +1,28 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include @@ -9,6 +34,8 @@ #include "util.h" #include "mcalign.h" +/* A simple program for testing pa_mcalign */ + int main(int argc, char *argv[]) { struct pa_mcalign *a = pa_mcalign_new(11, NULL); struct pa_memchunk c; diff --git a/polyp/memblock.h b/polyp/memblock.h index 91612ac9..8555954c 100644 --- a/polyp/memblock.h +++ b/polyp/memblock.h @@ -25,30 +25,54 @@ #include #include -enum pa_memblock_type { PA_MEMBLOCK_FIXED, PA_MEMBLOCK_APPENDED, PA_MEMBLOCK_DYNAMIC, PA_MEMBLOCK_USER }; +/* A pa_memblock is a reference counted memory block. Polypaudio + * passed references to pa_memblocks around instead of copying + * data. See pa_memchunk for a structure that describes parts of + * memory blocks. */ +/* The type of memory this block points to */ +enum pa_memblock_type { + PA_MEMBLOCK_FIXED, /* data is a pointer to fixed memory that needs not to be freed */ + PA_MEMBLOCK_APPENDED, /* The most common kind: the data is appended to the memory block */ + PA_MEMBLOCK_DYNAMIC, /* data is a pointer to some memory allocated with pa_xmalloc() */ + PA_MEMBLOCK_USER /* User supplied memory, to be freed with free_cb */ +}; + +/* A structure of keeping memory block statistics */ struct pa_memblock_stat; struct pa_memblock { enum pa_memblock_type type; - unsigned ref; - int read_only; + unsigned ref; /* the reference counter */ + int read_only; /* boolean */ size_t length; void *data; - void (*free_cb)(void *p); + void (*free_cb)(void *p); /* If type == PA_MEMBLOCK_USER this points to a function for freeing this memory block */ struct pa_memblock_stat *stat; }; +/* Allocate a new memory block of type PA_MEMBLOCK_APPENDED */ struct pa_memblock *pa_memblock_new(size_t length, struct pa_memblock_stat*s); + +/* Allocate a new memory block of type PA_MEMBLOCK_DYNAMIC. The pointer data is to be maintained be the memory block */ struct pa_memblock *pa_memblock_new_dynamic(void *data, size_t length, struct pa_memblock_stat*s); + +/* Allocate a new memory block of type PA_MEMBLOCK_FIXED */ struct pa_memblock *pa_memblock_new_fixed(void *data, size_t length, int read_only, struct pa_memblock_stat*s); + +/* Allocate a new memory block of type PA_MEMBLOCK_USER */ struct pa_memblock *pa_memblock_new_user(void *data, size_t length, void (*free_cb)(void *p), int read_only, struct pa_memblock_stat*s); void pa_memblock_unref(struct pa_memblock*b); struct pa_memblock* pa_memblock_ref(struct pa_memblock*b); +/* This special unref function has to be called by the owner of the +memory of a static memory block when he wants to release all +references to the memory. This causes the memory to be copied and +converted into a PA_MEMBLOCK_DYNAMIC type memory block */ void pa_memblock_unref_fixed(struct pa_memblock*b); +/* Matinatins statistics about memory blocks */ struct pa_memblock_stat { int ref; unsigned total; diff --git a/polyp/memblockq.h b/polyp/memblockq.h index 95e5c533..2c762bf4 100644 --- a/polyp/memblockq.h +++ b/polyp/memblockq.h @@ -7,17 +7,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -27,6 +27,12 @@ #include "memblock.h" #include "memchunk.h" +/* A memblockq is a queue of pa_memchunks (yepp, the name is not + * perfect). It is similar to the ring buffers used by most other + * audio software. In contrast to a ring buffer this memblockq data + * type doesn't need to copy any data around, it just maintains + * references to reference counted memory blocks. */ + struct pa_memblockq; /* Parameters: diff --git a/polyp/modargs.c b/polyp/modargs.c index 01a694cf..406f610f 100644 --- a/polyp/modargs.c +++ b/polyp/modargs.c @@ -44,7 +44,7 @@ struct entry { char *key, *value; }; -static int add_key_value(struct pa_hashmap *map, char *key, char *value, const char* const* valid_keys) { +static int add_key_value(struct pa_hashmap *map, char *key, char *value, const char* const valid_keys[]) { struct entry *e; assert(map && key && value); diff --git a/polyp/modargs.h b/polyp/modargs.h index 53753ba7..07db6ae5 100644 --- a/polyp/modargs.h +++ b/polyp/modargs.h @@ -28,14 +28,22 @@ struct pa_modargs; -struct pa_modargs *pa_modargs_new(const char *args, const char* const* keys); +/* A generic parser for module arguments */ + +/* Parse the string args. The NULL-terminated array keys contains all valid arguments. */ +struct pa_modargs *pa_modargs_new(const char *args, const char* const keys[]); void pa_modargs_free(struct pa_modargs*ma); +/* Return the module argument for the specified name as a string. If + * the argument was not specified, return def instead.*/ const char *pa_modargs_get_value(struct pa_modargs *ma, const char *key, const char *def); + +/* Return a module argument as unsigned 32bit value in *value */ int pa_modargs_get_value_u32(struct pa_modargs *ma, const char *key, uint32_t *value); int pa_modargs_get_value_s32(struct pa_modargs *ma, const char *key, int32_t *value); int pa_modargs_get_value_boolean(struct pa_modargs *ma, const char *key, int *value); +/* Return sample spec data from the three arguments "rate", "format" and "channels" */ int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *ss); #endif diff --git a/polyp/modinfo.c b/polyp/modinfo.c index a1328be6..a96bb17e 100644 --- a/polyp/modinfo.c +++ b/polyp/modinfo.c @@ -4,17 +4,17 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. polypaudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/polyp/modinfo.h b/polyp/modinfo.h index d6f7c6de..9da9dc4e 100644 --- a/polyp/modinfo.h +++ b/polyp/modinfo.h @@ -22,6 +22,8 @@ USA. ***/ +/* Some functions for reading module meta data from Polypaudio modules */ + struct pa_modinfo { char *author; char *description; @@ -29,9 +31,13 @@ struct pa_modinfo { char *version; }; +/* Read meta data from an libtool handle */ struct pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl); + +/* Read meta data from a module file */ struct pa_modinfo *pa_modinfo_get_by_name(const char *name); +/* Free meta data */ void pa_modinfo_free(struct pa_modinfo *i); #endif diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c index 2b36ce27..39aaab57 100644 --- a/polyp/module-tunnel.c +++ b/polyp/module-tunnel.c @@ -554,7 +554,7 @@ static int load_key(struct userdata *u, const char*fn) { if (!fn) fn = PA_NATIVE_COOKIE_FILE; - if (pa_authkey_load_from_home(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) + if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) return -1; pa_log(__FILE__": loading cookie from disk.\n"); diff --git a/polyp/module-x11-publish.c b/polyp/module-x11-publish.c index acf37759..598fe5b5 100644 --- a/polyp/module-x11-publish.c +++ b/polyp/module-x11-publish.c @@ -86,7 +86,7 @@ static int load_key(struct userdata *u, const char*fn) { if (!fn) fn = PA_NATIVE_COOKIE_FILE; - if (pa_authkey_load_from_home(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) + if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) return -1; pa_log(__FILE__": loading cookie from disk.\n"); diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index e4831e4d..84d4efe8 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -2066,7 +2066,7 @@ static int load_key(struct pa_protocol_native*p, const char*fn) { if (!fn) fn = PA_NATIVE_COOKIE_FILE; - if (pa_authkey_load_from_home(fn, p->auth_cookie, sizeof(p->auth_cookie)) < 0) + if (pa_authkey_load_auto(fn, p->auth_cookie, sizeof(p->auth_cookie)) < 0) return -1; pa_log(__FILE__": loading cookie from disk.\n"); -- cgit From 9f23c8f36299635f78475ee9e90b0a20c5cf3b84 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Nov 2004 22:07:47 +0000 Subject: Documentation updates git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@310 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/FAQ.html.in | 9 ++++++--- doc/Makefile.am | 10 +++++----- doc/README.html.in | 52 +++++++++++++++++++++++++++++++--------------------- doc/cli.html.in | 8 +++++++- doc/daemon.html.in | 34 +++++++++++++++++++++++++--------- doc/modules.html.in | 22 +++++++++++++++++++++- doc/todo | 7 ++----- 7 files changed, 97 insertions(+), 45 deletions(-) diff --git a/doc/FAQ.html.in b/doc/FAQ.html.in index 751ef562..9cacfb4c 100644 --- a/doc/FAQ.html.in +++ b/doc/FAQ.html.in @@ -126,9 +126,11 @@ connect to a running polypaudio daemon try using the following commands:

    killall -USR2 polypaudio
     bidilink unix-client:/tmp/polypaudio/cli
    -

    BTW: Someone should package that great tool for Debian!

    +

    BTW: Someone should package that great tool for Debian!

    +

    New: There's now a tool pacmd that automates sending SIGUSR2 to the daemon and running a bidilink like tool for you.

    +
  • How do the polypaudio libraries decide where to connect to?

    The following rule applies:

    @@ -142,10 +144,11 @@ bidilink unix-client:/tmp/polypaudio/cli
  • If $DISPLAY is set, the library tries to connect to the default TCP port of that host. If the connection fails, it proceeds with the next item.
  • The connection fails.
  • -

    - +
  • Why the heck does libpolyp link against libX11?

    +

    The Polypaudio client libraries look for some X11 root window properties for the credentials of the Polypaudio server to access. You may compile Polypaudio without X11 for disabling this.

  • +
    diff --git a/doc/Makefile.am b/doc/Makefile.am index 17688d3b..001f5b49 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -30,11 +30,11 @@ CLEANFILES += README endif tidy: README.html cli.html modules.html daemon.html - tidy -e < README.html - tidy -e < cli.html - tidy -e < daemon.html - tidy -e < modules.html - tidy -e < FAQ.html + tidy -qe < README.html + tidy -qe < cli.html + tidy -qe < daemon.html + tidy -qe < modules.html + tidy -qe < FAQ.html .PHONY: tidy diff --git a/doc/README.html.in b/doc/README.html.in index 31511886..eb57fdb7 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -44,15 +44,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    Sun Nov 21 2004:

    Version 0.7 released; -changes include: TCP wrappers support; don't load the complete sound -file into memory when playing back using pa_play_file(); -autoload API change; don't load all sound files as FLOAT32; shorten -default buffers; client-side latency interpolation; add new user -volume metrics; add module-tunnel, module-null-sink, -module-match and new tool paplay; new API version -macros; many client API improvements; correctly lock cookie file -generation; correctly lock daemon autospawning; print daemon layout to -STDERR on SIGHUP; new options for pacat: allow sample type specification.

    +changes include: IPv6 support; PID file support; publish credentials +in X11 root window (module-x11-publish; new tool pacmd; ESOUND backend; new command load-sample-dir-lazy; many, many minor fixes.

    Thu Oct 28 2004:

    Version 0.6 released; @@ -103,8 +96,9 @@ href="@PACKAGE_URL@polypaudio-0.1.tar.gz">Version 0.1 released

    operating systems. It is intended to be an improved drop-in replacement for the Enlightened Sound -Daemon (ESOUND). In addition to the features ESOUND provides -polypaudio has:

    +Daemon (ESOUND). It is my ultimate ambition to get Polypaudio into +Gnome as a replacement for ESOUND. In +addition to the features ESOUND provides polypaudio has:

    • Extensible plugin architecture (by loading dynamic loadable modules with dlopen())
    • @@ -139,13 +133,15 @@ available. A simple main loop implementation is available as well.

    • module-combine: combine multiple sinks into one.
    • module-sine: a sine generate sink input.
    • module-x11-bell: play a sample from the sample cache on every X11 bell event.
    • -
    • module-esound-protocol-tcp, module-esound-protocol-unix: ESOUND compatibility modules (for TCP/IP resp. UNIX domain sockets)
    • -
    • module-native-protocol-tcp, module-native-protocol-unix: Native polypaudio protocol (for TCP/IP resp. UNIX domain sockets)
    • -
    • module-simple-protocol-tcp, module-simple-protocol-unix: Simplistic protocol for playback/capture for usage with tools like netcat (for TCP/IP resp. UNIX domain sockets)
    • -
    • module-cli-protocol-tcp, module-cli-protocol-unix, module-cli: Expose polypaudio's internals whith a simple command line interface. (for TCP/IP resp. UNIX domain sockets resp. STDIN/STDOUT)
    • +
    • module-x11-publish: store Polypaudio credentials in the X11 root window.
    • +
    • module-esound-protocol-tcp, module-esound-protocol-tcp6, module-esound-protocol-unix: ESOUND compatibility modules (for TCP/IPv6 resp. TCP/IPv6 resp. UNIX domain sockets)
    • +
    • module-native-protocol-tcp, module-native-protocol-tcp6, module-native-protocol-unix: Native polypaudio protocol (for TCP/IPv4 resp. TCP/IPv6 resp. UNIX domain sockets)
    • +
    • module-simple-protocol-tcp, module-simple-protocol-tcp6, module-simple-protocol-unix: Simplistic protocol for playback/capture for usage with tools like netcat (for TCP/IP resp. UNIX domain sockets)
    • +
    • module-cli-protocol-tcp, module-cli-protocol-tcp6, module-cli-protocol-unix, module-cli: Expose polypaudio's internals whith a simple command line interface. (for TCP/IP resp. UNIX domain sockets resp. STDIN/STDOUT)
    • module-tunnel-sink, module-tunnel-source: make sinks/sources from other hosts available locally.
    • module-match: adjust volume automatically for newly created playback streams based on a regular expression matching table.
    • module-null-sink: a clocked sink similar to /dev/null.
    • +
    • module-esound-sink: a sink for forwarding audio data to an ESOUND server.

    polypaudio is the successor of my previous, ill-fated @@ -156,10 +152,18 @@ href="http://asd.sf.net/">asd.

    href="http://0pointer.de/lennart/projects/paman/">Polypaudio Manager. Another GTK GUI tool for Polypaudio is the Polypaudio Volume -Meter. There are output plugins for .

    + +

    There are output plugins for XMMS, libao and gstreamer. Drivers -for MPlayer and PortAudio will be released shortly.

    +href="http://0pointer.de/lennart/projects/libao-polyp/">libao +(merged in libao SVN) and gstreamer +(merged in gstreamer-plugins CVS), MPlayer (merged in MPlayer CVS) and Xine (merged in Xine CVS). Drivers for +PortAudio will be released +shortly.

    Status

    @@ -227,10 +231,10 @@ questions.

    Requirements

    -

    Currently, polypaudio is tested on Linux only. It requires an OSS or ALSA compatible soundcard.

    +

    Currently, polypaudio is tested on Linux and FreeBSD only. It requires an OSS or ALSA compatible soundcard.

    polypaudio was developed and tested on Debian GNU/Linux -"testing" from July 2004, it should work on most other Linux +"testing" from November 2004, it should work on most other Linux distributions (and maybe Unix versions) since it uses GNU autoconf and GNU libtool for source code configuration and shared library management.

    @@ -255,6 +259,12 @@ compilation and make install (as root) for installation of

    Eric B. Mitchell for writing ESOUND

    +

    Jeff Waugh for creating Ubuntu packages (and hopefully soon Debian)

    + +

    Miguel Freitas for writing a Polypaudio driver for Xine

    + +

    Joe Marcus Clarke for porting Polypaudio to FreeBSD

    +

    Download

    The newest release is always available from @PACKAGE_URL@

    @@ -272,7 +282,7 @@ compilation and make install (as root) for installation of

    New! There is now a Polypaudio wiki (based on trac) available.


    -
    Lennart Poettering <@PACKAGE_BUGREPORT@>, October 2004
    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, November 2004
    $Id$
    diff --git a/doc/cli.html.in b/doc/cli.html.in index 49e568f8..61d29e5a 100644 --- a/doc/cli.html.in +++ b/doc/cli.html.in @@ -112,6 +112,12 @@ immediately. The sample is loaded only when it is first used. After a certain idle time it is freed again. Expects the the desired sample name and file name to load as arguments.

    +

    load-sample-dir-lazy

    + +

    Load all entries in the specified directory into the sample cache +as lazy entries. A shell globbing expression (e.g. *.wav) may +be appended to the path of the directory to add.

    +

    Module Autoloading

    list-autoload

    @@ -203,6 +209,6 @@ play-file /usr/share/sounds/startup3.wav combined
    -
    Lennart Poettering <@PACKAGE_BUGREPORT@>, September 2004
    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, November 2004
    $Id$
    diff --git a/doc/daemon.html.in b/doc/daemon.html.in index 8d2414c0..a4db0bd7 100644 --- a/doc/daemon.html.in +++ b/doc/daemon.html.in @@ -14,26 +14,42 @@ The polypaudio daemon accepts several command line arguments:
    +COMMANDS:
       -h, --help                            Show this help
           --version                         Show version
           --dump-conf                       Dump default configuration
           --dump-modules                    Dump list of available modules
    +  -k  --kill                            Kill a running daemon
    +      --check                           Check for a running daemon
     
    +OPTIONS:
       -D, --daemonize[=BOOL]                Daemonize after startup
           --fail[=BOOL]                     Quit when startup fails
           --verbose[=BOOL]                  Be slightly more verbose
    -      --high-priority[=BOOL]            Try to set high process priority (only available as root)
    +      --high-priority[=BOOL]            Try to set high process priority
    +                                        (only available as root)
           --disallow-module-loading[=BOOL]  Disallow module loading after startup
    -      --exit-idle-time=SECS             Terminate the daemon when idle and this time passed
    -      --module-idle-time=SECS           Unload autoloaded modules when idle and this time passed
    -      --scache-idle-time=SECS           Unload autoloaded samples when idle and this time passed
    +      --exit-idle-time=SECS             Terminate the daemon when idle and this
    +                                        time passed
    +      --module-idle-time=SECS           Unload autoloaded modules when idle and
    +                                        this time passed
    +      --scache-idle-time=SECS           Unload autoloaded samples when idle and
    +                                        this time passed
           --log-target={auto,syslog,stderr} Specify the log target
    -  -p, --dl-search-path=PATH             Set the search path for dynamic shared objects (plugins)
    +  -p, --dl-search-path=PATH             Set the search path for dynamic shared
    +                                        objects (plugins)
           --resample-method=[METHOD]        Use the specified resampling method
    -
    -  -L, --load="MODULE ARGUMENTS"         Load the specified plugin module with the specified argument
    +                                        (one of src-sinc-medium-quality,
    +                                        src-sinc-best-quality,src-sinc-fastest
    +                                        src-zero-order-hold,src-linear,trivial)
    +      --use-pid-file[=BOOL]             Create a PID file
    +
    +STARTUP SCRIPT:
    +  -L, --load="MODULE ARGUMENTS"         Load the specified plugin module with
    +                                        the specified argument
       -F, --file=FILENAME                   Run the specified script
    -  -C                                    Open a command line on the running TTY after startup (identical to -Lmodule-cli)
    +  -C                                    Open a command line on the running TTY
    +                                        after startup
     
       -n                                    Don't load default script file
     
    @@ -67,6 +83,6 @@ The polypaudio daemon accepts several command line arguments:

    The daemon logs the current server layout.


    -
    Lennart Poettering <@PACKAGE_BUGREPORT@>, September 2004
    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, November 2004
    $Id$
    diff --git a/doc/modules.html.in b/doc/modules.html.in index 14fe7278..a549396d 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -267,6 +267,26 @@ about the two possible suffixes of this module.

    sink=Name of the sink to play the sample on. If ommited defaults to the default sink. +

    module-x11-publish

    + +

    Publishes the access credentials to the Polypaudio server in the +X11 root window. The following properties are used: +POLYP_SERVER, POYLP_SINK, POLYP_SOURCE, +POLYP_COOKIE. This is very useful when using SSH or any other +remote login tool for logging into other machines and getting audio +playback to your local speakers. The Polypaudio client libraries make +use of this data automatically. Instead of using this module you may +use the tool pax11publish which may be used to access, modify +and import credential data from/to the X11 display.

    + + + + + +
    display=X11 display to connect to. If ommited defaults to the value of $DISPLAY
    sink=Name of the default sink. If ommited this property isn't stored in the X11 display.
    source=Name of the default source. If ommited this property isn't stored in the X11 display.
    cookie=Name of the cookie file of the +cookie to store in the X11 display. If ommited the cookie of an +already loaded protocol module is used.
    +

    module-sine

    Creates a sink input and generates a sine waveform stream.

    @@ -301,6 +321,6 @@ about the two possible suffixes of this module.

    The volumes of all streams with titles starting with sample: are automatically set to 25. (FYI: All sample cache streams start with sample:)


    -
    Lennart Poettering <@PACKAGE_BUGREPORT@>, September 2004
    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, November 2004
    $Id$
    diff --git a/doc/todo b/doc/todo index 3e30af4f..d6cfb01a 100644 --- a/doc/todo +++ b/doc/todo @@ -1,10 +1,7 @@ *** $Id$ *** -*** 0.7 **** -- limit all resources -- commenting - -** later *** +*** later **** +- event more commenting - polish for starting polypaudio as root/system-wide instance - per-channel volume - improve module-oss-mmap latency measurement -- cgit From c827fca3b9ad589c970c08d792d62e283a8a7852 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Nov 2004 22:25:28 +0000 Subject: prepare for release git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@311 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- configure.ac | 5 +- doc/Makefile.am | 10 +- libtool.m4 | 5951 +++++++++++++++++++++++++++++++++++++++++++++++++++++ ltdl.m4 | 431 ++++ polyp/Makefile.am | 2 +- 6 files changed, 6393 insertions(+), 8 deletions(-) create mode 100644 libtool.m4 create mode 100644 ltdl.m4 diff --git a/Makefile.am b/Makefile.am index 9b419d1d..91f9740b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,7 +17,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -EXTRA_DIST = bootstrap.sh README LICENSE doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in +EXTRA_DIST = bootstrap.sh README LICENSE doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in libtool.m4 ltdl.m4 SUBDIRS=polyp doc libltdl MAINTAINERCLEANFILES=README diff --git a/configure.ac b/configure.ac index 332570dd..47f965e0 100644 --- a/configure.ac +++ b/configure.ac @@ -77,13 +77,16 @@ AC_FUNC_MMAP AC_FUNC_REALLOC AC_FUNC_SETPGRP AC_FUNC_VPRINTF +AC_FUNC_CLOSEDIR_VOID +AC_FUNC_SELECT_ARGTYPES AC_TYPE_SIGNAL AC_TYPE_UID_T -AC_CHECK_FUNCS([gethostname gettimeofday memchr memmove memset mkdir mkfifo munmap rmdir socket strcspn strerror strrchr strspn strstr strtol strtoul strcasecmp putenv strchr strpbrk strdup getgrgid_r getpwuid_r regcomp]) +AC_CHECK_FUNCS([gethostname gettimeofday memchr memmove memset mkdir mkfifo munmap rmdir socket strcspn strerror strrchr strspn strstr strtol strtoul strcasecmp putenv strchr strpbrk strdup getgrgid_r getpwuid_r regcomp ftruncate select]) AC_CHECK_LIB(m, pow) AC_CHECK_FUNCS(pow) AC_FUNC_STAT AC_HEADER_SYS_WAIT +AC_HEADER_DIRENT AC_C_BIGENDIAN AC_FUNC_GETGROUPS diff --git a/doc/Makefile.am b/doc/Makefile.am index 001f5b49..f67598f1 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -30,11 +30,11 @@ CLEANFILES += README endif tidy: README.html cli.html modules.html daemon.html - tidy -qe < README.html - tidy -qe < cli.html - tidy -qe < daemon.html - tidy -qe < modules.html - tidy -qe < FAQ.html + tidy -qe < README.html ; true + tidy -qe < cli.html ; true + tidy -qe < daemon.html ; true + tidy -qe < modules.html ; true + tidy -qe < FAQ.html ; true .PHONY: tidy diff --git a/libtool.m4 b/libtool.m4 new file mode 100644 index 00000000..4f5ac795 --- /dev/null +++ b/libtool.m4 @@ -0,0 +1,5951 @@ +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +## Copyright 1996, 1997, 1998, 1999, 2000, 2001 +## Free Software Foundation, Inc. +## Originally by Gordon Matzigkeit , 1996 +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +## As a special exception to the GNU General Public License, if you +## distribute this file as part of a program that contains a +## configuration script generated by Autoconf, you may include it under +## the same distribution terms that you use for the rest of that program. + +# serial 47 AC_PROG_LIBTOOL +# Debian $Rev: 214 $ + + +# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED) +# ----------------------------------------------------------- +# If this macro is not defined by Autoconf, define it here. +m4_ifdef([AC_PROVIDE_IFELSE], + [], + [m4_define([AC_PROVIDE_IFELSE], + [m4_ifdef([AC_PROVIDE_$1], + [$2], [$3])])]) + + +# AC_PROG_LIBTOOL +# --------------- +AC_DEFUN([AC_PROG_LIBTOOL], +[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl +dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX +dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. + AC_PROVIDE_IFELSE([AC_PROG_CXX], + [AC_LIBTOOL_CXX], + [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX + ])]) +dnl And a similar setup for Fortran 77 support + AC_PROVIDE_IFELSE([AC_PROG_F77], + [AC_LIBTOOL_F77], + [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77 +])]) + +dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. +dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run +dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. + AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [ifdef([AC_PROG_GCJ], + [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([A][M_PROG_GCJ], + [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([LT_AC_PROG_GCJ], + [define([LT_AC_PROG_GCJ], + defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])]) +])])# AC_PROG_LIBTOOL + + +# _AC_PROG_LIBTOOL +# ---------------- +AC_DEFUN([_AC_PROG_LIBTOOL], +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl +AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl +AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl +AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +# Prevent multiple expansion +define([AC_PROG_LIBTOOL], []) +])# _AC_PROG_LIBTOOL + + +# AC_LIBTOOL_SETUP +# ---------------- +AC_DEFUN([AC_LIBTOOL_SETUP], +[AC_PREREQ(2.50)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl +AC_REQUIRE([AC_PROG_NM])dnl + +AC_REQUIRE([AC_PROG_LN_S])dnl +AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! +AC_REQUIRE([AC_OBJEXT])dnl +AC_REQUIRE([AC_EXEEXT])dnl +dnl + +AC_LIBTOOL_SYS_MAX_CMD_LEN +AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +AC_LIBTOOL_OBJDIR + +AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +_LT_AC_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e s/^X//' +[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] + +# Same as above, but do not quote variable references. +[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except M$VC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" + +AC_CHECK_TOOL(AR, ar, false) +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(STRIP, strip, :) + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$SED" && SED=sed +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds" + ;; + *) + old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + AC_PATH_MAGIC + fi + ;; +esac + +AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +enable_win32_dll=yes, enable_win32_dll=no) + +AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +AC_ARG_WITH([pic], + [AC_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) +test -z "$pic_mode" && pic_mode=default + +# Use C for the default configuration in the libtool script +tagname= +AC_LIBTOOL_LANG_C_CONFIG +_LT_AC_TAGCONFIG +])# AC_LIBTOOL_SETUP + + +# _LT_AC_SYS_COMPILER +# ------------------- +AC_DEFUN([_LT_AC_SYS_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_AC_SYS_COMPILER + + +# _LT_AC_SYS_LIBPATH_AIX +# ---------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX], +[AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_AC_SYS_LIBPATH_AIX + + +# _LT_AC_SHELL_INIT(ARG) +# ---------------------- +AC_DEFUN([_LT_AC_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_AC_SHELL_INIT + + +# _LT_AC_PROG_ECHO_BACKSLASH +# -------------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], +[_LT_AC_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +echo=${ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null && + echo_test_string="`eval $cmd`" && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(ECHO) +])])# _LT_AC_PROG_ECHO_BACKSLASH + + +# _LT_AC_LOCK +# ----------- +AC_DEFUN([_LT_AC_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case "`/usr/bin/file conftest.o`" in + *32-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw* | *-*-pw32*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; + ]) +esac + +need_locks="$enable_libtool_lock" + +])# _LT_AC_LOCK + + +# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], +[AC_REQUIRE([LT_AC_PROG_SED]) +AC_CACHE_CHECK([$1], [$2], + [$2=no + ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s conftest.err; then + $2=yes + fi + fi + $rm conftest* +]) + +if test x"[$]$2" = xyes; then + ifelse([$5], , :, [$5]) +else + ifelse([$6], , :, [$6]) +fi +])# AC_LIBTOOL_COMPILER_OPTION + + +# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ------------------------------------------------------------ +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], +[AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + else + $2=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + ifelse([$4], , :, [$4]) +else + ifelse([$5], , :, [$5]) +fi +])# AC_LIBTOOL_LINKER_OPTION + + +# AC_LIBTOOL_SYS_MAX_CMD_LEN +# -------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], +[# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + *) + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while (test "X"`$CONFIG_SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \ + = "XX$teststring") >/dev/null 2>&1 && + new_result=`expr "X$teststring" : ".*" 2>&1` && + lt_cv_sys_max_cmd_len=$new_result && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + teststring= + # Add a significant safety factor because C++ compilers can tack on massive + # amounts of additional arguments before passing them to the linker. + # It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +])# AC_LIBTOOL_SYS_MAX_CMD_LEN + + +# _LT_AC_CHECK_DLFCN +# -------------------- +AC_DEFUN([_LT_AC_CHECK_DLFCN], +[AC_CHECK_HEADERS(dlfcn.h)dnl +])# _LT_AC_CHECK_DLFCN + + +# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ------------------------------------------------------------------ +AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +}] +EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_unknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_AC_TRY_DLOPEN_SELF + + +# AC_LIBTOOL_DLOPEN_SELF +# ------------------- +AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + LDFLAGS="$LDFLAGS $link_static_flag" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +])# AC_LIBTOOL_DLOPEN_SELF + + +# AC_LIBTOOL_PROG_CC_C_O([TAGNAME]) +# --------------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler +AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s out/conftest.err; then + _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* +]) +])# AC_LIBTOOL_PROG_CC_C_O + + +# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME]) +# ----------------------------------------- +# Check to see if we can do hard links to lock some files if needed +AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], +[AC_REQUIRE([_LT_AC_LOCK])dnl + +hard_links="nottested" +if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS + + +# AC_LIBTOOL_OBJDIR +# ----------------- +AC_DEFUN([AC_LIBTOOL_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +])# AC_LIBTOOL_OBJDIR + + +# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME]) +# ---------------------------------------------- +# Check hardcoding attributes. +AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_AC_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \ + test -n "$_LT_AC_TAGVAR(runpath_var $1)" || \ + test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)"="Xyes" ; then + + # We can hardcode non-existant directories. + if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_AC_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_AC_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_AC_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH + + +# AC_LIBTOOL_SYS_LIB_STRIP +# ------------------------ +AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP], +[striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) +fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +])# AC_LIBTOOL_SYS_LIB_STRIP + + +# AC_LIBTOOL_SYS_DYNAMIC_LINKER +# ----------------------------- +# PORTME Fill in your ld.so characteristics +AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER], +[AC_MSG_CHECKING([dynamic linker characteristics]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi4*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd*) + objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + *) # from 3.2 on + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case "$host_cpu" in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`$SED -e 's/[:,\t]/ /g;s/=[^=]*$//;s/=[^= ]* / /g' /etc/ld.so.conf | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +knetbsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + need_lib_prefix=no + need_version=yes + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no +])# AC_LIBTOOL_SYS_DYNAMIC_LINKER + + +# _LT_AC_TAGCONFIG +# ---------------- +AC_DEFUN([_LT_AC_TAGCONFIG], +[AC_ARG_WITH([tags], + [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@], + [include additional configurations @<:@automatic@:>@])], + [tagnames="$withval"]) + +if test -f "$ltmain" && test -n "$tagnames"; then + if test ! -f "${ofile}"; then + AC_MSG_WARN([output file `$ofile' does not exist]) + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) + else + AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) + fi + fi + + # Extract list of available tagged configurations in $ofile. + # Note that this assumes the entire list is on one line. + available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` + + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for tagname in $tagnames; do + IFS="$lt_save_ifs" + # Check whether tagname contains only valid characters + case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in + "") ;; + *) AC_MSG_ERROR([invalid tag name: $tagname]) + ;; + esac + + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null + then + AC_MSG_ERROR([tag name \"$tagname\" already exists]) + fi + + # Update the list of available tags. + if test -n "$tagname"; then + echo appending configuration tag \"$tagname\" to $ofile + + case $tagname in + CXX) + if test -n "$CXX" && test "X$CXX" != "Xno"; then + AC_LIBTOOL_LANG_CXX_CONFIG + else + tagname="" + fi + ;; + + F77) + if test -n "$F77" && test "X$F77" != "Xno"; then + AC_LIBTOOL_LANG_F77_CONFIG + else + tagname="" + fi + ;; + + GCJ) + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + AC_LIBTOOL_LANG_GCJ_CONFIG + else + tagname="" + fi + ;; + + RC) + AC_LIBTOOL_LANG_RC_CONFIG + ;; + + *) + AC_MSG_ERROR([Unsupported tag name: $tagname]) + ;; + esac + + # Append the new tag name to the list of available tags. + if test -n "$tagname" ; then + available_tags="$available_tags $tagname" + fi + fi + done + IFS="$lt_save_ifs" + + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + else + rm -f "${ofile}T" + AC_MSG_ERROR([unable to update list of available tagged configurations.]) + fi +fi +])# _LT_AC_TAGCONFIG + + +# AC_LIBTOOL_DLOPEN +# ----------------- +# enable checks for dlopen support +AC_DEFUN([AC_LIBTOOL_DLOPEN], + [AC_BEFORE([$0],[AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_DLOPEN + + +# AC_LIBTOOL_WIN32_DLL +# -------------------- +# declare package support for building win32 dll's +AC_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_BEFORE([$0], [AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_WIN32_DLL + + +# AC_ENABLE_SHARED([DEFAULT]) +# --------------------------- +# implement the --enable-shared flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_SHARED], +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([shared], + [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]AC_ENABLE_SHARED_DEFAULT) +])# AC_ENABLE_SHARED + + +# AC_DISABLE_SHARED +# ----------------- +#- set the default shared flag to --disable-shared +AC_DEFUN([AC_DISABLE_SHARED], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no) +])# AC_DISABLE_SHARED + + +# AC_ENABLE_STATIC([DEFAULT]) +# --------------------------- +# implement the --enable-static flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_STATIC], +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([static], + [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]AC_ENABLE_STATIC_DEFAULT) +])# AC_ENABLE_STATIC + + +# AC_DISABLE_STATIC +# ----------------- +# set the default static flag to --disable-static +AC_DEFUN([AC_DISABLE_STATIC], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no) +])# AC_DISABLE_STATIC + + +# AC_ENABLE_FAST_INSTALL([DEFAULT]) +# --------------------------------- +# implement the --enable-fast-install flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_FAST_INSTALL], +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([fast-install], + [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT) +])# AC_ENABLE_FAST_INSTALL + + +# AC_DISABLE_FAST_INSTALL +# ----------------------- +# set the default to --disable-fast-install +AC_DEFUN([AC_DISABLE_FAST_INSTALL], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no) +])# AC_DISABLE_FAST_INSTALL + + +# AC_LIBTOOL_PICMODE([MODE]) +# -------------------------- +# implement the --with-pic flag +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +AC_DEFUN([AC_LIBTOOL_PICMODE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +pic_mode=ifelse($#,1,$1,default) +])# AC_LIBTOOL_PICMODE + + +# AC_PROG_EGREP +# ------------- +# This is predefined starting with Autoconf 2.54, so this conditional +# definition can be removed once we require Autoconf 2.54 or later. +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP], +[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], + [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi]) + EGREP=$ac_cv_prog_egrep + AC_SUBST([EGREP]) +])]) + + +# AC_PATH_TOOL_PREFIX +# ------------------- +# find a file program which can recognise shared library +AC_DEFUN([AC_PATH_TOOL_PREFIX], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +])# AC_PATH_TOOL_PREFIX + + +# AC_PATH_MAGIC +# ------------- +# find a file program which can recognise a shared library +AC_DEFUN([AC_PATH_MAGIC], +[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# AC_PATH_MAGIC + + +# AC_PROG_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH([gnu-ld], + [AC_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no]) +AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case "$host_cpu" in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +nto-qnx*) + lt_cv_deplibs_check_method=unknown + ;; + +openbsd*) + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB shared object' + else + lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +sco3.2v5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown +])# AC_DEPLIBS_CHECK_METHOD + + +# AC_PROG_NM +# ---------- +# find the pathname to a BSD-compatible name lister +AC_DEFUN([AC_PROG_NM], +[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/${ac_tool_prefix}nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + esac + fi + done + IFS="$lt_save_ifs" + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi]) +NM="$lt_cv_path_NM" +])# AC_PROG_NM + + +# AC_CHECK_LIBM +# ------------- +# check for math library +AC_DEFUN([AC_CHECK_LIBM], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +])# AC_CHECK_LIBM + + +# AC_LIBLTDL_CONVENIENCE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl convenience library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-convenience to the configure arguments. Note that LIBLTDL +# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If +# DIRECTORY is not provided, it is assumed to be `libltdl'. LIBLTDL will +# be prefixed with '${top_builddir}/' and LTDLINCL will be prefixed with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +AC_DEFUN([AC_LIBLTDL_CONVENIENCE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_CONVENIENCE + + +# AC_LIBLTDL_INSTALLABLE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl installable library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-install to the configure arguments. Note that LIBLTDL +# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If +# DIRECTORY is not provided and an installed libltdl is not found, it is +# assumed to be `libltdl'. LIBLTDL will be prefixed with '${top_builddir}/' +# and LTDLINCL will be prefixed with '${top_srcdir}/' (note the single +# quotes!). If your package is not flat and you're not using automake, +# define top_builddir and top_srcdir appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN([AC_LIBLTDL_INSTALLABLE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, lt_dlinit, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + LTDLINCL= + fi + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_INSTALLABLE + + +# AC_LIBTOOL_CXX +# -------------- +# enable support for C++ libraries +AC_DEFUN([AC_LIBTOOL_CXX], +[AC_REQUIRE([_LT_AC_LANG_CXX]) +])# AC_LIBTOOL_CXX + + +# _LT_AC_LANG_CXX +# --------------- +AC_DEFUN([_LT_AC_LANG_CXX], +[AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([AC_PROG_CXXCPP]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX]) +])# _LT_AC_LANG_CXX + + +# AC_LIBTOOL_F77 +# -------------- +# enable support for Fortran 77 libraries +AC_DEFUN([AC_LIBTOOL_F77], +[AC_REQUIRE([_LT_AC_LANG_F77]) +])# AC_LIBTOOL_F77 + + +# _LT_AC_LANG_F77 +# --------------- +AC_DEFUN([_LT_AC_LANG_F77], +[AC_REQUIRE([AC_PROG_F77]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77]) +])# _LT_AC_LANG_F77 + + +# AC_LIBTOOL_GCJ +# -------------- +# enable support for GCJ libraries +AC_DEFUN([AC_LIBTOOL_GCJ], +[AC_REQUIRE([_LT_AC_LANG_GCJ]) +])# AC_LIBTOOL_GCJ + + +# _LT_AC_LANG_GCJ +# --------------- +AC_DEFUN([_LT_AC_LANG_GCJ], +[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], + [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], + [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], + [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ]) +])# _LT_AC_LANG_GCJ + + +# AC_LIBTOOL_RC +# -------------- +# enable support for Windows resource files +AC_DEFUN([AC_LIBTOOL_RC], +[AC_REQUIRE([LT_AC_PROG_RC]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC]) +])# AC_LIBTOOL_RC + + +# AC_LIBTOOL_LANG_C_CONFIG +# ------------------------ +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG]) +AC_DEFUN([_LT_AC_LANG_C_CONFIG], +[lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}\n' + +_LT_AC_SYS_COMPILER + +# +# Check for any special shared library compilation flags. +# +_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)= +if test "$GCC" = no; then + case $host_os in + sco3.2v5*) + _LT_AC_TAGVAR(lt_prog_cc_shlib, $1)='-belf' + ;; + esac +fi +if test -n "$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)"; then + AC_MSG_WARN([`$CC' requires `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to build shared libraries]) + if echo "$old_CC $old_CFLAGS " | grep "[[ ]]$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)[[ ]]" >/dev/null; then : + else + AC_MSG_WARN([add `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to the CC or CFLAGS env variable and reconfigure]) + _LT_AC_TAGVAR(lt_cv_prog_cc_can_build_shared, $1)=no + fi +fi + + +# +# Check to make sure the static flag actually works. +# +AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $_LT_AC_TAGVAR(lt_prog_compiler_static, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1), + $_LT_AC_TAGVAR(lt_prog_compiler_static, $1), + [], + [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=]) + + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_DLOPEN_SELF($1) + +# Report which librarie types wil actually be built +AC_MSG_CHECKING([if libtool supports shared libraries]) +AC_MSG_RESULT([$can_build_shared]) + +AC_MSG_CHECKING([whether to build shared libraries]) +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4* | aix5*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + darwin* | rhapsody*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case "$host_os" in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup' + ;; + esac + fi + ;; + esac + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; +esac +AC_MSG_RESULT([$enable_shared]) + +AC_MSG_CHECKING([whether to build static libraries]) +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +AC_MSG_RESULT([$enable_static]) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_C_CONFIG + + +# AC_LIBTOOL_LANG_CXX_CONFIG +# -------------------------- +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)]) +AC_DEFUN([_LT_AC_LANG_CXX_CONFIG], +[AC_LANG_PUSH(C++) +AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([AC_PROG_CXXCPP]) + +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_AC_TAGVAR(allow_undefined_flag, $1)= +_LT_AC_TAGVAR(always_export_symbols, $1)=no +_LT_AC_TAGVAR(archive_expsym_cmds, $1)= +_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_direct, $1)=no +_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_AC_TAGVAR(hardcode_libdir_separator, $1)= +_LT_AC_TAGVAR(hardcode_minus_L, $1)=no +_LT_AC_TAGVAR(hardcode_automatic, $1)=no +_LT_AC_TAGVAR(module_cmds, $1)= +_LT_AC_TAGVAR(module_expsym_cmds, $1)= +_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown +_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_AC_TAGVAR(no_undefined_flag, $1)= +_LT_AC_TAGVAR(whole_archive_flag_spec, $1)= +_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Dependencies to place before and after the object being linked: +_LT_AC_TAGVAR(predep_objects, $1)= +_LT_AC_TAGVAR(postdep_objects, $1)= +_LT_AC_TAGVAR(predeps, $1)= +_LT_AC_TAGVAR(postdeps, $1)= +_LT_AC_TAGVAR(compiler_lib_search_path, $1)= + +# Source file extension for C++ test sources. +ac_ext=cc + +# Object file extension for compiled C++ test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(int, char *[]) { return(0); }\n' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_LD=$LD +lt_save_GCC=$GCC +GCC=$GXX +lt_save_with_gnu_ld=$with_gnu_ld +lt_save_path_LD=$lt_cv_path_LD +if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx +else + unset lt_cv_prog_gnu_ld +fi +if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX +else + unset lt_cv_path_LD +fi +test -z "${LDCXX+set}" || LD=$LDCXX +CC=${CXX-"c++"} +compiler=$CC +_LT_AC_TAGVAR(compiler, $1)=$CC +cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'` + +# We don't want -fno-exception wen compiling C++ code, so set the +# no_builtin_flag separately +if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' +else + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= +fi + +if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + AC_PROG_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ + grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + +else + GXX=no + with_gnu_ld=no + wlarc= +fi + +# PORTME: fill in a description of your system's C++ link characteristics +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +_LT_AC_TAGVAR(ld_shlibs, $1)=yes +case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # -bexpall does not export symbols beginning with underscore (_) + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds it's shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + darwin* | rhapsody*) + if test "$GXX" = yes; then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case "$host_os" in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup' + ;; + esac + fi + ;; + esac + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + fi + _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + dgux*) + case $cc_basename in + ec++) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + freebsd[12]*) + # C++ shared libraries reported to be fairly broken before switch to ELF + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + freebsd-elf*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + freebsd* | kfreebsd*-gnu) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + ;; + gnu*) + ;; + hpux9*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[-]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + case "$host_cpu" in + hppa*64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + ;; + *) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case "$host_cpu" in + hppa*64*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + ia64*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC) + case "$host_cpu" in + hppa*64*|ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case "$host_cpu" in + ia64*|hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + irix5* | irix6*) + case $cc_basename in + CC) + # SGI C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' + fi + fi + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + linux*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc) + # Intel C++ + with_gnu_ld=yes + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + cxx) + # Compaq C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + esac + ;; + lynxos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + m88k*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + mvs*) + case $cc_basename in + cxx) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + osf3*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + + ;; + RCC) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + osf4* | osf5*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' + ;; + RCC) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry $objdir/so_locations -o $lib~ + $rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + psos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + sco*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + lcc) + # Lucid + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + solaris*) + case $cc_basename in + CC) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The C++ compiler is used as linker so we must use $wl + # flag to pass the commands to the underlying system + # linker. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[[LR]]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | grep -v '^2\.7' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + fi + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + fi + ;; + esac + ;; + sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + tandem*) + case $cc_basename in + NCC) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + vxworks*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; +esac +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_AC_TAGVAR(GCC, $1)="$GXX" +_LT_AC_TAGVAR(LD, $1)="$LD" + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +AC_LIBTOOL_POSTDEP_PREDEP($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_DLOPEN_SELF($1) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC=$lt_save_CC +LDCXX=$LD +LD=$lt_save_LD +GCC=$lt_save_GCC +with_gnu_ldcxx=$with_gnu_ld +with_gnu_ld=$lt_save_with_gnu_ld +lt_cv_path_LDCXX=$lt_cv_path_LD +lt_cv_path_LD=$lt_save_path_LD +lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld +lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +])# AC_LIBTOOL_LANG_CXX_CONFIG + +# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME]) +# ------------------------ +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[ +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +ifelse([$1],[],[cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext <> "$cfgfile" +ifelse([$1], [], +[#! $SHELL + +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="$SED -e s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +# The names of the tagged configurations supported by this script. +available_tags= + +# ### BEGIN LIBTOOL CONFIG], +[# ### BEGIN LIBTOOL TAG CONFIG: $tagname]) + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1) + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# A language-specific compiler. +CC=$lt_[]_LT_AC_TAGVAR(compiler, $1) + +# Is the compiler the GNU C compiler? +with_gcc=$_LT_AC_TAGVAR(GCC, $1) + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_[]_LT_AC_TAGVAR(LD, $1) + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) + +# Must we lock files when doing compilation ? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1) + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1) + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1) + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1) + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1) +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1) + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) + +# Commands used to build and install a shared archive. +archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1) +archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1) +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1) +module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1) + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1) + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1) + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1) + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1) + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1) + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1) + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1) + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1) + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1) + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1) + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1) + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1) + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)" + +# Set to yes if exported symbols are required. +always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1) + +# The commands to list exported symbols. +export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1) + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1) + +# Symbols that must always be exported. +include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1) + +ifelse([$1],[], +[# ### END LIBTOOL CONFIG], +[# ### END LIBTOOL TAG CONFIG: $tagname]) + +__EOF__ + +ifelse([$1],[], [ + case $host_os in + aix3*) + cat <<\EOF >> "$cfgfile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || \ + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +]) +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi +])# AC_LIBTOOL_CONFIG + + +# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl + +_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI + + +# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +# --------------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_NM]) +AC_REQUIRE([AC_OBJEXT]) +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Transform the above into a raw symbol and a C symbol. +symxfrm='\1 \2\3 \3' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) # Its linker distinguishes data from code symbols + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris* | sysv5*) + symcode='[[BDRT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Write the raw and C identifiers. + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if grep ' nm_test_var$' "$nlist" >/dev/null; then + if grep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[[]] = +{ +EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi +]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE + + +# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME]) +# --------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC], +[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) + ifelse([$1],[CXX],[ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | os2* | pw32*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix4* | aix5*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68) + # Green Hills C++ Compiler + # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | kfreebsd*-gnu) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux*) + case $cc_basename in + KCC) + # KAI C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + icpc) + # Intel C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + cxx) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC) + # Rational C++ 2.4.1 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx) + # Digital/Compaq C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + sco*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + *) + ;; + esac + ;; + solaris*) + case $cc_basename in + CC) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC) + # Sun C++ 4.x + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc) + # Lucid + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC) + # NonStop-UX NCC 3.20 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + unixware*) + ;; + vxworks*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + newsos6) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + linux*) + case $CC in + icc* | ecc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + ccc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + sco3.2v5*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-dn' + ;; + + solaris*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sunos4*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + uts4*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then + AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1), + [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +case "$host_os" in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])" + ;; +esac +]) + + +# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME]) +# ------------------------------------ +# See if the linker supports building shared libraries. +AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS], +[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +ifelse([$1],[CXX],[ + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix4* | aix5*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + ;; + linux*) + _LT_AC_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +],[ + runpath_var= + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)= + _LT_AC_TAGVAR(archive_expsym_cmds, $1)= + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)= + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + _LT_AC_TAGVAR(thread_safe_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown + _LT_AC_TAGVAR(hardcode_automatic, $1)=no + _LT_AC_TAGVAR(module_cmds, $1)= + _LT_AC_TAGVAR(module_expsym_cmds, $1)= + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_AC_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + else + ld_shlibs=no + fi + ;; + + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris* | sysv5*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sunos4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + linux*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_cmds, $1)="$tmp_archive_cmds" + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [01].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + if test $supports_anon_versioning = yes; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~ +cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ +$echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + else + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="$tmp_archive_cmds" + fi + _LT_AC_TAGVAR(link_all_deplibs, $1)=no + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = yes; then + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # -bexpall does not export symbols beginning with underscore (_) + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds it's shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + # see comment about different semantics on the GNU ld section + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + bsdi4*) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + if test "$GXX" = yes ; then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case "$host_os" in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup' + ;; + esac + fi + ;; + esac + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + fi + _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + dgux*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | kfreebsd*-gnu) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10* | hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case "$host_cpu" in + hppa*64*|ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case "$host_cpu" in + hppa*64*|ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + case "$host_cpu" in + hppa*64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + ;; + *) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + openbsd*) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + sco3.2v5*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ;; + + solaris*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4.2uw2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + hardcode_runpath_var=yes + runpath_var=LD_RUN_PATH + ;; + + sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z ${wl}text' + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv5*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + ;; + + uts4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +# +# Do we need to explicitly link libc? +# +case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_AC_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1) + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) + then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac +])# AC_LIBTOOL_PROG_LD_SHLIBS + + +# _LT_AC_FILE_LTDLL_C +# ------------------- +# Be careful that the start marker always follows a newline. +AC_DEFUN([_LT_AC_FILE_LTDLL_C], [ +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include +# #undef WIN32_LEAN_AND_MEAN +# #include +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ +])# _LT_AC_FILE_LTDLL_C + + +# _LT_AC_TAGVAR(VARNAME, [TAGNAME]) +# --------------------------------- +AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])]) + + +# old names +AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) +AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) +AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) +AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) +AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) + +# This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL]) + +AC_DEFUN([LT_AC_PROG_GCJ], +[AC_CHECK_TOOL(GCJ, gcj, no) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS) +]) + +AC_DEFUN([LT_AC_PROG_RC], +[AC_CHECK_TOOL(RC, windres, no) +]) + +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ +# LT_AC_PROG_SED +# -------------- +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +AC_DEFUN([LT_AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && break + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +SED=$lt_cv_path_SED +]) +AC_MSG_RESULT([$SED]) +]) diff --git a/ltdl.m4 b/ltdl.m4 new file mode 100644 index 00000000..aa6a0d13 --- /dev/null +++ b/ltdl.m4 @@ -0,0 +1,431 @@ +## ltdl.m4 - Configure ltdl for the target system. -*-Autoconf-*- +## Copyright (C) 1999-2000 Free Software Foundation, Inc. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +## As a special exception to the GNU General Public License, if you +## distribute this file as part of a program that contains a +## configuration script generated by Autoconf, you may include it under +## the same distribution terms that you use for the rest of that program. + +# serial 6 AC_LIB_LTDL +# Debian $Rev: 214 $ + +# AC_WITH_LTDL +# ------------ +# Clients of libltdl can use this macro to allow the installer to +# choose between a shipped copy of the ltdl sources or a preinstalled +# version of the library. +AC_DEFUN([AC_WITH_LTDL], +[AC_REQUIRE([AC_LIB_LTDL]) +AC_SUBST([LIBLTDL]) +AC_SUBST([INCLTDL]) + +# Unless the user asks us to check, assume no installed ltdl exists. +use_installed_libltdl=no + +AC_ARG_WITH([included_ltdl], + [ --with-included-ltdl use the GNU ltdl sources included here]) + +if test "x$with_included_ltdl" != xyes; then + # We are not being forced to use the included libltdl sources, so + # decide whether there is a useful installed version we can use. + AC_CHECK_HEADER([ltdl.h], + [AC_CHECK_LIB([ltdl], [lt_dlcaller_register], + [with_included_ltdl=no], + [with_included_ltdl=yes]) + ]) +fi + +if test "x$enable_ltdl_install" != xyes; then + # If the user did not specify an installable libltdl, then default + # to a convenience lib. + AC_LIBLTDL_CONVENIENCE +fi + +if test "x$with_included_ltdl" = xno; then + # If the included ltdl is not to be used. then Use the + # preinstalled libltdl we found. + AC_DEFINE([HAVE_LTDL], 1, + [Define this if a modern libltdl is already installed]) + LIBLTDL=-lltdl +fi + +# Report our decision... +AC_MSG_CHECKING([whether to use included libltdl]) +AC_MSG_RESULT([$with_included_ltdl]) + +AC_CONFIG_SUBDIRS([libltdl]) +])# AC_WITH_LTDL + + +# AC_LIB_LTDL +# ----------- +# Perform all the checks necessary for compilation of the ltdl objects +# -- including compiler checks and header checks. +AC_DEFUN([AC_LIB_LTDL], +[AC_PREREQ(2.50) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AC_C_CONST]) +AC_REQUIRE([AC_HEADER_STDC]) +AC_REQUIRE([AC_HEADER_DIRENT]) +AC_REQUIRE([_LT_AC_CHECK_DLFCN]) +AC_REQUIRE([AC_LTDL_ENABLE_INSTALL]) +AC_REQUIRE([AC_LTDL_SHLIBEXT]) +AC_REQUIRE([AC_LTDL_SHLIBPATH]) +AC_REQUIRE([AC_LTDL_SYSSEARCHPATH]) +AC_REQUIRE([AC_LTDL_OBJDIR]) +AC_REQUIRE([AC_LTDL_DLPREOPEN]) +AC_REQUIRE([AC_LTDL_DLLIB]) +AC_REQUIRE([AC_LTDL_SYMBOL_USCORE]) +AC_REQUIRE([AC_LTDL_DLSYM_USCORE]) +AC_REQUIRE([AC_LTDL_SYS_DLOPEN_DEPLIBS]) +AC_REQUIRE([AC_LTDL_FUNC_ARGZ]) + +AC_CHECK_HEADERS([assert.h ctype.h errno.h malloc.h memory.h stdlib.h \ + stdio.h unistd.h]) +AC_CHECK_HEADERS([dl.h sys/dl.h dld.h mach-o/dyld.h]) +AC_CHECK_HEADERS([string.h strings.h], [break]) + +AC_CHECK_FUNCS([strchr index], [break]) +AC_CHECK_FUNCS([strrchr rindex], [break]) +AC_CHECK_FUNCS([memcpy bcopy], [break]) +AC_CHECK_FUNCS([memmove strcmp]) +AC_CHECK_FUNCS([closedir opendir readdir]) +])# AC_LIB_LTDL + + +# AC_LTDL_ENABLE_INSTALL +# ---------------------- +AC_DEFUN([AC_LTDL_ENABLE_INSTALL], +[AC_ARG_ENABLE([ltdl-install], + [AC_HELP_STRING([--enable-ltdl-install], [install libltdl])]) + +AM_CONDITIONAL(INSTALL_LTDL, test x"${enable_ltdl_install-no}" != xno) +AM_CONDITIONAL(CONVENIENCE_LTDL, test x"${enable_ltdl_convenience-no}" != xno) +])])# AC_LTDL_ENABLE_INSTALL + + +# AC_LTDL_SYS_DLOPEN_DEPLIBS +# -------------------------- +AC_DEFUN([AC_LTDL_SYS_DLOPEN_DEPLIBS], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_CACHE_CHECK([whether deplibs are loaded by dlopen], + [libltdl_cv_sys_dlopen_deplibs], + [# PORTME does your system automatically load deplibs for dlopen? + # or its logical equivalent (e.g. shl_load for HP-UX < 11) + # For now, we just catch OSes we know something about -- in the + # future, we'll try test this programmatically. + libltdl_cv_sys_dlopen_deplibs=unknown + case "$host_os" in + aix3*|aix4.1.*|aix4.2.*) + # Unknown whether this is true for these versions of AIX, but + # we want this `case' here to explicitly catch those versions. + libltdl_cv_sys_dlopen_deplibs=unknown + ;; + aix[[45]]*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + darwin*) + # Assuming the user has installed a libdl from somewhere, this is true + # If you are looking for one http://www.opendarwin.org/projects/dlcompat + libltdl_cv_sys_dlopen_deplibs=yes + ;; + gnu* | linux* | kfreebsd*-gnu | knetbsd*-gnu) + # GNU and its variants, using gnu ld.so (Glibc) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + hpux10*|hpux11*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + irix[[12345]]*|irix6.[[01]]*) + # Catch all versions of IRIX before 6.2, and indicate that we don't + # know how it worked for any of those versions. + libltdl_cv_sys_dlopen_deplibs=unknown + ;; + irix*) + # The case above catches anything before 6.2, and it's known that + # at 6.2 and later dlopen does load deplibs. + libltdl_cv_sys_dlopen_deplibs=yes + ;; + netbsd* | netbsdelf*-gnu) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + openbsd*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + osf[[1234]]*) + # dlopen did load deplibs (at least at 4.x), but until the 5.x series, + # it did *not* use an RPATH in a shared library to find objects the + # library depends on, so we explictly say `no'. + libltdl_cv_sys_dlopen_deplibs=no + ;; + osf5.0|osf5.0a|osf5.1) + # dlopen *does* load deplibs and with the right loader patch applied + # it even uses RPATH in a shared library to search for shared objects + # that the library depends on, but there's no easy way to know if that + # patch is installed. Since this is the case, all we can really + # say is unknown -- it depends on the patch being installed. If + # it is, this changes to `yes'. Without it, it would be `no'. + libltdl_cv_sys_dlopen_deplibs=unknown + ;; + osf*) + # the two cases above should catch all versions of osf <= 5.1. Read + # the comments above for what we know about them. + # At > 5.1, deplibs are loaded *and* any RPATH in a shared library + # is used to find them so we can finally say `yes'. + libltdl_cv_sys_dlopen_deplibs=yes + ;; + solaris*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + esac + ]) +if test "$libltdl_cv_sys_dlopen_deplibs" != yes; then + AC_DEFINE([LTDL_DLOPEN_DEPLIBS], [1], + [Define if the OS needs help to load dependent libraries for dlopen().]) +fi +])# AC_LTDL_SYS_DLOPEN_DEPLIBS + + +# AC_LTDL_SHLIBEXT +# ---------------- +AC_DEFUN([AC_LTDL_SHLIBEXT], +[AC_REQUIRE([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) +AC_CACHE_CHECK([which extension is used for loadable modules], + [libltdl_cv_shlibext], +[ +module=yes +eval libltdl_cv_shlibext=$shrext_cmds + ]) +if test -n "$libltdl_cv_shlibext"; then + AC_DEFINE_UNQUOTED(LTDL_SHLIB_EXT, "$libltdl_cv_shlibext", + [Define to the extension used for shared libraries, say, ".so".]) +fi +])# AC_LTDL_SHLIBEXT + + +# AC_LTDL_SHLIBPATH +# ----------------- +AC_DEFUN([AC_LTDL_SHLIBPATH], +[AC_REQUIRE([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) +AC_CACHE_CHECK([which variable specifies run-time library path], + [libltdl_cv_shlibpath_var], [libltdl_cv_shlibpath_var="$shlibpath_var"]) +if test -n "$libltdl_cv_shlibpath_var"; then + AC_DEFINE_UNQUOTED(LTDL_SHLIBPATH_VAR, "$libltdl_cv_shlibpath_var", + [Define to the name of the environment variable that determines the dynamic library search path.]) +fi +])# AC_LTDL_SHLIBPATH + + +# AC_LTDL_SYSSEARCHPATH +# --------------------- +AC_DEFUN([AC_LTDL_SYSSEARCHPATH], +[AC_REQUIRE([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) +AC_CACHE_CHECK([for the default library search path], + [libltdl_cv_sys_search_path], + [libltdl_cv_sys_search_path="$sys_lib_dlsearch_path_spec"]) +if test -n "$libltdl_cv_sys_search_path"; then + sys_search_path= + for dir in $libltdl_cv_sys_search_path; do + if test -z "$sys_search_path"; then + sys_search_path="$dir" + else + sys_search_path="$sys_search_path$PATH_SEPARATOR$dir" + fi + done + AC_DEFINE_UNQUOTED(LTDL_SYSSEARCHPATH, "$sys_search_path", + [Define to the system default library search path.]) +fi +])# AC_LTDL_SYSSEARCHPATH + + +# AC_LTDL_OBJDIR +# -------------- +AC_DEFUN([AC_LTDL_OBJDIR], +[AC_CACHE_CHECK([for objdir], + [libltdl_cv_objdir], + [libltdl_cv_objdir="$objdir" + if test -n "$objdir"; then + : + else + rm -f .libs 2>/dev/null + mkdir .libs 2>/dev/null + if test -d .libs; then + libltdl_cv_objdir=.libs + else + # MS-DOS does not allow filenames that begin with a dot. + libltdl_cv_objdir=_libs + fi + rmdir .libs 2>/dev/null + fi + ]) +AC_DEFINE_UNQUOTED(LTDL_OBJDIR, "$libltdl_cv_objdir/", + [Define to the sub-directory in which libtool stores uninstalled libraries.]) +])# AC_LTDL_OBJDIR + + +# AC_LTDL_DLPREOPEN +# ----------------- +AC_DEFUN([AC_LTDL_DLPREOPEN], +[AC_REQUIRE([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE]) +AC_CACHE_CHECK([whether libtool supports -dlopen/-dlpreopen], + [libltdl_cv_preloaded_symbols], + [if test -n "$lt_cv_sys_global_symbol_pipe"; then + libltdl_cv_preloaded_symbols=yes + else + libltdl_cv_preloaded_symbols=no + fi + ]) +if test x"$libltdl_cv_preloaded_symbols" = xyes; then + AC_DEFINE(HAVE_PRELOADED_SYMBOLS, 1, + [Define if libtool can extract symbol lists from object files.]) +fi +])# AC_LTDL_DLPREOPEN + + +# AC_LTDL_DLLIB +# ------------- +AC_DEFUN([AC_LTDL_DLLIB], +[LIBADD_DL= +AC_SUBST(LIBADD_DL) +AC_LANG_PUSH([C]) + +AC_CHECK_FUNC([shl_load], + [AC_DEFINE([HAVE_SHL_LOAD], [1], + [Define if you have the shl_load function.])], + [AC_CHECK_LIB([dld], [shl_load], + [AC_DEFINE([HAVE_SHL_LOAD], [1], + [Define if you have the shl_load function.]) + LIBADD_DL="$LIBADD_DL -ldld"], + [AC_CHECK_LIB([dl], [dlopen], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) + LIBADD_DL="-ldl" libltdl_cv_lib_dl_dlopen="yes"], + [AC_TRY_LINK([#if HAVE_DLFCN_H +# include +#endif + ], + [dlopen(0, 0);], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) libltdl_cv_func_dlopen="yes"], + [AC_CHECK_LIB([svld], [dlopen], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) + LIBADD_DL="-lsvld" libltdl_cv_func_dlopen="yes"], + [AC_CHECK_LIB([dld], [dld_link], + [AC_DEFINE([HAVE_DLD], [1], + [Define if you have the GNU dld library.]) + LIBADD_DL="$LIBADD_DL -ldld"], + [AC_CHECK_FUNC([_dyld_func_lookup], + [AC_DEFINE([HAVE_DYLD], [1], + [Define if you have the _dyld_func_lookup function.])]) + ]) + ]) + ]) + ]) + ]) +]) + +if test x"$libltdl_cv_func_dlopen" = xyes || test x"$libltdl_cv_lib_dl_dlopen" = xyes +then + lt_save_LIBS="$LIBS" + LIBS="$LIBS $LIBADD_DL" + AC_CHECK_FUNCS([dlerror]) + LIBS="$lt_save_LIBS" +fi +AC_LANG_POP +])# AC_LTDL_DLLIB + + +# AC_LTDL_SYMBOL_USCORE +# --------------------- +# does the compiler prefix global symbols with an underscore? +AC_DEFUN([AC_LTDL_SYMBOL_USCORE], +[AC_REQUIRE([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE]) +AC_CACHE_CHECK([for _ prefix in compiled symbols], + [ac_cv_sys_symbol_underscore], + [ac_cv_sys_symbol_underscore=no + cat > conftest.$ac_ext < $ac_nlist) && test -s "$ac_nlist"; then + # See whether the symbols have a leading underscore. + if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then + ac_cv_sys_symbol_underscore=yes + else + if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then + : + else + echo "configure: cannot find nm_test_func in $ac_nlist" >&AC_FD_CC + fi + fi + else + echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&AC_FD_CC + fi + else + echo "configure: failed program was:" >&AC_FD_CC + cat conftest.c >&AC_FD_CC + fi + rm -rf conftest* + ]) +])# AC_LTDL_SYMBOL_USCORE + + +# AC_LTDL_DLSYM_USCORE +# -------------------- +AC_DEFUN([AC_LTDL_DLSYM_USCORE], +[AC_REQUIRE([AC_LTDL_SYMBOL_USCORE]) +if test x"$ac_cv_sys_symbol_underscore" = xyes; then + if test x"$libltdl_cv_func_dlopen" = xyes || + test x"$libltdl_cv_lib_dl_dlopen" = xyes ; then + AC_CACHE_CHECK([whether we have to add an underscore for dlsym], + [libltdl_cv_need_uscore], + [libltdl_cv_need_uscore=unknown + save_LIBS="$LIBS" + LIBS="$LIBS $LIBADD_DL" + _LT_AC_TRY_DLOPEN_SELF( + [libltdl_cv_need_uscore=no], [libltdl_cv_need_uscore=yes], + [], [libltdl_cv_need_uscore=cross]) + LIBS="$save_LIBS" + ]) + fi +fi + +if test x"$libltdl_cv_need_uscore" = xyes; then + AC_DEFINE(NEED_USCORE, 1, + [Define if dlsym() requires a leading underscore in symbol names.]) +fi +])# AC_LTDL_DLSYM_USCORE + +# AC_LTDL_FUNC_ARGZ +# ----------------- +AC_DEFUN([AC_LTDL_FUNC_ARGZ], +[AC_CHECK_HEADERS([argz.h]) + +AC_CHECK_TYPES([error_t], + [], + [AC_DEFINE([error_t], [int], + [Define to a type to use for `error_t' if it is not otherwise available.])], + [#if HAVE_ARGZ_H +# include +#endif]) + +AC_CHECK_FUNCS([argz_append argz_create_sep argz_insert argz_next argz_stringify]) +])# AC_LTDL_FUNC_ARGZ diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 1bae9afc..8c91ae4b 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -565,7 +565,7 @@ pax11publish_LDADD = $(AM_LDADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libpolyp_@PA_MAJORMINOR@_la_CFLAGS += $(X_CFLAGS) libpolyp_@PA_MAJORMINOR@_la_LDFLAGS += $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) -libpolyp_@PA_MAJORMINOR@_la_SOURCES += x11prop.c client-conf-x11.c +libpolyp_@PA_MAJORMINOR@_la_SOURCES += x11prop.c x11prop.h client-conf-x11.c client-conf-x11.h endif -- cgit From 29ec9d343b3163c03d491170a2182366e26b3408 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 23 Nov 2004 13:00:53 +0000 Subject: * some fixes for MacOS X by Conrad Parker * Minor build fixes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@312 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- doc/Makefile.am | 2 +- polyp/Makefile.am | 2 +- polyp/mcalign-test.c | 2 +- polyp/pid.c | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 47f965e0..4db6b5b9 100644 --- a/configure.ac +++ b/configure.ac @@ -168,7 +168,7 @@ if test x$lynx = xyes ; then AC_CHECK_PROG(have_lynx, lynx, yes, no) if test x$have_lynx = xno ; then - AC_MSG_ERROR([*** Sorry, you have to install lynx or use --disable-lynx ***]) + AC_MSG_WARN([*** lynx not found, plain text README will not be built ***]) fi fi diff --git a/doc/Makefile.am b/doc/Makefile.am index f67598f1..fff06551 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -19,7 +19,7 @@ noinst_DATA = README.html cli.html modules.html daemon.html README EXTRA_DIST = $(noinst_DATA) style.css README.html.in cli.html.in modules.html.in daemon.html.in todo FAQ.html.in -MAINTAINERCLEANFILES = README README.html cli.html modules.html daemon.html FAQ.html +MAINTAINERCLEANFILES = README.html cli.html modules.html daemon.html FAQ.html CLEANFILES = if USE_LYNX diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 8c91ae4b..db508d7a 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -729,7 +729,7 @@ daemon.conf: daemon.conf.in Makefile -e 's,@DEFAULT_CONFIG_FILE\@,$(polypconfdir)/daemon.conf,g' < $< > $@ install-exec-hook: - chown root $(DESTDIR)$(bindir)/polypaudio + chown root $(DESTDIR)$(bindir)/polypaudio ; true chmod u+s $(DESTDIR)$(bindir)/polypaudio ln -s pacat $(DESTDIR)$(bindir)/parec diff --git a/polyp/mcalign-test.c b/polyp/mcalign-test.c index f8af4f9f..e4a6a239 100644 --- a/polyp/mcalign-test.c +++ b/polyp/mcalign-test.c @@ -82,7 +82,7 @@ int main(int argc, char *argv[]) { break; pa_loop_write(STDOUT_FILENO, (uint8_t*) t.memblock->data + t.index, t.length); - fprintf(stderr, "Wrote %u bytes.\n", t.length); + fprintf(stderr, "Wrote %lu bytes.\n", (unsigned long) t.length); pa_memblock_unref(t.memblock); } diff --git a/polyp/pid.c b/polyp/pid.c index 232de216..32365136 100644 --- a/polyp/pid.c +++ b/polyp/pid.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include -- cgit From 758647868faf4c37845a3b572544313a34e5c579 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 23 Nov 2004 13:34:59 +0000 Subject: * install fix * use syslog as standard log target when run from esdcompat.sh git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@313 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 2 +- polyp/esdcompat.sh.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index db508d7a..7338b9e6 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -731,7 +731,7 @@ daemon.conf: daemon.conf.in Makefile install-exec-hook: chown root $(DESTDIR)$(bindir)/polypaudio ; true chmod u+s $(DESTDIR)$(bindir)/polypaudio - ln -s pacat $(DESTDIR)$(bindir)/parec + ln -sf pacat $(DESTDIR)$(bindir)/parec $(SYMDEF_FILES): module-defs.h.m4 $(M4) -Dfname="$@" $< > $@ diff --git a/polyp/esdcompat.sh.in b/polyp/esdcompat.sh.in index dd94bfea..76023f52 100755 --- a/polyp/esdcompat.sh.in +++ b/polyp/esdcompat.sh.in @@ -26,7 +26,7 @@ fail() { exit 1 } -ARGS="" +ARGS=" --log-target=syslog" for N in $(seq $#) ; do -- cgit From 9a9309f5938ecc2b79af72f1921ebd9178c029e4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 26 Nov 2004 00:07:24 +0000 Subject: * use setresuid() instead of setruid() if available * if fix for the non-fp resampler git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@314 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 3 +++ polyp/caps.c | 19 +++++++++++++------ polyp/resampler.c | 4 ++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index 4db6b5b9..3ab9491f 100644 --- a/configure.ac +++ b/configure.ac @@ -96,6 +96,9 @@ AC_SUBST(CAP_LIBS) AC_CHECK_HEADERS(sys/capability.h) +AC_CHECK_FUNCS(setresuid) +AC_CHECK_FUNCS(setreuid) + PKG_CHECK_MODULES(LIBSAMPLERATE, [ samplerate >= 0.1.0 ]) AC_SUBST(LIBSAMPLERATE_CFLAGS) AC_SUBST(LIBSAMPLERATE_LIBS) diff --git a/polyp/caps.c b/polyp/caps.c index 34d97eb5..93fca89f 100644 --- a/polyp/caps.c +++ b/polyp/caps.c @@ -23,6 +23,9 @@ #include #endif +/* setresuid() is only available on GNU */ +#define _GNU_SOURCE + #include #include #include @@ -41,13 +44,17 @@ void pa_drop_root(void) { if (uid == 0 || geteuid() != 0) return; - -/* pa_log(__FILE__": dropping root rights.\n"); */ - - setreuid(uid, uid); -/* setuid(uid); - seteuid(uid);*/ + /* pa_log(__FILE__": dropping root rights.\n"); */ + +#if defined(HAVE_SETRESUID) + setresuid(uid, uid, uid); +#elif defined(HAVE_SETREUID) + setreuid(uid, uid); +#else + setuid(uid); + seteuid(uid); +#endif } #ifdef HAVE_SYS_CAPABILITY_H diff --git a/polyp/resampler.c b/polyp/resampler.c index 377aa797..68c0129a 100644 --- a/polyp/resampler.c +++ b/polyp/resampler.c @@ -342,8 +342,8 @@ static void trivial_run(struct pa_resampler *r, const struct pa_memchunk *in, st unsigned j; j = (i->o_counter * r->i_ss.rate / r->o_ss.rate); - assert(j >= i->i_counter); - j = j - i->i_counter; + + j = j > i->i_counter ? j - i->i_counter : 0; if (j >= nframes) break; -- cgit From 7f3c92bad94b2eada69b4303a3f18d2b52a6d8bf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 27 Nov 2004 14:00:59 +0000 Subject: * fix autospawn lock file creation git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@315 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/polyplib-context.c | 1 + 1 file changed, 1 insertion(+) diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 899a8176..517fcbeb 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -592,6 +592,7 @@ int pa_context_connect(struct pa_context *c, const char *server, int spawn, cons char lf[PATH_MAX]; pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); + pa_make_secure_parent_dir(lf); assert(c->autospawn_lock_fd <= 0); c->autospawn_lock_fd = pa_lock_lockfile(lf); -- cgit From 5be9641ffe18c482294c99345306c382ba4cf750 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 27 Nov 2004 18:50:29 +0000 Subject: * really fix integer only resampler git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@316 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/resampler.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/polyp/resampler.c b/polyp/resampler.c index 68c0129a..28e49209 100644 --- a/polyp/resampler.c +++ b/polyp/resampler.c @@ -333,7 +333,7 @@ static void trivial_run(struct pa_resampler *r, const struct pa_memchunk *in, st unsigned o_index; /* The length of the new memory block rounded up */ - l = ((nframes * r->o_ss.rate + r->i_ss.rate - 1) / r->i_ss.rate) * fz; + l = ((((nframes+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz; out->index = 0; out->memblock = pa_memblock_new(l, r->memblock_stat); @@ -342,12 +342,11 @@ static void trivial_run(struct pa_resampler *r, const struct pa_memchunk *in, st unsigned j; j = (i->o_counter * r->i_ss.rate / r->o_ss.rate); - j = j > i->i_counter ? j - i->i_counter : 0; if (j >= nframes) break; - + assert(o_index*fz < out->memblock->length); memcpy((uint8_t*) out->memblock->data + fz*o_index, @@ -357,15 +356,15 @@ static void trivial_run(struct pa_resampler *r, const struct pa_memchunk *in, st out->length = o_index*fz; } - - /* Normalize the output counter */ - while (i->o_counter >= r->o_ss.rate) - i->o_counter -= r->o_ss.rate; i->i_counter += nframes; - while (i->i_counter >= r->i_ss.rate) + /* Normalize counters */ + while (i->i_counter >= r->i_ss.rate) { i->i_counter -= r->i_ss.rate; + assert(i->o_counter >= r->o_ss.rate); + i->o_counter -= r->o_ss.rate; + } } static void trivial_free(struct pa_resampler *r) { -- cgit From 73eabece3365c1bb47bf6b009682219c4492fda5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 11 Dec 2004 00:10:41 +0000 Subject: * add first part of zeroconf publisher * bump version to 0.7.1. * improve logging subsystem (introducing log levels) * remove verbose flag on cli * add new API pa_sample_format_to_string() * replace strtol() by usages of pa_atou() and pa_atoi() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@317 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 8 +- polyp/Makefile.am | 21 ++++- polyp/caps.c | 4 +- polyp/cli-command.c | 224 ++++++++++++++++++++------------------------- polyp/cli-command.h | 9 +- polyp/cli.c | 5 +- polyp/client.c | 6 +- polyp/client.h | 2 +- polyp/cmdline.c | 26 ++++-- polyp/conf-parser.c | 11 +-- polyp/daemon-conf.c | 77 +++++++++++++--- polyp/daemon-conf.h | 3 +- polyp/dumpmodules.c | 2 +- polyp/log.c | 74 +++++++++++++-- polyp/log.h | 27 +++++- polyp/main.c | 37 ++++---- polyp/memblockq.c | 4 +- polyp/modargs.c | 20 +--- polyp/module-combine.c | 8 +- polyp/module-defs.h.m4 | 11 ++- polyp/module-match.c | 15 ++- polyp/module-oss-mmap.c | 4 +- polyp/module-oss.c | 10 +- polyp/module-tunnel.c | 4 +- polyp/module-x11-bell.c | 4 +- polyp/module-x11-publish.c | 4 +- polyp/module.c | 8 +- polyp/namereg.c | 17 ++-- polyp/pid.c | 8 +- polyp/protocol-native.c | 6 +- polyp/sample.c | 13 ++- polyp/sample.h | 5 +- polyp/sink-input.c | 4 +- polyp/sink.c | 4 +- polyp/source-output.c | 6 ++ polyp/source.c | 4 +- polyp/util.c | 49 ++++++++-- polyp/util.h | 3 + 38 files changed, 467 insertions(+), 280 deletions(-) diff --git a/configure.ac b/configure.ac index 3ab9491f..5a4a4646 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. AC_PREREQ(2.57) -AC_INIT([polypaudio],[0.7],[mzcbylcnhqvb (at) 0pointer (dot) de]) +AC_INIT([polypaudio],[0.7.1],[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([polyp/main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) @@ -125,6 +125,12 @@ AC_SUBST(GLIB12_LIBS) AC_SUBST(HAVE_GLIB12) AM_CONDITIONAL([HAVE_GLIB12], [test "x$HAVE_GLIB12" = x1]) +PKG_CHECK_MODULES(HOWL, [ howl >= 0.9.8 ], HAVE_HOWL=1, HAVE_HOWL=0) +AC_SUBST(HOWL_CFLAGS) +AC_SUBST(HOWL_LIBS) +AC_SUBST(HAVE_HOWL) +AM_CONDITIONAL([HAVE_HOWL], [test "x$HAVE_HOWL" = x1]) + AC_PATH_PROG([M4], [m4 gm4], [no]) if test "x$M4" = xno ; then AC_MSG_ERROR([m4 missing]) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 7338b9e6..83b5670a 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -156,7 +156,8 @@ SYMDEF_FILES= \ module-tunnel-sink-symdef.h \ module-tunnel-source-symdef.h \ module-null-sink-symdef.h \ - module-esound-sink-symdef.h + module-esound-sink-symdef.h \ + module-zeroconf-publish-symdef.h EXTRA_DIST+=$(SYMDEF_FILES) BUILT_SOURCES+=$(SYMDEF_FILES) @@ -596,6 +597,24 @@ module_alsa_source_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la module_alsa_source_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) endif +### HOWL modules +if HAVE_HOWL +modlib_LTLIBRARIES+= \ + libhowl-wrap.la \ + module-zeroconf-publish.la + +libhowl_wrap_la_SOURCES = howl-wrap.c howl-wrap.h +libhowl_wrap_la_LDFLAGS = -avoid-version +libhowl_wrap_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) +libhowl_wrap_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) + +module_zeroconf_publish_la_SOURCES = module-zeroconf-publish.c +module_zeroconf_publish_la_LDFLAGS = -module -avoid-version +module_zeroconf_publish_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) libhowl-wrap.la +module_zeroconf_publish_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) + +endif + ### GLIB 2.0 support if HAVE_GLIB20 diff --git a/polyp/caps.c b/polyp/caps.c index 93fca89f..01ed1519 100644 --- a/polyp/caps.c +++ b/polyp/caps.c @@ -45,7 +45,7 @@ void pa_drop_root(void) { if (uid == 0 || geteuid() != 0) return; - /* pa_log(__FILE__": dropping root rights.\n"); */ + pa_log_info(__FILE__": dropping root rights.\n"); #if defined(HAVE_SETRESUID) setresuid(uid, uid, uid); @@ -76,7 +76,7 @@ int pa_limit_caps(void) { if (cap_set_proc(caps) < 0) goto fail; -/* pa_log(__FILE__": dropped capabilities successfully.\n"); */ + pa_log_info(__FILE__": dropped capabilities successfully.\n"); r = 0; diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 72e04bf8..0e8e09a5 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -48,45 +48,50 @@ #include "xmalloc.h" #include "sound-file-stream.h" #include "props.h" +#include "util.h" struct command { const char *name; - int (*proc) (struct pa_core *c, struct pa_tokenizer*t, struct pa_strbuf *buf, int *fail, int *verbose); + int (*proc) (struct pa_core *c, struct pa_tokenizer*t, struct pa_strbuf *buf, int *fail); const char *help; unsigned args; }; +#define INCLUDE_META ".include" +#define FAIL_META ".fail" +#define NOFAIL_META ".nofail" + /* Prototypes for all available commands */ -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 int pa_cli_command_scache_play(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); -static int pa_cli_command_scache_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); -static int pa_cli_command_scache_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); -static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); -static int pa_cli_command_scache_load_dir(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); -static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); -static int pa_cli_command_autoload_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); -static int pa_cli_command_autoload_add(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); -static int pa_cli_command_autoload_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); -static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); -static int pa_cli_command_list_props(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_exit(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_help(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_modules(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_clients(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_sinks(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_sources(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_sink_inputs(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_source_outputs(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_stat(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_info(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_unload(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_sink_volume(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_sink_input_volume(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_sink_default(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_source_default(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_kill_client(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_kill_sink_input(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_kill_source_output(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_play(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_load_dir(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_autoload_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_autoload_add(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_autoload_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_list_props(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); /* A method table for all available commands */ @@ -134,22 +139,21 @@ 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) + uint32_t index; + + if (pa_atou(n, &index) < 0) return (uint32_t) PA_IDXSET_INVALID; - return (uint32_t) index; + return index; } -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_exit(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { 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) { +static int pa_cli_command_help(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { const struct command*command; assert(c && t && buf); @@ -161,7 +165,7 @@ static int pa_cli_command_help(struct pa_core *c, struct pa_tokenizer *t, struct return 0; } -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_modules(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { char *s; assert(c && t); s = pa_module_list_to_string(c); @@ -171,7 +175,7 @@ static int pa_cli_command_modules(struct pa_core *c, struct pa_tokenizer *t, str return 0; } -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_clients(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { char *s; assert(c && t); s = pa_client_list_to_string(c); @@ -181,7 +185,7 @@ static int pa_cli_command_clients(struct pa_core *c, struct pa_tokenizer *t, str return 0; } -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_sinks(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { char *s; assert(c && t); s = pa_sink_list_to_string(c); @@ -191,7 +195,7 @@ static int pa_cli_command_sinks(struct pa_core *c, struct pa_tokenizer *t, struc return 0; } -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_sources(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { char *s; assert(c && t); s = pa_source_list_to_string(c); @@ -201,7 +205,7 @@ static int pa_cli_command_sources(struct pa_core *c, struct pa_tokenizer *t, str 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) { +static int pa_cli_command_sink_inputs(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { char *s; assert(c && t); s = pa_sink_input_list_to_string(c); @@ -211,7 +215,7 @@ static int pa_cli_command_sink_inputs(struct pa_core *c, struct pa_tokenizer *t, 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) { +static int pa_cli_command_source_outputs(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { char *s; assert(c && t); s = pa_source_output_list_to_string(c); @@ -221,7 +225,7 @@ static int pa_cli_command_source_outputs(struct pa_core *c, struct pa_tokenizer return 0; } -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_stat(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { char s[256]; assert(c && t); @@ -249,24 +253,23 @@ static int pa_cli_command_stat(struct pa_core *c, struct pa_tokenizer *t, struct return 0; } -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_info(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { 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); - pa_cli_command_scache_list(c, t, buf, fail, verbose); - pa_cli_command_autoload_list(c, t, buf, fail, verbose); + pa_cli_command_stat(c, t, buf, fail); + pa_cli_command_modules(c, t, buf, fail); + pa_cli_command_sinks(c, t, buf, fail); + pa_cli_command_sources(c, t, buf, fail); + pa_cli_command_clients(c, t, buf, fail); + pa_cli_command_sink_inputs(c, t, buf, fail); + pa_cli_command_source_outputs(c, t, buf, fail); + pa_cli_command_scache_list(c, t, buf, fail); + pa_cli_command_autoload_list(c, t, buf, fail); return 0; } -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_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { struct pa_module *m; const char *name; - char txt[256]; assert(c && t); if (!(name = pa_tokenizer_get(t, 1))) { @@ -279,14 +282,10 @@ static int pa_cli_command_load(struct pa_core *c, struct pa_tokenizer *t, struct 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) { +static int pa_cli_command_unload(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { struct pa_module *m; uint32_t index; const char *i; @@ -308,11 +307,10 @@ static int pa_cli_command_unload(struct pa_core *c, struct pa_tokenizer *t, stru 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) { +static int pa_cli_command_sink_volume(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { const char *n, *v; - char *x = NULL; struct pa_sink *sink; - long volume; + uint32_t 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"); @@ -324,8 +322,7 @@ static int pa_cli_command_sink_volume(struct pa_core *c, struct pa_tokenizer *t, return -1; } - volume = strtol(v, &x, 0); - if (!x || *x != 0 || volume < 0) { + if (pa_atou(v, &volume) < 0) { pa_strbuf_puts(buf, "Failed to parse volume.\n"); return -1; } @@ -339,12 +336,11 @@ static int pa_cli_command_sink_volume(struct pa_core *c, struct pa_tokenizer *t, 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) { +static int pa_cli_command_sink_input_volume(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { const char *n, *v; struct pa_sink_input *si; - long volume; + uint32_t 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"); @@ -361,9 +357,7 @@ static int pa_cli_command_sink_input_volume(struct pa_core *c, struct pa_tokeniz return -1; } - x = NULL; - volume = strtol(v, &x, 0); - if (!x || *x != 0 || volume < 0) { + if (pa_atou(v, &volume) < 0) { pa_strbuf_puts(buf, "Failed to parse volume.\n"); return -1; } @@ -377,7 +371,7 @@ static int pa_cli_command_sink_input_volume(struct pa_core *c, struct pa_tokeniz 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) { +static int pa_cli_command_sink_default(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { const char *n; assert(c && t); @@ -390,7 +384,7 @@ static int pa_cli_command_sink_default(struct pa_core *c, struct pa_tokenizer *t 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) { +static int pa_cli_command_source_default(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { const char *n; assert(c && t); @@ -403,7 +397,7 @@ static int pa_cli_command_source_default(struct pa_core *c, struct pa_tokenizer 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) { +static int pa_cli_command_kill_client(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { const char *n; struct pa_client *client; uint32_t index; @@ -428,7 +422,7 @@ static int pa_cli_command_kill_client(struct pa_core *c, struct pa_tokenizer *t, 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) { +static int pa_cli_command_kill_sink_input(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { const char *n; struct pa_sink_input *sink_input; uint32_t index; @@ -453,7 +447,7 @@ static int pa_cli_command_kill_sink_input(struct pa_core *c, struct pa_tokenizer 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) { +static int pa_cli_command_kill_source_output(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { const char *n; struct pa_source_output *source_output; uint32_t index; @@ -478,7 +472,7 @@ static int pa_cli_command_kill_source_output(struct pa_core *c, struct pa_tokeni return 0; } -static int pa_cli_command_scache_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { +static int pa_cli_command_scache_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { char *s; assert(c && t); s = pa_scache_list_to_string(c); @@ -488,10 +482,10 @@ static int pa_cli_command_scache_list(struct pa_core *c, struct pa_tokenizer *t, return 0; } -static int pa_cli_command_scache_play(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { +static int pa_cli_command_scache_play(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { const char *n, *sink_name; struct pa_sink *sink; - assert(c && t && buf && fail && verbose); + assert(c && t && buf && fail); if (!(n = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) { pa_strbuf_puts(buf, "You need to specify a sample name and a sink name.\n"); @@ -511,9 +505,9 @@ static int pa_cli_command_scache_play(struct pa_core *c, struct pa_tokenizer *t, return 0; } -static int pa_cli_command_scache_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { +static int pa_cli_command_scache_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { const char *n; - assert(c && t && buf && fail && verbose); + assert(c && t && buf && fail); if (!(n = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify a sample name.\n"); @@ -528,10 +522,10 @@ static int pa_cli_command_scache_remove(struct pa_core *c, struct pa_tokenizer * return 0; } -static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { +static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { const char *fname, *n; int r; - assert(c && t && buf && fail && verbose); + assert(c && t && buf && fail); if (!(fname = pa_tokenizer_get(t, 2)) || !(n = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify a file name and a sample name.\n"); @@ -549,9 +543,9 @@ static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t, return 0; } -static int pa_cli_command_scache_load_dir(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { +static int pa_cli_command_scache_load_dir(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { const char *pname; - assert(c && t && buf && fail && verbose); + assert(c && t && buf && fail); if (!(pname = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify a path name.\n"); @@ -566,10 +560,10 @@ static int pa_cli_command_scache_load_dir(struct pa_core *c, struct pa_tokenizer return 0; } -static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { +static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { const char *fname, *sink_name; struct pa_sink *sink; - assert(c && t && buf && fail && verbose); + assert(c && t && buf && fail); if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) { pa_strbuf_puts(buf, "You need to specify a file name and a sink name.\n"); @@ -585,9 +579,9 @@ static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, s return pa_play_file(sink, fname, PA_VOLUME_NORM); } -static int pa_cli_command_autoload_add(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { +static int pa_cli_command_autoload_add(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { const char *a, *b; - assert(c && t && buf && fail && verbose); + assert(c && t && buf && fail); if (!(a = pa_tokenizer_get(t, 1)) || !(b = pa_tokenizer_get(t, 2))) { pa_strbuf_puts(buf, "You need to specify a device name, a filename or a module name and optionally module arguments\n"); @@ -599,9 +593,9 @@ static int pa_cli_command_autoload_add(struct pa_core *c, struct pa_tokenizer *t return 0; } -static int pa_cli_command_autoload_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { +static int pa_cli_command_autoload_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { const char *name; - assert(c && t && buf && fail && verbose); + assert(c && t && buf && fail); if (!(name = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify a device name\n"); @@ -616,7 +610,7 @@ static int pa_cli_command_autoload_remove(struct pa_core *c, struct pa_tokenizer return 0; } -static int pa_cli_command_autoload_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { +static int pa_cli_command_autoload_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { char *s; assert(c && t); s = pa_autoload_list_to_string(c); @@ -626,13 +620,13 @@ static int pa_cli_command_autoload_list(struct pa_core *c, struct pa_tokenizer * return 0; } -static int pa_cli_command_list_props(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { +static int pa_cli_command_list_props(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { assert(c && t); pa_property_dump(c, buf); return 0; } -static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { +static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { struct pa_module *m; struct pa_sink *s; int nl; @@ -724,7 +718,7 @@ static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct } -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_line(struct pa_core *c, const char *s, struct pa_strbuf *buf, int *fail) { const char *cs; cs = s+strspn(s, whitespace); @@ -732,28 +726,18 @@ int pa_cli_command_execute_line(struct pa_core *c, const char *s, struct pa_strb 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)) + if (!strcmp(cs, FAIL_META)) *fail = 1; - else if (!strcmp(cs, nofail_meta)) + 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)) { + 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 (pa_cli_command_execute_file(c, filename, buf, fail) < 0) if (*fail) return -1; } else { pa_strbuf_printf(buf, "Invalid meta command: %s\n", cs); @@ -772,7 +756,7 @@ int pa_cli_command_execute_line(struct pa_core *c, const char *s, struct pa_strb int ret; struct pa_tokenizer *t = pa_tokenizer_new(cs, command->args); assert(t); - ret = command->proc(c, t, buf, fail, verbose); + ret = command->proc(c, t, buf, fail); pa_tokenizer_free(t); unknown = 0; @@ -792,7 +776,7 @@ int pa_cli_command_execute_line(struct pa_core *c, const char *s, struct pa_strb return 0; } -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_file(struct pa_core *c, const char *fn, struct pa_strbuf *buf, int *fail) { char line[256]; FILE *f = NULL; int ret = -1; @@ -805,20 +789,14 @@ int pa_cli_command_execute_file(struct pa_core *c, const char *fn, struct pa_str 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) + if (pa_cli_command_execute_line(c, line, buf, fail) < 0 && *fail) goto fail; } - if (*verbose) - pa_strbuf_printf(buf, "Executed file: '%s'\n", fn); - ret = 0; fail: @@ -828,16 +806,16 @@ fail: return ret; } -int pa_cli_command_execute(struct pa_core *c, const char *s, 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) { const char *p; - assert(c && s && buf && fail && verbose); + assert(c && s && buf && fail); p = s; while (*p) { size_t l = strcspn(p, linebreak); char *line = pa_xstrndup(p, l); - if (pa_cli_command_execute_line(c, line, buf, fail, verbose) < 0&& *fail) { + if (pa_cli_command_execute_line(c, line, buf, fail) < 0&& *fail) { pa_xfree(line); return -1; } diff --git a/polyp/cli-command.h b/polyp/cli-command.h index 4887c55e..7af9d014 100644 --- a/polyp/cli-command.h +++ b/polyp/cli-command.h @@ -27,15 +27,14 @@ /* Execute a single CLI command. Write the results to the string * buffer *buf. If *fail is non-zero the function will return -1 when - * one or more of the executed commands failed. If *verbose is - * non-zero the command is executed verbosely. Both *verbose and *fail + * one or more of the executed commands failed. *fail * may be modified by the function call. */ -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_line(struct pa_core *c, const char *s, struct pa_strbuf *buf, int *fail); /* Execute a whole file of CLI commands */ -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_file(struct pa_core *c, const char *fn, struct pa_strbuf *buf, int *fail); /* Split the specified string into lines and run pa_cli_command_execute_line() for each. */ -int pa_cli_command_execute(struct pa_core *c, const char *s, 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); #endif diff --git a/polyp/cli.c b/polyp/cli.c index 7780d03d..04fbb7e0 100644 --- a/polyp/cli.c +++ b/polyp/cli.c @@ -55,7 +55,7 @@ struct pa_cli { struct pa_client *client; - int fail, verbose, kill_requested, defer_kill; + int fail, kill_requested, defer_kill; }; static void line_callback(struct pa_ioline *line, const char *s, void *userdata); @@ -85,7 +85,6 @@ struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io, struct pa_ioline_puts(c->line, "Welcome to polypaudio! Use \"help\" for usage information.\n"PROMPT); c->fail = c->kill_requested = c->defer_kill = 0; - c->verbose = 1; return c; } @@ -129,7 +128,7 @@ static void line_callback(struct pa_ioline *line, const char *s, void *userdata) buf = pa_strbuf_new(); assert(buf); c->defer_kill++; - pa_cli_command_execute_line(c->core, s, buf, &c->fail, &c->verbose); + pa_cli_command_execute_line(c->core, s, buf, &c->fail); c->defer_kill--; pa_ioline_puts(line, p = pa_strbuf_tostring_free(buf)); pa_xfree(p); diff --git a/polyp/client.c b/polyp/client.c index 22c7197a..40f5e385 100644 --- a/polyp/client.c +++ b/polyp/client.c @@ -50,7 +50,7 @@ struct pa_client *pa_client_new(struct pa_core *core, const char *protocol_name, r = pa_idxset_put(core->clients, c, &c->index); assert(c->index != PA_IDXSET_INVALID && r >= 0); - pa_log(__FILE__": created %u \"%s\"\n", c->index, c->name); + pa_log_info(__FILE__": created %u \"%s\"\n", c->index, c->name); pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index); pa_core_check_quit(core); @@ -65,7 +65,7 @@ void pa_client_free(struct pa_client *c) { pa_core_check_quit(c->core); - pa_log(__FILE__": freed %u \"%s\"\n", c->index, c->name); + pa_log_info(__FILE__": freed %u \"%s\"\n", c->index, c->name); pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index); pa_xfree(c->name); pa_xfree(c->protocol_name); @@ -76,7 +76,7 @@ void pa_client_free(struct pa_client *c) { void pa_client_kill(struct pa_client *c) { assert(c); if (!c->kill) { - pa_log(__FILE__": kill() operation not implemented for client %u\n", c->index); + pa_log_warn(__FILE__": kill() operation not implemented for client %u\n", c->index); return; } diff --git a/polyp/client.h b/polyp/client.h index 58c5ee31..324bb27c 100644 --- a/polyp/client.h +++ b/polyp/client.h @@ -35,7 +35,7 @@ struct pa_client { struct pa_module *owner; char *name; struct pa_core *core; - const char *protocol_name; + char *protocol_name; void (*kill)(struct pa_client *c); void *userdata; diff --git a/polyp/cmdline.c b/polyp/cmdline.c index a39f6ca6..0951725a 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -43,7 +43,7 @@ enum { ARG_DUMP_MODULES, ARG_DAEMONIZE, ARG_FAIL, - ARG_VERBOSE, + ARG_LOG_LEVEL, ARG_HIGH_PRIORITY, ARG_DISALLOW_MODULE_LOADING, ARG_EXIT_IDLE_TIME, @@ -67,7 +67,8 @@ static struct option long_options[] = { {"dump-modules", 0, 0, ARG_DUMP_MODULES}, {"daemonize", 2, 0, ARG_DAEMONIZE}, {"fail", 2, 0, ARG_FAIL}, - {"verbose", 2, 0, ARG_VERBOSE}, + {"verbose", 2, 0, ARG_LOG_LEVEL}, + {"log-level", 2, 0, ARG_LOG_LEVEL}, {"high-priority", 2, 0, ARG_HIGH_PRIORITY}, {"disallow-module-loading", 2, 0, ARG_DISALLOW_MODULE_LOADING}, {"exit-idle-time", 2, 0, ARG_EXIT_IDLE_TIME}, @@ -104,7 +105,6 @@ void pa_cmdline_help(const char *argv0) { "OPTIONS:\n" " -D, --daemonize[=BOOL] Daemonize after startup\n" " --fail[=BOOL] Quit when startup fails\n" - " --verbose[=BOOL] Be slightly more verbose\n" " --high-priority[=BOOL] Try to set high process priority\n" " (only available as root)\n" " --disallow-module-loading[=BOOL] Disallow module loading after startup\n" @@ -114,6 +114,8 @@ void pa_cmdline_help(const char *argv0) { " this time passed\n" " --scache-idle-time=SECS Unload autoloaded samples when idle and\n" " this time passed\n" + " --log-level[=LEVEL] Increase or set verbosity level\n" + " -v Increase the verbosity level\n" " --log-target={auto,syslog,stderr} Specify the log target\n" " -p, --dl-search-path=PATH Set the search path for dynamic shared\n" " objects (plugins)\n" @@ -143,7 +145,7 @@ int pa_cmdline_parse(struct pa_daemon_conf *conf, int argc, char *const argv [], if (conf->script_commands) pa_strbuf_puts(buf, conf->script_commands); - while ((c = getopt_long(argc, argv, "L:F:ChDnp:k", long_options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "L:F:ChDnp:kv", long_options, NULL)) != -1) { switch (c) { case ARG_HELP: case 'h': @@ -200,11 +202,19 @@ int pa_cmdline_parse(struct pa_daemon_conf *conf, int argc, char *const argv [], } break; - case ARG_VERBOSE: - if ((conf->verbose = optarg ? pa_parse_boolean(optarg) : 1) < 0) { - pa_log(__FILE__": --verbose expects boolean argument\n"); - goto fail; + case 'v': + case ARG_LOG_LEVEL: + + if (optarg) { + if (pa_daemon_conf_set_log_level(conf, optarg) < 0) { + pa_log(__FILE__": --log-level expects log level argument (either numeric in range 0..4 or one of debug, info, notice, warn, error).\n"); + goto fail; + } + } else { + if (conf->log_level < PA_LOG_LEVEL_MAX-1) + conf->log_level++; } + break; case ARG_HIGH_PRIORITY: diff --git a/polyp/conf-parser.c b/polyp/conf-parser.c index 35c4766e..b25508e2 100644 --- a/polyp/conf-parser.c +++ b/polyp/conf-parser.c @@ -135,17 +135,16 @@ finish: } int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { - int *i = data, k; - char *x = NULL; + int *i = data; + int32_t k; assert(filename && lvalue && rvalue && data); - - k = strtol(rvalue, &x, 0); - if (!*rvalue || !x || *x) { + + if (pa_atoi(rvalue, &k) < 0) { pa_log(__FILE__": [%s:%u] Failed to parse numeric value: %s\n", filename, line, rvalue); return -1; } - *i = k; + *i = (int) k; return 0; } diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c index 7753da6a..a6afd05a 100644 --- a/polyp/daemon-conf.c +++ b/polyp/daemon-conf.c @@ -53,7 +53,6 @@ static const struct pa_daemon_conf default_conf = { .cmd = PA_CMD_DAEMON, .daemonize = 0, .fail = 1, - .verbose = 0, .high_priority = 0, .disallow_module_loading = 0, .exit_idle_time = -1, @@ -64,6 +63,7 @@ static const struct pa_daemon_conf default_conf = { .dl_search_path = NULL, .default_script_file = NULL, .log_target = PA_LOG_SYSLOG, + .log_level = PA_LOG_NOTICE, .resample_method = PA_RESAMPLER_SRC_SINC_FASTEST, .config_file = NULL, .use_pid_file = 1 @@ -108,6 +108,31 @@ int pa_daemon_conf_set_log_target(struct pa_daemon_conf *c, const char *string) return 0; } +int pa_daemon_conf_set_log_level(struct pa_daemon_conf *c, const char *string) { + uint32_t u; + assert(c && string); + + if (pa_atou(string, &u) >= 0) { + if (u >= PA_LOG_LEVEL_MAX) + return -1; + + c->log_level = (enum pa_log_level) u; + } else if (pa_startswith(string, "debug")) + c->log_level = PA_LOG_DEBUG; + else if (pa_startswith(string, "info")) + c->log_level = PA_LOG_INFO; + else if (pa_startswith(string, "notice")) + c->log_level = PA_LOG_NOTICE; + else if (pa_startswith(string, "warn")) + c->log_level = PA_LOG_WARN; + else if (pa_startswith(string, "err")) + c->log_level = PA_LOG_ERROR; + else + return -1; + + return 0; +} + int pa_daemon_conf_set_resample_method(struct pa_daemon_conf *c, const char *string) { int m; assert(c && string); @@ -131,6 +156,18 @@ static int parse_log_target(const char *filename, unsigned line, const char *lva return 0; } +static int parse_log_level(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { + struct pa_daemon_conf *c = data; + assert(filename && lvalue && rvalue && data); + + if (pa_daemon_conf_set_log_level(c, rvalue) < 0) { + pa_log(__FILE__": [%s:%u] Invalid log level '%s'.\n", filename, line, rvalue); + return -1; + } + + return 0; +} + static int parse_resample_method(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { struct pa_daemon_conf *c = data; assert(filename && lvalue && rvalue && data); @@ -148,7 +185,6 @@ int pa_daemon_conf_load(struct pa_daemon_conf *c, const char *filename) { FILE *f = NULL; struct pa_config_item table[] = { - { "verbose", pa_config_parse_bool, NULL }, { "daemonize", pa_config_parse_bool, NULL }, { "fail", pa_config_parse_bool, NULL }, { "high-priority", pa_config_parse_bool, NULL }, @@ -159,24 +195,27 @@ int pa_daemon_conf_load(struct pa_daemon_conf *c, const char *filename) { { "dl-search-path", pa_config_parse_string, NULL }, { "default-script-file", pa_config_parse_string, NULL }, { "log-target", parse_log_target, NULL }, + { "log-level", parse_log_level, NULL }, + { "verbose", parse_log_level, NULL }, { "resample-method", parse_resample_method, NULL }, { "use-pid-file", pa_config_parse_bool, NULL }, { NULL, NULL, NULL }, }; - table[0].data = &c->verbose; - table[1].data = &c->daemonize; - table[2].data = &c->fail; - table[3].data = &c->high_priority; - table[4].data = &c->disallow_module_loading; - table[5].data = &c->exit_idle_time; - table[6].data = &c->module_idle_time; - table[7].data = &c->scache_idle_time; - table[8].data = &c->dl_search_path; - table[9].data = &c->default_script_file; + table[0].data = &c->daemonize; + table[1].data = &c->fail; + table[2].data = &c->high_priority; + table[3].data = &c->disallow_module_loading; + table[4].data = &c->exit_idle_time; + table[5].data = &c->module_idle_time; + table[6].data = &c->scache_idle_time; + table[7].data = &c->dl_search_path; + table[8].data = &c->default_script_file; + table[9].data = c; table[10].data = c; table[11].data = c; - table[12].data = &c->use_pid_file; + table[12].data = c; + table[13].data = &c->use_pid_file; pa_xfree(c->config_file); c->config_file = NULL; @@ -214,13 +253,22 @@ int pa_daemon_conf_env(struct pa_daemon_conf *c) { return 0; } +static const char* const log_level_to_string[] = { + [PA_LOG_DEBUG] = "debug", + [PA_LOG_INFO] = "info", + [PA_LOG_NOTICE] = "notice", + [PA_LOG_WARN] = "warning", + [PA_LOG_ERROR] = "error" +}; + char *pa_daemon_conf_dump(struct pa_daemon_conf *c) { struct pa_strbuf *s = pa_strbuf_new(); if (c->config_file) pa_strbuf_printf(s, "### Read from configuration file: %s ###\n", c->config_file); + + assert(c->log_level <= PA_LOG_LEVEL_MAX); - pa_strbuf_printf(s, "verbose = %i\n", !!c->verbose); pa_strbuf_printf(s, "daemonize = %i\n", !!c->daemonize); pa_strbuf_printf(s, "fail = %i\n", !!c->fail); pa_strbuf_printf(s, "high-priority = %i\n", !!c->high_priority); @@ -231,6 +279,7 @@ char *pa_daemon_conf_dump(struct pa_daemon_conf *c) { pa_strbuf_printf(s, "dl-search-path = %s\n", c->dl_search_path ? c->dl_search_path : ""); pa_strbuf_printf(s, "default-script-file = %s\n", c->default_script_file); pa_strbuf_printf(s, "log-target = %s\n", c->auto_log_target ? "auto" : (c->log_target == PA_LOG_SYSLOG ? "syslog" : "stderr")); + pa_strbuf_printf(s, "log-level = %s\n", log_level_to_string[c->log_level]); pa_strbuf_printf(s, "resample-method = %s\n", pa_resample_method_to_string(c->resample_method)); pa_strbuf_printf(s, "use-pid-file = %i\n", c->use_pid_file); diff --git a/polyp/daemon-conf.h b/polyp/daemon-conf.h index f163400f..30137e8b 100644 --- a/polyp/daemon-conf.h +++ b/polyp/daemon-conf.h @@ -40,7 +40,6 @@ struct pa_daemon_conf { enum pa_daemon_conf_cmd cmd; int daemonize, fail, - verbose, high_priority, disallow_module_loading, exit_idle_time, @@ -50,6 +49,7 @@ struct pa_daemon_conf { use_pid_file; char *script_commands, *dl_search_path, *default_script_file; enum pa_log_target log_target; + enum pa_log_level log_level; int resample_method; char *config_file; }; @@ -74,6 +74,7 @@ int pa_daemon_conf_env(struct pa_daemon_conf *c); /* Set these configuration variables in the structure by passing a string */ int pa_daemon_conf_set_log_target(struct pa_daemon_conf *c, const char *string); +int pa_daemon_conf_set_log_level(struct pa_daemon_conf *c, const char *string); int pa_daemon_conf_set_resample_method(struct pa_daemon_conf *c, const char *string); #endif diff --git a/polyp/dumpmodules.c b/polyp/dumpmodules.c index 1903fe00..1dc14edc 100644 --- a/polyp/dumpmodules.c +++ b/polyp/dumpmodules.c @@ -86,7 +86,7 @@ static int callback(const char *path, lt_ptr data) { e = path; if (strlen(e) > sizeof(PREFIX)-1 && !strncmp(e, PREFIX, sizeof(PREFIX)-1)) - show_info(e, path, c->verbose ? long_info : short_info); + show_info(e, path, c->log_level >= PA_LOG_INFO ? long_info : short_info); return 0; } diff --git a/polyp/log.c b/polyp/log.c index dc41dcd2..530fa691 100644 --- a/polyp/log.c +++ b/polyp/log.c @@ -34,7 +34,16 @@ static char *log_ident = NULL; static enum pa_log_target log_target = PA_LOG_STDERR; -static void (*user_log_func)(const char *s) = NULL; +static void (*user_log_func)(enum pa_log_level l, const char *s) = NULL; +static enum pa_log_level maximal_level = PA_LOG_NOTICE; + +static const int level_to_syslog[] = { + [PA_LOG_ERROR] = LOG_ERR, + [PA_LOG_WARN] = LOG_WARNING, + [PA_LOG_NOTICE] = LOG_NOTICE, + [PA_LOG_INFO] = LOG_INFO, + [PA_LOG_DEBUG] = LOG_DEBUG +}; void pa_log_set_ident(const char *p) { if (log_ident) @@ -43,34 +52,85 @@ void pa_log_set_ident(const char *p) { log_ident = pa_xstrdup(p); } -void pa_log_set_target(enum pa_log_target t, void (*func)(const char*s)) { +void pa_log_set_maximal_level(enum pa_log_level l) { + assert(l < PA_LOG_LEVEL_MAX); + maximal_level = l; +} + +void pa_log_set_target(enum pa_log_target t, void (*func)(enum pa_log_level l, const char*s)) { assert(t == PA_LOG_USER || !func); log_target = t; user_log_func = func; } -void pa_log(const char *format, ...) { - va_list ap; - va_start(ap, format); +void pa_log_levelv(enum pa_log_level level, const char *format, va_list ap) { + assert(level < PA_LOG_LEVEL_MAX); + if (level > maximal_level) + return; + switch (log_target) { case PA_LOG_STDERR: vfprintf(stderr, format, ap); break; + case PA_LOG_SYSLOG: openlog(log_ident ? log_ident : "???", LOG_PID, LOG_USER); - vsyslog(LOG_INFO, format, ap); + vsyslog(level_to_syslog[level], format, ap); closelog(); break; + case PA_LOG_USER: { char *t = pa_vsprintf_malloc(format, ap); assert(user_log_func); - user_log_func(t); + user_log_func(level, t); pa_xfree(t); } + case PA_LOG_NULL: break; } +} + +void pa_log_level(enum pa_log_level level, const char *format, ...) { + va_list ap; + va_start(ap, format); + pa_log_levelv(level, format, ap); + va_end(ap); +} + +void pa_log_debug(const char *format, ...) { + va_list ap; + va_start(ap, format); + pa_log_levelv(PA_LOG_DEBUG, format, ap); + va_end(ap); +} + +void pa_log_info(const char *format, ...) { + va_list ap; + va_start(ap, format); + pa_log_levelv(PA_LOG_INFO, format, ap); + va_end(ap); +} + +void pa_log_notice(const char *format, ...) { + va_list ap; + va_start(ap, format); + pa_log_levelv(PA_LOG_INFO, format, ap); + va_end(ap); +} + +void pa_log_warn(const char *format, ...) { + va_list ap; + va_start(ap, format); + pa_log_levelv(PA_LOG_WARN, format, ap); + va_end(ap); +} + +void pa_log_error(const char *format, ...) { + va_list ap; + va_start(ap, format); + pa_log_levelv(PA_LOG_ERROR, format, ap); va_end(ap); } diff --git a/polyp/log.h b/polyp/log.h index cf55386c..fe2dad59 100644 --- a/polyp/log.h +++ b/polyp/log.h @@ -22,6 +22,7 @@ USA. ***/ +#include #include "gcc-printf.h" /* A simple logging subsystem */ @@ -34,13 +35,35 @@ enum pa_log_target { PA_LOG_NULL /* to /dev/null */ }; +enum pa_log_level { + PA_LOG_ERROR = 0, /* Error messages */ + PA_LOG_WARN = 1, /* Warning messages */ + PA_LOG_NOTICE = 2, /* Notice messages */ + PA_LOG_INFO = 3, /* Info messages */ + PA_LOG_DEBUG = 4, /* debug message */ + PA_LOG_LEVEL_MAX +}; + /* Set an identifcation for the current daemon. Used when logging to syslog. */ void pa_log_set_ident(const char *p); /* Set another log target. If t is PA_LOG_USER you may specify a function that is called every log string */ -void pa_log_set_target(enum pa_log_target t, void (*func)(const char*s)); +void pa_log_set_target(enum pa_log_target t, void (*func)(enum pa_log_level, const char*s)); + +/* Minimal log level */ +void pa_log_set_maximal_level(enum pa_log_level l); /* Do a log line */ -void pa_log(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +void pa_log_debug(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +void pa_log_info(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +void pa_log_notice(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +void pa_log_warn(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +void pa_log_error(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); + +void pa_log_level(enum pa_log_level level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); + +void pa_log_levelv(enum pa_log_level level, const char *format, va_list ap); + +#define pa_log pa_log_error #endif diff --git a/polyp/main.c b/polyp/main.c index 0ba28e5a..f49232d4 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -64,7 +64,7 @@ int deny_severity = LOG_WARNING; #endif static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { - pa_log(__FILE__": Got signal %s.\n", pa_strsignal(sig)); + pa_log_info(__FILE__": Got signal %s.\n", pa_strsignal(sig)); switch (sig) { case SIGUSR1: @@ -108,7 +108,7 @@ static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, default: return; } - pa_log(c); + pa_log_notice(c); pa_xfree(c); } @@ -118,7 +118,7 @@ static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, case SIGINT: case SIGTERM: default: - pa_log(__FILE__": Exiting.\n"); + pa_log_info(__FILE__": Exiting.\n"); m->quit(m, 1); return; } @@ -150,7 +150,7 @@ int main(int argc, char *argv[]) { suid_root = getuid() != 0 && geteuid() == 0; if (suid_root && (pa_uid_in_group("realtime", &gid) <= 0 || gid >= 1000)) { - pa_log(__FILE__": WARNING: called SUID root, but not in group 'realtime'.\n"); + pa_log_warn(__FILE__": WARNING: called SUID root, but not in group 'realtime'.\n"); pa_drop_root(); } @@ -165,15 +165,16 @@ int main(int argc, char *argv[]) { if (pa_daemon_conf_load(conf, NULL) < 0) goto finish; - + if (pa_daemon_conf_env(conf) < 0) goto finish; - + if (pa_cmdline_parse(conf, argc, argv, &d) < 0) { pa_log(__FILE__": failed to parse command line.\n"); goto finish; } - + + pa_log_set_maximal_level(conf->log_level); pa_log_set_target(conf->auto_log_target ? PA_LOG_STDERR : conf->log_target, NULL); if (conf->high_priority && conf->cmd == PA_CMD_DAEMON) @@ -215,11 +216,9 @@ int main(int argc, char *argv[]) { pid_t pid; if (pa_pid_file_check_running(&pid) < 0) { - if (conf->verbose) - pa_log(__FILE__": daemon not running\n"); + pa_log_info(__FILE__": daemon not running\n"); } else { - if (conf->verbose) - pa_log(__FILE__": daemon running as PID %u\n", pid); + pa_log_info(__FILE__": daemon running as PID %u\n", pid); retval = 0; } @@ -268,8 +267,10 @@ int main(int argc, char *argv[]) { retval = 1; } - if (conf->verbose) - pa_log(__FILE__": daemon startup %s.\n", retval ? "failed" : "succeeded"); + if (retval) + pa_log(__FILE__": daemon startup failed .\n"); + else + pa_log_info(__FILE__": daemon startup successful.\n"); goto finish; } @@ -318,10 +319,10 @@ int main(int argc, char *argv[]) { buf = pa_strbuf_new(); assert(buf); if (conf->default_script_file) - r = pa_cli_command_execute_file(c, conf->default_script_file, buf, &conf->fail, &conf->verbose); + r = pa_cli_command_execute_file(c, conf->default_script_file, buf, &conf->fail); if (r >= 0) - r = pa_cli_command_execute(c, conf->script_commands, buf, &conf->fail, &conf->verbose); + r = pa_cli_command_execute(c, conf->script_commands, buf, &conf->fail); pa_log(s = pa_strbuf_tostring_free(buf)); pa_xfree(s); @@ -345,10 +346,10 @@ int main(int argc, char *argv[]) { c->scache_idle_time = conf->scache_idle_time; c->resample_method = conf->resample_method; - pa_log(__FILE__": Daemon startup complete.\n"); + pa_log_info(__FILE__": Daemon startup complete.\n"); if (pa_mainloop_run(mainloop, &retval) < 0) retval = 1; - pa_log(__FILE__": Daemon shutdown initiated.\n"); + pa_log_info(__FILE__": Daemon shutdown initiated.\n"); } pa_core_free(c); @@ -357,7 +358,7 @@ int main(int argc, char *argv[]) { pa_signal_done(); pa_mainloop_free(mainloop); - pa_log(__FILE__": Daemon terminated.\n"); + pa_log_info(__FILE__": Daemon terminated.\n"); finish: diff --git a/polyp/memblockq.c b/polyp/memblockq.c index 16c0da8e..3f2e4db1 100644 --- a/polyp/memblockq.c +++ b/polyp/memblockq.c @@ -58,7 +58,7 @@ struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t b bq->current_length = 0; - /*pa_log(__FILE__": memblockq requested: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", maxlength, tlength, base, prebuf, minreq);*/ + pa_log_debug(__FILE__": memblockq requested: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", maxlength, tlength, base, prebuf, minreq); bq->base = base; @@ -83,7 +83,7 @@ struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t b bq->orig_prebuf = bq->prebuf; - pa_log(__FILE__": memblockq sanitized: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", bq->maxlength, bq->tlength, bq->base, bq->prebuf, bq->minreq); + pa_log_debug(__FILE__": memblockq sanitized: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", bq->maxlength, bq->tlength, bq->base, bq->prebuf, bq->minreq); bq->mcalign = NULL; diff --git a/polyp/modargs.c b/polyp/modargs.c index 406f610f..9437d839 100644 --- a/polyp/modargs.c +++ b/polyp/modargs.c @@ -190,41 +190,27 @@ const char *pa_modargs_get_value(struct pa_modargs *ma, const char *key, const c int pa_modargs_get_value_u32(struct pa_modargs *ma, const char *key, uint32_t *value) { const char *v; - char *e; - unsigned long l; assert(ma && key && value); if (!(v = pa_modargs_get_value(ma, key, NULL))) return 0; - if (!*v) - return -1; - - l = strtoul(v, &e, 0); - if (*e) + if (pa_atou(v, value) < 0) return -1; - *value = (uint32_t) l; return 0; } int pa_modargs_get_value_s32(struct pa_modargs *ma, const char *key, int32_t *value) { const char *v; - char *e; - signed long l; assert(ma && key && value); if (!(v = pa_modargs_get_value(ma, key, NULL))) return 0; - if (!*v) + if (pa_atoi(v, value) < 0) return -1; - - l = strtol(v, &e, 0); - if (*e) - return -1; - - *value = (int32_t) l; + return 0; } diff --git a/polyp/module-combine.c b/polyp/module-combine.c index 95bd958f..7b3c26dd 100644 --- a/polyp/module-combine.c +++ b/polyp/module-combine.c @@ -111,7 +111,7 @@ static void adjust_rates(struct userdata *u) { target_latency = max_sink_latency > min_total_latency ? max_sink_latency : min_total_latency; - pa_log(__FILE__": [%s] target latency is %0.0f usec.\n", u->sink->name, (float) target_latency); + pa_log_info(__FILE__": [%s] target latency is %0.0f usec.\n", u->sink->name, (float) target_latency); base_rate = u->sink->sample_spec.rate; @@ -124,9 +124,9 @@ static void adjust_rates(struct userdata *u) { r += (uint32_t) (((((double) o->total_latency - target_latency))/u->adjust_time)*r/ 1000000); if (r < (uint32_t) (base_rate*0.9) || r > (uint32_t) (base_rate*1.1)) - pa_log(__FILE__": [%s] sample rates too different, not adjusting (%u vs. %u).\n", o->sink_input->name, base_rate, r); + pa_log_warn(__FILE__": [%s] sample rates too different, not adjusting (%u vs. %u).\n", o->sink_input->name, base_rate, r); else { - pa_log(__FILE__": [%s] new rate is %u Hz; ratio is %0.3f; latency is %0.0f usec.\n", o->sink_input->name, r, (double) r / base_rate, (float) o->total_latency); + pa_log_info(__FILE__": [%s] new rate is %u Hz; ratio is %0.3f; latency is %0.0f usec.\n", o->sink_input->name, r, (double) r / base_rate, (float) o->total_latency); pa_sink_input_set_rate(o->sink_input, r); } } @@ -358,7 +358,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { } if (u->n_outputs <= 1) - pa_log(__FILE__": WARNING: no slave sinks specified.\n"); + pa_log_warn(__FILE__": WARNING: no slave sinks specified.\n"); if (u->adjust_time > 0) { gettimeofday(&tv, NULL); diff --git a/polyp/module-defs.h.m4 b/polyp/module-defs.h.m4 index 85eb64a2..2b9cdf9e 100644 --- a/polyp/module-defs.h.m4 +++ b/polyp/module-defs.h.m4 @@ -1,13 +1,16 @@ dnl $Id$ changecom(`/*', `*/')dnl -define(`module', patsubst(patsubst(fname, `-symdef.h$'), `[^0-9a-zA-Z]', `_'))dnl -define(`c_symbol', patsubst(module, `[^0-9a-zA-Z]', `_'))dnl -define(`c_macro', patsubst(module, `[^0-9a-zA-Z]', `'))dnl +define(`module_name', patsubst(patsubst(fname, `-symdef.h$'), `[^0-9a-zA-Z]', `_'))dnl +define(`c_symbol', patsubst(module_name, `[^0-9a-zA-Z]', `_'))dnl +define(`c_macro', patsubst(module_name, `[^0-9a-zA-Z]', `'))dnl define(`incmacro', `foo'c_macro`symdeffoo')dnl -define(`gen_symbol', `#define $1 'module`_LTX_$1')dnl +define(`gen_symbol', `#define $1 'module_name`_LTX_$1')dnl #ifndef incmacro #define incmacro +#include "core.h" +#include "module.h" + gen_symbol(pa__init) gen_symbol(pa__done) gen_symbol(pa__get_author) diff --git a/polyp/module-match.c b/polyp/module-match.c index 6f4fc38c..7fdc5f3e 100644 --- a/polyp/module-match.c +++ b/polyp/module-match.c @@ -88,8 +88,9 @@ static int load_rules(struct userdata *u, const char *filename) { } while (!feof(f)) { - char *d, *v, *e = NULL; + char *d, *v; pa_volume_t volume; + uint32_t k; regex_t regex; char ln[256]; struct rule *rule; @@ -114,14 +115,14 @@ static int load_rules(struct userdata *u, const char *filename) { } *d = 0; - - volume = (pa_volume_t) strtol(v, &e, 0); - - if (!e || *e) { + if (pa_atou(v, &k) < 0) { pa_log(__FILE__": [%s:%u] failed to parse volume\n", filename, n); goto finish; } + volume = (pa_volume_t) k; + + if (regcomp(®ex, ln, REG_EXTENDED|REG_NOSUB) != 0) { pa_log(__FILE__": [%s:%u] invalid regular expression\n", filename, n); goto finish; @@ -162,10 +163,8 @@ static void callback(struct pa_core *c, enum pa_subscription_event_type t, uint3 if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW)) return; - if (!(si = pa_idxset_get_by_index(c->sink_inputs, index))) { - pa_log(__FILE__": WARNING: failed to get sink input\n"); + if (!(si = pa_idxset_get_by_index(c->sink_inputs, index))) return; - } if (!si->name) return; diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index 66daa77d..6fe4fa0c 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -289,7 +289,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { goto fail; } - pa_log(__FILE__": input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + pa_log_info(__FILE__": input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); u->in_mmap_length = (u->in_fragment_size = info.fragsize) * (u->in_fragments = info.fragstotal); if ((u->in_mmap = mmap(NULL, u->in_mmap_length, PROT_READ, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { @@ -320,7 +320,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { goto fail; } - pa_log(__FILE__": output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + pa_log_info(__FILE__": output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); u->out_mmap_length = (u->out_fragment_size = info.fragsize) * (u->out_fragments = info.fragstotal); if ((u->out_mmap = mmap(NULL, u->out_mmap_length, PROT_WRITE, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { diff --git a/polyp/module-oss.c b/polyp/module-oss.c index fe12b0bb..fa01876d 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -214,7 +214,7 @@ static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { assert(s && u && u->sink); if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { - pa_log(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY.\n"); + pa_log_info(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY.\n"); s->get_latency = NULL; return 0; } @@ -230,7 +230,7 @@ static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { static pa_usec_t source_get_latency_cb(struct pa_source *s) { struct userdata *u = s->userdata; audio_buf_info info; - assert(s && u && u->sink); + assert(s && u && u->source); if (!u->use_getispace) return 0; @@ -291,7 +291,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { if ((fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, NULL)) < 0) goto fail; - pa_log(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + pa_log_info(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); if (nfrags >= 2 && frag_size >= 1) @@ -313,13 +313,13 @@ int pa__init(struct pa_core *c, struct pa_module*m) { u->use_getospace = u->use_getispace = 0; if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { - pa_log(__FILE__": input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + pa_log_info(__FILE__": input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); in_frag_size = info.fragsize; u->use_getispace = 1; } if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) { - pa_log(__FILE__": output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + pa_log_info(__FILE__": output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); out_frag_size = info.fragsize; u->use_getospace = 1; } diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c index 39aaab57..d165aab8 100644 --- a/polyp/module-tunnel.c +++ b/polyp/module-tunnel.c @@ -545,7 +545,7 @@ static int load_key(struct userdata *u, const char*fn) { u->auth_cookie_in_property = 0; if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { - pa_log(__FILE__": using already loaded auth cookie.\n"); + pa_log_debug(__FILE__": using already loaded auth cookie.\n"); pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); u->auth_cookie_in_property = 1; return 0; @@ -557,7 +557,7 @@ static int load_key(struct userdata *u, const char*fn) { if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) return -1; - pa_log(__FILE__": loading cookie from disk.\n"); + pa_log_debug(__FILE__": loading cookie from disk.\n"); if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) u->auth_cookie_in_property = 1; diff --git a/polyp/module-x11-bell.c b/polyp/module-x11-bell.c index c3987704..084f5d4b 100644 --- a/polyp/module-x11-bell.c +++ b/polyp/module-x11-bell.c @@ -69,7 +69,7 @@ static int ring_bell(struct userdata *u, int percent) { assert(u); if (!(s = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": Invalid sink\n"); + pa_log(__FILE__": Invalid sink: %s\n", u->sink_name); return -1; } @@ -88,7 +88,7 @@ static int x11_event_callback(struct pa_x11_wrapper *w, XEvent *e, void *userdat bne = (XkbBellNotifyEvent*) e; if (ring_bell(u, bne->percent) < 0) { - pa_log(__FILE__": Ringing bell failed, reverting to X11 device bell.\n"); + pa_log_info(__FILE__": Ringing bell failed, reverting to X11 device bell.\n"); XkbForceDeviceBell(pa_x11_wrapper_get_display(w), bne->device, bne->bell_class, bne->bell_id, bne->percent); } diff --git a/polyp/module-x11-publish.c b/polyp/module-x11-publish.c index 598fe5b5..a47a7606 100644 --- a/polyp/module-x11-publish.c +++ b/polyp/module-x11-publish.c @@ -77,7 +77,7 @@ static int load_key(struct userdata *u, const char*fn) { u->auth_cookie_in_property = 0; if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { - pa_log(__FILE__": using already loaded auth cookie.\n"); + pa_log_debug(__FILE__": using already loaded auth cookie.\n"); pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); u->auth_cookie_in_property = 1; return 0; @@ -89,7 +89,7 @@ static int load_key(struct userdata *u, const char*fn) { if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) return -1; - pa_log(__FILE__": loading cookie from disk.\n"); + pa_log_debug(__FILE__": loading cookie from disk.\n"); if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) u->auth_cookie_in_property = 1; diff --git a/polyp/module.c b/polyp/module.c index 67d7f44e..aedaae02 100644 --- a/polyp/module.c +++ b/polyp/module.c @@ -89,7 +89,7 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char assert(m->init); if (m->init(c, m) < 0) { - pa_log(__FILE__": Failed to load module \"%s\" (argument: \"%s\"): initialization failed.\n", name, argument ? argument : ""); + pa_log_error(__FILE__": Failed to load module \"%s\" (argument: \"%s\"): initialization failed.\n", name, argument ? argument : ""); goto fail; } @@ -108,7 +108,7 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char r = pa_idxset_put(c->modules, m, &m->index); assert(r >= 0 && m->index != PA_IDXSET_INVALID); - pa_log(__FILE__": Loaded \"%s\" (index: #%u; argument: \"%s\").\n", m->name, m->index, m->argument ? m->argument : ""); + pa_log_info(__FILE__": Loaded \"%s\" (index: #%u; argument: \"%s\").\n", m->name, m->index, m->argument ? m->argument : ""); pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_NEW, m->index); @@ -135,13 +135,13 @@ static void pa_module_free(struct pa_module *m) { if (m->core->disallow_module_loading) return; - pa_log(__FILE__": Unloading \"%s\" (index: #%u).\n", m->name, m->index); + pa_log_info(__FILE__": Unloading \"%s\" (index: #%u).\n", m->name, m->index); m->done(m->core, m); lt_dlclose(m->dl); - pa_log(__FILE__": Unloaded \"%s\" (index: #%u).\n", m->name, m->index); + pa_log_info(__FILE__": Unloaded \"%s\" (index: #%u).\n", m->name, m->index); pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_REMOVE, m->index); diff --git a/polyp/namereg.c b/polyp/namereg.c index dce8693f..04601442 100644 --- a/polyp/namereg.c +++ b/polyp/namereg.c @@ -35,6 +35,7 @@ #include "sink.h" #include "xmalloc.h" #include "subscribe.h" +#include "util.h" struct namereg_entry { enum pa_namereg_type type; @@ -112,8 +113,6 @@ void pa_namereg_unregister(struct pa_core *c, const char *name) { void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type type, int autoload) { struct namereg_entry *e; uint32_t index; - char *x = NULL; - void *d = NULL; assert(c); if (!name) { @@ -130,9 +129,7 @@ void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type t if (e->type == e->type) return e->data; - index = (uint32_t) strtol(name, &x, 0); - - if (!x || *x != 0) { + if (pa_atou(name, &index) < 0) { if (autoload) { pa_autoload_request(c, name, type); @@ -146,13 +143,13 @@ void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type t } if (type == PA_NAMEREG_SINK) - d = pa_idxset_get_by_index(c->sinks, index); + return pa_idxset_get_by_index(c->sinks, index); else if (type == PA_NAMEREG_SOURCE) - d = pa_idxset_get_by_index(c->sources, index); + return pa_idxset_get_by_index(c->sources, index); else if (type == PA_NAMEREG_SAMPLE && c->scache) - d = pa_idxset_get_by_index(c->scache, index); - - return d; + return pa_idxset_get_by_index(c->scache, index); + + return NULL; } void pa_namereg_set_default(struct pa_core*c, const char *name, enum pa_namereg_type type) { diff --git a/polyp/pid.c b/polyp/pid.c index 32365136..2fac687e 100644 --- a/polyp/pid.c +++ b/polyp/pid.c @@ -43,8 +43,8 @@ * pid could be read, return 0, on failure (pid_t) -1 */ static pid_t read_pid(const char *fn, int fd) { ssize_t r; - char t[20], *e = NULL; - long int pid; + char t[20], *e; + uint32_t pid; assert(fn && fd >= 0); @@ -57,8 +57,10 @@ static pid_t read_pid(const char *fn, int fd) { return (pid_t) 0; t[r] = 0; + if ((e = strchr(t, '\n'))) + *e = 0; - if (!t[0] || (pid = strtol(t, &e, 0)) == 0 || (*e != 0 && *e != '\n')) { + if (pa_atou(t, &pid) < 0) { pa_log(__FILE__": WARNING: failed to parse PID file '%s'\n", fn); return (pid_t) -1; } diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 84d4efe8..94dc5e5f 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -2003,7 +2003,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo assert(io && p); if (pa_idxset_ncontents(p->connections)+1 > MAX_CONNECTIONS) { - pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); + pa_log_warn(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); pa_iochannel_free(io); return; } @@ -2057,7 +2057,7 @@ static int load_key(struct pa_protocol_native*p, const char*fn) { p->auth_cookie_in_property = 0; if (!fn && pa_authkey_prop_get(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) { - pa_log(__FILE__": using already loaded auth cookie.\n"); + pa_log_info(__FILE__": using already loaded auth cookie.\n"); pa_authkey_prop_ref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); p->auth_cookie_in_property = 1; return 0; @@ -2069,7 +2069,7 @@ static int load_key(struct pa_protocol_native*p, const char*fn) { if (pa_authkey_load_auto(fn, p->auth_cookie, sizeof(p->auth_cookie)) < 0) return -1; - pa_log(__FILE__": loading cookie from disk.\n"); + pa_log_info(__FILE__": loading cookie from disk.\n"); if (pa_authkey_prop_put(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) p->auth_cookie_in_property = 1; diff --git a/polyp/sample.c b/polyp/sample.c index 978a3d6a..b0723f70 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -84,7 +84,7 @@ int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_s return (a->format == b->format) && (a->rate == b->rate) && (a->channels == b->channels); } -void pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spec) { +const char *pa_sample_format_to_string(enum pa_sample_format f) { static const char* const table[]= { [PA_SAMPLE_U8] = "U8", [PA_SAMPLE_ALAW] = "ALAW", @@ -95,12 +95,21 @@ void pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spec [PA_SAMPLE_FLOAT32BE] = "FLOAT32BE", }; + if (f >= PA_SAMPLE_MAX) + return NULL; + + return table[f]; +} + +void pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spec) { + assert(s && l && spec); + if (!pa_sample_spec_valid(spec)) { snprintf(s, l, "Invalid"); return; } - snprintf(s, l, "%s %uch %uHz", table[spec->format], spec->channels, spec->rate); + snprintf(s, l, "%s %uch %uHz", pa_sample_format_to_string(spec->format), spec->channels, spec->rate); } pa_volume_t pa_volume_multiply(pa_volume_t a, pa_volume_t b) { diff --git a/polyp/sample.h b/polyp/sample.h index 93025a10..59226c46 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -86,6 +86,9 @@ int pa_sample_spec_valid(const struct pa_sample_spec *spec); /** Return non-zero when the two sample type specifications match */ int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b); +/* Return a descriptive string for the specified sample format. \since 0.7.1 */ +const char *pa_sample_format_to_string(enum pa_sample_format f); + /** Maximum required string length for pa_sample_spec_snprint() */ #define PA_SAMPLE_SPEC_SNPRINT_MAX 32 @@ -126,7 +129,7 @@ pa_volume_t pa_volume_from_user(double v); /** Pretty print a byte size value. (i.e. "2.5 MB") */ void pa_bytes_snprint(char *s, size_t l, unsigned v); -/** Parse a sample format text */ +/** Parse a sample format text. Inverse of pa_sample_format_to_string() */ enum pa_sample_format pa_parse_sample_format(const char *format); PA_C_DECL_END diff --git a/polyp/sink-input.c b/polyp/sink-input.c index e66278ed..347b8f5c 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -85,7 +85,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con assert(r == 0); pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"\n", i->index, i->name, s->index, st); + pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"\n", i->index, i->name, s->index, st); pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index); @@ -115,6 +115,8 @@ static void sink_input_free(struct pa_sink_input* i) { if (i->state != PA_SINK_INPUT_DISCONNECTED) pa_sink_input_disconnect(i); + pa_log_info(__FILE__": freed %u \"%s\"\n", i->index, i->name); + if (i->resampled_chunk.memblock) pa_memblock_unref(i->resampled_chunk.memblock); if (i->resampler) diff --git a/polyp/sink.c b/polyp/sink.c index 29aef6fb..3d20884b 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -81,7 +81,7 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co assert(s->index != PA_IDXSET_INVALID && r >= 0); pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log(__FILE__": created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); + pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index); @@ -117,7 +117,7 @@ static void sink_free(struct pa_sink *s) { if (s->state != PA_SINK_DISCONNECTED) pa_sink_disconnect(s); - pa_log(__FILE__": freed %u \"%s\"\n", s->index, s->name); + pa_log_info(__FILE__": freed %u \"%s\"\n", s->index, s->name); pa_source_unref(s->monitor_source); s->monitor_source = NULL; diff --git a/polyp/source-output.c b/polyp/source-output.c index fb06ff8f..3568fd6f 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -37,6 +37,7 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n struct pa_source_output *o; struct pa_resampler *resampler = NULL; int r; + char st[256]; assert(s && spec); if (pa_idxset_ncontents(s->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { @@ -73,6 +74,9 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n r = pa_idxset_put(s->outputs, o, NULL); assert(r == 0); + pa_sample_spec_snprint(st, sizeof(st), spec); + pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"\n", o->index, o->name, s->index, st); + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); return o; @@ -100,6 +104,8 @@ static void source_output_free(struct pa_source_output* o) { if (o->state != PA_SOURCE_OUTPUT_DISCONNECTED) pa_source_output_disconnect(o); + pa_log_info(__FILE__": freed %u \"%s\"\n", o->index, o->name); + if (o->resampler) pa_resampler_free(o->resampler); diff --git a/polyp/source.c b/polyp/source.c index 026ec7a8..7cdb9117 100644 --- a/polyp/source.c +++ b/polyp/source.c @@ -68,7 +68,7 @@ struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail assert(s->index != PA_IDXSET_INVALID && r >= 0); pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log(__FILE__": created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); + pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index); @@ -101,7 +101,7 @@ static void source_free(struct pa_source *s) { if (s->state != PA_SOURCE_DISCONNECTED) pa_source_disconnect(s); - pa_log(__FILE__": freed %u \"%s\"\n", s->index, s->name); + pa_log_info(__FILE__": freed %u \"%s\"\n", s->index, s->name); pa_idxset_free(s->outputs, NULL, NULL); diff --git a/polyp/util.c b/polyp/util.c index 970ebb93..ff1aebf3 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -381,9 +381,9 @@ supported.*/ void pa_raise_priority(void) { if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) - pa_log(__FILE__": setpriority() failed: %s\n", strerror(errno)); -/* else */ -/* pa_log(__FILE__": Successfully gained nice level %i.\n", NICE_LEVEL); */ + pa_log_warn(__FILE__": setpriority() failed: %s\n", strerror(errno)); + else + pa_log_info(__FILE__": Successfully gained nice level %i.\n", NICE_LEVEL); #ifdef _POSIX_PRIORITY_SCHEDULING { @@ -396,11 +396,11 @@ void pa_raise_priority(void) { sp.sched_priority = 1; if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) { - pa_log(__FILE__": sched_setscheduler() failed: %s\n", strerror(errno)); + pa_log_warn(__FILE__": sched_setscheduler() failed: %s\n", strerror(errno)); return; } -/* pa_log(__FILE__": Successfully enabled SCHED_FIFO scheduling.\n"); */ + pa_log_info(__FILE__": Successfully enabled SCHED_FIFO scheduling.\n"); } #endif } @@ -698,17 +698,17 @@ int pa_unlock_lockfile(const char *fn, int fd) { assert(fn && fd >= 0); if (unlink(fn) < 0) { - pa_log(__FILE__": WARNING: unable to remove lock file '%s': %s\n", fn, strerror(errno)); + pa_log_warn(__FILE__": WARNING: unable to remove lock file '%s': %s\n", fn, strerror(errno)); r = -1; } if (pa_lock_fd(fd, 0) < 0) { - pa_log(__FILE__": WARNING: failed to unlock file '%s'.\n", fn); + pa_log_warn(__FILE__": WARNING: failed to unlock file '%s'.\n", fn); r = -1; } if (close(fd) < 0) { - pa_log(__FILE__": WARNING: failed to close lock file '%s': %s\n", fn, strerror(errno)); + pa_log_warn(__FILE__": WARNING: failed to close lock file '%s': %s\n", fn, strerror(errno)); r = -1; } @@ -862,6 +862,7 @@ char *pa_runtime_path(const char *fn, char *s, size_t l) { return s; } +/* Wait t milliseconds */ int pa_msleep(unsigned long t) { struct timespec ts; @@ -870,3 +871,35 @@ int pa_msleep(unsigned long t) { return nanosleep(&ts, NULL); } + +/* Convert the string s to a signed integer in *ret_i */ +int pa_atoi(const char *s, int32_t *ret_i) { + char *x = NULL; + long l; + assert(s && ret_i); + + l = strtol(s, &x, 0); + + if (x || *x) + return -1; + + *ret_i = (int32_t) l; + + return 0; +} + +/* Convert the string s to an unsigned integer in *ret_u */ +int pa_atou(const char *s, uint32_t *ret_u) { + char *x = NULL; + unsigned long l; + assert(s && ret_u); + + l = strtoul(s, &x, 0); + + if (!x || *x) + return -1; + + *ret_u = (uint32_t) l; + + return 0; +} diff --git a/polyp/util.h b/polyp/util.h index 922aa49e..2cfc5f6e 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -90,4 +90,7 @@ char *pa_runtime_path(const char *fn, char *s, size_t l); int pa_msleep(unsigned long t); +int pa_atoi(const char *s, int32_t *ret_i); +int pa_atou(const char *s, uint32_t *ret_u); + #endif -- cgit From 2d97e7522e6d075e5784659ce538e9dd194e5eae Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 11 Dec 2004 16:48:45 +0000 Subject: * fix alsa initialisation * add some missing zeroconf files * make module-match shut up a bit git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@318 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- polyp/alsa-util.c | 9 +- polyp/howl-wrap.c | 116 +++++++++++ polyp/howl-wrap.h | 37 ++++ polyp/module-match.c | 2 +- polyp/module-zeroconf-publish.c | 415 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 574 insertions(+), 7 deletions(-) create mode 100644 polyp/howl-wrap.c create mode 100644 polyp/howl-wrap.h create mode 100644 polyp/module-zeroconf-publish.c diff --git a/configure.ac b/configure.ac index 5a4a4646..a54f383f 100644 --- a/configure.ac +++ b/configure.ac @@ -166,7 +166,7 @@ fi # LYNX documentation generation AC_ARG_ENABLE(lynx, - AS_HELP_STRING(--disable-lynx,Turn off lynx usage for documentation generation), + AC_HELP_STRING(--disable-lynx,Turn off lynx usage for documentation generation), [case "${enableval}" in yes) lynx=yes ;; no) lynx=no ;; diff --git a/polyp/alsa-util.c b/polyp/alsa-util.c index b6b9ac11..2894c9e8 100644 --- a/polyp/alsa-util.c +++ b/polyp/alsa-util.c @@ -29,6 +29,7 @@ #include "alsa-util.h" #include "sample.h" #include "xmalloc.h" +#include "log.h" /* Set the hardware parameters of the given ALSA device. Returns the * selected fragment settings in *period and *period_size */ @@ -61,14 +62,12 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const struct pa_sample_spec *ss if (snd_pcm_prepare(pcm_handle) < 0) goto finish; - if (snd_pcm_hw_params_current(pcm_handle, hwparams) < 0) - goto finish; - if (snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size) < 0 || snd_pcm_hw_params_get_period_size(hwparams, period_size, NULL) < 0) goto finish; - - assert(buffer_size > 0 && *period_size > 0); + + assert(buffer_size > 0); + assert(*period_size > 0); *periods = buffer_size / *period_size; assert(*periods > 0); diff --git a/polyp/howl-wrap.c b/polyp/howl-wrap.c new file mode 100644 index 00000000..af050930 --- /dev/null +++ b/polyp/howl-wrap.c @@ -0,0 +1,116 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "howl-wrap.h" +#include "log.h" +#include "xmalloc.h" +#include "props.h" + +#define HOWL_PROPERTY "howl" + +struct pa_howl_wrapper { + struct pa_core *core; + int ref; + + struct pa_io_event *io_event; + sw_discovery discovery; + +}; + +static void howl_io_event(struct pa_mainloop_api*m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { + struct pa_howl_wrapper *w = userdata; + assert(m && e && fd >= 0 && w && w->ref >= 1); + + if (f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) + goto fail; + + if (sw_discovery_read_socket(w->discovery) != SW_OKAY) + goto fail; + + return; + +fail: + pa_log(__FILE__": howl connection died.\n"); + w->core->mainloop->io_free(w->io_event); + w->io_event = NULL; +} + +static struct pa_howl_wrapper* howl_wrapper_new(struct pa_core *c) { + struct pa_howl_wrapper *h; + sw_discovery session; + assert(c); + + if (sw_discovery_init(&session) != SW_OKAY) { + pa_log("sw_discovery_init() failed.\n"); + return NULL; + } + + h = pa_xmalloc(sizeof(struct pa_howl_wrapper)); + h->core = c; + h->ref = 1; + h->discovery = session; + + h->io_event = c->mainloop->io_new(c->mainloop, sw_discovery_socket(session), PA_IO_EVENT_INPUT, howl_io_event, h); + + return h; +} + +static void howl_wrapper_free(struct pa_howl_wrapper *h) { + assert(h); + + sw_discovery_fina(h->discovery); + + if (h->io_event) + h->core->mainloop->io_free(h->io_event); + + pa_xfree(h); +} + +struct pa_howl_wrapper* pa_howl_wrapper_get(struct pa_core *c) { + struct pa_howl_wrapper *h; + assert(c); + + if ((h = pa_property_get(c, HOWL_PROPERTY))) + return pa_howl_wrapper_ref(h); + + return howl_wrapper_new(c); +} + +struct pa_howl_wrapper* pa_howl_wrapper_ref(struct pa_howl_wrapper *h) { + assert(h && h->ref >= 1); + h->ref++; + return h; +} + +void pa_howl_wrapper_unref(struct pa_howl_wrapper *h) { + assert(h && h->ref >= 1); + if (!(--h->ref)) + howl_wrapper_free(h); +} + +sw_discovery pa_howl_wrapper_get_discovery(struct pa_howl_wrapper *h) { + assert(h && h->ref >= 1); + + return h->discovery; +} + diff --git a/polyp/howl-wrap.h b/polyp/howl-wrap.h new file mode 100644 index 00000000..feb54556 --- /dev/null +++ b/polyp/howl-wrap.h @@ -0,0 +1,37 @@ +#ifndef foohowlwrapperhfoo +#define foohowlwrapperhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "core.h" + +struct pa_howl_wrapper; + +struct pa_howl_wrapper* pa_howl_wrapper_get(struct pa_core *c); +struct pa_howl_wrapper* pa_howl_wrapper_ref(struct pa_howl_wrapper *h); +void pa_howl_wrapper_unref(struct pa_howl_wrapper *h); + +sw_discovery pa_howl_wrapper_get_discovery(struct pa_howl_wrapper *h); + +#endif diff --git a/polyp/module-match.c b/polyp/module-match.c index 7fdc5f3e..9d969b31 100644 --- a/polyp/module-match.c +++ b/polyp/module-match.c @@ -171,7 +171,7 @@ static void callback(struct pa_core *c, enum pa_subscription_event_type t, uint3 for (r = u->rules; r; r = r->next) { if (!regexec(&r->regex, si->name, 0, NULL, 0)) { - pa_log(__FILE__": changing volume of sink input '%s' to 0x%03x\n", si->name, r->volume); + pa_log_debug(__FILE__": changing volume of sink input '%s' to 0x%03x\n", si->name, r->volume); pa_sink_input_set_volume(si, r->volume); } } diff --git a/polyp/module-zeroconf-publish.c b/polyp/module-zeroconf-publish.c new file mode 100644 index 00000000..6eee143b --- /dev/null +++ b/polyp/module-zeroconf-publish.c @@ -0,0 +1,415 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "module-zeroconf-publish-symdef.h" +#include "howl-wrap.h" +#include "xmalloc.h" +#include "autoload.h" +#include "sink.h" +#include "source.h" +#include "native-common.h" +#include "util.h" +#include "log.h" +#include "subscribe.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Publisher") +PA_MODULE_VERSION(PACKAGE_VERSION) + +#define SERVICE_NAME_SINK "_polypaudio-sink._tcp" +#define SERVICE_NAME_SOURCE "_polypaudio-source._tcp" +#define SERVICE_NAME_SERVER "_polypaudio-server._tcp" + +struct service { + sw_discovery_oid oid; + char *name; + int published; /* 0 -> not yet registered, 1 -> registered with data from real device, 2 -> registered with data from autoload device */ + + struct { + int valid; + enum pa_namereg_type type; + uint32_t index; + } loaded; + + struct { + int valid; + enum pa_namereg_type type; + uint32_t index; + } autoload; +}; + +struct userdata { + struct pa_core *core; + struct pa_howl_wrapper *howl_wrapper; + struct pa_hashmap *services; + struct pa_subscription *subscription; +}; + +static sw_result publish_reply(sw_discovery discovery, sw_discovery_publish_status status, sw_discovery_oid oid, sw_opaque extra) { + return SW_OKAY; +} + +static void get_service_sample_spec(struct userdata *u, struct service *s, struct pa_sample_spec *ret_ss) { + assert(u && s && s->loaded.valid && ret_ss); + + if (s->loaded.type == PA_NAMEREG_SINK) { + struct pa_sink *sink = pa_idxset_get_by_index(u->core->sinks, s->loaded.index); + assert(sink); + *ret_ss = sink->sample_spec; + } else if (s->loaded.type == PA_NAMEREG_SOURCE) { + struct pa_source *source = pa_idxset_get_by_index(u->core->sources, s->loaded.index); + assert(source); + *ret_ss = source->sample_spec; + } else + assert(0); +} + +static int publish_service(struct userdata *u, struct service *s) { + assert(u && s); + char t[256]; + char hn[256]; + int r = -1; + sw_text_record txt; + int free_txt = 0; + + if ((s->published == 1 && s->loaded.valid) || + (s->published == 2 && s->autoload.valid && !s->loaded.valid)) + return 0; + + if (s->published) { + sw_discovery_cancel(pa_howl_wrapper_get_discovery(u->howl_wrapper), s->oid); + s->published = 0; + } + + snprintf(t, sizeof(t), "%s@%s", s->name, pa_get_host_name(hn, sizeof(hn))); + + if (sw_text_record_init(&txt) != SW_OKAY) { + pa_log(__FILE__": sw_text_record_init() failed\n"); + goto finish; + } + free_txt = 1; + + sw_text_record_add_key_and_string_value(txt, "device", s->name); + + if (s->loaded.valid) { + char z[64]; + struct pa_sample_spec ss; + + get_service_sample_spec(u, s, &ss); + + snprintf(z, sizeof(z), "%u", ss.rate); + sw_text_record_add_key_and_string_value(txt, "rate", z); + snprintf(z, sizeof(z), "%u", ss.channels); + sw_text_record_add_key_and_string_value(txt, "channels", z); + sw_text_record_add_key_and_string_value(txt, "format", pa_sample_format_to_string(ss.format)); + + if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t, + s->loaded.type == PA_NAMEREG_SINK ? SERVICE_NAME_SINK : SERVICE_NAME_SOURCE, + NULL, NULL, PA_NATIVE_DEFAULT_PORT, sw_text_record_bytes(txt), sw_text_record_len(txt), + publish_reply, s, &s->oid) != SW_OKAY) { + pa_log(__FILE__": failed to register sink on zeroconf.\n"); + goto finish; + } + + s->published = 1; + } else if (s->autoload.valid) { + + if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t, + s->autoload.type == PA_NAMEREG_SINK ? SERVICE_NAME_SINK : SERVICE_NAME_SOURCE, + NULL, NULL, PA_NATIVE_DEFAULT_PORT, sw_text_record_bytes(txt), sw_text_record_len(txt), + publish_reply, s, &s->oid) != SW_OKAY) { + pa_log(__FILE__": failed to register sink on zeroconf.\n"); + goto finish; + } + + s->published = 2; + } + + r = 0; + +finish: + + if (!s->published) { + /* Remove this service */ + pa_hashmap_remove(u->services, s->name); + pa_xfree(s->name); + pa_xfree(s); + } + + if (free_txt) + sw_text_record_fina(txt); + + return r; +} + +struct service *get_service(struct userdata *u, const char *name) { + struct service *s; + + if ((s = pa_hashmap_get(u->services, name))) + return s; + + s = pa_xmalloc(sizeof(struct service)); + s->published = 0; + s->name = pa_xstrdup(name); + s->loaded.valid = s->autoload.valid = 0; + + pa_hashmap_put(u->services, s->name, s); + + return s; +} + +static int publish_sink(struct userdata *u, struct pa_sink *s) { + struct service *svc; + assert(u && s); + + svc = get_service(u, s->name); + if (svc->loaded.valid) + return 0; + + svc->loaded.valid = 1; + svc->loaded.type = PA_NAMEREG_SINK; + svc->loaded.index = s->index; + + return publish_service(u, svc); +} + +static int publish_source(struct userdata *u, struct pa_source *s) { + struct service *svc; + assert(u && s); + + svc = get_service(u, s->name); + if (svc->loaded.valid) + return 0; + + svc->loaded.valid = 1; + svc->loaded.type = PA_NAMEREG_SOURCE; + svc->loaded.index = s->index; + + return publish_service(u, svc); +} + +static int publish_autoload(struct userdata *u, struct pa_autoload_entry *s) { + struct service *svc; + assert(u && s); + + svc = get_service(u, s->name); + if (svc->autoload.valid) + return 0; + + svc->autoload.valid = 1; + svc->autoload.type = s->type; + svc->autoload.index = s->index; + + return publish_service(u, svc); +} + +static int remove_sink(struct userdata *u, struct pa_sink *s) { + struct service *svc; + assert(u && s); + + if (!(svc = pa_hashmap_get(u->services, s->name))) + return 0; + + if (!svc->loaded.valid || svc->loaded.type != PA_NAMEREG_SINK) + return 0; + + svc->loaded.valid = 0; + return publish_service(u, svc); +} + +static int remove_source(struct userdata *u, struct pa_source *s) { + struct service *svc; + assert(u && s); + + if (!(svc = pa_hashmap_get(u->services, s->name))) + return 0; + + if (!svc->loaded.valid || svc->loaded.type != PA_NAMEREG_SOURCE) + return 0; + + svc->loaded.valid = 0; + return publish_service(u, svc); +} + +static int remove_autoload(struct userdata *u, struct pa_autoload_entry *s) { + struct service *svc; + assert(u && s); + + if (!(svc = pa_hashmap_get(u->services, s->name))) + return 0; + + if (!svc->autoload.valid || svc->autoload.type != s->type) + return 0; + + svc->autoload.valid = 0; + return publish_service(u, svc); +} + +static void subscribe_callback(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index, void *userdata) { + struct userdata *u = userdata; + assert(u && c); + + switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { + case PA_SUBSCRIPTION_EVENT_SINK: { + struct pa_sink *sink; + + pa_log("subscribe: %x\n", t); + + + + + if ((sink = pa_idxset_get_by_index(c->sinks, index))) { + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { + pa_log("add\n"); + if (publish_sink(u, sink) < 0) + goto fail; + } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + pa_log("remove\n"); + + + if (remove_sink(u, sink) < 0) + goto fail; + } + } + + break; + } + + case PA_SUBSCRIPTION_EVENT_SOURCE: { + struct pa_source *source; + + if ((source = pa_idxset_get_by_index(c->sources, index))) { + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { + if (publish_source(u, source) < 0) + goto fail; + } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + if (remove_source(u, source) < 0) + goto fail; + } + } + + break; + } + + case PA_SUBSCRIPTION_EVENT_AUTOLOAD: { + struct pa_autoload_entry *autoload; + + if ((autoload = pa_idxset_get_by_index(c->autoload_idxset, index))) { + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { + if (publish_autoload(u, autoload) < 0) + goto fail; + } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + if (remove_autoload(u, autoload) < 0) + goto fail; + } + } + + break; + } + } + + return; + +fail: + if (u->subscription) { + pa_subscription_free(u->subscription); + u->subscription = NULL; + } +} + +int pa__init(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + uint32_t index; + struct pa_sink *sink; + struct pa_source *source; + struct pa_autoload_entry *autoload; + + m->userdata = u = pa_xmalloc(sizeof(struct userdata)); + u->core = c; + + if (!(u->howl_wrapper = pa_howl_wrapper_get(c))) + goto fail; + + u->services = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + + u->subscription = pa_subscription_new(c, + PA_SUBSCRIPTION_MASK_SINK| + PA_SUBSCRIPTION_MASK_SOURCE| + PA_SUBSCRIPTION_MASK_AUTOLOAD, subscribe_callback, u); + + for (sink = pa_idxset_first(c->sinks, &index); sink; sink = pa_idxset_next(c->sinks, &index)) + if (publish_sink(u, sink) < 0) + goto fail; + + for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) + if (publish_source(u, source) < 0) + goto fail; + + if (c->autoload_idxset) + for (autoload = pa_idxset_first(c->autoload_idxset, &index); autoload; autoload = pa_idxset_next(c->autoload_idxset, &index)) + if (publish_autoload(u, autoload) < 0) + goto fail; + + return 0; + +fail: + pa__done(c, m); + return -1; +} + +static void service_free(void *p, void *userdata) { + struct service *s = p; + struct userdata *u = userdata; + assert(s && u); + sw_discovery_cancel(pa_howl_wrapper_get_discovery(u->howl_wrapper), s->oid); + pa_xfree(s->name); + pa_xfree(s); +} + +void pa__done(struct pa_core *c, struct pa_module*m) { + struct userdata*u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->services) + pa_hashmap_free(u->services, service_free, u); + + if (u->subscription) + pa_subscription_free(u->subscription); + + if (u->howl_wrapper) + pa_howl_wrapper_unref(u->howl_wrapper); + + pa_xfree(u); +} + -- cgit From 9a01cf44f09e92e14a720f4f531e943a50f26b72 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 12 Dec 2004 15:56:22 +0000 Subject: * complete zeroconf publisher * make cli.c shut up unless run with -v git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@319 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/cli.c | 4 +- polyp/module-zeroconf-publish.c | 104 +++++++++++++++++++++++----------------- 2 files changed, 61 insertions(+), 47 deletions(-) diff --git a/polyp/cli.c b/polyp/cli.c index 04fbb7e0..4d4342bf 100644 --- a/polyp/cli.c +++ b/polyp/cli.c @@ -102,7 +102,7 @@ static void client_kill(struct pa_client *client) { assert(client && client->userdata); c = client->userdata; - pa_log(__FILE__": CLI client killed.\n"); + pa_log_debug(__FILE__": CLI client killed.\n"); if (c->defer_kill) c->kill_requested = 1; else { @@ -118,7 +118,7 @@ static void line_callback(struct pa_ioline *line, const char *s, void *userdata) assert(line && c); if (!s) { - pa_log(__FILE__": CLI got EOF from user.\n"); + pa_log_debug(__FILE__": CLI got EOF from user.\n"); if (c->eof_callback) c->eof_callback(c, c->userdata); diff --git a/polyp/module-zeroconf-publish.c b/polyp/module-zeroconf-publish.c index 6eee143b..363c2419 100644 --- a/polyp/module-zeroconf-publish.c +++ b/polyp/module-zeroconf-publish.c @@ -39,6 +39,7 @@ #include "util.h" #include "log.h" #include "subscribe.h" +#include "dynarray.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Publisher") @@ -70,6 +71,7 @@ struct userdata { struct pa_core *core; struct pa_howl_wrapper *howl_wrapper; struct pa_hashmap *services; + struct pa_dynarray *sink_dynarray, *source_dynarray, *autoload_dynarray; struct pa_subscription *subscription; }; @@ -198,6 +200,8 @@ static int publish_sink(struct userdata *u, struct pa_sink *s) { svc->loaded.type = PA_NAMEREG_SINK; svc->loaded.index = s->index; + pa_dynarray_put(u->sink_dynarray, s->index, svc); + return publish_service(u, svc); } @@ -212,6 +216,8 @@ static int publish_source(struct userdata *u, struct pa_source *s) { svc->loaded.valid = 1; svc->loaded.type = PA_NAMEREG_SOURCE; svc->loaded.index = s->index; + + pa_dynarray_put(u->source_dynarray, s->index, svc); return publish_service(u, svc); } @@ -227,49 +233,57 @@ static int publish_autoload(struct userdata *u, struct pa_autoload_entry *s) { svc->autoload.valid = 1; svc->autoload.type = s->type; svc->autoload.index = s->index; + + pa_dynarray_put(u->autoload_dynarray, s->index, svc); return publish_service(u, svc); } -static int remove_sink(struct userdata *u, struct pa_sink *s) { +static int remove_sink(struct userdata *u, uint32_t index) { struct service *svc; - assert(u && s); + assert(u && index != PA_INVALID_INDEX); - if (!(svc = pa_hashmap_get(u->services, s->name))) + if (!(svc = pa_dynarray_get(u->sink_dynarray, index))) return 0; if (!svc->loaded.valid || svc->loaded.type != PA_NAMEREG_SINK) return 0; svc->loaded.valid = 0; + pa_dynarray_put(u->sink_dynarray, index, NULL); + return publish_service(u, svc); } -static int remove_source(struct userdata *u, struct pa_source *s) { +static int remove_source(struct userdata *u, uint32_t index) { struct service *svc; - assert(u && s); + assert(u && index != PA_INVALID_INDEX); - if (!(svc = pa_hashmap_get(u->services, s->name))) + if (!(svc = pa_dynarray_get(u->source_dynarray, index))) return 0; if (!svc->loaded.valid || svc->loaded.type != PA_NAMEREG_SOURCE) return 0; svc->loaded.valid = 0; + pa_dynarray_put(u->source_dynarray, index, NULL); + return publish_service(u, svc); } -static int remove_autoload(struct userdata *u, struct pa_autoload_entry *s) { +static int remove_autoload(struct userdata *u, uint32_t index) { struct service *svc; - assert(u && s); + assert(u && index != PA_INVALID_INDEX); - if (!(svc = pa_hashmap_get(u->services, s->name))) + if (!(svc = pa_dynarray_get(u->autoload_dynarray, index))) return 0; - if (!svc->autoload.valid || svc->autoload.type != s->type) + if (!svc->autoload.valid) return 0; svc->autoload.valid = 0; + pa_dynarray_put(u->autoload_dynarray, index, NULL); + return publish_service(u, svc); } @@ -277,63 +291,52 @@ static void subscribe_callback(struct pa_core *c, enum pa_subscription_event_typ struct userdata *u = userdata; assert(u && c); - switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { + switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) case PA_SUBSCRIPTION_EVENT_SINK: { - struct pa_sink *sink; + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { + struct pa_sink *sink; - pa_log("subscribe: %x\n", t); - - - - - if ((sink = pa_idxset_get_by_index(c->sinks, index))) { - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { - pa_log("add\n"); + if ((sink = pa_idxset_get_by_index(c->sinks, index))) { if (publish_sink(u, sink) < 0) goto fail; - } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - pa_log("remove\n"); - - - if (remove_sink(u, sink) < 0) - goto fail; } + } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + if (remove_sink(u, index) < 0) + goto fail; } break; - } - case PA_SUBSCRIPTION_EVENT_SOURCE: { - struct pa_source *source; + case PA_SUBSCRIPTION_EVENT_SOURCE: - if ((source = pa_idxset_get_by_index(c->sources, index))) { - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { + struct pa_source *source; + + if ((source = pa_idxset_get_by_index(c->sources, index))) { if (publish_source(u, source) < 0) goto fail; - } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - if (remove_source(u, source) < 0) - goto fail; } + } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + if (remove_source(u, index) < 0) + goto fail; } break; - } - case PA_SUBSCRIPTION_EVENT_AUTOLOAD: { - struct pa_autoload_entry *autoload; - - if ((autoload = pa_idxset_get_by_index(c->autoload_idxset, index))) { - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { + case PA_SUBSCRIPTION_EVENT_AUTOLOAD: + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { + struct pa_autoload_entry *autoload; + + if ((autoload = pa_idxset_get_by_index(c->autoload_idxset, index))) { if (publish_autoload(u, autoload) < 0) goto fail; - } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - if (remove_autoload(u, autoload) < 0) - goto fail; } + } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + if (remove_autoload(u, index) < 0) + goto fail; } break; - } } return; @@ -359,7 +362,10 @@ int pa__init(struct pa_core *c, struct pa_module*m) { goto fail; u->services = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - + u->sink_dynarray = pa_dynarray_new(); + u->source_dynarray = pa_dynarray_new(); + u->autoload_dynarray = pa_dynarray_new(); + u->subscription = pa_subscription_new(c, PA_SUBSCRIPTION_MASK_SINK| PA_SUBSCRIPTION_MASK_SOURCE| @@ -404,11 +410,19 @@ void pa__done(struct pa_core *c, struct pa_module*m) { if (u->services) pa_hashmap_free(u->services, service_free, u); + if (u->sink_dynarray) + pa_dynarray_free(u->sink_dynarray, NULL, NULL); + if (u->source_dynarray) + pa_dynarray_free(u->source_dynarray, NULL, NULL); + if (u->autoload_dynarray) + pa_dynarray_free(u->autoload_dynarray, NULL, NULL); + if (u->subscription) pa_subscription_free(u->subscription); if (u->howl_wrapper) pa_howl_wrapper_unref(u->howl_wrapper); + pa_xfree(u); } -- cgit From e02be6c15beddec976220bce2ee1a68520286c01 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 12 Dec 2004 22:58:53 +0000 Subject: * fix include file names in installed header files * add browsing API * add new tool pabrowse * add typeid subsystem * bump API version * split off random.c * add an identification cookie git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@320 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 4 +- doc/todo | 26 ++-- polyp/Makefile.am | 25 +++- polyp/authkey.c | 40 +----- polyp/cli-text.c | 19 ++- polyp/cli.c | 3 +- polyp/client.c | 5 +- polyp/client.h | 6 +- polyp/core.c | 4 +- polyp/core.h | 4 + polyp/endianmacros.h | 14 +- polyp/mainloop-api.h | 2 +- polyp/module-alsa-sink.c | 4 +- polyp/module-alsa-source.c | 4 +- polyp/module-combine.c | 6 +- polyp/module-esound-sink.c | 4 +- polyp/module-null-sink.c | 4 +- polyp/module-oss-mmap.c | 6 +- polyp/module-oss.c | 6 +- polyp/module-pipe-sink.c | 4 +- polyp/module-pipe-source.c | 4 +- polyp/module-sine.c | 4 +- polyp/module-tunnel.c | 6 +- polyp/module-zeroconf-publish.c | 33 ++++- polyp/pabrowse.c | 139 ++++++++++++++++++ polyp/pacat.c | 5 +- polyp/pactl.c | 37 +++-- polyp/paplay.c | 2 +- polyp/play-memchunk.c | 4 +- polyp/polyplib-browser.c | 307 ++++++++++++++++++++++++++++++++++++++++ polyp/polyplib-browser.h | 65 +++++++++ polyp/polyplib-context.h | 11 +- polyp/polyplib-def.h | 4 +- polyp/polyplib-introspect.c | 21 ++- polyp/polyplib-introspect.h | 16 ++- polyp/polyplib-operation.h | 4 +- polyp/polyplib-scache.h | 6 +- polyp/polyplib-stream.h | 8 +- polyp/polyplib-subscribe.h | 6 +- polyp/polyplib.h | 20 +-- polyp/protocol-esound.c | 8 +- polyp/protocol-native.c | 17 ++- polyp/protocol-simple.c | 8 +- polyp/random.c | 61 ++++++++ polyp/random.h | 27 ++++ polyp/sample.c | 18 +-- polyp/sample.h | 4 +- polyp/sink-input.c | 3 +- polyp/sink-input.h | 3 +- polyp/sink.c | 5 +- polyp/sink.h | 4 +- polyp/sound-file-stream.c | 3 +- polyp/source-output.c | 4 +- polyp/source-output.h | 3 +- polyp/source.c | 3 +- polyp/source.h | 4 +- polyp/typeid.c | 33 +++++ polyp/typeid.h | 40 ++++++ 58 files changed, 971 insertions(+), 169 deletions(-) create mode 100644 polyp/pabrowse.c create mode 100644 polyp/polyplib-browser.c create mode 100644 polyp/polyplib-browser.h create mode 100644 polyp/random.c create mode 100644 polyp/random.h create mode 100644 polyp/typeid.c create mode 100644 polyp/typeid.h diff --git a/configure.ac b/configure.ac index a54f383f..658910c6 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. AC_PREREQ(2.57) -AC_INIT([polypaudio],[0.7.1],[mzcbylcnhqvb (at) 0pointer (dot) de]) +AC_INIT([polypaudio],[0.8],[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([polyp/main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) @@ -28,7 +28,7 @@ AM_INIT_AUTOMAKE([foreign -Wall]) AC_SUBST(PA_MAJORMINOR, "$PACKAGE_VERSION") AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/polypaudio/]) -AC_SUBST(PA_API_VERSION, 7) +AC_SUBST(PA_API_VERSION, 8) if type -p stow > /dev/null && test -d /usr/local/stow ; then AC_MSG_NOTICE([*** Found /usr/local/stow: default install prefix set to /usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION} ***]) diff --git a/doc/todo b/doc/todo index d6cfb01a..efaeb332 100644 --- a/doc/todo +++ b/doc/todo @@ -1,23 +1,31 @@ *** $Id$ *** -*** later **** -- event more commenting -- polish for starting polypaudio as root/system-wide instance +Architectural changes: - per-channel volume +- channel mapping ("left", "right", "rear", "subwoofer") +- add API for synchronizing multiple sinks/sources to a common clock +- absolutely indexed write()s from client +- remove "polyplib-" prefix + +Fixes: - improve module-oss-mmap latency measurement - module-tunnel: improve latency calculation +- make alsa modules use mmap +- event more commenting + +Features: - add radio module -- pass meta info for hearing impaired -- add sync API -- X11: support for the X11 synchronization extension - xmlrpc/http - dbus - rendezvous -- make alsa modules use mmap +- polish for starting polypaudio as root/system-wide instance +- export connection fd -*********** +Long term: +- pass meta info for hearing impaired +- X11: support for the X11 synchronization extension -backends for: +Backends for: - portaudio (semi-done) - alsa-lib - sdl diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 83b5670a..70051671 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -220,7 +220,9 @@ polypaudio_SOURCES = idxset.c idxset.h \ props.h props.c \ mcalign.c mcalign.h \ g711.c g711.h \ - pid.c pid.h + pid.c pid.h \ + random.c random.h \ + typeid.c typeid.h polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL) @@ -455,7 +457,9 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = polyplib.h \ conf-parser.c conf-parser.h \ strlist.c strlist.h \ strbuf.c strbuf.h \ - mcalign.c mcalign.h + mcalign.c mcalign.h \ + typeid.c typeid.h \ + random.c random.h libpolyp_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) libpolyp_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 @@ -560,7 +564,7 @@ module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EX bin_PROGRAMS+= \ pax11publish -pax11publish_SOURCES = pax11publish.c util.c xmalloc.c log.c authkey.c client-conf.c conf-parser.c x11prop.c +pax11publish_SOURCES = pax11publish.c util.c util.h xmalloc.c xmalloc.h log.c log.h authkey.c authkey.h client-conf.c client-conf.h conf-parser.c conf-parser.h x11prop.c x11prop.h random.c random.h pax11publish_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) pax11publish_LDADD = $(AM_LDADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) @@ -613,6 +617,21 @@ module_zeroconf_publish_la_LDFLAGS = -module -avoid-version module_zeroconf_publish_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) libhowl-wrap.la module_zeroconf_publish_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) +lib_LTLIBRARIES+= \ + libpolyp-browse-@PA_MAJORMINOR@.la + +libpolyp_browse_@PA_MAJORMINOR@_la_SOURCES = polyplib-browser.c polyplib-browser.h +libpolyp_browse_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) +libpolyp_browse_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la $(HOWL_LIBS) +libpolyp_browse_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 + +bin_PROGRAMS += \ + pabrowse + +pabrowse_SOURCES = pabrowse.c +pabrowse_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-browse-@PA_MAJORMINOR@.la +pabrowse_CFLAGS = $(AM_CFLAGS) + endif ### GLIB 2.0 support diff --git a/polyp/authkey.c b/polyp/authkey.c index 1355c8d9..e16883d3 100644 --- a/polyp/authkey.c +++ b/polyp/authkey.c @@ -38,50 +38,24 @@ #include "authkey.h" #include "util.h" #include "log.h" - -#define RANDOM_DEVICE "/dev/urandom" +#include "random.h" /* Generate a new authorization key, store it in file fd and return it in *data */ -static int generate(int fd, void *data, size_t length) { - int random_fd, ret = -1; +static int generate(int fd, void *ret_data, size_t length) { ssize_t r; - assert(fd >= 0 && data && length); - - if ((random_fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) { - - if ((r = pa_loop_read(random_fd, data, length)) < 0 || (size_t) r != length) { - pa_log(__FILE__": failed to read entropy from '%s'\n", RANDOM_DEVICE); - goto finish; - } - - } else { - uint8_t *p; - size_t l; - pa_log(__FILE__": WARNING: Failed to open entropy device '"RANDOM_DEVICE"': %s" - ", falling back to unsecure pseudo RNG.\n", strerror(errno)); + assert(fd >= 0 && ret_data && length); - srandom(time(NULL)); - - for (p = data, l = length; l > 0; p++, l--) - *p = (uint8_t) random(); - } + pa_random(ret_data, length); lseek(fd, 0, SEEK_SET); ftruncate(fd, 0); - if ((r = pa_loop_write(fd, data, length)) < 0 || (size_t) r != length) { + if ((r = pa_loop_write(fd, ret_data, length)) < 0 || (size_t) r != length) { pa_log(__FILE__": failed to write cookie file: %s\n", strerror(errno)); - goto finish; + return -1; } - ret = 0; - -finish: - - if (random_fd >= 0) - close(random_fd); - - return ret; + return 0; } /* Load an euthorization cookie from file fn and store it in data. If diff --git a/polyp/cli-text.c b/polyp/cli-text.c index 629b28e2..dd40add2 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -59,6 +59,7 @@ char *pa_client_list_to_string(struct pa_core *c) { struct pa_strbuf *s; struct pa_client *client; uint32_t index = PA_IDXSET_INVALID; + char tid[5]; assert(c); s = pa_strbuf_new(); @@ -67,7 +68,7 @@ char *pa_client_list_to_string(struct pa_core *c) { pa_strbuf_printf(s, "%u client(s) logged in.\n", pa_idxset_ncontents(c->clients)); for (client = pa_idxset_first(c->clients, &index); client; client = pa_idxset_next(c->clients, &index)) { - pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\tprotocol_name: <%s>\n", client->index, client->name, client->protocol_name); + pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\ttype: <%s>\n", client->index, client->name, pa_typeid_to_string(client->typeid, tid, sizeof(tid))); if (client->owner) pa_strbuf_printf(s, "\towner module: <%u>\n", client->owner->index); @@ -80,6 +81,7 @@ char *pa_sink_list_to_string(struct pa_core *c) { struct pa_strbuf *s; struct pa_sink *sink; uint32_t index = PA_IDXSET_INVALID; + char tid[5]; assert(c); s = pa_strbuf_new(); @@ -93,9 +95,10 @@ char *pa_sink_list_to_string(struct pa_core *c) { assert(sink->monitor_source); pa_strbuf_printf( s, - " %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", + " %c index: %u\n\tname: <%s>\n\ttype: <%s>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ', sink->index, sink->name, + pa_typeid_to_string(sink->typeid, tid, sizeof(tid)), (unsigned) sink->volume, pa_volume_to_dB(sink->volume), (float) pa_sink_get_latency(sink), @@ -115,6 +118,7 @@ char *pa_source_list_to_string(struct pa_core *c) { struct pa_strbuf *s; struct pa_source *source; uint32_t index = PA_IDXSET_INVALID; + char tid[5]; assert(c); s = pa_strbuf_new(); @@ -125,10 +129,11 @@ char *pa_source_list_to_string(struct pa_core *c) { for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec); - pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n", + pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\ttype: <%s>\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n", c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ', source->index, source->name, + pa_typeid_to_string(source->typeid, tid, sizeof(tid)), (float) pa_source_get_latency(source), ss); @@ -148,6 +153,7 @@ char *pa_source_output_list_to_string(struct pa_core *c) { struct pa_strbuf *s; struct pa_source_output *o; uint32_t index = PA_IDXSET_INVALID; + char tid[5]; static const char* const state_table[] = { "RUNNING", "CORKED", @@ -170,9 +176,10 @@ char *pa_source_output_list_to_string(struct pa_core *c) { rm = "invalid"; pa_strbuf_printf( - s, " index: %u\n\tname: '%s'\n\tstate: %s\n\tsource: <%u> '%s'\n\tsample_spec: <%s>\n\tresample method: %s\n", + s, " index: %u\n\tname: '%s'\n\ttype: <%s>\n\tstate: %s\n\tsource: <%u> '%s'\n\tsample_spec: <%s>\n\tresample method: %s\n", o->index, o->name, + pa_typeid_to_string(o->typeid, tid, sizeof(tid)), state_table[o->state], o->source->index, o->source->name, ss, @@ -190,6 +197,7 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { struct pa_strbuf *s; struct pa_sink_input *i; uint32_t index = PA_IDXSET_INVALID; + char tid[5]; static const char* const state_table[] = { "RUNNING", "CORKED", @@ -212,9 +220,10 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec); assert(i->sink); pa_strbuf_printf( - s, " index: %u\n\tname: <%s>\n\tstate: %s\n\tsink: <%u> '%s'\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n\tresample method: %s\n", + s, " index: %u\n\tname: <%s>\n\ttype: <%s>\n\tstate: %s\n\tsink: <%u> '%s'\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n\tresample method: %s\n", i->index, i->name, + pa_typeid_to_string(i->typeid, tid, sizeof(tid)), state_table[i->state], i->sink->index, i->sink->name, (unsigned) i->volume, diff --git a/polyp/cli.c b/polyp/cli.c index 4d4342bf..16323cba 100644 --- a/polyp/cli.c +++ b/polyp/cli.c @@ -45,6 +45,7 @@ #include "log.h" #define PROMPT ">>> " +#define PA_TYPEID_CLI PA_TYPEID_MAKE('C', 'L', 'I', '_') struct pa_cli { struct pa_core *core; @@ -75,7 +76,7 @@ struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io, struct c->eof_callback = NULL; pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); - c->client = pa_client_new(core, "CLI", cname); + c->client = pa_client_new(core, PA_TYPEID_CLI, cname); assert(c->client); c->client->kill = client_kill; c->client->userdata = c; diff --git a/polyp/client.c b/polyp/client.c index 40f5e385..8c7f4800 100644 --- a/polyp/client.c +++ b/polyp/client.c @@ -33,7 +33,7 @@ #include "subscribe.h" #include "log.h" -struct pa_client *pa_client_new(struct pa_core *core, const char *protocol_name, char *name) { +struct pa_client *pa_client_new(struct pa_core *core, pa_typeid_t typeid, const char *name) { struct pa_client *c; int r; assert(core); @@ -42,7 +42,7 @@ struct pa_client *pa_client_new(struct pa_core *core, const char *protocol_name, c->name = pa_xstrdup(name); c->owner = NULL; c->core = core; - c->protocol_name = pa_xstrdup(protocol_name); + c->typeid = typeid; c->kill = NULL; c->userdata = NULL; @@ -68,7 +68,6 @@ void pa_client_free(struct pa_client *c) { pa_log_info(__FILE__": freed %u \"%s\"\n", c->index, c->name); pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index); pa_xfree(c->name); - pa_xfree(c->protocol_name); pa_xfree(c); } diff --git a/polyp/client.h b/polyp/client.h index 324bb27c..2a3a09e0 100644 --- a/polyp/client.h +++ b/polyp/client.h @@ -24,6 +24,7 @@ #include "core.h" #include "module.h" +#include "typeid.h" /* Every connection to the server should have a pa_client * attached. That way the user may generate a listing of all connected @@ -31,18 +32,17 @@ struct pa_client { uint32_t index; + pa_typeid_t typeid; struct pa_module *owner; char *name; struct pa_core *core; - char *protocol_name; void (*kill)(struct pa_client *c); void *userdata; }; -/* Protocol name should be something like "ESOUND", "NATIVE", ... */ -struct pa_client *pa_client_new(struct pa_core *c, const char *protocol_name, char *name); +struct pa_client *pa_client_new(struct pa_core *c, pa_typeid_t typeid, const char *name); /* This function should be called only by the code that created the client */ void pa_client_free(struct pa_client *c); diff --git a/polyp/core.c b/polyp/core.c index 03682fdc..c213faa0 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -39,6 +39,7 @@ #include "xmalloc.h" #include "subscribe.h" #include "props.h" +#include "random.h" struct pa_core* pa_core_new(struct pa_mainloop_api *m) { struct pa_core* c; @@ -84,9 +85,10 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->resample_method = PA_RESAMPLER_SRC_SINC_FASTEST; pa_property_init(c); + + pa_random(&c->cookie, sizeof(c->cookie)); pa_check_signal_is_blocked(SIGPIPE); - return c; } diff --git a/polyp/core.h b/polyp/core.h index 6c6070b1..36604424 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -34,6 +34,10 @@ * variables for the daemon. */ struct pa_core { + /* A random value which may be used to identify this instance of + * polypaudio. Not cryptographically secure in any way. */ + uint32_t cookie; + struct pa_mainloop_api *mainloop; /* idxset of all kinds of entities */ diff --git a/polyp/endianmacros.h b/polyp/endianmacros.h index 75c0af0a..00b992db 100644 --- a/polyp/endianmacros.h +++ b/polyp/endianmacros.h @@ -31,32 +31,44 @@ #define INT16_SWAP(x) ((int16_t)(((int16_t) x >> 8) | ((int16_t) x << 8))) #define UINT16_SWAP(x) ((uint16_t)(((uint16_t) x >> 8) | ((uint16_t) x << 8))) #define INT32_SWAP(x) ((int32_t)(((int32_t) x >> 24) | ((int32_t) x << 24) | (((int32_t) x & 0xFF00) << 16) | (((int32_t) x) >> 16) & 0xFF00)) -#define UINT32_SWAP(x) ((uint32_t)(((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 16) | (((uint32_t) x) >> 16) & 0xFF00)) +#define UINT32_SWAP(x) ((uint32_t)(((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 16) | ((((uint32_t) x) >> 16) & 0xFF00))) #ifdef WORDS_BIGENDIAN #define INT16_FROM_LE(x) INT16_SWAP(x) #define INT16_FROM_BE(x) ((int16_t)(x)) + #define INT16_TO_LE(x) INT16_SWAP(x) #define INT16_TO_BE(x) ((int16_t)(x)) #define UINT16_FROM_LE(x) UINT16_SWAP(x) #define UINT16_FROM_BE(x) ((uint16_t)(x)) + #define INT32_FROM_LE(x) INT32_SWAP(x) #define INT32_FROM_BE(x) ((int32_t)(x)) + #define UINT32_FROM_LE(x) UINT32_SWAP(x) #define UINT32_FROM_BE(x) ((uint32_t)(x)) + + #define UINT32_TO_LE(x) UINT32_SWAP(x) + #define UINT32_TO_BE(x) ((uint32_t)(x)) #else #define INT16_FROM_LE(x) ((int16_t)(x)) #define INT16_FROM_BE(x) INT16_SWAP(x) + #define INT16_TO_LE(x) ((int16_t)(x)) #define INT16_TO_BE(x) INT16_SWAP(x) #define UINT16_FROM_LE(x) ((uint16_t)(x)) #define UINT16_FROM_BE(x) UINT16_SWAP(x) + #define INT32_FROM_LE(x) ((int32_t)(x)) #define INT32_FROM_BE(x) INT32_SWAP(x) + #define UINT32_FROM_LE(x) ((uint32_t)(x)) #define UINT32_FROM_BE(x) UINT32_SWAP(x) + + #define UINT32_TO_LE(x) ((uint32_t)(x)) + #define UINT32_TO_BE(x) UINT32_SWAP(x) #endif #endif diff --git a/polyp/mainloop-api.h b/polyp/mainloop-api.h index daf71d71..3fb221fa 100644 --- a/polyp/mainloop-api.h +++ b/polyp/mainloop-api.h @@ -25,7 +25,7 @@ #include #include -#include "cdecl.h" +#include /** \file * diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index d7a1cb53..9933d37a 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -46,6 +46,8 @@ PA_MODULE_DESCRIPTION("ALSA Sink") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink_name= device= format= channels= rate= fragments= fragment_size=") +#define PA_TYPEID_ALSA PA_TYPEID_MAKE('A', 'L', 'S', 'A') + struct userdata { snd_pcm_t *pcm_handle; struct pa_sink *sink; @@ -212,7 +214,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { goto fail; } - u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); + u->sink = pa_sink_new(c, PA_TYPEID_ALSA, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index 56eb1455..67e38a1d 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -46,6 +46,8 @@ PA_MODULE_DESCRIPTION("ALSA Source") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("source_name= device= format= channels= rate= fragments= fragment_size=") +#define PA_TYPEID_ALSA PA_TYPEID_MAKE('A', 'L', 'S', 'A') + struct userdata { snd_pcm_t *pcm_handle; struct pa_source *source; @@ -203,7 +205,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { goto fail; } - u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); + u->source = pa_source_new(c, PA_TYPEID_ALSA, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); assert(u->source); u->source->userdata = u; diff --git a/polyp/module-combine.c b/polyp/module-combine.c index 7b3c26dd..ca79d7df 100644 --- a/polyp/module-combine.c +++ b/polyp/module-combine.c @@ -43,6 +43,8 @@ PA_MODULE_DESCRIPTION("Combine multiple sinks to one") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink_name= master= slaves= adjust_time= resample_method=") +#define PA_TYPEID_COMBINE PA_TYPEID_MAKE('C', 'M', 'B', 'N') + #define DEFAULT_SINK_NAME "combined" #define MEMBLOCKQ_MAXLENGTH (1024*170) #define RENDER_SIZE (1024*10) @@ -214,7 +216,7 @@ static struct output *output_new(struct userdata *u, struct pa_sink *sink, int r o->memblockq = pa_memblockq_new(MEMBLOCKQ_MAXLENGTH, MEMBLOCKQ_MAXLENGTH, pa_frame_size(&u->sink->sample_spec), 0, 0, sink->core->memblock_stat); snprintf(t, sizeof(t), "%s: output #%u", u->sink->name, u->n_outputs+1); - if (!(o->sink_input = pa_sink_input_new(sink, t, &u->sink->sample_spec, 1, resample_method))) + if (!(o->sink_input = pa_sink_input_new(sink, PA_TYPEID_COMBINE, t, &u->sink->sample_spec, 1, resample_method))) goto fail; o->sink_input->get_latency = sink_input_get_latency_cb; @@ -325,7 +327,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { goto fail; } - if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &master_sink->sample_spec))) { + if (!(u->sink = pa_sink_new(c, PA_TYPEID_COMBINE, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &master_sink->sample_spec))) { pa_log(__FILE__": failed to create sink\n"); goto fail; } diff --git a/polyp/module-esound-sink.c b/polyp/module-esound-sink.c index 2cc61440..82c38cc2 100644 --- a/polyp/module-esound-sink.c +++ b/polyp/module-esound-sink.c @@ -52,6 +52,8 @@ PA_MODULE_USAGE("sink_name= server=
    cookie=state = STATE_AUTH; u->latency = 0; - if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { + if (!(u->sink = pa_sink_new(c, PA_TYPEID_ESOUND_SINK, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { pa_log(__FILE__": failed to create sink.\n"); goto fail; } diff --git a/polyp/module-null-sink.c b/polyp/module-null-sink.c index 6d4ea89b..fcac1ea4 100644 --- a/polyp/module-null-sink.c +++ b/polyp/module-null-sink.c @@ -49,6 +49,8 @@ PA_MODULE_USAGE("format= channels= rate=module = m; m->userdata = u; - if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { + if (!(u->sink = pa_sink_new(c, PA_TYPEID_NULL, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { pa_log(__FILE__": failed to create sink.\n"); goto fail; } diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index 6fe4fa0c..3c5c0ad8 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -53,6 +53,8 @@ PA_MODULE_DESCRIPTION("OSS Sink/Source (mmap)") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= fragments= fragment_size=") +#define PA_TYPEID_OSS_MMAP PA_TYPEID_MAKE('O', 'S', 'S', 'M') + struct userdata { struct pa_sink *sink; struct pa_source *source; @@ -302,7 +304,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { } } else { - u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec); + u->source = pa_source_new(c, PA_TYPEID_OSS_MMAP, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec); assert(u->source); u->source->userdata = u; pa_source_set_owner(u->source, m); @@ -334,7 +336,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { } else { pa_silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec); - u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec); + u->sink = pa_sink_new(c, PA_TYPEID_OSS_MMAP, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; u->sink->userdata = u; diff --git a/polyp/module-oss.c b/polyp/module-oss.c index fa01876d..67922d82 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -52,6 +52,8 @@ PA_MODULE_DESCRIPTION("OSS Sink/Source") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= fragments= fragment_size=") +#define PA_TYPEID_OSS PA_TYPEID_MAKE('O', 'S', 'S', '_') + struct userdata { struct pa_sink *sink; struct pa_source *source; @@ -325,7 +327,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { } if (mode != O_WRONLY) { - u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); + u->source = pa_source_new(c, PA_TYPEID_OSS, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); assert(u->source); u->source->userdata = u; u->source->get_latency = source_get_latency_cb; @@ -335,7 +337,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { u->source = NULL; if (mode != O_RDONLY) { - u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); + u->sink = pa_sink_new(c, PA_TYPEID_OSS, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; u->sink->userdata = u; diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c index 6c441cc8..b6d8dc2e 100644 --- a/polyp/module-pipe-sink.c +++ b/polyp/module-pipe-sink.c @@ -50,6 +50,8 @@ PA_MODULE_USAGE("sink_name= file= format=module = m; m->userdata = u; - if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { + if (!(u->sink = pa_sink_new(c, PA_TYPEID_PIPE, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { pa_log(__FILE__": failed to create sink.\n"); goto fail; } diff --git a/polyp/module-pipe-source.c b/polyp/module-pipe-source.c index e8a17b96..5a397162 100644 --- a/polyp/module-pipe-source.c +++ b/polyp/module-pipe-source.c @@ -50,6 +50,8 @@ PA_MODULE_USAGE("source_name= file= forma #define DEFAULT_FIFO_NAME "/tmp/music.input" #define DEFAULT_SOURCE_NAME "fifo_input" +#define PA_TYPEID_PIPE PA_TYPEID_MAKE('P', 'I', 'P', 'E') + struct userdata { struct pa_core *core; @@ -152,7 +154,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { u->filename = pa_xstrdup(p); u->core = c; - if (!(u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss))) { + if (!(u->source = pa_source_new(c, PA_TYPEID_PIPE, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss))) { pa_log(__FILE__": failed to create source.\n"); goto fail; } diff --git a/polyp/module-sine.c b/polyp/module-sine.c index 83414821..d8f7e4ef 100644 --- a/polyp/module-sine.c +++ b/polyp/module-sine.c @@ -40,6 +40,8 @@ PA_MODULE_DESCRIPTION("Sine wave generator") PA_MODULE_USAGE("sink= frequency=") PA_MODULE_VERSION(PACKAGE_VERSION) +#define PA_TYPEID_SINE PA_TYPEID_MAKE('S', 'I', 'N', 'E') + struct userdata { struct pa_core *core; struct pa_module *module; @@ -140,7 +142,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { calc_sine(u->memblock->data, u->memblock->length, frequency); snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency); - if (!(u->sink_input = pa_sink_input_new(sink, t, &ss, 0, -1))) + if (!(u->sink_input = pa_sink_input_new(sink, PA_TYPEID_SINE, t, &ss, 0, -1))) goto fail; u->sink_input->peek = sink_input_peek; diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c index d165aab8..9da87b3d 100644 --- a/polyp/module-tunnel.c +++ b/polyp/module-tunnel.c @@ -60,6 +60,8 @@ PA_MODULE_USAGE("server=
    source= cookie= PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_VERSION(PACKAGE_VERSION) +#define PA_TYPEID_TUNNEL PA_TYPEID_MAKE('T', 'U', 'N', 'L') + #define DEFAULT_SINK_NAME "tunnel" #define DEFAULT_SOURCE_NAME "tunnel" @@ -624,7 +626,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { pa_socket_client_set_callback(u->client, on_connection, u); #ifdef TUNNEL_SINK - if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { + if (!(u->sink = pa_sink_new(c, PA_TYPEID_TUNNEL, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { pa_log(__FILE__": failed to create sink.\n"); goto fail; } @@ -636,7 +638,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { pa_sink_set_owner(u->sink, m); #else - if (!(u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss))) { + if (!(u->source = pa_source_new(c, PA_TYPEID_TUNNEL, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss))) { pa_log(__FILE__": failed to create source.\n"); goto fail; } diff --git a/polyp/module-zeroconf-publish.c b/polyp/module-zeroconf-publish.c index 363c2419..c88ac766 100644 --- a/polyp/module-zeroconf-publish.c +++ b/polyp/module-zeroconf-publish.c @@ -40,6 +40,7 @@ #include "log.h" #include "subscribe.h" #include "dynarray.h" +#include "endianmacros.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Publisher") @@ -79,21 +80,36 @@ static sw_result publish_reply(sw_discovery discovery, sw_discovery_publish_stat return SW_OKAY; } -static void get_service_sample_spec(struct userdata *u, struct service *s, struct pa_sample_spec *ret_ss) { - assert(u && s && s->loaded.valid && ret_ss); +static void get_service_data(struct userdata *u, struct service *s, struct pa_sample_spec *ret_ss, char **ret_description, pa_typeid_t *ret_typeid) { + assert(u && s && s->loaded.valid && ret_ss && ret_description && ret_typeid); if (s->loaded.type == PA_NAMEREG_SINK) { struct pa_sink *sink = pa_idxset_get_by_index(u->core->sinks, s->loaded.index); assert(sink); *ret_ss = sink->sample_spec; + *ret_description = sink->description; + *ret_typeid = sink->typeid; } else if (s->loaded.type == PA_NAMEREG_SOURCE) { struct pa_source *source = pa_idxset_get_by_index(u->core->sources, s->loaded.index); assert(source); *ret_ss = source->sample_spec; + *ret_description = source->description; + *ret_typeid = source->typeid; } else assert(0); } +static void txt_record_server_data(struct pa_core *c, sw_text_record t) { + char s[256]; + assert(c); + + sw_text_record_add_key_and_string_value(t, "server-version", PACKAGE_NAME" "PACKAGE_VERSION); + sw_text_record_add_key_and_string_value(t, "user-name", pa_get_user_name(s, sizeof(s))); + sw_text_record_add_key_and_string_value(t, "fqdn", pa_get_fqdn(s, sizeof(s))); + snprintf(s, sizeof(s), "0x%08x", c->cookie); + sw_text_record_add_key_and_string_value(t, "cookie", s); +} + static int publish_service(struct userdata *u, struct service *s) { assert(u && s); char t[256]; @@ -120,18 +136,27 @@ static int publish_service(struct userdata *u, struct service *s) { free_txt = 1; sw_text_record_add_key_and_string_value(txt, "device", s->name); + + txt_record_server_data(u->core, txt); if (s->loaded.valid) { - char z[64]; + char z[64], *description; + pa_typeid_t typeid; struct pa_sample_spec ss; - get_service_sample_spec(u, s, &ss); + get_service_data(u, s, &ss, &description, &typeid); snprintf(z, sizeof(z), "%u", ss.rate); sw_text_record_add_key_and_string_value(txt, "rate", z); snprintf(z, sizeof(z), "%u", ss.channels); sw_text_record_add_key_and_string_value(txt, "channels", z); sw_text_record_add_key_and_string_value(txt, "format", pa_sample_format_to_string(ss.format)); + + sw_text_record_add_key_and_string_value(txt, "description", description); + + snprintf(z, sizeof(z), "0x%8x", typeid); + sw_text_record_add_key_and_string_value(txt, "typeid", z); + if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t, s->loaded.type == PA_NAMEREG_SINK ? SERVICE_NAME_SINK : SERVICE_NAME_SOURCE, diff --git a/polyp/pabrowse.c b/polyp/pabrowse.c new file mode 100644 index 00000000..ccea0cd4 --- /dev/null +++ b/polyp/pabrowse.c @@ -0,0 +1,139 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include + +static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { + fprintf(stderr, "Got signal, exiting\n"); + m->quit(m, 0); +} + +static void dump_server(const struct pa_browse_info *i) { + char t[16]; + + if (i->cookie) + snprintf(t, sizeof(t), "0x%08x", *i->cookie); + + printf("server: %s\n" + "server-version: %s\n" + "user-name: %s\n" + "fqdn: %s\n" + "cookie: %s\n", + i->server, + i->server_version ? i->server_version : "n/a", + i->user_name ? i->user_name : "n/a", + i->fqdn ? i->fqdn : "n/a", + i->cookie ? t : "n/a"); +} + +static void dump_device(const struct pa_browse_info *i) { + char t[16], ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + if (i->sample_spec) + pa_sample_spec_snprint(ss, sizeof(ss), i->sample_spec); + + if (i->typeid) + pa_typeid_to_string(*i->typeid, t, sizeof(t)); + + printf("device: %s\n" + "description: %s\n" + "type: %s\n" + "sample spec: %s\n", + i->device, + i->description ? i->description : "n/a", + i->typeid ? t : "n/a", + i->sample_spec ? ss : "n/a"); + +} + +static void browser_callback(struct pa_browser *b, enum pa_browse_opcode c, const struct pa_browse_info *i, void *userdata) { + assert(b && i); + + switch (c) { + + case PA_BROWSE_NEW_SERVER: + printf("\n=> new server <%s>\n", i->name); + dump_server(i); + break; + + case PA_BROWSE_NEW_SINK: + printf("\n=> new sink <%s>\n", i->name); + dump_server(i); + dump_device(i); + break; + + case PA_BROWSE_NEW_SOURCE: + printf("\n=> new source <%s>\n", i->name); + dump_server(i); + dump_device(i); + break; + + case PA_BROWSE_REMOVE: + printf("\n=> removed service <%s>\n", i->name); + break; + + default: + ; + } +} + + +int main(int argc, char *argv[]) { + struct pa_mainloop *mainloop = NULL; + struct pa_browser *browser = NULL; + int ret = 1, r; + + if (!(mainloop = pa_mainloop_new())) + goto finish; + + r = pa_signal_init(pa_mainloop_get_api(mainloop)); + assert(r == 0); + pa_signal_new(SIGINT, exit_signal_callback, NULL); + pa_signal_new(SIGTERM, exit_signal_callback, NULL); + signal(SIGPIPE, SIG_IGN); + + if (!(browser = pa_browser_new(pa_mainloop_get_api(mainloop)))) + goto finish; + + pa_browser_set_callback(browser, browser_callback, NULL); + + ret = 0; + pa_mainloop_run(mainloop, &ret); + +finish: + if (mainloop) { + pa_signal_done(); + pa_mainloop_free(mainloop); + } + + return ret; +} diff --git a/polyp/pacat.c b/polyp/pacat.c index 8c3ee0ba..5910d13f 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -38,7 +38,7 @@ #include #include -#if PA_API_VERSION != 7 +#if PA_API_VERSION != 8 #error Invalid Polypaudio API version #endif @@ -290,7 +290,7 @@ static void stdout_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int /* UNIX signal to quit recieved */ static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { if (verbose) - fprintf(stderr, "Got SIGINT, exiting.\n"); + fprintf(stderr, "Got signal, exiting.\n"); quit(0); } @@ -479,6 +479,7 @@ int main(int argc, char *argv[]) { r = pa_signal_init(mainloop_api); assert(r == 0); pa_signal_new(SIGINT, exit_signal_callback, NULL); + pa_signal_new(SIGTERM, exit_signal_callback, NULL); pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL); signal(SIGPIPE, SIG_IGN); diff --git a/polyp/pactl.c b/polyp/pactl.c index 6300b656..d4dc6ad1 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -41,7 +41,7 @@ #include #include -#if PA_API_VERSION != 7 +#if PA_API_VERSION != 8 #error Invalid Polypaudio API version #endif @@ -134,20 +134,22 @@ static void get_server_info_callback(struct pa_context *c, const struct pa_serve "Server Version: %s\n" "Default Sample Specification: %s\n" "Default Sink: %s\n" - "Default Source: %s\n", + "Default Source: %s\n" + "Cookie: %08x\n", i->user_name, i->host_name, i->server_name, i->server_version, s, i->default_sink_name, - i->default_source_name); + i->default_source_name, + i->cookie); complete_action(); } static void get_sink_info_callback(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata) { - char s[PA_SAMPLE_SPEC_SNPRINT_MAX]; + char s[PA_SAMPLE_SPEC_SNPRINT_MAX], tid[5]; if (is_last < 0) { fprintf(stderr, "Failed to get sink information: %s\n", pa_strerror(pa_context_errno(c))); @@ -170,6 +172,7 @@ static void get_sink_info_callback(struct pa_context *c, const struct pa_sink_in printf("*** Sink #%u ***\n" "Name: %s\n" + "Type: %s\n" "Description: %s\n" "Sample Specification: %s\n" "Owner Module: %u\n" @@ -178,16 +181,18 @@ static void get_sink_info_callback(struct pa_context *c, const struct pa_sink_in "Latency: %0.0f usec\n", i->index, i->name, + pa_typeid_to_string(i->typeid, tid, sizeof(tid)), i->description, s, i->owner_module, i->volume, pa_volume_to_dB(i->volume), i->monitor_source, (double) i->latency); + } static void get_source_info_callback(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata) { - char s[PA_SAMPLE_SPEC_SNPRINT_MAX], t[32]; + char s[PA_SAMPLE_SPEC_SNPRINT_MAX], t[32], tid[5]; if (is_last < 0) { fprintf(stderr, "Failed to get source information: %s\n", pa_strerror(pa_context_errno(c))); @@ -212,18 +217,21 @@ static void get_source_info_callback(struct pa_context *c, const struct pa_sourc printf("*** Source #%u ***\n" "Name: %s\n" + "Type: %s\n" "Description: %s\n" "Sample Specification: %s\n" "Owner Module: %u\n" "Monitor of Sink: %s\n" "Latency: %0.0f usec\n", i->index, + pa_typeid_to_string(i->typeid, tid, sizeof(tid)), i->name, i->description, s, i->owner_module, i->monitor_of_sink != PA_INVALID_INDEX ? t : "no", (double) i->latency); + } static void get_module_info_callback(struct pa_context *c, const struct pa_module_info *i, int is_last, void *userdata) { @@ -261,7 +269,7 @@ static void get_module_info_callback(struct pa_context *c, const struct pa_modul } static void get_client_info_callback(struct pa_context *c, const struct pa_client_info *i, int is_last, void *userdata) { - char t[32]; + char t[32], tid[5]; if (is_last < 0) { fprintf(stderr, "Failed to get client information: %s\n", pa_strerror(pa_context_errno(c))); @@ -284,16 +292,16 @@ static void get_client_info_callback(struct pa_context *c, const struct pa_clien printf("*** Client #%u ***\n" "Name: %s\n" - "Owner Module: %s\n" - "Protocol Name: %s\n", + "Type: %s\n" + "Owner Module: %s\n", i->index, i->name, - i->owner_module != PA_INVALID_INDEX ? t : "n/a", - i->protocol_name); + pa_typeid_to_string(i->typeid, tid, sizeof(tid)), + i->owner_module != PA_INVALID_INDEX ? t : "n/a"); } static void get_sink_input_info_callback(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata) { - char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX]; + char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], tid[5]; if (is_last < 0) { fprintf(stderr, "Failed to get sink input information: %s\n", pa_strerror(pa_context_errno(c))); @@ -318,6 +326,7 @@ static void get_sink_input_info_callback(struct pa_context *c, const struct pa_s printf("*** Sink Input #%u ***\n" "Name: %s\n" + "Type: %s\n" "Owner Module: %s\n" "Client: %s\n" "Sink: %u\n" @@ -328,6 +337,7 @@ static void get_sink_input_info_callback(struct pa_context *c, const struct pa_s "Resample method: %s\n", i->index, i->name, + pa_typeid_to_string(i->typeid, tid, sizeof(tid)), i->owner_module != PA_INVALID_INDEX ? t : "n/a", i->client != PA_INVALID_INDEX ? k : "n/a", i->sink, @@ -338,8 +348,9 @@ static void get_sink_input_info_callback(struct pa_context *c, const struct pa_s i->resample_method ? i->resample_method : "n/a"); } + static void get_source_output_info_callback(struct pa_context *c, const struct pa_source_output_info *i, int is_last, void *userdata) { - char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX]; + char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], tid[5]; if (is_last < 0) { fprintf(stderr, "Failed to get source output information: %s\n", pa_strerror(pa_context_errno(c))); @@ -364,6 +375,7 @@ static void get_source_output_info_callback(struct pa_context *c, const struct p printf("*** Source Output #%u ***\n" "Name: %s\n" + "Type: %s\n" "Owner Module: %s\n" "Client: %s\n" "Source: %u\n" @@ -373,6 +385,7 @@ static void get_source_output_info_callback(struct pa_context *c, const struct p "Resample method: %s\n", i->index, i->name, + pa_typeid_to_string(i->typeid, tid, sizeof(tid)), i->owner_module != PA_INVALID_INDEX ? t : "n/a", i->client != PA_INVALID_INDEX ? k : "n/a", i->source, diff --git a/polyp/paplay.c b/polyp/paplay.c index 0faa0ff2..2eaf07c1 100644 --- a/polyp/paplay.c +++ b/polyp/paplay.c @@ -40,7 +40,7 @@ #include #include -#if PA_API_VERSION != 7 +#if PA_API_VERSION != 8 #error Invalid Polypaudio API version #endif diff --git a/polyp/play-memchunk.c b/polyp/play-memchunk.c index 1b611db4..c7a85454 100644 --- a/polyp/play-memchunk.c +++ b/polyp/play-memchunk.c @@ -32,6 +32,8 @@ #include "sink-input.h" #include "xmalloc.h" +#define PA_TYPEID_MEMCHUNK PA_TYPEID_MAKE('M', 'C', 'N', 'K') + static void sink_input_kill(struct pa_sink_input *i) { struct pa_memchunk *c; assert(i && i->userdata); @@ -88,7 +90,7 @@ int pa_play_memchunk(struct pa_sink *sink, const char *name, const struct pa_sam if (volume <= 0) return 0; - if (!(si = pa_sink_input_new(sink, name, ss, 0, -1))) + if (!(si = pa_sink_input_new(sink, PA_TYPEID_MEMCHUNK, name, ss, 0, -1))) return -1; si->volume = volume; diff --git a/polyp/polyplib-browser.c b/polyp/polyplib-browser.c new file mode 100644 index 00000000..a1bd3fb7 --- /dev/null +++ b/polyp/polyplib-browser.c @@ -0,0 +1,307 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include "polyplib-browser.h" +#include "xmalloc.h" +#include "log.h" +#include "util.h" + +#define SERVICE_NAME_SINK "_polypaudio-sink._tcp." +#define SERVICE_NAME_SOURCE "_polypaudio-source._tcp." +#define SERVICE_NAME_SERVER "_polypaudio-server._tcp." + +struct pa_browser { + int ref; + struct pa_mainloop_api *mainloop; + + void (*callback)(struct pa_browser *z, enum pa_browse_opcode c, const struct pa_browse_info *i, void *userdata); + void *callback_userdata; + + sw_discovery discovery; + struct pa_io_event *io_event; +}; + + +static void io_callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enum pa_io_event_flags events, void *userdata) { + struct pa_browser *b = userdata; + assert(a && b && b->mainloop == a); + + if (events != PA_IO_EVENT_INPUT || sw_discovery_read_socket(b->discovery) != SW_OKAY) { + pa_log(__FILE__": connection to HOWL daemon failed.\n"); + b->mainloop->io_free(b->io_event); + b->io_event = NULL; + return; + } +} + + +static sw_result resolve_reply( + sw_discovery discovery, + sw_discovery_oid oid, + sw_uint32 interface_index, + sw_const_string name, + sw_const_string type, + sw_const_string domain, + sw_ipv4_address address, + sw_port port, + sw_octets text_record, + sw_ulong text_record_len, + sw_opaque extra) { + + struct pa_browser *b = extra; + struct pa_browse_info i; + char ip[256], a[256]; + enum pa_browse_opcode opcode; + int device_found = 0; + uint32_t cookie; + pa_typeid_t typeid; + struct pa_sample_spec ss; + int ss_valid = 0; + sw_text_record_iterator iterator; + int free_iterator = 0; + char *c = NULL; + + assert(b); + + sw_discovery_cancel(discovery, oid); + + memset(&i, 0, sizeof(i)); + i.name = name; + + if (!b->callback) + goto fail; + + if (!strcmp(type, SERVICE_NAME_SINK)) + opcode = PA_BROWSE_NEW_SINK; + else if (!strcmp(type, SERVICE_NAME_SOURCE)) + opcode = PA_BROWSE_NEW_SOURCE; + else if (!strcmp(type, SERVICE_NAME_SERVER)) + opcode = PA_BROWSE_NEW_SERVER; + else + goto fail; + + + snprintf(a, sizeof(a), "tcp:%s:%u", sw_ipv4_address_name(address, ip, sizeof(ip)), port); + i.server = a; + + if (text_record && text_record_len) { + char key[SW_TEXT_RECORD_MAX_LEN]; + uint8_t val[SW_TEXT_RECORD_MAX_LEN]; + uint32_t val_len; + + if (sw_text_record_iterator_init(&iterator, text_record, text_record_len) != SW_OKAY) { + pa_log("sw_text_record_string_iterator_init() failed.\n"); + goto fail; + } + + free_iterator = 1; + + while (sw_text_record_iterator_next(iterator, key, val, &val_len) == SW_OKAY) { + c = pa_xstrndup((char*) val, val_len); + + if (!strcmp(key, "device")) { + device_found = 1; + pa_xfree((char*) i.device); + i.device = c; + c = NULL; + } else if (!strcmp(key, "server-version")) { + pa_xfree((char*) i.server_version); + i.server_version = c; + c = NULL; + } else if (!strcmp(key, "user-name")) { + pa_xfree((char*) i.user_name); + i.user_name = c; + c = NULL; + } else if (!strcmp(key, "fqdn")) { + pa_xfree((char*) i.fqdn); + i.fqdn = c; + c = NULL; + } else if (!strcmp(key, "cookie")) { + + if (pa_atou(c, &cookie) < 0) + goto fail; + + i.cookie = &cookie; + } else if (!strcmp(key, "description")) { + pa_xfree((char*) i.description); + i.description = c; + c = NULL; + } else if (!strcmp(key, "typeid")) { + + if (pa_atou(c, &typeid) < 0) + goto fail; + + i.typeid = &typeid; + } else if (!strcmp(key, "channels")) { + uint32_t ch; + + if (pa_atou(c, &ch) < 0 || ch <= 0 || ch > 255) + goto fail; + + ss.channels = (uint8_t) ch; + ss_valid |= 1; + + } else if (!strcmp(key, "rate")) { + if (pa_atou(c, &ss.rate) < 0) + goto fail; + ss_valid |= 2; + } else if (!strcmp(key, "format")) { + + if ((ss.format = pa_parse_sample_format(c)) == PA_SAMPLE_INVALID) + goto fail; + + ss_valid |= 4; + } + + pa_xfree(c); + c = NULL; + } + + } + + /* No device txt record was sent for a sink or source service */ + if (opcode != PA_BROWSE_NEW_SERVER && !device_found) + goto fail; + + if (ss_valid == 7) + i.sample_spec = &ss; + + + b->callback(b, opcode, &i, b->callback_userdata); + +fail: + pa_xfree((void*) i.device); + pa_xfree((void*) i.fqdn); + pa_xfree((void*) i.server_version); + pa_xfree((void*) i.user_name); + pa_xfree((void*) i.description); + pa_xfree(c); + + if (free_iterator) + sw_text_record_iterator_fina(iterator); + + + return SW_OKAY; +} + +static sw_result browse_reply( + sw_discovery discovery, + sw_discovery_oid id, + sw_discovery_browse_status status, + sw_uint32 interface_index, + sw_const_string name, + sw_const_string type, + sw_const_string domain, + sw_opaque extra) { + + struct pa_browser *b = extra; + assert(b); + + switch (status) { + case SW_DISCOVERY_BROWSE_ADD_SERVICE: { + sw_discovery_oid oid; + fprintf(stderr, "debug: new service: %s\n", name); + + if (sw_discovery_resolve(b->discovery, 0, name, type, domain, resolve_reply, b, &oid) != SW_OKAY) + pa_log("sw_discovery_resolve() failed\n"); + + break; + } + + case SW_DISCOVERY_BROWSE_REMOVE_SERVICE: + if (b->callback) { + struct pa_browse_info i; + memset(&i, 0, sizeof(i)); + i.name = name; + b->callback(b, PA_BROWSE_REMOVE, &i, b->callback_userdata); + } + break; + + default: + ; + } + + return SW_OKAY; +} + +struct pa_browser *pa_browser_new(struct pa_mainloop_api *mainloop) { + struct pa_browser *b; + sw_discovery_oid oid; + + b = pa_xmalloc(sizeof(struct pa_browser)); + b->mainloop = mainloop; + b->ref = 1; + b->callback = NULL; + b->callback_userdata = NULL; + + if (sw_discovery_init(&b->discovery) != SW_OKAY) { + pa_log("sw_discovery_init() failed.\n"); + pa_xfree(b); + return NULL; + } + + if (sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SERVER, NULL, browse_reply, b, &oid) != SW_OKAY || + sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SINK, NULL, browse_reply, b, &oid) != SW_OKAY || + sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SOURCE, NULL, browse_reply, b, &oid) != SW_OKAY) { + + pa_log("sw_discovery_browse() failed.\n"); + + sw_discovery_fina(b->discovery); + pa_xfree(b); + return NULL; + } + + b->io_event = mainloop->io_new(mainloop, sw_discovery_socket(b->discovery), PA_IO_EVENT_INPUT, io_callback, b); + return b; +} + +static void browser_free(struct pa_browser *b) { + assert(b && b->mainloop); + + if (b->io_event) + b->mainloop->io_free(b->io_event); + + sw_discovery_fina(b->discovery); + pa_xfree(b); +} + +struct pa_browser *pa_browser_ref(struct pa_browser *b) { + assert(b && b->ref >= 1); + b->ref++; + return b; +} + +void pa_browser_unref(struct pa_browser *b) { + assert(b && b->ref >= 1); + + if ((-- (b->ref)) <= 0) + browser_free(b); +} + +void pa_browser_set_callback(struct pa_browser *b, void (*cb)(struct pa_browser *z, enum pa_browse_opcode c, const struct pa_browse_info *i, void* userdata), void *userdata) { + assert(b); + + b->callback = cb; + b->callback_userdata = userdata; +} diff --git a/polyp/polyplib-browser.h b/polyp/polyplib-browser.h new file mode 100644 index 00000000..c13eff22 --- /dev/null +++ b/polyp/polyplib-browser.h @@ -0,0 +1,65 @@ +#ifndef foopolyplibbrowserhfoo +#define foopolyplibbrowserhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +PA_C_DECL_BEGIN + +struct pa_browser; + +enum pa_browse_opcode { + PA_BROWSE_NEW_SERVER, + PA_BROWSE_NEW_SINK, + PA_BROWSE_NEW_SOURCE, + PA_BROWSE_REMOVE +}; + +struct pa_browser *pa_browser_new(struct pa_mainloop_api *mainloop); +struct pa_browser *pa_browser_ref(struct pa_browser *z); +void pa_browser_unref(struct pa_browser *z); + +struct pa_browse_info { + /* Unique service name */ + const char *name; /* always available */ + + /* Server info */ + const char *server; /* always available */ + const char *server_version, *user_name, *fqdn; /* optional */ + const uint32_t *cookie; /* optional */ + + /* Device info */ + const char *device; /* always available when this information is of a sink/source */ + const char *description; /* optional */ + const pa_typeid_t *typeid; /* optional */ + const struct pa_sample_spec *sample_spec; /* optional */ +}; + +void pa_browser_set_callback(struct pa_browser *z, void (*cb)(struct pa_browser *z, enum pa_browse_opcode c, const struct pa_browse_info *i, void *userdata), void *userdata); + +PA_C_DECL_END + +#endif diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h index db4b121d..0283312a 100644 --- a/polyp/polyplib-context.h +++ b/polyp/polyplib-context.h @@ -1,4 +1,3 @@ - #ifndef foopolyplibcontexthfoo #define foopolyplibcontexthfoo @@ -23,11 +22,11 @@ USA. ***/ -#include "sample.h" -#include "polyplib-def.h" -#include "mainloop-api.h" -#include "cdecl.h" -#include "polyplib-operation.h" +#include +#include +#include +#include +#include /** \file * Connection contexts for asynchrononous communication with a diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index 44c2034b..9adb68fc 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -26,8 +26,8 @@ #include #include -#include "cdecl.h" -#include "sample.h" +#include +#include /** \file * Global definitions */ diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index fe632c26..166555c0 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -85,6 +85,7 @@ static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t c pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || pa_tagstruct_gets(t, &i.default_sink_name) < 0 || pa_tagstruct_gets(t, &i.default_source_name) < 0 || + pa_tagstruct_getu32(t, &i.cookie) < 0 || !pa_tagstruct_eof(t)) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); @@ -130,7 +131,9 @@ static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t com pa_tagstruct_getu32(t, &i.volume) < 0 || pa_tagstruct_getu32(t, &i.monitor_source) < 0 || pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || - pa_tagstruct_get_usec(t, &i.latency) < 0) { + pa_tagstruct_get_usec(t, &i.latency) < 0 || + pa_tagstruct_getu32(t, &i.typeid) < 0) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } @@ -222,7 +225,8 @@ static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t c pa_tagstruct_getu32(t, &i.owner_module) < 0 || pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 || - pa_tagstruct_get_usec(t, &i.latency) < 0) { + pa_tagstruct_get_usec(t, &i.latency) < 0 || + pa_tagstruct_getu32(t, &i.typeid) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; @@ -310,8 +314,8 @@ static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t c if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.protocol_name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0) { + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.typeid) < 0 ) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } @@ -450,7 +454,9 @@ static void context_get_sink_input_info_callback(struct pa_pdispatch *pd, uint32 pa_tagstruct_getu32(t, &i.volume) < 0 || pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || - pa_tagstruct_gets(t, &i.resample_method) < 0) { + pa_tagstruct_gets(t, &i.resample_method) < 0 || + pa_tagstruct_getu32(t, &i.typeid) < 0) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } @@ -521,7 +527,9 @@ static void context_get_source_output_info_callback(struct pa_pdispatch *pd, uin pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || pa_tagstruct_get_usec(t, &i.source_usec) < 0 || - pa_tagstruct_gets(t, &i.resample_method) < 0) { + pa_tagstruct_gets(t, &i.resample_method) < 0 || + pa_tagstruct_getu32(t, &i.typeid) < 0) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } @@ -659,6 +667,7 @@ static void context_get_sample_info_callback(struct pa_pdispatch *pd, uint32_t c pa_tagstruct_getu32(t, &i.bytes) < 0 || pa_tagstruct_get_boolean(t, &i.lazy) < 0 || pa_tagstruct_gets(t, &i.filename) < 0) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index 08b36f86..ba9bde3c 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -24,9 +24,10 @@ #include -#include "polyplib-operation.h" -#include "polyplib-context.h" -#include "cdecl.h" +#include +#include +#include +#include /** \file * @@ -57,6 +58,7 @@ struct pa_sink_info { uint32_t monitor_source; /**< Index of the monitor source connected to this sink */ const char *monitor_source_name; /**< The name of the monitor source */ pa_usec_t latency; /**< Length of filled playback buffer of this sink */ + pa_typeid_t typeid; /**< Implementation type. \since 0.8 */ }; /** Get information about a sink by its name */ @@ -78,6 +80,7 @@ struct pa_source_info { uint32_t monitor_of_sink; /**< If this is a monitor source the index of the owning sink, otherwise PA_INVALID_INDEX */ const char *monitor_of_sink_name; /**< Name of the owning sink, or PA_INVALID_INDEX */ pa_usec_t latency; /**< Length of filled record buffer of this source. \since 0.5 */ + pa_typeid_t typeid; /**< Implementation type. \since 0.8 */ }; /** Get information about a source by its name */ @@ -97,7 +100,8 @@ struct pa_server_info { const char *server_name; /**< Server package name (usually "polypaudio") */ struct pa_sample_spec sample_spec; /**< Default sample specification */ const char *default_sink_name; /**< Name of default sink. \since 0.4 */ - const char *default_source_name; /**< Name of default sink. \since 0.4*/ + const char *default_source_name; /**< Name of default sink. \since 0.4*/ + uint32_t cookie; /**< A random cookie for identifying this instance of polypaudio. \since 0.8 */ }; /** Get some information about the server */ @@ -123,7 +127,7 @@ struct pa_client_info { uint32_t index; /**< Index of this client */ const char *name; /**< Name of this client */ uint32_t owner_module; /**< Index of the owning module, or PA_INVALID_INDEX */ - const char *protocol_name; /**< A string describing the protocol name this client is connected over (i.e. "ESOUND", "NATIVE", "SIMPLE") */ + pa_typeid_t typeid; /**< Implementation type. \since 0.8 */ }; /** Get information about a client by its index */ @@ -144,6 +148,7 @@ struct pa_sink_input_info { pa_usec_t buffer_usec; /**< Latency due to buffering in sink input, see pa_latency_info for details */ pa_usec_t sink_usec; /**< Latency of the sink device, see pa_latency_info for details */ const char *resample_method; /**< Thre resampling method used by this sink input. \since 0.7 */ + pa_typeid_t typeid; /**< Implementation type. \since 0.8 */ }; /** Get some information about a sink input by its index */ @@ -163,6 +168,7 @@ struct pa_source_output_info { pa_usec_t buffer_usec; /**< Latency due to buffering in the source output, see pa_latency_info for details. \since 0.5 */ pa_usec_t source_usec; /**< Latency of the source device, see pa_latency_info for details. \since 0.5 */ const char *resample_method; /**< Thre resampling method used by this source output. \since 0.7 */ + pa_typeid_t typeid; /**< Implementation type. \since 0.8 */ }; /** Get information about a source output by its index */ diff --git a/polyp/polyplib-operation.h b/polyp/polyplib-operation.h index bd1366d2..5c3af49c 100644 --- a/polyp/polyplib-operation.h +++ b/polyp/polyplib-operation.h @@ -22,8 +22,8 @@ USA. ***/ -#include "cdecl.h" -#include "polyplib-def.h" +#include +#include /** \file * Asynchronous operations */ diff --git a/polyp/polyplib-scache.h b/polyp/polyplib-scache.h index 051bdd12..8ec375ea 100644 --- a/polyp/polyplib-scache.h +++ b/polyp/polyplib-scache.h @@ -24,9 +24,9 @@ #include -#include "polyplib-context.h" -#include "polyplib-stream.h" -#include "cdecl.h" +#include +#include +#include /** \file * All sample cache related routines */ diff --git a/polyp/polyplib-stream.h b/polyp/polyplib-stream.h index 53873491..939b2ae6 100644 --- a/polyp/polyplib-stream.h +++ b/polyp/polyplib-stream.h @@ -24,10 +24,10 @@ #include -#include "sample.h" -#include "polyplib-def.h" -#include "cdecl.h" -#include "polyplib-operation.h" +#include +#include +#include +#include /** \file * Audio streams for input, output and sample upload */ diff --git a/polyp/polyplib-subscribe.h b/polyp/polyplib-subscribe.h index a677bd02..5c697b71 100644 --- a/polyp/polyplib-subscribe.h +++ b/polyp/polyplib-subscribe.h @@ -24,9 +24,9 @@ #include -#include "polyplib-def.h" -#include "polyplib-context.h" -#include "cdecl.h" +#include +#include +#include /** \file * Daemon introspection event subscription subsystem. Use this diff --git a/polyp/polyplib.h b/polyp/polyplib.h index a0c418d4..b9b9b447 100644 --- a/polyp/polyplib.h +++ b/polyp/polyplib.h @@ -22,16 +22,16 @@ USA. ***/ -#include "cdecl.h" -#include "mainloop-api.h" -#include "sample.h" -#include "polyplib-def.h" -#include "polyplib-context.h" -#include "polyplib-stream.h" -#include "polyplib-introspect.h" -#include "polyplib-subscribe.h" -#include "polyplib-scache.h" -#include "polyplib-version.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /** \file * Include all polyplib header file at once. The following files are included: \ref mainloop-api.h, \ref sample.h, diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index a32a9bd8..d9ed66b9 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -63,6 +63,8 @@ #define SCACHE_PREFIX "esound." +#define PA_TYPEID_ESOUND PA_TYPEID_MAKE('E', 'S', 'D', 'P') + /* This is heavily based on esound's code */ struct connection { @@ -320,7 +322,7 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons assert(!c->sink_input && !c->input_memblockq); - if (!(c->sink_input = pa_sink_input_new(sink, name, &ss, 0, -1))) { + if (!(c->sink_input = pa_sink_input_new(sink, PA_TYPEID_ESOUND, name, &ss, 0, -1))) { pa_log(__FILE__": failed to create sink input.\n"); return -1; } @@ -392,7 +394,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co assert(!c->output_memblockq && !c->source_output); - if (!(c->source_output = pa_source_output_new(source, name, &ss, -1))) { + if (!(c->source_output = pa_source_output_new(source, PA_TYPEID_ESOUND, name, &ss, -1))) { pa_log(__FILE__": failed to create source output\n"); return -1; } @@ -1058,7 +1060,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); assert(p->core); - c->client = pa_client_new(p->core, "ESOUND", cname); + c->client = pa_client_new(p->core, PA_TYPEID_ESOUND, cname); assert(c->client); c->client->owner = p->module; c->client->kill = client_kill_cb; diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 94dc5e5f..d5619ef7 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -56,6 +56,8 @@ /* Don't accept more connection than this */ #define MAX_CONNECTIONS 10 +#define PA_TYPEID_NATIVE PA_TYPEID_MAKE('N', 'A', 'T', 'V') + struct connection; struct pa_protocol_native; @@ -272,7 +274,7 @@ static struct record_stream* record_stream_new(struct connection *c, struct pa_s size_t base; assert(c && source && ss && name && maxlength); - if (!(source_output = pa_source_output_new(source, name, ss, -1))) + if (!(source_output = pa_source_output_new(source, PA_TYPEID_NATIVE, name, ss, -1))) return NULL; s = pa_xmalloc(sizeof(struct record_stream)); @@ -316,7 +318,7 @@ static struct playback_stream* playback_stream_new(struct connection *c, struct struct pa_sink_input *sink_input; assert(c && sink && ss && name && maxlength); - if (!(sink_input = pa_sink_input_new(sink, name, ss, 0, -1))) + if (!(sink_input = pa_sink_input_new(sink, PA_TYPEID_NATIVE, name, ss, 0, -1))) return NULL; s = pa_xmalloc(sizeof(struct playback_stream)); @@ -1118,6 +1120,7 @@ static void sink_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink *sink) { pa_tagstruct_putu32(t, sink->monitor_source->index); pa_tagstruct_puts(t, sink->monitor_source->name); pa_tagstruct_put_usec(t, pa_sink_get_latency(sink)); + pa_tagstruct_putu32(t, sink->typeid); } static void source_fill_tagstruct(struct pa_tagstruct *t, struct pa_source *source) { @@ -1130,14 +1133,15 @@ static void source_fill_tagstruct(struct pa_tagstruct *t, struct pa_source *sour pa_tagstruct_putu32(t, source->monitor_of ? source->monitor_of->index : (uint32_t) -1); pa_tagstruct_puts(t, source->monitor_of ? source->monitor_of->name : NULL); pa_tagstruct_put_usec(t, pa_source_get_latency(source)); + pa_tagstruct_putu32(t, source->typeid); } static void client_fill_tagstruct(struct pa_tagstruct *t, struct pa_client *client) { assert(t && client); pa_tagstruct_putu32(t, client->index); pa_tagstruct_puts(t, client->name); - pa_tagstruct_puts(t, client->protocol_name); pa_tagstruct_putu32(t, client->owner ? client->owner->index : (uint32_t) -1); + pa_tagstruct_putu32(t, client->typeid); } static void module_fill_tagstruct(struct pa_tagstruct *t, struct pa_module *module) { @@ -1161,6 +1165,7 @@ static void sink_input_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink_inp pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s)); pa_tagstruct_put_usec(t, pa_sink_get_latency(s->sink)); pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s))); + pa_tagstruct_putu32(t, s->typeid); } static void source_output_fill_tagstruct(struct pa_tagstruct *t, struct pa_source_output *s) { @@ -1174,6 +1179,7 @@ static void source_output_fill_tagstruct(struct pa_tagstruct *t, struct pa_sourc pa_tagstruct_put_usec(t, pa_source_output_get_latency(s)); pa_tagstruct_put_usec(t, pa_source_get_latency(s->source)); pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s))); + pa_tagstruct_putu32(t, s->typeid); } static void scache_fill_tagstruct(struct pa_tagstruct *t, struct pa_scache_entry *e) { @@ -1366,6 +1372,9 @@ static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, u pa_tagstruct_puts(reply, n); n = pa_namereg_get_default_source_name(c->protocol->core); pa_tagstruct_puts(reply, n); + + pa_tagstruct_putu32(reply, c->protocol->core->cookie); + pa_pstream_send_tagstruct(c->pstream, reply); } @@ -2022,7 +2031,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->protocol = p; assert(p->core); - c->client = pa_client_new(p->core, "NATIVE", "Client"); + c->client = pa_client_new(p->core, PA_TYPEID_NATIVE, "Client"); assert(c->client); c->client->kill = client_kill_cb; c->client->userdata = c; diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index 3dddc474..8d05a7fa 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -42,6 +42,8 @@ /* Don't allow more than this many concurrent connections */ #define MAX_CONNECTIONS 10 +#define PA_TYPEID_SIMPLE PA_TYPEID_MAKE('S', 'M', 'P', 'L') + struct connection { struct pa_protocol_simple *protocol; struct pa_iochannel *io; @@ -308,7 +310,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->playback.fragment_size = 0; pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); - c->client = pa_client_new(p->core, "SIMPLE", cname); + c->client = pa_client_new(p->core, PA_TYPEID_SIMPLE, cname); assert(c->client); c->client->owner = p->module; c->client->kill = client_kill_cb; @@ -323,7 +325,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo goto fail; } - if (!(c->sink_input = pa_sink_input_new(sink, c->client->name, &p->sample_spec, 0, -1))) { + if (!(c->sink_input = pa_sink_input_new(sink, PA_TYPEID_SIMPLE, c->client->name, &p->sample_spec, 0, -1))) { pa_log(__FILE__": Failed to create sink input.\n"); goto fail; } @@ -353,7 +355,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo goto fail; } - c->source_output = pa_source_output_new(source, c->client->name, &p->sample_spec, -1); + c->source_output = pa_source_output_new(source, PA_TYPEID_SIMPLE, c->client->name, &p->sample_spec, -1); if (!c->source_output) { pa_log(__FILE__": Failed to create source output.\n"); goto fail; diff --git a/polyp/random.c b/polyp/random.c new file mode 100644 index 00000000..456954a2 --- /dev/null +++ b/polyp/random.c @@ -0,0 +1,61 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "random.h" +#include "util.h" +#include "log.h" + +#define RANDOM_DEVICE "/dev/urandom" + +void pa_random(void *ret_data, size_t length) { + int fd; + ssize_t r = 0; + assert(ret_data && length); + + if ((fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) { + + if ((r = pa_loop_read(fd, ret_data, length)) < 0 || (size_t) r != length) + pa_log_error(__FILE__": failed to read entropy from '%s'\n", RANDOM_DEVICE); + + close(fd); + } + + if ((size_t) r != length) { + uint8_t *p; + size_t l; + + pa_log_warn(__FILE__": WARNING: Failed to open entropy device '"RANDOM_DEVICE"': %s" + ", falling back to unsecure pseudo RNG.\n", strerror(errno)); + + srandom(time(NULL)); + + for (p = ret_data, l = length; l > 0; p++, l--) + *p = (uint8_t) random(); + } +} diff --git a/polyp/random.h b/polyp/random.h new file mode 100644 index 00000000..bfb3df08 --- /dev/null +++ b/polyp/random.h @@ -0,0 +1,27 @@ +#ifndef foorandomhfoo +#define foorandomhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +void pa_random(void *ret_data, size_t length); + +#endif diff --git a/polyp/sample.c b/polyp/sample.c index b0723f70..51afaa01 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -163,23 +163,23 @@ void pa_bytes_snprint(char *s, size_t l, unsigned v) { enum pa_sample_format pa_parse_sample_format(const char *format) { - if (strcmp(format, "s16le") == 0) + if (strcasecmp(format, "s16le") == 0) return PA_SAMPLE_S16LE; - else if (strcmp(format, "s16be") == 0) + else if (strcasecmp(format, "s16be") == 0) return PA_SAMPLE_S16BE; - else if (strcmp(format, "s16ne") == 0 || strcmp(format, "s16") == 0 || strcmp(format, "16") == 0) + else if (strcasecmp(format, "s16ne") == 0 || strcasecmp(format, "s16") == 0 || strcasecmp(format, "16") == 0) return PA_SAMPLE_S16NE; - else if (strcmp(format, "u8") == 0 || strcmp(format, "8") == 0) + else if (strcasecmp(format, "u8") == 0 || strcasecmp(format, "8") == 0) return PA_SAMPLE_U8; - else if (strcmp(format, "float32") == 0 || strcmp(format, "float32ne") == 0) + else if (strcasecmp(format, "float32") == 0 || strcasecmp(format, "float32ne") == 0) return PA_SAMPLE_FLOAT32; - else if (strcmp(format, "float32le") == 0) + else if (strcasecmp(format, "float32le") == 0) return PA_SAMPLE_FLOAT32LE; - else if (strcmp(format, "float32be") == 0) + else if (strcasecmp(format, "float32be") == 0) return PA_SAMPLE_FLOAT32BE; - else if (strcmp(format, "ulaw") == 0) + else if (strcasecmp(format, "ulaw") == 0) return PA_SAMPLE_ULAW; - else if (strcmp(format, "alaw") == 0) + else if (strcasecmp(format, "alaw") == 0) return PA_SAMPLE_ALAW; return -1; diff --git a/polyp/sample.h b/polyp/sample.h index 59226c46..d4873eb5 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -26,7 +26,7 @@ #include #include -#include "cdecl.h" +#include /** \file * Constants and routines for sample type handling */ @@ -86,7 +86,7 @@ int pa_sample_spec_valid(const struct pa_sample_spec *spec); /** Return non-zero when the two sample type specifications match */ int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b); -/* Return a descriptive string for the specified sample format. \since 0.7.1 */ +/* Return a descriptive string for the specified sample format. \since 0.8 */ const char *pa_sample_format_to_string(enum pa_sample_format f); /** Maximum required string length for pa_sample_spec_snprint() */ diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 347b8f5c..3e7fdf7b 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -36,7 +36,7 @@ #define CONVERT_BUFFER_LENGTH 4096 -struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec, int variable_rate, int resample_method) { +struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int variable_rate, int resample_method) { struct pa_sink_input *i; struct pa_resampler *resampler = NULL; int r; @@ -59,6 +59,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con i->ref = 1; i->state = PA_SINK_INPUT_RUNNING; i->name = pa_xstrdup(name); + i->typeid = typeid; i->client = NULL; i->owner = NULL; i->sink = s; diff --git a/polyp/sink-input.h b/polyp/sink-input.h index 5482369d..83abe537 100644 --- a/polyp/sink-input.h +++ b/polyp/sink-input.h @@ -42,6 +42,7 @@ struct pa_sink_input { enum pa_sink_input_state state; uint32_t index; + pa_typeid_t typeid; char *name; struct pa_module *owner; @@ -64,7 +65,7 @@ struct pa_sink_input { struct pa_resampler *resampler; }; -struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec, int variable_rate, int resample_method); +struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int variable_rate, int resample_method); void pa_sink_input_unref(struct pa_sink_input* i); struct pa_sink_input* pa_sink_input_ref(struct pa_sink_input* i); diff --git a/polyp/sink.c b/polyp/sink.c index 3d20884b..481e5cf7 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -39,7 +39,7 @@ #define MAX_MIX_CHANNELS 32 -struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec) { +struct pa_sink* pa_sink_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec) { struct pa_sink *s; char *n = NULL; char st[256]; @@ -55,6 +55,7 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co s->name = pa_xstrdup(name); s->description = NULL; + s->typeid = typeid; s->ref = 1; s->state = PA_SINK_RUNNING; @@ -65,7 +66,7 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co s->inputs = pa_idxset_new(NULL, NULL); n = pa_sprintf_malloc("%s_monitor", name); - s->monitor_source = pa_source_new(core, n, 0, spec); + s->monitor_source = pa_source_new(core, typeid, n, 0, spec); assert(s->monitor_source); pa_xfree(n); s->monitor_source->monitor_of = s; diff --git a/polyp/sink.h b/polyp/sink.h index 5da4ca43..844af964 100644 --- a/polyp/sink.h +++ b/polyp/sink.h @@ -30,6 +30,7 @@ struct pa_sink; #include "sample.h" #include "idxset.h" #include "source.h" +#include "typeid.h" #define PA_MAX_INPUTS_PER_SINK 6 @@ -43,6 +44,7 @@ struct pa_sink { enum pa_sink_state state; uint32_t index; + pa_typeid_t typeid; char *name, *description; struct pa_module *owner; @@ -59,7 +61,7 @@ struct pa_sink { void *userdata; }; -struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec); +struct pa_sink* pa_sink_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec); void pa_sink_disconnect(struct pa_sink* s); void pa_sink_unref(struct pa_sink*s); struct pa_sink* pa_sink_ref(struct pa_sink *s); diff --git a/polyp/sound-file-stream.c b/polyp/sound-file-stream.c index 43f93230..621c3ed9 100644 --- a/polyp/sound-file-stream.c +++ b/polyp/sound-file-stream.c @@ -36,6 +36,7 @@ #include "log.h" #define BUF_SIZE (1024*10) +#define PA_TYPEID_SOUND_FILE PA_TYPEID_MAKE('S', 'N', 'D', 'F') struct userdata { SNDFILE *sndfile; @@ -160,7 +161,7 @@ int pa_play_file(struct pa_sink *sink, const char *fname, pa_volume_t volume) { goto fail; } - if (!(u->sink_input = pa_sink_input_new(sink, fname, &ss, 0, -1))) + if (!(u->sink_input = pa_sink_input_new(sink, PA_TYPEID_SOUND_FILE, fname, &ss, 0, -1))) goto fail; u->sink_input->volume = volume; diff --git a/polyp/source-output.c b/polyp/source-output.c index 3568fd6f..f954c23f 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -33,7 +33,7 @@ #include "subscribe.h" #include "log.h" -struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec, int resample_method) { +struct pa_source_output* pa_source_output_new(struct pa_source *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int resample_method) { struct pa_source_output *o; struct pa_resampler *resampler = NULL; int r; @@ -56,6 +56,8 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n o->ref = 1; o->state = PA_SOURCE_OUTPUT_RUNNING; o->name = pa_xstrdup(name); + o->typeid = typeid; + o->client = NULL; o->owner = NULL; o->source = s; diff --git a/polyp/source-output.h b/polyp/source-output.h index 0247a09a..f3187aa9 100644 --- a/polyp/source-output.h +++ b/polyp/source-output.h @@ -42,6 +42,7 @@ struct pa_source_output { enum pa_source_output_state state; uint32_t index; + pa_typeid_t typeid; char *name; struct pa_module *owner; @@ -58,7 +59,7 @@ struct pa_source_output { void *userdata; }; -struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec, int resample_method); +struct pa_source_output* pa_source_output_new(struct pa_source *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int resample_method); void pa_source_output_unref(struct pa_source_output* o); struct pa_source_output* pa_source_output_ref(struct pa_source_output *o); diff --git a/polyp/source.c b/polyp/source.c index 7cdb9117..fc73272c 100644 --- a/polyp/source.c +++ b/polyp/source.c @@ -35,7 +35,7 @@ #include "subscribe.h" #include "log.h" -struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec) { +struct pa_source* pa_source_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec) { struct pa_source *s; char st[256]; int r; @@ -53,6 +53,7 @@ struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail s->name = pa_xstrdup(name); s->description = NULL; + s->typeid = typeid; s->owner = NULL; s->core = core; diff --git a/polyp/source.h b/polyp/source.h index 1e6310b0..0fac2b34 100644 --- a/polyp/source.h +++ b/polyp/source.h @@ -31,6 +31,7 @@ struct pa_source; #include "memblock.h" #include "memchunk.h" #include "sink.h" +#include "typeid.h" #define PA_MAX_OUTPUTS_PER_SOURCE 16 @@ -44,6 +45,7 @@ struct pa_source { enum pa_source_state state; uint32_t index; + pa_typeid_t typeid; char *name, *description; struct pa_module *owner; @@ -57,7 +59,7 @@ struct pa_source { void *userdata; }; -struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec); +struct pa_source* pa_source_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec); void pa_source_disconnect(struct pa_source *s); void pa_source_unref(struct pa_source *s); struct pa_source* pa_source_ref(struct pa_source *c); diff --git a/polyp/typeid.c b/polyp/typeid.c new file mode 100644 index 00000000..70d3df33 --- /dev/null +++ b/polyp/typeid.c @@ -0,0 +1,33 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "typeid.h" + +char *pa_typeid_to_string(pa_typeid_t id, char *ret_s, size_t length) { + if (id == PA_TYPEID_UNKNOWN) + snprintf(ret_s, length, "????"); + else + snprintf(ret_s, length, "%c%c%c%c", (char) (id >> 24), (char) (id >> 16), (char) (id >> 8), (char) (id)); + + return ret_s; +} diff --git a/polyp/typeid.h b/polyp/typeid.h new file mode 100644 index 00000000..bd10b2e4 --- /dev/null +++ b/polyp/typeid.h @@ -0,0 +1,40 @@ +#ifndef footypeidhfoo +#define footypeidhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +typedef uint32_t pa_typeid_t; + +#define PA_TYPEID_UNKNOWN ((pa_typeid_t) -1) + +char *pa_typeid_to_string(pa_typeid_t id, char *ret_s, size_t length); + +#define PA_TYPEID_MAKE(a,b,c,d) (\ + (((pa_typeid_t) a & 0xFF) << 24) | \ + (((pa_typeid_t) b & 0xFF) << 16) | \ + (((pa_typeid_t) c & 0xFF) << 8) | \ + (((pa_typeid_t) d & 0xFF))) + +#endif -- cgit From fa48de8a12730029fbc38f8ce7d61563ea5f6dcb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 14 Dec 2004 13:17:28 +0000 Subject: * prepare polyplib-browse for installation git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@321 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- configure.ac | 2 +- polyp/Makefile.am | 5 ++++- polyplib-browse.pc.in | 11 +++++++++++ 4 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 polyplib-browse.pc.in diff --git a/Makefile.am b/Makefile.am index 91f9740b..43e4b58a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,7 +24,7 @@ MAINTAINERCLEANFILES=README noinst_DATA = README pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc +pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc polyplib-browse.pc if HAVE_GLIB20 pkgconfig_DATA += \ diff --git a/configure.ac b/configure.ac index 658910c6..6917921b 100644 --- a/configure.ac +++ b/configure.ac @@ -185,5 +185,5 @@ AM_CONDITIONAL([USE_LYNX], [test "x$lynx" = xyes]) AM_CONDITIONAL(BUILD_LIBPOLYPCORE, false) -AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc polyplib-glib-mainloop.pc polyplib-glib12-mainloop.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf polyp/polyplib-version.h doc/FAQ.html]) +AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-browse.pc polyplib-error.pc polyplib-glib-mainloop.pc polyplib-glib12-mainloop.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf polyp/polyplib-version.h doc/FAQ.html]) AC_OUTPUT diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 70051671..79accfe6 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -74,7 +74,8 @@ polypinclude_HEADERS= \ mainloop.h \ mainloop-signal.h \ sample.h \ - glib-mainloop.h + glib-mainloop.h \ + typeid.h ### Warning! Due to an obscure bug in libtool/automake it is required ### that the libraries in modlib_LTLIBRARIES are specified in-order, @@ -632,6 +633,8 @@ pabrowse_SOURCES = pabrowse.c pabrowse_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-browse-@PA_MAJORMINOR@.la pabrowse_CFLAGS = $(AM_CFLAGS) +polypinclude_HEADERS+=polyplib-browser.h + endif ### GLIB 2.0 support diff --git a/polyplib-browse.pc.in b/polyplib-browse.pc.in new file mode 100644 index 00000000..b77967e0 --- /dev/null +++ b/polyplib-browse.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: polyplib-browse +Description: Polypaudio network browsing API +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lpolyp-browse-@PA_MAJORMINOR@ +Cflags: -D_REENTRANT -I${includedir} +Requires: polyplib-mainloop -- cgit From a370e6e7635d4a0b50c5c884974764c890959a48 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 14 Dec 2004 14:09:00 +0000 Subject: * fix daemonizing git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@322 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/polyp/main.c b/polyp/main.c index f49232d4..43a48f6b 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -34,6 +34,7 @@ #include #include #include +#include #ifdef HAVE_LIBWRAP #include @@ -286,6 +287,11 @@ int main(int argc, char *argv[]) { close(0); close(1); + close(2); + + open("/dev/null", O_RDONLY); + open("/dev/null", O_WRONLY); + open("/dev/null", O_WRONLY); } chdir("/"); -- cgit From bc5b917f93f39215b54593cc45228e97e14daec3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 14 Dec 2004 14:20:52 +0000 Subject: do mor daemonizing work git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@323 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/main.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/polyp/main.c b/polyp/main.c index 43a48f6b..f033c38e 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef HAVE_LIBWRAP #include @@ -241,6 +242,7 @@ int main(int argc, char *argv[]) { if (conf->daemonize) { pid_t child; + int tty_fd; if (pa_stdio_acquire() < 0) { pa_log(__FILE__": failed to acquire stdio.\n"); @@ -292,6 +294,15 @@ int main(int argc, char *argv[]) { open("/dev/null", O_RDONLY); open("/dev/null", O_WRONLY); open("/dev/null", O_WRONLY); + + signal(SIGTTOU, SIG_IGN); + signal(SIGTTIN, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + + if ((tty_fd = open("/dev/tty", O_RDWR)) >= 0) { + ioctl(tty_fd, TIOCNOTTY, (char*) 0); + close(tty_fd); + } } chdir("/"); -- cgit From 99e0779b51ccf4482dd35e78fe2f80744633004e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Dec 2004 01:02:50 +0000 Subject: * Publish server info in mDNS in addition to sinks/sources * Split off address parser * Add port= argument to module-zeroconf-publish git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@324 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 10 +++- polyp/module-zeroconf-publish.c | 61 ++++++++++++++++++++-- polyp/parseaddr.c | 112 ++++++++++++++++++++++++++++++++++++++++ polyp/parseaddr.h | 42 +++++++++++++++ polyp/polyplib-browser.c | 1 - polyp/socket-client.c | 108 ++++++++------------------------------ polyp/util.c | 2 +- 7 files changed, 242 insertions(+), 94 deletions(-) create mode 100644 polyp/parseaddr.c create mode 100644 polyp/parseaddr.h diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 79accfe6..0c491ce5 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -87,6 +87,7 @@ modlib_LTLIBRARIES= \ libiochannel.la \ libsocket-server.la \ libsocket-client.la \ + libparseaddr.la \ libpacket.la \ libpstream.la \ liboss-util.la \ @@ -228,7 +229,8 @@ polypaudio_SOURCES = idxset.c idxset.h \ polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL) polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) -polypaudio_LDFLAGS= $(AM_LDFLAGS) -export-dynamic -dlopen force #-static $(foreach f,$(modlib_LTLIBRARIES),-dlpreopen $(f)) +polypaudio_LDFLAGS= $(AM_LDFLAGS) -export-dynamic -dlopen force +#q-static $(foreach f,$(modlib_LTLIBRARIES),-dlpreopen $(f)) libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h libprotocol_simple_la_LDFLAGS = -avoid-version @@ -240,7 +242,10 @@ libsocket_server_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la $(LI libsocket_client_la_SOURCES = socket-client.c socket-client.h libsocket_client_la_LDFLAGS = -avoid-version -libsocket_client_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la +libsocket_client_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la libparseaddr.la + +libparseaddr_la_SOURCES = parseaddr.c parseaddr.h +libparseaddr_la_LDFLAGS = -avoid-version libpstream_la_SOURCES = pstream.c pstream.h libpstream_la_LDFLAGS = -avoid-version @@ -434,6 +439,7 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = polyplib.h \ util.c util.h \ memblock.c memblock.h \ socket-client.c socket-client.h \ + parseaddr.c parseaddr.h \ packet.c packet.h \ queue.c queue.h \ dynarray.c dynarray.h \ diff --git a/polyp/module-zeroconf-publish.c b/polyp/module-zeroconf-publish.c index c88ac766..511ceb47 100644 --- a/polyp/module-zeroconf-publish.c +++ b/polyp/module-zeroconf-publish.c @@ -41,15 +41,22 @@ #include "subscribe.h" #include "dynarray.h" #include "endianmacros.h" +#include "modargs.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Publisher") PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("port=") #define SERVICE_NAME_SINK "_polypaudio-sink._tcp" #define SERVICE_NAME_SOURCE "_polypaudio-source._tcp" #define SERVICE_NAME_SERVER "_polypaudio-server._tcp" +static const char* const valid_modargs[] = { + "port", + NULL +}; + struct service { sw_discovery_oid oid; char *name; @@ -74,6 +81,9 @@ struct userdata { struct pa_hashmap *services; struct pa_dynarray *sink_dynarray, *source_dynarray, *autoload_dynarray; struct pa_subscription *subscription; + + uint16_t port; + sw_discovery_oid server_oid; }; static sw_result publish_reply(sw_discovery discovery, sw_discovery_publish_status status, sw_discovery_oid oid, sw_opaque extra) { @@ -127,7 +137,7 @@ static int publish_service(struct userdata *u, struct service *s) { s->published = 0; } - snprintf(t, sizeof(t), "%s@%s", s->name, pa_get_host_name(hn, sizeof(hn))); + snprintf(t, sizeof(t), "Networked Audio device %s on %s", s->name, pa_get_host_name(hn, sizeof(hn))); if (sw_text_record_init(&txt) != SW_OKAY) { pa_log(__FILE__": sw_text_record_init() failed\n"); @@ -160,7 +170,7 @@ static int publish_service(struct userdata *u, struct service *s) { if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t, s->loaded.type == PA_NAMEREG_SINK ? SERVICE_NAME_SINK : SERVICE_NAME_SOURCE, - NULL, NULL, PA_NATIVE_DEFAULT_PORT, sw_text_record_bytes(txt), sw_text_record_len(txt), + NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt), publish_reply, s, &s->oid) != SW_OKAY) { pa_log(__FILE__": failed to register sink on zeroconf.\n"); goto finish; @@ -171,7 +181,7 @@ static int publish_service(struct userdata *u, struct service *s) { if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t, s->autoload.type == PA_NAMEREG_SINK ? SERVICE_NAME_SINK : SERVICE_NAME_SOURCE, - NULL, NULL, PA_NATIVE_DEFAULT_PORT, sw_text_record_bytes(txt), sw_text_record_len(txt), + NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt), publish_reply, s, &s->oid) != SW_OKAY) { pa_log(__FILE__": failed to register sink on zeroconf.\n"); goto finish; @@ -375,13 +385,28 @@ fail: int pa__init(struct pa_core *c, struct pa_module*m) { struct userdata *u; - uint32_t index; + uint32_t index, port = PA_NATIVE_DEFAULT_PORT; struct pa_sink *sink; struct pa_source *source; struct pa_autoload_entry *autoload; + struct pa_modargs *ma = NULL; + char t[256], hn[256]; + int free_txt = 0; + sw_text_record txt; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments.\n"); + goto fail; + } + + if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port == 0 || port >= 0xFFFF) { + pa_log(__FILE__": invalid port specified.\n"); + goto fail; + } m->userdata = u = pa_xmalloc(sizeof(struct userdata)); u->core = c; + u->port = (uint16_t) port; if (!(u->howl_wrapper = pa_howl_wrapper_get(c))) goto fail; @@ -409,10 +434,38 @@ int pa__init(struct pa_core *c, struct pa_module*m) { if (publish_autoload(u, autoload) < 0) goto fail; + snprintf(t, sizeof(t), "Networked Audio on %s", pa_get_host_name(hn, sizeof(hn))); + + if (sw_text_record_init(&txt) != SW_OKAY) { + pa_log(__FILE__": sw_text_record_init() failed\n"); + goto fail; + } + free_txt = 1; + + txt_record_server_data(u->core, txt); + + if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t, + SERVICE_NAME_SERVER, + NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt), + publish_reply, u, &u->server_oid) != SW_OKAY) { + pa_log(__FILE__": failed to register server on zeroconf.\n"); + goto fail; + } + + sw_text_record_fina(txt); + pa_modargs_free(ma); + return 0; fail: pa__done(c, m); + + if (ma) + pa_modargs_free(ma); + + if (free_txt) + sw_text_record_fina(txt); + return -1; } diff --git a/polyp/parseaddr.c b/polyp/parseaddr.c new file mode 100644 index 00000000..05ed508b --- /dev/null +++ b/polyp/parseaddr.c @@ -0,0 +1,112 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "xmalloc.h" +#include "util.h" +#include "parseaddr.h" + +/* Parse addresses in one of the following forms: + * HOSTNAME + * HOSTNAME:PORT + * [HOSTNAME] + * [HOSTNAME]:PORT + * + * Return a newly allocated string of the hostname and fill in *ret_port if specified */ + +static char *parse_host(const char *s, uint16_t *ret_port) { + assert(s && ret_port); + if (*s == '[') { + char *e; + if (!(e = strchr(s+1, ']'))) + return NULL; + + if (e[1] == ':') + *ret_port = atoi(e+2); + else if (e[1] != 0) + return NULL; + + return pa_xstrndup(s+1, e-s-1); + } else { + char *e; + + if (!(e = strrchr(s, ':'))) + return pa_xstrdup(s); + + *ret_port = atoi(e+1); + return pa_xstrndup(s, e-s); + } +} + +int pa_parse_address(const char *name, struct pa_parsed_address *ret_p) { + const char *p; + assert(name && ret_p); + memset(ret_p, 0, sizeof(struct pa_parsed_address)); + ret_p->type = PA_PARSED_ADDRESS_TCP_AUTO; + + if (*name == '{') { + char hn[256], *pfx; + /* The URL starts with a host specification for detecting local connections */ + + if (!pa_get_host_name(hn, sizeof(hn))) + return -1; + + pfx = pa_sprintf_malloc("{%s}", hn); + if (!pa_startswith(name, pfx)) { + pa_xfree(pfx); + /* Not local */ + return -1; + } + + p = name + strlen(pfx); + pa_xfree(pfx); + } else + p = name; + + if (*p == '/') + ret_p->type = PA_PARSED_ADDRESS_UNIX; + else if (pa_startswith(p, "unix:")) { + ret_p->type = PA_PARSED_ADDRESS_UNIX; + p += sizeof("unix:")-1; + } else if (pa_startswith(p, "tcp:") || pa_startswith(p, "tcp4:")) { + ret_p->type = PA_PARSED_ADDRESS_TCP4; + p += sizeof("tcp:")-1; + } else if (pa_startswith(p, "tcp6:")) { + ret_p->type = PA_PARSED_ADDRESS_TCP6; + p += sizeof("tcp6:")-1; + } + + if (ret_p->type == PA_PARSED_ADDRESS_UNIX) + ret_p->path_or_host = pa_xstrdup(p); + else + if (!(ret_p->path_or_host = parse_host(p, &ret_p->port))) + return -1; + + + return 0; +} diff --git a/polyp/parseaddr.h b/polyp/parseaddr.h new file mode 100644 index 00000000..5ddc0351 --- /dev/null +++ b/polyp/parseaddr.h @@ -0,0 +1,42 @@ +#ifndef fooparseaddrhfoo +#define fooparseaddrhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +enum pa_parsed_address_type { + PA_PARSED_ADDRESS_UNIX, + PA_PARSED_ADDRESS_TCP4, + PA_PARSED_ADDRESS_TCP6, + PA_PARSED_ADDRESS_TCP_AUTO +}; + +struct pa_parsed_address { + enum pa_parsed_address_type type; + char *path_or_host; + uint16_t port; +}; + +int pa_parse_address(const char *a, struct pa_parsed_address *ret_p); + +#endif diff --git a/polyp/polyplib-browser.c b/polyp/polyplib-browser.c index a1bd3fb7..7e56e2ce 100644 --- a/polyp/polyplib-browser.c +++ b/polyp/polyplib-browser.c @@ -221,7 +221,6 @@ static sw_result browse_reply( switch (status) { case SW_DISCOVERY_BROWSE_ADD_SERVICE: { sw_discovery_oid oid; - fprintf(stderr, "debug: new service: %s\n", name); if (sw_discovery_resolve(b->discovery, 0, name, type, domain, resolve_reply, b, &oid) != SW_OKAY) pa_log("sw_discovery_resolve() failed\n"); diff --git a/polyp/socket-client.c b/polyp/socket-client.c index c58c7bd4..0581e553 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -39,6 +39,7 @@ #include "util.h" #include "xmalloc.h" #include "log.h" +#include "parseaddr.h" struct pa_socket_client { int ref; @@ -254,121 +255,56 @@ struct pa_socket_client* pa_socket_client_new_ipv6(struct pa_mainloop_api *m, ui return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); } -/* Parse addresses in one of the following forms: - * HOSTNAME - * HOSTNAME:PORT - * [HOSTNAME] - * [HOSTNAME]:PORT - * - * Return a newly allocated string of the hostname and fill in *port if specified */ - -static char *parse_address(const char *s, uint16_t *port) { - assert(s && port); - if (*s == '[') { - char *e; - if (!(e = strchr(s+1, ']'))) - return NULL; - - if (e[1] == ':') - *port = atoi(e+2); - else if (e[1] != 0) - return NULL; - - return pa_xstrndup(s+1, e-s-1); - } else { - char *e; - - if (!(e = strrchr(s, ':'))) - return pa_xstrdup(s); - - *port = atoi(e+1); - return pa_xstrndup(s, e-s); - } -} - struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, const char*name, uint16_t default_port) { - const char *p; struct pa_socket_client *c = NULL; - enum { KIND_UNIX, KIND_TCP_AUTO, KIND_TCP4, KIND_TCP6 } kind = KIND_TCP_AUTO; + struct pa_parsed_address a; assert(m && name); - if (*name == '{') { - char hn[256], *pfx; - /* The URL starts with a host specification for detecting local connections */ - - if (!pa_get_host_name(hn, sizeof(hn))) - return NULL; - - pfx = pa_sprintf_malloc("{%s}", hn); - if (!pa_startswith(name, pfx)) - /* Not local */ - return NULL; - - p = name + strlen(pfx); - } else - p = name; - - if (*p == '/') - kind = KIND_UNIX; - else if (pa_startswith(p, "unix:")) { - kind = KIND_UNIX; - p += sizeof("unix:")-1; - } else if (pa_startswith(p, "tcp:") || pa_startswith(p, "tcp4:")) { - kind = KIND_TCP4; - p += sizeof("tcp:")-1; - } else if (pa_startswith(p, "tcp6:")) { - kind = KIND_TCP6; - p += sizeof("tcp6:")-1; - } + if (pa_parse_address(name, &a) < 0) + return NULL; - switch (kind) { - case KIND_UNIX: - return pa_socket_client_new_unix(m, p); + switch (a.type) { + case PA_PARSED_ADDRESS_UNIX: + c = pa_socket_client_new_unix(m, a.path_or_host); + break; - case KIND_TCP_AUTO: /* Fallthrough */ - case KIND_TCP4: - case KIND_TCP6: { - uint16_t port = default_port; - char *h; + case PA_PARSED_ADDRESS_TCP4: /* Fallthrough */ + case PA_PARSED_ADDRESS_TCP6: /* Fallthrough */ + case PA_PARSED_ADDRESS_TCP_AUTO:{ int ret; struct addrinfo hints, *res; - if (!(h = parse_address(p, &port))) - return NULL; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = kind == KIND_TCP4 ? AF_INET : (kind == KIND_TCP6 ? AF_INET6 : AF_UNSPEC); + hints.ai_family = a.type == PA_PARSED_ADDRESS_TCP4 ? AF_INET : (a.type == PA_PARSED_ADDRESS_TCP6 ? AF_INET6 : AF_UNSPEC); - ret = getaddrinfo(h, NULL, &hints, &res); - pa_xfree(h); + ret = getaddrinfo(a.path_or_host, NULL, &hints, &res); if (ret < 0 || !res || !res->ai_addr) - return NULL; + goto finish; if (res->ai_family == AF_INET) { if (res->ai_addrlen != sizeof(struct sockaddr_in)) - return NULL; + goto finish; assert(res->ai_addr->sa_family == res->ai_family); - ((struct sockaddr_in*) res->ai_addr)->sin_port = htons(port); + ((struct sockaddr_in*) res->ai_addr)->sin_port = htons(a.port); } else if (res->ai_family == AF_INET6) { if (res->ai_addrlen != sizeof(struct sockaddr_in6)) - return NULL; + goto finish; assert(res->ai_addr->sa_family == res->ai_family); - ((struct sockaddr_in6*) res->ai_addr)->sin6_port = htons(port); + ((struct sockaddr_in6*) res->ai_addr)->sin6_port = htons(a.port); } else - return NULL; + goto finish; c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); - return c; } } - /* Should never be reached */ - assert(0); - return NULL; +finish: + pa_xfree(a.path_or_host); + return c; } diff --git a/polyp/util.c b/polyp/util.c index ff1aebf3..ee3fa87d 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -880,7 +880,7 @@ int pa_atoi(const char *s, int32_t *ret_i) { l = strtol(s, &x, 0); - if (x || *x) + if (!x || *x) return -1; *ret_i = (int32_t) l; -- cgit From 400dacd66fd6ee60c6394eb9334840b7cd10bc69 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Dec 2004 01:04:13 +0000 Subject: cleanup zeroconf service names git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@325 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-zeroconf-publish.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/polyp/module-zeroconf-publish.c b/polyp/module-zeroconf-publish.c index 511ceb47..56696aea 100644 --- a/polyp/module-zeroconf-publish.c +++ b/polyp/module-zeroconf-publish.c @@ -137,7 +137,7 @@ static int publish_service(struct userdata *u, struct service *s) { s->published = 0; } - snprintf(t, sizeof(t), "Networked Audio device %s on %s", s->name, pa_get_host_name(hn, sizeof(hn))); + snprintf(t, sizeof(t), "Networked Audio Device %s on %s", s->name, pa_get_host_name(hn, sizeof(hn))); if (sw_text_record_init(&txt) != SW_OKAY) { pa_log(__FILE__": sw_text_record_init() failed\n"); @@ -434,7 +434,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { if (publish_autoload(u, autoload) < 0) goto fail; - snprintf(t, sizeof(t), "Networked Audio on %s", pa_get_host_name(hn, sizeof(hn))); + snprintf(t, sizeof(t), "Networked Audio Server on %s", pa_get_host_name(hn, sizeof(hn))); if (sw_text_record_init(&txt) != SW_OKAY) { pa_log(__FILE__": sw_text_record_init() failed\n"); -- cgit From b1369d29079bee2c8d96ad698da9ec43f569c0e5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Dec 2004 01:17:04 +0000 Subject: * fix error message when starting polypaudio while it is already running git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@326 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/polyp/main.c b/polyp/main.c index f033c38e..c5b3a7e8 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -271,7 +271,7 @@ int main(int argc, char *argv[]) { } if (retval) - pa_log(__FILE__": daemon startup failed .\n"); + pa_log(__FILE__": daemon startup failed.\n"); else pa_log_info(__FILE__": daemon startup successful.\n"); @@ -308,8 +308,10 @@ int main(int argc, char *argv[]) { chdir("/"); if (conf->use_pid_file) { - if (pa_pid_file_create() < 0) + if (pa_pid_file_create() < 0) { + pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); goto finish; + } valid_pid_file = 1; } -- cgit From 47ab6bd2fc21c22d98605a18e49a94857eb1e4b3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Dec 2004 20:08:50 +0000 Subject: gcc 2.95 compat git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@327 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-zeroconf-publish.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polyp/module-zeroconf-publish.c b/polyp/module-zeroconf-publish.c index 56696aea..a7e2073e 100644 --- a/polyp/module-zeroconf-publish.c +++ b/polyp/module-zeroconf-publish.c @@ -121,12 +121,12 @@ static void txt_record_server_data(struct pa_core *c, sw_text_record t) { } static int publish_service(struct userdata *u, struct service *s) { - assert(u && s); char t[256]; char hn[256]; int r = -1; sw_text_record txt; int free_txt = 0; + assert(u && s); if ((s->published == 1 && s->loaded.valid) || (s->published == 2 && s->autoload.valid && !s->loaded.valid)) -- cgit From 8199925cec93c9e7908f9afa9d18718623af13ee Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 18 Dec 2004 20:45:46 +0000 Subject: fix conditional X11 compilation git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@328 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 6917921b..dda1f4c6 100644 --- a/configure.ac +++ b/configure.ac @@ -57,7 +57,9 @@ HAVE_X11=0 test "x$no_x" != "xyes" && HAVE_X11=1 AC_SUBST(HAVE_X11) AM_CONDITIONAL(HAVE_X11, test "x$no_x" != "xyes") -AC_DEFINE([HAVE_X11], [], [Have X11]) +if test "x$no_x" != "xyes" ; then + AC_DEFINE([HAVE_X11], 1, [Have X11]) +fi # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST -- cgit From fb11e45cfd84290985e5a3c6f4c7a25fb1eab83c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 6 Jan 2005 01:07:43 +0000 Subject: minor fixes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@329 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/client-conf-x11.c | 11 +++++------ polyp/pax11publish.c | 21 ++++++++++----------- polyp/polyplib-context.c | 18 +++++++++++++----- polyp/protocol-esound.c | 3 ++- polyp/socket-client.c | 3 +++ 5 files changed, 33 insertions(+), 23 deletions(-) diff --git a/polyp/client-conf-x11.c b/polyp/client-conf-x11.c index eb471033..383aa64e 100644 --- a/polyp/client-conf-x11.c +++ b/polyp/client-conf-x11.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-13071 USA. ***/ @@ -48,11 +48,10 @@ int pa_client_conf_from_x11(struct pa_client_conf *c, const char *dname) { goto finish; } - if (!pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) - goto finish; - - pa_xfree(c->default_server); - c->default_server = pa_xstrdup(t); + if (pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) { + pa_xfree(c->default_server); + c->default_server = pa_xstrdup(t); + } if (pa_x11_get_prop(d, "POLYP_SINK", t, sizeof(t))) { pa_xfree(c->default_sink); diff --git a/polyp/pax11publish.c b/polyp/pax11publish.c index 206ab1cb..a1cb006a 100644 --- a/polyp/pax11publish.c +++ b/polyp/pax11publish.c @@ -96,10 +96,8 @@ int main(int argc, char *argv[]) { switch (mode) { case DUMP: { char t[1024]; - if (!pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) - goto finish; - - printf("Server: %s\n", t); + if (pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) + printf("Server: %s\n", t); if (pa_x11_get_prop(d, "POLYP_SOURCE", t, sizeof(t))) printf("Source: %s\n", t); if (pa_x11_get_prop(d, "POLYP_SINK", t, sizeof(t))) @@ -112,11 +110,8 @@ int main(int argc, char *argv[]) { case IMPORT: { char t[1024]; - if (!pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) - goto finish; - - printf("POLYP_SERVER='%s'\nexport POLYP_SERVER\n", t); - + if (pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) + printf("POLYP_SERVER='%s'\nexport POLYP_SERVER\n", t); if (pa_x11_get_prop(d, "POLYP_SOURCE", t, sizeof(t))) printf("POLYP_SOURCE='%s'\nexport POLYP_SOURCE\n", t); if (pa_x11_get_prop(d, "POLYP_SINK", t, sizeof(t))) @@ -155,10 +150,14 @@ int main(int argc, char *argv[]) { goto finish; } + pa_x11_del_prop(d, "POLYP_SERVER"); + pa_x11_del_prop(d, "POLYP_SINK"); + pa_x11_del_prop(d, "POLYP_SOURCE"); pa_x11_del_prop(d, "POLYP_ID"); - + pa_x11_del_prop(d, "POLYP_COOKIE"); + if (server) - pa_x11_set_prop(d, "POLYP_SERVER", c->default_server); + pa_x11_set_prop(d, "POLYP_SERVER", server); else if (c->default_server) pa_x11_set_prop(d, "POLYP_SERVER", c->default_server); else { diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 517fcbeb..e7ccda3e 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -512,7 +512,7 @@ static int try_next_connection(struct pa_context *c) { pa_xfree(c->server); c->server = pa_xstrdup(u); - + if (!(c->client = pa_socket_client_new_string(c->mainloop, u, PA_NATIVE_DEFAULT_PORT))) continue; @@ -564,7 +564,6 @@ int pa_context_connect(struct pa_context *c, const char *server, int spawn, cons if (!server) server = c->conf->default_server; - pa_context_ref(c); assert(!c->server_list); @@ -580,14 +579,23 @@ int pa_context_connect(struct pa_context *c, const char *server, int spawn, cons /* Prepend in reverse order */ - if ((d = getenv("DISPLAY"))) - c->server_list = pa_strlist_prepend(c->server_list, d); + if ((d = getenv("DISPLAY"))) { + char *e; + d = pa_xstrdup(d); + if ((e = strchr(d, ':'))) + *e = 0; + + if (*d) + c->server_list = pa_strlist_prepend(c->server_list, d); + + pa_xfree(d); + } c->server_list = pa_strlist_prepend(c->server_list, "tcp6:localhost"); c->server_list = pa_strlist_prepend(c->server_list, "localhost"); c->server_list = pa_strlist_prepend(c->server_list, pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET, ufn, sizeof(ufn))); - /* Wrap the connection attempts in a single transaction for sane autospwan locking */ + /* Wrap the connection attempts in a single transaction for sane autospawn locking */ if (spawn && c->conf->autospawn) { char lf[PATH_MAX]; diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index d9ed66b9..744ad4ed 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -714,7 +714,8 @@ static int do_read(struct connection *c) { assert(c->read_data_length < sizeof(c->request)); if ((r = pa_iochannel_read(c->io, ((uint8_t*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { - pa_log(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + if (r != 0) + pa_log_warn(__FILE__": read() failed: %s\n", strerror(errno)); return -1; } diff --git a/polyp/socket-client.c b/polyp/socket-client.c index 0581e553..4ec42dab 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -263,6 +263,9 @@ struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, if (pa_parse_address(name, &a) < 0) return NULL; + if (!a.port) + a.port = default_port; + switch (a.type) { case PA_PARSED_ADDRESS_UNIX: c = pa_socket_client_new_unix(m, a.path_or_host); -- cgit From 9b0ec37fcf11805da9511704e976557f4a3a57d2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 8 Jan 2005 01:15:11 +0000 Subject: * add support for asynchronous name resolution * remove directories listing from doxygen git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@330 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 10 ++++ doxygen/doxygen.conf.in | 3 + polyp/Makefile.am | 8 +++ polyp/socket-client.c | 142 ++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 135 insertions(+), 28 deletions(-) diff --git a/configure.ac b/configure.ac index dda1f4c6..e287f279 100644 --- a/configure.ac +++ b/configure.ac @@ -133,6 +133,16 @@ AC_SUBST(HOWL_LIBS) AC_SUBST(HAVE_HOWL) AM_CONDITIONAL([HAVE_HOWL], [test "x$HAVE_HOWL" = x1]) +PKG_CHECK_MODULES(LIBASYNCNS, [ libasyncns >= 0.1 ], HAVE_LIBASYNCNS=1, HAVE_LIBASYNCNS=0) +AC_SUBST(LIBASYNCNS_CFLAGS) +AC_SUBST(LIBASYNCNS_LIBS) +AC_SUBST(HAVE_LIBASYNCNS) +AM_CONDITIONAL([HAVE_LIBASYNCNS], [test "x$HAVE_LIBASYNCNS" = x1]) + +if test "x$HAVE_LIBASYNCNS" != "x0" ; then + AC_DEFINE([HAVE_LIBASYNCNS], 1, [Have libasyncns?]) +fi + AC_PATH_PROG([M4], [m4 gm4], [no]) if test "x$M4" = xno ; then AC_MSG_ERROR([m4 missing]) diff --git a/doxygen/doxygen.conf.in b/doxygen/doxygen.conf.in index 51b2a113..c0e122ea 100644 --- a/doxygen/doxygen.conf.in +++ b/doxygen/doxygen.conf.in @@ -1151,3 +1151,6 @@ DOT_CLEANUP = YES # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO + +SHOW_DIRECTORIES=NO + diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 0c491ce5..352e6a7a 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -470,6 +470,7 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = polyplib.h \ libpolyp_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) libpolyp_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 +libpolyp_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp_mainloop_@PA_MAJORMINOR@_la_SOURCES = mainloop-api.h mainloop-api.c \ mainloop.c mainloop.h \ @@ -581,6 +582,13 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES += x11prop.c x11prop.h client-conf-x11.c cli endif +### libasyncns stuff + +if HAVE_LIBASYNCNS +libpolyp_@PA_MAJORMINOR@_la_CFLAGS += $(LIBASYNCNS_CFLAGS) +libpolyp_@PA_MAJORMINOR@_la_LIBADD += $(LIBASYNCNS_LIBS) +endif + ### ALSA modules if HAVE_ALSA diff --git a/polyp/socket-client.c b/polyp/socket-client.c index 4ec42dab..8ac04a8b 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -23,6 +23,8 @@ #include #endif +/* #undef HAVE_LIBASYNCNS */ + #include #include #include @@ -33,6 +35,9 @@ #include #include #include +#ifdef HAVE_LIBASYNCNS +#include +#endif #include "socket-client.h" #include "socket-util.h" @@ -50,6 +55,11 @@ struct pa_socket_client { void (*callback)(struct pa_socket_client*c, struct pa_iochannel *io, void *userdata); void *userdata; int local; +#ifdef HAVE_LIBASYNCNS + asyncns_t *asyncns; + asyncns_query_t * asyncns_query; + struct pa_io_event *asyncns_io_event; +#endif }; static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) { @@ -65,6 +75,13 @@ static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) { c->callback = NULL; c->userdata = NULL; c->local = 0; + +#ifdef HAVE_LIBASYNCNS + c->asyncns = NULL; + c->asyncns_io_event = NULL; + c->asyncns_query = NULL; +#endif + return c; } @@ -75,6 +92,9 @@ static void do_call(struct pa_socket_client *c) { assert(c && c->callback); pa_socket_client_ref(c); + + if (c->fd < 0) + goto finish; lerror = sizeof(error); if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &error, &lerror) < 0) { @@ -97,7 +117,7 @@ static void do_call(struct pa_socket_client *c) { assert(io); finish: - if (!io) + if (!io && c->fd >= 0) close(c->fd); c->fd = -1; @@ -169,12 +189,11 @@ struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, co return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); } -struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) { - struct pa_socket_client *c; - assert(m && sa); - c = pa_socket_client_new(m); +static int sockaddr_prepare(struct pa_socket_client *c, const struct sockaddr *sa, size_t salen) { assert(c); - + assert(sa); + assert(salen); + switch (sa->sa_family) { case AF_UNIX: c->local = 1; @@ -194,7 +213,7 @@ struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) { pa_log(__FILE__": socket(): %s\n", strerror(errno)); - goto fail; + return -1; } pa_fd_set_cloexec(c->fd, 1); @@ -204,6 +223,18 @@ struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m pa_socket_low_delay(c->fd); if (do_connect(c, sa, salen) < 0) + return -1; + + return 0; +} + +struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) { + struct pa_socket_client *c; + assert(m && sa); + c = pa_socket_client_new(m); + assert(c); + + if (sockaddr_prepare(c, sa, salen) < 0) goto fail; return c; @@ -222,6 +253,16 @@ void socket_client_free(struct pa_socket_client *c) { c->mainloop->defer_free(c->defer_event); if (c->fd >= 0) close(c->fd); + +#ifdef HAVE_LIBASYNCNS + if (c->asyncns_query) + asyncns_cancel(c->asyncns, c->asyncns_query); + if (c->asyncns) + asyncns_free(c->asyncns); + if (c->asyncns_io_event) + c->mainloop->io_free(c->asyncns_io_event); +#endif + pa_xfree(c); } @@ -255,6 +296,40 @@ struct pa_socket_client* pa_socket_client_new_ipv6(struct pa_mainloop_api *m, ui return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); } +#ifdef HAVE_LIBASYNCNS + +static void asyncns_cb(struct pa_mainloop_api*m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { + struct pa_socket_client *c = userdata; + struct addrinfo *res = NULL; + int ret; + assert(m && c && c->asyncns_io_event == e && fd >= 0); + + if (asyncns_wait(c->asyncns, 0) < 0) + goto finish; + + if (!asyncns_isdone(c->asyncns, c->asyncns_query)) + return; + + ret = asyncns_getaddrinfo_done(c->asyncns, c->asyncns_query, &res); + c->asyncns_query = NULL; + + if (ret != 0 || !res) + goto finish; + + if (res->ai_addr) + sockaddr_prepare(c, res->ai_addr, res->ai_addrlen); + + asyncns_freeaddrinfo(res); + +finish: + + m->io_free(c->asyncns_io_event); + c->asyncns_io_event = NULL; + do_call(c); +} + +#endif + struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, const char*name, uint16_t default_port) { struct pa_socket_client *c = NULL; struct pa_parsed_address a; @@ -274,34 +349,45 @@ struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, case PA_PARSED_ADDRESS_TCP4: /* Fallthrough */ case PA_PARSED_ADDRESS_TCP6: /* Fallthrough */ case PA_PARSED_ADDRESS_TCP_AUTO:{ - int ret; - struct addrinfo hints, *res; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = a.type == PA_PARSED_ADDRESS_TCP4 ? AF_INET : (a.type == PA_PARSED_ADDRESS_TCP6 ? AF_INET6 : AF_UNSPEC); - - ret = getaddrinfo(a.path_or_host, NULL, &hints, &res); + struct addrinfo hints; + char port[12]; - if (ret < 0 || !res || !res->ai_addr) - goto finish; + snprintf(port, sizeof(port), "%u", (unsigned) a.port); - if (res->ai_family == AF_INET) { - if (res->ai_addrlen != sizeof(struct sockaddr_in)) - goto finish; - assert(res->ai_addr->sa_family == res->ai_family); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = a.type == PA_PARSED_ADDRESS_TCP4 ? PF_INET : (a.type == PA_PARSED_ADDRESS_TCP6 ? PF_INET6 : PF_UNSPEC); + hints.ai_socktype = SOCK_STREAM; + +#ifdef HAVE_LIBASYNCNS + { + asyncns_t *asyncns; - ((struct sockaddr_in*) res->ai_addr)->sin_port = htons(a.port); - } else if (res->ai_family == AF_INET6) { - if (res->ai_addrlen != sizeof(struct sockaddr_in6)) + if (!(asyncns = asyncns_new(1))) goto finish; - assert(res->ai_addr->sa_family == res->ai_family); + + c = pa_socket_client_new(m); + c->asyncns = asyncns; + c->asyncns_io_event = m->io_new(m, asyncns_fd(c->asyncns), PA_IO_EVENT_INPUT, asyncns_cb, c); + c->asyncns_query = asyncns_getaddrinfo(c->asyncns, a.path_or_host, port, &hints); + assert(c->asyncns_query); + } +#else + { + int ret; + struct addrinfo *res = NULL; + + ret = getaddrinfo(a.path_or_host, port, &hints, &res); - ((struct sockaddr_in6*) res->ai_addr)->sin6_port = htons(a.port); - } else - goto finish; + if (ret < 0 || !res) + goto finish; - c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen); - freeaddrinfo(res); + if (res->ai_addr) + c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen); + + freeaddrinfo(res); + } +#endif } } -- cgit From 9a59d016ddcf17ab6ce450b1e142fe357213413a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 8 Jan 2005 01:16:41 +0000 Subject: update todo list git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@331 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/todo b/doc/todo index efaeb332..16383ea9 100644 --- a/doc/todo +++ b/doc/todo @@ -11,7 +11,7 @@ Fixes: - improve module-oss-mmap latency measurement - module-tunnel: improve latency calculation - make alsa modules use mmap -- event more commenting +- even more commenting Features: - add radio module @@ -20,6 +20,8 @@ Features: - rendezvous - polish for starting polypaudio as root/system-wide instance - export connection fd +- lirc plugin +- /dev/input/event plugin Long term: - pass meta info for hearing impaired -- cgit From 1e78a1dd02e5b2f9c1b439fdc3c51753adbcb36c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 8 Jan 2005 01:19:34 +0000 Subject: change doxygen build stuff for better compat with moderm automakes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@332 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- doxygen/Makefile.am | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Makefile.am b/Makefile.am index 43e4b58a..7935321d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -53,6 +53,6 @@ distcleancheck: @: doxygen: - $(MAKE) -C doxygen + $(MAKE) -C doxygen doxygen .PHONY: homepage distcleancheck doxygen diff --git a/doxygen/Makefile.am b/doxygen/Makefile.am index 9ea724d0..79354b21 100644 --- a/doxygen/Makefile.am +++ b/doxygen/Makefile.am @@ -17,12 +17,10 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -noinst_DATA=html - -html: doxygen.conf +doxygen: doxygen.conf doxygen $< clean-local: rm -rf html -.PHONY: all html +.PHONY: all doxygen -- cgit From fb4cba436c691ebadb24068977643674fb8c143e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 8 Jan 2005 21:36:53 +0000 Subject: * add new module for LIRC volume control git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@333 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 7 ++ polyp/Makefile.am | 20 ++++- polyp/module-lirc.c | 221 +++++++++++++++++++++++++++++++++++++++++++++++++++ polyp/module-match.c | 6 +- polyp/module-oss.c | 1 - 5 files changed, 248 insertions(+), 7 deletions(-) create mode 100644 polyp/module-lirc.c diff --git a/configure.ac b/configure.ac index e287f279..644c4050 100644 --- a/configure.ac +++ b/configure.ac @@ -167,6 +167,13 @@ AC_MSG_RESULT(yes)], AC_SUBST(LIBWRAP_LIBS) LIBS="$saved_LIBS" +HAVE_LIRC=1 +AC_CHECK_HEADER(lirc/lirc_client.h,[AC_CHECK_LIB(lirc_client,lirc_init,,HAVE_LIRC=0)],HAVE_LIRC=0) +LIRC_LIBS=-llirc_client +AC_SUBST(LIRC_CFLAGS) +AC_SUBST(LIRC_LIBS) +AM_CONDITIONAL([HAVE_LIRC], [test "x$HAVE_LIRC" = x1]) + # If using GCC specify some additional parameters if test "x$GCC" = "xyes" ; then CFLAGS="$CFLAGS -pipe -W -Wall -pedantic" diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 352e6a7a..95a80ec1 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -159,7 +159,8 @@ SYMDEF_FILES= \ module-tunnel-source-symdef.h \ module-null-sink-symdef.h \ module-esound-sink-symdef.h \ - module-zeroconf-publish-symdef.h + module-zeroconf-publish-symdef.h \ + module-lirc-symdef.h EXTRA_DIST+=$(SYMDEF_FILES) BUILT_SOURCES+=$(SYMDEF_FILES) @@ -242,7 +243,8 @@ libsocket_server_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la $(LI libsocket_client_la_SOURCES = socket-client.c socket-client.h libsocket_client_la_LDFLAGS = -avoid-version -libsocket_client_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la libparseaddr.la +libsocket_client_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la libparseaddr.la $(LIBASYNCNS_LIBS) +libsocket_client_la_CFLAGS = $(AM_CFLAGS) $(LIBASYNCNS_CFLAGS) libparseaddr_la_SOURCES = parseaddr.c parseaddr.h libparseaddr_la_LDFLAGS = -avoid-version @@ -691,6 +693,20 @@ mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-main endif +### LIRC support + +if HAVE_LIRC + +modlib_LTLIBRARIES+= \ + module-lirc.la + +module_lirc_la_SOURCES = module-lirc.c +module_lirc_la_LDFLAGS = -module -avoid-version +module_lirc_la_LIBADD = $(AM_LIBADD) $(LIRC_LIBS) +module_lirc_la_CFLAGS = $(AM_CFLAGS) $(LIRC_CFLAGS) + +endif + ### libpolypcore (needs to be updated) if BUILD_LIBPOLYPCORE diff --git a/polyp/module-lirc.c b/polyp/module-lirc.c new file mode 100644 index 00000000..a68b5b99 --- /dev/null +++ b/polyp/module-lirc.c @@ -0,0 +1,221 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "module.h" +#include "iochannel.h" +#include "log.h" +#include "module-lirc-symdef.h" +#include "namereg.h" +#include "sink.h" +#include "xmalloc.h" +#include "modargs.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("LIRC volume control") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("config= sink=") + +static const char* const valid_modargs[] = { + "config", + "sink", + NULL, +}; + +struct userdata { + int lirc_fd; + struct pa_io_event *io; + struct lirc_config *config; + char *sink_name; + struct pa_module *module; + float mute_toggle_save; +}; + +static int lirc_in_use = 0; + +static void io_callback(struct pa_mainloop_api *io, struct pa_io_event *e, int fd, enum pa_io_event_flags events, void*userdata) { + struct userdata *u = userdata; + char *name = NULL, *code = NULL; + assert(io); + assert(u); + + if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { + pa_log(__FILE__": lost connection to LIRC daemon.\n"); + goto fail; + } + + if (events & PA_IO_EVENT_INPUT) { + char *c; + + if (lirc_nextcode(&code) != 0 || !code) { + pa_log(__FILE__": lirc_nextcode() failed.\n"); + goto fail; + } + + c = pa_xstrdup(code); + c[strcspn(c, "\n\r")] = 0; + pa_log_debug(__FILE__": raw IR code '%s'\n", c); + pa_xfree(c); + + while (lirc_code2char(u->config, code, &name) == 0 && name) { + enum { INVALID, UP, DOWN, MUTE, RESET, MUTE_TOGGLE } volchange = INVALID; + + pa_log_info(__FILE__": translated IR code '%s'\n", name); + + if (strcasecmp(name, "volume-up") == 0) + volchange = UP; + else if (strcasecmp(name, "volume-down") == 0) + volchange = DOWN; + else if (strcasecmp(name, "mute") == 0) + volchange = MUTE; + else if (strcasecmp(name, "mute-toggle") == 0) + volchange = MUTE_TOGGLE; + else if (strcasecmp(name, "reset") == 0) + volchange = RESET; + + if (volchange == INVALID) + pa_log_warn(__FILE__": recieved unknown IR code '%s'\n", name); + else { + struct pa_sink *s; + + if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) + pa_log(__FILE__": failed to get sink '%s'\n", u->sink_name); + else { + double v = pa_volume_to_user(s->volume); + + switch (volchange) { + case UP: v += .05; break; + case DOWN: v -= .05; break; + case MUTE: v = 0; break; + case RESET: v = 1; break; + case MUTE_TOGGLE: { + + if (v > 0) { + u->mute_toggle_save = v; + v = 0; + } else + v = u->mute_toggle_save; + } + default: + ; + } + + pa_sink_set_volume(s, pa_volume_from_user(v)); + } + } + } + } + + free(code); + + return; + +fail: + u->module->core->mainloop->io_free(u->io); + u->io = NULL; + + pa_module_unload_request(u->module); + + free(code); +} + +int pa__init(struct pa_core *c, struct pa_module*m) { + struct pa_modargs *ma = NULL; + struct userdata *u; + assert(c && m); + + if (lirc_in_use) { + pa_log(__FILE__": module-lirc may no be loaded twice.\n"); + return -1; + } + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": Failed to parse module arguments\n"); + goto fail; + } + + m->userdata = u = pa_xmalloc(sizeof(struct userdata)); + u->module = m; + u->io = NULL; + u->config = NULL; + u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); + u->lirc_fd = -1; + u->mute_toggle_save = 0; + + if ((u->lirc_fd = lirc_init("polypaudio", 1)) < 0) { + pa_log(__FILE__": lirc_init() failed.\n"); + goto fail; + } + + if (lirc_readconfig((char*) pa_modargs_get_value(ma, "config", NULL), &u->config, NULL) < 0) { + pa_log(__FILE__": lirc_readconfig() failed.\n"); + goto fail; + } + + u->io = c->mainloop->io_new(c->mainloop, u->lirc_fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u); + + lirc_in_use = 1; + + pa_modargs_free(ma); + + return 0; + +fail: + + if (ma) + pa_modargs_free(ma); + + pa__done(c, m); + return -1; +} + +void pa__done(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + assert(c); + assert(m); + + if (!(u = m->userdata)) + return; + + if (u->io) + m->core->mainloop->io_free(u->io); + + if (u->config) + lirc_freeconfig(u->config); + + if (u->lirc_fd >= 0) + lirc_deinit(); + + pa_xfree(u->sink_name); + pa_xfree(u); + + lirc_in_use = 0; +} diff --git a/polyp/module-match.c b/polyp/module-match.c index 9d969b31..3599a830 100644 --- a/polyp/module-match.c +++ b/polyp/module-match.c @@ -179,12 +179,10 @@ static void callback(struct pa_core *c, enum pa_subscription_event_type t, uint3 int pa__init(struct pa_core *c, struct pa_module*m) { struct pa_modargs *ma = NULL; - const char *table_file; struct userdata *u; assert(c && m); - if (!(ma = pa_modargs_new(m->argument, valid_modargs)) || - !(table_file = pa_modargs_get_value(ma, "table", NULL))) { + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": Failed to parse module arguments\n"); goto fail; } @@ -194,7 +192,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { u->subscription = NULL; m->userdata = u; - if (load_rules(u, table_file) < 0) + if (load_rules(u, pa_modargs_get_value(ma, "table", NULL)) < 0) goto fail; u->subscription = pa_subscription_new(c, PA_SUBSCRIPTION_MASK_SINK_INPUT, callback, u); diff --git a/polyp/module-oss.c b/polyp/module-oss.c index 67922d82..02acc6f4 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -295,7 +295,6 @@ int pa__init(struct pa_core *c, struct pa_module*m) { pa_log_info(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); - if (nfrags >= 2 && frag_size >= 1) if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) goto fail; -- cgit From c29c95d0aac40c6720fb27d77c60051e420a9d87 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 8 Jan 2005 21:40:25 +0000 Subject: * make lirc program name configurable git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@334 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-lirc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/polyp/module-lirc.c b/polyp/module-lirc.c index a68b5b99..485f570c 100644 --- a/polyp/module-lirc.c +++ b/polyp/module-lirc.c @@ -42,11 +42,12 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("LIRC volume control") PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("config= sink=") +PA_MODULE_USAGE("config= sink= appname=") static const char* const valid_modargs[] = { "config", "sink", + "appname", NULL, }; @@ -170,7 +171,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { u->lirc_fd = -1; u->mute_toggle_save = 0; - if ((u->lirc_fd = lirc_init("polypaudio", 1)) < 0) { + if ((u->lirc_fd = lirc_init(pa_modargs_get_value(ma, "appname", "polypaudio"), 1)) < 0) { pa_log(__FILE__": lirc_init() failed.\n"); goto fail; } -- cgit From 6911d7e981c9314ea62ec5fe5adf6bec1d4f7f4f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 8 Jan 2005 21:43:30 +0000 Subject: * increase timeout in pacmd git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@335 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/pacmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/polyp/pacmd.c b/polyp/pacmd.c index 741059ce..d69c14d7 100644 --- a/polyp/pacmd.c +++ b/polyp/pacmd.c @@ -75,11 +75,11 @@ int main() { goto fail; } - pa_msleep(10); + pa_msleep(50); } if (i >= 5) { - pa_log(__FILE__": daemon to responding.\n"); + pa_log(__FILE__": daemon not responding.\n"); goto fail; } -- cgit From 474b5683e957471d060ee030e5c19a6f6d73a1a2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 8 Jan 2005 22:32:53 +0000 Subject: * todo update * lirc warning fix * c++ compat git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@336 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 5 ++--- polyp/module-lirc.c | 2 +- polyp/pactl.c | 10 +++++----- polyp/polyplib-introspect.c | 10 +++++----- polyp/polyplib-introspect.h | 10 +++++----- polyp/typeid.h | 6 ++++++ 6 files changed, 24 insertions(+), 19 deletions(-) diff --git a/doc/todo b/doc/todo index 16383ea9..3292342a 100644 --- a/doc/todo +++ b/doc/todo @@ -16,11 +16,10 @@ Fixes: Features: - add radio module - xmlrpc/http -- dbus -- rendezvous +- dbus/hal +- rendezvous autotunnel module - polish for starting polypaudio as root/system-wide instance - export connection fd -- lirc plugin - /dev/input/event plugin Long term: diff --git a/polyp/module-lirc.c b/polyp/module-lirc.c index 485f570c..b400be12 100644 --- a/polyp/module-lirc.c +++ b/polyp/module-lirc.c @@ -171,7 +171,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { u->lirc_fd = -1; u->mute_toggle_save = 0; - if ((u->lirc_fd = lirc_init(pa_modargs_get_value(ma, "appname", "polypaudio"), 1)) < 0) { + if ((u->lirc_fd = lirc_init((char*) pa_modargs_get_value(ma, "appname", "polypaudio"), 1)) < 0) { pa_log(__FILE__": lirc_init() failed.\n"); goto fail; } diff --git a/polyp/pactl.c b/polyp/pactl.c index d4dc6ad1..423cce95 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -181,7 +181,7 @@ static void get_sink_info_callback(struct pa_context *c, const struct pa_sink_in "Latency: %0.0f usec\n", i->index, i->name, - pa_typeid_to_string(i->typeid, tid, sizeof(tid)), + pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), i->description, s, i->owner_module, @@ -224,7 +224,7 @@ static void get_source_info_callback(struct pa_context *c, const struct pa_sourc "Monitor of Sink: %s\n" "Latency: %0.0f usec\n", i->index, - pa_typeid_to_string(i->typeid, tid, sizeof(tid)), + pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), i->name, i->description, s, @@ -296,7 +296,7 @@ static void get_client_info_callback(struct pa_context *c, const struct pa_clien "Owner Module: %s\n", i->index, i->name, - pa_typeid_to_string(i->typeid, tid, sizeof(tid)), + pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), i->owner_module != PA_INVALID_INDEX ? t : "n/a"); } @@ -337,7 +337,7 @@ static void get_sink_input_info_callback(struct pa_context *c, const struct pa_s "Resample method: %s\n", i->index, i->name, - pa_typeid_to_string(i->typeid, tid, sizeof(tid)), + pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), i->owner_module != PA_INVALID_INDEX ? t : "n/a", i->client != PA_INVALID_INDEX ? k : "n/a", i->sink, @@ -385,7 +385,7 @@ static void get_source_output_info_callback(struct pa_context *c, const struct p "Resample method: %s\n", i->index, i->name, - pa_typeid_to_string(i->typeid, tid, sizeof(tid)), + pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), i->owner_module != PA_INVALID_INDEX ? t : "n/a", i->client != PA_INVALID_INDEX ? k : "n/a", i->source, diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index 166555c0..5d6d64ab 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -132,7 +132,7 @@ static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t com pa_tagstruct_getu32(t, &i.monitor_source) < 0 || pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || pa_tagstruct_get_usec(t, &i.latency) < 0 || - pa_tagstruct_getu32(t, &i.typeid) < 0) { + pa_tagstruct_getu32(t, &i._typeid) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; @@ -226,7 +226,7 @@ static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t c pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 || pa_tagstruct_get_usec(t, &i.latency) < 0 || - pa_tagstruct_getu32(t, &i.typeid) < 0) { + pa_tagstruct_getu32(t, &i._typeid) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; @@ -315,7 +315,7 @@ static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t c if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.typeid) < 0 ) { + pa_tagstruct_getu32(t, &i._typeid) < 0 ) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } @@ -455,7 +455,7 @@ static void context_get_sink_input_info_callback(struct pa_pdispatch *pd, uint32 pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || pa_tagstruct_gets(t, &i.resample_method) < 0 || - pa_tagstruct_getu32(t, &i.typeid) < 0) { + pa_tagstruct_getu32(t, &i._typeid) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; @@ -528,7 +528,7 @@ static void context_get_source_output_info_callback(struct pa_pdispatch *pd, uin pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || pa_tagstruct_get_usec(t, &i.source_usec) < 0 || pa_tagstruct_gets(t, &i.resample_method) < 0 || - pa_tagstruct_getu32(t, &i.typeid) < 0) { + pa_tagstruct_getu32(t, &i._typeid) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index ba9bde3c..83cdba16 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -58,7 +58,7 @@ struct pa_sink_info { uint32_t monitor_source; /**< Index of the monitor source connected to this sink */ const char *monitor_source_name; /**< The name of the monitor source */ pa_usec_t latency; /**< Length of filled playback buffer of this sink */ - pa_typeid_t typeid; /**< Implementation type. \since 0.8 */ + pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ }; /** Get information about a sink by its name */ @@ -80,7 +80,7 @@ struct pa_source_info { uint32_t monitor_of_sink; /**< If this is a monitor source the index of the owning sink, otherwise PA_INVALID_INDEX */ const char *monitor_of_sink_name; /**< Name of the owning sink, or PA_INVALID_INDEX */ pa_usec_t latency; /**< Length of filled record buffer of this source. \since 0.5 */ - pa_typeid_t typeid; /**< Implementation type. \since 0.8 */ + pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ }; /** Get information about a source by its name */ @@ -127,7 +127,7 @@ struct pa_client_info { uint32_t index; /**< Index of this client */ const char *name; /**< Name of this client */ uint32_t owner_module; /**< Index of the owning module, or PA_INVALID_INDEX */ - pa_typeid_t typeid; /**< Implementation type. \since 0.8 */ + pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ }; /** Get information about a client by its index */ @@ -148,7 +148,7 @@ struct pa_sink_input_info { pa_usec_t buffer_usec; /**< Latency due to buffering in sink input, see pa_latency_info for details */ pa_usec_t sink_usec; /**< Latency of the sink device, see pa_latency_info for details */ const char *resample_method; /**< Thre resampling method used by this sink input. \since 0.7 */ - pa_typeid_t typeid; /**< Implementation type. \since 0.8 */ + pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ }; /** Get some information about a sink input by its index */ @@ -168,7 +168,7 @@ struct pa_source_output_info { pa_usec_t buffer_usec; /**< Latency due to buffering in the source output, see pa_latency_info for details. \since 0.5 */ pa_usec_t source_usec; /**< Latency of the source device, see pa_latency_info for details. \since 0.5 */ const char *resample_method; /**< Thre resampling method used by this source output. \since 0.7 */ - pa_typeid_t typeid; /**< Implementation type. \since 0.8 */ + pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ }; /** Get information about a source output by its index */ diff --git a/polyp/typeid.h b/polyp/typeid.h index bd10b2e4..cc1676bc 100644 --- a/polyp/typeid.h +++ b/polyp/typeid.h @@ -25,6 +25,10 @@ #include #include +#include + +PA_C_DECL_BEGIN + typedef uint32_t pa_typeid_t; #define PA_TYPEID_UNKNOWN ((pa_typeid_t) -1) @@ -37,4 +41,6 @@ char *pa_typeid_to_string(pa_typeid_t id, char *ret_s, size_t length); (((pa_typeid_t) c & 0xFF) << 8) | \ (((pa_typeid_t) d & 0xFF))) +PA_C_DECL_END + #endif -- cgit From 5ab306402d9efcceb3cc7b1097602c45365f12bd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 9 Jan 2005 01:11:53 +0000 Subject: * add new module module-mmkbd-evdev * fix stupid error message in main.c git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@337 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 3 + doc/todo | 2 +- polyp/Makefile.am | 18 +++- polyp/main.c | 3 +- polyp/module-lirc.c | 1 - polyp/module-mmkbd-evdev.c | 225 +++++++++++++++++++++++++++++++++++++++++++++ polyp/pdispatch.c | 2 +- 7 files changed, 249 insertions(+), 5 deletions(-) create mode 100644 polyp/module-mmkbd-evdev.c diff --git a/configure.ac b/configure.ac index 644c4050..1bf49291 100644 --- a/configure.ac +++ b/configure.ac @@ -174,6 +174,9 @@ AC_SUBST(LIRC_CFLAGS) AC_SUBST(LIRC_LIBS) AM_CONDITIONAL([HAVE_LIRC], [test "x$HAVE_LIRC" = x1]) +AC_CHECK_HEADER(linux/input.h,HAVE_EVDEV=1,HAVE_EVDEV=0) +AM_CONDITIONAL([HAVE_EVDEV], [test "x$HAVE_EVDEV" = x1]) + # If using GCC specify some additional parameters if test "x$GCC" = "xyes" ; then CFLAGS="$CFLAGS -pipe -W -Wall -pedantic" diff --git a/doc/todo b/doc/todo index 3292342a..fd024778 100644 --- a/doc/todo +++ b/doc/todo @@ -6,6 +6,7 @@ Architectural changes: - add API for synchronizing multiple sinks/sources to a common clock - absolutely indexed write()s from client - remove "polyplib-" prefix +- hardware volume support Fixes: - improve module-oss-mmap latency measurement @@ -20,7 +21,6 @@ Features: - rendezvous autotunnel module - polish for starting polypaudio as root/system-wide instance - export connection fd -- /dev/input/event plugin Long term: - pass meta info for hearing impaired diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 95a80ec1..72731c1d 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -160,7 +160,8 @@ SYMDEF_FILES= \ module-null-sink-symdef.h \ module-esound-sink-symdef.h \ module-zeroconf-publish-symdef.h \ - module-lirc-symdef.h + module-lirc-symdef.h \ + module-mmkbd-evdev-symdef.h EXTRA_DIST+=$(SYMDEF_FILES) BUILT_SOURCES+=$(SYMDEF_FILES) @@ -707,6 +708,21 @@ module_lirc_la_CFLAGS = $(AM_CFLAGS) $(LIRC_CFLAGS) endif + +### Linux evdev + +if HAVE_EVDEV + +modlib_LTLIBRARIES+= \ + module-mmkbd-evdev.la + +module_mmkbd_evdev_la_SOURCES = module-mmkbd-evdev.c +module_mmkbd_evdev_la_LDFLAGS = -module -avoid-version +module_mmkbd_evdev_la_LIBADD = $(AM_LIBADD) +module_mmkbd_evdev_la_CFLAGS = $(AM_CFLAGS) + +endif + ### libpolypcore (needs to be updated) if BUILD_LIBPOLYPCORE diff --git a/polyp/main.c b/polyp/main.c index c5b3a7e8..51c41439 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -309,7 +309,8 @@ int main(int argc, char *argv[]) { if (conf->use_pid_file) { if (pa_pid_file_create() < 0) { - pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); + if (conf->daemonize) + pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); goto finish; } diff --git a/polyp/module-lirc.c b/polyp/module-lirc.c index b400be12..4cfc09de 100644 --- a/polyp/module-lirc.c +++ b/polyp/module-lirc.c @@ -31,7 +31,6 @@ #include #include "module.h" -#include "iochannel.h" #include "log.h" #include "module-lirc-symdef.h" #include "namereg.h" diff --git a/polyp/module-mmkbd-evdev.c b/polyp/module-mmkbd-evdev.c new file mode 100644 index 00000000..758aaae5 --- /dev/null +++ b/polyp/module-mmkbd-evdev.c @@ -0,0 +1,225 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "module.h" +#include "log.h" +#include "module-mmkbd-evdev-symdef.h" +#include "namereg.h" +#include "sink.h" +#include "xmalloc.h" +#include "modargs.h" +#include "util.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Multimedia keyboard support via Linux evdev") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("device= sink=") + +#define DEFAULT_DEVICE "/dev/input/event0" + +static const char* const valid_modargs[] = { + "device", + "sink", + NULL, +}; + +struct userdata { + int fd; + struct pa_io_event *io; + char *sink_name; + struct pa_module *module; + float mute_toggle_save; +}; + +static void io_callback(struct pa_mainloop_api *io, struct pa_io_event *e, int fd, enum pa_io_event_flags events, void*userdata) { + struct userdata *u = userdata; + assert(io); + assert(u); + + if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { + pa_log(__FILE__": lost connection to evdev device.\n"); + goto fail; + } + + if (events & PA_IO_EVENT_INPUT) { + struct input_event e; + + if (pa_loop_read(u->fd, &e, sizeof(e)) <= 0) { + pa_log(__FILE__": failed to read from event device: %s\n", strerror(errno)); + goto fail; + } + + if (e.type == EV_KEY && (e.value == 1 || e.value == 2)) { + enum { INVALID, UP, DOWN, MUTE_TOGGLE } volchange = INVALID; + + pa_log_debug(__FILE__": key code=%u, value=%u\n", e.code, e.value); + + switch (e.code) { + case KEY_VOLUMEDOWN: volchange = DOWN; break; + case KEY_VOLUMEUP: volchange = UP; break; + case KEY_MUTE: volchange = MUTE_TOGGLE; break; + } + + if (volchange != INVALID) { + struct pa_sink *s; + + if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) + pa_log(__FILE__": failed to get sink '%s'\n", u->sink_name); + else { + double v = pa_volume_to_user(s->volume); + + switch (volchange) { + case UP: v += .05; break; + case DOWN: v -= .05; break; + case MUTE_TOGGLE: { + + if (v > 0) { + u->mute_toggle_save = v; + v = 0; + } else + v = u->mute_toggle_save; + } + default: + ; + } + + pa_sink_set_volume(s, pa_volume_from_user(v)); + } + } + } + } + + return; + +fail: + u->module->core->mainloop->io_free(u->io); + u->io = NULL; + + pa_module_unload_request(u->module); +} + +#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8))) + +int pa__init(struct pa_core *c, struct pa_module*m) { + struct pa_modargs *ma = NULL; + struct userdata *u; + int version; + struct input_id input_id; + char name[256]; + uint8_t evtype_bitmask[EV_MAX/8 + 1]; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": Failed to parse module arguments\n"); + goto fail; + } + + m->userdata = u = pa_xmalloc(sizeof(struct userdata)); + u->module = m; + u->io = NULL; + u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); + u->fd = -1; + u->mute_toggle_save = 0; + + if ((u->fd = open(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), O_RDONLY)) < 0) { + pa_log(__FILE__": failed to open evdev device: %s\n", strerror(errno)); + goto fail; + } + + if (ioctl(u->fd, EVIOCGVERSION, &version) < 0) { + pa_log(__FILE__": EVIOCGVERSION failed: %s\n", strerror(errno)); + goto fail; + } + + pa_log_info(__FILE__": evdev driver version %i.%i.%i\n", version >> 16, (version >> 8) & 0xff, version & 0xff); + + if(ioctl(u->fd, EVIOCGID, &input_id)) { + pa_log(__FILE__": EVIOCGID failed: %s\n", strerror(errno)); + goto fail; + } + + pa_log_info(__FILE__": evdev vendor 0x%04hx product 0x%04hx version 0x%04hx bustype %u\n", + input_id.vendor, input_id.product, input_id.version, input_id.bustype); + + if(ioctl(u->fd, EVIOCGNAME(sizeof(name)), name) < 0) { + pa_log(__FILE__": EVIOCGNAME failed: %s\n", strerror(errno)); + goto fail; + } + + pa_log_info(__FILE__": evdev device name: %s\n", name); + + memset(evtype_bitmask, 0, sizeof(evtype_bitmask)); + if (ioctl(u->fd, EVIOCGBIT(0, EV_MAX), evtype_bitmask) < 0) { + pa_log(__FILE__": EVIOCGBIT failed: %s\n", strerror(errno)); + goto fail; + } + + if (!test_bit(EV_KEY, evtype_bitmask)) { + pa_log(__FILE__": device has no keys.\n"); + goto fail; + } + + u->io = c->mainloop->io_new(c->mainloop, u->fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u); + + pa_modargs_free(ma); + + return 0; + +fail: + + if (ma) + pa_modargs_free(ma); + + pa__done(c, m); + return -1; +} + +void pa__done(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + assert(c); + assert(m); + + if (!(u = m->userdata)) + return; + + if (u->io) + m->core->mainloop->io_free(u->io); + + if (u->fd >= 0) + close(u->fd); + + pa_xfree(u->sink_name); + pa_xfree(u); +} diff --git a/polyp/pdispatch.c b/polyp/pdispatch.c index 90de345f..7a9e9c68 100644 --- a/polyp/pdispatch.c +++ b/polyp/pdispatch.c @@ -33,7 +33,7 @@ #include "llist.h" #include "log.h" -/* #define DEBUG_OPCODES */ +/*#define DEBUG_OPCODES */ #ifdef DEBUG_OPCODES -- cgit From 32bf3a106a946303f2175f01f3124354edd95a3e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 11 Jan 2005 20:47:10 +0000 Subject: * new environment variable $POLYP_LOG * fix connection establishing algorithm * add timeout for establishing connections * add fqdn to the server directive to connect to in browse API * quieten ESOUND protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@338 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/log.c | 8 ++++- polyp/polyplib-browser.c | 8 ++++- polyp/polyplib-context.c | 4 +-- polyp/protocol-esound.c | 9 ++++-- polyp/socket-client.c | 82 ++++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 91 insertions(+), 20 deletions(-) diff --git a/polyp/log.c b/polyp/log.c index 530fa691..78736a47 100644 --- a/polyp/log.c +++ b/polyp/log.c @@ -32,6 +32,8 @@ #include "xmalloc.h" #include "util.h" +#define ENV_LOGLEVEL "POLYP_LOG" + static char *log_ident = NULL; static enum pa_log_target log_target = PA_LOG_STDERR; static void (*user_log_func)(enum pa_log_level l, const char *s) = NULL; @@ -64,11 +66,15 @@ void pa_log_set_target(enum pa_log_target t, void (*func)(enum pa_log_level l, c } void pa_log_levelv(enum pa_log_level level, const char *format, va_list ap) { + const char *e; assert(level < PA_LOG_LEVEL_MAX); + if ((e = getenv(ENV_LOGLEVEL))) + maximal_level = atoi(e); + if (level > maximal_level) return; - + switch (log_target) { case PA_LOG_STDERR: vfprintf(stderr, format, ap); diff --git a/polyp/polyplib-browser.c b/polyp/polyplib-browser.c index 7e56e2ce..2e75a42d 100644 --- a/polyp/polyplib-browser.c +++ b/polyp/polyplib-browser.c @@ -55,7 +55,6 @@ static void io_callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, } } - static sw_result resolve_reply( sw_discovery discovery, sw_discovery_oid oid, @@ -134,9 +133,16 @@ static sw_result resolve_reply( i.user_name = c; c = NULL; } else if (!strcmp(key, "fqdn")) { + size_t l; + pa_xfree((char*) i.fqdn); i.fqdn = c; c = NULL; + + l = strlen(a); + assert(l+1 <= sizeof(a)); + strncat(a, " ", sizeof(a)-l-1); + strncat(a, i.fqdn, sizeof(a)-l-2); } else if (!strcmp(key, "cookie")) { if (pa_atou(c, &cookie) < 0) diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index e7ccda3e..bca7d7ea 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -508,7 +508,7 @@ static int try_next_connection(struct pa_context *c) { goto finish; } -/* pa_log(__FILE__": Trying to connect to %s...\n", u); */ + pa_log_debug(__FILE__": Trying to connect to %s...\n", u); pa_xfree(c->server); c->server = pa_xstrdup(u); @@ -535,7 +535,7 @@ static void on_connection(struct pa_socket_client *client, struct pa_iochannel*i assert(client && c && c->state == PA_CONTEXT_CONNECTING); pa_context_ref(c); - + pa_socket_client_unref(client); c->client = NULL; diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 744ad4ed..d99b721c 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -764,7 +764,8 @@ static int do_read(struct connection *c) { assert(c->read_data && c->read_data_length < handler->data_length); if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { - pa_log(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + if (r != 0) + pa_log_warn(__FILE__": read() failed: %s\n", strerror(errno)); return -1; } @@ -784,7 +785,8 @@ static int do_read(struct connection *c) { assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { - pa_log(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + if (r!= 0) + pa_log_warn(__FILE__": read() failed: %s\n", strerror(errno)); return -1; } @@ -841,7 +843,8 @@ static int do_read(struct connection *c) { } if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { - pa_log(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + if (r != 0) + pa_log(__FILE__": read() failed: %s\n", strerror(errno)); return -1; } diff --git a/polyp/socket-client.c b/polyp/socket-client.c index 8ac04a8b..01f66371 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -46,11 +46,14 @@ #include "log.h" #include "parseaddr.h" +#define CONNECT_TIMEOUT 5 + struct pa_socket_client { int ref; struct pa_mainloop_api *mainloop; int fd; struct pa_io_event *io_event; + struct pa_time_event *timeout_event; struct pa_defer_event *defer_event; void (*callback)(struct pa_socket_client*c, struct pa_iochannel *io, void *userdata); void *userdata; @@ -72,6 +75,7 @@ static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) { c->fd = -1; c->io_event = NULL; c->defer_event = NULL; + c->timeout_event = NULL; c->callback = NULL; c->userdata = NULL; c->local = 0; @@ -85,6 +89,25 @@ static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) { return c; } +static void free_events(struct pa_socket_client *c) { + assert(c); + + if (c->io_event) { + c->mainloop->io_free(c->io_event); + c->io_event = NULL; + } + + if (c->defer_event) { + c->mainloop->defer_free(c->defer_event); + c->defer_event = NULL; + } + + if (c->timeout_event) { + c->mainloop->time_free(c->timeout_event); + c->timeout_event = NULL; + } +} + static void do_call(struct pa_socket_client *c) { struct pa_iochannel *io = NULL; int error; @@ -108,7 +131,7 @@ static void do_call(struct pa_socket_client *c) { } if (error != 0) { -/* pa_log(__FILE__": connect(): %s\n", strerror(error)); */ + pa_log_debug(__FILE__": connect(): %s\n", strerror(error)); errno = error; goto finish; } @@ -120,6 +143,8 @@ finish: if (!io && c->fd >= 0) close(c->fd); c->fd = -1; + + free_events(c); assert(c->callback); c->callback(c, io, c->userdata); @@ -130,16 +155,12 @@ finish: static void connect_fixed_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) { struct pa_socket_client *c = userdata; assert(m && c && c->defer_event == e); - m->defer_free(c->defer_event); - c->defer_event = NULL; do_call(c); } static void connect_io_cb(struct pa_mainloop_api*m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { struct pa_socket_client *c = userdata; assert(m && c && c->io_event == e && fd >= 0); - m->io_free(c->io_event); - c->io_event = NULL; do_call(c); } @@ -247,10 +268,10 @@ fail: void socket_client_free(struct pa_socket_client *c) { assert(c && c->mainloop); - if (c->io_event) - c->mainloop->io_free(c->io_event); - if (c->defer_event) - c->mainloop->defer_free(c->defer_event); + + + free_events(c); + if (c->fd >= 0) close(c->fd); @@ -305,7 +326,7 @@ static void asyncns_cb(struct pa_mainloop_api*m, struct pa_io_event *e, int fd, assert(m && c && c->asyncns_io_event == e && fd >= 0); if (asyncns_wait(c->asyncns, 0) < 0) - goto finish; + goto fail; if (!asyncns_isdone(c->asyncns, c->asyncns_query)) return; @@ -314,22 +335,53 @@ static void asyncns_cb(struct pa_mainloop_api*m, struct pa_io_event *e, int fd, c->asyncns_query = NULL; if (ret != 0 || !res) - goto finish; + goto fail; if (res->ai_addr) sockaddr_prepare(c, res->ai_addr, res->ai_addrlen); asyncns_freeaddrinfo(res); + goto finish; + +fail: + errno == EHOSTUNREACH; + do_call(c); + finish: m->io_free(c->asyncns_io_event); c->asyncns_io_event = NULL; - do_call(c); } #endif +static void timeout_cb(struct pa_mainloop_api *m, struct pa_time_event *e, const struct timeval *tv, void *userdata) { + struct pa_socket_client *c = userdata; + assert(m); + assert(e); + assert(tv); + assert(c); + + if (c->fd >= 0) { + close(c->fd); + c->fd = -1; + } + + errno = ETIMEDOUT; + do_call(c); +} + +static void start_timeout(struct pa_socket_client *c) { + struct timeval tv; + assert(c); + assert(!c->timeout_event); + + gettimeofday(&tv, NULL); + pa_timeval_add(&tv, CONNECT_TIMEOUT * 1000000); + c->timeout_event = c->mainloop->time_new(c->mainloop, &tv, timeout_cb, c); +} + struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, const char*name, uint16_t default_port) { struct pa_socket_client *c = NULL; struct pa_parsed_address a; @@ -344,6 +396,7 @@ struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, switch (a.type) { case PA_PARSED_ADDRESS_UNIX: c = pa_socket_client_new_unix(m, a.path_or_host); + start_timeout(c); break; case PA_PARSED_ADDRESS_TCP4: /* Fallthrough */ @@ -371,6 +424,7 @@ struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, c->asyncns_io_event = m->io_new(m, asyncns_fd(c->asyncns), PA_IO_EVENT_INPUT, asyncns_cb, c); c->asyncns_query = asyncns_getaddrinfo(c->asyncns, a.path_or_host, port, &hints); assert(c->asyncns_query); + start_timeout(c); } #else { @@ -382,8 +436,10 @@ struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, if (ret < 0 || !res) goto finish; - if (res->ai_addr) + if (res->ai_addr) { c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen); + start_timeout(c); + } freeaddrinfo(res); } -- cgit From 4590f09d0b44aeb7cef3eed72b419444ea36d8e0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Jan 2005 17:37:31 +0000 Subject: * make pa_sample_spec_snprint return point to written string * first try of a http module git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@339 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 30 +++++- polyp/caps.c | 3 - polyp/ioline.c | 33 +++++- polyp/ioline.h | 7 ++ polyp/module-protocol-stub.c | 17 +++ polyp/protocol-http.c | 244 +++++++++++++++++++++++++++++++++++++++++++ polyp/protocol-http.h | 35 +++++++ polyp/sample.c | 12 +-- polyp/sample.h | 2 +- polyp/socket-client.c | 9 +- 10 files changed, 374 insertions(+), 18 deletions(-) create mode 100644 polyp/protocol-http.c create mode 100644 polyp/protocol-http.h diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 72731c1d..009707c2 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -103,6 +103,7 @@ modlib_LTLIBRARIES= \ libprotocol-simple.la \ libprotocol-esound.la \ libprotocol-native.la \ + libprotocol-http.la \ module-cli.la \ module-cli-protocol-tcp.la \ module-cli-protocol-tcp6.la \ @@ -129,7 +130,10 @@ modlib_LTLIBRARIES= \ module-tunnel-sink.la \ module-tunnel-source.la \ module-null-sink.la \ - module-esound-sink.la + module-esound-sink.la \ + module-http-protocol-tcp.la \ + module-http-protocol-tcp6.la \ + module-http-protocol-unix.la SYMDEF_FILES= \ module-cli-symdef.h \ @@ -161,7 +165,10 @@ SYMDEF_FILES= \ module-esound-sink-symdef.h \ module-zeroconf-publish-symdef.h \ module-lirc-symdef.h \ - module-mmkbd-evdev-symdef.h + module-mmkbd-evdev-symdef.h \ + module-http-protocol-tcp-symdef.h \ + module-http-protocol-tcp6-symdef.h \ + module-http-protocol-unix-symdef.h EXTRA_DIST+=$(SYMDEF_FILES) BUILT_SOURCES+=$(SYMDEF_FILES) @@ -288,6 +295,10 @@ libprotocol_cli_la_SOURCES = protocol-cli.c protocol-cli.h libprotocol_cli_la_LDFLAGS = -avoid-version libprotocol_cli_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libcli.la +libprotocol_http_la_SOURCES = protocol-http.c protocol-http.h +libprotocol_http_la_LDFLAGS = -avoid-version +libprotocol_http_la_LIBADD = $(AM_LIBADD) libsocket-server.la libioline.la + libprotocol_native_la_SOURCES = protocol-native.c protocol-native.h native-common.h libprotocol_native_la_LDFLAGS = -avoid-version libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libstrlist.la @@ -338,6 +349,21 @@ module_cli_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_CLI $(AM_ module_cli_protocol_unix_la_LDFLAGS = -module -avoid-version module_cli_protocol_unix_la_LIBADD = $(AM_LIBADD) libprotocol-cli.la libsocket-server.la libsocket-util.la +module_http_protocol_tcp_la_SOURCES = module-protocol-stub.c +module_http_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_CFLAGS) +module_http_protocol_tcp_la_LDFLAGS = -module -avoid-version +module_http_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-http.la libsocket-server.la + +module_http_protocol_tcp6_la_SOURCES = module-protocol-stub.c +module_http_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_CFLAGS) +module_http_protocol_tcp6_la_LDFLAGS = -module -avoid-version +module_http_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libprotocol-http.la libsocket-server.la + +module_http_protocol_unix_la_SOURCES = module-protocol-stub.c +module_http_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_CFLAGS) +module_http_protocol_unix_la_LDFLAGS = -module -avoid-version +module_http_protocol_unix_la_LIBADD = $(AM_LIBADD) libprotocol-http.la libsocket-server.la libsocket-util.la + module_native_protocol_tcp_la_SOURCES = module-protocol-stub.c module_native_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) module_native_protocol_tcp_la_LDFLAGS = -module -avoid-version diff --git a/polyp/caps.c b/polyp/caps.c index 01ed1519..739e7071 100644 --- a/polyp/caps.c +++ b/polyp/caps.c @@ -23,9 +23,6 @@ #include #endif -/* setresuid() is only available on GNU */ -#define _GNU_SOURCE - #include #include #include diff --git a/polyp/ioline.c b/polyp/ioline.c index f52af2db..6f7886da 100644 --- a/polyp/ioline.c +++ b/polyp/ioline.c @@ -51,6 +51,8 @@ struct pa_ioline { void (*callback)(struct pa_ioline*io, const char *s, void *userdata); void *userdata; + + int defer_close; }; static void io_callback(struct pa_iochannel*io, void *userdata); @@ -78,6 +80,8 @@ struct pa_ioline* pa_ioline_new(struct pa_iochannel *io) { l->defer_event = l->mainloop->defer_new(l->mainloop, defer_callback, l); l->mainloop->defer_enable(l->defer_event, 0); + + l->defer_close = 0; pa_iochannel_set_callback(io, io_callback, l); @@ -181,8 +185,10 @@ static void failure(struct pa_ioline *l) { pa_ioline_close(l); - if (l->callback) + if (l->callback) { l->callback(l, NULL, l->userdata); + l->callback = NULL; + } } static void scan_for_lines(struct pa_ioline *l, size_t skip) { @@ -309,6 +315,9 @@ static void do_work(struct pa_ioline *l) { if (!l->dead) do_read(l); + if (l->defer_close && !l->wbuf_valid_length) + failure(l); + pa_ioline_unref(l); } @@ -325,3 +334,25 @@ static void defer_callback(struct pa_mainloop_api*m, struct pa_defer_event*e, vo do_work(l); } + +void pa_ioline_defer_close(struct pa_ioline *l) { + assert(l); + + l->defer_close = 1; + + if (!l->wbuf_valid_length) + l->mainloop->defer_enable(l->defer_event, 1); +} + +void pa_ioline_printf(struct pa_ioline *s, const char *format, ...) { + char *t; + va_list ap; + + + va_start(ap, format); + t = pa_vsprintf_malloc(format, ap); + va_end(ap); + + pa_ioline_puts(s, t); + pa_xfree(t); +} diff --git a/polyp/ioline.h b/polyp/ioline.h index f652dddb..6e9c76d0 100644 --- a/polyp/ioline.h +++ b/polyp/ioline.h @@ -23,6 +23,7 @@ ***/ #include "iochannel.h" +#include "util.h" /* An ioline wraps an iochannel for line based communication. A * callback function is called whenever a new line has been recieved @@ -38,7 +39,13 @@ void pa_ioline_close(struct pa_ioline *l); /* Write a string to the channel */ void pa_ioline_puts(struct pa_ioline *s, const char *c); +/* Write a string to the channel */ +void pa_ioline_printf(struct pa_ioline *s, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); + /* Set the callback function that is called for every recieved line */ void pa_ioline_set_callback(struct pa_ioline*io, void (*callback)(struct pa_ioline*io, const char *s, void *userdata), void *userdata); +/* Make sure to close the ioline object as soon as the send buffer is emptied */ +void pa_ioline_defer_close(struct pa_ioline *io); + #endif diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index 93e576af..be27b8e2 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -85,6 +85,23 @@ #endif PA_MODULE_DESCRIPTION("Command line interface protocol "SOCKET_DESCRIPTION) PA_MODULE_USAGE(SOCKET_USAGE) +#elif defined(USE_PROTOCOL_HTTP) + #include "protocol-http.h" + #define protocol_new pa_protocol_http_new + #define protocol_free pa_protocol_http_free + #define TCPWRAP_SERVICE "polypaudio-http" + #define IPV4_PORT 4714 + #define UNIX_SOCKET "http" + #define MODULE_ARGUMENTS + #ifdef USE_TCP_SOCKETS + #include "module-http-protocol-tcp-symdef.h" + #elif defined(USE_TCP6_SOCKETS) + #include "module-http-protocol-tcp6-symdef.h" + #else + #include "module-http-protocol-unix-symdef.h" + #endif + PA_MODULE_DESCRIPTION("HTTP "SOCKET_DESCRIPTION) + PA_MODULE_USAGE(SOCKET_USAGE) #elif defined(USE_PROTOCOL_NATIVE) #include "protocol-native.h" #define protocol_new pa_protocol_native_new diff --git a/polyp/protocol-http.c b/polyp/protocol-http.c new file mode 100644 index 00000000..768b7588 --- /dev/null +++ b/polyp/protocol-http.c @@ -0,0 +1,244 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "protocol-http.h" +#include "ioline.h" +#include "xmalloc.h" +#include "log.h" +#include "namereg.h" + +/* Don't allow more than this many concurrent connections */ +#define MAX_CONNECTIONS 10 + +#define internal_server_error(c) http_message((c), 500, "Internal Server Error", NULL) + +#define URL_ROOT "/" +#define URL_CSS "/style.css" + +struct connection { + struct pa_protocol_http *protocol; + struct pa_ioline *line; + enum { REQUEST_LINE, MIME_HEADER, DATA } state; + char *url; +}; + +struct pa_protocol_http { + struct pa_module *module; + struct pa_core *core; + struct pa_socket_server*server; + struct pa_idxset *connections; +}; + +static void http_response(struct connection *c, int code, const char *msg, const char *mime) { + char s[256]; + assert(c); + assert(msg); + assert(mime); + + snprintf(s, sizeof(s), + "HTTP/1.0 %i %s\n" + "Connection: close\n" + "Content-Type: %s\n" + "\n", code, msg, mime); + + pa_ioline_puts(c->line, s); +} + +static void http_message(struct connection *c, int code, const char *msg, const char *text) { + char s[256]; + assert(c); + + http_response(c, code, msg, "text/html"); + + if (!text) + text = msg; + + snprintf(s, sizeof(s), + "%s\n" + "%s\n", + text, text); + + pa_ioline_puts(c->line, s); + pa_ioline_defer_close(c->line); +} + + +static void connection_free(struct connection *c, int del) { + assert(c); + + if (c->url) + pa_xfree(c->url); + + if (del) + pa_idxset_remove_by_data(c->protocol->connections, c, NULL); + pa_ioline_unref(c->line); + pa_xfree(c); +} + +static void line_callback(struct pa_ioline *line, const char *s, void *userdata) { + struct connection *c = userdata; + assert(line); + assert(c); + + if (!s) { + /* EOF */ + connection_free(c, 1); + return; + } + + switch (c->state) { + case REQUEST_LINE: { + if (memcmp(s, "GET ", 4)) + goto fail; + + s +=4; + + c->url = pa_xstrndup(s, strcspn(s, " \r\n\t")); + c->state = MIME_HEADER; + break; + + } + + case MIME_HEADER: { + + /* Ignore MIME headers */ + if (strcspn(s, " \r\n") != 0) + break; + + /* We're done */ + c->state = DATA; + + pa_log("req for %s\n", c->url); + + if (!strcmp(c->url, URL_ROOT)) { + char txt[256]; + http_response(c, 200, "OK", "text/html"); + + pa_ioline_puts(c->line, + ""PACKAGE_NAME" "PACKAGE_VERSION"\n" + "\n"); + + pa_ioline_puts(c->line, + "

    "PACKAGE_NAME" "PACKAGE_VERSION"

    \n" + "

    Server Information

    \n" + ""); + +#define PRINTF_FIELD(a,b) pa_ioline_printf(c->line, "\n",(a),(b)) + + PRINTF_FIELD("User Name:", pa_get_user_name(txt, sizeof(txt))); + PRINTF_FIELD("Fully Qualified Domain Name:", pa_get_fqdn(txt, sizeof(txt))); + PRINTF_FIELD("Default Sample Specification:", pa_sample_spec_snprint(txt, sizeof(txt), &c->protocol->core->default_sample_spec)); + PRINTF_FIELD("Default Sink:", pa_namereg_get_default_sink_name(c->protocol->core)); + PRINTF_FIELD("Default Source:", pa_namereg_get_default_source_name(c->protocol->core)); + pa_ioline_puts(c->line, "
    %s%s
    "); + pa_ioline_puts(c->line, "\n"); + + pa_ioline_defer_close(c->line); + } else if (!strcmp(c->url, URL_CSS)) { + http_response(c, 200, "OK", "text/css"); + + pa_ioline_puts(c->line, + "body { color: black; background-color: white; margin: 0.5cm; }\n" + "a:link, a:visited { color: #900000; }\n" + "p { margin-left: 0.5cm; margin-right: 0.5cm; }\n" + "h1 { color: #00009F; }\n" + "h2 { color: #00009F; }\n" + "ul { margin-left: .5cm; }\n" + "ol { margin-left: .5cm; }\n" + "pre { margin-left: .5cm; background-color: #f0f0f0; padding: 0.4cm;}\n" + ".grey { color: #afafaf; }\n" + "table { margin-left: 1cm; border:1px solid lightgrey; padding: 0.2cm; }\n" + "td { padding-left:10px; padding-right:10px; }\n"); + + pa_ioline_defer_close(c->line); + } else + http_message(c, 404, "Not Found", NULL); + + break; + } + + default: + ; + } + + return; + +fail: + internal_server_error(c); +} + +static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { + struct pa_protocol_http *p = userdata; + struct connection *c; + assert(s && io && p); + + if (pa_idxset_ncontents(p->connections)+1 > MAX_CONNECTIONS) { + pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); + pa_iochannel_free(io); + return; + } + + c = pa_xmalloc(sizeof(struct connection)); + c->protocol = p; + c->line = pa_ioline_new(io); + c->state = REQUEST_LINE; + c->url = NULL; + + pa_ioline_set_callback(c->line, line_callback, c); + pa_idxset_put(p->connections, c, NULL); +} + +struct pa_protocol_http* pa_protocol_http_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { + struct pa_protocol_http* p; + assert(core && server); + + p = pa_xmalloc(sizeof(struct pa_protocol_http)); + p->module = m; + p->core = core; + p->server = server; + p->connections = pa_idxset_new(NULL, NULL); + + pa_socket_server_set_callback(p->server, on_connection, p); + + return p; +} + +static void free_connection(void *p, void *userdata) { + assert(p); + connection_free(p, 0); +} + +void pa_protocol_http_free(struct pa_protocol_http *p) { + assert(p); + + pa_idxset_free(p->connections, free_connection, NULL); + pa_socket_server_unref(p->server); + pa_xfree(p); +} diff --git a/polyp/protocol-http.h b/polyp/protocol-http.h new file mode 100644 index 00000000..3c9b8d76 --- /dev/null +++ b/polyp/protocol-http.h @@ -0,0 +1,35 @@ +#ifndef fooprotocolhttphfoo +#define fooprotocolhttphfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" +#include "socket-server.h" +#include "module.h" +#include "modargs.h" + +struct pa_protocol_http; + +struct pa_protocol_http* pa_protocol_http_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma); +void pa_protocol_http_free(struct pa_protocol_http *n); + +#endif diff --git a/polyp/sample.c b/polyp/sample.c index 51afaa01..f9d0c458 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -101,15 +101,15 @@ const char *pa_sample_format_to_string(enum pa_sample_format f) { return table[f]; } -void pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spec) { +char *pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spec) { assert(s && l && spec); - if (!pa_sample_spec_valid(spec)) { + if (!pa_sample_spec_valid(spec)) snprintf(s, l, "Invalid"); - return; - } - - snprintf(s, l, "%s %uch %uHz", pa_sample_format_to_string(spec->format), spec->channels, spec->rate); + else + snprintf(s, l, "%s %uch %uHz", pa_sample_format_to_string(spec->format), spec->channels, spec->rate); + + return s; } pa_volume_t pa_volume_multiply(pa_volume_t a, pa_volume_t b) { diff --git a/polyp/sample.h b/polyp/sample.h index d4873eb5..0494c7de 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -93,7 +93,7 @@ const char *pa_sample_format_to_string(enum pa_sample_format f); #define PA_SAMPLE_SPEC_SNPRINT_MAX 32 /** Pretty print a sample type specification to a string */ -void pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spec); +char* pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spec); /** Volume specification: 0: silence; < 256: diminished volume; 256: normal volume; > 256 amplified volume */ typedef uint32_t pa_volume_t; diff --git a/polyp/socket-client.c b/polyp/socket-client.c index 01f66371..1bcf82e3 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -395,8 +395,8 @@ struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, switch (a.type) { case PA_PARSED_ADDRESS_UNIX: - c = pa_socket_client_new_unix(m, a.path_or_host); - start_timeout(c); + if ((c = pa_socket_client_new_unix(m, a.path_or_host))) + start_timeout(c); break; case PA_PARSED_ADDRESS_TCP4: /* Fallthrough */ @@ -437,9 +437,8 @@ struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, goto finish; if (res->ai_addr) { - c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen); - start_timeout(c); - } + if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen))) + tart_timeout(c); freeaddrinfo(res); } -- cgit From f586ce084244d60961ebd9b2b4555ecdc499c9f9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Jan 2005 18:51:38 +0000 Subject: * extend HTTP module git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@340 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 +- polyp/cli-text.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ polyp/cli-text.h | 2 ++ polyp/main.c | 45 ++++++--------------------------------------- polyp/protocol-http.c | 41 +++++++++++++++++++++++++++++++---------- 5 files changed, 84 insertions(+), 50 deletions(-) diff --git a/doc/todo b/doc/todo index fd024778..7321396a 100644 --- a/doc/todo +++ b/doc/todo @@ -16,7 +16,7 @@ Fixes: Features: - add radio module -- xmlrpc/http +- xmlrpc - dbus/hal - rendezvous autotunnel module - polish for starting polypaudio as root/system-wide instance diff --git a/polyp/cli-text.c b/polyp/cli-text.c index dd40add2..d4c46dc0 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -37,6 +37,7 @@ #include "sample-util.h" #include "scache.h" #include "autoload.h" +#include "xmalloc.h" char *pa_module_list_to_string(struct pa_core *c) { struct pa_strbuf *s; @@ -306,3 +307,46 @@ char *pa_autoload_list_to_string(struct pa_core *c) { return pa_strbuf_tostring_free(s); } + +char *pa_full_status_string(struct pa_core *c) { + struct pa_strbuf *s; + int i; + + s = pa_strbuf_new(); + + for (i = 0; i < 8; i++) { + char *t = NULL; + + switch (i) { + case 0: + t = pa_sink_list_to_string(c); + break; + case 1: + t = pa_source_list_to_string(c); + break; + case 2: + t = pa_sink_input_list_to_string(c); + break; + case 3: + t = pa_source_output_list_to_string(c); + break; + case 4: + t = pa_client_list_to_string(c); + break; + case 5: + t = pa_module_list_to_string(c); + break; + case 6: + t = pa_scache_list_to_string(c); + break; + case 7: + t = pa_autoload_list_to_string(c); + break; + } + + pa_strbuf_puts(s, t); + pa_xfree(t); + } + + return pa_strbuf_tostring_free(s); +} diff --git a/polyp/cli-text.h b/polyp/cli-text.h index 65607e94..d19dd48c 100644 --- a/polyp/cli-text.h +++ b/polyp/cli-text.h @@ -36,5 +36,7 @@ char *pa_module_list_to_string(struct pa_core *c); char *pa_scache_list_to_string(struct pa_core *c); char *pa_autoload_list_to_string(struct pa_core *c); +char *pa_full_status_string(struct pa_core *c); + #endif diff --git a/polyp/main.c b/polyp/main.c index 51c41439..d6c25b4b 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -71,49 +71,16 @@ static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, switch (sig) { case SIGUSR1: pa_module_load(userdata, "module-cli", NULL); - return; + break; case SIGUSR2: pa_module_load(userdata, "module-cli-protocol-unix", NULL); - return; + break; case SIGHUP: { - int i; - - for (i = 0;; i++) { - char *c; - switch (i) { - case 0: - c = pa_sink_list_to_string(userdata); - break; - case 1: - c = pa_source_list_to_string(userdata); - break; - case 2: - c = pa_sink_input_list_to_string(userdata); - break; - case 3: - c = pa_source_output_list_to_string(userdata); - break; - case 4: - c = pa_client_list_to_string(userdata); - break; - case 5: - c = pa_module_list_to_string(userdata); - break; - case 6: - c = pa_scache_list_to_string(userdata); - break; - case 7: - c = pa_autoload_list_to_string(userdata); - break; - default: - return; - } - pa_log_notice(c); - pa_xfree(c); - } - + char *c = pa_full_status_string(userdata); + pa_log_notice(c); + pa_xfree(c); return; } @@ -122,7 +89,7 @@ static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, default: pa_log_info(__FILE__": Exiting.\n"); m->quit(m, 1); - return; + break; } } diff --git a/polyp/protocol-http.c b/polyp/protocol-http.c index 768b7588..64e6dadf 100644 --- a/polyp/protocol-http.c +++ b/polyp/protocol-http.c @@ -33,6 +33,7 @@ #include "xmalloc.h" #include "log.h" #include "namereg.h" +#include "cli-text.h" /* Don't allow more than this many concurrent connections */ #define MAX_CONNECTIONS 10 @@ -40,7 +41,8 @@ #define internal_server_error(c) http_message((c), 500, "Internal Server Error", NULL) #define URL_ROOT "/" -#define URL_CSS "/style.css" +#define URL_CSS "/style" +#define URL_STATUS "/status" struct connection { struct pa_protocol_http *protocol; @@ -66,6 +68,9 @@ static void http_response(struct connection *c, int code, const char *msg, const "HTTP/1.0 %i %s\n" "Connection: close\n" "Content-Type: %s\n" + "Cache-Control: no-cache\n" + "Expires: 0\n" + "Server: "PACKAGE_NAME"/"PACKAGE_VERSION"\n" "\n", code, msg, mime); pa_ioline_puts(c->line, s); @@ -80,8 +85,10 @@ static void http_message(struct connection *c, int code, const char *msg, const if (!text) text = msg; - snprintf(s, sizeof(s), - "%s\n" + snprintf(s, sizeof(s), + "\n" + "\n" + "%s\n" "%s\n", text, text); @@ -120,7 +127,7 @@ static void line_callback(struct pa_ioline *line, const char *s, void *userdata) s +=4; - c->url = pa_xstrndup(s, strcspn(s, " \r\n\t")); + c->url = pa_xstrndup(s, strcspn(s, " \r\n\t?")); c->state = MIME_HEADER; break; @@ -135,19 +142,20 @@ static void line_callback(struct pa_ioline *line, const char *s, void *userdata) /* We're done */ c->state = DATA; - pa_log("req for %s\n", c->url); + pa_log_info(__FILE__": request for %s\n", c->url); if (!strcmp(c->url, URL_ROOT)) { char txt[256]; http_response(c, 200, "OK", "text/html"); pa_ioline_puts(c->line, - ""PACKAGE_NAME" "PACKAGE_VERSION"\n" - "\n"); + "\n" + "\n" + ""PACKAGE_NAME" "PACKAGE_VERSION"\n" + "\n"); pa_ioline_puts(c->line, "

    "PACKAGE_NAME" "PACKAGE_VERSION"

    \n" - "

    Server Information

    \n" ""); #define PRINTF_FIELD(a,b) pa_ioline_printf(c->line, "\n",(a),(b)) @@ -157,7 +165,11 @@ static void line_callback(struct pa_ioline *line, const char *s, void *userdata) PRINTF_FIELD("Default Sample Specification:", pa_sample_spec_snprint(txt, sizeof(txt), &c->protocol->core->default_sample_spec)); PRINTF_FIELD("Default Sink:", pa_namereg_get_default_sink_name(c->protocol->core)); PRINTF_FIELD("Default Source:", pa_namereg_get_default_source_name(c->protocol->core)); + pa_ioline_puts(c->line, "
    %s%s
    "); + + pa_ioline_puts(c->line, "

    Click here for an extensive server status report.

    "); + pa_ioline_puts(c->line, "\n"); pa_ioline_defer_close(c->line); @@ -177,7 +189,16 @@ static void line_callback(struct pa_ioline *line, const char *s, void *userdata) "table { margin-left: 1cm; border:1px solid lightgrey; padding: 0.2cm; }\n" "td { padding-left:10px; padding-right:10px; }\n"); - pa_ioline_defer_close(c->line); + pa_ioline_defer_close(c->line); + } else if (!strcmp(c->url, URL_STATUS)) { + char *s; + + http_response(c, 200, "OK", "text/plain"); + s = pa_full_status_string(c->protocol->core); + pa_ioline_puts(c->line, s); + pa_xfree(s); + + pa_ioline_defer_close(c->line); } else http_message(c, 404, "Not Found", NULL); @@ -200,7 +221,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo assert(s && io && p); if (pa_idxset_ncontents(p->connections)+1 > MAX_CONNECTIONS) { - pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); + pa_log_warn(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); pa_iochannel_free(io); return; } -- cgit From 4daa0c164920de2f50860e71c1b19de0fd40424d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Jan 2005 20:22:08 +0000 Subject: * fix LIRC configuration git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@341 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 7 ++++--- doc/todo | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 1bf49291..27cfeecd 100644 --- a/configure.ac +++ b/configure.ac @@ -167,9 +167,10 @@ AC_MSG_RESULT(yes)], AC_SUBST(LIBWRAP_LIBS) LIBS="$saved_LIBS" -HAVE_LIRC=1 -AC_CHECK_HEADER(lirc/lirc_client.h,[AC_CHECK_LIB(lirc_client,lirc_init,,HAVE_LIRC=0)],HAVE_LIRC=0) -LIRC_LIBS=-llirc_client +LIRC_CFLAGS= +LIRC_LIBS= +AC_CHECK_HEADER(lirc/lirc_client.h,[AC_CHECK_LIB(lirc_client,lirc_init,[HAVE_LIRC=1 +LIRC_LIBS=-llirc_client],HAVE_LIRC=0)],HAVE_LIRC=0) AC_SUBST(LIRC_CFLAGS) AC_SUBST(LIRC_LIBS) AM_CONDITIONAL([HAVE_LIRC], [test "x$HAVE_LIRC" = x1]) diff --git a/doc/todo b/doc/todo index 7321396a..0da83206 100644 --- a/doc/todo +++ b/doc/todo @@ -3,10 +3,10 @@ Architectural changes: - per-channel volume - channel mapping ("left", "right", "rear", "subwoofer") +- hardware volume support - add API for synchronizing multiple sinks/sources to a common clock - absolutely indexed write()s from client - remove "polyplib-" prefix -- hardware volume support Fixes: - improve module-oss-mmap latency measurement -- cgit From b5f570723c559a95fad1346975b2bb20acc13551 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 15 Sep 2005 23:46:39 +0000 Subject: add libsamplerate/libsndfile CFLAGS git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@345 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 009707c2..389cb0d3 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -22,7 +22,7 @@ polypconfdir=$(sysconfdir)/polypaudio modlibdir=$(libdir)/polypaudio-@PA_MAJORMINOR@ -AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) +AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) AM_CFLAGS+=-DDLSEARCHPATH=\"$(modlibdir)\" AM_CFLAGS+=-DDEFAULT_CONFIG_DIR=\"$(polypconfdir)\" AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\" -- cgit From f1da8ade63568aec84e7f2bc6b92acbd77f5a13c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 15 Sep 2005 23:47:01 +0000 Subject: fix start_timeout() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@346 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/socket-client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/polyp/socket-client.c b/polyp/socket-client.c index 1bcf82e3..21563d35 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -438,7 +438,8 @@ struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, if (res->ai_addr) { if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen))) - tart_timeout(c); + start_timeout(c); + } freeaddrinfo(res); } -- cgit From fda09b92555bcd9b8e3cbd710557c1b0784cd697 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 15 Sep 2005 23:48:09 +0000 Subject: remove esound protocol directory on unload of module-protocol-esound git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@347 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-protocol-stub.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index be27b8e2..15697582 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -240,5 +240,12 @@ finish: void pa__done(struct pa_core *c, struct pa_module*m) { assert(c && m); +#if defined(USE_PROTOCOL_ESOUND) + if (remove (ESD_UNIX_SOCKET_NAME) != 0) + pa_log("%s: Failed to remove %s : %s.\n", __FILE__, ESD_UNIX_SOCKET_NAME, strerror (errno)); + if (remove (ESD_UNIX_SOCKET_DIR) != 0) + pa_log("%s: Failed to remove %s : %s.\n", __FILE__, ESD_UNIX_SOCKET_DIR, strerror (errno)); +#endif + protocol_free(m->userdata); } -- cgit From db4b25d8b2edbafa898b9ca12b8900bda5c0be1e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 15 Sep 2005 23:50:05 +0000 Subject: handle EOF in ioline.c git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@348 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/ioline.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/polyp/ioline.c b/polyp/ioline.c index 6f7886da..f437094d 100644 --- a/polyp/ioline.c +++ b/polyp/ioline.c @@ -262,8 +262,16 @@ static int do_read(struct pa_ioline *l) { assert(len >= READ_SIZE); /* Read some data */ - if ((r = pa_iochannel_read(l->io, l->rbuf+l->rbuf_index+l->rbuf_valid_length, len)) <= 0) { - pa_log(__FILE__": read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); + r = pa_iochannel_read(l->io, l->rbuf+l->rbuf_index+l->rbuf_valid_length, len); + if (r == 0) { + /* Got an EOF, so fake an exit command. */ + l->rbuf_index = 0; + snprintf (l->rbuf, l->rbuf_length, "exit\n"); + r = 5; + pa_ioline_puts(l, "\nExiting.\n"); + do_write(l); + } else if (r < 0) { + pa_log(__FILE__": read() failed: %s\n", strerror(errno)); failure(l); return -1; } -- cgit From b993e33cceac379f9ed882a8f4c34965873178cc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 15 Sep 2005 23:50:33 +0000 Subject: alter alsa periods number git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@349 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-alsa-sink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index 9933d37a..f6826c52 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -192,7 +192,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { } frame_size = pa_frame_size(&ss); - periods = 12; + periods = 8; fragsize = 1024; if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { pa_log(__FILE__": failed to parse buffer metrics\n"); -- cgit From c57cad926c5afea0cabae96183227651e686c633 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Sep 2005 00:00:39 +0000 Subject: bail out if no sink is defined git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@350 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/main.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/polyp/main.c b/polyp/main.c index d6c25b4b..e881821e 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -58,6 +58,7 @@ #include "caps.h" #include "cli-text.h" #include "pid.h" +#include "namereg.h" #ifdef HAVE_LIBWRAP /* Only one instance of these variables */ @@ -332,11 +333,16 @@ int main(int argc, char *argv[]) { c->module_idle_time = conf->module_idle_time; c->scache_idle_time = conf->scache_idle_time; c->resample_method = conf->resample_method; - - pa_log_info(__FILE__": Daemon startup complete.\n"); - if (pa_mainloop_run(mainloop, &retval) < 0) + + if (pa_namereg_get(c, c->default_sink_name, PA_NAMEREG_SINK, 1) == NULL) { + pa_log_error("%s : Fatal error. Default sink name (%s) does not exist in name register.\n", __FILE__, c->default_sink_name); retval = 1; - pa_log_info(__FILE__": Daemon shutdown initiated.\n"); + } else { + pa_log_info(__FILE__": Daemon startup complete.\n"); + if (pa_mainloop_run(mainloop, &retval) < 0) + retval = 1; + pa_log_info(__FILE__": Daemon shutdown initiated.\n"); + } } pa_core_free(c); -- cgit From 6d9dffebaed590706d0fa5a466c90d7ed72e624a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Sep 2005 00:00:59 +0000 Subject: build fix git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@351 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/ioline.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/polyp/ioline.c b/polyp/ioline.c index f437094d..72df6b87 100644 --- a/polyp/ioline.c +++ b/polyp/ioline.c @@ -224,6 +224,8 @@ static void scan_for_lines(struct pa_ioline *l, size_t skip) { l->rbuf_index = l->rbuf_valid_length = 0; } +static int do_write(struct pa_ioline *l); + static int do_read(struct pa_ioline *l) { assert(l && l->ref >= 1); -- cgit From e0d0f1bb3e93690a18cfb8db96e12f5ae11b3320 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Sep 2005 00:01:20 +0000 Subject: git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@352 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/protocol-native.c | 1 + 1 file changed, 1 insertion(+) diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index d5619ef7..7e1a8894 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -594,6 +594,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1); if (!sink) { + pa_log("%s: Can't find a suitable sink.\n", __FILE__); pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } -- cgit From 652e000f9e3b75fb705abf30c0dc447283a64191 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Sep 2005 00:02:10 +0000 Subject: print a nice message when libltdl is missing git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@353 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/configure.ac b/configure.ac index 27cfeecd..12541345 100644 --- a/configure.ac +++ b/configure.ac @@ -46,6 +46,14 @@ AC_LIBTOOL_DLOPEN AC_PROG_LIBTOOL AC_CONFIG_SUBDIRS(libltdl) +if test "x$ac_cv_lib_ltdl_lt_dlinit" = "xno" ; then + AC_MSG_ERROR([[ + + *** Cannot find the libltdl development files. + *** Maybe you need to install the libltdl-dev package. + ]]) +fi + # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h limits.h malloc.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h syslog.h]) -- cgit From 668f3cdcbc02ebb5074a31016f1766bfe4992240 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Sep 2005 00:03:19 +0000 Subject: handle float values in sound files sensibly git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@354 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/sound-file.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/polyp/sound-file.c b/polyp/sound-file.c index 80233da5..f16d326a 100644 --- a/polyp/sound-file.c +++ b/polyp/sound-file.c @@ -52,19 +52,18 @@ int pa_sound_file_load(const char *fname, struct pa_sample_spec *ss, struct pa_m goto finish; } - switch (sfinfo.format & 0xFF) { - case SF_FORMAT_PCM_16: - case SF_FORMAT_PCM_U8: - case SF_FORMAT_ULAW: - case SF_FORMAT_ALAW: - ss->format = PA_SAMPLE_S16NE; - readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_short; - break; + switch (sfinfo.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_FLOAT: - default: + case SF_FORMAT_DOUBLE: + /* Only float and double need a special case. */ ss->format = PA_SAMPLE_FLOAT32NE; readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_float; break; + default: + /* Everything else is cleanly converted to signed 16 bit. */ + ss->format = PA_SAMPLE_S16NE; + readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_short; + break; } ss->rate = sfinfo.samplerate; -- cgit From 48b2a87ed8ef8a40602f4c139432513a49eecf35 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Sep 2005 00:04:29 +0000 Subject: add pa_sound_file_too_big_to_cache() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@355 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/sound-file.c | 37 ++++++++++++++++++++++++++++++++++++- polyp/sound-file.h | 2 ++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/polyp/sound-file.c b/polyp/sound-file.c index f16d326a..326ddd8b 100644 --- a/polyp/sound-file.c +++ b/polyp/sound-file.c @@ -75,7 +75,7 @@ int pa_sound_file_load(const char *fname, struct pa_sample_spec *ss, struct pa_m } if ((l = pa_frame_size(ss)*sfinfo.frames) > MAX_FILE_SIZE) { - pa_log(__FILE__": File to large\n"); + pa_log(__FILE__": File too large\n"); goto finish; } @@ -102,3 +102,38 @@ finish: return ret; } + +int pa_sound_file_too_big_to_cache(const char *fname) { + SNDFILE*sf = NULL; + SF_INFO sfinfo; + struct pa_sample_spec ss; + + if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) { + pa_log(__FILE__": Failed to open file %s\n", fname); + return 0; + } + + sf_close(sf); + + switch (sfinfo.format & SF_FORMAT_SUBMASK) { + case SF_FORMAT_FLOAT: + case SF_FORMAT_DOUBLE: + /* Only float and double need a special case. */ + ss.format = PA_SAMPLE_FLOAT32NE; + break; + default: + /* Everything else is cleanly converted to signed 16 bit. */ + ss.format = PA_SAMPLE_S16NE; + break; + } + + ss.rate = sfinfo.samplerate; + ss.channels = sfinfo.channels; + + if ((pa_frame_size(&ss) * sfinfo.frames) > MAX_FILE_SIZE) { + pa_log(__FILE__": File too large %s\n", fname); + return 1; + } + + return 0; +} diff --git a/polyp/sound-file.h b/polyp/sound-file.h index e5359853..855e6883 100644 --- a/polyp/sound-file.h +++ b/polyp/sound-file.h @@ -27,4 +27,6 @@ int pa_sound_file_load(const char *fname, struct pa_sample_spec *ss, struct pa_memchunk *chunk, struct pa_memblock_stat *s); +int pa_sound_file_too_big_to_cache(const char *fname); + #endif -- cgit From e4395c223deea8803e2408b5ba57f52b4f65030f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Sep 2005 00:08:02 +0000 Subject: add new field running_as_daemon to pa_core git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@356 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/core.h | 2 +- polyp/main.c | 2 ++ polyp/module-cli.c | 11 +++++++++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/polyp/core.h b/polyp/core.h index 36604424..8ef66570 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -59,7 +59,7 @@ struct pa_core { struct pa_memblock_stat *memblock_stat; - int disallow_module_loading; + int disallow_module_loading, running_as_daemon; int exit_idle_time, module_idle_time, scache_idle_time; struct pa_time_event *quit_event; diff --git a/polyp/main.c b/polyp/main.c index e881821e..26fa4a87 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -296,6 +296,8 @@ int main(int argc, char *argv[]) { c = pa_core_new(pa_mainloop_get_api(mainloop)); assert(c); + if (conf->daemonize) + c->running_as_daemon = 1; pa_signal_new(SIGUSR1, signal_callback, c); pa_signal_new(SIGUSR2, signal_callback, c); diff --git a/polyp/module-cli.c b/polyp/module-cli.c index 55fe8ad4..7d278f90 100644 --- a/polyp/module-cli.c +++ b/polyp/module-cli.c @@ -50,6 +50,11 @@ int pa__init(struct pa_core *c, struct pa_module*m) { struct pa_iochannel *io; assert(c && m); + if (c->running_as_daemon) { + pa_log_info(__FILE__": Running as daemon so won't load this module.\n"); + return 0; + } + if (m->argument) { pa_log(__FILE__": module doesn't accept arguments.\n"); return -1; @@ -75,6 +80,8 @@ int pa__init(struct pa_core *c, struct pa_module*m) { void pa__done(struct pa_core *c, struct pa_module*m) { assert(c && m); - pa_cli_free(m->userdata); - pa_stdio_release(); + if (c->running_as_daemon == 0) { + pa_cli_free(m->userdata); + pa_stdio_release(); + } } -- cgit From d50bfd8496c15552b970079bdfcad86cf3cd59b2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Sep 2005 00:08:53 +0000 Subject: increase number of allowed connections git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@357 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/protocol-cli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polyp/protocol-cli.c b/polyp/protocol-cli.c index 7122d23a..107acb19 100644 --- a/polyp/protocol-cli.c +++ b/polyp/protocol-cli.c @@ -32,7 +32,7 @@ #include "log.h" /* Don't allow more than this many concurrent connections */ -#define MAX_CONNECTIONS 10 +#define MAX_CONNECTIONS 25 struct pa_protocol_cli { struct pa_module *module; -- cgit From 3a61b36c9d51b8698d196c91dd16c50d2cbbc48c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Sep 2005 00:09:19 +0000 Subject: initialize running_as_daemon git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@358 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/polyp/core.c b/polyp/core.c index c213faa0..e2bebec2 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -59,6 +59,7 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->scache = NULL; c->autoload_idxset = NULL; c->autoload_hashmap = NULL; + c->running_as_daemon = 0; c->default_sample_spec.format = PA_SAMPLE_S16NE; c->default_sample_spec.rate = 44100; -- cgit From 9177ef4ce22218c02334fa6d3ac9afbeea2913d7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Sep 2005 00:11:15 +0000 Subject: chance ALSA sink to use "default" as default alsa device git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@359 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-alsa-sink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index f6826c52..840fc536 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -71,7 +71,7 @@ static const char* const valid_modargs[] = { }; #define DEFAULT_SINK_NAME "alsa_output" -#define DEFAULT_DEVICE "plughw:0,0" +#define DEFAULT_DEVICE "default" static void update_usage(struct userdata *u) { pa_module_set_used(u->module, -- cgit From 656cf879937440e8764cf9f9429b7b484944dc1e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Sep 2005 00:11:48 +0000 Subject: fix alsa memory leak git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@360 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-alsa-sink.c | 1 + polyp/module-alsa-source.c | 1 + 2 files changed, 2 insertions(+) diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index 840fc536..69db2875 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -204,6 +204,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { m->userdata = u; u->module = m; + snd_config_update_free_global(); if (snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) { pa_log(__FILE__": Error opening PCM device %s\n", dev); goto fail; diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index 67e38a1d..55abe8e0 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -195,6 +195,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { m->userdata = u; u->module = m; + snd_config_update_free_global(); if (snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK) < 0) { pa_log(__FILE__": Error opening PCM device %s\n", dev); goto fail; -- cgit From 794033aa7512f148190cf0ea48b0058dcfe34e32 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 9 Jan 2006 12:37:17 +0000 Subject: fix synchronized clock change git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@425 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/polyplib-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 440217e7..a1a66990 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -414,7 +414,7 @@ static void stream_get_latency_info_callback(struct pa_pdispatch *pd, uint32_t c } else { gettimeofday(&now, NULL); - if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) { + if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now) < 0) { /* local and remote seem to have synchronized clocks */ if (o->stream->direction == PA_STREAM_PLAYBACK) -- cgit From 80ae72ce45dbc23ddc360749924110dcc752491e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 9 Jan 2006 12:38:06 +0000 Subject: improve sync clock change git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@426 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/polyplib-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index a1a66990..6a73c608 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -414,7 +414,7 @@ static void stream_get_latency_info_callback(struct pa_pdispatch *pd, uint32_t c } else { gettimeofday(&now, NULL); - if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now) < 0) { + if (pa_timeval_cmp(&local, &remote) <= 0 && pa_timeval_cmp(&remote, &now) <= 0) { /* local and remote seem to have synchronized clocks */ if (o->stream->direction == PA_STREAM_PLAYBACK) -- cgit From f7a99e90470526bb28cc0c225f96490110094aed Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 10 Jan 2006 17:51:06 +0000 Subject: Merge Pierre's changes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@445 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 18 +- acinclude.m4 | 41 ++ configure.ac | 344 ++++++++--- doc/Makefile.am | 3 +- polyp/Makefile.am | 1350 ++++++++++++++++++++++++------------------ polyp/authkey.c | 10 +- polyp/caps.c | 9 + polyp/cli-command.c | 4 + polyp/client-conf.c | 20 +- polyp/conf-parser.c | 4 + polyp/core.c | 4 +- polyp/cpulimit.c | 20 +- polyp/daemon-conf.c | 20 +- polyp/default.pa.win32 | 43 ++ polyp/dllmain.c | 46 ++ polyp/dumpmodules.c | 6 +- polyp/glib-mainloop.c | 2 +- polyp/glib12-mainloop.c | 2 +- polyp/inet_ntop.c | 80 +++ polyp/inet_ntop.h | 12 + polyp/iochannel.c | 30 +- polyp/log.c | 16 +- polyp/main.c | 111 +++- polyp/mainloop-signal.c | 114 +++- polyp/mainloop-test.c | 2 +- polyp/mainloop.c | 33 +- polyp/mcalign-test.c | 2 +- polyp/module-alsa-sink.c | 5 + polyp/module-alsa-source.c | 5 + polyp/module-combine.c | 4 +- polyp/module-esound-sink.c | 2 +- polyp/module-mmkbd-evdev.c | 13 +- polyp/module-null-sink.c | 2 +- polyp/module-protocol-stub.c | 13 +- polyp/module-solaris.c | 436 ++++++++++++++ polyp/module-tunnel.c | 9 +- polyp/module-waveout.c | 583 ++++++++++++++++++ polyp/module.c | 4 +- polyp/oss-util.c | 2 +- polyp/pacat.c | 4 + polyp/pactl.c | 2 + polyp/paplay.c | 2 + polyp/pdispatch.c | 3 +- polyp/pid.c | 31 +- polyp/poll.c | 190 ++++++ polyp/poll.h | 57 ++ polyp/polyplib-context.c | 27 +- polyp/polyplib-internal.h | 1 + polyp/polyplib-stream.c | 20 +- polyp/protocol-esound.c | 16 +- polyp/protocol-native.c | 6 +- polyp/pstream.c | 5 + polyp/random.c | 18 +- polyp/sample-util.c | 2 +- polyp/sample.h | 8 + polyp/scache.c | 37 +- polyp/socket-client.c | 65 +- polyp/socket-client.h | 3 +- polyp/socket-server.c | 49 +- polyp/socket-util.c | 66 ++- polyp/tagstruct.c | 73 ++- polyp/util.c | 355 +++++++++-- polyp/util.h | 3 + polyp/winsock.h | 23 + polyp/xmalloc.c | 2 + 65 files changed, 3614 insertions(+), 878 deletions(-) create mode 100644 polyp/default.pa.win32 create mode 100644 polyp/dllmain.c create mode 100644 polyp/inet_ntop.c create mode 100644 polyp/inet_ntop.h create mode 100644 polyp/module-solaris.c create mode 100644 polyp/module-waveout.c create mode 100644 polyp/poll.c create mode 100644 polyp/poll.h create mode 100644 polyp/winsock.h diff --git a/Makefile.am b/Makefile.am index 7935321d..2cf93c75 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,11 +17,11 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -EXTRA_DIST = bootstrap.sh README LICENSE doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in libtool.m4 ltdl.m4 -SUBDIRS=polyp doc libltdl +EXTRA_DIST = bootstrap.sh LICENSE doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in libtool.m4 ltdl.m4 +SUBDIRS=libltdl polyp doc -MAINTAINERCLEANFILES=README -noinst_DATA = README +MAINTAINERCLEANFILES = +noinst_DATA = pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc polyplib-browse.pc @@ -36,10 +36,16 @@ pkgconfig_DATA += \ polyplib-glib12-mainloop.pc endif +if USE_LYNX +EXTRA_DIST += README +MAINTAINERCLEANFILES += README +noinst_DATA += README + README: rm -f README $(MAKE) -C doc README cd $(srcdir) && ln -s doc/README README +endif homepage: all dist doxygen test -d $$HOME/homepage/private @@ -49,8 +55,8 @@ homepage: all dist doxygen cp -a doxygen/html/* $$HOME/homepage/private/projects/polypaudio/doxygen cp $$HOME/homepage/private/projects/polypaudio/README.html $$HOME/homepage/private/projects/polypaudio/index.html -distcleancheck: - @: +#distcleancheck: +# @: doxygen: $(MAKE) -C doxygen doxygen diff --git a/acinclude.m4 b/acinclude.m4 index bedf51c3..02f271b4 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -197,3 +197,44 @@ else fi AC_LANG_RESTORE ])dnl ACX_PTHREAD + +AC_DEFUN([AC_CHECK_DEFINE],[ +AS_VAR_PUSHDEF([ac_var],[ac_cv_defined_$1])dnl +AC_CACHE_CHECK([for $1 defined], ac_var, +AC_TRY_COMPILE([#include <$2>],[ + #ifdef $1 + int ok; + #else + choke me + #endif +],AS_VAR_SET(ac_var, yes),AS_VAR_SET(ac_var, no))) +AS_IF([test AS_VAR_GET(ac_var) != "no"], [$3], [$4])dnl +AS_VAR_POPDEF([ac_var])dnl +]) + +AC_DEFUN([ACX_LIBWRAP], [ +LIBWRAP_LIBS= +saved_LIBS="$LIBS" +LIBS="$LIBS -lwrap" +AC_MSG_CHECKING([for tcpwrap library and headers]) +AC_LINK_IFELSE( +AC_LANG_PROGRAM( +[#include +#include +int allow_severity = LOG_INFO; +int deny_severity = LOG_WARNING;], +[struct request_info *req; +return hosts_access (req);]), +[AC_DEFINE(HAVE_LIBWRAP, [], [Have tcpwrap?]) +LIBWRAP_LIBS="-lwrap" +AC_MSG_RESULT(yes)], +[AC_MSG_RESULT(no)]) +LIBS="$saved_LIBS" +]) + +AC_DEFUN([ACX_LIRC], [ +LIRC_CFLAGS= +LIRC_LIBS= +AC_CHECK_HEADER(lirc/lirc_client.h,[AC_CHECK_LIB(lirc_client,lirc_init,[HAVE_LIRC=1 +LIRC_LIBS=-llirc_client],HAVE_LIRC=0)],HAVE_LIRC=0) +]) diff --git a/configure.ac b/configure.ac index 12541345..e5e03d04 100644 --- a/configure.ac +++ b/configure.ac @@ -35,18 +35,60 @@ if type -p stow > /dev/null && test -d /usr/local/stow ; then ac_default_prefix="/usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION}" fi -# Checks for programs. +#### Checks for programs. #### + +# CC + AC_PROG_CC +AC_PROG_GCC_TRADITIONAL + +# If using GCC specify some additional parameters +if test "x$GCC" = "xyes" ; then + CFLAGS="$CFLAGS -pipe -W -Wall -pedantic" + + AC_LANG_CONFTEST([int main() {}]) + $CC -c conftest.c -std=gnu9x -Wno-unused-parameter $CFLAGS > /dev/null 2> /dev/null && CFLAGS="$CFLAGS -std=gnu9x -Wno-unused-parameter" + rm -f conftest.o +fi + +# M4 + +AC_PATH_PROG([M4], [m4 gm4], [no]) +if test "x$M4" = xno ; then + AC_MSG_ERROR([m4 missing]) +fi + +# LYNX documentation generation +AC_ARG_ENABLE(lynx, + AC_HELP_STRING(--disable-lynx,Turn off lynx usage for documentation generation), +[case "${enableval}" in + yes) lynx=yes ;; + no) lynx=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-lynx) ;; +esac],[lynx=yes]) + +if test x$lynx = xyes ; then + AC_CHECK_PROG(have_lynx, lynx, yes, no) + + if test x$have_lynx = xno ; then + AC_MSG_WARN([*** lynx not found, plain text README will not be built ***]) + fi +fi -# libtool stuff +AM_CONDITIONAL([USE_LYNX], [test "x$have_lynx" = xyes]) + +#### libtool stuff #### + +AC_LTDL_ENABLE_INSTALL AC_LIBLTDL_INSTALLABLE AC_SUBST(LTDLINCL) AC_SUBST(LIBLTDL) AC_LIBTOOL_DLOPEN +AC_LIBTOOL_WIN32_DLL AC_PROG_LIBTOOL AC_CONFIG_SUBDIRS(libltdl) -if test "x$ac_cv_lib_ltdl_lt_dlinit" = "xno" ; then +if test "x$enable_ltdl_install" = "xno" && test "x$ac_cv_lib_ltdl_lt_dlinit" = "xno" ; then AC_MSG_ERROR([[ *** Cannot find the libltdl development files. @@ -54,93 +96,211 @@ if test "x$ac_cv_lib_ltdl_lt_dlinit" = "xno" ; then ]]) fi -# Checks for header files. +#### Determine build environment #### + +os_is_win32=0 + +case "$host_os" in + mingw*) + AC_DEFINE([OS_IS_WIN32], 1, [Build target is Windows.]) + os_is_win32=1 + ;; + esac + +AM_CONDITIONAL(OS_IS_WIN32, test "x$os_is_win32" = "x1") + +################################### +# Basic environment checks # +################################### + +#### Checks for header files. #### + +# ISO AC_HEADER_STDC -AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h limits.h malloc.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h syslog.h]) -ACX_PTHREAD -AC_PATH_XTRA +# POSIX +AC_CHECK_HEADERS([arpa/inet.h glob.h grp.h netdb.h netinet/in.h \ + netinet/in_systm.h netinet/ip.h netinet/tcp.h pwd.h sched.h \ + sys/resource.h sys/select.h sys/socket.h sys/wait.h \ + syslog.h]) +AC_CHECK_HEADERS([regex.h], [HAVE_REGEX=1], [HAVE_REGEX=0]) +AC_CHECK_HEADERS([sys/un.h], [HAVE_AF_UNIX=1], [HAVE_AF_UNIX=0]) -HAVE_X11=0 -test "x$no_x" != "xyes" && HAVE_X11=1 -AC_SUBST(HAVE_X11) -AM_CONDITIONAL(HAVE_X11, test "x$no_x" != "xyes") -if test "x$no_x" != "xyes" ; then - AC_DEFINE([HAVE_X11], 1, [Have X11]) -fi +AM_CONDITIONAL(HAVE_REGEX, test "x$HAVE_REGEX" = "x1") +AM_CONDITIONAL(HAVE_AF_UNIX, test "x$HAVE_AF_UNIX" = "x1") + +# XPG4-UNIX +AC_CHECK_HEADERS([sys/poll.h]) + +# Linux +AC_CHECK_HEADERS([linux/input.h], [HAVE_EVDEV=1], [HAVE_EVDEV=0]) + +AM_CONDITIONAL([HAVE_EVDEV], [test "x$HAVE_EVDEV" = "x1"]) + +# Windows +AC_CHECK_HEADERS([windows.h winsock2.h ws2tcpip.h]) + +# Other +AC_CHECK_HEADERS([sys/ioctl.h]) + +#### Typdefs, structures, etc. #### -# Checks for typedefs, structures, and compiler characteristics. AC_C_CONST +AC_C_BIGENDIAN AC_TYPE_PID_T AC_TYPE_SIZE_T +AC_CHECK_TYPES(ssize_t, , [AC_DEFINE([ssize_t], [signed long], + [Define ssize_t if it is not done by the standard libs.])]) AC_TYPE_OFF_T -AC_HEADER_TIME - -# Checks for library functions. -AC_FUNC_FORK -AC_PROG_GCC_TRADITIONAL -AC_FUNC_LSTAT -AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK -AC_FUNC_MALLOC -AC_FUNC_MEMCMP -AC_FUNC_MMAP -AC_FUNC_REALLOC -AC_FUNC_SETPGRP -AC_FUNC_VPRINTF -AC_FUNC_CLOSEDIR_VOID -AC_FUNC_SELECT_ARGTYPES AC_TYPE_SIGNAL AC_TYPE_UID_T -AC_CHECK_FUNCS([gethostname gettimeofday memchr memmove memset mkdir mkfifo munmap rmdir socket strcspn strerror strrchr strspn strstr strtol strtoul strcasecmp putenv strchr strpbrk strdup getgrgid_r getpwuid_r regcomp ftruncate select]) -AC_CHECK_LIB(m, pow) -AC_CHECK_FUNCS(pow) -AC_FUNC_STAT -AC_HEADER_SYS_WAIT -AC_HEADER_DIRENT -AC_C_BIGENDIAN +AC_CHECK_DEFINE([SIGXCPU], [signal.h], [HAVE_SIGXCPU=1], [HAVE_SIGXCPU=0]) +AM_CONDITIONAL(HAVE_SIGXCPU, test "x$HAVE_SIGXCPU" = "x1") + +# Solaris lacks this +AC_CHECK_DEFINE([INADDR_NONE], [netinet/in.h], [], + [AC_DEFINE([INADDR_NONE], [0xffffffff], [Define INADDR_NONE if not found in ])]) + +#### Check for libs #### + +# ISO +AC_CHECK_LIB([m], [pow]) + +# POSIX +AC_CHECK_LIB([rt], [sched_setscheduler]) + +# BSD +AC_CHECK_LIB([socket], [connect]) + +# Non-standard + +# This magic is needed so we do not needlessly add static libs to the win32 +# build, disabling its ability to make dlls. +AC_CHECK_FUNCS([getopt_long], [], [AC_CHECK_LIB([iberty], [getopt_long])]) + +#### Check for functions #### + +# POSIX +AC_FUNC_FORK AC_FUNC_GETGROUPS +AC_FUNC_SELECT_ARGTYPES +AC_CHECK_FUNCS([getaddrinfo getgrgid_r getpwuid_r gettimeofday getuid \ + inet_ntop nanosleep setpgid setsid sigaction sleep]) +AC_CHECK_FUNCS([mkfifo], [HAVE_MKFIFO=1], [HAVE_MKFIFO=0]) -AC_CHECK_LIB(cap, cap_init, [CAP_LIBS='-lcap'], [CAP_LIBS='']) -AC_SUBST(CAP_LIBS) +AM_CONDITIONAL(HAVE_MKFIFO, test "x$HAVE_MKFIFO" = "x1") + +# X/OPEN +AC_CHECK_FUNCS([readlink]) + +# SUSv2 +AC_CHECK_FUNCS([ctime_r usleep]) -AC_CHECK_HEADERS(sys/capability.h) +# BSD +AC_CHECK_FUNCS([lstat]) + +# Non-standard AC_CHECK_FUNCS(setresuid) AC_CHECK_FUNCS(setreuid) +#### POSIX threads #### + +ACX_PTHREAD + +################################### +# External libraries # +################################### + +#### X11 (optional) #### + +HAVE_X11=0 + +# The macro tests the host, not the build target +if test "x$os_is_win32" != "x1" ; then + AC_PATH_XTRA + test "x$no_x" != "xyes" && HAVE_X11=1 +fi + +AC_SUBST(HAVE_X11) +AM_CONDITIONAL(HAVE_X11, test "x$HAVE_X11" = "x1") +if test "x$HAVE_X11" = "x1" ; then + AC_DEFINE([HAVE_X11], 1, [Have X11]) +fi + +#### Capabilities (optional) #### + +CAP_LIBS='' + +AC_ARG_WITH( + [caps], + AC_HELP_STRING([--without-caps],[Omit support for POSIX capabilities.])) + +if test "x${with_caps}" != "xno"; then + AC_CHECK_LIB(cap, cap_init, [CAP_LIBS='-lcap'], [CAP_LIBS='']) + AC_CHECK_HEADERS([sys/capability.h]) +fi +AC_SUBST(CAP_LIBS) + +#### Sample rate conversion #### + PKG_CHECK_MODULES(LIBSAMPLERATE, [ samplerate >= 0.1.0 ]) AC_SUBST(LIBSAMPLERATE_CFLAGS) AC_SUBST(LIBSAMPLERATE_LIBS) +#### Sound file #### + PKG_CHECK_MODULES(LIBSNDFILE, [ sndfile >= 1.0.10 ]) AC_SUBST(LIBSNDFILE_CFLAGS) AC_SUBST(LIBSNDFILE_LIBS) +#### OSS support (optional) #### + +AC_CHECK_HEADERS([sys/soundcard.h], [HAVE_OSS=1], [HAVE_OSS=0]) +AC_SUBST(HAVE_OSS) +AM_CONDITIONAL([HAVE_OSS], [test "x$HAVE_OSS" = x1]) + +#### ALSA support (optional) #### + PKG_CHECK_MODULES(ASOUNDLIB, [ alsa >= 1.0.0 ], [HAVE_ALSA=1], [HAVE_ALSA=0]) AC_SUBST(ASOUNDLIB_CFLAGS) AC_SUBST(ASOUNDLIB_LIBS) AC_SUBST(HAVE_ALSA) AM_CONDITIONAL([HAVE_ALSA], [test "x$HAVE_ALSA" = x1]) +#### Solaris audio support (optional) #### + +AC_CHECK_HEADERS([sys/audio.h], [HAVE_SOLARIS=1], [HAVE_SOLARIS=0]) +AC_SUBST(HAVE_SOLARIS) +AM_CONDITIONAL([HAVE_SOLARIS], [test "x$HAVE_SOLARIS" = x1]) + +#### GLib 2 support (optional) #### + PKG_CHECK_MODULES(GLIB20, [ glib-2.0 >= 2.4.0 ], HAVE_GLIB20=1, HAVE_GLIB20=0) AC_SUBST(GLIB20_CFLAGS) AC_SUBST(GLIB20_LIBS) AC_SUBST(HAVE_GLIB20) AM_CONDITIONAL([HAVE_GLIB20], [test "x$HAVE_GLIB20" = x1]) +#### GLib 1 support (optional) #### + PKG_CHECK_MODULES(GLIB12, [ glib >= 1.2.0 ], HAVE_GLIB12=1, HAVE_GLIB12=0) AC_SUBST(GLIB12_CFLAGS) AC_SUBST(GLIB12_LIBS) AC_SUBST(HAVE_GLIB12) AM_CONDITIONAL([HAVE_GLIB12], [test "x$HAVE_GLIB12" = x1]) +#### Howl support (optional) #### + PKG_CHECK_MODULES(HOWL, [ howl >= 0.9.8 ], HAVE_HOWL=1, HAVE_HOWL=0) AC_SUBST(HOWL_CFLAGS) AC_SUBST(HOWL_LIBS) AC_SUBST(HAVE_HOWL) AM_CONDITIONAL([HAVE_HOWL], [test "x$HAVE_HOWL" = x1]) +#### Async DNS support (optional) #### + PKG_CHECK_MODULES(LIBASYNCNS, [ libasyncns >= 0.1 ], HAVE_LIBASYNCNS=1, HAVE_LIBASYNCNS=0) AC_SUBST(LIBASYNCNS_CFLAGS) AC_SUBST(LIBASYNCNS_LIBS) @@ -151,70 +311,60 @@ if test "x$HAVE_LIBASYNCNS" != "x0" ; then AC_DEFINE([HAVE_LIBASYNCNS], 1, [Have libasyncns?]) fi -AC_PATH_PROG([M4], [m4 gm4], [no]) -if test "x$M4" = xno ; then - AC_MSG_ERROR([m4 missing]) -fi +#### TCP wrappers (optional) #### -AC_MSG_CHECKING([for tcpwrap library and headers]) -LIBWRAP_LIBS= -saved_LIBS="$LIBS" -LIBS="$LIBS -lwrap" -AC_LINK_IFELSE( -AC_LANG_PROGRAM( -[#include -#include -int allow_severity = LOG_INFO; -int deny_severity = LOG_WARNING;], -[struct request_info *req; -return hosts_access (req);]), -[AC_DEFINE(HAVE_LIBWRAP, [], [Have tcpwrap?]) -LIBWRAP_LIBS="-lwrap" -AC_MSG_RESULT(yes)], -[AC_MSG_RESULT(no)]) +ACX_LIBWRAP AC_SUBST(LIBWRAP_LIBS) -LIBS="$saved_LIBS" -LIRC_CFLAGS= -LIRC_LIBS= -AC_CHECK_HEADER(lirc/lirc_client.h,[AC_CHECK_LIB(lirc_client,lirc_init,[HAVE_LIRC=1 -LIRC_LIBS=-llirc_client],HAVE_LIRC=0)],HAVE_LIRC=0) +#### LIRC support (optional) #### + +ACX_LIRC AC_SUBST(LIRC_CFLAGS) AC_SUBST(LIRC_LIBS) AM_CONDITIONAL([HAVE_LIRC], [test "x$HAVE_LIRC" = x1]) -AC_CHECK_HEADER(linux/input.h,HAVE_EVDEV=1,HAVE_EVDEV=0) -AM_CONDITIONAL([HAVE_EVDEV], [test "x$HAVE_EVDEV" = x1]) - -# If using GCC specify some additional parameters -if test "x$GCC" = "xyes" ; then - CFLAGS="$CFLAGS -pipe -W -Wall -pedantic" - - AC_LANG_CONFTEST([int main() {}]) - $CC -c conftest.c -std=c99 -Wno-unused-parameter $CFLAGS > /dev/null 2> /dev/null && CFLAGS="$CFLAGS -std=c99 -Wno-unused-parameter" - rm -f conftest.o +################################### +# Output # +################################### + +AC_ARG_ENABLE( + [static-bins], + AC_HELP_STRING([--enable-static-bins],[Statically link executables.]), + [STATIC_BINS=1], [STATIC_BINS=0]) +AM_CONDITIONAL([STATIC_BINS], [test "x$STATIC_BINS" = "x1"]) + +AC_ARG_WITH( + [preopen-mods], + AC_HELP_STRING([--with-preopen-mods],[Modules to preopen in daemon (default: all).]), + [PREOPEN_MODS=$withval], [PREOPEN_MODS="all"]) +AM_CONDITIONAL([PREOPEN_MODS], [test "x$PREOPEN_MODS" != "xall"]) +if test "x$PREOPEN_MODS" != "xall" ; then + tmpLIBS="" + for mod in $PREOPEN_MODS; do + tmpLIBS="$tmpLIBS module-$mod.la" + done + PREOPEN_MODS="$tmpLIBS" + AC_SUBST(PREOPEN_MODS) fi -# LYNX documentation generation -AC_ARG_ENABLE(lynx, - AC_HELP_STRING(--disable-lynx,Turn off lynx usage for documentation generation), -[case "${enableval}" in - yes) lynx=yes ;; - no) lynx=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --disable-lynx) ;; -esac],[lynx=yes]) - -if test x$lynx = xyes ; then - AC_CHECK_PROG(have_lynx, lynx, yes, no) - - if test x$have_lynx = xno ; then - AC_MSG_WARN([*** lynx not found, plain text README will not be built ***]) - fi -fi - -AM_CONDITIONAL([USE_LYNX], [test "x$lynx" = xyes]) - -AM_CONDITIONAL(BUILD_LIBPOLYPCORE, false) - -AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-browse.pc polyplib-error.pc polyplib-glib-mainloop.pc polyplib-glib12-mainloop.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf polyp/polyplib-version.h doc/FAQ.html]) +AC_CONFIG_FILES([ +Makefile +polyp/Makefile +polyplib.pc +polyplib-simple.pc +polyplib-mainloop.pc +polyplib-browse.pc +polyplib-error.pc +polyplib-glib-mainloop.pc +polyplib-glib12-mainloop.pc +doc/Makefile +doc/README.html +doc/cli.html +doc/daemon.html +doc/modules.html +doxygen/Makefile +doxygen/doxygen.conf +polyp/polyplib-version.h +doc/FAQ.html +]) AC_OUTPUT diff --git a/doc/Makefile.am b/doc/Makefile.am index fff06551..c68c00f5 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -16,7 +16,7 @@ # along with polypaudio; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -noinst_DATA = README.html cli.html modules.html daemon.html README +noinst_DATA = README.html cli.html modules.html daemon.html EXTRA_DIST = $(noinst_DATA) style.css README.html.in cli.html.in modules.html.in daemon.html.in todo FAQ.html.in MAINTAINERCLEANFILES = README.html cli.html modules.html daemon.html FAQ.html @@ -26,6 +26,7 @@ if USE_LYNX README: README.html lynx --dump $^ | sed 's,file://localhost/.*/doc/README.html,README,' > $@ +noinst_DATA += README CLEANFILES += README endif diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 389cb0d3..22e8da3d 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -17,72 +17,483 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. + +################################### +# Extra directories # +################################### + polypincludedir=$(includedir)/polyp polypconfdir=$(sysconfdir)/polypaudio modlibdir=$(libdir)/polypaudio-@PA_MAJORMINOR@ -AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) -AM_CFLAGS+=-DDLSEARCHPATH=\"$(modlibdir)\" -AM_CFLAGS+=-DDEFAULT_CONFIG_DIR=\"$(polypconfdir)\" -AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\" +################################### +# Defines # +################################### + +POLYPAUDIO_BINARY=$(bindir)/polypaudio$(EXEEXT) +if OS_IS_WIN32 +DEFAULT_CONFIG_DIR=%POLYP_ROOT% +else +DEFAULT_CONFIG_DIR=$(polypconfdir) +endif + +################################### +# Compiler/linker flags # +################################### + +AM_CFLAGS = -D_GNU_SOURCE -I$(top_srcdir) +AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS +AM_CFLAGS += $(LTDLINCL) +AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) +AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" +AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\" +AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(POLYPAUDIO_BINARY)\" # This cool debug trap works on i386/gcc only -AM_CFLAGS+='-DDEBUG_TRAP=__asm__("int $$3")' +AM_CFLAGS += '-DDEBUG_TRAP=__asm__("int $$3")' + +AM_LIBADD = $(PTHREAD_LIBS) +AM_LDADD = $(PTHREAD_LIBS) + +# Only required on some platforms but defined for all to avoid errors +AM_LDFLAGS = -no-undefined + +if STATIC_BINS +BINLDFLAGS = -static +endif + +if OS_IS_WIN32 +AM_LDFLAGS+=-Wl,--export-all-symbols +WINSOCK_LIBS=-lwsock32 -lws2_32 -lwininet +endif + +################################### +# Extra files # +################################### + +EXTRA_DIST = \ + client.conf.in \ + daemon.conf.in \ + default.pa.in \ + depmod.py \ + esdcompat.sh.in \ + module-defs.h.m4 + +polypconf_DATA = default.pa daemon.conf client.conf + +BUILT_SOURCES = polyplib-version.h + +################################### +# Main daemon # +################################### + +bin_PROGRAMS = polypaudio + +polypaudio_SOURCES = \ + caps.h caps.c \ + cmdline.c cmdline.h \ + cpulimit.c cpulimit.h \ + conf-parser.h conf-parser.c \ + daemon-conf.c daemon-conf.h \ + dumpmodules.c dumpmodules.h \ + gcc-printf.h \ + main.c \ + pid.c pid.h + +polypaudio_CFLAGS = $(AM_CFLAGS) +polypaudio_CPPFLAGS = $(AM_CPPFLAGS) +polypaudio_LDADD = $(AM_LDADD) libpolypcore.la $(LIBLTDL) \ + $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) +polypaudio_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -dlopen force $(foreach f,$(PREOPEN_LIBS),-dlopen $(f)) + +if PREOPEN_MODS +PREOPEN_LIBS = $(PREOPEN_MODS) +else +PREOPEN_LIBS = $(modlib_LTLIBRARIES) +endif -AM_LIBADD=$(PTHREAD_LIBS) -lm -AM_LDADD=$(PTHREAD_LIBS) -lm +################################### +# Utility programs # +################################### -EXTRA_DIST = default.pa.in daemon.conf.in client.conf.in depmod.py esdcompat.sh.in module-defs.h.m4 -bin_PROGRAMS = \ - polypaudio \ +bin_PROGRAMS += \ pacat \ pactl \ - paplay \ - pacmd + paplay + +if HAVE_AF_UNIX +bin_PROGRAMS += pacmd +endif + +if HAVE_X11 +bin_PROGRAMS += pax11publish +endif + +if HAVE_HOWL +bin_PROGRAMS += pabrowse +endif bin_SCRIPTS = esdcompat.sh +pacat_SOURCES = pacat.c +pacat_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la +pacat_CFLAGS = $(AM_CFLAGS) +pacat_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +paplay_SOURCES = paplay.c +paplay_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) +paplay_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) +paplay_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +pactl_SOURCES = pactl.c +pactl_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) +pactl_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) +pactl_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +pacmd_SOURCES = pacmd.c util.c util.h xmalloc.c xmalloc.h log.c log.h pid.c pid.h +pacmd_CFLAGS = $(AM_CFLAGS) +pacmd_LDADD = $(AM_LDADD) +pacmd_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +pax11publish_SOURCES = pax11publish.c util.c util.h xmalloc.c xmalloc.h log.c log.h authkey.c authkey.h client-conf.c client-conf.h conf-parser.c conf-parser.h x11prop.c x11prop.h random.c random.h +pax11publish_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) +pax11publish_LDADD = $(AM_LDADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) +pax11publish_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +pabrowse_SOURCES = pabrowse.c +pabrowse_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-browse-@PA_MAJORMINOR@.la +pabrowse_CFLAGS = $(AM_CFLAGS) +pabrowse_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +################################### +# Test programs # +################################### + noinst_PROGRAMS = \ mainloop-test \ + mcalign-test \ pacat-simple \ parec-simple \ - cpulimit-test \ - cpulimit-test2 \ - voltest \ strlist-test \ - mcalign-test + voltest + +if HAVE_SIGXCPU +noinst_PROGRAMS += \ + cpulimit-test \ + cpulimit-test2 +endif + +if HAVE_GLIB20 +noinst_PROGRAMS += \ + mainloop-test-glib +endif + +if HAVE_GLIB12 +noinst_PROGRAMS += \ + mainloop-test-glib12 +endif + +mainloop_test_SOURCES = mainloop-test.c +mainloop_test_CFLAGS = $(AM_CFLAGS) +mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-@PA_MAJORMINOR@.la +mainloop_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +mcalign_test_SOURCES = mcalign-test.c util.c util.h xmalloc.c xmalloc.h log.c log.h mcalign.c mcalign.h memchunk.c memchunk.h memblock.c memblock.h +mcalign_test_CFLAGS = $(AM_CFLAGS) +mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) +mcalign_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +pacat_simple_SOURCES = pacat-simple.c +pacat_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la +pacat_simple_CFLAGS = $(AM_CFLAGS) +pacat_simple_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +parec_simple_SOURCES = parec-simple.c +parec_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la +parec_simple_CFLAGS = $(AM_CFLAGS) +parec_simple_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +strlist_test_SOURCES = strlist-test.c strlist.c strlist.h strbuf.c strbuf.h util.c util.h xmalloc.c xmalloc.h log.c log.h +strlist_test_CFLAGS = $(AM_CFLAGS) +strlist_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) +strlist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +voltest_SOURCES = voltest.c sample.c +voltest_CFLAGS = $(AM_CFLAGS) +voltest_LDADD = $(AM_LDADD) +voltest_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h +cpulimit_test_CFLAGS = $(AM_CFLAGS) +cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la +cpulimit_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +cpulimit_test2_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h +cpulimit_test2_CFLAGS = $(AM_CFLAGS) -DTEST2 +cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la +cpulimit_test2_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +mainloop_test_glib_SOURCES = $(mainloop_test_SOURCES) +mainloop_test_glib_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB20_CFLAGS) -DGLIB_MAIN_LOOP +mainloop_test_glib_LDADD = $(mainloop_test_LDADD) $(GLIB20_LIBS) libpolyp-mainloop-glib-@PA_MAJORMINOR@.la +mainloop_test_glib_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -polypconf_DATA=default.pa daemon.conf client.conf +mainloop_test_glib12_SOURCES = $(mainloop_test_SOURCES) +mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MAIN_LOOP +mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12-@PA_MAJORMINOR@.la +mainloop_test_glib12_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -BUILT_SOURCES=polyplib-version.h +################################### +# Client library # +################################### -polypinclude_HEADERS= \ +polypinclude_HEADERS = \ + cdecl.h \ + glib-mainloop.h \ + mainloop.h \ + mainloop-api.h \ + mainloop-signal.h \ polyplib.h \ + polyplib-context.h \ polyplib-def.h \ - polyplib-simple.h \ polyplib-error.h \ - polyplib-stream.h \ - polyplib-context.h \ polyplib-introspect.h \ - polyplib-subscribe.h \ polyplib-operation.h \ polyplib-scache.h \ + polyplib-simple.h \ + polyplib-stream.h \ + polyplib-subscribe.h \ polyplib-version.h \ - cdecl.h \ - mainloop-api.h \ - mainloop.h \ - mainloop-signal.h \ sample.h \ - glib-mainloop.h \ typeid.h +if HAVE_HOWL +polypinclude_HEADERS += \ + polyplib-browser.h +endif + +lib_LTLIBRARIES = \ + libpolyp-@PA_MAJORMINOR@.la \ + libpolyp-error-@PA_MAJORMINOR@.la \ + libpolyp-mainloop-@PA_MAJORMINOR@.la \ + libpolyp-simple-@PA_MAJORMINOR@.la + +if HAVE_HOWL +lib_LTLIBRARIES += \ + libpolyp-browse-@PA_MAJORMINOR@.la +endif + +if HAVE_GLIB20 +lib_LTLIBRARIES += \ + libpolyp-mainloop-glib-@PA_MAJORMINOR@.la +endif + +if HAVE_GLIB12 +lib_LTLIBRARIES += \ + libpolyp-mainloop-glib12-@PA_MAJORMINOR@.la +endif + +libpolyp_@PA_MAJORMINOR@_la_SOURCES = \ + authkey.c authkey.h \ + cdecl.h \ + client-conf.c client-conf.h \ + conf-parser.c conf-parser.h \ + dllmain.c \ + dynarray.c dynarray.h \ + gcc-printf.h \ + idxset.c idxset.h \ + iochannel.c iochannel.h \ + llist.h \ + log.c log.h \ + mainloop-api.c mainloop-api.h \ + mcalign.c mcalign.h \ + memblock.c memblock.h \ + memchunk.c memchunk.h \ + native-common.h \ + packet.c packet.h \ + parseaddr.c parseaddr.h \ + pdispatch.c pdispatch.h \ + polyplib.h \ + polyplib-context.c polyplib-context.h \ + polyplib-def.h \ + polyplib-internal.h \ + polyplib-introspect.c polyplib-introspect.h \ + polyplib-operation.c polyplib-operation.h \ + polyplib-scache.c polyplib-scache.h \ + polyplib-stream.c polyplib-stream.h \ + polyplib-subscribe.c polyplib-subscribe.h \ + pstream.c pstream.h \ + pstream-util.c pstream-util.h \ + queue.c queue.h \ + random.c random.h \ + sample.c sample.h \ + socket-client.c socket-client.h \ + socket-util.c socket-util.h \ + strbuf.c strbuf.h \ + strlist.c strlist.h \ + tagstruct.c tagstruct.h \ + typeid.c typeid.h \ + util.c util.h \ + winsock.h \ + xmalloc.c xmalloc.h + +if HAVE_X11 +libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ + client-conf-x11.c client-conf-x11.h \ + x11prop.c x11prop.h +endif + +libpolyp_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) +libpolyp_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 +libpolyp_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) + +if HAVE_X11 +libpolyp_@PA_MAJORMINOR@_la_CFLAGS += $(X_CFLAGS) +libpolyp_@PA_MAJORMINOR@_la_LDFLAGS += $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) +endif + +if HAVE_LIBASYNCNS +libpolyp_@PA_MAJORMINOR@_la_CFLAGS += $(LIBASYNCNS_CFLAGS) +libpolyp_@PA_MAJORMINOR@_la_LIBADD += $(LIBASYNCNS_LIBS) +endif + +libpolyp_error_@PA_MAJORMINOR@_la_SOURCES = polyplib-error.c polyplib-error.h +libpolyp_error_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) +libpolyp_error_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la +libpolyp_error_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 + +libpolyp_mainloop_@PA_MAJORMINOR@_la_SOURCES = \ + mainloop.c mainloop.h \ + mainloop-api.h mainloop-api.c \ + mainloop-signal.c mainloop-signal.h \ + poll.c poll.h +libpolyp_mainloop_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) +libpolyp_mainloop_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la $(WINSOCK_LIBS) +libpolyp_mainloop_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 + +libpolyp_simple_@PA_MAJORMINOR@_la_SOURCES = polyplib-simple.c polyplib-simple.h +libpolyp_simple_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) +libpolyp_simple_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la +libpolyp_simple_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 + +libpolyp_browse_@PA_MAJORMINOR@_la_SOURCES = polyplib-browser.c polyplib-browser.h +libpolyp_browse_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) +libpolyp_browse_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la $(HOWL_LIBS) +libpolyp_browse_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 + +libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_SOURCES = glib-mainloop.h glib-mainloop.c +libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) +libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop-@PA_MAJORMINOR@.la $(GLIB20_LIBS) +libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 + +libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_SOURCES = glib-mainloop.h glib12-mainloop.c +libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS) +libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop-@PA_MAJORMINOR@.la $(GLIB12_LIBS) +libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 + +################################### +# Daemon core library # +################################### + +polypinclude_HEADERS += \ + cli-command.h \ + client.h \ + core.h \ + dynarray.h \ + endianmacros.h \ + hashmap.h \ + idxset.h \ + iochannel.h \ + memblock.h \ + memblockq.h \ + memchunk.h \ + modargs.h \ + module.h \ + namereg.h \ + queue.h \ + resampler.h \ + sample-util.h \ + sink.h \ + sink-input.h \ + sioman.h \ + socket-server.h \ + socket-client.h \ + socket-util.h \ + source.h \ + source-output.h \ + strbuf.h \ + tokenizer.h \ + tagstruct.h \ + util.h + +lib_LTLIBRARIES += libpolypcore.la + +libpolypcore_la_SOURCES = \ + autoload.c autoload.h \ + cli-command.c cli-command.h \ + cli-text.c cli-text.h \ + client.c client.h \ + core.c core.h \ + dllmain.c \ + dynarray.c dynarray.h \ + endianmacros.h \ + g711.c g711.h \ + hashmap.c hashmap.h \ + idxset.c idxset.h \ + log.c log.h \ + mainloop.c mainloop.h \ + mainloop-api.c mainloop-api.h \ + mainloop-signal.c mainloop-signal.h \ + mcalign.c mcalign.h \ + memblock.c memblock.h \ + memblockq.c memblockq.h \ + memchunk.c memchunk.h \ + modargs.c modargs.h \ + modinfo.c modinfo.h \ + module.c module.h \ + namereg.c namereg.h \ + play-memchunk.c play-memchunk.h \ + poll.c poll.h \ + props.c props.h \ + queue.c queue.h \ + random.c random.h \ + resampler.c resampler.h \ + sample.c sample.h \ + sample-util.c sample-util.h \ + scache.c scache.h \ + sconv.c sconv.h \ + sconv-s16be.c sconv-s16be.h \ + sconv-s16le.c sconv-s16le.h \ + sink.c sink.h \ + sink-input.c sink-input.h \ + sioman.c sioman.h \ + sound-file.c sound-file.h \ + sound-file-stream.c sound-file-stream.h \ + source.c source.h \ + source-output.c source-output.h \ + strbuf.c strbuf.h \ + subscribe.c subscripe.h \ + tokenizer.c tokenizer.h \ + typeid.c typeid.h \ + util.c util.h \ + winsock.h \ + xmalloc.c xmalloc.h + +libpolypcore_la_CPPFLAGS = $(AM_CPPFLAGS) +libpolypcore_la_LDFLAGS = -avoid-version +libpolypcore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) + +################################### +# Plug-in support libraries # +################################### + ### Warning! Due to an obscure bug in libtool/automake it is required ### that the libraries in modlib_LTLIBRARIES are specified in-order, ### i.e. libraries near the end of the list depend on libraries near ### the head, and not the other way! -modlib_LTLIBRARIES= \ +modlib_LTLIBRARIES = \ libsocket-util.la \ libiochannel.la \ libsocket-server.la \ @@ -90,7 +501,6 @@ modlib_LTLIBRARIES= \ libparseaddr.la \ libpacket.la \ libpstream.la \ - liboss-util.la \ libioline.la \ libcli.la \ libprotocol-cli.la \ @@ -101,165 +511,53 @@ modlib_LTLIBRARIES= \ libauthkey-prop.la \ libstrlist.la \ libprotocol-simple.la \ - libprotocol-esound.la \ - libprotocol-native.la \ - libprotocol-http.la \ - module-cli.la \ - module-cli-protocol-tcp.la \ - module-cli-protocol-tcp6.la \ - module-cli-protocol-unix.la \ - module-pipe-sink.la \ - module-pipe-source.la \ - module-oss.la \ - module-oss-mmap.la \ - module-simple-protocol-tcp.la \ - module-simple-protocol-tcp6.la \ - module-simple-protocol-unix.la \ - module-esound-protocol-tcp.la \ - module-esound-protocol-tcp6.la \ - module-esound-protocol-unix.la \ - module-native-protocol-tcp.la \ - module-native-protocol-tcp6.la \ - module-native-protocol-unix.la \ - module-native-protocol-fd.la \ - module-sine.la \ - module-combine.la \ - module-esound-compat-spawnfd.la \ - module-esound-compat-spawnpid.la \ - module-match.la \ - module-tunnel-sink.la \ - module-tunnel-source.la \ - module-null-sink.la \ - module-esound-sink.la \ - module-http-protocol-tcp.la \ - module-http-protocol-tcp6.la \ - module-http-protocol-unix.la - -SYMDEF_FILES= \ - module-cli-symdef.h \ - module-cli-protocol-tcp-symdef.h \ - module-cli-protocol-tcp6-symdef.h \ - module-cli-protocol-unix-symdef.h \ - module-pipe-sink-symdef.h \ - module-pipe-source-symdef.h \ - module-oss-symdef.h \ - module-oss-mmap-symdef.h \ - module-simple-protocol-tcp-symdef.h \ - module-simple-protocol-tcp6-symdef.h \ - module-simple-protocol-unix-symdef.h \ - module-esound-protocol-tcp-symdef.h \ - module-esound-protocol-tcp6-symdef.h \ - module-esound-protocol-unix-symdef.h \ - module-native-protocol-tcp-symdef.h \ - module-native-protocol-tcp6-symdef.h \ - module-native-protocol-unix-symdef.h \ - module-native-protocol-fd-symdef.h \ - module-sine-symdef.h \ - module-combine-symdef.h \ - module-esound-compat-spawnfd-symdef.h \ - module-esound-compat-spawnpid-symdef.h \ - module-match-symdef.h \ - module-tunnel-sink-symdef.h \ - module-tunnel-source-symdef.h \ - module-null-sink-symdef.h \ - module-esound-sink-symdef.h \ - module-zeroconf-publish-symdef.h \ - module-lirc-symdef.h \ - module-mmkbd-evdev-symdef.h \ - module-http-protocol-tcp-symdef.h \ - module-http-protocol-tcp6-symdef.h \ - module-http-protocol-unix-symdef.h - -EXTRA_DIST+=$(SYMDEF_FILES) -BUILT_SOURCES+=$(SYMDEF_FILES) - -lib_LTLIBRARIES= \ - libpolyp-@PA_MAJORMINOR@.la \ - libpolyp-error-@PA_MAJORMINOR@.la \ - libpolyp-mainloop-@PA_MAJORMINOR@.la \ - libpolyp-simple-@PA_MAJORMINOR@.la - -polypaudio_SOURCES = idxset.c idxset.h \ - queue.c queue.h \ - strbuf.c strbuf.h \ - main.c \ - mainloop.c mainloop.h \ - memblock.c memblock.h \ - sample.c sample.h \ - sample-util.c sample-util.h \ - memblockq.c memblockq.h \ - client.c client.h \ - core.c core.h \ - source-output.c source-output.h \ - sink-input.c sink-input.h \ - source.c source.h \ - sink.c sink.h \ - module.c module.h \ - mainloop-signal.c mainloop-signal.h \ - mainloop-api.c mainloop-api.h \ - util.c util.h \ - hashmap.c hashmap.h \ - namereg.c namereg.h \ - sconv.c sconv.h \ - resampler.c resampler.h \ - endianmacros.h \ - memchunk.c memchunk.h \ - sconv-s16le.c sconv-s16le.h \ - sconv-s16be.c sconv-s16be.h \ - sioman.c sioman.h \ - modargs.c modargs.h \ - cmdline.c cmdline.h \ - cli-command.c cli-command.h \ - cli-text.c cli-text.h \ - tokenizer.c tokenizer.h \ - dynarray.c dynarray.h \ - scache.c scache.h \ - sound-file.c sound-file.h \ - play-memchunk.c play-memchunk.h \ - autoload.c autoload.h \ - xmalloc.c xmalloc.h \ - subscribe.h subscribe.c \ - sound-file-stream.c sound-file-stream.h \ - cpulimit.c cpulimit.h \ - log.c log.h \ - gcc-printf.h \ - modinfo.c modinfo.h \ - daemon-conf.c daemon-conf.h \ - dumpmodules.c dumpmodules.h \ - conf-parser.h conf-parser.c \ - caps.h caps.c \ - props.h props.c \ - mcalign.c mcalign.h \ - g711.c g711.h \ - pid.c pid.h \ - random.c random.h \ - typeid.c typeid.h + libprotocol-esound.la \ + libprotocol-native.la \ + libprotocol-http.la + +if HAVE_X11 +modlib_LTLIBRARIES += \ + libx11wrap.la \ + libx11prop.la +endif + +if HAVE_OSS +modlib_LTLIBRARIES += \ + liboss-util.la +endif -polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) -polypaudio_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL) -polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) -polypaudio_LDFLAGS= $(AM_LDFLAGS) -export-dynamic -dlopen force -#q-static $(foreach f,$(modlib_LTLIBRARIES),-dlpreopen $(f)) +if HAVE_ALSA +modlib_LTLIBRARIES += \ + libalsa-util.la +endif + +if HAVE_HOWL +modlib_LTLIBRARIES += \ + libhowl-wrap.la +endif libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h libprotocol_simple_la_LDFLAGS = -avoid-version -libprotocol_simple_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la +libprotocol_simple_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket-server.la libiochannel.la -libsocket_server_la_SOURCES = socket-server.c socket-server.h +libsocket_server_la_SOURCES = \ + inet_ntop.c inet_ntop.h \ + socket-server.c socket-server.h libsocket_server_la_LDFLAGS = -avoid-version -libsocket_server_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la $(LIBWRAP_LIBS) +libsocket_server_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la libsocket-util.la $(LIBWRAP_LIBS) $(WINSOCK_LIBS) libsocket_client_la_SOURCES = socket-client.c socket-client.h libsocket_client_la_LDFLAGS = -avoid-version -libsocket_client_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la libparseaddr.la $(LIBASYNCNS_LIBS) +libsocket_client_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la libsocket-util.la libparseaddr.la $(LIBASYNCNS_LIBS) $(WINSOCK_LIBS) libsocket_client_la_CFLAGS = $(AM_CFLAGS) $(LIBASYNCNS_CFLAGS) libparseaddr_la_SOURCES = parseaddr.c parseaddr.h libparseaddr_la_LDFLAGS = -avoid-version +libparseaddr_la_LIBADD = $(AM_LIBADD) libpolypcore.la libpstream_la_SOURCES = pstream.c pstream.h libpstream_la_LDFLAGS = -avoid-version -libpstream_la_LIBADD = $(AM_LIBADD) libpacket.la libiochannel.la +libpstream_la_LIBADD = $(AM_LIBADD) libpolypcore.la libpacket.la libiochannel.la $(WINSOCK_LIBS) libpstream_util_la_SOURCES = pstream-util.c pstream-util.h libpstream_util_la_LDFLAGS = -avoid-version @@ -267,326 +565,380 @@ libpstream_util_la_LIBADD = $(AM_LIBADD) libpacket.la libpstream.la libtagstruct libpdispatch_la_SOURCES = pdispatch.c pdispatch.h libpdispatch_la_LDFLAGS = -avoid-version -libpdispatch_la_LIBADD = $(AM_LIBADD) libtagstruct.la +libpdispatch_la_LIBADD = $(AM_LIBADD) libtagstruct.la libpolypcore.la libiochannel_la_SOURCES = iochannel.c iochannel.h libiochannel_la_LDFLAGS = -avoid-version -libiochannel_la_LIBADD = $(AM_LIBADD) libsocket-util.la +libiochannel_la_LIBADD = $(AM_LIBADD) libsocket-util.la libpolypcore.la $(WINSOCK_LIBS) libpacket_la_SOURCES = packet.c packet.h libpacket_la_LDFLAGS = -avoid-version - -liboss_util_la_SOURCES = oss-util.c oss-util.h -liboss_util_la_LDFLAGS = -avoid-version +libpacket_la_LIBADD = $(AM_LIBADD) libpolypcore.la libioline_la_SOURCES = ioline.c ioline.h libioline_la_LDFLAGS = -avoid-version -libioline_la_LIBADD = $(AM_LIBADD) libiochannel.la +libioline_la_LIBADD = $(AM_LIBADD) libiochannel.la libpolypcore.la libcli_la_SOURCES = cli.c cli.h +libcli_la_CPPFLAGS = $(AM_CPPFLAGS) libcli_la_LDFLAGS = -avoid-version -libcli_la_LIBADD = $(AM_LIBADD) libiochannel.la libioline.la +libcli_la_LIBADD = $(AM_LIBADD) libiochannel.la libioline.la libpolypcore.la libstrlist_la_SOURCES = strlist.c strlist.h libstrlist_la_LDFLAGS = -avoid-version -libstrlist_la_LIBADD = $(AM_LIBADD) +libstrlist_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol_cli_la_SOURCES = protocol-cli.c protocol-cli.h libprotocol_cli_la_LDFLAGS = -avoid-version -libprotocol_cli_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libcli.la +libprotocol_cli_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libcli.la libpolypcore.la libprotocol_http_la_SOURCES = protocol-http.c protocol-http.h libprotocol_http_la_LDFLAGS = -avoid-version -libprotocol_http_la_LIBADD = $(AM_LIBADD) libsocket-server.la libioline.la +libprotocol_http_la_LIBADD = $(AM_LIBADD) libsocket-server.la libioline.la libpolypcore.la libiochannel.la libprotocol_native_la_SOURCES = protocol-native.c protocol-native.h native-common.h libprotocol_native_la_LDFLAGS = -avoid-version -libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libstrlist.la +libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libstrlist.la libpolypcore.la libiochannel.la libtagstruct_la_SOURCES = tagstruct.c tagstruct.h libtagstruct_la_LDFLAGS = -avoid-version +libtagstruct_la_LIBADD = $(AM_LIBADD) libpolypcore.la $(WINSOCK_LIBS) libprotocol_esound_la_SOURCES = protocol-esound.c protocol-esound.h esound.h libprotocol_esound_la_LDFLAGS = -avoid-version -libprotocol_esound_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libauthkey.la +libprotocol_esound_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libauthkey.la libpolypcore.la libauthkey_la_SOURCES = authkey.c authkey.h libauthkey_la_LDFLAGS = -avoid-version +libauthkey_la_LIBADD = $(AM_LIBADD) libpolypcore.la libauthkey_prop_la_SOURCES = authkey-prop.c authkey-prop.h libauthkey_prop_la_LDFLAGS = -avoid-version +libauthkey_prop_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket_util_la_SOURCES = socket-util.c socket-util.h libsocket_util_la_LDFLAGS = -avoid-version +libsocket_util_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) + +# X11 + +libx11wrap_la_SOURCES = x11wrap.c x11wrap.h +libx11wrap_la_LDFLAGS = -avoid-version +libx11wrap_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) +libx11wrap_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) + +libx11prop_la_SOURCES = x11prop.c x11prop.h +libx11prop_la_LDFLAGS = -avoid-version +libx11prop_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) +libx11prop_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) + +# OSS + +liboss_util_la_SOURCES = oss-util.c oss-util.h +liboss_util_la_LDFLAGS = -avoid-version + +# ALSA + +libalsa_util_la_SOURCES = alsa-util.c alsa-util.h +libalsa_util_la_LDFLAGS = -avoid-version +libalsa_util_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) +libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) + +# HOWL + +libhowl_wrap_la_SOURCES = howl-wrap.c howl-wrap.h +libhowl_wrap_la_LDFLAGS = -avoid-version +libhowl_wrap_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) +libhowl_wrap_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) + +################################### +# Plug-in libraries # +################################### + +modlib_LTLIBRARIES += \ + module-cli.la \ + module-cli-protocol-tcp.la \ + module-cli-protocol-tcp6.la \ + module-simple-protocol-tcp.la \ + module-simple-protocol-tcp6.la \ + module-esound-protocol-tcp.la \ + module-esound-protocol-tcp6.la \ + module-native-protocol-tcp.la \ + module-native-protocol-tcp6.la \ + module-native-protocol-fd.la \ + module-sine.la \ + module-combine.la \ + module-tunnel-sink.la \ + module-tunnel-source.la \ + module-null-sink.la \ + module-esound-sink.la \ + module-http-protocol-tcp.la \ + module-http-protocol-tcp6.la + +if HAVE_AF_UNIX +modlib_LTLIBRARIES += \ + module-cli-protocol-unix.la \ + module-simple-protocol-unix.la \ + module-esound-protocol-unix.la \ + module-native-protocol-unix.la \ + module-http-protocol-unix.la +endif + +if HAVE_MKFIFO +modlib_LTLIBRARIES += \ + module-pipe-sink.la \ + module-pipe-source.la +endif + +if !OS_IS_WIN32 +modlib_LTLIBRARIES += \ + module-esound-compat-spawnfd.la \ + module-esound-compat-spawnpid.la +endif + +if HAVE_REGEX +modlib_LTLIBRARIES += \ + module-match.la +endif + +if HAVE_X11 +modlib_LTLIBRARIES += \ + module-x11-bell.la \ + module-x11-publish.la +endif + +if HAVE_OSS +modlib_LTLIBRARIES += \ + module-oss.la \ + module-oss-mmap.la +endif + +if HAVE_ALSA +modlib_LTLIBRARIES += \ + module-alsa-sink.la \ + module-alsa-source.la +endif + +if HAVE_SOLARIS +modlib_LTLIBRARIES += \ + module-solaris.la +endif + +if HAVE_HOWL +modlib_LTLIBRARIES += \ + module-zeroconf-publish.la +endif + +if HAVE_LIRC +modlib_LTLIBRARIES += \ + module-lirc.la +endif + +if HAVE_EVDEV +modlib_LTLIBRARIES += \ + module-mmkbd-evdev.la +endif + +if OS_IS_WIN32 +modlib_LTLIBRARIES += \ + module-waveout.la +endif + +# These are generated by a M4 script + +SYMDEF_FILES = \ + module-cli-symdef.h \ + module-cli-protocol-tcp-symdef.h \ + module-cli-protocol-tcp6-symdef.h \ + module-cli-protocol-unix-symdef.h \ + module-pipe-sink-symdef.h \ + module-pipe-source-symdef.h \ + module-simple-protocol-tcp-symdef.h \ + module-simple-protocol-tcp6-symdef.h \ + module-simple-protocol-unix-symdef.h \ + module-esound-protocol-tcp-symdef.h \ + module-esound-protocol-tcp6-symdef.h \ + module-esound-protocol-unix-symdef.h \ + module-native-protocol-tcp-symdef.h \ + module-native-protocol-tcp6-symdef.h \ + module-native-protocol-unix-symdef.h \ + module-native-protocol-fd-symdef.h \ + module-sine-symdef.h \ + module-combine-symdef.h \ + module-esound-compat-spawnfd-symdef.h \ + module-esound-compat-spawnpid-symdef.h \ + module-match-symdef.h \ + module-tunnel-sink-symdef.h \ + module-tunnel-source-symdef.h \ + module-null-sink-symdef.h \ + module-esound-sink-symdef.h \ + module-zeroconf-publish-symdef.h \ + module-lirc-symdef.h \ + module-mmkbd-evdev-symdef.h \ + module-http-protocol-tcp-symdef.h \ + module-http-protocol-tcp6-symdef.h \ + module-http-protocol-unix-symdef.h \ + module-x11-bell-symdef.h \ + module-x11-publish-symdef.h \ + module-oss-symdef.h \ + module-oss-mmap-symdef.h \ + module-alsa-sink-symdef.h \ + module-alsa-source-symdef.h \ + module-solaris-symdef.h \ + module-waveout-symdef.h + +EXTRA_DIST += $(SYMDEF_FILES) +BUILT_SOURCES += $(SYMDEF_FILES) + +$(SYMDEF_FILES): module-defs.h.m4 + $(M4) -Dfname="$@" $< > $@ + +# Simple protocol module_simple_protocol_tcp_la_SOURCES = module-protocol-stub.c module_simple_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) module_simple_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_simple_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-simple.la libsocket-server.la +module_simple_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-simple.la libsocket-server.la module_simple_protocol_tcp6_la_SOURCES = module-protocol-stub.c module_simple_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) module_simple_protocol_tcp6_la_LDFLAGS = -module -avoid-version -module_simple_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libprotocol-simple.la libsocket-server.la +module_simple_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-simple.la libsocket-server.la module_simple_protocol_unix_la_SOURCES = module-protocol-stub.c module_simple_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) module_simple_protocol_unix_la_LDFLAGS = -module -avoid-version -module_simple_protocol_unix_la_LIBADD = $(AM_LIBADD) libprotocol-simple.la libsocket-server.la libsocket-util.la +module_simple_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-simple.la libsocket-server.la libsocket-util.la + +# CLI protocol + +module_cli_la_SOURCES = module-cli.c +module_cli_la_LDFLAGS = -module -avoid-version +module_cli_la_LIBADD = $(AM_LIBADD) libcli.la libiochannel.la libpolypcore.la module_cli_protocol_tcp_la_SOURCES = module-protocol-stub.c module_cli_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) module_cli_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_cli_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-cli.la libsocket-server.la +module_cli_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-cli.la libsocket-server.la module_cli_protocol_tcp6_la_SOURCES = module-protocol-stub.c module_cli_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) module_cli_protocol_tcp6_la_LDFLAGS = -module -avoid-version -module_cli_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libprotocol-cli.la libsocket-server.la +module_cli_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-cli.la libsocket-server.la module_cli_protocol_unix_la_SOURCES = module-protocol-stub.c module_cli_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) module_cli_protocol_unix_la_LDFLAGS = -module -avoid-version -module_cli_protocol_unix_la_LIBADD = $(AM_LIBADD) libprotocol-cli.la libsocket-server.la libsocket-util.la +module_cli_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-cli.la libsocket-server.la libsocket-util.la + +# HTTP protocol module_http_protocol_tcp_la_SOURCES = module-protocol-stub.c module_http_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_CFLAGS) module_http_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_http_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-http.la libsocket-server.la +module_http_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-http.la libsocket-server.la module_http_protocol_tcp6_la_SOURCES = module-protocol-stub.c module_http_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_CFLAGS) module_http_protocol_tcp6_la_LDFLAGS = -module -avoid-version -module_http_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libprotocol-http.la libsocket-server.la +module_http_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-http.la libsocket-server.la module_http_protocol_unix_la_SOURCES = module-protocol-stub.c module_http_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_CFLAGS) module_http_protocol_unix_la_LDFLAGS = -module -avoid-version -module_http_protocol_unix_la_LIBADD = $(AM_LIBADD) libprotocol-http.la libsocket-server.la libsocket-util.la +module_http_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-http.la libsocket-server.la libsocket-util.la + +# Native protocol module_native_protocol_tcp_la_SOURCES = module-protocol-stub.c module_native_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) module_native_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_native_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-native.la libsocket-server.la +module_native_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la module_native_protocol_tcp6_la_SOURCES = module-protocol-stub.c module_native_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) module_native_protocol_tcp6_la_LDFLAGS = -module -avoid-version -module_native_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libprotocol-native.la libsocket-server.la +module_native_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la module_native_protocol_unix_la_SOURCES = module-protocol-stub.c module_native_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) module_native_protocol_unix_la_LDFLAGS = -module -avoid-version -module_native_protocol_unix_la_LIBADD = $(AM_LIBADD) libprotocol-native.la libsocket-server.la libsocket-util.la +module_native_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la libsocket-util.la module_native_protocol_fd_la_SOURCES = module-native-protocol-fd.c module_native_protocol_fd_la_CFLAGS = $(AM_CFLAGS) -module_native_protocol_fd_la_LDFLAGS = -module -avoid-version -module_native_protocol_fd_la_LIBADD = $(AM_LIBADD) libprotocol-native.la libsocket-server.la libsocket-util.la - -module_esound_protocol_tcp_la_SOURCES = module-protocol-stub.c -module_esound_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) -module_esound_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_esound_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-esound.la libsocket-server.la - -module_esound_protocol_tcp6_la_SOURCES = module-protocol-stub.c -module_esound_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) -module_esound_protocol_tcp6_la_LDFLAGS = -module -avoid-version -module_esound_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libprotocol-esound.la libsocket-server.la - -module_esound_protocol_unix_la_SOURCES = module-protocol-stub.c -module_esound_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) -module_esound_protocol_unix_la_LDFLAGS = -module -avoid-version -module_esound_protocol_unix_la_LIBADD = $(AM_LIBADD) libprotocol-esound.la libsocket-server.la libsocket-util.la - -module_pipe_sink_la_SOURCES = module-pipe-sink.c -module_pipe_sink_la_LDFLAGS = -module -avoid-version -module_pipe_sink_la_LIBADD = $(AM_LIBADD) libiochannel.la - -module_pipe_source_la_SOURCES = module-pipe-source.c -module_pipe_source_la_LDFLAGS = -module -avoid-version -module_pipe_source_la_LIBADD = $(AM_LIBADD) libiochannel.la - -module_oss_la_SOURCES = module-oss.c -module_oss_la_LDFLAGS = -module -avoid-version -module_oss_la_LIBADD = $(AM_LIBADD) libiochannel.la liboss-util.la - -module_oss_mmap_la_SOURCES = module-oss-mmap.c -module_oss_mmap_la_LDFLAGS = -module -avoid-version -module_oss_mmap_la_LIBADD = $(AM_LIBADD) liboss-util.la - -module_cli_la_SOURCES = module-cli.c -module_cli_la_LDFLAGS = -module -avoid-version -module_cli_la_LIBADD = $(AM_LIBADD) libcli.la libiochannel.la - -module_sine_la_SOURCES = module-sine.c -module_sine_la_LDFLAGS = -module -avoid-version -module_sine_la_LIBADD = $(AM_LIBADD) - -module_combine_la_SOURCES = module-combine.c -module_combine_la_LDFLAGS = -module -avoid-version -module_combine_la_LIBADD = $(AM_LIBADD) - -module_null_sink_la_SOURCES = module-null-sink.c -module_null_sink_la_LDFLAGS = -module -avoid-version -module_null_sink_la_LIBADD = $(AM_LIBADD) - -module_match_la_SOURCES = module-match.c -module_match_la_LDFLAGS = -module -avoid-version -module_match_la_LIBADD = $(AM_LIBADD) - -module_tunnel_sink_la_SOURCES = module-tunnel.c -module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS) -module_tunnel_sink_la_LDFLAGS = -module -avoid-version -module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la - -module_tunnel_source_la_SOURCES = module-tunnel.c -module_tunnel_source_la_LDFLAGS = -module -avoid-version -module_tunnel_source_la_LIBADD = $(AM_LIBADD) libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la - -module_esound_compat_spawnfd_la_SOURCES = module-esound-compat-spawnfd.c -module_esound_compat_spawnfd_la_LDFLAGS = -module -avoid-version -module_esound_compat_spawnfd_la_LIBADD = $(AM_LIBADD) - -module_esound_compat_spawnpid_la_SOURCES = module-esound-compat-spawnpid.c -module_esound_compat_spawnpid_la_LDFLAGS = -module -avoid-version -module_esound_compat_spawnpid_la_LIBADD = $(AM_LIBADD) - -module_esound_sink_la_SOURCES = module-esound-sink.c -module_esound_sink_la_LDFLAGS = -module -avoid-version -module_esound_sink_la_LIBADD = $(AM_LIBADD) libsocket-client.la libauthkey.la - -libpolyp_@PA_MAJORMINOR@_la_SOURCES = polyplib.h \ - polyplib-def.h \ - tagstruct.c tagstruct.h \ - iochannel.c iochannel.h \ - pstream.c pstream.h \ - pstream-util.c pstream-util.h \ - pdispatch.c pdispatch.h \ - mainloop-api.c mainloop-api.h \ - idxset.c idxset.h \ - util.c util.h \ - memblock.c memblock.h \ - socket-client.c socket-client.h \ - parseaddr.c parseaddr.h \ - packet.c packet.h \ - queue.c queue.h \ - dynarray.c dynarray.h \ - memchunk.c memchunk.h \ - authkey.c authkey.h \ - socket-util.c socket-util.h \ - native-common.h \ - sample.c sample.h \ - xmalloc.c xmalloc.h \ - polyplib-operation.c polyplib-operation.h \ - polyplib-context.c polyplib-context.h \ - polyplib-stream.c polyplib-stream.h \ - polyplib-introspect.c polyplib-introspect.h \ - polyplib-scache.c polyplib-scache.h \ - polyplib-subscribe.c polyplib-subscribe.h \ - polyplib-internal.h \ - cdecl.h \ - llist.h \ - log.c log.h \ - gcc-printf.h \ - client-conf.c client-conf.h \ - conf-parser.c conf-parser.h \ - strlist.c strlist.h \ - strbuf.c strbuf.h \ - mcalign.c mcalign.h \ - typeid.c typeid.h \ - random.c random.h - -libpolyp_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) -libpolyp_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 -libpolyp_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) - -libpolyp_mainloop_@PA_MAJORMINOR@_la_SOURCES = mainloop-api.h mainloop-api.c \ - mainloop.c mainloop.h \ - mainloop-signal.c mainloop-signal.h -libpolyp_mainloop_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) -libpolyp_mainloop_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la -libpolyp_mainloop_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 +module_native_protocol_fd_la_LDFLAGS = -module -avoid-version +module_native_protocol_fd_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la libsocket-util.la libiochannel.la -libpolyp_error_@PA_MAJORMINOR@_la_SOURCES = polyplib-error.c polyplib-error.h -libpolyp_error_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) -libpolyp_error_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la -libpolyp_error_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 +# EsounD protocol -libpolyp_simple_@PA_MAJORMINOR@_la_SOURCES = polyplib-simple.c polyplib-simple.h -libpolyp_simple_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) -libpolyp_simple_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la -libpolyp_simple_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 +module_esound_protocol_tcp_la_SOURCES = module-protocol-stub.c +module_esound_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) +module_esound_protocol_tcp_la_LDFLAGS = -module -avoid-version +module_esound_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-esound.la libsocket-server.la -pacat_SOURCES = pacat.c -pacat_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la -pacat_CFLAGS = $(AM_CFLAGS) +module_esound_protocol_tcp6_la_SOURCES = module-protocol-stub.c +module_esound_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) +module_esound_protocol_tcp6_la_LDFLAGS = -module -avoid-version +module_esound_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-esound.la libsocket-server.la -paplay_SOURCES = paplay.c -paplay_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) -paplay_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) +module_esound_protocol_unix_la_SOURCES = module-protocol-stub.c +module_esound_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) +module_esound_protocol_unix_la_LDFLAGS = -module -avoid-version +module_esound_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-esound.la libsocket-server.la libsocket-util.la -pactl_SOURCES = pactl.c -pactl_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) -pactl_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) +module_esound_compat_spawnfd_la_SOURCES = module-esound-compat-spawnfd.c +module_esound_compat_spawnfd_la_LDFLAGS = -module -avoid-version +module_esound_compat_spawnfd_la_LIBADD = $(AM_LIBADD) libpolypcore.la -pacat_simple_SOURCES = pacat-simple.c -pacat_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la -pacat_simple_CFLAGS = $(AM_CFLAGS) +module_esound_compat_spawnpid_la_SOURCES = module-esound-compat-spawnpid.c +module_esound_compat_spawnpid_la_LDFLAGS = -module -avoid-version +module_esound_compat_spawnpid_la_LIBADD = $(AM_LIBADD) libpolypcore.la -parec_simple_SOURCES = parec-simple.c -parec_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la -parec_simple_CFLAGS = $(AM_CFLAGS) +module_esound_sink_la_SOURCES = module-esound-sink.c +module_esound_sink_la_LDFLAGS = -module -avoid-version +module_esound_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la libsocket-client.la libauthkey.la -mainloop_test_SOURCES = mainloop-test.c -mainloop_test_CFLAGS = $(AM_CFLAGS) -mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-@PA_MAJORMINOR@.la +# Pipes -voltest_SOURCES = voltest.c sample.c -voltest_CFLAGS = $(AM_CFLAGS) -voltest_LDADD = $(AM_LDADD) +module_pipe_sink_la_SOURCES = module-pipe-sink.c +module_pipe_sink_la_LDFLAGS = -module -avoid-version +module_pipe_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la -strlist_test_SOURCES = strlist-test.c strlist.c strlist.h strbuf.c strbuf.h util.c util.h xmalloc.c xmalloc.h log.c log.h -strlist_test_CFLAGS = $(AM_CFLAGS) -strlist_test_LDADD = $(AM_LDADD) +module_pipe_source_la_SOURCES = module-pipe-source.c +module_pipe_source_la_LDFLAGS = -module -avoid-version +module_pipe_source_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la -mcalign_test_SOURCES = mcalign-test.c util.c util.h xmalloc.c xmalloc.h log.c log.h mcalign.c mcalign.h memchunk.c memchunk.h memblock.c memblock.h -mcalign_test_CFLAGS = $(AM_CFLAGS) -mcalign_test_LDADD = $(AM_LDADD) +# Fake sources/sinks -pacmd_SOURCES = pacmd.c util.c util.h xmalloc.c xmalloc.h log.c log.h pid.c pid.h -pacmd_CFLAGS = $(AM_CFLAGS) -pacmd_LDADD = $(AM_LDADD) +module_sine_la_SOURCES = module-sine.c +module_sine_la_LDFLAGS = -module -avoid-version +module_sine_la_LIBADD = $(AM_LIBADD) libpolypcore.la -cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h -cpulimit_test_CFLAGS = $(AM_CFLAGS) -cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la +module_null_sink_la_SOURCES = module-null-sink.c +module_null_sink_la_LDFLAGS = -module -avoid-version +module_null_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la -cpulimit_test2_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h -cpulimit_test2_CFLAGS = $(AM_CFLAGS) -DTEST2 -cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la +# Couplings -### X11 stuff +module_combine_la_SOURCES = module-combine.c +module_combine_la_LDFLAGS = -module -avoid-version +module_combine_la_LIBADD = $(AM_LIBADD) libpolypcore.la -if HAVE_X11 -modlib_LTLIBRARIES+= \ - libx11wrap.la \ - libx11prop.la \ - module-x11-bell.la \ - module-x11-publish.la -SYMDEF_FILES += \ - module-x11-bell-symdef.h \ - module-x11-publish-symdef.h +module_match_la_SOURCES = module-match.c +module_match_la_LDFLAGS = -module -avoid-version +module_match_la_LIBADD = $(AM_LIBADD) libpolypcore.la -libx11wrap_la_SOURCES = x11wrap.c x11wrap.h -libx11wrap_la_LDFLAGS = -avoid-version -libx11wrap_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) -libx11wrap_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) +module_tunnel_sink_la_SOURCES = module-tunnel.c +module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS) +module_tunnel_sink_la_LDFLAGS = -module -avoid-version +module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la -libx11prop_la_SOURCES = x11prop.c x11prop.h -libx11prop_la_LDFLAGS = -avoid-version -libx11prop_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) -libx11prop_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) +module_tunnel_source_la_SOURCES = module-tunnel.c +module_tunnel_source_la_LDFLAGS = -module -avoid-version +module_tunnel_source_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la + +# X11 module_x11_bell_la_SOURCES = module-x11-bell.c module_x11_bell_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) @@ -598,41 +950,17 @@ module_x11_publish_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) module_x11_publish_la_LDFLAGS = -module -avoid-version module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la libauthkey.la libauthkey-prop.la libx11prop.la libstrlist.la -bin_PROGRAMS+= \ - pax11publish - -pax11publish_SOURCES = pax11publish.c util.c util.h xmalloc.c xmalloc.h log.c log.h authkey.c authkey.h client-conf.c client-conf.h conf-parser.c conf-parser.h x11prop.c x11prop.h random.c random.h -pax11publish_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) -pax11publish_LDADD = $(AM_LDADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) - -libpolyp_@PA_MAJORMINOR@_la_CFLAGS += $(X_CFLAGS) -libpolyp_@PA_MAJORMINOR@_la_LDFLAGS += $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) -libpolyp_@PA_MAJORMINOR@_la_SOURCES += x11prop.c x11prop.h client-conf-x11.c client-conf-x11.h - -endif - -### libasyncns stuff - -if HAVE_LIBASYNCNS -libpolyp_@PA_MAJORMINOR@_la_CFLAGS += $(LIBASYNCNS_CFLAGS) -libpolyp_@PA_MAJORMINOR@_la_LIBADD += $(LIBASYNCNS_LIBS) -endif +# OSS -### ALSA modules +module_oss_la_SOURCES = module-oss.c +module_oss_la_LDFLAGS = -module -avoid-version +module_oss_la_LIBADD = $(AM_LIBADD) libiochannel.la liboss-util.la -if HAVE_ALSA -modlib_LTLIBRARIES+= \ - libalsa-util.la \ - module-alsa-sink.la \ - module-alsa-source.la -SYMDEF_FILES += \ - module-alsa-sink-symdef.h \ - module-alsa-source-symdef.h +module_oss_mmap_la_SOURCES = module-oss-mmap.c +module_oss_mmap_la_LDFLAGS = -module -avoid-version +module_oss_mmap_la_LIBADD = $(AM_LIBADD) liboss-util.la -libalsa_util_la_SOURCES = alsa-util.c alsa-util.h -libalsa_util_la_LDFLAGS = -avoid-version -libalsa_util_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) -libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) +# ALSA module_alsa_sink_la_SOURCES = module-alsa-sink.c module_alsa_sink_la_LDFLAGS = -module -avoid-version @@ -643,184 +971,44 @@ module_alsa_source_la_SOURCES = module-alsa-source.c module_alsa_source_la_LDFLAGS = -module -avoid-version module_alsa_source_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la module_alsa_source_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) -endif -### HOWL modules -if HAVE_HOWL -modlib_LTLIBRARIES+= \ - libhowl-wrap.la \ - module-zeroconf-publish.la +# Solaris -libhowl_wrap_la_SOURCES = howl-wrap.c howl-wrap.h -libhowl_wrap_la_LDFLAGS = -avoid-version -libhowl_wrap_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) -libhowl_wrap_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) +module_solaris_la_SOURCES = module-solaris.c +module_solaris_la_LDFLAGS = -module -avoid-version +module_solaris_la_LIBADD = $(AM_LIBADD) libiochannel.la + +# HOWL module_zeroconf_publish_la_SOURCES = module-zeroconf-publish.c module_zeroconf_publish_la_LDFLAGS = -module -avoid-version module_zeroconf_publish_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) libhowl-wrap.la module_zeroconf_publish_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) -lib_LTLIBRARIES+= \ - libpolyp-browse-@PA_MAJORMINOR@.la - -libpolyp_browse_@PA_MAJORMINOR@_la_SOURCES = polyplib-browser.c polyplib-browser.h -libpolyp_browse_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) -libpolyp_browse_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la $(HOWL_LIBS) -libpolyp_browse_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 - -bin_PROGRAMS += \ - pabrowse - -pabrowse_SOURCES = pabrowse.c -pabrowse_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-browse-@PA_MAJORMINOR@.la -pabrowse_CFLAGS = $(AM_CFLAGS) - -polypinclude_HEADERS+=polyplib-browser.h - -endif - -### GLIB 2.0 support - -if HAVE_GLIB20 -lib_LTLIBRARIES+= \ - libpolyp-mainloop-glib-@PA_MAJORMINOR@.la - -noinst_PROGRAMS+= \ - mainloop-test-glib - -libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_SOURCES = glib-mainloop.h glib-mainloop.c -libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) -libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop-@PA_MAJORMINOR@.la $(GLIB20_LIBS) -libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 - -mainloop_test_glib_SOURCES = $(mainloop_test_SOURCES) -mainloop_test_glib_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB20_CFLAGS) -DGLIB_MAIN_LOOP -mainloop_test_glib_LDADD = $(mainloop_test_LDADD) $(GLIB20_LIBS) libpolyp-mainloop-glib-@PA_MAJORMINOR@.la -endif - -### GLIB 1.2 support - -if HAVE_GLIB12 - -lib_LTLIBRARIES+= \ - libpolyp-mainloop-glib12-@PA_MAJORMINOR@.la - -noinst_PROGRAMS+= \ - mainloop-test-glib12 - -libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_SOURCES = glib-mainloop.h glib12-mainloop.c -libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS) -libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop-@PA_MAJORMINOR@.la $(GLIB12_LIBS) -libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 - -mainloop_test_glib12_SOURCES = $(mainloop_test_SOURCES) -mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MAIN_LOOP -mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12-@PA_MAJORMINOR@.la - -endif - -### LIRC support - -if HAVE_LIRC - -modlib_LTLIBRARIES+= \ - module-lirc.la +# LIRC module_lirc_la_SOURCES = module-lirc.c module_lirc_la_LDFLAGS = -module -avoid-version module_lirc_la_LIBADD = $(AM_LIBADD) $(LIRC_LIBS) module_lirc_la_CFLAGS = $(AM_CFLAGS) $(LIRC_CFLAGS) -endif - - -### Linux evdev - -if HAVE_EVDEV - -modlib_LTLIBRARIES+= \ - module-mmkbd-evdev.la +# Linux evdev module_mmkbd_evdev_la_SOURCES = module-mmkbd-evdev.c module_mmkbd_evdev_la_LDFLAGS = -module -avoid-version module_mmkbd_evdev_la_LIBADD = $(AM_LIBADD) module_mmkbd_evdev_la_CFLAGS = $(AM_CFLAGS) -endif - -### libpolypcore (needs to be updated) - -if BUILD_LIBPOLYPCORE - -polypinclude_HEADERS+=cli-command.h\ - client.h \ - core.h \ - dynarray.h \ - endianmacros.h \ - hashmap.h \ - idxset.h \ - iochannel.h \ - memblock.h \ - memblockq.h \ - memchunk.h \ - modargs.h \ - module.h \ - namereg.h \ - queue.h \ - resampler.h \ - sample-util.h \ - sink.h \ - sink-input.h \ - sioman.h \ - socket-server.h \ - socket-client.h \ - socket-util.h \ - source.h \ - source-output.h \ - strbuf.h \ - tokenizer.h \ - tagstruct.h \ - util.h - -lib_LTLIBRARIES+= libpolypcore.la - -libpolypcore_la_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 \ - sample-util.c sample-util.h \ - memblockq.c memblockq.h \ - client.c client.h \ - core.c core.h \ - source-output.c source-output.h \ - sink-input.c sink-input.h \ - source.c source.h \ - sink.c sink.h \ - module.c module.h \ - mainloop-signal.c mainloop-signal.h \ - mainloop-api.c mainloop-api.h \ - util.c util.h \ - hashmap.c hashmap.h \ - namereg.c namereg.h \ - sconv.c sconv.h \ - resampler.c resampler.h \ - endianmacros.h \ - memchunk.c memchunk.h \ - sconv-s16le.c sconv-s16le.h \ - sconv-s16be.c sconv-s16be.h \ - sioman.c sioman.h \ - modargs.c modargs.h \ - cli-command.c cli-command.h \ - cli-text.c cli-text.h \ - tokenizer.c tokenizer.h \ - dynarray.c dynarray.h +# Windows waveout -endif +module_waveout_la_SOURCES = module-waveout.c +module_waveout_la_LDFLAGS = -module -avoid-version +module_waveout_la_LIBADD = $(AM_LIBADD) libpolypcore.la -lwinmm +module_waveout_la_CFLAGS = $(AM_CFLAGS) -### Some minor stuff +################################### +# Some minor stuff # +################################### suid: polypaudio chown root $< @@ -829,22 +1017,24 @@ suid: polypaudio esdcompat.sh: esdcompat.sh.in Makefile sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ - -e 's,@POLYPAUDIO_BINARY\@,$(bindir)/polypaudio,g' < $< > $@ + -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ client.conf: client.conf.in Makefile - sed -e 's,@POLYPAUDIO_BINARY\@,$(bindir)/polypaudio,g' < $< > $@ + sed -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ +if OS_IS_WIN32 +default.pa: default.pa.win32 + cp $< $@ +else default.pa: default.pa.in Makefile - sed -e 's,@POLYPAUDIO_BINARY\@,$(bindir)/polypaudio,g' < $< > $@ + sed -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ +endif daemon.conf: daemon.conf.in Makefile sed -e 's,@DLSEARCHPATH\@,$(modlibdir),g' \ - -e 's,@DEFAULT_CONFIG_FILE\@,$(polypconfdir)/daemon.conf,g' < $< > $@ + -e 's,@DEFAULT_CONFIG_FILE\@,$(DEFAULT_CONFIG_DIR),g' < $< > $@ install-exec-hook: chown root $(DESTDIR)$(bindir)/polypaudio ; true chmod u+s $(DESTDIR)$(bindir)/polypaudio ln -sf pacat $(DESTDIR)$(bindir)/parec - -$(SYMDEF_FILES): module-defs.h.m4 - $(M4) -Dfname="$@" $< > $@ diff --git a/polyp/authkey.c b/polyp/authkey.c index e16883d3..969f09d9 100644 --- a/polyp/authkey.c +++ b/polyp/authkey.c @@ -63,7 +63,7 @@ static int generate(int fd, void *ret_data, size_t length) { static int load(const char *fn, void *data, size_t length) { int fd = -1; int writable = 1; - int unlock = 0, ret; + int unlock = 0, ret = -1; ssize_t r; assert(fn && data && length); @@ -128,12 +128,20 @@ int pa_authkey_load(const char *path, void *data, size_t length) { static const char *normalize_path(const char *fn, char *s, size_t l) { assert(fn && s && l > 0); +#ifndef OS_IS_WIN32 if (fn[0] != '/') { +#else + if (strlen(fn) < 3 || !isalpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') { +#endif char homedir[PATH_MAX]; if (!pa_get_home_dir(homedir, sizeof(homedir))) return NULL; +#ifndef OS_IS_WIN32 snprintf(s, l, "%s/%s", homedir, fn); +#else + snprintf(s, l, "%s\\%s", homedir, fn); +#endif return s; } diff --git a/polyp/caps.c b/polyp/caps.c index 739e7071..4ecb5848 100644 --- a/polyp/caps.c +++ b/polyp/caps.c @@ -35,6 +35,8 @@ #include "log.h" #include "caps.h" +#ifdef HAVE_GETUID + /* Drop root rights when called SUID root */ void pa_drop_root(void) { uid_t uid = getuid(); @@ -54,6 +56,13 @@ void pa_drop_root(void) { #endif } +#else + +void pa_drop_root(void) { +} + +#endif + #ifdef HAVE_SYS_CAPABILITY_H /* Limit capabilities set to CAPSYS_NICE */ diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 0e8e09a5..12447879 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -641,7 +641,11 @@ static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct time(&now); +#ifdef HAVE_CTIME_R pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime_r(&now, txt)); +#else + pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now)); +#endif for (m = pa_idxset_first(c->modules, &index); m; m = pa_idxset_next(c->modules, &index)) { diff --git a/polyp/client-conf.c b/polyp/client-conf.c index 4906383d..04c3d2ef 100644 --- a/polyp/client-conf.c +++ b/polyp/client-conf.c @@ -19,6 +19,10 @@ USA. ***/ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include @@ -33,11 +37,21 @@ #include "authkey.h" #ifndef DEFAULT_CONFIG_DIR -#define DEFAULT_CONFIG_DIR "/etc/polypaudio" +# ifndef OS_IS_WIN32 +# define DEFAULT_CONFIG_DIR "/etc/polypaudio" +# else +# define DEFAULT_CONFIG_DIR "%POLYP_ROOT%" +# endif +#endif + +#ifndef OS_IS_WIN32 +# define PATH_SEP "/" +#else +# define PATH_SEP "\\" #endif -#define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR"/client.conf" -#define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio/client.conf" +#define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "client.conf" +#define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio" PATH_SEP "client.conf" #define ENV_CLIENT_CONFIG_FILE "POLYP_CLIENTCONFIG" #define ENV_DEFAULT_SINK "POLYP_SINK" diff --git a/polyp/conf-parser.c b/polyp/conf-parser.c index b25508e2..8d2f2f68 100644 --- a/polyp/conf-parser.c +++ b/polyp/conf-parser.c @@ -19,6 +19,10 @@ USA. ***/ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include diff --git a/polyp/core.c b/polyp/core.c index e2bebec2..60439243 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -89,7 +89,9 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { pa_random(&c->cookie, sizeof(c->cookie)); +#ifdef SIGPIPE pa_check_signal_is_blocked(SIGPIPE); +#endif return c; } @@ -144,7 +146,7 @@ void pa_core_check_quit(struct pa_core *c) { if (!c->quit_event && c->exit_idle_time >= 0 && pa_idxset_ncontents(c->clients) == 0) { struct timeval tv; - gettimeofday(&tv, NULL); + pa_gettimeofday(&tv); tv.tv_sec+= c->exit_idle_time; c->quit_event = c->mainloop->time_new(c->mainloop, &tv, quit_callback, c); } else if (c->quit_event && pa_idxset_ncontents(c->clients) > 0) { diff --git a/polyp/cpulimit.c b/polyp/cpulimit.c index 0fab98a0..53920f50 100644 --- a/polyp/cpulimit.c +++ b/polyp/cpulimit.c @@ -23,15 +23,20 @@ #include #endif +#ifdef HAVE_SIGXCPU + #include #include #include #include #include -#include #include #include +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif + #include "cpulimit.h" #include "util.h" #include "log.h" @@ -219,3 +224,16 @@ void pa_cpu_limit_done(void) { installed = 0; } } + +#else /* HAVE_SIGXCPU */ + +struct pa_mainloop_api; + +int pa_cpu_limit_init(struct pa_mainloop_api *m) { + return 0; +} + +void pa_cpu_limit_done(void) { +} + +#endif diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c index a6afd05a..780581b2 100644 --- a/polyp/daemon-conf.c +++ b/polyp/daemon-conf.c @@ -37,13 +37,23 @@ #include "resampler.h" #ifndef DEFAULT_CONFIG_DIR -#define DEFAULT_CONFIG_DIR "/etc/polypaudio" +# ifndef OS_IS_WIN32 +# define DEFAULT_CONFIG_DIR "/etc/polypaudio" +# else +# define DEFAULT_CONFIG_DIR "%POLYP_ROOT%" +# endif #endif -#define DEFAULT_SCRIPT_FILE DEFAULT_CONFIG_DIR"/default.pa" -#define DEFAULT_SCRIPT_FILE_USER ".polypaudio/default.pa" -#define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR"/daemon.conf" -#define DEFAULT_CONFIG_FILE_USER ".polypaudio/daemon.conf" +#ifndef OS_IS_WIN32 +# define PATH_SEP "/" +#else +# define PATH_SEP "\\" +#endif + +#define DEFAULT_SCRIPT_FILE DEFAULT_CONFIG_DIR PATH_SEP "default.pa" +#define DEFAULT_SCRIPT_FILE_USER ".polypaudio" PATH_SEP "default.pa" +#define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "daemon.conf" +#define DEFAULT_CONFIG_FILE_USER ".polypaudio" PATH_SEP "daemon.conf" #define ENV_SCRIPT_FILE "POLYP_SCRIPT" #define ENV_CONFIG_FILE "POLYP_CONFIG" diff --git a/polyp/default.pa.win32 b/polyp/default.pa.win32 new file mode 100644 index 00000000..3478adab --- /dev/null +++ b/polyp/default.pa.win32 @@ -0,0 +1,43 @@ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with polypaudio; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + + +# Load audio drivers statically + +load-module module-waveout sink_name=output source_name=input +load-module module-null-sink + +# Load audio drivers automatically on access + +#add-autoload-sink output module-waveout sink_name=output source_name=input +#add-autoload-source input module-waveout sink_name=output source_name=input + +# Load several protocols +#load-module module-esound-protocol-tcp +#load-module module-native-protocol-tcp +#load-module module-simple-protocol-tcp +#load-module module-cli-protocol-tcp + +# Make some devices default +set-default-sink output +set-default-source input + +.nofail + +# Load something to the sample cache +load-sample x11-bell %WINDIR%\Media\ding.wav +load-sample-dir-lazy %WINDIR%\Media\*.wav diff --git a/polyp/dllmain.c b/polyp/dllmain.c new file mode 100644 index 00000000..34d0eed1 --- /dev/null +++ b/polyp/dllmain.c @@ -0,0 +1,46 @@ +/* $Id: dllmain.c 317 2004-12-11 00:10:41Z lennart $ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef OS_IS_WIN32 + +#include +#include +#include + +#include + +extern pa_set_root(HANDLE handle); + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { + if (fdwReason != DLL_PROCESS_ATTACH) + return TRUE; + + if (!pa_set_root(hinstDLL)) + return FALSE; + + return TRUE; +} + +#endif /* OS_IS_WIN32 */ diff --git a/polyp/dumpmodules.c b/polyp/dumpmodules.c index 1dc14edc..5aaa108d 100644 --- a/polyp/dumpmodules.c +++ b/polyp/dumpmodules.c @@ -31,6 +31,7 @@ #include "dumpmodules.h" #include "modinfo.h" +#include "util.h" #define PREFIX "module-" @@ -80,10 +81,7 @@ static int callback(const char *path, lt_ptr data) { const char *e; struct pa_daemon_conf *c = (data); - if ((e = (const char*) strrchr(path, '/'))) - e++; - else - e = path; + e = pa_path_get_filename(path); if (strlen(e) > sizeof(PREFIX)-1 && !strncmp(e, PREFIX, sizeof(PREFIX)-1)) show_info(e, path, c->log_level >= PA_LOG_INFO ? long_info : short_info); diff --git a/polyp/glib-mainloop.c b/polyp/glib-mainloop.c index 809c0b0f..0f96a594 100644 --- a/polyp/glib-mainloop.c +++ b/polyp/glib-mainloop.c @@ -241,7 +241,7 @@ static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv) struct timeval now; assert(e && e->mainloop && !e->dead); - gettimeofday(&now, NULL); + pa_gettimeofday(&now); if (e->source) { g_source_destroy(e->source); g_source_unref(e->source); diff --git a/polyp/glib12-mainloop.c b/polyp/glib12-mainloop.c index 5f037347..c328471c 100644 --- a/polyp/glib12-mainloop.c +++ b/polyp/glib12-mainloop.c @@ -233,7 +233,7 @@ static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv) struct timeval now; assert(e && e->mainloop && !e->dead); - gettimeofday(&now, NULL); + pa_gettimeofday(&now); if (e->source != (guint) -1) g_source_remove(e->source); diff --git a/polyp/inet_ntop.c b/polyp/inet_ntop.c new file mode 100644 index 00000000..ac2b5295 --- /dev/null +++ b/polyp/inet_ntop.c @@ -0,0 +1,80 @@ +/* $Id: inet_ntop.c 428 2006-01-09 16:50:39Z ossman $ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#ifndef HAVE_INET_NTOP + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#include "winsock.h" + +#include "inet_ntop.h" + +const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) { + struct in_addr *in = (struct in_addr*)src; + struct in6_addr *in6 = (struct in6_addr*)src; + + assert(src && dst); + + switch (af) { + case AF_INET: + snprintf(dst, cnt, "%d.%d.%d.%d", +#ifdef WORDS_BIGENDIAN + (int)(in->s_addr >> 24) & 0xff, + (int)(in->s_addr >> 16) & 0xff, + (int)(in->s_addr >> 8) & 0xff, + (int)(in->s_addr >> 0) & 0xff); +#else + (int)(in->s_addr >> 0) & 0xff, + (int)(in->s_addr >> 8) & 0xff, + (int)(in->s_addr >> 16) & 0xff, + (int)(in->s_addr >> 24) & 0xff); +#endif + break; + case AF_INET6: + snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x", + in6->s6_addr[ 0] << 8 | in6->s6_addr[ 1], + in6->s6_addr[ 2] << 8 | in6->s6_addr[ 3], + in6->s6_addr[ 4] << 8 | in6->s6_addr[ 5], + in6->s6_addr[ 6] << 8 | in6->s6_addr[ 7], + in6->s6_addr[ 8] << 8 | in6->s6_addr[ 9], + in6->s6_addr[10] << 8 | in6->s6_addr[11], + in6->s6_addr[12] << 8 | in6->s6_addr[13], + in6->s6_addr[14] << 8 | in6->s6_addr[15]); + break; + default: + errno = EAFNOSUPPORT; + return NULL; + } + + return dst; +} + +#endif /* INET_NTOP */ diff --git a/polyp/inet_ntop.h b/polyp/inet_ntop.h new file mode 100644 index 00000000..7fb67b44 --- /dev/null +++ b/polyp/inet_ntop.h @@ -0,0 +1,12 @@ +#ifndef fooinet_ntophfoo +#define fooinet_ntophfoo + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#include "winsock.h" + +const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt); + +#endif diff --git a/polyp/iochannel.c b/polyp/iochannel.c index 0e7e8db8..1a0dbf91 100644 --- a/polyp/iochannel.c +++ b/polyp/iochannel.c @@ -28,6 +28,8 @@ #include #include +#include "winsock.h" + #include "iochannel.h" #include "util.h" #include "socket-util.h" @@ -189,7 +191,19 @@ ssize_t pa_iochannel_write(struct pa_iochannel*io, const void*data, size_t l) { ssize_t r; assert(io && data && l && io->ofd >= 0); - if ((r = write(io->ofd, data, l)) >= 0) { +#ifdef OS_IS_WIN32 + r = send(io->ofd, data, l, 0); + if (r < 0) { + if (WSAGetLastError() != WSAENOTSOCK) { + errno = WSAGetLastError(); + return r; + } + } + + if (r < 0) +#endif + r = write(io->ofd, data, l); + if (r >= 0) { io->writable = 0; enable_mainloop_sources(io); } @@ -201,7 +215,19 @@ ssize_t pa_iochannel_read(struct pa_iochannel*io, void*data, size_t l) { ssize_t r; assert(io && data && io->ifd >= 0); - if ((r = read(io->ifd, data, l)) >= 0) { +#ifdef OS_IS_WIN32 + r = recv(io->ifd, data, l, 0); + if (r < 0) { + if (WSAGetLastError() != WSAENOTSOCK) { + errno = WSAGetLastError(); + return r; + } + } + + if (r < 0) +#endif + r = read(io->ifd, data, l); + if (r >= 0) { io->readable = 0; enable_mainloop_sources(io); } diff --git a/polyp/log.c b/polyp/log.c index 78736a47..2bbf2e86 100644 --- a/polyp/log.c +++ b/polyp/log.c @@ -25,9 +25,12 @@ #include #include -#include #include +#ifdef HAVE_SYSLOG_H +#include +#endif + #include "log.h" #include "xmalloc.h" #include "util.h" @@ -39,6 +42,7 @@ static enum pa_log_target log_target = PA_LOG_STDERR; static void (*user_log_func)(enum pa_log_level l, const char *s) = NULL; static enum pa_log_level maximal_level = PA_LOG_NOTICE; +#ifdef HAVE_SYSLOG_H static const int level_to_syslog[] = { [PA_LOG_ERROR] = LOG_ERR, [PA_LOG_WARN] = LOG_WARNING, @@ -46,6 +50,7 @@ static const int level_to_syslog[] = { [PA_LOG_INFO] = LOG_INFO, [PA_LOG_DEBUG] = LOG_DEBUG }; +#endif void pa_log_set_ident(const char *p) { if (log_ident) @@ -79,13 +84,15 @@ void pa_log_levelv(enum pa_log_level level, const char *format, va_list ap) { case PA_LOG_STDERR: vfprintf(stderr, format, ap); break; - + +#ifdef HAVE_SYSLOG_H case PA_LOG_SYSLOG: openlog(log_ident ? log_ident : "???", LOG_PID, LOG_USER); vsyslog(level_to_syslog[level], format, ap); closelog(); - break; - + break; +#endif + case PA_LOG_USER: { char *t = pa_vsprintf_malloc(format, ap); assert(user_log_func); @@ -94,6 +101,7 @@ void pa_log_levelv(enum pa_log_level level, const char *format, va_list ap) { } case PA_LOG_NULL: + default: break; } diff --git a/polyp/main.c b/polyp/main.c index 26fa4a87..e481fce1 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -35,13 +35,20 @@ #include #include #include +#include +#include + +#ifdef HAVE_SYS_IOCTL_H #include +#endif #ifdef HAVE_LIBWRAP #include #include #endif +#include "winsock.h" + #include "core.h" #include "mainloop.h" #include "module.h" @@ -66,24 +73,47 @@ int allow_severity = LOG_INFO; int deny_severity = LOG_WARNING; #endif +#ifdef OS_IS_WIN32 + +static void message_cb(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata) { + MSG msg; + + while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + if (msg.message == WM_QUIT) + raise(SIGTERM); + else { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } +} + +#endif + static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { pa_log_info(__FILE__": Got signal %s.\n", pa_strsignal(sig)); switch (sig) { +#ifdef SIGUSR1 case SIGUSR1: pa_module_load(userdata, "module-cli", NULL); break; +#endif +#ifdef SIGUSR2 case SIGUSR2: pa_module_load(userdata, "module-cli-protocol-unix", NULL); break; +#endif +#ifdef SIGHUP case SIGHUP: { char *c = pa_full_status_string(userdata); pa_log_notice(c); pa_xfree(c); return; } +#endif case SIGINT: case SIGTERM: @@ -111,24 +141,42 @@ int main(int argc, char *argv[]) { char *s; int r, retval = 1, d = 0; int daemon_pipe[2] = { -1, -1 }; - gid_t gid = (gid_t) -1; int suid_root; int valid_pid_file = 0; +#ifdef HAVE_GETUID + gid_t gid = (gid_t) -1; +#endif + +#ifdef OS_IS_WIN32 + struct pa_defer_event *defer; +#endif + pa_limit_caps(); +#ifdef HAVE_GETUID suid_root = getuid() != 0 && geteuid() == 0; if (suid_root && (pa_uid_in_group("realtime", &gid) <= 0 || gid >= 1000)) { pa_log_warn(__FILE__": WARNING: called SUID root, but not in group 'realtime'.\n"); pa_drop_root(); } +#else + suid_root = 0; +#endif LTDL_SET_PRELOADED_SYMBOLS(); r = lt_dlinit(); assert(r == 0); +#ifdef OS_IS_WIN32 + { + WSADATA data; + WSAStartup(MAKEWORD(2, 0), &data); + } +#endif + pa_log_set_ident("polypaudio"); conf = pa_daemon_conf_new(); @@ -217,6 +265,7 @@ int main(int argc, char *argv[]) { goto finish; } +#ifdef HAVE_FORK if (pipe(daemon_pipe) < 0) { pa_log(__FILE__": failed to create pipe.\n"); goto finish; @@ -248,13 +297,19 @@ int main(int argc, char *argv[]) { close(daemon_pipe[0]); daemon_pipe[0] = -1; +#endif if (conf->auto_log_target) pa_log_set_target(PA_LOG_SYSLOG, NULL); +#ifdef HAVE_SETSID setsid(); +#endif +#ifdef HAVE_SETPGID setpgid(0,0); - +#endif + +#ifndef OS_IS_WIN32 close(0); close(1); close(2); @@ -262,23 +317,37 @@ int main(int argc, char *argv[]) { open("/dev/null", O_RDONLY); open("/dev/null", O_WRONLY); open("/dev/null", O_WRONLY); - +#else + FreeConsole(); +#endif + +#ifdef SIGTTOU signal(SIGTTOU, SIG_IGN); +#endif +#ifdef SIGTTIN signal(SIGTTIN, SIG_IGN); +#endif +#ifdef SIGTSTP signal(SIGTSTP, SIG_IGN); +#endif +#ifdef TIOCNOTTY if ((tty_fd = open("/dev/tty", O_RDWR)) >= 0) { ioctl(tty_fd, TIOCNOTTY, (char*) 0); close(tty_fd); } +#endif } chdir("/"); if (conf->use_pid_file) { if (pa_pid_file_create() < 0) { + pa_log(__FILE__": pa_pid_file_create() failed.\n"); +#ifdef HAVE_FORK if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); +#endif goto finish; } @@ -288,20 +357,34 @@ int main(int argc, char *argv[]) { mainloop = pa_mainloop_new(); assert(mainloop); + c = pa_core_new(pa_mainloop_get_api(mainloop)); + assert(c); + r = pa_signal_init(pa_mainloop_get_api(mainloop)); assert(r == 0); pa_signal_new(SIGINT, signal_callback, c); pa_signal_new(SIGTERM, signal_callback, c); +#ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); +#endif + +#ifdef OS_IS_WIN32 + defer = pa_mainloop_get_api(mainloop)->defer_new(pa_mainloop_get_api(mainloop), message_cb, NULL); + assert(defer); +#endif - c = pa_core_new(pa_mainloop_get_api(mainloop)); - assert(c); if (conf->daemonize) c->running_as_daemon = 1; - + +#ifdef SIGUSR1 pa_signal_new(SIGUSR1, signal_callback, c); +#endif +#ifdef SIGUSR2 pa_signal_new(SIGUSR2, signal_callback, c); +#endif +#ifdef SIGHUP pa_signal_new(SIGHUP, signal_callback, c); +#endif r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop)); assert(r == 0); @@ -318,17 +401,23 @@ int main(int argc, char *argv[]) { if (r < 0 && conf->fail) { pa_log(__FILE__": failed to initialize daemon.\n"); +#ifdef HAVE_FORK if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); +#endif } else if (!c->modules || pa_idxset_ncontents(c->modules) == 0) { pa_log(__FILE__": daemon startup without any loaded modules, refusing to work.\n"); +#ifdef HAVE_FORK if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); +#endif } else { retval = 0; +#ifdef HAVE_FORK if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); +#endif c->disallow_module_loading = conf->disallow_module_loading; c->exit_idle_time = conf->exit_idle_time; @@ -346,7 +435,11 @@ int main(int argc, char *argv[]) { pa_log_info(__FILE__": Daemon shutdown initiated.\n"); } } - + +#ifdef OS_IS_WIN32 + pa_mainloop_get_api(mainloop)->defer_free(defer); +#endif + pa_core_free(c); pa_cpu_limit_done(); @@ -365,6 +458,10 @@ finish: close_pipe(daemon_pipe); +#ifdef OS_IS_WIN32 + WSACleanup(); +#endif + lt_dlexit(); return retval; diff --git a/polyp/mainloop-signal.c b/polyp/mainloop-signal.c index 89f195ed..432498a8 100644 --- a/polyp/mainloop-signal.c +++ b/polyp/mainloop-signal.c @@ -30,6 +30,11 @@ #include #include #include +#include + +#ifdef HAVE_WINDOWS_H +#include +#endif #include "mainloop-signal.h" #include "util.h" @@ -38,7 +43,11 @@ struct pa_signal_event { int sig; +#ifdef HAVE_SIGACTION struct sigaction saved_sigaction; +#else + void (*saved_handler)(int sig); +#endif void (*callback) (struct pa_mainloop_api*a, struct pa_signal_event *e, int signal, void *userdata); void *userdata; void (*destroy_callback) (struct pa_mainloop_api*a, struct pa_signal_event*e, void *userdata); @@ -48,16 +57,70 @@ struct pa_signal_event { static struct pa_mainloop_api *api = NULL; static int signal_pipe[2] = { -1, -1 }; static struct pa_io_event* io_event = NULL; +static struct pa_defer_event *defer_event = NULL; static struct pa_signal_event *signals = NULL; +#ifdef OS_IS_WIN32 +static unsigned int waiting_signals = 0; +static CRITICAL_SECTION crit; +#endif + static void signal_handler(int sig) { +#ifndef HAVE_SIGACTION + signal(sig, signal_handler); +#endif write(signal_pipe[1], &sig, sizeof(sig)); + +#ifdef OS_IS_WIN32 + EnterCriticalSection(&crit); + waiting_signals++; + LeaveCriticalSection(&crit); +#endif +} + +static void dispatch(struct pa_mainloop_api*a, int sig) { + struct pa_signal_event*s; + + for (s = signals; s; s = s->next) + if (s->sig == sig) { + assert(s->callback); + s->callback(a, s, sig, s->userdata); + break; + } +} + +static void defer(struct pa_mainloop_api*a, struct pa_defer_event*e, void *userdata) { + ssize_t r; + int sig; + unsigned int sigs; + +#ifdef OS_IS_WIN32 + EnterCriticalSection(&crit); + sigs = waiting_signals; + waiting_signals = 0; + LeaveCriticalSection(&crit); +#endif + + while (sigs) { + if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) { + pa_log(__FILE__": read(): %s\n", strerror(errno)); + return; + } + + if (r != sizeof(sig)) { + pa_log(__FILE__": short read()\n"); + return; + } + + dispatch(a, sig); + + sigs--; + } } static void callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata) { ssize_t r; int sig; - struct pa_signal_event*s; assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]); @@ -73,19 +136,18 @@ static void callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enu pa_log(__FILE__": short read()\n"); return; } - - for (s = signals; s; s = s->next) - if (s->sig == sig) { - assert(s->callback); - s->callback(a, s, sig, s->userdata); - break; - } + + dispatch(a, sig); } int pa_signal_init(struct pa_mainloop_api *a) { - assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event); - + assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event && !defer_event); + +#ifdef OS_IS_WIN32 + if (_pipe(signal_pipe, 200, _O_BINARY) < 0) { +#else if (pipe(signal_pipe) < 0) { +#endif pa_log(__FILE__": pipe() failed: %s\n", strerror(errno)); return -1; } @@ -96,20 +158,36 @@ int pa_signal_init(struct pa_mainloop_api *a) { pa_fd_set_cloexec(signal_pipe[1], 1); api = a; + +#ifndef OS_IS_WIN32 io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL); assert(io_event); +#else + defer_event = api->defer_new(api, defer, NULL); + assert(defer_event); + + InitializeCriticalSection(&crit); +#endif + return 0; } void pa_signal_done(void) { - assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && io_event); + assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && (io_event || defer_event)); while (signals) pa_signal_free(signals); - api->io_free(io_event); +#ifndef OS_IS_WIN32 + api->io_free(io_event); io_event = NULL; +#else + api->defer_free(defer_event); + defer_event = NULL; + + DeleteCriticalSection(&crit); +#endif close(signal_pipe[0]); close(signal_pipe[1]); @@ -120,7 +198,11 @@ void pa_signal_done(void) { struct pa_signal_event* pa_signal_new(int sig, void (*callback) (struct pa_mainloop_api *api, struct pa_signal_event*e, int sig, void *userdata), void *userdata) { struct pa_signal_event *e = NULL; + +#ifdef HAVE_SIGACTION struct sigaction sa; +#endif + assert(sig > 0 && callback); for (e = signals; e; e = e->next) @@ -133,12 +215,16 @@ struct pa_signal_event* pa_signal_new(int sig, void (*callback) (struct pa_mainl e->userdata = userdata; e->destroy_callback = NULL; +#ifdef HAVE_SIGACTION memset(&sa, 0, sizeof(sa)); sa.sa_handler = signal_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; if (sigaction(sig, &sa, &e->saved_sigaction) < 0) +#else + if ((e->saved_handler = signal(sig, signal_handler)) == SIG_ERR) +#endif goto fail; e->previous = NULL; @@ -162,7 +248,11 @@ void pa_signal_free(struct pa_signal_event *e) { else signals = e->next; +#ifdef HAVE_SIGACTION sigaction(e->sig, &e->saved_sigaction, NULL); +#else + signal(e->sig, e->saved_handler); +#endif if (e->destroy_callback) e->destroy_callback(api, e, e->userdata); diff --git a/polyp/mainloop-test.c b/polyp/mainloop-test.c index 0d40e76e..dd8f8137 100644 --- a/polyp/mainloop-test.c +++ b/polyp/mainloop-test.c @@ -111,7 +111,7 @@ int main(int argc, char *argv[]) { de = a->defer_new(a, dcb, NULL); assert(de); - gettimeofday(&tv, NULL); + pa_gettimeofday(&tv); tv.tv_sec += 10; te = a->time_new(a, &tv, tcb, NULL); diff --git a/polyp/mainloop.c b/polyp/mainloop.c index f6bb4145..ada74afc 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -26,13 +26,20 @@ #include #include #include -#include #include #include #include #include #include +#ifdef HAVE_SYS_POLL_H +#include +#else +#include "poll.h" +#endif + +#include "winsock.h" + #include "mainloop.h" #include "util.h" #include "idxset.h" @@ -103,6 +110,26 @@ static struct pa_io_event* mainloop_io_new(struct pa_mainloop_api*a, int fd, enu e->destroy_callback = NULL; e->pollfd = NULL; +#ifdef OS_IS_WIN32 + { + fd_set xset; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 0; + + FD_ZERO (&xset); + FD_SET (fd, &xset); + + if ((select((SELECT_TYPE_ARG1) fd, NULL, NULL, SELECT_TYPE_ARG234 &xset, + SELECT_TYPE_ARG5 &tv) == -1) && + (WSAGetLastError() == WSAENOTSOCK)) { + pa_log_warn(__FILE__": WARNING: cannot monitor non-socket file descriptors.\n"); + e->dead = 1; + } + } +#endif + pa_idxset_put(m->io_events, e, NULL); m->rebuild_pollfds = 1; return e; @@ -457,7 +484,7 @@ static int calc_next_timeout(struct pa_mainloop *m) { /* Let's save a system call */ if (!got_time) { - gettimeofday(&now, NULL); + pa_gettimeofday(&now); got_time = 1; } @@ -498,7 +525,7 @@ static int dispatch_timeout(struct pa_mainloop *m) { /* Let's save a system call */ if (!got_time) { - gettimeofday(&now, NULL); + pa_gettimeofday(&now); got_time = 1; } diff --git a/polyp/mcalign-test.c b/polyp/mcalign-test.c index e4a6a239..2ace6e59 100644 --- a/polyp/mcalign-test.c +++ b/polyp/mcalign-test.c @@ -66,7 +66,7 @@ int main(int argc, char *argv[]) { c.length = r; pa_mcalign_push(a, &c); - fprintf(stderr, "Read %u bytes\n", r); + fprintf(stderr, "Read %d bytes\n", r); c.index += r; diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index 69db2875..dde5d8b6 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -25,7 +25,12 @@ #include #include + +#ifdef HAVE_SYS_POLL_H #include +#else +#include "poll.h" +#endif #include diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index 55abe8e0..5b4076f8 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -25,7 +25,12 @@ #include #include + +#ifdef HAVE_SYS_POLL_H #include +#else +#include "poll.h" +#endif #include diff --git a/polyp/module-combine.c b/polyp/module-combine.c index ca79d7df..7283c554 100644 --- a/polyp/module-combine.c +++ b/polyp/module-combine.c @@ -157,7 +157,7 @@ static void time_callback(struct pa_mainloop_api*a, struct pa_time_event* e, con adjust_rates(u); - gettimeofday(&n, NULL); + pa_gettimeofday(&n); n.tv_sec += u->adjust_time; u->sink->core->mainloop->time_restart(e, &n); } @@ -363,7 +363,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { pa_log_warn(__FILE__": WARNING: no slave sinks specified.\n"); if (u->adjust_time > 0) { - gettimeofday(&tv, NULL); + pa_gettimeofday(&tv); tv.tv_sec += u->adjust_time; u->time_event = c->mainloop->time_new(c->mainloop, &tv, time_callback, u); } diff --git a/polyp/module-esound-sink.c b/polyp/module-esound-sink.c index 82c38cc2..19106506 100644 --- a/polyp/module-esound-sink.c +++ b/polyp/module-esound-sink.c @@ -144,7 +144,7 @@ static int do_write(struct userdata *u) { pa_module_set_used(u->module, pa_idxset_ncontents(u->sink->inputs) + pa_idxset_ncontents(u->sink->monitor_source->outputs)); if (!u->memchunk.length) - if (pa_sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0) + if (pa_sink_render(u->sink, 8192, &u->memchunk) < 0) return 0; assert(u->memchunk.memblock && u->memchunk.length); diff --git a/polyp/module-mmkbd-evdev.c b/polyp/module-mmkbd-evdev.c index 758aaae5..5368af50 100644 --- a/polyp/module-mmkbd-evdev.c +++ b/polyp/module-mmkbd-evdev.c @@ -49,6 +49,17 @@ PA_MODULE_USAGE("device= sink=") #define DEFAULT_DEVICE "/dev/input/event0" +/* + * This isn't defined in older kernel headers and there is no way of + * detecting it. + */ +struct _input_id { + __u16 bustype; + __u16 vendor; + __u16 product; + __u16 version; +}; + static const char* const valid_modargs[] = { "device", "sink", @@ -136,7 +147,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { struct pa_modargs *ma = NULL; struct userdata *u; int version; - struct input_id input_id; + struct _input_id input_id; char name[256]; uint8_t evtype_bitmask[EV_MAX/8 + 1]; assert(c && m); diff --git a/polyp/module-null-sink.c b/polyp/module-null-sink.c index fcac1ea4..6c7a44f2 100644 --- a/polyp/module-null-sink.c +++ b/polyp/module-null-sink.c @@ -117,7 +117,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { pa_sink_set_owner(u->sink, m); u->sink->description = pa_sprintf_malloc("NULL sink"); - gettimeofday(&tv, NULL); + pa_gettimeofday(&tv); u->time_event = c->mainloop->time_new(c->mainloop, &tv, time_callback, u); u->block_size = pa_bytes_per_second(&ss) / 10; diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index 15697582..141eadd3 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -27,9 +27,20 @@ #include #include #include -#include #include +#include + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H #include +#endif + +#include "winsock.h" #include "module.h" #include "socket-server.h" diff --git a/polyp/module-solaris.c b/polyp/module-solaris.c new file mode 100644 index 00000000..3eb66462 --- /dev/null +++ b/polyp/module-solaris.c @@ -0,0 +1,436 @@ +/* $Id: module-oss.c 333 2005-01-08 21:36:53Z lennart $ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "iochannel.h" +#include "sink.h" +#include "source.h" +#include "module.h" +#include "sample-util.h" +#include "util.h" +#include "modargs.h" +#include "xmalloc.h" +#include "log.h" +#include "module-solaris-symdef.h" + +PA_MODULE_AUTHOR("Pierre Ossman") +PA_MODULE_DESCRIPTION("Solaris Sink/Source") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= buffer_size=") + +#define PA_TYPEID_SOLARIS PA_TYPEID_MAKE('S', 'L', 'R', 'S') + +struct userdata { + struct pa_sink *sink; + struct pa_source *source; + struct pa_iochannel *io; + struct pa_core *core; + + struct pa_memchunk memchunk, silence; + + uint32_t sample_size; + unsigned int written_bytes, read_bytes; + + int fd; + struct pa_module *module; +}; + +static const char* const valid_modargs[] = { + "sink_name", + "source_name", + "device", + "record", + "playback", + "buffer_size", + "format", + "rate", + "channels", + NULL +}; + +#define DEFAULT_SINK_NAME "solaris_output" +#define DEFAULT_SOURCE_NAME "solaris_input" +#define DEFAULT_DEVICE "/dev/audio" + +#define CHUNK_SIZE 2048 + +static void update_usage(struct userdata *u) { + pa_module_set_used(u->module, + (u->sink ? pa_idxset_ncontents(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_ncontents(u->sink->monitor_source->outputs) : 0) + + (u->source ? pa_idxset_ncontents(u->source->outputs) : 0)); +} + +static void do_write(struct userdata *u) { + struct pa_memchunk *memchunk; + ssize_t r; + + assert(u); + + if (!u->sink || !pa_iochannel_is_writable(u->io)) + return; + + update_usage(u); + + memchunk = &u->memchunk; + + if (!memchunk->length) + if (pa_sink_render(u->sink, CHUNK_SIZE, memchunk) < 0) + memchunk = &u->silence; + + assert(memchunk->memblock); + assert(memchunk->memblock->data); + assert(memchunk->length); + + if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + return; + } + + if (memchunk == &u->silence) + assert(r % u->sample_size == 0); + else { + u->memchunk.index += r; + u->memchunk.length -= r; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + } + } + + u->written_bytes += r; +} + +static void do_read(struct userdata *u) { + struct pa_memchunk memchunk; + int err, l; + ssize_t r; + assert(u); + + if (!u->source || !pa_iochannel_is_readable(u->io)) + return; + + update_usage(u); + + err = ioctl(u->fd, I_NREAD, &l); + assert(err >= 0); + + memchunk.memblock = pa_memblock_new(l, u->core->memblock_stat); + assert(memchunk.memblock); + if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { + pa_memblock_unref(memchunk.memblock); + if (errno != EAGAIN) + pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + return; + } + + assert(r <= (ssize_t) memchunk.memblock->length); + memchunk.length = memchunk.memblock->length = r; + memchunk.index = 0; + + pa_source_post(u->source, &memchunk); + pa_memblock_unref(memchunk.memblock); + + u->read_bytes += r; +} + +static void io_callback(struct pa_iochannel *io, void*userdata) { + struct userdata *u = userdata; + assert(u); + do_write(u); + do_read(u); +} + +static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { + pa_usec_t r = 0; + audio_info_t info; + int err; + struct userdata *u = s->userdata; + assert(s && u && u->sink); + + err = ioctl(u->fd, AUDIO_GETINFO, &info); + assert(err >= 0); + + r += pa_bytes_to_usec(u->written_bytes, &s->sample_spec); + r -= pa_bytes_to_usec(info.play.samples * u->sample_size, &s->sample_spec); + + if (u->memchunk.memblock) + r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec); + + return r; +} + +static pa_usec_t source_get_latency_cb(struct pa_source *s) { + pa_usec_t r = 0; + struct userdata *u = s->userdata; + audio_info_t info; + int err; + assert(s && u && u->source); + + err = ioctl(u->fd, AUDIO_GETINFO, &info); + assert(err >= 0); + + r += pa_bytes_to_usec(info.record.samples * u->sample_size, &s->sample_spec); + r -= pa_bytes_to_usec(u->read_bytes, &s->sample_spec); + + return r; +} + +static int pa_solaris_auto_format(int fd, int mode, struct pa_sample_spec *ss) { + audio_info_t info; + + AUDIO_INITINFO(&info); + + if (mode != O_RDONLY) { + info.play.sample_rate = ss->rate; + info.play.channels = ss->channels; + switch (ss->format) { + case PA_SAMPLE_U8: + info.play.precision = 8; + info.play.encoding = AUDIO_ENCODING_LINEAR; + break; + case PA_SAMPLE_ALAW: + info.play.precision = 8; + info.play.encoding = AUDIO_ENCODING_ALAW; + break; + case PA_SAMPLE_ULAW: + info.play.precision = 8; + info.play.encoding = AUDIO_ENCODING_ULAW; + break; + case PA_SAMPLE_S16NE: + info.play.precision = 16; + info.play.encoding = AUDIO_ENCODING_LINEAR; + break; + default: + return -1; + } + } + + if (mode != O_WRONLY) { + info.record.sample_rate = ss->rate; + info.record.channels = ss->channels; + switch (ss->format) { + case PA_SAMPLE_U8: + info.record.precision = 8; + info.record.encoding = AUDIO_ENCODING_LINEAR; + break; + case PA_SAMPLE_ALAW: + info.record.precision = 8; + info.record.encoding = AUDIO_ENCODING_ALAW; + break; + case PA_SAMPLE_ULAW: + info.record.precision = 8; + info.record.encoding = AUDIO_ENCODING_ULAW; + break; + case PA_SAMPLE_S16NE: + info.record.precision = 16; + info.record.encoding = AUDIO_ENCODING_LINEAR; + break; + default: + return -1; + } + } + + if (ioctl(fd, AUDIO_SETINFO, &info) < 0) { + if (errno == EINVAL) + pa_log(__FILE__": AUDIO_SETINFO: Unsupported sample format.\n"); + else + pa_log(__FILE__": AUDIO_SETINFO: %s\n", strerror(errno)); + return -1; + } + + return 0; +} + +static int pa_solaris_set_buffer(int fd, int buffer_size) { + audio_info_t info; + + AUDIO_INITINFO(&info); + + info.record.buffer_size = buffer_size; + + if (ioctl(fd, AUDIO_SETINFO, &info) < 0) { + if (errno == EINVAL) + pa_log(__FILE__": AUDIO_SETINFO: Unsupported buffer size.\n"); + else + pa_log(__FILE__": AUDIO_SETINFO: %s\n", strerror(errno)); + return -1; + } + + return 0; +} + +int pa__init(struct pa_core *c, struct pa_module*m) { + struct userdata *u = NULL; + const char *p; + int fd = -1; + int buffer_size; + int mode; + int record = 1, playback = 1; + struct pa_sample_spec ss; + struct pa_modargs *ma = NULL; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments.\n"); + goto fail; + } + + if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { + pa_log(__FILE__": record= and playback= expect numeric argument.\n"); + goto fail; + } + + if (!playback && !record) { + pa_log(__FILE__": neither playback nor record enabled for device.\n"); + goto fail; + } + + mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); + + buffer_size = -1; + if (pa_modargs_get_value_s32(ma, "buffer_size", &buffer_size) < 0) { + pa_log(__FILE__": failed to parse buffer size argument\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": failed to parse sample specification\n"); + goto fail; + } + + if ((fd = open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), mode)) < 0) + goto fail; + + pa_log_info(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + + if (pa_solaris_auto_format(fd, mode, &ss) < 0) + goto fail; + + if ((mode != O_WRONLY) && (buffer_size >= 1)) + if (pa_solaris_set_buffer(fd, buffer_size) < 0) + goto fail; + + u = pa_xmalloc(sizeof(struct userdata)); + u->core = c; + + if (mode != O_WRONLY) { + u->source = pa_source_new(c, PA_TYPEID_SOLARIS, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); + assert(u->source); + u->source->userdata = u; + u->source->get_latency = source_get_latency_cb; + pa_source_set_owner(u->source, m); + u->source->description = pa_sprintf_malloc("Solaris PCM on '%s'", p); + } else + u->source = NULL; + + if (mode != O_RDONLY) { + u->sink = pa_sink_new(c, PA_TYPEID_SOLARIS, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); + assert(u->sink); + u->sink->get_latency = sink_get_latency_cb; + u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Solaris PCM on '%s'", p); + } else + u->sink = NULL; + + assert(u->source || u->sink); + + u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : 0); + assert(u->io); + pa_iochannel_set_callback(u->io, io_callback, u); + u->fd = fd; + + u->memchunk.memblock = NULL; + u->memchunk.length = 0; + u->sample_size = pa_frame_size(&ss); + + u->silence.memblock = pa_memblock_new(u->silence.length = CHUNK_SIZE, u->core->memblock_stat); + assert(u->silence.memblock); + pa_silence_memblock(u->silence.memblock, &ss); + u->silence.index = 0; + + u->written_bytes = 0; + u->read_bytes = 0; + + u->module = m; + m->userdata = u; + + pa_modargs_free(ma); + + return 0; + +fail: + if (fd >= 0) + close(fd); + + if (ma) + pa_modargs_free(ma); + + return -1; +} + +void pa__done(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + if (u->silence.memblock) + pa_memblock_unref(u->silence.memblock); + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + } + + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + } + + pa_iochannel_free(u->io); + pa_xfree(u); +} diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c index 9da87b3d..c6a35ca6 100644 --- a/polyp/module-tunnel.c +++ b/polyp/module-tunnel.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -284,7 +283,7 @@ static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t comman return; } - gettimeofday(&now, NULL); + pa_gettimeofday(&now); if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) { /* local and remote seem to have synchronized clocks */ @@ -324,7 +323,7 @@ static void request_latency(struct userdata *u) { pa_tagstruct_putu32(t, tag = u->ctag++); pa_tagstruct_putu32(t, u->channel); - gettimeofday(&now, NULL); + pa_gettimeofday(&now); pa_tagstruct_put_timeval(t, &now); pa_tagstruct_putu64(t, 0); @@ -536,7 +535,7 @@ static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, request_latency(u); - gettimeofday(&ntv, NULL); + pa_gettimeofday(&ntv); ntv.tv_sec += LATENCY_INTERVAL; m->time_restart(e, &ntv); } @@ -650,7 +649,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { pa_source_set_owner(u->source, m); #endif - gettimeofday(&ntv, NULL); + pa_gettimeofday(&ntv); ntv.tv_sec += LATENCY_INTERVAL; u->time_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, u); diff --git a/polyp/module-waveout.c b/polyp/module-waveout.c new file mode 100644 index 00000000..4e01bc75 --- /dev/null +++ b/polyp/module-waveout.c @@ -0,0 +1,583 @@ +/* $Id: module-waveout.c 333 2005-01-08 21:36:53Z lennart $ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "sink.h" +#include "source.h" +#include "module.h" +#include "mainloop-api.h" +#include "modargs.h" +#include "sample-util.h" +#include "util.h" +#include "log.h" +#include "xmalloc.h" +#include "module-waveout-symdef.h" + +PA_MODULE_AUTHOR("Pierre Ossman") +PA_MODULE_DESCRIPTION("Windows waveOut Sink/Source") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink_name= source_name= record= playback= format= channels= rate= fragments= fragment_size=") + +#define PA_TYPEID_WAVEOUT PA_TYPEID_MAKE('W', 'A', 'V', 'E') + +#define DEFAULT_SINK_NAME "wave_output" +#define DEFAULT_SOURCE_NAME "wave_input" + +struct userdata { + struct pa_sink *sink; + struct pa_source *source; + struct pa_core *core; + struct pa_time_event *event; + struct pa_defer_event *defer; + pa_usec_t poll_timeout; + + uint32_t fragments, fragment_size; + + uint32_t free_ofrags, free_ifrags; + + DWORD written_bytes; + + int cur_ohdr, cur_ihdr; + unsigned int oremain; + WAVEHDR *ohdrs, *ihdrs; + struct pa_memchunk silence; + + HWAVEOUT hwo; + HWAVEIN hwi; + struct pa_module *module; + + CRITICAL_SECTION crit; +}; + +static const char* const valid_modargs[] = { + "sink_name", + "source_name", + "record", + "playback", + "fragments", + "fragment_size", + "format", + "rate", + "channels", + NULL +}; + +static void update_usage(struct userdata *u) { + pa_module_set_used(u->module, + (u->sink ? pa_idxset_ncontents(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_ncontents(u->sink->monitor_source->outputs) : 0) + + (u->source ? pa_idxset_ncontents(u->source->outputs) : 0)); +} + +static void do_write(struct userdata *u) +{ + uint32_t free_frags, remain; + struct pa_memchunk memchunk, *cur_chunk; + WAVEHDR *hdr; + MMRESULT res; + + if (!u->sink) + return; + + EnterCriticalSection(&u->crit); + + free_frags = u->free_ofrags; + u->free_ofrags = 0; + + LeaveCriticalSection(&u->crit); + + while (free_frags) { + hdr = &u->ohdrs[u->cur_ohdr]; + if (hdr->dwFlags & WHDR_PREPARED) + waveOutUnprepareHeader(u->hwo, hdr, sizeof(WAVEHDR)); + + remain = u->oremain; + while (remain) { + cur_chunk = &memchunk; + + if (pa_sink_render(u->sink, remain, cur_chunk) < 0) { + /* + * Don't fill with silence unless we're getting close to + * underflowing. + */ + if (free_frags > u->fragments/2) + cur_chunk = &u->silence; + else { + EnterCriticalSection(&u->crit); + + u->free_ofrags += free_frags; + + LeaveCriticalSection(&u->crit); + + u->oremain = remain; + return; + } + } + + assert(cur_chunk->memblock); + assert(cur_chunk->memblock->data); + assert(cur_chunk->length); + + memcpy(hdr->lpData + u->fragment_size - remain, + (char*)cur_chunk->memblock->data + cur_chunk->index, + (cur_chunk->length < remain)?cur_chunk->length:remain); + + remain -= (cur_chunk->length < remain)?cur_chunk->length:remain; + + if (cur_chunk != &u->silence) { + pa_memblock_unref(cur_chunk->memblock); + cur_chunk->memblock = NULL; + } + } + + res = waveOutPrepareHeader(u->hwo, hdr, sizeof(WAVEHDR)); + if (res != MMSYSERR_NOERROR) { + pa_log_error(__FILE__ ": ERROR: Unable to prepare waveOut block: %d\n", + res); + } + res = waveOutWrite(u->hwo, hdr, sizeof(WAVEHDR)); + if (res != MMSYSERR_NOERROR) { + pa_log_error(__FILE__ ": ERROR: Unable to write waveOut block: %d\n", + res); + } + + u->written_bytes += u->fragment_size; + + free_frags--; + u->cur_ohdr++; + u->cur_ohdr %= u->fragments; + u->oremain = u->fragment_size; + } +} + +static void do_read(struct userdata *u) +{ + uint32_t free_frags; + struct pa_memchunk memchunk; + WAVEHDR *hdr; + MMRESULT res; + + if (!u->source) + return; + + EnterCriticalSection(&u->crit); + + free_frags = u->free_ifrags; + u->free_ifrags = 0; + + LeaveCriticalSection(&u->crit); + + while (free_frags) { + hdr = &u->ihdrs[u->cur_ihdr]; + if (hdr->dwFlags & WHDR_PREPARED) + waveInUnprepareHeader(u->hwi, hdr, sizeof(WAVEHDR)); + + if (hdr->dwBytesRecorded) { + memchunk.memblock = pa_memblock_new(hdr->dwBytesRecorded, u->core->memblock_stat); + assert(memchunk.memblock); + + memcpy((char*)memchunk.memblock->data, hdr->lpData, hdr->dwBytesRecorded); + + memchunk.length = memchunk.memblock->length = hdr->dwBytesRecorded; + memchunk.index = 0; + + pa_source_post(u->source, &memchunk); + pa_memblock_unref(memchunk.memblock); + } + + res = waveInPrepareHeader(u->hwi, hdr, sizeof(WAVEHDR)); + if (res != MMSYSERR_NOERROR) { + pa_log_error(__FILE__ ": ERROR: Unable to prepare waveIn block: %d\n", + res); + } + res = waveInAddBuffer(u->hwi, hdr, sizeof(WAVEHDR)); + if (res != MMSYSERR_NOERROR) { + pa_log_error(__FILE__ ": ERROR: Unable to add waveIn block: %d\n", + res); + } + + free_frags--; + u->cur_ihdr++; + u->cur_ihdr %= u->fragments; + } +} + +static void poll_cb(struct pa_mainloop_api*a, struct pa_time_event *e, const struct timeval *tv, void *userdata) { + struct userdata *u = userdata; + struct timeval ntv; + + assert(u); + + update_usage(u); + + do_write(u); + do_read(u); + + pa_gettimeofday(&ntv); + pa_timeval_add(&ntv, u->poll_timeout); + + a->time_restart(e, &ntv); +} + +static void defer_cb(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata) { + struct userdata *u = userdata; + + assert(u); + + a->defer_enable(e, 0); + + do_write(u); + do_read(u); +} + +static void CALLBACK chunk_done_cb(HWAVEOUT hwo, UINT msg, DWORD_PTR inst, DWORD param1, DWORD param2) { + struct userdata *u = (struct userdata *)inst; + + if (msg != WOM_DONE) + return; + + EnterCriticalSection(&u->crit); + + u->free_ofrags++; + assert(u->free_ofrags <= u->fragments); + + LeaveCriticalSection(&u->crit); +} + +static void CALLBACK chunk_ready_cb(HWAVEIN hwi, UINT msg, DWORD_PTR inst, DWORD param1, DWORD param2) { + struct userdata *u = (struct userdata *)inst; + + if (msg != WIM_DATA) + return; + + EnterCriticalSection(&u->crit); + + u->free_ifrags++; + assert(u->free_ifrags <= u->fragments); + + LeaveCriticalSection(&u->crit); +} + +static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { + struct userdata *u = s->userdata; + uint32_t free_frags; + MMTIME mmt; + assert(s && u && u->sink); + + memset(&mmt, 0, sizeof(mmt)); + mmt.wType = TIME_BYTES; + if (waveOutGetPosition(u->hwo, &mmt, sizeof(mmt)) == MMSYSERR_NOERROR) + return pa_bytes_to_usec(u->written_bytes - mmt.u.cb, &s->sample_spec); + else { + EnterCriticalSection(&u->crit); + + free_frags = u->free_ofrags; + + LeaveCriticalSection(&u->crit); + + return pa_bytes_to_usec((u->fragments - free_frags) * u->fragment_size, + &s->sample_spec); + } +} + +static pa_usec_t source_get_latency_cb(struct pa_source *s) { + pa_usec_t r = 0; + struct userdata *u = s->userdata; + uint32_t free_frags; + assert(s && u && u->sink); + + EnterCriticalSection(&u->crit); + + free_frags = u->free_ifrags; + + LeaveCriticalSection(&u->crit); + + r += pa_bytes_to_usec((free_frags + 1) * u->fragment_size, &s->sample_spec); + + fprintf(stderr, "Latency: %d us\n", (int)r); + + return r; +} + +static void notify_sink_cb(struct pa_sink *s) { + struct userdata *u = s->userdata; + assert(u); + + u->core->mainloop->defer_enable(u->defer, 1); +} + +static void notify_source_cb(struct pa_source *s) { + struct userdata *u = s->userdata; + assert(u); + + u->core->mainloop->defer_enable(u->defer, 1); +} + +static int ss_to_waveformat(struct pa_sample_spec *ss, LPWAVEFORMATEX wf) { + wf->wFormatTag = WAVE_FORMAT_PCM; + + if (ss->channels > 2) { + pa_log_error(__FILE__": ERROR: More than two channels not supported.\n"); + return -1; + } + + wf->nChannels = ss->channels; + + switch (ss->rate) { + case 8000: + case 11025: + case 22005: + case 44100: + break; + default: + pa_log_error(__FILE__": ERROR: Unsupported sample rate.\n"); + return -1; + } + + wf->nSamplesPerSec = ss->rate; + + if (ss->format == PA_SAMPLE_U8) + wf->wBitsPerSample = 8; + else if (ss->format == PA_SAMPLE_S16NE) + wf->wBitsPerSample = 16; + else { + pa_log_error(__FILE__": ERROR: Unsupported sample format.\n"); + return -1; + } + + wf->nBlockAlign = wf->nChannels * wf->wBitsPerSample/8; + wf->nAvgBytesPerSec = wf->nSamplesPerSec * wf->nBlockAlign; + + wf->cbSize = 0; + + return 0; +} + +int pa__init(struct pa_core *c, struct pa_module*m) { + struct userdata *u = NULL; + HWAVEOUT hwo = INVALID_HANDLE_VALUE; + HWAVEIN hwi = INVALID_HANDLE_VALUE; + WAVEFORMATEX wf; + int nfrags, frag_size; + int record = 1, playback = 1; + struct pa_sample_spec ss; + struct pa_modargs *ma = NULL; + unsigned int i; + struct timeval tv; + + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments.\n"); + goto fail; + } + + if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { + pa_log(__FILE__": record= and playback= expect boolean argument.\n"); + goto fail; + } + + if (!playback && !record) { + pa_log(__FILE__": neither playback nor record enabled for device.\n"); + goto fail; + } + + nfrags = 20; + frag_size = 1024; + if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { + pa_log(__FILE__": failed to parse fragments arguments\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": failed to parse sample specification\n"); + goto fail; + } + + if (ss_to_waveformat(&ss, &wf) < 0) + goto fail; + + u = pa_xmalloc(sizeof(struct userdata)); + + if (record) { + if (waveInOpen(&hwi, WAVE_MAPPER, &wf, (DWORD_PTR)chunk_ready_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) + goto fail; + if (waveInStart(hwi) != MMSYSERR_NOERROR) + goto fail; + pa_log_debug(__FILE__": Opened waveIn subsystem.\n"); + } + + if (playback) { + if (waveOutOpen(&hwo, WAVE_MAPPER, &wf, (DWORD_PTR)chunk_done_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) + goto fail; + pa_log_debug(__FILE__": Opened waveOut subsystem.\n"); + } + + InitializeCriticalSection(&u->crit); + + if (hwi != INVALID_HANDLE_VALUE) { + u->source = pa_source_new(c, PA_TYPEID_WAVEOUT, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); + assert(u->source); + u->source->userdata = u; + u->source->notify = notify_source_cb; + u->source->get_latency = source_get_latency_cb; + pa_source_set_owner(u->source, m); + u->source->description = pa_sprintf_malloc("Windows waveIn PCM"); + } else + u->source = NULL; + + if (hwo != INVALID_HANDLE_VALUE) { + u->sink = pa_sink_new(c, PA_TYPEID_WAVEOUT, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); + assert(u->sink); + u->sink->notify = notify_sink_cb; + u->sink->get_latency = sink_get_latency_cb; + u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Windows waveOut PCM"); + } else + u->sink = NULL; + + assert(u->source || u->sink); + + u->core = c; + u->hwi = hwi; + u->hwo = hwo; + + u->fragments = nfrags; + u->free_ifrags = u->fragments; + u->free_ofrags = u->fragments; + u->fragment_size = frag_size - (frag_size % pa_frame_size(&ss)); + + u->written_bytes = 0; + + u->oremain = u->fragment_size; + + u->poll_timeout = pa_bytes_to_usec(u->fragments * u->fragment_size / 3, &ss); + + pa_gettimeofday(&tv); + pa_timeval_add(&tv, u->poll_timeout); + + u->event = c->mainloop->time_new(c->mainloop, &tv, poll_cb, u); + assert(u->event); + + u->defer = c->mainloop->defer_new(c->mainloop, defer_cb, u); + assert(u->defer); + c->mainloop->defer_enable(u->defer, 0); + + u->cur_ihdr = 0; + u->cur_ohdr = 0; + u->ihdrs = pa_xmalloc0(sizeof(WAVEHDR) * u->fragments); + assert(u->ihdrs); + u->ohdrs = pa_xmalloc0(sizeof(WAVEHDR) * u->fragments); + assert(u->ohdrs); + for (i = 0;i < u->fragments;i++) { + u->ihdrs[i].dwBufferLength = u->fragment_size; + u->ohdrs[i].dwBufferLength = u->fragment_size; + u->ihdrs[i].lpData = pa_xmalloc(u->fragment_size); + assert(u->ihdrs); + u->ohdrs[i].lpData = pa_xmalloc(u->fragment_size); + assert(u->ohdrs); + } + + u->silence.length = u->fragment_size; + u->silence.memblock = pa_memblock_new(u->silence.length, u->core->memblock_stat); + assert(u->silence.memblock); + pa_silence_memblock(u->silence.memblock, &ss); + u->silence.index = 0; + + u->module = m; + m->userdata = u; + + pa_modargs_free(ma); + + return 0; + +fail: + if (hwi != INVALID_HANDLE_VALUE) + waveInClose(hwi); + + if (hwo != INVALID_HANDLE_VALUE) + waveOutClose(hwo); + + if (u) + pa_xfree(u); + + if (ma) + pa_modargs_free(ma); + + return -1; +} + +void pa__done(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + unsigned int i; + + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->event) + c->mainloop->time_free(u->event); + + if (u->defer) + c->mainloop->defer_free(u->defer); + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + } + + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + } + + if (u->hwi != INVALID_HANDLE_VALUE) { + waveInReset(u->hwi); + waveInClose(u->hwi); + } + + if (u->hwo != INVALID_HANDLE_VALUE) { + waveOutReset(u->hwo); + waveOutClose(u->hwo); + } + + for (i = 0;i < u->fragments;i++) { + pa_xfree(u->ihdrs[i].lpData); + pa_xfree(u->ohdrs[i].lpData); + } + + pa_xfree(u->ihdrs); + pa_xfree(u->ohdrs); + + DeleteCriticalSection(&u->crit); + + pa_xfree(u); +} diff --git a/polyp/module.c b/polyp/module.c index aedaae02..0a3d569b 100644 --- a/polyp/module.c +++ b/polyp/module.c @@ -47,7 +47,7 @@ static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, pa_module_unload_unused(c); - gettimeofday(&ntv, NULL); + pa_gettimeofday(&ntv); ntv.tv_sec += UNLOAD_POLL_TIME; m->time_restart(e, &ntv); } @@ -98,7 +98,7 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char if (!c->module_auto_unload_event) { struct timeval ntv; - gettimeofday(&ntv, NULL); + pa_gettimeofday(&ntv); ntv.tv_sec += UNLOAD_POLL_TIME; c->module_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); } diff --git a/polyp/oss-util.c b/polyp/oss-util.c index 8c83cbbf..799bc40a 100644 --- a/polyp/oss-util.c +++ b/polyp/oss-util.c @@ -92,7 +92,7 @@ fail: int pa_oss_auto_format(int fd, struct pa_sample_spec *ss) { int format, channels, speed, reqformat; - static const int format_trans[] = { + static const int format_trans[PA_SAMPLE_MAX] = { [PA_SAMPLE_U8] = AFMT_U8, [PA_SAMPLE_ALAW] = AFMT_A_LAW, [PA_SAMPLE_ULAW] = AFMT_MU_LAW, diff --git a/polyp/pacat.c b/polyp/pacat.c index 5910d13f..1bba2ee4 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -480,8 +480,12 @@ int main(int argc, char *argv[]) { assert(r == 0); pa_signal_new(SIGINT, exit_signal_callback, NULL); pa_signal_new(SIGTERM, exit_signal_callback, NULL); +#ifdef SIGUSR1 pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL); +#endif +#ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); +#endif if (!(stdio_event = mainloop_api->io_new(mainloop_api, mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO, diff --git a/polyp/pactl.c b/polyp/pactl.c index 423cce95..725b5460 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -739,7 +739,9 @@ int main(int argc, char *argv[]) { r = pa_signal_init(mainloop_api); assert(r == 0); pa_signal_new(SIGINT, exit_signal_callback, NULL); +#ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); +#endif if (!(context = pa_context_new(mainloop_api, client_name))) { fprintf(stderr, "pa_context_new() failed.\n"); diff --git a/polyp/paplay.c b/polyp/paplay.c index 2eaf07c1..4ace1973 100644 --- a/polyp/paplay.c +++ b/polyp/paplay.c @@ -338,7 +338,9 @@ int main(int argc, char *argv[]) { r = pa_signal_init(mainloop_api); assert(r == 0); pa_signal_new(SIGINT, exit_signal_callback, NULL); +#ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); +#endif /* Create a new connection context */ if (!(context = pa_context_new(mainloop_api, client_name))) { diff --git a/polyp/pdispatch.c b/polyp/pdispatch.c index 7a9e9c68..60dd911c 100644 --- a/polyp/pdispatch.c +++ b/polyp/pdispatch.c @@ -32,6 +32,7 @@ #include "xmalloc.h" #include "llist.h" #include "log.h" +#include "util.h" /*#define DEBUG_OPCODES */ @@ -245,7 +246,7 @@ void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int time r->userdata = userdata; r->tag = tag; - gettimeofday(&tv, NULL); + pa_gettimeofday(&tv); tv.tv_sec += timeout; r->time_event = pd->mainloop->time_new(pd->mainloop, &tv, timeout_callback, r); diff --git a/polyp/pid.c b/polyp/pid.c index 2fac687e..ae3dc7f5 100644 --- a/polyp/pid.c +++ b/polyp/pid.c @@ -35,6 +35,10 @@ #include #include +#ifdef HAVE_WINDOWS_H +#include +#endif + #include "pid.h" #include "util.h" #include "log.h" @@ -130,6 +134,10 @@ int pa_pid_file_create(void) { pid_t pid; size_t l; +#ifdef OS_IS_WIN32 + HANDLE process; +#endif + pa_runtime_path("pid", fn, sizeof(fn)); if ((fd = open_pid_file(fn, O_CREAT|O_RDWR)) < 0) @@ -138,7 +146,12 @@ int pa_pid_file_create(void) { if ((pid = read_pid(fn, fd)) == (pid_t) -1) pa_log(__FILE__": corrupt PID file, overwriting.\n"); else if (pid > 0) { +#ifdef OS_IS_WIN32 + if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)) != NULL) { + CloseHandle(process); +#else if (kill(pid, 0) >= 0 || errno != ESRCH) { +#endif pa_log(__FILE__": daemon already running.\n"); goto fail; } @@ -198,6 +211,12 @@ int pa_pid_file_remove(void) { goto fail; } +#ifdef OS_IS_WIN32 + pa_lock_fd(fd, 0); + close(fd); + fd = -1; +#endif + if (unlink(fn) < 0) { pa_log(__FILE__": failed to remove PID file '%s': %s\n", fn, strerror(errno)); goto fail; @@ -223,6 +242,8 @@ int pa_pid_file_check_running(pid_t *pid) { return pa_pid_file_kill(0, pid); } +#ifndef OS_IS_WIN32 + /* Kill a current running daemon. Return non-zero on success, -1 * otherwise. If successful *pid contains the PID of the daemon * process. */ @@ -242,7 +263,7 @@ int pa_pid_file_kill(int sig, pid_t *pid) { if ((*pid = read_pid(fn, fd)) == (pid_t) -1) goto fail; - + ret = kill(*pid, sig); fail: @@ -255,3 +276,11 @@ fail: return ret; } + +#else /* OS_IS_WIN32 */ + +int pa_pid_file_kill(int sig, pid_t *pid) { + return -1; +} + +#endif diff --git a/polyp/poll.c b/polyp/poll.c new file mode 100644 index 00000000..6a260daf --- /dev/null +++ b/polyp/poll.c @@ -0,0 +1,190 @@ +/* $Id: mainloop.c 302 2004-11-21 17:02:25Z lennart $ */ + +/*** + Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 2005, Cendio AB. + This file is part of polypaudio. + Based on work for the GNU C Library. + + polypaudio is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with polypaudio; If not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +***/ + +/* Poll the file descriptors described by the NFDS structures starting at + FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for + an event to occur; if TIMEOUT is -1, block until an event occurs. + Returns the number of file descriptors with events, zero if timed out, + or -1 for errors. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#include "winsock.h" + +#ifndef HAVE_SYS_POLL_H + +#include "util.h" +#include "poll.h" + +int poll (struct pollfd *fds, unsigned long int nfds, int timeout) { + struct timeval tv; + fd_set rset, wset, xset; + struct pollfd *f; + int ready; + int maxfd = 0; + char data[64]; + + FD_ZERO (&rset); + FD_ZERO (&wset); + FD_ZERO (&xset); + + if (nfds == 0) { + if (timeout >= 0) { + pa_msleep(timeout); + return 0; + } + +#ifdef OS_IS_WIN32 + /* + * Windows does not support signals properly so waiting for them would + * mean a deadlock. + */ + pa_msleep(100); + return 0; +#else + return select(0, NULL, NULL, NULL, NULL); +#endif + } + + for (f = fds; f < &fds[nfds]; ++f) { + if (f->fd != -1) { + if (f->events & POLLIN) + FD_SET (f->fd, &rset); + if (f->events & POLLOUT) + FD_SET (f->fd, &wset); + if (f->events & POLLPRI) + FD_SET (f->fd, &xset); + if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI))) + maxfd = f->fd; + } + } + + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + + ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset, + SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset, + SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv)); + if ((ready == -1) && (errno == EBADF)) { + ready = 0; + + FD_ZERO (&rset); + FD_ZERO (&wset); + FD_ZERO (&xset); + + maxfd = -1; + + for (f = fds; f < &fds[nfds]; ++f) { + if (f->fd != -1) { + fd_set sngl_rset, sngl_wset, sngl_xset; + + FD_ZERO (&sngl_rset); + FD_ZERO (&sngl_wset); + FD_ZERO (&sngl_xset); + + if (f->events & POLLIN) + FD_SET (f->fd, &sngl_rset); + if (f->events & POLLOUT) + FD_SET (f->fd, &sngl_wset); + if (f->events & POLLPRI) + FD_SET (f->fd, &sngl_xset); + if (f->events & (POLLIN|POLLOUT|POLLPRI)) { + struct timeval singl_tv; + + singl_tv.tv_sec = 0; + singl_tv.tv_usec = 0; + + if (select((SELECT_TYPE_ARG1) f->fd, SELECT_TYPE_ARG234 &rset, + SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset, + SELECT_TYPE_ARG5 &singl_tv) != -1) { + if (f->events & POLLIN) + FD_SET (f->fd, &rset); + if (f->events & POLLOUT) + FD_SET (f->fd, &wset); + if (f->events & POLLPRI) + FD_SET (f->fd, &xset); + if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI))) + maxfd = f->fd; + ++ready; + } else if (errno == EBADF) + f->revents |= POLLNVAL; + } + } + } + + if (ready) { + /* Linux alters the tv struct... but it shouldn't matter here ... + * as we're going to be a little bit out anyway as we've just eaten + * more than a couple of cpu cycles above */ + ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset, + SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset, + SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv)); + } + } + +#ifdef OS_IS_WIN32 + errno = WSAGetLastError(); +#endif + + if (ready > 0) { + ready = 0; + for (f = fds; f < &fds[nfds]; ++f) { + f->revents = 0; + if (f->fd != -1) { + if (FD_ISSET (f->fd, &rset)) { + /* support for POLLHUP. An hung up descriptor does not + increase the return value! */ + if (recv (f->fd, data, 64, MSG_PEEK) == -1) { + if (errno == ESHUTDOWN || errno == ECONNRESET || + errno == ECONNABORTED || errno == ENETRESET) { + fprintf(stderr, "Hangup\n"); + f->revents |= POLLHUP; + } + } + + if (f->revents == 0) + f->revents |= POLLIN; + } + if (FD_ISSET (f->fd, &wset)) + f->revents |= POLLOUT; + if (FD_ISSET (f->fd, &xset)) + f->revents |= POLLPRI; + } + if (f->revents) + ready++; + } + } + + return ready; +} + +#endif /* HAVE_SYS_POLL_H */ diff --git a/polyp/poll.h b/polyp/poll.h new file mode 100644 index 00000000..573f90ea --- /dev/null +++ b/polyp/poll.h @@ -0,0 +1,57 @@ +/* $Id: mainloop.c 302 2004-11-21 17:02:25Z lennart $ */ + +/*** + Compatibility definitions for System V `poll' interface. + Copyright (C) 1994,96,97,98,99,2000,2001,2004 Free Software Foundation, Inc. + Copyright (C) 2005, Cendio AB. + This file is part of polypaudio. + Based on work for the GNU C Library. + + polypaudio is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with polypaudio; If not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +***/ + +/* Event types that can be polled for. These bits may be set in `events' + to indicate the interesting event types; they will appear in `revents' + to indicate the status of the file descriptor. */ +#define POLLIN 0x001 /* There is data to read. */ +#define POLLPRI 0x002 /* There is urgent data to read. */ +#define POLLOUT 0x004 /* Writing now will not block. */ + +/* Event types always implicitly polled for. These bits need not be set in + `events', but they will appear in `revents' to indicate the status of + the file descriptor. */ +#define POLLERR 0x008 /* Error condition. */ +#define POLLHUP 0x010 /* Hung up. */ +#define POLLNVAL 0x020 /* Invalid polling request. */ + + +/* Type used for the number of file descriptors. */ +typedef unsigned long int nfds_t; + +/* Data structure describing a polling request. */ +struct pollfd + { + int fd; /* File descriptor to poll. */ + short int events; /* Types of events poller cares about. */ + short int revents; /* Types of events that actually occurred. */ + }; + +/* Poll the file descriptors described by the NFDS structures starting at + FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for + an event to occur; if TIMEOUT is -1, block until an event occurs. + Returns the number of file descriptors with events, zero if timed out, + or -1 for errors. */ +extern int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout); diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index bca7d7ea..f97d9b82 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -28,13 +28,24 @@ #include #include #include -#include -#include #include #include #include -#include #include +#include + +#ifdef HAVE_SYS_WAIT_H +#include +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif + +#include "winsock.h" #include "polyplib-internal.h" #include "polyplib-context.h" @@ -110,8 +121,10 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * c->autospawn_lock_fd = -1; memset(&c->spawn_api, 0, sizeof(c->spawn_api)); c->do_autospawn = 0; - + +#ifdef SIGPIPE pa_check_signal_is_blocked(SIGPIPE); +#endif c->conf = pa_client_conf_new(); pa_client_conf_load(c->conf, NULL); @@ -372,6 +385,8 @@ finish: static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata); +#ifndef OS_IS_WIN32 + static int context_connect_spawn(struct pa_context *c) { pid_t pid; int status, r; @@ -485,6 +500,8 @@ fail: return -1; } +#endif /* OS_IS_WIN32 */ + static int try_next_connection(struct pa_context *c) { char *u = NULL; int r = -1; @@ -499,10 +516,12 @@ static int try_next_connection(struct pa_context *c) { if (!u) { +#ifndef OS_IS_WIN32 if (c->do_autospawn) { r = context_connect_spawn(c); goto finish; } +#endif pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); goto finish; diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index d1b3a27f..8677c813 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -93,6 +93,7 @@ struct pa_stream { uint32_t requested_bytes; uint64_t counter; pa_usec_t previous_time; + pa_usec_t previous_ipol_time; enum pa_stream_state state; struct pa_mcalign *mcalign; diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 6a73c608..b6a091b3 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -66,6 +66,7 @@ struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const st s->counter = 0; s->previous_time = 0; + s->previous_ipol_time = 0; s->corked = 0; s->interpolate = 0; @@ -217,7 +218,7 @@ static void ipol_callback(struct pa_mainloop_api *m, struct pa_time_event *e, co s->ipol_requested = 1; } - gettimeofday(&tv2, NULL); + pa_gettimeofday(&tv2); pa_timeval_add(&tv2, LATENCY_IPOL_INTERVAL_USEC); m->time_restart(e, &tv2); @@ -256,7 +257,7 @@ void pa_create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32 struct timeval tv; pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); - gettimeofday(&tv, NULL); + pa_gettimeofday(&tv); tv.tv_usec += LATENCY_IPOL_INTERVAL_USEC; /* every 100 ms */ assert(!s->ipol_event); @@ -412,7 +413,7 @@ static void stream_get_latency_info_callback(struct pa_pdispatch *pd, uint32_t c pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } else { - gettimeofday(&now, NULL); + pa_gettimeofday(&now); if (pa_timeval_cmp(&local, &remote) <= 0 && pa_timeval_cmp(&remote, &now) <= 0) { /* local and remote seem to have synchronized clocks */ @@ -470,7 +471,7 @@ struct pa_operation* pa_stream_get_latency_info(struct pa_stream *s, void (*cb)( pa_tagstruct_putu32(t, tag = s->context->ctag++); pa_tagstruct_putu32(t, s->channel); - gettimeofday(&now, NULL); + pa_gettimeofday(&now); pa_tagstruct_put_timeval(t, &now); pa_tagstruct_putu64(t, s->counter); @@ -581,7 +582,7 @@ struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (stru s->ipol_usec = pa_stream_get_interpolated_time(s); else if (s->corked && !b) /* Unpausing */ - gettimeofday(&s->ipol_timestamp, NULL); + pa_gettimeofday(&s->ipol_timestamp); } s->corked = b; @@ -702,7 +703,7 @@ pa_usec_t pa_stream_get_time(struct pa_stream *s, const struct pa_latency_info * usec = s->previous_time; s->previous_time = usec; - + return usec; } @@ -762,10 +763,11 @@ pa_usec_t pa_stream_get_interpolated_time(struct pa_stream *s) { usec = s->ipol_usec + pa_timeval_age(&s->ipol_timestamp); } - if (usec < s->previous_time) - usec = s->previous_time; + if (usec < s->previous_ipol_time) + usec = s->previous_ipol_time; + + s->previous_ipol_time = usec; - s->previous_time = usec; return usec; } diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index d99b721c..18ecb0ac 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -239,11 +239,14 @@ static void* connection_write(struct connection *c, size_t length) { return (uint8_t*) c->write_data+i; } -static void format_esd2native(int format, struct pa_sample_spec *ss) { +static void format_esd2native(int format, int swap_bytes, struct pa_sample_spec *ss) { assert(ss); ss->channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; - ss->format = ((format & ESD_MASK_BITS) == ESD_BITS16) ? PA_SAMPLE_S16NE : PA_SAMPLE_U8; + if ((format & ESD_MASK_BITS) == ESD_BITS16) + ss->format = swap_bytes ? PA_SAMPLE_S16RE : PA_SAMPLE_S16NE; + else + ss->format = PA_SAMPLE_U8; } static int format_native2esd(struct pa_sample_spec *ss) { @@ -303,7 +306,7 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); ss.rate = rate; - format_esd2native(format, &ss); + format_esd2native(format, c->swap_byte_order, &ss); if (!pa_sample_spec_valid(&ss)) { pa_log(__FILE__": invalid sample specification\n"); @@ -359,7 +362,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); ss.rate = rate; - format_esd2native(format, &ss); + format_esd2native(format, c->swap_byte_order, &ss); if (!pa_sample_spec_valid(&ss)) { pa_log(__FILE__": invalid sample specification.\n"); @@ -426,7 +429,6 @@ static int esd_proto_get_latency(struct connection *c, esd_proto_t request, cons latency = 0; else { double usec = pa_sink_get_latency(sink); - usec += PLAYBACK_BUFFER_SECONDS*1000000; /* A better estimation would be a good idea! */ latency = (int) ((usec*44100)/1000000); } @@ -603,7 +605,7 @@ static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, con rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); ss.rate = rate; - format_esd2native(format, &ss); + format_esd2native(format, c->swap_byte_order, &ss); sc_length = (size_t) maybe_swap_endian_32(c->swap_byte_order, (*((int*)data + 2))); @@ -1099,7 +1101,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo if (!c->authorized) { struct timeval tv; - gettimeofday(&tv, NULL); + pa_gettimeofday(&tv); tv.tv_sec += AUTH_TIMEOUT; c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c); } else diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 7e1a8894..90dbdaf5 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -928,7 +928,7 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma pa_tagstruct_put_boolean(reply, pa_memblockq_is_readable(s->memblockq)); pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq)); pa_tagstruct_put_timeval(reply, &tv); - gettimeofday(&now, NULL); + pa_gettimeofday(&now); pa_tagstruct_put_timeval(reply, &now); pa_tagstruct_putu64(reply, counter); pa_pstream_send_tagstruct(c->pstream, reply); @@ -971,7 +971,7 @@ static void command_get_record_latency(struct pa_pdispatch *pd, uint32_t command pa_tagstruct_put_boolean(reply, 0); pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq)); pa_tagstruct_put_timeval(reply, &tv); - gettimeofday(&now, NULL); + pa_gettimeofday(&now); pa_tagstruct_put_timeval(reply, &now); pa_tagstruct_putu64(reply, counter); pa_pstream_send_tagstruct(c->pstream, reply); @@ -2024,7 +2024,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo if (!c->authorized) { struct timeval tv; - gettimeofday(&tv, NULL); + pa_gettimeofday(&tv); tv.tv_sec += AUTH_TIMEOUT; c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c); } else diff --git a/polyp/pstream.c b/polyp/pstream.c index c081c242..6f983289 100644 --- a/polyp/pstream.c +++ b/polyp/pstream.c @@ -27,7 +27,12 @@ #include #include #include + +#ifdef HAVE_NETINET_IN_H #include +#endif + +#include "winsock.h" #include "pstream.h" #include "queue.h" diff --git a/polyp/random.c b/polyp/random.c index 456954a2..12f27bfd 100644 --- a/polyp/random.c +++ b/polyp/random.c @@ -19,6 +19,10 @@ USA. ***/ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include @@ -31,13 +35,16 @@ #include "util.h" #include "log.h" +#ifndef OS_IS_WIN32 #define RANDOM_DEVICE "/dev/urandom" +#endif void pa_random(void *ret_data, size_t length) { int fd; ssize_t r = 0; assert(ret_data && length); - + +#ifdef RANDOM_DEVICE if ((fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) { if ((r = pa_loop_read(fd, ret_data, length)) < 0 || (size_t) r != length) @@ -45,17 +52,20 @@ void pa_random(void *ret_data, size_t length) { close(fd); } +#endif if ((size_t) r != length) { uint8_t *p; size_t l; - + +#ifdef RANDOM_DEVICE pa_log_warn(__FILE__": WARNING: Failed to open entropy device '"RANDOM_DEVICE"': %s" ", falling back to unsecure pseudo RNG.\n", strerror(errno)); +#endif - srandom(time(NULL)); + srand(time(NULL)); for (p = ret_data, l = length; l > 0; p++, l--) - *p = (uint8_t) random(); + *p = (uint8_t) rand(); } } diff --git a/polyp/sample-util.c b/polyp/sample-util.c index d521afe4..bf8be34e 100644 --- a/polyp/sample-util.c +++ b/polyp/sample-util.c @@ -161,7 +161,7 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz size_t d; for (d = 0;; d += sizeof(float)) { - float_t sum = 0; + pa_volume_t sum = 0; unsigned c; if (d >= length) diff --git a/polyp/sample.h b/polyp/sample.h index 0494c7de..82c14615 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -51,11 +51,19 @@ enum pa_sample_format { #define PA_SAMPLE_S16NE PA_SAMPLE_S16BE /** 32 Bit IEEE floating point, native endian */ #define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32BE +/** Signed 16 Bit PCM reverse endian */ +#define PA_SAMPLE_S16RE PA_SAMPLE_S16LE +/** 32 Bit IEEE floating point, reverse endian */ +#define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32LE #else /** Signed 16 Bit PCM, native endian */ #define PA_SAMPLE_S16NE PA_SAMPLE_S16LE /** 32 Bit IEEE floating point, native endian */ #define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32LE +/** Signed 16 Bit PCM reverse endian */ +#define PA_SAMPLE_S16RE PA_SAMPLE_S16BE +/** 32 Bit IEEE floating point, reverse endian */ +#define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32BE #endif /** A Shortcut for PA_SAMPLE_FLOAT32NE */ diff --git a/polyp/scache.c b/polyp/scache.c index ccdc7185..2953145d 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -32,7 +32,14 @@ #include #include #include + +#ifdef HAVE_GLOB_H #include +#endif + +#ifdef HAVE_WINDOWS_H +#include +#endif #include "scache.h" #include "sink-input.h" @@ -55,7 +62,7 @@ static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, pa_scache_unload_unused(c); - gettimeofday(&ntv, NULL); + pa_gettimeofday(&ntv); ntv.tv_sec += UNLOAD_POLL_TIME; m->time_restart(e, &ntv); } @@ -144,6 +151,13 @@ int pa_scache_add_file(struct pa_core *c, const char *name, const char *filename struct pa_memchunk chunk; int r; +#ifdef OS_IS_WIN32 + char buf[MAX_PATH]; + + if (ExpandEnvironmentStrings(filename, buf, MAX_PATH)) + filename = buf; +#endif + if (pa_sound_file_load(filename, &ss, &chunk, c->memblock_stat) < 0) return -1; @@ -155,6 +169,14 @@ int pa_scache_add_file(struct pa_core *c, const char *name, const char *filename int pa_scache_add_file_lazy(struct pa_core *c, const char *name, const char *filename, uint32_t *index) { struct pa_scache_entry *e; + +#ifdef OS_IS_WIN32 + char buf[MAX_PATH]; + + if (ExpandEnvironmentStrings(filename, buf, MAX_PATH)) + filename = buf; +#endif + assert(c && name); if (!(e = scache_add_item(c, name))) @@ -165,7 +187,7 @@ int pa_scache_add_file_lazy(struct pa_core *c, const char *name, const char *fil if (!c->scache_auto_unload_event) { struct timeval ntv; - gettimeofday(&ntv, NULL); + pa_gettimeofday(&ntv); ntv.tv_sec += UNLOAD_POLL_TIME; c->scache_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); } @@ -303,17 +325,16 @@ static void add_file(struct pa_core *c, const char *pathname) { struct stat st; const char *e; - if (!(e = strrchr(pathname, '/'))) - e = pathname; - else - e++; + e = pa_path_get_filename(pathname); if (stat(pathname, &st) < 0) { pa_log(__FILE__": stat('%s') failed: %s\n", pathname, strerror(errno)); return; } +#if defined(S_ISREG) && defined(S_ISLNK) if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) +#endif pa_scache_add_file_lazy(c, e, pathname, NULL); } @@ -323,6 +344,7 @@ int pa_scache_add_directory_lazy(struct pa_core *c, const char *pathname) { /* First try to open this as directory */ if (!(dir = opendir(pathname))) { +#ifdef HAVE_GLOB_H glob_t p; unsigned int i; /* If that fails, try to open it as shell glob */ @@ -336,6 +358,9 @@ int pa_scache_add_directory_lazy(struct pa_core *c, const char *pathname) { add_file(c, p.gl_pathv[i]); globfree(&p); +#else + return -1; +#endif } else { struct dirent *e; diff --git a/polyp/socket-client.c b/polyp/socket-client.c index 21563d35..51134b84 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -31,14 +31,29 @@ #include #include #include + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_SYS_UN_H #include -#include +#endif +#ifdef HAVE_ARPA_INET_H #include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H #include +#endif + #ifdef HAVE_LIBASYNCNS #include #endif +#include "winsock.h" + #include "socket-client.h" #include "socket-util.h" #include "util.h" @@ -120,7 +135,7 @@ static void do_call(struct pa_socket_client *c) { goto finish; lerror = sizeof(error); - if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &error, &lerror) < 0) { + if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &lerror) < 0) { pa_log(__FILE__": getsockopt(): %s\n", strerror(errno)); goto finish; } @@ -198,18 +213,28 @@ struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, ui return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); } +#ifdef HAVE_SYS_UN_H + struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename) { struct sockaddr_un sa; assert(m && filename); memset(&sa, 0, sizeof(sa)); - sa.sun_family = AF_LOCAL; + sa.sun_family = AF_UNIX; strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); sa.sun_path[sizeof(sa.sun_path) - 1] = 0; return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); } +#else /* HAVE_SYS_UN_H */ + +struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename) { + return NULL; +} + +#endif /* HAVE_SYS_UN_H */ + static int sockaddr_prepare(struct pa_socket_client *c, const struct sockaddr *sa, size_t salen) { assert(c); assert(sa); @@ -377,7 +402,7 @@ static void start_timeout(struct pa_socket_client *c) { assert(c); assert(!c->timeout_event); - gettimeofday(&tv, NULL); + pa_gettimeofday(&tv); pa_timeval_add(&tv, CONNECT_TIMEOUT * 1000000); c->timeout_event = c->mainloop->time_new(c->mainloop, &tv, timeout_cb, c); } @@ -426,8 +451,9 @@ struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, assert(c->asyncns_query); start_timeout(c); } -#else +#else /* HAVE_LIBASYNCNS */ { +#ifdef HAVE_GETADDRINFO int ret; struct addrinfo *res = NULL; @@ -438,12 +464,37 @@ struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, if (res->ai_addr) { if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen))) - start_timeout(c); + start_timeout(c); } freeaddrinfo(res); +#else /* HAVE_GETADDRINFO */ + struct hostent *host = NULL; + struct sockaddr_in s; + + /* FIXME: PF_INET6 support */ + if (hints.ai_family != PF_INET) + goto finish; + + host = gethostbyname(a.path_or_host); + if (!host) { + unsigned int addr = inet_addr(a.path_or_host); + if (addr != INADDR_NONE) + host = gethostbyaddr((char*)&addr, 4, AF_INET); + } + + if (!host) + goto finish; + + s.sin_family = AF_INET; + memcpy(&s.sin_addr, host->h_addr, sizeof(struct in_addr)); + s.sin_port = port; + + if ((c = pa_socket_client_new_sockaddr(m, &s, sizeof(s)))) + start_timeout(c); +#endif /* HAVE_GETADDRINFO */ } -#endif +#endif /* HAVE_LIBASYNCNS */ } } diff --git a/polyp/socket-client.h b/polyp/socket-client.h index 9c3e0b37..b8c73ed8 100644 --- a/polyp/socket-client.h +++ b/polyp/socket-client.h @@ -23,11 +23,12 @@ ***/ #include -#include #include "mainloop-api.h" #include "iochannel.h" +struct sockaddr; + struct pa_socket_client; struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port); diff --git a/polyp/socket-server.c b/polyp/socket-server.c index e67a9daa..a78f04cd 100644 --- a/polyp/socket-server.c +++ b/polyp/socket-server.c @@ -28,17 +28,36 @@ #include #include #include -#include #include #include + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_SYS_UN_H #include -#include +#ifndef SUN_LEN +#define SUN_LEN(ptr) \ + ((size_t)(((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path)) +#endif +#endif +#ifdef HAVE_ARPA_INET_H #include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif #ifdef HAVE_LIBWRAP #include #endif +#ifndef HAVE_INET_NTOP +#include "inet_ntop.h" +#endif + +#include "winsock.h" + #include "socket-server.h" #include "socket-util.h" #include "xmalloc.h" @@ -137,6 +156,8 @@ struct pa_socket_server* pa_socket_server_ref(struct pa_socket_server *s) { return s; } +#ifdef HAVE_SYS_UN_H + struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename) { int fd = -1; struct sockaddr_un sa; @@ -144,14 +165,14 @@ struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, co assert(m && filename); - if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { pa_log(__FILE__": socket(): %s\n", strerror(errno)); goto fail; } pa_fd_set_cloexec(fd, 1); - sa.sun_family = AF_LOCAL; + sa.sun_family = AF_UNIX; strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); sa.sun_path[sizeof(sa.sun_path) - 1] = 0; @@ -182,6 +203,14 @@ fail: return NULL; } +#else /* HAVE_SYS_UN_H */ + +struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename) { + return NULL; +} + +#endif /* HAVE_SYS_UN_H */ + struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service) { struct pa_socket_server *ss; int fd = -1; @@ -197,7 +226,7 @@ struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, ui pa_fd_set_cloexec(fd, 1); - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0) pa_log(__FILE__": setsockopt(): %s\n", strerror(errno)); pa_socket_tcp_low_delay(fd); @@ -246,7 +275,7 @@ struct pa_socket_server* pa_socket_server_new_ipv6(struct pa_mainloop_api *m, ui pa_fd_set_cloexec(fd, 1); - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0) pa_log(__FILE__": setsockopt(): %s\n", strerror(errno)); pa_socket_tcp_low_delay(fd); @@ -314,9 +343,9 @@ char *pa_socket_server_get_address(struct pa_socket_server *s, char *c, size_t l switch (s->type) { case SOCKET_SERVER_IPV6: { struct sockaddr_in6 sa; - socklen_t l = sizeof(sa); + socklen_t sa_len = sizeof(sa); - if (getsockname(s->fd, (struct sockaddr*) &sa, &l) < 0) { + if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) { pa_log(__FILE__": getsockname() failed: %s\n", strerror(errno)); return NULL; } @@ -350,9 +379,9 @@ char *pa_socket_server_get_address(struct pa_socket_server *s, char *c, size_t l case SOCKET_SERVER_IPV4: { struct sockaddr_in sa; - socklen_t l = sizeof(sa); + socklen_t sa_len = sizeof(sa); - if (getsockname(s->fd, &sa, &l) < 0) { + if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) { pa_log(__FILE__": getsockname() failed: %s\n", strerror(errno)); return NULL; } diff --git a/polyp/socket-util.c b/polyp/socket-util.c index 495ee1b0..381502b5 100644 --- a/polyp/socket-util.c +++ b/polyp/socket-util.c @@ -31,16 +31,33 @@ #include #include #include -#include -#include #include #include +#include + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN_SYSTM_H #include -#include +#endif +#ifdef HAVE_NETINET_IP_H #include -#include -#include +#endif +#ifdef HAVE_NETINET_TCP_H +#include +#endif +#ifdef HAVE_NETDB_H #include +#endif + +#include "winsock.h" #include "socket-util.h" #include "util.h" @@ -57,6 +74,7 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) { return; } +#ifndef OS_IS_WIN32 if (S_ISSOCK(st.st_mode)) { union { struct sockaddr sa; @@ -77,7 +95,7 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) { ip & 0xFF, ntohs(sa.in.sin_port)); return; - } else if (sa.sa.sa_family == AF_LOCAL) { + } else if (sa.sa.sa_family == AF_UNIX) { snprintf(c, l, "UNIX socket client"); return; } @@ -89,17 +107,18 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) { snprintf(c, l, "STDIN/STDOUT client"); return; } +#endif /* OS_IS_WIN32 */ snprintf(c, l, "Unknown client"); } int pa_socket_low_delay(int fd) { +#ifdef SO_PRIORITY int priority; assert(fd >= 0); -#ifdef SO_PRIORITY priority = 7; - if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) + if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (void*)&priority, sizeof(priority)) < 0) return -1; #endif @@ -114,12 +133,13 @@ int pa_socket_tcp_low_delay(int fd) { ret = pa_socket_low_delay(fd); on = 1; + tos = 0; #if defined(SOL_TCP) || defined(IPPROTO_TCP) #if defined(SOL_TCP) - if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) + if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0) #else - if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0) #endif ret = -1; #endif @@ -128,9 +148,9 @@ int pa_socket_tcp_low_delay(int fd) { defined(IPPROTO_IP)) tos = IPTOS_LOWDELAY; #ifdef SOL_IP - if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0) + if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) #else - if (setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) + if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) #endif ret = -1; #endif @@ -142,7 +162,7 @@ int pa_socket_tcp_low_delay(int fd) { int pa_socket_set_rcvbuf(int fd, size_t l) { assert(fd >= 0); -/* if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &l, sizeof(l)) < 0) { */ +/* if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&l, sizeof(l)) < 0) { */ /* pa_log(__FILE__": SO_RCVBUF: %s\n", strerror(errno)); */ /* return -1; */ /* } */ @@ -153,7 +173,7 @@ int pa_socket_set_rcvbuf(int fd, size_t l) { int pa_socket_set_sndbuf(int fd, size_t l) { assert(fd >= 0); -/* if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &l, sizeof(l)) < 0) { */ +/* if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&l, sizeof(l)) < 0) { */ /* pa_log(__FILE__": SO_SNDBUF: %s\n", strerror(errno)); */ /* return -1; */ /* } */ @@ -161,16 +181,18 @@ int pa_socket_set_sndbuf(int fd, size_t l) { return 0; } +#ifdef HAVE_SYS_UN_H + int pa_unix_socket_is_stale(const char *fn) { struct sockaddr_un sa; int fd = -1, ret = -1; - if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { pa_log(__FILE__": socket(): %s\n", strerror(errno)); goto finish; } - sa.sun_family = AF_LOCAL; + sa.sun_family = AF_UNIX; strncpy(sa.sun_path, fn, sizeof(sa.sun_path)-1); sa.sun_path[sizeof(sa.sun_path) - 1] = 0; @@ -202,3 +224,15 @@ int pa_unix_socket_remove_stale(const char *fn) { return 0; } + +#else /* HAVE_SYS_UN_H */ + +int pa_unix_socket_is_stale(const char *fn) { + return -1; +} + +int pa_unix_socket_remove_stale(const char *fn) { + return -1; +} + +#endif /* HAVE_SYS_UN_H */ diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c index a6dad868..1ff09cd1 100644 --- a/polyp/tagstruct.c +++ b/polyp/tagstruct.c @@ -27,9 +27,14 @@ #include #include #include -#include #include +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#include "winsock.h" + #include "tagstruct.h" #include "xmalloc.h" @@ -118,7 +123,8 @@ void pa_tagstruct_putu32(struct pa_tagstruct*t, uint32_t i) { assert(t); extend(t, 5); t->data[t->length] = TAG_U32; - *((uint32_t*) (t->data+t->length+1)) = htonl(i); + i = htonl(i); + memcpy(t->data+t->length+1, &i, 4); t->length += 5; } @@ -131,21 +137,25 @@ void pa_tagstruct_putu8(struct pa_tagstruct*t, uint8_t c) { } void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample_spec *ss) { + uint32_t rate; assert(t && ss); extend(t, 7); t->data[t->length] = TAG_SAMPLE_SPEC; t->data[t->length+1] = (uint8_t) ss->format; t->data[t->length+2] = ss->channels; - *(uint32_t*) (t->data+t->length+3) = htonl(ss->rate); + rate = htonl(ss->rate); + memcpy(t->data+t->length+3, &rate, 4); t->length += 7; } void pa_tagstruct_put_arbitrary(struct pa_tagstruct *t, const void *p, size_t length) { + uint32_t tmp; assert(t && p); extend(t, 5+length); t->data[t->length] = TAG_ARBITRARY; - *((uint32_t*) (t->data+t->length+1)) = htonl(length); + tmp = htonl(length); + memcpy(t->data+t->length+1, &tmp, 4); if (length) memcpy(t->data+t->length+5, p, length); t->length += 5+length; @@ -159,29 +169,38 @@ void pa_tagstruct_put_boolean(struct pa_tagstruct*t, int b) { } void pa_tagstruct_put_timeval(struct pa_tagstruct*t, const struct timeval *tv) { + uint32_t tmp; assert(t); extend(t, 9); t->data[t->length] = TAG_TIMEVAL; - *((uint32_t*) (t->data+t->length+1)) = htonl(tv->tv_sec); - *((uint32_t*) (t->data+t->length+5)) = htonl(tv->tv_usec); + tmp = htonl(tv->tv_sec); + memcpy(t->data+t->length+1, &tmp, 4); + tmp = htonl(tv->tv_usec); + memcpy(t->data+t->length+5, &tmp, 4); t->length += 9; } void pa_tagstruct_put_usec(struct pa_tagstruct*t, pa_usec_t u) { + uint32_t tmp; assert(t); extend(t, 9); t->data[t->length] = TAG_USEC; - *((uint32_t*) (t->data+t->length+1)) = htonl((uint32_t) (u >> 32)); - *((uint32_t*) (t->data+t->length+5)) = htonl((uint32_t) u); + tmp = htonl((uint32_t) (u >> 32)); + memcpy(t->data+t->length+1, &tmp, 4); + tmp = htonl((uint32_t) u); + memcpy(t->data+t->length+5, &tmp, 4); t->length += 9; } void pa_tagstruct_putu64(struct pa_tagstruct*t, uint64_t u) { + uint32_t tmp; assert(t); extend(t, 9); t->data[t->length] = TAG_U64; - *((uint32_t*) (t->data+t->length+1)) = htonl((uint32_t) (u >> 32)); - *((uint32_t*) (t->data+t->length+5)) = htonl((uint32_t) u); + tmp = htonl((uint32_t) (u >> 32)); + memcpy(t->data+t->length+1, &tmp, 4); + tmp = htonl((uint32_t) u); + memcpy(t->data+t->length+5, &tmp, 4); t->length += 9; } @@ -230,8 +249,9 @@ int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i) { if (t->data[t->rindex] != TAG_U32) return -1; - - *i = ntohl(*((uint32_t*) (t->data+t->rindex+1))); + + memcpy(i, t->data+t->rindex+1, 4); + *i = ntohl(*i); t->rindex += 5; return 0; } @@ -261,13 +281,15 @@ int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec * ss->format = t->data[t->rindex+1]; ss->channels = t->data[t->rindex+2]; - ss->rate = ntohl(*(uint32_t*) (t->data+t->rindex+3)); + memcpy(&ss->rate, t->data+t->rindex+3, 4); + ss->rate = ntohl(ss->rate); t->rindex += 7; return 0; } int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t length) { + uint32_t len; assert(t && p); if (t->rindex+5+length > t->length) @@ -276,7 +298,8 @@ int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t le if (t->data[t->rindex] != TAG_ARBITRARY) return -1; - if (ntohl(*((uint32_t*) (t->data+t->rindex+1))) != length) + memcpy(&len, t->data+t->rindex+1, 4); + if (ntohl(len) != length) return -1; *p = t->data+t->rindex+5; @@ -319,15 +342,18 @@ int pa_tagstruct_get_timeval(struct pa_tagstruct*t, struct timeval *tv) { if (t->data[t->rindex] != TAG_TIMEVAL) return -1; - - tv->tv_sec = ntohl(*((uint32_t*) (t->data+t->rindex+1))); - tv->tv_usec = ntohl(*((uint32_t*) (t->data+t->rindex+5))); + + memcpy(&tv->tv_sec, t->data+t->rindex+1, 4); + tv->tv_sec = ntohl(tv->tv_sec); + memcpy(&tv->tv_usec, t->data+t->rindex+5, 4); + tv->tv_usec = ntohl(tv->tv_usec); t->rindex += 9; return 0; } int pa_tagstruct_get_usec(struct pa_tagstruct*t, pa_usec_t *u) { + uint32_t tmp; assert(t && u); if (t->rindex+9 > t->length) @@ -336,13 +362,16 @@ int pa_tagstruct_get_usec(struct pa_tagstruct*t, pa_usec_t *u) { if (t->data[t->rindex] != TAG_USEC) return -1; - *u = (pa_usec_t) ntohl(*((uint32_t*) (t->data+t->rindex+1))) << 32; - *u |= (pa_usec_t) ntohl(*((uint32_t*) (t->data+t->rindex+5))); + memcpy(&tmp, t->data+t->rindex+1, 4); + *u = (pa_usec_t) ntohl(tmp) << 32; + memcpy(&tmp, t->data+t->rindex+5, 4); + *u |= (pa_usec_t) ntohl(tmp); t->rindex +=9; return 0; } int pa_tagstruct_getu64(struct pa_tagstruct*t, uint64_t *u) { + uint32_t tmp; assert(t && u); if (t->rindex+9 > t->length) @@ -351,8 +380,10 @@ int pa_tagstruct_getu64(struct pa_tagstruct*t, uint64_t *u) { if (t->data[t->rindex] != TAG_U64) return -1; - *u = (uint64_t) ntohl(*((uint32_t*) (t->data+t->rindex+1))) << 32; - *u |= (uint64_t) ntohl(*((uint32_t*) (t->data+t->rindex+5))); + memcpy(&tmp, t->data+t->rindex+1, 4); + *u = (pa_usec_t) ntohl(tmp) << 32; + memcpy(&tmp, t->data+t->rindex+5, 4); + *u |= (pa_usec_t) ntohl(tmp); t->rindex +=9; return 0; } diff --git a/polyp/util.c b/polyp/util.c index ee3fa87d..26d71203 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -32,35 +32,98 @@ #include #include #include +#include +#include +#include #include #include -#include -#include -#include #include + +#ifdef HAVE_SCHED_H #include +#endif + +#ifdef HAVE_SYS_RESOURCE_H #include -#include -#include -#include +#endif + +#ifdef HAVE_PTHREAD +#include +#endif + +#ifdef HAVE_NETDB_H #include +#endif + +#ifdef HAVE_WINDOWS_H +#include +#endif #include +#ifdef HAVE_PWD_H +#include +#endif +#ifdef HAVE_GRP_H +#include +#endif + +#include "winsock.h" + #include "util.h" #include "xmalloc.h" #include "log.h" +#ifndef OS_IS_WIN32 #define PA_RUNTIME_PATH_PREFIX "/tmp/polypaudio-" +#define PATH_SEP '/' +#else +#define PA_RUNTIME_PATH_PREFIX "%TEMP%\\polypaudio-" +#define PATH_SEP '\\' +#endif + +#ifdef OS_IS_WIN32 + +#define POLYP_ROOTENV "POLYP_ROOT" + +int pa_set_root(HANDLE handle) { + char library_path[MAX_PATH + sizeof(POLYP_ROOTENV) + 1], *sep; + + strcpy(library_path, POLYP_ROOTENV "="); + + if (!GetModuleFileName(handle, library_path + sizeof(POLYP_ROOTENV), MAX_PATH)) + return 0; + + sep = strrchr(library_path, '\\'); + if (sep) + *sep = '\0'; + + if (_putenv(library_path) < 0) + return 0; + + return 1; +} + +#endif /** Make a file descriptor nonblock. Doesn't do any error checking */ void pa_make_nonblock_fd(int fd) { +#ifdef O_NONBLOCK int v; assert(fd >= 0); if ((v = fcntl(fd, F_GETFL)) >= 0) if (!(v & O_NONBLOCK)) fcntl(fd, F_SETFL, v|O_NONBLOCK); +#elif defined(OS_IS_WIN32) + u_long arg = 1; + if (ioctlsocket(fd, FIONBIO, &arg) < 0) { + if (WSAGetLastError() == WSAENOTSOCK) + pa_log_warn(__FILE__": WARNING: Only sockets can be made non-blocking!\n"); + } +#else + pa_log_warn(__FILE__": WARNING: Non-blocking I/O not supported.!\n"); +#endif } /** Creates a directory securely */ @@ -68,15 +131,27 @@ int pa_make_secure_dir(const char* dir) { struct stat st; assert(dir); - if (mkdir(dir, 0700) < 0) +#ifdef OS_IS_WIN32 + if (mkdir(dir) < 0) +#else + if (mkdir(dir, 0700) < 0) +#endif if (errno != EEXIST) return -1; - - if (lstat(dir, &st) < 0) + +#ifdef HAVE_LSTAT + if (lstat(dir, &st) < 0) +#else + if (stat(dir, &st) < 0) +#endif goto fail; - + +#ifndef OS_IS_WIN32 if (!S_ISDIR(st.st_mode) || (st.st_uid != getuid()) || ((st.st_mode & 0777) != 0700)) goto fail; +#else + fprintf(stderr, "FIXME: pa_make_secure_dir()\n"); +#endif return 0; @@ -89,10 +164,11 @@ fail: int pa_make_secure_parent_dir(const char *fn) { int ret = -1; char *slash, *dir = pa_xstrdup(fn); - - if (!(slash = strrchr(dir, '/'))) + + slash = pa_path_get_filename(dir); + if (slash == fn) goto finish; - *slash = 0; + *(slash-1) = 0; if (pa_make_secure_dir(dir) < 0) goto finish; @@ -153,6 +229,7 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size) { /* Print a warning messages in case that the given signal is not * blocked or trapped */ void pa_check_signal_is_blocked(int sig) { +#ifdef HAVE_SIGACTION struct sigaction sa; sigset_t set; @@ -185,6 +262,9 @@ void pa_check_signal_is_blocked(int sig) { return; pa_log(__FILE__": WARNING: %s is not trapped. This might cause malfunction!\n", pa_strsignal(sig)); +#else /* HAVE_SIGACTION */ + pa_log(__FILE__": WARNING: %s might not be trapped. This might cause malfunction!\n", pa_strsignal(sig)); +#endif } /* The following function is based on an example from the GNU libc @@ -240,30 +320,47 @@ char *pa_vsprintf_malloc(const char *format, va_list ap) { /* Return the current username in the specified string buffer. */ char *pa_get_user_name(char *s, size_t l) { - struct passwd pw, *r; - char buf[1024]; char *p; + char buf[1024]; + +#ifdef HAVE_PWD_H + struct passwd pw, *r; +#endif + assert(s && l > 0); if (!(p = getenv("USER")) && !(p = getenv("LOGNAME")) && !(p = getenv("USERNAME"))) { +#ifdef HAVE_PWD_H #ifdef HAVE_GETPWUID_R if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { #else - /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) - * that do not support getpwuid_r. */ - if ((r = getpwuid(getuid())) == NULL) { + /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) + * that do not support getpwuid_r. */ + if ((r = getpwuid(getuid())) == NULL) { #endif - snprintf(s, l, "%lu", (unsigned long) getuid()); - return s; - } - - p = r->pw_name; + snprintf(s, l, "%lu", (unsigned long) getuid()); + return s; } + + p = r->pw_name; - return pa_strlcpy(s, p, l); +#elif defined(OS_IS_WIN32) /* HAVE_PWD_H */ + DWORD size = sizeof(buf); + + if (!GetUserName(buf, &size)) + return NULL; + + p = buf; + +#else /* HAVE_PWD_H */ + return NULL; +#endif /* HAVE_PWD_H */ } + return pa_strlcpy(s, p, l); +} + /* Return the current hostname in the specified buffer. */ char *pa_get_host_name(char *s, size_t l) { assert(s && l > 0); @@ -278,19 +375,37 @@ char *pa_get_host_name(char *s, size_t l) { /* Return the home directory of the current user */ char *pa_get_home_dir(char *s, size_t l) { char *e; + +#ifdef HAVE_PWD_H char buf[1024]; struct passwd pw, *r; +#endif + assert(s && l); if ((e = getenv("HOME"))) return pa_strlcpy(s, e, l); + if ((e = getenv("USERPROFILE"))) + return pa_strlcpy(s, e, l); + +#ifdef HAVE_PWD_H +#ifdef HAVE_GETPWUID_R if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { pa_log(__FILE__": getpwuid_r() failed\n"); +#else + /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) + * that do not support getpwuid_r. */ + if ((r = getpwuid(getuid())) == NULL) { + pa_log(__FILE__": getpwuid_r() failed\n"); +#endif return NULL; } return pa_strlcpy(s, r->pw_dir, l); +#else /* HAVE_PWD_H */ + return NULL; +#endif } /* Similar to OpenBSD's strlcpy() function */ @@ -302,6 +417,42 @@ char *pa_strlcpy(char *b, const char *s, size_t l) { return b; } +int pa_gettimeofday(struct timeval *tv) { +#ifdef HAVE_GETTIMEOFDAY + return gettimeofday(tv, NULL); +#elif defined(OS_IS_WIN32) + /* + * Copied from implementation by Steven Edwards (LGPL). + * Found on wine mailing list. + */ + +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define EPOCHFILETIME (116444736000000000i64) +#else +#define EPOCHFILETIME (116444736000000000LL) +#endif + + FILETIME ft; + LARGE_INTEGER li; + __int64 t; + + if (tv) { + GetSystemTimeAsFileTime(&ft); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + t = li.QuadPart; /* In 100-nanosecond intervals */ + t -= EPOCHFILETIME; /* Offset to the Epoch time */ + t /= 10; /* In microseconds */ + tv->tv_sec = (long)(t / 1000000); + tv->tv_usec = (long)(t % 1000000); + } + + return 0; +#else +#error "Platform lacks gettimeofday() or equivalent function." +#endif +} + /* Calculate the difference between the two specfified timeval * timestamsps. */ pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { @@ -351,7 +502,7 @@ int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { pa_usec_t pa_timeval_age(const struct timeval *tv) { struct timeval now; assert(tv); - gettimeofday(&now, NULL); + pa_gettimeofday(&now); return pa_timeval_diff(&now, tv); } @@ -380,10 +531,12 @@ sensible: set the nice level to -15 and enable realtime scheduling if supported.*/ void pa_raise_priority(void) { +#ifdef HAVE_SYS_RESOURCE_H if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) pa_log_warn(__FILE__": setpriority() failed: %s\n", strerror(errno)); else pa_log_info(__FILE__": Successfully gained nice level %i.\n", NICE_LEVEL); +#endif #ifdef _POSIX_PRIORITY_SCHEDULING { @@ -403,10 +556,21 @@ void pa_raise_priority(void) { pa_log_info(__FILE__": Successfully enabled SCHED_FIFO scheduling.\n"); } #endif + +#ifdef OS_IS_WIN32 + if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) + pa_log_warn(__FILE__": SetPriorityClass() failed: 0x%08X\n", GetLastError()); + else + pa_log_info(__FILE__": Successfully gained high priority class.\n"); +#endif } /* Reset the priority to normal, inverting the changes made by pa_raise_priority() */ void pa_reset_priority(void) { +#ifdef OS_IS_WIN32 + SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); +#endif + #ifdef _POSIX_PRIORITY_SCHEDULING { struct sched_param sp; @@ -416,11 +580,15 @@ void pa_reset_priority(void) { } #endif +#ifdef HAVE_SYS_RESOURCE_H setpriority(PRIO_PROCESS, 0, 0); +#endif } /* Set the FD_CLOEXEC flag for a fd */ int pa_fd_set_cloexec(int fd, int b) { + +#ifdef FD_CLOEXEC int v; assert(fd >= 0); @@ -431,7 +599,8 @@ int pa_fd_set_cloexec(int fd, int b) { if (fcntl(fd, F_SETFD, v) < 0) return -1; - +#endif + return 0; } @@ -439,6 +608,8 @@ int pa_fd_set_cloexec(int fd, int b) { * only. This shoul be used for eyecandy only, don't rely on return * non-NULL! */ char *pa_get_binary_name(char *s, size_t l) { + +#ifdef HAVE_READLINK char path[PATH_MAX]; int i; assert(s && l); @@ -451,6 +622,15 @@ char *pa_get_binary_name(char *s, size_t l) { s[i] = 0; return s; +#elif defined(OS_IS_WIN32) + char path[PATH_MAX]; + if (!GetModuleFileName(NULL, path, PATH_MAX)) + return NULL; + pa_strlcpy(s, pa_path_get_filename(path), l); + return s; +#else + return NULL; +#endif } /* Return a pointer to the filename inside a path (which is the last @@ -458,7 +638,7 @@ char *pa_get_binary_name(char *s, size_t l) { char *pa_path_get_filename(const char *p) { char *fn; - if ((fn = strrchr(p, '/'))) + if ((fn = strrchr(p, PATH_SEP))) return fn+1; return (char*) p; @@ -519,16 +699,29 @@ const char *pa_strsignal(int sig) { switch(sig) { case SIGINT: return "SIGINT"; case SIGTERM: return "SIGTERM"; +#ifdef SIGUSR1 case SIGUSR1: return "SIGUSR1"; +#endif +#ifdef SIGUSR2 case SIGUSR2: return "SIGUSR2"; +#endif +#ifdef SIGXCPU case SIGXCPU: return "SIGXCPU"; +#endif +#ifdef SIGPIPE case SIGPIPE: return "SIGPIPE"; +#endif +#ifdef SIGCHLD case SIGCHLD: return "SIGCHLD"; +#endif +#ifdef SIGHUP case SIGHUP: return "SIGHUP"; +#endif default: return "UNKNOWN SIGNAL"; } } +#ifdef HAVE_GRP_H /* Check whether the specified GID and the group name match */ static int is_group(gid_t gid, const char *name) { @@ -575,7 +768,7 @@ finish: /* Check the current user is member of the specified group */ int pa_uid_in_group(const char *name, gid_t *gid) { gid_t *gids, tgid; - long n = sysconf(_SC_NGROUPS_MAX); + GETGROUPS_T n = sysconf(_SC_NGROUPS_MAX); int r = -1, i; assert(n > 0); @@ -609,8 +802,18 @@ finish: return r; } -/* Lock or unlock a file entirely. (advisory) */ +#else /* HAVE_GRP_H */ + +int pa_uid_in_group(const char *name, gid_t *gid) { + return -1; +} + +#endif + +/* Lock or unlock a file entirely. + (advisory on UNIX, mandatory on Windows) */ int pa_lock_fd(int fd, int b) { +#ifdef F_SETLKW struct flock flock; /* Try a R/W lock first */ @@ -631,6 +834,19 @@ int pa_lock_fd(int fd, int b) { } pa_log(__FILE__": %slock failed: %s\n", !b ? "un" : "", strerror(errno)); +#endif + +#ifdef OS_IS_WIN32 + HANDLE h = (HANDLE)_get_osfhandle(fd); + + if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) + return 0; + if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) + return 0; + + pa_log(__FILE__": %slock failed: 0x%08X\n", !b ? "un" : "", GetLastError()); +#endif + return -1; } @@ -722,31 +938,51 @@ int pa_unlock_lockfile(const char *fn, int fd) { * allocated buffer containing the used configuration file is * stored there.*/ FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result) { - const char *e; + const char *fn; char h[PATH_MAX]; - if (env && (e = getenv(env))) { +#ifdef OS_IS_WIN32 + char buf[PATH_MAX]; + + if (!getenv(POLYP_ROOTENV)) + pa_set_root(NULL); +#endif + + if (env && (fn = getenv(env))) { +#ifdef OS_IS_WIN32 + if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX)) + return NULL; + fn = buf; +#endif + if (result) - *result = pa_xstrdup(e); - return fopen(e, "r"); + *result = pa_xstrdup(fn); + + return fopen(fn, "r"); } if (local && pa_get_home_dir(h, sizeof(h))) { FILE *f; - char *l; + char *lfn; - l = pa_sprintf_malloc("%s/%s", h, local); - f = fopen(l, "r"); + lfn = pa_sprintf_malloc("%s/%s", h, local); + +#ifdef OS_IS_WIN32 + if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) + return NULL; + lfn = buf; +#endif + + f = fopen(lfn, "r"); if (f || errno != ENOENT) { if (result) - *result = l; - else - pa_xfree(l); + *result = pa_xstrdup(lfn); + pa_xfree(lfn); return f; } - pa_xfree(l); + pa_xfree(lfn); } if (!global) { @@ -756,6 +992,12 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env return NULL; } +#ifdef OS_IS_WIN32 + if (!ExpandEnvironmentStrings(global, buf, PATH_MAX)) + return NULL; + global = buf; +#endif + if (result) *result = pa_xstrdup(global); @@ -823,11 +1065,14 @@ size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) { /* Return the fully qualified domain name in *s */ char *pa_get_fqdn(char *s, size_t l) { char hn[256]; +#ifdef HAVE_GETADDRINFO struct addrinfo *a, hints; +#endif if (!pa_get_host_name(hn, sizeof(hn))) return NULL; +#ifdef HAVE_GETADDRINFO memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_flags = AI_CANONNAME; @@ -838,6 +1083,9 @@ char *pa_get_fqdn(char *s, size_t l) { pa_strlcpy(s, a->ai_canonname, l); freeaddrinfo(a); return s; +#else + return pa_strlcpy(s, hn, l); +#endif } /* Returns nonzero when *s starts with *pfx */ @@ -855,21 +1103,44 @@ int pa_startswith(const char *s, const char *pfx) { char *pa_runtime_path(const char *fn, char *s, size_t l) { char u[256]; +#ifndef OS_IS_WIN32 if (fn && *fn == '/') +#else + if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\') +#endif return pa_strlcpy(s, fn, l); - - snprintf(s, l, PA_RUNTIME_PATH_PREFIX"%s%s%s", pa_get_user_name(u, sizeof(u)), fn ? "/" : "", fn ? fn : ""); + + if (fn) + snprintf(s, l, "%s%s%c%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn); + else + snprintf(s, l, "%s%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u))); + +#ifdef OS_IS_WIN32 + { + char buf[l]; + strcpy(buf, s); + ExpandEnvironmentStrings(buf, s, l); + } +#endif + return s; } /* Wait t milliseconds */ int pa_msleep(unsigned long t) { +#ifdef OS_IS_WIN32 + Sleep(t); + return 0; +#elif defined(HAVE_NANOSLEEP) struct timespec ts; ts.tv_sec = t/1000; ts.tv_nsec = (t % 1000) * 1000000; return nanosleep(&ts, NULL); +#else +#error "Platform lacks a sleep function." +#endif } /* Convert the string s to a signed integer in *ret_i */ diff --git a/polyp/util.h b/polyp/util.h index 2cfc5f6e..d9e18ddb 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -30,6 +30,8 @@ #include "gcc-printf.h" #include "sample.h" +struct timeval; + void pa_make_nonblock_fd(int fd); int pa_make_secure_dir(const char* dir); @@ -53,6 +55,7 @@ char *pa_get_home_dir(char *s, size_t l); char *pa_path_get_filename(const char *p); +int pa_gettimeofday(struct timeval *tv); pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); pa_usec_t pa_timeval_age(const struct timeval *tv); diff --git a/polyp/winsock.h b/polyp/winsock.h new file mode 100644 index 00000000..b1e0f7d4 --- /dev/null +++ b/polyp/winsock.h @@ -0,0 +1,23 @@ +#ifndef foowinsockhfoo +#define foowinsockhfoo + +#ifdef HAVE_WINSOCK2_H +#include + +#define ESHUTDOWN WSAESHUTDOWN +#define ECONNRESET WSAECONNRESET +#define ECONNABORTED WSAECONNABORTED +#define ENETRESET WSAENETRESET +#define EINPROGRESS WSAEINPROGRESS +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define ETIMEDOUT WSAETIMEDOUT +#define ECONNREFUSED WSAECONNREFUSED +#define EHOSTUNREACH WSAEHOSTUNREACH + +#endif + +#ifdef HAVE_WS2TCPIP_H +#include +#endif + +#endif diff --git a/polyp/xmalloc.c b/polyp/xmalloc.c index 7ddefa94..f2751e52 100644 --- a/polyp/xmalloc.c +++ b/polyp/xmalloc.c @@ -45,7 +45,9 @@ static void oom(void) { static const char e[] = "Not enough memory\n"; pa_loop_write(STDERR_FILENO, e, sizeof(e)-1); +#ifdef SIGQUIT raise(SIGQUIT); +#endif _exit(1); } -- cgit From 6c512fb5a3fdb578179be79672c5096de1a1d25b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 10 Jan 2006 18:04:54 +0000 Subject: build system updates, including support for some newer GCC options git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@446 fefdeb5f-60dc-0310-8127-8f9354f1896f --- bootstrap.sh | 38 ++++++++++++++++++++++++++---------- configure.ac | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 11 deletions(-) diff --git a/bootstrap.sh b/bootstrap.sh index 4b9032b6..7fa1dc9a 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -17,17 +17,32 @@ # along with polypaudio; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +VERSION=1.9 + run_versioned() { local P - type -p "$1-$2" &> /dev/null && P="$1-$2" || local P="$1" + local V + + V=$(echo "$2" | sed -e 's,\.,,g') + + if [ -e "`which $1$V`" ] ; then + P="$1$V" + else + if [ -e "`which $1-$2`" ] ; then + P="$1-$2" + else + P="$1" + fi + fi shift 2 "$P" "$@" } +set -ex + if [ "x$1" = "xam" ] ; then - set -ex - run_versioned automake 1.7 -a -c --foreign + run_versioned automake "$VERSION" -a -c --foreign ./config.status else set -ex @@ -35,13 +50,16 @@ else rm -rf autom4te.cache rm -f config.cache - run_versioned aclocal 1.7 - libtoolize -c --force --ltdl - autoheader - run_versioned automake 1.7 -a -c --foreign - autoconf -Wall + test "x$LIBTOOLIZE" = "x" && LIBTOOLIZE=libtoolize - CFLAGS="-g -O0" ./configure --sysconfdir=/etc "$@" + "$LIBTOOLIZE" -c --force + run_versioned aclocal "$VERSION" + run_versioned autoconf 2.59 -Wall + run_versioned autoheader 2.59 + run_versioned automake "$VERSION" -a -c --foreign - make clean + if test "x$NOCONFIGURE" = "x"; then + CFLAGS="-g -O0" ./configure --sysconfdir=/etc "$@" + make clean + fi fi diff --git a/configure.ac b/configure.ac index e5e03d04..f69eb636 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ AC_PREREQ(2.57) AC_INIT([polypaudio],[0.8],[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([polyp/main.c]) AC_CONFIG_HEADERS([config.h]) -AM_INIT_AUTOMAKE([foreign -Wall]) +AM_INIT_AUTOMAKE([foreign 1.9 -Wall]) AC_SUBST(PA_MAJORMINOR, "$PACKAGE_VERSION") AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/polypaudio/]) @@ -41,6 +41,7 @@ fi AC_PROG_CC AC_PROG_GCC_TRADITIONAL +AC_GNU_SOURCE # If using GCC specify some additional parameters if test "x$GCC" = "xyes" ; then @@ -58,6 +59,54 @@ if test "x$M4" = xno ; then AC_MSG_ERROR([m4 missing]) fi +# GCC flags + +test_gcc_flag() { + AC_LANG_CONFTEST([int main() {}]) + $CC -c conftest.c $CFLAGS $@ > /dev/null 2> /dev/null + ret=$? + rm -f conftest.o + return $ret +} + +# If using GCC specify some additional parameters +if test "x$GCC" = "xyes" ; then + + DESIRED_FLAGS="-Wall -W -Wextra -pedantic -pipe -Wformat -Wold-style-definition -Wdeclaration-after-statement -Wfloat-equal -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-noreturn -Wshadow -Wendif-labels -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings -Winline" + + if test "x$HAVE_NETLINK" = "xyes" ; then + # Test whether rtnetlink.h can be included when compiled with -std=c99 + # some distributions (e.g. archlinux) have broken headers that dont + # define __u64 with -std=c99 + AC_MSG_CHECKING([checking whether rtnetlink.h can be included with -std=c99]) + OLDCFLAGS="$CFLAGS" + CFLAGS="-std=c99" + AC_TRY_COMPILE([#include ], [], + use_stdc99=yes, use_stdc99=no) + + if test x"$use_stdc99" = xyes; then + DESIRED_FLAGS="-std=c99 $DESIRED_FLAGS" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + + CFLAGS="$OLDCFLAGS" + else + DESIRED_FLAGS="-std=c99 $DESIRED_FLAGS" + fi + + for flag in $DESIRED_FLAGS ; do + AC_MSG_CHECKING([whether $CC accepts $flag]) + if test_gcc_flag $flag ; then + CFLAGS="$CFLAGS $flag" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + done +fi + # LYNX documentation generation AC_ARG_ENABLE(lynx, AC_HELP_STRING(--disable-lynx,Turn off lynx usage for documentation generation), @@ -243,6 +292,18 @@ if test "x${with_caps}" != "xno"; then fi AC_SUBST(CAP_LIBS) +#### pkg-config #### + +# Check for pkg-config manually first, as if its not installed the +# PKG_PROG_PKG_CONFIG macro won't be defined. +AC_CHECK_PROG(have_pkg_config, pkg-config, yes, no) + +if test x"$have_pkg_config" = "xno"; then + AC_MSG_ERROR(pkg-config is required to install this program) +fi + +PKG_PROG_PKG_CONFIG + #### Sample rate conversion #### PKG_CHECK_MODULES(LIBSAMPLERATE, [ samplerate >= 0.1.0 ]) -- cgit From 1f0961368f58a9fec319d86c79a86a9f0d008cf5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 11 Jan 2006 01:17:39 +0000 Subject: * remove a lot of compiler warnings introduced by using some new GCC flags * add typedefs for public structs and enums and drop the struct/enum prefixs from all uses where it makes sense git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@447 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 6 +- polyp/alsa-util.c | 10 +- polyp/alsa-util.h | 6 +- polyp/authkey-prop.c | 8 +- polyp/authkey-prop.h | 8 +- polyp/autoload.c | 54 +-- polyp/autoload.h | 22 +- polyp/cli-command.c | 196 +++++------ polyp/cli-command.h | 6 +- polyp/cli-text.c | 102 +++--- polyp/cli-text.h | 20 +- polyp/cli.c | 32 +- polyp/cli.h | 8 +- polyp/client-conf-x11.c | 2 +- polyp/client-conf-x11.h | 2 +- polyp/client-conf.c | 16 +- polyp/client-conf.h | 14 +- polyp/client.c | 12 +- polyp/client.h | 16 +- polyp/cmdline.c | 4 +- polyp/cmdline.h | 2 +- polyp/conf-parser.c | 12 +- polyp/conf-parser.h | 6 +- polyp/core.c | 18 +- polyp/core.h | 36 +- polyp/cpulimit-test.c | 7 +- polyp/cpulimit.c | 21 +- polyp/cpulimit.h | 2 +- polyp/daemon-conf.c | 38 +- polyp/daemon-conf.h | 30 +- polyp/dumpmodules.c | 12 +- polyp/dumpmodules.h | 2 +- polyp/dynarray.c | 16 +- polyp/dynarray.h | 14 +- polyp/gcc-printf.h | 33 -- polyp/gccmacro.h | 53 +++ polyp/glib-mainloop.c | 126 +++---- polyp/glib-mainloop.h | 12 +- polyp/glib12-mainloop.c | 123 +++---- polyp/hashmap.c | 22 +- polyp/hashmap.h | 16 +- polyp/howl-wrap.c | 28 +- polyp/howl-wrap.h | 10 +- polyp/idxset.c | 124 +++---- polyp/idxset.h | 41 +-- polyp/iochannel.c | 88 +++-- polyp/iochannel.h | 29 +- polyp/ioline.c | 54 +-- polyp/ioline.h | 18 +- polyp/log.c | 26 +- polyp/log.h | 20 +- polyp/main.c | 20 +- polyp/mainloop-api.c | 13 +- polyp/mainloop-api.h | 48 +-- polyp/mainloop-signal.c | 41 +-- polyp/mainloop-signal.h | 12 +- polyp/mainloop-test.c | 24 +- polyp/mainloop.c | 168 ++++----- polyp/mainloop.h | 19 +- polyp/mcalign-test.c | 9 +- polyp/mcalign.c | 16 +- polyp/mcalign.h | 16 +- polyp/memblock.c | 38 +- polyp/memblock.h | 49 ++- polyp/memblockq.c | 54 +-- polyp/memblockq.h | 42 +-- polyp/memchunk.c | 6 +- polyp/memchunk.h | 12 +- polyp/modargs.c | 32 +- polyp/modargs.h | 16 +- polyp/modinfo.c | 12 +- polyp/modinfo.h | 10 +- polyp/module-alsa-sink.c | 26 +- polyp/module-alsa-source.c | 24 +- polyp/module-cli.c | 10 +- polyp/module-combine.c | 42 +-- polyp/module-defs.h.m4 | 5 + polyp/module-esound-compat-spawnfd.c | 6 +- polyp/module-esound-compat-spawnpid.c | 6 +- polyp/module-esound-sink.c | 34 +- polyp/module-lirc.c | 14 +- polyp/module-match.c | 14 +- polyp/module-mmkbd-evdev.c | 24 +- polyp/module-native-protocol-fd.c | 8 +- polyp/module-null-sink.c | 20 +- polyp/module-oss-mmap.c | 36 +- polyp/module-oss.c | 36 +- polyp/module-pipe-sink.c | 30 +- polyp/module-pipe-source.c | 24 +- polyp/module-protocol-stub.c | 14 +- polyp/module-sine.c | 24 +- polyp/module-solaris.c | 38 +- polyp/module-tunnel.c | 72 ++-- polyp/module-waveout.c | 46 +-- polyp/module-x11-bell.c | 16 +- polyp/module-x11-publish.c | 12 +- polyp/module-zeroconf-publish.c | 50 +-- polyp/module.c | 53 +-- polyp/module.h | 24 +- polyp/namereg.c | 36 +- polyp/namereg.h | 18 +- polyp/oss-util.c | 2 +- polyp/oss-util.h | 2 +- polyp/pabrowse.c | 12 +- polyp/pacat-simple.c | 7 +- polyp/pacat.c | 36 +- polyp/packet.c | 16 +- polyp/packet.h | 12 +- polyp/pacmd.c | 2 +- polyp/pactl.c | 44 +-- polyp/paplay.c | 33 +- polyp/parec-simple.c | 9 +- polyp/parseaddr.c | 4 +- polyp/parseaddr.h | 12 +- polyp/pax11publish.c | 22 +- polyp/pdispatch.c | 52 +-- polyp/pdispatch.h | 23 +- polyp/play-memchunk.c | 23 +- polyp/play-memchunk.h | 2 +- polyp/polyplib-browser.c | 38 +- polyp/polyplib-browser.h | 16 +- polyp/polyplib-context.c | 166 ++++----- polyp/polyplib-context.h | 38 +- polyp/polyplib-def.h | 40 +-- polyp/polyplib-internal.h | 94 ++--- polyp/polyplib-introspect.c | 373 ++++++++++---------- polyp/polyplib-introspect.h | 124 +++---- polyp/polyplib-operation.c | 22 +- polyp/polyplib-operation.h | 12 +- polyp/polyplib-scache.c | 24 +- polyp/polyplib-scache.h | 8 +- polyp/polyplib-simple.c | 130 +++---- polyp/polyplib-simple.h | 24 +- polyp/polyplib-stream.c | 160 ++++----- polyp/polyplib-stream.h | 58 +-- polyp/polyplib-subscribe.c | 17 +- polyp/polyplib-subscribe.h | 4 +- polyp/props.c | 36 +- polyp/props.h | 14 +- polyp/protocol-cli.c | 30 +- polyp/protocol-cli.h | 6 +- polyp/protocol-esound.c | 193 +++++----- polyp/protocol-esound.h | 6 +- polyp/protocol-http.c | 38 +- polyp/protocol-http.h | 6 +- polyp/protocol-native.c | 640 +++++++++++++++++----------------- polyp/protocol-native.h | 8 +- polyp/protocol-simple.c | 68 ++-- polyp/protocol-simple.h | 6 +- polyp/pstream-util.c | 12 +- polyp/pstream-util.h | 6 +- polyp/pstream.c | 86 +++-- polyp/pstream.h | 24 +- polyp/queue.c | 14 +- polyp/queue.h | 12 +- polyp/resampler.c | 52 +-- polyp/resampler.h | 22 +- polyp/sample-util.c | 12 +- polyp/sample-util.h | 16 +- polyp/sample.c | 16 +- polyp/sample.h | 26 +- polyp/scache.c | 83 ++--- polyp/scache.h | 32 +- polyp/sconv-s16be.c | 3 +- polyp/sconv-s16le.c | 1 + polyp/sconv.c | 8 +- polyp/sconv.h | 4 +- polyp/sink-input.c | 38 +- polyp/sink-input.h | 56 +-- polyp/sink.c | 55 ++- polyp/sink.h | 49 +-- polyp/socket-client.c | 74 ++-- polyp/socket-client.h | 20 +- polyp/socket-server.c | 42 +-- polyp/socket-server.h | 18 +- polyp/sound-file-stream.c | 16 +- polyp/sound-file-stream.h | 2 +- polyp/sound-file.c | 4 +- polyp/sound-file.h | 2 +- polyp/source-output.c | 32 +- polyp/source-output.h | 44 +-- polyp/source.c | 30 +- polyp/source.h | 39 ++- polyp/strbuf.c | 18 +- polyp/strbuf.h | 18 +- polyp/strlist-test.c | 5 +- polyp/strlist.c | 34 +- polyp/strlist.h | 14 +- polyp/subscribe.c | 49 ++- polyp/subscribe.h | 14 +- polyp/tagstruct.c | 52 +-- polyp/tagstruct.h | 56 +-- polyp/tokenizer.c | 17 +- polyp/tokenizer.h | 8 +- polyp/util.c | 8 +- polyp/util.h | 2 +- polyp/voltest.c | 3 +- polyp/x11wrap.c | 90 ++--- polyp/x11wrap.h | 16 +- polyp/xmalloc.c | 4 + polyp/xmalloc.h | 20 ++ 201 files changed, 3603 insertions(+), 3489 deletions(-) delete mode 100644 polyp/gcc-printf.h create mode 100644 polyp/gccmacro.h diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 22e8da3d..8712782f 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -42,7 +42,7 @@ endif # Compiler/linker flags # ################################### -AM_CFLAGS = -D_GNU_SOURCE -I$(top_srcdir) +AM_CFLAGS = -I$(top_srcdir) AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS AM_CFLAGS += $(LTDLINCL) AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) @@ -224,12 +224,12 @@ voltest_CFLAGS = $(AM_CFLAGS) voltest_LDADD = $(AM_LDADD) voltest_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h +cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h idxset.c idxset.h cpulimit_test_CFLAGS = $(AM_CFLAGS) cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la cpulimit_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -cpulimit_test2_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h +cpulimit_test2_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h idxset.c idxset.h cpulimit_test2_CFLAGS = $(AM_CFLAGS) -DTEST2 cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la cpulimit_test2_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) diff --git a/polyp/alsa-util.c b/polyp/alsa-util.c index 2894c9e8..73f3be7d 100644 --- a/polyp/alsa-util.c +++ b/polyp/alsa-util.c @@ -33,7 +33,7 @@ /* Set the hardware parameters of the given ALSA device. Returns the * selected fragment settings in *period and *period_size */ -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const struct pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { int ret = -1; snd_pcm_uframes_t buffer_size; snd_pcm_hw_params_t *hwparams = NULL; @@ -85,10 +85,10 @@ finish: * *io_events. Store the length of that array in *n_io_events. Use the * specified callback function and userdata. The array has to be freed * with pa_free_io_events(). */ -int pa_create_io_events(snd_pcm_t *pcm_handle, struct pa_mainloop_api* m, struct pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags events, void *userdata), void *userdata) { +int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api* m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags events, void *userdata), void *userdata) { unsigned i; struct pollfd *pfds, *ppfd; - struct pa_io_event **ios; + pa_io_event **ios; assert(pcm_handle && m && io_events && n_io_events && cb); *n_io_events = snd_pcm_poll_descriptors_count(pcm_handle); @@ -113,9 +113,9 @@ int pa_create_io_events(snd_pcm_t *pcm_handle, struct pa_mainloop_api* m, struct } /* Free the memory allocated by pa_create_io_events() */ -void pa_free_io_events(struct pa_mainloop_api* m, struct pa_io_event **io_events, unsigned n_io_events) { +void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_events, unsigned n_io_events) { unsigned i; - struct pa_io_event **ios; + pa_io_event **ios; assert(m && io_events); for (ios = io_events, i = 0; i < n_io_events; i++, ios++) diff --git a/polyp/alsa-util.h b/polyp/alsa-util.h index adec143f..787519f7 100644 --- a/polyp/alsa-util.h +++ b/polyp/alsa-util.h @@ -27,9 +27,9 @@ #include "sample.h" #include "mainloop-api.h" -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const struct pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size); +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size); -int pa_create_io_events(snd_pcm_t *pcm_handle, struct pa_mainloop_api *m, struct pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags events, void *userdata), void *userdata); -void pa_free_io_events(struct pa_mainloop_api* m, struct pa_io_event **io_sources, unsigned n_io_sources); +int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api *m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags events, void *userdata), void *userdata); +void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_sources, unsigned n_io_sources); #endif diff --git a/polyp/authkey-prop.c b/polyp/authkey-prop.c index 2adfc41f..8657f5a5 100644 --- a/polyp/authkey-prop.c +++ b/polyp/authkey-prop.c @@ -32,7 +32,7 @@ struct authkey_data { size_t length; }; -int pa_authkey_prop_get(struct pa_core *c, const char *name, void *data, size_t len) { +int pa_authkey_prop_get(pa_core *c, const char *name, void *data, size_t len) { struct authkey_data *a; assert(c && name && data && len > 0); @@ -44,7 +44,7 @@ int pa_authkey_prop_get(struct pa_core *c, const char *name, void *data, size_t return 0; } -int pa_authkey_prop_put(struct pa_core *c, const char *name, const void *data, size_t len) { +int pa_authkey_prop_put(pa_core *c, const char *name, const void *data, size_t len) { struct authkey_data *a; assert(c && name); @@ -61,7 +61,7 @@ int pa_authkey_prop_put(struct pa_core *c, const char *name, const void *data, s return 0; } -void pa_authkey_prop_ref(struct pa_core *c, const char *name) { +void pa_authkey_prop_ref(pa_core *c, const char *name) { struct authkey_data *a; assert(c && name); @@ -71,7 +71,7 @@ void pa_authkey_prop_ref(struct pa_core *c, const char *name) { a->ref++; } -void pa_authkey_prop_unref(struct pa_core *c, const char *name) { +void pa_authkey_prop_unref(pa_core *c, const char *name) { struct authkey_data *a; assert(c && name); diff --git a/polyp/authkey-prop.h b/polyp/authkey-prop.h index 1b1948c7..29b40bb2 100644 --- a/polyp/authkey-prop.h +++ b/polyp/authkey-prop.h @@ -29,15 +29,15 @@ * several modules. */ /* Return the data of the specified authorization key property. Doesn't alter the refernce count of the key */ -int pa_authkey_prop_get(struct pa_core *c, const char *name, void *data, size_t len); +int pa_authkey_prop_get(pa_core *c, const char *name, void *data, size_t len); /* Store data in the specified authorization key property. The initial reference count is set to 1 */ -int pa_authkey_prop_put(struct pa_core *c, const char *name, const void *data, size_t len); +int pa_authkey_prop_put(pa_core *c, const char *name, const void *data, size_t len); /* Increase the reference count of the specified authorization key */ -void pa_authkey_prop_ref(struct pa_core *c, const char *name); +void pa_authkey_prop_ref(pa_core *c, const char *name); /* Decrease the reference count of the specified authorization key */ -void pa_authkey_prop_unref(struct pa_core *c, const char *name); +void pa_authkey_prop_unref(pa_core *c, const char *name); #endif diff --git a/polyp/autoload.c b/polyp/autoload.c index 96fa750a..7e05c168 100644 --- a/polyp/autoload.c +++ b/polyp/autoload.c @@ -36,7 +36,7 @@ #include "scache.h" #include "subscribe.h" -static void entry_free(struct pa_autoload_entry *e) { +static void entry_free(pa_autoload_entry *e) { assert(e); pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_AUTOLOAD|PA_SUBSCRIPTION_EVENT_REMOVE, PA_INVALID_INDEX); pa_xfree(e->name); @@ -45,7 +45,7 @@ static void entry_free(struct pa_autoload_entry *e) { pa_xfree(e); } -static void entry_remove_and_free(struct pa_autoload_entry *e) { +static void entry_remove_and_free(pa_autoload_entry *e) { assert(e && e->core); pa_idxset_remove_by_data(e->core->autoload_idxset, e, NULL); @@ -53,14 +53,14 @@ static void entry_remove_and_free(struct pa_autoload_entry *e) { entry_free(e); } -static struct pa_autoload_entry* entry_new(struct pa_core *c, const char *name) { - struct pa_autoload_entry *e = NULL; +static pa_autoload_entry* entry_new(pa_core *c, const char *name) { + pa_autoload_entry *e = NULL; assert(c && name); if (c->autoload_hashmap && (e = pa_hashmap_get(c->autoload_hashmap, name))) return NULL; - e = pa_xmalloc(sizeof(struct pa_autoload_entry)); + e = pa_xmalloc(sizeof(pa_autoload_entry)); e->core = c; e->name = pa_xstrdup(name); e->module = e->argument = NULL; @@ -81,8 +81,8 @@ static struct pa_autoload_entry* entry_new(struct pa_core *c, const char *name) return e; } -int pa_autoload_add(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*module, const char *argument, uint32_t *index) { - struct pa_autoload_entry *e = NULL; +int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type type, const char*module, const char *argument, uint32_t *idx) { + pa_autoload_entry *e = NULL; assert(c && name && module && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); if (!(e = entry_new(c, name))) @@ -92,14 +92,14 @@ int pa_autoload_add(struct pa_core *c, const char*name, enum pa_namereg_type typ e->argument = pa_xstrdup(argument); e->type = type; - if (index) - *index = e->index; + if (idx) + *idx = e->index; return 0; } -int pa_autoload_remove_by_name(struct pa_core *c, const char*name, enum pa_namereg_type type) { - struct pa_autoload_entry *e; +int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type type) { + pa_autoload_entry *e; assert(c && name && type); if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type) @@ -109,20 +109,20 @@ int pa_autoload_remove_by_name(struct pa_core *c, const char*name, enum pa_namer return 0; } -int pa_autoload_remove_by_index(struct pa_core *c, uint32_t index) { - struct pa_autoload_entry *e; - assert(c && index != PA_IDXSET_INVALID); +int pa_autoload_remove_by_index(pa_core *c, uint32_t idx) { + pa_autoload_entry *e; + assert(c && idx != PA_IDXSET_INVALID); - if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, index))) + if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, idx))) return -1; entry_remove_and_free(e); return 0; } -void pa_autoload_request(struct pa_core *c, const char *name, enum pa_namereg_type type) { - struct pa_autoload_entry *e; - struct pa_module *m; +void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type type) { + pa_autoload_entry *e; + pa_module *m; assert(c && name); if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || (e->type != type)) @@ -141,13 +141,13 @@ void pa_autoload_request(struct pa_core *c, const char *name, enum pa_namereg_ty e->in_action = 0; } -static void free_func(void *p, void *userdata) { - struct pa_autoload_entry *e = p; +static void free_func(void *p, PA_GCC_UNUSED void *userdata) { + pa_autoload_entry *e = p; pa_idxset_remove_by_data(e->core->autoload_idxset, e, NULL); entry_free(e); } -void pa_autoload_free(struct pa_core *c) { +void pa_autoload_free(pa_core *c) { if (c->autoload_hashmap) { pa_hashmap_free(c->autoload_hashmap, free_func, NULL); c->autoload_hashmap = NULL; @@ -159,8 +159,8 @@ void pa_autoload_free(struct pa_core *c) { } } -const struct pa_autoload_entry* pa_autoload_get_by_name(struct pa_core *c, const char*name, enum pa_namereg_type type) { - struct pa_autoload_entry *e; +const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type type) { + pa_autoload_entry *e; assert(c && name); if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type) @@ -169,11 +169,11 @@ const struct pa_autoload_entry* pa_autoload_get_by_name(struct pa_core *c, const return e; } -const struct pa_autoload_entry* pa_autoload_get_by_index(struct pa_core *c, uint32_t index) { - struct pa_autoload_entry *e; - assert(c && index != PA_IDXSET_INVALID); +const pa_autoload_entry* pa_autoload_get_by_index(pa_core *c, uint32_t idx) { + pa_autoload_entry *e; + assert(c && idx != PA_IDXSET_INVALID); - if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, index))) + if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, idx))) return NULL; return e; diff --git a/polyp/autoload.h b/polyp/autoload.h index 23475684..622a854e 100644 --- a/polyp/autoload.h +++ b/polyp/autoload.h @@ -30,29 +30,29 @@ * specified module is loaded. */ /* An autoload entry, or "ghost" sink/source */ -struct pa_autoload_entry { - struct pa_core *core; +typedef struct pa_autoload_entry { + pa_core *core; uint32_t index; char *name; - enum pa_namereg_type type; /* Type of the autoload entry */ + pa_namereg_type type; /* Type of the autoload entry */ int in_action; /* Currently loaded */ char *module, *argument; -}; +} pa_autoload_entry; /* Add a new autoload entry of the given time, with the speicified * sink/source name, module name and argument. Return the entry's * index in *index */ -int pa_autoload_add(struct pa_core *c, const char*name, enum pa_namereg_type type, const char*module, const char *argument, uint32_t *index); +int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type type, const char*module, const char *argument, uint32_t *idx); /* Free all autoload entries */ -void pa_autoload_free(struct pa_core *c); -int pa_autoload_remove_by_name(struct pa_core *c, const char*name, enum pa_namereg_type type); -int pa_autoload_remove_by_index(struct pa_core *c, uint32_t index); +void pa_autoload_free(pa_core *c); +int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type type); +int pa_autoload_remove_by_index(pa_core *c, uint32_t idx); /* Request an autoload entry by its name, effectively causing a module to be loaded */ -void pa_autoload_request(struct pa_core *c, const char *name, enum pa_namereg_type type); +void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type type); -const struct pa_autoload_entry* pa_autoload_get_by_name(struct pa_core *c, const char*name, enum pa_namereg_type type); -const struct pa_autoload_entry* pa_autoload_get_by_index(struct pa_core *c, uint32_t index); +const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type type); +const pa_autoload_entry* pa_autoload_get_by_index(pa_core *c, uint32_t idx); #endif diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 12447879..63241a81 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -52,7 +52,7 @@ struct command { const char *name; - int (*proc) (struct pa_core *c, struct pa_tokenizer*t, struct pa_strbuf *buf, int *fail); + int (*proc) (pa_core *c, pa_tokenizer*t, pa_strbuf *buf, int *fail); const char *help; unsigned args; }; @@ -62,36 +62,36 @@ struct command { #define NOFAIL_META ".nofail" /* Prototypes for all available commands */ -static int pa_cli_command_exit(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_help(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_modules(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_clients(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_sinks(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_sources(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_sink_inputs(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_source_outputs(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_stat(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_info(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_unload(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_sink_volume(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_sink_input_volume(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_sink_default(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_source_default(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_kill_client(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_kill_sink_input(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_kill_source_output(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_play(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_load_dir(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_autoload_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_autoload_add(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_autoload_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); -static int pa_cli_command_list_props(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail); +static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); /* A method table for all available commands */ @@ -139,21 +139,21 @@ static const char whitespace[] = " \t\n\r"; static const char linebreak[] = "\n\r"; static uint32_t parse_index(const char *n) { - uint32_t index; + uint32_t idx; - if (pa_atou(n, &index) < 0) + if (pa_atou(n, &idx) < 0) return (uint32_t) PA_IDXSET_INVALID; - return index; + return idx; } -static int pa_cli_command_exit(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, PA_GCC_UNUSED pa_strbuf *buf, PA_GCC_UNUSED int *fail) { 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) { +static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { const struct command*command; assert(c && t && buf); @@ -165,7 +165,7 @@ static int pa_cli_command_help(struct pa_core *c, struct pa_tokenizer *t, struct return 0; } -static int pa_cli_command_modules(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { char *s; assert(c && t); s = pa_module_list_to_string(c); @@ -175,7 +175,7 @@ static int pa_cli_command_modules(struct pa_core *c, struct pa_tokenizer *t, str return 0; } -static int pa_cli_command_clients(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { char *s; assert(c && t); s = pa_client_list_to_string(c); @@ -185,7 +185,7 @@ static int pa_cli_command_clients(struct pa_core *c, struct pa_tokenizer *t, str return 0; } -static int pa_cli_command_sinks(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { char *s; assert(c && t); s = pa_sink_list_to_string(c); @@ -195,7 +195,7 @@ static int pa_cli_command_sinks(struct pa_core *c, struct pa_tokenizer *t, struc return 0; } -static int pa_cli_command_sources(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { char *s; assert(c && t); s = pa_source_list_to_string(c); @@ -205,7 +205,7 @@ static int pa_cli_command_sources(struct pa_core *c, struct pa_tokenizer *t, str return 0; } -static int pa_cli_command_sink_inputs(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { char *s; assert(c && t); s = pa_sink_input_list_to_string(c); @@ -215,7 +215,7 @@ static int pa_cli_command_sink_inputs(struct pa_core *c, struct pa_tokenizer *t, return 0; } -static int pa_cli_command_source_outputs(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { char *s; assert(c && t); s = pa_source_output_list_to_string(c); @@ -225,7 +225,7 @@ static int pa_cli_command_source_outputs(struct pa_core *c, struct pa_tokenizer return 0; } -static int pa_cli_command_stat(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { char s[256]; assert(c && t); @@ -253,7 +253,7 @@ static int pa_cli_command_stat(struct pa_core *c, struct pa_tokenizer *t, struct return 0; } -static int pa_cli_command_info(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { assert(c && t); pa_cli_command_stat(c, t, buf, fail); pa_cli_command_modules(c, t, buf, fail); @@ -267,8 +267,8 @@ static int pa_cli_command_info(struct pa_core *c, struct pa_tokenizer *t, struct return 0; } -static int pa_cli_command_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { - struct pa_module *m; +static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + pa_module *m; const char *name; assert(c && t); @@ -285,9 +285,9 @@ static int pa_cli_command_load(struct pa_core *c, struct pa_tokenizer *t, struct return 0; } -static int pa_cli_command_unload(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { - struct pa_module *m; - uint32_t index; +static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + pa_module *m; + uint32_t idx; const char *i; char *e; assert(c && t); @@ -297,8 +297,8 @@ static int pa_cli_command_unload(struct pa_core *c, struct pa_tokenizer *t, stru return -1; } - index = (uint32_t) strtoul(i, &e, 10); - if (*e || !(m = pa_idxset_get_by_index(c->modules, index))) { + idx = (uint32_t) strtoul(i, &e, 10); + if (*e || !(m = pa_idxset_get_by_index(c->modules, idx))) { pa_strbuf_puts(buf, "Invalid module index.\n"); return -1; } @@ -307,9 +307,9 @@ static int pa_cli_command_unload(struct pa_core *c, struct pa_tokenizer *t, stru return 0; } -static int pa_cli_command_sink_volume(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { const char *n, *v; - struct pa_sink *sink; + pa_sink *sink; uint32_t volume; if (!(n = pa_tokenizer_get(t, 1))) { @@ -336,18 +336,18 @@ static int pa_cli_command_sink_volume(struct pa_core *c, struct pa_tokenizer *t, return 0; } -static int pa_cli_command_sink_input_volume(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { const char *n, *v; - struct pa_sink_input *si; + pa_sink_input *si; uint32_t volume; - uint32_t index; + uint32_t idx; 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) { + if ((idx = parse_index(n)) == PA_IDXSET_INVALID) { pa_strbuf_puts(buf, "Failed to parse index.\n"); return -1; } @@ -362,7 +362,7 @@ static int pa_cli_command_sink_input_volume(struct pa_core *c, struct pa_tokeniz return -1; } - if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) index))) { + if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) { pa_strbuf_puts(buf, "No sink input found with this index.\n"); return -1; } @@ -371,7 +371,7 @@ static int pa_cli_command_sink_input_volume(struct pa_core *c, struct pa_tokeniz return 0; } -static int pa_cli_command_sink_default(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { const char *n; assert(c && t); @@ -384,7 +384,7 @@ static int pa_cli_command_sink_default(struct pa_core *c, struct pa_tokenizer *t return 0; } -static int pa_cli_command_source_default(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { const char *n; assert(c && t); @@ -397,10 +397,10 @@ static int pa_cli_command_source_default(struct pa_core *c, struct pa_tokenizer return 0; } -static int pa_cli_command_kill_client(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { const char *n; - struct pa_client *client; - uint32_t index; + pa_client *client; + uint32_t idx; assert(c && t); if (!(n = pa_tokenizer_get(t, 1))) { @@ -408,12 +408,12 @@ static int pa_cli_command_kill_client(struct pa_core *c, struct pa_tokenizer *t, return -1; } - if ((index = parse_index(n)) == PA_IDXSET_INVALID) { + if ((idx = 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))) { + if (!(client = pa_idxset_get_by_index(c->clients, idx))) { pa_strbuf_puts(buf, "No client found by this index.\n"); return -1; } @@ -422,10 +422,10 @@ static int pa_cli_command_kill_client(struct pa_core *c, struct pa_tokenizer *t, return 0; } -static int pa_cli_command_kill_sink_input(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { const char *n; - struct pa_sink_input *sink_input; - uint32_t index; + pa_sink_input *sink_input; + uint32_t idx; assert(c && t); if (!(n = pa_tokenizer_get(t, 1))) { @@ -433,12 +433,12 @@ static int pa_cli_command_kill_sink_input(struct pa_core *c, struct pa_tokenizer return -1; } - if ((index = parse_index(n)) == PA_IDXSET_INVALID) { + if ((idx = 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))) { + if (!(sink_input = pa_idxset_get_by_index(c->sink_inputs, idx))) { pa_strbuf_puts(buf, "No sink input found by this index.\n"); return -1; } @@ -447,10 +447,10 @@ static int pa_cli_command_kill_sink_input(struct pa_core *c, struct pa_tokenizer return 0; } -static int pa_cli_command_kill_source_output(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { const char *n; - struct pa_source_output *source_output; - uint32_t index; + pa_source_output *source_output; + uint32_t idx; assert(c && t); if (!(n = pa_tokenizer_get(t, 1))) { @@ -458,12 +458,12 @@ static int pa_cli_command_kill_source_output(struct pa_core *c, struct pa_tokeni return -1; } - if ((index = parse_index(n)) == PA_IDXSET_INVALID) { + if ((idx = 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))) { + if (!(source_output = pa_idxset_get_by_index(c->source_outputs, idx))) { pa_strbuf_puts(buf, "No source output found by this index.\n"); return -1; } @@ -472,7 +472,7 @@ static int pa_cli_command_kill_source_output(struct pa_core *c, struct pa_tokeni return 0; } -static int pa_cli_command_scache_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { char *s; assert(c && t); s = pa_scache_list_to_string(c); @@ -482,9 +482,9 @@ static int pa_cli_command_scache_list(struct pa_core *c, struct pa_tokenizer *t, return 0; } -static int pa_cli_command_scache_play(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *n, *sink_name; - struct pa_sink *sink; + pa_sink *sink; assert(c && t && buf && fail); if (!(n = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) { @@ -505,7 +505,7 @@ static int pa_cli_command_scache_play(struct pa_core *c, struct pa_tokenizer *t, return 0; } -static int pa_cli_command_scache_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *n; assert(c && t && buf && fail); @@ -522,7 +522,7 @@ static int pa_cli_command_scache_remove(struct pa_core *c, struct pa_tokenizer * return 0; } -static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *fname, *n; int r; assert(c && t && buf && fail); @@ -543,7 +543,7 @@ static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t, return 0; } -static int pa_cli_command_scache_load_dir(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *pname; assert(c && t && buf && fail); @@ -560,9 +560,9 @@ static int pa_cli_command_scache_load_dir(struct pa_core *c, struct pa_tokenizer return 0; } -static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *fname, *sink_name; - struct pa_sink *sink; + pa_sink *sink; assert(c && t && buf && fail); if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) { @@ -579,7 +579,7 @@ static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, s return pa_play_file(sink, fname, PA_VOLUME_NORM); } -static int pa_cli_command_autoload_add(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *a, *b; assert(c && t && buf && fail); @@ -593,7 +593,7 @@ static int pa_cli_command_autoload_add(struct pa_core *c, struct pa_tokenizer *t return 0; } -static int pa_cli_command_autoload_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *name; assert(c && t && buf && fail); @@ -610,7 +610,7 @@ static int pa_cli_command_autoload_remove(struct pa_core *c, struct pa_tokenizer return 0; } -static int pa_cli_command_autoload_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { char *s; assert(c && t); s = pa_autoload_list_to_string(c); @@ -620,22 +620,22 @@ static int pa_cli_command_autoload_list(struct pa_core *c, struct pa_tokenizer * return 0; } -static int pa_cli_command_list_props(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { +static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { assert(c && t); pa_property_dump(c, buf); return 0; } -static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail) { - struct pa_module *m; - struct pa_sink *s; +static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + pa_module *m; + pa_sink *s; int nl; const char *p; - uint32_t index; + uint32_t idx; char txt[256]; time_t now; void *i; - struct pa_autoload_entry *a; + pa_autoload_entry *a; assert(c && t); @@ -648,7 +648,7 @@ static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct #endif - for (m = pa_idxset_first(c->modules, &index); m; m = pa_idxset_next(c->modules, &index)) { + for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) { if (m->auto_unload) continue; @@ -662,7 +662,7 @@ static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct nl = 0; - for (s = pa_idxset_first(c->sinks, &index); s; s = pa_idxset_next(c->sinks, &index)) { + for (s = pa_idxset_first(c->sinks, &idx); s; s = pa_idxset_next(c->sinks, &idx)) { if (s->volume == PA_VOLUME_NORM) continue; @@ -722,7 +722,7 @@ static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct } -int pa_cli_command_execute_line(struct pa_core *c, const char *s, struct pa_strbuf *buf, int *fail) { +int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { const char *cs; cs = s+strspn(s, whitespace); @@ -758,7 +758,7 @@ int pa_cli_command_execute_line(struct pa_core *c, const char *s, struct pa_strb 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); + pa_tokenizer *t = pa_tokenizer_new(cs, command->args); assert(t); ret = command->proc(c, t, buf, fail); pa_tokenizer_free(t); @@ -780,7 +780,7 @@ int pa_cli_command_execute_line(struct pa_core *c, const char *s, struct pa_strb return 0; } -int pa_cli_command_execute_file(struct pa_core *c, const char *fn, struct pa_strbuf *buf, int *fail) { +int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int *fail) { char line[256]; FILE *f = NULL; int ret = -1; @@ -810,7 +810,7 @@ fail: return ret; } -int pa_cli_command_execute(struct pa_core *c, const char *s, struct pa_strbuf *buf, int *fail) { +int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { const char *p; assert(c && s && buf && fail); diff --git a/polyp/cli-command.h b/polyp/cli-command.h index 7af9d014..78b8d5c6 100644 --- a/polyp/cli-command.h +++ b/polyp/cli-command.h @@ -29,12 +29,12 @@ * buffer *buf. If *fail is non-zero the function will return -1 when * one or more of the executed commands failed. *fail * may be modified by the function call. */ -int pa_cli_command_execute_line(struct pa_core *c, const char *s, struct pa_strbuf *buf, int *fail); +int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail); /* Execute a whole file of CLI commands */ -int pa_cli_command_execute_file(struct pa_core *c, const char *fn, struct pa_strbuf *buf, int *fail); +int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int *fail); /* Split the specified string into lines and run pa_cli_command_execute_line() for each. */ -int pa_cli_command_execute(struct pa_core *c, const char *s, struct pa_strbuf *buf, int *fail); +int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail); #endif diff --git a/polyp/cli-text.c b/polyp/cli-text.c index d4c46dc0..a19bfc97 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -39,36 +39,36 @@ #include "autoload.h" #include "xmalloc.h" -char *pa_module_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_module *m; - uint32_t index = PA_IDXSET_INVALID; +char *pa_module_list_to_string(pa_core *c) { + pa_strbuf *s; + pa_module *m; + uint32_t idx = PA_IDXSET_INVALID; assert(c); s = pa_strbuf_new(); assert(s); - pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_ncontents(c->modules)); + pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_size(c->modules)); - for (m = pa_idxset_first(c->modules, &index); m; m = pa_idxset_next(c->modules, &index)) + for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\targument: <%s>\n\tused: %i\n\tauto unload: %s\n", m->index, m->name, m->argument, m->n_used, m->auto_unload ? "yes" : "no"); return pa_strbuf_tostring_free(s); } -char *pa_client_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_client *client; - uint32_t index = PA_IDXSET_INVALID; +char *pa_client_list_to_string(pa_core *c) { + pa_strbuf *s; + pa_client *client; + uint32_t idx = PA_IDXSET_INVALID; char tid[5]; assert(c); s = pa_strbuf_new(); assert(s); - pa_strbuf_printf(s, "%u client(s) logged in.\n", pa_idxset_ncontents(c->clients)); + pa_strbuf_printf(s, "%u client(s) logged in.\n", pa_idxset_size(c->clients)); - for (client = pa_idxset_first(c->clients, &index); client; client = pa_idxset_next(c->clients, &index)) { + for (client = pa_idxset_first(c->clients, &idx); client; client = pa_idxset_next(c->clients, &idx)) { pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\ttype: <%s>\n", client->index, client->name, pa_typeid_to_string(client->typeid, tid, sizeof(tid))); if (client->owner) @@ -78,19 +78,19 @@ char *pa_client_list_to_string(struct pa_core *c) { return pa_strbuf_tostring_free(s); } -char *pa_sink_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_sink *sink; - uint32_t index = PA_IDXSET_INVALID; +char *pa_sink_list_to_string(pa_core *c) { + pa_strbuf *s; + pa_sink *sink; + uint32_t idx = PA_IDXSET_INVALID; char tid[5]; assert(c); s = pa_strbuf_new(); assert(s); - pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_ncontents(c->sinks)); + pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_size(c->sinks)); - for (sink = pa_idxset_first(c->sinks, &index); sink; sink = pa_idxset_next(c->sinks, &index)) { + for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec); assert(sink->monitor_source); @@ -102,7 +102,7 @@ char *pa_sink_list_to_string(struct pa_core *c) { pa_typeid_to_string(sink->typeid, tid, sizeof(tid)), (unsigned) sink->volume, pa_volume_to_dB(sink->volume), - (float) pa_sink_get_latency(sink), + (double) pa_sink_get_latency(sink), sink->monitor_source->index, ss); @@ -115,19 +115,19 @@ char *pa_sink_list_to_string(struct pa_core *c) { return pa_strbuf_tostring_free(s); } -char *pa_source_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_source *source; - uint32_t index = PA_IDXSET_INVALID; +char *pa_source_list_to_string(pa_core *c) { + pa_strbuf *s; + pa_source *source; + uint32_t idx = PA_IDXSET_INVALID; char tid[5]; assert(c); s = pa_strbuf_new(); assert(s); - pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_ncontents(c->sources)); + pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_size(c->sources)); - for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) { + for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec); pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\ttype: <%s>\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n", @@ -135,7 +135,7 @@ char *pa_source_list_to_string(struct pa_core *c) { source->index, source->name, pa_typeid_to_string(source->typeid, tid, sizeof(tid)), - (float) pa_source_get_latency(source), + (double) pa_source_get_latency(source), ss); if (source->monitor_of) @@ -150,10 +150,10 @@ char *pa_source_list_to_string(struct pa_core *c) { } -char *pa_source_output_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_source_output *o; - uint32_t index = PA_IDXSET_INVALID; +char *pa_source_output_list_to_string(pa_core *c) { + pa_strbuf *s; + pa_source_output *o; + uint32_t idx = PA_IDXSET_INVALID; char tid[5]; static const char* const state_table[] = { "RUNNING", @@ -165,9 +165,9 @@ char *pa_source_output_list_to_string(struct pa_core *c) { s = pa_strbuf_new(); assert(s); - pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_ncontents(c->source_outputs)); + pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_size(c->source_outputs)); - for (o = pa_idxset_first(c->source_outputs, &index); o; o = pa_idxset_next(c->source_outputs, &index)) { + for (o = pa_idxset_first(c->source_outputs, &idx); o; o = pa_idxset_next(c->source_outputs, &idx)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; const char *rm; pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec); @@ -194,10 +194,10 @@ char *pa_source_output_list_to_string(struct pa_core *c) { return pa_strbuf_tostring_free(s); } -char *pa_sink_input_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; - struct pa_sink_input *i; - uint32_t index = PA_IDXSET_INVALID; +char *pa_sink_input_list_to_string(pa_core *c) { + pa_strbuf *s; + pa_sink_input *i; + uint32_t idx = PA_IDXSET_INVALID; char tid[5]; static const char* const state_table[] = { "RUNNING", @@ -209,9 +209,9 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { s = pa_strbuf_new(); assert(s); - pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_ncontents(c->sink_inputs)); + pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_size(c->sink_inputs)); - for (i = pa_idxset_first(c->sink_inputs, &index); i; i = pa_idxset_next(c->sink_inputs, &index)) { + for (i = pa_idxset_first(c->sink_inputs, &idx); i; i = pa_idxset_next(c->sink_inputs, &idx)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; const char *rm; @@ -229,7 +229,7 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { i->sink->index, i->sink->name, (unsigned) i->volume, pa_volume_to_dB(i->volume), - (float) pa_sink_input_get_latency(i), + (double) pa_sink_input_get_latency(i), ss, rm); @@ -242,20 +242,20 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { return pa_strbuf_tostring_free(s); } -char *pa_scache_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; +char *pa_scache_list_to_string(pa_core *c) { + pa_strbuf *s; assert(c); s = pa_strbuf_new(); assert(s); - pa_strbuf_printf(s, "%u cache entries available.\n", c->scache ? pa_idxset_ncontents(c->scache) : 0); + pa_strbuf_printf(s, "%u cache entries available.\n", c->scache ? pa_idxset_size(c->scache) : 0); if (c->scache) { - struct pa_scache_entry *e; - uint32_t index = PA_IDXSET_INVALID; + pa_scache_entry *e; + uint32_t idx = PA_IDXSET_INVALID; - for (e = pa_idxset_first(c->scache, &index); e; e = pa_idxset_next(c->scache, &index)) { + for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) { double l = 0; char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = "n/a"; @@ -280,17 +280,17 @@ char *pa_scache_list_to_string(struct pa_core *c) { return pa_strbuf_tostring_free(s); } -char *pa_autoload_list_to_string(struct pa_core *c) { - struct pa_strbuf *s; +char *pa_autoload_list_to_string(pa_core *c) { + pa_strbuf *s; assert(c); s = pa_strbuf_new(); assert(s); - pa_strbuf_printf(s, "%u autoload entries available.\n", c->autoload_hashmap ? pa_hashmap_ncontents(c->autoload_hashmap) : 0); + pa_strbuf_printf(s, "%u autoload entries available.\n", c->autoload_hashmap ? pa_hashmap_size(c->autoload_hashmap) : 0); if (c->autoload_hashmap) { - struct pa_autoload_entry *e; + pa_autoload_entry *e; void *state = NULL; while ((e = pa_hashmap_iterate(c->autoload_hashmap, &state, NULL))) { @@ -308,8 +308,8 @@ char *pa_autoload_list_to_string(struct pa_core *c) { return pa_strbuf_tostring_free(s); } -char *pa_full_status_string(struct pa_core *c) { - struct pa_strbuf *s; +char *pa_full_status_string(pa_core *c) { + pa_strbuf *s; int i; s = pa_strbuf_new(); diff --git a/polyp/cli-text.h b/polyp/cli-text.h index d19dd48c..7a1a0361 100644 --- a/polyp/cli-text.h +++ b/polyp/cli-text.h @@ -27,16 +27,16 @@ /* Some functions to generate pretty formatted listings of * entities. The returned strings have to be freed manually. */ -char *pa_sink_input_list_to_string(struct pa_core *c); -char *pa_source_output_list_to_string(struct pa_core *c); -char *pa_sink_list_to_string(struct pa_core *core); -char *pa_source_list_to_string(struct pa_core *c); -char *pa_client_list_to_string(struct pa_core *c); -char *pa_module_list_to_string(struct pa_core *c); -char *pa_scache_list_to_string(struct pa_core *c); -char *pa_autoload_list_to_string(struct pa_core *c); - -char *pa_full_status_string(struct pa_core *c); +char *pa_sink_input_list_to_string(pa_core *c); +char *pa_source_output_list_to_string(pa_core *c); +char *pa_sink_list_to_string(pa_core *core); +char *pa_source_list_to_string(pa_core *c); +char *pa_client_list_to_string(pa_core *c); +char *pa_module_list_to_string(pa_core *c); +char *pa_scache_list_to_string(pa_core *c); +char *pa_autoload_list_to_string(pa_core *c); + +char *pa_full_status_string(pa_core *c); #endif diff --git a/polyp/cli.c b/polyp/cli.c index 16323cba..7b1022c1 100644 --- a/polyp/cli.c +++ b/polyp/cli.c @@ -48,26 +48,26 @@ #define PA_TYPEID_CLI PA_TYPEID_MAKE('C', 'L', 'I', '_') struct pa_cli { - struct pa_core *core; - struct pa_ioline *line; + pa_core *core; + pa_ioline *line; - void (*eof_callback)(struct pa_cli *c, void *userdata); + void (*eof_callback)(pa_cli *c, void *userdata); void *userdata; - struct pa_client *client; + pa_client *client; int fail, kill_requested, defer_kill; }; -static void line_callback(struct pa_ioline *line, const char *s, void *userdata); -static void client_kill(struct pa_client *c); +static void line_callback(pa_ioline *line, const char *s, void *userdata); +static void client_kill(pa_client *c); -struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io, struct pa_module *m) { +pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m) { char cname[256]; - struct pa_cli *c; + pa_cli *c; assert(io); - c = pa_xmalloc(sizeof(struct pa_cli)); + c = pa_xmalloc(sizeof(pa_cli)); c->core = core; c->line = pa_ioline_new(io); assert(c->line); @@ -90,7 +90,7 @@ struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io, struct return c; } -void pa_cli_free(struct pa_cli *c) { +void pa_cli_free(pa_cli *c) { assert(c); pa_ioline_close(c->line); pa_ioline_unref(c->line); @@ -98,8 +98,8 @@ void pa_cli_free(struct pa_cli *c) { pa_xfree(c); } -static void client_kill(struct pa_client *client) { - struct pa_cli *c; +static void client_kill(pa_client *client) { + pa_cli *c; assert(client && client->userdata); c = client->userdata; @@ -112,9 +112,9 @@ static void client_kill(struct pa_client *client) { } } -static void line_callback(struct pa_ioline *line, const char *s, void *userdata) { - struct pa_strbuf *buf; - struct pa_cli *c = userdata; +static void line_callback(pa_ioline *line, const char *s, void *userdata) { + pa_strbuf *buf; + pa_cli *c = userdata; char *p; assert(line && c); @@ -141,7 +141,7 @@ static void line_callback(struct pa_ioline *line, const char *s, void *userdata) 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) { +void pa_cli_set_eof_callback(pa_cli *c, void (*cb)(pa_cli*c, void *userdata), void *userdata) { assert(c); c->eof_callback = cb; c->userdata = userdata; diff --git a/polyp/cli.h b/polyp/cli.h index 44ed706c..03f31c22 100644 --- a/polyp/cli.h +++ b/polyp/cli.h @@ -26,13 +26,13 @@ #include "core.h" #include "module.h" -struct pa_cli; +typedef struct pa_cli pa_cli; /* Create a new command line session on the specified io channel owned by the specified module */ -struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io, struct pa_module *m); -void pa_cli_free(struct pa_cli *cli); +pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m); +void pa_cli_free(pa_cli *cli); /* Set a callback function that is called whenever the command line session is terminated */ -void pa_cli_set_eof_callback(struct pa_cli *cli, void (*cb)(struct pa_cli*c, void *userdata), void *userdata); +void pa_cli_set_eof_callback(pa_cli *cli, void (*cb)(pa_cli*c, void *userdata), void *userdata); #endif diff --git a/polyp/client-conf-x11.c b/polyp/client-conf-x11.c index 383aa64e..4fd75744 100644 --- a/polyp/client-conf-x11.c +++ b/polyp/client-conf-x11.c @@ -35,7 +35,7 @@ #include "xmalloc.h" #include "util.h" -int pa_client_conf_from_x11(struct pa_client_conf *c, const char *dname) { +int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) { Display *d = NULL; int ret = -1; char t[1024]; diff --git a/polyp/client-conf-x11.h b/polyp/client-conf-x11.h index e65e8202..64459224 100644 --- a/polyp/client-conf-x11.h +++ b/polyp/client-conf-x11.h @@ -26,6 +26,6 @@ /* Load client configuration data from the specified X11 display, * overwriting the current settings in *c */ -int pa_client_conf_from_x11(struct pa_client_conf *c, const char *display); +int pa_client_conf_from_x11(pa_client_conf *c, const char *display); #endif diff --git a/polyp/client-conf.c b/polyp/client-conf.c index 04c3d2ef..bcd4275d 100644 --- a/polyp/client-conf.c +++ b/polyp/client-conf.c @@ -60,7 +60,7 @@ #define ENV_DAEMON_BINARY "POLYP_BINARY" #define ENV_COOKIE_FILE "POLYP_COOKIE" -static const struct pa_client_conf default_conf = { +static const pa_client_conf default_conf = { .daemon_binary = NULL, .extra_arguments = NULL, .default_sink = NULL, @@ -71,8 +71,8 @@ static const struct pa_client_conf default_conf = { .cookie_valid = 0 }; -struct pa_client_conf *pa_client_conf_new(void) { - struct pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); +pa_client_conf *pa_client_conf_new(void) { + pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); c->daemon_binary = pa_xstrdup(POLYPAUDIO_BINARY); c->extra_arguments = pa_xstrdup("--log-target=syslog --exit-idle-time=5"); @@ -81,7 +81,7 @@ struct pa_client_conf *pa_client_conf_new(void) { return c; } -void pa_client_conf_free(struct pa_client_conf *c) { +void pa_client_conf_free(pa_client_conf *c) { assert(c); pa_xfree(c->daemon_binary); pa_xfree(c->extra_arguments); @@ -91,13 +91,13 @@ void pa_client_conf_free(struct pa_client_conf *c) { pa_xfree(c->cookie_file); pa_xfree(c); } -int pa_client_conf_load(struct pa_client_conf *c, const char *filename) { +int pa_client_conf_load(pa_client_conf *c, const char *filename) { FILE *f = NULL; char *fn = NULL; int r = -1; /* Prepare the configuration parse table */ - struct pa_config_item table[] = { + pa_config_item table[] = { { "daemon-binary", pa_config_parse_string, NULL }, { "extra-arguments", pa_config_parse_string, NULL }, { "default-sink", pa_config_parse_string, NULL }, @@ -140,7 +140,7 @@ finish: return r; } -int pa_client_conf_env(struct pa_client_conf *c) { +int pa_client_conf_env(pa_client_conf *c) { char *e; if ((e = getenv(ENV_DEFAULT_SINK))) { @@ -173,7 +173,7 @@ int pa_client_conf_env(struct pa_client_conf *c) { return 0; } -int pa_client_conf_load_cookie(struct pa_client_conf* c) { +int pa_client_conf_load_cookie(pa_client_conf* c) { assert(c); c->cookie_valid = 0; diff --git a/polyp/client-conf.h b/polyp/client-conf.h index b4625039..7ca2f233 100644 --- a/polyp/client-conf.h +++ b/polyp/client-conf.h @@ -26,27 +26,27 @@ /* A structure containing configuration data for polypaudio clients. */ -struct pa_client_conf { +typedef struct pa_client_conf { char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server, *cookie_file; int autospawn; uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; int cookie_valid; /* non-zero, when cookie is valid */ -}; +} pa_client_conf; /* Create a new configuration data object and reset it to defaults */ -struct pa_client_conf *pa_client_conf_new(void); -void pa_client_conf_free(struct pa_client_conf *c); +pa_client_conf *pa_client_conf_new(void); +void pa_client_conf_free(pa_client_conf *c); /* Load the configuration data from the speicified file, overwriting * the current settings in *c. When the filename is NULL, the * default client configuration file name is used. */ -int pa_client_conf_load(struct pa_client_conf *c, const char *filename); +int pa_client_conf_load(pa_client_conf *c, const char *filename); /* Load the configuration data from the environment of the current process, overwriting the current settings in *c. */ -int pa_client_conf_env(struct pa_client_conf *c); +int pa_client_conf_env(pa_client_conf *c); /* Load cookie data from c->cookie_file into c->cookie */ -int pa_client_conf_load_cookie(struct pa_client_conf* c); +int pa_client_conf_load_cookie(pa_client_conf* c); #endif diff --git a/polyp/client.c b/polyp/client.c index 8c7f4800..1938a4e0 100644 --- a/polyp/client.c +++ b/polyp/client.c @@ -33,12 +33,12 @@ #include "subscribe.h" #include "log.h" -struct pa_client *pa_client_new(struct pa_core *core, pa_typeid_t typeid, const char *name) { - struct pa_client *c; +pa_client *pa_client_new(pa_core *core, pa_typeid_t typeid, const char *name) { + pa_client *c; int r; assert(core); - c = pa_xmalloc(sizeof(struct pa_client)); + c = pa_xmalloc(sizeof(pa_client)); c->name = pa_xstrdup(name); c->owner = NULL; c->core = core; @@ -58,7 +58,7 @@ struct pa_client *pa_client_new(struct pa_core *core, pa_typeid_t typeid, const return c; } -void pa_client_free(struct pa_client *c) { +void pa_client_free(pa_client *c) { assert(c && c->core); pa_idxset_remove_by_data(c->core->clients, c, NULL); @@ -72,7 +72,7 @@ void pa_client_free(struct pa_client *c) { } -void pa_client_kill(struct pa_client *c) { +void pa_client_kill(pa_client *c) { assert(c); if (!c->kill) { pa_log_warn(__FILE__": kill() operation not implemented for client %u\n", c->index); @@ -82,7 +82,7 @@ void pa_client_kill(struct pa_client *c) { c->kill(c); } -void pa_client_set_name(struct pa_client *c, const char *name) { +void pa_client_set_name(pa_client *c, const char *name) { assert(c); pa_xfree(c->name); c->name = pa_xstrdup(name); diff --git a/polyp/client.h b/polyp/client.h index 2a3a09e0..198dbbf6 100644 --- a/polyp/client.h +++ b/polyp/client.h @@ -30,28 +30,30 @@ * attached. That way the user may generate a listing of all connected * clients easily and kill them if he wants.*/ +typedef struct pa_client pa_client; + struct pa_client { uint32_t index; pa_typeid_t typeid; - struct pa_module *owner; + pa_module *owner; char *name; - struct pa_core *core; + pa_core *core; - void (*kill)(struct pa_client *c); + void (*kill)(pa_client *c); void *userdata; }; -struct pa_client *pa_client_new(struct pa_core *c, pa_typeid_t typeid, const char *name); +pa_client *pa_client_new(pa_core *c, pa_typeid_t typeid, const char *name); /* This function should be called only by the code that created the client */ -void pa_client_free(struct pa_client *c); +void pa_client_free(pa_client *c); /* Code that didn't create the client should call this function to * request destruction of the client */ -void pa_client_kill(struct pa_client *c); +void pa_client_kill(pa_client *c); /* Rename the client */ -void pa_client_set_name(struct pa_client *c, const char *name); +void pa_client_set_name(pa_client *c, const char *name); #endif diff --git a/polyp/cmdline.c b/polyp/cmdline.c index 0951725a..5635707f 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -135,8 +135,8 @@ void pa_cmdline_help(const char *argv0) { " -n Don't load default script file\n", e); } -int pa_cmdline_parse(struct pa_daemon_conf *conf, int argc, char *const argv [], int *d) { - struct pa_strbuf *buf = NULL; +int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d) { + pa_strbuf *buf = NULL; int c; assert(conf && argc && argv); diff --git a/polyp/cmdline.h b/polyp/cmdline.h index ca100d1d..e2eaf0d2 100644 --- a/polyp/cmdline.h +++ b/polyp/cmdline.h @@ -26,7 +26,7 @@ /* Parese the command line and store its data in *c. Return the index * of the first unparsed argument in *d. */ -int pa_cmdline_parse(struct pa_daemon_conf*c, int argc, char *const argv [], int *d); +int pa_cmdline_parse(pa_daemon_conf*c, int argc, char *const argv [], int *d); /* Show the command line help. The command name is extracted from * argv[0] which should be passed in argv0. */ diff --git a/polyp/conf-parser.c b/polyp/conf-parser.c index 8d2f2f68..507f2bf1 100644 --- a/polyp/conf-parser.c +++ b/polyp/conf-parser.c @@ -37,7 +37,7 @@ #define COMMENTS "#;\n" /* Run the user supplied parser for an assignment */ -static int next_assignment(const char *filename, unsigned line, const struct pa_config_item *t, const char *lvalue, const char *rvalue, void *userdata) { +static int next_assignment(const char *filename, unsigned line, const pa_config_item *t, const char *lvalue, const char *rvalue, void *userdata) { assert(filename && t && lvalue && rvalue); for (; t->parse; t++) @@ -77,7 +77,7 @@ static char *strip(char *s) { } /* Parse a variable assignment line */ -static int parse_line(const char *filename, unsigned line, const struct pa_config_item *t, char *l, void *userdata) { +static int parse_line(const char *filename, unsigned line, const pa_config_item *t, char *l, void *userdata) { char *e, *c, *b = l+strspn(l, WHITESPACE); if ((c = strpbrk(b, COMMENTS))) @@ -98,7 +98,7 @@ static int parse_line(const char *filename, unsigned line, const struct pa_confi } /* Go through the file and parse each line */ -int pa_config_parse(const char *filename, FILE *f, const struct pa_config_item *t, void *userdata) { +int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void *userdata) { int r = -1; unsigned line = 0; int do_close = !f; @@ -138,7 +138,7 @@ finish: return r; } -int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { +int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { int *i = data; int32_t k; assert(filename && lvalue && rvalue && data); @@ -152,7 +152,7 @@ int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, return 0; } -int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { +int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { int *b = data, k; assert(filename && lvalue && rvalue && data); @@ -166,7 +166,7 @@ int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue return 0; } -int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { +int pa_config_parse_string(const char *filename, PA_GCC_UNUSED unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { char **s = data; assert(filename && lvalue && rvalue && data); diff --git a/polyp/conf-parser.h b/polyp/conf-parser.h index 9add0be0..2dca3bce 100644 --- a/polyp/conf-parser.h +++ b/polyp/conf-parser.h @@ -28,16 +28,16 @@ * files consisting of variable assignments only. */ /* Wraps info for parsing a specific configuration variable */ -struct pa_config_item { +typedef struct pa_config_item { const char *lvalue; /* name of the variable */ int (*parse)(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); /* Function that is called to parse the variable's value */ void *data; /* Where to store the variable's data */ -}; +} pa_config_item; /* The configuration file parsing routine. Expects a table of * pa_config_items in *t that is terminated by an item where lvalue is * NULL */ -int pa_config_parse(const char *filename, FILE *f, const struct pa_config_item *t, void *userdata); +int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void *userdata); /* Generic parsers for integers, booleans and strings */ int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); diff --git a/polyp/core.c b/polyp/core.c index 60439243..678e8212 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -41,9 +41,9 @@ #include "props.h" #include "random.h" -struct pa_core* pa_core_new(struct pa_mainloop_api *m) { - struct pa_core* c; - c = pa_xmalloc(sizeof(struct pa_core)); +pa_core* pa_core_new(pa_mainloop_api *m) { + pa_core* c; + c = pa_xmalloc(sizeof(pa_core)); c->mainloop = m; c->clients = pa_idxset_new(NULL, NULL); @@ -95,7 +95,7 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { return c; } -void pa_core_free(struct pa_core *c) { +void pa_core_free(pa_core *c) { assert(c); pa_module_unload_all(c); @@ -134,22 +134,22 @@ void pa_core_free(struct pa_core *c) { pa_xfree(c); } -static void quit_callback(struct pa_mainloop_api*m, struct pa_time_event *e, const struct timeval *tv, void *userdata) { - struct pa_core *c = userdata; +static void quit_callback(pa_mainloop_api*m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + pa_core *c = userdata; assert(c->quit_event = e); m->quit(m, 0); } -void pa_core_check_quit(struct pa_core *c) { +void pa_core_check_quit(pa_core *c) { assert(c); - if (!c->quit_event && c->exit_idle_time >= 0 && pa_idxset_ncontents(c->clients) == 0) { + if (!c->quit_event && c->exit_idle_time >= 0 && pa_idxset_size(c->clients) == 0) { struct timeval tv; pa_gettimeofday(&tv); tv.tv_sec+= c->exit_idle_time; c->quit_event = c->mainloop->time_new(c->mainloop, &tv, quit_callback, c); - } else if (c->quit_event && pa_idxset_ncontents(c->clients) > 0) { + } else if (c->quit_event && pa_idxset_size(c->clients) > 0) { c->mainloop->time_free(c->quit_event); c->quit_event = NULL; } diff --git a/polyp/core.h b/polyp/core.h index 8ef66570..704246a9 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -22,12 +22,16 @@ USA. ***/ +typedef struct pa_core pa_core; + #include "idxset.h" #include "hashmap.h" #include "mainloop-api.h" #include "sample.h" #include "memblock.h" #include "resampler.h" +#include "queue.h" +#include "subscribe.h" /* The core structure of polypaudio. Every polypaudio daemon contains * exactly one of these. It is used for storing kind of global @@ -38,41 +42,41 @@ struct pa_core { * polypaudio. Not cryptographically secure in any way. */ uint32_t cookie; - struct pa_mainloop_api *mainloop; + pa_mainloop_api *mainloop; /* idxset of all kinds of entities */ - struct pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache, *autoload_idxset; + pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache, *autoload_idxset; /* Some hashmaps for all sorts of entities */ - struct pa_hashmap *namereg, *autoload_hashmap, *properties; + pa_hashmap *namereg, *autoload_hashmap, *properties; /* The name of the default sink/source */ char *default_source_name, *default_sink_name; - struct pa_sample_spec default_sample_spec; - struct pa_time_event *module_auto_unload_event; - struct pa_defer_event *module_defer_unload_event; + pa_sample_spec default_sample_spec; + pa_time_event *module_auto_unload_event; + pa_defer_event *module_defer_unload_event; - struct pa_defer_event *subscription_defer_event; - struct pa_queue *subscription_event_queue; - struct pa_subscription *subscriptions; + pa_defer_event *subscription_defer_event; + pa_queue *subscription_event_queue; + pa_subscription *subscriptions; - struct pa_memblock_stat *memblock_stat; + pa_memblock_stat *memblock_stat; int disallow_module_loading, running_as_daemon; int exit_idle_time, module_idle_time, scache_idle_time; - struct pa_time_event *quit_event; + pa_time_event *quit_event; - struct pa_time_event *scache_auto_unload_event; + pa_time_event *scache_auto_unload_event; - enum pa_resample_method resample_method; + pa_resample_method resample_method; }; -struct pa_core* pa_core_new(struct pa_mainloop_api *m); -void pa_core_free(struct pa_core*c); +pa_core* pa_core_new(pa_mainloop_api *m); +void pa_core_free(pa_core*c); /* Check whether noone is connected to this core */ -void pa_core_check_quit(struct pa_core *c); +void pa_core_check_quit(pa_core *c); #endif diff --git a/polyp/cpulimit-test.c b/polyp/cpulimit-test.c index de5e20ad..598b2dd2 100644 --- a/polyp/cpulimit-test.c +++ b/polyp/cpulimit-test.c @@ -31,6 +31,7 @@ #include "cpulimit.h" #include "mainloop.h" +#include "gccmacro.h" #ifdef TEST2 #include "mainloop-signal.h" @@ -42,7 +43,7 @@ static time_t start; #ifdef TEST2 -static void func(struct pa_mainloop_api *m, struct pa_signal_event *e, int sig, void *userdata) { +static void func(pa_mainloop_api *m, PA_GCC_UNUSED pa_signal_event *e, PA_GCC_UNUSED int sig, PA_GCC_UNUSED void *userdata) { time_t now; time(&now); @@ -55,8 +56,8 @@ static void func(struct pa_mainloop_api *m, struct pa_signal_event *e, int sig, #endif -int main() { - struct pa_mainloop *m; +int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { + pa_mainloop *m; m = pa_mainloop_new(); assert(m); diff --git a/polyp/cpulimit.c b/polyp/cpulimit.c index 53920f50..a834b094 100644 --- a/polyp/cpulimit.c +++ b/polyp/cpulimit.c @@ -23,6 +23,10 @@ #include #endif +#include "cpulimit.h" +#include "util.h" +#include "log.h" + #ifdef HAVE_SIGXCPU #include @@ -37,11 +41,6 @@ #include #endif -#include "cpulimit.h" -#include "util.h" -#include "log.h" - - /* This module implements a watchdog that makes sure that the current * process doesn't consume more than 70% CPU time for 10 seconds. This * is very useful when using SCHED_FIFO scheduling which effectively @@ -70,8 +69,8 @@ static time_t last_time = 0; static int the_pipe[2] = {-1, -1}; /* Main event loop and IO event for the FIFO */ -static struct pa_mainloop_api *api = NULL; -static struct pa_io_event *io_event = NULL; +static pa_mainloop_api *api = NULL; +static pa_io_event *io_event = NULL; /* Saved sigaction struct for SIGXCPU */ static struct sigaction sigaction_prev; @@ -153,7 +152,7 @@ static void signal_handler(int sig) { } /* Callback for IO events on the FIFO */ -static void callback(struct pa_mainloop_api*m, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata) { +static void callback(pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags f, void *userdata) { char c; assert(m && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == the_pipe[0]); read(the_pipe[0], &c, sizeof(c)); @@ -161,7 +160,7 @@ static void callback(struct pa_mainloop_api*m, struct pa_io_event*e, int fd, enu } /* Initializes CPU load limiter */ -int pa_cpu_limit_init(struct pa_mainloop_api *m) { +int pa_cpu_limit_init(pa_mainloop_api *m) { struct sigaction sa; assert(m && !api && !io_event && the_pipe[0] == -1 && the_pipe[1] == -1 && !installed); @@ -227,9 +226,7 @@ void pa_cpu_limit_done(void) { #else /* HAVE_SIGXCPU */ -struct pa_mainloop_api; - -int pa_cpu_limit_init(struct pa_mainloop_api *m) { +int pa_cpu_limit_init(PA_GCC_UNUSED pa_mainloop_api *m) { return 0; } diff --git a/polyp/cpulimit.h b/polyp/cpulimit.h index a171da9b..8ca4f8d9 100644 --- a/polyp/cpulimit.h +++ b/polyp/cpulimit.h @@ -28,7 +28,7 @@ * CPU time. This is build around setrlimit() and SIGXCPU. It is handy * in case of using SCHED_FIFO which may freeze the whole machine */ -int pa_cpu_limit_init(struct pa_mainloop_api *m); +int pa_cpu_limit_init(pa_mainloop_api *m); void pa_cpu_limit_done(void); #endif diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c index 780581b2..4ad78bab 100644 --- a/polyp/daemon-conf.c +++ b/polyp/daemon-conf.c @@ -59,7 +59,7 @@ #define ENV_CONFIG_FILE "POLYP_CONFIG" #define ENV_DL_SEARCH_PATH "POLYP_DLPATH" -static const struct pa_daemon_conf default_conf = { +static const pa_daemon_conf default_conf = { .cmd = PA_CMD_DAEMON, .daemonize = 0, .fail = 1, @@ -79,9 +79,9 @@ static const struct pa_daemon_conf default_conf = { .use_pid_file = 1 }; -struct pa_daemon_conf* pa_daemon_conf_new(void) { +pa_daemon_conf* pa_daemon_conf_new(void) { FILE *f; - struct pa_daemon_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); + pa_daemon_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); if ((f = pa_open_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE, &c->default_script_file))) fclose(f); @@ -92,7 +92,7 @@ struct pa_daemon_conf* pa_daemon_conf_new(void) { return c; } -void pa_daemon_conf_free(struct pa_daemon_conf *c) { +void pa_daemon_conf_free(pa_daemon_conf *c) { assert(c); pa_xfree(c->script_commands); pa_xfree(c->dl_search_path); @@ -101,7 +101,7 @@ void pa_daemon_conf_free(struct pa_daemon_conf *c) { pa_xfree(c); } -int pa_daemon_conf_set_log_target(struct pa_daemon_conf *c, const char *string) { +int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string) { assert(c && string); if (!strcmp(string, "auto")) @@ -118,7 +118,7 @@ int pa_daemon_conf_set_log_target(struct pa_daemon_conf *c, const char *string) return 0; } -int pa_daemon_conf_set_log_level(struct pa_daemon_conf *c, const char *string) { +int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string) { uint32_t u; assert(c && string); @@ -126,7 +126,7 @@ int pa_daemon_conf_set_log_level(struct pa_daemon_conf *c, const char *string) { if (u >= PA_LOG_LEVEL_MAX) return -1; - c->log_level = (enum pa_log_level) u; + c->log_level = (pa_log_level) u; } else if (pa_startswith(string, "debug")) c->log_level = PA_LOG_DEBUG; else if (pa_startswith(string, "info")) @@ -143,7 +143,7 @@ int pa_daemon_conf_set_log_level(struct pa_daemon_conf *c, const char *string) { return 0; } -int pa_daemon_conf_set_resample_method(struct pa_daemon_conf *c, const char *string) { +int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string) { int m; assert(c && string); @@ -154,8 +154,8 @@ int pa_daemon_conf_set_resample_method(struct pa_daemon_conf *c, const char *str return 0; } -static int parse_log_target(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { - struct pa_daemon_conf *c = data; +static int parse_log_target(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + pa_daemon_conf *c = data; assert(filename && lvalue && rvalue && data); if (pa_daemon_conf_set_log_target(c, rvalue) < 0) { @@ -166,8 +166,8 @@ static int parse_log_target(const char *filename, unsigned line, const char *lva return 0; } -static int parse_log_level(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { - struct pa_daemon_conf *c = data; +static int parse_log_level(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + pa_daemon_conf *c = data; assert(filename && lvalue && rvalue && data); if (pa_daemon_conf_set_log_level(c, rvalue) < 0) { @@ -178,8 +178,8 @@ static int parse_log_level(const char *filename, unsigned line, const char *lval return 0; } -static int parse_resample_method(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { - struct pa_daemon_conf *c = data; +static int parse_resample_method(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + pa_daemon_conf *c = data; assert(filename && lvalue && rvalue && data); if (pa_daemon_conf_set_resample_method(c, rvalue) < 0) { @@ -190,11 +190,11 @@ static int parse_resample_method(const char *filename, unsigned line, const char return 0; } -int pa_daemon_conf_load(struct pa_daemon_conf *c, const char *filename) { +int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { int r = -1; FILE *f = NULL; - struct pa_config_item table[] = { + pa_config_item table[] = { { "daemonize", pa_config_parse_bool, NULL }, { "fail", pa_config_parse_bool, NULL }, { "high-priority", pa_config_parse_bool, NULL }, @@ -248,7 +248,7 @@ finish: return r; } -int pa_daemon_conf_env(struct pa_daemon_conf *c) { +int pa_daemon_conf_env(pa_daemon_conf *c) { char *e; if ((e = getenv(ENV_DL_SEARCH_PATH))) { @@ -271,8 +271,8 @@ static const char* const log_level_to_string[] = { [PA_LOG_ERROR] = "error" }; -char *pa_daemon_conf_dump(struct pa_daemon_conf *c) { - struct pa_strbuf *s = pa_strbuf_new(); +char *pa_daemon_conf_dump(pa_daemon_conf *c) { + pa_strbuf *s = pa_strbuf_new(); if (c->config_file) pa_strbuf_printf(s, "### Read from configuration file: %s ###\n", c->config_file); diff --git a/polyp/daemon-conf.h b/polyp/daemon-conf.h index 30137e8b..4eb61365 100644 --- a/polyp/daemon-conf.h +++ b/polyp/daemon-conf.h @@ -25,7 +25,7 @@ #include "log.h" /* The actual command to execute */ -enum pa_daemon_conf_cmd { +typedef enum pa_daemon_conf_cmd { PA_CMD_DAEMON, /* the default */ PA_CMD_HELP, PA_CMD_VERSION, @@ -33,11 +33,11 @@ enum pa_daemon_conf_cmd { PA_CMD_DUMP_MODULES, PA_CMD_KILL, PA_CMD_CHECK -}; +} pa_daemon_conf_cmd; /* A structure containing configuration data for the Polypaudio server . */ -struct pa_daemon_conf { - enum pa_daemon_conf_cmd cmd; +typedef struct pa_daemon_conf { + pa_daemon_conf_cmd cmd; int daemonize, fail, high_priority, @@ -48,33 +48,33 @@ struct pa_daemon_conf { auto_log_target, use_pid_file; char *script_commands, *dl_search_path, *default_script_file; - enum pa_log_target log_target; - enum pa_log_level log_level; + pa_log_target log_target; + pa_log_level log_level; int resample_method; char *config_file; -}; +} pa_daemon_conf; /* Allocate a new structure and fill it with sane defaults */ -struct pa_daemon_conf* pa_daemon_conf_new(void); -void pa_daemon_conf_free(struct pa_daemon_conf*c); +pa_daemon_conf* pa_daemon_conf_new(void); +void pa_daemon_conf_free(pa_daemon_conf*c); /* Load configuration data from the specified file overwriting the * current settings in *c. If filename is NULL load the default daemon * configuration file */ -int pa_daemon_conf_load(struct pa_daemon_conf *c, const char *filename); +int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename); /* Pretty print the current configuration data of the daemon. The * returned string has to be freed manually. The output of this * function may be parsed with pa_daemon_conf_load(). */ -char *pa_daemon_conf_dump(struct pa_daemon_conf *c); +char *pa_daemon_conf_dump(pa_daemon_conf *c); /* Load the configuration data from the process' environment * overwriting the current settings in *c. */ -int pa_daemon_conf_env(struct pa_daemon_conf *c); +int pa_daemon_conf_env(pa_daemon_conf *c); /* Set these configuration variables in the structure by passing a string */ -int pa_daemon_conf_set_log_target(struct pa_daemon_conf *c, const char *string); -int pa_daemon_conf_set_log_level(struct pa_daemon_conf *c, const char *string); -int pa_daemon_conf_set_resample_method(struct pa_daemon_conf *c, const char *string); +int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string); +int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string); +int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string); #endif diff --git a/polyp/dumpmodules.c b/polyp/dumpmodules.c index 5aaa108d..6864b965 100644 --- a/polyp/dumpmodules.c +++ b/polyp/dumpmodules.c @@ -35,12 +35,12 @@ #define PREFIX "module-" -static void short_info(const char *name, const char *path, struct pa_modinfo *i) { +static void short_info(const char *name, PA_GCC_UNUSED const char *path, pa_modinfo *i) { assert(name && i); printf("%-40s%s\n", name, i->description ? i->description : "n/a"); } -static void long_info(const char *name, const char *path, struct pa_modinfo *i) { +static void long_info(const char *name, const char *path, pa_modinfo *i) { static int nl = 0; assert(name && i); @@ -68,8 +68,8 @@ static void long_info(const char *name, const char *path, struct pa_modinfo *i) printf("Path: %s\n", path); } -static void show_info(const char *name, const char *path, void (*info)(const char *name, const char *path, struct pa_modinfo*i)) { - struct pa_modinfo *i; +static void show_info(const char *name, const char *path, void (*info)(const char *name, const char *path, pa_modinfo*i)) { + pa_modinfo *i; if ((i = pa_modinfo_get_by_name(path ? path : name))) { info(name, path, i); @@ -79,7 +79,7 @@ static void show_info(const char *name, const char *path, void (*info)(const cha static int callback(const char *path, lt_ptr data) { const char *e; - struct pa_daemon_conf *c = (data); + pa_daemon_conf *c = (data); e = pa_path_get_filename(path); @@ -89,7 +89,7 @@ static int callback(const char *path, lt_ptr data) { return 0; } -void pa_dump_modules(struct pa_daemon_conf *c, int argc, char * const argv[]) { +void pa_dump_modules(pa_daemon_conf *c, int argc, char * const argv[]) { if (argc > 0) { int i; for (i = 0; i < argc; i++) diff --git a/polyp/dumpmodules.h b/polyp/dumpmodules.h index fadc571f..968d2de9 100644 --- a/polyp/dumpmodules.h +++ b/polyp/dumpmodules.h @@ -26,6 +26,6 @@ /* Dump all available modules to STDOUT. If argc > 0 print information * about the modules specified in argv[] instead. */ -void pa_dump_modules(struct pa_daemon_conf *c, int argc, char * const argv[]); +void pa_dump_modules(pa_daemon_conf *c, int argc, char * const argv[]); #endif diff --git a/polyp/dynarray.c b/polyp/dynarray.c index 0e406ea1..435fd768 100644 --- a/polyp/dynarray.c +++ b/polyp/dynarray.c @@ -38,16 +38,16 @@ struct pa_dynarray { unsigned n_allocated, n_entries; }; -struct pa_dynarray* pa_dynarray_new(void) { - struct pa_dynarray *a; - a = pa_xmalloc(sizeof(struct pa_dynarray)); +pa_dynarray* pa_dynarray_new(void) { + pa_dynarray *a; + a = pa_xnew(pa_dynarray, 1); a->data = NULL; a->n_entries = 0; a->n_allocated = 0; return a; } -void pa_dynarray_free(struct pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata) { +void pa_dynarray_free(pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata) { unsigned i; assert(a); @@ -60,7 +60,7 @@ void pa_dynarray_free(struct pa_dynarray* a, void (*func)(void *p, void *userdat pa_xfree(a); } -void pa_dynarray_put(struct pa_dynarray*a, unsigned i, void *p) { +void pa_dynarray_put(pa_dynarray*a, unsigned i, void *p) { assert(a); if (i >= a->n_allocated) { @@ -81,13 +81,13 @@ void pa_dynarray_put(struct pa_dynarray*a, unsigned i, void *p) { a->n_entries = i+1; } -unsigned pa_dynarray_append(struct pa_dynarray*a, void *p) { +unsigned pa_dynarray_append(pa_dynarray*a, void *p) { unsigned i = a->n_entries; pa_dynarray_put(a, i, p); return i; } -void *pa_dynarray_get(struct pa_dynarray*a, unsigned i) { +void *pa_dynarray_get(pa_dynarray*a, unsigned i) { assert(a); if (i >= a->n_allocated) return NULL; @@ -96,7 +96,7 @@ void *pa_dynarray_get(struct pa_dynarray*a, unsigned i) { return a->data[i]; } -unsigned pa_dynarray_ncontents(struct pa_dynarray*a) { +unsigned pa_dynarray_size(pa_dynarray*a) { assert(a); return a->n_entries; } diff --git a/polyp/dynarray.h b/polyp/dynarray.h index 6733e958..9b1601ba 100644 --- a/polyp/dynarray.h +++ b/polyp/dynarray.h @@ -22,28 +22,28 @@ USA. ***/ -struct pa_dynarray; +typedef struct pa_dynarray pa_dynarray; /* Implementation of a simple dynamically sized array. The array * expands if required, but doesn't shrink if possible. Memory * management of the array's entries is the user's job. */ -struct pa_dynarray* pa_dynarray_new(void); +pa_dynarray* pa_dynarray_new(void); /* Free the array calling the specified function for every entry in * the array. The function may be NULL. */ -void pa_dynarray_free(struct pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata); +void pa_dynarray_free(pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata); /* Store p at position i in the array */ -void pa_dynarray_put(struct pa_dynarray*a, unsigned i, void *p); +void pa_dynarray_put(pa_dynarray*a, unsigned i, void *p); /* Store p a the first free position in the array. Returns the index * of that entry. If entries are removed from the array their position * are not filled any more by this function. */ -unsigned pa_dynarray_append(struct pa_dynarray*a, void *p); +unsigned pa_dynarray_append(pa_dynarray*a, void *p); -void *pa_dynarray_get(struct pa_dynarray*a, unsigned i); +void *pa_dynarray_get(pa_dynarray*a, unsigned i); -unsigned pa_dynarray_ncontents(struct pa_dynarray*a); +unsigned pa_dynarray_size(pa_dynarray*a); #endif diff --git a/polyp/gcc-printf.h b/polyp/gcc-printf.h deleted file mode 100644 index 70679df9..00000000 --- a/polyp/gcc-printf.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef foogccprintfhfoo -#define foogccprintfhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -/* If we're in GNU C, use some magic for detecting invalid format strings */ - -#ifdef __GNUC__ -#define PA_GCC_PRINTF_ATTR(a,b) __attribute__ ((format (printf, a, b))) -#else -#define PA_GCC_PRINTF_ATTR(a,b) -#endif - -#endif diff --git a/polyp/gccmacro.h b/polyp/gccmacro.h new file mode 100644 index 00000000..9e212f2e --- /dev/null +++ b/polyp/gccmacro.h @@ -0,0 +1,53 @@ +#ifndef foogccmacrohfoo +#define foogccmacrohfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef __GNUC__ +#define PA_GCC_PRINTF_ATTR(a,b) __attribute__ ((format (printf, a, b))) +#else +/** If we're in GNU C, use some magic for detecting invalid format strings */ +#define PA_GCC_PRINTF_ATTR(a,b) +#endif + +#if defined(__GNUC__) && (__GNUC__ >= 4) +#define PA_GCC_SENTINEL __attribute__ ((sentinel)) +#else +/** Macro for usage of GCC's sentinel compilation warnings */ +#define PA_GCC_SENTINEL +#endif + +#ifdef __GNUC__ +#define PA_GCC_NORETURN __attribute__((noreturn)) +#else +/** Macro for no-return functions */ +#define PA_GCC_NORETURN +#endif + +#ifdef __GNUC__ +#define PA_GCC_UNUSED __attribute__ ((unused)) +#else +/** Macro for not used parameter */ +#define PA_GCC_UNUSED +#endif + +#endif diff --git a/polyp/glib-mainloop.c b/polyp/glib-mainloop.c index 0f96a594..6552da15 100644 --- a/polyp/glib-mainloop.c +++ b/polyp/glib-mainloop.c @@ -28,62 +28,64 @@ #include "glib-mainloop.h" #include "idxset.h" #include "xmalloc.h" +#include "glib.h" +#include "util.h" -struct pa_io_event { - struct pa_glib_mainloop *mainloop; +struct pa_io_event { + pa_glib_mainloop *mainloop; int dead; GIOChannel *io_channel; GSource *source; GIOCondition io_condition; int fd; - void (*callback) (struct pa_mainloop_api*m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata); + void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata); void *userdata; - void (*destroy_callback) (struct pa_mainloop_api *m, struct pa_io_event*e, void *userdata); - struct pa_io_event *next, *prev; + void (*destroy_callback) (pa_mainloop_api *m, pa_io_event*e, void *userdata); + pa_io_event *next, *prev; }; struct pa_time_event { - struct pa_glib_mainloop *mainloop; + pa_glib_mainloop *mainloop; int dead; GSource *source; struct timeval timeval; - void (*callback) (struct pa_mainloop_api*m, struct pa_time_event *e, const struct timeval *tv, void *userdata); + void (*callback) (pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata); void *userdata; - void (*destroy_callback) (struct pa_mainloop_api *m, struct pa_time_event*e, void *userdata); - struct pa_time_event *next, *prev; + void (*destroy_callback) (pa_mainloop_api *m, pa_time_event*e, void *userdata); + pa_time_event *next, *prev; }; struct pa_defer_event { - struct pa_glib_mainloop *mainloop; + pa_glib_mainloop *mainloop; int dead; GSource *source; - void (*callback) (struct pa_mainloop_api*m, struct pa_defer_event *e, void *userdata); + void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata); void *userdata; - void (*destroy_callback) (struct pa_mainloop_api *m, struct pa_defer_event*e, void *userdata); - struct pa_defer_event *next, *prev; + void (*destroy_callback) (pa_mainloop_api *m, pa_defer_event*e, void *userdata); + pa_defer_event *next, *prev; }; struct pa_glib_mainloop { GMainContext *glib_main_context; - struct pa_mainloop_api api; + pa_mainloop_api api; GSource *cleanup_source; - struct pa_io_event *io_events, *dead_io_events; - struct pa_time_event *time_events, *dead_time_events; - struct pa_defer_event *defer_events, *dead_defer_events; + pa_io_event *io_events, *dead_io_events; + pa_time_event *time_events, *dead_time_events; + pa_defer_event *defer_events, *dead_defer_events; }; -static void schedule_free_dead_events(struct pa_glib_mainloop *g); +static void schedule_free_dead_events(pa_glib_mainloop *g); -static void glib_io_enable(struct pa_io_event*e, enum pa_io_event_flags f); +static void glib_io_enable(pa_io_event*e, pa_io_event_flags f); -static struct pa_io_event* glib_io_new(struct pa_mainloop_api*m, int fd, enum pa_io_event_flags f, void (*callback) (struct pa_mainloop_api*m, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata), void *userdata) { - struct pa_io_event *e; - struct pa_glib_mainloop *g; +static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags f, void *userdata), void *userdata) { + pa_io_event *e; + pa_glib_mainloop *g; assert(m && m->userdata && fd >= 0 && callback); g = m->userdata; - e = pa_xmalloc(sizeof(struct pa_io_event)); + e = pa_xmalloc(sizeof(pa_io_event)); e->mainloop = m->userdata; e->dead = 0; e->fd = fd; @@ -108,8 +110,8 @@ static struct pa_io_event* glib_io_new(struct pa_mainloop_api*m, int fd, enum pa /* The callback GLIB calls whenever an IO condition is met */ static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { - struct pa_io_event *e = data; - enum pa_io_event_flags f; + pa_io_event *e = data; + pa_io_event_flags f; assert(source && e && e->io_channel == source); f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | @@ -121,7 +123,7 @@ static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) return TRUE; } -static void glib_io_enable(struct pa_io_event*e, enum pa_io_event_flags f) { +static void glib_io_enable(pa_io_event*e, pa_io_event_flags f) { GIOCondition c; assert(e && !e->dead); @@ -145,7 +147,7 @@ static void glib_io_enable(struct pa_io_event*e, enum pa_io_event_flags f) { e->io_condition = c; } -static void glib_io_free(struct pa_io_event*e) { +static void glib_io_free(pa_io_event*e) { assert(e && !e->dead); if (e->source) { @@ -172,23 +174,23 @@ static void glib_io_free(struct pa_io_event*e) { schedule_free_dead_events(e->mainloop); } -static void glib_io_set_destroy(struct pa_io_event*e, void (*callback)(struct pa_mainloop_api*m, struct pa_io_event *e, void *userdata)) { +static void glib_io_set_destroy(pa_io_event*e, void (*callback)(pa_mainloop_api*m, pa_io_event *e, void *userdata)) { assert(e); e->destroy_callback = callback; } /* Time sources */ -static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv); +static void glib_time_restart(pa_time_event*e, const struct timeval *tv); -static struct pa_time_event* glib_time_new(struct pa_mainloop_api*m, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*m, struct pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { - struct pa_glib_mainloop *g; - struct pa_time_event *e; +static pa_time_event* glib_time_new(pa_mainloop_api*m, const struct timeval *tv, void (*callback) (pa_mainloop_api*m, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { + pa_glib_mainloop *g; + pa_time_event *e; assert(m && m->userdata && tv && callback); g = m->userdata; - e = pa_xmalloc(sizeof(struct pa_time_event)); + e = pa_xmalloc(sizeof(pa_time_event)); e->mainloop = g; e->dead = 0; e->callback = callback; @@ -227,7 +229,7 @@ static guint msec_diff(const struct timeval *a, const struct timeval *b) { } static gboolean time_cb(gpointer data) { - struct pa_time_event* e = data; + pa_time_event* e = data; assert(e && e->mainloop && e->source); g_source_unref(e->source); @@ -237,7 +239,7 @@ static gboolean time_cb(gpointer data) { return FALSE; } -static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv) { +static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { struct timeval now; assert(e && e->mainloop && !e->dead); @@ -258,7 +260,7 @@ static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv) e->source = NULL; } -static void glib_time_free(struct pa_time_event *e) { +static void glib_time_free(pa_time_event *e) { assert(e && e->mainloop && !e->dead); if (e->source) { @@ -285,23 +287,23 @@ static void glib_time_free(struct pa_time_event *e) { schedule_free_dead_events(e->mainloop); } -static void glib_time_set_destroy(struct pa_time_event *e, void (*callback)(struct pa_mainloop_api*m, struct pa_time_event*e, void *userdata)) { +static void glib_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*m, pa_time_event*e, void *userdata)) { assert(e); e->destroy_callback = callback; } /* Deferred sources */ -static void glib_defer_enable(struct pa_defer_event *e, int b); +static void glib_defer_enable(pa_defer_event *e, int b); -static struct pa_defer_event* glib_defer_new(struct pa_mainloop_api*m, void (*callback) (struct pa_mainloop_api*m, struct pa_defer_event *e, void *userdata), void *userdata) { - struct pa_defer_event *e; - struct pa_glib_mainloop *g; +static pa_defer_event* glib_defer_new(pa_mainloop_api*m, void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata), void *userdata) { + pa_defer_event *e; + pa_glib_mainloop *g; assert(m && m->userdata && callback); g = m->userdata; - e = pa_xmalloc(sizeof(struct pa_defer_event)); + e = pa_xmalloc(sizeof(pa_defer_event)); e->mainloop = g; e->dead = 0; e->callback = callback; @@ -319,14 +321,14 @@ static struct pa_defer_event* glib_defer_new(struct pa_mainloop_api*m, void (*ca } static gboolean idle_cb(gpointer data) { - struct pa_defer_event* e = data; + pa_defer_event* e = data; assert(e && e->mainloop && e->source); e->callback(&e->mainloop->api, e, e->userdata); return TRUE; } -static void glib_defer_enable(struct pa_defer_event *e, int b) { +static void glib_defer_enable(pa_defer_event *e, int b) { assert(e && e->mainloop); if (e->source && !b) { @@ -342,7 +344,7 @@ static void glib_defer_enable(struct pa_defer_event *e, int b) { } } -static void glib_defer_free(struct pa_defer_event *e) { +static void glib_defer_free(pa_defer_event *e) { assert(e && e->mainloop && !e->dead); if (e->source) { @@ -369,22 +371,22 @@ static void glib_defer_free(struct pa_defer_event *e) { schedule_free_dead_events(e->mainloop); } -static void glib_defer_set_destroy(struct pa_defer_event *e, void (*callback)(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata)) { +static void glib_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api *m, pa_defer_event *e, void *userdata)) { assert(e); e->destroy_callback = callback; } /* quit() */ -static void glib_quit(struct pa_mainloop_api*a, int retval) { - struct pa_glib_mainloop *g; +static void glib_quit(pa_mainloop_api*a, PA_GCC_UNUSED int retval) { + pa_glib_mainloop *g; assert(a && a->userdata); g = a->userdata; /* NOOP */ } -static const struct pa_mainloop_api vtable = { +static const pa_mainloop_api vtable = { .userdata = NULL, .io_new = glib_io_new, @@ -405,10 +407,10 @@ static const struct pa_mainloop_api vtable = { .quit = glib_quit, }; -struct pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) { - struct pa_glib_mainloop *g; +pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) { + pa_glib_mainloop *g; - g = pa_xmalloc(sizeof(struct pa_glib_mainloop)); + g = pa_xmalloc(sizeof(pa_glib_mainloop)); if (c) { g->glib_main_context = c; g_main_context_ref(c); @@ -426,9 +428,9 @@ struct pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) { return g; } -static void free_io_events(struct pa_io_event *e) { +static void free_io_events(pa_io_event *e) { while (e) { - struct pa_io_event *r = e; + pa_io_event *r = e; e = r->next; if (r->source) { @@ -446,9 +448,9 @@ static void free_io_events(struct pa_io_event *e) { } } -static void free_time_events(struct pa_time_event *e) { +static void free_time_events(pa_time_event *e) { while (e) { - struct pa_time_event *r = e; + pa_time_event *r = e; e = r->next; if (r->source) { @@ -463,9 +465,9 @@ static void free_time_events(struct pa_time_event *e) { } } -static void free_defer_events(struct pa_defer_event *e) { +static void free_defer_events(pa_defer_event *e) { while (e) { - struct pa_defer_event *r = e; + pa_defer_event *r = e; e = r->next; if (r->source) { @@ -480,7 +482,7 @@ static void free_defer_events(struct pa_defer_event *e) { } } -void pa_glib_mainloop_free(struct pa_glib_mainloop* g) { +void pa_glib_mainloop_free(pa_glib_mainloop* g) { assert(g); free_io_events(g->io_events); @@ -499,13 +501,13 @@ void pa_glib_mainloop_free(struct pa_glib_mainloop* g) { pa_xfree(g); } -struct pa_mainloop_api* pa_glib_mainloop_get_api(struct pa_glib_mainloop *g) { +pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) { assert(g); return &g->api; } static gboolean free_dead_events(gpointer p) { - struct pa_glib_mainloop *g = p; + pa_glib_mainloop *g = p; assert(g); free_io_events(g->dead_io_events); @@ -523,7 +525,7 @@ static gboolean free_dead_events(gpointer p) { return FALSE; } -static void schedule_free_dead_events(struct pa_glib_mainloop *g) { +static void schedule_free_dead_events(pa_glib_mainloop *g) { assert(g && g->glib_main_context); if (g->cleanup_source) diff --git a/polyp/glib-mainloop.h b/polyp/glib-mainloop.h index d830561f..d3e98597 100644 --- a/polyp/glib-mainloop.h +++ b/polyp/glib-mainloop.h @@ -32,23 +32,23 @@ PA_C_DECL_BEGIN -/** \struct pa_glib_mainloop +/** \pa_glib_mainloop * An opaque GLIB main loop object */ -struct pa_glib_mainloop; +typedef struct pa_glib_mainloop pa_glib_mainloop; /** Create a new GLIB main loop object for the specified GLIB main loop context. If c is NULL the default context is used. */ #if GLIB_MAJOR_VERSION >= 2 -struct pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c); +pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c); #else -struct pa_glib_mainloop *pa_glib_mainloop_new(void); +pa_glib_mainloop *pa_glib_mainloop_new(void); #endif /** Free the GLIB main loop object */ -void pa_glib_mainloop_free(struct pa_glib_mainloop* g); +void pa_glib_mainloop_free(pa_glib_mainloop* g); /** Return the abstract main loop API vtable for the GLIB main loop object */ -struct pa_mainloop_api* pa_glib_mainloop_get_api(struct pa_glib_mainloop *g); +pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g); PA_C_DECL_END diff --git a/polyp/glib12-mainloop.c b/polyp/glib12-mainloop.c index c328471c..e322ac07 100644 --- a/polyp/glib12-mainloop.c +++ b/polyp/glib12-mainloop.c @@ -28,63 +28,64 @@ #include "glib-mainloop.h" #include "idxset.h" #include "xmalloc.h" +#include "util.h" /* A mainloop implementation based on GLIB 1.2 */ struct pa_io_event { - struct pa_glib_mainloop *mainloop; + pa_glib_mainloop *mainloop; int dead; GIOChannel *io_channel; guint source; GIOCondition io_condition; int fd; - void (*callback) (struct pa_mainloop_api*m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata); + void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata); void *userdata; - void (*destroy_callback) (struct pa_mainloop_api *m, struct pa_io_event*e, void *userdata); - struct pa_io_event *next, *prev; + void (*destroy_callback) (pa_mainloop_api *m, pa_io_event*e, void *userdata); + pa_io_event *next, *prev; }; struct pa_time_event { - struct pa_glib_mainloop *mainloop; + pa_glib_mainloop *mainloop; int dead; guint source; struct timeval timeval; - void (*callback) (struct pa_mainloop_api*m, struct pa_time_event *e, const struct timeval *tv, void *userdata); + void (*callback) (pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata); void *userdata; - void (*destroy_callback) (struct pa_mainloop_api *m, struct pa_time_event*e, void *userdata); - struct pa_time_event *next, *prev; + void (*destroy_callback) (pa_mainloop_api *m, pa_time_event*e, void *userdata); + pa_time_event *next, *prev; }; struct pa_defer_event { - struct pa_glib_mainloop *mainloop; + pa_glib_mainloop *mainloop; int dead; guint source; - void (*callback) (struct pa_mainloop_api*m, struct pa_defer_event *e, void *userdata); + void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata); void *userdata; - void (*destroy_callback) (struct pa_mainloop_api *m, struct pa_defer_event*e, void *userdata); - struct pa_defer_event *next, *prev; + void (*destroy_callback) (pa_mainloop_api *m, pa_defer_event*e, void *userdata); + pa_defer_event *next, *prev; }; struct pa_glib_mainloop { - struct pa_mainloop_api api; + pa_mainloop_api api; guint cleanup_source; - struct pa_io_event *io_events, *dead_io_events; - struct pa_time_event *time_events, *dead_time_events; - struct pa_defer_event *defer_events, *dead_defer_events; + pa_io_event *io_events, *dead_io_events; + pa_time_event *time_events, *dead_time_events; + pa_defer_event *defer_events, *dead_defer_events; }; -static void schedule_free_dead_events(struct pa_glib_mainloop *g); +static void schedule_free_dead_events(pa_glib_mainloop *g); -static void glib_io_enable(struct pa_io_event*e, enum pa_io_event_flags f); +static void glib_io_enable(pa_io_event*e, pa_io_event_flags f); -static struct pa_io_event* glib_io_new(struct pa_mainloop_api*m, int fd, enum pa_io_event_flags f, void (*callback) (struct pa_mainloop_api*m, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata), void *userdata) { - struct pa_io_event *e; - struct pa_glib_mainloop *g; +static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags f, void *userdata), void *userdata) { + pa_io_event *e; + pa_glib_mainloop *g; assert(m && m->userdata && fd >= 0 && callback); g = m->userdata; - e = pa_xmalloc(sizeof(struct pa_io_event)); + e = pa_xmalloc(sizeof(pa_io_event)); e->mainloop = m->userdata; e->dead = 0; e->fd = fd; @@ -108,8 +109,8 @@ static struct pa_io_event* glib_io_new(struct pa_mainloop_api*m, int fd, enum pa } static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { - struct pa_io_event *e = data; - enum pa_io_event_flags f; + pa_io_event *e = data; + pa_io_event_flags f; assert(source && e && e->io_channel == source); f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | @@ -121,7 +122,7 @@ static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) return TRUE; } -static void glib_io_enable(struct pa_io_event*e, enum pa_io_event_flags f) { +static void glib_io_enable(pa_io_event*e, pa_io_event_flags f) { GIOCondition c; assert(e && !e->dead); @@ -138,7 +139,7 @@ static void glib_io_enable(struct pa_io_event*e, enum pa_io_event_flags f) { e->io_condition = c; } -static void glib_io_free(struct pa_io_event*e) { +static void glib_io_free(pa_io_event*e) { assert(e && !e->dead); if (e->source != (guint) -1) { @@ -164,23 +165,23 @@ static void glib_io_free(struct pa_io_event*e) { schedule_free_dead_events(e->mainloop); } -static void glib_io_set_destroy(struct pa_io_event*e, void (*callback)(struct pa_mainloop_api*m, struct pa_io_event *e, void *userdata)) { +static void glib_io_set_destroy(pa_io_event*e, void (*callback)(pa_mainloop_api*m, pa_io_event *e, void *userdata)) { assert(e); e->destroy_callback = callback; } /* Time sources */ -static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv); +static void glib_time_restart(pa_time_event*e, const struct timeval *tv); -static struct pa_time_event* glib_time_new(struct pa_mainloop_api*m, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*m, struct pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { - struct pa_glib_mainloop *g; - struct pa_time_event *e; +static pa_time_event* glib_time_new(pa_mainloop_api*m, const struct timeval *tv, void (*callback) (pa_mainloop_api*m, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { + pa_glib_mainloop *g; + pa_time_event *e; assert(m && m->userdata && tv && callback); g = m->userdata; - e = pa_xmalloc(sizeof(struct pa_time_event)); + e = pa_xmalloc(sizeof(pa_time_event)); e->mainloop = g; e->dead = 0; e->callback = callback; @@ -219,7 +220,7 @@ static guint msec_diff(const struct timeval *a, const struct timeval *b) { } static gboolean time_cb(gpointer data) { - struct pa_time_event* e = data; + pa_time_event* e = data; assert(e && e->mainloop && e->source != (guint) -1); g_source_remove(e->source); @@ -229,7 +230,7 @@ static gboolean time_cb(gpointer data) { return FALSE; } -static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv) { +static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { struct timeval now; assert(e && e->mainloop && !e->dead); @@ -245,7 +246,7 @@ static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv) e->source = (guint) -1; } -static void glib_time_free(struct pa_time_event *e) { +static void glib_time_free(pa_time_event *e) { assert(e && e->mainloop && !e->dead); if (e->source != (guint) -1) { @@ -271,23 +272,23 @@ static void glib_time_free(struct pa_time_event *e) { schedule_free_dead_events(e->mainloop); } -static void glib_time_set_destroy(struct pa_time_event *e, void (*callback)(struct pa_mainloop_api*m, struct pa_time_event*e, void *userdata)) { +static void glib_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*m, pa_time_event*e, void *userdata)) { assert(e); e->destroy_callback = callback; } /* Deferred sources */ -static void glib_defer_enable(struct pa_defer_event *e, int b); +static void glib_defer_enable(pa_defer_event *e, int b); -static struct pa_defer_event* glib_defer_new(struct pa_mainloop_api*m, void (*callback) (struct pa_mainloop_api*m, struct pa_defer_event *e, void *userdata), void *userdata) { - struct pa_defer_event *e; - struct pa_glib_mainloop *g; +static pa_defer_event* glib_defer_new(pa_mainloop_api*m, void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata), void *userdata) { + pa_defer_event *e; + pa_glib_mainloop *g; assert(m && m->userdata && callback); g = m->userdata; - e = pa_xmalloc(sizeof(struct pa_defer_event)); + e = pa_xmalloc(sizeof(pa_defer_event)); e->mainloop = g; e->dead = 0; e->callback = callback; @@ -305,14 +306,14 @@ static struct pa_defer_event* glib_defer_new(struct pa_mainloop_api*m, void (*ca } static gboolean idle_cb(gpointer data) { - struct pa_defer_event* e = data; + pa_defer_event* e = data; assert(e && e->mainloop && e->source != (guint) -1); e->callback(&e->mainloop->api, e, e->userdata); return TRUE; } -static void glib_defer_enable(struct pa_defer_event *e, int b) { +static void glib_defer_enable(pa_defer_event *e, int b) { assert(e && e->mainloop); if (e->source != (guint) -1 && !b) { @@ -324,7 +325,7 @@ static void glib_defer_enable(struct pa_defer_event *e, int b) { } } -static void glib_defer_free(struct pa_defer_event *e) { +static void glib_defer_free(pa_defer_event *e) { assert(e && e->mainloop && !e->dead); if (e->source != (guint) -1) { @@ -350,22 +351,22 @@ static void glib_defer_free(struct pa_defer_event *e) { schedule_free_dead_events(e->mainloop); } -static void glib_defer_set_destroy(struct pa_defer_event *e, void (*callback)(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata)) { +static void glib_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api *m, pa_defer_event *e, void *userdata)) { assert(e); e->destroy_callback = callback; } /* quit() */ -static void glib_quit(struct pa_mainloop_api*a, int retval) { - struct pa_glib_mainloop *g; +static void glib_quit(pa_mainloop_api*a, PA_GCC_UNUSED int retval) { + pa_glib_mainloop *g; assert(a && a->userdata); g = a->userdata; /* NOOP */ } -static const struct pa_mainloop_api vtable = { +static const pa_mainloop_api vtable = { .userdata = NULL, .io_new = glib_io_new, @@ -386,10 +387,10 @@ static const struct pa_mainloop_api vtable = { .quit = glib_quit, }; -struct pa_glib_mainloop *pa_glib_mainloop_new(void) { - struct pa_glib_mainloop *g; +pa_glib_mainloop *pa_glib_mainloop_new(void) { + pa_glib_mainloop *g; - g = pa_xmalloc(sizeof(struct pa_glib_mainloop)); + g = pa_xmalloc(sizeof(pa_glib_mainloop)); g->api = vtable; g->api.userdata = g; @@ -402,9 +403,9 @@ struct pa_glib_mainloop *pa_glib_mainloop_new(void) { return g; } -static void free_io_events(struct pa_io_event *e) { +static void free_io_events(pa_io_event *e) { while (e) { - struct pa_io_event *r = e; + pa_io_event *r = e; e = r->next; if (r->source != (guint) -1) @@ -420,9 +421,9 @@ static void free_io_events(struct pa_io_event *e) { } } -static void free_time_events(struct pa_time_event *e) { +static void free_time_events(pa_time_event *e) { while (e) { - struct pa_time_event *r = e; + pa_time_event *r = e; e = r->next; if (r->source != (guint) -1) @@ -435,9 +436,9 @@ static void free_time_events(struct pa_time_event *e) { } } -static void free_defer_events(struct pa_defer_event *e) { +static void free_defer_events(pa_defer_event *e) { while (e) { - struct pa_defer_event *r = e; + pa_defer_event *r = e; e = r->next; if (r->source != (guint) -1) @@ -450,7 +451,7 @@ static void free_defer_events(struct pa_defer_event *e) { } } -void pa_glib_mainloop_free(struct pa_glib_mainloop* g) { +void pa_glib_mainloop_free(pa_glib_mainloop* g) { assert(g); free_io_events(g->io_events); @@ -466,13 +467,13 @@ void pa_glib_mainloop_free(struct pa_glib_mainloop* g) { pa_xfree(g); } -struct pa_mainloop_api* pa_glib_mainloop_get_api(struct pa_glib_mainloop *g) { +pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) { assert(g); return &g->api; } static gboolean free_dead_events(gpointer p) { - struct pa_glib_mainloop *g = p; + pa_glib_mainloop *g = p; assert(g); free_io_events(g->dead_io_events); @@ -489,7 +490,7 @@ static gboolean free_dead_events(gpointer p) { return FALSE; } -static void schedule_free_dead_events(struct pa_glib_mainloop *g) { +static void schedule_free_dead_events(pa_glib_mainloop *g) { assert(g); if (g->cleanup_source != (guint) -1) diff --git a/polyp/hashmap.c b/polyp/hashmap.c index 3b1265c9..a37decb8 100644 --- a/polyp/hashmap.c +++ b/polyp/hashmap.c @@ -51,9 +51,9 @@ struct pa_hashmap { int (*compare_func) (const void*a, const void*b); }; -struct pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { - struct pa_hashmap *h; - h = pa_xmalloc(sizeof(struct pa_hashmap)); +pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { + pa_hashmap *h; + h = pa_xmalloc(sizeof(pa_hashmap)); h->data = pa_xmalloc0(sizeof(struct hashmap_entry*)*(h->size = BUCKETS)); h->first_entry = NULL; h->n_entries = 0; @@ -62,7 +62,7 @@ struct pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*c return h; } -static void remove(struct pa_hashmap *h, struct hashmap_entry *e) { +static void remove(pa_hashmap *h, struct hashmap_entry *e) { assert(e); if (e->next) @@ -85,7 +85,7 @@ static void remove(struct pa_hashmap *h, struct hashmap_entry *e) { h->n_entries--; } -void pa_hashmap_free(struct pa_hashmap*h, void (*free_func)(void *p, void *userdata), void *userdata) { +void pa_hashmap_free(pa_hashmap*h, void (*free_func)(void *p, void *userdata), void *userdata) { assert(h); while (h->first_entry) { @@ -98,7 +98,7 @@ void pa_hashmap_free(struct pa_hashmap*h, void (*free_func)(void *p, void *userd pa_xfree(h); } -static struct hashmap_entry *get(struct pa_hashmap *h, unsigned hash, const void *key) { +static struct hashmap_entry *get(pa_hashmap *h, unsigned hash, const void *key) { struct hashmap_entry *e; assert(h && hash < h->size); @@ -109,7 +109,7 @@ static struct hashmap_entry *get(struct pa_hashmap *h, unsigned hash, const void return NULL; } -int pa_hashmap_put(struct pa_hashmap *h, const void *key, void *value) { +int pa_hashmap_put(pa_hashmap *h, const void *key, void *value) { struct hashmap_entry *e; unsigned hash; assert(h); @@ -140,7 +140,7 @@ int pa_hashmap_put(struct pa_hashmap *h, const void *key, void *value) { return 0; } -void* pa_hashmap_get(struct pa_hashmap *h, const void *key) { +void* pa_hashmap_get(pa_hashmap *h, const void *key) { unsigned hash; struct hashmap_entry *e; assert(h && key); @@ -153,7 +153,7 @@ void* pa_hashmap_get(struct pa_hashmap *h, const void *key) { return e->value; } -void* pa_hashmap_remove(struct pa_hashmap *h, const void *key) { +void* pa_hashmap_remove(pa_hashmap *h, const void *key) { struct hashmap_entry *e; unsigned hash; void *data; @@ -169,11 +169,11 @@ void* pa_hashmap_remove(struct pa_hashmap *h, const void *key) { return data; } -unsigned pa_hashmap_ncontents(struct pa_hashmap *h) { +unsigned pa_hashmap_size(pa_hashmap *h) { return h->n_entries; } -void *pa_hashmap_iterate(struct pa_hashmap *h, void **state, const void **key) { +void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void **key) { assert(h && state); if (!*state) diff --git a/polyp/hashmap.h b/polyp/hashmap.h index d55834c1..14f82705 100644 --- a/polyp/hashmap.h +++ b/polyp/hashmap.h @@ -26,28 +26,28 @@ * user's job. It's a good idea to have the key pointer point to a * string in the value data. */ -struct pa_hashmap; +typedef struct pa_hashmap pa_hashmap; /* Create a new hashmap. Use the specified functions for hashing and comparing objects in the map */ -struct pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); +pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); /* Free the hash table. Calls the specified function for every value in the table. The function may be NULL */ -void pa_hashmap_free(struct pa_hashmap*, void (*free_func)(void *p, void *userdata), void *userdata); +void pa_hashmap_free(pa_hashmap*, void (*free_func)(void *p, void *userdata), void *userdata); /* Returns non-zero when the entry already exists */ -int pa_hashmap_put(struct pa_hashmap *h, const void *key, void *value); -void* pa_hashmap_get(struct pa_hashmap *h, const void *key); +int pa_hashmap_put(pa_hashmap *h, const void *key, void *value); +void* pa_hashmap_get(pa_hashmap *h, const void *key); /* Returns the data of the entry while removing */ -void* pa_hashmap_remove(struct pa_hashmap *h, const void *key); +void* pa_hashmap_remove(pa_hashmap *h, const void *key); -unsigned pa_hashmap_ncontents(struct pa_hashmap *h); +unsigned pa_hashmap_size(pa_hashmap *h); /* May be used to iterate through the hashmap. Initially the opaque pointer *state has to be set to NULL. The hashmap may not be modified during iteration. The key of the entry is returned in *key, if key is non-NULL. After the last entry in the hashmap NULL is returned. */ -void *pa_hashmap_iterate(struct pa_hashmap *h, void **state, const void**key); +void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void**key); #endif diff --git a/polyp/howl-wrap.c b/polyp/howl-wrap.c index af050930..77d096ac 100644 --- a/polyp/howl-wrap.c +++ b/polyp/howl-wrap.c @@ -28,17 +28,17 @@ #define HOWL_PROPERTY "howl" -struct pa_howl_wrapper { - struct pa_core *core; +pa_howl_wrapper { + pa_core *core; int ref; - struct pa_io_event *io_event; + pa_io_event *io_event; sw_discovery discovery; }; -static void howl_io_event(struct pa_mainloop_api*m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { - struct pa_howl_wrapper *w = userdata; +static void howl_io_event(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata) { + pa_howl_wrapper *w = userdata; assert(m && e && fd >= 0 && w && w->ref >= 1); if (f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) @@ -55,8 +55,8 @@ fail: w->io_event = NULL; } -static struct pa_howl_wrapper* howl_wrapper_new(struct pa_core *c) { - struct pa_howl_wrapper *h; +static pa_howl_wrapper* howl_wrapper_new(pa_core *c) { + pa_howl_wrapper *h; sw_discovery session; assert(c); @@ -65,7 +65,7 @@ static struct pa_howl_wrapper* howl_wrapper_new(struct pa_core *c) { return NULL; } - h = pa_xmalloc(sizeof(struct pa_howl_wrapper)); + h = pa_xmalloc(sizeof(pa_howl_wrapper)); h->core = c; h->ref = 1; h->discovery = session; @@ -75,7 +75,7 @@ static struct pa_howl_wrapper* howl_wrapper_new(struct pa_core *c) { return h; } -static void howl_wrapper_free(struct pa_howl_wrapper *h) { +static void howl_wrapper_free(pa_howl_wrapper *h) { assert(h); sw_discovery_fina(h->discovery); @@ -86,8 +86,8 @@ static void howl_wrapper_free(struct pa_howl_wrapper *h) { pa_xfree(h); } -struct pa_howl_wrapper* pa_howl_wrapper_get(struct pa_core *c) { - struct pa_howl_wrapper *h; +pa_howl_wrapper* pa_howl_wrapper_get(pa_core *c) { + pa_howl_wrapper *h; assert(c); if ((h = pa_property_get(c, HOWL_PROPERTY))) @@ -96,19 +96,19 @@ struct pa_howl_wrapper* pa_howl_wrapper_get(struct pa_core *c) { return howl_wrapper_new(c); } -struct pa_howl_wrapper* pa_howl_wrapper_ref(struct pa_howl_wrapper *h) { +pa_howl_wrapper* pa_howl_wrapper_ref(pa_howl_wrapper *h) { assert(h && h->ref >= 1); h->ref++; return h; } -void pa_howl_wrapper_unref(struct pa_howl_wrapper *h) { +void pa_howl_wrapper_unref(pa_howl_wrapper *h) { assert(h && h->ref >= 1); if (!(--h->ref)) howl_wrapper_free(h); } -sw_discovery pa_howl_wrapper_get_discovery(struct pa_howl_wrapper *h) { +sw_discovery pa_howl_wrapper_get_discovery(pa_howl_wrapper *h) { assert(h && h->ref >= 1); return h->discovery; diff --git a/polyp/howl-wrap.h b/polyp/howl-wrap.h index feb54556..a670b082 100644 --- a/polyp/howl-wrap.h +++ b/polyp/howl-wrap.h @@ -26,12 +26,12 @@ #include "core.h" -struct pa_howl_wrapper; +pa_howl_wrapper; -struct pa_howl_wrapper* pa_howl_wrapper_get(struct pa_core *c); -struct pa_howl_wrapper* pa_howl_wrapper_ref(struct pa_howl_wrapper *h); -void pa_howl_wrapper_unref(struct pa_howl_wrapper *h); +pa_howl_wrapper* pa_howl_wrapper_get(pa_core *c); +pa_howl_wrapper* pa_howl_wrapper_ref(pa_howl_wrapper *h); +void pa_howl_wrapper_unref(pa_howl_wrapper *h); -sw_discovery pa_howl_wrapper_get_discovery(struct pa_howl_wrapper *h); +sw_discovery pa_howl_wrapper_get_discovery(pa_howl_wrapper *h); #endif diff --git a/polyp/idxset.c b/polyp/idxset.c index dcc38423..409d1fab 100644 --- a/polyp/idxset.c +++ b/polyp/idxset.c @@ -31,21 +31,21 @@ #include "idxset.h" #include "xmalloc.h" -struct idxset_entry { +typedef struct idxset_entry { void *data; uint32_t index; unsigned hash_value; struct idxset_entry *hash_prev, *hash_next; struct idxset_entry* iterate_prev, *iterate_next; -}; +} idxset_entry; struct pa_idxset { unsigned (*hash_func) (const void *p); int (*compare_func)(const void *a, const void *b); unsigned hash_table_size, n_entries; - struct idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail; + idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail; uint32_t index, start_index, array_size; }; @@ -71,14 +71,14 @@ int pa_idxset_trivial_compare_func(const void *a, const void *b) { return a != b; } -struct pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { - struct pa_idxset *s; +pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { + pa_idxset *s; - s = pa_xmalloc(sizeof(struct pa_idxset)); + s = pa_xnew(pa_idxset, 1); s->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; s->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; s->hash_table_size = 1023; - s->hash_table = pa_xmalloc0(sizeof(struct idxset_entry*)*s->hash_table_size); + s->hash_table = pa_xmalloc0(sizeof(idxset_entry*)*s->hash_table_size); s->array = NULL; s->array_size = 0; s->index = 0; @@ -90,11 +90,11 @@ struct pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*com return s; } -void pa_idxset_free(struct pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata) { +void pa_idxset_free(pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata) { assert(s); while (s->iterate_list_head) { - struct idxset_entry *e = s->iterate_list_head; + idxset_entry *e = s->iterate_list_head; s->iterate_list_head = s->iterate_list_head->iterate_next; if (free_func) @@ -107,7 +107,7 @@ void pa_idxset_free(struct pa_idxset *s, void (*free_func) (void *p, void *userd pa_xfree(s); } -static struct idxset_entry* hash_scan(struct pa_idxset *s, struct idxset_entry* e, const void *p) { +static idxset_entry* hash_scan(pa_idxset *s, idxset_entry* e, const void *p) { assert(p); assert(s->compare_func); @@ -118,20 +118,20 @@ static struct idxset_entry* hash_scan(struct pa_idxset *s, struct idxset_entry* return NULL; } -static void extend_array(struct pa_idxset *s, uint32_t index) { +static void extend_array(pa_idxset *s, uint32_t idx) { uint32_t i, j, l; - struct idxset_entry** n; - assert(index >= s->start_index); + idxset_entry** n; + assert(idx >= s->start_index); - if (index < s->start_index + s->array_size) + if (idx < s->start_index + s->array_size) return; for (i = 0; i < s->array_size; i++) if (s->array[i]) break; - l = index - s->start_index - i + 100; - n = pa_xmalloc0(sizeof(struct hash_table_entry*)*l); + l = idx - s->start_index - i + 100; + n = pa_xnew0(idxset_entry*, l); for (j = 0; j < s->array_size-i; j++) n[j] = s->array[i+j]; @@ -143,19 +143,19 @@ static void extend_array(struct pa_idxset *s, uint32_t index) { s->start_index += i; } -static struct idxset_entry** array_index(struct pa_idxset*s, uint32_t index) { - if (index >= s->start_index + s->array_size) +static idxset_entry** array_index(pa_idxset*s, uint32_t idx) { + if (idx >= s->start_index + s->array_size) return NULL; - if (index < s->start_index) + if (idx < s->start_index) return NULL; - return s->array + (index - s->start_index); + return s->array + (idx - s->start_index); } -int pa_idxset_put(struct pa_idxset*s, void *p, uint32_t *index) { +int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) { unsigned h; - struct idxset_entry *e, **a; + idxset_entry *e, **a; assert(s && p); assert(s->hash_func); @@ -163,13 +163,13 @@ int pa_idxset_put(struct pa_idxset*s, void *p, uint32_t *index) { assert(s->hash_table); if ((e = hash_scan(s, s->hash_table[h], p))) { - if (index) - *index = e->index; + if (idx) + *idx = e->index; return -1; } - e = pa_xmalloc(sizeof(struct idxset_entry)); + e = pa_xmalloc(sizeof(idxset_entry)); e->data = p; e->index = s->index++; e->hash_value = h; @@ -202,17 +202,17 @@ int pa_idxset_put(struct pa_idxset*s, void *p, uint32_t *index) { s->n_entries++; assert(s->n_entries >= 1); - if (index) - *index = e->index; + if (idx) + *idx = e->index; return 0; } -void* pa_idxset_get_by_index(struct pa_idxset*s, uint32_t index) { - struct idxset_entry **a; +void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx) { + idxset_entry **a; assert(s); - if (!(a = array_index(s, index))) + if (!(a = array_index(s, idx))) return NULL; if (!*a) @@ -221,9 +221,9 @@ void* pa_idxset_get_by_index(struct pa_idxset*s, uint32_t index) { return (*a)->data; } -void* pa_idxset_get_by_data(struct pa_idxset*s, const void *p, uint32_t *index) { +void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx) { unsigned h; - struct idxset_entry *e; + idxset_entry *e; assert(s && p); assert(s->hash_func); @@ -233,14 +233,14 @@ void* pa_idxset_get_by_data(struct pa_idxset*s, const void *p, uint32_t *index) if (!(e = hash_scan(s, s->hash_table[h], p))) return NULL; - if (index) - *index = e->index; + if (idx) + *idx = e->index; return e->data; } -static void remove_entry(struct pa_idxset *s, struct idxset_entry *e) { - struct idxset_entry **a; +static void remove_entry(pa_idxset *s, idxset_entry *e) { + idxset_entry **a; assert(s && e); /* Remove from array */ @@ -274,13 +274,13 @@ static void remove_entry(struct pa_idxset *s, struct idxset_entry *e) { s->n_entries--; } -void* pa_idxset_remove_by_index(struct pa_idxset*s, uint32_t index) { - struct idxset_entry **a; +void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx) { + idxset_entry **a; void *data; assert(s); - if (!(a = array_index(s, index))) + if (!(a = array_index(s, idx))) return NULL; data = (*a)->data; @@ -289,8 +289,8 @@ void* pa_idxset_remove_by_index(struct pa_idxset*s, uint32_t index) { return data; } -void* pa_idxset_remove_by_data(struct pa_idxset*s, const void *data, uint32_t *index) { - struct idxset_entry *e; +void* pa_idxset_remove_by_data(pa_idxset*s, const void *data, uint32_t *idx) { + idxset_entry *e; unsigned h; void *r; @@ -302,19 +302,19 @@ void* pa_idxset_remove_by_data(struct pa_idxset*s, const void *data, uint32_t *i return NULL; r = e->data; - if (index) - *index = e->index; + if (idx) + *idx = e->index; remove_entry(s, e); return r; } -void* pa_idxset_rrobin(struct pa_idxset *s, uint32_t *index) { - struct idxset_entry **a, *e = NULL; - assert(s && index); +void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx) { + idxset_entry **a, *e = NULL; + assert(s && idx); - if ((a = array_index(s, *index)) && *a) + if ((a = array_index(s, *idx)) && *a) e = (*a)->iterate_next; if (!e) @@ -323,46 +323,46 @@ void* pa_idxset_rrobin(struct pa_idxset *s, uint32_t *index) { if (!e) return NULL; - *index = e->index; + *idx = e->index; return e->data; } -void* pa_idxset_first(struct pa_idxset *s, uint32_t *index) { +void* pa_idxset_first(pa_idxset *s, uint32_t *idx) { assert(s); if (!s->iterate_list_head) return NULL; - if (index) - *index = s->iterate_list_head->index; + if (idx) + *idx = s->iterate_list_head->index; return s->iterate_list_head->data; } -void *pa_idxset_next(struct pa_idxset *s, uint32_t *index) { - struct idxset_entry **a, *e = NULL; - assert(s && index); +void *pa_idxset_next(pa_idxset *s, uint32_t *idx) { + idxset_entry **a, *e = NULL; + assert(s && idx); - if ((a = array_index(s, *index)) && *a) + if ((a = array_index(s, *idx)) && *a) e = (*a)->iterate_next; if (e) { - *index = e->index; + *idx = e->index; return e->data; } else { - *index = PA_IDXSET_INVALID; + *idx = PA_IDXSET_INVALID; return NULL; } } -int pa_idxset_foreach(struct pa_idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata) { - struct idxset_entry *e; +int pa_idxset_foreach(pa_idxset*s, int (*func)(void *p, uint32_t idx, int *del, void*userdata), void *userdata) { + idxset_entry *e; assert(s && func); e = s->iterate_list_head; while (e) { int del = 0, r; - struct idxset_entry *n = e->iterate_next; + idxset_entry *n = e->iterate_next; r = func(e->data, e->index, &del, userdata); @@ -378,12 +378,12 @@ int pa_idxset_foreach(struct pa_idxset*s, int (*func)(void *p, uint32_t index, i return 0; } -unsigned pa_idxset_ncontents(struct pa_idxset*s) { +unsigned pa_idxset_size(pa_idxset*s) { assert(s); return s->n_entries; } -int pa_idxset_isempty(struct pa_idxset *s) { +int pa_idxset_isempty(pa_idxset *s) { assert(s); return s->n_entries == 0; } diff --git a/polyp/idxset.h b/polyp/idxset.h index 4c89eea1..17ae16cb 100644 --- a/polyp/idxset.h +++ b/polyp/idxset.h @@ -41,53 +41,54 @@ int pa_idxset_trivial_compare_func(const void *a, const void *b); unsigned pa_idxset_string_hash_func(const void *p); int pa_idxset_string_compare_func(const void *a, const void *b); -struct pa_idxset; +typedef struct pa_idxset pa_idxset; /* Instantiate a new idxset with the specified hash and comparison functions */ -struct pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); +pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); /* Free the idxset. When the idxset is not empty the specified function is called for every entry contained */ -void pa_idxset_free(struct pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata); +void pa_idxset_free(pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata); -/* Store a new item in the idxset. The index of the item is returned in *index */ -int pa_idxset_put(struct pa_idxset*s, void *p, uint32_t *index); +/* Store a new item in the idxset. The index of the item is returned in *idx */ +int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx); -/* Get the entry by its index */ -void* pa_idxset_get_by_index(struct pa_idxset*s, uint32_t index); +/* Get the entry by its idx */ +void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx); -/* Get the entry by its data. The index is returned in *index */ -void* pa_idxset_get_by_data(struct pa_idxset*s, const void *p, uint32_t *index); +/* Get the entry by its data. The idx is returned in *index */ +void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx); /* Similar to pa_idxset_get_by_index(), but removes the entry from the idxset. */ -void* pa_idxset_remove_by_index(struct pa_idxset*s, uint32_t index); +void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx); /* Similar to pa_idxset_get_by_data(), but removes the entry from the idxset */ -void* pa_idxset_remove_by_data(struct pa_idxset*s, const void *p, uint32_t *index); +void* pa_idxset_remove_by_data(pa_idxset*s, const void *p, uint32_t *idx); /* This may be used to iterate through all entries. When called with an invalid index value it returns the first entry, otherwise the - next following. The function is best called with *index = + next following. The function is best called with *idx = PA_IDXSET_VALID first. It is safe to manipulate the idxset between the calls. It is not guaranteed that all entries have already been returned before the an entry is returned the second time.*/ -void* pa_idxset_rrobin(struct pa_idxset *s, uint32_t *index); +void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx); -/* Return the oldest entry in the idxset. Fill in its index in *index. */ -void* pa_idxset_first(struct pa_idxset *s, uint32_t *index); +/* Return the oldest entry in the idxset. Fill in its index in *idx. */ +void* pa_idxset_first(pa_idxset *s, uint32_t *idx); -/* Return the entry following the entry indexed by *index. After the +/* Return the entry following the entry indexed by *idx. After the * call *index contains the index of the returned * object. pa_idxset_first() and pa_idxset_next() may be used to * iterate through the set.*/ -void *pa_idxset_next(struct pa_idxset *s, uint32_t *index); +void *pa_idxset_next(pa_idxset *s, uint32_t *idx); /* Call a function for every item in the set. If the callback function returns -1, the loop is terminated. If *del is set to non-zero that specific item is removed. It is not safe to call any other functions on the idxset while pa_idxset_foreach is executed. */ -int pa_idxset_foreach(struct pa_idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata); +int pa_idxset_foreach(pa_idxset*s, int (*func)(void *p, uint32_t idx, int *del, void*userdata), void *userdata); -unsigned pa_idxset_ncontents(struct pa_idxset*s); -int pa_idxset_isempty(struct pa_idxset *s); +unsigned pa_idxset_size(pa_idxset*s); + +int pa_idxset_isempty(pa_idxset *s); #endif diff --git a/polyp/iochannel.c b/polyp/iochannel.c index 1a0dbf91..e6271319 100644 --- a/polyp/iochannel.c +++ b/polyp/iochannel.c @@ -37,9 +37,9 @@ struct pa_iochannel { int ifd, ofd; - struct pa_mainloop_api* mainloop; + pa_mainloop_api* mainloop; - void (*callback)(struct pa_iochannel*io, void *userdata); + pa_iochannel_callback_t callback; void*userdata; int readable; @@ -48,14 +48,14 @@ struct pa_iochannel { int no_close; - struct pa_io_event* input_event, *output_event; + pa_io_event* input_event, *output_event; }; -static void enable_mainloop_sources(struct pa_iochannel *io) { +static void enable_mainloop_sources(pa_iochannel *io) { assert(io); if (io->input_event == io->output_event && io->input_event) { - enum pa_io_event_flags f = PA_IO_EVENT_NULL; + pa_io_event_flags f = PA_IO_EVENT_NULL; assert(io->input_event); if (!io->readable) @@ -72,10 +72,14 @@ static void enable_mainloop_sources(struct pa_iochannel *io) { } } -static void callback(struct pa_mainloop_api* m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { - struct pa_iochannel *io = userdata; +static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata) { + pa_iochannel *io = userdata; int changed = 0; - assert(m && e && fd >= 0 && userdata); + + assert(m); + assert(e); + assert(fd >= 0); + assert(userdata); if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) { io->hungup = 1; @@ -87,9 +91,7 @@ static void callback(struct pa_mainloop_api* m, struct pa_io_event *e, int fd, e if (io->output_event == e) io->output_event = NULL; - } - - if (e == io->output_event) { + } else if (e == io->output_event) { io->mainloop->io_free(io->output_event); io->output_event = NULL; } @@ -116,11 +118,13 @@ static void callback(struct pa_mainloop_api* m, struct pa_io_event *e, int fd, e } } -struct pa_iochannel* pa_iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd) { - struct pa_iochannel *io; - assert(m && (ifd >= 0 || ofd >= 0)); +pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) { + pa_iochannel *io; + + assert(m); + assert(ifd >= 0 || ofd >= 0); - io = pa_xmalloc(sizeof(struct pa_iochannel)); + io = pa_xnew(pa_iochannel, 1); io->ifd = ifd; io->ofd = ofd; io->mainloop = m; @@ -154,16 +158,18 @@ struct pa_iochannel* pa_iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd return io; } -void pa_iochannel_free(struct pa_iochannel*io) { +void pa_iochannel_free(pa_iochannel*io) { assert(io); if (io->input_event) io->mainloop->io_free(io->input_event); + if (io->output_event && (io->output_event != io->input_event)) io->mainloop->io_free(io->output_event); if (!io->no_close) { if (io->ifd >= 0) + close(io->ifd); if (io->ofd >= 0 && io->ofd != io->ifd) close(io->ofd); @@ -172,24 +178,31 @@ void pa_iochannel_free(struct pa_iochannel*io) { pa_xfree(io); } -int pa_iochannel_is_readable(struct pa_iochannel*io) { +int pa_iochannel_is_readable(pa_iochannel*io) { assert(io); + return io->readable || io->hungup; } -int pa_iochannel_is_writable(struct pa_iochannel*io) { +int pa_iochannel_is_writable(pa_iochannel*io) { assert(io); + return io->writable && !io->hungup; } -int pa_iochannel_is_hungup(struct pa_iochannel*io) { +int pa_iochannel_is_hungup(pa_iochannel*io) { assert(io); + return io->hungup; } -ssize_t pa_iochannel_write(struct pa_iochannel*io, const void*data, size_t l) { +ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) { ssize_t r; - assert(io && data && l && io->ofd >= 0); + + assert(io); + assert(data); + assert(l); + assert(io->ofd >= 0); #ifdef OS_IS_WIN32 r = send(io->ofd, data, l, 0); @@ -211,9 +224,12 @@ ssize_t pa_iochannel_write(struct pa_iochannel*io, const void*data, size_t l) { return r; } -ssize_t pa_iochannel_read(struct pa_iochannel*io, void*data, size_t l) { +ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) { ssize_t r; - assert(io && data && io->ifd >= 0); + + assert(io); + assert(data); + assert(io->ifd >= 0); #ifdef OS_IS_WIN32 r = recv(io->ifd, data, l, 0); @@ -227,6 +243,7 @@ ssize_t pa_iochannel_read(struct pa_iochannel*io, void*data, size_t l) { if (r < 0) #endif r = read(io->ifd, data, l); + if (r >= 0) { io->readable = 0; enable_mainloop_sources(io); @@ -235,34 +252,41 @@ ssize_t pa_iochannel_read(struct pa_iochannel*io, void*data, size_t l) { return r; } -void pa_iochannel_set_callback(struct pa_iochannel*io, void (*callback)(struct pa_iochannel*io, void *userdata), void *userdata) { +void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_callback_t _callback, void *userdata) { assert(io); - io->callback = callback; + + io->callback = _callback; io->userdata = userdata; } -void pa_iochannel_set_noclose(struct pa_iochannel*io, int b) { +void pa_iochannel_set_noclose(pa_iochannel*io, int b) { assert(io); + io->no_close = b; } -void pa_iochannel_socket_peer_to_string(struct pa_iochannel*io, char*s, size_t l) { - assert(io && s && l); +void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) { + assert(io); + assert(s); + assert(l); + pa_socket_peer_to_string(io->ifd, s, l); } -int pa_iochannel_socket_set_rcvbuf(struct pa_iochannel *io, size_t l) { +int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) { assert(io); + return pa_socket_set_rcvbuf(io->ifd, l); } -int pa_iochannel_socket_set_sndbuf(struct pa_iochannel *io, size_t l) { +int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) { assert(io); + return pa_socket_set_sndbuf(io->ofd, l); } - -struct pa_mainloop_api* pa_iochannel_get_mainloop_api(struct pa_iochannel *io) { +pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) { assert(io); + return io->mainloop; } diff --git a/polyp/iochannel.h b/polyp/iochannel.h index 2a1ba370..e2b8bccf 100644 --- a/polyp/iochannel.h +++ b/polyp/iochannel.h @@ -35,37 +35,38 @@ * reached. Otherwise strange things may happen when an EOF is * reached. */ -struct pa_iochannel; +typedef struct pa_iochannel pa_iochannel; /* Create a new IO channel for the specified file descriptors for input resp. output. It is safe to pass the same file descriptor for both parameters (in case of full-duplex channels). For a simplex channel specify -1 for the other direction. */ -struct pa_iochannel* pa_iochannel_new(struct pa_mainloop_api*m, int ifd, int ofd); -void pa_iochannel_free(struct pa_iochannel*io); +pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd); +void pa_iochannel_free(pa_iochannel*io); -ssize_t pa_iochannel_write(struct pa_iochannel*io, const void*data, size_t l); -ssize_t pa_iochannel_read(struct pa_iochannel*io, void*data, size_t l); +ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l); +ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l); -int pa_iochannel_is_readable(struct pa_iochannel*io); -int pa_iochannel_is_writable(struct pa_iochannel*io); -int pa_iochannel_is_hungup(struct pa_iochannel*io); +int pa_iochannel_is_readable(pa_iochannel*io); +int pa_iochannel_is_writable(pa_iochannel*io); +int pa_iochannel_is_hungup(pa_iochannel*io); /* Don't close the file descirptors when the io channel is freed. By * default the file descriptors are closed. */ -void pa_iochannel_set_noclose(struct pa_iochannel*io, int b); +void pa_iochannel_set_noclose(pa_iochannel*io, int b); /* Set the callback function that is called whenever data becomes available for read or write */ -void pa_iochannel_set_callback(struct pa_iochannel*io, void (*callback)(struct pa_iochannel*io, void *userdata), void *userdata); +typedef void (*pa_iochannel_callback_t)(pa_iochannel*io, void *userdata); +void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_callback_t callback, void *userdata); /* In case the file descriptor is a socket, return a pretty-printed string in *s which describes the peer connected */ -void pa_iochannel_socket_peer_to_string(struct pa_iochannel*io, char*s, size_t l); +void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l); /* Use setsockopt() to tune the recieve and send buffers of TCP sockets */ -int pa_iochannel_socket_set_rcvbuf(struct pa_iochannel*io, size_t l); -int pa_iochannel_socket_set_sndbuf(struct pa_iochannel*io, size_t l); +int pa_iochannel_socket_set_rcvbuf(pa_iochannel*io, size_t l); +int pa_iochannel_socket_set_sndbuf(pa_iochannel*io, size_t l); -struct pa_mainloop_api* pa_iochannel_get_mainloop_api(struct pa_iochannel *io); +pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io); #endif diff --git a/polyp/ioline.c b/polyp/ioline.c index 72df6b87..5b669f5c 100644 --- a/polyp/ioline.c +++ b/polyp/ioline.c @@ -37,9 +37,9 @@ #define READ_SIZE (1024) struct pa_ioline { - struct pa_iochannel *io; - struct pa_defer_event *defer_event; - struct pa_mainloop_api *mainloop; + pa_iochannel *io; + pa_defer_event *defer_event; + pa_mainloop_api *mainloop; int ref; int dead; @@ -49,20 +49,20 @@ struct pa_ioline { char *rbuf; size_t rbuf_length, rbuf_index, rbuf_valid_length; - void (*callback)(struct pa_ioline*io, const char *s, void *userdata); + void (*callback)(pa_ioline*io, const char *s, void *userdata); void *userdata; int defer_close; }; -static void io_callback(struct pa_iochannel*io, void *userdata); -static void defer_callback(struct pa_mainloop_api*m, struct pa_defer_event*e, void *userdata); +static void io_callback(pa_iochannel*io, void *userdata); +static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata); -struct pa_ioline* pa_ioline_new(struct pa_iochannel *io) { - struct pa_ioline *l; +pa_ioline* pa_ioline_new(pa_iochannel *io) { + pa_ioline *l; assert(io); - l = pa_xmalloc(sizeof(struct pa_ioline)); + l = pa_xmalloc(sizeof(pa_ioline)); l->io = io; l->dead = 0; @@ -88,7 +88,7 @@ struct pa_ioline* pa_ioline_new(struct pa_iochannel *io) { return l; } -static void ioline_free(struct pa_ioline *l) { +static void ioline_free(pa_ioline *l) { assert(l); if (l->io) @@ -102,21 +102,21 @@ static void ioline_free(struct pa_ioline *l) { pa_xfree(l); } -void pa_ioline_unref(struct pa_ioline *l) { +void pa_ioline_unref(pa_ioline *l) { assert(l && l->ref >= 1); if ((--l->ref) <= 0) ioline_free(l); } -struct pa_ioline* pa_ioline_ref(struct pa_ioline *l) { +pa_ioline* pa_ioline_ref(pa_ioline *l) { assert(l && l->ref >= 1); l->ref++; return l; } -void pa_ioline_close(struct pa_ioline *l) { +void pa_ioline_close(pa_ioline *l) { assert(l && l->ref >= 1); l->dead = 1; @@ -131,7 +131,7 @@ void pa_ioline_close(struct pa_ioline *l) { } } -void pa_ioline_puts(struct pa_ioline *l, const char *c) { +void pa_ioline_puts(pa_ioline *l, const char *c) { size_t len; assert(l && c && l->ref >= 1 && !l->dead); @@ -174,13 +174,13 @@ void pa_ioline_puts(struct pa_ioline *l, const char *c) { pa_ioline_unref(l); } -void pa_ioline_set_callback(struct pa_ioline*l, void (*callback)(struct pa_ioline*io, const char *s, void *userdata), void *userdata) { +void pa_ioline_set_callback(pa_ioline*l, void (*callback)(pa_ioline*io, const char *s, void *userdata), void *userdata) { assert(l && l->ref >= 1); l->callback = callback; l->userdata = userdata; } -static void failure(struct pa_ioline *l) { +static void failure(pa_ioline *l) { assert(l && l->ref >= 1 && !l->dead); pa_ioline_close(l); @@ -191,7 +191,7 @@ static void failure(struct pa_ioline *l) { } } -static void scan_for_lines(struct pa_ioline *l, size_t skip) { +static void scan_for_lines(pa_ioline *l, size_t skip) { assert(l && l->ref >= 1 && skip < l->rbuf_valid_length); while (!l->dead && l->rbuf_valid_length > skip) { @@ -224,9 +224,9 @@ static void scan_for_lines(struct pa_ioline *l, size_t skip) { l->rbuf_index = l->rbuf_valid_length = 0; } -static int do_write(struct pa_ioline *l); +static int do_write(pa_ioline *l); -static int do_read(struct pa_ioline *l) { +static int do_read(pa_ioline *l) { assert(l && l->ref >= 1); while (!l->dead && pa_iochannel_is_readable(l->io)) { @@ -288,7 +288,7 @@ static int do_read(struct pa_ioline *l) { } /* Try to flush the buffer */ -static int do_write(struct pa_ioline *l) { +static int do_write(pa_ioline *l) { ssize_t r; assert(l && l->ref >= 1); @@ -312,7 +312,7 @@ static int do_write(struct pa_ioline *l) { } /* Try to flush read/write data */ -static void do_work(struct pa_ioline *l) { +static void do_work(pa_ioline *l) { assert(l && l->ref >= 1); pa_ioline_ref(l); @@ -331,21 +331,21 @@ static void do_work(struct pa_ioline *l) { pa_ioline_unref(l); } -static void io_callback(struct pa_iochannel*io, void *userdata) { - struct pa_ioline *l = userdata; +static void io_callback(pa_iochannel*io, void *userdata) { + pa_ioline *l = userdata; assert(io && l && l->ref >= 1); do_work(l); } -static void defer_callback(struct pa_mainloop_api*m, struct pa_defer_event*e, void *userdata) { - struct pa_ioline *l = userdata; +static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata) { + pa_ioline *l = userdata; assert(l && l->ref >= 1 && l->mainloop == m && l->defer_event == e); do_work(l); } -void pa_ioline_defer_close(struct pa_ioline *l) { +void pa_ioline_defer_close(pa_ioline *l) { assert(l); l->defer_close = 1; @@ -354,7 +354,7 @@ void pa_ioline_defer_close(struct pa_ioline *l) { l->mainloop->defer_enable(l->defer_event, 1); } -void pa_ioline_printf(struct pa_ioline *s, const char *format, ...) { +void pa_ioline_printf(pa_ioline *s, const char *format, ...) { char *t; va_list ap; diff --git a/polyp/ioline.h b/polyp/ioline.h index 6e9c76d0..84ccb47a 100644 --- a/polyp/ioline.h +++ b/polyp/ioline.h @@ -29,23 +29,23 @@ * callback function is called whenever a new line has been recieved * from the client */ -struct pa_ioline; +typedef struct pa_ioline pa_ioline; -struct pa_ioline* pa_ioline_new(struct pa_iochannel *io); -void pa_ioline_unref(struct pa_ioline *l); -struct pa_ioline* pa_ioline_ref(struct pa_ioline *l); -void pa_ioline_close(struct pa_ioline *l); +pa_ioline* pa_ioline_new(pa_iochannel *io); +void pa_ioline_unref(pa_ioline *l); +pa_ioline* pa_ioline_ref(pa_ioline *l); +void pa_ioline_close(pa_ioline *l); /* Write a string to the channel */ -void pa_ioline_puts(struct pa_ioline *s, const char *c); +void pa_ioline_puts(pa_ioline *s, const char *c); /* Write a string to the channel */ -void pa_ioline_printf(struct pa_ioline *s, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); +void pa_ioline_printf(pa_ioline *s, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); /* Set the callback function that is called for every recieved line */ -void pa_ioline_set_callback(struct pa_ioline*io, void (*callback)(struct pa_ioline*io, const char *s, void *userdata), void *userdata); +void pa_ioline_set_callback(pa_ioline*io, void (*callback)(pa_ioline*io, const char *s, void *userdata), void *userdata); /* Make sure to close the ioline object as soon as the send buffer is emptied */ -void pa_ioline_defer_close(struct pa_ioline *io); +void pa_ioline_defer_close(pa_ioline *io); #endif diff --git a/polyp/log.c b/polyp/log.c index 2bbf2e86..c41fbbae 100644 --- a/polyp/log.c +++ b/polyp/log.c @@ -38,9 +38,9 @@ #define ENV_LOGLEVEL "POLYP_LOG" static char *log_ident = NULL; -static enum pa_log_target log_target = PA_LOG_STDERR; -static void (*user_log_func)(enum pa_log_level l, const char *s) = NULL; -static enum pa_log_level maximal_level = PA_LOG_NOTICE; +static pa_log_target log_target = PA_LOG_STDERR; +static void (*user_log_func)(pa_log_level l, const char *s) = NULL; +static pa_log_level maximal_level = PA_LOG_NOTICE; #ifdef HAVE_SYSLOG_H static const int level_to_syslog[] = { @@ -59,18 +59,18 @@ void pa_log_set_ident(const char *p) { log_ident = pa_xstrdup(p); } -void pa_log_set_maximal_level(enum pa_log_level l) { +void pa_log_set_maximal_level(pa_log_level l) { assert(l < PA_LOG_LEVEL_MAX); maximal_level = l; } -void pa_log_set_target(enum pa_log_target t, void (*func)(enum pa_log_level l, const char*s)) { +void pa_log_set_target(pa_log_target t, void (*func)(pa_log_level l, const char*s)) { assert(t == PA_LOG_USER || !func); log_target = t; user_log_func = func; } -void pa_log_levelv(enum pa_log_level level, const char *format, va_list ap) { +void pa_log_with_levelv(pa_log_level level, const char *format, va_list ap) { const char *e; assert(level < PA_LOG_LEVEL_MAX); @@ -107,44 +107,44 @@ void pa_log_levelv(enum pa_log_level level, const char *format, va_list ap) { } -void pa_log_level(enum pa_log_level level, const char *format, ...) { +void pa_log_with_level(pa_log_level level, const char *format, ...) { va_list ap; va_start(ap, format); - pa_log_levelv(level, format, ap); + pa_log_with_levelv(level, format, ap); va_end(ap); } void pa_log_debug(const char *format, ...) { va_list ap; va_start(ap, format); - pa_log_levelv(PA_LOG_DEBUG, format, ap); + pa_log_with_levelv(PA_LOG_DEBUG, format, ap); va_end(ap); } void pa_log_info(const char *format, ...) { va_list ap; va_start(ap, format); - pa_log_levelv(PA_LOG_INFO, format, ap); + pa_log_with_levelv(PA_LOG_INFO, format, ap); va_end(ap); } void pa_log_notice(const char *format, ...) { va_list ap; va_start(ap, format); - pa_log_levelv(PA_LOG_INFO, format, ap); + pa_log_with_levelv(PA_LOG_INFO, format, ap); va_end(ap); } void pa_log_warn(const char *format, ...) { va_list ap; va_start(ap, format); - pa_log_levelv(PA_LOG_WARN, format, ap); + pa_log_with_levelv(PA_LOG_WARN, format, ap); va_end(ap); } void pa_log_error(const char *format, ...) { va_list ap; va_start(ap, format); - pa_log_levelv(PA_LOG_ERROR, format, ap); + pa_log_with_levelv(PA_LOG_ERROR, format, ap); va_end(ap); } diff --git a/polyp/log.h b/polyp/log.h index fe2dad59..7c6a8e61 100644 --- a/polyp/log.h +++ b/polyp/log.h @@ -23,35 +23,35 @@ ***/ #include -#include "gcc-printf.h" +#include "gccmacro.h" /* A simple logging subsystem */ /* Where to log to */ -enum pa_log_target { +typedef enum pa_log_target { PA_LOG_STDERR, /* default */ PA_LOG_SYSLOG, PA_LOG_USER, /* to user specified function */ PA_LOG_NULL /* to /dev/null */ -}; +} pa_log_target; -enum pa_log_level { +typedef enum pa_log_level { PA_LOG_ERROR = 0, /* Error messages */ PA_LOG_WARN = 1, /* Warning messages */ PA_LOG_NOTICE = 2, /* Notice messages */ PA_LOG_INFO = 3, /* Info messages */ PA_LOG_DEBUG = 4, /* debug message */ PA_LOG_LEVEL_MAX -}; +} pa_log_level; -/* Set an identifcation for the current daemon. Used when logging to syslog. */ +/* Set an identification for the current daemon. Used when logging to syslog. */ void pa_log_set_ident(const char *p); /* Set another log target. If t is PA_LOG_USER you may specify a function that is called every log string */ -void pa_log_set_target(enum pa_log_target t, void (*func)(enum pa_log_level, const char*s)); +void pa_log_set_target(pa_log_target t, void (*func)(pa_log_level, const char*s)); /* Minimal log level */ -void pa_log_set_maximal_level(enum pa_log_level l); +void pa_log_set_maximal_level(pa_log_level l); /* Do a log line */ void pa_log_debug(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); @@ -60,9 +60,9 @@ void pa_log_notice(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); void pa_log_warn(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); void pa_log_error(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); -void pa_log_level(enum pa_log_level level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); +void pa_log_with_level(pa_log_level level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); -void pa_log_levelv(enum pa_log_level level, const char *format, va_list ap); +void pa_log_with_levelv(pa_log_level level, const char *format, va_list ap); #define pa_log pa_log_error diff --git a/polyp/main.c b/polyp/main.c index e481fce1..1c3b566d 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -75,7 +75,7 @@ int deny_severity = LOG_WARNING; #ifdef OS_IS_WIN32 -static void message_cb(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata) { +static void message_cb(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { MSG msg; while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { @@ -90,7 +90,7 @@ static void message_cb(struct pa_mainloop_api*a, struct pa_defer_event *e, void #endif -static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { +static void signal_callback(pa_mainloop_api*m, PA_GCC_UNUSED pa_signal_event *e, int sig, void *userdata) { pa_log_info(__FILE__": Got signal %s.\n", pa_strsignal(sig)); switch (sig) { @@ -133,12 +133,12 @@ static void close_pipe(int p[2]) { } int main(int argc, char *argv[]) { - struct pa_core *c; - struct pa_strbuf *buf = NULL; - struct pa_daemon_conf *conf; - struct pa_mainloop *mainloop; + pa_core *c; + pa_strbuf *buf = NULL; + pa_daemon_conf *conf; + pa_mainloop *mainloop; - char *s; + char *s; int r, retval = 1, d = 0; int daemon_pipe[2] = { -1, -1 }; int suid_root; @@ -149,7 +149,7 @@ int main(int argc, char *argv[]) { #endif #ifdef OS_IS_WIN32 - struct pa_defer_event *defer; + pa_defer_event *defer; #endif pa_limit_caps(); @@ -213,7 +213,7 @@ int main(int argc, char *argv[]) { goto finish; case PA_CMD_DUMP_CONF: { - char *s = pa_daemon_conf_dump(conf); + s = pa_daemon_conf_dump(conf); fputs(s, stdout); pa_xfree(s); retval = 0; @@ -405,7 +405,7 @@ int main(int argc, char *argv[]) { if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); #endif - } else if (!c->modules || pa_idxset_ncontents(c->modules) == 0) { + } else if (!c->modules || pa_idxset_size(c->modules) == 0) { pa_log(__FILE__": daemon startup without any loaded modules, refusing to work.\n"); #ifdef HAVE_FORK if (conf->daemonize) diff --git a/polyp/mainloop-api.c b/polyp/mainloop-api.c index 7b80e4fe..3229ec20 100644 --- a/polyp/mainloop-api.c +++ b/polyp/mainloop-api.c @@ -28,13 +28,14 @@ #include "mainloop-api.h" #include "xmalloc.h" +#include "gccmacro.h" struct once_info { - void (*callback)(struct pa_mainloop_api*m, void *userdata); + void (*callback)(pa_mainloop_api*m, void *userdata); void *userdata; }; -static void once_callback(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) { +static void once_callback(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { struct once_info *i = userdata; assert(m && i && i->callback); @@ -44,18 +45,18 @@ static void once_callback(struct pa_mainloop_api *m, struct pa_defer_event *e, v m->defer_free(e); } -static void free_callback(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) { +static void free_callback(pa_mainloop_api *m, PA_GCC_UNUSED pa_defer_event *e, void *userdata) { struct once_info *i = userdata; assert(m && i); pa_xfree(i); } -void pa_mainloop_api_once(struct pa_mainloop_api* m, void (*callback)(struct pa_mainloop_api *m, void *userdata), void *userdata) { +void pa_mainloop_api_once(pa_mainloop_api* m, void (*callback)(pa_mainloop_api *m, void *userdata), void *userdata) { struct once_info *i; - struct pa_defer_event *e; + pa_defer_event *e; assert(m && callback); - i = pa_xmalloc(sizeof(struct once_info)); + i = pa_xnew(struct once_info, 1); i->callback = callback; i->userdata = userdata; diff --git a/polyp/mainloop-api.h b/polyp/mainloop-api.h index 3fb221fa..1604e740 100644 --- a/polyp/mainloop-api.h +++ b/polyp/mainloop-api.h @@ -45,73 +45,75 @@ PA_C_DECL_BEGIN /** A bitmask for IO events */ -enum pa_io_event_flags { +typedef enum pa_io_event_flags { PA_IO_EVENT_NULL = 0, /**< No event */ PA_IO_EVENT_INPUT = 1, /**< Input event */ PA_IO_EVENT_OUTPUT = 2, /**< Output event */ PA_IO_EVENT_HANGUP = 4, /**< Hangup event */ PA_IO_EVENT_ERROR = 8 /**< Error event */ -}; +} pa_io_event_flags; -/** \struct pa_io_event +/** \pa_io_event * An opaque IO event source object */ -struct pa_io_event; +typedef struct pa_io_event pa_io_event; -/** \struct pa_defer_event +/** \pa_defer_event * An opaque deferred event source object. Events of this type are triggered once in every main loop iteration */ -struct pa_defer_event; +typedef struct pa_defer_event pa_defer_event; -/** \struct pa_time_event +/** \pa_time_event * An opaque timer event source object */ -struct pa_time_event; +typedef struct pa_time_event pa_time_event; /** An abstract mainloop API vtable */ -struct pa_mainloop_api { +typedef struct pa_mainloop_api pa_mainloop_api; + +struct pa_mainloop_api { /** A pointer to some private, arbitrary data of the main loop implementation */ void *userdata; /** Create a new IO event source object */ - struct pa_io_event* (*io_new)(struct pa_mainloop_api*a, int fd, enum pa_io_event_flags events, void (*callback) (struct pa_mainloop_api*a, struct pa_io_event* e, int fd, enum pa_io_event_flags events, void *userdata), void *userdata); + pa_io_event* (*io_new)(pa_mainloop_api*a, int fd, pa_io_event_flags events, void (*callback) (pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags events, void *userdata), void *userdata); /** Enable or disable IO events on this object */ - void (*io_enable)(struct pa_io_event* e, enum pa_io_event_flags events); + void (*io_enable)(pa_io_event* e, pa_io_event_flags events); /** Free a IO event source object */ - void (*io_free)(struct pa_io_event* e); + void (*io_free)(pa_io_event* e); /** Set a function that is called when the IO event source is destroyed. Use this to free the userdata argument if required */ - void (*io_set_destroy)(struct pa_io_event *e, void (*callback) (struct pa_mainloop_api*a, struct pa_io_event *e, void *userdata)); + void (*io_set_destroy)(pa_io_event *e, void (*callback) (pa_mainloop_api*a, pa_io_event *e, void *userdata)); /** Create a new timer event source object for the specified Unix time */ - struct pa_time_event* (*time_new)(struct pa_mainloop_api*a, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*a, struct pa_time_event* e, const struct timeval *tv, void *userdata), void *userdata); + pa_time_event* (*time_new)(pa_mainloop_api*a, const struct timeval *tv, void (*callback) (pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata), void *userdata); /** Restart a running or expired timer event source with a new Unix time */ - void (*time_restart)(struct pa_time_event* e, const struct timeval *tv); + void (*time_restart)(pa_time_event* e, const struct timeval *tv); /** Free a deferred timer event source object */ - void (*time_free)(struct pa_time_event* e); + void (*time_free)(pa_time_event* e); /** Set a function that is called when the timer event source is destroyed. Use this to free the userdata argument if required */ - void (*time_set_destroy)(struct pa_time_event *e, void (*callback) (struct pa_mainloop_api*a, struct pa_time_event *e, void *userdata)); + void (*time_set_destroy)(pa_time_event *e, void (*callback) (pa_mainloop_api*a, pa_time_event *e, void *userdata)); /** Create a new deferred event source object */ - struct pa_defer_event* (*defer_new)(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, struct pa_defer_event* e, void *userdata), void *userdata); + pa_defer_event* (*defer_new)(pa_mainloop_api*a, void (*callback) (pa_mainloop_api*a, pa_defer_event* e, void *userdata), void *userdata); /** Enable or disable a deferred event source temporarily */ - void (*defer_enable)(struct pa_defer_event* e, int b); + void (*defer_enable)(pa_defer_event* e, int b); /** Free a deferred event source object */ - void (*defer_free)(struct pa_defer_event* e); + void (*defer_free)(pa_defer_event* e); /** Set a function that is called when the deferred event source is destroyed. Use this to free the userdata argument if required */ - void (*defer_set_destroy)(struct pa_defer_event *e, void (*callback) (struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata)); + void (*defer_set_destroy)(pa_defer_event *e, void (*callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata)); /** Exit the main loop and return the specfied retval*/ - void (*quit)(struct pa_mainloop_api*a, int retval); + void (*quit)(pa_mainloop_api*a, int retval); }; /** Run the specified callback function once from the main loop using an anonymous defer event. */ -void pa_mainloop_api_once(struct pa_mainloop_api*m, void (*callback)(struct pa_mainloop_api*m, void *userdata), void *userdata); +void pa_mainloop_api_once(pa_mainloop_api*m, void (*callback)(pa_mainloop_api*m, void *userdata), void *userdata); PA_C_DECL_END diff --git a/polyp/mainloop-signal.c b/polyp/mainloop-signal.c index 432498a8..f225e60b 100644 --- a/polyp/mainloop-signal.c +++ b/polyp/mainloop-signal.c @@ -40,6 +40,7 @@ #include "util.h" #include "xmalloc.h" #include "log.h" +#include "gccmacro.h" struct pa_signal_event { int sig; @@ -48,17 +49,17 @@ struct pa_signal_event { #else void (*saved_handler)(int sig); #endif - void (*callback) (struct pa_mainloop_api*a, struct pa_signal_event *e, int signal, void *userdata); + void (*callback) (pa_mainloop_api*a, pa_signal_event *e, int sig, void *userdata); void *userdata; - void (*destroy_callback) (struct pa_mainloop_api*a, struct pa_signal_event*e, void *userdata); - struct pa_signal_event *previous, *next; + void (*destroy_callback) (pa_mainloop_api*a, pa_signal_event*e, void *userdata); + pa_signal_event *previous, *next; }; -static struct pa_mainloop_api *api = NULL; +static pa_mainloop_api *api = NULL; static int signal_pipe[2] = { -1, -1 }; -static struct pa_io_event* io_event = NULL; -static struct pa_defer_event *defer_event = NULL; -static struct pa_signal_event *signals = NULL; +static pa_io_event* io_event = NULL; +static pa_defer_event *defer_event = NULL; +static pa_signal_event *signals = NULL; #ifdef OS_IS_WIN32 static unsigned int waiting_signals = 0; @@ -78,8 +79,8 @@ static void signal_handler(int sig) { #endif } -static void dispatch(struct pa_mainloop_api*a, int sig) { - struct pa_signal_event*s; +static void dispatch(pa_mainloop_api*a, int sig) { + pa_signal_event*s; for (s = signals; s; s = s->next) if (s->sig == sig) { @@ -89,7 +90,7 @@ static void dispatch(struct pa_mainloop_api*a, int sig) { } } -static void defer(struct pa_mainloop_api*a, struct pa_defer_event*e, void *userdata) { +static void defer(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event*e, PA_GCC_UNUSED void *userdata) { ssize_t r; int sig; unsigned int sigs; @@ -118,7 +119,7 @@ static void defer(struct pa_mainloop_api*a, struct pa_defer_event*e, void *userd } } -static void callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata) { +static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags f, PA_GCC_UNUSED void *userdata) { ssize_t r; int sig; assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]); @@ -140,7 +141,7 @@ static void callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enu dispatch(a, sig); } -int pa_signal_init(struct pa_mainloop_api *a) { +int pa_signal_init(pa_mainloop_api *a) { assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event && !defer_event); #ifdef OS_IS_WIN32 @@ -196,22 +197,22 @@ void pa_signal_done(void) { api = NULL; } -struct pa_signal_event* pa_signal_new(int sig, void (*callback) (struct pa_mainloop_api *api, struct pa_signal_event*e, int sig, void *userdata), void *userdata) { - struct pa_signal_event *e = NULL; +pa_signal_event* pa_signal_new(int sig, void (*_callback) (pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata), void *userdata) { + pa_signal_event *e = NULL; #ifdef HAVE_SIGACTION struct sigaction sa; #endif - assert(sig > 0 && callback); + assert(sig > 0 && _callback); for (e = signals; e; e = e->next) if (e->sig == sig) goto fail; - e = pa_xmalloc(sizeof(struct pa_signal_event)); + e = pa_xmalloc(sizeof(pa_signal_event)); e->sig = sig; - e->callback = callback; + e->callback = _callback; e->userdata = userdata; e->destroy_callback = NULL; @@ -238,7 +239,7 @@ fail: return NULL; } -void pa_signal_free(struct pa_signal_event *e) { +void pa_signal_free(pa_signal_event *e) { assert(e); if (e->next) @@ -260,7 +261,7 @@ void pa_signal_free(struct pa_signal_event *e) { pa_xfree(e); } -void pa_signal_set_destroy(struct pa_signal_event *e, void (*callback) (struct pa_mainloop_api *api, struct pa_signal_event*e, void *userdata)) { +void pa_signal_set_destroy(pa_signal_event *e, void (*_callback) (pa_mainloop_api *api, pa_signal_event*e, void *userdata)) { assert(e); - e->destroy_callback = callback; + e->destroy_callback = _callback; } diff --git a/polyp/mainloop-signal.h b/polyp/mainloop-signal.h index 9ba92141..6ce31370 100644 --- a/polyp/mainloop-signal.h +++ b/polyp/mainloop-signal.h @@ -37,23 +37,23 @@ PA_C_DECL_BEGIN */ /** Initialize the UNIX signal subsystem and bind it to the specified main loop */ -int pa_signal_init(struct pa_mainloop_api *api); +int pa_signal_init(pa_mainloop_api *api); /** Cleanup the signal subsystem */ void pa_signal_done(void); -/** \struct pa_signal_event +/** \pa_signal_event * An opaque UNIX signal event source object */ -struct pa_signal_event; +typedef struct pa_signal_event pa_signal_event; /** Create a new UNIX signal event source object */ -struct pa_signal_event* pa_signal_new(int signal, void (*callback) (struct pa_mainloop_api *api, struct pa_signal_event*e, int signal, void *userdata), void *userdata); +pa_signal_event* pa_signal_new(int sig, void (*callback) (pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata), void *userdata); /** Free a UNIX signal event source object */ -void pa_signal_free(struct pa_signal_event *e); +void pa_signal_free(pa_signal_event *e); /** Set a function that is called when the signal event source is destroyed. Use this to free the userdata argument if required */ -void pa_signal_set_destroy(struct pa_signal_event *e, void (*callback) (struct pa_mainloop_api *api, struct pa_signal_event*e, void *userdata)); +void pa_signal_set_destroy(pa_signal_event *e, void (*callback) (pa_mainloop_api *api, pa_signal_event*e, void *userdata)); PA_C_DECL_END diff --git a/polyp/mainloop-test.c b/polyp/mainloop-test.c index dd8f8137..097ce1c7 100644 --- a/polyp/mainloop-test.c +++ b/polyp/mainloop-test.c @@ -28,10 +28,14 @@ #include #include +#include "util.h" +#include "gccmacro.h" + #ifdef GLIB_MAIN_LOOP #include #include "glib-mainloop.h" + static GMainLoop* glib_main_loop = NULL; #if GLIB_MAJOR_VERSION >= 2 @@ -45,21 +49,21 @@ static GMainLoop* glib_main_loop = NULL; #include "mainloop.h" #endif /* GLIB_MAIN_LOOP */ -static struct pa_defer_event *de; +static pa_defer_event *de; -static void iocb(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { +static void iocb(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata) { unsigned char c; read(fd, &c, sizeof(c)); fprintf(stderr, "IO EVENT: %c\n", c < 32 ? '.' : c); a->defer_enable(de, 1); } -static void dcb(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata) { +static void dcb(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { fprintf(stderr, "DEFER EVENT\n"); a->defer_enable(e, 0); } -static void tcb(struct pa_mainloop_api*a, struct pa_time_event *e, const struct timeval *tv, void *userdata) { +static void tcb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) { fprintf(stderr, "TIME EVENT\n"); #if defined(GLIB_MAIN_LOOP) && defined(GLIB20) @@ -71,14 +75,14 @@ static void tcb(struct pa_mainloop_api*a, struct pa_time_event *e, const struct #endif } -int main(int argc, char *argv[]) { - struct pa_mainloop_api *a; - struct pa_io_event *ioe; - struct pa_time_event *te; +int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { + pa_mainloop_api *a; + pa_io_event *ioe; + pa_time_event *te; struct timeval tv; #ifdef GLIB_MAIN_LOOP - struct pa_glib_mainloop *g; + pa_glib_mainloop *g; #ifdef GLIB20 glib_main_loop = g_main_loop_new(NULL, FALSE); @@ -96,7 +100,7 @@ int main(int argc, char *argv[]) { a = pa_glib_mainloop_get_api(g); assert(a); #else /* GLIB_MAIN_LOOP */ - struct pa_mainloop *m; + pa_mainloop *m; m = pa_mainloop_new(); assert(m); diff --git a/polyp/mainloop.c b/polyp/mainloop.c index ada74afc..599a90f8 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -47,37 +47,37 @@ #include "log.h" struct pa_io_event { - struct pa_mainloop *mainloop; + pa_mainloop *mainloop; int dead; int fd; - enum pa_io_event_flags events; - void (*callback) (struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata); + pa_io_event_flags events; + void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata); struct pollfd *pollfd; void *userdata; - void (*destroy_callback) (struct pa_mainloop_api*a, struct pa_io_event *e, void *userdata); + void (*destroy_callback) (pa_mainloop_api*a, pa_io_event *e, void *userdata); }; struct pa_time_event { - struct pa_mainloop *mainloop; + pa_mainloop *mainloop; int dead; int enabled; struct timeval timeval; - void (*callback)(struct pa_mainloop_api*a, struct pa_time_event *e, const struct timeval*tv, void *userdata); + void (*callback)(pa_mainloop_api*a, pa_time_event *e, const struct timeval*tv, void *userdata); void *userdata; - void (*destroy_callback) (struct pa_mainloop_api*a, struct pa_time_event *e, void *userdata); + void (*destroy_callback) (pa_mainloop_api*a, pa_time_event *e, void *userdata); }; struct pa_defer_event { - struct pa_mainloop *mainloop; + pa_mainloop *mainloop; int dead; int enabled; - void (*callback)(struct pa_mainloop_api*a, struct pa_defer_event*e, void *userdata); + void (*callback)(pa_mainloop_api*a, pa_defer_event*e, void *userdata); void *userdata; - void (*destroy_callback) (struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata); + void (*destroy_callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata); }; struct pa_mainloop { - struct pa_idxset *io_events, *time_events, *defer_events; + pa_idxset *io_events, *time_events, *defer_events; int io_events_scan_dead, defer_events_scan_dead, time_events_scan_dead; struct pollfd *pollfds; @@ -85,21 +85,21 @@ struct pa_mainloop { int rebuild_pollfds; int quit, running, retval; - struct pa_mainloop_api api; + pa_mainloop_api api; int deferred_pending; }; /* IO events */ -static struct pa_io_event* mainloop_io_new(struct pa_mainloop_api*a, int fd, enum pa_io_event_flags events, void (*callback) (struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags events, void *userdata), void *userdata) { - struct pa_mainloop *m; - struct pa_io_event *e; +static pa_io_event* mainloop_io_new(pa_mainloop_api*a, int fd, pa_io_event_flags events, void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags events, void *userdata), void *userdata) { + pa_mainloop *m; + pa_io_event *e; assert(a && a->userdata && fd >= 0 && callback); m = a->userdata; assert(a == &m->api); - e = pa_xmalloc(sizeof(struct pa_io_event)); + e = pa_xmalloc(sizeof(pa_io_event)); e->mainloop = m; e->dead = 0; @@ -135,7 +135,7 @@ static struct pa_io_event* mainloop_io_new(struct pa_mainloop_api*a, int fd, enu return e; } -static void mainloop_io_enable(struct pa_io_event *e, enum pa_io_event_flags events) { +static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags events) { assert(e && e->mainloop); e->events = events; @@ -146,26 +146,26 @@ static void mainloop_io_enable(struct pa_io_event *e, enum pa_io_event_flags eve POLLERR | POLLHUP; } -static void mainloop_io_free(struct pa_io_event *e) { +static void mainloop_io_free(pa_io_event *e) { assert(e && e->mainloop); e->dead = e->mainloop->io_events_scan_dead = e->mainloop->rebuild_pollfds = 1; } -static void mainloop_io_set_destroy(struct pa_io_event *e, void (*callback)(struct pa_mainloop_api*a, struct pa_io_event *e, void *userdata)) { +static void mainloop_io_set_destroy(pa_io_event *e, void (*callback)(pa_mainloop_api*a, pa_io_event *e, void *userdata)) { assert(e); e->destroy_callback = callback; } /* Defer events */ -static struct pa_defer_event* mainloop_defer_new(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata), void *userdata) { - struct pa_mainloop *m; - struct pa_defer_event *e; +static pa_defer_event* mainloop_defer_new(pa_mainloop_api*a, void (*callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata), void *userdata) { + pa_mainloop *m; + pa_defer_event *e; assert(a && a->userdata && callback); m = a->userdata; assert(a == &m->api); - e = pa_xmalloc(sizeof(struct pa_defer_event)); + e = pa_xmalloc(sizeof(pa_defer_event)); e->mainloop = m; e->dead = 0; @@ -180,7 +180,7 @@ static struct pa_defer_event* mainloop_defer_new(struct pa_mainloop_api*a, void return e; } -static void mainloop_defer_enable(struct pa_defer_event *e, int b) { +static void mainloop_defer_enable(pa_defer_event *e, int b) { assert(e); if (e->enabled && !b) { @@ -192,7 +192,7 @@ static void mainloop_defer_enable(struct pa_defer_event *e, int b) { e->enabled = b; } -static void mainloop_defer_free(struct pa_defer_event *e) { +static void mainloop_defer_free(pa_defer_event *e) { assert(e); e->dead = e->mainloop->defer_events_scan_dead = 1; @@ -203,21 +203,21 @@ static void mainloop_defer_free(struct pa_defer_event *e) { } } -static void mainloop_defer_set_destroy(struct pa_defer_event *e, void (*callback)(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata)) { +static void mainloop_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api*a, pa_defer_event *e, void *userdata)) { assert(e); e->destroy_callback = callback; } /* Time events */ -static struct pa_time_event* mainloop_time_new(struct pa_mainloop_api*a, const struct timeval *tv, void (*callback) (struct pa_mainloop_api*a, struct pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { - struct pa_mainloop *m; - struct pa_time_event *e; +static pa_time_event* mainloop_time_new(pa_mainloop_api*a, const struct timeval *tv, void (*callback) (pa_mainloop_api*a, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { + pa_mainloop *m; + pa_time_event *e; assert(a && a->userdata && callback); m = a->userdata; assert(a == &m->api); - e = pa_xmalloc(sizeof(struct pa_time_event)); + e = pa_xmalloc(sizeof(pa_time_event)); e->mainloop = m; e->dead = 0; @@ -234,7 +234,7 @@ static struct pa_time_event* mainloop_time_new(struct pa_mainloop_api*a, const s return e; } -static void mainloop_time_restart(struct pa_time_event *e, const struct timeval *tv) { +static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) { assert(e); if (tv) { @@ -244,21 +244,21 @@ static void mainloop_time_restart(struct pa_time_event *e, const struct timeval e->enabled = 0; } -static void mainloop_time_free(struct pa_time_event *e) { +static void mainloop_time_free(pa_time_event *e) { assert(e); e->dead = e->mainloop->time_events_scan_dead = 1; } -static void mainloop_time_set_destroy(struct pa_time_event *e, void (*callback)(struct pa_mainloop_api*a, struct pa_time_event *e, void *userdata)) { +static void mainloop_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*a, pa_time_event *e, void *userdata)) { assert(e); e->destroy_callback = callback; } /* quit() */ -static void mainloop_quit(struct pa_mainloop_api*a, int retval) { - struct pa_mainloop *m; +static void mainloop_quit(pa_mainloop_api*a, int retval) { + pa_mainloop *m; assert(a && a->userdata); m = a->userdata; assert(a == &m->api); @@ -267,7 +267,7 @@ static void mainloop_quit(struct pa_mainloop_api*a, int retval) { m->retval = retval; } -static const struct pa_mainloop_api vtable = { +static const pa_mainloop_api vtable = { .userdata = NULL, .io_new= mainloop_io_new, @@ -288,10 +288,10 @@ static const struct pa_mainloop_api vtable = { .quit = mainloop_quit, }; -struct pa_mainloop *pa_mainloop_new(void) { - struct pa_mainloop *m; +pa_mainloop *pa_mainloop_new(void) { + pa_mainloop *m; - m = pa_xmalloc(sizeof(struct pa_mainloop)); + m = pa_xmalloc(sizeof(pa_mainloop)); m->io_events = pa_idxset_new(NULL, NULL); m->defer_events = pa_idxset_new(NULL, NULL); @@ -314,8 +314,8 @@ struct pa_mainloop *pa_mainloop_new(void) { return m; } -static int io_foreach(void *p, uint32_t index, int *del, void*userdata) { - struct pa_io_event *e = p; +static int io_foreach(void *p, uint32_t PA_GCC_UNUSED idx, int *del, void*userdata) { + pa_io_event *e = p; int *all = userdata; assert(e && del && all); @@ -329,8 +329,8 @@ static int io_foreach(void *p, uint32_t index, int *del, void*userdata) { return 0; } -static int time_foreach(void *p, uint32_t index, int *del, void*userdata) { - struct pa_time_event *e = p; +static int time_foreach(void *p, uint32_t PA_GCC_UNUSED idx, int *del, void*userdata) { + pa_time_event *e = p; int *all = userdata; assert(e && del && all); @@ -344,8 +344,8 @@ static int time_foreach(void *p, uint32_t index, int *del, void*userdata) { return 0; } -static int defer_foreach(void *p, uint32_t index, int *del, void*userdata) { - struct pa_defer_event *e = p; +static int defer_foreach(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void*userdata) { + pa_defer_event *e = p; int *all = userdata; assert(e && del && all); @@ -359,7 +359,7 @@ static int defer_foreach(void *p, uint32_t index, int *del, void*userdata) { return 0; } -void pa_mainloop_free(struct pa_mainloop* m) { +void pa_mainloop_free(pa_mainloop* m) { int all = 1; assert(m); @@ -375,7 +375,7 @@ void pa_mainloop_free(struct pa_mainloop* m) { pa_xfree(m); } -static void scan_dead(struct pa_mainloop *m) { +static void scan_dead(pa_mainloop *m) { int all = 0; assert(m); @@ -389,13 +389,13 @@ static void scan_dead(struct pa_mainloop *m) { m->io_events_scan_dead = m->time_events_scan_dead = m->defer_events_scan_dead = 0; } -static void rebuild_pollfds(struct pa_mainloop *m) { - struct pa_io_event*e; +static void rebuild_pollfds(pa_mainloop *m) { + pa_io_event*e; struct pollfd *p; - uint32_t index = PA_IDXSET_INVALID; + uint32_t idx = PA_IDXSET_INVALID; unsigned l; - l = pa_idxset_ncontents(m->io_events); + l = pa_idxset_size(m->io_events); if (m->max_pollfds < l) { m->pollfds = pa_xrealloc(m->pollfds, sizeof(struct pollfd)*l); m->max_pollfds = l; @@ -403,7 +403,7 @@ static void rebuild_pollfds(struct pa_mainloop *m) { m->n_pollfds = 0; p = m->pollfds; - for (e = pa_idxset_first(m->io_events, &index); e; e = pa_idxset_next(m->io_events, &index)) { + for (e = pa_idxset_first(m->io_events, &idx); e; e = pa_idxset_next(m->io_events, &idx)) { if (e->dead) { e->pollfd = NULL; continue; @@ -423,12 +423,12 @@ static void rebuild_pollfds(struct pa_mainloop *m) { } } -static int dispatch_pollfds(struct pa_mainloop *m) { - uint32_t index = PA_IDXSET_INVALID; - struct pa_io_event *e; +static int dispatch_pollfds(pa_mainloop *m) { + uint32_t idx = PA_IDXSET_INVALID; + pa_io_event *e; int r = 0; - for (e = pa_idxset_first(m->io_events, &index); e && !m->quit; e = pa_idxset_next(m->io_events, &index)) { + for (e = pa_idxset_first(m->io_events, &idx); e && !m->quit; e = pa_idxset_next(m->io_events, &idx)) { if (e->dead || !e->pollfd || !e->pollfd->revents) continue; @@ -446,15 +446,15 @@ static int dispatch_pollfds(struct pa_mainloop *m) { return r; } -static int dispatch_defer(struct pa_mainloop *m) { - uint32_t index; - struct pa_defer_event *e; +static int dispatch_defer(pa_mainloop *m) { + uint32_t idx; + pa_defer_event *e; int r = 0; if (!m->deferred_pending) return 0; - for (e = pa_idxset_first(m->defer_events, &index); e && !m->quit; e = pa_idxset_next(m->defer_events, &index)) { + for (e = pa_idxset_first(m->defer_events, &idx); e && !m->quit; e = pa_idxset_next(m->defer_events, &idx)) { if (e->dead || !e->enabled) continue; @@ -466,9 +466,9 @@ static int dispatch_defer(struct pa_mainloop *m) { return r; } -static int calc_next_timeout(struct pa_mainloop *m) { - uint32_t index; - struct pa_time_event *e; +static int calc_next_timeout(pa_mainloop *m) { + uint32_t idx; + pa_time_event *e; struct timeval now; int t = -1; int got_time = 0; @@ -476,7 +476,7 @@ static int calc_next_timeout(struct pa_mainloop *m) { if (pa_idxset_isempty(m->time_events)) return -1; - for (e = pa_idxset_first(m->time_events, &index); e; e = pa_idxset_next(m->time_events, &index)) { + for (e = pa_idxset_first(m->time_events, &idx); e; e = pa_idxset_next(m->time_events, &idx)) { int tmp; if (e->dead || !e->enabled) @@ -507,9 +507,9 @@ static int calc_next_timeout(struct pa_mainloop *m) { return t; } -static int dispatch_timeout(struct pa_mainloop *m) { - uint32_t index; - struct pa_time_event *e; +static int dispatch_timeout(pa_mainloop *m) { + uint32_t idx; + pa_time_event *e; struct timeval now; int got_time = 0; int r = 0; @@ -518,7 +518,7 @@ static int dispatch_timeout(struct pa_mainloop *m) { if (pa_idxset_isempty(m->time_events)) return 0; - for (e = pa_idxset_first(m->time_events, &index); e && !m->quit; e = pa_idxset_next(m->time_events, &index)) { + for (e = pa_idxset_first(m->time_events, &idx); e && !m->quit; e = pa_idxset_next(m->time_events, &idx)) { if (e->dead || !e->enabled) continue; @@ -542,7 +542,7 @@ static int dispatch_timeout(struct pa_mainloop *m) { return r; } -int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval) { +int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) { int r, t, dispatched = 0; assert(m && !m->running); @@ -601,7 +601,7 @@ quit: return -2; } -int pa_mainloop_run(struct pa_mainloop *m, int *retval) { +int pa_mainloop_run(pa_mainloop *m, int *retval) { int r; while ((r = pa_mainloop_iterate(m, 1, retval)) >= 0); @@ -613,31 +613,32 @@ int pa_mainloop_run(struct pa_mainloop *m, int *retval) { return 0; } -void pa_mainloop_quit(struct pa_mainloop *m, int r) { +void pa_mainloop_quit(pa_mainloop *m, int r) { assert(m); m->quit = r; } -struct pa_mainloop_api* pa_mainloop_get_api(struct pa_mainloop*m) { +pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m) { assert(m); return &m->api; } -int pa_mainloop_deferred_pending(struct pa_mainloop *m) { +int pa_mainloop_deferred_pending(pa_mainloop *m) { assert(m); return m->deferred_pending > 0; } -void pa_mainloop_dump(struct pa_mainloop *m) { +#if 0 +void pa_mainloop_dump(pa_mainloop *m) { assert(m); pa_log(__FILE__": Dumping mainloop sources START\n"); { - uint32_t index = PA_IDXSET_INVALID; - struct pa_io_event *e; - for (e = pa_idxset_first(m->io_events, &index); e; e = pa_idxset_next(m->io_events, &index)) { + uint32_t idx = PA_IDXSET_INVALID; + pa_io_event *e; + for (e = pa_idxset_first(m->io_events, &idx); e; e = pa_idxset_next(m->io_events, &idx)) { if (e->dead) continue; @@ -645,9 +646,9 @@ void pa_mainloop_dump(struct pa_mainloop *m) { } } { - uint32_t index = PA_IDXSET_INVALID; - struct pa_defer_event *e; - for (e = pa_idxset_first(m->defer_events, &index); e; e = pa_idxset_next(m->defer_events, &index)) { + uint32_t idx = PA_IDXSET_INVALID; + pa_defer_event *e; + for (e = pa_idxset_first(m->defer_events, &idx); e; e = pa_idxset_next(m->defer_events, &idx)) { if (e->dead) continue; @@ -655,9 +656,9 @@ void pa_mainloop_dump(struct pa_mainloop *m) { } } { - uint32_t index = PA_IDXSET_INVALID; - struct pa_time_event *e; - for (e = pa_idxset_first(m->time_events, &index); e; e = pa_idxset_next(m->time_events, &index)) { + uint32_t idx = PA_IDXSET_INVALID; + pa_time_event *e; + for (e = pa_idxset_first(m->time_events, &idx); e; e = pa_idxset_next(m->time_events, &idx)) { if (e->dead) continue; @@ -668,3 +669,4 @@ void pa_mainloop_dump(struct pa_mainloop *m) { pa_log(__FILE__": Dumping mainloop sources STOP\n"); } +#endif diff --git a/polyp/mainloop.h b/polyp/mainloop.h index 06a6ccaa..06764907 100644 --- a/polyp/mainloop.h +++ b/polyp/mainloop.h @@ -35,32 +35,35 @@ PA_C_DECL_BEGIN * defined in \ref mainloop-api.h. This implementation is thread safe * as long as you access the main loop object from a single thread only.*/ -/** \struct pa_mainloop +/** \pa_mainloop * An opaque main loop object */ -struct pa_mainloop; +typedef struct pa_mainloop pa_mainloop; /** Allocate a new main loop object */ -struct pa_mainloop *pa_mainloop_new(void); +pa_mainloop *pa_mainloop_new(void); /** Free a main loop object */ -void pa_mainloop_free(struct pa_mainloop* m); +void pa_mainloop_free(pa_mainloop* m); /** Run a single iteration of the main loop. Returns a negative value on error or exit request. If block is nonzero, block for events if none are queued. Optionally return the return value as specified with the main loop's quit() routine in the integer variable retval points to. On success returns the number of source dispatched in this iteration. */ -int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval); +int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval); /** Run unlimited iterations of the main loop object until the main loop's quit() routine is called. */ -int pa_mainloop_run(struct pa_mainloop *m, int *retval); +int pa_mainloop_run(pa_mainloop *m, int *retval); /** Return the abstract main loop abstraction layer vtable for this main loop. This calls pa_mainloop_iterate() iteratively.*/ -struct pa_mainloop_api* pa_mainloop_get_api(struct pa_mainloop*m); +pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m); /** Return non-zero when there are any deferred events pending. \since 0.5 */ -int pa_mainloop_deferred_pending(struct pa_mainloop *m); +int pa_mainloop_deferred_pending(pa_mainloop *m); + +/** Shutdown the main loop */ +void pa_mainloop_quit(pa_mainloop *m, int r); PA_C_DECL_END diff --git a/polyp/mcalign-test.c b/polyp/mcalign-test.c index 2ace6e59..c151d8f2 100644 --- a/polyp/mcalign-test.c +++ b/polyp/mcalign-test.c @@ -33,12 +33,13 @@ #include "util.h" #include "mcalign.h" +#include "gccmacro.h" /* A simple program for testing pa_mcalign */ -int main(int argc, char *argv[]) { - struct pa_mcalign *a = pa_mcalign_new(11, NULL); - struct pa_memchunk c; +int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { + pa_mcalign *a = pa_mcalign_new(11, NULL); + pa_memchunk c; pa_memchunk_reset(&c); @@ -76,7 +77,7 @@ int main(int argc, char *argv[]) { } for (;;) { - struct pa_memchunk t; + pa_memchunk t; if (pa_mcalign_pop(a, &t) < 0) break; diff --git a/polyp/mcalign.c b/polyp/mcalign.c index 0b7f0db0..4d765625 100644 --- a/polyp/mcalign.c +++ b/polyp/mcalign.c @@ -33,15 +33,15 @@ struct pa_mcalign { size_t base; - struct pa_memchunk leftover, current; - struct pa_memblock_stat *memblock_stat; + pa_memchunk leftover, current; + pa_memblock_stat *memblock_stat; }; -struct pa_mcalign *pa_mcalign_new(size_t base, struct pa_memblock_stat *s) { - struct pa_mcalign *m; +pa_mcalign *pa_mcalign_new(size_t base, pa_memblock_stat *s) { + pa_mcalign *m; assert(base); - m = pa_xmalloc(sizeof(struct pa_mcalign)); + m = pa_xnew(pa_mcalign, 1); m->base = base; pa_memchunk_reset(&m->leftover); pa_memchunk_reset(&m->current); @@ -50,7 +50,7 @@ struct pa_mcalign *pa_mcalign_new(size_t base, struct pa_memblock_stat *s) { return m; } -void pa_mcalign_free(struct pa_mcalign *m) { +void pa_mcalign_free(pa_mcalign *m) { assert(m); if (m->leftover.memblock) @@ -62,7 +62,7 @@ void pa_mcalign_free(struct pa_mcalign *m) { pa_xfree(m); } -void pa_mcalign_push(struct pa_mcalign *m, const struct pa_memchunk *c) { +void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { assert(m && c && c->memblock && c->length); /* Append to the leftover memory block */ @@ -122,7 +122,7 @@ void pa_mcalign_push(struct pa_mcalign *m, const struct pa_memchunk *c) { } } -int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c) { +int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) { assert(m && c); /* First test if there's a leftover memory block available */ diff --git a/polyp/mcalign.h b/polyp/mcalign.h index 925f438a..5de75bc7 100644 --- a/polyp/mcalign.h +++ b/polyp/mcalign.h @@ -36,10 +36,10 @@ * 0, the memchunk *c is valid and aligned to the granularity. Some * pseudocode illustrating this: * - * struct pa_mcalign *a = pa_mcalign_new(4, NULL); + * pa_mcalign *a = pa_mcalign_new(4, NULL); * * for (;;) { - * struct pa_memchunk input; + * pa_memchunk input; * * ... fill input ... * @@ -47,7 +47,7 @@ * pa_memblock_unref(input.memblock); * * for (;;) { - * struct pa_memchunk output; + * pa_memchunk output; * * if (pa_mcalign_pop(m, &output) < 0) * break; @@ -61,17 +61,17 @@ * pa_memchunk_free(a); * */ -struct pa_mcalign; +typedef struct pa_mcalign pa_mcalign; -struct pa_mcalign *pa_mcalign_new(size_t base, struct pa_memblock_stat *s); -void pa_mcalign_free(struct pa_mcalign *m); +pa_mcalign *pa_mcalign_new(size_t base, pa_memblock_stat *s); +void pa_mcalign_free(pa_mcalign *m); /* Push a new memchunk into the aligner. The caller of this routine * has to free the memchunk by himself. */ -void pa_mcalign_push(struct pa_mcalign *m, const struct pa_memchunk *c); +void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c); /* Pop a new memchunk from the aligner. Returns 0 when sucessful, * nonzero otherwise. */ -int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c); +int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c); #endif diff --git a/polyp/memblock.c b/polyp/memblock.c index c070bee6..8da53525 100644 --- a/polyp/memblock.c +++ b/polyp/memblock.c @@ -31,7 +31,7 @@ #include "memblock.h" #include "xmalloc.h" -static void stat_add(struct pa_memblock*m, struct pa_memblock_stat *s) { +static void stat_add(pa_memblock*m, pa_memblock_stat *s) { assert(m); if (!s) { @@ -46,7 +46,7 @@ static void stat_add(struct pa_memblock*m, struct pa_memblock_stat *s) { s->allocated_size += m->length; } -static void stat_remove(struct pa_memblock *m) { +static void stat_remove(pa_memblock *m) { assert(m); if (!m->stat) @@ -59,8 +59,8 @@ static void stat_remove(struct pa_memblock *m) { m->stat = NULL; } -struct pa_memblock *pa_memblock_new(size_t length, struct pa_memblock_stat*s) { - struct pa_memblock *b = pa_xmalloc(sizeof(struct pa_memblock)+length); +pa_memblock *pa_memblock_new(size_t length, pa_memblock_stat*s) { + pa_memblock *b = pa_xmalloc(sizeof(pa_memblock)+length); b->type = PA_MEMBLOCK_APPENDED; b->ref = 1; b->length = length; @@ -71,8 +71,8 @@ struct pa_memblock *pa_memblock_new(size_t length, struct pa_memblock_stat*s) { return b; } -struct pa_memblock *pa_memblock_new_dynamic(void *d, size_t length, struct pa_memblock_stat*s) { - struct pa_memblock *b = pa_xmalloc(sizeof(struct pa_memblock)); +pa_memblock *pa_memblock_new_dynamic(void *d, size_t length, pa_memblock_stat*s) { + pa_memblock *b = pa_xmalloc(sizeof(pa_memblock)); b->type = PA_MEMBLOCK_DYNAMIC; b->ref = 1; b->length = length; @@ -83,8 +83,8 @@ struct pa_memblock *pa_memblock_new_dynamic(void *d, size_t length, struct pa_me return b; } -struct pa_memblock *pa_memblock_new_fixed(void *d, size_t length, int read_only, struct pa_memblock_stat*s) { - struct pa_memblock *b = pa_xmalloc(sizeof(struct pa_memblock)); +pa_memblock *pa_memblock_new_fixed(void *d, size_t length, int read_only, pa_memblock_stat*s) { + pa_memblock *b = pa_xmalloc(sizeof(pa_memblock)); b->type = PA_MEMBLOCK_FIXED; b->ref = 1; b->length = length; @@ -95,10 +95,10 @@ struct pa_memblock *pa_memblock_new_fixed(void *d, size_t length, int read_only, return b; } -struct pa_memblock *pa_memblock_new_user(void *d, size_t length, void (*free_cb)(void *p), int read_only, struct pa_memblock_stat*s) { - struct pa_memblock *b; +pa_memblock *pa_memblock_new_user(void *d, size_t length, void (*free_cb)(void *p), int read_only, pa_memblock_stat*s) { + pa_memblock *b; assert(d && length && free_cb); - b = pa_xmalloc(sizeof(struct pa_memblock)); + b = pa_xmalloc(sizeof(pa_memblock)); b->type = PA_MEMBLOCK_USER; b->ref = 1; b->length = length; @@ -109,13 +109,13 @@ struct pa_memblock *pa_memblock_new_user(void *d, size_t length, void (*free_cb) return b; } -struct pa_memblock* pa_memblock_ref(struct pa_memblock*b) { +pa_memblock* pa_memblock_ref(pa_memblock*b) { assert(b && b->ref >= 1); b->ref++; return b; } -void pa_memblock_unref(struct pa_memblock*b) { +void pa_memblock_unref(pa_memblock*b) { assert(b && b->ref >= 1); if ((--(b->ref)) == 0) { @@ -131,7 +131,7 @@ void pa_memblock_unref(struct pa_memblock*b) { } } -void pa_memblock_unref_fixed(struct pa_memblock *b) { +void pa_memblock_unref_fixed(pa_memblock *b) { assert(b && b->ref >= 1 && b->type == PA_MEMBLOCK_FIXED); if (b->ref == 1) @@ -143,17 +143,17 @@ void pa_memblock_unref_fixed(struct pa_memblock *b) { } } -struct pa_memblock_stat* pa_memblock_stat_new(void) { - struct pa_memblock_stat *s; +pa_memblock_stat* pa_memblock_stat_new(void) { + pa_memblock_stat *s; - s = pa_xmalloc(sizeof(struct pa_memblock_stat)); + s = pa_xmalloc(sizeof(pa_memblock_stat)); s->ref = 1; s->total = s->total_size = s->allocated = s->allocated_size = 0; return s; } -void pa_memblock_stat_unref(struct pa_memblock_stat *s) { +void pa_memblock_stat_unref(pa_memblock_stat *s) { assert(s && s->ref >= 1); if (!(--(s->ref))) { @@ -162,7 +162,7 @@ void pa_memblock_stat_unref(struct pa_memblock_stat *s) { } } -struct pa_memblock_stat * pa_memblock_stat_ref(struct pa_memblock_stat *s) { +pa_memblock_stat * pa_memblock_stat_ref(pa_memblock_stat *s) { assert(s); s->ref++; return s; diff --git a/polyp/memblock.h b/polyp/memblock.h index 8555954c..cbf5d684 100644 --- a/polyp/memblock.h +++ b/polyp/memblock.h @@ -31,58 +31,57 @@ * memory blocks. */ /* The type of memory this block points to */ -enum pa_memblock_type { +typedef enum { PA_MEMBLOCK_FIXED, /* data is a pointer to fixed memory that needs not to be freed */ PA_MEMBLOCK_APPENDED, /* The most common kind: the data is appended to the memory block */ PA_MEMBLOCK_DYNAMIC, /* data is a pointer to some memory allocated with pa_xmalloc() */ PA_MEMBLOCK_USER /* User supplied memory, to be freed with free_cb */ -}; +} pa_memblock_type ; /* A structure of keeping memory block statistics */ -struct pa_memblock_stat; +/* Maintains statistics about memory blocks */ +typedef struct pa_memblock_stat { + int ref; + unsigned total; + unsigned total_size; + unsigned allocated; + unsigned allocated_size; +} pa_memblock_stat; -struct pa_memblock { - enum pa_memblock_type type; +typedef struct pa_memblock { + pa_memblock_type type; unsigned ref; /* the reference counter */ int read_only; /* boolean */ size_t length; void *data; void (*free_cb)(void *p); /* If type == PA_MEMBLOCK_USER this points to a function for freeing this memory block */ - struct pa_memblock_stat *stat; -}; + pa_memblock_stat *stat; +} pa_memblock; /* Allocate a new memory block of type PA_MEMBLOCK_APPENDED */ -struct pa_memblock *pa_memblock_new(size_t length, struct pa_memblock_stat*s); +pa_memblock *pa_memblock_new(size_t length, pa_memblock_stat*s); /* Allocate a new memory block of type PA_MEMBLOCK_DYNAMIC. The pointer data is to be maintained be the memory block */ -struct pa_memblock *pa_memblock_new_dynamic(void *data, size_t length, struct pa_memblock_stat*s); +pa_memblock *pa_memblock_new_dynamic(void *data, size_t length, pa_memblock_stat*s); /* Allocate a new memory block of type PA_MEMBLOCK_FIXED */ -struct pa_memblock *pa_memblock_new_fixed(void *data, size_t length, int read_only, struct pa_memblock_stat*s); +pa_memblock *pa_memblock_new_fixed(void *data, size_t length, int read_only, pa_memblock_stat*s); /* Allocate a new memory block of type PA_MEMBLOCK_USER */ -struct pa_memblock *pa_memblock_new_user(void *data, size_t length, void (*free_cb)(void *p), int read_only, struct pa_memblock_stat*s); +pa_memblock *pa_memblock_new_user(void *data, size_t length, void (*free_cb)(void *p), int read_only, pa_memblock_stat*s); -void pa_memblock_unref(struct pa_memblock*b); -struct pa_memblock* pa_memblock_ref(struct pa_memblock*b); +void pa_memblock_unref(pa_memblock*b); +pa_memblock* pa_memblock_ref(pa_memblock*b); /* This special unref function has to be called by the owner of the memory of a static memory block when he wants to release all references to the memory. This causes the memory to be copied and converted into a PA_MEMBLOCK_DYNAMIC type memory block */ -void pa_memblock_unref_fixed(struct pa_memblock*b); +void pa_memblock_unref_fixed(pa_memblock*b); -/* Matinatins statistics about memory blocks */ -struct pa_memblock_stat { - int ref; - unsigned total; - unsigned total_size; - unsigned allocated; - unsigned allocated_size; -}; -struct pa_memblock_stat* pa_memblock_stat_new(void); -void pa_memblock_stat_unref(struct pa_memblock_stat *s); -struct pa_memblock_stat * pa_memblock_stat_ref(struct pa_memblock_stat *s); +pa_memblock_stat* pa_memblock_stat_new(void); +void pa_memblock_stat_unref(pa_memblock_stat *s); +pa_memblock_stat * pa_memblock_stat_ref(pa_memblock_stat *s); #endif diff --git a/polyp/memblockq.c b/polyp/memblockq.c index 3f2e4db1..ba6b76ea 100644 --- a/polyp/memblockq.c +++ b/polyp/memblockq.c @@ -37,22 +37,22 @@ struct memblock_list { struct memblock_list *next, *prev; - struct pa_memchunk chunk; + pa_memchunk chunk; }; struct pa_memblockq { struct memblock_list *blocks, *blocks_tail; unsigned n_blocks; size_t current_length, maxlength, tlength, base, prebuf, orig_prebuf, minreq; - struct pa_mcalign *mcalign; - struct pa_memblock_stat *memblock_stat; + pa_mcalign *mcalign; + pa_memblock_stat *memblock_stat; }; -struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t base, size_t prebuf, size_t minreq, struct pa_memblock_stat *s) { - struct pa_memblockq* bq; +pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t base, size_t prebuf, size_t minreq, pa_memblock_stat *s) { + pa_memblockq* bq; assert(maxlength && base && maxlength); - bq = pa_xmalloc(sizeof(struct pa_memblockq)); + bq = pa_xmalloc(sizeof(pa_memblockq)); bq->blocks = bq->blocks_tail = 0; bq->n_blocks = 0; @@ -92,7 +92,7 @@ struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t b return bq; } -void pa_memblockq_free(struct pa_memblockq* bq) { +void pa_memblockq_free(pa_memblockq* bq) { assert(bq); pa_memblockq_flush(bq); @@ -103,7 +103,7 @@ void pa_memblockq_free(struct pa_memblockq* bq) { pa_xfree(bq); } -void pa_memblockq_push(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta) { +void pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *chunk, size_t delta) { struct memblock_list *q; assert(bq && chunk && chunk->memblock && chunk->length && (chunk->length % bq->base) == 0); @@ -138,7 +138,7 @@ void pa_memblockq_push(struct pa_memblockq* bq, const struct pa_memchunk *chunk, pa_memblockq_shorten(bq, bq->maxlength); } -int pa_memblockq_peek(struct pa_memblockq* bq, struct pa_memchunk *chunk) { +int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { assert(bq && chunk); if (!bq->blocks || bq->current_length < bq->prebuf) @@ -152,17 +152,17 @@ int pa_memblockq_peek(struct pa_memblockq* bq, struct pa_memchunk *chunk) { return 0; } -void pa_memblockq_drop(struct pa_memblockq *bq, const struct pa_memchunk *chunk, size_t length) { +void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length) { assert(bq && chunk && length); - if (!bq->blocks || memcmp(&bq->blocks->chunk, chunk, sizeof(struct pa_memchunk))) + if (!bq->blocks || memcmp(&bq->blocks->chunk, chunk, sizeof(pa_memchunk))) return; assert(length <= bq->blocks->chunk.length); pa_memblockq_skip(bq, length); } -static void remove_block(struct pa_memblockq *bq, struct memblock_list *q) { +static void remove_block(pa_memblockq *bq, struct memblock_list *q) { assert(bq && q); if (q->prev) @@ -185,7 +185,7 @@ static void remove_block(struct pa_memblockq *bq, struct memblock_list *q) { bq->n_blocks--; } -void pa_memblockq_skip(struct pa_memblockq *bq, size_t length) { +void pa_memblockq_skip(pa_memblockq *bq, size_t length) { assert(bq && length && (length % bq->base) == 0); while (length > 0) { @@ -206,7 +206,7 @@ void pa_memblockq_skip(struct pa_memblockq *bq, size_t length) { } } -void pa_memblockq_shorten(struct pa_memblockq *bq, size_t length) { +void pa_memblockq_shorten(pa_memblockq *bq, size_t length) { size_t l; assert(bq); @@ -223,29 +223,29 @@ void pa_memblockq_shorten(struct pa_memblockq *bq, size_t length) { } -void pa_memblockq_empty(struct pa_memblockq *bq) { +void pa_memblockq_empty(pa_memblockq *bq) { assert(bq); pa_memblockq_shorten(bq, 0); } -int pa_memblockq_is_readable(struct pa_memblockq *bq) { +int pa_memblockq_is_readable(pa_memblockq *bq) { assert(bq); return bq->current_length && (bq->current_length >= bq->prebuf); } -int pa_memblockq_is_writable(struct pa_memblockq *bq, size_t length) { +int pa_memblockq_is_writable(pa_memblockq *bq, size_t length) { assert(bq); return bq->current_length + length <= bq->tlength; } -uint32_t pa_memblockq_get_length(struct pa_memblockq *bq) { +uint32_t pa_memblockq_get_length(pa_memblockq *bq) { assert(bq); return bq->current_length; } -uint32_t pa_memblockq_missing(struct pa_memblockq *bq) { +uint32_t pa_memblockq_missing(pa_memblockq *bq) { size_t l; assert(bq); @@ -258,8 +258,8 @@ uint32_t pa_memblockq_missing(struct pa_memblockq *bq) { return (l >= bq->minreq) ? l : 0; } -void pa_memblockq_push_align(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta) { - struct pa_memchunk rchunk; +void pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk, size_t delta) { + pa_memchunk rchunk; assert(bq && chunk && bq->base); if (bq->base == 1) { @@ -281,22 +281,22 @@ void pa_memblockq_push_align(struct pa_memblockq* bq, const struct pa_memchunk * } } -uint32_t pa_memblockq_get_minreq(struct pa_memblockq *bq) { +uint32_t pa_memblockq_get_minreq(pa_memblockq *bq) { assert(bq); return bq->minreq; } -void pa_memblockq_prebuf_disable(struct pa_memblockq *bq) { +void pa_memblockq_prebuf_disable(pa_memblockq *bq) { assert(bq); bq->prebuf = 0; } -void pa_memblockq_prebuf_reenable(struct pa_memblockq *bq) { +void pa_memblockq_prebuf_reenable(pa_memblockq *bq) { assert(bq); bq->prebuf = bq->orig_prebuf; } -void pa_memblockq_seek(struct pa_memblockq *bq, size_t length) { +void pa_memblockq_seek(pa_memblockq *bq, size_t length) { assert(bq); if (!length) @@ -322,7 +322,7 @@ void pa_memblockq_seek(struct pa_memblockq *bq, size_t length) { } } -void pa_memblockq_flush(struct pa_memblockq *bq) { +void pa_memblockq_flush(pa_memblockq *bq) { struct memblock_list *l; assert(bq); @@ -337,7 +337,7 @@ void pa_memblockq_flush(struct pa_memblockq *bq) { bq->current_length = 0; } -uint32_t pa_memblockq_get_tlength(struct pa_memblockq *bq) { +uint32_t pa_memblockq_get_tlength(pa_memblockq *bq) { assert(bq); return bq->tlength; } diff --git a/polyp/memblockq.h b/polyp/memblockq.h index 2c762bf4..1695daba 100644 --- a/polyp/memblockq.h +++ b/polyp/memblockq.h @@ -33,7 +33,7 @@ * type doesn't need to copy any data around, it just maintains * references to reference counted memory blocks. */ -struct pa_memblockq; +typedef struct pa_memblockq pa_memblockq; /* Parameters: - maxlength: maximum length of queue. If more data is pushed into the queue, data from the front is dropped @@ -42,63 +42,63 @@ struct pa_memblockq; - prebuf: before passing the first byte out, make sure that enough bytes are in the queue - minreq: pa_memblockq_missing() will only return values greater than this value */ -struct pa_memblockq* pa_memblockq_new(size_t maxlength, +pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t base, size_t prebuf, size_t minreq, - struct pa_memblock_stat *s); -void pa_memblockq_free(struct pa_memblockq*bq); + pa_memblock_stat *s); +void pa_memblockq_free(pa_memblockq*bq); /* Push a new memory chunk into the queue. Optionally specify a value for future cancellation. */ -void pa_memblockq_push(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta); +void pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *chunk, size_t delta); /* Same as pa_memblockq_push(), however chunks are filtered through a mcalign object, and thus aligned to multiples of base */ -void pa_memblockq_push_align(struct pa_memblockq* bq, const struct pa_memchunk *chunk, size_t delta); +void pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk, size_t delta); /* Return a copy of the next memory chunk in the queue. It is not removed from the queue */ -int pa_memblockq_peek(struct pa_memblockq* bq, struct pa_memchunk *chunk); +int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk); /* Drop the specified bytes from the queue, only valid aufter pa_memblockq_peek() */ -void pa_memblockq_drop(struct pa_memblockq *bq, const struct pa_memchunk *chunk, size_t length); +void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length); /* Drop the specified bytes from the queue */ -void pa_memblockq_skip(struct pa_memblockq *bq, size_t length); +void pa_memblockq_skip(pa_memblockq *bq, size_t length); /* Shorten the pa_memblockq to the specified length by dropping data at the end of the queue */ -void pa_memblockq_shorten(struct pa_memblockq *bq, size_t length); +void pa_memblockq_shorten(pa_memblockq *bq, size_t length); /* Empty the pa_memblockq */ -void pa_memblockq_empty(struct pa_memblockq *bq); +void pa_memblockq_empty(pa_memblockq *bq); /* Test if the pa_memblockq is currently readable, that is, more data than base */ -int pa_memblockq_is_readable(struct pa_memblockq *bq); +int pa_memblockq_is_readable(pa_memblockq *bq); /* Test if the pa_memblockq is currently writable for the specified amount of bytes */ -int pa_memblockq_is_writable(struct pa_memblockq *bq, size_t length); +int pa_memblockq_is_writable(pa_memblockq *bq, size_t length); /* Return the length of the queue in bytes */ -uint32_t pa_memblockq_get_length(struct pa_memblockq *bq); +uint32_t pa_memblockq_get_length(pa_memblockq *bq); /* Return how many bytes are missing in queue to the specified fill amount */ -uint32_t pa_memblockq_missing(struct pa_memblockq *bq); +uint32_t pa_memblockq_missing(pa_memblockq *bq); /* Returns the minimal request value */ -uint32_t pa_memblockq_get_minreq(struct pa_memblockq *bq); +uint32_t pa_memblockq_get_minreq(pa_memblockq *bq); /* Force disabling of pre-buf even when the pre-buffer is not yet filled */ -void pa_memblockq_prebuf_disable(struct pa_memblockq *bq); +void pa_memblockq_prebuf_disable(pa_memblockq *bq); /* Reenable pre-buf to the initial level */ -void pa_memblockq_prebuf_reenable(struct pa_memblockq *bq); +void pa_memblockq_prebuf_reenable(pa_memblockq *bq); /* Manipulate the write pointer */ -void pa_memblockq_seek(struct pa_memblockq *bq, size_t delta); +void pa_memblockq_seek(pa_memblockq *bq, size_t delta); /* Flush the queue */ -void pa_memblockq_flush(struct pa_memblockq *bq); +void pa_memblockq_flush(pa_memblockq *bq); /* Get Target length */ -uint32_t pa_memblockq_get_tlength(struct pa_memblockq *bq); +uint32_t pa_memblockq_get_tlength(pa_memblockq *bq); #endif diff --git a/polyp/memchunk.c b/polyp/memchunk.c index d1c923f3..bfd74f9e 100644 --- a/polyp/memchunk.c +++ b/polyp/memchunk.c @@ -31,8 +31,8 @@ #include "memchunk.h" #include "xmalloc.h" -void pa_memchunk_make_writable(struct pa_memchunk *c, struct pa_memblock_stat *s, size_t min) { - struct pa_memblock *n; +void pa_memchunk_make_writable(pa_memchunk *c, pa_memblock_stat *s, size_t min) { + pa_memblock *n; size_t l; assert(c && c->memblock && c->memblock->ref >= 1); @@ -50,7 +50,7 @@ void pa_memchunk_make_writable(struct pa_memchunk *c, struct pa_memblock_stat *s c->index = 0; } -void pa_memchunk_reset(struct pa_memchunk *c) { +void pa_memchunk_reset(pa_memchunk *c) { assert(c); c->memblock = NULL; diff --git a/polyp/memchunk.h b/polyp/memchunk.h index a004c2e8..4eefc8c1 100644 --- a/polyp/memchunk.h +++ b/polyp/memchunk.h @@ -24,22 +24,22 @@ #include "memblock.h" -/* A memchunk is a part of a memblock. In contrast to the memblock, a +/* A memchunk describes a part of a memblock. In contrast to the memblock, a * memchunk is not allocated dynamically or reference counted, instead * it is usually stored on the stack and copied around */ -struct pa_memchunk { - struct pa_memblock *memblock; +typedef struct pa_memchunk { + pa_memblock *memblock; size_t index, length; -}; +} pa_memchunk; /* Make a memchunk writable, i.e. make sure that the caller may have * exclusive access to the memblock and it is not read_only. If needed * the memblock in the structure is replaced by a copy. */ -void pa_memchunk_make_writable(struct pa_memchunk *c, struct pa_memblock_stat *s, size_t min); +void pa_memchunk_make_writable(pa_memchunk *c, pa_memblock_stat *s, size_t min); /* Invalidate a memchunk. This does not free the cotaining memblock, * but sets all members to zero. */ -void pa_memchunk_reset(struct pa_memchunk *c); +void pa_memchunk_reset(pa_memchunk *c); #endif diff --git a/polyp/modargs.c b/polyp/modargs.c index 9437d839..07062946 100644 --- a/polyp/modargs.c +++ b/polyp/modargs.c @@ -38,13 +38,11 @@ #include "xmalloc.h" #include "util.h" -struct pa_modargs; - struct entry { char *key, *value; }; -static int add_key_value(struct pa_hashmap *map, char *key, char *value, const char* const valid_keys[]) { +static int add_key_value(pa_hashmap *map, char *key, char *value, const char* const valid_keys[]) { struct entry *e; assert(map && key && value); @@ -68,8 +66,8 @@ static int add_key_value(struct pa_hashmap *map, char *key, char *value, const c return 0; } -struct pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) { - struct pa_hashmap *map = NULL; +pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) { + pa_hashmap *map = NULL; map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); assert(map); @@ -154,18 +152,18 @@ struct pa_modargs *pa_modargs_new(const char *args, const char* const* valid_key goto fail; } - return (struct pa_modargs*) map; + return (pa_modargs*) map; fail: if (map) - pa_modargs_free((struct pa_modargs*) map); + pa_modargs_free((pa_modargs*) map); return NULL; } -static void free_func(void *p, void*userdata) { +static void free_func(void *p, PA_GCC_UNUSED void*userdata) { struct entry *e = p; assert(e); pa_xfree(e->key); @@ -173,13 +171,13 @@ static void free_func(void *p, void*userdata) { pa_xfree(e); } -void pa_modargs_free(struct pa_modargs*ma) { - struct pa_hashmap *map = (struct pa_hashmap*) ma; +void pa_modargs_free(pa_modargs*ma) { + pa_hashmap *map = (pa_hashmap*) ma; pa_hashmap_free(map, free_func, NULL); } -const char *pa_modargs_get_value(struct pa_modargs *ma, const char *key, const char *def) { - struct pa_hashmap *map = (struct pa_hashmap*) ma; +const char *pa_modargs_get_value(pa_modargs *ma, const char *key, const char *def) { + pa_hashmap *map = (pa_hashmap*) ma; struct entry*e; if (!(e = pa_hashmap_get(map, key))) @@ -188,7 +186,7 @@ const char *pa_modargs_get_value(struct pa_modargs *ma, const char *key, const c return e->value; } -int pa_modargs_get_value_u32(struct pa_modargs *ma, const char *key, uint32_t *value) { +int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value) { const char *v; assert(ma && key && value); @@ -201,7 +199,7 @@ int pa_modargs_get_value_u32(struct pa_modargs *ma, const char *key, uint32_t *v return 0; } -int pa_modargs_get_value_s32(struct pa_modargs *ma, const char *key, int32_t *value) { +int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value) { const char *v; assert(ma && key && value); @@ -214,7 +212,7 @@ int pa_modargs_get_value_s32(struct pa_modargs *ma, const char *key, int32_t *va return 0; } -int pa_modargs_get_value_boolean(struct pa_modargs *ma, const char *key, int *value) { +int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value) { const char *v; int r; assert(ma && key && value); @@ -232,10 +230,10 @@ int pa_modargs_get_value_boolean(struct pa_modargs *ma, const char *key, int *va return 0; } -int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *rss) { +int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) { const char *format; uint32_t channels; - struct pa_sample_spec ss; + pa_sample_spec ss; assert(ma && rss); /* DEBUG_TRAP;*/ diff --git a/polyp/modargs.h b/polyp/modargs.h index 07db6ae5..56605379 100644 --- a/polyp/modargs.h +++ b/polyp/modargs.h @@ -26,24 +26,24 @@ #include "sample.h" #include "core.h" -struct pa_modargs; +typedef struct pa_modargs pa_modargs; /* A generic parser for module arguments */ /* Parse the string args. The NULL-terminated array keys contains all valid arguments. */ -struct pa_modargs *pa_modargs_new(const char *args, const char* const keys[]); -void pa_modargs_free(struct pa_modargs*ma); +pa_modargs *pa_modargs_new(const char *args, const char* const keys[]); +void pa_modargs_free(pa_modargs*ma); /* Return the module argument for the specified name as a string. If * the argument was not specified, return def instead.*/ -const char *pa_modargs_get_value(struct pa_modargs *ma, const char *key, const char *def); +const char *pa_modargs_get_value(pa_modargs *ma, const char *key, const char *def); /* Return a module argument as unsigned 32bit value in *value */ -int pa_modargs_get_value_u32(struct pa_modargs *ma, const char *key, uint32_t *value); -int pa_modargs_get_value_s32(struct pa_modargs *ma, const char *key, int32_t *value); -int pa_modargs_get_value_boolean(struct pa_modargs *ma, const char *key, int *value); +int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value); +int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value); +int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value); /* Return sample spec data from the three arguments "rate", "format" and "channels" */ -int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *ss); +int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *ss); #endif diff --git a/polyp/modinfo.c b/polyp/modinfo.c index a96bb17e..53440612 100644 --- a/polyp/modinfo.c +++ b/polyp/modinfo.c @@ -36,12 +36,12 @@ #define PA_SYMBOL_USAGE "pa__get_usage" #define PA_SYMBOL_VERSION "pa__get_version" -struct pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl) { - struct pa_modinfo *i; +pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl) { + pa_modinfo *i; const char* (*func)(void); assert(dl); - i = pa_xmalloc0(sizeof(struct pa_modinfo)); + i = pa_xmalloc0(sizeof(pa_modinfo)); if ((func = (const char* (*)(void)) lt_dlsym(dl, PA_SYMBOL_AUTHOR))) i->author = pa_xstrdup(func()); @@ -58,9 +58,9 @@ struct pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl) { return i; } -struct pa_modinfo *pa_modinfo_get_by_name(const char *name) { +pa_modinfo *pa_modinfo_get_by_name(const char *name) { lt_dlhandle dl; - struct pa_modinfo *i; + pa_modinfo *i; assert(name); if (!(dl = lt_dlopenext(name))) { @@ -74,7 +74,7 @@ struct pa_modinfo *pa_modinfo_get_by_name(const char *name) { return i; } -void pa_modinfo_free(struct pa_modinfo *i) { +void pa_modinfo_free(pa_modinfo *i) { assert(i); pa_xfree(i->author); pa_xfree(i->description); diff --git a/polyp/modinfo.h b/polyp/modinfo.h index 9da9dc4e..53176147 100644 --- a/polyp/modinfo.h +++ b/polyp/modinfo.h @@ -24,20 +24,20 @@ /* Some functions for reading module meta data from Polypaudio modules */ -struct pa_modinfo { +typedef struct pa_modinfo { char *author; char *description; char *usage; char *version; -}; +} pa_modinfo; /* Read meta data from an libtool handle */ -struct pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl); +pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl); /* Read meta data from a module file */ -struct pa_modinfo *pa_modinfo_get_by_name(const char *name); +pa_modinfo *pa_modinfo_get_by_name(const char *name); /* Free meta data */ -void pa_modinfo_free(struct pa_modinfo *i); +void pa_modinfo_free(pa_modinfo *i); #endif diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index dde5d8b6..14070d63 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -55,13 +55,13 @@ PA_MODULE_USAGE("sink_name= device= format=module, - (u->sink ? pa_idxset_ncontents(u->sink->inputs) : 0) + - (u->sink ? pa_idxset_ncontents(u->sink->monitor_source->outputs) : 0)); + (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0)); } static void xrun_recovery(struct userdata *u) { @@ -99,7 +99,7 @@ static void do_write(struct userdata *u) { update_usage(u); for (;;) { - struct pa_memchunk *memchunk = NULL; + pa_memchunk *memchunk = NULL; snd_pcm_sframes_t frames; if (u->memchunk.memblock) @@ -142,7 +142,7 @@ static void do_write(struct userdata *u) { } } -static void io_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { +static void io_callback(pa_mainloop_api*a, pa_io_event *e, PA_GCC_UNUSED int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { struct userdata *u = userdata; assert(u && a && e); @@ -152,7 +152,7 @@ static void io_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, do_write(u); } -static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { +static pa_usec_t sink_get_latency_cb(pa_sink *s) { pa_usec_t r = 0; struct userdata *u = s->userdata; snd_pcm_sframes_t frames; @@ -175,12 +175,12 @@ static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { return r; } -int pa__init(struct pa_core *c, struct pa_module*m) { - struct pa_modargs *ma = NULL; +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; int ret = -1; struct userdata *u = NULL; const char *dev; - struct pa_sample_spec ss; + pa_sample_spec ss; uint32_t periods, fragsize; snd_pcm_uframes_t period_size; size_t frame_size; @@ -262,7 +262,7 @@ fail: goto finish; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { struct userdata *u; assert(c && m); diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index 5b4076f8..4ad8dd84 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -55,13 +55,13 @@ PA_MODULE_USAGE("source_name= device= format=< struct userdata { snd_pcm_t *pcm_handle; - struct pa_source *source; - struct pa_io_event **io_events; + pa_source *source; + pa_io_event **io_events; unsigned n_io_events; size_t frame_size, fragment_size; - struct pa_memchunk memchunk; - struct pa_module *module; + pa_memchunk memchunk; + pa_module *module; }; static const char* const valid_modargs[] = { @@ -80,7 +80,7 @@ static const char* const valid_modargs[] = { static void update_usage(struct userdata *u) { pa_module_set_used(u->module, - (u->source ? pa_idxset_ncontents(u->source->outputs) : 0)); + (u->source ? pa_idxset_size(u->source->outputs) : 0)); } static void xrun_recovery(struct userdata *u) { @@ -98,7 +98,7 @@ static void do_read(struct userdata *u) { update_usage(u); for (;;) { - struct pa_memchunk post_memchunk; + pa_memchunk post_memchunk; snd_pcm_sframes_t frames; size_t l; @@ -142,7 +142,7 @@ static void do_read(struct userdata *u) { } } -static void io_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { +static void io_callback(pa_mainloop_api*a, pa_io_event *e, PA_GCC_UNUSED int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { struct userdata *u = userdata; assert(u && a && e); @@ -152,7 +152,7 @@ static void io_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, do_read(u); } -static pa_usec_t source_get_latency_cb(struct pa_source *s) { +static pa_usec_t source_get_latency_cb(pa_source *s) { struct userdata *u = s->userdata; snd_pcm_sframes_t frames; assert(s && u && u->source); @@ -166,12 +166,12 @@ static pa_usec_t source_get_latency_cb(struct pa_source *s) { return pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec); } -int pa__init(struct pa_core *c, struct pa_module*m) { - struct pa_modargs *ma = NULL; +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; int ret = -1; struct userdata *u = NULL; const char *dev; - struct pa_sample_spec ss; + pa_sample_spec ss; unsigned periods, fragsize; snd_pcm_uframes_t period_size; size_t frame_size; @@ -250,7 +250,7 @@ fail: goto finish; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { struct userdata *u; assert(c && m); diff --git a/polyp/module-cli.c b/polyp/module-cli.c index 7d278f90..db0e895c 100644 --- a/polyp/module-cli.c +++ b/polyp/module-cli.c @@ -39,15 +39,15 @@ PA_MODULE_DESCRIPTION("Command line interface") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("No arguments") -static void eof_cb(struct pa_cli*c, void *userdata) { - struct pa_module *m = userdata; +static void eof_cb(pa_cli*c, void *userdata) { + pa_module *m = userdata; assert(c && m); pa_module_unload_request(m); } -int pa__init(struct pa_core *c, struct pa_module*m) { - struct pa_iochannel *io; +int pa__init(pa_core *c, pa_module*m) { + pa_iochannel *io; assert(c && m); if (c->running_as_daemon) { @@ -77,7 +77,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { return 0; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { assert(c && m); if (c->running_as_daemon == 0) { diff --git a/polyp/module-combine.c b/polyp/module-combine.c index 7283c554..cee0a5dc 100644 --- a/polyp/module-combine.c +++ b/polyp/module-combine.c @@ -62,20 +62,20 @@ static const char* const valid_modargs[] = { struct output { struct userdata *userdata; - struct pa_sink_input *sink_input; + pa_sink_input *sink_input; size_t counter; - struct pa_memblockq *memblockq; + pa_memblockq *memblockq; pa_usec_t total_latency; PA_LLIST_FIELDS(struct output); }; struct userdata { - struct pa_module *module; - struct pa_core *core; - struct pa_sink *sink; + pa_module *module; + pa_core *core; + pa_sink *sink; unsigned n_outputs; struct output *master; - struct pa_time_event *time_event; + pa_time_event *time_event; uint32_t adjust_time; PA_LLIST_HEAD(struct output, outputs); @@ -86,8 +86,8 @@ static void clear_up(struct userdata *u); static void update_usage(struct userdata *u) { pa_module_set_used(u->module, - (u->sink ? pa_idxset_ncontents(u->sink->inputs) : 0) + - (u->sink ? pa_idxset_ncontents(u->sink->monitor_source->outputs) : 0)); + (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0)); } @@ -135,7 +135,7 @@ static void adjust_rates(struct userdata *u) { } static void request_memblock(struct userdata *u) { - struct pa_memchunk chunk; + pa_memchunk chunk; struct output *o; assert(u && u->sink); @@ -150,7 +150,7 @@ static void request_memblock(struct userdata *u) { pa_memblock_unref(chunk.memblock); } -static void time_callback(struct pa_mainloop_api*a, struct pa_time_event* e, const struct timeval *tv, void *userdata) { +static void time_callback(pa_mainloop_api*a, pa_time_event* e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { struct userdata *u = userdata; struct timeval n; assert(u && a && u->time_event == e); @@ -162,7 +162,7 @@ static void time_callback(struct pa_mainloop_api*a, struct pa_time_event* e, con u->sink->core->mainloop->time_restart(e, &n); } -static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk) { +static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { struct output *o = i->userdata; assert(i && o && o->sink_input && chunk); @@ -175,7 +175,7 @@ static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk return pa_memblockq_peek(o->memblockq, chunk); } -static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length) { +static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { struct output *o = i->userdata; assert(i && o && o->sink_input && chunk && length); @@ -183,28 +183,28 @@ static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk o->counter += length; } -static void sink_input_kill_cb(struct pa_sink_input *i) { +static void sink_input_kill_cb(pa_sink_input *i) { struct output *o = i->userdata; assert(i && o && o->sink_input); pa_module_unload_request(o->userdata->module); clear_up(o->userdata); } -static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i) { +static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { struct output *o = i->userdata; assert(i && o && o->sink_input); return pa_bytes_to_usec(pa_memblockq_get_length(o->memblockq), &i->sample_spec); } -static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { +static pa_usec_t sink_get_latency_cb(pa_sink *s) { struct userdata *u = s->userdata; assert(s && u && u->sink && u->master); return pa_sink_input_get_latency(u->master->sink_input); } -static struct output *output_new(struct userdata *u, struct pa_sink *sink, int resample_method) { +static struct output *output_new(struct userdata *u, pa_sink *sink, int resample_method) { struct output *o = NULL; char t[256]; assert(u && sink && u->sink); @@ -278,11 +278,11 @@ static void clear_up(struct userdata *u) { } } -int pa__init(struct pa_core *c, struct pa_module*m) { +int pa__init(pa_core *c, pa_module*m) { struct userdata *u; - struct pa_modargs *ma = NULL; + pa_modargs *ma = NULL; const char *master_name, *slaves, *rm; - struct pa_sink *master_sink; + pa_sink *master_sink; char *n = NULL; const char*split_state; struct timeval tv; @@ -344,7 +344,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { split_state = NULL; while ((n = pa_split(slaves, ",", &split_state))) { - struct pa_sink *slave_sink; + pa_sink *slave_sink; if (!(slave_sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) { pa_log(__FILE__": invalid slave sink '%s'\n", n); @@ -381,7 +381,7 @@ fail: return -1; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { struct userdata *u; assert(c && m); diff --git a/polyp/module-defs.h.m4 b/polyp/module-defs.h.m4 index 2b9cdf9e..2eff25a7 100644 --- a/polyp/module-defs.h.m4 +++ b/polyp/module-defs.h.m4 @@ -21,4 +21,9 @@ gen_symbol(pa__get_version) int pa__init(struct pa_core *c, struct pa_module*m); void pa__done(struct pa_core *c, struct pa_module*m); +const char* pa__get_author(void); +const char* pa__get_description(void); +const char* pa__get_usage(void); +const char* pa__get_version(void); + #endif diff --git a/polyp/module-esound-compat-spawnfd.c b/polyp/module-esound-compat-spawnfd.c index de2cf4e6..5051e4d0 100644 --- a/polyp/module-esound-compat-spawnfd.c +++ b/polyp/module-esound-compat-spawnfd.c @@ -44,8 +44,8 @@ static const char* const valid_modargs[] = { NULL, }; -int pa__init(struct pa_core *c, struct pa_module*m) { - struct pa_modargs *ma = NULL; +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; int ret = -1, fd = -1; char x = 1; assert(c && m); @@ -73,7 +73,7 @@ finish: return ret; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { assert(c && m); } diff --git a/polyp/module-esound-compat-spawnpid.c b/polyp/module-esound-compat-spawnpid.c index 6f945728..aa8b0f82 100644 --- a/polyp/module-esound-compat-spawnpid.c +++ b/polyp/module-esound-compat-spawnpid.c @@ -44,8 +44,8 @@ static const char* const valid_modargs[] = { NULL, }; -int pa__init(struct pa_core *c, struct pa_module*m) { - struct pa_modargs *ma = NULL; +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; int ret = -1; uint32_t pid = 0; assert(c && m); @@ -71,7 +71,7 @@ finish: return ret; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { assert(c && m); } diff --git a/polyp/module-esound-sink.c b/polyp/module-esound-sink.c index 19106506..ac211a31 100644 --- a/polyp/module-esound-sink.c +++ b/polyp/module-esound-sink.c @@ -55,16 +55,16 @@ PA_MODULE_USAGE("sink_name= server=
    cookie=write_index = u->write_length = 0; } } else if (u->state == STATE_RUNNING) { - pa_module_set_used(u->module, pa_idxset_ncontents(u->sink->inputs) + pa_idxset_ncontents(u->sink->monitor_source->outputs)); + pa_module_set_used(u->module, pa_idxset_size(u->sink->inputs) + pa_idxset_size(u->sink->monitor_source->outputs)); if (!u->memchunk.length) if (pa_sink_render(u->sink, 8192, &u->memchunk) < 0) @@ -269,7 +269,7 @@ static void do_work(struct userdata *u) { cancel(u); } -static void notify_cb(struct pa_sink*s) { +static void notify_cb(pa_sink*s) { struct userdata *u = s->userdata; assert(s && u); @@ -277,7 +277,7 @@ static void notify_cb(struct pa_sink*s) { u->core->mainloop->defer_enable(u->defer_event, 1); } -static pa_usec_t get_latency_cb(struct pa_sink *s) { +static pa_usec_t get_latency_cb(pa_sink *s) { struct userdata *u = s->userdata; assert(s && u); @@ -286,19 +286,19 @@ static pa_usec_t get_latency_cb(struct pa_sink *s) { (u->memchunk.memblock ? pa_bytes_to_usec(u->memchunk.length, &s->sample_spec) : 0); } -static void defer_callback(struct pa_mainloop_api *m, struct pa_defer_event*e, void *userdata) { +static void defer_callback(PA_GCC_UNUSED pa_mainloop_api *m, PA_GCC_UNUSED pa_defer_event*e, void *userdata) { struct userdata *u = userdata; assert(u); do_work(u); } -static void io_callback(struct pa_iochannel *io, void*userdata) { +static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { struct userdata *u = userdata; assert(u); do_work(u); } -static void on_connection(struct pa_socket_client *c, struct pa_iochannel*io, void *userdata) { +static void on_connection(PA_GCC_UNUSED pa_socket_client *c, pa_iochannel*io, void *userdata) { struct userdata *u = userdata; pa_socket_client_unref(u->client); @@ -314,11 +314,11 @@ static void on_connection(struct pa_socket_client *c, struct pa_iochannel*io, vo pa_iochannel_set_callback(u->io, io_callback, u); } -int pa__init(struct pa_core *c, struct pa_module*m) { +int pa__init(pa_core *c, pa_module*m) { struct userdata *u = NULL; const char *p; - struct pa_sample_spec ss; - struct pa_modargs *ma = NULL; + pa_sample_spec ss; + pa_modargs *ma = NULL; assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -402,7 +402,7 @@ fail: return -1; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { struct userdata *u; assert(c && m); diff --git a/polyp/module-lirc.c b/polyp/module-lirc.c index 4cfc09de..eb71c47f 100644 --- a/polyp/module-lirc.c +++ b/polyp/module-lirc.c @@ -52,16 +52,16 @@ static const char* const valid_modargs[] = { struct userdata { int lirc_fd; - struct pa_io_event *io; + pa_io_event *io; struct lirc_config *config; char *sink_name; - struct pa_module *module; + pa_module *module; float mute_toggle_save; }; static int lirc_in_use = 0; -static void io_callback(struct pa_mainloop_api *io, struct pa_io_event *e, int fd, enum pa_io_event_flags events, void*userdata) { +static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags events, void*userdata) { struct userdata *u = userdata; char *name = NULL, *code = NULL; assert(io); @@ -104,7 +104,7 @@ static void io_callback(struct pa_mainloop_api *io, struct pa_io_event *e, int f if (volchange == INVALID) pa_log_warn(__FILE__": recieved unknown IR code '%s'\n", name); else { - struct pa_sink *s; + pa_sink *s; if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) pa_log(__FILE__": failed to get sink '%s'\n", u->sink_name); @@ -147,8 +147,8 @@ fail: free(code); } -int pa__init(struct pa_core *c, struct pa_module*m) { - struct pa_modargs *ma = NULL; +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; struct userdata *u; assert(c && m); @@ -197,7 +197,7 @@ fail: return -1; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { struct userdata *u; assert(c); assert(m); diff --git a/polyp/module-match.c b/polyp/module-match.c index 3599a830..e48d55ca 100644 --- a/polyp/module-match.c +++ b/polyp/module-match.c @@ -68,7 +68,7 @@ struct rule { struct userdata { struct rule *rules; - struct pa_subscription *subscription; + pa_subscription *subscription; }; static int load_rules(struct userdata *u, const char *filename) { @@ -154,16 +154,16 @@ finish: return ret; } -static void callback(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index, void *userdata) { +static void callback(pa_core *c, pa_subscription_event_type t, uint32_t idx, void *userdata) { struct userdata *u = userdata; - struct pa_sink_input *si; + pa_sink_input *si; struct rule *r; assert(c && u); if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW)) return; - if (!(si = pa_idxset_get_by_index(c->sink_inputs, index))) + if (!(si = pa_idxset_get_by_index(c->sink_inputs, idx))) return; if (!si->name) @@ -177,8 +177,8 @@ static void callback(struct pa_core *c, enum pa_subscription_event_type t, uint3 } } -int pa__init(struct pa_core *c, struct pa_module*m) { - struct pa_modargs *ma = NULL; +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; struct userdata *u; assert(c && m); @@ -208,7 +208,7 @@ fail: return -1; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { struct userdata* u; struct rule *r, *n; assert(c && m); diff --git a/polyp/module-mmkbd-evdev.c b/polyp/module-mmkbd-evdev.c index 5368af50..5eb55e35 100644 --- a/polyp/module-mmkbd-evdev.c +++ b/polyp/module-mmkbd-evdev.c @@ -68,13 +68,13 @@ static const char* const valid_modargs[] = { struct userdata { int fd; - struct pa_io_event *io; + pa_io_event *io; char *sink_name; - struct pa_module *module; + pa_module *module; float mute_toggle_save; }; -static void io_callback(struct pa_mainloop_api *io, struct pa_io_event *e, int fd, enum pa_io_event_flags events, void*userdata) { +static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags events, void*userdata) { struct userdata *u = userdata; assert(io); assert(u); @@ -85,26 +85,26 @@ static void io_callback(struct pa_mainloop_api *io, struct pa_io_event *e, int f } if (events & PA_IO_EVENT_INPUT) { - struct input_event e; + struct input_event ev; - if (pa_loop_read(u->fd, &e, sizeof(e)) <= 0) { + if (pa_loop_read(u->fd, &ev, sizeof(ev)) <= 0) { pa_log(__FILE__": failed to read from event device: %s\n", strerror(errno)); goto fail; } - if (e.type == EV_KEY && (e.value == 1 || e.value == 2)) { + if (ev.type == EV_KEY && (ev.value == 1 || ev.value == 2)) { enum { INVALID, UP, DOWN, MUTE_TOGGLE } volchange = INVALID; - pa_log_debug(__FILE__": key code=%u, value=%u\n", e.code, e.value); + pa_log_debug(__FILE__": key code=%u, value=%u\n", ev.code, ev.value); - switch (e.code) { + switch (ev.code) { case KEY_VOLUMEDOWN: volchange = DOWN; break; case KEY_VOLUMEUP: volchange = UP; break; case KEY_MUTE: volchange = MUTE_TOGGLE; break; } if (volchange != INVALID) { - struct pa_sink *s; + pa_sink *s; if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) pa_log(__FILE__": failed to get sink '%s'\n", u->sink_name); @@ -143,8 +143,8 @@ fail: #define test_bit(bit, array) (array[bit/8] & (1<<(bit%8))) -int pa__init(struct pa_core *c, struct pa_module*m) { - struct pa_modargs *ma = NULL; +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; struct userdata *u; int version; struct _input_id input_id; @@ -217,7 +217,7 @@ fail: return -1; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { struct userdata *u; assert(c); assert(m); diff --git a/polyp/module-native-protocol-fd.c b/polyp/module-native-protocol-fd.c index 11f6e572..7f09ff91 100644 --- a/polyp/module-native-protocol-fd.c +++ b/polyp/module-native-protocol-fd.c @@ -45,9 +45,9 @@ static const char* const valid_modargs[] = { NULL, }; -int pa__init(struct pa_core *c, struct pa_module*m) { - struct pa_iochannel *io; - struct pa_modargs *ma; +int pa__init(pa_core *c, pa_module*m) { + pa_iochannel *io; + pa_modargs *ma; int fd, r = -1; assert(c && m); @@ -77,7 +77,7 @@ finish: return r; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { assert(c && m); pa_protocol_native_free(m->userdata); diff --git a/polyp/module-null-sink.c b/polyp/module-null-sink.c index 6c7a44f2..b26ea50b 100644 --- a/polyp/module-null-sink.c +++ b/polyp/module-null-sink.c @@ -52,10 +52,10 @@ PA_MODULE_USAGE("format= channels= rate=time_restart(e, &ntv); } -int pa__init(struct pa_core *c, struct pa_module*m) { +int pa__init(pa_core *c, pa_module*m) { struct userdata *u = NULL; - struct pa_sample_spec ss; - struct pa_modargs *ma = NULL; + pa_sample_spec ss; + pa_modargs *ma = NULL; struct timeval tv; assert(c && m); @@ -135,7 +135,7 @@ fail: return -1; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { struct userdata *u; assert(c && m); diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index 3c5c0ad8..ac510f96 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -56,10 +56,10 @@ PA_MODULE_USAGE("sink_name= source_name= #define PA_TYPEID_OSS_MMAP PA_TYPEID_MAKE('O', 'S', 'S', 'M') struct userdata { - struct pa_sink *sink; - struct pa_source *source; - struct pa_core *core; - struct pa_sample_spec sample_spec; + pa_sink *sink; + pa_source *source; + pa_core *core; + pa_sample_spec sample_spec; size_t in_fragment_size, out_fragment_size, in_fragments, out_fragments, out_fill; @@ -68,11 +68,11 @@ struct userdata { void *in_mmap, *out_mmap; size_t in_mmap_length, out_mmap_length; - struct pa_io_event *io_event; + pa_io_event *io_event; - struct pa_memblock **in_memblocks, **out_memblocks; + pa_memblock **in_memblocks, **out_memblocks; unsigned out_current, in_current; - struct pa_module *module; + pa_module *module; }; static const char* const valid_modargs[] = { @@ -95,16 +95,16 @@ static const char* const valid_modargs[] = { static void update_usage(struct userdata *u) { pa_module_set_used(u->module, - (u->sink ? pa_idxset_ncontents(u->sink->inputs) : 0) + - (u->sink ? pa_idxset_ncontents(u->sink->monitor_source->outputs) : 0) + - (u->source ? pa_idxset_ncontents(u->source->outputs) : 0)); + (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0) + + (u->source ? pa_idxset_size(u->source->outputs) : 0)); } static void out_fill_memblocks(struct userdata *u, unsigned n) { assert(u && u->out_memblocks); while (n > 0) { - struct pa_memchunk chunk; + pa_memchunk chunk; if (u->out_memblocks[u->out_current]) pa_memblock_unref_fixed(u->out_memblocks[u->out_current]); @@ -147,7 +147,7 @@ static void in_post_memblocks(struct userdata *u, unsigned n) { assert(u && u->in_memblocks); while (n > 0) { - struct pa_memchunk chunk; + pa_memchunk chunk; if (!u->in_memblocks[u->in_current]) { chunk.memblock = u->in_memblocks[u->in_current] = pa_memblock_new_fixed((uint8_t*) u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size, 1, u->core->memblock_stat); @@ -204,7 +204,7 @@ static void do_read(struct userdata *u) { in_clear_memblocks(u, u->in_fragments/2); } -static void io_callback(struct pa_mainloop_api *m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { +static void io_callback(pa_mainloop_api *m, pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags f, void *userdata) { struct userdata *u = userdata; assert (u && u->core->mainloop == m && u->io_event == e); @@ -214,7 +214,7 @@ static void io_callback(struct pa_mainloop_api *m, struct pa_io_event *e, int fd do_write(u); } -static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { +static pa_usec_t sink_get_latency_cb(pa_sink *s) { struct userdata *u = s->userdata; assert(s && u); @@ -222,7 +222,7 @@ static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { return pa_bytes_to_usec(u->out_fill, &s->sample_spec); } -int pa__init(struct pa_core *c, struct pa_module*m) { +int pa__init(pa_core *c, pa_module*m) { struct audio_buf_info info; struct userdata *u = NULL; const char *p; @@ -230,7 +230,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { int mode, caps; int enable_bits = 0, zero = 0; int playback = 1, record = 1; - struct pa_modargs *ma = NULL; + pa_modargs *ma = NULL; assert(c && m); m->userdata = u = pa_xmalloc0(sizeof(struct userdata)); @@ -310,7 +310,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { pa_source_set_owner(u->source, m); u->source->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'", p); - u->in_memblocks = pa_xmalloc0(sizeof(struct pa_memblock *)*u->in_fragments); + u->in_memblocks = pa_xmalloc0(sizeof(pa_memblock *)*u->in_fragments); enable_bits |= PCM_ENABLE_INPUT; } @@ -378,7 +378,7 @@ fail: return -1; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { struct userdata *u; assert(c && m); diff --git a/polyp/module-oss.c b/polyp/module-oss.c index 02acc6f4..7c331893 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -55,18 +55,18 @@ PA_MODULE_USAGE("sink_name= source_name= #define PA_TYPEID_OSS PA_TYPEID_MAKE('O', 'S', 'S', '_') struct userdata { - struct pa_sink *sink; - struct pa_source *source; - struct pa_iochannel *io; - struct pa_core *core; + pa_sink *sink; + pa_source *source; + pa_iochannel *io; + pa_core *core; - struct pa_memchunk memchunk, silence; + pa_memchunk memchunk, silence; uint32_t in_fragment_size, out_fragment_size, sample_size; int use_getospace, use_getispace; int fd; - struct pa_module *module; + pa_module *module; }; static const char* const valid_modargs[] = { @@ -89,13 +89,13 @@ static const char* const valid_modargs[] = { static void update_usage(struct userdata *u) { pa_module_set_used(u->module, - (u->sink ? pa_idxset_ncontents(u->sink->inputs) : 0) + - (u->sink ? pa_idxset_ncontents(u->sink->monitor_source->outputs) : 0) + - (u->source ? pa_idxset_ncontents(u->source->outputs) : 0)); + (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0) + + (u->source ? pa_idxset_size(u->source->outputs) : 0)); } static void do_write(struct userdata *u) { - struct pa_memchunk *memchunk; + pa_memchunk *memchunk; ssize_t r; size_t l; int loop = 0; @@ -155,7 +155,7 @@ static void do_write(struct userdata *u) { } static void do_read(struct userdata *u) { - struct pa_memchunk memchunk; + pa_memchunk memchunk; ssize_t r; size_t l; int loop = 0; @@ -202,14 +202,14 @@ static void do_read(struct userdata *u) { } while (loop && l > 0); } -static void io_callback(struct pa_iochannel *io, void*userdata) { +static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { struct userdata *u = userdata; assert(u); do_write(u); do_read(u); } -static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { +static pa_usec_t sink_get_latency_cb(pa_sink *s) { pa_usec_t r = 0; int arg; struct userdata *u = s->userdata; @@ -229,7 +229,7 @@ static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { return r; } -static pa_usec_t source_get_latency_cb(struct pa_source *s) { +static pa_usec_t source_get_latency_cb(pa_source *s) { struct userdata *u = s->userdata; audio_buf_info info; assert(s && u && u->source); @@ -248,7 +248,7 @@ static pa_usec_t source_get_latency_cb(struct pa_source *s) { return pa_bytes_to_usec(info.bytes, &s->sample_spec); } -int pa__init(struct pa_core *c, struct pa_module*m) { +int pa__init(pa_core *c, pa_module*m) { struct audio_buf_info info; struct userdata *u = NULL; const char *p; @@ -256,8 +256,8 @@ int pa__init(struct pa_core *c, struct pa_module*m) { int nfrags, frag_size, in_frag_size, out_frag_size; int mode; int record = 1, playback = 1; - struct pa_sample_spec ss; - struct pa_modargs *ma = NULL; + pa_sample_spec ss; + pa_modargs *ma = NULL; assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -380,7 +380,7 @@ fail: return -1; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { struct userdata *u; assert(c && m); diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c index b6d8dc2e..537cb86b 100644 --- a/polyp/module-pipe-sink.c +++ b/polyp/module-pipe-sink.c @@ -53,16 +53,16 @@ PA_MODULE_USAGE("sink_name= file= format=io)) return; - pa_module_set_used(u->module, pa_idxset_ncontents(u->sink->inputs) + pa_idxset_ncontents(u->sink->monitor_source->outputs)); + pa_module_set_used(u->module, pa_idxset_size(u->sink->inputs) + pa_idxset_size(u->sink->monitor_source->outputs)); if (!u->memchunk.length) if (pa_sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0) @@ -105,7 +105,7 @@ static void do_write(struct userdata *u) { } } -static void notify_cb(struct pa_sink*s) { +static void notify_cb(pa_sink*s) { struct userdata *u = s->userdata; assert(s && u); @@ -113,32 +113,32 @@ static void notify_cb(struct pa_sink*s) { u->core->mainloop->defer_enable(u->defer_event, 1); } -static pa_usec_t get_latency_cb(struct pa_sink *s) { +static pa_usec_t get_latency_cb(pa_sink *s) { struct userdata *u = s->userdata; assert(s && u); return u->memchunk.memblock ? pa_bytes_to_usec(u->memchunk.length, &s->sample_spec) : 0; } -static void defer_callback(struct pa_mainloop_api *m, struct pa_defer_event*e, void *userdata) { +static void defer_callback(PA_GCC_UNUSED pa_mainloop_api *m, PA_GCC_UNUSED pa_defer_event*e, void *userdata) { struct userdata *u = userdata; assert(u); do_write(u); } -static void io_callback(struct pa_iochannel *io, void*userdata) { +static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { struct userdata *u = userdata; assert(u); do_write(u); } -int pa__init(struct pa_core *c, struct pa_module*m) { +int pa__init(pa_core *c, pa_module*m) { struct userdata *u = NULL; struct stat st; const char *p; int fd = -1; - struct pa_sample_spec ss; - struct pa_modargs *ma = NULL; + pa_sample_spec ss; + pa_modargs *ma = NULL; assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -215,7 +215,7 @@ fail: return -1; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { struct userdata *u; assert(c && m); diff --git a/polyp/module-pipe-source.c b/polyp/module-pipe-source.c index 5a397162..31653627 100644 --- a/polyp/module-pipe-source.c +++ b/polyp/module-pipe-source.c @@ -53,14 +53,14 @@ PA_MODULE_USAGE("source_name= file= forma #define PA_TYPEID_PIPE PA_TYPEID_MAKE('P', 'I', 'P', 'E') struct userdata { - struct pa_core *core; + pa_core *core; char *filename; - struct pa_source *source; - struct pa_iochannel *io; - struct pa_module *module; - struct pa_memchunk chunk; + pa_source *source; + pa_iochannel *io; + pa_module *module; + pa_memchunk chunk; }; static const char* const valid_modargs[] = { @@ -74,13 +74,13 @@ static const char* const valid_modargs[] = { static void do_read(struct userdata *u) { ssize_t r; - struct pa_memchunk chunk; + pa_memchunk chunk; assert(u); if (!pa_iochannel_is_readable(u->io)) return; - pa_module_set_used(u->module, pa_idxset_ncontents(u->source->outputs)); + pa_module_set_used(u->module, pa_idxset_size(u->source->outputs)); if (!u->chunk.memblock) { u->chunk.memblock = pa_memblock_new(1024, u->core->memblock_stat); @@ -104,19 +104,19 @@ static void do_read(struct userdata *u) { } } -static void io_callback(struct pa_iochannel *io, void*userdata) { +static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { struct userdata *u = userdata; assert(u); do_read(u); } -int pa__init(struct pa_core *c, struct pa_module*m) { +int pa__init(pa_core *c, pa_module*m) { struct userdata *u = NULL; struct stat st; const char *p; int fd = -1; - struct pa_sample_spec ss; - struct pa_modargs *ma = NULL; + pa_sample_spec ss; + pa_modargs *ma = NULL; assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -189,7 +189,7 @@ fail: return -1; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { struct userdata *u; assert(c && m); diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index 141eadd3..3cf3d9d4 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -166,8 +166,8 @@ static const char* const valid_modargs[] = { NULL }; -static struct pa_socket_server *create_socket_server(struct pa_core *c, struct pa_modargs *ma) { - struct pa_socket_server *s; +static pa_socket_server *create_socket_server(pa_core *c, pa_modargs *ma) { + pa_socket_server *s; #if defined(USE_TCP_SOCKETS) || defined(USE_TCP6_SOCKETS) int loopback = 1; uint32_t port = IPV4_PORT; @@ -183,7 +183,7 @@ static struct pa_socket_server *create_socket_server(struct pa_core *c, struct p } #ifdef USE_TCP6_SOCKETS - if (!(s = pa_socket_server_new_ipv6(c->mainloop, loopback ? (uint8_t*) &in6addr_loopback : (uint8_t*) &in6addr_any, port))) + if (!(s = pa_socket_server_new_ipv6(c->mainloop, loopback ? (const uint8_t*) &in6addr_loopback : (const uint8_t*) &in6addr_any, port))) return NULL; #else if (!(s = pa_socket_server_new_ipv4(c->mainloop, loopback ? INADDR_LOOPBACK : INADDR_ANY, port, TCPWRAP_SERVICE))) @@ -220,9 +220,9 @@ static struct pa_socket_server *create_socket_server(struct pa_core *c, struct p return s; } -int pa__init(struct pa_core *c, struct pa_module*m) { - struct pa_socket_server *s; - struct pa_modargs *ma = NULL; +int pa__init(pa_core *c, pa_module*m) { + pa_socket_server *s; + pa_modargs *ma = NULL; int ret = -1; assert(c && m); @@ -248,7 +248,7 @@ finish: return ret; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { assert(c && m); #if defined(USE_PROTOCOL_ESOUND) diff --git a/polyp/module-sine.c b/polyp/module-sine.c index d8f7e4ef..c531386a 100644 --- a/polyp/module-sine.c +++ b/polyp/module-sine.c @@ -43,10 +43,10 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define PA_TYPEID_SINE PA_TYPEID_MAKE('S', 'I', 'N', 'E') struct userdata { - struct pa_core *core; - struct pa_module *module; - struct pa_sink_input *sink_input; - struct pa_memblock *memblock; + pa_core *core; + pa_module *module; + pa_sink_input *sink_input; + pa_memblock *memblock; size_t peek_index; }; @@ -56,7 +56,7 @@ static const char* const valid_modargs[] = { NULL, }; -static int sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { +static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { struct userdata *u; assert(i && chunk && i->userdata); u = i->userdata; @@ -67,7 +67,7 @@ static int sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { return 0; } -static void sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length) { +static void sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { struct userdata *u; assert(i && chunk && length && i->userdata); u = i->userdata; @@ -80,7 +80,7 @@ static void sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk *c u->peek_index = 0; } -static void sink_input_kill(struct pa_sink_input *i) { +static void sink_input_kill(pa_sink_input *i) { struct userdata *u; assert(i && i->userdata); u = i->userdata; @@ -101,12 +101,12 @@ static void calc_sine(float *f, size_t l, float freq) { f[i] = (float) sin((double) i/l*M_PI*2*freq)/2; } -int pa__init(struct pa_core *c, struct pa_module*m) { - struct pa_modargs *ma = NULL; +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; struct userdata *u; - struct pa_sink *sink; + pa_sink *sink; const char *sink_name; - struct pa_sample_spec ss; + pa_sample_spec ss; uint32_t frequency; char t[256]; @@ -164,7 +164,7 @@ fail: return -1; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { struct userdata *u = m->userdata; assert(c && m); diff --git a/polyp/module-solaris.c b/polyp/module-solaris.c index 3eb66462..c8ad7cf1 100644 --- a/polyp/module-solaris.c +++ b/polyp/module-solaris.c @@ -58,18 +58,18 @@ PA_MODULE_USAGE("sink_name= source_name= #define PA_TYPEID_SOLARIS PA_TYPEID_MAKE('S', 'L', 'R', 'S') struct userdata { - struct pa_sink *sink; - struct pa_source *source; - struct pa_iochannel *io; - struct pa_core *core; + pa_sink *sink; + pa_source *source; + pa_iochannel *io; + pa_core *core; - struct pa_memchunk memchunk, silence; + pa_memchunk memchunk, silence; uint32_t sample_size; unsigned int written_bytes, read_bytes; int fd; - struct pa_module *module; + pa_module *module; }; static const char* const valid_modargs[] = { @@ -93,13 +93,13 @@ static const char* const valid_modargs[] = { static void update_usage(struct userdata *u) { pa_module_set_used(u->module, - (u->sink ? pa_idxset_ncontents(u->sink->inputs) : 0) + - (u->sink ? pa_idxset_ncontents(u->sink->monitor_source->outputs) : 0) + - (u->source ? pa_idxset_ncontents(u->source->outputs) : 0)); + (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0) + + (u->source ? pa_idxset_size(u->source->outputs) : 0)); } static void do_write(struct userdata *u) { - struct pa_memchunk *memchunk; + pa_memchunk *memchunk; ssize_t r; assert(u); @@ -140,7 +140,7 @@ static void do_write(struct userdata *u) { } static void do_read(struct userdata *u) { - struct pa_memchunk memchunk; + pa_memchunk memchunk; int err, l; ssize_t r; assert(u); @@ -172,14 +172,14 @@ static void do_read(struct userdata *u) { u->read_bytes += r; } -static void io_callback(struct pa_iochannel *io, void*userdata) { +static void io_callback(pa_iochannel *io, void*userdata) { struct userdata *u = userdata; assert(u); do_write(u); do_read(u); } -static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { +static pa_usec_t sink_get_latency_cb(pa_sink *s) { pa_usec_t r = 0; audio_info_t info; int err; @@ -198,7 +198,7 @@ static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { return r; } -static pa_usec_t source_get_latency_cb(struct pa_source *s) { +static pa_usec_t source_get_latency_cb(pa_source *s) { pa_usec_t r = 0; struct userdata *u = s->userdata; audio_info_t info; @@ -214,7 +214,7 @@ static pa_usec_t source_get_latency_cb(struct pa_source *s) { return r; } -static int pa_solaris_auto_format(int fd, int mode, struct pa_sample_spec *ss) { +static int pa_solaris_auto_format(int fd, int mode, pa_sample_spec *ss) { audio_info_t info; AUDIO_INITINFO(&info); @@ -298,15 +298,15 @@ static int pa_solaris_set_buffer(int fd, int buffer_size) { return 0; } -int pa__init(struct pa_core *c, struct pa_module*m) { +int pa__init(pa_core *c, pa_module*m) { struct userdata *u = NULL; const char *p; int fd = -1; int buffer_size; int mode; int record = 1, playback = 1; - struct pa_sample_spec ss; - struct pa_modargs *ma = NULL; + pa_sample_spec ss; + pa_modargs *ma = NULL; assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -409,7 +409,7 @@ fail: return -1; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { struct userdata *u; assert(c && m); diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c index c6a35ca6..e0eab6c2 100644 --- a/polyp/module-tunnel.c +++ b/polyp/module-tunnel.c @@ -90,37 +90,37 @@ static const char* const valid_modargs[] = { NULL, }; -static void command_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); #ifdef TUNNEL_SINK -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); #endif -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { +static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { #ifdef TUNNEL_SINK - [PA_COMMAND_REQUEST] = { command_request }, + [PA_COMMAND_REQUEST] = command_request, #endif - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { command_stream_killed }, + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = command_stream_killed, + [PA_COMMAND_RECORD_STREAM_KILLED] = command_stream_killed }; struct userdata { - struct pa_socket_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; + pa_socket_client *client; + pa_pstream *pstream; + pa_pdispatch *pdispatch; char *server_name; #ifdef TUNNEL_SINK char *sink_name; - struct pa_sink *sink; + pa_sink *sink; uint32_t requested_bytes; #else char *source_name; - struct pa_source *source; + pa_source *source; #endif - struct pa_module *module; - struct pa_core *core; + pa_module *module; + pa_core *core; uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; @@ -130,7 +130,7 @@ struct userdata { pa_usec_t host_latency; - struct pa_time_event *time_event; + pa_time_event *time_event; int auth_cookie_in_property; }; @@ -180,7 +180,7 @@ static void die(struct userdata *u) { pa_module_unload_request(u->module); } -static void command_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_stream_killed(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; assert(pd && t && u && u->pdispatch == pd); @@ -190,7 +190,7 @@ static void command_stream_killed(struct pa_pdispatch *pd, uint32_t command, uin #ifdef TUNNEL_SINK static void send_prebuf_request(struct userdata *u) { - struct pa_tagstruct *t; + pa_tagstruct *t; t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_PREBUF_PLAYBACK_STREAM); @@ -206,7 +206,7 @@ static void send_bytes(struct userdata *u) { return; while (u->requested_bytes > 0) { - struct pa_memchunk chunk; + pa_memchunk chunk; if (pa_sink_render(u->sink, u->requested_bytes, &chunk) < 0) { @@ -226,7 +226,7 @@ static void send_bytes(struct userdata *u) { } } -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; uint32_t bytes, channel; assert(pd && command == PA_COMMAND_REQUEST && t && u && u->pdispatch == pd); @@ -251,7 +251,7 @@ static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t #endif -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; pa_usec_t buffer_usec, sink_usec, source_usec, transport_usec; int playing; @@ -309,7 +309,7 @@ static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t comman } static void request_latency(struct userdata *u) { - struct pa_tagstruct *t; + pa_tagstruct *t; struct timeval now; uint32_t tag; assert(u); @@ -331,7 +331,7 @@ static void request_latency(struct userdata *u) { pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u); } -static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; assert(pd && u && u->pdispatch == pd); @@ -361,9 +361,9 @@ static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, ui #endif } -static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; - struct pa_tagstruct *reply; + pa_tagstruct *reply; char name[256], un[128], hn[128]; assert(pd && u && u->pdispatch == pd); @@ -424,7 +424,7 @@ static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, u pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, u); } -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { +static void pstream_die_callback(pa_pstream *p, void *userdata) { struct userdata *u = userdata; assert(p && u); @@ -433,7 +433,7 @@ static void pstream_die_callback(struct pa_pstream *p, void *userdata) { } -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { struct userdata *u = userdata; assert(p && packet && u); @@ -444,7 +444,7 @@ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *pack } #ifndef TUNNEL_SINK -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk, void *userdata) { +static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata) { struct userdata *u = userdata; assert(p && chunk && u); @@ -458,9 +458,9 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, ui } #endif -static void on_connection(struct pa_socket_client *sc, struct pa_iochannel *io, void *userdata) { +static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata) { struct userdata *u = userdata; - struct pa_tagstruct *t; + pa_tagstruct *t; uint32_t tag; assert(sc && u && u->client == sc); @@ -492,7 +492,7 @@ static void on_connection(struct pa_socket_client *sc, struct pa_iochannel *io, } #ifdef TUNNEL_SINK -static void sink_notify(struct pa_sink*sink) { +static void sink_notify(pa_sink*sink) { struct userdata *u; assert(sink && sink->userdata); u = sink->userdata; @@ -500,7 +500,7 @@ static void sink_notify(struct pa_sink*sink) { send_bytes(u); } -static pa_usec_t sink_get_latency(struct pa_sink *sink) { +static pa_usec_t sink_get_latency(pa_sink *sink) { struct userdata *u; uint32_t l; pa_usec_t usec = 0; @@ -519,7 +519,7 @@ static pa_usec_t sink_get_latency(struct pa_sink *sink) { return usec; } #else -static pa_usec_t source_get_latency(struct pa_source *source) { +static pa_usec_t source_get_latency(pa_source *source) { struct userdata *u; assert(source && source->userdata); u = source->userdata; @@ -528,7 +528,7 @@ static pa_usec_t source_get_latency(struct pa_source *source) { } #endif -static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, const struct timeval *tv, void *userdata) { +static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { struct userdata *u = userdata; struct timeval ntv; assert(m && e && u); @@ -566,10 +566,10 @@ static int load_key(struct userdata *u, const char*fn) { return 0; } -int pa__init(struct pa_core *c, struct pa_module*m) { - struct pa_modargs *ma = NULL; +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; struct userdata *u = NULL; - struct pa_sample_spec ss; + pa_sample_spec ss; struct timeval ntv; assert(c && m); @@ -665,7 +665,7 @@ fail: return -1; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { struct userdata* u; assert(c && m); diff --git a/polyp/module-waveout.c b/polyp/module-waveout.c index 4e01bc75..4d6d8c7b 100644 --- a/polyp/module-waveout.c +++ b/polyp/module-waveout.c @@ -49,11 +49,11 @@ PA_MODULE_USAGE("sink_name= source_name= #define DEFAULT_SOURCE_NAME "wave_input" struct userdata { - struct pa_sink *sink; - struct pa_source *source; - struct pa_core *core; - struct pa_time_event *event; - struct pa_defer_event *defer; + pa_sink *sink; + pa_source *source; + pa_core *core; + pa_time_event *event; + pa_defer_event *defer; pa_usec_t poll_timeout; uint32_t fragments, fragment_size; @@ -65,11 +65,11 @@ struct userdata { int cur_ohdr, cur_ihdr; unsigned int oremain; WAVEHDR *ohdrs, *ihdrs; - struct pa_memchunk silence; + pa_memchunk silence; HWAVEOUT hwo; HWAVEIN hwi; - struct pa_module *module; + pa_module *module; CRITICAL_SECTION crit; }; @@ -89,15 +89,15 @@ static const char* const valid_modargs[] = { static void update_usage(struct userdata *u) { pa_module_set_used(u->module, - (u->sink ? pa_idxset_ncontents(u->sink->inputs) : 0) + - (u->sink ? pa_idxset_ncontents(u->sink->monitor_source->outputs) : 0) + - (u->source ? pa_idxset_ncontents(u->source->outputs) : 0)); + (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0) + + (u->source ? pa_idxset_size(u->source->outputs) : 0)); } static void do_write(struct userdata *u) { uint32_t free_frags, remain; - struct pa_memchunk memchunk, *cur_chunk; + pa_memchunk memchunk, *cur_chunk; WAVEHDR *hdr; MMRESULT res; @@ -178,7 +178,7 @@ static void do_write(struct userdata *u) static void do_read(struct userdata *u) { uint32_t free_frags; - struct pa_memchunk memchunk; + pa_memchunk memchunk; WAVEHDR *hdr; MMRESULT res; @@ -227,7 +227,7 @@ static void do_read(struct userdata *u) } } -static void poll_cb(struct pa_mainloop_api*a, struct pa_time_event *e, const struct timeval *tv, void *userdata) { +static void poll_cb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) { struct userdata *u = userdata; struct timeval ntv; @@ -244,7 +244,7 @@ static void poll_cb(struct pa_mainloop_api*a, struct pa_time_event *e, const str a->time_restart(e, &ntv); } -static void defer_cb(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata) { +static void defer_cb(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { struct userdata *u = userdata; assert(u); @@ -283,7 +283,7 @@ static void CALLBACK chunk_ready_cb(HWAVEIN hwi, UINT msg, DWORD_PTR inst, DWORD LeaveCriticalSection(&u->crit); } -static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { +static pa_usec_t sink_get_latency_cb(pa_sink *s) { struct userdata *u = s->userdata; uint32_t free_frags; MMTIME mmt; @@ -305,7 +305,7 @@ static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { } } -static pa_usec_t source_get_latency_cb(struct pa_source *s) { +static pa_usec_t source_get_latency_cb(pa_source *s) { pa_usec_t r = 0; struct userdata *u = s->userdata; uint32_t free_frags; @@ -324,21 +324,21 @@ static pa_usec_t source_get_latency_cb(struct pa_source *s) { return r; } -static void notify_sink_cb(struct pa_sink *s) { +static void notify_sink_cb(pa_sink *s) { struct userdata *u = s->userdata; assert(u); u->core->mainloop->defer_enable(u->defer, 1); } -static void notify_source_cb(struct pa_source *s) { +static void notify_source_cb(pa_source *s) { struct userdata *u = s->userdata; assert(u); u->core->mainloop->defer_enable(u->defer, 1); } -static int ss_to_waveformat(struct pa_sample_spec *ss, LPWAVEFORMATEX wf) { +static int ss_to_waveformat(pa_sample_spec *ss, LPWAVEFORMATEX wf) { wf->wFormatTag = WAVE_FORMAT_PCM; if (ss->channels > 2) { @@ -378,15 +378,15 @@ static int ss_to_waveformat(struct pa_sample_spec *ss, LPWAVEFORMATEX wf) { return 0; } -int pa__init(struct pa_core *c, struct pa_module*m) { +int pa__init(pa_core *c, pa_module*m) { struct userdata *u = NULL; HWAVEOUT hwo = INVALID_HANDLE_VALUE; HWAVEIN hwi = INVALID_HANDLE_VALUE; WAVEFORMATEX wf; int nfrags, frag_size; int record = 1, playback = 1; - struct pa_sample_spec ss; - struct pa_modargs *ma = NULL; + pa_sample_spec ss; + pa_modargs *ma = NULL; unsigned int i; struct timeval tv; @@ -534,7 +534,7 @@ fail: return -1; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { struct userdata *u; unsigned int i; diff --git a/polyp/module-x11-bell.c b/polyp/module-x11-bell.c index 084f5d4b..9b08c166 100644 --- a/polyp/module-x11-bell.c +++ b/polyp/module-x11-bell.c @@ -47,14 +47,14 @@ PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink= sample= display=") struct userdata { - struct pa_core *core; + pa_core *core; int xkb_event_base; char *sink_name; char *scache_item; Display *display; - struct pa_x11_wrapper *x11_wrapper; - struct pa_x11_client *x11_client; + pa_x11_wrapper *x11_wrapper; + pa_x11_client *x11_client; }; static const char* const valid_modargs[] = { @@ -65,7 +65,7 @@ static const char* const valid_modargs[] = { }; static int ring_bell(struct userdata *u, int percent) { - struct pa_sink *s; + pa_sink *s; assert(u); if (!(s = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) { @@ -77,7 +77,7 @@ static int ring_bell(struct userdata *u, int percent) { return 0; } -static int x11_event_callback(struct pa_x11_wrapper *w, XEvent *e, void *userdata) { +static int x11_event_callback(pa_x11_wrapper *w, XEvent *e, void *userdata) { XkbBellNotifyEvent *bne; struct userdata *u = userdata; assert(w && e && u && u->x11_wrapper == w); @@ -95,9 +95,9 @@ static int x11_event_callback(struct pa_x11_wrapper *w, XEvent *e, void *userdat return 1; } -int pa__init(struct pa_core *c, struct pa_module*m) { +int pa__init(pa_core *c, pa_module*m) { struct userdata *u = NULL; - struct pa_modargs *ma = NULL; + pa_modargs *ma = NULL; int major, minor; unsigned int auto_ctrls, auto_values; assert(c && m); @@ -154,7 +154,7 @@ fail: return -1; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { struct userdata *u = m->userdata; assert(c && m && u); diff --git a/polyp/module-x11-publish.c b/polyp/module-x11-publish.c index a47a7606..0116914f 100644 --- a/polyp/module-x11-publish.c +++ b/polyp/module-x11-publish.c @@ -63,8 +63,8 @@ static const char* const valid_modargs[] = { }; struct userdata { - struct pa_core *core; - struct pa_x11_wrapper *x11_wrapper; + pa_core *core; + pa_x11_wrapper *x11_wrapper; Display *display; char *id; uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; @@ -97,14 +97,14 @@ static int load_key(struct userdata *u, const char*fn) { return 0; } -int pa__init(struct pa_core *c, struct pa_module*m) { +int pa__init(pa_core *c, pa_module*m) { struct userdata *u; - struct pa_modargs *ma = NULL; + pa_modargs *ma = NULL; char hn[256], un[128]; char hx[PA_NATIVE_COOKIE_LENGTH*2+1]; const char *t; char *s; - struct pa_strlist *l; + pa_strlist *l; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": failed to parse module arguments\n"); @@ -156,7 +156,7 @@ fail: return -1; } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { struct userdata*u; assert(c && m); diff --git a/polyp/module-zeroconf-publish.c b/polyp/module-zeroconf-publish.c index a7e2073e..7e0a2764 100644 --- a/polyp/module-zeroconf-publish.c +++ b/polyp/module-zeroconf-publish.c @@ -64,23 +64,23 @@ struct service { struct { int valid; - enum pa_namereg_type type; + pa_namereg_type type; uint32_t index; } loaded; struct { int valid; - enum pa_namereg_type type; + pa_namereg_type type; uint32_t index; } autoload; }; struct userdata { - struct pa_core *core; - struct pa_howl_wrapper *howl_wrapper; - struct pa_hashmap *services; - struct pa_dynarray *sink_dynarray, *source_dynarray, *autoload_dynarray; - struct pa_subscription *subscription; + pa_core *core; + pa_howl_wrapper *howl_wrapper; + pa_hashmap *services; + pa_dynarray *sink_dynarray, *source_dynarray, *autoload_dynarray; + pa_subscription *subscription; uint16_t port; sw_discovery_oid server_oid; @@ -90,17 +90,17 @@ static sw_result publish_reply(sw_discovery discovery, sw_discovery_publish_stat return SW_OKAY; } -static void get_service_data(struct userdata *u, struct service *s, struct pa_sample_spec *ret_ss, char **ret_description, pa_typeid_t *ret_typeid) { +static void get_service_data(struct userdata *u, struct service *s, pa_sample_spec *ret_ss, char **ret_description, pa_typeid_t *ret_typeid) { assert(u && s && s->loaded.valid && ret_ss && ret_description && ret_typeid); if (s->loaded.type == PA_NAMEREG_SINK) { - struct pa_sink *sink = pa_idxset_get_by_index(u->core->sinks, s->loaded.index); + pa_sink *sink = pa_idxset_get_by_index(u->core->sinks, s->loaded.index); assert(sink); *ret_ss = sink->sample_spec; *ret_description = sink->description; *ret_typeid = sink->typeid; } else if (s->loaded.type == PA_NAMEREG_SOURCE) { - struct pa_source *source = pa_idxset_get_by_index(u->core->sources, s->loaded.index); + pa_source *source = pa_idxset_get_by_index(u->core->sources, s->loaded.index); assert(source); *ret_ss = source->sample_spec; *ret_description = source->description; @@ -109,7 +109,7 @@ static void get_service_data(struct userdata *u, struct service *s, struct pa_sa assert(0); } -static void txt_record_server_data(struct pa_core *c, sw_text_record t) { +static void txt_record_server_data(pa_core *c, sw_text_record t) { char s[256]; assert(c); @@ -152,7 +152,7 @@ static int publish_service(struct userdata *u, struct service *s) { if (s->loaded.valid) { char z[64], *description; pa_typeid_t typeid; - struct pa_sample_spec ss; + pa_sample_spec ss; get_service_data(u, s, &ss, &description, &typeid); @@ -223,7 +223,7 @@ struct service *get_service(struct userdata *u, const char *name) { return s; } -static int publish_sink(struct userdata *u, struct pa_sink *s) { +static int publish_sink(struct userdata *u, pa_sink *s) { struct service *svc; assert(u && s); @@ -240,7 +240,7 @@ static int publish_sink(struct userdata *u, struct pa_sink *s) { return publish_service(u, svc); } -static int publish_source(struct userdata *u, struct pa_source *s) { +static int publish_source(struct userdata *u, pa_source *s) { struct service *svc; assert(u && s); @@ -257,7 +257,7 @@ static int publish_source(struct userdata *u, struct pa_source *s) { return publish_service(u, svc); } -static int publish_autoload(struct userdata *u, struct pa_autoload_entry *s) { +static int publish_autoload(struct userdata *u, pa_autoload_entry *s) { struct service *svc; assert(u && s); @@ -322,14 +322,14 @@ static int remove_autoload(struct userdata *u, uint32_t index) { return publish_service(u, svc); } -static void subscribe_callback(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index, void *userdata) { +static void subscribe_callback(pa_core *c, pa_subscription_event_type t, uint32_t index, void *userdata) { struct userdata *u = userdata; assert(u && c); switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) case PA_SUBSCRIPTION_EVENT_SINK: { if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { - struct pa_sink *sink; + pa_sink *sink; if ((sink = pa_idxset_get_by_index(c->sinks, index))) { if (publish_sink(u, sink) < 0) @@ -345,7 +345,7 @@ static void subscribe_callback(struct pa_core *c, enum pa_subscription_event_typ case PA_SUBSCRIPTION_EVENT_SOURCE: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { - struct pa_source *source; + pa_source *source; if ((source = pa_idxset_get_by_index(c->sources, index))) { if (publish_source(u, source) < 0) @@ -360,7 +360,7 @@ static void subscribe_callback(struct pa_core *c, enum pa_subscription_event_typ case PA_SUBSCRIPTION_EVENT_AUTOLOAD: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { - struct pa_autoload_entry *autoload; + pa_autoload_entry *autoload; if ((autoload = pa_idxset_get_by_index(c->autoload_idxset, index))) { if (publish_autoload(u, autoload) < 0) @@ -383,13 +383,13 @@ fail: } } -int pa__init(struct pa_core *c, struct pa_module*m) { +int pa__init(pa_core *c, pa_module*m) { struct userdata *u; uint32_t index, port = PA_NATIVE_DEFAULT_PORT; - struct pa_sink *sink; - struct pa_source *source; - struct pa_autoload_entry *autoload; - struct pa_modargs *ma = NULL; + pa_sink *sink; + pa_source *source; + pa_autoload_entry *autoload; + pa_modargs *ma = NULL; char t[256], hn[256]; int free_txt = 0; sw_text_record txt; @@ -478,7 +478,7 @@ static void service_free(void *p, void *userdata) { pa_xfree(s); } -void pa__done(struct pa_core *c, struct pa_module*m) { +void pa__done(pa_core *c, pa_module*m) { struct userdata*u; assert(c && m); diff --git a/polyp/module.c b/polyp/module.c index 0a3d569b..499ea299 100644 --- a/polyp/module.c +++ b/polyp/module.c @@ -34,14 +34,15 @@ #include "xmalloc.h" #include "subscribe.h" #include "log.h" +#include "util.h" #define PA_SYMBOL_INIT "pa__init" #define PA_SYMBOL_DONE "pa__done" #define UNLOAD_POLL_TIME 2 -static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, const struct timeval *tv, void *userdata) { - struct pa_core *c = userdata; +static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + pa_core *c = userdata; struct timeval ntv; assert(c && c->mainloop == m && c->module_auto_unload_event == e); @@ -52,8 +53,8 @@ static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, m->time_restart(e, &ntv); } -struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char *argument) { - struct pa_module *m = NULL; +pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { + pa_module *m = NULL; int r; assert(c && name); @@ -61,7 +62,7 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char if (c->disallow_module_loading) goto fail; - m = pa_xmalloc(sizeof(struct pa_module)); + m = pa_xmalloc(sizeof(pa_module)); m->name = pa_xstrdup(name); m->argument = pa_xstrdup(argument); @@ -71,12 +72,12 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char goto fail; } - if (!(m->init = (int (*)(struct pa_core *c, struct pa_module*m)) lt_dlsym(m->dl, PA_SYMBOL_INIT))) { + if (!(m->init = (int (*)(pa_core *_c, pa_module*_m)) lt_dlsym(m->dl, PA_SYMBOL_INIT))) { pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.\n", name); goto fail; } - if (!(m->done = (void (*)(struct pa_core *c, struct pa_module*m)) lt_dlsym(m->dl, PA_SYMBOL_DONE))) { + if (!(m->done = (void (*)(pa_core *_c, pa_module*_m)) lt_dlsym(m->dl, PA_SYMBOL_DONE))) { pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_DONE"\" not found.\n", name); goto fail; } @@ -129,7 +130,7 @@ fail: return NULL; } -static void pa_module_free(struct pa_module *m) { +static void pa_module_free(pa_module *m) { assert(m && m->done && m->core); if (m->core->disallow_module_loading) @@ -150,7 +151,7 @@ static void pa_module_free(struct pa_module *m) { pa_xfree(m); } -void pa_module_unload(struct pa_core *c, struct pa_module *m) { +void pa_module_unload(pa_core *c, pa_module *m) { assert(c && m); assert(c->modules); @@ -160,24 +161,24 @@ void pa_module_unload(struct pa_core *c, struct pa_module *m) { pa_module_free(m); } -void pa_module_unload_by_index(struct pa_core *c, uint32_t index) { - struct pa_module *m; - assert(c && index != PA_IDXSET_INVALID); +void pa_module_unload_by_index(pa_core *c, uint32_t idx) { + pa_module *m; + assert(c && idx != PA_IDXSET_INVALID); assert(c->modules); - if (!(m = pa_idxset_remove_by_index(c->modules, index))) + if (!(m = pa_idxset_remove_by_index(c->modules, idx))) return; pa_module_free(m); } -static void free_callback(void *p, void *userdata) { - struct pa_module *m = p; +static void free_callback(void *p, PA_GCC_UNUSED void *userdata) { + pa_module *m = p; assert(m); pa_module_free(m); } -void pa_module_unload_all(struct pa_core *c) { +void pa_module_unload_all(pa_core *c) { assert(c); if (!c->modules) @@ -197,8 +198,8 @@ void pa_module_unload_all(struct pa_core *c) { } } -static int unused_callback(void *p, uint32_t index, int *del, void *userdata) { - struct pa_module *m = p; +static int unused_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void *userdata) { + pa_module *m = p; time_t *now = userdata; assert(p && del && now); @@ -210,7 +211,7 @@ static int unused_callback(void *p, uint32_t index, int *del, void *userdata) { return 0; } -void pa_module_unload_unused(struct pa_core *c) { +void pa_module_unload_unused(pa_core *c) { time_t now; assert(c); @@ -221,8 +222,8 @@ void pa_module_unload_unused(struct pa_core *c) { pa_idxset_foreach(c->modules, unused_callback, &now); } -static int unload_callback(void *p, uint32_t index, int *del, void *userdata) { - struct pa_module *m = p; +static int unload_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, PA_GCC_UNUSED void *userdata) { + pa_module *m = p; assert(m); if (m->unload_requested) { @@ -233,8 +234,8 @@ static int unload_callback(void *p, uint32_t index, int *del, void *userdata) { return 0; } -static void defer_cb(struct pa_mainloop_api*api, struct pa_defer_event *e, void *userdata) { - struct pa_core *core = userdata; +static void defer_cb(pa_mainloop_api*api, pa_defer_event *e, void *userdata) { + pa_core *core = userdata; api->defer_enable(e, 0); if (!core->modules) @@ -244,7 +245,7 @@ static void defer_cb(struct pa_mainloop_api*api, struct pa_defer_event *e, void } -void pa_module_unload_request(struct pa_module *m) { +void pa_module_unload_request(pa_module *m) { assert(m); m->unload_requested = 1; @@ -255,7 +256,7 @@ void pa_module_unload_request(struct pa_module *m) { m->core->mainloop->defer_enable(m->core->module_defer_unload_event, 1); } -void pa_module_set_used(struct pa_module*m, int used) { +void pa_module_set_used(pa_module*m, int used) { assert(m); if (m->n_used != used) @@ -267,7 +268,7 @@ void pa_module_set_used(struct pa_module*m, int used) { m->n_used = used; } -struct pa_modinfo *pa_module_get_info(struct pa_module *m) { +pa_modinfo *pa_module_get_info(pa_module *m) { assert(m); return pa_modinfo_get_by_handle(m->dl); diff --git a/polyp/module.h b/polyp/module.h index f5daff95..6f137c15 100644 --- a/polyp/module.h +++ b/polyp/module.h @@ -28,15 +28,17 @@ #include "core.h" #include "modinfo.h" +typedef struct pa_module pa_module; + struct pa_module { - struct pa_core *core; + pa_core *core; char *name, *argument; uint32_t index; lt_dlhandle dl; - int (*init)(struct pa_core *c, struct pa_module*m); - void (*done)(struct pa_core *c, struct pa_module*m); + int (*init)(pa_core *c, pa_module*m); + void (*done)(pa_core *c, pa_module*m); void *userdata; @@ -47,22 +49,22 @@ struct pa_module { int unload_requested; }; -struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char*argument); -/* void pa_module_unload(struct pa_core *c, struct pa_module *m); */ -/* void pa_module_unload_by_index(struct pa_core *c, uint32_t index); */ +pa_module* pa_module_load(pa_core *c, const char *name, const char*argument); +void pa_module_unload(pa_core *c, pa_module *m); +void pa_module_unload_by_index(pa_core *c, uint32_t idx); -void pa_module_unload_all(struct pa_core *c); -void pa_module_unload_unused(struct pa_core *c); +void pa_module_unload_all(pa_core *c); +void pa_module_unload_unused(pa_core *c); -void pa_module_unload_request(struct pa_module *m); +void pa_module_unload_request(pa_module *m); -void pa_module_set_used(struct pa_module*m, int used); +void pa_module_set_used(pa_module*m, int used); #define PA_MODULE_AUTHOR(s) const char * pa__get_author(void) { return s; } #define PA_MODULE_DESCRIPTION(s) const char * pa__get_description(void) { return s; } #define PA_MODULE_USAGE(s) const char * pa__get_usage(void) { return s; } #define PA_MODULE_VERSION(s) const char * pa__get_version(void) { return s; } -struct pa_modinfo *pa_module_get_info(struct pa_module *m); +pa_modinfo *pa_module_get_info(pa_module *m); #endif diff --git a/polyp/namereg.c b/polyp/namereg.c index 04601442..7c53a05d 100644 --- a/polyp/namereg.c +++ b/polyp/namereg.c @@ -38,20 +38,20 @@ #include "util.h" struct namereg_entry { - enum pa_namereg_type type; + pa_namereg_type type; char *name; void *data; }; -void pa_namereg_free(struct pa_core *c) { +void pa_namereg_free(pa_core *c) { assert(c); if (!c->namereg) return; - assert(pa_hashmap_ncontents(c->namereg) == 0); + assert(pa_hashmap_size(c->namereg) == 0); pa_hashmap_free(c->namereg, NULL, NULL); } -const char *pa_namereg_register(struct pa_core *c, const char *name, enum pa_namereg_type type, void *data, int fail) { +const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type type, void *data, int fail) { struct namereg_entry *e; char *n = NULL; int r; @@ -99,7 +99,7 @@ const char *pa_namereg_register(struct pa_core *c, const char *name, enum pa_nam } -void pa_namereg_unregister(struct pa_core *c, const char *name) { +void pa_namereg_unregister(pa_core *c, const char *name) { struct namereg_entry *e; assert(c && name); @@ -110,9 +110,9 @@ void pa_namereg_unregister(struct pa_core *c, const char *name) { pa_xfree(e); } -void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type type, int autoload) { +void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type type, int autoload) { struct namereg_entry *e; - uint32_t index; + uint32_t idx; assert(c); if (!name) { @@ -129,7 +129,7 @@ void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type t if (e->type == e->type) return e->data; - if (pa_atou(name, &index) < 0) { + if (pa_atou(name, &idx) < 0) { if (autoload) { pa_autoload_request(c, name, type); @@ -143,16 +143,16 @@ void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type t } if (type == PA_NAMEREG_SINK) - return pa_idxset_get_by_index(c->sinks, index); + return pa_idxset_get_by_index(c->sinks, idx); else if (type == PA_NAMEREG_SOURCE) - return pa_idxset_get_by_index(c->sources, index); + return pa_idxset_get_by_index(c->sources, idx); else if (type == PA_NAMEREG_SAMPLE && c->scache) - return pa_idxset_get_by_index(c->scache, index); + return pa_idxset_get_by_index(c->scache, idx); return NULL; } -void pa_namereg_set_default(struct pa_core*c, const char *name, enum pa_namereg_type type) { +void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type type) { char **s; assert(c && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); @@ -170,8 +170,8 @@ void pa_namereg_set_default(struct pa_core*c, const char *name, enum pa_namereg_ pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); } -const char *pa_namereg_get_default_sink_name(struct pa_core *c) { - struct pa_sink *s; +const char *pa_namereg_get_default_sink_name(pa_core *c) { + pa_sink *s; assert(c); if (c->default_sink_name) @@ -186,16 +186,16 @@ const char *pa_namereg_get_default_sink_name(struct pa_core *c) { return NULL; } -const char *pa_namereg_get_default_source_name(struct pa_core *c) { - struct pa_source *s; - uint32_t index; +const char *pa_namereg_get_default_source_name(pa_core *c) { + pa_source *s; + uint32_t idx; assert(c); if (c->default_source_name) return c->default_source_name; - for (s = pa_idxset_first(c->sources, &index); s; s = pa_idxset_next(c->sources, &index)) + for (s = pa_idxset_first(c->sources, &idx); s; s = pa_idxset_next(c->sources, &idx)) if (!s->monitor_of) { pa_namereg_set_default(c, s->name, PA_NAMEREG_SOURCE); break; diff --git a/polyp/namereg.h b/polyp/namereg.h index 99032be8..04f1737b 100644 --- a/polyp/namereg.h +++ b/polyp/namereg.h @@ -24,20 +24,20 @@ #include "core.h" -enum pa_namereg_type { +typedef enum pa_namereg_type { PA_NAMEREG_SINK, PA_NAMEREG_SOURCE, PA_NAMEREG_SAMPLE -}; +} pa_namereg_type ; -void pa_namereg_free(struct pa_core *c); +void pa_namereg_free(pa_core *c); -const char *pa_namereg_register(struct pa_core *c, const char *name, enum pa_namereg_type type, void *data, int fail); -void pa_namereg_unregister(struct pa_core *c, const char *name); -void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type type, int autoload); -void pa_namereg_set_default(struct pa_core*c, const char *name, enum pa_namereg_type type); +const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type type, void *data, int fail); +void pa_namereg_unregister(pa_core *c, const char *name); +void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type type, int autoload); +void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type type); -const char *pa_namereg_get_default_sink_name(struct pa_core *c); -const char *pa_namereg_get_default_source_name(struct pa_core *c); +const char *pa_namereg_get_default_sink_name(pa_core *c); +const char *pa_namereg_get_default_source_name(pa_core *c); #endif diff --git a/polyp/oss-util.c b/polyp/oss-util.c index 799bc40a..20a2965a 100644 --- a/polyp/oss-util.c +++ b/polyp/oss-util.c @@ -90,7 +90,7 @@ fail: return fd; } -int pa_oss_auto_format(int fd, struct pa_sample_spec *ss) { +int pa_oss_auto_format(int fd, pa_sample_spec *ss) { int format, channels, speed, reqformat; static const int format_trans[PA_SAMPLE_MAX] = { [PA_SAMPLE_U8] = AFMT_U8, diff --git a/polyp/oss-util.h b/polyp/oss-util.h index c1c69632..3ee51cc5 100644 --- a/polyp/oss-util.h +++ b/polyp/oss-util.h @@ -25,7 +25,7 @@ #include "sample.h" int pa_oss_open(const char *device, int *mode, int* pcaps); -int pa_oss_auto_format(int fd, struct pa_sample_spec *ss); +int pa_oss_auto_format(int fd, pa_sample_spec *ss); int pa_oss_set_fragments(int fd, int frags, int frag_size); diff --git a/polyp/pabrowse.c b/polyp/pabrowse.c index ccea0cd4..634c308a 100644 --- a/polyp/pabrowse.c +++ b/polyp/pabrowse.c @@ -32,12 +32,12 @@ #include #include -static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { +static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { fprintf(stderr, "Got signal, exiting\n"); m->quit(m, 0); } -static void dump_server(const struct pa_browse_info *i) { +static void dump_server(const pa_browse_info *i) { char t[16]; if (i->cookie) @@ -55,7 +55,7 @@ static void dump_server(const struct pa_browse_info *i) { i->cookie ? t : "n/a"); } -static void dump_device(const struct pa_browse_info *i) { +static void dump_device(const pa_browse_info *i) { char t[16], ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; if (i->sample_spec) @@ -75,7 +75,7 @@ static void dump_device(const struct pa_browse_info *i) { } -static void browser_callback(struct pa_browser *b, enum pa_browse_opcode c, const struct pa_browse_info *i, void *userdata) { +static void browser_callback(pa_browser *b, pa_browse_opcode c, const pa_browse_info *i, void *userdata) { assert(b && i); switch (c) { @@ -108,8 +108,8 @@ static void browser_callback(struct pa_browser *b, enum pa_browse_opcode c, cons int main(int argc, char *argv[]) { - struct pa_mainloop *mainloop = NULL; - struct pa_browser *browser = NULL; + pa_mainloop *mainloop = NULL; + pa_browser *browser = NULL; int ret = 1, r; if (!(mainloop = pa_mainloop_new())) diff --git a/polyp/pacat-simple.c b/polyp/pacat-simple.c index 09cf4d1a..373cdd57 100644 --- a/polyp/pacat-simple.c +++ b/polyp/pacat-simple.c @@ -30,19 +30,20 @@ #include #include +#include "gccmacro.h" #define BUFSIZE 1024 -int main(int argc, char*argv[]) { +int main(PA_GCC_UNUSED int argc, char*argv[]) { /* The Sample format to use */ - static const struct pa_sample_spec ss = { + static const pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2 }; - struct pa_simple *s = NULL; + pa_simple *s = NULL; int ret = 1; int error; diff --git a/polyp/pacat.c b/polyp/pacat.c index 1bba2ee4..6842d61a 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -44,21 +44,21 @@ static enum { RECORD, PLAYBACK } mode = PLAYBACK; -static struct pa_context *context = NULL; -static struct pa_stream *stream = NULL; -static struct pa_mainloop_api *mainloop_api = NULL; +static pa_context *context = NULL; +static pa_stream *stream = NULL; +static pa_mainloop_api *mainloop_api = NULL; static void *buffer = NULL; static size_t buffer_length = 0, buffer_index = 0; -static struct pa_io_event* stdio_event = NULL; +static pa_io_event* stdio_event = NULL; static char *stream_name = NULL, *client_name = NULL, *device = NULL; static int verbose = 0; static pa_volume_t volume = PA_VOLUME_NORM; -static struct pa_sample_spec sample_spec = { +static pa_sample_spec sample_spec = { .format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2 @@ -94,7 +94,7 @@ static void do_stream_write(size_t length) { } /* This is called whenever new data may be written to the stream */ -static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) { +static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { assert(s && length); if (stdio_event) @@ -107,7 +107,7 @@ static void stream_write_callback(struct pa_stream *s, size_t length, void *user } /* This is called whenever new data may is available */ -static void stream_read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata) { +static void stream_read_callback(pa_stream *s, const void*data, size_t length, void *userdata) { assert(s && data && length); if (stdio_event) @@ -125,7 +125,7 @@ static void stream_read_callback(struct pa_stream *s, const void*data, size_t le } /* This routine is called whenever the stream state changes */ -static void stream_state_callback(struct pa_stream *s, void *userdata) { +static void stream_state_callback(pa_stream *s, void *userdata) { assert(s); switch (pa_stream_get_state(s)) { @@ -146,7 +146,7 @@ static void stream_state_callback(struct pa_stream *s, void *userdata) { } /* This is called whenever the context status changes */ -static void context_state_callback(struct pa_context *c, void *userdata) { +static void context_state_callback(pa_context *c, void *userdata) { assert(c); switch (pa_context_get_state(c)) { @@ -188,13 +188,13 @@ static void context_state_callback(struct pa_context *c, void *userdata) { } /* Connection draining complete */ -static void context_drain_complete(struct pa_context*c, void *userdata) { +static void context_drain_complete(pa_context*c, void *userdata) { pa_context_disconnect(c); } /* Stream draining complete */ -static void stream_drain_complete(struct pa_stream*s, int success, void *userdata) { - struct pa_operation *o; +static void stream_drain_complete(pa_stream*s, int success, void *userdata) { + pa_operation *o; if (!success) { fprintf(stderr, "Failed to drain stream: %s\n", pa_strerror(pa_context_errno(context))); @@ -219,7 +219,7 @@ static void stream_drain_complete(struct pa_stream*s, int success, void *userdat } /* New data on STDIN **/ -static void stdin_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { +static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata) { size_t l, w = 0; ssize_t r; assert(a == mainloop_api && e && stdio_event == e); @@ -257,7 +257,7 @@ static void stdin_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int } /* Some data may be written to STDOUT */ -static void stdout_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { +static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata) { ssize_t r; assert(a == mainloop_api && e && stdio_event == e); @@ -288,7 +288,7 @@ static void stdout_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int } /* UNIX signal to quit recieved */ -static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { +static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { if (verbose) fprintf(stderr, "Got signal, exiting.\n"); quit(0); @@ -296,7 +296,7 @@ static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_even } /* Show the current latency */ -static void stream_get_latency_callback(struct pa_stream *s, const struct pa_latency_info *i, void *userdata) { +static void stream_get_latency_callback(pa_stream *s, const pa_latency_info *i, void *userdata) { pa_usec_t total; int negative = 0; assert(s); @@ -315,7 +315,7 @@ static void stream_get_latency_callback(struct pa_stream *s, const struct pa_lat } /* Someone requested that the latency is shown */ -static void sigusr1_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { +static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { fprintf(stderr, "Got SIGUSR1, requesting latency.\n"); pa_operation_unref(pa_stream_get_latency_info(stream, stream_get_latency_callback, NULL)); } @@ -352,7 +352,7 @@ enum { }; int main(int argc, char *argv[]) { - struct pa_mainloop* m = NULL; + pa_mainloop* m = NULL; int ret = 1, r, c; char *bn, *server = NULL; diff --git a/polyp/packet.c b/polyp/packet.c index 84ac6d62..b3a2e074 100644 --- a/polyp/packet.c +++ b/polyp/packet.c @@ -29,10 +29,10 @@ #include "packet.h" #include "xmalloc.h" -struct pa_packet* pa_packet_new(size_t length) { - struct pa_packet *p; +pa_packet* pa_packet_new(size_t length) { + pa_packet *p; assert(length); - p = pa_xmalloc(sizeof(struct pa_packet)+length); + p = pa_xmalloc(sizeof(pa_packet)+length); p->ref = 1; p->length = length; p->data = (uint8_t*) (p+1); @@ -40,10 +40,10 @@ struct pa_packet* pa_packet_new(size_t length) { return p; } -struct pa_packet* pa_packet_new_dynamic(uint8_t* data, size_t length) { - struct pa_packet *p; +pa_packet* pa_packet_new_dynamic(uint8_t* data, size_t length) { + pa_packet *p; assert(data && length); - p = pa_xmalloc(sizeof(struct pa_packet)); + p = pa_xmalloc(sizeof(pa_packet)); p->ref = 1; p->length = length; p->data = data; @@ -51,13 +51,13 @@ struct pa_packet* pa_packet_new_dynamic(uint8_t* data, size_t length) { return p; } -struct pa_packet* pa_packet_ref(struct pa_packet *p) { +pa_packet* pa_packet_ref(pa_packet *p) { assert(p && p->ref >= 1); p->ref++; return p; } -void pa_packet_unref(struct pa_packet *p) { +void pa_packet_unref(pa_packet *p) { assert(p && p->ref >= 1); p->ref--; diff --git a/polyp/packet.h b/polyp/packet.h index 5e4e92f7..0ac47485 100644 --- a/polyp/packet.h +++ b/polyp/packet.h @@ -25,17 +25,17 @@ #include #include -struct pa_packet { +typedef struct pa_packet { enum { PA_PACKET_APPENDED, PA_PACKET_DYNAMIC } type; unsigned ref; size_t length; uint8_t *data; -}; +} pa_packet; -struct pa_packet* pa_packet_new(size_t length); -struct pa_packet* pa_packet_new_dynamic(uint8_t* data, size_t length); +pa_packet* pa_packet_new(size_t length); +pa_packet* pa_packet_new_dynamic(uint8_t* data, size_t length); -struct pa_packet* pa_packet_ref(struct pa_packet *p); -void pa_packet_unref(struct pa_packet *p); +pa_packet* pa_packet_ref(pa_packet *p); +void pa_packet_unref(pa_packet *p); #endif diff --git a/polyp/pacmd.c b/polyp/pacmd.c index d69c14d7..e6c0da6a 100644 --- a/polyp/pacmd.c +++ b/polyp/pacmd.c @@ -36,7 +36,7 @@ #include "log.h" #include "pid.h" -int main() { +int main(PA_GCC_UNUSED int main, PA_GCC_UNUSED char*argv[]) { pid_t pid ; int fd = -1; int ret = 1, i; diff --git a/polyp/pactl.c b/polyp/pactl.c index 725b5460..6943a11f 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -47,14 +47,14 @@ #define BUFSIZE 1024 -static struct pa_context *context = NULL; -static struct pa_mainloop_api *mainloop_api = NULL; +static pa_context *context = NULL; +static pa_mainloop_api *mainloop_api = NULL; static char *device = NULL, *sample_name = NULL; static SNDFILE *sndfile = NULL; -static struct pa_stream *sample_stream = NULL; -static struct pa_sample_spec sample_spec; +static pa_stream *sample_stream = NULL; +static pa_sample_spec sample_spec; static size_t sample_length = 0; static int actions = 1; @@ -77,12 +77,12 @@ static void quit(int ret) { } -static void context_drain_complete(struct pa_context *c, void *userdata) { +static void context_drain_complete(pa_context *c, void *userdata) { pa_context_disconnect(c); } static void drain(void) { - struct pa_operation *o; + pa_operation *o; if (!(o = pa_context_drain(context, context_drain_complete, NULL))) pa_context_disconnect(context); else @@ -97,7 +97,7 @@ static void complete_action(void) { drain(); } -static void stat_callback(struct pa_context *c, const struct pa_stat_info *i, void *userdata) { +static void stat_callback(pa_context *c, const pa_stat_info *i, void *userdata) { char s[128]; if (!i) { fprintf(stderr, "Failed to get statistics: %s\n", pa_strerror(pa_context_errno(c))); @@ -117,7 +117,7 @@ static void stat_callback(struct pa_context *c, const struct pa_stat_info *i, vo complete_action(); } -static void get_server_info_callback(struct pa_context *c, const struct pa_server_info *i, void *useerdata) { +static void get_server_info_callback(pa_context *c, const pa_server_info *i, void *useerdata) { char s[PA_SAMPLE_SPEC_SNPRINT_MAX]; if (!i) { @@ -148,7 +148,7 @@ static void get_server_info_callback(struct pa_context *c, const struct pa_serve complete_action(); } -static void get_sink_info_callback(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata) { +static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) { char s[PA_SAMPLE_SPEC_SNPRINT_MAX], tid[5]; if (is_last < 0) { @@ -191,7 +191,7 @@ static void get_sink_info_callback(struct pa_context *c, const struct pa_sink_in } -static void get_source_info_callback(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata) { +static void get_source_info_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) { char s[PA_SAMPLE_SPEC_SNPRINT_MAX], t[32], tid[5]; if (is_last < 0) { @@ -234,7 +234,7 @@ static void get_source_info_callback(struct pa_context *c, const struct pa_sourc } -static void get_module_info_callback(struct pa_context *c, const struct pa_module_info *i, int is_last, void *userdata) { +static void get_module_info_callback(pa_context *c, const pa_module_info *i, int is_last, void *userdata) { char t[32]; if (is_last < 0) { @@ -268,7 +268,7 @@ static void get_module_info_callback(struct pa_context *c, const struct pa_modul i->auto_unload ? "yes" : "no"); } -static void get_client_info_callback(struct pa_context *c, const struct pa_client_info *i, int is_last, void *userdata) { +static void get_client_info_callback(pa_context *c, const pa_client_info *i, int is_last, void *userdata) { char t[32], tid[5]; if (is_last < 0) { @@ -300,7 +300,7 @@ static void get_client_info_callback(struct pa_context *c, const struct pa_clien i->owner_module != PA_INVALID_INDEX ? t : "n/a"); } -static void get_sink_input_info_callback(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata) { +static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) { char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], tid[5]; if (is_last < 0) { @@ -349,7 +349,7 @@ static void get_sink_input_info_callback(struct pa_context *c, const struct pa_s } -static void get_source_output_info_callback(struct pa_context *c, const struct pa_source_output_info *i, int is_last, void *userdata) { +static void get_source_output_info_callback(pa_context *c, const pa_source_output_info *i, int is_last, void *userdata) { char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], tid[5]; if (is_last < 0) { @@ -395,7 +395,7 @@ static void get_source_output_info_callback(struct pa_context *c, const struct p i->resample_method ? i->resample_method : "n/a"); } -static void get_sample_info_callback(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata) { +static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int is_last, void *userdata) { char t[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX]; if (is_last < 0) { @@ -436,7 +436,7 @@ static void get_sample_info_callback(struct pa_context *c, const struct pa_sampl i->filename ? i->filename : "n/a"); } -static void get_autoload_info_callback(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata) { +static void get_autoload_info_callback(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata) { if (is_last < 0) { fprintf(stderr, "Failed to get autoload information: %s\n", pa_strerror(pa_context_errno(c))); quit(1); @@ -466,7 +466,7 @@ static void get_autoload_info_callback(struct pa_context *c, const struct pa_aut i->argument); } -static void simple_callback(struct pa_context *c, int success, void *userdata) { +static void simple_callback(pa_context *c, int success, void *userdata) { if (!success) { fprintf(stderr, "Failure: %s\n", pa_strerror(pa_context_errno(c))); quit(1); @@ -476,7 +476,7 @@ static void simple_callback(struct pa_context *c, int success, void *userdata) { complete_action(); } -static void stream_state_callback(struct pa_stream *s, void *userdata) { +static void stream_state_callback(pa_stream *s, void *userdata) { assert(s); switch (pa_stream_get_state(s)) { @@ -495,7 +495,7 @@ static void stream_state_callback(struct pa_stream *s, void *userdata) { } } -static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) { +static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { sf_count_t l; float *d; assert(s && length && sndfile); @@ -522,7 +522,7 @@ static void stream_write_callback(struct pa_stream *s, size_t length, void *user } } -static void context_state_callback(struct pa_context *c, void *userdata) { +static void context_state_callback(pa_context *c, void *userdata) { assert(c); switch (pa_context_get_state(c)) { case PA_CONTEXT_CONNECTING: @@ -587,7 +587,7 @@ static void context_state_callback(struct pa_context *c, void *userdata) { } } -static void exit_signal_callback(struct pa_mainloop_api *m, struct pa_signal_event *e, int sig, void *userdata) { +static void exit_signal_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) { fprintf(stderr, "Got SIGINT, exiting.\n"); quit(0); } @@ -610,7 +610,7 @@ static void help(const char *argv0) { enum { ARG_VERSION = 256 }; int main(int argc, char *argv[]) { - struct pa_mainloop* m = NULL; + pa_mainloop* m = NULL; char tmp[PATH_MAX]; int ret = 1, r, c; char *server = NULL, *client_name = NULL, *bn; diff --git a/polyp/paplay.c b/polyp/paplay.c index 4ace1973..d9aa71a6 100644 --- a/polyp/paplay.c +++ b/polyp/paplay.c @@ -44,9 +44,9 @@ #error Invalid Polypaudio API version #endif -static struct pa_context *context = NULL; -static struct pa_stream *stream = NULL; -static struct pa_mainloop_api *mainloop_api = NULL; +static pa_context *context = NULL; +static pa_stream *stream = NULL; +static pa_mainloop_api *mainloop_api = NULL; static char *stream_name = NULL, *client_name = NULL, *device = NULL; @@ -55,9 +55,9 @@ static pa_volume_t volume = PA_VOLUME_NORM; static SNDFILE* sndfile = NULL; -static struct pa_sample_spec sample_spec = { 0, 0, 0 }; +static pa_sample_spec sample_spec = { 0, 0, 0 }; -static sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames); +static sf_count_t (*readf_function)(SNDFILE *_sndfile, void *ptr, sf_count_t frames); /* A shortcut for terminating the application */ static void quit(int ret) { @@ -66,13 +66,13 @@ static void quit(int ret) { } /* Connection draining complete */ -static void context_drain_complete(struct pa_context*c, void *userdata) { +static void context_drain_complete(pa_context*c, void *userdata) { pa_context_disconnect(c); } /* Stream draining complete */ -static void stream_drain_complete(struct pa_stream*s, int success, void *userdata) { - struct pa_operation *o; +static void stream_drain_complete(pa_stream*s, int success, void *userdata) { + pa_operation *o; if (!success) { fprintf(stderr, "Failed to drain stream: %s\n", pa_strerror(pa_context_errno(context))); @@ -97,7 +97,7 @@ static void stream_drain_complete(struct pa_stream*s, int success, void *userdat } /* This is called whenever new data may be written to the stream */ -static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) { +static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { size_t k; sf_count_t f, n; void *data; @@ -125,7 +125,7 @@ static void stream_write_callback(struct pa_stream *s, size_t length, void *user } /* This routine is called whenever the stream state changes */ -static void stream_state_callback(struct pa_stream *s, void *userdata) { +static void stream_state_callback(pa_stream *s, void *userdata) { assert(s); switch (pa_stream_get_state(s)) { @@ -146,7 +146,7 @@ static void stream_state_callback(struct pa_stream *s, void *userdata) { } /* This is called whenever the context status changes */ -static void context_state_callback(struct pa_context *c, void *userdata) { +static void context_state_callback(pa_context *c, void *userdata) { assert(c); switch (pa_context_get_state(c)) { @@ -183,7 +183,7 @@ static void context_state_callback(struct pa_context *c, void *userdata) { } /* UNIX signal to quit recieved */ -static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { +static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { if (verbose) fprintf(stderr, "Got SIGINT, exiting.\n"); quit(0); @@ -211,9 +211,10 @@ enum { }; int main(int argc, char *argv[]) { - struct pa_mainloop* m = NULL; + pa_mainloop* m = NULL; int ret = 1, r, c; - char *bn, *server = NULL, *filename; + char *bn, *server = NULL; + const char *filename; SF_INFO sfinfo; static const struct option long_options[] = { @@ -312,12 +313,12 @@ int main(int argc, char *argv[]) { case SF_FORMAT_ULAW: case SF_FORMAT_ALAW: sample_spec.format = PA_SAMPLE_S16NE; - readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_short; + readf_function = (sf_count_t (*)(SNDFILE *_sndfile, void *ptr, sf_count_t frames)) sf_readf_short; break; case SF_FORMAT_FLOAT: default: sample_spec.format = PA_SAMPLE_FLOAT32NE; - readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_float; + readf_function = (sf_count_t (*)(SNDFILE *_sndfile, void *ptr, sf_count_t frames)) sf_readf_float; break; } diff --git a/polyp/parec-simple.c b/polyp/parec-simple.c index 130627d7..5f5abe11 100644 --- a/polyp/parec-simple.c +++ b/polyp/parec-simple.c @@ -30,6 +30,7 @@ #include #include +#include "gccmacro.h" #define BUFSIZE 1024 @@ -47,21 +48,21 @@ static ssize_t loop_write(int fd, const void*data, size_t size) { break; ret += r; - data = (uint8_t*) data + r; + data = (const uint8_t*) data + r; size -= r; } return ret; } -int main(int argc, char*argv[]) { +int main(PA_GCC_UNUSED int argc, char*argv[]) { /* The sample type to use */ - static const struct pa_sample_spec ss = { + static const pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2 }; - struct pa_simple *s = NULL; + pa_simple *s = NULL; int ret = 1; int error; diff --git a/polyp/parseaddr.c b/polyp/parseaddr.c index 05ed508b..5e4c689c 100644 --- a/polyp/parseaddr.c +++ b/polyp/parseaddr.c @@ -63,10 +63,10 @@ static char *parse_host(const char *s, uint16_t *ret_port) { } } -int pa_parse_address(const char *name, struct pa_parsed_address *ret_p) { +int pa_parse_address(const char *name, pa_parsed_address *ret_p) { const char *p; assert(name && ret_p); - memset(ret_p, 0, sizeof(struct pa_parsed_address)); + memset(ret_p, 0, sizeof(pa_parsed_address)); ret_p->type = PA_PARSED_ADDRESS_TCP_AUTO; if (*name == '{') { diff --git a/polyp/parseaddr.h b/polyp/parseaddr.h index 5ddc0351..f0efd766 100644 --- a/polyp/parseaddr.h +++ b/polyp/parseaddr.h @@ -24,19 +24,19 @@ #include -enum pa_parsed_address_type { +typedef enum pa_parsed_address_type { PA_PARSED_ADDRESS_UNIX, PA_PARSED_ADDRESS_TCP4, PA_PARSED_ADDRESS_TCP6, PA_PARSED_ADDRESS_TCP_AUTO -}; +} pa_parsed_address_type; -struct pa_parsed_address { - enum pa_parsed_address_type type; +typedef struct pa_parsed_address { + pa_parsed_address_type type; char *path_or_host; uint16_t port; -}; +} pa_parsed_address; -int pa_parse_address(const char *a, struct pa_parsed_address *ret_p); +int pa_parse_address(const char *a, pa_parsed_address *ret_p); #endif diff --git a/polyp/pax11publish.c b/polyp/pax11publish.c index a1cb006a..42947836 100644 --- a/polyp/pax11publish.c +++ b/polyp/pax11publish.c @@ -135,17 +135,17 @@ int main(int argc, char *argv[]) { } case EXPORT: { - struct pa_client_conf *c = pa_client_conf_new(); + pa_client_conf *conf = pa_client_conf_new(); uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; char hx[PA_NATIVE_COOKIE_LENGTH*2+1]; - assert(c); + assert(conf); - if (pa_client_conf_load(c, NULL) < 0) { + if (pa_client_conf_load(conf, NULL) < 0) { fprintf(stderr, "Failed to load client configuration file.\n"); goto finish; } - if (pa_client_conf_env(c) < 0) { + if (pa_client_conf_env(conf) < 0) { fprintf(stderr, "Failed to read environment configuration data.\n"); goto finish; } @@ -158,8 +158,8 @@ int main(int argc, char *argv[]) { if (server) pa_x11_set_prop(d, "POLYP_SERVER", server); - else if (c->default_server) - pa_x11_set_prop(d, "POLYP_SERVER", c->default_server); + else if (conf->default_server) + pa_x11_set_prop(d, "POLYP_SERVER", conf->default_server); else { char hn[256]; if (!pa_get_fqdn(hn, sizeof(hn))) { @@ -172,15 +172,15 @@ int main(int argc, char *argv[]) { if (sink) pa_x11_set_prop(d, "POLYP_SINK", sink); - else if (c->default_sink) - pa_x11_set_prop(d, "POLYP_SINK", c->default_sink); + else if (conf->default_sink) + pa_x11_set_prop(d, "POLYP_SINK", conf->default_sink); if (source) pa_x11_set_prop(d, "POLYP_SOURCE", source); - if (c->default_source) - pa_x11_set_prop(d, "POLYP_SOURCE", c->default_source); + if (conf->default_source) + pa_x11_set_prop(d, "POLYP_SOURCE", conf->default_source); - pa_client_conf_free(c); + pa_client_conf_free(conf); if (pa_authkey_load_auto(cookie_file, cookie, sizeof(cookie)) < 0) { fprintf(stderr, "Failed to load cookie data\n"); diff --git a/polyp/pdispatch.c b/polyp/pdispatch.c index 60dd911c..5a50a0d5 100644 --- a/polyp/pdispatch.c +++ b/polyp/pdispatch.c @@ -91,21 +91,21 @@ static const char *command_names[PA_COMMAND_MAX] = { #endif struct reply_info { - struct pa_pdispatch *pdispatch; + pa_pdispatch *pdispatch; PA_LLIST_FIELDS(struct reply_info); - void (*callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); + pa_pdispatch_callback callback; void *userdata; uint32_t tag; - struct pa_time_event *time_event; + pa_time_event *time_event; }; struct pa_pdispatch { int ref; - struct pa_mainloop_api *mainloop; - const struct pa_pdispatch_command *command_table; + pa_mainloop_api *mainloop; + const pa_pdispatch_callback *callback_table; unsigned n_commands; PA_LLIST_HEAD(struct reply_info, replies); - void (*drain_callback)(struct pa_pdispatch *pd, void *userdata); + pa_pdispatch_drain_callback drain_callback; void *drain_userdata; }; @@ -120,25 +120,25 @@ static void reply_info_free(struct reply_info *r) { pa_xfree(r); } -struct pa_pdispatch* pa_pdispatch_new(struct pa_mainloop_api *mainloop, const struct pa_pdispatch_command*table, unsigned entries) { - struct pa_pdispatch *pd; +pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_callback*table, unsigned entries) { + pa_pdispatch *pd; assert(mainloop); assert((entries && table) || (!entries && !table)); - pd = pa_xmalloc(sizeof(struct pa_pdispatch)); + pd = pa_xmalloc(sizeof(pa_pdispatch)); pd->ref = 1; pd->mainloop = mainloop; - pd->command_table = table; + pd->callback_table = table; pd->n_commands = entries; - PA_LLIST_HEAD_INIT(struct pa_reply_info, pd->replies); + PA_LLIST_HEAD_INIT(pa_reply_info, pd->replies); pd->drain_callback = NULL; pd->drain_userdata = NULL; return pd; } -void pdispatch_free(struct pa_pdispatch *pd) { +static void pdispatch_free(pa_pdispatch *pd) { assert(pd); while (pd->replies) @@ -147,8 +147,8 @@ void pdispatch_free(struct pa_pdispatch *pd) { pa_xfree(pd); } -static void run_action(struct pa_pdispatch *pd, struct reply_info *r, uint32_t command, struct pa_tagstruct *ts) { - void (*callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command, pa_tagstruct *ts) { + pa_pdispatch_callback callback; void *userdata; uint32_t tag; assert(r); @@ -169,9 +169,9 @@ static void run_action(struct pa_pdispatch *pd, struct reply_info *r, uint32_t c pa_pdispatch_unref(pd); } -int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *userdata) { +int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, void *userdata) { uint32_t tag, command; - struct pa_tagstruct *ts = NULL; + pa_tagstruct *ts = NULL; int ret = -1; assert(pd && packet && packet->data); @@ -208,10 +208,10 @@ int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *use if (r) run_action(pd, r, command, ts); - } else if (pd->command_table && (command < pd->n_commands) && pd->command_table[command].proc) { - const struct pa_pdispatch_command *c = pd->command_table+command; + } else if (pd->callback_table && (command < pd->n_commands) && pd->callback_table[command]) { + const pa_pdispatch_callback *c = pd->callback_table+command; - c->proc(pd, command, tag, ts, userdata); + (*c)(pd, command, tag, ts, userdata); } else { pa_log(__FILE__": Recieved unsupported command %u\n", command); goto finish; @@ -228,14 +228,14 @@ finish: return ret; } -static void timeout_callback(struct pa_mainloop_api*m, struct pa_time_event*e, const struct timeval *tv, void *userdata) { +static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { struct reply_info*r = userdata; assert(r && r->time_event == e && r->pdispatch && r->pdispatch->mainloop == m && r->callback); run_action(r->pdispatch, r, PA_COMMAND_TIMEOUT, NULL); } -void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int timeout, void (*cb)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void *userdata) { +void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_callback cb, void *userdata) { struct reply_info *r; struct timeval tv; assert(pd && pd->ref >= 1 && cb); @@ -255,13 +255,13 @@ void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int time PA_LLIST_PREPEND(struct reply_info, pd->replies, r); } -int pa_pdispatch_is_pending(struct pa_pdispatch *pd) { +int pa_pdispatch_is_pending(pa_pdispatch *pd) { assert(pd); return !!pd->replies; } -void pa_pdispatch_set_drain_callback(struct pa_pdispatch *pd, void (*cb)(struct pa_pdispatch *pd, void *userdata), void *userdata) { +void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, void (*cb)(pa_pdispatch *pd, void *userdata), void *userdata) { assert(pd); assert(!cb || pa_pdispatch_is_pending(pd)); @@ -269,7 +269,7 @@ void pa_pdispatch_set_drain_callback(struct pa_pdispatch *pd, void (*cb)(struct pd->drain_userdata = userdata; } -void pa_pdispatch_unregister_reply(struct pa_pdispatch *pd, void *userdata) { +void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata) { struct reply_info *r, *n; assert(pd); @@ -281,14 +281,14 @@ void pa_pdispatch_unregister_reply(struct pa_pdispatch *pd, void *userdata) { } } -void pa_pdispatch_unref(struct pa_pdispatch *pd) { +void pa_pdispatch_unref(pa_pdispatch *pd) { assert(pd && pd->ref >= 1); if (!(--(pd->ref))) pdispatch_free(pd); } -struct pa_pdispatch* pa_pdispatch_ref(struct pa_pdispatch *pd) { +pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd) { assert(pd && pd->ref >= 1); pd->ref++; return pd; diff --git a/polyp/pdispatch.h b/polyp/pdispatch.h index 571d0fb4..40f5d4c4 100644 --- a/polyp/pdispatch.h +++ b/polyp/pdispatch.h @@ -27,25 +27,24 @@ #include "packet.h" #include "mainloop-api.h" -struct pa_pdispatch; +typedef struct pa_pdispatch pa_pdispatch; -struct pa_pdispatch_command { - void (*proc)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -}; +typedef void (*pa_pdispatch_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -struct pa_pdispatch* pa_pdispatch_new(struct pa_mainloop_api *m, const struct pa_pdispatch_command*table, unsigned entries); -void pa_pdispatch_unref(struct pa_pdispatch *pd); -struct pa_pdispatch* pa_pdispatch_ref(struct pa_pdispatch *pd); +pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *m, const pa_pdispatch_callback*table, unsigned entries); +void pa_pdispatch_unref(pa_pdispatch *pd); +pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd); -int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*p, void *userdata); +int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*p, void *userdata); -void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int timeout, void (*cb)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void *userdata); +void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_callback callback, void *userdata); -int pa_pdispatch_is_pending(struct pa_pdispatch *pd); +int pa_pdispatch_is_pending(pa_pdispatch *pd); -void pa_pdispatch_set_drain_callback(struct pa_pdispatch *pd, void (*cb)(struct pa_pdispatch *pd, void *userdata), void *userdata); +typedef void (*pa_pdispatch_drain_callback)(pa_pdispatch *pd, void *userdata); +void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, pa_pdispatch_drain_callback callback, void *userdata); /* Remove all reply slots with the give userdata parameter */ -void pa_pdispatch_unregister_reply(struct pa_pdispatch *pd, void *userdata); +void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata); #endif diff --git a/polyp/play-memchunk.c b/polyp/play-memchunk.c index c7a85454..c3db1462 100644 --- a/polyp/play-memchunk.c +++ b/polyp/play-memchunk.c @@ -31,11 +31,12 @@ #include "play-memchunk.h" #include "sink-input.h" #include "xmalloc.h" +#include "gccmacro.h" #define PA_TYPEID_MEMCHUNK PA_TYPEID_MAKE('M', 'C', 'N', 'K') -static void sink_input_kill(struct pa_sink_input *i) { - struct pa_memchunk *c; +static void sink_input_kill(pa_sink_input *i) { + pa_memchunk *c; assert(i && i->userdata); c = i->userdata; @@ -47,8 +48,8 @@ static void sink_input_kill(struct pa_sink_input *i) { } -static int sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { - struct pa_memchunk *c; +static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { + pa_memchunk *c; assert(i && chunk && i->userdata); c = i->userdata; @@ -62,12 +63,12 @@ static int sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { return 0; } -static void si_kill(struct pa_mainloop_api *m, void *i) { +static void si_kill(PA_GCC_UNUSED pa_mainloop_api *m, void *i) { sink_input_kill(i); } -static void sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk*chunk, size_t length) { - struct pa_memchunk *c; +static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) { + pa_memchunk *c; assert(i && length && i->userdata); c = i->userdata; @@ -81,9 +82,9 @@ static void sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk*ch pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i); } -int pa_play_memchunk(struct pa_sink *sink, const char *name, const struct pa_sample_spec *ss, const struct pa_memchunk *chunk, pa_volume_t volume) { - struct pa_sink_input *si; - struct pa_memchunk *nchunk; +int pa_play_memchunk(pa_sink *sink, const char *name, const pa_sample_spec *ss, const pa_memchunk *chunk, pa_volume_t volume) { + pa_sink_input *si; + pa_memchunk *nchunk; assert(sink && chunk); @@ -98,7 +99,7 @@ int pa_play_memchunk(struct pa_sink *sink, const char *name, const struct pa_sam si->drop = sink_input_drop; si->kill = sink_input_kill; - si->userdata = nchunk = pa_xmalloc(sizeof(struct pa_memchunk)); + si->userdata = nchunk = pa_xmalloc(sizeof(pa_memchunk)); *nchunk = *chunk; pa_memblock_ref(chunk->memblock); diff --git a/polyp/play-memchunk.h b/polyp/play-memchunk.h index c69165a2..247cc870 100644 --- a/polyp/play-memchunk.h +++ b/polyp/play-memchunk.h @@ -25,6 +25,6 @@ #include "sink.h" #include "memchunk.h" -int pa_play_memchunk(struct pa_sink *sink, const char *name, const struct pa_sample_spec *ss, const struct pa_memchunk *chunk, pa_volume_t volume); +int pa_play_memchunk(pa_sink *sink, const char *name, const pa_sample_spec *ss, const pa_memchunk *chunk, pa_volume_t volume); #endif diff --git a/polyp/polyplib-browser.c b/polyp/polyplib-browser.c index 2e75a42d..6fee84a4 100644 --- a/polyp/polyplib-browser.c +++ b/polyp/polyplib-browser.c @@ -31,20 +31,20 @@ #define SERVICE_NAME_SOURCE "_polypaudio-source._tcp." #define SERVICE_NAME_SERVER "_polypaudio-server._tcp." -struct pa_browser { +pa_browser { int ref; - struct pa_mainloop_api *mainloop; + pa_mainloop_api *mainloop; - void (*callback)(struct pa_browser *z, enum pa_browse_opcode c, const struct pa_browse_info *i, void *userdata); + void (*callback)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void *userdata); void *callback_userdata; sw_discovery discovery; - struct pa_io_event *io_event; + pa_io_event *io_event; }; -static void io_callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enum pa_io_event_flags events, void *userdata) { - struct pa_browser *b = userdata; +static void io_callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags events, void *userdata) { + pa_browser *b = userdata; assert(a && b && b->mainloop == a); if (events != PA_IO_EVENT_INPUT || sw_discovery_read_socket(b->discovery) != SW_OKAY) { @@ -68,14 +68,14 @@ static sw_result resolve_reply( sw_ulong text_record_len, sw_opaque extra) { - struct pa_browser *b = extra; - struct pa_browse_info i; + pa_browser *b = extra; + pa_browse_info i; char ip[256], a[256]; - enum pa_browse_opcode opcode; + pa_browse_opcode opcode; int device_found = 0; uint32_t cookie; pa_typeid_t typeid; - struct pa_sample_spec ss; + pa_sample_spec ss; int ss_valid = 0; sw_text_record_iterator iterator; int free_iterator = 0; @@ -221,7 +221,7 @@ static sw_result browse_reply( sw_const_string domain, sw_opaque extra) { - struct pa_browser *b = extra; + pa_browser *b = extra; assert(b); switch (status) { @@ -236,7 +236,7 @@ static sw_result browse_reply( case SW_DISCOVERY_BROWSE_REMOVE_SERVICE: if (b->callback) { - struct pa_browse_info i; + pa_browse_info i; memset(&i, 0, sizeof(i)); i.name = name; b->callback(b, PA_BROWSE_REMOVE, &i, b->callback_userdata); @@ -250,11 +250,11 @@ static sw_result browse_reply( return SW_OKAY; } -struct pa_browser *pa_browser_new(struct pa_mainloop_api *mainloop) { - struct pa_browser *b; +pa_browser *pa_browser_new(pa_mainloop_api *mainloop) { + pa_browser *b; sw_discovery_oid oid; - b = pa_xmalloc(sizeof(struct pa_browser)); + b = pa_xmalloc(sizeof(pa_browser)); b->mainloop = mainloop; b->ref = 1; b->callback = NULL; @@ -281,7 +281,7 @@ struct pa_browser *pa_browser_new(struct pa_mainloop_api *mainloop) { return b; } -static void browser_free(struct pa_browser *b) { +static void browser_free(pa_browser *b) { assert(b && b->mainloop); if (b->io_event) @@ -291,20 +291,20 @@ static void browser_free(struct pa_browser *b) { pa_xfree(b); } -struct pa_browser *pa_browser_ref(struct pa_browser *b) { +pa_browser *pa_browser_ref(pa_browser *b) { assert(b && b->ref >= 1); b->ref++; return b; } -void pa_browser_unref(struct pa_browser *b) { +void pa_browser_unref(pa_browser *b) { assert(b && b->ref >= 1); if ((-- (b->ref)) <= 0) browser_free(b); } -void pa_browser_set_callback(struct pa_browser *b, void (*cb)(struct pa_browser *z, enum pa_browse_opcode c, const struct pa_browse_info *i, void* userdata), void *userdata) { +void pa_browser_set_callback(pa_browser *b, void (*cb)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void* userdata), void *userdata) { assert(b); b->callback = cb; diff --git a/polyp/polyplib-browser.h b/polyp/polyplib-browser.h index c13eff22..853304d7 100644 --- a/polyp/polyplib-browser.h +++ b/polyp/polyplib-browser.h @@ -29,20 +29,20 @@ PA_C_DECL_BEGIN -struct pa_browser; +pa_browser; -enum pa_browse_opcode { +pa_browse_opcode { PA_BROWSE_NEW_SERVER, PA_BROWSE_NEW_SINK, PA_BROWSE_NEW_SOURCE, PA_BROWSE_REMOVE }; -struct pa_browser *pa_browser_new(struct pa_mainloop_api *mainloop); -struct pa_browser *pa_browser_ref(struct pa_browser *z); -void pa_browser_unref(struct pa_browser *z); +pa_browser *pa_browser_new(pa_mainloop_api *mainloop); +pa_browser *pa_browser_ref(pa_browser *z); +void pa_browser_unref(pa_browser *z); -struct pa_browse_info { +pa_browse_info { /* Unique service name */ const char *name; /* always available */ @@ -55,10 +55,10 @@ struct pa_browse_info { const char *device; /* always available when this information is of a sink/source */ const char *description; /* optional */ const pa_typeid_t *typeid; /* optional */ - const struct pa_sample_spec *sample_spec; /* optional */ + const pa_sample_spec *sample_spec; /* optional */ }; -void pa_browser_set_callback(struct pa_browser *z, void (*cb)(struct pa_browser *z, enum pa_browse_opcode c, const struct pa_browse_info *i, void *userdata), void *userdata); +void pa_browser_set_callback(pa_browser *z, void (*cb)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void *userdata), void *userdata); PA_C_DECL_END diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index f97d9b82..0cf32490 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -49,6 +49,7 @@ #include "polyplib-internal.h" #include "polyplib-context.h" +#include "polyplib-version.h" #include "native-common.h" #include "pdispatch.h" #include "pstream.h" @@ -67,14 +68,14 @@ #define AUTOSPAWN_LOCK "autospawn.lock" -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_REQUEST] = { pa_command_request }, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { pa_command_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { pa_command_stream_killed }, - [PA_COMMAND_SUBSCRIBE_EVENT] = { pa_command_subscribe_event }, +static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_REQUEST] = pa_command_request, + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = pa_command_stream_killed, + [PA_COMMAND_RECORD_STREAM_KILLED] = pa_command_stream_killed, + [PA_COMMAND_SUBSCRIBE_EVENT] = pa_command_subscribe_event }; -static void unlock_autospawn_lock_file(struct pa_context *c) { +static void unlock_autospawn_lock_file(pa_context *c) { assert(c); if (c->autospawn_lock_fd >= 0) { @@ -86,11 +87,11 @@ static void unlock_autospawn_lock_file(struct pa_context *c) { } } -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { - struct pa_context *c; +pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { + pa_context *c; assert(mainloop && name); - c = pa_xmalloc(sizeof(struct pa_context)); + c = pa_xmalloc(sizeof(pa_context)); c->ref = 1; c->name = pa_xstrdup(name); c->mainloop = mainloop; @@ -101,8 +102,8 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * c->record_streams = pa_dynarray_new(); assert(c->playback_streams && c->record_streams); - PA_LLIST_HEAD_INIT(struct pa_stream, c->streams); - PA_LLIST_HEAD_INIT(struct pa_operation, c->operations); + PA_LLIST_HEAD_INIT(pa_stream, c->streams); + PA_LLIST_HEAD_INIT(pa_operation, c->operations); c->error = PA_ERROR_OK; c->state = PA_CONTEXT_UNCONNECTED; @@ -136,7 +137,7 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * return c; } -static void context_free(struct pa_context *c) { +static void context_free(pa_context *c) { assert(c); unlock_autospawn_lock_file(c); @@ -173,20 +174,20 @@ static void context_free(struct pa_context *c) { pa_xfree(c); } -struct pa_context* pa_context_ref(struct pa_context *c) { +pa_context* pa_context_ref(pa_context *c) { assert(c && c->ref >= 1); c->ref++; return c; } -void pa_context_unref(struct pa_context *c) { +void pa_context_unref(pa_context *c) { assert(c && c->ref >= 1); if ((--(c->ref)) == 0) context_free(c); } -void pa_context_set_state(struct pa_context *c, enum pa_context_state st) { +void pa_context_set_state(pa_context *c, pa_context_state st) { assert(c); if (c->state == st) @@ -195,11 +196,11 @@ void pa_context_set_state(struct pa_context *c, enum pa_context_state st) { pa_context_ref(c); if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) { - struct pa_stream *s; + pa_stream *s; s = c->streams ? pa_stream_ref(c->streams) : NULL; while (s) { - struct pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL; + pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL; pa_stream_set_state(s, st == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED); pa_stream_unref(s); s = n; @@ -227,20 +228,20 @@ void pa_context_set_state(struct pa_context *c, enum pa_context_state st) { pa_context_unref(c); } -void pa_context_fail(struct pa_context *c, int error) { +void pa_context_fail(pa_context *c, int error) { assert(c); c->error = error; pa_context_set_state(c, PA_CONTEXT_FAILED); } -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { - struct pa_context *c = userdata; +static void pstream_die_callback(pa_pstream *p, void *userdata) { + pa_context *c = userdata; assert(p && c); pa_context_fail(c, PA_ERROR_CONNECTIONTERMINATED); } -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { - struct pa_context *c = userdata; +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { + pa_context *c = userdata; assert(p && packet && c); pa_context_ref(c); @@ -253,9 +254,9 @@ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *pack pa_context_unref(c); } -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; +static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, PA_GCC_UNUSED uint32_t delta, const pa_memchunk *chunk, void *userdata) { + pa_context *c = userdata; + pa_stream *s; assert(p && chunk && c && chunk->memblock && chunk->memblock->data); pa_context_ref(c); @@ -264,7 +265,7 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, ui pa_mcalign_push(s->mcalign, chunk); for (;;) { - struct pa_memchunk t; + pa_memchunk t; if (pa_mcalign_pop(s->mcalign, &t) < 0) break; @@ -281,7 +282,7 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, ui pa_context_unref(c); } -int pa_context_handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { +int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t) { assert(c); if (command == PA_COMMAND_ERROR) { @@ -302,8 +303,8 @@ int pa_context_handle_error(struct pa_context *c, uint32_t command, struct pa_ta return 0; } -static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; +static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_context *c = userdata; assert(pd && c && (c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME)); pa_context_ref(c); @@ -319,13 +320,12 @@ static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, u switch(c->state) { case PA_CONTEXT_AUTHORIZING: { - struct pa_tagstruct *t; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_CLIENT_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, c->name); - pa_pstream_send_tagstruct(c->pstream, t); + pa_tagstruct *reply; + reply = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME); + pa_tagstruct_putu32(reply, tag = c->ctag++); + pa_tagstruct_puts(reply, c->name); + pa_pstream_send_tagstruct(c->pstream, reply); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); pa_context_set_state(c, PA_CONTEXT_SETTING_NAME); @@ -344,8 +344,8 @@ finish: pa_context_unref(c); } -static void setup_context(struct pa_context *c, struct pa_iochannel *io) { - struct pa_tagstruct *t; +static void setup_context(pa_context *c, pa_iochannel *io) { + pa_tagstruct *t; uint32_t tag; assert(c && io); @@ -383,15 +383,15 @@ finish: pa_context_unref(c); } -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata); +static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata); #ifndef OS_IS_WIN32 -static int context_connect_spawn(struct pa_context *c) { +static int context_connect_spawn(pa_context *c) { pid_t pid; int status, r; int fds[2] = { -1, -1} ; - struct pa_iochannel *io; + pa_iochannel *io; pa_context_ref(c); @@ -423,7 +423,7 @@ static int context_connect_spawn(struct pa_context *c) { char t[128]; const char *state = NULL; #define MAX_ARGS 64 - char *argv[MAX_ARGS+1]; + const char * argv[MAX_ARGS+1]; int n; /* Not required, since fds[0] has CLOEXEC enabled anyway */ @@ -453,7 +453,7 @@ static int context_connect_spawn(struct pa_context *c) { argv[n++] = NULL; - execv(argv[0], argv); + execv(argv[0], (char * const *) argv); _exit(1); #undef MAX_ARGS } @@ -502,7 +502,7 @@ fail: #endif /* OS_IS_WIN32 */ -static int try_next_connection(struct pa_context *c) { +static int try_next_connection(pa_context *c) { char *u = NULL; int r = -1; assert(c && !c->client); @@ -549,8 +549,8 @@ finish: return r; } -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { - struct pa_context *c = userdata; +static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata) { + pa_context *c = userdata; assert(client && c && c->state == PA_CONTEXT_CONNECTING); pa_context_ref(c); @@ -576,7 +576,7 @@ finish: pa_context_unref(c); } -int pa_context_connect(struct pa_context *c, const char *server, int spawn, const struct pa_spawn_api *api) { +int pa_context_connect(pa_context *c, const char *server, int spawn, const pa_spawn_api *api) { int r = -1; assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED); @@ -639,28 +639,28 @@ finish: return r; } -void pa_context_disconnect(struct pa_context *c) { +void pa_context_disconnect(pa_context *c) { assert(c); pa_context_set_state(c, PA_CONTEXT_TERMINATED); } -enum pa_context_state pa_context_get_state(struct pa_context *c) { +pa_context_state pa_context_get_state(pa_context *c) { assert(c && c->ref >= 1); return c->state; } -int pa_context_errno(struct pa_context *c) { +int pa_context_errno(pa_context *c) { assert(c && c->ref >= 1); return c->error; } -void pa_context_set_state_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { +void pa_context_set_state_callback(pa_context *c, void (*cb)(pa_context *c, void *userdata), void *userdata) { assert(c && c->ref >= 1); c->state_callback = cb; c->state_userdata = userdata; } -int pa_context_is_pending(struct pa_context *c) { +int pa_context_is_pending(pa_context *c) { assert(c && c->ref >= 1); /* pa_log("pstream: %i\n", pa_pstream_is_pending(c->pstream)); */ @@ -671,17 +671,17 @@ int pa_context_is_pending(struct pa_context *c) { c->client; } -static void set_dispatch_callbacks(struct pa_operation *o); +static void set_dispatch_callbacks(pa_operation *o); -static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { +static void pdispatch_drain_callback(PA_GCC_UNUSED pa_pdispatch*pd, void *userdata) { set_dispatch_callbacks(userdata); } -static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { +static void pstream_drain_callback(PA_GCC_UNUSED pa_pstream *s, void *userdata) { set_dispatch_callbacks(userdata); } -static void set_dispatch_callbacks(struct pa_operation *o) { +static void set_dispatch_callbacks(pa_operation *o) { int done = 1; assert(o && o->context && o->context->ref >= 1 && o->ref >= 1 && o->context->state == PA_CONTEXT_READY); @@ -702,8 +702,8 @@ static void set_dispatch_callbacks(struct pa_operation *o) { pa_operation_ref(o); else { if (o->callback) { - void (*cb)(struct pa_context *c, void *userdata); - cb = (void (*)(struct pa_context*, void*)) o->callback; + void (*cb)(pa_context *c, void *userdata); + cb = (void (*)(pa_context*, void*)) o->callback; cb(o->context, o->userdata); } @@ -713,8 +713,8 @@ static void set_dispatch_callbacks(struct pa_operation *o) { pa_operation_unref(o); } -struct pa_operation* pa_context_drain(struct pa_context *c, void (*cb) (struct pa_context*c, void *userdata), void *userdata) { - struct pa_operation *o; +pa_operation* pa_context_drain(pa_context *c, void (*cb) (pa_context*c, void *userdata), void *userdata) { + pa_operation *o; assert(c && c->ref >= 1); if (c->state != PA_CONTEXT_READY) @@ -725,7 +725,7 @@ struct pa_operation* pa_context_drain(struct pa_context *c, void (*cb) (struct p o = pa_operation_new(c, NULL); assert(o); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; set_dispatch_callbacks(pa_operation_ref(o)); @@ -733,8 +733,8 @@ struct pa_operation* pa_context_drain(struct pa_context *c, void (*cb) (struct p return o; } -void pa_context_exit_daemon(struct pa_context *c) { - struct pa_tagstruct *t; +void pa_context_exit_daemon(pa_context *c) { + pa_tagstruct *t; assert(c && c->ref >= 1); t = pa_tagstruct_new(NULL, 0); @@ -744,8 +744,8 @@ void pa_context_exit_daemon(struct pa_context *c) { pa_pstream_send_tagstruct(c->pstream, t); } -void pa_context_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_operation *o = userdata; +void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; int success = 1; assert(pd && o && o->context && o->ref >= 1); @@ -760,7 +760,7 @@ void pa_context_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, u } if (o->callback) { - void (*cb)(struct pa_context *c, int success, void *userdata) = o->callback; + void (*cb)(pa_context *c, int _success, void *_userdata) = (void (*)(pa_context *c, int _success, void *_userdata)) o->callback; cb(o->context, success, o->userdata); } @@ -769,9 +769,9 @@ finish: pa_operation_unref(o); } -struct pa_operation* pa_context_send_simple_command(struct pa_context *c, uint32_t command, void (*internal_callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void (*cb)(), void *userdata) { - struct pa_tagstruct *t; - struct pa_operation *o; +pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, void (*internal_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata), void (*cb)(void), void *userdata) { + pa_tagstruct *t; + pa_operation *o; uint32_t tag; assert(c && cb); @@ -788,14 +788,14 @@ struct pa_operation* pa_context_send_simple_command(struct pa_context *c, uint32 return pa_operation_ref(o); } -struct pa_operation* pa_context_set_default_sink(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - struct pa_operation *o; +pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; uint32_t tag; assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -808,14 +808,14 @@ struct pa_operation* pa_context_set_default_sink(struct pa_context *c, const cha return pa_operation_ref(o); } -struct pa_operation* pa_context_set_default_source(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - struct pa_operation *o; +pa_operation* pa_context_set_default_source(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; uint32_t tag; assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -828,19 +828,19 @@ struct pa_operation* pa_context_set_default_source(struct pa_context *c, const c return pa_operation_ref(o); } -int pa_context_is_local(struct pa_context *c) { +int pa_context_is_local(pa_context *c) { assert(c); return c->local; } -struct pa_operation* pa_context_set_name(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - struct pa_operation *o; +pa_operation* pa_context_set_name(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; uint32_t tag; assert(c && name && cb); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -857,7 +857,7 @@ const char* pa_get_library_version(void) { return PACKAGE_VERSION; } -const char* pa_context_get_server(struct pa_context *c) { +const char* pa_context_get_server(pa_context *c) { if (!c->server) return NULL; diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h index 0283312a..80c1b601 100644 --- a/polyp/polyplib-context.h +++ b/polyp/polyplib-context.h @@ -49,31 +49,33 @@ PA_C_DECL_BEGIN -/** \struct pa_context +/** \pa_context * An opaque connection context to a daemon */ -struct pa_context; +typedef struct pa_context pa_context; /** Instantiate a new connection context with an abstract mainloop API * and an application name */ -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); +pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name); /** Decrease the reference counter of the context by one */ -void pa_context_unref(struct pa_context *c); +void pa_context_unref(pa_context *c); /** Increase the reference counter of the context by one */ -struct pa_context* pa_context_ref(struct pa_context *c); +pa_context* pa_context_ref(pa_context *c); + +typedef void (*pa_context_state_callback)(pa_context *c, void *userdata); /** Set a callback function that is called whenever the context status changes */ -void pa_context_set_state_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); +void pa_context_set_state_callback(pa_context *c, pa_context_state_callback callback, void *userdata); /** Return the error number of the last failed operation */ -int pa_context_errno(struct pa_context *c); +int pa_context_errno(pa_context *c); /** Return non-zero if some data is pending to be written to the connection */ -int pa_context_is_pending(struct pa_context *c); +int pa_context_is_pending(pa_context *c); /** Return the current context status */ -enum pa_context_state pa_context_get_state(struct pa_context *c); +pa_context_state pa_context_get_state(pa_context *c); /** Connect the context to the specified server. If server is NULL, connect to the default server. This routine may but will not always @@ -82,33 +84,33 @@ be notified when the connection is established. If spawn is non-zero and no specific server is specified or accessible a new daemon is spawned. If api is non-NULL, the functions specified in the structure are used when forking a new child process. */ -int pa_context_connect(struct pa_context *c, const char *server, int spawn, const struct pa_spawn_api *api); +int pa_context_connect(pa_context *c, const char *server, int spawn, const pa_spawn_api *api); /** Terminate the context connection immediately */ -void pa_context_disconnect(struct pa_context *c); +void pa_context_disconnect(pa_context *c); /** Drain the context. If there is nothing to drain, the function returns NULL */ -struct pa_operation* pa_context_drain(struct pa_context *c, void (*cb) (struct pa_context*c, void *userdata), void *userdata); +pa_operation* pa_context_drain(pa_context *c, void (*cb) (pa_context*c, void *userdata), void *userdata); /** Tell the daemon to exit. No operation object is returned as the * connection is terminated when the daemon quits, thus this operation * would never complete. */ -void pa_context_exit_daemon(struct pa_context *c); +void pa_context_exit_daemon(pa_context *c); /** Set the name of the default sink. \since 0.4 */ -struct pa_operation* pa_context_set_default_sink(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata); +pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata); /** Set the name of the default source. \since 0.4 */ -struct pa_operation* pa_context_set_default_source(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata); +pa_operation* pa_context_set_default_source(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata); /** Returns 1 when the connection is to a local daemon. Returns negative when no connection has been made yet. \since 0.5 */ -int pa_context_is_local(struct pa_context *c); +int pa_context_is_local(pa_context *c); /** Set a different application name for context on the server. \since 0.5 */ -struct pa_operation* pa_context_set_name(struct pa_context *c, const char *name, void(*cb)(struct pa_context*c, int success, void *userdata), void *userdata); +pa_operation* pa_context_set_name(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata); /** Return the server name this context is connected to. \since 0.7 */ -const char* pa_context_get_server(struct pa_context *c); +const char* pa_context_get_server(pa_context *c); PA_C_DECL_END diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index 9adb68fc..499282c4 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -35,7 +35,7 @@ PA_C_DECL_BEGIN /** The state of a connection context */ -enum pa_context_state { +typedef enum pa_context_state { PA_CONTEXT_UNCONNECTED, /**< The context hasn't been connected yet */ PA_CONTEXT_CONNECTING, /**< A connection is being established */ PA_CONTEXT_AUTHORIZING, /**< The client is authorizing itself to the daemon */ @@ -43,37 +43,37 @@ enum pa_context_state { PA_CONTEXT_READY, /**< The connection is established, the context is ready to execute operations */ PA_CONTEXT_FAILED, /**< The connection failed or was disconnected */ PA_CONTEXT_TERMINATED /**< The connection was terminated cleanly */ -}; +} pa_context_state; /** The state of a stream */ -enum pa_stream_state { +typedef enum pa_stream_state { PA_STREAM_DISCONNECTED, /**< The stream is not yet connected to any sink or source */ PA_STREAM_CREATING, /**< The stream is being created */ PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */ PA_STREAM_FAILED, /**< An error occured that made the stream invalid */ PA_STREAM_TERMINATED /**< The stream has been terminated cleanly */ -}; +} pa_stream_state; /** The state of an operation */ -enum pa_operation_state { +typedef enum pa_operation_state { PA_OPERATION_RUNNING, /**< The operation is still running */ PA_OPERATION_DONE, /**< The operation has been completed */ PA_OPERATION_CANCELED /**< The operation has been canceled */ -}; +} pa_operation_state; /** An invalid index */ #define PA_INVALID_INDEX ((uint32_t) -1) /** The direction of a pa_stream object */ -enum pa_stream_direction { +typedef enum pa_stream_direction { PA_STREAM_NODIRECTION, /**< Invalid direction */ PA_STREAM_PLAYBACK, /**< Playback stream */ PA_STREAM_RECORD, /**< Record stream */ PA_STREAM_UPLOAD /**< Sample upload stream */ -}; +} pa_stream_direction; /** Some special flags for stream connections. \since 0.6 */ -enum pa_stream_flags { +typedef enum pa_stream_flags { PA_STREAM_START_CORKED = 1, /**< Create the stream corked, requiring an explicit pa_stream_cork() call to uncork it. */ PA_STREAM_INTERPOLATE_LATENCY = 2 /**< Interpolate the latency for * this stream. When enabled, @@ -90,16 +90,16 @@ enum pa_stream_flags { * information. This is * especially useful on long latency * network connections. */ -}; +} pa_stream_flags; /** Playback and record buffer metrics */ -struct pa_buffer_attr{ +typedef struct pa_buffer_attr { uint32_t maxlength; /**< Maximum length of the buffer */ uint32_t tlength; /**< Playback only: target length of the buffer. The server tries to assure that at least tlength bytes are always available in the buffer */ uint32_t prebuf; /**< Playback only: pre-buffering. The server does not start with playback before at least prebug bytes are available in the buffer */ uint32_t minreq; /**< Playback only: minimum request. The server does not request less than minreq bytes from the client, instead waints until the buffer is free enough to request more bytes at once */ uint32_t fragsize; /**< Recording only: fragment size. The server sends data in blocks of fragsize bytes size. Large values deminish interactivity with other operations on the connection context but decrease control overhead. */ -}; +} pa_buffer_attr; /** Error values as used by pa_context_errno(). Use pa_strerror() to convert these values to human readable strings */ enum { @@ -122,7 +122,7 @@ enum { }; /** Subscription event mask, as used by pa_context_subscribe() */ -enum pa_subscription_mask { +typedef enum pa_subscription_mask { PA_SUBSCRIPTION_MASK_NULL = 0, /**< No events */ PA_SUBSCRIPTION_MASK_SINK = 1, /**< Sink events */ PA_SUBSCRIPTION_MASK_SOURCE = 2, /**< Source events */ @@ -133,10 +133,10 @@ enum pa_subscription_mask { PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, /**< Sample cache events */ PA_SUBSCRIPTION_MASK_SERVER = 128, /**< Other global server changes. \since 0.4 */ PA_SUBSCRIPTION_MASK_AUTOLOAD = 256 /**< Autoload table events. \since 0.5 */ -}; +} pa_subscription_mask; /** Subscription event types, as used by pa_context_subscribe() */ -enum pa_subscription_event_type { +typedef enum pa_subscription_event_type { PA_SUBSCRIPTION_EVENT_SINK = 0, /**< Event type: Sink */ PA_SUBSCRIPTION_EVENT_SOURCE = 1, /**< Event type: Source */ PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2, /**< Event type: Sink input */ @@ -152,7 +152,7 @@ enum pa_subscription_event_type { PA_SUBSCRIPTION_EVENT_CHANGE = 16, /**< A property of the object was modified */ PA_SUBSCRIPTION_EVENT_REMOVE = 32, /**< An object was removed */ PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32 /**< A mask to extract the event operation from an event value */ -}; +} pa_subscription_event_type; /** Return one if an event type t matches an event mask bitfield */ #define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) @@ -170,7 +170,7 @@ enum pa_subscription_event_type { * source_usec+buffer_usec+transport_usec-sink_usec. (Take care of * sign issues!) When connected to a monitor source sink_usec contains * the latency of the owning sink.*/ -struct pa_latency_info { +typedef struct pa_latency_info { pa_usec_t buffer_usec; /**< Time in usecs the current buffer takes to play. For both playback and record streams. */ pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. For playback streams and record streams connected to a monitor source. */ pa_usec_t source_usec; /**< Time in usecs a sample takes from being recorded to being delivered to the application. Only for record streams. \since 0.5*/ @@ -187,7 +187,7 @@ struct pa_latency_info { * 0.5 */ struct timeval timestamp; /**< The time when this latency info was current */ uint64_t counter; /**< The byte counter current when the latency info was requested. \since 0.6 */ -}; +} pa_latency_info; /** A structure for the spawn api. This may be used to integrate auto * spawned daemons into your application. For more information see @@ -196,7 +196,7 @@ struct pa_latency_info { * block or ignore SIGCHLD signals, since this cannot be done in a * thread compatible way. You might have to do this in * prefork/postfork. \since 0.4 */ -struct pa_spawn_api { +typedef struct pa_spawn_api { void (*prefork)(void); /**< Is called just before the fork in the parent process. May be NULL. */ void (*postfork)(void); /**< Is called immediately after the fork in the parent process. May be NULL.*/ void (*atfork)(void); /**< Is called immediately after the @@ -206,7 +206,7 @@ struct pa_spawn_api { * unconditionally, since a UNIX socket * (created using socketpair()) is * passed to the new process. */ -}; +} pa_spawn_api; PA_C_DECL_END diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 8677c813..09f9473a 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -43,109 +43,111 @@ struct pa_context { int ref; char *name; - struct pa_mainloop_api* mainloop; + pa_mainloop_api* mainloop; - struct pa_socket_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; + pa_socket_client *client; + pa_pstream *pstream; + pa_pdispatch *pdispatch; - struct pa_dynarray *record_streams, *playback_streams; - PA_LLIST_HEAD(struct pa_stream, streams); - PA_LLIST_HEAD(struct pa_operation, operations); + pa_dynarray *record_streams, *playback_streams; + PA_LLIST_HEAD(pa_stream, streams); + PA_LLIST_HEAD(pa_operation, operations); uint32_t ctag; uint32_t error; - enum pa_context_state state; + pa_context_state state; - void (*state_callback)(struct pa_context*c, void *userdata); + void (*state_callback)(pa_context*c, void *userdata); void *state_userdata; - void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); + void (*subscribe_callback)(pa_context *c, pa_subscription_event_type t, uint32_t idx, void *userdata); void *subscribe_userdata; - struct pa_memblock_stat *memblock_stat; + pa_memblock_stat *memblock_stat; int local; int do_autospawn; int autospawn_lock_fd; - struct pa_spawn_api spawn_api; + pa_spawn_api spawn_api; - struct pa_strlist *server_list; + pa_strlist *server_list; char *server; - struct pa_client_conf *conf; + pa_client_conf *conf; }; struct pa_stream { int ref; - struct pa_context *context; - struct pa_mainloop_api *mainloop; - PA_LLIST_FIELDS(struct pa_stream); + pa_context *context; + pa_mainloop_api *mainloop; + PA_LLIST_FIELDS(pa_stream); char *name; - struct pa_buffer_attr buffer_attr; - struct pa_sample_spec sample_spec; + pa_buffer_attr buffer_attr; + pa_sample_spec sample_spec; uint32_t channel; int channel_valid; uint32_t device_index; - enum pa_stream_direction direction; + pa_stream_direction direction; uint32_t requested_bytes; uint64_t counter; pa_usec_t previous_time; pa_usec_t previous_ipol_time; - enum pa_stream_state state; - struct pa_mcalign *mcalign; + pa_stream_state state; + pa_mcalign *mcalign; int interpolate; int corked; uint32_t ipol_usec; struct timeval ipol_timestamp; - struct pa_time_event *ipol_event; + pa_time_event *ipol_event; int ipol_requested; - void (*state_callback)(struct pa_stream*c, void *userdata); + void (*state_callback)(pa_stream*c, void *userdata); void *state_userdata; - void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); + void (*read_callback)(pa_stream *p, const void*data, size_t length, void *userdata); void *read_userdata; - void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); + void (*write_callback)(pa_stream *p, size_t length, void *userdata); void *write_userdata; }; +typedef void (*pa_operation_callback)(void); + struct pa_operation { int ref; - struct pa_context *context; - struct pa_stream *stream; - PA_LLIST_FIELDS(struct pa_operation); + pa_context *context; + pa_stream *stream; + PA_LLIST_FIELDS(pa_operation); - enum pa_operation_state state; + pa_operation_state state; void *userdata; - void (*callback)(); + pa_operation_callback callback; }; -void pa_command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -void pa_command_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -void pa_command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +void pa_command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -struct pa_operation *pa_operation_new(struct pa_context *c, struct pa_stream *s); -void pa_operation_done(struct pa_operation *o); +pa_operation *pa_operation_new(pa_context *c, pa_stream *s); +void pa_operation_done(pa_operation *o); -void pa_create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -void pa_stream_disconnect_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -void pa_context_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -void pa_stream_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_context_fail(struct pa_context *c, int error); -void pa_context_set_state(struct pa_context *c, enum pa_context_state st); -int pa_context_handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t); -struct pa_operation* pa_context_send_simple_command(struct pa_context *c, uint32_t command, void (*internal_callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void (*cb)(), void *userdata); +void pa_context_fail(pa_context *c, int error); +void pa_context_set_state(pa_context *c, pa_context_state st); +int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t); +pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, void (*internal_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata), void (*cb)(void), void *userdata); -void pa_stream_set_state(struct pa_stream *s, enum pa_stream_state st); +void pa_stream_set_state(pa_stream *s, pa_stream_state st); -void pa_stream_trash_ipol(struct pa_stream *s); +void pa_stream_trash_ipol(pa_stream *s); #endif diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index 5d6d64ab..91105969 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -29,12 +29,13 @@ #include "polyplib-context.h" #include "polyplib-internal.h" #include "pstream-util.h" +#include "gccmacro.h" /*** Statistics ***/ -static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_operation *o = userdata; - struct pa_stat_info i, *p = &i; +static void context_stat_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + pa_stat_info i, *p = &i; assert(pd && o && o->context && o->ref >= 1); if (command != PA_COMMAND_REPLY) { @@ -53,7 +54,7 @@ static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uin } if (o->callback) { - void (*cb)(struct pa_context *s, const struct pa_stat_info*i, void *userdata) = o->callback; + void (*cb)(pa_context *s, const pa_stat_info*_i, void *_userdata) = (void (*)(pa_context *s, const pa_stat_info*_i, void *_userdata)) o->callback; cb(o->context, p, o->userdata); } @@ -62,15 +63,15 @@ finish: pa_operation_unref(o); } -struct pa_operation* pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_stat_info*i, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_STAT, context_stat_callback, cb, userdata); +pa_operation* pa_context_stat(pa_context *c, void (*cb)(pa_context *c, const pa_stat_info*i, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_STAT, context_stat_callback, (pa_operation_callback) cb, userdata); } /*** Server Info ***/ -static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_operation *o = userdata; - struct pa_server_info i, *p = &i; +static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + pa_server_info i, *p = &i; assert(pd && o && o->context && o->ref >= 1); if (command != PA_COMMAND_REPLY) { @@ -93,7 +94,7 @@ static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t c } if (o->callback) { - void (*cb)(struct pa_context *s, const struct pa_server_info*i, void *userdata) = o->callback; + void (*cb)(pa_context *s, const pa_server_info*_i, void *_userdata) = (void (*)(pa_context *s, const pa_server_info*_i, void *_userdata)) o->callback; cb(o->context, p, o->userdata); } @@ -102,14 +103,14 @@ finish: pa_operation_unref(o); } -struct pa_operation* pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SERVER_INFO, context_get_server_info_callback, cb, userdata); +pa_operation* pa_context_get_server_info(pa_context *c, void (*cb)(pa_context *c, const pa_server_info*i, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SERVER_INFO, context_get_server_info_callback, (pa_operation_callback) cb, userdata); } /*** Sink Info ***/ -static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_operation *o = userdata; +static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; int eof = 1; assert(pd && o && o->context && o->ref >= 1); @@ -121,7 +122,7 @@ static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t com } else { while (!pa_tagstruct_eof(t)) { - struct pa_sink_info i; + pa_sink_info i; if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || @@ -139,14 +140,14 @@ static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t com } if (o->callback) { - void (*cb)(struct pa_context *s, const struct pa_sink_info*i, int eof, void *userdata) = o->callback; + void (*cb)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata)) o->callback; cb(o->context, &i, 0, o->userdata); } } } if (o->callback) { - void (*cb)(struct pa_context *s, const struct pa_sink_info*i, int eof, void *userdata) = o->callback; + void (*cb)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata)) o->callback; cb(o->context, NULL, eof, o->userdata); } @@ -155,24 +156,24 @@ finish: pa_operation_unref(o); } -struct pa_operation* pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INFO_LIST, context_get_sink_info_callback, cb, userdata); +pa_operation* pa_context_get_sink_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INFO_LIST, context_get_sink_info_callback, (pa_operation_callback) cb, userdata); } -struct pa_operation* pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - struct pa_operation *o; +pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; uint32_t tag; assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); + pa_tagstruct_putu32(t, idx); pa_tagstruct_puts(t, NULL); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, o); @@ -180,14 +181,14 @@ struct pa_operation* pa_context_get_sink_info_by_index(struct pa_context *c, uin return pa_operation_ref(o); } -struct pa_operation* pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - struct pa_operation *o; +pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; uint32_t tag; assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -203,8 +204,8 @@ struct pa_operation* pa_context_get_sink_info_by_name(struct pa_context *c, cons /*** Source info ***/ -static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_operation *o = userdata; +static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; int eof = 1; assert(pd && o && o->context && o->ref >= 1); @@ -216,7 +217,7 @@ static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t c } else { while (!pa_tagstruct_eof(t)) { - struct pa_source_info i; + pa_source_info i; if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || @@ -233,14 +234,14 @@ static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t c } if (o->callback) { - void (*cb)(struct pa_context *s, const struct pa_source_info*i, int eof, void *userdata) = o->callback; + void (*cb)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata)) o->callback; cb(o->context, &i, 0, o->userdata); } } } if (o->callback) { - void (*cb)(struct pa_context *s, const struct pa_source_info*i, int eof, void *userdata) = o->callback; + void (*cb)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata)) o->callback; cb(o->context, NULL, eof, o->userdata); } @@ -249,24 +250,24 @@ finish: pa_operation_unref(o); } -struct pa_operation* pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_INFO_LIST, context_get_source_info_callback, cb, userdata); +pa_operation* pa_context_get_source_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_INFO_LIST, context_get_source_info_callback, (pa_operation_callback) cb, userdata); } -struct pa_operation* pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - struct pa_operation *o; +pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; uint32_t tag; assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); + pa_tagstruct_putu32(t, idx); pa_tagstruct_puts(t, NULL); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, o); @@ -274,14 +275,14 @@ struct pa_operation* pa_context_get_source_info_by_index(struct pa_context *c, u return pa_operation_ref(o); } -struct pa_operation* pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - struct pa_operation *o; +pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; uint32_t tag; assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -297,8 +298,8 @@ struct pa_operation* pa_context_get_source_info_by_name(struct pa_context *c, co /*** Client info ***/ -static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_operation *o = userdata; +static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; int eof = 1; assert(pd && o && o->context && o->ref >= 1); @@ -310,7 +311,7 @@ static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t c } else { while (!pa_tagstruct_eof(t)) { - struct pa_client_info i; + pa_client_info i; if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || @@ -321,14 +322,14 @@ static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t c } if (o->callback) { - void (*cb)(struct pa_context *s, const struct pa_client_info*i, int eof, void *userdata) = o->callback; + void (*cb)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata)) o->callback; cb(o->context, &i, 0, o->userdata); } } } if (o->callback) { - void (*cb)(struct pa_context *s, const struct pa_client_info*i, int eof, void *userdata) = o->callback; + void (*cb)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata)) o->callback; cb(o->context, NULL, eof, o->userdata); } @@ -337,34 +338,34 @@ finish: pa_operation_unref(o); } -struct pa_operation* pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - struct pa_operation *o; +pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; uint32_t tag; assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); + pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, o); return pa_operation_ref(o); } -struct pa_operation* pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_CLIENT_INFO_LIST, context_get_client_info_callback, cb, userdata); +pa_operation* pa_context_get_client_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_CLIENT_INFO_LIST, context_get_client_info_callback, (pa_operation_callback) cb, userdata); } /*** Module info ***/ -static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_operation *o = userdata; +static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; int eof = 1; assert(pd && o && o->context && o->ref >= 1); @@ -376,7 +377,7 @@ static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t c } else { while (!pa_tagstruct_eof(t)) { - struct pa_module_info i; + pa_module_info i; if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || @@ -388,14 +389,14 @@ static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t c } if (o->callback) { - void (*cb)(struct pa_context *s, const struct pa_module_info*i, int eof, void *userdata) = o->callback; + void (*cb)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata)) o->callback; cb(o->context, &i, 0, o->userdata); } } } if (o->callback) { - void (*cb)(struct pa_context *s, const struct pa_module_info*i, int eof, void *userdata) = o->callback; + void (*cb)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata)) o->callback; cb(o->context, NULL, eof, o->userdata); } @@ -404,34 +405,34 @@ finish: pa_operation_unref(o); } -struct pa_operation* pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - struct pa_operation *o; +pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; uint32_t tag; assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); + pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, o); return pa_operation_ref(o); } -struct pa_operation* pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_MODULE_INFO_LIST, context_get_module_info_callback, cb, userdata); +pa_operation* pa_context_get_module_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_MODULE_INFO_LIST, context_get_module_info_callback, (pa_operation_callback) cb, userdata); } /*** Sink input info ***/ -static void context_get_sink_input_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_operation *o = userdata; +static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; int eof = 1; assert(pd && o && o->context && o->ref >= 1); @@ -443,7 +444,7 @@ static void context_get_sink_input_info_callback(struct pa_pdispatch *pd, uint32 } else { while (!pa_tagstruct_eof(t)) { - struct pa_sink_input_info i; + pa_sink_input_info i; if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || @@ -462,14 +463,14 @@ static void context_get_sink_input_info_callback(struct pa_pdispatch *pd, uint32 } if (o->callback) { - void (*cb)(struct pa_context *s, const struct pa_sink_input_info*i, int eof, void *userdata) = o->callback; + void (*cb)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata)) o->callback; cb(o->context, &i, 0, o->userdata); } } } if (o->callback) { - void (*cb)(struct pa_context *s, const struct pa_sink_input_info*i, int eof, void *userdata) = o->callback; + void (*cb)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata)) o->callback; cb(o->context, NULL, eof, o->userdata); } @@ -478,34 +479,34 @@ finish: pa_operation_unref(o); } -struct pa_operation* pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - struct pa_operation *o; +pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; uint32_t tag; assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INPUT_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); + pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_input_info_callback, o); return pa_operation_ref(o); } -struct pa_operation* pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INPUT_INFO_LIST, context_get_sink_input_info_callback, cb, userdata); +pa_operation* pa_context_get_sink_input_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INPUT_INFO_LIST, context_get_sink_input_info_callback, (pa_operation_callback) cb, userdata); } /*** Source output info ***/ -static void context_get_source_output_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_operation *o = userdata; +static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; int eof = 1; assert(pd && o && o->context && o->ref >= 1); @@ -517,7 +518,7 @@ static void context_get_source_output_info_callback(struct pa_pdispatch *pd, uin } else { while (!pa_tagstruct_eof(t)) { - struct pa_source_output_info i; + pa_source_output_info i; if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || @@ -535,14 +536,14 @@ static void context_get_source_output_info_callback(struct pa_pdispatch *pd, uin } if (o->callback) { - void (*cb)(struct pa_context *s, const struct pa_source_output_info*i, int eof, void *userdata) = o->callback; + void (*cb)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata)) o->callback; cb(o->context, &i, 0, o->userdata); } } } if (o->callback) { - void (*cb)(struct pa_context *s, const struct pa_source_output_info*i, int eof, void *userdata) = o->callback; + void (*cb)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata))o->callback; cb(o->context, NULL, eof, o->userdata); } @@ -551,46 +552,46 @@ finish: pa_operation_unref(o); } -struct pa_operation* pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - struct pa_operation *o; +pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; uint32_t tag; assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_OUTPUT_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); + pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_output_info_callback, o); return pa_operation_ref(o); } -struct pa_operation* pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, context_get_source_output_info_callback, cb, userdata); +pa_operation* pa_context_get_source_output_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, context_get_source_output_info_callback, (pa_operation_callback) cb, userdata); } /*** Volume manipulation ***/ -struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, uint32_t index, pa_volume_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_operation *o; - struct pa_tagstruct *t; +pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, pa_volume_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; uint32_t tag; - assert(c && index != PA_INVALID_INDEX); + assert(c && idx != PA_INVALID_INDEX); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); + pa_tagstruct_putu32(t, idx); pa_tagstruct_puts(t, NULL); pa_tagstruct_putu32(t, volume); pa_pstream_send_tagstruct(c->pstream, t); @@ -599,14 +600,14 @@ struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, u return pa_operation_ref(o); } -struct pa_operation* pa_context_set_sink_volume_by_name(struct pa_context *c, const char *name, pa_volume_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_operation *o; - struct pa_tagstruct *t; +pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, pa_volume_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; uint32_t tag; assert(c && name); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -621,20 +622,20 @@ struct pa_operation* pa_context_set_sink_volume_by_name(struct pa_context *c, co return pa_operation_ref(o); } -struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, pa_volume_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_operation *o; - struct pa_tagstruct *t; +pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, pa_volume_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; uint32_t tag; - assert(c && index != PA_INVALID_INDEX); + assert(c && idx != PA_INVALID_INDEX); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME); pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); + pa_tagstruct_putu32(t, idx); pa_tagstruct_putu32(t, volume); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); @@ -644,8 +645,8 @@ struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint /** Sample Cache **/ -static void context_get_sample_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_operation *o = userdata; +static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; int eof = 1; assert(pd && o && o->context && o->ref >= 1); @@ -657,7 +658,7 @@ static void context_get_sample_info_callback(struct pa_pdispatch *pd, uint32_t c } else { while (!pa_tagstruct_eof(t)) { - struct pa_sample_info i; + pa_sample_info i; if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || @@ -673,14 +674,14 @@ static void context_get_sample_info_callback(struct pa_pdispatch *pd, uint32_t c } if (o->callback) { - void (*cb)(struct pa_context *s, const struct pa_sample_info*i, int eof, void *userdata) = o->callback; + void (*cb)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata)) o->callback; cb(o->context, &i, 0, o->userdata); } } } if (o->callback) { - void (*cb)(struct pa_context *s, const struct pa_sample_info*i, int eof, void *userdata) = o->callback; + void (*cb)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata)) o->callback; cb(o->context, NULL, eof, o->userdata); } @@ -689,14 +690,14 @@ finish: pa_operation_unref(o); } -struct pa_operation* pa_context_get_sample_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - struct pa_operation *o; +pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; uint32_t tag; assert(c && cb && name); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -710,20 +711,20 @@ struct pa_operation* pa_context_get_sample_info_by_name(struct pa_context *c, co return pa_operation_ref(o); } -struct pa_operation* pa_context_get_sample_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - struct pa_operation *o; +pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; uint32_t tag; assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_SAMPLE_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); + pa_tagstruct_putu32(t, idx); pa_tagstruct_puts(t, NULL); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, o); @@ -731,60 +732,60 @@ struct pa_operation* pa_context_get_sample_info_by_index(struct pa_context *c, u return pa_operation_ref(o); } -struct pa_operation* pa_context_get_sample_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SAMPLE_INFO_LIST, context_get_sample_info_callback, cb, userdata); +pa_operation* pa_context_get_sample_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SAMPLE_INFO_LIST, context_get_sample_info_callback, (pa_operation_callback) cb, userdata); } -static struct pa_operation* command_kill(struct pa_context *c, uint32_t command, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_operation *o; - struct pa_tagstruct *t; +static pa_operation* command_kill(pa_context *c, uint32_t command, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; uint32_t tag; - assert(c && index != PA_INVALID_INDEX); + assert(c && idx != PA_INVALID_INDEX); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, command); pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); + pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); return pa_operation_ref(o); } -struct pa_operation* pa_context_kill_client(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - return command_kill(c, PA_COMMAND_KILL_CLIENT, index, cb, userdata); +pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + return command_kill(c, PA_COMMAND_KILL_CLIENT, idx, cb, userdata); } -struct pa_operation* pa_context_kill_sink_input(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - return command_kill(c, PA_COMMAND_KILL_SINK_INPUT, index, cb, userdata); +pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + return command_kill(c, PA_COMMAND_KILL_SINK_INPUT, idx, cb, userdata); } -struct pa_operation* pa_context_kill_source_output(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - return command_kill(c, PA_COMMAND_KILL_SOURCE_OUTPUT, index, cb, userdata); +pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + return command_kill(c, PA_COMMAND_KILL_SOURCE_OUTPUT, idx, cb, userdata); } -static void load_module_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_operation *o = userdata; - uint32_t index = -1; +static void load_module_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + uint32_t idx = -1; assert(pd && o && o->context && o->ref >= 1); if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; - } else if (pa_tagstruct_getu32(t, &index) < 0 || + } else if (pa_tagstruct_getu32(t, &idx) < 0 || !pa_tagstruct_eof(t)) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } if (o->callback) { - void (*cb)(struct pa_context *c, uint32_t index, void *userdata) = o->callback; - cb(o->context, index, o->userdata); + void (*cb)(pa_context *c, uint32_t _idx, void *_userdata) = (void (*)(pa_context *c, uint32_t _idx, void *_userdata)) o->callback; + cb(o->context, idx, o->userdata); } finish: @@ -792,14 +793,14 @@ finish: pa_operation_unref(o); } -struct pa_operation* pa_context_load_module(struct pa_context *c, const char*name, const char *argument, void (*cb)(struct pa_context *c, uint32_t index, void *userdata), void *userdata) { - struct pa_operation *o; - struct pa_tagstruct *t; +pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, void (*cb)(pa_context *c, uint32_t idx, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; uint32_t tag; assert(c && name && argument); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -813,14 +814,14 @@ struct pa_operation* pa_context_load_module(struct pa_context *c, const char*nam return pa_operation_ref(o); } -struct pa_operation* pa_context_unload_module(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - return command_kill(c, PA_COMMAND_UNLOAD_MODULE, index, cb, userdata); +pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + return command_kill(c, PA_COMMAND_UNLOAD_MODULE, idx, cb, userdata); } /*** Autoload stuff ***/ -static void context_get_autoload_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_operation *o = userdata; +static void context_get_autoload_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; int eof = 1; assert(pd && o && o->context && o->ref >= 1); @@ -832,7 +833,7 @@ static void context_get_autoload_info_callback(struct pa_pdispatch *pd, uint32_t } else { while (!pa_tagstruct_eof(t)) { - struct pa_autoload_info i; + pa_autoload_info i; if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || @@ -844,14 +845,14 @@ static void context_get_autoload_info_callback(struct pa_pdispatch *pd, uint32_t } if (o->callback) { - void (*cb)(struct pa_context *s, const struct pa_autoload_info*i, int eof, void *userdata) = o->callback; + void (*cb)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata)) o->callback; cb(o->context, &i, 0, o->userdata); } } } if (o->callback) { - void (*cb)(struct pa_context *s, const struct pa_autoload_info*i, int eof, void *userdata) = o->callback; + void (*cb)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata)) o->callback; cb(o->context, NULL, eof, o->userdata); } @@ -860,14 +861,14 @@ finish: pa_operation_unref(o); } -struct pa_operation* pa_context_get_autoload_info_by_name(struct pa_context *c, const char *name, enum pa_autoload_type type, void (*cb)(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - struct pa_operation *o; +pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; uint32_t tag; assert(c && cb && name); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -881,49 +882,49 @@ struct pa_operation* pa_context_get_autoload_info_by_name(struct pa_context *c, return pa_operation_ref(o); } -struct pa_operation* pa_context_get_autoload_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - struct pa_operation *o; +pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; uint32_t tag; - assert(c && cb && index != PA_INVALID_INDEX); + assert(c && cb && idx != PA_INVALID_INDEX); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_AUTOLOAD_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); + pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, o); return pa_operation_ref(o); } -struct pa_operation* pa_context_get_autoload_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, context_get_autoload_info_callback, cb, userdata); +pa_operation* pa_context_get_autoload_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, context_get_autoload_info_callback, (pa_operation_callback) cb, userdata); } -static void context_add_autoload_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_operation *o = userdata; - uint32_t index; +static void context_add_autoload_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + uint32_t idx; assert(pd && o && o->context && o->ref >= 1); if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; - index = PA_INVALID_INDEX; - } else if (pa_tagstruct_getu32(t, &index) || + idx = PA_INVALID_INDEX; + } else if (pa_tagstruct_getu32(t, &idx) || !pa_tagstruct_eof(t)) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } if (o->callback) { - void (*cb)(struct pa_context *s, uint32_t index, void *userdata) = o->callback; - cb(o->context, index, o->userdata); + void (*cb)(pa_context *s, uint32_t _idx, void *_userdata) = (void (*)(pa_context *s, uint32_t _idx, void *_userdata)) o->callback; + cb(o->context, idx, o->userdata); } @@ -933,14 +934,14 @@ finish: } -struct pa_operation* pa_context_add_autoload(struct pa_context *c, const char *name, enum pa_autoload_type type, const char *module, const char*argument, void (*cb)(struct pa_context *c, int success, void *userdata), void* userdata) { - struct pa_operation *o; - struct pa_tagstruct *t; +pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type type, const char *module, const char*argument, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { + pa_operation *o; + pa_tagstruct *t; uint32_t tag; assert(c && name && module && argument); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -956,14 +957,14 @@ struct pa_operation* pa_context_add_autoload(struct pa_context *c, const char *n return pa_operation_ref(o); } -struct pa_operation* pa_context_remove_autoload_by_name(struct pa_context *c, const char *name, enum pa_autoload_type type, void (*cb)(struct pa_context *c, int success, void *userdata), void* userdata) { - struct pa_operation *o; - struct pa_tagstruct *t; +pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { + pa_operation *o; + pa_tagstruct *t; uint32_t tag; assert(c && name); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -977,20 +978,20 @@ struct pa_operation* pa_context_remove_autoload_by_name(struct pa_context *c, co return pa_operation_ref(o); } -struct pa_operation* pa_context_remove_autoload_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void* userdata) { - struct pa_operation *o; - struct pa_tagstruct *t; +pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { + pa_operation *o; + pa_tagstruct *t; uint32_t tag; - assert(c && index != PA_INVALID_INDEX); + assert(c && idx != PA_INVALID_INDEX); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_AUTOLOAD); pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); + pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index 83cdba16..2848e22f 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -48,224 +48,224 @@ PA_C_DECL_BEGIN /** Stores information about sinks */ -struct pa_sink_info { +typedef struct pa_sink_info { const char *name; /**< Name of the sink */ uint32_t index; /**< Index of the sink */ const char *description; /**< Description of this sink */ - struct pa_sample_spec sample_spec; /**< Sample spec of this sink */ + pa_sample_spec sample_spec; /**< Sample spec of this sink */ uint32_t owner_module; /**< Index of the owning module of this sink, or PA_INVALID_INDEX */ pa_volume_t volume; /**< Volume of the sink */ uint32_t monitor_source; /**< Index of the monitor source connected to this sink */ const char *monitor_source_name; /**< The name of the monitor source */ pa_usec_t latency; /**< Length of filled playback buffer of this sink */ pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ -}; +} pa_sink_info; /** Get information about a sink by its name */ -struct pa_operation* pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata); /** Get information about a sink by its index */ -struct pa_operation* pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t id, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata); /** Get the complete sink list */ -struct pa_operation* pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_sink_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata); /** Stores information about sources */ -struct pa_source_info { +typedef struct pa_source_info { const char *name ; /**< Name of the source */ uint32_t index; /**< Index of the source */ const char *description; /**< Description of this source */ - struct pa_sample_spec sample_spec; /**< Sample spec of this source */ + pa_sample_spec sample_spec; /**< Sample spec of this source */ uint32_t owner_module; /**< Owning module index, or PA_INVALID_INDEX */ uint32_t monitor_of_sink; /**< If this is a monitor source the index of the owning sink, otherwise PA_INVALID_INDEX */ const char *monitor_of_sink_name; /**< Name of the owning sink, or PA_INVALID_INDEX */ pa_usec_t latency; /**< Length of filled record buffer of this source. \since 0.5 */ pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ -}; +} pa_source_info; /** Get information about a source by its name */ -struct pa_operation* pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata); /** Get information about a source by its index */ -struct pa_operation* pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t id, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata); /** Get the complete source list */ -struct pa_operation* pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_source_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata); /** Server information */ -struct pa_server_info { +typedef struct pa_server_info { const char *user_name; /**< User name of the daemon process */ const char *host_name; /**< Host name the daemon is running on */ const char *server_version; /**< Version string of the daemon */ const char *server_name; /**< Server package name (usually "polypaudio") */ - struct pa_sample_spec sample_spec; /**< Default sample specification */ + pa_sample_spec sample_spec; /**< Default sample specification */ const char *default_sink_name; /**< Name of default sink. \since 0.4 */ const char *default_source_name; /**< Name of default sink. \since 0.4*/ uint32_t cookie; /**< A random cookie for identifying this instance of polypaudio. \since 0.8 */ -}; +} pa_server_info; /** Get some information about the server */ -struct pa_operation* pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); +pa_operation* pa_context_get_server_info(pa_context *c, void (*cb)(pa_context *c, const pa_server_info*i, void *userdata), void *userdata); /** Stores information about modules */ -struct pa_module_info { +typedef struct pa_module_info { uint32_t index; /**< Index of the module */ const char*name, /**< Name of the module */ *argument; /**< Argument string of the module */ uint32_t n_used; /**< Usage counter or PA_INVALID_INDEX */ int auto_unload; /**< Non-zero if this is an autoloaded module */ -}; +} pa_module_info; /** Get some information about a module by its index */ -struct pa_operation* pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata); /** Get the complete list of currently loaded modules */ -struct pa_operation* pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_module_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata); /** Stores information about clients */ -struct pa_client_info { +typedef struct pa_client_info { uint32_t index; /**< Index of this client */ const char *name; /**< Name of this client */ uint32_t owner_module; /**< Index of the owning module, or PA_INVALID_INDEX */ pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ -}; +} pa_client_info; /** Get information about a client by its index */ -struct pa_operation* pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata); /** Get the complete client list */ -struct pa_operation* pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_client_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata); /** Stores information about sink inputs */ -struct pa_sink_input_info { +typedef struct pa_sink_input_info { uint32_t index; /**< Index of the sink input */ const char *name; /**< Name of the sink input */ uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ uint32_t sink; /**< Index of the connected sink */ - struct pa_sample_spec sample_spec; /**< The sample specification of the sink input */ + pa_sample_spec sample_spec; /**< The sample specification of the sink input */ pa_volume_t volume; /**< The volume of this sink input */ pa_usec_t buffer_usec; /**< Latency due to buffering in sink input, see pa_latency_info for details */ pa_usec_t sink_usec; /**< Latency of the sink device, see pa_latency_info for details */ const char *resample_method; /**< Thre resampling method used by this sink input. \since 0.7 */ pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ -}; +} pa_sink_input_info; /** Get some information about a sink input by its index */ -struct pa_operation* pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata); /** Get the complete sink input list */ -struct pa_operation* pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_sink_input_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata); /** Stores information about source outputs */ -struct pa_source_output_info { +typedef struct pa_source_output_info { uint32_t index; /**< Index of the sink input */ const char *name; /**< Name of the sink input */ uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ uint32_t source; /**< Index of the connected source */ - struct pa_sample_spec sample_spec; /**< The sample specification of the source output */ + pa_sample_spec sample_spec; /**< The sample specification of the source output */ pa_usec_t buffer_usec; /**< Latency due to buffering in the source output, see pa_latency_info for details. \since 0.5 */ pa_usec_t source_usec; /**< Latency of the source device, see pa_latency_info for details. \since 0.5 */ const char *resample_method; /**< Thre resampling method used by this source output. \since 0.7 */ pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ -}; +} pa_source_output_info; /** Get information about a source output by its index */ -struct pa_operation* pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata); /** Get the complete list of source outputs */ -struct pa_operation* pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_source_output_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata); /** Set the volume of a sink device specified by its index */ -struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, uint32_t index, pa_volume_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, pa_volume_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); /** Set the volume of a sink device specified by its name */ -struct pa_operation* pa_context_set_sink_volume_by_name(struct pa_context *c, const char *name, pa_volume_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, pa_volume_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); /** Set the volume of a sink input stream */ -struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, pa_volume_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, pa_volume_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); /** Memory block statistics */ -struct pa_stat_info { +typedef struct pa_stat_info { uint32_t memblock_total; /**< Currently allocated memory blocks */ uint32_t memblock_total_size; /**< Currentl total size of allocated memory blocks */ uint32_t memblock_allocated; /**< Allocated memory blocks during the whole lifetime of the daemon */ uint32_t memblock_allocated_size; /**< Total size of all memory blocks allocated during the whole lifetime of the daemon */ uint32_t scache_size; /**< Total size of all sample cache entries. \since 0.4 */ -}; +} pa_stat_info; /** Get daemon memory block statistics */ -struct pa_operation* pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_stat_info *i, void *userdata), void *userdata); +pa_operation* pa_context_stat(pa_context *c, void (*cb)(pa_context *c, const pa_stat_info *i, void *userdata), void *userdata); /** Stores information about sample cache entries */ -struct pa_sample_info { +typedef struct pa_sample_info { uint32_t index; /**< Index of this entry */ const char *name; /**< Name of this entry */ pa_volume_t volume; /**< Default volume of this entry */ - struct pa_sample_spec sample_spec; /**< Sample specification of the sampel */ + pa_sample_spec sample_spec; /**< Sample specification of the sampel */ pa_usec_t duration; /**< Duration of this entry */ uint32_t bytes; /**< Length of this sample in bytes. \since 0.4 */ int lazy; /**< Non-zero when this is a lazy cache entry. \since 0.5 */ const char *filename; /**< In case this is a lazy cache entry, the filename for the sound file to be loaded on demand. \since 0.5 */ -}; +} pa_sample_info; /** Get information about a sample by its name */ -struct pa_operation* pa_context_get_sample_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata); /** Get information about a sample by its index */ -struct pa_operation* pa_context_get_sample_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata); /** Get the complete list of samples stored in the daemon. */ -struct pa_operation* pa_context_get_sample_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_sample_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata); /** Kill a client. \since 0.5 */ -struct pa_operation* pa_context_kill_client(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); /** Kill a sink input. \since 0.5 */ -struct pa_operation* pa_context_kill_sink_input(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); /** Kill a source output. \since 0.5 */ -struct pa_operation* pa_context_kill_source_output(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); /** Load a module. \since 0.5 */ -struct pa_operation* pa_context_load_module(struct pa_context *c, const char*name, const char *argument, void (*cb)(struct pa_context *c, uint32_t index, void *userdata), void *userdata); +pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, void (*cb)(pa_context *c, uint32_t idx, void *userdata), void *userdata); /** Unload a module. \since 0.5 */ -struct pa_operation* pa_context_unload_module(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); /** Type of an autoload entry. \since 0.5 */ -enum pa_autoload_type { +typedef enum pa_autoload_type { PA_AUTOLOAD_SINK = 0, PA_AUTOLOAD_SOURCE = 1 -}; +} pa_autoload_type; /** Stores information about autoload entries. \since 0.5 */ -struct pa_autoload_info { +typedef struct pa_autoload_info { uint32_t index; /**< Index of this autoload entry */ const char *name; /**< Name of the sink or source */ - enum pa_autoload_type type; /**< Type of the autoload entry */ + pa_autoload_type type; /**< Type of the autoload entry */ const char *module; /**< Module name to load */ const char *argument; /**< Argument string for module */ -}; +} pa_autoload_info; /** Get info about a specific autoload entry. \since 0.6 */ -struct pa_operation* pa_context_get_autoload_info_by_name(struct pa_context *c, const char *name, enum pa_autoload_type type, void (*cb)(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); /** Get info about a specific autoload entry. \since 0.6 */ -struct pa_operation* pa_context_get_autoload_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); /** Get the complete list of autoload entries. \since 0.5 */ -struct pa_operation* pa_context_get_autoload_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_autoload_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); /** Add a new autoload entry. \since 0.5 */ -struct pa_operation* pa_context_add_autoload(struct pa_context *c, const char *name, enum pa_autoload_type type, const char *module, const char*argument, void (*cb)(struct pa_context *c, int index, void *userdata), void* userdata); +pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type type, const char *module, const char*argument, void (*cb)(pa_context *c, int idx, void *userdata), void* userdata); /** Remove an autoload entry. \since 0.6 */ -struct pa_operation* pa_context_remove_autoload_by_name(struct pa_context *c, const char *name, enum pa_autoload_type type, void (*cb)(struct pa_context *c, int success, void *userdata), void* userdata); +pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata); /** Remove an autoload entry. \since 0.6 */ -struct pa_operation* pa_context_remove_autoload_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, int success, void *userdata), void* userdata); +pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void* userdata); PA_C_DECL_END diff --git a/polyp/polyplib-operation.c b/polyp/polyplib-operation.c index 77fe70fa..3bee8cc7 100644 --- a/polyp/polyplib-operation.c +++ b/polyp/polyplib-operation.c @@ -29,11 +29,11 @@ #include "polyplib-internal.h" #include "polyplib-operation.h" -struct pa_operation *pa_operation_new(struct pa_context *c, struct pa_stream *s) { - struct pa_operation *o; +pa_operation *pa_operation_new(pa_context *c, pa_stream *s) { + pa_operation *o; assert(c); - o = pa_xmalloc(sizeof(struct pa_operation)); + o = pa_xmalloc(sizeof(pa_operation)); o->ref = 1; o->context = pa_context_ref(c); o->stream = s ? pa_stream_ref(s) : NULL; @@ -42,17 +42,17 @@ struct pa_operation *pa_operation_new(struct pa_context *c, struct pa_stream *s) o->userdata = NULL; o->callback = NULL; - PA_LLIST_PREPEND(struct pa_operation, o->context->operations, o); + PA_LLIST_PREPEND(pa_operation, o->context->operations, o); return pa_operation_ref(o); } -struct pa_operation *pa_operation_ref(struct pa_operation *o) { +pa_operation *pa_operation_ref(pa_operation *o) { assert(o && o->ref >= 1); o->ref++; return o; } -void pa_operation_unref(struct pa_operation *o) { +void pa_operation_unref(pa_operation *o) { assert(o && o->ref >= 1); if ((--(o->ref)) == 0) { @@ -62,7 +62,7 @@ void pa_operation_unref(struct pa_operation *o) { } } -static void operation_set_state(struct pa_operation *o, enum pa_operation_state st) { +static void operation_set_state(pa_operation *o, pa_operation_state st) { assert(o && o->ref >= 1); if (st == o->state) @@ -74,7 +74,7 @@ static void operation_set_state(struct pa_operation *o, enum pa_operation_state o->state = st; if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) { - PA_LLIST_REMOVE(struct pa_operation, o->context->operations, o); + PA_LLIST_REMOVE(pa_operation, o->context->operations, o); pa_context_unref(o->context); if (o->stream) pa_stream_unref(o->stream); @@ -87,17 +87,17 @@ static void operation_set_state(struct pa_operation *o, enum pa_operation_state } } -void pa_operation_cancel(struct pa_operation *o) { +void pa_operation_cancel(pa_operation *o) { assert(o && o->ref >= 1); operation_set_state(o, PA_OPERATION_CANCELED); } -void pa_operation_done(struct pa_operation *o) { +void pa_operation_done(pa_operation *o) { assert(o && o->ref >= 1); operation_set_state(o, PA_OPERATION_DONE); } -enum pa_operation_state pa_operation_get_state(struct pa_operation *o) { +pa_operation_state pa_operation_get_state(pa_operation *o) { assert(o && o->ref >= 1); return o->state; } diff --git a/polyp/polyplib-operation.h b/polyp/polyplib-operation.h index 5c3af49c..63dcbc9f 100644 --- a/polyp/polyplib-operation.h +++ b/polyp/polyplib-operation.h @@ -30,21 +30,21 @@ PA_C_DECL_BEGIN -/** \struct pa_operation +/** \pa_operation * An asynchronous operation object */ -struct pa_operation; +typedef struct pa_operation pa_operation; /** Increase the reference count by one */ -struct pa_operation *pa_operation_ref(struct pa_operation *o); +pa_operation *pa_operation_ref(pa_operation *o); /** Decrease the reference count by one */ -void pa_operation_unref(struct pa_operation *o); +void pa_operation_unref(pa_operation *o); /** Cancel the operation. Beware! This will not necessarily cancel the execution of the operation on the server side. */ -void pa_operation_cancel(struct pa_operation *o); +void pa_operation_cancel(pa_operation *o); /** Return the current status of the operation */ -enum pa_operation_state pa_operation_get_state(struct pa_operation *o); +pa_operation_state pa_operation_get_state(pa_operation *o); PA_C_DECL_END diff --git a/polyp/polyplib-scache.c b/polyp/polyplib-scache.c index bce5d18a..01c64828 100644 --- a/polyp/polyplib-scache.c +++ b/polyp/polyplib-scache.c @@ -32,8 +32,8 @@ #include "polyplib-internal.h" #include "pstream-util.h" -void pa_stream_connect_upload(struct pa_stream *s, size_t length) { - struct pa_tagstruct *t; +void pa_stream_connect_upload(pa_stream *s, size_t length) { + pa_tagstruct *t; uint32_t tag; assert(s && length); @@ -55,8 +55,8 @@ void pa_stream_connect_upload(struct pa_stream *s, size_t length) { pa_stream_unref(s); } -void pa_stream_finish_upload(struct pa_stream *s) { - struct pa_tagstruct *t; +void pa_stream_finish_upload(pa_stream *s) { + pa_tagstruct *t; uint32_t tag; assert(s); @@ -77,14 +77,14 @@ void pa_stream_finish_upload(struct pa_stream *s) { pa_stream_unref(s); } -struct pa_operation * pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_operation *o; - struct pa_tagstruct *t; +pa_operation * pa_context_play_sample(pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; uint32_t tag; assert(c && name && *name && (!dev || *dev)); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; if (!dev) @@ -104,14 +104,14 @@ struct pa_operation * pa_context_play_sample(struct pa_context *c, const char *n return pa_operation_ref(o); } -struct pa_operation* pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_operation *o; - struct pa_tagstruct *t; +pa_operation* pa_context_remove_sample(pa_context *c, const char *name, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; uint32_t tag; assert(c && name); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); diff --git a/polyp/polyplib-scache.h b/polyp/polyplib-scache.h index 8ec375ea..89d27597 100644 --- a/polyp/polyplib-scache.h +++ b/polyp/polyplib-scache.h @@ -34,16 +34,16 @@ PA_C_DECL_BEGIN /** Make this stream a sample upload stream */ -void pa_stream_connect_upload(struct pa_stream *s, size_t length); +void pa_stream_connect_upload(pa_stream *s, size_t length); /** Finish the sample upload, the stream name will become the sample name. You cancel a sample upload by issuing pa_stream_disconnect() */ -void pa_stream_finish_upload(struct pa_stream *s); +void pa_stream_finish_upload(pa_stream *s); /** Play a sample from the sample cache to the specified device. If the latter is NULL use the default sink. Returns an operation object */ -struct pa_operation* pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_play_sample(pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); /** Remove a sample from the sample cache. Returns an operation object which may be used to cancel the operation while it is running */ -struct pa_operation* pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_remove_sample(pa_context *c, const char *name, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); PA_C_DECL_END diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c index a73aacfa..b1357128 100644 --- a/polyp/polyplib-simple.c +++ b/polyp/polyplib-simple.c @@ -36,10 +36,10 @@ #include "log.h" struct pa_simple { - struct pa_mainloop *mainloop; - struct pa_context *context; - struct pa_stream *stream; - enum pa_stream_direction direction; + pa_mainloop *mainloop; + pa_context *context; + pa_stream *stream; + pa_stream_direction direction; int dead; @@ -48,11 +48,11 @@ struct pa_simple { pa_usec_t latency; }; -static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata); +static void read_callback(pa_stream *s, const void*data, size_t length, void *userdata); -static int check_error(struct pa_simple *p, int *perror) { - enum pa_context_state cst; - enum pa_stream_state sst; +static int check_error(pa_simple *p, int *rerror) { + pa_context_state cst; + pa_stream_state sst; assert(p); if ((cst = pa_context_get_state(p->context)) == PA_CONTEXT_FAILED) @@ -70,18 +70,18 @@ static int check_error(struct pa_simple *p, int *perror) { return 0; fail: - if (perror) - *perror = pa_context_errno(p->context); + if (rerror) + *rerror = pa_context_errno(p->context); p->dead = 1; return -1; } -static int iterate(struct pa_simple *p, int block, int *perror) { +static int iterate(pa_simple *p, int block, int *rerror) { assert(p && p->context && p->mainloop); - if (check_error(p, perror) < 0) + if (check_error(p, rerror) < 0) return -1; if (!block && !pa_context_is_pending(p->context)) @@ -89,12 +89,12 @@ static int iterate(struct pa_simple *p, int block, int *perror) { do { if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) { - if (perror) - *perror = PA_ERROR_INTERNAL; + if (rerror) + *rerror = PA_ERROR_INTERNAL; return -1; } - if (check_error(p, perror) < 0) + if (check_error(p, rerror) < 0) return -1; } while (pa_context_is_pending(p->context)); @@ -103,34 +103,34 @@ static int iterate(struct pa_simple *p, int block, int *perror) { while (pa_mainloop_deferred_pending(p->mainloop)) { if (pa_mainloop_iterate(p->mainloop, 0, NULL) < 0) { - if (perror) - *perror = PA_ERROR_INTERNAL; + if (rerror) + *rerror = PA_ERROR_INTERNAL; return -1; } - if (check_error(p, perror) < 0) + if (check_error(p, rerror) < 0) return -1; } return 0; } -struct pa_simple* pa_simple_new( +pa_simple* pa_simple_new( const char *server, const char *name, - enum pa_stream_direction dir, + pa_stream_direction dir, const char *dev, const char *stream_name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, + const pa_sample_spec *ss, + const pa_buffer_attr *attr, pa_volume_t volume, - int *perror) { + int *rerror) { - struct pa_simple *p; + pa_simple *p; int error = PA_ERROR_INTERNAL; assert(ss && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); - p = pa_xmalloc(sizeof(struct pa_simple)); + p = pa_xmalloc(sizeof(pa_simple)); p->context = NULL; p->stream = NULL; p->mainloop = pa_mainloop_new(); @@ -171,13 +171,13 @@ struct pa_simple* pa_simple_new( return p; fail: - if (perror) - *perror = error; + if (rerror) + *rerror = error; pa_simple_free(p); return NULL; } -void pa_simple_free(struct pa_simple *s) { +void pa_simple_free(pa_simple *s) { assert(s); pa_xfree(s->read_data); @@ -194,12 +194,12 @@ void pa_simple_free(struct pa_simple *s) { pa_xfree(s); } -int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *perror) { +int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { assert(p && data && p->direction == PA_STREAM_PLAYBACK); if (p->dead) { - if (perror) - *perror = pa_context_errno(p->context); + if (rerror) + *rerror = pa_context_errno(p->context); return -1; } @@ -208,26 +208,26 @@ int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *pe size_t l; while (!(l = pa_stream_writable_size(p->stream))) - if (iterate(p, 1, perror) < 0) + if (iterate(p, 1, rerror) < 0) return -1; if (l > length) l = length; pa_stream_write(p->stream, data, l, NULL, 0); - data = (uint8_t*) data + l; + data = (const uint8_t*) data + l; length -= l; } /* Make sure that no data is pending for write */ - if (iterate(p, 0, perror) < 0) + if (iterate(p, 0, rerror) < 0) return -1; return 0; } -static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata) { - struct pa_simple *p = userdata; +static void read_callback(pa_stream *s, const void*data, size_t length, void *userdata) { + pa_simple *p = userdata; assert(s && data && length && p); if (p->read_data) { @@ -239,12 +239,12 @@ static void read_callback(struct pa_stream *s, const void*data, size_t length, v p->read_index = 0; } -int pa_simple_read(struct pa_simple *p, void*data, size_t length, int *perror) { +int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { assert(p && data && p->direction == PA_STREAM_RECORD); if (p->dead) { - if (perror) - *perror = pa_context_errno(p->context); + if (rerror) + *rerror = pa_context_errno(p->context); return -1; } @@ -276,27 +276,27 @@ int pa_simple_read(struct pa_simple *p, void*data, size_t length, int *perror) { assert(!p->read_data); } - if (iterate(p, 1, perror) < 0) + if (iterate(p, 1, rerror) < 0) return -1; } return 0; } -static void drain_or_flush_complete(struct pa_stream *s, int success, void *userdata) { - struct pa_simple *p = userdata; +static void drain_or_flush_complete(pa_stream *s, int success, void *userdata) { + pa_simple *p = userdata; assert(s && p); if (!success) p->dead = 1; } -int pa_simple_drain(struct pa_simple *p, int *perror) { - struct pa_operation *o; +int pa_simple_drain(pa_simple *p, int *rerror) { + pa_operation *o; assert(p && p->direction == PA_STREAM_PLAYBACK); if (p->dead) { - if (perror) - *perror = pa_context_errno(p->context); + if (rerror) + *rerror = pa_context_errno(p->context); return -1; } @@ -304,7 +304,7 @@ int pa_simple_drain(struct pa_simple *p, int *perror) { o = pa_stream_drain(p->stream, drain_or_flush_complete, p); while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { - if (iterate(p, 1, perror) < 0) { + if (iterate(p, 1, rerror) < 0) { pa_operation_cancel(o); pa_operation_unref(o); return -1; @@ -313,14 +313,14 @@ int pa_simple_drain(struct pa_simple *p, int *perror) { pa_operation_unref(o); - if (p->dead && perror) - *perror = pa_context_errno(p->context); + if (p->dead && rerror) + *rerror = pa_context_errno(p->context); return p->dead ? -1 : 0; } -static void latency_complete(struct pa_stream *s, const struct pa_latency_info *l, void *userdata) { - struct pa_simple *p = userdata; +static void latency_complete(pa_stream *s, const pa_latency_info *l, void *userdata) { + pa_simple *p = userdata; assert(s && p); if (!l) @@ -333,13 +333,13 @@ static void latency_complete(struct pa_stream *s, const struct pa_latency_info * } } -pa_usec_t pa_simple_get_playback_latency(struct pa_simple *p, int *perror) { - struct pa_operation *o; +pa_usec_t pa_simple_get_playback_latency(pa_simple *p, int *rerror) { + pa_operation *o; assert(p && p->direction == PA_STREAM_PLAYBACK); if (p->dead) { - if (perror) - *perror = pa_context_errno(p->context); + if (rerror) + *rerror = pa_context_errno(p->context); return (pa_usec_t) -1; } @@ -349,7 +349,7 @@ pa_usec_t pa_simple_get_playback_latency(struct pa_simple *p, int *perror) { while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { - if (iterate(p, 1, perror) < 0) { + if (iterate(p, 1, rerror) < 0) { pa_operation_cancel(o); pa_operation_unref(o); return -1; @@ -358,19 +358,19 @@ pa_usec_t pa_simple_get_playback_latency(struct pa_simple *p, int *perror) { pa_operation_unref(o); - if (p->dead && perror) - *perror = pa_context_errno(p->context); + if (p->dead && rerror) + *rerror = pa_context_errno(p->context); return p->dead ? (pa_usec_t) -1 : p->latency; } -int pa_simple_flush(struct pa_simple *p, int *perror) { - struct pa_operation *o; +int pa_simple_flush(pa_simple *p, int *rerror) { + pa_operation *o; assert(p && p->direction == PA_STREAM_PLAYBACK); if (p->dead) { - if (perror) - *perror = pa_context_errno(p->context); + if (rerror) + *rerror = pa_context_errno(p->context); return -1; } @@ -378,7 +378,7 @@ int pa_simple_flush(struct pa_simple *p, int *perror) { o = pa_stream_flush(p->stream, drain_or_flush_complete, p); while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { - if (iterate(p, 1, perror) < 0) { + if (iterate(p, 1, rerror) < 0) { pa_operation_cancel(o); pa_operation_unref(o); return -1; @@ -387,8 +387,8 @@ int pa_simple_flush(struct pa_simple *p, int *perror) { pa_operation_unref(o); - if (p->dead && perror) - *perror = pa_context_errno(p->context); + if (p->dead && rerror) + *rerror = pa_context_errno(p->context); return p->dead ? -1 : 0; } diff --git a/polyp/polyplib-simple.h b/polyp/polyplib-simple.h index 9abef3fa..d1589115 100644 --- a/polyp/polyplib-simple.h +++ b/polyp/polyplib-simple.h @@ -41,40 +41,40 @@ PA_C_DECL_BEGIN -/** \struct pa_simple +/** \pa_simple * An opaque simple connection object */ -struct pa_simple; +typedef struct pa_simple pa_simple; /** Create a new connection to the server */ -struct pa_simple* pa_simple_new( +pa_simple* pa_simple_new( const char *server, /**< Server name, or NULL for default */ const char *name, /**< A descriptive name for this client (application name, ...) */ - enum pa_stream_direction dir, /**< Open this stream for recording or playback? */ + pa_stream_direction dir, /**< Open this stream for recording or playback? */ const char *dev, /**< Sink (resp. source) name, or NULL for default */ const char *stream_name, /**< A descriptive name for this client (application name, song title, ...) */ - const struct pa_sample_spec *ss, /**< The sample type to use */ - const struct pa_buffer_attr *attr, /**< Buffering attributes, or NULL for default */ + const pa_sample_spec *ss, /**< The sample type to use */ + const pa_buffer_attr *attr, /**< Buffering attributes, or NULL for default */ pa_volume_t volume, /**< Initial volume. Only for playback streams. \since 0.5 */ int *error /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */ ); /** Close and free the connection to the server. The connection objects becomes invalid when this is called. */ -void pa_simple_free(struct pa_simple *s); +void pa_simple_free(pa_simple *s); /** Write some data to the server */ -int pa_simple_write(struct pa_simple *s, const void*data, size_t length, int *error); +int pa_simple_write(pa_simple *s, const void*data, size_t length, int *error); /** Wait until all data already written is played by the daemon */ -int pa_simple_drain(struct pa_simple *s, int *error); +int pa_simple_drain(pa_simple *s, int *error); /** Read some data from the server */ -int pa_simple_read(struct pa_simple *s, void*data, size_t length, int *error); +int pa_simple_read(pa_simple *s, void*data, size_t length, int *error); /** Return the playback latency. \since 0.5 */ -pa_usec_t pa_simple_get_playback_latency(struct pa_simple *s, int *perror); +pa_usec_t pa_simple_get_playback_latency(pa_simple *s, int *error); /** Flush the playback buffer. \since 0.5 */ -int pa_simple_flush(struct pa_simple *s, int *perror); +int pa_simple_flush(pa_simple *s, int *error); PA_C_DECL_END diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index b6a091b3..6c8ed9c5 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -36,11 +36,11 @@ #define LATENCY_IPOL_INTERVAL_USEC (10000L) -struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const struct pa_sample_spec *ss) { - struct pa_stream *s; +pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss) { + pa_stream *s; assert(c && ss); - s = pa_xmalloc(sizeof(struct pa_stream)); + s = pa_xmalloc(sizeof(pa_stream)); s->ref = 1; s->context = c; s->mainloop = c->mainloop; @@ -76,12 +76,12 @@ struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const st s->ipol_event = NULL; s->ipol_requested = 0; - PA_LLIST_PREPEND(struct pa_stream, c->streams, s); + PA_LLIST_PREPEND(pa_stream, c->streams, s); return pa_stream_ref(s); } -static void stream_free(struct pa_stream *s) { +static void stream_free(pa_stream *s) { assert(s); if (s->ipol_event) { @@ -95,35 +95,35 @@ static void stream_free(struct pa_stream *s) { pa_xfree(s); } -void pa_stream_unref(struct pa_stream *s) { +void pa_stream_unref(pa_stream *s) { assert(s && s->ref >= 1); if (--(s->ref) == 0) stream_free(s); } -struct pa_stream* pa_stream_ref(struct pa_stream *s) { +pa_stream* pa_stream_ref(pa_stream *s) { assert(s && s->ref >= 1); s->ref++; return s; } -enum pa_stream_state pa_stream_get_state(struct pa_stream *s) { +pa_stream_state pa_stream_get_state(pa_stream *s) { assert(s && s->ref >= 1); return s->state; } -struct pa_context* pa_stream_get_context(struct pa_stream *s) { +pa_context* pa_stream_get_context(pa_stream *s) { assert(s && s->ref >= 1); return s->context; } -uint32_t pa_stream_get_index(struct pa_stream *s) { +uint32_t pa_stream_get_index(pa_stream *s) { assert(s && s->ref >= 1); return s->device_index; } -void pa_stream_set_state(struct pa_stream *s, enum pa_stream_state st) { +void pa_stream_set_state(pa_stream *s, pa_stream_state st) { assert(s && s->ref >= 1); if (s->state == st) @@ -137,7 +137,7 @@ void pa_stream_set_state(struct pa_stream *s, enum pa_stream_state st) { if (s->channel_valid) pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - PA_LLIST_REMOVE(struct pa_stream, s->context->streams, s); + PA_LLIST_REMOVE(pa_stream, s->context->streams, s); pa_stream_unref(s); } @@ -147,9 +147,9 @@ void pa_stream_set_state(struct pa_stream *s, enum pa_stream_state st) { pa_stream_unref(s); } -void pa_command_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; +void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_context *c = userdata; + pa_stream *s; uint32_t channel; assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); @@ -171,9 +171,9 @@ finish: pa_context_unref(c); } -void pa_command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s; - struct pa_context *c = userdata; +void pa_command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_stream *s; + pa_context *c = userdata; uint32_t bytes, channel; assert(pd && command == PA_COMMAND_REQUEST && t && c); @@ -205,9 +205,9 @@ finish: pa_context_unref(c); } -static void ipol_callback(struct pa_mainloop_api *m, struct pa_time_event *e, const struct timeval *tv, void *userdata) { +static void ipol_callback(pa_mainloop_api *m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { struct timeval tv2; - struct pa_stream *s = userdata; + pa_stream *s = userdata; pa_stream_ref(s); @@ -227,8 +227,8 @@ static void ipol_callback(struct pa_mainloop_api *m, struct pa_time_event *e, co } -void pa_create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; +void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_stream *s = userdata; assert(pd && s && s->state == PA_STREAM_CREATING); pa_stream_ref(s); @@ -271,8 +271,8 @@ finish: pa_stream_unref(s); } -static void create_stream(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, enum pa_stream_flags flags, pa_volume_t volume) { - struct pa_tagstruct *t; +static void create_stream(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags flags, pa_volume_t volume) { + pa_tagstruct *t; uint32_t tag; assert(s && s->ref >= 1 && s->state == PA_STREAM_DISCONNECTED); @@ -326,20 +326,20 @@ static void create_stream(struct pa_stream *s, const char *dev, const struct pa_ pa_stream_unref(s); } -void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, enum pa_stream_flags flags, pa_volume_t volume) { +void pa_stream_connect_playback(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags flags, pa_volume_t volume) { assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); s->direction = PA_STREAM_PLAYBACK; create_stream(s, dev, attr, flags, volume); } -void pa_stream_connect_record(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, enum pa_stream_flags flags) { +void pa_stream_connect_record(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags flags) { assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); s->direction = PA_STREAM_RECORD; create_stream(s, dev, attr, flags, 0); } -void pa_stream_write(struct pa_stream *s, const void *data, size_t length, void (*free_cb)(void *p), size_t delta) { - struct pa_memchunk chunk; +void pa_stream_write(pa_stream *s, const void *data, size_t length, void (*free_cb)(void *p), size_t delta) { + pa_memchunk chunk; assert(s && s->context && data && length && s->state == PA_STREAM_READY && s->ref >= 1); if (free_cb) { @@ -364,20 +364,20 @@ void pa_stream_write(struct pa_stream *s, const void *data, size_t length, void s->counter += length; } -size_t pa_stream_writable_size(struct pa_stream *s) { +size_t pa_stream_writable_size(pa_stream *s) { assert(s && s->ref >= 1); return s->state == PA_STREAM_READY ? s->requested_bytes : 0; } -struct pa_operation * pa_stream_drain(struct pa_stream *s, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_operation *o; - struct pa_tagstruct *t; +pa_operation * pa_stream_drain(pa_stream *s, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; uint32_t tag; assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); o = pa_operation_new(s->context, s); assert(o); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -391,9 +391,9 @@ struct pa_operation * pa_stream_drain(struct pa_stream *s, void (*cb) (struct pa return pa_operation_ref(o); } -static void stream_get_latency_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_operation *o = userdata; - struct pa_latency_info i, *p = NULL; +static void stream_get_latency_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + pa_latency_info i, *p = NULL; struct timeval local, remote, now; assert(pd && o && o->stream && o->context); @@ -444,7 +444,7 @@ static void stream_get_latency_info_callback(struct pa_pdispatch *pd, uint32_t c } if (o->callback) { - void (*cb)(struct pa_stream *s, const struct pa_latency_info *i, void *userdata) = o->callback; + void (*cb)(pa_stream *s, const pa_latency_info *_i, void *_userdata) = (void (*)(pa_stream *s, const pa_latency_info *_i, void *_userdata)) o->callback; cb(o->stream, p, o->userdata); } @@ -453,16 +453,16 @@ finish: pa_operation_unref(o); } -struct pa_operation* pa_stream_get_latency_info(struct pa_stream *s, void (*cb)(struct pa_stream *p, const struct pa_latency_info*i, void *userdata), void *userdata) { +pa_operation* pa_stream_get_latency_info(pa_stream *s, void (*cb)(pa_stream *p, const pa_latency_info*i, void *userdata), void *userdata) { uint32_t tag; - struct pa_operation *o; - struct pa_tagstruct *t; + pa_operation *o; + pa_tagstruct *t; struct timeval now; assert(s && s->direction != PA_STREAM_UPLOAD); o = pa_operation_new(s->context, s); assert(o); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -481,8 +481,8 @@ struct pa_operation* pa_stream_get_latency_info(struct pa_stream *s, void (*cb)( return pa_operation_ref(o); } -void pa_stream_disconnect_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; +void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_stream *s = userdata; assert(pd && s && s->ref >= 1); pa_stream_ref(s); @@ -504,8 +504,8 @@ finish: pa_stream_unref(s); } -void pa_stream_disconnect(struct pa_stream *s) { - struct pa_tagstruct *t; +void pa_stream_disconnect(pa_stream *s) { + pa_tagstruct *t; uint32_t tag; assert(s && s->ref >= 1); @@ -527,26 +527,26 @@ void pa_stream_disconnect(struct pa_stream *s) { pa_stream_unref(s); } -void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { +void pa_stream_set_read_callback(pa_stream *s, void (*cb)(pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { assert(s && s->ref >= 1); s->read_callback = cb; s->read_userdata = userdata; } -void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { +void pa_stream_set_write_callback(pa_stream *s, void (*cb)(pa_stream *p, size_t length, void *userdata), void *userdata) { assert(s && s->ref >= 1); s->write_callback = cb; s->write_userdata = userdata; } -void pa_stream_set_state_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { +void pa_stream_set_state_callback(pa_stream *s, void (*cb)(pa_stream *s, void *userdata), void *userdata) { assert(s && s->ref >= 1); s->state_callback = cb; s->state_userdata = userdata; } -void pa_stream_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_operation *o = userdata; +void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; int success = 1; assert(pd && o && o->context && o->ref >= 1); @@ -561,7 +561,7 @@ void pa_stream_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, ui } if (o->callback) { - void (*cb)(struct pa_stream *s, int success, void *userdata) = o->callback; + void (*cb)(pa_stream *s, int _success, void *_userdata) = (void (*)(pa_stream *s, int _success, void *_userdata)) o->callback; cb(o->stream, success, o->userdata); } @@ -570,9 +570,9 @@ finish: pa_operation_unref(o); } -struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_operation *o; - struct pa_tagstruct *t; +pa_operation* pa_stream_cork(pa_stream *s, int b, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; uint32_t tag; assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); @@ -589,7 +589,7 @@ struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (stru o = pa_operation_new(s->context, s); assert(o); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -606,14 +606,14 @@ struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (stru return pa_operation_ref(o); } -struct pa_operation* pa_stream_send_simple_command(struct pa_stream *s, uint32_t command, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - struct pa_operation *o; +static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; uint32_t tag; assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); o = pa_operation_new(s->context, s); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -626,36 +626,36 @@ struct pa_operation* pa_stream_send_simple_command(struct pa_stream *s, uint32_t return pa_operation_ref(o); } -struct pa_operation* pa_stream_flush(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { - struct pa_operation *o; - o = pa_stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata); +pa_operation* pa_stream_flush(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { + pa_operation *o; + o = stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata); pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); return o; } -struct pa_operation* pa_stream_prebuf(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { - struct pa_operation *o; - o = pa_stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata); +pa_operation* pa_stream_prebuf(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { + pa_operation *o; + o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata); pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); return o; } -struct pa_operation* pa_stream_trigger(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { - struct pa_operation *o; - o = pa_stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata); +pa_operation* pa_stream_trigger(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { + pa_operation *o; + o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata); pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); return o; } -struct pa_operation* pa_stream_set_name(struct pa_stream *s, const char *name, void(*cb)(struct pa_stream*c, int success, void *userdata), void *userdata) { - struct pa_operation *o; - struct pa_tagstruct *t; +pa_operation* pa_stream_set_name(pa_stream *s, const char *name, void(*cb)(pa_stream*c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; uint32_t tag; assert(s && s->ref >= 1 && s->state == PA_STREAM_READY && name && s->direction != PA_STREAM_UPLOAD); o = pa_operation_new(s->context, s); assert(o); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -670,12 +670,12 @@ struct pa_operation* pa_stream_set_name(struct pa_stream *s, const char *name, v return pa_operation_ref(o); } -uint64_t pa_stream_get_counter(struct pa_stream *s) { +uint64_t pa_stream_get_counter(pa_stream *s) { assert(s); return s->counter; } -pa_usec_t pa_stream_get_time(struct pa_stream *s, const struct pa_latency_info *i) { +pa_usec_t pa_stream_get_time(pa_stream *s, const pa_latency_info *i) { pa_usec_t usec; assert(s); @@ -707,7 +707,7 @@ pa_usec_t pa_stream_get_time(struct pa_stream *s, const struct pa_latency_info * return usec; } -static pa_usec_t time_counter_diff(struct pa_stream *s, pa_usec_t t, pa_usec_t c, int *negative) { +static pa_usec_t time_counter_diff(pa_stream *s, pa_usec_t t, pa_usec_t c, int *negative) { assert(s); if (negative) @@ -725,7 +725,7 @@ static pa_usec_t time_counter_diff(struct pa_stream *s, pa_usec_t t, pa_usec_t c return c-t; } -pa_usec_t pa_stream_get_latency(struct pa_stream *s, const struct pa_latency_info *i, int *negative) { +pa_usec_t pa_stream_get_latency(pa_stream *s, const pa_latency_info *i, int *negative) { pa_usec_t t, c; assert(s && i); @@ -735,12 +735,12 @@ pa_usec_t pa_stream_get_latency(struct pa_stream *s, const struct pa_latency_inf return time_counter_diff(s, t, c, negative); } -const struct pa_sample_spec* pa_stream_get_sample_spec(struct pa_stream *s) { +const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) { assert(s); return &s->sample_spec; } -void pa_stream_trash_ipol(struct pa_stream *s) { +void pa_stream_trash_ipol(pa_stream *s) { assert(s); if (!s->interpolate) @@ -750,7 +750,7 @@ void pa_stream_trash_ipol(struct pa_stream *s) { s->ipol_usec = 0; } -pa_usec_t pa_stream_get_interpolated_time(struct pa_stream *s) { +pa_usec_t pa_stream_get_interpolated_time(pa_stream *s) { pa_usec_t usec; assert(s && s->interpolate); @@ -771,7 +771,7 @@ pa_usec_t pa_stream_get_interpolated_time(struct pa_stream *s) { return usec; } -pa_usec_t pa_stream_get_interpolated_latency(struct pa_stream *s, int *negative) { +pa_usec_t pa_stream_get_interpolated_latency(pa_stream *s, int *negative) { pa_usec_t t, c; assert(s && s->interpolate); diff --git a/polyp/polyplib-stream.h b/polyp/polyplib-stream.h index 939b2ae6..806579f5 100644 --- a/polyp/polyplib-stream.h +++ b/polyp/polyplib-stream.h @@ -34,43 +34,43 @@ PA_C_DECL_BEGIN -/** \struct pa_stream +/** \pa_stream * An opaque stream for playback or recording */ -struct pa_stream; +typedef struct pa_stream pa_stream; /** Create a new, unconnected stream with the specified name and sample type */ -struct pa_stream* pa_stream_new(struct pa_context *c, const char *name, const struct pa_sample_spec *ss); +pa_stream* pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss); /** Decrease the reference counter by one */ -void pa_stream_unref(struct pa_stream *s); +void pa_stream_unref(pa_stream *s); /** Increase the reference counter by one */ -struct pa_stream *pa_stream_ref(struct pa_stream *s); +pa_stream *pa_stream_ref(pa_stream *s); /** Return the current state of the stream */ -enum pa_stream_state pa_stream_get_state(struct pa_stream *p); +pa_stream_state pa_stream_get_state(pa_stream *p); /** Return the context this stream is attached to */ -struct pa_context* pa_stream_get_context(struct pa_stream *p); +pa_context* pa_stream_get_context(pa_stream *p); /** Return the device (sink input or source output) index this stream is connected to */ -uint32_t pa_stream_get_index(struct pa_stream *s); +uint32_t pa_stream_get_index(pa_stream *s); /** Connect the stream to a sink */ -void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, enum pa_stream_flags flags, pa_volume_t volume); +void pa_stream_connect_playback(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags flags, pa_volume_t volume); /** Connect the stream to a source */ -void pa_stream_connect_record(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, enum pa_stream_flags flags); +void pa_stream_connect_record(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags flags); /** Disconnect a stream from a source/sink */ -void pa_stream_disconnect(struct pa_stream *s); +void pa_stream_disconnect(pa_stream *s); /** Write some data to the server (for playback sinks), if free_cb is * non-NULL this routine is called when all data has been written out * and an internal reference to the specified data is kept, the data * is not copied. If NULL, the data is copied into an internal * buffer. */ -void pa_stream_write(struct pa_stream *p /**< The stream to use */, +void pa_stream_write(pa_stream *p /**< The stream to use */, const void *data /**< The data to write */, size_t length /**< The length of the data to write */, void (*free_cb)(void *p) /**< A cleanup routine for the data or NULL to request an internal copy */, @@ -96,74 +96,74 @@ void pa_stream_write(struct pa_stream *p /**< The stream to use */, upload streams. */); /** Return the amount of bytes that may be written using pa_stream_write() */ -size_t pa_stream_writable_size(struct pa_stream *p); +size_t pa_stream_writable_size(pa_stream *p); /** Drain a playback stream */ -struct pa_operation* pa_stream_drain(struct pa_stream *s, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); +pa_operation* pa_stream_drain(pa_stream *s, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata); /** Get the playback latency of a stream */ -struct pa_operation* pa_stream_get_latency_info(struct pa_stream *p, void (*cb)(struct pa_stream *p, const struct pa_latency_info *i, void *userdata), void *userdata); +pa_operation* pa_stream_get_latency_info(pa_stream *p, void (*cb)(pa_stream *p, const pa_latency_info *i, void *userdata), void *userdata); /** Set the callback function that is called whenever the state of the stream changes */ -void pa_stream_set_state_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); +void pa_stream_set_state_callback(pa_stream *s, void (*cb)(pa_stream *s, void *userdata), void *userdata); /** Set the callback function that is called when new data may be * written to the stream. */ -void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); +void pa_stream_set_write_callback(pa_stream *p, void (*cb)(pa_stream *p, size_t length, void *userdata), void *userdata); /** Set the callback function that is called when new data is available from the stream */ -void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); +void pa_stream_set_read_callback(pa_stream *p, void (*cb)(pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); /** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. \since 0.3 */ -struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); +pa_operation* pa_stream_cork(pa_stream *s, int b, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata); /** Flush the playback buffer of this stream. Most of the time you're * better off using the parameter delta of pa_stream_write() instead of this * function. Available on both playback and recording streams. \since 0.3 */ -struct pa_operation* pa_stream_flush(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata); +pa_operation* pa_stream_flush(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata); /** Reenable prebuffering. Available for playback streams only. \since 0.6 */ -struct pa_operation* pa_stream_prebuf(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata); +pa_operation* pa_stream_prebuf(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata); /** Request immediate start of playback on this stream. This disables * prebuffering as specified in the pa_buffer_attr structure. Available for playback streams only. \since * 0.3 */ -struct pa_operation* pa_stream_trigger(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata); +pa_operation* pa_stream_trigger(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata); /** Rename the stream. \since 0.5 */ -struct pa_operation* pa_stream_set_name(struct pa_stream *s, const char *name, void(*cb)(struct pa_stream*c, int success, void *userdata), void *userdata); +pa_operation* pa_stream_set_name(pa_stream *s, const char *name, void(*cb)(pa_stream*c, int success, void *userdata), void *userdata); /** Return the total number of bytes written to/read from the * stream. This counter is not reset on pa_stream_flush(), you may do * this yourself using pa_stream_reset_counter(). \since 0.6 */ -uint64_t pa_stream_get_counter(struct pa_stream *s); +uint64_t pa_stream_get_counter(pa_stream *s); /** Return the current playback/recording time. This is based on the * counter accessible with pa_stream_get_counter(). This function * requires a pa_latency_info structure as argument, which should be * acquired using pa_stream_get_latency(). \since 0.6 */ -pa_usec_t pa_stream_get_time(struct pa_stream *s, const struct pa_latency_info *i); +pa_usec_t pa_stream_get_time(pa_stream *s, const pa_latency_info *i); /** Return the total stream latency. Thus function requires a * pa_latency_info structure as argument, which should be aquired * using pa_stream_get_latency(). In case the stream is a monitoring * stream the result can be negative, i.e. the captured samples are * not yet played. In this case *negative is set to 1. \since 0.6 */ -pa_usec_t pa_stream_get_latency(struct pa_stream *s, const struct pa_latency_info *i, int *negative); +pa_usec_t pa_stream_get_latency(pa_stream *s, const pa_latency_info *i, int *negative); /** Return the interpolated playback/recording time. Requires the * PA_STREAM_INTERPOLATE_LATENCY bit set when creating the stream. In * contrast to pa_stream_get_latency() this function doesn't require * a whole roundtrip for response. \since 0.6 */ -pa_usec_t pa_stream_get_interpolated_time(struct pa_stream *s); +pa_usec_t pa_stream_get_interpolated_time(pa_stream *s); /** Return the interpolated playback/recording latency. Requires the * PA_STREAM_INTERPOLATE_LATENCY bit set when creating the * stream. \since 0.6 */ -pa_usec_t pa_stream_get_interpolated_latency(struct pa_stream *s, int *negative); +pa_usec_t pa_stream_get_interpolated_latency(pa_stream *s, int *negative); /** Return a pointer to the streams sample specification. \since 0.6 */ -const struct pa_sample_spec* pa_stream_get_sample_spec(struct pa_stream *s); +const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s); PA_C_DECL_END diff --git a/polyp/polyplib-subscribe.c b/polyp/polyplib-subscribe.c index d7e8e7c1..69ae588f 100644 --- a/polyp/polyplib-subscribe.c +++ b/polyp/polyplib-subscribe.c @@ -29,10 +29,11 @@ #include "polyplib-subscribe.h" #include "polyplib-internal.h" #include "pstream-util.h" +#include "gccmacro.h" -void pa_command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - enum pa_subscription_event_type e; +void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_context *c = userdata; + pa_subscription_event_type e; uint32_t index; assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); @@ -53,14 +54,14 @@ finish: } -struct pa_operation* pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_operation *o; - struct pa_tagstruct *t; +pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask m, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; uint32_t tag; assert(c); o = pa_operation_new(c, NULL); - o->callback = cb; + o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -73,7 +74,7 @@ struct pa_operation* pa_context_subscribe(struct pa_context *c, enum pa_subscrip return pa_operation_ref(o); } -void pa_context_set_subscribe_callback(struct pa_context *c, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { +void pa_context_set_subscribe_callback(pa_context *c, void (*cb)(pa_context *c, pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { assert(c); c->subscribe_callback = cb; c->subscribe_userdata = userdata; diff --git a/polyp/polyplib-subscribe.h b/polyp/polyplib-subscribe.h index 5c697b71..f2760ee6 100644 --- a/polyp/polyplib-subscribe.h +++ b/polyp/polyplib-subscribe.h @@ -37,10 +37,10 @@ PA_C_DECL_BEGIN /** Enable event notification */ -struct pa_operation* pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask m, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); /** Set the context specific call back function that is called whenever the state of the daemon changes */ -void pa_context_set_subscribe_callback(struct pa_context *c, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); +void pa_context_set_subscribe_callback(pa_context *c, void (*cb)(pa_context *c, pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); PA_C_DECL_END diff --git a/polyp/props.c b/polyp/props.c index 1046551b..df748c1e 100644 --- a/polyp/props.c +++ b/polyp/props.c @@ -25,17 +25,17 @@ #include "props.h" #include "log.h" -struct pa_property { +typedef struct pa_property { char *name; /* Points to memory allocated by the property subsystem */ void *data; /* Points to memory maintained by the caller */ -}; +} pa_property; /* Allocate a new property object */ -static struct pa_property* property_new(const char *name, void *data) { - struct pa_property* p; +static pa_property* property_new(const char *name, void *data) { + pa_property* p; assert(name && data); - p = pa_xmalloc(sizeof(struct pa_property)); + p = pa_xmalloc(sizeof(pa_property)); p->name = pa_xstrdup(name); p->data = data; @@ -43,15 +43,15 @@ static struct pa_property* property_new(const char *name, void *data) { } /* Free a property object */ -static void property_free(struct pa_property *p) { +static void property_free(pa_property *p) { assert(p); pa_xfree(p->name); pa_xfree(p); } -void* pa_property_get(struct pa_core *c, const char *name) { - struct pa_property *p; +void* pa_property_get(pa_core *c, const char *name) { + pa_property *p; assert(c && name && c->properties); if (!(p = pa_hashmap_get(c->properties, name))) @@ -60,8 +60,8 @@ void* pa_property_get(struct pa_core *c, const char *name) { return p->data; } -int pa_property_set(struct pa_core *c, const char *name, void *data) { - struct pa_property *p; +int pa_property_set(pa_core *c, const char *name, void *data) { + pa_property *p; assert(c && name && data && c->properties); if (pa_hashmap_get(c->properties, name)) @@ -72,8 +72,8 @@ int pa_property_set(struct pa_core *c, const char *name, void *data) { return 0; } -int pa_property_remove(struct pa_core *c, const char *name) { - struct pa_property *p; +int pa_property_remove(pa_core *c, const char *name) { + pa_property *p; assert(c && name && c->properties); if (!(p = pa_hashmap_remove(c->properties, name))) @@ -83,35 +83,35 @@ int pa_property_remove(struct pa_core *c, const char *name) { return 0; } -void pa_property_init(struct pa_core *c) { +void pa_property_init(pa_core *c) { assert(c); c->properties = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); } -void pa_property_cleanup(struct pa_core *c) { +void pa_property_cleanup(pa_core *c) { assert(c); if (!c->properties) return; - assert(!pa_hashmap_ncontents(c->properties)); + assert(!pa_hashmap_size(c->properties)); pa_hashmap_free(c->properties, NULL, NULL); c->properties = NULL; } -void pa_property_dump(struct pa_core *c, struct pa_strbuf *s) { +void pa_property_dump(pa_core *c, pa_strbuf *s) { void *state = NULL; - struct pa_property *p; + pa_property *p; assert(c && s); while ((p = pa_hashmap_iterate(c->properties, &state, NULL))) pa_strbuf_printf(s, "[%s] -> [%p]\n", p->name, p->data); } -int pa_property_replace(struct pa_core *c, const char *name, void *data) { +int pa_property_replace(pa_core *c, const char *name, void *data) { assert(c && name); pa_property_remove(c, name); diff --git a/polyp/props.h b/polyp/props.h index 9b379cf1..5abf8787 100644 --- a/polyp/props.h +++ b/polyp/props.h @@ -33,26 +33,26 @@ * reference counting themselves. */ /* Return a pointer to the value of the specified property. */ -void* pa_property_get(struct pa_core *c, const char *name); +void* pa_property_get(pa_core *c, const char *name); /* Set the property 'name' to 'data'. This function fails in case a * property by this name already exists. The property data is not * copied or reference counted. This is the caller's job. */ -int pa_property_set(struct pa_core *c, const char *name, void *data); +int pa_property_set(pa_core *c, const char *name, void *data); /* Remove the specified property. Return non-zero on failure */ -int pa_property_remove(struct pa_core *c, const char *name); +int pa_property_remove(pa_core *c, const char *name); /* A combination of pa_property_remove() and pa_property_set() */ -int pa_property_replace(struct pa_core *c, const char *name, void *data); +int pa_property_replace(pa_core *c, const char *name, void *data); /* Free all memory used by the property system */ -void pa_property_cleanup(struct pa_core *c); +void pa_property_cleanup(pa_core *c); /* Initialize the properties subsystem */ -void pa_property_init(struct pa_core *c); +void pa_property_init(pa_core *c); /* Dump the current set of properties */ -void pa_property_dump(struct pa_core *c, struct pa_strbuf *s); +void pa_property_dump(pa_core *c, pa_strbuf *s); #endif diff --git a/polyp/protocol-cli.c b/polyp/protocol-cli.c index 107acb19..d2d73550 100644 --- a/polyp/protocol-cli.c +++ b/polyp/protocol-cli.c @@ -35,25 +35,25 @@ #define MAX_CONNECTIONS 25 struct pa_protocol_cli { - struct pa_module *module; - struct pa_core *core; - struct pa_socket_server*server; - struct pa_idxset *connections; + pa_module *module; + pa_core *core; + pa_socket_server*server; + pa_idxset *connections; }; -static void cli_eof_cb(struct pa_cli*c, void*userdata) { - struct pa_protocol_cli *p = userdata; +static void cli_eof_cb(pa_cli*c, void*userdata) { + pa_protocol_cli *p = userdata; assert(p); pa_idxset_remove_by_data(p->connections, c, NULL); pa_cli_free(c); } -static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { - struct pa_protocol_cli *p = userdata; - struct pa_cli *c; +static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { + pa_protocol_cli *p = userdata; + pa_cli *c; assert(s && io && p); - if (pa_idxset_ncontents(p->connections)+1 > MAX_CONNECTIONS) { + if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); pa_iochannel_free(io); return; @@ -66,11 +66,11 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo pa_idxset_put(p->connections, c, NULL); } -struct pa_protocol_cli* pa_protocol_cli_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { - struct pa_protocol_cli* p; +pa_protocol_cli* pa_protocol_cli_new(pa_core *core, pa_socket_server *server, pa_module *m, PA_GCC_UNUSED pa_modargs *ma) { + pa_protocol_cli* p; assert(core && server); - p = pa_xmalloc(sizeof(struct pa_protocol_cli)); + p = pa_xmalloc(sizeof(pa_protocol_cli)); p->module = m; p->core = core; p->server = server; @@ -81,12 +81,12 @@ struct pa_protocol_cli* pa_protocol_cli_new(struct pa_core *core, struct pa_sock return p; } -static void free_connection(void *p, void *userdata) { +static void free_connection(void *p, PA_GCC_UNUSED void *userdata) { assert(p); pa_cli_free(p); } -void pa_protocol_cli_free(struct pa_protocol_cli *p) { +void pa_protocol_cli_free(pa_protocol_cli *p) { assert(p); pa_idxset_free(p->connections, free_connection, NULL); diff --git a/polyp/protocol-cli.h b/polyp/protocol-cli.h index e0fe4bc1..aed733c1 100644 --- a/polyp/protocol-cli.h +++ b/polyp/protocol-cli.h @@ -27,9 +27,9 @@ #include "module.h" #include "modargs.h" -struct pa_protocol_cli; +typedef struct pa_protocol_cli pa_protocol_cli; -struct pa_protocol_cli* pa_protocol_cli_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma); -void pa_protocol_cli_free(struct pa_protocol_cli *n); +pa_protocol_cli* pa_protocol_cli_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma); +void pa_protocol_cli_free(pa_protocol_cli *n); #endif diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 18ecb0ac..a97bc25c 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -45,6 +45,7 @@ #include "namereg.h" #include "xmalloc.h" #include "log.h" +#include "util.h" /* Don't accept more connection than this */ #define MAX_CONNECTIONS 10 @@ -70,9 +71,9 @@ struct connection { uint32_t index; int dead; - struct pa_protocol_esound *protocol; - struct pa_iochannel *io; - struct pa_client *client; + pa_protocol_esound *protocol; + pa_iochannel *io; + pa_client *client; int authorized, swap_byte_order; void *write_data; size_t write_data_alloc, write_data_index, write_data_length; @@ -80,31 +81,31 @@ struct connection { size_t read_data_alloc, read_data_length; esd_proto_t request; esd_client_state_t state; - struct pa_sink_input *sink_input; - struct pa_source_output *source_output; - struct pa_memblockq *input_memblockq, *output_memblockq; - struct pa_defer_event *defer_event; + pa_sink_input *sink_input; + pa_source_output *source_output; + pa_memblockq *input_memblockq, *output_memblockq; + pa_defer_event *defer_event; struct { - struct pa_memblock *current_memblock; + pa_memblock *current_memblock; size_t memblock_index, fragment_size; } playback; struct { - struct pa_memchunk memchunk; + pa_memchunk memchunk; char *name; - struct pa_sample_spec sample_spec; + pa_sample_spec sample_spec; } scache; - struct pa_time_event *auth_timeout_event; + pa_time_event *auth_timeout_event; }; struct pa_protocol_esound { int public; - struct pa_module *module; - struct pa_core *core; - struct pa_socket_server *server; - struct pa_idxset *connections; + pa_module *module; + pa_core *core; + pa_socket_server *server; + pa_idxset *connections; char *sink_name, *source_name; unsigned n_player; uint8_t esd_key[ESD_KEY_LEN]; @@ -116,14 +117,14 @@ typedef struct proto_handler { const char *description; } esd_proto_handler_info_t; -static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length); -static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk); -static void sink_input_kill_cb(struct pa_sink_input *i); -static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i); -static pa_usec_t source_output_get_latency_cb(struct pa_source_output *o); +static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length); +static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk); +static void sink_input_kill_cb(pa_sink_input *i); +static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i); +static pa_usec_t source_output_get_latency_cb(pa_source_output *o); -static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk); -static void source_output_kill_cb(struct pa_source_output *o); +static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk); +static void source_output_kill_cb(pa_source_output *o); static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length); static int esd_proto_stream_play(struct connection *c, esd_proto_t request, const void *data, size_t length); @@ -239,7 +240,7 @@ static void* connection_write(struct connection *c, size_t length) { return (uint8_t*) c->write_data+i; } -static void format_esd2native(int format, int swap_bytes, struct pa_sample_spec *ss) { +static void format_esd2native(int format, int swap_bytes, pa_sample_spec *ss) { assert(ss); ss->channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; @@ -249,7 +250,7 @@ static void format_esd2native(int format, int swap_bytes, struct pa_sample_spec ss->format = PA_SAMPLE_U8; } -static int format_native2esd(struct pa_sample_spec *ss) { +static int format_native2esd(pa_sample_spec *ss) { int format = 0; format = (ss->format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16; @@ -260,7 +261,7 @@ static int format_native2esd(struct pa_sample_spec *ss) { /*** esound commands ***/ -static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length) { +static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { uint32_t ekey; int *ok; assert(length == (ESD_KEY_LEN + sizeof(uint32_t))); @@ -278,7 +279,7 @@ static int esd_proto_connect(struct connection *c, esd_proto_t request, const vo } } - ekey = *(uint32_t*)((uint8_t*) data+ESD_KEY_LEN); + ekey = *(const uint32_t*)((const uint8_t*) data+ESD_KEY_LEN); if (ekey == ESD_ENDIAN_KEY) c->swap_byte_order = 0; else if (ekey == ESD_SWAP_ENDIAN_KEY) @@ -294,16 +295,16 @@ static int esd_proto_connect(struct connection *c, esd_proto_t request, const vo return 0; } -static int esd_proto_stream_play(struct connection *c, esd_proto_t request, const void *data, size_t length) { +static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { char name[ESD_NAME_MAX]; int format, rate; - struct pa_sink *sink; - struct pa_sample_spec ss; + pa_sink *sink; + pa_sample_spec ss; size_t l; assert(c && length == (sizeof(int)*2+ESD_NAME_MAX)); - format = maybe_swap_endian_32(c->swap_byte_order, *(int*)data); - rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); + format = maybe_swap_endian_32(c->swap_byte_order, *(const int*)data); + rate = maybe_swap_endian_32(c->swap_byte_order, *((const int*)data + 1)); ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); @@ -318,7 +319,7 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons return -1; } - strncpy(name, (char*) data + sizeof(int)*2, sizeof(name)); + strncpy(name, (const char*) data + sizeof(int)*2, sizeof(name)); name[sizeof(name)-1] = 0; pa_client_set_name(c->client, name); @@ -353,13 +354,13 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length) { char name[ESD_NAME_MAX]; int format, rate; - struct pa_source *source; - struct pa_sample_spec ss; + pa_source *source; + pa_sample_spec ss; size_t l; assert(c && length == (sizeof(int)*2+ESD_NAME_MAX)); - format = maybe_swap_endian_32(c->swap_byte_order, *(int*)data); - rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); + format = maybe_swap_endian_32(c->swap_byte_order, *(const int*)data); + rate = maybe_swap_endian_32(c->swap_byte_order, *((const int*)data + 1)); ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); @@ -370,7 +371,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co } if (request == ESD_PROTO_STREAM_MON) { - struct pa_sink* sink; + pa_sink* sink; if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { pa_log(__FILE__": no such sink.\n"); @@ -390,7 +391,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co } } - strncpy(name, (char*) data + sizeof(int)*2, sizeof(name)); + strncpy(name, (const char*) data + sizeof(int)*2, sizeof(name)); name[sizeof(name)-1] = 0; pa_client_set_name(c->client, name); @@ -420,8 +421,8 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co return 0; } -static int esd_proto_get_latency(struct connection *c, esd_proto_t request, const void *data, size_t length) { - struct pa_sink *sink; +static int esd_proto_get_latency(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + pa_sink *sink; int latency, *lag; assert(c && !data && length == 0); @@ -438,10 +439,10 @@ static int esd_proto_get_latency(struct connection *c, esd_proto_t request, cons return 0; } -static int esd_proto_server_info(struct connection *c, esd_proto_t request, const void *data, size_t length) { +static int esd_proto_server_info(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { int rate = 44100, format = ESD_STEREO|ESD_BITS16; int *response; - struct pa_sink *sink; + pa_sink *sink; assert(c && data && length == sizeof(int)); if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { @@ -461,7 +462,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v uint8_t *response; size_t t, k, s; struct connection *conn; - size_t index = PA_IDXSET_INVALID; + size_t idx = PA_IDXSET_INVALID; unsigned nsamples; assert(c && data && length == sizeof(int)); @@ -470,11 +471,11 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v k = sizeof(int)*5+ESD_NAME_MAX; s = sizeof(int)*6+ESD_NAME_MAX; - nsamples = c->protocol->core->scache ? pa_idxset_ncontents(c->protocol->core->scache) : 0; + nsamples = c->protocol->core->scache ? pa_idxset_size(c->protocol->core->scache) : 0; response = connection_write(c, (t = s*(nsamples+1) + k*(c->protocol->n_player+1))); assert(k); - for (conn = pa_idxset_first(c->protocol->connections, &index); conn; conn = pa_idxset_next(c->protocol->connections, &index)) { + for (conn = pa_idxset_first(c->protocol->connections, &idx); conn; conn = pa_idxset_next(c->protocol->connections, &idx)) { int format = ESD_BITS16 | ESD_STEREO, rate = 44100, volume = 0xFF; if (conn->state != ESD_STREAMING_DATA) @@ -522,10 +523,10 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v t -= k; if (nsamples) { - struct pa_scache_entry *ce; + pa_scache_entry *ce; - index = PA_IDXSET_INVALID; - for (ce = pa_idxset_first(c->protocol->core->scache, &index); ce; ce = pa_idxset_next(c->protocol->core->scache, &index)) { + idx = PA_IDXSET_INVALID; + for (ce = pa_idxset_first(c->protocol->core->scache, &idx); ce; ce = pa_idxset_next(c->protocol->core->scache, &idx)) { assert(t >= s*2); /* id */ @@ -569,20 +570,20 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v return 0; } -static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const void *data, size_t length) { +static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { int *ok; - uint32_t index, volume; + uint32_t idx, volume; struct connection *conn; assert(c && data && length == sizeof(int)*3); - index = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *(int*)data)-1; - volume = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); + idx = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *(const int*)data)-1; + volume = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *((const int*)data + 1)); volume = (volume*0x100)/0xFF; ok = connection_write(c, sizeof(int)); assert(ok); - if ((conn = pa_idxset_get_by_index(c->protocol->connections, index))) { + if ((conn = pa_idxset_get_by_index(c->protocol->connections, idx))) { assert(conn->sink_input); conn->sink_input->volume = volume; *ok = 1; @@ -592,28 +593,28 @@ static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const return 0; } -static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, const void *data, size_t length) { - struct pa_sample_spec ss; +static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + pa_sample_spec ss; int format, rate; size_t sc_length; - uint32_t index; + uint32_t idx; int *ok; char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; assert(c && data && length == (ESD_NAME_MAX+3*sizeof(int))); - format = maybe_swap_endian_32(c->swap_byte_order, *(int*)data); - rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1)); + format = maybe_swap_endian_32(c->swap_byte_order, *(const int*)data); + rate = maybe_swap_endian_32(c->swap_byte_order, *((const int*)data + 1)); ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); - sc_length = (size_t) maybe_swap_endian_32(c->swap_byte_order, (*((int*)data + 2))); + sc_length = (size_t) maybe_swap_endian_32(c->swap_byte_order, (*((const int*)data + 2))); if (sc_length >= MAX_CACHE_SAMPLE_SIZE) return -1; strcpy(name, SCACHE_PREFIX); - strncpy(name+sizeof(SCACHE_PREFIX)-1, (char*) data+3*sizeof(int), ESD_NAME_MAX); + strncpy(name+sizeof(SCACHE_PREFIX)-1, (const char*) data+3*sizeof(int), ESD_NAME_MAX); name[sizeof(name)-1] = 0; assert(!c->scache.memchunk.memblock); @@ -626,19 +627,19 @@ static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, con c->state = ESD_CACHING_SAMPLE; - pa_scache_add_item(c->protocol->core, c->scache.name, NULL, NULL, &index); + pa_scache_add_item(c->protocol->core, c->scache.name, NULL, NULL, &idx); ok = connection_write(c, sizeof(int)); assert(ok); - *ok = index+1; + *ok = idx+1; return 0; } -static int esd_proto_sample_get_id(struct connection *c, esd_proto_t request, const void *data, size_t length) { +static int esd_proto_sample_get_id(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { int *ok; - uint32_t index; + uint32_t idx; char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; assert(c && data && length == ESD_NAME_MAX); @@ -651,8 +652,8 @@ static int esd_proto_sample_get_id(struct connection *c, esd_proto_t request, co strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX); name[sizeof(name)-1] = 0; - if ((index = pa_scache_get_id_by_name(c->protocol->core, name)) != PA_IDXSET_INVALID) - *ok = (int) index +1; + if ((idx = pa_scache_get_id_by_name(c->protocol->core, name)) != PA_IDXSET_INVALID) + *ok = (int) idx +1; return 0; } @@ -660,35 +661,35 @@ static int esd_proto_sample_get_id(struct connection *c, esd_proto_t request, co static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length) { int *ok; const char *name; - uint32_t index; + uint32_t idx; assert(c && data && length == sizeof(int)); - index = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *(int*)data)-1; + idx = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *(const int*)data)-1; ok = connection_write(c, sizeof(int)); assert(ok); *ok = 0; - if ((name = pa_scache_get_name_by_id(c->protocol->core, index))) { + if ((name = pa_scache_get_name_by_id(c->protocol->core, idx))) { if (request == ESD_PROTO_SAMPLE_PLAY) { - struct pa_sink *sink; + pa_sink *sink; if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) if (pa_scache_play_item(c->protocol->core, name, sink, PA_VOLUME_NORM) >= 0) - *ok = (int) index+1; + *ok = (int) idx+1; } else { assert(request == ESD_PROTO_SAMPLE_FREE); if (pa_scache_remove_item(c->protocol->core, name) >= 0) - *ok = (int) index+1; + *ok = (int) idx+1; } } return 0; } -static int esd_proto_standby_or_resume(struct connection *c, esd_proto_t request, const void *data, size_t length) { +static int esd_proto_standby_or_resume(struct connection *c, PA_GCC_UNUSED esd_proto_t request, PA_GCC_UNUSED const void *data, PA_GCC_UNUSED size_t length) { int *ok; ok = connection_write(c, sizeof(int)*2); assert(ok); @@ -699,7 +700,7 @@ static int esd_proto_standby_or_resume(struct connection *c, esd_proto_t request /*** client callbacks ***/ -static void client_kill_cb(struct pa_client *c) { +static void client_kill_cb(pa_client *c) { assert(c && c->userdata); connection_free(c->userdata); } @@ -796,11 +797,11 @@ static int do_read(struct connection *c) { assert(c->scache.memchunk.index <= c->scache.memchunk.length); if (c->scache.memchunk.index == c->scache.memchunk.length) { - uint32_t index; + uint32_t idx; int *ok; c->scache.memchunk.index = 0; - pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, &c->scache.memchunk, &index); + pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, &c->scache.memchunk, &idx); pa_memblock_unref(c->scache.memchunk.memblock); c->scache.memchunk.memblock = NULL; @@ -813,11 +814,11 @@ static int do_read(struct connection *c) { ok = connection_write(c, sizeof(int)); assert(ok); - *ok = index+1; + *ok = idx+1; } } else if (c->state == ESD_STREAMING_DATA && c->sink_input) { - struct pa_memchunk chunk; + pa_memchunk chunk; ssize_t r; size_t l; @@ -886,7 +887,7 @@ static int do_write(struct connection *c) { c->write_data_length = c->write_data_index = 0; } else if (c->state == ESD_STREAMING_DATA && c->source_output) { - struct pa_memchunk chunk; + pa_memchunk chunk; ssize_t r; assert(c->output_memblockq); @@ -945,7 +946,7 @@ fail: connection_free(c); } -static void io_callback(struct pa_iochannel*io, void *userdata) { +static void io_callback(pa_iochannel*io, void *userdata) { struct connection *c = userdata; assert(io && c && c->io == io); @@ -956,7 +957,7 @@ static void io_callback(struct pa_iochannel*io, void *userdata) { /*** defer callback ***/ -static void defer_callback(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata) { +static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { struct connection *c = userdata; assert(a && c && c->defer_event == e); @@ -967,7 +968,7 @@ static void defer_callback(struct pa_mainloop_api*a, struct pa_defer_event *e, v /*** sink_input callbacks ***/ -static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk) { +static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { struct connection*c; assert(i && i->userdata && chunk); c = i->userdata; @@ -983,7 +984,7 @@ static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk return 0; } -static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length) { +static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { struct connection*c = i->userdata; assert(i && c && length); @@ -1000,12 +1001,12 @@ static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk /* assert(pa_memblockq_get_length(c->input_memblockq) > 2048); */ } -static void sink_input_kill_cb(struct pa_sink_input *i) { +static void sink_input_kill_cb(pa_sink_input *i) { assert(i && i->userdata); connection_free((struct connection *) i->userdata); } -static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i) { +static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { struct connection*c = i->userdata; assert(i && c); return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); @@ -1013,7 +1014,7 @@ static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i) { /*** source_output callbacks ***/ -static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk) { +static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { struct connection *c = o->userdata; assert(o && c && chunk); @@ -1026,12 +1027,12 @@ static void source_output_push_cb(struct pa_source_output *o, const struct pa_me c->protocol->core->mainloop->defer_enable(c->defer_event, 1); } -static void source_output_kill_cb(struct pa_source_output *o) { +static void source_output_kill_cb(pa_source_output *o) { assert(o && o->userdata); connection_free((struct connection *) o->userdata); } -static pa_usec_t source_output_get_latency_cb(struct pa_source_output *o) { +static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { struct connection*c = o->userdata; assert(o && c); return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec); @@ -1039,7 +1040,7 @@ static pa_usec_t source_output_get_latency_cb(struct pa_source_output *o) { /*** socket server callback ***/ -static void auth_timeout(struct pa_mainloop_api*m, struct pa_time_event *e, const struct timeval *tv, void *userdata) { +static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { struct connection *c = userdata; assert(m && tv && c && c->auth_timeout_event == e); @@ -1047,13 +1048,13 @@ static void auth_timeout(struct pa_mainloop_api*m, struct pa_time_event *e, cons connection_free(c); } -static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { +static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { struct connection *c; - struct pa_protocol_esound *p = userdata; + pa_protocol_esound *p = userdata; char cname[256]; assert(s && io && p); - if (pa_idxset_ncontents(p->connections)+1 > MAX_CONNECTIONS) { + if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); pa_iochannel_free(io); return; @@ -1116,12 +1117,12 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo /*** entry points ***/ -struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { - struct pa_protocol_esound *p; +pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { + pa_protocol_esound *p; int public = 0; assert(core && server && ma); - p = pa_xmalloc(sizeof(struct pa_protocol_esound)); + p = pa_xmalloc(sizeof(pa_protocol_esound)); if (pa_modargs_get_value_boolean(ma, "public", &public) < 0) { pa_log(__FILE__": public= expects a boolean argument.\n"); @@ -1148,7 +1149,7 @@ struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa return p; } -void pa_protocol_esound_free(struct pa_protocol_esound *p) { +void pa_protocol_esound_free(pa_protocol_esound *p) { struct connection *c; assert(p); diff --git a/polyp/protocol-esound.h b/polyp/protocol-esound.h index dda6977d..71d58464 100644 --- a/polyp/protocol-esound.h +++ b/polyp/protocol-esound.h @@ -27,9 +27,9 @@ #include "module.h" #include "modargs.h" -struct pa_protocol_esound; +typedef struct pa_protocol_esound pa_protocol_esound; -struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma); -void pa_protocol_esound_free(struct pa_protocol_esound *p); +pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma); +void pa_protocol_esound_free(pa_protocol_esound *p); #endif diff --git a/polyp/protocol-http.c b/polyp/protocol-http.c index 64e6dadf..3e55df03 100644 --- a/polyp/protocol-http.c +++ b/polyp/protocol-http.c @@ -45,17 +45,17 @@ #define URL_STATUS "/status" struct connection { - struct pa_protocol_http *protocol; - struct pa_ioline *line; + pa_protocol_http *protocol; + pa_ioline *line; enum { REQUEST_LINE, MIME_HEADER, DATA } state; char *url; }; struct pa_protocol_http { - struct pa_module *module; - struct pa_core *core; - struct pa_socket_server*server; - struct pa_idxset *connections; + pa_module *module; + pa_core *core; + pa_socket_server*server; + pa_idxset *connections; }; static void http_response(struct connection *c, int code, const char *msg, const char *mime) { @@ -109,7 +109,7 @@ static void connection_free(struct connection *c, int del) { pa_xfree(c); } -static void line_callback(struct pa_ioline *line, const char *s, void *userdata) { +static void line_callback(pa_ioline *line, const char *s, void *userdata) { struct connection *c = userdata; assert(line); assert(c); @@ -191,12 +191,12 @@ static void line_callback(struct pa_ioline *line, const char *s, void *userdata) pa_ioline_defer_close(c->line); } else if (!strcmp(c->url, URL_STATUS)) { - char *s; + char *r; http_response(c, 200, "OK", "text/plain"); - s = pa_full_status_string(c->protocol->core); - pa_ioline_puts(c->line, s); - pa_xfree(s); + r = pa_full_status_string(c->protocol->core); + pa_ioline_puts(c->line, r); + pa_xfree(r); pa_ioline_defer_close(c->line); } else @@ -215,12 +215,12 @@ fail: internal_server_error(c); } -static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { - struct pa_protocol_http *p = userdata; +static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { + pa_protocol_http *p = userdata; struct connection *c; assert(s && io && p); - if (pa_idxset_ncontents(p->connections)+1 > MAX_CONNECTIONS) { + if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { pa_log_warn(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); pa_iochannel_free(io); return; @@ -236,11 +236,11 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo pa_idxset_put(p->connections, c, NULL); } -struct pa_protocol_http* pa_protocol_http_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { - struct pa_protocol_http* p; +pa_protocol_http* pa_protocol_http_new(pa_core *core, pa_socket_server *server, pa_module *m, PA_GCC_UNUSED pa_modargs *ma) { + pa_protocol_http* p; assert(core && server); - p = pa_xmalloc(sizeof(struct pa_protocol_http)); + p = pa_xmalloc(sizeof(pa_protocol_http)); p->module = m; p->core = core; p->server = server; @@ -251,12 +251,12 @@ struct pa_protocol_http* pa_protocol_http_new(struct pa_core *core, struct pa_so return p; } -static void free_connection(void *p, void *userdata) { +static void free_connection(void *p, PA_GCC_UNUSED void *userdata) { assert(p); connection_free(p, 0); } -void pa_protocol_http_free(struct pa_protocol_http *p) { +void pa_protocol_http_free(pa_protocol_http *p) { assert(p); pa_idxset_free(p->connections, free_connection, NULL); diff --git a/polyp/protocol-http.h b/polyp/protocol-http.h index 3c9b8d76..0a1855e9 100644 --- a/polyp/protocol-http.h +++ b/polyp/protocol-http.h @@ -27,9 +27,9 @@ #include "module.h" #include "modargs.h" -struct pa_protocol_http; +typedef struct pa_protocol_http pa_protocol_http; -struct pa_protocol_http* pa_protocol_http_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma); -void pa_protocol_http_free(struct pa_protocol_http *n); +pa_protocol_http* pa_protocol_http_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma); +void pa_protocol_http_free(pa_protocol_http *n); #endif diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 90dbdaf5..b19d30d9 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -64,8 +64,8 @@ struct pa_protocol_native; struct record_stream { struct connection *connection; uint32_t index; - struct pa_source_output *source_output; - struct pa_memblockq *memblockq; + pa_source_output *source_output; + pa_memblockq *memblockq; size_t fragment_size; }; @@ -73,8 +73,8 @@ struct playback_stream { int type; struct connection *connection; uint32_t index; - struct pa_sink_input *sink_input; - struct pa_memblockq *memblockq; + pa_sink_input *sink_input; + pa_memblockq *memblockq; size_t requested_bytes; int drain_request; uint32_t drain_tag; @@ -84,10 +84,10 @@ struct upload_stream { int type; struct connection *connection; uint32_t index; - struct pa_memchunk memchunk; + pa_memchunk memchunk; size_t length; char *name; - struct pa_sample_spec sample_spec; + pa_sample_spec sample_spec; }; struct output_stream { @@ -101,141 +101,141 @@ enum { struct connection { int authorized; - struct pa_protocol_native *protocol; - struct pa_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; - struct pa_idxset *record_streams, *output_streams; + pa_protocol_native *protocol; + pa_client *client; + pa_pstream *pstream; + pa_pdispatch *pdispatch; + pa_idxset *record_streams, *output_streams; uint32_t rrobin_index; - struct pa_subscription *subscription; - struct pa_time_event *auth_timeout_event; + pa_subscription *subscription; + pa_time_event *auth_timeout_event; }; struct pa_protocol_native { - struct pa_module *module; + pa_module *module; int public; - struct pa_core *core; - struct pa_socket_server *server; - struct pa_idxset *connections; + pa_core *core; + pa_socket_server *server; + pa_idxset *connections; uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; int auth_cookie_in_property; }; -static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk); -static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length); -static void sink_input_kill_cb(struct pa_sink_input *i); -static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i); +static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk); +static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length); +static void sink_input_kill_cb(pa_sink_input *i); +static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i); static void request_bytes(struct playback_stream*s); -static void source_output_kill_cb(struct pa_source_output *o); -static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk); -static pa_usec_t source_output_get_latency_cb(struct pa_source_output *o); - -static void command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_delete_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_set_client_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_get_record_latency(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_create_upload_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_finish_upload_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_play_sample(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_remove_sample(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_subscribe(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_set_volume(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_cork_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_flush_or_trigger_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_set_default_sink_or_source(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_set_stream_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_kill(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_load_module(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_unload_module(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_add_autoload(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_remove_autoload(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_get_autoload_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_get_autoload_info_list(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_cork_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_flush_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_TIMEOUT] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { command_create_playback_stream }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { command_delete_stream }, - [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = { command_drain_playback_stream }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { command_create_record_stream }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { command_delete_stream }, - [PA_COMMAND_AUTH] = { command_auth }, - [PA_COMMAND_REQUEST] = { NULL }, - [PA_COMMAND_EXIT] = { command_exit }, - [PA_COMMAND_SET_CLIENT_NAME] = { command_set_client_name }, - [PA_COMMAND_LOOKUP_SINK] = { command_lookup }, - [PA_COMMAND_LOOKUP_SOURCE] = { command_lookup }, - [PA_COMMAND_STAT] = { command_stat }, - [PA_COMMAND_GET_PLAYBACK_LATENCY] = { command_get_playback_latency }, - [PA_COMMAND_GET_RECORD_LATENCY] = { command_get_record_latency }, - [PA_COMMAND_CREATE_UPLOAD_STREAM] = { command_create_upload_stream }, - [PA_COMMAND_DELETE_UPLOAD_STREAM] = { command_delete_stream }, - [PA_COMMAND_FINISH_UPLOAD_STREAM] = { command_finish_upload_stream }, - [PA_COMMAND_PLAY_SAMPLE] = { command_play_sample }, - [PA_COMMAND_REMOVE_SAMPLE] = { command_remove_sample }, - [PA_COMMAND_GET_SINK_INFO] = { command_get_info }, - [PA_COMMAND_GET_SOURCE_INFO] = { command_get_info }, - [PA_COMMAND_GET_CLIENT_INFO] = { command_get_info }, - [PA_COMMAND_GET_MODULE_INFO] = { command_get_info }, - [PA_COMMAND_GET_SINK_INPUT_INFO] = { command_get_info }, - [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = { command_get_info }, - [PA_COMMAND_GET_SAMPLE_INFO] = { command_get_info }, - [PA_COMMAND_GET_SINK_INFO_LIST] = { command_get_info_list }, - [PA_COMMAND_GET_SOURCE_INFO_LIST] = { command_get_info_list }, - [PA_COMMAND_GET_MODULE_INFO_LIST] = { command_get_info_list }, - [PA_COMMAND_GET_CLIENT_INFO_LIST] = { command_get_info_list }, - [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = { command_get_info_list }, - [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = { command_get_info_list }, - [PA_COMMAND_GET_SAMPLE_INFO_LIST] = { command_get_info_list }, - [PA_COMMAND_GET_SERVER_INFO] = { command_get_server_info }, - [PA_COMMAND_SUBSCRIBE] = { command_subscribe }, - - [PA_COMMAND_SET_SINK_VOLUME] = { command_set_volume }, - [PA_COMMAND_SET_SINK_INPUT_VOLUME] = { command_set_volume }, +static void source_output_kill_cb(pa_source_output *o); +static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk); +static pa_usec_t source_output_get_latency_cb(pa_source_output *o); + +static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_flush_or_trigger_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_add_autoload(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_remove_autoload(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_autoload_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_autoload_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); + +static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = NULL, + [PA_COMMAND_TIMEOUT] = NULL, + [PA_COMMAND_REPLY] = NULL, + [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream, + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream, + [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream, + [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream, + [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream, + [PA_COMMAND_AUTH] = command_auth, + [PA_COMMAND_REQUEST] = NULL, + [PA_COMMAND_EXIT] = command_exit, + [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name, + [PA_COMMAND_LOOKUP_SINK] = command_lookup, + [PA_COMMAND_LOOKUP_SOURCE] = command_lookup, + [PA_COMMAND_STAT] = command_stat, + [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency, + [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency, + [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream, + [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream, + [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream, + [PA_COMMAND_PLAY_SAMPLE] = command_play_sample, + [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample, + [PA_COMMAND_GET_SINK_INFO] = command_get_info, + [PA_COMMAND_GET_SOURCE_INFO] = command_get_info, + [PA_COMMAND_GET_CLIENT_INFO] = command_get_info, + [PA_COMMAND_GET_MODULE_INFO] = command_get_info, + [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info, + [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info, + [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info, + [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info, + [PA_COMMAND_SUBSCRIBE] = command_subscribe, + + [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume, + [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume, - [PA_COMMAND_CORK_PLAYBACK_STREAM] = { command_cork_playback_stream }, - [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = { command_flush_or_trigger_playback_stream }, - [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = { command_flush_or_trigger_playback_stream }, - [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = { command_flush_or_trigger_playback_stream }, + [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream, + [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_flush_or_trigger_playback_stream, + [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_flush_or_trigger_playback_stream, + [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_flush_or_trigger_playback_stream, - [PA_COMMAND_CORK_RECORD_STREAM] = { command_cork_record_stream }, - [PA_COMMAND_FLUSH_RECORD_STREAM] = { command_flush_record_stream }, + [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream, + [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream, - [PA_COMMAND_SET_DEFAULT_SINK] = { command_set_default_sink_or_source }, - [PA_COMMAND_SET_DEFAULT_SOURCE] = { command_set_default_sink_or_source }, - [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = { command_set_stream_name }, - [PA_COMMAND_SET_RECORD_STREAM_NAME] = { command_set_stream_name }, - [PA_COMMAND_KILL_CLIENT] = { command_kill }, - [PA_COMMAND_KILL_SINK_INPUT] = { command_kill }, - [PA_COMMAND_KILL_SOURCE_OUTPUT] = { command_kill }, - [PA_COMMAND_LOAD_MODULE] = { command_load_module }, - [PA_COMMAND_UNLOAD_MODULE] = { command_unload_module }, - [PA_COMMAND_GET_AUTOLOAD_INFO] = { command_get_autoload_info }, - [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = { command_get_autoload_info_list }, - [PA_COMMAND_ADD_AUTOLOAD] = { command_add_autoload }, - [PA_COMMAND_REMOVE_AUTOLOAD] = { command_remove_autoload }, + [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source, + [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source, + [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name, + [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name, + [PA_COMMAND_KILL_CLIENT] = command_kill, + [PA_COMMAND_KILL_SINK_INPUT] = command_kill, + [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill, + [PA_COMMAND_LOAD_MODULE] = command_load_module, + [PA_COMMAND_UNLOAD_MODULE] = command_unload_module, + [PA_COMMAND_GET_AUTOLOAD_INFO] = command_get_autoload_info, + [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = command_get_autoload_info_list, + [PA_COMMAND_ADD_AUTOLOAD] = command_add_autoload, + [PA_COMMAND_REMOVE_AUTOLOAD] = command_remove_autoload, }; /* structure management */ -static struct upload_stream* upload_stream_new(struct connection *c, const struct pa_sample_spec *ss, const char *name, size_t length) { +static struct upload_stream* upload_stream_new(struct connection *c, const pa_sample_spec *ss, const char *name, size_t length) { struct upload_stream *s; assert(c && ss && name && length); @@ -268,9 +268,9 @@ static void upload_stream_free(struct upload_stream *o) { pa_xfree(o); } -static struct record_stream* record_stream_new(struct connection *c, struct pa_source *source, const struct pa_sample_spec *ss, const char *name, size_t maxlength, size_t fragment_size) { +static struct record_stream* record_stream_new(struct connection *c, pa_source *source, const pa_sample_spec *ss, const char *name, size_t maxlength, size_t fragment_size) { struct record_stream *s; - struct pa_source_output *source_output; + pa_source_output *source_output; size_t base; assert(c && source && ss && name && maxlength); @@ -308,14 +308,14 @@ static void record_stream_free(struct record_stream* r) { pa_xfree(r); } -static struct playback_stream* playback_stream_new(struct connection *c, struct pa_sink *sink, const struct pa_sample_spec *ss, const char *name, +static struct playback_stream* playback_stream_new(struct connection *c, pa_sink *sink, const pa_sample_spec *ss, const char *name, size_t maxlength, size_t tlength, size_t prebuf, size_t minreq, pa_volume_t volume) { struct playback_stream *s; - struct pa_sink_input *sink_input; + pa_sink_input *sink_input; assert(c && sink && ss && name && maxlength); if (!(sink_input = pa_sink_input_new(sink, PA_TYPEID_NATIVE, name, ss, 0, -1))) @@ -391,7 +391,7 @@ static void connection_free(struct connection *c) { } static void request_bytes(struct playback_stream *s) { - struct pa_tagstruct *t; + pa_tagstruct *t; size_t l; assert(s); @@ -425,7 +425,7 @@ static void send_memblock(struct connection *c) { start = PA_IDXSET_INVALID; for (;;) { - struct pa_memchunk chunk; + pa_memchunk chunk; if (!(r = pa_idxset_rrobin(c->record_streams, &c->rrobin_index))) return; @@ -436,7 +436,7 @@ static void send_memblock(struct connection *c) { return; if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) { - struct pa_memchunk schunk = chunk; + pa_memchunk schunk = chunk; if (schunk.length > r->fragment_size) schunk.length = r->fragment_size; @@ -451,7 +451,7 @@ static void send_memblock(struct connection *c) { } static void send_playback_stream_killed(struct playback_stream *p) { - struct pa_tagstruct *t; + pa_tagstruct *t; assert(p); t = pa_tagstruct_new(NULL, 0); @@ -463,7 +463,7 @@ static void send_playback_stream_killed(struct playback_stream *p) { } static void send_record_stream_killed(struct record_stream *r) { - struct pa_tagstruct *t; + pa_tagstruct *t; assert(r); t = pa_tagstruct_new(NULL, 0); @@ -476,7 +476,7 @@ static void send_record_stream_killed(struct record_stream *r) { /*** sinkinput callbacks ***/ -static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk) { +static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { struct playback_stream *s; assert(i && i->userdata && chunk); s = i->userdata; @@ -487,7 +487,7 @@ static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk return 0; } -static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length) { +static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { struct playback_stream *s; assert(i && i->userdata && length); s = i->userdata; @@ -503,13 +503,13 @@ static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk /* pa_log(__FILE__": after_drop: %u\n", pa_memblockq_get_length(s->memblockq)); */ } -static void sink_input_kill_cb(struct pa_sink_input *i) { +static void sink_input_kill_cb(pa_sink_input *i) { assert(i && i->userdata); send_playback_stream_killed((struct playback_stream *) i->userdata); playback_stream_free((struct playback_stream *) i->userdata); } -static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i) { +static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { struct playback_stream *s; assert(i && i->userdata); s = i->userdata; @@ -521,7 +521,7 @@ static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i) { /*** source_output callbacks ***/ -static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk) { +static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { struct record_stream *s; assert(o && o->userdata && chunk); s = o->userdata; @@ -531,13 +531,13 @@ static void source_output_push_cb(struct pa_source_output *o, const struct pa_me send_memblock(s->connection); } -static void source_output_kill_cb(struct pa_source_output *o) { +static void source_output_kill_cb(pa_source_output *o) { assert(o && o->userdata); send_record_stream_killed((struct record_stream *) o->userdata); record_stream_free((struct record_stream *) o->userdata); } -static pa_usec_t source_output_get_latency_cb(struct pa_source_output *o) { +static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { struct record_stream *s; assert(o && o->userdata); s = o->userdata; @@ -554,15 +554,15 @@ static void protocol_error(struct connection *c) { connection_free(c); } -static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; struct playback_stream *s; size_t maxlength, tlength, prebuf, minreq; uint32_t sink_index; const char *name, *sink_name; - struct pa_sample_spec ss; - struct pa_tagstruct *reply; - struct pa_sink *sink; + pa_sample_spec ss; + pa_tagstruct *reply; + pa_sink *sink; pa_volume_t volume; int corked; assert(c && t && c->protocol && c->protocol->core); @@ -618,7 +618,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com request_bytes(s); } -static void command_delete_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; uint32_t channel; assert(c && t); @@ -664,15 +664,15 @@ static void command_delete_stream(struct pa_pdispatch *pd, uint32_t command, uin pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; struct record_stream *s; size_t maxlength, fragment_size; uint32_t source_index; const char *name, *source_name; - struct pa_sample_spec ss; - struct pa_tagstruct *reply; - struct pa_source *source; + pa_sample_spec ss; + pa_tagstruct *reply; + pa_source *source; int corked; assert(c && t && c->protocol && c->protocol->core); @@ -720,7 +720,7 @@ static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t comma pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_exit(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; assert(c && t); @@ -740,7 +740,7 @@ static void command_exit(struct pa_pdispatch *pd, uint32_t command, uint32_t tag return; } -static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; const void*cookie; assert(c && t); @@ -769,7 +769,7 @@ static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag return; } -static void command_set_client_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_set_client_name(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; const char *name; assert(c && t); @@ -785,10 +785,10 @@ static void command_set_client_name(struct pa_pdispatch *pd, uint32_t command, u return; } -static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; const char *name; - uint32_t index = PA_IDXSET_INVALID; + uint32_t idx = PA_IDXSET_INVALID; assert(c && t); if (pa_tagstruct_gets(t, &name) < 0 || !name || @@ -803,36 +803,36 @@ static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t t } if (command == PA_COMMAND_LOOKUP_SINK) { - struct pa_sink *sink; + pa_sink *sink; if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1))) - index = sink->index; + idx = sink->index; } else { - struct pa_source *source; + pa_source *source; assert(command == PA_COMMAND_LOOKUP_SOURCE); if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1))) - index = source->index; + idx = source->index; } - if (index == PA_IDXSET_INVALID) + if (idx == PA_IDXSET_INVALID) pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); else { - struct pa_tagstruct *reply; + pa_tagstruct *reply; reply = pa_tagstruct_new(NULL, 0); assert(reply); pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); pa_tagstruct_putu32(reply, tag); - pa_tagstruct_putu32(reply, index); + pa_tagstruct_putu32(reply, idx); pa_pstream_send_tagstruct(c->pstream, reply); } } -static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - uint32_t index; + uint32_t idx; struct playback_stream *s; assert(c && t); - if (pa_tagstruct_getu32(t, &index) < 0 || + if (pa_tagstruct_getu32(t, &idx) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -843,7 +843,7 @@ static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t comm return; } - if (!(s = pa_idxset_get_by_index(c->output_streams, index)) || s->type != PLAYBACK_STREAM) { + if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -864,9 +864,9 @@ static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t comm } } -static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - struct pa_tagstruct *reply; + pa_tagstruct *reply; assert(c && t); if (!pa_tagstruct_eof(t)) { @@ -891,16 +891,16 @@ static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - struct pa_tagstruct *reply; + pa_tagstruct *reply; struct playback_stream *s; struct timeval tv, now; uint64_t counter; - uint32_t index; + uint32_t idx; assert(c && t); - if (pa_tagstruct_getu32(t, &index) < 0 || + if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_get_timeval(t, &tv) < 0 || pa_tagstruct_getu64(t, &counter) < 0 || !pa_tagstruct_eof(t)) { @@ -913,7 +913,7 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma return; } - if (!(s = pa_idxset_get_by_index(c->output_streams, index)) || s->type != PLAYBACK_STREAM) { + if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -934,16 +934,16 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_get_record_latency(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - struct pa_tagstruct *reply; + pa_tagstruct *reply; struct record_stream *s; struct timeval tv, now; uint64_t counter; - uint32_t index; + uint32_t idx; assert(c && t); - if (pa_tagstruct_getu32(t, &index) < 0 || + if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_get_timeval(t, &tv) < 0 || pa_tagstruct_getu64(t, &counter) < 0 || !pa_tagstruct_eof(t)) { @@ -956,7 +956,7 @@ static void command_get_record_latency(struct pa_pdispatch *pd, uint32_t command return; } - if (!(s = pa_idxset_get_by_index(c->record_streams, index))) { + if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -978,13 +978,13 @@ static void command_get_record_latency(struct pa_pdispatch *pd, uint32_t command } -static void command_create_upload_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; struct upload_stream *s; size_t length; const char *name; - struct pa_sample_spec ss; - struct pa_tagstruct *reply; + pa_sample_spec ss; + pa_tagstruct *reply; assert(c && t && c->protocol && c->protocol->core); if (pa_tagstruct_gets(t, &name) < 0 || !name || @@ -1019,11 +1019,11 @@ static void command_create_upload_stream(struct pa_pdispatch *pd, uint32_t comma pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_finish_upload_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; uint32_t channel; struct upload_stream *s; - uint32_t index; + uint32_t idx; assert(c && t); if (pa_tagstruct_getu32(t, &channel) < 0 || @@ -1042,15 +1042,15 @@ static void command_finish_upload_stream(struct pa_pdispatch *pd, uint32_t comma return; } - pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->memchunk, &index); + pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->memchunk, &idx); pa_pstream_send_simple_ack(c->pstream, tag); upload_stream_free(s); } -static void command_play_sample(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; uint32_t sink_index, volume; - struct pa_sink *sink; + pa_sink *sink; const char *name, *sink_name; assert(c && t); @@ -1086,7 +1086,7 @@ static void command_play_sample(struct pa_pdispatch *pd, uint32_t command, uint3 pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_remove_sample(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_remove_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; const char *name; assert(c && t); @@ -1110,7 +1110,7 @@ static void command_remove_sample(struct pa_pdispatch *pd, uint32_t command, uin pa_pstream_send_simple_ack(c->pstream, tag); } -static void sink_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink *sink) { +static void sink_fill_tagstruct(pa_tagstruct *t, pa_sink *sink) { assert(t && sink); pa_tagstruct_putu32(t, sink->index); pa_tagstruct_puts(t, sink->name); @@ -1124,7 +1124,7 @@ static void sink_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink *sink) { pa_tagstruct_putu32(t, sink->typeid); } -static void source_fill_tagstruct(struct pa_tagstruct *t, struct pa_source *source) { +static void source_fill_tagstruct(pa_tagstruct *t, pa_source *source) { assert(t && source); pa_tagstruct_putu32(t, source->index); pa_tagstruct_puts(t, source->name); @@ -1137,7 +1137,7 @@ static void source_fill_tagstruct(struct pa_tagstruct *t, struct pa_source *sour pa_tagstruct_putu32(t, source->typeid); } -static void client_fill_tagstruct(struct pa_tagstruct *t, struct pa_client *client) { +static void client_fill_tagstruct(pa_tagstruct *t, pa_client *client) { assert(t && client); pa_tagstruct_putu32(t, client->index); pa_tagstruct_puts(t, client->name); @@ -1145,7 +1145,7 @@ static void client_fill_tagstruct(struct pa_tagstruct *t, struct pa_client *clie pa_tagstruct_putu32(t, client->typeid); } -static void module_fill_tagstruct(struct pa_tagstruct *t, struct pa_module *module) { +static void module_fill_tagstruct(pa_tagstruct *t, pa_module *module) { assert(t && module); pa_tagstruct_putu32(t, module->index); pa_tagstruct_puts(t, module->name); @@ -1154,7 +1154,7 @@ static void module_fill_tagstruct(struct pa_tagstruct *t, struct pa_module *modu pa_tagstruct_put_boolean(t, module->auto_unload); } -static void sink_input_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink_input *s) { +static void sink_input_fill_tagstruct(pa_tagstruct *t, pa_sink_input *s) { assert(t && s); pa_tagstruct_putu32(t, s->index); pa_tagstruct_puts(t, s->name); @@ -1169,7 +1169,7 @@ static void sink_input_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink_inp pa_tagstruct_putu32(t, s->typeid); } -static void source_output_fill_tagstruct(struct pa_tagstruct *t, struct pa_source_output *s) { +static void source_output_fill_tagstruct(pa_tagstruct *t, pa_source_output *s) { assert(t && s); pa_tagstruct_putu32(t, s->index); pa_tagstruct_puts(t, s->name); @@ -1183,7 +1183,7 @@ static void source_output_fill_tagstruct(struct pa_tagstruct *t, struct pa_sourc pa_tagstruct_putu32(t, s->typeid); } -static void scache_fill_tagstruct(struct pa_tagstruct *t, struct pa_scache_entry *e) { +static void scache_fill_tagstruct(pa_tagstruct *t, pa_scache_entry *e) { assert(t && e); pa_tagstruct_putu32(t, e->index); pa_tagstruct_puts(t, e->name); @@ -1195,22 +1195,22 @@ static void scache_fill_tagstruct(struct pa_tagstruct *t, struct pa_scache_entry pa_tagstruct_puts(t, e->filename); } -static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - uint32_t index; - struct pa_sink *sink = NULL; - struct pa_source *source = NULL; - struct pa_client *client = NULL; - struct pa_module *module = NULL; - struct pa_sink_input *si = NULL; - struct pa_source_output *so = NULL; - struct pa_scache_entry *sce = NULL; + uint32_t idx; + pa_sink *sink = NULL; + pa_source *source = NULL; + pa_client *client = NULL; + pa_module *module = NULL; + pa_sink_input *si = NULL; + pa_source_output *so = NULL; + pa_scache_entry *sce = NULL; const char *name; - struct pa_tagstruct *reply; + pa_tagstruct *reply; assert(c && t); - if (pa_tagstruct_getu32(t, &index) < 0 || + if (pa_tagstruct_getu32(t, &idx) < 0 || (command != PA_COMMAND_GET_CLIENT_INFO && command != PA_COMMAND_GET_MODULE_INFO && command != PA_COMMAND_GET_SINK_INPUT_INFO && @@ -1227,27 +1227,27 @@ static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t } if (command == PA_COMMAND_GET_SINK_INFO) { - if (index != (uint32_t) -1) - sink = pa_idxset_get_by_index(c->protocol->core->sinks, index); + if (idx != (uint32_t) -1) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); else sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); } else if (command == PA_COMMAND_GET_SOURCE_INFO) { - if (index != (uint32_t) -1) - source = pa_idxset_get_by_index(c->protocol->core->sources, index); + if (idx != (uint32_t) -1) + source = pa_idxset_get_by_index(c->protocol->core->sources, idx); else source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); } else if (command == PA_COMMAND_GET_CLIENT_INFO) - client = pa_idxset_get_by_index(c->protocol->core->clients, index); + client = pa_idxset_get_by_index(c->protocol->core->clients, idx); else if (command == PA_COMMAND_GET_MODULE_INFO) - module = pa_idxset_get_by_index(c->protocol->core->modules, index); + module = pa_idxset_get_by_index(c->protocol->core->modules, idx); else if (command == PA_COMMAND_GET_SINK_INPUT_INFO) - si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, index); + si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO) - so = pa_idxset_get_by_index(c->protocol->core->source_outputs, index); + so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); else { assert(command == PA_COMMAND_GET_SAMPLE_INFO); - if (index != (uint32_t) -1) - sce = pa_idxset_get_by_index(c->protocol->core->scache, index); + if (idx != (uint32_t) -1) + sce = pa_idxset_get_by_index(c->protocol->core->scache, idx); else sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE, 0); } @@ -1278,12 +1278,12 @@ static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - struct pa_idxset *i; - uint32_t index; + pa_idxset *i; + uint32_t idx; void *p; - struct pa_tagstruct *reply; + pa_tagstruct *reply; assert(c && t); if (!pa_tagstruct_eof(t)) { @@ -1319,7 +1319,7 @@ static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uin } if (i) { - for (p = pa_idxset_first(i, &index); p; p = pa_idxset_next(i, &index)) { + for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) { if (command == PA_COMMAND_GET_SINK_INFO_LIST) sink_fill_tagstruct(reply, p); else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST) @@ -1342,9 +1342,9 @@ static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uin pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_get_server_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - struct pa_tagstruct *reply; + pa_tagstruct *reply; char txt[256]; const char *n; assert(c && t); @@ -1379,8 +1379,8 @@ static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, u pa_pstream_send_tagstruct(c->pstream, reply); } -static void subscription_cb(struct pa_core *core, enum pa_subscription_event_type e, uint32_t index, void *userdata) { - struct pa_tagstruct *t; +static void subscription_cb(pa_core *core, pa_subscription_event_type e, uint32_t idx, void *userdata) { + pa_tagstruct *t; struct connection *c = userdata; assert(c && core); @@ -1389,13 +1389,13 @@ static void subscription_cb(struct pa_core *core, enum pa_subscription_event_typ pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT); pa_tagstruct_putu32(t, (uint32_t) -1); pa_tagstruct_putu32(t, e); - pa_tagstruct_putu32(t, index); + pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); } -static void command_subscribe(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - enum pa_subscription_mask m; + pa_subscription_mask m; assert(c && t); if (pa_tagstruct_getu32(t, &m) < 0 || @@ -1421,15 +1421,15 @@ static void command_subscribe(struct pa_pdispatch *pd, uint32_t command, uint32_ pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_set_volume(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_set_volume(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - uint32_t index, volume; - struct pa_sink *sink = NULL; - struct pa_sink_input *si = NULL; + uint32_t idx, volume; + pa_sink *sink = NULL; + pa_sink_input *si = NULL; const char *name = NULL; assert(c && t); - if (pa_tagstruct_getu32(t, &index) < 0 || + if (pa_tagstruct_getu32(t, &idx) < 0 || (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) || pa_tagstruct_getu32(t, &volume) || !pa_tagstruct_eof(t)) { @@ -1443,13 +1443,13 @@ static void command_set_volume(struct pa_pdispatch *pd, uint32_t command, uint32 } if (command == PA_COMMAND_SET_SINK_VOLUME) { - if (index != (uint32_t) -1) - sink = pa_idxset_get_by_index(c->protocol->core->sinks, index); + if (idx != (uint32_t) -1) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); else sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); } else { assert(command == PA_COMMAND_SET_SINK_INPUT_VOLUME); - si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, index); + si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); } if (!si && !sink) { @@ -1465,14 +1465,14 @@ static void command_set_volume(struct pa_pdispatch *pd, uint32_t command, uint32 pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_cork_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - uint32_t index; + uint32_t idx; int b; struct playback_stream *s; assert(c && t); - if (pa_tagstruct_getu32(t, &index) < 0 || + if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_get_boolean(t, &b) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1484,7 +1484,7 @@ static void command_cork_playback_stream(struct pa_pdispatch *pd, uint32_t comma return; } - if (!(s = pa_idxset_get_by_index(c->output_streams, index)) || s->type != PLAYBACK_STREAM) { + if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -1493,13 +1493,13 @@ static void command_cork_playback_stream(struct pa_pdispatch *pd, uint32_t comma pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_flush_or_trigger_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_flush_or_trigger_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - uint32_t index; + uint32_t idx; struct playback_stream *s; assert(c && t); - if (pa_tagstruct_getu32(t, &index) < 0 || + if (pa_tagstruct_getu32(t, &idx) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1510,7 +1510,7 @@ static void command_flush_or_trigger_playback_stream(struct pa_pdispatch *pd, ui return; } - if (!(s = pa_idxset_get_by_index(c->output_streams, index)) || s->type != PLAYBACK_STREAM) { + if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -1530,14 +1530,14 @@ static void command_flush_or_trigger_playback_stream(struct pa_pdispatch *pd, ui request_bytes(s); } -static void command_cork_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_cork_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - uint32_t index; + uint32_t idx; struct record_stream *s; int b; assert(c && t); - if (pa_tagstruct_getu32(t, &index) < 0 || + if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_get_boolean(t, &b) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1549,7 +1549,7 @@ static void command_cork_record_stream(struct pa_pdispatch *pd, uint32_t command return; } - if (!(s = pa_idxset_get_by_index(c->record_streams, index))) { + if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -1558,13 +1558,13 @@ static void command_cork_record_stream(struct pa_pdispatch *pd, uint32_t command pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_flush_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_flush_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - uint32_t index; + uint32_t idx; struct record_stream *s; assert(c && t); - if (pa_tagstruct_getu32(t, &index) < 0 || + if (pa_tagstruct_getu32(t, &idx) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1575,7 +1575,7 @@ static void command_flush_record_stream(struct pa_pdispatch *pd, uint32_t comman return; } - if (!(s = pa_idxset_get_by_index(c->record_streams, index))) { + if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -1584,13 +1584,13 @@ static void command_flush_record_stream(struct pa_pdispatch *pd, uint32_t comman pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_set_default_sink_or_source(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_set_default_sink_or_source(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - uint32_t index; + uint32_t idx; const char *s; assert(c && t); - if (pa_tagstruct_getu32(t, &index) < 0 || + if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_gets(t, &s) < 0 || !s || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1606,13 +1606,13 @@ static void command_set_default_sink_or_source(struct pa_pdispatch *pd, uint32_t pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_set_stream_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - uint32_t index; + uint32_t idx; const char *name; assert(c && t); - if (pa_tagstruct_getu32(t, &index) < 0 || + if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_gets(t, &name) < 0 || !name || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1627,7 +1627,7 @@ static void command_set_stream_name(struct pa_pdispatch *pd, uint32_t command, u if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) { struct playback_stream *s; - if (!(s = pa_idxset_get_by_index(c->output_streams, index)) || s->type != PLAYBACK_STREAM) { + if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -1637,7 +1637,7 @@ static void command_set_stream_name(struct pa_pdispatch *pd, uint32_t command, u } else { struct record_stream *s; - if (!(s = pa_idxset_get_by_index(c->record_streams, index))) { + if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -1648,12 +1648,12 @@ static void command_set_stream_name(struct pa_pdispatch *pd, uint32_t command, u pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_kill(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - uint32_t index; + uint32_t idx; assert(c && t); - if (pa_tagstruct_getu32(t, &index) < 0 || + if (pa_tagstruct_getu32(t, &idx) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1665,29 +1665,29 @@ static void command_kill(struct pa_pdispatch *pd, uint32_t command, uint32_t tag } if (command == PA_COMMAND_KILL_CLIENT) { - struct pa_client *client; + pa_client *client; - if (!(client = pa_idxset_get_by_index(c->protocol->core->clients, index))) { + if (!(client = pa_idxset_get_by_index(c->protocol->core->clients, idx))) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } pa_client_kill(client); } else if (command == PA_COMMAND_KILL_SINK_INPUT) { - struct pa_sink_input *s; + pa_sink_input *s; - if (!(s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, index))) { + if (!(s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx))) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } pa_sink_input_kill(s); } else { - struct pa_source_output *s; + pa_source_output *s; assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT); - if (!(s = pa_idxset_get_by_index(c->protocol->core->source_outputs, index))) { + if (!(s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx))) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -1698,11 +1698,11 @@ static void command_kill(struct pa_pdispatch *pd, uint32_t command, uint32_t tag pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_load_module(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_load_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - struct pa_module *m; + pa_module *m; const char *name, *argument; - struct pa_tagstruct *reply; + pa_tagstruct *reply; assert(c && t); if (pa_tagstruct_gets(t, &name) < 0 || !name || @@ -1729,13 +1729,13 @@ static void command_load_module(struct pa_pdispatch *pd, uint32_t command, uint3 pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_unload_module(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_unload_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - uint32_t index; - struct pa_module *m; + uint32_t idx; + pa_module *m; assert(c && t); - if (pa_tagstruct_getu32(t, &index) < 0 || + if (pa_tagstruct_getu32(t, &idx) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1746,7 +1746,7 @@ static void command_unload_module(struct pa_pdispatch *pd, uint32_t command, uin return; } - if (!(m = pa_idxset_get_by_index(c->protocol->core->modules, index))) { + if (!(m = pa_idxset_get_by_index(c->protocol->core->modules, idx))) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -1755,12 +1755,12 @@ static void command_unload_module(struct pa_pdispatch *pd, uint32_t command, uin pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_add_autoload(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_add_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; const char *name, *module, *argument; uint32_t type; - uint32_t index; - struct pa_tagstruct *reply; + uint32_t idx; + pa_tagstruct *reply; assert(c && t); if (pa_tagstruct_gets(t, &name) < 0 || !name || @@ -1777,7 +1777,7 @@ static void command_add_autoload(struct pa_pdispatch *pd, uint32_t command, uint return; } - if (pa_autoload_add(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, module, argument, &index) < 0) { + if (pa_autoload_add(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, module, argument, &idx) < 0) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); return; } @@ -1785,21 +1785,21 @@ static void command_add_autoload(struct pa_pdispatch *pd, uint32_t command, uint reply = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); pa_tagstruct_putu32(reply, tag); - pa_tagstruct_putu32(reply, index); + pa_tagstruct_putu32(reply, idx); pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_remove_autoload(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_remove_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; const char *name = NULL; - uint32_t type, index = PA_IDXSET_INVALID; + uint32_t type, idx = PA_IDXSET_INVALID; int r; assert(c && t); - if ((pa_tagstruct_getu32(t, &index) < 0 && + if ((pa_tagstruct_getu32(t, &idx) < 0 && (pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_getu32(t, &type) < 0)) || - (!name && index == PA_IDXSET_INVALID) || + (!name && idx == PA_IDXSET_INVALID) || (name && type > 1) || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1814,7 +1814,7 @@ static void command_remove_autoload(struct pa_pdispatch *pd, uint32_t command, u if (name) r = pa_autoload_remove_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE); else - r = pa_autoload_remove_by_index(c->protocol->core, index); + r = pa_autoload_remove_by_index(c->protocol->core, idx); if (r < 0) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); @@ -1824,7 +1824,7 @@ static void command_remove_autoload(struct pa_pdispatch *pd, uint32_t command, u pa_pstream_send_simple_ack(c->pstream, tag); } -static void autoload_fill_tagstruct(struct pa_tagstruct *t, const struct pa_autoload_entry *e) { +static void autoload_fill_tagstruct(pa_tagstruct *t, const pa_autoload_entry *e) { assert(t && e); pa_tagstruct_putu32(t, e->index); @@ -1834,18 +1834,18 @@ static void autoload_fill_tagstruct(struct pa_tagstruct *t, const struct pa_auto pa_tagstruct_puts(t, e->argument); } -static void command_get_autoload_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_get_autoload_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - const struct pa_autoload_entry *a = NULL; - uint32_t type, index; + const pa_autoload_entry *a = NULL; + uint32_t type, idx; const char *name; - struct pa_tagstruct *reply; + pa_tagstruct *reply; assert(c && t); - if ((pa_tagstruct_getu32(t, &index) < 0 && + if ((pa_tagstruct_getu32(t, &idx) < 0 && (pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_getu32(t, &type) < 0)) || - (!name && index == PA_IDXSET_INVALID) || + (!name && idx == PA_IDXSET_INVALID) || (name && type > 1) || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1861,7 +1861,7 @@ static void command_get_autoload_info(struct pa_pdispatch *pd, uint32_t command, if (name) a = pa_autoload_get_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE); else - a = pa_autoload_get_by_index(c->protocol->core, index); + a = pa_autoload_get_by_index(c->protocol->core, idx); if (!a) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); @@ -1876,9 +1876,9 @@ static void command_get_autoload_info(struct pa_pdispatch *pd, uint32_t command, pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_get_autoload_info_list(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - struct pa_tagstruct *reply; + pa_tagstruct *reply; assert(c && t); if (!pa_tagstruct_eof(t)) { @@ -1896,7 +1896,7 @@ static void command_get_autoload_info_list(struct pa_pdispatch *pd, uint32_t com pa_tagstruct_putu32(reply, tag); if (c->protocol->core->autoload_hashmap) { - struct pa_autoload_entry *a; + pa_autoload_entry *a; void *state = NULL; while ((a = pa_hashmap_iterate(c->protocol->core->autoload_hashmap, &state, NULL))) @@ -1908,7 +1908,7 @@ static void command_get_autoload_info_list(struct pa_pdispatch *pd, uint32_t com /*** pstream callbacks ***/ -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { struct connection *c = userdata; assert(p && packet && packet->data && c); @@ -1918,7 +1918,7 @@ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *pack } } -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk, void *userdata) { +static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata) { struct connection *c = userdata; struct output_stream *stream; assert(p && chunk && userdata); @@ -1930,17 +1930,17 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, ui } if (stream->type == PLAYBACK_STREAM) { - struct playback_stream *p = (struct playback_stream*) stream; - if (chunk->length >= p->requested_bytes) - p->requested_bytes = 0; + struct playback_stream *ps = (struct playback_stream*) stream; + if (chunk->length >= ps->requested_bytes) + ps->requested_bytes = 0; else - p->requested_bytes -= chunk->length; + ps->requested_bytes -= chunk->length; - pa_memblockq_push_align(p->memblockq, chunk, delta); - assert(p->sink_input); + pa_memblockq_push_align(ps->memblockq, chunk, delta); + assert(ps->sink_input); /* pa_log(__FILE__": after_recv: %u\n", pa_memblockq_get_length(p->memblockq)); */ - pa_sink_notify(p->sink_input->sink); + pa_sink_notify(ps->sink_input->sink); /* pa_log(__FILE__": Recieved %u bytes.\n", chunk->length); */ } else { @@ -1974,7 +1974,7 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, ui } } -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { +static void pstream_die_callback(pa_pstream *p, void *userdata) { struct connection *c = userdata; assert(p && c); connection_free(c); @@ -1983,7 +1983,7 @@ static void pstream_die_callback(struct pa_pstream *p, void *userdata) { } -static void pstream_drain_callback(struct pa_pstream *p, void *userdata) { +static void pstream_drain_callback(pa_pstream *p, void *userdata) { struct connection *c = userdata; assert(p && c); @@ -1992,14 +1992,14 @@ static void pstream_drain_callback(struct pa_pstream *p, void *userdata) { /*** client callbacks ***/ -static void client_kill_cb(struct pa_client *c) { +static void client_kill_cb(pa_client *c) { assert(c && c->userdata); connection_free(c->userdata); } /*** socket server callbacks ***/ -static void auth_timeout(struct pa_mainloop_api*m, struct pa_time_event *e, const struct timeval *tv, void *userdata) { +static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { struct connection *c = userdata; assert(m && tv && c && c->auth_timeout_event == e); @@ -2007,12 +2007,12 @@ static void auth_timeout(struct pa_mainloop_api*m, struct pa_time_event *e, cons connection_free(c); } -static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { - struct pa_protocol_native *p = userdata; +static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, void *userdata) { + pa_protocol_native *p = userdata; struct connection *c; assert(io && p); - if (pa_idxset_ncontents(p->connections)+1 > MAX_CONNECTIONS) { + if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { pa_log_warn(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); pa_iochannel_free(io); return; @@ -2061,7 +2061,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo /*** module entry points ***/ -static int load_key(struct pa_protocol_native*p, const char*fn) { +static int load_key(pa_protocol_native*p, const char*fn) { assert(p); p->auth_cookie_in_property = 0; @@ -2087,8 +2087,8 @@ static int load_key(struct pa_protocol_native*p, const char*fn) { return 0; } -static struct pa_protocol_native* protocol_new_internal(struct pa_core *c, struct pa_module *m, struct pa_modargs *ma) { - struct pa_protocol_native *p; +static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_modargs *ma) { + pa_protocol_native *p; int public = 0; assert(c && ma); @@ -2097,7 +2097,7 @@ static struct pa_protocol_native* protocol_new_internal(struct pa_core *c, struc return NULL; } - p = pa_xmalloc(sizeof(struct pa_protocol_native)); + p = pa_xmalloc(sizeof(pa_protocol_native)); p->core = c; p->module = m; p->public = public; @@ -2114,9 +2114,9 @@ static struct pa_protocol_native* protocol_new_internal(struct pa_core *c, struc return p; } -struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { +pa_protocol_native* pa_protocol_native_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { char t[256]; - struct pa_protocol_native *p; + pa_protocol_native *p; if (!(p = protocol_new_internal(core, m, ma))) return NULL; @@ -2125,7 +2125,7 @@ struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct p pa_socket_server_set_callback(p->server, on_connection, p); if (pa_socket_server_get_address(p->server, t, sizeof(t))) { - struct pa_strlist *l; + pa_strlist *l; l = pa_property_get(core, PA_NATIVE_SERVER_PROPERTY_NAME); l = pa_strlist_prepend(l, t); pa_property_replace(core, PA_NATIVE_SERVER_PROPERTY_NAME, l); @@ -2134,7 +2134,7 @@ struct pa_protocol_native* pa_protocol_native_new(struct pa_core *core, struct p return p; } -void pa_protocol_native_free(struct pa_protocol_native *p) { +void pa_protocol_native_free(pa_protocol_native *p) { struct connection *c; assert(p); @@ -2146,7 +2146,7 @@ void pa_protocol_native_free(struct pa_protocol_native *p) { char t[256]; if (pa_socket_server_get_address(p->server, t, sizeof(t))) { - struct pa_strlist *l; + pa_strlist *l; l = pa_property_get(p->core, PA_NATIVE_SERVER_PROPERTY_NAME); l = pa_strlist_remove(l, t); @@ -2165,8 +2165,8 @@ void pa_protocol_native_free(struct pa_protocol_native *p) { pa_xfree(p); } -struct pa_protocol_native* pa_protocol_native_new_iochannel(struct pa_core*core, struct pa_iochannel *io, struct pa_module *m, struct pa_modargs *ma) { - struct pa_protocol_native *p; +pa_protocol_native* pa_protocol_native_new_iochannel(pa_core*core, pa_iochannel *io, pa_module *m, pa_modargs *ma) { + pa_protocol_native *p; if (!(p = protocol_new_internal(core, m, ma))) return NULL; diff --git a/polyp/protocol-native.h b/polyp/protocol-native.h index 57c29e38..12e85d0b 100644 --- a/polyp/protocol-native.h +++ b/polyp/protocol-native.h @@ -27,11 +27,11 @@ #include "module.h" #include "modargs.h" -struct pa_protocol_native; +typedef struct pa_protocol_native pa_protocol_native; -struct pa_protocol_native* pa_protocol_native_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma); -void pa_protocol_native_free(struct pa_protocol_native *n); +pa_protocol_native* pa_protocol_native_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma); +void pa_protocol_native_free(pa_protocol_native *n); -struct pa_protocol_native* pa_protocol_native_new_iochannel(struct pa_core*core, struct pa_iochannel *io, struct pa_module *m, struct pa_modargs *ma); +pa_protocol_native* pa_protocol_native_new_iochannel(pa_core*core, pa_iochannel *io, pa_module *m, pa_modargs *ma); #endif diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index 8d05a7fa..a3d7099c 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -45,31 +45,31 @@ #define PA_TYPEID_SIMPLE PA_TYPEID_MAKE('S', 'M', 'P', 'L') struct connection { - struct pa_protocol_simple *protocol; - struct pa_iochannel *io; - struct pa_sink_input *sink_input; - struct pa_source_output *source_output; - struct pa_client *client; - struct pa_memblockq *input_memblockq, *output_memblockq; - struct pa_defer_event *defer_event; + pa_protocol_simple *protocol; + pa_iochannel *io; + pa_sink_input *sink_input; + pa_source_output *source_output; + pa_client *client; + pa_memblockq *input_memblockq, *output_memblockq; + pa_defer_event *defer_event; struct { - struct pa_memblock *current_memblock; + pa_memblock *current_memblock; size_t memblock_index, fragment_size; } playback; }; struct pa_protocol_simple { - struct pa_module *module; - struct pa_core *core; - struct pa_socket_server*server; - struct pa_idxset *connections; + pa_module *module; + pa_core *core; + pa_socket_server*server; + pa_idxset *connections; enum { RECORD = 1, PLAYBACK = 2, DUPLEX = 3 } mode; - struct pa_sample_spec sample_spec; + pa_sample_spec sample_spec; char *source_name, *sink_name; }; @@ -107,7 +107,7 @@ static void connection_free(struct connection *c) { } static int do_read(struct connection *c) { - struct pa_memchunk chunk; + pa_memchunk chunk; ssize_t r; size_t l; @@ -151,7 +151,7 @@ static int do_read(struct connection *c) { } static int do_write(struct connection *c) { - struct pa_memchunk chunk; + pa_memchunk chunk; ssize_t r; if (!c->source_output) @@ -201,7 +201,7 @@ fail: /*** sink_input callbacks ***/ -static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk) { +static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { struct connection*c; assert(i && i->userdata && chunk); c = i->userdata; @@ -212,7 +212,7 @@ static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk return 0; } -static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length) { +static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { struct connection*c = i->userdata; assert(i && c && length); @@ -223,13 +223,13 @@ static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk c->protocol->core->mainloop->defer_enable(c->defer_event, 1); } -static void sink_input_kill_cb(struct pa_sink_input *i) { +static void sink_input_kill_cb(pa_sink_input *i) { assert(i && i->userdata); connection_free((struct connection *) i->userdata); } -static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i) { +static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { struct connection*c = i->userdata; assert(i && c); return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); @@ -237,7 +237,7 @@ static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i) { /*** source_output callbacks ***/ -static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk) { +static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { struct connection *c = o->userdata; assert(o && c && chunk); @@ -248,12 +248,12 @@ static void source_output_push_cb(struct pa_source_output *o, const struct pa_me c->protocol->core->mainloop->defer_enable(c->defer_event, 1); } -static void source_output_kill_cb(struct pa_source_output *o) { +static void source_output_kill_cb(pa_source_output *o) { assert(o && o->userdata); connection_free((struct connection *) o->userdata); } -static pa_usec_t source_output_get_latency_cb(struct pa_source_output *o) { +static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { struct connection*c = o->userdata; assert(o && c); return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec); @@ -261,14 +261,14 @@ static pa_usec_t source_output_get_latency_cb(struct pa_source_output *o) { /*** client callbacks ***/ -static void client_kill_cb(struct pa_client *c) { +static void client_kill_cb(pa_client *c) { assert(c && c->userdata); connection_free((struct connection *) c->userdata); } /*** pa_iochannel callbacks ***/ -static void io_callback(struct pa_iochannel*io, void *userdata) { +static void io_callback(pa_iochannel*io, void *userdata) { struct connection *c = userdata; assert(io && c && c->io == io); @@ -277,7 +277,7 @@ static void io_callback(struct pa_iochannel*io, void *userdata) { /*** fixed callback ***/ -static void defer_callback(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata) { +static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { struct connection *c = userdata; assert(a && c && c->defer_event == e); @@ -286,13 +286,13 @@ static void defer_callback(struct pa_mainloop_api*a, struct pa_defer_event *e, v /*** socket_server callbacks ***/ -static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { - struct pa_protocol_simple *p = userdata; +static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { + pa_protocol_simple *p = userdata; struct connection *c = NULL; char cname[256]; assert(s && io && p); - if (pa_idxset_ncontents(p->connections)+1 > MAX_CONNECTIONS) { + if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); pa_iochannel_free(io); return; @@ -317,7 +317,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->client->userdata = c; if (p->mode & PLAYBACK) { - struct pa_sink *sink; + pa_sink *sink; size_t l; if (!(sink = pa_namereg_get(p->core, p->sink_name, PA_NAMEREG_SINK, 1))) { @@ -347,7 +347,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo } if (p->mode & RECORD) { - struct pa_source *source; + pa_source *source; size_t l; if (!(source = pa_namereg_get(p->core, p->source_name, PA_NAMEREG_SOURCE, 1))) { @@ -387,12 +387,12 @@ fail: connection_free(c); } -struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { - struct pa_protocol_simple* p = NULL; +pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { + pa_protocol_simple* p = NULL; int enable; assert(core && server && ma); - p = pa_xmalloc0(sizeof(struct pa_protocol_simple)); + p = pa_xmalloc0(sizeof(pa_protocol_simple)); p->module = m; p->core = core; p->server = server; @@ -437,7 +437,7 @@ fail: } -void pa_protocol_simple_free(struct pa_protocol_simple *p) { +void pa_protocol_simple_free(pa_protocol_simple *p) { struct connection *c; assert(p); diff --git a/polyp/protocol-simple.h b/polyp/protocol-simple.h index 7b15ffcd..63455a53 100644 --- a/polyp/protocol-simple.h +++ b/polyp/protocol-simple.h @@ -27,9 +27,9 @@ #include "core.h" #include "modargs.h" -struct pa_protocol_simple; +typedef struct pa_protocol_simple pa_protocol_simple; -struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma); -void pa_protocol_simple_free(struct pa_protocol_simple *n); +pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma); +void pa_protocol_simple_free(pa_protocol_simple *n); #endif diff --git a/polyp/pstream-util.c b/polyp/pstream-util.c index 8526f29c..ecd63d15 100644 --- a/polyp/pstream-util.c +++ b/polyp/pstream-util.c @@ -28,10 +28,10 @@ #include "native-common.h" #include "pstream-util.h" -void pa_pstream_send_tagstruct(struct pa_pstream *p, struct pa_tagstruct *t) { +void pa_pstream_send_tagstruct(pa_pstream *p, pa_tagstruct *t) { size_t length; uint8_t *data; - struct pa_packet *packet; + pa_packet *packet; assert(p); assert(t); @@ -43,8 +43,8 @@ void pa_pstream_send_tagstruct(struct pa_pstream *p, struct pa_tagstruct *t) { pa_packet_unref(packet); } -void pa_pstream_send_error(struct pa_pstream *p, uint32_t tag, uint32_t error) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); +void pa_pstream_send_error(pa_pstream *p, uint32_t tag, uint32_t error) { + pa_tagstruct *t = pa_tagstruct_new(NULL, 0); assert(t); pa_tagstruct_putu32(t, PA_COMMAND_ERROR); pa_tagstruct_putu32(t, tag); @@ -52,8 +52,8 @@ void pa_pstream_send_error(struct pa_pstream *p, uint32_t tag, uint32_t error) { pa_pstream_send_tagstruct(p, t); } -void pa_pstream_send_simple_ack(struct pa_pstream *p, uint32_t tag) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); +void pa_pstream_send_simple_ack(pa_pstream *p, uint32_t tag) { + pa_tagstruct *t = pa_tagstruct_new(NULL, 0); assert(t); pa_tagstruct_putu32(t, PA_COMMAND_REPLY); pa_tagstruct_putu32(t, tag); diff --git a/polyp/pstream-util.h b/polyp/pstream-util.h index 9560bfe7..601a9e99 100644 --- a/polyp/pstream-util.h +++ b/polyp/pstream-util.h @@ -27,9 +27,9 @@ #include "tagstruct.h" /* The tagstruct is freed!*/ -void pa_pstream_send_tagstruct(struct pa_pstream *p, struct pa_tagstruct *t); +void pa_pstream_send_tagstruct(pa_pstream *p, pa_tagstruct *t); -void pa_pstream_send_error(struct pa_pstream *p, uint32_t tag, uint32_t error); -void pa_pstream_send_simple_ack(struct pa_pstream *p, uint32_t tag); +void pa_pstream_send_error(pa_pstream *p, uint32_t tag, uint32_t error); +void pa_pstream_send_simple_ack(pa_pstream *p, uint32_t tag); #endif diff --git a/polyp/pstream.c b/polyp/pstream.c index 6f983289..bd00ba4f 100644 --- a/polyp/pstream.c +++ b/polyp/pstream.c @@ -39,12 +39,12 @@ #include "xmalloc.h" #include "log.h" -enum pa_pstream_descriptor_index { +typedef enum pa_pstream_descriptor_index { PA_PSTREAM_DESCRIPTOR_LENGTH, PA_PSTREAM_DESCRIPTOR_CHANNEL, PA_PSTREAM_DESCRIPTOR_DELTA, PA_PSTREAM_DESCRIPTOR_MAX -}; +} pa_pstream_descriptor_index; typedef uint32_t pa_pstream_descriptor[PA_PSTREAM_DESCRIPTOR_MAX]; @@ -55,24 +55,24 @@ struct item_info { enum { PA_PSTREAM_ITEM_PACKET, PA_PSTREAM_ITEM_MEMBLOCK } type; /* memblock info */ - struct pa_memchunk chunk; + pa_memchunk chunk; uint32_t channel; uint32_t delta; /* packet info */ - struct pa_packet *packet; + pa_packet *packet; }; struct pa_pstream { int ref; - struct pa_mainloop_api *mainloop; - struct pa_defer_event *defer_event; - struct pa_iochannel *io; - struct pa_queue *send_queue; + pa_mainloop_api *mainloop; + pa_defer_event *defer_event; + pa_iochannel *io; + pa_queue *send_queue; int dead; - void (*die_callback) (struct pa_pstream *p, void *userdata); + void (*die_callback) (pa_pstream *p, void *userdata); void *die_callback_userdata; struct { @@ -83,29 +83,29 @@ struct pa_pstream { } write; struct { - struct pa_memblock *memblock; - struct pa_packet *packet; + pa_memblock *memblock; + pa_packet *packet; pa_pstream_descriptor descriptor; void *data; size_t index; } read; - void (*recieve_packet_callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata); + void (*recieve_packet_callback) (pa_pstream *p, pa_packet *packet, void *userdata); void *recieve_packet_callback_userdata; - void (*recieve_memblock_callback) (struct pa_pstream *p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk, void *userdata); + void (*recieve_memblock_callback) (pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata); void *recieve_memblock_callback_userdata; - void (*drain_callback)(struct pa_pstream *p, void *userdata); + void (*drain_callback)(pa_pstream *p, void *userdata); void *drain_userdata; - struct pa_memblock_stat *memblock_stat; + pa_memblock_stat *memblock_stat; }; -static void do_write(struct pa_pstream *p); -static void do_read(struct pa_pstream *p); +static void do_write(pa_pstream *p); +static void do_read(pa_pstream *p); -static void do_something(struct pa_pstream *p) { +static void do_something(pa_pstream *p) { assert(p); p->mainloop->defer_enable(p->defer_event, 0); @@ -127,23 +127,23 @@ static void do_something(struct pa_pstream *p) { pa_pstream_unref(p); } -static void io_callback(struct pa_iochannel*io, void *userdata) { - struct pa_pstream *p = userdata; +static void io_callback(pa_iochannel*io, void *userdata) { + pa_pstream *p = userdata; assert(p && p->io == io); do_something(p); } -static void defer_callback(struct pa_mainloop_api *m, struct pa_defer_event *e, void*userdata) { - struct pa_pstream *p = userdata; +static void defer_callback(pa_mainloop_api *m, pa_defer_event *e, void*userdata) { + pa_pstream *p = userdata; assert(p && p->defer_event == e && p->mainloop == m); do_something(p); } -struct pa_pstream *pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel *io, struct pa_memblock_stat *s) { - struct pa_pstream *p; +pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_stat *s) { + pa_pstream *p; assert(io); - p = pa_xmalloc(sizeof(struct pa_pstream)); + p = pa_xmalloc(sizeof(pa_pstream)); p->ref = 1; p->io = io; pa_iochannel_set_callback(io, io_callback, p); @@ -183,7 +183,7 @@ struct pa_pstream *pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel return p; } -static void item_free(void *item, void *p) { +static void item_free(void *item, PA_GCC_UNUSED void *p) { struct item_info *i = item; assert(i); @@ -199,7 +199,7 @@ static void item_free(void *item, void *p) { pa_xfree(i); } -static void pstream_free(struct pa_pstream *p) { +static void pstream_free(pa_pstream *p) { assert(p); pa_pstream_close(p); @@ -218,7 +218,7 @@ static void pstream_free(struct pa_pstream *p) { pa_xfree(p); } -void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet) { +void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet) { struct item_info *i; assert(p && packet && p->ref >= 1); @@ -235,7 +235,7 @@ void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet) { p->mainloop->defer_enable(p->defer_event, 1); } -void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk) { +void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk) { struct item_info *i; assert(p && channel != (uint32_t) -1 && chunk && p->ref >= 1); @@ -256,21 +256,21 @@ void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, uint32_t de p->mainloop->defer_enable(p->defer_event, 1); } -void pa_pstream_set_recieve_packet_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata), void *userdata) { +void pa_pstream_set_recieve_packet_callback(pa_pstream *p, void (*callback) (pa_pstream *p, pa_packet *packet, void *userdata), void *userdata) { assert(p && callback); p->recieve_packet_callback = callback; p->recieve_packet_callback_userdata = userdata; } -void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk, void *userdata), void *userdata) { +void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, void (*callback) (pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata), void *userdata) { assert(p && callback); p->recieve_memblock_callback = callback; p->recieve_memblock_callback_userdata = userdata; } -static void prepare_next_write_item(struct pa_pstream *p) { +static void prepare_next_write_item(pa_pstream *p) { assert(p); if (!(p->write.current = pa_queue_pop(p->send_queue))) @@ -295,7 +295,7 @@ static void prepare_next_write_item(struct pa_pstream *p) { } } -static void do_write(struct pa_pstream *p) { +static void do_write(pa_pstream *p) { void *d; size_t l; ssize_t r; @@ -339,9 +339,9 @@ die: p->die_callback(p, p->die_callback_userdata); } -static void do_read(struct pa_pstream *p) { +static void do_read(pa_pstream *p) { void *d; - size_t l; + size_t l; ssize_t r; assert(p); @@ -386,12 +386,10 @@ static void do_read(struct pa_pstream *p) { /* Frame payload available */ if (p->read.memblock && p->recieve_memblock_callback) { /* Is this memblock data? Than pass it to the user */ - size_t l; - l = (p->read.index - r) < PA_PSTREAM_DESCRIPTOR_SIZE ? p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE : (size_t) r; if (l > 0) { - struct pa_memchunk chunk; + pa_memchunk chunk; chunk.memblock = p->read.memblock; chunk.index = p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE - l; @@ -437,13 +435,13 @@ die: } -void pa_pstream_set_die_callback(struct pa_pstream *p, void (*callback)(struct pa_pstream *p, void *userdata), void *userdata) { +void pa_pstream_set_die_callback(pa_pstream *p, void (*callback)(pa_pstream *p, void *userdata), void *userdata) { assert(p && callback); p->die_callback = callback; p->die_callback_userdata = userdata; } -int pa_pstream_is_pending(struct pa_pstream *p) { +int pa_pstream_is_pending(pa_pstream *p) { assert(p); if (p->dead) @@ -452,27 +450,27 @@ int pa_pstream_is_pending(struct pa_pstream *p) { return p->write.current || !pa_queue_is_empty(p->send_queue); } -void pa_pstream_set_drain_callback(struct pa_pstream *p, void (*cb)(struct pa_pstream *p, void *userdata), void *userdata) { +void pa_pstream_set_drain_callback(pa_pstream *p, void (*cb)(pa_pstream *p, void *userdata), void *userdata) { assert(p); p->drain_callback = cb; p->drain_userdata = userdata; } -void pa_pstream_unref(struct pa_pstream*p) { +void pa_pstream_unref(pa_pstream*p) { assert(p && p->ref >= 1); if (!(--(p->ref))) pstream_free(p); } -struct pa_pstream* pa_pstream_ref(struct pa_pstream*p) { +pa_pstream* pa_pstream_ref(pa_pstream*p) { assert(p && p->ref >= 1); p->ref++; return p; } -void pa_pstream_close(struct pa_pstream *p) { +void pa_pstream_close(pa_pstream *p) { assert(p); p->dead = 1; diff --git a/polyp/pstream.h b/polyp/pstream.h index 8fa62f06..77c92802 100644 --- a/polyp/pstream.h +++ b/polyp/pstream.h @@ -30,23 +30,23 @@ #include "mainloop-api.h" #include "memchunk.h" -struct pa_pstream; +typedef struct pa_pstream pa_pstream; -struct pa_pstream* pa_pstream_new(struct pa_mainloop_api *m, struct pa_iochannel *io, struct pa_memblock_stat *s); -void pa_pstream_unref(struct pa_pstream*p); -struct pa_pstream* pa_pstream_ref(struct pa_pstream*p); +pa_pstream* pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_stat *s); +void pa_pstream_unref(pa_pstream*p); +pa_pstream* pa_pstream_ref(pa_pstream*p); -void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet); -void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk); +void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet); +void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk); -void pa_pstream_set_recieve_packet_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, struct pa_packet *packet, void *userdata), void *userdata); -void pa_pstream_set_recieve_memblock_callback(struct pa_pstream *p, void (*callback) (struct pa_pstream *p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk, void *userdata), void *userdata); -void pa_pstream_set_drain_callback(struct pa_pstream *p, void (*cb)(struct pa_pstream *p, void *userdata), void *userdata); +void pa_pstream_set_recieve_packet_callback(pa_pstream *p, void (*callback) (pa_pstream *p, pa_packet *packet, void *userdata), void *userdata); +void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, void (*callback) (pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata), void *userdata); +void pa_pstream_set_drain_callback(pa_pstream *p, void (*cb)(pa_pstream *p, void *userdata), void *userdata); -void pa_pstream_set_die_callback(struct pa_pstream *p, void (*callback)(struct pa_pstream *p, void *userdata), void *userdata); +void pa_pstream_set_die_callback(pa_pstream *p, void (*callback)(pa_pstream *p, void *userdata), void *userdata); -int pa_pstream_is_pending(struct pa_pstream *p); +int pa_pstream_is_pending(pa_pstream *p); -void pa_pstream_close(struct pa_pstream *p); +void pa_pstream_close(pa_pstream *p); #endif diff --git a/polyp/queue.c b/polyp/queue.c index e0a06ae1..80ec0068 100644 --- a/polyp/queue.c +++ b/polyp/queue.c @@ -39,14 +39,14 @@ struct pa_queue { unsigned length; }; -struct pa_queue* pa_queue_new(void) { - struct pa_queue *q = pa_xmalloc(sizeof(struct pa_queue)); +pa_queue* pa_queue_new(void) { + pa_queue *q = pa_xnew(pa_queue, 1); q->front = q->back = NULL; q->length = 0; return q; } -void pa_queue_free(struct pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata) { +void pa_queue_free(pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata) { struct queue_entry *e; assert(q); @@ -64,10 +64,10 @@ void pa_queue_free(struct pa_queue* q, void (*destroy)(void *p, void *userdata), pa_xfree(q); } -void pa_queue_push(struct pa_queue *q, void *p) { +void pa_queue_push(pa_queue *q, void *p) { struct queue_entry *e; - e = pa_xmalloc(sizeof(struct queue_entry)); + e = pa_xnew(struct queue_entry, 1); e->data = p; e->next = NULL; @@ -82,7 +82,7 @@ void pa_queue_push(struct pa_queue *q, void *p) { q->length++; } -void* pa_queue_pop(struct pa_queue *q) { +void* pa_queue_pop(pa_queue *q) { void *p; struct queue_entry *e; assert(q); @@ -102,7 +102,7 @@ void* pa_queue_pop(struct pa_queue *q) { return p; } -int pa_queue_is_empty(struct pa_queue *q) { +int pa_queue_is_empty(pa_queue *q) { assert(q); return q->length == 0; } diff --git a/polyp/queue.h b/polyp/queue.h index a739ab74..3edcfb63 100644 --- a/polyp/queue.h +++ b/polyp/queue.h @@ -22,19 +22,19 @@ USA. ***/ -struct pa_queue; +typedef struct pa_queue pa_queue; /* A simple implementation of the abstract data type queue. Stores * pointers as members. The memory has to be managed by the caller. */ -struct pa_queue* pa_queue_new(void); +pa_queue* pa_queue_new(void); /* Free the queue and run the specified callback function for every remaining entry. The callback function may be NULL. */ -void pa_queue_free(struct pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata); +void pa_queue_free(pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata); -void pa_queue_push(struct pa_queue *q, void *p); -void* pa_queue_pop(struct pa_queue *q); +void pa_queue_push(pa_queue *q, void *p); +void* pa_queue_pop(pa_queue *q); -int pa_queue_is_empty(struct pa_queue *q); +int pa_queue_is_empty(pa_queue *q); #endif diff --git a/polyp/resampler.c b/polyp/resampler.c index 28e49209..96a1678f 100644 --- a/polyp/resampler.c +++ b/polyp/resampler.c @@ -34,16 +34,16 @@ #include "log.h" struct pa_resampler { - struct pa_sample_spec i_ss, o_ss; + pa_sample_spec i_ss, o_ss; size_t i_fz, o_fz; - struct pa_memblock_stat *memblock_stat; + pa_memblock_stat *memblock_stat; void *impl_data; int channels; - enum pa_resample_method resample_method; + pa_resample_method resample_method; - void (*impl_free)(struct pa_resampler *r); - void (*impl_set_input_rate)(struct pa_resampler *r, uint32_t rate); - void (*impl_run)(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out); + void (*impl_free)(pa_resampler *r); + void (*impl_set_input_rate)(pa_resampler *r, uint32_t rate); + void (*impl_run)(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out); }; struct impl_libsamplerate { @@ -59,17 +59,17 @@ struct impl_trivial { unsigned i_counter; }; -static int libsamplerate_init(struct pa_resampler*r); -static int trivial_init(struct pa_resampler*r); +static int libsamplerate_init(pa_resampler*r); +static int trivial_init(pa_resampler*r); -struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b, struct pa_memblock_stat *s, enum pa_resample_method resample_method) { - struct pa_resampler *r = NULL; +pa_resampler* pa_resampler_new(const pa_sample_spec *a, const pa_sample_spec *b, pa_memblock_stat *s, pa_resample_method resample_method) { + pa_resampler *r = NULL; assert(a && b && pa_sample_spec_valid(a) && pa_sample_spec_valid(b) && resample_method != PA_RESAMPLER_INVALID); if (a->channels != b->channels && a->channels != 1 && b->channels != 1) goto fail; - r = pa_xmalloc(sizeof(struct pa_resampler)); + r = pa_xmalloc(sizeof(pa_resampler)); r->impl_data = NULL; r->memblock_stat = s; r->resample_method = resample_method; @@ -113,7 +113,7 @@ fail: return NULL; } -void pa_resampler_free(struct pa_resampler *r) { +void pa_resampler_free(pa_resampler *r) { assert(r); if (r->impl_free) @@ -122,7 +122,7 @@ void pa_resampler_free(struct pa_resampler *r) { pa_xfree(r); } -void pa_resampler_set_input_rate(struct pa_resampler *r, uint32_t rate) { +void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate) { assert(r && rate); r->i_ss.rate = rate; @@ -130,24 +130,24 @@ void pa_resampler_set_input_rate(struct pa_resampler *r, uint32_t rate) { r->impl_set_input_rate(r, rate); } -void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out) { +void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { assert(r && in && out && r->impl_run); r->impl_run(r, in, out); } -size_t pa_resampler_request(struct pa_resampler *r, size_t out_length) { +size_t pa_resampler_request(pa_resampler *r, size_t out_length) { assert(r && (out_length % r->o_fz) == 0); return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz; } -enum pa_resample_method pa_resampler_get_method(struct pa_resampler *r) { +pa_resample_method pa_resampler_get_method(pa_resampler *r) { assert(r); return r->resample_method; } /* Parse a libsamplrate compatible resampling implementation */ -enum pa_resample_method pa_parse_resample_method(const char *string) { +pa_resample_method pa_parse_resample_method(const char *string) { assert(string); if (!strcmp(string, "src-sinc-best-quality")) @@ -168,7 +168,7 @@ enum pa_resample_method pa_parse_resample_method(const char *string) { /*** libsamplerate based implementation ***/ -static void libsamplerate_free(struct pa_resampler *r) { +static void libsamplerate_free(pa_resampler *r) { struct impl_libsamplerate *i; assert(r && r->impl_data); i = r->impl_data; @@ -181,7 +181,7 @@ static void libsamplerate_free(struct pa_resampler *r) { pa_xfree(i); } -static void libsamplerate_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out) { +static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { unsigned i_nchannels, o_nchannels, ins, ons, eff_ins, eff_ons; float *cbuf; struct impl_libsamplerate *i; @@ -267,7 +267,7 @@ static void libsamplerate_run(struct pa_resampler *r, const struct pa_memchunk * } } -static void libsamplerate_set_input_rate(struct pa_resampler *r, uint32_t rate) { +static void libsamplerate_set_input_rate(pa_resampler *r, uint32_t rate) { int ret; struct impl_libsamplerate *i; assert(r && rate > 0 && r->impl_data); @@ -277,7 +277,7 @@ static void libsamplerate_set_input_rate(struct pa_resampler *r, uint32_t rate) assert(ret == 0); } -static int libsamplerate_init(struct pa_resampler *r) { +static int libsamplerate_init(pa_resampler *r) { struct impl_libsamplerate *i = NULL; int err; @@ -308,7 +308,7 @@ fail: /* Trivial implementation */ -static void trivial_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out) { +static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { size_t fz; unsigned nframes; struct impl_trivial *i; @@ -367,12 +367,12 @@ static void trivial_run(struct pa_resampler *r, const struct pa_memchunk *in, st } } -static void trivial_free(struct pa_resampler *r) { +static void trivial_free(pa_resampler *r) { assert(r); pa_xfree(r->impl_data); } -static void trivial_set_input_rate(struct pa_resampler *r, uint32_t rate) { +static void trivial_set_input_rate(pa_resampler *r, uint32_t rate) { struct impl_trivial *i; assert(r && rate > 0 && r->impl_data); i = r->impl_data; @@ -381,7 +381,7 @@ static void trivial_set_input_rate(struct pa_resampler *r, uint32_t rate) { i->o_counter = 0; } -static int trivial_init(struct pa_resampler*r) { +static int trivial_init(pa_resampler*r) { struct impl_trivial *i; assert(r && r->i_ss.format == r->o_ss.format && r->i_ss.channels == r->o_ss.channels); @@ -395,7 +395,7 @@ static int trivial_init(struct pa_resampler*r) { return 0; } -const char *pa_resample_method_to_string(enum pa_resample_method m) { +const char *pa_resample_method_to_string(pa_resample_method m) { static const char * const resample_methods[] = { "src-sinc-best-quality", "src-sinc-medium-quality", diff --git a/polyp/resampler.h b/polyp/resampler.h index 0109e790..358c872a 100644 --- a/polyp/resampler.h +++ b/polyp/resampler.h @@ -28,9 +28,9 @@ #include "memblock.h" #include "memchunk.h" -struct pa_resampler; +typedef struct pa_resampler pa_resampler; -enum pa_resample_method { +typedef enum pa_resample_method { PA_RESAMPLER_INVALID = -1, PA_RESAMPLER_SRC_SINC_BEST_QUALITY = SRC_SINC_BEST_QUALITY, PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY = SRC_SINC_MEDIUM_QUALITY, @@ -39,27 +39,27 @@ enum pa_resample_method { PA_RESAMPLER_SRC_LINEAR = SRC_LINEAR, PA_RESAMPLER_TRIVIAL, PA_RESAMPLER_MAX -}; +} pa_resample_method; -struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b, struct pa_memblock_stat *s, int resample_method); -void pa_resampler_free(struct pa_resampler *r); +pa_resampler* pa_resampler_new(const pa_sample_spec *a, const pa_sample_spec *b, pa_memblock_stat *s, int resample_method); +void pa_resampler_free(pa_resampler *r); /* Returns the size of an input memory block which is required to return the specified amount of output data */ -size_t pa_resampler_request(struct pa_resampler *r, size_t out_length); +size_t pa_resampler_request(pa_resampler *r, size_t out_length); /* Pass the specified memory chunk to the resampler and return the newly resampled data */ -void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out); +void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out); /* Change the input rate of the resampler object */ -void pa_resampler_set_input_rate(struct pa_resampler *r, uint32_t rate); +void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate); /* Return the resampling method of the resampler object */ -enum pa_resample_method pa_resampler_get_method(struct pa_resampler *r); +pa_resample_method pa_resampler_get_method(pa_resampler *r); /* Try to parse the resampler method */ -enum pa_resample_method pa_parse_resample_method(const char *string); +pa_resample_method pa_parse_resample_method(const char *string); /* return a human readable string for the specified resampling method. Inverse of pa_parse_resample_method() */ -const char *pa_resample_method_to_string(enum pa_resample_method m); +const char *pa_resample_method_to_string(pa_resample_method m); #endif diff --git a/polyp/sample-util.c b/polyp/sample-util.c index bf8be34e..cb5dd1c3 100644 --- a/polyp/sample-util.c +++ b/polyp/sample-util.c @@ -30,18 +30,18 @@ #include "sample-util.h" -struct pa_memblock *pa_silence_memblock(struct pa_memblock* b, const struct pa_sample_spec *spec) { +pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) { assert(b && b->data && spec); pa_silence_memory(b->data, b->length, spec); return b; } -void pa_silence_memchunk(struct pa_memchunk *c, const struct pa_sample_spec *spec) { +void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) { assert(c && c->memblock && c->memblock->data && spec && c->length); pa_silence_memory((uint8_t*) c->memblock->data+c->index, c->length, spec); } -void pa_silence_memory(void *p, size_t length, const struct pa_sample_spec *spec) { +void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { uint8_t c = 0; assert(p && length && spec); @@ -65,7 +65,7 @@ void pa_silence_memory(void *p, size_t length, const struct pa_sample_spec *spec memset(p, c, length); } -size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const struct pa_sample_spec *spec, pa_volume_t volume) { +size_t pa_mix(pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const pa_sample_spec *spec, pa_volume_t volume) { assert(channels && data && length && spec); if (spec->format == PA_SAMPLE_S16NE) { @@ -161,7 +161,7 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz size_t d; for (d = 0;; d += sizeof(float)) { - pa_volume_t sum = 0; + float sum = 0; unsigned c; if (d >= length) @@ -203,7 +203,7 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz } -void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, pa_volume_t volume) { +void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, pa_volume_t volume) { assert(c && spec && (c->length % pa_frame_size(spec) == 0)); if (volume == PA_VOLUME_NORM) diff --git a/polyp/sample-util.h b/polyp/sample-util.h index aafdda63..eaebe91d 100644 --- a/polyp/sample-util.h +++ b/polyp/sample-util.h @@ -27,18 +27,18 @@ #include "memchunk.h" -struct pa_memblock *pa_silence_memblock(struct pa_memblock* b, const struct pa_sample_spec *spec); -void pa_silence_memchunk(struct pa_memchunk *c, const struct pa_sample_spec *spec); -void pa_silence_memory(void *p, size_t length, const struct pa_sample_spec *spec); +pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec); +void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec); +void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec); -struct pa_mix_info { - struct pa_memchunk chunk; +typedef struct pa_mix_info { + pa_memchunk chunk; pa_volume_t volume; void *userdata; -}; +} pa_mix_info ; -size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const struct pa_sample_spec *spec, pa_volume_t volume); +size_t pa_mix(pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const pa_sample_spec *spec, pa_volume_t volume); -void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, pa_volume_t volume); +void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, pa_volume_t volume); #endif diff --git a/polyp/sample.c b/polyp/sample.c index f9d0c458..37ab96a0 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -30,7 +30,7 @@ #include "sample.h" -size_t pa_frame_size(const struct pa_sample_spec *spec) { +size_t pa_frame_size(const pa_sample_spec *spec) { size_t b = 1; assert(spec); @@ -55,18 +55,18 @@ size_t pa_frame_size(const struct pa_sample_spec *spec) { return b * spec->channels; } -size_t pa_bytes_per_second(const struct pa_sample_spec *spec) { +size_t pa_bytes_per_second(const pa_sample_spec *spec) { assert(spec); return spec->rate*pa_frame_size(spec); } -pa_usec_t pa_bytes_to_usec(uint64_t length, const struct pa_sample_spec *spec) { +pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) { assert(spec); return (pa_usec_t) (((double) length/pa_frame_size(spec)*1000000)/spec->rate); } -int pa_sample_spec_valid(const struct pa_sample_spec *spec) { +int pa_sample_spec_valid(const pa_sample_spec *spec) { assert(spec); if (spec->rate <= 0 || spec->channels <= 0) @@ -78,13 +78,13 @@ int pa_sample_spec_valid(const struct pa_sample_spec *spec) { return 1; } -int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b) { +int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b) { assert(a && b); return (a->format == b->format) && (a->rate == b->rate) && (a->channels == b->channels); } -const char *pa_sample_format_to_string(enum pa_sample_format f) { +const char *pa_sample_format_to_string(pa_sample_format f) { static const char* const table[]= { [PA_SAMPLE_U8] = "U8", [PA_SAMPLE_ALAW] = "ALAW", @@ -101,7 +101,7 @@ const char *pa_sample_format_to_string(enum pa_sample_format f) { return table[f]; } -char *pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spec) { +char *pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec) { assert(s && l && spec); if (!pa_sample_spec_valid(spec)) @@ -161,7 +161,7 @@ void pa_bytes_snprint(char *s, size_t l, unsigned v) { snprintf(s, l, "%u B", (unsigned) v); } -enum pa_sample_format pa_parse_sample_format(const char *format) { +pa_sample_format pa_parse_sample_format(const char *format) { if (strcasecmp(format, "s16le") == 0) return PA_SAMPLE_S16LE; diff --git a/polyp/sample.h b/polyp/sample.h index 82c14615..739cb337 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -34,7 +34,7 @@ PA_C_DECL_BEGIN /** Sample format */ -enum pa_sample_format { +typedef enum pa_sample_format { PA_SAMPLE_U8, /**< Unsigned 8 Bit PCM */ PA_SAMPLE_ALAW, /**< 8 Bit a-Law */ PA_SAMPLE_ULAW, /**< 8 Bit mu-Law */ @@ -44,7 +44,7 @@ enum pa_sample_format { PA_SAMPLE_FLOAT32BE, /**< 32 Bit IEEE floating point, big endian, range -1..1 */ PA_SAMPLE_MAX, /**< Upper limit of valid sample types */ PA_SAMPLE_INVALID = -1 /**< An invalid value */ -}; +} pa_sample_format; #ifdef WORDS_BIGENDIAN /** Signed 16 Bit PCM, native endian */ @@ -70,38 +70,38 @@ enum pa_sample_format { #define PA_SAMPLE_FLOAT32 PA_SAMPLE_FLOAT32NE /** A sample format and attribute specification */ -struct pa_sample_spec { - enum pa_sample_format format; /**< The sample format */ +typedef struct pa_sample_spec { + pa_sample_format format; /**< The sample format */ uint32_t rate; /**< The sample rate. (e.g. 44100) */ uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */ -}; +} pa_sample_spec; /** Type for usec specifications (unsigned). May be either 32 or 64 bit, depending on the architecture */ typedef uint64_t pa_usec_t; /** Return the amount of bytes playback of a second of audio with the specified sample type takes */ -size_t pa_bytes_per_second(const struct pa_sample_spec *spec); +size_t pa_bytes_per_second(const pa_sample_spec *spec); /** Return the size of a frame with the specific sample type */ -size_t pa_frame_size(const struct pa_sample_spec *spec); +size_t pa_frame_size(const pa_sample_spec *spec); /** Calculate the time the specified bytes take to play with the specified sample type */ -pa_usec_t pa_bytes_to_usec(uint64_t length, const struct pa_sample_spec *spec); +pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec); /** Return non-zero when the sample type specification is valid */ -int pa_sample_spec_valid(const struct pa_sample_spec *spec); +int pa_sample_spec_valid(const pa_sample_spec *spec); /** Return non-zero when the two sample type specifications match */ -int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b); +int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b); /* Return a descriptive string for the specified sample format. \since 0.8 */ -const char *pa_sample_format_to_string(enum pa_sample_format f); +const char *pa_sample_format_to_string(pa_sample_format f); /** Maximum required string length for pa_sample_spec_snprint() */ #define PA_SAMPLE_SPEC_SNPRINT_MAX 32 /** Pretty print a sample type specification to a string */ -char* pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spec); +char* pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec); /** Volume specification: 0: silence; < 256: diminished volume; 256: normal volume; > 256 amplified volume */ typedef uint32_t pa_volume_t; @@ -138,7 +138,7 @@ pa_volume_t pa_volume_from_user(double v); void pa_bytes_snprint(char *s, size_t l, unsigned v); /** Parse a sample format text. Inverse of pa_sample_format_to_string() */ -enum pa_sample_format pa_parse_sample_format(const char *format); +pa_sample_format pa_parse_sample_format(const char *format); PA_C_DECL_END diff --git a/polyp/scache.c b/polyp/scache.c index 2953145d..32c89a99 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -55,8 +55,8 @@ #define UNLOAD_POLL_TIME 2 -static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, const struct timeval *tv, void *userdata) { - struct pa_core *c = userdata; +static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + pa_core *c = userdata; struct timeval ntv; assert(c && c->mainloop == m && c->scache_auto_unload_event == e); @@ -67,7 +67,7 @@ static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, m->time_restart(e, &ntv); } -static void free_entry(struct pa_scache_entry *e) { +static void free_entry(pa_scache_entry *e) { assert(e); pa_namereg_unregister(e->core, e->name); pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_REMOVE, e->index); @@ -78,8 +78,8 @@ static void free_entry(struct pa_scache_entry *e) { pa_xfree(e); } -static struct pa_scache_entry* scache_add_item(struct pa_core *c, const char *name) { - struct pa_scache_entry *e; +static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { + pa_scache_entry *e; assert(c && name); if ((e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) { @@ -92,7 +92,7 @@ static struct pa_scache_entry* scache_add_item(struct pa_core *c, const char *na pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); } else { - e = pa_xmalloc(sizeof(struct pa_scache_entry)); + e = pa_xmalloc(sizeof(pa_scache_entry)); if (!pa_namereg_register(c, name, PA_NAMEREG_SAMPLE, e, 1)) { pa_xfree(e); @@ -120,13 +120,13 @@ static struct pa_scache_entry* scache_add_item(struct pa_core *c, const char *na e->lazy = 0; e->last_used_time = 0; - memset(&e->sample_spec, 0, sizeof(struct pa_sample_spec)); + memset(&e->sample_spec, 0, sizeof(pa_sample_spec)); return e; } -int pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index) { - struct pa_scache_entry *e; +int pa_scache_add_item(pa_core *c, const char *name, pa_sample_spec *ss, pa_memchunk *chunk, uint32_t *idx) { + pa_scache_entry *e; assert(c && name); if (!(e = scache_add_item(c, name))) @@ -140,15 +140,15 @@ int pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spe pa_memblock_ref(e->memchunk.memblock); } - if (index) - *index = e->index; + if (idx) + *idx = e->index; return 0; } -int pa_scache_add_file(struct pa_core *c, const char *name, const char *filename, uint32_t *index) { - struct pa_sample_spec ss; - struct pa_memchunk chunk; +int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint32_t *idx) { + pa_sample_spec ss; + pa_memchunk chunk; int r; #ifdef OS_IS_WIN32 @@ -161,14 +161,14 @@ int pa_scache_add_file(struct pa_core *c, const char *name, const char *filename if (pa_sound_file_load(filename, &ss, &chunk, c->memblock_stat) < 0) return -1; - r = pa_scache_add_item(c, name, &ss, &chunk, index); + r = pa_scache_add_item(c, name, &ss, &chunk, idx); pa_memblock_unref(chunk.memblock); return r; } -int pa_scache_add_file_lazy(struct pa_core *c, const char *name, const char *filename, uint32_t *index) { - struct pa_scache_entry *e; +int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, uint32_t *idx) { + pa_scache_entry *e; #ifdef OS_IS_WIN32 char buf[MAX_PATH]; @@ -192,11 +192,14 @@ int pa_scache_add_file_lazy(struct pa_core *c, const char *name, const char *fil c->scache_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); } + if (idx) + *idx = e->index; + return 0; } -int pa_scache_remove_item(struct pa_core *c, const char *name) { - struct pa_scache_entry *e; +int pa_scache_remove_item(pa_core *c, const char *name) { + pa_scache_entry *e; assert(c && name); if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) @@ -209,13 +212,13 @@ int pa_scache_remove_item(struct pa_core *c, const char *name) { return 0; } -static void free_cb(void *p, void *userdata) { - struct pa_scache_entry *e = p; +static void free_cb(void *p, PA_GCC_UNUSED void *userdata) { + pa_scache_entry *e = p; assert(e); free_entry(e); } -void pa_scache_free(struct pa_core *c) { +void pa_scache_free(pa_core *c) { assert(c); if (c->scache) { @@ -227,8 +230,8 @@ void pa_scache_free(struct pa_core *c) { c->mainloop->time_free(c->scache_auto_unload_event); } -int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sink, uint32_t volume) { - struct pa_scache_entry *e; +int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, uint32_t volume) { + pa_scache_entry *e; char *t; assert(c && name && sink); @@ -259,8 +262,8 @@ int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sin return 0; } -const char * pa_scache_get_name_by_id(struct pa_core *c, uint32_t id) { - struct pa_scache_entry *e; +const char * pa_scache_get_name_by_id(pa_core *c, uint32_t id) { + pa_scache_entry *e; assert(c && id != PA_IDXSET_INVALID); if (!c->scache || !(e = pa_idxset_get_by_index(c->scache, id))) @@ -269,8 +272,8 @@ const char * pa_scache_get_name_by_id(struct pa_core *c, uint32_t id) { return e->name; } -uint32_t pa_scache_get_id_by_name(struct pa_core *c, const char *name) { - struct pa_scache_entry *e; +uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name) { + pa_scache_entry *e; assert(c && name); if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) @@ -279,33 +282,33 @@ uint32_t pa_scache_get_id_by_name(struct pa_core *c, const char *name) { return e->index; } -uint32_t pa_scache_total_size(struct pa_core *c) { - struct pa_scache_entry *e; - uint32_t index, sum = 0; +uint32_t pa_scache_total_size(pa_core *c) { + pa_scache_entry *e; + uint32_t idx, sum = 0; assert(c); - if (!c->scache || !pa_idxset_ncontents(c->scache)) + if (!c->scache || !pa_idxset_size(c->scache)) return 0; - for (e = pa_idxset_first(c->scache, &index); e; e = pa_idxset_next(c->scache, &index)) + for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) if (e->memchunk.memblock) sum += e->memchunk.length; return sum; } -void pa_scache_unload_unused(struct pa_core *c) { - struct pa_scache_entry *e; +void pa_scache_unload_unused(pa_core *c) { + pa_scache_entry *e; time_t now; - uint32_t index; + uint32_t idx; assert(c); - if (!c->scache || !pa_idxset_ncontents(c->scache)) + if (!c->scache || !pa_idxset_size(c->scache)) return; time(&now); - for (e = pa_idxset_first(c->scache, &index); e; e = pa_idxset_next(c->scache, &index)) { + for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) { if (!e->lazy || !e->memchunk.memblock) continue; @@ -321,7 +324,7 @@ void pa_scache_unload_unused(struct pa_core *c) { } } -static void add_file(struct pa_core *c, const char *pathname) { +static void add_file(pa_core *c, const char *pathname) { struct stat st; const char *e; @@ -338,7 +341,7 @@ static void add_file(struct pa_core *c, const char *pathname) { pa_scache_add_file_lazy(c, e, pathname, NULL); } -int pa_scache_add_directory_lazy(struct pa_core *c, const char *pathname) { +int pa_scache_add_directory_lazy(pa_core *c, const char *pathname) { DIR *dir; assert(c && pathname); diff --git a/polyp/scache.h b/polyp/scache.h index f7043f16..c23e33de 100644 --- a/polyp/scache.h +++ b/polyp/scache.h @@ -26,36 +26,36 @@ #include "memchunk.h" #include "sink.h" -struct pa_scache_entry { - struct pa_core *core; +typedef struct pa_scache_entry { + pa_core *core; uint32_t index; char *name; uint32_t volume; - struct pa_sample_spec sample_spec; - struct pa_memchunk memchunk; + pa_sample_spec sample_spec; + pa_memchunk memchunk; char *filename; int lazy; time_t last_used_time; -}; +} pa_scache_entry; -int pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index); -int pa_scache_add_file(struct pa_core *c, const char *name, const char *filename, uint32_t *index); -int pa_scache_add_file_lazy(struct pa_core *c, const char *name, const char *filename, uint32_t *index); +int pa_scache_add_item(pa_core *c, const char *name, pa_sample_spec *ss, pa_memchunk *chunk, uint32_t *idx); +int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint32_t *idx); +int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, uint32_t *idx); -int pa_scache_add_directory_lazy(struct pa_core *c, const char *pathname); +int pa_scache_add_directory_lazy(pa_core *c, const char *pathname); -int pa_scache_remove_item(struct pa_core *c, const char *name); -int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sink, uint32_t volume); -void pa_scache_free(struct pa_core *c); +int pa_scache_remove_item(pa_core *c, const char *name); +int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, uint32_t volume); +void pa_scache_free(pa_core *c); -const char *pa_scache_get_name_by_id(struct pa_core *c, uint32_t id); -uint32_t pa_scache_get_id_by_name(struct pa_core *c, const char *name); +const char *pa_scache_get_name_by_id(pa_core *c, uint32_t id); +uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name); -uint32_t pa_scache_total_size(struct pa_core *c); +uint32_t pa_scache_total_size(pa_core *c); -void pa_scache_unload_unused(struct pa_core *c); +void pa_scache_unload_unused(pa_core *c); #endif diff --git a/polyp/sconv-s16be.c b/polyp/sconv-s16be.c index 54efc78c..3880b043 100644 --- a/polyp/sconv-s16be.c +++ b/polyp/sconv-s16be.c @@ -23,12 +23,11 @@ #include #endif -#include "sconv-s16be.h" - #define INT16_FROM INT16_FROM_BE #define INT16_TO INT16_TO_BE #define pa_sconv_s16le_to_float32ne pa_sconv_s16be_to_float32ne #define pa_sconv_s16le_from_float32ne pa_sconv_s16be_from_float32ne +#include "sconv-s16le.h" #include "sconv-s16le.c" diff --git a/polyp/sconv-s16le.c b/polyp/sconv-s16le.c index 49c47461..c9682fff 100644 --- a/polyp/sconv-s16le.c +++ b/polyp/sconv-s16le.c @@ -28,6 +28,7 @@ #include "endianmacros.h" #include "sconv.h" +#include "sconv-s16le.h" #include "log.h" #ifndef INT16_FROM diff --git a/polyp/sconv.c b/polyp/sconv.c index a404f432..223df5d9 100644 --- a/polyp/sconv.c +++ b/polyp/sconv.c @@ -115,7 +115,7 @@ static void ulaw_to_float32ne(unsigned n, const void *a, unsigned an, float *b) float sum = 0; for (i = 0; i < an; i++) - sum += (float) st_ulaw2linear16(*ca++) / 0x7FFF; + sum += st_ulaw2linear16(*ca++) * 1.0F / 0x7FFF; if (sum > 1) sum = 1; @@ -156,7 +156,7 @@ static void alaw_to_float32ne(unsigned n, const void *a, unsigned an, float *b) float sum = 0; for (i = 0; i < an; i++) - sum += (float) st_alaw2linear16(*ca++) / 0x7FFF; + sum += st_alaw2linear16(*ca++) * 1.0F / 0x7FFF; if (sum > 1) sum = 1; @@ -190,7 +190,7 @@ static void alaw_from_float32ne(unsigned n, const float *a, void *b, unsigned bn } -pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(enum pa_sample_format f) { +pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format f) { switch(f) { case PA_SAMPLE_U8: return u8_to_float32ne; @@ -209,7 +209,7 @@ pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(enum pa_samp } } -pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(enum pa_sample_format f) { +pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format f) { switch(f) { case PA_SAMPLE_U8: return u8_from_float32ne; diff --git a/polyp/sconv.h b/polyp/sconv.h index 71517ec2..2866fd41 100644 --- a/polyp/sconv.h +++ b/polyp/sconv.h @@ -27,7 +27,7 @@ typedef void (*pa_convert_to_float32ne_func_t)(unsigned n, const void *a, unsigned an, float *b); typedef void (*pa_convert_from_float32ne_func_t)(unsigned n, const float *a, void *b, unsigned bn); -pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(enum pa_sample_format f); -pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(enum pa_sample_format f); +pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format f); +pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format f); #endif diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 3e7fdf7b..682b3222 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -36,14 +36,14 @@ #define CONVERT_BUFFER_LENGTH 4096 -struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int variable_rate, int resample_method) { - struct pa_sink_input *i; - struct pa_resampler *resampler = NULL; +pa_sink_input* pa_sink_input_new(pa_sink *s, pa_typeid_t typeid, const char *name, const pa_sample_spec *spec, int variable_rate, int resample_method) { + pa_sink_input *i; + pa_resampler *resampler = NULL; int r; char st[256]; assert(s && spec && s->state == PA_SINK_RUNNING); - if (pa_idxset_ncontents(s->inputs) >= PA_MAX_INPUTS_PER_SINK) { + if (pa_idxset_size(s->inputs) >= PA_MAX_INPUTS_PER_SINK) { pa_log(__FILE__": Failed to create sink input: too many inputs per sink.\n"); return NULL; } @@ -55,7 +55,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, pa_typeid_t typeid, c if (!(resampler = pa_resampler_new(spec, &s->sample_spec, s->core->memblock_stat, resample_method))) return NULL; - i = pa_xmalloc(sizeof(struct pa_sink_input)); + i = pa_xmalloc(sizeof(pa_sink_input)); i->ref = 1; i->state = PA_SINK_INPUT_RUNNING; i->name = pa_xstrdup(name); @@ -93,7 +93,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, pa_typeid_t typeid, c return i; } -void pa_sink_input_disconnect(struct pa_sink_input *i) { +void pa_sink_input_disconnect(pa_sink_input *i) { assert(i && i->state != PA_SINK_INPUT_DISCONNECTED && i->sink && i->sink->core); pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); @@ -110,7 +110,7 @@ void pa_sink_input_disconnect(struct pa_sink_input *i) { i->state = PA_SINK_INPUT_DISCONNECTED; } -static void sink_input_free(struct pa_sink_input* i) { +static void sink_input_free(pa_sink_input* i) { assert(i); if (i->state != PA_SINK_INPUT_DISCONNECTED) @@ -127,27 +127,27 @@ static void sink_input_free(struct pa_sink_input* i) { pa_xfree(i); } -void pa_sink_input_unref(struct pa_sink_input *i) { +void pa_sink_input_unref(pa_sink_input *i) { assert(i && i->ref >= 1); if (!(--i->ref)) sink_input_free(i); } -struct pa_sink_input* pa_sink_input_ref(struct pa_sink_input *i) { +pa_sink_input* pa_sink_input_ref(pa_sink_input *i) { assert(i && i->ref >= 1); i->ref++; return i; } -void pa_sink_input_kill(struct pa_sink_input*i) { +void pa_sink_input_kill(pa_sink_input*i) { assert(i && i->ref >= 1); if (i->kill) i->kill(i); } -pa_usec_t pa_sink_input_get_latency(struct pa_sink_input *i) { +pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) { pa_usec_t r = 0; assert(i && i->ref >= 1); @@ -160,7 +160,7 @@ pa_usec_t pa_sink_input_get_latency(struct pa_sink_input *i) { return r; } -int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { +int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { int ret = -1; assert(i && chunk && i->ref >= 1); @@ -175,7 +175,7 @@ int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { } while (!i->resampled_chunk.memblock) { - struct pa_memchunk tchunk; + pa_memchunk tchunk; size_t l; if ((ret = i->peek(i, &tchunk)) < 0) @@ -213,7 +213,7 @@ finish: return ret; } -void pa_sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length) { +void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { assert(i && length && i->ref >= 1); if (!i->resampler) { @@ -234,7 +234,7 @@ void pa_sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk *chunk } } -void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume) { +void pa_sink_input_set_volume(pa_sink_input *i, pa_volume_t volume) { assert(i && i->sink && i->sink->core && i->ref >= 1); if (i->volume != volume) { @@ -243,7 +243,7 @@ void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume) { } } -void pa_sink_input_cork(struct pa_sink_input *i, int b) { +void pa_sink_input_cork(pa_sink_input *i, int b) { int n; assert(i && i->ref >= 1); @@ -257,7 +257,7 @@ void pa_sink_input_cork(struct pa_sink_input *i, int b) { pa_sink_notify(i->sink); } -void pa_sink_input_set_rate(struct pa_sink_input *i, uint32_t rate) { +void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) { assert(i && i->resampler && i->ref >= 1); if (i->sample_spec.rate == rate) @@ -267,7 +267,7 @@ void pa_sink_input_set_rate(struct pa_sink_input *i, uint32_t rate) { pa_resampler_set_input_rate(i->resampler, rate); } -void pa_sink_input_set_name(struct pa_sink_input *i, const char *name) { +void pa_sink_input_set_name(pa_sink_input *i, const char *name) { assert(i && i->ref >= 1); pa_xfree(i->name); @@ -276,7 +276,7 @@ void pa_sink_input_set_name(struct pa_sink_input *i, const char *name) { pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); } -enum pa_resample_method pa_sink_input_get_resample_method(struct pa_sink_input *i) { +pa_resample_method pa_sink_input_get_resample_method(pa_sink_input *i) { assert(i && i->ref >= 1); if (!i->resampler) diff --git a/polyp/sink-input.h b/polyp/sink-input.h index 83abe537..b4c3ec7f 100644 --- a/polyp/sink-input.h +++ b/polyp/sink-input.h @@ -24,6 +24,8 @@ #include +typedef struct pa_sink_input pa_sink_input; + #include "sink.h" #include "sample.h" #include "memblockq.h" @@ -31,63 +33,63 @@ #include "module.h" #include "client.h" -enum pa_sink_input_state { +typedef enum { PA_SINK_INPUT_RUNNING, PA_SINK_INPUT_CORKED, PA_SINK_INPUT_DISCONNECTED -}; +} pa_sink_input_state ; struct pa_sink_input { int ref; - enum pa_sink_input_state state; + pa_sink_input_state state; uint32_t index; pa_typeid_t typeid; char *name; - struct pa_module *owner; - struct pa_client *client; - struct pa_sink *sink; - struct pa_sample_spec sample_spec; + pa_module *owner; + pa_client *client; + pa_sink *sink; + pa_sample_spec sample_spec; uint32_t volume; - int (*peek) (struct pa_sink_input *i, struct pa_memchunk *chunk); - void (*drop) (struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length); - void (*kill) (struct pa_sink_input *i); - pa_usec_t (*get_latency) (struct pa_sink_input *i); - void (*underrun) (struct pa_sink_input *i); + int (*peek) (pa_sink_input *i, pa_memchunk *chunk); + void (*drop) (pa_sink_input *i, const pa_memchunk *chunk, size_t length); + void (*kill) (pa_sink_input *i); + pa_usec_t (*get_latency) (pa_sink_input *i); + void (*underrun) (pa_sink_input *i); void *userdata; int playing; - struct pa_memchunk resampled_chunk; - struct pa_resampler *resampler; + pa_memchunk resampled_chunk; + pa_resampler *resampler; }; -struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int variable_rate, int resample_method); -void pa_sink_input_unref(struct pa_sink_input* i); -struct pa_sink_input* pa_sink_input_ref(struct pa_sink_input* i); +pa_sink_input* pa_sink_input_new(pa_sink *s, pa_typeid_t typeid, const char *name, const pa_sample_spec *spec, int variable_rate, int resample_method); +void pa_sink_input_unref(pa_sink_input* i); +pa_sink_input* pa_sink_input_ref(pa_sink_input* i); /* To be called by the implementing module only */ -void pa_sink_input_disconnect(struct pa_sink_input* i); +void pa_sink_input_disconnect(pa_sink_input* i); /* External code may request disconnection with this funcion */ -void pa_sink_input_kill(struct pa_sink_input*i); +void pa_sink_input_kill(pa_sink_input*i); -pa_usec_t pa_sink_input_get_latency(struct pa_sink_input *i); +pa_usec_t pa_sink_input_get_latency(pa_sink_input *i); -int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk); -void pa_sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length); +int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk); +void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length); -void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume); +void pa_sink_input_set_volume(pa_sink_input *i, pa_volume_t volume); -void pa_sink_input_cork(struct pa_sink_input *i, int b); +void pa_sink_input_cork(pa_sink_input *i, int b); -void pa_sink_input_set_rate(struct pa_sink_input *i, uint32_t rate); +void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate); -void pa_sink_input_set_name(struct pa_sink_input *i, const char *name); +void pa_sink_input_set_name(pa_sink_input *i, const char *name); -enum pa_resample_method pa_sink_input_get_resample_method(struct pa_sink_input *i); +pa_resample_method pa_sink_input_get_resample_method(pa_sink_input *i); #endif diff --git a/polyp/sink.c b/polyp/sink.c index 481e5cf7..aac90c04 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -36,17 +36,18 @@ #include "xmalloc.h" #include "subscribe.h" #include "log.h" +#include "polyplib-introspect.h" #define MAX_MIX_CHANNELS 32 -struct pa_sink* pa_sink_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec) { - struct pa_sink *s; +pa_sink* pa_sink_new(pa_core *core, pa_typeid_t typeid, const char *name, int fail, const pa_sample_spec *spec) { + pa_sink *s; char *n = NULL; char st[256]; int r; assert(core && name && *name && spec); - s = pa_xmalloc(sizeof(struct pa_sink)); + s = pa_xmalloc(sizeof(pa_sink)); if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) { pa_xfree(s); @@ -89,8 +90,8 @@ struct pa_sink* pa_sink_new(struct pa_core *core, pa_typeid_t typeid, const char return s; } -void pa_sink_disconnect(struct pa_sink* s) { - struct pa_sink_input *i, *j = NULL; +void pa_sink_disconnect(pa_sink* s) { + pa_sink_input *i, *j = NULL; assert(s && s->state == PA_SINK_RUNNING); pa_namereg_unregister(s->core, s->name); @@ -112,7 +113,7 @@ void pa_sink_disconnect(struct pa_sink* s) { s->state = PA_SINK_DISCONNECTED; } -static void sink_free(struct pa_sink *s) { +static void sink_free(pa_sink *s) { assert(s && s->ref == 0); if (s->state != PA_SINK_DISCONNECTED) @@ -130,34 +131,34 @@ static void sink_free(struct pa_sink *s) { pa_xfree(s); } -void pa_sink_unref(struct pa_sink*s) { +void pa_sink_unref(pa_sink*s) { assert(s && s->ref >= 1); if (!(--s->ref)) sink_free(s); } -struct pa_sink* pa_sink_ref(struct pa_sink *s) { +pa_sink* pa_sink_ref(pa_sink *s) { assert(s && s->ref >= 1); s->ref++; return s; } -void pa_sink_notify(struct pa_sink*s) { +void pa_sink_notify(pa_sink*s) { assert(s && s->ref >= 1); if (s->notify) s->notify(s); } -static unsigned fill_mix_info(struct pa_sink *s, struct pa_mix_info *info, unsigned maxinfo) { - uint32_t index = PA_IDXSET_INVALID; - struct pa_sink_input *i; +static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) { + uint32_t idx = PA_IDXSET_INVALID; + pa_sink_input *i; unsigned n = 0; assert(s && s->ref >= 1 && info); - for (i = pa_idxset_first(s->inputs, &index); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &index)) { + for (i = pa_idxset_first(s->inputs, &idx); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &idx)) { pa_sink_input_ref(i); if (pa_sink_input_peek(i, &info->chunk) < 0) { @@ -178,11 +179,11 @@ static unsigned fill_mix_info(struct pa_sink *s, struct pa_mix_info *info, unsig return n; } -static void inputs_drop(struct pa_sink *s, struct pa_mix_info *info, unsigned maxinfo, size_t length) { +static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned maxinfo, size_t length) { assert(s && s->ref >= 1 && info); for (; maxinfo > 0; maxinfo--, info++) { - struct pa_sink_input *i = info->userdata; + pa_sink_input *i = info->userdata; assert(i && info->chunk.memblock); pa_sink_input_drop(i, &info->chunk, length); @@ -193,8 +194,8 @@ static void inputs_drop(struct pa_sink *s, struct pa_mix_info *info, unsigned ma } } -int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result) { - struct pa_mix_info info[MAX_MIX_CHANNELS]; +int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { + pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; size_t l; int r = -1; @@ -212,7 +213,7 @@ int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result) if (n == 1) { uint32_t volume = PA_VOLUME_NORM; - struct pa_sink_input *i = info[0].userdata; + pa_sink_input *i = info[0].userdata; assert(i); *result = info[0].chunk; pa_memblock_ref(result->memblock); @@ -252,8 +253,8 @@ finish: return r; } -int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target) { - struct pa_mix_info info[MAX_MIX_CHANNELS]; +int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { + pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; size_t l; int r = -1; @@ -268,8 +269,6 @@ int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target) { if (n == 1) { uint32_t volume = PA_VOLUME_NORM; - struct pa_sink_info *i = info[0].userdata; - assert(i); l = target->length; if (l > info[0].chunk.length) @@ -300,8 +299,8 @@ finish: return r; } -void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target) { - struct pa_memchunk chunk; +void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { + pa_memchunk chunk; size_t l, d; assert(s && s->ref >= 1 && target && target->memblock && target->length && target->memblock->data); @@ -331,7 +330,7 @@ void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target) { pa_sink_unref(s); } -void pa_sink_render_full(struct pa_sink *s, size_t length, struct pa_memchunk *result) { +void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { assert(s && s->ref >= 1 && length && result); /*** This needs optimization ***/ @@ -342,7 +341,7 @@ void pa_sink_render_full(struct pa_sink *s, size_t length, struct pa_memchunk *r pa_sink_render_into_full(s, result); } -pa_usec_t pa_sink_get_latency(struct pa_sink *s) { +pa_usec_t pa_sink_get_latency(pa_sink *s) { assert(s && s->ref >= 1); if (!s->get_latency) @@ -351,7 +350,7 @@ pa_usec_t pa_sink_get_latency(struct pa_sink *s) { return s->get_latency(s); } -void pa_sink_set_owner(struct pa_sink *s, struct pa_module *m) { +void pa_sink_set_owner(pa_sink *s, pa_module *m) { assert(s && s->ref >= 1); s->owner = m; @@ -360,7 +359,7 @@ void pa_sink_set_owner(struct pa_sink *s, struct pa_module *m) { pa_source_set_owner(s->monitor_source, m); } -void pa_sink_set_volume(struct pa_sink *s, pa_volume_t volume) { +void pa_sink_set_volume(pa_sink *s, pa_volume_t volume) { assert(s && s->ref >= 1); if (s->volume != volume) { diff --git a/polyp/sink.h b/polyp/sink.h index 844af964..22d90858 100644 --- a/polyp/sink.h +++ b/polyp/sink.h @@ -22,61 +22,62 @@ USA. ***/ -struct pa_sink; - #include +typedef struct pa_sink pa_sink; + #include "core.h" #include "sample.h" #include "idxset.h" #include "source.h" #include "typeid.h" +#include "module.h" #define PA_MAX_INPUTS_PER_SINK 6 -enum pa_sink_state { +typedef enum pa_sink_state { PA_SINK_RUNNING, PA_SINK_DISCONNECTED -}; +} pa_sink_state; struct pa_sink { int ref; - enum pa_sink_state state; + pa_sink_state state; uint32_t index; pa_typeid_t typeid; char *name, *description; - struct pa_module *owner; - struct pa_core *core; - struct pa_sample_spec sample_spec; - struct pa_idxset *inputs; + pa_module *owner; + pa_core *core; + pa_sample_spec sample_spec; + pa_idxset *inputs; - struct pa_source *monitor_source; + pa_source *monitor_source; pa_volume_t volume; - void (*notify)(struct pa_sink*sink); - pa_usec_t (*get_latency)(struct pa_sink *s); + void (*notify)(pa_sink*sink); + pa_usec_t (*get_latency)(pa_sink *s); void *userdata; }; -struct pa_sink* pa_sink_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec); -void pa_sink_disconnect(struct pa_sink* s); -void pa_sink_unref(struct pa_sink*s); -struct pa_sink* pa_sink_ref(struct pa_sink *s); +pa_sink* pa_sink_new(pa_core *core, pa_typeid_t typeid, const char *name, int fail, const pa_sample_spec *spec); +void pa_sink_disconnect(pa_sink* s); +void pa_sink_unref(pa_sink*s); +pa_sink* pa_sink_ref(pa_sink *s); -int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result); -void pa_sink_render_full(struct pa_sink *s, size_t length, struct pa_memchunk *result); -int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target); -void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target); +int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result); +void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result); +int pa_sink_render_into(pa_sink*s, pa_memchunk *target); +void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target); -pa_usec_t pa_sink_get_latency(struct pa_sink *s); +pa_usec_t pa_sink_get_latency(pa_sink *s); -void pa_sink_notify(struct pa_sink*s); +void pa_sink_notify(pa_sink*s); -void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m); +void pa_sink_set_owner(pa_sink *sink, pa_module *m); -void pa_sink_set_volume(struct pa_sink *sink, pa_volume_t volume); +void pa_sink_set_volume(pa_sink *sink, pa_volume_t volume); #endif diff --git a/polyp/socket-client.c b/polyp/socket-client.c index 51134b84..a884aa61 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -65,26 +65,26 @@ struct pa_socket_client { int ref; - struct pa_mainloop_api *mainloop; + pa_mainloop_api *mainloop; int fd; - struct pa_io_event *io_event; - struct pa_time_event *timeout_event; - struct pa_defer_event *defer_event; - void (*callback)(struct pa_socket_client*c, struct pa_iochannel *io, void *userdata); + pa_io_event *io_event; + pa_time_event *timeout_event; + pa_defer_event *defer_event; + void (*callback)(pa_socket_client*c, pa_iochannel *io, void *userdata); void *userdata; int local; #ifdef HAVE_LIBASYNCNS asyncns_t *asyncns; asyncns_query_t * asyncns_query; - struct pa_io_event *asyncns_io_event; + pa_io_event *asyncns_io_event; #endif }; -static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) { - struct pa_socket_client *c; +static pa_socket_client*pa_socket_client_new(pa_mainloop_api *m) { + pa_socket_client *c; assert(m); - c = pa_xmalloc(sizeof(struct pa_socket_client)); + c = pa_xmalloc(sizeof(pa_socket_client)); c->ref = 1; c->mainloop = m; c->fd = -1; @@ -104,7 +104,7 @@ static struct pa_socket_client*pa_socket_client_new(struct pa_mainloop_api *m) { return c; } -static void free_events(struct pa_socket_client *c) { +static void free_events(pa_socket_client *c) { assert(c); if (c->io_event) { @@ -123,8 +123,8 @@ static void free_events(struct pa_socket_client *c) { } } -static void do_call(struct pa_socket_client *c) { - struct pa_iochannel *io = NULL; +static void do_call(pa_socket_client *c) { + pa_iochannel *io = NULL; int error; socklen_t lerror; assert(c && c->callback); @@ -167,19 +167,19 @@ finish: pa_socket_client_unref(c); } -static void connect_fixed_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) { - struct pa_socket_client *c = userdata; +static void connect_fixed_cb(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { + pa_socket_client *c = userdata; assert(m && c && c->defer_event == e); do_call(c); } -static void connect_io_cb(struct pa_mainloop_api*m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { - struct pa_socket_client *c = userdata; +static void connect_io_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { + pa_socket_client *c = userdata; assert(m && c && c->io_event == e && fd >= 0); do_call(c); } -static int do_connect(struct pa_socket_client *c, const struct sockaddr *sa, socklen_t len) { +static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t len) { int r; assert(c && sa && len); @@ -201,7 +201,7 @@ static int do_connect(struct pa_socket_client *c, const struct sockaddr *sa, soc return 0; } -struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port) { +pa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port) { struct sockaddr_in sa; assert(m && port > 0); @@ -215,7 +215,7 @@ struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, ui #ifdef HAVE_SYS_UN_H -struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename) { +pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) { struct sockaddr_un sa; assert(m && filename); @@ -229,13 +229,13 @@ struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, co #else /* HAVE_SYS_UN_H */ -struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename) { +pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) { return NULL; } #endif /* HAVE_SYS_UN_H */ -static int sockaddr_prepare(struct pa_socket_client *c, const struct sockaddr *sa, size_t salen) { +static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size_t salen) { assert(c); assert(sa); assert(salen); @@ -274,8 +274,8 @@ static int sockaddr_prepare(struct pa_socket_client *c, const struct sockaddr *s return 0; } -struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) { - struct pa_socket_client *c; +pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) { + pa_socket_client *c; assert(m && sa); c = pa_socket_client_new(m); assert(c); @@ -291,7 +291,7 @@ fail: } -void socket_client_free(struct pa_socket_client *c) { +static void socket_client_free(pa_socket_client *c) { assert(c && c->mainloop); @@ -312,26 +312,26 @@ void socket_client_free(struct pa_socket_client *c) { pa_xfree(c); } -void pa_socket_client_unref(struct pa_socket_client *c) { +void pa_socket_client_unref(pa_socket_client *c) { assert(c && c->ref >= 1); if (!(--(c->ref))) socket_client_free(c); } -struct pa_socket_client* pa_socket_client_ref(struct pa_socket_client *c) { +pa_socket_client* pa_socket_client_ref(pa_socket_client *c) { assert(c && c->ref >= 1); c->ref++; return c; } -void pa_socket_client_set_callback(struct pa_socket_client *c, void (*on_connection)(struct pa_socket_client *c, struct pa_iochannel*io, void *userdata), void *userdata) { +void pa_socket_client_set_callback(pa_socket_client *c, void (*on_connection)(pa_socket_client *c, pa_iochannel*io, void *userdata), void *userdata) { assert(c); c->callback = on_connection; c->userdata = userdata; } -struct pa_socket_client* pa_socket_client_new_ipv6(struct pa_mainloop_api *m, uint8_t address[16], uint16_t port) { +pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[16], uint16_t port) { struct sockaddr_in6 sa; memset(&sa, 0, sizeof(sa)); @@ -344,8 +344,8 @@ struct pa_socket_client* pa_socket_client_new_ipv6(struct pa_mainloop_api *m, ui #ifdef HAVE_LIBASYNCNS -static void asyncns_cb(struct pa_mainloop_api*m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { - struct pa_socket_client *c = userdata; +static void asyncns_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { + pa_socket_client *c = userdata; struct addrinfo *res = NULL; int ret; assert(m && c && c->asyncns_io_event == e && fd >= 0); @@ -381,8 +381,8 @@ finish: #endif -static void timeout_cb(struct pa_mainloop_api *m, struct pa_time_event *e, const struct timeval *tv, void *userdata) { - struct pa_socket_client *c = userdata; +static void timeout_cb(pa_mainloop_api *m, pa_time_event *e, const struct timeval *tv, void *userdata) { + pa_socket_client *c = userdata; assert(m); assert(e); assert(tv); @@ -397,7 +397,7 @@ static void timeout_cb(struct pa_mainloop_api *m, struct pa_time_event *e, const do_call(c); } -static void start_timeout(struct pa_socket_client *c) { +static void start_timeout(pa_socket_client *c) { struct timeval tv; assert(c); assert(!c->timeout_event); @@ -407,9 +407,9 @@ static void start_timeout(struct pa_socket_client *c) { c->timeout_event = c->mainloop->time_new(c->mainloop, &tv, timeout_cb, c); } -struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, const char*name, uint16_t default_port) { - struct pa_socket_client *c = NULL; - struct pa_parsed_address a; +pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*name, uint16_t default_port) { + pa_socket_client *c = NULL; + pa_parsed_address a; assert(m && name); if (pa_parse_address(name, &a) < 0) @@ -507,7 +507,7 @@ finish: /* Return non-zero when the target sockaddr is considered local. "local" means UNIX socket or TCP socket on localhost. Other local IP addresses are not considered local. */ -int pa_socket_client_is_local(struct pa_socket_client *c) { +int pa_socket_client_is_local(pa_socket_client *c) { assert(c); return c->local; } diff --git a/polyp/socket-client.h b/polyp/socket-client.h index b8c73ed8..40e9629a 100644 --- a/polyp/socket-client.h +++ b/polyp/socket-client.h @@ -29,19 +29,19 @@ struct sockaddr; -struct pa_socket_client; +typedef struct pa_socket_client pa_socket_client; -struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port); -struct pa_socket_client* pa_socket_client_new_ipv6(struct pa_mainloop_api *m, uint8_t address[16], uint16_t port); -struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename); -struct pa_socket_client* pa_socket_client_new_sockaddr(struct pa_mainloop_api *m, const struct sockaddr *sa, size_t salen); -struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, const char *a, uint16_t default_port); +pa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port); +pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[16], uint16_t port); +pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename); +pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen); +pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char *a, uint16_t default_port); -void pa_socket_client_unref(struct pa_socket_client *c); -struct pa_socket_client* pa_socket_client_ref(struct pa_socket_client *c); +void pa_socket_client_unref(pa_socket_client *c); +pa_socket_client* pa_socket_client_ref(pa_socket_client *c); -void pa_socket_client_set_callback(struct pa_socket_client *c, void (*on_connection)(struct pa_socket_client *c, struct pa_iochannel*io, void *userdata), void *userdata); +void pa_socket_client_set_callback(pa_socket_client *c, void (*on_connection)(pa_socket_client *c, pa_iochannel*io, void *userdata), void *userdata); -int pa_socket_client_is_local(struct pa_socket_client *c); +int pa_socket_client_is_local(pa_socket_client *c); #endif diff --git a/polyp/socket-server.c b/polyp/socket-server.c index a78f04cd..6f1794bc 100644 --- a/polyp/socket-server.c +++ b/polyp/socket-server.c @@ -70,17 +70,17 @@ struct pa_socket_server { char *filename; char *tcpwrap_service; - void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata); + void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata); void *userdata; - struct pa_io_event *io_event; - struct pa_mainloop_api *mainloop; + pa_io_event *io_event; + pa_mainloop_api *mainloop; enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX, SOCKET_SERVER_IPV6 } type; }; -static void callback(struct pa_mainloop_api *mainloop, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { - struct pa_socket_server *s = userdata; - struct pa_iochannel *io; +static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { + pa_socket_server *s = userdata; + pa_iochannel *io; int nfd; assert(s && s->mainloop == mainloop && s->io_event == e && e && fd >= 0 && fd == s->fd); @@ -129,11 +129,11 @@ finish: pa_socket_server_unref(s); } -struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd) { - struct pa_socket_server *s; +pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) { + pa_socket_server *s; assert(m && fd >= 0); - s = pa_xmalloc(sizeof(struct pa_socket_server)); + s = pa_xmalloc(sizeof(pa_socket_server)); s->ref = 1; s->fd = fd; s->filename = NULL; @@ -150,7 +150,7 @@ struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd) return s; } -struct pa_socket_server* pa_socket_server_ref(struct pa_socket_server *s) { +pa_socket_server* pa_socket_server_ref(pa_socket_server *s) { assert(s && s->ref >= 1); s->ref++; return s; @@ -158,10 +158,10 @@ struct pa_socket_server* pa_socket_server_ref(struct pa_socket_server *s) { #ifdef HAVE_SYS_UN_H -struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename) { +pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) { int fd = -1; struct sockaddr_un sa; - struct pa_socket_server *s; + pa_socket_server *s; assert(m && filename); @@ -205,14 +205,14 @@ fail: #else /* HAVE_SYS_UN_H */ -struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename) { +pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) { return NULL; } #endif /* HAVE_SYS_UN_H */ -struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service) { - struct pa_socket_server *ss; +pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service) { + pa_socket_server *ss; int fd = -1; struct sockaddr_in sa; int on = 1; @@ -260,8 +260,8 @@ fail: return NULL; } -struct pa_socket_server* pa_socket_server_new_ipv6(struct pa_mainloop_api *m, uint8_t address[16], uint16_t port) { - struct pa_socket_server *ss; +pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port) { + pa_socket_server *ss; int fd = -1; struct sockaddr_in6 sa; int on = 1; @@ -307,7 +307,7 @@ fail: return NULL; } -static void socket_server_free(struct pa_socket_server*s) { +static void socket_server_free(pa_socket_server*s) { assert(s); close(s->fd); @@ -322,14 +322,14 @@ static void socket_server_free(struct pa_socket_server*s) { pa_xfree(s); } -void pa_socket_server_unref(struct pa_socket_server *s) { +void pa_socket_server_unref(pa_socket_server *s) { assert(s && s->ref >= 1); if (!(--(s->ref))) socket_server_free(s); } -void pa_socket_server_set_callback(struct pa_socket_server*s, void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata), void *userdata) { +void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata), void *userdata) { assert(s && s->ref >= 1); s->on_connection = on_connection; @@ -337,7 +337,7 @@ void pa_socket_server_set_callback(struct pa_socket_server*s, void (*on_connecti } -char *pa_socket_server_get_address(struct pa_socket_server *s, char *c, size_t l) { +char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { assert(s && c && l > 0); switch (s->type) { diff --git a/polyp/socket-server.h b/polyp/socket-server.h index dbd82518..6c5d7bac 100644 --- a/polyp/socket-server.h +++ b/polyp/socket-server.h @@ -28,18 +28,18 @@ /* It is safe to destroy the calling socket_server object from the callback */ -struct pa_socket_server; +typedef struct pa_socket_server pa_socket_server; -struct pa_socket_server* pa_socket_server_new(struct pa_mainloop_api *m, int fd); -struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename); -struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service); -struct pa_socket_server* pa_socket_server_new_ipv6(struct pa_mainloop_api *m, uint8_t address[16], uint16_t port); +pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd); +pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename); +pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port); -void pa_socket_server_unref(struct pa_socket_server*s); -struct pa_socket_server* pa_socket_server_ref(struct pa_socket_server *s); +void pa_socket_server_unref(pa_socket_server*s); +pa_socket_server* pa_socket_server_ref(pa_socket_server *s); -void pa_socket_server_set_callback(struct pa_socket_server*s, void (*on_connection)(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata), void *userdata); +void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata), void *userdata); -char *pa_socket_server_get_address(struct pa_socket_server *s, char *c, size_t l); +char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l); #endif diff --git a/polyp/sound-file-stream.c b/polyp/sound-file-stream.c index 621c3ed9..a277eb25 100644 --- a/polyp/sound-file-stream.c +++ b/polyp/sound-file-stream.c @@ -40,8 +40,8 @@ struct userdata { SNDFILE *sndfile; - struct pa_sink_input *sink_input; - struct pa_memchunk memchunk; + pa_sink_input *sink_input; + pa_memchunk memchunk; sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames); }; @@ -60,16 +60,16 @@ static void free_userdata(struct userdata *u) { pa_xfree(u); } -static void sink_input_kill(struct pa_sink_input *i) { +static void sink_input_kill(pa_sink_input *i) { assert(i && i->userdata); free_userdata(i->userdata); } -static void si_kill(struct pa_mainloop_api *m, void *i) { +static void si_kill(PA_GCC_UNUSED pa_mainloop_api *m, void *i) { sink_input_kill(i); } -static int sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { +static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { struct userdata *u; assert(i && chunk && i->userdata); u = i->userdata; @@ -98,7 +98,7 @@ static int sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { return 0; } -static void sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk*chunk, size_t length) { +static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) { struct userdata *u; assert(i && chunk && length && i->userdata); u = i->userdata; @@ -116,10 +116,10 @@ static void sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk*ch } } -int pa_play_file(struct pa_sink *sink, const char *fname, pa_volume_t volume) { +int pa_play_file(pa_sink *sink, const char *fname, pa_volume_t volume) { struct userdata *u = NULL; SF_INFO sfinfo; - struct pa_sample_spec ss; + pa_sample_spec ss; assert(sink && fname); if (volume <= 0) diff --git a/polyp/sound-file-stream.h b/polyp/sound-file-stream.h index f5ab8e2c..0b383f96 100644 --- a/polyp/sound-file-stream.h +++ b/polyp/sound-file-stream.h @@ -24,6 +24,6 @@ #include "sink.h" -int pa_play_file(struct pa_sink *sink, const char *fname, pa_volume_t volume); +int pa_play_file(pa_sink *sink, const char *fname, pa_volume_t volume); #endif diff --git a/polyp/sound-file.c b/polyp/sound-file.c index 326ddd8b..0048ed74 100644 --- a/polyp/sound-file.c +++ b/polyp/sound-file.c @@ -34,7 +34,7 @@ #define MAX_FILE_SIZE (1024*1024) -int pa_sound_file_load(const char *fname, struct pa_sample_spec *ss, struct pa_memchunk *chunk, struct pa_memblock_stat *s) { +int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_memchunk *chunk, pa_memblock_stat *s) { SNDFILE*sf = NULL; SF_INFO sfinfo; int ret = -1; @@ -106,7 +106,7 @@ finish: int pa_sound_file_too_big_to_cache(const char *fname) { SNDFILE*sf = NULL; SF_INFO sfinfo; - struct pa_sample_spec ss; + pa_sample_spec ss; if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) { pa_log(__FILE__": Failed to open file %s\n", fname); diff --git a/polyp/sound-file.h b/polyp/sound-file.h index 855e6883..e0534275 100644 --- a/polyp/sound-file.h +++ b/polyp/sound-file.h @@ -25,7 +25,7 @@ #include "memchunk.h" #include "sample.h" -int pa_sound_file_load(const char *fname, struct pa_sample_spec *ss, struct pa_memchunk *chunk, struct pa_memblock_stat *s); +int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_memchunk *chunk, pa_memblock_stat *s); int pa_sound_file_too_big_to_cache(const char *fname); diff --git a/polyp/source-output.c b/polyp/source-output.c index f954c23f..7a540633 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -33,14 +33,14 @@ #include "subscribe.h" #include "log.h" -struct pa_source_output* pa_source_output_new(struct pa_source *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int resample_method) { - struct pa_source_output *o; - struct pa_resampler *resampler = NULL; +pa_source_output* pa_source_output_new(pa_source *s, pa_typeid_t typeid, const char *name, const pa_sample_spec *spec, int resample_method) { + pa_source_output *o; + pa_resampler *resampler = NULL; int r; char st[256]; assert(s && spec); - if (pa_idxset_ncontents(s->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { + if (pa_idxset_size(s->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { pa_log(__FILE__": Failed to create source output: too many outputs per source.\n"); return NULL; } @@ -52,7 +52,7 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, pa_typeid_t t if (!(resampler = pa_resampler_new(&s->sample_spec, spec, s->core->memblock_stat, resample_method))) return NULL; - o = pa_xmalloc(sizeof(struct pa_source_output)); + o = pa_xmalloc(sizeof(pa_source_output)); o->ref = 1; o->state = PA_SOURCE_OUTPUT_RUNNING; o->name = pa_xstrdup(name); @@ -84,7 +84,7 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, pa_typeid_t t return o; } -void pa_source_output_disconnect(struct pa_source_output*o) { +void pa_source_output_disconnect(pa_source_output*o) { assert(o && o->state != PA_SOURCE_OUTPUT_DISCONNECTED && o->source && o->source->core); pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); @@ -100,7 +100,7 @@ void pa_source_output_disconnect(struct pa_source_output*o) { o->state = PA_SOURCE_OUTPUT_DISCONNECTED; } -static void source_output_free(struct pa_source_output* o) { +static void source_output_free(pa_source_output* o) { assert(o); if (o->state != PA_SOURCE_OUTPUT_DISCONNECTED) @@ -116,29 +116,29 @@ static void source_output_free(struct pa_source_output* o) { } -void pa_source_output_unref(struct pa_source_output* o) { +void pa_source_output_unref(pa_source_output* o) { assert(o && o->ref >= 1); if (!(--o->ref)) source_output_free(o); } -struct pa_source_output* pa_source_output_ref(struct pa_source_output *o) { +pa_source_output* pa_source_output_ref(pa_source_output *o) { assert(o && o->ref >= 1); o->ref++; return o; } -void pa_source_output_kill(struct pa_source_output*o) { +void pa_source_output_kill(pa_source_output*o) { assert(o && o->ref >= 1); if (o->kill) o->kill(o); } -void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk *chunk) { - struct pa_memchunk rchunk; +void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { + pa_memchunk rchunk; assert(o && chunk && chunk->length && o->push); if (o->state == PA_SOURCE_OUTPUT_CORKED) @@ -158,7 +158,7 @@ void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk pa_memblock_unref(rchunk.memblock); } -void pa_source_output_set_name(struct pa_source_output *o, const char *name) { +void pa_source_output_set_name(pa_source_output *o, const char *name) { assert(o && o->ref >= 1); pa_xfree(o->name); o->name = pa_xstrdup(name); @@ -166,7 +166,7 @@ void pa_source_output_set_name(struct pa_source_output *o, const char *name) { pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); } -pa_usec_t pa_source_output_get_latency(struct pa_source_output *o) { +pa_usec_t pa_source_output_get_latency(pa_source_output *o) { assert(o && o->ref >= 1); if (o->get_latency) @@ -175,7 +175,7 @@ pa_usec_t pa_source_output_get_latency(struct pa_source_output *o) { return 0; } -void pa_source_output_cork(struct pa_source_output *o, int b) { +void pa_source_output_cork(pa_source_output *o, int b) { assert(o && o->ref >= 1); if (o->state == PA_SOURCE_OUTPUT_DISCONNECTED) @@ -184,7 +184,7 @@ void pa_source_output_cork(struct pa_source_output *o, int b) { o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; } -enum pa_resample_method pa_source_output_get_resample_method(struct pa_source_output *o) { +pa_resample_method pa_source_output_get_resample_method(pa_source_output *o) { assert(o && o->ref >= 1); if (!o->resampler) diff --git a/polyp/source-output.h b/polyp/source-output.h index f3187aa9..ef8f9fa9 100644 --- a/polyp/source-output.h +++ b/polyp/source-output.h @@ -24,6 +24,8 @@ #include +typedef struct pa_source_output pa_source_output; + #include "source.h" #include "sample.h" #include "memblockq.h" @@ -31,52 +33,52 @@ #include "module.h" #include "client.h" -enum pa_source_output_state { +typedef enum { PA_SOURCE_OUTPUT_RUNNING, PA_SOURCE_OUTPUT_CORKED, PA_SOURCE_OUTPUT_DISCONNECTED -}; +} pa_source_output_state; struct pa_source_output { int ref; - enum pa_source_output_state state; + pa_source_output_state state; uint32_t index; pa_typeid_t typeid; char *name; - struct pa_module *owner; - struct pa_client *client; - struct pa_source *source; - struct pa_sample_spec sample_spec; + pa_module *owner; + pa_client *client; + pa_source *source; + pa_sample_spec sample_spec; - void (*push)(struct pa_source_output *o, const struct pa_memchunk *chunk); - void (*kill)(struct pa_source_output* o); - pa_usec_t (*get_latency) (struct pa_source_output *i); + void (*push)(pa_source_output *o, const pa_memchunk *chunk); + void (*kill)(pa_source_output* o); + pa_usec_t (*get_latency) (pa_source_output *i); - struct pa_resampler* resampler; + pa_resampler* resampler; void *userdata; }; -struct pa_source_output* pa_source_output_new(struct pa_source *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int resample_method); -void pa_source_output_unref(struct pa_source_output* o); -struct pa_source_output* pa_source_output_ref(struct pa_source_output *o); +pa_source_output* pa_source_output_new(pa_source *s, pa_typeid_t typeid, const char *name, const pa_sample_spec *spec, int resample_method); +void pa_source_output_unref(pa_source_output* o); +pa_source_output* pa_source_output_ref(pa_source_output *o); /* To be called by the implementing module only */ -void pa_source_output_disconnect(struct pa_source_output*o); +void pa_source_output_disconnect(pa_source_output*o); /* External code may request disconnection with this funcion */ -void pa_source_output_kill(struct pa_source_output*o); +void pa_source_output_kill(pa_source_output*o); -void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk *chunk); +void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk); -void pa_source_output_set_name(struct pa_source_output *i, const char *name); +void pa_source_output_set_name(pa_source_output *i, const char *name); -pa_usec_t pa_source_output_get_latency(struct pa_source_output *i); +pa_usec_t pa_source_output_get_latency(pa_source_output *i); -void pa_source_output_cork(struct pa_source_output *i, int b); +void pa_source_output_cork(pa_source_output *i, int b); -enum pa_resample_method pa_source_output_get_resample_method(struct pa_source_output *o); +pa_resample_method pa_source_output_get_resample_method(pa_source_output *o); #endif diff --git a/polyp/source.c b/polyp/source.c index fc73272c..c287899e 100644 --- a/polyp/source.c +++ b/polyp/source.c @@ -35,13 +35,13 @@ #include "subscribe.h" #include "log.h" -struct pa_source* pa_source_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec) { - struct pa_source *s; +pa_source* pa_source_new(pa_core *core, pa_typeid_t typeid, const char *name, int fail, const pa_sample_spec *spec) { + pa_source *s; char st[256]; int r; assert(core && spec && name && *name); - s = pa_xmalloc(sizeof(struct pa_source)); + s = pa_xmalloc(sizeof(pa_source)); if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SOURCE, s, fail))) { pa_xfree(s); @@ -76,8 +76,8 @@ struct pa_source* pa_source_new(struct pa_core *core, pa_typeid_t typeid, const return s; } -void pa_source_disconnect(struct pa_source *s) { - struct pa_source_output *o, *j = NULL; +void pa_source_disconnect(pa_source *s) { + pa_source_output *o, *j = NULL; assert(s && s->state == PA_SOURCE_RUNNING); pa_namereg_unregister(s->core, s->name); @@ -96,7 +96,7 @@ void pa_source_disconnect(struct pa_source *s) { s->state = PA_SOURCE_DISCONNECTED; } -static void source_free(struct pa_source *s) { +static void source_free(pa_source *s) { assert(s && !s->ref); if (s->state != PA_SOURCE_DISCONNECTED) @@ -111,36 +111,36 @@ static void source_free(struct pa_source *s) { pa_xfree(s); } -void pa_source_unref(struct pa_source *s) { +void pa_source_unref(pa_source *s) { assert(s && s->ref >= 1); if (!(--s->ref)) source_free(s); } -struct pa_source* pa_source_ref(struct pa_source *s) { +pa_source* pa_source_ref(pa_source *s) { assert(s && s->ref >= 1); s->ref++; return s; } -void pa_source_notify(struct pa_source*s) { +void pa_source_notify(pa_source*s) { assert(s && s->ref >= 1); if (s->notify) s->notify(s); } -static int do_post(void *p, uint32_t index, int *del, void*userdata) { - const struct pa_memchunk *chunk = userdata; - struct pa_source_output *o = p; +static int do_post(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void*userdata) { + const pa_memchunk *chunk = userdata; + pa_source_output *o = p; assert(o && o->push && del && chunk); pa_source_output_push(o, chunk); return 0; } -void pa_source_post(struct pa_source*s, const struct pa_memchunk *chunk) { +void pa_source_post(pa_source*s, const pa_memchunk *chunk) { assert(s && s->ref >= 1 && chunk); pa_source_ref(s); @@ -148,12 +148,12 @@ void pa_source_post(struct pa_source*s, const struct pa_memchunk *chunk) { pa_source_unref(s); } -void pa_source_set_owner(struct pa_source *s, struct pa_module *m) { +void pa_source_set_owner(pa_source *s, pa_module *m) { assert(s); s->owner = m; } -pa_usec_t pa_source_get_latency(struct pa_source *s) { +pa_usec_t pa_source_get_latency(pa_source *s) { assert(s && s->ref >= 1); if (!s->get_latency) diff --git a/polyp/source.h b/polyp/source.h index 0fac2b34..c7f8d059 100644 --- a/polyp/source.h +++ b/polyp/source.h @@ -22,7 +22,7 @@ USA. ***/ -struct pa_source; +typedef struct pa_source pa_source; #include #include "core.h" @@ -32,45 +32,46 @@ struct pa_source; #include "memchunk.h" #include "sink.h" #include "typeid.h" +#include "module.h" #define PA_MAX_OUTPUTS_PER_SOURCE 16 -enum pa_source_state { +typedef enum pa_source_state { PA_SOURCE_RUNNING, PA_SOURCE_DISCONNECTED -}; +} pa_source_state; struct pa_source { int ref; - enum pa_source_state state; + pa_source_state state; uint32_t index; pa_typeid_t typeid; char *name, *description; - struct pa_module *owner; - struct pa_core *core; - struct pa_sample_spec sample_spec; - struct pa_idxset *outputs; - struct pa_sink *monitor_of; + pa_module *owner; + pa_core *core; + pa_sample_spec sample_spec; + pa_idxset *outputs; + pa_sink *monitor_of; - void (*notify)(struct pa_source*source); - pa_usec_t (*get_latency)(struct pa_source *s); + void (*notify)(pa_source*source); + pa_usec_t (*get_latency)(pa_source *s); void *userdata; }; -struct pa_source* pa_source_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec); -void pa_source_disconnect(struct pa_source *s); -void pa_source_unref(struct pa_source *s); -struct pa_source* pa_source_ref(struct pa_source *c); +pa_source* pa_source_new(pa_core *core, pa_typeid_t typeid, const char *name, int fail, const pa_sample_spec *spec); +void pa_source_disconnect(pa_source *s); +void pa_source_unref(pa_source *s); +pa_source* pa_source_ref(pa_source *c); /* Pass a new memory block to all output streams */ -void pa_source_post(struct pa_source*s, const struct pa_memchunk *b); +void pa_source_post(pa_source*s, const pa_memchunk *b); -void pa_source_notify(struct pa_source *s); +void pa_source_notify(pa_source *s); -void pa_source_set_owner(struct pa_source *s, struct pa_module *m); +void pa_source_set_owner(pa_source *s, pa_module *m); -pa_usec_t pa_source_get_latency(struct pa_source *s); +pa_usec_t pa_source_get_latency(pa_source *s); #endif diff --git a/polyp/strbuf.c b/polyp/strbuf.c index 1aa710ea..aa20218a 100644 --- a/polyp/strbuf.c +++ b/polyp/strbuf.c @@ -46,14 +46,14 @@ struct pa_strbuf { struct chunk *head, *tail; }; -struct pa_strbuf *pa_strbuf_new(void) { - struct pa_strbuf *sb = pa_xmalloc(sizeof(struct pa_strbuf)); +pa_strbuf *pa_strbuf_new(void) { + pa_strbuf *sb = pa_xmalloc(sizeof(pa_strbuf)); sb->length = 0; sb->head = sb->tail = NULL; return sb; } -void pa_strbuf_free(struct pa_strbuf *sb) { +void pa_strbuf_free(pa_strbuf *sb) { assert(sb); while (sb->head) { struct chunk *c = sb->head; @@ -66,7 +66,7 @@ void pa_strbuf_free(struct pa_strbuf *sb) { /* Make a C string from the string buffer. The caller has to free * string with pa_xfree(). */ -char *pa_strbuf_tostring(struct pa_strbuf *sb) { +char *pa_strbuf_tostring(pa_strbuf *sb) { char *t, *e; struct chunk *c; assert(sb); @@ -88,7 +88,7 @@ char *pa_strbuf_tostring(struct pa_strbuf *sb) { } /* Combination of pa_strbuf_free() and pa_strbuf_tostring() */ -char *pa_strbuf_tostring_free(struct pa_strbuf *sb) { +char *pa_strbuf_tostring_free(pa_strbuf *sb) { char *t; assert(sb); t = pa_strbuf_tostring(sb); @@ -97,13 +97,13 @@ char *pa_strbuf_tostring_free(struct pa_strbuf *sb) { } /* Append a string to the string buffer */ -void pa_strbuf_puts(struct pa_strbuf *sb, const char *t) { +void pa_strbuf_puts(pa_strbuf *sb, const char *t) { assert(sb && t); pa_strbuf_putsn(sb, t, strlen(t)); } /* Append a new chunk to the linked list */ -static void append(struct pa_strbuf *sb, struct chunk *c) { +static void append(pa_strbuf *sb, struct chunk *c) { assert(sb && c); if (sb->tail) { @@ -120,7 +120,7 @@ static void append(struct pa_strbuf *sb, struct chunk *c) { } /* Append up to l bytes of a string to the string buffer */ -void pa_strbuf_putsn(struct pa_strbuf *sb, const char *t, size_t l) { +void pa_strbuf_putsn(pa_strbuf *sb, const char *t, size_t l) { struct chunk *c; assert(sb && t); @@ -136,7 +136,7 @@ void pa_strbuf_putsn(struct pa_strbuf *sb, const char *t, size_t l) { /* Append a printf() style formatted string to the string buffer. */ /* The following is based on an example from the GNU libc documentation */ -int pa_strbuf_printf(struct pa_strbuf *sb, const char *format, ...) { +int pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) { int size = 100; struct chunk *c = NULL; diff --git a/polyp/strbuf.h b/polyp/strbuf.h index 281eee1e..a88f5190 100644 --- a/polyp/strbuf.h +++ b/polyp/strbuf.h @@ -22,17 +22,17 @@ USA. ***/ -#include "gcc-printf.h" +#include "gccmacro.h" -struct pa_strbuf; +typedef struct pa_strbuf pa_strbuf; -struct pa_strbuf *pa_strbuf_new(void); -void pa_strbuf_free(struct pa_strbuf *sb); -char *pa_strbuf_tostring(struct pa_strbuf *sb); -char *pa_strbuf_tostring_free(struct pa_strbuf *sb); +pa_strbuf *pa_strbuf_new(void); +void pa_strbuf_free(pa_strbuf *sb); +char *pa_strbuf_tostring(pa_strbuf *sb); +char *pa_strbuf_tostring_free(pa_strbuf *sb); -int pa_strbuf_printf(struct pa_strbuf *sb, const char *format, ...) PA_GCC_PRINTF_ATTR(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); +int pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); +void pa_strbuf_puts(pa_strbuf *sb, const char *t); +void pa_strbuf_putsn(pa_strbuf *sb, const char *t, size_t m); #endif diff --git a/polyp/strlist-test.c b/polyp/strlist-test.c index b68a0415..c670a105 100644 --- a/polyp/strlist-test.c +++ b/polyp/strlist-test.c @@ -2,10 +2,11 @@ #include "strlist.h" #include "xmalloc.h" +#include "gccmacro.h" -int main(int argc, char* argv[]) { +int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char* argv[]) { char *t, *u; - struct pa_strlist *l = NULL; + pa_strlist *l = NULL; l = pa_strlist_prepend(l, "e"); l = pa_strlist_prepend(l, "d"); diff --git a/polyp/strlist.c b/polyp/strlist.c index 6dc865d1..09eb0c8a 100644 --- a/polyp/strlist.c +++ b/polyp/strlist.c @@ -32,22 +32,22 @@ #include "util.h" struct pa_strlist { - struct pa_strlist *next; + pa_strlist *next; char *str; }; -struct pa_strlist* pa_strlist_prepend(struct pa_strlist *l, const char *s) { - struct pa_strlist *n; +pa_strlist* pa_strlist_prepend(pa_strlist *l, const char *s) { + pa_strlist *n; assert(s); - n = pa_xmalloc(sizeof(struct pa_strlist)); + n = pa_xmalloc(sizeof(pa_strlist)); n->str = pa_xstrdup(s); n->next = l; return n; } -char *pa_strlist_tostring(struct pa_strlist *l) { +char *pa_strlist_tostring(pa_strlist *l) { int first = 1; - struct pa_strbuf *b; + pa_strbuf *b; b = pa_strbuf_new(); for (; l; l = l->next) { @@ -60,13 +60,13 @@ char *pa_strlist_tostring(struct pa_strlist *l) { return pa_strbuf_tostring_free(b); } -struct pa_strlist* pa_strlist_remove(struct pa_strlist *l, const char *s) { - struct pa_strlist *ret = l, *prev = NULL; +pa_strlist* pa_strlist_remove(pa_strlist *l, const char *s) { + pa_strlist *ret = l, *prev = NULL; assert(l && s); while (l) { if (!strcmp(l->str, s)) { - struct pa_strlist *n = l->next; + pa_strlist *n = l->next; if (!prev) { assert(ret == l); @@ -88,9 +88,9 @@ struct pa_strlist* pa_strlist_remove(struct pa_strlist *l, const char *s) { return ret; } -void pa_strlist_free(struct pa_strlist *l) { +void pa_strlist_free(pa_strlist *l) { while (l) { - struct pa_strlist *c = l; + pa_strlist *c = l; l = l->next; pa_xfree(c->str); @@ -98,8 +98,8 @@ void pa_strlist_free(struct pa_strlist *l) { } } -struct pa_strlist* pa_strlist_pop(struct pa_strlist *l, char **s) { - struct pa_strlist *r; +pa_strlist* pa_strlist_pop(pa_strlist *l, char **s) { + pa_strlist *r; assert(s); if (!l) { @@ -113,15 +113,15 @@ struct pa_strlist* pa_strlist_pop(struct pa_strlist *l, char **s) { return r; } -struct pa_strlist* pa_strlist_parse(const char *s) { - struct pa_strlist *head = NULL, *p = NULL; +pa_strlist* pa_strlist_parse(const char *s) { + pa_strlist *head = NULL, *p = NULL; const char *state = NULL; char *r; while ((r = pa_split_spaces(s, &state))) { - struct pa_strlist *n; + pa_strlist *n; - n = pa_xmalloc(sizeof(struct pa_strlist)); + n = pa_xmalloc(sizeof(pa_strlist)); n->str = r; n->next = NULL; diff --git a/polyp/strlist.h b/polyp/strlist.h index 533f5533..2c54dc74 100644 --- a/polyp/strlist.h +++ b/polyp/strlist.h @@ -22,26 +22,26 @@ USA. ***/ -struct pa_strlist; +typedef struct pa_strlist pa_strlist; /* Add the specified server string to the list, return the new linked list head */ -struct pa_strlist* pa_strlist_prepend(struct pa_strlist *l, const char *s); +pa_strlist* pa_strlist_prepend(pa_strlist *l, const char *s); /* Remove the specified string from the list, return the new linked list head */ -struct pa_strlist* pa_strlist_remove(struct pa_strlist *l, const char *s); +pa_strlist* pa_strlist_remove(pa_strlist *l, const char *s); /* Make a whitespace separated string of all server stringes. Returned memory has to be freed with pa_xfree() */ -char *pa_strlist_tostring(struct pa_strlist *l); +char *pa_strlist_tostring(pa_strlist *l); /* Free the entire list */ -void pa_strlist_free(struct pa_strlist *l); +void pa_strlist_free(pa_strlist *l); /* Return the next entry in the list in *string and remove it from * the list. Returns the new list head. The memory *string points to * has to be freed with pa_xfree() */ -struct pa_strlist* pa_strlist_pop(struct pa_strlist *l, char **s); +pa_strlist* pa_strlist_pop(pa_strlist *l, char **s); /* Parse a whitespace separated server list */ -struct pa_strlist* pa_strlist_parse(const char *s); +pa_strlist* pa_strlist_parse(const char *s); #endif diff --git a/polyp/subscribe.c b/polyp/subscribe.c index ee6ef3aa..d3db90f7 100644 --- a/polyp/subscribe.c +++ b/polyp/subscribe.c @@ -39,28 +39,28 @@ * called from within the stack frame the entity was created in. */ struct pa_subscription { - struct pa_core *core; + pa_core *core; int dead; - void (*callback)(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); + void (*callback)(pa_core *c, pa_subscription_event_type t, uint32_t index, void *userdata); void *userdata; - enum pa_subscription_mask mask; + pa_subscription_mask mask; - struct pa_subscription *prev, *next; + pa_subscription *prev, *next; }; struct pa_subscription_event { - enum pa_subscription_event_type type; + pa_subscription_event_type type; uint32_t index; }; -static void sched_event(struct pa_core *c); +static void sched_event(pa_core *c); /* Allocate a new subscription object for the given subscription mask. Use the specified callback function and user data */ -struct pa_subscription* pa_subscription_new(struct pa_core *c, enum pa_subscription_mask m, void (*callback)(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { - struct pa_subscription *s; +pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask m, void (*callback)(pa_core *c, pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { + pa_subscription *s; assert(c); - s = pa_xmalloc(sizeof(struct pa_subscription)); + s = pa_xmalloc(sizeof(pa_subscription)); s->core = c; s->dead = 0; s->callback = callback; @@ -75,13 +75,13 @@ struct pa_subscription* pa_subscription_new(struct pa_core *c, enum pa_subscript } /* Free a subscription object, effectively marking it for deletion */ -void pa_subscription_free(struct pa_subscription*s) { +void pa_subscription_free(pa_subscription*s) { assert(s && !s->dead); s->dead = 1; sched_event(s->core); } -static void free_item(struct pa_subscription *s) { +static void free_item(pa_subscription *s) { assert(s && s->core); if (s->prev) @@ -96,8 +96,8 @@ static void free_item(struct pa_subscription *s) { } /* Free all subscription objects */ -void pa_subscription_free_all(struct pa_core *c) { - struct pa_subscription_event *e; +void pa_subscription_free_all(pa_core *c) { + pa_subscription_event *e; assert(c); while (c->subscriptions) @@ -117,7 +117,7 @@ void pa_subscription_free_all(struct pa_core *c) { } } -/*static void dump_event(struct pa_subscription_event*e) { +/*static void dump_event(pa_subscription_event*e) { switch (e->type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { case PA_SUBSCRIPTION_EVENT_SINK: pa_log(__FILE__": SINK_EVENT"); @@ -161,10 +161,10 @@ void pa_subscription_free_all(struct pa_core *c) { }*/ /* Deferred callback for dispatching subscirption events */ -static void defer_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) { - struct pa_core *c = userdata; - struct pa_subscription *s; - assert(c && c->subscription_defer_event == e && c->mainloop == m); +static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) { + pa_core *c = userdata; + pa_subscription *s; + assert(c && c->subscription_defer_event == de && c->mainloop == m); c->mainloop->defer_enable(c->subscription_defer_event, 0); @@ -172,10 +172,9 @@ static void defer_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void * /* Dispatch queued events */ if (c->subscription_event_queue) { - struct pa_subscription_event *e; + pa_subscription_event *e; while ((e = pa_queue_pop(c->subscription_event_queue))) { - struct pa_subscription *s; for (s = c->subscriptions; s; s = s->next) { @@ -191,7 +190,7 @@ static void defer_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void * s = c->subscriptions; while (s) { - struct pa_subscription *n = s->next; + pa_subscription *n = s->next; if (s->dead) free_item(s); s = n; @@ -199,7 +198,7 @@ static void defer_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void * } /* Schedule an mainloop event so that a pending subscription event is dispatched */ -static void sched_event(struct pa_core *c) { +static void sched_event(pa_core *c) { assert(c); if (!c->subscription_defer_event) { @@ -211,11 +210,11 @@ static void sched_event(struct pa_core *c) { } /* Append a new subscription event to the subscription event queue and schedule a main loop event */ -void pa_subscription_post(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index) { - struct pa_subscription_event *e; +void pa_subscription_post(pa_core *c, pa_subscription_event_type t, uint32_t index) { + pa_subscription_event *e; assert(c); - e = pa_xmalloc(sizeof(struct pa_subscription_event)); + e = pa_xmalloc(sizeof(pa_subscription_event)); e->type = t; e->index = index; diff --git a/polyp/subscribe.h b/polyp/subscribe.h index 38323faf..6980328f 100644 --- a/polyp/subscribe.h +++ b/polyp/subscribe.h @@ -22,16 +22,16 @@ USA. ***/ +typedef struct pa_subscription pa_subscription; +typedef struct pa_subscription_event pa_subscription_event; + #include "core.h" #include "native-common.h" -struct pa_subscription; -struct pa_subscription_event; - -struct pa_subscription* pa_subscription_new(struct pa_core *c, enum pa_subscription_mask m, void (*callback)(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); -void pa_subscription_free(struct pa_subscription*s); -void pa_subscription_free_all(struct pa_core *c); +pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask m, void (*callback)(pa_core *c, pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); +void pa_subscription_free(pa_subscription*s); +void pa_subscription_free_all(pa_core *c); -void pa_subscription_post(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index); +void pa_subscription_post(pa_core *c, pa_subscription_event_type t, uint32_t idx); #endif diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c index 1ff09cd1..28b1afa6 100644 --- a/polyp/tagstruct.c +++ b/polyp/tagstruct.c @@ -65,12 +65,12 @@ struct pa_tagstruct { int dynamic; }; -struct pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) { - struct pa_tagstruct*t; +pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) { + pa_tagstruct*t; assert(!data || (data && length)); - t = pa_xmalloc(sizeof(struct pa_tagstruct)); + t = pa_xmalloc(sizeof(pa_tagstruct)); t->data = (uint8_t*) data; t->allocated = t->length = data ? length : 0; t->rindex = 0; @@ -78,14 +78,14 @@ struct pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) { return t; } -void pa_tagstruct_free(struct pa_tagstruct*t) { +void pa_tagstruct_free(pa_tagstruct*t) { assert(t); if (t->dynamic) pa_xfree(t->data); pa_xfree(t); } -uint8_t* pa_tagstruct_free_data(struct pa_tagstruct*t, size_t *l) { +uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l) { uint8_t *p; assert(t && t->dynamic && l); p = t->data; @@ -94,7 +94,7 @@ uint8_t* pa_tagstruct_free_data(struct pa_tagstruct*t, size_t *l) { return p; } -static void extend(struct pa_tagstruct*t, size_t l) { +static void extend(pa_tagstruct*t, size_t l) { assert(t && t->dynamic); if (t->length+l <= t->allocated) @@ -103,7 +103,7 @@ static void extend(struct pa_tagstruct*t, size_t l) { t->data = pa_xrealloc(t->data, t->allocated = t->length+l+100); } -void pa_tagstruct_puts(struct pa_tagstruct*t, const char *s) { +void pa_tagstruct_puts(pa_tagstruct*t, const char *s) { size_t l; assert(t); if (s) { @@ -119,7 +119,7 @@ void pa_tagstruct_puts(struct pa_tagstruct*t, const char *s) { } } -void pa_tagstruct_putu32(struct pa_tagstruct*t, uint32_t i) { +void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i) { assert(t); extend(t, 5); t->data[t->length] = TAG_U32; @@ -128,7 +128,7 @@ void pa_tagstruct_putu32(struct pa_tagstruct*t, uint32_t i) { t->length += 5; } -void pa_tagstruct_putu8(struct pa_tagstruct*t, uint8_t c) { +void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c) { assert(t); extend(t, 2); t->data[t->length] = TAG_U8; @@ -136,7 +136,7 @@ void pa_tagstruct_putu8(struct pa_tagstruct*t, uint8_t c) { t->length += 2; } -void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample_spec *ss) { +void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss) { uint32_t rate; assert(t && ss); extend(t, 7); @@ -148,7 +148,7 @@ void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample t->length += 7; } -void pa_tagstruct_put_arbitrary(struct pa_tagstruct *t, const void *p, size_t length) { +void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) { uint32_t tmp; assert(t && p); @@ -161,14 +161,14 @@ void pa_tagstruct_put_arbitrary(struct pa_tagstruct *t, const void *p, size_t le t->length += 5+length; } -void pa_tagstruct_put_boolean(struct pa_tagstruct*t, int b) { +void pa_tagstruct_put_boolean(pa_tagstruct*t, int b) { assert(t); extend(t, 1); t->data[t->length] = b ? TAG_BOOLEAN_TRUE : TAG_BOOLEAN_FALSE; t->length += 1; } -void pa_tagstruct_put_timeval(struct pa_tagstruct*t, const struct timeval *tv) { +void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv) { uint32_t tmp; assert(t); extend(t, 9); @@ -180,7 +180,7 @@ void pa_tagstruct_put_timeval(struct pa_tagstruct*t, const struct timeval *tv) { t->length += 9; } -void pa_tagstruct_put_usec(struct pa_tagstruct*t, pa_usec_t u) { +void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u) { uint32_t tmp; assert(t); extend(t, 9); @@ -192,7 +192,7 @@ void pa_tagstruct_put_usec(struct pa_tagstruct*t, pa_usec_t u) { t->length += 9; } -void pa_tagstruct_putu64(struct pa_tagstruct*t, uint64_t u) { +void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) { uint32_t tmp; assert(t); extend(t, 9); @@ -204,7 +204,7 @@ void pa_tagstruct_putu64(struct pa_tagstruct*t, uint64_t u) { t->length += 9; } -int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s) { +int pa_tagstruct_gets(pa_tagstruct*t, const char **s) { int error = 0; size_t n; char *c; @@ -241,7 +241,7 @@ int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s) { return 0; } -int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i) { +int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) { assert(t && i); if (t->rindex+5 > t->length) @@ -256,7 +256,7 @@ int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i) { return 0; } -int pa_tagstruct_getu8(struct pa_tagstruct*t, uint8_t *c) { +int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) { assert(t && c); if (t->rindex+2 > t->length) @@ -270,7 +270,7 @@ int pa_tagstruct_getu8(struct pa_tagstruct*t, uint8_t *c) { return 0; } -int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec *ss) { +int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) { assert(t && ss); if (t->rindex+7 > t->length) @@ -288,7 +288,7 @@ int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec * return 0; } -int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t length) { +int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) { uint32_t len; assert(t && p); @@ -307,18 +307,18 @@ int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t le return 0; } -int pa_tagstruct_eof(struct pa_tagstruct*t) { +int pa_tagstruct_eof(pa_tagstruct*t) { assert(t); return t->rindex >= t->length; } -const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l) { +const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) { assert(t && t->dynamic && l); *l = t->length; return t->data; } -int pa_tagstruct_get_boolean(struct pa_tagstruct*t, int *b) { +int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) { assert(t && b); if (t->rindex+1 > t->length) @@ -335,7 +335,7 @@ int pa_tagstruct_get_boolean(struct pa_tagstruct*t, int *b) { return 0; } -int pa_tagstruct_get_timeval(struct pa_tagstruct*t, struct timeval *tv) { +int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) { if (t->rindex+9 > t->length) return -1; @@ -352,7 +352,7 @@ int pa_tagstruct_get_timeval(struct pa_tagstruct*t, struct timeval *tv) { } -int pa_tagstruct_get_usec(struct pa_tagstruct*t, pa_usec_t *u) { +int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) { uint32_t tmp; assert(t && u); @@ -370,7 +370,7 @@ int pa_tagstruct_get_usec(struct pa_tagstruct*t, pa_usec_t *u) { return 0; } -int pa_tagstruct_getu64(struct pa_tagstruct*t, uint64_t *u) { +int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) { uint32_t tmp; assert(t && u); diff --git a/polyp/tagstruct.h b/polyp/tagstruct.h index 135825e6..85b324b7 100644 --- a/polyp/tagstruct.h +++ b/polyp/tagstruct.h @@ -29,33 +29,33 @@ #include "sample.h" -struct pa_tagstruct; - -struct pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length); -void pa_tagstruct_free(struct pa_tagstruct*t); -uint8_t* pa_tagstruct_free_data(struct pa_tagstruct*t, size_t *l); - -void pa_tagstruct_puts(struct pa_tagstruct*t, const char *s); -void pa_tagstruct_putu8(struct pa_tagstruct*t, uint8_t c); -void pa_tagstruct_putu32(struct pa_tagstruct*t, uint32_t i); -void pa_tagstruct_putu64(struct pa_tagstruct*t, uint64_t i); -void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample_spec *ss); -void pa_tagstruct_put_arbitrary(struct pa_tagstruct*t, const void *p, size_t length); -void pa_tagstruct_put_boolean(struct pa_tagstruct*t, int b); -void pa_tagstruct_put_timeval(struct pa_tagstruct*t, const struct timeval *tv); -void pa_tagstruct_put_usec(struct pa_tagstruct*t, pa_usec_t u); - -int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s); -int pa_tagstruct_getu8(struct pa_tagstruct*t, uint8_t *c); -int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i); -int pa_tagstruct_getu64(struct pa_tagstruct*t, uint64_t *i); -int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec *ss); -int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t length); -int pa_tagstruct_get_boolean(struct pa_tagstruct *t, int *b); -int pa_tagstruct_get_timeval(struct pa_tagstruct*t, struct timeval *tv); -int pa_tagstruct_get_usec(struct pa_tagstruct*t, pa_usec_t *u); - -int pa_tagstruct_eof(struct pa_tagstruct*t); -const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l); +typedef struct pa_tagstruct pa_tagstruct; + +pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length); +void pa_tagstruct_free(pa_tagstruct*t); +uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l); + +void pa_tagstruct_puts(pa_tagstruct*t, const char *s); +void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c); +void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i); +void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t i); +void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss); +void pa_tagstruct_put_arbitrary(pa_tagstruct*t, const void *p, size_t length); +void pa_tagstruct_put_boolean(pa_tagstruct*t, int b); +void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv); +void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u); + +int pa_tagstruct_gets(pa_tagstruct*t, const char **s); +int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c); +int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i); +int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *i); +int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss); +int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length); +int pa_tagstruct_get_boolean(pa_tagstruct *t, int *b); +int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv); +int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u); + +int pa_tagstruct_eof(pa_tagstruct*t); +const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l); #endif diff --git a/polyp/tokenizer.c b/polyp/tokenizer.c index 8ccbc84f..5e0c1b16 100644 --- a/polyp/tokenizer.c +++ b/polyp/tokenizer.c @@ -30,16 +30,17 @@ #include "tokenizer.h" #include "dynarray.h" #include "xmalloc.h" +#include "gccmacro.h" struct pa_tokenizer { - struct pa_dynarray *dynarray; + pa_dynarray *dynarray; }; -static void token_free(void *p, void *userdata) { +static void token_free(void *p, PA_GCC_UNUSED void *userdata) { pa_xfree(p); } -static void parse(struct pa_dynarray*a, const char *s, unsigned args) { +static void parse(pa_dynarray*a, const char *s, unsigned args) { int infty = 0; const char delimiter[] = " \t\n\r"; const char *p; @@ -64,10 +65,10 @@ static void parse(struct pa_dynarray*a, const char *s, unsigned args) { } } -struct pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args) { - struct pa_tokenizer *t; +pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args) { + pa_tokenizer *t; - t = pa_xmalloc(sizeof(struct pa_tokenizer)); + t = pa_xmalloc(sizeof(pa_tokenizer)); t->dynarray = pa_dynarray_new(); assert(t->dynarray); @@ -75,13 +76,13 @@ struct pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args) { return t; } -void pa_tokenizer_free(struct pa_tokenizer *t) { +void pa_tokenizer_free(pa_tokenizer *t) { assert(t); pa_dynarray_free(t->dynarray, token_free, NULL); pa_xfree(t); } -const char *pa_tokenizer_get(struct pa_tokenizer *t, unsigned i) { +const char *pa_tokenizer_get(pa_tokenizer *t, unsigned i) { assert(t); return pa_dynarray_get(t->dynarray, i); } diff --git a/polyp/tokenizer.h b/polyp/tokenizer.h index 0b1c5022..bedacb8a 100644 --- a/polyp/tokenizer.h +++ b/polyp/tokenizer.h @@ -22,11 +22,11 @@ USA. ***/ -struct pa_tokenizer; +typedef struct pa_tokenizer pa_tokenizer; -struct pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args); -void pa_tokenizer_free(struct pa_tokenizer *t); +pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args); +void pa_tokenizer_free(pa_tokenizer *t); -const char *pa_tokenizer_get(struct pa_tokenizer *t, unsigned i); +const char *pa_tokenizer_get(pa_tokenizer *t, unsigned i); #endif diff --git a/polyp/util.c b/polyp/util.c index 26d71203..f9098704 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -219,7 +219,7 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size) { break; ret += r; - data = (uint8_t*) data + r; + data = (const uint8_t*) data + r; size -= r; } @@ -767,13 +767,13 @@ finish: /* Check the current user is member of the specified group */ int pa_uid_in_group(const char *name, gid_t *gid) { - gid_t *gids, tgid; - GETGROUPS_T n = sysconf(_SC_NGROUPS_MAX); + GETGROUPS_T *gids, tgid; + int n = sysconf(_SC_NGROUPS_MAX); int r = -1, i; assert(n > 0); - gids = pa_xmalloc(sizeof(gid_t)*n); + gids = pa_xmalloc(sizeof(GETGROUPS_T)*n); if ((n = getgroups(n, gids)) < 0) { pa_log(__FILE__": getgroups() failed: %s\n", strerror(errno)); diff --git a/polyp/util.h b/polyp/util.h index d9e18ddb..95e7b99b 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -27,7 +27,7 @@ #include #include -#include "gcc-printf.h" +#include "gccmacro.h" #include "sample.h" struct timeval; diff --git a/polyp/voltest.c b/polyp/voltest.c index d8d5c569..286334d0 100644 --- a/polyp/voltest.c +++ b/polyp/voltest.c @@ -3,8 +3,9 @@ #include #include +#include "gccmacro.h" -int main() { +int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { int p; for (p = 0; p <= 200; p++) { pa_volume_t v = pa_volume_from_user((double) p/100); diff --git a/polyp/x11wrap.c b/polyp/x11wrap.c index 4d8d6930..64923320 100644 --- a/polyp/x11wrap.c +++ b/polyp/x11wrap.c @@ -28,42 +28,42 @@ #include "log.h" #include "props.h" -struct pa_x11_client; +typedef struct pa_x11_internal pa_x11_internal; struct pa_x11_internal { - PA_LLIST_FIELDS(struct pa_x11_internal); - struct pa_x11_wrapper *wrapper; - struct pa_io_event* io_event; + PA_LLIST_FIELDS(pa_x11_internal); + pa_x11_wrapper *wrapper; + pa_io_event* io_event; int fd; }; struct pa_x11_wrapper { - struct pa_core *core; + pa_core *core; int ref; char *property_name; Display *display; - struct pa_defer_event* defer_event; - struct pa_io_event* io_event; + pa_defer_event* defer_event; + pa_io_event* io_event; - PA_LLIST_HEAD(struct pa_x11_client, clients); - PA_LLIST_HEAD(struct pa_x11_internal, internals); + PA_LLIST_HEAD(pa_x11_client, clients); + PA_LLIST_HEAD(pa_x11_internal, internals); }; struct pa_x11_client { - PA_LLIST_FIELDS(struct pa_x11_client); - struct pa_x11_wrapper *wrapper; - int (*callback)(struct pa_x11_wrapper *w, XEvent *e, void *userdata); + PA_LLIST_FIELDS(pa_x11_client); + pa_x11_wrapper *wrapper; + int (*callback)(pa_x11_wrapper *w, XEvent *e, void *userdata); void *userdata; }; /* Dispatch all pending X11 events */ -static void work(struct pa_x11_wrapper *w) { +static void work(pa_x11_wrapper *w) { assert(w && w->ref >= 1); while (XPending(w->display)) { - struct pa_x11_client *c; + pa_x11_client *c; XEvent e; XNextEvent(w->display, &e); @@ -76,63 +76,63 @@ static void work(struct pa_x11_wrapper *w) { } /* IO notification event for the X11 display connection */ -static void display_io_event(struct pa_mainloop_api *m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { - struct pa_x11_wrapper *w = userdata; +static void display_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { + pa_x11_wrapper *w = userdata; assert(m && e && fd >= 0 && w && w->ref >= 1); work(w); } /* Deferred notification event. Called once each main loop iteration */ -static void defer_event(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) { - struct pa_x11_wrapper *w = userdata; +static void defer_event(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { + pa_x11_wrapper *w = userdata; assert(m && e && w && w->ref >= 1); work(w); } /* IO notification event for X11 internal connections */ -static void internal_io_event(struct pa_mainloop_api *m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { - struct pa_x11_wrapper *w = userdata; +static void internal_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { + pa_x11_wrapper *w = userdata; assert(m && e && fd >= 0 && w && w->ref >= 1); XProcessInternalConnection(w->display, fd); } /* Add a new IO source for the specified X11 internal connection */ -static struct pa_x11_internal* x11_internal_add(struct pa_x11_wrapper *w, int fd) { - struct pa_x11_internal *i; +static pa_x11_internal* x11_internal_add(pa_x11_wrapper *w, int fd) { + pa_x11_internal *i; assert(i && fd >= 0); - i = pa_xmalloc(sizeof(struct pa_x11_internal)); + i = pa_xmalloc(sizeof(pa_x11_internal)); i->wrapper = w; i->io_event = w->core->mainloop->io_new(w->core->mainloop, fd, PA_IO_EVENT_INPUT, internal_io_event, w); i->fd = fd; - PA_LLIST_PREPEND(struct pa_x11_internal, w->internals, i); + PA_LLIST_PREPEND(pa_x11_internal, w->internals, i); return i; } /* Remove an IO source for an X11 internal connection */ -void x11_internal_remove(struct pa_x11_wrapper *w, struct pa_x11_internal *i) { +static void x11_internal_remove(pa_x11_wrapper *w, pa_x11_internal *i) { assert(i); - PA_LLIST_REMOVE(struct pa_x11_internal, w->internals, i); + PA_LLIST_REMOVE(pa_x11_internal, w->internals, i); w->core->mainloop->io_free(i->io_event); pa_xfree(i); } /* Implementation of XConnectionWatchProc */ static void x11_watch(Display *display, XPointer userdata, int fd, Bool opening, XPointer *watch_data) { - struct pa_x11_wrapper *w = (struct pa_x11_wrapper*) userdata; + pa_x11_wrapper *w = (pa_x11_wrapper*) userdata; assert(display && w && fd >= 0); if (opening) *watch_data = (XPointer) x11_internal_add(w, fd); else - x11_internal_remove(w, (struct pa_x11_internal*) *watch_data); + x11_internal_remove(w, (pa_x11_internal*) *watch_data); } -static struct pa_x11_wrapper* x11_wrapper_new(struct pa_core *c, const char *name, const char *t) { - struct pa_x11_wrapper*w; +static pa_x11_wrapper* x11_wrapper_new(pa_core *c, const char *name, const char *t) { + pa_x11_wrapper*w; Display *d; int r; @@ -141,14 +141,14 @@ static struct pa_x11_wrapper* x11_wrapper_new(struct pa_core *c, const char *nam return NULL; } - w = pa_xmalloc(sizeof(struct pa_x11_wrapper)); + w = pa_xmalloc(sizeof(pa_x11_wrapper)); w->core = c; w->ref = 1; w->property_name = pa_xstrdup(t); w->display = d; - PA_LLIST_HEAD_INIT(struct pa_x11_client, w->clients); - PA_LLIST_HEAD_INIT(struct pa_x11_internal, w->internals); + PA_LLIST_HEAD_INIT(pa_x11_client, w->clients); + PA_LLIST_HEAD_INIT(pa_x11_internal, w->internals); w->defer_event = c->mainloop->defer_new(c->mainloop, defer_event, w); w->io_event = c->mainloop->io_new(c->mainloop, ConnectionNumber(d), PA_IO_EVENT_INPUT, display_io_event, w); @@ -161,7 +161,7 @@ static struct pa_x11_wrapper* x11_wrapper_new(struct pa_core *c, const char *nam return w; } -static void x11_wrapper_free(struct pa_x11_wrapper*w) { +static void x11_wrapper_free(pa_x11_wrapper*w) { int r; assert(w); @@ -183,9 +183,9 @@ static void x11_wrapper_free(struct pa_x11_wrapper*w) { pa_xfree(w); } -struct pa_x11_wrapper* pa_x11_wrapper_get(struct pa_core *c, const char *name) { +pa_x11_wrapper* pa_x11_wrapper_get(pa_core *c, const char *name) { char t[256]; - struct pa_x11_wrapper *w; + pa_x11_wrapper *w; assert(c); snprintf(t, sizeof(t), "x11-wrapper%s%s", name ? "-" : "", name ? name : ""); @@ -195,41 +195,41 @@ struct pa_x11_wrapper* pa_x11_wrapper_get(struct pa_core *c, const char *name) { return x11_wrapper_new(c, name, t); } -struct pa_x11_wrapper* pa_x11_wrapper_ref(struct pa_x11_wrapper *w) { +pa_x11_wrapper* pa_x11_wrapper_ref(pa_x11_wrapper *w) { assert(w && w->ref >= 1); w->ref++; return w; } -void pa_x11_wrapper_unref(struct pa_x11_wrapper* w) { +void pa_x11_wrapper_unref(pa_x11_wrapper* w) { assert(w && w->ref >= 1); if (!(--w->ref)) x11_wrapper_free(w); } -Display *pa_x11_wrapper_get_display(struct pa_x11_wrapper *w) { +Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w) { assert(w && w->ref >= 1); return w->display; } -struct pa_x11_client* pa_x11_client_new(struct pa_x11_wrapper *w, int (*cb)(struct pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata) { - struct pa_x11_client *c; +pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata) { + pa_x11_client *c; assert(w && w->ref >= 1); - c = pa_xmalloc(sizeof(struct pa_x11_client)); + c = pa_xmalloc(sizeof(pa_x11_client)); c->wrapper = w; c->callback = cb; c->userdata = userdata; - PA_LLIST_PREPEND(struct pa_x11_client, w->clients, c); + PA_LLIST_PREPEND(pa_x11_client, w->clients, c); return c; } -void pa_x11_client_free(struct pa_x11_client *c) { +void pa_x11_client_free(pa_x11_client *c) { assert(c && c->wrapper && c->wrapper->ref >= 1); - PA_LLIST_REMOVE(struct pa_x11_client, c->wrapper->clients, c); + PA_LLIST_REMOVE(pa_x11_client, c->wrapper->clients, c); pa_xfree(c); } diff --git a/polyp/x11wrap.h b/polyp/x11wrap.h index 9ed690fe..15645168 100644 --- a/polyp/x11wrap.h +++ b/polyp/x11wrap.h @@ -26,27 +26,27 @@ #include "core.h" -struct pa_x11_wrapper; +typedef struct pa_x11_wrapper pa_x11_wrapper; /* Return the X11 wrapper for this core. In case no wrapper was existant before, allocate a new one */ -struct pa_x11_wrapper* pa_x11_wrapper_get(struct pa_core *c, const char *name); +pa_x11_wrapper* pa_x11_wrapper_get(pa_core *c, const char *name); /* Increase the wrapper's reference count by one */ -struct pa_x11_wrapper* pa_x11_wrapper_ref(struct pa_x11_wrapper *w); +pa_x11_wrapper* pa_x11_wrapper_ref(pa_x11_wrapper *w); /* Decrease the reference counter of an X11 wrapper object */ -void pa_x11_wrapper_unref(struct pa_x11_wrapper* w); +void pa_x11_wrapper_unref(pa_x11_wrapper* w); /* Return the X11 display object for this connection */ -Display *pa_x11_wrapper_get_display(struct pa_x11_wrapper *w); +Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w); -struct pa_x11_client; +typedef struct pa_x11_client pa_x11_client; /* Register an X11 client, that is called for each X11 event */ -struct pa_x11_client* pa_x11_client_new(struct pa_x11_wrapper *w, int (*cb)(struct pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata); +pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata); /* Free an X11 client object */ -void pa_x11_client_free(struct pa_x11_client *c); +void pa_x11_client_free(pa_x11_client *c); #endif diff --git a/polyp/xmalloc.c b/polyp/xmalloc.c index f2751e52..bf366347 100644 --- a/polyp/xmalloc.c +++ b/polyp/xmalloc.c @@ -30,6 +30,8 @@ #include "memory.h" #include "util.h" +#include "xmalloc.h" +#include "gccmacro.h" /* Make sure not to allocate more than this much memory. */ #define MAX_ALLOC_SIZE (1024*1024*20) /* 20MB */ @@ -40,6 +42,8 @@ /* #undef strndup */ /* #undef strdup */ +static void oom(void) PA_GCC_NORETURN; + /** called in case of an OOM situation. Prints an error message and * exits */ static void oom(void) { diff --git a/polyp/xmalloc.h b/polyp/xmalloc.h index b37ece90..2946011a 100644 --- a/polyp/xmalloc.h +++ b/polyp/xmalloc.h @@ -24,6 +24,8 @@ #include #include +#include +#include void* pa_xmalloc(size_t l); void *pa_xmalloc0(size_t l); @@ -35,4 +37,22 @@ char *pa_xstrndup(const char *s, size_t l); void* pa_xmemdup(const void *p, size_t l); +/** Internal helper for pa_xnew() */ +static inline void* pa_xnew_internal(unsigned n, size_t k) { + assert(n < INT_MAX/k); + return pa_xmalloc(n*k); +} + +/** Allocate n new structures of the specified type. */ +#define pa_xnew(type, n) ((type*) pa_xnew_internal((n), sizeof(type))) + +/** Internal helper for pa_xnew0() */ +static inline void* pa_xnew0_internal(unsigned n, size_t k) { + assert(n < INT_MAX/k); + return pa_xmalloc0(n*k); +} + +/** Same as pa_xnew() but set the memory to zero */ +#define pa_xnew0(type, n) ((type*) pa_xnew0_internal((n), sizeof(type))) + #endif -- cgit From 70ac72ee7fa277705b8c3d8b0245d9a43740ef28 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 11 Jan 2006 14:12:38 +0000 Subject: Our makefiles work just fine on older automakes (1.7 tested). Let's keep this out until we run into something that doesn't work. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@448 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f69eb636..20d9b866 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ AC_PREREQ(2.57) AC_INIT([polypaudio],[0.8],[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([polyp/main.c]) AC_CONFIG_HEADERS([config.h]) -AM_INIT_AUTOMAKE([foreign 1.9 -Wall]) +AM_INIT_AUTOMAKE([foreign -Wall]) AC_SUBST(PA_MAJORMINOR, "$PACKAGE_VERSION") AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/polypaudio/]) -- cgit From 2623edcc4222884d57ce161e4ab0ba86feb8a2b8 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 11 Jan 2006 14:13:28 +0000 Subject: Remove the old compiler flag test now that we have a new shiny one. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@449 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/configure.ac b/configure.ac index 20d9b866..8a87928b 100644 --- a/configure.ac +++ b/configure.ac @@ -43,15 +43,6 @@ AC_PROG_CC AC_PROG_GCC_TRADITIONAL AC_GNU_SOURCE -# If using GCC specify some additional parameters -if test "x$GCC" = "xyes" ; then - CFLAGS="$CFLAGS -pipe -W -Wall -pedantic" - - AC_LANG_CONFTEST([int main() {}]) - $CC -c conftest.c -std=gnu9x -Wno-unused-parameter $CFLAGS > /dev/null 2> /dev/null && CFLAGS="$CFLAGS -std=gnu9x -Wno-unused-parameter" - rm -f conftest.o -fi - # M4 AC_PATH_PROG([M4], [m4 gm4], [no]) @@ -72,7 +63,7 @@ test_gcc_flag() { # If using GCC specify some additional parameters if test "x$GCC" = "xyes" ; then - DESIRED_FLAGS="-Wall -W -Wextra -pedantic -pipe -Wformat -Wold-style-definition -Wdeclaration-after-statement -Wfloat-equal -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-noreturn -Wshadow -Wendif-labels -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings -Winline" + DESIRED_FLAGS="-Wall -W -Wextra -pedantic -pipe -Wformat -Wold-style-definition -Wdeclaration-after-statement -Wfloat-equal -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-noreturn -Wshadow -Wendif-labels -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings -Winline -Wno-unused-parameter" if test "x$HAVE_NETLINK" = "xyes" ; then # Test whether rtnetlink.h can be included when compiled with -std=c99 -- cgit From 72316ccf9c8c7fec6fbd5d190852a61168002b24 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 11 Jan 2006 14:36:02 +0000 Subject: Many (FSF and Sun at least) have interpreted the C99 standard in a way that int64_t and similar types are only defined on 64 bit platforms. Using -std=gnu99 lifts this rather silly restriction. The HAVE_NETLINK define is not generated anywhere in our configure. So it was rather pointless to use it for any test. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@450 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/configure.ac b/configure.ac index 8a87928b..bfe6ecd1 100644 --- a/configure.ac +++ b/configure.ac @@ -63,29 +63,9 @@ test_gcc_flag() { # If using GCC specify some additional parameters if test "x$GCC" = "xyes" ; then - DESIRED_FLAGS="-Wall -W -Wextra -pedantic -pipe -Wformat -Wold-style-definition -Wdeclaration-after-statement -Wfloat-equal -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-noreturn -Wshadow -Wendif-labels -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings -Winline -Wno-unused-parameter" - - if test "x$HAVE_NETLINK" = "xyes" ; then - # Test whether rtnetlink.h can be included when compiled with -std=c99 - # some distributions (e.g. archlinux) have broken headers that dont - # define __u64 with -std=c99 - AC_MSG_CHECKING([checking whether rtnetlink.h can be included with -std=c99]) - OLDCFLAGS="$CFLAGS" - CFLAGS="-std=c99" - AC_TRY_COMPILE([#include ], [], - use_stdc99=yes, use_stdc99=no) - - if test x"$use_stdc99" = xyes; then - DESIRED_FLAGS="-std=c99 $DESIRED_FLAGS" - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - fi - - CFLAGS="$OLDCFLAGS" - else - DESIRED_FLAGS="-std=c99 $DESIRED_FLAGS" - fi + # We use gnu99 instead of c99 because many have interpreted the standard + # in a way that int64_t isn't defined on non-64 bit platforms. + DESIRED_FLAGS="-std=gnu99 -Wall -W -Wextra -pedantic -pipe -Wformat -Wold-style-definition -Wdeclaration-after-statement -Wfloat-equal -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-noreturn -Wshadow -Wendif-labels -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings -Winline -Wno-unused-parameter" for flag in $DESIRED_FLAGS ; do AC_MSG_CHECKING([whether $CC accepts $flag]) -- cgit From f61be8b654d33f3ab1b693c7e3a5d790617fbf6e Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 12 Jan 2006 16:04:21 +0000 Subject: If the card couldn't do duplex when required we would incorrectly return success from this function with a closed fd. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@451 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/oss-util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/polyp/oss-util.c b/polyp/oss-util.c index 20a2965a..ae6772fd 100644 --- a/polyp/oss-util.c +++ b/polyp/oss-util.c @@ -57,7 +57,7 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { if (*tcaps & DSP_CAP_DUPLEX) return fd; - close(fd); + goto fail; } if ((fd = open(device, (*mode = O_WRONLY)|O_NDELAY)) < 0) { @@ -87,7 +87,7 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { fail: if (fd >= 0) close(fd); - return fd; + return -1; } int pa_oss_auto_format(int fd, pa_sample_spec *ss) { -- cgit From fc93e4b3a722833ca6c1ad8a3c9af0b95b954000 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 12 Jan 2006 16:08:14 +0000 Subject: Used 0 as an invalid fd. Changed to -1. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@452 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-oss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polyp/module-oss.c b/polyp/module-oss.c index 7c331893..d060b489 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -347,7 +347,7 @@ int pa__init(pa_core *c, pa_module*m) { assert(u->source || u->sink); - u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : 0); + u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : -1); assert(u->io); pa_iochannel_set_callback(u->io, io_callback, u); u->fd = fd; -- cgit From 289c914b470537234c1de498cf195323826d7984 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 12 Jan 2006 16:09:58 +0000 Subject: Some drivers (via82xx) doesn't start recording until we read something. This is ugly, but unfortunately required. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@453 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-oss.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/polyp/module-oss.c b/polyp/module-oss.c index d060b489..12cedf19 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -368,6 +368,15 @@ int pa__init(pa_core *c, pa_module*m) { pa_modargs_free(ma); + /* + * Some crappy drivers do not start the recording until we read something. + * Without this snippet, poll will never register the fd as ready. + */ + if (u->source) { + char buf[u->sample_size]; + read(u->fd, buf, u->sample_size); + } + return 0; fail: -- cgit From cb2a7ed02840c076f8b53023658920ea8d12d849 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 12 Jan 2006 16:11:54 +0000 Subject: Some crappy hardware generate noise on the output when reading input. To avoid triggering this needlesly we tweak the algorithm a bit to avoid reading when nothing is connected to the source. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@454 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-oss.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/polyp/module-oss.c b/polyp/module-oss.c index 12cedf19..06679a97 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -161,7 +161,7 @@ static void do_read(struct userdata *u) { int loop = 0; assert(u); - if (!u->source || !pa_iochannel_is_readable(u->io)) + if (!u->source || !pa_iochannel_is_readable(u->io) || !pa_idxset_size(u->source->outputs)) return; update_usage(u); @@ -209,6 +209,12 @@ static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { do_read(u); } +static void source_notify_cb(pa_source *s) { + struct userdata *u = s->userdata; + assert(u); + do_read(u); +} + static pa_usec_t sink_get_latency_cb(pa_sink *s) { pa_usec_t r = 0; int arg; @@ -329,6 +335,7 @@ int pa__init(pa_core *c, pa_module*m) { u->source = pa_source_new(c, PA_TYPEID_OSS, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); assert(u->source); u->source->userdata = u; + u->source->notify = source_notify_cb; u->source->get_latency = source_get_latency_cb; pa_source_set_owner(u->source, m); u->source->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); -- cgit From 262c60fcaaa8c0edb6515d2f57bbe41af360ffef Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 12 Jan 2006 17:12:44 +0000 Subject: Under win32 we freed the wrong pointer causing a segmentation fault. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@455 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/util.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/polyp/util.c b/polyp/util.c index f9098704..4b6edb97 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -965,19 +965,19 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env FILE *f; char *lfn; - lfn = pa_sprintf_malloc("%s/%s", h, local); + fn = lfn = pa_sprintf_malloc("%s/%s", h, local); #ifdef OS_IS_WIN32 if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) return NULL; - lfn = buf; + fn = buf; #endif - f = fopen(lfn, "r"); + f = fopen(fn, "r"); if (f || errno != ENOENT) { if (result) - *result = pa_xstrdup(lfn); + *result = pa_xstrdup(fn); pa_xfree(lfn); return f; } -- cgit From 719c3773d4314beb9dcd406d780d8df5855a2946 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 16 Jan 2006 13:35:25 +0000 Subject: We need a logical, not an arithmetic shift here. So use unsigned types when doing the shifting. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@456 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/endianmacros.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/polyp/endianmacros.h b/polyp/endianmacros.h index 00b992db..d07652fb 100644 --- a/polyp/endianmacros.h +++ b/polyp/endianmacros.h @@ -28,9 +28,9 @@ #include #endif -#define INT16_SWAP(x) ((int16_t)(((int16_t) x >> 8) | ((int16_t) x << 8))) +#define INT16_SWAP(x) ((int16_t)(((uint16_t) x >> 8) | ((uint16_t) x << 8))) #define UINT16_SWAP(x) ((uint16_t)(((uint16_t) x >> 8) | ((uint16_t) x << 8))) -#define INT32_SWAP(x) ((int32_t)(((int32_t) x >> 24) | ((int32_t) x << 24) | (((int32_t) x & 0xFF00) << 16) | (((int32_t) x) >> 16) & 0xFF00)) +#define INT32_SWAP(x) ((int32_t)(((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 16) | (((uint32_t) x) >> 16) & 0xFF00)) #define UINT32_SWAP(x) ((uint32_t)(((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 16) | ((((uint32_t) x) >> 16) & 0xFF00))) #ifdef WORDS_BIGENDIAN -- cgit From 0ca9a0ea09a8518c9e6b541812a76fa7abac15f1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 19 Jan 2006 10:24:49 +0000 Subject: Ugly hack to get around Solaris particularly brain dead sound system. The system has a buffer size of 0.5 MB which cannot be changed. We emulate a smaller buffer through some SIGPOLL trickery. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@457 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-solaris.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/polyp/module-solaris.c b/polyp/module-solaris.c index c8ad7cf1..984a5f66 100644 --- a/polyp/module-solaris.c +++ b/polyp/module-solaris.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -48,6 +49,7 @@ #include "modargs.h" #include "xmalloc.h" #include "log.h" +#include "mainloop-signal.h" #include "module-solaris-symdef.h" PA_MODULE_AUTHOR("Pierre Ossman") @@ -62,10 +64,12 @@ struct userdata { pa_source *source; pa_iochannel *io; pa_core *core; + pa_signal_event *sig; pa_memchunk memchunk, silence; uint32_t sample_size; + uint32_t buffer_size; unsigned int written_bytes, read_bytes; int fd; @@ -99,7 +103,10 @@ static void update_usage(struct userdata *u) { } static void do_write(struct userdata *u) { + audio_info_t info; + int err; pa_memchunk *memchunk; + size_t len; ssize_t r; assert(u); @@ -109,17 +116,40 @@ static void do_write(struct userdata *u) { update_usage(u); + err = ioctl(u->fd, AUDIO_GETINFO, &info); + assert(err >= 0); + + /* + * Since we cannot modify the size of the output buffer we fake it + * by not filling it more than u->buffer_size. + */ + len = u->buffer_size; + len -= u->written_bytes - (info.play.samples * u->sample_size); + + /* + * Do not fill more than half the buffer in one chunk since we only + * get notifications upon completion of entire chunks. + */ + if (len > (u->buffer_size / 2)) + len = u->buffer_size / 2; + + if (len < u->sample_size) + return; + memchunk = &u->memchunk; if (!memchunk->length) - if (pa_sink_render(u->sink, CHUNK_SIZE, memchunk) < 0) + if (pa_sink_render(u->sink, len, memchunk) < 0) memchunk = &u->silence; assert(memchunk->memblock); assert(memchunk->memblock->data); assert(memchunk->length); + + if (memchunk->length < len) + len = memchunk->length; - if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { + if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, len)) < 0) { pa_log(__FILE__": write() failed: %s\n", strerror(errno)); return; } @@ -137,6 +167,14 @@ static void do_write(struct userdata *u) { } u->written_bytes += r; + + /* + * Write 0 bytes which will generate a SIGPOLL when "played". + */ + if (write(u->fd, NULL, 0) < 0) { + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + return; + } } static void do_read(struct userdata *u) { @@ -179,6 +217,12 @@ static void io_callback(pa_iochannel *io, void*userdata) { do_read(u); } +void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata) { + struct userdata *u = userdata; + assert(u); + do_write(u); +} + static pa_usec_t sink_get_latency_cb(pa_sink *s) { pa_usec_t r = 0; audio_info_t info; @@ -326,7 +370,7 @@ int pa__init(pa_core *c, pa_module*m) { mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); - buffer_size = -1; + buffer_size = 16384; if (pa_modargs_get_value_s32(ma, "buffer_size", &buffer_size) < 0) { pa_log(__FILE__": failed to parse buffer size argument\n"); goto fail; @@ -383,6 +427,7 @@ int pa__init(pa_core *c, pa_module*m) { u->memchunk.memblock = NULL; u->memchunk.length = 0; u->sample_size = pa_frame_size(&ss); + u->buffer_size = buffer_size; u->silence.memblock = pa_memblock_new(u->silence.length = CHUNK_SIZE, u->core->memblock_stat); assert(u->silence.memblock); @@ -395,6 +440,10 @@ int pa__init(pa_core *c, pa_module*m) { u->module = m; m->userdata = u; + u->sig = pa_signal_new(SIGPOLL, sig_callback, u); + assert(u->sig); + ioctl(u->fd, I_SETSIG, S_MSG); + pa_modargs_free(ma); return 0; @@ -415,6 +464,9 @@ void pa__done(pa_core *c, pa_module*m) { if (!(u = m->userdata)) return; + + ioctl(u->fd, I_SETSIG, 0); + pa_signal_free(u->sig); if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); -- cgit From 60dbf8b82d694bba5a4ebbe651e504cb12df927b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 19 Jan 2006 10:26:06 +0000 Subject: Open the device in non-blocking mode. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@458 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-solaris.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polyp/module-solaris.c b/polyp/module-solaris.c index 984a5f66..01a151d6 100644 --- a/polyp/module-solaris.c +++ b/polyp/module-solaris.c @@ -382,7 +382,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - if ((fd = open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), mode)) < 0) + if ((fd = open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), mode | O_NONBLOCK)) < 0) goto fail; pa_log_info(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); -- cgit From 30bb5ceaeea2c612c10245780cf1de80122ac06b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 20 Jan 2006 10:16:37 +0000 Subject: Fix so that peer name can be determined on Windows. We do not support console on Windows at this time so we do not have to worry about that right now. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@459 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/socket-util.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/polyp/socket-util.c b/polyp/socket-util.c index 381502b5..032a3c91 100644 --- a/polyp/socket-util.c +++ b/polyp/socket-util.c @@ -69,17 +69,22 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) { assert(c && l && fd >= 0); +#ifndef OS_IS_WIN32 if (fstat(fd, &st) < 0) { snprintf(c, l, "Invalid client fd"); return; } +#endif #ifndef OS_IS_WIN32 if (S_ISSOCK(st.st_mode)) { +#endif union { struct sockaddr sa; struct sockaddr_in in; +#ifdef HAVE_SYS_UN_H struct sockaddr_un un; +#endif } sa; socklen_t sa_len = sizeof(sa); @@ -95,12 +100,15 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) { ip & 0xFF, ntohs(sa.in.sin_port)); return; +#ifdef HAVE_SYS_UN_H } else if (sa.sa.sa_family == AF_UNIX) { snprintf(c, l, "UNIX socket client"); return; +#endif } } +#ifndef OS_IS_WIN32 snprintf(c, l, "Unknown network client"); return; } else if (S_ISCHR(st.st_mode) && (fd == 0 || fd == 1)) { -- cgit From 104797b5a0c869a668690d13737056646be198bc Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 25 Jan 2006 17:25:28 +0000 Subject: Use AC_SEARCH_LIBS instead of AC_CHECK_LIBS since it is a lot smarter and doesn't add unnecessary libs. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@460 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index bfe6ecd1..1700c863 100644 --- a/configure.ac +++ b/configure.ac @@ -185,13 +185,13 @@ AC_CHECK_DEFINE([INADDR_NONE], [netinet/in.h], [], #### Check for libs #### # ISO -AC_CHECK_LIB([m], [pow]) +AC_SEARCH_LIBS([pow], [m]) # POSIX -AC_CHECK_LIB([rt], [sched_setscheduler]) +AC_SEARCH_LIBS([sched_setscheduler], [rt]) # BSD -AC_CHECK_LIB([socket], [connect]) +AC_SEARCH_LIBS([connect], [socket]) # Non-standard @@ -258,7 +258,7 @@ AC_ARG_WITH( AC_HELP_STRING([--without-caps],[Omit support for POSIX capabilities.])) if test "x${with_caps}" != "xno"; then - AC_CHECK_LIB(cap, cap_init, [CAP_LIBS='-lcap'], [CAP_LIBS='']) + AC_SEARCH_LIBS([cap_init], [cap], [CAP_LIBS='-lcap'], [CAP_LIBS='']) AC_CHECK_HEADERS([sys/capability.h]) fi AC_SUBST(CAP_LIBS) -- cgit From 917d8765c62779dc74b9e49dab4f12d9590859c5 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 25 Jan 2006 17:27:10 +0000 Subject: We get the -lcap through LIBS, so no need for CAP_LIBS. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@461 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 3 +-- polyp/Makefile.am | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 1700c863..f2de1653 100644 --- a/configure.ac +++ b/configure.ac @@ -258,10 +258,9 @@ AC_ARG_WITH( AC_HELP_STRING([--without-caps],[Omit support for POSIX capabilities.])) if test "x${with_caps}" != "xno"; then - AC_SEARCH_LIBS([cap_init], [cap], [CAP_LIBS='-lcap'], [CAP_LIBS='']) + AC_SEARCH_LIBS([cap_init], [cap]) AC_CHECK_HEADERS([sys/capability.h]) fi -AC_SUBST(CAP_LIBS) #### pkg-config #### diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 8712782f..3a0d2f21 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -104,7 +104,7 @@ polypaudio_SOURCES = \ polypaudio_CFLAGS = $(AM_CFLAGS) polypaudio_CPPFLAGS = $(AM_CPPFLAGS) polypaudio_LDADD = $(AM_LDADD) libpolypcore.la $(LIBLTDL) \ - $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) + $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) polypaudio_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -dlopen force $(foreach f,$(PREOPEN_LIBS),-dlopen $(f)) if PREOPEN_MODS -- cgit From 759721cbbc265cc6ce4c5dd9141e00ca67c8fe2d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 27 Jan 2006 14:52:17 +0000 Subject: Remove the version number from the module directory. Makes life easier for any external projects that need to use that directory. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@462 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 3a0d2f21..0181ae6a 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -25,7 +25,7 @@ polypincludedir=$(includedir)/polyp polypconfdir=$(sysconfdir)/polypaudio -modlibdir=$(libdir)/polypaudio-@PA_MAJORMINOR@ +modlibdir=$(libdir)/polypaudio ################################### # Defines # -- cgit From dd10c982414dfa8fbb9aeeeae61c68e4a6f081cc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 27 Jan 2006 16:25:31 +0000 Subject: Mega patch: * implement inner loops using liboil * drop "typeid" stuff * add support for channel maps * add support for seperate volumes per channel * add support for hardware mixer settings (only module-oss implements this for now) * fix a lot of types for _t suffix git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@463 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 5 + polyp/Makefile.am | 26 ++- polyp/alsa-util.c | 2 +- polyp/alsa-util.h | 2 +- polyp/autoload.c | 8 +- polyp/autoload.h | 10 +- polyp/channelmap.c | 202 ++++++++++++++++ polyp/channelmap.h | 94 ++++++++ polyp/cli-command.c | 21 +- polyp/cli-text.c | 129 ++++++---- polyp/cli.c | 3 +- polyp/client.c | 6 +- polyp/client.h | 6 +- polyp/core.h | 2 +- polyp/daemon-conf.c | 2 +- polyp/daemon-conf.h | 8 +- polyp/dllmain.c | 2 +- polyp/glib-mainloop.c | 12 +- polyp/glib12-mainloop.c | 10 +- polyp/inet_ntop.c | 2 +- polyp/iochannel.c | 4 +- polyp/log.c | 26 +-- polyp/log.h | 12 +- polyp/main.c | 3 + polyp/mainloop-api.h | 6 +- polyp/mainloop-signal.c | 2 +- polyp/mainloop-test.c | 2 +- polyp/mainloop.c | 14 +- polyp/memblock.h | 6 +- polyp/module-alsa-sink.c | 8 +- polyp/module-alsa-source.c | 6 +- polyp/module-combine.c | 6 +- polyp/module-esound-sink.c | 6 +- polyp/module-lirc.c | 39 +++- polyp/module-match.c | 6 +- polyp/module-mmkbd-evdev.c | 25 +- polyp/module-null-sink.c | 4 +- polyp/module-oss-mmap.c | 8 +- polyp/module-oss.c | 54 ++++- polyp/module-pipe-sink.c | 4 +- polyp/module-pipe-source.c | 4 +- polyp/module-protocol-stub.c | 2 +- polyp/module-sine.c | 4 +- polyp/module-solaris.c | 2 +- polyp/module-tunnel.c | 6 +- polyp/module-waveout.c | 2 +- polyp/module-x11-bell.c | 3 +- polyp/namereg.c | 8 +- polyp/namereg.h | 8 +- polyp/native-common.h | 5 + polyp/pacat-simple.c | 2 +- polyp/pacat.c | 13 +- polyp/pactl.c | 77 +++--- polyp/paplay.c | 8 +- polyp/parec-simple.c | 2 +- polyp/parseaddr.h | 4 +- polyp/play-memchunk.c | 26 ++- polyp/play-memchunk.h | 8 +- polyp/poll.c | 2 +- polyp/poll.h | 2 +- polyp/polyplib-context.c | 4 +- polyp/polyplib-context.h | 2 +- polyp/polyplib-def.h | 14 +- polyp/polyplib-internal.h | 15 +- polyp/polyplib-introspect.c | 28 ++- polyp/polyplib-introspect.h | 46 ++-- polyp/polyplib-operation.c | 4 +- polyp/polyplib-operation.h | 2 +- polyp/polyplib-simple.c | 13 +- polyp/polyplib-simple.h | 3 +- polyp/polyplib-stream.c | 39 +++- polyp/polyplib-stream.h | 19 +- polyp/polyplib-subscribe.c | 6 +- polyp/polyplib-subscribe.h | 4 +- polyp/protocol-esound.c | 40 ++-- polyp/protocol-native.c | 108 ++++++--- polyp/protocol-simple.c | 8 +- polyp/resampler.c | 546 +++++++++++++++++++++++++++++-------------- polyp/resampler.h | 18 +- polyp/sample-util.c | 354 ++++++++++++++++------------ polyp/sample-util.h | 23 +- polyp/sample.c | 83 ++----- polyp/sample.h | 49 +--- polyp/scache.c | 21 +- polyp/scache.h | 7 +- polyp/sconv-s16be.c | 8 + polyp/sconv-s16be.h | 4 +- polyp/sconv-s16le.c | 64 +++-- polyp/sconv-s16le.h | 4 +- polyp/sconv.c | 155 ++++-------- polyp/sconv.h | 8 +- polyp/sink-input.c | 152 +++++++++--- polyp/sink-input.h | 37 +-- polyp/sink.c | 226 ++++++++++++------ polyp/sink.h | 41 +++- polyp/socket-client.c | 4 +- polyp/socket-server.c | 2 +- polyp/sound-file-stream.c | 11 +- polyp/sound-file-stream.h | 2 +- polyp/source-output.c | 74 ++++-- polyp/source-output.h | 26 ++- polyp/source.c | 65 ++++-- polyp/source.h | 27 ++- polyp/subscribe.c | 10 +- polyp/subscribe.h | 4 +- polyp/tagstruct.c | 91 +++++++- polyp/tagstruct.h | 6 + polyp/typeid.c | 33 --- polyp/typeid.h | 46 ---- polyp/voltest.c | 17 +- polyp/volume.c | 176 ++++++++++++++ polyp/volume.h | 107 +++++++++ polyp/x11prop.c | 2 +- polyp/x11wrap.c | 4 +- 114 files changed, 2549 insertions(+), 1294 deletions(-) create mode 100644 polyp/channelmap.c create mode 100644 polyp/channelmap.h delete mode 100644 polyp/typeid.c delete mode 100644 polyp/typeid.h create mode 100644 polyp/volume.c create mode 100644 polyp/volume.h diff --git a/configure.ac b/configure.ac index f2de1653..710f205b 100644 --- a/configure.ac +++ b/configure.ac @@ -330,6 +330,11 @@ AC_SUBST(HOWL_LIBS) AC_SUBST(HAVE_HOWL) AM_CONDITIONAL([HAVE_HOWL], [test "x$HAVE_HOWL" = x1]) + +PKG_CHECK_MODULES(LIBOIL, [ liboil-0.3 >= 0.3.0 ]) +AC_SUBST(LIBOIL_CFLAGS) +AC_SUBST(LIBOIL_LIBS) + #### Async DNS support (optional) #### PKG_CHECK_MODULES(LIBASYNCNS, [ libasyncns >= 0.1 ], HAVE_LIBASYNCNS=1, HAVE_LIBASYNCNS=0) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 0181ae6a..ad9952a5 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -47,6 +47,7 @@ AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS AM_CFLAGS += $(LTDLINCL) AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" +#AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\" AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\" AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(POLYPAUDIO_BINARY)\" @@ -101,10 +102,10 @@ polypaudio_SOURCES = \ main.c \ pid.c pid.h -polypaudio_CFLAGS = $(AM_CFLAGS) -polypaudio_CPPFLAGS = $(AM_CPPFLAGS) +polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) +polypaudio_CPPFLAGS = $(AM_CPPFLAGS) polypaudio_LDADD = $(AM_LDADD) libpolypcore.la $(LIBLTDL) \ - $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) + $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) $(LIBOIL_LIBS) polypaudio_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -dlopen force $(foreach f,$(PREOPEN_LIBS),-dlopen $(f)) if PREOPEN_MODS @@ -219,7 +220,7 @@ strlist_test_CFLAGS = $(AM_CFLAGS) strlist_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) strlist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -voltest_SOURCES = voltest.c sample.c +voltest_SOURCES = voltest.c sample.c volume.c volume.h sample.h voltest_CFLAGS = $(AM_CFLAGS) voltest_LDADD = $(AM_LDADD) voltest_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -265,8 +266,7 @@ polypinclude_HEADERS = \ polyplib-stream.h \ polyplib-subscribe.h \ polyplib-version.h \ - sample.h \ - typeid.h + sample.h if HAVE_HOWL polypinclude_HEADERS += \ @@ -333,10 +333,11 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = \ strbuf.c strbuf.h \ strlist.c strlist.h \ tagstruct.c tagstruct.h \ - typeid.c typeid.h \ util.c util.h \ winsock.h \ - xmalloc.c xmalloc.h + xmalloc.c xmalloc.h \ + channelmap.c channelmap.h \ + volume.c volume.h if HAVE_X11 libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ @@ -475,14 +476,15 @@ libpolypcore_la_SOURCES = \ strbuf.c strbuf.h \ subscribe.c subscripe.h \ tokenizer.c tokenizer.h \ - typeid.c typeid.h \ util.c util.h \ winsock.h \ - xmalloc.c xmalloc.h + xmalloc.c xmalloc.h \ + volume.c volume.h \ + channelmap.c channelmap.h -libpolypcore_la_CPPFLAGS = $(AM_CPPFLAGS) +libpolypcore_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBOIL_CFLAGS) libpolypcore_la_LDFLAGS = -avoid-version -libpolypcore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) +libpolypcore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) $(LIBOIL_LIBS) ################################### # Plug-in support libraries # diff --git a/polyp/alsa-util.c b/polyp/alsa-util.c index 73f3be7d..cc65b8de 100644 --- a/polyp/alsa-util.c +++ b/polyp/alsa-util.c @@ -85,7 +85,7 @@ finish: * *io_events. Store the length of that array in *n_io_events. Use the * specified callback function and userdata. The array has to be freed * with pa_free_io_events(). */ -int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api* m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags events, void *userdata), void *userdata) { +int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api* m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata) { unsigned i; struct pollfd *pfds, *ppfd; pa_io_event **ios; diff --git a/polyp/alsa-util.h b/polyp/alsa-util.h index 787519f7..d180db3e 100644 --- a/polyp/alsa-util.h +++ b/polyp/alsa-util.h @@ -29,7 +29,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size); -int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api *m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags events, void *userdata), void *userdata); +int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api *m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata); void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_sources, unsigned n_io_sources); #endif diff --git a/polyp/autoload.c b/polyp/autoload.c index 7e05c168..ff2916cb 100644 --- a/polyp/autoload.c +++ b/polyp/autoload.c @@ -81,7 +81,7 @@ static pa_autoload_entry* entry_new(pa_core *c, const char *name) { return e; } -int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type type, const char*module, const char *argument, uint32_t *idx) { +int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const char*module, const char *argument, uint32_t *idx) { pa_autoload_entry *e = NULL; assert(c && name && module && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); @@ -98,7 +98,7 @@ int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type type, const cha return 0; } -int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type type) { +int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type_t type) { pa_autoload_entry *e; assert(c && name && type); @@ -120,7 +120,7 @@ int pa_autoload_remove_by_index(pa_core *c, uint32_t idx) { return 0; } -void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type type) { +void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type_t type) { pa_autoload_entry *e; pa_module *m; assert(c && name); @@ -159,7 +159,7 @@ void pa_autoload_free(pa_core *c) { } } -const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type type) { +const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type_t type) { pa_autoload_entry *e; assert(c && name); diff --git a/polyp/autoload.h b/polyp/autoload.h index 622a854e..7350c16a 100644 --- a/polyp/autoload.h +++ b/polyp/autoload.h @@ -34,7 +34,7 @@ typedef struct pa_autoload_entry { pa_core *core; uint32_t index; char *name; - pa_namereg_type type; /* Type of the autoload entry */ + pa_namereg_type_t type; /* Type of the autoload entry */ int in_action; /* Currently loaded */ char *module, *argument; } pa_autoload_entry; @@ -42,17 +42,17 @@ typedef struct pa_autoload_entry { /* Add a new autoload entry of the given time, with the speicified * sink/source name, module name and argument. Return the entry's * index in *index */ -int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type type, const char*module, const char *argument, uint32_t *idx); +int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const char*module, const char *argument, uint32_t *idx); /* Free all autoload entries */ void pa_autoload_free(pa_core *c); -int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type type); +int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type_t type); int pa_autoload_remove_by_index(pa_core *c, uint32_t idx); /* Request an autoload entry by its name, effectively causing a module to be loaded */ -void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type type); +void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type_t type); -const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type type); +const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type_t type); const pa_autoload_entry* pa_autoload_get_by_index(pa_core *c, uint32_t idx); #endif diff --git a/polyp/channelmap.c b/polyp/channelmap.c new file mode 100644 index 00000000..7bfd21e6 --- /dev/null +++ b/polyp/channelmap.c @@ -0,0 +1,202 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "channelmap.h" + +pa_channel_map* pa_channel_map_init(pa_channel_map *m) { + unsigned c; + assert(m); + + m->channels = 0; + + for (c = 0; c < PA_CHANNELS_MAX; c++) + m->map[c] = PA_CHANNEL_POSITION_INVALID; + + return m; +} + +pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m) { + assert(m); + + pa_channel_map_init(m); + + m->channels = 1; + m->map[0] = PA_CHANNEL_POSITION_MONO; + return m; +} + +pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m) { + assert(m); + + pa_channel_map_init(m); + + m->channels = 2; + m->map[0] = PA_CHANNEL_POSITION_LEFT; + m->map[1] = PA_CHANNEL_POSITION_RIGHT; + return m; +} + +pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels) { + assert(m); + assert(channels > 0); + assert(channels <= PA_CHANNELS_MAX); + + pa_channel_map_init(m); + + m->channels = channels; + + switch (channels) { + case 1: + m->map[0] = PA_CHANNEL_POSITION_MONO; + return m; + + case 8: + m->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; + m->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; + /* Fall through */ + + case 6: + m->map[5] = PA_CHANNEL_POSITION_LFE; + /* Fall through */ + + case 5: + m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; + /* Fall through */ + + case 4: + m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT; + m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; + /* Fall through */ + + case 2: + m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + return m; + + default: + return NULL; + } +} + +const char* pa_channel_position_to_string(pa_channel_position_t pos) { + + const char *const table[] = { + [PA_CHANNEL_POSITION_MONO] = "mono", + + [PA_CHANNEL_POSITION_FRONT_CENTER] = "front-center", + [PA_CHANNEL_POSITION_FRONT_LEFT] = "front-left", + [PA_CHANNEL_POSITION_FRONT_RIGHT] = "front-right", + + [PA_CHANNEL_POSITION_REAR_CENTER] = "rear-center", + [PA_CHANNEL_POSITION_REAR_LEFT] = "rear-left", + [PA_CHANNEL_POSITION_REAR_RIGHT] = "rear-right", + + [PA_CHANNEL_POSITION_LFE] = "lfe", + + [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = "front-left-of-center", + [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = "front-right-of-center", + + [PA_CHANNEL_POSITION_SIDE_LEFT] = "side-left", + [PA_CHANNEL_POSITION_SIDE_RIGHT] = "side-right", + + [PA_CHANNEL_POSITION_AUX1] = "aux1", + [PA_CHANNEL_POSITION_AUX2] = "aux2", + [PA_CHANNEL_POSITION_AUX3] = "aux3", + [PA_CHANNEL_POSITION_AUX4] = "aux4", + [PA_CHANNEL_POSITION_AUX5] = "aux5", + [PA_CHANNEL_POSITION_AUX6] = "aux6", + [PA_CHANNEL_POSITION_AUX7] = "aux7", + [PA_CHANNEL_POSITION_AUX8] = "aux8", + [PA_CHANNEL_POSITION_AUX9] = "aux9", + [PA_CHANNEL_POSITION_AUX10] = "aux10", + [PA_CHANNEL_POSITION_AUX11] = "aux11", + [PA_CHANNEL_POSITION_AUX12] = "aux12" + }; + + if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX) + return NULL; + + return table[pos]; +} + +int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) { + unsigned c; + + assert(a); + assert(b); + + if (a->channels != b->channels) + return 0; + + for (c = 0; c < a->channels; c++) + if (a->map[c] != b->map[c]) + return 0; + + return 1; +} + +char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) { + unsigned channel; + int first = 1; + char *e; + + assert(s); + assert(l > 0); + assert(map); + + *(e = s) = 0; + + for (channel = 0; channel < map->channels && l > 1; channel++) { + l -= snprintf(e, l, "%s%u:%s", + first ? "" : " ", + channel, + pa_channel_position_to_string(map->map[channel])); + + e = strchr(e, 0); + first = 0; + } + + return s; +} + +int pa_channel_map_valid(const pa_channel_map *map) { + unsigned c; + + assert(map); + + if (map->channels <= 0 || map->channels > PA_CHANNELS_MAX) + return 0; + + for (c = 0; c < map->channels; c++) + if (map->map[c] < 0 ||map->map[c] >= PA_CHANNEL_POSITION_MAX) + return 0; + + return 1; +} diff --git a/polyp/channelmap.h b/polyp/channelmap.h new file mode 100644 index 00000000..6466eecf --- /dev/null +++ b/polyp/channelmap.h @@ -0,0 +1,94 @@ +#ifndef foochannelmaphfoo +#define foochannelmaphfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/** \file + * Constants and routines for channel mapping handling */ + +PA_C_DECL_BEGIN + +typedef enum { + PA_CHANNEL_POSITION_INVALID = -1, + PA_CHANNEL_POSITION_MONO = 0, + + PA_CHANNEL_POSITION_LEFT, + PA_CHANNEL_POSITION_RIGHT, + + PA_CHANNEL_POSITION_FRONT_CENTER, + PA_CHANNEL_POSITION_FRONT_LEFT = PA_CHANNEL_POSITION_LEFT, + PA_CHANNEL_POSITION_FRONT_RIGHT = PA_CHANNEL_POSITION_RIGHT, + + PA_CHANNEL_POSITION_REAR_CENTER, + PA_CHANNEL_POSITION_REAR_LEFT, + PA_CHANNEL_POSITION_REAR_RIGHT, + + PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_SUBWOOFER = PA_CHANNEL_POSITION_LFE, + + PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, + PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, + + PA_CHANNEL_POSITION_SIDE_LEFT, + PA_CHANNEL_POSITION_SIDE_RIGHT, + + PA_CHANNEL_POSITION_AUX1, + PA_CHANNEL_POSITION_AUX2, + PA_CHANNEL_POSITION_AUX3, + PA_CHANNEL_POSITION_AUX4, + PA_CHANNEL_POSITION_AUX5, + PA_CHANNEL_POSITION_AUX6, + PA_CHANNEL_POSITION_AUX7, + PA_CHANNEL_POSITION_AUX8, + PA_CHANNEL_POSITION_AUX9, + PA_CHANNEL_POSITION_AUX10, + PA_CHANNEL_POSITION_AUX11, + PA_CHANNEL_POSITION_AUX12, + + PA_CHANNEL_POSITION_MAX +} pa_channel_position_t; + +typedef struct pa_channel_map { + uint8_t channels; + pa_channel_position_t map[PA_CHANNELS_MAX]; +} pa_channel_map; + +pa_channel_map* pa_channel_map_init(pa_channel_map *m); +pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m); +pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m); +pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels); + +const char* pa_channel_position_to_string(pa_channel_position_t pos); + +#define PA_CHANNEL_MAP_SNPRINT_MAX 64 +char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map); + +int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b); + +int pa_channel_map_valid(const pa_channel_map *map); + +PA_C_DECL_END + +#endif diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 63241a81..f6192bf8 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -311,6 +311,7 @@ static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *bu const char *n, *v; pa_sink *sink; uint32_t volume; + pa_cvolume cvolume; 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"); @@ -332,14 +333,16 @@ static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *bu return -1; } - pa_sink_set_volume(sink, (uint32_t) volume); + pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume); + pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &cvolume); return 0; } static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { const char *n, *v; pa_sink_input *si; - uint32_t volume; + pa_volume_t volume; + pa_cvolume cvolume; uint32_t idx; if (!(n = pa_tokenizer_get(t, 1))) { @@ -367,7 +370,8 @@ static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strb return -1; } - pa_sink_input_set_volume(si, (uint32_t) volume); + pa_cvolume_set(&cvolume, si->sample_spec.channels, volume); + pa_sink_input_set_volume(si, &cvolume); return 0; } @@ -497,7 +501,7 @@ static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *bu return -1; } - if (pa_scache_play_item(c, n, sink, PA_VOLUME_NORM) < 0) { + if (pa_scache_play_item(c, n, sink, NULL) < 0) { pa_strbuf_puts(buf, "Failed to play sample.\n"); return -1; } @@ -576,7 +580,7 @@ static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, } - return pa_play_file(sink, fname, PA_VOLUME_NORM); + return pa_play_file(sink, fname, NULL); } static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { @@ -663,9 +667,6 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G nl = 0; for (s = pa_idxset_first(c->sinks, &idx); s; s = pa_idxset_next(c->sinks, &idx)) { - if (s->volume == PA_VOLUME_NORM) - continue; - if (s->owner && s->owner->auto_unload) continue; @@ -673,8 +674,8 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G pa_strbuf_puts(buf, "\n"); nl = 1; } - - pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", s->name, s->volume); + + pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", s->name, pa_cvolume_avg(pa_sink_get_volume(s, PA_MIXER_HARDWARE))); } diff --git a/polyp/cli-text.c b/polyp/cli-text.c index a19bfc97..328aca4c 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -38,6 +38,7 @@ #include "scache.h" #include "autoload.h" #include "xmalloc.h" +#include "volume.h" char *pa_module_list_to_string(pa_core *c) { pa_strbuf *s; @@ -60,7 +61,6 @@ char *pa_client_list_to_string(pa_core *c) { pa_strbuf *s; pa_client *client; uint32_t idx = PA_IDXSET_INVALID; - char tid[5]; assert(c); s = pa_strbuf_new(); @@ -69,7 +69,7 @@ char *pa_client_list_to_string(pa_core *c) { pa_strbuf_printf(s, "%u client(s) logged in.\n", pa_idxset_size(c->clients)); for (client = pa_idxset_first(c->clients, &idx); client; client = pa_idxset_next(c->clients, &idx)) { - pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\ttype: <%s>\n", client->index, client->name, pa_typeid_to_string(client->typeid, tid, sizeof(tid))); + pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\tdriver: <%s>\n", client->index, client->name, client->driver); if (client->owner) pa_strbuf_printf(s, "\towner module: <%u>\n", client->owner->index); @@ -82,7 +82,6 @@ char *pa_sink_list_to_string(pa_core *c) { pa_strbuf *s; pa_sink *sink; uint32_t idx = PA_IDXSET_INVALID; - char tid[5]; assert(c); s = pa_strbuf_new(); @@ -91,20 +90,26 @@ char *pa_sink_list_to_string(pa_core *c) { pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_size(c->sinks)); for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) { - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; - pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec); - assert(sink->monitor_source); + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + pa_strbuf_printf( s, - " %c index: %u\n\tname: <%s>\n\ttype: <%s>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", + " %c index: %u\n" + "\tname: <%s>\n" + "\tdriver: <%s>\n" + "\tvolume: <%s>\n" + "\tlatency: <%0.0f usec>\n" + "\tmonitor_source: <%u>\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n", c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ', sink->index, sink->name, - pa_typeid_to_string(sink->typeid, tid, sizeof(tid)), - (unsigned) sink->volume, - pa_volume_to_dB(sink->volume), + sink->driver, + pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, PA_MIXER_HARDWARE)), (double) pa_sink_get_latency(sink), sink->monitor_source->index, - ss); + pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map)); if (sink->owner) pa_strbuf_printf(s, "\towner module: <%u>\n", sink->owner->index); @@ -119,7 +124,6 @@ char *pa_source_list_to_string(pa_core *c) { pa_strbuf *s; pa_source *source; uint32_t idx = PA_IDXSET_INVALID; - char tid[5]; assert(c); s = pa_strbuf_new(); @@ -128,15 +132,24 @@ char *pa_source_list_to_string(pa_core *c) { pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_size(c->sources)); for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) { - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; - pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec); - pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\ttype: <%s>\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n", - c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ', - source->index, - source->name, - pa_typeid_to_string(source->typeid, tid, sizeof(tid)), - (double) pa_source_get_latency(source), - ss); + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + + + pa_strbuf_printf( + s, + " %c index: %u\n" + "\tname: <%s>\n" + "\tdriver: <%s>\n" + "\tlatency: <%0.0f usec>\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n", + c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ', + source->index, + source->name, + source->driver, + (double) pa_source_get_latency(source), + pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map)); if (source->monitor_of) pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index); @@ -154,7 +167,6 @@ char *pa_source_output_list_to_string(pa_core *c) { pa_strbuf *s; pa_source_output *o; uint32_t idx = PA_IDXSET_INVALID; - char tid[5]; static const char* const state_table[] = { "RUNNING", "CORKED", @@ -168,23 +180,28 @@ char *pa_source_output_list_to_string(pa_core *c) { pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_size(c->source_outputs)); for (o = pa_idxset_first(c->source_outputs, &idx); o; o = pa_idxset_next(c->source_outputs, &idx)) { - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; - const char *rm; - pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec); + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + assert(o->source); - - if (!(rm = pa_resample_method_to_string(pa_source_output_get_resample_method(o)))) - rm = "invalid"; pa_strbuf_printf( - s, " index: %u\n\tname: '%s'\n\ttype: <%s>\n\tstate: %s\n\tsource: <%u> '%s'\n\tsample_spec: <%s>\n\tresample method: %s\n", + s, + " index: %u\n" + "\tname: '%s'\n" + "\tdriver: <%s>\n" + "\tstate: %s\n" + "\tsource: <%u> '%s'\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n" + "\tresample method: %s\n", o->index, o->name, - pa_typeid_to_string(o->typeid, tid, sizeof(tid)), + o->driver, state_table[o->state], o->source->index, o->source->name, - ss, - rm); + pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map), + pa_resample_method_to_string(pa_source_output_get_resample_method(o))); if (o->owner) pa_strbuf_printf(s, "\towner module: <%u>\n", o->owner->index); if (o->client) @@ -198,7 +215,6 @@ char *pa_sink_input_list_to_string(pa_core *c) { pa_strbuf *s; pa_sink_input *i; uint32_t idx = PA_IDXSET_INVALID; - char tid[5]; static const char* const state_table[] = { "RUNNING", "CORKED", @@ -212,26 +228,32 @@ char *pa_sink_input_list_to_string(pa_core *c) { pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_size(c->sink_inputs)); for (i = pa_idxset_first(c->sink_inputs, &idx); i; i = pa_idxset_next(c->sink_inputs, &idx)) { - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; - const char *rm; - - if (!(rm = pa_resample_method_to_string(pa_sink_input_get_resample_method(i)))) - rm = "invalid"; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec); assert(i->sink); + pa_strbuf_printf( - s, " index: %u\n\tname: <%s>\n\ttype: <%s>\n\tstate: %s\n\tsink: <%u> '%s'\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n\tresample method: %s\n", + s, + " index: %u\n" + "\tname: <%s>\n" + "\tdriver: <%s>\n" + "\tstate: %s\n" + "\tsink: <%u> '%s'\n" + "\tvolume: <%s>\n" + "\tlatency: <%0.0f usec>\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n" + "\tresample method: %s\n", i->index, i->name, - pa_typeid_to_string(i->typeid, tid, sizeof(tid)), + i->driver, state_table[i->state], i->sink->index, i->sink->name, - (unsigned) i->volume, - pa_volume_to_dB(i->volume), + pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)), (double) pa_sink_input_get_latency(i), - ss, - rm); + pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), + pa_resample_method_to_string(pa_sink_input_get_resample_method(i))); if (i->owner) pa_strbuf_printf(s, "\towner module: <%u>\n", i->owner->index); @@ -257,21 +279,32 @@ char *pa_scache_list_to_string(pa_core *c) { for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) { double l = 0; - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = "n/a"; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = "n/a", cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; if (e->memchunk.memblock) { pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec); + pa_channel_map_snprint(cm, sizeof(cm), &e->channel_map); l = (double) e->memchunk.length / pa_bytes_per_second(&e->sample_spec); } pa_strbuf_printf( - s, " name: <%s>\n\tindex: <%u>\n\tsample_spec: <%s>\n\tlength: <%u>\n\tduration: <%0.1fs>\n\tvolume: <0x%04x>\n\tlazy: %s\n\tfilename: %s\n", + s, + " name: <%s>\n" + "\tindex: <%u>\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n" + "\tlength: <%u>\n" + "\tduration: <%0.1fs>\n" + "\tvolume: <%s>\n" + "\tlazy: %s\n" + "\tfilename: %s\n", e->name, e->index, ss, + cm, e->memchunk.memblock ? e->memchunk.length : 0, l, - e->volume, + pa_cvolume_snprint(cv, sizeof(cv), &e->volume), e->lazy ? "yes" : "no", e->filename ? e->filename : "n/a"); } diff --git a/polyp/cli.c b/polyp/cli.c index 7b1022c1..bc0c285d 100644 --- a/polyp/cli.c +++ b/polyp/cli.c @@ -45,7 +45,6 @@ #include "log.h" #define PROMPT ">>> " -#define PA_TYPEID_CLI PA_TYPEID_MAKE('C', 'L', 'I', '_') struct pa_cli { pa_core *core; @@ -76,7 +75,7 @@ pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m) { c->eof_callback = NULL; pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); - c->client = pa_client_new(core, PA_TYPEID_CLI, cname); + c->client = pa_client_new(core, __FILE__, cname); assert(c->client); c->client->kill = client_kill; c->client->userdata = c; diff --git a/polyp/client.c b/polyp/client.c index 1938a4e0..3c2084bf 100644 --- a/polyp/client.c +++ b/polyp/client.c @@ -33,16 +33,16 @@ #include "subscribe.h" #include "log.h" -pa_client *pa_client_new(pa_core *core, pa_typeid_t typeid, const char *name) { +pa_client *pa_client_new(pa_core *core, const char *name, const char *driver) { pa_client *c; int r; assert(core); c = pa_xmalloc(sizeof(pa_client)); c->name = pa_xstrdup(name); + c->driver = pa_xstrdup(driver); c->owner = NULL; c->core = core; - c->typeid = typeid; c->kill = NULL; c->userdata = NULL; @@ -68,8 +68,8 @@ void pa_client_free(pa_client *c) { pa_log_info(__FILE__": freed %u \"%s\"\n", c->index, c->name); pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index); pa_xfree(c->name); + pa_xfree(c->driver); pa_xfree(c); - } void pa_client_kill(pa_client *c) { diff --git a/polyp/client.h b/polyp/client.h index 198dbbf6..92430338 100644 --- a/polyp/client.h +++ b/polyp/client.h @@ -24,7 +24,6 @@ #include "core.h" #include "module.h" -#include "typeid.h" /* Every connection to the server should have a pa_client * attached. That way the user may generate a listing of all connected @@ -34,17 +33,16 @@ typedef struct pa_client pa_client; struct pa_client { uint32_t index; - pa_typeid_t typeid; pa_module *owner; - char *name; + char *name, *driver; pa_core *core; void (*kill)(pa_client *c); void *userdata; }; -pa_client *pa_client_new(pa_core *c, pa_typeid_t typeid, const char *name); +pa_client *pa_client_new(pa_core *c, const char *name, const char *driver); /* This function should be called only by the code that created the client */ void pa_client_free(pa_client *c); diff --git a/polyp/core.h b/polyp/core.h index 704246a9..9241fcd8 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -70,7 +70,7 @@ struct pa_core { pa_time_event *scache_auto_unload_event; - pa_resample_method resample_method; + pa_resample_method_t resample_method; }; pa_core* pa_core_new(pa_mainloop_api *m); diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c index 4ad78bab..103cf46a 100644 --- a/polyp/daemon-conf.c +++ b/polyp/daemon-conf.c @@ -126,7 +126,7 @@ int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string) { if (u >= PA_LOG_LEVEL_MAX) return -1; - c->log_level = (pa_log_level) u; + c->log_level = (pa_log_level_t) u; } else if (pa_startswith(string, "debug")) c->log_level = PA_LOG_DEBUG; else if (pa_startswith(string, "info")) diff --git a/polyp/daemon-conf.h b/polyp/daemon-conf.h index 4eb61365..cebc0bd6 100644 --- a/polyp/daemon-conf.h +++ b/polyp/daemon-conf.h @@ -33,11 +33,11 @@ typedef enum pa_daemon_conf_cmd { PA_CMD_DUMP_MODULES, PA_CMD_KILL, PA_CMD_CHECK -} pa_daemon_conf_cmd; +} pa_daemon_conf_cmd_t; /* A structure containing configuration data for the Polypaudio server . */ typedef struct pa_daemon_conf { - pa_daemon_conf_cmd cmd; + pa_daemon_conf_cmd_t cmd; int daemonize, fail, high_priority, @@ -48,8 +48,8 @@ typedef struct pa_daemon_conf { auto_log_target, use_pid_file; char *script_commands, *dl_search_path, *default_script_file; - pa_log_target log_target; - pa_log_level log_level; + pa_log_target_t log_target; + pa_log_level_t log_level; int resample_method; char *config_file; } pa_daemon_conf; diff --git a/polyp/dllmain.c b/polyp/dllmain.c index 34d0eed1..d1d120ab 100644 --- a/polyp/dllmain.c +++ b/polyp/dllmain.c @@ -1,4 +1,4 @@ -/* $Id: dllmain.c 317 2004-12-11 00:10:41Z lennart $ */ +/* $Id$ */ /*** This file is part of polypaudio. diff --git a/polyp/glib-mainloop.c b/polyp/glib-mainloop.c index 6552da15..6f7c1dc5 100644 --- a/polyp/glib-mainloop.c +++ b/polyp/glib-mainloop.c @@ -38,9 +38,9 @@ struct pa_io_event { GSource *source; GIOCondition io_condition; int fd; - void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata); + void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_io_event*e, void *userdata); + void (*destroy_callback) (pa_mainloop_api *m, pa_io_event *e, void *userdata); pa_io_event *next, *prev; }; @@ -76,9 +76,9 @@ struct pa_glib_mainloop { static void schedule_free_dead_events(pa_glib_mainloop *g); -static void glib_io_enable(pa_io_event*e, pa_io_event_flags f); +static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f); -static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags f, void *userdata), void *userdata) { +static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags_t f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata), void *userdata) { pa_io_event *e; pa_glib_mainloop *g; @@ -111,7 +111,7 @@ static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags f, /* The callback GLIB calls whenever an IO condition is met */ static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { pa_io_event *e = data; - pa_io_event_flags f; + pa_io_event_flags_t f; assert(source && e && e->io_channel == source); f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | @@ -123,7 +123,7 @@ static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) return TRUE; } -static void glib_io_enable(pa_io_event*e, pa_io_event_flags f) { +static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { GIOCondition c; assert(e && !e->dead); diff --git a/polyp/glib12-mainloop.c b/polyp/glib12-mainloop.c index e322ac07..8bc4483b 100644 --- a/polyp/glib12-mainloop.c +++ b/polyp/glib12-mainloop.c @@ -39,7 +39,7 @@ struct pa_io_event { guint source; GIOCondition io_condition; int fd; - void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata); + void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); void *userdata; void (*destroy_callback) (pa_mainloop_api *m, pa_io_event*e, void *userdata); pa_io_event *next, *prev; @@ -76,9 +76,9 @@ struct pa_glib_mainloop { static void schedule_free_dead_events(pa_glib_mainloop *g); -static void glib_io_enable(pa_io_event*e, pa_io_event_flags f); +static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f); -static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags f, void *userdata), void *userdata) { +static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags_t f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata), void *userdata) { pa_io_event *e; pa_glib_mainloop *g; @@ -110,7 +110,7 @@ static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags f, static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { pa_io_event *e = data; - pa_io_event_flags f; + pa_io_event_flags_t f; assert(source && e && e->io_channel == source); f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | @@ -122,7 +122,7 @@ static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) return TRUE; } -static void glib_io_enable(pa_io_event*e, pa_io_event_flags f) { +static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { GIOCondition c; assert(e && !e->dead); diff --git a/polyp/inet_ntop.c b/polyp/inet_ntop.c index ac2b5295..a25c3c95 100644 --- a/polyp/inet_ntop.c +++ b/polyp/inet_ntop.c @@ -1,4 +1,4 @@ -/* $Id: inet_ntop.c 428 2006-01-09 16:50:39Z ossman $ */ +/* $Id$ */ /*** This file is part of polypaudio. diff --git a/polyp/iochannel.c b/polyp/iochannel.c index e6271319..273d47e0 100644 --- a/polyp/iochannel.c +++ b/polyp/iochannel.c @@ -55,7 +55,7 @@ static void enable_mainloop_sources(pa_iochannel *io) { assert(io); if (io->input_event == io->output_event && io->input_event) { - pa_io_event_flags f = PA_IO_EVENT_NULL; + pa_io_event_flags_t f = PA_IO_EVENT_NULL; assert(io->input_event); if (!io->readable) @@ -72,7 +72,7 @@ static void enable_mainloop_sources(pa_iochannel *io) { } } -static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata) { +static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { pa_iochannel *io = userdata; int changed = 0; diff --git a/polyp/log.c b/polyp/log.c index c41fbbae..97406f79 100644 --- a/polyp/log.c +++ b/polyp/log.c @@ -38,9 +38,9 @@ #define ENV_LOGLEVEL "POLYP_LOG" static char *log_ident = NULL; -static pa_log_target log_target = PA_LOG_STDERR; -static void (*user_log_func)(pa_log_level l, const char *s) = NULL; -static pa_log_level maximal_level = PA_LOG_NOTICE; +static pa_log_target_t log_target = PA_LOG_STDERR; +static void (*user_log_func)(pa_log_level_t l, const char *s) = NULL; +static pa_log_level_t maximal_level = PA_LOG_NOTICE; #ifdef HAVE_SYSLOG_H static const int level_to_syslog[] = { @@ -59,18 +59,18 @@ void pa_log_set_ident(const char *p) { log_ident = pa_xstrdup(p); } -void pa_log_set_maximal_level(pa_log_level l) { +void pa_log_set_maximal_level(pa_log_level_t l) { assert(l < PA_LOG_LEVEL_MAX); maximal_level = l; } -void pa_log_set_target(pa_log_target t, void (*func)(pa_log_level l, const char*s)) { +void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t l, const char*s)) { assert(t == PA_LOG_USER || !func); log_target = t; user_log_func = func; } -void pa_log_with_levelv(pa_log_level level, const char *format, va_list ap) { +void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { const char *e; assert(level < PA_LOG_LEVEL_MAX); @@ -107,44 +107,44 @@ void pa_log_with_levelv(pa_log_level level, const char *format, va_list ap) { } -void pa_log_with_level(pa_log_level level, const char *format, ...) { +void pa_log_level(pa_log_level_t level, const char *format, ...) { va_list ap; va_start(ap, format); - pa_log_with_levelv(level, format, ap); + pa_log_levelv(level, format, ap); va_end(ap); } void pa_log_debug(const char *format, ...) { va_list ap; va_start(ap, format); - pa_log_with_levelv(PA_LOG_DEBUG, format, ap); + pa_log_levelv(PA_LOG_DEBUG, format, ap); va_end(ap); } void pa_log_info(const char *format, ...) { va_list ap; va_start(ap, format); - pa_log_with_levelv(PA_LOG_INFO, format, ap); + pa_log_levelv(PA_LOG_INFO, format, ap); va_end(ap); } void pa_log_notice(const char *format, ...) { va_list ap; va_start(ap, format); - pa_log_with_levelv(PA_LOG_INFO, format, ap); + pa_log_levelv(PA_LOG_INFO, format, ap); va_end(ap); } void pa_log_warn(const char *format, ...) { va_list ap; va_start(ap, format); - pa_log_with_levelv(PA_LOG_WARN, format, ap); + pa_log_levelv(PA_LOG_WARN, format, ap); va_end(ap); } void pa_log_error(const char *format, ...) { va_list ap; va_start(ap, format); - pa_log_with_levelv(PA_LOG_ERROR, format, ap); + pa_log_levelv(PA_LOG_ERROR, format, ap); va_end(ap); } diff --git a/polyp/log.h b/polyp/log.h index 7c6a8e61..ce8aea98 100644 --- a/polyp/log.h +++ b/polyp/log.h @@ -33,7 +33,7 @@ typedef enum pa_log_target { PA_LOG_SYSLOG, PA_LOG_USER, /* to user specified function */ PA_LOG_NULL /* to /dev/null */ -} pa_log_target; +} pa_log_target_t; typedef enum pa_log_level { PA_LOG_ERROR = 0, /* Error messages */ @@ -42,16 +42,16 @@ typedef enum pa_log_level { PA_LOG_INFO = 3, /* Info messages */ PA_LOG_DEBUG = 4, /* debug message */ PA_LOG_LEVEL_MAX -} pa_log_level; +} pa_log_level_t; /* Set an identification for the current daemon. Used when logging to syslog. */ void pa_log_set_ident(const char *p); /* Set another log target. If t is PA_LOG_USER you may specify a function that is called every log string */ -void pa_log_set_target(pa_log_target t, void (*func)(pa_log_level, const char*s)); +void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t t, const char*s)); /* Minimal log level */ -void pa_log_set_maximal_level(pa_log_level l); +void pa_log_set_maximal_level(pa_log_level_t l); /* Do a log line */ void pa_log_debug(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); @@ -60,9 +60,9 @@ void pa_log_notice(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); void pa_log_warn(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); void pa_log_error(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); -void pa_log_with_level(pa_log_level level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); +void pa_log_level(pa_log_level_t level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); -void pa_log_with_levelv(pa_log_level level, const char *format, va_list ap); +void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap); #define pa_log pa_log_error diff --git a/polyp/main.c b/polyp/main.c index 1c3b566d..c984e28e 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -37,6 +37,7 @@ #include #include #include +#include #ifdef HAVE_SYS_IOCTL_H #include @@ -386,6 +387,8 @@ int main(int argc, char *argv[]) { pa_signal_new(SIGHUP, signal_callback, c); #endif + oil_init(); + r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop)); assert(r == 0); diff --git a/polyp/mainloop-api.h b/polyp/mainloop-api.h index 1604e740..91ee4111 100644 --- a/polyp/mainloop-api.h +++ b/polyp/mainloop-api.h @@ -51,7 +51,7 @@ typedef enum pa_io_event_flags { PA_IO_EVENT_OUTPUT = 2, /**< Output event */ PA_IO_EVENT_HANGUP = 4, /**< Hangup event */ PA_IO_EVENT_ERROR = 8 /**< Error event */ -} pa_io_event_flags; +} pa_io_event_flags_t; /** \pa_io_event * An opaque IO event source object */ @@ -73,10 +73,10 @@ struct pa_mainloop_api { void *userdata; /** Create a new IO event source object */ - pa_io_event* (*io_new)(pa_mainloop_api*a, int fd, pa_io_event_flags events, void (*callback) (pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags events, void *userdata), void *userdata); + pa_io_event* (*io_new)(pa_mainloop_api*a, int fd, pa_io_event_flags_t events, void (*callback) (pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata); /** Enable or disable IO events on this object */ - void (*io_enable)(pa_io_event* e, pa_io_event_flags events); + void (*io_enable)(pa_io_event* e, pa_io_event_flags_t events); /** Free a IO event source object */ void (*io_free)(pa_io_event* e); diff --git a/polyp/mainloop-signal.c b/polyp/mainloop-signal.c index f225e60b..76936031 100644 --- a/polyp/mainloop-signal.c +++ b/polyp/mainloop-signal.c @@ -119,7 +119,7 @@ static void defer(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event*e, PA_GCC_UNUS } } -static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags f, PA_GCC_UNUSED void *userdata) { +static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags_t f, PA_GCC_UNUSED void *userdata) { ssize_t r; int sig; assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]); diff --git a/polyp/mainloop-test.c b/polyp/mainloop-test.c index 097ce1c7..ee0f8711 100644 --- a/polyp/mainloop-test.c +++ b/polyp/mainloop-test.c @@ -51,7 +51,7 @@ static GMainLoop* glib_main_loop = NULL; static pa_defer_event *de; -static void iocb(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata) { +static void iocb(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { unsigned char c; read(fd, &c, sizeof(c)); fprintf(stderr, "IO EVENT: %c\n", c < 32 ? '.' : c); diff --git a/polyp/mainloop.c b/polyp/mainloop.c index 599a90f8..26ba2425 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -50,8 +50,8 @@ struct pa_io_event { pa_mainloop *mainloop; int dead; int fd; - pa_io_event_flags events; - void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata); + pa_io_event_flags_t events; + void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); struct pollfd *pollfd; void *userdata; void (*destroy_callback) (pa_mainloop_api*a, pa_io_event *e, void *userdata); @@ -91,7 +91,13 @@ struct pa_mainloop { }; /* IO events */ -static pa_io_event* mainloop_io_new(pa_mainloop_api*a, int fd, pa_io_event_flags events, void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags events, void *userdata), void *userdata) { +static pa_io_event* mainloop_io_new( + pa_mainloop_api*a, + int fd, + pa_io_event_flags_t events, + void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), + void *userdata) { + pa_mainloop *m; pa_io_event *e; @@ -135,7 +141,7 @@ static pa_io_event* mainloop_io_new(pa_mainloop_api*a, int fd, pa_io_event_flags return e; } -static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags events) { +static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags_t events) { assert(e && e->mainloop); e->events = events; diff --git a/polyp/memblock.h b/polyp/memblock.h index cbf5d684..c5751406 100644 --- a/polyp/memblock.h +++ b/polyp/memblock.h @@ -31,12 +31,12 @@ * memory blocks. */ /* The type of memory this block points to */ -typedef enum { +typedef enum pa_memblock_type { PA_MEMBLOCK_FIXED, /* data is a pointer to fixed memory that needs not to be freed */ PA_MEMBLOCK_APPENDED, /* The most common kind: the data is appended to the memory block */ PA_MEMBLOCK_DYNAMIC, /* data is a pointer to some memory allocated with pa_xmalloc() */ PA_MEMBLOCK_USER /* User supplied memory, to be freed with free_cb */ -} pa_memblock_type ; +} pa_memblock_type_t; /* A structure of keeping memory block statistics */ /* Maintains statistics about memory blocks */ @@ -49,7 +49,7 @@ typedef struct pa_memblock_stat { } pa_memblock_stat; typedef struct pa_memblock { - pa_memblock_type type; + pa_memblock_type_t type; unsigned ref; /* the reference counter */ int read_only; /* boolean */ size_t length; diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index 14070d63..ea6ca424 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -51,8 +51,6 @@ PA_MODULE_DESCRIPTION("ALSA Sink") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink_name= device= format= channels= rate= fragments= fragment_size=") -#define PA_TYPEID_ALSA PA_TYPEID_MAKE('A', 'L', 'S', 'A') - struct userdata { snd_pcm_t *pcm_handle; pa_sink *sink; @@ -142,7 +140,7 @@ static void do_write(struct userdata *u) { } } -static void io_callback(pa_mainloop_api*a, pa_io_event *e, PA_GCC_UNUSED int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { +static void io_callback(pa_mainloop_api*a, pa_io_event *e, PA_GCC_UNUSED int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { struct userdata *u = userdata; assert(u && a && e); @@ -220,7 +218,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - u->sink = pa_sink_new(c, PA_TYPEID_ALSA, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); + u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; @@ -236,7 +234,7 @@ int pa__init(pa_core *c, pa_module*m) { u->frame_size = frame_size; u->fragment_size = period_size; - pa_log(__FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); + pa_log_info(__FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); u->silence.memblock = pa_memblock_new(u->silence.length = u->fragment_size, c->memblock_stat); assert(u->silence.memblock); diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index 4ad8dd84..2aa47aad 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -51,8 +51,6 @@ PA_MODULE_DESCRIPTION("ALSA Source") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("source_name= device= format= channels= rate= fragments= fragment_size=") -#define PA_TYPEID_ALSA PA_TYPEID_MAKE('A', 'L', 'S', 'A') - struct userdata { snd_pcm_t *pcm_handle; pa_source *source; @@ -142,7 +140,7 @@ static void do_read(struct userdata *u) { } } -static void io_callback(pa_mainloop_api*a, pa_io_event *e, PA_GCC_UNUSED int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { +static void io_callback(pa_mainloop_api*a, pa_io_event *e, PA_GCC_UNUSED int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { struct userdata *u = userdata; assert(u && a && e); @@ -211,7 +209,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - u->source = pa_source_new(c, PA_TYPEID_ALSA, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); assert(u->source); u->source->userdata = u; diff --git a/polyp/module-combine.c b/polyp/module-combine.c index cee0a5dc..0c21c2f5 100644 --- a/polyp/module-combine.c +++ b/polyp/module-combine.c @@ -43,8 +43,6 @@ PA_MODULE_DESCRIPTION("Combine multiple sinks to one") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink_name= master= slaves= adjust_time= resample_method=") -#define PA_TYPEID_COMBINE PA_TYPEID_MAKE('C', 'M', 'B', 'N') - #define DEFAULT_SINK_NAME "combined" #define MEMBLOCKQ_MAXLENGTH (1024*170) #define RENDER_SIZE (1024*10) @@ -216,7 +214,7 @@ static struct output *output_new(struct userdata *u, pa_sink *sink, int resample o->memblockq = pa_memblockq_new(MEMBLOCKQ_MAXLENGTH, MEMBLOCKQ_MAXLENGTH, pa_frame_size(&u->sink->sample_spec), 0, 0, sink->core->memblock_stat); snprintf(t, sizeof(t), "%s: output #%u", u->sink->name, u->n_outputs+1); - if (!(o->sink_input = pa_sink_input_new(sink, PA_TYPEID_COMBINE, t, &u->sink->sample_spec, 1, resample_method))) + if (!(o->sink_input = pa_sink_input_new(sink, __FILE__, t, &u->sink->sample_spec, &u->sink->channel_map, 1, resample_method))) goto fail; o->sink_input->get_latency = sink_input_get_latency_cb; @@ -327,7 +325,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - if (!(u->sink = pa_sink_new(c, PA_TYPEID_COMBINE, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &master_sink->sample_spec))) { + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &master_sink->sample_spec, &master_sink->channel_map))) { pa_log(__FILE__": failed to create sink\n"); goto fail; } diff --git a/polyp/module-esound-sink.c b/polyp/module-esound-sink.c index ac211a31..afd5feed 100644 --- a/polyp/module-esound-sink.c +++ b/polyp/module-esound-sink.c @@ -46,14 +46,12 @@ #include "authkey.h" PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Esound ") +PA_MODULE_DESCRIPTION("ESOUND Sink") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink_name= server=
    cookie= format= channels= rate=") #define DEFAULT_SINK_NAME "esound_output" -#define PA_TYPEID_ESOUND_SINK PA_TYPEID_MAKE('E', 'S', 'D', 'S') - struct userdata { pa_core *core; @@ -354,7 +352,7 @@ int pa__init(pa_core *c, pa_module*m) { u->state = STATE_AUTH; u->latency = 0; - if (!(u->sink = pa_sink_new(c, PA_TYPEID_ESOUND_SINK, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { pa_log(__FILE__": failed to create sink.\n"); goto fail; } diff --git a/polyp/module-lirc.c b/polyp/module-lirc.c index eb71c47f..d2e248aa 100644 --- a/polyp/module-lirc.c +++ b/polyp/module-lirc.c @@ -61,7 +61,7 @@ struct userdata { static int lirc_in_use = 0; -static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags events, void*userdata) { +static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void*userdata) { struct userdata *u = userdata; char *name = NULL, *code = NULL; assert(io); @@ -109,26 +109,45 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) pa_log(__FILE__": failed to get sink '%s'\n", u->sink_name); else { - double v = pa_volume_to_user(s->volume); - + pa_volume_t v = pa_cvolume_avg(pa_sink_get_volume(s, PA_MIXER_HARDWARE)); + pa_cvolume cv; +#define DELTA (PA_VOLUME_NORM/20) + switch (volchange) { - case UP: v += .05; break; - case DOWN: v -= .05; break; - case MUTE: v = 0; break; - case RESET: v = 1; break; + case UP: + v += PA_VOLUME_NORM/20; + break; + + case DOWN: + if (v > DELTA) + v -= DELTA; + else + v = PA_VOLUME_MUTED; + + break; + + case MUTE: + v = PA_VOLUME_MUTED; + break; + + case RESET: + v = PA_VOLUME_NORM; + break; + case MUTE_TOGGLE: { if (v > 0) { u->mute_toggle_save = v; - v = 0; + v = PA_VOLUME_MUTED; } else v = u->mute_toggle_save; } default: ; } - - pa_sink_set_volume(s, pa_volume_from_user(v)); + + pa_cvolume_set(&cv, PA_CHANNELS_MAX, v); + pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); } } } diff --git a/polyp/module-match.c b/polyp/module-match.c index e48d55ca..e3e7b17d 100644 --- a/polyp/module-match.c +++ b/polyp/module-match.c @@ -154,7 +154,7 @@ finish: return ret; } -static void callback(pa_core *c, pa_subscription_event_type t, uint32_t idx, void *userdata) { +static void callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { struct userdata *u = userdata; pa_sink_input *si; struct rule *r; @@ -171,8 +171,10 @@ static void callback(pa_core *c, pa_subscription_event_type t, uint32_t idx, voi for (r = u->rules; r; r = r->next) { if (!regexec(&r->regex, si->name, 0, NULL, 0)) { + pa_cvolume cv; pa_log_debug(__FILE__": changing volume of sink input '%s' to 0x%03x\n", si->name, r->volume); - pa_sink_input_set_volume(si, r->volume); + pa_cvolume_set(&cv, r->volume, si->sample_spec.channels); + pa_sink_input_set_volume(si, &cv); } } } diff --git a/polyp/module-mmkbd-evdev.c b/polyp/module-mmkbd-evdev.c index 5eb55e35..ec45ec4b 100644 --- a/polyp/module-mmkbd-evdev.c +++ b/polyp/module-mmkbd-evdev.c @@ -74,7 +74,7 @@ struct userdata { float mute_toggle_save; }; -static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags events, void*userdata) { +static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void*userdata) { struct userdata *u = userdata; assert(io); assert(u); @@ -109,16 +109,28 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) pa_log(__FILE__": failed to get sink '%s'\n", u->sink_name); else { - double v = pa_volume_to_user(s->volume); + pa_volume_t v = pa_cvolume_avg(pa_sink_get_volume(s, PA_MIXER_HARDWARE)); + pa_cvolume cv; +#define DELTA (PA_VOLUME_NORM/20) switch (volchange) { - case UP: v += .05; break; - case DOWN: v -= .05; break; + case UP: + v += DELTA; + break; + + case DOWN: + if (v > DELTA) + v -= DELTA; + else + v = PA_VOLUME_MUTED; + + break; + case MUTE_TOGGLE: { if (v > 0) { u->mute_toggle_save = v; - v = 0; + v = PA_VOLUME_MUTED; } else v = u->mute_toggle_save; } @@ -126,7 +138,8 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC ; } - pa_sink_set_volume(s, pa_volume_from_user(v)); + pa_cvolume_set(&cv, PA_CHANNELS_MAX, v); + pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); } } } diff --git a/polyp/module-null-sink.c b/polyp/module-null-sink.c index b26ea50b..93abca78 100644 --- a/polyp/module-null-sink.c +++ b/polyp/module-null-sink.c @@ -49,8 +49,6 @@ PA_MODULE_USAGE("format= channels= rate=module = m; m->userdata = u; - if (!(u->sink = pa_sink_new(c, PA_TYPEID_NULL, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { pa_log(__FILE__": failed to create sink.\n"); goto fail; } diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index ac510f96..f976cf81 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -53,8 +53,6 @@ PA_MODULE_DESCRIPTION("OSS Sink/Source (mmap)") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= fragments= fragment_size=") -#define PA_TYPEID_OSS_MMAP PA_TYPEID_MAKE('O', 'S', 'S', 'M') - struct userdata { pa_sink *sink; pa_source *source; @@ -204,7 +202,7 @@ static void do_read(struct userdata *u) { in_clear_memblocks(u, u->in_fragments/2); } -static void io_callback(pa_mainloop_api *m, pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags f, void *userdata) { +static void io_callback(pa_mainloop_api *m, pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t f, void *userdata) { struct userdata *u = userdata; assert (u && u->core->mainloop == m && u->io_event == e); @@ -304,7 +302,7 @@ int pa__init(pa_core *c, pa_module*m) { } } else { - u->source = pa_source_new(c, PA_TYPEID_OSS_MMAP, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec); + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec, NULL); assert(u->source); u->source->userdata = u; pa_source_set_owner(u->source, m); @@ -336,7 +334,7 @@ int pa__init(pa_core *c, pa_module*m) { } else { pa_silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec); - u->sink = pa_sink_new(c, PA_TYPEID_OSS_MMAP, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec); + u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec, NULL); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; u->sink->userdata = u; diff --git a/polyp/module-oss.c b/polyp/module-oss.c index 06679a97..b5c7ae8c 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -52,8 +52,6 @@ PA_MODULE_DESCRIPTION("OSS Sink/Source") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= fragments= fragment_size=") -#define PA_TYPEID_OSS PA_TYPEID_MAKE('O', 'S', 'S', '_') - struct userdata { pa_sink *sink; pa_source *source; @@ -222,7 +220,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { assert(s && u && u->sink); if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { - pa_log_info(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY.\n"); + pa_log_info(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY: %s\n", strerror(errno)); s->get_latency = NULL; return 0; } @@ -254,6 +252,46 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { return pa_bytes_to_usec(info.bytes, &s->sample_spec); } +static int sink_get_hw_volume(pa_sink *s) { + struct userdata *u = s->userdata; + char cv[PA_CVOLUME_SNPRINT_MAX]; + unsigned vol; + + if (ioctl(u->fd, SOUND_MIXER_READ_PCM, &vol) < 0) { + pa_log_info(__FILE__": device doesn't support reading mixer settings: %s\n", strerror(errno)); + s->get_hw_volume = NULL; + return -1; + } + + s->hw_volume.values[0] = ((vol & 0xFF) * PA_VOLUME_NORM) / 100; + + if ((s->hw_volume.channels = s->sample_spec.channels) >= 2) + s->hw_volume.values[1] = (((vol >> 8) & 0xFF) * PA_VOLUME_NORM) / 100; + + pa_log_info(__FILE__": Read mixer settings: %s\n", pa_cvolume_snprint(cv, sizeof(cv), &s->hw_volume)); + return 0; +} + +static int sink_set_hw_volume(pa_sink *s) { + struct userdata *u = s->userdata; + char cv[PA_CVOLUME_SNPRINT_MAX]; + unsigned vol; + + vol = (s->hw_volume.values[0]*100)/PA_VOLUME_NORM; + + if (s->sample_spec.channels >= 2) + vol |= ((s->hw_volume.values[1]*100)/PA_VOLUME_NORM) << 8; + + if (ioctl(u->fd, SOUND_MIXER_WRITE_PCM, &vol) < 0) { + pa_log_info(__FILE__": device doesn't support writing mixer settings: %s\n", strerror(errno)); + s->set_hw_volume = NULL; + return -1; + } + + pa_log_info(__FILE__": Wrote mixer settings: %s\n", pa_cvolume_snprint(cv, sizeof(cv), &s->hw_volume)); + return 0; +} + int pa__init(pa_core *c, pa_module*m) { struct audio_buf_info info; struct userdata *u = NULL; @@ -332,7 +370,7 @@ int pa__init(pa_core *c, pa_module*m) { } if (mode != O_WRONLY) { - u->source = pa_source_new(c, PA_TYPEID_OSS, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); assert(u->source); u->source->userdata = u; u->source->notify = source_notify_cb; @@ -343,9 +381,11 @@ int pa__init(pa_core *c, pa_module*m) { u->source = NULL; if (mode != O_RDONLY) { - u->sink = pa_sink_new(c, PA_TYPEID_OSS, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); + u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; + u->sink->get_hw_volume = sink_get_hw_volume; + u->sink->set_hw_volume = sink_set_hw_volume; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); u->sink->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); @@ -384,6 +424,10 @@ int pa__init(pa_core *c, pa_module*m) { read(u->fd, buf, u->sample_size); } + /* Read mixer settings */ + if (u->sink) + sink_get_hw_volume(u->sink); + return 0; fail: diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c index 537cb86b..20e220ce 100644 --- a/polyp/module-pipe-sink.c +++ b/polyp/module-pipe-sink.c @@ -50,8 +50,6 @@ PA_MODULE_USAGE("sink_name= file= format=module = m; m->userdata = u; - if (!(u->sink = pa_sink_new(c, PA_TYPEID_PIPE, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { pa_log(__FILE__": failed to create sink.\n"); goto fail; } diff --git a/polyp/module-pipe-source.c b/polyp/module-pipe-source.c index 31653627..42f13d4b 100644 --- a/polyp/module-pipe-source.c +++ b/polyp/module-pipe-source.c @@ -50,8 +50,6 @@ PA_MODULE_USAGE("source_name= file= forma #define DEFAULT_FIFO_NAME "/tmp/music.input" #define DEFAULT_SOURCE_NAME "fifo_input" -#define PA_TYPEID_PIPE PA_TYPEID_MAKE('P', 'I', 'P', 'E') - struct userdata { pa_core *core; @@ -154,7 +152,7 @@ int pa__init(pa_core *c, pa_module*m) { u->filename = pa_xstrdup(p); u->core = c; - if (!(u->source = pa_source_new(c, PA_TYPEID_PIPE, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss))) { + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL))) { pa_log(__FILE__": failed to create source.\n"); goto fail; } diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index 3cf3d9d4..44d1c022 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -146,7 +146,7 @@ #else #include "module-esound-protocol-unix-symdef.h" #endif - PA_MODULE_DESCRIPTION("EsounD protocol "SOCKET_DESCRIPTION) + PA_MODULE_DESCRIPTION("ESOUND protocol "SOCKET_DESCRIPTION) PA_MODULE_USAGE("sink= source= public= cookie= "SOCKET_USAGE) #else #error "Broken build system" diff --git a/polyp/module-sine.c b/polyp/module-sine.c index c531386a..529c061a 100644 --- a/polyp/module-sine.c +++ b/polyp/module-sine.c @@ -40,8 +40,6 @@ PA_MODULE_DESCRIPTION("Sine wave generator") PA_MODULE_USAGE("sink= frequency=") PA_MODULE_VERSION(PACKAGE_VERSION) -#define PA_TYPEID_SINE PA_TYPEID_MAKE('S', 'I', 'N', 'E') - struct userdata { pa_core *core; pa_module *module; @@ -142,7 +140,7 @@ int pa__init(pa_core *c, pa_module*m) { calc_sine(u->memblock->data, u->memblock->length, frequency); snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency); - if (!(u->sink_input = pa_sink_input_new(sink, PA_TYPEID_SINE, t, &ss, 0, -1))) + if (!(u->sink_input = pa_sink_input_new(sink, __FILE__, t, &ss, NULL, 0, -1))) goto fail; u->sink_input->peek = sink_input_peek; diff --git a/polyp/module-solaris.c b/polyp/module-solaris.c index 01a151d6..ce9308be 100644 --- a/polyp/module-solaris.c +++ b/polyp/module-solaris.c @@ -1,4 +1,4 @@ -/* $Id: module-oss.c 333 2005-01-08 21:36:53Z lennart $ */ +/* $Id$ */ /*** This file is part of polypaudio. diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c index e0eab6c2..c088dae0 100644 --- a/polyp/module-tunnel.c +++ b/polyp/module-tunnel.c @@ -59,8 +59,6 @@ PA_MODULE_USAGE("server=
    source= cookie= PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_VERSION(PACKAGE_VERSION) -#define PA_TYPEID_TUNNEL PA_TYPEID_MAKE('T', 'U', 'N', 'L') - #define DEFAULT_SINK_NAME "tunnel" #define DEFAULT_SOURCE_NAME "tunnel" @@ -625,7 +623,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_socket_client_set_callback(u->client, on_connection, u); #ifdef TUNNEL_SINK - if (!(u->sink = pa_sink_new(c, PA_TYPEID_TUNNEL, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { pa_log(__FILE__": failed to create sink.\n"); goto fail; } @@ -637,7 +635,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_sink_set_owner(u->sink, m); #else - if (!(u->source = pa_source_new(c, PA_TYPEID_TUNNEL, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss))) { + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL))) { pa_log(__FILE__": failed to create source.\n"); goto fail; } diff --git a/polyp/module-waveout.c b/polyp/module-waveout.c index 4d6d8c7b..a5ef847b 100644 --- a/polyp/module-waveout.c +++ b/polyp/module-waveout.c @@ -1,4 +1,4 @@ -/* $Id: module-waveout.c 333 2005-01-08 21:36:53Z lennart $ */ +/* $Id$ */ /*** This file is part of polypaudio. diff --git a/polyp/module-x11-bell.c b/polyp/module-x11-bell.c index 9b08c166..4fc4a60d 100644 --- a/polyp/module-x11-bell.c +++ b/polyp/module-x11-bell.c @@ -66,6 +66,7 @@ static const char* const valid_modargs[] = { static int ring_bell(struct userdata *u, int percent) { pa_sink *s; + pa_cvolume cv; assert(u); if (!(s = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) { @@ -73,7 +74,7 @@ static int ring_bell(struct userdata *u, int percent) { return -1; } - pa_scache_play_item(u->core, u->scache_item, s, percent*2); + pa_scache_play_item(u->core, u->scache_item, s, pa_cvolume_set(&cv, PA_CHANNELS_MAX, percent*PA_VOLUME_NORM/100)); return 0; } diff --git a/polyp/namereg.c b/polyp/namereg.c index 7c53a05d..07fb485c 100644 --- a/polyp/namereg.c +++ b/polyp/namereg.c @@ -38,7 +38,7 @@ #include "util.h" struct namereg_entry { - pa_namereg_type type; + pa_namereg_type_t type; char *name; void *data; }; @@ -51,7 +51,7 @@ void pa_namereg_free(pa_core *c) { pa_hashmap_free(c->namereg, NULL, NULL); } -const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type type, void *data, int fail) { +const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, int fail) { struct namereg_entry *e; char *n = NULL; int r; @@ -110,7 +110,7 @@ void pa_namereg_unregister(pa_core *c, const char *name) { pa_xfree(e); } -void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type type, int autoload) { +void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int autoload) { struct namereg_entry *e; uint32_t idx; assert(c); @@ -152,7 +152,7 @@ void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type type, int aut return NULL; } -void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type type) { +void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type) { char **s; assert(c && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); diff --git a/polyp/namereg.h b/polyp/namereg.h index 04f1737b..961fd44b 100644 --- a/polyp/namereg.h +++ b/polyp/namereg.h @@ -28,14 +28,14 @@ typedef enum pa_namereg_type { PA_NAMEREG_SINK, PA_NAMEREG_SOURCE, PA_NAMEREG_SAMPLE -} pa_namereg_type ; +} pa_namereg_type_t; void pa_namereg_free(pa_core *c); -const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type type, void *data, int fail); +const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, int fail); void pa_namereg_unregister(pa_core *c, const char *name); -void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type type, int autoload); -void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type type); +void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int autoload); +void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type); const char *pa_namereg_get_default_sink_name(pa_core *c); const char *pa_namereg_get_default_source_name(pa_core *c); diff --git a/polyp/native-common.h b/polyp/native-common.h index 892629e8..569f3b71 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -51,6 +51,7 @@ enum { PA_COMMAND_FINISH_UPLOAD_STREAM, PA_COMMAND_PLAY_SAMPLE, PA_COMMAND_REMOVE_SAMPLE, + PA_COMMAND_GET_SERVER_INFO, PA_COMMAND_GET_SINK_INFO, PA_COMMAND_GET_SINK_INFO_LIST, @@ -68,15 +69,19 @@ enum { PA_COMMAND_GET_SAMPLE_INFO_LIST, PA_COMMAND_SUBSCRIBE, PA_COMMAND_SUBSCRIBE_EVENT, + PA_COMMAND_SET_SINK_VOLUME, PA_COMMAND_SET_SINK_INPUT_VOLUME, PA_COMMAND_CORK_PLAYBACK_STREAM, PA_COMMAND_FLUSH_PLAYBACK_STREAM, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, + PA_COMMAND_SET_DEFAULT_SINK, PA_COMMAND_SET_DEFAULT_SOURCE, + PA_COMMAND_SET_PLAYBACK_STREAM_NAME, PA_COMMAND_SET_RECORD_STREAM_NAME, + PA_COMMAND_KILL_CLIENT, PA_COMMAND_KILL_SINK_INPUT, PA_COMMAND_KILL_SOURCE_OUTPUT, diff --git a/polyp/pacat-simple.c b/polyp/pacat-simple.c index 373cdd57..2825fee5 100644 --- a/polyp/pacat-simple.c +++ b/polyp/pacat-simple.c @@ -48,7 +48,7 @@ int main(PA_GCC_UNUSED int argc, char*argv[]) { int error; /* Create a new playback stream */ - if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, PA_VOLUME_NORM, &error))) { + if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, &error))) { fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); goto finish; } diff --git a/polyp/pacat.c b/polyp/pacat.c index 6842d61a..bd2b64fd 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -162,16 +162,17 @@ static void context_state_callback(pa_context *c, void *userdata) { if (verbose) fprintf(stderr, "Connection established.\n"); - stream = pa_stream_new(c, stream_name, &sample_spec); + stream = pa_stream_new(c, stream_name, &sample_spec, NULL); assert(stream); pa_stream_set_state_callback(stream, stream_state_callback, NULL); pa_stream_set_write_callback(stream, stream_write_callback, NULL); pa_stream_set_read_callback(stream, stream_read_callback, NULL); - if (mode == PLAYBACK) - pa_stream_connect_playback(stream, device, NULL, 0, volume); - else + if (mode == PLAYBACK) { + pa_cvolume cv; + pa_stream_connect_playback(stream, device, NULL, 0, pa_cvolume_set(&cv, PA_CHANNELS_MAX, volume)); + } else pa_stream_connect_record(stream, device, NULL, 0); break; @@ -219,7 +220,7 @@ static void stream_drain_complete(pa_stream*s, int success, void *userdata) { } /* New data on STDIN **/ -static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata) { +static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { size_t l, w = 0; ssize_t r; assert(a == mainloop_api && e && stdio_event == e); @@ -257,7 +258,7 @@ static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_even } /* Some data may be written to STDOUT */ -static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata) { +static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { ssize_t r; assert(a == mainloop_api && e && stdio_event == e); diff --git a/polyp/pactl.c b/polyp/pactl.c index 6943a11f..23bd924b 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -149,8 +149,8 @@ static void get_server_info_callback(pa_context *c, const pa_server_info *i, voi } static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) { - char s[PA_SAMPLE_SPEC_SNPRINT_MAX], tid[5]; - + char s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + if (is_last < 0) { fprintf(stderr, "Failed to get sink information: %s\n", pa_strerror(pa_context_errno(c))); quit(1); @@ -168,31 +168,31 @@ static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_ printf("\n"); nl = 1; - pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); - printf("*** Sink #%u ***\n" "Name: %s\n" - "Type: %s\n" + "Driver: %s\n" "Description: %s\n" "Sample Specification: %s\n" + "Channel Map: %s\n" "Owner Module: %u\n" - "Volume: 0x%03x (%0.2f dB)\n" + "Volume: %s\n" "Monitor Source: %u\n" "Latency: %0.0f usec\n", i->index, i->name, - pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), + i->driver, i->description, - s, + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), i->owner_module, - i->volume, pa_volume_to_dB(i->volume), + pa_cvolume_snprint(cv, sizeof(cv), &i->volume), i->monitor_source, (double) i->latency); } static void get_source_info_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) { - char s[PA_SAMPLE_SPEC_SNPRINT_MAX], t[32], tid[5]; + char s[PA_SAMPLE_SPEC_SNPRINT_MAX], t[32], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; if (is_last < 0) { fprintf(stderr, "Failed to get source information: %s\n", pa_strerror(pa_context_errno(c))); @@ -213,21 +213,21 @@ static void get_source_info_callback(pa_context *c, const pa_source_info *i, int snprintf(t, sizeof(t), "%u", i->monitor_of_sink); - pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); - printf("*** Source #%u ***\n" "Name: %s\n" - "Type: %s\n" + "Driver: %s\n" "Description: %s\n" "Sample Specification: %s\n" + "Channel Map: %s\n" "Owner Module: %u\n" "Monitor of Sink: %s\n" "Latency: %0.0f usec\n", i->index, - pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), + i->driver, i->name, i->description, - s, + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), i->owner_module, i->monitor_of_sink != PA_INVALID_INDEX ? t : "no", (double) i->latency); @@ -269,7 +269,7 @@ static void get_module_info_callback(pa_context *c, const pa_module_info *i, int } static void get_client_info_callback(pa_context *c, const pa_client_info *i, int is_last, void *userdata) { - char t[32], tid[5]; + char t[32]; if (is_last < 0) { fprintf(stderr, "Failed to get client information: %s\n", pa_strerror(pa_context_errno(c))); @@ -292,16 +292,16 @@ static void get_client_info_callback(pa_context *c, const pa_client_info *i, int printf("*** Client #%u ***\n" "Name: %s\n" - "Type: %s\n" + "Driver: %s\n" "Owner Module: %s\n", i->index, i->name, - pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), + i->driver, i->owner_module != PA_INVALID_INDEX ? t : "n/a"); } static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) { - char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], tid[5]; + char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; if (is_last < 0) { fprintf(stderr, "Failed to get sink input information: %s\n", pa_strerror(pa_context_errno(c))); @@ -320,29 +320,30 @@ static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info printf("\n"); nl = 1; - pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); snprintf(t, sizeof(t), "%u", i->owner_module); snprintf(k, sizeof(k), "%u", i->client); printf("*** Sink Input #%u ***\n" "Name: %s\n" - "Type: %s\n" + "Driver: %s\n" "Owner Module: %s\n" "Client: %s\n" "Sink: %u\n" "Sample Specification: %s\n" - "Volume: 0x%03x (%0.2f dB)\n" + "Channel Map: %s\n" + "Volume: %s\n" "Buffer Latency: %0.0f usec\n" "Sink Latency: %0.0f usec\n" "Resample method: %s\n", i->index, i->name, - pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), + i->driver, i->owner_module != PA_INVALID_INDEX ? t : "n/a", i->client != PA_INVALID_INDEX ? k : "n/a", i->sink, - s, - i->volume, pa_volume_to_dB(i->volume), + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), + pa_cvolume_snprint(cv, sizeof(cv), &i->volume), (double) i->buffer_usec, (double) i->sink_usec, i->resample_method ? i->resample_method : "n/a"); @@ -350,7 +351,7 @@ static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info static void get_source_output_info_callback(pa_context *c, const pa_source_output_info *i, int is_last, void *userdata) { - char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], tid[5]; + char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; if (is_last < 0) { fprintf(stderr, "Failed to get source output information: %s\n", pa_strerror(pa_context_errno(c))); @@ -369,34 +370,36 @@ static void get_source_output_info_callback(pa_context *c, const pa_source_outpu printf("\n"); nl = 1; - pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); + snprintf(t, sizeof(t), "%u", i->owner_module); snprintf(k, sizeof(k), "%u", i->client); printf("*** Source Output #%u ***\n" "Name: %s\n" - "Type: %s\n" + "Driver: %s\n" "Owner Module: %s\n" "Client: %s\n" "Source: %u\n" "Sample Specification: %s\n" + "Channel Map: %s\n" "Buffer Latency: %0.0f usec\n" "Source Latency: %0.0f usec\n" "Resample method: %s\n", i->index, i->name, - pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), + i->driver, i->owner_module != PA_INVALID_INDEX ? t : "n/a", i->client != PA_INVALID_INDEX ? k : "n/a", i->source, - s, + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), (double) i->buffer_usec, (double) i->source_usec, i->resample_method ? i->resample_method : "n/a"); } static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int is_last, void *userdata) { - char t[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX]; + char t[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; if (is_last < 0) { fprintf(stderr, "Failed to get sample information: %s\n", pa_strerror(pa_context_errno(c))); @@ -415,21 +418,23 @@ static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int printf("\n"); nl = 1; - pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); + pa_bytes_snprint(t, sizeof(t), i->bytes); printf("*** Sample #%u ***\n" "Name: %s\n" - "Volume: 0x%03x (%0.2f dB)\n" + "Volume: %s\n" "Sample Specification: %s\n" + "Channel Map: %s\n" "Duration: %0.1fs\n" "Size: %s\n" "Lazy: %s\n" "Filename: %s\n", i->index, i->name, - i->volume, pa_volume_to_dB(i->volume), - pa_sample_spec_valid(&i->sample_spec) ? s : "n/a", + pa_cvolume_snprint(cv, sizeof(cv), &i->volume), + pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : "n/a", + pa_sample_spec_valid(&i->sample_spec) ? pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map) : "n/a", (double) i->duration/1000000, t, i->lazy ? "yes" : "no", @@ -547,7 +552,7 @@ static void context_state_callback(pa_context *c, void *userdata) { break; case UPLOAD_SAMPLE: - sample_stream = pa_stream_new(c, sample_name, &sample_spec); + sample_stream = pa_stream_new(c, sample_name, &sample_spec, NULL); assert(sample_stream); pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL); diff --git a/polyp/paplay.c b/polyp/paplay.c index d9aa71a6..ddc1cbc1 100644 --- a/polyp/paplay.c +++ b/polyp/paplay.c @@ -155,21 +155,23 @@ static void context_state_callback(pa_context *c, void *userdata) { case PA_CONTEXT_SETTING_NAME: break; - case PA_CONTEXT_READY: + case PA_CONTEXT_READY: { + pa_cvolume cv; assert(c && !stream); if (verbose) fprintf(stderr, "Connection established.\n"); - stream = pa_stream_new(c, stream_name, &sample_spec); + stream = pa_stream_new(c, stream_name, &sample_spec, NULL); assert(stream); pa_stream_set_state_callback(stream, stream_state_callback, NULL); pa_stream_set_write_callback(stream, stream_write_callback, NULL); - pa_stream_connect_playback(stream, device, NULL, 0, volume); + pa_stream_connect_playback(stream, device, NULL, 0, pa_cvolume_set(&cv, PA_CHANNELS_MAX, volume)); break; + } case PA_CONTEXT_TERMINATED: quit(0); diff --git a/polyp/parec-simple.c b/polyp/parec-simple.c index 5f5abe11..524cc4f1 100644 --- a/polyp/parec-simple.c +++ b/polyp/parec-simple.c @@ -67,7 +67,7 @@ int main(PA_GCC_UNUSED int argc, char*argv[]) { int error; /* Create the recording stream */ - if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, 0, &error))) { + if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, &error))) { fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); goto finish; } diff --git a/polyp/parseaddr.h b/polyp/parseaddr.h index f0efd766..eff9dd3b 100644 --- a/polyp/parseaddr.h +++ b/polyp/parseaddr.h @@ -29,10 +29,10 @@ typedef enum pa_parsed_address_type { PA_PARSED_ADDRESS_TCP4, PA_PARSED_ADDRESS_TCP6, PA_PARSED_ADDRESS_TCP_AUTO -} pa_parsed_address_type; +} pa_parsed_address_type_t; typedef struct pa_parsed_address { - pa_parsed_address_type type; + pa_parsed_address_type_t type; char *path_or_host; uint16_t port; } pa_parsed_address; diff --git a/polyp/play-memchunk.c b/polyp/play-memchunk.c index c3db1462..e24d4427 100644 --- a/polyp/play-memchunk.c +++ b/polyp/play-memchunk.c @@ -33,8 +33,6 @@ #include "xmalloc.h" #include "gccmacro.h" -#define PA_TYPEID_MEMCHUNK PA_TYPEID_MAKE('M', 'C', 'N', 'K') - static void sink_input_kill(pa_sink_input *i) { pa_memchunk *c; assert(i && i->userdata); @@ -45,7 +43,6 @@ static void sink_input_kill(pa_sink_input *i) { pa_memblock_unref(c->memblock); pa_xfree(c); - } static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { @@ -82,24 +79,35 @@ static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t le pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i); } -int pa_play_memchunk(pa_sink *sink, const char *name, const pa_sample_spec *ss, const pa_memchunk *chunk, pa_volume_t volume) { +int pa_play_memchunk( + pa_sink *sink, + const char *name, + const pa_sample_spec *ss, + const pa_channel_map *map, + const pa_memchunk *chunk, + pa_cvolume *cvolume) { + pa_sink_input *si; pa_memchunk *nchunk; - assert(sink && chunk); + assert(sink); + assert(ss); + assert(chunk); - if (volume <= 0) + if (cvolume && pa_cvolume_is_muted(cvolume)) return 0; - if (!(si = pa_sink_input_new(sink, PA_TYPEID_MEMCHUNK, name, ss, 0, -1))) + if (!(si = pa_sink_input_new(sink, name, __FILE__, ss, map, 0, PA_RESAMPLER_INVALID))) return -1; - si->volume = volume; + if (cvolume) + si->volume = *cvolume; + si->peek = sink_input_peek; si->drop = sink_input_drop; si->kill = sink_input_kill; - si->userdata = nchunk = pa_xmalloc(sizeof(pa_memchunk)); + si->userdata = nchunk = pa_xnew(pa_memchunk, 1); *nchunk = *chunk; pa_memblock_ref(chunk->memblock); diff --git a/polyp/play-memchunk.h b/polyp/play-memchunk.h index 247cc870..fc0654a6 100644 --- a/polyp/play-memchunk.h +++ b/polyp/play-memchunk.h @@ -25,6 +25,12 @@ #include "sink.h" #include "memchunk.h" -int pa_play_memchunk(pa_sink *sink, const char *name, const pa_sample_spec *ss, const pa_memchunk *chunk, pa_volume_t volume); +int pa_play_memchunk( + pa_sink *sink, + const char *name, + const pa_sample_spec *ss, + const pa_channel_map *map, + const pa_memchunk *chunk, + pa_cvolume *cvolume); #endif diff --git a/polyp/poll.c b/polyp/poll.c index 6a260daf..193fc812 100644 --- a/polyp/poll.c +++ b/polyp/poll.c @@ -1,4 +1,4 @@ -/* $Id: mainloop.c 302 2004-11-21 17:02:25Z lennart $ */ +/* $Id$ */ /*** Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc. diff --git a/polyp/poll.h b/polyp/poll.h index 573f90ea..c201014e 100644 --- a/polyp/poll.h +++ b/polyp/poll.h @@ -1,4 +1,4 @@ -/* $Id: mainloop.c 302 2004-11-21 17:02:25Z lennart $ */ +/* $Id$ */ /*** Compatibility definitions for System V `poll' interface. diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 0cf32490..15f2e4cd 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -187,7 +187,7 @@ void pa_context_unref(pa_context *c) { context_free(c); } -void pa_context_set_state(pa_context *c, pa_context_state st) { +void pa_context_set_state(pa_context *c, pa_context_state_t st) { assert(c); if (c->state == st) @@ -644,7 +644,7 @@ void pa_context_disconnect(pa_context *c) { pa_context_set_state(c, PA_CONTEXT_TERMINATED); } -pa_context_state pa_context_get_state(pa_context *c) { +pa_context_state_t pa_context_get_state(pa_context *c) { assert(c && c->ref >= 1); return c->state; } diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h index 80c1b601..febb75f4 100644 --- a/polyp/polyplib-context.h +++ b/polyp/polyplib-context.h @@ -75,7 +75,7 @@ int pa_context_errno(pa_context *c); int pa_context_is_pending(pa_context *c); /** Return the current context status */ -pa_context_state pa_context_get_state(pa_context *c); +pa_context_state_t pa_context_get_state(pa_context *c); /** Connect the context to the specified server. If server is NULL, connect to the default server. This routine may but will not always diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index 499282c4..0591ce6c 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -43,7 +43,7 @@ typedef enum pa_context_state { PA_CONTEXT_READY, /**< The connection is established, the context is ready to execute operations */ PA_CONTEXT_FAILED, /**< The connection failed or was disconnected */ PA_CONTEXT_TERMINATED /**< The connection was terminated cleanly */ -} pa_context_state; +} pa_context_state_t; /** The state of a stream */ typedef enum pa_stream_state { @@ -52,14 +52,14 @@ typedef enum pa_stream_state { PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */ PA_STREAM_FAILED, /**< An error occured that made the stream invalid */ PA_STREAM_TERMINATED /**< The stream has been terminated cleanly */ -} pa_stream_state; +} pa_stream_state_t; /** The state of an operation */ typedef enum pa_operation_state { PA_OPERATION_RUNNING, /**< The operation is still running */ PA_OPERATION_DONE, /**< The operation has been completed */ PA_OPERATION_CANCELED /**< The operation has been canceled */ -} pa_operation_state; +} pa_operation_state_t; /** An invalid index */ #define PA_INVALID_INDEX ((uint32_t) -1) @@ -70,7 +70,7 @@ typedef enum pa_stream_direction { PA_STREAM_PLAYBACK, /**< Playback stream */ PA_STREAM_RECORD, /**< Record stream */ PA_STREAM_UPLOAD /**< Sample upload stream */ -} pa_stream_direction; +} pa_stream_direction_t; /** Some special flags for stream connections. \since 0.6 */ typedef enum pa_stream_flags { @@ -90,7 +90,7 @@ typedef enum pa_stream_flags { * information. This is * especially useful on long latency * network connections. */ -} pa_stream_flags; +} pa_stream_flags_t; /** Playback and record buffer metrics */ typedef struct pa_buffer_attr { @@ -133,7 +133,7 @@ typedef enum pa_subscription_mask { PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, /**< Sample cache events */ PA_SUBSCRIPTION_MASK_SERVER = 128, /**< Other global server changes. \since 0.4 */ PA_SUBSCRIPTION_MASK_AUTOLOAD = 256 /**< Autoload table events. \since 0.5 */ -} pa_subscription_mask; +} pa_subscription_mask_t; /** Subscription event types, as used by pa_context_subscribe() */ typedef enum pa_subscription_event_type { @@ -152,7 +152,7 @@ typedef enum pa_subscription_event_type { PA_SUBSCRIPTION_EVENT_CHANGE = 16, /**< A property of the object was modified */ PA_SUBSCRIPTION_EVENT_REMOVE = 32, /**< An object was removed */ PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32 /**< A mask to extract the event operation from an event value */ -} pa_subscription_event_type; +} pa_subscription_event_type_t; /** Return one if an event type t matches an event mask bitfield */ #define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 09f9473a..29596069 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -55,12 +55,12 @@ struct pa_context { uint32_t ctag; uint32_t error; - pa_context_state state; + pa_context_state_t state; void (*state_callback)(pa_context*c, void *userdata); void *state_userdata; - void (*subscribe_callback)(pa_context *c, pa_subscription_event_type t, uint32_t idx, void *userdata); + void (*subscribe_callback)(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata); void *subscribe_userdata; pa_memblock_stat *memblock_stat; @@ -86,15 +86,16 @@ struct pa_stream { char *name; pa_buffer_attr buffer_attr; pa_sample_spec sample_spec; + pa_channel_map channel_map; uint32_t channel; int channel_valid; uint32_t device_index; - pa_stream_direction direction; + pa_stream_direction_t direction; uint32_t requested_bytes; uint64_t counter; pa_usec_t previous_time; pa_usec_t previous_ipol_time; - pa_stream_state state; + pa_stream_state_t state; pa_mcalign *mcalign; int interpolate; @@ -123,7 +124,7 @@ struct pa_operation { pa_stream *stream; PA_LLIST_FIELDS(pa_operation); - pa_operation_state state; + pa_operation_state_t state; void *userdata; pa_operation_callback callback; }; @@ -141,11 +142,11 @@ void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); void pa_context_fail(pa_context *c, int error); -void pa_context_set_state(pa_context *c, pa_context_state st); +void pa_context_set_state(pa_context *c, pa_context_state_t st); int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t); pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, void (*internal_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata), void (*cb)(void), void *userdata); -void pa_stream_set_state(pa_stream *s, pa_stream_state st); +void pa_stream_set_state(pa_stream *s, pa_stream_state_t st); void pa_stream_trash_ipol(pa_stream *s); diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index 91105969..8c0c4449 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -128,12 +128,13 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_gets(t, &i.description) < 0 || pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.volume) < 0 || + pa_tagstruct_get_cvolume(t, &i.volume) < 0 || pa_tagstruct_getu32(t, &i.monitor_source) < 0 || pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || pa_tagstruct_get_usec(t, &i.latency) < 0 || - pa_tagstruct_getu32(t, &i._typeid) < 0) { + pa_tagstruct_gets(t, &i.driver) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; @@ -223,11 +224,12 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_gets(t, &i.description) < 0 || pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || pa_tagstruct_getu32(t, &i.owner_module) < 0 || pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 || pa_tagstruct_get_usec(t, &i.latency) < 0 || - pa_tagstruct_getu32(t, &i._typeid) < 0) { + pa_tagstruct_gets(t, &i.driver) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; @@ -316,7 +318,7 @@ static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i._typeid) < 0 ) { + pa_tagstruct_gets(t, &i.driver) < 0 ) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } @@ -452,11 +454,12 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm pa_tagstruct_getu32(t, &i.client) < 0 || pa_tagstruct_getu32(t, &i.sink) < 0 || pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.volume) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || + pa_tagstruct_get_cvolume(t, &i.volume) < 0 || pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || pa_tagstruct_gets(t, &i.resample_method) < 0 || - pa_tagstruct_getu32(t, &i._typeid) < 0) { + pa_tagstruct_gets(t, &i.driver) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; @@ -526,10 +529,11 @@ static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t c pa_tagstruct_getu32(t, &i.client) < 0 || pa_tagstruct_getu32(t, &i.source) < 0 || pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || pa_tagstruct_get_usec(t, &i.source_usec) < 0 || pa_tagstruct_gets(t, &i.resample_method) < 0 || - pa_tagstruct_getu32(t, &i._typeid) < 0) { + pa_tagstruct_gets(t, &i.driver) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; @@ -662,9 +666,10 @@ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_getu32(t, &i.volume) < 0 || + pa_tagstruct_get_cvolume(t, &i.volume) < 0 || pa_tagstruct_get_usec(t, &i.duration) < 0 || pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || pa_tagstruct_getu32(t, &i.bytes) < 0 || pa_tagstruct_get_boolean(t, &i.lazy) < 0 || pa_tagstruct_gets(t, &i.filename) < 0) { @@ -861,7 +866,7 @@ finish: pa_operation_unref(o); } -pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { +pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; @@ -933,8 +938,7 @@ finish: pa_operation_unref(o); } - -pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type type, const char *module, const char*argument, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { +pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; @@ -957,7 +961,7 @@ pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autolo return pa_operation_ref(o); } -pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { +pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index 2848e22f..10e6d0e3 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -27,7 +27,8 @@ #include #include #include -#include +#include +#include /** \file * @@ -52,13 +53,14 @@ typedef struct pa_sink_info { const char *name; /**< Name of the sink */ uint32_t index; /**< Index of the sink */ const char *description; /**< Description of this sink */ - pa_sample_spec sample_spec; /**< Sample spec of this sink */ + pa_sample_spec sample_spec; /**< Sample spec of this sink */ + pa_channel_map channel_map; /**< Channel map \since 0.9 */ uint32_t owner_module; /**< Index of the owning module of this sink, or PA_INVALID_INDEX */ - pa_volume_t volume; /**< Volume of the sink */ + pa_cvolume volume; /**< Volume of the sink */ uint32_t monitor_source; /**< Index of the monitor source connected to this sink */ const char *monitor_source_name; /**< The name of the monitor source */ pa_usec_t latency; /**< Length of filled playback buffer of this sink */ - pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ + const char *driver; /**< Driver name. \since 0.9 */ } pa_sink_info; /** Get information about a sink by its name */ @@ -75,12 +77,13 @@ typedef struct pa_source_info { const char *name ; /**< Name of the source */ uint32_t index; /**< Index of the source */ const char *description; /**< Description of this source */ - pa_sample_spec sample_spec; /**< Sample spec of this source */ + pa_sample_spec sample_spec; /**< Sample spec of this source */ + pa_channel_map channel_map; /**< Channel map \since 0.9 */ uint32_t owner_module; /**< Owning module index, or PA_INVALID_INDEX */ uint32_t monitor_of_sink; /**< If this is a monitor source the index of the owning sink, otherwise PA_INVALID_INDEX */ const char *monitor_of_sink_name; /**< Name of the owning sink, or PA_INVALID_INDEX */ pa_usec_t latency; /**< Length of filled record buffer of this source. \since 0.5 */ - pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ + const char *driver; /**< Driver name \since 0.9 */ } pa_source_info; /** Get information about a source by its name */ @@ -98,7 +101,7 @@ typedef struct pa_server_info { const char *host_name; /**< Host name the daemon is running on */ const char *server_version; /**< Version string of the daemon */ const char *server_name; /**< Server package name (usually "polypaudio") */ - pa_sample_spec sample_spec; /**< Default sample specification */ + pa_sample_spec sample_spec; /**< Default sample specification */ const char *default_sink_name; /**< Name of default sink. \since 0.4 */ const char *default_source_name; /**< Name of default sink. \since 0.4*/ uint32_t cookie; /**< A random cookie for identifying this instance of polypaudio. \since 0.8 */ @@ -127,7 +130,7 @@ typedef struct pa_client_info { uint32_t index; /**< Index of this client */ const char *name; /**< Name of this client */ uint32_t owner_module; /**< Index of the owning module, or PA_INVALID_INDEX */ - pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ + const char *driver; /**< Driver name \since 0.9 */ } pa_client_info; /** Get information about a client by its index */ @@ -143,12 +146,13 @@ typedef struct pa_sink_input_info { uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ uint32_t sink; /**< Index of the connected sink */ - pa_sample_spec sample_spec; /**< The sample specification of the sink input */ - pa_volume_t volume; /**< The volume of this sink input */ + pa_sample_spec sample_spec; /**< The sample specification of the sink input */ + pa_channel_map channel_map; /**< Channel map */ + pa_cvolume volume; /**< The volume of this sink input */ pa_usec_t buffer_usec; /**< Latency due to buffering in sink input, see pa_latency_info for details */ pa_usec_t sink_usec; /**< Latency of the sink device, see pa_latency_info for details */ const char *resample_method; /**< Thre resampling method used by this sink input. \since 0.7 */ - pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ + const char *driver; /**< Driver name \since 0.9 */ } pa_sink_input_info; /** Get some information about a sink input by its index */ @@ -164,11 +168,12 @@ typedef struct pa_source_output_info { uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ uint32_t source; /**< Index of the connected source */ - pa_sample_spec sample_spec; /**< The sample specification of the source output */ + pa_sample_spec sample_spec; /**< The sample specification of the source output */ + pa_channel_map channel_map; /**< Channel map */ pa_usec_t buffer_usec; /**< Latency due to buffering in the source output, see pa_latency_info for details. \since 0.5 */ pa_usec_t source_usec; /**< Latency of the source device, see pa_latency_info for details. \since 0.5 */ const char *resample_method; /**< Thre resampling method used by this source output. \since 0.7 */ - pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ + const char *driver; /**< Driver name \since 0.9 */ } pa_source_output_info; /** Get information about a source output by its index */ @@ -202,8 +207,9 @@ pa_operation* pa_context_stat(pa_context *c, void (*cb)(pa_context *c, const pa_ typedef struct pa_sample_info { uint32_t index; /**< Index of this entry */ const char *name; /**< Name of this entry */ - pa_volume_t volume; /**< Default volume of this entry */ - pa_sample_spec sample_spec; /**< Sample specification of the sampel */ + pa_cvolume volume; /**< Default volume of this entry */ + pa_sample_spec sample_spec; /**< Sample specification of the sample */ + pa_channel_map channel_map; /**< The channel map */ pa_usec_t duration; /**< Duration of this entry */ uint32_t bytes; /**< Length of this sample in bytes. \since 0.4 */ int lazy; /**< Non-zero when this is a lazy cache entry. \since 0.5 */ @@ -238,19 +244,19 @@ pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, void (*cb)(p typedef enum pa_autoload_type { PA_AUTOLOAD_SINK = 0, PA_AUTOLOAD_SOURCE = 1 -} pa_autoload_type; +} pa_autoload_type_t; /** Stores information about autoload entries. \since 0.5 */ typedef struct pa_autoload_info { uint32_t index; /**< Index of this autoload entry */ const char *name; /**< Name of the sink or source */ - pa_autoload_type type; /**< Type of the autoload entry */ + pa_autoload_type_t type; /**< Type of the autoload entry */ const char *module; /**< Module name to load */ const char *argument; /**< Argument string for module */ } pa_autoload_info; /** Get info about a specific autoload entry. \since 0.6 */ -pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); /** Get info about a specific autoload entry. \since 0.6 */ pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); @@ -259,10 +265,10 @@ pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, pa_operation* pa_context_get_autoload_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); /** Add a new autoload entry. \since 0.5 */ -pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type type, const char *module, const char*argument, void (*cb)(pa_context *c, int idx, void *userdata), void* userdata); +pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, void (*cb)(pa_context *c, int idx, void *userdata), void* userdata); /** Remove an autoload entry. \since 0.6 */ -pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata); +pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata); /** Remove an autoload entry. \since 0.6 */ pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void* userdata); diff --git a/polyp/polyplib-operation.c b/polyp/polyplib-operation.c index 3bee8cc7..68bc8c6a 100644 --- a/polyp/polyplib-operation.c +++ b/polyp/polyplib-operation.c @@ -62,7 +62,7 @@ void pa_operation_unref(pa_operation *o) { } } -static void operation_set_state(pa_operation *o, pa_operation_state st) { +static void operation_set_state(pa_operation *o, pa_operation_state_t st) { assert(o && o->ref >= 1); if (st == o->state) @@ -97,7 +97,7 @@ void pa_operation_done(pa_operation *o) { operation_set_state(o, PA_OPERATION_DONE); } -pa_operation_state pa_operation_get_state(pa_operation *o) { +pa_operation_state_t pa_operation_get_state(pa_operation *o) { assert(o && o->ref >= 1); return o->state; } diff --git a/polyp/polyplib-operation.h b/polyp/polyplib-operation.h index 63dcbc9f..cac03e30 100644 --- a/polyp/polyplib-operation.h +++ b/polyp/polyplib-operation.h @@ -44,7 +44,7 @@ void pa_operation_unref(pa_operation *o); void pa_operation_cancel(pa_operation *o); /** Return the current status of the operation */ -pa_operation_state pa_operation_get_state(pa_operation *o); +pa_operation_state_t pa_operation_get_state(pa_operation *o); PA_C_DECL_END diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c index b1357128..e5512152 100644 --- a/polyp/polyplib-simple.c +++ b/polyp/polyplib-simple.c @@ -39,7 +39,7 @@ struct pa_simple { pa_mainloop *mainloop; pa_context *context; pa_stream *stream; - pa_stream_direction direction; + pa_stream_direction_t direction; int dead; @@ -51,8 +51,8 @@ struct pa_simple { static void read_callback(pa_stream *s, const void*data, size_t length, void *userdata); static int check_error(pa_simple *p, int *rerror) { - pa_context_state cst; - pa_stream_state sst; + pa_context_state_t cst; + pa_stream_state_t sst; assert(p); if ((cst = pa_context_get_state(p->context)) == PA_CONTEXT_FAILED) @@ -118,12 +118,11 @@ static int iterate(pa_simple *p, int block, int *rerror) { pa_simple* pa_simple_new( const char *server, const char *name, - pa_stream_direction dir, + pa_stream_direction_t dir, const char *dev, const char *stream_name, const pa_sample_spec *ss, const pa_buffer_attr *attr, - pa_volume_t volume, int *rerror) { pa_simple *p; @@ -152,11 +151,11 @@ pa_simple* pa_simple_new( goto fail; } - if (!(p->stream = pa_stream_new(p->context, stream_name, ss))) + if (!(p->stream = pa_stream_new(p->context, stream_name, ss, NULL))) goto fail; if (dir == PA_STREAM_PLAYBACK) - pa_stream_connect_playback(p->stream, dev, attr, 0, volume); + pa_stream_connect_playback(p->stream, dev, attr, 0, NULL); else pa_stream_connect_record(p->stream, dev, attr, 0); diff --git a/polyp/polyplib-simple.h b/polyp/polyplib-simple.h index d1589115..0c80f460 100644 --- a/polyp/polyplib-simple.h +++ b/polyp/polyplib-simple.h @@ -49,12 +49,11 @@ typedef struct pa_simple pa_simple; pa_simple* pa_simple_new( const char *server, /**< Server name, or NULL for default */ const char *name, /**< A descriptive name for this client (application name, ...) */ - pa_stream_direction dir, /**< Open this stream for recording or playback? */ + pa_stream_direction_t dir, /**< Open this stream for recording or playback? */ const char *dev, /**< Sink (resp. source) name, or NULL for default */ const char *stream_name, /**< A descriptive name for this client (application name, song title, ...) */ const pa_sample_spec *ss, /**< The sample type to use */ const pa_buffer_attr *attr, /**< Buffering attributes, or NULL for default */ - pa_volume_t volume, /**< Initial volume. Only for playback streams. \since 0.5 */ int *error /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */ ); diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 6c8ed9c5..51ee6a22 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -36,11 +36,18 @@ #define LATENCY_IPOL_INTERVAL_USEC (10000L) -pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss) { +pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map) { pa_stream *s; - assert(c && ss); + assert(c); + assert(ss); - s = pa_xmalloc(sizeof(pa_stream)); + if (!pa_sample_spec_valid(ss)) + return NULL; + + if (map && !pa_channel_map_valid(map)) + return NULL; + + s = pa_xnew(pa_stream, 1); s->ref = 1; s->context = c; s->mainloop = c->mainloop; @@ -55,6 +62,12 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->direction = PA_STREAM_NODIRECTION; s->name = pa_xstrdup(name); s->sample_spec = *ss; + + if (map) + s->channel_map = *map; + else + pa_channel_map_init_auto(&s->channel_map, ss->channels); + s->channel = 0; s->channel_valid = 0; s->device_index = PA_INVALID_INDEX; @@ -108,7 +121,7 @@ pa_stream* pa_stream_ref(pa_stream *s) { return s; } -pa_stream_state pa_stream_get_state(pa_stream *s) { +pa_stream_state_t pa_stream_get_state(pa_stream *s) { assert(s && s->ref >= 1); return s->state; } @@ -123,7 +136,7 @@ uint32_t pa_stream_get_index(pa_stream *s) { return s->device_index; } -void pa_stream_set_state(pa_stream *s, pa_stream_state st) { +void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { assert(s && s->ref >= 1); if (s->state == st) @@ -271,7 +284,7 @@ finish: pa_stream_unref(s); } -static void create_stream(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags flags, pa_volume_t volume) { +static void create_stream(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags, const pa_cvolume *volume) { pa_tagstruct *t; uint32_t tag; assert(s && s->ref >= 1 && s->state == PA_STREAM_DISCONNECTED); @@ -308,15 +321,23 @@ static void create_stream(pa_stream *s, const char *dev, const pa_buffer_attr *a pa_tagstruct_putu32(t, tag = s->context->ctag++); pa_tagstruct_puts(t, s->name); pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_put_channel_map(t, &s->channel_map); pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, dev); pa_tagstruct_putu32(t, s->buffer_attr.maxlength); pa_tagstruct_put_boolean(t, !!(flags & PA_STREAM_START_CORKED)); if (s->direction == PA_STREAM_PLAYBACK) { + pa_cvolume cv; pa_tagstruct_putu32(t, s->buffer_attr.tlength); pa_tagstruct_putu32(t, s->buffer_attr.prebuf); pa_tagstruct_putu32(t, s->buffer_attr.minreq); - pa_tagstruct_putu32(t, volume); + + if (!volume) { + pa_cvolume_reset(&cv, s->sample_spec.channels); + volume = &cv; + } + + pa_tagstruct_put_cvolume(t, volume); } else pa_tagstruct_putu32(t, s->buffer_attr.fragsize); @@ -326,13 +347,13 @@ static void create_stream(pa_stream *s, const char *dev, const pa_buffer_attr *a pa_stream_unref(s); } -void pa_stream_connect_playback(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags flags, pa_volume_t volume) { +void pa_stream_connect_playback(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags, pa_cvolume *volume) { assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); s->direction = PA_STREAM_PLAYBACK; create_stream(s, dev, attr, flags, volume); } -void pa_stream_connect_record(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags flags) { +void pa_stream_connect_record(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags) { assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); s->direction = PA_STREAM_RECORD; create_stream(s, dev, attr, flags, 0); diff --git a/polyp/polyplib-stream.h b/polyp/polyplib-stream.h index 806579f5..bc828b71 100644 --- a/polyp/polyplib-stream.h +++ b/polyp/polyplib-stream.h @@ -25,6 +25,8 @@ #include #include +#include +#include #include #include #include @@ -39,7 +41,7 @@ PA_C_DECL_BEGIN typedef struct pa_stream pa_stream; /** Create a new, unconnected stream with the specified name and sample type */ -pa_stream* pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss); +pa_stream* pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map); /** Decrease the reference counter by one */ void pa_stream_unref(pa_stream *s); @@ -48,7 +50,7 @@ void pa_stream_unref(pa_stream *s); pa_stream *pa_stream_ref(pa_stream *s); /** Return the current state of the stream */ -pa_stream_state pa_stream_get_state(pa_stream *p); +pa_stream_state_t pa_stream_get_state(pa_stream *p); /** Return the context this stream is attached to */ pa_context* pa_stream_get_context(pa_stream *p); @@ -57,10 +59,19 @@ pa_context* pa_stream_get_context(pa_stream *p); uint32_t pa_stream_get_index(pa_stream *s); /** Connect the stream to a sink */ -void pa_stream_connect_playback(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags flags, pa_volume_t volume); +void pa_stream_connect_playback( + pa_stream *s, + const char *dev, + const pa_buffer_attr *attr, + pa_stream_flags_t flags, + pa_cvolume *volume); /** Connect the stream to a source */ -void pa_stream_connect_record(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags flags); +void pa_stream_connect_record( + pa_stream *s, + const char *dev, + const pa_buffer_attr *attr, + pa_stream_flags_t flags); /** Disconnect a stream from a source/sink */ void pa_stream_disconnect(pa_stream *s); diff --git a/polyp/polyplib-subscribe.c b/polyp/polyplib-subscribe.c index 69ae588f..ef90ab0b 100644 --- a/polyp/polyplib-subscribe.c +++ b/polyp/polyplib-subscribe.c @@ -33,7 +33,7 @@ void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_context *c = userdata; - pa_subscription_event_type e; + pa_subscription_event_type_t e; uint32_t index; assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); @@ -54,7 +54,7 @@ finish: } -pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask m, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { +pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; @@ -74,7 +74,7 @@ pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask m, void ( return pa_operation_ref(o); } -void pa_context_set_subscribe_callback(pa_context *c, void (*cb)(pa_context *c, pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { +void pa_context_set_subscribe_callback(pa_context *c, void (*cb)(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata) { assert(c); c->subscribe_callback = cb; c->subscribe_userdata = userdata; diff --git a/polyp/polyplib-subscribe.h b/polyp/polyplib-subscribe.h index f2760ee6..920c9853 100644 --- a/polyp/polyplib-subscribe.h +++ b/polyp/polyplib-subscribe.h @@ -37,10 +37,10 @@ PA_C_DECL_BEGIN /** Enable event notification */ -pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask m, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); /** Set the context specific call back function that is called whenever the state of the daemon changes */ -void pa_context_set_subscribe_callback(pa_context *c, void (*cb)(pa_context *c, pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); +void pa_context_set_subscribe_callback(pa_context *c, void (*cb)(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata); PA_C_DECL_END diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index a97bc25c..ce183a6f 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -64,8 +64,6 @@ #define SCACHE_PREFIX "esound." -#define PA_TYPEID_ESOUND PA_TYPEID_MAKE('E', 'S', 'D', 'P') - /* This is heavily based on esound's code */ struct connection { @@ -326,7 +324,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t assert(!c->sink_input && !c->input_memblockq); - if (!(c->sink_input = pa_sink_input_new(sink, PA_TYPEID_ESOUND, name, &ss, 0, -1))) { + if (!(c->sink_input = pa_sink_input_new(sink, __FILE__, name, &ss, NULL, 0, -1))) { pa_log(__FILE__": failed to create sink input.\n"); return -1; } @@ -398,7 +396,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co assert(!c->output_memblockq && !c->source_output); - if (!(c->source_output = pa_source_output_new(source, PA_TYPEID_ESOUND, name, &ss, -1))) { + if (!(c->source_output = pa_source_output_new(source, __FILE__, name, &ss, NULL, -1))) { pa_log(__FILE__": failed to create source output\n"); return -1; } @@ -476,7 +474,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v assert(k); for (conn = pa_idxset_first(c->protocol->connections, &idx); conn; conn = pa_idxset_next(c->protocol->connections, &idx)) { - int format = ESD_BITS16 | ESD_STEREO, rate = 44100, volume = 0xFF; + int format = ESD_BITS16 | ESD_STEREO, rate = 44100, lvolume = 0xFF, rvolume = 0xFF; if (conn->state != ESD_STREAMING_DATA) continue; @@ -485,7 +483,8 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v if (conn->sink_input) { rate = conn->sink_input->sample_spec.rate; - volume = (conn->sink_input->volume*0xFF)/0x100; + lvolume = (conn->sink_input->volume.values[0]*0xFF)/0x100; + rvolume = (conn->sink_input->volume.values[1]*0xFF)/0x100; format = format_native2esd(&conn->sink_input->sample_spec); } @@ -503,11 +502,11 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v response += sizeof(int); /* left */ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, volume); + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, lvolume); response += sizeof(int); /*right*/ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, volume); + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, rvolume); response += sizeof(int); /*format*/ @@ -545,11 +544,11 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v response += sizeof(int); /* left */ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (ce->volume*0xFF)/0x100); + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (ce->volume.values[0]*0xFF)/0x100); response += sizeof(int); /*right*/ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (ce->volume*0xFF)/0x100); + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (ce->volume.values[0]*0xFF)/0x100); response += sizeof(int); /*format*/ @@ -572,20 +571,25 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { int *ok; - uint32_t idx, volume; + uint32_t idx; + pa_volume_t lvolume, rvolume; struct connection *conn; assert(c && data && length == sizeof(int)*3); idx = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *(const int*)data)-1; - volume = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *((const int*)data + 1)); - volume = (volume*0x100)/0xFF; + lvolume = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *((const int*)data + 1)); + lvolume = (lvolume*0x100)/0xFF; + rvolume = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *((const int*)data + 2)); + rvolume = (rvolume*0x100)/0xFF; ok = connection_write(c, sizeof(int)); assert(ok); if ((conn = pa_idxset_get_by_index(c->protocol->connections, idx))) { assert(conn->sink_input); - conn->sink_input->volume = volume; + conn->sink_input->volume.values[0] = lvolume; + conn->sink_input->volume.values[1] = rvolume; + conn->sink_input->volume.channels = 2; *ok = 1; } else *ok = 0; @@ -627,7 +631,7 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ c->state = ESD_CACHING_SAMPLE; - pa_scache_add_item(c->protocol->core, c->scache.name, NULL, NULL, &idx); + pa_scache_add_item(c->protocol->core, c->scache.name, NULL, NULL, NULL, &idx); ok = connection_write(c, sizeof(int)); assert(ok); @@ -676,7 +680,7 @@ static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t reque pa_sink *sink; if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) - if (pa_scache_play_item(c->protocol->core, name, sink, PA_VOLUME_NORM) >= 0) + if (pa_scache_play_item(c->protocol->core, name, sink, NULL) >= 0) *ok = (int) idx+1; } else { assert(request == ESD_PROTO_SAMPLE_FREE); @@ -801,7 +805,7 @@ static int do_read(struct connection *c) { int *ok; c->scache.memchunk.index = 0; - pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, &c->scache.memchunk, &idx); + pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, NULL, &c->scache.memchunk, &idx); pa_memblock_unref(c->scache.memchunk.memblock); c->scache.memchunk.memblock = NULL; @@ -1067,7 +1071,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); assert(p->core); - c->client = pa_client_new(p->core, PA_TYPEID_ESOUND, cname); + c->client = pa_client_new(p->core, __FILE__, cname); assert(c->client); c->client->owner = p->module; c->client->kill = client_kill_cb; diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index b19d30d9..0491dc41 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -56,8 +56,6 @@ /* Don't accept more connection than this */ #define MAX_CONNECTIONS 10 -#define PA_TYPEID_NATIVE PA_TYPEID_MAKE('N', 'A', 'T', 'V') - struct connection; struct pa_protocol_native; @@ -88,6 +86,7 @@ struct upload_stream { size_t length; char *name; pa_sample_spec sample_spec; + pa_channel_map channel_map; }; struct output_stream { @@ -235,7 +234,12 @@ static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { /* structure management */ -static struct upload_stream* upload_stream_new(struct connection *c, const pa_sample_spec *ss, const char *name, size_t length) { +static struct upload_stream* upload_stream_new( + struct connection *c, + const pa_sample_spec *ss, + const pa_channel_map *map, + const char *name, size_t length) { + struct upload_stream *s; assert(c && ss && name && length); @@ -243,6 +247,7 @@ static struct upload_stream* upload_stream_new(struct connection *c, const pa_sa s->type = UPLOAD_STREAM; s->connection = c; s->sample_spec = *ss; + s->channel_map = *map; s->name = pa_xstrdup(name); s->memchunk.memblock = NULL; @@ -268,13 +273,21 @@ static void upload_stream_free(struct upload_stream *o) { pa_xfree(o); } -static struct record_stream* record_stream_new(struct connection *c, pa_source *source, const pa_sample_spec *ss, const char *name, size_t maxlength, size_t fragment_size) { +static struct record_stream* record_stream_new( + struct connection *c, + pa_source *source, + const pa_sample_spec *ss, + const pa_channel_map *map, + const char *name, + size_t maxlength, + size_t fragment_size) { + struct record_stream *s; pa_source_output *source_output; size_t base; assert(c && source && ss && name && maxlength); - if (!(source_output = pa_source_output_new(source, PA_TYPEID_NATIVE, name, ss, -1))) + if (!(source_output = pa_source_output_new(source, __FILE__, name, ss, map, -1))) return NULL; s = pa_xmalloc(sizeof(struct record_stream)); @@ -308,17 +321,23 @@ static void record_stream_free(struct record_stream* r) { pa_xfree(r); } -static struct playback_stream* playback_stream_new(struct connection *c, pa_sink *sink, const pa_sample_spec *ss, const char *name, - size_t maxlength, - size_t tlength, - size_t prebuf, - size_t minreq, - pa_volume_t volume) { +static struct playback_stream* playback_stream_new( + struct connection *c, + pa_sink *sink, + const pa_sample_spec *ss, + const pa_channel_map *map, + const char *name, + size_t maxlength, + size_t tlength, + size_t prebuf, + size_t minreq, + pa_cvolume *volume) { + struct playback_stream *s; pa_sink_input *sink_input; assert(c && sink && ss && name && maxlength); - if (!(sink_input = pa_sink_input_new(sink, PA_TYPEID_NATIVE, name, ss, 0, -1))) + if (!(sink_input = pa_sink_input_new(sink, __FILE__, name, ss, map, 0, -1))) return NULL; s = pa_xmalloc(sizeof(struct playback_stream)); @@ -340,7 +359,7 @@ static struct playback_stream* playback_stream_new(struct connection *c, pa_sink s->requested_bytes = 0; s->drain_request = 0; - s->sink_input->volume = volume; + s->sink_input->volume = *volume; pa_idxset_put(c->output_streams, s, &s->index); return s; @@ -561,14 +580,17 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC uint32_t sink_index; const char *name, *sink_name; pa_sample_spec ss; + pa_channel_map map; pa_tagstruct *reply; pa_sink *sink; - pa_volume_t volume; + pa_cvolume volume; int corked; + assert(c && t && c->protocol && c->protocol->core); if (pa_tagstruct_gets(t, &name) < 0 || !name || pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_get_channel_map(t, &map) < 0 || pa_tagstruct_getu32(t, &sink_index) < 0 || pa_tagstruct_gets(t, &sink_name) < 0 || pa_tagstruct_getu32(t, &maxlength) < 0 || @@ -576,13 +598,12 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC pa_tagstruct_getu32(t, &tlength) < 0 || pa_tagstruct_getu32(t, &prebuf) < 0 || pa_tagstruct_getu32(t, &minreq) < 0 || - pa_tagstruct_getu32(t, &volume) < 0 || + pa_tagstruct_get_cvolume(t, &volume) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; } - if (!c->authorized) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); return; @@ -599,7 +620,7 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC return; } - if (!(s = playback_stream_new(c, sink, &ss, name, maxlength, tlength, prebuf, minreq, volume))) { + if (!(s = playback_stream_new(c, sink, &ss, &map, name, maxlength, tlength, prebuf, minreq, &volume))) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); return; } @@ -671,6 +692,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ uint32_t source_index; const char *name, *source_name; pa_sample_spec ss; + pa_channel_map map; pa_tagstruct *reply; pa_source *source; int corked; @@ -678,6 +700,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ if (pa_tagstruct_gets(t, &name) < 0 || !name || pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_get_channel_map(t, &map) < 0 || pa_tagstruct_getu32(t, &source_index) < 0 || pa_tagstruct_gets(t, &source_name) < 0 || pa_tagstruct_getu32(t, &maxlength) < 0 || @@ -703,7 +726,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ return; } - if (!(s = record_stream_new(c, source, &ss, name, maxlength, fragment_size))) { + if (!(s = record_stream_new(c, source, &ss, &map, name, maxlength, fragment_size))) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); return; } @@ -984,11 +1007,13 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ size_t length; const char *name; pa_sample_spec ss; + pa_channel_map map; pa_tagstruct *reply; assert(c && t && c->protocol && c->protocol->core); if (pa_tagstruct_gets(t, &name) < 0 || !name || pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_get_channel_map(t, &map) < 0 || pa_tagstruct_getu32(t, &length) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1005,7 +1030,7 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ return; } - if (!(s = upload_stream_new(c, &ss, name, length))) { + if (!(s = upload_stream_new(c, &ss, &map, name, length))) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); return; } @@ -1042,21 +1067,22 @@ static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ return; } - pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->memchunk, &idx); + pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, &idx); pa_pstream_send_simple_ack(c->pstream, tag); upload_stream_free(s); } static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - uint32_t sink_index, volume; + uint32_t sink_index; + pa_cvolume volume; pa_sink *sink; const char *name, *sink_name; assert(c && t); if (pa_tagstruct_getu32(t, &sink_index) < 0 || pa_tagstruct_gets(t, &sink_name) < 0 || - pa_tagstruct_getu32(t, &volume) < 0 || + pa_tagstruct_get_cvolume(t, &volume) < 0 || pa_tagstruct_gets(t, &name) < 0 || !name || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1078,7 +1104,7 @@ static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui return; } - if (pa_scache_play_item(c->protocol->core, name, sink, volume) < 0) { + if (pa_scache_play_item(c->protocol->core, name, sink, &volume) < 0) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -1116,12 +1142,13 @@ static void sink_fill_tagstruct(pa_tagstruct *t, pa_sink *sink) { pa_tagstruct_puts(t, sink->name); pa_tagstruct_puts(t, sink->description); pa_tagstruct_put_sample_spec(t, &sink->sample_spec); + pa_tagstruct_put_channel_map(t, &sink->channel_map); pa_tagstruct_putu32(t, sink->owner ? sink->owner->index : (uint32_t) -1); - pa_tagstruct_putu32(t, sink->volume); + pa_tagstruct_put_cvolume(t, pa_sink_get_volume(sink, PA_MIXER_HARDWARE)); pa_tagstruct_putu32(t, sink->monitor_source->index); pa_tagstruct_puts(t, sink->monitor_source->name); pa_tagstruct_put_usec(t, pa_sink_get_latency(sink)); - pa_tagstruct_putu32(t, sink->typeid); + pa_tagstruct_puts(t, sink->driver); } static void source_fill_tagstruct(pa_tagstruct *t, pa_source *source) { @@ -1130,11 +1157,12 @@ static void source_fill_tagstruct(pa_tagstruct *t, pa_source *source) { pa_tagstruct_puts(t, source->name); pa_tagstruct_puts(t, source->description); pa_tagstruct_put_sample_spec(t, &source->sample_spec); + pa_tagstruct_put_channel_map(t, &source->channel_map); pa_tagstruct_putu32(t, source->owner ? source->owner->index : (uint32_t) -1); pa_tagstruct_putu32(t, source->monitor_of ? source->monitor_of->index : (uint32_t) -1); pa_tagstruct_puts(t, source->monitor_of ? source->monitor_of->name : NULL); pa_tagstruct_put_usec(t, pa_source_get_latency(source)); - pa_tagstruct_putu32(t, source->typeid); + pa_tagstruct_puts(t, source->driver); } static void client_fill_tagstruct(pa_tagstruct *t, pa_client *client) { @@ -1142,7 +1170,7 @@ static void client_fill_tagstruct(pa_tagstruct *t, pa_client *client) { pa_tagstruct_putu32(t, client->index); pa_tagstruct_puts(t, client->name); pa_tagstruct_putu32(t, client->owner ? client->owner->index : (uint32_t) -1); - pa_tagstruct_putu32(t, client->typeid); + pa_tagstruct_puts(t, client->driver); } static void module_fill_tagstruct(pa_tagstruct *t, pa_module *module) { @@ -1162,11 +1190,12 @@ static void sink_input_fill_tagstruct(pa_tagstruct *t, pa_sink_input *s) { pa_tagstruct_putu32(t, s->client ? s->client->index : (uint32_t) -1); pa_tagstruct_putu32(t, s->sink->index); pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, s->volume); + pa_tagstruct_put_channel_map(t, &s->channel_map); + pa_tagstruct_put_cvolume(t, &s->volume); pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s)); pa_tagstruct_put_usec(t, pa_sink_get_latency(s->sink)); pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s))); - pa_tagstruct_putu32(t, s->typeid); + pa_tagstruct_puts(t, s->driver); } static void source_output_fill_tagstruct(pa_tagstruct *t, pa_source_output *s) { @@ -1177,19 +1206,21 @@ static void source_output_fill_tagstruct(pa_tagstruct *t, pa_source_output *s) { pa_tagstruct_putu32(t, s->client ? s->client->index : (uint32_t) -1); pa_tagstruct_putu32(t, s->source->index); pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_put_channel_map(t, &s->channel_map); pa_tagstruct_put_usec(t, pa_source_output_get_latency(s)); pa_tagstruct_put_usec(t, pa_source_get_latency(s->source)); pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s))); - pa_tagstruct_putu32(t, s->typeid); + pa_tagstruct_puts(t, s->driver); } static void scache_fill_tagstruct(pa_tagstruct *t, pa_scache_entry *e) { assert(t && e); pa_tagstruct_putu32(t, e->index); pa_tagstruct_puts(t, e->name); - pa_tagstruct_putu32(t, e->volume); + pa_tagstruct_put_cvolume(t, &e->volume); pa_tagstruct_put_usec(t, pa_bytes_to_usec(e->memchunk.length, &e->sample_spec)); pa_tagstruct_put_sample_spec(t, &e->sample_spec); + pa_tagstruct_put_channel_map(t, &e->channel_map); pa_tagstruct_putu32(t, e->memchunk.length); pa_tagstruct_put_boolean(t, e->lazy); pa_tagstruct_puts(t, e->filename); @@ -1379,7 +1410,7 @@ static void command_get_server_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE pa_pstream_send_tagstruct(c->pstream, reply); } -static void subscription_cb(pa_core *core, pa_subscription_event_type e, uint32_t idx, void *userdata) { +static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) { pa_tagstruct *t; struct connection *c = userdata; assert(c && core); @@ -1395,7 +1426,7 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type e, uint32_ static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - pa_subscription_mask m; + pa_subscription_mask_t m; assert(c && t); if (pa_tagstruct_getu32(t, &m) < 0 || @@ -1423,7 +1454,8 @@ static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint static void command_set_volume(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - uint32_t idx, volume; + uint32_t idx; + pa_cvolume volume; pa_sink *sink = NULL; pa_sink_input *si = NULL; const char *name = NULL; @@ -1431,7 +1463,7 @@ static void command_set_volume(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, if (pa_tagstruct_getu32(t, &idx) < 0 || (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) || - pa_tagstruct_getu32(t, &volume) || + pa_tagstruct_get_cvolume(t, &volume) || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1458,9 +1490,9 @@ static void command_set_volume(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, } if (sink) - pa_sink_set_volume(sink, volume); + pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &volume); else if (si) - pa_sink_input_set_volume(si, volume); + pa_sink_input_set_volume(si, &volume); pa_pstream_send_simple_ack(c->pstream, tag); } @@ -2032,7 +2064,7 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo c->protocol = p; assert(p->core); - c->client = pa_client_new(p->core, PA_TYPEID_NATIVE, "Client"); + c->client = pa_client_new(p->core, __FILE__, "Client"); assert(c->client); c->client->kill = client_kill_cb; c->client->userdata = c; diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index a3d7099c..113919b3 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -42,8 +42,6 @@ /* Don't allow more than this many concurrent connections */ #define MAX_CONNECTIONS 10 -#define PA_TYPEID_SIMPLE PA_TYPEID_MAKE('S', 'M', 'P', 'L') - struct connection { pa_protocol_simple *protocol; pa_iochannel *io; @@ -310,7 +308,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->playback.fragment_size = 0; pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); - c->client = pa_client_new(p->core, PA_TYPEID_SIMPLE, cname); + c->client = pa_client_new(p->core, __FILE__, cname); assert(c->client); c->client->owner = p->module; c->client->kill = client_kill_cb; @@ -325,7 +323,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) goto fail; } - if (!(c->sink_input = pa_sink_input_new(sink, PA_TYPEID_SIMPLE, c->client->name, &p->sample_spec, 0, -1))) { + if (!(c->sink_input = pa_sink_input_new(sink, __FILE__, c->client->name, &p->sample_spec, NULL, 0, -1))) { pa_log(__FILE__": Failed to create sink input.\n"); goto fail; } @@ -355,7 +353,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) goto fail; } - c->source_output = pa_source_output_new(source, PA_TYPEID_SIMPLE, c->client->name, &p->sample_spec, -1); + c->source_output = pa_source_output_new(source, __FILE__, c->client->name, &p->sample_spec, NULL, -1); if (!c->source_output) { pa_log(__FILE__": Failed to create source output.\n"); goto fail; diff --git a/polyp/resampler.c b/polyp/resampler.c index 96a1678f..0417e44e 100644 --- a/polyp/resampler.c +++ b/polyp/resampler.c @@ -27,6 +27,8 @@ #include #include +#include +#include #include "resampler.h" #include "sconv.h" @@ -34,24 +36,28 @@ #include "log.h" struct pa_resampler { + pa_resample_method_t resample_method; pa_sample_spec i_ss, o_ss; + pa_channel_map i_cm, o_cm; size_t i_fz, o_fz; pa_memblock_stat *memblock_stat; - void *impl_data; - int channels; - pa_resample_method resample_method; void (*impl_free)(pa_resampler *r); - void (*impl_set_input_rate)(pa_resampler *r, uint32_t rate); + void (*impl_update_input_rate)(pa_resampler *r, uint32_t rate); void (*impl_run)(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out); + void *impl_data; }; struct impl_libsamplerate { - float* i_buf, *o_buf; - unsigned i_alloc, o_alloc; + float* buf1, *buf2, *buf3, *buf4; + unsigned buf1_samples, buf2_samples, buf3_samples, buf4_samples; + pa_convert_to_float32ne_func_t to_float32ne_func; pa_convert_from_float32ne_func_t from_float32ne_func; SRC_STATE *src_state; + + int map_table[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; + int map_required; }; struct impl_trivial { @@ -62,35 +68,54 @@ struct impl_trivial { static int libsamplerate_init(pa_resampler*r); static int trivial_init(pa_resampler*r); -pa_resampler* pa_resampler_new(const pa_sample_spec *a, const pa_sample_spec *b, pa_memblock_stat *s, pa_resample_method resample_method) { +pa_resampler* pa_resampler_new( + const pa_sample_spec *a, + const pa_channel_map *am, + const pa_sample_spec *b, + const pa_channel_map *bm, + pa_memblock_stat *s, + pa_resample_method_t resample_method) { + pa_resampler *r = NULL; - assert(a && b && pa_sample_spec_valid(a) && pa_sample_spec_valid(b) && resample_method != PA_RESAMPLER_INVALID); - if (a->channels != b->channels && a->channels != 1 && b->channels != 1) - goto fail; + assert(a); + assert(b); + assert(pa_sample_spec_valid(a)); + assert(pa_sample_spec_valid(b)); + assert(resample_method != PA_RESAMPLER_INVALID); - r = pa_xmalloc(sizeof(pa_resampler)); + r = pa_xnew(pa_resampler, 1); r->impl_data = NULL; r->memblock_stat = s; r->resample_method = resample_method; r->impl_free = NULL; - r->impl_set_input_rate = NULL; + r->impl_update_input_rate = NULL; r->impl_run = NULL; /* Fill sample specs */ r->i_ss = *a; r->o_ss = *b; + if (am) + r->i_cm = *am; + else + pa_channel_map_init_auto(&r->i_cm, r->i_ss.channels); + + if (bm) + r->o_cm = *bm; + else + pa_channel_map_init_auto(&r->o_cm, r->o_ss.channels); + r->i_fz = pa_frame_size(a); r->o_fz = pa_frame_size(b); - r->channels = a->channels; - if (b->channels < r->channels) - r->channels = b->channels; - /* Choose implementation */ - if (a->channels != b->channels || a->format != b->format || resample_method != PA_RESAMPLER_TRIVIAL) { + if (a->channels != b->channels || + a->format != b->format || + !pa_channel_map_equal(&r->i_cm, &r->o_cm) || + resample_method != PA_RESAMPLER_TRIVIAL) { + /* Use the libsamplerate based resampler for the complicated cases */ if (resample_method == PA_RESAMPLER_TRIVIAL) r->resample_method = PA_RESAMPLER_SRC_ZERO_ORDER_HOLD; @@ -123,11 +148,16 @@ void pa_resampler_free(pa_resampler *r) { } void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate) { - assert(r && rate); + assert(r); + assert(rate > 0); + if (r->i_ss.rate == rate) + return; + r->i_ss.rate = rate; - if (r->impl_set_input_rate) - r->impl_set_input_rate(r, rate); + + if (r->impl_update_input_rate) + r->impl_update_input_rate(r, rate); } void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { @@ -141,168 +171,342 @@ size_t pa_resampler_request(pa_resampler *r, size_t out_length) { return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz; } -pa_resample_method pa_resampler_get_method(pa_resampler *r) { +pa_resample_method_t pa_resampler_get_method(pa_resampler *r) { assert(r); return r->resample_method; } -/* Parse a libsamplrate compatible resampling implementation */ -pa_resample_method pa_parse_resample_method(const char *string) { +static const char * const resample_methods[] = { + "src-sinc-best-quality", + "src-sinc-medium-quality", + "src-sinc-fastest", + "src-zero-order-hold", + "src-linear", + "trivial" +}; + +const char *pa_resample_method_to_string(pa_resample_method_t m) { + + if (m < 0 || m >= PA_RESAMPLER_MAX) + return NULL; + + return resample_methods[m]; +} + +pa_resample_method_t pa_parse_resample_method(const char *string) { + pa_resample_method_t m; + assert(string); - if (!strcmp(string, "src-sinc-best-quality")) - return PA_RESAMPLER_SRC_SINC_BEST_QUALITY; - else if (!strcmp(string, "src-sinc-medium-quality")) - return PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY; - else if (!strcmp(string, "src-sinc-fastest")) - return PA_RESAMPLER_SRC_SINC_FASTEST; - else if (!strcmp(string, "src-zero-order-hold")) - return PA_RESAMPLER_SRC_ZERO_ORDER_HOLD; - else if (!strcmp(string, "src-linear")) - return PA_RESAMPLER_SRC_LINEAR; - else if (!strcmp(string, "trivial")) - return PA_RESAMPLER_TRIVIAL; - else - return PA_RESAMPLER_INVALID; + for (m = 0; m < PA_RESAMPLER_MAX; m++) + if (!strcmp(string, resample_methods[m])) + return m; + + return PA_RESAMPLER_INVALID; } + /*** libsamplerate based implementation ***/ static void libsamplerate_free(pa_resampler *r) { - struct impl_libsamplerate *i; - assert(r && r->impl_data); - i = r->impl_data; + struct impl_libsamplerate *u; + + assert(r); + assert(r->impl_data); - if (i->src_state) - src_delete(i->src_state); + u = r->impl_data; + + if (u->src_state) + src_delete(u->src_state); + + pa_xfree(u->buf1); + pa_xfree(u->buf2); + pa_xfree(u->buf3); + pa_xfree(u->buf4); + pa_xfree(u); +} + +static void calc_map_table(pa_resampler *r) { + struct impl_libsamplerate *u; + unsigned oc; + assert(r); + assert(r->impl_data); - pa_xfree(i->i_buf); - pa_xfree(i->o_buf); - pa_xfree(i); + u = r->impl_data; + + if (!(u->map_required = (!pa_channel_map_equal(&r->i_cm, &r->o_cm) || r->i_ss.channels != r->o_ss.channels))) + return; + + for (oc = 0; oc < r->o_ss.channels; oc++) { + unsigned ic, i = 0; + + for (ic = 0; ic < r->i_ss.channels; ic++) { + pa_channel_position_t a, b; + + a = r->i_cm.map[ic]; + b = r->o_cm.map[oc]; + + if (a == b || + (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_LEFT) || + (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_RIGHT) || + (a == PA_CHANNEL_POSITION_LEFT && b == PA_CHANNEL_POSITION_MONO) || + (a == PA_CHANNEL_POSITION_RIGHT && b == PA_CHANNEL_POSITION_MONO)) + + u->map_table[oc][i++] = ic; + } + + /* Add an end marker */ + if (i < PA_CHANNELS_MAX) + u->map_table[oc][i] = -1; + } } -static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { - unsigned i_nchannels, o_nchannels, ins, ons, eff_ins, eff_ons; - float *cbuf; - struct impl_libsamplerate *i; - assert(r && in && out && in->length && in->memblock && (in->length % r->i_fz) == 0 && r->impl_data); - i = r->impl_data; +static float * convert_to_float(pa_resampler *r, float *input, unsigned n_frames) { + struct impl_libsamplerate *u; + unsigned n_samples; - /* How many input samples? */ - ins = in->length/r->i_fz; + assert(r); + assert(input); + assert(r->impl_data); + u = r->impl_data; + + /* Convert the incoming sample into floats and place them in buf1 */ -/* pa_log("%u / %u = %u\n", in->length, r->i_fz, ins); */ + if (!u->to_float32ne_func) + return input; + + n_samples = n_frames * r->i_ss.channels; - /* How much space for output samples? */ - if (i->src_state) - ons = (ins*r->o_ss.rate/r->i_ss.rate)+1024; - else - ons = ins; + if (u->buf1_samples < n_samples) + u->buf1 = pa_xrealloc(u->buf1, sizeof(float) * (u->buf1_samples = n_samples)); - /* How many channels? */ - if (r->i_ss.channels == r->o_ss.channels) { - i_nchannels = o_nchannels = 1; - eff_ins = ins*r->i_ss.channels; /* effective samples */ - eff_ons = ons*r->o_ss.channels; - } else { - i_nchannels = r->i_ss.channels; - o_nchannels = r->o_ss.channels; - eff_ins = ins; - eff_ons = ons; - } + u->to_float32ne_func(n_samples, input, u->buf1); -/* pa_log("eff_ins = %u \n", eff_ins); */ + return u->buf1; +} + +static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) { + struct impl_libsamplerate *u; + unsigned n_samples; + int i_skip, o_skip; + unsigned oc; + assert(r); + assert(input); + assert(r->impl_data); + u = r->impl_data; + + /* Remap channels and place the result int buf2 */ - out->memblock = pa_memblock_new(out->length = (ons*r->o_fz), r->memblock_stat); - out->index = 0; - assert(out->memblock); + if (!u->map_required) + return input; - if (i->i_alloc < eff_ins) - i->i_buf = pa_xrealloc(i->i_buf, sizeof(float) * (i->i_alloc = eff_ins)); - assert(i->i_buf); + n_samples = n_frames * r->o_ss.channels; -/* pa_log("eff_ins = %u \n", eff_ins); */ + if (u->buf2_samples < n_samples) + u->buf2 = pa_xrealloc(u->buf2, sizeof(float) * (u->buf2_samples = n_samples)); - i->to_float32ne_func(eff_ins, (uint8_t*) in->memblock->data+in->index, i_nchannels, i->i_buf); + memset(u->buf2, 0, n_samples * sizeof(float)); - if (i->src_state) { - int ret; - SRC_DATA data; + o_skip = sizeof(float) * r->o_ss.channels; + i_skip = sizeof(float) * r->i_ss.channels; + + for (oc = 0; oc < r->o_ss.channels; oc++) { + unsigned i; + static const float one = 1.0; + + for (i = 0; i < PA_CHANNELS_MAX && u->map_table[oc][i] >= 0; i++) + oil_vectoradd_f32( + u->buf2 + oc, o_skip, + u->buf2 + oc, o_skip, + input + u->map_table[oc][i], i_skip, + n_frames, + &one, &one); + } - if (i->o_alloc < eff_ons) - i->o_buf = pa_xrealloc(i->o_buf, sizeof(float) * (i->o_alloc = eff_ons)); - assert(i->o_buf); + return u->buf2; +} - data.data_in = i->i_buf; - data.input_frames = ins; +static float *resample(pa_resampler *r, float *input, unsigned *n_frames) { + struct impl_libsamplerate *u; + SRC_DATA data; + unsigned out_n_frames, out_n_samples; + int ret; - data.data_out = i->o_buf; - data.output_frames = ons; - - data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate; - data.end_of_input = 0; + assert(r); + assert(input); + assert(n_frames); + assert(r->impl_data); + u = r->impl_data; + + /* Resample the data and place the result in buf3 */ + + if (!u->src_state) + return input; + + out_n_frames = (*n_frames*r->o_ss.rate/r->i_ss.rate)+1024; + out_n_samples = out_n_frames * r->o_ss.channels; + + if (u->buf3_samples < out_n_samples) + u->buf3 = pa_xrealloc(u->buf3, sizeof(float) * (u->buf3_samples = out_n_samples)); + + data.data_in = input; + data.input_frames = *n_frames; + + data.data_out = u->buf3; + data.output_frames = out_n_frames; - ret = src_process(i->src_state, &data); - assert(ret == 0); - assert((unsigned) data.input_frames_used == ins); + data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate; + data.end_of_input = 0; - cbuf = i->o_buf; - ons = data.output_frames_gen; - - if (r->i_ss.channels == r->o_ss.channels) - eff_ons = ons*r->o_ss.channels; - else - eff_ons = ons; - } else - cbuf = i->i_buf; - - if (eff_ons) - i->from_float32ne_func(eff_ons, cbuf, (uint8_t*)out->memblock->data+out->index, o_nchannels); - out->length = ons*r->o_fz; - - if (!out->length) { - pa_memblock_unref(out->memblock); + ret = src_process(u->src_state, &data); + assert(ret == 0); + assert((unsigned) data.input_frames_used == *n_frames); + + *n_frames = data.output_frames_gen; + + return u->buf3; +} + +static float *convert_from_float(pa_resampler *r, float *input, unsigned n_frames) { + struct impl_libsamplerate *u; + unsigned n_samples; + + assert(r); + assert(input); + assert(r->impl_data); + u = r->impl_data; + + /* Convert the data into the correct sample type and place the result in buf4 */ + + if (!u->from_float32ne_func) + return input; + + n_samples = n_frames * r->o_ss.channels; + + if (u->buf4_samples < n_samples) + u->buf4 = pa_xrealloc(u->buf4, sizeof(float) * (u->buf4_samples = n_samples)); + + u->from_float32ne_func(n_samples, input, u->buf4); + + return u->buf4; +} + +static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { + struct impl_libsamplerate *u; + float *buf, *input; + unsigned n_frames; + + assert(r); + assert(in); + assert(out); + assert(in->length); + assert(in->memblock); + assert(in->length % r->i_fz == 0); + assert(r->impl_data); + + u = r->impl_data; + + buf = input = (float*) ((uint8_t*) in->memblock->data + in->index); + n_frames = in->length / r->i_fz; + assert(n_frames > 0); + + buf = convert_to_float(r, buf, n_frames); + buf = remap_channels(r, buf, n_frames); + buf = resample(r, buf, &n_frames); + + if (n_frames) { + buf = convert_from_float(r, buf, n_frames); + + if (buf == input) { + /* Mm, no adjustment has been necessary, so let's return the original block */ + out->memblock = pa_memblock_ref(in->memblock); + out->index = in->index; + out->length = in->length; + } else { + float **p = NULL; + + out->length = n_frames * r->o_fz; + out->index = 0; + + if (buf == u->buf1) { + p = &u->buf1; + u->buf1_samples = 0; + } else if (buf == u->buf2) { + p = &u->buf2; + u->buf2_samples = 0; + } else if (buf == u->buf3) { + p = &u->buf3; + u->buf3_samples = 0; + } else if (buf == u->buf4) { + p = &u->buf4; + u->buf4_samples = 0; + } + + assert(p); + + /* Take the existing buffer and make it a memblock */ + out->memblock = pa_memblock_new_dynamic(*p, out->length, r->memblock_stat); + *p = NULL; + } + } else { out->memblock = NULL; + out->index = out->length = 0; } } -static void libsamplerate_set_input_rate(pa_resampler *r, uint32_t rate) { - int ret; - struct impl_libsamplerate *i; - assert(r && rate > 0 && r->impl_data); - i = r->impl_data; - - ret = src_set_ratio(i->src_state, (double) r->o_ss.rate / r->i_ss.rate); - assert(ret == 0); +static void libsamplerate_update_input_rate(pa_resampler *r, uint32_t rate) { + struct impl_libsamplerate *u; + + assert(r); + assert(rate > 0); + assert(r->impl_data); + u = r->impl_data; + + if (!u->src_state) { + int err; + u->src_state = src_new(r->resample_method, r->o_ss.channels, &err); + assert(u->src_state); + } else { + int ret = src_set_ratio(u->src_state, (double) r->o_ss.rate / rate); + assert(ret == 0); + } } static int libsamplerate_init(pa_resampler *r) { - struct impl_libsamplerate *i = NULL; + struct impl_libsamplerate *u = NULL; int err; - r->impl_data = i = pa_xmalloc(sizeof(struct impl_libsamplerate)); - - i->to_float32ne_func = pa_get_convert_to_float32ne_function(r->i_ss.format); - i->from_float32ne_func = pa_get_convert_from_float32ne_function(r->o_ss.format); + r->impl_data = u = pa_xnew(struct impl_libsamplerate, 1); + + u->buf1 = u->buf2 = u->buf3 = u->buf4 = NULL; + u->buf1_samples = u->buf2_samples = u->buf3_samples = u->buf4_samples = 0; - if (!i->to_float32ne_func || !i->from_float32ne_func) + if (r->i_ss.format == PA_SAMPLE_FLOAT32NE) + u->to_float32ne_func = NULL; + else if (!(u->to_float32ne_func = pa_get_convert_to_float32ne_function(r->i_ss.format))) goto fail; - - if (!(i->src_state = src_new(r->resample_method, r->channels, &err)) || !i->src_state) + + if (r->o_ss.format == PA_SAMPLE_FLOAT32NE) + u->from_float32ne_func = NULL; + else if (!(u->from_float32ne_func = pa_get_convert_from_float32ne_function(r->o_ss.format))) goto fail; - i->i_buf = i->o_buf = NULL; - i->i_alloc = i->o_alloc = 0; + if (r->o_ss.rate == r->i_ss.rate) + u->src_state = NULL; + else if (!(u->src_state = src_new(r->resample_method, r->o_ss.channels, &err))) + goto fail; r->impl_free = libsamplerate_free; - r->impl_set_input_rate = libsamplerate_set_input_rate; + r->impl_update_input_rate = libsamplerate_update_input_rate; r->impl_run = libsamplerate_run; + + calc_map_table(r); return 0; fail: - pa_xfree(i); + pa_xfree(u); return -1; } @@ -310,15 +514,20 @@ fail: static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { size_t fz; - unsigned nframes; - struct impl_trivial *i; - assert(r && in && out && r->impl_data); - i = r->impl_data; + unsigned n_frames; + struct impl_trivial *u; + + assert(r); + assert(in); + assert(out); + assert(r->impl_data); + + u = r->impl_data; fz = r->i_fz; assert(fz == r->o_fz); - nframes = in->length/fz; + n_frames = in->length/fz; if (r->i_ss.rate == r->o_ss.rate) { @@ -326,25 +535,25 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out *out = *in; pa_memblock_ref(out->memblock); - i->o_counter += nframes; + u->o_counter += n_frames; } else { /* Do real resampling */ size_t l; unsigned o_index; /* The length of the new memory block rounded up */ - l = ((((nframes+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz; + l = ((((n_frames+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz; out->index = 0; out->memblock = pa_memblock_new(l, r->memblock_stat); - for (o_index = 0;; o_index++, i->o_counter++) { + for (o_index = 0;; o_index++, u->o_counter++) { unsigned j; - j = (i->o_counter * r->i_ss.rate / r->o_ss.rate); - j = j > i->i_counter ? j - i->i_counter : 0; + j = (u->o_counter * r->i_ss.rate / r->o_ss.rate); + j = j > u->i_counter ? j - u->i_counter : 0; - if (j >= nframes) + if (j >= n_frames) break; assert(o_index*fz < out->memblock->length); @@ -357,56 +566,49 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out out->length = o_index*fz; } - i->i_counter += nframes; + u->i_counter += n_frames; /* Normalize counters */ - while (i->i_counter >= r->i_ss.rate) { - i->i_counter -= r->i_ss.rate; - assert(i->o_counter >= r->o_ss.rate); - i->o_counter -= r->o_ss.rate; + while (u->i_counter >= r->i_ss.rate) { + u->i_counter -= r->i_ss.rate; + assert(u->o_counter >= r->o_ss.rate); + u->o_counter -= r->o_ss.rate; } } static void trivial_free(pa_resampler *r) { assert(r); + pa_xfree(r->impl_data); } -static void trivial_set_input_rate(pa_resampler *r, uint32_t rate) { - struct impl_trivial *i; - assert(r && rate > 0 && r->impl_data); - i = r->impl_data; +static void trivial_update_input_rate(pa_resampler *r, uint32_t rate) { + struct impl_trivial *u; + + assert(r); + assert(rate > 0); + assert(r->impl_data); - i->i_counter = 0; - i->o_counter = 0; + u = r->impl_data; + u->i_counter = 0; + u->o_counter = 0; } static int trivial_init(pa_resampler*r) { - struct impl_trivial *i; - assert(r && r->i_ss.format == r->o_ss.format && r->i_ss.channels == r->o_ss.channels); + struct impl_trivial *u; + + assert(r); + assert(r->i_ss.format == r->o_ss.format); + assert(r->i_ss.channels == r->o_ss.channels); - r->impl_data = i = pa_xmalloc(sizeof(struct impl_trivial)); - i->o_counter = i->i_counter = 0; + r->impl_data = u = pa_xnew(struct impl_trivial, 1); + u->o_counter = u->i_counter = 0; r->impl_run = trivial_run; r->impl_free = trivial_free; - r->impl_set_input_rate = trivial_set_input_rate; + r->impl_update_input_rate = trivial_update_input_rate; return 0; } -const char *pa_resample_method_to_string(pa_resample_method m) { - static const char * const resample_methods[] = { - "src-sinc-best-quality", - "src-sinc-medium-quality", - "src-sinc-fastest", - "src-zero-order-hold", - "src-linear", - "trivial" - }; - if (m < 0 || m >= PA_RESAMPLER_MAX) - return NULL; - - return resample_methods[m]; -} diff --git a/polyp/resampler.h b/polyp/resampler.h index 358c872a..e14942f3 100644 --- a/polyp/resampler.h +++ b/polyp/resampler.h @@ -27,6 +27,7 @@ #include "sample.h" #include "memblock.h" #include "memchunk.h" +#include "channelmap.h" typedef struct pa_resampler pa_resampler; @@ -39,9 +40,16 @@ typedef enum pa_resample_method { PA_RESAMPLER_SRC_LINEAR = SRC_LINEAR, PA_RESAMPLER_TRIVIAL, PA_RESAMPLER_MAX -} pa_resample_method; +} pa_resample_method_t; + +pa_resampler* pa_resampler_new( + const pa_sample_spec *a, + const pa_channel_map *am, + const pa_sample_spec *b, + const pa_channel_map *bm, + pa_memblock_stat *s, + pa_resample_method_t resample_method); -pa_resampler* pa_resampler_new(const pa_sample_spec *a, const pa_sample_spec *b, pa_memblock_stat *s, int resample_method); void pa_resampler_free(pa_resampler *r); /* Returns the size of an input memory block which is required to return the specified amount of output data */ @@ -54,12 +62,12 @@ void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out); void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate); /* Return the resampling method of the resampler object */ -pa_resample_method pa_resampler_get_method(pa_resampler *r); +pa_resample_method_t pa_resampler_get_method(pa_resampler *r); /* Try to parse the resampler method */ -pa_resample_method pa_parse_resample_method(const char *string); +pa_resample_method_t pa_parse_resample_method(const char *string); /* return a human readable string for the specified resampling method. Inverse of pa_parse_resample_method() */ -const char *pa_resample_method_to_string(pa_resample_method m); +const char *pa_resample_method_to_string(pa_resample_method_t m); #endif diff --git a/polyp/sample-util.c b/polyp/sample-util.c index cb5dd1c3..d2bb3150 100644 --- a/polyp/sample-util.c +++ b/polyp/sample-util.c @@ -28,6 +28,8 @@ #include #include +#include + #include "sample-util.h" pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) { @@ -38,6 +40,7 @@ pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) { void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) { assert(c && c->memblock && c->memblock->data && spec && c->length); + pa_silence_memory((uint8_t*) c->memblock->data+c->index, c->length, spec); } @@ -65,204 +68,255 @@ void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { memset(p, c, length); } -size_t pa_mix(pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const pa_sample_spec *spec, pa_volume_t volume) { - assert(channels && data && length && spec); +size_t pa_mix( + const pa_mix_info streams[], + unsigned nstreams, + void *data, + size_t length, + const pa_sample_spec *spec, + const pa_cvolume *volume) { - if (spec->format == PA_SAMPLE_S16NE) { - size_t d; - - for (d = 0;; d += sizeof(int16_t)) { - unsigned c; - int32_t sum = 0; - - if (d >= length) - return d; + assert(streams && data && length && spec); + + switch (spec->format) { + case PA_SAMPLE_S16NE:{ + size_t d; + unsigned channel = 0; - for (c = 0; c < nchannels; c++) { - int32_t v; - pa_volume_t cvolume = channels[c].volume; + for (d = 0;; d += sizeof(int16_t)) { + int32_t sum = 0; - if (d >= channels[c].chunk.length) + if (d >= length) return d; - - if (cvolume == PA_VOLUME_MUTED) - v = 0; - else { - v = *((int16_t*) ((uint8_t*) channels[c].chunk.memblock->data + channels[c].chunk.index + d)); + + if (volume->values[channel] != PA_VOLUME_MUTED) { + unsigned i; - if (cvolume != PA_VOLUME_NORM) { - v *= cvolume; - v /= PA_VOLUME_NORM; + for (i = 0; i < nstreams; i++) { + int32_t v; + pa_volume_t cvolume = streams[i].volume.values[channel]; + + if (d >= streams[i].chunk.length) + return d; + + if (cvolume == PA_VOLUME_MUTED) + v = 0; + else { + v = *((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); + + if (cvolume != PA_VOLUME_NORM) { + v *= cvolume; + v /= PA_VOLUME_NORM; + } + } + + sum += v; + } + + if (volume->values[channel] != PA_VOLUME_NORM) { + sum *= volume->values[channel]; + sum /= PA_VOLUME_NORM; } + + if (sum < -0x8000) sum = -0x8000; + if (sum > 0x7FFF) sum = 0x7FFF; + } - sum += v; - } - - if (volume == PA_VOLUME_MUTED) - sum = 0; - else if (volume != PA_VOLUME_NORM) { - sum *= volume; - sum /= PA_VOLUME_NORM; + *((int16_t*) data) = sum; + data = (uint8_t*) data + sizeof(int16_t); + + if (++channel >= spec->channels) + channel = 0; } - - if (sum < -0x8000) sum = -0x8000; - if (sum > 0x7FFF) sum = 0x7FFF; - - *((int16_t*) data) = sum; - data = (uint8_t*) data + sizeof(int16_t); } - } else if (spec->format == PA_SAMPLE_U8) { - size_t d; - - for (d = 0;; d ++) { - int32_t sum = 0; - unsigned c; - if (d >= length) - return d; + case PA_SAMPLE_U8: { + size_t d; + unsigned channel = 0; - for (c = 0; c < nchannels; c++) { - int32_t v; - pa_volume_t cvolume = channels[c].volume; + for (d = 0;; d ++) { + int32_t sum = 0; - if (d >= channels[c].chunk.length) + if (d >= length) return d; - - if (cvolume == PA_VOLUME_MUTED) - v = 0; - else { - v = (int32_t) *((uint8_t*) channels[c].chunk.memblock->data + channels[c].chunk.index + d) - 0x80; + + if (volume->values[channel] != PA_VOLUME_MUTED) { + unsigned i; - if (cvolume != PA_VOLUME_NORM) { - v *= cvolume; - v /= PA_VOLUME_NORM; + for (i = 0; i < nstreams; i++) { + int32_t v; + pa_volume_t cvolume = streams[i].volume.values[channel]; + + if (d >= streams[i].chunk.length) + return d; + + if (cvolume == PA_VOLUME_MUTED) + v = 0; + else { + v = (int32_t) *((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d) - 0x80; + + if (cvolume != PA_VOLUME_NORM) { + v *= cvolume; + v /= PA_VOLUME_NORM; + } + } + + sum += v; + } + + if (volume->values[channel] != PA_VOLUME_NORM) { + sum *= volume->values[channel]; + sum /= PA_VOLUME_NORM; } + + if (sum < -0x80) sum = -0x80; + if (sum > 0x7F) sum = 0x7F; + } - sum += v; - } - - if (volume == PA_VOLUME_MUTED) - sum = 0; - else if (volume != PA_VOLUME_NORM) { - sum *= volume; - sum /= PA_VOLUME_NORM; + *((uint8_t*) data) = (uint8_t) (sum + 0x80); + data = (uint8_t*) data + 1; + + if (++channel >= spec->channels) + channel = 0; } - - if (sum < -0x80) sum = -0x80; - if (sum > 0x7F) sum = 0x7F; - - *((uint8_t*) data) = (uint8_t) (sum + 0x80); - data = (uint8_t*) data + 1; } - - } else if (spec->format == PA_SAMPLE_FLOAT32NE) { - size_t d; - - for (d = 0;; d += sizeof(float)) { - float sum = 0; - unsigned c; - if (d >= length) - return d; + case PA_SAMPLE_FLOAT32NE: { + size_t d; + unsigned channel = 0; - for (c = 0; c < nchannels; c++) { - float v; - pa_volume_t cvolume = channels[c].volume; + for (d = 0;; d += sizeof(float)) { + float sum = 0; - if (d >= channels[c].chunk.length) + if (d >= length) return d; - if (cvolume == PA_VOLUME_MUTED) - v = 0; - else { - v = *((float*) ((uint8_t*) channels[c].chunk.memblock->data + channels[c].chunk.index + d)); + if (volume->values[channel] != PA_VOLUME_MUTED) { + unsigned i; - if (cvolume != PA_VOLUME_NORM) - v = v*cvolume/PA_VOLUME_NORM; - } - - sum += v; - } - - if (volume == PA_VOLUME_MUTED) - sum = 0; - else if (volume != PA_VOLUME_NORM) - sum = sum*volume/PA_VOLUME_NORM; + for (i = 0; i < nstreams; i++) { + float v; + pa_volume_t cvolume = streams[i].volume.values[channel]; + + if (d >= streams[i].chunk.length) + return d; + + if (cvolume == PA_VOLUME_MUTED) + v = 0; + else { + v = *((float*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); + + if (cvolume != PA_VOLUME_NORM) { + v *= cvolume; + v /= PA_VOLUME_NORM; + } + } + + sum += v; + } - if (sum < -1) sum = -1; - if (sum > 1) sum = 1; + if (volume->values[channel] != PA_VOLUME_NORM) { + sum *= volume->values[channel]; + sum /= PA_VOLUME_NORM; + } + } - *((float*) data) = sum; - data = (uint8_t*) data + sizeof(float); + *((float*) data) = sum; + data = (uint8_t*) data + sizeof(float); + + if (++channel >= spec->channels) + channel = 0; + } } - } else { - abort(); + + default: + abort(); } } -void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, pa_volume_t volume) { +void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvolume *volume) { assert(c && spec && (c->length % pa_frame_size(spec) == 0)); + assert(volume); - if (volume == PA_VOLUME_NORM) + if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM)) return; - if (volume == PA_VOLUME_MUTED) { + if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) { pa_silence_memchunk(c, spec); return; } - if (spec->format == PA_SAMPLE_S16NE) { - int16_t *d; - size_t n; - - for (d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { - int32_t t = (int32_t)(*d); + switch (spec->format) { + case PA_SAMPLE_S16NE: { + int16_t *d; + size_t n; + unsigned channel = 0; - t *= volume; - t /= PA_VOLUME_NORM; + for (d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { + int32_t t = (int32_t)(*d); + + t *= volume->values[channel]; + t /= PA_VOLUME_NORM; + + if (t < -0x8000) t = -0x8000; + if (t > 0x7FFF) t = 0x7FFF; + + *d = (int16_t) t; + + if (++channel >= spec->channels) + channel = 0; + } + } - if (t < -0x8000) t = -0x8000; - if (t > 0x7FFF) t = 0x7FFF; + case PA_SAMPLE_U8: { + uint8_t *d; + size_t n; + unsigned channel = 0; - *d = (int16_t) t; + for (d = (uint8_t*) c->memblock->data + c->index, n = c->length; n > 0; d++, n--) { + int32_t t = (int32_t) *d - 0x80; + + t *= volume->values[channel]; + t /= PA_VOLUME_NORM; + + if (t < -0x80) t = -0x80; + if (t > 0x7F) t = 0x7F; + + *d = (uint8_t) (t + 0x80); + + if (++channel >= spec->channels) + channel = 0; + } } - } else if (spec->format == PA_SAMPLE_U8) { - uint8_t *d; - size_t n; - - for (d = (uint8_t*) c->memblock->data + c->index, n = c->length; n > 0; d++, n--) { - int32_t t = (int32_t) *d - 0x80; - - t *= volume; - t /= PA_VOLUME_NORM; - - if (t < -0x80) t = -0x80; - if (t > 0x7F) t = 0x7F; - - *d = (uint8_t) (t + 0x80); + case PA_SAMPLE_FLOAT32NE: { + float *d; + int skip; + unsigned n; + unsigned channel; + + d = (float*) ((uint8_t*) c->memblock->data + c->index); + skip = spec->channels * sizeof(float); + n = c->length/sizeof(float)/spec->channels; + + for (channel = 0; channel < spec->channels ; channel ++) { + float v, *t; + + if (volume->values[channel] == PA_VOLUME_NORM) + continue; + + v = (float) volume->values[channel] / PA_VOLUME_NORM; + + t = d + channel; + oil_scalarmult_f32(t, skip, t, skip, &v, n); + } } - } else if (spec->format == PA_SAMPLE_FLOAT32NE) { - float *d; - size_t n; - - for (d = (float*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(float); n > 0; d++, n--) { - float t = *d; - - t *= volume; - t /= PA_VOLUME_NORM; - if (t < -1) t = -1; - if (t > 1) t = 1; - - *d = t; - } - - } else { - abort(); + default: + abort(); } } diff --git a/polyp/sample-util.h b/polyp/sample-util.h index eaebe91d..e433f9c8 100644 --- a/polyp/sample-util.h +++ b/polyp/sample-util.h @@ -25,7 +25,7 @@ #include "sample.h" #include "memblock.h" #include "memchunk.h" - +#include "volume.h" pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec); void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec); @@ -33,12 +33,21 @@ void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec); typedef struct pa_mix_info { pa_memchunk chunk; - pa_volume_t volume; + pa_cvolume volume; void *userdata; -} pa_mix_info ; - -size_t pa_mix(pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const pa_sample_spec *spec, pa_volume_t volume); - -void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, pa_volume_t volume); +} pa_mix_info; + +size_t pa_mix( + const pa_mix_info channels[], + unsigned nchannels, + void *data, + size_t length, + const pa_sample_spec *spec, + const pa_cvolume *volume); + +void pa_volume_memchunk( + pa_memchunk*c, + const pa_sample_spec *spec, + const pa_cvolume *volume); #endif diff --git a/polyp/sample.c b/polyp/sample.c index 37ab96a0..d587170c 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -30,29 +30,29 @@ #include "sample.h" -size_t pa_frame_size(const pa_sample_spec *spec) { - size_t b = 1; +size_t pa_sample_size(const pa_sample_spec *spec) { assert(spec); switch (spec->format) { case PA_SAMPLE_U8: case PA_SAMPLE_ULAW: case PA_SAMPLE_ALAW: - b = 1; - break; + return 1; case PA_SAMPLE_S16LE: case PA_SAMPLE_S16BE: - b = 2; - break; + return 2; case PA_SAMPLE_FLOAT32LE: case PA_SAMPLE_FLOAT32BE: - b = 4; - break; + return 4; default: assert(0); } +} + +size_t pa_frame_size(const pa_sample_spec *spec) { + assert(spec); - return b * spec->channels; + return pa_sample_size(spec) * spec->channels; } size_t pa_bytes_per_second(const pa_sample_spec *spec) { @@ -69,10 +69,11 @@ pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) { int pa_sample_spec_valid(const pa_sample_spec *spec) { assert(spec); - if (spec->rate <= 0 || spec->channels <= 0) - return 0; - - if (spec->format >= PA_SAMPLE_MAX || spec->format < 0) + if (spec->rate <= 0 || + spec->channels <= 0 || + spec->channels > PA_CHANNELS_MAX || + spec->format >= PA_SAMPLE_MAX || + spec->format < 0) return 0; return 1; @@ -84,15 +85,15 @@ int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b) { return (a->format == b->format) && (a->rate == b->rate) && (a->channels == b->channels); } -const char *pa_sample_format_to_string(pa_sample_format f) { +const char *pa_sample_format_to_string(pa_sample_format_t f) { static const char* const table[]= { - [PA_SAMPLE_U8] = "U8", - [PA_SAMPLE_ALAW] = "ALAW", - [PA_SAMPLE_ULAW] = "ULAW", - [PA_SAMPLE_S16LE] = "S16LE", - [PA_SAMPLE_S16BE] = "S16BE", - [PA_SAMPLE_FLOAT32LE] = "FLOAT32LE", - [PA_SAMPLE_FLOAT32BE] = "FLOAT32BE", + [PA_SAMPLE_U8] = "u8", + [PA_SAMPLE_ALAW] = "aLaw", + [PA_SAMPLE_ULAW] = "uLaw", + [PA_SAMPLE_S16LE] = "s16le", + [PA_SAMPLE_S16BE] = "s16be", + [PA_SAMPLE_FLOAT32LE] = "float32le", + [PA_SAMPLE_FLOAT32BE] = "float32be", }; if (f >= PA_SAMPLE_MAX) @@ -112,44 +113,6 @@ char *pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec) { return s; } -pa_volume_t pa_volume_multiply(pa_volume_t a, pa_volume_t b) { - uint64_t p = a; - p *= b; - p /= PA_VOLUME_NORM; - - return (pa_volume_t) p; -} - -pa_volume_t pa_volume_from_dB(double f) { - if (f <= PA_DECIBEL_MININFTY) - return PA_VOLUME_MUTED; - - return (pa_volume_t) (pow(10, f/20)*PA_VOLUME_NORM); -} - -double pa_volume_to_dB(pa_volume_t v) { - if (v == PA_VOLUME_MUTED) - return PA_DECIBEL_MININFTY; - - return 20*log10((double) v/PA_VOLUME_NORM); -} - -#define USER_DECIBEL_RANGE 30 - -double pa_volume_to_user(pa_volume_t v) { - double dB = pa_volume_to_dB(v); - - return dB < -USER_DECIBEL_RANGE ? 0 : dB/USER_DECIBEL_RANGE+1; -} - -pa_volume_t pa_volume_from_user(double v) { - - if (v <= 0) - return PA_VOLUME_MUTED; - - return pa_volume_from_dB((v-1)*USER_DECIBEL_RANGE); -} - void pa_bytes_snprint(char *s, size_t l, unsigned v) { if (v >= ((unsigned) 1024)*1024*1024) snprintf(s, l, "%0.1f GB", ((double) v)/1024/1024/1024); @@ -161,7 +124,7 @@ void pa_bytes_snprint(char *s, size_t l, unsigned v) { snprintf(s, l, "%u B", (unsigned) v); } -pa_sample_format pa_parse_sample_format(const char *format) { +pa_sample_format_t pa_parse_sample_format(const char *format) { if (strcasecmp(format, "s16le") == 0) return PA_SAMPLE_S16LE; diff --git a/polyp/sample.h b/polyp/sample.h index 739cb337..c1b98f1c 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -33,6 +33,9 @@ PA_C_DECL_BEGIN +/* Maximum allowed channels */ +#define PA_CHANNELS_MAX 16 + /** Sample format */ typedef enum pa_sample_format { PA_SAMPLE_U8, /**< Unsigned 8 Bit PCM */ @@ -44,7 +47,7 @@ typedef enum pa_sample_format { PA_SAMPLE_FLOAT32BE, /**< 32 Bit IEEE floating point, big endian, range -1..1 */ PA_SAMPLE_MAX, /**< Upper limit of valid sample types */ PA_SAMPLE_INVALID = -1 /**< An invalid value */ -} pa_sample_format; +} pa_sample_format_t; #ifdef WORDS_BIGENDIAN /** Signed 16 Bit PCM, native endian */ @@ -71,7 +74,7 @@ typedef enum pa_sample_format { /** A sample format and attribute specification */ typedef struct pa_sample_spec { - pa_sample_format format; /**< The sample format */ + pa_sample_format_t format; /**< The sample format */ uint32_t rate; /**< The sample rate. (e.g. 44100) */ uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */ } pa_sample_spec; @@ -85,6 +88,9 @@ size_t pa_bytes_per_second(const pa_sample_spec *spec); /** Return the size of a frame with the specific sample type */ size_t pa_frame_size(const pa_sample_spec *spec); +/** Return the size of a sample with the specific sample type */ +size_t pa_sample_size(const pa_sample_spec *spec); + /** Calculate the time the specified bytes take to play with the specified sample type */ pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec); @@ -95,7 +101,10 @@ int pa_sample_spec_valid(const pa_sample_spec *spec); int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b); /* Return a descriptive string for the specified sample format. \since 0.8 */ -const char *pa_sample_format_to_string(pa_sample_format f); +const char *pa_sample_format_to_string(pa_sample_format_t f); + +/** Parse a sample format text. Inverse of pa_sample_format_to_string() */ +pa_sample_format_t pa_parse_sample_format(const char *format); /** Maximum required string length for pa_sample_spec_snprint() */ #define PA_SAMPLE_SPEC_SNPRINT_MAX 32 @@ -103,43 +112,9 @@ const char *pa_sample_format_to_string(pa_sample_format f); /** Pretty print a sample type specification to a string */ char* pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec); -/** Volume specification: 0: silence; < 256: diminished volume; 256: normal volume; > 256 amplified volume */ -typedef uint32_t pa_volume_t; - -/** Normal volume (100%) */ -#define PA_VOLUME_NORM (0x100) - -/** Muted volume (0%) */ -#define PA_VOLUME_MUTED (0) - -/** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. */ -pa_volume_t pa_volume_multiply(pa_volume_t a, pa_volume_t b); - -/** Convert volume from decibel to linear level. \since 0.4 */ -pa_volume_t pa_volume_from_dB(double f); - -/** Convert volume from linear level to decibel. \since 0.4 */ -double pa_volume_to_dB(pa_volume_t v); - -/** Convert volume to scaled value understandable by the user (between 0 and 1). \since 0.6 */ -double pa_volume_to_user(pa_volume_t v); - -/** Convert user volume to polypaudio volume. \since 0.6 */ -pa_volume_t pa_volume_from_user(double v); - -#ifdef INFINITY -#define PA_DECIBEL_MININFTY (-INFINITY) -#else -/** This value is used as minus infinity when using pa_volume_{to,from}_dB(). \since 0.4 */ -#define PA_DECIBEL_MININFTY (-200) -#endif - /** Pretty print a byte size value. (i.e. "2.5 MB") */ void pa_bytes_snprint(char *s, size_t l, unsigned v); -/** Parse a sample format text. Inverse of pa_sample_format_to_string() */ -pa_sample_format pa_parse_sample_format(const char *format); - PA_C_DECL_END #endif diff --git a/polyp/scache.c b/polyp/scache.c index 32c89a99..39fa26f3 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -52,6 +52,8 @@ #include "sound-file.h" #include "util.h" #include "log.h" +#include "channelmap.h" +#include "volume.h" #define UNLOAD_POLL_TIME 2 @@ -112,7 +114,7 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_NEW, e->index); } - e->volume = PA_VOLUME_NORM; + pa_cvolume_reset(&e->volume, PA_CHANNELS_MAX); e->last_used_time = 0; e->memchunk.memblock = NULL; e->memchunk.index = e->memchunk.length = 0; @@ -125,15 +127,20 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { return e; } -int pa_scache_add_item(pa_core *c, const char *name, pa_sample_spec *ss, pa_memchunk *chunk, uint32_t *idx) { +int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx) { pa_scache_entry *e; assert(c && name); if (!(e = scache_add_item(c, name))) return -1; - if (ss) + if (ss) { e->sample_spec = *ss; + pa_channel_map_init_auto(&e->channel_map, ss->channels); + } + + if (map) + e->channel_map = *map; if (chunk) { e->memchunk = *chunk; @@ -161,7 +168,7 @@ int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint3 if (pa_sound_file_load(filename, &ss, &chunk, c->memblock_stat) < 0) return -1; - r = pa_scache_add_item(c, name, &ss, &chunk, idx); + r = pa_scache_add_item(c, name, &ss, NULL, &chunk, idx); pa_memblock_unref(chunk.memblock); return r; @@ -230,9 +237,10 @@ void pa_scache_free(pa_core *c) { c->mainloop->time_free(c->scache_auto_unload_event); } -int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, uint32_t volume) { +int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, const pa_cvolume *volume) { pa_scache_entry *e; char *t; + pa_cvolume r; assert(c && name && sink); if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1))) @@ -249,7 +257,8 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, uint32_t vo return -1; t = pa_sprintf_malloc("sample:%s", name); - if (pa_play_memchunk(sink, t, &e->sample_spec, &e->memchunk, pa_volume_multiply(volume, e->volume)) < 0) { + + if (pa_play_memchunk(sink, t, &e->sample_spec, &e->channel_map, &e->memchunk, pa_sw_cvolume_multiply(&r, volume, &e->volume)) < 0) { free(t); return -1; } diff --git a/polyp/scache.h b/polyp/scache.h index c23e33de..d667ae60 100644 --- a/polyp/scache.h +++ b/polyp/scache.h @@ -31,8 +31,9 @@ typedef struct pa_scache_entry { uint32_t index; char *name; - uint32_t volume; + pa_cvolume volume; pa_sample_spec sample_spec; + pa_channel_map channel_map; pa_memchunk memchunk; char *filename; @@ -41,14 +42,14 @@ typedef struct pa_scache_entry { time_t last_used_time; } pa_scache_entry; -int pa_scache_add_item(pa_core *c, const char *name, pa_sample_spec *ss, pa_memchunk *chunk, uint32_t *idx); +int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx); int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint32_t *idx); int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, uint32_t *idx); int pa_scache_add_directory_lazy(pa_core *c, const char *pathname); int pa_scache_remove_item(pa_core *c, const char *name); -int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, uint32_t volume); +int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, const pa_cvolume *cvolume); void pa_scache_free(pa_core *c); const char *pa_scache_get_name_by_id(pa_core *c, uint32_t id); diff --git a/polyp/sconv-s16be.c b/polyp/sconv-s16be.c index 3880b043..8b076f06 100644 --- a/polyp/sconv-s16be.c +++ b/polyp/sconv-s16be.c @@ -23,11 +23,19 @@ #include #endif +#include "endianmacros.h" + #define INT16_FROM INT16_FROM_BE #define INT16_TO INT16_TO_BE #define pa_sconv_s16le_to_float32ne pa_sconv_s16be_to_float32ne #define pa_sconv_s16le_from_float32ne pa_sconv_s16be_from_float32ne +#ifdef WORDS_BIGENDIAN +#define SWAP_WORDS 0 +#else +#define SWAP_WORDS 1 +#endif + #include "sconv-s16le.h" #include "sconv-s16le.c" diff --git a/polyp/sconv-s16be.h b/polyp/sconv-s16be.h index 86107fb5..b2b6a8c7 100644 --- a/polyp/sconv-s16be.h +++ b/polyp/sconv-s16be.h @@ -22,7 +22,7 @@ USA. ***/ -void pa_sconv_s16be_to_float32ne(unsigned n, const void *a, unsigned an, float *b); -void pa_sconv_s16be_from_float32ne(unsigned n, const float *a, void *b, unsigned bn); +void pa_sconv_s16be_to_float32ne(unsigned n, const void *a, float *b); +void pa_sconv_s16be_from_float32ne(unsigned n, const float *a, void *b); #endif diff --git a/polyp/sconv-s16le.c b/polyp/sconv-s16le.c index c9682fff..e47c5e8e 100644 --- a/polyp/sconv-s16le.c +++ b/polyp/sconv-s16le.c @@ -26,6 +26,8 @@ #include #include +#include + #include "endianmacros.h" #include "sconv.h" #include "sconv-s16le.h" @@ -39,49 +41,61 @@ #define INT16_TO INT16_TO_LE #endif -void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, unsigned an, float *b) { +#ifndef SWAP_WORDS +#ifdef WORDS_BIGENDIAN +#define SWAP_WORDS 1 +#else +#define SWAP_WORDS 0 +#endif +#endif + +void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b) { const int16_t *ca = a; - assert(n && a && an && b); + assert(a); + assert(b); + +#if SWAP_WORDS == 1 + for (; n > 0; n--) { - unsigned i; - float sum = 0; - - for (i = 0; i < an; i++) { - int16_t s = *(ca++); - sum += ((float) INT16_FROM(s))/0x7FFF; - } - - if (sum > 1) - sum = 1; - if (sum < -1) - sum = -1; - - *(b++) = sum; + int16_t s = *(ca++); + *(b++) = ((float) INT16_FROM(s))/0x7FFF; } + +#else +{ + static const double add = 0, factor = 1.0/0x7FFF; + oil_scaleconv_f32_s16(b, ca, n, &add, &factor); +} +#endif } -void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b, unsigned bn) { +void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b) { int16_t *cb = b; - -/* pa_log("%u %p %p %u\n", n, a, b, bn); */ - assert(n && a && b && bn); + assert(a); + assert(b); + +#if SWAP_WORDS == 1 for (; n > 0; n--) { - unsigned i; int16_t s; float v = *(a++); if (v > 1) v = 1; + if (v < -1) v = -1; s = (int16_t) (v * 0x7FFF); - s = INT16_TO(s); - - for (i = 0; i < bn; i++) - *(cb++) = s; + *(cb++) = INT16_TO(s); } + +#else +{ + static const double add = 0, factor = 0x7FFF; + oil_scaleconv_s16_f32(cb, a, n, &add, &factor); +} +#endif } diff --git a/polyp/sconv-s16le.h b/polyp/sconv-s16le.h index caed826e..ef5e31e8 100644 --- a/polyp/sconv-s16le.h +++ b/polyp/sconv-s16le.h @@ -22,7 +22,7 @@ USA. ***/ -void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, unsigned an, float *b); -void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b, unsigned bn); +void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b); +void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b); #endif diff --git a/polyp/sconv.c b/polyp/sconv.c index 223df5d9..1fcb5a0c 100644 --- a/polyp/sconv.c +++ b/polyp/sconv.c @@ -26,6 +26,10 @@ #include #include #include + +#include +#include + #include "endianmacros.h" #include "sconv.h" #include "g711.h" @@ -33,107 +37,58 @@ #include "sconv-s16le.h" #include "sconv-s16be.h" -static void u8_to_float32ne(unsigned n, const void *a, unsigned an, float *b) { - unsigned i; +static void u8_to_float32ne(unsigned n, const void *a, float *b) { const uint8_t *ca = a; - assert(n && a && an && b); - - for (; n > 0; n--) { - float sum = 0; + static const double add = -128.0/127.0, factor = 1.0/127.0; + + assert(a); + assert(b); - for (i = 0; i < an; i++) { - uint8_t v = *(ca++); - sum += (((float) v)-128)/127; - } - - if (sum > 1) - sum = 1; - if (sum < -1) - sum = -1; - - *(b++) = sum; - } + oil_scaleconv_f32_u8(b, ca, n, &add, &factor); } -static void u8_from_float32ne(unsigned n, const float *a, void *b, unsigned bn) { - unsigned i; +static void u8_from_float32ne(unsigned n, const float *a, void *b) { uint8_t *cb = b; + static const double add = 128.0, factor = 127.0; - assert(n && a && b && bn); - for (; n > 0; n--) { - float v = *(a++); - uint8_t u; - - if (v > 1) - v = 1; - - if (v < -1) - v = -1; + assert(a); + assert(b); - u = (uint8_t) (v*127+128); - - for (i = 0; i < bn; i++) - *(cb++) = u; - } + oil_scaleconv_u8_f32(cb, a, n, &add, &factor); } -static void float32ne_to_float32ne(unsigned n, const void *a, unsigned an, float *b) { - unsigned i; - const float *ca = a; - assert(n && a && an && b); - for (; n > 0; n--) { - float sum = 0; - - for (i = 0; i < an; i++) - sum += *(ca++); +static void float32ne_to_float32ne(unsigned n, const void *a, float *b) { + assert(a); + assert(b); - if (sum > 1) - sum = 1; - if (sum < -1) - sum = -1; - - *(b++) = sum; - } + oil_memcpy(b, a, sizeof(float) * n); } -static void float32ne_from_float32ne(unsigned n, const float *a, void *b, unsigned bn) { - unsigned i; - float *cb = b; - assert(n && a && b && bn); - for (; n > 0; n--) { - float v = *(a++); - for (i = 0; i < bn; i++) - *(cb++) = v; - } +static void float32ne_from_float32ne(unsigned n, const float *a, void *b) { + assert(a); + assert(b); + + oil_memcpy(b, a, sizeof(float) * n); } -static void ulaw_to_float32ne(unsigned n, const void *a, unsigned an, float *b) { - unsigned i; +static void ulaw_to_float32ne(unsigned n, const void *a, float *b) { const uint8_t *ca = a; - assert(n && a && an && b); - for (; n > 0; n--) { - float sum = 0; - - for (i = 0; i < an; i++) - sum += st_ulaw2linear16(*ca++) * 1.0F / 0x7FFF; - if (sum > 1) - sum = 1; - if (sum < -1) - sum = -1; - - *(b++) = sum; - } + assert(a); + assert(b); + + for (; n > 0; n--) + *(b++) = st_ulaw2linear16(*(ca++)) * 1.0F / 0x7FFF; } -static void ulaw_from_float32ne(unsigned n, const float *a, void *b, unsigned bn) { - unsigned i; +static void ulaw_from_float32ne(unsigned n, const float *a, void *b) { uint8_t *cb = b; - assert(n && a && b && bn); + assert(a); + assert(b); + for (; n > 0; n--) { float v = *(a++); - uint8_t u; if (v > 1) v = 1; @@ -141,40 +96,28 @@ static void ulaw_from_float32ne(unsigned n, const float *a, void *b, unsigned bn if (v < -1) v = -1; - u = st_14linear2ulaw((int16_t) (v * 0x1FFF)); - - for (i = 0; i < bn; i++) - *(cb++) = u; + *(cb++) = st_14linear2ulaw((int16_t) (v * 0x1FFF)); } } -static void alaw_to_float32ne(unsigned n, const void *a, unsigned an, float *b) { - unsigned i; +static void alaw_to_float32ne(unsigned n, const void *a, float *b) { const uint8_t *ca = a; - assert(n && a && an && b); - for (; n > 0; n--) { - float sum = 0; - - for (i = 0; i < an; i++) - sum += st_alaw2linear16(*ca++) * 1.0F / 0x7FFF; - if (sum > 1) - sum = 1; - if (sum < -1) - sum = -1; + assert(a); + assert(b); - *(b++) = sum; - } + for (; n > 0; n--) + *(b++) = st_alaw2linear16(*(ca++)) * 1.0F / 0x7FFF; } -static void alaw_from_float32ne(unsigned n, const float *a, void *b, unsigned bn) { - unsigned i; +static void alaw_from_float32ne(unsigned n, const float *a, void *b) { uint8_t *cb = b; - assert(n && a && b && bn); + assert(a); + assert(b); + for (; n > 0; n--) { float v = *(a++); - uint8_t u; if (v > 1) v = 1; @@ -182,15 +125,11 @@ static void alaw_from_float32ne(unsigned n, const float *a, void *b, unsigned bn if (v < -1) v = -1; - u = st_13linear2alaw((int16_t) (v * 0xFFF)); - - for (i = 0; i < bn; i++) - *(cb++) = u; + *(cb++) = st_13linear2alaw((int16_t) (v * 0xFFF)); } } - -pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format f) { +pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f) { switch(f) { case PA_SAMPLE_U8: return u8_to_float32ne; @@ -209,7 +148,7 @@ pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_fo } } -pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format f) { +pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f) { switch(f) { case PA_SAMPLE_U8: return u8_from_float32ne; diff --git a/polyp/sconv.h b/polyp/sconv.h index 2866fd41..2a005219 100644 --- a/polyp/sconv.h +++ b/polyp/sconv.h @@ -24,10 +24,10 @@ #include "sample.h" -typedef void (*pa_convert_to_float32ne_func_t)(unsigned n, const void *a, unsigned an, float *b); -typedef void (*pa_convert_from_float32ne_func_t)(unsigned n, const float *a, void *b, unsigned bn); +typedef void (*pa_convert_to_float32ne_func_t)(unsigned n, const void *a, float *b); +typedef void (*pa_convert_from_float32ne_func_t)(unsigned n, const float *a, void *b); -pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format f); -pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format f); +pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f); +pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f); #endif diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 682b3222..4a847e46 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -36,47 +36,66 @@ #define CONVERT_BUFFER_LENGTH 4096 -pa_sink_input* pa_sink_input_new(pa_sink *s, pa_typeid_t typeid, const char *name, const pa_sample_spec *spec, int variable_rate, int resample_method) { +pa_sink_input* pa_sink_input_new( + pa_sink *s, + const char *driver, + const char *name, + const pa_sample_spec *spec, + const pa_channel_map *map, + int variable_rate, + int resample_method) { + pa_sink_input *i; pa_resampler *resampler = NULL; int r; char st[256]; - assert(s && spec && s->state == PA_SINK_RUNNING); + pa_channel_map tmap; + + assert(s); + assert(spec); + assert(s->state == PA_SINK_RUNNING); if (pa_idxset_size(s->inputs) >= PA_MAX_INPUTS_PER_SINK) { - pa_log(__FILE__": Failed to create sink input: too many inputs per sink.\n"); + pa_log_warn(__FILE__": Failed to create sink input: too many inputs per sink.\n"); return NULL; } if (resample_method == PA_RESAMPLER_INVALID) resample_method = s->core->resample_method; - if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec)) - if (!(resampler = pa_resampler_new(spec, &s->sample_spec, s->core->memblock_stat, resample_method))) + if (!map) { + pa_channel_map_init_auto(&tmap, spec->channels); + map = &tmap; + } + + if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec) || !pa_channel_map_equal(map, &s->channel_map)) + if (!(resampler = pa_resampler_new(spec, map, &s->sample_spec, &s->channel_map, s->core->memblock_stat, resample_method))) return NULL; - i = pa_xmalloc(sizeof(pa_sink_input)); + i = pa_xnew(pa_sink_input, 1); i->ref = 1; i->state = PA_SINK_INPUT_RUNNING; i->name = pa_xstrdup(name); - i->typeid = typeid; - i->client = NULL; + i->driver = pa_xstrdup(driver); i->owner = NULL; i->sink = s; + i->client = NULL; + i->sample_spec = *spec; + i->channel_map = *map; + pa_cvolume_reset(&i->volume, spec->channels); + i->peek = NULL; i->drop = NULL; i->kill = NULL; i->get_latency = NULL; - i->userdata = NULL; i->underrun = NULL; + i->userdata = NULL; - i->volume = PA_VOLUME_NORM; i->playing = 0; - i->resampled_chunk.memblock = NULL; - i->resampled_chunk.index = i->resampled_chunk.length = 0; + pa_memchunk_reset(&i->resampled_chunk); i->resampler = resampler; assert(s->core); @@ -94,7 +113,10 @@ pa_sink_input* pa_sink_input_new(pa_sink *s, pa_typeid_t typeid, const char *nam } void pa_sink_input_disconnect(pa_sink_input *i) { - assert(i && i->state != PA_SINK_INPUT_DISCONNECTED && i->sink && i->sink->core); + assert(i); + assert(i->state != PA_SINK_INPUT_DISCONNECTED); + assert(i->sink); + assert(i->sink->core); pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); pa_idxset_remove_by_data(i->sink->inputs, i, NULL); @@ -106,7 +128,9 @@ void pa_sink_input_disconnect(pa_sink_input *i) { i->drop = NULL; i->kill = NULL; i->get_latency = NULL; + i->underrun = NULL; + i->playing = 0; i->state = PA_SINK_INPUT_DISCONNECTED; } @@ -120,28 +144,34 @@ static void sink_input_free(pa_sink_input* i) { if (i->resampled_chunk.memblock) pa_memblock_unref(i->resampled_chunk.memblock); + if (i->resampler) pa_resampler_free(i->resampler); pa_xfree(i->name); + pa_xfree(i->driver); pa_xfree(i); } void pa_sink_input_unref(pa_sink_input *i) { - assert(i && i->ref >= 1); + assert(i); + assert(i->ref >= 1); if (!(--i->ref)) sink_input_free(i); } pa_sink_input* pa_sink_input_ref(pa_sink_input *i) { - assert(i && i->ref >= 1); + assert(i); + assert(i->ref >= 1); + i->ref++; return i; } void pa_sink_input_kill(pa_sink_input*i) { - assert(i && i->ref >= 1); + assert(i); + assert(i->ref >= 1); if (i->kill) i->kill(i); @@ -149,7 +179,9 @@ void pa_sink_input_kill(pa_sink_input*i) { pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) { pa_usec_t r = 0; - assert(i && i->ref >= 1); + + assert(i); + assert(i->ref >= 1); if (i->get_latency) r += i->get_latency(i); @@ -160,20 +192,28 @@ pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) { return r; } -int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { +int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) { int ret = -1; - assert(i && chunk && i->ref >= 1); + int do_volume_adj_here; + + assert(i); + assert(i->ref >= 1); + assert(chunk); + assert(volume); pa_sink_input_ref(i); if (!i->peek || !i->drop || i->state == PA_SINK_INPUT_CORKED) goto finish; - + if (!i->resampler) { + do_volume_adj_here = 0; ret = i->peek(i, chunk); goto finish; } + do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map); + while (!i->resampled_chunk.memblock) { pa_memchunk tchunk; size_t l; @@ -182,6 +222,12 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { goto finish; assert(tchunk.length); + + /* It might be necessary to adjust the volume here */ + if (do_volume_adj_here) { + pa_memchunk_make_writable(&tchunk, i->sink->core->memblock_stat, 0); + pa_volume_memchunk(&tchunk, &i->sample_spec, &i->volume); + } l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); @@ -195,7 +241,9 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { pa_memblock_unref(tchunk.memblock); } - assert(i->resampled_chunk.memblock && i->resampled_chunk.length); + assert(i->resampled_chunk.memblock); + assert(i->resampled_chunk.length); + *chunk = i->resampled_chunk; pa_memblock_ref(i->resampled_chunk.memblock); @@ -207,6 +255,19 @@ finish: i->underrun(i); i->playing = ret >= 0; + + if (ret >= 0) { + /* Let's see if we had to apply the volume adjustment + * ourselves, or if this can be done by the sink for us */ + + if (do_volume_adj_here) + /* We've both the same channel map, so let's have the sink do the adjustment for us*/ + + pa_cvolume_reset(volume, i->sample_spec.channels); + else + /* We had different channel maps, so we already did the adjustment */ + *volume = i->volume; + } pa_sink_input_unref(i); @@ -214,7 +275,9 @@ finish: } void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { - assert(i && length && i->ref >= 1); + assert(i); + assert(i->ref >= 1); + assert(length > 0); if (!i->resampler) { if (i->drop) @@ -222,35 +285,50 @@ void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t lengt return; } - assert(i->resampled_chunk.memblock && i->resampled_chunk.length >= length); + assert(i->resampled_chunk.memblock); + assert(i->resampled_chunk.length >= length); i->resampled_chunk.index += length; i->resampled_chunk.length -= length; - if (!i->resampled_chunk.length) { + if (i->resampled_chunk.length <= 0) { pa_memblock_unref(i->resampled_chunk.memblock); i->resampled_chunk.memblock = NULL; i->resampled_chunk.index = i->resampled_chunk.length = 0; } } -void pa_sink_input_set_volume(pa_sink_input *i, pa_volume_t volume) { - assert(i && i->sink && i->sink->core && i->ref >= 1); +void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) { + assert(i); + assert(i->ref >= 1); + assert(i->sink); + assert(i->sink->core); - if (i->volume != volume) { - i->volume = volume; - pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); - } + if (pa_cvolume_equal(&i->volume, volume)) + return; + + i->volume = *volume; + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); +} + +const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i) { + assert(i); + assert(i->ref >= 1); + + return &i->volume; } void pa_sink_input_cork(pa_sink_input *i, int b) { int n; - assert(i && i->ref >= 1); + + assert(i); + assert(i->ref >= 1); if (i->state == PA_SINK_INPUT_DISCONNECTED) return; n = i->state == PA_SINK_INPUT_CORKED && !b; + i->state = b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING; if (n) @@ -258,7 +336,9 @@ void pa_sink_input_cork(pa_sink_input *i, int b) { } void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) { - assert(i && i->resampler && i->ref >= 1); + assert(i); + assert(i->resampler); + assert(i->ref >= 1); if (i->sample_spec.rate == rate) return; @@ -268,7 +348,8 @@ void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) { } void pa_sink_input_set_name(pa_sink_input *i, const char *name) { - assert(i && i->ref >= 1); + assert(i); + assert(i->ref >= 1); pa_xfree(i->name); i->name = pa_xstrdup(name); @@ -276,8 +357,9 @@ void pa_sink_input_set_name(pa_sink_input *i, const char *name) { pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); } -pa_resample_method pa_sink_input_get_resample_method(pa_sink_input *i) { - assert(i && i->ref >= 1); +pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) { + assert(i); + assert(i->ref >= 1); if (!i->resampler) return PA_RESAMPLER_INVALID; diff --git a/polyp/sink-input.h b/polyp/sink-input.h index b4c3ec7f..1db993f5 100644 --- a/polyp/sink-input.h +++ b/polyp/sink-input.h @@ -33,25 +33,27 @@ typedef struct pa_sink_input pa_sink_input; #include "module.h" #include "client.h" -typedef enum { +typedef enum pa_sink_input_state { PA_SINK_INPUT_RUNNING, PA_SINK_INPUT_CORKED, PA_SINK_INPUT_DISCONNECTED -} pa_sink_input_state ; +} pa_sink_input_state_t; struct pa_sink_input { int ref; - pa_sink_input_state state; - uint32_t index; - pa_typeid_t typeid; - - char *name; + pa_sink_input_state_t state; + + char *name, *driver; pa_module *owner; - pa_client *client; + pa_sink *sink; + pa_client *client; + pa_sample_spec sample_spec; - uint32_t volume; + pa_channel_map channel_map; + + pa_cvolume volume; int (*peek) (pa_sink_input *i, pa_memchunk *chunk); void (*drop) (pa_sink_input *i, const pa_memchunk *chunk, size_t length); @@ -67,7 +69,15 @@ struct pa_sink_input { pa_resampler *resampler; }; -pa_sink_input* pa_sink_input_new(pa_sink *s, pa_typeid_t typeid, const char *name, const pa_sample_spec *spec, int variable_rate, int resample_method); +pa_sink_input* pa_sink_input_new( + pa_sink *s, + const char *driver, + const char *name, + const pa_sample_spec *spec, + const pa_channel_map *map, + int variable_rate, + int resample_method); + void pa_sink_input_unref(pa_sink_input* i); pa_sink_input* pa_sink_input_ref(pa_sink_input* i); @@ -79,10 +89,11 @@ void pa_sink_input_kill(pa_sink_input*i); pa_usec_t pa_sink_input_get_latency(pa_sink_input *i); -int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk); +int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume); void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length); -void pa_sink_input_set_volume(pa_sink_input *i, pa_volume_t volume); +void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume); +const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i); void pa_sink_input_cork(pa_sink_input *i, int b); @@ -90,6 +101,6 @@ void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate); void pa_sink_input_set_name(pa_sink_input *i, const char *name); -pa_resample_method pa_sink_input_get_resample_method(pa_sink_input *i); +pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i); #endif diff --git a/polyp/sink.c b/polyp/sink.c index aac90c04..bb656649 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -40,43 +40,54 @@ #define MAX_MIX_CHANNELS 32 -pa_sink* pa_sink_new(pa_core *core, pa_typeid_t typeid, const char *name, int fail, const pa_sample_spec *spec) { +pa_sink* pa_sink_new( + pa_core *core, + const char *driver, + const char *name, + int fail, + const pa_sample_spec *spec, + const pa_channel_map *map) { + pa_sink *s; char *n = NULL; char st[256]; int r; - assert(core && name && *name && spec); - s = pa_xmalloc(sizeof(pa_sink)); + assert(core); + assert(name); + assert(*name); + assert(spec); + + s = pa_xnew(pa_sink, 1); if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) { pa_xfree(s); return NULL; } - s->name = pa_xstrdup(name); - s->description = NULL; - s->typeid = typeid; - s->ref = 1; + s->core = core; s->state = PA_SINK_RUNNING; - + s->name = pa_xstrdup(name); + s->description = NULL; + s->driver = pa_xstrdup(driver); s->owner = NULL; - s->core = core; + s->sample_spec = *spec; + if (map) + s->channel_map = *map; + else + pa_channel_map_init_auto(&s->channel_map, spec->channels); + s->inputs = pa_idxset_new(NULL, NULL); - n = pa_sprintf_malloc("%s_monitor", name); - s->monitor_source = pa_source_new(core, typeid, n, 0, spec); - assert(s->monitor_source); - pa_xfree(n); - s->monitor_source->monitor_of = s; - s->monitor_source->description = pa_sprintf_malloc("Monitor source of sink '%s'", s->name); - - s->volume = PA_VOLUME_NORM; + pa_cvolume_reset(&s->sw_volume, spec->channels); + pa_cvolume_reset(&s->hw_volume, spec->channels); - s->notify = NULL; s->get_latency = NULL; + s->notify = NULL; + s->set_hw_volume = NULL; + s->get_hw_volume = NULL; s->userdata = NULL; r = pa_idxset_put(core->sinks, s, &s->index); @@ -85,6 +96,13 @@ pa_sink* pa_sink_new(pa_core *core, pa_typeid_t typeid, const char *name, int fa pa_sample_spec_snprint(st, sizeof(st), spec); pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); + n = pa_sprintf_malloc("%s_monitor", name); + s->monitor_source = pa_source_new(core, driver, n, 0, spec, map); + assert(s->monitor_source); + pa_xfree(n); + s->monitor_source->monitor_of = s; + s->monitor_source->description = pa_sprintf_malloc("Monitor source of sink '%s'", s->name); + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index); return s; @@ -92,7 +110,9 @@ pa_sink* pa_sink_new(pa_core *core, pa_typeid_t typeid, const char *name, int fa void pa_sink_disconnect(pa_sink* s) { pa_sink_input *i, *j = NULL; - assert(s && s->state == PA_SINK_RUNNING); + + assert(s); + assert(s->state == PA_SINK_RUNNING); pa_namereg_unregister(s->core, s->name); @@ -105,16 +125,19 @@ void pa_sink_disconnect(pa_sink* s) { pa_source_disconnect(s->monitor_source); pa_idxset_remove_by_data(s->core->sinks, s, NULL); - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); - s->notify = NULL; s->get_latency = NULL; + s->notify = NULL; + s->get_hw_volume = NULL; + s->set_hw_volume = NULL; s->state = PA_SINK_DISCONNECTED; + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); } static void sink_free(pa_sink *s) { - assert(s && s->ref == 0); + assert(s); + assert(!s->ref); if (s->state != PA_SINK_DISCONNECTED) pa_sink_disconnect(s); @@ -128,24 +151,29 @@ static void sink_free(pa_sink *s) { pa_xfree(s->name); pa_xfree(s->description); + pa_xfree(s->driver); pa_xfree(s); } void pa_sink_unref(pa_sink*s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); if (!(--s->ref)) sink_free(s); } pa_sink* pa_sink_ref(pa_sink *s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); + s->ref++; return s; } void pa_sink_notify(pa_sink*s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); if (s->notify) s->notify(s); @@ -156,20 +184,25 @@ static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) { pa_sink_input *i; unsigned n = 0; - assert(s && s->ref >= 1 && info); + assert(s); + assert(s->ref >= 1); + assert(info); for (i = pa_idxset_first(s->inputs, &idx); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &idx)) { + /* Increase ref counter, to make sure that this input doesn't + * vanish while we still need it */ pa_sink_input_ref(i); - if (pa_sink_input_peek(i, &info->chunk) < 0) { + if (pa_sink_input_peek(i, &info->chunk, &info->volume) < 0) { pa_sink_input_unref(i); continue; } - info->volume = i->volume; info->userdata = i; - assert(info->chunk.memblock && info->chunk.memblock->data && info->chunk.length); + assert(info->chunk.memblock); + assert(info->chunk.memblock->data); + assert(info->chunk.length); info++; maxinfo--; @@ -180,15 +213,21 @@ static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) { } static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned maxinfo, size_t length) { - assert(s && s->ref >= 1 && info); + assert(s); + assert(s->ref >= 1); + assert(info); for (; maxinfo > 0; maxinfo--, info++) { pa_sink_input *i = info->userdata; - assert(i && info->chunk.memblock); + assert(i); + assert(info->chunk.memblock); + + /* Drop read data */ pa_sink_input_drop(i, &info->chunk, length); pa_memblock_unref(info->chunk.memblock); + /* Decrease ref counter */ pa_sink_input_unref(i); info->userdata = NULL; } @@ -197,8 +236,8 @@ static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned maxinfo, size_t int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; - size_t l; int r = -1; + assert(s); assert(s->ref >= 1); assert(length); @@ -212,37 +251,29 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { goto finish; if (n == 1) { - uint32_t volume = PA_VOLUME_NORM; - pa_sink_input *i = info[0].userdata; - assert(i); + pa_cvolume volume; + *result = info[0].chunk; pa_memblock_ref(result->memblock); if (result->length > length) result->length = length; - l = result->length; - - if (s->volume != PA_VOLUME_NORM || info[0].volume != PA_VOLUME_NORM) - volume = pa_volume_multiply(s->volume, info[0].volume); + pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); - if (volume != PA_VOLUME_NORM) { + if (!pa_cvolume_is_norm(&volume)) { pa_memchunk_make_writable(result, s->core->memblock_stat, 0); - pa_volume_memchunk(result, &s->sample_spec, volume); + pa_volume_memchunk(result, &s->sample_spec, &volume); } } else { result->memblock = pa_memblock_new(length, s->core->memblock_stat); assert(result->memblock); - result->length = l = pa_mix(info, n, result->memblock->data, length, &s->sample_spec, s->volume); + result->length = pa_mix(info, n, result->memblock->data, length, &s->sample_spec, &s->sw_volume); result->index = 0; - - assert(l); } - inputs_drop(s, info, n, l); - - assert(s->monitor_source); + inputs_drop(s, info, n, result->length); pa_source_post(s->monitor_source, result); r = 0; @@ -256,9 +287,14 @@ finish: int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; - size_t l; int r = -1; - assert(s && s->ref >= 1 && target && target->length && target->memblock && target->memblock->data); + + assert(s); + assert(s->ref >= 1); + assert(target); + assert(target->memblock); + assert(target->length); + assert(target->memblock->data); pa_sink_ref(s); @@ -268,27 +304,27 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { goto finish; if (n == 1) { - uint32_t volume = PA_VOLUME_NORM; + pa_cvolume volume; - l = target->length; - if (l > info[0].chunk.length) - l = info[0].chunk.length; + if (target->length > info[0].chunk.length) + target->length = info[0].chunk.length; - memcpy((uint8_t*) target->memblock->data+target->index, (uint8_t*) info[0].chunk.memblock->data + info[0].chunk.index, l); - target->length = l; - - if (s->volume != PA_VOLUME_NORM || info[0].volume != PA_VOLUME_NORM) - volume = pa_volume_multiply(s->volume, info[0].volume); + memcpy((uint8_t*) target->memblock->data + target->index, + (uint8_t*) info[0].chunk.memblock->data + info[0].chunk.index, + target->length); - if (volume != PA_VOLUME_NORM) - pa_volume_memchunk(target, &s->sample_spec, volume); + pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); + + if (!pa_cvolume_is_norm(&volume)) + pa_volume_memchunk(target, &s->sample_spec, &volume); } else - target->length = l = pa_mix(info, n, (uint8_t*) target->memblock->data+target->index, target->length, &s->sample_spec, s->volume); + target->length = pa_mix(info, n, + (uint8_t*) target->memblock->data + target->index, + target->length, + &s->sample_spec, + &s->sw_volume); - assert(l); - inputs_drop(s, info, n, l); - - assert(s->monitor_source); + inputs_drop(s, info, n, target->length); pa_source_post(s->monitor_source, target); r = 0; @@ -302,7 +338,13 @@ finish: void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { pa_memchunk chunk; size_t l, d; - assert(s && s->ref >= 1 && target && target->memblock && target->length && target->memblock->data); + + assert(s); + assert(s->ref >= 1); + assert(target); + assert(target->memblock); + assert(target->length); + assert(target->memblock->data); pa_sink_ref(s); @@ -331,7 +373,10 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { } void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { - assert(s && s->ref >= 1 && length && result); + assert(s); + assert(s->ref >= 1); + assert(length); + assert(result); /*** This needs optimization ***/ @@ -342,7 +387,8 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { } pa_usec_t pa_sink_get_latency(pa_sink *s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); if (!s->get_latency) return 0; @@ -351,7 +397,8 @@ pa_usec_t pa_sink_get_latency(pa_sink *s) { } void pa_sink_set_owner(pa_sink *s, pa_module *m) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); s->owner = m; @@ -359,11 +406,40 @@ void pa_sink_set_owner(pa_sink *s, pa_module *m) { pa_source_set_owner(s->monitor_source, m); } -void pa_sink_set_volume(pa_sink *s, pa_volume_t volume) { - assert(s && s->ref >= 1); +void pa_sink_set_volume(pa_sink *s, pa_mixer_t m, const pa_cvolume *volume) { + pa_cvolume *v; - if (s->volume != volume) { - s->volume = volume; - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); - } + assert(s); + assert(s->ref >= 1); + assert(volume); + + if (m == PA_MIXER_HARDWARE && s->set_hw_volume) + v = &s->hw_volume; + else + v = &s->sw_volume; + + if (pa_cvolume_equal(v, volume)) + return; + + *v = *volume; + + if (v == &s->hw_volume) + if (s->set_hw_volume(s) < 0) + s->sw_volume = *volume; + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); +} + +const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_mixer_t m) { + assert(s); + assert(s->ref >= 1); + + if (m == PA_MIXER_HARDWARE && s->set_hw_volume) { + + if (s->get_hw_volume) + s->get_hw_volume(s); + + return &s->hw_volume; + } else + return &s->sw_volume; } diff --git a/polyp/sink.h b/polyp/sink.h index 22d90858..33aba233 100644 --- a/polyp/sink.h +++ b/polyp/sink.h @@ -30,39 +30,55 @@ typedef struct pa_sink pa_sink; #include "sample.h" #include "idxset.h" #include "source.h" -#include "typeid.h" +#include "channelmap.h" #include "module.h" +#include "volume.h" #define PA_MAX_INPUTS_PER_SINK 6 typedef enum pa_sink_state { PA_SINK_RUNNING, PA_SINK_DISCONNECTED -} pa_sink_state; +} pa_sink_state_t; + +typedef enum pa_mixer { + PA_MIXER_SOFTWARE, + PA_MIXER_HARDWARE +} pa_mixer_t; struct pa_sink { int ref; - pa_sink_state state; - uint32_t index; - pa_typeid_t typeid; + pa_core *core; + pa_sink_state_t state; - char *name, *description; + char *name, *description, *driver; pa_module *owner; - pa_core *core; + pa_sample_spec sample_spec; - pa_idxset *inputs; + pa_channel_map channel_map; + pa_idxset *inputs; pa_source *monitor_source; - - pa_volume_t volume; + + pa_cvolume hw_volume, sw_volume; void (*notify)(pa_sink*sink); pa_usec_t (*get_latency)(pa_sink *s); + int (*set_hw_volume)(pa_sink *s); + int (*get_hw_volume)(pa_sink *s); + void *userdata; }; -pa_sink* pa_sink_new(pa_core *core, pa_typeid_t typeid, const char *name, int fail, const pa_sample_spec *spec); +pa_sink* pa_sink_new( + pa_core *core, + const char *driver, + const char *name, + int namereg_fail, + const pa_sample_spec *spec, + const pa_channel_map *map); + void pa_sink_disconnect(pa_sink* s); void pa_sink_unref(pa_sink*s); pa_sink* pa_sink_ref(pa_sink *s); @@ -78,6 +94,7 @@ void pa_sink_notify(pa_sink*s); void pa_sink_set_owner(pa_sink *sink, pa_module *m); -void pa_sink_set_volume(pa_sink *sink, pa_volume_t volume); +void pa_sink_set_volume(pa_sink *sink, pa_mixer_t m, const pa_cvolume *volume); +const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_mixer_t m); #endif diff --git a/polyp/socket-client.c b/polyp/socket-client.c index a884aa61..29c9775e 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -173,7 +173,7 @@ static void connect_fixed_cb(pa_mainloop_api *m, pa_defer_event *e, void *userda do_call(c); } -static void connect_io_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { +static void connect_io_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { pa_socket_client *c = userdata; assert(m && c && c->io_event == e && fd >= 0); do_call(c); @@ -344,7 +344,7 @@ pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[ #ifdef HAVE_LIBASYNCNS -static void asyncns_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { +static void asyncns_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { pa_socket_client *c = userdata; struct addrinfo *res = NULL; int ret; diff --git a/polyp/socket-server.c b/polyp/socket-server.c index 6f1794bc..262b32a7 100644 --- a/polyp/socket-server.c +++ b/polyp/socket-server.c @@ -78,7 +78,7 @@ struct pa_socket_server { enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX, SOCKET_SERVER_IPV6 } type; }; -static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { +static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { pa_socket_server *s = userdata; pa_iochannel *io; int nfd; diff --git a/polyp/sound-file-stream.c b/polyp/sound-file-stream.c index a277eb25..881e3077 100644 --- a/polyp/sound-file-stream.c +++ b/polyp/sound-file-stream.c @@ -36,7 +36,6 @@ #include "log.h" #define BUF_SIZE (1024*10) -#define PA_TYPEID_SOUND_FILE PA_TYPEID_MAKE('S', 'N', 'D', 'F') struct userdata { SNDFILE *sndfile; @@ -116,15 +115,12 @@ static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t le } } -int pa_play_file(pa_sink *sink, const char *fname, pa_volume_t volume) { +int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume) { struct userdata *u = NULL; SF_INFO sfinfo; pa_sample_spec ss; assert(sink && fname); - if (volume <= 0) - goto fail; - u = pa_xmalloc(sizeof(struct userdata)); u->sink_input = NULL; u->memchunk.memblock = NULL; @@ -161,10 +157,11 @@ int pa_play_file(pa_sink *sink, const char *fname, pa_volume_t volume) { goto fail; } - if (!(u->sink_input = pa_sink_input_new(sink, PA_TYPEID_SOUND_FILE, fname, &ss, 0, -1))) + if (!(u->sink_input = pa_sink_input_new(sink, __FILE__, fname, &ss, NULL, 0, -1))) goto fail; - u->sink_input->volume = volume; + if (volume) + u->sink_input->volume = *volume; u->sink_input->peek = sink_input_peek; u->sink_input->drop = sink_input_drop; u->sink_input->kill = sink_input_kill; diff --git a/polyp/sound-file-stream.h b/polyp/sound-file-stream.h index 0b383f96..2e56ef49 100644 --- a/polyp/sound-file-stream.h +++ b/polyp/sound-file-stream.h @@ -24,6 +24,6 @@ #include "sink.h" -int pa_play_file(pa_sink *sink, const char *fname, pa_volume_t volume); +int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume); #endif diff --git a/polyp/source-output.c b/polyp/source-output.c index 7a540633..e1d8ccf7 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -33,13 +33,24 @@ #include "subscribe.h" #include "log.h" -pa_source_output* pa_source_output_new(pa_source *s, pa_typeid_t typeid, const char *name, const pa_sample_spec *spec, int resample_method) { +pa_source_output* pa_source_output_new( + pa_source *s, + const char *driver, + const char *name, + const pa_sample_spec *spec, + const pa_channel_map *map, + int resample_method) { + pa_source_output *o; pa_resampler *resampler = NULL; int r; char st[256]; - assert(s && spec); + pa_channel_map tmap; + assert(s); + assert(spec); + assert(s->state == PA_SOURCE_RUNNING); + if (pa_idxset_size(s->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { pa_log(__FILE__": Failed to create source output: too many outputs per source.\n"); return NULL; @@ -48,25 +59,31 @@ pa_source_output* pa_source_output_new(pa_source *s, pa_typeid_t typeid, const c if (resample_method == PA_RESAMPLER_INVALID) resample_method = s->core->resample_method; - if (!pa_sample_spec_equal(&s->sample_spec, spec)) - if (!(resampler = pa_resampler_new(&s->sample_spec, spec, s->core->memblock_stat, resample_method))) + if (!map) { + pa_channel_map_init_auto(&tmap, spec->channels); + map = &tmap; + } + + if (!pa_sample_spec_equal(&s->sample_spec, spec) || !pa_channel_map_equal(&s->channel_map, map)) + if (!(resampler = pa_resampler_new(&s->sample_spec, &s->channel_map, spec, map, s->core->memblock_stat, resample_method))) return NULL; o = pa_xmalloc(sizeof(pa_source_output)); o->ref = 1; o->state = PA_SOURCE_OUTPUT_RUNNING; o->name = pa_xstrdup(name); - o->typeid = typeid; - - o->client = NULL; + o->driver = pa_xstrdup(driver); o->owner = NULL; o->source = s; + o->client = NULL; + o->sample_spec = *spec; + o->channel_map = *map; o->push = NULL; o->kill = NULL; - o->userdata = NULL; o->get_latency = NULL; + o->userdata = NULL; o->resampler = resampler; @@ -85,7 +102,10 @@ pa_source_output* pa_source_output_new(pa_source *s, pa_typeid_t typeid, const c } void pa_source_output_disconnect(pa_source_output*o) { - assert(o && o->state != PA_SOURCE_OUTPUT_DISCONNECTED && o->source && o->source->core); + assert(o); + assert(o->state != PA_SOURCE_OUTPUT_DISCONNECTED); + assert(o->source); + assert(o->source->core); pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); pa_idxset_remove_by_data(o->source->outputs, o, NULL); @@ -95,7 +115,7 @@ void pa_source_output_disconnect(pa_source_output*o) { o->push = NULL; o->kill = NULL; - + o->get_latency = NULL; o->state = PA_SOURCE_OUTPUT_DISCONNECTED; } @@ -112,26 +132,31 @@ static void source_output_free(pa_source_output* o) { pa_resampler_free(o->resampler); pa_xfree(o->name); + pa_xfree(o->driver); pa_xfree(o); } void pa_source_output_unref(pa_source_output* o) { - assert(o && o->ref >= 1); + assert(o); + assert(o->ref >= 1); if (!(--o->ref)) source_output_free(o); } pa_source_output* pa_source_output_ref(pa_source_output *o) { - assert(o && o->ref >= 1); + assert(o); + assert(o->ref >= 1); + o->ref++; return o; } void pa_source_output_kill(pa_source_output*o) { - assert(o && o->ref >= 1); + assert(o); + assert(o->ref >= 1); if (o->kill) o->kill(o); @@ -139,7 +164,11 @@ void pa_source_output_kill(pa_source_output*o) { void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { pa_memchunk rchunk; - assert(o && chunk && chunk->length && o->push); + + assert(o); + assert(chunk); + assert(chunk->length); + assert(o->push); if (o->state == PA_SOURCE_OUTPUT_CORKED) return; @@ -159,7 +188,9 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { } void pa_source_output_set_name(pa_source_output *o, const char *name) { - assert(o && o->ref >= 1); + assert(o); + assert(o->ref >= 1); + pa_xfree(o->name); o->name = pa_xstrdup(name); @@ -167,7 +198,8 @@ void pa_source_output_set_name(pa_source_output *o, const char *name) { } pa_usec_t pa_source_output_get_latency(pa_source_output *o) { - assert(o && o->ref >= 1); + assert(o); + assert(o->ref >= 1); if (o->get_latency) return o->get_latency(o); @@ -176,7 +208,8 @@ pa_usec_t pa_source_output_get_latency(pa_source_output *o) { } void pa_source_output_cork(pa_source_output *o, int b) { - assert(o && o->ref >= 1); + assert(o); + assert(o->ref >= 1); if (o->state == PA_SOURCE_OUTPUT_DISCONNECTED) return; @@ -184,9 +217,10 @@ void pa_source_output_cork(pa_source_output *o, int b) { o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; } -pa_resample_method pa_source_output_get_resample_method(pa_source_output *o) { - assert(o && o->ref >= 1); - +pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { + assert(o); + assert(o->ref >= 1); + if (!o->resampler) return PA_RESAMPLER_INVALID; diff --git a/polyp/source-output.h b/polyp/source-output.h index ef8f9fa9..f8e4b152 100644 --- a/polyp/source-output.h +++ b/polyp/source-output.h @@ -37,20 +37,21 @@ typedef enum { PA_SOURCE_OUTPUT_RUNNING, PA_SOURCE_OUTPUT_CORKED, PA_SOURCE_OUTPUT_DISCONNECTED -} pa_source_output_state; +} pa_source_output_state_t; struct pa_source_output { int ref; - pa_source_output_state state; - uint32_t index; - pa_typeid_t typeid; - - char *name; + pa_source_output_state_t state; + + char *name, *driver; pa_module *owner; - pa_client *client; + pa_source *source; + pa_client *client; + pa_sample_spec sample_spec; + pa_channel_map channel_map; void (*push)(pa_source_output *o, const pa_memchunk *chunk); void (*kill)(pa_source_output* o); @@ -61,7 +62,14 @@ struct pa_source_output { void *userdata; }; -pa_source_output* pa_source_output_new(pa_source *s, pa_typeid_t typeid, const char *name, const pa_sample_spec *spec, int resample_method); +pa_source_output* pa_source_output_new( + pa_source *s, + const char *driver, + const char *name, + const pa_sample_spec *spec, + const pa_channel_map *map, + int resample_method); + void pa_source_output_unref(pa_source_output* o); pa_source_output* pa_source_output_ref(pa_source_output *o); @@ -79,6 +87,6 @@ pa_usec_t pa_source_output_get_latency(pa_source_output *i); void pa_source_output_cork(pa_source_output *i, int b); -pa_resample_method pa_source_output_get_resample_method(pa_source_output *o); +pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o); #endif diff --git a/polyp/source.c b/polyp/source.c index c287899e..6e377b20 100644 --- a/polyp/source.c +++ b/polyp/source.c @@ -35,13 +35,24 @@ #include "subscribe.h" #include "log.h" -pa_source* pa_source_new(pa_core *core, pa_typeid_t typeid, const char *name, int fail, const pa_sample_spec *spec) { +pa_source* pa_source_new( + pa_core *core, + const char *driver, + const char *name, + int fail, + const pa_sample_spec *spec, + const pa_channel_map *map) { + pa_source *s; char st[256]; int r; - assert(core && spec && name && *name); + + assert(core); + assert(name); + assert(*name); + assert(spec); - s = pa_xmalloc(sizeof(pa_source)); + s = pa_xnew(pa_source, 1); if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SOURCE, s, fail))) { pa_xfree(s); @@ -49,15 +60,19 @@ pa_source* pa_source_new(pa_core *core, pa_typeid_t typeid, const char *name, in } s->ref = 1; + s->core = core; s->state = PA_SOURCE_RUNNING; - s->name = pa_xstrdup(name); s->description = NULL; - s->typeid = typeid; - + s->driver = pa_xstrdup(driver); s->owner = NULL; - s->core = core; + s->sample_spec = *spec; + if (map) + s->channel_map = *map; + else + pa_channel_map_init_auto(&s->channel_map, spec->channels); + s->outputs = pa_idxset_new(NULL, NULL); s->monitor_of = NULL; @@ -78,7 +93,9 @@ pa_source* pa_source_new(pa_core *core, pa_typeid_t typeid, const char *name, in void pa_source_disconnect(pa_source *s) { pa_source_output *o, *j = NULL; - assert(s && s->state == PA_SOURCE_RUNNING); + + assert(s); + assert(s->state == PA_SOURCE_RUNNING); pa_namereg_unregister(s->core, s->name); @@ -89,15 +106,17 @@ void pa_source_disconnect(pa_source *s) { } pa_idxset_remove_by_data(s->core->sources, s, NULL); - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); + s->get_latency = NULL; s->notify = NULL; s->state = PA_SOURCE_DISCONNECTED; + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); } static void source_free(pa_source *s) { - assert(s && !s->ref); + assert(s); + assert(!s->ref); if (s->state != PA_SOURCE_DISCONNECTED) pa_source_disconnect(s); @@ -108,40 +127,49 @@ static void source_free(pa_source *s) { pa_xfree(s->name); pa_xfree(s->description); + pa_xfree(s->driver); pa_xfree(s); } void pa_source_unref(pa_source *s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); if (!(--s->ref)) source_free(s); } pa_source* pa_source_ref(pa_source *s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); + s->ref++; return s; } void pa_source_notify(pa_source*s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); if (s->notify) s->notify(s); } static int do_post(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void*userdata) { - const pa_memchunk *chunk = userdata; pa_source_output *o = p; - assert(o && o->push && del && chunk); + const pa_memchunk *chunk = userdata; + + assert(o); + assert(chunk); pa_source_output_push(o, chunk); return 0; } void pa_source_post(pa_source*s, const pa_memchunk *chunk) { - assert(s && s->ref >= 1 && chunk); + assert(s); + assert(s->ref >= 1); + assert(chunk); pa_source_ref(s); pa_idxset_foreach(s->outputs, do_post, (void*) chunk); @@ -150,11 +178,14 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) { void pa_source_set_owner(pa_source *s, pa_module *m) { assert(s); + assert(s->ref >= 1); + s->owner = m; } pa_usec_t pa_source_get_latency(pa_source *s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); if (!s->get_latency) return 0; diff --git a/polyp/source.h b/polyp/source.h index c7f8d059..823a9424 100644 --- a/polyp/source.h +++ b/polyp/source.h @@ -31,7 +31,7 @@ typedef struct pa_source pa_source; #include "memblock.h" #include "memchunk.h" #include "sink.h" -#include "typeid.h" +#include "channelmap.h" #include "module.h" #define PA_MAX_OUTPUTS_PER_SOURCE 16 @@ -39,28 +39,37 @@ typedef struct pa_source pa_source; typedef enum pa_source_state { PA_SOURCE_RUNNING, PA_SOURCE_DISCONNECTED -} pa_source_state; +} pa_source_state_t; struct pa_source { int ref; - pa_source_state state; - uint32_t index; - pa_typeid_t typeid; + pa_core *core; + pa_source_state_t state; - char *name, *description; + char *name, *description, *driver; pa_module *owner; - pa_core *core; + pa_sample_spec sample_spec; + pa_channel_map channel_map; + pa_idxset *outputs; pa_sink *monitor_of; - + void (*notify)(pa_source*source); pa_usec_t (*get_latency)(pa_source *s); + void *userdata; }; -pa_source* pa_source_new(pa_core *core, pa_typeid_t typeid, const char *name, int fail, const pa_sample_spec *spec); +pa_source* pa_source_new( + pa_core *core, + const char *driver, + const char *name, + int namereg_fail, + const pa_sample_spec *spec, + const pa_channel_map *map); + void pa_source_disconnect(pa_source *s); void pa_source_unref(pa_source *s); pa_source* pa_source_ref(pa_source *c); diff --git a/polyp/subscribe.c b/polyp/subscribe.c index d3db90f7..e8b3c841 100644 --- a/polyp/subscribe.c +++ b/polyp/subscribe.c @@ -41,22 +41,22 @@ struct pa_subscription { pa_core *core; int dead; - void (*callback)(pa_core *c, pa_subscription_event_type t, uint32_t index, void *userdata); + void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata); void *userdata; - pa_subscription_mask mask; + pa_subscription_mask_t mask; pa_subscription *prev, *next; }; struct pa_subscription_event { - pa_subscription_event_type type; + pa_subscription_event_type_t type; uint32_t index; }; static void sched_event(pa_core *c); /* Allocate a new subscription object for the given subscription mask. Use the specified callback function and user data */ -pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask m, void (*callback)(pa_core *c, pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { +pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata) { pa_subscription *s; assert(c); @@ -210,7 +210,7 @@ static void sched_event(pa_core *c) { } /* Append a new subscription event to the subscription event queue and schedule a main loop event */ -void pa_subscription_post(pa_core *c, pa_subscription_event_type t, uint32_t index) { +void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t index) { pa_subscription_event *e; assert(c); diff --git a/polyp/subscribe.h b/polyp/subscribe.h index 6980328f..625159e3 100644 --- a/polyp/subscribe.h +++ b/polyp/subscribe.h @@ -28,10 +28,10 @@ typedef struct pa_subscription_event pa_subscription_event; #include "core.h" #include "native-common.h" -pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask m, void (*callback)(pa_core *c, pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); +pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata); void pa_subscription_free(pa_subscription*s); void pa_subscription_free_all(pa_core *c); -void pa_subscription_post(pa_core *c, pa_subscription_event_type t, uint32_t idx); +void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t idx); #endif diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c index 28b1afa6..d4980411 100644 --- a/polyp/tagstruct.c +++ b/polyp/tagstruct.c @@ -54,7 +54,9 @@ enum tags { TAG_BOOLEAN_TRUE = '1', TAG_BOOLEAN_FALSE = '0', TAG_TIMEVAL = 'T', - TAG_USEC = 'U' /* 64bit unsigned */ + TAG_USEC = 'U' /* 64bit unsigned */, + TAG_CHANNEL_MAP = 'm', + TAG_CVOLUME = 'v' }; struct pa_tagstruct { @@ -204,6 +206,34 @@ void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) { t->length += 9; } +void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) { + unsigned i; + + assert(t); + extend(t, 2 + map->channels); + + t->data[t->length++] = TAG_CHANNEL_MAP; + t->data[t->length++] = map->channels; + + for (i = 0; i < map->channels; i ++) + t->data[t->length++] = (uint8_t) map->map[i]; +} + +void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) { + unsigned i; + + assert(t); + extend(t, 2 + cvolume->channels * sizeof(pa_volume_t)); + + t->data[t->length++] = TAG_CVOLUME; + t->data[t->length++] = cvolume->channels; + + for (i = 0; i < cvolume->channels; i ++) { + *(pa_volume_t*) (t->data + t->length) = htonl(cvolume->values[i]); + t->length += sizeof(pa_volume_t); + } +} + int pa_tagstruct_gets(pa_tagstruct*t, const char **s) { int error = 0; size_t n; @@ -283,6 +313,9 @@ int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) { ss->channels = t->data[t->rindex+2]; memcpy(&ss->rate, t->data+t->rindex+3, 4); ss->rate = ntohl(ss->rate); + + if (!pa_sample_spec_valid(ss)) + return -1; t->rindex += 7; return 0; @@ -387,3 +420,59 @@ int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) { t->rindex +=9; return 0; } + +int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) { + unsigned i; + + assert(t); + assert(map); + + if (t->rindex+2 > t->length) + return -1; + + if (t->data[t->rindex] != TAG_CHANNEL_MAP) + return -1; + + if ((map->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX) + return -1; + + if (t->rindex+2+map->channels > t->length) + return -1; + + for (i = 0; i < map->channels; i ++) + map->map[i] = (int8_t) t->data[t->rindex + 2 + i]; + + if (!pa_channel_map_valid(map)) + return -1; + + t->rindex += 2 + map->channels; + return 0; +} + +int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) { + unsigned i; + + assert(t); + assert(cvolume); + + if (t->rindex+2 > t->length) + return -1; + + if (t->data[t->rindex] != TAG_CVOLUME) + return -1; + + if ((cvolume->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX) + return -1; + + if (t->rindex+2+cvolume->channels*sizeof(pa_volume_t) > t->length) + return -1; + + for (i = 0; i < cvolume->channels; i ++) + cvolume->values[i] = (pa_volume_t) ntohl(*((pa_volume_t*) (t->data + t->rindex + 2)+i)); + + if (!pa_cvolume_valid(cvolume)) + return -1; + + t->rindex += 2 + cvolume->channels * sizeof(pa_volume_t); + return 0; +} diff --git a/polyp/tagstruct.h b/polyp/tagstruct.h index 85b324b7..cd6a8f99 100644 --- a/polyp/tagstruct.h +++ b/polyp/tagstruct.h @@ -28,6 +28,8 @@ #include #include "sample.h" +#include "channelmap.h" +#include "volume.h" typedef struct pa_tagstruct pa_tagstruct; @@ -44,6 +46,8 @@ void pa_tagstruct_put_arbitrary(pa_tagstruct*t, const void *p, size_t length); void pa_tagstruct_put_boolean(pa_tagstruct*t, int b); void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv); void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u); +void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map); +void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume); int pa_tagstruct_gets(pa_tagstruct*t, const char **s); int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c); @@ -54,6 +58,8 @@ int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length); int pa_tagstruct_get_boolean(pa_tagstruct *t, int *b); int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv); int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u); +int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map); +int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *v); int pa_tagstruct_eof(pa_tagstruct*t); const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l); diff --git a/polyp/typeid.c b/polyp/typeid.c deleted file mode 100644 index 70d3df33..00000000 --- a/polyp/typeid.c +++ /dev/null @@ -1,33 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "typeid.h" - -char *pa_typeid_to_string(pa_typeid_t id, char *ret_s, size_t length) { - if (id == PA_TYPEID_UNKNOWN) - snprintf(ret_s, length, "????"); - else - snprintf(ret_s, length, "%c%c%c%c", (char) (id >> 24), (char) (id >> 16), (char) (id >> 8), (char) (id)); - - return ret_s; -} diff --git a/polyp/typeid.h b/polyp/typeid.h deleted file mode 100644 index cc1676bc..00000000 --- a/polyp/typeid.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef footypeidhfoo -#define footypeidhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -#include - -PA_C_DECL_BEGIN - -typedef uint32_t pa_typeid_t; - -#define PA_TYPEID_UNKNOWN ((pa_typeid_t) -1) - -char *pa_typeid_to_string(pa_typeid_t id, char *ret_s, size_t length); - -#define PA_TYPEID_MAKE(a,b,c,d) (\ - (((pa_typeid_t) a & 0xFF) << 24) | \ - (((pa_typeid_t) b & 0xFF) << 16) | \ - (((pa_typeid_t) c & 0xFF) << 8) | \ - (((pa_typeid_t) d & 0xFF))) - -PA_C_DECL_END - -#endif diff --git a/polyp/voltest.c b/polyp/voltest.c index 286334d0..917e04d3 100644 --- a/polyp/voltest.c +++ b/polyp/voltest.c @@ -2,14 +2,19 @@ #include -#include +#include #include "gccmacro.h" int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { - int p; - for (p = 0; p <= 200; p++) { - pa_volume_t v = pa_volume_from_user((double) p/100); - double dB = pa_volume_to_dB(v); - printf("%3i%% = %u = %0.2f dB = %u = %3i%%\n", p, v, dB, pa_volume_from_dB(dB), (int) (pa_volume_to_user(v)*100)); + pa_volume_t v; + + for (v = PA_VOLUME_MUTED; v <= PA_VOLUME_NORM*2; v += 256) { + + double dB = pa_sw_volume_to_dB(v); + double f = pa_sw_volume_to_linear(v); + + printf("Volume: %3i; percent: %i%%; decibel %0.2f; linear = %0.2f; volume(decibel): %3i; volume(linear): %3i\n", + v, (v*100)/PA_VOLUME_NORM, dB, f, pa_sw_volume_from_dB(dB), pa_sw_volume_from_linear(f)); + } } diff --git a/polyp/volume.c b/polyp/volume.c new file mode 100644 index 00000000..0f153141 --- /dev/null +++ b/polyp/volume.c @@ -0,0 +1,176 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "volume.h" + +int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) { + int i; + assert(a); + assert(b); + + if (a->channels != b->channels) + return 0; + + for (i = 0; i < a->channels; i++) + if (a->values[i] != b->values[i]) + return 0; + + return 1; +} + +pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) { + int i; + + assert(a); + assert(channels > 0); + assert(channels <= PA_CHANNELS_MAX); + + a->channels = channels; + + for (i = 0; i < a->channels; i++) + a->values[i] = v; + + return a; +} + +pa_volume_t pa_cvolume_avg(const pa_cvolume *a) { + uint64_t sum = 0; + int i; + assert(a); + + for (i = 0; i < a->channels; i++) + sum += a->values[i]; + + sum /= a->channels; + + return (pa_volume_t) sum; +} + +pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) { + return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a)* pa_sw_volume_to_linear(b)); +} + +#define USER_DECIBEL_RANGE 30 + +pa_volume_t pa_sw_volume_from_dB(double dB) { + if (dB <= -USER_DECIBEL_RANGE) + return PA_VOLUME_MUTED; + + return (pa_volume_t) ((dB/USER_DECIBEL_RANGE+1)*PA_VOLUME_NORM); +} + +double pa_sw_volume_to_dB(pa_volume_t v) { + if (v == PA_VOLUME_MUTED) + return PA_DECIBEL_MININFTY; + + return ((double) v/PA_VOLUME_NORM-1)*USER_DECIBEL_RANGE; +} + +pa_volume_t pa_sw_volume_from_linear(double v) { + + if (v <= 0) + return PA_VOLUME_MUTED; + + if (v > .999 && v < 1.001) + return PA_VOLUME_NORM; + + return pa_sw_volume_from_dB(20*log10(v)); +} + +double pa_sw_volume_to_linear(pa_volume_t v) { + + if (v == PA_VOLUME_MUTED) + return 0; + + return pow(10, pa_sw_volume_to_dB(v)/20); +} + +char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) { + unsigned channel; + int first = 1; + char *e; + + assert(s); + assert(l > 0); + assert(c); + + *(e = s) = 0; + + for (channel = 0; channel < c->channels && l > 1; channel++) { + l -= snprintf(e, l, "%s%u: %3u%%", + first ? "" : " ", + channel, + (c->values[channel]*100)/PA_VOLUME_NORM); + + e = strchr(e, 0); + first = 0; + } + + return s; +} + +/** Return non-zero if the volume of all channels is equal to the specified value */ +int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) { + unsigned c; + assert(a); + + for (c = 0; c < a->channels; c++) + if (a->values[c] != v) + return 0; + + return 1; +} + +pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { + unsigned i; + + assert(dest); + assert(a); + assert(b); + + for (i = 0; i < a->channels || i < b->channels || i < PA_CHANNELS_MAX; i++) { + + dest->values[i] = pa_sw_volume_multiply( + i < a->channels ? a->values[i] : PA_VOLUME_NORM, + i < b->channels ? b->values[i] : PA_VOLUME_NORM); + } + + dest->channels = i; + + return dest; +} + +int pa_cvolume_valid(const pa_cvolume *v) { + assert(v); + + if (v->channels <= 0 || v->channels > PA_CHANNELS_MAX) + return 0; + + return 1; +} diff --git a/polyp/volume.h b/polyp/volume.h new file mode 100644 index 00000000..b2a48084 --- /dev/null +++ b/polyp/volume.h @@ -0,0 +1,107 @@ +#ifndef foovolumehfoo +#define foovolumehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include + +/** \file + * Constants and routines for volume handling */ + +PA_C_DECL_BEGIN + +/** Volume specification: + * PA_VOLUME_MUTED: silence; + * < PA_VOLUME_NORM: decreased volume; + * PA_VOLUME_NORM: normal volume; + * > PA_VOLUME_NORM: increased volume */ +typedef uint32_t pa_volume_t; + +/** Normal volume (100%) */ +#define PA_VOLUME_NORM (0x10000) + +/** Muted volume (0%) */ +#define PA_VOLUME_MUTED (0) + +/** A structure encapsulating a per-channel volume */ +typedef struct pa_cvolume { + uint8_t channels; + pa_volume_t values[PA_CHANNELS_MAX]; +} pa_cvolume; + +/** Return non-zero when *a == *b */ +int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b); + +/** Set the volume of all channels to PA_VOLUME_NORM */ +#define pa_cvolume_reset(a, n) pa_cvolume_set((a), (n), PA_VOLUME_NORM) + +/** Set the volume of all channels to PA_VOLUME_MUTED */ +#define pa_cvolume_mute(a, n) pa_cvolume_set((a), (n), PA_VOLUME_MUTED) + +/** Set the volume of all channels to the specified parameter */ +pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v); + +/** Pretty print a volume structure */ +#define PA_CVOLUME_SNPRINT_MAX 64 +char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c); + +/** Return the average volume of all channels */ +pa_volume_t pa_cvolume_avg(const pa_cvolume *a); + +/** Return TRUE when the passed cvolume structure is valid, FALSE otherwise */ +int pa_cvolume_valid(const pa_cvolume *v); + +/** Return non-zero if the volume of all channels is equal to the specified value */ +int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v); + +#define pa_cvolume_is_muted(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_MUTED) +#define pa_cvolume_is_norm(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_NORM) + +/** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. */ +pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b); + +pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b); + +/** Convert a decibel value to a volume. \since 0.4 */ +pa_volume_t pa_sw_volume_from_dB(double f); + +/** Convert a volume to a decibel value. \since 0.4 */ +double pa_sw_volume_to_dB(pa_volume_t v); + +/** Convert a linear factor to a volume. \since 0.8 */ +pa_volume_t pa_sw_volume_from_linear(double v); + +/** Convert a volume to a linear factor. \since 0.8 */ +double pa_sw_volume_to_linear(pa_volume_t v); + +#ifdef INFINITY +#define PA_DECIBEL_MININFTY (-INFINITY) +#else +/** This value is used as minus infinity when using pa_volume_{to,from}_dB(). \since 0.4 */ +#define PA_DECIBEL_MININFTY (-200) +#endif + +PA_C_DECL_END + +#endif diff --git a/polyp/x11prop.c b/polyp/x11prop.c index bbe3e32c..e57fc136 100644 --- a/polyp/x11prop.c +++ b/polyp/x11prop.c @@ -33,7 +33,7 @@ void pa_x11_set_prop(Display *d, const char *name, const char *data) { Atom a = XInternAtom(d, name, False); - XChangeProperty(d, RootWindow(d, 0), a, XA_STRING, 8, PropModeReplace, (unsigned char*) data, strlen(data)+1); + XChangeProperty(d, RootWindow(d, 0), a, XA_STRING, 8, PropModeReplace, (const unsigned char*) data, strlen(data)+1); } void pa_x11_del_prop(Display *d, const char *name) { diff --git a/polyp/x11wrap.c b/polyp/x11wrap.c index 64923320..e20a50a6 100644 --- a/polyp/x11wrap.c +++ b/polyp/x11wrap.c @@ -76,7 +76,7 @@ static void work(pa_x11_wrapper *w) { } /* IO notification event for the X11 display connection */ -static void display_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { +static void display_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { pa_x11_wrapper *w = userdata; assert(m && e && fd >= 0 && w && w->ref >= 1); work(w); @@ -90,7 +90,7 @@ static void defer_event(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { } /* IO notification event for X11 internal connections */ -static void internal_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { +static void internal_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { pa_x11_wrapper *w = userdata; assert(m && e && fd >= 0 && w && w->ref >= 1); -- cgit From 8580967062c79d49c35a24052f682533d1baa461 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 27 Jan 2006 16:30:09 +0000 Subject: add support more for up to 16 auxiliary channel positions git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@464 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/channelmap.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/polyp/channelmap.h b/polyp/channelmap.h index 6466eecf..0b9f6e26 100644 --- a/polyp/channelmap.h +++ b/polyp/channelmap.h @@ -54,6 +54,7 @@ typedef enum { PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, + PA_CHANNEL_POSITION_AUX0, PA_CHANNEL_POSITION_AUX1, PA_CHANNEL_POSITION_AUX2, PA_CHANNEL_POSITION_AUX3, @@ -66,6 +67,9 @@ typedef enum { PA_CHANNEL_POSITION_AUX10, PA_CHANNEL_POSITION_AUX11, PA_CHANNEL_POSITION_AUX12, + PA_CHANNEL_POSITION_AUX13, + PA_CHANNEL_POSITION_AUX14, + PA_CHANNEL_POSITION_AUX15, PA_CHANNEL_POSITION_MAX } pa_channel_position_t; -- cgit From db6dc13e683fbcdb40498f7d1e1e83eba520ac4d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 28 Jan 2006 01:07:09 +0000 Subject: * add variadic function pa_tagstruct_get() and pa_tagstruct_put() for parsing/constructing tagstruct records * convert some of the tagstruct uses to this new API git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@466 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 4 +- polyp/polyplib-stream.c | 29 ++++--- polyp/protocol-native.c | 53 ++++++------ polyp/tagstruct.c | 216 ++++++++++++++++++++++++++++++++++++++---------- polyp/tagstruct.h | 29 ++++++- 5 files changed, 247 insertions(+), 84 deletions(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index ad9952a5..b24d5483 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -46,8 +46,8 @@ AM_CFLAGS = -I$(top_srcdir) AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS AM_CFLAGS += $(LTDLINCL) AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) -AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" -#AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\" +#AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" +AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\" AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\" AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(POLYPAUDIO_BINARY)\" diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 51ee6a22..7b9d6863 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -317,20 +317,25 @@ static void create_stream(pa_stream *s, const char *dev, const pa_buffer_attr *a dev = s->context->conf->default_source; } - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_put_channel_map(t, &s->channel_map); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, dev); - pa_tagstruct_putu32(t, s->buffer_attr.maxlength); - pa_tagstruct_put_boolean(t, !!(flags & PA_STREAM_START_CORKED)); + pa_tagstruct_put(t, + PA_TAG_U32, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM, + PA_TAG_U32, tag = s->context->ctag++, + PA_TAG_STRING, s->name, + PA_TAG_SAMPLE_SPEC, &s->sample_spec, + PA_TAG_CHANNEL_MAP, &s->channel_map, + PA_TAG_U32, PA_INVALID_INDEX, + PA_TAG_STRING, dev, + PA_TAG_U32, s->buffer_attr.maxlength, + PA_TAG_BOOLEAN, !!(flags & PA_STREAM_START_CORKED), + PA_TAG_INVALID); + if (s->direction == PA_STREAM_PLAYBACK) { pa_cvolume cv; - pa_tagstruct_putu32(t, s->buffer_attr.tlength); - pa_tagstruct_putu32(t, s->buffer_attr.prebuf); - pa_tagstruct_putu32(t, s->buffer_attr.minreq); + pa_tagstruct_put(t, + PA_TAG_U32, s->buffer_attr.tlength, + PA_TAG_U32, s->buffer_attr.prebuf, + PA_TAG_U32, s->buffer_attr.minreq, + PA_TAG_INVALID); if (!volume) { pa_cvolume_reset(&cv, s->sample_spec.channels); diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 0491dc41..b94903d9 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -588,18 +588,22 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC assert(c && t && c->protocol && c->protocol->core); - if (pa_tagstruct_gets(t, &name) < 0 || !name || - pa_tagstruct_get_sample_spec(t, &ss) < 0 || - pa_tagstruct_get_channel_map(t, &map) < 0 || - pa_tagstruct_getu32(t, &sink_index) < 0 || - pa_tagstruct_gets(t, &sink_name) < 0 || - pa_tagstruct_getu32(t, &maxlength) < 0 || - pa_tagstruct_get_boolean(t, &corked) < 0 || - pa_tagstruct_getu32(t, &tlength) < 0 || - pa_tagstruct_getu32(t, &prebuf) < 0 || - pa_tagstruct_getu32(t, &minreq) < 0 || - pa_tagstruct_get_cvolume(t, &volume) < 0 || - !pa_tagstruct_eof(t)) { + if (pa_tagstruct_get( + t, + PA_TAG_STRING, &name, + PA_TAG_SAMPLE_SPEC, &ss, + PA_TAG_CHANNEL_MAP, &map, + PA_TAG_U32, &sink_index, + PA_TAG_STRING, &sink_name, + PA_TAG_U32, &maxlength, + PA_TAG_BOOLEAN, &corked, + PA_TAG_U32, &tlength, + PA_TAG_U32, &prebuf, + PA_TAG_U32, &minreq, + PA_TAG_CVOLUME, &volume, + PA_TAG_INVALID) < 0 || + !pa_tagstruct_eof(t) || + !name) { protocol_error(c); return; } @@ -1138,17 +1142,20 @@ static void command_remove_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED static void sink_fill_tagstruct(pa_tagstruct *t, pa_sink *sink) { assert(t && sink); - pa_tagstruct_putu32(t, sink->index); - pa_tagstruct_puts(t, sink->name); - pa_tagstruct_puts(t, sink->description); - pa_tagstruct_put_sample_spec(t, &sink->sample_spec); - pa_tagstruct_put_channel_map(t, &sink->channel_map); - pa_tagstruct_putu32(t, sink->owner ? sink->owner->index : (uint32_t) -1); - pa_tagstruct_put_cvolume(t, pa_sink_get_volume(sink, PA_MIXER_HARDWARE)); - pa_tagstruct_putu32(t, sink->monitor_source->index); - pa_tagstruct_puts(t, sink->monitor_source->name); - pa_tagstruct_put_usec(t, pa_sink_get_latency(sink)); - pa_tagstruct_puts(t, sink->driver); + pa_tagstruct_put( + t, + PA_TAG_U32, sink->index, + PA_TAG_STRING, sink->name, + PA_TAG_STRING, sink->description, + PA_TAG_SAMPLE_SPEC, &sink->sample_spec, + PA_TAG_CHANNEL_MAP, &sink->channel_map, + PA_TAG_U32, sink->owner ? sink->owner->index : PA_INVALID_INDEX, + PA_TAG_CVOLUME, pa_sink_get_volume(sink, PA_MIXER_HARDWARE), + PA_TAG_U32, sink->monitor_source->index, + PA_TAG_STRING, sink->monitor_source->name, + PA_TAG_USEC, pa_sink_get_latency(sink), + PA_TAG_STRING, sink->driver, + PA_TAG_INVALID); } static void source_fill_tagstruct(pa_tagstruct *t, pa_source *source) { diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c index d4980411..64f00e4d 100644 --- a/polyp/tagstruct.c +++ b/polyp/tagstruct.c @@ -28,6 +28,7 @@ #include #include #include +#include #ifdef HAVE_NETINET_IN_H #include @@ -38,26 +39,6 @@ #include "tagstruct.h" #include "xmalloc.h" -enum tags { - TAG_STRING = 't', - TAG_NULL_STRING = 'N', - TAG_U32 = 'L', - TAG_S32 = 'l', - TAG_U16 = 'S', - TAG_S16 = 's', - TAG_U8 = 'B', - TAG_S8 = 'b', - TAG_U64 = 'R', - TAG_S64 = 'r', - TAG_SAMPLE_SPEC = 'a', - TAG_ARBITRARY = 'x', - TAG_BOOLEAN_TRUE = '1', - TAG_BOOLEAN_FALSE = '0', - TAG_TIMEVAL = 'T', - TAG_USEC = 'U' /* 64bit unsigned */, - TAG_CHANNEL_MAP = 'm', - TAG_CVOLUME = 'v' -}; struct pa_tagstruct { uint8_t *data; @@ -105,18 +86,19 @@ static void extend(pa_tagstruct*t, size_t l) { t->data = pa_xrealloc(t->data, t->allocated = t->length+l+100); } + void pa_tagstruct_puts(pa_tagstruct*t, const char *s) { size_t l; assert(t); if (s) { l = strlen(s)+2; extend(t, l); - t->data[t->length] = TAG_STRING; + t->data[t->length] = PA_TAG_STRING; strcpy((char*) (t->data+t->length+1), s); t->length += l; } else { extend(t, 1); - t->data[t->length] = TAG_NULL_STRING; + t->data[t->length] = PA_TAG_STRING_NULL; t->length += 1; } } @@ -124,7 +106,7 @@ void pa_tagstruct_puts(pa_tagstruct*t, const char *s) { void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i) { assert(t); extend(t, 5); - t->data[t->length] = TAG_U32; + t->data[t->length] = PA_TAG_U32; i = htonl(i); memcpy(t->data+t->length+1, &i, 4); t->length += 5; @@ -133,7 +115,7 @@ void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i) { void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c) { assert(t); extend(t, 2); - t->data[t->length] = TAG_U8; + t->data[t->length] = PA_TAG_U8; *(t->data+t->length+1) = c; t->length += 2; } @@ -142,7 +124,7 @@ void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss) { uint32_t rate; assert(t && ss); extend(t, 7); - t->data[t->length] = TAG_SAMPLE_SPEC; + t->data[t->length] = PA_TAG_SAMPLE_SPEC; t->data[t->length+1] = (uint8_t) ss->format; t->data[t->length+2] = ss->channels; rate = htonl(ss->rate); @@ -155,7 +137,7 @@ void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) { assert(t && p); extend(t, 5+length); - t->data[t->length] = TAG_ARBITRARY; + t->data[t->length] = PA_TAG_ARBITRARY; tmp = htonl(length); memcpy(t->data+t->length+1, &tmp, 4); if (length) @@ -166,7 +148,7 @@ void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) { void pa_tagstruct_put_boolean(pa_tagstruct*t, int b) { assert(t); extend(t, 1); - t->data[t->length] = b ? TAG_BOOLEAN_TRUE : TAG_BOOLEAN_FALSE; + t->data[t->length] = b ? PA_TAG_BOOLEAN_TRUE : PA_TAG_BOOLEAN_FALSE; t->length += 1; } @@ -174,7 +156,7 @@ void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv) { uint32_t tmp; assert(t); extend(t, 9); - t->data[t->length] = TAG_TIMEVAL; + t->data[t->length] = PA_TAG_TIMEVAL; tmp = htonl(tv->tv_sec); memcpy(t->data+t->length+1, &tmp, 4); tmp = htonl(tv->tv_usec); @@ -186,7 +168,7 @@ void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u) { uint32_t tmp; assert(t); extend(t, 9); - t->data[t->length] = TAG_USEC; + t->data[t->length] = PA_TAG_USEC; tmp = htonl((uint32_t) (u >> 32)); memcpy(t->data+t->length+1, &tmp, 4); tmp = htonl((uint32_t) u); @@ -198,7 +180,7 @@ void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) { uint32_t tmp; assert(t); extend(t, 9); - t->data[t->length] = TAG_U64; + t->data[t->length] = PA_TAG_U64; tmp = htonl((uint32_t) (u >> 32)); memcpy(t->data+t->length+1, &tmp, 4); tmp = htonl((uint32_t) u); @@ -212,7 +194,7 @@ void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) { assert(t); extend(t, 2 + map->channels); - t->data[t->length++] = TAG_CHANNEL_MAP; + t->data[t->length++] = PA_TAG_CHANNEL_MAP; t->data[t->length++] = map->channels; for (i = 0; i < map->channels; i ++) @@ -225,7 +207,7 @@ void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) { assert(t); extend(t, 2 + cvolume->channels * sizeof(pa_volume_t)); - t->data[t->length++] = TAG_CVOLUME; + t->data[t->length++] = PA_TAG_CVOLUME; t->data[t->length++] = cvolume->channels; for (i = 0; i < cvolume->channels; i ++) { @@ -243,7 +225,7 @@ int pa_tagstruct_gets(pa_tagstruct*t, const char **s) { if (t->rindex+1 > t->length) return -1; - if (t->data[t->rindex] == TAG_NULL_STRING) { + if (t->data[t->rindex] == PA_TAG_STRING_NULL) { t->rindex++; *s = NULL; return 0; @@ -252,7 +234,7 @@ int pa_tagstruct_gets(pa_tagstruct*t, const char **s) { if (t->rindex+2 > t->length) return -1; - if (t->data[t->rindex] != TAG_STRING) + if (t->data[t->rindex] != PA_TAG_STRING) return -1; error = 1; @@ -277,7 +259,7 @@ int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) { if (t->rindex+5 > t->length) return -1; - if (t->data[t->rindex] != TAG_U32) + if (t->data[t->rindex] != PA_TAG_U32) return -1; memcpy(i, t->data+t->rindex+1, 4); @@ -292,7 +274,7 @@ int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) { if (t->rindex+2 > t->length) return -1; - if (t->data[t->rindex] != TAG_U8) + if (t->data[t->rindex] != PA_TAG_U8) return -1; *c = t->data[t->rindex+1]; @@ -306,7 +288,7 @@ int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) { if (t->rindex+7 > t->length) return -1; - if (t->data[t->rindex] != TAG_SAMPLE_SPEC) + if (t->data[t->rindex] != PA_TAG_SAMPLE_SPEC) return -1; ss->format = t->data[t->rindex+1]; @@ -328,7 +310,7 @@ int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) { if (t->rindex+5+length > t->length) return -1; - if (t->data[t->rindex] != TAG_ARBITRARY) + if (t->data[t->rindex] != PA_TAG_ARBITRARY) return -1; memcpy(&len, t->data+t->rindex+1, 4); @@ -357,9 +339,9 @@ int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) { if (t->rindex+1 > t->length) return -1; - if (t->data[t->rindex] == TAG_BOOLEAN_TRUE) + if (t->data[t->rindex] == PA_TAG_BOOLEAN_TRUE) *b = 1; - else if (t->data[t->rindex] == TAG_BOOLEAN_FALSE) + else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE) *b = 0; else return -1; @@ -373,7 +355,7 @@ int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) { if (t->rindex+9 > t->length) return -1; - if (t->data[t->rindex] != TAG_TIMEVAL) + if (t->data[t->rindex] != PA_TAG_TIMEVAL) return -1; memcpy(&tv->tv_sec, t->data+t->rindex+1, 4); @@ -392,7 +374,7 @@ int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) { if (t->rindex+9 > t->length) return -1; - if (t->data[t->rindex] != TAG_USEC) + if (t->data[t->rindex] != PA_TAG_USEC) return -1; memcpy(&tmp, t->data+t->rindex+1, 4); @@ -410,7 +392,7 @@ int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) { if (t->rindex+9 > t->length) return -1; - if (t->data[t->rindex] != TAG_U64) + if (t->data[t->rindex] != PA_TAG_U64) return -1; memcpy(&tmp, t->data+t->rindex+1, 4); @@ -430,7 +412,7 @@ int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) { if (t->rindex+2 > t->length) return -1; - if (t->data[t->rindex] != TAG_CHANNEL_MAP) + if (t->data[t->rindex] != PA_TAG_CHANNEL_MAP) return -1; if ((map->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX) @@ -458,7 +440,7 @@ int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) { if (t->rindex+2 > t->length) return -1; - if (t->data[t->rindex] != TAG_CVOLUME) + if (t->data[t->rindex] != PA_TAG_CVOLUME) return -1; if ((cvolume->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX) @@ -476,3 +458,147 @@ int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) { t->rindex += 2 + cvolume->channels * sizeof(pa_volume_t); return 0; } + +void pa_tagstruct_put(pa_tagstruct *t, ...) { + va_list va; + assert(t); + + va_start(va, t); + + for (;;) { + int tag = va_arg(va, int); + + if (tag == PA_TAG_INVALID) + break; + + switch (tag) { + case PA_TAG_STRING: + case PA_TAG_STRING_NULL: + pa_tagstruct_puts(t, va_arg(va, char*)); + break; + + case PA_TAG_U32: + pa_tagstruct_putu32(t, va_arg(va, uint32_t)); + break; + + case PA_TAG_U8: + pa_tagstruct_putu8(t, (uint8_t) va_arg(va, int)); + break; + + case PA_TAG_U64: + pa_tagstruct_putu64(t, va_arg(va, uint64_t)); + break; + + case PA_TAG_SAMPLE_SPEC: + pa_tagstruct_put_sample_spec(t, va_arg(va, pa_sample_spec*)); + break; + + case PA_TAG_ARBITRARY: { + void *p = va_arg(va, void*); + size_t size = va_arg(va, size_t); + pa_tagstruct_put_arbitrary(t, p, size); + break; + } + + case PA_TAG_BOOLEAN_TRUE: + case PA_TAG_BOOLEAN_FALSE: + pa_tagstruct_put_boolean(t, va_arg(va, int)); + break; + + case PA_TAG_TIMEVAL: + pa_tagstruct_put_timeval(t, va_arg(va, struct timeval*)); + break; + + case PA_TAG_USEC: + pa_tagstruct_put_usec(t, va_arg(va, pa_usec_t)); + break; + + case PA_TAG_CHANNEL_MAP: + pa_tagstruct_put_channel_map(t, va_arg(va, pa_channel_map *)); + break; + + case PA_TAG_CVOLUME: + pa_tagstruct_put_cvolume(t, va_arg(va, pa_cvolume *)); + break; + + default: + abort(); + } + } + + va_end(va); +} + +int pa_tagstruct_get(pa_tagstruct *t, ...) { + va_list va; + int ret = 0; + + assert(t); + + va_start(va, t); + while (ret == 0) { + int tag = va_arg(va, int); + + if (tag == PA_TAG_INVALID) + break; + + switch (tag) { + case PA_TAG_STRING: + case PA_TAG_STRING_NULL: + ret = pa_tagstruct_gets(t, va_arg(va, const char**)); + break; + + case PA_TAG_U32: + ret = pa_tagstruct_getu32(t, va_arg(va, uint32_t*)); + break; + + case PA_TAG_U8: + ret = pa_tagstruct_getu8(t, va_arg(va, uint8_t*)); + break; + + case PA_TAG_U64: + ret = pa_tagstruct_getu64(t, va_arg(va, uint64_t*)); + break; + + case PA_TAG_SAMPLE_SPEC: + ret = pa_tagstruct_get_sample_spec(t, va_arg(va, pa_sample_spec*)); + break; + + case PA_TAG_ARBITRARY: { + const void **p = va_arg(va, const void**); + size_t size = va_arg(va, size_t); + ret = pa_tagstruct_get_arbitrary(t, p, size); + break; + } + + case PA_TAG_BOOLEAN_TRUE: + case PA_TAG_BOOLEAN_FALSE: + ret = pa_tagstruct_get_boolean(t, va_arg(va, int*)); + break; + + case PA_TAG_TIMEVAL: + ret = pa_tagstruct_get_timeval(t, va_arg(va, struct timeval*)); + break; + + case PA_TAG_USEC: + ret = pa_tagstruct_get_usec(t, va_arg(va, pa_usec_t*)); + break; + + case PA_TAG_CHANNEL_MAP: + ret = pa_tagstruct_get_channel_map(t, va_arg(va, pa_channel_map *)); + break; + + case PA_TAG_CVOLUME: + ret = pa_tagstruct_get_cvolume(t, va_arg(va, pa_cvolume *)); + break; + + + default: + abort(); + } + + } + + va_end(va); + return ret; +} diff --git a/polyp/tagstruct.h b/polyp/tagstruct.h index cd6a8f99..b41936ff 100644 --- a/polyp/tagstruct.h +++ b/polyp/tagstruct.h @@ -33,10 +33,35 @@ typedef struct pa_tagstruct pa_tagstruct; +enum { + PA_TAG_INVALID = 0, + PA_TAG_STRING = 't', + PA_TAG_STRING_NULL = 'N', + PA_TAG_U32 = 'L', + PA_TAG_U8 = 'B', + PA_TAG_U64 = 'R', + PA_TAG_SAMPLE_SPEC = 'a', + PA_TAG_ARBITRARY = 'x', + PA_TAG_BOOLEAN_TRUE = '1', + PA_TAG_BOOLEAN_FALSE = '0', + PA_TAG_BOOLEAN = PA_TAG_BOOLEAN_TRUE, + PA_TAG_TIMEVAL = 'T', + PA_TAG_USEC = 'U' /* 64bit unsigned */, + PA_TAG_CHANNEL_MAP = 'm', + PA_TAG_CVOLUME = 'v' +}; + + + pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length); void pa_tagstruct_free(pa_tagstruct*t); uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l); +int pa_tagstruct_eof(pa_tagstruct*t); +const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l); + +void pa_tagstruct_put(pa_tagstruct *t, ...); + void pa_tagstruct_puts(pa_tagstruct*t, const char *s); void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c); void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i); @@ -49,6 +74,8 @@ void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u); void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map); void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume); +int pa_tagstruct_get(pa_tagstruct *t, ...); + int pa_tagstruct_gets(pa_tagstruct*t, const char **s); int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c); int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i); @@ -61,7 +88,5 @@ int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u); int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map); int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *v); -int pa_tagstruct_eof(pa_tagstruct*t); -const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l); #endif -- cgit From f8808a25257a79256f1c7c651386b94c259cbc57 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 30 Jan 2006 11:38:20 +0000 Subject: Print an error message before aborting. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@467 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/sample-util.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/polyp/sample-util.c b/polyp/sample-util.c index d2bb3150..2310f3cb 100644 --- a/polyp/sample-util.c +++ b/polyp/sample-util.c @@ -30,6 +30,7 @@ #include +#include "log.h" #include "sample-util.h" pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) { @@ -316,6 +317,8 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol } default: + pa_log_error(__FILE__": ERROR: Unable to change volume of format %s.\n", + pa_sample_format_to_string(spec->format)); abort(); } } -- cgit From 22db575adc789c9bf6deabefe0843addc7ed2910 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 30 Jan 2006 11:49:03 +0000 Subject: Breaks missing from conversion to a switch statement. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@468 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/sample-util.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/polyp/sample-util.c b/polyp/sample-util.c index 2310f3cb..52974c46 100644 --- a/polyp/sample-util.c +++ b/polyp/sample-util.c @@ -270,6 +270,7 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol if (++channel >= spec->channels) channel = 0; } + break; } case PA_SAMPLE_U8: { @@ -291,6 +292,7 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol if (++channel >= spec->channels) channel = 0; } + break; } case PA_SAMPLE_FLOAT32NE: { @@ -314,6 +316,7 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol t = d + channel; oil_scalarmult_f32(t, skip, t, skip, &v, n); } + break; } default: -- cgit From 7da06d3fe7ce17422e1175339bd59b0dfb716443 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 30 Jan 2006 12:21:53 +0000 Subject: Fixes for the new infrastructure so that the solaris module compiles. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@469 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-solaris.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/polyp/module-solaris.c b/polyp/module-solaris.c index ce9308be..f85e71df 100644 --- a/polyp/module-solaris.c +++ b/polyp/module-solaris.c @@ -57,8 +57,6 @@ PA_MODULE_DESCRIPTION("Solaris Sink/Source") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= buffer_size=") -#define PA_TYPEID_SOLARIS PA_TYPEID_MAKE('S', 'L', 'R', 'S') - struct userdata { pa_sink *sink; pa_source *source; @@ -398,7 +396,7 @@ int pa__init(pa_core *c, pa_module*m) { u->core = c; if (mode != O_WRONLY) { - u->source = pa_source_new(c, PA_TYPEID_SOLARIS, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); assert(u->source); u->source->userdata = u; u->source->get_latency = source_get_latency_cb; @@ -408,7 +406,7 @@ int pa__init(pa_core *c, pa_module*m) { u->source = NULL; if (mode != O_RDONLY) { - u->sink = pa_sink_new(c, PA_TYPEID_SOLARIS, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); + u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; u->sink->userdata = u; -- cgit From dd7b38024a027155a81f4ead9c1e6732768bf152 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 30 Jan 2006 12:58:53 +0000 Subject: Fixes for the new infrastructure so that the waveout module compiles. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@470 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-waveout.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/polyp/module-waveout.c b/polyp/module-waveout.c index a5ef847b..e9d9f12e 100644 --- a/polyp/module-waveout.c +++ b/polyp/module-waveout.c @@ -43,8 +43,6 @@ PA_MODULE_DESCRIPTION("Windows waveOut Sink/Source") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink_name= source_name= record= playback= format= channels= rate= fragments= fragment_size=") -#define PA_TYPEID_WAVEOUT PA_TYPEID_MAKE('W', 'A', 'V', 'E') - #define DEFAULT_SINK_NAME "wave_output" #define DEFAULT_SOURCE_NAME "wave_input" @@ -442,7 +440,7 @@ int pa__init(pa_core *c, pa_module*m) { InitializeCriticalSection(&u->crit); if (hwi != INVALID_HANDLE_VALUE) { - u->source = pa_source_new(c, PA_TYPEID_WAVEOUT, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); assert(u->source); u->source->userdata = u; u->source->notify = notify_source_cb; @@ -453,7 +451,7 @@ int pa__init(pa_core *c, pa_module*m) { u->source = NULL; if (hwo != INVALID_HANDLE_VALUE) { - u->sink = pa_sink_new(c, PA_TYPEID_WAVEOUT, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); + u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); assert(u->sink); u->sink->notify = notify_sink_cb; u->sink->get_latency = sink_get_latency_cb; -- cgit From c34f35a797590376f8a979c1bfc2a35b3bd80f75 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 3 Feb 2006 09:14:30 +0000 Subject: Reverting an incorrect checkin. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@471 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index b24d5483..73039ed1 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -46,8 +46,7 @@ AM_CFLAGS = -I$(top_srcdir) AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS AM_CFLAGS += $(LTDLINCL) AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) -#AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" -AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\" +AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\" AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(POLYPAUDIO_BINARY)\" -- cgit From bbc6dd68e22171670271e694f3a42db736eca60d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 3 Feb 2006 12:23:17 +0000 Subject: Volume adjustment must be done _after_ dropping the chunk since drop will reject a modified chunk. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@472 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/sink-input.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 4a847e46..f447b8cf 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -222,12 +222,6 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) goto finish; assert(tchunk.length); - - /* It might be necessary to adjust the volume here */ - if (do_volume_adj_here) { - pa_memchunk_make_writable(&tchunk, i->sink->core->memblock_stat, 0); - pa_volume_memchunk(&tchunk, &i->sample_spec, &i->volume); - } l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); @@ -237,6 +231,12 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) i->drop(i, &tchunk, l); tchunk.length = l; + /* It might be necessary to adjust the volume here */ + if (do_volume_adj_here) { + pa_memchunk_make_writable(&tchunk, i->sink->core->memblock_stat, 0); + pa_volume_memchunk(&tchunk, &i->sample_spec, &i->volume); + } + pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk); pa_memblock_unref(tchunk.memblock); } -- cgit From d431e0094b95f671a9f557887dc4cfbc40a28d10 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 3 Feb 2006 13:33:21 +0000 Subject: Use defines and not hard coded values for volume levels. Caused incorrect volume levels for all esound clients that changed the volume. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@473 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/protocol-esound.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index ce183a6f..40b0be28 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -474,7 +474,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v assert(k); for (conn = pa_idxset_first(c->protocol->connections, &idx); conn; conn = pa_idxset_next(c->protocol->connections, &idx)) { - int format = ESD_BITS16 | ESD_STEREO, rate = 44100, lvolume = 0xFF, rvolume = 0xFF; + int format = ESD_BITS16 | ESD_STEREO, rate = 44100, lvolume = ESD_VOLUME_BASE, rvolume = ESD_VOLUME_BASE; if (conn->state != ESD_STREAMING_DATA) continue; @@ -483,8 +483,8 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v if (conn->sink_input) { rate = conn->sink_input->sample_spec.rate; - lvolume = (conn->sink_input->volume.values[0]*0xFF)/0x100; - rvolume = (conn->sink_input->volume.values[1]*0xFF)/0x100; + lvolume = (conn->sink_input->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; + rvolume = (conn->sink_input->volume.values[1]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; format = format_native2esd(&conn->sink_input->sample_spec); } @@ -544,11 +544,11 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v response += sizeof(int); /* left */ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (ce->volume.values[0]*0xFF)/0x100); + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); response += sizeof(int); /*right*/ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (ce->volume.values[0]*0xFF)/0x100); + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); response += sizeof(int); /*format*/ @@ -578,9 +578,9 @@ static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t idx = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *(const int*)data)-1; lvolume = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *((const int*)data + 1)); - lvolume = (lvolume*0x100)/0xFF; + lvolume = (lvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; rvolume = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *((const int*)data + 2)); - rvolume = (rvolume*0x100)/0xFF; + rvolume = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; ok = connection_write(c, sizeof(int)); assert(ok); -- cgit From 5c01c1029fc73016184119ce81bb9ae95b3c1f0f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 3 Feb 2006 14:36:19 +0000 Subject: Fix endian conversion macros and reformat them to be a bit more readable. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@474 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/endianmacros.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/polyp/endianmacros.h b/polyp/endianmacros.h index d07652fb..91489cd3 100644 --- a/polyp/endianmacros.h +++ b/polyp/endianmacros.h @@ -28,10 +28,10 @@ #include #endif -#define INT16_SWAP(x) ((int16_t)(((uint16_t) x >> 8) | ((uint16_t) x << 8))) -#define UINT16_SWAP(x) ((uint16_t)(((uint16_t) x >> 8) | ((uint16_t) x << 8))) -#define INT32_SWAP(x) ((int32_t)(((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 16) | (((uint32_t) x) >> 16) & 0xFF00)) -#define UINT32_SWAP(x) ((uint32_t)(((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 16) | ((((uint32_t) x) >> 16) & 0xFF00))) +#define INT16_SWAP(x) ( (int16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) ) +#define UINT16_SWAP(x) ( (uint16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) ) +#define INT32_SWAP(x) ( (int32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) ) +#define UINT32_SWAP(x) ( (uint32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) ) #ifdef WORDS_BIGENDIAN #define INT16_FROM_LE(x) INT16_SWAP(x) -- cgit From d9bfd5b294f2771d9c41fa100d835067dcc7f718 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 3 Feb 2006 14:39:39 +0000 Subject: Let's have just one endian conversion macro suite. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@475 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/endianmacros.h | 3 +++ polyp/esound.h | 6 +----- polyp/protocol-esound.c | 54 ++++++++++++++++++++++++------------------------- 3 files changed, 31 insertions(+), 32 deletions(-) diff --git a/polyp/endianmacros.h b/polyp/endianmacros.h index 91489cd3..3ab1826a 100644 --- a/polyp/endianmacros.h +++ b/polyp/endianmacros.h @@ -33,6 +33,9 @@ #define INT32_SWAP(x) ( (int32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) ) #define UINT32_SWAP(x) ( (uint32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) ) +#define MAYBE_INT32_SWAP(c,x) ((c) ? INT32_SWAP(x) : x) +#define MAYBE_UINT32_SWAP(c,x) ((c) ? UINT32_SWAP(x) : x) + #ifdef WORDS_BIGENDIAN #define INT16_FROM_LE(x) INT16_SWAP(x) #define INT16_FROM_BE(x) ((int16_t)(x)) diff --git a/polyp/esound.h b/polyp/esound.h index 5dc2583b..9c507ef9 100644 --- a/polyp/esound.h +++ b/polyp/esound.h @@ -200,14 +200,10 @@ enum esd_client_state { }; typedef int esd_client_state_t; -/* switch endian order for cross platform playing */ -#define swap_endian_32(x) ((x >> 24) | ((x >> 8) & 0xFF00) | (((x & 0xFF00) << 8)) | (x << 24)) -#define maybe_swap_endian_32(c,x) ((c) ? swap_endian_32(x) : x) - /* the endian key is transferred in binary, if it's read into int, */ /* and matches ESD_ENDIAN_KEY (ENDN), then the endianness of the */ /* server and the client match; if it's SWAP_ENDIAN_KEY, swap data */ -#define ESD_SWAP_ENDIAN_KEY ((uint32_t) swap_endian_32(ESD_ENDIAN_KEY)) +#define ESD_SWAP_ENDIAN_KEY (UINT32_SWAP(ESD_ENDIAN_KEY)) #endif diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 40b0be28..6f004e16 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -46,6 +46,7 @@ #include "xmalloc.h" #include "log.h" #include "util.h" +#include "endianmacros.h" /* Don't accept more connection than this */ #define MAX_CONNECTIONS 10 @@ -301,8 +302,8 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t size_t l; assert(c && length == (sizeof(int)*2+ESD_NAME_MAX)); - format = maybe_swap_endian_32(c->swap_byte_order, *(const int*)data); - rate = maybe_swap_endian_32(c->swap_byte_order, *((const int*)data + 1)); + format = MAYBE_INT32_SWAP(c->swap_byte_order, *(const int*)data); + rate = MAYBE_INT32_SWAP(c->swap_byte_order, *((const int*)data + 1)); ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); @@ -357,8 +358,8 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co size_t l; assert(c && length == (sizeof(int)*2+ESD_NAME_MAX)); - format = maybe_swap_endian_32(c->swap_byte_order, *(const int*)data); - rate = maybe_swap_endian_32(c->swap_byte_order, *((const int*)data + 1)); + format = MAYBE_INT32_SWAP(c->swap_byte_order, *(const int*)data); + rate = MAYBE_INT32_SWAP(c->swap_byte_order, *((const int*)data + 1)); ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); @@ -433,7 +434,7 @@ static int esd_proto_get_latency(struct connection *c, PA_GCC_UNUSED esd_proto_t lag = connection_write(c, sizeof(int)); assert(lag); - *lag = c->swap_byte_order ? swap_endian_32(latency) : latency; + *lag = MAYBE_INT32_SWAP(c->swap_byte_order, latency); return 0; } @@ -451,8 +452,8 @@ static int esd_proto_server_info(struct connection *c, PA_GCC_UNUSED esd_proto_t response = connection_write(c, sizeof(int)*3); assert(response); *(response++) = 0; - *(response++) = maybe_swap_endian_32(c->swap_byte_order, rate); - *(response++) = maybe_swap_endian_32(c->swap_byte_order, format); + *(response++) = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + *(response++) = MAYBE_INT32_SWAP(c->swap_byte_order, format); return 0; } @@ -489,7 +490,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v } /* id */ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (int) (conn->index+1)); + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (int) (conn->index+1)); response += sizeof(int); /* name */ @@ -498,19 +499,19 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v response += ESD_NAME_MAX; /* rate */ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, rate); + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, rate); response += sizeof(int); /* left */ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, lvolume); + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, lvolume); response += sizeof(int); /*right*/ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, rvolume); + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, rvolume); response += sizeof(int); /*format*/ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, format); + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, format); response += sizeof(int); t-= k; @@ -529,7 +530,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v assert(t >= s*2); /* id */ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (int) (ce->index+1)); + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (int) (ce->index+1)); response += sizeof(int); /* name */ @@ -540,23 +541,23 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v response += ESD_NAME_MAX; /* rate */ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, ce->sample_spec.rate); + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, ce->sample_spec.rate); response += sizeof(int); /* left */ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); response += sizeof(int); /*right*/ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); response += sizeof(int); /*format*/ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, format_native2esd(&ce->sample_spec)); + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, format_native2esd(&ce->sample_spec)); response += sizeof(int); /*length*/ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (int) ce->memchunk.length); + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (int) ce->memchunk.length); response += sizeof(int); t -= s; @@ -576,10 +577,10 @@ static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t struct connection *conn; assert(c && data && length == sizeof(int)*3); - idx = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *(const int*)data)-1; - lvolume = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *((const int*)data + 1)); + idx = MAYBE_UINT32_SWAP(c->swap_byte_order, *(const int*)data)-1; + lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, *((const int*)data + 1)); lvolume = (lvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; - rvolume = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *((const int*)data + 2)); + rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, *((const int*)data + 2)); rvolume = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; ok = connection_write(c, sizeof(int)); @@ -606,13 +607,13 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; assert(c && data && length == (ESD_NAME_MAX+3*sizeof(int))); - format = maybe_swap_endian_32(c->swap_byte_order, *(const int*)data); - rate = maybe_swap_endian_32(c->swap_byte_order, *((const int*)data + 1)); + format = MAYBE_INT32_SWAP(c->swap_byte_order, *(const int*)data); + rate = MAYBE_INT32_SWAP(c->swap_byte_order, *((const int*)data + 1)); ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); - sc_length = (size_t) maybe_swap_endian_32(c->swap_byte_order, (*((const int*)data + 2))); + sc_length = (size_t) MAYBE_INT32_SWAP(c->swap_byte_order, (*((const int*)data + 2))); if (sc_length >= MAX_CACHE_SAMPLE_SIZE) return -1; @@ -668,7 +669,7 @@ static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t reque uint32_t idx; assert(c && data && length == sizeof(int)); - idx = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *(const int*)data)-1; + idx = (uint32_t) MAYBE_INT32_SWAP(c->swap_byte_order, *(const int*)data)-1; ok = connection_write(c, sizeof(int)); assert(ok); @@ -729,8 +730,7 @@ static int do_read(struct connection *c) { if ((c->read_data_length+= r) >= sizeof(c->request)) { struct proto_handler *handler; - if (c->swap_byte_order) - c->request = swap_endian_32(c->request); + c->request = MAYBE_INT32_SWAP(c->swap_byte_order, c->request); if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) { pa_log(__FILE__": recieved invalid request.\n"); -- cgit From 8d91ffe4b42d460efff32c36edc51ee01f3af442 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 10 Feb 2006 08:44:42 +0000 Subject: Install the new headers for channels and volume. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@476 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 73039ed1..e2154b32 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -250,6 +250,7 @@ mainloop_test_glib12_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) polypinclude_HEADERS = \ cdecl.h \ + channelmap.h \ glib-mainloop.h \ mainloop.h \ mainloop-api.h \ @@ -265,7 +266,8 @@ polypinclude_HEADERS = \ polyplib-stream.h \ polyplib-subscribe.h \ polyplib-version.h \ - sample.h + sample.h \ + volume.h if HAVE_HOWL polypinclude_HEADERS += \ -- cgit From 4ab432a81952b5ef608775522d27ad9709b97307 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 10 Feb 2006 12:05:33 +0000 Subject: Fix some new alignment bugs in the tagstruct handling. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@477 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/tagstruct.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c index 64f00e4d..676f67de 100644 --- a/polyp/tagstruct.c +++ b/polyp/tagstruct.c @@ -203,6 +203,7 @@ void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) { void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) { unsigned i; + pa_volume_t vol; assert(t); extend(t, 2 + cvolume->channels * sizeof(pa_volume_t)); @@ -211,7 +212,8 @@ void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) { t->data[t->length++] = cvolume->channels; for (i = 0; i < cvolume->channels; i ++) { - *(pa_volume_t*) (t->data + t->length) = htonl(cvolume->values[i]); + vol = htonl(cvolume->values[i]); + memcpy(t->data + t->length, &vol, sizeof(pa_volume_t)); t->length += sizeof(pa_volume_t); } } @@ -433,6 +435,7 @@ int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) { int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) { unsigned i; + pa_volume_t vol; assert(t); assert(cvolume); @@ -449,8 +452,10 @@ int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) { if (t->rindex+2+cvolume->channels*sizeof(pa_volume_t) > t->length) return -1; - for (i = 0; i < cvolume->channels; i ++) - cvolume->values[i] = (pa_volume_t) ntohl(*((pa_volume_t*) (t->data + t->rindex + 2)+i)); + for (i = 0; i < cvolume->channels; i ++) { + memcpy(&vol, t->data + t->rindex + 2 + i * sizeof(pa_volume_t), sizeof(pa_volume_t)); + cvolume->values[i] = (pa_volume_t) ntohl(vol); + } if (!pa_cvolume_valid(cvolume)) return -1; -- cgit From bbaf1543bd77e5c428e5e4c7d40fde0a42bf3daf Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 13 Feb 2006 13:28:45 +0000 Subject: Split mainloop_iterate() into three, distinct parts. Allows for more flexible use, like having the poll() run in a separate thread. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@478 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/mainloop.c | 157 +++++++++++++++++++++++++++++++++++++++---------------- polyp/mainloop.h | 25 +++++++-- 2 files changed, 133 insertions(+), 49 deletions(-) diff --git a/polyp/mainloop.c b/polyp/mainloop.c index 26ba2425..e131e1a1 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -84,10 +84,20 @@ struct pa_mainloop { unsigned max_pollfds, n_pollfds; int rebuild_pollfds; - int quit, running, retval; + int prepared_timeout; + + int quit, retval; pa_mainloop_api api; int deferred_pending; + + enum { + STATE_PASSIVE, + STATE_PREPARED, + STATE_POLLING, + STATE_POLLED, + STATE_QUIT + } state; }; /* IO events */ @@ -145,11 +155,7 @@ static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags_t events) { assert(e && e->mainloop); e->events = events; - if (e->pollfd) - e->pollfd->events = - (events & PA_IO_EVENT_INPUT ? POLLIN : 0) | - (events & PA_IO_EVENT_OUTPUT ? POLLOUT : 0) | - POLLERR | POLLHUP; + e->mainloop->rebuild_pollfds = 1; } static void mainloop_io_free(pa_io_event *e) { @@ -310,12 +316,14 @@ pa_mainloop *pa_mainloop_new(void) { m->pollfds = NULL; m->max_pollfds = m->n_pollfds = m->rebuild_pollfds = 0; - m->quit = m->running = m->retval = 0; + m->quit = m->retval = 0; m->api = vtable; m->api.userdata = m; m->deferred_pending = 0; + + m->state = STATE_PASSIVE; return m; } @@ -367,7 +375,7 @@ static int defer_foreach(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void*use void pa_mainloop_free(pa_mainloop* m) { int all = 1; - assert(m); + assert(m && (m->state != STATE_POLLING)); pa_idxset_foreach(m->io_events, io_foreach, &all); pa_idxset_foreach(m->time_events, time_foreach, &all); @@ -427,6 +435,8 @@ static void rebuild_pollfds(pa_mainloop *m) { p++; m->n_pollfds++; } + + m->rebuild_pollfds = 0; } static int dispatch_pollfds(pa_mainloop *m) { @@ -548,65 +558,122 @@ static int dispatch_timeout(pa_mainloop *m) { return r; } -int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) { - int r, t, dispatched = 0; - assert(m && !m->running); +int pa_mainloop_prepare(pa_mainloop *m, int timeout) { + int dispatched = 0; + + assert(m && (m->state == STATE_PASSIVE)); - m->running ++; + scan_dead(m); if (m->quit) goto quit; - scan_dead(m); dispatched += dispatch_defer(m); - if(m->quit) + if (m->quit) goto quit; - - if (m->rebuild_pollfds) { + + if (m->rebuild_pollfds) rebuild_pollfds(m); - m->rebuild_pollfds = 0; - } - t = block ? calc_next_timeout(m) : 0; + m->prepared_timeout = calc_next_timeout(m); + if ((timeout >= 0) && (m->prepared_timeout > timeout)) + m->prepared_timeout = timeout; - r = poll(m->pollfds, m->n_pollfds, t); + m->state = STATE_PREPARED; - if (r < 0) { - if (errno == EINTR) - r = 0; - else - pa_log(__FILE__": select(): %s\n", strerror(errno)); - } else { - dispatched += dispatch_timeout(m); + return dispatched; - if(m->quit) - goto quit; - - if (r > 0) { - dispatched += dispatch_pollfds(m); +quit: - if(m->quit) - goto quit; - } - } - - m->running--; + m->state = STATE_QUIT; -/* pa_log("dispatched: %i\n", dispatched); */ + return -2; +} + +int pa_mainloop_poll(pa_mainloop *m) { + int r; + + assert(m && (m->state == STATE_PREPARED)); + + m->state = STATE_POLLING; + + r = poll(m->pollfds, m->n_pollfds, m->prepared_timeout); + + if ((r < 0) && (errno == EINTR)) + r = 0; + + if (r < 0) + m->state = STATE_PASSIVE; + else + m->state = STATE_POLLED; + + return r; +} + +int pa_mainloop_dispatch(pa_mainloop *m) { + int dispatched = 0; + + assert(m && (m->state == STATE_POLLED)); + + dispatched += dispatch_timeout(m); + + if (m->quit) + goto quit; - return r < 0 ? -1 : dispatched; + dispatched += dispatch_pollfds(m); + + if (m->quit) + goto quit; + + m->state = STATE_PASSIVE; + + return dispatched; quit: - - m->running--; - - if (retval) - *retval = m->retval; + + m->state = STATE_QUIT; return -2; } +int pa_mainloop_get_retval(pa_mainloop *m) { + assert(m); + return m->retval; +} + +int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) { + int r, dispatched = 0; + + assert(m); + + r = pa_mainloop_prepare(m, block ? -1 : 0); + if (r < 0) { + if ((r == -2) && retval) + *retval = pa_mainloop_get_retval(m); + return r; + } + + dispatched += r; + + r = pa_mainloop_poll(m); + if (r < 0) { + pa_log(__FILE__": poll(): %s\n", strerror(errno)); + return r; + } + + r = pa_mainloop_dispatch(m); + if (r < 0) { + if ((r == -2) && retval) + *retval = pa_mainloop_get_retval(m); + return r; + } + + dispatched += r; + + return dispatched; +} + int pa_mainloop_run(pa_mainloop *m, int *retval) { int r; while ((r = pa_mainloop_iterate(m, 1, retval)) >= 0); diff --git a/polyp/mainloop.h b/polyp/mainloop.h index 06764907..2be9e6ff 100644 --- a/polyp/mainloop.h +++ b/polyp/mainloop.h @@ -46,10 +46,27 @@ pa_mainloop *pa_mainloop_new(void); /** Free a main loop object */ void pa_mainloop_free(pa_mainloop* m); -/** Run a single iteration of the main loop. Returns a negative value -on error or exit request. If block is nonzero, block for events if -none are queued. Optionally return the return value as specified with -the main loop's quit() routine in the integer variable retval points + +/** Prepare for a single iteration of the main loop. Returns a negative value +on error or exit request. timeout specifies a maximum timeout for the subsequent +poll, or -1 for blocking behaviour. Defer events are also dispatched when this +function is called. On success returns the number of source dispatched in this +iteration.*/ +int pa_mainloop_prepare(pa_mainloop *m, int timeout); +/** Execute the previously prepared poll. Returns a negative value on error.*/ +int pa_mainloop_poll(pa_mainloop *m); +/** Dispatch timeout and io events from the previously executed poll. Returns +a negative value on error. On success returns the number of source dispatched. */ +int pa_mainloop_dispatch(pa_mainloop *m); + +/** Return the return value as specified with the main loop's quit() routine. */ +int pa_mainloop_get_retval(pa_mainloop *m); + +/** Run a single iteration of the main loop. This is a convenience function +for pa_mainloop_prepare(), pa_mainloop_poll() and pa_mainloop_dispatch(). +Returns a negative value on error or exit request. If block is nonzero, +block for events if none are queued. Optionally return the return value as +specified with the main loop's quit() routine in the integer variable retval points to. On success returns the number of source dispatched in this iteration. */ int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval); -- cgit From f77d5e14dc6c18846f228af3f2d6436537077f1d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 13 Feb 2006 13:37:22 +0000 Subject: Add function to "wake up", i.e. interrupt, a running poll(). This is needed when having the poll() in a separate thread. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@479 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/mainloop.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- polyp/mainloop.h | 3 +++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/polyp/mainloop.c b/polyp/mainloop.c index e131e1a1..d25af78a 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -91,6 +91,8 @@ struct pa_mainloop { int deferred_pending; + int wakeup_pipe[2]; + enum { STATE_PASSIVE, STATE_PREPARED, @@ -115,6 +117,8 @@ static pa_io_event* mainloop_io_new( m = a->userdata; assert(a == &m->api); + pa_mainloop_wakeup(m); + e = pa_xmalloc(sizeof(pa_io_event)); e->mainloop = m; e->dead = 0; @@ -154,12 +158,17 @@ static pa_io_event* mainloop_io_new( static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags_t events) { assert(e && e->mainloop); + pa_mainloop_wakeup(e->mainloop); + e->events = events; e->mainloop->rebuild_pollfds = 1; } static void mainloop_io_free(pa_io_event *e) { assert(e && e->mainloop); + + pa_mainloop_wakeup(e->mainloop); + e->dead = e->mainloop->io_events_scan_dead = e->mainloop->rebuild_pollfds = 1; } @@ -229,6 +238,8 @@ static pa_time_event* mainloop_time_new(pa_mainloop_api*a, const struct timeval m = a->userdata; assert(a == &m->api); + pa_mainloop_wakeup(m); + e = pa_xmalloc(sizeof(pa_time_event)); e->mainloop = m; e->dead = 0; @@ -249,6 +260,8 @@ static pa_time_event* mainloop_time_new(pa_mainloop_api*a, const struct timeval static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) { assert(e); + pa_mainloop_wakeup(e->mainloop); + if (tv) { e->enabled = 1; e->timeval = *tv; @@ -259,6 +272,8 @@ static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) { static void mainloop_time_free(pa_time_event *e) { assert(e); + pa_mainloop_wakeup(e->mainloop); + e->dead = e->mainloop->time_events_scan_dead = 1; } @@ -275,6 +290,8 @@ static void mainloop_quit(pa_mainloop_api*a, int retval) { m = a->userdata; assert(a == &m->api); + pa_mainloop_wakeup(m); + m->quit = 1; m->retval = retval; } @@ -305,6 +322,19 @@ pa_mainloop *pa_mainloop_new(void) { m = pa_xmalloc(sizeof(pa_mainloop)); +#ifndef OS_ISWIN32 + if (pipe(m->wakeup_pipe) < 0) { + pa_xfree(m); + return NULL; + } + + pa_make_nonblock_fd(m->wakeup_pipe[0]); + pa_make_nonblock_fd(m->wakeup_pipe[1]); +#else + m->wakeup_pipe[0] = -1; + m->wakeup_pipe[1] = -1; +#endif + m->io_events = pa_idxset_new(NULL, NULL); m->defer_events = pa_idxset_new(NULL, NULL); m->time_events = pa_idxset_new(NULL, NULL); @@ -386,6 +416,12 @@ void pa_mainloop_free(pa_mainloop* m) { pa_idxset_free(m->defer_events, NULL, NULL); pa_xfree(m->pollfds); + + if (m->wakeup_pipe[0] >= 0) + close(m->wakeup_pipe[0]); + if (m->wakeup_pipe[1] >= 0) + close(m->wakeup_pipe[1]); + pa_xfree(m); } @@ -409,7 +445,7 @@ static void rebuild_pollfds(pa_mainloop *m) { uint32_t idx = PA_IDXSET_INVALID; unsigned l; - l = pa_idxset_size(m->io_events); + l = pa_idxset_size(m->io_events) + 1; if (m->max_pollfds < l) { m->pollfds = pa_xrealloc(m->pollfds, sizeof(struct pollfd)*l); m->max_pollfds = l; @@ -417,6 +453,15 @@ static void rebuild_pollfds(pa_mainloop *m) { m->n_pollfds = 0; p = m->pollfds; + + if (m->wakeup_pipe[0] >= 0) { + m->pollfds[0].fd = m->wakeup_pipe[0]; + m->pollfds[0].events = POLLIN; + m->pollfds[0].revents = 0; + p++; + m->n_pollfds++; + } + for (e = pa_idxset_first(m->io_events, &idx); e; e = pa_idxset_next(m->io_events, &idx)) { if (e->dead) { e->pollfd = NULL; @@ -558,11 +603,32 @@ static int dispatch_timeout(pa_mainloop *m) { return r; } +void pa_mainloop_wakeup(pa_mainloop *m) { + char c = 'W'; + assert(m); + + if (m->wakeup_pipe[1] >= 0) + write(m->wakeup_pipe[1], &c, sizeof(c)); +} + +static void clear_wakeup(pa_mainloop *m) { + char c[10]; + + assert(m); + + if (m->wakeup_pipe[0] < 0) + return; + + while (read(m->wakeup_pipe[0], &c, sizeof(c)) == sizeof(c)); +} + int pa_mainloop_prepare(pa_mainloop *m, int timeout) { int dispatched = 0; assert(m && (m->state == STATE_PASSIVE)); + clear_wakeup(m); + scan_dead(m); if (m->quit) @@ -688,6 +754,7 @@ int pa_mainloop_run(pa_mainloop *m, int *retval) { void pa_mainloop_quit(pa_mainloop *m, int r) { assert(m); + pa_mainloop_wakeup(m); m->quit = r; } diff --git a/polyp/mainloop.h b/polyp/mainloop.h index 2be9e6ff..921a0709 100644 --- a/polyp/mainloop.h +++ b/polyp/mainloop.h @@ -82,6 +82,9 @@ int pa_mainloop_deferred_pending(pa_mainloop *m); /** Shutdown the main loop */ void pa_mainloop_quit(pa_mainloop *m, int r); +/** Interrupt a running poll (for threaded systems) */ +void pa_mainloop_wakeup(pa_mainloop *m); + PA_C_DECL_END #endif -- cgit From 0f0fc32a6e93df3fcdac4cfd5e41260ad0c30893 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 14 Feb 2006 13:41:30 +0000 Subject: Fix api. Setting volume is done through a pa_cvolume struct, not a pa_volume_t scalar. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@480 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/polyplib-introspect.c | 12 ++++++------ polyp/polyplib-introspect.h | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index 8c0c4449..49298a96 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -582,7 +582,7 @@ pa_operation* pa_context_get_source_output_info_list(pa_context *c, void (*cb)(p /*** Volume manipulation ***/ -pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, pa_volume_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { +pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; @@ -597,14 +597,14 @@ pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, p pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, idx); pa_tagstruct_puts(t, NULL); - pa_tagstruct_putu32(t, volume); + pa_tagstruct_put_cvolume(t, volume); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); return pa_operation_ref(o); } -pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, pa_volume_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { +pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; @@ -619,14 +619,14 @@ pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, name); - pa_tagstruct_putu32(t, volume); + pa_tagstruct_put_cvolume(t, volume); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); return pa_operation_ref(o); } -pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, pa_volume_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { +pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; @@ -640,7 +640,7 @@ pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, pa_v pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, idx); - pa_tagstruct_putu32(t, volume); + pa_tagstruct_put_cvolume(t, volume); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index 10e6d0e3..d3489908 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -183,13 +183,13 @@ pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, voi pa_operation* pa_context_get_source_output_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata); /** Set the volume of a sink device specified by its index */ -pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, pa_volume_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); /** Set the volume of a sink device specified by its name */ -pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, pa_volume_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); /** Set the volume of a sink input stream */ -pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, pa_volume_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); /** Memory block statistics */ typedef struct pa_stat_info { -- cgit From 22e1f408a2d35f7244086d4532eb5a3ab47d0623 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Feb 2006 23:44:04 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@481 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/doc/todo b/doc/todo index 0da83206..345171a6 100644 --- a/doc/todo +++ b/doc/todo @@ -1,9 +1,6 @@ *** $Id$ *** Architectural changes: -- per-channel volume -- channel mapping ("left", "right", "rear", "subwoofer") -- hardware volume support - add API for synchronizing multiple sinks/sources to a common clock - absolutely indexed write()s from client - remove "polyplib-" prefix @@ -28,6 +25,14 @@ Long term: Backends for: - portaudio (semi-done) -- alsa-lib - sdl - OSS (esddsp style) + +------------------ + +Done: +- per-channel volume +- channel mapping ("left", "right", "rear", "subwoofer") +- hardware volume support +- alsa-lib + -- cgit From cc3fe432afdfe2892ad808d84a90abd1208b5a36 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Feb 2006 01:14:51 +0000 Subject: fix warning text git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@482 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-protocol-stub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index 44d1c022..a0314368 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -173,7 +173,7 @@ static pa_socket_server *create_socket_server(pa_core *c, pa_modargs *ma) { uint32_t port = IPV4_PORT; if (pa_modargs_get_value_boolean(ma, "loopback", &loopback) < 0) { - pa_log(__FILE__": loopback= expects a numerical argument.\n"); + pa_log(__FILE__": loopback= expects a boolean argument.\n"); return NULL; } -- cgit From a9950d4ab28a07dcb96d47b4cd44c57be5c825f7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Feb 2006 01:15:31 +0000 Subject: print ALSA error messages on failure git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@483 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/module-alsa-sink.c | 9 +++++---- polyp/module-alsa-source.c | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index ea6ca424..9aa220be 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -182,6 +182,7 @@ int pa__init(pa_core *c, pa_module*m) { uint32_t periods, fragsize; snd_pcm_uframes_t period_size; size_t frame_size; + int err; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": failed to parse module arguments\n"); @@ -208,13 +209,13 @@ int pa__init(pa_core *c, pa_module*m) { u->module = m; snd_config_update_free_global(); - if (snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) { - pa_log(__FILE__": Error opening PCM device %s\n", dev); + if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { + pa_log(__FILE__": Error opening PCM device %s: %s\n", dev, snd_strerror(err)); goto fail; } - if (pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size) < 0) { - pa_log(__FILE__": Failed to set hardware parameters\n"); + if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) { + pa_log(__FILE__": Failed to set hardware parameters: %s\n", snd_strerror(err)); goto fail; } diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index 2aa47aad..efc84efe 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -173,6 +173,7 @@ int pa__init(pa_core *c, pa_module*m) { unsigned periods, fragsize; snd_pcm_uframes_t period_size; size_t frame_size; + int err; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": failed to parse module arguments\n"); @@ -199,13 +200,13 @@ int pa__init(pa_core *c, pa_module*m) { u->module = m; snd_config_update_free_global(); - if (snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK) < 0) { - pa_log(__FILE__": Error opening PCM device %s\n", dev); + if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { + pa_log(__FILE__": Error opening PCM device %s: %s\n", dev, snd_strerror(err)); goto fail; } - if (pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size) < 0) { - pa_log(__FILE__": Failed to set hardware parameters\n"); + if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) { + pa_log(__FILE__": Failed to set hardware parameters: %s\n", snd_strerror(err)); goto fail; } -- cgit From 61fbafcb9495744d7ef82fe7dcb56610c8063888 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Feb 2006 01:16:02 +0000 Subject: allow polypaudio to startup without any enabled module git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@484 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/polyp/main.c b/polyp/main.c index c984e28e..b5aac851 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -428,7 +428,8 @@ int main(int argc, char *argv[]) { c->scache_idle_time = conf->scache_idle_time; c->resample_method = conf->resample_method; - if (pa_namereg_get(c, c->default_sink_name, PA_NAMEREG_SINK, 1) == NULL) { + if (c->default_sink_name && + pa_namereg_get(c, c->default_sink_name, PA_NAMEREG_SINK, 1) == NULL) { pa_log_error("%s : Fatal error. Default sink name (%s) does not exist in name register.\n", __FILE__, c->default_sink_name); retval = 1; } else { -- cgit From 6ad876efa803de188eaa8e9ffdedb68fd8c9423f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Feb 2006 01:16:39 +0000 Subject: Add HAVE_ALSA and HAVE_OSS defines git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@485 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 710f205b..03663590 100644 --- a/configure.ac +++ b/configure.ac @@ -288,13 +288,20 @@ AC_SUBST(LIBSNDFILE_LIBS) #### OSS support (optional) #### -AC_CHECK_HEADERS([sys/soundcard.h], [HAVE_OSS=1], [HAVE_OSS=0]) +AC_CHECK_HEADERS([sys/soundcard.h], [ +HAVE_OSS=1 +AC_DEFINE([HAVE_OSS], 1, [Have OSS?]) +], [HAVE_OSS=0]) AC_SUBST(HAVE_OSS) AM_CONDITIONAL([HAVE_OSS], [test "x$HAVE_OSS" = x1]) + #### ALSA support (optional) #### -PKG_CHECK_MODULES(ASOUNDLIB, [ alsa >= 1.0.0 ], [HAVE_ALSA=1], [HAVE_ALSA=0]) +PKG_CHECK_MODULES(ASOUNDLIB, [ alsa >= 1.0.0 ], [ +HAVE_ALSA=1 +AC_DEFINE([HAVE_ALSA], 1, [Have ALSA?]) +], [HAVE_ALSA=0]) AC_SUBST(ASOUNDLIB_CFLAGS) AC_SUBST(ASOUNDLIB_LIBS) AC_SUBST(HAVE_ALSA) -- cgit From 5b881e62282f26b353635120935d114e0c7c3f3c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Feb 2006 01:17:30 +0000 Subject: add simple hardware auto detection module git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@486 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 13 ++- polyp/module-detect.c | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 237 insertions(+), 2 deletions(-) create mode 100644 polyp/module-detect.c diff --git a/polyp/Makefile.am b/polyp/Makefile.am index e2154b32..061b82b4 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -47,6 +47,7 @@ AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS AM_CFLAGS += $(LTDLINCL) AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" +#AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\" AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\" AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(POLYPAUDIO_BINARY)\" @@ -676,7 +677,8 @@ modlib_LTLIBRARIES += \ module-null-sink.la \ module-esound-sink.la \ module-http-protocol-tcp.la \ - module-http-protocol-tcp6.la + module-http-protocol-tcp6.la \ + module-detect.la if HAVE_AF_UNIX modlib_LTLIBRARIES += \ @@ -788,7 +790,8 @@ SYMDEF_FILES = \ module-alsa-sink-symdef.h \ module-alsa-source-symdef.h \ module-solaris-symdef.h \ - module-waveout-symdef.h + module-waveout-symdef.h \ + module-detect-symdef.h EXTRA_DIST += $(SYMDEF_FILES) BUILT_SOURCES += $(SYMDEF_FILES) @@ -1009,6 +1012,12 @@ module_waveout_la_LDFLAGS = -module -avoid-version module_waveout_la_LIBADD = $(AM_LIBADD) libpolypcore.la -lwinmm module_waveout_la_CFLAGS = $(AM_CFLAGS) +# Hardware autodetection module +module_detect_la_SOURCES = module-detect.c +module_detect_la_LDFLAGS = -module -avoid-version +module_detect_la_LIBADD = $(AM_LIBADD) +module_detect_la_CFLAGS = $(AM_CFLAGS) + ################################### # Some minor stuff # ################################### diff --git a/polyp/module-detect.c b/polyp/module-detect.c new file mode 100644 index 00000000..ee75da36 --- /dev/null +++ b/polyp/module-detect.c @@ -0,0 +1,226 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "module.h" +#include "log.h" +#include "module-detect-symdef.h" +#include "xmalloc.h" +#include "modargs.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("just-one=") + +static const char *endswith(const char *haystack, const char *needle) { + size_t l, m; + const char *p; + + if ((l = strlen(haystack)) < (m = strlen(needle))) + return NULL; + + if (strcmp(p = haystack + l - m, needle)) + return NULL; + + return p; +} + +#ifdef HAVE_ALSA +static int detect_alsa(pa_core *c, int just_one) { + FILE *f; + int n = 0, n_sink = 0, n_source = 0; + + if (!(f = fopen("/proc/asound/devices", "r"))) { + + if (errno != ENOENT) + pa_log_error(__FILE__": open(\"/proc/asound/devices\") failed: %s\n", strerror(errno)); + + return -1; + } + + while (!feof(f)) { + char line[64], args[64]; + unsigned device, subdevice; + int is_sink; + + if (!fgets(line, sizeof(line), f)) + break; + + line[strcspn(line, "\r\n")] = 0; + + if (endswith(line, "digital audio playback")) + is_sink = 1; + else if (endswith(line, "digital audio capture")) + is_sink = 0; + else + continue; + + if (just_one && is_sink && n_sink >= 1) + continue; + + if (just_one && !is_sink && n_source >= 1) + continue; + + if (sscanf(line, " %*i: [%u- %u]: ", &device, &subdevice) != 2) + continue; + + /* Only one sink per device */ + if (subdevice != 0) + continue; + + snprintf(args, sizeof(args), "device=hw:%u,0", device); + if (!pa_module_load(c, is_sink ? "module-alsa-sink" : "module-alsa-source", args)) + continue; + + n++; + + if (is_sink) + n_sink++; + else + n_source++; + } + + fclose(f); + + return n; +} +#endif + +#ifdef HAVE_OSS +static int detect_oss(pa_core *c, int just_one) { + FILE *f; + int n = 0, b = 0; + + if (!(f = fopen("/dev/sndstat", "r")) && + !(f = fopen("/proc/sndstat", "r")) && + !(f = fopen("/proc/asound/oss/sndstat", "r"))) { + + if (errno != ENOENT) + pa_log_error(__FILE__": failed to open OSS sndstat device: %s\n", strerror(errno)); + + return -1; + } + + while (!feof(f)) { + char line[64], args[64]; + unsigned device; + + if (!fgets(line, sizeof(line), f)) + break; + + line[strcspn(line, "\r\n")] = 0; + + if (!b) { + b = strcmp(line, "Audio devices:") == 0; + continue; + } + + if (line[0] == 0) + break; + + if (sscanf(line, "%u: ", &device) != 1) + continue; + + if (device == 0) + snprintf(args, sizeof(args), "device=/dev/dsp"); + else + snprintf(args, sizeof(args), "device=/dev/dsp%u", device); + + if (!pa_module_load(c, "module-oss", args)) + continue; + + n++; + + if (just_one) + break; + } + + fclose(f); + return n; +} +#endif + +int pa__init(pa_core *c, pa_module*m) { + int just_one = 0, n = 0; + pa_modargs *ma; + + static const char* const valid_modargs[] = { + "just-one", + NULL + }; + + assert(c); + assert(m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": Failed to parse module arguments\n"); + goto fail; + } + + if (pa_modargs_get_value_boolean(ma, "just-one", &just_one) < 0) { + pa_log(__FILE__": just_one= expects a boolean argument.\n"); + goto fail; + } + +#if HAVE_ALSA + if ((n = detect_alsa(c, just_one)) <= 0) +#endif +#if HAVE_OSS + if ((n = detect_oss(c, just_one)) <= 0) +#endif + { + pa_log_warn(__FILE__": failed to detect any sound hardware.\n"); + goto fail; + } + + pa_log_info(__FILE__": loaded %i modules.\n", n); + + /* We were successful and can unload ourselves now. */ + pa_module_unload_request(m); + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + return -1; +} + + +void pa__done(pa_core *c, pa_module*m) { + /* NOP */ +} + -- cgit From e205b25d65ccb380fa158711e24d55b6de5d9bc1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 16 Feb 2006 19:19:58 +0000 Subject: Reorganised the source tree. We now have src/ with a couple of subdirs: * daemon/ - Contains the files specific to the polypaudio daemon. * modules/ - All loadable modules. * polyp/ - Files that are part of the public, application interface or are only used in libpolyp. * polypcore/ - All other shared files. * tests/ - Test programs. * utils/ - Utility programs. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@487 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- configure.ac | 6 +- polyp/Makefile.am | 1052 ----------- polyp/alsa-util.c | 124 -- polyp/alsa-util.h | 35 - polyp/authkey-prop.c | 87 - polyp/authkey-prop.h | 43 - polyp/authkey.c | 201 --- polyp/authkey.h | 32 - polyp/autoload.c | 180 -- polyp/autoload.h | 58 - polyp/caps.c | 131 -- polyp/caps.h | 29 - polyp/cdecl.h | 42 - polyp/channelmap.c | 202 --- polyp/channelmap.h | 98 -- polyp/cli-command.c | 834 --------- polyp/cli-command.h | 40 - polyp/cli-text.c | 385 ---- polyp/cli-text.h | 42 - polyp/cli.c | 147 -- polyp/cli.h | 38 - polyp/client-conf-x11.c | 91 - polyp/client-conf-x11.h | 31 - polyp/client-conf.c | 190 -- polyp/client-conf.h | 52 - polyp/client.c | 91 - polyp/client.conf.in | 39 - polyp/client.h | 57 - polyp/cmdline.c | 300 ---- polyp/cmdline.h | 35 - polyp/conf-parser.c | 176 -- polyp/conf-parser.h | 47 - polyp/core.c | 157 -- polyp/core.h | 82 - polyp/cpulimit-test.c | 92 - polyp/cpulimit.c | 236 --- polyp/cpulimit.h | 34 - polyp/daemon-conf.c | 297 ---- polyp/daemon-conf.h | 80 - polyp/daemon.conf.in | 77 - polyp/default.pa.in | 66 - polyp/default.pa.win32 | 43 - polyp/depmod.py | 73 - polyp/dllmain.c | 46 - polyp/dumpmodules.c | 99 -- polyp/dumpmodules.h | 31 - polyp/dynarray.c | 102 -- polyp/dynarray.h | 49 - polyp/endianmacros.h | 77 - polyp/esdcompat.sh.in | 98 -- polyp/esound.h | 209 --- polyp/g711.c | 2531 --------------------------- polyp/g711.h | 40 - polyp/gccmacro.h | 53 - polyp/glib-mainloop.c | 538 ------ polyp/glib-mainloop.h | 55 - polyp/glib12-mainloop.c | 500 ------ polyp/hashmap.c | 194 -- polyp/hashmap.h | 53 - polyp/howl-wrap.c | 116 -- polyp/howl-wrap.h | 37 - polyp/idxset.c | 390 ----- polyp/idxset.h | 94 - polyp/inet_ntop.c | 80 - polyp/inet_ntop.h | 12 - polyp/iochannel.c | 292 --- polyp/iochannel.h | 72 - polyp/ioline.c | 368 ---- polyp/ioline.h | 51 - polyp/llist.h | 69 - polyp/log.c | 150 -- polyp/log.h | 69 - polyp/main.c | 472 ----- polyp/mainloop-api.c | 68 - polyp/mainloop-api.h | 120 -- polyp/mainloop-signal.c | 267 --- polyp/mainloop-signal.h | 60 - polyp/mainloop-test.c | 146 -- polyp/mainloop.c | 812 --------- polyp/mainloop.h | 90 - polyp/mcalign-test.c | 96 - polyp/mcalign.c | 188 -- polyp/mcalign.h | 77 - polyp/memblock.c | 169 -- polyp/memblock.h | 87 - polyp/memblockq.c | 343 ---- polyp/memblockq.h | 104 -- polyp/memchunk.c | 58 - polyp/memchunk.h | 45 - polyp/modargs.c | 260 --- polyp/modargs.h | 49 - polyp/modinfo.c | 84 - polyp/modinfo.h | 43 - polyp/module-alsa-sink.c | 291 --- polyp/module-alsa-source.c | 277 --- polyp/module-cli.c | 87 - polyp/module-combine.c | 393 ----- polyp/module-defs.h.m4 | 29 - polyp/module-detect.c | 226 --- polyp/module-esound-compat-spawnfd.c | 80 - polyp/module-esound-compat-spawnpid.c | 78 - polyp/module-esound-sink.c | 426 ----- polyp/module-lirc.c | 240 --- polyp/module-match.c | 234 --- polyp/module-mmkbd-evdev.c | 249 --- polyp/module-native-protocol-fd.c | 84 - polyp/module-null-sink.c | 149 -- polyp/module-oss-mmap.c | 425 ----- polyp/module-oss.c | 467 ----- polyp/module-pipe-sink.c | 236 --- polyp/module-pipe-source.c | 209 --- polyp/module-protocol-stub.c | 262 --- polyp/module-sine.c | 181 -- polyp/module-solaris.c | 486 ----- polyp/module-tunnel.c | 688 -------- polyp/module-waveout.c | 581 ------ polyp/module-x11-bell.c | 172 -- polyp/module-x11-publish.c | 191 -- polyp/module-zeroconf-publish.c | 507 ------ polyp/module.c | 275 --- polyp/module.h | 70 - polyp/namereg.c | 212 --- polyp/namereg.h | 43 - polyp/native-common.h | 114 -- polyp/oss-util.c | 167 -- polyp/oss-util.h | 32 - polyp/pabrowse.c | 139 -- polyp/pacat-simple.c | 101 -- polyp/pacat.c | 541 ------ polyp/packet.c | 69 - polyp/packet.h | 41 - polyp/pacmd.c | 183 -- polyp/pactl.c | 784 --------- polyp/paplay.c | 386 ---- polyp/parec-simple.c | 100 -- polyp/parseaddr.c | 112 -- polyp/parseaddr.h | 42 - polyp/pax11publish.c | 217 --- polyp/pdispatch.c | 295 ---- polyp/pdispatch.h | 50 - polyp/pid.c | 286 --- polyp/pid.h | 30 - polyp/play-memchunk.c | 118 -- polyp/play-memchunk.h | 36 - polyp/poll.c | 190 -- polyp/poll.h | 57 - polyp/polyplib-browser.c | 312 ---- polyp/polyplib-browser.h | 65 - polyp/polyplib-context.c | 871 --------- polyp/polyplib-context.h | 117 -- polyp/polyplib-def.h | 213 --- polyp/polyplib-error.c | 54 - polyp/polyplib-error.h | 38 - polyp/polyplib-internal.h | 154 -- polyp/polyplib-introspect.c | 1003 ----------- polyp/polyplib-introspect.h | 279 --- polyp/polyplib-operation.c | 103 -- polyp/polyplib-operation.h | 51 - polyp/polyplib-scache.c | 127 -- polyp/polyplib-scache.h | 50 - polyp/polyplib-simple.c | 393 ----- polyp/polyplib-simple.h | 80 - polyp/polyplib-stream.c | 807 --------- polyp/polyplib-stream.h | 181 -- polyp/polyplib-subscribe.c | 81 - polyp/polyplib-subscribe.h | 47 - polyp/polyplib-version.h.in | 47 - polyp/polyplib.h | 86 - polyp/props.c | 119 -- polyp/props.h | 58 - polyp/protocol-cli.c | 95 - polyp/protocol-cli.h | 35 - polyp/protocol-esound.c | 1166 ------------ polyp/protocol-esound.h | 35 - polyp/protocol-http.c | 265 --- polyp/protocol-http.h | 35 - polyp/protocol-native.c | 2216 ----------------------- polyp/protocol-native.h | 37 - polyp/protocol-simple.c | 453 ----- polyp/protocol-simple.h | 35 - polyp/pstream-util.c | 61 - polyp/pstream-util.h | 35 - polyp/pstream.c | 492 ------ polyp/pstream.h | 52 - polyp/queue.c | 108 -- polyp/queue.h | 40 - polyp/random.c | 71 - polyp/random.h | 27 - polyp/resampler.c | 614 ------- polyp/resampler.h | 73 - polyp/sample-util.c | 328 ---- polyp/sample-util.h | 53 - polyp/sample.c | 149 -- polyp/sample.h | 120 -- polyp/scache.c | 392 ----- polyp/scache.h | 62 - polyp/sconv-s16be.c | 41 - polyp/sconv-s16be.h | 28 - polyp/sconv-s16le.c | 101 -- polyp/sconv-s16le.h | 28 - polyp/sconv.c | 168 -- polyp/sconv.h | 33 - polyp/sink-input.c | 368 ---- polyp/sink-input.h | 106 -- polyp/sink.c | 445 ----- polyp/sink.h | 100 -- polyp/sioman.c | 42 - polyp/sioman.h | 28 - polyp/socket-client.c | 513 ------ polyp/socket-client.h | 47 - polyp/socket-server.c | 432 ----- polyp/socket-server.h | 45 - polyp/socket-util.c | 246 --- polyp/socket-util.h | 38 - polyp/sound-file-stream.c | 179 -- polyp/sound-file-stream.h | 29 - polyp/sound-file.c | 139 -- polyp/sound-file.h | 32 - polyp/source-output.c | 228 --- polyp/source-output.h | 92 - polyp/source.c | 195 --- polyp/source.h | 86 - polyp/strbuf.c | 166 -- polyp/strbuf.h | 38 - polyp/strlist-test.c | 42 - polyp/strlist.c | 137 -- polyp/strlist.h | 47 - polyp/subscribe.c | 230 --- polyp/subscribe.h | 37 - polyp/tagstruct.c | 609 ------- polyp/tagstruct.h | 92 - polyp/tokenizer.c | 88 - polyp/tokenizer.h | 32 - polyp/util.c | 1176 ------------- polyp/util.h | 99 -- polyp/voltest.c | 20 - polyp/volume.c | 176 -- polyp/volume.h | 107 -- polyp/winsock.h | 23 - polyp/x11prop.c | 70 - polyp/x11prop.h | 33 - polyp/x11wrap.c | 235 --- polyp/x11wrap.h | 52 - polyp/xmalloc.c | 122 -- polyp/xmalloc.h | 58 - src/Makefile.am | 1061 +++++++++++ src/client.conf.in | 39 + src/daemon.conf.in | 77 + src/daemon/caps.c | 131 ++ src/daemon/caps.h | 29 + src/daemon/cmdline.c | 300 ++++ src/daemon/cmdline.h | 35 + src/daemon/cpulimit.c | 236 +++ src/daemon/cpulimit.h | 34 + src/daemon/daemon-conf.c | 297 ++++ src/daemon/daemon-conf.h | 80 + src/daemon/dumpmodules.c | 99 ++ src/daemon/dumpmodules.h | 31 + src/daemon/main.c | 472 +++++ src/default.pa.in | 66 + src/default.pa.win32 | 43 + src/depmod.py | 73 + src/modules/module-alsa-sink.c | 292 +++ src/modules/module-alsa-source.c | 278 +++ src/modules/module-cli.c | 88 + src/modules/module-combine.c | 394 +++++ src/modules/module-defs.h.m4 | 29 + src/modules/module-detect.c | 227 +++ src/modules/module-esound-compat-spawnfd.c | 81 + src/modules/module-esound-compat-spawnpid.c | 79 + src/modules/module-esound-sink.c | 427 +++++ src/modules/module-lirc.c | 241 +++ src/modules/module-match.c | 235 +++ src/modules/module-mmkbd-evdev.c | 250 +++ src/modules/module-native-protocol-fd.c | 85 + src/modules/module-null-sink.c | 150 ++ src/modules/module-oss-mmap.c | 426 +++++ src/modules/module-oss.c | 468 +++++ src/modules/module-pipe-sink.c | 237 +++ src/modules/module-pipe-source.c | 210 +++ src/modules/module-protocol-stub.c | 261 +++ src/modules/module-sine.c | 182 ++ src/modules/module-solaris.c | 488 ++++++ src/modules/module-tunnel.c | 688 ++++++++ src/modules/module-waveout.c | 583 ++++++ src/modules/module-x11-bell.c | 173 ++ src/modules/module-x11-publish.c | 192 ++ src/modules/module-zeroconf-publish.c | 508 ++++++ src/polyp/cdecl.h | 42 + src/polyp/channelmap.c | 202 +++ src/polyp/channelmap.h | 98 ++ src/polyp/client-conf-x11.c | 91 + src/polyp/client-conf-x11.h | 31 + src/polyp/client-conf.c | 191 ++ src/polyp/client-conf.h | 52 + src/polyp/glib-mainloop.c | 538 ++++++ src/polyp/glib-mainloop.h | 55 + src/polyp/glib12-mainloop.c | 500 ++++++ src/polyp/mainloop-api.c | 68 + src/polyp/mainloop-api.h | 120 ++ src/polyp/mainloop-signal.c | 267 +++ src/polyp/mainloop-signal.h | 60 + src/polyp/mainloop.c | 812 +++++++++ src/polyp/mainloop.h | 90 + src/polyp/polyplib-browser.c | 312 ++++ src/polyp/polyplib-browser.h | 65 + src/polyp/polyplib-context.c | 871 +++++++++ src/polyp/polyplib-context.h | 117 ++ src/polyp/polyplib-def.h | 213 +++ src/polyp/polyplib-error.c | 54 + src/polyp/polyplib-error.h | 38 + src/polyp/polyplib-internal.h | 154 ++ src/polyp/polyplib-introspect.c | 1003 +++++++++++ src/polyp/polyplib-introspect.h | 279 +++ src/polyp/polyplib-operation.c | 103 ++ src/polyp/polyplib-operation.h | 51 + src/polyp/polyplib-scache.c | 127 ++ src/polyp/polyplib-scache.h | 50 + src/polyp/polyplib-simple.c | 393 +++++ src/polyp/polyplib-simple.h | 80 + src/polyp/polyplib-stream.c | 807 +++++++++ src/polyp/polyplib-stream.h | 181 ++ src/polyp/polyplib-subscribe.c | 81 + src/polyp/polyplib-subscribe.h | 47 + src/polyp/polyplib-version.h.in | 47 + src/polyp/polyplib.h | 86 + src/polyp/sample.c | 149 ++ src/polyp/sample.h | 120 ++ src/polyp/volume.c | 176 ++ src/polyp/volume.h | 107 ++ src/polypcore/alsa-util.c | 124 ++ src/polypcore/alsa-util.h | 35 + src/polypcore/authkey-prop.c | 87 + src/polypcore/authkey-prop.h | 43 + src/polypcore/authkey.c | 201 +++ src/polypcore/authkey.h | 32 + src/polypcore/autoload.c | 180 ++ src/polypcore/autoload.h | 58 + src/polypcore/cli-command.c | 834 +++++++++ src/polypcore/cli-command.h | 40 + src/polypcore/cli-text.c | 385 ++++ src/polypcore/cli-text.h | 42 + src/polypcore/cli.c | 147 ++ src/polypcore/cli.h | 38 + src/polypcore/client.c | 91 + src/polypcore/client.h | 57 + src/polypcore/conf-parser.c | 176 ++ src/polypcore/conf-parser.h | 47 + src/polypcore/core.c | 157 ++ src/polypcore/core.h | 82 + src/polypcore/dllmain.c | 46 + src/polypcore/dynarray.c | 102 ++ src/polypcore/dynarray.h | 49 + src/polypcore/endianmacros.h | 77 + src/polypcore/esound.h | 209 +++ src/polypcore/g711.c | 2531 +++++++++++++++++++++++++++ src/polypcore/g711.h | 40 + src/polypcore/gccmacro.h | 53 + src/polypcore/hashmap.c | 194 ++ src/polypcore/hashmap.h | 53 + src/polypcore/howl-wrap.c | 116 ++ src/polypcore/howl-wrap.h | 37 + src/polypcore/idxset.c | 390 +++++ src/polypcore/idxset.h | 94 + src/polypcore/inet_ntop.c | 80 + src/polypcore/inet_ntop.h | 12 + src/polypcore/iochannel.c | 292 +++ src/polypcore/iochannel.h | 72 + src/polypcore/ioline.c | 368 ++++ src/polypcore/ioline.h | 51 + src/polypcore/llist.h | 69 + src/polypcore/log.c | 150 ++ src/polypcore/log.h | 69 + src/polypcore/mcalign.c | 188 ++ src/polypcore/mcalign.h | 77 + src/polypcore/memblock.c | 169 ++ src/polypcore/memblock.h | 87 + src/polypcore/memblockq.c | 343 ++++ src/polypcore/memblockq.h | 104 ++ src/polypcore/memchunk.c | 58 + src/polypcore/memchunk.h | 45 + src/polypcore/modargs.c | 260 +++ src/polypcore/modargs.h | 49 + src/polypcore/modinfo.c | 84 + src/polypcore/modinfo.h | 43 + src/polypcore/module.c | 275 +++ src/polypcore/module.h | 70 + src/polypcore/namereg.c | 212 +++ src/polypcore/namereg.h | 43 + src/polypcore/native-common.h | 114 ++ src/polypcore/oss-util.c | 167 ++ src/polypcore/oss-util.h | 32 + src/polypcore/packet.c | 69 + src/polypcore/packet.h | 41 + src/polypcore/parseaddr.c | 112 ++ src/polypcore/parseaddr.h | 42 + src/polypcore/pdispatch.c | 295 ++++ src/polypcore/pdispatch.h | 50 + src/polypcore/pid.c | 286 +++ src/polypcore/pid.h | 30 + src/polypcore/play-memchunk.c | 118 ++ src/polypcore/play-memchunk.h | 36 + src/polypcore/poll.c | 190 ++ src/polypcore/poll.h | 57 + src/polypcore/props.c | 119 ++ src/polypcore/props.h | 58 + src/polypcore/protocol-cli.c | 95 + src/polypcore/protocol-cli.h | 35 + src/polypcore/protocol-esound.c | 1166 ++++++++++++ src/polypcore/protocol-esound.h | 35 + src/polypcore/protocol-http.c | 265 +++ src/polypcore/protocol-http.h | 35 + src/polypcore/protocol-native.c | 2216 +++++++++++++++++++++++ src/polypcore/protocol-native.h | 37 + src/polypcore/protocol-simple.c | 453 +++++ src/polypcore/protocol-simple.h | 35 + src/polypcore/pstream-util.c | 61 + src/polypcore/pstream-util.h | 35 + src/polypcore/pstream.c | 492 ++++++ src/polypcore/pstream.h | 52 + src/polypcore/queue.c | 108 ++ src/polypcore/queue.h | 40 + src/polypcore/random.c | 71 + src/polypcore/random.h | 27 + src/polypcore/resampler.c | 614 +++++++ src/polypcore/resampler.h | 73 + src/polypcore/sample-util.c | 328 ++++ src/polypcore/sample-util.h | 53 + src/polypcore/scache.c | 392 +++++ src/polypcore/scache.h | 62 + src/polypcore/sconv-s16be.c | 41 + src/polypcore/sconv-s16be.h | 28 + src/polypcore/sconv-s16le.c | 101 ++ src/polypcore/sconv-s16le.h | 28 + src/polypcore/sconv.c | 168 ++ src/polypcore/sconv.h | 33 + src/polypcore/sink-input.c | 368 ++++ src/polypcore/sink-input.h | 106 ++ src/polypcore/sink.c | 445 +++++ src/polypcore/sink.h | 100 ++ src/polypcore/sioman.c | 42 + src/polypcore/sioman.h | 28 + src/polypcore/socket-client.c | 513 ++++++ src/polypcore/socket-client.h | 47 + src/polypcore/socket-server.c | 432 +++++ src/polypcore/socket-server.h | 45 + src/polypcore/socket-util.c | 246 +++ src/polypcore/socket-util.h | 38 + src/polypcore/sound-file-stream.c | 179 ++ src/polypcore/sound-file-stream.h | 29 + src/polypcore/sound-file.c | 139 ++ src/polypcore/sound-file.h | 32 + src/polypcore/source-output.c | 228 +++ src/polypcore/source-output.h | 92 + src/polypcore/source.c | 195 +++ src/polypcore/source.h | 86 + src/polypcore/strbuf.c | 167 ++ src/polypcore/strbuf.h | 38 + src/polypcore/strlist.c | 137 ++ src/polypcore/strlist.h | 47 + src/polypcore/subscribe.c | 230 +++ src/polypcore/subscribe.h | 37 + src/polypcore/tagstruct.c | 609 +++++++ src/polypcore/tagstruct.h | 92 + src/polypcore/tokenizer.c | 88 + src/polypcore/tokenizer.h | 32 + src/polypcore/util.c | 1176 +++++++++++++ src/polypcore/util.h | 99 ++ src/polypcore/winsock.h | 23 + src/polypcore/x11prop.c | 70 + src/polypcore/x11prop.h | 33 + src/polypcore/x11wrap.c | 235 +++ src/polypcore/x11wrap.h | 52 + src/polypcore/xmalloc.c | 122 ++ src/polypcore/xmalloc.h | 58 + src/tests/cpulimit-test.c | 92 + src/tests/mainloop-test.c | 146 ++ src/tests/mcalign-test.c | 96 + src/tests/pacat-simple.c | 101 ++ src/tests/parec-simple.c | 100 ++ src/tests/strlist-test.c | 42 + src/tests/voltest.c | 20 + src/utils/esdcompat.sh.in | 98 ++ src/utils/pabrowse.c | 139 ++ src/utils/pacat.c | 541 ++++++ src/utils/pacmd.c | 183 ++ src/utils/pactl.c | 784 +++++++++ src/utils/paplay.c | 386 ++++ src/utils/pax11publish.c | 217 +++ 490 files changed, 48099 insertions(+), 48064 deletions(-) delete mode 100644 polyp/Makefile.am delete mode 100644 polyp/alsa-util.c delete mode 100644 polyp/alsa-util.h delete mode 100644 polyp/authkey-prop.c delete mode 100644 polyp/authkey-prop.h delete mode 100644 polyp/authkey.c delete mode 100644 polyp/authkey.h delete mode 100644 polyp/autoload.c delete mode 100644 polyp/autoload.h delete mode 100644 polyp/caps.c delete mode 100644 polyp/caps.h delete mode 100644 polyp/cdecl.h delete mode 100644 polyp/channelmap.c delete mode 100644 polyp/channelmap.h delete mode 100644 polyp/cli-command.c delete mode 100644 polyp/cli-command.h delete mode 100644 polyp/cli-text.c delete mode 100644 polyp/cli-text.h delete mode 100644 polyp/cli.c delete mode 100644 polyp/cli.h delete mode 100644 polyp/client-conf-x11.c delete mode 100644 polyp/client-conf-x11.h delete mode 100644 polyp/client-conf.c delete mode 100644 polyp/client-conf.h delete mode 100644 polyp/client.c delete mode 100644 polyp/client.conf.in delete mode 100644 polyp/client.h delete mode 100644 polyp/cmdline.c delete mode 100644 polyp/cmdline.h delete mode 100644 polyp/conf-parser.c delete mode 100644 polyp/conf-parser.h delete mode 100644 polyp/core.c delete mode 100644 polyp/core.h delete mode 100644 polyp/cpulimit-test.c delete mode 100644 polyp/cpulimit.c delete mode 100644 polyp/cpulimit.h delete mode 100644 polyp/daemon-conf.c delete mode 100644 polyp/daemon-conf.h delete mode 100644 polyp/daemon.conf.in delete mode 100755 polyp/default.pa.in delete mode 100644 polyp/default.pa.win32 delete mode 100755 polyp/depmod.py delete mode 100644 polyp/dllmain.c delete mode 100644 polyp/dumpmodules.c delete mode 100644 polyp/dumpmodules.h delete mode 100644 polyp/dynarray.c delete mode 100644 polyp/dynarray.h delete mode 100644 polyp/endianmacros.h delete mode 100755 polyp/esdcompat.sh.in delete mode 100644 polyp/esound.h delete mode 100644 polyp/g711.c delete mode 100644 polyp/g711.h delete mode 100644 polyp/gccmacro.h delete mode 100644 polyp/glib-mainloop.c delete mode 100644 polyp/glib-mainloop.h delete mode 100644 polyp/glib12-mainloop.c delete mode 100644 polyp/hashmap.c delete mode 100644 polyp/hashmap.h delete mode 100644 polyp/howl-wrap.c delete mode 100644 polyp/howl-wrap.h delete mode 100644 polyp/idxset.c delete mode 100644 polyp/idxset.h delete mode 100644 polyp/inet_ntop.c delete mode 100644 polyp/inet_ntop.h delete mode 100644 polyp/iochannel.c delete mode 100644 polyp/iochannel.h delete mode 100644 polyp/ioline.c delete mode 100644 polyp/ioline.h delete mode 100644 polyp/llist.h delete mode 100644 polyp/log.c delete mode 100644 polyp/log.h delete mode 100644 polyp/main.c delete mode 100644 polyp/mainloop-api.c delete mode 100644 polyp/mainloop-api.h delete mode 100644 polyp/mainloop-signal.c delete mode 100644 polyp/mainloop-signal.h delete mode 100644 polyp/mainloop-test.c delete mode 100644 polyp/mainloop.c delete mode 100644 polyp/mainloop.h delete mode 100644 polyp/mcalign-test.c delete mode 100644 polyp/mcalign.c delete mode 100644 polyp/mcalign.h delete mode 100644 polyp/memblock.c delete mode 100644 polyp/memblock.h delete mode 100644 polyp/memblockq.c delete mode 100644 polyp/memblockq.h delete mode 100644 polyp/memchunk.c delete mode 100644 polyp/memchunk.h delete mode 100644 polyp/modargs.c delete mode 100644 polyp/modargs.h delete mode 100644 polyp/modinfo.c delete mode 100644 polyp/modinfo.h delete mode 100644 polyp/module-alsa-sink.c delete mode 100644 polyp/module-alsa-source.c delete mode 100644 polyp/module-cli.c delete mode 100644 polyp/module-combine.c delete mode 100644 polyp/module-defs.h.m4 delete mode 100644 polyp/module-detect.c delete mode 100644 polyp/module-esound-compat-spawnfd.c delete mode 100644 polyp/module-esound-compat-spawnpid.c delete mode 100644 polyp/module-esound-sink.c delete mode 100644 polyp/module-lirc.c delete mode 100644 polyp/module-match.c delete mode 100644 polyp/module-mmkbd-evdev.c delete mode 100644 polyp/module-native-protocol-fd.c delete mode 100644 polyp/module-null-sink.c delete mode 100644 polyp/module-oss-mmap.c delete mode 100644 polyp/module-oss.c delete mode 100644 polyp/module-pipe-sink.c delete mode 100644 polyp/module-pipe-source.c delete mode 100644 polyp/module-protocol-stub.c delete mode 100644 polyp/module-sine.c delete mode 100644 polyp/module-solaris.c delete mode 100644 polyp/module-tunnel.c delete mode 100644 polyp/module-waveout.c delete mode 100644 polyp/module-x11-bell.c delete mode 100644 polyp/module-x11-publish.c delete mode 100644 polyp/module-zeroconf-publish.c delete mode 100644 polyp/module.c delete mode 100644 polyp/module.h delete mode 100644 polyp/namereg.c delete mode 100644 polyp/namereg.h delete mode 100644 polyp/native-common.h delete mode 100644 polyp/oss-util.c delete mode 100644 polyp/oss-util.h delete mode 100644 polyp/pabrowse.c delete mode 100644 polyp/pacat-simple.c delete mode 100644 polyp/pacat.c delete mode 100644 polyp/packet.c delete mode 100644 polyp/packet.h delete mode 100644 polyp/pacmd.c delete mode 100644 polyp/pactl.c delete mode 100644 polyp/paplay.c delete mode 100644 polyp/parec-simple.c delete mode 100644 polyp/parseaddr.c delete mode 100644 polyp/parseaddr.h delete mode 100644 polyp/pax11publish.c delete mode 100644 polyp/pdispatch.c delete mode 100644 polyp/pdispatch.h delete mode 100644 polyp/pid.c delete mode 100644 polyp/pid.h delete mode 100644 polyp/play-memchunk.c delete mode 100644 polyp/play-memchunk.h delete mode 100644 polyp/poll.c delete mode 100644 polyp/poll.h delete mode 100644 polyp/polyplib-browser.c delete mode 100644 polyp/polyplib-browser.h delete mode 100644 polyp/polyplib-context.c delete mode 100644 polyp/polyplib-context.h delete mode 100644 polyp/polyplib-def.h delete mode 100644 polyp/polyplib-error.c delete mode 100644 polyp/polyplib-error.h delete mode 100644 polyp/polyplib-internal.h delete mode 100644 polyp/polyplib-introspect.c delete mode 100644 polyp/polyplib-introspect.h delete mode 100644 polyp/polyplib-operation.c delete mode 100644 polyp/polyplib-operation.h delete mode 100644 polyp/polyplib-scache.c delete mode 100644 polyp/polyplib-scache.h delete mode 100644 polyp/polyplib-simple.c delete mode 100644 polyp/polyplib-simple.h delete mode 100644 polyp/polyplib-stream.c delete mode 100644 polyp/polyplib-stream.h delete mode 100644 polyp/polyplib-subscribe.c delete mode 100644 polyp/polyplib-subscribe.h delete mode 100644 polyp/polyplib-version.h.in delete mode 100644 polyp/polyplib.h delete mode 100644 polyp/props.c delete mode 100644 polyp/props.h delete mode 100644 polyp/protocol-cli.c delete mode 100644 polyp/protocol-cli.h delete mode 100644 polyp/protocol-esound.c delete mode 100644 polyp/protocol-esound.h delete mode 100644 polyp/protocol-http.c delete mode 100644 polyp/protocol-http.h delete mode 100644 polyp/protocol-native.c delete mode 100644 polyp/protocol-native.h delete mode 100644 polyp/protocol-simple.c delete mode 100644 polyp/protocol-simple.h delete mode 100644 polyp/pstream-util.c delete mode 100644 polyp/pstream-util.h delete mode 100644 polyp/pstream.c delete mode 100644 polyp/pstream.h delete mode 100644 polyp/queue.c delete mode 100644 polyp/queue.h delete mode 100644 polyp/random.c delete mode 100644 polyp/random.h delete mode 100644 polyp/resampler.c delete mode 100644 polyp/resampler.h delete mode 100644 polyp/sample-util.c delete mode 100644 polyp/sample-util.h delete mode 100644 polyp/sample.c delete mode 100644 polyp/sample.h delete mode 100644 polyp/scache.c delete mode 100644 polyp/scache.h delete mode 100644 polyp/sconv-s16be.c delete mode 100644 polyp/sconv-s16be.h delete mode 100644 polyp/sconv-s16le.c delete mode 100644 polyp/sconv-s16le.h delete mode 100644 polyp/sconv.c delete mode 100644 polyp/sconv.h delete mode 100644 polyp/sink-input.c delete mode 100644 polyp/sink-input.h delete mode 100644 polyp/sink.c delete mode 100644 polyp/sink.h delete mode 100644 polyp/sioman.c delete mode 100644 polyp/sioman.h delete mode 100644 polyp/socket-client.c delete mode 100644 polyp/socket-client.h delete mode 100644 polyp/socket-server.c delete mode 100644 polyp/socket-server.h delete mode 100644 polyp/socket-util.c delete mode 100644 polyp/socket-util.h delete mode 100644 polyp/sound-file-stream.c delete mode 100644 polyp/sound-file-stream.h delete mode 100644 polyp/sound-file.c delete mode 100644 polyp/sound-file.h delete mode 100644 polyp/source-output.c delete mode 100644 polyp/source-output.h delete mode 100644 polyp/source.c delete mode 100644 polyp/source.h delete mode 100644 polyp/strbuf.c delete mode 100644 polyp/strbuf.h delete mode 100644 polyp/strlist-test.c delete mode 100644 polyp/strlist.c delete mode 100644 polyp/strlist.h delete mode 100644 polyp/subscribe.c delete mode 100644 polyp/subscribe.h delete mode 100644 polyp/tagstruct.c delete mode 100644 polyp/tagstruct.h delete mode 100644 polyp/tokenizer.c delete mode 100644 polyp/tokenizer.h delete mode 100644 polyp/util.c delete mode 100644 polyp/util.h delete mode 100644 polyp/voltest.c delete mode 100644 polyp/volume.c delete mode 100644 polyp/volume.h delete mode 100644 polyp/winsock.h delete mode 100644 polyp/x11prop.c delete mode 100644 polyp/x11prop.h delete mode 100644 polyp/x11wrap.c delete mode 100644 polyp/x11wrap.h delete mode 100644 polyp/xmalloc.c delete mode 100644 polyp/xmalloc.h create mode 100644 src/Makefile.am create mode 100644 src/client.conf.in create mode 100644 src/daemon.conf.in create mode 100644 src/daemon/caps.c create mode 100644 src/daemon/caps.h create mode 100644 src/daemon/cmdline.c create mode 100644 src/daemon/cmdline.h create mode 100644 src/daemon/cpulimit.c create mode 100644 src/daemon/cpulimit.h create mode 100644 src/daemon/daemon-conf.c create mode 100644 src/daemon/daemon-conf.h create mode 100644 src/daemon/dumpmodules.c create mode 100644 src/daemon/dumpmodules.h create mode 100644 src/daemon/main.c create mode 100755 src/default.pa.in create mode 100644 src/default.pa.win32 create mode 100755 src/depmod.py create mode 100644 src/modules/module-alsa-sink.c create mode 100644 src/modules/module-alsa-source.c create mode 100644 src/modules/module-cli.c create mode 100644 src/modules/module-combine.c create mode 100644 src/modules/module-defs.h.m4 create mode 100644 src/modules/module-detect.c create mode 100644 src/modules/module-esound-compat-spawnfd.c create mode 100644 src/modules/module-esound-compat-spawnpid.c create mode 100644 src/modules/module-esound-sink.c create mode 100644 src/modules/module-lirc.c create mode 100644 src/modules/module-match.c create mode 100644 src/modules/module-mmkbd-evdev.c create mode 100644 src/modules/module-native-protocol-fd.c create mode 100644 src/modules/module-null-sink.c create mode 100644 src/modules/module-oss-mmap.c create mode 100644 src/modules/module-oss.c create mode 100644 src/modules/module-pipe-sink.c create mode 100644 src/modules/module-pipe-source.c create mode 100644 src/modules/module-protocol-stub.c create mode 100644 src/modules/module-sine.c create mode 100644 src/modules/module-solaris.c create mode 100644 src/modules/module-tunnel.c create mode 100644 src/modules/module-waveout.c create mode 100644 src/modules/module-x11-bell.c create mode 100644 src/modules/module-x11-publish.c create mode 100644 src/modules/module-zeroconf-publish.c create mode 100644 src/polyp/cdecl.h create mode 100644 src/polyp/channelmap.c create mode 100644 src/polyp/channelmap.h create mode 100644 src/polyp/client-conf-x11.c create mode 100644 src/polyp/client-conf-x11.h create mode 100644 src/polyp/client-conf.c create mode 100644 src/polyp/client-conf.h create mode 100644 src/polyp/glib-mainloop.c create mode 100644 src/polyp/glib-mainloop.h create mode 100644 src/polyp/glib12-mainloop.c create mode 100644 src/polyp/mainloop-api.c create mode 100644 src/polyp/mainloop-api.h create mode 100644 src/polyp/mainloop-signal.c create mode 100644 src/polyp/mainloop-signal.h create mode 100644 src/polyp/mainloop.c create mode 100644 src/polyp/mainloop.h create mode 100644 src/polyp/polyplib-browser.c create mode 100644 src/polyp/polyplib-browser.h create mode 100644 src/polyp/polyplib-context.c create mode 100644 src/polyp/polyplib-context.h create mode 100644 src/polyp/polyplib-def.h create mode 100644 src/polyp/polyplib-error.c create mode 100644 src/polyp/polyplib-error.h create mode 100644 src/polyp/polyplib-internal.h create mode 100644 src/polyp/polyplib-introspect.c create mode 100644 src/polyp/polyplib-introspect.h create mode 100644 src/polyp/polyplib-operation.c create mode 100644 src/polyp/polyplib-operation.h create mode 100644 src/polyp/polyplib-scache.c create mode 100644 src/polyp/polyplib-scache.h create mode 100644 src/polyp/polyplib-simple.c create mode 100644 src/polyp/polyplib-simple.h create mode 100644 src/polyp/polyplib-stream.c create mode 100644 src/polyp/polyplib-stream.h create mode 100644 src/polyp/polyplib-subscribe.c create mode 100644 src/polyp/polyplib-subscribe.h create mode 100644 src/polyp/polyplib-version.h.in create mode 100644 src/polyp/polyplib.h create mode 100644 src/polyp/sample.c create mode 100644 src/polyp/sample.h create mode 100644 src/polyp/volume.c create mode 100644 src/polyp/volume.h create mode 100644 src/polypcore/alsa-util.c create mode 100644 src/polypcore/alsa-util.h create mode 100644 src/polypcore/authkey-prop.c create mode 100644 src/polypcore/authkey-prop.h create mode 100644 src/polypcore/authkey.c create mode 100644 src/polypcore/authkey.h create mode 100644 src/polypcore/autoload.c create mode 100644 src/polypcore/autoload.h create mode 100644 src/polypcore/cli-command.c create mode 100644 src/polypcore/cli-command.h create mode 100644 src/polypcore/cli-text.c create mode 100644 src/polypcore/cli-text.h create mode 100644 src/polypcore/cli.c create mode 100644 src/polypcore/cli.h create mode 100644 src/polypcore/client.c create mode 100644 src/polypcore/client.h create mode 100644 src/polypcore/conf-parser.c create mode 100644 src/polypcore/conf-parser.h create mode 100644 src/polypcore/core.c create mode 100644 src/polypcore/core.h create mode 100644 src/polypcore/dllmain.c create mode 100644 src/polypcore/dynarray.c create mode 100644 src/polypcore/dynarray.h create mode 100644 src/polypcore/endianmacros.h create mode 100644 src/polypcore/esound.h create mode 100644 src/polypcore/g711.c create mode 100644 src/polypcore/g711.h create mode 100644 src/polypcore/gccmacro.h create mode 100644 src/polypcore/hashmap.c create mode 100644 src/polypcore/hashmap.h create mode 100644 src/polypcore/howl-wrap.c create mode 100644 src/polypcore/howl-wrap.h create mode 100644 src/polypcore/idxset.c create mode 100644 src/polypcore/idxset.h create mode 100644 src/polypcore/inet_ntop.c create mode 100644 src/polypcore/inet_ntop.h create mode 100644 src/polypcore/iochannel.c create mode 100644 src/polypcore/iochannel.h create mode 100644 src/polypcore/ioline.c create mode 100644 src/polypcore/ioline.h create mode 100644 src/polypcore/llist.h create mode 100644 src/polypcore/log.c create mode 100644 src/polypcore/log.h create mode 100644 src/polypcore/mcalign.c create mode 100644 src/polypcore/mcalign.h create mode 100644 src/polypcore/memblock.c create mode 100644 src/polypcore/memblock.h create mode 100644 src/polypcore/memblockq.c create mode 100644 src/polypcore/memblockq.h create mode 100644 src/polypcore/memchunk.c create mode 100644 src/polypcore/memchunk.h create mode 100644 src/polypcore/modargs.c create mode 100644 src/polypcore/modargs.h create mode 100644 src/polypcore/modinfo.c create mode 100644 src/polypcore/modinfo.h create mode 100644 src/polypcore/module.c create mode 100644 src/polypcore/module.h create mode 100644 src/polypcore/namereg.c create mode 100644 src/polypcore/namereg.h create mode 100644 src/polypcore/native-common.h create mode 100644 src/polypcore/oss-util.c create mode 100644 src/polypcore/oss-util.h create mode 100644 src/polypcore/packet.c create mode 100644 src/polypcore/packet.h create mode 100644 src/polypcore/parseaddr.c create mode 100644 src/polypcore/parseaddr.h create mode 100644 src/polypcore/pdispatch.c create mode 100644 src/polypcore/pdispatch.h create mode 100644 src/polypcore/pid.c create mode 100644 src/polypcore/pid.h create mode 100644 src/polypcore/play-memchunk.c create mode 100644 src/polypcore/play-memchunk.h create mode 100644 src/polypcore/poll.c create mode 100644 src/polypcore/poll.h create mode 100644 src/polypcore/props.c create mode 100644 src/polypcore/props.h create mode 100644 src/polypcore/protocol-cli.c create mode 100644 src/polypcore/protocol-cli.h create mode 100644 src/polypcore/protocol-esound.c create mode 100644 src/polypcore/protocol-esound.h create mode 100644 src/polypcore/protocol-http.c create mode 100644 src/polypcore/protocol-http.h create mode 100644 src/polypcore/protocol-native.c create mode 100644 src/polypcore/protocol-native.h create mode 100644 src/polypcore/protocol-simple.c create mode 100644 src/polypcore/protocol-simple.h create mode 100644 src/polypcore/pstream-util.c create mode 100644 src/polypcore/pstream-util.h create mode 100644 src/polypcore/pstream.c create mode 100644 src/polypcore/pstream.h create mode 100644 src/polypcore/queue.c create mode 100644 src/polypcore/queue.h create mode 100644 src/polypcore/random.c create mode 100644 src/polypcore/random.h create mode 100644 src/polypcore/resampler.c create mode 100644 src/polypcore/resampler.h create mode 100644 src/polypcore/sample-util.c create mode 100644 src/polypcore/sample-util.h create mode 100644 src/polypcore/scache.c create mode 100644 src/polypcore/scache.h create mode 100644 src/polypcore/sconv-s16be.c create mode 100644 src/polypcore/sconv-s16be.h create mode 100644 src/polypcore/sconv-s16le.c create mode 100644 src/polypcore/sconv-s16le.h create mode 100644 src/polypcore/sconv.c create mode 100644 src/polypcore/sconv.h create mode 100644 src/polypcore/sink-input.c create mode 100644 src/polypcore/sink-input.h create mode 100644 src/polypcore/sink.c create mode 100644 src/polypcore/sink.h create mode 100644 src/polypcore/sioman.c create mode 100644 src/polypcore/sioman.h create mode 100644 src/polypcore/socket-client.c create mode 100644 src/polypcore/socket-client.h create mode 100644 src/polypcore/socket-server.c create mode 100644 src/polypcore/socket-server.h create mode 100644 src/polypcore/socket-util.c create mode 100644 src/polypcore/socket-util.h create mode 100644 src/polypcore/sound-file-stream.c create mode 100644 src/polypcore/sound-file-stream.h create mode 100644 src/polypcore/sound-file.c create mode 100644 src/polypcore/sound-file.h create mode 100644 src/polypcore/source-output.c create mode 100644 src/polypcore/source-output.h create mode 100644 src/polypcore/source.c create mode 100644 src/polypcore/source.h create mode 100644 src/polypcore/strbuf.c create mode 100644 src/polypcore/strbuf.h create mode 100644 src/polypcore/strlist.c create mode 100644 src/polypcore/strlist.h create mode 100644 src/polypcore/subscribe.c create mode 100644 src/polypcore/subscribe.h create mode 100644 src/polypcore/tagstruct.c create mode 100644 src/polypcore/tagstruct.h create mode 100644 src/polypcore/tokenizer.c create mode 100644 src/polypcore/tokenizer.h create mode 100644 src/polypcore/util.c create mode 100644 src/polypcore/util.h create mode 100644 src/polypcore/winsock.h create mode 100644 src/polypcore/x11prop.c create mode 100644 src/polypcore/x11prop.h create mode 100644 src/polypcore/x11wrap.c create mode 100644 src/polypcore/x11wrap.h create mode 100644 src/polypcore/xmalloc.c create mode 100644 src/polypcore/xmalloc.h create mode 100644 src/tests/cpulimit-test.c create mode 100644 src/tests/mainloop-test.c create mode 100644 src/tests/mcalign-test.c create mode 100644 src/tests/pacat-simple.c create mode 100644 src/tests/parec-simple.c create mode 100644 src/tests/strlist-test.c create mode 100644 src/tests/voltest.c create mode 100755 src/utils/esdcompat.sh.in create mode 100644 src/utils/pabrowse.c create mode 100644 src/utils/pacat.c create mode 100644 src/utils/pacmd.c create mode 100644 src/utils/pactl.c create mode 100644 src/utils/paplay.c create mode 100644 src/utils/pax11publish.c diff --git a/Makefile.am b/Makefile.am index 2cf93c75..9705d45d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,7 +18,7 @@ # USA. EXTRA_DIST = bootstrap.sh LICENSE doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in libtool.m4 ltdl.m4 -SUBDIRS=libltdl polyp doc +SUBDIRS=libltdl src doc MAINTAINERCLEANFILES = noinst_DATA = diff --git a/configure.ac b/configure.ac index 03663590..182a2455 100644 --- a/configure.ac +++ b/configure.ac @@ -21,7 +21,7 @@ AC_PREREQ(2.57) AC_INIT([polypaudio],[0.8],[mzcbylcnhqvb (at) 0pointer (dot) de]) -AC_CONFIG_SRCDIR([polyp/main.c]) +AC_CONFIG_SRCDIR([src/daemon/main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) @@ -392,7 +392,7 @@ fi AC_CONFIG_FILES([ Makefile -polyp/Makefile +src/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc @@ -407,7 +407,7 @@ doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf -polyp/polyplib-version.h +src/polyp/polyplib-version.h doc/FAQ.html ]) AC_OUTPUT diff --git a/polyp/Makefile.am b/polyp/Makefile.am deleted file mode 100644 index 061b82b4..00000000 --- a/polyp/Makefile.am +++ /dev/null @@ -1,1052 +0,0 @@ -# $Id$ -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - - -################################### -# Extra directories # -################################### - -polypincludedir=$(includedir)/polyp -polypconfdir=$(sysconfdir)/polypaudio - -modlibdir=$(libdir)/polypaudio - -################################### -# Defines # -################################### - -POLYPAUDIO_BINARY=$(bindir)/polypaudio$(EXEEXT) -if OS_IS_WIN32 -DEFAULT_CONFIG_DIR=%POLYP_ROOT% -else -DEFAULT_CONFIG_DIR=$(polypconfdir) -endif - -################################### -# Compiler/linker flags # -################################### - -AM_CFLAGS = -I$(top_srcdir) -AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS -AM_CFLAGS += $(LTDLINCL) -AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) -AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" -#AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\" -AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\" -AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(POLYPAUDIO_BINARY)\" - -# This cool debug trap works on i386/gcc only -AM_CFLAGS += '-DDEBUG_TRAP=__asm__("int $$3")' - -AM_LIBADD = $(PTHREAD_LIBS) -AM_LDADD = $(PTHREAD_LIBS) - -# Only required on some platforms but defined for all to avoid errors -AM_LDFLAGS = -no-undefined - -if STATIC_BINS -BINLDFLAGS = -static -endif - -if OS_IS_WIN32 -AM_LDFLAGS+=-Wl,--export-all-symbols -WINSOCK_LIBS=-lwsock32 -lws2_32 -lwininet -endif - -################################### -# Extra files # -################################### - -EXTRA_DIST = \ - client.conf.in \ - daemon.conf.in \ - default.pa.in \ - depmod.py \ - esdcompat.sh.in \ - module-defs.h.m4 - -polypconf_DATA = default.pa daemon.conf client.conf - -BUILT_SOURCES = polyplib-version.h - -################################### -# Main daemon # -################################### - -bin_PROGRAMS = polypaudio - -polypaudio_SOURCES = \ - caps.h caps.c \ - cmdline.c cmdline.h \ - cpulimit.c cpulimit.h \ - conf-parser.h conf-parser.c \ - daemon-conf.c daemon-conf.h \ - dumpmodules.c dumpmodules.h \ - gcc-printf.h \ - main.c \ - pid.c pid.h - -polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) -polypaudio_CPPFLAGS = $(AM_CPPFLAGS) -polypaudio_LDADD = $(AM_LDADD) libpolypcore.la $(LIBLTDL) \ - $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) $(LIBOIL_LIBS) -polypaudio_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -dlopen force $(foreach f,$(PREOPEN_LIBS),-dlopen $(f)) - -if PREOPEN_MODS -PREOPEN_LIBS = $(PREOPEN_MODS) -else -PREOPEN_LIBS = $(modlib_LTLIBRARIES) -endif - -################################### -# Utility programs # -################################### - -bin_PROGRAMS += \ - pacat \ - pactl \ - paplay - -if HAVE_AF_UNIX -bin_PROGRAMS += pacmd -endif - -if HAVE_X11 -bin_PROGRAMS += pax11publish -endif - -if HAVE_HOWL -bin_PROGRAMS += pabrowse -endif - -bin_SCRIPTS = esdcompat.sh - -pacat_SOURCES = pacat.c -pacat_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la -pacat_CFLAGS = $(AM_CFLAGS) -pacat_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) - -paplay_SOURCES = paplay.c -paplay_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) -paplay_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) -paplay_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) - -pactl_SOURCES = pactl.c -pactl_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) -pactl_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) -pactl_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) - -pacmd_SOURCES = pacmd.c util.c util.h xmalloc.c xmalloc.h log.c log.h pid.c pid.h -pacmd_CFLAGS = $(AM_CFLAGS) -pacmd_LDADD = $(AM_LDADD) -pacmd_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) - -pax11publish_SOURCES = pax11publish.c util.c util.h xmalloc.c xmalloc.h log.c log.h authkey.c authkey.h client-conf.c client-conf.h conf-parser.c conf-parser.h x11prop.c x11prop.h random.c random.h -pax11publish_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) -pax11publish_LDADD = $(AM_LDADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) -pax11publish_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) - -pabrowse_SOURCES = pabrowse.c -pabrowse_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-browse-@PA_MAJORMINOR@.la -pabrowse_CFLAGS = $(AM_CFLAGS) -pabrowse_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) - -################################### -# Test programs # -################################### - -noinst_PROGRAMS = \ - mainloop-test \ - mcalign-test \ - pacat-simple \ - parec-simple \ - strlist-test \ - voltest - -if HAVE_SIGXCPU -noinst_PROGRAMS += \ - cpulimit-test \ - cpulimit-test2 -endif - -if HAVE_GLIB20 -noinst_PROGRAMS += \ - mainloop-test-glib -endif - -if HAVE_GLIB12 -noinst_PROGRAMS += \ - mainloop-test-glib12 -endif - -mainloop_test_SOURCES = mainloop-test.c -mainloop_test_CFLAGS = $(AM_CFLAGS) -mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-@PA_MAJORMINOR@.la -mainloop_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) - -mcalign_test_SOURCES = mcalign-test.c util.c util.h xmalloc.c xmalloc.h log.c log.h mcalign.c mcalign.h memchunk.c memchunk.h memblock.c memblock.h -mcalign_test_CFLAGS = $(AM_CFLAGS) -mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) -mcalign_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) - -pacat_simple_SOURCES = pacat-simple.c -pacat_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la -pacat_simple_CFLAGS = $(AM_CFLAGS) -pacat_simple_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) - -parec_simple_SOURCES = parec-simple.c -parec_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la -parec_simple_CFLAGS = $(AM_CFLAGS) -parec_simple_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) - -strlist_test_SOURCES = strlist-test.c strlist.c strlist.h strbuf.c strbuf.h util.c util.h xmalloc.c xmalloc.h log.c log.h -strlist_test_CFLAGS = $(AM_CFLAGS) -strlist_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) -strlist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) - -voltest_SOURCES = voltest.c sample.c volume.c volume.h sample.h -voltest_CFLAGS = $(AM_CFLAGS) -voltest_LDADD = $(AM_LDADD) -voltest_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) - -cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h idxset.c idxset.h -cpulimit_test_CFLAGS = $(AM_CFLAGS) -cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la -cpulimit_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) - -cpulimit_test2_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h idxset.c idxset.h -cpulimit_test2_CFLAGS = $(AM_CFLAGS) -DTEST2 -cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la -cpulimit_test2_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) - -mainloop_test_glib_SOURCES = $(mainloop_test_SOURCES) -mainloop_test_glib_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB20_CFLAGS) -DGLIB_MAIN_LOOP -mainloop_test_glib_LDADD = $(mainloop_test_LDADD) $(GLIB20_LIBS) libpolyp-mainloop-glib-@PA_MAJORMINOR@.la -mainloop_test_glib_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) - -mainloop_test_glib12_SOURCES = $(mainloop_test_SOURCES) -mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MAIN_LOOP -mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12-@PA_MAJORMINOR@.la -mainloop_test_glib12_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) - -################################### -# Client library # -################################### - -polypinclude_HEADERS = \ - cdecl.h \ - channelmap.h \ - glib-mainloop.h \ - mainloop.h \ - mainloop-api.h \ - mainloop-signal.h \ - polyplib.h \ - polyplib-context.h \ - polyplib-def.h \ - polyplib-error.h \ - polyplib-introspect.h \ - polyplib-operation.h \ - polyplib-scache.h \ - polyplib-simple.h \ - polyplib-stream.h \ - polyplib-subscribe.h \ - polyplib-version.h \ - sample.h \ - volume.h - -if HAVE_HOWL -polypinclude_HEADERS += \ - polyplib-browser.h -endif - -lib_LTLIBRARIES = \ - libpolyp-@PA_MAJORMINOR@.la \ - libpolyp-error-@PA_MAJORMINOR@.la \ - libpolyp-mainloop-@PA_MAJORMINOR@.la \ - libpolyp-simple-@PA_MAJORMINOR@.la - -if HAVE_HOWL -lib_LTLIBRARIES += \ - libpolyp-browse-@PA_MAJORMINOR@.la -endif - -if HAVE_GLIB20 -lib_LTLIBRARIES += \ - libpolyp-mainloop-glib-@PA_MAJORMINOR@.la -endif - -if HAVE_GLIB12 -lib_LTLIBRARIES += \ - libpolyp-mainloop-glib12-@PA_MAJORMINOR@.la -endif - -libpolyp_@PA_MAJORMINOR@_la_SOURCES = \ - authkey.c authkey.h \ - cdecl.h \ - client-conf.c client-conf.h \ - conf-parser.c conf-parser.h \ - dllmain.c \ - dynarray.c dynarray.h \ - gcc-printf.h \ - idxset.c idxset.h \ - iochannel.c iochannel.h \ - llist.h \ - log.c log.h \ - mainloop-api.c mainloop-api.h \ - mcalign.c mcalign.h \ - memblock.c memblock.h \ - memchunk.c memchunk.h \ - native-common.h \ - packet.c packet.h \ - parseaddr.c parseaddr.h \ - pdispatch.c pdispatch.h \ - polyplib.h \ - polyplib-context.c polyplib-context.h \ - polyplib-def.h \ - polyplib-internal.h \ - polyplib-introspect.c polyplib-introspect.h \ - polyplib-operation.c polyplib-operation.h \ - polyplib-scache.c polyplib-scache.h \ - polyplib-stream.c polyplib-stream.h \ - polyplib-subscribe.c polyplib-subscribe.h \ - pstream.c pstream.h \ - pstream-util.c pstream-util.h \ - queue.c queue.h \ - random.c random.h \ - sample.c sample.h \ - socket-client.c socket-client.h \ - socket-util.c socket-util.h \ - strbuf.c strbuf.h \ - strlist.c strlist.h \ - tagstruct.c tagstruct.h \ - util.c util.h \ - winsock.h \ - xmalloc.c xmalloc.h \ - channelmap.c channelmap.h \ - volume.c volume.h - -if HAVE_X11 -libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ - client-conf-x11.c client-conf-x11.h \ - x11prop.c x11prop.h -endif - -libpolyp_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) -libpolyp_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 -libpolyp_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) - -if HAVE_X11 -libpolyp_@PA_MAJORMINOR@_la_CFLAGS += $(X_CFLAGS) -libpolyp_@PA_MAJORMINOR@_la_LDFLAGS += $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) -endif - -if HAVE_LIBASYNCNS -libpolyp_@PA_MAJORMINOR@_la_CFLAGS += $(LIBASYNCNS_CFLAGS) -libpolyp_@PA_MAJORMINOR@_la_LIBADD += $(LIBASYNCNS_LIBS) -endif - -libpolyp_error_@PA_MAJORMINOR@_la_SOURCES = polyplib-error.c polyplib-error.h -libpolyp_error_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) -libpolyp_error_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la -libpolyp_error_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 - -libpolyp_mainloop_@PA_MAJORMINOR@_la_SOURCES = \ - mainloop.c mainloop.h \ - mainloop-api.h mainloop-api.c \ - mainloop-signal.c mainloop-signal.h \ - poll.c poll.h -libpolyp_mainloop_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) -libpolyp_mainloop_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la $(WINSOCK_LIBS) -libpolyp_mainloop_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 - -libpolyp_simple_@PA_MAJORMINOR@_la_SOURCES = polyplib-simple.c polyplib-simple.h -libpolyp_simple_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) -libpolyp_simple_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la -libpolyp_simple_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 - -libpolyp_browse_@PA_MAJORMINOR@_la_SOURCES = polyplib-browser.c polyplib-browser.h -libpolyp_browse_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) -libpolyp_browse_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la $(HOWL_LIBS) -libpolyp_browse_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 - -libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_SOURCES = glib-mainloop.h glib-mainloop.c -libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) -libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop-@PA_MAJORMINOR@.la $(GLIB20_LIBS) -libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 - -libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_SOURCES = glib-mainloop.h glib12-mainloop.c -libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS) -libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop-@PA_MAJORMINOR@.la $(GLIB12_LIBS) -libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 - -################################### -# Daemon core library # -################################### - -polypinclude_HEADERS += \ - cli-command.h \ - client.h \ - core.h \ - dynarray.h \ - endianmacros.h \ - hashmap.h \ - idxset.h \ - iochannel.h \ - memblock.h \ - memblockq.h \ - memchunk.h \ - modargs.h \ - module.h \ - namereg.h \ - queue.h \ - resampler.h \ - sample-util.h \ - sink.h \ - sink-input.h \ - sioman.h \ - socket-server.h \ - socket-client.h \ - socket-util.h \ - source.h \ - source-output.h \ - strbuf.h \ - tokenizer.h \ - tagstruct.h \ - util.h - -lib_LTLIBRARIES += libpolypcore.la - -libpolypcore_la_SOURCES = \ - autoload.c autoload.h \ - cli-command.c cli-command.h \ - cli-text.c cli-text.h \ - client.c client.h \ - core.c core.h \ - dllmain.c \ - dynarray.c dynarray.h \ - endianmacros.h \ - g711.c g711.h \ - hashmap.c hashmap.h \ - idxset.c idxset.h \ - log.c log.h \ - mainloop.c mainloop.h \ - mainloop-api.c mainloop-api.h \ - mainloop-signal.c mainloop-signal.h \ - mcalign.c mcalign.h \ - memblock.c memblock.h \ - memblockq.c memblockq.h \ - memchunk.c memchunk.h \ - modargs.c modargs.h \ - modinfo.c modinfo.h \ - module.c module.h \ - namereg.c namereg.h \ - play-memchunk.c play-memchunk.h \ - poll.c poll.h \ - props.c props.h \ - queue.c queue.h \ - random.c random.h \ - resampler.c resampler.h \ - sample.c sample.h \ - sample-util.c sample-util.h \ - scache.c scache.h \ - sconv.c sconv.h \ - sconv-s16be.c sconv-s16be.h \ - sconv-s16le.c sconv-s16le.h \ - sink.c sink.h \ - sink-input.c sink-input.h \ - sioman.c sioman.h \ - sound-file.c sound-file.h \ - sound-file-stream.c sound-file-stream.h \ - source.c source.h \ - source-output.c source-output.h \ - strbuf.c strbuf.h \ - subscribe.c subscripe.h \ - tokenizer.c tokenizer.h \ - util.c util.h \ - winsock.h \ - xmalloc.c xmalloc.h \ - volume.c volume.h \ - channelmap.c channelmap.h - -libpolypcore_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBOIL_CFLAGS) -libpolypcore_la_LDFLAGS = -avoid-version -libpolypcore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) $(LIBOIL_LIBS) - -################################### -# Plug-in support libraries # -################################### - -### Warning! Due to an obscure bug in libtool/automake it is required -### that the libraries in modlib_LTLIBRARIES are specified in-order, -### i.e. libraries near the end of the list depend on libraries near -### the head, and not the other way! - -modlib_LTLIBRARIES = \ - libsocket-util.la \ - libiochannel.la \ - libsocket-server.la \ - libsocket-client.la \ - libparseaddr.la \ - libpacket.la \ - libpstream.la \ - libioline.la \ - libcli.la \ - libprotocol-cli.la \ - libtagstruct.la \ - libpstream-util.la \ - libpdispatch.la \ - libauthkey.la \ - libauthkey-prop.la \ - libstrlist.la \ - libprotocol-simple.la \ - libprotocol-esound.la \ - libprotocol-native.la \ - libprotocol-http.la - -if HAVE_X11 -modlib_LTLIBRARIES += \ - libx11wrap.la \ - libx11prop.la -endif - -if HAVE_OSS -modlib_LTLIBRARIES += \ - liboss-util.la -endif - -if HAVE_ALSA -modlib_LTLIBRARIES += \ - libalsa-util.la -endif - -if HAVE_HOWL -modlib_LTLIBRARIES += \ - libhowl-wrap.la -endif - -libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h -libprotocol_simple_la_LDFLAGS = -avoid-version -libprotocol_simple_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket-server.la libiochannel.la - -libsocket_server_la_SOURCES = \ - inet_ntop.c inet_ntop.h \ - socket-server.c socket-server.h -libsocket_server_la_LDFLAGS = -avoid-version -libsocket_server_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la libsocket-util.la $(LIBWRAP_LIBS) $(WINSOCK_LIBS) - -libsocket_client_la_SOURCES = socket-client.c socket-client.h -libsocket_client_la_LDFLAGS = -avoid-version -libsocket_client_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la libsocket-util.la libparseaddr.la $(LIBASYNCNS_LIBS) $(WINSOCK_LIBS) -libsocket_client_la_CFLAGS = $(AM_CFLAGS) $(LIBASYNCNS_CFLAGS) - -libparseaddr_la_SOURCES = parseaddr.c parseaddr.h -libparseaddr_la_LDFLAGS = -avoid-version -libparseaddr_la_LIBADD = $(AM_LIBADD) libpolypcore.la - -libpstream_la_SOURCES = pstream.c pstream.h -libpstream_la_LDFLAGS = -avoid-version -libpstream_la_LIBADD = $(AM_LIBADD) libpolypcore.la libpacket.la libiochannel.la $(WINSOCK_LIBS) - -libpstream_util_la_SOURCES = pstream-util.c pstream-util.h -libpstream_util_la_LDFLAGS = -avoid-version -libpstream_util_la_LIBADD = $(AM_LIBADD) libpacket.la libpstream.la libtagstruct.la - -libpdispatch_la_SOURCES = pdispatch.c pdispatch.h -libpdispatch_la_LDFLAGS = -avoid-version -libpdispatch_la_LIBADD = $(AM_LIBADD) libtagstruct.la libpolypcore.la - -libiochannel_la_SOURCES = iochannel.c iochannel.h -libiochannel_la_LDFLAGS = -avoid-version -libiochannel_la_LIBADD = $(AM_LIBADD) libsocket-util.la libpolypcore.la $(WINSOCK_LIBS) - -libpacket_la_SOURCES = packet.c packet.h -libpacket_la_LDFLAGS = -avoid-version -libpacket_la_LIBADD = $(AM_LIBADD) libpolypcore.la - -libioline_la_SOURCES = ioline.c ioline.h -libioline_la_LDFLAGS = -avoid-version -libioline_la_LIBADD = $(AM_LIBADD) libiochannel.la libpolypcore.la - -libcli_la_SOURCES = cli.c cli.h -libcli_la_CPPFLAGS = $(AM_CPPFLAGS) -libcli_la_LDFLAGS = -avoid-version -libcli_la_LIBADD = $(AM_LIBADD) libiochannel.la libioline.la libpolypcore.la - -libstrlist_la_SOURCES = strlist.c strlist.h -libstrlist_la_LDFLAGS = -avoid-version -libstrlist_la_LIBADD = $(AM_LIBADD) libpolypcore.la - -libprotocol_cli_la_SOURCES = protocol-cli.c protocol-cli.h -libprotocol_cli_la_LDFLAGS = -avoid-version -libprotocol_cli_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libcli.la libpolypcore.la - -libprotocol_http_la_SOURCES = protocol-http.c protocol-http.h -libprotocol_http_la_LDFLAGS = -avoid-version -libprotocol_http_la_LIBADD = $(AM_LIBADD) libsocket-server.la libioline.la libpolypcore.la libiochannel.la - -libprotocol_native_la_SOURCES = protocol-native.c protocol-native.h native-common.h -libprotocol_native_la_LDFLAGS = -avoid-version -libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libstrlist.la libpolypcore.la libiochannel.la - -libtagstruct_la_SOURCES = tagstruct.c tagstruct.h -libtagstruct_la_LDFLAGS = -avoid-version -libtagstruct_la_LIBADD = $(AM_LIBADD) libpolypcore.la $(WINSOCK_LIBS) - -libprotocol_esound_la_SOURCES = protocol-esound.c protocol-esound.h esound.h -libprotocol_esound_la_LDFLAGS = -avoid-version -libprotocol_esound_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libauthkey.la libpolypcore.la - -libauthkey_la_SOURCES = authkey.c authkey.h -libauthkey_la_LDFLAGS = -avoid-version -libauthkey_la_LIBADD = $(AM_LIBADD) libpolypcore.la - -libauthkey_prop_la_SOURCES = authkey-prop.c authkey-prop.h -libauthkey_prop_la_LDFLAGS = -avoid-version -libauthkey_prop_la_LIBADD = $(AM_LIBADD) libpolypcore.la - -libsocket_util_la_SOURCES = socket-util.c socket-util.h -libsocket_util_la_LDFLAGS = -avoid-version -libsocket_util_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) - -# X11 - -libx11wrap_la_SOURCES = x11wrap.c x11wrap.h -libx11wrap_la_LDFLAGS = -avoid-version -libx11wrap_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) -libx11wrap_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) - -libx11prop_la_SOURCES = x11prop.c x11prop.h -libx11prop_la_LDFLAGS = -avoid-version -libx11prop_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) -libx11prop_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) - -# OSS - -liboss_util_la_SOURCES = oss-util.c oss-util.h -liboss_util_la_LDFLAGS = -avoid-version - -# ALSA - -libalsa_util_la_SOURCES = alsa-util.c alsa-util.h -libalsa_util_la_LDFLAGS = -avoid-version -libalsa_util_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) -libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) - -# HOWL - -libhowl_wrap_la_SOURCES = howl-wrap.c howl-wrap.h -libhowl_wrap_la_LDFLAGS = -avoid-version -libhowl_wrap_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) -libhowl_wrap_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) - -################################### -# Plug-in libraries # -################################### - -modlib_LTLIBRARIES += \ - module-cli.la \ - module-cli-protocol-tcp.la \ - module-cli-protocol-tcp6.la \ - module-simple-protocol-tcp.la \ - module-simple-protocol-tcp6.la \ - module-esound-protocol-tcp.la \ - module-esound-protocol-tcp6.la \ - module-native-protocol-tcp.la \ - module-native-protocol-tcp6.la \ - module-native-protocol-fd.la \ - module-sine.la \ - module-combine.la \ - module-tunnel-sink.la \ - module-tunnel-source.la \ - module-null-sink.la \ - module-esound-sink.la \ - module-http-protocol-tcp.la \ - module-http-protocol-tcp6.la \ - module-detect.la - -if HAVE_AF_UNIX -modlib_LTLIBRARIES += \ - module-cli-protocol-unix.la \ - module-simple-protocol-unix.la \ - module-esound-protocol-unix.la \ - module-native-protocol-unix.la \ - module-http-protocol-unix.la -endif - -if HAVE_MKFIFO -modlib_LTLIBRARIES += \ - module-pipe-sink.la \ - module-pipe-source.la -endif - -if !OS_IS_WIN32 -modlib_LTLIBRARIES += \ - module-esound-compat-spawnfd.la \ - module-esound-compat-spawnpid.la -endif - -if HAVE_REGEX -modlib_LTLIBRARIES += \ - module-match.la -endif - -if HAVE_X11 -modlib_LTLIBRARIES += \ - module-x11-bell.la \ - module-x11-publish.la -endif - -if HAVE_OSS -modlib_LTLIBRARIES += \ - module-oss.la \ - module-oss-mmap.la -endif - -if HAVE_ALSA -modlib_LTLIBRARIES += \ - module-alsa-sink.la \ - module-alsa-source.la -endif - -if HAVE_SOLARIS -modlib_LTLIBRARIES += \ - module-solaris.la -endif - -if HAVE_HOWL -modlib_LTLIBRARIES += \ - module-zeroconf-publish.la -endif - -if HAVE_LIRC -modlib_LTLIBRARIES += \ - module-lirc.la -endif - -if HAVE_EVDEV -modlib_LTLIBRARIES += \ - module-mmkbd-evdev.la -endif - -if OS_IS_WIN32 -modlib_LTLIBRARIES += \ - module-waveout.la -endif - -# These are generated by a M4 script - -SYMDEF_FILES = \ - module-cli-symdef.h \ - module-cli-protocol-tcp-symdef.h \ - module-cli-protocol-tcp6-symdef.h \ - module-cli-protocol-unix-symdef.h \ - module-pipe-sink-symdef.h \ - module-pipe-source-symdef.h \ - module-simple-protocol-tcp-symdef.h \ - module-simple-protocol-tcp6-symdef.h \ - module-simple-protocol-unix-symdef.h \ - module-esound-protocol-tcp-symdef.h \ - module-esound-protocol-tcp6-symdef.h \ - module-esound-protocol-unix-symdef.h \ - module-native-protocol-tcp-symdef.h \ - module-native-protocol-tcp6-symdef.h \ - module-native-protocol-unix-symdef.h \ - module-native-protocol-fd-symdef.h \ - module-sine-symdef.h \ - module-combine-symdef.h \ - module-esound-compat-spawnfd-symdef.h \ - module-esound-compat-spawnpid-symdef.h \ - module-match-symdef.h \ - module-tunnel-sink-symdef.h \ - module-tunnel-source-symdef.h \ - module-null-sink-symdef.h \ - module-esound-sink-symdef.h \ - module-zeroconf-publish-symdef.h \ - module-lirc-symdef.h \ - module-mmkbd-evdev-symdef.h \ - module-http-protocol-tcp-symdef.h \ - module-http-protocol-tcp6-symdef.h \ - module-http-protocol-unix-symdef.h \ - module-x11-bell-symdef.h \ - module-x11-publish-symdef.h \ - module-oss-symdef.h \ - module-oss-mmap-symdef.h \ - module-alsa-sink-symdef.h \ - module-alsa-source-symdef.h \ - module-solaris-symdef.h \ - module-waveout-symdef.h \ - module-detect-symdef.h - -EXTRA_DIST += $(SYMDEF_FILES) -BUILT_SOURCES += $(SYMDEF_FILES) - -$(SYMDEF_FILES): module-defs.h.m4 - $(M4) -Dfname="$@" $< > $@ - -# Simple protocol - -module_simple_protocol_tcp_la_SOURCES = module-protocol-stub.c -module_simple_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) -module_simple_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_simple_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-simple.la libsocket-server.la - -module_simple_protocol_tcp6_la_SOURCES = module-protocol-stub.c -module_simple_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) -module_simple_protocol_tcp6_la_LDFLAGS = -module -avoid-version -module_simple_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-simple.la libsocket-server.la - -module_simple_protocol_unix_la_SOURCES = module-protocol-stub.c -module_simple_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) -module_simple_protocol_unix_la_LDFLAGS = -module -avoid-version -module_simple_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-simple.la libsocket-server.la libsocket-util.la - -# CLI protocol - -module_cli_la_SOURCES = module-cli.c -module_cli_la_LDFLAGS = -module -avoid-version -module_cli_la_LIBADD = $(AM_LIBADD) libcli.la libiochannel.la libpolypcore.la - -module_cli_protocol_tcp_la_SOURCES = module-protocol-stub.c -module_cli_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) -module_cli_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_cli_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-cli.la libsocket-server.la - -module_cli_protocol_tcp6_la_SOURCES = module-protocol-stub.c -module_cli_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) -module_cli_protocol_tcp6_la_LDFLAGS = -module -avoid-version -module_cli_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-cli.la libsocket-server.la - -module_cli_protocol_unix_la_SOURCES = module-protocol-stub.c -module_cli_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) -module_cli_protocol_unix_la_LDFLAGS = -module -avoid-version -module_cli_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-cli.la libsocket-server.la libsocket-util.la - -# HTTP protocol - -module_http_protocol_tcp_la_SOURCES = module-protocol-stub.c -module_http_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_CFLAGS) -module_http_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_http_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-http.la libsocket-server.la - -module_http_protocol_tcp6_la_SOURCES = module-protocol-stub.c -module_http_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_CFLAGS) -module_http_protocol_tcp6_la_LDFLAGS = -module -avoid-version -module_http_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-http.la libsocket-server.la - -module_http_protocol_unix_la_SOURCES = module-protocol-stub.c -module_http_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_CFLAGS) -module_http_protocol_unix_la_LDFLAGS = -module -avoid-version -module_http_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-http.la libsocket-server.la libsocket-util.la - -# Native protocol - -module_native_protocol_tcp_la_SOURCES = module-protocol-stub.c -module_native_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) -module_native_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_native_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la - -module_native_protocol_tcp6_la_SOURCES = module-protocol-stub.c -module_native_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) -module_native_protocol_tcp6_la_LDFLAGS = -module -avoid-version -module_native_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la - -module_native_protocol_unix_la_SOURCES = module-protocol-stub.c -module_native_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) -module_native_protocol_unix_la_LDFLAGS = -module -avoid-version -module_native_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la libsocket-util.la - -module_native_protocol_fd_la_SOURCES = module-native-protocol-fd.c -module_native_protocol_fd_la_CFLAGS = $(AM_CFLAGS) -module_native_protocol_fd_la_LDFLAGS = -module -avoid-version -module_native_protocol_fd_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la libsocket-util.la libiochannel.la - -# EsounD protocol - -module_esound_protocol_tcp_la_SOURCES = module-protocol-stub.c -module_esound_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) -module_esound_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_esound_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-esound.la libsocket-server.la - -module_esound_protocol_tcp6_la_SOURCES = module-protocol-stub.c -module_esound_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) -module_esound_protocol_tcp6_la_LDFLAGS = -module -avoid-version -module_esound_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-esound.la libsocket-server.la - -module_esound_protocol_unix_la_SOURCES = module-protocol-stub.c -module_esound_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) -module_esound_protocol_unix_la_LDFLAGS = -module -avoid-version -module_esound_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-esound.la libsocket-server.la libsocket-util.la - -module_esound_compat_spawnfd_la_SOURCES = module-esound-compat-spawnfd.c -module_esound_compat_spawnfd_la_LDFLAGS = -module -avoid-version -module_esound_compat_spawnfd_la_LIBADD = $(AM_LIBADD) libpolypcore.la - -module_esound_compat_spawnpid_la_SOURCES = module-esound-compat-spawnpid.c -module_esound_compat_spawnpid_la_LDFLAGS = -module -avoid-version -module_esound_compat_spawnpid_la_LIBADD = $(AM_LIBADD) libpolypcore.la - -module_esound_sink_la_SOURCES = module-esound-sink.c -module_esound_sink_la_LDFLAGS = -module -avoid-version -module_esound_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la libsocket-client.la libauthkey.la - -# Pipes - -module_pipe_sink_la_SOURCES = module-pipe-sink.c -module_pipe_sink_la_LDFLAGS = -module -avoid-version -module_pipe_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la - -module_pipe_source_la_SOURCES = module-pipe-source.c -module_pipe_source_la_LDFLAGS = -module -avoid-version -module_pipe_source_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la - -# Fake sources/sinks - -module_sine_la_SOURCES = module-sine.c -module_sine_la_LDFLAGS = -module -avoid-version -module_sine_la_LIBADD = $(AM_LIBADD) libpolypcore.la - -module_null_sink_la_SOURCES = module-null-sink.c -module_null_sink_la_LDFLAGS = -module -avoid-version -module_null_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la - -# Couplings - -module_combine_la_SOURCES = module-combine.c -module_combine_la_LDFLAGS = -module -avoid-version -module_combine_la_LIBADD = $(AM_LIBADD) libpolypcore.la - -module_match_la_SOURCES = module-match.c -module_match_la_LDFLAGS = -module -avoid-version -module_match_la_LIBADD = $(AM_LIBADD) libpolypcore.la - -module_tunnel_sink_la_SOURCES = module-tunnel.c -module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS) -module_tunnel_sink_la_LDFLAGS = -module -avoid-version -module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la - -module_tunnel_source_la_SOURCES = module-tunnel.c -module_tunnel_source_la_LDFLAGS = -module -avoid-version -module_tunnel_source_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la - -# X11 - -module_x11_bell_la_SOURCES = module-x11-bell.c -module_x11_bell_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) -module_x11_bell_la_LDFLAGS = -module -avoid-version -module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la - -module_x11_publish_la_SOURCES = module-x11-publish.c -module_x11_publish_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) -module_x11_publish_la_LDFLAGS = -module -avoid-version -module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la libauthkey.la libauthkey-prop.la libx11prop.la libstrlist.la - -# OSS - -module_oss_la_SOURCES = module-oss.c -module_oss_la_LDFLAGS = -module -avoid-version -module_oss_la_LIBADD = $(AM_LIBADD) libiochannel.la liboss-util.la - -module_oss_mmap_la_SOURCES = module-oss-mmap.c -module_oss_mmap_la_LDFLAGS = -module -avoid-version -module_oss_mmap_la_LIBADD = $(AM_LIBADD) liboss-util.la - -# ALSA - -module_alsa_sink_la_SOURCES = module-alsa-sink.c -module_alsa_sink_la_LDFLAGS = -module -avoid-version -module_alsa_sink_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la -module_alsa_sink_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) - -module_alsa_source_la_SOURCES = module-alsa-source.c -module_alsa_source_la_LDFLAGS = -module -avoid-version -module_alsa_source_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la -module_alsa_source_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) - -# Solaris - -module_solaris_la_SOURCES = module-solaris.c -module_solaris_la_LDFLAGS = -module -avoid-version -module_solaris_la_LIBADD = $(AM_LIBADD) libiochannel.la - -# HOWL - -module_zeroconf_publish_la_SOURCES = module-zeroconf-publish.c -module_zeroconf_publish_la_LDFLAGS = -module -avoid-version -module_zeroconf_publish_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) libhowl-wrap.la -module_zeroconf_publish_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) - -# LIRC - -module_lirc_la_SOURCES = module-lirc.c -module_lirc_la_LDFLAGS = -module -avoid-version -module_lirc_la_LIBADD = $(AM_LIBADD) $(LIRC_LIBS) -module_lirc_la_CFLAGS = $(AM_CFLAGS) $(LIRC_CFLAGS) - -# Linux evdev - -module_mmkbd_evdev_la_SOURCES = module-mmkbd-evdev.c -module_mmkbd_evdev_la_LDFLAGS = -module -avoid-version -module_mmkbd_evdev_la_LIBADD = $(AM_LIBADD) -module_mmkbd_evdev_la_CFLAGS = $(AM_CFLAGS) - -# Windows waveout - -module_waveout_la_SOURCES = module-waveout.c -module_waveout_la_LDFLAGS = -module -avoid-version -module_waveout_la_LIBADD = $(AM_LIBADD) libpolypcore.la -lwinmm -module_waveout_la_CFLAGS = $(AM_CFLAGS) - -# Hardware autodetection module -module_detect_la_SOURCES = module-detect.c -module_detect_la_LDFLAGS = -module -avoid-version -module_detect_la_LIBADD = $(AM_LIBADD) -module_detect_la_CFLAGS = $(AM_CFLAGS) - -################################### -# Some minor stuff # -################################### - -suid: polypaudio - chown root $< - chmod u+s $< - -esdcompat.sh: esdcompat.sh.in Makefile - sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ - -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ - -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ - -client.conf: client.conf.in Makefile - sed -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ - -if OS_IS_WIN32 -default.pa: default.pa.win32 - cp $< $@ -else -default.pa: default.pa.in Makefile - sed -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ -endif - -daemon.conf: daemon.conf.in Makefile - sed -e 's,@DLSEARCHPATH\@,$(modlibdir),g' \ - -e 's,@DEFAULT_CONFIG_FILE\@,$(DEFAULT_CONFIG_DIR),g' < $< > $@ - -install-exec-hook: - chown root $(DESTDIR)$(bindir)/polypaudio ; true - chmod u+s $(DESTDIR)$(bindir)/polypaudio - ln -sf pacat $(DESTDIR)$(bindir)/parec diff --git a/polyp/alsa-util.c b/polyp/alsa-util.c deleted file mode 100644 index cc65b8de..00000000 --- a/polyp/alsa-util.c +++ /dev/null @@ -1,124 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "alsa-util.h" -#include "sample.h" -#include "xmalloc.h" -#include "log.h" - -/* Set the hardware parameters of the given ALSA device. Returns the - * selected fragment settings in *period and *period_size */ -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { - int ret = -1; - snd_pcm_uframes_t buffer_size; - snd_pcm_hw_params_t *hwparams = NULL; - static const snd_pcm_format_t format_trans[] = { - [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8, - [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW, - [PA_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW, - [PA_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE, - [PA_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE, - [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE, - [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, - }; - assert(pcm_handle && ss && periods && period_size); - - if (snd_pcm_hw_params_malloc(&hwparams) < 0 || - snd_pcm_hw_params_any(pcm_handle, hwparams) < 0 || - snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0 || - snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format]) < 0 || - snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &ss->rate, NULL) < 0 || - snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels) < 0 || - (*periods > 0 && snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, periods, NULL) < 0) || - (*period_size > 0 && snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL) < 0) || - snd_pcm_hw_params(pcm_handle, hwparams) < 0) - goto finish; - - if (snd_pcm_prepare(pcm_handle) < 0) - goto finish; - - if (snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size) < 0 || - snd_pcm_hw_params_get_period_size(hwparams, period_size, NULL) < 0) - goto finish; - - assert(buffer_size > 0); - assert(*period_size > 0); - *periods = buffer_size / *period_size; - assert(*periods > 0); - - ret = 0; - -finish: - if (hwparams) - snd_pcm_hw_params_free(hwparams); - - return ret; -} - -/* Allocate an IO event for every ALSA poll descriptor for the - * specified ALSA device. Return a pointer to such an array in - * *io_events. Store the length of that array in *n_io_events. Use the - * specified callback function and userdata. The array has to be freed - * with pa_free_io_events(). */ -int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api* m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata) { - unsigned i; - struct pollfd *pfds, *ppfd; - pa_io_event **ios; - assert(pcm_handle && m && io_events && n_io_events && cb); - - *n_io_events = snd_pcm_poll_descriptors_count(pcm_handle); - - pfds = pa_xmalloc(sizeof(struct pollfd) * *n_io_events); - if (snd_pcm_poll_descriptors(pcm_handle, pfds, *n_io_events) < 0) { - pa_xfree(pfds); - return -1; - } - - *io_events = pa_xmalloc(sizeof(void*) * *n_io_events); - - for (i = 0, ios = *io_events, ppfd = pfds; i < *n_io_events; i++, ios++, ppfd++) { - *ios = m->io_new(m, ppfd->fd, - ((ppfd->events & POLLIN) ? PA_IO_EVENT_INPUT : 0) | - ((ppfd->events & POLLOUT) ? PA_IO_EVENT_OUTPUT : 0), cb, userdata); - assert(*ios); - } - - pa_xfree(pfds); - return 0; -} - -/* Free the memory allocated by pa_create_io_events() */ -void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_events, unsigned n_io_events) { - unsigned i; - pa_io_event **ios; - assert(m && io_events); - - for (ios = io_events, i = 0; i < n_io_events; i++, ios++) - m->io_free(*ios); - pa_xfree(io_events); -} diff --git a/polyp/alsa-util.h b/polyp/alsa-util.h deleted file mode 100644 index d180db3e..00000000 --- a/polyp/alsa-util.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef fooalsautilhfoo -#define fooalsautilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "sample.h" -#include "mainloop-api.h" - -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size); - -int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api *m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata); -void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_sources, unsigned n_io_sources); - -#endif diff --git a/polyp/authkey-prop.c b/polyp/authkey-prop.c deleted file mode 100644 index 8657f5a5..00000000 --- a/polyp/authkey-prop.c +++ /dev/null @@ -1,87 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -#include "xmalloc.h" -#include "authkey-prop.h" -#include "props.h" -#include "log.h" - -struct authkey_data { - int ref; - size_t length; -}; - -int pa_authkey_prop_get(pa_core *c, const char *name, void *data, size_t len) { - struct authkey_data *a; - assert(c && name && data && len > 0); - - if (!(a = pa_property_get(c, name))) - return -1; - - assert(a->length == len); - memcpy(data, a+1, len); - return 0; -} - -int pa_authkey_prop_put(pa_core *c, const char *name, const void *data, size_t len) { - struct authkey_data *a; - assert(c && name); - - if (pa_property_get(c, name)) - return -1; - - a = pa_xmalloc(sizeof(struct authkey_data) + len); - a->ref = 1; - a->length = len; - memcpy(a+1, data, len); - - pa_property_set(c, name, a); - - return 0; -} - -void pa_authkey_prop_ref(pa_core *c, const char *name) { - struct authkey_data *a; - assert(c && name); - - a = pa_property_get(c, name); - assert(a && a->ref >= 1); - - a->ref++; -} - -void pa_authkey_prop_unref(pa_core *c, const char *name) { - struct authkey_data *a; - assert(c && name); - - a = pa_property_get(c, name); - assert(a && a->ref >= 1); - - if (!(--a->ref)) { - pa_property_remove(c, name); - pa_xfree(a); - } -} - - diff --git a/polyp/authkey-prop.h b/polyp/authkey-prop.h deleted file mode 100644 index 29b40bb2..00000000 --- a/polyp/authkey-prop.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef fooauthkeyprophfoo -#define fooauthkeyprophfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "core.h" - -/* The authkey-prop uses a central property to store a previously - * loaded cookie in memory. Useful for sharing the same cookie between - * several modules. */ - -/* Return the data of the specified authorization key property. Doesn't alter the refernce count of the key */ -int pa_authkey_prop_get(pa_core *c, const char *name, void *data, size_t len); - -/* Store data in the specified authorization key property. The initial reference count is set to 1 */ -int pa_authkey_prop_put(pa_core *c, const char *name, const void *data, size_t len); - -/* Increase the reference count of the specified authorization key */ -void pa_authkey_prop_ref(pa_core *c, const char *name); - -/* Decrease the reference count of the specified authorization key */ -void pa_authkey_prop_unref(pa_core *c, const char *name); - -#endif diff --git a/polyp/authkey.c b/polyp/authkey.c deleted file mode 100644 index 969f09d9..00000000 --- a/polyp/authkey.c +++ /dev/null @@ -1,201 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "authkey.h" -#include "util.h" -#include "log.h" -#include "random.h" - -/* Generate a new authorization key, store it in file fd and return it in *data */ -static int generate(int fd, void *ret_data, size_t length) { - ssize_t r; - assert(fd >= 0 && ret_data && length); - - pa_random(ret_data, length); - - lseek(fd, 0, SEEK_SET); - ftruncate(fd, 0); - - if ((r = pa_loop_write(fd, ret_data, length)) < 0 || (size_t) r != length) { - pa_log(__FILE__": failed to write cookie file: %s\n", strerror(errno)); - return -1; - } - - return 0; -} - -/* Load an euthorization cookie from file fn and store it in data. If - * the cookie file doesn't exist, create it */ -static int load(const char *fn, void *data, size_t length) { - int fd = -1; - int writable = 1; - int unlock = 0, ret = -1; - ssize_t r; - assert(fn && data && length); - - if ((fd = open(fn, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { - if (errno != EACCES || (fd = open(fn, O_RDONLY)) < 0) { - pa_log(__FILE__": failed to open cookie file '%s': %s\n", fn, strerror(errno)); - goto finish; - } else - writable = 0; - } - - unlock = pa_lock_fd(fd, 1) >= 0; - - if ((r = pa_loop_read(fd, data, length)) < 0) { - pa_log(__FILE__": failed to read cookie file '%s': %s\n", fn, strerror(errno)); - goto finish; - } - - if ((size_t) r != length) { - - if (!writable) { - pa_log(__FILE__": unable to write cookie to read only file\n"); - goto finish; - } - - if (generate(fd, data, length) < 0) - goto finish; - } - - ret = 0; - -finish: - - if (fd >= 0) { - - if (unlock) - pa_lock_fd(fd, 0); - - close(fd); - } - - return ret; -} - -/* Load a cookie from a cookie file. If the file doesn't exist, create it. */ -int pa_authkey_load(const char *path, void *data, size_t length) { - int ret; - - assert(path && data && length); - - ret = load(path, data, length); - - if (ret < 0) - pa_log(__FILE__": Failed to load authorization key '%s': %s\n", path, - (ret == -1) ? strerror(errno) : "file corrupt"); - - return ret; -} - -/* If the specified file path starts with / return it, otherwise - * return path prepended with home directory */ -static const char *normalize_path(const char *fn, char *s, size_t l) { - assert(fn && s && l > 0); - -#ifndef OS_IS_WIN32 - if (fn[0] != '/') { -#else - if (strlen(fn) < 3 || !isalpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') { -#endif - char homedir[PATH_MAX]; - if (!pa_get_home_dir(homedir, sizeof(homedir))) - return NULL; - -#ifndef OS_IS_WIN32 - snprintf(s, l, "%s/%s", homedir, fn); -#else - snprintf(s, l, "%s\\%s", homedir, fn); -#endif - return s; - } - - return fn; -} - -/* Load a cookie from a file in the home directory. If the specified - * path starts with /, use it as absolute path instead. */ -int pa_authkey_load_auto(const char *fn, void *data, size_t length) { - char path[PATH_MAX]; - const char *p; - assert(fn && data && length); - - if (!(p = normalize_path(fn, path, sizeof(path)))) - return -2; - - return pa_authkey_load(p, data, length); -} - -/* Store the specified cookie in the speicified cookie file */ -int pa_authkey_save(const char *fn, const void *data, size_t length) { - int fd = -1; - int unlock = 0, ret = -1; - ssize_t r; - char path[PATH_MAX]; - const char *p; - assert(fn && data && length); - - if (!(p = normalize_path(fn, path, sizeof(path)))) - return -2; - - if ((fd = open(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { - pa_log(__FILE__": failed to open cookie file '%s': %s\n", fn, strerror(errno)); - goto finish; - } - - unlock = pa_lock_fd(fd, 1) >= 0; - - if ((r = pa_loop_write(fd, data, length)) < 0 || (size_t) r != length) { - pa_log(__FILE__": failed to read cookie file '%s': %s\n", fn, strerror(errno)); - goto finish; - } - - ret = 0; - -finish: - - if (fd >= 0) { - - if (unlock) - pa_lock_fd(fd, 0); - - close(fd); - } - - return ret; -} diff --git a/polyp/authkey.h b/polyp/authkey.h deleted file mode 100644 index 81b1a578..00000000 --- a/polyp/authkey.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef fooauthkeyhfoo -#define fooauthkeyhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -int pa_authkey_load(const char *path, void *data, size_t len); -int pa_authkey_load_auto(const char *fn, void *data, size_t length); - -int pa_authkey_save(const char *path, const void *data, size_t length); - -#endif diff --git a/polyp/autoload.c b/polyp/autoload.c deleted file mode 100644 index ff2916cb..00000000 --- a/polyp/autoload.c +++ /dev/null @@ -1,180 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "autoload.h" -#include "module.h" -#include "xmalloc.h" -#include "memchunk.h" -#include "sound-file.h" -#include "log.h" -#include "scache.h" -#include "subscribe.h" - -static void entry_free(pa_autoload_entry *e) { - assert(e); - pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_AUTOLOAD|PA_SUBSCRIPTION_EVENT_REMOVE, PA_INVALID_INDEX); - pa_xfree(e->name); - pa_xfree(e->module); - pa_xfree(e->argument); - pa_xfree(e); -} - -static void entry_remove_and_free(pa_autoload_entry *e) { - assert(e && e->core); - - pa_idxset_remove_by_data(e->core->autoload_idxset, e, NULL); - pa_hashmap_remove(e->core->autoload_hashmap, e->name); - entry_free(e); -} - -static pa_autoload_entry* entry_new(pa_core *c, const char *name) { - pa_autoload_entry *e = NULL; - assert(c && name); - - if (c->autoload_hashmap && (e = pa_hashmap_get(c->autoload_hashmap, name))) - return NULL; - - e = pa_xmalloc(sizeof(pa_autoload_entry)); - e->core = c; - e->name = pa_xstrdup(name); - e->module = e->argument = NULL; - e->in_action = 0; - - if (!c->autoload_hashmap) - c->autoload_hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - assert(c->autoload_hashmap); - - pa_hashmap_put(c->autoload_hashmap, e->name, e); - - if (!c->autoload_idxset) - c->autoload_idxset = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - pa_idxset_put(c->autoload_idxset, e, &e->index); - - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_AUTOLOAD|PA_SUBSCRIPTION_EVENT_NEW, e->index); - - return e; -} - -int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const char*module, const char *argument, uint32_t *idx) { - pa_autoload_entry *e = NULL; - assert(c && name && module && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); - - if (!(e = entry_new(c, name))) - return -1; - - e->module = pa_xstrdup(module); - e->argument = pa_xstrdup(argument); - e->type = type; - - if (idx) - *idx = e->index; - - return 0; -} - -int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type_t type) { - pa_autoload_entry *e; - assert(c && name && type); - - if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type) - return -1; - - entry_remove_and_free(e); - return 0; -} - -int pa_autoload_remove_by_index(pa_core *c, uint32_t idx) { - pa_autoload_entry *e; - assert(c && idx != PA_IDXSET_INVALID); - - if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, idx))) - return -1; - - entry_remove_and_free(e); - return 0; -} - -void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type_t type) { - pa_autoload_entry *e; - pa_module *m; - assert(c && name); - - if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || (e->type != type)) - return; - - if (e->in_action) - return; - - e->in_action = 1; - - if (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE) { - if ((m = pa_module_load(c, e->module, e->argument))) - m->auto_unload = 1; - } - - e->in_action = 0; -} - -static void free_func(void *p, PA_GCC_UNUSED void *userdata) { - pa_autoload_entry *e = p; - pa_idxset_remove_by_data(e->core->autoload_idxset, e, NULL); - entry_free(e); -} - -void pa_autoload_free(pa_core *c) { - if (c->autoload_hashmap) { - pa_hashmap_free(c->autoload_hashmap, free_func, NULL); - c->autoload_hashmap = NULL; - } - - if (c->autoload_idxset) { - pa_idxset_free(c->autoload_idxset, NULL, NULL); - c->autoload_idxset = NULL; - } -} - -const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type_t type) { - pa_autoload_entry *e; - assert(c && name); - - if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type) - return NULL; - - return e; -} - -const pa_autoload_entry* pa_autoload_get_by_index(pa_core *c, uint32_t idx) { - pa_autoload_entry *e; - assert(c && idx != PA_IDXSET_INVALID); - - if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, idx))) - return NULL; - - return e; -} diff --git a/polyp/autoload.h b/polyp/autoload.h deleted file mode 100644 index 7350c16a..00000000 --- a/polyp/autoload.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef fooautoloadhfoo -#define fooautoloadhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "namereg.h" - -/* Using the autoloading facility, modules by be loaded on-demand and - * synchronously. The user may register a "ghost sink" or "ghost - * source". Whenever this sink/source is requested but not available a - * specified module is loaded. */ - -/* An autoload entry, or "ghost" sink/source */ -typedef struct pa_autoload_entry { - pa_core *core; - uint32_t index; - char *name; - pa_namereg_type_t type; /* Type of the autoload entry */ - int in_action; /* Currently loaded */ - char *module, *argument; -} pa_autoload_entry; - -/* Add a new autoload entry of the given time, with the speicified - * sink/source name, module name and argument. Return the entry's - * index in *index */ -int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const char*module, const char *argument, uint32_t *idx); - -/* Free all autoload entries */ -void pa_autoload_free(pa_core *c); -int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type_t type); -int pa_autoload_remove_by_index(pa_core *c, uint32_t idx); - -/* Request an autoload entry by its name, effectively causing a module to be loaded */ -void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type_t type); - -const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type_t type); -const pa_autoload_entry* pa_autoload_get_by_index(pa_core *c, uint32_t idx); - -#endif diff --git a/polyp/caps.c b/polyp/caps.c deleted file mode 100644 index 4ecb5848..00000000 --- a/polyp/caps.c +++ /dev/null @@ -1,131 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#ifdef HAVE_SYS_CAPABILITY_H -#include -#endif - -#include "log.h" -#include "caps.h" - -#ifdef HAVE_GETUID - -/* Drop root rights when called SUID root */ -void pa_drop_root(void) { - uid_t uid = getuid(); - - if (uid == 0 || geteuid() != 0) - return; - - pa_log_info(__FILE__": dropping root rights.\n"); - -#if defined(HAVE_SETRESUID) - setresuid(uid, uid, uid); -#elif defined(HAVE_SETREUID) - setreuid(uid, uid); -#else - setuid(uid); - seteuid(uid); -#endif -} - -#else - -void pa_drop_root(void) { -} - -#endif - -#ifdef HAVE_SYS_CAPABILITY_H - -/* Limit capabilities set to CAPSYS_NICE */ -int pa_limit_caps(void) { - int r = -1; - cap_t caps; - cap_value_t nice_cap = CAP_SYS_NICE; - - caps = cap_init(); - assert(caps); - - cap_clear(caps); - - cap_set_flag(caps, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET); - cap_set_flag(caps, CAP_PERMITTED, 1, &nice_cap, CAP_SET); - - if (cap_set_proc(caps) < 0) - goto fail; - - pa_log_info(__FILE__": dropped capabilities successfully.\n"); - - r = 0; - -fail: - cap_free (caps); - - return r; -} - -/* Drop all capabilities, effectively becoming a normal user */ -int pa_drop_caps(void) { - cap_t caps; - int r = -1; - - caps = cap_init(); - assert(caps); - - cap_clear(caps); - - if (cap_set_proc(caps) < 0) { - pa_log(__FILE__": failed to drop capabilities: %s\n", strerror(errno)); - goto fail; - } - - r = 0; - -fail: - cap_free (caps); - - return r; -} - -#else - -/* NOOPs in case capabilities are not available. */ -int pa_limit_caps(void) { - return 0; -} - -int pa_drop_caps(void) { - pa_drop_root(); - return 0; -} - -#endif - diff --git a/polyp/caps.h b/polyp/caps.h deleted file mode 100644 index 3bb861d1..00000000 --- a/polyp/caps.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef foocapshfoo -#define foocapshfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -void pa_drop_root(void); -int pa_limit_caps(void); -int pa_drop_caps(void); - -#endif diff --git a/polyp/cdecl.h b/polyp/cdecl.h deleted file mode 100644 index d51ae026..00000000 --- a/polyp/cdecl.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef foocdeclhfoo -#define foocdeclhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -/** \file - * C++ compatibility support */ - -#ifdef __cplusplus -/** If using C++ this macro enables C mode, otherwise does nothing */ -#define PA_C_DECL_BEGIN extern "C" { -/** If using C++ this macros switches back to C++ mode, otherwise does nothing */ -#define PA_C_DECL_END } - -#else -/** If using C++ this macro enables C mode, otherwise does nothing */ -#define PA_C_DECL_BEGIN -/** If using C++ this macros switches back to C++ mode, otherwise does nothing */ -#define PA_C_DECL_END - -#endif - -#endif diff --git a/polyp/channelmap.c b/polyp/channelmap.c deleted file mode 100644 index 7bfd21e6..00000000 --- a/polyp/channelmap.c +++ /dev/null @@ -1,202 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "channelmap.h" - -pa_channel_map* pa_channel_map_init(pa_channel_map *m) { - unsigned c; - assert(m); - - m->channels = 0; - - for (c = 0; c < PA_CHANNELS_MAX; c++) - m->map[c] = PA_CHANNEL_POSITION_INVALID; - - return m; -} - -pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m) { - assert(m); - - pa_channel_map_init(m); - - m->channels = 1; - m->map[0] = PA_CHANNEL_POSITION_MONO; - return m; -} - -pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m) { - assert(m); - - pa_channel_map_init(m); - - m->channels = 2; - m->map[0] = PA_CHANNEL_POSITION_LEFT; - m->map[1] = PA_CHANNEL_POSITION_RIGHT; - return m; -} - -pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels) { - assert(m); - assert(channels > 0); - assert(channels <= PA_CHANNELS_MAX); - - pa_channel_map_init(m); - - m->channels = channels; - - switch (channels) { - case 1: - m->map[0] = PA_CHANNEL_POSITION_MONO; - return m; - - case 8: - m->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; - m->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; - /* Fall through */ - - case 6: - m->map[5] = PA_CHANNEL_POSITION_LFE; - /* Fall through */ - - case 5: - m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; - /* Fall through */ - - case 4: - m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT; - m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; - /* Fall through */ - - case 2: - m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - return m; - - default: - return NULL; - } -} - -const char* pa_channel_position_to_string(pa_channel_position_t pos) { - - const char *const table[] = { - [PA_CHANNEL_POSITION_MONO] = "mono", - - [PA_CHANNEL_POSITION_FRONT_CENTER] = "front-center", - [PA_CHANNEL_POSITION_FRONT_LEFT] = "front-left", - [PA_CHANNEL_POSITION_FRONT_RIGHT] = "front-right", - - [PA_CHANNEL_POSITION_REAR_CENTER] = "rear-center", - [PA_CHANNEL_POSITION_REAR_LEFT] = "rear-left", - [PA_CHANNEL_POSITION_REAR_RIGHT] = "rear-right", - - [PA_CHANNEL_POSITION_LFE] = "lfe", - - [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = "front-left-of-center", - [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = "front-right-of-center", - - [PA_CHANNEL_POSITION_SIDE_LEFT] = "side-left", - [PA_CHANNEL_POSITION_SIDE_RIGHT] = "side-right", - - [PA_CHANNEL_POSITION_AUX1] = "aux1", - [PA_CHANNEL_POSITION_AUX2] = "aux2", - [PA_CHANNEL_POSITION_AUX3] = "aux3", - [PA_CHANNEL_POSITION_AUX4] = "aux4", - [PA_CHANNEL_POSITION_AUX5] = "aux5", - [PA_CHANNEL_POSITION_AUX6] = "aux6", - [PA_CHANNEL_POSITION_AUX7] = "aux7", - [PA_CHANNEL_POSITION_AUX8] = "aux8", - [PA_CHANNEL_POSITION_AUX9] = "aux9", - [PA_CHANNEL_POSITION_AUX10] = "aux10", - [PA_CHANNEL_POSITION_AUX11] = "aux11", - [PA_CHANNEL_POSITION_AUX12] = "aux12" - }; - - if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX) - return NULL; - - return table[pos]; -} - -int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) { - unsigned c; - - assert(a); - assert(b); - - if (a->channels != b->channels) - return 0; - - for (c = 0; c < a->channels; c++) - if (a->map[c] != b->map[c]) - return 0; - - return 1; -} - -char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) { - unsigned channel; - int first = 1; - char *e; - - assert(s); - assert(l > 0); - assert(map); - - *(e = s) = 0; - - for (channel = 0; channel < map->channels && l > 1; channel++) { - l -= snprintf(e, l, "%s%u:%s", - first ? "" : " ", - channel, - pa_channel_position_to_string(map->map[channel])); - - e = strchr(e, 0); - first = 0; - } - - return s; -} - -int pa_channel_map_valid(const pa_channel_map *map) { - unsigned c; - - assert(map); - - if (map->channels <= 0 || map->channels > PA_CHANNELS_MAX) - return 0; - - for (c = 0; c < map->channels; c++) - if (map->map[c] < 0 ||map->map[c] >= PA_CHANNEL_POSITION_MAX) - return 0; - - return 1; -} diff --git a/polyp/channelmap.h b/polyp/channelmap.h deleted file mode 100644 index 0b9f6e26..00000000 --- a/polyp/channelmap.h +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef foochannelmaphfoo -#define foochannelmaphfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -/** \file - * Constants and routines for channel mapping handling */ - -PA_C_DECL_BEGIN - -typedef enum { - PA_CHANNEL_POSITION_INVALID = -1, - PA_CHANNEL_POSITION_MONO = 0, - - PA_CHANNEL_POSITION_LEFT, - PA_CHANNEL_POSITION_RIGHT, - - PA_CHANNEL_POSITION_FRONT_CENTER, - PA_CHANNEL_POSITION_FRONT_LEFT = PA_CHANNEL_POSITION_LEFT, - PA_CHANNEL_POSITION_FRONT_RIGHT = PA_CHANNEL_POSITION_RIGHT, - - PA_CHANNEL_POSITION_REAR_CENTER, - PA_CHANNEL_POSITION_REAR_LEFT, - PA_CHANNEL_POSITION_REAR_RIGHT, - - PA_CHANNEL_POSITION_LFE, - PA_CHANNEL_POSITION_SUBWOOFER = PA_CHANNEL_POSITION_LFE, - - PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, - PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, - - PA_CHANNEL_POSITION_SIDE_LEFT, - PA_CHANNEL_POSITION_SIDE_RIGHT, - - PA_CHANNEL_POSITION_AUX0, - PA_CHANNEL_POSITION_AUX1, - PA_CHANNEL_POSITION_AUX2, - PA_CHANNEL_POSITION_AUX3, - PA_CHANNEL_POSITION_AUX4, - PA_CHANNEL_POSITION_AUX5, - PA_CHANNEL_POSITION_AUX6, - PA_CHANNEL_POSITION_AUX7, - PA_CHANNEL_POSITION_AUX8, - PA_CHANNEL_POSITION_AUX9, - PA_CHANNEL_POSITION_AUX10, - PA_CHANNEL_POSITION_AUX11, - PA_CHANNEL_POSITION_AUX12, - PA_CHANNEL_POSITION_AUX13, - PA_CHANNEL_POSITION_AUX14, - PA_CHANNEL_POSITION_AUX15, - - PA_CHANNEL_POSITION_MAX -} pa_channel_position_t; - -typedef struct pa_channel_map { - uint8_t channels; - pa_channel_position_t map[PA_CHANNELS_MAX]; -} pa_channel_map; - -pa_channel_map* pa_channel_map_init(pa_channel_map *m); -pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m); -pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m); -pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels); - -const char* pa_channel_position_to_string(pa_channel_position_t pos); - -#define PA_CHANNEL_MAP_SNPRINT_MAX 64 -char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map); - -int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b); - -int pa_channel_map_valid(const pa_channel_map *map); - -PA_C_DECL_END - -#endif diff --git a/polyp/cli-command.c b/polyp/cli-command.c deleted file mode 100644 index f6192bf8..00000000 --- a/polyp/cli-command.c +++ /dev/null @@ -1,834 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "cli-command.h" -#include "module.h" -#include "sink.h" -#include "source.h" -#include "client.h" -#include "sink-input.h" -#include "source-output.h" -#include "tokenizer.h" -#include "strbuf.h" -#include "namereg.h" -#include "cli-text.h" -#include "scache.h" -#include "sample-util.h" -#include "sound-file.h" -#include "play-memchunk.h" -#include "autoload.h" -#include "xmalloc.h" -#include "sound-file-stream.h" -#include "props.h" -#include "util.h" - -struct command { - const char *name; - int (*proc) (pa_core *c, pa_tokenizer*t, pa_strbuf *buf, int *fail); - const char *help; - unsigned args; -}; - -#define INCLUDE_META ".include" -#define FAIL_META ".fail" -#define NOFAIL_META ".nofail" - -/* Prototypes for all available commands */ -static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); - - -/* A method table for all available commands */ - -static const struct command commands[] = { - { "exit", pa_cli_command_exit, "Terminate the daemon", 1 }, - { "help", pa_cli_command_help, "Show this help", 1 }, - { "list-modules", pa_cli_command_modules, "List loaded modules", 1 }, - { "list-sinks", pa_cli_command_sinks, "List loaded sinks", 1 }, - { "list-sources", pa_cli_command_sources, "List loaded sources", 1 }, - { "list-clients", pa_cli_command_clients, "List loaded clients", 1 }, - { "list-sink-inputs", pa_cli_command_sink_inputs, "List sink inputs", 1 }, - { "list-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-module", pa_cli_command_load, "Load a module (args: name, arguments)", 3}, - { "unload-module", pa_cli_command_unload, "Unload a module (args: index)", 2}, - { "set-sink-volume", pa_cli_command_sink_volume, "Set the volume of a sink (args: index|name, volume)", 3}, - { "set-sink-input-volume", pa_cli_command_sink_input_volume, "Set the volume of a sink input (args: index|name, volume)", 3}, - { "set-default-sink", pa_cli_command_sink_default, "Set the default sink (args: index|name)", 2}, - { "set-default-source", 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}, - { "list-samples", pa_cli_command_scache_list, "List all entries in the sample cache", 1}, - { "play-sample", pa_cli_command_scache_play, "Play a sample from the sample cache (args: name, sink|index)", 3}, - { "remove-sample", pa_cli_command_scache_remove, "Remove a sample from the sample cache (args: name)", 2}, - { "load-sample", pa_cli_command_scache_load, "Load a sound file into the sample cache (args: name, filename)", 3}, - { "load-sample-lazy", pa_cli_command_scache_load, "Lazily load a sound file into the sample cache (args: name, filename)", 3}, - { "load-sample-dir-lazy", pa_cli_command_scache_load_dir, "Lazily load all files in a directory into the sample cache (args: pathname)", 2}, - { "play-file", pa_cli_command_play_file, "Play a sound file (args: filename, sink|index)", 3}, - { "list-autoload", pa_cli_command_autoload_list, "List autoload entries", 1}, - { "add-autoload-sink", pa_cli_command_autoload_add, "Add autoload entry for a sink (args: sink, module name, arguments)", 4}, - { "add-autoload-source", pa_cli_command_autoload_add, "Add autoload entry for a source (args: source, module name, arguments)", 4}, - { "remove-autoload-sink", pa_cli_command_autoload_remove, "Remove autoload entry for a sink (args: name)", 2}, - { "remove-autoload-source", pa_cli_command_autoload_remove, "Remove autoload entry for a source (args: name)", 2}, - { "dump", pa_cli_command_dump, "Dump daemon configuration", 1}, - { "list-props", pa_cli_command_list_props, NULL, 1}, - { 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) { - uint32_t idx; - - if (pa_atou(n, &idx) < 0) - return (uint32_t) PA_IDXSET_INVALID; - - return idx; -} - -static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, PA_GCC_UNUSED pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - assert(c && c->mainloop && t); - c->mainloop->quit(c->mainloop, 0); - return 0; -} - -static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - 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, " %-25s %s\n", command->name, command->help); - return 0; -} - -static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - char *s; - assert(c && t); - s = pa_module_list_to_string(c); - assert(s); - pa_strbuf_puts(buf, s); - pa_xfree(s); - return 0; -} - -static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - char *s; - assert(c && t); - s = pa_client_list_to_string(c); - assert(s); - pa_strbuf_puts(buf, s); - pa_xfree(s); - return 0; -} - -static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - char *s; - assert(c && t); - s = pa_sink_list_to_string(c); - assert(s); - pa_strbuf_puts(buf, s); - pa_xfree(s); - return 0; -} - -static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - char *s; - assert(c && t); - s = pa_source_list_to_string(c); - assert(s); - pa_strbuf_puts(buf, s); - pa_xfree(s); - return 0; -} - -static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - char *s; - assert(c && t); - s = pa_sink_input_list_to_string(c); - assert(s); - pa_strbuf_puts(buf, s); - pa_xfree(s); - return 0; -} - -static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - char *s; - assert(c && t); - s = pa_source_output_list_to_string(c); - assert(s); - pa_strbuf_puts(buf, s); - pa_xfree(s); - return 0; -} - -static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - char s[256]; - assert(c && t); - - pa_bytes_snprint(s, sizeof(s), c->memblock_stat->total_size); - pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n", - c->memblock_stat->total, - s); - - pa_bytes_snprint(s, sizeof(s), c->memblock_stat->allocated_size); - pa_strbuf_printf(buf, "Memory blocks allocated during the whole lifetime: %u, size: %s.\n", - c->memblock_stat->allocated, - s); - - pa_bytes_snprint(s, sizeof(s), pa_scache_total_size(c)); - pa_strbuf_printf(buf, "Total sample cache size: %s.\n", s); - - pa_sample_spec_snprint(s, sizeof(s), &c->default_sample_spec); - pa_strbuf_printf(buf, "Default sample spec: %s\n", s); - - pa_strbuf_printf(buf, "Default sink name: %s\n" - "Default source name: %s\n", - pa_namereg_get_default_sink_name(c), - pa_namereg_get_default_source_name(c)); - - return 0; -} - -static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { - assert(c && t); - pa_cli_command_stat(c, t, buf, fail); - pa_cli_command_modules(c, t, buf, fail); - pa_cli_command_sinks(c, t, buf, fail); - pa_cli_command_sources(c, t, buf, fail); - pa_cli_command_clients(c, t, buf, fail); - pa_cli_command_sink_inputs(c, t, buf, fail); - pa_cli_command_source_outputs(c, t, buf, fail); - pa_cli_command_scache_list(c, t, buf, fail); - pa_cli_command_autoload_list(c, t, buf, fail); - return 0; -} - -static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - pa_module *m; - const char *name; - 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; - } - - return 0; -} - -static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - pa_module *m; - uint32_t idx; - 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; - } - - idx = (uint32_t) strtoul(i, &e, 10); - if (*e || !(m = pa_idxset_get_by_index(c->modules, idx))) { - pa_strbuf_puts(buf, "Invalid module index.\n"); - return -1; - } - - pa_module_unload_request(m); - return 0; -} - -static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - const char *n, *v; - pa_sink *sink; - uint32_t volume; - pa_cvolume cvolume; - - 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; - } - - if (pa_atou(v, &volume) < 0) { - pa_strbuf_puts(buf, "Failed to parse volume.\n"); - return -1; - } - - if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) { - pa_strbuf_puts(buf, "No sink found by this name or index.\n"); - return -1; - } - - pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume); - pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &cvolume); - return 0; -} - -static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - const char *n, *v; - pa_sink_input *si; - pa_volume_t volume; - pa_cvolume cvolume; - uint32_t idx; - - 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 ((idx = 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; - } - - if (pa_atou(v, &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) idx))) { - pa_strbuf_puts(buf, "No sink input found with this index.\n"); - return -1; - } - - pa_cvolume_set(&cvolume, si->sample_spec.channels, volume); - pa_sink_input_set_volume(si, &cvolume); - return 0; -} - -static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - const char *n; - 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; - } - - pa_namereg_set_default(c, n, PA_NAMEREG_SINK); - return 0; -} - -static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - const char *n; - 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; - } - - pa_namereg_set_default(c, n, PA_NAMEREG_SOURCE); - return 0; -} - -static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - const char *n; - pa_client *client; - uint32_t idx; - 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 ((idx = 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, idx))) { - 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(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - const char *n; - pa_sink_input *sink_input; - uint32_t idx; - 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 ((idx = 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, idx))) { - 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(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - const char *n; - pa_source_output *source_output; - uint32_t idx; - 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 ((idx = 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, idx))) { - pa_strbuf_puts(buf, "No source output found by this index.\n"); - return -1; - } - - pa_source_output_kill(source_output); - return 0; -} - -static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - char *s; - assert(c && t); - s = pa_scache_list_to_string(c); - assert(s); - pa_strbuf_puts(buf, s); - pa_xfree(s); - return 0; -} - -static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { - const char *n, *sink_name; - pa_sink *sink; - assert(c && t && buf && fail); - - if (!(n = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) { - pa_strbuf_puts(buf, "You need to specify a sample name and a sink name.\n"); - return -1; - } - - if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) { - pa_strbuf_puts(buf, "No sink by that name.\n"); - return -1; - } - - if (pa_scache_play_item(c, n, sink, NULL) < 0) { - pa_strbuf_puts(buf, "Failed to play sample.\n"); - return -1; - } - - return 0; -} - -static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { - const char *n; - assert(c && t && buf && fail); - - if (!(n = pa_tokenizer_get(t, 1))) { - pa_strbuf_puts(buf, "You need to specify a sample name.\n"); - return -1; - } - - if (pa_scache_remove_item(c, n) < 0) { - pa_strbuf_puts(buf, "Failed to remove sample.\n"); - return -1; - } - - return 0; -} - -static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { - const char *fname, *n; - int r; - assert(c && t && buf && fail); - - if (!(fname = pa_tokenizer_get(t, 2)) || !(n = pa_tokenizer_get(t, 1))) { - pa_strbuf_puts(buf, "You need to specify a file name and a sample name.\n"); - return -1; - } - - if (strstr(pa_tokenizer_get(t, 0), "lazy")) - r = pa_scache_add_file_lazy(c, n, fname, NULL); - else - r = pa_scache_add_file(c, n, fname, NULL); - - if (r < 0) - pa_strbuf_puts(buf, "Failed to load sound file.\n"); - - return 0; -} - -static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { - const char *pname; - assert(c && t && buf && fail); - - if (!(pname = pa_tokenizer_get(t, 1))) { - pa_strbuf_puts(buf, "You need to specify a path name.\n"); - return -1; - } - - if (pa_scache_add_directory_lazy(c, pname) < 0) { - pa_strbuf_puts(buf, "Failed to load directory.\n"); - return -1; - } - - return 0; -} - -static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { - const char *fname, *sink_name; - pa_sink *sink; - assert(c && t && buf && fail); - - if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) { - pa_strbuf_puts(buf, "You need to specify a file name and a sink name.\n"); - return -1; - } - - if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) { - pa_strbuf_puts(buf, "No sink by that name.\n"); - return -1; - } - - - return pa_play_file(sink, fname, NULL); -} - -static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { - const char *a, *b; - assert(c && t && buf && fail); - - if (!(a = pa_tokenizer_get(t, 1)) || !(b = pa_tokenizer_get(t, 2))) { - pa_strbuf_puts(buf, "You need to specify a device name, a filename or a module name and optionally module arguments\n"); - return -1; - } - - pa_autoload_add(c, a, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, b, pa_tokenizer_get(t, 3), NULL); - - return 0; -} - -static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { - const char *name; - assert(c && t && buf && fail); - - if (!(name = pa_tokenizer_get(t, 1))) { - pa_strbuf_puts(buf, "You need to specify a device name\n"); - return -1; - } - - if (pa_autoload_remove_by_name(c, name, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE) < 0) { - pa_strbuf_puts(buf, "Failed to remove autload entry\n"); - return -1; - } - - return 0; -} - -static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - char *s; - assert(c && t); - s = pa_autoload_list_to_string(c); - assert(s); - pa_strbuf_puts(buf, s); - pa_xfree(s); - return 0; -} - -static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - assert(c && t); - pa_property_dump(c, buf); - return 0; -} - -static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - pa_module *m; - pa_sink *s; - int nl; - const char *p; - uint32_t idx; - char txt[256]; - time_t now; - void *i; - pa_autoload_entry *a; - - assert(c && t); - - time(&now); - -#ifdef HAVE_CTIME_R - pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime_r(&now, txt)); -#else - pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now)); -#endif - - - for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) { - if (m->auto_unload) - continue; - - pa_strbuf_printf(buf, "load-module %s", m->name); - - if (m->argument) - pa_strbuf_printf(buf, " %s", m->argument); - - pa_strbuf_puts(buf, "\n"); - } - - nl = 0; - - for (s = pa_idxset_first(c->sinks, &idx); s; s = pa_idxset_next(c->sinks, &idx)) { - if (s->owner && s->owner->auto_unload) - continue; - - if (!nl) { - pa_strbuf_puts(buf, "\n"); - nl = 1; - } - - pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", s->name, pa_cvolume_avg(pa_sink_get_volume(s, PA_MIXER_HARDWARE))); - } - - - if (c->autoload_hashmap) { - nl = 0; - - i = NULL; - while ((a = pa_hashmap_iterate(c->autoload_hashmap, &i, NULL))) { - - if (!nl) { - pa_strbuf_puts(buf, "\n"); - nl = 1; - } - - pa_strbuf_printf(buf, "add-autoload-%s %s %s", a->type == PA_NAMEREG_SINK ? "sink" : "source", a->name, a->module); - - if (a->argument) - pa_strbuf_printf(buf, " %s", a->argument); - - pa_strbuf_puts(buf, "\n"); - } - } - - nl = 0; - - if ((p = pa_namereg_get_default_sink_name(c))) { - if (!nl) { - pa_strbuf_puts(buf, "\n"); - nl = 1; - } - pa_strbuf_printf(buf, "set-default-sink %s\n", p); - } - - if ((p = pa_namereg_get_default_source_name(c))) { - if (!nl) { - pa_strbuf_puts(buf, "\n"); - nl = 1; - } - pa_strbuf_printf(buf, "set-default-source %s\n", p); - } - - pa_strbuf_puts(buf, "\n### EOF\n"); - - return 0; -} - - -int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { - const char *cs; - - cs = s+strspn(s, whitespace); - - if (*cs == '#' || !*cs) - return 0; - else if (*cs == '.') { - if (!strcmp(cs, FAIL_META)) - *fail = 1; - else if (!strcmp(cs, NOFAIL_META)) - *fail = 0; - else { - size_t l; - 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) < 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; - pa_tokenizer *t = pa_tokenizer_new(cs, command->args); - assert(t); - ret = command->proc(c, t, buf, fail); - 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(pa_core *c, const char *fn, pa_strbuf *buf, int *fail) { - 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; - } - - while (fgets(line, sizeof(line), f)) { - char *e = line + strcspn(line, linebreak); - *e = 0; - - if (pa_cli_command_execute_line(c, line, buf, fail) < 0 && *fail) - goto fail; - } - - ret = 0; - -fail: - if (f) - fclose(f); - - return ret; -} - -int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { - const char *p; - assert(c && s && buf && fail); - - p = s; - while (*p) { - size_t l = strcspn(p, linebreak); - char *line = pa_xstrndup(p, l); - - if (pa_cli_command_execute_line(c, line, buf, fail) < 0&& *fail) { - pa_xfree(line); - return -1; - } - pa_xfree(line); - - p += l; - p += strspn(p, linebreak); - } - - return 0; -} diff --git a/polyp/cli-command.h b/polyp/cli-command.h deleted file mode 100644 index 78b8d5c6..00000000 --- a/polyp/cli-command.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef fooclicommandhfoo -#define fooclicommandhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "strbuf.h" -#include "core.h" - -/* Execute a single CLI command. Write the results to the string - * buffer *buf. If *fail is non-zero the function will return -1 when - * one or more of the executed commands failed. *fail - * may be modified by the function call. */ -int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail); - -/* Execute a whole file of CLI commands */ -int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int *fail); - -/* Split the specified string into lines and run pa_cli_command_execute_line() for each. */ -int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail); - -#endif diff --git a/polyp/cli-text.c b/polyp/cli-text.c deleted file mode 100644 index 328aca4c..00000000 --- a/polyp/cli-text.c +++ /dev/null @@ -1,385 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "cli-text.h" -#include "module.h" -#include "client.h" -#include "sink.h" -#include "source.h" -#include "sink-input.h" -#include "source-output.h" -#include "strbuf.h" -#include "sample-util.h" -#include "scache.h" -#include "autoload.h" -#include "xmalloc.h" -#include "volume.h" - -char *pa_module_list_to_string(pa_core *c) { - pa_strbuf *s; - pa_module *m; - uint32_t idx = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_size(c->modules)); - - for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) - pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\targument: <%s>\n\tused: %i\n\tauto unload: %s\n", m->index, m->name, m->argument, m->n_used, m->auto_unload ? "yes" : "no"); - - return pa_strbuf_tostring_free(s); -} - -char *pa_client_list_to_string(pa_core *c) { - pa_strbuf *s; - pa_client *client; - uint32_t idx = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u client(s) logged in.\n", pa_idxset_size(c->clients)); - - for (client = pa_idxset_first(c->clients, &idx); client; client = pa_idxset_next(c->clients, &idx)) { - pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\tdriver: <%s>\n", client->index, client->name, client->driver); - - if (client->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", client->owner->index); - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_sink_list_to_string(pa_core *c) { - pa_strbuf *s; - pa_sink *sink; - uint32_t idx = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_size(c->sinks)); - - for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) { - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - - pa_strbuf_printf( - s, - " %c index: %u\n" - "\tname: <%s>\n" - "\tdriver: <%s>\n" - "\tvolume: <%s>\n" - "\tlatency: <%0.0f usec>\n" - "\tmonitor_source: <%u>\n" - "\tsample spec: <%s>\n" - "\tchannel map: <%s>\n", - c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ', - sink->index, sink->name, - sink->driver, - pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, PA_MIXER_HARDWARE)), - (double) pa_sink_get_latency(sink), - sink->monitor_source->index, - pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec), - pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map)); - - if (sink->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", sink->owner->index); - if (sink->description) - pa_strbuf_printf(s, "\tdescription: <%s>\n", sink->description); - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_source_list_to_string(pa_core *c) { - pa_strbuf *s; - pa_source *source; - uint32_t idx = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_size(c->sources)); - - for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) { - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - - - pa_strbuf_printf( - s, - " %c index: %u\n" - "\tname: <%s>\n" - "\tdriver: <%s>\n" - "\tlatency: <%0.0f usec>\n" - "\tsample spec: <%s>\n" - "\tchannel map: <%s>\n", - c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ', - source->index, - source->name, - source->driver, - (double) pa_source_get_latency(source), - pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec), - pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map)); - - if (source->monitor_of) - pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index); - if (source->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", source->owner->index); - if (source->description) - pa_strbuf_printf(s, "\tdescription: <%s>\n", source->description); - } - - return pa_strbuf_tostring_free(s); -} - - -char *pa_source_output_list_to_string(pa_core *c) { - pa_strbuf *s; - pa_source_output *o; - uint32_t idx = PA_IDXSET_INVALID; - static const char* const state_table[] = { - "RUNNING", - "CORKED", - "DISCONNECTED" - }; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_size(c->source_outputs)); - - for (o = pa_idxset_first(c->source_outputs, &idx); o; o = pa_idxset_next(c->source_outputs, &idx)) { - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - - assert(o->source); - - pa_strbuf_printf( - s, - " index: %u\n" - "\tname: '%s'\n" - "\tdriver: <%s>\n" - "\tstate: %s\n" - "\tsource: <%u> '%s'\n" - "\tsample spec: <%s>\n" - "\tchannel map: <%s>\n" - "\tresample method: %s\n", - o->index, - o->name, - o->driver, - state_table[o->state], - o->source->index, o->source->name, - pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec), - pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map), - pa_resample_method_to_string(pa_source_output_get_resample_method(o))); - if (o->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", o->owner->index); - if (o->client) - pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", o->client->index, o->client->name); - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_sink_input_list_to_string(pa_core *c) { - pa_strbuf *s; - pa_sink_input *i; - uint32_t idx = PA_IDXSET_INVALID; - static const char* const state_table[] = { - "RUNNING", - "CORKED", - "DISCONNECTED" - }; - - assert(c); - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_size(c->sink_inputs)); - - for (i = pa_idxset_first(c->sink_inputs, &idx); i; i = pa_idxset_next(c->sink_inputs, &idx)) { - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - - assert(i->sink); - - pa_strbuf_printf( - s, - " index: %u\n" - "\tname: <%s>\n" - "\tdriver: <%s>\n" - "\tstate: %s\n" - "\tsink: <%u> '%s'\n" - "\tvolume: <%s>\n" - "\tlatency: <%0.0f usec>\n" - "\tsample spec: <%s>\n" - "\tchannel map: <%s>\n" - "\tresample method: %s\n", - i->index, - i->name, - i->driver, - state_table[i->state], - i->sink->index, i->sink->name, - pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)), - (double) pa_sink_input_get_latency(i), - pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec), - pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), - pa_resample_method_to_string(pa_sink_input_get_resample_method(i))); - - if (i->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", i->owner->index); - if (i->client) - pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", i->client->index, i->client->name); - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_scache_list_to_string(pa_core *c) { - pa_strbuf *s; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u cache entries available.\n", c->scache ? pa_idxset_size(c->scache) : 0); - - if (c->scache) { - pa_scache_entry *e; - uint32_t idx = PA_IDXSET_INVALID; - - for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) { - double l = 0; - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = "n/a", cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - - if (e->memchunk.memblock) { - pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec); - pa_channel_map_snprint(cm, sizeof(cm), &e->channel_map); - l = (double) e->memchunk.length / pa_bytes_per_second(&e->sample_spec); - } - - pa_strbuf_printf( - s, - " name: <%s>\n" - "\tindex: <%u>\n" - "\tsample spec: <%s>\n" - "\tchannel map: <%s>\n" - "\tlength: <%u>\n" - "\tduration: <%0.1fs>\n" - "\tvolume: <%s>\n" - "\tlazy: %s\n" - "\tfilename: %s\n", - e->name, - e->index, - ss, - cm, - e->memchunk.memblock ? e->memchunk.length : 0, - l, - pa_cvolume_snprint(cv, sizeof(cv), &e->volume), - e->lazy ? "yes" : "no", - e->filename ? e->filename : "n/a"); - } - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_autoload_list_to_string(pa_core *c) { - pa_strbuf *s; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u autoload entries available.\n", c->autoload_hashmap ? pa_hashmap_size(c->autoload_hashmap) : 0); - - if (c->autoload_hashmap) { - pa_autoload_entry *e; - void *state = NULL; - - while ((e = pa_hashmap_iterate(c->autoload_hashmap, &state, NULL))) { - pa_strbuf_printf( - s, " name: <%s>\n\ttype: <%s>\n\tindex: <%u>\n\tmodule_name: <%s>\n\targuments: <%s>\n", - e->name, - e->type == PA_NAMEREG_SOURCE ? "source" : "sink", - e->index, - e->module, - e->argument); - - } - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_full_status_string(pa_core *c) { - pa_strbuf *s; - int i; - - s = pa_strbuf_new(); - - for (i = 0; i < 8; i++) { - char *t = NULL; - - switch (i) { - case 0: - t = pa_sink_list_to_string(c); - break; - case 1: - t = pa_source_list_to_string(c); - break; - case 2: - t = pa_sink_input_list_to_string(c); - break; - case 3: - t = pa_source_output_list_to_string(c); - break; - case 4: - t = pa_client_list_to_string(c); - break; - case 5: - t = pa_module_list_to_string(c); - break; - case 6: - t = pa_scache_list_to_string(c); - break; - case 7: - t = pa_autoload_list_to_string(c); - break; - } - - pa_strbuf_puts(s, t); - pa_xfree(t); - } - - return pa_strbuf_tostring_free(s); -} diff --git a/polyp/cli-text.h b/polyp/cli-text.h deleted file mode 100644 index 7a1a0361..00000000 --- a/polyp/cli-text.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef fooclitexthfoo -#define fooclitexthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "core.h" - -/* Some functions to generate pretty formatted listings of - * entities. The returned strings have to be freed manually. */ - -char *pa_sink_input_list_to_string(pa_core *c); -char *pa_source_output_list_to_string(pa_core *c); -char *pa_sink_list_to_string(pa_core *core); -char *pa_source_list_to_string(pa_core *c); -char *pa_client_list_to_string(pa_core *c); -char *pa_module_list_to_string(pa_core *c); -char *pa_scache_list_to_string(pa_core *c); -char *pa_autoload_list_to_string(pa_core *c); - -char *pa_full_status_string(pa_core *c); - -#endif - diff --git a/polyp/cli.c b/polyp/cli.c deleted file mode 100644 index bc0c285d..00000000 --- a/polyp/cli.c +++ /dev/null @@ -1,147 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "ioline.h" -#include "cli.h" -#include "module.h" -#include "sink.h" -#include "source.h" -#include "client.h" -#include "sink-input.h" -#include "source-output.h" -#include "tokenizer.h" -#include "strbuf.h" -#include "namereg.h" -#include "cli-text.h" -#include "cli-command.h" -#include "xmalloc.h" -#include "log.h" - -#define PROMPT ">>> " - -struct pa_cli { - pa_core *core; - pa_ioline *line; - - void (*eof_callback)(pa_cli *c, void *userdata); - void *userdata; - - pa_client *client; - - int fail, kill_requested, defer_kill; -}; - -static void line_callback(pa_ioline *line, const char *s, void *userdata); -static void client_kill(pa_client *c); - -pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m) { - char cname[256]; - pa_cli *c; - assert(io); - - c = pa_xmalloc(sizeof(pa_cli)); - c->core = core; - c->line = pa_ioline_new(io); - assert(c->line); - - c->userdata = NULL; - c->eof_callback = NULL; - - pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); - c->client = pa_client_new(core, __FILE__, cname); - assert(c->client); - c->client->kill = client_kill; - c->client->userdata = c; - c->client->owner = m; - - pa_ioline_set_callback(c->line, line_callback, c); - pa_ioline_puts(c->line, "Welcome to polypaudio! Use \"help\" for usage information.\n"PROMPT); - - c->fail = c->kill_requested = c->defer_kill = 0; - - return c; -} - -void pa_cli_free(pa_cli *c) { - assert(c); - pa_ioline_close(c->line); - pa_ioline_unref(c->line); - pa_client_free(c->client); - pa_xfree(c); -} - -static void client_kill(pa_client *client) { - pa_cli *c; - assert(client && client->userdata); - c = client->userdata; - - pa_log_debug(__FILE__": CLI client killed.\n"); - if (c->defer_kill) - c->kill_requested = 1; - else { - if (c->eof_callback) - c->eof_callback(c, c->userdata); - } -} - -static void line_callback(pa_ioline *line, const char *s, void *userdata) { - pa_strbuf *buf; - pa_cli *c = userdata; - char *p; - assert(line && c); - - if (!s) { - pa_log_debug(__FILE__": CLI got EOF from user.\n"); - if (c->eof_callback) - c->eof_callback(c, c->userdata); - - return; - } - - buf = pa_strbuf_new(); - assert(buf); - c->defer_kill++; - pa_cli_command_execute_line(c->core, s, buf, &c->fail); - c->defer_kill--; - pa_ioline_puts(line, p = pa_strbuf_tostring_free(buf)); - pa_xfree(p); - - 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(pa_cli *c, void (*cb)(pa_cli*c, void *userdata), void *userdata) { - assert(c); - c->eof_callback = cb; - c->userdata = userdata; -} diff --git a/polyp/cli.h b/polyp/cli.h deleted file mode 100644 index 03f31c22..00000000 --- a/polyp/cli.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef fooclihfoo -#define fooclihfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "iochannel.h" -#include "core.h" -#include "module.h" - -typedef struct pa_cli pa_cli; - -/* Create a new command line session on the specified io channel owned by the specified module */ -pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m); -void pa_cli_free(pa_cli *cli); - -/* Set a callback function that is called whenever the command line session is terminated */ -void pa_cli_set_eof_callback(pa_cli *cli, void (*cb)(pa_cli*c, void *userdata), void *userdata); - -#endif diff --git a/polyp/client-conf-x11.c b/polyp/client-conf-x11.c deleted file mode 100644 index 4fd75744..00000000 --- a/polyp/client-conf-x11.c +++ /dev/null @@ -1,91 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-13071 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include -#include - -#include "client-conf-x11.h" -#include "x11prop.h" -#include "log.h" -#include "xmalloc.h" -#include "util.h" - -int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) { - Display *d = NULL; - int ret = -1; - char t[1024]; - - if (!dname && !getenv("DISPLAY")) - goto finish; - - if (!(d = XOpenDisplay(dname))) { - pa_log(__FILE__": XOpenDisplay() failed\n"); - goto finish; - } - - if (pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) { - pa_xfree(c->default_server); - c->default_server = pa_xstrdup(t); - } - - if (pa_x11_get_prop(d, "POLYP_SINK", t, sizeof(t))) { - pa_xfree(c->default_sink); - c->default_sink = pa_xstrdup(t); - } - - if (pa_x11_get_prop(d, "POLYP_SOURCE", t, sizeof(t))) { - pa_xfree(c->default_source); - c->default_source = pa_xstrdup(t); - } - - if (pa_x11_get_prop(d, "POLYP_COOKIE", t, sizeof(t))) { - uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; - - if (pa_parsehex(t, cookie, sizeof(cookie)) != sizeof(cookie)) { - pa_log(__FILE__": failed to parse cookie data\n"); - goto finish; - } - - assert(sizeof(cookie) == sizeof(c->cookie)); - memcpy(c->cookie, cookie, sizeof(cookie)); - - c->cookie_valid = 1; - - pa_xfree(c->cookie_file); - c->cookie_file = NULL; - } - - ret = 0; - -finish: - if (d) - XCloseDisplay(d); - - return ret; - -} diff --git a/polyp/client-conf-x11.h b/polyp/client-conf-x11.h deleted file mode 100644 index 64459224..00000000 --- a/polyp/client-conf-x11.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef fooclientconfx11hfoo -#define fooclientconfx11hfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "client-conf.h" - -/* Load client configuration data from the specified X11 display, - * overwriting the current settings in *c */ -int pa_client_conf_from_x11(pa_client_conf *c, const char *display); - -#endif diff --git a/polyp/client-conf.c b/polyp/client-conf.c deleted file mode 100644 index bcd4275d..00000000 --- a/polyp/client-conf.c +++ /dev/null @@ -1,190 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "client-conf.h" -#include "xmalloc.h" -#include "log.h" -#include "conf-parser.h" -#include "util.h" -#include "authkey.h" - -#ifndef DEFAULT_CONFIG_DIR -# ifndef OS_IS_WIN32 -# define DEFAULT_CONFIG_DIR "/etc/polypaudio" -# else -# define DEFAULT_CONFIG_DIR "%POLYP_ROOT%" -# endif -#endif - -#ifndef OS_IS_WIN32 -# define PATH_SEP "/" -#else -# define PATH_SEP "\\" -#endif - -#define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "client.conf" -#define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio" PATH_SEP "client.conf" - -#define ENV_CLIENT_CONFIG_FILE "POLYP_CLIENTCONFIG" -#define ENV_DEFAULT_SINK "POLYP_SINK" -#define ENV_DEFAULT_SOURCE "POLYP_SOURCE" -#define ENV_DEFAULT_SERVER "POLYP_SERVER" -#define ENV_DAEMON_BINARY "POLYP_BINARY" -#define ENV_COOKIE_FILE "POLYP_COOKIE" - -static const pa_client_conf default_conf = { - .daemon_binary = NULL, - .extra_arguments = NULL, - .default_sink = NULL, - .default_source = NULL, - .default_server = NULL, - .autospawn = 0, - .cookie_file = NULL, - .cookie_valid = 0 -}; - -pa_client_conf *pa_client_conf_new(void) { - pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); - - c->daemon_binary = pa_xstrdup(POLYPAUDIO_BINARY); - c->extra_arguments = pa_xstrdup("--log-target=syslog --exit-idle-time=5"); - c->cookie_file = pa_xstrdup(PA_NATIVE_COOKIE_FILE); - - return c; -} - -void pa_client_conf_free(pa_client_conf *c) { - assert(c); - pa_xfree(c->daemon_binary); - pa_xfree(c->extra_arguments); - pa_xfree(c->default_sink); - pa_xfree(c->default_source); - pa_xfree(c->default_server); - pa_xfree(c->cookie_file); - pa_xfree(c); -} -int pa_client_conf_load(pa_client_conf *c, const char *filename) { - FILE *f = NULL; - char *fn = NULL; - int r = -1; - - /* Prepare the configuration parse table */ - pa_config_item table[] = { - { "daemon-binary", pa_config_parse_string, NULL }, - { "extra-arguments", pa_config_parse_string, NULL }, - { "default-sink", pa_config_parse_string, NULL }, - { "default-source", pa_config_parse_string, NULL }, - { "default-server", pa_config_parse_string, NULL }, - { "autospawn", pa_config_parse_bool, NULL }, - { "cookie-file", pa_config_parse_string, NULL }, - { NULL, NULL, NULL }, - }; - - table[0].data = &c->daemon_binary; - table[1].data = &c->extra_arguments; - table[2].data = &c->default_sink; - table[3].data = &c->default_source; - table[4].data = &c->default_server; - table[5].data = &c->autospawn; - table[6].data = &c->cookie_file; - - f = filename ? - fopen((fn = pa_xstrdup(filename)), "r") : - pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn); - - if (!f && errno != EINTR) { - pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno)); - goto finish; - } - - r = f ? pa_config_parse(fn, f, table, NULL) : 0; - - if (!r) - r = pa_client_conf_load_cookie(c); - - -finish: - pa_xfree(fn); - - if (f) - fclose(f); - - return r; -} - -int pa_client_conf_env(pa_client_conf *c) { - char *e; - - if ((e = getenv(ENV_DEFAULT_SINK))) { - pa_xfree(c->default_sink); - c->default_sink = pa_xstrdup(e); - } - - if ((e = getenv(ENV_DEFAULT_SOURCE))) { - pa_xfree(c->default_source); - c->default_source = pa_xstrdup(e); - } - - if ((e = getenv(ENV_DEFAULT_SERVER))) { - pa_xfree(c->default_server); - c->default_server = pa_xstrdup(e); - } - - if ((e = getenv(ENV_DAEMON_BINARY))) { - pa_xfree(c->daemon_binary); - c->daemon_binary = pa_xstrdup(e); - } - - if ((e = getenv(ENV_COOKIE_FILE))) { - pa_xfree(c->cookie_file); - c->cookie_file = pa_xstrdup(e); - - return pa_client_conf_load_cookie(c); - } - - return 0; -} - -int pa_client_conf_load_cookie(pa_client_conf* c) { - assert(c); - - c->cookie_valid = 0; - - if (!c->cookie_file) - return -1; - - if (pa_authkey_load_auto(c->cookie_file, c->cookie, sizeof(c->cookie)) < 0) - return -1; - - c->cookie_valid = 1; - return 0; -} - diff --git a/polyp/client-conf.h b/polyp/client-conf.h deleted file mode 100644 index 7ca2f233..00000000 --- a/polyp/client-conf.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef fooclientconfhfoo -#define fooclientconfhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "native-common.h" - -/* A structure containing configuration data for polypaudio clients. */ - -typedef struct pa_client_conf { - char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server, *cookie_file; - int autospawn; - uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; - int cookie_valid; /* non-zero, when cookie is valid */ -} pa_client_conf; - -/* Create a new configuration data object and reset it to defaults */ -pa_client_conf *pa_client_conf_new(void); -void pa_client_conf_free(pa_client_conf *c); - -/* Load the configuration data from the speicified file, overwriting - * the current settings in *c. When the filename is NULL, the - * default client configuration file name is used. */ -int pa_client_conf_load(pa_client_conf *c, const char *filename); - -/* Load the configuration data from the environment of the current - process, overwriting the current settings in *c. */ -int pa_client_conf_env(pa_client_conf *c); - -/* Load cookie data from c->cookie_file into c->cookie */ -int pa_client_conf_load_cookie(pa_client_conf* c); - -#endif diff --git a/polyp/client.c b/polyp/client.c deleted file mode 100644 index 3c2084bf..00000000 --- a/polyp/client.c +++ /dev/null @@ -1,91 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "client.h" -#include "xmalloc.h" -#include "subscribe.h" -#include "log.h" - -pa_client *pa_client_new(pa_core *core, const char *name, const char *driver) { - pa_client *c; - int r; - assert(core); - - c = pa_xmalloc(sizeof(pa_client)); - c->name = pa_xstrdup(name); - c->driver = pa_xstrdup(driver); - c->owner = NULL; - c->core = core; - - c->kill = NULL; - c->userdata = NULL; - - r = pa_idxset_put(core->clients, c, &c->index); - assert(c->index != PA_IDXSET_INVALID && r >= 0); - - pa_log_info(__FILE__": created %u \"%s\"\n", c->index, c->name); - pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index); - - pa_core_check_quit(core); - - return c; -} - -void pa_client_free(pa_client *c) { - assert(c && c->core); - - pa_idxset_remove_by_data(c->core->clients, c, NULL); - - pa_core_check_quit(c->core); - - pa_log_info(__FILE__": freed %u \"%s\"\n", c->index, c->name); - pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index); - pa_xfree(c->name); - pa_xfree(c->driver); - pa_xfree(c); -} - -void pa_client_kill(pa_client *c) { - assert(c); - if (!c->kill) { - pa_log_warn(__FILE__": kill() operation not implemented for client %u\n", c->index); - return; - } - - c->kill(c); -} - -void pa_client_set_name(pa_client *c, const char *name) { - assert(c); - pa_xfree(c->name); - c->name = pa_xstrdup(name); - - pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->index); -} diff --git a/polyp/client.conf.in b/polyp/client.conf.in deleted file mode 100644 index fbf645a4..00000000 --- a/polyp/client.conf.in +++ /dev/null @@ -1,39 +0,0 @@ -# $Id$ -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -## Configuration file for polypaudio clients. Default values are -## commented out. Use either ; or # for commenting - -## Path to the polypaudio daemon to run when autospawning. -; daemon-binary = @POLYPAUDIO_BINARY@ - -## Extra arguments to pass to the polypaudio daemon -; extra-arguments = --log-target=syslog --exit-idle-time=5 - -## The default sink to connect to -; default-sink = - -## The default source to connect to -; default-source = - -## The default sever to connect to -; default-server = - -## Autospawn daemons? -; autospawn = 0 diff --git a/polyp/client.h b/polyp/client.h deleted file mode 100644 index 92430338..00000000 --- a/polyp/client.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef fooclienthfoo -#define fooclienthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "core.h" -#include "module.h" - -/* Every connection to the server should have a pa_client - * attached. That way the user may generate a listing of all connected - * clients easily and kill them if he wants.*/ - -typedef struct pa_client pa_client; - -struct pa_client { - uint32_t index; - - pa_module *owner; - char *name, *driver; - pa_core *core; - - void (*kill)(pa_client *c); - void *userdata; -}; - -pa_client *pa_client_new(pa_core *c, const char *name, const char *driver); - -/* This function should be called only by the code that created the client */ -void pa_client_free(pa_client *c); - -/* Code that didn't create the client should call this function to - * request destruction of the client */ -void pa_client_kill(pa_client *c); - -/* Rename the client */ -void pa_client_set_name(pa_client *c, const char *name); - -#endif diff --git a/polyp/cmdline.c b/polyp/cmdline.c deleted file mode 100644 index 5635707f..00000000 --- a/polyp/cmdline.c +++ /dev/null @@ -1,300 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "cmdline.h" -#include "util.h" -#include "strbuf.h" -#include "xmalloc.h" - -/* Argument codes for getopt_long() */ -enum { - ARG_HELP = 256, - ARG_VERSION, - ARG_DUMP_CONF, - ARG_DUMP_MODULES, - ARG_DAEMONIZE, - ARG_FAIL, - ARG_LOG_LEVEL, - ARG_HIGH_PRIORITY, - ARG_DISALLOW_MODULE_LOADING, - ARG_EXIT_IDLE_TIME, - ARG_MODULE_IDLE_TIME, - ARG_SCACHE_IDLE_TIME, - ARG_LOG_TARGET, - ARG_LOAD, - ARG_FILE, - ARG_DL_SEARCH_PATH, - ARG_RESAMPLE_METHOD, - ARG_KILL, - ARG_USE_PID_FILE, - ARG_CHECK -}; - -/* Tabel for getopt_long() */ -static struct option long_options[] = { - {"help", 0, 0, ARG_HELP}, - {"version", 0, 0, ARG_VERSION}, - {"dump-conf", 0, 0, ARG_DUMP_CONF}, - {"dump-modules", 0, 0, ARG_DUMP_MODULES}, - {"daemonize", 2, 0, ARG_DAEMONIZE}, - {"fail", 2, 0, ARG_FAIL}, - {"verbose", 2, 0, ARG_LOG_LEVEL}, - {"log-level", 2, 0, ARG_LOG_LEVEL}, - {"high-priority", 2, 0, ARG_HIGH_PRIORITY}, - {"disallow-module-loading", 2, 0, ARG_DISALLOW_MODULE_LOADING}, - {"exit-idle-time", 2, 0, ARG_EXIT_IDLE_TIME}, - {"module-idle-time", 2, 0, ARG_MODULE_IDLE_TIME}, - {"scache-idle-time", 2, 0, ARG_SCACHE_IDLE_TIME}, - {"log-target", 1, 0, ARG_LOG_TARGET}, - {"load", 1, 0, ARG_LOAD}, - {"file", 1, 0, ARG_FILE}, - {"dl-search-path", 1, 0, ARG_DL_SEARCH_PATH}, - {"resample-method", 1, 0, ARG_RESAMPLE_METHOD}, - {"kill", 0, 0, ARG_KILL}, - {"use-pid-file", 2, 0, ARG_USE_PID_FILE}, - {"check", 0, 0, ARG_CHECK}, - {NULL, 0, 0, 0} -}; - -void pa_cmdline_help(const char *argv0) { - const char *e; - - if ((e = strrchr(argv0, '/'))) - e++; - else - e = argv0; - - printf("%s [options]\n\n" - "COMMANDS:\n" - " -h, --help Show this help\n" - " --version Show version\n" - " --dump-conf Dump default configuration\n" - " --dump-modules Dump list of available modules\n" - " -k --kill Kill a running daemon\n" - " --check Check for a running daemon\n\n" - - "OPTIONS:\n" - " -D, --daemonize[=BOOL] Daemonize after startup\n" - " --fail[=BOOL] Quit when startup fails\n" - " --high-priority[=BOOL] Try to set high process priority\n" - " (only available as root)\n" - " --disallow-module-loading[=BOOL] Disallow module loading after startup\n" - " --exit-idle-time=SECS Terminate the daemon when idle and this\n" - " time passed\n" - " --module-idle-time=SECS Unload autoloaded modules when idle and\n" - " this time passed\n" - " --scache-idle-time=SECS Unload autoloaded samples when idle and\n" - " this time passed\n" - " --log-level[=LEVEL] Increase or set verbosity level\n" - " -v Increase the verbosity level\n" - " --log-target={auto,syslog,stderr} Specify the log target\n" - " -p, --dl-search-path=PATH Set the search path for dynamic shared\n" - " objects (plugins)\n" - " --resample-method=[METHOD] Use the specified resampling method\n" - " (one of src-sinc-medium-quality,\n" - " src-sinc-best-quality,src-sinc-fastest\n" - " src-zero-order-hold,src-linear,trivial)\n" - " --use-pid-file[=BOOL] Create a PID file\n\n" - - "STARTUP SCRIPT:\n" - " -L, --load=\"MODULE ARGUMENTS\" Load the specified plugin module with\n" - " the specified argument\n" - " -F, --file=FILENAME Run the specified script\n" - " -C Open a command line on the running TTY\n" - " after startup\n\n" - - " -n Don't load default script file\n", e); -} - -int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d) { - pa_strbuf *buf = NULL; - int c; - assert(conf && argc && argv); - - buf = pa_strbuf_new(); - - if (conf->script_commands) - pa_strbuf_puts(buf, conf->script_commands); - - while ((c = getopt_long(argc, argv, "L:F:ChDnp:kv", long_options, NULL)) != -1) { - switch (c) { - case ARG_HELP: - case 'h': - conf->cmd = PA_CMD_HELP; - break; - - case ARG_VERSION: - conf->cmd = PA_CMD_VERSION; - break; - - case ARG_DUMP_CONF: - conf->cmd = PA_CMD_DUMP_CONF; - break; - - case ARG_DUMP_MODULES: - conf->cmd = PA_CMD_DUMP_MODULES; - break; - - case 'k': - case ARG_KILL: - conf->cmd = PA_CMD_KILL; - break; - - case ARG_CHECK: - conf->cmd = PA_CMD_CHECK; - break; - - case ARG_LOAD: - case 'L': - pa_strbuf_printf(buf, "load-module %s\n", optarg); - break; - - case ARG_FILE: - case 'F': - pa_strbuf_printf(buf, ".include %s\n", optarg); - break; - - case 'C': - pa_strbuf_puts(buf, "load-module module-cli\n"); - break; - - case ARG_DAEMONIZE: - case 'D': - if ((conf->daemonize = optarg ? pa_parse_boolean(optarg) : 1) < 0) { - pa_log(__FILE__": --daemonize expects boolean argument\n"); - goto fail; - } - break; - - case ARG_FAIL: - if ((conf->fail = optarg ? pa_parse_boolean(optarg) : 1) < 0) { - pa_log(__FILE__": --fail expects boolean argument\n"); - goto fail; - } - break; - - case 'v': - case ARG_LOG_LEVEL: - - if (optarg) { - if (pa_daemon_conf_set_log_level(conf, optarg) < 0) { - pa_log(__FILE__": --log-level expects log level argument (either numeric in range 0..4 or one of debug, info, notice, warn, error).\n"); - goto fail; - } - } else { - if (conf->log_level < PA_LOG_LEVEL_MAX-1) - conf->log_level++; - } - - break; - - case ARG_HIGH_PRIORITY: - if ((conf->high_priority = optarg ? pa_parse_boolean(optarg) : 1) < 0) { - pa_log(__FILE__": --high-priority expects boolean argument\n"); - goto fail; - } - break; - - case ARG_DISALLOW_MODULE_LOADING: - if ((conf->disallow_module_loading = optarg ? pa_parse_boolean(optarg) : 1) < 0) { - pa_log(__FILE__": --disallow-module-loading expects boolean argument\n"); - goto fail; - } - break; - - case ARG_USE_PID_FILE: - if ((conf->use_pid_file = optarg ? pa_parse_boolean(optarg) : 1) < 0) { - pa_log(__FILE__": --use-pid-file expects boolean argument\n"); - goto fail; - } - break; - - case 'p': - case ARG_DL_SEARCH_PATH: - pa_xfree(conf->dl_search_path); - conf->dl_search_path = *optarg ? pa_xstrdup(optarg) : NULL; - break; - - case 'n': - pa_xfree(conf->default_script_file); - conf->default_script_file = NULL; - break; - - case ARG_LOG_TARGET: - if (pa_daemon_conf_set_log_target(conf, optarg) < 0) { - pa_log(__FILE__": Invalid log target: use either 'syslog', 'stderr' or 'auto'.\n"); - goto fail; - } - break; - - case ARG_EXIT_IDLE_TIME: - conf->exit_idle_time = atoi(optarg); - break; - - case ARG_MODULE_IDLE_TIME: - conf->module_idle_time = atoi(optarg); - break; - - case ARG_SCACHE_IDLE_TIME: - conf->scache_idle_time = atoi(optarg); - break; - - case ARG_RESAMPLE_METHOD: - if (pa_daemon_conf_set_resample_method(conf, optarg) < 0) { - pa_log(__FILE__": Invalid resample method '%s'.\n", optarg); - goto fail; - } - break; - - default: - goto fail; - } - } - - pa_xfree(conf->script_commands); - conf->script_commands = pa_strbuf_tostring_free(buf); - - if (!conf->script_commands) { - pa_xfree(conf->script_commands); - conf->script_commands = NULL; - } - - *d = optind; - - return 0; - -fail: - if (buf) - pa_strbuf_free(buf); - - return -1; -} diff --git a/polyp/cmdline.h b/polyp/cmdline.h deleted file mode 100644 index e2eaf0d2..00000000 --- a/polyp/cmdline.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef foocmdlinehfoo -#define foocmdlinehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "daemon-conf.h" - -/* Parese the command line and store its data in *c. Return the index - * of the first unparsed argument in *d. */ -int pa_cmdline_parse(pa_daemon_conf*c, int argc, char *const argv [], int *d); - -/* Show the command line help. The command name is extracted from - * argv[0] which should be passed in argv0. */ -void pa_cmdline_help(const char *argv0); - -#endif diff --git a/polyp/conf-parser.c b/polyp/conf-parser.c deleted file mode 100644 index 507f2bf1..00000000 --- a/polyp/conf-parser.c +++ /dev/null @@ -1,176 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "conf-parser.h" -#include "log.h" -#include "util.h" -#include "xmalloc.h" - -#define WHITESPACE " \t\n" -#define COMMENTS "#;\n" - -/* Run the user supplied parser for an assignment */ -static int next_assignment(const char *filename, unsigned line, const pa_config_item *t, const char *lvalue, const char *rvalue, void *userdata) { - assert(filename && t && lvalue && rvalue); - - for (; t->parse; t++) - if (!strcmp(lvalue, t->lvalue)) - return t->parse(filename, line, lvalue, rvalue, t->data, userdata); - - pa_log(__FILE__": [%s:%u] Unknown lvalue '%s'.\n", filename, line, lvalue); - - return -1; -} - -/* Returns non-zero when c is contained in s */ -static int in_string(char c, const char *s) { - assert(s); - - for (; *s; s++) - if (*s == c) - return 1; - - return 0; -} - -/* Remove all whitepsapce from the beginning and the end of *s. *s may - * be modified. */ -static char *strip(char *s) { - char *b = s+strspn(s, WHITESPACE); - char *e, *l = NULL; - - for (e = b; *e; e++) - if (!in_string(*e, WHITESPACE)) - l = e; - - if (l) - *(l+1) = 0; - - return b; -} - -/* Parse a variable assignment line */ -static int parse_line(const char *filename, unsigned line, const pa_config_item *t, char *l, void *userdata) { - char *e, *c, *b = l+strspn(l, WHITESPACE); - - if ((c = strpbrk(b, COMMENTS))) - *c = 0; - - if (!*b) - return 0; - - if (!(e = strchr(b, '='))) { - pa_log(__FILE__": [%s:%u] Missing '='.\n", filename, line); - return -1; - } - - *e = 0; - e++; - - return next_assignment(filename, line, t, strip(b), strip(e), userdata); -} - -/* Go through the file and parse each line */ -int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void *userdata) { - int r = -1; - unsigned line = 0; - int do_close = !f; - assert(filename && t); - - if (!f && !(f = fopen(filename, "r"))) { - if (errno == ENOENT) { - r = 0; - goto finish; - } - - pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno)); - goto finish; - } - - while (!feof(f)) { - char l[256]; - if (!fgets(l, sizeof(l), f)) { - if (feof(f)) - break; - - pa_log(__FILE__": WARNING: failed to read configuration file '%s': %s\n", filename, strerror(errno)); - goto finish; - } - - if (parse_line(filename, ++line, t, l, userdata) < 0) - goto finish; - } - - r = 0; - -finish: - - if (do_close && f) - fclose(f); - - return r; -} - -int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { - int *i = data; - int32_t k; - assert(filename && lvalue && rvalue && data); - - if (pa_atoi(rvalue, &k) < 0) { - pa_log(__FILE__": [%s:%u] Failed to parse numeric value: %s\n", filename, line, rvalue); - return -1; - } - - *i = (int) k; - return 0; -} - -int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { - int *b = data, k; - assert(filename && lvalue && rvalue && data); - - if ((k = pa_parse_boolean(rvalue)) < 0) { - pa_log(__FILE__": [%s:%u] Failed to parse boolean value: %s\n", filename, line, rvalue); - return -1; - } - - *b = k; - - return 0; -} - -int pa_config_parse_string(const char *filename, PA_GCC_UNUSED unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { - char **s = data; - assert(filename && lvalue && rvalue && data); - - pa_xfree(*s); - *s = *rvalue ? pa_xstrdup(rvalue) : NULL; - return 0; -} diff --git a/polyp/conf-parser.h b/polyp/conf-parser.h deleted file mode 100644 index 2dca3bce..00000000 --- a/polyp/conf-parser.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef fooconfparserhfoo -#define fooconfparserhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -/* An abstract parser for simple, line based, shallow configuration - * files consisting of variable assignments only. */ - -/* Wraps info for parsing a specific configuration variable */ -typedef struct pa_config_item { - const char *lvalue; /* name of the variable */ - int (*parse)(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); /* Function that is called to parse the variable's value */ - void *data; /* Where to store the variable's data */ -} pa_config_item; - -/* The configuration file parsing routine. Expects a table of - * pa_config_items in *t that is terminated by an item where lvalue is - * NULL */ -int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void *userdata); - -/* Generic parsers for integers, booleans and strings */ -int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); -int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); -int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); - -#endif diff --git a/polyp/core.c b/polyp/core.c deleted file mode 100644 index 678e8212..00000000 --- a/polyp/core.c +++ /dev/null @@ -1,157 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "core.h" -#include "module.h" -#include "sink.h" -#include "source.h" -#include "namereg.h" -#include "util.h" -#include "scache.h" -#include "autoload.h" -#include "xmalloc.h" -#include "subscribe.h" -#include "props.h" -#include "random.h" - -pa_core* pa_core_new(pa_mainloop_api *m) { - pa_core* c; - c = pa_xmalloc(sizeof(pa_core)); - - c->mainloop = m; - c->clients = pa_idxset_new(NULL, NULL); - c->sinks = pa_idxset_new(NULL, NULL); - c->sources = pa_idxset_new(NULL, NULL); - c->source_outputs = pa_idxset_new(NULL, NULL); - c->sink_inputs = pa_idxset_new(NULL, NULL); - - c->default_source_name = c->default_sink_name = NULL; - - c->modules = NULL; - c->namereg = NULL; - c->scache = NULL; - c->autoload_idxset = NULL; - c->autoload_hashmap = NULL; - c->running_as_daemon = 0; - - c->default_sample_spec.format = PA_SAMPLE_S16NE; - c->default_sample_spec.rate = 44100; - c->default_sample_spec.channels = 2; - - c->module_auto_unload_event = NULL; - c->module_defer_unload_event = NULL; - c->scache_auto_unload_event = NULL; - - c->subscription_defer_event = NULL; - c->subscription_event_queue = NULL; - c->subscriptions = NULL; - - c->memblock_stat = pa_memblock_stat_new(); - - c->disallow_module_loading = 0; - - c->quit_event = NULL; - - c->exit_idle_time = -1; - c->module_idle_time = 20; - c->scache_idle_time = 20; - - c->resample_method = PA_RESAMPLER_SRC_SINC_FASTEST; - - pa_property_init(c); - - pa_random(&c->cookie, sizeof(c->cookie)); - -#ifdef SIGPIPE - pa_check_signal_is_blocked(SIGPIPE); -#endif - return c; -} - -void pa_core_free(pa_core *c) { - assert(c); - - pa_module_unload_all(c); - assert(!c->modules); - - assert(pa_idxset_isempty(c->clients)); - pa_idxset_free(c->clients, NULL, NULL); - - assert(pa_idxset_isempty(c->sinks)); - pa_idxset_free(c->sinks, NULL, NULL); - - assert(pa_idxset_isempty(c->sources)); - pa_idxset_free(c->sources, NULL, NULL); - - assert(pa_idxset_isempty(c->source_outputs)); - pa_idxset_free(c->source_outputs, NULL, NULL); - - assert(pa_idxset_isempty(c->sink_inputs)); - pa_idxset_free(c->sink_inputs, NULL, NULL); - - pa_scache_free(c); - pa_namereg_free(c); - pa_autoload_free(c); - pa_subscription_free_all(c); - - if (c->quit_event) - c->mainloop->time_free(c->quit_event); - - pa_xfree(c->default_source_name); - pa_xfree(c->default_sink_name); - - pa_memblock_stat_unref(c->memblock_stat); - - pa_property_cleanup(c); - - pa_xfree(c); -} - -static void quit_callback(pa_mainloop_api*m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - pa_core *c = userdata; - assert(c->quit_event = e); - - m->quit(m, 0); -} - -void pa_core_check_quit(pa_core *c) { - assert(c); - - if (!c->quit_event && c->exit_idle_time >= 0 && pa_idxset_size(c->clients) == 0) { - struct timeval tv; - pa_gettimeofday(&tv); - tv.tv_sec+= c->exit_idle_time; - c->quit_event = c->mainloop->time_new(c->mainloop, &tv, quit_callback, c); - } else if (c->quit_event && pa_idxset_size(c->clients) > 0) { - c->mainloop->time_free(c->quit_event); - c->quit_event = NULL; - } -} - diff --git a/polyp/core.h b/polyp/core.h deleted file mode 100644 index 9241fcd8..00000000 --- a/polyp/core.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef foocorehfoo -#define foocorehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -typedef struct pa_core pa_core; - -#include "idxset.h" -#include "hashmap.h" -#include "mainloop-api.h" -#include "sample.h" -#include "memblock.h" -#include "resampler.h" -#include "queue.h" -#include "subscribe.h" - -/* The core structure of polypaudio. Every polypaudio daemon contains - * exactly one of these. It is used for storing kind of global - * variables for the daemon. */ - -struct pa_core { - /* A random value which may be used to identify this instance of - * polypaudio. Not cryptographically secure in any way. */ - uint32_t cookie; - - pa_mainloop_api *mainloop; - - /* idxset of all kinds of entities */ - pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache, *autoload_idxset; - - /* Some hashmaps for all sorts of entities */ - pa_hashmap *namereg, *autoload_hashmap, *properties; - - /* The name of the default sink/source */ - char *default_source_name, *default_sink_name; - - pa_sample_spec default_sample_spec; - pa_time_event *module_auto_unload_event; - pa_defer_event *module_defer_unload_event; - - pa_defer_event *subscription_defer_event; - pa_queue *subscription_event_queue; - pa_subscription *subscriptions; - - pa_memblock_stat *memblock_stat; - - int disallow_module_loading, running_as_daemon; - int exit_idle_time, module_idle_time, scache_idle_time; - - pa_time_event *quit_event; - - pa_time_event *scache_auto_unload_event; - - pa_resample_method_t resample_method; -}; - -pa_core* pa_core_new(pa_mainloop_api *m); -void pa_core_free(pa_core*c); - -/* Check whether noone is connected to this core */ -void pa_core_check_quit(pa_core *c); - -#endif diff --git a/polyp/cpulimit-test.c b/polyp/cpulimit-test.c deleted file mode 100644 index 598b2dd2..00000000 --- a/polyp/cpulimit-test.c +++ /dev/null @@ -1,92 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "cpulimit.h" -#include "mainloop.h" -#include "gccmacro.h" - -#ifdef TEST2 -#include "mainloop-signal.h" -#endif - -/* A simple example for testing the cpulimit subsystem */ - -static time_t start; - -#ifdef TEST2 - -static void func(pa_mainloop_api *m, PA_GCC_UNUSED pa_signal_event *e, PA_GCC_UNUSED int sig, PA_GCC_UNUSED void *userdata) { - time_t now; - time(&now); - - if ((now - start) >= 30) { - m->quit(m, 1); - fprintf(stderr, "Test failed\n"); - } else - raise(SIGUSR1); -} - -#endif - -int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { - pa_mainloop *m; - - m = pa_mainloop_new(); - assert(m); - - pa_cpu_limit_init(pa_mainloop_get_api(m)); - - time(&start); - -#ifdef TEST2 - pa_signal_init(pa_mainloop_get_api(m)); - pa_signal_new(SIGUSR1, func, NULL); - raise(SIGUSR1); - pa_mainloop_run(m, NULL); - pa_signal_done(); -#else - for (;;) { - time_t now; - time(&now); - - if ((now - start) >= 30) { - fprintf(stderr, "Test failed\n"); - break; - } - } -#endif - - pa_cpu_limit_done(); - - pa_mainloop_free(m); - - return 0; -} diff --git a/polyp/cpulimit.c b/polyp/cpulimit.c deleted file mode 100644 index a834b094..00000000 --- a/polyp/cpulimit.c +++ /dev/null @@ -1,236 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "cpulimit.h" -#include "util.h" -#include "log.h" - -#ifdef HAVE_SIGXCPU - -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif - -/* This module implements a watchdog that makes sure that the current - * process doesn't consume more than 70% CPU time for 10 seconds. This - * is very useful when using SCHED_FIFO scheduling which effectively - * disables multitasking. */ - -/* Method of operation: Using SIGXCPU a signal handler is called every - * 10s process CPU time. That function checks if less than 14s system - * time have passed. In that case, it tries to contact the main event - * loop through a pipe. After two additional seconds it is checked - * whether the main event loop contact was successful. If not, the - * program is terminated forcibly. */ - -/* Utilize this much CPU time at maximum */ -#define CPUTIME_PERCENT 70 - -/* Check every 10s */ -#define CPUTIME_INTERVAL_SOFT (10) - -/* Recheck after 2s */ -#define CPUTIME_INTERVAL_HARD (2) - -/* Time of the last CPU load check */ -static time_t last_time = 0; - -/* Pipe for communicating with the main loop */ -static int the_pipe[2] = {-1, -1}; - -/* Main event loop and IO event for the FIFO */ -static pa_mainloop_api *api = NULL; -static pa_io_event *io_event = NULL; - -/* Saved sigaction struct for SIGXCPU */ -static struct sigaction sigaction_prev; - -/* Nonzero after pa_cpu_limit_init() */ -static int installed = 0; - -/* The current state of operation */ -static enum { - PHASE_IDLE, /* Normal state */ - PHASE_SOFT /* After CPU overload has been detected */ -} phase = PHASE_IDLE; - -/* Reset the SIGXCPU timer to the next t seconds */ -static void reset_cpu_time(int t) { - int r; - long n; - struct rlimit rl; - struct rusage ru; - - /* Get the current CPU time of the current process */ - r = getrusage(RUSAGE_SELF, &ru); - assert(r >= 0); - - n = ru.ru_utime.tv_sec + ru.ru_stime.tv_sec + t; - - r = getrlimit(RLIMIT_CPU, &rl); - assert(r >= 0); - - rl.rlim_cur = n; - r = setrlimit(RLIMIT_CPU, &rl); - assert(r >= 0); -} - -/* A simple, thread-safe puts() work-alike */ -static void write_err(const char *p) { - pa_loop_write(2, p, strlen(p)); -} - -/* The signal handler, called on every SIGXCPU */ -static void signal_handler(int sig) { - assert(sig == SIGXCPU); - - if (phase == PHASE_IDLE) { - time_t now; - -#ifdef PRINT_CPU_LOAD - char t[256]; -#endif - - time(&now); - -#ifdef PRINT_CPU_LOAD - snprintf(t, sizeof(t), "Using %0.1f%% CPU\n", (double)CPUTIME_INTERVAL_SOFT/(now-last_time)*100); - write_err(t); -#endif - - if (CPUTIME_INTERVAL_SOFT >= ((now-last_time)*(double)CPUTIME_PERCENT/100)) { - static const char c = 'X'; - - write_err("Soft CPU time limit exhausted, terminating.\n"); - - /* Try a soft cleanup */ - write(the_pipe[1], &c, sizeof(c)); - phase = PHASE_SOFT; - reset_cpu_time(CPUTIME_INTERVAL_HARD); - - } else { - - /* Everything's fine */ - reset_cpu_time(CPUTIME_INTERVAL_SOFT); - last_time = now; - } - - } else if (phase == PHASE_SOFT) { - write_err("Hard CPU time limit exhausted, terminating forcibly.\n"); - _exit(1); /* Forced exit */ - } -} - -/* Callback for IO events on the FIFO */ -static void callback(pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags f, void *userdata) { - char c; - assert(m && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == the_pipe[0]); - read(the_pipe[0], &c, sizeof(c)); - m->quit(m, 1); /* Quit the main loop */ -} - -/* Initializes CPU load limiter */ -int pa_cpu_limit_init(pa_mainloop_api *m) { - struct sigaction sa; - assert(m && !api && !io_event && the_pipe[0] == -1 && the_pipe[1] == -1 && !installed); - - time(&last_time); - - /* Prepare the main loop pipe */ - if (pipe(the_pipe) < 0) { - pa_log(__FILE__": pipe() failed: %s\n", strerror(errno)); - return -1; - } - - pa_make_nonblock_fd(the_pipe[0]); - pa_make_nonblock_fd(the_pipe[1]); - pa_fd_set_cloexec(the_pipe[0], 1); - pa_fd_set_cloexec(the_pipe[1], 1); - - api = m; - io_event = api->io_new(m, the_pipe[0], PA_IO_EVENT_INPUT, callback, NULL); - - phase = PHASE_IDLE; - - /* Install signal handler for SIGXCPU */ - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = signal_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - - if (sigaction(SIGXCPU, &sa, &sigaction_prev) < 0) { - pa_cpu_limit_done(); - return -1; - } - - installed = 1; - - reset_cpu_time(CPUTIME_INTERVAL_SOFT); - - return 0; -} - -/* Shutdown CPU load limiter */ -void pa_cpu_limit_done(void) { - int r; - - if (io_event) { - assert(api); - api->io_free(io_event); - io_event = NULL; - api = NULL; - } - - if (the_pipe[0] >= 0) - close(the_pipe[0]); - if (the_pipe[1] >= 0) - close(the_pipe[1]); - the_pipe[0] = the_pipe[1] = -1; - - if (installed) { - r = sigaction(SIGXCPU, &sigaction_prev, NULL); - assert(r >= 0); - installed = 0; - } -} - -#else /* HAVE_SIGXCPU */ - -int pa_cpu_limit_init(PA_GCC_UNUSED pa_mainloop_api *m) { - return 0; -} - -void pa_cpu_limit_done(void) { -} - -#endif diff --git a/polyp/cpulimit.h b/polyp/cpulimit.h deleted file mode 100644 index 8ca4f8d9..00000000 --- a/polyp/cpulimit.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef foocpulimithfoo -#define foocpulimithfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "mainloop-api.h" - -/* This kills the polypaudio process if it eats more than 70% of the - * CPU time. This is build around setrlimit() and SIGXCPU. It is handy - * in case of using SCHED_FIFO which may freeze the whole machine */ - -int pa_cpu_limit_init(pa_mainloop_api *m); -void pa_cpu_limit_done(void); - -#endif diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c deleted file mode 100644 index 103cf46a..00000000 --- a/polyp/daemon-conf.c +++ /dev/null @@ -1,297 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "daemon-conf.h" -#include "util.h" -#include "xmalloc.h" -#include "strbuf.h" -#include "conf-parser.h" -#include "resampler.h" - -#ifndef DEFAULT_CONFIG_DIR -# ifndef OS_IS_WIN32 -# define DEFAULT_CONFIG_DIR "/etc/polypaudio" -# else -# define DEFAULT_CONFIG_DIR "%POLYP_ROOT%" -# endif -#endif - -#ifndef OS_IS_WIN32 -# define PATH_SEP "/" -#else -# define PATH_SEP "\\" -#endif - -#define DEFAULT_SCRIPT_FILE DEFAULT_CONFIG_DIR PATH_SEP "default.pa" -#define DEFAULT_SCRIPT_FILE_USER ".polypaudio" PATH_SEP "default.pa" -#define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "daemon.conf" -#define DEFAULT_CONFIG_FILE_USER ".polypaudio" PATH_SEP "daemon.conf" - -#define ENV_SCRIPT_FILE "POLYP_SCRIPT" -#define ENV_CONFIG_FILE "POLYP_CONFIG" -#define ENV_DL_SEARCH_PATH "POLYP_DLPATH" - -static const pa_daemon_conf default_conf = { - .cmd = PA_CMD_DAEMON, - .daemonize = 0, - .fail = 1, - .high_priority = 0, - .disallow_module_loading = 0, - .exit_idle_time = -1, - .module_idle_time = 20, - .scache_idle_time = 20, - .auto_log_target = 1, - .script_commands = NULL, - .dl_search_path = NULL, - .default_script_file = NULL, - .log_target = PA_LOG_SYSLOG, - .log_level = PA_LOG_NOTICE, - .resample_method = PA_RESAMPLER_SRC_SINC_FASTEST, - .config_file = NULL, - .use_pid_file = 1 -}; - -pa_daemon_conf* pa_daemon_conf_new(void) { - FILE *f; - pa_daemon_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); - - if ((f = pa_open_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE, &c->default_script_file))) - fclose(f); - -#ifdef DLSEARCHPATH - c->dl_search_path = pa_xstrdup(DLSEARCHPATH); -#endif - return c; -} - -void pa_daemon_conf_free(pa_daemon_conf *c) { - assert(c); - pa_xfree(c->script_commands); - pa_xfree(c->dl_search_path); - pa_xfree(c->default_script_file); - pa_xfree(c->config_file); - pa_xfree(c); -} - -int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string) { - assert(c && string); - - if (!strcmp(string, "auto")) - c->auto_log_target = 1; - else if (!strcmp(string, "syslog")) { - c->auto_log_target = 0; - c->log_target = PA_LOG_SYSLOG; - } else if (!strcmp(string, "stderr")) { - c->auto_log_target = 0; - c->log_target = PA_LOG_STDERR; - } else - return -1; - - return 0; -} - -int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string) { - uint32_t u; - assert(c && string); - - if (pa_atou(string, &u) >= 0) { - if (u >= PA_LOG_LEVEL_MAX) - return -1; - - c->log_level = (pa_log_level_t) u; - } else if (pa_startswith(string, "debug")) - c->log_level = PA_LOG_DEBUG; - else if (pa_startswith(string, "info")) - c->log_level = PA_LOG_INFO; - else if (pa_startswith(string, "notice")) - c->log_level = PA_LOG_NOTICE; - else if (pa_startswith(string, "warn")) - c->log_level = PA_LOG_WARN; - else if (pa_startswith(string, "err")) - c->log_level = PA_LOG_ERROR; - else - return -1; - - return 0; -} - -int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string) { - int m; - assert(c && string); - - if ((m = pa_parse_resample_method(string)) < 0) - return -1; - - c->resample_method = m; - return 0; -} - -static int parse_log_target(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { - pa_daemon_conf *c = data; - assert(filename && lvalue && rvalue && data); - - if (pa_daemon_conf_set_log_target(c, rvalue) < 0) { - pa_log(__FILE__": [%s:%u] Invalid log target '%s'.\n", filename, line, rvalue); - return -1; - } - - return 0; -} - -static int parse_log_level(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { - pa_daemon_conf *c = data; - assert(filename && lvalue && rvalue && data); - - if (pa_daemon_conf_set_log_level(c, rvalue) < 0) { - pa_log(__FILE__": [%s:%u] Invalid log level '%s'.\n", filename, line, rvalue); - return -1; - } - - return 0; -} - -static int parse_resample_method(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { - pa_daemon_conf *c = data; - assert(filename && lvalue && rvalue && data); - - if (pa_daemon_conf_set_resample_method(c, rvalue) < 0) { - pa_log(__FILE__": [%s:%u] Inavalid resample method '%s'.\n", filename, line, rvalue); - return -1; - } - - return 0; -} - -int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { - int r = -1; - FILE *f = NULL; - - pa_config_item table[] = { - { "daemonize", pa_config_parse_bool, NULL }, - { "fail", pa_config_parse_bool, NULL }, - { "high-priority", pa_config_parse_bool, NULL }, - { "disallow-module-loading", pa_config_parse_bool, NULL }, - { "exit-idle-time", pa_config_parse_int, NULL }, - { "module-idle-time", pa_config_parse_int, NULL }, - { "scache-idle-time", pa_config_parse_int, NULL }, - { "dl-search-path", pa_config_parse_string, NULL }, - { "default-script-file", pa_config_parse_string, NULL }, - { "log-target", parse_log_target, NULL }, - { "log-level", parse_log_level, NULL }, - { "verbose", parse_log_level, NULL }, - { "resample-method", parse_resample_method, NULL }, - { "use-pid-file", pa_config_parse_bool, NULL }, - { NULL, NULL, NULL }, - }; - - table[0].data = &c->daemonize; - table[1].data = &c->fail; - table[2].data = &c->high_priority; - table[3].data = &c->disallow_module_loading; - table[4].data = &c->exit_idle_time; - table[5].data = &c->module_idle_time; - table[6].data = &c->scache_idle_time; - table[7].data = &c->dl_search_path; - table[8].data = &c->default_script_file; - table[9].data = c; - table[10].data = c; - table[11].data = c; - table[12].data = c; - table[13].data = &c->use_pid_file; - - pa_xfree(c->config_file); - c->config_file = NULL; - - f = filename ? - fopen(c->config_file = pa_xstrdup(filename), "r") : - pa_open_config_file(DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file); - - if (!f && errno != ENOENT) { - pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno)); - goto finish; - } - - r = f ? pa_config_parse(c->config_file, f, table, NULL) : 0; - -finish: - if (f) - fclose(f); - - return r; -} - -int pa_daemon_conf_env(pa_daemon_conf *c) { - char *e; - - if ((e = getenv(ENV_DL_SEARCH_PATH))) { - pa_xfree(c->dl_search_path); - c->dl_search_path = pa_xstrdup(e); - } - if ((e = getenv(ENV_SCRIPT_FILE))) { - pa_xfree(c->default_script_file); - c->default_script_file = pa_xstrdup(e); - } - - return 0; -} - -static const char* const log_level_to_string[] = { - [PA_LOG_DEBUG] = "debug", - [PA_LOG_INFO] = "info", - [PA_LOG_NOTICE] = "notice", - [PA_LOG_WARN] = "warning", - [PA_LOG_ERROR] = "error" -}; - -char *pa_daemon_conf_dump(pa_daemon_conf *c) { - pa_strbuf *s = pa_strbuf_new(); - - if (c->config_file) - pa_strbuf_printf(s, "### Read from configuration file: %s ###\n", c->config_file); - - assert(c->log_level <= PA_LOG_LEVEL_MAX); - - pa_strbuf_printf(s, "daemonize = %i\n", !!c->daemonize); - pa_strbuf_printf(s, "fail = %i\n", !!c->fail); - pa_strbuf_printf(s, "high-priority = %i\n", !!c->high_priority); - pa_strbuf_printf(s, "disallow-module-loading = %i\n", !!c->disallow_module_loading); - pa_strbuf_printf(s, "exit-idle-time = %i\n", c->exit_idle_time); - pa_strbuf_printf(s, "module-idle-time = %i\n", c->module_idle_time); - pa_strbuf_printf(s, "scache-idle-time = %i\n", c->scache_idle_time); - pa_strbuf_printf(s, "dl-search-path = %s\n", c->dl_search_path ? c->dl_search_path : ""); - pa_strbuf_printf(s, "default-script-file = %s\n", c->default_script_file); - pa_strbuf_printf(s, "log-target = %s\n", c->auto_log_target ? "auto" : (c->log_target == PA_LOG_SYSLOG ? "syslog" : "stderr")); - pa_strbuf_printf(s, "log-level = %s\n", log_level_to_string[c->log_level]); - pa_strbuf_printf(s, "resample-method = %s\n", pa_resample_method_to_string(c->resample_method)); - pa_strbuf_printf(s, "use-pid-file = %i\n", c->use_pid_file); - - return pa_strbuf_tostring_free(s); -} diff --git a/polyp/daemon-conf.h b/polyp/daemon-conf.h deleted file mode 100644 index cebc0bd6..00000000 --- a/polyp/daemon-conf.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef foodaemonconfhfoo -#define foodaemonconfhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "log.h" - -/* The actual command to execute */ -typedef enum pa_daemon_conf_cmd { - PA_CMD_DAEMON, /* the default */ - PA_CMD_HELP, - PA_CMD_VERSION, - PA_CMD_DUMP_CONF, - PA_CMD_DUMP_MODULES, - PA_CMD_KILL, - PA_CMD_CHECK -} pa_daemon_conf_cmd_t; - -/* A structure containing configuration data for the Polypaudio server . */ -typedef struct pa_daemon_conf { - pa_daemon_conf_cmd_t cmd; - int daemonize, - fail, - high_priority, - disallow_module_loading, - exit_idle_time, - module_idle_time, - scache_idle_time, - auto_log_target, - use_pid_file; - char *script_commands, *dl_search_path, *default_script_file; - pa_log_target_t log_target; - pa_log_level_t log_level; - int resample_method; - char *config_file; -} pa_daemon_conf; - -/* Allocate a new structure and fill it with sane defaults */ -pa_daemon_conf* pa_daemon_conf_new(void); -void pa_daemon_conf_free(pa_daemon_conf*c); - -/* Load configuration data from the specified file overwriting the - * current settings in *c. If filename is NULL load the default daemon - * configuration file */ -int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename); - -/* Pretty print the current configuration data of the daemon. The - * returned string has to be freed manually. The output of this - * function may be parsed with pa_daemon_conf_load(). */ -char *pa_daemon_conf_dump(pa_daemon_conf *c); - -/* Load the configuration data from the process' environment - * overwriting the current settings in *c. */ -int pa_daemon_conf_env(pa_daemon_conf *c); - -/* Set these configuration variables in the structure by passing a string */ -int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string); -int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string); -int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string); - -#endif diff --git a/polyp/daemon.conf.in b/polyp/daemon.conf.in deleted file mode 100644 index d5373018..00000000 --- a/polyp/daemon.conf.in +++ /dev/null @@ -1,77 +0,0 @@ -# $Id$ -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -## Configuration file for the polypaudio daemon. Default values are -## commented out. Use either ; or # for commenting - -# Extra verbositiy -; verbose = 0 - -## Daemonize after startup -; daemonize = 0 - -## Quit if startup fails -; fail = 1 - -## Renice the daemon to level -15 and try to get SCHED_FIFO -## scheduling. This a good idea if you hear annyoing noise in the -## playback. However, this is a certain security issue, since it works -## when called SUID root only. root is dropped immediately after gaining -## the nice level and SCHED_FIFO scheduling on startup. -; high-priority = 0 - -## Disallow module loading after startup -; disallow-module-loading = 0 - -## Terminate the daemon after the last client quit and this time -## passed. Use a negative value to disable this feature. -; exit-idle-time = -1 - -## Unload autoloaded modules after being idle for this time -; module-idle-time = 20 - -## The path were to look for dynamic shared objects (DSOs aka -## plugins). You may specify more than one path seperated by -## colons. -; dl-search-path = @DLSEARCHPATH@ - -## The default script file to load. Specify an empty string for not -## loading a default script file. The -; default-script-file = @DEFAULT_CONFIG_FILE@ - -## The default log target. Use either "stderr", "syslog" or -## "auto". The latter is equivalent to "sylog" in case daemonize is -## true, otherwise to "stderr". -; log-target = auto - -## The resampling algorithm to use. Use one of src-sinc-best-quality, -## src-sinc-medium-quality, src-sinc-fastest, src-zero-order-hold, -## src-linear, trivial. See the documentation of libsamplerate for an -## explanation for the different methods. The method 'trivial' is the -## only algorithm implemented without usage of floating point -## numbers. If you're tight on CPU consider using this. On the other -## hand it has the worst quality of all. -; resample-method = sinc-fastest - -## Create a PID file in /tmp/polypaudio-$USER/pid. Of this is enabled -## you may use commands like "polypaudio --kill" or "polypaudio -## --check". If you are planning to start more than one polypaudio -## process per user, you better disable this option since it -## effectively disables multiple instances. -; use-pid-file = 1 diff --git a/polyp/default.pa.in b/polyp/default.pa.in deleted file mode 100755 index 3aaeeaf0..00000000 --- a/polyp/default.pa.in +++ /dev/null @@ -1,66 +0,0 @@ -#!@POLYPAUDIO_BINARY@ -nF - -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - - -# Load audio drivers statically - -#load-module module-alsa-sink -# load-module module-alsa-source device=plughw:1,0 -load-module module-oss device="/dev/dsp" sink_name=output source_name=input -#load-module module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -load-module module-null-sink -#load-module module-pipe-sink - -# Load audio drivers automatically on access - -#add-autoload-sink output module-oss device="/dev/dsp" sink_name=output source_name=input -#add-autoload-source input module-oss device="/dev/dsp" sink_name=output source_name=input -#add-autoload-sink output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#add-autoload-source input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#add-autoload-sink output module-alsa-sink sink_name=output -#add-autoload-source input module-alsa-source source_name=input - -# Load several protocols -load-module module-esound-protocol-unix -#load-module module-esound-protocol-tcp -load-module module-native-protocol-unix -#load-module module-simple-protocol-tcp -#load-module module-cli-protocol-unix - -# Load the CLI module -load-module module-cli - -# Make some devices default -set-default-sink output -set-default-source input - -.nofail - -# Load something to the sample cache -load-sample x11-bell /usr/share/sounds/KDE_Notify.wav -load-sample-dir-lazy /usr/share/sounds/*.wav - -# Load X11 bell module -load-module module-x11-bell sample=x11-bell sink=output - -# Publish connection data in the X11 root window -load-module module-x11-publish - -#load-module module-pipe-source -#load-module module-pipe-sink diff --git a/polyp/default.pa.win32 b/polyp/default.pa.win32 deleted file mode 100644 index 3478adab..00000000 --- a/polyp/default.pa.win32 +++ /dev/null @@ -1,43 +0,0 @@ -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - - -# Load audio drivers statically - -load-module module-waveout sink_name=output source_name=input -load-module module-null-sink - -# Load audio drivers automatically on access - -#add-autoload-sink output module-waveout sink_name=output source_name=input -#add-autoload-source input module-waveout sink_name=output source_name=input - -# Load several protocols -#load-module module-esound-protocol-tcp -#load-module module-native-protocol-tcp -#load-module module-simple-protocol-tcp -#load-module module-cli-protocol-tcp - -# Make some devices default -set-default-sink output -set-default-source input - -.nofail - -# Load something to the sample cache -load-sample x11-bell %WINDIR%\Media\ding.wav -load-sample-dir-lazy %WINDIR%\Media\*.wav diff --git a/polyp/depmod.py b/polyp/depmod.py deleted file mode 100755 index 7bb223b1..00000000 --- a/polyp/depmod.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/python -# $Id$ -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -import sys, os, string - -exported_symbols = {} -imported_symbols = {} - -for fn in sys.argv[1:]: - f = os.popen("nm '%s'" % fn, "r") - - imported_symbols[fn] = [] - - for line in f: - sym_address = line[:7].strip() - sym_type = line[9].strip() - sym_name = line[11:].strip() - - if sym_name in ('_fini', '_init'): - continue - - if sym_type in ('T', 'B', 'R', 'D' 'G', 'S', 'D'): - if exported_symbols.has_key(sym_name): - sys.stderr.write("CONFLICT: %s defined in both '%s' and '%s'.\n" % (sym_name, fn, exported_symbols[sym_name])) - else: - exported_symbols[sym_name] = fn - elif sym_type in ('U',): - if sym_name[:3] == 'pa_': - imported_symbols[fn].append(sym_name) - - f.close() - -dependencies = {} -unresolved_symbols = {} - -for fn in imported_symbols: - dependencies[fn] = [] - - for sym in imported_symbols[fn]: - if exported_symbols.has_key(sym): - if exported_symbols[sym] not in dependencies[fn]: - dependencies[fn].append(exported_symbols[sym]) - else: - if unresolved_symbols.has_key(sym): - unresolved_symbols[sym].append(fn) - else: - unresolved_symbols[sym] = [fn] - -for sym, files in unresolved_symbols.iteritems(): - print "WARNING: Unresolved symbol '%s' in %s" % (sym, `files`) - -k = dependencies.keys() -k.sort() -for fn in k: - dependencies[fn].sort() - print "%s: %s" % (fn, string.join(dependencies[fn], " ")) diff --git a/polyp/dllmain.c b/polyp/dllmain.c deleted file mode 100644 index d1d120ab..00000000 --- a/polyp/dllmain.c +++ /dev/null @@ -1,46 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifdef OS_IS_WIN32 - -#include -#include -#include - -#include - -extern pa_set_root(HANDLE handle); - -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { - if (fdwReason != DLL_PROCESS_ATTACH) - return TRUE; - - if (!pa_set_root(hinstDLL)) - return FALSE; - - return TRUE; -} - -#endif /* OS_IS_WIN32 */ diff --git a/polyp/dumpmodules.c b/polyp/dumpmodules.c deleted file mode 100644 index 6864b965..00000000 --- a/polyp/dumpmodules.c +++ /dev/null @@ -1,99 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "dumpmodules.h" -#include "modinfo.h" -#include "util.h" - -#define PREFIX "module-" - -static void short_info(const char *name, PA_GCC_UNUSED const char *path, pa_modinfo *i) { - assert(name && i); - printf("%-40s%s\n", name, i->description ? i->description : "n/a"); -} - -static void long_info(const char *name, const char *path, pa_modinfo *i) { - static int nl = 0; - assert(name && i); - - if (nl) - printf("\n"); - - nl = 1; - - printf("Name: %s\n", name); - - if (!i->description && !i->version && !i->author && !i->usage) - printf("No module information available\n"); - else { - if (i->version) - printf("Version: %s\n", i->version); - if (i->description) - printf("Description: %s\n", i->description); - if (i->author) - printf("Author: %s\n", i->author); - if (i->usage) - printf("Usage: %s\n", i->usage); - } - - if (path) - printf("Path: %s\n", path); -} - -static void show_info(const char *name, const char *path, void (*info)(const char *name, const char *path, pa_modinfo*i)) { - pa_modinfo *i; - - if ((i = pa_modinfo_get_by_name(path ? path : name))) { - info(name, path, i); - pa_modinfo_free(i); - } -} - -static int callback(const char *path, lt_ptr data) { - const char *e; - pa_daemon_conf *c = (data); - - e = pa_path_get_filename(path); - - if (strlen(e) > sizeof(PREFIX)-1 && !strncmp(e, PREFIX, sizeof(PREFIX)-1)) - show_info(e, path, c->log_level >= PA_LOG_INFO ? long_info : short_info); - - return 0; -} - -void pa_dump_modules(pa_daemon_conf *c, int argc, char * const argv[]) { - if (argc > 0) { - int i; - for (i = 0; i < argc; i++) - show_info(argv[i], NULL, long_info); - } else - lt_dlforeachfile(NULL, callback, c); -} diff --git a/polyp/dumpmodules.h b/polyp/dumpmodules.h deleted file mode 100644 index 968d2de9..00000000 --- a/polyp/dumpmodules.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef foodumpmoduleshfoo -#define foodumpmoduleshfoo - -/* $Id*/ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "daemon-conf.h" - -/* Dump all available modules to STDOUT. If argc > 0 print information - * about the modules specified in argv[] instead. */ -void pa_dump_modules(pa_daemon_conf *c, int argc, char * const argv[]); - -#endif diff --git a/polyp/dynarray.c b/polyp/dynarray.c deleted file mode 100644 index 435fd768..00000000 --- a/polyp/dynarray.c +++ /dev/null @@ -1,102 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "dynarray.h" -#include "xmalloc.h" - -/* If the array becomes to small, increase its size by 100 entries */ -#define INCREASE_BY 100 - -struct pa_dynarray { - void **data; - unsigned n_allocated, n_entries; -}; - -pa_dynarray* pa_dynarray_new(void) { - pa_dynarray *a; - a = pa_xnew(pa_dynarray, 1); - a->data = NULL; - a->n_entries = 0; - a->n_allocated = 0; - return a; -} - -void pa_dynarray_free(pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata) { - unsigned i; - assert(a); - - if (func) - for (i = 0; i < a->n_entries; i++) - if (a->data[i]) - func(a->data[i], userdata); - - pa_xfree(a->data); - pa_xfree(a); -} - -void pa_dynarray_put(pa_dynarray*a, unsigned i, void *p) { - assert(a); - - if (i >= a->n_allocated) { - unsigned n; - - if (!p) - return; - - n = i+INCREASE_BY; - a->data = pa_xrealloc(a->data, sizeof(void*)*n); - memset(a->data+a->n_allocated, 0, sizeof(void*)*(n-a->n_allocated)); - a->n_allocated = n; - } - - a->data[i] = p; - - if (i >= a->n_entries) - a->n_entries = i+1; -} - -unsigned pa_dynarray_append(pa_dynarray*a, void *p) { - unsigned i = a->n_entries; - pa_dynarray_put(a, i, p); - return i; -} - -void *pa_dynarray_get(pa_dynarray*a, unsigned i) { - assert(a); - if (i >= a->n_allocated) - return NULL; - - assert(a->data); - return a->data[i]; -} - -unsigned pa_dynarray_size(pa_dynarray*a) { - assert(a); - return a->n_entries; -} diff --git a/polyp/dynarray.h b/polyp/dynarray.h deleted file mode 100644 index 9b1601ba..00000000 --- a/polyp/dynarray.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef foodynarrayhfoo -#define foodynarrayhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -typedef struct pa_dynarray pa_dynarray; - -/* Implementation of a simple dynamically sized array. The array - * expands if required, but doesn't shrink if possible. Memory - * management of the array's entries is the user's job. */ - -pa_dynarray* pa_dynarray_new(void); - -/* Free the array calling the specified function for every entry in - * the array. The function may be NULL. */ -void pa_dynarray_free(pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata); - -/* Store p at position i in the array */ -void pa_dynarray_put(pa_dynarray*a, unsigned i, void *p); - -/* Store p a the first free position in the array. Returns the index - * of that entry. If entries are removed from the array their position - * are not filled any more by this function. */ -unsigned pa_dynarray_append(pa_dynarray*a, void *p); - -void *pa_dynarray_get(pa_dynarray*a, unsigned i); - -unsigned pa_dynarray_size(pa_dynarray*a); - -#endif diff --git a/polyp/endianmacros.h b/polyp/endianmacros.h deleted file mode 100644 index 3ab1826a..00000000 --- a/polyp/endianmacros.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef fooendianmacroshfoo -#define fooendianmacroshfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define INT16_SWAP(x) ( (int16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) ) -#define UINT16_SWAP(x) ( (uint16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) ) -#define INT32_SWAP(x) ( (int32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) ) -#define UINT32_SWAP(x) ( (uint32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) ) - -#define MAYBE_INT32_SWAP(c,x) ((c) ? INT32_SWAP(x) : x) -#define MAYBE_UINT32_SWAP(c,x) ((c) ? UINT32_SWAP(x) : x) - -#ifdef WORDS_BIGENDIAN - #define INT16_FROM_LE(x) INT16_SWAP(x) - #define INT16_FROM_BE(x) ((int16_t)(x)) - - #define INT16_TO_LE(x) INT16_SWAP(x) - #define INT16_TO_BE(x) ((int16_t)(x)) - - #define UINT16_FROM_LE(x) UINT16_SWAP(x) - #define UINT16_FROM_BE(x) ((uint16_t)(x)) - - #define INT32_FROM_LE(x) INT32_SWAP(x) - #define INT32_FROM_BE(x) ((int32_t)(x)) - - #define UINT32_FROM_LE(x) UINT32_SWAP(x) - #define UINT32_FROM_BE(x) ((uint32_t)(x)) - - #define UINT32_TO_LE(x) UINT32_SWAP(x) - #define UINT32_TO_BE(x) ((uint32_t)(x)) -#else - #define INT16_FROM_LE(x) ((int16_t)(x)) - #define INT16_FROM_BE(x) INT16_SWAP(x) - - #define INT16_TO_LE(x) ((int16_t)(x)) - #define INT16_TO_BE(x) INT16_SWAP(x) - - #define UINT16_FROM_LE(x) ((uint16_t)(x)) - #define UINT16_FROM_BE(x) UINT16_SWAP(x) - - #define INT32_FROM_LE(x) ((int32_t)(x)) - #define INT32_FROM_BE(x) INT32_SWAP(x) - - #define UINT32_FROM_LE(x) ((uint32_t)(x)) - #define UINT32_FROM_BE(x) UINT32_SWAP(x) - - #define UINT32_TO_LE(x) ((uint32_t)(x)) - #define UINT32_TO_BE(x) UINT32_SWAP(x) -#endif - -#endif diff --git a/polyp/esdcompat.sh.in b/polyp/esdcompat.sh.in deleted file mode 100755 index 76023f52..00000000 --- a/polyp/esdcompat.sh.in +++ /dev/null @@ -1,98 +0,0 @@ -#!/bin/sh - -# $Id$ -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -VERSION_STRING="@PACKAGE_NAME@ esd wrapper @PACKAGE_VERSION@" - -fail() { - echo "ERROR: $1" - exit 1 -} - -ARGS=" --log-target=syslog" - -for N in $(seq $#) ; do - - case "$1" in - "") - ;; - - -v|--version) - echo "$VERSION_STRING" - exit 0 - ;; - - -h|--help) - cat <> 3; */ - - /* A-law using even bit inversion */ - if (pcm_val >= 0) { - mask = 0xD5; /* sign (7th) bit = 1 */ - } else { - mask = 0x55; /* sign bit = 0 */ - pcm_val = -pcm_val - 1; - } - - /* Convert the scaled magnitude to segment number. */ - seg = search(pcm_val, seg_aend, 8); - - /* Combine the sign, segment, and quantization bits. */ - - if (seg >= 8) /* out of range, return maximum value. */ - return (unsigned char) (0x7F ^ mask); - else { - aval = (unsigned char) seg << SEG_SHIFT; - if (seg < 2) - aval |= (pcm_val >> 1) & QUANT_MASK; - else - aval |= (pcm_val >> seg) & QUANT_MASK; - return (aval ^ mask); - } -} - -/* - * alaw2linear() - Convert an A-law value to 16-bit signed linear PCM - * - */ -int16_t st_alaw2linear16( - unsigned char a_val) -{ - int16_t t; - int16_t seg; - - a_val ^= 0x55; - - t = (a_val & QUANT_MASK) << 4; - seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT; - switch (seg) { - case 0: - t += 8; - break; - case 1: - t += 0x108; - break; - default: - t += 0x108; - t <<= seg - 1; - } - return ((a_val & SIGN_BIT) ? t : -t); -} -#endif /* !FAST_ALAW_CONVERSION */ - -#define BIAS (0x84) /* Bias for linear code. */ -#define CLIP 8159 - -#ifndef FAST_ULAW_CONVERSION -/* - * linear2ulaw() accepts a 14-bit signed integer and encodes it as u-law data - * stored in a unsigned char. This function should only be called with - * the data shifted such that it only contains information in the lower - * 14-bits. - * - * In order to simplify the encoding process, the original linear magnitude - * is biased by adding 33 which shifts the encoding range from (0 - 8158) to - * (33 - 8191). The result can be seen in the following encoding table: - * - * Biased Linear Input Code Compressed Code - * ------------------------ --------------- - * 00000001wxyza 000wxyz - * 0000001wxyzab 001wxyz - * 000001wxyzabc 010wxyz - * 00001wxyzabcd 011wxyz - * 0001wxyzabcde 100wxyz - * 001wxyzabcdef 101wxyz - * 01wxyzabcdefg 110wxyz - * 1wxyzabcdefgh 111wxyz - * - * Each biased linear code has a leading 1 which identifies the segment - * number. The value of the segment number is equal to 7 minus the number - * of leading 0's. The quantization interval is directly available as the - * four bits wxyz. * The trailing bits (a - h) are ignored. - * - * Ordinarily the complement of the resulting code word is used for - * transmission, and so the code word is complemented before it is returned. - * - * For further information see John C. Bellamy's Digital Telephony, 1982, - * John Wiley & Sons, pps 98-111 and 472-476. - */ -unsigned char st_14linear2ulaw( - int16_t pcm_val) /* 2's complement (14-bit range) */ -{ - int16_t mask; - int16_t seg; - unsigned char uval; - - /* Have calling software do it since its already doing a shift - * from 32-bits down to 16-bits. - */ - /* pcm_val = pcm_val >> 2; */ - - /* u-law inverts all bits */ - /* Get the sign and the magnitude of the value. */ - if (pcm_val < 0) { - pcm_val = -pcm_val; - mask = 0x7F; - } else { - mask = 0xFF; - } - if ( pcm_val > CLIP ) pcm_val = CLIP; /* clip the magnitude */ - pcm_val += (BIAS >> 2); - - /* Convert the scaled magnitude to segment number. */ - seg = search(pcm_val, seg_uend, 8); - - /* - * Combine the sign, segment, quantization bits; - * and complement the code word. - */ - if (seg >= 8) /* out of range, return maximum value. */ - return (unsigned char) (0x7F ^ mask); - else { - uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF); - return (uval ^ mask); - } - -} - -/* - * ulaw2linear() - Convert a u-law value to 16-bit linear PCM - * - * First, a biased linear code is derived from the code word. An unbiased - * output can then be obtained by subtracting 33 from the biased code. - * - * Note that this function expects to be passed the complement of the - * original code word. This is in keeping with ISDN conventions. - */ -int16_t st_ulaw2linear16( - unsigned char u_val) -{ - int16_t t; - - /* Complement to obtain normal u-law value. */ - u_val = ~u_val; - - /* - * Extract and bias the quantization bits. Then - * shift up by the segment number and subtract out the bias. - */ - t = ((u_val & QUANT_MASK) << 3) + BIAS; - t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; - - return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); -} -#endif /* !FAST_ULAW_CONVERSION */ - -#ifdef FAST_ALAW_CONVERSION - -int16_t _st_alaw2linear16[256] = { - -5504, -5248, -6016, -5760, -4480, -4224, -4992, - -4736, -7552, -7296, -8064, -7808, -6528, -6272, - -7040, -6784, -2752, -2624, -3008, -2880, -2240, - -2112, -2496, -2368, -3776, -3648, -4032, -3904, - -3264, -3136, -3520, -3392, -22016, -20992, -24064, - -23040, -17920, -16896, -19968, -18944, -30208, -29184, - -32256, -31232, -26112, -25088, -28160, -27136, -11008, - -10496, -12032, -11520, -8960, -8448, -9984, -9472, - -15104, -14592, -16128, -15616, -13056, -12544, -14080, - -13568, -344, -328, -376, -360, -280, -264, - -312, -296, -472, -456, -504, -488, -408, - -392, -440, -424, -88, -72, -120, -104, - -24, -8, -56, -40, -216, -200, -248, - -232, -152, -136, -184, -168, -1376, -1312, - -1504, -1440, -1120, -1056, -1248, -1184, -1888, - -1824, -2016, -1952, -1632, -1568, -1760, -1696, - -688, -656, -752, -720, -560, -528, -624, - -592, -944, -912, -1008, -976, -816, -784, - -880, -848, 5504, 5248, 6016, 5760, 4480, - 4224, 4992, 4736, 7552, 7296, 8064, 7808, - 6528, 6272, 7040, 6784, 2752, 2624, 3008, - 2880, 2240, 2112, 2496, 2368, 3776, 3648, - 4032, 3904, 3264, 3136, 3520, 3392, 22016, - 20992, 24064, 23040, 17920, 16896, 19968, 18944, - 30208, 29184, 32256, 31232, 26112, 25088, 28160, - 27136, 11008, 10496, 12032, 11520, 8960, 8448, - 9984, 9472, 15104, 14592, 16128, 15616, 13056, - 12544, 14080, 13568, 344, 328, 376, 360, - 280, 264, 312, 296, 472, 456, 504, - 488, 408, 392, 440, 424, 88, 72, - 120, 104, 24, 8, 56, 40, 216, - 200, 248, 232, 152, 136, 184, 168, - 1376, 1312, 1504, 1440, 1120, 1056, 1248, - 1184, 1888, 1824, 2016, 1952, 1632, 1568, - 1760, 1696, 688, 656, 752, 720, 560, - 528, 624, 592, 944, 912, 1008, 976, - 816, 784, 880, 848 -}; - -uint8_t _st_13linear2alaw[0x2000] = { - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, - 0x6b, 0x6b, 0x6b, 0x6b, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, - 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x6e, 0x6e, 0x6e, 0x6e, - 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, - 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, - 0x6d, 0x6d, 0x6d, 0x6d, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x60, 0x60, 0x60, 0x60, - 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, - 0x67, 0x67, 0x67, 0x67, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, - 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x7a, 0x7a, 0x7a, 0x7a, - 0x7b, 0x7b, 0x7b, 0x7b, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, - 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7c, 0x7c, 0x7c, 0x7c, - 0x7d, 0x7d, 0x7d, 0x7d, 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x73, - 0x70, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x71, 0x76, 0x76, 0x76, 0x76, - 0x77, 0x77, 0x77, 0x77, 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x75, - 0x4a, 0x4a, 0x4b, 0x4b, 0x48, 0x48, 0x49, 0x49, 0x4e, 0x4e, 0x4f, 0x4f, - 0x4c, 0x4c, 0x4d, 0x4d, 0x42, 0x42, 0x43, 0x43, 0x40, 0x40, 0x41, 0x41, - 0x46, 0x46, 0x47, 0x47, 0x44, 0x44, 0x45, 0x45, 0x5a, 0x5a, 0x5b, 0x5b, - 0x58, 0x58, 0x59, 0x59, 0x5e, 0x5e, 0x5f, 0x5f, 0x5c, 0x5c, 0x5d, 0x5d, - 0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51, 0x56, 0x56, 0x57, 0x57, - 0x54, 0x54, 0x55, 0x55, 0xd5, 0xd5, 0xd4, 0xd4, 0xd7, 0xd7, 0xd6, 0xd6, - 0xd1, 0xd1, 0xd0, 0xd0, 0xd3, 0xd3, 0xd2, 0xd2, 0xdd, 0xdd, 0xdc, 0xdc, - 0xdf, 0xdf, 0xde, 0xde, 0xd9, 0xd9, 0xd8, 0xd8, 0xdb, 0xdb, 0xda, 0xda, - 0xc5, 0xc5, 0xc4, 0xc4, 0xc7, 0xc7, 0xc6, 0xc6, 0xc1, 0xc1, 0xc0, 0xc0, - 0xc3, 0xc3, 0xc2, 0xc2, 0xcd, 0xcd, 0xcc, 0xcc, 0xcf, 0xcf, 0xce, 0xce, - 0xc9, 0xc9, 0xc8, 0xc8, 0xcb, 0xcb, 0xca, 0xca, 0xf5, 0xf5, 0xf5, 0xf5, - 0xf4, 0xf4, 0xf4, 0xf4, 0xf7, 0xf7, 0xf7, 0xf7, 0xf6, 0xf6, 0xf6, 0xf6, - 0xf1, 0xf1, 0xf1, 0xf1, 0xf0, 0xf0, 0xf0, 0xf0, 0xf3, 0xf3, 0xf3, 0xf3, - 0xf2, 0xf2, 0xf2, 0xf2, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xf9, 0xf9, 0xf9, 0xf9, - 0xf8, 0xf8, 0xf8, 0xf8, 0xfb, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xfa, - 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4, - 0xe4, 0xe4, 0xe4, 0xe4, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, - 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe1, 0xe1, 0xe1, 0xe1, - 0xe1, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, - 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, - 0xe2, 0xe2, 0xe2, 0xe2, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, - 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xef, 0xef, 0xef, 0xef, - 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, - 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, - 0xe8, 0xe8, 0xe8, 0xe8, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, - 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa -}; - -#endif /* FAST_ALAW_CONVERSION */ - -#ifdef FAST_ULAW_CONVERSION - -int16_t _st_ulaw2linear16[256] = { - -32124, -31100, -30076, -29052, -28028, -27004, -25980, - -24956, -23932, -22908, -21884, -20860, -19836, -18812, - -17788, -16764, -15996, -15484, -14972, -14460, -13948, - -13436, -12924, -12412, -11900, -11388, -10876, -10364, - -9852, -9340, -8828, -8316, -7932, -7676, -7420, - -7164, -6908, -6652, -6396, -6140, -5884, -5628, - -5372, -5116, -4860, -4604, -4348, -4092, -3900, - -3772, -3644, -3516, -3388, -3260, -3132, -3004, - -2876, -2748, -2620, -2492, -2364, -2236, -2108, - -1980, -1884, -1820, -1756, -1692, -1628, -1564, - -1500, -1436, -1372, -1308, -1244, -1180, -1116, - -1052, -988, -924, -876, -844, -812, -780, - -748, -716, -684, -652, -620, -588, -556, - -524, -492, -460, -428, -396, -372, -356, - -340, -324, -308, -292, -276, -260, -244, - -228, -212, -196, -180, -164, -148, -132, - -120, -112, -104, -96, -88, -80, -72, - -64, -56, -48, -40, -32, -24, -16, - -8, 0, 32124, 31100, 30076, 29052, 28028, - 27004, 25980, 24956, 23932, 22908, 21884, 20860, - 19836, 18812, 17788, 16764, 15996, 15484, 14972, - 14460, 13948, 13436, 12924, 12412, 11900, 11388, - 10876, 10364, 9852, 9340, 8828, 8316, 7932, - 7676, 7420, 7164, 6908, 6652, 6396, 6140, - 5884, 5628, 5372, 5116, 4860, 4604, 4348, - 4092, 3900, 3772, 3644, 3516, 3388, 3260, - 3132, 3004, 2876, 2748, 2620, 2492, 2364, - 2236, 2108, 1980, 1884, 1820, 1756, 1692, - 1628, 1564, 1500, 1436, 1372, 1308, 1244, - 1180, 1116, 1052, 988, 924, 876, 844, - 812, 780, 748, 716, 684, 652, 620, - 588, 556, 524, 492, 460, 428, 396, - 372, 356, 340, 324, 308, 292, 276, - 260, 244, 228, 212, 196, 180, 164, - 148, 132, 120, 112, 104, 96, 88, - 80, 72, 64, 56, 48, 40, 32, - 24, 16, 8, 0 -}; - -uint8_t _st_14linear2ulaw[0x4000] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x40, 0x40, - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, - 0x40, 0x40, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, - 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, - 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, - 0x43, 0x43, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, - 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, - 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x46, 0x46, - 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, - 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, - 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, - 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, - 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, - 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, - 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, - 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, - 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, - 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, - 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, - 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, - 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, - 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, - 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, - 0x52, 0x52, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, - 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x57, 0x57, - 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, - 0x58, 0x58, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a, 0x5a, - 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, - 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, - 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, - 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x60, 0x60, - 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x62, 0x63, 0x63, - 0x63, 0x63, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, - 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, - 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, - 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, - 0x6f, 0x6f, 0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x74, 0x74, - 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a, - 0x7b, 0x7b, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0xff, 0xfe, 0xfe, 0xfd, - 0xfd, 0xfc, 0xfc, 0xfb, 0xfb, 0xfa, 0xfa, 0xf9, 0xf9, 0xf8, 0xf8, 0xf7, - 0xf7, 0xf6, 0xf6, 0xf5, 0xf5, 0xf4, 0xf4, 0xf3, 0xf3, 0xf2, 0xf2, 0xf1, - 0xf1, 0xf0, 0xf0, 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xed, - 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xeb, 0xeb, 0xeb, 0xeb, 0xea, - 0xea, 0xea, 0xea, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, 0xe7, - 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, - 0xe4, 0xe4, 0xe4, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, 0xe1, - 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, - 0xdf, 0xdf, 0xdf, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, - 0xdc, 0xdc, 0xdc, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xda, - 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, - 0xd9, 0xd9, 0xd9, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd7, - 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, - 0xd6, 0xd6, 0xd6, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd4, - 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, - 0xd3, 0xd3, 0xd3, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd1, - 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, - 0xd0, 0xd0, 0xd0, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, - 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xce, 0xce, 0xce, 0xce, 0xce, - 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xcd, - 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, - 0xcd, 0xcd, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, - 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, - 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xca, - 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, - 0xca, 0xca, 0xca, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, - 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, - 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc7, - 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, - 0xc7, 0xc7, 0xc7, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, - 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, - 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc4, - 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, - 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, - 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, - 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc1, - 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, - 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, - 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80 -}; - -#endif /* FAST_ULAW_CONVERSION */ - -/* The following code was used to generate the lookup tables */ -#if 0 -int main() -{ - int x, y, find2a = 0; - - y = 0; - printf("int16_t _st_alaw2linear16[256] = {\n "); - for (x = 0; x < 256; x++) - { - printf("%8d,", st_alaw2linear16(x)); - y++; - if (y == 7) - { - y = 0; - printf("\n "); - } - } - - printf("\n};\n\nuint8_t _st_13linear2alaw[0x2000] = {\n "); - y = 0; - for (x = 0; x < 0x2000; x++) - { - printf(" 0x%02x,", st_13linear2alaw((-0x1000)+x)); - y++; - if (y == 12) - { - y = 0; - printf("\n "); - } - } - - printf("\n};\n\nint16_t _st_ulaw2linear16[256] = {\n "); - y = 0; - for (x = 0; x < 256; x++) - { - printf("%8d,", st_ulaw2linear16(x)); - y++; - if (y == 7) - { - y = 0; - printf("\n "); - } - } - - printf("\n};\n\nuint8_t _st_14linear2ulaw[0x4000] = {\n "); - y = 0; - for (x = 0; x < 0x4000; x++) - { - printf(" 0x%02x,", st_14linear2ulaw((-0x2000)+x)); - y++; - if (y == 12) - { - y = 0; - printf("\n "); - } - } - printf("\n};\n"); - -} -#endif - -/* The following is not used by SoX but kept for reference */ -#if 0 -/* copy from CCITT G.711 specifications */ -unsigned char _u2a[128] = { /* u- to A-law conversions */ - 1, 1, 2, 2, 3, 3, 4, 4, - 5, 5, 6, 6, 7, 7, 8, 8, - 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, - 25, 27, 29, 31, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, - 46, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, - 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, -/* corrected: - 81, 82, 83, 84, 85, 86, 87, 88, - should be: */ - 80, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, 126, 127, 128}; - -unsigned char _a2u[128] = { /* A- to u-law conversions */ - 1, 3, 5, 7, 9, 11, 13, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 32, 33, 33, 34, 34, 35, 35, - 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 48, 49, 49, - 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 64, - 65, 66, 67, 68, 69, 70, 71, 72, -/* corrected: - 73, 74, 75, 76, 77, 78, 79, 79, - should be: */ - 73, 74, 75, 76, 77, 78, 79, 80, - - 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127}; - -/* A-law to u-law conversion */ -unsigned char st_alaw2ulaw( - unsigned char aval) -{ - aval &= 0xff; - return (unsigned char) ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) : - (0x7F ^ _a2u[aval ^ 0x55])); -} - -/* u-law to A-law conversion */ -unsigned char st_ulaw2alaw( - unsigned char uval) -{ - uval &= 0xff; - return (unsigned char) ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) : - (unsigned char) (0x55 ^ (_u2a[0x7F ^ uval] - 1))); -} -#endif diff --git a/polyp/g711.h b/polyp/g711.h deleted file mode 100644 index 97cedf81..00000000 --- a/polyp/g711.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef foog711hfoo -#define foog711hfoo - -/* g711.h - include for G711 u-law and a-law conversion routines -** -** Copyright (C) 2001 Chris Bagwell -** -** Permission to use, copy, modify, and distribute this software and its -** documentation for any purpose and without fee is hereby granted, provided -** that the above copyright notice appear in all copies and that both that -** copyright notice and this permission notice appear in supporting -** documentation. This software is provided "as is" without express or -** implied warranty. -*/ - -/** Copied from sox -- Lennart Poettring*/ - -#include - -#ifdef FAST_ALAW_CONVERSION -extern uint8_t _st_13linear2alaw[0x2000]; -extern int16_t _st_alaw2linear16[256]; -#define st_13linear2alaw(sw) (_st_13linear2alaw[(sw + 0x1000)]) -#define st_alaw2linear16(uc) (_st_alaw2linear16[uc]) -#else -unsigned char st_13linear2alaw(int16_t pcm_val); -int16_t st_alaw2linear16(unsigned char); -#endif - -#ifdef FAST_ULAW_CONVERSION -extern uint8_t _st_14linear2ulaw[0x4000]; -extern int16_t _st_ulaw2linear16[256]; -#define st_14linear2ulaw(sw) (_st_14linear2ulaw[(sw + 0x2000)]) -#define st_ulaw2linear16(uc) (_st_ulaw2linear16[uc]) -#else -unsigned char st_14linear2ulaw(int16_t pcm_val); -int16_t st_ulaw2linear16(unsigned char); -#endif - -#endif diff --git a/polyp/gccmacro.h b/polyp/gccmacro.h deleted file mode 100644 index 9e212f2e..00000000 --- a/polyp/gccmacro.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef foogccmacrohfoo -#define foogccmacrohfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef __GNUC__ -#define PA_GCC_PRINTF_ATTR(a,b) __attribute__ ((format (printf, a, b))) -#else -/** If we're in GNU C, use some magic for detecting invalid format strings */ -#define PA_GCC_PRINTF_ATTR(a,b) -#endif - -#if defined(__GNUC__) && (__GNUC__ >= 4) -#define PA_GCC_SENTINEL __attribute__ ((sentinel)) -#else -/** Macro for usage of GCC's sentinel compilation warnings */ -#define PA_GCC_SENTINEL -#endif - -#ifdef __GNUC__ -#define PA_GCC_NORETURN __attribute__((noreturn)) -#else -/** Macro for no-return functions */ -#define PA_GCC_NORETURN -#endif - -#ifdef __GNUC__ -#define PA_GCC_UNUSED __attribute__ ((unused)) -#else -/** Macro for not used parameter */ -#define PA_GCC_UNUSED -#endif - -#endif diff --git a/polyp/glib-mainloop.c b/polyp/glib-mainloop.c deleted file mode 100644 index 6f7c1dc5..00000000 --- a/polyp/glib-mainloop.c +++ /dev/null @@ -1,538 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "glib-mainloop.h" -#include "idxset.h" -#include "xmalloc.h" -#include "glib.h" -#include "util.h" - -struct pa_io_event { - pa_glib_mainloop *mainloop; - int dead; - GIOChannel *io_channel; - GSource *source; - GIOCondition io_condition; - int fd; - void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_io_event *e, void *userdata); - pa_io_event *next, *prev; -}; - -struct pa_time_event { - pa_glib_mainloop *mainloop; - int dead; - GSource *source; - struct timeval timeval; - void (*callback) (pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_time_event*e, void *userdata); - pa_time_event *next, *prev; -}; - -struct pa_defer_event { - pa_glib_mainloop *mainloop; - int dead; - GSource *source; - void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_defer_event*e, void *userdata); - pa_defer_event *next, *prev; -}; - -struct pa_glib_mainloop { - GMainContext *glib_main_context; - pa_mainloop_api api; - GSource *cleanup_source; - pa_io_event *io_events, *dead_io_events; - pa_time_event *time_events, *dead_time_events; - pa_defer_event *defer_events, *dead_defer_events; -}; - -static void schedule_free_dead_events(pa_glib_mainloop *g); - -static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f); - -static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags_t f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata), void *userdata) { - pa_io_event *e; - pa_glib_mainloop *g; - - assert(m && m->userdata && fd >= 0 && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_io_event)); - e->mainloop = m->userdata; - e->dead = 0; - e->fd = fd; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - - e->io_channel = g_io_channel_unix_new(e->fd); - assert(e->io_channel); - e->source = NULL; - e->io_condition = 0; - - glib_io_enable(e, f); - - e->next = g->io_events; - if (e->next) e->next->prev = e; - g->io_events = e; - e->prev = NULL; - - return e; -} - -/* The callback GLIB calls whenever an IO condition is met */ -static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { - pa_io_event *e = data; - pa_io_event_flags_t f; - assert(source && e && e->io_channel == source); - - f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | - (condition & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) | - (condition & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) | - (condition & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0); - - e->callback(&e->mainloop->api, e, e->fd, f, e->userdata); - return TRUE; -} - -static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { - GIOCondition c; - assert(e && !e->dead); - - c = (f & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | (f & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0); - - if (c == e->io_condition) - return; - - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); - } - - e->source = g_io_create_watch(e->io_channel, c | G_IO_ERR | G_IO_HUP); - assert(e->source); - - g_source_set_callback(e->source, (GSourceFunc) io_cb, e, NULL); - g_source_attach(e->source, e->mainloop->glib_main_context); - g_source_set_priority(e->source, G_PRIORITY_DEFAULT); - - e->io_condition = c; -} - -static void glib_io_free(pa_io_event*e) { - assert(e && !e->dead); - - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); - e->source = NULL; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->io_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_io_events)) - e->next->prev = e; - - e->mainloop->dead_io_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_io_set_destroy(pa_io_event*e, void (*callback)(pa_mainloop_api*m, pa_io_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Time sources */ - -static void glib_time_restart(pa_time_event*e, const struct timeval *tv); - -static pa_time_event* glib_time_new(pa_mainloop_api*m, const struct timeval *tv, void (*callback) (pa_mainloop_api*m, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { - pa_glib_mainloop *g; - pa_time_event *e; - - assert(m && m->userdata && tv && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_time_event)); - e->mainloop = g; - e->dead = 0; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - e->source = NULL; - - glib_time_restart(e, tv); - - e->next = g->time_events; - if (e->next) e->next->prev = e; - g->time_events = e; - e->prev = NULL; - - return e; -} - -static guint msec_diff(const struct timeval *a, const struct timeval *b) { - guint r; - assert(a && b); - - if (a->tv_sec < b->tv_sec) - return 0; - - if (a->tv_sec == b->tv_sec && a->tv_sec <= b->tv_sec) - return 0; - - r = (a->tv_sec-b->tv_sec)*1000; - - if (a->tv_usec >= b->tv_usec) - r += (a->tv_usec - b->tv_usec) / 1000; - else - r -= (b->tv_usec - a->tv_usec) / 1000; - - return r; -} - -static gboolean time_cb(gpointer data) { - pa_time_event* e = data; - assert(e && e->mainloop && e->source); - - g_source_unref(e->source); - e->source = NULL; - - e->callback(&e->mainloop->api, e, &e->timeval, e->userdata); - return FALSE; -} - -static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { - struct timeval now; - assert(e && e->mainloop && !e->dead); - - pa_gettimeofday(&now); - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); - } - - if (tv) { - e->timeval = *tv; - e->source = g_timeout_source_new(msec_diff(tv, &now)); - assert(e->source); - g_source_set_callback(e->source, time_cb, e, NULL); - g_source_set_priority(e->source, G_PRIORITY_DEFAULT); - g_source_attach(e->source, e->mainloop->glib_main_context); - } else - e->source = NULL; - } - -static void glib_time_free(pa_time_event *e) { - assert(e && e->mainloop && !e->dead); - - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); - e->source = NULL; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->time_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_time_events)) - e->next->prev = e; - - e->mainloop->dead_time_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*m, pa_time_event*e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Deferred sources */ - -static void glib_defer_enable(pa_defer_event *e, int b); - -static pa_defer_event* glib_defer_new(pa_mainloop_api*m, void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata), void *userdata) { - pa_defer_event *e; - pa_glib_mainloop *g; - - assert(m && m->userdata && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_defer_event)); - e->mainloop = g; - e->dead = 0; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - e->source = NULL; - - glib_defer_enable(e, 1); - - e->next = g->defer_events; - if (e->next) e->next->prev = e; - g->defer_events = e; - e->prev = NULL; - return e; -} - -static gboolean idle_cb(gpointer data) { - pa_defer_event* e = data; - assert(e && e->mainloop && e->source); - - e->callback(&e->mainloop->api, e, e->userdata); - return TRUE; -} - -static void glib_defer_enable(pa_defer_event *e, int b) { - assert(e && e->mainloop); - - if (e->source && !b) { - g_source_destroy(e->source); - g_source_unref(e->source); - e->source = NULL; - } else if (!e->source && b) { - e->source = g_idle_source_new(); - assert(e->source); - g_source_set_callback(e->source, idle_cb, e, NULL); - g_source_attach(e->source, e->mainloop->glib_main_context); - g_source_set_priority(e->source, G_PRIORITY_HIGH); - } -} - -static void glib_defer_free(pa_defer_event *e) { - assert(e && e->mainloop && !e->dead); - - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); - e->source = NULL; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->defer_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_defer_events)) - e->next->prev = e; - - e->mainloop->dead_defer_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api *m, pa_defer_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* quit() */ - -static void glib_quit(pa_mainloop_api*a, PA_GCC_UNUSED int retval) { - pa_glib_mainloop *g; - assert(a && a->userdata); - g = a->userdata; - - /* NOOP */ -} - -static const pa_mainloop_api vtable = { - .userdata = NULL, - - .io_new = glib_io_new, - .io_enable = glib_io_enable, - .io_free = glib_io_free, - .io_set_destroy= glib_io_set_destroy, - - .time_new = glib_time_new, - .time_restart = glib_time_restart, - .time_free = glib_time_free, - .time_set_destroy = glib_time_set_destroy, - - .defer_new = glib_defer_new, - .defer_enable = glib_defer_enable, - .defer_free = glib_defer_free, - .defer_set_destroy = glib_defer_set_destroy, - - .quit = glib_quit, -}; - -pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) { - pa_glib_mainloop *g; - - g = pa_xmalloc(sizeof(pa_glib_mainloop)); - if (c) { - g->glib_main_context = c; - g_main_context_ref(c); - } else - g->glib_main_context = g_main_context_default(); - - g->api = vtable; - g->api.userdata = g; - - g->io_events = g->dead_io_events = NULL; - g->time_events = g->dead_time_events = NULL; - g->defer_events = g->dead_defer_events = NULL; - - g->cleanup_source = NULL; - return g; -} - -static void free_io_events(pa_io_event *e) { - while (e) { - pa_io_event *r = e; - e = r->next; - - if (r->source) { - g_source_destroy(r->source); - g_source_unref(r->source); - } - - if (r->io_channel) - g_io_channel_unref(r->io_channel); - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -static void free_time_events(pa_time_event *e) { - while (e) { - pa_time_event *r = e; - e = r->next; - - if (r->source) { - g_source_destroy(r->source); - g_source_unref(r->source); - } - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -static void free_defer_events(pa_defer_event *e) { - while (e) { - pa_defer_event *r = e; - e = r->next; - - if (r->source) { - g_source_destroy(r->source); - g_source_unref(r->source); - } - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -void pa_glib_mainloop_free(pa_glib_mainloop* g) { - assert(g); - - free_io_events(g->io_events); - free_io_events(g->dead_io_events); - free_defer_events(g->defer_events); - free_defer_events(g->dead_defer_events); - free_time_events(g->time_events); - free_time_events(g->dead_time_events); - - if (g->cleanup_source) { - g_source_destroy(g->cleanup_source); - g_source_unref(g->cleanup_source); - } - - g_main_context_unref(g->glib_main_context); - pa_xfree(g); -} - -pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) { - assert(g); - return &g->api; -} - -static gboolean free_dead_events(gpointer p) { - pa_glib_mainloop *g = p; - assert(g); - - free_io_events(g->dead_io_events); - free_defer_events(g->dead_defer_events); - free_time_events(g->dead_time_events); - - g->dead_io_events = NULL; - g->dead_defer_events = NULL; - g->dead_time_events = NULL; - - g_source_destroy(g->cleanup_source); - g_source_unref(g->cleanup_source); - g->cleanup_source = NULL; - - return FALSE; -} - -static void schedule_free_dead_events(pa_glib_mainloop *g) { - assert(g && g->glib_main_context); - - if (g->cleanup_source) - return; - - g->cleanup_source = g_idle_source_new(); - assert(g->cleanup_source); - g_source_set_callback(g->cleanup_source, free_dead_events, g, NULL); - g_source_attach(g->cleanup_source, g->glib_main_context); -} diff --git a/polyp/glib-mainloop.h b/polyp/glib-mainloop.h deleted file mode 100644 index d3e98597..00000000 --- a/polyp/glib-mainloop.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef fooglibmainloophfoo -#define fooglibmainloophfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "mainloop-api.h" -#include "cdecl.h" - -/** \file - * GLIB main loop support */ - -PA_C_DECL_BEGIN - -/** \pa_glib_mainloop - * An opaque GLIB main loop object */ -typedef struct pa_glib_mainloop pa_glib_mainloop; - -/** Create a new GLIB main loop object for the specified GLIB main loop context. If c is NULL the default context is used. */ -#if GLIB_MAJOR_VERSION >= 2 -pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c); -#else -pa_glib_mainloop *pa_glib_mainloop_new(void); -#endif - - -/** Free the GLIB main loop object */ -void pa_glib_mainloop_free(pa_glib_mainloop* g); - -/** Return the abstract main loop API vtable for the GLIB main loop object */ -pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g); - -PA_C_DECL_END - -#endif diff --git a/polyp/glib12-mainloop.c b/polyp/glib12-mainloop.c deleted file mode 100644 index 8bc4483b..00000000 --- a/polyp/glib12-mainloop.c +++ /dev/null @@ -1,500 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "glib-mainloop.h" -#include "idxset.h" -#include "xmalloc.h" -#include "util.h" - -/* A mainloop implementation based on GLIB 1.2 */ - -struct pa_io_event { - pa_glib_mainloop *mainloop; - int dead; - GIOChannel *io_channel; - guint source; - GIOCondition io_condition; - int fd; - void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_io_event*e, void *userdata); - pa_io_event *next, *prev; -}; - -struct pa_time_event { - pa_glib_mainloop *mainloop; - int dead; - guint source; - struct timeval timeval; - void (*callback) (pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_time_event*e, void *userdata); - pa_time_event *next, *prev; -}; - -struct pa_defer_event { - pa_glib_mainloop *mainloop; - int dead; - guint source; - void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_defer_event*e, void *userdata); - pa_defer_event *next, *prev; -}; - -struct pa_glib_mainloop { - pa_mainloop_api api; - guint cleanup_source; - pa_io_event *io_events, *dead_io_events; - pa_time_event *time_events, *dead_time_events; - pa_defer_event *defer_events, *dead_defer_events; -}; - -static void schedule_free_dead_events(pa_glib_mainloop *g); - -static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f); - -static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags_t f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata), void *userdata) { - pa_io_event *e; - pa_glib_mainloop *g; - - assert(m && m->userdata && fd >= 0 && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_io_event)); - e->mainloop = m->userdata; - e->dead = 0; - e->fd = fd; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - - e->io_channel = g_io_channel_unix_new(e->fd); - assert(e->io_channel); - e->source = (guint) -1; - e->io_condition = 0; - - glib_io_enable(e, f); - - e->next = g->io_events; - if (e->next) e->next->prev = e; - g->io_events = e; - e->prev = NULL; - - return e; -} - -static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { - pa_io_event *e = data; - pa_io_event_flags_t f; - assert(source && e && e->io_channel == source); - - f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | - (condition & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) | - (condition & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) | - (condition & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0); - - e->callback(&e->mainloop->api, e, e->fd, f, e->userdata); - return TRUE; -} - -static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { - GIOCondition c; - assert(e && !e->dead); - - c = (f & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | (f & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0); - - if (c == e->io_condition) - return; - - if (e->source != (guint) -1) - g_source_remove(e->source); - - e->source = g_io_add_watch_full(e->io_channel, G_PRIORITY_DEFAULT, c | G_IO_ERR | G_IO_HUP, io_cb, e, NULL); - assert(e->source != (guint) -1); - e->io_condition = c; -} - -static void glib_io_free(pa_io_event*e) { - assert(e && !e->dead); - - if (e->source != (guint) -1) { - g_source_remove(e->source); - e->source = (guint) -1; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->io_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_io_events)) - e->next->prev = e; - - e->mainloop->dead_io_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_io_set_destroy(pa_io_event*e, void (*callback)(pa_mainloop_api*m, pa_io_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Time sources */ - -static void glib_time_restart(pa_time_event*e, const struct timeval *tv); - -static pa_time_event* glib_time_new(pa_mainloop_api*m, const struct timeval *tv, void (*callback) (pa_mainloop_api*m, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { - pa_glib_mainloop *g; - pa_time_event *e; - - assert(m && m->userdata && tv && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_time_event)); - e->mainloop = g; - e->dead = 0; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - e->source = (guint) -1; - - glib_time_restart(e, tv); - - e->next = g->time_events; - if (e->next) e->next->prev = e; - g->time_events = e; - e->prev = NULL; - - return e; -} - -static guint msec_diff(const struct timeval *a, const struct timeval *b) { - guint r; - assert(a && b); - - if (a->tv_sec < b->tv_sec) - return 0; - - if (a->tv_sec == b->tv_sec && a->tv_sec <= b->tv_sec) - return 0; - - r = (a->tv_sec-b->tv_sec)*1000; - - if (a->tv_usec >= b->tv_usec) - r += (a->tv_usec - b->tv_usec) / 1000; - else - r -= (b->tv_usec - a->tv_usec) / 1000; - - return r; -} - -static gboolean time_cb(gpointer data) { - pa_time_event* e = data; - assert(e && e->mainloop && e->source != (guint) -1); - - g_source_remove(e->source); - e->source = (guint) -1; - - e->callback(&e->mainloop->api, e, &e->timeval, e->userdata); - return FALSE; -} - -static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { - struct timeval now; - assert(e && e->mainloop && !e->dead); - - pa_gettimeofday(&now); - if (e->source != (guint) -1) - g_source_remove(e->source); - - if (tv) { - e->timeval = *tv; - e->source = g_timeout_add_full(G_PRIORITY_DEFAULT, msec_diff(tv, &now), time_cb, e, NULL); - assert(e->source != (guint) -1); - } else - e->source = (guint) -1; - } - -static void glib_time_free(pa_time_event *e) { - assert(e && e->mainloop && !e->dead); - - if (e->source != (guint) -1) { - g_source_remove(e->source); - e->source = (guint) -1; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->time_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_time_events)) - e->next->prev = e; - - e->mainloop->dead_time_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*m, pa_time_event*e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Deferred sources */ - -static void glib_defer_enable(pa_defer_event *e, int b); - -static pa_defer_event* glib_defer_new(pa_mainloop_api*m, void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata), void *userdata) { - pa_defer_event *e; - pa_glib_mainloop *g; - - assert(m && m->userdata && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_defer_event)); - e->mainloop = g; - e->dead = 0; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - e->source = (guint) -1; - - glib_defer_enable(e, 1); - - e->next = g->defer_events; - if (e->next) e->next->prev = e; - g->defer_events = e; - e->prev = NULL; - return e; -} - -static gboolean idle_cb(gpointer data) { - pa_defer_event* e = data; - assert(e && e->mainloop && e->source != (guint) -1); - - e->callback(&e->mainloop->api, e, e->userdata); - return TRUE; -} - -static void glib_defer_enable(pa_defer_event *e, int b) { - assert(e && e->mainloop); - - if (e->source != (guint) -1 && !b) { - g_source_remove(e->source); - e->source = (guint) -1; - } else if (e->source == (guint) -1 && b) { - e->source = g_idle_add_full(G_PRIORITY_HIGH, idle_cb, e, NULL); - assert(e->source != (guint) -1); - } -} - -static void glib_defer_free(pa_defer_event *e) { - assert(e && e->mainloop && !e->dead); - - if (e->source != (guint) -1) { - g_source_remove(e->source); - e->source = (guint) -1; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->defer_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_defer_events)) - e->next->prev = e; - - e->mainloop->dead_defer_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api *m, pa_defer_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* quit() */ - -static void glib_quit(pa_mainloop_api*a, PA_GCC_UNUSED int retval) { - pa_glib_mainloop *g; - assert(a && a->userdata); - g = a->userdata; - - /* NOOP */ -} - -static const pa_mainloop_api vtable = { - .userdata = NULL, - - .io_new = glib_io_new, - .io_enable = glib_io_enable, - .io_free = glib_io_free, - .io_set_destroy= glib_io_set_destroy, - - .time_new = glib_time_new, - .time_restart = glib_time_restart, - .time_free = glib_time_free, - .time_set_destroy = glib_time_set_destroy, - - .defer_new = glib_defer_new, - .defer_enable = glib_defer_enable, - .defer_free = glib_defer_free, - .defer_set_destroy = glib_defer_set_destroy, - - .quit = glib_quit, -}; - -pa_glib_mainloop *pa_glib_mainloop_new(void) { - pa_glib_mainloop *g; - - g = pa_xmalloc(sizeof(pa_glib_mainloop)); - - g->api = vtable; - g->api.userdata = g; - - g->io_events = g->dead_io_events = NULL; - g->time_events = g->dead_time_events = NULL; - g->defer_events = g->dead_defer_events = NULL; - - g->cleanup_source = (guint) -1; - return g; -} - -static void free_io_events(pa_io_event *e) { - while (e) { - pa_io_event *r = e; - e = r->next; - - if (r->source != (guint) -1) - g_source_remove(r->source); - - if (r->io_channel) - g_io_channel_unref(r->io_channel); - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -static void free_time_events(pa_time_event *e) { - while (e) { - pa_time_event *r = e; - e = r->next; - - if (r->source != (guint) -1) - g_source_remove(r->source); - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -static void free_defer_events(pa_defer_event *e) { - while (e) { - pa_defer_event *r = e; - e = r->next; - - if (r->source != (guint) -1) - g_source_remove(r->source); - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -void pa_glib_mainloop_free(pa_glib_mainloop* g) { - assert(g); - - free_io_events(g->io_events); - free_io_events(g->dead_io_events); - free_defer_events(g->defer_events); - free_defer_events(g->dead_defer_events); - free_time_events(g->time_events); - free_time_events(g->dead_time_events); - - if (g->cleanup_source != (guint) -1) - g_source_remove(g->cleanup_source); - - pa_xfree(g); -} - -pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) { - assert(g); - return &g->api; -} - -static gboolean free_dead_events(gpointer p) { - pa_glib_mainloop *g = p; - assert(g); - - free_io_events(g->dead_io_events); - free_defer_events(g->dead_defer_events); - free_time_events(g->dead_time_events); - - g->dead_io_events = NULL; - g->dead_defer_events = NULL; - g->dead_time_events = NULL; - - g_source_remove(g->cleanup_source); - g->cleanup_source = (guint) -1; - - return FALSE; -} - -static void schedule_free_dead_events(pa_glib_mainloop *g) { - assert(g); - - if (g->cleanup_source != (guint) -1) - return; - - g->cleanup_source = g_idle_add_full(G_PRIORITY_HIGH, free_dead_events, g, NULL); -} diff --git a/polyp/hashmap.c b/polyp/hashmap.c deleted file mode 100644 index a37decb8..00000000 --- a/polyp/hashmap.c +++ /dev/null @@ -1,194 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "hashmap.h" -#include "idxset.h" -#include "xmalloc.h" -#include "log.h" - -#define BUCKETS 1023 - -struct hashmap_entry { - struct hashmap_entry *next, *previous, *bucket_next, *bucket_previous; - unsigned hash; - const void *key; - void *value; -}; - -struct pa_hashmap { - unsigned size; - struct hashmap_entry **data; - struct hashmap_entry *first_entry; - - unsigned n_entries; - unsigned (*hash_func) (const void *p); - int (*compare_func) (const void*a, const void*b); -}; - -pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { - pa_hashmap *h; - h = pa_xmalloc(sizeof(pa_hashmap)); - h->data = pa_xmalloc0(sizeof(struct hashmap_entry*)*(h->size = BUCKETS)); - h->first_entry = NULL; - h->n_entries = 0; - h->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; - h->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; - return h; -} - -static void remove(pa_hashmap *h, struct hashmap_entry *e) { - assert(e); - - if (e->next) - e->next->previous = e->previous; - if (e->previous) - e->previous->next = e->next; - else - h->first_entry = e->next; - - if (e->bucket_next) - e->bucket_next->bucket_previous = e->bucket_previous; - if (e->bucket_previous) - e->bucket_previous->bucket_next = e->bucket_next; - else { - assert(e->hash < h->size); - h->data[e->hash] = e->bucket_next; - } - - pa_xfree(e); - h->n_entries--; -} - -void pa_hashmap_free(pa_hashmap*h, void (*free_func)(void *p, void *userdata), void *userdata) { - assert(h); - - while (h->first_entry) { - if (free_func) - free_func(h->first_entry->value, userdata); - remove(h, h->first_entry); - } - - pa_xfree(h->data); - pa_xfree(h); -} - -static struct hashmap_entry *get(pa_hashmap *h, unsigned hash, const void *key) { - struct hashmap_entry *e; - assert(h && hash < h->size); - - for (e = h->data[hash]; e; e = e->bucket_next) - if (h->compare_func(e->key, key) == 0) - return e; - - return NULL; -} - -int pa_hashmap_put(pa_hashmap *h, const void *key, void *value) { - struct hashmap_entry *e; - unsigned hash; - assert(h); - - hash = h->hash_func(key) % h->size; - - if ((e = get(h, hash, key))) - return -1; - - e = pa_xmalloc(sizeof(struct hashmap_entry)); - e->hash = hash; - e->key = key; - e->value = value; - - e->previous = NULL; - e->next = h->first_entry; - if (h->first_entry) - h->first_entry->previous = e; - h->first_entry = e; - - e->bucket_previous = NULL; - e->bucket_next = h->data[hash]; - if (h->data[hash]) - h->data[hash]->bucket_previous = e; - h->data[hash] = e; - - h->n_entries ++; - return 0; -} - -void* pa_hashmap_get(pa_hashmap *h, const void *key) { - unsigned hash; - struct hashmap_entry *e; - assert(h && key); - - hash = h->hash_func(key) % h->size; - - if (!(e = get(h, hash, key))) - return NULL; - - return e->value; -} - -void* pa_hashmap_remove(pa_hashmap *h, const void *key) { - struct hashmap_entry *e; - unsigned hash; - void *data; - assert(h && key); - - hash = h->hash_func(key) % h->size; - - if (!(e = get(h, hash, key))) - return NULL; - - data = e->value; - remove(h, e); - return data; -} - -unsigned pa_hashmap_size(pa_hashmap *h) { - return h->n_entries; -} - -void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void **key) { - assert(h && state); - - if (!*state) - *state = h->first_entry; - else - *state = ((struct hashmap_entry*) *state)->next; - - if (!*state) { - if (key) - *key = NULL; - return NULL; - } - - if (key) - *key = ((struct hashmap_entry*) *state)->key; - - return ((struct hashmap_entry*) *state)->value; -} diff --git a/polyp/hashmap.h b/polyp/hashmap.h deleted file mode 100644 index 14f82705..00000000 --- a/polyp/hashmap.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef foohashmaphfoo -#define foohashmaphfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -/* Simple Implementation of a hash table. Memory management is the - * user's job. It's a good idea to have the key pointer point to a - * string in the value data. */ - -typedef struct pa_hashmap pa_hashmap; - -/* Create a new hashmap. Use the specified functions for hashing and comparing objects in the map */ -pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); - -/* Free the hash table. Calls the specified function for every value in the table. The function may be NULL */ -void pa_hashmap_free(pa_hashmap*, void (*free_func)(void *p, void *userdata), void *userdata); - -/* Returns non-zero when the entry already exists */ -int pa_hashmap_put(pa_hashmap *h, const void *key, void *value); -void* pa_hashmap_get(pa_hashmap *h, const void *key); - -/* Returns the data of the entry while removing */ -void* pa_hashmap_remove(pa_hashmap *h, const void *key); - -unsigned pa_hashmap_size(pa_hashmap *h); - -/* May be used to iterate through the hashmap. Initially the opaque - pointer *state has to be set to NULL. The hashmap may not be - modified during iteration. The key of the entry is returned in - *key, if key is non-NULL. After the last entry in the hashmap NULL - is returned. */ -void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void**key); - -#endif diff --git a/polyp/howl-wrap.c b/polyp/howl-wrap.c deleted file mode 100644 index 77d096ac..00000000 --- a/polyp/howl-wrap.c +++ /dev/null @@ -1,116 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "howl-wrap.h" -#include "log.h" -#include "xmalloc.h" -#include "props.h" - -#define HOWL_PROPERTY "howl" - -pa_howl_wrapper { - pa_core *core; - int ref; - - pa_io_event *io_event; - sw_discovery discovery; - -}; - -static void howl_io_event(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata) { - pa_howl_wrapper *w = userdata; - assert(m && e && fd >= 0 && w && w->ref >= 1); - - if (f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) - goto fail; - - if (sw_discovery_read_socket(w->discovery) != SW_OKAY) - goto fail; - - return; - -fail: - pa_log(__FILE__": howl connection died.\n"); - w->core->mainloop->io_free(w->io_event); - w->io_event = NULL; -} - -static pa_howl_wrapper* howl_wrapper_new(pa_core *c) { - pa_howl_wrapper *h; - sw_discovery session; - assert(c); - - if (sw_discovery_init(&session) != SW_OKAY) { - pa_log("sw_discovery_init() failed.\n"); - return NULL; - } - - h = pa_xmalloc(sizeof(pa_howl_wrapper)); - h->core = c; - h->ref = 1; - h->discovery = session; - - h->io_event = c->mainloop->io_new(c->mainloop, sw_discovery_socket(session), PA_IO_EVENT_INPUT, howl_io_event, h); - - return h; -} - -static void howl_wrapper_free(pa_howl_wrapper *h) { - assert(h); - - sw_discovery_fina(h->discovery); - - if (h->io_event) - h->core->mainloop->io_free(h->io_event); - - pa_xfree(h); -} - -pa_howl_wrapper* pa_howl_wrapper_get(pa_core *c) { - pa_howl_wrapper *h; - assert(c); - - if ((h = pa_property_get(c, HOWL_PROPERTY))) - return pa_howl_wrapper_ref(h); - - return howl_wrapper_new(c); -} - -pa_howl_wrapper* pa_howl_wrapper_ref(pa_howl_wrapper *h) { - assert(h && h->ref >= 1); - h->ref++; - return h; -} - -void pa_howl_wrapper_unref(pa_howl_wrapper *h) { - assert(h && h->ref >= 1); - if (!(--h->ref)) - howl_wrapper_free(h); -} - -sw_discovery pa_howl_wrapper_get_discovery(pa_howl_wrapper *h) { - assert(h && h->ref >= 1); - - return h->discovery; -} - diff --git a/polyp/howl-wrap.h b/polyp/howl-wrap.h deleted file mode 100644 index a670b082..00000000 --- a/polyp/howl-wrap.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef foohowlwrapperhfoo -#define foohowlwrapperhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "core.h" - -pa_howl_wrapper; - -pa_howl_wrapper* pa_howl_wrapper_get(pa_core *c); -pa_howl_wrapper* pa_howl_wrapper_ref(pa_howl_wrapper *h); -void pa_howl_wrapper_unref(pa_howl_wrapper *h); - -sw_discovery pa_howl_wrapper_get_discovery(pa_howl_wrapper *h); - -#endif diff --git a/polyp/idxset.c b/polyp/idxset.c deleted file mode 100644 index 409d1fab..00000000 --- a/polyp/idxset.c +++ /dev/null @@ -1,390 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "idxset.h" -#include "xmalloc.h" - -typedef struct idxset_entry { - void *data; - uint32_t index; - unsigned hash_value; - - struct idxset_entry *hash_prev, *hash_next; - struct idxset_entry* iterate_prev, *iterate_next; -} idxset_entry; - -struct pa_idxset { - unsigned (*hash_func) (const void *p); - int (*compare_func)(const void *a, const void *b); - - unsigned hash_table_size, n_entries; - idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail; - uint32_t index, start_index, array_size; -}; - -unsigned pa_idxset_string_hash_func(const void *p) { - unsigned hash = 0; - const char *c; - - for (c = p; *c; c++) - hash = 31 * hash + *c; - - return hash; -} - -int pa_idxset_string_compare_func(const void *a, const void *b) { - return strcmp(a, b); -} - -unsigned pa_idxset_trivial_hash_func(const void *p) { - return (unsigned) p; -} - -int pa_idxset_trivial_compare_func(const void *a, const void *b) { - return a != b; -} - -pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { - pa_idxset *s; - - s = pa_xnew(pa_idxset, 1); - s->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; - s->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; - s->hash_table_size = 1023; - s->hash_table = pa_xmalloc0(sizeof(idxset_entry*)*s->hash_table_size); - s->array = NULL; - s->array_size = 0; - s->index = 0; - s->start_index = 0; - s->n_entries = 0; - - s->iterate_list_head = s->iterate_list_tail = NULL; - - return s; -} - -void pa_idxset_free(pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata) { - assert(s); - - while (s->iterate_list_head) { - idxset_entry *e = s->iterate_list_head; - s->iterate_list_head = s->iterate_list_head->iterate_next; - - if (free_func) - free_func(e->data, userdata); - pa_xfree(e); - } - - pa_xfree(s->hash_table); - pa_xfree(s->array); - pa_xfree(s); -} - -static idxset_entry* hash_scan(pa_idxset *s, idxset_entry* e, const void *p) { - assert(p); - - assert(s->compare_func); - for (; e; e = e->hash_next) - if (s->compare_func(e->data, p) == 0) - return e; - - return NULL; -} - -static void extend_array(pa_idxset *s, uint32_t idx) { - uint32_t i, j, l; - idxset_entry** n; - assert(idx >= s->start_index); - - if (idx < s->start_index + s->array_size) - return; - - for (i = 0; i < s->array_size; i++) - if (s->array[i]) - break; - - l = idx - s->start_index - i + 100; - n = pa_xnew0(idxset_entry*, l); - - for (j = 0; j < s->array_size-i; j++) - n[j] = s->array[i+j]; - - pa_xfree(s->array); - - s->array = n; - s->array_size = l; - s->start_index += i; -} - -static idxset_entry** array_index(pa_idxset*s, uint32_t idx) { - if (idx >= s->start_index + s->array_size) - return NULL; - - if (idx < s->start_index) - return NULL; - - return s->array + (idx - s->start_index); -} - -int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) { - unsigned h; - idxset_entry *e, **a; - assert(s && p); - - assert(s->hash_func); - h = s->hash_func(p) % s->hash_table_size; - - assert(s->hash_table); - if ((e = hash_scan(s, s->hash_table[h], p))) { - if (idx) - *idx = e->index; - - return -1; - } - - e = pa_xmalloc(sizeof(idxset_entry)); - e->data = p; - e->index = s->index++; - e->hash_value = h; - - /* Insert into hash table */ - e->hash_next = s->hash_table[h]; - e->hash_prev = NULL; - if (s->hash_table[h]) - s->hash_table[h]->hash_prev = e; - s->hash_table[h] = e; - - /* Insert into array */ - extend_array(s, e->index); - a = array_index(s, e->index); - assert(a && !*a); - *a = e; - - /* Insert into linked list */ - e->iterate_next = NULL; - e->iterate_prev = s->iterate_list_tail; - if (s->iterate_list_tail) { - assert(s->iterate_list_head); - s->iterate_list_tail->iterate_next = e; - } else { - assert(!s->iterate_list_head); - s->iterate_list_head = e; - } - s->iterate_list_tail = e; - - s->n_entries++; - assert(s->n_entries >= 1); - - if (idx) - *idx = e->index; - - return 0; -} - -void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx) { - idxset_entry **a; - assert(s); - - if (!(a = array_index(s, idx))) - return NULL; - - if (!*a) - return NULL; - - return (*a)->data; -} - -void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx) { - unsigned h; - idxset_entry *e; - assert(s && p); - - assert(s->hash_func); - h = s->hash_func(p) % s->hash_table_size; - - assert(s->hash_table); - if (!(e = hash_scan(s, s->hash_table[h], p))) - return NULL; - - if (idx) - *idx = e->index; - - return e->data; -} - -static void remove_entry(pa_idxset *s, idxset_entry *e) { - idxset_entry **a; - assert(s && e); - - /* Remove from array */ - a = array_index(s, e->index); - assert(a && *a && *a == e); - *a = NULL; - - /* Remove from linked list */ - if (e->iterate_next) - e->iterate_next->iterate_prev = e->iterate_prev; - else - s->iterate_list_tail = e->iterate_prev; - - if (e->iterate_prev) - e->iterate_prev->iterate_next = e->iterate_next; - else - s->iterate_list_head = e->iterate_next; - - /* Remove from hash table */ - if (e->hash_next) - e->hash_next->hash_prev = e->hash_prev; - - if (e->hash_prev) - e->hash_prev->hash_next = e->hash_next; - else - s->hash_table[e->hash_value] = e->hash_next; - - pa_xfree(e); - - assert(s->n_entries >= 1); - s->n_entries--; -} - -void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx) { - idxset_entry **a; - void *data; - - assert(s); - - if (!(a = array_index(s, idx))) - return NULL; - - data = (*a)->data; - remove_entry(s, *a); - - return data; -} - -void* pa_idxset_remove_by_data(pa_idxset*s, const void *data, uint32_t *idx) { - idxset_entry *e; - unsigned h; - void *r; - - assert(s->hash_func); - h = s->hash_func(data) % s->hash_table_size; - - assert(s->hash_table); - if (!(e = hash_scan(s, s->hash_table[h], data))) - return NULL; - - r = e->data; - if (idx) - *idx = e->index; - - remove_entry(s, e); - - return r; -} - -void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx) { - idxset_entry **a, *e = NULL; - assert(s && idx); - - if ((a = array_index(s, *idx)) && *a) - e = (*a)->iterate_next; - - if (!e) - e = s->iterate_list_head; - - if (!e) - return NULL; - - *idx = e->index; - return e->data; -} - -void* pa_idxset_first(pa_idxset *s, uint32_t *idx) { - assert(s); - - if (!s->iterate_list_head) - return NULL; - - if (idx) - *idx = s->iterate_list_head->index; - return s->iterate_list_head->data; -} - -void *pa_idxset_next(pa_idxset *s, uint32_t *idx) { - idxset_entry **a, *e = NULL; - assert(s && idx); - - if ((a = array_index(s, *idx)) && *a) - e = (*a)->iterate_next; - - if (e) { - *idx = e->index; - return e->data; - } else { - *idx = PA_IDXSET_INVALID; - return NULL; - } -} - - -int pa_idxset_foreach(pa_idxset*s, int (*func)(void *p, uint32_t idx, int *del, void*userdata), void *userdata) { - idxset_entry *e; - assert(s && func); - - e = s->iterate_list_head; - while (e) { - int del = 0, r; - idxset_entry *n = e->iterate_next; - - r = func(e->data, e->index, &del, userdata); - - if (del) - remove_entry(s, e); - - if (r < 0) - return r; - - e = n; - } - - return 0; -} - -unsigned pa_idxset_size(pa_idxset*s) { - assert(s); - return s->n_entries; -} - -int pa_idxset_isempty(pa_idxset *s) { - assert(s); - return s->n_entries == 0; -} - diff --git a/polyp/idxset.h b/polyp/idxset.h deleted file mode 100644 index 17ae16cb..00000000 --- a/polyp/idxset.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef fooidxsethfoo -#define fooidxsethfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -/* A combination of a set and a dynamic array. Entries are indexable - * both through a numeric automatically generated index and the entry's - * data pointer. As usual, memory management is the user's job. */ - -/* A special index value denoting the invalid index. */ -#define PA_IDXSET_INVALID ((uint32_t) -1) - -/* Generic implementations for hash and comparison functions. Just - * compares the pointer or calculates the hash value directly from the - * pointer value. */ -unsigned pa_idxset_trivial_hash_func(const void *p); -int pa_idxset_trivial_compare_func(const void *a, const void *b); - -/* Generic implementations for hash and comparison functions for strings. */ -unsigned pa_idxset_string_hash_func(const void *p); -int pa_idxset_string_compare_func(const void *a, const void *b); - -typedef struct pa_idxset pa_idxset; - -/* Instantiate a new idxset with the specified hash and comparison functions */ -pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); - -/* Free the idxset. When the idxset is not empty the specified function is called for every entry contained */ -void pa_idxset_free(pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata); - -/* Store a new item in the idxset. The index of the item is returned in *idx */ -int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx); - -/* Get the entry by its idx */ -void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx); - -/* Get the entry by its data. The idx is returned in *index */ -void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx); - -/* Similar to pa_idxset_get_by_index(), but removes the entry from the idxset. */ -void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx); - -/* Similar to pa_idxset_get_by_data(), but removes the entry from the idxset */ -void* pa_idxset_remove_by_data(pa_idxset*s, const void *p, uint32_t *idx); - -/* This may be used to iterate through all entries. When called with - an invalid index value it returns the first entry, otherwise the - next following. The function is best called with *idx = - PA_IDXSET_VALID first. It is safe to manipulate the idxset between - the calls. It is not guaranteed that all entries have already been - returned before the an entry is returned the second time.*/ -void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx); - -/* Return the oldest entry in the idxset. Fill in its index in *idx. */ -void* pa_idxset_first(pa_idxset *s, uint32_t *idx); - -/* Return the entry following the entry indexed by *idx. After the - * call *index contains the index of the returned - * object. pa_idxset_first() and pa_idxset_next() may be used to - * iterate through the set.*/ -void *pa_idxset_next(pa_idxset *s, uint32_t *idx); - -/* Call a function for every item in the set. If the callback function - returns -1, the loop is terminated. If *del is set to non-zero that - specific item is removed. It is not safe to call any other - functions on the idxset while pa_idxset_foreach is executed. */ -int pa_idxset_foreach(pa_idxset*s, int (*func)(void *p, uint32_t idx, int *del, void*userdata), void *userdata); - -unsigned pa_idxset_size(pa_idxset*s); - -int pa_idxset_isempty(pa_idxset *s); - -#endif diff --git a/polyp/inet_ntop.c b/polyp/inet_ntop.c deleted file mode 100644 index a25c3c95..00000000 --- a/polyp/inet_ntop.c +++ /dev/null @@ -1,80 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#ifndef HAVE_INET_NTOP - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#include "winsock.h" - -#include "inet_ntop.h" - -const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) { - struct in_addr *in = (struct in_addr*)src; - struct in6_addr *in6 = (struct in6_addr*)src; - - assert(src && dst); - - switch (af) { - case AF_INET: - snprintf(dst, cnt, "%d.%d.%d.%d", -#ifdef WORDS_BIGENDIAN - (int)(in->s_addr >> 24) & 0xff, - (int)(in->s_addr >> 16) & 0xff, - (int)(in->s_addr >> 8) & 0xff, - (int)(in->s_addr >> 0) & 0xff); -#else - (int)(in->s_addr >> 0) & 0xff, - (int)(in->s_addr >> 8) & 0xff, - (int)(in->s_addr >> 16) & 0xff, - (int)(in->s_addr >> 24) & 0xff); -#endif - break; - case AF_INET6: - snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x", - in6->s6_addr[ 0] << 8 | in6->s6_addr[ 1], - in6->s6_addr[ 2] << 8 | in6->s6_addr[ 3], - in6->s6_addr[ 4] << 8 | in6->s6_addr[ 5], - in6->s6_addr[ 6] << 8 | in6->s6_addr[ 7], - in6->s6_addr[ 8] << 8 | in6->s6_addr[ 9], - in6->s6_addr[10] << 8 | in6->s6_addr[11], - in6->s6_addr[12] << 8 | in6->s6_addr[13], - in6->s6_addr[14] << 8 | in6->s6_addr[15]); - break; - default: - errno = EAFNOSUPPORT; - return NULL; - } - - return dst; -} - -#endif /* INET_NTOP */ diff --git a/polyp/inet_ntop.h b/polyp/inet_ntop.h deleted file mode 100644 index 7fb67b44..00000000 --- a/polyp/inet_ntop.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef fooinet_ntophfoo -#define fooinet_ntophfoo - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#include "winsock.h" - -const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt); - -#endif diff --git a/polyp/iochannel.c b/polyp/iochannel.c deleted file mode 100644 index 273d47e0..00000000 --- a/polyp/iochannel.c +++ /dev/null @@ -1,292 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "winsock.h" - -#include "iochannel.h" -#include "util.h" -#include "socket-util.h" -#include "xmalloc.h" - -struct pa_iochannel { - int ifd, ofd; - pa_mainloop_api* mainloop; - - pa_iochannel_callback_t callback; - void*userdata; - - int readable; - int writable; - int hungup; - - int no_close; - - pa_io_event* input_event, *output_event; -}; - -static void enable_mainloop_sources(pa_iochannel *io) { - assert(io); - - if (io->input_event == io->output_event && io->input_event) { - pa_io_event_flags_t f = PA_IO_EVENT_NULL; - assert(io->input_event); - - if (!io->readable) - f |= PA_IO_EVENT_INPUT; - if (!io->writable) - f |= PA_IO_EVENT_OUTPUT; - - io->mainloop->io_enable(io->input_event, f); - } else { - if (io->input_event) - io->mainloop->io_enable(io->input_event, io->readable ? PA_IO_EVENT_NULL : PA_IO_EVENT_INPUT); - if (io->output_event) - io->mainloop->io_enable(io->output_event, io->writable ? PA_IO_EVENT_NULL : PA_IO_EVENT_OUTPUT); - } -} - -static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { - pa_iochannel *io = userdata; - int changed = 0; - - assert(m); - assert(e); - assert(fd >= 0); - assert(userdata); - - if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) { - io->hungup = 1; - changed = 1; - - if (e == io->input_event) { - io->mainloop->io_free(io->input_event); - io->input_event = NULL; - - if (io->output_event == e) - io->output_event = NULL; - } else if (e == io->output_event) { - io->mainloop->io_free(io->output_event); - io->output_event = NULL; - } - } else { - - if ((f & PA_IO_EVENT_INPUT) && !io->readable) { - io->readable = 1; - changed = 1; - assert(e == io->input_event); - } - - if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) { - io->writable = 1; - changed = 1; - assert(e == io->output_event); - } - } - - if (changed) { - enable_mainloop_sources(io); - - if (io->callback) - io->callback(io, io->userdata); - } -} - -pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) { - pa_iochannel *io; - - assert(m); - assert(ifd >= 0 || ofd >= 0); - - io = pa_xnew(pa_iochannel, 1); - io->ifd = ifd; - io->ofd = ofd; - io->mainloop = m; - - io->userdata = NULL; - io->callback = NULL; - io->readable = 0; - io->writable = 0; - io->hungup = 0; - io->no_close = 0; - - io->input_event = io->output_event = NULL; - - if (ifd == ofd) { - assert(ifd >= 0); - pa_make_nonblock_fd(io->ifd); - io->input_event = io->output_event = m->io_new(m, ifd, PA_IO_EVENT_INPUT|PA_IO_EVENT_OUTPUT, callback, io); - } else { - - if (ifd >= 0) { - pa_make_nonblock_fd(io->ifd); - io->input_event = m->io_new(m, ifd, PA_IO_EVENT_INPUT, callback, io); - } - - if (ofd >= 0) { - pa_make_nonblock_fd(io->ofd); - io->output_event = m->io_new(m, ofd, PA_IO_EVENT_OUTPUT, callback, io); - } - } - - return io; -} - -void pa_iochannel_free(pa_iochannel*io) { - assert(io); - - if (io->input_event) - io->mainloop->io_free(io->input_event); - - if (io->output_event && (io->output_event != io->input_event)) - io->mainloop->io_free(io->output_event); - - if (!io->no_close) { - if (io->ifd >= 0) - - close(io->ifd); - if (io->ofd >= 0 && io->ofd != io->ifd) - close(io->ofd); - } - - pa_xfree(io); -} - -int pa_iochannel_is_readable(pa_iochannel*io) { - assert(io); - - return io->readable || io->hungup; -} - -int pa_iochannel_is_writable(pa_iochannel*io) { - assert(io); - - return io->writable && !io->hungup; -} - -int pa_iochannel_is_hungup(pa_iochannel*io) { - assert(io); - - return io->hungup; -} - -ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) { - ssize_t r; - - assert(io); - assert(data); - assert(l); - assert(io->ofd >= 0); - -#ifdef OS_IS_WIN32 - r = send(io->ofd, data, l, 0); - if (r < 0) { - if (WSAGetLastError() != WSAENOTSOCK) { - errno = WSAGetLastError(); - return r; - } - } - - if (r < 0) -#endif - r = write(io->ofd, data, l); - if (r >= 0) { - io->writable = 0; - enable_mainloop_sources(io); - } - - return r; -} - -ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) { - ssize_t r; - - assert(io); - assert(data); - assert(io->ifd >= 0); - -#ifdef OS_IS_WIN32 - r = recv(io->ifd, data, l, 0); - if (r < 0) { - if (WSAGetLastError() != WSAENOTSOCK) { - errno = WSAGetLastError(); - return r; - } - } - - if (r < 0) -#endif - r = read(io->ifd, data, l); - - if (r >= 0) { - io->readable = 0; - enable_mainloop_sources(io); - } - - return r; -} - -void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_callback_t _callback, void *userdata) { - assert(io); - - io->callback = _callback; - io->userdata = userdata; -} - -void pa_iochannel_set_noclose(pa_iochannel*io, int b) { - assert(io); - - io->no_close = b; -} - -void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) { - assert(io); - assert(s); - assert(l); - - pa_socket_peer_to_string(io->ifd, s, l); -} - -int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) { - assert(io); - - return pa_socket_set_rcvbuf(io->ifd, l); -} - -int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) { - assert(io); - - return pa_socket_set_sndbuf(io->ofd, l); -} - -pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) { - assert(io); - - return io->mainloop; -} diff --git a/polyp/iochannel.h b/polyp/iochannel.h deleted file mode 100644 index e2b8bccf..00000000 --- a/polyp/iochannel.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef fooiochannelhfoo -#define fooiochannelhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include "mainloop-api.h" - -/* A wrapper around UNIX file descriptors for attaching them to the a - main event loop. Everytime new data may be read or be written to - the channel a callback function is called. It is safe to destroy - the calling iochannel object from the callback */ - -/* When pa_iochannel_is_readable() returns non-zero, the user has to - * call this function in a loop until it is no longer set or EOF - * reached. Otherwise strange things may happen when an EOF is - * reached. */ - -typedef struct pa_iochannel pa_iochannel; - -/* Create a new IO channel for the specified file descriptors for -input resp. output. It is safe to pass the same file descriptor for -both parameters (in case of full-duplex channels). For a simplex -channel specify -1 for the other direction. */ - -pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd); -void pa_iochannel_free(pa_iochannel*io); - -ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l); -ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l); - -int pa_iochannel_is_readable(pa_iochannel*io); -int pa_iochannel_is_writable(pa_iochannel*io); -int pa_iochannel_is_hungup(pa_iochannel*io); - -/* Don't close the file descirptors when the io channel is freed. By - * default the file descriptors are closed. */ -void pa_iochannel_set_noclose(pa_iochannel*io, int b); - -/* Set the callback function that is called whenever data becomes available for read or write */ -typedef void (*pa_iochannel_callback_t)(pa_iochannel*io, void *userdata); -void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_callback_t callback, void *userdata); - -/* In case the file descriptor is a socket, return a pretty-printed string in *s which describes the peer connected */ -void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l); - -/* Use setsockopt() to tune the recieve and send buffers of TCP sockets */ -int pa_iochannel_socket_set_rcvbuf(pa_iochannel*io, size_t l); -int pa_iochannel_socket_set_sndbuf(pa_iochannel*io, size_t l); - -pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io); - -#endif diff --git a/polyp/ioline.c b/polyp/ioline.c deleted file mode 100644 index 5b669f5c..00000000 --- a/polyp/ioline.c +++ /dev/null @@ -1,368 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "ioline.h" -#include "xmalloc.h" -#include "log.h" - -#define BUFFER_LIMIT (64*1024) -#define READ_SIZE (1024) - -struct pa_ioline { - pa_iochannel *io; - pa_defer_event *defer_event; - pa_mainloop_api *mainloop; - int ref; - 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)(pa_ioline*io, const char *s, void *userdata); - void *userdata; - - int defer_close; -}; - -static void io_callback(pa_iochannel*io, void *userdata); -static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata); - -pa_ioline* pa_ioline_new(pa_iochannel *io) { - pa_ioline *l; - assert(io); - - l = pa_xmalloc(sizeof(pa_ioline)); - 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; - l->ref = 1; - - l->mainloop = pa_iochannel_get_mainloop_api(io); - - l->defer_event = l->mainloop->defer_new(l->mainloop, defer_callback, l); - l->mainloop->defer_enable(l->defer_event, 0); - - l->defer_close = 0; - - pa_iochannel_set_callback(io, io_callback, l); - - return l; -} - -static void ioline_free(pa_ioline *l) { - assert(l); - - if (l->io) - pa_iochannel_free(l->io); - - if (l->defer_event) - l->mainloop->defer_free(l->defer_event); - - pa_xfree(l->wbuf); - pa_xfree(l->rbuf); - pa_xfree(l); -} - -void pa_ioline_unref(pa_ioline *l) { - assert(l && l->ref >= 1); - - if ((--l->ref) <= 0) - ioline_free(l); -} - -pa_ioline* pa_ioline_ref(pa_ioline *l) { - assert(l && l->ref >= 1); - - l->ref++; - return l; -} - -void pa_ioline_close(pa_ioline *l) { - assert(l && l->ref >= 1); - - l->dead = 1; - if (l->io) { - pa_iochannel_free(l->io); - l->io = NULL; - } - - if (l->defer_event) { - l->mainloop->defer_free(l->defer_event); - l->defer_event = NULL; - } -} - -void pa_ioline_puts(pa_ioline *l, const char *c) { - size_t len; - assert(l && c && l->ref >= 1 && !l->dead); - - pa_ioline_ref(l); - - len = strlen(c); - if (len > BUFFER_LIMIT - l->wbuf_valid_length) - len = BUFFER_LIMIT - l->wbuf_valid_length; - - if (len) { - assert(l->wbuf_length >= l->wbuf_valid_length); - - /* In case the allocated buffer is too small, enlarge it. */ - if (l->wbuf_valid_length + len > l->wbuf_length) { - size_t n = l->wbuf_valid_length+len; - char *new = pa_xmalloc(n); - if (l->wbuf) { - memcpy(new, l->wbuf+l->wbuf_index, l->wbuf_valid_length); - pa_xfree(l->wbuf); - } - l->wbuf = new; - l->wbuf_length = n; - l->wbuf_index = 0; - } else if (l->wbuf_index + l->wbuf_valid_length + len > l->wbuf_length) { - - /* In case the allocated buffer fits, but the current index is too far from the start, move it to the front. */ - memmove(l->wbuf, l->wbuf+l->wbuf_index, l->wbuf_valid_length); - l->wbuf_index = 0; - } - - assert(l->wbuf_index + l->wbuf_valid_length + len <= l->wbuf_length); - - /* Append the new string */ - memcpy(l->wbuf + l->wbuf_index + l->wbuf_valid_length, c, len); - l->wbuf_valid_length += len; - - l->mainloop->defer_enable(l->defer_event, 1); - } - - pa_ioline_unref(l); -} - -void pa_ioline_set_callback(pa_ioline*l, void (*callback)(pa_ioline*io, const char *s, void *userdata), void *userdata) { - assert(l && l->ref >= 1); - l->callback = callback; - l->userdata = userdata; -} - -static void failure(pa_ioline *l) { - assert(l && l->ref >= 1 && !l->dead); - - pa_ioline_close(l); - - if (l->callback) { - l->callback(l, NULL, l->userdata); - l->callback = NULL; - } -} - -static void scan_for_lines(pa_ioline *l, size_t skip) { - assert(l && l->ref >= 1 && skip < l->rbuf_valid_length); - - while (!l->dead && l->rbuf_valid_length > skip) { - char *e, *p; - size_t m; - - if (!(e = memchr(l->rbuf + l->rbuf_index + skip, '\n', l->rbuf_valid_length - skip))) - break; - - *e = 0; - - p = l->rbuf + l->rbuf_index; - m = strlen(p); - - l->rbuf_index += m+1; - l->rbuf_valid_length -= m+1; - - /* A shortcut for the next time */ - if (l->rbuf_valid_length == 0) - l->rbuf_index = 0; - - if (l->callback) - l->callback(l, p, l->userdata); - - skip = 0; - } - - /* If the buffer became too large and still no newline was found, drop it. */ - if (l->rbuf_valid_length >= BUFFER_LIMIT) - l->rbuf_index = l->rbuf_valid_length = 0; -} - -static int do_write(pa_ioline *l); - -static int do_read(pa_ioline *l) { - assert(l && l->ref >= 1); - - while (!l->dead && pa_iochannel_is_readable(l->io)) { - ssize_t r; - size_t len; - - len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length; - - /* Check if we have to enlarge the read buffer */ - 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) { - /* The current buffer is large enough, let's just move the data to the front */ - if (l->rbuf_valid_length) - memmove(l->rbuf, l->rbuf+l->rbuf_index, l->rbuf_valid_length); - } else { - /* Enlarge the buffer */ - char *new = pa_xmalloc(n); - if (l->rbuf_valid_length) - memcpy(new, l->rbuf+l->rbuf_index, l->rbuf_valid_length); - pa_xfree(l->rbuf); - l->rbuf = new; - l->rbuf_length = n; - } - - l->rbuf_index = 0; - } - - len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length; - - assert(len >= READ_SIZE); - - /* Read some data */ - r = pa_iochannel_read(l->io, l->rbuf+l->rbuf_index+l->rbuf_valid_length, len); - if (r == 0) { - /* Got an EOF, so fake an exit command. */ - l->rbuf_index = 0; - snprintf (l->rbuf, l->rbuf_length, "exit\n"); - r = 5; - pa_ioline_puts(l, "\nExiting.\n"); - do_write(l); - } else if (r < 0) { - pa_log(__FILE__": read() failed: %s\n", strerror(errno)); - failure(l); - return -1; - } - - l->rbuf_valid_length += r; - - /* Look if a line has been terminated in the newly read data */ - scan_for_lines(l, l->rbuf_valid_length - r); - } - - return 0; -} - -/* Try to flush the buffer */ -static int do_write(pa_ioline *l) { - ssize_t r; - assert(l && l->ref >= 1); - - while (!l->dead && pa_iochannel_is_writable(l->io) && l->wbuf_valid_length) { - - if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0) { - pa_log(__FILE__": write() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); - failure(l); - return -1; - } - - l->wbuf_index += r; - l->wbuf_valid_length -= r; - - /* A shortcut for the next time */ - if (l->wbuf_valid_length == 0) - l->wbuf_index = 0; - } - - return 0; -} - -/* Try to flush read/write data */ -static void do_work(pa_ioline *l) { - assert(l && l->ref >= 1); - - pa_ioline_ref(l); - - l->mainloop->defer_enable(l->defer_event, 0); - - if (!l->dead) - do_write(l); - - if (!l->dead) - do_read(l); - - if (l->defer_close && !l->wbuf_valid_length) - failure(l); - - pa_ioline_unref(l); -} - -static void io_callback(pa_iochannel*io, void *userdata) { - pa_ioline *l = userdata; - assert(io && l && l->ref >= 1); - - do_work(l); -} - -static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata) { - pa_ioline *l = userdata; - assert(l && l->ref >= 1 && l->mainloop == m && l->defer_event == e); - - do_work(l); -} - -void pa_ioline_defer_close(pa_ioline *l) { - assert(l); - - l->defer_close = 1; - - if (!l->wbuf_valid_length) - l->mainloop->defer_enable(l->defer_event, 1); -} - -void pa_ioline_printf(pa_ioline *s, const char *format, ...) { - char *t; - va_list ap; - - - va_start(ap, format); - t = pa_vsprintf_malloc(format, ap); - va_end(ap); - - pa_ioline_puts(s, t); - pa_xfree(t); -} diff --git a/polyp/ioline.h b/polyp/ioline.h deleted file mode 100644 index 84ccb47a..00000000 --- a/polyp/ioline.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef fooiolinehfoo -#define fooiolinehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "iochannel.h" -#include "util.h" - -/* An ioline wraps an iochannel for line based communication. A - * callback function is called whenever a new line has been recieved - * from the client */ - -typedef struct pa_ioline pa_ioline; - -pa_ioline* pa_ioline_new(pa_iochannel *io); -void pa_ioline_unref(pa_ioline *l); -pa_ioline* pa_ioline_ref(pa_ioline *l); -void pa_ioline_close(pa_ioline *l); - -/* Write a string to the channel */ -void pa_ioline_puts(pa_ioline *s, const char *c); - -/* Write a string to the channel */ -void pa_ioline_printf(pa_ioline *s, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); - -/* Set the callback function that is called for every recieved line */ -void pa_ioline_set_callback(pa_ioline*io, void (*callback)(pa_ioline*io, const char *s, void *userdata), void *userdata); - -/* Make sure to close the ioline object as soon as the send buffer is emptied */ -void pa_ioline_defer_close(pa_ioline *io); - -#endif diff --git a/polyp/llist.h b/polyp/llist.h deleted file mode 100644 index eb8cd017..00000000 --- a/polyp/llist.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef foollistfoo -#define foollistfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -/* Some macros for maintaining doubly linked lists */ - -/* The head of the linked list. Use this in the structure that shall - * contain the head of the linked list */ -#define PA_LLIST_HEAD(t,name) t *name - -/* The pointers in the linked list's items. Use this in the item structure */ -#define PA_LLIST_FIELDS(t) t *next, *prev - -/* Initialize the list's head */ -#define PA_LLIST_HEAD_INIT(t,item) do { (item) = NULL; } while(0) - -/* Initialize a list item */ -#define PA_LLIST_INIT(t,item) do { \ - t *_item = (item); \ - assert(_item); \ - _item->prev = _item->next = NULL; \ - } while(0) - -/* Prepend an item to the list */ -#define PA_LLIST_PREPEND(t,head,item) do { \ - t **_head = &(head), *_item = (item); \ - assert(_item); \ - if ((_item->next = *_head)) \ - _item->next->prev = _item; \ - _item->prev = NULL; \ - *_head = _item; \ - } while (0) - -/* Remove an item from the list */ -#define PA_LLIST_REMOVE(t,head,item) do { \ - t **_head = &(head), *_item = (item); \ - assert(_item); \ - if (_item->next) \ - _item->next->prev = _item->prev; \ - if (_item->prev) \ - _item->prev->next = _item->next; \ - else {\ - assert(*_head == _item); \ - *_head = _item->next; \ - } \ - _item->next = _item->prev = NULL; \ - } while(0) - -#endif diff --git a/polyp/log.c b/polyp/log.c deleted file mode 100644 index 97406f79..00000000 --- a/polyp/log.c +++ /dev/null @@ -1,150 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#ifdef HAVE_SYSLOG_H -#include -#endif - -#include "log.h" -#include "xmalloc.h" -#include "util.h" - -#define ENV_LOGLEVEL "POLYP_LOG" - -static char *log_ident = NULL; -static pa_log_target_t log_target = PA_LOG_STDERR; -static void (*user_log_func)(pa_log_level_t l, const char *s) = NULL; -static pa_log_level_t maximal_level = PA_LOG_NOTICE; - -#ifdef HAVE_SYSLOG_H -static const int level_to_syslog[] = { - [PA_LOG_ERROR] = LOG_ERR, - [PA_LOG_WARN] = LOG_WARNING, - [PA_LOG_NOTICE] = LOG_NOTICE, - [PA_LOG_INFO] = LOG_INFO, - [PA_LOG_DEBUG] = LOG_DEBUG -}; -#endif - -void pa_log_set_ident(const char *p) { - if (log_ident) - pa_xfree(log_ident); - - log_ident = pa_xstrdup(p); -} - -void pa_log_set_maximal_level(pa_log_level_t l) { - assert(l < PA_LOG_LEVEL_MAX); - maximal_level = l; -} - -void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t l, const char*s)) { - assert(t == PA_LOG_USER || !func); - log_target = t; - user_log_func = func; -} - -void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { - const char *e; - assert(level < PA_LOG_LEVEL_MAX); - - if ((e = getenv(ENV_LOGLEVEL))) - maximal_level = atoi(e); - - if (level > maximal_level) - return; - - switch (log_target) { - case PA_LOG_STDERR: - vfprintf(stderr, format, ap); - break; - -#ifdef HAVE_SYSLOG_H - case PA_LOG_SYSLOG: - openlog(log_ident ? log_ident : "???", LOG_PID, LOG_USER); - vsyslog(level_to_syslog[level], format, ap); - closelog(); - break; -#endif - - case PA_LOG_USER: { - char *t = pa_vsprintf_malloc(format, ap); - assert(user_log_func); - user_log_func(level, t); - pa_xfree(t); - } - - case PA_LOG_NULL: - default: - break; - } - -} - -void pa_log_level(pa_log_level_t level, const char *format, ...) { - va_list ap; - va_start(ap, format); - pa_log_levelv(level, format, ap); - va_end(ap); -} - -void pa_log_debug(const char *format, ...) { - va_list ap; - va_start(ap, format); - pa_log_levelv(PA_LOG_DEBUG, format, ap); - va_end(ap); -} - -void pa_log_info(const char *format, ...) { - va_list ap; - va_start(ap, format); - pa_log_levelv(PA_LOG_INFO, format, ap); - va_end(ap); -} - -void pa_log_notice(const char *format, ...) { - va_list ap; - va_start(ap, format); - pa_log_levelv(PA_LOG_INFO, format, ap); - va_end(ap); -} - -void pa_log_warn(const char *format, ...) { - va_list ap; - va_start(ap, format); - pa_log_levelv(PA_LOG_WARN, format, ap); - va_end(ap); -} - -void pa_log_error(const char *format, ...) { - va_list ap; - va_start(ap, format); - pa_log_levelv(PA_LOG_ERROR, format, ap); - va_end(ap); -} diff --git a/polyp/log.h b/polyp/log.h deleted file mode 100644 index ce8aea98..00000000 --- a/polyp/log.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef foologhfoo -#define foologhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include "gccmacro.h" - -/* A simple logging subsystem */ - -/* Where to log to */ -typedef enum pa_log_target { - PA_LOG_STDERR, /* default */ - PA_LOG_SYSLOG, - PA_LOG_USER, /* to user specified function */ - PA_LOG_NULL /* to /dev/null */ -} pa_log_target_t; - -typedef enum pa_log_level { - PA_LOG_ERROR = 0, /* Error messages */ - PA_LOG_WARN = 1, /* Warning messages */ - PA_LOG_NOTICE = 2, /* Notice messages */ - PA_LOG_INFO = 3, /* Info messages */ - PA_LOG_DEBUG = 4, /* debug message */ - PA_LOG_LEVEL_MAX -} pa_log_level_t; - -/* Set an identification for the current daemon. Used when logging to syslog. */ -void pa_log_set_ident(const char *p); - -/* Set another log target. If t is PA_LOG_USER you may specify a function that is called every log string */ -void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t t, const char*s)); - -/* Minimal log level */ -void pa_log_set_maximal_level(pa_log_level_t l); - -/* Do a log line */ -void pa_log_debug(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); -void pa_log_info(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); -void pa_log_notice(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); -void pa_log_warn(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); -void pa_log_error(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); - -void pa_log_level(pa_log_level_t level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); - -void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap); - -#define pa_log pa_log_error - -#endif diff --git a/polyp/main.c b/polyp/main.c deleted file mode 100644 index b5aac851..00000000 --- a/polyp/main.c +++ /dev/null @@ -1,472 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_IOCTL_H -#include -#endif - -#ifdef HAVE_LIBWRAP -#include -#include -#endif - -#include "winsock.h" - -#include "core.h" -#include "mainloop.h" -#include "module.h" -#include "mainloop-signal.h" -#include "cmdline.h" -#include "cli-command.h" -#include "util.h" -#include "sioman.h" -#include "xmalloc.h" -#include "cpulimit.h" -#include "log.h" -#include "daemon-conf.h" -#include "dumpmodules.h" -#include "caps.h" -#include "cli-text.h" -#include "pid.h" -#include "namereg.h" - -#ifdef HAVE_LIBWRAP -/* Only one instance of these variables */ -int allow_severity = LOG_INFO; -int deny_severity = LOG_WARNING; -#endif - -#ifdef OS_IS_WIN32 - -static void message_cb(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { - MSG msg; - - while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { - if (msg.message == WM_QUIT) - raise(SIGTERM); - else { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } -} - -#endif - -static void signal_callback(pa_mainloop_api*m, PA_GCC_UNUSED pa_signal_event *e, int sig, void *userdata) { - pa_log_info(__FILE__": Got signal %s.\n", pa_strsignal(sig)); - - switch (sig) { -#ifdef SIGUSR1 - case SIGUSR1: - pa_module_load(userdata, "module-cli", NULL); - break; -#endif - -#ifdef SIGUSR2 - case SIGUSR2: - pa_module_load(userdata, "module-cli-protocol-unix", NULL); - break; -#endif - -#ifdef SIGHUP - case SIGHUP: { - char *c = pa_full_status_string(userdata); - pa_log_notice(c); - pa_xfree(c); - return; - } -#endif - - case SIGINT: - case SIGTERM: - default: - pa_log_info(__FILE__": Exiting.\n"); - m->quit(m, 1); - break; - } -} - -static void close_pipe(int p[2]) { - if (p[0] != -1) - close(p[0]); - if (p[1] != -1) - close(p[1]); - p[0] = p[1] = -1; -} - -int main(int argc, char *argv[]) { - pa_core *c; - pa_strbuf *buf = NULL; - pa_daemon_conf *conf; - pa_mainloop *mainloop; - - char *s; - int r, retval = 1, d = 0; - int daemon_pipe[2] = { -1, -1 }; - int suid_root; - int valid_pid_file = 0; - -#ifdef HAVE_GETUID - gid_t gid = (gid_t) -1; -#endif - -#ifdef OS_IS_WIN32 - pa_defer_event *defer; -#endif - - pa_limit_caps(); - -#ifdef HAVE_GETUID - suid_root = getuid() != 0 && geteuid() == 0; - - if (suid_root && (pa_uid_in_group("realtime", &gid) <= 0 || gid >= 1000)) { - pa_log_warn(__FILE__": WARNING: called SUID root, but not in group 'realtime'.\n"); - pa_drop_root(); - } -#else - suid_root = 0; -#endif - - LTDL_SET_PRELOADED_SYMBOLS(); - - r = lt_dlinit(); - assert(r == 0); - -#ifdef OS_IS_WIN32 - { - WSADATA data; - WSAStartup(MAKEWORD(2, 0), &data); - } -#endif - - pa_log_set_ident("polypaudio"); - - conf = pa_daemon_conf_new(); - - if (pa_daemon_conf_load(conf, NULL) < 0) - goto finish; - - if (pa_daemon_conf_env(conf) < 0) - goto finish; - - if (pa_cmdline_parse(conf, argc, argv, &d) < 0) { - pa_log(__FILE__": failed to parse command line.\n"); - goto finish; - } - - pa_log_set_maximal_level(conf->log_level); - pa_log_set_target(conf->auto_log_target ? PA_LOG_STDERR : conf->log_target, NULL); - - if (conf->high_priority && conf->cmd == PA_CMD_DAEMON) - pa_raise_priority(); - - pa_drop_caps(); - - if (suid_root) - pa_drop_root(); - - if (conf->dl_search_path) - lt_dlsetsearchpath(conf->dl_search_path); - - switch (conf->cmd) { - case PA_CMD_DUMP_MODULES: - pa_dump_modules(conf, argc-d, argv+d); - retval = 0; - goto finish; - - case PA_CMD_DUMP_CONF: { - s = pa_daemon_conf_dump(conf); - fputs(s, stdout); - pa_xfree(s); - retval = 0; - goto finish; - } - - case PA_CMD_HELP : - pa_cmdline_help(argv[0]); - retval = 0; - goto finish; - - case PA_CMD_VERSION : - printf(PACKAGE_NAME" "PACKAGE_VERSION"\n"); - retval = 0; - goto finish; - - case PA_CMD_CHECK: { - pid_t pid; - - if (pa_pid_file_check_running(&pid) < 0) { - pa_log_info(__FILE__": daemon not running\n"); - } else { - pa_log_info(__FILE__": daemon running as PID %u\n", pid); - retval = 0; - } - - goto finish; - - } - case PA_CMD_KILL: - - if (pa_pid_file_kill(SIGINT, NULL) < 0) - pa_log(__FILE__": failed to kill daemon.\n"); - else - retval = 0; - - goto finish; - - default: - assert(conf->cmd == PA_CMD_DAEMON); - } - - if (conf->daemonize) { - pid_t child; - int tty_fd; - - if (pa_stdio_acquire() < 0) { - pa_log(__FILE__": failed to acquire stdio.\n"); - goto finish; - } - -#ifdef HAVE_FORK - if (pipe(daemon_pipe) < 0) { - pa_log(__FILE__": failed to create pipe.\n"); - goto finish; - } - - if ((child = fork()) < 0) { - pa_log(__FILE__": fork() failed: %s\n", strerror(errno)); - goto finish; - } - - if (child != 0) { - /* Father */ - - close(daemon_pipe[1]); - daemon_pipe[1] = -1; - - if (pa_loop_read(daemon_pipe[0], &retval, sizeof(retval)) != sizeof(retval)) { - pa_log(__FILE__": read() failed: %s\n", strerror(errno)); - retval = 1; - } - - if (retval) - pa_log(__FILE__": daemon startup failed.\n"); - else - pa_log_info(__FILE__": daemon startup successful.\n"); - - goto finish; - } - - close(daemon_pipe[0]); - daemon_pipe[0] = -1; -#endif - - if (conf->auto_log_target) - pa_log_set_target(PA_LOG_SYSLOG, NULL); - -#ifdef HAVE_SETSID - setsid(); -#endif -#ifdef HAVE_SETPGID - setpgid(0,0); -#endif - -#ifndef OS_IS_WIN32 - close(0); - close(1); - close(2); - - open("/dev/null", O_RDONLY); - open("/dev/null", O_WRONLY); - open("/dev/null", O_WRONLY); -#else - FreeConsole(); -#endif - -#ifdef SIGTTOU - signal(SIGTTOU, SIG_IGN); -#endif -#ifdef SIGTTIN - signal(SIGTTIN, SIG_IGN); -#endif -#ifdef SIGTSTP - signal(SIGTSTP, SIG_IGN); -#endif - -#ifdef TIOCNOTTY - if ((tty_fd = open("/dev/tty", O_RDWR)) >= 0) { - ioctl(tty_fd, TIOCNOTTY, (char*) 0); - close(tty_fd); - } -#endif - } - - chdir("/"); - - if (conf->use_pid_file) { - if (pa_pid_file_create() < 0) { - pa_log(__FILE__": pa_pid_file_create() failed.\n"); -#ifdef HAVE_FORK - if (conf->daemonize) - pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); -#endif - goto finish; - } - - valid_pid_file = 1; - } - - mainloop = pa_mainloop_new(); - assert(mainloop); - - c = pa_core_new(pa_mainloop_get_api(mainloop)); - assert(c); - - r = pa_signal_init(pa_mainloop_get_api(mainloop)); - assert(r == 0); - pa_signal_new(SIGINT, signal_callback, c); - pa_signal_new(SIGTERM, signal_callback, c); -#ifdef SIGPIPE - signal(SIGPIPE, SIG_IGN); -#endif - -#ifdef OS_IS_WIN32 - defer = pa_mainloop_get_api(mainloop)->defer_new(pa_mainloop_get_api(mainloop), message_cb, NULL); - assert(defer); -#endif - - if (conf->daemonize) - c->running_as_daemon = 1; - -#ifdef SIGUSR1 - pa_signal_new(SIGUSR1, signal_callback, c); -#endif -#ifdef SIGUSR2 - pa_signal_new(SIGUSR2, signal_callback, c); -#endif -#ifdef SIGHUP - pa_signal_new(SIGHUP, signal_callback, c); -#endif - - oil_init(); - - r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop)); - assert(r == 0); - - buf = pa_strbuf_new(); - assert(buf); - if (conf->default_script_file) - r = pa_cli_command_execute_file(c, conf->default_script_file, buf, &conf->fail); - - if (r >= 0) - r = pa_cli_command_execute(c, conf->script_commands, buf, &conf->fail); - pa_log(s = pa_strbuf_tostring_free(buf)); - pa_xfree(s); - - if (r < 0 && conf->fail) { - pa_log(__FILE__": failed to initialize daemon.\n"); -#ifdef HAVE_FORK - if (conf->daemonize) - pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); -#endif - } else if (!c->modules || pa_idxset_size(c->modules) == 0) { - pa_log(__FILE__": daemon startup without any loaded modules, refusing to work.\n"); -#ifdef HAVE_FORK - if (conf->daemonize) - pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); -#endif - } else { - - retval = 0; -#ifdef HAVE_FORK - if (conf->daemonize) - pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); -#endif - - c->disallow_module_loading = conf->disallow_module_loading; - c->exit_idle_time = conf->exit_idle_time; - c->module_idle_time = conf->module_idle_time; - c->scache_idle_time = conf->scache_idle_time; - c->resample_method = conf->resample_method; - - if (c->default_sink_name && - pa_namereg_get(c, c->default_sink_name, PA_NAMEREG_SINK, 1) == NULL) { - pa_log_error("%s : Fatal error. Default sink name (%s) does not exist in name register.\n", __FILE__, c->default_sink_name); - retval = 1; - } else { - pa_log_info(__FILE__": Daemon startup complete.\n"); - if (pa_mainloop_run(mainloop, &retval) < 0) - retval = 1; - pa_log_info(__FILE__": Daemon shutdown initiated.\n"); - } - } - -#ifdef OS_IS_WIN32 - pa_mainloop_get_api(mainloop)->defer_free(defer); -#endif - - pa_core_free(c); - - pa_cpu_limit_done(); - pa_signal_done(); - pa_mainloop_free(mainloop); - - pa_log_info(__FILE__": Daemon terminated.\n"); - -finish: - - if (conf) - pa_daemon_conf_free(conf); - - if (valid_pid_file) - pa_pid_file_remove(); - - close_pipe(daemon_pipe); - -#ifdef OS_IS_WIN32 - WSACleanup(); -#endif - - lt_dlexit(); - - return retval; -} diff --git a/polyp/mainloop-api.c b/polyp/mainloop-api.c deleted file mode 100644 index 3229ec20..00000000 --- a/polyp/mainloop-api.c +++ /dev/null @@ -1,68 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "mainloop-api.h" -#include "xmalloc.h" -#include "gccmacro.h" - -struct once_info { - void (*callback)(pa_mainloop_api*m, void *userdata); - void *userdata; -}; - -static void once_callback(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { - struct once_info *i = userdata; - assert(m && i && i->callback); - - i->callback(m, i->userdata); - - assert(m->defer_free); - m->defer_free(e); -} - -static void free_callback(pa_mainloop_api *m, PA_GCC_UNUSED pa_defer_event *e, void *userdata) { - struct once_info *i = userdata; - assert(m && i); - pa_xfree(i); -} - -void pa_mainloop_api_once(pa_mainloop_api* m, void (*callback)(pa_mainloop_api *m, void *userdata), void *userdata) { - struct once_info *i; - pa_defer_event *e; - assert(m && callback); - - i = pa_xnew(struct once_info, 1); - i->callback = callback; - i->userdata = userdata; - - assert(m->defer_new); - e = m->defer_new(m, once_callback, i); - assert(e); - m->defer_set_destroy(e, free_callback); -} - diff --git a/polyp/mainloop-api.h b/polyp/mainloop-api.h deleted file mode 100644 index 91ee4111..00000000 --- a/polyp/mainloop-api.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef foomainloopapihfoo -#define foomainloopapihfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -#include - -/** \file - * - * Main loop abstraction layer. Both the polypaudio core and the - * polypaudio client library use a main loop abstraction layer. Due to - * this it is possible to embed polypaudio into other - * applications easily. Two main loop implemenations are - * currently available: - * \li A minimal implementation based on the C library's poll() function (See \ref mainloop.h) - * \li A wrapper around the GLIB main loop. Use this to embed polypaudio into your GLIB/GTK+/GNOME programs (See \ref glib-mainloop.h) - * - * The structure pa_mainloop_api is used as vtable for the main loop abstraction. - * - * This mainloop abstraction layer has no direct support for UNIX signals. Generic, mainloop implementation agnostic support is available throught \ref mainloop-signal.h. - * */ - -PA_C_DECL_BEGIN - -/** A bitmask for IO events */ -typedef enum pa_io_event_flags { - PA_IO_EVENT_NULL = 0, /**< No event */ - PA_IO_EVENT_INPUT = 1, /**< Input event */ - PA_IO_EVENT_OUTPUT = 2, /**< Output event */ - PA_IO_EVENT_HANGUP = 4, /**< Hangup event */ - PA_IO_EVENT_ERROR = 8 /**< Error event */ -} pa_io_event_flags_t; - -/** \pa_io_event - * An opaque IO event source object */ -typedef struct pa_io_event pa_io_event; - -/** \pa_defer_event - * An opaque deferred event source object. Events of this type are triggered once in every main loop iteration */ -typedef struct pa_defer_event pa_defer_event; - -/** \pa_time_event - * An opaque timer event source object */ -typedef struct pa_time_event pa_time_event; - -/** An abstract mainloop API vtable */ -typedef struct pa_mainloop_api pa_mainloop_api; - -struct pa_mainloop_api { - /** A pointer to some private, arbitrary data of the main loop implementation */ - void *userdata; - - /** Create a new IO event source object */ - pa_io_event* (*io_new)(pa_mainloop_api*a, int fd, pa_io_event_flags_t events, void (*callback) (pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata); - - /** Enable or disable IO events on this object */ - void (*io_enable)(pa_io_event* e, pa_io_event_flags_t events); - - /** Free a IO event source object */ - void (*io_free)(pa_io_event* e); - - /** Set a function that is called when the IO event source is destroyed. Use this to free the userdata argument if required */ - void (*io_set_destroy)(pa_io_event *e, void (*callback) (pa_mainloop_api*a, pa_io_event *e, void *userdata)); - - /** Create a new timer event source object for the specified Unix time */ - pa_time_event* (*time_new)(pa_mainloop_api*a, const struct timeval *tv, void (*callback) (pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata), void *userdata); - - /** Restart a running or expired timer event source with a new Unix time */ - void (*time_restart)(pa_time_event* e, const struct timeval *tv); - - /** Free a deferred timer event source object */ - void (*time_free)(pa_time_event* e); - - /** Set a function that is called when the timer event source is destroyed. Use this to free the userdata argument if required */ - void (*time_set_destroy)(pa_time_event *e, void (*callback) (pa_mainloop_api*a, pa_time_event *e, void *userdata)); - - /** Create a new deferred event source object */ - pa_defer_event* (*defer_new)(pa_mainloop_api*a, void (*callback) (pa_mainloop_api*a, pa_defer_event* e, void *userdata), void *userdata); - - /** Enable or disable a deferred event source temporarily */ - void (*defer_enable)(pa_defer_event* e, int b); - - /** Free a deferred event source object */ - void (*defer_free)(pa_defer_event* e); - - /** Set a function that is called when the deferred event source is destroyed. Use this to free the userdata argument if required */ - void (*defer_set_destroy)(pa_defer_event *e, void (*callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata)); - - /** Exit the main loop and return the specfied retval*/ - void (*quit)(pa_mainloop_api*a, int retval); -}; - -/** Run the specified callback function once from the main loop using an anonymous defer event. */ -void pa_mainloop_api_once(pa_mainloop_api*m, void (*callback)(pa_mainloop_api*m, void *userdata), void *userdata); - -PA_C_DECL_END - -#endif diff --git a/polyp/mainloop-signal.c b/polyp/mainloop-signal.c deleted file mode 100644 index 76936031..00000000 --- a/polyp/mainloop-signal.c +++ /dev/null @@ -1,267 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_WINDOWS_H -#include -#endif - -#include "mainloop-signal.h" -#include "util.h" -#include "xmalloc.h" -#include "log.h" -#include "gccmacro.h" - -struct pa_signal_event { - int sig; -#ifdef HAVE_SIGACTION - struct sigaction saved_sigaction; -#else - void (*saved_handler)(int sig); -#endif - void (*callback) (pa_mainloop_api*a, pa_signal_event *e, int sig, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api*a, pa_signal_event*e, void *userdata); - pa_signal_event *previous, *next; -}; - -static pa_mainloop_api *api = NULL; -static int signal_pipe[2] = { -1, -1 }; -static pa_io_event* io_event = NULL; -static pa_defer_event *defer_event = NULL; -static pa_signal_event *signals = NULL; - -#ifdef OS_IS_WIN32 -static unsigned int waiting_signals = 0; -static CRITICAL_SECTION crit; -#endif - -static void signal_handler(int sig) { -#ifndef HAVE_SIGACTION - signal(sig, signal_handler); -#endif - write(signal_pipe[1], &sig, sizeof(sig)); - -#ifdef OS_IS_WIN32 - EnterCriticalSection(&crit); - waiting_signals++; - LeaveCriticalSection(&crit); -#endif -} - -static void dispatch(pa_mainloop_api*a, int sig) { - pa_signal_event*s; - - for (s = signals; s; s = s->next) - if (s->sig == sig) { - assert(s->callback); - s->callback(a, s, sig, s->userdata); - break; - } -} - -static void defer(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event*e, PA_GCC_UNUSED void *userdata) { - ssize_t r; - int sig; - unsigned int sigs; - -#ifdef OS_IS_WIN32 - EnterCriticalSection(&crit); - sigs = waiting_signals; - waiting_signals = 0; - LeaveCriticalSection(&crit); -#endif - - while (sigs) { - if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) { - pa_log(__FILE__": read(): %s\n", strerror(errno)); - return; - } - - if (r != sizeof(sig)) { - pa_log(__FILE__": short read()\n"); - return; - } - - dispatch(a, sig); - - sigs--; - } -} - -static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags_t f, PA_GCC_UNUSED void *userdata) { - ssize_t r; - int sig; - assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]); - - - if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) { - if (errno == EAGAIN) - return; - - pa_log(__FILE__": read(): %s\n", strerror(errno)); - return; - } - - if (r != sizeof(sig)) { - pa_log(__FILE__": short read()\n"); - return; - } - - dispatch(a, sig); -} - -int pa_signal_init(pa_mainloop_api *a) { - assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event && !defer_event); - -#ifdef OS_IS_WIN32 - if (_pipe(signal_pipe, 200, _O_BINARY) < 0) { -#else - if (pipe(signal_pipe) < 0) { -#endif - pa_log(__FILE__": pipe() failed: %s\n", strerror(errno)); - return -1; - } - - pa_make_nonblock_fd(signal_pipe[0]); - pa_make_nonblock_fd(signal_pipe[1]); - pa_fd_set_cloexec(signal_pipe[0], 1); - pa_fd_set_cloexec(signal_pipe[1], 1); - - api = a; - -#ifndef OS_IS_WIN32 - io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL); - assert(io_event); -#else - defer_event = api->defer_new(api, defer, NULL); - assert(defer_event); - - InitializeCriticalSection(&crit); -#endif - - return 0; -} - -void pa_signal_done(void) { - assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && (io_event || defer_event)); - - while (signals) - pa_signal_free(signals); - - -#ifndef OS_IS_WIN32 - api->io_free(io_event); - io_event = NULL; -#else - api->defer_free(defer_event); - defer_event = NULL; - - DeleteCriticalSection(&crit); -#endif - - close(signal_pipe[0]); - close(signal_pipe[1]); - signal_pipe[0] = signal_pipe[1] = -1; - - api = NULL; -} - -pa_signal_event* pa_signal_new(int sig, void (*_callback) (pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata), void *userdata) { - pa_signal_event *e = NULL; - -#ifdef HAVE_SIGACTION - struct sigaction sa; -#endif - - assert(sig > 0 && _callback); - - for (e = signals; e; e = e->next) - if (e->sig == sig) - goto fail; - - e = pa_xmalloc(sizeof(pa_signal_event)); - e->sig = sig; - e->callback = _callback; - e->userdata = userdata; - e->destroy_callback = NULL; - -#ifdef HAVE_SIGACTION - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = signal_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - - if (sigaction(sig, &sa, &e->saved_sigaction) < 0) -#else - if ((e->saved_handler = signal(sig, signal_handler)) == SIG_ERR) -#endif - goto fail; - - e->previous = NULL; - e->next = signals; - signals = e; - - return e; -fail: - if (e) - pa_xfree(e); - return NULL; -} - -void pa_signal_free(pa_signal_event *e) { - assert(e); - - if (e->next) - e->next->previous = e->previous; - if (e->previous) - e->previous->next = e->next; - else - signals = e->next; - -#ifdef HAVE_SIGACTION - sigaction(e->sig, &e->saved_sigaction, NULL); -#else - signal(e->sig, e->saved_handler); -#endif - - if (e->destroy_callback) - e->destroy_callback(api, e, e->userdata); - - pa_xfree(e); -} - -void pa_signal_set_destroy(pa_signal_event *e, void (*_callback) (pa_mainloop_api *api, pa_signal_event*e, void *userdata)) { - assert(e); - e->destroy_callback = _callback; -} diff --git a/polyp/mainloop-signal.h b/polyp/mainloop-signal.h deleted file mode 100644 index 6ce31370..00000000 --- a/polyp/mainloop-signal.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef foomainloopsignalhfoo -#define foomainloopsignalhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "mainloop-api.h" -#include "cdecl.h" - -PA_C_DECL_BEGIN - -/** \file - * UNIX signal support for main loops. In contrast to other - * main loop event sources such as timer and IO events, UNIX signal - * support requires modification of the global process - * environment. Due to this the generic main loop abstraction layer as - * defined in \ref mainloop-api.h doesn't have direct support for UNIX - * signals. However, you may hook signal support into an abstract main loop via the routines defined herein. - */ - -/** Initialize the UNIX signal subsystem and bind it to the specified main loop */ -int pa_signal_init(pa_mainloop_api *api); - -/** Cleanup the signal subsystem */ -void pa_signal_done(void); - -/** \pa_signal_event - * An opaque UNIX signal event source object */ -typedef struct pa_signal_event pa_signal_event; - -/** Create a new UNIX signal event source object */ -pa_signal_event* pa_signal_new(int sig, void (*callback) (pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata), void *userdata); - -/** Free a UNIX signal event source object */ -void pa_signal_free(pa_signal_event *e); - -/** Set a function that is called when the signal event source is destroyed. Use this to free the userdata argument if required */ -void pa_signal_set_destroy(pa_signal_event *e, void (*callback) (pa_mainloop_api *api, pa_signal_event*e, void *userdata)); - -PA_C_DECL_END - -#endif diff --git a/polyp/mainloop-test.c b/polyp/mainloop-test.c deleted file mode 100644 index ee0f8711..00000000 --- a/polyp/mainloop-test.c +++ /dev/null @@ -1,146 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "util.h" -#include "gccmacro.h" - -#ifdef GLIB_MAIN_LOOP - -#include -#include "glib-mainloop.h" - -static GMainLoop* glib_main_loop = NULL; - -#if GLIB_MAJOR_VERSION >= 2 -#define GLIB20 -#else -#undef GLIB20 -#endif - - -#else /* GLIB_MAIN_LOOP */ -#include "mainloop.h" -#endif /* GLIB_MAIN_LOOP */ - -static pa_defer_event *de; - -static void iocb(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { - unsigned char c; - read(fd, &c, sizeof(c)); - fprintf(stderr, "IO EVENT: %c\n", c < 32 ? '.' : c); - a->defer_enable(de, 1); -} - -static void dcb(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { - fprintf(stderr, "DEFER EVENT\n"); - a->defer_enable(e, 0); -} - -static void tcb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) { - fprintf(stderr, "TIME EVENT\n"); - -#if defined(GLIB_MAIN_LOOP) && defined(GLIB20) - g_main_loop_quit(glib_main_loop); -#elif defined(GLIB_MAIN_LOOP) - g_main_quit(glib_main_loop); -#else - a->quit(a, 0); -#endif -} - -int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { - pa_mainloop_api *a; - pa_io_event *ioe; - pa_time_event *te; - struct timeval tv; - -#ifdef GLIB_MAIN_LOOP - pa_glib_mainloop *g; - -#ifdef GLIB20 - glib_main_loop = g_main_loop_new(NULL, FALSE); - assert(glib_main_loop); - - g = pa_glib_mainloop_new(NULL); -#else /* GLIB20 */ - glib_main_loop = g_main_new(FALSE); - assert(glib_main_loop); - - g = pa_glib_mainloop_new(); -#endif /* GLIB20 */ - assert(g); - - a = pa_glib_mainloop_get_api(g); - assert(a); -#else /* GLIB_MAIN_LOOP */ - pa_mainloop *m; - - m = pa_mainloop_new(); - assert(m); - - a = pa_mainloop_get_api(m); - assert(a); -#endif /* GLIB_MAIN_LOOP */ - - ioe = a->io_new(a, 0, PA_IO_EVENT_INPUT, iocb, NULL); - assert(ioe); - - de = a->defer_new(a, dcb, NULL); - assert(de); - - pa_gettimeofday(&tv); - tv.tv_sec += 10; - te = a->time_new(a, &tv, tcb, NULL); - -#if defined(GLIB_MAIN_LOOP) && defined(GLIB20) - g_main_loop_run(glib_main_loop); -#elif defined(GLIB_MAIN_LOOP) - g_main_run(glib_main_loop); -#else - pa_mainloop_run(m, NULL); -#endif - - a->time_free(te); - a->defer_free(de); - a->io_free(ioe); - -#ifdef GLIB_MAIN_LOOP - pa_glib_mainloop_free(g); -#ifdef GLIB20 - g_main_loop_unref(glib_main_loop); -#else - g_main_destroy(glib_main_loop); -#endif -#else - pa_mainloop_free(m); -#endif - - return 0; -} diff --git a/polyp/mainloop.c b/polyp/mainloop.c deleted file mode 100644 index d25af78a..00000000 --- a/polyp/mainloop.c +++ /dev/null @@ -1,812 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_POLL_H -#include -#else -#include "poll.h" -#endif - -#include "winsock.h" - -#include "mainloop.h" -#include "util.h" -#include "idxset.h" -#include "xmalloc.h" -#include "log.h" - -struct pa_io_event { - pa_mainloop *mainloop; - int dead; - int fd; - pa_io_event_flags_t events; - void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); - struct pollfd *pollfd; - void *userdata; - void (*destroy_callback) (pa_mainloop_api*a, pa_io_event *e, void *userdata); -}; - -struct pa_time_event { - pa_mainloop *mainloop; - int dead; - int enabled; - struct timeval timeval; - void (*callback)(pa_mainloop_api*a, pa_time_event *e, const struct timeval*tv, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api*a, pa_time_event *e, void *userdata); -}; - -struct pa_defer_event { - pa_mainloop *mainloop; - int dead; - int enabled; - void (*callback)(pa_mainloop_api*a, pa_defer_event*e, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata); -}; - -struct pa_mainloop { - pa_idxset *io_events, *time_events, *defer_events; - int io_events_scan_dead, defer_events_scan_dead, time_events_scan_dead; - - struct pollfd *pollfds; - unsigned max_pollfds, n_pollfds; - int rebuild_pollfds; - - int prepared_timeout; - - int quit, retval; - pa_mainloop_api api; - - int deferred_pending; - - int wakeup_pipe[2]; - - enum { - STATE_PASSIVE, - STATE_PREPARED, - STATE_POLLING, - STATE_POLLED, - STATE_QUIT - } state; -}; - -/* IO events */ -static pa_io_event* mainloop_io_new( - pa_mainloop_api*a, - int fd, - pa_io_event_flags_t events, - void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), - void *userdata) { - - pa_mainloop *m; - pa_io_event *e; - - assert(a && a->userdata && fd >= 0 && callback); - m = a->userdata; - assert(a == &m->api); - - pa_mainloop_wakeup(m); - - e = pa_xmalloc(sizeof(pa_io_event)); - e->mainloop = m; - e->dead = 0; - - e->fd = fd; - e->events = events; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - e->pollfd = NULL; - -#ifdef OS_IS_WIN32 - { - fd_set xset; - struct timeval tv; - - tv.tv_sec = 0; - tv.tv_usec = 0; - - FD_ZERO (&xset); - FD_SET (fd, &xset); - - if ((select((SELECT_TYPE_ARG1) fd, NULL, NULL, SELECT_TYPE_ARG234 &xset, - SELECT_TYPE_ARG5 &tv) == -1) && - (WSAGetLastError() == WSAENOTSOCK)) { - pa_log_warn(__FILE__": WARNING: cannot monitor non-socket file descriptors.\n"); - e->dead = 1; - } - } -#endif - - pa_idxset_put(m->io_events, e, NULL); - m->rebuild_pollfds = 1; - return e; -} - -static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags_t events) { - assert(e && e->mainloop); - - pa_mainloop_wakeup(e->mainloop); - - e->events = events; - e->mainloop->rebuild_pollfds = 1; -} - -static void mainloop_io_free(pa_io_event *e) { - assert(e && e->mainloop); - - pa_mainloop_wakeup(e->mainloop); - - e->dead = e->mainloop->io_events_scan_dead = e->mainloop->rebuild_pollfds = 1; -} - -static void mainloop_io_set_destroy(pa_io_event *e, void (*callback)(pa_mainloop_api*a, pa_io_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Defer events */ -static pa_defer_event* mainloop_defer_new(pa_mainloop_api*a, void (*callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata), void *userdata) { - pa_mainloop *m; - pa_defer_event *e; - - assert(a && a->userdata && callback); - m = a->userdata; - assert(a == &m->api); - - e = pa_xmalloc(sizeof(pa_defer_event)); - e->mainloop = m; - e->dead = 0; - - e->enabled = 1; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - - pa_idxset_put(m->defer_events, e, NULL); - - m->deferred_pending++; - return e; -} - -static void mainloop_defer_enable(pa_defer_event *e, int b) { - assert(e); - - if (e->enabled && !b) { - assert(e->mainloop->deferred_pending > 0); - e->mainloop->deferred_pending--; - } else if (!e->enabled && b) - e->mainloop->deferred_pending++; - - e->enabled = b; -} - -static void mainloop_defer_free(pa_defer_event *e) { - assert(e); - e->dead = e->mainloop->defer_events_scan_dead = 1; - - if (e->enabled) { - e->enabled = 0; - assert(e->mainloop->deferred_pending > 0); - e->mainloop->deferred_pending--; - } -} - -static void mainloop_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api*a, pa_defer_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Time events */ -static pa_time_event* mainloop_time_new(pa_mainloop_api*a, const struct timeval *tv, void (*callback) (pa_mainloop_api*a, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { - pa_mainloop *m; - pa_time_event *e; - - assert(a && a->userdata && callback); - m = a->userdata; - assert(a == &m->api); - - pa_mainloop_wakeup(m); - - e = pa_xmalloc(sizeof(pa_time_event)); - e->mainloop = m; - e->dead = 0; - - e->enabled = !!tv; - if (tv) - e->timeval = *tv; - - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - - pa_idxset_put(m->time_events, e, NULL); - - return e; -} - -static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) { - assert(e); - - pa_mainloop_wakeup(e->mainloop); - - if (tv) { - e->enabled = 1; - e->timeval = *tv; - } else - e->enabled = 0; -} - -static void mainloop_time_free(pa_time_event *e) { - assert(e); - - pa_mainloop_wakeup(e->mainloop); - - e->dead = e->mainloop->time_events_scan_dead = 1; -} - -static void mainloop_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*a, pa_time_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* quit() */ - -static void mainloop_quit(pa_mainloop_api*a, int retval) { - pa_mainloop *m; - assert(a && a->userdata); - m = a->userdata; - assert(a == &m->api); - - pa_mainloop_wakeup(m); - - m->quit = 1; - m->retval = retval; -} - -static const pa_mainloop_api vtable = { - .userdata = NULL, - - .io_new= mainloop_io_new, - .io_enable= mainloop_io_enable, - .io_free= mainloop_io_free, - .io_set_destroy= mainloop_io_set_destroy, - - .time_new = mainloop_time_new, - .time_restart = mainloop_time_restart, - .time_free = mainloop_time_free, - .time_set_destroy = mainloop_time_set_destroy, - - .defer_new = mainloop_defer_new, - .defer_enable = mainloop_defer_enable, - .defer_free = mainloop_defer_free, - .defer_set_destroy = mainloop_defer_set_destroy, - - .quit = mainloop_quit, -}; - -pa_mainloop *pa_mainloop_new(void) { - pa_mainloop *m; - - m = pa_xmalloc(sizeof(pa_mainloop)); - -#ifndef OS_ISWIN32 - if (pipe(m->wakeup_pipe) < 0) { - pa_xfree(m); - return NULL; - } - - pa_make_nonblock_fd(m->wakeup_pipe[0]); - pa_make_nonblock_fd(m->wakeup_pipe[1]); -#else - m->wakeup_pipe[0] = -1; - m->wakeup_pipe[1] = -1; -#endif - - m->io_events = pa_idxset_new(NULL, NULL); - m->defer_events = pa_idxset_new(NULL, NULL); - m->time_events = pa_idxset_new(NULL, NULL); - - assert(m->io_events && m->defer_events && m->time_events); - - m->io_events_scan_dead = m->defer_events_scan_dead = m->time_events_scan_dead = 0; - - m->pollfds = NULL; - m->max_pollfds = m->n_pollfds = m->rebuild_pollfds = 0; - - m->quit = m->retval = 0; - - m->api = vtable; - m->api.userdata = m; - - m->deferred_pending = 0; - - m->state = STATE_PASSIVE; - - return m; -} - -static int io_foreach(void *p, uint32_t PA_GCC_UNUSED idx, int *del, void*userdata) { - pa_io_event *e = p; - int *all = userdata; - assert(e && del && all); - - if (!*all && !e->dead) - return 0; - - if (e->destroy_callback) - e->destroy_callback(&e->mainloop->api, e, e->userdata); - pa_xfree(e); - *del = 1; - return 0; -} - -static int time_foreach(void *p, uint32_t PA_GCC_UNUSED idx, int *del, void*userdata) { - pa_time_event *e = p; - int *all = userdata; - assert(e && del && all); - - if (!*all && !e->dead) - return 0; - - if (e->destroy_callback) - e->destroy_callback(&e->mainloop->api, e, e->userdata); - pa_xfree(e); - *del = 1; - return 0; -} - -static int defer_foreach(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void*userdata) { - pa_defer_event *e = p; - int *all = userdata; - assert(e && del && all); - - if (!*all && !e->dead) - return 0; - - if (e->destroy_callback) - e->destroy_callback(&e->mainloop->api, e, e->userdata); - pa_xfree(e); - *del = 1; - return 0; -} - -void pa_mainloop_free(pa_mainloop* m) { - int all = 1; - assert(m && (m->state != STATE_POLLING)); - - pa_idxset_foreach(m->io_events, io_foreach, &all); - pa_idxset_foreach(m->time_events, time_foreach, &all); - pa_idxset_foreach(m->defer_events, defer_foreach, &all); - - pa_idxset_free(m->io_events, NULL, NULL); - pa_idxset_free(m->time_events, NULL, NULL); - pa_idxset_free(m->defer_events, NULL, NULL); - - pa_xfree(m->pollfds); - - if (m->wakeup_pipe[0] >= 0) - close(m->wakeup_pipe[0]); - if (m->wakeup_pipe[1] >= 0) - close(m->wakeup_pipe[1]); - - pa_xfree(m); -} - -static void scan_dead(pa_mainloop *m) { - int all = 0; - assert(m); - - if (m->io_events_scan_dead) - pa_idxset_foreach(m->io_events, io_foreach, &all); - if (m->time_events_scan_dead) - pa_idxset_foreach(m->time_events, time_foreach, &all); - if (m->defer_events_scan_dead) - pa_idxset_foreach(m->defer_events, defer_foreach, &all); - - m->io_events_scan_dead = m->time_events_scan_dead = m->defer_events_scan_dead = 0; -} - -static void rebuild_pollfds(pa_mainloop *m) { - pa_io_event*e; - struct pollfd *p; - uint32_t idx = PA_IDXSET_INVALID; - unsigned l; - - l = pa_idxset_size(m->io_events) + 1; - if (m->max_pollfds < l) { - m->pollfds = pa_xrealloc(m->pollfds, sizeof(struct pollfd)*l); - m->max_pollfds = l; - } - - m->n_pollfds = 0; - p = m->pollfds; - - if (m->wakeup_pipe[0] >= 0) { - m->pollfds[0].fd = m->wakeup_pipe[0]; - m->pollfds[0].events = POLLIN; - m->pollfds[0].revents = 0; - p++; - m->n_pollfds++; - } - - for (e = pa_idxset_first(m->io_events, &idx); e; e = pa_idxset_next(m->io_events, &idx)) { - if (e->dead) { - e->pollfd = NULL; - continue; - } - - e->pollfd = p; - p->fd = e->fd; - p->events = - ((e->events & PA_IO_EVENT_INPUT) ? POLLIN : 0) | - ((e->events & PA_IO_EVENT_OUTPUT) ? POLLOUT : 0) | - POLLHUP | - POLLERR; - p->revents = 0; - - p++; - m->n_pollfds++; - } - - m->rebuild_pollfds = 0; -} - -static int dispatch_pollfds(pa_mainloop *m) { - uint32_t idx = PA_IDXSET_INVALID; - pa_io_event *e; - int r = 0; - - for (e = pa_idxset_first(m->io_events, &idx); e && !m->quit; e = pa_idxset_next(m->io_events, &idx)) { - if (e->dead || !e->pollfd || !e->pollfd->revents) - continue; - - assert(e->pollfd->fd == e->fd && e->callback); - e->callback(&m->api, e, e->fd, - (e->pollfd->revents & POLLHUP ? PA_IO_EVENT_HANGUP : 0) | - (e->pollfd->revents & POLLIN ? PA_IO_EVENT_INPUT : 0) | - (e->pollfd->revents & POLLOUT ? PA_IO_EVENT_OUTPUT : 0) | - (e->pollfd->revents & POLLERR ? PA_IO_EVENT_ERROR : 0), - e->userdata); - e->pollfd->revents = 0; - r++; - } - - return r; -} - -static int dispatch_defer(pa_mainloop *m) { - uint32_t idx; - pa_defer_event *e; - int r = 0; - - if (!m->deferred_pending) - return 0; - - for (e = pa_idxset_first(m->defer_events, &idx); e && !m->quit; e = pa_idxset_next(m->defer_events, &idx)) { - if (e->dead || !e->enabled) - continue; - - assert(e->callback); - e->callback(&m->api, e, e->userdata); - r++; - } - - return r; -} - -static int calc_next_timeout(pa_mainloop *m) { - uint32_t idx; - pa_time_event *e; - struct timeval now; - int t = -1; - int got_time = 0; - - if (pa_idxset_isempty(m->time_events)) - return -1; - - for (e = pa_idxset_first(m->time_events, &idx); e; e = pa_idxset_next(m->time_events, &idx)) { - int tmp; - - if (e->dead || !e->enabled) - continue; - - /* Let's save a system call */ - if (!got_time) { - pa_gettimeofday(&now); - got_time = 1; - } - - if (e->timeval.tv_sec < now.tv_sec || (e->timeval.tv_sec == now.tv_sec && e->timeval.tv_usec <= now.tv_usec)) - return 0; - - tmp = (e->timeval.tv_sec - now.tv_sec)*1000; - - if (e->timeval.tv_usec > now.tv_usec) - tmp += (e->timeval.tv_usec - now.tv_usec)/1000; - else - tmp -= (now.tv_usec - e->timeval.tv_usec)/1000; - - if (tmp == 0) - return 0; - else if (t == -1 || tmp < t) - t = tmp; - } - - return t; -} - -static int dispatch_timeout(pa_mainloop *m) { - uint32_t idx; - pa_time_event *e; - struct timeval now; - int got_time = 0; - int r = 0; - assert(m); - - if (pa_idxset_isempty(m->time_events)) - return 0; - - for (e = pa_idxset_first(m->time_events, &idx); e && !m->quit; e = pa_idxset_next(m->time_events, &idx)) { - - if (e->dead || !e->enabled) - continue; - - /* Let's save a system call */ - if (!got_time) { - pa_gettimeofday(&now); - got_time = 1; - } - - if (e->timeval.tv_sec < now.tv_sec || (e->timeval.tv_sec == now.tv_sec && e->timeval.tv_usec <= now.tv_usec)) { - assert(e->callback); - - e->enabled = 0; - e->callback(&m->api, e, &e->timeval, e->userdata); - - r++; - } - } - - return r; -} - -void pa_mainloop_wakeup(pa_mainloop *m) { - char c = 'W'; - assert(m); - - if (m->wakeup_pipe[1] >= 0) - write(m->wakeup_pipe[1], &c, sizeof(c)); -} - -static void clear_wakeup(pa_mainloop *m) { - char c[10]; - - assert(m); - - if (m->wakeup_pipe[0] < 0) - return; - - while (read(m->wakeup_pipe[0], &c, sizeof(c)) == sizeof(c)); -} - -int pa_mainloop_prepare(pa_mainloop *m, int timeout) { - int dispatched = 0; - - assert(m && (m->state == STATE_PASSIVE)); - - clear_wakeup(m); - - scan_dead(m); - - if (m->quit) - goto quit; - - dispatched += dispatch_defer(m); - - if (m->quit) - goto quit; - - if (m->rebuild_pollfds) - rebuild_pollfds(m); - - m->prepared_timeout = calc_next_timeout(m); - if ((timeout >= 0) && (m->prepared_timeout > timeout)) - m->prepared_timeout = timeout; - - m->state = STATE_PREPARED; - - return dispatched; - -quit: - - m->state = STATE_QUIT; - - return -2; -} - -int pa_mainloop_poll(pa_mainloop *m) { - int r; - - assert(m && (m->state == STATE_PREPARED)); - - m->state = STATE_POLLING; - - r = poll(m->pollfds, m->n_pollfds, m->prepared_timeout); - - if ((r < 0) && (errno == EINTR)) - r = 0; - - if (r < 0) - m->state = STATE_PASSIVE; - else - m->state = STATE_POLLED; - - return r; -} - -int pa_mainloop_dispatch(pa_mainloop *m) { - int dispatched = 0; - - assert(m && (m->state == STATE_POLLED)); - - dispatched += dispatch_timeout(m); - - if (m->quit) - goto quit; - - dispatched += dispatch_pollfds(m); - - if (m->quit) - goto quit; - - m->state = STATE_PASSIVE; - - return dispatched; - -quit: - - m->state = STATE_QUIT; - - return -2; -} - -int pa_mainloop_get_retval(pa_mainloop *m) { - assert(m); - return m->retval; -} - -int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) { - int r, dispatched = 0; - - assert(m); - - r = pa_mainloop_prepare(m, block ? -1 : 0); - if (r < 0) { - if ((r == -2) && retval) - *retval = pa_mainloop_get_retval(m); - return r; - } - - dispatched += r; - - r = pa_mainloop_poll(m); - if (r < 0) { - pa_log(__FILE__": poll(): %s\n", strerror(errno)); - return r; - } - - r = pa_mainloop_dispatch(m); - if (r < 0) { - if ((r == -2) && retval) - *retval = pa_mainloop_get_retval(m); - return r; - } - - dispatched += r; - - return dispatched; -} - -int pa_mainloop_run(pa_mainloop *m, int *retval) { - int r; - while ((r = pa_mainloop_iterate(m, 1, retval)) >= 0); - - if (r == -2) - return 1; - else if (r < 0) - return -1; - else - return 0; -} - -void pa_mainloop_quit(pa_mainloop *m, int r) { - assert(m); - pa_mainloop_wakeup(m); - m->quit = r; -} - -pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m) { - assert(m); - return &m->api; -} - -int pa_mainloop_deferred_pending(pa_mainloop *m) { - assert(m); - return m->deferred_pending > 0; -} - - -#if 0 -void pa_mainloop_dump(pa_mainloop *m) { - assert(m); - - pa_log(__FILE__": Dumping mainloop sources START\n"); - - { - uint32_t idx = PA_IDXSET_INVALID; - pa_io_event *e; - for (e = pa_idxset_first(m->io_events, &idx); e; e = pa_idxset_next(m->io_events, &idx)) { - if (e->dead) - continue; - - pa_log(__FILE__": kind=io fd=%i events=%i callback=%p userdata=%p\n", e->fd, (int) e->events, (void*) e->callback, (void*) e->userdata); - } - } - { - uint32_t idx = PA_IDXSET_INVALID; - pa_defer_event *e; - for (e = pa_idxset_first(m->defer_events, &idx); e; e = pa_idxset_next(m->defer_events, &idx)) { - if (e->dead) - continue; - - pa_log(__FILE__": kind=defer enabled=%i callback=%p userdata=%p\n", e->enabled, (void*) e->callback, (void*) e->userdata); - } - } - { - uint32_t idx = PA_IDXSET_INVALID; - pa_time_event *e; - for (e = pa_idxset_first(m->time_events, &idx); e; e = pa_idxset_next(m->time_events, &idx)) { - if (e->dead) - continue; - - pa_log(__FILE__": kind=time enabled=%i time=%lu.%lu callback=%p userdata=%p\n", e->enabled, (unsigned long) e->timeval.tv_sec, (unsigned long) e->timeval.tv_usec, (void*) e->callback, (void*) e->userdata); - } - } - - pa_log(__FILE__": Dumping mainloop sources STOP\n"); - -} -#endif diff --git a/polyp/mainloop.h b/polyp/mainloop.h deleted file mode 100644 index 921a0709..00000000 --- a/polyp/mainloop.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef foomainloophfoo -#define foomainloophfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "mainloop-api.h" -#include "cdecl.h" - -PA_C_DECL_BEGIN - -/** \file - * - * A minimal main loop implementation based on the C library's poll() - * function. Using the routines defined herein you may create a simple - * main loop supporting the generic main loop abstraction layer as - * defined in \ref mainloop-api.h. This implementation is thread safe - * as long as you access the main loop object from a single thread only.*/ - -/** \pa_mainloop - * An opaque main loop object - */ -typedef struct pa_mainloop pa_mainloop; - -/** Allocate a new main loop object */ -pa_mainloop *pa_mainloop_new(void); - -/** Free a main loop object */ -void pa_mainloop_free(pa_mainloop* m); - - -/** Prepare for a single iteration of the main loop. Returns a negative value -on error or exit request. timeout specifies a maximum timeout for the subsequent -poll, or -1 for blocking behaviour. Defer events are also dispatched when this -function is called. On success returns the number of source dispatched in this -iteration.*/ -int pa_mainloop_prepare(pa_mainloop *m, int timeout); -/** Execute the previously prepared poll. Returns a negative value on error.*/ -int pa_mainloop_poll(pa_mainloop *m); -/** Dispatch timeout and io events from the previously executed poll. Returns -a negative value on error. On success returns the number of source dispatched. */ -int pa_mainloop_dispatch(pa_mainloop *m); - -/** Return the return value as specified with the main loop's quit() routine. */ -int pa_mainloop_get_retval(pa_mainloop *m); - -/** Run a single iteration of the main loop. This is a convenience function -for pa_mainloop_prepare(), pa_mainloop_poll() and pa_mainloop_dispatch(). -Returns a negative value on error or exit request. If block is nonzero, -block for events if none are queued. Optionally return the return value as -specified with the main loop's quit() routine in the integer variable retval points -to. On success returns the number of source dispatched in this iteration. */ -int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval); - -/** Run unlimited iterations of the main loop object until the main loop's quit() routine is called. */ -int pa_mainloop_run(pa_mainloop *m, int *retval); - -/** Return the abstract main loop abstraction layer vtable for this main loop. This calls pa_mainloop_iterate() iteratively.*/ -pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m); - -/** Return non-zero when there are any deferred events pending. \since 0.5 */ -int pa_mainloop_deferred_pending(pa_mainloop *m); - -/** Shutdown the main loop */ -void pa_mainloop_quit(pa_mainloop *m, int r); - -/** Interrupt a running poll (for threaded systems) */ -void pa_mainloop_wakeup(pa_mainloop *m); - -PA_C_DECL_END - -#endif diff --git a/polyp/mcalign-test.c b/polyp/mcalign-test.c deleted file mode 100644 index c151d8f2..00000000 --- a/polyp/mcalign-test.c +++ /dev/null @@ -1,96 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "util.h" -#include "mcalign.h" -#include "gccmacro.h" - -/* A simple program for testing pa_mcalign */ - -int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { - pa_mcalign *a = pa_mcalign_new(11, NULL); - pa_memchunk c; - - pa_memchunk_reset(&c); - - srand(time(NULL)); - - for (;;) { - ssize_t r; - size_t l; - - if (!c.memblock) { - c.memblock = pa_memblock_new(2048, NULL); - c.index = c.length = 0; - } - - assert(c.index < c.memblock->length); - - l = c.memblock->length - c.index; - - l = l <= 1 ? l : rand() % (l-1) +1 ; - - if ((r = read(STDIN_FILENO, (uint8_t*) c.memblock->data + c.index, l)) <= 0) { - fprintf(stderr, "read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); - break; - } - - c.length = r; - pa_mcalign_push(a, &c); - fprintf(stderr, "Read %d bytes\n", r); - - c.index += r; - - if (c.index >= c.memblock->length) { - pa_memblock_unref(c.memblock); - pa_memchunk_reset(&c); - } - - for (;;) { - pa_memchunk t; - - if (pa_mcalign_pop(a, &t) < 0) - break; - - pa_loop_write(STDOUT_FILENO, (uint8_t*) t.memblock->data + t.index, t.length); - fprintf(stderr, "Wrote %lu bytes.\n", (unsigned long) t.length); - - pa_memblock_unref(t.memblock); - } - } - - pa_mcalign_free(a); - - if (c.memblock) - pa_memblock_unref(c.memblock); -} diff --git a/polyp/mcalign.c b/polyp/mcalign.c deleted file mode 100644 index 4d765625..00000000 --- a/polyp/mcalign.c +++ /dev/null @@ -1,188 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "mcalign.h" -#include "xmalloc.h" - -struct pa_mcalign { - size_t base; - pa_memchunk leftover, current; - pa_memblock_stat *memblock_stat; -}; - -pa_mcalign *pa_mcalign_new(size_t base, pa_memblock_stat *s) { - pa_mcalign *m; - assert(base); - - m = pa_xnew(pa_mcalign, 1); - m->base = base; - pa_memchunk_reset(&m->leftover); - pa_memchunk_reset(&m->current); - m->memblock_stat = s; - - return m; -} - -void pa_mcalign_free(pa_mcalign *m) { - assert(m); - - if (m->leftover.memblock) - pa_memblock_unref(m->leftover.memblock); - - if (m->current.memblock) - pa_memblock_unref(m->current.memblock); - - pa_xfree(m); -} - -void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { - assert(m && c && c->memblock && c->length); - - /* Append to the leftover memory block */ - if (m->leftover.memblock) { - assert(!m->current.memblock); - - /* Try to merge */ - if (m->leftover.memblock == c->memblock && - m->leftover.index + m->leftover.length == c->index) { - - /* Merge */ - m->leftover.length += c->length; - - /* If the new chunk is larger than m->base, move it to current */ - if (m->leftover.length >= m->base) { - m->current = m->leftover; - pa_memchunk_reset(&m->leftover); - } - - } else { - size_t l; - - /* We have to copy */ - assert(m->leftover.length < m->base); - l = m->base - m->leftover.length; - - if (l > c->length) - l = c->length; - - /* Can we use the current block? */ - pa_memchunk_make_writable(&m->leftover, m->memblock_stat, m->base); - - memcpy((uint8_t*) m->leftover.memblock->data + m->leftover.index + m->leftover.length, (uint8_t*) c->memblock->data + c->index, l); - m->leftover.length += l; - - assert(m->leftover.length <= m->base && m->leftover.length <= m->leftover.memblock->length); - - if (c->length > l) { - /* Save the remainder of the memory block */ - m->current = *c; - m->current.index += l; - m->current.length -= l; - pa_memblock_ref(m->current.memblock); - } - } - } else { - assert(!m->leftover.memblock && !m->current.memblock); - - /* Nothing to merge or copy, just store it */ - - if (c->length >= m->base) - m->current = *c; - else - m->leftover = *c; - - pa_memblock_ref(c->memblock); - } -} - -int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) { - assert(m && c); - - /* First test if there's a leftover memory block available */ - if (m->leftover.memblock) { - assert(m->leftover.length > 0 && m->leftover.length <= m->base); - - /* The leftover memory block is not yet complete */ - if (m->leftover.length < m->base) - return -1; - - /* Return the leftover memory block */ - *c = m->leftover; - pa_memchunk_reset(&m->leftover); - - /* If the current memblock is too small move it the leftover */ - if (m->current.memblock && m->current.length < m->base) { - m->leftover = m->current; - pa_memchunk_reset(&m->current); - } - - return 0; - } - - /* Now let's see if there is other data available */ - if (m->current.memblock) { - size_t l; - assert(m->current.length >= m->base); - - /* The length of the returned memory block */ - l = m->current.length; - l /= m->base; - l *= m->base; - assert(l > 0); - - /* Prepare the returned block */ - *c = m->current; - pa_memblock_ref(c->memblock); - c->length = l; - - /* Drop that from the current memory block */ - assert(l <= m->current.length); - m->current.index += l; - m->current.length -= l; - - /* In case the whole block was dropped ... */ - if (m->current.length == 0) - pa_memblock_unref(m->current.memblock); - else { - /* Move the raimainder to leftover */ - assert(m->current.length < m->base && !m->leftover.memblock); - - m->leftover = m->current; - } - - pa_memchunk_reset(&m->current); - - return 0; - } - - /* There's simply nothing */ - return -1; - -} diff --git a/polyp/mcalign.h b/polyp/mcalign.h deleted file mode 100644 index 5de75bc7..00000000 --- a/polyp/mcalign.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef foomcalignhfoo -#define foomcalignhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "memblock.h" -#include "memchunk.h" - -/* An alignment object, used for aligning memchunks to multiples of - * the frame size. */ - -/* Method of operation: the user creates a new mcalign object by - * calling pa_mcalign_new() with the appropriate aligning - * granularity. After that he may call pa_mcalign_push() for an input - * memchunk. After exactly one memchunk the user has to call - * pa_mcalign_pop() until it returns -1. If pa_mcalign_pop() returns - * 0, the memchunk *c is valid and aligned to the granularity. Some - * pseudocode illustrating this: - * - * pa_mcalign *a = pa_mcalign_new(4, NULL); - * - * for (;;) { - * pa_memchunk input; - * - * ... fill input ... - * - * pa_mcalign_push(m, &input); - * pa_memblock_unref(input.memblock); - * - * for (;;) { - * pa_memchunk output; - * - * if (pa_mcalign_pop(m, &output) < 0) - * break; - * - * ... consume output ... - * - * pa_memblock_unref(output.memblock); - * } - * } - * - * pa_memchunk_free(a); - * */ - -typedef struct pa_mcalign pa_mcalign; - -pa_mcalign *pa_mcalign_new(size_t base, pa_memblock_stat *s); -void pa_mcalign_free(pa_mcalign *m); - -/* Push a new memchunk into the aligner. The caller of this routine - * has to free the memchunk by himself. */ -void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c); - -/* Pop a new memchunk from the aligner. Returns 0 when sucessful, - * nonzero otherwise. */ -int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c); - -#endif diff --git a/polyp/memblock.c b/polyp/memblock.c deleted file mode 100644 index 8da53525..00000000 --- a/polyp/memblock.c +++ /dev/null @@ -1,169 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "memblock.h" -#include "xmalloc.h" - -static void stat_add(pa_memblock*m, pa_memblock_stat *s) { - assert(m); - - if (!s) { - m->stat = NULL; - return; - } - - m->stat = pa_memblock_stat_ref(s); - s->total++; - s->allocated++; - s->total_size += m->length; - s->allocated_size += m->length; -} - -static void stat_remove(pa_memblock *m) { - assert(m); - - if (!m->stat) - return; - - m->stat->total--; - m->stat->total_size -= m->length; - - pa_memblock_stat_unref(m->stat); - m->stat = NULL; -} - -pa_memblock *pa_memblock_new(size_t length, pa_memblock_stat*s) { - pa_memblock *b = pa_xmalloc(sizeof(pa_memblock)+length); - b->type = PA_MEMBLOCK_APPENDED; - b->ref = 1; - b->length = length; - b->data = b+1; - b->free_cb = NULL; - b->read_only = 0; - stat_add(b, s); - return b; -} - -pa_memblock *pa_memblock_new_dynamic(void *d, size_t length, pa_memblock_stat*s) { - pa_memblock *b = pa_xmalloc(sizeof(pa_memblock)); - b->type = PA_MEMBLOCK_DYNAMIC; - b->ref = 1; - b->length = length; - b->data = d; - b->free_cb = NULL; - b->read_only = 0; - stat_add(b, s); - return b; -} - -pa_memblock *pa_memblock_new_fixed(void *d, size_t length, int read_only, pa_memblock_stat*s) { - pa_memblock *b = pa_xmalloc(sizeof(pa_memblock)); - b->type = PA_MEMBLOCK_FIXED; - b->ref = 1; - b->length = length; - b->data = d; - b->free_cb = NULL; - b->read_only = read_only; - stat_add(b, s); - return b; -} - -pa_memblock *pa_memblock_new_user(void *d, size_t length, void (*free_cb)(void *p), int read_only, pa_memblock_stat*s) { - pa_memblock *b; - assert(d && length && free_cb); - b = pa_xmalloc(sizeof(pa_memblock)); - b->type = PA_MEMBLOCK_USER; - b->ref = 1; - b->length = length; - b->data = d; - b->free_cb = free_cb; - b->read_only = read_only; - stat_add(b, s); - return b; -} - -pa_memblock* pa_memblock_ref(pa_memblock*b) { - assert(b && b->ref >= 1); - b->ref++; - return b; -} - -void pa_memblock_unref(pa_memblock*b) { - assert(b && b->ref >= 1); - - if ((--(b->ref)) == 0) { - stat_remove(b); - - if (b->type == PA_MEMBLOCK_USER) { - assert(b->free_cb); - b->free_cb(b->data); - } else if (b->type == PA_MEMBLOCK_DYNAMIC) - pa_xfree(b->data); - - pa_xfree(b); - } -} - -void pa_memblock_unref_fixed(pa_memblock *b) { - assert(b && b->ref >= 1 && b->type == PA_MEMBLOCK_FIXED); - - if (b->ref == 1) - pa_memblock_unref(b); - else { - b->data = pa_xmemdup(b->data, b->length); - b->type = PA_MEMBLOCK_DYNAMIC; - b->ref--; - } -} - -pa_memblock_stat* pa_memblock_stat_new(void) { - pa_memblock_stat *s; - - s = pa_xmalloc(sizeof(pa_memblock_stat)); - s->ref = 1; - s->total = s->total_size = s->allocated = s->allocated_size = 0; - - return s; -} - -void pa_memblock_stat_unref(pa_memblock_stat *s) { - assert(s && s->ref >= 1); - - if (!(--(s->ref))) { - assert(!s->total); - pa_xfree(s); - } -} - -pa_memblock_stat * pa_memblock_stat_ref(pa_memblock_stat *s) { - assert(s); - s->ref++; - return s; -} diff --git a/polyp/memblock.h b/polyp/memblock.h deleted file mode 100644 index c5751406..00000000 --- a/polyp/memblock.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef foomemblockhfoo -#define foomemblockhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -/* A pa_memblock is a reference counted memory block. Polypaudio - * passed references to pa_memblocks around instead of copying - * data. See pa_memchunk for a structure that describes parts of - * memory blocks. */ - -/* The type of memory this block points to */ -typedef enum pa_memblock_type { - PA_MEMBLOCK_FIXED, /* data is a pointer to fixed memory that needs not to be freed */ - PA_MEMBLOCK_APPENDED, /* The most common kind: the data is appended to the memory block */ - PA_MEMBLOCK_DYNAMIC, /* data is a pointer to some memory allocated with pa_xmalloc() */ - PA_MEMBLOCK_USER /* User supplied memory, to be freed with free_cb */ -} pa_memblock_type_t; - -/* A structure of keeping memory block statistics */ -/* Maintains statistics about memory blocks */ -typedef struct pa_memblock_stat { - int ref; - unsigned total; - unsigned total_size; - unsigned allocated; - unsigned allocated_size; -} pa_memblock_stat; - -typedef struct pa_memblock { - pa_memblock_type_t type; - unsigned ref; /* the reference counter */ - int read_only; /* boolean */ - size_t length; - void *data; - void (*free_cb)(void *p); /* If type == PA_MEMBLOCK_USER this points to a function for freeing this memory block */ - pa_memblock_stat *stat; -} pa_memblock; - -/* Allocate a new memory block of type PA_MEMBLOCK_APPENDED */ -pa_memblock *pa_memblock_new(size_t length, pa_memblock_stat*s); - -/* Allocate a new memory block of type PA_MEMBLOCK_DYNAMIC. The pointer data is to be maintained be the memory block */ -pa_memblock *pa_memblock_new_dynamic(void *data, size_t length, pa_memblock_stat*s); - -/* Allocate a new memory block of type PA_MEMBLOCK_FIXED */ -pa_memblock *pa_memblock_new_fixed(void *data, size_t length, int read_only, pa_memblock_stat*s); - -/* Allocate a new memory block of type PA_MEMBLOCK_USER */ -pa_memblock *pa_memblock_new_user(void *data, size_t length, void (*free_cb)(void *p), int read_only, pa_memblock_stat*s); - -void pa_memblock_unref(pa_memblock*b); -pa_memblock* pa_memblock_ref(pa_memblock*b); - -/* This special unref function has to be called by the owner of the -memory of a static memory block when he wants to release all -references to the memory. This causes the memory to be copied and -converted into a PA_MEMBLOCK_DYNAMIC type memory block */ -void pa_memblock_unref_fixed(pa_memblock*b); - - -pa_memblock_stat* pa_memblock_stat_new(void); -void pa_memblock_stat_unref(pa_memblock_stat *s); -pa_memblock_stat * pa_memblock_stat_ref(pa_memblock_stat *s); - -#endif diff --git a/polyp/memblockq.c b/polyp/memblockq.c deleted file mode 100644 index ba6b76ea..00000000 --- a/polyp/memblockq.c +++ /dev/null @@ -1,343 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "memblockq.h" -#include "xmalloc.h" -#include "log.h" -#include "mcalign.h" - -struct memblock_list { - struct memblock_list *next, *prev; - pa_memchunk chunk; -}; - -struct pa_memblockq { - struct memblock_list *blocks, *blocks_tail; - unsigned n_blocks; - size_t current_length, maxlength, tlength, base, prebuf, orig_prebuf, minreq; - pa_mcalign *mcalign; - pa_memblock_stat *memblock_stat; -}; - -pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t base, size_t prebuf, size_t minreq, pa_memblock_stat *s) { - pa_memblockq* bq; - assert(maxlength && base && maxlength); - - bq = pa_xmalloc(sizeof(pa_memblockq)); - bq->blocks = bq->blocks_tail = 0; - bq->n_blocks = 0; - - bq->current_length = 0; - - pa_log_debug(__FILE__": memblockq requested: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", maxlength, tlength, base, prebuf, minreq); - - bq->base = base; - - bq->maxlength = ((maxlength+base-1)/base)*base; - assert(bq->maxlength >= base); - - bq->tlength = ((tlength+base-1)/base)*base; - if (!bq->tlength || bq->tlength >= bq->maxlength) - bq->tlength = bq->maxlength; - - bq->minreq = (minreq/base)*base; - if (bq->minreq == 0) - bq->minreq = 1; - - bq->prebuf = (prebuf == (size_t) -1) ? bq->maxlength/2 : prebuf; - bq->prebuf = (bq->prebuf/base)*base; - if (bq->prebuf > bq->maxlength) - bq->prebuf = bq->maxlength; - - if (bq->prebuf > bq->tlength - bq->minreq) - bq->prebuf = bq->tlength - bq->minreq; - - bq->orig_prebuf = bq->prebuf; - - pa_log_debug(__FILE__": memblockq sanitized: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", bq->maxlength, bq->tlength, bq->base, bq->prebuf, bq->minreq); - - bq->mcalign = NULL; - - bq->memblock_stat = s; - - return bq; -} - -void pa_memblockq_free(pa_memblockq* bq) { - assert(bq); - - pa_memblockq_flush(bq); - - if (bq->mcalign) - pa_mcalign_free(bq->mcalign); - - pa_xfree(bq); -} - -void pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *chunk, size_t delta) { - struct memblock_list *q; - assert(bq && chunk && chunk->memblock && chunk->length && (chunk->length % bq->base) == 0); - - pa_memblockq_seek(bq, delta); - - if (bq->blocks_tail && bq->blocks_tail->chunk.memblock == chunk->memblock) { - /* Try to merge memory chunks */ - - if (bq->blocks_tail->chunk.index+bq->blocks_tail->chunk.length == chunk->index) { - bq->blocks_tail->chunk.length += chunk->length; - bq->current_length += chunk->length; - return; - } - } - - q = pa_xmalloc(sizeof(struct memblock_list)); - - q->chunk = *chunk; - pa_memblock_ref(q->chunk.memblock); - assert(q->chunk.index+q->chunk.length <= q->chunk.memblock->length); - q->next = NULL; - if ((q->prev = bq->blocks_tail)) - bq->blocks_tail->next = q; - else - bq->blocks = q; - - bq->blocks_tail = q; - - bq->n_blocks++; - bq->current_length += chunk->length; - - pa_memblockq_shorten(bq, bq->maxlength); -} - -int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { - assert(bq && chunk); - - if (!bq->blocks || bq->current_length < bq->prebuf) - return -1; - - bq->prebuf = 0; - - *chunk = bq->blocks->chunk; - pa_memblock_ref(chunk->memblock); - - return 0; -} - -void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length) { - assert(bq && chunk && length); - - if (!bq->blocks || memcmp(&bq->blocks->chunk, chunk, sizeof(pa_memchunk))) - return; - - assert(length <= bq->blocks->chunk.length); - pa_memblockq_skip(bq, length); -} - -static void remove_block(pa_memblockq *bq, struct memblock_list *q) { - assert(bq && q); - - if (q->prev) - q->prev->next = q->next; - else { - assert(bq->blocks == q); - bq->blocks = q->next; - } - - if (q->next) - q->next->prev = q->prev; - else { - assert(bq->blocks_tail == q); - bq->blocks_tail = q->prev; - } - - pa_memblock_unref(q->chunk.memblock); - pa_xfree(q); - - bq->n_blocks--; -} - -void pa_memblockq_skip(pa_memblockq *bq, size_t length) { - assert(bq && length && (length % bq->base) == 0); - - while (length > 0) { - size_t l = length; - assert(bq->blocks && bq->current_length >= length); - - if (l > bq->blocks->chunk.length) - l = bq->blocks->chunk.length; - - bq->blocks->chunk.index += l; - bq->blocks->chunk.length -= l; - bq->current_length -= l; - - if (!bq->blocks->chunk.length) - remove_block(bq, bq->blocks); - - length -= l; - } -} - -void pa_memblockq_shorten(pa_memblockq *bq, size_t length) { - size_t l; - assert(bq); - - if (bq->current_length <= length) - return; - - /*pa_log(__FILE__": Warning! pa_memblockq_shorten()\n");*/ - - l = bq->current_length - length; - l /= bq->base; - l *= bq->base; - - pa_memblockq_skip(bq, l); -} - - -void pa_memblockq_empty(pa_memblockq *bq) { - assert(bq); - pa_memblockq_shorten(bq, 0); -} - -int pa_memblockq_is_readable(pa_memblockq *bq) { - assert(bq); - - return bq->current_length && (bq->current_length >= bq->prebuf); -} - -int pa_memblockq_is_writable(pa_memblockq *bq, size_t length) { - assert(bq); - - return bq->current_length + length <= bq->tlength; -} - -uint32_t pa_memblockq_get_length(pa_memblockq *bq) { - assert(bq); - return bq->current_length; -} - -uint32_t pa_memblockq_missing(pa_memblockq *bq) { - size_t l; - assert(bq); - - if (bq->current_length >= bq->tlength) - return 0; - - l = bq->tlength - bq->current_length; - assert(l); - - return (l >= bq->minreq) ? l : 0; -} - -void pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk, size_t delta) { - pa_memchunk rchunk; - assert(bq && chunk && bq->base); - - if (bq->base == 1) { - pa_memblockq_push(bq, chunk, delta); - return; - } - - if (!bq->mcalign) { - bq->mcalign = pa_mcalign_new(bq->base, bq->memblock_stat); - assert(bq->mcalign); - } - - pa_mcalign_push(bq->mcalign, chunk); - - while (pa_mcalign_pop(bq->mcalign, &rchunk) >= 0) { - pa_memblockq_push(bq, &rchunk, delta); - pa_memblock_unref(rchunk.memblock); - delta = 0; - } -} - -uint32_t pa_memblockq_get_minreq(pa_memblockq *bq) { - assert(bq); - return bq->minreq; -} - -void pa_memblockq_prebuf_disable(pa_memblockq *bq) { - assert(bq); - bq->prebuf = 0; -} - -void pa_memblockq_prebuf_reenable(pa_memblockq *bq) { - assert(bq); - bq->prebuf = bq->orig_prebuf; -} - -void pa_memblockq_seek(pa_memblockq *bq, size_t length) { - assert(bq); - - if (!length) - return; - - while (length >= bq->base) { - size_t l = length; - if (!bq->current_length) - return; - - assert(bq->blocks_tail); - - if (l > bq->blocks_tail->chunk.length) - l = bq->blocks_tail->chunk.length; - - bq->blocks_tail->chunk.length -= l; - bq->current_length -= l; - - if (bq->blocks_tail->chunk.length == 0) - remove_block(bq, bq->blocks); - - length -= l; - } -} - -void pa_memblockq_flush(pa_memblockq *bq) { - struct memblock_list *l; - assert(bq); - - while ((l = bq->blocks)) { - bq->blocks = l->next; - pa_memblock_unref(l->chunk.memblock); - pa_xfree(l); - } - - bq->blocks_tail = NULL; - bq->n_blocks = 0; - bq->current_length = 0; -} - -uint32_t pa_memblockq_get_tlength(pa_memblockq *bq) { - assert(bq); - return bq->tlength; -} diff --git a/polyp/memblockq.h b/polyp/memblockq.h deleted file mode 100644 index 1695daba..00000000 --- a/polyp/memblockq.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef foomemblockqhfoo -#define foomemblockqhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "memblock.h" -#include "memchunk.h" - -/* A memblockq is a queue of pa_memchunks (yepp, the name is not - * perfect). It is similar to the ring buffers used by most other - * audio software. In contrast to a ring buffer this memblockq data - * type doesn't need to copy any data around, it just maintains - * references to reference counted memory blocks. */ - -typedef struct pa_memblockq pa_memblockq; - -/* Parameters: - - maxlength: maximum length of queue. If more data is pushed into the queue, data from the front is dropped - - length: the target length of the queue. - - base: a base value for all metrics. Only multiples of this value are popped from the queue - - prebuf: before passing the first byte out, make sure that enough bytes are in the queue - - minreq: pa_memblockq_missing() will only return values greater than this value -*/ -pa_memblockq* pa_memblockq_new(size_t maxlength, - size_t tlength, - size_t base, - size_t prebuf, - size_t minreq, - pa_memblock_stat *s); -void pa_memblockq_free(pa_memblockq*bq); - -/* Push a new memory chunk into the queue. Optionally specify a value for future cancellation. */ -void pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *chunk, size_t delta); - -/* Same as pa_memblockq_push(), however chunks are filtered through a mcalign object, and thus aligned to multiples of base */ -void pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk, size_t delta); - -/* Return a copy of the next memory chunk in the queue. It is not removed from the queue */ -int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk); - -/* Drop the specified bytes from the queue, only valid aufter pa_memblockq_peek() */ -void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length); - -/* Drop the specified bytes from the queue */ -void pa_memblockq_skip(pa_memblockq *bq, size_t length); - -/* Shorten the pa_memblockq to the specified length by dropping data at the end of the queue */ -void pa_memblockq_shorten(pa_memblockq *bq, size_t length); - -/* Empty the pa_memblockq */ -void pa_memblockq_empty(pa_memblockq *bq); - -/* Test if the pa_memblockq is currently readable, that is, more data than base */ -int pa_memblockq_is_readable(pa_memblockq *bq); - -/* Test if the pa_memblockq is currently writable for the specified amount of bytes */ -int pa_memblockq_is_writable(pa_memblockq *bq, size_t length); - -/* Return the length of the queue in bytes */ -uint32_t pa_memblockq_get_length(pa_memblockq *bq); - -/* Return how many bytes are missing in queue to the specified fill amount */ -uint32_t pa_memblockq_missing(pa_memblockq *bq); - -/* Returns the minimal request value */ -uint32_t pa_memblockq_get_minreq(pa_memblockq *bq); - -/* Force disabling of pre-buf even when the pre-buffer is not yet filled */ -void pa_memblockq_prebuf_disable(pa_memblockq *bq); - -/* Reenable pre-buf to the initial level */ -void pa_memblockq_prebuf_reenable(pa_memblockq *bq); - -/* Manipulate the write pointer */ -void pa_memblockq_seek(pa_memblockq *bq, size_t delta); - -/* Flush the queue */ -void pa_memblockq_flush(pa_memblockq *bq); - -/* Get Target length */ -uint32_t pa_memblockq_get_tlength(pa_memblockq *bq); - -#endif diff --git a/polyp/memchunk.c b/polyp/memchunk.c deleted file mode 100644 index bfd74f9e..00000000 --- a/polyp/memchunk.c +++ /dev/null @@ -1,58 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "memchunk.h" -#include "xmalloc.h" - -void pa_memchunk_make_writable(pa_memchunk *c, pa_memblock_stat *s, size_t min) { - pa_memblock *n; - size_t l; - assert(c && c->memblock && c->memblock->ref >= 1); - - if (c->memblock->ref == 1 && !c->memblock->read_only && c->memblock->length >= c->index+min) - return; - - l = c->length; - if (l < min) - l = min; - - n = pa_memblock_new(l, s); - memcpy(n->data, (uint8_t*) c->memblock->data + c->index, c->length); - pa_memblock_unref(c->memblock); - c->memblock = n; - c->index = 0; -} - -void pa_memchunk_reset(pa_memchunk *c) { - assert(c); - - c->memblock = NULL; - c->length = c->index = 0; -} diff --git a/polyp/memchunk.h b/polyp/memchunk.h deleted file mode 100644 index 4eefc8c1..00000000 --- a/polyp/memchunk.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef foomemchunkhfoo -#define foomemchunkhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "memblock.h" - -/* A memchunk describes a part of a memblock. In contrast to the memblock, a - * memchunk is not allocated dynamically or reference counted, instead - * it is usually stored on the stack and copied around */ - -typedef struct pa_memchunk { - pa_memblock *memblock; - size_t index, length; -} pa_memchunk; - -/* Make a memchunk writable, i.e. make sure that the caller may have - * exclusive access to the memblock and it is not read_only. If needed - * the memblock in the structure is replaced by a copy. */ -void pa_memchunk_make_writable(pa_memchunk *c, pa_memblock_stat *s, size_t min); - -/* Invalidate a memchunk. This does not free the cotaining memblock, - * but sets all members to zero. */ -void pa_memchunk_reset(pa_memchunk *c); - -#endif diff --git a/polyp/modargs.c b/polyp/modargs.c deleted file mode 100644 index 07062946..00000000 --- a/polyp/modargs.c +++ /dev/null @@ -1,260 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "hashmap.h" -#include "modargs.h" -#include "idxset.h" -#include "sample-util.h" -#include "namereg.h" -#include "sink.h" -#include "source.h" -#include "xmalloc.h" -#include "util.h" - -struct entry { - char *key, *value; -}; - -static int add_key_value(pa_hashmap *map, char *key, char *value, const char* const valid_keys[]) { - struct entry *e; - assert(map && key && value); - - if (valid_keys) { - const char*const* v; - for (v = valid_keys; *v; v++) - if (strcmp(*v, key) == 0) - break; - - if (!*v) { - pa_xfree(key); - pa_xfree(value); - return -1; - } - } - - e = pa_xmalloc(sizeof(struct entry)); - e->key = key; - e->value = value; - pa_hashmap_put(map, key, e); - return 0; -} - -pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) { - pa_hashmap *map = NULL; - - map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - assert(map); - - if (args) { - enum { WHITESPACE, KEY, VALUE_START, VALUE_SIMPLE, VALUE_DOUBLE_QUOTES, VALUE_TICKS } state; - const char *p, *key, *value; - size_t key_len = 0, value_len = 0; - - key = value = NULL; - state = WHITESPACE; - for (p = args; *p; p++) { - switch (state) { - case WHITESPACE: - if (*p == '=') - goto fail; - else if (!isspace(*p)) { - key = p; - state = KEY; - key_len = 1; - } - break; - case KEY: - if (*p == '=') - state = VALUE_START; - else - key_len++; - break; - case VALUE_START: - if (*p == '\'') { - state = VALUE_TICKS; - value = p+1; - value_len = 0; - } else if (*p == '"') { - state = VALUE_DOUBLE_QUOTES; - value = p+1; - value_len = 0; - } else if (isspace(*p)) { - if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0) - goto fail; - state = WHITESPACE; - } else { - state = VALUE_SIMPLE; - value = p; - value_len = 1; - } - break; - case VALUE_SIMPLE: - if (isspace(*p)) { - if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) - goto fail; - state = WHITESPACE; - } else - value_len++; - break; - case VALUE_DOUBLE_QUOTES: - if (*p == '"') { - if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) - goto fail; - state = WHITESPACE; - } else - value_len++; - break; - case VALUE_TICKS: - if (*p == '\'') { - if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) - goto fail; - state = WHITESPACE; - } else - value_len++; - break; - } - } - - if (state == VALUE_START) { - if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0) - goto fail; - } else if (state == VALUE_SIMPLE) { - if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(value), valid_keys) < 0) - goto fail; - } else if (state != WHITESPACE) - goto fail; - } - - return (pa_modargs*) map; - -fail: - - if (map) - pa_modargs_free((pa_modargs*) map); - - return NULL; -} - - -static void free_func(void *p, PA_GCC_UNUSED void*userdata) { - struct entry *e = p; - assert(e); - pa_xfree(e->key); - pa_xfree(e->value); - pa_xfree(e); -} - -void pa_modargs_free(pa_modargs*ma) { - pa_hashmap *map = (pa_hashmap*) ma; - pa_hashmap_free(map, free_func, NULL); -} - -const char *pa_modargs_get_value(pa_modargs *ma, const char *key, const char *def) { - pa_hashmap *map = (pa_hashmap*) ma; - struct entry*e; - - if (!(e = pa_hashmap_get(map, key))) - return def; - - return e->value; -} - -int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value) { - const char *v; - assert(ma && key && value); - - if (!(v = pa_modargs_get_value(ma, key, NULL))) - return 0; - - if (pa_atou(v, value) < 0) - return -1; - - return 0; -} - -int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value) { - const char *v; - assert(ma && key && value); - - if (!(v = pa_modargs_get_value(ma, key, NULL))) - return 0; - - if (pa_atoi(v, value) < 0) - return -1; - - return 0; -} - -int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value) { - const char *v; - int r; - assert(ma && key && value); - - if (!(v = pa_modargs_get_value(ma, key, NULL))) - return 0; - - if (!*v) - return -1; - - if ((r = pa_parse_boolean(v)) < 0) - return -1; - - *value = r; - return 0; -} - -int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) { - const char *format; - uint32_t channels; - pa_sample_spec ss; - assert(ma && rss); - -/* DEBUG_TRAP;*/ - - ss = *rss; - if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0) - return -1; - - channels = ss.channels; - if ((pa_modargs_get_value_u32(ma, "channels", &channels)) < 0) - return -1; - ss.channels = (uint8_t) channels; - - if ((format = pa_modargs_get_value(ma, "format", NULL))) - if ((ss.format = pa_parse_sample_format(format)) < 0) - return -1; - - if (!pa_sample_spec_valid(&ss)) - return -1; - - *rss = ss; - - return 0; -} diff --git a/polyp/modargs.h b/polyp/modargs.h deleted file mode 100644 index 56605379..00000000 --- a/polyp/modargs.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef foomodargshfoo -#define foomodargshfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include "sample.h" -#include "core.h" - -typedef struct pa_modargs pa_modargs; - -/* A generic parser for module arguments */ - -/* Parse the string args. The NULL-terminated array keys contains all valid arguments. */ -pa_modargs *pa_modargs_new(const char *args, const char* const keys[]); -void pa_modargs_free(pa_modargs*ma); - -/* Return the module argument for the specified name as a string. If - * the argument was not specified, return def instead.*/ -const char *pa_modargs_get_value(pa_modargs *ma, const char *key, const char *def); - -/* Return a module argument as unsigned 32bit value in *value */ -int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value); -int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value); -int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value); - -/* Return sample spec data from the three arguments "rate", "format" and "channels" */ -int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *ss); - -#endif diff --git a/polyp/modinfo.c b/polyp/modinfo.c deleted file mode 100644 index 53440612..00000000 --- a/polyp/modinfo.c +++ /dev/null @@ -1,84 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "xmalloc.h" -#include "util.h" -#include "modinfo.h" -#include "log.h" - -#define PA_SYMBOL_AUTHOR "pa__get_author" -#define PA_SYMBOL_DESCRIPTION "pa__get_description" -#define PA_SYMBOL_USAGE "pa__get_usage" -#define PA_SYMBOL_VERSION "pa__get_version" - -pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl) { - pa_modinfo *i; - const char* (*func)(void); - assert(dl); - - i = pa_xmalloc0(sizeof(pa_modinfo)); - - if ((func = (const char* (*)(void)) lt_dlsym(dl, PA_SYMBOL_AUTHOR))) - i->author = pa_xstrdup(func()); - - if ((func = (const char* (*)(void)) lt_dlsym(dl, PA_SYMBOL_DESCRIPTION))) - i->description = pa_xstrdup(func()); - - if ((func = (const char* (*)(void)) lt_dlsym(dl, PA_SYMBOL_USAGE))) - i->usage = pa_xstrdup(func()); - - if ((func = (const char* (*)(void)) lt_dlsym(dl, PA_SYMBOL_VERSION))) - i->version = pa_xstrdup(func()); - - return i; -} - -pa_modinfo *pa_modinfo_get_by_name(const char *name) { - lt_dlhandle dl; - pa_modinfo *i; - assert(name); - - if (!(dl = lt_dlopenext(name))) { - pa_log(__FILE__": Failed to open module \"%s\": %s\n", name, lt_dlerror()); - return NULL; - } - - i = pa_modinfo_get_by_handle(dl); - lt_dlclose(dl); - - return i; -} - -void pa_modinfo_free(pa_modinfo *i) { - assert(i); - pa_xfree(i->author); - pa_xfree(i->description); - pa_xfree(i->usage); - pa_xfree(i->version); - pa_xfree(i); -} diff --git a/polyp/modinfo.h b/polyp/modinfo.h deleted file mode 100644 index 53176147..00000000 --- a/polyp/modinfo.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef foomodinfohfoo -#define foomodinfohfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -/* Some functions for reading module meta data from Polypaudio modules */ - -typedef struct pa_modinfo { - char *author; - char *description; - char *usage; - char *version; -} pa_modinfo; - -/* Read meta data from an libtool handle */ -pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl); - -/* Read meta data from a module file */ -pa_modinfo *pa_modinfo_get_by_name(const char *name); - -/* Free meta data */ -void pa_modinfo_free(pa_modinfo *i); - -#endif diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c deleted file mode 100644 index 9aa220be..00000000 --- a/polyp/module-alsa-sink.c +++ /dev/null @@ -1,291 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#ifdef HAVE_SYS_POLL_H -#include -#else -#include "poll.h" -#endif - -#include - -#include "module.h" -#include "core.h" -#include "memchunk.h" -#include "sink.h" -#include "modargs.h" -#include "util.h" -#include "sample-util.h" -#include "alsa-util.h" -#include "xmalloc.h" -#include "log.h" -#include "module-alsa-sink-symdef.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("ALSA Sink") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= device= format= channels= rate= fragments= fragment_size=") - -struct userdata { - snd_pcm_t *pcm_handle; - pa_sink *sink; - pa_io_event **io_events; - unsigned n_io_events; - - size_t frame_size, fragment_size; - pa_memchunk memchunk, silence; - pa_module *module; -}; - -static const char* const valid_modargs[] = { - "device", - "sink_name", - "format", - "channels", - "rate", - "fragments", - "fragment_size", - NULL -}; - -#define DEFAULT_SINK_NAME "alsa_output" -#define DEFAULT_DEVICE "default" - -static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, - (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + - (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0)); -} - -static void xrun_recovery(struct userdata *u) { - assert(u); - - pa_log(__FILE__": *** ALSA-XRUN (playback) ***\n"); - - if (snd_pcm_prepare(u->pcm_handle) < 0) - pa_log(__FILE__": snd_pcm_prepare() failed\n"); -} - -static void do_write(struct userdata *u) { - assert(u); - - update_usage(u); - - for (;;) { - pa_memchunk *memchunk = NULL; - snd_pcm_sframes_t frames; - - if (u->memchunk.memblock) - memchunk = &u->memchunk; - else { - if (pa_sink_render(u->sink, u->fragment_size, &u->memchunk) < 0) - memchunk = &u->silence; - else - memchunk = &u->memchunk; - } - - assert(memchunk->memblock && memchunk->memblock->data && memchunk->length && memchunk->memblock->length && (memchunk->length % u->frame_size) == 0); - - if ((frames = snd_pcm_writei(u->pcm_handle, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length / u->frame_size)) < 0) { - if (frames == -EAGAIN) - return; - - if (frames == -EPIPE) { - xrun_recovery(u); - continue; - } - - pa_log(__FILE__": snd_pcm_writei() failed\n"); - return; - } - - if (memchunk == &u->memchunk) { - size_t l = frames * u->frame_size; - memchunk->index += l; - memchunk->length -= l; - - if (memchunk->length == 0) { - pa_memblock_unref(memchunk->memblock); - memchunk->memblock = NULL; - memchunk->index = memchunk->length = 0; - } - } - - break; - } -} - -static void io_callback(pa_mainloop_api*a, pa_io_event *e, PA_GCC_UNUSED int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { - struct userdata *u = userdata; - assert(u && a && e); - - if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) - xrun_recovery(u); - - do_write(u); -} - -static pa_usec_t sink_get_latency_cb(pa_sink *s) { - pa_usec_t r = 0; - struct userdata *u = s->userdata; - snd_pcm_sframes_t frames; - assert(s && u && u->sink); - - if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { - pa_log(__FILE__": failed to get delay\n"); - s->get_latency = NULL; - return 0; - } - - if (frames < 0) - frames = 0; - - r += pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec); - - if (u->memchunk.memblock) - r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec); - - return r; -} - -int pa__init(pa_core *c, pa_module*m) { - pa_modargs *ma = NULL; - int ret = -1; - struct userdata *u = NULL; - const char *dev; - pa_sample_spec ss; - uint32_t periods, fragsize; - snd_pcm_uframes_t period_size; - size_t frame_size; - int err; - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); - goto fail; - } - - ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": failed to parse sample specification\n"); - goto fail; - } - frame_size = pa_frame_size(&ss); - - periods = 8; - fragsize = 1024; - if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { - pa_log(__FILE__": failed to parse buffer metrics\n"); - goto fail; - } - period_size = fragsize; - - u = pa_xmalloc0(sizeof(struct userdata)); - m->userdata = u; - u->module = m; - - snd_config_update_free_global(); - if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { - pa_log(__FILE__": Error opening PCM device %s: %s\n", dev, snd_strerror(err)); - goto fail; - } - - if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) { - pa_log(__FILE__": Failed to set hardware parameters: %s\n", snd_strerror(err)); - goto fail; - } - - u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); - assert(u->sink); - - u->sink->get_latency = sink_get_latency_cb; - u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); - - if (pa_create_io_events(u->pcm_handle, c->mainloop, &u->io_events, &u->n_io_events, io_callback, u) < 0) { - pa_log(__FILE__": failed to obtain file descriptors\n"); - goto fail; - } - - u->frame_size = frame_size; - u->fragment_size = period_size; - - pa_log_info(__FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); - - u->silence.memblock = pa_memblock_new(u->silence.length = u->fragment_size, c->memblock_stat); - assert(u->silence.memblock); - pa_silence_memblock(u->silence.memblock, &ss); - u->silence.index = 0; - - u->memchunk.memblock = NULL; - u->memchunk.index = u->memchunk.length = 0; - - ret = 0; - -finish: - if (ma) - pa_modargs_free(ma); - - return ret; - -fail: - - if (u) - pa__done(c, m); - - goto finish; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u; - assert(c && m); - - if (!(u = m->userdata)) - return; - - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - } - - if (u->io_events) - pa_free_io_events(c->mainloop, u->io_events, u->n_io_events); - - if (u->pcm_handle) { - snd_pcm_drop(u->pcm_handle); - snd_pcm_close(u->pcm_handle); - } - - if (u->memchunk.memblock) - pa_memblock_unref(u->memchunk.memblock); - if (u->silence.memblock) - pa_memblock_unref(u->silence.memblock); - - pa_xfree(u); -} - diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c deleted file mode 100644 index efc84efe..00000000 --- a/polyp/module-alsa-source.c +++ /dev/null @@ -1,277 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#ifdef HAVE_SYS_POLL_H -#include -#else -#include "poll.h" -#endif - -#include - -#include "module.h" -#include "core.h" -#include "memchunk.h" -#include "sink.h" -#include "modargs.h" -#include "util.h" -#include "sample-util.h" -#include "alsa-util.h" -#include "xmalloc.h" -#include "log.h" -#include "module-alsa-source-symdef.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("ALSA Source") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("source_name= device= format= channels= rate= fragments= fragment_size=") - -struct userdata { - snd_pcm_t *pcm_handle; - pa_source *source; - pa_io_event **io_events; - unsigned n_io_events; - - size_t frame_size, fragment_size; - pa_memchunk memchunk; - pa_module *module; -}; - -static const char* const valid_modargs[] = { - "device", - "source_name", - "channels", - "rate", - "format", - "fragments", - "fragment_size", - NULL -}; - -#define DEFAULT_SOURCE_NAME "alsa_input" -#define DEFAULT_DEVICE "hw:0,0" - -static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, - (u->source ? pa_idxset_size(u->source->outputs) : 0)); -} - -static void xrun_recovery(struct userdata *u) { - assert(u); - - pa_log(__FILE__": *** ALSA-XRUN (capture) ***\n"); - - if (snd_pcm_prepare(u->pcm_handle) < 0) - pa_log(__FILE__": snd_pcm_prepare() failed\n"); -} - -static void do_read(struct userdata *u) { - assert(u); - - update_usage(u); - - for (;;) { - pa_memchunk post_memchunk; - snd_pcm_sframes_t frames; - size_t l; - - if (!u->memchunk.memblock) { - u->memchunk.memblock = pa_memblock_new(u->memchunk.length = u->fragment_size, u->source->core->memblock_stat); - u->memchunk.index = 0; - } - - assert(u->memchunk.memblock && u->memchunk.memblock->data && u->memchunk.length && u->memchunk.memblock->length && (u->memchunk.length % u->frame_size) == 0); - - if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { - if (frames == -EAGAIN) - return; - - if (frames == -EPIPE) { - xrun_recovery(u); - continue; - } - - pa_log(__FILE__": snd_pcm_readi() failed: %s\n", strerror(-frames)); - return; - } - - l = frames * u->frame_size; - - post_memchunk = u->memchunk; - post_memchunk.length = l; - - pa_source_post(u->source, &post_memchunk); - - u->memchunk.index += l; - u->memchunk.length -= l; - - if (u->memchunk.length == 0) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - u->memchunk.index = u->memchunk.length = 0; - } - - break; - } -} - -static void io_callback(pa_mainloop_api*a, pa_io_event *e, PA_GCC_UNUSED int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { - struct userdata *u = userdata; - assert(u && a && e); - - if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) - xrun_recovery(u); - - do_read(u); -} - -static pa_usec_t source_get_latency_cb(pa_source *s) { - struct userdata *u = s->userdata; - snd_pcm_sframes_t frames; - assert(s && u && u->source); - - if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { - pa_log(__FILE__": failed to get delay\n"); - s->get_latency = NULL; - return 0; - } - - return pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec); -} - -int pa__init(pa_core *c, pa_module*m) { - pa_modargs *ma = NULL; - int ret = -1; - struct userdata *u = NULL; - const char *dev; - pa_sample_spec ss; - unsigned periods, fragsize; - snd_pcm_uframes_t period_size; - size_t frame_size; - int err; - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); - goto fail; - } - - ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": failed to parse sample specification\n"); - goto fail; - } - frame_size = pa_frame_size(&ss); - - periods = 12; - fragsize = 1024; - if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { - pa_log(__FILE__": failed to parse buffer metrics\n"); - goto fail; - } - period_size = fragsize; - - u = pa_xmalloc0(sizeof(struct userdata)); - m->userdata = u; - u->module = m; - - snd_config_update_free_global(); - if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { - pa_log(__FILE__": Error opening PCM device %s: %s\n", dev, snd_strerror(err)); - goto fail; - } - - if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) { - pa_log(__FILE__": Failed to set hardware parameters: %s\n", snd_strerror(err)); - goto fail; - } - - u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); - assert(u->source); - - u->source->userdata = u; - u->source->get_latency = source_get_latency_cb; - pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); - - if (pa_create_io_events(u->pcm_handle, c->mainloop, &u->io_events, &u->n_io_events, io_callback, u) < 0) { - pa_log(__FILE__": failed to obtain file descriptors\n"); - goto fail; - } - - u->frame_size = frame_size; - u->fragment_size = period_size; - - pa_log(__FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); - - u->memchunk.memblock = NULL; - u->memchunk.index = u->memchunk.length = 0; - - snd_pcm_start(u->pcm_handle); - - ret = 0; - -finish: - if (ma) - pa_modargs_free(ma); - - return ret; - -fail: - - if (u) - pa__done(c, m); - - goto finish; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u; - assert(c && m); - - if (!(u = m->userdata)) - return; - - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - } - - if (u->io_events) - pa_free_io_events(c->mainloop, u->io_events, u->n_io_events); - - if (u->pcm_handle) { - snd_pcm_drop(u->pcm_handle); - snd_pcm_close(u->pcm_handle); - } - - if (u->memchunk.memblock) - pa_memblock_unref(u->memchunk.memblock); - - pa_xfree(u); -} - diff --git a/polyp/module-cli.c b/polyp/module-cli.c deleted file mode 100644 index db0e895c..00000000 --- a/polyp/module-cli.c +++ /dev/null @@ -1,87 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "module.h" -#include "iochannel.h" -#include "cli.h" -#include "sioman.h" -#include "log.h" -#include "module-cli-symdef.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Command line interface") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("No arguments") - -static void eof_cb(pa_cli*c, void *userdata) { - pa_module *m = userdata; - assert(c && m); - - pa_module_unload_request(m); -} - -int pa__init(pa_core *c, pa_module*m) { - pa_iochannel *io; - assert(c && m); - - if (c->running_as_daemon) { - pa_log_info(__FILE__": Running as daemon so won't load this module.\n"); - return 0; - } - - if (m->argument) { - pa_log(__FILE__": module doesn't accept arguments.\n"); - return -1; - } - - if (pa_stdio_acquire() < 0) { - pa_log(__FILE__": STDIN/STDUSE already in use.\n"); - return -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, m); - assert(m->userdata); - - pa_cli_set_eof_callback(m->userdata, eof_cb, m); - - return 0; -} - -void pa__done(pa_core *c, pa_module*m) { - assert(c && m); - - if (c->running_as_daemon == 0) { - pa_cli_free(m->userdata); - pa_stdio_release(); - } -} diff --git a/polyp/module-combine.c b/polyp/module-combine.c deleted file mode 100644 index 0c21c2f5..00000000 --- a/polyp/module-combine.c +++ /dev/null @@ -1,393 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "module.h" -#include "llist.h" -#include "sink.h" -#include "sink-input.h" -#include "memblockq.h" -#include "log.h" -#include "util.h" -#include "xmalloc.h" -#include "modargs.h" -#include "namereg.h" -#include "module-combine-symdef.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Combine multiple sinks to one") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= master= slaves= adjust_time= resample_method=") - -#define DEFAULT_SINK_NAME "combined" -#define MEMBLOCKQ_MAXLENGTH (1024*170) -#define RENDER_SIZE (1024*10) - -#define DEFAULT_ADJUST_TIME 20 - -static const char* const valid_modargs[] = { - "sink_name", - "master", - "slaves", - "adjust_time", - "resample_method", - NULL -}; - -struct output { - struct userdata *userdata; - pa_sink_input *sink_input; - size_t counter; - pa_memblockq *memblockq; - pa_usec_t total_latency; - PA_LLIST_FIELDS(struct output); -}; - -struct userdata { - pa_module *module; - pa_core *core; - pa_sink *sink; - unsigned n_outputs; - struct output *master; - pa_time_event *time_event; - uint32_t adjust_time; - - PA_LLIST_HEAD(struct output, outputs); -}; - -static void output_free(struct output *o); -static void clear_up(struct userdata *u); - -static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, - (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + - (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0)); -} - - -static void adjust_rates(struct userdata *u) { - struct output *o; - pa_usec_t max_sink_latency = 0, min_total_latency = (pa_usec_t) -1, target_latency; - uint32_t base_rate; - assert(u && u->sink); - - for (o = u->outputs; o; o = o->next) { - uint32_t sink_latency = o->sink_input->sink ? pa_sink_get_latency(o->sink_input->sink) : 0; - - o->total_latency = sink_latency + pa_sink_input_get_latency(o->sink_input); - - if (sink_latency > max_sink_latency) - max_sink_latency = sink_latency; - - if (o->total_latency < min_total_latency) - min_total_latency = o->total_latency; - } - - assert(min_total_latency != (pa_usec_t) -1); - - target_latency = max_sink_latency > min_total_latency ? max_sink_latency : min_total_latency; - - pa_log_info(__FILE__": [%s] target latency is %0.0f usec.\n", u->sink->name, (float) target_latency); - - base_rate = u->sink->sample_spec.rate; - - for (o = u->outputs; o; o = o->next) { - uint32_t r = base_rate; - - if (o->total_latency < target_latency) - r -= (uint32_t) (((((double) target_latency - o->total_latency))/u->adjust_time)*r/ 1000000); - else if (o->total_latency > target_latency) - r += (uint32_t) (((((double) o->total_latency - target_latency))/u->adjust_time)*r/ 1000000); - - if (r < (uint32_t) (base_rate*0.9) || r > (uint32_t) (base_rate*1.1)) - pa_log_warn(__FILE__": [%s] sample rates too different, not adjusting (%u vs. %u).\n", o->sink_input->name, base_rate, r); - else { - pa_log_info(__FILE__": [%s] new rate is %u Hz; ratio is %0.3f; latency is %0.0f usec.\n", o->sink_input->name, r, (double) r / base_rate, (float) o->total_latency); - pa_sink_input_set_rate(o->sink_input, r); - } - } -} - -static void request_memblock(struct userdata *u) { - pa_memchunk chunk; - struct output *o; - assert(u && u->sink); - - update_usage(u); - - if (pa_sink_render(u->sink, RENDER_SIZE, &chunk) < 0) - return; - - for (o = u->outputs; o; o = o->next) - pa_memblockq_push_align(o->memblockq, &chunk, 0); - - pa_memblock_unref(chunk.memblock); -} - -static void time_callback(pa_mainloop_api*a, pa_time_event* e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - struct userdata *u = userdata; - struct timeval n; - assert(u && a && u->time_event == e); - - adjust_rates(u); - - pa_gettimeofday(&n); - n.tv_sec += u->adjust_time; - u->sink->core->mainloop->time_restart(e, &n); -} - -static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { - struct output *o = i->userdata; - assert(i && o && o->sink_input && chunk); - - if (pa_memblockq_peek(o->memblockq, chunk) >= 0) - return 0; - - /* Try harder */ - request_memblock(o->userdata); - - return pa_memblockq_peek(o->memblockq, chunk); -} - -static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { - struct output *o = i->userdata; - assert(i && o && o->sink_input && chunk && length); - - pa_memblockq_drop(o->memblockq, chunk, length); - o->counter += length; -} - -static void sink_input_kill_cb(pa_sink_input *i) { - struct output *o = i->userdata; - assert(i && o && o->sink_input); - pa_module_unload_request(o->userdata->module); - clear_up(o->userdata); -} - -static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { - struct output *o = i->userdata; - assert(i && o && o->sink_input); - - return pa_bytes_to_usec(pa_memblockq_get_length(o->memblockq), &i->sample_spec); -} - -static pa_usec_t sink_get_latency_cb(pa_sink *s) { - struct userdata *u = s->userdata; - assert(s && u && u->sink && u->master); - - return pa_sink_input_get_latency(u->master->sink_input); -} - -static struct output *output_new(struct userdata *u, pa_sink *sink, int resample_method) { - struct output *o = NULL; - char t[256]; - assert(u && sink && u->sink); - - o = pa_xmalloc(sizeof(struct output)); - o->userdata = u; - - o->counter = 0; - o->memblockq = pa_memblockq_new(MEMBLOCKQ_MAXLENGTH, MEMBLOCKQ_MAXLENGTH, pa_frame_size(&u->sink->sample_spec), 0, 0, sink->core->memblock_stat); - - snprintf(t, sizeof(t), "%s: output #%u", u->sink->name, u->n_outputs+1); - if (!(o->sink_input = pa_sink_input_new(sink, __FILE__, t, &u->sink->sample_spec, &u->sink->channel_map, 1, resample_method))) - goto fail; - - o->sink_input->get_latency = sink_input_get_latency_cb; - o->sink_input->peek = sink_input_peek_cb; - o->sink_input->drop = sink_input_drop_cb; - o->sink_input->kill = sink_input_kill_cb; - o->sink_input->userdata = o; - o->sink_input->owner = u->module; - - PA_LLIST_PREPEND(struct output, u->outputs, o); - u->n_outputs++; - return o; - -fail: - - if (o) { - if (o->sink_input) { - pa_sink_input_disconnect(o->sink_input); - pa_sink_input_unref(o->sink_input); - } - - if (o->memblockq) - pa_memblockq_free(o->memblockq); - - pa_xfree(o); - } - - return NULL; -} - -static void output_free(struct output *o) { - assert(o); - PA_LLIST_REMOVE(struct output, o->userdata->outputs, o); - o->userdata->n_outputs--; - pa_memblockq_free(o->memblockq); - pa_sink_input_disconnect(o->sink_input); - pa_sink_input_unref(o->sink_input); - pa_xfree(o); -} - -static void clear_up(struct userdata *u) { - struct output *o; - assert(u); - - if (u->time_event) { - u->core->mainloop->time_free(u->time_event); - u->time_event = NULL; - } - - while ((o = u->outputs)) - output_free(o); - - u->master = NULL; - - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - u->sink = NULL; - } -} - -int pa__init(pa_core *c, pa_module*m) { - struct userdata *u; - pa_modargs *ma = NULL; - const char *master_name, *slaves, *rm; - pa_sink *master_sink; - char *n = NULL; - const char*split_state; - struct timeval tv; - int resample_method = -1; - assert(c && m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); - goto fail; - } - - if ((rm = pa_modargs_get_value(ma, "resample_method", NULL))) { - if ((resample_method = pa_parse_resample_method(rm)) < 0) { - pa_log(__FILE__": invalid resample method '%s'\n", rm); - goto fail; - } - } - - u = pa_xmalloc(sizeof(struct userdata)); - m->userdata = u; - u->sink = NULL; - u->n_outputs = 0; - u->master = NULL; - u->module = m; - u->core = c; - u->time_event = NULL; - u->adjust_time = DEFAULT_ADJUST_TIME; - PA_LLIST_HEAD_INIT(struct output, u->outputs); - - if (pa_modargs_get_value_u32(ma, "adjust_time", &u->adjust_time) < 0) { - pa_log(__FILE__": failed to parse adjust_time value\n"); - goto fail; - } - - if (!(master_name = pa_modargs_get_value(ma, "master", NULL)) || !(slaves = pa_modargs_get_value(ma, "slaves", NULL))) { - pa_log(__FILE__": no master or slave sinks specified\n"); - goto fail; - } - - if (!(master_sink = pa_namereg_get(c, master_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": invalid master sink '%s'\n", master_name); - goto fail; - } - - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &master_sink->sample_spec, &master_sink->channel_map))) { - pa_log(__FILE__": failed to create sink\n"); - goto fail; - } - - pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Combined sink"); - u->sink->get_latency = sink_get_latency_cb; - u->sink->userdata = u; - - if (!(u->master = output_new(u, master_sink, resample_method))) { - pa_log(__FILE__": failed to create master sink input on sink '%s'.\n", u->sink->name); - goto fail; - } - - split_state = NULL; - while ((n = pa_split(slaves, ",", &split_state))) { - pa_sink *slave_sink; - - if (!(slave_sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": invalid slave sink '%s'\n", n); - goto fail; - } - - pa_xfree(n); - - if (!output_new(u, slave_sink, resample_method)) { - pa_log(__FILE__": failed to create slave sink input on sink '%s'.\n", slave_sink->name); - goto fail; - } - } - - if (u->n_outputs <= 1) - pa_log_warn(__FILE__": WARNING: no slave sinks specified.\n"); - - if (u->adjust_time > 0) { - pa_gettimeofday(&tv); - tv.tv_sec += u->adjust_time; - u->time_event = c->mainloop->time_new(c->mainloop, &tv, time_callback, u); - } - - pa_modargs_free(ma); - return 0; - -fail: - pa_xfree(n); - - if (ma) - pa_modargs_free(ma); - - pa__done(c, m); - return -1; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u; - assert(c && m); - - if (!(u = m->userdata)) - return; - - clear_up(u); - pa_xfree(u); -} - - diff --git a/polyp/module-defs.h.m4 b/polyp/module-defs.h.m4 deleted file mode 100644 index 2eff25a7..00000000 --- a/polyp/module-defs.h.m4 +++ /dev/null @@ -1,29 +0,0 @@ -dnl $Id$ -changecom(`/*', `*/')dnl -define(`module_name', patsubst(patsubst(fname, `-symdef.h$'), `[^0-9a-zA-Z]', `_'))dnl -define(`c_symbol', patsubst(module_name, `[^0-9a-zA-Z]', `_'))dnl -define(`c_macro', patsubst(module_name, `[^0-9a-zA-Z]', `'))dnl -define(`incmacro', `foo'c_macro`symdeffoo')dnl -define(`gen_symbol', `#define $1 'module_name`_LTX_$1')dnl -#ifndef incmacro -#define incmacro - -#include "core.h" -#include "module.h" - -gen_symbol(pa__init) -gen_symbol(pa__done) -gen_symbol(pa__get_author) -gen_symbol(pa__get_description) -gen_symbol(pa__get_usage) -gen_symbol(pa__get_version) - -int pa__init(struct pa_core *c, struct pa_module*m); -void pa__done(struct pa_core *c, struct pa_module*m); - -const char* pa__get_author(void); -const char* pa__get_description(void); -const char* pa__get_usage(void); -const char* pa__get_version(void); - -#endif diff --git a/polyp/module-detect.c b/polyp/module-detect.c deleted file mode 100644 index ee75da36..00000000 --- a/polyp/module-detect.c +++ /dev/null @@ -1,226 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "module.h" -#include "log.h" -#include "module-detect-symdef.h" -#include "xmalloc.h" -#include "modargs.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("just-one=") - -static const char *endswith(const char *haystack, const char *needle) { - size_t l, m; - const char *p; - - if ((l = strlen(haystack)) < (m = strlen(needle))) - return NULL; - - if (strcmp(p = haystack + l - m, needle)) - return NULL; - - return p; -} - -#ifdef HAVE_ALSA -static int detect_alsa(pa_core *c, int just_one) { - FILE *f; - int n = 0, n_sink = 0, n_source = 0; - - if (!(f = fopen("/proc/asound/devices", "r"))) { - - if (errno != ENOENT) - pa_log_error(__FILE__": open(\"/proc/asound/devices\") failed: %s\n", strerror(errno)); - - return -1; - } - - while (!feof(f)) { - char line[64], args[64]; - unsigned device, subdevice; - int is_sink; - - if (!fgets(line, sizeof(line), f)) - break; - - line[strcspn(line, "\r\n")] = 0; - - if (endswith(line, "digital audio playback")) - is_sink = 1; - else if (endswith(line, "digital audio capture")) - is_sink = 0; - else - continue; - - if (just_one && is_sink && n_sink >= 1) - continue; - - if (just_one && !is_sink && n_source >= 1) - continue; - - if (sscanf(line, " %*i: [%u- %u]: ", &device, &subdevice) != 2) - continue; - - /* Only one sink per device */ - if (subdevice != 0) - continue; - - snprintf(args, sizeof(args), "device=hw:%u,0", device); - if (!pa_module_load(c, is_sink ? "module-alsa-sink" : "module-alsa-source", args)) - continue; - - n++; - - if (is_sink) - n_sink++; - else - n_source++; - } - - fclose(f); - - return n; -} -#endif - -#ifdef HAVE_OSS -static int detect_oss(pa_core *c, int just_one) { - FILE *f; - int n = 0, b = 0; - - if (!(f = fopen("/dev/sndstat", "r")) && - !(f = fopen("/proc/sndstat", "r")) && - !(f = fopen("/proc/asound/oss/sndstat", "r"))) { - - if (errno != ENOENT) - pa_log_error(__FILE__": failed to open OSS sndstat device: %s\n", strerror(errno)); - - return -1; - } - - while (!feof(f)) { - char line[64], args[64]; - unsigned device; - - if (!fgets(line, sizeof(line), f)) - break; - - line[strcspn(line, "\r\n")] = 0; - - if (!b) { - b = strcmp(line, "Audio devices:") == 0; - continue; - } - - if (line[0] == 0) - break; - - if (sscanf(line, "%u: ", &device) != 1) - continue; - - if (device == 0) - snprintf(args, sizeof(args), "device=/dev/dsp"); - else - snprintf(args, sizeof(args), "device=/dev/dsp%u", device); - - if (!pa_module_load(c, "module-oss", args)) - continue; - - n++; - - if (just_one) - break; - } - - fclose(f); - return n; -} -#endif - -int pa__init(pa_core *c, pa_module*m) { - int just_one = 0, n = 0; - pa_modargs *ma; - - static const char* const valid_modargs[] = { - "just-one", - NULL - }; - - assert(c); - assert(m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments\n"); - goto fail; - } - - if (pa_modargs_get_value_boolean(ma, "just-one", &just_one) < 0) { - pa_log(__FILE__": just_one= expects a boolean argument.\n"); - goto fail; - } - -#if HAVE_ALSA - if ((n = detect_alsa(c, just_one)) <= 0) -#endif -#if HAVE_OSS - if ((n = detect_oss(c, just_one)) <= 0) -#endif - { - pa_log_warn(__FILE__": failed to detect any sound hardware.\n"); - goto fail; - } - - pa_log_info(__FILE__": loaded %i modules.\n", n); - - /* We were successful and can unload ourselves now. */ - pa_module_unload_request(m); - - pa_modargs_free(ma); - - return 0; - -fail: - if (ma) - pa_modargs_free(ma); - - return -1; -} - - -void pa__done(pa_core *c, pa_module*m) { - /* NOP */ -} - diff --git a/polyp/module-esound-compat-spawnfd.c b/polyp/module-esound-compat-spawnfd.c deleted file mode 100644 index 5051e4d0..00000000 --- a/polyp/module-esound-compat-spawnfd.c +++ /dev/null @@ -1,80 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "module.h" -#include "util.h" -#include "modargs.h" -#include "log.h" -#include "module-esound-compat-spawnfd-symdef.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("ESOUND compatibility module: -spawnfd emulation") -PA_MODULE_USAGE("fd=") -PA_MODULE_VERSION(PACKAGE_VERSION) - -static const char* const valid_modargs[] = { - "fd", - NULL, -}; - -int pa__init(pa_core *c, pa_module*m) { - pa_modargs *ma = NULL; - int ret = -1, fd = -1; - char x = 1; - assert(c && m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs)) || - pa_modargs_get_value_s32(ma, "fd", &fd) < 0 || - fd < 0) { - pa_log(__FILE__": Failed to parse module arguments\n"); - goto finish; - } - - if (pa_loop_write(fd, &x, sizeof(x)) != sizeof(x)) - pa_log(__FILE__": WARNING: write(%u, 1, 1) failed: %s\n", fd, strerror(errno)); - - close(fd); - - pa_module_unload_request(m); - - ret = 0; - -finish: - if (ma) - pa_modargs_free(ma); - - return ret; -} - -void pa__done(pa_core *c, pa_module*m) { - assert(c && m); -} - - diff --git a/polyp/module-esound-compat-spawnpid.c b/polyp/module-esound-compat-spawnpid.c deleted file mode 100644 index aa8b0f82..00000000 --- a/polyp/module-esound-compat-spawnpid.c +++ /dev/null @@ -1,78 +0,0 @@ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "module.h" -#include "util.h" -#include "modargs.h" -#include "log.h" -#include "module-esound-compat-spawnpid-symdef.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("ESOUND compatibility module: -spawnpid emulation") -PA_MODULE_USAGE("pid=") -PA_MODULE_VERSION(PACKAGE_VERSION) - -static const char* const valid_modargs[] = { - "pid", - NULL, -}; - -int pa__init(pa_core *c, pa_module*m) { - pa_modargs *ma = NULL; - int ret = -1; - uint32_t pid = 0; - assert(c && m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs)) || - pa_modargs_get_value_u32(ma, "pid", &pid) < 0 || - !pid) { - pa_log(__FILE__": Failed to parse module arguments\n"); - goto finish; - } - - if (kill(pid, SIGUSR1) < 0) - pa_log(__FILE__": WARNING: kill(%u) failed: %s\n", pid, strerror(errno)); - - pa_module_unload_request(m); - - ret = 0; - -finish: - if (ma) - pa_modargs_free(ma); - - return ret; -} - -void pa__done(pa_core *c, pa_module*m) { - assert(c && m); -} - - diff --git a/polyp/module-esound-sink.c b/polyp/module-esound-sink.c deleted file mode 100644 index afd5feed..00000000 --- a/polyp/module-esound-sink.c +++ /dev/null @@ -1,426 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "iochannel.h" -#include "sink.h" -#include "module.h" -#include "util.h" -#include "modargs.h" -#include "xmalloc.h" -#include "log.h" -#include "module-esound-sink-symdef.h" -#include "socket-client.h" -#include "esound.h" -#include "authkey.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("ESOUND Sink") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= server=
    cookie= format= channels= rate=") - -#define DEFAULT_SINK_NAME "esound_output" - -struct userdata { - pa_core *core; - - pa_sink *sink; - pa_iochannel *io; - pa_socket_client *client; - - pa_defer_event *defer_event; - - pa_memchunk memchunk; - pa_module *module; - - void *write_data; - size_t write_length, write_index; - - void *read_data; - size_t read_length, read_index; - - enum { STATE_AUTH, STATE_LATENCY, STATE_RUNNING, STATE_DEAD } state; - - pa_usec_t latency; - - esd_format_t format; - int32_t rate; -}; - -static const char* const valid_modargs[] = { - "server", - "cookie", - "rate", - "format", - "channels", - "sink_name", - NULL -}; - -static void cancel(struct userdata *u) { - assert(u); - - u->state = STATE_DEAD; - - if (u->io) { - pa_iochannel_free(u->io); - u->io = NULL; - } - - if (u->defer_event) { - u->core->mainloop->defer_free(u->defer_event); - u->defer_event = NULL; - } - - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - u->sink = NULL; - } - - if (u->module) { - pa_module_unload_request(u->module); - u->module = NULL; - } -} - -static int do_write(struct userdata *u) { - ssize_t r; - assert(u); - - if (!pa_iochannel_is_writable(u->io)) - return 0; - - if (u->write_data) { - assert(u->write_index < u->write_length); - - if ((r = pa_iochannel_write(u->io, (uint8_t*) u->write_data + u->write_index, u->write_length - u->write_index)) <= 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); - return -1; - } - - u->write_index += r; - assert(u->write_index <= u->write_length); - - if (u->write_index == u->write_length) { - free(u->write_data); - u->write_data = NULL; - u->write_index = u->write_length = 0; - } - } else if (u->state == STATE_RUNNING) { - pa_module_set_used(u->module, pa_idxset_size(u->sink->inputs) + pa_idxset_size(u->sink->monitor_source->outputs)); - - if (!u->memchunk.length) - if (pa_sink_render(u->sink, 8192, &u->memchunk) < 0) - return 0; - - assert(u->memchunk.memblock && u->memchunk.length); - - if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); - return -1; - } - - u->memchunk.index += r; - u->memchunk.length -= r; - - if (u->memchunk.length <= 0) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - } - } - - return 0; -} - -static int handle_response(struct userdata *u) { - assert(u); - - switch (u->state) { - case STATE_AUTH: - assert(u->read_length == sizeof(int32_t)); - - /* Process auth data */ - if (!*(int32_t*) u->read_data) { - pa_log(__FILE__": Authentication failed: %s\n", strerror(errno)); - return -1; - } - - /* Request latency data */ - assert(!u->write_data); - *(int32_t*) (u->write_data = pa_xmalloc(u->write_length = sizeof(int32_t))) = ESD_PROTO_LATENCY; - - u->write_index = 0; - u->state = STATE_LATENCY; - - /* Space for next response */ - assert(u->read_length >= sizeof(int32_t)); - u->read_index = 0; - u->read_length = sizeof(int32_t); - - break; - - case STATE_LATENCY: { - int32_t *p; - assert(u->read_length == sizeof(int32_t)); - - /* Process latency info */ - u->latency = (pa_usec_t) ((double) (*(int32_t*) u->read_data) * 1000000 / 44100); - if (u->latency > 10000000) { - pa_log(__FILE__": WARNING! Invalid latency information received from server\n"); - u->latency = 0; - } - - /* Create stream */ - assert(!u->write_data); - p = u->write_data = pa_xmalloc0(u->write_length = sizeof(int32_t)*3+ESD_NAME_MAX); - *(p++) = ESD_PROTO_STREAM_PLAY; - *(p++) = u->format; - *(p++) = u->rate; - pa_strlcpy((char*) p, "Polypaudio Tunnel", ESD_NAME_MAX); - - u->write_index = 0; - u->state = STATE_RUNNING; - - /* Don't read any further */ - pa_xfree(u->read_data); - u->read_data = NULL; - u->read_index = u->read_length = 0; - - break; - } - - default: - abort(); - } - - return 0; -} - -static int do_read(struct userdata *u) { - assert(u); - - if (!pa_iochannel_is_readable(u->io)) - return 0; - - if (u->state == STATE_AUTH || u->state == STATE_LATENCY) { - ssize_t r; - - if (!u->read_data) - return 0; - - assert(u->read_index < u->read_length); - - if ((r = pa_iochannel_read(u->io, (uint8_t*) u->read_data + u->read_index, u->read_length - u->read_index)) <= 0) { - pa_log(__FILE__": read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); - cancel(u); - return -1; - } - - u->read_index += r; - assert(u->read_index <= u->read_length); - - if (u->read_index == u->read_length) - return handle_response(u); - } - - return 0; -} - -static void do_work(struct userdata *u) { - assert(u); - - u->core->mainloop->defer_enable(u->defer_event, 0); - - if (do_read(u) < 0 || do_write(u) < 0) - cancel(u); -} - -static void notify_cb(pa_sink*s) { - struct userdata *u = s->userdata; - assert(s && u); - - if (pa_iochannel_is_writable(u->io)) - u->core->mainloop->defer_enable(u->defer_event, 1); -} - -static pa_usec_t get_latency_cb(pa_sink *s) { - struct userdata *u = s->userdata; - assert(s && u); - - return - u->latency + - (u->memchunk.memblock ? pa_bytes_to_usec(u->memchunk.length, &s->sample_spec) : 0); -} - -static void defer_callback(PA_GCC_UNUSED pa_mainloop_api *m, PA_GCC_UNUSED pa_defer_event*e, void *userdata) { - struct userdata *u = userdata; - assert(u); - do_work(u); -} - -static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { - struct userdata *u = userdata; - assert(u); - do_work(u); -} - -static void on_connection(PA_GCC_UNUSED pa_socket_client *c, pa_iochannel*io, void *userdata) { - struct userdata *u = userdata; - - pa_socket_client_unref(u->client); - u->client = NULL; - - if (!io) { - pa_log(__FILE__": connection failed: %s\n", strerror(errno)); - cancel(u); - return; - } - - u->io = io; - pa_iochannel_set_callback(u->io, io_callback, u); -} - -int pa__init(pa_core *c, pa_module*m) { - struct userdata *u = NULL; - const char *p; - pa_sample_spec ss; - pa_modargs *ma = NULL; - assert(c && m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); - goto fail; - } - - ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": invalid sample format specification\n"); - goto fail; - } - - if ((ss.format != PA_SAMPLE_U8 && ss.format != PA_SAMPLE_S16NE) || - (ss.channels > 2)) { - pa_log(__FILE__": esound sample type support is limited to mono/stereo and U8 or S16NE sample data\n"); - goto fail; - } - - u = pa_xmalloc0(sizeof(struct userdata)); - u->core = c; - u->module = m; - m->userdata = u; - u->format = - (ss.format == PA_SAMPLE_U8 ? ESD_BITS8 : ESD_BITS16) | - (ss.channels == 2 ? ESD_STEREO : ESD_MONO); - u->rate = ss.rate; - u->sink = NULL; - u->client = NULL; - u->io = NULL; - u->read_data = u->write_data = NULL; - u->read_index = u->write_index = u->read_length = u->write_length = 0; - u->state = STATE_AUTH; - u->latency = 0; - - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { - pa_log(__FILE__": failed to create sink.\n"); - goto fail; - } - - if (!(u->client = pa_socket_client_new_string(u->core->mainloop, p = pa_modargs_get_value(ma, "server", ESD_UNIX_SOCKET_NAME), ESD_DEFAULT_PORT))) { - pa_log(__FILE__": failed to connect to server.\n"); - goto fail; - } - pa_socket_client_set_callback(u->client, on_connection, u); - - /* Prepare the initial request */ - u->write_data = pa_xmalloc(u->write_length = ESD_KEY_LEN + sizeof(int32_t)); - if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", ".esd_auth"), u->write_data, ESD_KEY_LEN) < 0) { - pa_log(__FILE__": failed to load cookie\n"); - goto fail; - } - *(int32_t*) ((uint8_t*) u->write_data + ESD_KEY_LEN) = ESD_ENDIAN_KEY; - - /* Reserve space for the response */ - u->read_data = pa_xmalloc(u->read_length = sizeof(int32_t)); - - u->sink->notify = notify_cb; - u->sink->get_latency = get_latency_cb; - u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Esound sink '%s'", p); - - u->memchunk.memblock = NULL; - u->memchunk.length = 0; - - u->defer_event = c->mainloop->defer_new(c->mainloop, defer_callback, u); - c->mainloop->defer_enable(u->defer_event, 0); - - - pa_modargs_free(ma); - - return 0; - -fail: - if (ma) - pa_modargs_free(ma); - - pa__done(c, m); - - return -1; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u; - assert(c && m); - - if (!(u = m->userdata)) - return; - - u->module = NULL; - cancel(u); - - if (u->memchunk.memblock) - pa_memblock_unref(u->memchunk.memblock); - - if (u->client) - pa_socket_client_unref(u->client); - - pa_xfree(u->read_data); - pa_xfree(u->write_data); - - pa_xfree(u); -} - - - diff --git a/polyp/module-lirc.c b/polyp/module-lirc.c deleted file mode 100644 index d2e248aa..00000000 --- a/polyp/module-lirc.c +++ /dev/null @@ -1,240 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "module.h" -#include "log.h" -#include "module-lirc-symdef.h" -#include "namereg.h" -#include "sink.h" -#include "xmalloc.h" -#include "modargs.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("LIRC volume control") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("config= sink= appname=") - -static const char* const valid_modargs[] = { - "config", - "sink", - "appname", - NULL, -}; - -struct userdata { - int lirc_fd; - pa_io_event *io; - struct lirc_config *config; - char *sink_name; - pa_module *module; - float mute_toggle_save; -}; - -static int lirc_in_use = 0; - -static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void*userdata) { - struct userdata *u = userdata; - char *name = NULL, *code = NULL; - assert(io); - assert(u); - - if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { - pa_log(__FILE__": lost connection to LIRC daemon.\n"); - goto fail; - } - - if (events & PA_IO_EVENT_INPUT) { - char *c; - - if (lirc_nextcode(&code) != 0 || !code) { - pa_log(__FILE__": lirc_nextcode() failed.\n"); - goto fail; - } - - c = pa_xstrdup(code); - c[strcspn(c, "\n\r")] = 0; - pa_log_debug(__FILE__": raw IR code '%s'\n", c); - pa_xfree(c); - - while (lirc_code2char(u->config, code, &name) == 0 && name) { - enum { INVALID, UP, DOWN, MUTE, RESET, MUTE_TOGGLE } volchange = INVALID; - - pa_log_info(__FILE__": translated IR code '%s'\n", name); - - if (strcasecmp(name, "volume-up") == 0) - volchange = UP; - else if (strcasecmp(name, "volume-down") == 0) - volchange = DOWN; - else if (strcasecmp(name, "mute") == 0) - volchange = MUTE; - else if (strcasecmp(name, "mute-toggle") == 0) - volchange = MUTE_TOGGLE; - else if (strcasecmp(name, "reset") == 0) - volchange = RESET; - - if (volchange == INVALID) - pa_log_warn(__FILE__": recieved unknown IR code '%s'\n", name); - else { - pa_sink *s; - - if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) - pa_log(__FILE__": failed to get sink '%s'\n", u->sink_name); - else { - pa_volume_t v = pa_cvolume_avg(pa_sink_get_volume(s, PA_MIXER_HARDWARE)); - pa_cvolume cv; -#define DELTA (PA_VOLUME_NORM/20) - - switch (volchange) { - case UP: - v += PA_VOLUME_NORM/20; - break; - - case DOWN: - if (v > DELTA) - v -= DELTA; - else - v = PA_VOLUME_MUTED; - - break; - - case MUTE: - v = PA_VOLUME_MUTED; - break; - - case RESET: - v = PA_VOLUME_NORM; - break; - - case MUTE_TOGGLE: { - - if (v > 0) { - u->mute_toggle_save = v; - v = PA_VOLUME_MUTED; - } else - v = u->mute_toggle_save; - } - default: - ; - } - - pa_cvolume_set(&cv, PA_CHANNELS_MAX, v); - pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); - } - } - } - } - - free(code); - - return; - -fail: - u->module->core->mainloop->io_free(u->io); - u->io = NULL; - - pa_module_unload_request(u->module); - - free(code); -} - -int pa__init(pa_core *c, pa_module*m) { - pa_modargs *ma = NULL; - struct userdata *u; - assert(c && m); - - if (lirc_in_use) { - pa_log(__FILE__": module-lirc may no be loaded twice.\n"); - return -1; - } - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments\n"); - goto fail; - } - - m->userdata = u = pa_xmalloc(sizeof(struct userdata)); - u->module = m; - u->io = NULL; - u->config = NULL; - u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); - u->lirc_fd = -1; - u->mute_toggle_save = 0; - - if ((u->lirc_fd = lirc_init((char*) pa_modargs_get_value(ma, "appname", "polypaudio"), 1)) < 0) { - pa_log(__FILE__": lirc_init() failed.\n"); - goto fail; - } - - if (lirc_readconfig((char*) pa_modargs_get_value(ma, "config", NULL), &u->config, NULL) < 0) { - pa_log(__FILE__": lirc_readconfig() failed.\n"); - goto fail; - } - - u->io = c->mainloop->io_new(c->mainloop, u->lirc_fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u); - - lirc_in_use = 1; - - pa_modargs_free(ma); - - return 0; - -fail: - - if (ma) - pa_modargs_free(ma); - - pa__done(c, m); - return -1; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u; - assert(c); - assert(m); - - if (!(u = m->userdata)) - return; - - if (u->io) - m->core->mainloop->io_free(u->io); - - if (u->config) - lirc_freeconfig(u->config); - - if (u->lirc_fd >= 0) - lirc_deinit(); - - pa_xfree(u->sink_name); - pa_xfree(u); - - lirc_in_use = 0; -} diff --git a/polyp/module-match.c b/polyp/module-match.c deleted file mode 100644 index e3e7b17d..00000000 --- a/polyp/module-match.c +++ /dev/null @@ -1,234 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "module.h" -#include "util.h" -#include "modargs.h" -#include "log.h" -#include "subscribe.h" -#include "xmalloc.h" -#include "sink-input.h" -#include "module-match-symdef.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Sink input matching module") -PA_MODULE_USAGE("table=") -PA_MODULE_VERSION(PACKAGE_VERSION) - -#define WHITESPACE "\n\r \t" - -#ifndef DEFAULT_CONFIG_DIR -#define DEFAULT_CONFIG_DIR "/etc/polypaudio" -#endif - -#define DEFAULT_MATCH_TABLE_FILE DEFAULT_CONFIG_DIR"/match.table" -#define DEFAULT_MATCH_TABLE_FILE_USER ".polypaudio/match.table" - -static const char* const valid_modargs[] = { - "table", - NULL, -}; - -struct rule { - regex_t regex; - pa_volume_t volume; - struct rule *next; -}; - -struct userdata { - struct rule *rules; - pa_subscription *subscription; -}; - -static int load_rules(struct userdata *u, const char *filename) { - FILE *f; - int n = 0; - int ret = -1; - struct rule *end = NULL; - char *fn = NULL; - - f = filename ? - fopen(fn = pa_xstrdup(filename), "r") : - pa_open_config_file(DEFAULT_MATCH_TABLE_FILE, DEFAULT_MATCH_TABLE_FILE_USER, NULL, &fn); - - if (!f) { - pa_log(__FILE__": failed to open file '%s': %s\n", fn, strerror(errno)); - goto finish; - } - - while (!feof(f)) { - char *d, *v; - pa_volume_t volume; - uint32_t k; - regex_t regex; - char ln[256]; - struct rule *rule; - - if (!fgets(ln, sizeof(ln), f)) - break; - - n++; - - pa_strip_nl(ln); - - if (ln[0] == '#' || !*ln ) - continue; - - d = ln+strcspn(ln, WHITESPACE); - v = d+strspn(d, WHITESPACE); - - - if (!*v) { - pa_log(__FILE__ ": [%s:%u] failed to parse line - too few words\n", filename, n); - goto finish; - } - - *d = 0; - if (pa_atou(v, &k) < 0) { - pa_log(__FILE__": [%s:%u] failed to parse volume\n", filename, n); - goto finish; - } - - volume = (pa_volume_t) k; - - - if (regcomp(®ex, ln, REG_EXTENDED|REG_NOSUB) != 0) { - pa_log(__FILE__": [%s:%u] invalid regular expression\n", filename, n); - goto finish; - } - - rule = pa_xmalloc(sizeof(struct rule)); - rule->regex = regex; - rule->volume = volume; - rule->next = NULL; - - if (end) - end->next = rule; - else - u->rules = rule; - end = rule; - - *d = 0; - } - - ret = 0; - -finish: - if (f) - fclose(f); - - if (fn) - pa_xfree(fn); - - return ret; -} - -static void callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { - struct userdata *u = userdata; - pa_sink_input *si; - struct rule *r; - assert(c && u); - - if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW)) - return; - - if (!(si = pa_idxset_get_by_index(c->sink_inputs, idx))) - return; - - if (!si->name) - return; - - for (r = u->rules; r; r = r->next) { - if (!regexec(&r->regex, si->name, 0, NULL, 0)) { - pa_cvolume cv; - pa_log_debug(__FILE__": changing volume of sink input '%s' to 0x%03x\n", si->name, r->volume); - pa_cvolume_set(&cv, r->volume, si->sample_spec.channels); - pa_sink_input_set_volume(si, &cv); - } - } -} - -int pa__init(pa_core *c, pa_module*m) { - pa_modargs *ma = NULL; - struct userdata *u; - assert(c && m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments\n"); - goto fail; - } - - u = pa_xmalloc(sizeof(struct userdata)); - u->rules = NULL; - u->subscription = NULL; - m->userdata = u; - - if (load_rules(u, pa_modargs_get_value(ma, "table", NULL)) < 0) - goto fail; - - u->subscription = pa_subscription_new(c, PA_SUBSCRIPTION_MASK_SINK_INPUT, callback, u); - - pa_modargs_free(ma); - return 0; - -fail: - pa__done(c, m); - - if (ma) - pa_modargs_free(ma); - return -1; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata* u; - struct rule *r, *n; - assert(c && m); - - if (!(u = m->userdata)) - return; - - if (u->subscription) - pa_subscription_free(u->subscription); - - for (r = u->rules; r; r = n) { - n = r->next; - - regfree(&r->regex); - pa_xfree(r); - } - - pa_xfree(u); -} - - diff --git a/polyp/module-mmkbd-evdev.c b/polyp/module-mmkbd-evdev.c deleted file mode 100644 index ec45ec4b..00000000 --- a/polyp/module-mmkbd-evdev.c +++ /dev/null @@ -1,249 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "module.h" -#include "log.h" -#include "module-mmkbd-evdev-symdef.h" -#include "namereg.h" -#include "sink.h" -#include "xmalloc.h" -#include "modargs.h" -#include "util.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Multimedia keyboard support via Linux evdev") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("device= sink=") - -#define DEFAULT_DEVICE "/dev/input/event0" - -/* - * This isn't defined in older kernel headers and there is no way of - * detecting it. - */ -struct _input_id { - __u16 bustype; - __u16 vendor; - __u16 product; - __u16 version; -}; - -static const char* const valid_modargs[] = { - "device", - "sink", - NULL, -}; - -struct userdata { - int fd; - pa_io_event *io; - char *sink_name; - pa_module *module; - float mute_toggle_save; -}; - -static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void*userdata) { - struct userdata *u = userdata; - assert(io); - assert(u); - - if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { - pa_log(__FILE__": lost connection to evdev device.\n"); - goto fail; - } - - if (events & PA_IO_EVENT_INPUT) { - struct input_event ev; - - if (pa_loop_read(u->fd, &ev, sizeof(ev)) <= 0) { - pa_log(__FILE__": failed to read from event device: %s\n", strerror(errno)); - goto fail; - } - - if (ev.type == EV_KEY && (ev.value == 1 || ev.value == 2)) { - enum { INVALID, UP, DOWN, MUTE_TOGGLE } volchange = INVALID; - - pa_log_debug(__FILE__": key code=%u, value=%u\n", ev.code, ev.value); - - switch (ev.code) { - case KEY_VOLUMEDOWN: volchange = DOWN; break; - case KEY_VOLUMEUP: volchange = UP; break; - case KEY_MUTE: volchange = MUTE_TOGGLE; break; - } - - if (volchange != INVALID) { - pa_sink *s; - - if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) - pa_log(__FILE__": failed to get sink '%s'\n", u->sink_name); - else { - pa_volume_t v = pa_cvolume_avg(pa_sink_get_volume(s, PA_MIXER_HARDWARE)); - pa_cvolume cv; -#define DELTA (PA_VOLUME_NORM/20) - - switch (volchange) { - case UP: - v += DELTA; - break; - - case DOWN: - if (v > DELTA) - v -= DELTA; - else - v = PA_VOLUME_MUTED; - - break; - - case MUTE_TOGGLE: { - - if (v > 0) { - u->mute_toggle_save = v; - v = PA_VOLUME_MUTED; - } else - v = u->mute_toggle_save; - } - default: - ; - } - - pa_cvolume_set(&cv, PA_CHANNELS_MAX, v); - pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); - } - } - } - } - - return; - -fail: - u->module->core->mainloop->io_free(u->io); - u->io = NULL; - - pa_module_unload_request(u->module); -} - -#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8))) - -int pa__init(pa_core *c, pa_module*m) { - pa_modargs *ma = NULL; - struct userdata *u; - int version; - struct _input_id input_id; - char name[256]; - uint8_t evtype_bitmask[EV_MAX/8 + 1]; - assert(c && m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments\n"); - goto fail; - } - - m->userdata = u = pa_xmalloc(sizeof(struct userdata)); - u->module = m; - u->io = NULL; - u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); - u->fd = -1; - u->mute_toggle_save = 0; - - if ((u->fd = open(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), O_RDONLY)) < 0) { - pa_log(__FILE__": failed to open evdev device: %s\n", strerror(errno)); - goto fail; - } - - if (ioctl(u->fd, EVIOCGVERSION, &version) < 0) { - pa_log(__FILE__": EVIOCGVERSION failed: %s\n", strerror(errno)); - goto fail; - } - - pa_log_info(__FILE__": evdev driver version %i.%i.%i\n", version >> 16, (version >> 8) & 0xff, version & 0xff); - - if(ioctl(u->fd, EVIOCGID, &input_id)) { - pa_log(__FILE__": EVIOCGID failed: %s\n", strerror(errno)); - goto fail; - } - - pa_log_info(__FILE__": evdev vendor 0x%04hx product 0x%04hx version 0x%04hx bustype %u\n", - input_id.vendor, input_id.product, input_id.version, input_id.bustype); - - if(ioctl(u->fd, EVIOCGNAME(sizeof(name)), name) < 0) { - pa_log(__FILE__": EVIOCGNAME failed: %s\n", strerror(errno)); - goto fail; - } - - pa_log_info(__FILE__": evdev device name: %s\n", name); - - memset(evtype_bitmask, 0, sizeof(evtype_bitmask)); - if (ioctl(u->fd, EVIOCGBIT(0, EV_MAX), evtype_bitmask) < 0) { - pa_log(__FILE__": EVIOCGBIT failed: %s\n", strerror(errno)); - goto fail; - } - - if (!test_bit(EV_KEY, evtype_bitmask)) { - pa_log(__FILE__": device has no keys.\n"); - goto fail; - } - - u->io = c->mainloop->io_new(c->mainloop, u->fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u); - - pa_modargs_free(ma); - - return 0; - -fail: - - if (ma) - pa_modargs_free(ma); - - pa__done(c, m); - return -1; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u; - assert(c); - assert(m); - - if (!(u = m->userdata)) - return; - - if (u->io) - m->core->mainloop->io_free(u->io); - - if (u->fd >= 0) - close(u->fd); - - pa_xfree(u->sink_name); - pa_xfree(u); -} diff --git a/polyp/module-native-protocol-fd.c b/polyp/module-native-protocol-fd.c deleted file mode 100644 index 7f09ff91..00000000 --- a/polyp/module-native-protocol-fd.c +++ /dev/null @@ -1,84 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "module.h" -#include "iochannel.h" -#include "modargs.h" -#include "protocol-native.h" -#include "log.h" -#include "module-native-protocol-fd-symdef.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Native protocol autospawn helper") -PA_MODULE_VERSION(PACKAGE_VERSION) - -static const char* const valid_modargs[] = { - "fd", - "public", - "cookie", - NULL, -}; - -int pa__init(pa_core *c, pa_module*m) { - pa_iochannel *io; - pa_modargs *ma; - int fd, r = -1; - assert(c && m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments.\n"); - goto finish; - } - - if (pa_modargs_get_value_s32(ma, "fd", &fd) < 0) { - pa_log(__FILE__": invalid file descriptor.\n"); - goto finish; - } - - io = pa_iochannel_new(c->mainloop, fd, fd); - - if (!(m->userdata = pa_protocol_native_new_iochannel(c, io, m, ma))) { - pa_iochannel_free(io); - goto finish; - } - - r = 0; - -finish: - if (ma) - pa_modargs_free(ma); - - return r; -} - -void pa__done(pa_core *c, pa_module*m) { - assert(c && m); - - pa_protocol_native_free(m->userdata); -} diff --git a/polyp/module-null-sink.c b/polyp/module-null-sink.c deleted file mode 100644 index 93abca78..00000000 --- a/polyp/module-null-sink.c +++ /dev/null @@ -1,149 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "iochannel.h" -#include "sink.h" -#include "module.h" -#include "util.h" -#include "modargs.h" -#include "xmalloc.h" -#include "log.h" -#include "module-null-sink-symdef.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Clocked NULL sink") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("format= channels= rate= sink_name=") - -#define DEFAULT_SINK_NAME "null" - -struct userdata { - pa_core *core; - pa_module *module; - pa_sink *sink; - pa_time_event *time_event; - size_t block_size; -}; - -static const char* const valid_modargs[] = { - "rate", - "format", - "channels", - "sink_name", - NULL -}; - -static void time_callback(pa_mainloop_api *m, pa_time_event*e, const struct timeval *tv, void *userdata) { - struct userdata *u = userdata; - pa_memchunk chunk; - struct timeval ntv = *tv; - size_t l; - - assert(u); - - if (pa_sink_render(u->sink, u->block_size, &chunk) >= 0) { - l = chunk.length; - pa_memblock_unref(chunk.memblock); - } else - l = u->block_size; - - pa_timeval_add(&ntv, pa_bytes_to_usec(l, &u->sink->sample_spec)); - m->time_restart(e, &ntv); -} - -int pa__init(pa_core *c, pa_module*m) { - struct userdata *u = NULL; - pa_sample_spec ss; - pa_modargs *ma = NULL; - struct timeval tv; - assert(c && m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments.\n"); - goto fail; - } - - ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": invalid sample format specification.\n"); - goto fail; - } - - u = pa_xmalloc0(sizeof(struct userdata)); - u->core = c; - u->module = m; - m->userdata = u; - - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { - pa_log(__FILE__": failed to create sink.\n"); - goto fail; - } - - u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("NULL sink"); - - pa_gettimeofday(&tv); - u->time_event = c->mainloop->time_new(c->mainloop, &tv, time_callback, u); - - u->block_size = pa_bytes_per_second(&ss) / 10; - - pa_modargs_free(ma); - - return 0; - -fail: - if (ma) - pa_modargs_free(ma); - - pa__done(c, m); - - return -1; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u; - assert(c && m); - - if (!(u = m->userdata)) - return; - - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - - u->core->mainloop->time_free(u->time_event); - - pa_xfree(u); -} diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c deleted file mode 100644 index f976cf81..00000000 --- a/polyp/module-oss-mmap.c +++ /dev/null @@ -1,425 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "iochannel.h" -#include "sink.h" -#include "source.h" -#include "module.h" -#include "oss-util.h" -#include "sample-util.h" -#include "util.h" -#include "modargs.h" -#include "xmalloc.h" -#include "log.h" -#include "module-oss-mmap-symdef.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("OSS Sink/Source (mmap)") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= fragments= fragment_size=") - -struct userdata { - pa_sink *sink; - pa_source *source; - pa_core *core; - pa_sample_spec sample_spec; - - size_t in_fragment_size, out_fragment_size, in_fragments, out_fragments, out_fill; - - int fd; - - void *in_mmap, *out_mmap; - size_t in_mmap_length, out_mmap_length; - - pa_io_event *io_event; - - pa_memblock **in_memblocks, **out_memblocks; - unsigned out_current, in_current; - pa_module *module; -}; - -static const char* const valid_modargs[] = { - "sink_name", - "source_name", - "device", - "record", - "playback", - "fragments", - "fragment_size", - "format", - "rate", - "channels", - NULL -}; - -#define DEFAULT_SINK_NAME "oss_output" -#define DEFAULT_SOURCE_NAME "oss_input" -#define DEFAULT_DEVICE "/dev/dsp" - -static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, - (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + - (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0) + - (u->source ? pa_idxset_size(u->source->outputs) : 0)); -} - -static void out_fill_memblocks(struct userdata *u, unsigned n) { - assert(u && u->out_memblocks); - - while (n > 0) { - pa_memchunk chunk; - - if (u->out_memblocks[u->out_current]) - pa_memblock_unref_fixed(u->out_memblocks[u->out_current]); - - chunk.memblock = u->out_memblocks[u->out_current] = pa_memblock_new_fixed((uint8_t*)u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size, 1, u->core->memblock_stat); - assert(chunk.memblock); - chunk.length = chunk.memblock->length; - chunk.index = 0; - - pa_sink_render_into_full(u->sink, &chunk); - - u->out_current++; - while (u->out_current >= u->out_fragments) - u->out_current -= u->out_fragments; - - n--; - } -} - -static void do_write(struct userdata *u) { - struct count_info info; - assert(u && u->sink); - - update_usage(u); - - if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETOPTR: %s\n", strerror(errno)); - return; - } - - u->out_fill = (u->out_fragment_size * u->out_fragments) - (info.ptr % u->out_fragment_size); - - if (!info.blocks) - return; - - out_fill_memblocks(u, info.blocks); -} - -static void in_post_memblocks(struct userdata *u, unsigned n) { - assert(u && u->in_memblocks); - - while (n > 0) { - pa_memchunk chunk; - - if (!u->in_memblocks[u->in_current]) { - chunk.memblock = u->in_memblocks[u->in_current] = pa_memblock_new_fixed((uint8_t*) u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size, 1, u->core->memblock_stat); - chunk.length = chunk.memblock->length; - chunk.index = 0; - - pa_source_post(u->source, &chunk); - } - - u->in_current++; - while (u->in_current >= u->in_fragments) - u->in_current -= u->in_fragments; - - n--; - } -} - -static void in_clear_memblocks(struct userdata*u, unsigned n) { - unsigned i = u->in_current; - assert(u && u->in_memblocks); - - if (n > u->in_fragments) - n = u->in_fragments; - - while (n > 0) { - if (u->in_memblocks[i]) { - pa_memblock_unref_fixed(u->in_memblocks[i]); - u->in_memblocks[i] = NULL; - } - - i++; - while (i >= u->in_fragments) - i -= u->in_fragments; - - n--; - } -} - -static void do_read(struct userdata *u) { - struct count_info info; - assert(u && u->source); - - update_usage(u); - - if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETIPTR: %s\n", strerror(errno)); - return; - } - - if (!info.blocks) - return; - - in_post_memblocks(u, info.blocks); - in_clear_memblocks(u, u->in_fragments/2); -} - -static void io_callback(pa_mainloop_api *m, pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t f, void *userdata) { - struct userdata *u = userdata; - assert (u && u->core->mainloop == m && u->io_event == e); - - if (f & PA_IO_EVENT_INPUT) - do_read(u); - if (f & PA_IO_EVENT_OUTPUT) - do_write(u); -} - -static pa_usec_t sink_get_latency_cb(pa_sink *s) { - struct userdata *u = s->userdata; - assert(s && u); - - do_write(u); - return pa_bytes_to_usec(u->out_fill, &s->sample_spec); -} - -int pa__init(pa_core *c, pa_module*m) { - struct audio_buf_info info; - struct userdata *u = NULL; - const char *p; - int nfrags, frag_size; - int mode, caps; - int enable_bits = 0, zero = 0; - int playback = 1, record = 1; - pa_modargs *ma = NULL; - assert(c && m); - - m->userdata = u = pa_xmalloc0(sizeof(struct userdata)); - u->module = m; - u->fd = -1; - u->core = c; - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments.\n"); - goto fail; - } - - if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { - pa_log(__FILE__": record= and playback= expect numeric arguments.\n"); - goto fail; - } - - if (!playback && !record) { - pa_log(__FILE__": neither playback nor record enabled for device.\n"); - goto fail; - } - - mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); - - nfrags = 12; - frag_size = 1024; - if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { - pa_log(__FILE__": failed to parse fragments arguments\n"); - goto fail; - } - - u->sample_spec = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &u->sample_spec) < 0) { - pa_log(__FILE__": failed to parse sample specification\n"); - goto fail; - } - - if ((u->fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0) - goto fail; - - if (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_REALTIME) || !(caps & DSP_CAP_TRIGGER)) { - pa_log(__FILE__": OSS device not mmap capable.\n"); - goto fail; - } - - pa_log(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); - - if (nfrags >= 2 && frag_size >= 1) - if (pa_oss_set_fragments(u->fd, nfrags, frag_size) < 0) - goto fail; - - if (pa_oss_auto_format(u->fd, &u->sample_spec) < 0) - goto fail; - - if (mode != O_WRONLY) { - if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETISPACE: %s\n", strerror(errno)); - goto fail; - } - - pa_log_info(__FILE__": input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); - u->in_mmap_length = (u->in_fragment_size = info.fragsize) * (u->in_fragments = info.fragstotal); - - if ((u->in_mmap = mmap(NULL, u->in_mmap_length, PROT_READ, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { - if (mode == O_RDWR) { - pa_log(__FILE__": mmap failed for input. Changing to O_WRONLY mode.\n"); - mode = O_WRONLY; - } else { - pa_log(__FILE__": mmap(): %s\n", strerror(errno)); - goto fail; - } - } else { - - u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec, NULL); - assert(u->source); - u->source->userdata = u; - pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'", p); - - u->in_memblocks = pa_xmalloc0(sizeof(pa_memblock *)*u->in_fragments); - - enable_bits |= PCM_ENABLE_INPUT; - } - } - - if (mode != O_RDONLY) { - if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETOSPACE: %s\n", strerror(errno)); - goto fail; - } - - pa_log_info(__FILE__": output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); - u->out_mmap_length = (u->out_fragment_size = info.fragsize) * (u->out_fragments = info.fragstotal); - - if ((u->out_mmap = mmap(NULL, u->out_mmap_length, PROT_WRITE, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { - if (mode == O_RDWR) { - pa_log(__FILE__": mmap filed for output. Changing to O_RDONLY mode.\n"); - mode = O_RDONLY; - } else { - pa_log(__FILE__": mmap(): %s\n", strerror(errno)); - goto fail; - } - } else { - pa_silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec); - - u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec, NULL); - assert(u->sink); - u->sink->get_latency = sink_get_latency_cb; - u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'", p); - - u->out_memblocks = pa_xmalloc0(sizeof(struct memblock *)*u->out_fragments); - - enable_bits |= PCM_ENABLE_OUTPUT; - } - } - - zero = 0; - if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero) < 0) { - pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s\n", strerror(errno)); - goto fail; - } - - if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0) { - pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s\n", strerror(errno)); - goto fail; - } - - assert(u->source || u->sink); - - u->io_event = c->mainloop->io_new(c->mainloop, u->fd, (u->source ? PA_IO_EVENT_INPUT : 0) | (u->sink ? PA_IO_EVENT_OUTPUT : 0), io_callback, u); - assert(u->io_event); - - pa_modargs_free(ma); - - return 0; - -fail: - pa__done(c, m); - - if (ma) - pa_modargs_free(ma); - - return -1; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u; - assert(c && m); - - if (!(u = m->userdata)) - return; - - if (u->out_memblocks) { - unsigned i; - for (i = 0; i < u->out_fragments; i++) - if (u->out_memblocks[i]) - pa_memblock_unref_fixed(u->out_memblocks[i]); - pa_xfree(u->out_memblocks); - } - - if (u->in_memblocks) { - unsigned i; - for (i = 0; i < u->in_fragments; i++) - if (u->in_memblocks[i]) - pa_memblock_unref_fixed(u->in_memblocks[i]); - pa_xfree(u->in_memblocks); - } - - if (u->in_mmap && u->in_mmap != MAP_FAILED) - munmap(u->in_mmap, u->in_mmap_length); - - if (u->out_mmap && u->out_mmap != MAP_FAILED) - munmap(u->out_mmap, u->out_mmap_length); - - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - } - - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - } - - if (u->io_event) - u->core->mainloop->io_free(u->io_event); - - if (u->fd >= 0) - close(u->fd); - - pa_xfree(u); -} diff --git a/polyp/module-oss.c b/polyp/module-oss.c deleted file mode 100644 index b5c7ae8c..00000000 --- a/polyp/module-oss.c +++ /dev/null @@ -1,467 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "iochannel.h" -#include "sink.h" -#include "source.h" -#include "module.h" -#include "oss-util.h" -#include "sample-util.h" -#include "util.h" -#include "modargs.h" -#include "xmalloc.h" -#include "log.h" -#include "module-oss-symdef.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("OSS Sink/Source") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= fragments= fragment_size=") - -struct userdata { - pa_sink *sink; - pa_source *source; - pa_iochannel *io; - pa_core *core; - - pa_memchunk memchunk, silence; - - uint32_t in_fragment_size, out_fragment_size, sample_size; - int use_getospace, use_getispace; - - int fd; - pa_module *module; -}; - -static const char* const valid_modargs[] = { - "sink_name", - "source_name", - "device", - "record", - "playback", - "fragments", - "fragment_size", - "format", - "rate", - "channels", - NULL -}; - -#define DEFAULT_SINK_NAME "oss_output" -#define DEFAULT_SOURCE_NAME "oss_input" -#define DEFAULT_DEVICE "/dev/dsp" - -static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, - (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + - (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0) + - (u->source ? pa_idxset_size(u->source->outputs) : 0)); -} - -static void do_write(struct userdata *u) { - pa_memchunk *memchunk; - ssize_t r; - size_t l; - int loop = 0; - - assert(u); - - if (!u->sink || !pa_iochannel_is_writable(u->io)) - return; - - update_usage(u); - - l = u->out_fragment_size; - - if (u->use_getospace) { - audio_buf_info info; - - if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) - u->use_getospace = 0; - else { - if (info.bytes/l > 0) { - l = (info.bytes/l)*l; - loop = 1; - } - } - } - - do { - memchunk = &u->memchunk; - - if (!memchunk->length) - if (pa_sink_render(u->sink, l, memchunk) < 0) - memchunk = &u->silence; - - assert(memchunk->memblock); - assert(memchunk->memblock->data); - assert(memchunk->length); - - if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); - break; - } - - if (memchunk == &u->silence) - assert(r % u->sample_size == 0); - else { - u->memchunk.index += r; - u->memchunk.length -= r; - - if (u->memchunk.length <= 0) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - } - } - - l = l > (size_t) r ? l - r : 0; - } while (loop && l > 0); -} - -static void do_read(struct userdata *u) { - pa_memchunk memchunk; - ssize_t r; - size_t l; - int loop = 0; - assert(u); - - if (!u->source || !pa_iochannel_is_readable(u->io) || !pa_idxset_size(u->source->outputs)) - return; - - update_usage(u); - - l = u->in_fragment_size; - - if (u->use_getispace) { - audio_buf_info info; - - if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) - u->use_getispace = 0; - else { - if (info.bytes/l > 0) { - l = (info.bytes/l)*l; - loop = 1; - } - } - } - - do { - memchunk.memblock = pa_memblock_new(l, u->core->memblock_stat); - assert(memchunk.memblock); - if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { - pa_memblock_unref(memchunk.memblock); - if (errno != EAGAIN) - pa_log(__FILE__": read() failed: %s\n", strerror(errno)); - break; - } - - assert(r <= (ssize_t) memchunk.memblock->length); - memchunk.length = memchunk.memblock->length = r; - memchunk.index = 0; - - pa_source_post(u->source, &memchunk); - pa_memblock_unref(memchunk.memblock); - - l = l > (size_t) r ? l - r : 0; - } while (loop && l > 0); -} - -static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { - struct userdata *u = userdata; - assert(u); - do_write(u); - do_read(u); -} - -static void source_notify_cb(pa_source *s) { - struct userdata *u = s->userdata; - assert(u); - do_read(u); -} - -static pa_usec_t sink_get_latency_cb(pa_sink *s) { - pa_usec_t r = 0; - int arg; - struct userdata *u = s->userdata; - assert(s && u && u->sink); - - if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { - pa_log_info(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY: %s\n", strerror(errno)); - s->get_latency = NULL; - return 0; - } - - r += pa_bytes_to_usec(arg, &s->sample_spec); - - if (u->memchunk.memblock) - r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec); - - return r; -} - -static pa_usec_t source_get_latency_cb(pa_source *s) { - struct userdata *u = s->userdata; - audio_buf_info info; - assert(s && u && u->source); - - if (!u->use_getispace) - return 0; - - if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { - u->use_getispace = 0; - return 0; - } - - if (info.bytes <= 0) - return 0; - - return pa_bytes_to_usec(info.bytes, &s->sample_spec); -} - -static int sink_get_hw_volume(pa_sink *s) { - struct userdata *u = s->userdata; - char cv[PA_CVOLUME_SNPRINT_MAX]; - unsigned vol; - - if (ioctl(u->fd, SOUND_MIXER_READ_PCM, &vol) < 0) { - pa_log_info(__FILE__": device doesn't support reading mixer settings: %s\n", strerror(errno)); - s->get_hw_volume = NULL; - return -1; - } - - s->hw_volume.values[0] = ((vol & 0xFF) * PA_VOLUME_NORM) / 100; - - if ((s->hw_volume.channels = s->sample_spec.channels) >= 2) - s->hw_volume.values[1] = (((vol >> 8) & 0xFF) * PA_VOLUME_NORM) / 100; - - pa_log_info(__FILE__": Read mixer settings: %s\n", pa_cvolume_snprint(cv, sizeof(cv), &s->hw_volume)); - return 0; -} - -static int sink_set_hw_volume(pa_sink *s) { - struct userdata *u = s->userdata; - char cv[PA_CVOLUME_SNPRINT_MAX]; - unsigned vol; - - vol = (s->hw_volume.values[0]*100)/PA_VOLUME_NORM; - - if (s->sample_spec.channels >= 2) - vol |= ((s->hw_volume.values[1]*100)/PA_VOLUME_NORM) << 8; - - if (ioctl(u->fd, SOUND_MIXER_WRITE_PCM, &vol) < 0) { - pa_log_info(__FILE__": device doesn't support writing mixer settings: %s\n", strerror(errno)); - s->set_hw_volume = NULL; - return -1; - } - - pa_log_info(__FILE__": Wrote mixer settings: %s\n", pa_cvolume_snprint(cv, sizeof(cv), &s->hw_volume)); - return 0; -} - -int pa__init(pa_core *c, pa_module*m) { - struct audio_buf_info info; - struct userdata *u = NULL; - const char *p; - int fd = -1; - int nfrags, frag_size, in_frag_size, out_frag_size; - int mode; - int record = 1, playback = 1; - pa_sample_spec ss; - pa_modargs *ma = NULL; - assert(c && m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments.\n"); - goto fail; - } - - if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { - pa_log(__FILE__": record= and playback= expect numeric argument.\n"); - goto fail; - } - - if (!playback && !record) { - pa_log(__FILE__": neither playback nor record enabled for device.\n"); - goto fail; - } - - mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); - - nfrags = 12; - frag_size = 1024; - if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { - pa_log(__FILE__": failed to parse fragments arguments\n"); - goto fail; - } - - ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": failed to parse sample specification\n"); - goto fail; - } - - if ((fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, NULL)) < 0) - goto fail; - - pa_log_info(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); - - if (nfrags >= 2 && frag_size >= 1) - if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) - goto fail; - - if (pa_oss_auto_format(fd, &ss) < 0) - goto fail; - - if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETBLKSIZE: %s\n", strerror(errno)); - goto fail; - } - assert(frag_size); - in_frag_size = out_frag_size = frag_size; - - u = pa_xmalloc(sizeof(struct userdata)); - u->core = c; - u->use_getospace = u->use_getispace = 0; - - if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { - pa_log_info(__FILE__": input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); - in_frag_size = info.fragsize; - u->use_getispace = 1; - } - - if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) { - pa_log_info(__FILE__": output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); - out_frag_size = info.fragsize; - u->use_getospace = 1; - } - - if (mode != O_WRONLY) { - u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); - assert(u->source); - u->source->userdata = u; - u->source->notify = source_notify_cb; - u->source->get_latency = source_get_latency_cb; - pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); - } else - u->source = NULL; - - if (mode != O_RDONLY) { - u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); - assert(u->sink); - u->sink->get_latency = sink_get_latency_cb; - u->sink->get_hw_volume = sink_get_hw_volume; - u->sink->set_hw_volume = sink_set_hw_volume; - u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); - } else - u->sink = NULL; - - assert(u->source || u->sink); - - u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : -1); - assert(u->io); - pa_iochannel_set_callback(u->io, io_callback, u); - u->fd = fd; - - u->memchunk.memblock = NULL; - u->memchunk.length = 0; - u->sample_size = pa_frame_size(&ss); - - u->out_fragment_size = out_frag_size; - u->in_fragment_size = in_frag_size; - u->silence.memblock = pa_memblock_new(u->silence.length = u->out_fragment_size, u->core->memblock_stat); - assert(u->silence.memblock); - pa_silence_memblock(u->silence.memblock, &ss); - u->silence.index = 0; - - u->module = m; - m->userdata = u; - - pa_modargs_free(ma); - - /* - * Some crappy drivers do not start the recording until we read something. - * Without this snippet, poll will never register the fd as ready. - */ - if (u->source) { - char buf[u->sample_size]; - read(u->fd, buf, u->sample_size); - } - - /* Read mixer settings */ - if (u->sink) - sink_get_hw_volume(u->sink); - - return 0; - -fail: - if (fd >= 0) - close(fd); - - if (ma) - pa_modargs_free(ma); - - return -1; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u; - assert(c && m); - - if (!(u = m->userdata)) - return; - - if (u->memchunk.memblock) - pa_memblock_unref(u->memchunk.memblock); - if (u->silence.memblock) - pa_memblock_unref(u->silence.memblock); - - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - } - - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - } - - pa_iochannel_free(u->io); - pa_xfree(u); -} diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c deleted file mode 100644 index 20e220ce..00000000 --- a/polyp/module-pipe-sink.c +++ /dev/null @@ -1,236 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "iochannel.h" -#include "sink.h" -#include "module.h" -#include "util.h" -#include "modargs.h" -#include "xmalloc.h" -#include "log.h" -#include "module-pipe-sink-symdef.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("UNIX pipe sink") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= file= format= channels= rate=") - -#define DEFAULT_FIFO_NAME "/tmp/music.output" -#define DEFAULT_SINK_NAME "fifo_output" - -struct userdata { - pa_core *core; - - char *filename; - - pa_sink *sink; - pa_iochannel *io; - pa_defer_event *defer_event; - - pa_memchunk memchunk; - pa_module *module; -}; - -static const char* const valid_modargs[] = { - "file", - "rate", - "format", - "channels", - "sink_name", - NULL -}; - -static void do_write(struct userdata *u) { - ssize_t r; - assert(u); - - u->core->mainloop->defer_enable(u->defer_event, 0); - - if (!pa_iochannel_is_writable(u->io)) - return; - - pa_module_set_used(u->module, pa_idxset_size(u->sink->inputs) + pa_idxset_size(u->sink->monitor_source->outputs)); - - if (!u->memchunk.length) - if (pa_sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0) - return; - - assert(u->memchunk.memblock && u->memchunk.length); - - if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); - return; - } - - u->memchunk.index += r; - u->memchunk.length -= r; - - if (u->memchunk.length <= 0) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - } -} - -static void notify_cb(pa_sink*s) { - struct userdata *u = s->userdata; - assert(s && u); - - if (pa_iochannel_is_writable(u->io)) - u->core->mainloop->defer_enable(u->defer_event, 1); -} - -static pa_usec_t get_latency_cb(pa_sink *s) { - struct userdata *u = s->userdata; - assert(s && u); - - return u->memchunk.memblock ? pa_bytes_to_usec(u->memchunk.length, &s->sample_spec) : 0; -} - -static void defer_callback(PA_GCC_UNUSED pa_mainloop_api *m, PA_GCC_UNUSED pa_defer_event*e, void *userdata) { - struct userdata *u = userdata; - assert(u); - do_write(u); -} - -static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { - struct userdata *u = userdata; - assert(u); - do_write(u); -} - -int pa__init(pa_core *c, pa_module*m) { - struct userdata *u = NULL; - struct stat st; - const char *p; - int fd = -1; - pa_sample_spec ss; - pa_modargs *ma = NULL; - assert(c && m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); - goto fail; - } - - ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": invalid sample format specification\n"); - goto fail; - } - - mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777); - - if ((fd = open(p, O_RDWR)) < 0) { - pa_log(__FILE__": open('%s'): %s\n", p, strerror(errno)); - goto fail; - } - - pa_fd_set_cloexec(fd, 1); - - if (fstat(fd, &st) < 0) { - pa_log(__FILE__": fstat('%s'): %s\n", p, strerror(errno)); - goto fail; - } - - if (!S_ISFIFO(st.st_mode)) { - pa_log(__FILE__": '%s' is not a FIFO.\n", p); - goto fail; - } - - u = pa_xmalloc0(sizeof(struct userdata)); - u->filename = pa_xstrdup(p); - u->core = c; - u->module = m; - m->userdata = u; - - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { - pa_log(__FILE__": failed to create sink.\n"); - goto fail; - } - u->sink->notify = notify_cb; - u->sink->get_latency = get_latency_cb; - u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Unix FIFO sink '%s'", p); - assert(u->sink->description); - - u->io = pa_iochannel_new(c->mainloop, -1, fd); - assert(u->io); - pa_iochannel_set_callback(u->io, io_callback, u); - - u->memchunk.memblock = NULL; - u->memchunk.length = 0; - - u->defer_event = c->mainloop->defer_new(c->mainloop, defer_callback, u); - assert(u->defer_event); - c->mainloop->defer_enable(u->defer_event, 0); - - pa_modargs_free(ma); - - return 0; - -fail: - if (ma) - pa_modargs_free(ma); - - if (fd >= 0) - close(fd); - - pa__done(c, m); - - return -1; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u; - assert(c && m); - - if (!(u = m->userdata)) - return; - - if (u->memchunk.memblock) - pa_memblock_unref(u->memchunk.memblock); - - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - pa_iochannel_free(u->io); - u->core->mainloop->defer_free(u->defer_event); - - assert(u->filename); - unlink(u->filename); - pa_xfree(u->filename); - - pa_xfree(u); -} diff --git a/polyp/module-pipe-source.c b/polyp/module-pipe-source.c deleted file mode 100644 index 42f13d4b..00000000 --- a/polyp/module-pipe-source.c +++ /dev/null @@ -1,209 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "iochannel.h" -#include "source.h" -#include "module.h" -#include "util.h" -#include "modargs.h" -#include "xmalloc.h" -#include "log.h" -#include "module-pipe-source-symdef.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("UNIX pipe source") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("source_name= file= format= channels= rate=") - -#define DEFAULT_FIFO_NAME "/tmp/music.input" -#define DEFAULT_SOURCE_NAME "fifo_input" - -struct userdata { - pa_core *core; - - char *filename; - - pa_source *source; - pa_iochannel *io; - pa_module *module; - pa_memchunk chunk; -}; - -static const char* const valid_modargs[] = { - "file", - "rate", - "channels", - "format", - "source_name", - NULL -}; - -static void do_read(struct userdata *u) { - ssize_t r; - pa_memchunk chunk; - assert(u); - - if (!pa_iochannel_is_readable(u->io)) - return; - - pa_module_set_used(u->module, pa_idxset_size(u->source->outputs)); - - if (!u->chunk.memblock) { - u->chunk.memblock = pa_memblock_new(1024, u->core->memblock_stat); - u->chunk.index = chunk.length = 0; - } - - assert(u->chunk.memblock && u->chunk.memblock->length > u->chunk.index); - if ((r = pa_iochannel_read(u->io, (uint8_t*) u->chunk.memblock->data + u->chunk.index, u->chunk.memblock->length - u->chunk.index)) <= 0) { - pa_log(__FILE__": read() failed: %s\n", strerror(errno)); - return; - } - - u->chunk.length = r; - pa_source_post(u->source, &u->chunk); - u->chunk.index += r; - - if (u->chunk.index >= u->chunk.memblock->length) { - u->chunk.index = u->chunk.length = 0; - pa_memblock_unref(u->chunk.memblock); - u->chunk.memblock = NULL; - } -} - -static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { - struct userdata *u = userdata; - assert(u); - do_read(u); -} - -int pa__init(pa_core *c, pa_module*m) { - struct userdata *u = NULL; - struct stat st; - const char *p; - int fd = -1; - pa_sample_spec ss; - pa_modargs *ma = NULL; - assert(c && m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); - goto fail; - } - - ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": invalid sample format specification\n"); - goto fail; - } - - mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777); - - if ((fd = open(p, O_RDWR)) < 0) { - pa_log(__FILE__": open('%s'): %s\n", p, strerror(errno)); - goto fail; - } - - pa_fd_set_cloexec(fd, 1); - - if (fstat(fd, &st) < 0) { - pa_log(__FILE__": fstat('%s'): %s\n", p, strerror(errno)); - goto fail; - } - - if (!S_ISFIFO(st.st_mode)) { - pa_log(__FILE__": '%s' is not a FIFO.\n", p); - goto fail; - } - - u = pa_xmalloc0(sizeof(struct userdata)); - - u->filename = pa_xstrdup(p); - u->core = c; - - if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL))) { - pa_log(__FILE__": failed to create source.\n"); - goto fail; - } - u->source->userdata = u; - pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Unix FIFO source '%s'", p); - assert(u->source->description); - - u->io = pa_iochannel_new(c->mainloop, fd, -1); - assert(u->io); - pa_iochannel_set_callback(u->io, io_callback, u); - - u->chunk.memblock = NULL; - u->chunk.index = u->chunk.length = 0; - - u->module = m; - m->userdata = u; - - pa_modargs_free(ma); - - return 0; - -fail: - if (ma) - pa_modargs_free(ma); - - if (fd >= 0) - close(fd); - - pa__done(c, m); - - return -1; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u; - assert(c && m); - - if (!(u = m->userdata)) - return; - - if (u->chunk.memblock) - pa_memblock_unref(u->chunk.memblock); - - pa_source_disconnect(u->source); - pa_source_unref(u->source); - pa_iochannel_free(u->io); - - assert(u->filename); - unlink(u->filename); - pa_xfree(u->filename); - - pa_xfree(u); -} diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c deleted file mode 100644 index a0314368..00000000 --- a/polyp/module-protocol-stub.c +++ /dev/null @@ -1,262 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif - -#include "winsock.h" - -#include "module.h" -#include "socket-server.h" -#include "socket-util.h" -#include "util.h" -#include "modargs.h" -#include "log.h" -#include "native-common.h" -#include "util.h" - -#ifdef USE_TCP_SOCKETS -#define SOCKET_DESCRIPTION "(TCP sockets)" -#define SOCKET_USAGE "port= loopback=" -#elif defined(USE_TCP6_SOCKETS) -#define SOCKET_DESCRIPTION "(TCP/IPv6 sockets)" -#define SOCKET_USAGE "port= loopback=" -#else -#define SOCKET_DESCRIPTION "(UNIX sockets)" -#define SOCKET_USAGE "socket=" -#endif - -#if defined(USE_PROTOCOL_SIMPLE) - #include "protocol-simple.h" - #define protocol_new pa_protocol_simple_new - #define protocol_free pa_protocol_simple_free - #define TCPWRAP_SERVICE "polypaudio-simple" - #define IPV4_PORT 4711 - #define UNIX_SOCKET "simple" - #define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record", - #if defined(USE_TCP_SOCKETS) - #include "module-simple-protocol-tcp-symdef.h" - #elif defined(USE_TCP6_SOCKETS) - #include "module-simple-protocol-tcp6-symdef.h" - #else - #include "module-simple-protocol-unix-symdef.h" - #endif - PA_MODULE_DESCRIPTION("Simple protocol "SOCKET_DESCRIPTION) - PA_MODULE_USAGE("rate= format= channels= sink= source= playback= record= "SOCKET_USAGE) -#elif defined(USE_PROTOCOL_CLI) - #include "protocol-cli.h" - #define protocol_new pa_protocol_cli_new - #define protocol_free pa_protocol_cli_free - #define TCPWRAP_SERVICE "polypaudio-cli" - #define IPV4_PORT 4712 - #define UNIX_SOCKET "cli" - #define MODULE_ARGUMENTS - #ifdef USE_TCP_SOCKETS - #include "module-cli-protocol-tcp-symdef.h" - #elif defined(USE_TCP6_SOCKETS) - #include "module-cli-protocol-tcp6-symdef.h" - #else - #include "module-cli-protocol-unix-symdef.h" - #endif - PA_MODULE_DESCRIPTION("Command line interface protocol "SOCKET_DESCRIPTION) - PA_MODULE_USAGE(SOCKET_USAGE) -#elif defined(USE_PROTOCOL_HTTP) - #include "protocol-http.h" - #define protocol_new pa_protocol_http_new - #define protocol_free pa_protocol_http_free - #define TCPWRAP_SERVICE "polypaudio-http" - #define IPV4_PORT 4714 - #define UNIX_SOCKET "http" - #define MODULE_ARGUMENTS - #ifdef USE_TCP_SOCKETS - #include "module-http-protocol-tcp-symdef.h" - #elif defined(USE_TCP6_SOCKETS) - #include "module-http-protocol-tcp6-symdef.h" - #else - #include "module-http-protocol-unix-symdef.h" - #endif - PA_MODULE_DESCRIPTION("HTTP "SOCKET_DESCRIPTION) - PA_MODULE_USAGE(SOCKET_USAGE) -#elif defined(USE_PROTOCOL_NATIVE) - #include "protocol-native.h" - #define protocol_new pa_protocol_native_new - #define protocol_free pa_protocol_native_free - #define TCPWRAP_SERVICE "polypaudio-native" - #define IPV4_PORT PA_NATIVE_DEFAULT_PORT - #define UNIX_SOCKET PA_NATIVE_DEFAULT_UNIX_SOCKET - #define MODULE_ARGUMENTS "public", "cookie", - #ifdef USE_TCP_SOCKETS - #include "module-native-protocol-tcp-symdef.h" - #elif defined(USE_TCP6_SOCKETS) - #include "module-native-protocol-tcp6-symdef.h" - #else - #include "module-native-protocol-unix-symdef.h" - #endif - PA_MODULE_DESCRIPTION("Native protocol "SOCKET_DESCRIPTION) - PA_MODULE_USAGE("public= cookie= "SOCKET_USAGE) -#elif defined(USE_PROTOCOL_ESOUND) - #include "protocol-esound.h" - #include "esound.h" - #define protocol_new pa_protocol_esound_new - #define protocol_free pa_protocol_esound_free - #define TCPWRAP_SERVICE "esound" - #define IPV4_PORT ESD_DEFAULT_PORT - #define UNIX_SOCKET ESD_UNIX_SOCKET_NAME - #define MODULE_ARGUMENTS "sink", "source", "public", "cookie", - #ifdef USE_TCP_SOCKETS - #include "module-esound-protocol-tcp-symdef.h" - #elif defined(USE_TCP6_SOCKETS) - #include "module-esound-protocol-tcp6-symdef.h" - #else - #include "module-esound-protocol-unix-symdef.h" - #endif - PA_MODULE_DESCRIPTION("ESOUND protocol "SOCKET_DESCRIPTION) - PA_MODULE_USAGE("sink= source= public= cookie= "SOCKET_USAGE) -#else - #error "Broken build system" -#endif - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_VERSION(PACKAGE_VERSION) - -static const char* const valid_modargs[] = { - MODULE_ARGUMENTS -#if defined(USE_TCP_SOCKETS) || defined(USE_TCP6_SOCKETS) - "port", - "loopback", -#else - "socket", -#endif - NULL -}; - -static pa_socket_server *create_socket_server(pa_core *c, pa_modargs *ma) { - pa_socket_server *s; -#if defined(USE_TCP_SOCKETS) || defined(USE_TCP6_SOCKETS) - int loopback = 1; - uint32_t port = IPV4_PORT; - - if (pa_modargs_get_value_boolean(ma, "loopback", &loopback) < 0) { - pa_log(__FILE__": loopback= expects a boolean argument.\n"); - return NULL; - } - - if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) { - pa_log(__FILE__": port= expects a numerical argument between 1 and 65535.\n"); - return NULL; - } - -#ifdef USE_TCP6_SOCKETS - if (!(s = pa_socket_server_new_ipv6(c->mainloop, loopback ? (const uint8_t*) &in6addr_loopback : (const uint8_t*) &in6addr_any, port))) - return NULL; -#else - if (!(s = pa_socket_server_new_ipv4(c->mainloop, loopback ? INADDR_LOOPBACK : INADDR_ANY, port, TCPWRAP_SERVICE))) - return NULL; -#endif - -#else - int r; - const char *v; - char tmp[PATH_MAX]; - - v = pa_modargs_get_value(ma, "socket", UNIX_SOCKET); - assert(v); - - pa_runtime_path(v, tmp, sizeof(tmp)); - - if (pa_make_secure_parent_dir(tmp) < 0) { - pa_log(__FILE__": Failed to create secure socket directory.\n"); - return NULL; - } - - if ((r = pa_unix_socket_remove_stale(tmp)) < 0) { - pa_log(__FILE__": Failed to remove stale UNIX socket '%s': %s\n", tmp, strerror(errno)); - return NULL; - } - - if (r) - pa_log(__FILE__": Removed stale UNIX socket '%s'.", tmp); - - if (!(s = pa_socket_server_new_unix(c->mainloop, tmp))) - return NULL; - -#endif - return s; -} - -int pa__init(pa_core *c, pa_module*m) { - pa_socket_server *s; - pa_modargs *ma = NULL; - int ret = -1; - assert(c && m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments\n"); - goto finish; - } - - if (!(s = create_socket_server(c, ma))) - goto finish; - - if (!(m->userdata = protocol_new(c, s, m, ma))) { - pa_socket_server_unref(s); - goto finish; - } - - ret = 0; - -finish: - if (ma) - pa_modargs_free(ma); - - return ret; -} - -void pa__done(pa_core *c, pa_module*m) { - assert(c && m); - -#if defined(USE_PROTOCOL_ESOUND) - if (remove (ESD_UNIX_SOCKET_NAME) != 0) - pa_log("%s: Failed to remove %s : %s.\n", __FILE__, ESD_UNIX_SOCKET_NAME, strerror (errno)); - if (remove (ESD_UNIX_SOCKET_DIR) != 0) - pa_log("%s: Failed to remove %s : %s.\n", __FILE__, ESD_UNIX_SOCKET_DIR, strerror (errno)); -#endif - - protocol_free(m->userdata); -} diff --git a/polyp/module-sine.c b/polyp/module-sine.c deleted file mode 100644 index 529c061a..00000000 --- a/polyp/module-sine.c +++ /dev/null @@ -1,181 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "sink-input.h" -#include "module.h" -#include "modargs.h" -#include "xmalloc.h" -#include "namereg.h" -#include "log.h" -#include "module-sine-symdef.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Sine wave generator") -PA_MODULE_USAGE("sink= frequency=") -PA_MODULE_VERSION(PACKAGE_VERSION) - -struct userdata { - pa_core *core; - pa_module *module; - pa_sink_input *sink_input; - pa_memblock *memblock; - size_t peek_index; -}; - -static const char* const valid_modargs[] = { - "sink", - "frequency", - NULL, -}; - -static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { - struct userdata *u; - assert(i && chunk && i->userdata); - u = i->userdata; - - chunk->memblock = pa_memblock_ref(u->memblock); - chunk->index = u->peek_index; - chunk->length = u->memblock->length - u->peek_index; - return 0; -} - -static void sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { - struct userdata *u; - assert(i && chunk && length && i->userdata); - u = i->userdata; - - assert(chunk->memblock == u->memblock && length <= u->memblock->length-u->peek_index); - - u->peek_index += length; - - if (u->peek_index >= u->memblock->length) - u->peek_index = 0; -} - -static void sink_input_kill(pa_sink_input *i) { - struct userdata *u; - assert(i && i->userdata); - u = i->userdata; - - pa_sink_input_disconnect(u->sink_input); - pa_sink_input_unref(u->sink_input); - u->sink_input = NULL; - - pa_module_unload_request(u->module); -} - -static void calc_sine(float *f, size_t l, float freq) { - size_t i; - - l /= sizeof(float); - - for (i = 0; i < l; i++) - f[i] = (float) sin((double) i/l*M_PI*2*freq)/2; -} - -int pa__init(pa_core *c, pa_module*m) { - pa_modargs *ma = NULL; - struct userdata *u; - pa_sink *sink; - const char *sink_name; - pa_sample_spec ss; - uint32_t frequency; - char t[256]; - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments\n"); - goto fail; - } - - m->userdata = u = pa_xmalloc(sizeof(struct userdata)); - u->core = c; - u->module = m; - u->sink_input = NULL; - u->memblock = NULL; - - sink_name = pa_modargs_get_value(ma, "sink", NULL); - - if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": No such sink.\n"); - goto fail; - } - - ss.format = PA_SAMPLE_FLOAT32; - ss.rate = sink->sample_spec.rate; - ss.channels = 1; - - frequency = 440; - if (pa_modargs_get_value_u32(ma, "frequency", &frequency) < 0 || frequency < 1 || frequency > ss.rate/2) { - pa_log(__FILE__": Invalid frequency specification\n"); - goto fail; - } - - u->memblock = pa_memblock_new(pa_bytes_per_second(&ss), c->memblock_stat); - calc_sine(u->memblock->data, u->memblock->length, frequency); - - snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency); - if (!(u->sink_input = pa_sink_input_new(sink, __FILE__, t, &ss, NULL, 0, -1))) - goto fail; - - u->sink_input->peek = sink_input_peek; - u->sink_input->drop = sink_input_drop; - u->sink_input->kill = sink_input_kill; - u->sink_input->userdata = u; - u->sink_input->owner = m; - - u->peek_index = 0; - - pa_modargs_free(ma); - return 0; - -fail: - if (ma) - pa_modargs_free(ma); - - pa__done(c, m); - return -1; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u = m->userdata; - assert(c && m); - - if (!u) - return; - - if (u->sink_input) { - pa_sink_input_disconnect(u->sink_input); - pa_sink_input_unref(u->sink_input); - } - - if (u->memblock) - pa_memblock_unref(u->memblock); - pa_xfree(u); -} - diff --git a/polyp/module-solaris.c b/polyp/module-solaris.c deleted file mode 100644 index f85e71df..00000000 --- a/polyp/module-solaris.c +++ /dev/null @@ -1,486 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "iochannel.h" -#include "sink.h" -#include "source.h" -#include "module.h" -#include "sample-util.h" -#include "util.h" -#include "modargs.h" -#include "xmalloc.h" -#include "log.h" -#include "mainloop-signal.h" -#include "module-solaris-symdef.h" - -PA_MODULE_AUTHOR("Pierre Ossman") -PA_MODULE_DESCRIPTION("Solaris Sink/Source") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= buffer_size=") - -struct userdata { - pa_sink *sink; - pa_source *source; - pa_iochannel *io; - pa_core *core; - pa_signal_event *sig; - - pa_memchunk memchunk, silence; - - uint32_t sample_size; - uint32_t buffer_size; - unsigned int written_bytes, read_bytes; - - int fd; - pa_module *module; -}; - -static const char* const valid_modargs[] = { - "sink_name", - "source_name", - "device", - "record", - "playback", - "buffer_size", - "format", - "rate", - "channels", - NULL -}; - -#define DEFAULT_SINK_NAME "solaris_output" -#define DEFAULT_SOURCE_NAME "solaris_input" -#define DEFAULT_DEVICE "/dev/audio" - -#define CHUNK_SIZE 2048 - -static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, - (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + - (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0) + - (u->source ? pa_idxset_size(u->source->outputs) : 0)); -} - -static void do_write(struct userdata *u) { - audio_info_t info; - int err; - pa_memchunk *memchunk; - size_t len; - ssize_t r; - - assert(u); - - if (!u->sink || !pa_iochannel_is_writable(u->io)) - return; - - update_usage(u); - - err = ioctl(u->fd, AUDIO_GETINFO, &info); - assert(err >= 0); - - /* - * Since we cannot modify the size of the output buffer we fake it - * by not filling it more than u->buffer_size. - */ - len = u->buffer_size; - len -= u->written_bytes - (info.play.samples * u->sample_size); - - /* - * Do not fill more than half the buffer in one chunk since we only - * get notifications upon completion of entire chunks. - */ - if (len > (u->buffer_size / 2)) - len = u->buffer_size / 2; - - if (len < u->sample_size) - return; - - memchunk = &u->memchunk; - - if (!memchunk->length) - if (pa_sink_render(u->sink, len, memchunk) < 0) - memchunk = &u->silence; - - assert(memchunk->memblock); - assert(memchunk->memblock->data); - assert(memchunk->length); - - if (memchunk->length < len) - len = memchunk->length; - - if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, len)) < 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); - return; - } - - if (memchunk == &u->silence) - assert(r % u->sample_size == 0); - else { - u->memchunk.index += r; - u->memchunk.length -= r; - - if (u->memchunk.length <= 0) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - } - } - - u->written_bytes += r; - - /* - * Write 0 bytes which will generate a SIGPOLL when "played". - */ - if (write(u->fd, NULL, 0) < 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); - return; - } -} - -static void do_read(struct userdata *u) { - pa_memchunk memchunk; - int err, l; - ssize_t r; - assert(u); - - if (!u->source || !pa_iochannel_is_readable(u->io)) - return; - - update_usage(u); - - err = ioctl(u->fd, I_NREAD, &l); - assert(err >= 0); - - memchunk.memblock = pa_memblock_new(l, u->core->memblock_stat); - assert(memchunk.memblock); - if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { - pa_memblock_unref(memchunk.memblock); - if (errno != EAGAIN) - pa_log(__FILE__": read() failed: %s\n", strerror(errno)); - return; - } - - assert(r <= (ssize_t) memchunk.memblock->length); - memchunk.length = memchunk.memblock->length = r; - memchunk.index = 0; - - pa_source_post(u->source, &memchunk); - pa_memblock_unref(memchunk.memblock); - - u->read_bytes += r; -} - -static void io_callback(pa_iochannel *io, void*userdata) { - struct userdata *u = userdata; - assert(u); - do_write(u); - do_read(u); -} - -void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata) { - struct userdata *u = userdata; - assert(u); - do_write(u); -} - -static pa_usec_t sink_get_latency_cb(pa_sink *s) { - pa_usec_t r = 0; - audio_info_t info; - int err; - struct userdata *u = s->userdata; - assert(s && u && u->sink); - - err = ioctl(u->fd, AUDIO_GETINFO, &info); - assert(err >= 0); - - r += pa_bytes_to_usec(u->written_bytes, &s->sample_spec); - r -= pa_bytes_to_usec(info.play.samples * u->sample_size, &s->sample_spec); - - if (u->memchunk.memblock) - r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec); - - return r; -} - -static pa_usec_t source_get_latency_cb(pa_source *s) { - pa_usec_t r = 0; - struct userdata *u = s->userdata; - audio_info_t info; - int err; - assert(s && u && u->source); - - err = ioctl(u->fd, AUDIO_GETINFO, &info); - assert(err >= 0); - - r += pa_bytes_to_usec(info.record.samples * u->sample_size, &s->sample_spec); - r -= pa_bytes_to_usec(u->read_bytes, &s->sample_spec); - - return r; -} - -static int pa_solaris_auto_format(int fd, int mode, pa_sample_spec *ss) { - audio_info_t info; - - AUDIO_INITINFO(&info); - - if (mode != O_RDONLY) { - info.play.sample_rate = ss->rate; - info.play.channels = ss->channels; - switch (ss->format) { - case PA_SAMPLE_U8: - info.play.precision = 8; - info.play.encoding = AUDIO_ENCODING_LINEAR; - break; - case PA_SAMPLE_ALAW: - info.play.precision = 8; - info.play.encoding = AUDIO_ENCODING_ALAW; - break; - case PA_SAMPLE_ULAW: - info.play.precision = 8; - info.play.encoding = AUDIO_ENCODING_ULAW; - break; - case PA_SAMPLE_S16NE: - info.play.precision = 16; - info.play.encoding = AUDIO_ENCODING_LINEAR; - break; - default: - return -1; - } - } - - if (mode != O_WRONLY) { - info.record.sample_rate = ss->rate; - info.record.channels = ss->channels; - switch (ss->format) { - case PA_SAMPLE_U8: - info.record.precision = 8; - info.record.encoding = AUDIO_ENCODING_LINEAR; - break; - case PA_SAMPLE_ALAW: - info.record.precision = 8; - info.record.encoding = AUDIO_ENCODING_ALAW; - break; - case PA_SAMPLE_ULAW: - info.record.precision = 8; - info.record.encoding = AUDIO_ENCODING_ULAW; - break; - case PA_SAMPLE_S16NE: - info.record.precision = 16; - info.record.encoding = AUDIO_ENCODING_LINEAR; - break; - default: - return -1; - } - } - - if (ioctl(fd, AUDIO_SETINFO, &info) < 0) { - if (errno == EINVAL) - pa_log(__FILE__": AUDIO_SETINFO: Unsupported sample format.\n"); - else - pa_log(__FILE__": AUDIO_SETINFO: %s\n", strerror(errno)); - return -1; - } - - return 0; -} - -static int pa_solaris_set_buffer(int fd, int buffer_size) { - audio_info_t info; - - AUDIO_INITINFO(&info); - - info.record.buffer_size = buffer_size; - - if (ioctl(fd, AUDIO_SETINFO, &info) < 0) { - if (errno == EINVAL) - pa_log(__FILE__": AUDIO_SETINFO: Unsupported buffer size.\n"); - else - pa_log(__FILE__": AUDIO_SETINFO: %s\n", strerror(errno)); - return -1; - } - - return 0; -} - -int pa__init(pa_core *c, pa_module*m) { - struct userdata *u = NULL; - const char *p; - int fd = -1; - int buffer_size; - int mode; - int record = 1, playback = 1; - pa_sample_spec ss; - pa_modargs *ma = NULL; - assert(c && m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments.\n"); - goto fail; - } - - if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { - pa_log(__FILE__": record= and playback= expect numeric argument.\n"); - goto fail; - } - - if (!playback && !record) { - pa_log(__FILE__": neither playback nor record enabled for device.\n"); - goto fail; - } - - mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); - - buffer_size = 16384; - if (pa_modargs_get_value_s32(ma, "buffer_size", &buffer_size) < 0) { - pa_log(__FILE__": failed to parse buffer size argument\n"); - goto fail; - } - - ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": failed to parse sample specification\n"); - goto fail; - } - - if ((fd = open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), mode | O_NONBLOCK)) < 0) - goto fail; - - pa_log_info(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); - - if (pa_solaris_auto_format(fd, mode, &ss) < 0) - goto fail; - - if ((mode != O_WRONLY) && (buffer_size >= 1)) - if (pa_solaris_set_buffer(fd, buffer_size) < 0) - goto fail; - - u = pa_xmalloc(sizeof(struct userdata)); - u->core = c; - - if (mode != O_WRONLY) { - u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); - assert(u->source); - u->source->userdata = u; - u->source->get_latency = source_get_latency_cb; - pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Solaris PCM on '%s'", p); - } else - u->source = NULL; - - if (mode != O_RDONLY) { - u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); - assert(u->sink); - u->sink->get_latency = sink_get_latency_cb; - u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Solaris PCM on '%s'", p); - } else - u->sink = NULL; - - assert(u->source || u->sink); - - u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : 0); - assert(u->io); - pa_iochannel_set_callback(u->io, io_callback, u); - u->fd = fd; - - u->memchunk.memblock = NULL; - u->memchunk.length = 0; - u->sample_size = pa_frame_size(&ss); - u->buffer_size = buffer_size; - - u->silence.memblock = pa_memblock_new(u->silence.length = CHUNK_SIZE, u->core->memblock_stat); - assert(u->silence.memblock); - pa_silence_memblock(u->silence.memblock, &ss); - u->silence.index = 0; - - u->written_bytes = 0; - u->read_bytes = 0; - - u->module = m; - m->userdata = u; - - u->sig = pa_signal_new(SIGPOLL, sig_callback, u); - assert(u->sig); - ioctl(u->fd, I_SETSIG, S_MSG); - - pa_modargs_free(ma); - - return 0; - -fail: - if (fd >= 0) - close(fd); - - if (ma) - pa_modargs_free(ma); - - return -1; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u; - assert(c && m); - - if (!(u = m->userdata)) - return; - - ioctl(u->fd, I_SETSIG, 0); - pa_signal_free(u->sig); - - if (u->memchunk.memblock) - pa_memblock_unref(u->memchunk.memblock); - if (u->silence.memblock) - pa_memblock_unref(u->silence.memblock); - - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - } - - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - } - - pa_iochannel_free(u->io); - pa_xfree(u); -} diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c deleted file mode 100644 index c088dae0..00000000 --- a/polyp/module-tunnel.c +++ /dev/null @@ -1,688 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "module.h" -#include "util.h" -#include "modargs.h" -#include "log.h" -#include "subscribe.h" -#include "xmalloc.h" -#include "sink-input.h" -#include "pdispatch.h" -#include "pstream.h" -#include "pstream-util.h" -#include "authkey.h" -#include "socket-client.h" -#include "socket-util.h" -#include "authkey-prop.h" - -#ifdef TUNNEL_SINK -#include "module-tunnel-sink-symdef.h" -PA_MODULE_DESCRIPTION("Tunnel module for sinks") -PA_MODULE_USAGE("server=
    sink= cookie= format= channels= rate= sink_name=") -#else -#include "module-tunnel-source-symdef.h" -PA_MODULE_DESCRIPTION("Tunnel module for sources") -PA_MODULE_USAGE("server=
    source= cookie= format= channels= rate= source_name=") -#endif - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_VERSION(PACKAGE_VERSION) - -#define DEFAULT_SINK_NAME "tunnel" -#define DEFAULT_SOURCE_NAME "tunnel" - -#define DEFAULT_TLENGTH (44100*2*2/10) //(10240*8) -#define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2) -#define DEFAULT_MINREQ 512 -#define DEFAULT_PREBUF (DEFAULT_TLENGTH-DEFAULT_MINREQ) -#define DEFAULT_FRAGSIZE 1024 - -#define DEFAULT_TIMEOUT 5 - -#define LATENCY_INTERVAL 10 - -static const char* const valid_modargs[] = { - "server", - "cookie", - "format", - "channels", - "rate", -#ifdef TUNNEL_SINK - "sink_name", - "sink", -#else - "source_name", - "source", -#endif - NULL, -}; - -static void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); - -#ifdef TUNNEL_SINK -static void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -#endif - -static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { -#ifdef TUNNEL_SINK - [PA_COMMAND_REQUEST] = command_request, -#endif - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = command_stream_killed, - [PA_COMMAND_RECORD_STREAM_KILLED] = command_stream_killed -}; - -struct userdata { - pa_socket_client *client; - pa_pstream *pstream; - pa_pdispatch *pdispatch; - - char *server_name; -#ifdef TUNNEL_SINK - char *sink_name; - pa_sink *sink; - uint32_t requested_bytes; -#else - char *source_name; - pa_source *source; -#endif - - pa_module *module; - pa_core *core; - - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; - - uint32_t ctag; - uint32_t device_index; - uint32_t channel; - - pa_usec_t host_latency; - - pa_time_event *time_event; - - int auth_cookie_in_property; -}; - -static void close_stuff(struct userdata *u) { - assert(u); - - if (u->pstream) { - pa_pstream_close(u->pstream); - pa_pstream_unref(u->pstream); - u->pstream = NULL; - } - - if (u->pdispatch) { - pa_pdispatch_unref(u->pdispatch); - u->pdispatch = NULL; - } - - if (u->client) { - pa_socket_client_unref(u->client); - u->client = NULL; - } - -#ifdef TUNNEL_SINK - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - u->sink = NULL; - } -#else - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - u->source = NULL; - } -#endif - - if (u->time_event) { - u->core->mainloop->time_free(u->time_event); - u->time_event = NULL; - } -} - -static void die(struct userdata *u) { - assert(u); - close_stuff(u); - pa_module_unload_request(u->module); -} - -static void command_stream_killed(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - struct userdata *u = userdata; - assert(pd && t && u && u->pdispatch == pd); - - pa_log(__FILE__": stream killed\n"); - die(u); -} - -#ifdef TUNNEL_SINK -static void send_prebuf_request(struct userdata *u) { - pa_tagstruct *t; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_PREBUF_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, u->ctag++); - pa_tagstruct_putu32(t, u->channel); - pa_pstream_send_tagstruct(u->pstream, t); -} - -static void send_bytes(struct userdata *u) { - assert(u); - - if (!u->pstream) - return; - - while (u->requested_bytes > 0) { - pa_memchunk chunk; - if (pa_sink_render(u->sink, u->requested_bytes, &chunk) < 0) { - - - if (u->requested_bytes >= DEFAULT_TLENGTH-DEFAULT_PREBUF) - send_prebuf_request(u); - - return; - } - - pa_pstream_send_memblock(u->pstream, u->channel, 0, &chunk); - pa_memblock_unref(chunk.memblock); - - if (chunk.length > u->requested_bytes) - u->requested_bytes = 0; - else - u->requested_bytes -= chunk.length; - } -} - -static void command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - struct userdata *u = userdata; - uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && u && u->pdispatch == pd); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid protocol reply\n"); - die(u); - return; - } - - if (channel != u->channel) { - pa_log(__FILE__": recieved data for invalid channel\n"); - die(u); - return; - } - - u->requested_bytes += bytes; - send_bytes(u); -} - -#endif - -static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - struct userdata *u = userdata; - pa_usec_t buffer_usec, sink_usec, source_usec, transport_usec; - int playing; - uint32_t queue_length; - uint64_t counter; - struct timeval local, remote, now; - assert(pd && u); - - if (command != PA_COMMAND_REPLY) { - if (command == PA_COMMAND_ERROR) - pa_log(__FILE__": failed to get latency.\n"); - else - pa_log(__FILE__": protocol error.\n"); - die(u); - return; - } - - if (pa_tagstruct_get_usec(t, &buffer_usec) < 0 || - pa_tagstruct_get_usec(t, &sink_usec) < 0 || - pa_tagstruct_get_usec(t, &source_usec) < 0 || - pa_tagstruct_get_boolean(t, &playing) < 0 || - pa_tagstruct_getu32(t, &queue_length) < 0 || - pa_tagstruct_get_timeval(t, &local) < 0 || - pa_tagstruct_get_timeval(t, &remote) < 0 || - pa_tagstruct_getu64(t, &counter) < 0 || - !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid reply.\n"); - die(u); - return; - } - - pa_gettimeofday(&now); - - if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) { - /* local and remote seem to have synchronized clocks */ -#ifdef TUNNEL_SINK - transport_usec = pa_timeval_diff(&remote, &local); -#else - transport_usec = pa_timeval_diff(&now, &remote); -#endif - } else - transport_usec = pa_timeval_diff(&now, &local)/2; - -#ifdef TUNNEL_SINK - u->host_latency = sink_usec + transport_usec; -#else - u->host_latency = source_usec + transport_usec; - if (u->host_latency > sink_usec) - u->host_latency -= sink_usec; - else - u->host_latency = 0; -#endif - -/* pa_log(__FILE__": estimated host latency: %0.0f usec\n", (double) u->host_latency); */ -} - -static void request_latency(struct userdata *u) { - pa_tagstruct *t; - struct timeval now; - uint32_t tag; - assert(u); - - t = pa_tagstruct_new(NULL, 0); -#ifdef TUNNEL_SINK - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); -#else - pa_tagstruct_putu32(t, PA_COMMAND_GET_RECORD_LATENCY); -#endif - pa_tagstruct_putu32(t, tag = u->ctag++); - pa_tagstruct_putu32(t, u->channel); - - pa_gettimeofday(&now); - pa_tagstruct_put_timeval(t, &now); - pa_tagstruct_putu64(t, 0); - - pa_pstream_send_tagstruct(u->pstream, t); - pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u); -} - -static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - struct userdata *u = userdata; - assert(pd && u && u->pdispatch == pd); - - if (command != PA_COMMAND_REPLY) { - if (command == PA_COMMAND_ERROR) - pa_log(__FILE__": failed to create stream.\n"); - else - pa_log(__FILE__": protocol error.\n"); - die(u); - return; - } - - if (pa_tagstruct_getu32(t, &u->channel) < 0 || - pa_tagstruct_getu32(t, &u->device_index) < 0 || -#ifdef TUNNEL_SINK - pa_tagstruct_getu32(t, &u->requested_bytes) < 0 || -#endif - !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid reply.\n"); - die(u); - return; - } - - request_latency(u); -#ifdef TUNNEL_SINK - send_bytes(u); -#endif -} - -static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct userdata *u = userdata; - pa_tagstruct *reply; - char name[256], un[128], hn[128]; - assert(pd && u && u->pdispatch == pd); - - if (command != PA_COMMAND_REPLY || !pa_tagstruct_eof(t)) { - if (command == PA_COMMAND_ERROR) - pa_log(__FILE__": failed to authenticate\n"); - else - pa_log(__FILE__": protocol error.\n"); - die(u); - return; - } -#ifdef TUNNEL_SINK - snprintf(name, sizeof(name), "Tunnel from host '%s', user '%s', sink '%s'", - pa_get_host_name(hn, sizeof(hn)), - pa_get_user_name(un, sizeof(un)), - u->sink->name); -#else - snprintf(name, sizeof(name), "Tunnel from host '%s', user '%s', source '%s'", - pa_get_host_name(hn, sizeof(hn)), - pa_get_user_name(un, sizeof(un)), - u->source->name); -#endif - - reply = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME); - pa_tagstruct_putu32(reply, tag = u->ctag++); - pa_tagstruct_puts(reply, name); - pa_pstream_send_tagstruct(u->pstream, reply); - /* We ignore the server's reply here */ - - reply = pa_tagstruct_new(NULL, 0); -#ifdef TUNNEL_SINK - pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_PLAYBACK_STREAM); - pa_tagstruct_putu32(reply, tag = u->ctag++); - pa_tagstruct_puts(reply, name); - pa_tagstruct_put_sample_spec(reply, &u->sink->sample_spec); - pa_tagstruct_putu32(reply, PA_INVALID_INDEX); - pa_tagstruct_puts(reply, u->sink_name); - pa_tagstruct_putu32(reply, DEFAULT_MAXLENGTH); - pa_tagstruct_put_boolean(reply, 0); - pa_tagstruct_putu32(reply, DEFAULT_TLENGTH); - pa_tagstruct_putu32(reply, DEFAULT_PREBUF); - pa_tagstruct_putu32(reply, DEFAULT_MINREQ); - pa_tagstruct_putu32(reply, PA_VOLUME_NORM); -#else - pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_RECORD_STREAM); - pa_tagstruct_putu32(reply, tag = u->ctag++); - pa_tagstruct_puts(reply, name); - pa_tagstruct_put_sample_spec(reply, &u->source->sample_spec); - pa_tagstruct_putu32(reply, PA_INVALID_INDEX); - pa_tagstruct_puts(reply, u->source_name); - pa_tagstruct_putu32(reply, DEFAULT_MAXLENGTH); - pa_tagstruct_put_boolean(reply, 0); - pa_tagstruct_putu32(reply, DEFAULT_FRAGSIZE); -#endif - - pa_pstream_send_tagstruct(u->pstream, reply); - pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, u); -} - -static void pstream_die_callback(pa_pstream *p, void *userdata) { - struct userdata *u = userdata; - assert(p && u); - - pa_log(__FILE__": stream died.\n"); - die(u); -} - - -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { - struct userdata *u = userdata; - assert(p && packet && u); - - if (pa_pdispatch_run(u->pdispatch, packet, u) < 0) { - pa_log(__FILE__": invalid packet\n"); - die(u); - } -} - -#ifndef TUNNEL_SINK -static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata) { - struct userdata *u = userdata; - assert(p && chunk && u); - - if (channel != u->channel) { - pa_log(__FILE__": recieved memory block on bad channel.\n"); - die(u); - return; - } - - pa_source_post(u->source, chunk); -} -#endif - -static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata) { - struct userdata *u = userdata; - pa_tagstruct *t; - uint32_t tag; - assert(sc && u && u->client == sc); - - pa_socket_client_unref(u->client); - u->client = NULL; - - if (!io) { - pa_log(__FILE__": connection failed.\n"); - pa_module_unload_request(u->module); - return; - } - - u->pstream = pa_pstream_new(u->core->mainloop, io, u->core->memblock_stat); - u->pdispatch = pa_pdispatch_new(u->core->mainloop, command_table, PA_COMMAND_MAX); - - pa_pstream_set_die_callback(u->pstream, pstream_die_callback, u); - pa_pstream_set_recieve_packet_callback(u->pstream, pstream_packet_callback, u); -#ifndef TUNNEL_SINK - pa_pstream_set_recieve_memblock_callback(u->pstream, pstream_memblock_callback, u); -#endif - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = u->ctag++); - pa_tagstruct_put_arbitrary(t, u->auth_cookie, sizeof(u->auth_cookie)); - pa_pstream_send_tagstruct(u->pstream, t); - pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, u); - -} - -#ifdef TUNNEL_SINK -static void sink_notify(pa_sink*sink) { - struct userdata *u; - assert(sink && sink->userdata); - u = sink->userdata; - - send_bytes(u); -} - -static pa_usec_t sink_get_latency(pa_sink *sink) { - struct userdata *u; - uint32_t l; - pa_usec_t usec = 0; - assert(sink && sink->userdata); - u = sink->userdata; - - l = DEFAULT_TLENGTH; - - if (l > u->requested_bytes) { - l -= u->requested_bytes; - usec += pa_bytes_to_usec(l, &u->sink->sample_spec); - } - - usec += u->host_latency; - - return usec; -} -#else -static pa_usec_t source_get_latency(pa_source *source) { - struct userdata *u; - assert(source && source->userdata); - u = source->userdata; - - return u->host_latency; -} -#endif - -static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - struct userdata *u = userdata; - struct timeval ntv; - assert(m && e && u); - - request_latency(u); - - pa_gettimeofday(&ntv); - ntv.tv_sec += LATENCY_INTERVAL; - m->time_restart(e, &ntv); -} - -static int load_key(struct userdata *u, const char*fn) { - assert(u); - - u->auth_cookie_in_property = 0; - - if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { - pa_log_debug(__FILE__": using already loaded auth cookie.\n"); - pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); - u->auth_cookie_in_property = 1; - return 0; - } - - if (!fn) - fn = PA_NATIVE_COOKIE_FILE; - - if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) - return -1; - - pa_log_debug(__FILE__": loading cookie from disk.\n"); - - if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) - u->auth_cookie_in_property = 1; - - return 0; -} - -int pa__init(pa_core *c, pa_module*m) { - pa_modargs *ma = NULL; - struct userdata *u = NULL; - pa_sample_spec ss; - struct timeval ntv; - assert(c && m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); - goto fail; - } - - u = pa_xmalloc(sizeof(struct userdata)); - m->userdata = u; - u->module = m; - u->core = c; - u->client = NULL; - u->pdispatch = NULL; - u->pstream = NULL; - u->server_name = NULL; -#ifdef TUNNEL_SINK - u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));; - u->sink = NULL; - u->requested_bytes = 0; -#else - u->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));; - u->source = NULL; -#endif - u->ctag = 1; - u->device_index = u->channel = PA_INVALID_INDEX; - u->host_latency = 0; - u->auth_cookie_in_property = 0; - u->time_event = NULL; - - if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0) - goto fail; - - if (!(u->server_name = pa_xstrdup(pa_modargs_get_value(ma, "server", NULL)))) { - pa_log(__FILE__": no server specified.\n"); - goto fail; - } - - ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": invalid sample format specification\n"); - goto fail; - } - - if (!(u->client = pa_socket_client_new_string(c->mainloop, u->server_name, PA_NATIVE_DEFAULT_PORT))) { - pa_log(__FILE__": failed to connect to server '%s'\n", u->server_name); - goto fail; - } - - if (!u->client) - goto fail; - - pa_socket_client_set_callback(u->client, on_connection, u); - -#ifdef TUNNEL_SINK - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { - pa_log(__FILE__": failed to create sink.\n"); - goto fail; - } - - u->sink->notify = sink_notify; - u->sink->get_latency = sink_get_latency; - u->sink->userdata = u; - u->sink->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->sink_name ? u->sink_name : "", u->sink_name ? "@" : "", u->server_name); - - pa_sink_set_owner(u->sink, m); -#else - if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL))) { - pa_log(__FILE__": failed to create source.\n"); - goto fail; - } - - u->source->get_latency = source_get_latency; - u->source->userdata = u; - u->source->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->source_name ? u->source_name : "", u->source_name ? "@" : "", u->server_name); - - pa_source_set_owner(u->source, m); -#endif - - pa_gettimeofday(&ntv); - ntv.tv_sec += LATENCY_INTERVAL; - u->time_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, u); - - pa_modargs_free(ma); - - return 0; - -fail: - pa__done(c, m); - - if (ma) - pa_modargs_free(ma); - return -1; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata* u; - assert(c && m); - - if (!(u = m->userdata)) - return; - - close_stuff(u); - - if (u->auth_cookie_in_property) - pa_authkey_prop_unref(c, PA_NATIVE_COOKIE_PROPERTY_NAME); - -#ifdef TUNNEL_SINK - pa_xfree(u->sink_name); -#else - pa_xfree(u->source_name); -#endif - pa_xfree(u->server_name); - - pa_xfree(u); -} - - diff --git a/polyp/module-waveout.c b/polyp/module-waveout.c deleted file mode 100644 index e9d9f12e..00000000 --- a/polyp/module-waveout.c +++ /dev/null @@ -1,581 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "sink.h" -#include "source.h" -#include "module.h" -#include "mainloop-api.h" -#include "modargs.h" -#include "sample-util.h" -#include "util.h" -#include "log.h" -#include "xmalloc.h" -#include "module-waveout-symdef.h" - -PA_MODULE_AUTHOR("Pierre Ossman") -PA_MODULE_DESCRIPTION("Windows waveOut Sink/Source") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= source_name= record= playback= format= channels= rate= fragments= fragment_size=") - -#define DEFAULT_SINK_NAME "wave_output" -#define DEFAULT_SOURCE_NAME "wave_input" - -struct userdata { - pa_sink *sink; - pa_source *source; - pa_core *core; - pa_time_event *event; - pa_defer_event *defer; - pa_usec_t poll_timeout; - - uint32_t fragments, fragment_size; - - uint32_t free_ofrags, free_ifrags; - - DWORD written_bytes; - - int cur_ohdr, cur_ihdr; - unsigned int oremain; - WAVEHDR *ohdrs, *ihdrs; - pa_memchunk silence; - - HWAVEOUT hwo; - HWAVEIN hwi; - pa_module *module; - - CRITICAL_SECTION crit; -}; - -static const char* const valid_modargs[] = { - "sink_name", - "source_name", - "record", - "playback", - "fragments", - "fragment_size", - "format", - "rate", - "channels", - NULL -}; - -static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, - (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + - (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0) + - (u->source ? pa_idxset_size(u->source->outputs) : 0)); -} - -static void do_write(struct userdata *u) -{ - uint32_t free_frags, remain; - pa_memchunk memchunk, *cur_chunk; - WAVEHDR *hdr; - MMRESULT res; - - if (!u->sink) - return; - - EnterCriticalSection(&u->crit); - - free_frags = u->free_ofrags; - u->free_ofrags = 0; - - LeaveCriticalSection(&u->crit); - - while (free_frags) { - hdr = &u->ohdrs[u->cur_ohdr]; - if (hdr->dwFlags & WHDR_PREPARED) - waveOutUnprepareHeader(u->hwo, hdr, sizeof(WAVEHDR)); - - remain = u->oremain; - while (remain) { - cur_chunk = &memchunk; - - if (pa_sink_render(u->sink, remain, cur_chunk) < 0) { - /* - * Don't fill with silence unless we're getting close to - * underflowing. - */ - if (free_frags > u->fragments/2) - cur_chunk = &u->silence; - else { - EnterCriticalSection(&u->crit); - - u->free_ofrags += free_frags; - - LeaveCriticalSection(&u->crit); - - u->oremain = remain; - return; - } - } - - assert(cur_chunk->memblock); - assert(cur_chunk->memblock->data); - assert(cur_chunk->length); - - memcpy(hdr->lpData + u->fragment_size - remain, - (char*)cur_chunk->memblock->data + cur_chunk->index, - (cur_chunk->length < remain)?cur_chunk->length:remain); - - remain -= (cur_chunk->length < remain)?cur_chunk->length:remain; - - if (cur_chunk != &u->silence) { - pa_memblock_unref(cur_chunk->memblock); - cur_chunk->memblock = NULL; - } - } - - res = waveOutPrepareHeader(u->hwo, hdr, sizeof(WAVEHDR)); - if (res != MMSYSERR_NOERROR) { - pa_log_error(__FILE__ ": ERROR: Unable to prepare waveOut block: %d\n", - res); - } - res = waveOutWrite(u->hwo, hdr, sizeof(WAVEHDR)); - if (res != MMSYSERR_NOERROR) { - pa_log_error(__FILE__ ": ERROR: Unable to write waveOut block: %d\n", - res); - } - - u->written_bytes += u->fragment_size; - - free_frags--; - u->cur_ohdr++; - u->cur_ohdr %= u->fragments; - u->oremain = u->fragment_size; - } -} - -static void do_read(struct userdata *u) -{ - uint32_t free_frags; - pa_memchunk memchunk; - WAVEHDR *hdr; - MMRESULT res; - - if (!u->source) - return; - - EnterCriticalSection(&u->crit); - - free_frags = u->free_ifrags; - u->free_ifrags = 0; - - LeaveCriticalSection(&u->crit); - - while (free_frags) { - hdr = &u->ihdrs[u->cur_ihdr]; - if (hdr->dwFlags & WHDR_PREPARED) - waveInUnprepareHeader(u->hwi, hdr, sizeof(WAVEHDR)); - - if (hdr->dwBytesRecorded) { - memchunk.memblock = pa_memblock_new(hdr->dwBytesRecorded, u->core->memblock_stat); - assert(memchunk.memblock); - - memcpy((char*)memchunk.memblock->data, hdr->lpData, hdr->dwBytesRecorded); - - memchunk.length = memchunk.memblock->length = hdr->dwBytesRecorded; - memchunk.index = 0; - - pa_source_post(u->source, &memchunk); - pa_memblock_unref(memchunk.memblock); - } - - res = waveInPrepareHeader(u->hwi, hdr, sizeof(WAVEHDR)); - if (res != MMSYSERR_NOERROR) { - pa_log_error(__FILE__ ": ERROR: Unable to prepare waveIn block: %d\n", - res); - } - res = waveInAddBuffer(u->hwi, hdr, sizeof(WAVEHDR)); - if (res != MMSYSERR_NOERROR) { - pa_log_error(__FILE__ ": ERROR: Unable to add waveIn block: %d\n", - res); - } - - free_frags--; - u->cur_ihdr++; - u->cur_ihdr %= u->fragments; - } -} - -static void poll_cb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) { - struct userdata *u = userdata; - struct timeval ntv; - - assert(u); - - update_usage(u); - - do_write(u); - do_read(u); - - pa_gettimeofday(&ntv); - pa_timeval_add(&ntv, u->poll_timeout); - - a->time_restart(e, &ntv); -} - -static void defer_cb(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { - struct userdata *u = userdata; - - assert(u); - - a->defer_enable(e, 0); - - do_write(u); - do_read(u); -} - -static void CALLBACK chunk_done_cb(HWAVEOUT hwo, UINT msg, DWORD_PTR inst, DWORD param1, DWORD param2) { - struct userdata *u = (struct userdata *)inst; - - if (msg != WOM_DONE) - return; - - EnterCriticalSection(&u->crit); - - u->free_ofrags++; - assert(u->free_ofrags <= u->fragments); - - LeaveCriticalSection(&u->crit); -} - -static void CALLBACK chunk_ready_cb(HWAVEIN hwi, UINT msg, DWORD_PTR inst, DWORD param1, DWORD param2) { - struct userdata *u = (struct userdata *)inst; - - if (msg != WIM_DATA) - return; - - EnterCriticalSection(&u->crit); - - u->free_ifrags++; - assert(u->free_ifrags <= u->fragments); - - LeaveCriticalSection(&u->crit); -} - -static pa_usec_t sink_get_latency_cb(pa_sink *s) { - struct userdata *u = s->userdata; - uint32_t free_frags; - MMTIME mmt; - assert(s && u && u->sink); - - memset(&mmt, 0, sizeof(mmt)); - mmt.wType = TIME_BYTES; - if (waveOutGetPosition(u->hwo, &mmt, sizeof(mmt)) == MMSYSERR_NOERROR) - return pa_bytes_to_usec(u->written_bytes - mmt.u.cb, &s->sample_spec); - else { - EnterCriticalSection(&u->crit); - - free_frags = u->free_ofrags; - - LeaveCriticalSection(&u->crit); - - return pa_bytes_to_usec((u->fragments - free_frags) * u->fragment_size, - &s->sample_spec); - } -} - -static pa_usec_t source_get_latency_cb(pa_source *s) { - pa_usec_t r = 0; - struct userdata *u = s->userdata; - uint32_t free_frags; - assert(s && u && u->sink); - - EnterCriticalSection(&u->crit); - - free_frags = u->free_ifrags; - - LeaveCriticalSection(&u->crit); - - r += pa_bytes_to_usec((free_frags + 1) * u->fragment_size, &s->sample_spec); - - fprintf(stderr, "Latency: %d us\n", (int)r); - - return r; -} - -static void notify_sink_cb(pa_sink *s) { - struct userdata *u = s->userdata; - assert(u); - - u->core->mainloop->defer_enable(u->defer, 1); -} - -static void notify_source_cb(pa_source *s) { - struct userdata *u = s->userdata; - assert(u); - - u->core->mainloop->defer_enable(u->defer, 1); -} - -static int ss_to_waveformat(pa_sample_spec *ss, LPWAVEFORMATEX wf) { - wf->wFormatTag = WAVE_FORMAT_PCM; - - if (ss->channels > 2) { - pa_log_error(__FILE__": ERROR: More than two channels not supported.\n"); - return -1; - } - - wf->nChannels = ss->channels; - - switch (ss->rate) { - case 8000: - case 11025: - case 22005: - case 44100: - break; - default: - pa_log_error(__FILE__": ERROR: Unsupported sample rate.\n"); - return -1; - } - - wf->nSamplesPerSec = ss->rate; - - if (ss->format == PA_SAMPLE_U8) - wf->wBitsPerSample = 8; - else if (ss->format == PA_SAMPLE_S16NE) - wf->wBitsPerSample = 16; - else { - pa_log_error(__FILE__": ERROR: Unsupported sample format.\n"); - return -1; - } - - wf->nBlockAlign = wf->nChannels * wf->wBitsPerSample/8; - wf->nAvgBytesPerSec = wf->nSamplesPerSec * wf->nBlockAlign; - - wf->cbSize = 0; - - return 0; -} - -int pa__init(pa_core *c, pa_module*m) { - struct userdata *u = NULL; - HWAVEOUT hwo = INVALID_HANDLE_VALUE; - HWAVEIN hwi = INVALID_HANDLE_VALUE; - WAVEFORMATEX wf; - int nfrags, frag_size; - int record = 1, playback = 1; - pa_sample_spec ss; - pa_modargs *ma = NULL; - unsigned int i; - struct timeval tv; - - assert(c && m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments.\n"); - goto fail; - } - - if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { - pa_log(__FILE__": record= and playback= expect boolean argument.\n"); - goto fail; - } - - if (!playback && !record) { - pa_log(__FILE__": neither playback nor record enabled for device.\n"); - goto fail; - } - - nfrags = 20; - frag_size = 1024; - if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { - pa_log(__FILE__": failed to parse fragments arguments\n"); - goto fail; - } - - ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": failed to parse sample specification\n"); - goto fail; - } - - if (ss_to_waveformat(&ss, &wf) < 0) - goto fail; - - u = pa_xmalloc(sizeof(struct userdata)); - - if (record) { - if (waveInOpen(&hwi, WAVE_MAPPER, &wf, (DWORD_PTR)chunk_ready_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) - goto fail; - if (waveInStart(hwi) != MMSYSERR_NOERROR) - goto fail; - pa_log_debug(__FILE__": Opened waveIn subsystem.\n"); - } - - if (playback) { - if (waveOutOpen(&hwo, WAVE_MAPPER, &wf, (DWORD_PTR)chunk_done_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) - goto fail; - pa_log_debug(__FILE__": Opened waveOut subsystem.\n"); - } - - InitializeCriticalSection(&u->crit); - - if (hwi != INVALID_HANDLE_VALUE) { - u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); - assert(u->source); - u->source->userdata = u; - u->source->notify = notify_source_cb; - u->source->get_latency = source_get_latency_cb; - pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Windows waveIn PCM"); - } else - u->source = NULL; - - if (hwo != INVALID_HANDLE_VALUE) { - u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); - assert(u->sink); - u->sink->notify = notify_sink_cb; - u->sink->get_latency = sink_get_latency_cb; - u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Windows waveOut PCM"); - } else - u->sink = NULL; - - assert(u->source || u->sink); - - u->core = c; - u->hwi = hwi; - u->hwo = hwo; - - u->fragments = nfrags; - u->free_ifrags = u->fragments; - u->free_ofrags = u->fragments; - u->fragment_size = frag_size - (frag_size % pa_frame_size(&ss)); - - u->written_bytes = 0; - - u->oremain = u->fragment_size; - - u->poll_timeout = pa_bytes_to_usec(u->fragments * u->fragment_size / 3, &ss); - - pa_gettimeofday(&tv); - pa_timeval_add(&tv, u->poll_timeout); - - u->event = c->mainloop->time_new(c->mainloop, &tv, poll_cb, u); - assert(u->event); - - u->defer = c->mainloop->defer_new(c->mainloop, defer_cb, u); - assert(u->defer); - c->mainloop->defer_enable(u->defer, 0); - - u->cur_ihdr = 0; - u->cur_ohdr = 0; - u->ihdrs = pa_xmalloc0(sizeof(WAVEHDR) * u->fragments); - assert(u->ihdrs); - u->ohdrs = pa_xmalloc0(sizeof(WAVEHDR) * u->fragments); - assert(u->ohdrs); - for (i = 0;i < u->fragments;i++) { - u->ihdrs[i].dwBufferLength = u->fragment_size; - u->ohdrs[i].dwBufferLength = u->fragment_size; - u->ihdrs[i].lpData = pa_xmalloc(u->fragment_size); - assert(u->ihdrs); - u->ohdrs[i].lpData = pa_xmalloc(u->fragment_size); - assert(u->ohdrs); - } - - u->silence.length = u->fragment_size; - u->silence.memblock = pa_memblock_new(u->silence.length, u->core->memblock_stat); - assert(u->silence.memblock); - pa_silence_memblock(u->silence.memblock, &ss); - u->silence.index = 0; - - u->module = m; - m->userdata = u; - - pa_modargs_free(ma); - - return 0; - -fail: - if (hwi != INVALID_HANDLE_VALUE) - waveInClose(hwi); - - if (hwo != INVALID_HANDLE_VALUE) - waveOutClose(hwo); - - if (u) - pa_xfree(u); - - if (ma) - pa_modargs_free(ma); - - return -1; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u; - unsigned int i; - - assert(c && m); - - if (!(u = m->userdata)) - return; - - if (u->event) - c->mainloop->time_free(u->event); - - if (u->defer) - c->mainloop->defer_free(u->defer); - - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - } - - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - } - - if (u->hwi != INVALID_HANDLE_VALUE) { - waveInReset(u->hwi); - waveInClose(u->hwi); - } - - if (u->hwo != INVALID_HANDLE_VALUE) { - waveOutReset(u->hwo); - waveOutClose(u->hwo); - } - - for (i = 0;i < u->fragments;i++) { - pa_xfree(u->ihdrs[i].lpData); - pa_xfree(u->ohdrs[i].lpData); - } - - pa_xfree(u->ihdrs); - pa_xfree(u->ohdrs); - - DeleteCriticalSection(&u->crit); - - pa_xfree(u); -} diff --git a/polyp/module-x11-bell.c b/polyp/module-x11-bell.c deleted file mode 100644 index 4fc4a60d..00000000 --- a/polyp/module-x11-bell.c +++ /dev/null @@ -1,172 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include -#include - -#include "module.h" -#include "sink.h" -#include "scache.h" -#include "modargs.h" -#include "xmalloc.h" -#include "namereg.h" -#include "log.h" -#include "x11wrap.h" -#include "module-x11-bell-symdef.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("X11 Bell interceptor") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink= sample= display=") - -struct userdata { - pa_core *core; - int xkb_event_base; - char *sink_name; - char *scache_item; - Display *display; - - pa_x11_wrapper *x11_wrapper; - pa_x11_client *x11_client; -}; - -static const char* const valid_modargs[] = { - "sink", - "sample", - "display", - NULL -}; - -static int ring_bell(struct userdata *u, int percent) { - pa_sink *s; - pa_cvolume cv; - assert(u); - - if (!(s = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": Invalid sink: %s\n", u->sink_name); - return -1; - } - - pa_scache_play_item(u->core, u->scache_item, s, pa_cvolume_set(&cv, PA_CHANNELS_MAX, percent*PA_VOLUME_NORM/100)); - return 0; -} - -static int x11_event_callback(pa_x11_wrapper *w, XEvent *e, void *userdata) { - XkbBellNotifyEvent *bne; - struct userdata *u = userdata; - assert(w && e && u && u->x11_wrapper == w); - - if (((XkbEvent*) e)->any.xkb_type != XkbBellNotify) - return 0; - - bne = (XkbBellNotifyEvent*) e; - - if (ring_bell(u, bne->percent) < 0) { - pa_log_info(__FILE__": Ringing bell failed, reverting to X11 device bell.\n"); - XkbForceDeviceBell(pa_x11_wrapper_get_display(w), bne->device, bne->bell_class, bne->bell_id, bne->percent); - } - - return 1; -} - -int pa__init(pa_core *c, pa_module*m) { - struct userdata *u = NULL; - pa_modargs *ma = NULL; - int major, minor; - unsigned int auto_ctrls, auto_values; - assert(c && m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); - goto fail; - } - - m->userdata = u = pa_xmalloc(sizeof(struct userdata)); - u->core = c; - u->scache_item = pa_xstrdup(pa_modargs_get_value(ma, "sample", "x11-bell")); - u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); - u->x11_client = NULL; - - if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL)))) - goto fail; - - u->display = pa_x11_wrapper_get_display(u->x11_wrapper); - - major = XkbMajorVersion; - minor = XkbMinorVersion; - - if (!XkbLibraryVersion(&major, &minor)) { - pa_log(__FILE__": XkbLibraryVersion() failed\n"); - goto fail; - } - - major = XkbMajorVersion; - minor = XkbMinorVersion; - - - if (!XkbQueryExtension(u->display, NULL, &u->xkb_event_base, NULL, &major, &minor)) { - pa_log(__FILE__": XkbQueryExtension() failed\n"); - goto fail; - } - - XkbSelectEvents(u->display, XkbUseCoreKbd, XkbBellNotifyMask, XkbBellNotifyMask); - auto_ctrls = auto_values = XkbAudibleBellMask; - XkbSetAutoResetControls(u->display, XkbAudibleBellMask, &auto_ctrls, &auto_values); - XkbChangeEnabledControls(u->display, XkbUseCoreKbd, XkbAudibleBellMask, 0); - - u->x11_client = pa_x11_client_new(u->x11_wrapper, x11_event_callback, u); - - pa_modargs_free(ma); - - return 0; - -fail: - if (ma) - pa_modargs_free(ma); - if (m->userdata) - pa__done(c, m); - return -1; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u = m->userdata; - assert(c && m && u); - - pa_xfree(u->scache_item); - pa_xfree(u->sink_name); - - if (u->x11_client) - pa_x11_client_free(u->x11_client); - - if (u->x11_wrapper) - pa_x11_wrapper_unref(u->x11_wrapper); - - pa_xfree(u); -} diff --git a/polyp/module-x11-publish.c b/polyp/module-x11-publish.c deleted file mode 100644 index 0116914f..00000000 --- a/polyp/module-x11-publish.c +++ /dev/null @@ -1,191 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include -#include - -#include "module.h" -#include "sink.h" -#include "scache.h" -#include "modargs.h" -#include "xmalloc.h" -#include "namereg.h" -#include "log.h" -#include "x11wrap.h" -#include "util.h" -#include "native-common.h" -#include "module-x11-publish-symdef.h" -#include "authkey-prop.h" -#include "authkey.h" -#include "x11prop.h" -#include "strlist.h" -#include "props.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("X11 Credential Publisher") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("display=") - -static const char* const valid_modargs[] = { - "display", - "sink", - "source", - "cookie", - NULL -}; - -struct userdata { - pa_core *core; - pa_x11_wrapper *x11_wrapper; - Display *display; - char *id; - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; - int auth_cookie_in_property; -}; - -static int load_key(struct userdata *u, const char*fn) { - assert(u); - - u->auth_cookie_in_property = 0; - - if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { - pa_log_debug(__FILE__": using already loaded auth cookie.\n"); - pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); - u->auth_cookie_in_property = 1; - return 0; - } - - if (!fn) - fn = PA_NATIVE_COOKIE_FILE; - - if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) - return -1; - - pa_log_debug(__FILE__": loading cookie from disk.\n"); - - if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) - u->auth_cookie_in_property = 1; - - return 0; -} - -int pa__init(pa_core *c, pa_module*m) { - struct userdata *u; - pa_modargs *ma = NULL; - char hn[256], un[128]; - char hx[PA_NATIVE_COOKIE_LENGTH*2+1]; - const char *t; - char *s; - pa_strlist *l; - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); - goto fail; - } - - m->userdata = u = pa_xmalloc(sizeof(struct userdata)); - u->core = c; - u->id = NULL; - u->auth_cookie_in_property = 0; - - if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0) - goto fail; - - if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL)))) - goto fail; - - u->display = pa_x11_wrapper_get_display(u->x11_wrapper); - - if (!(l = pa_property_get(c, PA_NATIVE_SERVER_PROPERTY_NAME))) - goto fail; - - s = pa_strlist_tostring(l); - pa_x11_set_prop(u->display, "POLYP_SERVER", s); - pa_xfree(s); - - if (!pa_get_fqdn(hn, sizeof(hn)) || !pa_get_user_name(un, sizeof(un))) - goto fail; - - u->id = pa_sprintf_malloc("%s@%s/%u", un, hn, (unsigned) getpid()); - pa_x11_set_prop(u->display, "POLYP_ID", u->id); - - if ((t = pa_modargs_get_value(ma, "source", NULL))) - pa_x11_set_prop(u->display, "POLYP_SOURCE", t); - - if ((t = pa_modargs_get_value(ma, "sink", NULL))) - pa_x11_set_prop(u->display, "POLYP_SINK", t); - - pa_x11_set_prop(u->display, "POLYP_COOKIE", pa_hexstr(u->auth_cookie, sizeof(u->auth_cookie), hx, sizeof(hx))); - - pa_modargs_free(ma); - return 0; - -fail: - if (ma) - pa_modargs_free(ma); - - pa__done(c, m); - return -1; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata*u; - assert(c && m); - - if (!(u = m->userdata)) - return; - - if (u->x11_wrapper) { - char t[256]; - - /* Yes, here is a race condition */ - if (!pa_x11_get_prop(u->display, "POLYP_ID", t, sizeof(t)) || strcmp(t, u->id)) - pa_log("WARNING: Polypaudio information vanished from X11!\n"); - else { - pa_x11_del_prop(u->display, "POLYP_ID"); - pa_x11_del_prop(u->display, "POLYP_SERVER"); - pa_x11_del_prop(u->display, "POLYP_SINK"); - pa_x11_del_prop(u->display, "POLYP_SOURCE"); - pa_x11_del_prop(u->display, "POLYP_COOKIE"); - XSync(u->display, False); - } - } - - if (u->x11_wrapper) - pa_x11_wrapper_unref(u->x11_wrapper); - - if (u->auth_cookie_in_property) - pa_authkey_prop_unref(c, PA_NATIVE_COOKIE_PROPERTY_NAME); - - pa_xfree(u->id); - pa_xfree(u); -} - diff --git a/polyp/module-zeroconf-publish.c b/polyp/module-zeroconf-publish.c deleted file mode 100644 index 7e0a2764..00000000 --- a/polyp/module-zeroconf-publish.c +++ /dev/null @@ -1,507 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "module-zeroconf-publish-symdef.h" -#include "howl-wrap.h" -#include "xmalloc.h" -#include "autoload.h" -#include "sink.h" -#include "source.h" -#include "native-common.h" -#include "util.h" -#include "log.h" -#include "subscribe.h" -#include "dynarray.h" -#include "endianmacros.h" -#include "modargs.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Publisher") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("port=") - -#define SERVICE_NAME_SINK "_polypaudio-sink._tcp" -#define SERVICE_NAME_SOURCE "_polypaudio-source._tcp" -#define SERVICE_NAME_SERVER "_polypaudio-server._tcp" - -static const char* const valid_modargs[] = { - "port", - NULL -}; - -struct service { - sw_discovery_oid oid; - char *name; - int published; /* 0 -> not yet registered, 1 -> registered with data from real device, 2 -> registered with data from autoload device */ - - struct { - int valid; - pa_namereg_type type; - uint32_t index; - } loaded; - - struct { - int valid; - pa_namereg_type type; - uint32_t index; - } autoload; -}; - -struct userdata { - pa_core *core; - pa_howl_wrapper *howl_wrapper; - pa_hashmap *services; - pa_dynarray *sink_dynarray, *source_dynarray, *autoload_dynarray; - pa_subscription *subscription; - - uint16_t port; - sw_discovery_oid server_oid; -}; - -static sw_result publish_reply(sw_discovery discovery, sw_discovery_publish_status status, sw_discovery_oid oid, sw_opaque extra) { - return SW_OKAY; -} - -static void get_service_data(struct userdata *u, struct service *s, pa_sample_spec *ret_ss, char **ret_description, pa_typeid_t *ret_typeid) { - assert(u && s && s->loaded.valid && ret_ss && ret_description && ret_typeid); - - if (s->loaded.type == PA_NAMEREG_SINK) { - pa_sink *sink = pa_idxset_get_by_index(u->core->sinks, s->loaded.index); - assert(sink); - *ret_ss = sink->sample_spec; - *ret_description = sink->description; - *ret_typeid = sink->typeid; - } else if (s->loaded.type == PA_NAMEREG_SOURCE) { - pa_source *source = pa_idxset_get_by_index(u->core->sources, s->loaded.index); - assert(source); - *ret_ss = source->sample_spec; - *ret_description = source->description; - *ret_typeid = source->typeid; - } else - assert(0); -} - -static void txt_record_server_data(pa_core *c, sw_text_record t) { - char s[256]; - assert(c); - - sw_text_record_add_key_and_string_value(t, "server-version", PACKAGE_NAME" "PACKAGE_VERSION); - sw_text_record_add_key_and_string_value(t, "user-name", pa_get_user_name(s, sizeof(s))); - sw_text_record_add_key_and_string_value(t, "fqdn", pa_get_fqdn(s, sizeof(s))); - snprintf(s, sizeof(s), "0x%08x", c->cookie); - sw_text_record_add_key_and_string_value(t, "cookie", s); -} - -static int publish_service(struct userdata *u, struct service *s) { - char t[256]; - char hn[256]; - int r = -1; - sw_text_record txt; - int free_txt = 0; - assert(u && s); - - if ((s->published == 1 && s->loaded.valid) || - (s->published == 2 && s->autoload.valid && !s->loaded.valid)) - return 0; - - if (s->published) { - sw_discovery_cancel(pa_howl_wrapper_get_discovery(u->howl_wrapper), s->oid); - s->published = 0; - } - - snprintf(t, sizeof(t), "Networked Audio Device %s on %s", s->name, pa_get_host_name(hn, sizeof(hn))); - - if (sw_text_record_init(&txt) != SW_OKAY) { - pa_log(__FILE__": sw_text_record_init() failed\n"); - goto finish; - } - free_txt = 1; - - sw_text_record_add_key_and_string_value(txt, "device", s->name); - - txt_record_server_data(u->core, txt); - - if (s->loaded.valid) { - char z[64], *description; - pa_typeid_t typeid; - pa_sample_spec ss; - - get_service_data(u, s, &ss, &description, &typeid); - - snprintf(z, sizeof(z), "%u", ss.rate); - sw_text_record_add_key_and_string_value(txt, "rate", z); - snprintf(z, sizeof(z), "%u", ss.channels); - sw_text_record_add_key_and_string_value(txt, "channels", z); - sw_text_record_add_key_and_string_value(txt, "format", pa_sample_format_to_string(ss.format)); - - sw_text_record_add_key_and_string_value(txt, "description", description); - - snprintf(z, sizeof(z), "0x%8x", typeid); - sw_text_record_add_key_and_string_value(txt, "typeid", z); - - - if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t, - s->loaded.type == PA_NAMEREG_SINK ? SERVICE_NAME_SINK : SERVICE_NAME_SOURCE, - NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt), - publish_reply, s, &s->oid) != SW_OKAY) { - pa_log(__FILE__": failed to register sink on zeroconf.\n"); - goto finish; - } - - s->published = 1; - } else if (s->autoload.valid) { - - if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t, - s->autoload.type == PA_NAMEREG_SINK ? SERVICE_NAME_SINK : SERVICE_NAME_SOURCE, - NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt), - publish_reply, s, &s->oid) != SW_OKAY) { - pa_log(__FILE__": failed to register sink on zeroconf.\n"); - goto finish; - } - - s->published = 2; - } - - r = 0; - -finish: - - if (!s->published) { - /* Remove this service */ - pa_hashmap_remove(u->services, s->name); - pa_xfree(s->name); - pa_xfree(s); - } - - if (free_txt) - sw_text_record_fina(txt); - - return r; -} - -struct service *get_service(struct userdata *u, const char *name) { - struct service *s; - - if ((s = pa_hashmap_get(u->services, name))) - return s; - - s = pa_xmalloc(sizeof(struct service)); - s->published = 0; - s->name = pa_xstrdup(name); - s->loaded.valid = s->autoload.valid = 0; - - pa_hashmap_put(u->services, s->name, s); - - return s; -} - -static int publish_sink(struct userdata *u, pa_sink *s) { - struct service *svc; - assert(u && s); - - svc = get_service(u, s->name); - if (svc->loaded.valid) - return 0; - - svc->loaded.valid = 1; - svc->loaded.type = PA_NAMEREG_SINK; - svc->loaded.index = s->index; - - pa_dynarray_put(u->sink_dynarray, s->index, svc); - - return publish_service(u, svc); -} - -static int publish_source(struct userdata *u, pa_source *s) { - struct service *svc; - assert(u && s); - - svc = get_service(u, s->name); - if (svc->loaded.valid) - return 0; - - svc->loaded.valid = 1; - svc->loaded.type = PA_NAMEREG_SOURCE; - svc->loaded.index = s->index; - - pa_dynarray_put(u->source_dynarray, s->index, svc); - - return publish_service(u, svc); -} - -static int publish_autoload(struct userdata *u, pa_autoload_entry *s) { - struct service *svc; - assert(u && s); - - svc = get_service(u, s->name); - if (svc->autoload.valid) - return 0; - - svc->autoload.valid = 1; - svc->autoload.type = s->type; - svc->autoload.index = s->index; - - pa_dynarray_put(u->autoload_dynarray, s->index, svc); - - return publish_service(u, svc); -} - -static int remove_sink(struct userdata *u, uint32_t index) { - struct service *svc; - assert(u && index != PA_INVALID_INDEX); - - if (!(svc = pa_dynarray_get(u->sink_dynarray, index))) - return 0; - - if (!svc->loaded.valid || svc->loaded.type != PA_NAMEREG_SINK) - return 0; - - svc->loaded.valid = 0; - pa_dynarray_put(u->sink_dynarray, index, NULL); - - return publish_service(u, svc); -} - -static int remove_source(struct userdata *u, uint32_t index) { - struct service *svc; - assert(u && index != PA_INVALID_INDEX); - - if (!(svc = pa_dynarray_get(u->source_dynarray, index))) - return 0; - - if (!svc->loaded.valid || svc->loaded.type != PA_NAMEREG_SOURCE) - return 0; - - svc->loaded.valid = 0; - pa_dynarray_put(u->source_dynarray, index, NULL); - - return publish_service(u, svc); -} - -static int remove_autoload(struct userdata *u, uint32_t index) { - struct service *svc; - assert(u && index != PA_INVALID_INDEX); - - if (!(svc = pa_dynarray_get(u->autoload_dynarray, index))) - return 0; - - if (!svc->autoload.valid) - return 0; - - svc->autoload.valid = 0; - pa_dynarray_put(u->autoload_dynarray, index, NULL); - - return publish_service(u, svc); -} - -static void subscribe_callback(pa_core *c, pa_subscription_event_type t, uint32_t index, void *userdata) { - struct userdata *u = userdata; - assert(u && c); - - switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) - case PA_SUBSCRIPTION_EVENT_SINK: { - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { - pa_sink *sink; - - if ((sink = pa_idxset_get_by_index(c->sinks, index))) { - if (publish_sink(u, sink) < 0) - goto fail; - } - } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - if (remove_sink(u, index) < 0) - goto fail; - } - - break; - - case PA_SUBSCRIPTION_EVENT_SOURCE: - - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { - pa_source *source; - - if ((source = pa_idxset_get_by_index(c->sources, index))) { - if (publish_source(u, source) < 0) - goto fail; - } - } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - if (remove_source(u, index) < 0) - goto fail; - } - - break; - - case PA_SUBSCRIPTION_EVENT_AUTOLOAD: - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { - pa_autoload_entry *autoload; - - if ((autoload = pa_idxset_get_by_index(c->autoload_idxset, index))) { - if (publish_autoload(u, autoload) < 0) - goto fail; - } - } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - if (remove_autoload(u, index) < 0) - goto fail; - } - - break; - } - - return; - -fail: - if (u->subscription) { - pa_subscription_free(u->subscription); - u->subscription = NULL; - } -} - -int pa__init(pa_core *c, pa_module*m) { - struct userdata *u; - uint32_t index, port = PA_NATIVE_DEFAULT_PORT; - pa_sink *sink; - pa_source *source; - pa_autoload_entry *autoload; - pa_modargs *ma = NULL; - char t[256], hn[256]; - int free_txt = 0; - sw_text_record txt; - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments.\n"); - goto fail; - } - - if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port == 0 || port >= 0xFFFF) { - pa_log(__FILE__": invalid port specified.\n"); - goto fail; - } - - m->userdata = u = pa_xmalloc(sizeof(struct userdata)); - u->core = c; - u->port = (uint16_t) port; - - if (!(u->howl_wrapper = pa_howl_wrapper_get(c))) - goto fail; - - u->services = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - u->sink_dynarray = pa_dynarray_new(); - u->source_dynarray = pa_dynarray_new(); - u->autoload_dynarray = pa_dynarray_new(); - - u->subscription = pa_subscription_new(c, - PA_SUBSCRIPTION_MASK_SINK| - PA_SUBSCRIPTION_MASK_SOURCE| - PA_SUBSCRIPTION_MASK_AUTOLOAD, subscribe_callback, u); - - for (sink = pa_idxset_first(c->sinks, &index); sink; sink = pa_idxset_next(c->sinks, &index)) - if (publish_sink(u, sink) < 0) - goto fail; - - for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) - if (publish_source(u, source) < 0) - goto fail; - - if (c->autoload_idxset) - for (autoload = pa_idxset_first(c->autoload_idxset, &index); autoload; autoload = pa_idxset_next(c->autoload_idxset, &index)) - if (publish_autoload(u, autoload) < 0) - goto fail; - - snprintf(t, sizeof(t), "Networked Audio Server on %s", pa_get_host_name(hn, sizeof(hn))); - - if (sw_text_record_init(&txt) != SW_OKAY) { - pa_log(__FILE__": sw_text_record_init() failed\n"); - goto fail; - } - free_txt = 1; - - txt_record_server_data(u->core, txt); - - if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t, - SERVICE_NAME_SERVER, - NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt), - publish_reply, u, &u->server_oid) != SW_OKAY) { - pa_log(__FILE__": failed to register server on zeroconf.\n"); - goto fail; - } - - sw_text_record_fina(txt); - pa_modargs_free(ma); - - return 0; - -fail: - pa__done(c, m); - - if (ma) - pa_modargs_free(ma); - - if (free_txt) - sw_text_record_fina(txt); - - return -1; -} - -static void service_free(void *p, void *userdata) { - struct service *s = p; - struct userdata *u = userdata; - assert(s && u); - sw_discovery_cancel(pa_howl_wrapper_get_discovery(u->howl_wrapper), s->oid); - pa_xfree(s->name); - pa_xfree(s); -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata*u; - assert(c && m); - - if (!(u = m->userdata)) - return; - - if (u->services) - pa_hashmap_free(u->services, service_free, u); - - if (u->sink_dynarray) - pa_dynarray_free(u->sink_dynarray, NULL, NULL); - if (u->source_dynarray) - pa_dynarray_free(u->source_dynarray, NULL, NULL); - if (u->autoload_dynarray) - pa_dynarray_free(u->autoload_dynarray, NULL, NULL); - - if (u->subscription) - pa_subscription_free(u->subscription); - - if (u->howl_wrapper) - pa_howl_wrapper_unref(u->howl_wrapper); - - - pa_xfree(u); -} - diff --git a/polyp/module.c b/polyp/module.c deleted file mode 100644 index 499ea299..00000000 --- a/polyp/module.c +++ /dev/null @@ -1,275 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "module.h" -#include "xmalloc.h" -#include "subscribe.h" -#include "log.h" -#include "util.h" - -#define PA_SYMBOL_INIT "pa__init" -#define PA_SYMBOL_DONE "pa__done" - -#define UNLOAD_POLL_TIME 2 - -static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - pa_core *c = userdata; - struct timeval ntv; - assert(c && c->mainloop == m && c->module_auto_unload_event == e); - - pa_module_unload_unused(c); - - pa_gettimeofday(&ntv); - ntv.tv_sec += UNLOAD_POLL_TIME; - m->time_restart(e, &ntv); -} - -pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { - pa_module *m = NULL; - int r; - - assert(c && name); - - if (c->disallow_module_loading) - goto fail; - - m = pa_xmalloc(sizeof(pa_module)); - - m->name = pa_xstrdup(name); - m->argument = pa_xstrdup(argument); - - if (!(m->dl = lt_dlopenext(name))) { - pa_log(__FILE__": Failed to open module \"%s\": %s\n", name, lt_dlerror()); - goto fail; - } - - if (!(m->init = (int (*)(pa_core *_c, pa_module*_m)) lt_dlsym(m->dl, PA_SYMBOL_INIT))) { - pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.\n", name); - goto fail; - } - - if (!(m->done = (void (*)(pa_core *_c, pa_module*_m)) lt_dlsym(m->dl, PA_SYMBOL_DONE))) { - pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_DONE"\" not found.\n", name); - goto fail; - } - - m->userdata = NULL; - m->core = c; - m->n_used = -1; - m->auto_unload = 0; - m->unload_requested = 0; - - assert(m->init); - if (m->init(c, m) < 0) { - pa_log_error(__FILE__": Failed to load module \"%s\" (argument: \"%s\"): initialization failed.\n", name, argument ? argument : ""); - goto fail; - } - - if (!c->modules) - c->modules = pa_idxset_new(NULL, NULL); - - if (!c->module_auto_unload_event) { - struct timeval ntv; - pa_gettimeofday(&ntv); - ntv.tv_sec += UNLOAD_POLL_TIME; - c->module_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); - } - assert(c->module_auto_unload_event); - - assert(c->modules); - r = pa_idxset_put(c->modules, m, &m->index); - assert(r >= 0 && m->index != PA_IDXSET_INVALID); - - pa_log_info(__FILE__": Loaded \"%s\" (index: #%u; argument: \"%s\").\n", m->name, m->index, m->argument ? m->argument : ""); - - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_NEW, m->index); - - return m; - -fail: - - if (m) { - pa_xfree(m->argument); - pa_xfree(m->name); - - if (m->dl) - lt_dlclose(m->dl); - - pa_xfree(m); - } - - return NULL; -} - -static void pa_module_free(pa_module *m) { - assert(m && m->done && m->core); - - if (m->core->disallow_module_loading) - return; - - pa_log_info(__FILE__": Unloading \"%s\" (index: #%u).\n", m->name, m->index); - - m->done(m->core, m); - - lt_dlclose(m->dl); - - pa_log_info(__FILE__": Unloaded \"%s\" (index: #%u).\n", m->name, m->index); - - pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_REMOVE, m->index); - - pa_xfree(m->name); - pa_xfree(m->argument); - pa_xfree(m); -} - -void pa_module_unload(pa_core *c, pa_module *m) { - assert(c && m); - - assert(c->modules); - if (!(m = pa_idxset_remove_by_data(c->modules, m, NULL))) - return; - - pa_module_free(m); -} - -void pa_module_unload_by_index(pa_core *c, uint32_t idx) { - pa_module *m; - assert(c && idx != PA_IDXSET_INVALID); - - assert(c->modules); - if (!(m = pa_idxset_remove_by_index(c->modules, idx))) - return; - - pa_module_free(m); -} - -static void free_callback(void *p, PA_GCC_UNUSED void *userdata) { - pa_module *m = p; - assert(m); - pa_module_free(m); -} - -void pa_module_unload_all(pa_core *c) { - assert(c); - - if (!c->modules) - return; - - pa_idxset_free(c->modules, free_callback, NULL); - c->modules = NULL; - - if (c->module_auto_unload_event) { - c->mainloop->time_free(c->module_auto_unload_event); - c->module_auto_unload_event = NULL; - } - - if (c->module_defer_unload_event) { - c->mainloop->defer_free(c->module_defer_unload_event); - c->module_defer_unload_event = NULL; - } -} - -static int unused_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void *userdata) { - pa_module *m = p; - time_t *now = userdata; - assert(p && del && now); - - if (m->n_used == 0 && m->auto_unload && m->last_used_time+m->core->module_idle_time <= *now) { - pa_module_free(m); - *del = 1; - } - - return 0; -} - -void pa_module_unload_unused(pa_core *c) { - time_t now; - assert(c); - - if (!c->modules) - return; - - time(&now); - pa_idxset_foreach(c->modules, unused_callback, &now); -} - -static int unload_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, PA_GCC_UNUSED void *userdata) { - pa_module *m = p; - assert(m); - - if (m->unload_requested) { - pa_module_free(m); - *del = 1; - } - - return 0; -} - -static void defer_cb(pa_mainloop_api*api, pa_defer_event *e, void *userdata) { - pa_core *core = userdata; - api->defer_enable(e, 0); - - if (!core->modules) - return; - - pa_idxset_foreach(core->modules, unload_callback, NULL); - -} - -void pa_module_unload_request(pa_module *m) { - assert(m); - - m->unload_requested = 1; - - if (!m->core->module_defer_unload_event) - m->core->module_defer_unload_event = m->core->mainloop->defer_new(m->core->mainloop, defer_cb, m->core); - - m->core->mainloop->defer_enable(m->core->module_defer_unload_event, 1); -} - -void pa_module_set_used(pa_module*m, int used) { - assert(m); - - if (m->n_used != used) - pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_CHANGE, m->index); - - if (m->n_used != used && used == 0) - time(&m->last_used_time); - - m->n_used = used; -} - -pa_modinfo *pa_module_get_info(pa_module *m) { - assert(m); - - return pa_modinfo_get_by_handle(m->dl); -} diff --git a/polyp/module.h b/polyp/module.h deleted file mode 100644 index 6f137c15..00000000 --- a/polyp/module.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef foomodulehfoo -#define foomodulehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -#include "core.h" -#include "modinfo.h" - -typedef struct pa_module pa_module; - -struct pa_module { - pa_core *core; - char *name, *argument; - uint32_t index; - - lt_dlhandle dl; - - int (*init)(pa_core *c, pa_module*m); - void (*done)(pa_core *c, pa_module*m); - - void *userdata; - - int n_used; - int auto_unload; - time_t last_used_time; - - int unload_requested; -}; - -pa_module* pa_module_load(pa_core *c, const char *name, const char*argument); -void pa_module_unload(pa_core *c, pa_module *m); -void pa_module_unload_by_index(pa_core *c, uint32_t idx); - -void pa_module_unload_all(pa_core *c); -void pa_module_unload_unused(pa_core *c); - -void pa_module_unload_request(pa_module *m); - -void pa_module_set_used(pa_module*m, int used); - -#define PA_MODULE_AUTHOR(s) const char * pa__get_author(void) { return s; } -#define PA_MODULE_DESCRIPTION(s) const char * pa__get_description(void) { return s; } -#define PA_MODULE_USAGE(s) const char * pa__get_usage(void) { return s; } -#define PA_MODULE_VERSION(s) const char * pa__get_version(void) { return s; } - -pa_modinfo *pa_module_get_info(pa_module *m); - -#endif diff --git a/polyp/namereg.c b/polyp/namereg.c deleted file mode 100644 index 07fb485c..00000000 --- a/polyp/namereg.c +++ /dev/null @@ -1,212 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "namereg.h" -#include "autoload.h" -#include "source.h" -#include "sink.h" -#include "xmalloc.h" -#include "subscribe.h" -#include "util.h" - -struct namereg_entry { - pa_namereg_type_t type; - char *name; - void *data; -}; - -void pa_namereg_free(pa_core *c) { - assert(c); - if (!c->namereg) - return; - assert(pa_hashmap_size(c->namereg) == 0); - pa_hashmap_free(c->namereg, NULL, NULL); -} - -const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, int fail) { - struct namereg_entry *e; - char *n = NULL; - int r; - - assert(c && name && data); - - if (!c->namereg) { - c->namereg = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - assert(c->namereg); - } - - if ((e = pa_hashmap_get(c->namereg, name)) && fail) - return NULL; - - if (!e) - n = pa_xstrdup(name); - else { - unsigned i; - size_t l = strlen(name); - n = pa_xmalloc(l+3); - - for (i = 1; i <= 99; i++) { - snprintf(n, l+2, "%s%u", name, i); - - if (!(e = pa_hashmap_get(c->namereg, n))) - break; - } - - if (e) { - pa_xfree(n); - return NULL; - } - } - - assert(n); - e = pa_xmalloc(sizeof(struct namereg_entry)); - e->type = type; - e->name = n; - e->data = data; - - r = pa_hashmap_put(c->namereg, e->name, e); - assert (r >= 0); - - return e->name; - -} - -void pa_namereg_unregister(pa_core *c, const char *name) { - struct namereg_entry *e; - assert(c && name); - - e = pa_hashmap_remove(c->namereg, name); - assert(e); - - pa_xfree(e->name); - pa_xfree(e); -} - -void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int autoload) { - struct namereg_entry *e; - uint32_t idx; - assert(c); - - if (!name) { - if (type == PA_NAMEREG_SOURCE) - name = pa_namereg_get_default_source_name(c); - else if (type == PA_NAMEREG_SINK) - name = pa_namereg_get_default_sink_name(c); - } - - if (!name) - return NULL; - - if (c->namereg && (e = pa_hashmap_get(c->namereg, name))) - if (e->type == e->type) - return e->data; - - if (pa_atou(name, &idx) < 0) { - - if (autoload) { - pa_autoload_request(c, name, type); - - if (c->namereg && (e = pa_hashmap_get(c->namereg, name))) - if (e->type == e->type) - return e->data; - } - - return NULL; - } - - if (type == PA_NAMEREG_SINK) - return pa_idxset_get_by_index(c->sinks, idx); - else if (type == PA_NAMEREG_SOURCE) - return pa_idxset_get_by_index(c->sources, idx); - else if (type == PA_NAMEREG_SAMPLE && c->scache) - return pa_idxset_get_by_index(c->scache, idx); - - return NULL; -} - -void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type) { - char **s; - assert(c && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); - - s = type == PA_NAMEREG_SINK ? &c->default_sink_name : &c->default_source_name; - assert(s); - - if (!name && !*s) - return; - - if (name && *s && !strcmp(name, *s)) - return; - - pa_xfree(*s); - *s = pa_xstrdup(name); - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); -} - -const char *pa_namereg_get_default_sink_name(pa_core *c) { - pa_sink *s; - assert(c); - - if (c->default_sink_name) - return c->default_sink_name; - - if ((s = pa_idxset_first(c->sinks, NULL))) - pa_namereg_set_default(c, s->name, PA_NAMEREG_SINK); - - if (c->default_sink_name) - return c->default_sink_name; - - return NULL; -} - -const char *pa_namereg_get_default_source_name(pa_core *c) { - pa_source *s; - uint32_t idx; - - assert(c); - - if (c->default_source_name) - return c->default_source_name; - - for (s = pa_idxset_first(c->sources, &idx); s; s = pa_idxset_next(c->sources, &idx)) - if (!s->monitor_of) { - pa_namereg_set_default(c, s->name, PA_NAMEREG_SOURCE); - break; - } - - if (!c->default_source_name) - if ((s = pa_idxset_first(c->sources, NULL))) - pa_namereg_set_default(c, s->name, PA_NAMEREG_SOURCE); - - if (c->default_source_name) - return c->default_source_name; - - return NULL; -} diff --git a/polyp/namereg.h b/polyp/namereg.h deleted file mode 100644 index 961fd44b..00000000 --- a/polyp/namereg.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef foonamereghfoo -#define foonamereghfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "core.h" - -typedef enum pa_namereg_type { - PA_NAMEREG_SINK, - PA_NAMEREG_SOURCE, - PA_NAMEREG_SAMPLE -} pa_namereg_type_t; - -void pa_namereg_free(pa_core *c); - -const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, int fail); -void pa_namereg_unregister(pa_core *c, const char *name); -void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int autoload); -void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type); - -const char *pa_namereg_get_default_sink_name(pa_core *c); -const char *pa_namereg_get_default_source_name(pa_core *c); - -#endif diff --git a/polyp/native-common.h b/polyp/native-common.h deleted file mode 100644 index 569f3b71..00000000 --- a/polyp/native-common.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef foonativecommonhfoo -#define foonativecommonhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "cdecl.h" -#include "polyplib-def.h" - -PA_C_DECL_BEGIN - -enum { - PA_COMMAND_ERROR, - PA_COMMAND_TIMEOUT, /* pseudo command */ - PA_COMMAND_REPLY, - PA_COMMAND_CREATE_PLAYBACK_STREAM, - PA_COMMAND_DELETE_PLAYBACK_STREAM, - PA_COMMAND_CREATE_RECORD_STREAM, - PA_COMMAND_DELETE_RECORD_STREAM, - PA_COMMAND_EXIT, - PA_COMMAND_REQUEST, - PA_COMMAND_AUTH, - PA_COMMAND_SET_CLIENT_NAME, - PA_COMMAND_LOOKUP_SINK, - PA_COMMAND_LOOKUP_SOURCE, - PA_COMMAND_DRAIN_PLAYBACK_STREAM, - PA_COMMAND_PLAYBACK_STREAM_KILLED, - PA_COMMAND_RECORD_STREAM_KILLED, - PA_COMMAND_STAT, - PA_COMMAND_GET_PLAYBACK_LATENCY, - PA_COMMAND_CREATE_UPLOAD_STREAM, - PA_COMMAND_DELETE_UPLOAD_STREAM, - PA_COMMAND_FINISH_UPLOAD_STREAM, - PA_COMMAND_PLAY_SAMPLE, - PA_COMMAND_REMOVE_SAMPLE, - - PA_COMMAND_GET_SERVER_INFO, - PA_COMMAND_GET_SINK_INFO, - PA_COMMAND_GET_SINK_INFO_LIST, - PA_COMMAND_GET_SOURCE_INFO, - PA_COMMAND_GET_SOURCE_INFO_LIST, - PA_COMMAND_GET_MODULE_INFO, - PA_COMMAND_GET_MODULE_INFO_LIST, - PA_COMMAND_GET_CLIENT_INFO, - PA_COMMAND_GET_CLIENT_INFO_LIST, - PA_COMMAND_GET_SINK_INPUT_INFO, - PA_COMMAND_GET_SINK_INPUT_INFO_LIST, - PA_COMMAND_GET_SOURCE_OUTPUT_INFO, - PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, - PA_COMMAND_GET_SAMPLE_INFO, - PA_COMMAND_GET_SAMPLE_INFO_LIST, - PA_COMMAND_SUBSCRIBE, - PA_COMMAND_SUBSCRIBE_EVENT, - - PA_COMMAND_SET_SINK_VOLUME, - PA_COMMAND_SET_SINK_INPUT_VOLUME, - PA_COMMAND_CORK_PLAYBACK_STREAM, - PA_COMMAND_FLUSH_PLAYBACK_STREAM, - PA_COMMAND_TRIGGER_PLAYBACK_STREAM, - - PA_COMMAND_SET_DEFAULT_SINK, - PA_COMMAND_SET_DEFAULT_SOURCE, - - PA_COMMAND_SET_PLAYBACK_STREAM_NAME, - PA_COMMAND_SET_RECORD_STREAM_NAME, - - PA_COMMAND_KILL_CLIENT, - PA_COMMAND_KILL_SINK_INPUT, - PA_COMMAND_KILL_SOURCE_OUTPUT, - PA_COMMAND_LOAD_MODULE, - PA_COMMAND_UNLOAD_MODULE, - PA_COMMAND_ADD_AUTOLOAD, - PA_COMMAND_REMOVE_AUTOLOAD, - PA_COMMAND_GET_AUTOLOAD_INFO, - PA_COMMAND_GET_AUTOLOAD_INFO_LIST, - PA_COMMAND_GET_RECORD_LATENCY, - PA_COMMAND_CORK_RECORD_STREAM, - PA_COMMAND_FLUSH_RECORD_STREAM, - PA_COMMAND_PREBUF_PLAYBACK_STREAM, - PA_COMMAND_MAX -}; - -#define PA_NATIVE_COOKIE_LENGTH 256 -#define PA_NATIVE_COOKIE_FILE ".polypaudio-cookie" - -#define PA_NATIVE_DEFAULT_PORT 4713 - -#define PA_NATIVE_COOKIE_PROPERTY_NAME "protocol-native-cookie" -#define PA_NATIVE_SERVER_PROPERTY_NAME "protocol-native-server" - -#define PA_NATIVE_DEFAULT_UNIX_SOCKET "native" - - -PA_C_DECL_END - -#endif diff --git a/polyp/oss-util.c b/polyp/oss-util.c deleted file mode 100644 index ae6772fd..00000000 --- a/polyp/oss-util.c +++ /dev/null @@ -1,167 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "oss-util.h" -#include "util.h" -#include "log.h" - -int pa_oss_open(const char *device, int *mode, int* pcaps) { - int fd = -1; - assert(device && mode && (*mode == O_RDWR || *mode == O_RDONLY || *mode == O_WRONLY)); - - if (*mode == O_RDWR) { - if ((fd = open(device, O_RDWR|O_NDELAY)) >= 0) { - int dcaps, *tcaps; - ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0); - - tcaps = pcaps ? pcaps : &dcaps; - - if (ioctl(fd, SNDCTL_DSP_GETCAPS, tcaps) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); - goto fail; - } - - if (*tcaps & DSP_CAP_DUPLEX) - return fd; - - goto fail; - } - - if ((fd = open(device, (*mode = O_WRONLY)|O_NDELAY)) < 0) { - if ((fd = open(device, (*mode = O_RDONLY)|O_NDELAY)) < 0) { - pa_log(__FILE__": open('%s'): %s\n", device, strerror(errno)); - goto fail; - } - } - } else { - if ((fd = open(device, *mode|O_NDELAY)) < 0) { - pa_log(__FILE__": open('%s'): %s\n", device, strerror(errno)); - goto fail; - } - } - - if (pcaps) { - if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); - goto fail; - } - } - - pa_fd_set_cloexec(fd, 1); - - return fd; - -fail: - if (fd >= 0) - close(fd); - return -1; -} - -int pa_oss_auto_format(int fd, pa_sample_spec *ss) { - int format, channels, speed, reqformat; - static const int format_trans[PA_SAMPLE_MAX] = { - [PA_SAMPLE_U8] = AFMT_U8, - [PA_SAMPLE_ALAW] = AFMT_A_LAW, - [PA_SAMPLE_ULAW] = AFMT_MU_LAW, - [PA_SAMPLE_S16LE] = AFMT_S16_LE, - [PA_SAMPLE_S16BE] = AFMT_S16_BE, - [PA_SAMPLE_FLOAT32LE] = AFMT_QUERY, /* not supported */ - [PA_SAMPLE_FLOAT32BE] = AFMT_QUERY, /* not supported */ - }; - - assert(fd >= 0 && ss); - - reqformat = format = format_trans[ss->format]; - if (reqformat == AFMT_QUERY || ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != reqformat) { - format = AFMT_S16_NE; - if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_S16_NE) { - int f = AFMT_S16_NE == AFMT_S16_LE ? AFMT_S16_BE : AFMT_S16_LE; - format = f; - if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != f) { - format = AFMT_U8; - if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_U8) { - pa_log(__FILE__": SNDCTL_DSP_SETFMT: %s\n", format != AFMT_U8 ? "No supported sample format" : strerror(errno)); - return -1; - } else - ss->format = PA_SAMPLE_U8; - } else - ss->format = f == AFMT_S16_LE ? PA_SAMPLE_S16LE : PA_SAMPLE_S16BE; - } else - ss->format = PA_SAMPLE_S16NE; - } - - channels = ss->channels; - if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) { - pa_log(__FILE__": SNDCTL_DSP_CHANNELS: %s\n", strerror(errno)); - return -1; - } - assert(channels); - ss->channels = channels; - - speed = ss->rate; - if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) { - pa_log(__FILE__": SNDCTL_DSP_SPEED: %s\n", strerror(errno)); - return -1; - } - assert(speed); - ss->rate = speed; - - return 0; -} - -static int simple_log2(int v) { - int k = 0; - - for (;;) { - v >>= 1; - if (!v) break; - k++; - } - - return k; -} - -int pa_oss_set_fragments(int fd, int nfrags, int frag_size) { - int arg; - arg = ((int) nfrags << 16) | simple_log2(frag_size); - - if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &arg) < 0) { - pa_log(__FILE__": SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno)); - return -1; - } - - return 0; -} diff --git a/polyp/oss-util.h b/polyp/oss-util.h deleted file mode 100644 index 3ee51cc5..00000000 --- a/polyp/oss-util.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef fooossutilhfoo -#define fooossutilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "sample.h" - -int pa_oss_open(const char *device, int *mode, int* pcaps); -int pa_oss_auto_format(int fd, pa_sample_spec *ss); - -int pa_oss_set_fragments(int fd, int frags, int frag_size); - -#endif diff --git a/polyp/pabrowse.c b/polyp/pabrowse.c deleted file mode 100644 index 634c308a..00000000 --- a/polyp/pabrowse.c +++ /dev/null @@ -1,139 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include -#include -#include -#include - -static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { - fprintf(stderr, "Got signal, exiting\n"); - m->quit(m, 0); -} - -static void dump_server(const pa_browse_info *i) { - char t[16]; - - if (i->cookie) - snprintf(t, sizeof(t), "0x%08x", *i->cookie); - - printf("server: %s\n" - "server-version: %s\n" - "user-name: %s\n" - "fqdn: %s\n" - "cookie: %s\n", - i->server, - i->server_version ? i->server_version : "n/a", - i->user_name ? i->user_name : "n/a", - i->fqdn ? i->fqdn : "n/a", - i->cookie ? t : "n/a"); -} - -static void dump_device(const pa_browse_info *i) { - char t[16], ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; - - if (i->sample_spec) - pa_sample_spec_snprint(ss, sizeof(ss), i->sample_spec); - - if (i->typeid) - pa_typeid_to_string(*i->typeid, t, sizeof(t)); - - printf("device: %s\n" - "description: %s\n" - "type: %s\n" - "sample spec: %s\n", - i->device, - i->description ? i->description : "n/a", - i->typeid ? t : "n/a", - i->sample_spec ? ss : "n/a"); - -} - -static void browser_callback(pa_browser *b, pa_browse_opcode c, const pa_browse_info *i, void *userdata) { - assert(b && i); - - switch (c) { - - case PA_BROWSE_NEW_SERVER: - printf("\n=> new server <%s>\n", i->name); - dump_server(i); - break; - - case PA_BROWSE_NEW_SINK: - printf("\n=> new sink <%s>\n", i->name); - dump_server(i); - dump_device(i); - break; - - case PA_BROWSE_NEW_SOURCE: - printf("\n=> new source <%s>\n", i->name); - dump_server(i); - dump_device(i); - break; - - case PA_BROWSE_REMOVE: - printf("\n=> removed service <%s>\n", i->name); - break; - - default: - ; - } -} - - -int main(int argc, char *argv[]) { - pa_mainloop *mainloop = NULL; - pa_browser *browser = NULL; - int ret = 1, r; - - if (!(mainloop = pa_mainloop_new())) - goto finish; - - r = pa_signal_init(pa_mainloop_get_api(mainloop)); - assert(r == 0); - pa_signal_new(SIGINT, exit_signal_callback, NULL); - pa_signal_new(SIGTERM, exit_signal_callback, NULL); - signal(SIGPIPE, SIG_IGN); - - if (!(browser = pa_browser_new(pa_mainloop_get_api(mainloop)))) - goto finish; - - pa_browser_set_callback(browser, browser_callback, NULL); - - ret = 0; - pa_mainloop_run(mainloop, &ret); - -finish: - if (mainloop) { - pa_signal_done(); - pa_mainloop_free(mainloop); - } - - return ret; -} diff --git a/polyp/pacat-simple.c b/polyp/pacat-simple.c deleted file mode 100644 index 2825fee5..00000000 --- a/polyp/pacat-simple.c +++ /dev/null @@ -1,101 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include -#include -#include "gccmacro.h" - -#define BUFSIZE 1024 - -int main(PA_GCC_UNUSED int argc, char*argv[]) { - - /* The Sample format to use */ - static const pa_sample_spec ss = { - .format = PA_SAMPLE_S16LE, - .rate = 44100, - .channels = 2 - }; - - pa_simple *s = NULL; - int ret = 1; - int error; - - /* Create a new playback stream */ - if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, &error))) { - fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); - goto finish; - } - - for (;;) { - uint8_t buf[BUFSIZE]; - ssize_t r; - -#if 0 - pa_usec_t latency; - - if ((latency = pa_simple_get_playback_latency(s, &error)) == (pa_usec_t) -1) { - fprintf(stderr, __FILE__": pa_simple_get_playback_latency() failed: %s\n", pa_strerror(error)); - goto finish; - } - - fprintf(stderr, "%0.0f usec \r", (float)latency); -#endif - - /* Read some data ... */ - if ((r = read(STDIN_FILENO, buf, sizeof(buf))) <= 0) { - if (r == 0) /* EOF */ - break; - - fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno)); - goto finish; - } - - /* ... and play it */ - if (pa_simple_write(s, buf, r, &error) < 0) { - fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error)); - goto finish; - } - } - - /* Make sure that every single sample was played */ - if (pa_simple_drain(s, &error) < 0) { - fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(error)); - goto finish; - } - - ret = 0; - -finish: - - if (s) - pa_simple_free(s); - - return ret; -} diff --git a/polyp/pacat.c b/polyp/pacat.c deleted file mode 100644 index bd2b64fd..00000000 --- a/polyp/pacat.c +++ /dev/null @@ -1,541 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#if PA_API_VERSION != 8 -#error Invalid Polypaudio API version -#endif - -static enum { RECORD, PLAYBACK } mode = PLAYBACK; - -static pa_context *context = NULL; -static pa_stream *stream = NULL; -static pa_mainloop_api *mainloop_api = NULL; - -static void *buffer = NULL; -static size_t buffer_length = 0, buffer_index = 0; - -static pa_io_event* stdio_event = NULL; - -static char *stream_name = NULL, *client_name = NULL, *device = NULL; - -static int verbose = 0; -static pa_volume_t volume = PA_VOLUME_NORM; - -static pa_sample_spec sample_spec = { - .format = PA_SAMPLE_S16LE, - .rate = 44100, - .channels = 2 -}; - -/* A shortcut for terminating the application */ -static void quit(int ret) { - assert(mainloop_api); - mainloop_api->quit(mainloop_api, ret); -} - -/* Write some data to the stream */ -static void do_stream_write(size_t length) { - size_t l; - assert(length); - - if (!buffer || !buffer_length) - return; - - l = length; - if (l > buffer_length) - l = buffer_length; - - pa_stream_write(stream, (uint8_t*) buffer + buffer_index, l, NULL, 0); - buffer_length -= l; - buffer_index += l; - - if (!buffer_length) { - free(buffer); - buffer = NULL; - buffer_index = buffer_length = 0; - } -} - -/* This is called whenever new data may be written to the stream */ -static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { - assert(s && length); - - if (stdio_event) - mainloop_api->io_enable(stdio_event, PA_IO_EVENT_INPUT); - - if (!buffer) - return; - - do_stream_write(length); -} - -/* This is called whenever new data may is available */ -static void stream_read_callback(pa_stream *s, const void*data, size_t length, void *userdata) { - assert(s && data && length); - - if (stdio_event) - mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT); - - if (buffer) { - fprintf(stderr, "Buffer overrun, dropping incoming data\n"); - return; - } - - buffer = malloc(buffer_length = length); - assert(buffer); - memcpy(buffer, data, length); - buffer_index = 0; -} - -/* This routine is called whenever the stream state changes */ -static void stream_state_callback(pa_stream *s, void *userdata) { - assert(s); - - switch (pa_stream_get_state(s)) { - case PA_STREAM_CREATING: - case PA_STREAM_TERMINATED: - break; - - case PA_STREAM_READY: - if (verbose) - fprintf(stderr, "Stream successfully created\n"); - break; - - case PA_STREAM_FAILED: - default: - fprintf(stderr, "Stream error: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); - quit(1); - } -} - -/* This is called whenever the context status changes */ -static void context_state_callback(pa_context *c, void *userdata) { - assert(c); - - switch (pa_context_get_state(c)) { - case PA_CONTEXT_CONNECTING: - case PA_CONTEXT_AUTHORIZING: - case PA_CONTEXT_SETTING_NAME: - break; - - case PA_CONTEXT_READY: - - assert(c && !stream); - - if (verbose) - fprintf(stderr, "Connection established.\n"); - - stream = pa_stream_new(c, stream_name, &sample_spec, NULL); - assert(stream); - - pa_stream_set_state_callback(stream, stream_state_callback, NULL); - pa_stream_set_write_callback(stream, stream_write_callback, NULL); - pa_stream_set_read_callback(stream, stream_read_callback, NULL); - - if (mode == PLAYBACK) { - pa_cvolume cv; - pa_stream_connect_playback(stream, device, NULL, 0, pa_cvolume_set(&cv, PA_CHANNELS_MAX, volume)); - } else - pa_stream_connect_record(stream, device, NULL, 0); - - break; - - case PA_CONTEXT_TERMINATED: - quit(0); - break; - - case PA_CONTEXT_FAILED: - default: - fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c))); - quit(1); - } -} - -/* Connection draining complete */ -static void context_drain_complete(pa_context*c, void *userdata) { - pa_context_disconnect(c); -} - -/* Stream draining complete */ -static void stream_drain_complete(pa_stream*s, int success, void *userdata) { - pa_operation *o; - - if (!success) { - fprintf(stderr, "Failed to drain stream: %s\n", pa_strerror(pa_context_errno(context))); - quit(1); - } - - if (verbose) - fprintf(stderr, "Playback stream drained.\n"); - - pa_stream_disconnect(stream); - pa_stream_unref(stream); - stream = NULL; - - if (!(o = pa_context_drain(context, context_drain_complete, NULL))) - pa_context_disconnect(context); - else { - pa_operation_unref(o); - - if (verbose) - fprintf(stderr, "Draining connection to server.\n"); - } -} - -/* New data on STDIN **/ -static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { - size_t l, w = 0; - ssize_t r; - assert(a == mainloop_api && e && stdio_event == e); - - if (buffer) { - mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL); - return; - } - - if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY || !(l = w = pa_stream_writable_size(stream))) - l = 4096; - - buffer = malloc(l); - assert(buffer); - if ((r = read(fd, buffer, l)) <= 0) { - if (r == 0) { - if (verbose) - fprintf(stderr, "Got EOF.\n"); - pa_operation_unref(pa_stream_drain(stream, stream_drain_complete, NULL)); - } else { - fprintf(stderr, "read() failed: %s\n", strerror(errno)); - quit(1); - } - - mainloop_api->io_free(stdio_event); - stdio_event = NULL; - return; - } - - buffer_length = r; - buffer_index = 0; - - if (w) - do_stream_write(w); -} - -/* Some data may be written to STDOUT */ -static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { - ssize_t r; - assert(a == mainloop_api && e && stdio_event == e); - - if (!buffer) { - mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL); - return; - } - - assert(buffer_length); - - if ((r = write(fd, (uint8_t*) buffer+buffer_index, buffer_length)) <= 0) { - fprintf(stderr, "write() failed: %s\n", strerror(errno)); - quit(1); - - mainloop_api->io_free(stdio_event); - stdio_event = NULL; - return; - } - - buffer_length -= r; - buffer_index += r; - - if (!buffer_length) { - free(buffer); - buffer = NULL; - buffer_length = buffer_index = 0; - } -} - -/* UNIX signal to quit recieved */ -static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { - if (verbose) - fprintf(stderr, "Got signal, exiting.\n"); - quit(0); - -} - -/* Show the current latency */ -static void stream_get_latency_callback(pa_stream *s, const pa_latency_info *i, void *userdata) { - pa_usec_t total; - int negative = 0; - assert(s); - - if (!i) { - fprintf(stderr, "Failed to get latency: %s\n", pa_strerror(pa_context_errno(context))); - quit(1); - return; - } - - total = pa_stream_get_latency(s, i, &negative); - - fprintf(stderr, "Latency: buffer: %0.0f usec; sink: %0.0f usec; source: %0.0f usec; transport: %0.0f usec; total: %0.0f usec; synchronized clocks: %s.\n", - (float) i->buffer_usec, (float) i->sink_usec, (float) i->source_usec, (float) i->transport_usec, (float) total * (negative?-1:1), - i->synchronized_clocks ? "yes" : "no"); -} - -/* Someone requested that the latency is shown */ -static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { - fprintf(stderr, "Got SIGUSR1, requesting latency.\n"); - pa_operation_unref(pa_stream_get_latency_info(stream, stream_get_latency_callback, NULL)); -} - - -static void help(const char *argv0) { - - printf("%s [options]\n\n" - " -h, --help Show this help\n" - " --version Show version\n\n" - " -r, --record Create a connection for recording\n" - " -p, --playback Create a connection for playback\n\n" - " -v, --verbose Enable verbose operations\n\n" - " -s, --server=SERVER The name of the server to connect to\n" - " -d, --device=DEVICE The name of the sink/source to connect to\n" - " -n, --client-name=NAME How to call this client on the server\n" - " --stream-name=NAME How to call this stream on the server\n" - " --volume=VOLUME Specify the initial (linear) volume in range 0...256\n" - " --rate=SAMPLERATE The sample rate in Hz (defaults to 44100)\n" - " --format=SAMPLEFORMAT The sample type, one of s16le, s16be, u8, float32le,\n" - " float32be, ulaw, alaw (defaults to s16ne)\n" - " --channels=CHANNELS The number of channels, 1 for mono, 2 for stereo\n" - " (defaults to 2)\n", - argv0); -} - -enum { - ARG_VERSION = 256, - ARG_STREAM_NAME, - ARG_VOLUME, - ARG_SAMPLERATE, - ARG_SAMPLEFORMAT, - ARG_CHANNELS -}; - -int main(int argc, char *argv[]) { - pa_mainloop* m = NULL; - int ret = 1, r, c; - char *bn, *server = NULL; - - static const struct option long_options[] = { - {"record", 0, NULL, 'r'}, - {"playback", 0, NULL, 'p'}, - {"device", 1, NULL, 'd'}, - {"server", 1, NULL, 's'}, - {"client-name", 1, NULL, 'n'}, - {"stream-name", 1, NULL, ARG_STREAM_NAME}, - {"version", 0, NULL, ARG_VERSION}, - {"help", 0, NULL, 'h'}, - {"verbose", 0, NULL, 'v'}, - {"volume", 1, NULL, ARG_VOLUME}, - {"rate", 1, NULL, ARG_SAMPLERATE}, - {"format", 1, NULL, ARG_SAMPLEFORMAT}, - {"channels", 1, NULL, ARG_CHANNELS}, - {NULL, 0, NULL, 0} - }; - - if (!(bn = strrchr(argv[0], '/'))) - bn = argv[0]; - else - bn++; - - if (strstr(bn, "rec") || strstr(bn, "mon")) - mode = RECORD; - else if (strstr(bn, "cat") || strstr(bn, "play")) - mode = PLAYBACK; - - while ((c = getopt_long(argc, argv, "rpd:s:n:hv", long_options, NULL)) != -1) { - - switch (c) { - case 'h' : - help(bn); - ret = 0; - goto quit; - - case ARG_VERSION: - printf("pacat "PACKAGE_VERSION"\nCompiled with libpolyp %s\nLinked with libpolyp %s\n", pa_get_headers_version(), pa_get_library_version()); - ret = 0; - goto quit; - - case 'r': - mode = RECORD; - break; - - case 'p': - mode = PLAYBACK; - break; - - case 'd': - free(device); - device = strdup(optarg); - break; - - case 's': - free(server); - server = strdup(optarg); - break; - - case 'n': - free(client_name); - client_name = strdup(optarg); - break; - - case ARG_STREAM_NAME: - free(stream_name); - stream_name = strdup(optarg); - break; - - case 'v': - verbose = 1; - break; - - case ARG_VOLUME: { - int v = atoi(optarg); - volume = v < 0 ? 0 : v; - break; - } - - case ARG_CHANNELS: - sample_spec.channels = atoi(optarg); - break; - - case ARG_SAMPLEFORMAT: - sample_spec.format = pa_parse_sample_format(optarg); - break; - - case ARG_SAMPLERATE: - sample_spec.rate = atoi(optarg); - break; - - default: - goto quit; - } - } - - if (!client_name) - client_name = strdup(bn); - - if (!stream_name) - stream_name = strdup(client_name); - - if (!pa_sample_spec_valid(&sample_spec)) { - fprintf(stderr, "Invalid sample specification\n"); - goto quit; - } - - if (verbose) { - char t[PA_SAMPLE_SPEC_SNPRINT_MAX]; - pa_sample_spec_snprint(t, sizeof(t), &sample_spec); - fprintf(stderr, "Opening a %s stream with sample specification '%s'.\n", mode == RECORD ? "recording" : "playback", t); - } - - /* Set up a new main loop */ - if (!(m = pa_mainloop_new())) { - fprintf(stderr, "pa_mainloop_new() failed.\n"); - goto quit; - } - - mainloop_api = pa_mainloop_get_api(m); - - r = pa_signal_init(mainloop_api); - assert(r == 0); - pa_signal_new(SIGINT, exit_signal_callback, NULL); - pa_signal_new(SIGTERM, exit_signal_callback, NULL); -#ifdef SIGUSR1 - pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL); -#endif -#ifdef SIGPIPE - signal(SIGPIPE, SIG_IGN); -#endif - - if (!(stdio_event = mainloop_api->io_new(mainloop_api, - mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO, - mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT, - mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) { - fprintf(stderr, "source_io() failed.\n"); - goto quit; - } - - /* Create a new connection context */ - if (!(context = pa_context_new(mainloop_api, client_name))) { - fprintf(stderr, "pa_context_new() failed.\n"); - goto quit; - } - - pa_context_set_state_callback(context, context_state_callback, NULL); - - /* Connect the context */ - pa_context_connect(context, server, 1, NULL); - - /* Run the main loop */ - if (pa_mainloop_run(m, &ret) < 0) { - fprintf(stderr, "pa_mainloop_run() failed.\n"); - goto quit; - } - -quit: - if (stream) - pa_stream_unref(stream); - - if (context) - pa_context_unref(context); - - if (stdio_event) { - assert(mainloop_api); - mainloop_api->io_free(stdio_event); - } - - if (m) { - pa_signal_done(); - pa_mainloop_free(m); - } - - free(buffer); - - free(server); - free(device); - free(client_name); - free(stream_name); - - return ret; -} diff --git a/polyp/packet.c b/polyp/packet.c deleted file mode 100644 index b3a2e074..00000000 --- a/polyp/packet.c +++ /dev/null @@ -1,69 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "packet.h" -#include "xmalloc.h" - -pa_packet* pa_packet_new(size_t length) { - pa_packet *p; - assert(length); - p = pa_xmalloc(sizeof(pa_packet)+length); - p->ref = 1; - p->length = length; - p->data = (uint8_t*) (p+1); - p->type = PA_PACKET_APPENDED; - return p; -} - -pa_packet* pa_packet_new_dynamic(uint8_t* data, size_t length) { - pa_packet *p; - assert(data && length); - p = pa_xmalloc(sizeof(pa_packet)); - p->ref = 1; - p->length = length; - p->data = data; - p->type = PA_PACKET_DYNAMIC; - return p; -} - -pa_packet* pa_packet_ref(pa_packet *p) { - assert(p && p->ref >= 1); - p->ref++; - return p; -} - -void pa_packet_unref(pa_packet *p) { - assert(p && p->ref >= 1); - p->ref--; - - if (p->ref == 0) { - if (p->type == PA_PACKET_DYNAMIC) - pa_xfree(p->data); - pa_xfree(p); - } -} diff --git a/polyp/packet.h b/polyp/packet.h deleted file mode 100644 index 0ac47485..00000000 --- a/polyp/packet.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef foopackethfoo -#define foopackethfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -typedef struct pa_packet { - enum { PA_PACKET_APPENDED, PA_PACKET_DYNAMIC } type; - unsigned ref; - size_t length; - uint8_t *data; -} pa_packet; - -pa_packet* pa_packet_new(size_t length); -pa_packet* pa_packet_new_dynamic(uint8_t* data, size_t length); - -pa_packet* pa_packet_ref(pa_packet *p); -void pa_packet_unref(pa_packet *p); - -#endif diff --git a/polyp/pacmd.c b/polyp/pacmd.c deleted file mode 100644 index e6c0da6a..00000000 --- a/polyp/pacmd.c +++ /dev/null @@ -1,183 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "util.h" -#include "log.h" -#include "pid.h" - -int main(PA_GCC_UNUSED int main, PA_GCC_UNUSED char*argv[]) { - pid_t pid ; - int fd = -1; - int ret = 1, i; - struct sockaddr_un sa; - char ibuf[256], obuf[256]; - size_t ibuf_index, ibuf_length, obuf_index, obuf_length; - fd_set ifds, ofds; - - if (pa_pid_file_check_running(&pid) < 0) { - pa_log(__FILE__": no Polypaudio daemon running\n"); - goto fail; - } - - if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(PF_UNIX, SOCK_STREAM, 0): %s\n", strerror(errno)); - goto fail; - } - - memset(&sa, 0, sizeof(sa)); - sa.sun_family = AF_UNIX; - pa_runtime_path("cli", sa.sun_path, sizeof(sa.sun_path)); - - for (i = 0; i < 5; i++) { - int r; - - if ((r = connect(fd, (struct sockaddr*) &sa, sizeof(sa))) < 0 && (errno != ECONNREFUSED && errno != ENOENT)) { - pa_log(__FILE__": connect() failed: %s\n", strerror(errno)); - goto fail; - } - - if (r >= 0) - break; - - if (pa_pid_file_kill(SIGUSR2, NULL) < 0) { - pa_log(__FILE__": failed to kill Polypaudio daemon.\n"); - goto fail; - } - - pa_msleep(50); - } - - if (i >= 5) { - pa_log(__FILE__": daemon not responding.\n"); - goto fail; - } - - ibuf_index = ibuf_length = obuf_index = obuf_length = 0; - - - FD_ZERO(&ifds); - FD_SET(0, &ifds); - FD_SET(fd, &ifds); - - FD_ZERO(&ofds); - - for (;;) { - if (select(FD_SETSIZE, &ifds, &ofds, NULL, NULL) < 0) { - pa_log(__FILE__": select() failed: %s\n", strerror(errno)); - goto fail; - } - - if (FD_ISSET(0, &ifds)) { - ssize_t r; - assert(!ibuf_length); - - if ((r = read(0, ibuf, sizeof(ibuf))) <= 0) { - if (r == 0) - break; - - pa_log(__FILE__": read() failed: %s\n", strerror(errno)); - goto fail; - } - - ibuf_length = (size_t) r; - ibuf_index = 0; - } - - if (FD_ISSET(fd, &ifds)) { - ssize_t r; - assert(!obuf_length); - - if ((r = read(fd, obuf, sizeof(obuf))) <= 0) { - if (r == 0) - break; - - pa_log(__FILE__": read() failed: %s\n", strerror(errno)); - goto fail; - } - - obuf_length = (size_t) r; - obuf_index = 0; - } - - if (FD_ISSET(1, &ofds)) { - ssize_t r; - assert(obuf_length); - - if ((r = write(1, obuf + obuf_index, obuf_length)) < 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); - goto fail; - } - - obuf_length -= (size_t) r; - obuf_index += obuf_index; - - } - - if (FD_ISSET(fd, &ofds)) { - ssize_t r; - assert(ibuf_length); - - if ((r = write(fd, ibuf + ibuf_index, ibuf_length)) < 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); - goto fail; - } - - ibuf_length -= (size_t) r; - ibuf_index += obuf_index; - - } - - FD_ZERO(&ifds); - FD_ZERO(&ofds); - - if (obuf_length <= 0) - FD_SET(fd, &ifds); - else - FD_SET(1, &ofds); - - if (ibuf_length <= 0) - FD_SET(0, &ifds); - else - FD_SET(fd, &ofds); - } - - - ret = 0; - -fail: - if (fd >= 0) - close(fd); - - return ret; -} diff --git a/polyp/pactl.c b/polyp/pactl.c deleted file mode 100644 index 23bd924b..00000000 --- a/polyp/pactl.c +++ /dev/null @@ -1,784 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#if PA_API_VERSION != 8 -#error Invalid Polypaudio API version -#endif - -#define BUFSIZE 1024 - -static pa_context *context = NULL; -static pa_mainloop_api *mainloop_api = NULL; - -static char *device = NULL, *sample_name = NULL; - -static SNDFILE *sndfile = NULL; -static pa_stream *sample_stream = NULL; -static pa_sample_spec sample_spec; -static size_t sample_length = 0; - -static int actions = 1; - -static int nl = 0; - -static enum { - NONE, - EXIT, - STAT, - UPLOAD_SAMPLE, - PLAY_SAMPLE, - REMOVE_SAMPLE, - LIST -} action = NONE; - -static void quit(int ret) { - assert(mainloop_api); - mainloop_api->quit(mainloop_api, ret); -} - - -static void context_drain_complete(pa_context *c, void *userdata) { - pa_context_disconnect(c); -} - -static void drain(void) { - pa_operation *o; - if (!(o = pa_context_drain(context, context_drain_complete, NULL))) - pa_context_disconnect(context); - else - pa_operation_unref(o); -} - - -static void complete_action(void) { - assert(actions > 0); - - if (!(--actions)) - drain(); -} - -static void stat_callback(pa_context *c, const pa_stat_info *i, void *userdata) { - char s[128]; - if (!i) { - fprintf(stderr, "Failed to get statistics: %s\n", pa_strerror(pa_context_errno(c))); - quit(1); - return; - } - - pa_bytes_snprint(s, sizeof(s), i->memblock_total_size); - printf("Currently in use: %u blocks containing %s bytes total.\n", i->memblock_total, s); - - pa_bytes_snprint(s, sizeof(s), i->memblock_allocated_size); - printf("Allocated during whole lifetime: %u blocks containing %s bytes total.\n", i->memblock_allocated, s); - - pa_bytes_snprint(s, sizeof(s), i->scache_size); - printf("Sample cache size: %s\n", s); - - complete_action(); -} - -static void get_server_info_callback(pa_context *c, const pa_server_info *i, void *useerdata) { - char s[PA_SAMPLE_SPEC_SNPRINT_MAX]; - - if (!i) { - fprintf(stderr, "Failed to get server information: %s\n", pa_strerror(pa_context_errno(c))); - quit(1); - return; - } - - pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); - - printf("User name: %s\n" - "Host Name: %s\n" - "Server Name: %s\n" - "Server Version: %s\n" - "Default Sample Specification: %s\n" - "Default Sink: %s\n" - "Default Source: %s\n" - "Cookie: %08x\n", - i->user_name, - i->host_name, - i->server_name, - i->server_version, - s, - i->default_sink_name, - i->default_source_name, - i->cookie); - - complete_action(); -} - -static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) { - char s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - - if (is_last < 0) { - fprintf(stderr, "Failed to get sink information: %s\n", pa_strerror(pa_context_errno(c))); - quit(1); - return; - } - - if (is_last) { - complete_action(); - return; - } - - assert(i); - - if (nl) - printf("\n"); - nl = 1; - - printf("*** Sink #%u ***\n" - "Name: %s\n" - "Driver: %s\n" - "Description: %s\n" - "Sample Specification: %s\n" - "Channel Map: %s\n" - "Owner Module: %u\n" - "Volume: %s\n" - "Monitor Source: %u\n" - "Latency: %0.0f usec\n", - i->index, - i->name, - i->driver, - i->description, - pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), - pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), - i->owner_module, - pa_cvolume_snprint(cv, sizeof(cv), &i->volume), - i->monitor_source, - (double) i->latency); - -} - -static void get_source_info_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) { - char s[PA_SAMPLE_SPEC_SNPRINT_MAX], t[32], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - - if (is_last < 0) { - fprintf(stderr, "Failed to get source information: %s\n", pa_strerror(pa_context_errno(c))); - quit(1); - return; - } - - if (is_last) { - complete_action(); - return; - } - - assert(i); - - if (nl) - printf("\n"); - nl = 1; - - snprintf(t, sizeof(t), "%u", i->monitor_of_sink); - - printf("*** Source #%u ***\n" - "Name: %s\n" - "Driver: %s\n" - "Description: %s\n" - "Sample Specification: %s\n" - "Channel Map: %s\n" - "Owner Module: %u\n" - "Monitor of Sink: %s\n" - "Latency: %0.0f usec\n", - i->index, - i->driver, - i->name, - i->description, - pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), - pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), - i->owner_module, - i->monitor_of_sink != PA_INVALID_INDEX ? t : "no", - (double) i->latency); - -} - -static void get_module_info_callback(pa_context *c, const pa_module_info *i, int is_last, void *userdata) { - char t[32]; - - if (is_last < 0) { - fprintf(stderr, "Failed to get module information: %s\n", pa_strerror(pa_context_errno(c))); - quit(1); - return; - } - - if (is_last) { - complete_action(); - return; - } - - assert(i); - - if (nl) - printf("\n"); - nl = 1; - - snprintf(t, sizeof(t), "%u", i->n_used); - - printf("*** Module #%u ***\n" - "Name: %s\n" - "Argument: %s\n" - "Usage counter: %s\n" - "Auto unload: %s\n", - i->index, - i->name, - i->argument, - i->n_used != PA_INVALID_INDEX ? t : "n/a", - i->auto_unload ? "yes" : "no"); -} - -static void get_client_info_callback(pa_context *c, const pa_client_info *i, int is_last, void *userdata) { - char t[32]; - - if (is_last < 0) { - fprintf(stderr, "Failed to get client information: %s\n", pa_strerror(pa_context_errno(c))); - quit(1); - return; - } - - if (is_last) { - complete_action(); - return; - } - - assert(i); - - if (nl) - printf("\n"); - nl = 1; - - snprintf(t, sizeof(t), "%u", i->owner_module); - - printf("*** Client #%u ***\n" - "Name: %s\n" - "Driver: %s\n" - "Owner Module: %s\n", - i->index, - i->name, - i->driver, - i->owner_module != PA_INVALID_INDEX ? t : "n/a"); -} - -static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) { - char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - - if (is_last < 0) { - fprintf(stderr, "Failed to get sink input information: %s\n", pa_strerror(pa_context_errno(c))); - quit(1); - return; - } - - if (is_last) { - complete_action(); - return; - } - - assert(i); - - if (nl) - printf("\n"); - nl = 1; - - snprintf(t, sizeof(t), "%u", i->owner_module); - snprintf(k, sizeof(k), "%u", i->client); - - printf("*** Sink Input #%u ***\n" - "Name: %s\n" - "Driver: %s\n" - "Owner Module: %s\n" - "Client: %s\n" - "Sink: %u\n" - "Sample Specification: %s\n" - "Channel Map: %s\n" - "Volume: %s\n" - "Buffer Latency: %0.0f usec\n" - "Sink Latency: %0.0f usec\n" - "Resample method: %s\n", - i->index, - i->name, - i->driver, - i->owner_module != PA_INVALID_INDEX ? t : "n/a", - i->client != PA_INVALID_INDEX ? k : "n/a", - i->sink, - pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), - pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), - pa_cvolume_snprint(cv, sizeof(cv), &i->volume), - (double) i->buffer_usec, - (double) i->sink_usec, - i->resample_method ? i->resample_method : "n/a"); -} - - -static void get_source_output_info_callback(pa_context *c, const pa_source_output_info *i, int is_last, void *userdata) { - char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - - if (is_last < 0) { - fprintf(stderr, "Failed to get source output information: %s\n", pa_strerror(pa_context_errno(c))); - quit(1); - return; - } - - if (is_last) { - complete_action(); - return; - } - - assert(i); - - if (nl) - printf("\n"); - nl = 1; - - - snprintf(t, sizeof(t), "%u", i->owner_module); - snprintf(k, sizeof(k), "%u", i->client); - - printf("*** Source Output #%u ***\n" - "Name: %s\n" - "Driver: %s\n" - "Owner Module: %s\n" - "Client: %s\n" - "Source: %u\n" - "Sample Specification: %s\n" - "Channel Map: %s\n" - "Buffer Latency: %0.0f usec\n" - "Source Latency: %0.0f usec\n" - "Resample method: %s\n", - i->index, - i->name, - i->driver, - i->owner_module != PA_INVALID_INDEX ? t : "n/a", - i->client != PA_INVALID_INDEX ? k : "n/a", - i->source, - pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), - pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), - (double) i->buffer_usec, - (double) i->source_usec, - i->resample_method ? i->resample_method : "n/a"); -} - -static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int is_last, void *userdata) { - char t[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - - if (is_last < 0) { - fprintf(stderr, "Failed to get sample information: %s\n", pa_strerror(pa_context_errno(c))); - quit(1); - return; - } - - if (is_last) { - complete_action(); - return; - } - - assert(i); - - if (nl) - printf("\n"); - nl = 1; - - - pa_bytes_snprint(t, sizeof(t), i->bytes); - - printf("*** Sample #%u ***\n" - "Name: %s\n" - "Volume: %s\n" - "Sample Specification: %s\n" - "Channel Map: %s\n" - "Duration: %0.1fs\n" - "Size: %s\n" - "Lazy: %s\n" - "Filename: %s\n", - i->index, - i->name, - pa_cvolume_snprint(cv, sizeof(cv), &i->volume), - pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : "n/a", - pa_sample_spec_valid(&i->sample_spec) ? pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map) : "n/a", - (double) i->duration/1000000, - t, - i->lazy ? "yes" : "no", - i->filename ? i->filename : "n/a"); -} - -static void get_autoload_info_callback(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata) { - if (is_last < 0) { - fprintf(stderr, "Failed to get autoload information: %s\n", pa_strerror(pa_context_errno(c))); - quit(1); - return; - } - - if (is_last) { - complete_action(); - return; - } - - assert(i); - - if (nl) - printf("\n"); - nl = 1; - - printf("*** Autoload Entry #%u ***\n" - "Name: %s\n" - "Type: %s\n" - "Module: %s\n" - "Argument: %s\n", - i->index, - i->name, - i->type == PA_AUTOLOAD_SINK ? "sink" : "source", - i->module, - i->argument); -} - -static void simple_callback(pa_context *c, int success, void *userdata) { - if (!success) { - fprintf(stderr, "Failure: %s\n", pa_strerror(pa_context_errno(c))); - quit(1); - return; - } - - complete_action(); -} - -static void stream_state_callback(pa_stream *s, void *userdata) { - assert(s); - - switch (pa_stream_get_state(s)) { - case PA_STREAM_CREATING: - case PA_STREAM_READY: - break; - - case PA_STREAM_TERMINATED: - drain(); - break; - - case PA_STREAM_FAILED: - default: - fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); - quit(1); - } -} - -static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { - sf_count_t l; - float *d; - assert(s && length && sndfile); - - d = malloc(length); - assert(d); - - assert(sample_length >= length); - l = length/pa_frame_size(&sample_spec); - - if ((sf_readf_float(sndfile, d, l)) != l) { - free(d); - fprintf(stderr, "Premature end of file\n"); - quit(1); - } - - pa_stream_write(s, d, length, free, 0); - - sample_length -= length; - - if (sample_length <= 0) { - pa_stream_set_write_callback(sample_stream, NULL, NULL); - pa_stream_finish_upload(sample_stream); - } -} - -static void context_state_callback(pa_context *c, void *userdata) { - assert(c); - switch (pa_context_get_state(c)) { - case PA_CONTEXT_CONNECTING: - case PA_CONTEXT_AUTHORIZING: - case PA_CONTEXT_SETTING_NAME: - break; - - case PA_CONTEXT_READY: - switch (action) { - case STAT: - actions = 2; - pa_operation_unref(pa_context_stat(c, stat_callback, NULL)); - pa_operation_unref(pa_context_get_server_info(c, get_server_info_callback, NULL)); - break; - - case PLAY_SAMPLE: - pa_operation_unref(pa_context_play_sample(c, sample_name, device, PA_VOLUME_NORM, simple_callback, NULL)); - break; - - case REMOVE_SAMPLE: - pa_operation_unref(pa_context_remove_sample(c, sample_name, simple_callback, NULL)); - break; - - case UPLOAD_SAMPLE: - sample_stream = pa_stream_new(c, sample_name, &sample_spec, NULL); - assert(sample_stream); - - pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL); - pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL); - pa_stream_connect_upload(sample_stream, sample_length); - break; - - case EXIT: - pa_context_exit_daemon(c); - drain(); - - case LIST: - actions = 8; - pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL)); - pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL)); - pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL)); - pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL)); - pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL)); - pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL)); - pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL)); - pa_operation_unref(pa_context_get_autoload_info_list(c, get_autoload_info_callback, NULL)); - break; - - default: - assert(0); - } - break; - - case PA_CONTEXT_TERMINATED: - quit(0); - break; - - case PA_CONTEXT_FAILED: - default: - fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c))); - quit(1); - } -} - -static void exit_signal_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) { - fprintf(stderr, "Got SIGINT, exiting.\n"); - quit(0); -} - -static void help(const char *argv0) { - - printf("%s [options] stat\n" - "%s [options] list\n" - "%s [options] exit\n" - "%s [options] upload-sample FILENAME [NAME]\n" - "%s [options] play-sample NAME [SINK]\n" - "%s [options] remove-sample NAME\n\n" - " -h, --help Show this help\n" - " --version Show version\n\n" - " -s, --server=SERVER The name of the server to connect to\n" - " -n, --client-name=NAME How to call this client on the server\n", - argv0, argv0, argv0, argv0, argv0, argv0); -} - -enum { ARG_VERSION = 256 }; - -int main(int argc, char *argv[]) { - pa_mainloop* m = NULL; - char tmp[PATH_MAX]; - int ret = 1, r, c; - char *server = NULL, *client_name = NULL, *bn; - - static const struct option long_options[] = { - {"server", 1, NULL, 's'}, - {"client-name", 1, NULL, 'n'}, - {"version", 0, NULL, ARG_VERSION}, - {"help", 0, NULL, 'h'}, - {NULL, 0, NULL, 0} - }; - - if (!(bn = strrchr(argv[0], '/'))) - bn = argv[0]; - else - bn++; - - while ((c = getopt_long(argc, argv, "s:n:h", long_options, NULL)) != -1) { - switch (c) { - case 'h' : - help(bn); - ret = 0; - goto quit; - - case ARG_VERSION: - printf("pactl "PACKAGE_VERSION"\nCompiled with libpolyp %s\nLinked with libpolyp %s\n", pa_get_headers_version(), pa_get_library_version()); - ret = 0; - goto quit; - - case 's': - free(server); - server = strdup(optarg); - break; - - case 'n': - free(client_name); - client_name = strdup(optarg); - break; - - default: - goto quit; - } - } - - if (!client_name) - client_name = strdup(bn); - - if (optind < argc) { - if (!strcmp(argv[optind], "stat")) - action = STAT; - else if (!strcmp(argv[optind], "exit")) - action = EXIT; - else if (!strcmp(argv[optind], "list")) - action = LIST; - else if (!strcmp(argv[optind], "upload-sample")) { - struct SF_INFO sfinfo; - action = UPLOAD_SAMPLE; - - if (optind+1 >= argc) { - fprintf(stderr, "Please specify a sample file to load\n"); - goto quit; - } - - if (optind+2 < argc) - sample_name = strdup(argv[optind+2]); - else { - char *f = strrchr(argv[optind+1], '/'); - size_t n; - if (f) - f++; - else - f = argv[optind]; - - n = strcspn(f, "."); - strncpy(tmp, f, n); - tmp[n] = 0; - sample_name = strdup(tmp); - } - - memset(&sfinfo, 0, sizeof(sfinfo)); - if (!(sndfile = sf_open(argv[optind+1], SFM_READ, &sfinfo))) { - fprintf(stderr, "Failed to open sound file.\n"); - goto quit; - } - - sample_spec.format = PA_SAMPLE_FLOAT32; - sample_spec.rate = sfinfo.samplerate; - sample_spec.channels = sfinfo.channels; - - sample_length = sfinfo.frames*pa_frame_size(&sample_spec); - } else if (!strcmp(argv[optind], "play-sample")) { - action = PLAY_SAMPLE; - if (optind+1 >= argc) { - fprintf(stderr, "You have to specify a sample name to play\n"); - goto quit; - } - - sample_name = strdup(argv[optind+1]); - - if (optind+2 < argc) - device = strdup(argv[optind+2]); - - } else if (!strcmp(argv[optind], "remove-sample")) { - action = REMOVE_SAMPLE; - if (optind+1 >= argc) { - fprintf(stderr, "You have to specify a sample name to remove\n"); - goto quit; - } - - sample_name = strdup(argv[optind+1]); - } - } - - if (action == NONE) { - fprintf(stderr, "No valid command specified.\n"); - goto quit; - } - - if (!(m = pa_mainloop_new())) { - fprintf(stderr, "pa_mainloop_new() failed.\n"); - goto quit; - } - - mainloop_api = pa_mainloop_get_api(m); - - r = pa_signal_init(mainloop_api); - assert(r == 0); - pa_signal_new(SIGINT, exit_signal_callback, NULL); -#ifdef SIGPIPE - signal(SIGPIPE, SIG_IGN); -#endif - - if (!(context = pa_context_new(mainloop_api, client_name))) { - fprintf(stderr, "pa_context_new() failed.\n"); - goto quit; - } - - pa_context_set_state_callback(context, context_state_callback, NULL); - pa_context_connect(context, server, 1, NULL); - - if (pa_mainloop_run(m, &ret) < 0) { - fprintf(stderr, "pa_mainloop_run() failed.\n"); - goto quit; - } - -quit: - if (sample_stream) - pa_stream_unref(sample_stream); - - if (context) - pa_context_unref(context); - - if (m) { - pa_signal_done(); - pa_mainloop_free(m); - } - - if (sndfile) - sf_close(sndfile); - - free(server); - free(device); - free(sample_name); - - return ret; -} diff --git a/polyp/paplay.c b/polyp/paplay.c deleted file mode 100644 index ddc1cbc1..00000000 --- a/polyp/paplay.c +++ /dev/null @@ -1,386 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#if PA_API_VERSION != 8 -#error Invalid Polypaudio API version -#endif - -static pa_context *context = NULL; -static pa_stream *stream = NULL; -static pa_mainloop_api *mainloop_api = NULL; - -static char *stream_name = NULL, *client_name = NULL, *device = NULL; - -static int verbose = 0; -static pa_volume_t volume = PA_VOLUME_NORM; - -static SNDFILE* sndfile = NULL; - -static pa_sample_spec sample_spec = { 0, 0, 0 }; - -static sf_count_t (*readf_function)(SNDFILE *_sndfile, void *ptr, sf_count_t frames); - -/* A shortcut for terminating the application */ -static void quit(int ret) { - assert(mainloop_api); - mainloop_api->quit(mainloop_api, ret); -} - -/* Connection draining complete */ -static void context_drain_complete(pa_context*c, void *userdata) { - pa_context_disconnect(c); -} - -/* Stream draining complete */ -static void stream_drain_complete(pa_stream*s, int success, void *userdata) { - pa_operation *o; - - if (!success) { - fprintf(stderr, "Failed to drain stream: %s\n", pa_strerror(pa_context_errno(context))); - quit(1); - } - - if (verbose) - fprintf(stderr, "Playback stream drained.\n"); - - pa_stream_disconnect(stream); - pa_stream_unref(stream); - stream = NULL; - - if (!(o = pa_context_drain(context, context_drain_complete, NULL))) - pa_context_disconnect(context); - else { - pa_operation_unref(o); - - if (verbose) - fprintf(stderr, "Draining connection to server.\n"); - } -} - -/* This is called whenever new data may be written to the stream */ -static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { - size_t k; - sf_count_t f, n; - void *data; - assert(s && length); - - if (!sndfile) - return; - - k = pa_frame_size(&sample_spec); - - data = malloc(length); - - n = length/k; - - f = readf_function(sndfile, data, n); - - if (f > 0) - pa_stream_write(s, data, f*k, free, 0); - - if (f < n) { - sf_close(sndfile); - sndfile = NULL; - pa_operation_unref(pa_stream_drain(s, stream_drain_complete, NULL)); - } -} - -/* This routine is called whenever the stream state changes */ -static void stream_state_callback(pa_stream *s, void *userdata) { - assert(s); - - switch (pa_stream_get_state(s)) { - case PA_STREAM_CREATING: - case PA_STREAM_TERMINATED: - break; - - case PA_STREAM_READY: - if (verbose) - fprintf(stderr, "Stream successfully created\n"); - break; - - case PA_STREAM_FAILED: - default: - fprintf(stderr, "Stream errror: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); - quit(1); - } -} - -/* This is called whenever the context status changes */ -static void context_state_callback(pa_context *c, void *userdata) { - assert(c); - - switch (pa_context_get_state(c)) { - case PA_CONTEXT_CONNECTING: - case PA_CONTEXT_AUTHORIZING: - case PA_CONTEXT_SETTING_NAME: - break; - - case PA_CONTEXT_READY: { - pa_cvolume cv; - - assert(c && !stream); - - if (verbose) - fprintf(stderr, "Connection established.\n"); - - stream = pa_stream_new(c, stream_name, &sample_spec, NULL); - assert(stream); - - pa_stream_set_state_callback(stream, stream_state_callback, NULL); - pa_stream_set_write_callback(stream, stream_write_callback, NULL); - pa_stream_connect_playback(stream, device, NULL, 0, pa_cvolume_set(&cv, PA_CHANNELS_MAX, volume)); - - break; - } - - case PA_CONTEXT_TERMINATED: - quit(0); - break; - - case PA_CONTEXT_FAILED: - default: - fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c))); - quit(1); - } -} - -/* UNIX signal to quit recieved */ -static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { - if (verbose) - fprintf(stderr, "Got SIGINT, exiting.\n"); - quit(0); - -} - -static void help(const char *argv0) { - - printf("%s [options] [FILE]\n\n" - " -h, --help Show this help\n" - " --version Show version\n\n" - " -v, --verbose Enable verbose operations\n\n" - " -s, --server=SERVER The name of the server to connect to\n" - " -d, --device=DEVICE The name of the sink/source to connect to\n" - " -n, --client-name=NAME How to call this client on the server\n" - " --stream-name=NAME How to call this stream on the server\n" - " --volume=VOLUME Specify the initial (linear) volume in range 0...256\n", - argv0); -} - -enum { - ARG_VERSION = 256, - ARG_STREAM_NAME, - ARG_VOLUME -}; - -int main(int argc, char *argv[]) { - pa_mainloop* m = NULL; - int ret = 1, r, c; - char *bn, *server = NULL; - const char *filename; - SF_INFO sfinfo; - - static const struct option long_options[] = { - {"device", 1, NULL, 'd'}, - {"server", 1, NULL, 's'}, - {"client-name", 1, NULL, 'n'}, - {"stream-name", 1, NULL, ARG_STREAM_NAME}, - {"version", 0, NULL, ARG_VERSION}, - {"help", 0, NULL, 'h'}, - {"verbose", 0, NULL, 'v'}, - {"volume", 1, NULL, ARG_VOLUME}, - {NULL, 0, NULL, 0} - }; - - if (!(bn = strrchr(argv[0], '/'))) - bn = argv[0]; - else - bn++; - - while ((c = getopt_long(argc, argv, "d:s:n:hv", long_options, NULL)) != -1) { - - switch (c) { - case 'h' : - help(bn); - ret = 0; - goto quit; - - case ARG_VERSION: - printf("paplay "PACKAGE_VERSION"\nCompiled with libpolyp %s\nLinked with libpolyp %s\n", pa_get_headers_version(), pa_get_library_version()); - ret = 0; - goto quit; - - case 'd': - free(device); - device = strdup(optarg); - break; - - case 's': - free(server); - server = strdup(optarg); - break; - - case 'n': - free(client_name); - client_name = strdup(optarg); - break; - - case ARG_STREAM_NAME: - free(stream_name); - stream_name = strdup(optarg); - break; - - case 'v': - verbose = 1; - break; - - case ARG_VOLUME: { - int v = atoi(optarg); - volume = v < 0 ? 0 : v; - break; - } - - default: - goto quit; - } - } - - - filename = optind < argc ? argv[optind] : "STDIN"; - - - if (!client_name) - client_name = strdup(bn); - - if (!stream_name) - stream_name = strdup(filename); - - memset(&sfinfo, 0, sizeof(sfinfo)); - - if (optind < argc) - sndfile = sf_open(filename, SFM_READ, &sfinfo); - else - sndfile = sf_open_fd(STDIN_FILENO, SFM_READ, &sfinfo, 0); - - if (!sndfile) { - fprintf(stderr, "Failed to open file '%s'\n", filename); - goto quit; - } - - sample_spec.rate = sfinfo.samplerate; - sample_spec.channels = sfinfo.channels; - - switch (sfinfo.format & 0xFF) { - case SF_FORMAT_PCM_16: - case SF_FORMAT_PCM_U8: - case SF_FORMAT_ULAW: - case SF_FORMAT_ALAW: - sample_spec.format = PA_SAMPLE_S16NE; - readf_function = (sf_count_t (*)(SNDFILE *_sndfile, void *ptr, sf_count_t frames)) sf_readf_short; - break; - case SF_FORMAT_FLOAT: - default: - sample_spec.format = PA_SAMPLE_FLOAT32NE; - readf_function = (sf_count_t (*)(SNDFILE *_sndfile, void *ptr, sf_count_t frames)) sf_readf_float; - break; - } - - if (verbose) { - char t[PA_SAMPLE_SPEC_SNPRINT_MAX]; - pa_sample_spec_snprint(t, sizeof(t), &sample_spec); - fprintf(stderr, "Using sample spec '%s'\n", t); - } - - /* Set up a new main loop */ - if (!(m = pa_mainloop_new())) { - fprintf(stderr, "pa_mainloop_new() failed.\n"); - goto quit; - } - - mainloop_api = pa_mainloop_get_api(m); - - r = pa_signal_init(mainloop_api); - assert(r == 0); - pa_signal_new(SIGINT, exit_signal_callback, NULL); -#ifdef SIGPIPE - signal(SIGPIPE, SIG_IGN); -#endif - - /* Create a new connection context */ - if (!(context = pa_context_new(mainloop_api, client_name))) { - fprintf(stderr, "pa_context_new() failed.\n"); - goto quit; - } - - pa_context_set_state_callback(context, context_state_callback, NULL); - - /* Connect the context */ - pa_context_connect(context, server, 1, NULL); - - /* Run the main loop */ - if (pa_mainloop_run(m, &ret) < 0) { - fprintf(stderr, "pa_mainloop_run() failed.\n"); - goto quit; - } - -quit: - if (stream) - pa_stream_unref(stream); - - if (context) - pa_context_unref(context); - - if (m) { - pa_signal_done(); - pa_mainloop_free(m); - } - - free(server); - free(device); - free(client_name); - free(stream_name); - - if (sndfile) - sf_close(sndfile); - - return ret; -} diff --git a/polyp/parec-simple.c b/polyp/parec-simple.c deleted file mode 100644 index 524cc4f1..00000000 --- a/polyp/parec-simple.c +++ /dev/null @@ -1,100 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include -#include -#include "gccmacro.h" - -#define BUFSIZE 1024 - -/* A simple routine calling UNIX write() in a loop */ -static ssize_t loop_write(int fd, const void*data, size_t size) { - ssize_t ret = 0; - - while (size > 0) { - ssize_t r; - - if ((r = write(fd, data, size)) < 0) - return r; - - if (r == 0) - break; - - ret += r; - data = (const uint8_t*) data + r; - size -= r; - } - - return ret; -} - -int main(PA_GCC_UNUSED int argc, char*argv[]) { - /* The sample type to use */ - static const pa_sample_spec ss = { - .format = PA_SAMPLE_S16LE, - .rate = 44100, - .channels = 2 - }; - pa_simple *s = NULL; - int ret = 1; - int error; - - /* Create the recording stream */ - if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, &error))) { - fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); - goto finish; - } - - for (;;) { - uint8_t buf[BUFSIZE]; - ssize_t r; - - /* Record some data ... */ - if (pa_simple_read(s, buf, sizeof(buf), &error) < 0) { - fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error)); - goto finish; - } - - /* And write it to STDOUT */ - if ((r = loop_write(STDOUT_FILENO, buf, sizeof(buf))) <= 0) { - fprintf(stderr, __FILE__": write() failed: %s\n", strerror(errno)); - goto finish; - } - } - - ret = 0; - -finish: - - if (s) - pa_simple_free(s); - - return ret; -} diff --git a/polyp/parseaddr.c b/polyp/parseaddr.c deleted file mode 100644 index 5e4c689c..00000000 --- a/polyp/parseaddr.c +++ /dev/null @@ -1,112 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "xmalloc.h" -#include "util.h" -#include "parseaddr.h" - -/* Parse addresses in one of the following forms: - * HOSTNAME - * HOSTNAME:PORT - * [HOSTNAME] - * [HOSTNAME]:PORT - * - * Return a newly allocated string of the hostname and fill in *ret_port if specified */ - -static char *parse_host(const char *s, uint16_t *ret_port) { - assert(s && ret_port); - if (*s == '[') { - char *e; - if (!(e = strchr(s+1, ']'))) - return NULL; - - if (e[1] == ':') - *ret_port = atoi(e+2); - else if (e[1] != 0) - return NULL; - - return pa_xstrndup(s+1, e-s-1); - } else { - char *e; - - if (!(e = strrchr(s, ':'))) - return pa_xstrdup(s); - - *ret_port = atoi(e+1); - return pa_xstrndup(s, e-s); - } -} - -int pa_parse_address(const char *name, pa_parsed_address *ret_p) { - const char *p; - assert(name && ret_p); - memset(ret_p, 0, sizeof(pa_parsed_address)); - ret_p->type = PA_PARSED_ADDRESS_TCP_AUTO; - - if (*name == '{') { - char hn[256], *pfx; - /* The URL starts with a host specification for detecting local connections */ - - if (!pa_get_host_name(hn, sizeof(hn))) - return -1; - - pfx = pa_sprintf_malloc("{%s}", hn); - if (!pa_startswith(name, pfx)) { - pa_xfree(pfx); - /* Not local */ - return -1; - } - - p = name + strlen(pfx); - pa_xfree(pfx); - } else - p = name; - - if (*p == '/') - ret_p->type = PA_PARSED_ADDRESS_UNIX; - else if (pa_startswith(p, "unix:")) { - ret_p->type = PA_PARSED_ADDRESS_UNIX; - p += sizeof("unix:")-1; - } else if (pa_startswith(p, "tcp:") || pa_startswith(p, "tcp4:")) { - ret_p->type = PA_PARSED_ADDRESS_TCP4; - p += sizeof("tcp:")-1; - } else if (pa_startswith(p, "tcp6:")) { - ret_p->type = PA_PARSED_ADDRESS_TCP6; - p += sizeof("tcp6:")-1; - } - - if (ret_p->type == PA_PARSED_ADDRESS_UNIX) - ret_p->path_or_host = pa_xstrdup(p); - else - if (!(ret_p->path_or_host = parse_host(p, &ret_p->port))) - return -1; - - - return 0; -} diff --git a/polyp/parseaddr.h b/polyp/parseaddr.h deleted file mode 100644 index eff9dd3b..00000000 --- a/polyp/parseaddr.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef fooparseaddrhfoo -#define fooparseaddrhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -typedef enum pa_parsed_address_type { - PA_PARSED_ADDRESS_UNIX, - PA_PARSED_ADDRESS_TCP4, - PA_PARSED_ADDRESS_TCP6, - PA_PARSED_ADDRESS_TCP_AUTO -} pa_parsed_address_type_t; - -typedef struct pa_parsed_address { - pa_parsed_address_type_t type; - char *path_or_host; - uint16_t port; -} pa_parsed_address; - -int pa_parse_address(const char *a, pa_parsed_address *ret_p); - -#endif diff --git a/polyp/pax11publish.c b/polyp/pax11publish.c deleted file mode 100644 index 42947836..00000000 --- a/polyp/pax11publish.c +++ /dev/null @@ -1,217 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include -#include - -#include "util.h" -#include "log.h" -#include "authkey.h" -#include "native-common.h" -#include "client-conf.h" -#include "x11prop.h" - -int main(int argc, char *argv[]) { - const char *dname = NULL, *sink = NULL, *source = NULL, *server = NULL, *cookie_file = PA_NATIVE_COOKIE_FILE; - int c, ret = 1; - Display *d = NULL; - enum { DUMP, EXPORT, IMPORT, REMOVE } mode = DUMP; - - while ((c = getopt(argc, argv, "deiD:S:O:I:c:hr")) != -1) { - switch (c) { - case 'D' : - dname = optarg; - break; - case 'h': - printf("%s [-D display] [-S server] [-O sink] [-I source] [-c file] [-d|-e|-i|-r]\n\n" - " -d Show current Polypaudio data attached to X11 display (default)\n" - " -e Export local Polypaudio data to X11 display\n" - " -i Import Polypaudio data from X11 display to local environment variables and cookie file.\n" - " -r Remove Polypaudio data from X11 display\n", - pa_path_get_filename(argv[0])); - ret = 0; - goto finish; - case 'd': - mode = DUMP; - break; - case 'e': - mode = EXPORT; - break; - case 'i': - mode = IMPORT; - break; - case 'r': - mode = REMOVE; - break; - case 'c': - cookie_file = optarg; - break; - case 'I': - source = optarg; - break; - case 'O': - sink = optarg; - break; - case 'S': - server = optarg; - break; - default: - fprintf(stderr, "Failed to parse command line.\n"); - goto finish; - } - } - - if (!(d = XOpenDisplay(dname))) { - pa_log(__FILE__": XOpenDisplay() failed\n"); - goto finish; - } - - switch (mode) { - case DUMP: { - char t[1024]; - if (pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) - printf("Server: %s\n", t); - if (pa_x11_get_prop(d, "POLYP_SOURCE", t, sizeof(t))) - printf("Source: %s\n", t); - if (pa_x11_get_prop(d, "POLYP_SINK", t, sizeof(t))) - printf("Sink: %s\n", t); - if (pa_x11_get_prop(d, "POLYP_COOKIE", t, sizeof(t))) - printf("Cookie: %s\n", t); - - break; - } - - case IMPORT: { - char t[1024]; - if (pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) - printf("POLYP_SERVER='%s'\nexport POLYP_SERVER\n", t); - if (pa_x11_get_prop(d, "POLYP_SOURCE", t, sizeof(t))) - printf("POLYP_SOURCE='%s'\nexport POLYP_SOURCE\n", t); - if (pa_x11_get_prop(d, "POLYP_SINK", t, sizeof(t))) - printf("POLYP_SINK='%s'\nexport POLYP_SINK\n", t); - - if (pa_x11_get_prop(d, "POLYP_COOKIE", t, sizeof(t))) { - uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; - size_t l; - if ((l = pa_parsehex(t, cookie, sizeof(cookie))) != sizeof(cookie)) { - fprintf(stderr, "Failed to parse cookie data\n"); - goto finish; - } - - if (pa_authkey_save(cookie_file, cookie, l) < 0) { - fprintf(stderr, "Failed to save cookie data\n"); - goto finish; - } - } - - break; - } - - case EXPORT: { - pa_client_conf *conf = pa_client_conf_new(); - uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; - char hx[PA_NATIVE_COOKIE_LENGTH*2+1]; - assert(conf); - - if (pa_client_conf_load(conf, NULL) < 0) { - fprintf(stderr, "Failed to load client configuration file.\n"); - goto finish; - } - - if (pa_client_conf_env(conf) < 0) { - fprintf(stderr, "Failed to read environment configuration data.\n"); - goto finish; - } - - pa_x11_del_prop(d, "POLYP_SERVER"); - pa_x11_del_prop(d, "POLYP_SINK"); - pa_x11_del_prop(d, "POLYP_SOURCE"); - pa_x11_del_prop(d, "POLYP_ID"); - pa_x11_del_prop(d, "POLYP_COOKIE"); - - if (server) - pa_x11_set_prop(d, "POLYP_SERVER", server); - else if (conf->default_server) - pa_x11_set_prop(d, "POLYP_SERVER", conf->default_server); - else { - char hn[256]; - if (!pa_get_fqdn(hn, sizeof(hn))) { - fprintf(stderr, "Failed to get FQDN.\n"); - goto finish; - } - - pa_x11_set_prop(d, "POLYP_SERVER", hn); - } - - if (sink) - pa_x11_set_prop(d, "POLYP_SINK", sink); - else if (conf->default_sink) - pa_x11_set_prop(d, "POLYP_SINK", conf->default_sink); - - if (source) - pa_x11_set_prop(d, "POLYP_SOURCE", source); - if (conf->default_source) - pa_x11_set_prop(d, "POLYP_SOURCE", conf->default_source); - - pa_client_conf_free(conf); - - if (pa_authkey_load_auto(cookie_file, cookie, sizeof(cookie)) < 0) { - fprintf(stderr, "Failed to load cookie data\n"); - goto finish; - } - - pa_x11_set_prop(d, "POLYP_COOKIE", pa_hexstr(cookie, sizeof(cookie), hx, sizeof(hx))); - break; - } - - case REMOVE: - pa_x11_del_prop(d, "POLYP_SERVER"); - pa_x11_del_prop(d, "POLYP_SINK"); - pa_x11_del_prop(d, "POLYP_SOURCE"); - pa_x11_del_prop(d, "POLYP_ID"); - pa_x11_del_prop(d, "POLYP_COOKIE"); - break; - - default: - fprintf(stderr, "No yet implemented.\n"); - goto finish; - } - - ret = 0; - -finish: - - if (d) { - XSync(d, False); - XCloseDisplay(d); - } - - return ret; -} diff --git a/polyp/pdispatch.c b/polyp/pdispatch.c deleted file mode 100644 index 5a50a0d5..00000000 --- a/polyp/pdispatch.c +++ /dev/null @@ -1,295 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "pdispatch.h" -#include "native-common.h" -#include "xmalloc.h" -#include "llist.h" -#include "log.h" -#include "util.h" - -/*#define DEBUG_OPCODES */ - -#ifdef DEBUG_OPCODES - -static const char *command_names[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = "ERROR", - [PA_COMMAND_TIMEOUT] = "TIMEOUT", - [PA_COMMAND_REPLY] = "REPLY", - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = "CREATE_PLAYBACK_STREAM", - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = "DELETE_PLAYBACK_STREAM", - [PA_COMMAND_CREATE_RECORD_STREAM] = "CREATE_RECORD_STREAM", - [PA_COMMAND_DELETE_RECORD_STREAM] = "DELETE_RECORD_STREAM", - [PA_COMMAND_AUTH] = "AUTH", - [PA_COMMAND_REQUEST] = "REQUEST", - [PA_COMMAND_EXIT] = "EXIT", - [PA_COMMAND_SET_CLIENT_NAME] = "SET_CLIENT_NAME", - [PA_COMMAND_LOOKUP_SINK] = "LOOKUP_SINK", - [PA_COMMAND_LOOKUP_SOURCE] = "LOOKUP_SOURCE", - [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = "DRAIN_PLAYBACK_STREAM", - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = "PLAYBACK_STREAM_KILLED", - [PA_COMMAND_RECORD_STREAM_KILLED] = "RECORD_STREAM_KILLED", - [PA_COMMAND_STAT] = "STAT", - [PA_COMMAND_GET_PLAYBACK_LATENCY] = "PLAYBACK_LATENCY", - [PA_COMMAND_CREATE_UPLOAD_STREAM] = "CREATE_UPLOAD_STREAM", - [PA_COMMAND_DELETE_UPLOAD_STREAM] = "DELETE_UPLOAD_STREAM", - [PA_COMMAND_FINISH_UPLOAD_STREAM] = "FINISH_UPLOAD_STREAM", - [PA_COMMAND_PLAY_SAMPLE] = "PLAY_SAMPLE", - [PA_COMMAND_REMOVE_SAMPLE] = "REMOVE_SAMPLE", - [PA_COMMAND_GET_SERVER_INFO] = "GET_SERVER_INFO", - [PA_COMMAND_GET_SINK_INFO] = "GET_SINK_INFO", - [PA_COMMAND_GET_SINK_INFO_LIST] = "GET_SINK_INFO_LIST", - [PA_COMMAND_GET_SOURCE_INFO] = "GET_SOURCE_INFO", - [PA_COMMAND_GET_SOURCE_INFO_LIST] = "GET_SOURCE_INFO_LIST", - [PA_COMMAND_GET_MODULE_INFO] = "GET_MODULE_INFO", - [PA_COMMAND_GET_MODULE_INFO_LIST] = "GET_MODULE_INFO_LIST", - [PA_COMMAND_GET_CLIENT_INFO] = "GET_CLIENT_INFO", - [PA_COMMAND_GET_CLIENT_INFO_LIST] = "GET_CLIENT_INFO_LIST", - [PA_COMMAND_GET_SAMPLE_INFO] = "GET_SAMPLE_INFO", - [PA_COMMAND_GET_SAMPLE_INFO_LIST] = "GET_SAMPLE_INFO_LIST", - [PA_COMMAND_GET_SINK_INPUT_INFO] = "GET_SINK_INPUT_INFO", - [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = "GET_SINK_INPUT_INFO_LIST", - [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = "GET_SOURCE_OUTPUT_INFO", - [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = "GET_SOURCE_OUTPUT_INFO_LIST", - [PA_COMMAND_SUBSCRIBE] = "SUBSCRIBE", - [PA_COMMAND_SUBSCRIBE_EVENT] = "SUBSCRIBE_EVENT", - [PA_COMMAND_SET_SINK_VOLUME] = "SET_SINK_VOLUME", - [PA_COMMAND_SET_SINK_INPUT_VOLUME] = "SET_SINK_INPUT_VOLUME", - [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = "TRIGGER_PLAYBACK_STREAM", - [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = "FLUSH_PLAYBACK_STREAM", - [PA_COMMAND_CORK_PLAYBACK_STREAM] = "CORK_PLAYBACK_STREAM", - [PA_COMMAND_GET_AUTOLOAD_INFO] = "GET_AUTOLOAD_INFO", - [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = "GET_AUTOLOAD_INFO_LIST", -}; - -#endif - -struct reply_info { - pa_pdispatch *pdispatch; - PA_LLIST_FIELDS(struct reply_info); - pa_pdispatch_callback callback; - void *userdata; - uint32_t tag; - pa_time_event *time_event; -}; - -struct pa_pdispatch { - int ref; - pa_mainloop_api *mainloop; - const pa_pdispatch_callback *callback_table; - unsigned n_commands; - PA_LLIST_HEAD(struct reply_info, replies); - pa_pdispatch_drain_callback drain_callback; - void *drain_userdata; -}; - -static void reply_info_free(struct reply_info *r) { - assert(r && r->pdispatch && r->pdispatch->mainloop); - - if (r->time_event) - r->pdispatch->mainloop->time_free(r->time_event); - - PA_LLIST_REMOVE(struct reply_info, r->pdispatch->replies, r); - - pa_xfree(r); -} - -pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_callback*table, unsigned entries) { - pa_pdispatch *pd; - assert(mainloop); - - assert((entries && table) || (!entries && !table)); - - pd = pa_xmalloc(sizeof(pa_pdispatch)); - pd->ref = 1; - pd->mainloop = mainloop; - pd->callback_table = table; - pd->n_commands = entries; - PA_LLIST_HEAD_INIT(pa_reply_info, pd->replies); - pd->drain_callback = NULL; - pd->drain_userdata = NULL; - - return pd; -} - -static void pdispatch_free(pa_pdispatch *pd) { - assert(pd); - - while (pd->replies) - reply_info_free(pd->replies); - - pa_xfree(pd); -} - -static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command, pa_tagstruct *ts) { - pa_pdispatch_callback callback; - void *userdata; - uint32_t tag; - assert(r); - - pa_pdispatch_ref(pd); - - callback = r->callback; - userdata = r->userdata; - tag = r->tag; - - reply_info_free(r); - - callback(pd, command, tag, ts, userdata); - - if (pd->drain_callback && !pa_pdispatch_is_pending(pd)) - pd->drain_callback(pd, pd->drain_userdata); - - pa_pdispatch_unref(pd); -} - -int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, void *userdata) { - uint32_t tag, command; - pa_tagstruct *ts = NULL; - int ret = -1; - assert(pd && packet && packet->data); - - pa_pdispatch_ref(pd); - - if (packet->length <= 8) - goto finish; - - ts = pa_tagstruct_new(packet->data, packet->length); - assert(ts); - - if (pa_tagstruct_getu32(ts, &command) < 0 || - pa_tagstruct_getu32(ts, &tag) < 0) - goto finish; - -#ifdef DEBUG_OPCODES -{ - char t[256]; - char const *p; - if (!(p = command_names[command])) - snprintf((char*) (p = t), sizeof(t), "%u", command); - - pa_log(__FILE__": Recieved opcode <%s>\n", p); -} -#endif - - if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) { - struct reply_info *r; - - for (r = pd->replies; r; r = r->next) - if (r->tag == tag) - break; - - if (r) - run_action(pd, r, command, ts); - - } else if (pd->callback_table && (command < pd->n_commands) && pd->callback_table[command]) { - const pa_pdispatch_callback *c = pd->callback_table+command; - - (*c)(pd, command, tag, ts, userdata); - } else { - pa_log(__FILE__": Recieved unsupported command %u\n", command); - goto finish; - } - - ret = 0; - -finish: - if (ts) - pa_tagstruct_free(ts); - - pa_pdispatch_unref(pd); - - return ret; -} - -static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - struct reply_info*r = userdata; - assert(r && r->time_event == e && r->pdispatch && r->pdispatch->mainloop == m && r->callback); - - run_action(r->pdispatch, r, PA_COMMAND_TIMEOUT, NULL); -} - -void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_callback cb, void *userdata) { - struct reply_info *r; - struct timeval tv; - assert(pd && pd->ref >= 1 && cb); - - r = pa_xmalloc(sizeof(struct reply_info)); - r->pdispatch = pd; - r->callback = cb; - r->userdata = userdata; - r->tag = tag; - - pa_gettimeofday(&tv); - tv.tv_sec += timeout; - - r->time_event = pd->mainloop->time_new(pd->mainloop, &tv, timeout_callback, r); - assert(r->time_event); - - PA_LLIST_PREPEND(struct reply_info, pd->replies, r); -} - -int pa_pdispatch_is_pending(pa_pdispatch *pd) { - assert(pd); - - return !!pd->replies; -} - -void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, void (*cb)(pa_pdispatch *pd, void *userdata), void *userdata) { - assert(pd); - assert(!cb || pa_pdispatch_is_pending(pd)); - - pd->drain_callback = cb; - pd->drain_userdata = userdata; -} - -void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata) { - struct reply_info *r, *n; - assert(pd); - - for (r = pd->replies; r; r = n) { - n = r->next; - - if (r->userdata == userdata) - reply_info_free(r); - } -} - -void pa_pdispatch_unref(pa_pdispatch *pd) { - assert(pd && pd->ref >= 1); - - if (!(--(pd->ref))) - pdispatch_free(pd); -} - -pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd) { - assert(pd && pd->ref >= 1); - pd->ref++; - return pd; -} diff --git a/polyp/pdispatch.h b/polyp/pdispatch.h deleted file mode 100644 index 40f5d4c4..00000000 --- a/polyp/pdispatch.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef foopdispatchhfoo -#define foopdispatchhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include "tagstruct.h" -#include "packet.h" -#include "mainloop-api.h" - -typedef struct pa_pdispatch pa_pdispatch; - -typedef void (*pa_pdispatch_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); - -pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *m, const pa_pdispatch_callback*table, unsigned entries); -void pa_pdispatch_unref(pa_pdispatch *pd); -pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd); - -int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*p, void *userdata); - -void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_callback callback, void *userdata); - -int pa_pdispatch_is_pending(pa_pdispatch *pd); - -typedef void (*pa_pdispatch_drain_callback)(pa_pdispatch *pd, void *userdata); -void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, pa_pdispatch_drain_callback callback, void *userdata); - -/* Remove all reply slots with the give userdata parameter */ -void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata); - -#endif diff --git a/polyp/pid.c b/polyp/pid.c deleted file mode 100644 index ae3dc7f5..00000000 --- a/polyp/pid.c +++ /dev/null @@ -1,286 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_WINDOWS_H -#include -#endif - -#include "pid.h" -#include "util.h" -#include "log.h" - -/* Read the PID data from the file descriptor fd, and return it. If no - * pid could be read, return 0, on failure (pid_t) -1 */ -static pid_t read_pid(const char *fn, int fd) { - ssize_t r; - char t[20], *e; - uint32_t pid; - - assert(fn && fd >= 0); - - if ((r = pa_loop_read(fd, t, sizeof(t)-1)) < 0) { - pa_log(__FILE__": WARNING: failed to read PID file '%s': %s\n", fn, strerror(errno)); - return (pid_t) -1; - } - - if (r == 0) - return (pid_t) 0; - - t[r] = 0; - if ((e = strchr(t, '\n'))) - *e = 0; - - if (pa_atou(t, &pid) < 0) { - pa_log(__FILE__": WARNING: failed to parse PID file '%s'\n", fn); - return (pid_t) -1; - } - - return (pid_t) pid; -} - -static int open_pid_file(const char *fn, int mode) { - int fd = -1; - int lock = -1; - - for (;;) { - struct stat st; - - pa_make_secure_parent_dir(fn); - - if ((fd = open(fn, mode, S_IRUSR|S_IWUSR)) < 0) { - if (mode != O_RDONLY || errno != ENOENT) - pa_log(__FILE__": WARNING: failed to open PID file '%s': %s\n", fn, strerror(errno)); - goto fail; - } - - /* Try to lock the file. If that fails, go without */ - if (pa_lock_fd(fd, 1) < 0) - goto fail; - - if (fstat(fd, &st) < 0) { - pa_log(__FILE__": Failed to fstat() PID file '%s': %s\n", fn, strerror(errno)); - goto fail; - } - - /* Does the file still exist in the file system? When ye, w're done, otherwise restart */ - if (st.st_nlink >= 1) - break; - - if (pa_lock_fd(fd, 0) < 0) - goto fail; - - if (close(fd) < 0) { - pa_log(__FILE__": Failed to close file '%s': %s\n", fn, strerror(errno)); - goto fail; - } - - fd = -1; - } - - return fd; - -fail: - - if (fd < 0) { - if (lock >= 0) - pa_lock_fd(fd, 0); - - close(fd); - } - - return -1; -} - -/* Create a new PID file for the current process. */ -int pa_pid_file_create(void) { - int fd = -1; - int ret = -1; - char fn[PATH_MAX]; - char t[20]; - pid_t pid; - size_t l; - -#ifdef OS_IS_WIN32 - HANDLE process; -#endif - - pa_runtime_path("pid", fn, sizeof(fn)); - - if ((fd = open_pid_file(fn, O_CREAT|O_RDWR)) < 0) - goto fail; - - if ((pid = read_pid(fn, fd)) == (pid_t) -1) - pa_log(__FILE__": corrupt PID file, overwriting.\n"); - else if (pid > 0) { -#ifdef OS_IS_WIN32 - if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)) != NULL) { - CloseHandle(process); -#else - if (kill(pid, 0) >= 0 || errno != ESRCH) { -#endif - pa_log(__FILE__": daemon already running.\n"); - goto fail; - } - - pa_log(__FILE__": stale PID file, overwriting.\n"); - } - - /* Overwrite the current PID file */ - if (lseek(fd, 0, SEEK_SET) == (off_t) -1 || ftruncate(fd, 0) < 0) { - pa_log(__FILE__": failed to truncate PID fil: %s.\n", strerror(errno)); - goto fail; - } - - snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid()); - l = strlen(t); - - if (pa_loop_write(fd, t, l) != (ssize_t) l) { - pa_log(__FILE__": failed to write PID file.\n"); - goto fail; - } - - ret = 0; - -fail: - if (fd >= 0) { - pa_lock_fd(fd, 0); - close(fd); - } - - return ret; -} - -/* Remove the PID file, if it is ours */ -int pa_pid_file_remove(void) { - int fd = -1; - char fn[PATH_MAX]; - int ret = -1; - pid_t pid; - - pa_runtime_path("pid", fn, sizeof(fn)); - - if ((fd = open_pid_file(fn, O_RDWR)) < 0) { - pa_log(__FILE__": WARNING: failed to open PID file '%s': %s\n", fn, strerror(errno)); - goto fail; - } - - if ((pid = read_pid(fn, fd)) == (pid_t) -1) - goto fail; - - if (pid != getpid()) { - pa_log(__FILE__": WARNING: PID file '%s' not mine!\n", fn); - goto fail; - } - - if (ftruncate(fd, 0) < 0) { - pa_log(__FILE__": failed to truncate PID file '%s': %s\n", fn, strerror(errno)); - goto fail; - } - -#ifdef OS_IS_WIN32 - pa_lock_fd(fd, 0); - close(fd); - fd = -1; -#endif - - if (unlink(fn) < 0) { - pa_log(__FILE__": failed to remove PID file '%s': %s\n", fn, strerror(errno)); - goto fail; - } - - ret = 0; - -fail: - - if (fd >= 0) { - pa_lock_fd(fd, 0); - close(fd); - } - - return ret; -} - -/* Check whether the daemon is currently running, i.e. if a PID file - * exists and the PID therein too. Returns 0 on succcess, -1 - * otherwise. If pid is non-NULL and a running daemon was found, - * return its PID therein */ -int pa_pid_file_check_running(pid_t *pid) { - return pa_pid_file_kill(0, pid); -} - -#ifndef OS_IS_WIN32 - -/* Kill a current running daemon. Return non-zero on success, -1 - * otherwise. If successful *pid contains the PID of the daemon - * process. */ -int pa_pid_file_kill(int sig, pid_t *pid) { - int fd = -1; - char fn[PATH_MAX]; - int ret = -1; - pid_t _pid; - - if (!pid) - pid = &_pid; - - pa_runtime_path("pid", fn, sizeof(fn)); - - if ((fd = open_pid_file(fn, O_RDONLY)) < 0) - goto fail; - - if ((*pid = read_pid(fn, fd)) == (pid_t) -1) - goto fail; - - ret = kill(*pid, sig); - -fail: - - if (fd >= 0) { - pa_lock_fd(fd, 0); - close(fd); - } - - return ret; - -} - -#else /* OS_IS_WIN32 */ - -int pa_pid_file_kill(int sig, pid_t *pid) { - return -1; -} - -#endif diff --git a/polyp/pid.h b/polyp/pid.h deleted file mode 100644 index 906ab6da..00000000 --- a/polyp/pid.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef foopidhfoo -#define foopidhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -int pa_pid_file_create(void); -int pa_pid_file_remove(void); -int pa_pid_file_check_running(pid_t *pid); -int pa_pid_file_kill(int sig, pid_t *pid); - -#endif diff --git a/polyp/play-memchunk.c b/polyp/play-memchunk.c deleted file mode 100644 index e24d4427..00000000 --- a/polyp/play-memchunk.c +++ /dev/null @@ -1,118 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "play-memchunk.h" -#include "sink-input.h" -#include "xmalloc.h" -#include "gccmacro.h" - -static void sink_input_kill(pa_sink_input *i) { - pa_memchunk *c; - assert(i && i->userdata); - c = i->userdata; - - pa_sink_input_disconnect(i); - pa_sink_input_unref(i); - - pa_memblock_unref(c->memblock); - pa_xfree(c); -} - -static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { - pa_memchunk *c; - assert(i && chunk && i->userdata); - c = i->userdata; - - if (c->length <= 0) - return -1; - - assert(c->memblock && c->memblock->length); - *chunk = *c; - pa_memblock_ref(c->memblock); - - return 0; -} - -static void si_kill(PA_GCC_UNUSED pa_mainloop_api *m, void *i) { - sink_input_kill(i); -} - -static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) { - pa_memchunk *c; - assert(i && length && i->userdata); - c = i->userdata; - - assert(!memcmp(chunk, c, sizeof(chunk))); - assert(length <= c->length); - - c->length -= length; - c->index += length; - - if (c->length <= 0) - pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i); -} - -int pa_play_memchunk( - pa_sink *sink, - const char *name, - const pa_sample_spec *ss, - const pa_channel_map *map, - const pa_memchunk *chunk, - pa_cvolume *cvolume) { - - pa_sink_input *si; - pa_memchunk *nchunk; - - assert(sink); - assert(ss); - assert(chunk); - - if (cvolume && pa_cvolume_is_muted(cvolume)) - return 0; - - if (!(si = pa_sink_input_new(sink, name, __FILE__, ss, map, 0, PA_RESAMPLER_INVALID))) - return -1; - - if (cvolume) - si->volume = *cvolume; - - si->peek = sink_input_peek; - si->drop = sink_input_drop; - si->kill = sink_input_kill; - - si->userdata = nchunk = pa_xnew(pa_memchunk, 1); - *nchunk = *chunk; - - pa_memblock_ref(chunk->memblock); - - pa_sink_notify(sink); - - return 0; -} diff --git a/polyp/play-memchunk.h b/polyp/play-memchunk.h deleted file mode 100644 index fc0654a6..00000000 --- a/polyp/play-memchunk.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef fooplaychunkhfoo -#define fooplaychunkhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "sink.h" -#include "memchunk.h" - -int pa_play_memchunk( - pa_sink *sink, - const char *name, - const pa_sample_spec *ss, - const pa_channel_map *map, - const pa_memchunk *chunk, - pa_cvolume *cvolume); - -#endif diff --git a/polyp/poll.c b/polyp/poll.c deleted file mode 100644 index 193fc812..00000000 --- a/polyp/poll.c +++ /dev/null @@ -1,190 +0,0 @@ -/* $Id$ */ - -/*** - Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc. - Copyright (C) 2005, Cendio AB. - This file is part of polypaudio. - Based on work for the GNU C Library. - - polypaudio is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with polypaudio; If not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. -***/ - -/* Poll the file descriptors described by the NFDS structures starting at - FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for - an event to occur; if TIMEOUT is -1, block until an event occurs. - Returns the number of file descriptors with events, zero if timed out, - or -1 for errors. */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#ifdef HAVE_SYS_SELECT_H -#include -#endif - -#include "winsock.h" - -#ifndef HAVE_SYS_POLL_H - -#include "util.h" -#include "poll.h" - -int poll (struct pollfd *fds, unsigned long int nfds, int timeout) { - struct timeval tv; - fd_set rset, wset, xset; - struct pollfd *f; - int ready; - int maxfd = 0; - char data[64]; - - FD_ZERO (&rset); - FD_ZERO (&wset); - FD_ZERO (&xset); - - if (nfds == 0) { - if (timeout >= 0) { - pa_msleep(timeout); - return 0; - } - -#ifdef OS_IS_WIN32 - /* - * Windows does not support signals properly so waiting for them would - * mean a deadlock. - */ - pa_msleep(100); - return 0; -#else - return select(0, NULL, NULL, NULL, NULL); -#endif - } - - for (f = fds; f < &fds[nfds]; ++f) { - if (f->fd != -1) { - if (f->events & POLLIN) - FD_SET (f->fd, &rset); - if (f->events & POLLOUT) - FD_SET (f->fd, &wset); - if (f->events & POLLPRI) - FD_SET (f->fd, &xset); - if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI))) - maxfd = f->fd; - } - } - - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - - ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset, - SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset, - SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv)); - if ((ready == -1) && (errno == EBADF)) { - ready = 0; - - FD_ZERO (&rset); - FD_ZERO (&wset); - FD_ZERO (&xset); - - maxfd = -1; - - for (f = fds; f < &fds[nfds]; ++f) { - if (f->fd != -1) { - fd_set sngl_rset, sngl_wset, sngl_xset; - - FD_ZERO (&sngl_rset); - FD_ZERO (&sngl_wset); - FD_ZERO (&sngl_xset); - - if (f->events & POLLIN) - FD_SET (f->fd, &sngl_rset); - if (f->events & POLLOUT) - FD_SET (f->fd, &sngl_wset); - if (f->events & POLLPRI) - FD_SET (f->fd, &sngl_xset); - if (f->events & (POLLIN|POLLOUT|POLLPRI)) { - struct timeval singl_tv; - - singl_tv.tv_sec = 0; - singl_tv.tv_usec = 0; - - if (select((SELECT_TYPE_ARG1) f->fd, SELECT_TYPE_ARG234 &rset, - SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset, - SELECT_TYPE_ARG5 &singl_tv) != -1) { - if (f->events & POLLIN) - FD_SET (f->fd, &rset); - if (f->events & POLLOUT) - FD_SET (f->fd, &wset); - if (f->events & POLLPRI) - FD_SET (f->fd, &xset); - if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI))) - maxfd = f->fd; - ++ready; - } else if (errno == EBADF) - f->revents |= POLLNVAL; - } - } - } - - if (ready) { - /* Linux alters the tv struct... but it shouldn't matter here ... - * as we're going to be a little bit out anyway as we've just eaten - * more than a couple of cpu cycles above */ - ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset, - SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset, - SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv)); - } - } - -#ifdef OS_IS_WIN32 - errno = WSAGetLastError(); -#endif - - if (ready > 0) { - ready = 0; - for (f = fds; f < &fds[nfds]; ++f) { - f->revents = 0; - if (f->fd != -1) { - if (FD_ISSET (f->fd, &rset)) { - /* support for POLLHUP. An hung up descriptor does not - increase the return value! */ - if (recv (f->fd, data, 64, MSG_PEEK) == -1) { - if (errno == ESHUTDOWN || errno == ECONNRESET || - errno == ECONNABORTED || errno == ENETRESET) { - fprintf(stderr, "Hangup\n"); - f->revents |= POLLHUP; - } - } - - if (f->revents == 0) - f->revents |= POLLIN; - } - if (FD_ISSET (f->fd, &wset)) - f->revents |= POLLOUT; - if (FD_ISSET (f->fd, &xset)) - f->revents |= POLLPRI; - } - if (f->revents) - ready++; - } - } - - return ready; -} - -#endif /* HAVE_SYS_POLL_H */ diff --git a/polyp/poll.h b/polyp/poll.h deleted file mode 100644 index c201014e..00000000 --- a/polyp/poll.h +++ /dev/null @@ -1,57 +0,0 @@ -/* $Id$ */ - -/*** - Compatibility definitions for System V `poll' interface. - Copyright (C) 1994,96,97,98,99,2000,2001,2004 Free Software Foundation, Inc. - Copyright (C) 2005, Cendio AB. - This file is part of polypaudio. - Based on work for the GNU C Library. - - polypaudio is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with polypaudio; If not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. -***/ - -/* Event types that can be polled for. These bits may be set in `events' - to indicate the interesting event types; they will appear in `revents' - to indicate the status of the file descriptor. */ -#define POLLIN 0x001 /* There is data to read. */ -#define POLLPRI 0x002 /* There is urgent data to read. */ -#define POLLOUT 0x004 /* Writing now will not block. */ - -/* Event types always implicitly polled for. These bits need not be set in - `events', but they will appear in `revents' to indicate the status of - the file descriptor. */ -#define POLLERR 0x008 /* Error condition. */ -#define POLLHUP 0x010 /* Hung up. */ -#define POLLNVAL 0x020 /* Invalid polling request. */ - - -/* Type used for the number of file descriptors. */ -typedef unsigned long int nfds_t; - -/* Data structure describing a polling request. */ -struct pollfd - { - int fd; /* File descriptor to poll. */ - short int events; /* Types of events poller cares about. */ - short int revents; /* Types of events that actually occurred. */ - }; - -/* Poll the file descriptors described by the NFDS structures starting at - FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for - an event to occur; if TIMEOUT is -1, block until an event occurs. - Returns the number of file descriptors with events, zero if timed out, - or -1 for errors. */ -extern int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout); diff --git a/polyp/polyplib-browser.c b/polyp/polyplib-browser.c deleted file mode 100644 index 6fee84a4..00000000 --- a/polyp/polyplib-browser.c +++ /dev/null @@ -1,312 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -#include "polyplib-browser.h" -#include "xmalloc.h" -#include "log.h" -#include "util.h" - -#define SERVICE_NAME_SINK "_polypaudio-sink._tcp." -#define SERVICE_NAME_SOURCE "_polypaudio-source._tcp." -#define SERVICE_NAME_SERVER "_polypaudio-server._tcp." - -pa_browser { - int ref; - pa_mainloop_api *mainloop; - - void (*callback)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void *userdata); - void *callback_userdata; - - sw_discovery discovery; - pa_io_event *io_event; -}; - - -static void io_callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags events, void *userdata) { - pa_browser *b = userdata; - assert(a && b && b->mainloop == a); - - if (events != PA_IO_EVENT_INPUT || sw_discovery_read_socket(b->discovery) != SW_OKAY) { - pa_log(__FILE__": connection to HOWL daemon failed.\n"); - b->mainloop->io_free(b->io_event); - b->io_event = NULL; - return; - } -} - -static sw_result resolve_reply( - sw_discovery discovery, - sw_discovery_oid oid, - sw_uint32 interface_index, - sw_const_string name, - sw_const_string type, - sw_const_string domain, - sw_ipv4_address address, - sw_port port, - sw_octets text_record, - sw_ulong text_record_len, - sw_opaque extra) { - - pa_browser *b = extra; - pa_browse_info i; - char ip[256], a[256]; - pa_browse_opcode opcode; - int device_found = 0; - uint32_t cookie; - pa_typeid_t typeid; - pa_sample_spec ss; - int ss_valid = 0; - sw_text_record_iterator iterator; - int free_iterator = 0; - char *c = NULL; - - assert(b); - - sw_discovery_cancel(discovery, oid); - - memset(&i, 0, sizeof(i)); - i.name = name; - - if (!b->callback) - goto fail; - - if (!strcmp(type, SERVICE_NAME_SINK)) - opcode = PA_BROWSE_NEW_SINK; - else if (!strcmp(type, SERVICE_NAME_SOURCE)) - opcode = PA_BROWSE_NEW_SOURCE; - else if (!strcmp(type, SERVICE_NAME_SERVER)) - opcode = PA_BROWSE_NEW_SERVER; - else - goto fail; - - - snprintf(a, sizeof(a), "tcp:%s:%u", sw_ipv4_address_name(address, ip, sizeof(ip)), port); - i.server = a; - - if (text_record && text_record_len) { - char key[SW_TEXT_RECORD_MAX_LEN]; - uint8_t val[SW_TEXT_RECORD_MAX_LEN]; - uint32_t val_len; - - if (sw_text_record_iterator_init(&iterator, text_record, text_record_len) != SW_OKAY) { - pa_log("sw_text_record_string_iterator_init() failed.\n"); - goto fail; - } - - free_iterator = 1; - - while (sw_text_record_iterator_next(iterator, key, val, &val_len) == SW_OKAY) { - c = pa_xstrndup((char*) val, val_len); - - if (!strcmp(key, "device")) { - device_found = 1; - pa_xfree((char*) i.device); - i.device = c; - c = NULL; - } else if (!strcmp(key, "server-version")) { - pa_xfree((char*) i.server_version); - i.server_version = c; - c = NULL; - } else if (!strcmp(key, "user-name")) { - pa_xfree((char*) i.user_name); - i.user_name = c; - c = NULL; - } else if (!strcmp(key, "fqdn")) { - size_t l; - - pa_xfree((char*) i.fqdn); - i.fqdn = c; - c = NULL; - - l = strlen(a); - assert(l+1 <= sizeof(a)); - strncat(a, " ", sizeof(a)-l-1); - strncat(a, i.fqdn, sizeof(a)-l-2); - } else if (!strcmp(key, "cookie")) { - - if (pa_atou(c, &cookie) < 0) - goto fail; - - i.cookie = &cookie; - } else if (!strcmp(key, "description")) { - pa_xfree((char*) i.description); - i.description = c; - c = NULL; - } else if (!strcmp(key, "typeid")) { - - if (pa_atou(c, &typeid) < 0) - goto fail; - - i.typeid = &typeid; - } else if (!strcmp(key, "channels")) { - uint32_t ch; - - if (pa_atou(c, &ch) < 0 || ch <= 0 || ch > 255) - goto fail; - - ss.channels = (uint8_t) ch; - ss_valid |= 1; - - } else if (!strcmp(key, "rate")) { - if (pa_atou(c, &ss.rate) < 0) - goto fail; - ss_valid |= 2; - } else if (!strcmp(key, "format")) { - - if ((ss.format = pa_parse_sample_format(c)) == PA_SAMPLE_INVALID) - goto fail; - - ss_valid |= 4; - } - - pa_xfree(c); - c = NULL; - } - - } - - /* No device txt record was sent for a sink or source service */ - if (opcode != PA_BROWSE_NEW_SERVER && !device_found) - goto fail; - - if (ss_valid == 7) - i.sample_spec = &ss; - - - b->callback(b, opcode, &i, b->callback_userdata); - -fail: - pa_xfree((void*) i.device); - pa_xfree((void*) i.fqdn); - pa_xfree((void*) i.server_version); - pa_xfree((void*) i.user_name); - pa_xfree((void*) i.description); - pa_xfree(c); - - if (free_iterator) - sw_text_record_iterator_fina(iterator); - - - return SW_OKAY; -} - -static sw_result browse_reply( - sw_discovery discovery, - sw_discovery_oid id, - sw_discovery_browse_status status, - sw_uint32 interface_index, - sw_const_string name, - sw_const_string type, - sw_const_string domain, - sw_opaque extra) { - - pa_browser *b = extra; - assert(b); - - switch (status) { - case SW_DISCOVERY_BROWSE_ADD_SERVICE: { - sw_discovery_oid oid; - - if (sw_discovery_resolve(b->discovery, 0, name, type, domain, resolve_reply, b, &oid) != SW_OKAY) - pa_log("sw_discovery_resolve() failed\n"); - - break; - } - - case SW_DISCOVERY_BROWSE_REMOVE_SERVICE: - if (b->callback) { - pa_browse_info i; - memset(&i, 0, sizeof(i)); - i.name = name; - b->callback(b, PA_BROWSE_REMOVE, &i, b->callback_userdata); - } - break; - - default: - ; - } - - return SW_OKAY; -} - -pa_browser *pa_browser_new(pa_mainloop_api *mainloop) { - pa_browser *b; - sw_discovery_oid oid; - - b = pa_xmalloc(sizeof(pa_browser)); - b->mainloop = mainloop; - b->ref = 1; - b->callback = NULL; - b->callback_userdata = NULL; - - if (sw_discovery_init(&b->discovery) != SW_OKAY) { - pa_log("sw_discovery_init() failed.\n"); - pa_xfree(b); - return NULL; - } - - if (sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SERVER, NULL, browse_reply, b, &oid) != SW_OKAY || - sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SINK, NULL, browse_reply, b, &oid) != SW_OKAY || - sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SOURCE, NULL, browse_reply, b, &oid) != SW_OKAY) { - - pa_log("sw_discovery_browse() failed.\n"); - - sw_discovery_fina(b->discovery); - pa_xfree(b); - return NULL; - } - - b->io_event = mainloop->io_new(mainloop, sw_discovery_socket(b->discovery), PA_IO_EVENT_INPUT, io_callback, b); - return b; -} - -static void browser_free(pa_browser *b) { - assert(b && b->mainloop); - - if (b->io_event) - b->mainloop->io_free(b->io_event); - - sw_discovery_fina(b->discovery); - pa_xfree(b); -} - -pa_browser *pa_browser_ref(pa_browser *b) { - assert(b && b->ref >= 1); - b->ref++; - return b; -} - -void pa_browser_unref(pa_browser *b) { - assert(b && b->ref >= 1); - - if ((-- (b->ref)) <= 0) - browser_free(b); -} - -void pa_browser_set_callback(pa_browser *b, void (*cb)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void* userdata), void *userdata) { - assert(b); - - b->callback = cb; - b->callback_userdata = userdata; -} diff --git a/polyp/polyplib-browser.h b/polyp/polyplib-browser.h deleted file mode 100644 index 853304d7..00000000 --- a/polyp/polyplib-browser.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef foopolyplibbrowserhfoo -#define foopolyplibbrowserhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include - -PA_C_DECL_BEGIN - -pa_browser; - -pa_browse_opcode { - PA_BROWSE_NEW_SERVER, - PA_BROWSE_NEW_SINK, - PA_BROWSE_NEW_SOURCE, - PA_BROWSE_REMOVE -}; - -pa_browser *pa_browser_new(pa_mainloop_api *mainloop); -pa_browser *pa_browser_ref(pa_browser *z); -void pa_browser_unref(pa_browser *z); - -pa_browse_info { - /* Unique service name */ - const char *name; /* always available */ - - /* Server info */ - const char *server; /* always available */ - const char *server_version, *user_name, *fqdn; /* optional */ - const uint32_t *cookie; /* optional */ - - /* Device info */ - const char *device; /* always available when this information is of a sink/source */ - const char *description; /* optional */ - const pa_typeid_t *typeid; /* optional */ - const pa_sample_spec *sample_spec; /* optional */ -}; - -void pa_browser_set_callback(pa_browser *z, void (*cb)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void *userdata), void *userdata); - -PA_C_DECL_END - -#endif diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c deleted file mode 100644 index 15f2e4cd..00000000 --- a/polyp/polyplib-context.c +++ /dev/null @@ -1,871 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_WAIT_H -#include -#endif - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif - -#include "winsock.h" - -#include "polyplib-internal.h" -#include "polyplib-context.h" -#include "polyplib-version.h" -#include "native-common.h" -#include "pdispatch.h" -#include "pstream.h" -#include "dynarray.h" -#include "socket-client.h" -#include "pstream-util.h" -#include "util.h" -#include "xmalloc.h" -#include "log.h" -#include "client-conf.h" -#include "socket-util.h" - -#ifdef HAVE_X11 -#include "client-conf-x11.h" -#endif - -#define AUTOSPAWN_LOCK "autospawn.lock" - -static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_REQUEST] = pa_command_request, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = pa_command_stream_killed, - [PA_COMMAND_RECORD_STREAM_KILLED] = pa_command_stream_killed, - [PA_COMMAND_SUBSCRIBE_EVENT] = pa_command_subscribe_event -}; - -static void unlock_autospawn_lock_file(pa_context *c) { - assert(c); - - if (c->autospawn_lock_fd >= 0) { - char lf[PATH_MAX]; - pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); - - pa_unlock_lockfile(lf, c->autospawn_lock_fd); - c->autospawn_lock_fd = -1; - } -} - -pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { - pa_context *c; - assert(mainloop && name); - - c = pa_xmalloc(sizeof(pa_context)); - c->ref = 1; - c->name = pa_xstrdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - c->record_streams = pa_dynarray_new(); - assert(c->playback_streams && c->record_streams); - - PA_LLIST_HEAD_INIT(pa_stream, c->streams); - PA_LLIST_HEAD_INIT(pa_operation, c->operations); - - c->error = PA_ERROR_OK; - c->state = PA_CONTEXT_UNCONNECTED; - c->ctag = 0; - - c->state_callback = NULL; - c->state_userdata = NULL; - - c->subscribe_callback = NULL; - c->subscribe_userdata = NULL; - - c->memblock_stat = pa_memblock_stat_new(); - c->local = -1; - c->server_list = NULL; - c->server = NULL; - c->autospawn_lock_fd = -1; - memset(&c->spawn_api, 0, sizeof(c->spawn_api)); - c->do_autospawn = 0; - -#ifdef SIGPIPE - pa_check_signal_is_blocked(SIGPIPE); -#endif - - c->conf = pa_client_conf_new(); - pa_client_conf_load(c->conf, NULL); -#ifdef HAVE_X11 - pa_client_conf_from_x11(c->conf, NULL); -#endif - pa_client_conf_env(c->conf); - - return c; -} - -static void context_free(pa_context *c) { - assert(c); - - unlock_autospawn_lock_file(c); - - while (c->operations) - pa_operation_cancel(c->operations); - - while (c->streams) - pa_stream_set_state(c->streams, PA_STREAM_TERMINATED); - - if (c->client) - pa_socket_client_unref(c->client); - if (c->pdispatch) - pa_pdispatch_unref(c->pdispatch); - if (c->pstream) { - pa_pstream_close(c->pstream); - pa_pstream_unref(c->pstream); - } - - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - pa_memblock_stat_unref(c->memblock_stat); - - if (c->conf) - pa_client_conf_free(c->conf); - - pa_strlist_free(c->server_list); - - pa_xfree(c->name); - pa_xfree(c->server); - pa_xfree(c); -} - -pa_context* pa_context_ref(pa_context *c) { - assert(c && c->ref >= 1); - c->ref++; - return c; -} - -void pa_context_unref(pa_context *c) { - assert(c && c->ref >= 1); - - if ((--(c->ref)) == 0) - context_free(c); -} - -void pa_context_set_state(pa_context *c, pa_context_state_t st) { - assert(c); - - if (c->state == st) - return; - - pa_context_ref(c); - - if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) { - pa_stream *s; - - s = c->streams ? pa_stream_ref(c->streams) : NULL; - while (s) { - pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL; - pa_stream_set_state(s, st == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED); - pa_stream_unref(s); - s = n; - } - - if (c->pdispatch) - pa_pdispatch_unref(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) { - pa_pstream_close(c->pstream); - pa_pstream_unref(c->pstream); - } - c->pstream = NULL; - - if (c->client) - pa_socket_client_unref(c->client); - c->client = NULL; - } - - c->state = st; - if (c->state_callback) - c->state_callback(c, c->state_userdata); - - pa_context_unref(c); -} - -void pa_context_fail(pa_context *c, int error) { - assert(c); - c->error = error; - pa_context_set_state(c, PA_CONTEXT_FAILED); -} - -static void pstream_die_callback(pa_pstream *p, void *userdata) { - pa_context *c = userdata; - assert(p && c); - pa_context_fail(c, PA_ERROR_CONNECTIONTERMINATED); -} - -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { - pa_context *c = userdata; - assert(p && packet && c); - - pa_context_ref(c); - - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - pa_log(__FILE__": invalid packet.\n"); - pa_context_fail(c, PA_ERROR_PROTOCOL); - } - - pa_context_unref(c); -} - -static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, PA_GCC_UNUSED uint32_t delta, const pa_memchunk *chunk, void *userdata) { - pa_context *c = userdata; - pa_stream *s; - assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - - pa_context_ref(c); - - if ((s = pa_dynarray_get(c->record_streams, channel))) { - pa_mcalign_push(s->mcalign, chunk); - - for (;;) { - pa_memchunk t; - - if (pa_mcalign_pop(s->mcalign, &t) < 0) - break; - - if (s->read_callback) { - s->read_callback(s, (uint8_t*) t.memblock->data + t.index, t.length, s->read_userdata); - s->counter += chunk->length; - } - - pa_memblock_unref(t.memblock); - } - } - - pa_context_unref(c); -} - -int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t) { - assert(c); - - if (command == PA_COMMAND_ERROR) { - assert(t); - - if (pa_tagstruct_getu32(t, &c->error) < 0) { - pa_context_fail(c, PA_ERROR_PROTOCOL); - return -1; - - } - } else if (command == PA_COMMAND_TIMEOUT) - c->error = PA_ERROR_TIMEOUT; - else { - pa_context_fail(c, PA_ERROR_PROTOCOL); - return -1; - } - - return 0; -} - -static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_context *c = userdata; - assert(pd && c && (c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME)); - - pa_context_ref(c); - - if (command != PA_COMMAND_REPLY) { - - if (pa_context_handle_error(c, command, t) < 0) - pa_context_fail(c, PA_ERROR_PROTOCOL); - - pa_context_fail(c, c->error); - goto finish; - } - - switch(c->state) { - case PA_CONTEXT_AUTHORIZING: { - pa_tagstruct *reply; - reply = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME); - pa_tagstruct_putu32(reply, tag = c->ctag++); - pa_tagstruct_puts(reply, c->name); - pa_pstream_send_tagstruct(c->pstream, reply); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - - pa_context_set_state(c, PA_CONTEXT_SETTING_NAME); - break; - } - - case PA_CONTEXT_SETTING_NAME : - pa_context_set_state(c, PA_CONTEXT_READY); - break; - - default: - assert(0); - } - -finish: - pa_context_unref(c); -} - -static void setup_context(pa_context *c, pa_iochannel *io) { - pa_tagstruct *t; - uint32_t tag; - assert(c && io); - - pa_context_ref(c); - - assert(!c->pstream); - c->pstream = pa_pstream_new(c->mainloop, io, c->memblock_stat); - assert(c->pstream); - - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - - assert(!c->pdispatch); - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); - - if (!c->conf->cookie_valid) { - pa_context_fail(c, PA_ERROR_AUTHKEY); - goto finish; - } - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie)); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - - pa_context_set_state(c, PA_CONTEXT_AUTHORIZING); - -finish: - - pa_context_unref(c); -} - -static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata); - -#ifndef OS_IS_WIN32 - -static int context_connect_spawn(pa_context *c) { - pid_t pid; - int status, r; - int fds[2] = { -1, -1} ; - pa_iochannel *io; - - pa_context_ref(c); - - if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { - pa_log(__FILE__": socketpair() failed: %s\n", strerror(errno)); - pa_context_fail(c, PA_ERROR_INTERNAL); - goto fail; - } - - pa_fd_set_cloexec(fds[0], 1); - - pa_socket_low_delay(fds[0]); - pa_socket_low_delay(fds[1]); - - if (c->spawn_api.prefork) - c->spawn_api.prefork(); - - if ((pid = fork()) < 0) { - pa_log(__FILE__": fork() failed: %s\n", strerror(errno)); - pa_context_fail(c, PA_ERROR_INTERNAL); - - if (c->spawn_api.postfork) - c->spawn_api.postfork(); - - goto fail; - } else if (!pid) { - /* Child */ - - char t[128]; - const char *state = NULL; -#define MAX_ARGS 64 - const char * argv[MAX_ARGS+1]; - int n; - - /* Not required, since fds[0] has CLOEXEC enabled anyway */ - close(fds[0]); - - if (c->spawn_api.atfork) - c->spawn_api.atfork(); - - /* Setup argv */ - - n = 0; - - argv[n++] = c->conf->daemon_binary; - argv[n++] = "--daemonize=yes"; - - snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]); - argv[n++] = strdup(t); - - while (n < MAX_ARGS) { - char *a; - - if (!(a = pa_split_spaces(c->conf->extra_arguments, &state))) - break; - - argv[n++] = a; - } - - argv[n++] = NULL; - - execv(argv[0], (char * const *) argv); - _exit(1); -#undef MAX_ARGS - } - - /* Parent */ - - r = waitpid(pid, &status, 0); - - if (c->spawn_api.postfork) - c->spawn_api.postfork(); - - if (r < 0) { - pa_log(__FILE__": waitpid() failed: %s\n", strerror(errno)); - pa_context_fail(c, PA_ERROR_INTERNAL); - goto fail; - } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); - goto fail; - } - - close(fds[1]); - - c->local = 1; - - io = pa_iochannel_new(c->mainloop, fds[0], fds[0]); - - setup_context(c, io); - unlock_autospawn_lock_file(c); - - pa_context_unref(c); - - return 0; - -fail: - if (fds[0] != -1) - close(fds[0]); - if (fds[1] != -1) - close(fds[1]); - - unlock_autospawn_lock_file(c); - - pa_context_unref(c); - - return -1; -} - -#endif /* OS_IS_WIN32 */ - -static int try_next_connection(pa_context *c) { - char *u = NULL; - int r = -1; - assert(c && !c->client); - - for (;;) { - if (u) - pa_xfree(u); - u = NULL; - - c->server_list = pa_strlist_pop(c->server_list, &u); - - if (!u) { - -#ifndef OS_IS_WIN32 - if (c->do_autospawn) { - r = context_connect_spawn(c); - goto finish; - } -#endif - - pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); - goto finish; - } - - pa_log_debug(__FILE__": Trying to connect to %s...\n", u); - - pa_xfree(c->server); - c->server = pa_xstrdup(u); - - if (!(c->client = pa_socket_client_new_string(c->mainloop, u, PA_NATIVE_DEFAULT_PORT))) - continue; - - c->local = pa_socket_client_is_local(c->client); - pa_socket_client_set_callback(c->client, on_connection, c); - break; - } - - r = 0; - -finish: - if (u) - pa_xfree(u); - - return r; -} - -static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata) { - pa_context *c = userdata; - assert(client && c && c->state == PA_CONTEXT_CONNECTING); - - pa_context_ref(c); - - pa_socket_client_unref(client); - c->client = NULL; - - if (!io) { - /* Try the item in the list */ - if (errno == ECONNREFUSED || errno == ETIMEDOUT || errno == EHOSTUNREACH) { - try_next_connection(c); - goto finish; - } - - pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); - goto finish; - } - - unlock_autospawn_lock_file(c); - setup_context(c, io); - -finish: - pa_context_unref(c); -} - -int pa_context_connect(pa_context *c, const char *server, int spawn, const pa_spawn_api *api) { - int r = -1; - assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED); - - if (!server) - server = c->conf->default_server; - - pa_context_ref(c); - - assert(!c->server_list); - - if (server) { - if (!(c->server_list = pa_strlist_parse(server))) { - pa_context_fail(c, PA_ERROR_INVALIDSERVER); - goto finish; - } - } else { - char *d; - char ufn[PATH_MAX]; - - /* Prepend in reverse order */ - - if ((d = getenv("DISPLAY"))) { - char *e; - d = pa_xstrdup(d); - if ((e = strchr(d, ':'))) - *e = 0; - - if (*d) - c->server_list = pa_strlist_prepend(c->server_list, d); - - pa_xfree(d); - } - - c->server_list = pa_strlist_prepend(c->server_list, "tcp6:localhost"); - c->server_list = pa_strlist_prepend(c->server_list, "localhost"); - c->server_list = pa_strlist_prepend(c->server_list, pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET, ufn, sizeof(ufn))); - - /* Wrap the connection attempts in a single transaction for sane autospawn locking */ - if (spawn && c->conf->autospawn) { - char lf[PATH_MAX]; - - pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); - pa_make_secure_parent_dir(lf); - assert(c->autospawn_lock_fd <= 0); - c->autospawn_lock_fd = pa_lock_lockfile(lf); - - if (api) - c->spawn_api = *api; - c->do_autospawn = 1; - } - - } - - pa_context_set_state(c, PA_CONTEXT_CONNECTING); - r = try_next_connection(c); - -finish: - pa_context_unref(c); - - return r; -} - -void pa_context_disconnect(pa_context *c) { - assert(c); - pa_context_set_state(c, PA_CONTEXT_TERMINATED); -} - -pa_context_state_t pa_context_get_state(pa_context *c) { - assert(c && c->ref >= 1); - return c->state; -} - -int pa_context_errno(pa_context *c) { - assert(c && c->ref >= 1); - return c->error; -} - -void pa_context_set_state_callback(pa_context *c, void (*cb)(pa_context *c, void *userdata), void *userdata) { - assert(c && c->ref >= 1); - c->state_callback = cb; - c->state_userdata = userdata; -} - -int pa_context_is_pending(pa_context *c) { - assert(c && c->ref >= 1); - -/* pa_log("pstream: %i\n", pa_pstream_is_pending(c->pstream)); */ -/* pa_log("pdispatch: %i\n", pa_pdispatch_is_pending(c->pdispatch)); */ - - return (c->pstream && pa_pstream_is_pending(c->pstream)) || - (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) || - c->client; -} - -static void set_dispatch_callbacks(pa_operation *o); - -static void pdispatch_drain_callback(PA_GCC_UNUSED pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void pstream_drain_callback(PA_GCC_UNUSED pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void set_dispatch_callbacks(pa_operation *o) { - int done = 1; - assert(o && o->context && o->context->ref >= 1 && o->ref >= 1 && o->context->state == PA_CONTEXT_READY); - - pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(o->context->pdispatch)) { - pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o); - done = 0; - } - - if (pa_pstream_is_pending(o->context->pstream)) { - pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o); - done = 0; - } - - if (!done) - pa_operation_ref(o); - else { - if (o->callback) { - void (*cb)(pa_context *c, void *userdata); - cb = (void (*)(pa_context*, void*)) o->callback; - cb(o->context, o->userdata); - } - - pa_operation_done(o); - } - - pa_operation_unref(o); -} - -pa_operation* pa_context_drain(pa_context *c, void (*cb) (pa_context*c, void *userdata), void *userdata) { - pa_operation *o; - assert(c && c->ref >= 1); - - if (c->state != PA_CONTEXT_READY) - return NULL; - - if (!pa_context_is_pending(c)) - return NULL; - - o = pa_operation_new(c, NULL); - assert(o); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - set_dispatch_callbacks(pa_operation_ref(o)); - - return o; -} - -void pa_context_exit_daemon(pa_context *c) { - pa_tagstruct *t; - assert(c && c->ref >= 1); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); -} - -void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int success = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - success = 0; - } else if (!pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *c, int _success, void *_userdata) = (void (*)(pa_context *c, int _success, void *_userdata)) o->callback; - cb(o->context, success, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, void (*internal_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata), void (*cb)(void), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, command); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_DEFAULT_SINK); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_set_default_source(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_DEFAULT_SOURCE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -int pa_context_is_local(pa_context *c) { - assert(c); - return c->local; -} - -pa_operation* pa_context_set_name(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && name && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_CLIENT_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -const char* pa_get_library_version(void) { - return PACKAGE_VERSION; -} - -const char* pa_context_get_server(pa_context *c) { - - if (!c->server) - return NULL; - - if (*c->server == '{') { - char *e = strchr(c->server+1, '}'); - return e ? e+1 : c->server; - } - - return c->server; -} diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h deleted file mode 100644 index febb75f4..00000000 --- a/polyp/polyplib-context.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef foopolyplibcontexthfoo -#define foopolyplibcontexthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include -#include - -/** \file - * Connection contexts for asynchrononous communication with a - * server. A pa_context object wraps a connection to a polypaudio - * server using its native protocol. A context may be used to issue - * commands on the server or to create playback or recording - * streams. Multiple playback streams may be piped through a single - * connection context. Operations on the contect involving - * communication with the server are executed asynchronously: i.e. the - * client function do not implicitely wait for completion of the - * operation on the server. Instead the caller specifies a call back - * function that is called when the operation is completed. Currently - * running operations may be canceled using pa_operation_cancel(). */ - -/** \example pacat.c - * A playback and recording tool using the asynchronous API */ - -/** \example paplay.c - * A sound file playback tool using the asynchronous API, based on libsndfile */ - -PA_C_DECL_BEGIN - -/** \pa_context - * An opaque connection context to a daemon */ -typedef struct pa_context pa_context; - -/** Instantiate a new connection context with an abstract mainloop API - * and an application name */ -pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name); - -/** Decrease the reference counter of the context by one */ -void pa_context_unref(pa_context *c); - -/** Increase the reference counter of the context by one */ -pa_context* pa_context_ref(pa_context *c); - -typedef void (*pa_context_state_callback)(pa_context *c, void *userdata); - -/** Set a callback function that is called whenever the context status changes */ -void pa_context_set_state_callback(pa_context *c, pa_context_state_callback callback, void *userdata); - -/** Return the error number of the last failed operation */ -int pa_context_errno(pa_context *c); - -/** Return non-zero if some data is pending to be written to the connection */ -int pa_context_is_pending(pa_context *c); - -/** Return the current context status */ -pa_context_state_t pa_context_get_state(pa_context *c); - -/** Connect the context to the specified server. If server is NULL, -connect to the default server. This routine may but will not always -return synchronously on error. Use pa_context_set_state_callback() to -be notified when the connection is established. If spawn is non-zero -and no specific server is specified or accessible a new daemon is -spawned. If api is non-NULL, the functions specified in the structure -are used when forking a new child process. */ -int pa_context_connect(pa_context *c, const char *server, int spawn, const pa_spawn_api *api); - -/** Terminate the context connection immediately */ -void pa_context_disconnect(pa_context *c); - -/** Drain the context. If there is nothing to drain, the function returns NULL */ -pa_operation* pa_context_drain(pa_context *c, void (*cb) (pa_context*c, void *userdata), void *userdata); - -/** Tell the daemon to exit. No operation object is returned as the - * connection is terminated when the daemon quits, thus this operation - * would never complete. */ -void pa_context_exit_daemon(pa_context *c); - -/** Set the name of the default sink. \since 0.4 */ -pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata); - -/** Set the name of the default source. \since 0.4 */ -pa_operation* pa_context_set_default_source(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata); - -/** Returns 1 when the connection is to a local daemon. Returns negative when no connection has been made yet. \since 0.5 */ -int pa_context_is_local(pa_context *c); - -/** Set a different application name for context on the server. \since 0.5 */ -pa_operation* pa_context_set_name(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata); - -/** Return the server name this context is connected to. \since 0.7 */ -const char* pa_context_get_server(pa_context *c); - -PA_C_DECL_END - -#endif diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h deleted file mode 100644 index 0591ce6c..00000000 --- a/polyp/polyplib-def.h +++ /dev/null @@ -1,213 +0,0 @@ -#ifndef foopolyplibdefhfoo -#define foopolyplibdefhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include - -#include -#include - -/** \file - * Global definitions */ - -PA_C_DECL_BEGIN - -/** The state of a connection context */ -typedef enum pa_context_state { - PA_CONTEXT_UNCONNECTED, /**< The context hasn't been connected yet */ - PA_CONTEXT_CONNECTING, /**< A connection is being established */ - PA_CONTEXT_AUTHORIZING, /**< The client is authorizing itself to the daemon */ - PA_CONTEXT_SETTING_NAME, /**< The client is passing its application name to the daemon */ - PA_CONTEXT_READY, /**< The connection is established, the context is ready to execute operations */ - PA_CONTEXT_FAILED, /**< The connection failed or was disconnected */ - PA_CONTEXT_TERMINATED /**< The connection was terminated cleanly */ -} pa_context_state_t; - -/** The state of a stream */ -typedef enum pa_stream_state { - PA_STREAM_DISCONNECTED, /**< The stream is not yet connected to any sink or source */ - PA_STREAM_CREATING, /**< The stream is being created */ - PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */ - PA_STREAM_FAILED, /**< An error occured that made the stream invalid */ - PA_STREAM_TERMINATED /**< The stream has been terminated cleanly */ -} pa_stream_state_t; - -/** The state of an operation */ -typedef enum pa_operation_state { - PA_OPERATION_RUNNING, /**< The operation is still running */ - PA_OPERATION_DONE, /**< The operation has been completed */ - PA_OPERATION_CANCELED /**< The operation has been canceled */ -} pa_operation_state_t; - -/** An invalid index */ -#define PA_INVALID_INDEX ((uint32_t) -1) - -/** The direction of a pa_stream object */ -typedef enum pa_stream_direction { - PA_STREAM_NODIRECTION, /**< Invalid direction */ - PA_STREAM_PLAYBACK, /**< Playback stream */ - PA_STREAM_RECORD, /**< Record stream */ - PA_STREAM_UPLOAD /**< Sample upload stream */ -} pa_stream_direction_t; - -/** Some special flags for stream connections. \since 0.6 */ -typedef enum pa_stream_flags { - PA_STREAM_START_CORKED = 1, /**< Create the stream corked, requiring an explicit pa_stream_cork() call to uncork it. */ - PA_STREAM_INTERPOLATE_LATENCY = 2 /**< Interpolate the latency for - * this stream. When enabled, - * you can use - * pa_stream_interpolated_xxx() - * for synchronization. Using - * these functions instead of - * pa_stream_get_latency() has - * the advantage of not - * requiring a whole roundtrip - * for responses. Consider using - * this option when frequently - * requesting latency - * information. This is - * especially useful on long latency - * network connections. */ -} pa_stream_flags_t; - -/** Playback and record buffer metrics */ -typedef struct pa_buffer_attr { - uint32_t maxlength; /**< Maximum length of the buffer */ - uint32_t tlength; /**< Playback only: target length of the buffer. The server tries to assure that at least tlength bytes are always available in the buffer */ - uint32_t prebuf; /**< Playback only: pre-buffering. The server does not start with playback before at least prebug bytes are available in the buffer */ - uint32_t minreq; /**< Playback only: minimum request. The server does not request less than minreq bytes from the client, instead waints until the buffer is free enough to request more bytes at once */ - uint32_t fragsize; /**< Recording only: fragment size. The server sends data in blocks of fragsize bytes size. Large values deminish interactivity with other operations on the connection context but decrease control overhead. */ -} pa_buffer_attr; - -/** Error values as used by pa_context_errno(). Use pa_strerror() to convert these values to human readable strings */ -enum { - PA_ERROR_OK, /**< No error */ - PA_ERROR_ACCESS, /**< Access failure */ - PA_ERROR_COMMAND, /**< Unknown command */ - PA_ERROR_INVALID, /**< Invalid argument */ - PA_ERROR_EXIST, /**< Entity exists */ - PA_ERROR_NOENTITY, /**< No such entity */ - PA_ERROR_CONNECTIONREFUSED, /**< Connection refused */ - PA_ERROR_PROTOCOL, /**< Protocol error */ - PA_ERROR_TIMEOUT, /**< Timeout */ - PA_ERROR_AUTHKEY, /**< No authorization key */ - PA_ERROR_INTERNAL, /**< Internal error */ - PA_ERROR_CONNECTIONTERMINATED, /**< Connection terminated */ - PA_ERROR_KILLED, /**< Entity killed */ - PA_ERROR_INVALIDSERVER, /**< Invalid server */ - PA_ERROR_INITFAILED, /**< Module initialization failed */ - PA_ERROR_MAX /**< Not really an error but the first invalid error code */ -}; - -/** Subscription event mask, as used by pa_context_subscribe() */ -typedef enum pa_subscription_mask { - PA_SUBSCRIPTION_MASK_NULL = 0, /**< No events */ - PA_SUBSCRIPTION_MASK_SINK = 1, /**< Sink events */ - PA_SUBSCRIPTION_MASK_SOURCE = 2, /**< Source events */ - PA_SUBSCRIPTION_MASK_SINK_INPUT = 4, /**< Sink input events */ - PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8, /**< Source output events */ - PA_SUBSCRIPTION_MASK_MODULE = 16, /**< Module events */ - PA_SUBSCRIPTION_MASK_CLIENT = 32, /**< Client events */ - PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, /**< Sample cache events */ - PA_SUBSCRIPTION_MASK_SERVER = 128, /**< Other global server changes. \since 0.4 */ - PA_SUBSCRIPTION_MASK_AUTOLOAD = 256 /**< Autoload table events. \since 0.5 */ -} pa_subscription_mask_t; - -/** Subscription event types, as used by pa_context_subscribe() */ -typedef enum pa_subscription_event_type { - PA_SUBSCRIPTION_EVENT_SINK = 0, /**< Event type: Sink */ - PA_SUBSCRIPTION_EVENT_SOURCE = 1, /**< Event type: Source */ - PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2, /**< Event type: Sink input */ - PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 3, /**< Event type: Source output */ - PA_SUBSCRIPTION_EVENT_MODULE = 4, /**< Event type: Module */ - PA_SUBSCRIPTION_EVENT_CLIENT = 5, /**< Event type: Client */ - PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, /**< Event type: Sample cache item */ - PA_SUBSCRIPTION_EVENT_SERVER = 7, /**< Event type: Global server change, only occuring with PA_SUBSCRIPTION_EVENT_CHANGE. \since 0.4 */ - PA_SUBSCRIPTION_EVENT_AUTOLOAD = 8, /**< Event type: Autoload table changes. \since 0.5 */ - PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 15, /**< A mask to extract the event type from an event value */ - - PA_SUBSCRIPTION_EVENT_NEW = 0, /**< A new object was created */ - PA_SUBSCRIPTION_EVENT_CHANGE = 16, /**< A property of the object was modified */ - PA_SUBSCRIPTION_EVENT_REMOVE = 32, /**< An object was removed */ - PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32 /**< A mask to extract the event operation from an event value */ -} pa_subscription_event_type_t; - -/** Return one if an event type t matches an event mask bitfield */ -#define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) - -/** A structure for latency info. See pa_stream_get_latency(). The - * total output latency a sample that is written with - * pa_stream_write() takes to be played may be estimated by - * sink_usec+buffer_usec+transport_usec. The output buffer to which - * buffer_usec relates may be manipulated freely (with - * pa_stream_write()'s delta argument, pa_stream_flush() and friends), - * the buffers sink_usec/source_usec relates to is a first-in - * first-out buffer which cannot be flushed or manipulated in any - * way. The total input latency a sample that is recorded takes to be - * delivered to the application is: - * source_usec+buffer_usec+transport_usec-sink_usec. (Take care of - * sign issues!) When connected to a monitor source sink_usec contains - * the latency of the owning sink.*/ -typedef struct pa_latency_info { - pa_usec_t buffer_usec; /**< Time in usecs the current buffer takes to play. For both playback and record streams. */ - pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. For playback streams and record streams connected to a monitor source. */ - pa_usec_t source_usec; /**< Time in usecs a sample takes from being recorded to being delivered to the application. Only for record streams. \since 0.5*/ - pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to/from the daemon. For both playback and record streams. \since 0.5 */ - int playing; /**< Non-zero when the stream is currently playing. Only for playback streams. */ - uint32_t queue_length; /**< Queue size in bytes. For both playback and record streams. */ - int synchronized_clocks; /**< Non-zero if the local and the - * remote machine have synchronized - * clocks. If synchronized clocks are - * detected transport_usec becomes much - * more reliable. However, the code that - * detects synchronized clocks is very - * limited und unreliable itself. \since - * 0.5 */ - struct timeval timestamp; /**< The time when this latency info was current */ - uint64_t counter; /**< The byte counter current when the latency info was requested. \since 0.6 */ -} pa_latency_info; - -/** A structure for the spawn api. This may be used to integrate auto - * spawned daemons into your application. For more information see - * pa_context_connect(). When spawning a new child process the - * waitpid() is used on the child's PID. The spawn routine will not - * block or ignore SIGCHLD signals, since this cannot be done in a - * thread compatible way. You might have to do this in - * prefork/postfork. \since 0.4 */ -typedef struct pa_spawn_api { - void (*prefork)(void); /**< Is called just before the fork in the parent process. May be NULL. */ - void (*postfork)(void); /**< Is called immediately after the fork in the parent process. May be NULL.*/ - void (*atfork)(void); /**< Is called immediately after the - * fork in the child process. May be - * NULL. It is not safe to close all - * file descriptors in this function - * unconditionally, since a UNIX socket - * (created using socketpair()) is - * passed to the new process. */ -} pa_spawn_api; - -PA_C_DECL_END - -#endif diff --git a/polyp/polyplib-error.c b/polyp/polyplib-error.c deleted file mode 100644 index 50a67270..00000000 --- a/polyp/polyplib-error.c +++ /dev/null @@ -1,54 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "polyplib-error.h" -#include "native-common.h" - -static const char* const errortab[PA_ERROR_MAX] = { - [PA_ERROR_OK] = "OK", - [PA_ERROR_ACCESS] = "Access denied", - [PA_ERROR_COMMAND] = "Unknown command", - [PA_ERROR_INVALID] = "Invalid argument", - [PA_ERROR_EXIST] = "Entity exists", - [PA_ERROR_NOENTITY] = "No such entity", - [PA_ERROR_CONNECTIONREFUSED] = "Connection refused", - [PA_ERROR_PROTOCOL] = "Protocol error", - [PA_ERROR_TIMEOUT] = "Timeout", - [PA_ERROR_AUTHKEY] = "No authorization key", - [PA_ERROR_INTERNAL] = "Internal error", - [PA_ERROR_CONNECTIONTERMINATED] = "Connection terminated", - [PA_ERROR_KILLED] = "Entity killed", - [PA_ERROR_INVALIDSERVER] = "Invalid server", -}; - -const char*pa_strerror(uint32_t error) { - if (error >= PA_ERROR_MAX) - return NULL; - - return errortab[error]; -} diff --git a/polyp/polyplib-error.h b/polyp/polyplib-error.h deleted file mode 100644 index dbbbf006..00000000 --- a/polyp/polyplib-error.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef foopolypliberrorhfoo -#define foopolypliberrorhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include "cdecl.h" - -/** \file - * Error management */ - -PA_C_DECL_BEGIN - -/** Return a human readable error message for the specified numeric error code */ -const char* pa_strerror(uint32_t error); - -PA_C_DECL_END - -#endif diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h deleted file mode 100644 index 29596069..00000000 --- a/polyp/polyplib-internal.h +++ /dev/null @@ -1,154 +0,0 @@ -#ifndef foopolyplibinternalhfoo -#define foopolyplibinternalhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "mainloop-api.h" -#include "socket-client.h" -#include "pstream.h" -#include "pdispatch.h" -#include "dynarray.h" - -#include "polyplib-context.h" -#include "polyplib-stream.h" -#include "polyplib-operation.h" -#include "llist.h" -#include "native-common.h" -#include "client-conf.h" -#include "strlist.h" -#include "mcalign.h" - -#define DEFAULT_TIMEOUT (10) - -struct pa_context { - int ref; - - char *name; - pa_mainloop_api* mainloop; - - pa_socket_client *client; - pa_pstream *pstream; - pa_pdispatch *pdispatch; - - pa_dynarray *record_streams, *playback_streams; - PA_LLIST_HEAD(pa_stream, streams); - PA_LLIST_HEAD(pa_operation, operations); - - uint32_t ctag; - uint32_t error; - pa_context_state_t state; - - void (*state_callback)(pa_context*c, void *userdata); - void *state_userdata; - - void (*subscribe_callback)(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata); - void *subscribe_userdata; - - pa_memblock_stat *memblock_stat; - - int local; - int do_autospawn; - int autospawn_lock_fd; - pa_spawn_api spawn_api; - - pa_strlist *server_list; - - char *server; - - pa_client_conf *conf; -}; - -struct pa_stream { - int ref; - pa_context *context; - pa_mainloop_api *mainloop; - PA_LLIST_FIELDS(pa_stream); - - char *name; - pa_buffer_attr buffer_attr; - pa_sample_spec sample_spec; - pa_channel_map channel_map; - uint32_t channel; - int channel_valid; - uint32_t device_index; - pa_stream_direction_t direction; - uint32_t requested_bytes; - uint64_t counter; - pa_usec_t previous_time; - pa_usec_t previous_ipol_time; - pa_stream_state_t state; - pa_mcalign *mcalign; - - int interpolate; - int corked; - - uint32_t ipol_usec; - struct timeval ipol_timestamp; - pa_time_event *ipol_event; - int ipol_requested; - - void (*state_callback)(pa_stream*c, void *userdata); - void *state_userdata; - - void (*read_callback)(pa_stream *p, const void*data, size_t length, void *userdata); - void *read_userdata; - - void (*write_callback)(pa_stream *p, size_t length, void *userdata); - void *write_userdata; -}; - -typedef void (*pa_operation_callback)(void); - -struct pa_operation { - int ref; - pa_context *context; - pa_stream *stream; - PA_LLIST_FIELDS(pa_operation); - - pa_operation_state_t state; - void *userdata; - pa_operation_callback callback; -}; - -void pa_command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); - -pa_operation *pa_operation_new(pa_context *c, pa_stream *s); -void pa_operation_done(pa_operation *o); - -void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); - -void pa_context_fail(pa_context *c, int error); -void pa_context_set_state(pa_context *c, pa_context_state_t st); -int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t); -pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, void (*internal_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata), void (*cb)(void), void *userdata); - -void pa_stream_set_state(pa_stream *s, pa_stream_state_t st); - -void pa_stream_trash_ipol(pa_stream *s); - - -#endif diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c deleted file mode 100644 index 49298a96..00000000 --- a/polyp/polyplib-introspect.c +++ /dev/null @@ -1,1003 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "polyplib-introspect.h" -#include "polyplib-context.h" -#include "polyplib-internal.h" -#include "pstream-util.h" -#include "gccmacro.h" - -/*** Statistics ***/ - -static void context_stat_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - pa_stat_info i, *p = &i; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - p = NULL; - } else if (pa_tagstruct_getu32(t, &i.memblock_total) < 0 || - pa_tagstruct_getu32(t, &i.memblock_total_size) < 0 || - pa_tagstruct_getu32(t, &i.memblock_allocated) < 0 || - pa_tagstruct_getu32(t, &i.memblock_allocated_size) < 0 || - pa_tagstruct_getu32(t, &i.scache_size) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_stat_info*_i, void *_userdata) = (void (*)(pa_context *s, const pa_stat_info*_i, void *_userdata)) o->callback; - cb(o->context, p, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_stat(pa_context *c, void (*cb)(pa_context *c, const pa_stat_info*i, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_STAT, context_stat_callback, (pa_operation_callback) cb, userdata); -} - -/*** Server Info ***/ - -static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - pa_server_info i, *p = &i; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - p = NULL; - } else if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_gets(t, &i.default_sink_name) < 0 || - pa_tagstruct_gets(t, &i.default_source_name) < 0 || - pa_tagstruct_getu32(t, &i.cookie) < 0 || - !pa_tagstruct_eof(t)) { - - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_server_info*_i, void *_userdata) = (void (*)(pa_context *s, const pa_server_info*_i, void *_userdata)) o->callback; - cb(o->context, p, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_server_info(pa_context *c, void (*cb)(pa_context *c, const pa_server_info*i, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SERVER_INFO, context_get_server_info_callback, (pa_operation_callback) cb, userdata); -} - -/*** Sink Info ***/ - -static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eof = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_sink_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_get_cvolume(t, &i.volume) < 0 || - pa_tagstruct_getu32(t, &i.monitor_source) < 0 || - pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || - pa_tagstruct_get_usec(t, &i.latency) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0) { - - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_sink_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INFO_LIST, context_get_sink_info_callback, (pa_operation_callback) cb, userdata); -} - -pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, o); - - return pa_operation_ref(o); -} - -/*** Source info ***/ - -static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eof = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_source_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || - pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 || - pa_tagstruct_get_usec(t, &i.latency) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0) { - - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_source_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_INFO_LIST, context_get_source_info_callback, (pa_operation_callback) cb, userdata); -} - -pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, o); - - return pa_operation_ref(o); -} - -/*** Client info ***/ - -static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eof = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_client_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0 ) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_client_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_CLIENT_INFO_LIST, context_get_client_info_callback, (pa_operation_callback) cb, userdata); -} - -/*** Module info ***/ - -static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eof = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_module_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_get_boolean(t, &i.auto_unload) < 0) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_module_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_MODULE_INFO_LIST, context_get_module_info_callback, (pa_operation_callback) cb, userdata); -} - -/*** Sink input info ***/ - -static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eof = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_sink_input_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.client) < 0 || - pa_tagstruct_getu32(t, &i.sink) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_get_cvolume(t, &i.volume) < 0 || - pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || - pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || - pa_tagstruct_gets(t, &i.resample_method) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0) { - - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INPUT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_input_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_sink_input_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INPUT_INFO_LIST, context_get_sink_input_info_callback, (pa_operation_callback) cb, userdata); -} - -/*** Source output info ***/ - -static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eof = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_source_output_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.client) < 0 || - pa_tagstruct_getu32(t, &i.source) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || - pa_tagstruct_get_usec(t, &i.source_usec) < 0 || - pa_tagstruct_gets(t, &i.resample_method) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0) { - - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata))o->callback; - cb(o->context, NULL, eof, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_OUTPUT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_output_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_source_output_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, context_get_source_output_info_callback, (pa_operation_callback) cb, userdata); -} - -/*** Volume manipulation ***/ - -pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && idx != PA_INVALID_INDEX); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_tagstruct_put_cvolume(t, volume); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && name); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_cvolume(t, volume); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && idx != PA_INVALID_INDEX); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_put_cvolume(t, volume); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -/** Sample Cache **/ - -static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eof = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_sample_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_get_cvolume(t, &i.volume) < 0 || - pa_tagstruct_get_usec(t, &i.duration) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_getu32(t, &i.bytes) < 0 || - pa_tagstruct_get_boolean(t, &i.lazy) < 0 || - pa_tagstruct_gets(t, &i.filename) < 0) { - - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb && name); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SAMPLE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SAMPLE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_sample_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SAMPLE_INFO_LIST, context_get_sample_info_callback, (pa_operation_callback) cb, userdata); -} - -static pa_operation* command_kill(pa_context *c, uint32_t command, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && idx != PA_INVALID_INDEX); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, command); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - return command_kill(c, PA_COMMAND_KILL_CLIENT, idx, cb, userdata); -} - -pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - return command_kill(c, PA_COMMAND_KILL_SINK_INPUT, idx, cb, userdata); -} - -pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - return command_kill(c, PA_COMMAND_KILL_SOURCE_OUTPUT, idx, cb, userdata); -} - -static void load_module_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - uint32_t idx = -1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - } else if (pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *c, uint32_t _idx, void *_userdata) = (void (*)(pa_context *c, uint32_t _idx, void *_userdata)) o->callback; - cb(o->context, idx, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, void (*cb)(pa_context *c, uint32_t idx, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && name && argument); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_LOAD_MODULE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_puts(t, argument); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, load_module_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - return command_kill(c, PA_COMMAND_UNLOAD_MODULE, idx, cb, userdata); -} - -/*** Autoload stuff ***/ - -static void context_get_autoload_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eof = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_autoload_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_getu32(t, &i.type) < 0 || - pa_tagstruct_gets(t, &i.module) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb && name); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_AUTOLOAD_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_putu32(t, type); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb && idx != PA_INVALID_INDEX); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_AUTOLOAD_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_autoload_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, context_get_autoload_info_callback, (pa_operation_callback) cb, userdata); -} - -static void context_add_autoload_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - uint32_t idx; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - idx = PA_INVALID_INDEX; - } else if (pa_tagstruct_getu32(t, &idx) || - !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, uint32_t _idx, void *_userdata) = (void (*)(pa_context *s, uint32_t _idx, void *_userdata)) o->callback; - cb(o->context, idx, o->userdata); - } - - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && name && module && argument); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_ADD_AUTOLOAD); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_putu32(t, type); - pa_tagstruct_puts(t, module); - pa_tagstruct_puts(t, argument); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_add_autoload_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && name); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_AUTOLOAD); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_putu32(t, type); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && idx != PA_INVALID_INDEX); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_AUTOLOAD); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h deleted file mode 100644 index d3489908..00000000 --- a/polyp/polyplib-introspect.h +++ /dev/null @@ -1,279 +0,0 @@ -#ifndef foopolyplibintrospecthfoo -#define foopolyplibintrospecthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include -#include -#include -#include -#include - -/** \file - * - * Routines for daemon introspection. When enumerating all entitites - * of a certain kind, use the pa_context_xxx_list() functions. The - * specified callback function is called once for each entry. The - * enumeration is finished by a call to the callback function with - * is_last=1 and i=NULL. Strings referenced in pa_xxx_info structures - * and the structures themselves point to internal memory that may not - * be modified. That memory is only valid during the call to the - * callback function. A deep copy is required if you need this data - * outside the callback functions. An error is signalled by a call to * the callback function with i=NULL and is_last=0. - * - * When using the routines that ask fo a single entry only, a callback - * with the same signature is used. However, no finishing call to the - * routine is issued. */ - -PA_C_DECL_BEGIN - -/** Stores information about sinks */ -typedef struct pa_sink_info { - const char *name; /**< Name of the sink */ - uint32_t index; /**< Index of the sink */ - const char *description; /**< Description of this sink */ - pa_sample_spec sample_spec; /**< Sample spec of this sink */ - pa_channel_map channel_map; /**< Channel map \since 0.9 */ - uint32_t owner_module; /**< Index of the owning module of this sink, or PA_INVALID_INDEX */ - pa_cvolume volume; /**< Volume of the sink */ - uint32_t monitor_source; /**< Index of the monitor source connected to this sink */ - const char *monitor_source_name; /**< The name of the monitor source */ - pa_usec_t latency; /**< Length of filled playback buffer of this sink */ - const char *driver; /**< Driver name. \since 0.9 */ -} pa_sink_info; - -/** Get information about a sink by its name */ -pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata); - -/** Get information about a sink by its index */ -pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t id, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata); - -/** Get the complete sink list */ -pa_operation* pa_context_get_sink_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata); - -/** Stores information about sources */ -typedef struct pa_source_info { - const char *name ; /**< Name of the source */ - uint32_t index; /**< Index of the source */ - const char *description; /**< Description of this source */ - pa_sample_spec sample_spec; /**< Sample spec of this source */ - pa_channel_map channel_map; /**< Channel map \since 0.9 */ - uint32_t owner_module; /**< Owning module index, or PA_INVALID_INDEX */ - uint32_t monitor_of_sink; /**< If this is a monitor source the index of the owning sink, otherwise PA_INVALID_INDEX */ - const char *monitor_of_sink_name; /**< Name of the owning sink, or PA_INVALID_INDEX */ - pa_usec_t latency; /**< Length of filled record buffer of this source. \since 0.5 */ - const char *driver; /**< Driver name \since 0.9 */ -} pa_source_info; - -/** Get information about a source by its name */ -pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata); - -/** Get information about a source by its index */ -pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t id, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata); - -/** Get the complete source list */ -pa_operation* pa_context_get_source_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata); - -/** Server information */ -typedef struct pa_server_info { - const char *user_name; /**< User name of the daemon process */ - const char *host_name; /**< Host name the daemon is running on */ - const char *server_version; /**< Version string of the daemon */ - const char *server_name; /**< Server package name (usually "polypaudio") */ - pa_sample_spec sample_spec; /**< Default sample specification */ - const char *default_sink_name; /**< Name of default sink. \since 0.4 */ - const char *default_source_name; /**< Name of default sink. \since 0.4*/ - uint32_t cookie; /**< A random cookie for identifying this instance of polypaudio. \since 0.8 */ -} pa_server_info; - -/** Get some information about the server */ -pa_operation* pa_context_get_server_info(pa_context *c, void (*cb)(pa_context *c, const pa_server_info*i, void *userdata), void *userdata); - -/** Stores information about modules */ -typedef struct pa_module_info { - uint32_t index; /**< Index of the module */ - const char*name, /**< Name of the module */ - *argument; /**< Argument string of the module */ - uint32_t n_used; /**< Usage counter or PA_INVALID_INDEX */ - int auto_unload; /**< Non-zero if this is an autoloaded module */ -} pa_module_info; - -/** Get some information about a module by its index */ -pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata); - -/** Get the complete list of currently loaded modules */ -pa_operation* pa_context_get_module_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata); - -/** Stores information about clients */ -typedef struct pa_client_info { - uint32_t index; /**< Index of this client */ - const char *name; /**< Name of this client */ - uint32_t owner_module; /**< Index of the owning module, or PA_INVALID_INDEX */ - const char *driver; /**< Driver name \since 0.9 */ -} pa_client_info; - -/** Get information about a client by its index */ -pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata); - -/** Get the complete client list */ -pa_operation* pa_context_get_client_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata); - -/** Stores information about sink inputs */ -typedef struct pa_sink_input_info { - uint32_t index; /**< Index of the sink input */ - const char *name; /**< Name of the sink input */ - uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ - uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ - uint32_t sink; /**< Index of the connected sink */ - pa_sample_spec sample_spec; /**< The sample specification of the sink input */ - pa_channel_map channel_map; /**< Channel map */ - pa_cvolume volume; /**< The volume of this sink input */ - pa_usec_t buffer_usec; /**< Latency due to buffering in sink input, see pa_latency_info for details */ - pa_usec_t sink_usec; /**< Latency of the sink device, see pa_latency_info for details */ - const char *resample_method; /**< Thre resampling method used by this sink input. \since 0.7 */ - const char *driver; /**< Driver name \since 0.9 */ -} pa_sink_input_info; - -/** Get some information about a sink input by its index */ -pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata); - -/** Get the complete sink input list */ -pa_operation* pa_context_get_sink_input_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata); - -/** Stores information about source outputs */ -typedef struct pa_source_output_info { - uint32_t index; /**< Index of the sink input */ - const char *name; /**< Name of the sink input */ - uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ - uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ - uint32_t source; /**< Index of the connected source */ - pa_sample_spec sample_spec; /**< The sample specification of the source output */ - pa_channel_map channel_map; /**< Channel map */ - pa_usec_t buffer_usec; /**< Latency due to buffering in the source output, see pa_latency_info for details. \since 0.5 */ - pa_usec_t source_usec; /**< Latency of the source device, see pa_latency_info for details. \since 0.5 */ - const char *resample_method; /**< Thre resampling method used by this source output. \since 0.7 */ - const char *driver; /**< Driver name \since 0.9 */ -} pa_source_output_info; - -/** Get information about a source output by its index */ -pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata); - -/** Get the complete list of source outputs */ -pa_operation* pa_context_get_source_output_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata); - -/** Set the volume of a sink device specified by its index */ -pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -/** Set the volume of a sink device specified by its name */ -pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -/** Set the volume of a sink input stream */ -pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -/** Memory block statistics */ -typedef struct pa_stat_info { - uint32_t memblock_total; /**< Currently allocated memory blocks */ - uint32_t memblock_total_size; /**< Currentl total size of allocated memory blocks */ - uint32_t memblock_allocated; /**< Allocated memory blocks during the whole lifetime of the daemon */ - uint32_t memblock_allocated_size; /**< Total size of all memory blocks allocated during the whole lifetime of the daemon */ - uint32_t scache_size; /**< Total size of all sample cache entries. \since 0.4 */ -} pa_stat_info; - -/** Get daemon memory block statistics */ -pa_operation* pa_context_stat(pa_context *c, void (*cb)(pa_context *c, const pa_stat_info *i, void *userdata), void *userdata); - -/** Stores information about sample cache entries */ -typedef struct pa_sample_info { - uint32_t index; /**< Index of this entry */ - const char *name; /**< Name of this entry */ - pa_cvolume volume; /**< Default volume of this entry */ - pa_sample_spec sample_spec; /**< Sample specification of the sample */ - pa_channel_map channel_map; /**< The channel map */ - pa_usec_t duration; /**< Duration of this entry */ - uint32_t bytes; /**< Length of this sample in bytes. \since 0.4 */ - int lazy; /**< Non-zero when this is a lazy cache entry. \since 0.5 */ - const char *filename; /**< In case this is a lazy cache entry, the filename for the sound file to be loaded on demand. \since 0.5 */ -} pa_sample_info; - -/** Get information about a sample by its name */ -pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata); - -/** Get information about a sample by its index */ -pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata); - -/** Get the complete list of samples stored in the daemon. */ -pa_operation* pa_context_get_sample_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata); - -/** Kill a client. \since 0.5 */ -pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -/** Kill a sink input. \since 0.5 */ -pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -/** Kill a source output. \since 0.5 */ -pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -/** Load a module. \since 0.5 */ -pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, void (*cb)(pa_context *c, uint32_t idx, void *userdata), void *userdata); - -/** Unload a module. \since 0.5 */ -pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -/** Type of an autoload entry. \since 0.5 */ -typedef enum pa_autoload_type { - PA_AUTOLOAD_SINK = 0, - PA_AUTOLOAD_SOURCE = 1 -} pa_autoload_type_t; - -/** Stores information about autoload entries. \since 0.5 */ -typedef struct pa_autoload_info { - uint32_t index; /**< Index of this autoload entry */ - const char *name; /**< Name of the sink or source */ - pa_autoload_type_t type; /**< Type of the autoload entry */ - const char *module; /**< Module name to load */ - const char *argument; /**< Argument string for module */ -} pa_autoload_info; - -/** Get info about a specific autoload entry. \since 0.6 */ -pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); - -/** Get info about a specific autoload entry. \since 0.6 */ -pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); - -/** Get the complete list of autoload entries. \since 0.5 */ -pa_operation* pa_context_get_autoload_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); - -/** Add a new autoload entry. \since 0.5 */ -pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, void (*cb)(pa_context *c, int idx, void *userdata), void* userdata); - -/** Remove an autoload entry. \since 0.6 */ -pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata); - -/** Remove an autoload entry. \since 0.6 */ -pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void* userdata); - - -PA_C_DECL_END - -#endif diff --git a/polyp/polyplib-operation.c b/polyp/polyplib-operation.c deleted file mode 100644 index 68bc8c6a..00000000 --- a/polyp/polyplib-operation.c +++ /dev/null @@ -1,103 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "xmalloc.h" -#include "polyplib-internal.h" -#include "polyplib-operation.h" - -pa_operation *pa_operation_new(pa_context *c, pa_stream *s) { - pa_operation *o; - assert(c); - - o = pa_xmalloc(sizeof(pa_operation)); - o->ref = 1; - o->context = pa_context_ref(c); - o->stream = s ? pa_stream_ref(s) : NULL; - - o->state = PA_OPERATION_RUNNING; - o->userdata = NULL; - o->callback = NULL; - - PA_LLIST_PREPEND(pa_operation, o->context->operations, o); - return pa_operation_ref(o); -} - -pa_operation *pa_operation_ref(pa_operation *o) { - assert(o && o->ref >= 1); - o->ref++; - return o; -} - -void pa_operation_unref(pa_operation *o) { - assert(o && o->ref >= 1); - - if ((--(o->ref)) == 0) { - assert(!o->context); - assert(!o->stream); - free(o); - } -} - -static void operation_set_state(pa_operation *o, pa_operation_state_t st) { - assert(o && o->ref >= 1); - - if (st == o->state) - return; - - if (!o->context) - return; - - o->state = st; - - if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) { - PA_LLIST_REMOVE(pa_operation, o->context->operations, o); - pa_context_unref(o->context); - if (o->stream) - pa_stream_unref(o->stream); - o->context = NULL; - o->stream = NULL; - o->callback = NULL; - o->userdata = NULL; - - pa_operation_unref(o); - } -} - -void pa_operation_cancel(pa_operation *o) { - assert(o && o->ref >= 1); - operation_set_state(o, PA_OPERATION_CANCELED); -} - -void pa_operation_done(pa_operation *o) { - assert(o && o->ref >= 1); - operation_set_state(o, PA_OPERATION_DONE); -} - -pa_operation_state_t pa_operation_get_state(pa_operation *o) { - assert(o && o->ref >= 1); - return o->state; -} diff --git a/polyp/polyplib-operation.h b/polyp/polyplib-operation.h deleted file mode 100644 index cac03e30..00000000 --- a/polyp/polyplib-operation.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef foopolypliboperationhfoo -#define foopolypliboperationhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -/** \file - * Asynchronous operations */ - -PA_C_DECL_BEGIN - -/** \pa_operation - * An asynchronous operation object */ -typedef struct pa_operation pa_operation; - -/** Increase the reference count by one */ -pa_operation *pa_operation_ref(pa_operation *o); - -/** Decrease the reference count by one */ -void pa_operation_unref(pa_operation *o); - -/** Cancel the operation. Beware! This will not necessarily cancel the execution of the operation on the server side. */ -void pa_operation_cancel(pa_operation *o); - -/** Return the current status of the operation */ -pa_operation_state_t pa_operation_get_state(pa_operation *o); - -PA_C_DECL_END - -#endif diff --git a/polyp/polyplib-scache.c b/polyp/polyplib-scache.c deleted file mode 100644 index 01c64828..00000000 --- a/polyp/polyplib-scache.c +++ /dev/null @@ -1,127 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "polyplib-scache.h" -#include "polyplib-internal.h" -#include "pstream-util.h" - -void pa_stream_connect_upload(pa_stream *s, size_t length) { - pa_tagstruct *t; - uint32_t tag; - - assert(s && length); - - pa_stream_ref(s); - - s->state = PA_STREAM_CREATING; - s->direction = PA_STREAM_UPLOAD; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, length); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s); - - pa_stream_unref(s); -} - -void pa_stream_finish_upload(pa_stream *s) { - pa_tagstruct *t; - uint32_t tag; - assert(s); - - if (!s->channel_valid || !s->context->state == PA_CONTEXT_READY) - return; - - pa_stream_ref(s); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s); - - pa_stream_unref(s); -} - -pa_operation * pa_context_play_sample(pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && name && *name && (!dev || *dev)); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - if (!dev) - dev = c->conf->default_sink; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev); - pa_tagstruct_putu32(t, volume); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_remove_sample(pa_context *c, const char *name, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && name); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - diff --git a/polyp/polyplib-scache.h b/polyp/polyplib-scache.h deleted file mode 100644 index 89d27597..00000000 --- a/polyp/polyplib-scache.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef foopolyplibscachehfoo -#define foopolyplibscachehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include -#include -#include - -/** \file - * All sample cache related routines */ - -PA_C_DECL_BEGIN - -/** Make this stream a sample upload stream */ -void pa_stream_connect_upload(pa_stream *s, size_t length); - -/** Finish the sample upload, the stream name will become the sample name. You cancel a sample upload by issuing pa_stream_disconnect() */ -void pa_stream_finish_upload(pa_stream *s); - -/** Play a sample from the sample cache to the specified device. If the latter is NULL use the default sink. Returns an operation object */ -pa_operation* pa_context_play_sample(pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -/** Remove a sample from the sample cache. Returns an operation object which may be used to cancel the operation while it is running */ -pa_operation* pa_context_remove_sample(pa_context *c, const char *name, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -PA_C_DECL_END - -#endif diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c deleted file mode 100644 index e5512152..00000000 --- a/polyp/polyplib-simple.c +++ /dev/null @@ -1,393 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "polyplib-simple.h" -#include "polyplib.h" -#include "mainloop.h" -#include "native-common.h" -#include "xmalloc.h" -#include "log.h" - -struct pa_simple { - pa_mainloop *mainloop; - pa_context *context; - pa_stream *stream; - pa_stream_direction_t direction; - - int dead; - - void *read_data; - size_t read_index, read_length; - pa_usec_t latency; -}; - -static void read_callback(pa_stream *s, const void*data, size_t length, void *userdata); - -static int check_error(pa_simple *p, int *rerror) { - pa_context_state_t cst; - pa_stream_state_t sst; - assert(p); - - if ((cst = pa_context_get_state(p->context)) == PA_CONTEXT_FAILED) - goto fail; - - assert(cst != PA_CONTEXT_TERMINATED); - - if (p->stream) { - if ((sst = pa_stream_get_state(p->stream)) == PA_STREAM_FAILED) - goto fail; - - assert(sst != PA_STREAM_TERMINATED); - } - - return 0; - -fail: - if (rerror) - *rerror = pa_context_errno(p->context); - - p->dead = 1; - - return -1; -} - -static int iterate(pa_simple *p, int block, int *rerror) { - assert(p && p->context && p->mainloop); - - if (check_error(p, rerror) < 0) - return -1; - - if (!block && !pa_context_is_pending(p->context)) - return 0; - - do { - if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) { - if (rerror) - *rerror = PA_ERROR_INTERNAL; - return -1; - } - - if (check_error(p, rerror) < 0) - return -1; - - } while (pa_context_is_pending(p->context)); - - - while (pa_mainloop_deferred_pending(p->mainloop)) { - - if (pa_mainloop_iterate(p->mainloop, 0, NULL) < 0) { - if (rerror) - *rerror = PA_ERROR_INTERNAL; - return -1; - } - - if (check_error(p, rerror) < 0) - return -1; - } - - return 0; -} - -pa_simple* pa_simple_new( - const char *server, - const char *name, - pa_stream_direction_t dir, - const char *dev, - const char *stream_name, - const pa_sample_spec *ss, - const pa_buffer_attr *attr, - int *rerror) { - - pa_simple *p; - int error = PA_ERROR_INTERNAL; - assert(ss && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); - - p = pa_xmalloc(sizeof(pa_simple)); - p->context = NULL; - p->stream = NULL; - p->mainloop = pa_mainloop_new(); - assert(p->mainloop); - p->dead = 0; - p->direction = dir; - p->read_data = NULL; - p->read_index = p->read_length = 0; - p->latency = 0; - - if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name))) - goto fail; - - pa_context_connect(p->context, server, 1, NULL); - - /* Wait until the context is ready */ - while (pa_context_get_state(p->context) != PA_CONTEXT_READY) { - if (iterate(p, 1, &error) < 0) - goto fail; - } - - if (!(p->stream = pa_stream_new(p->context, stream_name, ss, NULL))) - goto fail; - - if (dir == PA_STREAM_PLAYBACK) - pa_stream_connect_playback(p->stream, dev, attr, 0, NULL); - else - pa_stream_connect_record(p->stream, dev, attr, 0); - - /* Wait until the stream is ready */ - while (pa_stream_get_state(p->stream) != PA_STREAM_READY) { - if (iterate(p, 1, &error) < 0) - goto fail; - } - - pa_stream_set_read_callback(p->stream, read_callback, p); - - return p; - -fail: - if (rerror) - *rerror = error; - pa_simple_free(p); - return NULL; -} - -void pa_simple_free(pa_simple *s) { - assert(s); - - pa_xfree(s->read_data); - - if (s->stream) - pa_stream_unref(s->stream); - - if (s->context) - pa_context_unref(s->context); - - if (s->mainloop) - pa_mainloop_free(s->mainloop); - - pa_xfree(s); -} - -int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { - assert(p && data && p->direction == PA_STREAM_PLAYBACK); - - if (p->dead) { - if (rerror) - *rerror = pa_context_errno(p->context); - - return -1; - } - - while (length > 0) { - size_t l; - - while (!(l = pa_stream_writable_size(p->stream))) - if (iterate(p, 1, rerror) < 0) - return -1; - - if (l > length) - l = length; - - pa_stream_write(p->stream, data, l, NULL, 0); - data = (const uint8_t*) data + l; - length -= l; - } - - /* Make sure that no data is pending for write */ - if (iterate(p, 0, rerror) < 0) - return -1; - - return 0; -} - -static void read_callback(pa_stream *s, const void*data, size_t length, void *userdata) { - pa_simple *p = userdata; - assert(s && data && length && p); - - if (p->read_data) { - pa_log(__FILE__": Buffer overflow, dropping incoming memory blocks.\n"); - pa_xfree(p->read_data); - } - - p->read_data = pa_xmemdup(data, p->read_length = length); - p->read_index = 0; -} - -int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { - assert(p && data && p->direction == PA_STREAM_RECORD); - - if (p->dead) { - if (rerror) - *rerror = pa_context_errno(p->context); - - return -1; - } - - while (length > 0) { - if (p->read_data) { - size_t l = length; - - if (p->read_length <= l) - l = p->read_length; - - memcpy(data, (uint8_t*) p->read_data+p->read_index, l); - - data = (uint8_t*) data + l; - length -= l; - - p->read_index += l; - p->read_length -= l; - - if (!p->read_length) { - pa_xfree(p->read_data); - p->read_data = NULL; - p->read_index = 0; - } - - if (!length) - return 0; - - assert(!p->read_data); - } - - if (iterate(p, 1, rerror) < 0) - return -1; - } - - return 0; -} - -static void drain_or_flush_complete(pa_stream *s, int success, void *userdata) { - pa_simple *p = userdata; - assert(s && p); - if (!success) - p->dead = 1; -} - -int pa_simple_drain(pa_simple *p, int *rerror) { - pa_operation *o; - assert(p && p->direction == PA_STREAM_PLAYBACK); - - if (p->dead) { - if (rerror) - *rerror = pa_context_errno(p->context); - - return -1; - } - - o = pa_stream_drain(p->stream, drain_or_flush_complete, p); - - while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { - if (iterate(p, 1, rerror) < 0) { - pa_operation_cancel(o); - pa_operation_unref(o); - return -1; - } - } - - pa_operation_unref(o); - - if (p->dead && rerror) - *rerror = pa_context_errno(p->context); - - return p->dead ? -1 : 0; -} - -static void latency_complete(pa_stream *s, const pa_latency_info *l, void *userdata) { - pa_simple *p = userdata; - assert(s && p); - - if (!l) - p->dead = 1; - else { - int negative = 0; - p->latency = pa_stream_get_latency(s, l, &negative); - if (negative) - p->latency = 0; - } -} - -pa_usec_t pa_simple_get_playback_latency(pa_simple *p, int *rerror) { - pa_operation *o; - assert(p && p->direction == PA_STREAM_PLAYBACK); - - if (p->dead) { - if (rerror) - *rerror = pa_context_errno(p->context); - - return (pa_usec_t) -1; - } - - p->latency = 0; - o = pa_stream_get_latency_info(p->stream, latency_complete, p); - - while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { - - if (iterate(p, 1, rerror) < 0) { - pa_operation_cancel(o); - pa_operation_unref(o); - return -1; - } - } - - pa_operation_unref(o); - - if (p->dead && rerror) - *rerror = pa_context_errno(p->context); - - return p->dead ? (pa_usec_t) -1 : p->latency; -} - -int pa_simple_flush(pa_simple *p, int *rerror) { - pa_operation *o; - assert(p && p->direction == PA_STREAM_PLAYBACK); - - if (p->dead) { - if (rerror) - *rerror = pa_context_errno(p->context); - - return -1; - } - - o = pa_stream_flush(p->stream, drain_or_flush_complete, p); - - while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { - if (iterate(p, 1, rerror) < 0) { - pa_operation_cancel(o); - pa_operation_unref(o); - return -1; - } - } - - pa_operation_unref(o); - - if (p->dead && rerror) - *rerror = pa_context_errno(p->context); - - return p->dead ? -1 : 0; -} diff --git a/polyp/polyplib-simple.h b/polyp/polyplib-simple.h deleted file mode 100644 index 0c80f460..00000000 --- a/polyp/polyplib-simple.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef foopolyplibsimplehfoo -#define foopolyplibsimplehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "sample.h" -#include "polyplib-def.h" -#include "cdecl.h" - -/** \file - * A simple but limited synchronous playback and recording - * API. This is synchronouse, simplified wrapper around the standard - * asynchronous API. */ - -/** \example pacat-simple.c - * A simple playback tool using the simple API */ - -/** \example parec-simple.c - * A simple recording tool using the simple API */ - -PA_C_DECL_BEGIN - -/** \pa_simple - * An opaque simple connection object */ -typedef struct pa_simple pa_simple; - -/** Create a new connection to the server */ -pa_simple* pa_simple_new( - const char *server, /**< Server name, or NULL for default */ - const char *name, /**< A descriptive name for this client (application name, ...) */ - pa_stream_direction_t dir, /**< Open this stream for recording or playback? */ - const char *dev, /**< Sink (resp. source) name, or NULL for default */ - const char *stream_name, /**< A descriptive name for this client (application name, song title, ...) */ - const pa_sample_spec *ss, /**< The sample type to use */ - const pa_buffer_attr *attr, /**< Buffering attributes, or NULL for default */ - int *error /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */ - ); - -/** Close and free the connection to the server. The connection objects becomes invalid when this is called. */ -void pa_simple_free(pa_simple *s); - -/** Write some data to the server */ -int pa_simple_write(pa_simple *s, const void*data, size_t length, int *error); - -/** Wait until all data already written is played by the daemon */ -int pa_simple_drain(pa_simple *s, int *error); - -/** Read some data from the server */ -int pa_simple_read(pa_simple *s, void*data, size_t length, int *error); - -/** Return the playback latency. \since 0.5 */ -pa_usec_t pa_simple_get_playback_latency(pa_simple *s, int *error); - -/** Flush the playback buffer. \since 0.5 */ -int pa_simple_flush(pa_simple *s, int *error); - -PA_C_DECL_END - -#endif diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c deleted file mode 100644 index 7b9d6863..00000000 --- a/polyp/polyplib-stream.c +++ /dev/null @@ -1,807 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "polyplib-internal.h" -#include "xmalloc.h" -#include "pstream-util.h" -#include "util.h" -#include "log.h" - -#define LATENCY_IPOL_INTERVAL_USEC (10000L) - -pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map) { - pa_stream *s; - assert(c); - assert(ss); - - if (!pa_sample_spec_valid(ss)) - return NULL; - - if (map && !pa_channel_map_valid(map)) - return NULL; - - s = pa_xnew(pa_stream, 1); - s->ref = 1; - s->context = c; - s->mainloop = c->mainloop; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->state_callback = NULL; - s->state_userdata = NULL; - - s->direction = PA_STREAM_NODIRECTION; - s->name = pa_xstrdup(name); - s->sample_spec = *ss; - - if (map) - s->channel_map = *map; - else - pa_channel_map_init_auto(&s->channel_map, ss->channels); - - s->channel = 0; - s->channel_valid = 0; - s->device_index = PA_INVALID_INDEX; - s->requested_bytes = 0; - s->state = PA_STREAM_DISCONNECTED; - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->mcalign = pa_mcalign_new(pa_frame_size(ss), c->memblock_stat); - - s->counter = 0; - s->previous_time = 0; - s->previous_ipol_time = 0; - - s->corked = 0; - s->interpolate = 0; - - s->ipol_usec = 0; - memset(&s->ipol_timestamp, 0, sizeof(s->ipol_timestamp)); - s->ipol_event = NULL; - s->ipol_requested = 0; - - PA_LLIST_PREPEND(pa_stream, c->streams, s); - - return pa_stream_ref(s); -} - -static void stream_free(pa_stream *s) { - assert(s); - - if (s->ipol_event) { - assert(s->mainloop); - s->mainloop->time_free(s->ipol_event); - } - - pa_mcalign_free(s->mcalign); - - pa_xfree(s->name); - pa_xfree(s); -} - -void pa_stream_unref(pa_stream *s) { - assert(s && s->ref >= 1); - - if (--(s->ref) == 0) - stream_free(s); -} - -pa_stream* pa_stream_ref(pa_stream *s) { - assert(s && s->ref >= 1); - s->ref++; - return s; -} - -pa_stream_state_t pa_stream_get_state(pa_stream *s) { - assert(s && s->ref >= 1); - return s->state; -} - -pa_context* pa_stream_get_context(pa_stream *s) { - assert(s && s->ref >= 1); - return s->context; -} - -uint32_t pa_stream_get_index(pa_stream *s) { - assert(s && s->ref >= 1); - return s->device_index; -} - -void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { - assert(s && s->ref >= 1); - - if (s->state == st) - return; - - pa_stream_ref(s); - - s->state = st; - - if ((st == PA_STREAM_FAILED || st == PA_STREAM_TERMINATED) && s->context) { - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - PA_LLIST_REMOVE(pa_stream, s->context->streams, s); - pa_stream_unref(s); - } - - if (s->state_callback) - s->state_callback(s, s->state_userdata); - - pa_stream_unref(s); -} - -void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_context *c = userdata; - pa_stream *s; - uint32_t channel; - assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); - - pa_context_ref(c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(c, PA_ERROR_PROTOCOL); - goto finish; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - goto finish; - - c->error = PA_ERROR_KILLED; - pa_stream_set_state(s, PA_STREAM_FAILED); - -finish: - pa_context_unref(c); -} - -void pa_command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_stream *s; - pa_context *c = userdata; - uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && c); - - pa_context_ref(c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(c, PA_ERROR_PROTOCOL); - goto finish; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - goto finish; - - if (s->state != PA_STREAM_READY) - goto finish; - - pa_stream_ref(s); - - s->requested_bytes += bytes; - - if (s->requested_bytes && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); - - pa_stream_unref(s); - -finish: - pa_context_unref(c); -} - -static void ipol_callback(pa_mainloop_api *m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - struct timeval tv2; - pa_stream *s = userdata; - - pa_stream_ref(s); - -/* pa_log("requesting new ipol data\n"); */ - - if (s->state == PA_STREAM_READY && !s->ipol_requested) { - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); - s->ipol_requested = 1; - } - - pa_gettimeofday(&tv2); - pa_timeval_add(&tv2, LATENCY_IPOL_INTERVAL_USEC); - - m->time_restart(e, &tv2); - - pa_stream_unref(s); -} - - -void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_stream *s = userdata; - assert(pd && s && s->state == PA_STREAM_CREATING); - - pa_stream_ref(s); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(s->context, command, t) < 0) - goto finish; - - pa_stream_set_state(s, PA_STREAM_FAILED); - goto finish; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - ((s->direction != PA_STREAM_RECORD) && pa_tagstruct_getu32(t, &s->requested_bytes) < 0) || - !pa_tagstruct_eof(t)) { - pa_context_fail(s->context, PA_ERROR_PROTOCOL); - goto finish; - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - pa_stream_set_state(s, PA_STREAM_READY); - - if (s->interpolate) { - struct timeval tv; - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); - - pa_gettimeofday(&tv); - tv.tv_usec += LATENCY_IPOL_INTERVAL_USEC; /* every 100 ms */ - - assert(!s->ipol_event); - s->ipol_event = s->mainloop->time_new(s->mainloop, &tv, &ipol_callback, s); - } - - if (s->requested_bytes && s->ref > 1 && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); - -finish: - pa_stream_unref(s); -} - -static void create_stream(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags, const pa_cvolume *volume) { - pa_tagstruct *t; - uint32_t tag; - assert(s && s->ref >= 1 && s->state == PA_STREAM_DISCONNECTED); - - pa_stream_ref(s); - - s->interpolate = !!(flags & PA_STREAM_INTERPOLATE_LATENCY); - pa_stream_trash_ipol(s); - - if (attr) - s->buffer_attr = *attr; - else { - /* half a second */ - s->buffer_attr.tlength = pa_bytes_per_second(&s->sample_spec)/2; - s->buffer_attr.maxlength = (s->buffer_attr.tlength*3)/2; - s->buffer_attr.minreq = s->buffer_attr.tlength/100; - s->buffer_attr.prebuf = s->buffer_attr.tlength - s->buffer_attr.minreq; - s->buffer_attr.fragsize = s->buffer_attr.tlength/100; - } - - pa_stream_set_state(s, PA_STREAM_CREATING); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - if (!dev) { - if (s->direction == PA_STREAM_PLAYBACK) - dev = s->context->conf->default_sink; - else - dev = s->context->conf->default_source; - } - - pa_tagstruct_put(t, - PA_TAG_U32, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM, - PA_TAG_U32, tag = s->context->ctag++, - PA_TAG_STRING, s->name, - PA_TAG_SAMPLE_SPEC, &s->sample_spec, - PA_TAG_CHANNEL_MAP, &s->channel_map, - PA_TAG_U32, PA_INVALID_INDEX, - PA_TAG_STRING, dev, - PA_TAG_U32, s->buffer_attr.maxlength, - PA_TAG_BOOLEAN, !!(flags & PA_STREAM_START_CORKED), - PA_TAG_INVALID); - - if (s->direction == PA_STREAM_PLAYBACK) { - pa_cvolume cv; - pa_tagstruct_put(t, - PA_TAG_U32, s->buffer_attr.tlength, - PA_TAG_U32, s->buffer_attr.prebuf, - PA_TAG_U32, s->buffer_attr.minreq, - PA_TAG_INVALID); - - if (!volume) { - pa_cvolume_reset(&cv, s->sample_spec.channels); - volume = &cv; - } - - pa_tagstruct_put_cvolume(t, volume); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s); - - pa_stream_unref(s); -} - -void pa_stream_connect_playback(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags, pa_cvolume *volume) { - assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); - s->direction = PA_STREAM_PLAYBACK; - create_stream(s, dev, attr, flags, volume); -} - -void pa_stream_connect_record(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags) { - assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); - s->direction = PA_STREAM_RECORD; - create_stream(s, dev, attr, flags, 0); -} - -void pa_stream_write(pa_stream *s, const void *data, size_t length, void (*free_cb)(void *p), size_t delta) { - pa_memchunk chunk; - assert(s && s->context && data && length && s->state == PA_STREAM_READY && s->ref >= 1); - - if (free_cb) { - chunk.memblock = pa_memblock_new_user((void*) data, length, free_cb, 1, s->context->memblock_stat); - assert(chunk.memblock && chunk.memblock->data); - } else { - chunk.memblock = pa_memblock_new(length, s->context->memblock_stat); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); - } - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, delta, &chunk); - pa_memblock_unref(chunk.memblock); - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; - - s->counter += length; -} - -size_t pa_stream_writable_size(pa_stream *s) { - assert(s && s->ref >= 1); - return s->state == PA_STREAM_READY ? s->requested_bytes : 0; -} - -pa_operation * pa_stream_drain(pa_stream *s, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); - - o = pa_operation_new(s->context, s); - assert(o); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -static void stream_get_latency_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - pa_latency_info i, *p = NULL; - struct timeval local, remote, now; - assert(pd && o && o->stream && o->context); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - } else if (pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || - pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || - pa_tagstruct_get_usec(t, &i.source_usec) < 0 || - pa_tagstruct_get_boolean(t, &i.playing) < 0 || - pa_tagstruct_getu32(t, &i.queue_length) < 0 || - pa_tagstruct_get_timeval(t, &local) < 0 || - pa_tagstruct_get_timeval(t, &remote) < 0 || - pa_tagstruct_getu64(t, &i.counter) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } else { - pa_gettimeofday(&now); - - if (pa_timeval_cmp(&local, &remote) <= 0 && pa_timeval_cmp(&remote, &now) <= 0) { - /* local and remote seem to have synchronized clocks */ - - if (o->stream->direction == PA_STREAM_PLAYBACK) - i.transport_usec = pa_timeval_diff(&remote, &local); - else - i.transport_usec = pa_timeval_diff(&now, &remote); - - i.synchronized_clocks = 1; - i.timestamp = remote; - } else { - /* clocks are not synchronized, let's estimate latency then */ - i.transport_usec = pa_timeval_diff(&now, &local)/2; - i.synchronized_clocks = 0; - i.timestamp = local; - pa_timeval_add(&i.timestamp, i.transport_usec); - } - - if (o->stream->interpolate) { -/* pa_log("new interpol data\n"); */ - o->stream->ipol_timestamp = i.timestamp; - o->stream->ipol_usec = pa_stream_get_time(o->stream, &i); - o->stream->ipol_requested = 0; - } - - p = &i; - } - - if (o->callback) { - void (*cb)(pa_stream *s, const pa_latency_info *_i, void *_userdata) = (void (*)(pa_stream *s, const pa_latency_info *_i, void *_userdata)) o->callback; - cb(o->stream, p, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_stream_get_latency_info(pa_stream *s, void (*cb)(pa_stream *p, const pa_latency_info*i, void *userdata), void *userdata) { - uint32_t tag; - pa_operation *o; - pa_tagstruct *t; - struct timeval now; - assert(s && s->direction != PA_STREAM_UPLOAD); - - o = pa_operation_new(s->context, s); - assert(o); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_GET_PLAYBACK_LATENCY : PA_COMMAND_GET_RECORD_LATENCY); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - - pa_gettimeofday(&now); - pa_tagstruct_put_timeval(t, &now); - pa_tagstruct_putu64(t, s->counter); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_info_callback, o); - - return pa_operation_ref(o); -} - -void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_stream *s = userdata; - assert(pd && s && s->ref >= 1); - - pa_stream_ref(s); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(s->context, command, t) < 0) - goto finish; - - pa_stream_set_state(s, PA_STREAM_FAILED); - goto finish; - } else if (!pa_tagstruct_eof(t)) { - pa_context_fail(s->context, PA_ERROR_PROTOCOL); - goto finish; - } - - pa_stream_set_state(s, PA_STREAM_TERMINATED); - -finish: - pa_stream_unref(s); -} - -void pa_stream_disconnect(pa_stream *s) { - pa_tagstruct *t; - uint32_t tag; - assert(s && s->ref >= 1); - - if (!s->channel_valid || !s->context->state == PA_CONTEXT_READY) - return; - - pa_stream_ref(s); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s); - - pa_stream_unref(s); -} - -void pa_stream_set_read_callback(pa_stream *s, void (*cb)(pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && s->ref >= 1); - s->read_callback = cb; - s->read_userdata = userdata; -} - -void pa_stream_set_write_callback(pa_stream *s, void (*cb)(pa_stream *p, size_t length, void *userdata), void *userdata) { - assert(s && s->ref >= 1); - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_set_state_callback(pa_stream *s, void (*cb)(pa_stream *s, void *userdata), void *userdata) { - assert(s && s->ref >= 1); - s->state_callback = cb; - s->state_userdata = userdata; -} - -void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int success = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - success = 0; - } else if (!pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_stream *s, int _success, void *_userdata) = (void (*)(pa_stream *s, int _success, void *_userdata)) o->callback; - cb(o->stream, success, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_stream_cork(pa_stream *s, int b, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); - - if (s->interpolate) { - if (!s->corked && b) - /* Pausing */ - s->ipol_usec = pa_stream_get_interpolated_time(s); - else if (s->corked && !b) - /* Unpausing */ - pa_gettimeofday(&s->ipol_timestamp); - } - - s->corked = b; - - o = pa_operation_new(s->context, s); - assert(o); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CORK_PLAYBACK_STREAM : PA_COMMAND_CORK_RECORD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_tagstruct_put_boolean(t, !!b); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); - - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); - - return pa_operation_ref(o); -} - -static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); - - o = pa_operation_new(s->context, s); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, command); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_stream_flush(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { - pa_operation *o; - o = stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata); - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); - return o; -} - -pa_operation* pa_stream_prebuf(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { - pa_operation *o; - o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata); - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); - return o; -} - -pa_operation* pa_stream_trigger(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { - pa_operation *o; - o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata); - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); - return o; -} - -pa_operation* pa_stream_set_name(pa_stream *s, const char *name, void(*cb)(pa_stream*c, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(s && s->ref >= 1 && s->state == PA_STREAM_READY && name && s->direction != PA_STREAM_UPLOAD); - - o = pa_operation_new(s->context, s); - assert(o); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, s->direction == PA_STREAM_RECORD ? PA_COMMAND_SET_RECORD_STREAM_NAME : PA_COMMAND_SET_PLAYBACK_STREAM_NAME); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -uint64_t pa_stream_get_counter(pa_stream *s) { - assert(s); - return s->counter; -} - -pa_usec_t pa_stream_get_time(pa_stream *s, const pa_latency_info *i) { - pa_usec_t usec; - assert(s); - - usec = pa_bytes_to_usec(i->counter, &s->sample_spec); - - if (i) { - if (s->direction == PA_STREAM_PLAYBACK) { - pa_usec_t latency = i->transport_usec + i->buffer_usec + i->sink_usec; - if (usec < latency) - usec = 0; - else - usec -= latency; - - } else if (s->direction == PA_STREAM_RECORD) { - usec += i->source_usec + i->buffer_usec + i->transport_usec; - - if (usec > i->sink_usec) - usec -= i->sink_usec; - else - usec = 0; - } - } - - if (usec < s->previous_time) - usec = s->previous_time; - - s->previous_time = usec; - - return usec; -} - -static pa_usec_t time_counter_diff(pa_stream *s, pa_usec_t t, pa_usec_t c, int *negative) { - assert(s); - - if (negative) - *negative = 0; - - if (c < t) { - if (s->direction == PA_STREAM_RECORD) { - if (negative) - *negative = 1; - - return t-c; - } else - return 0; - } else - return c-t; -} - -pa_usec_t pa_stream_get_latency(pa_stream *s, const pa_latency_info *i, int *negative) { - pa_usec_t t, c; - assert(s && i); - - t = pa_stream_get_time(s, i); - c = pa_bytes_to_usec(s->counter, &s->sample_spec); - - return time_counter_diff(s, t, c, negative); -} - -const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) { - assert(s); - return &s->sample_spec; -} - -void pa_stream_trash_ipol(pa_stream *s) { - assert(s); - - if (!s->interpolate) - return; - - memset(&s->ipol_timestamp, 0, sizeof(s->ipol_timestamp)); - s->ipol_usec = 0; -} - -pa_usec_t pa_stream_get_interpolated_time(pa_stream *s) { - pa_usec_t usec; - assert(s && s->interpolate); - - if (s->corked) - usec = s->ipol_usec; - else { - if (s->ipol_timestamp.tv_sec == 0) - usec = 0; - else - usec = s->ipol_usec + pa_timeval_age(&s->ipol_timestamp); - } - - if (usec < s->previous_ipol_time) - usec = s->previous_ipol_time; - - s->previous_ipol_time = usec; - - return usec; -} - -pa_usec_t pa_stream_get_interpolated_latency(pa_stream *s, int *negative) { - pa_usec_t t, c; - assert(s && s->interpolate); - - t = pa_stream_get_interpolated_time(s); - c = pa_bytes_to_usec(s->counter, &s->sample_spec); - return time_counter_diff(s, t, c, negative); -} diff --git a/polyp/polyplib-stream.h b/polyp/polyplib-stream.h deleted file mode 100644 index bc828b71..00000000 --- a/polyp/polyplib-stream.h +++ /dev/null @@ -1,181 +0,0 @@ -#ifndef foopolyplibstreamhfoo -#define foopolyplibstreamhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include -#include -#include -#include -#include -#include - -/** \file - * Audio streams for input, output and sample upload */ - -PA_C_DECL_BEGIN - -/** \pa_stream - * An opaque stream for playback or recording */ -typedef struct pa_stream pa_stream; - -/** Create a new, unconnected stream with the specified name and sample type */ -pa_stream* pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map); - -/** Decrease the reference counter by one */ -void pa_stream_unref(pa_stream *s); - -/** Increase the reference counter by one */ -pa_stream *pa_stream_ref(pa_stream *s); - -/** Return the current state of the stream */ -pa_stream_state_t pa_stream_get_state(pa_stream *p); - -/** Return the context this stream is attached to */ -pa_context* pa_stream_get_context(pa_stream *p); - -/** Return the device (sink input or source output) index this stream is connected to */ -uint32_t pa_stream_get_index(pa_stream *s); - -/** Connect the stream to a sink */ -void pa_stream_connect_playback( - pa_stream *s, - const char *dev, - const pa_buffer_attr *attr, - pa_stream_flags_t flags, - pa_cvolume *volume); - -/** Connect the stream to a source */ -void pa_stream_connect_record( - pa_stream *s, - const char *dev, - const pa_buffer_attr *attr, - pa_stream_flags_t flags); - -/** Disconnect a stream from a source/sink */ -void pa_stream_disconnect(pa_stream *s); - -/** Write some data to the server (for playback sinks), if free_cb is - * non-NULL this routine is called when all data has been written out - * and an internal reference to the specified data is kept, the data - * is not copied. If NULL, the data is copied into an internal - * buffer. */ -void pa_stream_write(pa_stream *p /**< The stream to use */, - const void *data /**< The data to write */, - size_t length /**< The length of the data to write */, - void (*free_cb)(void *p) /**< A cleanup routine for the data or NULL to request an internal copy */, - size_t delta /**< Drop this many - bytes in the playback - buffer before writing - this data. Use - (size_t) -1 for - clearing the whole - playback - buffer. Normally you - will specify 0 here, - i.e. append to the - playback buffer. If - the value given here - is greater than the - buffered data length - the buffer is cleared - and the data is - written to the - buffer's start. This - value is ignored on - upload streams. */); - -/** Return the amount of bytes that may be written using pa_stream_write() */ -size_t pa_stream_writable_size(pa_stream *p); - -/** Drain a playback stream */ -pa_operation* pa_stream_drain(pa_stream *s, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata); - -/** Get the playback latency of a stream */ -pa_operation* pa_stream_get_latency_info(pa_stream *p, void (*cb)(pa_stream *p, const pa_latency_info *i, void *userdata), void *userdata); - -/** Set the callback function that is called whenever the state of the stream changes */ -void pa_stream_set_state_callback(pa_stream *s, void (*cb)(pa_stream *s, void *userdata), void *userdata); - -/** Set the callback function that is called when new data may be - * written to the stream. */ -void pa_stream_set_write_callback(pa_stream *p, void (*cb)(pa_stream *p, size_t length, void *userdata), void *userdata); - -/** Set the callback function that is called when new data is available from the stream */ -void pa_stream_set_read_callback(pa_stream *p, void (*cb)(pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); - -/** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. \since 0.3 */ -pa_operation* pa_stream_cork(pa_stream *s, int b, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata); - -/** Flush the playback buffer of this stream. Most of the time you're - * better off using the parameter delta of pa_stream_write() instead of this - * function. Available on both playback and recording streams. \since 0.3 */ -pa_operation* pa_stream_flush(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata); - -/** Reenable prebuffering. Available for playback streams only. \since 0.6 */ -pa_operation* pa_stream_prebuf(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata); - -/** Request immediate start of playback on this stream. This disables - * prebuffering as specified in the pa_buffer_attr structure. Available for playback streams only. \since - * 0.3 */ -pa_operation* pa_stream_trigger(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata); - -/** Rename the stream. \since 0.5 */ -pa_operation* pa_stream_set_name(pa_stream *s, const char *name, void(*cb)(pa_stream*c, int success, void *userdata), void *userdata); - -/** Return the total number of bytes written to/read from the - * stream. This counter is not reset on pa_stream_flush(), you may do - * this yourself using pa_stream_reset_counter(). \since 0.6 */ -uint64_t pa_stream_get_counter(pa_stream *s); - -/** Return the current playback/recording time. This is based on the - * counter accessible with pa_stream_get_counter(). This function - * requires a pa_latency_info structure as argument, which should be - * acquired using pa_stream_get_latency(). \since 0.6 */ -pa_usec_t pa_stream_get_time(pa_stream *s, const pa_latency_info *i); - -/** Return the total stream latency. Thus function requires a - * pa_latency_info structure as argument, which should be aquired - * using pa_stream_get_latency(). In case the stream is a monitoring - * stream the result can be negative, i.e. the captured samples are - * not yet played. In this case *negative is set to 1. \since 0.6 */ -pa_usec_t pa_stream_get_latency(pa_stream *s, const pa_latency_info *i, int *negative); - -/** Return the interpolated playback/recording time. Requires the - * PA_STREAM_INTERPOLATE_LATENCY bit set when creating the stream. In - * contrast to pa_stream_get_latency() this function doesn't require - * a whole roundtrip for response. \since 0.6 */ -pa_usec_t pa_stream_get_interpolated_time(pa_stream *s); - -/** Return the interpolated playback/recording latency. Requires the - * PA_STREAM_INTERPOLATE_LATENCY bit set when creating the - * stream. \since 0.6 */ -pa_usec_t pa_stream_get_interpolated_latency(pa_stream *s, int *negative); - -/** Return a pointer to the streams sample specification. \since 0.6 */ -const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s); - -PA_C_DECL_END - -#endif diff --git a/polyp/polyplib-subscribe.c b/polyp/polyplib-subscribe.c deleted file mode 100644 index ef90ab0b..00000000 --- a/polyp/polyplib-subscribe.c +++ /dev/null @@ -1,81 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "polyplib-subscribe.h" -#include "polyplib-internal.h" -#include "pstream-util.h" -#include "gccmacro.h" - -void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_context *c = userdata; - pa_subscription_event_type_t e; - uint32_t index; - assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); - - pa_context_ref(c); - - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &index) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(c, PA_ERROR_PROTOCOL); - goto finish; - } - - if (c->subscribe_callback) - c->subscribe_callback(c, e, index, c->subscribe_userdata); - -finish: - pa_context_unref(c); -} - - -pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, m); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -void pa_context_set_subscribe_callback(pa_context *c, void (*cb)(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata) { - assert(c); - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; -} diff --git a/polyp/polyplib-subscribe.h b/polyp/polyplib-subscribe.h deleted file mode 100644 index 920c9853..00000000 --- a/polyp/polyplib-subscribe.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef foopolyplibsubscribehfoo -#define foopolyplibsubscribehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include -#include -#include - -/** \file - * Daemon introspection event subscription subsystem. Use this - * to be notified whenever the internal layout of daemon changes: - * i.e. entities such as sinks or sources are create, removed or - * modified. */ - -PA_C_DECL_BEGIN - -/** Enable event notification */ -pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -/** Set the context specific call back function that is called whenever the state of the daemon changes */ -void pa_context_set_subscribe_callback(pa_context *c, void (*cb)(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata); - -PA_C_DECL_END - -#endif diff --git a/polyp/polyplib-version.h.in b/polyp/polyplib-version.h.in deleted file mode 100644 index 89e0a0e5..00000000 --- a/polyp/polyplib-version.h.in +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef foopolyplibversionhfoo /*-*-C-*-*/ -#define foopolyplibversionhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -/* WARNING: Make sure to edit the real source file polyplib-version.h.in! */ - -/** \file - * Define header version */ - -PA_C_DECL_BEGIN - -/** Return the version of the header files. Keep in mind that this is -a macro and not a function, so it is impossible to get the pointer of -it. */ -#define pa_get_headers_version() ("@PACKAGE_VERSION@") - -/** Return the version of the library the current application is linked to. */ -const char* pa_get_library_version(void); - -/** The current API version. Version 6 relates to polypaudio - * 0.6. Prior versions (i.e. Polypaudio 0.5.1 and older) have - * PA_API_VERSION undefined. */ -#define PA_API_VERSION @PA_API_VERSION@ - -PA_C_DECL_END - -#endif diff --git a/polyp/polyplib.h b/polyp/polyplib.h deleted file mode 100644 index b9b9b447..00000000 --- a/polyp/polyplib.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** \file - * Include all polyplib header file at once. The following files are included: \ref mainloop-api.h, \ref sample.h, - * \ref polyplib-def.h, \ref polyplib-context.h, \ref polyplib-stream.h, - * \ref polyplib-introspect.h, \ref polyplib-subscribe.h and \ref polyplib-scache.h \ref polyplib-version.h - * at once */ - -/** \mainpage - * - * \section intro_sec Introduction - * - * This document describes the client API for the polypaudio sound - * server. The API comes in two flavours: - * - * \li The complete but somewhat complicated to use asynchronous API - * \li And the simplified, easy to use, but limited synchronous API - * - * The polypaudio client libraries are thread safe as long as all - * objects created by any library function are accessed from the thread - * that created them only. - * - * \section simple_sec Simple API - * - * Use this if you develop your program in synchronous style and just - * need a way to play or record data on the sound server. See - * \ref polyplib-simple.h for more details. - * - * \section async_api Asynchronous API - * - * Use this if you develop your programs in asynchronous, main loop - * based style or want to use advanced features of the polypaudio - * API. A good starting point is \ref polyplib-context.h - * - * The asynchronous API relies on an abstract main loop API that is - * described in \ref mainloop-api.h. Two distinct implementations are - * available: - * - * \li \ref mainloop.h: a minimal but fast implementation based on poll() - * \li \ref glib-mainloop.h: a wrapper around GLIB's main loop - * - * UNIX signals may be hooked to a main loop using the functions from - * \ref mainloop-signal.h - * - * \section pkgconfig pkg-config - * - * The polypaudio libraries provide pkg-config snippets for the different modules. To use the - * asynchronous API use "polyplib" as pkg-config file. GLIB main loop - * support is available as "polyplib-glib-mainloop". The simple - * synchronous API is available as "polyplib-simple". - */ - -#endif diff --git a/polyp/props.c b/polyp/props.c deleted file mode 100644 index df748c1e..00000000 --- a/polyp/props.c +++ /dev/null @@ -1,119 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "xmalloc.h" -#include "props.h" -#include "log.h" - -typedef struct pa_property { - char *name; /* Points to memory allocated by the property subsystem */ - void *data; /* Points to memory maintained by the caller */ -} pa_property; - -/* Allocate a new property object */ -static pa_property* property_new(const char *name, void *data) { - pa_property* p; - assert(name && data); - - p = pa_xmalloc(sizeof(pa_property)); - p->name = pa_xstrdup(name); - p->data = data; - - return p; -} - -/* Free a property object */ -static void property_free(pa_property *p) { - assert(p); - - pa_xfree(p->name); - pa_xfree(p); -} - -void* pa_property_get(pa_core *c, const char *name) { - pa_property *p; - assert(c && name && c->properties); - - if (!(p = pa_hashmap_get(c->properties, name))) - return NULL; - - return p->data; -} - -int pa_property_set(pa_core *c, const char *name, void *data) { - pa_property *p; - assert(c && name && data && c->properties); - - if (pa_hashmap_get(c->properties, name)) - return -1; - - p = property_new(name, data); - pa_hashmap_put(c->properties, p->name, p); - return 0; -} - -int pa_property_remove(pa_core *c, const char *name) { - pa_property *p; - assert(c && name && c->properties); - - if (!(p = pa_hashmap_remove(c->properties, name))) - return -1; - - property_free(p); - return 0; -} - -void pa_property_init(pa_core *c) { - assert(c); - - c->properties = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); -} - -void pa_property_cleanup(pa_core *c) { - assert(c); - - if (!c->properties) - return; - - assert(!pa_hashmap_size(c->properties)); - - pa_hashmap_free(c->properties, NULL, NULL); - c->properties = NULL; - -} - -void pa_property_dump(pa_core *c, pa_strbuf *s) { - void *state = NULL; - pa_property *p; - assert(c && s); - - while ((p = pa_hashmap_iterate(c->properties, &state, NULL))) - pa_strbuf_printf(s, "[%s] -> [%p]\n", p->name, p->data); -} - -int pa_property_replace(pa_core *c, const char *name, void *data) { - assert(c && name); - - pa_property_remove(c, name); - return pa_property_set(c, name, data); -} diff --git a/polyp/props.h b/polyp/props.h deleted file mode 100644 index 5abf8787..00000000 --- a/polyp/props.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef foopropshfoo -#define foopropshfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "core.h" -#include "strbuf.h" - -/* The property subsystem is to be used to share data between - * modules. Consider them to be kind of "global" variables for a - * core. Why not use the hashmap functions directly? The hashmap - * functions copy neither the key nor value, while this property - * system copies the key. Users of this system have to think about - * reference counting themselves. */ - -/* Return a pointer to the value of the specified property. */ -void* pa_property_get(pa_core *c, const char *name); - -/* Set the property 'name' to 'data'. This function fails in case a - * property by this name already exists. The property data is not - * copied or reference counted. This is the caller's job. */ -int pa_property_set(pa_core *c, const char *name, void *data); - -/* Remove the specified property. Return non-zero on failure */ -int pa_property_remove(pa_core *c, const char *name); - -/* A combination of pa_property_remove() and pa_property_set() */ -int pa_property_replace(pa_core *c, const char *name, void *data); - -/* Free all memory used by the property system */ -void pa_property_cleanup(pa_core *c); - -/* Initialize the properties subsystem */ -void pa_property_init(pa_core *c); - -/* Dump the current set of properties */ -void pa_property_dump(pa_core *c, pa_strbuf *s); - -#endif diff --git a/polyp/protocol-cli.c b/polyp/protocol-cli.c deleted file mode 100644 index d2d73550..00000000 --- a/polyp/protocol-cli.c +++ /dev/null @@ -1,95 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "protocol-cli.h" -#include "cli.h" -#include "xmalloc.h" -#include "log.h" - -/* Don't allow more than this many concurrent connections */ -#define MAX_CONNECTIONS 25 - -struct pa_protocol_cli { - pa_module *module; - pa_core *core; - pa_socket_server*server; - pa_idxset *connections; -}; - -static void cli_eof_cb(pa_cli*c, void*userdata) { - pa_protocol_cli *p = userdata; - assert(p); - pa_idxset_remove_by_data(p->connections, c, NULL); - pa_cli_free(c); -} - -static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { - pa_protocol_cli *p = userdata; - pa_cli *c; - assert(s && io && p); - - if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); - pa_iochannel_free(io); - return; - } - - c = pa_cli_new(p->core, io, p->module); - assert(c); - pa_cli_set_eof_callback(c, cli_eof_cb, p); - - pa_idxset_put(p->connections, c, NULL); -} - -pa_protocol_cli* pa_protocol_cli_new(pa_core *core, pa_socket_server *server, pa_module *m, PA_GCC_UNUSED pa_modargs *ma) { - pa_protocol_cli* p; - assert(core && server); - - p = pa_xmalloc(sizeof(pa_protocol_cli)); - p->module = m; - p->core = core; - p->server = server; - p->connections = pa_idxset_new(NULL, NULL); - - pa_socket_server_set_callback(p->server, on_connection, p); - - return p; -} - -static void free_connection(void *p, PA_GCC_UNUSED void *userdata) { - assert(p); - pa_cli_free(p); -} - -void pa_protocol_cli_free(pa_protocol_cli *p) { - assert(p); - - pa_idxset_free(p->connections, free_connection, NULL); - pa_socket_server_unref(p->server); - pa_xfree(p); -} diff --git a/polyp/protocol-cli.h b/polyp/protocol-cli.h deleted file mode 100644 index aed733c1..00000000 --- a/polyp/protocol-cli.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef fooprotocolclihfoo -#define fooprotocolclihfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "core.h" -#include "socket-server.h" -#include "module.h" -#include "modargs.h" - -typedef struct pa_protocol_cli pa_protocol_cli; - -pa_protocol_cli* pa_protocol_cli_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma); -void pa_protocol_cli_free(pa_protocol_cli *n); - -#endif diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c deleted file mode 100644 index 6f004e16..00000000 --- a/polyp/protocol-esound.c +++ /dev/null @@ -1,1166 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "protocol-esound.h" -#include "esound.h" -#include "memblock.h" -#include "client.h" -#include "sink-input.h" -#include "sink.h" -#include "source-output.h" -#include "source.h" -#include "sample.h" -#include "scache.h" -#include "sample-util.h" -#include "authkey.h" -#include "namereg.h" -#include "xmalloc.h" -#include "log.h" -#include "util.h" -#include "endianmacros.h" - -/* Don't accept more connection than this */ -#define MAX_CONNECTIONS 10 - -/* Kick a client if it doesn't authenticate within this time */ -#define AUTH_TIMEOUT 5 - -#define DEFAULT_COOKIE_FILE ".esd_auth" - -#define PLAYBACK_BUFFER_SECONDS (.5) -#define PLAYBACK_BUFFER_FRAGMENTS (10) -#define RECORD_BUFFER_SECONDS (5) -#define RECORD_BUFFER_FRAGMENTS (100) - -#define MAX_CACHE_SAMPLE_SIZE (1024000) - -#define SCACHE_PREFIX "esound." - -/* This is heavily based on esound's code */ - -struct connection { - uint32_t index; - int dead; - pa_protocol_esound *protocol; - pa_iochannel *io; - pa_client *client; - int authorized, swap_byte_order; - void *write_data; - size_t write_data_alloc, write_data_index, write_data_length; - void *read_data; - size_t read_data_alloc, read_data_length; - esd_proto_t request; - esd_client_state_t state; - pa_sink_input *sink_input; - pa_source_output *source_output; - pa_memblockq *input_memblockq, *output_memblockq; - pa_defer_event *defer_event; - - struct { - pa_memblock *current_memblock; - size_t memblock_index, fragment_size; - } playback; - - struct { - pa_memchunk memchunk; - char *name; - pa_sample_spec sample_spec; - } scache; - - pa_time_event *auth_timeout_event; -}; - -struct pa_protocol_esound { - int public; - pa_module *module; - pa_core *core; - pa_socket_server *server; - pa_idxset *connections; - char *sink_name, *source_name; - unsigned n_player; - uint8_t esd_key[ESD_KEY_LEN]; -}; - -typedef struct proto_handler { - size_t data_length; - int (*proc)(struct connection *c, esd_proto_t request, const void *data, size_t length); - const char *description; -} esd_proto_handler_info_t; - -static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length); -static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk); -static void sink_input_kill_cb(pa_sink_input *i); -static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i); -static pa_usec_t source_output_get_latency_cb(pa_source_output *o); - -static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk); -static void source_output_kill_cb(pa_source_output *o); - -static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_stream_play(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_get_latency(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_server_info(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_sample_get_id(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_standby_or_resume(struct connection *c, esd_proto_t request, const void *data, size_t length); - -/* the big map of protocol handler info */ -static struct proto_handler proto_map[ESD_PROTO_MAX] = { - { ESD_KEY_LEN + sizeof(int), esd_proto_connect, "connect" }, - { ESD_KEY_LEN + sizeof(int), NULL, "lock" }, - { ESD_KEY_LEN + sizeof(int), NULL, "unlock" }, - - { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_play, "stream play" }, - { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream rec" }, - { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream mon" }, - - { ESD_NAME_MAX + 3 * sizeof(int), esd_proto_sample_cache, "sample cache" }, /* 6 */ - { sizeof(int), esd_proto_sample_free_or_play, "sample free" }, - { sizeof(int), esd_proto_sample_free_or_play, "sample play" }, /* 8 */ - { sizeof(int), NULL, "sample loop" }, - { sizeof(int), NULL, "sample stop" }, - { -1, NULL, "TODO: sample kill" }, - - { ESD_KEY_LEN + sizeof(int), esd_proto_standby_or_resume, "standby" }, /* NOOP! */ - { ESD_KEY_LEN + sizeof(int), esd_proto_standby_or_resume, "resume" }, /* NOOP! */ /* 13 */ - - { ESD_NAME_MAX, esd_proto_sample_get_id, "sample getid" }, /* 14 */ - { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" }, - - { sizeof(int), esd_proto_server_info, "server info" }, - { sizeof(int), esd_proto_all_info, "all info" }, - { -1, NULL, "TODO: subscribe" }, - { -1, NULL, "TODO: unsubscribe" }, - - { 3 * sizeof(int), esd_proto_stream_pan, "stream pan"}, - { 3 * sizeof(int), NULL, "sample pan" }, - - { sizeof(int), NULL, "standby mode" }, - { 0, esd_proto_get_latency, "get latency" } -}; - - -static void connection_free(struct connection *c) { - assert(c); - pa_idxset_remove_by_data(c->protocol->connections, c, NULL); - - if (c->state == ESD_STREAMING_DATA) - c->protocol->n_player--; - - pa_client_free(c->client); - - if (c->sink_input) { - pa_sink_input_disconnect(c->sink_input); - pa_sink_input_unref(c->sink_input); - } - - if (c->source_output) { - pa_source_output_disconnect(c->source_output); - pa_source_output_unref(c->source_output); - } - - if (c->input_memblockq) - pa_memblockq_free(c->input_memblockq); - if (c->output_memblockq) - pa_memblockq_free(c->output_memblockq); - - if (c->playback.current_memblock) - pa_memblock_unref(c->playback.current_memblock); - - pa_xfree(c->read_data); - pa_xfree(c->write_data); - - if (c->io) - pa_iochannel_free(c->io); - - if (c->defer_event) - c->protocol->core->mainloop->defer_free(c->defer_event); - - if (c->scache.memchunk.memblock) - pa_memblock_unref(c->scache.memchunk.memblock); - pa_xfree(c->scache.name); - - if (c->auth_timeout_event) - c->protocol->core->mainloop->time_free(c->auth_timeout_event); - - pa_xfree(c); -} - -static void* connection_write(struct connection *c, size_t length) { - size_t t, i; - assert(c); - - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); - - t = c->write_data_length+length; - - if (c->write_data_alloc < t) - c->write_data = pa_xrealloc(c->write_data, c->write_data_alloc = t); - - assert(c->write_data); - - i = c->write_data_length; - c->write_data_length += length; - - return (uint8_t*) c->write_data+i; -} - -static void format_esd2native(int format, int swap_bytes, pa_sample_spec *ss) { - assert(ss); - - ss->channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; - if ((format & ESD_MASK_BITS) == ESD_BITS16) - ss->format = swap_bytes ? PA_SAMPLE_S16RE : PA_SAMPLE_S16NE; - else - ss->format = PA_SAMPLE_U8; -} - -static int format_native2esd(pa_sample_spec *ss) { - int format = 0; - - format = (ss->format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16; - format |= (ss->channels >= 2) ? ESD_STEREO : ESD_MONO; - - return format; -} - -/*** esound commands ***/ - -static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { - uint32_t ekey; - int *ok; - assert(length == (ESD_KEY_LEN + sizeof(uint32_t))); - - if (!c->authorized) { - if (memcmp(data, c->protocol->esd_key, ESD_KEY_LEN) != 0) { - pa_log(__FILE__": kicked client with invalid authorization key.\n"); - return -1; - } - - c->authorized = 1; - if (c->auth_timeout_event) { - c->protocol->core->mainloop->time_free(c->auth_timeout_event); - c->auth_timeout_event = NULL; - } - } - - ekey = *(const uint32_t*)((const uint8_t*) data+ESD_KEY_LEN); - if (ekey == ESD_ENDIAN_KEY) - c->swap_byte_order = 0; - else if (ekey == ESD_SWAP_ENDIAN_KEY) - c->swap_byte_order = 1; - else { - pa_log(__FILE__": client sent invalid endian key\n"); - return -1; - } - - ok = connection_write(c, sizeof(int)); - assert(ok); - *ok = 1; - return 0; -} - -static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { - char name[ESD_NAME_MAX]; - int format, rate; - pa_sink *sink; - pa_sample_spec ss; - size_t l; - assert(c && length == (sizeof(int)*2+ESD_NAME_MAX)); - - format = MAYBE_INT32_SWAP(c->swap_byte_order, *(const int*)data); - rate = MAYBE_INT32_SWAP(c->swap_byte_order, *((const int*)data + 1)); - - ss.rate = rate; - format_esd2native(format, c->swap_byte_order, &ss); - - if (!pa_sample_spec_valid(&ss)) { - pa_log(__FILE__": invalid sample specification\n"); - return -1; - } - - if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": no such sink\n"); - return -1; - } - - strncpy(name, (const char*) data + sizeof(int)*2, sizeof(name)); - name[sizeof(name)-1] = 0; - - pa_client_set_name(c->client, name); - - assert(!c->sink_input && !c->input_memblockq); - - if (!(c->sink_input = pa_sink_input_new(sink, __FILE__, name, &ss, NULL, 0, -1))) { - pa_log(__FILE__": failed to create sink input.\n"); - return -1; - } - - l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); - c->input_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&ss), l/2, l/PLAYBACK_BUFFER_FRAGMENTS, c->protocol->core->memblock_stat); - pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2); - c->playback.fragment_size = l/10; - - c->sink_input->owner = c->protocol->module; - c->sink_input->client = c->client; - c->sink_input->peek = sink_input_peek_cb; - c->sink_input->drop = sink_input_drop_cb; - c->sink_input->kill = sink_input_kill_cb; - c->sink_input->get_latency = sink_input_get_latency_cb; - c->sink_input->userdata = c; - - c->state = ESD_STREAMING_DATA; - - c->protocol->n_player++; - - return 0; -} - -static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length) { - char name[ESD_NAME_MAX]; - int format, rate; - pa_source *source; - pa_sample_spec ss; - size_t l; - assert(c && length == (sizeof(int)*2+ESD_NAME_MAX)); - - format = MAYBE_INT32_SWAP(c->swap_byte_order, *(const int*)data); - rate = MAYBE_INT32_SWAP(c->swap_byte_order, *((const int*)data + 1)); - - ss.rate = rate; - format_esd2native(format, c->swap_byte_order, &ss); - - if (!pa_sample_spec_valid(&ss)) { - pa_log(__FILE__": invalid sample specification.\n"); - return -1; - } - - if (request == ESD_PROTO_STREAM_MON) { - pa_sink* sink; - - if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": no such sink.\n"); - return -1; - } - - if (!(source = sink->monitor_source)) { - pa_log(__FILE__": no such monitor source.\n"); - return -1; - } - } else { - assert(request == ESD_PROTO_STREAM_REC); - - if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) { - pa_log(__FILE__": no such source.\n"); - return -1; - } - } - - strncpy(name, (const char*) data + sizeof(int)*2, sizeof(name)); - name[sizeof(name)-1] = 0; - - pa_client_set_name(c->client, name); - - assert(!c->output_memblockq && !c->source_output); - - if (!(c->source_output = pa_source_output_new(source, __FILE__, name, &ss, NULL, -1))) { - pa_log(__FILE__": failed to create source output\n"); - return -1; - } - - l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); - c->output_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&ss), 0, 0, c->protocol->core->memblock_stat); - pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); - - c->source_output->owner = c->protocol->module; - c->source_output->client = c->client; - c->source_output->push = source_output_push_cb; - c->source_output->kill = source_output_kill_cb; - c->source_output->get_latency = source_output_get_latency_cb; - c->source_output->userdata = c; - - c->state = ESD_STREAMING_DATA; - - c->protocol->n_player++; - - return 0; -} - -static int esd_proto_get_latency(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { - pa_sink *sink; - int latency, *lag; - assert(c && !data && length == 0); - - if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) - latency = 0; - else { - double usec = pa_sink_get_latency(sink); - latency = (int) ((usec*44100)/1000000); - } - - lag = connection_write(c, sizeof(int)); - assert(lag); - *lag = MAYBE_INT32_SWAP(c->swap_byte_order, latency); - return 0; -} - -static int esd_proto_server_info(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { - int rate = 44100, format = ESD_STEREO|ESD_BITS16; - int *response; - pa_sink *sink; - assert(c && data && length == sizeof(int)); - - if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { - rate = sink->sample_spec.rate; - format = format_native2esd(&sink->sample_spec); - } - - response = connection_write(c, sizeof(int)*3); - assert(response); - *(response++) = 0; - *(response++) = MAYBE_INT32_SWAP(c->swap_byte_order, rate); - *(response++) = MAYBE_INT32_SWAP(c->swap_byte_order, format); - return 0; -} - -static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length) { - uint8_t *response; - size_t t, k, s; - struct connection *conn; - size_t idx = PA_IDXSET_INVALID; - unsigned nsamples; - assert(c && data && length == sizeof(int)); - - if (esd_proto_server_info(c, request, data, length) < 0) - return -1; - - k = sizeof(int)*5+ESD_NAME_MAX; - s = sizeof(int)*6+ESD_NAME_MAX; - nsamples = c->protocol->core->scache ? pa_idxset_size(c->protocol->core->scache) : 0; - response = connection_write(c, (t = s*(nsamples+1) + k*(c->protocol->n_player+1))); - assert(k); - - for (conn = pa_idxset_first(c->protocol->connections, &idx); conn; conn = pa_idxset_next(c->protocol->connections, &idx)) { - int format = ESD_BITS16 | ESD_STEREO, rate = 44100, lvolume = ESD_VOLUME_BASE, rvolume = ESD_VOLUME_BASE; - - if (conn->state != ESD_STREAMING_DATA) - continue; - - assert(t >= s+k+k); - - if (conn->sink_input) { - rate = conn->sink_input->sample_spec.rate; - lvolume = (conn->sink_input->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; - rvolume = (conn->sink_input->volume.values[1]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; - format = format_native2esd(&conn->sink_input->sample_spec); - } - - /* id */ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (int) (conn->index+1)); - response += sizeof(int); - - /* name */ - assert(conn->client); - strncpy((char*) response, conn->client->name, ESD_NAME_MAX); - response += ESD_NAME_MAX; - - /* rate */ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, rate); - response += sizeof(int); - - /* left */ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, lvolume); - response += sizeof(int); - - /*right*/ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, rvolume); - response += sizeof(int); - - /*format*/ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, format); - response += sizeof(int); - - t-= k; - } - - assert(t == s*(nsamples+1)+k); - memset(response, 0, k); - response += k; - t -= k; - - if (nsamples) { - pa_scache_entry *ce; - - idx = PA_IDXSET_INVALID; - for (ce = pa_idxset_first(c->protocol->core->scache, &idx); ce; ce = pa_idxset_next(c->protocol->core->scache, &idx)) { - assert(t >= s*2); - - /* id */ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (int) (ce->index+1)); - response += sizeof(int); - - /* name */ - if (strncmp(ce->name, SCACHE_PREFIX, sizeof(SCACHE_PREFIX)-1) == 0) - strncpy((char*) response, ce->name+sizeof(SCACHE_PREFIX)-1, ESD_NAME_MAX); - else - snprintf((char*) response, ESD_NAME_MAX, "native.%s", ce->name); - response += ESD_NAME_MAX; - - /* rate */ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, ce->sample_spec.rate); - response += sizeof(int); - - /* left */ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); - response += sizeof(int); - - /*right*/ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); - response += sizeof(int); - - /*format*/ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, format_native2esd(&ce->sample_spec)); - response += sizeof(int); - - /*length*/ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (int) ce->memchunk.length); - response += sizeof(int); - - t -= s; - } - } - - assert(t == s); - memset(response, 0, s); - - return 0; -} - -static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { - int *ok; - uint32_t idx; - pa_volume_t lvolume, rvolume; - struct connection *conn; - assert(c && data && length == sizeof(int)*3); - - idx = MAYBE_UINT32_SWAP(c->swap_byte_order, *(const int*)data)-1; - lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, *((const int*)data + 1)); - lvolume = (lvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; - rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, *((const int*)data + 2)); - rvolume = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; - - ok = connection_write(c, sizeof(int)); - assert(ok); - - if ((conn = pa_idxset_get_by_index(c->protocol->connections, idx))) { - assert(conn->sink_input); - conn->sink_input->volume.values[0] = lvolume; - conn->sink_input->volume.values[1] = rvolume; - conn->sink_input->volume.channels = 2; - *ok = 1; - } else - *ok = 0; - - return 0; -} - -static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { - pa_sample_spec ss; - int format, rate; - size_t sc_length; - uint32_t idx; - int *ok; - char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; - assert(c && data && length == (ESD_NAME_MAX+3*sizeof(int))); - - format = MAYBE_INT32_SWAP(c->swap_byte_order, *(const int*)data); - rate = MAYBE_INT32_SWAP(c->swap_byte_order, *((const int*)data + 1)); - - ss.rate = rate; - format_esd2native(format, c->swap_byte_order, &ss); - - sc_length = (size_t) MAYBE_INT32_SWAP(c->swap_byte_order, (*((const int*)data + 2))); - - if (sc_length >= MAX_CACHE_SAMPLE_SIZE) - return -1; - - strcpy(name, SCACHE_PREFIX); - strncpy(name+sizeof(SCACHE_PREFIX)-1, (const char*) data+3*sizeof(int), ESD_NAME_MAX); - name[sizeof(name)-1] = 0; - - assert(!c->scache.memchunk.memblock); - c->scache.memchunk.memblock = pa_memblock_new(sc_length, c->protocol->core->memblock_stat); - c->scache.memchunk.index = 0; - c->scache.memchunk.length = sc_length; - c->scache.sample_spec = ss; - assert(!c->scache.name); - c->scache.name = pa_xstrdup(name); - - c->state = ESD_CACHING_SAMPLE; - - pa_scache_add_item(c->protocol->core, c->scache.name, NULL, NULL, NULL, &idx); - - ok = connection_write(c, sizeof(int)); - assert(ok); - - *ok = idx+1; - - return 0; -} - -static int esd_proto_sample_get_id(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { - int *ok; - uint32_t idx; - char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; - assert(c && data && length == ESD_NAME_MAX); - - ok = connection_write(c, sizeof(int)); - assert(ok); - - *ok = -1; - - strcpy(name, SCACHE_PREFIX); - strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX); - name[sizeof(name)-1] = 0; - - if ((idx = pa_scache_get_id_by_name(c->protocol->core, name)) != PA_IDXSET_INVALID) - *ok = (int) idx +1; - - return 0; -} - -static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length) { - int *ok; - const char *name; - uint32_t idx; - assert(c && data && length == sizeof(int)); - - idx = (uint32_t) MAYBE_INT32_SWAP(c->swap_byte_order, *(const int*)data)-1; - - ok = connection_write(c, sizeof(int)); - assert(ok); - - *ok = 0; - - if ((name = pa_scache_get_name_by_id(c->protocol->core, idx))) { - if (request == ESD_PROTO_SAMPLE_PLAY) { - pa_sink *sink; - - if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) - if (pa_scache_play_item(c->protocol->core, name, sink, NULL) >= 0) - *ok = (int) idx+1; - } else { - assert(request == ESD_PROTO_SAMPLE_FREE); - - if (pa_scache_remove_item(c->protocol->core, name) >= 0) - *ok = (int) idx+1; - } - } - - return 0; -} - -static int esd_proto_standby_or_resume(struct connection *c, PA_GCC_UNUSED esd_proto_t request, PA_GCC_UNUSED const void *data, PA_GCC_UNUSED size_t length) { - int *ok; - ok = connection_write(c, sizeof(int)*2); - assert(ok); - ok[0] = 1; - ok[1] = 1; - return 0; -} - -/*** client callbacks ***/ - -static void client_kill_cb(pa_client *c) { - assert(c && c->userdata); - connection_free(c->userdata); -} - -/*** pa_iochannel callbacks ***/ - -static int do_read(struct connection *c) { - assert(c && c->io); - -/* pa_log("READ\n"); */ - - if (c->state == ESD_NEXT_REQUEST) { - ssize_t r; - assert(c->read_data_length < sizeof(c->request)); - - if ((r = pa_iochannel_read(c->io, ((uint8_t*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { - if (r != 0) - pa_log_warn(__FILE__": read() failed: %s\n", strerror(errno)); - return -1; - } - - if ((c->read_data_length+= r) >= sizeof(c->request)) { - struct proto_handler *handler; - - c->request = MAYBE_INT32_SWAP(c->swap_byte_order, c->request); - - if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) { - pa_log(__FILE__": recieved invalid request.\n"); - return -1; - } - - handler = proto_map+c->request; - -/* pa_log(__FILE__": executing request #%u\n", c->request); */ - - if (!handler->proc) { - pa_log(__FILE__": recieved unimplemented request #%u.\n", c->request); - return -1; - } - - if (handler->data_length == 0) { - c->read_data_length = 0; - - if (handler->proc(c, c->request, NULL, 0) < 0) - return -1; - - } else { - if (c->read_data_alloc < handler->data_length) - c->read_data = pa_xrealloc(c->read_data, c->read_data_alloc = handler->data_length); - assert(c->read_data); - - c->state = ESD_NEEDS_REQDATA; - c->read_data_length = 0; - } - } - - } else if (c->state == ESD_NEEDS_REQDATA) { - ssize_t r; - struct proto_handler *handler = proto_map+c->request; - - assert(handler->proc); - - assert(c->read_data && c->read_data_length < handler->data_length); - - if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { - if (r != 0) - pa_log_warn(__FILE__": read() failed: %s\n", strerror(errno)); - return -1; - } - - if ((c->read_data_length+= r) >= handler->data_length) { - size_t l = c->read_data_length; - assert(handler->proc); - - c->state = ESD_NEXT_REQUEST; - c->read_data_length = 0; - - if (handler->proc(c, c->request, c->read_data, l) < 0) - return -1; - } - } else if (c->state == ESD_CACHING_SAMPLE) { - ssize_t r; - - assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); - - if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { - if (r!= 0) - pa_log_warn(__FILE__": read() failed: %s\n", strerror(errno)); - return -1; - } - - c->scache.memchunk.index += r; - assert(c->scache.memchunk.index <= c->scache.memchunk.length); - - if (c->scache.memchunk.index == c->scache.memchunk.length) { - uint32_t idx; - int *ok; - - c->scache.memchunk.index = 0; - pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, NULL, &c->scache.memchunk, &idx); - - pa_memblock_unref(c->scache.memchunk.memblock); - c->scache.memchunk.memblock = NULL; - c->scache.memchunk.index = c->scache.memchunk.length = 0; - - pa_xfree(c->scache.name); - c->scache.name = NULL; - - c->state = ESD_NEXT_REQUEST; - - ok = connection_write(c, sizeof(int)); - assert(ok); - *ok = idx+1; - } - - } else if (c->state == ESD_STREAMING_DATA && c->sink_input) { - pa_memchunk chunk; - ssize_t r; - size_t l; - - assert(c->input_memblockq); - -/* pa_log("STREAMING_DATA\n"); */ - - if (!(l = pa_memblockq_missing(c->input_memblockq))) - return 0; - - if (l > c->playback.fragment_size) - l = c->playback.fragment_size; - - if (c->playback.current_memblock) - if (c->playback.current_memblock->length - c->playback.memblock_index < l) { - pa_memblock_unref(c->playback.current_memblock); - c->playback.current_memblock = NULL; - c->playback.memblock_index = 0; - } - - if (!c->playback.current_memblock) { - c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2, c->protocol->core->memblock_stat); - assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); - c->playback.memblock_index = 0; - } - - if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { - if (r != 0) - pa_log(__FILE__": read() failed: %s\n", strerror(errno)); - return -1; - } - -/* pa_log(__FILE__": read %u\n", r); */ - - chunk.memblock = c->playback.current_memblock; - chunk.index = c->playback.memblock_index; - chunk.length = r; - assert(chunk.memblock); - - c->playback.memblock_index += r; - - assert(c->input_memblockq); - pa_memblockq_push_align(c->input_memblockq, &chunk, 0); - assert(c->sink_input); - pa_sink_notify(c->sink_input->sink); - } - - return 0; -} - -static int do_write(struct connection *c) { - assert(c && c->io); - -/* pa_log("WRITE\n"); */ - - if (c->write_data_length) { - ssize_t r; - - assert(c->write_data_index < c->write_data_length); - if ((r = pa_iochannel_write(c->io, (uint8_t*) c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); - return -1; - } - - if ((c->write_data_index +=r) >= c->write_data_length) - c->write_data_length = c->write_data_index = 0; - - } else if (c->state == ESD_STREAMING_DATA && c->source_output) { - pa_memchunk chunk; - ssize_t r; - - assert(c->output_memblockq); - if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) - return 0; - - assert(chunk.memblock && chunk.length); - - if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { - pa_memblock_unref(chunk.memblock); - pa_log(__FILE__": write(): %s\n", strerror(errno)); - return -1; - } - - pa_memblockq_drop(c->output_memblockq, &chunk, r); - pa_memblock_unref(chunk.memblock); - } - - return 0; -} - -static void do_work(struct connection *c) { - assert(c); - - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - c->protocol->core->mainloop->defer_enable(c->defer_event, 0); - -/* pa_log("DOWORK %i\n", pa_iochannel_is_hungup(c->io)); */ - - if (!c->dead && pa_iochannel_is_readable(c->io)) - if (do_read(c) < 0) - goto fail; - - if (!c->dead && pa_iochannel_is_writable(c->io)) - if (do_write(c) < 0) - goto fail; - - /* In case the line was hungup, make sure to rerun this function - as soon as possible, until all data has been read. */ - - if (!c->dead && pa_iochannel_is_hungup(c->io)) - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); - - return; - -fail: - - if (c->state == ESD_STREAMING_DATA && c->sink_input) { - c->dead = 1; - pa_memblockq_prebuf_disable(c->input_memblockq); - - pa_iochannel_free(c->io); - c->io = NULL; - - } else - connection_free(c); -} - -static void io_callback(pa_iochannel*io, void *userdata) { - struct connection *c = userdata; - assert(io && c && c->io == io); - -/* pa_log("IO\n"); */ - - do_work(c); -} - -/*** defer callback ***/ - -static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { - struct connection *c = userdata; - assert(a && c && c->defer_event == e); - -/* pa_log("DEFER\n"); */ - - do_work(c); -} - -/*** sink_input callbacks ***/ - -static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { - struct connection*c; - assert(i && i->userdata && chunk); - c = i->userdata; - - if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) { - - if (c->dead) - connection_free(c); - - return -1; - } - - return 0; -} - -static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { - struct connection*c = i->userdata; - assert(i && c && length); - -/* pa_log("DROP\n"); */ - - pa_memblockq_drop(c->input_memblockq, chunk, length); - - /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - - if (!c->dead) - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); - -/* assert(pa_memblockq_get_length(c->input_memblockq) > 2048); */ -} - -static void sink_input_kill_cb(pa_sink_input *i) { - assert(i && i->userdata); - connection_free((struct connection *) i->userdata); -} - -static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { - struct connection*c = i->userdata; - assert(i && c); - return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); -} - -/*** source_output callbacks ***/ - -static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { - struct connection *c = o->userdata; - assert(o && c && chunk); - - pa_memblockq_push(c->output_memblockq, chunk, 0); - - /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - - if (!c->dead) - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); -} - -static void source_output_kill_cb(pa_source_output *o) { - assert(o && o->userdata); - connection_free((struct connection *) o->userdata); -} - -static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { - struct connection*c = o->userdata; - assert(o && c); - return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec); -} - -/*** socket server callback ***/ - -static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { - struct connection *c = userdata; - assert(m && tv && c && c->auth_timeout_event == e); - - if (!c->authorized) - connection_free(c); -} - -static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { - struct connection *c; - pa_protocol_esound *p = userdata; - char cname[256]; - assert(s && io && p); - - if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); - pa_iochannel_free(io); - return; - } - - c = pa_xmalloc(sizeof(struct connection)); - c->protocol = p; - c->io = io; - pa_iochannel_set_callback(c->io, io_callback, c); - - pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); - assert(p->core); - c->client = pa_client_new(p->core, __FILE__, cname); - assert(c->client); - c->client->owner = p->module; - c->client->kill = client_kill_cb; - c->client->userdata = c; - - c->authorized = p->public; - c->swap_byte_order = 0; - c->dead = 0; - - c->read_data_length = 0; - c->read_data = pa_xmalloc(c->read_data_alloc = proto_map[ESD_PROTO_CONNECT].data_length); - - c->write_data_length = c->write_data_index = c->write_data_alloc = 0; - c->write_data = NULL; - - c->state = ESD_NEEDS_REQDATA; - c->request = ESD_PROTO_CONNECT; - - c->sink_input = NULL; - c->input_memblockq = NULL; - - c->source_output = NULL; - c->output_memblockq = NULL; - - c->playback.current_memblock = NULL; - c->playback.memblock_index = 0; - c->playback.fragment_size = 0; - - c->scache.memchunk.length = c->scache.memchunk.index = 0; - c->scache.memchunk.memblock = NULL; - c->scache.name = NULL; - - if (!c->authorized) { - struct timeval tv; - pa_gettimeofday(&tv); - tv.tv_sec += AUTH_TIMEOUT; - c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c); - } else - c->auth_timeout_event = NULL; - - c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c); - assert(c->defer_event); - p->core->mainloop->defer_enable(c->defer_event, 0); - - pa_idxset_put(p->connections, c, &c->index); -} - -/*** entry points ***/ - -pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { - pa_protocol_esound *p; - int public = 0; - assert(core && server && ma); - - p = pa_xmalloc(sizeof(pa_protocol_esound)); - - if (pa_modargs_get_value_boolean(ma, "public", &public) < 0) { - pa_log(__FILE__": public= expects a boolean argument.\n"); - return NULL; - } - - if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", DEFAULT_COOKIE_FILE), p->esd_key, sizeof(p->esd_key)) < 0) { - pa_xfree(p); - return NULL; - } - - p->module = m; - p->public = public; - p->server = server; - pa_socket_server_set_callback(p->server, on_connection, p); - p->core = core; - p->connections = pa_idxset_new(NULL, NULL); - assert(p->connections); - - p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); - p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL)); - p->n_player = 0; - - return p; -} - -void pa_protocol_esound_free(pa_protocol_esound *p) { - struct connection *c; - assert(p); - - while ((c = pa_idxset_first(p->connections, NULL))) - connection_free(c); - - pa_idxset_free(p->connections, NULL, NULL); - pa_socket_server_unref(p->server); - pa_xfree(p); -} diff --git a/polyp/protocol-esound.h b/polyp/protocol-esound.h deleted file mode 100644 index 71d58464..00000000 --- a/polyp/protocol-esound.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef fooprotocolesoundhfoo -#define fooprotocolesoundhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "core.h" -#include "socket-server.h" -#include "module.h" -#include "modargs.h" - -typedef struct pa_protocol_esound pa_protocol_esound; - -pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma); -void pa_protocol_esound_free(pa_protocol_esound *p); - -#endif diff --git a/polyp/protocol-http.c b/polyp/protocol-http.c deleted file mode 100644 index 3e55df03..00000000 --- a/polyp/protocol-http.c +++ /dev/null @@ -1,265 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "protocol-http.h" -#include "ioline.h" -#include "xmalloc.h" -#include "log.h" -#include "namereg.h" -#include "cli-text.h" - -/* Don't allow more than this many concurrent connections */ -#define MAX_CONNECTIONS 10 - -#define internal_server_error(c) http_message((c), 500, "Internal Server Error", NULL) - -#define URL_ROOT "/" -#define URL_CSS "/style" -#define URL_STATUS "/status" - -struct connection { - pa_protocol_http *protocol; - pa_ioline *line; - enum { REQUEST_LINE, MIME_HEADER, DATA } state; - char *url; -}; - -struct pa_protocol_http { - pa_module *module; - pa_core *core; - pa_socket_server*server; - pa_idxset *connections; -}; - -static void http_response(struct connection *c, int code, const char *msg, const char *mime) { - char s[256]; - assert(c); - assert(msg); - assert(mime); - - snprintf(s, sizeof(s), - "HTTP/1.0 %i %s\n" - "Connection: close\n" - "Content-Type: %s\n" - "Cache-Control: no-cache\n" - "Expires: 0\n" - "Server: "PACKAGE_NAME"/"PACKAGE_VERSION"\n" - "\n", code, msg, mime); - - pa_ioline_puts(c->line, s); -} - -static void http_message(struct connection *c, int code, const char *msg, const char *text) { - char s[256]; - assert(c); - - http_response(c, code, msg, "text/html"); - - if (!text) - text = msg; - - snprintf(s, sizeof(s), - "\n" - "\n" - "%s\n" - "%s\n", - text, text); - - pa_ioline_puts(c->line, s); - pa_ioline_defer_close(c->line); -} - - -static void connection_free(struct connection *c, int del) { - assert(c); - - if (c->url) - pa_xfree(c->url); - - if (del) - pa_idxset_remove_by_data(c->protocol->connections, c, NULL); - pa_ioline_unref(c->line); - pa_xfree(c); -} - -static void line_callback(pa_ioline *line, const char *s, void *userdata) { - struct connection *c = userdata; - assert(line); - assert(c); - - if (!s) { - /* EOF */ - connection_free(c, 1); - return; - } - - switch (c->state) { - case REQUEST_LINE: { - if (memcmp(s, "GET ", 4)) - goto fail; - - s +=4; - - c->url = pa_xstrndup(s, strcspn(s, " \r\n\t?")); - c->state = MIME_HEADER; - break; - - } - - case MIME_HEADER: { - - /* Ignore MIME headers */ - if (strcspn(s, " \r\n") != 0) - break; - - /* We're done */ - c->state = DATA; - - pa_log_info(__FILE__": request for %s\n", c->url); - - if (!strcmp(c->url, URL_ROOT)) { - char txt[256]; - http_response(c, 200, "OK", "text/html"); - - pa_ioline_puts(c->line, - "\n" - "\n" - ""PACKAGE_NAME" "PACKAGE_VERSION"\n" - "\n"); - - pa_ioline_puts(c->line, - "

    "PACKAGE_NAME" "PACKAGE_VERSION"

    \n" - ""); - -#define PRINTF_FIELD(a,b) pa_ioline_printf(c->line, "\n",(a),(b)) - - PRINTF_FIELD("User Name:", pa_get_user_name(txt, sizeof(txt))); - PRINTF_FIELD("Fully Qualified Domain Name:", pa_get_fqdn(txt, sizeof(txt))); - PRINTF_FIELD("Default Sample Specification:", pa_sample_spec_snprint(txt, sizeof(txt), &c->protocol->core->default_sample_spec)); - PRINTF_FIELD("Default Sink:", pa_namereg_get_default_sink_name(c->protocol->core)); - PRINTF_FIELD("Default Source:", pa_namereg_get_default_source_name(c->protocol->core)); - - pa_ioline_puts(c->line, "
    %s%s
    "); - - pa_ioline_puts(c->line, "

    Click here for an extensive server status report.

    "); - - pa_ioline_puts(c->line, "\n"); - - pa_ioline_defer_close(c->line); - } else if (!strcmp(c->url, URL_CSS)) { - http_response(c, 200, "OK", "text/css"); - - pa_ioline_puts(c->line, - "body { color: black; background-color: white; margin: 0.5cm; }\n" - "a:link, a:visited { color: #900000; }\n" - "p { margin-left: 0.5cm; margin-right: 0.5cm; }\n" - "h1 { color: #00009F; }\n" - "h2 { color: #00009F; }\n" - "ul { margin-left: .5cm; }\n" - "ol { margin-left: .5cm; }\n" - "pre { margin-left: .5cm; background-color: #f0f0f0; padding: 0.4cm;}\n" - ".grey { color: #afafaf; }\n" - "table { margin-left: 1cm; border:1px solid lightgrey; padding: 0.2cm; }\n" - "td { padding-left:10px; padding-right:10px; }\n"); - - pa_ioline_defer_close(c->line); - } else if (!strcmp(c->url, URL_STATUS)) { - char *r; - - http_response(c, 200, "OK", "text/plain"); - r = pa_full_status_string(c->protocol->core); - pa_ioline_puts(c->line, r); - pa_xfree(r); - - pa_ioline_defer_close(c->line); - } else - http_message(c, 404, "Not Found", NULL); - - break; - } - - default: - ; - } - - return; - -fail: - internal_server_error(c); -} - -static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { - pa_protocol_http *p = userdata; - struct connection *c; - assert(s && io && p); - - if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log_warn(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); - pa_iochannel_free(io); - return; - } - - c = pa_xmalloc(sizeof(struct connection)); - c->protocol = p; - c->line = pa_ioline_new(io); - c->state = REQUEST_LINE; - c->url = NULL; - - pa_ioline_set_callback(c->line, line_callback, c); - pa_idxset_put(p->connections, c, NULL); -} - -pa_protocol_http* pa_protocol_http_new(pa_core *core, pa_socket_server *server, pa_module *m, PA_GCC_UNUSED pa_modargs *ma) { - pa_protocol_http* p; - assert(core && server); - - p = pa_xmalloc(sizeof(pa_protocol_http)); - p->module = m; - p->core = core; - p->server = server; - p->connections = pa_idxset_new(NULL, NULL); - - pa_socket_server_set_callback(p->server, on_connection, p); - - return p; -} - -static void free_connection(void *p, PA_GCC_UNUSED void *userdata) { - assert(p); - connection_free(p, 0); -} - -void pa_protocol_http_free(pa_protocol_http *p) { - assert(p); - - pa_idxset_free(p->connections, free_connection, NULL); - pa_socket_server_unref(p->server); - pa_xfree(p); -} diff --git a/polyp/protocol-http.h b/polyp/protocol-http.h deleted file mode 100644 index 0a1855e9..00000000 --- a/polyp/protocol-http.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef fooprotocolhttphfoo -#define fooprotocolhttphfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "core.h" -#include "socket-server.h" -#include "module.h" -#include "modargs.h" - -typedef struct pa_protocol_http pa_protocol_http; - -pa_protocol_http* pa_protocol_http_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma); -void pa_protocol_http_free(pa_protocol_http *n); - -#endif diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c deleted file mode 100644 index b94903d9..00000000 --- a/polyp/protocol-native.c +++ /dev/null @@ -1,2216 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "protocol-native.h" -#include "native-common.h" -#include "packet.h" -#include "client.h" -#include "source-output.h" -#include "sink-input.h" -#include "pstream.h" -#include "tagstruct.h" -#include "pdispatch.h" -#include "pstream-util.h" -#include "authkey.h" -#include "namereg.h" -#include "scache.h" -#include "xmalloc.h" -#include "util.h" -#include "subscribe.h" -#include "log.h" -#include "autoload.h" -#include "authkey-prop.h" -#include "strlist.h" -#include "props.h" - -/* Kick a client if it doesn't authenticate within this time */ -#define AUTH_TIMEOUT 5 - -/* Don't accept more connection than this */ -#define MAX_CONNECTIONS 10 - -struct connection; -struct pa_protocol_native; - -struct record_stream { - struct connection *connection; - uint32_t index; - pa_source_output *source_output; - pa_memblockq *memblockq; - size_t fragment_size; -}; - -struct playback_stream { - int type; - struct connection *connection; - uint32_t index; - pa_sink_input *sink_input; - pa_memblockq *memblockq; - size_t requested_bytes; - int drain_request; - uint32_t drain_tag; -}; - -struct upload_stream { - int type; - struct connection *connection; - uint32_t index; - pa_memchunk memchunk; - size_t length; - char *name; - pa_sample_spec sample_spec; - pa_channel_map channel_map; -}; - -struct output_stream { - int type; -}; - -enum { - UPLOAD_STREAM, - PLAYBACK_STREAM -}; - -struct connection { - int authorized; - pa_protocol_native *protocol; - pa_client *client; - pa_pstream *pstream; - pa_pdispatch *pdispatch; - pa_idxset *record_streams, *output_streams; - uint32_t rrobin_index; - pa_subscription *subscription; - pa_time_event *auth_timeout_event; -}; - -struct pa_protocol_native { - pa_module *module; - int public; - pa_core *core; - pa_socket_server *server; - pa_idxset *connections; - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; - int auth_cookie_in_property; -}; - -static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk); -static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length); -static void sink_input_kill_cb(pa_sink_input *i); -static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i); - -static void request_bytes(struct playback_stream*s); - -static void source_output_kill_cb(pa_source_output *o); -static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk); -static pa_usec_t source_output_get_latency_cb(pa_source_output *o); - -static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_flush_or_trigger_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_add_autoload(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_remove_autoload(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_get_autoload_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_get_autoload_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); - -static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = NULL, - [PA_COMMAND_TIMEOUT] = NULL, - [PA_COMMAND_REPLY] = NULL, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream, - [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream, - [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream, - [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream, - [PA_COMMAND_AUTH] = command_auth, - [PA_COMMAND_REQUEST] = NULL, - [PA_COMMAND_EXIT] = command_exit, - [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name, - [PA_COMMAND_LOOKUP_SINK] = command_lookup, - [PA_COMMAND_LOOKUP_SOURCE] = command_lookup, - [PA_COMMAND_STAT] = command_stat, - [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency, - [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency, - [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream, - [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream, - [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream, - [PA_COMMAND_PLAY_SAMPLE] = command_play_sample, - [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample, - [PA_COMMAND_GET_SINK_INFO] = command_get_info, - [PA_COMMAND_GET_SOURCE_INFO] = command_get_info, - [PA_COMMAND_GET_CLIENT_INFO] = command_get_info, - [PA_COMMAND_GET_MODULE_INFO] = command_get_info, - [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info, - [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info, - [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info, - [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list, - [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list, - [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list, - [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list, - [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list, - [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list, - [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list, - [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info, - [PA_COMMAND_SUBSCRIBE] = command_subscribe, - - [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume, - [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume, - - [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream, - [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_flush_or_trigger_playback_stream, - [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_flush_or_trigger_playback_stream, - [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_flush_or_trigger_playback_stream, - - [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream, - [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream, - - [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source, - [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source, - [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name, - [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name, - [PA_COMMAND_KILL_CLIENT] = command_kill, - [PA_COMMAND_KILL_SINK_INPUT] = command_kill, - [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill, - [PA_COMMAND_LOAD_MODULE] = command_load_module, - [PA_COMMAND_UNLOAD_MODULE] = command_unload_module, - [PA_COMMAND_GET_AUTOLOAD_INFO] = command_get_autoload_info, - [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = command_get_autoload_info_list, - [PA_COMMAND_ADD_AUTOLOAD] = command_add_autoload, - [PA_COMMAND_REMOVE_AUTOLOAD] = command_remove_autoload, - -}; - -/* structure management */ - -static struct upload_stream* upload_stream_new( - struct connection *c, - const pa_sample_spec *ss, - const pa_channel_map *map, - const char *name, size_t length) { - - struct upload_stream *s; - assert(c && ss && name && length); - - s = pa_xmalloc(sizeof(struct upload_stream)); - s->type = UPLOAD_STREAM; - s->connection = c; - s->sample_spec = *ss; - s->channel_map = *map; - s->name = pa_xstrdup(name); - - s->memchunk.memblock = NULL; - s->memchunk.index = 0; - s->memchunk.length = 0; - - s->length = length; - - pa_idxset_put(c->output_streams, s, &s->index); - return s; -} - -static void upload_stream_free(struct upload_stream *o) { - assert(o && o->connection); - - pa_idxset_remove_by_data(o->connection->output_streams, o, NULL); - - pa_xfree(o->name); - - if (o->memchunk.memblock) - pa_memblock_unref(o->memchunk.memblock); - - pa_xfree(o); -} - -static struct record_stream* record_stream_new( - struct connection *c, - pa_source *source, - const pa_sample_spec *ss, - const pa_channel_map *map, - const char *name, - size_t maxlength, - size_t fragment_size) { - - struct record_stream *s; - pa_source_output *source_output; - size_t base; - assert(c && source && ss && name && maxlength); - - if (!(source_output = pa_source_output_new(source, __FILE__, name, ss, map, -1))) - return NULL; - - s = pa_xmalloc(sizeof(struct record_stream)); - s->connection = c; - s->source_output = source_output; - s->source_output->push = source_output_push_cb; - s->source_output->kill = source_output_kill_cb; - s->source_output->get_latency = source_output_get_latency_cb; - s->source_output->userdata = s; - s->source_output->owner = c->protocol->module; - s->source_output->client = c->client; - - s->memblockq = pa_memblockq_new(maxlength, 0, base = pa_frame_size(ss), 0, 0, c->protocol->core->memblock_stat); - assert(s->memblockq); - - s->fragment_size = (fragment_size/base)*base; - if (!s->fragment_size) - s->fragment_size = base; - - pa_idxset_put(c->record_streams, s, &s->index); - return s; -} - -static void record_stream_free(struct record_stream* r) { - assert(r && r->connection); - - pa_idxset_remove_by_data(r->connection->record_streams, r, NULL); - pa_source_output_disconnect(r->source_output); - pa_source_output_unref(r->source_output); - pa_memblockq_free(r->memblockq); - pa_xfree(r); -} - -static struct playback_stream* playback_stream_new( - struct connection *c, - pa_sink *sink, - const pa_sample_spec *ss, - const pa_channel_map *map, - const char *name, - size_t maxlength, - size_t tlength, - size_t prebuf, - size_t minreq, - pa_cvolume *volume) { - - struct playback_stream *s; - pa_sink_input *sink_input; - assert(c && sink && ss && name && maxlength); - - if (!(sink_input = pa_sink_input_new(sink, __FILE__, name, ss, map, 0, -1))) - return NULL; - - s = pa_xmalloc(sizeof(struct playback_stream)); - s->type = PLAYBACK_STREAM; - s->connection = c; - s->sink_input = sink_input; - - s->sink_input->peek = sink_input_peek_cb; - s->sink_input->drop = sink_input_drop_cb; - s->sink_input->kill = sink_input_kill_cb; - s->sink_input->get_latency = sink_input_get_latency_cb; - s->sink_input->userdata = s; - s->sink_input->owner = c->protocol->module; - s->sink_input->client = c->client; - - s->memblockq = pa_memblockq_new(maxlength, tlength, pa_frame_size(ss), prebuf, minreq, c->protocol->core->memblock_stat); - assert(s->memblockq); - - s->requested_bytes = 0; - s->drain_request = 0; - - s->sink_input->volume = *volume; - - pa_idxset_put(c->output_streams, s, &s->index); - return s; -} - -static void playback_stream_free(struct playback_stream* p) { - assert(p && p->connection); - - if (p->drain_request) - pa_pstream_send_error(p->connection->pstream, p->drain_tag, PA_ERROR_NOENTITY); - - pa_idxset_remove_by_data(p->connection->output_streams, p, NULL); - pa_sink_input_disconnect(p->sink_input); - pa_sink_input_unref(p->sink_input); - pa_memblockq_free(p->memblockq); - pa_xfree(p); -} - -static void connection_free(struct connection *c) { - struct record_stream *r; - struct output_stream *o; - assert(c && c->protocol); - - pa_idxset_remove_by_data(c->protocol->connections, c, NULL); - while ((r = pa_idxset_first(c->record_streams, NULL))) - record_stream_free(r); - pa_idxset_free(c->record_streams, NULL, NULL); - - while ((o = pa_idxset_first(c->output_streams, NULL))) - if (o->type == PLAYBACK_STREAM) - playback_stream_free((struct playback_stream*) o); - else - upload_stream_free((struct upload_stream*) o); - pa_idxset_free(c->output_streams, NULL, NULL); - - pa_pdispatch_unref(c->pdispatch); - pa_pstream_close(c->pstream); - pa_pstream_unref(c->pstream); - pa_client_free(c->client); - - if (c->subscription) - pa_subscription_free(c->subscription); - - if (c->auth_timeout_event) - c->protocol->core->mainloop->time_free(c->auth_timeout_event); - - pa_xfree(c); -} - -static void request_bytes(struct playback_stream *s) { - pa_tagstruct *t; - size_t l; - assert(s); - - if (!(l = pa_memblockq_missing(s->memblockq))) - return; - - if (l <= s->requested_bytes) - return; - - l -= s->requested_bytes; - - if (l < pa_memblockq_get_minreq(s->memblockq)) - return; - - s->requested_bytes += l; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REQUEST); - pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ - pa_tagstruct_putu32(t, s->index); - pa_tagstruct_putu32(t, l); - pa_pstream_send_tagstruct(s->connection->pstream, t); - -/* pa_log(__FILE__": Requesting %u bytes\n", l); */ -} - -static void send_memblock(struct connection *c) { - uint32_t start; - struct record_stream *r; - - start = PA_IDXSET_INVALID; - for (;;) { - pa_memchunk chunk; - - if (!(r = pa_idxset_rrobin(c->record_streams, &c->rrobin_index))) - return; - - if (start == PA_IDXSET_INVALID) - start = c->rrobin_index; - else if (start == c->rrobin_index) - return; - - if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) { - pa_memchunk schunk = chunk; - - if (schunk.length > r->fragment_size) - schunk.length = r->fragment_size; - - pa_pstream_send_memblock(c->pstream, r->index, 0, &schunk); - pa_memblockq_drop(r->memblockq, &chunk, schunk.length); - pa_memblock_unref(schunk.memblock); - - return; - } - } -} - -static void send_playback_stream_killed(struct playback_stream *p) { - pa_tagstruct *t; - assert(p); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED); - pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ - pa_tagstruct_putu32(t, p->index); - pa_pstream_send_tagstruct(p->connection->pstream, t); -} - -static void send_record_stream_killed(struct record_stream *r) { - pa_tagstruct *t; - assert(r); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED); - pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ - pa_tagstruct_putu32(t, r->index); - pa_pstream_send_tagstruct(r->connection->pstream, t); -} - -/*** sinkinput callbacks ***/ - -static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { - struct playback_stream *s; - assert(i && i->userdata && chunk); - s = i->userdata; - - if (pa_memblockq_peek(s->memblockq, chunk) < 0) - return -1; - - return 0; -} - -static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { - struct playback_stream *s; - assert(i && i->userdata && length); - s = i->userdata; - - pa_memblockq_drop(s->memblockq, chunk, length); - request_bytes(s); - - if (s->drain_request && !pa_memblockq_is_readable(s->memblockq)) { - pa_pstream_send_simple_ack(s->connection->pstream, s->drain_tag); - s->drain_request = 0; - } - -/* pa_log(__FILE__": after_drop: %u\n", pa_memblockq_get_length(s->memblockq)); */ -} - -static void sink_input_kill_cb(pa_sink_input *i) { - assert(i && i->userdata); - send_playback_stream_killed((struct playback_stream *) i->userdata); - playback_stream_free((struct playback_stream *) i->userdata); -} - -static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { - struct playback_stream *s; - assert(i && i->userdata); - s = i->userdata; - - /*pa_log(__FILE__": get_latency: %u\n", pa_memblockq_get_length(s->memblockq));*/ - - return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec); -} - -/*** source_output callbacks ***/ - -static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { - struct record_stream *s; - assert(o && o->userdata && chunk); - s = o->userdata; - - pa_memblockq_push_align(s->memblockq, chunk, 0); - if (!pa_pstream_is_pending(s->connection->pstream)) - send_memblock(s->connection); -} - -static void source_output_kill_cb(pa_source_output *o) { - assert(o && o->userdata); - send_record_stream_killed((struct record_stream *) o->userdata); - record_stream_free((struct record_stream *) o->userdata); -} - -static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { - struct record_stream *s; - assert(o && o->userdata); - s = o->userdata; - - /*pa_log(__FILE__": get_latency: %u\n", pa_memblockq_get_length(s->memblockq));*/ - - return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec); -} - -/*** pdispatch callbacks ***/ - -static void protocol_error(struct connection *c) { - pa_log(__FILE__": protocol error, kicking client\n"); - connection_free(c); -} - -static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - struct playback_stream *s; - size_t maxlength, tlength, prebuf, minreq; - uint32_t sink_index; - const char *name, *sink_name; - pa_sample_spec ss; - pa_channel_map map; - pa_tagstruct *reply; - pa_sink *sink; - pa_cvolume volume; - int corked; - - assert(c && t && c->protocol && c->protocol->core); - - if (pa_tagstruct_get( - t, - PA_TAG_STRING, &name, - PA_TAG_SAMPLE_SPEC, &ss, - PA_TAG_CHANNEL_MAP, &map, - PA_TAG_U32, &sink_index, - PA_TAG_STRING, &sink_name, - PA_TAG_U32, &maxlength, - PA_TAG_BOOLEAN, &corked, - PA_TAG_U32, &tlength, - PA_TAG_U32, &prebuf, - PA_TAG_U32, &minreq, - PA_TAG_CVOLUME, &volume, - PA_TAG_INVALID) < 0 || - !pa_tagstruct_eof(t) || - !name) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (sink_index != (uint32_t) -1) - sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); - else - sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1); - - if (!sink) { - pa_log("%s: Can't find a suitable sink.\n", __FILE__); - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - if (!(s = playback_stream_new(c, sink, &ss, &map, name, maxlength, tlength, prebuf, minreq, &volume))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); - return; - } - - pa_sink_input_cork(s->sink_input, corked); - - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - pa_tagstruct_putu32(reply, s->index); - assert(s->sink_input); - pa_tagstruct_putu32(reply, s->sink_input->index); - pa_tagstruct_putu32(reply, s->requested_bytes = pa_memblockq_missing(s->memblockq)); - pa_pstream_send_tagstruct(c->pstream, reply); - request_bytes(s); -} - -static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t channel; - assert(c && t); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (command == PA_COMMAND_DELETE_PLAYBACK_STREAM) { - struct playback_stream *s; - if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != PLAYBACK_STREAM)) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); - return; - } - - playback_stream_free(s); - } else if (command == PA_COMMAND_DELETE_RECORD_STREAM) { - struct record_stream *s; - if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); - return; - } - - record_stream_free(s); - } else { - struct upload_stream *s; - assert(command == PA_COMMAND_DELETE_UPLOAD_STREAM); - if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != UPLOAD_STREAM)) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); - return; - } - - upload_stream_free(s); - } - - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - struct record_stream *s; - size_t maxlength, fragment_size; - uint32_t source_index; - const char *name, *source_name; - pa_sample_spec ss; - pa_channel_map map; - pa_tagstruct *reply; - pa_source *source; - int corked; - assert(c && t && c->protocol && c->protocol->core); - - if (pa_tagstruct_gets(t, &name) < 0 || !name || - pa_tagstruct_get_sample_spec(t, &ss) < 0 || - pa_tagstruct_get_channel_map(t, &map) < 0 || - pa_tagstruct_getu32(t, &source_index) < 0 || - pa_tagstruct_gets(t, &source_name) < 0 || - pa_tagstruct_getu32(t, &maxlength) < 0 || - pa_tagstruct_get_boolean(t, &corked) < 0 || - pa_tagstruct_getu32(t, &fragment_size) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (source_index != (uint32_t) -1) - source = pa_idxset_get_by_index(c->protocol->core->sources, source_index); - else - source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE, 1); - - if (!source) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - if (!(s = record_stream_new(c, source, &ss, &map, name, maxlength, fragment_size))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); - return; - } - - pa_source_output_cork(s->source_output, corked); - - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - pa_tagstruct_putu32(reply, s->index); - assert(s->source_output); - pa_tagstruct_putu32(reply, s->source_output->index); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_exit(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - assert(c && t); - - if (!pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop); - c->protocol->core->mainloop->quit(c->protocol->core->mainloop, 0); - pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */ - return; -} - -static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - const void*cookie; - assert(c && t); - - if (pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) != 0) { - pa_log(__FILE__": Denied access to client with invalid authorization key.\n"); - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - c->authorized = 1; - if (c->auth_timeout_event) { - c->protocol->core->mainloop->time_free(c->auth_timeout_event); - c->auth_timeout_event = NULL; - } - } - - pa_pstream_send_simple_ack(c->pstream, tag); - return; -} - -static void command_set_client_name(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - const char *name; - assert(c && t); - - if (pa_tagstruct_gets(t, &name) < 0 || !name || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - pa_client_set_name(c->client, name); - pa_pstream_send_simple_ack(c->pstream, tag); - return; -} - -static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - const char *name; - uint32_t idx = PA_IDXSET_INVALID; - assert(c && t); - - if (pa_tagstruct_gets(t, &name) < 0 || !name || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (command == PA_COMMAND_LOOKUP_SINK) { - pa_sink *sink; - if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1))) - idx = sink->index; - } else { - pa_source *source; - assert(command == PA_COMMAND_LOOKUP_SOURCE); - if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1))) - idx = source->index; - } - - if (idx == PA_IDXSET_INVALID) - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - else { - pa_tagstruct *reply; - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - pa_tagstruct_putu32(reply, idx); - pa_pstream_send_tagstruct(c->pstream, reply); - } -} - -static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - struct playback_stream *s; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - s->drain_request = 0; - - pa_memblockq_prebuf_disable(s->memblockq); - - if (!pa_memblockq_is_readable(s->memblockq)) { -/* pa_log("immediate drain: %u\n", pa_memblockq_get_length(s->memblockq)); */ - pa_pstream_send_simple_ack(c->pstream, tag); - } else { -/* pa_log("slow drain triggered\n"); */ - s->drain_request = 1; - s->drain_tag = tag; - - pa_sink_notify(s->sink_input->sink); - } -} - -static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - pa_tagstruct *reply; - assert(c && t); - - if (!pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->total); - pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->total_size); - pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->allocated); - pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->allocated_size); - pa_tagstruct_putu32(reply, pa_scache_total_size(c->protocol->core)); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - pa_tagstruct *reply; - struct playback_stream *s; - struct timeval tv, now; - uint64_t counter; - uint32_t idx; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - pa_tagstruct_get_timeval(t, &tv) < 0 || - pa_tagstruct_getu64(t, &counter) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - pa_tagstruct_put_usec(reply, pa_sink_input_get_latency(s->sink_input)); - pa_tagstruct_put_usec(reply, pa_sink_get_latency(s->sink_input->sink)); - pa_tagstruct_put_usec(reply, 0); - pa_tagstruct_put_boolean(reply, pa_memblockq_is_readable(s->memblockq)); - pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq)); - pa_tagstruct_put_timeval(reply, &tv); - pa_gettimeofday(&now); - pa_tagstruct_put_timeval(reply, &now); - pa_tagstruct_putu64(reply, counter); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - pa_tagstruct *reply; - struct record_stream *s; - struct timeval tv, now; - uint64_t counter; - uint32_t idx; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - pa_tagstruct_get_timeval(t, &tv) < 0 || - pa_tagstruct_getu64(t, &counter) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - pa_tagstruct_put_usec(reply, pa_source_output_get_latency(s->source_output)); - pa_tagstruct_put_usec(reply, s->source_output->source->monitor_of ? pa_sink_get_latency(s->source_output->source->monitor_of) : 0); - pa_tagstruct_put_usec(reply, pa_source_get_latency(s->source_output->source)); - pa_tagstruct_put_boolean(reply, 0); - pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq)); - pa_tagstruct_put_timeval(reply, &tv); - pa_gettimeofday(&now); - pa_tagstruct_put_timeval(reply, &now); - pa_tagstruct_putu64(reply, counter); - pa_pstream_send_tagstruct(c->pstream, reply); -} - - -static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - struct upload_stream *s; - size_t length; - const char *name; - pa_sample_spec ss; - pa_channel_map map; - pa_tagstruct *reply; - assert(c && t && c->protocol && c->protocol->core); - - if (pa_tagstruct_gets(t, &name) < 0 || !name || - pa_tagstruct_get_sample_spec(t, &ss) < 0 || - pa_tagstruct_get_channel_map(t, &map) < 0 || - pa_tagstruct_getu32(t, &length) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if ((length % pa_frame_size(&ss)) != 0 || length <= 0 || !*name) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); - return; - } - - if (!(s = upload_stream_new(c, &ss, &map, name, length))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); - return; - } - - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - pa_tagstruct_putu32(reply, s->index); - pa_tagstruct_putu32(reply, length); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t channel; - struct upload_stream *s; - uint32_t idx; - assert(c && t); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != UPLOAD_STREAM)) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); - return; - } - - pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, &idx); - pa_pstream_send_simple_ack(c->pstream, tag); - upload_stream_free(s); -} - -static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t sink_index; - pa_cvolume volume; - pa_sink *sink; - const char *name, *sink_name; - assert(c && t); - - if (pa_tagstruct_getu32(t, &sink_index) < 0 || - pa_tagstruct_gets(t, &sink_name) < 0 || - pa_tagstruct_get_cvolume(t, &volume) < 0 || - pa_tagstruct_gets(t, &name) < 0 || !name || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (sink_index != (uint32_t) -1) - sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); - else - sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1); - - if (!sink) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - if (pa_scache_play_item(c->protocol->core, name, sink, &volume) < 0) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_remove_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - const char *name; - assert(c && t); - - if (pa_tagstruct_gets(t, &name) < 0 || !name || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (pa_scache_remove_item(c->protocol->core, name) < 0) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void sink_fill_tagstruct(pa_tagstruct *t, pa_sink *sink) { - assert(t && sink); - pa_tagstruct_put( - t, - PA_TAG_U32, sink->index, - PA_TAG_STRING, sink->name, - PA_TAG_STRING, sink->description, - PA_TAG_SAMPLE_SPEC, &sink->sample_spec, - PA_TAG_CHANNEL_MAP, &sink->channel_map, - PA_TAG_U32, sink->owner ? sink->owner->index : PA_INVALID_INDEX, - PA_TAG_CVOLUME, pa_sink_get_volume(sink, PA_MIXER_HARDWARE), - PA_TAG_U32, sink->monitor_source->index, - PA_TAG_STRING, sink->monitor_source->name, - PA_TAG_USEC, pa_sink_get_latency(sink), - PA_TAG_STRING, sink->driver, - PA_TAG_INVALID); -} - -static void source_fill_tagstruct(pa_tagstruct *t, pa_source *source) { - assert(t && source); - pa_tagstruct_putu32(t, source->index); - pa_tagstruct_puts(t, source->name); - pa_tagstruct_puts(t, source->description); - pa_tagstruct_put_sample_spec(t, &source->sample_spec); - pa_tagstruct_put_channel_map(t, &source->channel_map); - pa_tagstruct_putu32(t, source->owner ? source->owner->index : (uint32_t) -1); - pa_tagstruct_putu32(t, source->monitor_of ? source->monitor_of->index : (uint32_t) -1); - pa_tagstruct_puts(t, source->monitor_of ? source->monitor_of->name : NULL); - pa_tagstruct_put_usec(t, pa_source_get_latency(source)); - pa_tagstruct_puts(t, source->driver); -} - -static void client_fill_tagstruct(pa_tagstruct *t, pa_client *client) { - assert(t && client); - pa_tagstruct_putu32(t, client->index); - pa_tagstruct_puts(t, client->name); - pa_tagstruct_putu32(t, client->owner ? client->owner->index : (uint32_t) -1); - pa_tagstruct_puts(t, client->driver); -} - -static void module_fill_tagstruct(pa_tagstruct *t, pa_module *module) { - assert(t && module); - pa_tagstruct_putu32(t, module->index); - pa_tagstruct_puts(t, module->name); - pa_tagstruct_puts(t, module->argument); - pa_tagstruct_putu32(t, module->n_used); - pa_tagstruct_put_boolean(t, module->auto_unload); -} - -static void sink_input_fill_tagstruct(pa_tagstruct *t, pa_sink_input *s) { - assert(t && s); - pa_tagstruct_putu32(t, s->index); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_putu32(t, s->owner ? s->owner->index : (uint32_t) -1); - pa_tagstruct_putu32(t, s->client ? s->client->index : (uint32_t) -1); - pa_tagstruct_putu32(t, s->sink->index); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_put_channel_map(t, &s->channel_map); - pa_tagstruct_put_cvolume(t, &s->volume); - pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s)); - pa_tagstruct_put_usec(t, pa_sink_get_latency(s->sink)); - pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s))); - pa_tagstruct_puts(t, s->driver); -} - -static void source_output_fill_tagstruct(pa_tagstruct *t, pa_source_output *s) { - assert(t && s); - pa_tagstruct_putu32(t, s->index); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_putu32(t, s->owner ? s->owner->index : (uint32_t) -1); - pa_tagstruct_putu32(t, s->client ? s->client->index : (uint32_t) -1); - pa_tagstruct_putu32(t, s->source->index); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_put_channel_map(t, &s->channel_map); - pa_tagstruct_put_usec(t, pa_source_output_get_latency(s)); - pa_tagstruct_put_usec(t, pa_source_get_latency(s->source)); - pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s))); - pa_tagstruct_puts(t, s->driver); -} - -static void scache_fill_tagstruct(pa_tagstruct *t, pa_scache_entry *e) { - assert(t && e); - pa_tagstruct_putu32(t, e->index); - pa_tagstruct_puts(t, e->name); - pa_tagstruct_put_cvolume(t, &e->volume); - pa_tagstruct_put_usec(t, pa_bytes_to_usec(e->memchunk.length, &e->sample_spec)); - pa_tagstruct_put_sample_spec(t, &e->sample_spec); - pa_tagstruct_put_channel_map(t, &e->channel_map); - pa_tagstruct_putu32(t, e->memchunk.length); - pa_tagstruct_put_boolean(t, e->lazy); - pa_tagstruct_puts(t, e->filename); -} - -static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - pa_sink *sink = NULL; - pa_source *source = NULL; - pa_client *client = NULL; - pa_module *module = NULL; - pa_sink_input *si = NULL; - pa_source_output *so = NULL; - pa_scache_entry *sce = NULL; - const char *name; - pa_tagstruct *reply; - assert(c && t); - - - if (pa_tagstruct_getu32(t, &idx) < 0 || - (command != PA_COMMAND_GET_CLIENT_INFO && - command != PA_COMMAND_GET_MODULE_INFO && - command != PA_COMMAND_GET_SINK_INPUT_INFO && - command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO && - pa_tagstruct_gets(t, &name) < 0) || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (command == PA_COMMAND_GET_SINK_INFO) { - if (idx != (uint32_t) -1) - sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); - else - sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); - } else if (command == PA_COMMAND_GET_SOURCE_INFO) { - if (idx != (uint32_t) -1) - source = pa_idxset_get_by_index(c->protocol->core->sources, idx); - else - source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); - } else if (command == PA_COMMAND_GET_CLIENT_INFO) - client = pa_idxset_get_by_index(c->protocol->core->clients, idx); - else if (command == PA_COMMAND_GET_MODULE_INFO) - module = pa_idxset_get_by_index(c->protocol->core->modules, idx); - else if (command == PA_COMMAND_GET_SINK_INPUT_INFO) - si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); - else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO) - so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); - else { - assert(command == PA_COMMAND_GET_SAMPLE_INFO); - if (idx != (uint32_t) -1) - sce = pa_idxset_get_by_index(c->protocol->core->scache, idx); - else - sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE, 0); - } - - if (!sink && !source && !client && !module && !si && !so && !sce) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - if (sink) - sink_fill_tagstruct(reply, sink); - else if (source) - source_fill_tagstruct(reply, source); - else if (client) - client_fill_tagstruct(reply, client); - else if (module) - module_fill_tagstruct(reply, module); - else if (si) - sink_input_fill_tagstruct(reply, si); - else if (so) - source_output_fill_tagstruct(reply, so); - else - scache_fill_tagstruct(reply, sce); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - pa_idxset *i; - uint32_t idx; - void *p; - pa_tagstruct *reply; - assert(c && t); - - if (!pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - - if (command == PA_COMMAND_GET_SINK_INFO_LIST) - i = c->protocol->core->sinks; - else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST) - i = c->protocol->core->sources; - else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST) - i = c->protocol->core->clients; - else if (command == PA_COMMAND_GET_MODULE_INFO_LIST) - i = c->protocol->core->modules; - else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) - i = c->protocol->core->sink_inputs; - else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST) - i = c->protocol->core->source_outputs; - else { - assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); - i = c->protocol->core->scache; - } - - if (i) { - for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) { - if (command == PA_COMMAND_GET_SINK_INFO_LIST) - sink_fill_tagstruct(reply, p); - else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST) - source_fill_tagstruct(reply, p); - else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST) - client_fill_tagstruct(reply, p); - else if (command == PA_COMMAND_GET_MODULE_INFO_LIST) - module_fill_tagstruct(reply, p); - else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) - sink_input_fill_tagstruct(reply, p); - else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST) - source_output_fill_tagstruct(reply, p); - else { - assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); - scache_fill_tagstruct(reply, p); - } - } - } - - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_get_server_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - pa_tagstruct *reply; - char txt[256]; - const char *n; - assert(c && t); - - if (!pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - pa_tagstruct_puts(reply, PACKAGE_NAME); - pa_tagstruct_puts(reply, PACKAGE_VERSION); - pa_tagstruct_puts(reply, pa_get_user_name(txt, sizeof(txt))); - pa_tagstruct_puts(reply, pa_get_fqdn(txt, sizeof(txt))); - pa_tagstruct_put_sample_spec(reply, &c->protocol->core->default_sample_spec); - - n = pa_namereg_get_default_sink_name(c->protocol->core); - pa_tagstruct_puts(reply, n); - n = pa_namereg_get_default_source_name(c->protocol->core); - pa_tagstruct_puts(reply, n); - - pa_tagstruct_putu32(reply, c->protocol->core->cookie); - - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) { - pa_tagstruct *t; - struct connection *c = userdata; - assert(c && core); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_putu32(t, e); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - pa_subscription_mask_t m; - assert(c && t); - - if (pa_tagstruct_getu32(t, &m) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (c->subscription) - pa_subscription_free(c->subscription); - - if (m != 0) { - c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c); - assert(c->subscription); - } else - c->subscription = NULL; - - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_set_volume(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - pa_cvolume volume; - pa_sink *sink = NULL; - pa_sink_input *si = NULL; - const char *name = NULL; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) || - pa_tagstruct_get_cvolume(t, &volume) || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (command == PA_COMMAND_SET_SINK_VOLUME) { - if (idx != (uint32_t) -1) - sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); - else - sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); - } else { - assert(command == PA_COMMAND_SET_SINK_INPUT_VOLUME); - si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); - } - - if (!si && !sink) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - if (sink) - pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &volume); - else if (si) - pa_sink_input_set_volume(si, &volume); - - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - int b; - struct playback_stream *s; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - pa_tagstruct_get_boolean(t, &b) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - pa_sink_input_cork(s->sink_input, b); - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_flush_or_trigger_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - struct playback_stream *s; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - if (command == PA_COMMAND_PREBUF_PLAYBACK_STREAM) - pa_memblockq_prebuf_reenable(s->memblockq); - else if (command == PA_COMMAND_TRIGGER_PLAYBACK_STREAM) - pa_memblockq_prebuf_disable(s->memblockq); - else { - assert(command == PA_COMMAND_FLUSH_PLAYBACK_STREAM); - pa_memblockq_flush(s->memblockq); - /*pa_log(__FILE__": flush: %u\n", pa_memblockq_get_length(s->memblockq));*/ - } - - pa_sink_notify(s->sink_input->sink); - pa_pstream_send_simple_ack(c->pstream, tag); - request_bytes(s); -} - -static void command_cork_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - struct record_stream *s; - int b; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - pa_tagstruct_get_boolean(t, &b) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - pa_source_output_cork(s->source_output, b); - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_flush_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - struct record_stream *s; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - pa_memblockq_flush(s->memblockq); - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_set_default_sink_or_source(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - const char *s; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - pa_tagstruct_gets(t, &s) < 0 || !s || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - pa_namereg_set_default(c->protocol->core, s, command == PA_COMMAND_SET_DEFAULT_SOURCE ? PA_NAMEREG_SOURCE : PA_NAMEREG_SINK); - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - const char *name; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - pa_tagstruct_gets(t, &name) < 0 || !name || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) { - struct playback_stream *s; - - if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - pa_sink_input_set_name(s->sink_input, name); - - } else { - struct record_stream *s; - - if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - pa_source_output_set_name(s->source_output, name); - } - - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (command == PA_COMMAND_KILL_CLIENT) { - pa_client *client; - - if (!(client = pa_idxset_get_by_index(c->protocol->core->clients, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - pa_client_kill(client); - } else if (command == PA_COMMAND_KILL_SINK_INPUT) { - pa_sink_input *s; - - if (!(s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - pa_sink_input_kill(s); - } else { - pa_source_output *s; - - assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT); - - if (!(s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - pa_source_output_kill(s); - } - - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_load_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - pa_module *m; - const char *name, *argument; - pa_tagstruct *reply; - assert(c && t); - - if (pa_tagstruct_gets(t, &name) < 0 || !name || - pa_tagstruct_gets(t, &argument) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (!(m = pa_module_load(c->protocol->core, name, argument))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_INITFAILED); - return; - } - - reply = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - pa_tagstruct_putu32(reply, m->index); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_unload_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - pa_module *m; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (!(m = pa_idxset_get_by_index(c->protocol->core->modules, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - pa_module_unload_request(m); - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_add_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - const char *name, *module, *argument; - uint32_t type; - uint32_t idx; - pa_tagstruct *reply; - assert(c && t); - - if (pa_tagstruct_gets(t, &name) < 0 || !name || - pa_tagstruct_getu32(t, &type) < 0 || type > 1 || - pa_tagstruct_gets(t, &module) < 0 || !module || - pa_tagstruct_gets(t, &argument) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (pa_autoload_add(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, module, argument, &idx) < 0) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); - return; - } - - reply = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - pa_tagstruct_putu32(reply, idx); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_remove_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - const char *name = NULL; - uint32_t type, idx = PA_IDXSET_INVALID; - int r; - assert(c && t); - - if ((pa_tagstruct_getu32(t, &idx) < 0 && - (pa_tagstruct_gets(t, &name) < 0 || - pa_tagstruct_getu32(t, &type) < 0)) || - (!name && idx == PA_IDXSET_INVALID) || - (name && type > 1) || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - if (name) - r = pa_autoload_remove_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE); - else - r = pa_autoload_remove_by_index(c->protocol->core, idx); - - if (r < 0) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void autoload_fill_tagstruct(pa_tagstruct *t, const pa_autoload_entry *e) { - assert(t && e); - - pa_tagstruct_putu32(t, e->index); - pa_tagstruct_puts(t, e->name); - pa_tagstruct_putu32(t, e->type == PA_NAMEREG_SINK ? 0 : 1); - pa_tagstruct_puts(t, e->module); - pa_tagstruct_puts(t, e->argument); -} - -static void command_get_autoload_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - const pa_autoload_entry *a = NULL; - uint32_t type, idx; - const char *name; - pa_tagstruct *reply; - assert(c && t); - - if ((pa_tagstruct_getu32(t, &idx) < 0 && - (pa_tagstruct_gets(t, &name) < 0 || - pa_tagstruct_getu32(t, &type) < 0)) || - (!name && idx == PA_IDXSET_INVALID) || - (name && type > 1) || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - - if (name) - a = pa_autoload_get_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE); - else - a = pa_autoload_get_by_index(c->protocol->core, idx); - - if (!a) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); - return; - } - - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - autoload_fill_tagstruct(reply, a); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - pa_tagstruct *reply; - assert(c && t); - - if (!pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); - return; - } - - reply = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - - if (c->protocol->core->autoload_hashmap) { - pa_autoload_entry *a; - void *state = NULL; - - while ((a = pa_hashmap_iterate(c->protocol->core->autoload_hashmap, &state, NULL))) - autoload_fill_tagstruct(reply, a); - } - - pa_pstream_send_tagstruct(c->pstream, reply); -} - -/*** pstream callbacks ***/ - -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { - struct connection *c = userdata; - assert(p && packet && packet->data && c); - - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - pa_log(__FILE__": invalid packet.\n"); - connection_free(c); - } -} - -static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata) { - struct connection *c = userdata; - struct output_stream *stream; - assert(p && chunk && userdata); - - if (!(stream = pa_idxset_get_by_index(c->output_streams, channel))) { - pa_log(__FILE__": client sent block for invalid stream.\n"); - connection_free(c); - return; - } - - if (stream->type == PLAYBACK_STREAM) { - struct playback_stream *ps = (struct playback_stream*) stream; - if (chunk->length >= ps->requested_bytes) - ps->requested_bytes = 0; - else - ps->requested_bytes -= chunk->length; - - pa_memblockq_push_align(ps->memblockq, chunk, delta); - assert(ps->sink_input); -/* pa_log(__FILE__": after_recv: %u\n", pa_memblockq_get_length(p->memblockq)); */ - - pa_sink_notify(ps->sink_input->sink); -/* pa_log(__FILE__": Recieved %u bytes.\n", chunk->length); */ - - } else { - struct upload_stream *u = (struct upload_stream*) stream; - size_t l; - assert(u->type == UPLOAD_STREAM); - - if (!u->memchunk.memblock) { - if (u->length == chunk->length) { - u->memchunk = *chunk; - pa_memblock_ref(u->memchunk.memblock); - u->length = 0; - } else { - u->memchunk.memblock = pa_memblock_new(u->length, c->protocol->core->memblock_stat); - u->memchunk.index = u->memchunk.length = 0; - } - } - - assert(u->memchunk.memblock); - - l = u->length; - if (l > chunk->length) - l = chunk->length; - - if (l > 0) { - memcpy((uint8_t*) u->memchunk.memblock->data + u->memchunk.index + u->memchunk.length, - (uint8_t*) chunk->memblock->data+chunk->index, l); - u->memchunk.length += l; - u->length -= l; - } - } -} - -static void pstream_die_callback(pa_pstream *p, void *userdata) { - struct connection *c = userdata; - assert(p && c); - connection_free(c); - -/* pa_log(__FILE__": connection died.\n");*/ -} - - -static void pstream_drain_callback(pa_pstream *p, void *userdata) { - struct connection *c = userdata; - assert(p && c); - - send_memblock(c); -} - -/*** client callbacks ***/ - -static void client_kill_cb(pa_client *c) { - assert(c && c->userdata); - connection_free(c->userdata); -} - -/*** socket server callbacks ***/ - -static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { - struct connection *c = userdata; - assert(m && tv && c && c->auth_timeout_event == e); - - if (!c->authorized) - connection_free(c); -} - -static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, void *userdata) { - pa_protocol_native *p = userdata; - struct connection *c; - assert(io && p); - - if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log_warn(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); - pa_iochannel_free(io); - return; - } - - c = pa_xmalloc(sizeof(struct connection)); - - c->authorized =!! p->public; - - if (!c->authorized) { - struct timeval tv; - pa_gettimeofday(&tv); - tv.tv_sec += AUTH_TIMEOUT; - c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c); - } else - c->auth_timeout_event = NULL; - - c->protocol = p; - assert(p->core); - c->client = pa_client_new(p->core, __FILE__, "Client"); - assert(c->client); - c->client->kill = client_kill_cb; - c->client->userdata = c; - c->client->owner = p->module; - - c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->memblock_stat); - assert(c->pstream); - - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - - c->pdispatch = pa_pdispatch_new(p->core->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); - - c->record_streams = pa_idxset_new(NULL, NULL); - c->output_streams = pa_idxset_new(NULL, NULL); - assert(c->record_streams && c->output_streams); - - c->rrobin_index = PA_IDXSET_INVALID; - c->subscription = NULL; - - pa_idxset_put(p->connections, c, NULL); -} - -/*** module entry points ***/ - -static int load_key(pa_protocol_native*p, const char*fn) { - assert(p); - - p->auth_cookie_in_property = 0; - - if (!fn && pa_authkey_prop_get(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) { - pa_log_info(__FILE__": using already loaded auth cookie.\n"); - pa_authkey_prop_ref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); - p->auth_cookie_in_property = 1; - return 0; - } - - if (!fn) - fn = PA_NATIVE_COOKIE_FILE; - - if (pa_authkey_load_auto(fn, p->auth_cookie, sizeof(p->auth_cookie)) < 0) - return -1; - - pa_log_info(__FILE__": loading cookie from disk.\n"); - - if (pa_authkey_prop_put(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) - p->auth_cookie_in_property = 1; - - return 0; -} - -static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_modargs *ma) { - pa_protocol_native *p; - int public = 0; - assert(c && ma); - - if (pa_modargs_get_value_boolean(ma, "public", &public) < 0) { - pa_log(__FILE__": public= expects a boolean argument.\n"); - return NULL; - } - - p = pa_xmalloc(sizeof(pa_protocol_native)); - p->core = c; - p->module = m; - p->public = public; - p->server = NULL; - - if (load_key(p, pa_modargs_get_value(ma, "cookie", NULL)) < 0) { - pa_xfree(p); - return NULL; - } - - p->connections = pa_idxset_new(NULL, NULL); - assert(p->connections); - - return p; -} - -pa_protocol_native* pa_protocol_native_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { - char t[256]; - pa_protocol_native *p; - - if (!(p = protocol_new_internal(core, m, ma))) - return NULL; - - p->server = server; - pa_socket_server_set_callback(p->server, on_connection, p); - - if (pa_socket_server_get_address(p->server, t, sizeof(t))) { - pa_strlist *l; - l = pa_property_get(core, PA_NATIVE_SERVER_PROPERTY_NAME); - l = pa_strlist_prepend(l, t); - pa_property_replace(core, PA_NATIVE_SERVER_PROPERTY_NAME, l); - } - - return p; -} - -void pa_protocol_native_free(pa_protocol_native *p) { - struct connection *c; - assert(p); - - while ((c = pa_idxset_first(p->connections, NULL))) - connection_free(c); - pa_idxset_free(p->connections, NULL, NULL); - - if (p->server) { - char t[256]; - - if (pa_socket_server_get_address(p->server, t, sizeof(t))) { - pa_strlist *l; - l = pa_property_get(p->core, PA_NATIVE_SERVER_PROPERTY_NAME); - l = pa_strlist_remove(l, t); - - if (l) - pa_property_replace(p->core, PA_NATIVE_SERVER_PROPERTY_NAME, l); - else - pa_property_remove(p->core, PA_NATIVE_SERVER_PROPERTY_NAME); - } - - pa_socket_server_unref(p->server); - } - - if (p->auth_cookie_in_property) - pa_authkey_prop_unref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); - - pa_xfree(p); -} - -pa_protocol_native* pa_protocol_native_new_iochannel(pa_core*core, pa_iochannel *io, pa_module *m, pa_modargs *ma) { - pa_protocol_native *p; - - if (!(p = protocol_new_internal(core, m, ma))) - return NULL; - - on_connection(NULL, io, p); - - return p; -} diff --git a/polyp/protocol-native.h b/polyp/protocol-native.h deleted file mode 100644 index 12e85d0b..00000000 --- a/polyp/protocol-native.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef fooprotocolnativehfoo -#define fooprotocolnativehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "core.h" -#include "socket-server.h" -#include "module.h" -#include "modargs.h" - -typedef struct pa_protocol_native pa_protocol_native; - -pa_protocol_native* pa_protocol_native_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma); -void pa_protocol_native_free(pa_protocol_native *n); - -pa_protocol_native* pa_protocol_native_new_iochannel(pa_core*core, pa_iochannel *io, pa_module *m, pa_modargs *ma); - -#endif diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c deleted file mode 100644 index 113919b3..00000000 --- a/polyp/protocol-simple.c +++ /dev/null @@ -1,453 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "sink-input.h" -#include "source-output.h" -#include "protocol-simple.h" -#include "client.h" -#include "sample-util.h" -#include "namereg.h" -#include "xmalloc.h" -#include "log.h" - -/* Don't allow more than this many concurrent connections */ -#define MAX_CONNECTIONS 10 - -struct connection { - pa_protocol_simple *protocol; - pa_iochannel *io; - pa_sink_input *sink_input; - pa_source_output *source_output; - pa_client *client; - pa_memblockq *input_memblockq, *output_memblockq; - pa_defer_event *defer_event; - - struct { - pa_memblock *current_memblock; - size_t memblock_index, fragment_size; - } playback; -}; - -struct pa_protocol_simple { - pa_module *module; - pa_core *core; - pa_socket_server*server; - pa_idxset *connections; - enum { - RECORD = 1, - PLAYBACK = 2, - DUPLEX = 3 - } mode; - pa_sample_spec sample_spec; - char *source_name, *sink_name; -}; - -#define PLAYBACK_BUFFER_SECONDS (.5) -#define PLAYBACK_BUFFER_FRAGMENTS (10) -#define RECORD_BUFFER_SECONDS (5) -#define RECORD_BUFFER_FRAGMENTS (100) - -static void connection_free(struct connection *c) { - assert(c); - - pa_idxset_remove_by_data(c->protocol->connections, c, NULL); - - if (c->playback.current_memblock) - pa_memblock_unref(c->playback.current_memblock); - if (c->sink_input) { - pa_sink_input_disconnect(c->sink_input); - pa_sink_input_unref(c->sink_input); - } - if (c->source_output) { - pa_source_output_disconnect(c->source_output); - pa_source_output_unref(c->source_output); - } - if (c->client) - pa_client_free(c->client); - if (c->io) - pa_iochannel_free(c->io); - if (c->input_memblockq) - pa_memblockq_free(c->input_memblockq); - if (c->output_memblockq) - pa_memblockq_free(c->output_memblockq); - if (c->defer_event) - c->protocol->core->mainloop->defer_free(c->defer_event); - pa_xfree(c); -} - -static int do_read(struct connection *c) { - pa_memchunk chunk; - ssize_t r; - size_t l; - - if (!c->sink_input || !(l = pa_memblockq_missing(c->input_memblockq))) - return 0; - - if (l > c->playback.fragment_size) - l = c->playback.fragment_size; - - if (c->playback.current_memblock) - if (c->playback.current_memblock->length - c->playback.memblock_index < l) { - pa_memblock_unref(c->playback.current_memblock); - c->playback.current_memblock = NULL; - c->playback.memblock_index = 0; - } - - if (!c->playback.current_memblock) { - c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2, c->protocol->core->memblock_stat); - assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); - c->playback.memblock_index = 0; - } - - if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { - pa_log(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); - return -1; - } - - chunk.memblock = c->playback.current_memblock; - chunk.index = c->playback.memblock_index; - chunk.length = r; - assert(chunk.memblock); - - c->playback.memblock_index += r; - - assert(c->input_memblockq); - pa_memblockq_push_align(c->input_memblockq, &chunk, 0); - assert(c->sink_input); - pa_sink_notify(c->sink_input->sink); - - return 0; -} - -static int do_write(struct connection *c) { - pa_memchunk chunk; - ssize_t r; - - if (!c->source_output) - return 0; - - assert(c->output_memblockq); - if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) - return 0; - - assert(chunk.memblock && chunk.length); - - if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { - pa_memblock_unref(chunk.memblock); - pa_log(__FILE__": write(): %s\n", strerror(errno)); - return -1; - } - - pa_memblockq_drop(c->output_memblockq, &chunk, r); - pa_memblock_unref(chunk.memblock); - - return 0; -} - - -static void do_work(struct connection *c) { - assert(c); - - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - c->protocol->core->mainloop->defer_enable(c->defer_event, 0); - - if (pa_iochannel_is_writable(c->io)) - if (do_write(c) < 0) - goto fail; - - if (pa_iochannel_is_readable(c->io)) - if (do_read(c) < 0) - goto fail; - - if (pa_iochannel_is_hungup(c->io)) - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); - - return; - -fail: - connection_free(c); -} - -/*** sink_input callbacks ***/ - -static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { - struct connection*c; - assert(i && i->userdata && chunk); - c = i->userdata; - - if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) - return -1; - - return 0; -} - -static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { - struct connection*c = i->userdata; - assert(i && c && length); - - pa_memblockq_drop(c->input_memblockq, chunk, length); - - /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); -} - -static void sink_input_kill_cb(pa_sink_input *i) { - assert(i && i->userdata); - connection_free((struct connection *) i->userdata); -} - - -static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { - struct connection*c = i->userdata; - assert(i && c); - return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); -} - -/*** source_output callbacks ***/ - -static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { - struct connection *c = o->userdata; - assert(o && c && chunk); - - pa_memblockq_push(c->output_memblockq, chunk, 0); - - /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); -} - -static void source_output_kill_cb(pa_source_output *o) { - assert(o && o->userdata); - connection_free((struct connection *) o->userdata); -} - -static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { - struct connection*c = o->userdata; - assert(o && c); - return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec); -} - -/*** client callbacks ***/ - -static void client_kill_cb(pa_client *c) { - assert(c && c->userdata); - connection_free((struct connection *) c->userdata); -} - -/*** pa_iochannel callbacks ***/ - -static void io_callback(pa_iochannel*io, void *userdata) { - struct connection *c = userdata; - assert(io && c && c->io == io); - - do_work(c); -} - -/*** fixed callback ***/ - -static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { - struct connection *c = userdata; - assert(a && c && c->defer_event == e); - - do_work(c); -} - -/*** socket_server callbacks ***/ - -static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { - pa_protocol_simple *p = userdata; - struct connection *c = NULL; - char cname[256]; - assert(s && io && p); - - if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); - pa_iochannel_free(io); - return; - } - - c = pa_xmalloc(sizeof(struct connection)); - c->io = io; - c->sink_input = NULL; - c->source_output = NULL; - c->defer_event = NULL; - c->input_memblockq = c->output_memblockq = NULL; - c->protocol = p; - c->playback.current_memblock = NULL; - c->playback.memblock_index = 0; - c->playback.fragment_size = 0; - - pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); - c->client = pa_client_new(p->core, __FILE__, cname); - assert(c->client); - c->client->owner = p->module; - c->client->kill = client_kill_cb; - c->client->userdata = c; - - if (p->mode & PLAYBACK) { - pa_sink *sink; - size_t l; - - if (!(sink = pa_namereg_get(p->core, p->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": Failed to get sink.\n"); - goto fail; - } - - if (!(c->sink_input = pa_sink_input_new(sink, __FILE__, c->client->name, &p->sample_spec, NULL, 0, -1))) { - pa_log(__FILE__": Failed to create sink input.\n"); - goto fail; - } - - c->sink_input->owner = p->module; - c->sink_input->client = c->client; - - c->sink_input->peek = sink_input_peek_cb; - c->sink_input->drop = sink_input_drop_cb; - c->sink_input->kill = sink_input_kill_cb; - c->sink_input->get_latency = sink_input_get_latency_cb; - c->sink_input->userdata = c; - - l = (size_t) (pa_bytes_per_second(&p->sample_spec)*PLAYBACK_BUFFER_SECONDS); - c->input_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&p->sample_spec), l/2, l/PLAYBACK_BUFFER_FRAGMENTS, p->core->memblock_stat); - assert(c->input_memblockq); - pa_iochannel_socket_set_rcvbuf(io, l/PLAYBACK_BUFFER_FRAGMENTS*5); - c->playback.fragment_size = l/10; - } - - if (p->mode & RECORD) { - pa_source *source; - size_t l; - - if (!(source = pa_namereg_get(p->core, p->source_name, PA_NAMEREG_SOURCE, 1))) { - pa_log(__FILE__": Failed to get source.\n"); - goto fail; - } - - c->source_output = pa_source_output_new(source, __FILE__, c->client->name, &p->sample_spec, NULL, -1); - if (!c->source_output) { - pa_log(__FILE__": Failed to create source output.\n"); - goto fail; - } - c->source_output->owner = p->module; - c->source_output->client = c->client; - - c->source_output->push = source_output_push_cb; - c->source_output->kill = source_output_kill_cb; - c->source_output->get_latency = source_output_get_latency_cb; - c->source_output->userdata = c; - - l = (size_t) (pa_bytes_per_second(&p->sample_spec)*RECORD_BUFFER_SECONDS); - c->output_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&p->sample_spec), 0, 0, p->core->memblock_stat); - pa_iochannel_socket_set_sndbuf(io, l/RECORD_BUFFER_FRAGMENTS*2); - } - - pa_iochannel_set_callback(c->io, io_callback, c); - pa_idxset_put(p->connections, c, NULL); - - c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c); - assert(c->defer_event); - p->core->mainloop->defer_enable(c->defer_event, 0); - - return; - -fail: - if (c) - connection_free(c); -} - -pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { - pa_protocol_simple* p = NULL; - int enable; - assert(core && server && ma); - - p = pa_xmalloc0(sizeof(pa_protocol_simple)); - p->module = m; - p->core = core; - p->server = server; - p->connections = pa_idxset_new(NULL, NULL); - - p->sample_spec = core->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &p->sample_spec) < 0) { - pa_log(__FILE__": Failed to parse sample type specification.\n"); - goto fail; - } - - p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL)); - p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); - - enable = 0; - if (pa_modargs_get_value_boolean(ma, "record", &enable) < 0) { - pa_log(__FILE__": record= expects a numeric argument.\n"); - goto fail; - } - p->mode = enable ? RECORD : 0; - - enable = 1; - if (pa_modargs_get_value_boolean(ma, "playback", &enable) < 0) { - pa_log(__FILE__": playback= expects a numeric argument.\n"); - goto fail; - } - p->mode |= enable ? PLAYBACK : 0; - - if ((p->mode & (RECORD|PLAYBACK)) == 0) { - pa_log(__FILE__": neither playback nor recording enabled for protocol.\n"); - goto fail; - } - - pa_socket_server_set_callback(p->server, on_connection, p); - - return p; - -fail: - if (p) - pa_protocol_simple_free(p); - return NULL; -} - - -void pa_protocol_simple_free(pa_protocol_simple *p) { - struct connection *c; - assert(p); - - if (p->connections) { - while((c = pa_idxset_first(p->connections, NULL))) - connection_free(c); - - pa_idxset_free(p->connections, NULL, NULL); - } - - if (p->server) - pa_socket_server_unref(p->server); - pa_xfree(p); -} - diff --git a/polyp/protocol-simple.h b/polyp/protocol-simple.h deleted file mode 100644 index 63455a53..00000000 --- a/polyp/protocol-simple.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef fooprotocolsimplehfoo -#define fooprotocolsimplehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "socket-server.h" -#include "module.h" -#include "core.h" -#include "modargs.h" - -typedef struct pa_protocol_simple pa_protocol_simple; - -pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma); -void pa_protocol_simple_free(pa_protocol_simple *n); - -#endif diff --git a/polyp/pstream-util.c b/polyp/pstream-util.c deleted file mode 100644 index ecd63d15..00000000 --- a/polyp/pstream-util.c +++ /dev/null @@ -1,61 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "native-common.h" -#include "pstream-util.h" - -void pa_pstream_send_tagstruct(pa_pstream *p, pa_tagstruct *t) { - size_t length; - uint8_t *data; - pa_packet *packet; - assert(p); - assert(t); - - data = pa_tagstruct_free_data(t, &length); - assert(data && length); - packet = pa_packet_new_dynamic(data, length); - assert(packet); - pa_pstream_send_packet(p, packet); - pa_packet_unref(packet); -} - -void pa_pstream_send_error(pa_pstream *p, uint32_t tag, uint32_t error) { - pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_ERROR); - pa_tagstruct_putu32(t, tag); - pa_tagstruct_putu32(t, error); - pa_pstream_send_tagstruct(p, t); -} - -void pa_pstream_send_simple_ack(pa_pstream *p, uint32_t tag) { - pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REPLY); - pa_tagstruct_putu32(t, tag); - pa_pstream_send_tagstruct(p, t); -} diff --git a/polyp/pstream-util.h b/polyp/pstream-util.h deleted file mode 100644 index 601a9e99..00000000 --- a/polyp/pstream-util.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef foopstreamutilhfoo -#define foopstreamutilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include "pstream.h" -#include "tagstruct.h" - -/* The tagstruct is freed!*/ -void pa_pstream_send_tagstruct(pa_pstream *p, pa_tagstruct *t); - -void pa_pstream_send_error(pa_pstream *p, uint32_t tag, uint32_t error); -void pa_pstream_send_simple_ack(pa_pstream *p, uint32_t tag); - -#endif diff --git a/polyp/pstream.c b/polyp/pstream.c deleted file mode 100644 index bd00ba4f..00000000 --- a/polyp/pstream.c +++ /dev/null @@ -1,492 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#ifdef HAVE_NETINET_IN_H -#include -#endif - -#include "winsock.h" - -#include "pstream.h" -#include "queue.h" -#include "xmalloc.h" -#include "log.h" - -typedef enum pa_pstream_descriptor_index { - PA_PSTREAM_DESCRIPTOR_LENGTH, - PA_PSTREAM_DESCRIPTOR_CHANNEL, - PA_PSTREAM_DESCRIPTOR_DELTA, - PA_PSTREAM_DESCRIPTOR_MAX -} pa_pstream_descriptor_index; - -typedef uint32_t pa_pstream_descriptor[PA_PSTREAM_DESCRIPTOR_MAX]; - -#define PA_PSTREAM_DESCRIPTOR_SIZE (PA_PSTREAM_DESCRIPTOR_MAX*sizeof(uint32_t)) -#define FRAME_SIZE_MAX (1024*500) /* half a megabyte */ - -struct item_info { - enum { PA_PSTREAM_ITEM_PACKET, PA_PSTREAM_ITEM_MEMBLOCK } type; - - /* memblock info */ - pa_memchunk chunk; - uint32_t channel; - uint32_t delta; - - /* packet info */ - pa_packet *packet; -}; - -struct pa_pstream { - int ref; - - pa_mainloop_api *mainloop; - pa_defer_event *defer_event; - pa_iochannel *io; - pa_queue *send_queue; - - int dead; - void (*die_callback) (pa_pstream *p, void *userdata); - void *die_callback_userdata; - - struct { - struct item_info* current; - pa_pstream_descriptor descriptor; - void *data; - size_t index; - } write; - - struct { - pa_memblock *memblock; - pa_packet *packet; - pa_pstream_descriptor descriptor; - void *data; - size_t index; - } read; - - void (*recieve_packet_callback) (pa_pstream *p, pa_packet *packet, void *userdata); - void *recieve_packet_callback_userdata; - - void (*recieve_memblock_callback) (pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata); - void *recieve_memblock_callback_userdata; - - void (*drain_callback)(pa_pstream *p, void *userdata); - void *drain_userdata; - - pa_memblock_stat *memblock_stat; -}; - -static void do_write(pa_pstream *p); -static void do_read(pa_pstream *p); - -static void do_something(pa_pstream *p) { - assert(p); - - p->mainloop->defer_enable(p->defer_event, 0); - - pa_pstream_ref(p); - - if (!p->dead && pa_iochannel_is_readable(p->io)) - do_read(p); - - if (!p->dead && pa_iochannel_is_writable(p->io)) - do_write(p); - - /* In case the line was hungup, make sure to rerun this function - as soon as possible, until all data has been read. */ - - if (!p->dead && pa_iochannel_is_hungup(p->io)) - p->mainloop->defer_enable(p->defer_event, 1); - - pa_pstream_unref(p); -} - -static void io_callback(pa_iochannel*io, void *userdata) { - pa_pstream *p = userdata; - assert(p && p->io == io); - do_something(p); -} - -static void defer_callback(pa_mainloop_api *m, pa_defer_event *e, void*userdata) { - pa_pstream *p = userdata; - assert(p && p->defer_event == e && p->mainloop == m); - do_something(p); -} - -pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_stat *s) { - pa_pstream *p; - assert(io); - - p = pa_xmalloc(sizeof(pa_pstream)); - p->ref = 1; - p->io = io; - pa_iochannel_set_callback(io, io_callback, p); - - p->dead = 0; - p->die_callback = NULL; - p->die_callback_userdata = NULL; - - p->mainloop = m; - p->defer_event = m->defer_new(m, defer_callback, p); - m->defer_enable(p->defer_event, 0); - - p->send_queue = pa_queue_new(); - assert(p->send_queue); - - p->write.current = NULL; - p->write.index = 0; - - p->read.memblock = NULL; - p->read.packet = NULL; - p->read.index = 0; - - p->recieve_packet_callback = NULL; - p->recieve_packet_callback_userdata = NULL; - - p->recieve_memblock_callback = NULL; - p->recieve_memblock_callback_userdata = NULL; - - p->drain_callback = NULL; - p->drain_userdata = NULL; - - p->memblock_stat = s; - - pa_iochannel_socket_set_rcvbuf(io, 1024*8); - pa_iochannel_socket_set_sndbuf(io, 1024*8); - - return p; -} - -static void item_free(void *item, PA_GCC_UNUSED void *p) { - struct item_info *i = item; - assert(i); - - if (i->type == PA_PSTREAM_ITEM_MEMBLOCK) { - assert(i->chunk.memblock); - pa_memblock_unref(i->chunk.memblock); - } else { - assert(i->type == PA_PSTREAM_ITEM_PACKET); - assert(i->packet); - pa_packet_unref(i->packet); - } - - pa_xfree(i); -} - -static void pstream_free(pa_pstream *p) { - assert(p); - - pa_pstream_close(p); - - pa_queue_free(p->send_queue, item_free, NULL); - - if (p->write.current) - item_free(p->write.current, NULL); - - if (p->read.memblock) - pa_memblock_unref(p->read.memblock); - - if (p->read.packet) - pa_packet_unref(p->read.packet); - - pa_xfree(p); -} - -void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet) { - struct item_info *i; - assert(p && packet && p->ref >= 1); - - if (p->dead) - return; - -/* pa_log(__FILE__": push-packet %p\n", packet); */ - - i = pa_xmalloc(sizeof(struct item_info)); - i->type = PA_PSTREAM_ITEM_PACKET; - i->packet = pa_packet_ref(packet); - - pa_queue_push(p->send_queue, i); - p->mainloop->defer_enable(p->defer_event, 1); -} - -void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk) { - struct item_info *i; - assert(p && channel != (uint32_t) -1 && chunk && p->ref >= 1); - - if (p->dead) - return; - -/* pa_log(__FILE__": push-memblock %p\n", chunk); */ - - i = pa_xmalloc(sizeof(struct item_info)); - i->type = PA_PSTREAM_ITEM_MEMBLOCK; - i->chunk = *chunk; - i->channel = channel; - i->delta = delta; - - pa_memblock_ref(i->chunk.memblock); - - pa_queue_push(p->send_queue, i); - p->mainloop->defer_enable(p->defer_event, 1); -} - -void pa_pstream_set_recieve_packet_callback(pa_pstream *p, void (*callback) (pa_pstream *p, pa_packet *packet, void *userdata), void *userdata) { - assert(p && callback); - - p->recieve_packet_callback = callback; - p->recieve_packet_callback_userdata = userdata; -} - -void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, void (*callback) (pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata), void *userdata) { - assert(p && callback); - - p->recieve_memblock_callback = callback; - p->recieve_memblock_callback_userdata = userdata; -} - -static void prepare_next_write_item(pa_pstream *p) { - assert(p); - - if (!(p->write.current = pa_queue_pop(p->send_queue))) - return; - - p->write.index = 0; - - if (p->write.current->type == PA_PSTREAM_ITEM_PACKET) { - /*pa_log(__FILE__": pop-packet %p\n", p->write.current->packet);*/ - - assert(p->write.current->packet); - p->write.data = p->write.current->packet->data; - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->packet->length); - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl((uint32_t) -1); - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA] = 0; - } else { - assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK && p->write.current->chunk.memblock); - p->write.data = (uint8_t*) p->write.current->chunk.memblock->data + p->write.current->chunk.index; - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length); - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl(p->write.current->channel); - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA] = htonl(p->write.current->delta); - } -} - -static void do_write(pa_pstream *p) { - void *d; - size_t l; - ssize_t r; - assert(p); - - if (!p->write.current) - prepare_next_write_item(p); - - if (!p->write.current) - return; - - assert(p->write.data); - - if (p->write.index < PA_PSTREAM_DESCRIPTOR_SIZE) { - d = (uint8_t*) p->write.descriptor + p->write.index; - l = PA_PSTREAM_DESCRIPTOR_SIZE - p->write.index; - } else { - d = (uint8_t*) p->write.data + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE; - l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE); - } - - if ((r = pa_iochannel_write(p->io, d, l)) < 0) - goto die; - - p->write.index += r; - - if (p->write.index >= PA_PSTREAM_DESCRIPTOR_SIZE+ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])) { - assert(p->write.current); - item_free(p->write.current, (void *) 1); - p->write.current = NULL; - - if (p->drain_callback && !pa_pstream_is_pending(p)) - p->drain_callback(p, p->drain_userdata); - } - - return; - -die: - p->dead = 1; - if (p->die_callback) - p->die_callback(p, p->die_callback_userdata); -} - -static void do_read(pa_pstream *p) { - void *d; - size_t l; - ssize_t r; - assert(p); - - if (p->read.index < PA_PSTREAM_DESCRIPTOR_SIZE) { - d = (uint8_t*) p->read.descriptor + p->read.index; - l = PA_PSTREAM_DESCRIPTOR_SIZE - p->read.index; - } else { - assert(p->read.data); - d = (uint8_t*) p->read.data + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE; - l = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE); - } - - if ((r = pa_iochannel_read(p->io, d, l)) <= 0) - goto die; - - p->read.index += r; - - if (p->read.index == PA_PSTREAM_DESCRIPTOR_SIZE) { - /* Reading of frame descriptor complete */ - - /* Frame size too large */ - if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) > FRAME_SIZE_MAX) { - pa_log(__FILE__": Frame size too large\n"); - goto die; - } - - assert(!p->read.packet && !p->read.memblock); - - if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]) == (uint32_t) -1) { - /* Frame is a packet frame */ - p->read.packet = pa_packet_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])); - assert(p->read.packet); - p->read.data = p->read.packet->data; - } else { - /* Frame is a memblock frame */ - p->read.memblock = pa_memblock_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]), p->memblock_stat); - assert(p->read.memblock); - p->read.data = p->read.memblock->data; - } - - } else if (p->read.index > PA_PSTREAM_DESCRIPTOR_SIZE) { - /* Frame payload available */ - - if (p->read.memblock && p->recieve_memblock_callback) { /* Is this memblock data? Than pass it to the user */ - l = (p->read.index - r) < PA_PSTREAM_DESCRIPTOR_SIZE ? p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE : (size_t) r; - - if (l > 0) { - pa_memchunk chunk; - - chunk.memblock = p->read.memblock; - chunk.index = p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE - l; - chunk.length = l; - - if (p->recieve_memblock_callback) - p->recieve_memblock_callback( - p, - ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]), - ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA]), - &chunk, - p->recieve_memblock_callback_userdata); - } - } - - /* Frame complete */ - if (p->read.index >= ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) + PA_PSTREAM_DESCRIPTOR_SIZE) { - if (p->read.memblock) { - assert(!p->read.packet); - - pa_memblock_unref(p->read.memblock); - p->read.memblock = NULL; - } else { - assert(p->read.packet); - - if (p->recieve_packet_callback) - p->recieve_packet_callback(p, p->read.packet, p->recieve_packet_callback_userdata); - - pa_packet_unref(p->read.packet); - p->read.packet = NULL; - } - - p->read.index = 0; - } - } - - return; - -die: - p->dead = 1; - if (p->die_callback) - p->die_callback(p, p->die_callback_userdata); - -} - -void pa_pstream_set_die_callback(pa_pstream *p, void (*callback)(pa_pstream *p, void *userdata), void *userdata) { - assert(p && callback); - p->die_callback = callback; - p->die_callback_userdata = userdata; -} - -int pa_pstream_is_pending(pa_pstream *p) { - assert(p); - - if (p->dead) - return 0; - - return p->write.current || !pa_queue_is_empty(p->send_queue); -} - -void pa_pstream_set_drain_callback(pa_pstream *p, void (*cb)(pa_pstream *p, void *userdata), void *userdata) { - assert(p); - - p->drain_callback = cb; - p->drain_userdata = userdata; -} - -void pa_pstream_unref(pa_pstream*p) { - assert(p && p->ref >= 1); - - if (!(--(p->ref))) - pstream_free(p); -} - -pa_pstream* pa_pstream_ref(pa_pstream*p) { - assert(p && p->ref >= 1); - p->ref++; - return p; -} - -void pa_pstream_close(pa_pstream *p) { - assert(p); - - p->dead = 1; - - if (p->io) { - pa_iochannel_free(p->io); - p->io = NULL; - } - - if (p->defer_event) { - p->mainloop->defer_free(p->defer_event); - p->defer_event = NULL; - } - - p->die_callback = NULL; - p->drain_callback = NULL; - p->recieve_packet_callback = NULL; - p->recieve_memblock_callback = NULL; -} diff --git a/polyp/pstream.h b/polyp/pstream.h deleted file mode 100644 index 77c92802..00000000 --- a/polyp/pstream.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef foopstreamhfoo -#define foopstreamhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "packet.h" -#include "memblock.h" -#include "iochannel.h" -#include "mainloop-api.h" -#include "memchunk.h" - -typedef struct pa_pstream pa_pstream; - -pa_pstream* pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_stat *s); -void pa_pstream_unref(pa_pstream*p); -pa_pstream* pa_pstream_ref(pa_pstream*p); - -void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet); -void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk); - -void pa_pstream_set_recieve_packet_callback(pa_pstream *p, void (*callback) (pa_pstream *p, pa_packet *packet, void *userdata), void *userdata); -void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, void (*callback) (pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata), void *userdata); -void pa_pstream_set_drain_callback(pa_pstream *p, void (*cb)(pa_pstream *p, void *userdata), void *userdata); - -void pa_pstream_set_die_callback(pa_pstream *p, void (*callback)(pa_pstream *p, void *userdata), void *userdata); - -int pa_pstream_is_pending(pa_pstream *p); - -void pa_pstream_close(pa_pstream *p); - -#endif diff --git a/polyp/queue.c b/polyp/queue.c deleted file mode 100644 index 80ec0068..00000000 --- a/polyp/queue.c +++ /dev/null @@ -1,108 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "queue.h" -#include "xmalloc.h" - -struct queue_entry { - struct queue_entry *next; - void *data; -}; - -struct pa_queue { - struct queue_entry *front, *back; - unsigned length; -}; - -pa_queue* pa_queue_new(void) { - pa_queue *q = pa_xnew(pa_queue, 1); - q->front = q->back = NULL; - q->length = 0; - return q; -} - -void pa_queue_free(pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata) { - struct queue_entry *e; - assert(q); - - e = q->front; - while (e) { - struct queue_entry *n = e->next; - - if (destroy) - destroy(e->data, userdata); - - pa_xfree(e); - e = n; - } - - pa_xfree(q); -} - -void pa_queue_push(pa_queue *q, void *p) { - struct queue_entry *e; - - e = pa_xnew(struct queue_entry, 1); - e->data = p; - e->next = NULL; - - if (q->back) - q->back->next = e; - else { - assert(!q->front); - q->front = e; - } - - q->back = e; - q->length++; -} - -void* pa_queue_pop(pa_queue *q) { - void *p; - struct queue_entry *e; - assert(q); - - if (!(e = q->front)) - return NULL; - - q->front = e->next; - if (q->back == e) - q->back = NULL; - - p = e->data; - pa_xfree(e); - - q->length--; - - return p; -} - -int pa_queue_is_empty(pa_queue *q) { - assert(q); - return q->length == 0; -} diff --git a/polyp/queue.h b/polyp/queue.h deleted file mode 100644 index 3edcfb63..00000000 --- a/polyp/queue.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef fooqueuehfoo -#define fooqueuehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -typedef struct pa_queue pa_queue; - -/* A simple implementation of the abstract data type queue. Stores - * pointers as members. The memory has to be managed by the caller. */ - -pa_queue* pa_queue_new(void); - -/* Free the queue and run the specified callback function for every remaining entry. The callback function may be NULL. */ -void pa_queue_free(pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata); - -void pa_queue_push(pa_queue *q, void *p); -void* pa_queue_pop(pa_queue *q); - -int pa_queue_is_empty(pa_queue *q); - -#endif diff --git a/polyp/random.c b/polyp/random.c deleted file mode 100644 index 12f27bfd..00000000 --- a/polyp/random.c +++ /dev/null @@ -1,71 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "random.h" -#include "util.h" -#include "log.h" - -#ifndef OS_IS_WIN32 -#define RANDOM_DEVICE "/dev/urandom" -#endif - -void pa_random(void *ret_data, size_t length) { - int fd; - ssize_t r = 0; - assert(ret_data && length); - -#ifdef RANDOM_DEVICE - if ((fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) { - - if ((r = pa_loop_read(fd, ret_data, length)) < 0 || (size_t) r != length) - pa_log_error(__FILE__": failed to read entropy from '%s'\n", RANDOM_DEVICE); - - close(fd); - } -#endif - - if ((size_t) r != length) { - uint8_t *p; - size_t l; - -#ifdef RANDOM_DEVICE - pa_log_warn(__FILE__": WARNING: Failed to open entropy device '"RANDOM_DEVICE"': %s" - ", falling back to unsecure pseudo RNG.\n", strerror(errno)); -#endif - - srand(time(NULL)); - - for (p = ret_data, l = length; l > 0; p++, l--) - *p = (uint8_t) rand(); - } -} diff --git a/polyp/random.h b/polyp/random.h deleted file mode 100644 index bfb3df08..00000000 --- a/polyp/random.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef foorandomhfoo -#define foorandomhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -void pa_random(void *ret_data, size_t length); - -#endif diff --git a/polyp/resampler.c b/polyp/resampler.c deleted file mode 100644 index 0417e44e..00000000 --- a/polyp/resampler.c +++ /dev/null @@ -1,614 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include -#include -#include - -#include "resampler.h" -#include "sconv.h" -#include "xmalloc.h" -#include "log.h" - -struct pa_resampler { - pa_resample_method_t resample_method; - pa_sample_spec i_ss, o_ss; - pa_channel_map i_cm, o_cm; - size_t i_fz, o_fz; - pa_memblock_stat *memblock_stat; - - void (*impl_free)(pa_resampler *r); - void (*impl_update_input_rate)(pa_resampler *r, uint32_t rate); - void (*impl_run)(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out); - void *impl_data; -}; - -struct impl_libsamplerate { - float* buf1, *buf2, *buf3, *buf4; - unsigned buf1_samples, buf2_samples, buf3_samples, buf4_samples; - - pa_convert_to_float32ne_func_t to_float32ne_func; - pa_convert_from_float32ne_func_t from_float32ne_func; - SRC_STATE *src_state; - - int map_table[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; - int map_required; -}; - -struct impl_trivial { - unsigned o_counter; - unsigned i_counter; -}; - -static int libsamplerate_init(pa_resampler*r); -static int trivial_init(pa_resampler*r); - -pa_resampler* pa_resampler_new( - const pa_sample_spec *a, - const pa_channel_map *am, - const pa_sample_spec *b, - const pa_channel_map *bm, - pa_memblock_stat *s, - pa_resample_method_t resample_method) { - - pa_resampler *r = NULL; - - assert(a); - assert(b); - assert(pa_sample_spec_valid(a)); - assert(pa_sample_spec_valid(b)); - assert(resample_method != PA_RESAMPLER_INVALID); - - r = pa_xnew(pa_resampler, 1); - r->impl_data = NULL; - r->memblock_stat = s; - r->resample_method = resample_method; - - r->impl_free = NULL; - r->impl_update_input_rate = NULL; - r->impl_run = NULL; - - /* Fill sample specs */ - r->i_ss = *a; - r->o_ss = *b; - - if (am) - r->i_cm = *am; - else - pa_channel_map_init_auto(&r->i_cm, r->i_ss.channels); - - if (bm) - r->o_cm = *bm; - else - pa_channel_map_init_auto(&r->o_cm, r->o_ss.channels); - - r->i_fz = pa_frame_size(a); - r->o_fz = pa_frame_size(b); - - /* Choose implementation */ - if (a->channels != b->channels || - a->format != b->format || - !pa_channel_map_equal(&r->i_cm, &r->o_cm) || - resample_method != PA_RESAMPLER_TRIVIAL) { - - /* Use the libsamplerate based resampler for the complicated cases */ - if (resample_method == PA_RESAMPLER_TRIVIAL) - r->resample_method = PA_RESAMPLER_SRC_ZERO_ORDER_HOLD; - - if (libsamplerate_init(r) < 0) - goto fail; - - } else { - /* Use our own simple non-fp resampler for the trivial cases and when the user selects it */ - if (trivial_init(r) < 0) - goto fail; - } - - return r; - -fail: - if (r) - pa_xfree(r); - - return NULL; -} - -void pa_resampler_free(pa_resampler *r) { - assert(r); - - if (r->impl_free) - r->impl_free(r); - - pa_xfree(r); -} - -void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate) { - assert(r); - assert(rate > 0); - - if (r->i_ss.rate == rate) - return; - - r->i_ss.rate = rate; - - if (r->impl_update_input_rate) - r->impl_update_input_rate(r, rate); -} - -void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { - assert(r && in && out && r->impl_run); - - r->impl_run(r, in, out); -} - -size_t pa_resampler_request(pa_resampler *r, size_t out_length) { - assert(r && (out_length % r->o_fz) == 0); - return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz; -} - -pa_resample_method_t pa_resampler_get_method(pa_resampler *r) { - assert(r); - return r->resample_method; -} - -static const char * const resample_methods[] = { - "src-sinc-best-quality", - "src-sinc-medium-quality", - "src-sinc-fastest", - "src-zero-order-hold", - "src-linear", - "trivial" -}; - -const char *pa_resample_method_to_string(pa_resample_method_t m) { - - if (m < 0 || m >= PA_RESAMPLER_MAX) - return NULL; - - return resample_methods[m]; -} - -pa_resample_method_t pa_parse_resample_method(const char *string) { - pa_resample_method_t m; - - assert(string); - - for (m = 0; m < PA_RESAMPLER_MAX; m++) - if (!strcmp(string, resample_methods[m])) - return m; - - return PA_RESAMPLER_INVALID; -} - - -/*** libsamplerate based implementation ***/ - -static void libsamplerate_free(pa_resampler *r) { - struct impl_libsamplerate *u; - - assert(r); - assert(r->impl_data); - - u = r->impl_data; - - if (u->src_state) - src_delete(u->src_state); - - pa_xfree(u->buf1); - pa_xfree(u->buf2); - pa_xfree(u->buf3); - pa_xfree(u->buf4); - pa_xfree(u); -} - -static void calc_map_table(pa_resampler *r) { - struct impl_libsamplerate *u; - unsigned oc; - assert(r); - assert(r->impl_data); - - u = r->impl_data; - - if (!(u->map_required = (!pa_channel_map_equal(&r->i_cm, &r->o_cm) || r->i_ss.channels != r->o_ss.channels))) - return; - - for (oc = 0; oc < r->o_ss.channels; oc++) { - unsigned ic, i = 0; - - for (ic = 0; ic < r->i_ss.channels; ic++) { - pa_channel_position_t a, b; - - a = r->i_cm.map[ic]; - b = r->o_cm.map[oc]; - - if (a == b || - (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_LEFT) || - (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_RIGHT) || - (a == PA_CHANNEL_POSITION_LEFT && b == PA_CHANNEL_POSITION_MONO) || - (a == PA_CHANNEL_POSITION_RIGHT && b == PA_CHANNEL_POSITION_MONO)) - - u->map_table[oc][i++] = ic; - } - - /* Add an end marker */ - if (i < PA_CHANNELS_MAX) - u->map_table[oc][i] = -1; - } -} - -static float * convert_to_float(pa_resampler *r, float *input, unsigned n_frames) { - struct impl_libsamplerate *u; - unsigned n_samples; - - assert(r); - assert(input); - assert(r->impl_data); - u = r->impl_data; - - /* Convert the incoming sample into floats and place them in buf1 */ - - if (!u->to_float32ne_func) - return input; - - n_samples = n_frames * r->i_ss.channels; - - if (u->buf1_samples < n_samples) - u->buf1 = pa_xrealloc(u->buf1, sizeof(float) * (u->buf1_samples = n_samples)); - - u->to_float32ne_func(n_samples, input, u->buf1); - - return u->buf1; -} - -static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) { - struct impl_libsamplerate *u; - unsigned n_samples; - int i_skip, o_skip; - unsigned oc; - - assert(r); - assert(input); - assert(r->impl_data); - u = r->impl_data; - - /* Remap channels and place the result int buf2 */ - - if (!u->map_required) - return input; - - n_samples = n_frames * r->o_ss.channels; - - if (u->buf2_samples < n_samples) - u->buf2 = pa_xrealloc(u->buf2, sizeof(float) * (u->buf2_samples = n_samples)); - - memset(u->buf2, 0, n_samples * sizeof(float)); - - o_skip = sizeof(float) * r->o_ss.channels; - i_skip = sizeof(float) * r->i_ss.channels; - - for (oc = 0; oc < r->o_ss.channels; oc++) { - unsigned i; - static const float one = 1.0; - - for (i = 0; i < PA_CHANNELS_MAX && u->map_table[oc][i] >= 0; i++) - oil_vectoradd_f32( - u->buf2 + oc, o_skip, - u->buf2 + oc, o_skip, - input + u->map_table[oc][i], i_skip, - n_frames, - &one, &one); - } - - return u->buf2; -} - -static float *resample(pa_resampler *r, float *input, unsigned *n_frames) { - struct impl_libsamplerate *u; - SRC_DATA data; - unsigned out_n_frames, out_n_samples; - int ret; - - assert(r); - assert(input); - assert(n_frames); - assert(r->impl_data); - u = r->impl_data; - - /* Resample the data and place the result in buf3 */ - - if (!u->src_state) - return input; - - out_n_frames = (*n_frames*r->o_ss.rate/r->i_ss.rate)+1024; - out_n_samples = out_n_frames * r->o_ss.channels; - - if (u->buf3_samples < out_n_samples) - u->buf3 = pa_xrealloc(u->buf3, sizeof(float) * (u->buf3_samples = out_n_samples)); - - data.data_in = input; - data.input_frames = *n_frames; - - data.data_out = u->buf3; - data.output_frames = out_n_frames; - - data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate; - data.end_of_input = 0; - - ret = src_process(u->src_state, &data); - assert(ret == 0); - assert((unsigned) data.input_frames_used == *n_frames); - - *n_frames = data.output_frames_gen; - - return u->buf3; -} - -static float *convert_from_float(pa_resampler *r, float *input, unsigned n_frames) { - struct impl_libsamplerate *u; - unsigned n_samples; - - assert(r); - assert(input); - assert(r->impl_data); - u = r->impl_data; - - /* Convert the data into the correct sample type and place the result in buf4 */ - - if (!u->from_float32ne_func) - return input; - - n_samples = n_frames * r->o_ss.channels; - - if (u->buf4_samples < n_samples) - u->buf4 = pa_xrealloc(u->buf4, sizeof(float) * (u->buf4_samples = n_samples)); - - u->from_float32ne_func(n_samples, input, u->buf4); - - return u->buf4; -} - -static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { - struct impl_libsamplerate *u; - float *buf, *input; - unsigned n_frames; - - assert(r); - assert(in); - assert(out); - assert(in->length); - assert(in->memblock); - assert(in->length % r->i_fz == 0); - assert(r->impl_data); - - u = r->impl_data; - - buf = input = (float*) ((uint8_t*) in->memblock->data + in->index); - n_frames = in->length / r->i_fz; - assert(n_frames > 0); - - buf = convert_to_float(r, buf, n_frames); - buf = remap_channels(r, buf, n_frames); - buf = resample(r, buf, &n_frames); - - if (n_frames) { - buf = convert_from_float(r, buf, n_frames); - - if (buf == input) { - /* Mm, no adjustment has been necessary, so let's return the original block */ - out->memblock = pa_memblock_ref(in->memblock); - out->index = in->index; - out->length = in->length; - } else { - float **p = NULL; - - out->length = n_frames * r->o_fz; - out->index = 0; - - if (buf == u->buf1) { - p = &u->buf1; - u->buf1_samples = 0; - } else if (buf == u->buf2) { - p = &u->buf2; - u->buf2_samples = 0; - } else if (buf == u->buf3) { - p = &u->buf3; - u->buf3_samples = 0; - } else if (buf == u->buf4) { - p = &u->buf4; - u->buf4_samples = 0; - } - - assert(p); - - /* Take the existing buffer and make it a memblock */ - out->memblock = pa_memblock_new_dynamic(*p, out->length, r->memblock_stat); - *p = NULL; - } - } else { - out->memblock = NULL; - out->index = out->length = 0; - } -} - -static void libsamplerate_update_input_rate(pa_resampler *r, uint32_t rate) { - struct impl_libsamplerate *u; - - assert(r); - assert(rate > 0); - assert(r->impl_data); - u = r->impl_data; - - if (!u->src_state) { - int err; - u->src_state = src_new(r->resample_method, r->o_ss.channels, &err); - assert(u->src_state); - } else { - int ret = src_set_ratio(u->src_state, (double) r->o_ss.rate / rate); - assert(ret == 0); - } -} - -static int libsamplerate_init(pa_resampler *r) { - struct impl_libsamplerate *u = NULL; - int err; - - r->impl_data = u = pa_xnew(struct impl_libsamplerate, 1); - - u->buf1 = u->buf2 = u->buf3 = u->buf4 = NULL; - u->buf1_samples = u->buf2_samples = u->buf3_samples = u->buf4_samples = 0; - - if (r->i_ss.format == PA_SAMPLE_FLOAT32NE) - u->to_float32ne_func = NULL; - else if (!(u->to_float32ne_func = pa_get_convert_to_float32ne_function(r->i_ss.format))) - goto fail; - - if (r->o_ss.format == PA_SAMPLE_FLOAT32NE) - u->from_float32ne_func = NULL; - else if (!(u->from_float32ne_func = pa_get_convert_from_float32ne_function(r->o_ss.format))) - goto fail; - - if (r->o_ss.rate == r->i_ss.rate) - u->src_state = NULL; - else if (!(u->src_state = src_new(r->resample_method, r->o_ss.channels, &err))) - goto fail; - - r->impl_free = libsamplerate_free; - r->impl_update_input_rate = libsamplerate_update_input_rate; - r->impl_run = libsamplerate_run; - - calc_map_table(r); - - return 0; - -fail: - pa_xfree(u); - return -1; -} - -/* Trivial implementation */ - -static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { - size_t fz; - unsigned n_frames; - struct impl_trivial *u; - - assert(r); - assert(in); - assert(out); - assert(r->impl_data); - - u = r->impl_data; - - fz = r->i_fz; - assert(fz == r->o_fz); - - n_frames = in->length/fz; - - if (r->i_ss.rate == r->o_ss.rate) { - - /* In case there's no diefference in sample types, do nothing */ - *out = *in; - pa_memblock_ref(out->memblock); - - u->o_counter += n_frames; - } else { - /* Do real resampling */ - size_t l; - unsigned o_index; - - /* The length of the new memory block rounded up */ - l = ((((n_frames+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz; - - out->index = 0; - out->memblock = pa_memblock_new(l, r->memblock_stat); - - for (o_index = 0;; o_index++, u->o_counter++) { - unsigned j; - - j = (u->o_counter * r->i_ss.rate / r->o_ss.rate); - j = j > u->i_counter ? j - u->i_counter : 0; - - if (j >= n_frames) - break; - - assert(o_index*fz < out->memblock->length); - - memcpy((uint8_t*) out->memblock->data + fz*o_index, - (uint8_t*) in->memblock->data + in->index + fz*j, fz); - - } - - out->length = o_index*fz; - } - - u->i_counter += n_frames; - - /* Normalize counters */ - while (u->i_counter >= r->i_ss.rate) { - u->i_counter -= r->i_ss.rate; - assert(u->o_counter >= r->o_ss.rate); - u->o_counter -= r->o_ss.rate; - } -} - -static void trivial_free(pa_resampler *r) { - assert(r); - - pa_xfree(r->impl_data); -} - -static void trivial_update_input_rate(pa_resampler *r, uint32_t rate) { - struct impl_trivial *u; - - assert(r); - assert(rate > 0); - assert(r->impl_data); - - u = r->impl_data; - u->i_counter = 0; - u->o_counter = 0; -} - -static int trivial_init(pa_resampler*r) { - struct impl_trivial *u; - - assert(r); - assert(r->i_ss.format == r->o_ss.format); - assert(r->i_ss.channels == r->o_ss.channels); - - r->impl_data = u = pa_xnew(struct impl_trivial, 1); - u->o_counter = u->i_counter = 0; - - r->impl_run = trivial_run; - r->impl_free = trivial_free; - r->impl_update_input_rate = trivial_update_input_rate; - - return 0; -} - - diff --git a/polyp/resampler.h b/polyp/resampler.h deleted file mode 100644 index e14942f3..00000000 --- a/polyp/resampler.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef fooresamplerhfoo -#define fooresamplerhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "sample.h" -#include "memblock.h" -#include "memchunk.h" -#include "channelmap.h" - -typedef struct pa_resampler pa_resampler; - -typedef enum pa_resample_method { - PA_RESAMPLER_INVALID = -1, - PA_RESAMPLER_SRC_SINC_BEST_QUALITY = SRC_SINC_BEST_QUALITY, - PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY = SRC_SINC_MEDIUM_QUALITY, - PA_RESAMPLER_SRC_SINC_FASTEST = SRC_SINC_FASTEST, - PA_RESAMPLER_SRC_ZERO_ORDER_HOLD = SRC_ZERO_ORDER_HOLD, - PA_RESAMPLER_SRC_LINEAR = SRC_LINEAR, - PA_RESAMPLER_TRIVIAL, - PA_RESAMPLER_MAX -} pa_resample_method_t; - -pa_resampler* pa_resampler_new( - const pa_sample_spec *a, - const pa_channel_map *am, - const pa_sample_spec *b, - const pa_channel_map *bm, - pa_memblock_stat *s, - pa_resample_method_t resample_method); - -void pa_resampler_free(pa_resampler *r); - -/* Returns the size of an input memory block which is required to return the specified amount of output data */ -size_t pa_resampler_request(pa_resampler *r, size_t out_length); - -/* Pass the specified memory chunk to the resampler and return the newly resampled data */ -void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out); - -/* Change the input rate of the resampler object */ -void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate); - -/* Return the resampling method of the resampler object */ -pa_resample_method_t pa_resampler_get_method(pa_resampler *r); - -/* Try to parse the resampler method */ -pa_resample_method_t pa_parse_resample_method(const char *string); - -/* return a human readable string for the specified resampling method. Inverse of pa_parse_resample_method() */ -const char *pa_resample_method_to_string(pa_resample_method_t m); - -#endif diff --git a/polyp/sample-util.c b/polyp/sample-util.c deleted file mode 100644 index 52974c46..00000000 --- a/polyp/sample-util.c +++ /dev/null @@ -1,328 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -#include "log.h" -#include "sample-util.h" - -pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) { - assert(b && b->data && spec); - pa_silence_memory(b->data, b->length, spec); - return b; -} - -void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) { - assert(c && c->memblock && c->memblock->data && spec && c->length); - - pa_silence_memory((uint8_t*) c->memblock->data+c->index, c->length, spec); -} - -void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { - uint8_t c = 0; - assert(p && length && spec); - - switch (spec->format) { - case PA_SAMPLE_U8: - c = 0x80; - break; - case PA_SAMPLE_S16LE: - case PA_SAMPLE_S16BE: - case PA_SAMPLE_FLOAT32: - c = 0; - break; - case PA_SAMPLE_ALAW: - case PA_SAMPLE_ULAW: - c = 80; - break; - default: - assert(0); - } - - memset(p, c, length); -} - -size_t pa_mix( - const pa_mix_info streams[], - unsigned nstreams, - void *data, - size_t length, - const pa_sample_spec *spec, - const pa_cvolume *volume) { - - assert(streams && data && length && spec); - - switch (spec->format) { - case PA_SAMPLE_S16NE:{ - size_t d; - unsigned channel = 0; - - for (d = 0;; d += sizeof(int16_t)) { - int32_t sum = 0; - - if (d >= length) - return d; - - if (volume->values[channel] != PA_VOLUME_MUTED) { - unsigned i; - - for (i = 0; i < nstreams; i++) { - int32_t v; - pa_volume_t cvolume = streams[i].volume.values[channel]; - - if (d >= streams[i].chunk.length) - return d; - - if (cvolume == PA_VOLUME_MUTED) - v = 0; - else { - v = *((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); - - if (cvolume != PA_VOLUME_NORM) { - v *= cvolume; - v /= PA_VOLUME_NORM; - } - } - - sum += v; - } - - if (volume->values[channel] != PA_VOLUME_NORM) { - sum *= volume->values[channel]; - sum /= PA_VOLUME_NORM; - } - - if (sum < -0x8000) sum = -0x8000; - if (sum > 0x7FFF) sum = 0x7FFF; - - } - - *((int16_t*) data) = sum; - data = (uint8_t*) data + sizeof(int16_t); - - if (++channel >= spec->channels) - channel = 0; - } - } - - case PA_SAMPLE_U8: { - size_t d; - unsigned channel = 0; - - for (d = 0;; d ++) { - int32_t sum = 0; - - if (d >= length) - return d; - - if (volume->values[channel] != PA_VOLUME_MUTED) { - unsigned i; - - for (i = 0; i < nstreams; i++) { - int32_t v; - pa_volume_t cvolume = streams[i].volume.values[channel]; - - if (d >= streams[i].chunk.length) - return d; - - if (cvolume == PA_VOLUME_MUTED) - v = 0; - else { - v = (int32_t) *((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d) - 0x80; - - if (cvolume != PA_VOLUME_NORM) { - v *= cvolume; - v /= PA_VOLUME_NORM; - } - } - - sum += v; - } - - if (volume->values[channel] != PA_VOLUME_NORM) { - sum *= volume->values[channel]; - sum /= PA_VOLUME_NORM; - } - - if (sum < -0x80) sum = -0x80; - if (sum > 0x7F) sum = 0x7F; - - } - - *((uint8_t*) data) = (uint8_t) (sum + 0x80); - data = (uint8_t*) data + 1; - - if (++channel >= spec->channels) - channel = 0; - } - } - - case PA_SAMPLE_FLOAT32NE: { - size_t d; - unsigned channel = 0; - - for (d = 0;; d += sizeof(float)) { - float sum = 0; - - if (d >= length) - return d; - - if (volume->values[channel] != PA_VOLUME_MUTED) { - unsigned i; - - for (i = 0; i < nstreams; i++) { - float v; - pa_volume_t cvolume = streams[i].volume.values[channel]; - - if (d >= streams[i].chunk.length) - return d; - - if (cvolume == PA_VOLUME_MUTED) - v = 0; - else { - v = *((float*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); - - if (cvolume != PA_VOLUME_NORM) { - v *= cvolume; - v /= PA_VOLUME_NORM; - } - } - - sum += v; - } - - if (volume->values[channel] != PA_VOLUME_NORM) { - sum *= volume->values[channel]; - sum /= PA_VOLUME_NORM; - } - } - - *((float*) data) = sum; - data = (uint8_t*) data + sizeof(float); - - if (++channel >= spec->channels) - channel = 0; - } - } - - default: - abort(); - } -} - - -void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvolume *volume) { - assert(c && spec && (c->length % pa_frame_size(spec) == 0)); - assert(volume); - - if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM)) - return; - - if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) { - pa_silence_memchunk(c, spec); - return; - } - - switch (spec->format) { - case PA_SAMPLE_S16NE: { - int16_t *d; - size_t n; - unsigned channel = 0; - - for (d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { - int32_t t = (int32_t)(*d); - - t *= volume->values[channel]; - t /= PA_VOLUME_NORM; - - if (t < -0x8000) t = -0x8000; - if (t > 0x7FFF) t = 0x7FFF; - - *d = (int16_t) t; - - if (++channel >= spec->channels) - channel = 0; - } - break; - } - - case PA_SAMPLE_U8: { - uint8_t *d; - size_t n; - unsigned channel = 0; - - for (d = (uint8_t*) c->memblock->data + c->index, n = c->length; n > 0; d++, n--) { - int32_t t = (int32_t) *d - 0x80; - - t *= volume->values[channel]; - t /= PA_VOLUME_NORM; - - if (t < -0x80) t = -0x80; - if (t > 0x7F) t = 0x7F; - - *d = (uint8_t) (t + 0x80); - - if (++channel >= spec->channels) - channel = 0; - } - break; - } - - case PA_SAMPLE_FLOAT32NE: { - float *d; - int skip; - unsigned n; - unsigned channel; - - d = (float*) ((uint8_t*) c->memblock->data + c->index); - skip = spec->channels * sizeof(float); - n = c->length/sizeof(float)/spec->channels; - - for (channel = 0; channel < spec->channels ; channel ++) { - float v, *t; - - if (volume->values[channel] == PA_VOLUME_NORM) - continue; - - v = (float) volume->values[channel] / PA_VOLUME_NORM; - - t = d + channel; - oil_scalarmult_f32(t, skip, t, skip, &v, n); - } - break; - } - - default: - pa_log_error(__FILE__": ERROR: Unable to change volume of format %s.\n", - pa_sample_format_to_string(spec->format)); - abort(); - } -} - diff --git a/polyp/sample-util.h b/polyp/sample-util.h deleted file mode 100644 index e433f9c8..00000000 --- a/polyp/sample-util.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef foosampleutilhfoo -#define foosampleutilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "sample.h" -#include "memblock.h" -#include "memchunk.h" -#include "volume.h" - -pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec); -void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec); -void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec); - -typedef struct pa_mix_info { - pa_memchunk chunk; - pa_cvolume volume; - void *userdata; -} pa_mix_info; - -size_t pa_mix( - const pa_mix_info channels[], - unsigned nchannels, - void *data, - size_t length, - const pa_sample_spec *spec, - const pa_cvolume *volume); - -void pa_volume_memchunk( - pa_memchunk*c, - const pa_sample_spec *spec, - const pa_cvolume *volume); - -#endif diff --git a/polyp/sample.c b/polyp/sample.c deleted file mode 100644 index d587170c..00000000 --- a/polyp/sample.c +++ /dev/null @@ -1,149 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "sample.h" - -size_t pa_sample_size(const pa_sample_spec *spec) { - assert(spec); - - switch (spec->format) { - case PA_SAMPLE_U8: - case PA_SAMPLE_ULAW: - case PA_SAMPLE_ALAW: - return 1; - case PA_SAMPLE_S16LE: - case PA_SAMPLE_S16BE: - return 2; - case PA_SAMPLE_FLOAT32LE: - case PA_SAMPLE_FLOAT32BE: - return 4; - default: - assert(0); - } -} - -size_t pa_frame_size(const pa_sample_spec *spec) { - assert(spec); - - return pa_sample_size(spec) * spec->channels; -} - -size_t pa_bytes_per_second(const pa_sample_spec *spec) { - assert(spec); - return spec->rate*pa_frame_size(spec); -} - -pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) { - assert(spec); - - return (pa_usec_t) (((double) length/pa_frame_size(spec)*1000000)/spec->rate); -} - -int pa_sample_spec_valid(const pa_sample_spec *spec) { - assert(spec); - - if (spec->rate <= 0 || - spec->channels <= 0 || - spec->channels > PA_CHANNELS_MAX || - spec->format >= PA_SAMPLE_MAX || - spec->format < 0) - return 0; - - return 1; -} - -int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b) { - assert(a && b); - - return (a->format == b->format) && (a->rate == b->rate) && (a->channels == b->channels); -} - -const char *pa_sample_format_to_string(pa_sample_format_t f) { - static const char* const table[]= { - [PA_SAMPLE_U8] = "u8", - [PA_SAMPLE_ALAW] = "aLaw", - [PA_SAMPLE_ULAW] = "uLaw", - [PA_SAMPLE_S16LE] = "s16le", - [PA_SAMPLE_S16BE] = "s16be", - [PA_SAMPLE_FLOAT32LE] = "float32le", - [PA_SAMPLE_FLOAT32BE] = "float32be", - }; - - if (f >= PA_SAMPLE_MAX) - return NULL; - - return table[f]; -} - -char *pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec) { - assert(s && l && spec); - - if (!pa_sample_spec_valid(spec)) - snprintf(s, l, "Invalid"); - else - snprintf(s, l, "%s %uch %uHz", pa_sample_format_to_string(spec->format), spec->channels, spec->rate); - - return s; -} - -void pa_bytes_snprint(char *s, size_t l, unsigned v) { - if (v >= ((unsigned) 1024)*1024*1024) - snprintf(s, l, "%0.1f GB", ((double) v)/1024/1024/1024); - else if (v >= ((unsigned) 1024)*1024) - snprintf(s, l, "%0.1f MB", ((double) v)/1024/1024); - else if (v >= (unsigned) 1024) - snprintf(s, l, "%0.1f KB", ((double) v)/1024); - else - snprintf(s, l, "%u B", (unsigned) v); -} - -pa_sample_format_t pa_parse_sample_format(const char *format) { - - if (strcasecmp(format, "s16le") == 0) - return PA_SAMPLE_S16LE; - else if (strcasecmp(format, "s16be") == 0) - return PA_SAMPLE_S16BE; - else if (strcasecmp(format, "s16ne") == 0 || strcasecmp(format, "s16") == 0 || strcasecmp(format, "16") == 0) - return PA_SAMPLE_S16NE; - else if (strcasecmp(format, "u8") == 0 || strcasecmp(format, "8") == 0) - return PA_SAMPLE_U8; - else if (strcasecmp(format, "float32") == 0 || strcasecmp(format, "float32ne") == 0) - return PA_SAMPLE_FLOAT32; - else if (strcasecmp(format, "float32le") == 0) - return PA_SAMPLE_FLOAT32LE; - else if (strcasecmp(format, "float32be") == 0) - return PA_SAMPLE_FLOAT32BE; - else if (strcasecmp(format, "ulaw") == 0) - return PA_SAMPLE_ULAW; - else if (strcasecmp(format, "alaw") == 0) - return PA_SAMPLE_ALAW; - - return -1; -} diff --git a/polyp/sample.h b/polyp/sample.h deleted file mode 100644 index c1b98f1c..00000000 --- a/polyp/sample.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef foosamplehfoo -#define foosamplehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include - -#include - -/** \file - * Constants and routines for sample type handling */ - -PA_C_DECL_BEGIN - -/* Maximum allowed channels */ -#define PA_CHANNELS_MAX 16 - -/** Sample format */ -typedef enum pa_sample_format { - PA_SAMPLE_U8, /**< Unsigned 8 Bit PCM */ - PA_SAMPLE_ALAW, /**< 8 Bit a-Law */ - PA_SAMPLE_ULAW, /**< 8 Bit mu-Law */ - PA_SAMPLE_S16LE, /**< Signed 16 Bit PCM, little endian (PC) */ - PA_SAMPLE_S16BE, /**< Signed 16 Bit PCM, big endian */ - PA_SAMPLE_FLOAT32LE, /**< 32 Bit IEEE floating point, little endian, range -1..1 */ - PA_SAMPLE_FLOAT32BE, /**< 32 Bit IEEE floating point, big endian, range -1..1 */ - PA_SAMPLE_MAX, /**< Upper limit of valid sample types */ - PA_SAMPLE_INVALID = -1 /**< An invalid value */ -} pa_sample_format_t; - -#ifdef WORDS_BIGENDIAN -/** Signed 16 Bit PCM, native endian */ -#define PA_SAMPLE_S16NE PA_SAMPLE_S16BE -/** 32 Bit IEEE floating point, native endian */ -#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32BE -/** Signed 16 Bit PCM reverse endian */ -#define PA_SAMPLE_S16RE PA_SAMPLE_S16LE -/** 32 Bit IEEE floating point, reverse endian */ -#define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32LE -#else -/** Signed 16 Bit PCM, native endian */ -#define PA_SAMPLE_S16NE PA_SAMPLE_S16LE -/** 32 Bit IEEE floating point, native endian */ -#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32LE -/** Signed 16 Bit PCM reverse endian */ -#define PA_SAMPLE_S16RE PA_SAMPLE_S16BE -/** 32 Bit IEEE floating point, reverse endian */ -#define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32BE -#endif - -/** A Shortcut for PA_SAMPLE_FLOAT32NE */ -#define PA_SAMPLE_FLOAT32 PA_SAMPLE_FLOAT32NE - -/** A sample format and attribute specification */ -typedef struct pa_sample_spec { - pa_sample_format_t format; /**< The sample format */ - uint32_t rate; /**< The sample rate. (e.g. 44100) */ - uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */ -} pa_sample_spec; - -/** Type for usec specifications (unsigned). May be either 32 or 64 bit, depending on the architecture */ -typedef uint64_t pa_usec_t; - -/** Return the amount of bytes playback of a second of audio with the specified sample type takes */ -size_t pa_bytes_per_second(const pa_sample_spec *spec); - -/** Return the size of a frame with the specific sample type */ -size_t pa_frame_size(const pa_sample_spec *spec); - -/** Return the size of a sample with the specific sample type */ -size_t pa_sample_size(const pa_sample_spec *spec); - -/** Calculate the time the specified bytes take to play with the specified sample type */ -pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec); - -/** Return non-zero when the sample type specification is valid */ -int pa_sample_spec_valid(const pa_sample_spec *spec); - -/** Return non-zero when the two sample type specifications match */ -int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b); - -/* Return a descriptive string for the specified sample format. \since 0.8 */ -const char *pa_sample_format_to_string(pa_sample_format_t f); - -/** Parse a sample format text. Inverse of pa_sample_format_to_string() */ -pa_sample_format_t pa_parse_sample_format(const char *format); - -/** Maximum required string length for pa_sample_spec_snprint() */ -#define PA_SAMPLE_SPEC_SNPRINT_MAX 32 - -/** Pretty print a sample type specification to a string */ -char* pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec); - -/** Pretty print a byte size value. (i.e. "2.5 MB") */ -void pa_bytes_snprint(char *s, size_t l, unsigned v); - -PA_C_DECL_END - -#endif diff --git a/polyp/scache.c b/polyp/scache.c deleted file mode 100644 index 39fa26f3..00000000 --- a/polyp/scache.c +++ /dev/null @@ -1,392 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_GLOB_H -#include -#endif - -#ifdef HAVE_WINDOWS_H -#include -#endif - -#include "scache.h" -#include "sink-input.h" -#include "mainloop.h" -#include "sample-util.h" -#include "play-memchunk.h" -#include "xmalloc.h" -#include "subscribe.h" -#include "namereg.h" -#include "sound-file.h" -#include "util.h" -#include "log.h" -#include "channelmap.h" -#include "volume.h" - -#define UNLOAD_POLL_TIME 2 - -static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - pa_core *c = userdata; - struct timeval ntv; - assert(c && c->mainloop == m && c->scache_auto_unload_event == e); - - pa_scache_unload_unused(c); - - pa_gettimeofday(&ntv); - ntv.tv_sec += UNLOAD_POLL_TIME; - m->time_restart(e, &ntv); -} - -static void free_entry(pa_scache_entry *e) { - assert(e); - pa_namereg_unregister(e->core, e->name); - pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_REMOVE, e->index); - pa_xfree(e->name); - pa_xfree(e->filename); - if (e->memchunk.memblock) - pa_memblock_unref(e->memchunk.memblock); - pa_xfree(e); -} - -static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { - pa_scache_entry *e; - assert(c && name); - - if ((e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) { - if (e->memchunk.memblock) - pa_memblock_unref(e->memchunk.memblock); - - pa_xfree(e->filename); - - assert(e->core == c); - - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); - } else { - e = pa_xmalloc(sizeof(pa_scache_entry)); - - if (!pa_namereg_register(c, name, PA_NAMEREG_SAMPLE, e, 1)) { - pa_xfree(e); - return NULL; - } - - e->name = pa_xstrdup(name); - e->core = c; - - if (!c->scache) { - c->scache = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - assert(c->scache); - } - - pa_idxset_put(c->scache, e, &e->index); - - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_NEW, e->index); - } - - pa_cvolume_reset(&e->volume, PA_CHANNELS_MAX); - e->last_used_time = 0; - e->memchunk.memblock = NULL; - e->memchunk.index = e->memchunk.length = 0; - e->filename = NULL; - e->lazy = 0; - e->last_used_time = 0; - - memset(&e->sample_spec, 0, sizeof(pa_sample_spec)); - - return e; -} - -int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx) { - pa_scache_entry *e; - assert(c && name); - - if (!(e = scache_add_item(c, name))) - return -1; - - if (ss) { - e->sample_spec = *ss; - pa_channel_map_init_auto(&e->channel_map, ss->channels); - } - - if (map) - e->channel_map = *map; - - if (chunk) { - e->memchunk = *chunk; - pa_memblock_ref(e->memchunk.memblock); - } - - if (idx) - *idx = e->index; - - return 0; -} - -int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint32_t *idx) { - pa_sample_spec ss; - pa_memchunk chunk; - int r; - -#ifdef OS_IS_WIN32 - char buf[MAX_PATH]; - - if (ExpandEnvironmentStrings(filename, buf, MAX_PATH)) - filename = buf; -#endif - - if (pa_sound_file_load(filename, &ss, &chunk, c->memblock_stat) < 0) - return -1; - - r = pa_scache_add_item(c, name, &ss, NULL, &chunk, idx); - pa_memblock_unref(chunk.memblock); - - return r; -} - -int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, uint32_t *idx) { - pa_scache_entry *e; - -#ifdef OS_IS_WIN32 - char buf[MAX_PATH]; - - if (ExpandEnvironmentStrings(filename, buf, MAX_PATH)) - filename = buf; -#endif - - assert(c && name); - - if (!(e = scache_add_item(c, name))) - return -1; - - e->lazy = 1; - e->filename = pa_xstrdup(filename); - - if (!c->scache_auto_unload_event) { - struct timeval ntv; - pa_gettimeofday(&ntv); - ntv.tv_sec += UNLOAD_POLL_TIME; - c->scache_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); - } - - if (idx) - *idx = e->index; - - return 0; -} - -int pa_scache_remove_item(pa_core *c, const char *name) { - pa_scache_entry *e; - assert(c && name); - - if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) - return -1; - - if (pa_idxset_remove_by_data(c->scache, e, NULL) != e) - assert(0); - - free_entry(e); - return 0; -} - -static void free_cb(void *p, PA_GCC_UNUSED void *userdata) { - pa_scache_entry *e = p; - assert(e); - free_entry(e); -} - -void pa_scache_free(pa_core *c) { - assert(c); - - if (c->scache) { - pa_idxset_free(c->scache, free_cb, NULL); - c->scache = NULL; - } - - if (c->scache_auto_unload_event) - c->mainloop->time_free(c->scache_auto_unload_event); -} - -int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, const pa_cvolume *volume) { - pa_scache_entry *e; - char *t; - pa_cvolume r; - assert(c && name && sink); - - if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1))) - return -1; - - if (e->lazy && !e->memchunk.memblock) { - if (pa_sound_file_load(e->filename, &e->sample_spec, &e->memchunk, c->memblock_stat) < 0) - return -1; - - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); - } - - if (!e->memchunk.memblock) - return -1; - - t = pa_sprintf_malloc("sample:%s", name); - - if (pa_play_memchunk(sink, t, &e->sample_spec, &e->channel_map, &e->memchunk, pa_sw_cvolume_multiply(&r, volume, &e->volume)) < 0) { - free(t); - return -1; - } - - free(t); - - if (e->lazy) - time(&e->last_used_time); - - return 0; -} - -const char * pa_scache_get_name_by_id(pa_core *c, uint32_t id) { - pa_scache_entry *e; - assert(c && id != PA_IDXSET_INVALID); - - if (!c->scache || !(e = pa_idxset_get_by_index(c->scache, id))) - return NULL; - - return e->name; -} - -uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name) { - pa_scache_entry *e; - assert(c && name); - - if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) - return PA_IDXSET_INVALID; - - return e->index; -} - -uint32_t pa_scache_total_size(pa_core *c) { - pa_scache_entry *e; - uint32_t idx, sum = 0; - assert(c); - - if (!c->scache || !pa_idxset_size(c->scache)) - return 0; - - for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) - if (e->memchunk.memblock) - sum += e->memchunk.length; - - return sum; -} - -void pa_scache_unload_unused(pa_core *c) { - pa_scache_entry *e; - time_t now; - uint32_t idx; - assert(c); - - if (!c->scache || !pa_idxset_size(c->scache)) - return; - - time(&now); - - for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) { - - if (!e->lazy || !e->memchunk.memblock) - continue; - - if (e->last_used_time + c->scache_idle_time > now) - continue; - - pa_memblock_unref(e->memchunk.memblock); - e->memchunk.memblock = NULL; - e->memchunk.index = e->memchunk.length = 0; - - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); - } -} - -static void add_file(pa_core *c, const char *pathname) { - struct stat st; - const char *e; - - e = pa_path_get_filename(pathname); - - if (stat(pathname, &st) < 0) { - pa_log(__FILE__": stat('%s') failed: %s\n", pathname, strerror(errno)); - return; - } - -#if defined(S_ISREG) && defined(S_ISLNK) - if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) -#endif - pa_scache_add_file_lazy(c, e, pathname, NULL); -} - -int pa_scache_add_directory_lazy(pa_core *c, const char *pathname) { - DIR *dir; - assert(c && pathname); - - /* First try to open this as directory */ - if (!(dir = opendir(pathname))) { -#ifdef HAVE_GLOB_H - glob_t p; - unsigned int i; - /* If that fails, try to open it as shell glob */ - - if (glob(pathname, GLOB_ERR|GLOB_NOSORT, NULL, &p) < 0) { - pa_log(__FILE__": Failed to open directory: %s\n", strerror(errno)); - return -1; - } - - for (i = 0; i < p.gl_pathc; i++) - add_file(c, p.gl_pathv[i]); - - globfree(&p); -#else - return -1; -#endif - } else { - struct dirent *e; - - while ((e = readdir(dir))) { - char p[PATH_MAX]; - - if (e->d_name[0] == '.') - continue; - - snprintf(p, sizeof(p), "%s/%s", pathname, e->d_name); - add_file(c, p); - } - } - - closedir(dir); - return 0; -} diff --git a/polyp/scache.h b/polyp/scache.h deleted file mode 100644 index d667ae60..00000000 --- a/polyp/scache.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef fooscachehfoo -#define fooscachehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "core.h" -#include "memchunk.h" -#include "sink.h" - -typedef struct pa_scache_entry { - pa_core *core; - uint32_t index; - char *name; - - pa_cvolume volume; - pa_sample_spec sample_spec; - pa_channel_map channel_map; - pa_memchunk memchunk; - - char *filename; - - int lazy; - time_t last_used_time; -} pa_scache_entry; - -int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx); -int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint32_t *idx); -int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, uint32_t *idx); - -int pa_scache_add_directory_lazy(pa_core *c, const char *pathname); - -int pa_scache_remove_item(pa_core *c, const char *name); -int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, const pa_cvolume *cvolume); -void pa_scache_free(pa_core *c); - -const char *pa_scache_get_name_by_id(pa_core *c, uint32_t id); -uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name); - -uint32_t pa_scache_total_size(pa_core *c); - -void pa_scache_unload_unused(pa_core *c); - -#endif diff --git a/polyp/sconv-s16be.c b/polyp/sconv-s16be.c deleted file mode 100644 index 8b076f06..00000000 --- a/polyp/sconv-s16be.c +++ /dev/null @@ -1,41 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "endianmacros.h" - -#define INT16_FROM INT16_FROM_BE -#define INT16_TO INT16_TO_BE - -#define pa_sconv_s16le_to_float32ne pa_sconv_s16be_to_float32ne -#define pa_sconv_s16le_from_float32ne pa_sconv_s16be_from_float32ne - -#ifdef WORDS_BIGENDIAN -#define SWAP_WORDS 0 -#else -#define SWAP_WORDS 1 -#endif - -#include "sconv-s16le.h" -#include "sconv-s16le.c" diff --git a/polyp/sconv-s16be.h b/polyp/sconv-s16be.h deleted file mode 100644 index b2b6a8c7..00000000 --- a/polyp/sconv-s16be.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef foosconv_s16befoo -#define foosconv_s16befoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -void pa_sconv_s16be_to_float32ne(unsigned n, const void *a, float *b); -void pa_sconv_s16be_from_float32ne(unsigned n, const float *a, void *b); - -#endif diff --git a/polyp/sconv-s16le.c b/polyp/sconv-s16le.c deleted file mode 100644 index e47c5e8e..00000000 --- a/polyp/sconv-s16le.c +++ /dev/null @@ -1,101 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include - -#include "endianmacros.h" -#include "sconv.h" -#include "sconv-s16le.h" -#include "log.h" - -#ifndef INT16_FROM -#define INT16_FROM INT16_FROM_LE -#endif - -#ifndef INT16_TO -#define INT16_TO INT16_TO_LE -#endif - -#ifndef SWAP_WORDS -#ifdef WORDS_BIGENDIAN -#define SWAP_WORDS 1 -#else -#define SWAP_WORDS 0 -#endif -#endif - -void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b) { - const int16_t *ca = a; - - assert(a); - assert(b); - -#if SWAP_WORDS == 1 - - for (; n > 0; n--) { - int16_t s = *(ca++); - *(b++) = ((float) INT16_FROM(s))/0x7FFF; - } - -#else -{ - static const double add = 0, factor = 1.0/0x7FFF; - oil_scaleconv_f32_s16(b, ca, n, &add, &factor); -} -#endif -} - -void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b) { - int16_t *cb = b; - - assert(a); - assert(b); - -#if SWAP_WORDS == 1 - - for (; n > 0; n--) { - int16_t s; - float v = *(a++); - - if (v > 1) - v = 1; - - if (v < -1) - v = -1; - - s = (int16_t) (v * 0x7FFF); - *(cb++) = INT16_TO(s); - } - -#else -{ - static const double add = 0, factor = 0x7FFF; - oil_scaleconv_s16_f32(cb, a, n, &add, &factor); -} -#endif -} diff --git a/polyp/sconv-s16le.h b/polyp/sconv-s16le.h deleted file mode 100644 index ef5e31e8..00000000 --- a/polyp/sconv-s16le.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef foosconv_s16lefoo -#define foosconv_s16lefoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b); -void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b); - -#endif diff --git a/polyp/sconv.c b/polyp/sconv.c deleted file mode 100644 index 1fcb5a0c..00000000 --- a/polyp/sconv.c +++ /dev/null @@ -1,168 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include -#include - -#include "endianmacros.h" -#include "sconv.h" -#include "g711.h" - -#include "sconv-s16le.h" -#include "sconv-s16be.h" - -static void u8_to_float32ne(unsigned n, const void *a, float *b) { - const uint8_t *ca = a; - static const double add = -128.0/127.0, factor = 1.0/127.0; - - assert(a); - assert(b); - - oil_scaleconv_f32_u8(b, ca, n, &add, &factor); -} - -static void u8_from_float32ne(unsigned n, const float *a, void *b) { - uint8_t *cb = b; - static const double add = 128.0, factor = 127.0; - - assert(a); - assert(b); - - oil_scaleconv_u8_f32(cb, a, n, &add, &factor); -} - -static void float32ne_to_float32ne(unsigned n, const void *a, float *b) { - assert(a); - assert(b); - - oil_memcpy(b, a, sizeof(float) * n); -} - -static void float32ne_from_float32ne(unsigned n, const float *a, void *b) { - assert(a); - assert(b); - - oil_memcpy(b, a, sizeof(float) * n); -} - -static void ulaw_to_float32ne(unsigned n, const void *a, float *b) { - const uint8_t *ca = a; - - assert(a); - assert(b); - - for (; n > 0; n--) - *(b++) = st_ulaw2linear16(*(ca++)) * 1.0F / 0x7FFF; -} - -static void ulaw_from_float32ne(unsigned n, const float *a, void *b) { - uint8_t *cb = b; - - assert(a); - assert(b); - - for (; n > 0; n--) { - float v = *(a++); - - if (v > 1) - v = 1; - - if (v < -1) - v = -1; - - *(cb++) = st_14linear2ulaw((int16_t) (v * 0x1FFF)); - } -} - -static void alaw_to_float32ne(unsigned n, const void *a, float *b) { - const uint8_t *ca = a; - - assert(a); - assert(b); - - for (; n > 0; n--) - *(b++) = st_alaw2linear16(*(ca++)) * 1.0F / 0x7FFF; -} - -static void alaw_from_float32ne(unsigned n, const float *a, void *b) { - uint8_t *cb = b; - - assert(a); - assert(b); - - for (; n > 0; n--) { - float v = *(a++); - - if (v > 1) - v = 1; - - if (v < -1) - v = -1; - - *(cb++) = st_13linear2alaw((int16_t) (v * 0xFFF)); - } -} - -pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f) { - switch(f) { - case PA_SAMPLE_U8: - return u8_to_float32ne; - case PA_SAMPLE_S16LE: - return pa_sconv_s16le_to_float32ne; - case PA_SAMPLE_S16BE: - return pa_sconv_s16be_to_float32ne; - case PA_SAMPLE_FLOAT32NE: - return float32ne_to_float32ne; - case PA_SAMPLE_ALAW: - return alaw_to_float32ne; - case PA_SAMPLE_ULAW: - return ulaw_to_float32ne; - default: - return NULL; - } -} - -pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f) { - switch(f) { - case PA_SAMPLE_U8: - return u8_from_float32ne; - case PA_SAMPLE_S16LE: - return pa_sconv_s16le_from_float32ne; - case PA_SAMPLE_S16BE: - return pa_sconv_s16be_from_float32ne; - case PA_SAMPLE_FLOAT32NE: - return float32ne_from_float32ne; - case PA_SAMPLE_ALAW: - return alaw_from_float32ne; - case PA_SAMPLE_ULAW: - return ulaw_from_float32ne; - default: - return NULL; - } -} diff --git a/polyp/sconv.h b/polyp/sconv.h deleted file mode 100644 index 2a005219..00000000 --- a/polyp/sconv.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef foosconvhfoo -#define foosconvhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "sample.h" - -typedef void (*pa_convert_to_float32ne_func_t)(unsigned n, const void *a, float *b); -typedef void (*pa_convert_from_float32ne_func_t)(unsigned n, const float *a, void *b); - -pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f); -pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f); - -#endif diff --git a/polyp/sink-input.c b/polyp/sink-input.c deleted file mode 100644 index f447b8cf..00000000 --- a/polyp/sink-input.c +++ /dev/null @@ -1,368 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "sink-input.h" -#include "sample-util.h" -#include "xmalloc.h" -#include "subscribe.h" -#include "log.h" - -#define CONVERT_BUFFER_LENGTH 4096 - -pa_sink_input* pa_sink_input_new( - pa_sink *s, - const char *driver, - const char *name, - const pa_sample_spec *spec, - const pa_channel_map *map, - int variable_rate, - int resample_method) { - - pa_sink_input *i; - pa_resampler *resampler = NULL; - int r; - char st[256]; - pa_channel_map tmap; - - assert(s); - assert(spec); - assert(s->state == PA_SINK_RUNNING); - - if (pa_idxset_size(s->inputs) >= PA_MAX_INPUTS_PER_SINK) { - pa_log_warn(__FILE__": Failed to create sink input: too many inputs per sink.\n"); - return NULL; - } - - if (resample_method == PA_RESAMPLER_INVALID) - resample_method = s->core->resample_method; - - if (!map) { - pa_channel_map_init_auto(&tmap, spec->channels); - map = &tmap; - } - - if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec) || !pa_channel_map_equal(map, &s->channel_map)) - if (!(resampler = pa_resampler_new(spec, map, &s->sample_spec, &s->channel_map, s->core->memblock_stat, resample_method))) - return NULL; - - i = pa_xnew(pa_sink_input, 1); - i->ref = 1; - i->state = PA_SINK_INPUT_RUNNING; - i->name = pa_xstrdup(name); - i->driver = pa_xstrdup(driver); - i->owner = NULL; - i->sink = s; - i->client = NULL; - - i->sample_spec = *spec; - i->channel_map = *map; - - pa_cvolume_reset(&i->volume, spec->channels); - - i->peek = NULL; - i->drop = NULL; - i->kill = NULL; - i->get_latency = NULL; - i->underrun = NULL; - i->userdata = NULL; - - i->playing = 0; - - pa_memchunk_reset(&i->resampled_chunk); - i->resampler = resampler; - - assert(s->core); - r = pa_idxset_put(s->core->sink_inputs, i, &i->index); - assert(r == 0 && i->index != PA_IDXSET_INVALID); - r = pa_idxset_put(s->inputs, i, NULL); - assert(r == 0); - - pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"\n", i->index, i->name, s->index, st); - - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index); - - return i; -} - -void pa_sink_input_disconnect(pa_sink_input *i) { - assert(i); - assert(i->state != PA_SINK_INPUT_DISCONNECTED); - assert(i->sink); - assert(i->sink->core); - - pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); - pa_idxset_remove_by_data(i->sink->inputs, i, NULL); - - pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index); - i->sink = NULL; - - i->peek = NULL; - i->drop = NULL; - i->kill = NULL; - i->get_latency = NULL; - i->underrun = NULL; - - i->playing = 0; - i->state = PA_SINK_INPUT_DISCONNECTED; -} - -static void sink_input_free(pa_sink_input* i) { - assert(i); - - if (i->state != PA_SINK_INPUT_DISCONNECTED) - pa_sink_input_disconnect(i); - - pa_log_info(__FILE__": freed %u \"%s\"\n", i->index, i->name); - - if (i->resampled_chunk.memblock) - pa_memblock_unref(i->resampled_chunk.memblock); - - if (i->resampler) - pa_resampler_free(i->resampler); - - pa_xfree(i->name); - pa_xfree(i->driver); - pa_xfree(i); -} - -void pa_sink_input_unref(pa_sink_input *i) { - assert(i); - assert(i->ref >= 1); - - if (!(--i->ref)) - sink_input_free(i); -} - -pa_sink_input* pa_sink_input_ref(pa_sink_input *i) { - assert(i); - assert(i->ref >= 1); - - i->ref++; - return i; -} - -void pa_sink_input_kill(pa_sink_input*i) { - assert(i); - assert(i->ref >= 1); - - if (i->kill) - i->kill(i); -} - -pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) { - pa_usec_t r = 0; - - assert(i); - assert(i->ref >= 1); - - if (i->get_latency) - r += i->get_latency(i); - - if (i->resampled_chunk.memblock) - r += pa_bytes_to_usec(i->resampled_chunk.length, &i->sample_spec); - - return r; -} - -int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) { - int ret = -1; - int do_volume_adj_here; - - assert(i); - assert(i->ref >= 1); - assert(chunk); - assert(volume); - - pa_sink_input_ref(i); - - if (!i->peek || !i->drop || i->state == PA_SINK_INPUT_CORKED) - goto finish; - - if (!i->resampler) { - do_volume_adj_here = 0; - ret = i->peek(i, chunk); - goto finish; - } - - do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map); - - while (!i->resampled_chunk.memblock) { - pa_memchunk tchunk; - size_t l; - - if ((ret = i->peek(i, &tchunk)) < 0) - goto finish; - - assert(tchunk.length); - - l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); - - if (l > tchunk.length) - l = tchunk.length; - - i->drop(i, &tchunk, l); - tchunk.length = l; - - /* It might be necessary to adjust the volume here */ - if (do_volume_adj_here) { - pa_memchunk_make_writable(&tchunk, i->sink->core->memblock_stat, 0); - pa_volume_memchunk(&tchunk, &i->sample_spec, &i->volume); - } - - pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk); - pa_memblock_unref(tchunk.memblock); - } - - assert(i->resampled_chunk.memblock); - assert(i->resampled_chunk.length); - - *chunk = i->resampled_chunk; - pa_memblock_ref(i->resampled_chunk.memblock); - - ret = 0; - -finish: - - if (ret < 0 && i->playing && i->underrun) - i->underrun(i); - - i->playing = ret >= 0; - - if (ret >= 0) { - /* Let's see if we had to apply the volume adjustment - * ourselves, or if this can be done by the sink for us */ - - if (do_volume_adj_here) - /* We've both the same channel map, so let's have the sink do the adjustment for us*/ - - pa_cvolume_reset(volume, i->sample_spec.channels); - else - /* We had different channel maps, so we already did the adjustment */ - *volume = i->volume; - } - - pa_sink_input_unref(i); - - return ret; -} - -void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { - assert(i); - assert(i->ref >= 1); - assert(length > 0); - - if (!i->resampler) { - if (i->drop) - i->drop(i, chunk, length); - return; - } - - assert(i->resampled_chunk.memblock); - assert(i->resampled_chunk.length >= length); - - i->resampled_chunk.index += length; - i->resampled_chunk.length -= length; - - if (i->resampled_chunk.length <= 0) { - pa_memblock_unref(i->resampled_chunk.memblock); - i->resampled_chunk.memblock = NULL; - i->resampled_chunk.index = i->resampled_chunk.length = 0; - } -} - -void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) { - assert(i); - assert(i->ref >= 1); - assert(i->sink); - assert(i->sink->core); - - if (pa_cvolume_equal(&i->volume, volume)) - return; - - i->volume = *volume; - pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); -} - -const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i) { - assert(i); - assert(i->ref >= 1); - - return &i->volume; -} - -void pa_sink_input_cork(pa_sink_input *i, int b) { - int n; - - assert(i); - assert(i->ref >= 1); - - if (i->state == PA_SINK_INPUT_DISCONNECTED) - return; - - n = i->state == PA_SINK_INPUT_CORKED && !b; - - i->state = b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING; - - if (n) - pa_sink_notify(i->sink); -} - -void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) { - assert(i); - assert(i->resampler); - assert(i->ref >= 1); - - if (i->sample_spec.rate == rate) - return; - - i->sample_spec.rate = rate; - pa_resampler_set_input_rate(i->resampler, rate); -} - -void pa_sink_input_set_name(pa_sink_input *i, const char *name) { - assert(i); - assert(i->ref >= 1); - - pa_xfree(i->name); - i->name = pa_xstrdup(name); - - pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); -} - -pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) { - assert(i); - assert(i->ref >= 1); - - if (!i->resampler) - return PA_RESAMPLER_INVALID; - - return pa_resampler_get_method(i->resampler); -} diff --git a/polyp/sink-input.h b/polyp/sink-input.h deleted file mode 100644 index 1db993f5..00000000 --- a/polyp/sink-input.h +++ /dev/null @@ -1,106 +0,0 @@ -#ifndef foosinkinputhfoo -#define foosinkinputhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -typedef struct pa_sink_input pa_sink_input; - -#include "sink.h" -#include "sample.h" -#include "memblockq.h" -#include "resampler.h" -#include "module.h" -#include "client.h" - -typedef enum pa_sink_input_state { - PA_SINK_INPUT_RUNNING, - PA_SINK_INPUT_CORKED, - PA_SINK_INPUT_DISCONNECTED -} pa_sink_input_state_t; - -struct pa_sink_input { - int ref; - uint32_t index; - pa_sink_input_state_t state; - - char *name, *driver; - pa_module *owner; - - pa_sink *sink; - pa_client *client; - - pa_sample_spec sample_spec; - pa_channel_map channel_map; - - pa_cvolume volume; - - int (*peek) (pa_sink_input *i, pa_memchunk *chunk); - void (*drop) (pa_sink_input *i, const pa_memchunk *chunk, size_t length); - void (*kill) (pa_sink_input *i); - pa_usec_t (*get_latency) (pa_sink_input *i); - void (*underrun) (pa_sink_input *i); - - void *userdata; - - int playing; - - pa_memchunk resampled_chunk; - pa_resampler *resampler; -}; - -pa_sink_input* pa_sink_input_new( - pa_sink *s, - const char *driver, - const char *name, - const pa_sample_spec *spec, - const pa_channel_map *map, - int variable_rate, - int resample_method); - -void pa_sink_input_unref(pa_sink_input* i); -pa_sink_input* pa_sink_input_ref(pa_sink_input* i); - -/* To be called by the implementing module only */ -void pa_sink_input_disconnect(pa_sink_input* i); - -/* External code may request disconnection with this funcion */ -void pa_sink_input_kill(pa_sink_input*i); - -pa_usec_t pa_sink_input_get_latency(pa_sink_input *i); - -int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume); -void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length); - -void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume); -const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i); - -void pa_sink_input_cork(pa_sink_input *i, int b); - -void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate); - -void pa_sink_input_set_name(pa_sink_input *i, const char *name); - -pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i); - -#endif diff --git a/polyp/sink.c b/polyp/sink.c deleted file mode 100644 index bb656649..00000000 --- a/polyp/sink.c +++ /dev/null @@ -1,445 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "sink.h" -#include "sink-input.h" -#include "namereg.h" -#include "util.h" -#include "sample-util.h" -#include "xmalloc.h" -#include "subscribe.h" -#include "log.h" -#include "polyplib-introspect.h" - -#define MAX_MIX_CHANNELS 32 - -pa_sink* pa_sink_new( - pa_core *core, - const char *driver, - const char *name, - int fail, - const pa_sample_spec *spec, - const pa_channel_map *map) { - - pa_sink *s; - char *n = NULL; - char st[256]; - int r; - - assert(core); - assert(name); - assert(*name); - assert(spec); - - s = pa_xnew(pa_sink, 1); - - if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) { - pa_xfree(s); - return NULL; - } - - s->ref = 1; - s->core = core; - s->state = PA_SINK_RUNNING; - s->name = pa_xstrdup(name); - s->description = NULL; - s->driver = pa_xstrdup(driver); - s->owner = NULL; - - s->sample_spec = *spec; - if (map) - s->channel_map = *map; - else - pa_channel_map_init_auto(&s->channel_map, spec->channels); - - s->inputs = pa_idxset_new(NULL, NULL); - - pa_cvolume_reset(&s->sw_volume, spec->channels); - pa_cvolume_reset(&s->hw_volume, spec->channels); - - s->get_latency = NULL; - s->notify = NULL; - s->set_hw_volume = NULL; - s->get_hw_volume = NULL; - s->userdata = NULL; - - r = pa_idxset_put(core->sinks, s, &s->index); - assert(s->index != PA_IDXSET_INVALID && r >= 0); - - pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); - - n = pa_sprintf_malloc("%s_monitor", name); - s->monitor_source = pa_source_new(core, driver, n, 0, spec, map); - assert(s->monitor_source); - pa_xfree(n); - s->monitor_source->monitor_of = s; - s->monitor_source->description = pa_sprintf_malloc("Monitor source of sink '%s'", s->name); - - pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index); - - return s; -} - -void pa_sink_disconnect(pa_sink* s) { - pa_sink_input *i, *j = NULL; - - assert(s); - assert(s->state == PA_SINK_RUNNING); - - pa_namereg_unregister(s->core, s->name); - - while ((i = pa_idxset_first(s->inputs, NULL))) { - assert(i != j); - pa_sink_input_kill(i); - j = i; - } - - pa_source_disconnect(s->monitor_source); - - pa_idxset_remove_by_data(s->core->sinks, s, NULL); - - s->get_latency = NULL; - s->notify = NULL; - s->get_hw_volume = NULL; - s->set_hw_volume = NULL; - - s->state = PA_SINK_DISCONNECTED; - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); -} - -static void sink_free(pa_sink *s) { - assert(s); - assert(!s->ref); - - if (s->state != PA_SINK_DISCONNECTED) - pa_sink_disconnect(s); - - pa_log_info(__FILE__": freed %u \"%s\"\n", s->index, s->name); - - pa_source_unref(s->monitor_source); - s->monitor_source = NULL; - - pa_idxset_free(s->inputs, NULL, NULL); - - pa_xfree(s->name); - pa_xfree(s->description); - pa_xfree(s->driver); - pa_xfree(s); -} - -void pa_sink_unref(pa_sink*s) { - assert(s); - assert(s->ref >= 1); - - if (!(--s->ref)) - sink_free(s); -} - -pa_sink* pa_sink_ref(pa_sink *s) { - assert(s); - assert(s->ref >= 1); - - s->ref++; - return s; -} - -void pa_sink_notify(pa_sink*s) { - assert(s); - assert(s->ref >= 1); - - if (s->notify) - s->notify(s); -} - -static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) { - uint32_t idx = PA_IDXSET_INVALID; - pa_sink_input *i; - unsigned n = 0; - - assert(s); - assert(s->ref >= 1); - assert(info); - - for (i = pa_idxset_first(s->inputs, &idx); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &idx)) { - /* Increase ref counter, to make sure that this input doesn't - * vanish while we still need it */ - pa_sink_input_ref(i); - - if (pa_sink_input_peek(i, &info->chunk, &info->volume) < 0) { - pa_sink_input_unref(i); - continue; - } - - info->userdata = i; - - assert(info->chunk.memblock); - assert(info->chunk.memblock->data); - assert(info->chunk.length); - - info++; - maxinfo--; - n++; - } - - return n; -} - -static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned maxinfo, size_t length) { - assert(s); - assert(s->ref >= 1); - assert(info); - - for (; maxinfo > 0; maxinfo--, info++) { - pa_sink_input *i = info->userdata; - - assert(i); - assert(info->chunk.memblock); - - /* Drop read data */ - pa_sink_input_drop(i, &info->chunk, length); - pa_memblock_unref(info->chunk.memblock); - - /* Decrease ref counter */ - pa_sink_input_unref(i); - info->userdata = NULL; - } -} - -int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { - pa_mix_info info[MAX_MIX_CHANNELS]; - unsigned n; - int r = -1; - - assert(s); - assert(s->ref >= 1); - assert(length); - assert(result); - - pa_sink_ref(s); - - n = fill_mix_info(s, info, MAX_MIX_CHANNELS); - - if (n <= 0) - goto finish; - - if (n == 1) { - pa_cvolume volume; - - *result = info[0].chunk; - pa_memblock_ref(result->memblock); - - if (result->length > length) - result->length = length; - - pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); - - if (!pa_cvolume_is_norm(&volume)) { - pa_memchunk_make_writable(result, s->core->memblock_stat, 0); - pa_volume_memchunk(result, &s->sample_spec, &volume); - } - } else { - result->memblock = pa_memblock_new(length, s->core->memblock_stat); - assert(result->memblock); - - result->length = pa_mix(info, n, result->memblock->data, length, &s->sample_spec, &s->sw_volume); - result->index = 0; - } - - inputs_drop(s, info, n, result->length); - pa_source_post(s->monitor_source, result); - - r = 0; - -finish: - pa_sink_unref(s); - - return r; -} - -int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { - pa_mix_info info[MAX_MIX_CHANNELS]; - unsigned n; - int r = -1; - - assert(s); - assert(s->ref >= 1); - assert(target); - assert(target->memblock); - assert(target->length); - assert(target->memblock->data); - - pa_sink_ref(s); - - n = fill_mix_info(s, info, MAX_MIX_CHANNELS); - - if (n <= 0) - goto finish; - - if (n == 1) { - pa_cvolume volume; - - if (target->length > info[0].chunk.length) - target->length = info[0].chunk.length; - - memcpy((uint8_t*) target->memblock->data + target->index, - (uint8_t*) info[0].chunk.memblock->data + info[0].chunk.index, - target->length); - - pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); - - if (!pa_cvolume_is_norm(&volume)) - pa_volume_memchunk(target, &s->sample_spec, &volume); - } else - target->length = pa_mix(info, n, - (uint8_t*) target->memblock->data + target->index, - target->length, - &s->sample_spec, - &s->sw_volume); - - inputs_drop(s, info, n, target->length); - pa_source_post(s->monitor_source, target); - - r = 0; - -finish: - pa_sink_unref(s); - - return r; -} - -void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { - pa_memchunk chunk; - size_t l, d; - - assert(s); - assert(s->ref >= 1); - assert(target); - assert(target->memblock); - assert(target->length); - assert(target->memblock->data); - - pa_sink_ref(s); - - l = target->length; - d = 0; - while (l > 0) { - chunk = *target; - chunk.index += d; - chunk.length -= d; - - if (pa_sink_render_into(s, &chunk) < 0) - break; - - d += chunk.length; - l -= chunk.length; - } - - if (l > 0) { - chunk = *target; - chunk.index += d; - chunk.length -= d; - pa_silence_memchunk(&chunk, &s->sample_spec); - } - - pa_sink_unref(s); -} - -void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { - assert(s); - assert(s->ref >= 1); - assert(length); - assert(result); - - /*** This needs optimization ***/ - - result->memblock = pa_memblock_new(result->length = length, s->core->memblock_stat); - result->index = 0; - - pa_sink_render_into_full(s, result); -} - -pa_usec_t pa_sink_get_latency(pa_sink *s) { - assert(s); - assert(s->ref >= 1); - - if (!s->get_latency) - return 0; - - return s->get_latency(s); -} - -void pa_sink_set_owner(pa_sink *s, pa_module *m) { - assert(s); - assert(s->ref >= 1); - - s->owner = m; - - if (s->monitor_source) - pa_source_set_owner(s->monitor_source, m); -} - -void pa_sink_set_volume(pa_sink *s, pa_mixer_t m, const pa_cvolume *volume) { - pa_cvolume *v; - - assert(s); - assert(s->ref >= 1); - assert(volume); - - if (m == PA_MIXER_HARDWARE && s->set_hw_volume) - v = &s->hw_volume; - else - v = &s->sw_volume; - - if (pa_cvolume_equal(v, volume)) - return; - - *v = *volume; - - if (v == &s->hw_volume) - if (s->set_hw_volume(s) < 0) - s->sw_volume = *volume; - - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); -} - -const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_mixer_t m) { - assert(s); - assert(s->ref >= 1); - - if (m == PA_MIXER_HARDWARE && s->set_hw_volume) { - - if (s->get_hw_volume) - s->get_hw_volume(s); - - return &s->hw_volume; - } else - return &s->sw_volume; -} diff --git a/polyp/sink.h b/polyp/sink.h deleted file mode 100644 index 33aba233..00000000 --- a/polyp/sink.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef foosinkhfoo -#define foosinkhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -typedef struct pa_sink pa_sink; - -#include "core.h" -#include "sample.h" -#include "idxset.h" -#include "source.h" -#include "channelmap.h" -#include "module.h" -#include "volume.h" - -#define PA_MAX_INPUTS_PER_SINK 6 - -typedef enum pa_sink_state { - PA_SINK_RUNNING, - PA_SINK_DISCONNECTED -} pa_sink_state_t; - -typedef enum pa_mixer { - PA_MIXER_SOFTWARE, - PA_MIXER_HARDWARE -} pa_mixer_t; - -struct pa_sink { - int ref; - uint32_t index; - pa_core *core; - pa_sink_state_t state; - - char *name, *description, *driver; - pa_module *owner; - - pa_sample_spec sample_spec; - pa_channel_map channel_map; - - pa_idxset *inputs; - pa_source *monitor_source; - - pa_cvolume hw_volume, sw_volume; - - void (*notify)(pa_sink*sink); - pa_usec_t (*get_latency)(pa_sink *s); - int (*set_hw_volume)(pa_sink *s); - int (*get_hw_volume)(pa_sink *s); - - void *userdata; -}; - -pa_sink* pa_sink_new( - pa_core *core, - const char *driver, - const char *name, - int namereg_fail, - const pa_sample_spec *spec, - const pa_channel_map *map); - -void pa_sink_disconnect(pa_sink* s); -void pa_sink_unref(pa_sink*s); -pa_sink* pa_sink_ref(pa_sink *s); - -int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result); -void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result); -int pa_sink_render_into(pa_sink*s, pa_memchunk *target); -void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target); - -pa_usec_t pa_sink_get_latency(pa_sink *s); - -void pa_sink_notify(pa_sink*s); - -void pa_sink_set_owner(pa_sink *sink, pa_module *m); - -void pa_sink_set_volume(pa_sink *sink, pa_mixer_t m, const pa_cvolume *volume); -const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_mixer_t m); - -#endif diff --git a/polyp/sioman.c b/polyp/sioman.c deleted file mode 100644 index 8d7b136c..00000000 --- a/polyp/sioman.c +++ /dev/null @@ -1,42 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#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/polyp/sioman.h b/polyp/sioman.h deleted file mode 100644 index 840d93f2..00000000 --- a/polyp/sioman.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef foosiomanhfoo -#define foosiomanhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -int pa_stdio_acquire(void); -void pa_stdio_release(void); - -#endif diff --git a/polyp/socket-client.c b/polyp/socket-client.c deleted file mode 100644 index 29c9775e..00000000 --- a/polyp/socket-client.c +++ /dev/null @@ -1,513 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -/* #undef HAVE_LIBASYNCNS */ - -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_SYS_UN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif - -#ifdef HAVE_LIBASYNCNS -#include -#endif - -#include "winsock.h" - -#include "socket-client.h" -#include "socket-util.h" -#include "util.h" -#include "xmalloc.h" -#include "log.h" -#include "parseaddr.h" - -#define CONNECT_TIMEOUT 5 - -struct pa_socket_client { - int ref; - pa_mainloop_api *mainloop; - int fd; - pa_io_event *io_event; - pa_time_event *timeout_event; - pa_defer_event *defer_event; - void (*callback)(pa_socket_client*c, pa_iochannel *io, void *userdata); - void *userdata; - int local; -#ifdef HAVE_LIBASYNCNS - asyncns_t *asyncns; - asyncns_query_t * asyncns_query; - pa_io_event *asyncns_io_event; -#endif -}; - -static pa_socket_client*pa_socket_client_new(pa_mainloop_api *m) { - pa_socket_client *c; - assert(m); - - c = pa_xmalloc(sizeof(pa_socket_client)); - c->ref = 1; - c->mainloop = m; - c->fd = -1; - c->io_event = NULL; - c->defer_event = NULL; - c->timeout_event = NULL; - c->callback = NULL; - c->userdata = NULL; - c->local = 0; - -#ifdef HAVE_LIBASYNCNS - c->asyncns = NULL; - c->asyncns_io_event = NULL; - c->asyncns_query = NULL; -#endif - - return c; -} - -static void free_events(pa_socket_client *c) { - assert(c); - - if (c->io_event) { - c->mainloop->io_free(c->io_event); - c->io_event = NULL; - } - - if (c->defer_event) { - c->mainloop->defer_free(c->defer_event); - c->defer_event = NULL; - } - - if (c->timeout_event) { - c->mainloop->time_free(c->timeout_event); - c->timeout_event = NULL; - } -} - -static void do_call(pa_socket_client *c) { - pa_iochannel *io = NULL; - int error; - socklen_t lerror; - assert(c && c->callback); - - pa_socket_client_ref(c); - - if (c->fd < 0) - goto finish; - - lerror = sizeof(error); - if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &lerror) < 0) { - pa_log(__FILE__": getsockopt(): %s\n", strerror(errno)); - goto finish; - } - - if (lerror != sizeof(error)) { - pa_log(__FILE__": getsockopt() returned invalid size.\n"); - goto finish; - } - - if (error != 0) { - pa_log_debug(__FILE__": connect(): %s\n", strerror(error)); - errno = error; - goto finish; - } - - io = pa_iochannel_new(c->mainloop, c->fd, c->fd); - assert(io); - -finish: - if (!io && c->fd >= 0) - close(c->fd); - c->fd = -1; - - free_events(c); - - assert(c->callback); - c->callback(c, io, c->userdata); - - pa_socket_client_unref(c); -} - -static void connect_fixed_cb(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { - pa_socket_client *c = userdata; - assert(m && c && c->defer_event == e); - do_call(c); -} - -static void connect_io_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { - pa_socket_client *c = userdata; - assert(m && c && c->io_event == e && fd >= 0); - do_call(c); -} - -static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t len) { - int r; - assert(c && sa && len); - - pa_make_nonblock_fd(c->fd); - - if ((r = connect(c->fd, sa, len)) < 0) { - if (errno != EINPROGRESS) { - /*pa_log(__FILE__": connect(): %s\n", strerror(errno));*/ - return -1; - } - - c->io_event = c->mainloop->io_new(c->mainloop, c->fd, PA_IO_EVENT_OUTPUT, connect_io_cb, c); - assert(c->io_event); - } else { - c->defer_event = c->mainloop->defer_new(c->mainloop, connect_fixed_cb, c); - assert(c->defer_event); - } - - return 0; -} - -pa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port) { - struct sockaddr_in sa; - assert(m && port > 0); - - memset(&sa, 0, sizeof(sa)); - sa.sin_family = AF_INET; - sa.sin_port = htons(port); - sa.sin_addr.s_addr = htonl(address); - - return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); -} - -#ifdef HAVE_SYS_UN_H - -pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) { - struct sockaddr_un sa; - assert(m && filename); - - memset(&sa, 0, sizeof(sa)); - sa.sun_family = AF_UNIX; - strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); - sa.sun_path[sizeof(sa.sun_path) - 1] = 0; - - return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); -} - -#else /* HAVE_SYS_UN_H */ - -pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) { - return NULL; -} - -#endif /* HAVE_SYS_UN_H */ - -static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size_t salen) { - assert(c); - assert(sa); - assert(salen); - - switch (sa->sa_family) { - case AF_UNIX: - c->local = 1; - break; - - case AF_INET: - c->local = ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK; - break; - - case AF_INET6: - c->local = memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0; - break; - - default: - c->local = 0; - } - - if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s\n", strerror(errno)); - return -1; - } - - pa_fd_set_cloexec(c->fd, 1); - if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) - pa_socket_tcp_low_delay(c->fd); - else - pa_socket_low_delay(c->fd); - - if (do_connect(c, sa, salen) < 0) - return -1; - - return 0; -} - -pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) { - pa_socket_client *c; - assert(m && sa); - c = pa_socket_client_new(m); - assert(c); - - if (sockaddr_prepare(c, sa, salen) < 0) - goto fail; - - return c; - -fail: - pa_socket_client_unref(c); - return NULL; - -} - -static void socket_client_free(pa_socket_client *c) { - assert(c && c->mainloop); - - - free_events(c); - - if (c->fd >= 0) - close(c->fd); - -#ifdef HAVE_LIBASYNCNS - if (c->asyncns_query) - asyncns_cancel(c->asyncns, c->asyncns_query); - if (c->asyncns) - asyncns_free(c->asyncns); - if (c->asyncns_io_event) - c->mainloop->io_free(c->asyncns_io_event); -#endif - - pa_xfree(c); -} - -void pa_socket_client_unref(pa_socket_client *c) { - assert(c && c->ref >= 1); - - if (!(--(c->ref))) - socket_client_free(c); -} - -pa_socket_client* pa_socket_client_ref(pa_socket_client *c) { - assert(c && c->ref >= 1); - c->ref++; - return c; -} - -void pa_socket_client_set_callback(pa_socket_client *c, void (*on_connection)(pa_socket_client *c, pa_iochannel*io, void *userdata), void *userdata) { - assert(c); - c->callback = on_connection; - c->userdata = userdata; -} - -pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[16], uint16_t port) { - struct sockaddr_in6 sa; - - memset(&sa, 0, sizeof(sa)); - sa.sin6_family = AF_INET6; - sa.sin6_port = htons(port); - memcpy(&sa.sin6_addr, address, sizeof(sa.sin6_addr)); - - return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); -} - -#ifdef HAVE_LIBASYNCNS - -static void asyncns_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { - pa_socket_client *c = userdata; - struct addrinfo *res = NULL; - int ret; - assert(m && c && c->asyncns_io_event == e && fd >= 0); - - if (asyncns_wait(c->asyncns, 0) < 0) - goto fail; - - if (!asyncns_isdone(c->asyncns, c->asyncns_query)) - return; - - ret = asyncns_getaddrinfo_done(c->asyncns, c->asyncns_query, &res); - c->asyncns_query = NULL; - - if (ret != 0 || !res) - goto fail; - - if (res->ai_addr) - sockaddr_prepare(c, res->ai_addr, res->ai_addrlen); - - asyncns_freeaddrinfo(res); - - goto finish; - -fail: - errno == EHOSTUNREACH; - do_call(c); - -finish: - - m->io_free(c->asyncns_io_event); - c->asyncns_io_event = NULL; -} - -#endif - -static void timeout_cb(pa_mainloop_api *m, pa_time_event *e, const struct timeval *tv, void *userdata) { - pa_socket_client *c = userdata; - assert(m); - assert(e); - assert(tv); - assert(c); - - if (c->fd >= 0) { - close(c->fd); - c->fd = -1; - } - - errno = ETIMEDOUT; - do_call(c); -} - -static void start_timeout(pa_socket_client *c) { - struct timeval tv; - assert(c); - assert(!c->timeout_event); - - pa_gettimeofday(&tv); - pa_timeval_add(&tv, CONNECT_TIMEOUT * 1000000); - c->timeout_event = c->mainloop->time_new(c->mainloop, &tv, timeout_cb, c); -} - -pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*name, uint16_t default_port) { - pa_socket_client *c = NULL; - pa_parsed_address a; - assert(m && name); - - if (pa_parse_address(name, &a) < 0) - return NULL; - - if (!a.port) - a.port = default_port; - - switch (a.type) { - case PA_PARSED_ADDRESS_UNIX: - if ((c = pa_socket_client_new_unix(m, a.path_or_host))) - start_timeout(c); - break; - - case PA_PARSED_ADDRESS_TCP4: /* Fallthrough */ - case PA_PARSED_ADDRESS_TCP6: /* Fallthrough */ - case PA_PARSED_ADDRESS_TCP_AUTO:{ - - struct addrinfo hints; - char port[12]; - - snprintf(port, sizeof(port), "%u", (unsigned) a.port); - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = a.type == PA_PARSED_ADDRESS_TCP4 ? PF_INET : (a.type == PA_PARSED_ADDRESS_TCP6 ? PF_INET6 : PF_UNSPEC); - hints.ai_socktype = SOCK_STREAM; - -#ifdef HAVE_LIBASYNCNS - { - asyncns_t *asyncns; - - if (!(asyncns = asyncns_new(1))) - goto finish; - - c = pa_socket_client_new(m); - c->asyncns = asyncns; - c->asyncns_io_event = m->io_new(m, asyncns_fd(c->asyncns), PA_IO_EVENT_INPUT, asyncns_cb, c); - c->asyncns_query = asyncns_getaddrinfo(c->asyncns, a.path_or_host, port, &hints); - assert(c->asyncns_query); - start_timeout(c); - } -#else /* HAVE_LIBASYNCNS */ - { -#ifdef HAVE_GETADDRINFO - int ret; - struct addrinfo *res = NULL; - - ret = getaddrinfo(a.path_or_host, port, &hints, &res); - - if (ret < 0 || !res) - goto finish; - - if (res->ai_addr) { - if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen))) - start_timeout(c); - } - - freeaddrinfo(res); -#else /* HAVE_GETADDRINFO */ - struct hostent *host = NULL; - struct sockaddr_in s; - - /* FIXME: PF_INET6 support */ - if (hints.ai_family != PF_INET) - goto finish; - - host = gethostbyname(a.path_or_host); - if (!host) { - unsigned int addr = inet_addr(a.path_or_host); - if (addr != INADDR_NONE) - host = gethostbyaddr((char*)&addr, 4, AF_INET); - } - - if (!host) - goto finish; - - s.sin_family = AF_INET; - memcpy(&s.sin_addr, host->h_addr, sizeof(struct in_addr)); - s.sin_port = port; - - if ((c = pa_socket_client_new_sockaddr(m, &s, sizeof(s)))) - start_timeout(c); -#endif /* HAVE_GETADDRINFO */ - } -#endif /* HAVE_LIBASYNCNS */ - } - } - -finish: - pa_xfree(a.path_or_host); - return c; - -} - -/* Return non-zero when the target sockaddr is considered - local. "local" means UNIX socket or TCP socket on localhost. Other - local IP addresses are not considered local. */ -int pa_socket_client_is_local(pa_socket_client *c) { - assert(c); - return c->local; -} diff --git a/polyp/socket-client.h b/polyp/socket-client.h deleted file mode 100644 index 40e9629a..00000000 --- a/polyp/socket-client.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef foosocketclienthfoo -#define foosocketclienthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "mainloop-api.h" -#include "iochannel.h" - -struct sockaddr; - -typedef struct pa_socket_client pa_socket_client; - -pa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port); -pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[16], uint16_t port); -pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename); -pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen); -pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char *a, uint16_t default_port); - -void pa_socket_client_unref(pa_socket_client *c); -pa_socket_client* pa_socket_client_ref(pa_socket_client *c); - -void pa_socket_client_set_callback(pa_socket_client *c, void (*on_connection)(pa_socket_client *c, pa_iochannel*io, void *userdata), void *userdata); - -int pa_socket_client_is_local(pa_socket_client *c); - -#endif diff --git a/polyp/socket-server.c b/polyp/socket-server.c deleted file mode 100644 index 262b32a7..00000000 --- a/polyp/socket-server.c +++ /dev/null @@ -1,432 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_SYS_UN_H -#include -#ifndef SUN_LEN -#define SUN_LEN(ptr) \ - ((size_t)(((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path)) -#endif -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif - -#ifdef HAVE_LIBWRAP -#include -#endif - -#ifndef HAVE_INET_NTOP -#include "inet_ntop.h" -#endif - -#include "winsock.h" - -#include "socket-server.h" -#include "socket-util.h" -#include "xmalloc.h" -#include "util.h" -#include "log.h" - -struct pa_socket_server { - int ref; - int fd; - char *filename; - char *tcpwrap_service; - - void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata); - void *userdata; - - pa_io_event *io_event; - pa_mainloop_api *mainloop; - enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX, SOCKET_SERVER_IPV6 } type; -}; - -static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { - pa_socket_server *s = userdata; - pa_iochannel *io; - int nfd; - assert(s && s->mainloop == mainloop && s->io_event == e && e && fd >= 0 && fd == s->fd); - - pa_socket_server_ref(s); - - if ((nfd = accept(fd, NULL, NULL)) < 0) { - pa_log(__FILE__": accept(): %s\n", strerror(errno)); - goto finish; - } - - pa_fd_set_cloexec(nfd, 1); - - if (!s->on_connection) { - close(nfd); - goto finish; - } - -#ifdef HAVE_LIBWRAP - - if (s->type == SOCKET_SERVER_IPV4 && s->tcpwrap_service) { - struct request_info req; - - request_init(&req, RQ_DAEMON, s->tcpwrap_service, RQ_FILE, nfd, NULL); - fromhost(&req); - if (!hosts_access(&req)) { - pa_log(__FILE__": TCP connection refused by tcpwrap.\n"); - close(nfd); - goto finish; - } - - pa_log(__FILE__": TCP connection accepted by tcpwrap.\n"); - } -#endif - - /* There should be a check for socket type here */ - if (s->type == SOCKET_SERVER_IPV4) - pa_socket_tcp_low_delay(fd); - else - pa_socket_low_delay(fd); - - io = pa_iochannel_new(s->mainloop, nfd, nfd); - assert(io); - s->on_connection(s, io, s->userdata); - -finish: - pa_socket_server_unref(s); -} - -pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) { - pa_socket_server *s; - assert(m && fd >= 0); - - s = pa_xmalloc(sizeof(pa_socket_server)); - s->ref = 1; - s->fd = fd; - s->filename = NULL; - s->on_connection = NULL; - s->userdata = NULL; - s->tcpwrap_service = NULL; - - s->mainloop = m; - s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s); - assert(s->io_event); - - s->type = SOCKET_SERVER_GENERIC; - - return s; -} - -pa_socket_server* pa_socket_server_ref(pa_socket_server *s) { - assert(s && s->ref >= 1); - s->ref++; - return s; -} - -#ifdef HAVE_SYS_UN_H - -pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) { - int fd = -1; - struct sockaddr_un sa; - pa_socket_server *s; - - assert(m && filename); - - if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s\n", strerror(errno)); - goto fail; - } - - pa_fd_set_cloexec(fd, 1); - - sa.sun_family = AF_UNIX; - strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); - sa.sun_path[sizeof(sa.sun_path) - 1] = 0; - - pa_socket_low_delay(fd); - - if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) { - pa_log(__FILE__": bind(): %s\n", strerror(errno)); - goto fail; - } - - if (listen(fd, 5) < 0) { - pa_log(__FILE__": listen(): %s\n", strerror(errno)); - goto fail; - } - - s = pa_socket_server_new(m, fd); - assert(s); - - s->filename = pa_xstrdup(filename); - s->type = SOCKET_SERVER_UNIX; - - return s; - -fail: - if (fd >= 0) - close(fd); - - return NULL; -} - -#else /* HAVE_SYS_UN_H */ - -pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) { - return NULL; -} - -#endif /* HAVE_SYS_UN_H */ - -pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service) { - pa_socket_server *ss; - int fd = -1; - struct sockaddr_in sa; - int on = 1; - - assert(m && port); - - if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s\n", strerror(errno)); - goto fail; - } - - pa_fd_set_cloexec(fd, 1); - - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0) - pa_log(__FILE__": setsockopt(): %s\n", strerror(errno)); - - pa_socket_tcp_low_delay(fd); - - memset(&sa, 0, sizeof(sa)); - sa.sin_family = AF_INET; - sa.sin_port = htons(port); - sa.sin_addr.s_addr = htonl(address); - - if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { - pa_log(__FILE__": bind(): %s\n", strerror(errno)); - goto fail; - } - - if (listen(fd, 5) < 0) { - pa_log(__FILE__": listen(): %s\n", strerror(errno)); - goto fail; - } - - if ((ss = pa_socket_server_new(m, fd))) { - ss->type = SOCKET_SERVER_IPV4; - ss->tcpwrap_service = pa_xstrdup(tcpwrap_service); - } - - return ss; - -fail: - if (fd >= 0) - close(fd); - - return NULL; -} - -pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port) { - pa_socket_server *ss; - int fd = -1; - struct sockaddr_in6 sa; - int on = 1; - - assert(m && port); - - if ((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s\n", strerror(errno)); - goto fail; - } - - pa_fd_set_cloexec(fd, 1); - - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0) - pa_log(__FILE__": setsockopt(): %s\n", strerror(errno)); - - pa_socket_tcp_low_delay(fd); - - memset(&sa, 0, sizeof(sa)); - sa.sin6_family = AF_INET6; - sa.sin6_port = htons(port); - memcpy(sa.sin6_addr.s6_addr, address, 16); - - if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { - pa_log(__FILE__": bind(): %s\n", strerror(errno)); - goto fail; - } - - if (listen(fd, 5) < 0) { - pa_log(__FILE__": listen(): %s\n", strerror(errno)); - goto fail; - } - - if ((ss = pa_socket_server_new(m, fd))) - ss->type = SOCKET_SERVER_IPV6; - - return ss; - -fail: - if (fd >= 0) - close(fd); - - return NULL; -} - -static void socket_server_free(pa_socket_server*s) { - assert(s); - close(s->fd); - - if (s->filename) { - unlink(s->filename); - pa_xfree(s->filename); - } - - pa_xfree(s->tcpwrap_service); - - s->mainloop->io_free(s->io_event); - pa_xfree(s); -} - -void pa_socket_server_unref(pa_socket_server *s) { - assert(s && s->ref >= 1); - - if (!(--(s->ref))) - socket_server_free(s); -} - -void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata), void *userdata) { - assert(s && s->ref >= 1); - - s->on_connection = on_connection; - s->userdata = userdata; -} - - -char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { - assert(s && c && l > 0); - - switch (s->type) { - case SOCKET_SERVER_IPV6: { - struct sockaddr_in6 sa; - socklen_t sa_len = sizeof(sa); - - if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) { - pa_log(__FILE__": getsockname() failed: %s\n", strerror(errno)); - return NULL; - } - - if (memcmp(&in6addr_any, &sa.sin6_addr, sizeof(in6addr_any)) == 0) { - char fqdn[256]; - if (!pa_get_fqdn(fqdn, sizeof(fqdn))) - return NULL; - - snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port)); - - } else if (memcmp(&in6addr_loopback, &sa.sin6_addr, sizeof(in6addr_loopback)) == 0) { - char hn[256]; - if (!pa_get_host_name(hn, sizeof(hn))) - return NULL; - - snprintf(c, l, "{%s}tcp6:localhost:%u", hn, (unsigned) ntohs(sa.sin6_port)); - } else { - char ip[INET6_ADDRSTRLEN]; - - if (!inet_ntop(AF_INET6, &sa.sin6_addr, ip, sizeof(ip))) { - pa_log(__FILE__": inet_ntop() failed: %s\n", strerror(errno)); - return NULL; - } - - snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port)); - } - - return c; - } - - case SOCKET_SERVER_IPV4: { - struct sockaddr_in sa; - socklen_t sa_len = sizeof(sa); - - if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) { - pa_log(__FILE__": getsockname() failed: %s\n", strerror(errno)); - return NULL; - } - - if (sa.sin_addr.s_addr == INADDR_ANY) { - char fqdn[256]; - if (!pa_get_fqdn(fqdn, sizeof(fqdn))) - return NULL; - - snprintf(c, l, "tcp:%s:%u", fqdn, (unsigned) ntohs(sa.sin_port)); - } else if (sa.sin_addr.s_addr == INADDR_LOOPBACK) { - char hn[256]; - if (!pa_get_host_name(hn, sizeof(hn))) - return NULL; - - snprintf(c, l, "{%s}tcp:localhost:%u", hn, (unsigned) ntohs(sa.sin_port)); - } else { - char ip[INET_ADDRSTRLEN]; - - if (!inet_ntop(AF_INET, &sa.sin_addr, ip, sizeof(ip))) { - pa_log(__FILE__": inet_ntop() failed: %s\n", strerror(errno)); - return NULL; - } - - snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port)); - - } - - return c; - } - - case SOCKET_SERVER_UNIX: { - char hn[256]; - - if (!s->filename) - return NULL; - - if (!pa_get_host_name(hn, sizeof(hn))) - return NULL; - - snprintf(c, l, "{%s}unix:%s", hn, s->filename); - return c; - } - - default: - return NULL; - } -} diff --git a/polyp/socket-server.h b/polyp/socket-server.h deleted file mode 100644 index 6c5d7bac..00000000 --- a/polyp/socket-server.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef foosocketserverhfoo -#define foosocketserverhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include "mainloop-api.h" -#include "iochannel.h" - -/* It is safe to destroy the calling socket_server object from the callback */ - -typedef struct pa_socket_server pa_socket_server; - -pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd); -pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename); -pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service); -pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port); - -void pa_socket_server_unref(pa_socket_server*s); -pa_socket_server* pa_socket_server_ref(pa_socket_server *s); - -void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata), void *userdata); - -char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l); - -#endif diff --git a/polyp/socket-util.c b/polyp/socket-util.c deleted file mode 100644 index 032a3c91..00000000 --- a/polyp/socket-util.c +++ /dev/null @@ -1,246 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_SYS_UN_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_IN_SYSTM_H -#include -#endif -#ifdef HAVE_NETINET_IP_H -#include -#endif -#ifdef HAVE_NETINET_TCP_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif - -#include "winsock.h" - -#include "socket-util.h" -#include "util.h" -#include "xmalloc.h" -#include "log.h" - -void pa_socket_peer_to_string(int fd, char *c, size_t l) { - struct stat st; - - assert(c && l && fd >= 0); - -#ifndef OS_IS_WIN32 - if (fstat(fd, &st) < 0) { - snprintf(c, l, "Invalid client fd"); - return; - } -#endif - -#ifndef OS_IS_WIN32 - if (S_ISSOCK(st.st_mode)) { -#endif - union { - struct sockaddr sa; - struct sockaddr_in in; -#ifdef HAVE_SYS_UN_H - struct sockaddr_un un; -#endif - } sa; - socklen_t sa_len = sizeof(sa); - - if (getpeername(fd, &sa.sa, &sa_len) >= 0) { - - if (sa.sa.sa_family == AF_INET) { - uint32_t ip = ntohl(sa.in.sin_addr.s_addr); - - snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u", - ip >> 24, - (ip >> 16) & 0xFF, - (ip >> 8) & 0xFF, - ip & 0xFF, - ntohs(sa.in.sin_port)); - return; -#ifdef HAVE_SYS_UN_H - } else if (sa.sa.sa_family == AF_UNIX) { - snprintf(c, l, "UNIX socket client"); - return; -#endif - } - - } -#ifndef OS_IS_WIN32 - snprintf(c, l, "Unknown network client"); - return; - } else if (S_ISCHR(st.st_mode) && (fd == 0 || fd == 1)) { - snprintf(c, l, "STDIN/STDOUT client"); - return; - } -#endif /* OS_IS_WIN32 */ - - snprintf(c, l, "Unknown client"); -} - -int pa_socket_low_delay(int fd) { -#ifdef SO_PRIORITY - int priority; - assert(fd >= 0); - - priority = 7; - if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (void*)&priority, sizeof(priority)) < 0) - return -1; -#endif - - return 0; -} - -int pa_socket_tcp_low_delay(int fd) { - int ret, tos, on; - - assert(fd >= 0); - - ret = pa_socket_low_delay(fd); - - on = 1; - tos = 0; - -#if defined(SOL_TCP) || defined(IPPROTO_TCP) -#if defined(SOL_TCP) - if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0) -#else - if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0) -#endif - ret = -1; -#endif - -#if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || \ - defined(IPPROTO_IP)) - tos = IPTOS_LOWDELAY; -#ifdef SOL_IP - if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) -#else - if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) -#endif - ret = -1; -#endif - - return ret; - -} - -int pa_socket_set_rcvbuf(int fd, size_t l) { - assert(fd >= 0); - -/* if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&l, sizeof(l)) < 0) { */ -/* pa_log(__FILE__": SO_RCVBUF: %s\n", strerror(errno)); */ -/* return -1; */ -/* } */ - - return 0; -} - -int pa_socket_set_sndbuf(int fd, size_t l) { - assert(fd >= 0); - -/* if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&l, sizeof(l)) < 0) { */ -/* pa_log(__FILE__": SO_SNDBUF: %s\n", strerror(errno)); */ -/* return -1; */ -/* } */ - - return 0; -} - -#ifdef HAVE_SYS_UN_H - -int pa_unix_socket_is_stale(const char *fn) { - struct sockaddr_un sa; - int fd = -1, ret = -1; - - if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s\n", strerror(errno)); - goto finish; - } - - sa.sun_family = AF_UNIX; - strncpy(sa.sun_path, fn, sizeof(sa.sun_path)-1); - sa.sun_path[sizeof(sa.sun_path) - 1] = 0; - - if (connect(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) { - if (errno == ECONNREFUSED) - ret = 1; - } else - ret = 0; - -finish: - if (fd >= 0) - close(fd); - - return ret; -} - -int pa_unix_socket_remove_stale(const char *fn) { - int r; - - if ((r = pa_unix_socket_is_stale(fn)) < 0) - return errno != ENOENT ? -1 : 0; - - if (!r) - return 0; - - /* Yes, here is a race condition. But who cares? */ - if (unlink(fn) < 0) - return -1; - - return 0; -} - -#else /* HAVE_SYS_UN_H */ - -int pa_unix_socket_is_stale(const char *fn) { - return -1; -} - -int pa_unix_socket_remove_stale(const char *fn) { - return -1; -} - -#endif /* HAVE_SYS_UN_H */ diff --git a/polyp/socket-util.h b/polyp/socket-util.h deleted file mode 100644 index ae16fb16..00000000 --- a/polyp/socket-util.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef foosocketutilhfoo -#define foosocketutilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -void pa_socket_peer_to_string(int fd, char *c, size_t l); - -int pa_socket_low_delay(int fd); -int pa_socket_tcp_low_delay(int fd); - -int pa_socket_set_sndbuf(int fd, size_t l); -int pa_socket_set_rcvbuf(int fd, size_t l); - -int pa_unix_socket_is_stale(const char *fn); -int pa_unix_socket_remove_stale(const char *fn); - -#endif diff --git a/polyp/sound-file-stream.c b/polyp/sound-file-stream.c deleted file mode 100644 index 881e3077..00000000 --- a/polyp/sound-file-stream.c +++ /dev/null @@ -1,179 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -#include "sound-file-stream.h" -#include "sink-input.h" -#include "xmalloc.h" -#include "log.h" - -#define BUF_SIZE (1024*10) - -struct userdata { - SNDFILE *sndfile; - pa_sink_input *sink_input; - pa_memchunk memchunk; - sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames); -}; - -static void free_userdata(struct userdata *u) { - assert(u); - if (u->sink_input) { - pa_sink_input_disconnect(u->sink_input); - pa_sink_input_unref(u->sink_input); - } - - if (u->memchunk.memblock) - pa_memblock_unref(u->memchunk.memblock); - if (u->sndfile) - sf_close(u->sndfile); - - pa_xfree(u); -} - -static void sink_input_kill(pa_sink_input *i) { - assert(i && i->userdata); - free_userdata(i->userdata); -} - -static void si_kill(PA_GCC_UNUSED pa_mainloop_api *m, void *i) { - sink_input_kill(i); -} - -static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { - struct userdata *u; - assert(i && chunk && i->userdata); - u = i->userdata; - - if (!u->memchunk.memblock) { - uint32_t fs = pa_frame_size(&i->sample_spec); - sf_count_t samples = BUF_SIZE/fs; - - u->memchunk.memblock = pa_memblock_new(BUF_SIZE, i->sink->core->memblock_stat); - u->memchunk.index = 0; - samples = u->readf_function(u->sndfile, u->memchunk.memblock->data, samples); - u->memchunk.length = samples*fs; - - if (!u->memchunk.length) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - u->memchunk.index = u->memchunk.length = 0; - pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i); - return -1; - } - } - - *chunk = u->memchunk; - pa_memblock_ref(chunk->memblock); - assert(chunk->length); - return 0; -} - -static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) { - struct userdata *u; - assert(i && chunk && length && i->userdata); - u = i->userdata; - - assert(!memcmp(chunk, &u->memchunk, sizeof(chunk))); - assert(length <= u->memchunk.length); - - u->memchunk.index += length; - u->memchunk.length -= length; - - if (u->memchunk.length <= 0) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - u->memchunk.index = u->memchunk.length = 0; - } -} - -int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume) { - struct userdata *u = NULL; - SF_INFO sfinfo; - pa_sample_spec ss; - assert(sink && fname); - - u = pa_xmalloc(sizeof(struct userdata)); - u->sink_input = NULL; - u->memchunk.memblock = NULL; - u->memchunk.index = u->memchunk.length = 0; - u->sndfile = NULL; - - memset(&sfinfo, 0, sizeof(sfinfo)); - - if (!(u->sndfile = sf_open(fname, SFM_READ, &sfinfo))) { - pa_log(__FILE__": Failed to open file %s\n", fname); - goto fail; - } - - switch (sfinfo.format & 0xFF) { - case SF_FORMAT_PCM_16: - case SF_FORMAT_PCM_U8: - case SF_FORMAT_ULAW: - case SF_FORMAT_ALAW: - ss.format = PA_SAMPLE_S16NE; - u->readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_short; - break; - case SF_FORMAT_FLOAT: - default: - ss.format = PA_SAMPLE_FLOAT32NE; - u->readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_float; - break; - } - - ss.rate = sfinfo.samplerate; - ss.channels = sfinfo.channels; - - if (!pa_sample_spec_valid(&ss)) { - pa_log(__FILE__": Unsupported sample format in file %s\n", fname); - goto fail; - } - - if (!(u->sink_input = pa_sink_input_new(sink, __FILE__, fname, &ss, NULL, 0, -1))) - goto fail; - - if (volume) - u->sink_input->volume = *volume; - u->sink_input->peek = sink_input_peek; - u->sink_input->drop = sink_input_drop; - u->sink_input->kill = sink_input_kill; - u->sink_input->userdata = u; - - pa_sink_notify(sink); - - return 0; - -fail: - if (u) - free_userdata(u); - - return -1; -} diff --git a/polyp/sound-file-stream.h b/polyp/sound-file-stream.h deleted file mode 100644 index 2e56ef49..00000000 --- a/polyp/sound-file-stream.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef foosoundfilestreamhfoo -#define foosoundfilestreamhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "sink.h" - -int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume); - -#endif diff --git a/polyp/sound-file.c b/polyp/sound-file.c deleted file mode 100644 index 0048ed74..00000000 --- a/polyp/sound-file.c +++ /dev/null @@ -1,139 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include - -#include "sound-file.h" -#include "sample.h" -#include "log.h" - -#define MAX_FILE_SIZE (1024*1024) - -int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_memchunk *chunk, pa_memblock_stat *s) { - SNDFILE*sf = NULL; - SF_INFO sfinfo; - int ret = -1; - size_t l; - sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames); - assert(fname && ss && chunk); - - chunk->memblock = NULL; - chunk->index = chunk->length = 0; - - memset(&sfinfo, 0, sizeof(sfinfo)); - - if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) { - pa_log(__FILE__": Failed to open file %s\n", fname); - goto finish; - } - - switch (sfinfo.format & SF_FORMAT_SUBMASK) { - case SF_FORMAT_FLOAT: - case SF_FORMAT_DOUBLE: - /* Only float and double need a special case. */ - ss->format = PA_SAMPLE_FLOAT32NE; - readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_float; - break; - default: - /* Everything else is cleanly converted to signed 16 bit. */ - ss->format = PA_SAMPLE_S16NE; - readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_short; - break; - } - - ss->rate = sfinfo.samplerate; - ss->channels = sfinfo.channels; - - if (!pa_sample_spec_valid(ss)) { - pa_log(__FILE__": Unsupported sample format in file %s\n", fname); - goto finish; - } - - if ((l = pa_frame_size(ss)*sfinfo.frames) > MAX_FILE_SIZE) { - pa_log(__FILE__": File too large\n"); - goto finish; - } - - chunk->memblock = pa_memblock_new(l, s); - assert(chunk->memblock); - chunk->index = 0; - chunk->length = l; - - if (readf_function(sf, chunk->memblock->data, sfinfo.frames) != sfinfo.frames) { - pa_log(__FILE__": Premature file end\n"); - goto finish; - } - - ret = 0; - -finish: - - if (sf) - sf_close(sf); - - if (ret != 0 && chunk->memblock) - pa_memblock_unref(chunk->memblock); - - return ret; - -} - -int pa_sound_file_too_big_to_cache(const char *fname) { - SNDFILE*sf = NULL; - SF_INFO sfinfo; - pa_sample_spec ss; - - if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) { - pa_log(__FILE__": Failed to open file %s\n", fname); - return 0; - } - - sf_close(sf); - - switch (sfinfo.format & SF_FORMAT_SUBMASK) { - case SF_FORMAT_FLOAT: - case SF_FORMAT_DOUBLE: - /* Only float and double need a special case. */ - ss.format = PA_SAMPLE_FLOAT32NE; - break; - default: - /* Everything else is cleanly converted to signed 16 bit. */ - ss.format = PA_SAMPLE_S16NE; - break; - } - - ss.rate = sfinfo.samplerate; - ss.channels = sfinfo.channels; - - if ((pa_frame_size(&ss) * sfinfo.frames) > MAX_FILE_SIZE) { - pa_log(__FILE__": File too large %s\n", fname); - return 1; - } - - return 0; -} diff --git a/polyp/sound-file.h b/polyp/sound-file.h deleted file mode 100644 index e0534275..00000000 --- a/polyp/sound-file.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef soundfilehfoo -#define soundfilehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "memchunk.h" -#include "sample.h" - -int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_memchunk *chunk, pa_memblock_stat *s); - -int pa_sound_file_too_big_to_cache(const char *fname); - -#endif diff --git a/polyp/source-output.c b/polyp/source-output.c deleted file mode 100644 index e1d8ccf7..00000000 --- a/polyp/source-output.c +++ /dev/null @@ -1,228 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "source-output.h" -#include "xmalloc.h" -#include "subscribe.h" -#include "log.h" - -pa_source_output* pa_source_output_new( - pa_source *s, - const char *driver, - const char *name, - const pa_sample_spec *spec, - const pa_channel_map *map, - int resample_method) { - - pa_source_output *o; - pa_resampler *resampler = NULL; - int r; - char st[256]; - pa_channel_map tmap; - - assert(s); - assert(spec); - assert(s->state == PA_SOURCE_RUNNING); - - if (pa_idxset_size(s->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { - pa_log(__FILE__": Failed to create source output: too many outputs per source.\n"); - return NULL; - } - - if (resample_method == PA_RESAMPLER_INVALID) - resample_method = s->core->resample_method; - - if (!map) { - pa_channel_map_init_auto(&tmap, spec->channels); - map = &tmap; - } - - if (!pa_sample_spec_equal(&s->sample_spec, spec) || !pa_channel_map_equal(&s->channel_map, map)) - if (!(resampler = pa_resampler_new(&s->sample_spec, &s->channel_map, spec, map, s->core->memblock_stat, resample_method))) - return NULL; - - o = pa_xmalloc(sizeof(pa_source_output)); - o->ref = 1; - o->state = PA_SOURCE_OUTPUT_RUNNING; - o->name = pa_xstrdup(name); - o->driver = pa_xstrdup(driver); - o->owner = NULL; - o->source = s; - o->client = NULL; - - o->sample_spec = *spec; - o->channel_map = *map; - - o->push = NULL; - o->kill = NULL; - o->get_latency = NULL; - o->userdata = NULL; - - o->resampler = resampler; - - assert(s->core); - r = pa_idxset_put(s->core->source_outputs, o, &o->index); - assert(r == 0 && o->index != PA_IDXSET_INVALID); - r = pa_idxset_put(s->outputs, o, NULL); - assert(r == 0); - - pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"\n", o->index, o->name, s->index, st); - - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); - - return o; -} - -void pa_source_output_disconnect(pa_source_output*o) { - assert(o); - assert(o->state != PA_SOURCE_OUTPUT_DISCONNECTED); - assert(o->source); - assert(o->source->core); - - pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); - pa_idxset_remove_by_data(o->source->outputs, o, NULL); - - pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); - o->source = NULL; - - o->push = NULL; - o->kill = NULL; - o->get_latency = NULL; - - o->state = PA_SOURCE_OUTPUT_DISCONNECTED; -} - -static void source_output_free(pa_source_output* o) { - assert(o); - - if (o->state != PA_SOURCE_OUTPUT_DISCONNECTED) - pa_source_output_disconnect(o); - - pa_log_info(__FILE__": freed %u \"%s\"\n", o->index, o->name); - - if (o->resampler) - pa_resampler_free(o->resampler); - - pa_xfree(o->name); - pa_xfree(o->driver); - pa_xfree(o); -} - - -void pa_source_output_unref(pa_source_output* o) { - assert(o); - assert(o->ref >= 1); - - if (!(--o->ref)) - source_output_free(o); -} - -pa_source_output* pa_source_output_ref(pa_source_output *o) { - assert(o); - assert(o->ref >= 1); - - o->ref++; - return o; -} - - -void pa_source_output_kill(pa_source_output*o) { - assert(o); - assert(o->ref >= 1); - - if (o->kill) - o->kill(o); -} - -void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { - pa_memchunk rchunk; - - assert(o); - assert(chunk); - assert(chunk->length); - assert(o->push); - - if (o->state == PA_SOURCE_OUTPUT_CORKED) - return; - - if (!o->resampler) { - o->push(o, chunk); - return; - } - - pa_resampler_run(o->resampler, chunk, &rchunk); - if (!rchunk.length) - return; - - assert(rchunk.memblock); - o->push(o, &rchunk); - pa_memblock_unref(rchunk.memblock); -} - -void pa_source_output_set_name(pa_source_output *o, const char *name) { - assert(o); - assert(o->ref >= 1); - - pa_xfree(o->name); - o->name = pa_xstrdup(name); - - pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); -} - -pa_usec_t pa_source_output_get_latency(pa_source_output *o) { - assert(o); - assert(o->ref >= 1); - - if (o->get_latency) - return o->get_latency(o); - - return 0; -} - -void pa_source_output_cork(pa_source_output *o, int b) { - assert(o); - assert(o->ref >= 1); - - if (o->state == PA_SOURCE_OUTPUT_DISCONNECTED) - return; - - o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; -} - -pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { - assert(o); - assert(o->ref >= 1); - - if (!o->resampler) - return PA_RESAMPLER_INVALID; - - return pa_resampler_get_method(o->resampler); -} diff --git a/polyp/source-output.h b/polyp/source-output.h deleted file mode 100644 index f8e4b152..00000000 --- a/polyp/source-output.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef foosourceoutputhfoo -#define foosourceoutputhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -typedef struct pa_source_output pa_source_output; - -#include "source.h" -#include "sample.h" -#include "memblockq.h" -#include "resampler.h" -#include "module.h" -#include "client.h" - -typedef enum { - PA_SOURCE_OUTPUT_RUNNING, - PA_SOURCE_OUTPUT_CORKED, - PA_SOURCE_OUTPUT_DISCONNECTED -} pa_source_output_state_t; - -struct pa_source_output { - int ref; - uint32_t index; - pa_source_output_state_t state; - - char *name, *driver; - pa_module *owner; - - pa_source *source; - pa_client *client; - - pa_sample_spec sample_spec; - pa_channel_map channel_map; - - void (*push)(pa_source_output *o, const pa_memchunk *chunk); - void (*kill)(pa_source_output* o); - pa_usec_t (*get_latency) (pa_source_output *i); - - pa_resampler* resampler; - - void *userdata; -}; - -pa_source_output* pa_source_output_new( - pa_source *s, - const char *driver, - const char *name, - const pa_sample_spec *spec, - const pa_channel_map *map, - int resample_method); - -void pa_source_output_unref(pa_source_output* o); -pa_source_output* pa_source_output_ref(pa_source_output *o); - -/* To be called by the implementing module only */ -void pa_source_output_disconnect(pa_source_output*o); - -/* External code may request disconnection with this funcion */ -void pa_source_output_kill(pa_source_output*o); - -void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk); - -void pa_source_output_set_name(pa_source_output *i, const char *name); - -pa_usec_t pa_source_output_get_latency(pa_source_output *i); - -void pa_source_output_cork(pa_source_output *i, int b); - -pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o); - -#endif diff --git a/polyp/source.c b/polyp/source.c deleted file mode 100644 index 6e377b20..00000000 --- a/polyp/source.c +++ /dev/null @@ -1,195 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "source.h" -#include "source-output.h" -#include "namereg.h" -#include "xmalloc.h" -#include "subscribe.h" -#include "log.h" - -pa_source* pa_source_new( - pa_core *core, - const char *driver, - const char *name, - int fail, - const pa_sample_spec *spec, - const pa_channel_map *map) { - - pa_source *s; - char st[256]; - int r; - - assert(core); - assert(name); - assert(*name); - assert(spec); - - s = pa_xnew(pa_source, 1); - - if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SOURCE, s, fail))) { - pa_xfree(s); - return NULL; - } - - s->ref = 1; - s->core = core; - s->state = PA_SOURCE_RUNNING; - s->name = pa_xstrdup(name); - s->description = NULL; - s->driver = pa_xstrdup(driver); - s->owner = NULL; - - s->sample_spec = *spec; - if (map) - s->channel_map = *map; - else - pa_channel_map_init_auto(&s->channel_map, spec->channels); - - s->outputs = pa_idxset_new(NULL, NULL); - s->monitor_of = NULL; - - s->get_latency = NULL; - s->notify = NULL; - s->userdata = NULL; - - r = pa_idxset_put(core->sources, s, &s->index); - assert(s->index != PA_IDXSET_INVALID && r >= 0); - - pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); - - pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index); - - return s; -} - -void pa_source_disconnect(pa_source *s) { - pa_source_output *o, *j = NULL; - - assert(s); - assert(s->state == PA_SOURCE_RUNNING); - - pa_namereg_unregister(s->core, s->name); - - while ((o = pa_idxset_first(s->outputs, NULL))) { - assert(o != j); - pa_source_output_kill(o); - j = o; - } - - pa_idxset_remove_by_data(s->core->sources, s, NULL); - - s->get_latency = NULL; - s->notify = NULL; - - s->state = PA_SOURCE_DISCONNECTED; - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); -} - -static void source_free(pa_source *s) { - assert(s); - assert(!s->ref); - - if (s->state != PA_SOURCE_DISCONNECTED) - pa_source_disconnect(s); - - pa_log_info(__FILE__": freed %u \"%s\"\n", s->index, s->name); - - pa_idxset_free(s->outputs, NULL, NULL); - - pa_xfree(s->name); - pa_xfree(s->description); - pa_xfree(s->driver); - pa_xfree(s); -} - -void pa_source_unref(pa_source *s) { - assert(s); - assert(s->ref >= 1); - - if (!(--s->ref)) - source_free(s); -} - -pa_source* pa_source_ref(pa_source *s) { - assert(s); - assert(s->ref >= 1); - - s->ref++; - return s; -} - -void pa_source_notify(pa_source*s) { - assert(s); - assert(s->ref >= 1); - - if (s->notify) - s->notify(s); -} - -static int do_post(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void*userdata) { - pa_source_output *o = p; - const pa_memchunk *chunk = userdata; - - assert(o); - assert(chunk); - - pa_source_output_push(o, chunk); - return 0; -} - -void pa_source_post(pa_source*s, const pa_memchunk *chunk) { - assert(s); - assert(s->ref >= 1); - assert(chunk); - - pa_source_ref(s); - pa_idxset_foreach(s->outputs, do_post, (void*) chunk); - pa_source_unref(s); -} - -void pa_source_set_owner(pa_source *s, pa_module *m) { - assert(s); - assert(s->ref >= 1); - - s->owner = m; -} - -pa_usec_t pa_source_get_latency(pa_source *s) { - assert(s); - assert(s->ref >= 1); - - if (!s->get_latency) - return 0; - - return s->get_latency(s); -} - diff --git a/polyp/source.h b/polyp/source.h deleted file mode 100644 index 823a9424..00000000 --- a/polyp/source.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef foosourcehfoo -#define foosourcehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -typedef struct pa_source pa_source; - -#include -#include "core.h" -#include "sample.h" -#include "idxset.h" -#include "memblock.h" -#include "memchunk.h" -#include "sink.h" -#include "channelmap.h" -#include "module.h" - -#define PA_MAX_OUTPUTS_PER_SOURCE 16 - -typedef enum pa_source_state { - PA_SOURCE_RUNNING, - PA_SOURCE_DISCONNECTED -} pa_source_state_t; - -struct pa_source { - int ref; - uint32_t index; - pa_core *core; - pa_source_state_t state; - - char *name, *description, *driver; - pa_module *owner; - - pa_sample_spec sample_spec; - pa_channel_map channel_map; - - pa_idxset *outputs; - pa_sink *monitor_of; - - void (*notify)(pa_source*source); - pa_usec_t (*get_latency)(pa_source *s); - - void *userdata; -}; - -pa_source* pa_source_new( - pa_core *core, - const char *driver, - const char *name, - int namereg_fail, - const pa_sample_spec *spec, - const pa_channel_map *map); - -void pa_source_disconnect(pa_source *s); -void pa_source_unref(pa_source *s); -pa_source* pa_source_ref(pa_source *c); - -/* Pass a new memory block to all output streams */ -void pa_source_post(pa_source*s, const pa_memchunk *b); - -void pa_source_notify(pa_source *s); - -void pa_source_set_owner(pa_source *s, pa_module *m); - -pa_usec_t pa_source_get_latency(pa_source *s); - -#endif diff --git a/polyp/strbuf.c b/polyp/strbuf.c deleted file mode 100644 index aa20218a..00000000 --- a/polyp/strbuf.c +++ /dev/null @@ -1,166 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "strbuf.h" - -/* A chunk of the linked list that makes up the string */ -struct chunk { - struct chunk *next; - size_t length; -}; - -#define CHUNK_TO_TEXT(c) ((char*) (c) + sizeof(struct chunk)) - -struct pa_strbuf { - size_t length; - struct chunk *head, *tail; -}; - -pa_strbuf *pa_strbuf_new(void) { - pa_strbuf *sb = pa_xmalloc(sizeof(pa_strbuf)); - sb->length = 0; - sb->head = sb->tail = NULL; - return sb; -} - -void pa_strbuf_free(pa_strbuf *sb) { - assert(sb); - while (sb->head) { - struct chunk *c = sb->head; - sb->head = sb->head->next; - pa_xfree(c); - } - - pa_xfree(sb); -} - -/* Make a C string from the string buffer. The caller has to free - * string with pa_xfree(). */ -char *pa_strbuf_tostring(pa_strbuf *sb) { - char *t, *e; - struct chunk *c; - assert(sb); - - e = t = pa_xmalloc(sb->length+1); - - for (c = sb->head; c; c = c->next) { - assert((size_t) (e-t) <= sb->length); - memcpy(e, CHUNK_TO_TEXT(c), c->length); - e += c->length; - } - - /* Trailing NUL */ - *e = 0; - - assert(e == t+sb->length); - - return t; -} - -/* Combination of pa_strbuf_free() and pa_strbuf_tostring() */ -char *pa_strbuf_tostring_free(pa_strbuf *sb) { - char *t; - assert(sb); - t = pa_strbuf_tostring(sb); - pa_strbuf_free(sb); - return t; -} - -/* Append a string to the string buffer */ -void pa_strbuf_puts(pa_strbuf *sb, const char *t) { - assert(sb && t); - pa_strbuf_putsn(sb, t, strlen(t)); -} - -/* Append a new chunk to the linked list */ -static void append(pa_strbuf *sb, struct chunk *c) { - assert(sb && c); - - if (sb->tail) { - assert(sb->head); - sb->tail->next = c; - } else { - assert(!sb->head); - sb->head = c; - } - - sb->tail = c; - sb->length += c->length; - c->next = NULL; -} - -/* Append up to l bytes of a string to the string buffer */ -void pa_strbuf_putsn(pa_strbuf *sb, const char *t, size_t l) { - struct chunk *c; - assert(sb && t); - - if (!l) - return; - - c = pa_xmalloc(sizeof(struct chunk)+l); - c->length = l; - memcpy(CHUNK_TO_TEXT(c), t, l); - - append(sb, c); -} - -/* Append a printf() style formatted string to the string buffer. */ -/* The following is based on an example from the GNU libc documentation */ -int pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) { - int size = 100; - struct chunk *c = NULL; - - assert(sb); - - for(;;) { - va_list ap; - int r; - - c = pa_xrealloc(c, sizeof(struct chunk)+size); - - va_start(ap, format); - r = vsnprintf(CHUNK_TO_TEXT(c), size, format, ap); - va_end(ap); - - if (r > -1 && r < size) { - c->length = r; - append(sb, c); - return r; - } - - if (r > -1) /* glibc 2.1 */ - size = r+1; - else /* glibc 2.0 */ - size *= 2; - } -} diff --git a/polyp/strbuf.h b/polyp/strbuf.h deleted file mode 100644 index a88f5190..00000000 --- a/polyp/strbuf.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef foostrbufhfoo -#define foostrbufhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "gccmacro.h" - -typedef struct pa_strbuf pa_strbuf; - -pa_strbuf *pa_strbuf_new(void); -void pa_strbuf_free(pa_strbuf *sb); -char *pa_strbuf_tostring(pa_strbuf *sb); -char *pa_strbuf_tostring_free(pa_strbuf *sb); - -int pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); -void pa_strbuf_puts(pa_strbuf *sb, const char *t); -void pa_strbuf_putsn(pa_strbuf *sb, const char *t, size_t m); - -#endif diff --git a/polyp/strlist-test.c b/polyp/strlist-test.c deleted file mode 100644 index c670a105..00000000 --- a/polyp/strlist-test.c +++ /dev/null @@ -1,42 +0,0 @@ -#include - -#include "strlist.h" -#include "xmalloc.h" -#include "gccmacro.h" - -int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char* argv[]) { - char *t, *u; - pa_strlist *l = NULL; - - l = pa_strlist_prepend(l, "e"); - l = pa_strlist_prepend(l, "d"); - l = pa_strlist_prepend(l, "c"); - l = pa_strlist_prepend(l, "b"); - l = pa_strlist_prepend(l, "a"); - - t = pa_strlist_tostring(l); - pa_strlist_free(l); - - fprintf(stderr, "1: %s\n", t); - - l = pa_strlist_parse(t); - pa_xfree(t); - - t = pa_strlist_tostring(l); - fprintf(stderr, "2: %s\n", t); - pa_xfree(t); - - l = pa_strlist_pop(l, &u); - fprintf(stderr, "3: %s\n", u); - pa_xfree(u); - - l = pa_strlist_remove(l, "c"); - - t = pa_strlist_tostring(l); - fprintf(stderr, "4: %s\n", t); - pa_xfree(t); - - pa_strlist_free(l); - - return 0; -} diff --git a/polyp/strlist.c b/polyp/strlist.c deleted file mode 100644 index 09eb0c8a..00000000 --- a/polyp/strlist.c +++ /dev/null @@ -1,137 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "strlist.h" -#include "xmalloc.h" -#include "strbuf.h" -#include "util.h" - -struct pa_strlist { - pa_strlist *next; - char *str; -}; - -pa_strlist* pa_strlist_prepend(pa_strlist *l, const char *s) { - pa_strlist *n; - assert(s); - n = pa_xmalloc(sizeof(pa_strlist)); - n->str = pa_xstrdup(s); - n->next = l; - return n; -} - -char *pa_strlist_tostring(pa_strlist *l) { - int first = 1; - pa_strbuf *b; - - b = pa_strbuf_new(); - for (; l; l = l->next) { - if (!first) - pa_strbuf_puts(b, " "); - first = 0; - pa_strbuf_puts(b, l->str); - } - - return pa_strbuf_tostring_free(b); -} - -pa_strlist* pa_strlist_remove(pa_strlist *l, const char *s) { - pa_strlist *ret = l, *prev = NULL; - assert(l && s); - - while (l) { - if (!strcmp(l->str, s)) { - pa_strlist *n = l->next; - - if (!prev) { - assert(ret == l); - ret = n; - } else - prev->next = n; - - pa_xfree(l->str); - pa_xfree(l); - - l = n; - - } else { - prev = l; - l = l->next; - } - } - - return ret; -} - -void pa_strlist_free(pa_strlist *l) { - while (l) { - pa_strlist *c = l; - l = l->next; - - pa_xfree(c->str); - pa_xfree(c); - } -} - -pa_strlist* pa_strlist_pop(pa_strlist *l, char **s) { - pa_strlist *r; - assert(s); - - if (!l) { - *s = NULL; - return NULL; - } - - *s = l->str; - r = l->next; - pa_xfree(l); - return r; -} - -pa_strlist* pa_strlist_parse(const char *s) { - pa_strlist *head = NULL, *p = NULL; - const char *state = NULL; - char *r; - - while ((r = pa_split_spaces(s, &state))) { - pa_strlist *n; - - n = pa_xmalloc(sizeof(pa_strlist)); - n->str = r; - n->next = NULL; - - if (p) - p->next = n; - else - head = n; - - p = n; - } - - return head; -} diff --git a/polyp/strlist.h b/polyp/strlist.h deleted file mode 100644 index 2c54dc74..00000000 --- a/polyp/strlist.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef foostrlisthfoo -#define foostrlisthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -typedef struct pa_strlist pa_strlist; - -/* Add the specified server string to the list, return the new linked list head */ -pa_strlist* pa_strlist_prepend(pa_strlist *l, const char *s); - -/* Remove the specified string from the list, return the new linked list head */ -pa_strlist* pa_strlist_remove(pa_strlist *l, const char *s); - -/* Make a whitespace separated string of all server stringes. Returned memory has to be freed with pa_xfree() */ -char *pa_strlist_tostring(pa_strlist *l); - -/* Free the entire list */ -void pa_strlist_free(pa_strlist *l); - -/* Return the next entry in the list in *string and remove it from - * the list. Returns the new list head. The memory *string points to - * has to be freed with pa_xfree() */ -pa_strlist* pa_strlist_pop(pa_strlist *l, char **s); - -/* Parse a whitespace separated server list */ -pa_strlist* pa_strlist_parse(const char *s); - -#endif diff --git a/polyp/subscribe.c b/polyp/subscribe.c deleted file mode 100644 index e8b3c841..00000000 --- a/polyp/subscribe.c +++ /dev/null @@ -1,230 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "queue.h" -#include "subscribe.h" -#include "xmalloc.h" -#include "log.h" - -/* The subscription subsystem may be used to be notified whenever an - * entity (sink, source, ...) is created or deleted. Modules may - * register a callback function that is called whenever an event - * matching a subscription mask happens. The execution of the callback - * function is postponed to the next main loop iteration, i.e. is not - * called from within the stack frame the entity was created in. */ - -struct pa_subscription { - pa_core *core; - int dead; - void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata); - void *userdata; - pa_subscription_mask_t mask; - - pa_subscription *prev, *next; -}; - -struct pa_subscription_event { - pa_subscription_event_type_t type; - uint32_t index; -}; - -static void sched_event(pa_core *c); - -/* Allocate a new subscription object for the given subscription mask. Use the specified callback function and user data */ -pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata) { - pa_subscription *s; - assert(c); - - s = pa_xmalloc(sizeof(pa_subscription)); - s->core = c; - s->dead = 0; - s->callback = callback; - s->userdata = userdata; - s->mask = m; - - if ((s->next = c->subscriptions)) - s->next->prev = s; - s->prev = NULL; - c->subscriptions = s; - return s; -} - -/* Free a subscription object, effectively marking it for deletion */ -void pa_subscription_free(pa_subscription*s) { - assert(s && !s->dead); - s->dead = 1; - sched_event(s->core); -} - -static void free_item(pa_subscription *s) { - assert(s && s->core); - - if (s->prev) - s->prev->next = s->next; - else - s->core->subscriptions = s->next; - - if (s->next) - s->next->prev = s->prev; - - pa_xfree(s); -} - -/* Free all subscription objects */ -void pa_subscription_free_all(pa_core *c) { - pa_subscription_event *e; - assert(c); - - while (c->subscriptions) - free_item(c->subscriptions); - - if (c->subscription_event_queue) { - while ((e = pa_queue_pop(c->subscription_event_queue))) - pa_xfree(e); - - pa_queue_free(c->subscription_event_queue, NULL, NULL); - c->subscription_event_queue = NULL; - } - - if (c->subscription_defer_event) { - c->mainloop->defer_free(c->subscription_defer_event); - c->subscription_defer_event = NULL; - } -} - -/*static void dump_event(pa_subscription_event*e) { - switch (e->type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { - case PA_SUBSCRIPTION_EVENT_SINK: - pa_log(__FILE__": SINK_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_SOURCE: - pa_log(__FILE__": SOURCE_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_SINK_INPUT: - pa_log(__FILE__": SINK_INPUT_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: - pa_log(__FILE__": SOURCE_OUTPUT_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_MODULE: - pa_log(__FILE__": MODULE_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_CLIENT: - pa_log(__FILE__": CLIENT_EVENT"); - break; - default: - pa_log(__FILE__": OTHER"); - break; - } - - switch (e->type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) { - case PA_SUBSCRIPTION_EVENT_NEW: - pa_log(__FILE__": NEW"); - break; - case PA_SUBSCRIPTION_EVENT_CHANGE: - pa_log(__FILE__": CHANGE"); - break; - case PA_SUBSCRIPTION_EVENT_REMOVE: - pa_log(__FILE__": REMOVE"); - break; - default: - pa_log(__FILE__": OTHER"); - break; - } - - pa_log(__FILE__": %u\n", e->index); -}*/ - -/* Deferred callback for dispatching subscirption events */ -static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) { - pa_core *c = userdata; - pa_subscription *s; - assert(c && c->subscription_defer_event == de && c->mainloop == m); - - c->mainloop->defer_enable(c->subscription_defer_event, 0); - - - /* Dispatch queued events */ - - if (c->subscription_event_queue) { - pa_subscription_event *e; - - while ((e = pa_queue_pop(c->subscription_event_queue))) { - - for (s = c->subscriptions; s; s = s->next) { - - if (!s->dead && pa_subscription_match_flags(s->mask, e->type)) - s->callback(c, e->type, e->index, s->userdata); - } - - pa_xfree(e); - } - } - - /* Remove dead subscriptions */ - - s = c->subscriptions; - while (s) { - pa_subscription *n = s->next; - if (s->dead) - free_item(s); - s = n; - } -} - -/* Schedule an mainloop event so that a pending subscription event is dispatched */ -static void sched_event(pa_core *c) { - assert(c); - - if (!c->subscription_defer_event) { - c->subscription_defer_event = c->mainloop->defer_new(c->mainloop, defer_cb, c); - assert(c->subscription_defer_event); - } - - c->mainloop->defer_enable(c->subscription_defer_event, 1); -} - -/* Append a new subscription event to the subscription event queue and schedule a main loop event */ -void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t index) { - pa_subscription_event *e; - assert(c); - - e = pa_xmalloc(sizeof(pa_subscription_event)); - e->type = t; - e->index = index; - - if (!c->subscription_event_queue) { - c->subscription_event_queue = pa_queue_new(); - assert(c->subscription_event_queue); - } - - pa_queue_push(c->subscription_event_queue, e); - sched_event(c); -} - - diff --git a/polyp/subscribe.h b/polyp/subscribe.h deleted file mode 100644 index 625159e3..00000000 --- a/polyp/subscribe.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef foosubscribehfoo -#define foosubscribehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -typedef struct pa_subscription pa_subscription; -typedef struct pa_subscription_event pa_subscription_event; - -#include "core.h" -#include "native-common.h" - -pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata); -void pa_subscription_free(pa_subscription*s); -void pa_subscription_free_all(pa_core *c); - -void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t idx); - -#endif diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c deleted file mode 100644 index 676f67de..00000000 --- a/polyp/tagstruct.c +++ /dev/null @@ -1,609 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_NETINET_IN_H -#include -#endif - -#include "winsock.h" - -#include "tagstruct.h" -#include "xmalloc.h" - - -struct pa_tagstruct { - uint8_t *data; - size_t length, allocated; - size_t rindex; - - int dynamic; -}; - -pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) { - pa_tagstruct*t; - - assert(!data || (data && length)); - - t = pa_xmalloc(sizeof(pa_tagstruct)); - t->data = (uint8_t*) data; - t->allocated = t->length = data ? length : 0; - t->rindex = 0; - t->dynamic = !data; - return t; -} - -void pa_tagstruct_free(pa_tagstruct*t) { - assert(t); - if (t->dynamic) - pa_xfree(t->data); - pa_xfree(t); -} - -uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l) { - uint8_t *p; - assert(t && t->dynamic && l); - p = t->data; - *l = t->length; - pa_xfree(t); - return p; -} - -static void extend(pa_tagstruct*t, size_t l) { - assert(t && t->dynamic); - - if (t->length+l <= t->allocated) - return; - - t->data = pa_xrealloc(t->data, t->allocated = t->length+l+100); -} - - -void pa_tagstruct_puts(pa_tagstruct*t, const char *s) { - size_t l; - assert(t); - if (s) { - l = strlen(s)+2; - extend(t, l); - t->data[t->length] = PA_TAG_STRING; - strcpy((char*) (t->data+t->length+1), s); - t->length += l; - } else { - extend(t, 1); - t->data[t->length] = PA_TAG_STRING_NULL; - t->length += 1; - } -} - -void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i) { - assert(t); - extend(t, 5); - t->data[t->length] = PA_TAG_U32; - i = htonl(i); - memcpy(t->data+t->length+1, &i, 4); - t->length += 5; -} - -void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c) { - assert(t); - extend(t, 2); - t->data[t->length] = PA_TAG_U8; - *(t->data+t->length+1) = c; - t->length += 2; -} - -void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss) { - uint32_t rate; - assert(t && ss); - extend(t, 7); - t->data[t->length] = PA_TAG_SAMPLE_SPEC; - t->data[t->length+1] = (uint8_t) ss->format; - t->data[t->length+2] = ss->channels; - rate = htonl(ss->rate); - memcpy(t->data+t->length+3, &rate, 4); - t->length += 7; -} - -void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) { - uint32_t tmp; - assert(t && p); - - extend(t, 5+length); - t->data[t->length] = PA_TAG_ARBITRARY; - tmp = htonl(length); - memcpy(t->data+t->length+1, &tmp, 4); - if (length) - memcpy(t->data+t->length+5, p, length); - t->length += 5+length; -} - -void pa_tagstruct_put_boolean(pa_tagstruct*t, int b) { - assert(t); - extend(t, 1); - t->data[t->length] = b ? PA_TAG_BOOLEAN_TRUE : PA_TAG_BOOLEAN_FALSE; - t->length += 1; -} - -void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv) { - uint32_t tmp; - assert(t); - extend(t, 9); - t->data[t->length] = PA_TAG_TIMEVAL; - tmp = htonl(tv->tv_sec); - memcpy(t->data+t->length+1, &tmp, 4); - tmp = htonl(tv->tv_usec); - memcpy(t->data+t->length+5, &tmp, 4); - t->length += 9; -} - -void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u) { - uint32_t tmp; - assert(t); - extend(t, 9); - t->data[t->length] = PA_TAG_USEC; - tmp = htonl((uint32_t) (u >> 32)); - memcpy(t->data+t->length+1, &tmp, 4); - tmp = htonl((uint32_t) u); - memcpy(t->data+t->length+5, &tmp, 4); - t->length += 9; -} - -void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) { - uint32_t tmp; - assert(t); - extend(t, 9); - t->data[t->length] = PA_TAG_U64; - tmp = htonl((uint32_t) (u >> 32)); - memcpy(t->data+t->length+1, &tmp, 4); - tmp = htonl((uint32_t) u); - memcpy(t->data+t->length+5, &tmp, 4); - t->length += 9; -} - -void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) { - unsigned i; - - assert(t); - extend(t, 2 + map->channels); - - t->data[t->length++] = PA_TAG_CHANNEL_MAP; - t->data[t->length++] = map->channels; - - for (i = 0; i < map->channels; i ++) - t->data[t->length++] = (uint8_t) map->map[i]; -} - -void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) { - unsigned i; - pa_volume_t vol; - - assert(t); - extend(t, 2 + cvolume->channels * sizeof(pa_volume_t)); - - t->data[t->length++] = PA_TAG_CVOLUME; - t->data[t->length++] = cvolume->channels; - - for (i = 0; i < cvolume->channels; i ++) { - vol = htonl(cvolume->values[i]); - memcpy(t->data + t->length, &vol, sizeof(pa_volume_t)); - t->length += sizeof(pa_volume_t); - } -} - -int pa_tagstruct_gets(pa_tagstruct*t, const char **s) { - int error = 0; - size_t n; - char *c; - assert(t && s); - - if (t->rindex+1 > t->length) - return -1; - - if (t->data[t->rindex] == PA_TAG_STRING_NULL) { - t->rindex++; - *s = NULL; - return 0; - } - - if (t->rindex+2 > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_STRING) - return -1; - - error = 1; - for (n = 0, c = (char*) (t->data+t->rindex+1); t->rindex+1+n < t->length; n++, c++) - if (!*c) { - error = 0; - break; - } - - if (error) - return -1; - - *s = (char*) (t->data+t->rindex+1); - - t->rindex += n+2; - return 0; -} - -int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) { - assert(t && i); - - if (t->rindex+5 > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_U32) - return -1; - - memcpy(i, t->data+t->rindex+1, 4); - *i = ntohl(*i); - t->rindex += 5; - return 0; -} - -int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) { - assert(t && c); - - if (t->rindex+2 > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_U8) - return -1; - - *c = t->data[t->rindex+1]; - t->rindex +=2; - return 0; -} - -int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) { - assert(t && ss); - - if (t->rindex+7 > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_SAMPLE_SPEC) - return -1; - - ss->format = t->data[t->rindex+1]; - ss->channels = t->data[t->rindex+2]; - memcpy(&ss->rate, t->data+t->rindex+3, 4); - ss->rate = ntohl(ss->rate); - - if (!pa_sample_spec_valid(ss)) - return -1; - - t->rindex += 7; - return 0; -} - -int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) { - uint32_t len; - assert(t && p); - - if (t->rindex+5+length > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_ARBITRARY) - return -1; - - memcpy(&len, t->data+t->rindex+1, 4); - if (ntohl(len) != length) - return -1; - - *p = t->data+t->rindex+5; - t->rindex += 5+length; - return 0; -} - -int pa_tagstruct_eof(pa_tagstruct*t) { - assert(t); - return t->rindex >= t->length; -} - -const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) { - assert(t && t->dynamic && l); - *l = t->length; - return t->data; -} - -int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) { - assert(t && b); - - if (t->rindex+1 > t->length) - return -1; - - if (t->data[t->rindex] == PA_TAG_BOOLEAN_TRUE) - *b = 1; - else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE) - *b = 0; - else - return -1; - - t->rindex +=1; - return 0; -} - -int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) { - - if (t->rindex+9 > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_TIMEVAL) - return -1; - - memcpy(&tv->tv_sec, t->data+t->rindex+1, 4); - tv->tv_sec = ntohl(tv->tv_sec); - memcpy(&tv->tv_usec, t->data+t->rindex+5, 4); - tv->tv_usec = ntohl(tv->tv_usec); - t->rindex += 9; - return 0; - -} - -int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) { - uint32_t tmp; - assert(t && u); - - if (t->rindex+9 > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_USEC) - return -1; - - memcpy(&tmp, t->data+t->rindex+1, 4); - *u = (pa_usec_t) ntohl(tmp) << 32; - memcpy(&tmp, t->data+t->rindex+5, 4); - *u |= (pa_usec_t) ntohl(tmp); - t->rindex +=9; - return 0; -} - -int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) { - uint32_t tmp; - assert(t && u); - - if (t->rindex+9 > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_U64) - return -1; - - memcpy(&tmp, t->data+t->rindex+1, 4); - *u = (pa_usec_t) ntohl(tmp) << 32; - memcpy(&tmp, t->data+t->rindex+5, 4); - *u |= (pa_usec_t) ntohl(tmp); - t->rindex +=9; - return 0; -} - -int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) { - unsigned i; - - assert(t); - assert(map); - - if (t->rindex+2 > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_CHANNEL_MAP) - return -1; - - if ((map->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX) - return -1; - - if (t->rindex+2+map->channels > t->length) - return -1; - - for (i = 0; i < map->channels; i ++) - map->map[i] = (int8_t) t->data[t->rindex + 2 + i]; - - if (!pa_channel_map_valid(map)) - return -1; - - t->rindex += 2 + map->channels; - return 0; -} - -int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) { - unsigned i; - pa_volume_t vol; - - assert(t); - assert(cvolume); - - if (t->rindex+2 > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_CVOLUME) - return -1; - - if ((cvolume->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX) - return -1; - - if (t->rindex+2+cvolume->channels*sizeof(pa_volume_t) > t->length) - return -1; - - for (i = 0; i < cvolume->channels; i ++) { - memcpy(&vol, t->data + t->rindex + 2 + i * sizeof(pa_volume_t), sizeof(pa_volume_t)); - cvolume->values[i] = (pa_volume_t) ntohl(vol); - } - - if (!pa_cvolume_valid(cvolume)) - return -1; - - t->rindex += 2 + cvolume->channels * sizeof(pa_volume_t); - return 0; -} - -void pa_tagstruct_put(pa_tagstruct *t, ...) { - va_list va; - assert(t); - - va_start(va, t); - - for (;;) { - int tag = va_arg(va, int); - - if (tag == PA_TAG_INVALID) - break; - - switch (tag) { - case PA_TAG_STRING: - case PA_TAG_STRING_NULL: - pa_tagstruct_puts(t, va_arg(va, char*)); - break; - - case PA_TAG_U32: - pa_tagstruct_putu32(t, va_arg(va, uint32_t)); - break; - - case PA_TAG_U8: - pa_tagstruct_putu8(t, (uint8_t) va_arg(va, int)); - break; - - case PA_TAG_U64: - pa_tagstruct_putu64(t, va_arg(va, uint64_t)); - break; - - case PA_TAG_SAMPLE_SPEC: - pa_tagstruct_put_sample_spec(t, va_arg(va, pa_sample_spec*)); - break; - - case PA_TAG_ARBITRARY: { - void *p = va_arg(va, void*); - size_t size = va_arg(va, size_t); - pa_tagstruct_put_arbitrary(t, p, size); - break; - } - - case PA_TAG_BOOLEAN_TRUE: - case PA_TAG_BOOLEAN_FALSE: - pa_tagstruct_put_boolean(t, va_arg(va, int)); - break; - - case PA_TAG_TIMEVAL: - pa_tagstruct_put_timeval(t, va_arg(va, struct timeval*)); - break; - - case PA_TAG_USEC: - pa_tagstruct_put_usec(t, va_arg(va, pa_usec_t)); - break; - - case PA_TAG_CHANNEL_MAP: - pa_tagstruct_put_channel_map(t, va_arg(va, pa_channel_map *)); - break; - - case PA_TAG_CVOLUME: - pa_tagstruct_put_cvolume(t, va_arg(va, pa_cvolume *)); - break; - - default: - abort(); - } - } - - va_end(va); -} - -int pa_tagstruct_get(pa_tagstruct *t, ...) { - va_list va; - int ret = 0; - - assert(t); - - va_start(va, t); - while (ret == 0) { - int tag = va_arg(va, int); - - if (tag == PA_TAG_INVALID) - break; - - switch (tag) { - case PA_TAG_STRING: - case PA_TAG_STRING_NULL: - ret = pa_tagstruct_gets(t, va_arg(va, const char**)); - break; - - case PA_TAG_U32: - ret = pa_tagstruct_getu32(t, va_arg(va, uint32_t*)); - break; - - case PA_TAG_U8: - ret = pa_tagstruct_getu8(t, va_arg(va, uint8_t*)); - break; - - case PA_TAG_U64: - ret = pa_tagstruct_getu64(t, va_arg(va, uint64_t*)); - break; - - case PA_TAG_SAMPLE_SPEC: - ret = pa_tagstruct_get_sample_spec(t, va_arg(va, pa_sample_spec*)); - break; - - case PA_TAG_ARBITRARY: { - const void **p = va_arg(va, const void**); - size_t size = va_arg(va, size_t); - ret = pa_tagstruct_get_arbitrary(t, p, size); - break; - } - - case PA_TAG_BOOLEAN_TRUE: - case PA_TAG_BOOLEAN_FALSE: - ret = pa_tagstruct_get_boolean(t, va_arg(va, int*)); - break; - - case PA_TAG_TIMEVAL: - ret = pa_tagstruct_get_timeval(t, va_arg(va, struct timeval*)); - break; - - case PA_TAG_USEC: - ret = pa_tagstruct_get_usec(t, va_arg(va, pa_usec_t*)); - break; - - case PA_TAG_CHANNEL_MAP: - ret = pa_tagstruct_get_channel_map(t, va_arg(va, pa_channel_map *)); - break; - - case PA_TAG_CVOLUME: - ret = pa_tagstruct_get_cvolume(t, va_arg(va, pa_cvolume *)); - break; - - - default: - abort(); - } - - } - - va_end(va); - return ret; -} diff --git a/polyp/tagstruct.h b/polyp/tagstruct.h deleted file mode 100644 index b41936ff..00000000 --- a/polyp/tagstruct.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef footagstructhfoo -#define footagstructhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include - -#include "sample.h" -#include "channelmap.h" -#include "volume.h" - -typedef struct pa_tagstruct pa_tagstruct; - -enum { - PA_TAG_INVALID = 0, - PA_TAG_STRING = 't', - PA_TAG_STRING_NULL = 'N', - PA_TAG_U32 = 'L', - PA_TAG_U8 = 'B', - PA_TAG_U64 = 'R', - PA_TAG_SAMPLE_SPEC = 'a', - PA_TAG_ARBITRARY = 'x', - PA_TAG_BOOLEAN_TRUE = '1', - PA_TAG_BOOLEAN_FALSE = '0', - PA_TAG_BOOLEAN = PA_TAG_BOOLEAN_TRUE, - PA_TAG_TIMEVAL = 'T', - PA_TAG_USEC = 'U' /* 64bit unsigned */, - PA_TAG_CHANNEL_MAP = 'm', - PA_TAG_CVOLUME = 'v' -}; - - - -pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length); -void pa_tagstruct_free(pa_tagstruct*t); -uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l); - -int pa_tagstruct_eof(pa_tagstruct*t); -const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l); - -void pa_tagstruct_put(pa_tagstruct *t, ...); - -void pa_tagstruct_puts(pa_tagstruct*t, const char *s); -void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c); -void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i); -void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t i); -void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss); -void pa_tagstruct_put_arbitrary(pa_tagstruct*t, const void *p, size_t length); -void pa_tagstruct_put_boolean(pa_tagstruct*t, int b); -void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv); -void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u); -void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map); -void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume); - -int pa_tagstruct_get(pa_tagstruct *t, ...); - -int pa_tagstruct_gets(pa_tagstruct*t, const char **s); -int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c); -int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i); -int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *i); -int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss); -int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length); -int pa_tagstruct_get_boolean(pa_tagstruct *t, int *b); -int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv); -int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u); -int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map); -int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *v); - - -#endif diff --git a/polyp/tokenizer.c b/polyp/tokenizer.c deleted file mode 100644 index 5e0c1b16..00000000 --- a/polyp/tokenizer.c +++ /dev/null @@ -1,88 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "tokenizer.h" -#include "dynarray.h" -#include "xmalloc.h" -#include "gccmacro.h" - -struct pa_tokenizer { - pa_dynarray *dynarray; -}; - -static void token_free(void *p, PA_GCC_UNUSED void *userdata) { - pa_xfree(p); -} - -static void parse(pa_dynarray*a, const char *s, unsigned args) { - int infty = 0; - const char delimiter[] = " \t\n\r"; - const char *p; - assert(a && s); - - if (args == 0) - infty = 1; - - p = s+strspn(s, delimiter); - while (*p && (infty || args >= 2)) { - size_t l = strcspn(p, delimiter); - char *n = pa_xstrndup(p, l); - pa_dynarray_append(a, n); - p += l; - p += strspn(p, delimiter); - args--; - } - - if (args && *p) { - char *n = pa_xstrdup(p); - pa_dynarray_append(a, n); - } -} - -pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args) { - pa_tokenizer *t; - - t = pa_xmalloc(sizeof(pa_tokenizer)); - t->dynarray = pa_dynarray_new(); - assert(t->dynarray); - - parse(t->dynarray, s, args); - return t; -} - -void pa_tokenizer_free(pa_tokenizer *t) { - assert(t); - pa_dynarray_free(t->dynarray, token_free, NULL); - pa_xfree(t); -} - -const char *pa_tokenizer_get(pa_tokenizer *t, unsigned i) { - assert(t); - return pa_dynarray_get(t->dynarray, i); -} diff --git a/polyp/tokenizer.h b/polyp/tokenizer.h deleted file mode 100644 index bedacb8a..00000000 --- a/polyp/tokenizer.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef footokenizerhfoo -#define footokenizerhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -typedef struct pa_tokenizer pa_tokenizer; - -pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args); -void pa_tokenizer_free(pa_tokenizer *t); - -const char *pa_tokenizer_get(pa_tokenizer *t, unsigned i); - -#endif diff --git a/polyp/util.c b/polyp/util.c deleted file mode 100644 index 4b6edb97..00000000 --- a/polyp/util.c +++ /dev/null @@ -1,1176 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SCHED_H -#include -#endif - -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif - -#ifdef HAVE_PTHREAD -#include -#endif - -#ifdef HAVE_NETDB_H -#include -#endif - -#ifdef HAVE_WINDOWS_H -#include -#endif - -#include - -#ifdef HAVE_PWD_H -#include -#endif -#ifdef HAVE_GRP_H -#include -#endif - -#include "winsock.h" - -#include "util.h" -#include "xmalloc.h" -#include "log.h" - -#ifndef OS_IS_WIN32 -#define PA_RUNTIME_PATH_PREFIX "/tmp/polypaudio-" -#define PATH_SEP '/' -#else -#define PA_RUNTIME_PATH_PREFIX "%TEMP%\\polypaudio-" -#define PATH_SEP '\\' -#endif - -#ifdef OS_IS_WIN32 - -#define POLYP_ROOTENV "POLYP_ROOT" - -int pa_set_root(HANDLE handle) { - char library_path[MAX_PATH + sizeof(POLYP_ROOTENV) + 1], *sep; - - strcpy(library_path, POLYP_ROOTENV "="); - - if (!GetModuleFileName(handle, library_path + sizeof(POLYP_ROOTENV), MAX_PATH)) - return 0; - - sep = strrchr(library_path, '\\'); - if (sep) - *sep = '\0'; - - if (_putenv(library_path) < 0) - return 0; - - return 1; -} - -#endif - -/** Make a file descriptor nonblock. Doesn't do any error checking */ -void pa_make_nonblock_fd(int fd) { -#ifdef O_NONBLOCK - int v; - assert(fd >= 0); - - if ((v = fcntl(fd, F_GETFL)) >= 0) - if (!(v & O_NONBLOCK)) - fcntl(fd, F_SETFL, v|O_NONBLOCK); -#elif defined(OS_IS_WIN32) - u_long arg = 1; - if (ioctlsocket(fd, FIONBIO, &arg) < 0) { - if (WSAGetLastError() == WSAENOTSOCK) - pa_log_warn(__FILE__": WARNING: Only sockets can be made non-blocking!\n"); - } -#else - pa_log_warn(__FILE__": WARNING: Non-blocking I/O not supported.!\n"); -#endif -} - -/** Creates a directory securely */ -int pa_make_secure_dir(const char* dir) { - struct stat st; - assert(dir); - -#ifdef OS_IS_WIN32 - if (mkdir(dir) < 0) -#else - if (mkdir(dir, 0700) < 0) -#endif - if (errno != EEXIST) - return -1; - -#ifdef HAVE_LSTAT - if (lstat(dir, &st) < 0) -#else - if (stat(dir, &st) < 0) -#endif - goto fail; - -#ifndef OS_IS_WIN32 - if (!S_ISDIR(st.st_mode) || (st.st_uid != getuid()) || ((st.st_mode & 0777) != 0700)) - goto fail; -#else - fprintf(stderr, "FIXME: pa_make_secure_dir()\n"); -#endif - - return 0; - -fail: - rmdir(dir); - return -1; -} - -/* Creates a the parent directory of the specified path securely */ -int pa_make_secure_parent_dir(const char *fn) { - int ret = -1; - char *slash, *dir = pa_xstrdup(fn); - - slash = pa_path_get_filename(dir); - if (slash == fn) - goto finish; - *(slash-1) = 0; - - if (pa_make_secure_dir(dir) < 0) - goto finish; - - ret = 0; - -finish: - pa_xfree(dir); - return ret; -} - - -/** Calls read() in a loop. Makes sure that as much as 'size' bytes, - * unless EOF is reached or an error occured */ -ssize_t pa_loop_read(int fd, void*data, size_t size) { - ssize_t ret = 0; - assert(fd >= 0 && data && size); - - while (size > 0) { - ssize_t r; - - if ((r = read(fd, data, size)) < 0) - return r; - - if (r == 0) - break; - - ret += r; - data = (uint8_t*) data + r; - size -= r; - } - - return ret; -} - -/** Similar to pa_loop_read(), but wraps write() */ -ssize_t pa_loop_write(int fd, const void*data, size_t size) { - ssize_t ret = 0; - assert(fd >= 0 && data && size); - - while (size > 0) { - ssize_t r; - - if ((r = write(fd, data, size)) < 0) - return r; - - if (r == 0) - break; - - ret += r; - data = (const uint8_t*) data + r; - size -= r; - } - - return ret; -} - -/* Print a warning messages in case that the given signal is not - * blocked or trapped */ -void pa_check_signal_is_blocked(int sig) { -#ifdef HAVE_SIGACTION - struct sigaction sa; - sigset_t set; - - /* If POSIX threads are supported use thread-aware - * pthread_sigmask() function, to check if the signal is - * blocked. Otherwise fall back to sigprocmask() */ - -#ifdef HAVE_PTHREAD - if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) { -#endif - if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) { - pa_log(__FILE__": sigprocmask() failed: %s\n", strerror(errno)); - return; - } -#ifdef HAVE_PTHREAD - } -#endif - - if (sigismember(&set, sig)) - return; - - /* Check whether the signal is trapped */ - - if (sigaction(sig, NULL, &sa) < 0) { - pa_log(__FILE__": sigaction() failed: %s\n", strerror(errno)); - return; - } - - if (sa.sa_handler != SIG_DFL) - return; - - pa_log(__FILE__": WARNING: %s is not trapped. This might cause malfunction!\n", pa_strsignal(sig)); -#else /* HAVE_SIGACTION */ - pa_log(__FILE__": WARNING: %s might not be trapped. This might cause malfunction!\n", pa_strsignal(sig)); -#endif -} - -/* The following function is based on an example from the GNU libc - * documentation. This function is similar to GNU's asprintf(). */ -char *pa_sprintf_malloc(const char *format, ...) { - int size = 100; - char *c = NULL; - - assert(format); - - for(;;) { - int r; - va_list ap; - - c = pa_xrealloc(c, size); - - va_start(ap, format); - r = vsnprintf(c, size, format, ap); - va_end(ap); - - if (r > -1 && r < size) - return c; - - if (r > -1) /* glibc 2.1 */ - size = r+1; - else /* glibc 2.0 */ - size *= 2; - } -} - -/* Same as the previous function, but use a va_list instead of an - * ellipsis */ -char *pa_vsprintf_malloc(const char *format, va_list ap) { - int size = 100; - char *c = NULL; - - assert(format); - - for(;;) { - int r; - c = pa_xrealloc(c, size); - r = vsnprintf(c, size, format, ap); - - if (r > -1 && r < size) - return c; - - if (r > -1) /* glibc 2.1 */ - size = r+1; - else /* glibc 2.0 */ - size *= 2; - } -} - -/* Return the current username in the specified string buffer. */ -char *pa_get_user_name(char *s, size_t l) { - char *p; - char buf[1024]; - -#ifdef HAVE_PWD_H - struct passwd pw, *r; -#endif - - assert(s && l > 0); - - if (!(p = getenv("USER")) && !(p = getenv("LOGNAME")) && !(p = getenv("USERNAME"))) { -#ifdef HAVE_PWD_H - -#ifdef HAVE_GETPWUID_R - if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { -#else - /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) - * that do not support getpwuid_r. */ - if ((r = getpwuid(getuid())) == NULL) { -#endif - snprintf(s, l, "%lu", (unsigned long) getuid()); - return s; - } - - p = r->pw_name; - -#elif defined(OS_IS_WIN32) /* HAVE_PWD_H */ - DWORD size = sizeof(buf); - - if (!GetUserName(buf, &size)) - return NULL; - - p = buf; - -#else /* HAVE_PWD_H */ - return NULL; -#endif /* HAVE_PWD_H */ - } - - return pa_strlcpy(s, p, l); -} - -/* Return the current hostname in the specified buffer. */ -char *pa_get_host_name(char *s, size_t l) { - assert(s && l > 0); - if (gethostname(s, l) < 0) { - pa_log(__FILE__": gethostname(): %s\n", strerror(errno)); - return NULL; - } - s[l-1] = 0; - return s; -} - -/* Return the home directory of the current user */ -char *pa_get_home_dir(char *s, size_t l) { - char *e; - -#ifdef HAVE_PWD_H - char buf[1024]; - struct passwd pw, *r; -#endif - - assert(s && l); - - if ((e = getenv("HOME"))) - return pa_strlcpy(s, e, l); - - if ((e = getenv("USERPROFILE"))) - return pa_strlcpy(s, e, l); - -#ifdef HAVE_PWD_H -#ifdef HAVE_GETPWUID_R - if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { - pa_log(__FILE__": getpwuid_r() failed\n"); -#else - /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) - * that do not support getpwuid_r. */ - if ((r = getpwuid(getuid())) == NULL) { - pa_log(__FILE__": getpwuid_r() failed\n"); -#endif - return NULL; - } - - return pa_strlcpy(s, r->pw_dir, l); -#else /* HAVE_PWD_H */ - return NULL; -#endif -} - -/* Similar to OpenBSD's strlcpy() function */ -char *pa_strlcpy(char *b, const char *s, size_t l) { - assert(b && s && l > 0); - - strncpy(b, s, l); - b[l-1] = 0; - return b; -} - -int pa_gettimeofday(struct timeval *tv) { -#ifdef HAVE_GETTIMEOFDAY - return gettimeofday(tv, NULL); -#elif defined(OS_IS_WIN32) - /* - * Copied from implementation by Steven Edwards (LGPL). - * Found on wine mailing list. - */ - -#if defined(_MSC_VER) || defined(__BORLANDC__) -#define EPOCHFILETIME (116444736000000000i64) -#else -#define EPOCHFILETIME (116444736000000000LL) -#endif - - FILETIME ft; - LARGE_INTEGER li; - __int64 t; - - if (tv) { - GetSystemTimeAsFileTime(&ft); - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - t = li.QuadPart; /* In 100-nanosecond intervals */ - t -= EPOCHFILETIME; /* Offset to the Epoch time */ - t /= 10; /* In microseconds */ - tv->tv_sec = (long)(t / 1000000); - tv->tv_usec = (long)(t % 1000000); - } - - return 0; -#else -#error "Platform lacks gettimeofday() or equivalent function." -#endif -} - -/* Calculate the difference between the two specfified timeval - * timestamsps. */ -pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { - pa_usec_t r; - assert(a && b); - - /* Check which whan is the earlier time and swap the two arguments if reuqired. */ - if (pa_timeval_cmp(a, b) < 0) { - const struct timeval *c; - c = a; - a = b; - b = c; - } - - /* Calculate the second difference*/ - r = ((pa_usec_t) a->tv_sec - b->tv_sec)* 1000000; - - /* Calculate the microsecond difference */ - if (a->tv_usec > b->tv_usec) - r += ((pa_usec_t) a->tv_usec - b->tv_usec); - else if (a->tv_usec < b->tv_usec) - r -= ((pa_usec_t) b->tv_usec - a->tv_usec); - - return r; -} - -/* Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwse */ -int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { - assert(a && b); - - if (a->tv_sec < b->tv_sec) - return -1; - - if (a->tv_sec > b->tv_sec) - return 1; - - if (a->tv_usec < b->tv_usec) - return -1; - - if (a->tv_usec > b->tv_usec) - return 1; - - return 0; -} - -/* Return the time difference between now and the specified timestamp */ -pa_usec_t pa_timeval_age(const struct timeval *tv) { - struct timeval now; - assert(tv); - pa_gettimeofday(&now); - return pa_timeval_diff(&now, tv); -} - -/* Add the specified time inmicroseconds to the specified timeval structure */ -void pa_timeval_add(struct timeval *tv, pa_usec_t v) { - unsigned long secs; - assert(tv); - - secs = (v/1000000); - tv->tv_sec += (unsigned long) secs; - v -= secs*1000000; - - tv->tv_usec += v; - - /* Normalize */ - while (tv->tv_usec >= 1000000) { - tv->tv_sec++; - tv->tv_usec -= 1000000; - } -} - -#define NICE_LEVEL (-15) - -/* Raise the priority of the current process as much as possible and -sensible: set the nice level to -15 and enable realtime scheduling if -supported.*/ -void pa_raise_priority(void) { - -#ifdef HAVE_SYS_RESOURCE_H - if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) - pa_log_warn(__FILE__": setpriority() failed: %s\n", strerror(errno)); - else - pa_log_info(__FILE__": Successfully gained nice level %i.\n", NICE_LEVEL); -#endif - -#ifdef _POSIX_PRIORITY_SCHEDULING - { - struct sched_param sp; - - if (sched_getparam(0, &sp) < 0) { - pa_log(__FILE__": sched_getparam() failed: %s\n", strerror(errno)); - return; - } - - sp.sched_priority = 1; - if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) { - pa_log_warn(__FILE__": sched_setscheduler() failed: %s\n", strerror(errno)); - return; - } - - pa_log_info(__FILE__": Successfully enabled SCHED_FIFO scheduling.\n"); - } -#endif - -#ifdef OS_IS_WIN32 - if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) - pa_log_warn(__FILE__": SetPriorityClass() failed: 0x%08X\n", GetLastError()); - else - pa_log_info(__FILE__": Successfully gained high priority class.\n"); -#endif -} - -/* Reset the priority to normal, inverting the changes made by pa_raise_priority() */ -void pa_reset_priority(void) { -#ifdef OS_IS_WIN32 - SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); -#endif - -#ifdef _POSIX_PRIORITY_SCHEDULING - { - struct sched_param sp; - sched_getparam(0, &sp); - sp.sched_priority = 0; - sched_setscheduler(0, SCHED_OTHER, &sp); - } -#endif - -#ifdef HAVE_SYS_RESOURCE_H - setpriority(PRIO_PROCESS, 0, 0); -#endif -} - -/* Set the FD_CLOEXEC flag for a fd */ -int pa_fd_set_cloexec(int fd, int b) { - -#ifdef FD_CLOEXEC - int v; - assert(fd >= 0); - - if ((v = fcntl(fd, F_GETFD, 0)) < 0) - return -1; - - v = (v & ~FD_CLOEXEC) | (b ? FD_CLOEXEC : 0); - - if (fcntl(fd, F_SETFD, v) < 0) - return -1; -#endif - - return 0; -} - -/* Return the binary file name of the current process. Works on Linux - * only. This shoul be used for eyecandy only, don't rely on return - * non-NULL! */ -char *pa_get_binary_name(char *s, size_t l) { - -#ifdef HAVE_READLINK - char path[PATH_MAX]; - int i; - assert(s && l); - - /* This works on Linux only */ - - snprintf(path, sizeof(path), "/proc/%u/exe", (unsigned) getpid()); - if ((i = readlink(path, s, l-1)) < 0) - return NULL; - - s[i] = 0; - return s; -#elif defined(OS_IS_WIN32) - char path[PATH_MAX]; - if (!GetModuleFileName(NULL, path, PATH_MAX)) - return NULL; - pa_strlcpy(s, pa_path_get_filename(path), l); - return s; -#else - return NULL; -#endif -} - -/* Return a pointer to the filename inside a path (which is the last - * component). */ -char *pa_path_get_filename(const char *p) { - char *fn; - - if ((fn = strrchr(p, PATH_SEP))) - return fn+1; - - return (char*) p; -} - -/* Try to parse a boolean string value.*/ -int pa_parse_boolean(const char *v) { - - if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on")) - return 1; - else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off")) - return 0; - - return -1; -} - -/* Split the specified string wherever one of the strings in delimiter - * occurs. Each time it is called returns a newly allocated string - * with pa_xmalloc(). The variable state points to, should be - * initiallized to NULL before the first call. */ -char *pa_split(const char *c, const char *delimiter, const char**state) { - const char *current = *state ? *state : c; - size_t l; - - if (!*current) - return NULL; - - l = strcspn(current, delimiter); - *state = current+l; - - if (**state) - (*state)++; - - return pa_xstrndup(current, l); -} - -/* What is interpreted as whitespace? */ -#define WHITESPACE " \t\n" - -/* Split a string into words. Otherwise similar to pa_split(). */ -char *pa_split_spaces(const char *c, const char **state) { - const char *current = *state ? *state : c; - size_t l; - - if (!*current || *c == 0) - return NULL; - - current += strspn(current, WHITESPACE); - l = strcspn(current, WHITESPACE); - - *state = current+l; - - return pa_xstrndup(current, l); -} - -/* Return the name of an UNIX signal. Similar to GNU's strsignal() */ -const char *pa_strsignal(int sig) { - switch(sig) { - case SIGINT: return "SIGINT"; - case SIGTERM: return "SIGTERM"; -#ifdef SIGUSR1 - case SIGUSR1: return "SIGUSR1"; -#endif -#ifdef SIGUSR2 - case SIGUSR2: return "SIGUSR2"; -#endif -#ifdef SIGXCPU - case SIGXCPU: return "SIGXCPU"; -#endif -#ifdef SIGPIPE - case SIGPIPE: return "SIGPIPE"; -#endif -#ifdef SIGCHLD - case SIGCHLD: return "SIGCHLD"; -#endif -#ifdef SIGHUP - case SIGHUP: return "SIGHUP"; -#endif - default: return "UNKNOWN SIGNAL"; - } -} - -#ifdef HAVE_GRP_H - -/* Check whether the specified GID and the group name match */ -static int is_group(gid_t gid, const char *name) { - struct group group, *result = NULL; - long n; - void *data; - int r = -1; - -#ifdef HAVE_GETGRGID_R -#ifdef _SC_GETGR_R_SIZE_MAX - n = sysconf(_SC_GETGR_R_SIZE_MAX); -#else - n = -1; -#endif - if (n < 0) n = 512; - data = pa_xmalloc(n); - - if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) { - pa_log(__FILE__ ": getgrgid_r(%u) failed: %s\n", gid, strerror(errno)); - goto finish; - } - - - r = strcmp(name, result->gr_name) == 0; - -finish: - pa_xfree(data); -#else - /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not - * support getgrgid_r. */ - if ((result = getgrgid(gid)) == NULL) { - pa_log(__FILE__ ": getgrgid(%u) failed: %s\n", gid, strerror(errno)); - goto finish; - } - - r = strcmp(name, result->gr_name) == 0; - -finish: -#endif - - return r; -} - -/* Check the current user is member of the specified group */ -int pa_uid_in_group(const char *name, gid_t *gid) { - GETGROUPS_T *gids, tgid; - int n = sysconf(_SC_NGROUPS_MAX); - int r = -1, i; - - assert(n > 0); - - gids = pa_xmalloc(sizeof(GETGROUPS_T)*n); - - if ((n = getgroups(n, gids)) < 0) { - pa_log(__FILE__": getgroups() failed: %s\n", strerror(errno)); - goto finish; - } - - for (i = 0; i < n; i++) { - if (is_group(gids[i], name) > 0) { - *gid = gids[i]; - r = 1; - goto finish; - } - } - - if (is_group(tgid = getgid(), name) > 0) { - *gid = tgid; - r = 1; - goto finish; - } - - r = 0; - -finish: - - pa_xfree(gids); - return r; -} - -#else /* HAVE_GRP_H */ - -int pa_uid_in_group(const char *name, gid_t *gid) { - return -1; -} - -#endif - -/* Lock or unlock a file entirely. - (advisory on UNIX, mandatory on Windows) */ -int pa_lock_fd(int fd, int b) { -#ifdef F_SETLKW - struct flock flock; - - /* Try a R/W lock first */ - - flock.l_type = b ? F_WRLCK : F_UNLCK; - flock.l_whence = SEEK_SET; - flock.l_start = 0; - flock.l_len = 0; - - if (fcntl(fd, F_SETLKW, &flock) >= 0) - return 0; - - /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */ - if (b && errno == EBADF) { - flock.l_type = F_RDLCK; - if (fcntl(fd, F_SETLKW, &flock) >= 0) - return 0; - } - - pa_log(__FILE__": %slock failed: %s\n", !b ? "un" : "", strerror(errno)); -#endif - -#ifdef OS_IS_WIN32 - HANDLE h = (HANDLE)_get_osfhandle(fd); - - if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) - return 0; - if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) - return 0; - - pa_log(__FILE__": %slock failed: 0x%08X\n", !b ? "un" : "", GetLastError()); -#endif - - return -1; -} - -/* Remove trailing newlines from a string */ -char* pa_strip_nl(char *s) { - assert(s); - - s[strcspn(s, "\r\n")] = 0; - return s; -} - -/* Create a temporary lock file and lock it. */ -int pa_lock_lockfile(const char *fn) { - int fd = -1; - assert(fn); - - for (;;) { - struct stat st; - - if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { - pa_log(__FILE__": failed to create lock file '%s': %s\n", fn, strerror(errno)); - goto fail; - } - - if (pa_lock_fd(fd, 1) < 0) { - pa_log(__FILE__": failed to lock file '%s'.\n", fn); - goto fail; - } - - if (fstat(fd, &st) < 0) { - pa_log(__FILE__": failed to fstat() file '%s'.\n", fn); - goto fail; - } - - /* Check wheter the file has been removed meanwhile. When yes, restart this loop, otherwise, we're done */ - if (st.st_nlink >= 1) - break; - - if (pa_lock_fd(fd, 0) < 0) { - pa_log(__FILE__": failed to unlock file '%s'.\n", fn); - goto fail; - } - - if (close(fd) < 0) { - pa_log(__FILE__": failed to close file '%s'.\n", fn); - goto fail; - } - - fd = -1; - } - - return fd; - -fail: - - if (fd >= 0) - close(fd); - - return -1; -} - -/* Unlock a temporary lcok file */ -int pa_unlock_lockfile(const char *fn, int fd) { - int r = 0; - assert(fn && fd >= 0); - - if (unlink(fn) < 0) { - pa_log_warn(__FILE__": WARNING: unable to remove lock file '%s': %s\n", fn, strerror(errno)); - r = -1; - } - - if (pa_lock_fd(fd, 0) < 0) { - pa_log_warn(__FILE__": WARNING: failed to unlock file '%s'.\n", fn); - r = -1; - } - - if (close(fd) < 0) { - pa_log_warn(__FILE__": WARNING: failed to close lock file '%s': %s\n", fn, strerror(errno)); - r = -1; - } - - return r; -} - -/* Try to open a configuration file. If "env" is specified, open the - * value of the specified environment variable. Otherwise look for a - * file "local" in the home directory or a file "global" in global - * file system. If "result" is non-NULL, a pointer to a newly - * allocated buffer containing the used configuration file is - * stored there.*/ -FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result) { - const char *fn; - char h[PATH_MAX]; - -#ifdef OS_IS_WIN32 - char buf[PATH_MAX]; - - if (!getenv(POLYP_ROOTENV)) - pa_set_root(NULL); -#endif - - if (env && (fn = getenv(env))) { -#ifdef OS_IS_WIN32 - if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX)) - return NULL; - fn = buf; -#endif - - if (result) - *result = pa_xstrdup(fn); - - return fopen(fn, "r"); - } - - if (local && pa_get_home_dir(h, sizeof(h))) { - FILE *f; - char *lfn; - - fn = lfn = pa_sprintf_malloc("%s/%s", h, local); - -#ifdef OS_IS_WIN32 - if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) - return NULL; - fn = buf; -#endif - - f = fopen(fn, "r"); - - if (f || errno != ENOENT) { - if (result) - *result = pa_xstrdup(fn); - pa_xfree(lfn); - return f; - } - - pa_xfree(lfn); - } - - if (!global) { - if (result) - *result = NULL; - errno = ENOENT; - return NULL; - } - -#ifdef OS_IS_WIN32 - if (!ExpandEnvironmentStrings(global, buf, PATH_MAX)) - return NULL; - global = buf; -#endif - - if (result) - *result = pa_xstrdup(global); - - return fopen(global, "r"); -} - -/* Format the specified data as a hexademical string */ -char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) { - size_t i = 0, j = 0; - const char hex[] = "0123456789abcdef"; - assert(d && s && slength > 0); - - while (i < dlength && j+3 <= slength) { - s[j++] = hex[*d >> 4]; - s[j++] = hex[*d & 0xF]; - - d++; - i++; - } - - s[j < slength ? j : slength] = 0; - return s; -} - -/* Convert a hexadecimal digit to a number or -1 if invalid */ -static int hexc(char c) { - if (c >= '0' && c <= '9') - return c - '0'; - - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - - return -1; -} - -/* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */ -size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) { - size_t j = 0; - assert(p && d); - - while (j < dlength && *p) { - int b; - - if ((b = hexc(*(p++))) < 0) - return (size_t) -1; - - d[j] = (uint8_t) (b << 4); - - if (!*p) - return (size_t) -1; - - if ((b = hexc(*(p++))) < 0) - return (size_t) -1; - - d[j] |= (uint8_t) b; - j++; - } - - return j; -} - -/* Return the fully qualified domain name in *s */ -char *pa_get_fqdn(char *s, size_t l) { - char hn[256]; -#ifdef HAVE_GETADDRINFO - struct addrinfo *a, hints; -#endif - - if (!pa_get_host_name(hn, sizeof(hn))) - return NULL; - -#ifdef HAVE_GETADDRINFO - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_flags = AI_CANONNAME; - - if (getaddrinfo(hn, NULL, &hints, &a) < 0 || !a || !a->ai_canonname || !*a->ai_canonname) - return pa_strlcpy(s, hn, l); - - pa_strlcpy(s, a->ai_canonname, l); - freeaddrinfo(a); - return s; -#else - return pa_strlcpy(s, hn, l); -#endif -} - -/* Returns nonzero when *s starts with *pfx */ -int pa_startswith(const char *s, const char *pfx) { - size_t l; - assert(s && pfx); - l = strlen(pfx); - - return strlen(s) >= l && strncmp(s, pfx, l) == 0; -} - -/* if fn is null return the polypaudio run time path in s (/tmp/polypaudio) - * if fn is non-null and starts with / return fn in s - * otherwise append fn to the run time path and return it in s */ -char *pa_runtime_path(const char *fn, char *s, size_t l) { - char u[256]; - -#ifndef OS_IS_WIN32 - if (fn && *fn == '/') -#else - if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\') -#endif - return pa_strlcpy(s, fn, l); - - if (fn) - snprintf(s, l, "%s%s%c%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn); - else - snprintf(s, l, "%s%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u))); - -#ifdef OS_IS_WIN32 - { - char buf[l]; - strcpy(buf, s); - ExpandEnvironmentStrings(buf, s, l); - } -#endif - - return s; -} - -/* Wait t milliseconds */ -int pa_msleep(unsigned long t) { -#ifdef OS_IS_WIN32 - Sleep(t); - return 0; -#elif defined(HAVE_NANOSLEEP) - struct timespec ts; - - ts.tv_sec = t/1000; - ts.tv_nsec = (t % 1000) * 1000000; - - return nanosleep(&ts, NULL); -#else -#error "Platform lacks a sleep function." -#endif -} - -/* Convert the string s to a signed integer in *ret_i */ -int pa_atoi(const char *s, int32_t *ret_i) { - char *x = NULL; - long l; - assert(s && ret_i); - - l = strtol(s, &x, 0); - - if (!x || *x) - return -1; - - *ret_i = (int32_t) l; - - return 0; -} - -/* Convert the string s to an unsigned integer in *ret_u */ -int pa_atou(const char *s, uint32_t *ret_u) { - char *x = NULL; - unsigned long l; - assert(s && ret_u); - - l = strtoul(s, &x, 0); - - if (!x || *x) - return -1; - - *ret_u = (uint32_t) l; - - return 0; -} diff --git a/polyp/util.h b/polyp/util.h deleted file mode 100644 index 95e7b99b..00000000 --- a/polyp/util.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef fooutilhfoo -#define fooutilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include - -#include "gccmacro.h" -#include "sample.h" - -struct timeval; - -void pa_make_nonblock_fd(int fd); - -int pa_make_secure_dir(const char* dir); -int pa_make_secure_parent_dir(const char *fn); - -ssize_t pa_loop_read(int fd, void*data, size_t size); -ssize_t pa_loop_write(int fd, const void*data, size_t size); - -void pa_check_signal_is_blocked(int sig); - -char *pa_sprintf_malloc(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); -char *pa_vsprintf_malloc(const char *format, va_list ap); - -char *pa_strlcpy(char *b, const char *s, size_t l); - -char *pa_get_user_name(char *s, size_t l); -char *pa_get_host_name(char *s, size_t l); -char *pa_get_fqdn(char *s, size_t l); -char *pa_get_binary_name(char *s, size_t l); -char *pa_get_home_dir(char *s, size_t l); - -char *pa_path_get_filename(const char *p); - -int pa_gettimeofday(struct timeval *tv); -pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); -int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); -pa_usec_t pa_timeval_age(const struct timeval *tv); -void pa_timeval_add(struct timeval *tv, pa_usec_t v); - -void pa_raise_priority(void); -void pa_reset_priority(void); - -int pa_fd_set_cloexec(int fd, int b); - -int pa_parse_boolean(const char *s); - -char *pa_split(const char *c, const char*delimiters, const char **state); -char *pa_split_spaces(const char *c, const char **state); - -char *pa_strip_nl(char *s); - -const char *pa_strsignal(int sig); - -int pa_uid_in_group(const char *name, gid_t *gid); - -int pa_lock_fd(int fd, int b); - -int pa_lock_lockfile(const char *fn); -int pa_unlock_lockfile(const char *fn, int fd); - -FILE *pa_open_config_file(const char *env, const char *global, const char *local, char **result); - -char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength); -size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength); - -int pa_startswith(const char *s, const char *pfx); - -char *pa_runtime_path(const char *fn, char *s, size_t l); - -int pa_msleep(unsigned long t); - -int pa_atoi(const char *s, int32_t *ret_i); -int pa_atou(const char *s, uint32_t *ret_u); - -#endif diff --git a/polyp/voltest.c b/polyp/voltest.c deleted file mode 100644 index 917e04d3..00000000 --- a/polyp/voltest.c +++ /dev/null @@ -1,20 +0,0 @@ -/* $Id$ */ - -#include - -#include -#include "gccmacro.h" - -int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { - pa_volume_t v; - - for (v = PA_VOLUME_MUTED; v <= PA_VOLUME_NORM*2; v += 256) { - - double dB = pa_sw_volume_to_dB(v); - double f = pa_sw_volume_to_linear(v); - - printf("Volume: %3i; percent: %i%%; decibel %0.2f; linear = %0.2f; volume(decibel): %3i; volume(linear): %3i\n", - v, (v*100)/PA_VOLUME_NORM, dB, f, pa_sw_volume_from_dB(dB), pa_sw_volume_from_linear(f)); - - } -} diff --git a/polyp/volume.c b/polyp/volume.c deleted file mode 100644 index 0f153141..00000000 --- a/polyp/volume.c +++ /dev/null @@ -1,176 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "volume.h" - -int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) { - int i; - assert(a); - assert(b); - - if (a->channels != b->channels) - return 0; - - for (i = 0; i < a->channels; i++) - if (a->values[i] != b->values[i]) - return 0; - - return 1; -} - -pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) { - int i; - - assert(a); - assert(channels > 0); - assert(channels <= PA_CHANNELS_MAX); - - a->channels = channels; - - for (i = 0; i < a->channels; i++) - a->values[i] = v; - - return a; -} - -pa_volume_t pa_cvolume_avg(const pa_cvolume *a) { - uint64_t sum = 0; - int i; - assert(a); - - for (i = 0; i < a->channels; i++) - sum += a->values[i]; - - sum /= a->channels; - - return (pa_volume_t) sum; -} - -pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) { - return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a)* pa_sw_volume_to_linear(b)); -} - -#define USER_DECIBEL_RANGE 30 - -pa_volume_t pa_sw_volume_from_dB(double dB) { - if (dB <= -USER_DECIBEL_RANGE) - return PA_VOLUME_MUTED; - - return (pa_volume_t) ((dB/USER_DECIBEL_RANGE+1)*PA_VOLUME_NORM); -} - -double pa_sw_volume_to_dB(pa_volume_t v) { - if (v == PA_VOLUME_MUTED) - return PA_DECIBEL_MININFTY; - - return ((double) v/PA_VOLUME_NORM-1)*USER_DECIBEL_RANGE; -} - -pa_volume_t pa_sw_volume_from_linear(double v) { - - if (v <= 0) - return PA_VOLUME_MUTED; - - if (v > .999 && v < 1.001) - return PA_VOLUME_NORM; - - return pa_sw_volume_from_dB(20*log10(v)); -} - -double pa_sw_volume_to_linear(pa_volume_t v) { - - if (v == PA_VOLUME_MUTED) - return 0; - - return pow(10, pa_sw_volume_to_dB(v)/20); -} - -char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) { - unsigned channel; - int first = 1; - char *e; - - assert(s); - assert(l > 0); - assert(c); - - *(e = s) = 0; - - for (channel = 0; channel < c->channels && l > 1; channel++) { - l -= snprintf(e, l, "%s%u: %3u%%", - first ? "" : " ", - channel, - (c->values[channel]*100)/PA_VOLUME_NORM); - - e = strchr(e, 0); - first = 0; - } - - return s; -} - -/** Return non-zero if the volume of all channels is equal to the specified value */ -int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) { - unsigned c; - assert(a); - - for (c = 0; c < a->channels; c++) - if (a->values[c] != v) - return 0; - - return 1; -} - -pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { - unsigned i; - - assert(dest); - assert(a); - assert(b); - - for (i = 0; i < a->channels || i < b->channels || i < PA_CHANNELS_MAX; i++) { - - dest->values[i] = pa_sw_volume_multiply( - i < a->channels ? a->values[i] : PA_VOLUME_NORM, - i < b->channels ? b->values[i] : PA_VOLUME_NORM); - } - - dest->channels = i; - - return dest; -} - -int pa_cvolume_valid(const pa_cvolume *v) { - assert(v); - - if (v->channels <= 0 || v->channels > PA_CHANNELS_MAX) - return 0; - - return 1; -} diff --git a/polyp/volume.h b/polyp/volume.h deleted file mode 100644 index b2a48084..00000000 --- a/polyp/volume.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef foovolumehfoo -#define foovolumehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include - -/** \file - * Constants and routines for volume handling */ - -PA_C_DECL_BEGIN - -/** Volume specification: - * PA_VOLUME_MUTED: silence; - * < PA_VOLUME_NORM: decreased volume; - * PA_VOLUME_NORM: normal volume; - * > PA_VOLUME_NORM: increased volume */ -typedef uint32_t pa_volume_t; - -/** Normal volume (100%) */ -#define PA_VOLUME_NORM (0x10000) - -/** Muted volume (0%) */ -#define PA_VOLUME_MUTED (0) - -/** A structure encapsulating a per-channel volume */ -typedef struct pa_cvolume { - uint8_t channels; - pa_volume_t values[PA_CHANNELS_MAX]; -} pa_cvolume; - -/** Return non-zero when *a == *b */ -int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b); - -/** Set the volume of all channels to PA_VOLUME_NORM */ -#define pa_cvolume_reset(a, n) pa_cvolume_set((a), (n), PA_VOLUME_NORM) - -/** Set the volume of all channels to PA_VOLUME_MUTED */ -#define pa_cvolume_mute(a, n) pa_cvolume_set((a), (n), PA_VOLUME_MUTED) - -/** Set the volume of all channels to the specified parameter */ -pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v); - -/** Pretty print a volume structure */ -#define PA_CVOLUME_SNPRINT_MAX 64 -char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c); - -/** Return the average volume of all channels */ -pa_volume_t pa_cvolume_avg(const pa_cvolume *a); - -/** Return TRUE when the passed cvolume structure is valid, FALSE otherwise */ -int pa_cvolume_valid(const pa_cvolume *v); - -/** Return non-zero if the volume of all channels is equal to the specified value */ -int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v); - -#define pa_cvolume_is_muted(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_MUTED) -#define pa_cvolume_is_norm(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_NORM) - -/** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. */ -pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b); - -pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b); - -/** Convert a decibel value to a volume. \since 0.4 */ -pa_volume_t pa_sw_volume_from_dB(double f); - -/** Convert a volume to a decibel value. \since 0.4 */ -double pa_sw_volume_to_dB(pa_volume_t v); - -/** Convert a linear factor to a volume. \since 0.8 */ -pa_volume_t pa_sw_volume_from_linear(double v); - -/** Convert a volume to a linear factor. \since 0.8 */ -double pa_sw_volume_to_linear(pa_volume_t v); - -#ifdef INFINITY -#define PA_DECIBEL_MININFTY (-INFINITY) -#else -/** This value is used as minus infinity when using pa_volume_{to,from}_dB(). \since 0.4 */ -#define PA_DECIBEL_MININFTY (-200) -#endif - -PA_C_DECL_END - -#endif diff --git a/polyp/winsock.h b/polyp/winsock.h deleted file mode 100644 index b1e0f7d4..00000000 --- a/polyp/winsock.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef foowinsockhfoo -#define foowinsockhfoo - -#ifdef HAVE_WINSOCK2_H -#include - -#define ESHUTDOWN WSAESHUTDOWN -#define ECONNRESET WSAECONNRESET -#define ECONNABORTED WSAECONNABORTED -#define ENETRESET WSAENETRESET -#define EINPROGRESS WSAEINPROGRESS -#define EAFNOSUPPORT WSAEAFNOSUPPORT -#define ETIMEDOUT WSAETIMEDOUT -#define ECONNREFUSED WSAECONNREFUSED -#define EHOSTUNREACH WSAEHOSTUNREACH - -#endif - -#ifdef HAVE_WS2TCPIP_H -#include -#endif - -#endif diff --git a/polyp/x11prop.c b/polyp/x11prop.c deleted file mode 100644 index e57fc136..00000000 --- a/polyp/x11prop.c +++ /dev/null @@ -1,70 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include -#include - -#include "x11prop.h" - - -void pa_x11_set_prop(Display *d, const char *name, const char *data) { - Atom a = XInternAtom(d, name, False); - XChangeProperty(d, RootWindow(d, 0), a, XA_STRING, 8, PropModeReplace, (const unsigned char*) data, strlen(data)+1); -} - -void pa_x11_del_prop(Display *d, const char *name) { - Atom a = XInternAtom(d, name, False); - XDeleteProperty(d, RootWindow(d, 0), a); -} - -char* pa_x11_get_prop(Display *d, const char *name, char *p, size_t l) { - Atom actual_type; - int actual_format; - unsigned long nitems; - unsigned long nbytes_after; - unsigned char *prop = NULL; - char *ret = NULL; - - Atom a = XInternAtom(d, name, False); - if (XGetWindowProperty(d, RootWindow(d, 0), a, 0, (l+2)/4, False, XA_STRING, &actual_type, &actual_format, &nitems, &nbytes_after, &prop) != Success) - goto finish; - - if (actual_type != XA_STRING) - goto finish; - - memcpy(p, prop, nitems); - p[nitems] = 0; - - ret = p; - -finish: - - if (prop) - XFree(prop); - - return ret; -} diff --git a/polyp/x11prop.h b/polyp/x11prop.h deleted file mode 100644 index 5531c640..00000000 --- a/polyp/x11prop.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef foox11prophfoo -#define foox11prophfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include - -void pa_x11_set_prop(Display *d, const char *name, const char *data); -void pa_x11_del_prop(Display *d, const char *name); -char* pa_x11_get_prop(Display *d, const char *name, char *p, size_t l); - -#endif diff --git a/polyp/x11wrap.c b/polyp/x11wrap.c deleted file mode 100644 index e20a50a6..00000000 --- a/polyp/x11wrap.c +++ /dev/null @@ -1,235 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -#include "llist.h" -#include "x11wrap.h" -#include "xmalloc.h" -#include "log.h" -#include "props.h" - -typedef struct pa_x11_internal pa_x11_internal; - -struct pa_x11_internal { - PA_LLIST_FIELDS(pa_x11_internal); - pa_x11_wrapper *wrapper; - pa_io_event* io_event; - int fd; -}; - -struct pa_x11_wrapper { - pa_core *core; - int ref; - - char *property_name; - Display *display; - - pa_defer_event* defer_event; - pa_io_event* io_event; - - PA_LLIST_HEAD(pa_x11_client, clients); - PA_LLIST_HEAD(pa_x11_internal, internals); -}; - -struct pa_x11_client { - PA_LLIST_FIELDS(pa_x11_client); - pa_x11_wrapper *wrapper; - int (*callback)(pa_x11_wrapper *w, XEvent *e, void *userdata); - void *userdata; -}; - -/* Dispatch all pending X11 events */ -static void work(pa_x11_wrapper *w) { - assert(w && w->ref >= 1); - - while (XPending(w->display)) { - pa_x11_client *c; - XEvent e; - XNextEvent(w->display, &e); - - for (c = w->clients; c; c = c->next) { - assert(c->callback); - if (c->callback(w, &e, c->userdata) != 0) - break; - } - } -} - -/* IO notification event for the X11 display connection */ -static void display_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { - pa_x11_wrapper *w = userdata; - assert(m && e && fd >= 0 && w && w->ref >= 1); - work(w); -} - -/* Deferred notification event. Called once each main loop iteration */ -static void defer_event(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { - pa_x11_wrapper *w = userdata; - assert(m && e && w && w->ref >= 1); - work(w); -} - -/* IO notification event for X11 internal connections */ -static void internal_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { - pa_x11_wrapper *w = userdata; - assert(m && e && fd >= 0 && w && w->ref >= 1); - - XProcessInternalConnection(w->display, fd); -} - -/* Add a new IO source for the specified X11 internal connection */ -static pa_x11_internal* x11_internal_add(pa_x11_wrapper *w, int fd) { - pa_x11_internal *i; - assert(i && fd >= 0); - - i = pa_xmalloc(sizeof(pa_x11_internal)); - i->wrapper = w; - i->io_event = w->core->mainloop->io_new(w->core->mainloop, fd, PA_IO_EVENT_INPUT, internal_io_event, w); - i->fd = fd; - - PA_LLIST_PREPEND(pa_x11_internal, w->internals, i); - return i; -} - -/* Remove an IO source for an X11 internal connection */ -static void x11_internal_remove(pa_x11_wrapper *w, pa_x11_internal *i) { - assert(i); - - PA_LLIST_REMOVE(pa_x11_internal, w->internals, i); - w->core->mainloop->io_free(i->io_event); - pa_xfree(i); -} - -/* Implementation of XConnectionWatchProc */ -static void x11_watch(Display *display, XPointer userdata, int fd, Bool opening, XPointer *watch_data) { - pa_x11_wrapper *w = (pa_x11_wrapper*) userdata; - assert(display && w && fd >= 0); - - if (opening) - *watch_data = (XPointer) x11_internal_add(w, fd); - else - x11_internal_remove(w, (pa_x11_internal*) *watch_data); -} - -static pa_x11_wrapper* x11_wrapper_new(pa_core *c, const char *name, const char *t) { - pa_x11_wrapper*w; - Display *d; - int r; - - if (!(d = XOpenDisplay(name))) { - pa_log(__FILE__": XOpenDisplay() failed\n"); - return NULL; - } - - w = pa_xmalloc(sizeof(pa_x11_wrapper)); - w->core = c; - w->ref = 1; - w->property_name = pa_xstrdup(t); - w->display = d; - - PA_LLIST_HEAD_INIT(pa_x11_client, w->clients); - PA_LLIST_HEAD_INIT(pa_x11_internal, w->internals); - - w->defer_event = c->mainloop->defer_new(c->mainloop, defer_event, w); - w->io_event = c->mainloop->io_new(c->mainloop, ConnectionNumber(d), PA_IO_EVENT_INPUT, display_io_event, w); - - XAddConnectionWatch(d, x11_watch, (XPointer) w); - - r = pa_property_set(c, w->property_name, w); - assert(r >= 0); - - return w; -} - -static void x11_wrapper_free(pa_x11_wrapper*w) { - int r; - assert(w); - - r = pa_property_remove(w->core, w->property_name); - assert(r >= 0); - - assert(!w->clients); - - XRemoveConnectionWatch(w->display, x11_watch, (XPointer) w); - XCloseDisplay(w->display); - - w->core->mainloop->io_free(w->io_event); - w->core->mainloop->defer_free(w->defer_event); - - while (w->internals) - x11_internal_remove(w, w->internals); - - pa_xfree(w->property_name); - pa_xfree(w); -} - -pa_x11_wrapper* pa_x11_wrapper_get(pa_core *c, const char *name) { - char t[256]; - pa_x11_wrapper *w; - assert(c); - - snprintf(t, sizeof(t), "x11-wrapper%s%s", name ? "-" : "", name ? name : ""); - if ((w = pa_property_get(c, t))) - return pa_x11_wrapper_ref(w); - - return x11_wrapper_new(c, name, t); -} - -pa_x11_wrapper* pa_x11_wrapper_ref(pa_x11_wrapper *w) { - assert(w && w->ref >= 1); - w->ref++; - return w; -} - -void pa_x11_wrapper_unref(pa_x11_wrapper* w) { - assert(w && w->ref >= 1); - - if (!(--w->ref)) - x11_wrapper_free(w); -} - -Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w) { - assert(w && w->ref >= 1); - return w->display; -} - -pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata) { - pa_x11_client *c; - assert(w && w->ref >= 1); - - c = pa_xmalloc(sizeof(pa_x11_client)); - c->wrapper = w; - c->callback = cb; - c->userdata = userdata; - - PA_LLIST_PREPEND(pa_x11_client, w->clients, c); - - return c; -} - -void pa_x11_client_free(pa_x11_client *c) { - assert(c && c->wrapper && c->wrapper->ref >= 1); - - PA_LLIST_REMOVE(pa_x11_client, c->wrapper->clients, c); - pa_xfree(c); -} diff --git a/polyp/x11wrap.h b/polyp/x11wrap.h deleted file mode 100644 index 15645168..00000000 --- a/polyp/x11wrap.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef foox11wraphfoo -#define foox11wraphfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "core.h" - -typedef struct pa_x11_wrapper pa_x11_wrapper; - -/* Return the X11 wrapper for this core. In case no wrapper was - existant before, allocate a new one */ -pa_x11_wrapper* pa_x11_wrapper_get(pa_core *c, const char *name); - -/* Increase the wrapper's reference count by one */ -pa_x11_wrapper* pa_x11_wrapper_ref(pa_x11_wrapper *w); - -/* Decrease the reference counter of an X11 wrapper object */ -void pa_x11_wrapper_unref(pa_x11_wrapper* w); - -/* Return the X11 display object for this connection */ -Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w); - -typedef struct pa_x11_client pa_x11_client; - -/* Register an X11 client, that is called for each X11 event */ -pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata); - -/* Free an X11 client object */ -void pa_x11_client_free(pa_x11_client *c); - -#endif diff --git a/polyp/xmalloc.c b/polyp/xmalloc.c deleted file mode 100644 index bf366347..00000000 --- a/polyp/xmalloc.c +++ /dev/null @@ -1,122 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "memory.h" -#include "util.h" -#include "xmalloc.h" -#include "gccmacro.h" - -/* Make sure not to allocate more than this much memory. */ -#define MAX_ALLOC_SIZE (1024*1024*20) /* 20MB */ - -/* #undef malloc */ -/* #undef free */ -/* #undef realloc */ -/* #undef strndup */ -/* #undef strdup */ - -static void oom(void) PA_GCC_NORETURN; - -/** called in case of an OOM situation. Prints an error message and - * exits */ -static void oom(void) { - static const char e[] = "Not enough memory\n"; - pa_loop_write(STDERR_FILENO, e, sizeof(e)-1); -#ifdef SIGQUIT - raise(SIGQUIT); -#endif - _exit(1); -} - -void* pa_xmalloc(size_t size) { - void *p; - assert(size > 0); - assert(size < MAX_ALLOC_SIZE); - - if (!(p = malloc(size))) - oom(); - - return p; -} - -void* pa_xmalloc0(size_t size) { - void *p; - assert(size > 0); - assert(size < MAX_ALLOC_SIZE); - - if (!(p = calloc(1, size))) - oom(); - - return p; -} - -void *pa_xrealloc(void *ptr, size_t size) { - void *p; - assert(size > 0); - assert(size < MAX_ALLOC_SIZE); - - if (!(p = realloc(ptr, size))) - oom(); - return p; -} - -void* pa_xmemdup(const void *p, size_t l) { - if (!p) - return NULL; - else { - char *r = pa_xmalloc(l); - memcpy(r, p, l); - return r; - } -} - -char *pa_xstrdup(const char *s) { - if (!s) - return NULL; - - return pa_xmemdup(s, strlen(s)+1); -} - -char *pa_xstrndup(const char *s, size_t l) { - if (!s) - return NULL; - else { - char *r; - size_t t = strlen(s); - - if (t > l) - t = l; - - r = pa_xmemdup(s, t+1); - r[t] = 0; - return r; - } -} - diff --git a/polyp/xmalloc.h b/polyp/xmalloc.h deleted file mode 100644 index 2946011a..00000000 --- a/polyp/xmalloc.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef foomemoryhfoo -#define foomemoryhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include - -void* pa_xmalloc(size_t l); -void *pa_xmalloc0(size_t l); -void *pa_xrealloc(void *ptr, size_t size); -#define pa_xfree free - -char *pa_xstrdup(const char *s); -char *pa_xstrndup(const char *s, size_t l); - -void* pa_xmemdup(const void *p, size_t l); - -/** Internal helper for pa_xnew() */ -static inline void* pa_xnew_internal(unsigned n, size_t k) { - assert(n < INT_MAX/k); - return pa_xmalloc(n*k); -} - -/** Allocate n new structures of the specified type. */ -#define pa_xnew(type, n) ((type*) pa_xnew_internal((n), sizeof(type))) - -/** Internal helper for pa_xnew0() */ -static inline void* pa_xnew0_internal(unsigned n, size_t k) { - assert(n < INT_MAX/k); - return pa_xmalloc0(n*k); -} - -/** Same as pa_xnew() but set the memory to zero */ -#define pa_xnew0(type, n) ((type*) pa_xnew0_internal((n), sizeof(type))) - -#endif diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 00000000..92c7dae1 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,1061 @@ +# $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + + +################################### +# Extra directories # +################################### + +polypincludedir=$(includedir)/polyp +polypcoreincludedir=$(includedir)/polypcore +polypconfdir=$(sysconfdir)/polypaudio + +modlibdir=$(libdir)/polypaudio + +################################### +# Defines # +################################### + +POLYPAUDIO_BINARY=$(bindir)/polypaudio$(EXEEXT) +if OS_IS_WIN32 +DEFAULT_CONFIG_DIR=%POLYP_ROOT% +else +DEFAULT_CONFIG_DIR=$(polypconfdir) +endif + +################################### +# Compiler/linker flags # +################################### + +AM_CFLAGS = -I$(top_srcdir)/src +AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS +AM_CFLAGS += $(LTDLINCL) +AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) +AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" +#AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\" +AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\" +AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(POLYPAUDIO_BINARY)\" + +# This cool debug trap works on i386/gcc only +AM_CFLAGS += '-DDEBUG_TRAP=__asm__("int $$3")' + +AM_LIBADD = $(PTHREAD_LIBS) +AM_LDADD = $(PTHREAD_LIBS) + +# Only required on some platforms but defined for all to avoid errors +AM_LDFLAGS = -no-undefined + +if STATIC_BINS +BINLDFLAGS = -static +endif + +if OS_IS_WIN32 +AM_LDFLAGS+=-Wl,--export-all-symbols +WINSOCK_LIBS=-lwsock32 -lws2_32 -lwininet +endif + +################################### +# Extra files # +################################### + +EXTRA_DIST = \ + client.conf.in \ + daemon.conf.in \ + default.pa.in \ + depmod.py \ + utils/esdcompat.sh.in \ + modules/module-defs.h.m4 + +polypconf_DATA = default.pa daemon.conf client.conf + +BUILT_SOURCES = polyp/polyplib-version.h + +################################### +# Main daemon # +################################### + +bin_PROGRAMS = polypaudio + +polypaudio_SOURCES = \ + daemon/caps.h daemon/caps.c \ + daemon/cmdline.c daemon/cmdline.h \ + daemon/cpulimit.c daemon/cpulimit.h \ + daemon/daemon-conf.c daemon/daemon-conf.h \ + daemon/dumpmodules.c daemon/dumpmodules.h \ + daemon/main.c \ + polypcore/gccmacro.h + +polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) +polypaudio_CPPFLAGS = $(AM_CPPFLAGS) +polypaudio_LDADD = $(AM_LDADD) libpolypcore.la $(LIBLTDL) \ + $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) $(LIBOIL_LIBS) +polypaudio_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -dlopen force $(foreach f,$(PREOPEN_LIBS),-dlopen $(f)) + +if PREOPEN_MODS +PREOPEN_LIBS = $(PREOPEN_MODS) +else +PREOPEN_LIBS = $(modlib_LTLIBRARIES) +endif + +################################### +# Utility programs # +################################### + +bin_PROGRAMS += \ + pacat \ + pactl \ + paplay + +if HAVE_AF_UNIX +bin_PROGRAMS += pacmd +endif + +if HAVE_X11 +bin_PROGRAMS += pax11publish +endif + +if HAVE_HOWL +bin_PROGRAMS += pabrowse +endif + +bin_SCRIPTS = utils/esdcompat.sh + +pacat_SOURCES = utils/pacat.c +pacat_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la +pacat_CFLAGS = $(AM_CFLAGS) +pacat_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +paplay_SOURCES = utils/paplay.c +paplay_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) +paplay_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) +paplay_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +pactl_SOURCES = utils/pactl.c +pactl_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) +pactl_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) +pactl_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +pacmd_SOURCES = utils/pacmd.c polypcore/pid.c polypcore/pid.h +pacmd_CFLAGS = $(AM_CFLAGS) +pacmd_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la +pacmd_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +pax11publish_SOURCES = utils/pax11publish.c +pax11publish_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) +pax11publish_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) +pax11publish_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +pabrowse_SOURCES = utils/pabrowse.c +pabrowse_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-browse-@PA_MAJORMINOR@.la +pabrowse_CFLAGS = $(AM_CFLAGS) +pabrowse_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +################################### +# Test programs # +################################### + +noinst_PROGRAMS = \ + mainloop-test \ + mcalign-test \ + pacat-simple \ + parec-simple \ + strlist-test \ + voltest + +if HAVE_SIGXCPU +noinst_PROGRAMS += \ + cpulimit-test \ + cpulimit-test2 +endif + +if HAVE_GLIB20 +noinst_PROGRAMS += \ + mainloop-test-glib +endif + +if HAVE_GLIB12 +noinst_PROGRAMS += \ + mainloop-test-glib12 +endif + +mainloop_test_SOURCES = tests/mainloop-test.c +mainloop_test_CFLAGS = $(AM_CFLAGS) +mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-@PA_MAJORMINOR@.la +mainloop_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +mcalign_test_SOURCES = tests/mcalign-test.c +mcalign_test_CFLAGS = $(AM_CFLAGS) +mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpolypcore.la +mcalign_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +pacat_simple_SOURCES = tests/pacat-simple.c +pacat_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la +pacat_simple_CFLAGS = $(AM_CFLAGS) +pacat_simple_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +parec_simple_SOURCES = tests/parec-simple.c +parec_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la +parec_simple_CFLAGS = $(AM_CFLAGS) +parec_simple_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +strlist_test_SOURCES = tests/strlist-test.c +strlist_test_CFLAGS = $(AM_CFLAGS) +strlist_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpolypcore.la libstrlist.la +strlist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +voltest_SOURCES = tests/voltest.c +voltest_CFLAGS = $(AM_CFLAGS) +voltest_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la +voltest_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +cpulimit_test_SOURCES = tests/cpulimit-test.c daemon/cpulimit.c daemon/cpulimit.h +cpulimit_test_CFLAGS = $(AM_CFLAGS) +cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la libpolypcore.la +cpulimit_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +cpulimit_test2_SOURCES = tests/cpulimit-test.c daemon/cpulimit.c daemon/cpulimit.h +cpulimit_test2_CFLAGS = $(AM_CFLAGS) -DTEST2 +cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la libpolypcore.la +cpulimit_test2_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +mainloop_test_glib_SOURCES = $(mainloop_test_SOURCES) +mainloop_test_glib_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB20_CFLAGS) -DGLIB_MAIN_LOOP +mainloop_test_glib_LDADD = $(mainloop_test_LDADD) $(GLIB20_LIBS) libpolyp-mainloop-glib-@PA_MAJORMINOR@.la +mainloop_test_glib_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +mainloop_test_glib12_SOURCES = $(mainloop_test_SOURCES) +mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MAIN_LOOP +mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12-@PA_MAJORMINOR@.la +mainloop_test_glib12_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +################################### +# Client library # +################################### + +polypinclude_HEADERS = \ + polyp/cdecl.h \ + polyp/channelmap.h \ + polyp/glib-mainloop.h \ + polyp/mainloop.h \ + polyp/mainloop-api.h \ + polyp/mainloop-signal.h \ + polyp/polyplib.h \ + polyp/polyplib-context.h \ + polyp/polyplib-def.h \ + polyp/polyplib-error.h \ + polyp/polyplib-introspect.h \ + polyp/polyplib-operation.h \ + polyp/polyplib-scache.h \ + polyp/polyplib-simple.h \ + polyp/polyplib-stream.h \ + polyp/polyplib-subscribe.h \ + polyp/polyplib-version.h \ + polyp/sample.h \ + polyp/volume.h + +if HAVE_HOWL +polypinclude_HEADERS += \ + polyp/polyplib-browser.h +endif + +lib_LTLIBRARIES = \ + libpolyp-@PA_MAJORMINOR@.la \ + libpolyp-error-@PA_MAJORMINOR@.la \ + libpolyp-mainloop-@PA_MAJORMINOR@.la \ + libpolyp-simple-@PA_MAJORMINOR@.la + +if HAVE_HOWL +lib_LTLIBRARIES += \ + libpolyp-browse-@PA_MAJORMINOR@.la +endif + +if HAVE_GLIB20 +lib_LTLIBRARIES += \ + libpolyp-mainloop-glib-@PA_MAJORMINOR@.la +endif + +if HAVE_GLIB12 +lib_LTLIBRARIES += \ + libpolyp-mainloop-glib12-@PA_MAJORMINOR@.la +endif + +# Public interface +libpolyp_@PA_MAJORMINOR@_la_SOURCES = \ + polyp/cdecl.h \ + polyp/channelmap.c polyp/channelmap.h \ + polyp/client-conf.c polyp/client-conf.h \ + polyp/llist.h \ + polyp/mainloop-api.c polyp/mainloop-api.h \ + polyp/polyplib.h \ + polyp/polyplib-context.c polyp/polyplib-context.h \ + polyp/polyplib-def.h \ + polyp/polyplib-internal.h \ + polyp/polyplib-introspect.c polyp/polyplib-introspect.h \ + polyp/polyplib-operation.c polyp/polyplib-operation.h \ + polyp/polyplib-scache.c polyp/polyplib-scache.h \ + polyp/polyplib-stream.c polyp/polyplib-stream.h \ + polyp/polyplib-subscribe.c polyp/polyplib-subscribe.h \ + polyp/sample.c polyp/sample.h \ + polyp/volume.c polyp/volume.h + +# Internal stuff that is shared with libpolypcore +libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ + polypcore/authkey.c polypcore/authkey.h \ + polypcore/conf-parser.c polypcore/conf-parser.h \ + polypcore/dllmain.c \ + polypcore/dynarray.c polypcore/dynarray.h \ + polypcore/gccmacro.h \ + polypcore/idxset.c polypcore/idxset.h \ + polypcore/iochannel.c polypcore/iochannel.h \ + polypcore/log.c polypcore/log.h \ + polypcore/mcalign.c polypcore/mcalign.h \ + polypcore/memblock.c polypcore/memblock.h \ + polypcore/memchunk.c polypcore/memchunk.h \ + polypcore/native-common.h \ + polypcore/packet.c polypcore/packet.h \ + polypcore/parseaddr.c polypcore/parseaddr.h \ + polypcore/pdispatch.c polypcore/pdispatch.h \ + polypcore/pstream.c polypcore/pstream.h \ + polypcore/pstream-util.c polypcore/pstream-util.h \ + polypcore/queue.c polypcore/queue.h \ + polypcore/random.c polypcore/random.h \ + polypcore/socket-client.c polypcore/socket-client.h \ + polypcore/socket-util.c polypcore/socket-util.h \ + polypcore/strbuf.c polypcore/strbuf.h \ + polypcore/strlist.c polypcore/strlist.h \ + polypcore/tagstruct.c polypcore/tagstruct.h \ + polypcore/util.c polypcore/util.h \ + polypcore/winsock.h \ + polypcore/xmalloc.c polypcore/xmalloc.h + +if HAVE_X11 +libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ + polyp/client-conf-x11.c polyp/client-conf-x11.h \ + polypcore/x11prop.c polypcore/x11prop.h +endif + +libpolyp_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) +libpolyp_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 +libpolyp_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) + +if HAVE_X11 +libpolyp_@PA_MAJORMINOR@_la_CFLAGS += $(X_CFLAGS) +libpolyp_@PA_MAJORMINOR@_la_LDFLAGS += $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) +endif + +if HAVE_LIBASYNCNS +libpolyp_@PA_MAJORMINOR@_la_CFLAGS += $(LIBASYNCNS_CFLAGS) +libpolyp_@PA_MAJORMINOR@_la_LIBADD += $(LIBASYNCNS_LIBS) +endif + +libpolyp_error_@PA_MAJORMINOR@_la_SOURCES = polyp/polyplib-error.c polyp/polyplib-error.h +libpolyp_error_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) +libpolyp_error_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la +libpolyp_error_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 + +libpolyp_mainloop_@PA_MAJORMINOR@_la_SOURCES = \ + polyp/mainloop.c polyp/mainloop.h \ + polyp/mainloop-signal.c polyp/mainloop-signal.h \ + polypcore/poll.c polypcore/poll.h +libpolyp_mainloop_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) +libpolyp_mainloop_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la $(WINSOCK_LIBS) +libpolyp_mainloop_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 + +libpolyp_simple_@PA_MAJORMINOR@_la_SOURCES = polyp/polyplib-simple.c polyp/polyplib-simple.h +libpolyp_simple_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) +libpolyp_simple_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la +libpolyp_simple_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 + +libpolyp_browse_@PA_MAJORMINOR@_la_SOURCES = polyp/polyplib-browser.c polyp/polyplib-browser.h +libpolyp_browse_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) +libpolyp_browse_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la $(HOWL_LIBS) +libpolyp_browse_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 + +libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_SOURCES = polyp/glib-mainloop.h polyp/glib-mainloop.c +libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) +libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop-@PA_MAJORMINOR@.la $(GLIB20_LIBS) +libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 + +libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_SOURCES = polyp/glib-mainloop.h polyp/glib12-mainloop.c +libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS) +libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop-@PA_MAJORMINOR@.la $(GLIB12_LIBS) +libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 + +################################### +# Daemon core library # +################################### + +polypcoreinclude_HEADERS = \ + polypcore/cli-command.h \ + polypcore/client.h \ + polypcore/core.h \ + polypcore/dynarray.h \ + polypcore/endianmacros.h \ + polypcore/hashmap.h \ + polypcore/idxset.h \ + polypcore/iochannel.h \ + polypcore/log.h \ + polypcore/memblock.h \ + polypcore/memblockq.h \ + polypcore/memchunk.h \ + polypcore/modargs.h \ + polypcore/module.h \ + polypcore/namereg.h \ + polypcore/queue.h \ + polypcore/resampler.h \ + polypcore/sample-util.h \ + polypcore/sink.h \ + polypcore/sink-input.h \ + polypcore/sioman.h \ + polypcore/socket-server.h \ + polypcore/socket-client.h \ + polypcore/socket-util.h \ + polypcore/source.h \ + polypcore/source-output.h \ + polypcore/strbuf.h \ + polypcore/tokenizer.h \ + polypcore/tagstruct.h \ + polypcore/util.h + +lib_LTLIBRARIES += libpolypcore.la + +# Some public stuff is used even in the core. +libpolypcore_la_SOURCES = \ + polyp/channelmap.c polyp/channelmap.h \ + polyp/mainloop.c polyp/mainloop.h \ + polyp/mainloop-api.c polyp/mainloop-api.h \ + polyp/mainloop-signal.c polyp/mainloop-signal.h \ + polyp/sample.c polyp/sample.h \ + polyp/volume.c polyp/volume.h + +# Pure core stuff (some are shared in libpolyp though). +libpolypcore_la_SOURCES += \ + polypcore/autoload.c polypcore/autoload.h \ + polypcore/cli-command.c polypcore/cli-command.h \ + polypcore/cli-text.c polypcore/cli-text.h \ + polypcore/client.c polypcore/client.h \ + polypcore/conf-parser.c polypcore/conf-parser.h \ + polypcore/core.c polypcore/core.h \ + polypcore/dllmain.c \ + polypcore/dynarray.c polypcore/dynarray.h \ + polypcore/endianmacros.h \ + polypcore/g711.c polypcore/g711.h \ + polypcore/hashmap.c polypcore/hashmap.h \ + polypcore/idxset.c polypcore/idxset.h \ + polypcore/log.c polypcore/log.h \ + polypcore/mcalign.c polypcore/mcalign.h \ + polypcore/memblock.c polypcore/memblock.h \ + polypcore/memblockq.c polypcore/memblockq.h \ + polypcore/memchunk.c polypcore/memchunk.h \ + polypcore/modargs.c polypcore/modargs.h \ + polypcore/modinfo.c polypcore/modinfo.h \ + polypcore/module.c polypcore/module.h \ + polypcore/namereg.c polypcore/namereg.h \ + polypcore/pid.c polypcore/pid.h \ + polypcore/play-memchunk.c polypcore/play-memchunk.h \ + polypcore/poll.c polypcore/poll.h \ + polypcore/props.c polypcore/props.h \ + polypcore/queue.c polypcore/queue.h \ + polypcore/random.c polypcore/random.h \ + polypcore/resampler.c polypcore/resampler.h \ + polypcore/sample-util.c polypcore/sample-util.h \ + polypcore/scache.c polypcore/scache.h \ + polypcore/sconv.c polypcore/sconv.h \ + polypcore/sconv-s16be.c polypcore/sconv-s16be.h \ + polypcore/sconv-s16le.c polypcore/sconv-s16le.h \ + polypcore/sink.c polypcore/sink.h \ + polypcore/sink-input.c polypcore/sink-input.h \ + polypcore/sioman.c polypcore/sioman.h \ + polypcore/sound-file.c polypcore/sound-file.h \ + polypcore/sound-file-stream.c polypcore/sound-file-stream.h \ + polypcore/source.c polypcore/source.h \ + polypcore/source-output.c polypcore/source-output.h \ + polypcore/strbuf.c polypcore/strbuf.h \ + polypcore/subscribe.c polypcore/subscribe.h \ + polypcore/tokenizer.c polypcore/tokenizer.h \ + polypcore/util.c polypcore/util.h \ + polypcore/winsock.h \ + polypcore/xmalloc.c polypcore/xmalloc.h + +libpolypcore_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBOIL_CFLAGS) +libpolypcore_la_LDFLAGS = -avoid-version +libpolypcore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) $(LIBOIL_LIBS) + +################################### +# Plug-in support libraries # +################################### + +### Warning! Due to an obscure bug in libtool/automake it is required +### that the libraries in modlib_LTLIBRARIES are specified in-order, +### i.e. libraries near the end of the list depend on libraries near +### the head, and not the other way! + +modlib_LTLIBRARIES = \ + libsocket-util.la \ + libiochannel.la \ + libsocket-server.la \ + libsocket-client.la \ + libparseaddr.la \ + libpacket.la \ + libpstream.la \ + libioline.la \ + libcli.la \ + libprotocol-cli.la \ + libtagstruct.la \ + libpstream-util.la \ + libpdispatch.la \ + libauthkey.la \ + libauthkey-prop.la \ + libstrlist.la \ + libprotocol-simple.la \ + libprotocol-esound.la \ + libprotocol-native.la \ + libprotocol-http.la + +if HAVE_X11 +modlib_LTLIBRARIES += \ + libx11wrap.la \ + libx11prop.la +endif + +if HAVE_OSS +modlib_LTLIBRARIES += \ + liboss-util.la +endif + +if HAVE_ALSA +modlib_LTLIBRARIES += \ + libalsa-util.la +endif + +if HAVE_HOWL +modlib_LTLIBRARIES += \ + libhowl-wrap.la +endif + +libprotocol_simple_la_SOURCES = polypcore/protocol-simple.c polypcore/protocol-simple.h +libprotocol_simple_la_LDFLAGS = -avoid-version +libprotocol_simple_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket-server.la libiochannel.la + +libsocket_server_la_SOURCES = \ + polypcore/inet_ntop.c polypcore/inet_ntop.h \ + polypcore/socket-server.c polypcore/socket-server.h +libsocket_server_la_LDFLAGS = -avoid-version +libsocket_server_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la libsocket-util.la $(LIBWRAP_LIBS) $(WINSOCK_LIBS) + +libsocket_client_la_SOURCES = polypcore/socket-client.c polypcore/socket-client.h +libsocket_client_la_LDFLAGS = -avoid-version +libsocket_client_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la libsocket-util.la libparseaddr.la $(LIBASYNCNS_LIBS) $(WINSOCK_LIBS) +libsocket_client_la_CFLAGS = $(AM_CFLAGS) $(LIBASYNCNS_CFLAGS) + +libparseaddr_la_SOURCES = polypcore/parseaddr.c polypcore/parseaddr.h +libparseaddr_la_LDFLAGS = -avoid-version +libparseaddr_la_LIBADD = $(AM_LIBADD) libpolypcore.la + +libpstream_la_SOURCES = polypcore/pstream.c polypcore/pstream.h +libpstream_la_LDFLAGS = -avoid-version +libpstream_la_LIBADD = $(AM_LIBADD) libpolypcore.la libpacket.la libiochannel.la $(WINSOCK_LIBS) + +libpstream_util_la_SOURCES = polypcore/pstream-util.c polypcore/pstream-util.h +libpstream_util_la_LDFLAGS = -avoid-version +libpstream_util_la_LIBADD = $(AM_LIBADD) libpacket.la libpstream.la libtagstruct.la + +libpdispatch_la_SOURCES = polypcore/pdispatch.c polypcore/pdispatch.h +libpdispatch_la_LDFLAGS = -avoid-version +libpdispatch_la_LIBADD = $(AM_LIBADD) libtagstruct.la libpolypcore.la + +libiochannel_la_SOURCES = polypcore/iochannel.c polypcore/iochannel.h +libiochannel_la_LDFLAGS = -avoid-version +libiochannel_la_LIBADD = $(AM_LIBADD) libsocket-util.la libpolypcore.la $(WINSOCK_LIBS) + +libpacket_la_SOURCES = polypcore/packet.c polypcore/packet.h +libpacket_la_LDFLAGS = -avoid-version +libpacket_la_LIBADD = $(AM_LIBADD) libpolypcore.la + +libioline_la_SOURCES = polypcore/ioline.c polypcore/ioline.h +libioline_la_LDFLAGS = -avoid-version +libioline_la_LIBADD = $(AM_LIBADD) libiochannel.la libpolypcore.la + +libcli_la_SOURCES = polypcore/cli.c polypcore/cli.h +libcli_la_CPPFLAGS = $(AM_CPPFLAGS) +libcli_la_LDFLAGS = -avoid-version +libcli_la_LIBADD = $(AM_LIBADD) libiochannel.la libioline.la libpolypcore.la + +libstrlist_la_SOURCES = polypcore/strlist.c polypcore/strlist.h +libstrlist_la_LDFLAGS = -avoid-version +libstrlist_la_LIBADD = $(AM_LIBADD) libpolypcore.la + +libprotocol_cli_la_SOURCES = polypcore/protocol-cli.c polypcore/protocol-cli.h +libprotocol_cli_la_LDFLAGS = -avoid-version +libprotocol_cli_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libcli.la libpolypcore.la + +libprotocol_http_la_SOURCES = polypcore/protocol-http.c polypcore/protocol-http.h +libprotocol_http_la_LDFLAGS = -avoid-version +libprotocol_http_la_LIBADD = $(AM_LIBADD) libsocket-server.la libioline.la libpolypcore.la libiochannel.la + +libprotocol_native_la_SOURCES = polypcore/protocol-native.c polypcore/protocol-native.h polypcore/native-common.h +libprotocol_native_la_LDFLAGS = -avoid-version +libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libstrlist.la libpolypcore.la libiochannel.la + +libtagstruct_la_SOURCES = polypcore/tagstruct.c polypcore/tagstruct.h +libtagstruct_la_LDFLAGS = -avoid-version +libtagstruct_la_LIBADD = $(AM_LIBADD) libpolypcore.la $(WINSOCK_LIBS) + +libprotocol_esound_la_SOURCES = polypcore/protocol-esound.c polypcore/protocol-esound.h polypcore/esound.h +libprotocol_esound_la_LDFLAGS = -avoid-version +libprotocol_esound_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libauthkey.la libpolypcore.la + +libauthkey_la_SOURCES = polypcore/authkey.c polypcore/authkey.h +libauthkey_la_LDFLAGS = -avoid-version +libauthkey_la_LIBADD = $(AM_LIBADD) libpolypcore.la + +libauthkey_prop_la_SOURCES = polypcore/authkey-prop.c polypcore/authkey-prop.h +libauthkey_prop_la_LDFLAGS = -avoid-version +libauthkey_prop_la_LIBADD = $(AM_LIBADD) libpolypcore.la + +libsocket_util_la_SOURCES = polypcore/socket-util.c polypcore/socket-util.h +libsocket_util_la_LDFLAGS = -avoid-version +libsocket_util_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) + +# X11 + +libx11wrap_la_SOURCES = polypcore/x11wrap.c polypcore/x11wrap.h +libx11wrap_la_LDFLAGS = -avoid-version +libx11wrap_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) +libx11wrap_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) + +libx11prop_la_SOURCES = polypcore/x11prop.c polypcore/x11prop.h +libx11prop_la_LDFLAGS = -avoid-version +libx11prop_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) +libx11prop_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) + +# OSS + +liboss_util_la_SOURCES = polypcore/oss-util.c polypcore/oss-util.h +liboss_util_la_LDFLAGS = -avoid-version + +# ALSA + +libalsa_util_la_SOURCES = polypcore/alsa-util.c polypcore/alsa-util.h +libalsa_util_la_LDFLAGS = -avoid-version +libalsa_util_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) +libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) + +# HOWL + +libhowl_wrap_la_SOURCES = polypcore/howl-wrap.c polypcore/howl-wrap.h +libhowl_wrap_la_LDFLAGS = -avoid-version +libhowl_wrap_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) +libhowl_wrap_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) + +################################### +# Plug-in libraries # +################################### + +modlib_LTLIBRARIES += \ + module-cli.la \ + module-cli-protocol-tcp.la \ + module-cli-protocol-tcp6.la \ + module-simple-protocol-tcp.la \ + module-simple-protocol-tcp6.la \ + module-esound-protocol-tcp.la \ + module-esound-protocol-tcp6.la \ + module-native-protocol-tcp.la \ + module-native-protocol-tcp6.la \ + module-native-protocol-fd.la \ + module-sine.la \ + module-combine.la \ + module-tunnel-sink.la \ + module-tunnel-source.la \ + module-null-sink.la \ + module-esound-sink.la \ + module-http-protocol-tcp.la \ + module-http-protocol-tcp6.la \ + module-detect.la + +if HAVE_AF_UNIX +modlib_LTLIBRARIES += \ + module-cli-protocol-unix.la \ + module-simple-protocol-unix.la \ + module-esound-protocol-unix.la \ + module-native-protocol-unix.la \ + module-http-protocol-unix.la +endif + +if HAVE_MKFIFO +modlib_LTLIBRARIES += \ + module-pipe-sink.la \ + module-pipe-source.la +endif + +if !OS_IS_WIN32 +modlib_LTLIBRARIES += \ + module-esound-compat-spawnfd.la \ + module-esound-compat-spawnpid.la +endif + +if HAVE_REGEX +modlib_LTLIBRARIES += \ + module-match.la +endif + +if HAVE_X11 +modlib_LTLIBRARIES += \ + module-x11-bell.la \ + module-x11-publish.la +endif + +if HAVE_OSS +modlib_LTLIBRARIES += \ + module-oss.la \ + module-oss-mmap.la +endif + +if HAVE_ALSA +modlib_LTLIBRARIES += \ + module-alsa-sink.la \ + module-alsa-source.la +endif + +if HAVE_SOLARIS +modlib_LTLIBRARIES += \ + module-solaris.la +endif + +if HAVE_HOWL +modlib_LTLIBRARIES += \ + module-zeroconf-publish.la +endif + +if HAVE_LIRC +modlib_LTLIBRARIES += \ + module-lirc.la +endif + +if HAVE_EVDEV +modlib_LTLIBRARIES += \ + module-mmkbd-evdev.la +endif + +if OS_IS_WIN32 +modlib_LTLIBRARIES += \ + module-waveout.la +endif + +# These are generated by a M4 script + +SYMDEF_FILES = \ + modules/module-cli-symdef.h \ + modules/module-cli-protocol-tcp-symdef.h \ + modules/module-cli-protocol-tcp6-symdef.h \ + modules/module-cli-protocol-unix-symdef.h \ + modules/module-pipe-sink-symdef.h \ + modules/module-pipe-source-symdef.h \ + modules/module-simple-protocol-tcp-symdef.h \ + modules/module-simple-protocol-tcp6-symdef.h \ + modules/module-simple-protocol-unix-symdef.h \ + modules/module-esound-protocol-tcp-symdef.h \ + modules/module-esound-protocol-tcp6-symdef.h \ + modules/module-esound-protocol-unix-symdef.h \ + modules/module-native-protocol-tcp-symdef.h \ + modules/module-native-protocol-tcp6-symdef.h \ + modules/module-native-protocol-unix-symdef.h \ + modules/module-native-protocol-fd-symdef.h \ + modules/module-sine-symdef.h \ + modules/module-combine-symdef.h \ + modules/module-esound-compat-spawnfd-symdef.h \ + modules/module-esound-compat-spawnpid-symdef.h \ + modules/module-match-symdef.h \ + modules/module-tunnel-sink-symdef.h \ + modules/module-tunnel-source-symdef.h \ + modules/module-null-sink-symdef.h \ + modules/module-esound-sink-symdef.h \ + modules/module-zeroconf-publish-symdef.h \ + modules/module-lirc-symdef.h \ + modules/module-mmkbd-evdev-symdef.h \ + modules/module-http-protocol-tcp-symdef.h \ + modules/module-http-protocol-tcp6-symdef.h \ + modules/module-http-protocol-unix-symdef.h \ + modules/module-x11-bell-symdef.h \ + modules/module-x11-publish-symdef.h \ + modules/module-oss-symdef.h \ + modules/module-oss-mmap-symdef.h \ + modules/module-alsa-sink-symdef.h \ + modules/module-alsa-source-symdef.h \ + modules/module-solaris-symdef.h \ + modules/module-waveout-symdef.h \ + modules/module-detect-symdef.h + +EXTRA_DIST += $(SYMDEF_FILES) +BUILT_SOURCES += $(SYMDEF_FILES) + +$(SYMDEF_FILES): modules/module-defs.h.m4 + $(M4) -Dfname="$@" $< > $@ + +# Simple protocol + +module_simple_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c +module_simple_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) +module_simple_protocol_tcp_la_LDFLAGS = -module -avoid-version +module_simple_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-simple.la libsocket-server.la + +module_simple_protocol_tcp6_la_SOURCES = modules/module-protocol-stub.c +module_simple_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) +module_simple_protocol_tcp6_la_LDFLAGS = -module -avoid-version +module_simple_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-simple.la libsocket-server.la + +module_simple_protocol_unix_la_SOURCES = modules/module-protocol-stub.c +module_simple_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) +module_simple_protocol_unix_la_LDFLAGS = -module -avoid-version +module_simple_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-simple.la libsocket-server.la libsocket-util.la + +# CLI protocol + +module_cli_la_SOURCES = modules/module-cli.c +module_cli_la_LDFLAGS = -module -avoid-version +module_cli_la_LIBADD = $(AM_LIBADD) libcli.la libiochannel.la libpolypcore.la + +module_cli_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c +module_cli_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) +module_cli_protocol_tcp_la_LDFLAGS = -module -avoid-version +module_cli_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-cli.la libsocket-server.la + +module_cli_protocol_tcp6_la_SOURCES = modules/module-protocol-stub.c +module_cli_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) +module_cli_protocol_tcp6_la_LDFLAGS = -module -avoid-version +module_cli_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-cli.la libsocket-server.la + +module_cli_protocol_unix_la_SOURCES = modules/module-protocol-stub.c +module_cli_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) +module_cli_protocol_unix_la_LDFLAGS = -module -avoid-version +module_cli_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-cli.la libsocket-server.la libsocket-util.la + +# HTTP protocol + +module_http_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c +module_http_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_CFLAGS) +module_http_protocol_tcp_la_LDFLAGS = -module -avoid-version +module_http_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-http.la libsocket-server.la + +module_http_protocol_tcp6_la_SOURCES = modules/module-protocol-stub.c +module_http_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_CFLAGS) +module_http_protocol_tcp6_la_LDFLAGS = -module -avoid-version +module_http_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-http.la libsocket-server.la + +module_http_protocol_unix_la_SOURCES = modules/module-protocol-stub.c +module_http_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_CFLAGS) +module_http_protocol_unix_la_LDFLAGS = -module -avoid-version +module_http_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-http.la libsocket-server.la libsocket-util.la + +# Native protocol + +module_native_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c +module_native_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) +module_native_protocol_tcp_la_LDFLAGS = -module -avoid-version +module_native_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la + +module_native_protocol_tcp6_la_SOURCES = modules/module-protocol-stub.c +module_native_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) +module_native_protocol_tcp6_la_LDFLAGS = -module -avoid-version +module_native_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la + +module_native_protocol_unix_la_SOURCES = modules/module-protocol-stub.c +module_native_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) +module_native_protocol_unix_la_LDFLAGS = -module -avoid-version +module_native_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la libsocket-util.la + +module_native_protocol_fd_la_SOURCES = modules/module-native-protocol-fd.c +module_native_protocol_fd_la_CFLAGS = $(AM_CFLAGS) +module_native_protocol_fd_la_LDFLAGS = -module -avoid-version +module_native_protocol_fd_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la libsocket-util.la libiochannel.la + +# EsounD protocol + +module_esound_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c +module_esound_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) +module_esound_protocol_tcp_la_LDFLAGS = -module -avoid-version +module_esound_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-esound.la libsocket-server.la + +module_esound_protocol_tcp6_la_SOURCES = modules/module-protocol-stub.c +module_esound_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) +module_esound_protocol_tcp6_la_LDFLAGS = -module -avoid-version +module_esound_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-esound.la libsocket-server.la + +module_esound_protocol_unix_la_SOURCES = modules/module-protocol-stub.c +module_esound_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) +module_esound_protocol_unix_la_LDFLAGS = -module -avoid-version +module_esound_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-esound.la libsocket-server.la libsocket-util.la + +module_esound_compat_spawnfd_la_SOURCES = modules/module-esound-compat-spawnfd.c +module_esound_compat_spawnfd_la_LDFLAGS = -module -avoid-version +module_esound_compat_spawnfd_la_LIBADD = $(AM_LIBADD) libpolypcore.la + +module_esound_compat_spawnpid_la_SOURCES = modules/module-esound-compat-spawnpid.c +module_esound_compat_spawnpid_la_LDFLAGS = -module -avoid-version +module_esound_compat_spawnpid_la_LIBADD = $(AM_LIBADD) libpolypcore.la + +module_esound_sink_la_SOURCES = modules/module-esound-sink.c +module_esound_sink_la_LDFLAGS = -module -avoid-version +module_esound_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la libsocket-client.la libauthkey.la + +# Pipes + +module_pipe_sink_la_SOURCES = modules/module-pipe-sink.c +module_pipe_sink_la_LDFLAGS = -module -avoid-version +module_pipe_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la + +module_pipe_source_la_SOURCES = modules/module-pipe-source.c +module_pipe_source_la_LDFLAGS = -module -avoid-version +module_pipe_source_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la + +# Fake sources/sinks + +module_sine_la_SOURCES = modules/module-sine.c +module_sine_la_LDFLAGS = -module -avoid-version +module_sine_la_LIBADD = $(AM_LIBADD) libpolypcore.la + +module_null_sink_la_SOURCES = modules/module-null-sink.c +module_null_sink_la_LDFLAGS = -module -avoid-version +module_null_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la + +# Couplings + +module_combine_la_SOURCES = modules/module-combine.c +module_combine_la_LDFLAGS = -module -avoid-version +module_combine_la_LIBADD = $(AM_LIBADD) libpolypcore.la + +module_match_la_SOURCES = modules/module-match.c +module_match_la_LDFLAGS = -module -avoid-version +module_match_la_LIBADD = $(AM_LIBADD) libpolypcore.la + +module_tunnel_sink_la_SOURCES = modules/module-tunnel.c +module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS) +module_tunnel_sink_la_LDFLAGS = -module -avoid-version +module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la + +module_tunnel_source_la_SOURCES = modules/module-tunnel.c +module_tunnel_source_la_LDFLAGS = -module -avoid-version +module_tunnel_source_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la + +# X11 + +module_x11_bell_la_SOURCES = modules/module-x11-bell.c +module_x11_bell_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) +module_x11_bell_la_LDFLAGS = -module -avoid-version +module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la + +module_x11_publish_la_SOURCES = modules/module-x11-publish.c +module_x11_publish_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) +module_x11_publish_la_LDFLAGS = -module -avoid-version +module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la libauthkey.la libauthkey-prop.la libx11prop.la libstrlist.la + +# OSS + +module_oss_la_SOURCES = modules/module-oss.c +module_oss_la_LDFLAGS = -module -avoid-version +module_oss_la_LIBADD = $(AM_LIBADD) libiochannel.la liboss-util.la + +module_oss_mmap_la_SOURCES = modules/module-oss-mmap.c +module_oss_mmap_la_LDFLAGS = -module -avoid-version +module_oss_mmap_la_LIBADD = $(AM_LIBADD) liboss-util.la + +# ALSA + +module_alsa_sink_la_SOURCES = modules/module-alsa-sink.c +module_alsa_sink_la_LDFLAGS = -module -avoid-version +module_alsa_sink_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la +module_alsa_sink_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) + +module_alsa_source_la_SOURCES = modules/module-alsa-source.c +module_alsa_source_la_LDFLAGS = -module -avoid-version +module_alsa_source_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la +module_alsa_source_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) + +# Solaris + +module_solaris_la_SOURCES = modules/module-solaris.c +module_solaris_la_LDFLAGS = -module -avoid-version +module_solaris_la_LIBADD = $(AM_LIBADD) libiochannel.la + +# HOWL + +module_zeroconf_publish_la_SOURCES = modules/module-zeroconf-publish.c +module_zeroconf_publish_la_LDFLAGS = -module -avoid-version +module_zeroconf_publish_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) libhowl-wrap.la +module_zeroconf_publish_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) + +# LIRC + +module_lirc_la_SOURCES = modules/module-lirc.c +module_lirc_la_LDFLAGS = -module -avoid-version +module_lirc_la_LIBADD = $(AM_LIBADD) $(LIRC_LIBS) +module_lirc_la_CFLAGS = $(AM_CFLAGS) $(LIRC_CFLAGS) + +# Linux evdev + +module_mmkbd_evdev_la_SOURCES = modules/module-mmkbd-evdev.c +module_mmkbd_evdev_la_LDFLAGS = -module -avoid-version +module_mmkbd_evdev_la_LIBADD = $(AM_LIBADD) +module_mmkbd_evdev_la_CFLAGS = $(AM_CFLAGS) + +# Windows waveout + +module_waveout_la_SOURCES = modules/module-waveout.c +module_waveout_la_LDFLAGS = -module -avoid-version +module_waveout_la_LIBADD = $(AM_LIBADD) libpolypcore.la -lwinmm +module_waveout_la_CFLAGS = $(AM_CFLAGS) + +# Hardware autodetection module +module_detect_la_SOURCES = modules/module-detect.c +module_detect_la_LDFLAGS = -module -avoid-version +module_detect_la_LIBADD = $(AM_LIBADD) +module_detect_la_CFLAGS = $(AM_CFLAGS) + +################################### +# Some minor stuff # +################################### + +suid: polypaudio + chown root $< + chmod u+s $< + +utils/esdcompat.sh: utils/esdcompat.sh.in Makefile + sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ + -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ + -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ + +client.conf: client.conf.in Makefile + sed -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ + +if OS_IS_WIN32 +default.pa: default.pa.win32 + cp $< $@ +else +default.pa: default.pa.in Makefile + sed -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ +endif + +daemon.conf: daemon.conf.in Makefile + sed -e 's,@DLSEARCHPATH\@,$(modlibdir),g' \ + -e 's,@DEFAULT_CONFIG_FILE\@,$(DEFAULT_CONFIG_DIR),g' < $< > $@ + +install-exec-hook: + chown root $(DESTDIR)$(bindir)/polypaudio ; true + chmod u+s $(DESTDIR)$(bindir)/polypaudio + ln -sf pacat $(DESTDIR)$(bindir)/parec diff --git a/src/client.conf.in b/src/client.conf.in new file mode 100644 index 00000000..fbf645a4 --- /dev/null +++ b/src/client.conf.in @@ -0,0 +1,39 @@ +# $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +## Configuration file for polypaudio clients. Default values are +## commented out. Use either ; or # for commenting + +## Path to the polypaudio daemon to run when autospawning. +; daemon-binary = @POLYPAUDIO_BINARY@ + +## Extra arguments to pass to the polypaudio daemon +; extra-arguments = --log-target=syslog --exit-idle-time=5 + +## The default sink to connect to +; default-sink = + +## The default source to connect to +; default-source = + +## The default sever to connect to +; default-server = + +## Autospawn daemons? +; autospawn = 0 diff --git a/src/daemon.conf.in b/src/daemon.conf.in new file mode 100644 index 00000000..d5373018 --- /dev/null +++ b/src/daemon.conf.in @@ -0,0 +1,77 @@ +# $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +## Configuration file for the polypaudio daemon. Default values are +## commented out. Use either ; or # for commenting + +# Extra verbositiy +; verbose = 0 + +## Daemonize after startup +; daemonize = 0 + +## Quit if startup fails +; fail = 1 + +## Renice the daemon to level -15 and try to get SCHED_FIFO +## scheduling. This a good idea if you hear annyoing noise in the +## playback. However, this is a certain security issue, since it works +## when called SUID root only. root is dropped immediately after gaining +## the nice level and SCHED_FIFO scheduling on startup. +; high-priority = 0 + +## Disallow module loading after startup +; disallow-module-loading = 0 + +## Terminate the daemon after the last client quit and this time +## passed. Use a negative value to disable this feature. +; exit-idle-time = -1 + +## Unload autoloaded modules after being idle for this time +; module-idle-time = 20 + +## The path were to look for dynamic shared objects (DSOs aka +## plugins). You may specify more than one path seperated by +## colons. +; dl-search-path = @DLSEARCHPATH@ + +## The default script file to load. Specify an empty string for not +## loading a default script file. The +; default-script-file = @DEFAULT_CONFIG_FILE@ + +## The default log target. Use either "stderr", "syslog" or +## "auto". The latter is equivalent to "sylog" in case daemonize is +## true, otherwise to "stderr". +; log-target = auto + +## The resampling algorithm to use. Use one of src-sinc-best-quality, +## src-sinc-medium-quality, src-sinc-fastest, src-zero-order-hold, +## src-linear, trivial. See the documentation of libsamplerate for an +## explanation for the different methods. The method 'trivial' is the +## only algorithm implemented without usage of floating point +## numbers. If you're tight on CPU consider using this. On the other +## hand it has the worst quality of all. +; resample-method = sinc-fastest + +## Create a PID file in /tmp/polypaudio-$USER/pid. Of this is enabled +## you may use commands like "polypaudio --kill" or "polypaudio +## --check". If you are planning to start more than one polypaudio +## process per user, you better disable this option since it +## effectively disables multiple instances. +; use-pid-file = 1 diff --git a/src/daemon/caps.c b/src/daemon/caps.c new file mode 100644 index 00000000..8d429459 --- /dev/null +++ b/src/daemon/caps.c @@ -0,0 +1,131 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_SYS_CAPABILITY_H +#include +#endif + +#include +#include "caps.h" + +#ifdef HAVE_GETUID + +/* Drop root rights when called SUID root */ +void pa_drop_root(void) { + uid_t uid = getuid(); + + if (uid == 0 || geteuid() != 0) + return; + + pa_log_info(__FILE__": dropping root rights.\n"); + +#if defined(HAVE_SETRESUID) + setresuid(uid, uid, uid); +#elif defined(HAVE_SETREUID) + setreuid(uid, uid); +#else + setuid(uid); + seteuid(uid); +#endif +} + +#else + +void pa_drop_root(void) { +} + +#endif + +#ifdef HAVE_SYS_CAPABILITY_H + +/* Limit capabilities set to CAPSYS_NICE */ +int pa_limit_caps(void) { + int r = -1; + cap_t caps; + cap_value_t nice_cap = CAP_SYS_NICE; + + caps = cap_init(); + assert(caps); + + cap_clear(caps); + + cap_set_flag(caps, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET); + cap_set_flag(caps, CAP_PERMITTED, 1, &nice_cap, CAP_SET); + + if (cap_set_proc(caps) < 0) + goto fail; + + pa_log_info(__FILE__": dropped capabilities successfully.\n"); + + r = 0; + +fail: + cap_free (caps); + + return r; +} + +/* Drop all capabilities, effectively becoming a normal user */ +int pa_drop_caps(void) { + cap_t caps; + int r = -1; + + caps = cap_init(); + assert(caps); + + cap_clear(caps); + + if (cap_set_proc(caps) < 0) { + pa_log(__FILE__": failed to drop capabilities: %s\n", strerror(errno)); + goto fail; + } + + r = 0; + +fail: + cap_free (caps); + + return r; +} + +#else + +/* NOOPs in case capabilities are not available. */ +int pa_limit_caps(void) { + return 0; +} + +int pa_drop_caps(void) { + pa_drop_root(); + return 0; +} + +#endif + diff --git a/src/daemon/caps.h b/src/daemon/caps.h new file mode 100644 index 00000000..3bb861d1 --- /dev/null +++ b/src/daemon/caps.h @@ -0,0 +1,29 @@ +#ifndef foocapshfoo +#define foocapshfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +void pa_drop_root(void); +int pa_limit_caps(void); +int pa_drop_caps(void); + +#endif diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c new file mode 100644 index 00000000..0b5f9ec7 --- /dev/null +++ b/src/daemon/cmdline.c @@ -0,0 +1,300 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "cmdline.h" +#include +#include +#include + +/* Argument codes for getopt_long() */ +enum { + ARG_HELP = 256, + ARG_VERSION, + ARG_DUMP_CONF, + ARG_DUMP_MODULES, + ARG_DAEMONIZE, + ARG_FAIL, + ARG_LOG_LEVEL, + ARG_HIGH_PRIORITY, + ARG_DISALLOW_MODULE_LOADING, + ARG_EXIT_IDLE_TIME, + ARG_MODULE_IDLE_TIME, + ARG_SCACHE_IDLE_TIME, + ARG_LOG_TARGET, + ARG_LOAD, + ARG_FILE, + ARG_DL_SEARCH_PATH, + ARG_RESAMPLE_METHOD, + ARG_KILL, + ARG_USE_PID_FILE, + ARG_CHECK +}; + +/* Tabel for getopt_long() */ +static struct option long_options[] = { + {"help", 0, 0, ARG_HELP}, + {"version", 0, 0, ARG_VERSION}, + {"dump-conf", 0, 0, ARG_DUMP_CONF}, + {"dump-modules", 0, 0, ARG_DUMP_MODULES}, + {"daemonize", 2, 0, ARG_DAEMONIZE}, + {"fail", 2, 0, ARG_FAIL}, + {"verbose", 2, 0, ARG_LOG_LEVEL}, + {"log-level", 2, 0, ARG_LOG_LEVEL}, + {"high-priority", 2, 0, ARG_HIGH_PRIORITY}, + {"disallow-module-loading", 2, 0, ARG_DISALLOW_MODULE_LOADING}, + {"exit-idle-time", 2, 0, ARG_EXIT_IDLE_TIME}, + {"module-idle-time", 2, 0, ARG_MODULE_IDLE_TIME}, + {"scache-idle-time", 2, 0, ARG_SCACHE_IDLE_TIME}, + {"log-target", 1, 0, ARG_LOG_TARGET}, + {"load", 1, 0, ARG_LOAD}, + {"file", 1, 0, ARG_FILE}, + {"dl-search-path", 1, 0, ARG_DL_SEARCH_PATH}, + {"resample-method", 1, 0, ARG_RESAMPLE_METHOD}, + {"kill", 0, 0, ARG_KILL}, + {"use-pid-file", 2, 0, ARG_USE_PID_FILE}, + {"check", 0, 0, ARG_CHECK}, + {NULL, 0, 0, 0} +}; + +void pa_cmdline_help(const char *argv0) { + const char *e; + + if ((e = strrchr(argv0, '/'))) + e++; + else + e = argv0; + + printf("%s [options]\n\n" + "COMMANDS:\n" + " -h, --help Show this help\n" + " --version Show version\n" + " --dump-conf Dump default configuration\n" + " --dump-modules Dump list of available modules\n" + " -k --kill Kill a running daemon\n" + " --check Check for a running daemon\n\n" + + "OPTIONS:\n" + " -D, --daemonize[=BOOL] Daemonize after startup\n" + " --fail[=BOOL] Quit when startup fails\n" + " --high-priority[=BOOL] Try to set high process priority\n" + " (only available as root)\n" + " --disallow-module-loading[=BOOL] Disallow module loading after startup\n" + " --exit-idle-time=SECS Terminate the daemon when idle and this\n" + " time passed\n" + " --module-idle-time=SECS Unload autoloaded modules when idle and\n" + " this time passed\n" + " --scache-idle-time=SECS Unload autoloaded samples when idle and\n" + " this time passed\n" + " --log-level[=LEVEL] Increase or set verbosity level\n" + " -v Increase the verbosity level\n" + " --log-target={auto,syslog,stderr} Specify the log target\n" + " -p, --dl-search-path=PATH Set the search path for dynamic shared\n" + " objects (plugins)\n" + " --resample-method=[METHOD] Use the specified resampling method\n" + " (one of src-sinc-medium-quality,\n" + " src-sinc-best-quality,src-sinc-fastest\n" + " src-zero-order-hold,src-linear,trivial)\n" + " --use-pid-file[=BOOL] Create a PID file\n\n" + + "STARTUP SCRIPT:\n" + " -L, --load=\"MODULE ARGUMENTS\" Load the specified plugin module with\n" + " the specified argument\n" + " -F, --file=FILENAME Run the specified script\n" + " -C Open a command line on the running TTY\n" + " after startup\n\n" + + " -n Don't load default script file\n", e); +} + +int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d) { + pa_strbuf *buf = NULL; + int c; + assert(conf && argc && argv); + + buf = pa_strbuf_new(); + + if (conf->script_commands) + pa_strbuf_puts(buf, conf->script_commands); + + while ((c = getopt_long(argc, argv, "L:F:ChDnp:kv", long_options, NULL)) != -1) { + switch (c) { + case ARG_HELP: + case 'h': + conf->cmd = PA_CMD_HELP; + break; + + case ARG_VERSION: + conf->cmd = PA_CMD_VERSION; + break; + + case ARG_DUMP_CONF: + conf->cmd = PA_CMD_DUMP_CONF; + break; + + case ARG_DUMP_MODULES: + conf->cmd = PA_CMD_DUMP_MODULES; + break; + + case 'k': + case ARG_KILL: + conf->cmd = PA_CMD_KILL; + break; + + case ARG_CHECK: + conf->cmd = PA_CMD_CHECK; + break; + + case ARG_LOAD: + case 'L': + pa_strbuf_printf(buf, "load-module %s\n", optarg); + break; + + case ARG_FILE: + case 'F': + pa_strbuf_printf(buf, ".include %s\n", optarg); + break; + + case 'C': + pa_strbuf_puts(buf, "load-module module-cli\n"); + break; + + case ARG_DAEMONIZE: + case 'D': + if ((conf->daemonize = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + pa_log(__FILE__": --daemonize expects boolean argument\n"); + goto fail; + } + break; + + case ARG_FAIL: + if ((conf->fail = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + pa_log(__FILE__": --fail expects boolean argument\n"); + goto fail; + } + break; + + case 'v': + case ARG_LOG_LEVEL: + + if (optarg) { + if (pa_daemon_conf_set_log_level(conf, optarg) < 0) { + pa_log(__FILE__": --log-level expects log level argument (either numeric in range 0..4 or one of debug, info, notice, warn, error).\n"); + goto fail; + } + } else { + if (conf->log_level < PA_LOG_LEVEL_MAX-1) + conf->log_level++; + } + + break; + + case ARG_HIGH_PRIORITY: + if ((conf->high_priority = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + pa_log(__FILE__": --high-priority expects boolean argument\n"); + goto fail; + } + break; + + case ARG_DISALLOW_MODULE_LOADING: + if ((conf->disallow_module_loading = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + pa_log(__FILE__": --disallow-module-loading expects boolean argument\n"); + goto fail; + } + break; + + case ARG_USE_PID_FILE: + if ((conf->use_pid_file = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + pa_log(__FILE__": --use-pid-file expects boolean argument\n"); + goto fail; + } + break; + + case 'p': + case ARG_DL_SEARCH_PATH: + pa_xfree(conf->dl_search_path); + conf->dl_search_path = *optarg ? pa_xstrdup(optarg) : NULL; + break; + + case 'n': + pa_xfree(conf->default_script_file); + conf->default_script_file = NULL; + break; + + case ARG_LOG_TARGET: + if (pa_daemon_conf_set_log_target(conf, optarg) < 0) { + pa_log(__FILE__": Invalid log target: use either 'syslog', 'stderr' or 'auto'.\n"); + goto fail; + } + break; + + case ARG_EXIT_IDLE_TIME: + conf->exit_idle_time = atoi(optarg); + break; + + case ARG_MODULE_IDLE_TIME: + conf->module_idle_time = atoi(optarg); + break; + + case ARG_SCACHE_IDLE_TIME: + conf->scache_idle_time = atoi(optarg); + break; + + case ARG_RESAMPLE_METHOD: + if (pa_daemon_conf_set_resample_method(conf, optarg) < 0) { + pa_log(__FILE__": Invalid resample method '%s'.\n", optarg); + goto fail; + } + break; + + default: + goto fail; + } + } + + pa_xfree(conf->script_commands); + conf->script_commands = pa_strbuf_tostring_free(buf); + + if (!conf->script_commands) { + pa_xfree(conf->script_commands); + conf->script_commands = NULL; + } + + *d = optind; + + return 0; + +fail: + if (buf) + pa_strbuf_free(buf); + + return -1; +} diff --git a/src/daemon/cmdline.h b/src/daemon/cmdline.h new file mode 100644 index 00000000..e2eaf0d2 --- /dev/null +++ b/src/daemon/cmdline.h @@ -0,0 +1,35 @@ +#ifndef foocmdlinehfoo +#define foocmdlinehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "daemon-conf.h" + +/* Parese the command line and store its data in *c. Return the index + * of the first unparsed argument in *d. */ +int pa_cmdline_parse(pa_daemon_conf*c, int argc, char *const argv [], int *d); + +/* Show the command line help. The command name is extracted from + * argv[0] which should be passed in argv0. */ +void pa_cmdline_help(const char *argv0); + +#endif diff --git a/src/daemon/cpulimit.c b/src/daemon/cpulimit.c new file mode 100644 index 00000000..6887796f --- /dev/null +++ b/src/daemon/cpulimit.c @@ -0,0 +1,236 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "cpulimit.h" +#include +#include + +#ifdef HAVE_SIGXCPU + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif + +/* This module implements a watchdog that makes sure that the current + * process doesn't consume more than 70% CPU time for 10 seconds. This + * is very useful when using SCHED_FIFO scheduling which effectively + * disables multitasking. */ + +/* Method of operation: Using SIGXCPU a signal handler is called every + * 10s process CPU time. That function checks if less than 14s system + * time have passed. In that case, it tries to contact the main event + * loop through a pipe. After two additional seconds it is checked + * whether the main event loop contact was successful. If not, the + * program is terminated forcibly. */ + +/* Utilize this much CPU time at maximum */ +#define CPUTIME_PERCENT 70 + +/* Check every 10s */ +#define CPUTIME_INTERVAL_SOFT (10) + +/* Recheck after 2s */ +#define CPUTIME_INTERVAL_HARD (2) + +/* Time of the last CPU load check */ +static time_t last_time = 0; + +/* Pipe for communicating with the main loop */ +static int the_pipe[2] = {-1, -1}; + +/* Main event loop and IO event for the FIFO */ +static pa_mainloop_api *api = NULL; +static pa_io_event *io_event = NULL; + +/* Saved sigaction struct for SIGXCPU */ +static struct sigaction sigaction_prev; + +/* Nonzero after pa_cpu_limit_init() */ +static int installed = 0; + +/* The current state of operation */ +static enum { + PHASE_IDLE, /* Normal state */ + PHASE_SOFT /* After CPU overload has been detected */ +} phase = PHASE_IDLE; + +/* Reset the SIGXCPU timer to the next t seconds */ +static void reset_cpu_time(int t) { + int r; + long n; + struct rlimit rl; + struct rusage ru; + + /* Get the current CPU time of the current process */ + r = getrusage(RUSAGE_SELF, &ru); + assert(r >= 0); + + n = ru.ru_utime.tv_sec + ru.ru_stime.tv_sec + t; + + r = getrlimit(RLIMIT_CPU, &rl); + assert(r >= 0); + + rl.rlim_cur = n; + r = setrlimit(RLIMIT_CPU, &rl); + assert(r >= 0); +} + +/* A simple, thread-safe puts() work-alike */ +static void write_err(const char *p) { + pa_loop_write(2, p, strlen(p)); +} + +/* The signal handler, called on every SIGXCPU */ +static void signal_handler(int sig) { + assert(sig == SIGXCPU); + + if (phase == PHASE_IDLE) { + time_t now; + +#ifdef PRINT_CPU_LOAD + char t[256]; +#endif + + time(&now); + +#ifdef PRINT_CPU_LOAD + snprintf(t, sizeof(t), "Using %0.1f%% CPU\n", (double)CPUTIME_INTERVAL_SOFT/(now-last_time)*100); + write_err(t); +#endif + + if (CPUTIME_INTERVAL_SOFT >= ((now-last_time)*(double)CPUTIME_PERCENT/100)) { + static const char c = 'X'; + + write_err("Soft CPU time limit exhausted, terminating.\n"); + + /* Try a soft cleanup */ + write(the_pipe[1], &c, sizeof(c)); + phase = PHASE_SOFT; + reset_cpu_time(CPUTIME_INTERVAL_HARD); + + } else { + + /* Everything's fine */ + reset_cpu_time(CPUTIME_INTERVAL_SOFT); + last_time = now; + } + + } else if (phase == PHASE_SOFT) { + write_err("Hard CPU time limit exhausted, terminating forcibly.\n"); + _exit(1); /* Forced exit */ + } +} + +/* Callback for IO events on the FIFO */ +static void callback(pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags f, void *userdata) { + char c; + assert(m && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == the_pipe[0]); + read(the_pipe[0], &c, sizeof(c)); + m->quit(m, 1); /* Quit the main loop */ +} + +/* Initializes CPU load limiter */ +int pa_cpu_limit_init(pa_mainloop_api *m) { + struct sigaction sa; + assert(m && !api && !io_event && the_pipe[0] == -1 && the_pipe[1] == -1 && !installed); + + time(&last_time); + + /* Prepare the main loop pipe */ + if (pipe(the_pipe) < 0) { + pa_log(__FILE__": pipe() failed: %s\n", strerror(errno)); + return -1; + } + + pa_make_nonblock_fd(the_pipe[0]); + pa_make_nonblock_fd(the_pipe[1]); + pa_fd_set_cloexec(the_pipe[0], 1); + pa_fd_set_cloexec(the_pipe[1], 1); + + api = m; + io_event = api->io_new(m, the_pipe[0], PA_IO_EVENT_INPUT, callback, NULL); + + phase = PHASE_IDLE; + + /* Install signal handler for SIGXCPU */ + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = signal_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + + if (sigaction(SIGXCPU, &sa, &sigaction_prev) < 0) { + pa_cpu_limit_done(); + return -1; + } + + installed = 1; + + reset_cpu_time(CPUTIME_INTERVAL_SOFT); + + return 0; +} + +/* Shutdown CPU load limiter */ +void pa_cpu_limit_done(void) { + int r; + + if (io_event) { + assert(api); + api->io_free(io_event); + io_event = NULL; + api = NULL; + } + + if (the_pipe[0] >= 0) + close(the_pipe[0]); + if (the_pipe[1] >= 0) + close(the_pipe[1]); + the_pipe[0] = the_pipe[1] = -1; + + if (installed) { + r = sigaction(SIGXCPU, &sigaction_prev, NULL); + assert(r >= 0); + installed = 0; + } +} + +#else /* HAVE_SIGXCPU */ + +int pa_cpu_limit_init(PA_GCC_UNUSED pa_mainloop_api *m) { + return 0; +} + +void pa_cpu_limit_done(void) { +} + +#endif diff --git a/src/daemon/cpulimit.h b/src/daemon/cpulimit.h new file mode 100644 index 00000000..f3c5534d --- /dev/null +++ b/src/daemon/cpulimit.h @@ -0,0 +1,34 @@ +#ifndef foocpulimithfoo +#define foocpulimithfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +/* This kills the polypaudio process if it eats more than 70% of the + * CPU time. This is build around setrlimit() and SIGXCPU. It is handy + * in case of using SCHED_FIFO which may freeze the whole machine */ + +int pa_cpu_limit_init(pa_mainloop_api *m); +void pa_cpu_limit_done(void); + +#endif diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c new file mode 100644 index 00000000..8fe3c4cc --- /dev/null +++ b/src/daemon/daemon-conf.c @@ -0,0 +1,297 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "daemon-conf.h" +#include +#include +#include +#include +#include + +#ifndef DEFAULT_CONFIG_DIR +# ifndef OS_IS_WIN32 +# define DEFAULT_CONFIG_DIR "/etc/polypaudio" +# else +# define DEFAULT_CONFIG_DIR "%POLYP_ROOT%" +# endif +#endif + +#ifndef OS_IS_WIN32 +# define PATH_SEP "/" +#else +# define PATH_SEP "\\" +#endif + +#define DEFAULT_SCRIPT_FILE DEFAULT_CONFIG_DIR PATH_SEP "default.pa" +#define DEFAULT_SCRIPT_FILE_USER ".polypaudio" PATH_SEP "default.pa" +#define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "daemon.conf" +#define DEFAULT_CONFIG_FILE_USER ".polypaudio" PATH_SEP "daemon.conf" + +#define ENV_SCRIPT_FILE "POLYP_SCRIPT" +#define ENV_CONFIG_FILE "POLYP_CONFIG" +#define ENV_DL_SEARCH_PATH "POLYP_DLPATH" + +static const pa_daemon_conf default_conf = { + .cmd = PA_CMD_DAEMON, + .daemonize = 0, + .fail = 1, + .high_priority = 0, + .disallow_module_loading = 0, + .exit_idle_time = -1, + .module_idle_time = 20, + .scache_idle_time = 20, + .auto_log_target = 1, + .script_commands = NULL, + .dl_search_path = NULL, + .default_script_file = NULL, + .log_target = PA_LOG_SYSLOG, + .log_level = PA_LOG_NOTICE, + .resample_method = PA_RESAMPLER_SRC_SINC_FASTEST, + .config_file = NULL, + .use_pid_file = 1 +}; + +pa_daemon_conf* pa_daemon_conf_new(void) { + FILE *f; + pa_daemon_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); + + if ((f = pa_open_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE, &c->default_script_file))) + fclose(f); + +#ifdef DLSEARCHPATH + c->dl_search_path = pa_xstrdup(DLSEARCHPATH); +#endif + return c; +} + +void pa_daemon_conf_free(pa_daemon_conf *c) { + assert(c); + pa_xfree(c->script_commands); + pa_xfree(c->dl_search_path); + pa_xfree(c->default_script_file); + pa_xfree(c->config_file); + pa_xfree(c); +} + +int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string) { + assert(c && string); + + if (!strcmp(string, "auto")) + c->auto_log_target = 1; + else if (!strcmp(string, "syslog")) { + c->auto_log_target = 0; + c->log_target = PA_LOG_SYSLOG; + } else if (!strcmp(string, "stderr")) { + c->auto_log_target = 0; + c->log_target = PA_LOG_STDERR; + } else + return -1; + + return 0; +} + +int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string) { + uint32_t u; + assert(c && string); + + if (pa_atou(string, &u) >= 0) { + if (u >= PA_LOG_LEVEL_MAX) + return -1; + + c->log_level = (pa_log_level_t) u; + } else if (pa_startswith(string, "debug")) + c->log_level = PA_LOG_DEBUG; + else if (pa_startswith(string, "info")) + c->log_level = PA_LOG_INFO; + else if (pa_startswith(string, "notice")) + c->log_level = PA_LOG_NOTICE; + else if (pa_startswith(string, "warn")) + c->log_level = PA_LOG_WARN; + else if (pa_startswith(string, "err")) + c->log_level = PA_LOG_ERROR; + else + return -1; + + return 0; +} + +int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string) { + int m; + assert(c && string); + + if ((m = pa_parse_resample_method(string)) < 0) + return -1; + + c->resample_method = m; + return 0; +} + +static int parse_log_target(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + pa_daemon_conf *c = data; + assert(filename && lvalue && rvalue && data); + + if (pa_daemon_conf_set_log_target(c, rvalue) < 0) { + pa_log(__FILE__": [%s:%u] Invalid log target '%s'.\n", filename, line, rvalue); + return -1; + } + + return 0; +} + +static int parse_log_level(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + pa_daemon_conf *c = data; + assert(filename && lvalue && rvalue && data); + + if (pa_daemon_conf_set_log_level(c, rvalue) < 0) { + pa_log(__FILE__": [%s:%u] Invalid log level '%s'.\n", filename, line, rvalue); + return -1; + } + + return 0; +} + +static int parse_resample_method(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + pa_daemon_conf *c = data; + assert(filename && lvalue && rvalue && data); + + if (pa_daemon_conf_set_resample_method(c, rvalue) < 0) { + pa_log(__FILE__": [%s:%u] Inavalid resample method '%s'.\n", filename, line, rvalue); + return -1; + } + + return 0; +} + +int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { + int r = -1; + FILE *f = NULL; + + pa_config_item table[] = { + { "daemonize", pa_config_parse_bool, NULL }, + { "fail", pa_config_parse_bool, NULL }, + { "high-priority", pa_config_parse_bool, NULL }, + { "disallow-module-loading", pa_config_parse_bool, NULL }, + { "exit-idle-time", pa_config_parse_int, NULL }, + { "module-idle-time", pa_config_parse_int, NULL }, + { "scache-idle-time", pa_config_parse_int, NULL }, + { "dl-search-path", pa_config_parse_string, NULL }, + { "default-script-file", pa_config_parse_string, NULL }, + { "log-target", parse_log_target, NULL }, + { "log-level", parse_log_level, NULL }, + { "verbose", parse_log_level, NULL }, + { "resample-method", parse_resample_method, NULL }, + { "use-pid-file", pa_config_parse_bool, NULL }, + { NULL, NULL, NULL }, + }; + + table[0].data = &c->daemonize; + table[1].data = &c->fail; + table[2].data = &c->high_priority; + table[3].data = &c->disallow_module_loading; + table[4].data = &c->exit_idle_time; + table[5].data = &c->module_idle_time; + table[6].data = &c->scache_idle_time; + table[7].data = &c->dl_search_path; + table[8].data = &c->default_script_file; + table[9].data = c; + table[10].data = c; + table[11].data = c; + table[12].data = c; + table[13].data = &c->use_pid_file; + + pa_xfree(c->config_file); + c->config_file = NULL; + + f = filename ? + fopen(c->config_file = pa_xstrdup(filename), "r") : + pa_open_config_file(DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file); + + if (!f && errno != ENOENT) { + pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno)); + goto finish; + } + + r = f ? pa_config_parse(c->config_file, f, table, NULL) : 0; + +finish: + if (f) + fclose(f); + + return r; +} + +int pa_daemon_conf_env(pa_daemon_conf *c) { + char *e; + + if ((e = getenv(ENV_DL_SEARCH_PATH))) { + pa_xfree(c->dl_search_path); + c->dl_search_path = pa_xstrdup(e); + } + if ((e = getenv(ENV_SCRIPT_FILE))) { + pa_xfree(c->default_script_file); + c->default_script_file = pa_xstrdup(e); + } + + return 0; +} + +static const char* const log_level_to_string[] = { + [PA_LOG_DEBUG] = "debug", + [PA_LOG_INFO] = "info", + [PA_LOG_NOTICE] = "notice", + [PA_LOG_WARN] = "warning", + [PA_LOG_ERROR] = "error" +}; + +char *pa_daemon_conf_dump(pa_daemon_conf *c) { + pa_strbuf *s = pa_strbuf_new(); + + if (c->config_file) + pa_strbuf_printf(s, "### Read from configuration file: %s ###\n", c->config_file); + + assert(c->log_level <= PA_LOG_LEVEL_MAX); + + pa_strbuf_printf(s, "daemonize = %i\n", !!c->daemonize); + pa_strbuf_printf(s, "fail = %i\n", !!c->fail); + pa_strbuf_printf(s, "high-priority = %i\n", !!c->high_priority); + pa_strbuf_printf(s, "disallow-module-loading = %i\n", !!c->disallow_module_loading); + pa_strbuf_printf(s, "exit-idle-time = %i\n", c->exit_idle_time); + pa_strbuf_printf(s, "module-idle-time = %i\n", c->module_idle_time); + pa_strbuf_printf(s, "scache-idle-time = %i\n", c->scache_idle_time); + pa_strbuf_printf(s, "dl-search-path = %s\n", c->dl_search_path ? c->dl_search_path : ""); + pa_strbuf_printf(s, "default-script-file = %s\n", c->default_script_file); + pa_strbuf_printf(s, "log-target = %s\n", c->auto_log_target ? "auto" : (c->log_target == PA_LOG_SYSLOG ? "syslog" : "stderr")); + pa_strbuf_printf(s, "log-level = %s\n", log_level_to_string[c->log_level]); + pa_strbuf_printf(s, "resample-method = %s\n", pa_resample_method_to_string(c->resample_method)); + pa_strbuf_printf(s, "use-pid-file = %i\n", c->use_pid_file); + + return pa_strbuf_tostring_free(s); +} diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h new file mode 100644 index 00000000..d5131419 --- /dev/null +++ b/src/daemon/daemon-conf.h @@ -0,0 +1,80 @@ +#ifndef foodaemonconfhfoo +#define foodaemonconfhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +/* The actual command to execute */ +typedef enum pa_daemon_conf_cmd { + PA_CMD_DAEMON, /* the default */ + PA_CMD_HELP, + PA_CMD_VERSION, + PA_CMD_DUMP_CONF, + PA_CMD_DUMP_MODULES, + PA_CMD_KILL, + PA_CMD_CHECK +} pa_daemon_conf_cmd_t; + +/* A structure containing configuration data for the Polypaudio server . */ +typedef struct pa_daemon_conf { + pa_daemon_conf_cmd_t cmd; + int daemonize, + fail, + high_priority, + disallow_module_loading, + exit_idle_time, + module_idle_time, + scache_idle_time, + auto_log_target, + use_pid_file; + char *script_commands, *dl_search_path, *default_script_file; + pa_log_target_t log_target; + pa_log_level_t log_level; + int resample_method; + char *config_file; +} pa_daemon_conf; + +/* Allocate a new structure and fill it with sane defaults */ +pa_daemon_conf* pa_daemon_conf_new(void); +void pa_daemon_conf_free(pa_daemon_conf*c); + +/* Load configuration data from the specified file overwriting the + * current settings in *c. If filename is NULL load the default daemon + * configuration file */ +int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename); + +/* Pretty print the current configuration data of the daemon. The + * returned string has to be freed manually. The output of this + * function may be parsed with pa_daemon_conf_load(). */ +char *pa_daemon_conf_dump(pa_daemon_conf *c); + +/* Load the configuration data from the process' environment + * overwriting the current settings in *c. */ +int pa_daemon_conf_env(pa_daemon_conf *c); + +/* Set these configuration variables in the structure by passing a string */ +int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string); +int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string); +int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string); + +#endif diff --git a/src/daemon/dumpmodules.c b/src/daemon/dumpmodules.c new file mode 100644 index 00000000..8d8eb0b9 --- /dev/null +++ b/src/daemon/dumpmodules.c @@ -0,0 +1,99 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "dumpmodules.h" +#include +#include + +#define PREFIX "module-" + +static void short_info(const char *name, PA_GCC_UNUSED const char *path, pa_modinfo *i) { + assert(name && i); + printf("%-40s%s\n", name, i->description ? i->description : "n/a"); +} + +static void long_info(const char *name, const char *path, pa_modinfo *i) { + static int nl = 0; + assert(name && i); + + if (nl) + printf("\n"); + + nl = 1; + + printf("Name: %s\n", name); + + if (!i->description && !i->version && !i->author && !i->usage) + printf("No module information available\n"); + else { + if (i->version) + printf("Version: %s\n", i->version); + if (i->description) + printf("Description: %s\n", i->description); + if (i->author) + printf("Author: %s\n", i->author); + if (i->usage) + printf("Usage: %s\n", i->usage); + } + + if (path) + printf("Path: %s\n", path); +} + +static void show_info(const char *name, const char *path, void (*info)(const char *name, const char *path, pa_modinfo*i)) { + pa_modinfo *i; + + if ((i = pa_modinfo_get_by_name(path ? path : name))) { + info(name, path, i); + pa_modinfo_free(i); + } +} + +static int callback(const char *path, lt_ptr data) { + const char *e; + pa_daemon_conf *c = (data); + + e = pa_path_get_filename(path); + + if (strlen(e) > sizeof(PREFIX)-1 && !strncmp(e, PREFIX, sizeof(PREFIX)-1)) + show_info(e, path, c->log_level >= PA_LOG_INFO ? long_info : short_info); + + return 0; +} + +void pa_dump_modules(pa_daemon_conf *c, int argc, char * const argv[]) { + if (argc > 0) { + int i; + for (i = 0; i < argc; i++) + show_info(argv[i], NULL, long_info); + } else + lt_dlforeachfile(NULL, callback, c); +} diff --git a/src/daemon/dumpmodules.h b/src/daemon/dumpmodules.h new file mode 100644 index 00000000..968d2de9 --- /dev/null +++ b/src/daemon/dumpmodules.h @@ -0,0 +1,31 @@ +#ifndef foodumpmoduleshfoo +#define foodumpmoduleshfoo + +/* $Id*/ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "daemon-conf.h" + +/* Dump all available modules to STDOUT. If argc > 0 print information + * about the modules specified in argv[] instead. */ +void pa_dump_modules(pa_daemon_conf *c, int argc, char * const argv[]); + +#endif diff --git a/src/daemon/main.c b/src/daemon/main.c new file mode 100644 index 00000000..6be83d8c --- /dev/null +++ b/src/daemon/main.c @@ -0,0 +1,472 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#ifdef HAVE_LIBWRAP +#include +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include "cmdline.h" +#include +#include +#include +#include +#include "cpulimit.h" +#include +#include "daemon-conf.h" +#include "dumpmodules.h" +#include "caps.h" +#include +#include +#include + +#ifdef HAVE_LIBWRAP +/* Only one instance of these variables */ +int allow_severity = LOG_INFO; +int deny_severity = LOG_WARNING; +#endif + +#ifdef OS_IS_WIN32 + +static void message_cb(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { + MSG msg; + + while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + if (msg.message == WM_QUIT) + raise(SIGTERM); + else { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } +} + +#endif + +static void signal_callback(pa_mainloop_api*m, PA_GCC_UNUSED pa_signal_event *e, int sig, void *userdata) { + pa_log_info(__FILE__": Got signal %s.\n", pa_strsignal(sig)); + + switch (sig) { +#ifdef SIGUSR1 + case SIGUSR1: + pa_module_load(userdata, "module-cli", NULL); + break; +#endif + +#ifdef SIGUSR2 + case SIGUSR2: + pa_module_load(userdata, "module-cli-protocol-unix", NULL); + break; +#endif + +#ifdef SIGHUP + case SIGHUP: { + char *c = pa_full_status_string(userdata); + pa_log_notice(c); + pa_xfree(c); + return; + } +#endif + + case SIGINT: + case SIGTERM: + default: + pa_log_info(__FILE__": Exiting.\n"); + m->quit(m, 1); + break; + } +} + +static void close_pipe(int p[2]) { + if (p[0] != -1) + close(p[0]); + if (p[1] != -1) + close(p[1]); + p[0] = p[1] = -1; +} + +int main(int argc, char *argv[]) { + pa_core *c; + pa_strbuf *buf = NULL; + pa_daemon_conf *conf; + pa_mainloop *mainloop; + + char *s; + int r, retval = 1, d = 0; + int daemon_pipe[2] = { -1, -1 }; + int suid_root; + int valid_pid_file = 0; + +#ifdef HAVE_GETUID + gid_t gid = (gid_t) -1; +#endif + +#ifdef OS_IS_WIN32 + pa_defer_event *defer; +#endif + + pa_limit_caps(); + +#ifdef HAVE_GETUID + suid_root = getuid() != 0 && geteuid() == 0; + + if (suid_root && (pa_uid_in_group("realtime", &gid) <= 0 || gid >= 1000)) { + pa_log_warn(__FILE__": WARNING: called SUID root, but not in group 'realtime'.\n"); + pa_drop_root(); + } +#else + suid_root = 0; +#endif + + LTDL_SET_PRELOADED_SYMBOLS(); + + r = lt_dlinit(); + assert(r == 0); + +#ifdef OS_IS_WIN32 + { + WSADATA data; + WSAStartup(MAKEWORD(2, 0), &data); + } +#endif + + pa_log_set_ident("polypaudio"); + + conf = pa_daemon_conf_new(); + + if (pa_daemon_conf_load(conf, NULL) < 0) + goto finish; + + if (pa_daemon_conf_env(conf) < 0) + goto finish; + + if (pa_cmdline_parse(conf, argc, argv, &d) < 0) { + pa_log(__FILE__": failed to parse command line.\n"); + goto finish; + } + + pa_log_set_maximal_level(conf->log_level); + pa_log_set_target(conf->auto_log_target ? PA_LOG_STDERR : conf->log_target, NULL); + + if (conf->high_priority && conf->cmd == PA_CMD_DAEMON) + pa_raise_priority(); + + pa_drop_caps(); + + if (suid_root) + pa_drop_root(); + + if (conf->dl_search_path) + lt_dlsetsearchpath(conf->dl_search_path); + + switch (conf->cmd) { + case PA_CMD_DUMP_MODULES: + pa_dump_modules(conf, argc-d, argv+d); + retval = 0; + goto finish; + + case PA_CMD_DUMP_CONF: { + s = pa_daemon_conf_dump(conf); + fputs(s, stdout); + pa_xfree(s); + retval = 0; + goto finish; + } + + case PA_CMD_HELP : + pa_cmdline_help(argv[0]); + retval = 0; + goto finish; + + case PA_CMD_VERSION : + printf(PACKAGE_NAME" "PACKAGE_VERSION"\n"); + retval = 0; + goto finish; + + case PA_CMD_CHECK: { + pid_t pid; + + if (pa_pid_file_check_running(&pid) < 0) { + pa_log_info(__FILE__": daemon not running\n"); + } else { + pa_log_info(__FILE__": daemon running as PID %u\n", pid); + retval = 0; + } + + goto finish; + + } + case PA_CMD_KILL: + + if (pa_pid_file_kill(SIGINT, NULL) < 0) + pa_log(__FILE__": failed to kill daemon.\n"); + else + retval = 0; + + goto finish; + + default: + assert(conf->cmd == PA_CMD_DAEMON); + } + + if (conf->daemonize) { + pid_t child; + int tty_fd; + + if (pa_stdio_acquire() < 0) { + pa_log(__FILE__": failed to acquire stdio.\n"); + goto finish; + } + +#ifdef HAVE_FORK + if (pipe(daemon_pipe) < 0) { + pa_log(__FILE__": failed to create pipe.\n"); + goto finish; + } + + if ((child = fork()) < 0) { + pa_log(__FILE__": fork() failed: %s\n", strerror(errno)); + goto finish; + } + + if (child != 0) { + /* Father */ + + close(daemon_pipe[1]); + daemon_pipe[1] = -1; + + if (pa_loop_read(daemon_pipe[0], &retval, sizeof(retval)) != sizeof(retval)) { + pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + retval = 1; + } + + if (retval) + pa_log(__FILE__": daemon startup failed.\n"); + else + pa_log_info(__FILE__": daemon startup successful.\n"); + + goto finish; + } + + close(daemon_pipe[0]); + daemon_pipe[0] = -1; +#endif + + if (conf->auto_log_target) + pa_log_set_target(PA_LOG_SYSLOG, NULL); + +#ifdef HAVE_SETSID + setsid(); +#endif +#ifdef HAVE_SETPGID + setpgid(0,0); +#endif + +#ifndef OS_IS_WIN32 + close(0); + close(1); + close(2); + + open("/dev/null", O_RDONLY); + open("/dev/null", O_WRONLY); + open("/dev/null", O_WRONLY); +#else + FreeConsole(); +#endif + +#ifdef SIGTTOU + signal(SIGTTOU, SIG_IGN); +#endif +#ifdef SIGTTIN + signal(SIGTTIN, SIG_IGN); +#endif +#ifdef SIGTSTP + signal(SIGTSTP, SIG_IGN); +#endif + +#ifdef TIOCNOTTY + if ((tty_fd = open("/dev/tty", O_RDWR)) >= 0) { + ioctl(tty_fd, TIOCNOTTY, (char*) 0); + close(tty_fd); + } +#endif + } + + chdir("/"); + + if (conf->use_pid_file) { + if (pa_pid_file_create() < 0) { + pa_log(__FILE__": pa_pid_file_create() failed.\n"); +#ifdef HAVE_FORK + if (conf->daemonize) + pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); +#endif + goto finish; + } + + valid_pid_file = 1; + } + + mainloop = pa_mainloop_new(); + assert(mainloop); + + c = pa_core_new(pa_mainloop_get_api(mainloop)); + assert(c); + + r = pa_signal_init(pa_mainloop_get_api(mainloop)); + assert(r == 0); + pa_signal_new(SIGINT, signal_callback, c); + pa_signal_new(SIGTERM, signal_callback, c); +#ifdef SIGPIPE + signal(SIGPIPE, SIG_IGN); +#endif + +#ifdef OS_IS_WIN32 + defer = pa_mainloop_get_api(mainloop)->defer_new(pa_mainloop_get_api(mainloop), message_cb, NULL); + assert(defer); +#endif + + if (conf->daemonize) + c->running_as_daemon = 1; + +#ifdef SIGUSR1 + pa_signal_new(SIGUSR1, signal_callback, c); +#endif +#ifdef SIGUSR2 + pa_signal_new(SIGUSR2, signal_callback, c); +#endif +#ifdef SIGHUP + pa_signal_new(SIGHUP, signal_callback, c); +#endif + + oil_init(); + + r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop)); + assert(r == 0); + + buf = pa_strbuf_new(); + assert(buf); + if (conf->default_script_file) + r = pa_cli_command_execute_file(c, conf->default_script_file, buf, &conf->fail); + + if (r >= 0) + r = pa_cli_command_execute(c, conf->script_commands, buf, &conf->fail); + pa_log(s = pa_strbuf_tostring_free(buf)); + pa_xfree(s); + + if (r < 0 && conf->fail) { + pa_log(__FILE__": failed to initialize daemon.\n"); +#ifdef HAVE_FORK + if (conf->daemonize) + pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); +#endif + } else if (!c->modules || pa_idxset_size(c->modules) == 0) { + pa_log(__FILE__": daemon startup without any loaded modules, refusing to work.\n"); +#ifdef HAVE_FORK + if (conf->daemonize) + pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); +#endif + } else { + + retval = 0; +#ifdef HAVE_FORK + if (conf->daemonize) + pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); +#endif + + c->disallow_module_loading = conf->disallow_module_loading; + c->exit_idle_time = conf->exit_idle_time; + c->module_idle_time = conf->module_idle_time; + c->scache_idle_time = conf->scache_idle_time; + c->resample_method = conf->resample_method; + + if (c->default_sink_name && + pa_namereg_get(c, c->default_sink_name, PA_NAMEREG_SINK, 1) == NULL) { + pa_log_error("%s : Fatal error. Default sink name (%s) does not exist in name register.\n", __FILE__, c->default_sink_name); + retval = 1; + } else { + pa_log_info(__FILE__": Daemon startup complete.\n"); + if (pa_mainloop_run(mainloop, &retval) < 0) + retval = 1; + pa_log_info(__FILE__": Daemon shutdown initiated.\n"); + } + } + +#ifdef OS_IS_WIN32 + pa_mainloop_get_api(mainloop)->defer_free(defer); +#endif + + pa_core_free(c); + + pa_cpu_limit_done(); + pa_signal_done(); + pa_mainloop_free(mainloop); + + pa_log_info(__FILE__": Daemon terminated.\n"); + +finish: + + if (conf) + pa_daemon_conf_free(conf); + + if (valid_pid_file) + pa_pid_file_remove(); + + close_pipe(daemon_pipe); + +#ifdef OS_IS_WIN32 + WSACleanup(); +#endif + + lt_dlexit(); + + return retval; +} diff --git a/src/default.pa.in b/src/default.pa.in new file mode 100755 index 00000000..3aaeeaf0 --- /dev/null +++ b/src/default.pa.in @@ -0,0 +1,66 @@ +#!@POLYPAUDIO_BINARY@ -nF + +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with polypaudio; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + + +# Load audio drivers statically + +#load-module module-alsa-sink +# load-module module-alsa-source device=plughw:1,0 +load-module module-oss device="/dev/dsp" sink_name=output source_name=input +#load-module module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +load-module module-null-sink +#load-module module-pipe-sink + +# Load audio drivers automatically on access + +#add-autoload-sink output module-oss device="/dev/dsp" sink_name=output source_name=input +#add-autoload-source input module-oss device="/dev/dsp" sink_name=output source_name=input +#add-autoload-sink output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#add-autoload-source input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#add-autoload-sink output module-alsa-sink sink_name=output +#add-autoload-source input module-alsa-source source_name=input + +# Load several protocols +load-module module-esound-protocol-unix +#load-module module-esound-protocol-tcp +load-module module-native-protocol-unix +#load-module module-simple-protocol-tcp +#load-module module-cli-protocol-unix + +# Load the CLI module +load-module module-cli + +# Make some devices default +set-default-sink output +set-default-source input + +.nofail + +# Load something to the sample cache +load-sample x11-bell /usr/share/sounds/KDE_Notify.wav +load-sample-dir-lazy /usr/share/sounds/*.wav + +# Load X11 bell module +load-module module-x11-bell sample=x11-bell sink=output + +# Publish connection data in the X11 root window +load-module module-x11-publish + +#load-module module-pipe-source +#load-module module-pipe-sink diff --git a/src/default.pa.win32 b/src/default.pa.win32 new file mode 100644 index 00000000..3478adab --- /dev/null +++ b/src/default.pa.win32 @@ -0,0 +1,43 @@ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with polypaudio; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + + +# Load audio drivers statically + +load-module module-waveout sink_name=output source_name=input +load-module module-null-sink + +# Load audio drivers automatically on access + +#add-autoload-sink output module-waveout sink_name=output source_name=input +#add-autoload-source input module-waveout sink_name=output source_name=input + +# Load several protocols +#load-module module-esound-protocol-tcp +#load-module module-native-protocol-tcp +#load-module module-simple-protocol-tcp +#load-module module-cli-protocol-tcp + +# Make some devices default +set-default-sink output +set-default-source input + +.nofail + +# Load something to the sample cache +load-sample x11-bell %WINDIR%\Media\ding.wav +load-sample-dir-lazy %WINDIR%\Media\*.wav diff --git a/src/depmod.py b/src/depmod.py new file mode 100755 index 00000000..7bb223b1 --- /dev/null +++ b/src/depmod.py @@ -0,0 +1,73 @@ +#!/usr/bin/python +# $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +import sys, os, string + +exported_symbols = {} +imported_symbols = {} + +for fn in sys.argv[1:]: + f = os.popen("nm '%s'" % fn, "r") + + imported_symbols[fn] = [] + + for line in f: + sym_address = line[:7].strip() + sym_type = line[9].strip() + sym_name = line[11:].strip() + + if sym_name in ('_fini', '_init'): + continue + + if sym_type in ('T', 'B', 'R', 'D' 'G', 'S', 'D'): + if exported_symbols.has_key(sym_name): + sys.stderr.write("CONFLICT: %s defined in both '%s' and '%s'.\n" % (sym_name, fn, exported_symbols[sym_name])) + else: + exported_symbols[sym_name] = fn + elif sym_type in ('U',): + if sym_name[:3] == 'pa_': + imported_symbols[fn].append(sym_name) + + f.close() + +dependencies = {} +unresolved_symbols = {} + +for fn in imported_symbols: + dependencies[fn] = [] + + for sym in imported_symbols[fn]: + if exported_symbols.has_key(sym): + if exported_symbols[sym] not in dependencies[fn]: + dependencies[fn].append(exported_symbols[sym]) + else: + if unresolved_symbols.has_key(sym): + unresolved_symbols[sym].append(fn) + else: + unresolved_symbols[sym] = [fn] + +for sym, files in unresolved_symbols.iteritems(): + print "WARNING: Unresolved symbol '%s' in %s" % (sym, `files`) + +k = dependencies.keys() +k.sort() +for fn in k: + dependencies[fn].sort() + print "%s: %s" % (fn, string.join(dependencies[fn], " ")) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c new file mode 100644 index 00000000..48e90e9f --- /dev/null +++ b/src/modules/module-alsa-sink.c @@ -0,0 +1,292 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#ifdef HAVE_SYS_POLL_H +#include +#else +#include "poll.h" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-alsa-sink-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("ALSA Sink") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink_name= device= format= channels= rate= fragments= fragment_size=") + +struct userdata { + snd_pcm_t *pcm_handle; + pa_sink *sink; + pa_io_event **io_events; + unsigned n_io_events; + + size_t frame_size, fragment_size; + pa_memchunk memchunk, silence; + pa_module *module; +}; + +static const char* const valid_modargs[] = { + "device", + "sink_name", + "format", + "channels", + "rate", + "fragments", + "fragment_size", + NULL +}; + +#define DEFAULT_SINK_NAME "alsa_output" +#define DEFAULT_DEVICE "default" + +static void update_usage(struct userdata *u) { + pa_module_set_used(u->module, + (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0)); +} + +static void xrun_recovery(struct userdata *u) { + assert(u); + + pa_log(__FILE__": *** ALSA-XRUN (playback) ***\n"); + + if (snd_pcm_prepare(u->pcm_handle) < 0) + pa_log(__FILE__": snd_pcm_prepare() failed\n"); +} + +static void do_write(struct userdata *u) { + assert(u); + + update_usage(u); + + for (;;) { + pa_memchunk *memchunk = NULL; + snd_pcm_sframes_t frames; + + if (u->memchunk.memblock) + memchunk = &u->memchunk; + else { + if (pa_sink_render(u->sink, u->fragment_size, &u->memchunk) < 0) + memchunk = &u->silence; + else + memchunk = &u->memchunk; + } + + assert(memchunk->memblock && memchunk->memblock->data && memchunk->length && memchunk->memblock->length && (memchunk->length % u->frame_size) == 0); + + if ((frames = snd_pcm_writei(u->pcm_handle, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length / u->frame_size)) < 0) { + if (frames == -EAGAIN) + return; + + if (frames == -EPIPE) { + xrun_recovery(u); + continue; + } + + pa_log(__FILE__": snd_pcm_writei() failed\n"); + return; + } + + if (memchunk == &u->memchunk) { + size_t l = frames * u->frame_size; + memchunk->index += l; + memchunk->length -= l; + + if (memchunk->length == 0) { + pa_memblock_unref(memchunk->memblock); + memchunk->memblock = NULL; + memchunk->index = memchunk->length = 0; + } + } + + break; + } +} + +static void io_callback(pa_mainloop_api*a, pa_io_event *e, PA_GCC_UNUSED int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { + struct userdata *u = userdata; + assert(u && a && e); + + if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) + xrun_recovery(u); + + do_write(u); +} + +static pa_usec_t sink_get_latency_cb(pa_sink *s) { + pa_usec_t r = 0; + struct userdata *u = s->userdata; + snd_pcm_sframes_t frames; + assert(s && u && u->sink); + + if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { + pa_log(__FILE__": failed to get delay\n"); + s->get_latency = NULL; + return 0; + } + + if (frames < 0) + frames = 0; + + r += pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec); + + if (u->memchunk.memblock) + r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec); + + return r; +} + +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; + int ret = -1; + struct userdata *u = NULL; + const char *dev; + pa_sample_spec ss; + uint32_t periods, fragsize; + snd_pcm_uframes_t period_size; + size_t frame_size; + int err; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": failed to parse sample specification\n"); + goto fail; + } + frame_size = pa_frame_size(&ss); + + periods = 8; + fragsize = 1024; + if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { + pa_log(__FILE__": failed to parse buffer metrics\n"); + goto fail; + } + period_size = fragsize; + + u = pa_xmalloc0(sizeof(struct userdata)); + m->userdata = u; + u->module = m; + + snd_config_update_free_global(); + if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { + pa_log(__FILE__": Error opening PCM device %s: %s\n", dev, snd_strerror(err)); + goto fail; + } + + if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) { + pa_log(__FILE__": Failed to set hardware parameters: %s\n", snd_strerror(err)); + goto fail; + } + + u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); + assert(u->sink); + + u->sink->get_latency = sink_get_latency_cb; + u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); + + if (pa_create_io_events(u->pcm_handle, c->mainloop, &u->io_events, &u->n_io_events, io_callback, u) < 0) { + pa_log(__FILE__": failed to obtain file descriptors\n"); + goto fail; + } + + u->frame_size = frame_size; + u->fragment_size = period_size; + + pa_log_info(__FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); + + u->silence.memblock = pa_memblock_new(u->silence.length = u->fragment_size, c->memblock_stat); + assert(u->silence.memblock); + pa_silence_memblock(u->silence.memblock, &ss); + u->silence.index = 0; + + u->memchunk.memblock = NULL; + u->memchunk.index = u->memchunk.length = 0; + + ret = 0; + +finish: + if (ma) + pa_modargs_free(ma); + + return ret; + +fail: + + if (u) + pa__done(c, m); + + goto finish; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + } + + if (u->io_events) + pa_free_io_events(c->mainloop, u->io_events, u->n_io_events); + + if (u->pcm_handle) { + snd_pcm_drop(u->pcm_handle); + snd_pcm_close(u->pcm_handle); + } + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + if (u->silence.memblock) + pa_memblock_unref(u->silence.memblock); + + pa_xfree(u); +} + diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c new file mode 100644 index 00000000..f03e51ad --- /dev/null +++ b/src/modules/module-alsa-source.c @@ -0,0 +1,278 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#ifdef HAVE_SYS_POLL_H +#include +#else +#include "poll.h" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-alsa-source-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("ALSA Source") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("source_name= device= format= channels= rate= fragments= fragment_size=") + +struct userdata { + snd_pcm_t *pcm_handle; + pa_source *source; + pa_io_event **io_events; + unsigned n_io_events; + + size_t frame_size, fragment_size; + pa_memchunk memchunk; + pa_module *module; +}; + +static const char* const valid_modargs[] = { + "device", + "source_name", + "channels", + "rate", + "format", + "fragments", + "fragment_size", + NULL +}; + +#define DEFAULT_SOURCE_NAME "alsa_input" +#define DEFAULT_DEVICE "hw:0,0" + +static void update_usage(struct userdata *u) { + pa_module_set_used(u->module, + (u->source ? pa_idxset_size(u->source->outputs) : 0)); +} + +static void xrun_recovery(struct userdata *u) { + assert(u); + + pa_log(__FILE__": *** ALSA-XRUN (capture) ***\n"); + + if (snd_pcm_prepare(u->pcm_handle) < 0) + pa_log(__FILE__": snd_pcm_prepare() failed\n"); +} + +static void do_read(struct userdata *u) { + assert(u); + + update_usage(u); + + for (;;) { + pa_memchunk post_memchunk; + snd_pcm_sframes_t frames; + size_t l; + + if (!u->memchunk.memblock) { + u->memchunk.memblock = pa_memblock_new(u->memchunk.length = u->fragment_size, u->source->core->memblock_stat); + u->memchunk.index = 0; + } + + assert(u->memchunk.memblock && u->memchunk.memblock->data && u->memchunk.length && u->memchunk.memblock->length && (u->memchunk.length % u->frame_size) == 0); + + if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { + if (frames == -EAGAIN) + return; + + if (frames == -EPIPE) { + xrun_recovery(u); + continue; + } + + pa_log(__FILE__": snd_pcm_readi() failed: %s\n", strerror(-frames)); + return; + } + + l = frames * u->frame_size; + + post_memchunk = u->memchunk; + post_memchunk.length = l; + + pa_source_post(u->source, &post_memchunk); + + u->memchunk.index += l; + u->memchunk.length -= l; + + if (u->memchunk.length == 0) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + u->memchunk.index = u->memchunk.length = 0; + } + + break; + } +} + +static void io_callback(pa_mainloop_api*a, pa_io_event *e, PA_GCC_UNUSED int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { + struct userdata *u = userdata; + assert(u && a && e); + + if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) + xrun_recovery(u); + + do_read(u); +} + +static pa_usec_t source_get_latency_cb(pa_source *s) { + struct userdata *u = s->userdata; + snd_pcm_sframes_t frames; + assert(s && u && u->source); + + if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { + pa_log(__FILE__": failed to get delay\n"); + s->get_latency = NULL; + return 0; + } + + return pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec); +} + +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; + int ret = -1; + struct userdata *u = NULL; + const char *dev; + pa_sample_spec ss; + unsigned periods, fragsize; + snd_pcm_uframes_t period_size; + size_t frame_size; + int err; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": failed to parse sample specification\n"); + goto fail; + } + frame_size = pa_frame_size(&ss); + + periods = 12; + fragsize = 1024; + if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { + pa_log(__FILE__": failed to parse buffer metrics\n"); + goto fail; + } + period_size = fragsize; + + u = pa_xmalloc0(sizeof(struct userdata)); + m->userdata = u; + u->module = m; + + snd_config_update_free_global(); + if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { + pa_log(__FILE__": Error opening PCM device %s: %s\n", dev, snd_strerror(err)); + goto fail; + } + + if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) { + pa_log(__FILE__": Failed to set hardware parameters: %s\n", snd_strerror(err)); + goto fail; + } + + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); + assert(u->source); + + u->source->userdata = u; + u->source->get_latency = source_get_latency_cb; + pa_source_set_owner(u->source, m); + u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); + + if (pa_create_io_events(u->pcm_handle, c->mainloop, &u->io_events, &u->n_io_events, io_callback, u) < 0) { + pa_log(__FILE__": failed to obtain file descriptors\n"); + goto fail; + } + + u->frame_size = frame_size; + u->fragment_size = period_size; + + pa_log(__FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); + + u->memchunk.memblock = NULL; + u->memchunk.index = u->memchunk.length = 0; + + snd_pcm_start(u->pcm_handle); + + ret = 0; + +finish: + if (ma) + pa_modargs_free(ma); + + return ret; + +fail: + + if (u) + pa__done(c, m); + + goto finish; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + } + + if (u->io_events) + pa_free_io_events(c->mainloop, u->io_events, u->n_io_events); + + if (u->pcm_handle) { + snd_pcm_drop(u->pcm_handle); + snd_pcm_close(u->pcm_handle); + } + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + + pa_xfree(u); +} + diff --git a/src/modules/module-cli.c b/src/modules/module-cli.c new file mode 100644 index 00000000..c782ff8d --- /dev/null +++ b/src/modules/module-cli.c @@ -0,0 +1,88 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "module-cli-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Command line interface") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("No arguments") + +static void eof_cb(pa_cli*c, void *userdata) { + pa_module *m = userdata; + assert(c && m); + + pa_module_unload_request(m); +} + +int pa__init(pa_core *c, pa_module*m) { + pa_iochannel *io; + assert(c && m); + + if (c->running_as_daemon) { + pa_log_info(__FILE__": Running as daemon so won't load this module.\n"); + return 0; + } + + if (m->argument) { + pa_log(__FILE__": module doesn't accept arguments.\n"); + return -1; + } + + if (pa_stdio_acquire() < 0) { + pa_log(__FILE__": STDIN/STDUSE already in use.\n"); + return -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, m); + assert(m->userdata); + + pa_cli_set_eof_callback(m->userdata, eof_cb, m); + + return 0; +} + +void pa__done(pa_core *c, pa_module*m) { + assert(c && m); + + if (c->running_as_daemon == 0) { + pa_cli_free(m->userdata); + pa_stdio_release(); + } +} diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c new file mode 100644 index 00000000..aabb8f28 --- /dev/null +++ b/src/modules/module-combine.c @@ -0,0 +1,394 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-combine-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Combine multiple sinks to one") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink_name= master= slaves= adjust_time= resample_method=") + +#define DEFAULT_SINK_NAME "combined" +#define MEMBLOCKQ_MAXLENGTH (1024*170) +#define RENDER_SIZE (1024*10) + +#define DEFAULT_ADJUST_TIME 20 + +static const char* const valid_modargs[] = { + "sink_name", + "master", + "slaves", + "adjust_time", + "resample_method", + NULL +}; + +struct output { + struct userdata *userdata; + pa_sink_input *sink_input; + size_t counter; + pa_memblockq *memblockq; + pa_usec_t total_latency; + PA_LLIST_FIELDS(struct output); +}; + +struct userdata { + pa_module *module; + pa_core *core; + pa_sink *sink; + unsigned n_outputs; + struct output *master; + pa_time_event *time_event; + uint32_t adjust_time; + + PA_LLIST_HEAD(struct output, outputs); +}; + +static void output_free(struct output *o); +static void clear_up(struct userdata *u); + +static void update_usage(struct userdata *u) { + pa_module_set_used(u->module, + (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0)); +} + + +static void adjust_rates(struct userdata *u) { + struct output *o; + pa_usec_t max_sink_latency = 0, min_total_latency = (pa_usec_t) -1, target_latency; + uint32_t base_rate; + assert(u && u->sink); + + for (o = u->outputs; o; o = o->next) { + uint32_t sink_latency = o->sink_input->sink ? pa_sink_get_latency(o->sink_input->sink) : 0; + + o->total_latency = sink_latency + pa_sink_input_get_latency(o->sink_input); + + if (sink_latency > max_sink_latency) + max_sink_latency = sink_latency; + + if (o->total_latency < min_total_latency) + min_total_latency = o->total_latency; + } + + assert(min_total_latency != (pa_usec_t) -1); + + target_latency = max_sink_latency > min_total_latency ? max_sink_latency : min_total_latency; + + pa_log_info(__FILE__": [%s] target latency is %0.0f usec.\n", u->sink->name, (float) target_latency); + + base_rate = u->sink->sample_spec.rate; + + for (o = u->outputs; o; o = o->next) { + uint32_t r = base_rate; + + if (o->total_latency < target_latency) + r -= (uint32_t) (((((double) target_latency - o->total_latency))/u->adjust_time)*r/ 1000000); + else if (o->total_latency > target_latency) + r += (uint32_t) (((((double) o->total_latency - target_latency))/u->adjust_time)*r/ 1000000); + + if (r < (uint32_t) (base_rate*0.9) || r > (uint32_t) (base_rate*1.1)) + pa_log_warn(__FILE__": [%s] sample rates too different, not adjusting (%u vs. %u).\n", o->sink_input->name, base_rate, r); + else { + pa_log_info(__FILE__": [%s] new rate is %u Hz; ratio is %0.3f; latency is %0.0f usec.\n", o->sink_input->name, r, (double) r / base_rate, (float) o->total_latency); + pa_sink_input_set_rate(o->sink_input, r); + } + } +} + +static void request_memblock(struct userdata *u) { + pa_memchunk chunk; + struct output *o; + assert(u && u->sink); + + update_usage(u); + + if (pa_sink_render(u->sink, RENDER_SIZE, &chunk) < 0) + return; + + for (o = u->outputs; o; o = o->next) + pa_memblockq_push_align(o->memblockq, &chunk, 0); + + pa_memblock_unref(chunk.memblock); +} + +static void time_callback(pa_mainloop_api*a, pa_time_event* e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + struct userdata *u = userdata; + struct timeval n; + assert(u && a && u->time_event == e); + + adjust_rates(u); + + pa_gettimeofday(&n); + n.tv_sec += u->adjust_time; + u->sink->core->mainloop->time_restart(e, &n); +} + +static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { + struct output *o = i->userdata; + assert(i && o && o->sink_input && chunk); + + if (pa_memblockq_peek(o->memblockq, chunk) >= 0) + return 0; + + /* Try harder */ + request_memblock(o->userdata); + + return pa_memblockq_peek(o->memblockq, chunk); +} + +static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { + struct output *o = i->userdata; + assert(i && o && o->sink_input && chunk && length); + + pa_memblockq_drop(o->memblockq, chunk, length); + o->counter += length; +} + +static void sink_input_kill_cb(pa_sink_input *i) { + struct output *o = i->userdata; + assert(i && o && o->sink_input); + pa_module_unload_request(o->userdata->module); + clear_up(o->userdata); +} + +static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { + struct output *o = i->userdata; + assert(i && o && o->sink_input); + + return pa_bytes_to_usec(pa_memblockq_get_length(o->memblockq), &i->sample_spec); +} + +static pa_usec_t sink_get_latency_cb(pa_sink *s) { + struct userdata *u = s->userdata; + assert(s && u && u->sink && u->master); + + return pa_sink_input_get_latency(u->master->sink_input); +} + +static struct output *output_new(struct userdata *u, pa_sink *sink, int resample_method) { + struct output *o = NULL; + char t[256]; + assert(u && sink && u->sink); + + o = pa_xmalloc(sizeof(struct output)); + o->userdata = u; + + o->counter = 0; + o->memblockq = pa_memblockq_new(MEMBLOCKQ_MAXLENGTH, MEMBLOCKQ_MAXLENGTH, pa_frame_size(&u->sink->sample_spec), 0, 0, sink->core->memblock_stat); + + snprintf(t, sizeof(t), "%s: output #%u", u->sink->name, u->n_outputs+1); + if (!(o->sink_input = pa_sink_input_new(sink, __FILE__, t, &u->sink->sample_spec, &u->sink->channel_map, 1, resample_method))) + goto fail; + + o->sink_input->get_latency = sink_input_get_latency_cb; + o->sink_input->peek = sink_input_peek_cb; + o->sink_input->drop = sink_input_drop_cb; + o->sink_input->kill = sink_input_kill_cb; + o->sink_input->userdata = o; + o->sink_input->owner = u->module; + + PA_LLIST_PREPEND(struct output, u->outputs, o); + u->n_outputs++; + return o; + +fail: + + if (o) { + if (o->sink_input) { + pa_sink_input_disconnect(o->sink_input); + pa_sink_input_unref(o->sink_input); + } + + if (o->memblockq) + pa_memblockq_free(o->memblockq); + + pa_xfree(o); + } + + return NULL; +} + +static void output_free(struct output *o) { + assert(o); + PA_LLIST_REMOVE(struct output, o->userdata->outputs, o); + o->userdata->n_outputs--; + pa_memblockq_free(o->memblockq); + pa_sink_input_disconnect(o->sink_input); + pa_sink_input_unref(o->sink_input); + pa_xfree(o); +} + +static void clear_up(struct userdata *u) { + struct output *o; + assert(u); + + if (u->time_event) { + u->core->mainloop->time_free(u->time_event); + u->time_event = NULL; + } + + while ((o = u->outputs)) + output_free(o); + + u->master = NULL; + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + u->sink = NULL; + } +} + +int pa__init(pa_core *c, pa_module*m) { + struct userdata *u; + pa_modargs *ma = NULL; + const char *master_name, *slaves, *rm; + pa_sink *master_sink; + char *n = NULL; + const char*split_state; + struct timeval tv; + int resample_method = -1; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments\n"); + goto fail; + } + + if ((rm = pa_modargs_get_value(ma, "resample_method", NULL))) { + if ((resample_method = pa_parse_resample_method(rm)) < 0) { + pa_log(__FILE__": invalid resample method '%s'\n", rm); + goto fail; + } + } + + u = pa_xmalloc(sizeof(struct userdata)); + m->userdata = u; + u->sink = NULL; + u->n_outputs = 0; + u->master = NULL; + u->module = m; + u->core = c; + u->time_event = NULL; + u->adjust_time = DEFAULT_ADJUST_TIME; + PA_LLIST_HEAD_INIT(struct output, u->outputs); + + if (pa_modargs_get_value_u32(ma, "adjust_time", &u->adjust_time) < 0) { + pa_log(__FILE__": failed to parse adjust_time value\n"); + goto fail; + } + + if (!(master_name = pa_modargs_get_value(ma, "master", NULL)) || !(slaves = pa_modargs_get_value(ma, "slaves", NULL))) { + pa_log(__FILE__": no master or slave sinks specified\n"); + goto fail; + } + + if (!(master_sink = pa_namereg_get(c, master_name, PA_NAMEREG_SINK, 1))) { + pa_log(__FILE__": invalid master sink '%s'\n", master_name); + goto fail; + } + + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &master_sink->sample_spec, &master_sink->channel_map))) { + pa_log(__FILE__": failed to create sink\n"); + goto fail; + } + + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Combined sink"); + u->sink->get_latency = sink_get_latency_cb; + u->sink->userdata = u; + + if (!(u->master = output_new(u, master_sink, resample_method))) { + pa_log(__FILE__": failed to create master sink input on sink '%s'.\n", u->sink->name); + goto fail; + } + + split_state = NULL; + while ((n = pa_split(slaves, ",", &split_state))) { + pa_sink *slave_sink; + + if (!(slave_sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) { + pa_log(__FILE__": invalid slave sink '%s'\n", n); + goto fail; + } + + pa_xfree(n); + + if (!output_new(u, slave_sink, resample_method)) { + pa_log(__FILE__": failed to create slave sink input on sink '%s'.\n", slave_sink->name); + goto fail; + } + } + + if (u->n_outputs <= 1) + pa_log_warn(__FILE__": WARNING: no slave sinks specified.\n"); + + if (u->adjust_time > 0) { + pa_gettimeofday(&tv); + tv.tv_sec += u->adjust_time; + u->time_event = c->mainloop->time_new(c->mainloop, &tv, time_callback, u); + } + + pa_modargs_free(ma); + return 0; + +fail: + pa_xfree(n); + + if (ma) + pa_modargs_free(ma); + + pa__done(c, m); + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + clear_up(u); + pa_xfree(u); +} + + diff --git a/src/modules/module-defs.h.m4 b/src/modules/module-defs.h.m4 new file mode 100644 index 00000000..8f10d659 --- /dev/null +++ b/src/modules/module-defs.h.m4 @@ -0,0 +1,29 @@ +dnl $Id$ +changecom(`/*', `*/')dnl +define(`module_name', patsubst(patsubst(patsubst(fname, `-symdef.h$'), `^.*/'), `[^0-9a-zA-Z]', `_'))dnl +define(`c_symbol', patsubst(module_name, `[^0-9a-zA-Z]', `_'))dnl +define(`c_macro', patsubst(module_name, `[^0-9a-zA-Z]', `'))dnl +define(`incmacro', `foo'c_macro`symdeffoo')dnl +define(`gen_symbol', `#define $1 'module_name`_LTX_$1')dnl +#ifndef incmacro +#define incmacro + +#include +#include + +gen_symbol(pa__init) +gen_symbol(pa__done) +gen_symbol(pa__get_author) +gen_symbol(pa__get_description) +gen_symbol(pa__get_usage) +gen_symbol(pa__get_version) + +int pa__init(struct pa_core *c, struct pa_module*m); +void pa__done(struct pa_core *c, struct pa_module*m); + +const char* pa__get_author(void); +const char* pa__get_description(void); +const char* pa__get_usage(void); +const char* pa__get_version(void); + +#endif diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c new file mode 100644 index 00000000..e325b22c --- /dev/null +++ b/src/modules/module-detect.c @@ -0,0 +1,227 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "module-detect-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("just-one=") + +static const char *endswith(const char *haystack, const char *needle) { + size_t l, m; + const char *p; + + if ((l = strlen(haystack)) < (m = strlen(needle))) + return NULL; + + if (strcmp(p = haystack + l - m, needle)) + return NULL; + + return p; +} + +#ifdef HAVE_ALSA +static int detect_alsa(pa_core *c, int just_one) { + FILE *f; + int n = 0, n_sink = 0, n_source = 0; + + if (!(f = fopen("/proc/asound/devices", "r"))) { + + if (errno != ENOENT) + pa_log_error(__FILE__": open(\"/proc/asound/devices\") failed: %s\n", strerror(errno)); + + return -1; + } + + while (!feof(f)) { + char line[64], args[64]; + unsigned device, subdevice; + int is_sink; + + if (!fgets(line, sizeof(line), f)) + break; + + line[strcspn(line, "\r\n")] = 0; + + if (endswith(line, "digital audio playback")) + is_sink = 1; + else if (endswith(line, "digital audio capture")) + is_sink = 0; + else + continue; + + if (just_one && is_sink && n_sink >= 1) + continue; + + if (just_one && !is_sink && n_source >= 1) + continue; + + if (sscanf(line, " %*i: [%u- %u]: ", &device, &subdevice) != 2) + continue; + + /* Only one sink per device */ + if (subdevice != 0) + continue; + + snprintf(args, sizeof(args), "device=hw:%u,0", device); + if (!pa_module_load(c, is_sink ? "module-alsa-sink" : "module-alsa-source", args)) + continue; + + n++; + + if (is_sink) + n_sink++; + else + n_source++; + } + + fclose(f); + + return n; +} +#endif + +#ifdef HAVE_OSS +static int detect_oss(pa_core *c, int just_one) { + FILE *f; + int n = 0, b = 0; + + if (!(f = fopen("/dev/sndstat", "r")) && + !(f = fopen("/proc/sndstat", "r")) && + !(f = fopen("/proc/asound/oss/sndstat", "r"))) { + + if (errno != ENOENT) + pa_log_error(__FILE__": failed to open OSS sndstat device: %s\n", strerror(errno)); + + return -1; + } + + while (!feof(f)) { + char line[64], args[64]; + unsigned device; + + if (!fgets(line, sizeof(line), f)) + break; + + line[strcspn(line, "\r\n")] = 0; + + if (!b) { + b = strcmp(line, "Audio devices:") == 0; + continue; + } + + if (line[0] == 0) + break; + + if (sscanf(line, "%u: ", &device) != 1) + continue; + + if (device == 0) + snprintf(args, sizeof(args), "device=/dev/dsp"); + else + snprintf(args, sizeof(args), "device=/dev/dsp%u", device); + + if (!pa_module_load(c, "module-oss", args)) + continue; + + n++; + + if (just_one) + break; + } + + fclose(f); + return n; +} +#endif + +int pa__init(pa_core *c, pa_module*m) { + int just_one = 0, n = 0; + pa_modargs *ma; + + static const char* const valid_modargs[] = { + "just-one", + NULL + }; + + assert(c); + assert(m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": Failed to parse module arguments\n"); + goto fail; + } + + if (pa_modargs_get_value_boolean(ma, "just-one", &just_one) < 0) { + pa_log(__FILE__": just_one= expects a boolean argument.\n"); + goto fail; + } + +#if HAVE_ALSA + if ((n = detect_alsa(c, just_one)) <= 0) +#endif +#if HAVE_OSS + if ((n = detect_oss(c, just_one)) <= 0) +#endif + { + pa_log_warn(__FILE__": failed to detect any sound hardware.\n"); + goto fail; + } + + pa_log_info(__FILE__": loaded %i modules.\n", n); + + /* We were successful and can unload ourselves now. */ + pa_module_unload_request(m); + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + return -1; +} + + +void pa__done(pa_core *c, pa_module*m) { + /* NOP */ +} + diff --git a/src/modules/module-esound-compat-spawnfd.c b/src/modules/module-esound-compat-spawnfd.c new file mode 100644 index 00000000..5c656be9 --- /dev/null +++ b/src/modules/module-esound-compat-spawnfd.c @@ -0,0 +1,81 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "module-esound-compat-spawnfd-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("ESOUND compatibility module: -spawnfd emulation") +PA_MODULE_USAGE("fd=") +PA_MODULE_VERSION(PACKAGE_VERSION) + +static const char* const valid_modargs[] = { + "fd", + NULL, +}; + +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; + int ret = -1, fd = -1; + char x = 1; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs)) || + pa_modargs_get_value_s32(ma, "fd", &fd) < 0 || + fd < 0) { + pa_log(__FILE__": Failed to parse module arguments\n"); + goto finish; + } + + if (pa_loop_write(fd, &x, sizeof(x)) != sizeof(x)) + pa_log(__FILE__": WARNING: write(%u, 1, 1) failed: %s\n", fd, strerror(errno)); + + close(fd); + + pa_module_unload_request(m); + + ret = 0; + +finish: + if (ma) + pa_modargs_free(ma); + + return ret; +} + +void pa__done(pa_core *c, pa_module*m) { + assert(c && m); +} + + diff --git a/src/modules/module-esound-compat-spawnpid.c b/src/modules/module-esound-compat-spawnpid.c new file mode 100644 index 00000000..5daa1297 --- /dev/null +++ b/src/modules/module-esound-compat-spawnpid.c @@ -0,0 +1,79 @@ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "module-esound-compat-spawnpid-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("ESOUND compatibility module: -spawnpid emulation") +PA_MODULE_USAGE("pid=") +PA_MODULE_VERSION(PACKAGE_VERSION) + +static const char* const valid_modargs[] = { + "pid", + NULL, +}; + +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; + int ret = -1; + uint32_t pid = 0; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs)) || + pa_modargs_get_value_u32(ma, "pid", &pid) < 0 || + !pid) { + pa_log(__FILE__": Failed to parse module arguments\n"); + goto finish; + } + + if (kill(pid, SIGUSR1) < 0) + pa_log(__FILE__": WARNING: kill(%u) failed: %s\n", pid, strerror(errno)); + + pa_module_unload_request(m); + + ret = 0; + +finish: + if (ma) + pa_modargs_free(ma); + + return ret; +} + +void pa__done(pa_core *c, pa_module*m) { + assert(c && m); +} + + diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c new file mode 100644 index 00000000..4f724811 --- /dev/null +++ b/src/modules/module-esound-sink.c @@ -0,0 +1,427 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-esound-sink-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("ESOUND Sink") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink_name= server=
    cookie= format= channels= rate=") + +#define DEFAULT_SINK_NAME "esound_output" + +struct userdata { + pa_core *core; + + pa_sink *sink; + pa_iochannel *io; + pa_socket_client *client; + + pa_defer_event *defer_event; + + pa_memchunk memchunk; + pa_module *module; + + void *write_data; + size_t write_length, write_index; + + void *read_data; + size_t read_length, read_index; + + enum { STATE_AUTH, STATE_LATENCY, STATE_RUNNING, STATE_DEAD } state; + + pa_usec_t latency; + + esd_format_t format; + int32_t rate; +}; + +static const char* const valid_modargs[] = { + "server", + "cookie", + "rate", + "format", + "channels", + "sink_name", + NULL +}; + +static void cancel(struct userdata *u) { + assert(u); + + u->state = STATE_DEAD; + + if (u->io) { + pa_iochannel_free(u->io); + u->io = NULL; + } + + if (u->defer_event) { + u->core->mainloop->defer_free(u->defer_event); + u->defer_event = NULL; + } + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + u->sink = NULL; + } + + if (u->module) { + pa_module_unload_request(u->module); + u->module = NULL; + } +} + +static int do_write(struct userdata *u) { + ssize_t r; + assert(u); + + if (!pa_iochannel_is_writable(u->io)) + return 0; + + if (u->write_data) { + assert(u->write_index < u->write_length); + + if ((r = pa_iochannel_write(u->io, (uint8_t*) u->write_data + u->write_index, u->write_length - u->write_index)) <= 0) { + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + return -1; + } + + u->write_index += r; + assert(u->write_index <= u->write_length); + + if (u->write_index == u->write_length) { + free(u->write_data); + u->write_data = NULL; + u->write_index = u->write_length = 0; + } + } else if (u->state == STATE_RUNNING) { + pa_module_set_used(u->module, pa_idxset_size(u->sink->inputs) + pa_idxset_size(u->sink->monitor_source->outputs)); + + if (!u->memchunk.length) + if (pa_sink_render(u->sink, 8192, &u->memchunk) < 0) + return 0; + + assert(u->memchunk.memblock && u->memchunk.length); + + if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + return -1; + } + + u->memchunk.index += r; + u->memchunk.length -= r; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + } + } + + return 0; +} + +static int handle_response(struct userdata *u) { + assert(u); + + switch (u->state) { + case STATE_AUTH: + assert(u->read_length == sizeof(int32_t)); + + /* Process auth data */ + if (!*(int32_t*) u->read_data) { + pa_log(__FILE__": Authentication failed: %s\n", strerror(errno)); + return -1; + } + + /* Request latency data */ + assert(!u->write_data); + *(int32_t*) (u->write_data = pa_xmalloc(u->write_length = sizeof(int32_t))) = ESD_PROTO_LATENCY; + + u->write_index = 0; + u->state = STATE_LATENCY; + + /* Space for next response */ + assert(u->read_length >= sizeof(int32_t)); + u->read_index = 0; + u->read_length = sizeof(int32_t); + + break; + + case STATE_LATENCY: { + int32_t *p; + assert(u->read_length == sizeof(int32_t)); + + /* Process latency info */ + u->latency = (pa_usec_t) ((double) (*(int32_t*) u->read_data) * 1000000 / 44100); + if (u->latency > 10000000) { + pa_log(__FILE__": WARNING! Invalid latency information received from server\n"); + u->latency = 0; + } + + /* Create stream */ + assert(!u->write_data); + p = u->write_data = pa_xmalloc0(u->write_length = sizeof(int32_t)*3+ESD_NAME_MAX); + *(p++) = ESD_PROTO_STREAM_PLAY; + *(p++) = u->format; + *(p++) = u->rate; + pa_strlcpy((char*) p, "Polypaudio Tunnel", ESD_NAME_MAX); + + u->write_index = 0; + u->state = STATE_RUNNING; + + /* Don't read any further */ + pa_xfree(u->read_data); + u->read_data = NULL; + u->read_index = u->read_length = 0; + + break; + } + + default: + abort(); + } + + return 0; +} + +static int do_read(struct userdata *u) { + assert(u); + + if (!pa_iochannel_is_readable(u->io)) + return 0; + + if (u->state == STATE_AUTH || u->state == STATE_LATENCY) { + ssize_t r; + + if (!u->read_data) + return 0; + + assert(u->read_index < u->read_length); + + if ((r = pa_iochannel_read(u->io, (uint8_t*) u->read_data + u->read_index, u->read_length - u->read_index)) <= 0) { + pa_log(__FILE__": read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); + cancel(u); + return -1; + } + + u->read_index += r; + assert(u->read_index <= u->read_length); + + if (u->read_index == u->read_length) + return handle_response(u); + } + + return 0; +} + +static void do_work(struct userdata *u) { + assert(u); + + u->core->mainloop->defer_enable(u->defer_event, 0); + + if (do_read(u) < 0 || do_write(u) < 0) + cancel(u); +} + +static void notify_cb(pa_sink*s) { + struct userdata *u = s->userdata; + assert(s && u); + + if (pa_iochannel_is_writable(u->io)) + u->core->mainloop->defer_enable(u->defer_event, 1); +} + +static pa_usec_t get_latency_cb(pa_sink *s) { + struct userdata *u = s->userdata; + assert(s && u); + + return + u->latency + + (u->memchunk.memblock ? pa_bytes_to_usec(u->memchunk.length, &s->sample_spec) : 0); +} + +static void defer_callback(PA_GCC_UNUSED pa_mainloop_api *m, PA_GCC_UNUSED pa_defer_event*e, void *userdata) { + struct userdata *u = userdata; + assert(u); + do_work(u); +} + +static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { + struct userdata *u = userdata; + assert(u); + do_work(u); +} + +static void on_connection(PA_GCC_UNUSED pa_socket_client *c, pa_iochannel*io, void *userdata) { + struct userdata *u = userdata; + + pa_socket_client_unref(u->client); + u->client = NULL; + + if (!io) { + pa_log(__FILE__": connection failed: %s\n", strerror(errno)); + cancel(u); + return; + } + + u->io = io; + pa_iochannel_set_callback(u->io, io_callback, u); +} + +int pa__init(pa_core *c, pa_module*m) { + struct userdata *u = NULL; + const char *p; + pa_sample_spec ss; + pa_modargs *ma = NULL; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": invalid sample format specification\n"); + goto fail; + } + + if ((ss.format != PA_SAMPLE_U8 && ss.format != PA_SAMPLE_S16NE) || + (ss.channels > 2)) { + pa_log(__FILE__": esound sample type support is limited to mono/stereo and U8 or S16NE sample data\n"); + goto fail; + } + + u = pa_xmalloc0(sizeof(struct userdata)); + u->core = c; + u->module = m; + m->userdata = u; + u->format = + (ss.format == PA_SAMPLE_U8 ? ESD_BITS8 : ESD_BITS16) | + (ss.channels == 2 ? ESD_STEREO : ESD_MONO); + u->rate = ss.rate; + u->sink = NULL; + u->client = NULL; + u->io = NULL; + u->read_data = u->write_data = NULL; + u->read_index = u->write_index = u->read_length = u->write_length = 0; + u->state = STATE_AUTH; + u->latency = 0; + + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { + pa_log(__FILE__": failed to create sink.\n"); + goto fail; + } + + if (!(u->client = pa_socket_client_new_string(u->core->mainloop, p = pa_modargs_get_value(ma, "server", ESD_UNIX_SOCKET_NAME), ESD_DEFAULT_PORT))) { + pa_log(__FILE__": failed to connect to server.\n"); + goto fail; + } + pa_socket_client_set_callback(u->client, on_connection, u); + + /* Prepare the initial request */ + u->write_data = pa_xmalloc(u->write_length = ESD_KEY_LEN + sizeof(int32_t)); + if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", ".esd_auth"), u->write_data, ESD_KEY_LEN) < 0) { + pa_log(__FILE__": failed to load cookie\n"); + goto fail; + } + *(int32_t*) ((uint8_t*) u->write_data + ESD_KEY_LEN) = ESD_ENDIAN_KEY; + + /* Reserve space for the response */ + u->read_data = pa_xmalloc(u->read_length = sizeof(int32_t)); + + u->sink->notify = notify_cb; + u->sink->get_latency = get_latency_cb; + u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Esound sink '%s'", p); + + u->memchunk.memblock = NULL; + u->memchunk.length = 0; + + u->defer_event = c->mainloop->defer_new(c->mainloop, defer_callback, u); + c->mainloop->defer_enable(u->defer_event, 0); + + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + pa__done(c, m); + + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + u->module = NULL; + cancel(u); + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + + if (u->client) + pa_socket_client_unref(u->client); + + pa_xfree(u->read_data); + pa_xfree(u->write_data); + + pa_xfree(u); +} + + + diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c new file mode 100644 index 00000000..ea8a2bd2 --- /dev/null +++ b/src/modules/module-lirc.c @@ -0,0 +1,241 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "module-lirc-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("LIRC volume control") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("config= sink= appname=") + +static const char* const valid_modargs[] = { + "config", + "sink", + "appname", + NULL, +}; + +struct userdata { + int lirc_fd; + pa_io_event *io; + struct lirc_config *config; + char *sink_name; + pa_module *module; + float mute_toggle_save; +}; + +static int lirc_in_use = 0; + +static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void*userdata) { + struct userdata *u = userdata; + char *name = NULL, *code = NULL; + assert(io); + assert(u); + + if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { + pa_log(__FILE__": lost connection to LIRC daemon.\n"); + goto fail; + } + + if (events & PA_IO_EVENT_INPUT) { + char *c; + + if (lirc_nextcode(&code) != 0 || !code) { + pa_log(__FILE__": lirc_nextcode() failed.\n"); + goto fail; + } + + c = pa_xstrdup(code); + c[strcspn(c, "\n\r")] = 0; + pa_log_debug(__FILE__": raw IR code '%s'\n", c); + pa_xfree(c); + + while (lirc_code2char(u->config, code, &name) == 0 && name) { + enum { INVALID, UP, DOWN, MUTE, RESET, MUTE_TOGGLE } volchange = INVALID; + + pa_log_info(__FILE__": translated IR code '%s'\n", name); + + if (strcasecmp(name, "volume-up") == 0) + volchange = UP; + else if (strcasecmp(name, "volume-down") == 0) + volchange = DOWN; + else if (strcasecmp(name, "mute") == 0) + volchange = MUTE; + else if (strcasecmp(name, "mute-toggle") == 0) + volchange = MUTE_TOGGLE; + else if (strcasecmp(name, "reset") == 0) + volchange = RESET; + + if (volchange == INVALID) + pa_log_warn(__FILE__": recieved unknown IR code '%s'\n", name); + else { + pa_sink *s; + + if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) + pa_log(__FILE__": failed to get sink '%s'\n", u->sink_name); + else { + pa_volume_t v = pa_cvolume_avg(pa_sink_get_volume(s, PA_MIXER_HARDWARE)); + pa_cvolume cv; +#define DELTA (PA_VOLUME_NORM/20) + + switch (volchange) { + case UP: + v += PA_VOLUME_NORM/20; + break; + + case DOWN: + if (v > DELTA) + v -= DELTA; + else + v = PA_VOLUME_MUTED; + + break; + + case MUTE: + v = PA_VOLUME_MUTED; + break; + + case RESET: + v = PA_VOLUME_NORM; + break; + + case MUTE_TOGGLE: { + + if (v > 0) { + u->mute_toggle_save = v; + v = PA_VOLUME_MUTED; + } else + v = u->mute_toggle_save; + } + default: + ; + } + + pa_cvolume_set(&cv, PA_CHANNELS_MAX, v); + pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); + } + } + } + } + + free(code); + + return; + +fail: + u->module->core->mainloop->io_free(u->io); + u->io = NULL; + + pa_module_unload_request(u->module); + + free(code); +} + +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; + struct userdata *u; + assert(c && m); + + if (lirc_in_use) { + pa_log(__FILE__": module-lirc may no be loaded twice.\n"); + return -1; + } + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": Failed to parse module arguments\n"); + goto fail; + } + + m->userdata = u = pa_xmalloc(sizeof(struct userdata)); + u->module = m; + u->io = NULL; + u->config = NULL; + u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); + u->lirc_fd = -1; + u->mute_toggle_save = 0; + + if ((u->lirc_fd = lirc_init((char*) pa_modargs_get_value(ma, "appname", "polypaudio"), 1)) < 0) { + pa_log(__FILE__": lirc_init() failed.\n"); + goto fail; + } + + if (lirc_readconfig((char*) pa_modargs_get_value(ma, "config", NULL), &u->config, NULL) < 0) { + pa_log(__FILE__": lirc_readconfig() failed.\n"); + goto fail; + } + + u->io = c->mainloop->io_new(c->mainloop, u->lirc_fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u); + + lirc_in_use = 1; + + pa_modargs_free(ma); + + return 0; + +fail: + + if (ma) + pa_modargs_free(ma); + + pa__done(c, m); + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c); + assert(m); + + if (!(u = m->userdata)) + return; + + if (u->io) + m->core->mainloop->io_free(u->io); + + if (u->config) + lirc_freeconfig(u->config); + + if (u->lirc_fd >= 0) + lirc_deinit(); + + pa_xfree(u->sink_name); + pa_xfree(u); + + lirc_in_use = 0; +} diff --git a/src/modules/module-match.c b/src/modules/module-match.c new file mode 100644 index 00000000..10ceb75e --- /dev/null +++ b/src/modules/module-match.c @@ -0,0 +1,235 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "module-match-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Sink input matching module") +PA_MODULE_USAGE("table=") +PA_MODULE_VERSION(PACKAGE_VERSION) + +#define WHITESPACE "\n\r \t" + +#ifndef DEFAULT_CONFIG_DIR +#define DEFAULT_CONFIG_DIR "/etc/polypaudio" +#endif + +#define DEFAULT_MATCH_TABLE_FILE DEFAULT_CONFIG_DIR"/match.table" +#define DEFAULT_MATCH_TABLE_FILE_USER ".polypaudio/match.table" + +static const char* const valid_modargs[] = { + "table", + NULL, +}; + +struct rule { + regex_t regex; + pa_volume_t volume; + struct rule *next; +}; + +struct userdata { + struct rule *rules; + pa_subscription *subscription; +}; + +static int load_rules(struct userdata *u, const char *filename) { + FILE *f; + int n = 0; + int ret = -1; + struct rule *end = NULL; + char *fn = NULL; + + f = filename ? + fopen(fn = pa_xstrdup(filename), "r") : + pa_open_config_file(DEFAULT_MATCH_TABLE_FILE, DEFAULT_MATCH_TABLE_FILE_USER, NULL, &fn); + + if (!f) { + pa_log(__FILE__": failed to open file '%s': %s\n", fn, strerror(errno)); + goto finish; + } + + while (!feof(f)) { + char *d, *v; + pa_volume_t volume; + uint32_t k; + regex_t regex; + char ln[256]; + struct rule *rule; + + if (!fgets(ln, sizeof(ln), f)) + break; + + n++; + + pa_strip_nl(ln); + + if (ln[0] == '#' || !*ln ) + continue; + + d = ln+strcspn(ln, WHITESPACE); + v = d+strspn(d, WHITESPACE); + + + if (!*v) { + pa_log(__FILE__ ": [%s:%u] failed to parse line - too few words\n", filename, n); + goto finish; + } + + *d = 0; + if (pa_atou(v, &k) < 0) { + pa_log(__FILE__": [%s:%u] failed to parse volume\n", filename, n); + goto finish; + } + + volume = (pa_volume_t) k; + + + if (regcomp(®ex, ln, REG_EXTENDED|REG_NOSUB) != 0) { + pa_log(__FILE__": [%s:%u] invalid regular expression\n", filename, n); + goto finish; + } + + rule = pa_xmalloc(sizeof(struct rule)); + rule->regex = regex; + rule->volume = volume; + rule->next = NULL; + + if (end) + end->next = rule; + else + u->rules = rule; + end = rule; + + *d = 0; + } + + ret = 0; + +finish: + if (f) + fclose(f); + + if (fn) + pa_xfree(fn); + + return ret; +} + +static void callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { + struct userdata *u = userdata; + pa_sink_input *si; + struct rule *r; + assert(c && u); + + if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW)) + return; + + if (!(si = pa_idxset_get_by_index(c->sink_inputs, idx))) + return; + + if (!si->name) + return; + + for (r = u->rules; r; r = r->next) { + if (!regexec(&r->regex, si->name, 0, NULL, 0)) { + pa_cvolume cv; + pa_log_debug(__FILE__": changing volume of sink input '%s' to 0x%03x\n", si->name, r->volume); + pa_cvolume_set(&cv, r->volume, si->sample_spec.channels); + pa_sink_input_set_volume(si, &cv); + } + } +} + +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; + struct userdata *u; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": Failed to parse module arguments\n"); + goto fail; + } + + u = pa_xmalloc(sizeof(struct userdata)); + u->rules = NULL; + u->subscription = NULL; + m->userdata = u; + + if (load_rules(u, pa_modargs_get_value(ma, "table", NULL)) < 0) + goto fail; + + u->subscription = pa_subscription_new(c, PA_SUBSCRIPTION_MASK_SINK_INPUT, callback, u); + + pa_modargs_free(ma); + return 0; + +fail: + pa__done(c, m); + + if (ma) + pa_modargs_free(ma); + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata* u; + struct rule *r, *n; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->subscription) + pa_subscription_free(u->subscription); + + for (r = u->rules; r; r = n) { + n = r->next; + + regfree(&r->regex); + pa_xfree(r); + } + + pa_xfree(u); +} + + diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c new file mode 100644 index 00000000..b60f786d --- /dev/null +++ b/src/modules/module-mmkbd-evdev.c @@ -0,0 +1,250 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "module-mmkbd-evdev-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Multimedia keyboard support via Linux evdev") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("device= sink=") + +#define DEFAULT_DEVICE "/dev/input/event0" + +/* + * This isn't defined in older kernel headers and there is no way of + * detecting it. + */ +struct _input_id { + __u16 bustype; + __u16 vendor; + __u16 product; + __u16 version; +}; + +static const char* const valid_modargs[] = { + "device", + "sink", + NULL, +}; + +struct userdata { + int fd; + pa_io_event *io; + char *sink_name; + pa_module *module; + float mute_toggle_save; +}; + +static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void*userdata) { + struct userdata *u = userdata; + assert(io); + assert(u); + + if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { + pa_log(__FILE__": lost connection to evdev device.\n"); + goto fail; + } + + if (events & PA_IO_EVENT_INPUT) { + struct input_event ev; + + if (pa_loop_read(u->fd, &ev, sizeof(ev)) <= 0) { + pa_log(__FILE__": failed to read from event device: %s\n", strerror(errno)); + goto fail; + } + + if (ev.type == EV_KEY && (ev.value == 1 || ev.value == 2)) { + enum { INVALID, UP, DOWN, MUTE_TOGGLE } volchange = INVALID; + + pa_log_debug(__FILE__": key code=%u, value=%u\n", ev.code, ev.value); + + switch (ev.code) { + case KEY_VOLUMEDOWN: volchange = DOWN; break; + case KEY_VOLUMEUP: volchange = UP; break; + case KEY_MUTE: volchange = MUTE_TOGGLE; break; + } + + if (volchange != INVALID) { + pa_sink *s; + + if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) + pa_log(__FILE__": failed to get sink '%s'\n", u->sink_name); + else { + pa_volume_t v = pa_cvolume_avg(pa_sink_get_volume(s, PA_MIXER_HARDWARE)); + pa_cvolume cv; +#define DELTA (PA_VOLUME_NORM/20) + + switch (volchange) { + case UP: + v += DELTA; + break; + + case DOWN: + if (v > DELTA) + v -= DELTA; + else + v = PA_VOLUME_MUTED; + + break; + + case MUTE_TOGGLE: { + + if (v > 0) { + u->mute_toggle_save = v; + v = PA_VOLUME_MUTED; + } else + v = u->mute_toggle_save; + } + default: + ; + } + + pa_cvolume_set(&cv, PA_CHANNELS_MAX, v); + pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); + } + } + } + } + + return; + +fail: + u->module->core->mainloop->io_free(u->io); + u->io = NULL; + + pa_module_unload_request(u->module); +} + +#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8))) + +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; + struct userdata *u; + int version; + struct _input_id input_id; + char name[256]; + uint8_t evtype_bitmask[EV_MAX/8 + 1]; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": Failed to parse module arguments\n"); + goto fail; + } + + m->userdata = u = pa_xmalloc(sizeof(struct userdata)); + u->module = m; + u->io = NULL; + u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); + u->fd = -1; + u->mute_toggle_save = 0; + + if ((u->fd = open(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), O_RDONLY)) < 0) { + pa_log(__FILE__": failed to open evdev device: %s\n", strerror(errno)); + goto fail; + } + + if (ioctl(u->fd, EVIOCGVERSION, &version) < 0) { + pa_log(__FILE__": EVIOCGVERSION failed: %s\n", strerror(errno)); + goto fail; + } + + pa_log_info(__FILE__": evdev driver version %i.%i.%i\n", version >> 16, (version >> 8) & 0xff, version & 0xff); + + if(ioctl(u->fd, EVIOCGID, &input_id)) { + pa_log(__FILE__": EVIOCGID failed: %s\n", strerror(errno)); + goto fail; + } + + pa_log_info(__FILE__": evdev vendor 0x%04hx product 0x%04hx version 0x%04hx bustype %u\n", + input_id.vendor, input_id.product, input_id.version, input_id.bustype); + + if(ioctl(u->fd, EVIOCGNAME(sizeof(name)), name) < 0) { + pa_log(__FILE__": EVIOCGNAME failed: %s\n", strerror(errno)); + goto fail; + } + + pa_log_info(__FILE__": evdev device name: %s\n", name); + + memset(evtype_bitmask, 0, sizeof(evtype_bitmask)); + if (ioctl(u->fd, EVIOCGBIT(0, EV_MAX), evtype_bitmask) < 0) { + pa_log(__FILE__": EVIOCGBIT failed: %s\n", strerror(errno)); + goto fail; + } + + if (!test_bit(EV_KEY, evtype_bitmask)) { + pa_log(__FILE__": device has no keys.\n"); + goto fail; + } + + u->io = c->mainloop->io_new(c->mainloop, u->fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u); + + pa_modargs_free(ma); + + return 0; + +fail: + + if (ma) + pa_modargs_free(ma); + + pa__done(c, m); + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c); + assert(m); + + if (!(u = m->userdata)) + return; + + if (u->io) + m->core->mainloop->io_free(u->io); + + if (u->fd >= 0) + close(u->fd); + + pa_xfree(u->sink_name); + pa_xfree(u); +} diff --git a/src/modules/module-native-protocol-fd.c b/src/modules/module-native-protocol-fd.c new file mode 100644 index 00000000..abc531b3 --- /dev/null +++ b/src/modules/module-native-protocol-fd.c @@ -0,0 +1,85 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "module-native-protocol-fd-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Native protocol autospawn helper") +PA_MODULE_VERSION(PACKAGE_VERSION) + +static const char* const valid_modargs[] = { + "fd", + "public", + "cookie", + NULL, +}; + +int pa__init(pa_core *c, pa_module*m) { + pa_iochannel *io; + pa_modargs *ma; + int fd, r = -1; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments.\n"); + goto finish; + } + + if (pa_modargs_get_value_s32(ma, "fd", &fd) < 0) { + pa_log(__FILE__": invalid file descriptor.\n"); + goto finish; + } + + io = pa_iochannel_new(c->mainloop, fd, fd); + + if (!(m->userdata = pa_protocol_native_new_iochannel(c, io, m, ma))) { + pa_iochannel_free(io); + goto finish; + } + + r = 0; + +finish: + if (ma) + pa_modargs_free(ma); + + return r; +} + +void pa__done(pa_core *c, pa_module*m) { + assert(c && m); + + pa_protocol_native_free(m->userdata); +} diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c new file mode 100644 index 00000000..5731a403 --- /dev/null +++ b/src/modules/module-null-sink.c @@ -0,0 +1,150 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "module-null-sink-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Clocked NULL sink") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("format= channels= rate= sink_name=") + +#define DEFAULT_SINK_NAME "null" + +struct userdata { + pa_core *core; + pa_module *module; + pa_sink *sink; + pa_time_event *time_event; + size_t block_size; +}; + +static const char* const valid_modargs[] = { + "rate", + "format", + "channels", + "sink_name", + NULL +}; + +static void time_callback(pa_mainloop_api *m, pa_time_event*e, const struct timeval *tv, void *userdata) { + struct userdata *u = userdata; + pa_memchunk chunk; + struct timeval ntv = *tv; + size_t l; + + assert(u); + + if (pa_sink_render(u->sink, u->block_size, &chunk) >= 0) { + l = chunk.length; + pa_memblock_unref(chunk.memblock); + } else + l = u->block_size; + + pa_timeval_add(&ntv, pa_bytes_to_usec(l, &u->sink->sample_spec)); + m->time_restart(e, &ntv); +} + +int pa__init(pa_core *c, pa_module*m) { + struct userdata *u = NULL; + pa_sample_spec ss; + pa_modargs *ma = NULL; + struct timeval tv; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments.\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": invalid sample format specification.\n"); + goto fail; + } + + u = pa_xmalloc0(sizeof(struct userdata)); + u->core = c; + u->module = m; + m->userdata = u; + + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { + pa_log(__FILE__": failed to create sink.\n"); + goto fail; + } + + u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("NULL sink"); + + pa_gettimeofday(&tv); + u->time_event = c->mainloop->time_new(c->mainloop, &tv, time_callback, u); + + u->block_size = pa_bytes_per_second(&ss) / 10; + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + pa__done(c, m); + + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + + u->core->mainloop->time_free(u->time_event); + + pa_xfree(u); +} diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c new file mode 100644 index 00000000..6986b03c --- /dev/null +++ b/src/modules/module-oss-mmap.c @@ -0,0 +1,426 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-oss-mmap-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("OSS Sink/Source (mmap)") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= fragments= fragment_size=") + +struct userdata { + pa_sink *sink; + pa_source *source; + pa_core *core; + pa_sample_spec sample_spec; + + size_t in_fragment_size, out_fragment_size, in_fragments, out_fragments, out_fill; + + int fd; + + void *in_mmap, *out_mmap; + size_t in_mmap_length, out_mmap_length; + + pa_io_event *io_event; + + pa_memblock **in_memblocks, **out_memblocks; + unsigned out_current, in_current; + pa_module *module; +}; + +static const char* const valid_modargs[] = { + "sink_name", + "source_name", + "device", + "record", + "playback", + "fragments", + "fragment_size", + "format", + "rate", + "channels", + NULL +}; + +#define DEFAULT_SINK_NAME "oss_output" +#define DEFAULT_SOURCE_NAME "oss_input" +#define DEFAULT_DEVICE "/dev/dsp" + +static void update_usage(struct userdata *u) { + pa_module_set_used(u->module, + (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0) + + (u->source ? pa_idxset_size(u->source->outputs) : 0)); +} + +static void out_fill_memblocks(struct userdata *u, unsigned n) { + assert(u && u->out_memblocks); + + while (n > 0) { + pa_memchunk chunk; + + if (u->out_memblocks[u->out_current]) + pa_memblock_unref_fixed(u->out_memblocks[u->out_current]); + + chunk.memblock = u->out_memblocks[u->out_current] = pa_memblock_new_fixed((uint8_t*)u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size, 1, u->core->memblock_stat); + assert(chunk.memblock); + chunk.length = chunk.memblock->length; + chunk.index = 0; + + pa_sink_render_into_full(u->sink, &chunk); + + u->out_current++; + while (u->out_current >= u->out_fragments) + u->out_current -= u->out_fragments; + + n--; + } +} + +static void do_write(struct userdata *u) { + struct count_info info; + assert(u && u->sink); + + update_usage(u); + + if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { + pa_log(__FILE__": SNDCTL_DSP_GETOPTR: %s\n", strerror(errno)); + return; + } + + u->out_fill = (u->out_fragment_size * u->out_fragments) - (info.ptr % u->out_fragment_size); + + if (!info.blocks) + return; + + out_fill_memblocks(u, info.blocks); +} + +static void in_post_memblocks(struct userdata *u, unsigned n) { + assert(u && u->in_memblocks); + + while (n > 0) { + pa_memchunk chunk; + + if (!u->in_memblocks[u->in_current]) { + chunk.memblock = u->in_memblocks[u->in_current] = pa_memblock_new_fixed((uint8_t*) u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size, 1, u->core->memblock_stat); + chunk.length = chunk.memblock->length; + chunk.index = 0; + + pa_source_post(u->source, &chunk); + } + + u->in_current++; + while (u->in_current >= u->in_fragments) + u->in_current -= u->in_fragments; + + n--; + } +} + +static void in_clear_memblocks(struct userdata*u, unsigned n) { + unsigned i = u->in_current; + assert(u && u->in_memblocks); + + if (n > u->in_fragments) + n = u->in_fragments; + + while (n > 0) { + if (u->in_memblocks[i]) { + pa_memblock_unref_fixed(u->in_memblocks[i]); + u->in_memblocks[i] = NULL; + } + + i++; + while (i >= u->in_fragments) + i -= u->in_fragments; + + n--; + } +} + +static void do_read(struct userdata *u) { + struct count_info info; + assert(u && u->source); + + update_usage(u); + + if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { + pa_log(__FILE__": SNDCTL_DSP_GETIPTR: %s\n", strerror(errno)); + return; + } + + if (!info.blocks) + return; + + in_post_memblocks(u, info.blocks); + in_clear_memblocks(u, u->in_fragments/2); +} + +static void io_callback(pa_mainloop_api *m, pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t f, void *userdata) { + struct userdata *u = userdata; + assert (u && u->core->mainloop == m && u->io_event == e); + + if (f & PA_IO_EVENT_INPUT) + do_read(u); + if (f & PA_IO_EVENT_OUTPUT) + do_write(u); +} + +static pa_usec_t sink_get_latency_cb(pa_sink *s) { + struct userdata *u = s->userdata; + assert(s && u); + + do_write(u); + return pa_bytes_to_usec(u->out_fill, &s->sample_spec); +} + +int pa__init(pa_core *c, pa_module*m) { + struct audio_buf_info info; + struct userdata *u = NULL; + const char *p; + int nfrags, frag_size; + int mode, caps; + int enable_bits = 0, zero = 0; + int playback = 1, record = 1; + pa_modargs *ma = NULL; + assert(c && m); + + m->userdata = u = pa_xmalloc0(sizeof(struct userdata)); + u->module = m; + u->fd = -1; + u->core = c; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments.\n"); + goto fail; + } + + if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { + pa_log(__FILE__": record= and playback= expect numeric arguments.\n"); + goto fail; + } + + if (!playback && !record) { + pa_log(__FILE__": neither playback nor record enabled for device.\n"); + goto fail; + } + + mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); + + nfrags = 12; + frag_size = 1024; + if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { + pa_log(__FILE__": failed to parse fragments arguments\n"); + goto fail; + } + + u->sample_spec = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &u->sample_spec) < 0) { + pa_log(__FILE__": failed to parse sample specification\n"); + goto fail; + } + + if ((u->fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0) + goto fail; + + if (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_REALTIME) || !(caps & DSP_CAP_TRIGGER)) { + pa_log(__FILE__": OSS device not mmap capable.\n"); + goto fail; + } + + pa_log(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + + if (nfrags >= 2 && frag_size >= 1) + if (pa_oss_set_fragments(u->fd, nfrags, frag_size) < 0) + goto fail; + + if (pa_oss_auto_format(u->fd, &u->sample_spec) < 0) + goto fail; + + if (mode != O_WRONLY) { + if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { + pa_log(__FILE__": SNDCTL_DSP_GETISPACE: %s\n", strerror(errno)); + goto fail; + } + + pa_log_info(__FILE__": input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + u->in_mmap_length = (u->in_fragment_size = info.fragsize) * (u->in_fragments = info.fragstotal); + + if ((u->in_mmap = mmap(NULL, u->in_mmap_length, PROT_READ, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { + if (mode == O_RDWR) { + pa_log(__FILE__": mmap failed for input. Changing to O_WRONLY mode.\n"); + mode = O_WRONLY; + } else { + pa_log(__FILE__": mmap(): %s\n", strerror(errno)); + goto fail; + } + } else { + + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec, NULL); + assert(u->source); + u->source->userdata = u; + pa_source_set_owner(u->source, m); + u->source->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'", p); + + u->in_memblocks = pa_xmalloc0(sizeof(pa_memblock *)*u->in_fragments); + + enable_bits |= PCM_ENABLE_INPUT; + } + } + + if (mode != O_RDONLY) { + if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { + pa_log(__FILE__": SNDCTL_DSP_GETOSPACE: %s\n", strerror(errno)); + goto fail; + } + + pa_log_info(__FILE__": output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + u->out_mmap_length = (u->out_fragment_size = info.fragsize) * (u->out_fragments = info.fragstotal); + + if ((u->out_mmap = mmap(NULL, u->out_mmap_length, PROT_WRITE, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { + if (mode == O_RDWR) { + pa_log(__FILE__": mmap filed for output. Changing to O_RDONLY mode.\n"); + mode = O_RDONLY; + } else { + pa_log(__FILE__": mmap(): %s\n", strerror(errno)); + goto fail; + } + } else { + pa_silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec); + + u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec, NULL); + assert(u->sink); + u->sink->get_latency = sink_get_latency_cb; + u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'", p); + + u->out_memblocks = pa_xmalloc0(sizeof(struct memblock *)*u->out_fragments); + + enable_bits |= PCM_ENABLE_OUTPUT; + } + } + + zero = 0; + if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero) < 0) { + pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s\n", strerror(errno)); + goto fail; + } + + if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0) { + pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s\n", strerror(errno)); + goto fail; + } + + assert(u->source || u->sink); + + u->io_event = c->mainloop->io_new(c->mainloop, u->fd, (u->source ? PA_IO_EVENT_INPUT : 0) | (u->sink ? PA_IO_EVENT_OUTPUT : 0), io_callback, u); + assert(u->io_event); + + pa_modargs_free(ma); + + return 0; + +fail: + pa__done(c, m); + + if (ma) + pa_modargs_free(ma); + + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->out_memblocks) { + unsigned i; + for (i = 0; i < u->out_fragments; i++) + if (u->out_memblocks[i]) + pa_memblock_unref_fixed(u->out_memblocks[i]); + pa_xfree(u->out_memblocks); + } + + if (u->in_memblocks) { + unsigned i; + for (i = 0; i < u->in_fragments; i++) + if (u->in_memblocks[i]) + pa_memblock_unref_fixed(u->in_memblocks[i]); + pa_xfree(u->in_memblocks); + } + + if (u->in_mmap && u->in_mmap != MAP_FAILED) + munmap(u->in_mmap, u->in_mmap_length); + + if (u->out_mmap && u->out_mmap != MAP_FAILED) + munmap(u->out_mmap, u->out_mmap_length); + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + } + + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + } + + if (u->io_event) + u->core->mainloop->io_free(u->io_event); + + if (u->fd >= 0) + close(u->fd); + + pa_xfree(u); +} diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c new file mode 100644 index 00000000..04458419 --- /dev/null +++ b/src/modules/module-oss.c @@ -0,0 +1,468 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-oss-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("OSS Sink/Source") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= fragments= fragment_size=") + +struct userdata { + pa_sink *sink; + pa_source *source; + pa_iochannel *io; + pa_core *core; + + pa_memchunk memchunk, silence; + + uint32_t in_fragment_size, out_fragment_size, sample_size; + int use_getospace, use_getispace; + + int fd; + pa_module *module; +}; + +static const char* const valid_modargs[] = { + "sink_name", + "source_name", + "device", + "record", + "playback", + "fragments", + "fragment_size", + "format", + "rate", + "channels", + NULL +}; + +#define DEFAULT_SINK_NAME "oss_output" +#define DEFAULT_SOURCE_NAME "oss_input" +#define DEFAULT_DEVICE "/dev/dsp" + +static void update_usage(struct userdata *u) { + pa_module_set_used(u->module, + (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0) + + (u->source ? pa_idxset_size(u->source->outputs) : 0)); +} + +static void do_write(struct userdata *u) { + pa_memchunk *memchunk; + ssize_t r; + size_t l; + int loop = 0; + + assert(u); + + if (!u->sink || !pa_iochannel_is_writable(u->io)) + return; + + update_usage(u); + + l = u->out_fragment_size; + + if (u->use_getospace) { + audio_buf_info info; + + if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) + u->use_getospace = 0; + else { + if (info.bytes/l > 0) { + l = (info.bytes/l)*l; + loop = 1; + } + } + } + + do { + memchunk = &u->memchunk; + + if (!memchunk->length) + if (pa_sink_render(u->sink, l, memchunk) < 0) + memchunk = &u->silence; + + assert(memchunk->memblock); + assert(memchunk->memblock->data); + assert(memchunk->length); + + if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + break; + } + + if (memchunk == &u->silence) + assert(r % u->sample_size == 0); + else { + u->memchunk.index += r; + u->memchunk.length -= r; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + } + } + + l = l > (size_t) r ? l - r : 0; + } while (loop && l > 0); +} + +static void do_read(struct userdata *u) { + pa_memchunk memchunk; + ssize_t r; + size_t l; + int loop = 0; + assert(u); + + if (!u->source || !pa_iochannel_is_readable(u->io) || !pa_idxset_size(u->source->outputs)) + return; + + update_usage(u); + + l = u->in_fragment_size; + + if (u->use_getispace) { + audio_buf_info info; + + if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) + u->use_getispace = 0; + else { + if (info.bytes/l > 0) { + l = (info.bytes/l)*l; + loop = 1; + } + } + } + + do { + memchunk.memblock = pa_memblock_new(l, u->core->memblock_stat); + assert(memchunk.memblock); + if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { + pa_memblock_unref(memchunk.memblock); + if (errno != EAGAIN) + pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + break; + } + + assert(r <= (ssize_t) memchunk.memblock->length); + memchunk.length = memchunk.memblock->length = r; + memchunk.index = 0; + + pa_source_post(u->source, &memchunk); + pa_memblock_unref(memchunk.memblock); + + l = l > (size_t) r ? l - r : 0; + } while (loop && l > 0); +} + +static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { + struct userdata *u = userdata; + assert(u); + do_write(u); + do_read(u); +} + +static void source_notify_cb(pa_source *s) { + struct userdata *u = s->userdata; + assert(u); + do_read(u); +} + +static pa_usec_t sink_get_latency_cb(pa_sink *s) { + pa_usec_t r = 0; + int arg; + struct userdata *u = s->userdata; + assert(s && u && u->sink); + + if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { + pa_log_info(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY: %s\n", strerror(errno)); + s->get_latency = NULL; + return 0; + } + + r += pa_bytes_to_usec(arg, &s->sample_spec); + + if (u->memchunk.memblock) + r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec); + + return r; +} + +static pa_usec_t source_get_latency_cb(pa_source *s) { + struct userdata *u = s->userdata; + audio_buf_info info; + assert(s && u && u->source); + + if (!u->use_getispace) + return 0; + + if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { + u->use_getispace = 0; + return 0; + } + + if (info.bytes <= 0) + return 0; + + return pa_bytes_to_usec(info.bytes, &s->sample_spec); +} + +static int sink_get_hw_volume(pa_sink *s) { + struct userdata *u = s->userdata; + char cv[PA_CVOLUME_SNPRINT_MAX]; + unsigned vol; + + if (ioctl(u->fd, SOUND_MIXER_READ_PCM, &vol) < 0) { + pa_log_info(__FILE__": device doesn't support reading mixer settings: %s\n", strerror(errno)); + s->get_hw_volume = NULL; + return -1; + } + + s->hw_volume.values[0] = ((vol & 0xFF) * PA_VOLUME_NORM) / 100; + + if ((s->hw_volume.channels = s->sample_spec.channels) >= 2) + s->hw_volume.values[1] = (((vol >> 8) & 0xFF) * PA_VOLUME_NORM) / 100; + + pa_log_info(__FILE__": Read mixer settings: %s\n", pa_cvolume_snprint(cv, sizeof(cv), &s->hw_volume)); + return 0; +} + +static int sink_set_hw_volume(pa_sink *s) { + struct userdata *u = s->userdata; + char cv[PA_CVOLUME_SNPRINT_MAX]; + unsigned vol; + + vol = (s->hw_volume.values[0]*100)/PA_VOLUME_NORM; + + if (s->sample_spec.channels >= 2) + vol |= ((s->hw_volume.values[1]*100)/PA_VOLUME_NORM) << 8; + + if (ioctl(u->fd, SOUND_MIXER_WRITE_PCM, &vol) < 0) { + pa_log_info(__FILE__": device doesn't support writing mixer settings: %s\n", strerror(errno)); + s->set_hw_volume = NULL; + return -1; + } + + pa_log_info(__FILE__": Wrote mixer settings: %s\n", pa_cvolume_snprint(cv, sizeof(cv), &s->hw_volume)); + return 0; +} + +int pa__init(pa_core *c, pa_module*m) { + struct audio_buf_info info; + struct userdata *u = NULL; + const char *p; + int fd = -1; + int nfrags, frag_size, in_frag_size, out_frag_size; + int mode; + int record = 1, playback = 1; + pa_sample_spec ss; + pa_modargs *ma = NULL; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments.\n"); + goto fail; + } + + if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { + pa_log(__FILE__": record= and playback= expect numeric argument.\n"); + goto fail; + } + + if (!playback && !record) { + pa_log(__FILE__": neither playback nor record enabled for device.\n"); + goto fail; + } + + mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); + + nfrags = 12; + frag_size = 1024; + if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { + pa_log(__FILE__": failed to parse fragments arguments\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": failed to parse sample specification\n"); + goto fail; + } + + if ((fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, NULL)) < 0) + goto fail; + + pa_log_info(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + + if (nfrags >= 2 && frag_size >= 1) + if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) + goto fail; + + if (pa_oss_auto_format(fd, &ss) < 0) + goto fail; + + if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) { + pa_log(__FILE__": SNDCTL_DSP_GETBLKSIZE: %s\n", strerror(errno)); + goto fail; + } + assert(frag_size); + in_frag_size = out_frag_size = frag_size; + + u = pa_xmalloc(sizeof(struct userdata)); + u->core = c; + u->use_getospace = u->use_getispace = 0; + + if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { + pa_log_info(__FILE__": input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + in_frag_size = info.fragsize; + u->use_getispace = 1; + } + + if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) { + pa_log_info(__FILE__": output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + out_frag_size = info.fragsize; + u->use_getospace = 1; + } + + if (mode != O_WRONLY) { + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); + assert(u->source); + u->source->userdata = u; + u->source->notify = source_notify_cb; + u->source->get_latency = source_get_latency_cb; + pa_source_set_owner(u->source, m); + u->source->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); + } else + u->source = NULL; + + if (mode != O_RDONLY) { + u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); + assert(u->sink); + u->sink->get_latency = sink_get_latency_cb; + u->sink->get_hw_volume = sink_get_hw_volume; + u->sink->set_hw_volume = sink_set_hw_volume; + u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); + } else + u->sink = NULL; + + assert(u->source || u->sink); + + u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : -1); + assert(u->io); + pa_iochannel_set_callback(u->io, io_callback, u); + u->fd = fd; + + u->memchunk.memblock = NULL; + u->memchunk.length = 0; + u->sample_size = pa_frame_size(&ss); + + u->out_fragment_size = out_frag_size; + u->in_fragment_size = in_frag_size; + u->silence.memblock = pa_memblock_new(u->silence.length = u->out_fragment_size, u->core->memblock_stat); + assert(u->silence.memblock); + pa_silence_memblock(u->silence.memblock, &ss); + u->silence.index = 0; + + u->module = m; + m->userdata = u; + + pa_modargs_free(ma); + + /* + * Some crappy drivers do not start the recording until we read something. + * Without this snippet, poll will never register the fd as ready. + */ + if (u->source) { + char buf[u->sample_size]; + read(u->fd, buf, u->sample_size); + } + + /* Read mixer settings */ + if (u->sink) + sink_get_hw_volume(u->sink); + + return 0; + +fail: + if (fd >= 0) + close(fd); + + if (ma) + pa_modargs_free(ma); + + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + if (u->silence.memblock) + pa_memblock_unref(u->silence.memblock); + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + } + + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + } + + pa_iochannel_free(u->io); + pa_xfree(u); +} diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c new file mode 100644 index 00000000..6ace377f --- /dev/null +++ b/src/modules/module-pipe-sink.c @@ -0,0 +1,237 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "module-pipe-sink-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("UNIX pipe sink") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink_name= file= format= channels= rate=") + +#define DEFAULT_FIFO_NAME "/tmp/music.output" +#define DEFAULT_SINK_NAME "fifo_output" + +struct userdata { + pa_core *core; + + char *filename; + + pa_sink *sink; + pa_iochannel *io; + pa_defer_event *defer_event; + + pa_memchunk memchunk; + pa_module *module; +}; + +static const char* const valid_modargs[] = { + "file", + "rate", + "format", + "channels", + "sink_name", + NULL +}; + +static void do_write(struct userdata *u) { + ssize_t r; + assert(u); + + u->core->mainloop->defer_enable(u->defer_event, 0); + + if (!pa_iochannel_is_writable(u->io)) + return; + + pa_module_set_used(u->module, pa_idxset_size(u->sink->inputs) + pa_idxset_size(u->sink->monitor_source->outputs)); + + if (!u->memchunk.length) + if (pa_sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0) + return; + + assert(u->memchunk.memblock && u->memchunk.length); + + if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + return; + } + + u->memchunk.index += r; + u->memchunk.length -= r; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + } +} + +static void notify_cb(pa_sink*s) { + struct userdata *u = s->userdata; + assert(s && u); + + if (pa_iochannel_is_writable(u->io)) + u->core->mainloop->defer_enable(u->defer_event, 1); +} + +static pa_usec_t get_latency_cb(pa_sink *s) { + struct userdata *u = s->userdata; + assert(s && u); + + return u->memchunk.memblock ? pa_bytes_to_usec(u->memchunk.length, &s->sample_spec) : 0; +} + +static void defer_callback(PA_GCC_UNUSED pa_mainloop_api *m, PA_GCC_UNUSED pa_defer_event*e, void *userdata) { + struct userdata *u = userdata; + assert(u); + do_write(u); +} + +static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { + struct userdata *u = userdata; + assert(u); + do_write(u); +} + +int pa__init(pa_core *c, pa_module*m) { + struct userdata *u = NULL; + struct stat st; + const char *p; + int fd = -1; + pa_sample_spec ss; + pa_modargs *ma = NULL; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": invalid sample format specification\n"); + goto fail; + } + + mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777); + + if ((fd = open(p, O_RDWR)) < 0) { + pa_log(__FILE__": open('%s'): %s\n", p, strerror(errno)); + goto fail; + } + + pa_fd_set_cloexec(fd, 1); + + if (fstat(fd, &st) < 0) { + pa_log(__FILE__": fstat('%s'): %s\n", p, strerror(errno)); + goto fail; + } + + if (!S_ISFIFO(st.st_mode)) { + pa_log(__FILE__": '%s' is not a FIFO.\n", p); + goto fail; + } + + u = pa_xmalloc0(sizeof(struct userdata)); + u->filename = pa_xstrdup(p); + u->core = c; + u->module = m; + m->userdata = u; + + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { + pa_log(__FILE__": failed to create sink.\n"); + goto fail; + } + u->sink->notify = notify_cb; + u->sink->get_latency = get_latency_cb; + u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Unix FIFO sink '%s'", p); + assert(u->sink->description); + + u->io = pa_iochannel_new(c->mainloop, -1, fd); + assert(u->io); + pa_iochannel_set_callback(u->io, io_callback, u); + + u->memchunk.memblock = NULL; + u->memchunk.length = 0; + + u->defer_event = c->mainloop->defer_new(c->mainloop, defer_callback, u); + assert(u->defer_event); + c->mainloop->defer_enable(u->defer_event, 0); + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + if (fd >= 0) + close(fd); + + pa__done(c, m); + + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + pa_iochannel_free(u->io); + u->core->mainloop->defer_free(u->defer_event); + + assert(u->filename); + unlink(u->filename); + pa_xfree(u->filename); + + pa_xfree(u); +} diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c new file mode 100644 index 00000000..a7bb0ce7 --- /dev/null +++ b/src/modules/module-pipe-source.c @@ -0,0 +1,210 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "module-pipe-source-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("UNIX pipe source") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("source_name= file= format= channels= rate=") + +#define DEFAULT_FIFO_NAME "/tmp/music.input" +#define DEFAULT_SOURCE_NAME "fifo_input" + +struct userdata { + pa_core *core; + + char *filename; + + pa_source *source; + pa_iochannel *io; + pa_module *module; + pa_memchunk chunk; +}; + +static const char* const valid_modargs[] = { + "file", + "rate", + "channels", + "format", + "source_name", + NULL +}; + +static void do_read(struct userdata *u) { + ssize_t r; + pa_memchunk chunk; + assert(u); + + if (!pa_iochannel_is_readable(u->io)) + return; + + pa_module_set_used(u->module, pa_idxset_size(u->source->outputs)); + + if (!u->chunk.memblock) { + u->chunk.memblock = pa_memblock_new(1024, u->core->memblock_stat); + u->chunk.index = chunk.length = 0; + } + + assert(u->chunk.memblock && u->chunk.memblock->length > u->chunk.index); + if ((r = pa_iochannel_read(u->io, (uint8_t*) u->chunk.memblock->data + u->chunk.index, u->chunk.memblock->length - u->chunk.index)) <= 0) { + pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + return; + } + + u->chunk.length = r; + pa_source_post(u->source, &u->chunk); + u->chunk.index += r; + + if (u->chunk.index >= u->chunk.memblock->length) { + u->chunk.index = u->chunk.length = 0; + pa_memblock_unref(u->chunk.memblock); + u->chunk.memblock = NULL; + } +} + +static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { + struct userdata *u = userdata; + assert(u); + do_read(u); +} + +int pa__init(pa_core *c, pa_module*m) { + struct userdata *u = NULL; + struct stat st; + const char *p; + int fd = -1; + pa_sample_spec ss; + pa_modargs *ma = NULL; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": invalid sample format specification\n"); + goto fail; + } + + mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777); + + if ((fd = open(p, O_RDWR)) < 0) { + pa_log(__FILE__": open('%s'): %s\n", p, strerror(errno)); + goto fail; + } + + pa_fd_set_cloexec(fd, 1); + + if (fstat(fd, &st) < 0) { + pa_log(__FILE__": fstat('%s'): %s\n", p, strerror(errno)); + goto fail; + } + + if (!S_ISFIFO(st.st_mode)) { + pa_log(__FILE__": '%s' is not a FIFO.\n", p); + goto fail; + } + + u = pa_xmalloc0(sizeof(struct userdata)); + + u->filename = pa_xstrdup(p); + u->core = c; + + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL))) { + pa_log(__FILE__": failed to create source.\n"); + goto fail; + } + u->source->userdata = u; + pa_source_set_owner(u->source, m); + u->source->description = pa_sprintf_malloc("Unix FIFO source '%s'", p); + assert(u->source->description); + + u->io = pa_iochannel_new(c->mainloop, fd, -1); + assert(u->io); + pa_iochannel_set_callback(u->io, io_callback, u); + + u->chunk.memblock = NULL; + u->chunk.index = u->chunk.length = 0; + + u->module = m; + m->userdata = u; + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + if (fd >= 0) + close(fd); + + pa__done(c, m); + + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->chunk.memblock) + pa_memblock_unref(u->chunk.memblock); + + pa_source_disconnect(u->source); + pa_source_unref(u->source); + pa_iochannel_free(u->io); + + assert(u->filename); + unlink(u->filename); + pa_xfree(u->filename); + + pa_xfree(u); +} diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c new file mode 100644 index 00000000..469ddcee --- /dev/null +++ b/src/modules/module-protocol-stub.c @@ -0,0 +1,261 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_TCP_SOCKETS +#define SOCKET_DESCRIPTION "(TCP sockets)" +#define SOCKET_USAGE "port= loopback=" +#elif defined(USE_TCP6_SOCKETS) +#define SOCKET_DESCRIPTION "(TCP/IPv6 sockets)" +#define SOCKET_USAGE "port= loopback=" +#else +#define SOCKET_DESCRIPTION "(UNIX sockets)" +#define SOCKET_USAGE "socket=" +#endif + +#if defined(USE_PROTOCOL_SIMPLE) + #include + #define protocol_new pa_protocol_simple_new + #define protocol_free pa_protocol_simple_free + #define TCPWRAP_SERVICE "polypaudio-simple" + #define IPV4_PORT 4711 + #define UNIX_SOCKET "simple" + #define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record", + #if defined(USE_TCP_SOCKETS) + #include "module-simple-protocol-tcp-symdef.h" + #elif defined(USE_TCP6_SOCKETS) + #include "module-simple-protocol-tcp6-symdef.h" + #else + #include "module-simple-protocol-unix-symdef.h" + #endif + PA_MODULE_DESCRIPTION("Simple protocol "SOCKET_DESCRIPTION) + PA_MODULE_USAGE("rate= format= channels= sink= source= playback= record= "SOCKET_USAGE) +#elif defined(USE_PROTOCOL_CLI) + #include + #define protocol_new pa_protocol_cli_new + #define protocol_free pa_protocol_cli_free + #define TCPWRAP_SERVICE "polypaudio-cli" + #define IPV4_PORT 4712 + #define UNIX_SOCKET "cli" + #define MODULE_ARGUMENTS + #ifdef USE_TCP_SOCKETS + #include "module-cli-protocol-tcp-symdef.h" + #elif defined(USE_TCP6_SOCKETS) + #include "module-cli-protocol-tcp6-symdef.h" + #else + #include "module-cli-protocol-unix-symdef.h" + #endif + PA_MODULE_DESCRIPTION("Command line interface protocol "SOCKET_DESCRIPTION) + PA_MODULE_USAGE(SOCKET_USAGE) +#elif defined(USE_PROTOCOL_HTTP) + #include + #define protocol_new pa_protocol_http_new + #define protocol_free pa_protocol_http_free + #define TCPWRAP_SERVICE "polypaudio-http" + #define IPV4_PORT 4714 + #define UNIX_SOCKET "http" + #define MODULE_ARGUMENTS + #ifdef USE_TCP_SOCKETS + #include "module-http-protocol-tcp-symdef.h" + #elif defined(USE_TCP6_SOCKETS) + #include "module-http-protocol-tcp6-symdef.h" + #else + #include "module-http-protocol-unix-symdef.h" + #endif + PA_MODULE_DESCRIPTION("HTTP "SOCKET_DESCRIPTION) + PA_MODULE_USAGE(SOCKET_USAGE) +#elif defined(USE_PROTOCOL_NATIVE) + #include + #define protocol_new pa_protocol_native_new + #define protocol_free pa_protocol_native_free + #define TCPWRAP_SERVICE "polypaudio-native" + #define IPV4_PORT PA_NATIVE_DEFAULT_PORT + #define UNIX_SOCKET PA_NATIVE_DEFAULT_UNIX_SOCKET + #define MODULE_ARGUMENTS "public", "cookie", + #ifdef USE_TCP_SOCKETS + #include "module-native-protocol-tcp-symdef.h" + #elif defined(USE_TCP6_SOCKETS) + #include "module-native-protocol-tcp6-symdef.h" + #else + #include "module-native-protocol-unix-symdef.h" + #endif + PA_MODULE_DESCRIPTION("Native protocol "SOCKET_DESCRIPTION) + PA_MODULE_USAGE("public= cookie= "SOCKET_USAGE) +#elif defined(USE_PROTOCOL_ESOUND) + #include + #include + #define protocol_new pa_protocol_esound_new + #define protocol_free pa_protocol_esound_free + #define TCPWRAP_SERVICE "esound" + #define IPV4_PORT ESD_DEFAULT_PORT + #define UNIX_SOCKET ESD_UNIX_SOCKET_NAME + #define MODULE_ARGUMENTS "sink", "source", "public", "cookie", + #ifdef USE_TCP_SOCKETS + #include "module-esound-protocol-tcp-symdef.h" + #elif defined(USE_TCP6_SOCKETS) + #include "module-esound-protocol-tcp6-symdef.h" + #else + #include "module-esound-protocol-unix-symdef.h" + #endif + PA_MODULE_DESCRIPTION("ESOUND protocol "SOCKET_DESCRIPTION) + PA_MODULE_USAGE("sink= source= public= cookie= "SOCKET_USAGE) +#else + #error "Broken build system" +#endif + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_VERSION(PACKAGE_VERSION) + +static const char* const valid_modargs[] = { + MODULE_ARGUMENTS +#if defined(USE_TCP_SOCKETS) || defined(USE_TCP6_SOCKETS) + "port", + "loopback", +#else + "socket", +#endif + NULL +}; + +static pa_socket_server *create_socket_server(pa_core *c, pa_modargs *ma) { + pa_socket_server *s; +#if defined(USE_TCP_SOCKETS) || defined(USE_TCP6_SOCKETS) + int loopback = 1; + uint32_t port = IPV4_PORT; + + if (pa_modargs_get_value_boolean(ma, "loopback", &loopback) < 0) { + pa_log(__FILE__": loopback= expects a boolean argument.\n"); + return NULL; + } + + if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) { + pa_log(__FILE__": port= expects a numerical argument between 1 and 65535.\n"); + return NULL; + } + +#ifdef USE_TCP6_SOCKETS + if (!(s = pa_socket_server_new_ipv6(c->mainloop, loopback ? (const uint8_t*) &in6addr_loopback : (const uint8_t*) &in6addr_any, port))) + return NULL; +#else + if (!(s = pa_socket_server_new_ipv4(c->mainloop, loopback ? INADDR_LOOPBACK : INADDR_ANY, port, TCPWRAP_SERVICE))) + return NULL; +#endif + +#else + int r; + const char *v; + char tmp[PATH_MAX]; + + v = pa_modargs_get_value(ma, "socket", UNIX_SOCKET); + assert(v); + + pa_runtime_path(v, tmp, sizeof(tmp)); + + if (pa_make_secure_parent_dir(tmp) < 0) { + pa_log(__FILE__": Failed to create secure socket directory.\n"); + return NULL; + } + + if ((r = pa_unix_socket_remove_stale(tmp)) < 0) { + pa_log(__FILE__": Failed to remove stale UNIX socket '%s': %s\n", tmp, strerror(errno)); + return NULL; + } + + if (r) + pa_log(__FILE__": Removed stale UNIX socket '%s'.", tmp); + + if (!(s = pa_socket_server_new_unix(c->mainloop, tmp))) + return NULL; + +#endif + return s; +} + +int pa__init(pa_core *c, pa_module*m) { + pa_socket_server *s; + pa_modargs *ma = NULL; + int ret = -1; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": Failed to parse module arguments\n"); + goto finish; + } + + if (!(s = create_socket_server(c, ma))) + goto finish; + + if (!(m->userdata = protocol_new(c, s, m, ma))) { + pa_socket_server_unref(s); + goto finish; + } + + ret = 0; + +finish: + if (ma) + pa_modargs_free(ma); + + return ret; +} + +void pa__done(pa_core *c, pa_module*m) { + assert(c && m); + +#if defined(USE_PROTOCOL_ESOUND) + if (remove (ESD_UNIX_SOCKET_NAME) != 0) + pa_log("%s: Failed to remove %s : %s.\n", __FILE__, ESD_UNIX_SOCKET_NAME, strerror (errno)); + if (remove (ESD_UNIX_SOCKET_DIR) != 0) + pa_log("%s: Failed to remove %s : %s.\n", __FILE__, ESD_UNIX_SOCKET_DIR, strerror (errno)); +#endif + + protocol_free(m->userdata); +} diff --git a/src/modules/module-sine.c b/src/modules/module-sine.c new file mode 100644 index 00000000..446e3974 --- /dev/null +++ b/src/modules/module-sine.c @@ -0,0 +1,182 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "module-sine-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Sine wave generator") +PA_MODULE_USAGE("sink= frequency=") +PA_MODULE_VERSION(PACKAGE_VERSION) + +struct userdata { + pa_core *core; + pa_module *module; + pa_sink_input *sink_input; + pa_memblock *memblock; + size_t peek_index; +}; + +static const char* const valid_modargs[] = { + "sink", + "frequency", + NULL, +}; + +static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { + struct userdata *u; + assert(i && chunk && i->userdata); + u = i->userdata; + + chunk->memblock = pa_memblock_ref(u->memblock); + chunk->index = u->peek_index; + chunk->length = u->memblock->length - u->peek_index; + return 0; +} + +static void sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { + struct userdata *u; + assert(i && chunk && length && i->userdata); + u = i->userdata; + + assert(chunk->memblock == u->memblock && length <= u->memblock->length-u->peek_index); + + u->peek_index += length; + + if (u->peek_index >= u->memblock->length) + u->peek_index = 0; +} + +static void sink_input_kill(pa_sink_input *i) { + struct userdata *u; + assert(i && i->userdata); + u = i->userdata; + + pa_sink_input_disconnect(u->sink_input); + pa_sink_input_unref(u->sink_input); + u->sink_input = NULL; + + pa_module_unload_request(u->module); +} + +static void calc_sine(float *f, size_t l, float freq) { + size_t i; + + l /= sizeof(float); + + for (i = 0; i < l; i++) + f[i] = (float) sin((double) i/l*M_PI*2*freq)/2; +} + +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; + struct userdata *u; + pa_sink *sink; + const char *sink_name; + pa_sample_spec ss; + uint32_t frequency; + char t[256]; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": Failed to parse module arguments\n"); + goto fail; + } + + m->userdata = u = pa_xmalloc(sizeof(struct userdata)); + u->core = c; + u->module = m; + u->sink_input = NULL; + u->memblock = NULL; + + sink_name = pa_modargs_get_value(ma, "sink", NULL); + + if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) { + pa_log(__FILE__": No such sink.\n"); + goto fail; + } + + ss.format = PA_SAMPLE_FLOAT32; + ss.rate = sink->sample_spec.rate; + ss.channels = 1; + + frequency = 440; + if (pa_modargs_get_value_u32(ma, "frequency", &frequency) < 0 || frequency < 1 || frequency > ss.rate/2) { + pa_log(__FILE__": Invalid frequency specification\n"); + goto fail; + } + + u->memblock = pa_memblock_new(pa_bytes_per_second(&ss), c->memblock_stat); + calc_sine(u->memblock->data, u->memblock->length, frequency); + + snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency); + if (!(u->sink_input = pa_sink_input_new(sink, __FILE__, t, &ss, NULL, 0, -1))) + goto fail; + + u->sink_input->peek = sink_input_peek; + u->sink_input->drop = sink_input_drop; + u->sink_input->kill = sink_input_kill; + u->sink_input->userdata = u; + u->sink_input->owner = m; + + u->peek_index = 0; + + pa_modargs_free(ma); + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + pa__done(c, m); + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u = m->userdata; + assert(c && m); + + if (!u) + return; + + if (u->sink_input) { + pa_sink_input_disconnect(u->sink_input); + pa_sink_input_unref(u->sink_input); + } + + if (u->memblock) + pa_memblock_unref(u->memblock); + pa_xfree(u); +} + diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c new file mode 100644 index 00000000..e0745fc0 --- /dev/null +++ b/src/modules/module-solaris.c @@ -0,0 +1,488 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-solaris-symdef.h" + +PA_MODULE_AUTHOR("Pierre Ossman") +PA_MODULE_DESCRIPTION("Solaris Sink/Source") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= buffer_size=") + +struct userdata { + pa_sink *sink; + pa_source *source; + pa_iochannel *io; + pa_core *core; + pa_signal_event *sig; + + pa_memchunk memchunk, silence; + + uint32_t sample_size; + uint32_t buffer_size; + unsigned int written_bytes, read_bytes; + + int fd; + pa_module *module; +}; + +static const char* const valid_modargs[] = { + "sink_name", + "source_name", + "device", + "record", + "playback", + "buffer_size", + "format", + "rate", + "channels", + NULL +}; + +#define DEFAULT_SINK_NAME "solaris_output" +#define DEFAULT_SOURCE_NAME "solaris_input" +#define DEFAULT_DEVICE "/dev/audio" + +#define CHUNK_SIZE 2048 + +static void update_usage(struct userdata *u) { + pa_module_set_used(u->module, + (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0) + + (u->source ? pa_idxset_size(u->source->outputs) : 0)); +} + +static void do_write(struct userdata *u) { + audio_info_t info; + int err; + pa_memchunk *memchunk; + size_t len; + ssize_t r; + + assert(u); + + if (!u->sink || !pa_iochannel_is_writable(u->io)) + return; + + update_usage(u); + + err = ioctl(u->fd, AUDIO_GETINFO, &info); + assert(err >= 0); + + /* + * Since we cannot modify the size of the output buffer we fake it + * by not filling it more than u->buffer_size. + */ + len = u->buffer_size; + len -= u->written_bytes - (info.play.samples * u->sample_size); + + /* + * Do not fill more than half the buffer in one chunk since we only + * get notifications upon completion of entire chunks. + */ + if (len > (u->buffer_size / 2)) + len = u->buffer_size / 2; + + if (len < u->sample_size) + return; + + memchunk = &u->memchunk; + + if (!memchunk->length) + if (pa_sink_render(u->sink, len, memchunk) < 0) + memchunk = &u->silence; + + assert(memchunk->memblock); + assert(memchunk->memblock->data); + assert(memchunk->length); + + if (memchunk->length < len) + len = memchunk->length; + + if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, len)) < 0) { + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + return; + } + + if (memchunk == &u->silence) + assert(r % u->sample_size == 0); + else { + u->memchunk.index += r; + u->memchunk.length -= r; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + } + } + + u->written_bytes += r; + + /* + * Write 0 bytes which will generate a SIGPOLL when "played". + */ + if (write(u->fd, NULL, 0) < 0) { + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + return; + } +} + +static void do_read(struct userdata *u) { + pa_memchunk memchunk; + int err, l; + ssize_t r; + assert(u); + + if (!u->source || !pa_iochannel_is_readable(u->io)) + return; + + update_usage(u); + + err = ioctl(u->fd, I_NREAD, &l); + assert(err >= 0); + + memchunk.memblock = pa_memblock_new(l, u->core->memblock_stat); + assert(memchunk.memblock); + if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { + pa_memblock_unref(memchunk.memblock); + if (errno != EAGAIN) + pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + return; + } + + assert(r <= (ssize_t) memchunk.memblock->length); + memchunk.length = memchunk.memblock->length = r; + memchunk.index = 0; + + pa_source_post(u->source, &memchunk); + pa_memblock_unref(memchunk.memblock); + + u->read_bytes += r; +} + +static void io_callback(pa_iochannel *io, void*userdata) { + struct userdata *u = userdata; + assert(u); + do_write(u); + do_read(u); +} + +void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata) { + struct userdata *u = userdata; + assert(u); + do_write(u); +} + +static pa_usec_t sink_get_latency_cb(pa_sink *s) { + pa_usec_t r = 0; + audio_info_t info; + int err; + struct userdata *u = s->userdata; + assert(s && u && u->sink); + + err = ioctl(u->fd, AUDIO_GETINFO, &info); + assert(err >= 0); + + r += pa_bytes_to_usec(u->written_bytes, &s->sample_spec); + r -= pa_bytes_to_usec(info.play.samples * u->sample_size, &s->sample_spec); + + if (u->memchunk.memblock) + r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec); + + return r; +} + +static pa_usec_t source_get_latency_cb(pa_source *s) { + pa_usec_t r = 0; + struct userdata *u = s->userdata; + audio_info_t info; + int err; + assert(s && u && u->source); + + err = ioctl(u->fd, AUDIO_GETINFO, &info); + assert(err >= 0); + + r += pa_bytes_to_usec(info.record.samples * u->sample_size, &s->sample_spec); + r -= pa_bytes_to_usec(u->read_bytes, &s->sample_spec); + + return r; +} + +static int pa_solaris_auto_format(int fd, int mode, pa_sample_spec *ss) { + audio_info_t info; + + AUDIO_INITINFO(&info); + + if (mode != O_RDONLY) { + info.play.sample_rate = ss->rate; + info.play.channels = ss->channels; + switch (ss->format) { + case PA_SAMPLE_U8: + info.play.precision = 8; + info.play.encoding = AUDIO_ENCODING_LINEAR; + break; + case PA_SAMPLE_ALAW: + info.play.precision = 8; + info.play.encoding = AUDIO_ENCODING_ALAW; + break; + case PA_SAMPLE_ULAW: + info.play.precision = 8; + info.play.encoding = AUDIO_ENCODING_ULAW; + break; + case PA_SAMPLE_S16NE: + info.play.precision = 16; + info.play.encoding = AUDIO_ENCODING_LINEAR; + break; + default: + return -1; + } + } + + if (mode != O_WRONLY) { + info.record.sample_rate = ss->rate; + info.record.channels = ss->channels; + switch (ss->format) { + case PA_SAMPLE_U8: + info.record.precision = 8; + info.record.encoding = AUDIO_ENCODING_LINEAR; + break; + case PA_SAMPLE_ALAW: + info.record.precision = 8; + info.record.encoding = AUDIO_ENCODING_ALAW; + break; + case PA_SAMPLE_ULAW: + info.record.precision = 8; + info.record.encoding = AUDIO_ENCODING_ULAW; + break; + case PA_SAMPLE_S16NE: + info.record.precision = 16; + info.record.encoding = AUDIO_ENCODING_LINEAR; + break; + default: + return -1; + } + } + + if (ioctl(fd, AUDIO_SETINFO, &info) < 0) { + if (errno == EINVAL) + pa_log(__FILE__": AUDIO_SETINFO: Unsupported sample format.\n"); + else + pa_log(__FILE__": AUDIO_SETINFO: %s\n", strerror(errno)); + return -1; + } + + return 0; +} + +static int pa_solaris_set_buffer(int fd, int buffer_size) { + audio_info_t info; + + AUDIO_INITINFO(&info); + + info.record.buffer_size = buffer_size; + + if (ioctl(fd, AUDIO_SETINFO, &info) < 0) { + if (errno == EINVAL) + pa_log(__FILE__": AUDIO_SETINFO: Unsupported buffer size.\n"); + else + pa_log(__FILE__": AUDIO_SETINFO: %s\n", strerror(errno)); + return -1; + } + + return 0; +} + +int pa__init(pa_core *c, pa_module*m) { + struct userdata *u = NULL; + const char *p; + int fd = -1; + int buffer_size; + int mode; + int record = 1, playback = 1; + pa_sample_spec ss; + pa_modargs *ma = NULL; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments.\n"); + goto fail; + } + + if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { + pa_log(__FILE__": record= and playback= expect numeric argument.\n"); + goto fail; + } + + if (!playback && !record) { + pa_log(__FILE__": neither playback nor record enabled for device.\n"); + goto fail; + } + + mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); + + buffer_size = 16384; + if (pa_modargs_get_value_s32(ma, "buffer_size", &buffer_size) < 0) { + pa_log(__FILE__": failed to parse buffer size argument\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": failed to parse sample specification\n"); + goto fail; + } + + if ((fd = open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), mode | O_NONBLOCK)) < 0) + goto fail; + + pa_log_info(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + + if (pa_solaris_auto_format(fd, mode, &ss) < 0) + goto fail; + + if ((mode != O_WRONLY) && (buffer_size >= 1)) + if (pa_solaris_set_buffer(fd, buffer_size) < 0) + goto fail; + + u = pa_xmalloc(sizeof(struct userdata)); + u->core = c; + + if (mode != O_WRONLY) { + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); + assert(u->source); + u->source->userdata = u; + u->source->get_latency = source_get_latency_cb; + pa_source_set_owner(u->source, m); + u->source->description = pa_sprintf_malloc("Solaris PCM on '%s'", p); + } else + u->source = NULL; + + if (mode != O_RDONLY) { + u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); + assert(u->sink); + u->sink->get_latency = sink_get_latency_cb; + u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Solaris PCM on '%s'", p); + } else + u->sink = NULL; + + assert(u->source || u->sink); + + u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : 0); + assert(u->io); + pa_iochannel_set_callback(u->io, io_callback, u); + u->fd = fd; + + u->memchunk.memblock = NULL; + u->memchunk.length = 0; + u->sample_size = pa_frame_size(&ss); + u->buffer_size = buffer_size; + + u->silence.memblock = pa_memblock_new(u->silence.length = CHUNK_SIZE, u->core->memblock_stat); + assert(u->silence.memblock); + pa_silence_memblock(u->silence.memblock, &ss); + u->silence.index = 0; + + u->written_bytes = 0; + u->read_bytes = 0; + + u->module = m; + m->userdata = u; + + u->sig = pa_signal_new(SIGPOLL, sig_callback, u); + assert(u->sig); + ioctl(u->fd, I_SETSIG, S_MSG); + + pa_modargs_free(ma); + + return 0; + +fail: + if (fd >= 0) + close(fd); + + if (ma) + pa_modargs_free(ma); + + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + ioctl(u->fd, I_SETSIG, 0); + pa_signal_free(u->sig); + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + if (u->silence.memblock) + pa_memblock_unref(u->silence.memblock); + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + } + + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + } + + pa_iochannel_free(u->io); + pa_xfree(u); +} diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c new file mode 100644 index 00000000..5ee10fda --- /dev/null +++ b/src/modules/module-tunnel.c @@ -0,0 +1,688 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef TUNNEL_SINK +#include "module-tunnel-sink-symdef.h" +PA_MODULE_DESCRIPTION("Tunnel module for sinks") +PA_MODULE_USAGE("server=
    sink= cookie= format= channels= rate= sink_name=") +#else +#include "module-tunnel-source-symdef.h" +PA_MODULE_DESCRIPTION("Tunnel module for sources") +PA_MODULE_USAGE("server=
    source= cookie= format= channels= rate= source_name=") +#endif + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_VERSION(PACKAGE_VERSION) + +#define DEFAULT_SINK_NAME "tunnel" +#define DEFAULT_SOURCE_NAME "tunnel" + +#define DEFAULT_TLENGTH (44100*2*2/10) //(10240*8) +#define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2) +#define DEFAULT_MINREQ 512 +#define DEFAULT_PREBUF (DEFAULT_TLENGTH-DEFAULT_MINREQ) +#define DEFAULT_FRAGSIZE 1024 + +#define DEFAULT_TIMEOUT 5 + +#define LATENCY_INTERVAL 10 + +static const char* const valid_modargs[] = { + "server", + "cookie", + "format", + "channels", + "rate", +#ifdef TUNNEL_SINK + "sink_name", + "sink", +#else + "source_name", + "source", +#endif + NULL, +}; + +static void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); + +#ifdef TUNNEL_SINK +static void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +#endif + +static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { +#ifdef TUNNEL_SINK + [PA_COMMAND_REQUEST] = command_request, +#endif + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = command_stream_killed, + [PA_COMMAND_RECORD_STREAM_KILLED] = command_stream_killed +}; + +struct userdata { + pa_socket_client *client; + pa_pstream *pstream; + pa_pdispatch *pdispatch; + + char *server_name; +#ifdef TUNNEL_SINK + char *sink_name; + pa_sink *sink; + uint32_t requested_bytes; +#else + char *source_name; + pa_source *source; +#endif + + pa_module *module; + pa_core *core; + + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; + + uint32_t ctag; + uint32_t device_index; + uint32_t channel; + + pa_usec_t host_latency; + + pa_time_event *time_event; + + int auth_cookie_in_property; +}; + +static void close_stuff(struct userdata *u) { + assert(u); + + if (u->pstream) { + pa_pstream_close(u->pstream); + pa_pstream_unref(u->pstream); + u->pstream = NULL; + } + + if (u->pdispatch) { + pa_pdispatch_unref(u->pdispatch); + u->pdispatch = NULL; + } + + if (u->client) { + pa_socket_client_unref(u->client); + u->client = NULL; + } + +#ifdef TUNNEL_SINK + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + u->sink = NULL; + } +#else + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + u->source = NULL; + } +#endif + + if (u->time_event) { + u->core->mainloop->time_free(u->time_event); + u->time_event = NULL; + } +} + +static void die(struct userdata *u) { + assert(u); + close_stuff(u); + pa_module_unload_request(u->module); +} + +static void command_stream_killed(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + assert(pd && t && u && u->pdispatch == pd); + + pa_log(__FILE__": stream killed\n"); + die(u); +} + +#ifdef TUNNEL_SINK +static void send_prebuf_request(struct userdata *u) { + pa_tagstruct *t; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_PREBUF_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, u->ctag++); + pa_tagstruct_putu32(t, u->channel); + pa_pstream_send_tagstruct(u->pstream, t); +} + +static void send_bytes(struct userdata *u) { + assert(u); + + if (!u->pstream) + return; + + while (u->requested_bytes > 0) { + pa_memchunk chunk; + if (pa_sink_render(u->sink, u->requested_bytes, &chunk) < 0) { + + + if (u->requested_bytes >= DEFAULT_TLENGTH-DEFAULT_PREBUF) + send_prebuf_request(u); + + return; + } + + pa_pstream_send_memblock(u->pstream, u->channel, 0, &chunk); + pa_memblock_unref(chunk.memblock); + + if (chunk.length > u->requested_bytes) + u->requested_bytes = 0; + else + u->requested_bytes -= chunk.length; + } +} + +static void command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + uint32_t bytes, channel; + assert(pd && command == PA_COMMAND_REQUEST && t && u && u->pdispatch == pd); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + pa_tagstruct_getu32(t, &bytes) < 0 || + !pa_tagstruct_eof(t)) { + pa_log(__FILE__": invalid protocol reply\n"); + die(u); + return; + } + + if (channel != u->channel) { + pa_log(__FILE__": recieved data for invalid channel\n"); + die(u); + return; + } + + u->requested_bytes += bytes; + send_bytes(u); +} + +#endif + +static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + pa_usec_t buffer_usec, sink_usec, source_usec, transport_usec; + int playing; + uint32_t queue_length; + uint64_t counter; + struct timeval local, remote, now; + assert(pd && u); + + if (command != PA_COMMAND_REPLY) { + if (command == PA_COMMAND_ERROR) + pa_log(__FILE__": failed to get latency.\n"); + else + pa_log(__FILE__": protocol error.\n"); + die(u); + return; + } + + if (pa_tagstruct_get_usec(t, &buffer_usec) < 0 || + pa_tagstruct_get_usec(t, &sink_usec) < 0 || + pa_tagstruct_get_usec(t, &source_usec) < 0 || + pa_tagstruct_get_boolean(t, &playing) < 0 || + pa_tagstruct_getu32(t, &queue_length) < 0 || + pa_tagstruct_get_timeval(t, &local) < 0 || + pa_tagstruct_get_timeval(t, &remote) < 0 || + pa_tagstruct_getu64(t, &counter) < 0 || + !pa_tagstruct_eof(t)) { + pa_log(__FILE__": invalid reply.\n"); + die(u); + return; + } + + pa_gettimeofday(&now); + + if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) { + /* local and remote seem to have synchronized clocks */ +#ifdef TUNNEL_SINK + transport_usec = pa_timeval_diff(&remote, &local); +#else + transport_usec = pa_timeval_diff(&now, &remote); +#endif + } else + transport_usec = pa_timeval_diff(&now, &local)/2; + +#ifdef TUNNEL_SINK + u->host_latency = sink_usec + transport_usec; +#else + u->host_latency = source_usec + transport_usec; + if (u->host_latency > sink_usec) + u->host_latency -= sink_usec; + else + u->host_latency = 0; +#endif + +/* pa_log(__FILE__": estimated host latency: %0.0f usec\n", (double) u->host_latency); */ +} + +static void request_latency(struct userdata *u) { + pa_tagstruct *t; + struct timeval now; + uint32_t tag; + assert(u); + + t = pa_tagstruct_new(NULL, 0); +#ifdef TUNNEL_SINK + pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); +#else + pa_tagstruct_putu32(t, PA_COMMAND_GET_RECORD_LATENCY); +#endif + pa_tagstruct_putu32(t, tag = u->ctag++); + pa_tagstruct_putu32(t, u->channel); + + pa_gettimeofday(&now); + pa_tagstruct_put_timeval(t, &now); + pa_tagstruct_putu64(t, 0); + + pa_pstream_send_tagstruct(u->pstream, t); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u); +} + +static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + assert(pd && u && u->pdispatch == pd); + + if (command != PA_COMMAND_REPLY) { + if (command == PA_COMMAND_ERROR) + pa_log(__FILE__": failed to create stream.\n"); + else + pa_log(__FILE__": protocol error.\n"); + die(u); + return; + } + + if (pa_tagstruct_getu32(t, &u->channel) < 0 || + pa_tagstruct_getu32(t, &u->device_index) < 0 || +#ifdef TUNNEL_SINK + pa_tagstruct_getu32(t, &u->requested_bytes) < 0 || +#endif + !pa_tagstruct_eof(t)) { + pa_log(__FILE__": invalid reply.\n"); + die(u); + return; + } + + request_latency(u); +#ifdef TUNNEL_SINK + send_bytes(u); +#endif +} + +static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + pa_tagstruct *reply; + char name[256], un[128], hn[128]; + assert(pd && u && u->pdispatch == pd); + + if (command != PA_COMMAND_REPLY || !pa_tagstruct_eof(t)) { + if (command == PA_COMMAND_ERROR) + pa_log(__FILE__": failed to authenticate\n"); + else + pa_log(__FILE__": protocol error.\n"); + die(u); + return; + } +#ifdef TUNNEL_SINK + snprintf(name, sizeof(name), "Tunnel from host '%s', user '%s', sink '%s'", + pa_get_host_name(hn, sizeof(hn)), + pa_get_user_name(un, sizeof(un)), + u->sink->name); +#else + snprintf(name, sizeof(name), "Tunnel from host '%s', user '%s', source '%s'", + pa_get_host_name(hn, sizeof(hn)), + pa_get_user_name(un, sizeof(un)), + u->source->name); +#endif + + reply = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME); + pa_tagstruct_putu32(reply, tag = u->ctag++); + pa_tagstruct_puts(reply, name); + pa_pstream_send_tagstruct(u->pstream, reply); + /* We ignore the server's reply here */ + + reply = pa_tagstruct_new(NULL, 0); +#ifdef TUNNEL_SINK + pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_PLAYBACK_STREAM); + pa_tagstruct_putu32(reply, tag = u->ctag++); + pa_tagstruct_puts(reply, name); + pa_tagstruct_put_sample_spec(reply, &u->sink->sample_spec); + pa_tagstruct_putu32(reply, PA_INVALID_INDEX); + pa_tagstruct_puts(reply, u->sink_name); + pa_tagstruct_putu32(reply, DEFAULT_MAXLENGTH); + pa_tagstruct_put_boolean(reply, 0); + pa_tagstruct_putu32(reply, DEFAULT_TLENGTH); + pa_tagstruct_putu32(reply, DEFAULT_PREBUF); + pa_tagstruct_putu32(reply, DEFAULT_MINREQ); + pa_tagstruct_putu32(reply, PA_VOLUME_NORM); +#else + pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_RECORD_STREAM); + pa_tagstruct_putu32(reply, tag = u->ctag++); + pa_tagstruct_puts(reply, name); + pa_tagstruct_put_sample_spec(reply, &u->source->sample_spec); + pa_tagstruct_putu32(reply, PA_INVALID_INDEX); + pa_tagstruct_puts(reply, u->source_name); + pa_tagstruct_putu32(reply, DEFAULT_MAXLENGTH); + pa_tagstruct_put_boolean(reply, 0); + pa_tagstruct_putu32(reply, DEFAULT_FRAGSIZE); +#endif + + pa_pstream_send_tagstruct(u->pstream, reply); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, u); +} + +static void pstream_die_callback(pa_pstream *p, void *userdata) { + struct userdata *u = userdata; + assert(p && u); + + pa_log(__FILE__": stream died.\n"); + die(u); +} + + +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { + struct userdata *u = userdata; + assert(p && packet && u); + + if (pa_pdispatch_run(u->pdispatch, packet, u) < 0) { + pa_log(__FILE__": invalid packet\n"); + die(u); + } +} + +#ifndef TUNNEL_SINK +static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata) { + struct userdata *u = userdata; + assert(p && chunk && u); + + if (channel != u->channel) { + pa_log(__FILE__": recieved memory block on bad channel.\n"); + die(u); + return; + } + + pa_source_post(u->source, chunk); +} +#endif + +static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata) { + struct userdata *u = userdata; + pa_tagstruct *t; + uint32_t tag; + assert(sc && u && u->client == sc); + + pa_socket_client_unref(u->client); + u->client = NULL; + + if (!io) { + pa_log(__FILE__": connection failed.\n"); + pa_module_unload_request(u->module); + return; + } + + u->pstream = pa_pstream_new(u->core->mainloop, io, u->core->memblock_stat); + u->pdispatch = pa_pdispatch_new(u->core->mainloop, command_table, PA_COMMAND_MAX); + + pa_pstream_set_die_callback(u->pstream, pstream_die_callback, u); + pa_pstream_set_recieve_packet_callback(u->pstream, pstream_packet_callback, u); +#ifndef TUNNEL_SINK + pa_pstream_set_recieve_memblock_callback(u->pstream, pstream_memblock_callback, u); +#endif + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_AUTH); + pa_tagstruct_putu32(t, tag = u->ctag++); + pa_tagstruct_put_arbitrary(t, u->auth_cookie, sizeof(u->auth_cookie)); + pa_pstream_send_tagstruct(u->pstream, t); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, u); + +} + +#ifdef TUNNEL_SINK +static void sink_notify(pa_sink*sink) { + struct userdata *u; + assert(sink && sink->userdata); + u = sink->userdata; + + send_bytes(u); +} + +static pa_usec_t sink_get_latency(pa_sink *sink) { + struct userdata *u; + uint32_t l; + pa_usec_t usec = 0; + assert(sink && sink->userdata); + u = sink->userdata; + + l = DEFAULT_TLENGTH; + + if (l > u->requested_bytes) { + l -= u->requested_bytes; + usec += pa_bytes_to_usec(l, &u->sink->sample_spec); + } + + usec += u->host_latency; + + return usec; +} +#else +static pa_usec_t source_get_latency(pa_source *source) { + struct userdata *u; + assert(source && source->userdata); + u = source->userdata; + + return u->host_latency; +} +#endif + +static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + struct userdata *u = userdata; + struct timeval ntv; + assert(m && e && u); + + request_latency(u); + + pa_gettimeofday(&ntv); + ntv.tv_sec += LATENCY_INTERVAL; + m->time_restart(e, &ntv); +} + +static int load_key(struct userdata *u, const char*fn) { + assert(u); + + u->auth_cookie_in_property = 0; + + if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { + pa_log_debug(__FILE__": using already loaded auth cookie.\n"); + pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); + u->auth_cookie_in_property = 1; + return 0; + } + + if (!fn) + fn = PA_NATIVE_COOKIE_FILE; + + if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) + return -1; + + pa_log_debug(__FILE__": loading cookie from disk.\n"); + + if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) + u->auth_cookie_in_property = 1; + + return 0; +} + +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; + struct userdata *u = NULL; + pa_sample_spec ss; + struct timeval ntv; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments\n"); + goto fail; + } + + u = pa_xmalloc(sizeof(struct userdata)); + m->userdata = u; + u->module = m; + u->core = c; + u->client = NULL; + u->pdispatch = NULL; + u->pstream = NULL; + u->server_name = NULL; +#ifdef TUNNEL_SINK + u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));; + u->sink = NULL; + u->requested_bytes = 0; +#else + u->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));; + u->source = NULL; +#endif + u->ctag = 1; + u->device_index = u->channel = PA_INVALID_INDEX; + u->host_latency = 0; + u->auth_cookie_in_property = 0; + u->time_event = NULL; + + if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0) + goto fail; + + if (!(u->server_name = pa_xstrdup(pa_modargs_get_value(ma, "server", NULL)))) { + pa_log(__FILE__": no server specified.\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": invalid sample format specification\n"); + goto fail; + } + + if (!(u->client = pa_socket_client_new_string(c->mainloop, u->server_name, PA_NATIVE_DEFAULT_PORT))) { + pa_log(__FILE__": failed to connect to server '%s'\n", u->server_name); + goto fail; + } + + if (!u->client) + goto fail; + + pa_socket_client_set_callback(u->client, on_connection, u); + +#ifdef TUNNEL_SINK + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { + pa_log(__FILE__": failed to create sink.\n"); + goto fail; + } + + u->sink->notify = sink_notify; + u->sink->get_latency = sink_get_latency; + u->sink->userdata = u; + u->sink->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->sink_name ? u->sink_name : "", u->sink_name ? "@" : "", u->server_name); + + pa_sink_set_owner(u->sink, m); +#else + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL))) { + pa_log(__FILE__": failed to create source.\n"); + goto fail; + } + + u->source->get_latency = source_get_latency; + u->source->userdata = u; + u->source->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->source_name ? u->source_name : "", u->source_name ? "@" : "", u->server_name); + + pa_source_set_owner(u->source, m); +#endif + + pa_gettimeofday(&ntv); + ntv.tv_sec += LATENCY_INTERVAL; + u->time_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, u); + + pa_modargs_free(ma); + + return 0; + +fail: + pa__done(c, m); + + if (ma) + pa_modargs_free(ma); + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata* u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + close_stuff(u); + + if (u->auth_cookie_in_property) + pa_authkey_prop_unref(c, PA_NATIVE_COOKIE_PROPERTY_NAME); + +#ifdef TUNNEL_SINK + pa_xfree(u->sink_name); +#else + pa_xfree(u->source_name); +#endif + pa_xfree(u->server_name); + + pa_xfree(u); +} + + diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c new file mode 100644 index 00000000..8809c31d --- /dev/null +++ b/src/modules/module-waveout.c @@ -0,0 +1,583 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-waveout-symdef.h" + +PA_MODULE_AUTHOR("Pierre Ossman") +PA_MODULE_DESCRIPTION("Windows waveOut Sink/Source") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink_name= source_name= record= playback= format= channels= rate= fragments= fragment_size=") + +#define DEFAULT_SINK_NAME "wave_output" +#define DEFAULT_SOURCE_NAME "wave_input" + +struct userdata { + pa_sink *sink; + pa_source *source; + pa_core *core; + pa_time_event *event; + pa_defer_event *defer; + pa_usec_t poll_timeout; + + uint32_t fragments, fragment_size; + + uint32_t free_ofrags, free_ifrags; + + DWORD written_bytes; + + int cur_ohdr, cur_ihdr; + unsigned int oremain; + WAVEHDR *ohdrs, *ihdrs; + pa_memchunk silence; + + HWAVEOUT hwo; + HWAVEIN hwi; + pa_module *module; + + CRITICAL_SECTION crit; +}; + +static const char* const valid_modargs[] = { + "sink_name", + "source_name", + "record", + "playback", + "fragments", + "fragment_size", + "format", + "rate", + "channels", + NULL +}; + +static void update_usage(struct userdata *u) { + pa_module_set_used(u->module, + (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0) + + (u->source ? pa_idxset_size(u->source->outputs) : 0)); +} + +static void do_write(struct userdata *u) +{ + uint32_t free_frags, remain; + pa_memchunk memchunk, *cur_chunk; + WAVEHDR *hdr; + MMRESULT res; + + if (!u->sink) + return; + + EnterCriticalSection(&u->crit); + + free_frags = u->free_ofrags; + u->free_ofrags = 0; + + LeaveCriticalSection(&u->crit); + + while (free_frags) { + hdr = &u->ohdrs[u->cur_ohdr]; + if (hdr->dwFlags & WHDR_PREPARED) + waveOutUnprepareHeader(u->hwo, hdr, sizeof(WAVEHDR)); + + remain = u->oremain; + while (remain) { + cur_chunk = &memchunk; + + if (pa_sink_render(u->sink, remain, cur_chunk) < 0) { + /* + * Don't fill with silence unless we're getting close to + * underflowing. + */ + if (free_frags > u->fragments/2) + cur_chunk = &u->silence; + else { + EnterCriticalSection(&u->crit); + + u->free_ofrags += free_frags; + + LeaveCriticalSection(&u->crit); + + u->oremain = remain; + return; + } + } + + assert(cur_chunk->memblock); + assert(cur_chunk->memblock->data); + assert(cur_chunk->length); + + memcpy(hdr->lpData + u->fragment_size - remain, + (char*)cur_chunk->memblock->data + cur_chunk->index, + (cur_chunk->length < remain)?cur_chunk->length:remain); + + remain -= (cur_chunk->length < remain)?cur_chunk->length:remain; + + if (cur_chunk != &u->silence) { + pa_memblock_unref(cur_chunk->memblock); + cur_chunk->memblock = NULL; + } + } + + res = waveOutPrepareHeader(u->hwo, hdr, sizeof(WAVEHDR)); + if (res != MMSYSERR_NOERROR) { + pa_log_error(__FILE__ ": ERROR: Unable to prepare waveOut block: %d\n", + res); + } + res = waveOutWrite(u->hwo, hdr, sizeof(WAVEHDR)); + if (res != MMSYSERR_NOERROR) { + pa_log_error(__FILE__ ": ERROR: Unable to write waveOut block: %d\n", + res); + } + + u->written_bytes += u->fragment_size; + + free_frags--; + u->cur_ohdr++; + u->cur_ohdr %= u->fragments; + u->oremain = u->fragment_size; + } +} + +static void do_read(struct userdata *u) +{ + uint32_t free_frags; + pa_memchunk memchunk; + WAVEHDR *hdr; + MMRESULT res; + + if (!u->source) + return; + + EnterCriticalSection(&u->crit); + + free_frags = u->free_ifrags; + u->free_ifrags = 0; + + LeaveCriticalSection(&u->crit); + + while (free_frags) { + hdr = &u->ihdrs[u->cur_ihdr]; + if (hdr->dwFlags & WHDR_PREPARED) + waveInUnprepareHeader(u->hwi, hdr, sizeof(WAVEHDR)); + + if (hdr->dwBytesRecorded) { + memchunk.memblock = pa_memblock_new(hdr->dwBytesRecorded, u->core->memblock_stat); + assert(memchunk.memblock); + + memcpy((char*)memchunk.memblock->data, hdr->lpData, hdr->dwBytesRecorded); + + memchunk.length = memchunk.memblock->length = hdr->dwBytesRecorded; + memchunk.index = 0; + + pa_source_post(u->source, &memchunk); + pa_memblock_unref(memchunk.memblock); + } + + res = waveInPrepareHeader(u->hwi, hdr, sizeof(WAVEHDR)); + if (res != MMSYSERR_NOERROR) { + pa_log_error(__FILE__ ": ERROR: Unable to prepare waveIn block: %d\n", + res); + } + res = waveInAddBuffer(u->hwi, hdr, sizeof(WAVEHDR)); + if (res != MMSYSERR_NOERROR) { + pa_log_error(__FILE__ ": ERROR: Unable to add waveIn block: %d\n", + res); + } + + free_frags--; + u->cur_ihdr++; + u->cur_ihdr %= u->fragments; + } +} + +static void poll_cb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) { + struct userdata *u = userdata; + struct timeval ntv; + + assert(u); + + update_usage(u); + + do_write(u); + do_read(u); + + pa_gettimeofday(&ntv); + pa_timeval_add(&ntv, u->poll_timeout); + + a->time_restart(e, &ntv); +} + +static void defer_cb(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { + struct userdata *u = userdata; + + assert(u); + + a->defer_enable(e, 0); + + do_write(u); + do_read(u); +} + +static void CALLBACK chunk_done_cb(HWAVEOUT hwo, UINT msg, DWORD_PTR inst, DWORD param1, DWORD param2) { + struct userdata *u = (struct userdata *)inst; + + if (msg != WOM_DONE) + return; + + EnterCriticalSection(&u->crit); + + u->free_ofrags++; + assert(u->free_ofrags <= u->fragments); + + LeaveCriticalSection(&u->crit); +} + +static void CALLBACK chunk_ready_cb(HWAVEIN hwi, UINT msg, DWORD_PTR inst, DWORD param1, DWORD param2) { + struct userdata *u = (struct userdata *)inst; + + if (msg != WIM_DATA) + return; + + EnterCriticalSection(&u->crit); + + u->free_ifrags++; + assert(u->free_ifrags <= u->fragments); + + LeaveCriticalSection(&u->crit); +} + +static pa_usec_t sink_get_latency_cb(pa_sink *s) { + struct userdata *u = s->userdata; + uint32_t free_frags; + MMTIME mmt; + assert(s && u && u->sink); + + memset(&mmt, 0, sizeof(mmt)); + mmt.wType = TIME_BYTES; + if (waveOutGetPosition(u->hwo, &mmt, sizeof(mmt)) == MMSYSERR_NOERROR) + return pa_bytes_to_usec(u->written_bytes - mmt.u.cb, &s->sample_spec); + else { + EnterCriticalSection(&u->crit); + + free_frags = u->free_ofrags; + + LeaveCriticalSection(&u->crit); + + return pa_bytes_to_usec((u->fragments - free_frags) * u->fragment_size, + &s->sample_spec); + } +} + +static pa_usec_t source_get_latency_cb(pa_source *s) { + pa_usec_t r = 0; + struct userdata *u = s->userdata; + uint32_t free_frags; + assert(s && u && u->sink); + + EnterCriticalSection(&u->crit); + + free_frags = u->free_ifrags; + + LeaveCriticalSection(&u->crit); + + r += pa_bytes_to_usec((free_frags + 1) * u->fragment_size, &s->sample_spec); + + fprintf(stderr, "Latency: %d us\n", (int)r); + + return r; +} + +static void notify_sink_cb(pa_sink *s) { + struct userdata *u = s->userdata; + assert(u); + + u->core->mainloop->defer_enable(u->defer, 1); +} + +static void notify_source_cb(pa_source *s) { + struct userdata *u = s->userdata; + assert(u); + + u->core->mainloop->defer_enable(u->defer, 1); +} + +static int ss_to_waveformat(pa_sample_spec *ss, LPWAVEFORMATEX wf) { + wf->wFormatTag = WAVE_FORMAT_PCM; + + if (ss->channels > 2) { + pa_log_error(__FILE__": ERROR: More than two channels not supported.\n"); + return -1; + } + + wf->nChannels = ss->channels; + + switch (ss->rate) { + case 8000: + case 11025: + case 22005: + case 44100: + break; + default: + pa_log_error(__FILE__": ERROR: Unsupported sample rate.\n"); + return -1; + } + + wf->nSamplesPerSec = ss->rate; + + if (ss->format == PA_SAMPLE_U8) + wf->wBitsPerSample = 8; + else if (ss->format == PA_SAMPLE_S16NE) + wf->wBitsPerSample = 16; + else { + pa_log_error(__FILE__": ERROR: Unsupported sample format.\n"); + return -1; + } + + wf->nBlockAlign = wf->nChannels * wf->wBitsPerSample/8; + wf->nAvgBytesPerSec = wf->nSamplesPerSec * wf->nBlockAlign; + + wf->cbSize = 0; + + return 0; +} + +int pa__init(pa_core *c, pa_module*m) { + struct userdata *u = NULL; + HWAVEOUT hwo = INVALID_HANDLE_VALUE; + HWAVEIN hwi = INVALID_HANDLE_VALUE; + WAVEFORMATEX wf; + int nfrags, frag_size; + int record = 1, playback = 1; + pa_sample_spec ss; + pa_modargs *ma = NULL; + unsigned int i; + struct timeval tv; + + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments.\n"); + goto fail; + } + + if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { + pa_log(__FILE__": record= and playback= expect boolean argument.\n"); + goto fail; + } + + if (!playback && !record) { + pa_log(__FILE__": neither playback nor record enabled for device.\n"); + goto fail; + } + + nfrags = 20; + frag_size = 1024; + if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { + pa_log(__FILE__": failed to parse fragments arguments\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": failed to parse sample specification\n"); + goto fail; + } + + if (ss_to_waveformat(&ss, &wf) < 0) + goto fail; + + u = pa_xmalloc(sizeof(struct userdata)); + + if (record) { + if (waveInOpen(&hwi, WAVE_MAPPER, &wf, (DWORD_PTR)chunk_ready_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) + goto fail; + if (waveInStart(hwi) != MMSYSERR_NOERROR) + goto fail; + pa_log_debug(__FILE__": Opened waveIn subsystem.\n"); + } + + if (playback) { + if (waveOutOpen(&hwo, WAVE_MAPPER, &wf, (DWORD_PTR)chunk_done_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) + goto fail; + pa_log_debug(__FILE__": Opened waveOut subsystem.\n"); + } + + InitializeCriticalSection(&u->crit); + + if (hwi != INVALID_HANDLE_VALUE) { + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); + assert(u->source); + u->source->userdata = u; + u->source->notify = notify_source_cb; + u->source->get_latency = source_get_latency_cb; + pa_source_set_owner(u->source, m); + u->source->description = pa_sprintf_malloc("Windows waveIn PCM"); + } else + u->source = NULL; + + if (hwo != INVALID_HANDLE_VALUE) { + u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); + assert(u->sink); + u->sink->notify = notify_sink_cb; + u->sink->get_latency = sink_get_latency_cb; + u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Windows waveOut PCM"); + } else + u->sink = NULL; + + assert(u->source || u->sink); + + u->core = c; + u->hwi = hwi; + u->hwo = hwo; + + u->fragments = nfrags; + u->free_ifrags = u->fragments; + u->free_ofrags = u->fragments; + u->fragment_size = frag_size - (frag_size % pa_frame_size(&ss)); + + u->written_bytes = 0; + + u->oremain = u->fragment_size; + + u->poll_timeout = pa_bytes_to_usec(u->fragments * u->fragment_size / 3, &ss); + + pa_gettimeofday(&tv); + pa_timeval_add(&tv, u->poll_timeout); + + u->event = c->mainloop->time_new(c->mainloop, &tv, poll_cb, u); + assert(u->event); + + u->defer = c->mainloop->defer_new(c->mainloop, defer_cb, u); + assert(u->defer); + c->mainloop->defer_enable(u->defer, 0); + + u->cur_ihdr = 0; + u->cur_ohdr = 0; + u->ihdrs = pa_xmalloc0(sizeof(WAVEHDR) * u->fragments); + assert(u->ihdrs); + u->ohdrs = pa_xmalloc0(sizeof(WAVEHDR) * u->fragments); + assert(u->ohdrs); + for (i = 0;i < u->fragments;i++) { + u->ihdrs[i].dwBufferLength = u->fragment_size; + u->ohdrs[i].dwBufferLength = u->fragment_size; + u->ihdrs[i].lpData = pa_xmalloc(u->fragment_size); + assert(u->ihdrs); + u->ohdrs[i].lpData = pa_xmalloc(u->fragment_size); + assert(u->ohdrs); + } + + u->silence.length = u->fragment_size; + u->silence.memblock = pa_memblock_new(u->silence.length, u->core->memblock_stat); + assert(u->silence.memblock); + pa_silence_memblock(u->silence.memblock, &ss); + u->silence.index = 0; + + u->module = m; + m->userdata = u; + + pa_modargs_free(ma); + + return 0; + +fail: + if (hwi != INVALID_HANDLE_VALUE) + waveInClose(hwi); + + if (hwo != INVALID_HANDLE_VALUE) + waveOutClose(hwo); + + if (u) + pa_xfree(u); + + if (ma) + pa_modargs_free(ma); + + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + unsigned int i; + + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->event) + c->mainloop->time_free(u->event); + + if (u->defer) + c->mainloop->defer_free(u->defer); + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + } + + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + } + + if (u->hwi != INVALID_HANDLE_VALUE) { + waveInReset(u->hwi); + waveInClose(u->hwi); + } + + if (u->hwo != INVALID_HANDLE_VALUE) { + waveOutReset(u->hwo); + waveOutClose(u->hwo); + } + + for (i = 0;i < u->fragments;i++) { + pa_xfree(u->ihdrs[i].lpData); + pa_xfree(u->ohdrs[i].lpData); + } + + pa_xfree(u->ihdrs); + pa_xfree(u->ohdrs); + + DeleteCriticalSection(&u->crit); + + pa_xfree(u); +} diff --git a/src/modules/module-x11-bell.c b/src/modules/module-x11-bell.c new file mode 100644 index 00000000..d722b732 --- /dev/null +++ b/src/modules/module-x11-bell.c @@ -0,0 +1,173 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-x11-bell-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("X11 Bell interceptor") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink= sample= display=") + +struct userdata { + pa_core *core; + int xkb_event_base; + char *sink_name; + char *scache_item; + Display *display; + + pa_x11_wrapper *x11_wrapper; + pa_x11_client *x11_client; +}; + +static const char* const valid_modargs[] = { + "sink", + "sample", + "display", + NULL +}; + +static int ring_bell(struct userdata *u, int percent) { + pa_sink *s; + pa_cvolume cv; + assert(u); + + if (!(s = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) { + pa_log(__FILE__": Invalid sink: %s\n", u->sink_name); + return -1; + } + + pa_scache_play_item(u->core, u->scache_item, s, pa_cvolume_set(&cv, PA_CHANNELS_MAX, percent*PA_VOLUME_NORM/100)); + return 0; +} + +static int x11_event_callback(pa_x11_wrapper *w, XEvent *e, void *userdata) { + XkbBellNotifyEvent *bne; + struct userdata *u = userdata; + assert(w && e && u && u->x11_wrapper == w); + + if (((XkbEvent*) e)->any.xkb_type != XkbBellNotify) + return 0; + + bne = (XkbBellNotifyEvent*) e; + + if (ring_bell(u, bne->percent) < 0) { + pa_log_info(__FILE__": Ringing bell failed, reverting to X11 device bell.\n"); + XkbForceDeviceBell(pa_x11_wrapper_get_display(w), bne->device, bne->bell_class, bne->bell_id, bne->percent); + } + + return 1; +} + +int pa__init(pa_core *c, pa_module*m) { + struct userdata *u = NULL; + pa_modargs *ma = NULL; + int major, minor; + unsigned int auto_ctrls, auto_values; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments\n"); + goto fail; + } + + m->userdata = u = pa_xmalloc(sizeof(struct userdata)); + u->core = c; + u->scache_item = pa_xstrdup(pa_modargs_get_value(ma, "sample", "x11-bell")); + u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); + u->x11_client = NULL; + + if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL)))) + goto fail; + + u->display = pa_x11_wrapper_get_display(u->x11_wrapper); + + major = XkbMajorVersion; + minor = XkbMinorVersion; + + if (!XkbLibraryVersion(&major, &minor)) { + pa_log(__FILE__": XkbLibraryVersion() failed\n"); + goto fail; + } + + major = XkbMajorVersion; + minor = XkbMinorVersion; + + + if (!XkbQueryExtension(u->display, NULL, &u->xkb_event_base, NULL, &major, &minor)) { + pa_log(__FILE__": XkbQueryExtension() failed\n"); + goto fail; + } + + XkbSelectEvents(u->display, XkbUseCoreKbd, XkbBellNotifyMask, XkbBellNotifyMask); + auto_ctrls = auto_values = XkbAudibleBellMask; + XkbSetAutoResetControls(u->display, XkbAudibleBellMask, &auto_ctrls, &auto_values); + XkbChangeEnabledControls(u->display, XkbUseCoreKbd, XkbAudibleBellMask, 0); + + u->x11_client = pa_x11_client_new(u->x11_wrapper, x11_event_callback, u); + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + if (m->userdata) + pa__done(c, m); + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u = m->userdata; + assert(c && m && u); + + pa_xfree(u->scache_item); + pa_xfree(u->sink_name); + + if (u->x11_client) + pa_x11_client_free(u->x11_client); + + if (u->x11_wrapper) + pa_x11_wrapper_unref(u->x11_wrapper); + + pa_xfree(u); +} diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c new file mode 100644 index 00000000..dca5d049 --- /dev/null +++ b/src/modules/module-x11-publish.c @@ -0,0 +1,192 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-x11-publish-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("X11 Credential Publisher") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("display=") + +static const char* const valid_modargs[] = { + "display", + "sink", + "source", + "cookie", + NULL +}; + +struct userdata { + pa_core *core; + pa_x11_wrapper *x11_wrapper; + Display *display; + char *id; + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; + int auth_cookie_in_property; +}; + +static int load_key(struct userdata *u, const char*fn) { + assert(u); + + u->auth_cookie_in_property = 0; + + if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { + pa_log_debug(__FILE__": using already loaded auth cookie.\n"); + pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); + u->auth_cookie_in_property = 1; + return 0; + } + + if (!fn) + fn = PA_NATIVE_COOKIE_FILE; + + if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) + return -1; + + pa_log_debug(__FILE__": loading cookie from disk.\n"); + + if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) + u->auth_cookie_in_property = 1; + + return 0; +} + +int pa__init(pa_core *c, pa_module*m) { + struct userdata *u; + pa_modargs *ma = NULL; + char hn[256], un[128]; + char hx[PA_NATIVE_COOKIE_LENGTH*2+1]; + const char *t; + char *s; + pa_strlist *l; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments\n"); + goto fail; + } + + m->userdata = u = pa_xmalloc(sizeof(struct userdata)); + u->core = c; + u->id = NULL; + u->auth_cookie_in_property = 0; + + if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0) + goto fail; + + if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL)))) + goto fail; + + u->display = pa_x11_wrapper_get_display(u->x11_wrapper); + + if (!(l = pa_property_get(c, PA_NATIVE_SERVER_PROPERTY_NAME))) + goto fail; + + s = pa_strlist_tostring(l); + pa_x11_set_prop(u->display, "POLYP_SERVER", s); + pa_xfree(s); + + if (!pa_get_fqdn(hn, sizeof(hn)) || !pa_get_user_name(un, sizeof(un))) + goto fail; + + u->id = pa_sprintf_malloc("%s@%s/%u", un, hn, (unsigned) getpid()); + pa_x11_set_prop(u->display, "POLYP_ID", u->id); + + if ((t = pa_modargs_get_value(ma, "source", NULL))) + pa_x11_set_prop(u->display, "POLYP_SOURCE", t); + + if ((t = pa_modargs_get_value(ma, "sink", NULL))) + pa_x11_set_prop(u->display, "POLYP_SINK", t); + + pa_x11_set_prop(u->display, "POLYP_COOKIE", pa_hexstr(u->auth_cookie, sizeof(u->auth_cookie), hx, sizeof(hx))); + + pa_modargs_free(ma); + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + pa__done(c, m); + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata*u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->x11_wrapper) { + char t[256]; + + /* Yes, here is a race condition */ + if (!pa_x11_get_prop(u->display, "POLYP_ID", t, sizeof(t)) || strcmp(t, u->id)) + pa_log("WARNING: Polypaudio information vanished from X11!\n"); + else { + pa_x11_del_prop(u->display, "POLYP_ID"); + pa_x11_del_prop(u->display, "POLYP_SERVER"); + pa_x11_del_prop(u->display, "POLYP_SINK"); + pa_x11_del_prop(u->display, "POLYP_SOURCE"); + pa_x11_del_prop(u->display, "POLYP_COOKIE"); + XSync(u->display, False); + } + } + + if (u->x11_wrapper) + pa_x11_wrapper_unref(u->x11_wrapper); + + if (u->auth_cookie_in_property) + pa_authkey_prop_unref(c, PA_NATIVE_COOKIE_PROPERTY_NAME); + + pa_xfree(u->id); + pa_xfree(u); +} + diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c new file mode 100644 index 00000000..45d566ae --- /dev/null +++ b/src/modules/module-zeroconf-publish.c @@ -0,0 +1,508 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-zeroconf-publish-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Publisher") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("port=") + +#define SERVICE_NAME_SINK "_polypaudio-sink._tcp" +#define SERVICE_NAME_SOURCE "_polypaudio-source._tcp" +#define SERVICE_NAME_SERVER "_polypaudio-server._tcp" + +static const char* const valid_modargs[] = { + "port", + NULL +}; + +struct service { + sw_discovery_oid oid; + char *name; + int published; /* 0 -> not yet registered, 1 -> registered with data from real device, 2 -> registered with data from autoload device */ + + struct { + int valid; + pa_namereg_type type; + uint32_t index; + } loaded; + + struct { + int valid; + pa_namereg_type type; + uint32_t index; + } autoload; +}; + +struct userdata { + pa_core *core; + pa_howl_wrapper *howl_wrapper; + pa_hashmap *services; + pa_dynarray *sink_dynarray, *source_dynarray, *autoload_dynarray; + pa_subscription *subscription; + + uint16_t port; + sw_discovery_oid server_oid; +}; + +static sw_result publish_reply(sw_discovery discovery, sw_discovery_publish_status status, sw_discovery_oid oid, sw_opaque extra) { + return SW_OKAY; +} + +static void get_service_data(struct userdata *u, struct service *s, pa_sample_spec *ret_ss, char **ret_description, pa_typeid_t *ret_typeid) { + assert(u && s && s->loaded.valid && ret_ss && ret_description && ret_typeid); + + if (s->loaded.type == PA_NAMEREG_SINK) { + pa_sink *sink = pa_idxset_get_by_index(u->core->sinks, s->loaded.index); + assert(sink); + *ret_ss = sink->sample_spec; + *ret_description = sink->description; + *ret_typeid = sink->typeid; + } else if (s->loaded.type == PA_NAMEREG_SOURCE) { + pa_source *source = pa_idxset_get_by_index(u->core->sources, s->loaded.index); + assert(source); + *ret_ss = source->sample_spec; + *ret_description = source->description; + *ret_typeid = source->typeid; + } else + assert(0); +} + +static void txt_record_server_data(pa_core *c, sw_text_record t) { + char s[256]; + assert(c); + + sw_text_record_add_key_and_string_value(t, "server-version", PACKAGE_NAME" "PACKAGE_VERSION); + sw_text_record_add_key_and_string_value(t, "user-name", pa_get_user_name(s, sizeof(s))); + sw_text_record_add_key_and_string_value(t, "fqdn", pa_get_fqdn(s, sizeof(s))); + snprintf(s, sizeof(s), "0x%08x", c->cookie); + sw_text_record_add_key_and_string_value(t, "cookie", s); +} + +static int publish_service(struct userdata *u, struct service *s) { + char t[256]; + char hn[256]; + int r = -1; + sw_text_record txt; + int free_txt = 0; + assert(u && s); + + if ((s->published == 1 && s->loaded.valid) || + (s->published == 2 && s->autoload.valid && !s->loaded.valid)) + return 0; + + if (s->published) { + sw_discovery_cancel(pa_howl_wrapper_get_discovery(u->howl_wrapper), s->oid); + s->published = 0; + } + + snprintf(t, sizeof(t), "Networked Audio Device %s on %s", s->name, pa_get_host_name(hn, sizeof(hn))); + + if (sw_text_record_init(&txt) != SW_OKAY) { + pa_log(__FILE__": sw_text_record_init() failed\n"); + goto finish; + } + free_txt = 1; + + sw_text_record_add_key_and_string_value(txt, "device", s->name); + + txt_record_server_data(u->core, txt); + + if (s->loaded.valid) { + char z[64], *description; + pa_typeid_t typeid; + pa_sample_spec ss; + + get_service_data(u, s, &ss, &description, &typeid); + + snprintf(z, sizeof(z), "%u", ss.rate); + sw_text_record_add_key_and_string_value(txt, "rate", z); + snprintf(z, sizeof(z), "%u", ss.channels); + sw_text_record_add_key_and_string_value(txt, "channels", z); + sw_text_record_add_key_and_string_value(txt, "format", pa_sample_format_to_string(ss.format)); + + sw_text_record_add_key_and_string_value(txt, "description", description); + + snprintf(z, sizeof(z), "0x%8x", typeid); + sw_text_record_add_key_and_string_value(txt, "typeid", z); + + + if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t, + s->loaded.type == PA_NAMEREG_SINK ? SERVICE_NAME_SINK : SERVICE_NAME_SOURCE, + NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt), + publish_reply, s, &s->oid) != SW_OKAY) { + pa_log(__FILE__": failed to register sink on zeroconf.\n"); + goto finish; + } + + s->published = 1; + } else if (s->autoload.valid) { + + if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t, + s->autoload.type == PA_NAMEREG_SINK ? SERVICE_NAME_SINK : SERVICE_NAME_SOURCE, + NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt), + publish_reply, s, &s->oid) != SW_OKAY) { + pa_log(__FILE__": failed to register sink on zeroconf.\n"); + goto finish; + } + + s->published = 2; + } + + r = 0; + +finish: + + if (!s->published) { + /* Remove this service */ + pa_hashmap_remove(u->services, s->name); + pa_xfree(s->name); + pa_xfree(s); + } + + if (free_txt) + sw_text_record_fina(txt); + + return r; +} + +struct service *get_service(struct userdata *u, const char *name) { + struct service *s; + + if ((s = pa_hashmap_get(u->services, name))) + return s; + + s = pa_xmalloc(sizeof(struct service)); + s->published = 0; + s->name = pa_xstrdup(name); + s->loaded.valid = s->autoload.valid = 0; + + pa_hashmap_put(u->services, s->name, s); + + return s; +} + +static int publish_sink(struct userdata *u, pa_sink *s) { + struct service *svc; + assert(u && s); + + svc = get_service(u, s->name); + if (svc->loaded.valid) + return 0; + + svc->loaded.valid = 1; + svc->loaded.type = PA_NAMEREG_SINK; + svc->loaded.index = s->index; + + pa_dynarray_put(u->sink_dynarray, s->index, svc); + + return publish_service(u, svc); +} + +static int publish_source(struct userdata *u, pa_source *s) { + struct service *svc; + assert(u && s); + + svc = get_service(u, s->name); + if (svc->loaded.valid) + return 0; + + svc->loaded.valid = 1; + svc->loaded.type = PA_NAMEREG_SOURCE; + svc->loaded.index = s->index; + + pa_dynarray_put(u->source_dynarray, s->index, svc); + + return publish_service(u, svc); +} + +static int publish_autoload(struct userdata *u, pa_autoload_entry *s) { + struct service *svc; + assert(u && s); + + svc = get_service(u, s->name); + if (svc->autoload.valid) + return 0; + + svc->autoload.valid = 1; + svc->autoload.type = s->type; + svc->autoload.index = s->index; + + pa_dynarray_put(u->autoload_dynarray, s->index, svc); + + return publish_service(u, svc); +} + +static int remove_sink(struct userdata *u, uint32_t index) { + struct service *svc; + assert(u && index != PA_INVALID_INDEX); + + if (!(svc = pa_dynarray_get(u->sink_dynarray, index))) + return 0; + + if (!svc->loaded.valid || svc->loaded.type != PA_NAMEREG_SINK) + return 0; + + svc->loaded.valid = 0; + pa_dynarray_put(u->sink_dynarray, index, NULL); + + return publish_service(u, svc); +} + +static int remove_source(struct userdata *u, uint32_t index) { + struct service *svc; + assert(u && index != PA_INVALID_INDEX); + + if (!(svc = pa_dynarray_get(u->source_dynarray, index))) + return 0; + + if (!svc->loaded.valid || svc->loaded.type != PA_NAMEREG_SOURCE) + return 0; + + svc->loaded.valid = 0; + pa_dynarray_put(u->source_dynarray, index, NULL); + + return publish_service(u, svc); +} + +static int remove_autoload(struct userdata *u, uint32_t index) { + struct service *svc; + assert(u && index != PA_INVALID_INDEX); + + if (!(svc = pa_dynarray_get(u->autoload_dynarray, index))) + return 0; + + if (!svc->autoload.valid) + return 0; + + svc->autoload.valid = 0; + pa_dynarray_put(u->autoload_dynarray, index, NULL); + + return publish_service(u, svc); +} + +static void subscribe_callback(pa_core *c, pa_subscription_event_type t, uint32_t index, void *userdata) { + struct userdata *u = userdata; + assert(u && c); + + switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) + case PA_SUBSCRIPTION_EVENT_SINK: { + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { + pa_sink *sink; + + if ((sink = pa_idxset_get_by_index(c->sinks, index))) { + if (publish_sink(u, sink) < 0) + goto fail; + } + } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + if (remove_sink(u, index) < 0) + goto fail; + } + + break; + + case PA_SUBSCRIPTION_EVENT_SOURCE: + + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { + pa_source *source; + + if ((source = pa_idxset_get_by_index(c->sources, index))) { + if (publish_source(u, source) < 0) + goto fail; + } + } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + if (remove_source(u, index) < 0) + goto fail; + } + + break; + + case PA_SUBSCRIPTION_EVENT_AUTOLOAD: + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { + pa_autoload_entry *autoload; + + if ((autoload = pa_idxset_get_by_index(c->autoload_idxset, index))) { + if (publish_autoload(u, autoload) < 0) + goto fail; + } + } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + if (remove_autoload(u, index) < 0) + goto fail; + } + + break; + } + + return; + +fail: + if (u->subscription) { + pa_subscription_free(u->subscription); + u->subscription = NULL; + } +} + +int pa__init(pa_core *c, pa_module*m) { + struct userdata *u; + uint32_t index, port = PA_NATIVE_DEFAULT_PORT; + pa_sink *sink; + pa_source *source; + pa_autoload_entry *autoload; + pa_modargs *ma = NULL; + char t[256], hn[256]; + int free_txt = 0; + sw_text_record txt; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments.\n"); + goto fail; + } + + if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port == 0 || port >= 0xFFFF) { + pa_log(__FILE__": invalid port specified.\n"); + goto fail; + } + + m->userdata = u = pa_xmalloc(sizeof(struct userdata)); + u->core = c; + u->port = (uint16_t) port; + + if (!(u->howl_wrapper = pa_howl_wrapper_get(c))) + goto fail; + + u->services = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + u->sink_dynarray = pa_dynarray_new(); + u->source_dynarray = pa_dynarray_new(); + u->autoload_dynarray = pa_dynarray_new(); + + u->subscription = pa_subscription_new(c, + PA_SUBSCRIPTION_MASK_SINK| + PA_SUBSCRIPTION_MASK_SOURCE| + PA_SUBSCRIPTION_MASK_AUTOLOAD, subscribe_callback, u); + + for (sink = pa_idxset_first(c->sinks, &index); sink; sink = pa_idxset_next(c->sinks, &index)) + if (publish_sink(u, sink) < 0) + goto fail; + + for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) + if (publish_source(u, source) < 0) + goto fail; + + if (c->autoload_idxset) + for (autoload = pa_idxset_first(c->autoload_idxset, &index); autoload; autoload = pa_idxset_next(c->autoload_idxset, &index)) + if (publish_autoload(u, autoload) < 0) + goto fail; + + snprintf(t, sizeof(t), "Networked Audio Server on %s", pa_get_host_name(hn, sizeof(hn))); + + if (sw_text_record_init(&txt) != SW_OKAY) { + pa_log(__FILE__": sw_text_record_init() failed\n"); + goto fail; + } + free_txt = 1; + + txt_record_server_data(u->core, txt); + + if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t, + SERVICE_NAME_SERVER, + NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt), + publish_reply, u, &u->server_oid) != SW_OKAY) { + pa_log(__FILE__": failed to register server on zeroconf.\n"); + goto fail; + } + + sw_text_record_fina(txt); + pa_modargs_free(ma); + + return 0; + +fail: + pa__done(c, m); + + if (ma) + pa_modargs_free(ma); + + if (free_txt) + sw_text_record_fina(txt); + + return -1; +} + +static void service_free(void *p, void *userdata) { + struct service *s = p; + struct userdata *u = userdata; + assert(s && u); + sw_discovery_cancel(pa_howl_wrapper_get_discovery(u->howl_wrapper), s->oid); + pa_xfree(s->name); + pa_xfree(s); +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata*u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->services) + pa_hashmap_free(u->services, service_free, u); + + if (u->sink_dynarray) + pa_dynarray_free(u->sink_dynarray, NULL, NULL); + if (u->source_dynarray) + pa_dynarray_free(u->source_dynarray, NULL, NULL); + if (u->autoload_dynarray) + pa_dynarray_free(u->autoload_dynarray, NULL, NULL); + + if (u->subscription) + pa_subscription_free(u->subscription); + + if (u->howl_wrapper) + pa_howl_wrapper_unref(u->howl_wrapper); + + + pa_xfree(u); +} + diff --git a/src/polyp/cdecl.h b/src/polyp/cdecl.h new file mode 100644 index 00000000..d51ae026 --- /dev/null +++ b/src/polyp/cdecl.h @@ -0,0 +1,42 @@ +#ifndef foocdeclhfoo +#define foocdeclhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/** \file + * C++ compatibility support */ + +#ifdef __cplusplus +/** If using C++ this macro enables C mode, otherwise does nothing */ +#define PA_C_DECL_BEGIN extern "C" { +/** If using C++ this macros switches back to C++ mode, otherwise does nothing */ +#define PA_C_DECL_END } + +#else +/** If using C++ this macro enables C mode, otherwise does nothing */ +#define PA_C_DECL_BEGIN +/** If using C++ this macros switches back to C++ mode, otherwise does nothing */ +#define PA_C_DECL_END + +#endif + +#endif diff --git a/src/polyp/channelmap.c b/src/polyp/channelmap.c new file mode 100644 index 00000000..7bfd21e6 --- /dev/null +++ b/src/polyp/channelmap.c @@ -0,0 +1,202 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "channelmap.h" + +pa_channel_map* pa_channel_map_init(pa_channel_map *m) { + unsigned c; + assert(m); + + m->channels = 0; + + for (c = 0; c < PA_CHANNELS_MAX; c++) + m->map[c] = PA_CHANNEL_POSITION_INVALID; + + return m; +} + +pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m) { + assert(m); + + pa_channel_map_init(m); + + m->channels = 1; + m->map[0] = PA_CHANNEL_POSITION_MONO; + return m; +} + +pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m) { + assert(m); + + pa_channel_map_init(m); + + m->channels = 2; + m->map[0] = PA_CHANNEL_POSITION_LEFT; + m->map[1] = PA_CHANNEL_POSITION_RIGHT; + return m; +} + +pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels) { + assert(m); + assert(channels > 0); + assert(channels <= PA_CHANNELS_MAX); + + pa_channel_map_init(m); + + m->channels = channels; + + switch (channels) { + case 1: + m->map[0] = PA_CHANNEL_POSITION_MONO; + return m; + + case 8: + m->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; + m->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; + /* Fall through */ + + case 6: + m->map[5] = PA_CHANNEL_POSITION_LFE; + /* Fall through */ + + case 5: + m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; + /* Fall through */ + + case 4: + m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT; + m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; + /* Fall through */ + + case 2: + m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + return m; + + default: + return NULL; + } +} + +const char* pa_channel_position_to_string(pa_channel_position_t pos) { + + const char *const table[] = { + [PA_CHANNEL_POSITION_MONO] = "mono", + + [PA_CHANNEL_POSITION_FRONT_CENTER] = "front-center", + [PA_CHANNEL_POSITION_FRONT_LEFT] = "front-left", + [PA_CHANNEL_POSITION_FRONT_RIGHT] = "front-right", + + [PA_CHANNEL_POSITION_REAR_CENTER] = "rear-center", + [PA_CHANNEL_POSITION_REAR_LEFT] = "rear-left", + [PA_CHANNEL_POSITION_REAR_RIGHT] = "rear-right", + + [PA_CHANNEL_POSITION_LFE] = "lfe", + + [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = "front-left-of-center", + [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = "front-right-of-center", + + [PA_CHANNEL_POSITION_SIDE_LEFT] = "side-left", + [PA_CHANNEL_POSITION_SIDE_RIGHT] = "side-right", + + [PA_CHANNEL_POSITION_AUX1] = "aux1", + [PA_CHANNEL_POSITION_AUX2] = "aux2", + [PA_CHANNEL_POSITION_AUX3] = "aux3", + [PA_CHANNEL_POSITION_AUX4] = "aux4", + [PA_CHANNEL_POSITION_AUX5] = "aux5", + [PA_CHANNEL_POSITION_AUX6] = "aux6", + [PA_CHANNEL_POSITION_AUX7] = "aux7", + [PA_CHANNEL_POSITION_AUX8] = "aux8", + [PA_CHANNEL_POSITION_AUX9] = "aux9", + [PA_CHANNEL_POSITION_AUX10] = "aux10", + [PA_CHANNEL_POSITION_AUX11] = "aux11", + [PA_CHANNEL_POSITION_AUX12] = "aux12" + }; + + if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX) + return NULL; + + return table[pos]; +} + +int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) { + unsigned c; + + assert(a); + assert(b); + + if (a->channels != b->channels) + return 0; + + for (c = 0; c < a->channels; c++) + if (a->map[c] != b->map[c]) + return 0; + + return 1; +} + +char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) { + unsigned channel; + int first = 1; + char *e; + + assert(s); + assert(l > 0); + assert(map); + + *(e = s) = 0; + + for (channel = 0; channel < map->channels && l > 1; channel++) { + l -= snprintf(e, l, "%s%u:%s", + first ? "" : " ", + channel, + pa_channel_position_to_string(map->map[channel])); + + e = strchr(e, 0); + first = 0; + } + + return s; +} + +int pa_channel_map_valid(const pa_channel_map *map) { + unsigned c; + + assert(map); + + if (map->channels <= 0 || map->channels > PA_CHANNELS_MAX) + return 0; + + for (c = 0; c < map->channels; c++) + if (map->map[c] < 0 ||map->map[c] >= PA_CHANNEL_POSITION_MAX) + return 0; + + return 1; +} diff --git a/src/polyp/channelmap.h b/src/polyp/channelmap.h new file mode 100644 index 00000000..0b9f6e26 --- /dev/null +++ b/src/polyp/channelmap.h @@ -0,0 +1,98 @@ +#ifndef foochannelmaphfoo +#define foochannelmaphfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/** \file + * Constants and routines for channel mapping handling */ + +PA_C_DECL_BEGIN + +typedef enum { + PA_CHANNEL_POSITION_INVALID = -1, + PA_CHANNEL_POSITION_MONO = 0, + + PA_CHANNEL_POSITION_LEFT, + PA_CHANNEL_POSITION_RIGHT, + + PA_CHANNEL_POSITION_FRONT_CENTER, + PA_CHANNEL_POSITION_FRONT_LEFT = PA_CHANNEL_POSITION_LEFT, + PA_CHANNEL_POSITION_FRONT_RIGHT = PA_CHANNEL_POSITION_RIGHT, + + PA_CHANNEL_POSITION_REAR_CENTER, + PA_CHANNEL_POSITION_REAR_LEFT, + PA_CHANNEL_POSITION_REAR_RIGHT, + + PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_SUBWOOFER = PA_CHANNEL_POSITION_LFE, + + PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, + PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, + + PA_CHANNEL_POSITION_SIDE_LEFT, + PA_CHANNEL_POSITION_SIDE_RIGHT, + + PA_CHANNEL_POSITION_AUX0, + PA_CHANNEL_POSITION_AUX1, + PA_CHANNEL_POSITION_AUX2, + PA_CHANNEL_POSITION_AUX3, + PA_CHANNEL_POSITION_AUX4, + PA_CHANNEL_POSITION_AUX5, + PA_CHANNEL_POSITION_AUX6, + PA_CHANNEL_POSITION_AUX7, + PA_CHANNEL_POSITION_AUX8, + PA_CHANNEL_POSITION_AUX9, + PA_CHANNEL_POSITION_AUX10, + PA_CHANNEL_POSITION_AUX11, + PA_CHANNEL_POSITION_AUX12, + PA_CHANNEL_POSITION_AUX13, + PA_CHANNEL_POSITION_AUX14, + PA_CHANNEL_POSITION_AUX15, + + PA_CHANNEL_POSITION_MAX +} pa_channel_position_t; + +typedef struct pa_channel_map { + uint8_t channels; + pa_channel_position_t map[PA_CHANNELS_MAX]; +} pa_channel_map; + +pa_channel_map* pa_channel_map_init(pa_channel_map *m); +pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m); +pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m); +pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels); + +const char* pa_channel_position_to_string(pa_channel_position_t pos); + +#define PA_CHANNEL_MAP_SNPRINT_MAX 64 +char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map); + +int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b); + +int pa_channel_map_valid(const pa_channel_map *map); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/client-conf-x11.c b/src/polyp/client-conf-x11.c new file mode 100644 index 00000000..83d0bd2e --- /dev/null +++ b/src/polyp/client-conf-x11.c @@ -0,0 +1,91 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-13071 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include + +#include "client-conf-x11.h" +#include +#include +#include +#include + +int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) { + Display *d = NULL; + int ret = -1; + char t[1024]; + + if (!dname && !getenv("DISPLAY")) + goto finish; + + if (!(d = XOpenDisplay(dname))) { + pa_log(__FILE__": XOpenDisplay() failed\n"); + goto finish; + } + + if (pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) { + pa_xfree(c->default_server); + c->default_server = pa_xstrdup(t); + } + + if (pa_x11_get_prop(d, "POLYP_SINK", t, sizeof(t))) { + pa_xfree(c->default_sink); + c->default_sink = pa_xstrdup(t); + } + + if (pa_x11_get_prop(d, "POLYP_SOURCE", t, sizeof(t))) { + pa_xfree(c->default_source); + c->default_source = pa_xstrdup(t); + } + + if (pa_x11_get_prop(d, "POLYP_COOKIE", t, sizeof(t))) { + uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; + + if (pa_parsehex(t, cookie, sizeof(cookie)) != sizeof(cookie)) { + pa_log(__FILE__": failed to parse cookie data\n"); + goto finish; + } + + assert(sizeof(cookie) == sizeof(c->cookie)); + memcpy(c->cookie, cookie, sizeof(cookie)); + + c->cookie_valid = 1; + + pa_xfree(c->cookie_file); + c->cookie_file = NULL; + } + + ret = 0; + +finish: + if (d) + XCloseDisplay(d); + + return ret; + +} diff --git a/src/polyp/client-conf-x11.h b/src/polyp/client-conf-x11.h new file mode 100644 index 00000000..80841171 --- /dev/null +++ b/src/polyp/client-conf-x11.h @@ -0,0 +1,31 @@ +#ifndef fooclientconfx11hfoo +#define fooclientconfx11hfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +/* Load client configuration data from the specified X11 display, + * overwriting the current settings in *c */ +int pa_client_conf_from_x11(pa_client_conf *c, const char *display); + +#endif diff --git a/src/polyp/client-conf.c b/src/polyp/client-conf.c new file mode 100644 index 00000000..2df201ce --- /dev/null +++ b/src/polyp/client-conf.c @@ -0,0 +1,191 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#ifndef DEFAULT_CONFIG_DIR +# ifndef OS_IS_WIN32 +# define DEFAULT_CONFIG_DIR "/etc/polypaudio" +# else +# define DEFAULT_CONFIG_DIR "%POLYP_ROOT%" +# endif +#endif + +#ifndef OS_IS_WIN32 +# define PATH_SEP "/" +#else +# define PATH_SEP "\\" +#endif + +#define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "client.conf" +#define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio" PATH_SEP "client.conf" + +#define ENV_CLIENT_CONFIG_FILE "POLYP_CLIENTCONFIG" +#define ENV_DEFAULT_SINK "POLYP_SINK" +#define ENV_DEFAULT_SOURCE "POLYP_SOURCE" +#define ENV_DEFAULT_SERVER "POLYP_SERVER" +#define ENV_DAEMON_BINARY "POLYP_BINARY" +#define ENV_COOKIE_FILE "POLYP_COOKIE" + +static const pa_client_conf default_conf = { + .daemon_binary = NULL, + .extra_arguments = NULL, + .default_sink = NULL, + .default_source = NULL, + .default_server = NULL, + .autospawn = 0, + .cookie_file = NULL, + .cookie_valid = 0 +}; + +pa_client_conf *pa_client_conf_new(void) { + pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); + + c->daemon_binary = pa_xstrdup(POLYPAUDIO_BINARY); + c->extra_arguments = pa_xstrdup("--log-target=syslog --exit-idle-time=5"); + c->cookie_file = pa_xstrdup(PA_NATIVE_COOKIE_FILE); + + return c; +} + +void pa_client_conf_free(pa_client_conf *c) { + assert(c); + pa_xfree(c->daemon_binary); + pa_xfree(c->extra_arguments); + pa_xfree(c->default_sink); + pa_xfree(c->default_source); + pa_xfree(c->default_server); + pa_xfree(c->cookie_file); + pa_xfree(c); +} +int pa_client_conf_load(pa_client_conf *c, const char *filename) { + FILE *f = NULL; + char *fn = NULL; + int r = -1; + + /* Prepare the configuration parse table */ + pa_config_item table[] = { + { "daemon-binary", pa_config_parse_string, NULL }, + { "extra-arguments", pa_config_parse_string, NULL }, + { "default-sink", pa_config_parse_string, NULL }, + { "default-source", pa_config_parse_string, NULL }, + { "default-server", pa_config_parse_string, NULL }, + { "autospawn", pa_config_parse_bool, NULL }, + { "cookie-file", pa_config_parse_string, NULL }, + { NULL, NULL, NULL }, + }; + + table[0].data = &c->daemon_binary; + table[1].data = &c->extra_arguments; + table[2].data = &c->default_sink; + table[3].data = &c->default_source; + table[4].data = &c->default_server; + table[5].data = &c->autospawn; + table[6].data = &c->cookie_file; + + f = filename ? + fopen((fn = pa_xstrdup(filename)), "r") : + pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn); + + if (!f && errno != EINTR) { + pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno)); + goto finish; + } + + r = f ? pa_config_parse(fn, f, table, NULL) : 0; + + if (!r) + r = pa_client_conf_load_cookie(c); + + +finish: + pa_xfree(fn); + + if (f) + fclose(f); + + return r; +} + +int pa_client_conf_env(pa_client_conf *c) { + char *e; + + if ((e = getenv(ENV_DEFAULT_SINK))) { + pa_xfree(c->default_sink); + c->default_sink = pa_xstrdup(e); + } + + if ((e = getenv(ENV_DEFAULT_SOURCE))) { + pa_xfree(c->default_source); + c->default_source = pa_xstrdup(e); + } + + if ((e = getenv(ENV_DEFAULT_SERVER))) { + pa_xfree(c->default_server); + c->default_server = pa_xstrdup(e); + } + + if ((e = getenv(ENV_DAEMON_BINARY))) { + pa_xfree(c->daemon_binary); + c->daemon_binary = pa_xstrdup(e); + } + + if ((e = getenv(ENV_COOKIE_FILE))) { + pa_xfree(c->cookie_file); + c->cookie_file = pa_xstrdup(e); + + return pa_client_conf_load_cookie(c); + } + + return 0; +} + +int pa_client_conf_load_cookie(pa_client_conf* c) { + assert(c); + + c->cookie_valid = 0; + + if (!c->cookie_file) + return -1; + + if (pa_authkey_load_auto(c->cookie_file, c->cookie, sizeof(c->cookie)) < 0) + return -1; + + c->cookie_valid = 1; + return 0; +} + diff --git a/src/polyp/client-conf.h b/src/polyp/client-conf.h new file mode 100644 index 00000000..2d8a019f --- /dev/null +++ b/src/polyp/client-conf.h @@ -0,0 +1,52 @@ +#ifndef fooclientconfhfoo +#define fooclientconfhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "../polypcore/native-common.h" + +/* A structure containing configuration data for polypaudio clients. */ + +typedef struct pa_client_conf { + char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server, *cookie_file; + int autospawn; + uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; + int cookie_valid; /* non-zero, when cookie is valid */ +} pa_client_conf; + +/* Create a new configuration data object and reset it to defaults */ +pa_client_conf *pa_client_conf_new(void); +void pa_client_conf_free(pa_client_conf *c); + +/* Load the configuration data from the speicified file, overwriting + * the current settings in *c. When the filename is NULL, the + * default client configuration file name is used. */ +int pa_client_conf_load(pa_client_conf *c, const char *filename); + +/* Load the configuration data from the environment of the current + process, overwriting the current settings in *c. */ +int pa_client_conf_env(pa_client_conf *c); + +/* Load cookie data from c->cookie_file into c->cookie */ +int pa_client_conf_load_cookie(pa_client_conf* c); + +#endif diff --git a/src/polyp/glib-mainloop.c b/src/polyp/glib-mainloop.c new file mode 100644 index 00000000..962eb574 --- /dev/null +++ b/src/polyp/glib-mainloop.c @@ -0,0 +1,538 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include "glib.h" +#include + +struct pa_io_event { + pa_glib_mainloop *mainloop; + int dead; + GIOChannel *io_channel; + GSource *source; + GIOCondition io_condition; + int fd; + void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); + void *userdata; + void (*destroy_callback) (pa_mainloop_api *m, pa_io_event *e, void *userdata); + pa_io_event *next, *prev; +}; + +struct pa_time_event { + pa_glib_mainloop *mainloop; + int dead; + GSource *source; + struct timeval timeval; + void (*callback) (pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata); + void *userdata; + void (*destroy_callback) (pa_mainloop_api *m, pa_time_event*e, void *userdata); + pa_time_event *next, *prev; +}; + +struct pa_defer_event { + pa_glib_mainloop *mainloop; + int dead; + GSource *source; + void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata); + void *userdata; + void (*destroy_callback) (pa_mainloop_api *m, pa_defer_event*e, void *userdata); + pa_defer_event *next, *prev; +}; + +struct pa_glib_mainloop { + GMainContext *glib_main_context; + pa_mainloop_api api; + GSource *cleanup_source; + pa_io_event *io_events, *dead_io_events; + pa_time_event *time_events, *dead_time_events; + pa_defer_event *defer_events, *dead_defer_events; +}; + +static void schedule_free_dead_events(pa_glib_mainloop *g); + +static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f); + +static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags_t f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata), void *userdata) { + pa_io_event *e; + pa_glib_mainloop *g; + + assert(m && m->userdata && fd >= 0 && callback); + g = m->userdata; + + e = pa_xmalloc(sizeof(pa_io_event)); + e->mainloop = m->userdata; + e->dead = 0; + e->fd = fd; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + + e->io_channel = g_io_channel_unix_new(e->fd); + assert(e->io_channel); + e->source = NULL; + e->io_condition = 0; + + glib_io_enable(e, f); + + e->next = g->io_events; + if (e->next) e->next->prev = e; + g->io_events = e; + e->prev = NULL; + + return e; +} + +/* The callback GLIB calls whenever an IO condition is met */ +static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { + pa_io_event *e = data; + pa_io_event_flags_t f; + assert(source && e && e->io_channel == source); + + f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | + (condition & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) | + (condition & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) | + (condition & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0); + + e->callback(&e->mainloop->api, e, e->fd, f, e->userdata); + return TRUE; +} + +static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { + GIOCondition c; + assert(e && !e->dead); + + c = (f & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | (f & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0); + + if (c == e->io_condition) + return; + + if (e->source) { + g_source_destroy(e->source); + g_source_unref(e->source); + } + + e->source = g_io_create_watch(e->io_channel, c | G_IO_ERR | G_IO_HUP); + assert(e->source); + + g_source_set_callback(e->source, (GSourceFunc) io_cb, e, NULL); + g_source_attach(e->source, e->mainloop->glib_main_context); + g_source_set_priority(e->source, G_PRIORITY_DEFAULT); + + e->io_condition = c; +} + +static void glib_io_free(pa_io_event*e) { + assert(e && !e->dead); + + if (e->source) { + g_source_destroy(e->source); + g_source_unref(e->source); + e->source = NULL; + } + + if (e->prev) + e->prev->next = e->next; + else + e->mainloop->io_events = e->next; + + if (e->next) + e->next->prev = e->prev; + + if ((e->next = e->mainloop->dead_io_events)) + e->next->prev = e; + + e->mainloop->dead_io_events = e; + e->prev = NULL; + + e->dead = 1; + schedule_free_dead_events(e->mainloop); +} + +static void glib_io_set_destroy(pa_io_event*e, void (*callback)(pa_mainloop_api*m, pa_io_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* Time sources */ + +static void glib_time_restart(pa_time_event*e, const struct timeval *tv); + +static pa_time_event* glib_time_new(pa_mainloop_api*m, const struct timeval *tv, void (*callback) (pa_mainloop_api*m, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { + pa_glib_mainloop *g; + pa_time_event *e; + + assert(m && m->userdata && tv && callback); + g = m->userdata; + + e = pa_xmalloc(sizeof(pa_time_event)); + e->mainloop = g; + e->dead = 0; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + e->source = NULL; + + glib_time_restart(e, tv); + + e->next = g->time_events; + if (e->next) e->next->prev = e; + g->time_events = e; + e->prev = NULL; + + return e; +} + +static guint msec_diff(const struct timeval *a, const struct timeval *b) { + guint r; + assert(a && b); + + if (a->tv_sec < b->tv_sec) + return 0; + + if (a->tv_sec == b->tv_sec && a->tv_sec <= b->tv_sec) + return 0; + + r = (a->tv_sec-b->tv_sec)*1000; + + if (a->tv_usec >= b->tv_usec) + r += (a->tv_usec - b->tv_usec) / 1000; + else + r -= (b->tv_usec - a->tv_usec) / 1000; + + return r; +} + +static gboolean time_cb(gpointer data) { + pa_time_event* e = data; + assert(e && e->mainloop && e->source); + + g_source_unref(e->source); + e->source = NULL; + + e->callback(&e->mainloop->api, e, &e->timeval, e->userdata); + return FALSE; +} + +static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { + struct timeval now; + assert(e && e->mainloop && !e->dead); + + pa_gettimeofday(&now); + if (e->source) { + g_source_destroy(e->source); + g_source_unref(e->source); + } + + if (tv) { + e->timeval = *tv; + e->source = g_timeout_source_new(msec_diff(tv, &now)); + assert(e->source); + g_source_set_callback(e->source, time_cb, e, NULL); + g_source_set_priority(e->source, G_PRIORITY_DEFAULT); + g_source_attach(e->source, e->mainloop->glib_main_context); + } else + e->source = NULL; + } + +static void glib_time_free(pa_time_event *e) { + assert(e && e->mainloop && !e->dead); + + if (e->source) { + g_source_destroy(e->source); + g_source_unref(e->source); + e->source = NULL; + } + + if (e->prev) + e->prev->next = e->next; + else + e->mainloop->time_events = e->next; + + if (e->next) + e->next->prev = e->prev; + + if ((e->next = e->mainloop->dead_time_events)) + e->next->prev = e; + + e->mainloop->dead_time_events = e; + e->prev = NULL; + + e->dead = 1; + schedule_free_dead_events(e->mainloop); +} + +static void glib_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*m, pa_time_event*e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* Deferred sources */ + +static void glib_defer_enable(pa_defer_event *e, int b); + +static pa_defer_event* glib_defer_new(pa_mainloop_api*m, void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata), void *userdata) { + pa_defer_event *e; + pa_glib_mainloop *g; + + assert(m && m->userdata && callback); + g = m->userdata; + + e = pa_xmalloc(sizeof(pa_defer_event)); + e->mainloop = g; + e->dead = 0; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + e->source = NULL; + + glib_defer_enable(e, 1); + + e->next = g->defer_events; + if (e->next) e->next->prev = e; + g->defer_events = e; + e->prev = NULL; + return e; +} + +static gboolean idle_cb(gpointer data) { + pa_defer_event* e = data; + assert(e && e->mainloop && e->source); + + e->callback(&e->mainloop->api, e, e->userdata); + return TRUE; +} + +static void glib_defer_enable(pa_defer_event *e, int b) { + assert(e && e->mainloop); + + if (e->source && !b) { + g_source_destroy(e->source); + g_source_unref(e->source); + e->source = NULL; + } else if (!e->source && b) { + e->source = g_idle_source_new(); + assert(e->source); + g_source_set_callback(e->source, idle_cb, e, NULL); + g_source_attach(e->source, e->mainloop->glib_main_context); + g_source_set_priority(e->source, G_PRIORITY_HIGH); + } +} + +static void glib_defer_free(pa_defer_event *e) { + assert(e && e->mainloop && !e->dead); + + if (e->source) { + g_source_destroy(e->source); + g_source_unref(e->source); + e->source = NULL; + } + + if (e->prev) + e->prev->next = e->next; + else + e->mainloop->defer_events = e->next; + + if (e->next) + e->next->prev = e->prev; + + if ((e->next = e->mainloop->dead_defer_events)) + e->next->prev = e; + + e->mainloop->dead_defer_events = e; + e->prev = NULL; + + e->dead = 1; + schedule_free_dead_events(e->mainloop); +} + +static void glib_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api *m, pa_defer_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* quit() */ + +static void glib_quit(pa_mainloop_api*a, PA_GCC_UNUSED int retval) { + pa_glib_mainloop *g; + assert(a && a->userdata); + g = a->userdata; + + /* NOOP */ +} + +static const pa_mainloop_api vtable = { + .userdata = NULL, + + .io_new = glib_io_new, + .io_enable = glib_io_enable, + .io_free = glib_io_free, + .io_set_destroy= glib_io_set_destroy, + + .time_new = glib_time_new, + .time_restart = glib_time_restart, + .time_free = glib_time_free, + .time_set_destroy = glib_time_set_destroy, + + .defer_new = glib_defer_new, + .defer_enable = glib_defer_enable, + .defer_free = glib_defer_free, + .defer_set_destroy = glib_defer_set_destroy, + + .quit = glib_quit, +}; + +pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) { + pa_glib_mainloop *g; + + g = pa_xmalloc(sizeof(pa_glib_mainloop)); + if (c) { + g->glib_main_context = c; + g_main_context_ref(c); + } else + g->glib_main_context = g_main_context_default(); + + g->api = vtable; + g->api.userdata = g; + + g->io_events = g->dead_io_events = NULL; + g->time_events = g->dead_time_events = NULL; + g->defer_events = g->dead_defer_events = NULL; + + g->cleanup_source = NULL; + return g; +} + +static void free_io_events(pa_io_event *e) { + while (e) { + pa_io_event *r = e; + e = r->next; + + if (r->source) { + g_source_destroy(r->source); + g_source_unref(r->source); + } + + if (r->io_channel) + g_io_channel_unref(r->io_channel); + + if (r->destroy_callback) + r->destroy_callback(&r->mainloop->api, r, r->userdata); + + pa_xfree(r); + } +} + +static void free_time_events(pa_time_event *e) { + while (e) { + pa_time_event *r = e; + e = r->next; + + if (r->source) { + g_source_destroy(r->source); + g_source_unref(r->source); + } + + if (r->destroy_callback) + r->destroy_callback(&r->mainloop->api, r, r->userdata); + + pa_xfree(r); + } +} + +static void free_defer_events(pa_defer_event *e) { + while (e) { + pa_defer_event *r = e; + e = r->next; + + if (r->source) { + g_source_destroy(r->source); + g_source_unref(r->source); + } + + if (r->destroy_callback) + r->destroy_callback(&r->mainloop->api, r, r->userdata); + + pa_xfree(r); + } +} + +void pa_glib_mainloop_free(pa_glib_mainloop* g) { + assert(g); + + free_io_events(g->io_events); + free_io_events(g->dead_io_events); + free_defer_events(g->defer_events); + free_defer_events(g->dead_defer_events); + free_time_events(g->time_events); + free_time_events(g->dead_time_events); + + if (g->cleanup_source) { + g_source_destroy(g->cleanup_source); + g_source_unref(g->cleanup_source); + } + + g_main_context_unref(g->glib_main_context); + pa_xfree(g); +} + +pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) { + assert(g); + return &g->api; +} + +static gboolean free_dead_events(gpointer p) { + pa_glib_mainloop *g = p; + assert(g); + + free_io_events(g->dead_io_events); + free_defer_events(g->dead_defer_events); + free_time_events(g->dead_time_events); + + g->dead_io_events = NULL; + g->dead_defer_events = NULL; + g->dead_time_events = NULL; + + g_source_destroy(g->cleanup_source); + g_source_unref(g->cleanup_source); + g->cleanup_source = NULL; + + return FALSE; +} + +static void schedule_free_dead_events(pa_glib_mainloop *g) { + assert(g && g->glib_main_context); + + if (g->cleanup_source) + return; + + g->cleanup_source = g_idle_source_new(); + assert(g->cleanup_source); + g_source_set_callback(g->cleanup_source, free_dead_events, g, NULL); + g_source_attach(g->cleanup_source, g->glib_main_context); +} diff --git a/src/polyp/glib-mainloop.h b/src/polyp/glib-mainloop.h new file mode 100644 index 00000000..b4815ed9 --- /dev/null +++ b/src/polyp/glib-mainloop.h @@ -0,0 +1,55 @@ +#ifndef fooglibmainloophfoo +#define fooglibmainloophfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include + +/** \file + * GLIB main loop support */ + +PA_C_DECL_BEGIN + +/** \pa_glib_mainloop + * An opaque GLIB main loop object */ +typedef struct pa_glib_mainloop pa_glib_mainloop; + +/** Create a new GLIB main loop object for the specified GLIB main loop context. If c is NULL the default context is used. */ +#if GLIB_MAJOR_VERSION >= 2 +pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c); +#else +pa_glib_mainloop *pa_glib_mainloop_new(void); +#endif + + +/** Free the GLIB main loop object */ +void pa_glib_mainloop_free(pa_glib_mainloop* g); + +/** Return the abstract main loop API vtable for the GLIB main loop object */ +pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/glib12-mainloop.c b/src/polyp/glib12-mainloop.c new file mode 100644 index 00000000..80a02b1c --- /dev/null +++ b/src/polyp/glib12-mainloop.c @@ -0,0 +1,500 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include + +/* A mainloop implementation based on GLIB 1.2 */ + +struct pa_io_event { + pa_glib_mainloop *mainloop; + int dead; + GIOChannel *io_channel; + guint source; + GIOCondition io_condition; + int fd; + void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); + void *userdata; + void (*destroy_callback) (pa_mainloop_api *m, pa_io_event*e, void *userdata); + pa_io_event *next, *prev; +}; + +struct pa_time_event { + pa_glib_mainloop *mainloop; + int dead; + guint source; + struct timeval timeval; + void (*callback) (pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata); + void *userdata; + void (*destroy_callback) (pa_mainloop_api *m, pa_time_event*e, void *userdata); + pa_time_event *next, *prev; +}; + +struct pa_defer_event { + pa_glib_mainloop *mainloop; + int dead; + guint source; + void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata); + void *userdata; + void (*destroy_callback) (pa_mainloop_api *m, pa_defer_event*e, void *userdata); + pa_defer_event *next, *prev; +}; + +struct pa_glib_mainloop { + pa_mainloop_api api; + guint cleanup_source; + pa_io_event *io_events, *dead_io_events; + pa_time_event *time_events, *dead_time_events; + pa_defer_event *defer_events, *dead_defer_events; +}; + +static void schedule_free_dead_events(pa_glib_mainloop *g); + +static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f); + +static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags_t f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata), void *userdata) { + pa_io_event *e; + pa_glib_mainloop *g; + + assert(m && m->userdata && fd >= 0 && callback); + g = m->userdata; + + e = pa_xmalloc(sizeof(pa_io_event)); + e->mainloop = m->userdata; + e->dead = 0; + e->fd = fd; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + + e->io_channel = g_io_channel_unix_new(e->fd); + assert(e->io_channel); + e->source = (guint) -1; + e->io_condition = 0; + + glib_io_enable(e, f); + + e->next = g->io_events; + if (e->next) e->next->prev = e; + g->io_events = e; + e->prev = NULL; + + return e; +} + +static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { + pa_io_event *e = data; + pa_io_event_flags_t f; + assert(source && e && e->io_channel == source); + + f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | + (condition & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) | + (condition & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) | + (condition & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0); + + e->callback(&e->mainloop->api, e, e->fd, f, e->userdata); + return TRUE; +} + +static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { + GIOCondition c; + assert(e && !e->dead); + + c = (f & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | (f & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0); + + if (c == e->io_condition) + return; + + if (e->source != (guint) -1) + g_source_remove(e->source); + + e->source = g_io_add_watch_full(e->io_channel, G_PRIORITY_DEFAULT, c | G_IO_ERR | G_IO_HUP, io_cb, e, NULL); + assert(e->source != (guint) -1); + e->io_condition = c; +} + +static void glib_io_free(pa_io_event*e) { + assert(e && !e->dead); + + if (e->source != (guint) -1) { + g_source_remove(e->source); + e->source = (guint) -1; + } + + if (e->prev) + e->prev->next = e->next; + else + e->mainloop->io_events = e->next; + + if (e->next) + e->next->prev = e->prev; + + if ((e->next = e->mainloop->dead_io_events)) + e->next->prev = e; + + e->mainloop->dead_io_events = e; + e->prev = NULL; + + e->dead = 1; + schedule_free_dead_events(e->mainloop); +} + +static void glib_io_set_destroy(pa_io_event*e, void (*callback)(pa_mainloop_api*m, pa_io_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* Time sources */ + +static void glib_time_restart(pa_time_event*e, const struct timeval *tv); + +static pa_time_event* glib_time_new(pa_mainloop_api*m, const struct timeval *tv, void (*callback) (pa_mainloop_api*m, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { + pa_glib_mainloop *g; + pa_time_event *e; + + assert(m && m->userdata && tv && callback); + g = m->userdata; + + e = pa_xmalloc(sizeof(pa_time_event)); + e->mainloop = g; + e->dead = 0; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + e->source = (guint) -1; + + glib_time_restart(e, tv); + + e->next = g->time_events; + if (e->next) e->next->prev = e; + g->time_events = e; + e->prev = NULL; + + return e; +} + +static guint msec_diff(const struct timeval *a, const struct timeval *b) { + guint r; + assert(a && b); + + if (a->tv_sec < b->tv_sec) + return 0; + + if (a->tv_sec == b->tv_sec && a->tv_sec <= b->tv_sec) + return 0; + + r = (a->tv_sec-b->tv_sec)*1000; + + if (a->tv_usec >= b->tv_usec) + r += (a->tv_usec - b->tv_usec) / 1000; + else + r -= (b->tv_usec - a->tv_usec) / 1000; + + return r; +} + +static gboolean time_cb(gpointer data) { + pa_time_event* e = data; + assert(e && e->mainloop && e->source != (guint) -1); + + g_source_remove(e->source); + e->source = (guint) -1; + + e->callback(&e->mainloop->api, e, &e->timeval, e->userdata); + return FALSE; +} + +static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { + struct timeval now; + assert(e && e->mainloop && !e->dead); + + pa_gettimeofday(&now); + if (e->source != (guint) -1) + g_source_remove(e->source); + + if (tv) { + e->timeval = *tv; + e->source = g_timeout_add_full(G_PRIORITY_DEFAULT, msec_diff(tv, &now), time_cb, e, NULL); + assert(e->source != (guint) -1); + } else + e->source = (guint) -1; + } + +static void glib_time_free(pa_time_event *e) { + assert(e && e->mainloop && !e->dead); + + if (e->source != (guint) -1) { + g_source_remove(e->source); + e->source = (guint) -1; + } + + if (e->prev) + e->prev->next = e->next; + else + e->mainloop->time_events = e->next; + + if (e->next) + e->next->prev = e->prev; + + if ((e->next = e->mainloop->dead_time_events)) + e->next->prev = e; + + e->mainloop->dead_time_events = e; + e->prev = NULL; + + e->dead = 1; + schedule_free_dead_events(e->mainloop); +} + +static void glib_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*m, pa_time_event*e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* Deferred sources */ + +static void glib_defer_enable(pa_defer_event *e, int b); + +static pa_defer_event* glib_defer_new(pa_mainloop_api*m, void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata), void *userdata) { + pa_defer_event *e; + pa_glib_mainloop *g; + + assert(m && m->userdata && callback); + g = m->userdata; + + e = pa_xmalloc(sizeof(pa_defer_event)); + e->mainloop = g; + e->dead = 0; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + e->source = (guint) -1; + + glib_defer_enable(e, 1); + + e->next = g->defer_events; + if (e->next) e->next->prev = e; + g->defer_events = e; + e->prev = NULL; + return e; +} + +static gboolean idle_cb(gpointer data) { + pa_defer_event* e = data; + assert(e && e->mainloop && e->source != (guint) -1); + + e->callback(&e->mainloop->api, e, e->userdata); + return TRUE; +} + +static void glib_defer_enable(pa_defer_event *e, int b) { + assert(e && e->mainloop); + + if (e->source != (guint) -1 && !b) { + g_source_remove(e->source); + e->source = (guint) -1; + } else if (e->source == (guint) -1 && b) { + e->source = g_idle_add_full(G_PRIORITY_HIGH, idle_cb, e, NULL); + assert(e->source != (guint) -1); + } +} + +static void glib_defer_free(pa_defer_event *e) { + assert(e && e->mainloop && !e->dead); + + if (e->source != (guint) -1) { + g_source_remove(e->source); + e->source = (guint) -1; + } + + if (e->prev) + e->prev->next = e->next; + else + e->mainloop->defer_events = e->next; + + if (e->next) + e->next->prev = e->prev; + + if ((e->next = e->mainloop->dead_defer_events)) + e->next->prev = e; + + e->mainloop->dead_defer_events = e; + e->prev = NULL; + + e->dead = 1; + schedule_free_dead_events(e->mainloop); +} + +static void glib_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api *m, pa_defer_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* quit() */ + +static void glib_quit(pa_mainloop_api*a, PA_GCC_UNUSED int retval) { + pa_glib_mainloop *g; + assert(a && a->userdata); + g = a->userdata; + + /* NOOP */ +} + +static const pa_mainloop_api vtable = { + .userdata = NULL, + + .io_new = glib_io_new, + .io_enable = glib_io_enable, + .io_free = glib_io_free, + .io_set_destroy= glib_io_set_destroy, + + .time_new = glib_time_new, + .time_restart = glib_time_restart, + .time_free = glib_time_free, + .time_set_destroy = glib_time_set_destroy, + + .defer_new = glib_defer_new, + .defer_enable = glib_defer_enable, + .defer_free = glib_defer_free, + .defer_set_destroy = glib_defer_set_destroy, + + .quit = glib_quit, +}; + +pa_glib_mainloop *pa_glib_mainloop_new(void) { + pa_glib_mainloop *g; + + g = pa_xmalloc(sizeof(pa_glib_mainloop)); + + g->api = vtable; + g->api.userdata = g; + + g->io_events = g->dead_io_events = NULL; + g->time_events = g->dead_time_events = NULL; + g->defer_events = g->dead_defer_events = NULL; + + g->cleanup_source = (guint) -1; + return g; +} + +static void free_io_events(pa_io_event *e) { + while (e) { + pa_io_event *r = e; + e = r->next; + + if (r->source != (guint) -1) + g_source_remove(r->source); + + if (r->io_channel) + g_io_channel_unref(r->io_channel); + + if (r->destroy_callback) + r->destroy_callback(&r->mainloop->api, r, r->userdata); + + pa_xfree(r); + } +} + +static void free_time_events(pa_time_event *e) { + while (e) { + pa_time_event *r = e; + e = r->next; + + if (r->source != (guint) -1) + g_source_remove(r->source); + + if (r->destroy_callback) + r->destroy_callback(&r->mainloop->api, r, r->userdata); + + pa_xfree(r); + } +} + +static void free_defer_events(pa_defer_event *e) { + while (e) { + pa_defer_event *r = e; + e = r->next; + + if (r->source != (guint) -1) + g_source_remove(r->source); + + if (r->destroy_callback) + r->destroy_callback(&r->mainloop->api, r, r->userdata); + + pa_xfree(r); + } +} + +void pa_glib_mainloop_free(pa_glib_mainloop* g) { + assert(g); + + free_io_events(g->io_events); + free_io_events(g->dead_io_events); + free_defer_events(g->defer_events); + free_defer_events(g->dead_defer_events); + free_time_events(g->time_events); + free_time_events(g->dead_time_events); + + if (g->cleanup_source != (guint) -1) + g_source_remove(g->cleanup_source); + + pa_xfree(g); +} + +pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) { + assert(g); + return &g->api; +} + +static gboolean free_dead_events(gpointer p) { + pa_glib_mainloop *g = p; + assert(g); + + free_io_events(g->dead_io_events); + free_defer_events(g->dead_defer_events); + free_time_events(g->dead_time_events); + + g->dead_io_events = NULL; + g->dead_defer_events = NULL; + g->dead_time_events = NULL; + + g_source_remove(g->cleanup_source); + g->cleanup_source = (guint) -1; + + return FALSE; +} + +static void schedule_free_dead_events(pa_glib_mainloop *g) { + assert(g); + + if (g->cleanup_source != (guint) -1) + return; + + g->cleanup_source = g_idle_add_full(G_PRIORITY_HIGH, free_dead_events, g, NULL); +} diff --git a/src/polyp/mainloop-api.c b/src/polyp/mainloop-api.c new file mode 100644 index 00000000..a3eaee9c --- /dev/null +++ b/src/polyp/mainloop-api.c @@ -0,0 +1,68 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "mainloop-api.h" +#include +#include + +struct once_info { + void (*callback)(pa_mainloop_api*m, void *userdata); + void *userdata; +}; + +static void once_callback(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { + struct once_info *i = userdata; + assert(m && i && i->callback); + + i->callback(m, i->userdata); + + assert(m->defer_free); + m->defer_free(e); +} + +static void free_callback(pa_mainloop_api *m, PA_GCC_UNUSED pa_defer_event *e, void *userdata) { + struct once_info *i = userdata; + assert(m && i); + pa_xfree(i); +} + +void pa_mainloop_api_once(pa_mainloop_api* m, void (*callback)(pa_mainloop_api *m, void *userdata), void *userdata) { + struct once_info *i; + pa_defer_event *e; + assert(m && callback); + + i = pa_xnew(struct once_info, 1); + i->callback = callback; + i->userdata = userdata; + + assert(m->defer_new); + e = m->defer_new(m, once_callback, i); + assert(e); + m->defer_set_destroy(e, free_callback); +} + diff --git a/src/polyp/mainloop-api.h b/src/polyp/mainloop-api.h new file mode 100644 index 00000000..91ee4111 --- /dev/null +++ b/src/polyp/mainloop-api.h @@ -0,0 +1,120 @@ +#ifndef foomainloopapihfoo +#define foomainloopapihfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include + +/** \file + * + * Main loop abstraction layer. Both the polypaudio core and the + * polypaudio client library use a main loop abstraction layer. Due to + * this it is possible to embed polypaudio into other + * applications easily. Two main loop implemenations are + * currently available: + * \li A minimal implementation based on the C library's poll() function (See \ref mainloop.h) + * \li A wrapper around the GLIB main loop. Use this to embed polypaudio into your GLIB/GTK+/GNOME programs (See \ref glib-mainloop.h) + * + * The structure pa_mainloop_api is used as vtable for the main loop abstraction. + * + * This mainloop abstraction layer has no direct support for UNIX signals. Generic, mainloop implementation agnostic support is available throught \ref mainloop-signal.h. + * */ + +PA_C_DECL_BEGIN + +/** A bitmask for IO events */ +typedef enum pa_io_event_flags { + PA_IO_EVENT_NULL = 0, /**< No event */ + PA_IO_EVENT_INPUT = 1, /**< Input event */ + PA_IO_EVENT_OUTPUT = 2, /**< Output event */ + PA_IO_EVENT_HANGUP = 4, /**< Hangup event */ + PA_IO_EVENT_ERROR = 8 /**< Error event */ +} pa_io_event_flags_t; + +/** \pa_io_event + * An opaque IO event source object */ +typedef struct pa_io_event pa_io_event; + +/** \pa_defer_event + * An opaque deferred event source object. Events of this type are triggered once in every main loop iteration */ +typedef struct pa_defer_event pa_defer_event; + +/** \pa_time_event + * An opaque timer event source object */ +typedef struct pa_time_event pa_time_event; + +/** An abstract mainloop API vtable */ +typedef struct pa_mainloop_api pa_mainloop_api; + +struct pa_mainloop_api { + /** A pointer to some private, arbitrary data of the main loop implementation */ + void *userdata; + + /** Create a new IO event source object */ + pa_io_event* (*io_new)(pa_mainloop_api*a, int fd, pa_io_event_flags_t events, void (*callback) (pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata); + + /** Enable or disable IO events on this object */ + void (*io_enable)(pa_io_event* e, pa_io_event_flags_t events); + + /** Free a IO event source object */ + void (*io_free)(pa_io_event* e); + + /** Set a function that is called when the IO event source is destroyed. Use this to free the userdata argument if required */ + void (*io_set_destroy)(pa_io_event *e, void (*callback) (pa_mainloop_api*a, pa_io_event *e, void *userdata)); + + /** Create a new timer event source object for the specified Unix time */ + pa_time_event* (*time_new)(pa_mainloop_api*a, const struct timeval *tv, void (*callback) (pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata), void *userdata); + + /** Restart a running or expired timer event source with a new Unix time */ + void (*time_restart)(pa_time_event* e, const struct timeval *tv); + + /** Free a deferred timer event source object */ + void (*time_free)(pa_time_event* e); + + /** Set a function that is called when the timer event source is destroyed. Use this to free the userdata argument if required */ + void (*time_set_destroy)(pa_time_event *e, void (*callback) (pa_mainloop_api*a, pa_time_event *e, void *userdata)); + + /** Create a new deferred event source object */ + pa_defer_event* (*defer_new)(pa_mainloop_api*a, void (*callback) (pa_mainloop_api*a, pa_defer_event* e, void *userdata), void *userdata); + + /** Enable or disable a deferred event source temporarily */ + void (*defer_enable)(pa_defer_event* e, int b); + + /** Free a deferred event source object */ + void (*defer_free)(pa_defer_event* e); + + /** Set a function that is called when the deferred event source is destroyed. Use this to free the userdata argument if required */ + void (*defer_set_destroy)(pa_defer_event *e, void (*callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata)); + + /** Exit the main loop and return the specfied retval*/ + void (*quit)(pa_mainloop_api*a, int retval); +}; + +/** Run the specified callback function once from the main loop using an anonymous defer event. */ +void pa_mainloop_api_once(pa_mainloop_api*m, void (*callback)(pa_mainloop_api*m, void *userdata), void *userdata); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/mainloop-signal.c b/src/polyp/mainloop-signal.c new file mode 100644 index 00000000..a03c9159 --- /dev/null +++ b/src/polyp/mainloop-signal.c @@ -0,0 +1,267 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include +#include +#include +#include +#include + +struct pa_signal_event { + int sig; +#ifdef HAVE_SIGACTION + struct sigaction saved_sigaction; +#else + void (*saved_handler)(int sig); +#endif + void (*callback) (pa_mainloop_api*a, pa_signal_event *e, int sig, void *userdata); + void *userdata; + void (*destroy_callback) (pa_mainloop_api*a, pa_signal_event*e, void *userdata); + pa_signal_event *previous, *next; +}; + +static pa_mainloop_api *api = NULL; +static int signal_pipe[2] = { -1, -1 }; +static pa_io_event* io_event = NULL; +static pa_defer_event *defer_event = NULL; +static pa_signal_event *signals = NULL; + +#ifdef OS_IS_WIN32 +static unsigned int waiting_signals = 0; +static CRITICAL_SECTION crit; +#endif + +static void signal_handler(int sig) { +#ifndef HAVE_SIGACTION + signal(sig, signal_handler); +#endif + write(signal_pipe[1], &sig, sizeof(sig)); + +#ifdef OS_IS_WIN32 + EnterCriticalSection(&crit); + waiting_signals++; + LeaveCriticalSection(&crit); +#endif +} + +static void dispatch(pa_mainloop_api*a, int sig) { + pa_signal_event*s; + + for (s = signals; s; s = s->next) + if (s->sig == sig) { + assert(s->callback); + s->callback(a, s, sig, s->userdata); + break; + } +} + +static void defer(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event*e, PA_GCC_UNUSED void *userdata) { + ssize_t r; + int sig; + unsigned int sigs; + +#ifdef OS_IS_WIN32 + EnterCriticalSection(&crit); + sigs = waiting_signals; + waiting_signals = 0; + LeaveCriticalSection(&crit); +#endif + + while (sigs) { + if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) { + pa_log(__FILE__": read(): %s\n", strerror(errno)); + return; + } + + if (r != sizeof(sig)) { + pa_log(__FILE__": short read()\n"); + return; + } + + dispatch(a, sig); + + sigs--; + } +} + +static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags_t f, PA_GCC_UNUSED void *userdata) { + ssize_t r; + int sig; + assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]); + + + if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) { + if (errno == EAGAIN) + return; + + pa_log(__FILE__": read(): %s\n", strerror(errno)); + return; + } + + if (r != sizeof(sig)) { + pa_log(__FILE__": short read()\n"); + return; + } + + dispatch(a, sig); +} + +int pa_signal_init(pa_mainloop_api *a) { + assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event && !defer_event); + +#ifdef OS_IS_WIN32 + if (_pipe(signal_pipe, 200, _O_BINARY) < 0) { +#else + if (pipe(signal_pipe) < 0) { +#endif + pa_log(__FILE__": pipe() failed: %s\n", strerror(errno)); + return -1; + } + + pa_make_nonblock_fd(signal_pipe[0]); + pa_make_nonblock_fd(signal_pipe[1]); + pa_fd_set_cloexec(signal_pipe[0], 1); + pa_fd_set_cloexec(signal_pipe[1], 1); + + api = a; + +#ifndef OS_IS_WIN32 + io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL); + assert(io_event); +#else + defer_event = api->defer_new(api, defer, NULL); + assert(defer_event); + + InitializeCriticalSection(&crit); +#endif + + return 0; +} + +void pa_signal_done(void) { + assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && (io_event || defer_event)); + + while (signals) + pa_signal_free(signals); + + +#ifndef OS_IS_WIN32 + api->io_free(io_event); + io_event = NULL; +#else + api->defer_free(defer_event); + defer_event = NULL; + + DeleteCriticalSection(&crit); +#endif + + close(signal_pipe[0]); + close(signal_pipe[1]); + signal_pipe[0] = signal_pipe[1] = -1; + + api = NULL; +} + +pa_signal_event* pa_signal_new(int sig, void (*_callback) (pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata), void *userdata) { + pa_signal_event *e = NULL; + +#ifdef HAVE_SIGACTION + struct sigaction sa; +#endif + + assert(sig > 0 && _callback); + + for (e = signals; e; e = e->next) + if (e->sig == sig) + goto fail; + + e = pa_xmalloc(sizeof(pa_signal_event)); + e->sig = sig; + e->callback = _callback; + e->userdata = userdata; + e->destroy_callback = NULL; + +#ifdef HAVE_SIGACTION + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = signal_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + + if (sigaction(sig, &sa, &e->saved_sigaction) < 0) +#else + if ((e->saved_handler = signal(sig, signal_handler)) == SIG_ERR) +#endif + goto fail; + + e->previous = NULL; + e->next = signals; + signals = e; + + return e; +fail: + if (e) + pa_xfree(e); + return NULL; +} + +void pa_signal_free(pa_signal_event *e) { + assert(e); + + if (e->next) + e->next->previous = e->previous; + if (e->previous) + e->previous->next = e->next; + else + signals = e->next; + +#ifdef HAVE_SIGACTION + sigaction(e->sig, &e->saved_sigaction, NULL); +#else + signal(e->sig, e->saved_handler); +#endif + + if (e->destroy_callback) + e->destroy_callback(api, e, e->userdata); + + pa_xfree(e); +} + +void pa_signal_set_destroy(pa_signal_event *e, void (*_callback) (pa_mainloop_api *api, pa_signal_event*e, void *userdata)) { + assert(e); + e->destroy_callback = _callback; +} diff --git a/src/polyp/mainloop-signal.h b/src/polyp/mainloop-signal.h new file mode 100644 index 00000000..76065b22 --- /dev/null +++ b/src/polyp/mainloop-signal.h @@ -0,0 +1,60 @@ +#ifndef foomainloopsignalhfoo +#define foomainloopsignalhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +PA_C_DECL_BEGIN + +/** \file + * UNIX signal support for main loops. In contrast to other + * main loop event sources such as timer and IO events, UNIX signal + * support requires modification of the global process + * environment. Due to this the generic main loop abstraction layer as + * defined in \ref mainloop-api.h doesn't have direct support for UNIX + * signals. However, you may hook signal support into an abstract main loop via the routines defined herein. + */ + +/** Initialize the UNIX signal subsystem and bind it to the specified main loop */ +int pa_signal_init(pa_mainloop_api *api); + +/** Cleanup the signal subsystem */ +void pa_signal_done(void); + +/** \pa_signal_event + * An opaque UNIX signal event source object */ +typedef struct pa_signal_event pa_signal_event; + +/** Create a new UNIX signal event source object */ +pa_signal_event* pa_signal_new(int sig, void (*callback) (pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata), void *userdata); + +/** Free a UNIX signal event source object */ +void pa_signal_free(pa_signal_event *e); + +/** Set a function that is called when the signal event source is destroyed. Use this to free the userdata argument if required */ +void pa_signal_set_destroy(pa_signal_event *e, void (*callback) (pa_mainloop_api *api, pa_signal_event*e, void *userdata)); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/mainloop.c b/src/polyp/mainloop.c new file mode 100644 index 00000000..3fa9245c --- /dev/null +++ b/src/polyp/mainloop.c @@ -0,0 +1,812 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_POLL_H +#include +#else +#include "poll.h" +#endif + +#include + +#include "mainloop.h" +#include +#include +#include +#include + +struct pa_io_event { + pa_mainloop *mainloop; + int dead; + int fd; + pa_io_event_flags_t events; + void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); + struct pollfd *pollfd; + void *userdata; + void (*destroy_callback) (pa_mainloop_api*a, pa_io_event *e, void *userdata); +}; + +struct pa_time_event { + pa_mainloop *mainloop; + int dead; + int enabled; + struct timeval timeval; + void (*callback)(pa_mainloop_api*a, pa_time_event *e, const struct timeval*tv, void *userdata); + void *userdata; + void (*destroy_callback) (pa_mainloop_api*a, pa_time_event *e, void *userdata); +}; + +struct pa_defer_event { + pa_mainloop *mainloop; + int dead; + int enabled; + void (*callback)(pa_mainloop_api*a, pa_defer_event*e, void *userdata); + void *userdata; + void (*destroy_callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata); +}; + +struct pa_mainloop { + pa_idxset *io_events, *time_events, *defer_events; + int io_events_scan_dead, defer_events_scan_dead, time_events_scan_dead; + + struct pollfd *pollfds; + unsigned max_pollfds, n_pollfds; + int rebuild_pollfds; + + int prepared_timeout; + + int quit, retval; + pa_mainloop_api api; + + int deferred_pending; + + int wakeup_pipe[2]; + + enum { + STATE_PASSIVE, + STATE_PREPARED, + STATE_POLLING, + STATE_POLLED, + STATE_QUIT + } state; +}; + +/* IO events */ +static pa_io_event* mainloop_io_new( + pa_mainloop_api*a, + int fd, + pa_io_event_flags_t events, + void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), + void *userdata) { + + pa_mainloop *m; + pa_io_event *e; + + assert(a && a->userdata && fd >= 0 && callback); + m = a->userdata; + assert(a == &m->api); + + pa_mainloop_wakeup(m); + + e = pa_xmalloc(sizeof(pa_io_event)); + e->mainloop = m; + e->dead = 0; + + e->fd = fd; + e->events = events; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + e->pollfd = NULL; + +#ifdef OS_IS_WIN32 + { + fd_set xset; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 0; + + FD_ZERO (&xset); + FD_SET (fd, &xset); + + if ((select((SELECT_TYPE_ARG1) fd, NULL, NULL, SELECT_TYPE_ARG234 &xset, + SELECT_TYPE_ARG5 &tv) == -1) && + (WSAGetLastError() == WSAENOTSOCK)) { + pa_log_warn(__FILE__": WARNING: cannot monitor non-socket file descriptors.\n"); + e->dead = 1; + } + } +#endif + + pa_idxset_put(m->io_events, e, NULL); + m->rebuild_pollfds = 1; + return e; +} + +static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags_t events) { + assert(e && e->mainloop); + + pa_mainloop_wakeup(e->mainloop); + + e->events = events; + e->mainloop->rebuild_pollfds = 1; +} + +static void mainloop_io_free(pa_io_event *e) { + assert(e && e->mainloop); + + pa_mainloop_wakeup(e->mainloop); + + e->dead = e->mainloop->io_events_scan_dead = e->mainloop->rebuild_pollfds = 1; +} + +static void mainloop_io_set_destroy(pa_io_event *e, void (*callback)(pa_mainloop_api*a, pa_io_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* Defer events */ +static pa_defer_event* mainloop_defer_new(pa_mainloop_api*a, void (*callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata), void *userdata) { + pa_mainloop *m; + pa_defer_event *e; + + assert(a && a->userdata && callback); + m = a->userdata; + assert(a == &m->api); + + e = pa_xmalloc(sizeof(pa_defer_event)); + e->mainloop = m; + e->dead = 0; + + e->enabled = 1; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + + pa_idxset_put(m->defer_events, e, NULL); + + m->deferred_pending++; + return e; +} + +static void mainloop_defer_enable(pa_defer_event *e, int b) { + assert(e); + + if (e->enabled && !b) { + assert(e->mainloop->deferred_pending > 0); + e->mainloop->deferred_pending--; + } else if (!e->enabled && b) + e->mainloop->deferred_pending++; + + e->enabled = b; +} + +static void mainloop_defer_free(pa_defer_event *e) { + assert(e); + e->dead = e->mainloop->defer_events_scan_dead = 1; + + if (e->enabled) { + e->enabled = 0; + assert(e->mainloop->deferred_pending > 0); + e->mainloop->deferred_pending--; + } +} + +static void mainloop_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api*a, pa_defer_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* Time events */ +static pa_time_event* mainloop_time_new(pa_mainloop_api*a, const struct timeval *tv, void (*callback) (pa_mainloop_api*a, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { + pa_mainloop *m; + pa_time_event *e; + + assert(a && a->userdata && callback); + m = a->userdata; + assert(a == &m->api); + + pa_mainloop_wakeup(m); + + e = pa_xmalloc(sizeof(pa_time_event)); + e->mainloop = m; + e->dead = 0; + + e->enabled = !!tv; + if (tv) + e->timeval = *tv; + + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + + pa_idxset_put(m->time_events, e, NULL); + + return e; +} + +static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) { + assert(e); + + pa_mainloop_wakeup(e->mainloop); + + if (tv) { + e->enabled = 1; + e->timeval = *tv; + } else + e->enabled = 0; +} + +static void mainloop_time_free(pa_time_event *e) { + assert(e); + + pa_mainloop_wakeup(e->mainloop); + + e->dead = e->mainloop->time_events_scan_dead = 1; +} + +static void mainloop_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*a, pa_time_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* quit() */ + +static void mainloop_quit(pa_mainloop_api*a, int retval) { + pa_mainloop *m; + assert(a && a->userdata); + m = a->userdata; + assert(a == &m->api); + + pa_mainloop_wakeup(m); + + m->quit = 1; + m->retval = retval; +} + +static const pa_mainloop_api vtable = { + .userdata = NULL, + + .io_new= mainloop_io_new, + .io_enable= mainloop_io_enable, + .io_free= mainloop_io_free, + .io_set_destroy= mainloop_io_set_destroy, + + .time_new = mainloop_time_new, + .time_restart = mainloop_time_restart, + .time_free = mainloop_time_free, + .time_set_destroy = mainloop_time_set_destroy, + + .defer_new = mainloop_defer_new, + .defer_enable = mainloop_defer_enable, + .defer_free = mainloop_defer_free, + .defer_set_destroy = mainloop_defer_set_destroy, + + .quit = mainloop_quit, +}; + +pa_mainloop *pa_mainloop_new(void) { + pa_mainloop *m; + + m = pa_xmalloc(sizeof(pa_mainloop)); + +#ifndef OS_ISWIN32 + if (pipe(m->wakeup_pipe) < 0) { + pa_xfree(m); + return NULL; + } + + pa_make_nonblock_fd(m->wakeup_pipe[0]); + pa_make_nonblock_fd(m->wakeup_pipe[1]); +#else + m->wakeup_pipe[0] = -1; + m->wakeup_pipe[1] = -1; +#endif + + m->io_events = pa_idxset_new(NULL, NULL); + m->defer_events = pa_idxset_new(NULL, NULL); + m->time_events = pa_idxset_new(NULL, NULL); + + assert(m->io_events && m->defer_events && m->time_events); + + m->io_events_scan_dead = m->defer_events_scan_dead = m->time_events_scan_dead = 0; + + m->pollfds = NULL; + m->max_pollfds = m->n_pollfds = m->rebuild_pollfds = 0; + + m->quit = m->retval = 0; + + m->api = vtable; + m->api.userdata = m; + + m->deferred_pending = 0; + + m->state = STATE_PASSIVE; + + return m; +} + +static int io_foreach(void *p, uint32_t PA_GCC_UNUSED idx, int *del, void*userdata) { + pa_io_event *e = p; + int *all = userdata; + assert(e && del && all); + + if (!*all && !e->dead) + return 0; + + if (e->destroy_callback) + e->destroy_callback(&e->mainloop->api, e, e->userdata); + pa_xfree(e); + *del = 1; + return 0; +} + +static int time_foreach(void *p, uint32_t PA_GCC_UNUSED idx, int *del, void*userdata) { + pa_time_event *e = p; + int *all = userdata; + assert(e && del && all); + + if (!*all && !e->dead) + return 0; + + if (e->destroy_callback) + e->destroy_callback(&e->mainloop->api, e, e->userdata); + pa_xfree(e); + *del = 1; + return 0; +} + +static int defer_foreach(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void*userdata) { + pa_defer_event *e = p; + int *all = userdata; + assert(e && del && all); + + if (!*all && !e->dead) + return 0; + + if (e->destroy_callback) + e->destroy_callback(&e->mainloop->api, e, e->userdata); + pa_xfree(e); + *del = 1; + return 0; +} + +void pa_mainloop_free(pa_mainloop* m) { + int all = 1; + assert(m && (m->state != STATE_POLLING)); + + pa_idxset_foreach(m->io_events, io_foreach, &all); + pa_idxset_foreach(m->time_events, time_foreach, &all); + pa_idxset_foreach(m->defer_events, defer_foreach, &all); + + pa_idxset_free(m->io_events, NULL, NULL); + pa_idxset_free(m->time_events, NULL, NULL); + pa_idxset_free(m->defer_events, NULL, NULL); + + pa_xfree(m->pollfds); + + if (m->wakeup_pipe[0] >= 0) + close(m->wakeup_pipe[0]); + if (m->wakeup_pipe[1] >= 0) + close(m->wakeup_pipe[1]); + + pa_xfree(m); +} + +static void scan_dead(pa_mainloop *m) { + int all = 0; + assert(m); + + if (m->io_events_scan_dead) + pa_idxset_foreach(m->io_events, io_foreach, &all); + if (m->time_events_scan_dead) + pa_idxset_foreach(m->time_events, time_foreach, &all); + if (m->defer_events_scan_dead) + pa_idxset_foreach(m->defer_events, defer_foreach, &all); + + m->io_events_scan_dead = m->time_events_scan_dead = m->defer_events_scan_dead = 0; +} + +static void rebuild_pollfds(pa_mainloop *m) { + pa_io_event*e; + struct pollfd *p; + uint32_t idx = PA_IDXSET_INVALID; + unsigned l; + + l = pa_idxset_size(m->io_events) + 1; + if (m->max_pollfds < l) { + m->pollfds = pa_xrealloc(m->pollfds, sizeof(struct pollfd)*l); + m->max_pollfds = l; + } + + m->n_pollfds = 0; + p = m->pollfds; + + if (m->wakeup_pipe[0] >= 0) { + m->pollfds[0].fd = m->wakeup_pipe[0]; + m->pollfds[0].events = POLLIN; + m->pollfds[0].revents = 0; + p++; + m->n_pollfds++; + } + + for (e = pa_idxset_first(m->io_events, &idx); e; e = pa_idxset_next(m->io_events, &idx)) { + if (e->dead) { + e->pollfd = NULL; + continue; + } + + e->pollfd = p; + p->fd = e->fd; + p->events = + ((e->events & PA_IO_EVENT_INPUT) ? POLLIN : 0) | + ((e->events & PA_IO_EVENT_OUTPUT) ? POLLOUT : 0) | + POLLHUP | + POLLERR; + p->revents = 0; + + p++; + m->n_pollfds++; + } + + m->rebuild_pollfds = 0; +} + +static int dispatch_pollfds(pa_mainloop *m) { + uint32_t idx = PA_IDXSET_INVALID; + pa_io_event *e; + int r = 0; + + for (e = pa_idxset_first(m->io_events, &idx); e && !m->quit; e = pa_idxset_next(m->io_events, &idx)) { + if (e->dead || !e->pollfd || !e->pollfd->revents) + continue; + + assert(e->pollfd->fd == e->fd && e->callback); + e->callback(&m->api, e, e->fd, + (e->pollfd->revents & POLLHUP ? PA_IO_EVENT_HANGUP : 0) | + (e->pollfd->revents & POLLIN ? PA_IO_EVENT_INPUT : 0) | + (e->pollfd->revents & POLLOUT ? PA_IO_EVENT_OUTPUT : 0) | + (e->pollfd->revents & POLLERR ? PA_IO_EVENT_ERROR : 0), + e->userdata); + e->pollfd->revents = 0; + r++; + } + + return r; +} + +static int dispatch_defer(pa_mainloop *m) { + uint32_t idx; + pa_defer_event *e; + int r = 0; + + if (!m->deferred_pending) + return 0; + + for (e = pa_idxset_first(m->defer_events, &idx); e && !m->quit; e = pa_idxset_next(m->defer_events, &idx)) { + if (e->dead || !e->enabled) + continue; + + assert(e->callback); + e->callback(&m->api, e, e->userdata); + r++; + } + + return r; +} + +static int calc_next_timeout(pa_mainloop *m) { + uint32_t idx; + pa_time_event *e; + struct timeval now; + int t = -1; + int got_time = 0; + + if (pa_idxset_isempty(m->time_events)) + return -1; + + for (e = pa_idxset_first(m->time_events, &idx); e; e = pa_idxset_next(m->time_events, &idx)) { + int tmp; + + if (e->dead || !e->enabled) + continue; + + /* Let's save a system call */ + if (!got_time) { + pa_gettimeofday(&now); + got_time = 1; + } + + if (e->timeval.tv_sec < now.tv_sec || (e->timeval.tv_sec == now.tv_sec && e->timeval.tv_usec <= now.tv_usec)) + return 0; + + tmp = (e->timeval.tv_sec - now.tv_sec)*1000; + + if (e->timeval.tv_usec > now.tv_usec) + tmp += (e->timeval.tv_usec - now.tv_usec)/1000; + else + tmp -= (now.tv_usec - e->timeval.tv_usec)/1000; + + if (tmp == 0) + return 0; + else if (t == -1 || tmp < t) + t = tmp; + } + + return t; +} + +static int dispatch_timeout(pa_mainloop *m) { + uint32_t idx; + pa_time_event *e; + struct timeval now; + int got_time = 0; + int r = 0; + assert(m); + + if (pa_idxset_isempty(m->time_events)) + return 0; + + for (e = pa_idxset_first(m->time_events, &idx); e && !m->quit; e = pa_idxset_next(m->time_events, &idx)) { + + if (e->dead || !e->enabled) + continue; + + /* Let's save a system call */ + if (!got_time) { + pa_gettimeofday(&now); + got_time = 1; + } + + if (e->timeval.tv_sec < now.tv_sec || (e->timeval.tv_sec == now.tv_sec && e->timeval.tv_usec <= now.tv_usec)) { + assert(e->callback); + + e->enabled = 0; + e->callback(&m->api, e, &e->timeval, e->userdata); + + r++; + } + } + + return r; +} + +void pa_mainloop_wakeup(pa_mainloop *m) { + char c = 'W'; + assert(m); + + if (m->wakeup_pipe[1] >= 0) + write(m->wakeup_pipe[1], &c, sizeof(c)); +} + +static void clear_wakeup(pa_mainloop *m) { + char c[10]; + + assert(m); + + if (m->wakeup_pipe[0] < 0) + return; + + while (read(m->wakeup_pipe[0], &c, sizeof(c)) == sizeof(c)); +} + +int pa_mainloop_prepare(pa_mainloop *m, int timeout) { + int dispatched = 0; + + assert(m && (m->state == STATE_PASSIVE)); + + clear_wakeup(m); + + scan_dead(m); + + if (m->quit) + goto quit; + + dispatched += dispatch_defer(m); + + if (m->quit) + goto quit; + + if (m->rebuild_pollfds) + rebuild_pollfds(m); + + m->prepared_timeout = calc_next_timeout(m); + if ((timeout >= 0) && (m->prepared_timeout > timeout)) + m->prepared_timeout = timeout; + + m->state = STATE_PREPARED; + + return dispatched; + +quit: + + m->state = STATE_QUIT; + + return -2; +} + +int pa_mainloop_poll(pa_mainloop *m) { + int r; + + assert(m && (m->state == STATE_PREPARED)); + + m->state = STATE_POLLING; + + r = poll(m->pollfds, m->n_pollfds, m->prepared_timeout); + + if ((r < 0) && (errno == EINTR)) + r = 0; + + if (r < 0) + m->state = STATE_PASSIVE; + else + m->state = STATE_POLLED; + + return r; +} + +int pa_mainloop_dispatch(pa_mainloop *m) { + int dispatched = 0; + + assert(m && (m->state == STATE_POLLED)); + + dispatched += dispatch_timeout(m); + + if (m->quit) + goto quit; + + dispatched += dispatch_pollfds(m); + + if (m->quit) + goto quit; + + m->state = STATE_PASSIVE; + + return dispatched; + +quit: + + m->state = STATE_QUIT; + + return -2; +} + +int pa_mainloop_get_retval(pa_mainloop *m) { + assert(m); + return m->retval; +} + +int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) { + int r, dispatched = 0; + + assert(m); + + r = pa_mainloop_prepare(m, block ? -1 : 0); + if (r < 0) { + if ((r == -2) && retval) + *retval = pa_mainloop_get_retval(m); + return r; + } + + dispatched += r; + + r = pa_mainloop_poll(m); + if (r < 0) { + pa_log(__FILE__": poll(): %s\n", strerror(errno)); + return r; + } + + r = pa_mainloop_dispatch(m); + if (r < 0) { + if ((r == -2) && retval) + *retval = pa_mainloop_get_retval(m); + return r; + } + + dispatched += r; + + return dispatched; +} + +int pa_mainloop_run(pa_mainloop *m, int *retval) { + int r; + while ((r = pa_mainloop_iterate(m, 1, retval)) >= 0); + + if (r == -2) + return 1; + else if (r < 0) + return -1; + else + return 0; +} + +void pa_mainloop_quit(pa_mainloop *m, int r) { + assert(m); + pa_mainloop_wakeup(m); + m->quit = r; +} + +pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m) { + assert(m); + return &m->api; +} + +int pa_mainloop_deferred_pending(pa_mainloop *m) { + assert(m); + return m->deferred_pending > 0; +} + + +#if 0 +void pa_mainloop_dump(pa_mainloop *m) { + assert(m); + + pa_log(__FILE__": Dumping mainloop sources START\n"); + + { + uint32_t idx = PA_IDXSET_INVALID; + pa_io_event *e; + for (e = pa_idxset_first(m->io_events, &idx); e; e = pa_idxset_next(m->io_events, &idx)) { + if (e->dead) + continue; + + pa_log(__FILE__": kind=io fd=%i events=%i callback=%p userdata=%p\n", e->fd, (int) e->events, (void*) e->callback, (void*) e->userdata); + } + } + { + uint32_t idx = PA_IDXSET_INVALID; + pa_defer_event *e; + for (e = pa_idxset_first(m->defer_events, &idx); e; e = pa_idxset_next(m->defer_events, &idx)) { + if (e->dead) + continue; + + pa_log(__FILE__": kind=defer enabled=%i callback=%p userdata=%p\n", e->enabled, (void*) e->callback, (void*) e->userdata); + } + } + { + uint32_t idx = PA_IDXSET_INVALID; + pa_time_event *e; + for (e = pa_idxset_first(m->time_events, &idx); e; e = pa_idxset_next(m->time_events, &idx)) { + if (e->dead) + continue; + + pa_log(__FILE__": kind=time enabled=%i time=%lu.%lu callback=%p userdata=%p\n", e->enabled, (unsigned long) e->timeval.tv_sec, (unsigned long) e->timeval.tv_usec, (void*) e->callback, (void*) e->userdata); + } + } + + pa_log(__FILE__": Dumping mainloop sources STOP\n"); + +} +#endif diff --git a/src/polyp/mainloop.h b/src/polyp/mainloop.h new file mode 100644 index 00000000..691f8c50 --- /dev/null +++ b/src/polyp/mainloop.h @@ -0,0 +1,90 @@ +#ifndef foomainloophfoo +#define foomainloophfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +PA_C_DECL_BEGIN + +/** \file + * + * A minimal main loop implementation based on the C library's poll() + * function. Using the routines defined herein you may create a simple + * main loop supporting the generic main loop abstraction layer as + * defined in \ref mainloop-api.h. This implementation is thread safe + * as long as you access the main loop object from a single thread only.*/ + +/** \pa_mainloop + * An opaque main loop object + */ +typedef struct pa_mainloop pa_mainloop; + +/** Allocate a new main loop object */ +pa_mainloop *pa_mainloop_new(void); + +/** Free a main loop object */ +void pa_mainloop_free(pa_mainloop* m); + + +/** Prepare for a single iteration of the main loop. Returns a negative value +on error or exit request. timeout specifies a maximum timeout for the subsequent +poll, or -1 for blocking behaviour. Defer events are also dispatched when this +function is called. On success returns the number of source dispatched in this +iteration.*/ +int pa_mainloop_prepare(pa_mainloop *m, int timeout); +/** Execute the previously prepared poll. Returns a negative value on error.*/ +int pa_mainloop_poll(pa_mainloop *m); +/** Dispatch timeout and io events from the previously executed poll. Returns +a negative value on error. On success returns the number of source dispatched. */ +int pa_mainloop_dispatch(pa_mainloop *m); + +/** Return the return value as specified with the main loop's quit() routine. */ +int pa_mainloop_get_retval(pa_mainloop *m); + +/** Run a single iteration of the main loop. This is a convenience function +for pa_mainloop_prepare(), pa_mainloop_poll() and pa_mainloop_dispatch(). +Returns a negative value on error or exit request. If block is nonzero, +block for events if none are queued. Optionally return the return value as +specified with the main loop's quit() routine in the integer variable retval points +to. On success returns the number of source dispatched in this iteration. */ +int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval); + +/** Run unlimited iterations of the main loop object until the main loop's quit() routine is called. */ +int pa_mainloop_run(pa_mainloop *m, int *retval); + +/** Return the abstract main loop abstraction layer vtable for this main loop. This calls pa_mainloop_iterate() iteratively.*/ +pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m); + +/** Return non-zero when there are any deferred events pending. \since 0.5 */ +int pa_mainloop_deferred_pending(pa_mainloop *m); + +/** Shutdown the main loop */ +void pa_mainloop_quit(pa_mainloop *m, int r); + +/** Interrupt a running poll (for threaded systems) */ +void pa_mainloop_wakeup(pa_mainloop *m); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/polyplib-browser.c b/src/polyp/polyplib-browser.c new file mode 100644 index 00000000..9a389484 --- /dev/null +++ b/src/polyp/polyplib-browser.c @@ -0,0 +1,312 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include "polyplib-browser.h" +#include +#include +#include + +#define SERVICE_NAME_SINK "_polypaudio-sink._tcp." +#define SERVICE_NAME_SOURCE "_polypaudio-source._tcp." +#define SERVICE_NAME_SERVER "_polypaudio-server._tcp." + +pa_browser { + int ref; + pa_mainloop_api *mainloop; + + void (*callback)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void *userdata); + void *callback_userdata; + + sw_discovery discovery; + pa_io_event *io_event; +}; + + +static void io_callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags events, void *userdata) { + pa_browser *b = userdata; + assert(a && b && b->mainloop == a); + + if (events != PA_IO_EVENT_INPUT || sw_discovery_read_socket(b->discovery) != SW_OKAY) { + pa_log(__FILE__": connection to HOWL daemon failed.\n"); + b->mainloop->io_free(b->io_event); + b->io_event = NULL; + return; + } +} + +static sw_result resolve_reply( + sw_discovery discovery, + sw_discovery_oid oid, + sw_uint32 interface_index, + sw_const_string name, + sw_const_string type, + sw_const_string domain, + sw_ipv4_address address, + sw_port port, + sw_octets text_record, + sw_ulong text_record_len, + sw_opaque extra) { + + pa_browser *b = extra; + pa_browse_info i; + char ip[256], a[256]; + pa_browse_opcode opcode; + int device_found = 0; + uint32_t cookie; + pa_typeid_t typeid; + pa_sample_spec ss; + int ss_valid = 0; + sw_text_record_iterator iterator; + int free_iterator = 0; + char *c = NULL; + + assert(b); + + sw_discovery_cancel(discovery, oid); + + memset(&i, 0, sizeof(i)); + i.name = name; + + if (!b->callback) + goto fail; + + if (!strcmp(type, SERVICE_NAME_SINK)) + opcode = PA_BROWSE_NEW_SINK; + else if (!strcmp(type, SERVICE_NAME_SOURCE)) + opcode = PA_BROWSE_NEW_SOURCE; + else if (!strcmp(type, SERVICE_NAME_SERVER)) + opcode = PA_BROWSE_NEW_SERVER; + else + goto fail; + + + snprintf(a, sizeof(a), "tcp:%s:%u", sw_ipv4_address_name(address, ip, sizeof(ip)), port); + i.server = a; + + if (text_record && text_record_len) { + char key[SW_TEXT_RECORD_MAX_LEN]; + uint8_t val[SW_TEXT_RECORD_MAX_LEN]; + uint32_t val_len; + + if (sw_text_record_iterator_init(&iterator, text_record, text_record_len) != SW_OKAY) { + pa_log("sw_text_record_string_iterator_init() failed.\n"); + goto fail; + } + + free_iterator = 1; + + while (sw_text_record_iterator_next(iterator, key, val, &val_len) == SW_OKAY) { + c = pa_xstrndup((char*) val, val_len); + + if (!strcmp(key, "device")) { + device_found = 1; + pa_xfree((char*) i.device); + i.device = c; + c = NULL; + } else if (!strcmp(key, "server-version")) { + pa_xfree((char*) i.server_version); + i.server_version = c; + c = NULL; + } else if (!strcmp(key, "user-name")) { + pa_xfree((char*) i.user_name); + i.user_name = c; + c = NULL; + } else if (!strcmp(key, "fqdn")) { + size_t l; + + pa_xfree((char*) i.fqdn); + i.fqdn = c; + c = NULL; + + l = strlen(a); + assert(l+1 <= sizeof(a)); + strncat(a, " ", sizeof(a)-l-1); + strncat(a, i.fqdn, sizeof(a)-l-2); + } else if (!strcmp(key, "cookie")) { + + if (pa_atou(c, &cookie) < 0) + goto fail; + + i.cookie = &cookie; + } else if (!strcmp(key, "description")) { + pa_xfree((char*) i.description); + i.description = c; + c = NULL; + } else if (!strcmp(key, "typeid")) { + + if (pa_atou(c, &typeid) < 0) + goto fail; + + i.typeid = &typeid; + } else if (!strcmp(key, "channels")) { + uint32_t ch; + + if (pa_atou(c, &ch) < 0 || ch <= 0 || ch > 255) + goto fail; + + ss.channels = (uint8_t) ch; + ss_valid |= 1; + + } else if (!strcmp(key, "rate")) { + if (pa_atou(c, &ss.rate) < 0) + goto fail; + ss_valid |= 2; + } else if (!strcmp(key, "format")) { + + if ((ss.format = pa_parse_sample_format(c)) == PA_SAMPLE_INVALID) + goto fail; + + ss_valid |= 4; + } + + pa_xfree(c); + c = NULL; + } + + } + + /* No device txt record was sent for a sink or source service */ + if (opcode != PA_BROWSE_NEW_SERVER && !device_found) + goto fail; + + if (ss_valid == 7) + i.sample_spec = &ss; + + + b->callback(b, opcode, &i, b->callback_userdata); + +fail: + pa_xfree((void*) i.device); + pa_xfree((void*) i.fqdn); + pa_xfree((void*) i.server_version); + pa_xfree((void*) i.user_name); + pa_xfree((void*) i.description); + pa_xfree(c); + + if (free_iterator) + sw_text_record_iterator_fina(iterator); + + + return SW_OKAY; +} + +static sw_result browse_reply( + sw_discovery discovery, + sw_discovery_oid id, + sw_discovery_browse_status status, + sw_uint32 interface_index, + sw_const_string name, + sw_const_string type, + sw_const_string domain, + sw_opaque extra) { + + pa_browser *b = extra; + assert(b); + + switch (status) { + case SW_DISCOVERY_BROWSE_ADD_SERVICE: { + sw_discovery_oid oid; + + if (sw_discovery_resolve(b->discovery, 0, name, type, domain, resolve_reply, b, &oid) != SW_OKAY) + pa_log("sw_discovery_resolve() failed\n"); + + break; + } + + case SW_DISCOVERY_BROWSE_REMOVE_SERVICE: + if (b->callback) { + pa_browse_info i; + memset(&i, 0, sizeof(i)); + i.name = name; + b->callback(b, PA_BROWSE_REMOVE, &i, b->callback_userdata); + } + break; + + default: + ; + } + + return SW_OKAY; +} + +pa_browser *pa_browser_new(pa_mainloop_api *mainloop) { + pa_browser *b; + sw_discovery_oid oid; + + b = pa_xmalloc(sizeof(pa_browser)); + b->mainloop = mainloop; + b->ref = 1; + b->callback = NULL; + b->callback_userdata = NULL; + + if (sw_discovery_init(&b->discovery) != SW_OKAY) { + pa_log("sw_discovery_init() failed.\n"); + pa_xfree(b); + return NULL; + } + + if (sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SERVER, NULL, browse_reply, b, &oid) != SW_OKAY || + sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SINK, NULL, browse_reply, b, &oid) != SW_OKAY || + sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SOURCE, NULL, browse_reply, b, &oid) != SW_OKAY) { + + pa_log("sw_discovery_browse() failed.\n"); + + sw_discovery_fina(b->discovery); + pa_xfree(b); + return NULL; + } + + b->io_event = mainloop->io_new(mainloop, sw_discovery_socket(b->discovery), PA_IO_EVENT_INPUT, io_callback, b); + return b; +} + +static void browser_free(pa_browser *b) { + assert(b && b->mainloop); + + if (b->io_event) + b->mainloop->io_free(b->io_event); + + sw_discovery_fina(b->discovery); + pa_xfree(b); +} + +pa_browser *pa_browser_ref(pa_browser *b) { + assert(b && b->ref >= 1); + b->ref++; + return b; +} + +void pa_browser_unref(pa_browser *b) { + assert(b && b->ref >= 1); + + if ((-- (b->ref)) <= 0) + browser_free(b); +} + +void pa_browser_set_callback(pa_browser *b, void (*cb)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void* userdata), void *userdata) { + assert(b); + + b->callback = cb; + b->callback_userdata = userdata; +} diff --git a/src/polyp/polyplib-browser.h b/src/polyp/polyplib-browser.h new file mode 100644 index 00000000..853304d7 --- /dev/null +++ b/src/polyp/polyplib-browser.h @@ -0,0 +1,65 @@ +#ifndef foopolyplibbrowserhfoo +#define foopolyplibbrowserhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +PA_C_DECL_BEGIN + +pa_browser; + +pa_browse_opcode { + PA_BROWSE_NEW_SERVER, + PA_BROWSE_NEW_SINK, + PA_BROWSE_NEW_SOURCE, + PA_BROWSE_REMOVE +}; + +pa_browser *pa_browser_new(pa_mainloop_api *mainloop); +pa_browser *pa_browser_ref(pa_browser *z); +void pa_browser_unref(pa_browser *z); + +pa_browse_info { + /* Unique service name */ + const char *name; /* always available */ + + /* Server info */ + const char *server; /* always available */ + const char *server_version, *user_name, *fqdn; /* optional */ + const uint32_t *cookie; /* optional */ + + /* Device info */ + const char *device; /* always available when this information is of a sink/source */ + const char *description; /* optional */ + const pa_typeid_t *typeid; /* optional */ + const pa_sample_spec *sample_spec; /* optional */ +}; + +void pa_browser_set_callback(pa_browser *z, void (*cb)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void *userdata), void *userdata); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/polyplib-context.c b/src/polyp/polyplib-context.c new file mode 100644 index 00000000..c392f0fc --- /dev/null +++ b/src/polyp/polyplib-context.c @@ -0,0 +1,871 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_WAIT_H +#include +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif + +#include + +#include "polyplib-internal.h" +#include "polyplib-context.h" +#include "polyplib-version.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_X11 +#include "client-conf-x11.h" +#endif + +#define AUTOSPAWN_LOCK "autospawn.lock" + +static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_REQUEST] = pa_command_request, + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = pa_command_stream_killed, + [PA_COMMAND_RECORD_STREAM_KILLED] = pa_command_stream_killed, + [PA_COMMAND_SUBSCRIBE_EVENT] = pa_command_subscribe_event +}; + +static void unlock_autospawn_lock_file(pa_context *c) { + assert(c); + + if (c->autospawn_lock_fd >= 0) { + char lf[PATH_MAX]; + pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); + + pa_unlock_lockfile(lf, c->autospawn_lock_fd); + c->autospawn_lock_fd = -1; + } +} + +pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { + pa_context *c; + assert(mainloop && name); + + c = pa_xmalloc(sizeof(pa_context)); + c->ref = 1; + c->name = pa_xstrdup(name); + c->mainloop = mainloop; + c->client = NULL; + c->pstream = NULL; + c->pdispatch = NULL; + c->playback_streams = pa_dynarray_new(); + c->record_streams = pa_dynarray_new(); + assert(c->playback_streams && c->record_streams); + + PA_LLIST_HEAD_INIT(pa_stream, c->streams); + PA_LLIST_HEAD_INIT(pa_operation, c->operations); + + c->error = PA_ERROR_OK; + c->state = PA_CONTEXT_UNCONNECTED; + c->ctag = 0; + + c->state_callback = NULL; + c->state_userdata = NULL; + + c->subscribe_callback = NULL; + c->subscribe_userdata = NULL; + + c->memblock_stat = pa_memblock_stat_new(); + c->local = -1; + c->server_list = NULL; + c->server = NULL; + c->autospawn_lock_fd = -1; + memset(&c->spawn_api, 0, sizeof(c->spawn_api)); + c->do_autospawn = 0; + +#ifdef SIGPIPE + pa_check_signal_is_blocked(SIGPIPE); +#endif + + c->conf = pa_client_conf_new(); + pa_client_conf_load(c->conf, NULL); +#ifdef HAVE_X11 + pa_client_conf_from_x11(c->conf, NULL); +#endif + pa_client_conf_env(c->conf); + + return c; +} + +static void context_free(pa_context *c) { + assert(c); + + unlock_autospawn_lock_file(c); + + while (c->operations) + pa_operation_cancel(c->operations); + + while (c->streams) + pa_stream_set_state(c->streams, PA_STREAM_TERMINATED); + + if (c->client) + pa_socket_client_unref(c->client); + if (c->pdispatch) + pa_pdispatch_unref(c->pdispatch); + if (c->pstream) { + pa_pstream_close(c->pstream); + pa_pstream_unref(c->pstream); + } + + if (c->record_streams) + pa_dynarray_free(c->record_streams, NULL, NULL); + if (c->playback_streams) + pa_dynarray_free(c->playback_streams, NULL, NULL); + + pa_memblock_stat_unref(c->memblock_stat); + + if (c->conf) + pa_client_conf_free(c->conf); + + pa_strlist_free(c->server_list); + + pa_xfree(c->name); + pa_xfree(c->server); + pa_xfree(c); +} + +pa_context* pa_context_ref(pa_context *c) { + assert(c && c->ref >= 1); + c->ref++; + return c; +} + +void pa_context_unref(pa_context *c) { + assert(c && c->ref >= 1); + + if ((--(c->ref)) == 0) + context_free(c); +} + +void pa_context_set_state(pa_context *c, pa_context_state_t st) { + assert(c); + + if (c->state == st) + return; + + pa_context_ref(c); + + if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) { + pa_stream *s; + + s = c->streams ? pa_stream_ref(c->streams) : NULL; + while (s) { + pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL; + pa_stream_set_state(s, st == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED); + pa_stream_unref(s); + s = n; + } + + if (c->pdispatch) + pa_pdispatch_unref(c->pdispatch); + c->pdispatch = NULL; + + if (c->pstream) { + pa_pstream_close(c->pstream); + pa_pstream_unref(c->pstream); + } + c->pstream = NULL; + + if (c->client) + pa_socket_client_unref(c->client); + c->client = NULL; + } + + c->state = st; + if (c->state_callback) + c->state_callback(c, c->state_userdata); + + pa_context_unref(c); +} + +void pa_context_fail(pa_context *c, int error) { + assert(c); + c->error = error; + pa_context_set_state(c, PA_CONTEXT_FAILED); +} + +static void pstream_die_callback(pa_pstream *p, void *userdata) { + pa_context *c = userdata; + assert(p && c); + pa_context_fail(c, PA_ERROR_CONNECTIONTERMINATED); +} + +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { + pa_context *c = userdata; + assert(p && packet && c); + + pa_context_ref(c); + + if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { + pa_log(__FILE__": invalid packet.\n"); + pa_context_fail(c, PA_ERROR_PROTOCOL); + } + + pa_context_unref(c); +} + +static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, PA_GCC_UNUSED uint32_t delta, const pa_memchunk *chunk, void *userdata) { + pa_context *c = userdata; + pa_stream *s; + assert(p && chunk && c && chunk->memblock && chunk->memblock->data); + + pa_context_ref(c); + + if ((s = pa_dynarray_get(c->record_streams, channel))) { + pa_mcalign_push(s->mcalign, chunk); + + for (;;) { + pa_memchunk t; + + if (pa_mcalign_pop(s->mcalign, &t) < 0) + break; + + if (s->read_callback) { + s->read_callback(s, (uint8_t*) t.memblock->data + t.index, t.length, s->read_userdata); + s->counter += chunk->length; + } + + pa_memblock_unref(t.memblock); + } + } + + pa_context_unref(c); +} + +int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t) { + assert(c); + + if (command == PA_COMMAND_ERROR) { + assert(t); + + if (pa_tagstruct_getu32(t, &c->error) < 0) { + pa_context_fail(c, PA_ERROR_PROTOCOL); + return -1; + + } + } else if (command == PA_COMMAND_TIMEOUT) + c->error = PA_ERROR_TIMEOUT; + else { + pa_context_fail(c, PA_ERROR_PROTOCOL); + return -1; + } + + return 0; +} + +static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_context *c = userdata; + assert(pd && c && (c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME)); + + pa_context_ref(c); + + if (command != PA_COMMAND_REPLY) { + + if (pa_context_handle_error(c, command, t) < 0) + pa_context_fail(c, PA_ERROR_PROTOCOL); + + pa_context_fail(c, c->error); + goto finish; + } + + switch(c->state) { + case PA_CONTEXT_AUTHORIZING: { + pa_tagstruct *reply; + reply = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME); + pa_tagstruct_putu32(reply, tag = c->ctag++); + pa_tagstruct_puts(reply, c->name); + pa_pstream_send_tagstruct(c->pstream, reply); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + + pa_context_set_state(c, PA_CONTEXT_SETTING_NAME); + break; + } + + case PA_CONTEXT_SETTING_NAME : + pa_context_set_state(c, PA_CONTEXT_READY); + break; + + default: + assert(0); + } + +finish: + pa_context_unref(c); +} + +static void setup_context(pa_context *c, pa_iochannel *io) { + pa_tagstruct *t; + uint32_t tag; + assert(c && io); + + pa_context_ref(c); + + assert(!c->pstream); + c->pstream = pa_pstream_new(c->mainloop, io, c->memblock_stat); + assert(c->pstream); + + pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); + pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); + pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); + + assert(!c->pdispatch); + c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); + assert(c->pdispatch); + + if (!c->conf->cookie_valid) { + pa_context_fail(c, PA_ERROR_AUTHKEY); + goto finish; + } + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_AUTH); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie)); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + + pa_context_set_state(c, PA_CONTEXT_AUTHORIZING); + +finish: + + pa_context_unref(c); +} + +static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata); + +#ifndef OS_IS_WIN32 + +static int context_connect_spawn(pa_context *c) { + pid_t pid; + int status, r; + int fds[2] = { -1, -1} ; + pa_iochannel *io; + + pa_context_ref(c); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { + pa_log(__FILE__": socketpair() failed: %s\n", strerror(errno)); + pa_context_fail(c, PA_ERROR_INTERNAL); + goto fail; + } + + pa_fd_set_cloexec(fds[0], 1); + + pa_socket_low_delay(fds[0]); + pa_socket_low_delay(fds[1]); + + if (c->spawn_api.prefork) + c->spawn_api.prefork(); + + if ((pid = fork()) < 0) { + pa_log(__FILE__": fork() failed: %s\n", strerror(errno)); + pa_context_fail(c, PA_ERROR_INTERNAL); + + if (c->spawn_api.postfork) + c->spawn_api.postfork(); + + goto fail; + } else if (!pid) { + /* Child */ + + char t[128]; + const char *state = NULL; +#define MAX_ARGS 64 + const char * argv[MAX_ARGS+1]; + int n; + + /* Not required, since fds[0] has CLOEXEC enabled anyway */ + close(fds[0]); + + if (c->spawn_api.atfork) + c->spawn_api.atfork(); + + /* Setup argv */ + + n = 0; + + argv[n++] = c->conf->daemon_binary; + argv[n++] = "--daemonize=yes"; + + snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]); + argv[n++] = strdup(t); + + while (n < MAX_ARGS) { + char *a; + + if (!(a = pa_split_spaces(c->conf->extra_arguments, &state))) + break; + + argv[n++] = a; + } + + argv[n++] = NULL; + + execv(argv[0], (char * const *) argv); + _exit(1); +#undef MAX_ARGS + } + + /* Parent */ + + r = waitpid(pid, &status, 0); + + if (c->spawn_api.postfork) + c->spawn_api.postfork(); + + if (r < 0) { + pa_log(__FILE__": waitpid() failed: %s\n", strerror(errno)); + pa_context_fail(c, PA_ERROR_INTERNAL); + goto fail; + } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + goto fail; + } + + close(fds[1]); + + c->local = 1; + + io = pa_iochannel_new(c->mainloop, fds[0], fds[0]); + + setup_context(c, io); + unlock_autospawn_lock_file(c); + + pa_context_unref(c); + + return 0; + +fail: + if (fds[0] != -1) + close(fds[0]); + if (fds[1] != -1) + close(fds[1]); + + unlock_autospawn_lock_file(c); + + pa_context_unref(c); + + return -1; +} + +#endif /* OS_IS_WIN32 */ + +static int try_next_connection(pa_context *c) { + char *u = NULL; + int r = -1; + assert(c && !c->client); + + for (;;) { + if (u) + pa_xfree(u); + u = NULL; + + c->server_list = pa_strlist_pop(c->server_list, &u); + + if (!u) { + +#ifndef OS_IS_WIN32 + if (c->do_autospawn) { + r = context_connect_spawn(c); + goto finish; + } +#endif + + pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + goto finish; + } + + pa_log_debug(__FILE__": Trying to connect to %s...\n", u); + + pa_xfree(c->server); + c->server = pa_xstrdup(u); + + if (!(c->client = pa_socket_client_new_string(c->mainloop, u, PA_NATIVE_DEFAULT_PORT))) + continue; + + c->local = pa_socket_client_is_local(c->client); + pa_socket_client_set_callback(c->client, on_connection, c); + break; + } + + r = 0; + +finish: + if (u) + pa_xfree(u); + + return r; +} + +static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata) { + pa_context *c = userdata; + assert(client && c && c->state == PA_CONTEXT_CONNECTING); + + pa_context_ref(c); + + pa_socket_client_unref(client); + c->client = NULL; + + if (!io) { + /* Try the item in the list */ + if (errno == ECONNREFUSED || errno == ETIMEDOUT || errno == EHOSTUNREACH) { + try_next_connection(c); + goto finish; + } + + pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + goto finish; + } + + unlock_autospawn_lock_file(c); + setup_context(c, io); + +finish: + pa_context_unref(c); +} + +int pa_context_connect(pa_context *c, const char *server, int spawn, const pa_spawn_api *api) { + int r = -1; + assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED); + + if (!server) + server = c->conf->default_server; + + pa_context_ref(c); + + assert(!c->server_list); + + if (server) { + if (!(c->server_list = pa_strlist_parse(server))) { + pa_context_fail(c, PA_ERROR_INVALIDSERVER); + goto finish; + } + } else { + char *d; + char ufn[PATH_MAX]; + + /* Prepend in reverse order */ + + if ((d = getenv("DISPLAY"))) { + char *e; + d = pa_xstrdup(d); + if ((e = strchr(d, ':'))) + *e = 0; + + if (*d) + c->server_list = pa_strlist_prepend(c->server_list, d); + + pa_xfree(d); + } + + c->server_list = pa_strlist_prepend(c->server_list, "tcp6:localhost"); + c->server_list = pa_strlist_prepend(c->server_list, "localhost"); + c->server_list = pa_strlist_prepend(c->server_list, pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET, ufn, sizeof(ufn))); + + /* Wrap the connection attempts in a single transaction for sane autospawn locking */ + if (spawn && c->conf->autospawn) { + char lf[PATH_MAX]; + + pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); + pa_make_secure_parent_dir(lf); + assert(c->autospawn_lock_fd <= 0); + c->autospawn_lock_fd = pa_lock_lockfile(lf); + + if (api) + c->spawn_api = *api; + c->do_autospawn = 1; + } + + } + + pa_context_set_state(c, PA_CONTEXT_CONNECTING); + r = try_next_connection(c); + +finish: + pa_context_unref(c); + + return r; +} + +void pa_context_disconnect(pa_context *c) { + assert(c); + pa_context_set_state(c, PA_CONTEXT_TERMINATED); +} + +pa_context_state_t pa_context_get_state(pa_context *c) { + assert(c && c->ref >= 1); + return c->state; +} + +int pa_context_errno(pa_context *c) { + assert(c && c->ref >= 1); + return c->error; +} + +void pa_context_set_state_callback(pa_context *c, void (*cb)(pa_context *c, void *userdata), void *userdata) { + assert(c && c->ref >= 1); + c->state_callback = cb; + c->state_userdata = userdata; +} + +int pa_context_is_pending(pa_context *c) { + assert(c && c->ref >= 1); + +/* pa_log("pstream: %i\n", pa_pstream_is_pending(c->pstream)); */ +/* pa_log("pdispatch: %i\n", pa_pdispatch_is_pending(c->pdispatch)); */ + + return (c->pstream && pa_pstream_is_pending(c->pstream)) || + (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) || + c->client; +} + +static void set_dispatch_callbacks(pa_operation *o); + +static void pdispatch_drain_callback(PA_GCC_UNUSED pa_pdispatch*pd, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void pstream_drain_callback(PA_GCC_UNUSED pa_pstream *s, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void set_dispatch_callbacks(pa_operation *o) { + int done = 1; + assert(o && o->context && o->context->ref >= 1 && o->ref >= 1 && o->context->state == PA_CONTEXT_READY); + + pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL); + + if (pa_pdispatch_is_pending(o->context->pdispatch)) { + pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o); + done = 0; + } + + if (pa_pstream_is_pending(o->context->pstream)) { + pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o); + done = 0; + } + + if (!done) + pa_operation_ref(o); + else { + if (o->callback) { + void (*cb)(pa_context *c, void *userdata); + cb = (void (*)(pa_context*, void*)) o->callback; + cb(o->context, o->userdata); + } + + pa_operation_done(o); + } + + pa_operation_unref(o); +} + +pa_operation* pa_context_drain(pa_context *c, void (*cb) (pa_context*c, void *userdata), void *userdata) { + pa_operation *o; + assert(c && c->ref >= 1); + + if (c->state != PA_CONTEXT_READY) + return NULL; + + if (!pa_context_is_pending(c)) + return NULL; + + o = pa_operation_new(c, NULL); + assert(o); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + set_dispatch_callbacks(pa_operation_ref(o)); + + return o; +} + +void pa_context_exit_daemon(pa_context *c) { + pa_tagstruct *t; + assert(c && c->ref >= 1); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_EXIT); + pa_tagstruct_putu32(t, c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); +} + +void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int success = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + success = 0; + } else if (!pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *c, int _success, void *_userdata) = (void (*)(pa_context *c, int _success, void *_userdata)) o->callback; + cb(o->context, success, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, void (*internal_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata), void (*cb)(void), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, command); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_DEFAULT_SINK); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_set_default_source(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_DEFAULT_SOURCE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +int pa_context_is_local(pa_context *c) { + assert(c); + return c->local; +} + +pa_operation* pa_context_set_name(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && name && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_CLIENT_NAME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +const char* pa_get_library_version(void) { + return PACKAGE_VERSION; +} + +const char* pa_context_get_server(pa_context *c) { + + if (!c->server) + return NULL; + + if (*c->server == '{') { + char *e = strchr(c->server+1, '}'); + return e ? e+1 : c->server; + } + + return c->server; +} diff --git a/src/polyp/polyplib-context.h b/src/polyp/polyplib-context.h new file mode 100644 index 00000000..febb75f4 --- /dev/null +++ b/src/polyp/polyplib-context.h @@ -0,0 +1,117 @@ +#ifndef foopolyplibcontexthfoo +#define foopolyplibcontexthfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include +#include + +/** \file + * Connection contexts for asynchrononous communication with a + * server. A pa_context object wraps a connection to a polypaudio + * server using its native protocol. A context may be used to issue + * commands on the server or to create playback or recording + * streams. Multiple playback streams may be piped through a single + * connection context. Operations on the contect involving + * communication with the server are executed asynchronously: i.e. the + * client function do not implicitely wait for completion of the + * operation on the server. Instead the caller specifies a call back + * function that is called when the operation is completed. Currently + * running operations may be canceled using pa_operation_cancel(). */ + +/** \example pacat.c + * A playback and recording tool using the asynchronous API */ + +/** \example paplay.c + * A sound file playback tool using the asynchronous API, based on libsndfile */ + +PA_C_DECL_BEGIN + +/** \pa_context + * An opaque connection context to a daemon */ +typedef struct pa_context pa_context; + +/** Instantiate a new connection context with an abstract mainloop API + * and an application name */ +pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name); + +/** Decrease the reference counter of the context by one */ +void pa_context_unref(pa_context *c); + +/** Increase the reference counter of the context by one */ +pa_context* pa_context_ref(pa_context *c); + +typedef void (*pa_context_state_callback)(pa_context *c, void *userdata); + +/** Set a callback function that is called whenever the context status changes */ +void pa_context_set_state_callback(pa_context *c, pa_context_state_callback callback, void *userdata); + +/** Return the error number of the last failed operation */ +int pa_context_errno(pa_context *c); + +/** Return non-zero if some data is pending to be written to the connection */ +int pa_context_is_pending(pa_context *c); + +/** Return the current context status */ +pa_context_state_t pa_context_get_state(pa_context *c); + +/** Connect the context to the specified server. If server is NULL, +connect to the default server. This routine may but will not always +return synchronously on error. Use pa_context_set_state_callback() to +be notified when the connection is established. If spawn is non-zero +and no specific server is specified or accessible a new daemon is +spawned. If api is non-NULL, the functions specified in the structure +are used when forking a new child process. */ +int pa_context_connect(pa_context *c, const char *server, int spawn, const pa_spawn_api *api); + +/** Terminate the context connection immediately */ +void pa_context_disconnect(pa_context *c); + +/** Drain the context. If there is nothing to drain, the function returns NULL */ +pa_operation* pa_context_drain(pa_context *c, void (*cb) (pa_context*c, void *userdata), void *userdata); + +/** Tell the daemon to exit. No operation object is returned as the + * connection is terminated when the daemon quits, thus this operation + * would never complete. */ +void pa_context_exit_daemon(pa_context *c); + +/** Set the name of the default sink. \since 0.4 */ +pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata); + +/** Set the name of the default source. \since 0.4 */ +pa_operation* pa_context_set_default_source(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata); + +/** Returns 1 when the connection is to a local daemon. Returns negative when no connection has been made yet. \since 0.5 */ +int pa_context_is_local(pa_context *c); + +/** Set a different application name for context on the server. \since 0.5 */ +pa_operation* pa_context_set_name(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata); + +/** Return the server name this context is connected to. \since 0.7 */ +const char* pa_context_get_server(pa_context *c); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/polyplib-def.h b/src/polyp/polyplib-def.h new file mode 100644 index 00000000..0591ce6c --- /dev/null +++ b/src/polyp/polyplib-def.h @@ -0,0 +1,213 @@ +#ifndef foopolyplibdefhfoo +#define foopolyplibdefhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include + +#include +#include + +/** \file + * Global definitions */ + +PA_C_DECL_BEGIN + +/** The state of a connection context */ +typedef enum pa_context_state { + PA_CONTEXT_UNCONNECTED, /**< The context hasn't been connected yet */ + PA_CONTEXT_CONNECTING, /**< A connection is being established */ + PA_CONTEXT_AUTHORIZING, /**< The client is authorizing itself to the daemon */ + PA_CONTEXT_SETTING_NAME, /**< The client is passing its application name to the daemon */ + PA_CONTEXT_READY, /**< The connection is established, the context is ready to execute operations */ + PA_CONTEXT_FAILED, /**< The connection failed or was disconnected */ + PA_CONTEXT_TERMINATED /**< The connection was terminated cleanly */ +} pa_context_state_t; + +/** The state of a stream */ +typedef enum pa_stream_state { + PA_STREAM_DISCONNECTED, /**< The stream is not yet connected to any sink or source */ + PA_STREAM_CREATING, /**< The stream is being created */ + PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */ + PA_STREAM_FAILED, /**< An error occured that made the stream invalid */ + PA_STREAM_TERMINATED /**< The stream has been terminated cleanly */ +} pa_stream_state_t; + +/** The state of an operation */ +typedef enum pa_operation_state { + PA_OPERATION_RUNNING, /**< The operation is still running */ + PA_OPERATION_DONE, /**< The operation has been completed */ + PA_OPERATION_CANCELED /**< The operation has been canceled */ +} pa_operation_state_t; + +/** An invalid index */ +#define PA_INVALID_INDEX ((uint32_t) -1) + +/** The direction of a pa_stream object */ +typedef enum pa_stream_direction { + PA_STREAM_NODIRECTION, /**< Invalid direction */ + PA_STREAM_PLAYBACK, /**< Playback stream */ + PA_STREAM_RECORD, /**< Record stream */ + PA_STREAM_UPLOAD /**< Sample upload stream */ +} pa_stream_direction_t; + +/** Some special flags for stream connections. \since 0.6 */ +typedef enum pa_stream_flags { + PA_STREAM_START_CORKED = 1, /**< Create the stream corked, requiring an explicit pa_stream_cork() call to uncork it. */ + PA_STREAM_INTERPOLATE_LATENCY = 2 /**< Interpolate the latency for + * this stream. When enabled, + * you can use + * pa_stream_interpolated_xxx() + * for synchronization. Using + * these functions instead of + * pa_stream_get_latency() has + * the advantage of not + * requiring a whole roundtrip + * for responses. Consider using + * this option when frequently + * requesting latency + * information. This is + * especially useful on long latency + * network connections. */ +} pa_stream_flags_t; + +/** Playback and record buffer metrics */ +typedef struct pa_buffer_attr { + uint32_t maxlength; /**< Maximum length of the buffer */ + uint32_t tlength; /**< Playback only: target length of the buffer. The server tries to assure that at least tlength bytes are always available in the buffer */ + uint32_t prebuf; /**< Playback only: pre-buffering. The server does not start with playback before at least prebug bytes are available in the buffer */ + uint32_t minreq; /**< Playback only: minimum request. The server does not request less than minreq bytes from the client, instead waints until the buffer is free enough to request more bytes at once */ + uint32_t fragsize; /**< Recording only: fragment size. The server sends data in blocks of fragsize bytes size. Large values deminish interactivity with other operations on the connection context but decrease control overhead. */ +} pa_buffer_attr; + +/** Error values as used by pa_context_errno(). Use pa_strerror() to convert these values to human readable strings */ +enum { + PA_ERROR_OK, /**< No error */ + PA_ERROR_ACCESS, /**< Access failure */ + PA_ERROR_COMMAND, /**< Unknown command */ + PA_ERROR_INVALID, /**< Invalid argument */ + PA_ERROR_EXIST, /**< Entity exists */ + PA_ERROR_NOENTITY, /**< No such entity */ + PA_ERROR_CONNECTIONREFUSED, /**< Connection refused */ + PA_ERROR_PROTOCOL, /**< Protocol error */ + PA_ERROR_TIMEOUT, /**< Timeout */ + PA_ERROR_AUTHKEY, /**< No authorization key */ + PA_ERROR_INTERNAL, /**< Internal error */ + PA_ERROR_CONNECTIONTERMINATED, /**< Connection terminated */ + PA_ERROR_KILLED, /**< Entity killed */ + PA_ERROR_INVALIDSERVER, /**< Invalid server */ + PA_ERROR_INITFAILED, /**< Module initialization failed */ + PA_ERROR_MAX /**< Not really an error but the first invalid error code */ +}; + +/** Subscription event mask, as used by pa_context_subscribe() */ +typedef enum pa_subscription_mask { + PA_SUBSCRIPTION_MASK_NULL = 0, /**< No events */ + PA_SUBSCRIPTION_MASK_SINK = 1, /**< Sink events */ + PA_SUBSCRIPTION_MASK_SOURCE = 2, /**< Source events */ + PA_SUBSCRIPTION_MASK_SINK_INPUT = 4, /**< Sink input events */ + PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8, /**< Source output events */ + PA_SUBSCRIPTION_MASK_MODULE = 16, /**< Module events */ + PA_SUBSCRIPTION_MASK_CLIENT = 32, /**< Client events */ + PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, /**< Sample cache events */ + PA_SUBSCRIPTION_MASK_SERVER = 128, /**< Other global server changes. \since 0.4 */ + PA_SUBSCRIPTION_MASK_AUTOLOAD = 256 /**< Autoload table events. \since 0.5 */ +} pa_subscription_mask_t; + +/** Subscription event types, as used by pa_context_subscribe() */ +typedef enum pa_subscription_event_type { + PA_SUBSCRIPTION_EVENT_SINK = 0, /**< Event type: Sink */ + PA_SUBSCRIPTION_EVENT_SOURCE = 1, /**< Event type: Source */ + PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2, /**< Event type: Sink input */ + PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 3, /**< Event type: Source output */ + PA_SUBSCRIPTION_EVENT_MODULE = 4, /**< Event type: Module */ + PA_SUBSCRIPTION_EVENT_CLIENT = 5, /**< Event type: Client */ + PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, /**< Event type: Sample cache item */ + PA_SUBSCRIPTION_EVENT_SERVER = 7, /**< Event type: Global server change, only occuring with PA_SUBSCRIPTION_EVENT_CHANGE. \since 0.4 */ + PA_SUBSCRIPTION_EVENT_AUTOLOAD = 8, /**< Event type: Autoload table changes. \since 0.5 */ + PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 15, /**< A mask to extract the event type from an event value */ + + PA_SUBSCRIPTION_EVENT_NEW = 0, /**< A new object was created */ + PA_SUBSCRIPTION_EVENT_CHANGE = 16, /**< A property of the object was modified */ + PA_SUBSCRIPTION_EVENT_REMOVE = 32, /**< An object was removed */ + PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32 /**< A mask to extract the event operation from an event value */ +} pa_subscription_event_type_t; + +/** Return one if an event type t matches an event mask bitfield */ +#define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) + +/** A structure for latency info. See pa_stream_get_latency(). The + * total output latency a sample that is written with + * pa_stream_write() takes to be played may be estimated by + * sink_usec+buffer_usec+transport_usec. The output buffer to which + * buffer_usec relates may be manipulated freely (with + * pa_stream_write()'s delta argument, pa_stream_flush() and friends), + * the buffers sink_usec/source_usec relates to is a first-in + * first-out buffer which cannot be flushed or manipulated in any + * way. The total input latency a sample that is recorded takes to be + * delivered to the application is: + * source_usec+buffer_usec+transport_usec-sink_usec. (Take care of + * sign issues!) When connected to a monitor source sink_usec contains + * the latency of the owning sink.*/ +typedef struct pa_latency_info { + pa_usec_t buffer_usec; /**< Time in usecs the current buffer takes to play. For both playback and record streams. */ + pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. For playback streams and record streams connected to a monitor source. */ + pa_usec_t source_usec; /**< Time in usecs a sample takes from being recorded to being delivered to the application. Only for record streams. \since 0.5*/ + pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to/from the daemon. For both playback and record streams. \since 0.5 */ + int playing; /**< Non-zero when the stream is currently playing. Only for playback streams. */ + uint32_t queue_length; /**< Queue size in bytes. For both playback and record streams. */ + int synchronized_clocks; /**< Non-zero if the local and the + * remote machine have synchronized + * clocks. If synchronized clocks are + * detected transport_usec becomes much + * more reliable. However, the code that + * detects synchronized clocks is very + * limited und unreliable itself. \since + * 0.5 */ + struct timeval timestamp; /**< The time when this latency info was current */ + uint64_t counter; /**< The byte counter current when the latency info was requested. \since 0.6 */ +} pa_latency_info; + +/** A structure for the spawn api. This may be used to integrate auto + * spawned daemons into your application. For more information see + * pa_context_connect(). When spawning a new child process the + * waitpid() is used on the child's PID. The spawn routine will not + * block or ignore SIGCHLD signals, since this cannot be done in a + * thread compatible way. You might have to do this in + * prefork/postfork. \since 0.4 */ +typedef struct pa_spawn_api { + void (*prefork)(void); /**< Is called just before the fork in the parent process. May be NULL. */ + void (*postfork)(void); /**< Is called immediately after the fork in the parent process. May be NULL.*/ + void (*atfork)(void); /**< Is called immediately after the + * fork in the child process. May be + * NULL. It is not safe to close all + * file descriptors in this function + * unconditionally, since a UNIX socket + * (created using socketpair()) is + * passed to the new process. */ +} pa_spawn_api; + +PA_C_DECL_END + +#endif diff --git a/src/polyp/polyplib-error.c b/src/polyp/polyplib-error.c new file mode 100644 index 00000000..188d6a93 --- /dev/null +++ b/src/polyp/polyplib-error.c @@ -0,0 +1,54 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "polyplib-error.h" +#include + +static const char* const errortab[PA_ERROR_MAX] = { + [PA_ERROR_OK] = "OK", + [PA_ERROR_ACCESS] = "Access denied", + [PA_ERROR_COMMAND] = "Unknown command", + [PA_ERROR_INVALID] = "Invalid argument", + [PA_ERROR_EXIST] = "Entity exists", + [PA_ERROR_NOENTITY] = "No such entity", + [PA_ERROR_CONNECTIONREFUSED] = "Connection refused", + [PA_ERROR_PROTOCOL] = "Protocol error", + [PA_ERROR_TIMEOUT] = "Timeout", + [PA_ERROR_AUTHKEY] = "No authorization key", + [PA_ERROR_INTERNAL] = "Internal error", + [PA_ERROR_CONNECTIONTERMINATED] = "Connection terminated", + [PA_ERROR_KILLED] = "Entity killed", + [PA_ERROR_INVALIDSERVER] = "Invalid server", +}; + +const char*pa_strerror(uint32_t error) { + if (error >= PA_ERROR_MAX) + return NULL; + + return errortab[error]; +} diff --git a/src/polyp/polyplib-error.h b/src/polyp/polyplib-error.h new file mode 100644 index 00000000..1bb97822 --- /dev/null +++ b/src/polyp/polyplib-error.h @@ -0,0 +1,38 @@ +#ifndef foopolypliberrorhfoo +#define foopolypliberrorhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/** \file + * Error management */ + +PA_C_DECL_BEGIN + +/** Return a human readable error message for the specified numeric error code */ +const char* pa_strerror(uint32_t error); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/polyplib-internal.h b/src/polyp/polyplib-internal.h new file mode 100644 index 00000000..b95a20f3 --- /dev/null +++ b/src/polyp/polyplib-internal.h @@ -0,0 +1,154 @@ +#ifndef foopolyplibinternalhfoo +#define foopolyplibinternalhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include +#include + +#include "polyplib-context.h" +#include "polyplib-stream.h" +#include "polyplib-operation.h" +#include +#include +#include +#include +#include + +#define DEFAULT_TIMEOUT (10) + +struct pa_context { + int ref; + + char *name; + pa_mainloop_api* mainloop; + + pa_socket_client *client; + pa_pstream *pstream; + pa_pdispatch *pdispatch; + + pa_dynarray *record_streams, *playback_streams; + PA_LLIST_HEAD(pa_stream, streams); + PA_LLIST_HEAD(pa_operation, operations); + + uint32_t ctag; + uint32_t error; + pa_context_state_t state; + + void (*state_callback)(pa_context*c, void *userdata); + void *state_userdata; + + void (*subscribe_callback)(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata); + void *subscribe_userdata; + + pa_memblock_stat *memblock_stat; + + int local; + int do_autospawn; + int autospawn_lock_fd; + pa_spawn_api spawn_api; + + pa_strlist *server_list; + + char *server; + + pa_client_conf *conf; +}; + +struct pa_stream { + int ref; + pa_context *context; + pa_mainloop_api *mainloop; + PA_LLIST_FIELDS(pa_stream); + + char *name; + pa_buffer_attr buffer_attr; + pa_sample_spec sample_spec; + pa_channel_map channel_map; + uint32_t channel; + int channel_valid; + uint32_t device_index; + pa_stream_direction_t direction; + uint32_t requested_bytes; + uint64_t counter; + pa_usec_t previous_time; + pa_usec_t previous_ipol_time; + pa_stream_state_t state; + pa_mcalign *mcalign; + + int interpolate; + int corked; + + uint32_t ipol_usec; + struct timeval ipol_timestamp; + pa_time_event *ipol_event; + int ipol_requested; + + void (*state_callback)(pa_stream*c, void *userdata); + void *state_userdata; + + void (*read_callback)(pa_stream *p, const void*data, size_t length, void *userdata); + void *read_userdata; + + void (*write_callback)(pa_stream *p, size_t length, void *userdata); + void *write_userdata; +}; + +typedef void (*pa_operation_callback)(void); + +struct pa_operation { + int ref; + pa_context *context; + pa_stream *stream; + PA_LLIST_FIELDS(pa_operation); + + pa_operation_state_t state; + void *userdata; + pa_operation_callback callback; +}; + +void pa_command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); + +pa_operation *pa_operation_new(pa_context *c, pa_stream *s); +void pa_operation_done(pa_operation *o); + +void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); + +void pa_context_fail(pa_context *c, int error); +void pa_context_set_state(pa_context *c, pa_context_state_t st); +int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t); +pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, void (*internal_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata), void (*cb)(void), void *userdata); + +void pa_stream_set_state(pa_stream *s, pa_stream_state_t st); + +void pa_stream_trash_ipol(pa_stream *s); + + +#endif diff --git a/src/polyp/polyplib-introspect.c b/src/polyp/polyplib-introspect.c new file mode 100644 index 00000000..0bdffa35 --- /dev/null +++ b/src/polyp/polyplib-introspect.c @@ -0,0 +1,1003 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "polyplib-introspect.h" +#include "polyplib-context.h" +#include "polyplib-internal.h" +#include +#include + +/*** Statistics ***/ + +static void context_stat_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + pa_stat_info i, *p = &i; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + p = NULL; + } else if (pa_tagstruct_getu32(t, &i.memblock_total) < 0 || + pa_tagstruct_getu32(t, &i.memblock_total_size) < 0 || + pa_tagstruct_getu32(t, &i.memblock_allocated) < 0 || + pa_tagstruct_getu32(t, &i.memblock_allocated_size) < 0 || + pa_tagstruct_getu32(t, &i.scache_size) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_stat_info*_i, void *_userdata) = (void (*)(pa_context *s, const pa_stat_info*_i, void *_userdata)) o->callback; + cb(o->context, p, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_stat(pa_context *c, void (*cb)(pa_context *c, const pa_stat_info*i, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_STAT, context_stat_callback, (pa_operation_callback) cb, userdata); +} + +/*** Server Info ***/ + +static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + pa_server_info i, *p = &i; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + p = NULL; + } else if (pa_tagstruct_gets(t, &i.server_name) < 0 || + pa_tagstruct_gets(t, &i.server_version) < 0 || + pa_tagstruct_gets(t, &i.user_name) < 0 || + pa_tagstruct_gets(t, &i.host_name) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_gets(t, &i.default_sink_name) < 0 || + pa_tagstruct_gets(t, &i.default_source_name) < 0 || + pa_tagstruct_getu32(t, &i.cookie) < 0 || + !pa_tagstruct_eof(t)) { + + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_server_info*_i, void *_userdata) = (void (*)(pa_context *s, const pa_server_info*_i, void *_userdata)) o->callback; + cb(o->context, p, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_server_info(pa_context *c, void (*cb)(pa_context *c, const pa_server_info*i, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SERVER_INFO, context_get_server_info_callback, (pa_operation_callback) cb, userdata); +} + +/*** Sink Info ***/ + +static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_sink_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_get_cvolume(t, &i.volume) < 0 || + pa_tagstruct_getu32(t, &i.monitor_source) < 0 || + pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || + pa_tagstruct_get_usec(t, &i.latency) < 0 || + pa_tagstruct_gets(t, &i.driver) < 0) { + + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_sink_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INFO_LIST, context_get_sink_info_callback, (pa_operation_callback) cb, userdata); +} + +pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, o); + + return pa_operation_ref(o); +} + +/*** Source info ***/ + +static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_source_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || + pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 || + pa_tagstruct_get_usec(t, &i.latency) < 0 || + pa_tagstruct_gets(t, &i.driver) < 0) { + + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_source_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_INFO_LIST, context_get_source_info_callback, (pa_operation_callback) cb, userdata); +} + +pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, o); + + return pa_operation_ref(o); +} + +/*** Client info ***/ + +static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_client_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_gets(t, &i.driver) < 0 ) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_client_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_CLIENT_INFO_LIST, context_get_client_info_callback, (pa_operation_callback) cb, userdata); +} + +/*** Module info ***/ + +static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_module_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.argument) < 0 || + pa_tagstruct_getu32(t, &i.n_used) < 0 || + pa_tagstruct_get_boolean(t, &i.auto_unload) < 0) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_module_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_MODULE_INFO_LIST, context_get_module_info_callback, (pa_operation_callback) cb, userdata); +} + +/*** Sink input info ***/ + +static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_sink_input_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.client) < 0 || + pa_tagstruct_getu32(t, &i.sink) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || + pa_tagstruct_get_cvolume(t, &i.volume) < 0 || + pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || + pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || + pa_tagstruct_gets(t, &i.resample_method) < 0 || + pa_tagstruct_gets(t, &i.driver) < 0) { + + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INPUT_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_input_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_sink_input_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INPUT_INFO_LIST, context_get_sink_input_info_callback, (pa_operation_callback) cb, userdata); +} + +/*** Source output info ***/ + +static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_source_output_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.client) < 0 || + pa_tagstruct_getu32(t, &i.source) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || + pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || + pa_tagstruct_get_usec(t, &i.source_usec) < 0 || + pa_tagstruct_gets(t, &i.resample_method) < 0 || + pa_tagstruct_gets(t, &i.driver) < 0) { + + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata))o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_OUTPUT_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_output_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_source_output_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, context_get_source_output_info_callback, (pa_operation_callback) cb, userdata); +} + +/*** Volume manipulation ***/ + +pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && idx != PA_INVALID_INDEX); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_tagstruct_put_cvolume(t, volume); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && name); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_tagstruct_put_cvolume(t, volume); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && idx != PA_INVALID_INDEX); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_put_cvolume(t, volume); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +/** Sample Cache **/ + +static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_sample_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_get_cvolume(t, &i.volume) < 0 || + pa_tagstruct_get_usec(t, &i.duration) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || + pa_tagstruct_getu32(t, &i.bytes) < 0 || + pa_tagstruct_get_boolean(t, &i.lazy) < 0 || + pa_tagstruct_gets(t, &i.filename) < 0) { + + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb && name); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SAMPLE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SAMPLE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_sample_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SAMPLE_INFO_LIST, context_get_sample_info_callback, (pa_operation_callback) cb, userdata); +} + +static pa_operation* command_kill(pa_context *c, uint32_t command, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && idx != PA_INVALID_INDEX); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, command); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + return command_kill(c, PA_COMMAND_KILL_CLIENT, idx, cb, userdata); +} + +pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + return command_kill(c, PA_COMMAND_KILL_SINK_INPUT, idx, cb, userdata); +} + +pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + return command_kill(c, PA_COMMAND_KILL_SOURCE_OUTPUT, idx, cb, userdata); +} + +static void load_module_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + uint32_t idx = -1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + } else if (pa_tagstruct_getu32(t, &idx) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *c, uint32_t _idx, void *_userdata) = (void (*)(pa_context *c, uint32_t _idx, void *_userdata)) o->callback; + cb(o->context, idx, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, void (*cb)(pa_context *c, uint32_t idx, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && name && argument); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_LOAD_MODULE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_puts(t, argument); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, load_module_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + return command_kill(c, PA_COMMAND_UNLOAD_MODULE, idx, cb, userdata); +} + +/*** Autoload stuff ***/ + +static void context_get_autoload_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_autoload_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_getu32(t, &i.type) < 0 || + pa_tagstruct_gets(t, &i.module) < 0 || + pa_tagstruct_gets(t, &i.argument) < 0) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb && name); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_AUTOLOAD_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_putu32(t, type); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb && idx != PA_INVALID_INDEX); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_AUTOLOAD_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_autoload_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, context_get_autoload_info_callback, (pa_operation_callback) cb, userdata); +} + +static void context_add_autoload_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + uint32_t idx; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + idx = PA_INVALID_INDEX; + } else if (pa_tagstruct_getu32(t, &idx) || + !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, uint32_t _idx, void *_userdata) = (void (*)(pa_context *s, uint32_t _idx, void *_userdata)) o->callback; + cb(o->context, idx, o->userdata); + } + + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && name && module && argument); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_ADD_AUTOLOAD); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_putu32(t, type); + pa_tagstruct_puts(t, module); + pa_tagstruct_puts(t, argument); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_add_autoload_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && name); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_AUTOLOAD); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_putu32(t, type); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && idx != PA_INVALID_INDEX); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_AUTOLOAD); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} diff --git a/src/polyp/polyplib-introspect.h b/src/polyp/polyplib-introspect.h new file mode 100644 index 00000000..d3489908 --- /dev/null +++ b/src/polyp/polyplib-introspect.h @@ -0,0 +1,279 @@ +#ifndef foopolyplibintrospecthfoo +#define foopolyplibintrospecthfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include +#include +#include +#include + +/** \file + * + * Routines for daemon introspection. When enumerating all entitites + * of a certain kind, use the pa_context_xxx_list() functions. The + * specified callback function is called once for each entry. The + * enumeration is finished by a call to the callback function with + * is_last=1 and i=NULL. Strings referenced in pa_xxx_info structures + * and the structures themselves point to internal memory that may not + * be modified. That memory is only valid during the call to the + * callback function. A deep copy is required if you need this data + * outside the callback functions. An error is signalled by a call to * the callback function with i=NULL and is_last=0. + * + * When using the routines that ask fo a single entry only, a callback + * with the same signature is used. However, no finishing call to the + * routine is issued. */ + +PA_C_DECL_BEGIN + +/** Stores information about sinks */ +typedef struct pa_sink_info { + const char *name; /**< Name of the sink */ + uint32_t index; /**< Index of the sink */ + const char *description; /**< Description of this sink */ + pa_sample_spec sample_spec; /**< Sample spec of this sink */ + pa_channel_map channel_map; /**< Channel map \since 0.9 */ + uint32_t owner_module; /**< Index of the owning module of this sink, or PA_INVALID_INDEX */ + pa_cvolume volume; /**< Volume of the sink */ + uint32_t monitor_source; /**< Index of the monitor source connected to this sink */ + const char *monitor_source_name; /**< The name of the monitor source */ + pa_usec_t latency; /**< Length of filled playback buffer of this sink */ + const char *driver; /**< Driver name. \since 0.9 */ +} pa_sink_info; + +/** Get information about a sink by its name */ +pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata); + +/** Get information about a sink by its index */ +pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t id, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata); + +/** Get the complete sink list */ +pa_operation* pa_context_get_sink_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata); + +/** Stores information about sources */ +typedef struct pa_source_info { + const char *name ; /**< Name of the source */ + uint32_t index; /**< Index of the source */ + const char *description; /**< Description of this source */ + pa_sample_spec sample_spec; /**< Sample spec of this source */ + pa_channel_map channel_map; /**< Channel map \since 0.9 */ + uint32_t owner_module; /**< Owning module index, or PA_INVALID_INDEX */ + uint32_t monitor_of_sink; /**< If this is a monitor source the index of the owning sink, otherwise PA_INVALID_INDEX */ + const char *monitor_of_sink_name; /**< Name of the owning sink, or PA_INVALID_INDEX */ + pa_usec_t latency; /**< Length of filled record buffer of this source. \since 0.5 */ + const char *driver; /**< Driver name \since 0.9 */ +} pa_source_info; + +/** Get information about a source by its name */ +pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata); + +/** Get information about a source by its index */ +pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t id, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata); + +/** Get the complete source list */ +pa_operation* pa_context_get_source_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata); + +/** Server information */ +typedef struct pa_server_info { + const char *user_name; /**< User name of the daemon process */ + const char *host_name; /**< Host name the daemon is running on */ + const char *server_version; /**< Version string of the daemon */ + const char *server_name; /**< Server package name (usually "polypaudio") */ + pa_sample_spec sample_spec; /**< Default sample specification */ + const char *default_sink_name; /**< Name of default sink. \since 0.4 */ + const char *default_source_name; /**< Name of default sink. \since 0.4*/ + uint32_t cookie; /**< A random cookie for identifying this instance of polypaudio. \since 0.8 */ +} pa_server_info; + +/** Get some information about the server */ +pa_operation* pa_context_get_server_info(pa_context *c, void (*cb)(pa_context *c, const pa_server_info*i, void *userdata), void *userdata); + +/** Stores information about modules */ +typedef struct pa_module_info { + uint32_t index; /**< Index of the module */ + const char*name, /**< Name of the module */ + *argument; /**< Argument string of the module */ + uint32_t n_used; /**< Usage counter or PA_INVALID_INDEX */ + int auto_unload; /**< Non-zero if this is an autoloaded module */ +} pa_module_info; + +/** Get some information about a module by its index */ +pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata); + +/** Get the complete list of currently loaded modules */ +pa_operation* pa_context_get_module_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata); + +/** Stores information about clients */ +typedef struct pa_client_info { + uint32_t index; /**< Index of this client */ + const char *name; /**< Name of this client */ + uint32_t owner_module; /**< Index of the owning module, or PA_INVALID_INDEX */ + const char *driver; /**< Driver name \since 0.9 */ +} pa_client_info; + +/** Get information about a client by its index */ +pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata); + +/** Get the complete client list */ +pa_operation* pa_context_get_client_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata); + +/** Stores information about sink inputs */ +typedef struct pa_sink_input_info { + uint32_t index; /**< Index of the sink input */ + const char *name; /**< Name of the sink input */ + uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ + uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ + uint32_t sink; /**< Index of the connected sink */ + pa_sample_spec sample_spec; /**< The sample specification of the sink input */ + pa_channel_map channel_map; /**< Channel map */ + pa_cvolume volume; /**< The volume of this sink input */ + pa_usec_t buffer_usec; /**< Latency due to buffering in sink input, see pa_latency_info for details */ + pa_usec_t sink_usec; /**< Latency of the sink device, see pa_latency_info for details */ + const char *resample_method; /**< Thre resampling method used by this sink input. \since 0.7 */ + const char *driver; /**< Driver name \since 0.9 */ +} pa_sink_input_info; + +/** Get some information about a sink input by its index */ +pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata); + +/** Get the complete sink input list */ +pa_operation* pa_context_get_sink_input_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata); + +/** Stores information about source outputs */ +typedef struct pa_source_output_info { + uint32_t index; /**< Index of the sink input */ + const char *name; /**< Name of the sink input */ + uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ + uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ + uint32_t source; /**< Index of the connected source */ + pa_sample_spec sample_spec; /**< The sample specification of the source output */ + pa_channel_map channel_map; /**< Channel map */ + pa_usec_t buffer_usec; /**< Latency due to buffering in the source output, see pa_latency_info for details. \since 0.5 */ + pa_usec_t source_usec; /**< Latency of the source device, see pa_latency_info for details. \since 0.5 */ + const char *resample_method; /**< Thre resampling method used by this source output. \since 0.7 */ + const char *driver; /**< Driver name \since 0.9 */ +} pa_source_output_info; + +/** Get information about a source output by its index */ +pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata); + +/** Get the complete list of source outputs */ +pa_operation* pa_context_get_source_output_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata); + +/** Set the volume of a sink device specified by its index */ +pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +/** Set the volume of a sink device specified by its name */ +pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +/** Set the volume of a sink input stream */ +pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +/** Memory block statistics */ +typedef struct pa_stat_info { + uint32_t memblock_total; /**< Currently allocated memory blocks */ + uint32_t memblock_total_size; /**< Currentl total size of allocated memory blocks */ + uint32_t memblock_allocated; /**< Allocated memory blocks during the whole lifetime of the daemon */ + uint32_t memblock_allocated_size; /**< Total size of all memory blocks allocated during the whole lifetime of the daemon */ + uint32_t scache_size; /**< Total size of all sample cache entries. \since 0.4 */ +} pa_stat_info; + +/** Get daemon memory block statistics */ +pa_operation* pa_context_stat(pa_context *c, void (*cb)(pa_context *c, const pa_stat_info *i, void *userdata), void *userdata); + +/** Stores information about sample cache entries */ +typedef struct pa_sample_info { + uint32_t index; /**< Index of this entry */ + const char *name; /**< Name of this entry */ + pa_cvolume volume; /**< Default volume of this entry */ + pa_sample_spec sample_spec; /**< Sample specification of the sample */ + pa_channel_map channel_map; /**< The channel map */ + pa_usec_t duration; /**< Duration of this entry */ + uint32_t bytes; /**< Length of this sample in bytes. \since 0.4 */ + int lazy; /**< Non-zero when this is a lazy cache entry. \since 0.5 */ + const char *filename; /**< In case this is a lazy cache entry, the filename for the sound file to be loaded on demand. \since 0.5 */ +} pa_sample_info; + +/** Get information about a sample by its name */ +pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata); + +/** Get information about a sample by its index */ +pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata); + +/** Get the complete list of samples stored in the daemon. */ +pa_operation* pa_context_get_sample_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata); + +/** Kill a client. \since 0.5 */ +pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +/** Kill a sink input. \since 0.5 */ +pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +/** Kill a source output. \since 0.5 */ +pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +/** Load a module. \since 0.5 */ +pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, void (*cb)(pa_context *c, uint32_t idx, void *userdata), void *userdata); + +/** Unload a module. \since 0.5 */ +pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +/** Type of an autoload entry. \since 0.5 */ +typedef enum pa_autoload_type { + PA_AUTOLOAD_SINK = 0, + PA_AUTOLOAD_SOURCE = 1 +} pa_autoload_type_t; + +/** Stores information about autoload entries. \since 0.5 */ +typedef struct pa_autoload_info { + uint32_t index; /**< Index of this autoload entry */ + const char *name; /**< Name of the sink or source */ + pa_autoload_type_t type; /**< Type of the autoload entry */ + const char *module; /**< Module name to load */ + const char *argument; /**< Argument string for module */ +} pa_autoload_info; + +/** Get info about a specific autoload entry. \since 0.6 */ +pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); + +/** Get info about a specific autoload entry. \since 0.6 */ +pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); + +/** Get the complete list of autoload entries. \since 0.5 */ +pa_operation* pa_context_get_autoload_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); + +/** Add a new autoload entry. \since 0.5 */ +pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, void (*cb)(pa_context *c, int idx, void *userdata), void* userdata); + +/** Remove an autoload entry. \since 0.6 */ +pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata); + +/** Remove an autoload entry. \since 0.6 */ +pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void* userdata); + + +PA_C_DECL_END + +#endif diff --git a/src/polyp/polyplib-operation.c b/src/polyp/polyplib-operation.c new file mode 100644 index 00000000..ea336c17 --- /dev/null +++ b/src/polyp/polyplib-operation.c @@ -0,0 +1,103 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include "polyplib-internal.h" +#include "polyplib-operation.h" + +pa_operation *pa_operation_new(pa_context *c, pa_stream *s) { + pa_operation *o; + assert(c); + + o = pa_xmalloc(sizeof(pa_operation)); + o->ref = 1; + o->context = pa_context_ref(c); + o->stream = s ? pa_stream_ref(s) : NULL; + + o->state = PA_OPERATION_RUNNING; + o->userdata = NULL; + o->callback = NULL; + + PA_LLIST_PREPEND(pa_operation, o->context->operations, o); + return pa_operation_ref(o); +} + +pa_operation *pa_operation_ref(pa_operation *o) { + assert(o && o->ref >= 1); + o->ref++; + return o; +} + +void pa_operation_unref(pa_operation *o) { + assert(o && o->ref >= 1); + + if ((--(o->ref)) == 0) { + assert(!o->context); + assert(!o->stream); + free(o); + } +} + +static void operation_set_state(pa_operation *o, pa_operation_state_t st) { + assert(o && o->ref >= 1); + + if (st == o->state) + return; + + if (!o->context) + return; + + o->state = st; + + if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) { + PA_LLIST_REMOVE(pa_operation, o->context->operations, o); + pa_context_unref(o->context); + if (o->stream) + pa_stream_unref(o->stream); + o->context = NULL; + o->stream = NULL; + o->callback = NULL; + o->userdata = NULL; + + pa_operation_unref(o); + } +} + +void pa_operation_cancel(pa_operation *o) { + assert(o && o->ref >= 1); + operation_set_state(o, PA_OPERATION_CANCELED); +} + +void pa_operation_done(pa_operation *o) { + assert(o && o->ref >= 1); + operation_set_state(o, PA_OPERATION_DONE); +} + +pa_operation_state_t pa_operation_get_state(pa_operation *o) { + assert(o && o->ref >= 1); + return o->state; +} diff --git a/src/polyp/polyplib-operation.h b/src/polyp/polyplib-operation.h new file mode 100644 index 00000000..cac03e30 --- /dev/null +++ b/src/polyp/polyplib-operation.h @@ -0,0 +1,51 @@ +#ifndef foopolypliboperationhfoo +#define foopolypliboperationhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/** \file + * Asynchronous operations */ + +PA_C_DECL_BEGIN + +/** \pa_operation + * An asynchronous operation object */ +typedef struct pa_operation pa_operation; + +/** Increase the reference count by one */ +pa_operation *pa_operation_ref(pa_operation *o); + +/** Decrease the reference count by one */ +void pa_operation_unref(pa_operation *o); + +/** Cancel the operation. Beware! This will not necessarily cancel the execution of the operation on the server side. */ +void pa_operation_cancel(pa_operation *o); + +/** Return the current status of the operation */ +pa_operation_state_t pa_operation_get_state(pa_operation *o); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/polyplib-scache.c b/src/polyp/polyplib-scache.c new file mode 100644 index 00000000..1315af97 --- /dev/null +++ b/src/polyp/polyplib-scache.c @@ -0,0 +1,127 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "polyplib-scache.h" +#include "polyplib-internal.h" +#include + +void pa_stream_connect_upload(pa_stream *s, size_t length) { + pa_tagstruct *t; + uint32_t tag; + + assert(s && length); + + pa_stream_ref(s); + + s->state = PA_STREAM_CREATING; + s->direction = PA_STREAM_UPLOAD; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_puts(t, s->name); + pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_putu32(t, length); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s); + + pa_stream_unref(s); +} + +void pa_stream_finish_upload(pa_stream *s) { + pa_tagstruct *t; + uint32_t tag; + assert(s); + + if (!s->channel_valid || !s->context->state == PA_CONTEXT_READY) + return; + + pa_stream_ref(s); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s); + + pa_stream_unref(s); +} + +pa_operation * pa_context_play_sample(pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && name && *name && (!dev || *dev)); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + if (!dev) + dev = c->conf->default_sink; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_puts(t, dev); + pa_tagstruct_putu32(t, volume); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_remove_sample(pa_context *c, const char *name, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && name); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + diff --git a/src/polyp/polyplib-scache.h b/src/polyp/polyplib-scache.h new file mode 100644 index 00000000..89d27597 --- /dev/null +++ b/src/polyp/polyplib-scache.h @@ -0,0 +1,50 @@ +#ifndef foopolyplibscachehfoo +#define foopolyplibscachehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include +#include + +/** \file + * All sample cache related routines */ + +PA_C_DECL_BEGIN + +/** Make this stream a sample upload stream */ +void pa_stream_connect_upload(pa_stream *s, size_t length); + +/** Finish the sample upload, the stream name will become the sample name. You cancel a sample upload by issuing pa_stream_disconnect() */ +void pa_stream_finish_upload(pa_stream *s); + +/** Play a sample from the sample cache to the specified device. If the latter is NULL use the default sink. Returns an operation object */ +pa_operation* pa_context_play_sample(pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +/** Remove a sample from the sample cache. Returns an operation object which may be used to cancel the operation while it is running */ +pa_operation* pa_context_remove_sample(pa_context *c, const char *name, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/polyplib-simple.c b/src/polyp/polyplib-simple.c new file mode 100644 index 00000000..7436f007 --- /dev/null +++ b/src/polyp/polyplib-simple.c @@ -0,0 +1,393 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "polyplib-simple.h" +#include "polyplib.h" +#include "mainloop.h" +#include +#include +#include + +struct pa_simple { + pa_mainloop *mainloop; + pa_context *context; + pa_stream *stream; + pa_stream_direction_t direction; + + int dead; + + void *read_data; + size_t read_index, read_length; + pa_usec_t latency; +}; + +static void read_callback(pa_stream *s, const void*data, size_t length, void *userdata); + +static int check_error(pa_simple *p, int *rerror) { + pa_context_state_t cst; + pa_stream_state_t sst; + assert(p); + + if ((cst = pa_context_get_state(p->context)) == PA_CONTEXT_FAILED) + goto fail; + + assert(cst != PA_CONTEXT_TERMINATED); + + if (p->stream) { + if ((sst = pa_stream_get_state(p->stream)) == PA_STREAM_FAILED) + goto fail; + + assert(sst != PA_STREAM_TERMINATED); + } + + return 0; + +fail: + if (rerror) + *rerror = pa_context_errno(p->context); + + p->dead = 1; + + return -1; +} + +static int iterate(pa_simple *p, int block, int *rerror) { + assert(p && p->context && p->mainloop); + + if (check_error(p, rerror) < 0) + return -1; + + if (!block && !pa_context_is_pending(p->context)) + return 0; + + do { + if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) { + if (rerror) + *rerror = PA_ERROR_INTERNAL; + return -1; + } + + if (check_error(p, rerror) < 0) + return -1; + + } while (pa_context_is_pending(p->context)); + + + while (pa_mainloop_deferred_pending(p->mainloop)) { + + if (pa_mainloop_iterate(p->mainloop, 0, NULL) < 0) { + if (rerror) + *rerror = PA_ERROR_INTERNAL; + return -1; + } + + if (check_error(p, rerror) < 0) + return -1; + } + + return 0; +} + +pa_simple* pa_simple_new( + const char *server, + const char *name, + pa_stream_direction_t dir, + const char *dev, + const char *stream_name, + const pa_sample_spec *ss, + const pa_buffer_attr *attr, + int *rerror) { + + pa_simple *p; + int error = PA_ERROR_INTERNAL; + assert(ss && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); + + p = pa_xmalloc(sizeof(pa_simple)); + p->context = NULL; + p->stream = NULL; + p->mainloop = pa_mainloop_new(); + assert(p->mainloop); + p->dead = 0; + p->direction = dir; + p->read_data = NULL; + p->read_index = p->read_length = 0; + p->latency = 0; + + if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name))) + goto fail; + + pa_context_connect(p->context, server, 1, NULL); + + /* Wait until the context is ready */ + while (pa_context_get_state(p->context) != PA_CONTEXT_READY) { + if (iterate(p, 1, &error) < 0) + goto fail; + } + + if (!(p->stream = pa_stream_new(p->context, stream_name, ss, NULL))) + goto fail; + + if (dir == PA_STREAM_PLAYBACK) + pa_stream_connect_playback(p->stream, dev, attr, 0, NULL); + else + pa_stream_connect_record(p->stream, dev, attr, 0); + + /* Wait until the stream is ready */ + while (pa_stream_get_state(p->stream) != PA_STREAM_READY) { + if (iterate(p, 1, &error) < 0) + goto fail; + } + + pa_stream_set_read_callback(p->stream, read_callback, p); + + return p; + +fail: + if (rerror) + *rerror = error; + pa_simple_free(p); + return NULL; +} + +void pa_simple_free(pa_simple *s) { + assert(s); + + pa_xfree(s->read_data); + + if (s->stream) + pa_stream_unref(s->stream); + + if (s->context) + pa_context_unref(s->context); + + if (s->mainloop) + pa_mainloop_free(s->mainloop); + + pa_xfree(s); +} + +int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { + assert(p && data && p->direction == PA_STREAM_PLAYBACK); + + if (p->dead) { + if (rerror) + *rerror = pa_context_errno(p->context); + + return -1; + } + + while (length > 0) { + size_t l; + + while (!(l = pa_stream_writable_size(p->stream))) + if (iterate(p, 1, rerror) < 0) + return -1; + + if (l > length) + l = length; + + pa_stream_write(p->stream, data, l, NULL, 0); + data = (const uint8_t*) data + l; + length -= l; + } + + /* Make sure that no data is pending for write */ + if (iterate(p, 0, rerror) < 0) + return -1; + + return 0; +} + +static void read_callback(pa_stream *s, const void*data, size_t length, void *userdata) { + pa_simple *p = userdata; + assert(s && data && length && p); + + if (p->read_data) { + pa_log(__FILE__": Buffer overflow, dropping incoming memory blocks.\n"); + pa_xfree(p->read_data); + } + + p->read_data = pa_xmemdup(data, p->read_length = length); + p->read_index = 0; +} + +int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { + assert(p && data && p->direction == PA_STREAM_RECORD); + + if (p->dead) { + if (rerror) + *rerror = pa_context_errno(p->context); + + return -1; + } + + while (length > 0) { + if (p->read_data) { + size_t l = length; + + if (p->read_length <= l) + l = p->read_length; + + memcpy(data, (uint8_t*) p->read_data+p->read_index, l); + + data = (uint8_t*) data + l; + length -= l; + + p->read_index += l; + p->read_length -= l; + + if (!p->read_length) { + pa_xfree(p->read_data); + p->read_data = NULL; + p->read_index = 0; + } + + if (!length) + return 0; + + assert(!p->read_data); + } + + if (iterate(p, 1, rerror) < 0) + return -1; + } + + return 0; +} + +static void drain_or_flush_complete(pa_stream *s, int success, void *userdata) { + pa_simple *p = userdata; + assert(s && p); + if (!success) + p->dead = 1; +} + +int pa_simple_drain(pa_simple *p, int *rerror) { + pa_operation *o; + assert(p && p->direction == PA_STREAM_PLAYBACK); + + if (p->dead) { + if (rerror) + *rerror = pa_context_errno(p->context); + + return -1; + } + + o = pa_stream_drain(p->stream, drain_or_flush_complete, p); + + while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { + if (iterate(p, 1, rerror) < 0) { + pa_operation_cancel(o); + pa_operation_unref(o); + return -1; + } + } + + pa_operation_unref(o); + + if (p->dead && rerror) + *rerror = pa_context_errno(p->context); + + return p->dead ? -1 : 0; +} + +static void latency_complete(pa_stream *s, const pa_latency_info *l, void *userdata) { + pa_simple *p = userdata; + assert(s && p); + + if (!l) + p->dead = 1; + else { + int negative = 0; + p->latency = pa_stream_get_latency(s, l, &negative); + if (negative) + p->latency = 0; + } +} + +pa_usec_t pa_simple_get_playback_latency(pa_simple *p, int *rerror) { + pa_operation *o; + assert(p && p->direction == PA_STREAM_PLAYBACK); + + if (p->dead) { + if (rerror) + *rerror = pa_context_errno(p->context); + + return (pa_usec_t) -1; + } + + p->latency = 0; + o = pa_stream_get_latency_info(p->stream, latency_complete, p); + + while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { + + if (iterate(p, 1, rerror) < 0) { + pa_operation_cancel(o); + pa_operation_unref(o); + return -1; + } + } + + pa_operation_unref(o); + + if (p->dead && rerror) + *rerror = pa_context_errno(p->context); + + return p->dead ? (pa_usec_t) -1 : p->latency; +} + +int pa_simple_flush(pa_simple *p, int *rerror) { + pa_operation *o; + assert(p && p->direction == PA_STREAM_PLAYBACK); + + if (p->dead) { + if (rerror) + *rerror = pa_context_errno(p->context); + + return -1; + } + + o = pa_stream_flush(p->stream, drain_or_flush_complete, p); + + while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { + if (iterate(p, 1, rerror) < 0) { + pa_operation_cancel(o); + pa_operation_unref(o); + return -1; + } + } + + pa_operation_unref(o); + + if (p->dead && rerror) + *rerror = pa_context_errno(p->context); + + return p->dead ? -1 : 0; +} diff --git a/src/polyp/polyplib-simple.h b/src/polyp/polyplib-simple.h new file mode 100644 index 00000000..b01f30d5 --- /dev/null +++ b/src/polyp/polyplib-simple.h @@ -0,0 +1,80 @@ +#ifndef foopolyplibsimplehfoo +#define foopolyplibsimplehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "sample.h" +#include "polyplib-def.h" +#include + +/** \file + * A simple but limited synchronous playback and recording + * API. This is synchronouse, simplified wrapper around the standard + * asynchronous API. */ + +/** \example pacat-simple.c + * A simple playback tool using the simple API */ + +/** \example parec-simple.c + * A simple recording tool using the simple API */ + +PA_C_DECL_BEGIN + +/** \pa_simple + * An opaque simple connection object */ +typedef struct pa_simple pa_simple; + +/** Create a new connection to the server */ +pa_simple* pa_simple_new( + const char *server, /**< Server name, or NULL for default */ + const char *name, /**< A descriptive name for this client (application name, ...) */ + pa_stream_direction_t dir, /**< Open this stream for recording or playback? */ + const char *dev, /**< Sink (resp. source) name, or NULL for default */ + const char *stream_name, /**< A descriptive name for this client (application name, song title, ...) */ + const pa_sample_spec *ss, /**< The sample type to use */ + const pa_buffer_attr *attr, /**< Buffering attributes, or NULL for default */ + int *error /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */ + ); + +/** Close and free the connection to the server. The connection objects becomes invalid when this is called. */ +void pa_simple_free(pa_simple *s); + +/** Write some data to the server */ +int pa_simple_write(pa_simple *s, const void*data, size_t length, int *error); + +/** Wait until all data already written is played by the daemon */ +int pa_simple_drain(pa_simple *s, int *error); + +/** Read some data from the server */ +int pa_simple_read(pa_simple *s, void*data, size_t length, int *error); + +/** Return the playback latency. \since 0.5 */ +pa_usec_t pa_simple_get_playback_latency(pa_simple *s, int *error); + +/** Flush the playback buffer. \since 0.5 */ +int pa_simple_flush(pa_simple *s, int *error); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/polyplib-stream.c b/src/polyp/polyplib-stream.c new file mode 100644 index 00000000..63c9245b --- /dev/null +++ b/src/polyp/polyplib-stream.c @@ -0,0 +1,807 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "polyplib-internal.h" +#include +#include +#include +#include + +#define LATENCY_IPOL_INTERVAL_USEC (10000L) + +pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map) { + pa_stream *s; + assert(c); + assert(ss); + + if (!pa_sample_spec_valid(ss)) + return NULL; + + if (map && !pa_channel_map_valid(map)) + return NULL; + + s = pa_xnew(pa_stream, 1); + s->ref = 1; + s->context = c; + s->mainloop = c->mainloop; + + s->read_callback = NULL; + s->read_userdata = NULL; + s->write_callback = NULL; + s->write_userdata = NULL; + s->state_callback = NULL; + s->state_userdata = NULL; + + s->direction = PA_STREAM_NODIRECTION; + s->name = pa_xstrdup(name); + s->sample_spec = *ss; + + if (map) + s->channel_map = *map; + else + pa_channel_map_init_auto(&s->channel_map, ss->channels); + + s->channel = 0; + s->channel_valid = 0; + s->device_index = PA_INVALID_INDEX; + s->requested_bytes = 0; + s->state = PA_STREAM_DISCONNECTED; + memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); + + s->mcalign = pa_mcalign_new(pa_frame_size(ss), c->memblock_stat); + + s->counter = 0; + s->previous_time = 0; + s->previous_ipol_time = 0; + + s->corked = 0; + s->interpolate = 0; + + s->ipol_usec = 0; + memset(&s->ipol_timestamp, 0, sizeof(s->ipol_timestamp)); + s->ipol_event = NULL; + s->ipol_requested = 0; + + PA_LLIST_PREPEND(pa_stream, c->streams, s); + + return pa_stream_ref(s); +} + +static void stream_free(pa_stream *s) { + assert(s); + + if (s->ipol_event) { + assert(s->mainloop); + s->mainloop->time_free(s->ipol_event); + } + + pa_mcalign_free(s->mcalign); + + pa_xfree(s->name); + pa_xfree(s); +} + +void pa_stream_unref(pa_stream *s) { + assert(s && s->ref >= 1); + + if (--(s->ref) == 0) + stream_free(s); +} + +pa_stream* pa_stream_ref(pa_stream *s) { + assert(s && s->ref >= 1); + s->ref++; + return s; +} + +pa_stream_state_t pa_stream_get_state(pa_stream *s) { + assert(s && s->ref >= 1); + return s->state; +} + +pa_context* pa_stream_get_context(pa_stream *s) { + assert(s && s->ref >= 1); + return s->context; +} + +uint32_t pa_stream_get_index(pa_stream *s) { + assert(s && s->ref >= 1); + return s->device_index; +} + +void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { + assert(s && s->ref >= 1); + + if (s->state == st) + return; + + pa_stream_ref(s); + + s->state = st; + + if ((st == PA_STREAM_FAILED || st == PA_STREAM_TERMINATED) && s->context) { + if (s->channel_valid) + pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); + + PA_LLIST_REMOVE(pa_stream, s->context->streams, s); + pa_stream_unref(s); + } + + if (s->state_callback) + s->state_callback(s, s->state_userdata); + + pa_stream_unref(s); +} + +void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_context *c = userdata; + pa_stream *s; + uint32_t channel; + assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); + + pa_context_ref(c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(c, PA_ERROR_PROTOCOL); + goto finish; + } + + if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) + goto finish; + + c->error = PA_ERROR_KILLED; + pa_stream_set_state(s, PA_STREAM_FAILED); + +finish: + pa_context_unref(c); +} + +void pa_command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_stream *s; + pa_context *c = userdata; + uint32_t bytes, channel; + assert(pd && command == PA_COMMAND_REQUEST && t && c); + + pa_context_ref(c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + pa_tagstruct_getu32(t, &bytes) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(c, PA_ERROR_PROTOCOL); + goto finish; + } + + if (!(s = pa_dynarray_get(c->playback_streams, channel))) + goto finish; + + if (s->state != PA_STREAM_READY) + goto finish; + + pa_stream_ref(s); + + s->requested_bytes += bytes; + + if (s->requested_bytes && s->write_callback) + s->write_callback(s, s->requested_bytes, s->write_userdata); + + pa_stream_unref(s); + +finish: + pa_context_unref(c); +} + +static void ipol_callback(pa_mainloop_api *m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + struct timeval tv2; + pa_stream *s = userdata; + + pa_stream_ref(s); + +/* pa_log("requesting new ipol data\n"); */ + + if (s->state == PA_STREAM_READY && !s->ipol_requested) { + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + s->ipol_requested = 1; + } + + pa_gettimeofday(&tv2); + pa_timeval_add(&tv2, LATENCY_IPOL_INTERVAL_USEC); + + m->time_restart(e, &tv2); + + pa_stream_unref(s); +} + + +void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_stream *s = userdata; + assert(pd && s && s->state == PA_STREAM_CREATING); + + pa_stream_ref(s); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(s->context, command, t) < 0) + goto finish; + + pa_stream_set_state(s, PA_STREAM_FAILED); + goto finish; + } + + if (pa_tagstruct_getu32(t, &s->channel) < 0 || + ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || + ((s->direction != PA_STREAM_RECORD) && pa_tagstruct_getu32(t, &s->requested_bytes) < 0) || + !pa_tagstruct_eof(t)) { + pa_context_fail(s->context, PA_ERROR_PROTOCOL); + goto finish; + } + + s->channel_valid = 1; + pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); + pa_stream_set_state(s, PA_STREAM_READY); + + if (s->interpolate) { + struct timeval tv; + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + + pa_gettimeofday(&tv); + tv.tv_usec += LATENCY_IPOL_INTERVAL_USEC; /* every 100 ms */ + + assert(!s->ipol_event); + s->ipol_event = s->mainloop->time_new(s->mainloop, &tv, &ipol_callback, s); + } + + if (s->requested_bytes && s->ref > 1 && s->write_callback) + s->write_callback(s, s->requested_bytes, s->write_userdata); + +finish: + pa_stream_unref(s); +} + +static void create_stream(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags, const pa_cvolume *volume) { + pa_tagstruct *t; + uint32_t tag; + assert(s && s->ref >= 1 && s->state == PA_STREAM_DISCONNECTED); + + pa_stream_ref(s); + + s->interpolate = !!(flags & PA_STREAM_INTERPOLATE_LATENCY); + pa_stream_trash_ipol(s); + + if (attr) + s->buffer_attr = *attr; + else { + /* half a second */ + s->buffer_attr.tlength = pa_bytes_per_second(&s->sample_spec)/2; + s->buffer_attr.maxlength = (s->buffer_attr.tlength*3)/2; + s->buffer_attr.minreq = s->buffer_attr.tlength/100; + s->buffer_attr.prebuf = s->buffer_attr.tlength - s->buffer_attr.minreq; + s->buffer_attr.fragsize = s->buffer_attr.tlength/100; + } + + pa_stream_set_state(s, PA_STREAM_CREATING); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + if (!dev) { + if (s->direction == PA_STREAM_PLAYBACK) + dev = s->context->conf->default_sink; + else + dev = s->context->conf->default_source; + } + + pa_tagstruct_put(t, + PA_TAG_U32, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM, + PA_TAG_U32, tag = s->context->ctag++, + PA_TAG_STRING, s->name, + PA_TAG_SAMPLE_SPEC, &s->sample_spec, + PA_TAG_CHANNEL_MAP, &s->channel_map, + PA_TAG_U32, PA_INVALID_INDEX, + PA_TAG_STRING, dev, + PA_TAG_U32, s->buffer_attr.maxlength, + PA_TAG_BOOLEAN, !!(flags & PA_STREAM_START_CORKED), + PA_TAG_INVALID); + + if (s->direction == PA_STREAM_PLAYBACK) { + pa_cvolume cv; + pa_tagstruct_put(t, + PA_TAG_U32, s->buffer_attr.tlength, + PA_TAG_U32, s->buffer_attr.prebuf, + PA_TAG_U32, s->buffer_attr.minreq, + PA_TAG_INVALID); + + if (!volume) { + pa_cvolume_reset(&cv, s->sample_spec.channels); + volume = &cv; + } + + pa_tagstruct_put_cvolume(t, volume); + } else + pa_tagstruct_putu32(t, s->buffer_attr.fragsize); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s); + + pa_stream_unref(s); +} + +void pa_stream_connect_playback(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags, pa_cvolume *volume) { + assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); + s->direction = PA_STREAM_PLAYBACK; + create_stream(s, dev, attr, flags, volume); +} + +void pa_stream_connect_record(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags) { + assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); + s->direction = PA_STREAM_RECORD; + create_stream(s, dev, attr, flags, 0); +} + +void pa_stream_write(pa_stream *s, const void *data, size_t length, void (*free_cb)(void *p), size_t delta) { + pa_memchunk chunk; + assert(s && s->context && data && length && s->state == PA_STREAM_READY && s->ref >= 1); + + if (free_cb) { + chunk.memblock = pa_memblock_new_user((void*) data, length, free_cb, 1, s->context->memblock_stat); + assert(chunk.memblock && chunk.memblock->data); + } else { + chunk.memblock = pa_memblock_new(length, s->context->memblock_stat); + assert(chunk.memblock && chunk.memblock->data); + memcpy(chunk.memblock->data, data, length); + } + chunk.index = 0; + chunk.length = length; + + pa_pstream_send_memblock(s->context->pstream, s->channel, delta, &chunk); + pa_memblock_unref(chunk.memblock); + + if (length < s->requested_bytes) + s->requested_bytes -= length; + else + s->requested_bytes = 0; + + s->counter += length; +} + +size_t pa_stream_writable_size(pa_stream *s) { + assert(s && s->ref >= 1); + return s->state == PA_STREAM_READY ? s->requested_bytes : 0; +} + +pa_operation * pa_stream_drain(pa_stream *s, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); + + o = pa_operation_new(s->context, s); + assert(o); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +static void stream_get_latency_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + pa_latency_info i, *p = NULL; + struct timeval local, remote, now; + assert(pd && o && o->stream && o->context); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + } else if (pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || + pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || + pa_tagstruct_get_usec(t, &i.source_usec) < 0 || + pa_tagstruct_get_boolean(t, &i.playing) < 0 || + pa_tagstruct_getu32(t, &i.queue_length) < 0 || + pa_tagstruct_get_timeval(t, &local) < 0 || + pa_tagstruct_get_timeval(t, &remote) < 0 || + pa_tagstruct_getu64(t, &i.counter) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } else { + pa_gettimeofday(&now); + + if (pa_timeval_cmp(&local, &remote) <= 0 && pa_timeval_cmp(&remote, &now) <= 0) { + /* local and remote seem to have synchronized clocks */ + + if (o->stream->direction == PA_STREAM_PLAYBACK) + i.transport_usec = pa_timeval_diff(&remote, &local); + else + i.transport_usec = pa_timeval_diff(&now, &remote); + + i.synchronized_clocks = 1; + i.timestamp = remote; + } else { + /* clocks are not synchronized, let's estimate latency then */ + i.transport_usec = pa_timeval_diff(&now, &local)/2; + i.synchronized_clocks = 0; + i.timestamp = local; + pa_timeval_add(&i.timestamp, i.transport_usec); + } + + if (o->stream->interpolate) { +/* pa_log("new interpol data\n"); */ + o->stream->ipol_timestamp = i.timestamp; + o->stream->ipol_usec = pa_stream_get_time(o->stream, &i); + o->stream->ipol_requested = 0; + } + + p = &i; + } + + if (o->callback) { + void (*cb)(pa_stream *s, const pa_latency_info *_i, void *_userdata) = (void (*)(pa_stream *s, const pa_latency_info *_i, void *_userdata)) o->callback; + cb(o->stream, p, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_stream_get_latency_info(pa_stream *s, void (*cb)(pa_stream *p, const pa_latency_info*i, void *userdata), void *userdata) { + uint32_t tag; + pa_operation *o; + pa_tagstruct *t; + struct timeval now; + assert(s && s->direction != PA_STREAM_UPLOAD); + + o = pa_operation_new(s->context, s); + assert(o); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_GET_PLAYBACK_LATENCY : PA_COMMAND_GET_RECORD_LATENCY); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + + pa_gettimeofday(&now); + pa_tagstruct_put_timeval(t, &now); + pa_tagstruct_putu64(t, s->counter); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_info_callback, o); + + return pa_operation_ref(o); +} + +void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_stream *s = userdata; + assert(pd && s && s->ref >= 1); + + pa_stream_ref(s); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(s->context, command, t) < 0) + goto finish; + + pa_stream_set_state(s, PA_STREAM_FAILED); + goto finish; + } else if (!pa_tagstruct_eof(t)) { + pa_context_fail(s->context, PA_ERROR_PROTOCOL); + goto finish; + } + + pa_stream_set_state(s, PA_STREAM_TERMINATED); + +finish: + pa_stream_unref(s); +} + +void pa_stream_disconnect(pa_stream *s) { + pa_tagstruct *t; + uint32_t tag; + assert(s && s->ref >= 1); + + if (!s->channel_valid || !s->context->state == PA_CONTEXT_READY) + return; + + pa_stream_ref(s); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : + (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s); + + pa_stream_unref(s); +} + +void pa_stream_set_read_callback(pa_stream *s, void (*cb)(pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { + assert(s && s->ref >= 1); + s->read_callback = cb; + s->read_userdata = userdata; +} + +void pa_stream_set_write_callback(pa_stream *s, void (*cb)(pa_stream *p, size_t length, void *userdata), void *userdata) { + assert(s && s->ref >= 1); + s->write_callback = cb; + s->write_userdata = userdata; +} + +void pa_stream_set_state_callback(pa_stream *s, void (*cb)(pa_stream *s, void *userdata), void *userdata) { + assert(s && s->ref >= 1); + s->state_callback = cb; + s->state_userdata = userdata; +} + +void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int success = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + success = 0; + } else if (!pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_stream *s, int _success, void *_userdata) = (void (*)(pa_stream *s, int _success, void *_userdata)) o->callback; + cb(o->stream, success, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_stream_cork(pa_stream *s, int b, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); + + if (s->interpolate) { + if (!s->corked && b) + /* Pausing */ + s->ipol_usec = pa_stream_get_interpolated_time(s); + else if (s->corked && !b) + /* Unpausing */ + pa_gettimeofday(&s->ipol_timestamp); + } + + s->corked = b; + + o = pa_operation_new(s->context, s); + assert(o); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CORK_PLAYBACK_STREAM : PA_COMMAND_CORK_RECORD_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_tagstruct_put_boolean(t, !!b); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); + + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + + return pa_operation_ref(o); +} + +static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); + + o = pa_operation_new(s->context, s); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, command); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_stream_flush(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { + pa_operation *o; + o = stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata); + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + return o; +} + +pa_operation* pa_stream_prebuf(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { + pa_operation *o; + o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata); + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + return o; +} + +pa_operation* pa_stream_trigger(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { + pa_operation *o; + o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata); + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + return o; +} + +pa_operation* pa_stream_set_name(pa_stream *s, const char *name, void(*cb)(pa_stream*c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(s && s->ref >= 1 && s->state == PA_STREAM_READY && name && s->direction != PA_STREAM_UPLOAD); + + o = pa_operation_new(s->context, s); + assert(o); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, s->direction == PA_STREAM_RECORD ? PA_COMMAND_SET_RECORD_STREAM_NAME : PA_COMMAND_SET_PLAYBACK_STREAM_NAME); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +uint64_t pa_stream_get_counter(pa_stream *s) { + assert(s); + return s->counter; +} + +pa_usec_t pa_stream_get_time(pa_stream *s, const pa_latency_info *i) { + pa_usec_t usec; + assert(s); + + usec = pa_bytes_to_usec(i->counter, &s->sample_spec); + + if (i) { + if (s->direction == PA_STREAM_PLAYBACK) { + pa_usec_t latency = i->transport_usec + i->buffer_usec + i->sink_usec; + if (usec < latency) + usec = 0; + else + usec -= latency; + + } else if (s->direction == PA_STREAM_RECORD) { + usec += i->source_usec + i->buffer_usec + i->transport_usec; + + if (usec > i->sink_usec) + usec -= i->sink_usec; + else + usec = 0; + } + } + + if (usec < s->previous_time) + usec = s->previous_time; + + s->previous_time = usec; + + return usec; +} + +static pa_usec_t time_counter_diff(pa_stream *s, pa_usec_t t, pa_usec_t c, int *negative) { + assert(s); + + if (negative) + *negative = 0; + + if (c < t) { + if (s->direction == PA_STREAM_RECORD) { + if (negative) + *negative = 1; + + return t-c; + } else + return 0; + } else + return c-t; +} + +pa_usec_t pa_stream_get_latency(pa_stream *s, const pa_latency_info *i, int *negative) { + pa_usec_t t, c; + assert(s && i); + + t = pa_stream_get_time(s, i); + c = pa_bytes_to_usec(s->counter, &s->sample_spec); + + return time_counter_diff(s, t, c, negative); +} + +const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) { + assert(s); + return &s->sample_spec; +} + +void pa_stream_trash_ipol(pa_stream *s) { + assert(s); + + if (!s->interpolate) + return; + + memset(&s->ipol_timestamp, 0, sizeof(s->ipol_timestamp)); + s->ipol_usec = 0; +} + +pa_usec_t pa_stream_get_interpolated_time(pa_stream *s) { + pa_usec_t usec; + assert(s && s->interpolate); + + if (s->corked) + usec = s->ipol_usec; + else { + if (s->ipol_timestamp.tv_sec == 0) + usec = 0; + else + usec = s->ipol_usec + pa_timeval_age(&s->ipol_timestamp); + } + + if (usec < s->previous_ipol_time) + usec = s->previous_ipol_time; + + s->previous_ipol_time = usec; + + return usec; +} + +pa_usec_t pa_stream_get_interpolated_latency(pa_stream *s, int *negative) { + pa_usec_t t, c; + assert(s && s->interpolate); + + t = pa_stream_get_interpolated_time(s); + c = pa_bytes_to_usec(s->counter, &s->sample_spec); + return time_counter_diff(s, t, c, negative); +} diff --git a/src/polyp/polyplib-stream.h b/src/polyp/polyplib-stream.h new file mode 100644 index 00000000..bc828b71 --- /dev/null +++ b/src/polyp/polyplib-stream.h @@ -0,0 +1,181 @@ +#ifndef foopolyplibstreamhfoo +#define foopolyplibstreamhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include +#include +#include +#include +#include + +/** \file + * Audio streams for input, output and sample upload */ + +PA_C_DECL_BEGIN + +/** \pa_stream + * An opaque stream for playback or recording */ +typedef struct pa_stream pa_stream; + +/** Create a new, unconnected stream with the specified name and sample type */ +pa_stream* pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map); + +/** Decrease the reference counter by one */ +void pa_stream_unref(pa_stream *s); + +/** Increase the reference counter by one */ +pa_stream *pa_stream_ref(pa_stream *s); + +/** Return the current state of the stream */ +pa_stream_state_t pa_stream_get_state(pa_stream *p); + +/** Return the context this stream is attached to */ +pa_context* pa_stream_get_context(pa_stream *p); + +/** Return the device (sink input or source output) index this stream is connected to */ +uint32_t pa_stream_get_index(pa_stream *s); + +/** Connect the stream to a sink */ +void pa_stream_connect_playback( + pa_stream *s, + const char *dev, + const pa_buffer_attr *attr, + pa_stream_flags_t flags, + pa_cvolume *volume); + +/** Connect the stream to a source */ +void pa_stream_connect_record( + pa_stream *s, + const char *dev, + const pa_buffer_attr *attr, + pa_stream_flags_t flags); + +/** Disconnect a stream from a source/sink */ +void pa_stream_disconnect(pa_stream *s); + +/** Write some data to the server (for playback sinks), if free_cb is + * non-NULL this routine is called when all data has been written out + * and an internal reference to the specified data is kept, the data + * is not copied. If NULL, the data is copied into an internal + * buffer. */ +void pa_stream_write(pa_stream *p /**< The stream to use */, + const void *data /**< The data to write */, + size_t length /**< The length of the data to write */, + void (*free_cb)(void *p) /**< A cleanup routine for the data or NULL to request an internal copy */, + size_t delta /**< Drop this many + bytes in the playback + buffer before writing + this data. Use + (size_t) -1 for + clearing the whole + playback + buffer. Normally you + will specify 0 here, + i.e. append to the + playback buffer. If + the value given here + is greater than the + buffered data length + the buffer is cleared + and the data is + written to the + buffer's start. This + value is ignored on + upload streams. */); + +/** Return the amount of bytes that may be written using pa_stream_write() */ +size_t pa_stream_writable_size(pa_stream *p); + +/** Drain a playback stream */ +pa_operation* pa_stream_drain(pa_stream *s, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata); + +/** Get the playback latency of a stream */ +pa_operation* pa_stream_get_latency_info(pa_stream *p, void (*cb)(pa_stream *p, const pa_latency_info *i, void *userdata), void *userdata); + +/** Set the callback function that is called whenever the state of the stream changes */ +void pa_stream_set_state_callback(pa_stream *s, void (*cb)(pa_stream *s, void *userdata), void *userdata); + +/** Set the callback function that is called when new data may be + * written to the stream. */ +void pa_stream_set_write_callback(pa_stream *p, void (*cb)(pa_stream *p, size_t length, void *userdata), void *userdata); + +/** Set the callback function that is called when new data is available from the stream */ +void pa_stream_set_read_callback(pa_stream *p, void (*cb)(pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); + +/** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. \since 0.3 */ +pa_operation* pa_stream_cork(pa_stream *s, int b, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata); + +/** Flush the playback buffer of this stream. Most of the time you're + * better off using the parameter delta of pa_stream_write() instead of this + * function. Available on both playback and recording streams. \since 0.3 */ +pa_operation* pa_stream_flush(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata); + +/** Reenable prebuffering. Available for playback streams only. \since 0.6 */ +pa_operation* pa_stream_prebuf(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata); + +/** Request immediate start of playback on this stream. This disables + * prebuffering as specified in the pa_buffer_attr structure. Available for playback streams only. \since + * 0.3 */ +pa_operation* pa_stream_trigger(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata); + +/** Rename the stream. \since 0.5 */ +pa_operation* pa_stream_set_name(pa_stream *s, const char *name, void(*cb)(pa_stream*c, int success, void *userdata), void *userdata); + +/** Return the total number of bytes written to/read from the + * stream. This counter is not reset on pa_stream_flush(), you may do + * this yourself using pa_stream_reset_counter(). \since 0.6 */ +uint64_t pa_stream_get_counter(pa_stream *s); + +/** Return the current playback/recording time. This is based on the + * counter accessible with pa_stream_get_counter(). This function + * requires a pa_latency_info structure as argument, which should be + * acquired using pa_stream_get_latency(). \since 0.6 */ +pa_usec_t pa_stream_get_time(pa_stream *s, const pa_latency_info *i); + +/** Return the total stream latency. Thus function requires a + * pa_latency_info structure as argument, which should be aquired + * using pa_stream_get_latency(). In case the stream is a monitoring + * stream the result can be negative, i.e. the captured samples are + * not yet played. In this case *negative is set to 1. \since 0.6 */ +pa_usec_t pa_stream_get_latency(pa_stream *s, const pa_latency_info *i, int *negative); + +/** Return the interpolated playback/recording time. Requires the + * PA_STREAM_INTERPOLATE_LATENCY bit set when creating the stream. In + * contrast to pa_stream_get_latency() this function doesn't require + * a whole roundtrip for response. \since 0.6 */ +pa_usec_t pa_stream_get_interpolated_time(pa_stream *s); + +/** Return the interpolated playback/recording latency. Requires the + * PA_STREAM_INTERPOLATE_LATENCY bit set when creating the + * stream. \since 0.6 */ +pa_usec_t pa_stream_get_interpolated_latency(pa_stream *s, int *negative); + +/** Return a pointer to the streams sample specification. \since 0.6 */ +const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/polyplib-subscribe.c b/src/polyp/polyplib-subscribe.c new file mode 100644 index 00000000..13fcfb42 --- /dev/null +++ b/src/polyp/polyplib-subscribe.c @@ -0,0 +1,81 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "polyplib-subscribe.h" +#include "polyplib-internal.h" +#include +#include + +void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_context *c = userdata; + pa_subscription_event_type_t e; + uint32_t index; + assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); + + pa_context_ref(c); + + if (pa_tagstruct_getu32(t, &e) < 0 || + pa_tagstruct_getu32(t, &index) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(c, PA_ERROR_PROTOCOL); + goto finish; + } + + if (c->subscribe_callback) + c->subscribe_callback(c, e, index, c->subscribe_userdata); + +finish: + pa_context_unref(c); +} + + +pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, m); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +void pa_context_set_subscribe_callback(pa_context *c, void (*cb)(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata) { + assert(c); + c->subscribe_callback = cb; + c->subscribe_userdata = userdata; +} diff --git a/src/polyp/polyplib-subscribe.h b/src/polyp/polyplib-subscribe.h new file mode 100644 index 00000000..920c9853 --- /dev/null +++ b/src/polyp/polyplib-subscribe.h @@ -0,0 +1,47 @@ +#ifndef foopolyplibsubscribehfoo +#define foopolyplibsubscribehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include +#include + +/** \file + * Daemon introspection event subscription subsystem. Use this + * to be notified whenever the internal layout of daemon changes: + * i.e. entities such as sinks or sources are create, removed or + * modified. */ + +PA_C_DECL_BEGIN + +/** Enable event notification */ +pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +/** Set the context specific call back function that is called whenever the state of the daemon changes */ +void pa_context_set_subscribe_callback(pa_context *c, void (*cb)(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/polyplib-version.h.in b/src/polyp/polyplib-version.h.in new file mode 100644 index 00000000..89e0a0e5 --- /dev/null +++ b/src/polyp/polyplib-version.h.in @@ -0,0 +1,47 @@ +#ifndef foopolyplibversionhfoo /*-*-C-*-*/ +#define foopolyplibversionhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* WARNING: Make sure to edit the real source file polyplib-version.h.in! */ + +/** \file + * Define header version */ + +PA_C_DECL_BEGIN + +/** Return the version of the header files. Keep in mind that this is +a macro and not a function, so it is impossible to get the pointer of +it. */ +#define pa_get_headers_version() ("@PACKAGE_VERSION@") + +/** Return the version of the library the current application is linked to. */ +const char* pa_get_library_version(void); + +/** The current API version. Version 6 relates to polypaudio + * 0.6. Prior versions (i.e. Polypaudio 0.5.1 and older) have + * PA_API_VERSION undefined. */ +#define PA_API_VERSION @PA_API_VERSION@ + +PA_C_DECL_END + +#endif diff --git a/src/polyp/polyplib.h b/src/polyp/polyplib.h new file mode 100644 index 00000000..b9b9b447 --- /dev/null +++ b/src/polyp/polyplib.h @@ -0,0 +1,86 @@ +#ifndef foopolyplibhfoo +#define foopolyplibhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** \file + * Include all polyplib header file at once. The following files are included: \ref mainloop-api.h, \ref sample.h, + * \ref polyplib-def.h, \ref polyplib-context.h, \ref polyplib-stream.h, + * \ref polyplib-introspect.h, \ref polyplib-subscribe.h and \ref polyplib-scache.h \ref polyplib-version.h + * at once */ + +/** \mainpage + * + * \section intro_sec Introduction + * + * This document describes the client API for the polypaudio sound + * server. The API comes in two flavours: + * + * \li The complete but somewhat complicated to use asynchronous API + * \li And the simplified, easy to use, but limited synchronous API + * + * The polypaudio client libraries are thread safe as long as all + * objects created by any library function are accessed from the thread + * that created them only. + * + * \section simple_sec Simple API + * + * Use this if you develop your program in synchronous style and just + * need a way to play or record data on the sound server. See + * \ref polyplib-simple.h for more details. + * + * \section async_api Asynchronous API + * + * Use this if you develop your programs in asynchronous, main loop + * based style or want to use advanced features of the polypaudio + * API. A good starting point is \ref polyplib-context.h + * + * The asynchronous API relies on an abstract main loop API that is + * described in \ref mainloop-api.h. Two distinct implementations are + * available: + * + * \li \ref mainloop.h: a minimal but fast implementation based on poll() + * \li \ref glib-mainloop.h: a wrapper around GLIB's main loop + * + * UNIX signals may be hooked to a main loop using the functions from + * \ref mainloop-signal.h + * + * \section pkgconfig pkg-config + * + * The polypaudio libraries provide pkg-config snippets for the different modules. To use the + * asynchronous API use "polyplib" as pkg-config file. GLIB main loop + * support is available as "polyplib-glib-mainloop". The simple + * synchronous API is available as "polyplib-simple". + */ + +#endif diff --git a/src/polyp/sample.c b/src/polyp/sample.c new file mode 100644 index 00000000..d587170c --- /dev/null +++ b/src/polyp/sample.c @@ -0,0 +1,149 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "sample.h" + +size_t pa_sample_size(const pa_sample_spec *spec) { + assert(spec); + + switch (spec->format) { + case PA_SAMPLE_U8: + case PA_SAMPLE_ULAW: + case PA_SAMPLE_ALAW: + return 1; + case PA_SAMPLE_S16LE: + case PA_SAMPLE_S16BE: + return 2; + case PA_SAMPLE_FLOAT32LE: + case PA_SAMPLE_FLOAT32BE: + return 4; + default: + assert(0); + } +} + +size_t pa_frame_size(const pa_sample_spec *spec) { + assert(spec); + + return pa_sample_size(spec) * spec->channels; +} + +size_t pa_bytes_per_second(const pa_sample_spec *spec) { + assert(spec); + return spec->rate*pa_frame_size(spec); +} + +pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) { + assert(spec); + + return (pa_usec_t) (((double) length/pa_frame_size(spec)*1000000)/spec->rate); +} + +int pa_sample_spec_valid(const pa_sample_spec *spec) { + assert(spec); + + if (spec->rate <= 0 || + spec->channels <= 0 || + spec->channels > PA_CHANNELS_MAX || + spec->format >= PA_SAMPLE_MAX || + spec->format < 0) + return 0; + + return 1; +} + +int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b) { + assert(a && b); + + return (a->format == b->format) && (a->rate == b->rate) && (a->channels == b->channels); +} + +const char *pa_sample_format_to_string(pa_sample_format_t f) { + static const char* const table[]= { + [PA_SAMPLE_U8] = "u8", + [PA_SAMPLE_ALAW] = "aLaw", + [PA_SAMPLE_ULAW] = "uLaw", + [PA_SAMPLE_S16LE] = "s16le", + [PA_SAMPLE_S16BE] = "s16be", + [PA_SAMPLE_FLOAT32LE] = "float32le", + [PA_SAMPLE_FLOAT32BE] = "float32be", + }; + + if (f >= PA_SAMPLE_MAX) + return NULL; + + return table[f]; +} + +char *pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec) { + assert(s && l && spec); + + if (!pa_sample_spec_valid(spec)) + snprintf(s, l, "Invalid"); + else + snprintf(s, l, "%s %uch %uHz", pa_sample_format_to_string(spec->format), spec->channels, spec->rate); + + return s; +} + +void pa_bytes_snprint(char *s, size_t l, unsigned v) { + if (v >= ((unsigned) 1024)*1024*1024) + snprintf(s, l, "%0.1f GB", ((double) v)/1024/1024/1024); + else if (v >= ((unsigned) 1024)*1024) + snprintf(s, l, "%0.1f MB", ((double) v)/1024/1024); + else if (v >= (unsigned) 1024) + snprintf(s, l, "%0.1f KB", ((double) v)/1024); + else + snprintf(s, l, "%u B", (unsigned) v); +} + +pa_sample_format_t pa_parse_sample_format(const char *format) { + + if (strcasecmp(format, "s16le") == 0) + return PA_SAMPLE_S16LE; + else if (strcasecmp(format, "s16be") == 0) + return PA_SAMPLE_S16BE; + else if (strcasecmp(format, "s16ne") == 0 || strcasecmp(format, "s16") == 0 || strcasecmp(format, "16") == 0) + return PA_SAMPLE_S16NE; + else if (strcasecmp(format, "u8") == 0 || strcasecmp(format, "8") == 0) + return PA_SAMPLE_U8; + else if (strcasecmp(format, "float32") == 0 || strcasecmp(format, "float32ne") == 0) + return PA_SAMPLE_FLOAT32; + else if (strcasecmp(format, "float32le") == 0) + return PA_SAMPLE_FLOAT32LE; + else if (strcasecmp(format, "float32be") == 0) + return PA_SAMPLE_FLOAT32BE; + else if (strcasecmp(format, "ulaw") == 0) + return PA_SAMPLE_ULAW; + else if (strcasecmp(format, "alaw") == 0) + return PA_SAMPLE_ALAW; + + return -1; +} diff --git a/src/polyp/sample.h b/src/polyp/sample.h new file mode 100644 index 00000000..c1b98f1c --- /dev/null +++ b/src/polyp/sample.h @@ -0,0 +1,120 @@ +#ifndef foosamplehfoo +#define foosamplehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include + +#include + +/** \file + * Constants and routines for sample type handling */ + +PA_C_DECL_BEGIN + +/* Maximum allowed channels */ +#define PA_CHANNELS_MAX 16 + +/** Sample format */ +typedef enum pa_sample_format { + PA_SAMPLE_U8, /**< Unsigned 8 Bit PCM */ + PA_SAMPLE_ALAW, /**< 8 Bit a-Law */ + PA_SAMPLE_ULAW, /**< 8 Bit mu-Law */ + PA_SAMPLE_S16LE, /**< Signed 16 Bit PCM, little endian (PC) */ + PA_SAMPLE_S16BE, /**< Signed 16 Bit PCM, big endian */ + PA_SAMPLE_FLOAT32LE, /**< 32 Bit IEEE floating point, little endian, range -1..1 */ + PA_SAMPLE_FLOAT32BE, /**< 32 Bit IEEE floating point, big endian, range -1..1 */ + PA_SAMPLE_MAX, /**< Upper limit of valid sample types */ + PA_SAMPLE_INVALID = -1 /**< An invalid value */ +} pa_sample_format_t; + +#ifdef WORDS_BIGENDIAN +/** Signed 16 Bit PCM, native endian */ +#define PA_SAMPLE_S16NE PA_SAMPLE_S16BE +/** 32 Bit IEEE floating point, native endian */ +#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32BE +/** Signed 16 Bit PCM reverse endian */ +#define PA_SAMPLE_S16RE PA_SAMPLE_S16LE +/** 32 Bit IEEE floating point, reverse endian */ +#define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32LE +#else +/** Signed 16 Bit PCM, native endian */ +#define PA_SAMPLE_S16NE PA_SAMPLE_S16LE +/** 32 Bit IEEE floating point, native endian */ +#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32LE +/** Signed 16 Bit PCM reverse endian */ +#define PA_SAMPLE_S16RE PA_SAMPLE_S16BE +/** 32 Bit IEEE floating point, reverse endian */ +#define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32BE +#endif + +/** A Shortcut for PA_SAMPLE_FLOAT32NE */ +#define PA_SAMPLE_FLOAT32 PA_SAMPLE_FLOAT32NE + +/** A sample format and attribute specification */ +typedef struct pa_sample_spec { + pa_sample_format_t format; /**< The sample format */ + uint32_t rate; /**< The sample rate. (e.g. 44100) */ + uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */ +} pa_sample_spec; + +/** Type for usec specifications (unsigned). May be either 32 or 64 bit, depending on the architecture */ +typedef uint64_t pa_usec_t; + +/** Return the amount of bytes playback of a second of audio with the specified sample type takes */ +size_t pa_bytes_per_second(const pa_sample_spec *spec); + +/** Return the size of a frame with the specific sample type */ +size_t pa_frame_size(const pa_sample_spec *spec); + +/** Return the size of a sample with the specific sample type */ +size_t pa_sample_size(const pa_sample_spec *spec); + +/** Calculate the time the specified bytes take to play with the specified sample type */ +pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec); + +/** Return non-zero when the sample type specification is valid */ +int pa_sample_spec_valid(const pa_sample_spec *spec); + +/** Return non-zero when the two sample type specifications match */ +int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b); + +/* Return a descriptive string for the specified sample format. \since 0.8 */ +const char *pa_sample_format_to_string(pa_sample_format_t f); + +/** Parse a sample format text. Inverse of pa_sample_format_to_string() */ +pa_sample_format_t pa_parse_sample_format(const char *format); + +/** Maximum required string length for pa_sample_spec_snprint() */ +#define PA_SAMPLE_SPEC_SNPRINT_MAX 32 + +/** Pretty print a sample type specification to a string */ +char* pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec); + +/** Pretty print a byte size value. (i.e. "2.5 MB") */ +void pa_bytes_snprint(char *s, size_t l, unsigned v); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/volume.c b/src/polyp/volume.c new file mode 100644 index 00000000..0f153141 --- /dev/null +++ b/src/polyp/volume.c @@ -0,0 +1,176 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "volume.h" + +int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) { + int i; + assert(a); + assert(b); + + if (a->channels != b->channels) + return 0; + + for (i = 0; i < a->channels; i++) + if (a->values[i] != b->values[i]) + return 0; + + return 1; +} + +pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) { + int i; + + assert(a); + assert(channels > 0); + assert(channels <= PA_CHANNELS_MAX); + + a->channels = channels; + + for (i = 0; i < a->channels; i++) + a->values[i] = v; + + return a; +} + +pa_volume_t pa_cvolume_avg(const pa_cvolume *a) { + uint64_t sum = 0; + int i; + assert(a); + + for (i = 0; i < a->channels; i++) + sum += a->values[i]; + + sum /= a->channels; + + return (pa_volume_t) sum; +} + +pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) { + return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a)* pa_sw_volume_to_linear(b)); +} + +#define USER_DECIBEL_RANGE 30 + +pa_volume_t pa_sw_volume_from_dB(double dB) { + if (dB <= -USER_DECIBEL_RANGE) + return PA_VOLUME_MUTED; + + return (pa_volume_t) ((dB/USER_DECIBEL_RANGE+1)*PA_VOLUME_NORM); +} + +double pa_sw_volume_to_dB(pa_volume_t v) { + if (v == PA_VOLUME_MUTED) + return PA_DECIBEL_MININFTY; + + return ((double) v/PA_VOLUME_NORM-1)*USER_DECIBEL_RANGE; +} + +pa_volume_t pa_sw_volume_from_linear(double v) { + + if (v <= 0) + return PA_VOLUME_MUTED; + + if (v > .999 && v < 1.001) + return PA_VOLUME_NORM; + + return pa_sw_volume_from_dB(20*log10(v)); +} + +double pa_sw_volume_to_linear(pa_volume_t v) { + + if (v == PA_VOLUME_MUTED) + return 0; + + return pow(10, pa_sw_volume_to_dB(v)/20); +} + +char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) { + unsigned channel; + int first = 1; + char *e; + + assert(s); + assert(l > 0); + assert(c); + + *(e = s) = 0; + + for (channel = 0; channel < c->channels && l > 1; channel++) { + l -= snprintf(e, l, "%s%u: %3u%%", + first ? "" : " ", + channel, + (c->values[channel]*100)/PA_VOLUME_NORM); + + e = strchr(e, 0); + first = 0; + } + + return s; +} + +/** Return non-zero if the volume of all channels is equal to the specified value */ +int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) { + unsigned c; + assert(a); + + for (c = 0; c < a->channels; c++) + if (a->values[c] != v) + return 0; + + return 1; +} + +pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { + unsigned i; + + assert(dest); + assert(a); + assert(b); + + for (i = 0; i < a->channels || i < b->channels || i < PA_CHANNELS_MAX; i++) { + + dest->values[i] = pa_sw_volume_multiply( + i < a->channels ? a->values[i] : PA_VOLUME_NORM, + i < b->channels ? b->values[i] : PA_VOLUME_NORM); + } + + dest->channels = i; + + return dest; +} + +int pa_cvolume_valid(const pa_cvolume *v) { + assert(v); + + if (v->channels <= 0 || v->channels > PA_CHANNELS_MAX) + return 0; + + return 1; +} diff --git a/src/polyp/volume.h b/src/polyp/volume.h new file mode 100644 index 00000000..b2a48084 --- /dev/null +++ b/src/polyp/volume.h @@ -0,0 +1,107 @@ +#ifndef foovolumehfoo +#define foovolumehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include + +/** \file + * Constants and routines for volume handling */ + +PA_C_DECL_BEGIN + +/** Volume specification: + * PA_VOLUME_MUTED: silence; + * < PA_VOLUME_NORM: decreased volume; + * PA_VOLUME_NORM: normal volume; + * > PA_VOLUME_NORM: increased volume */ +typedef uint32_t pa_volume_t; + +/** Normal volume (100%) */ +#define PA_VOLUME_NORM (0x10000) + +/** Muted volume (0%) */ +#define PA_VOLUME_MUTED (0) + +/** A structure encapsulating a per-channel volume */ +typedef struct pa_cvolume { + uint8_t channels; + pa_volume_t values[PA_CHANNELS_MAX]; +} pa_cvolume; + +/** Return non-zero when *a == *b */ +int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b); + +/** Set the volume of all channels to PA_VOLUME_NORM */ +#define pa_cvolume_reset(a, n) pa_cvolume_set((a), (n), PA_VOLUME_NORM) + +/** Set the volume of all channels to PA_VOLUME_MUTED */ +#define pa_cvolume_mute(a, n) pa_cvolume_set((a), (n), PA_VOLUME_MUTED) + +/** Set the volume of all channels to the specified parameter */ +pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v); + +/** Pretty print a volume structure */ +#define PA_CVOLUME_SNPRINT_MAX 64 +char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c); + +/** Return the average volume of all channels */ +pa_volume_t pa_cvolume_avg(const pa_cvolume *a); + +/** Return TRUE when the passed cvolume structure is valid, FALSE otherwise */ +int pa_cvolume_valid(const pa_cvolume *v); + +/** Return non-zero if the volume of all channels is equal to the specified value */ +int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v); + +#define pa_cvolume_is_muted(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_MUTED) +#define pa_cvolume_is_norm(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_NORM) + +/** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. */ +pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b); + +pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b); + +/** Convert a decibel value to a volume. \since 0.4 */ +pa_volume_t pa_sw_volume_from_dB(double f); + +/** Convert a volume to a decibel value. \since 0.4 */ +double pa_sw_volume_to_dB(pa_volume_t v); + +/** Convert a linear factor to a volume. \since 0.8 */ +pa_volume_t pa_sw_volume_from_linear(double v); + +/** Convert a volume to a linear factor. \since 0.8 */ +double pa_sw_volume_to_linear(pa_volume_t v); + +#ifdef INFINITY +#define PA_DECIBEL_MININFTY (-INFINITY) +#else +/** This value is used as minus infinity when using pa_volume_{to,from}_dB(). \since 0.4 */ +#define PA_DECIBEL_MININFTY (-200) +#endif + +PA_C_DECL_END + +#endif diff --git a/src/polypcore/alsa-util.c b/src/polypcore/alsa-util.c new file mode 100644 index 00000000..7528ee0b --- /dev/null +++ b/src/polypcore/alsa-util.c @@ -0,0 +1,124 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "alsa-util.h" +#include +#include "xmalloc.h" +#include "log.h" + +/* Set the hardware parameters of the given ALSA device. Returns the + * selected fragment settings in *period and *period_size */ +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { + int ret = -1; + snd_pcm_uframes_t buffer_size; + snd_pcm_hw_params_t *hwparams = NULL; + static const snd_pcm_format_t format_trans[] = { + [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8, + [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW, + [PA_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW, + [PA_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE, + [PA_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE, + [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE, + [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, + }; + assert(pcm_handle && ss && periods && period_size); + + if (snd_pcm_hw_params_malloc(&hwparams) < 0 || + snd_pcm_hw_params_any(pcm_handle, hwparams) < 0 || + snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0 || + snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format]) < 0 || + snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &ss->rate, NULL) < 0 || + snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels) < 0 || + (*periods > 0 && snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, periods, NULL) < 0) || + (*period_size > 0 && snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL) < 0) || + snd_pcm_hw_params(pcm_handle, hwparams) < 0) + goto finish; + + if (snd_pcm_prepare(pcm_handle) < 0) + goto finish; + + if (snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size) < 0 || + snd_pcm_hw_params_get_period_size(hwparams, period_size, NULL) < 0) + goto finish; + + assert(buffer_size > 0); + assert(*period_size > 0); + *periods = buffer_size / *period_size; + assert(*periods > 0); + + ret = 0; + +finish: + if (hwparams) + snd_pcm_hw_params_free(hwparams); + + return ret; +} + +/* Allocate an IO event for every ALSA poll descriptor for the + * specified ALSA device. Return a pointer to such an array in + * *io_events. Store the length of that array in *n_io_events. Use the + * specified callback function and userdata. The array has to be freed + * with pa_free_io_events(). */ +int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api* m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata) { + unsigned i; + struct pollfd *pfds, *ppfd; + pa_io_event **ios; + assert(pcm_handle && m && io_events && n_io_events && cb); + + *n_io_events = snd_pcm_poll_descriptors_count(pcm_handle); + + pfds = pa_xmalloc(sizeof(struct pollfd) * *n_io_events); + if (snd_pcm_poll_descriptors(pcm_handle, pfds, *n_io_events) < 0) { + pa_xfree(pfds); + return -1; + } + + *io_events = pa_xmalloc(sizeof(void*) * *n_io_events); + + for (i = 0, ios = *io_events, ppfd = pfds; i < *n_io_events; i++, ios++, ppfd++) { + *ios = m->io_new(m, ppfd->fd, + ((ppfd->events & POLLIN) ? PA_IO_EVENT_INPUT : 0) | + ((ppfd->events & POLLOUT) ? PA_IO_EVENT_OUTPUT : 0), cb, userdata); + assert(*ios); + } + + pa_xfree(pfds); + return 0; +} + +/* Free the memory allocated by pa_create_io_events() */ +void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_events, unsigned n_io_events) { + unsigned i; + pa_io_event **ios; + assert(m && io_events); + + for (ios = io_events, i = 0; i < n_io_events; i++, ios++) + m->io_free(*ios); + pa_xfree(io_events); +} diff --git a/src/polypcore/alsa-util.h b/src/polypcore/alsa-util.h new file mode 100644 index 00000000..5d6d6634 --- /dev/null +++ b/src/polypcore/alsa-util.h @@ -0,0 +1,35 @@ +#ifndef fooalsautilhfoo +#define fooalsautilhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include + +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size); + +int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api *m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata); +void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_sources, unsigned n_io_sources); + +#endif diff --git a/src/polypcore/authkey-prop.c b/src/polypcore/authkey-prop.c new file mode 100644 index 00000000..8657f5a5 --- /dev/null +++ b/src/polypcore/authkey-prop.c @@ -0,0 +1,87 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include "xmalloc.h" +#include "authkey-prop.h" +#include "props.h" +#include "log.h" + +struct authkey_data { + int ref; + size_t length; +}; + +int pa_authkey_prop_get(pa_core *c, const char *name, void *data, size_t len) { + struct authkey_data *a; + assert(c && name && data && len > 0); + + if (!(a = pa_property_get(c, name))) + return -1; + + assert(a->length == len); + memcpy(data, a+1, len); + return 0; +} + +int pa_authkey_prop_put(pa_core *c, const char *name, const void *data, size_t len) { + struct authkey_data *a; + assert(c && name); + + if (pa_property_get(c, name)) + return -1; + + a = pa_xmalloc(sizeof(struct authkey_data) + len); + a->ref = 1; + a->length = len; + memcpy(a+1, data, len); + + pa_property_set(c, name, a); + + return 0; +} + +void pa_authkey_prop_ref(pa_core *c, const char *name) { + struct authkey_data *a; + assert(c && name); + + a = pa_property_get(c, name); + assert(a && a->ref >= 1); + + a->ref++; +} + +void pa_authkey_prop_unref(pa_core *c, const char *name) { + struct authkey_data *a; + assert(c && name); + + a = pa_property_get(c, name); + assert(a && a->ref >= 1); + + if (!(--a->ref)) { + pa_property_remove(c, name); + pa_xfree(a); + } +} + + diff --git a/src/polypcore/authkey-prop.h b/src/polypcore/authkey-prop.h new file mode 100644 index 00000000..29b40bb2 --- /dev/null +++ b/src/polypcore/authkey-prop.h @@ -0,0 +1,43 @@ +#ifndef fooauthkeyprophfoo +#define fooauthkeyprophfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" + +/* The authkey-prop uses a central property to store a previously + * loaded cookie in memory. Useful for sharing the same cookie between + * several modules. */ + +/* Return the data of the specified authorization key property. Doesn't alter the refernce count of the key */ +int pa_authkey_prop_get(pa_core *c, const char *name, void *data, size_t len); + +/* Store data in the specified authorization key property. The initial reference count is set to 1 */ +int pa_authkey_prop_put(pa_core *c, const char *name, const void *data, size_t len); + +/* Increase the reference count of the specified authorization key */ +void pa_authkey_prop_ref(pa_core *c, const char *name); + +/* Decrease the reference count of the specified authorization key */ +void pa_authkey_prop_unref(pa_core *c, const char *name); + +#endif diff --git a/src/polypcore/authkey.c b/src/polypcore/authkey.c new file mode 100644 index 00000000..969f09d9 --- /dev/null +++ b/src/polypcore/authkey.c @@ -0,0 +1,201 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "authkey.h" +#include "util.h" +#include "log.h" +#include "random.h" + +/* Generate a new authorization key, store it in file fd and return it in *data */ +static int generate(int fd, void *ret_data, size_t length) { + ssize_t r; + assert(fd >= 0 && ret_data && length); + + pa_random(ret_data, length); + + lseek(fd, 0, SEEK_SET); + ftruncate(fd, 0); + + if ((r = pa_loop_write(fd, ret_data, length)) < 0 || (size_t) r != length) { + pa_log(__FILE__": failed to write cookie file: %s\n", strerror(errno)); + return -1; + } + + return 0; +} + +/* Load an euthorization cookie from file fn and store it in data. If + * the cookie file doesn't exist, create it */ +static int load(const char *fn, void *data, size_t length) { + int fd = -1; + int writable = 1; + int unlock = 0, ret = -1; + ssize_t r; + assert(fn && data && length); + + if ((fd = open(fn, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { + if (errno != EACCES || (fd = open(fn, O_RDONLY)) < 0) { + pa_log(__FILE__": failed to open cookie file '%s': %s\n", fn, strerror(errno)); + goto finish; + } else + writable = 0; + } + + unlock = pa_lock_fd(fd, 1) >= 0; + + if ((r = pa_loop_read(fd, data, length)) < 0) { + pa_log(__FILE__": failed to read cookie file '%s': %s\n", fn, strerror(errno)); + goto finish; + } + + if ((size_t) r != length) { + + if (!writable) { + pa_log(__FILE__": unable to write cookie to read only file\n"); + goto finish; + } + + if (generate(fd, data, length) < 0) + goto finish; + } + + ret = 0; + +finish: + + if (fd >= 0) { + + if (unlock) + pa_lock_fd(fd, 0); + + close(fd); + } + + return ret; +} + +/* Load a cookie from a cookie file. If the file doesn't exist, create it. */ +int pa_authkey_load(const char *path, void *data, size_t length) { + int ret; + + assert(path && data && length); + + ret = load(path, data, length); + + if (ret < 0) + pa_log(__FILE__": Failed to load authorization key '%s': %s\n", path, + (ret == -1) ? strerror(errno) : "file corrupt"); + + return ret; +} + +/* If the specified file path starts with / return it, otherwise + * return path prepended with home directory */ +static const char *normalize_path(const char *fn, char *s, size_t l) { + assert(fn && s && l > 0); + +#ifndef OS_IS_WIN32 + if (fn[0] != '/') { +#else + if (strlen(fn) < 3 || !isalpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') { +#endif + char homedir[PATH_MAX]; + if (!pa_get_home_dir(homedir, sizeof(homedir))) + return NULL; + +#ifndef OS_IS_WIN32 + snprintf(s, l, "%s/%s", homedir, fn); +#else + snprintf(s, l, "%s\\%s", homedir, fn); +#endif + return s; + } + + return fn; +} + +/* Load a cookie from a file in the home directory. If the specified + * path starts with /, use it as absolute path instead. */ +int pa_authkey_load_auto(const char *fn, void *data, size_t length) { + char path[PATH_MAX]; + const char *p; + assert(fn && data && length); + + if (!(p = normalize_path(fn, path, sizeof(path)))) + return -2; + + return pa_authkey_load(p, data, length); +} + +/* Store the specified cookie in the speicified cookie file */ +int pa_authkey_save(const char *fn, const void *data, size_t length) { + int fd = -1; + int unlock = 0, ret = -1; + ssize_t r; + char path[PATH_MAX]; + const char *p; + assert(fn && data && length); + + if (!(p = normalize_path(fn, path, sizeof(path)))) + return -2; + + if ((fd = open(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { + pa_log(__FILE__": failed to open cookie file '%s': %s\n", fn, strerror(errno)); + goto finish; + } + + unlock = pa_lock_fd(fd, 1) >= 0; + + if ((r = pa_loop_write(fd, data, length)) < 0 || (size_t) r != length) { + pa_log(__FILE__": failed to read cookie file '%s': %s\n", fn, strerror(errno)); + goto finish; + } + + ret = 0; + +finish: + + if (fd >= 0) { + + if (unlock) + pa_lock_fd(fd, 0); + + close(fd); + } + + return ret; +} diff --git a/src/polypcore/authkey.h b/src/polypcore/authkey.h new file mode 100644 index 00000000..81b1a578 --- /dev/null +++ b/src/polypcore/authkey.h @@ -0,0 +1,32 @@ +#ifndef fooauthkeyhfoo +#define fooauthkeyhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +int pa_authkey_load(const char *path, void *data, size_t len); +int pa_authkey_load_auto(const char *fn, void *data, size_t length); + +int pa_authkey_save(const char *path, const void *data, size_t length); + +#endif diff --git a/src/polypcore/autoload.c b/src/polypcore/autoload.c new file mode 100644 index 00000000..ff2916cb --- /dev/null +++ b/src/polypcore/autoload.c @@ -0,0 +1,180 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "autoload.h" +#include "module.h" +#include "xmalloc.h" +#include "memchunk.h" +#include "sound-file.h" +#include "log.h" +#include "scache.h" +#include "subscribe.h" + +static void entry_free(pa_autoload_entry *e) { + assert(e); + pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_AUTOLOAD|PA_SUBSCRIPTION_EVENT_REMOVE, PA_INVALID_INDEX); + pa_xfree(e->name); + pa_xfree(e->module); + pa_xfree(e->argument); + pa_xfree(e); +} + +static void entry_remove_and_free(pa_autoload_entry *e) { + assert(e && e->core); + + pa_idxset_remove_by_data(e->core->autoload_idxset, e, NULL); + pa_hashmap_remove(e->core->autoload_hashmap, e->name); + entry_free(e); +} + +static pa_autoload_entry* entry_new(pa_core *c, const char *name) { + pa_autoload_entry *e = NULL; + assert(c && name); + + if (c->autoload_hashmap && (e = pa_hashmap_get(c->autoload_hashmap, name))) + return NULL; + + e = pa_xmalloc(sizeof(pa_autoload_entry)); + e->core = c; + e->name = pa_xstrdup(name); + e->module = e->argument = NULL; + e->in_action = 0; + + if (!c->autoload_hashmap) + c->autoload_hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + assert(c->autoload_hashmap); + + pa_hashmap_put(c->autoload_hashmap, e->name, e); + + if (!c->autoload_idxset) + c->autoload_idxset = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + pa_idxset_put(c->autoload_idxset, e, &e->index); + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_AUTOLOAD|PA_SUBSCRIPTION_EVENT_NEW, e->index); + + return e; +} + +int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const char*module, const char *argument, uint32_t *idx) { + pa_autoload_entry *e = NULL; + assert(c && name && module && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); + + if (!(e = entry_new(c, name))) + return -1; + + e->module = pa_xstrdup(module); + e->argument = pa_xstrdup(argument); + e->type = type; + + if (idx) + *idx = e->index; + + return 0; +} + +int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type_t type) { + pa_autoload_entry *e; + assert(c && name && type); + + if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type) + return -1; + + entry_remove_and_free(e); + return 0; +} + +int pa_autoload_remove_by_index(pa_core *c, uint32_t idx) { + pa_autoload_entry *e; + assert(c && idx != PA_IDXSET_INVALID); + + if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, idx))) + return -1; + + entry_remove_and_free(e); + return 0; +} + +void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type_t type) { + pa_autoload_entry *e; + pa_module *m; + assert(c && name); + + if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || (e->type != type)) + return; + + if (e->in_action) + return; + + e->in_action = 1; + + if (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE) { + if ((m = pa_module_load(c, e->module, e->argument))) + m->auto_unload = 1; + } + + e->in_action = 0; +} + +static void free_func(void *p, PA_GCC_UNUSED void *userdata) { + pa_autoload_entry *e = p; + pa_idxset_remove_by_data(e->core->autoload_idxset, e, NULL); + entry_free(e); +} + +void pa_autoload_free(pa_core *c) { + if (c->autoload_hashmap) { + pa_hashmap_free(c->autoload_hashmap, free_func, NULL); + c->autoload_hashmap = NULL; + } + + if (c->autoload_idxset) { + pa_idxset_free(c->autoload_idxset, NULL, NULL); + c->autoload_idxset = NULL; + } +} + +const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type_t type) { + pa_autoload_entry *e; + assert(c && name); + + if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type) + return NULL; + + return e; +} + +const pa_autoload_entry* pa_autoload_get_by_index(pa_core *c, uint32_t idx) { + pa_autoload_entry *e; + assert(c && idx != PA_IDXSET_INVALID); + + if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, idx))) + return NULL; + + return e; +} diff --git a/src/polypcore/autoload.h b/src/polypcore/autoload.h new file mode 100644 index 00000000..7350c16a --- /dev/null +++ b/src/polypcore/autoload.h @@ -0,0 +1,58 @@ +#ifndef fooautoloadhfoo +#define fooautoloadhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "namereg.h" + +/* Using the autoloading facility, modules by be loaded on-demand and + * synchronously. The user may register a "ghost sink" or "ghost + * source". Whenever this sink/source is requested but not available a + * specified module is loaded. */ + +/* An autoload entry, or "ghost" sink/source */ +typedef struct pa_autoload_entry { + pa_core *core; + uint32_t index; + char *name; + pa_namereg_type_t type; /* Type of the autoload entry */ + int in_action; /* Currently loaded */ + char *module, *argument; +} pa_autoload_entry; + +/* Add a new autoload entry of the given time, with the speicified + * sink/source name, module name and argument. Return the entry's + * index in *index */ +int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const char*module, const char *argument, uint32_t *idx); + +/* Free all autoload entries */ +void pa_autoload_free(pa_core *c); +int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type_t type); +int pa_autoload_remove_by_index(pa_core *c, uint32_t idx); + +/* Request an autoload entry by its name, effectively causing a module to be loaded */ +void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type_t type); + +const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type_t type); +const pa_autoload_entry* pa_autoload_get_by_index(pa_core *c, uint32_t idx); + +#endif diff --git a/src/polypcore/cli-command.c b/src/polypcore/cli-command.c new file mode 100644 index 00000000..f6192bf8 --- /dev/null +++ b/src/polypcore/cli-command.c @@ -0,0 +1,834 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "cli-command.h" +#include "module.h" +#include "sink.h" +#include "source.h" +#include "client.h" +#include "sink-input.h" +#include "source-output.h" +#include "tokenizer.h" +#include "strbuf.h" +#include "namereg.h" +#include "cli-text.h" +#include "scache.h" +#include "sample-util.h" +#include "sound-file.h" +#include "play-memchunk.h" +#include "autoload.h" +#include "xmalloc.h" +#include "sound-file-stream.h" +#include "props.h" +#include "util.h" + +struct command { + const char *name; + int (*proc) (pa_core *c, pa_tokenizer*t, pa_strbuf *buf, int *fail); + const char *help; + unsigned args; +}; + +#define INCLUDE_META ".include" +#define FAIL_META ".fail" +#define NOFAIL_META ".nofail" + +/* Prototypes for all available commands */ +static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); + + +/* A method table for all available commands */ + +static const struct command commands[] = { + { "exit", pa_cli_command_exit, "Terminate the daemon", 1 }, + { "help", pa_cli_command_help, "Show this help", 1 }, + { "list-modules", pa_cli_command_modules, "List loaded modules", 1 }, + { "list-sinks", pa_cli_command_sinks, "List loaded sinks", 1 }, + { "list-sources", pa_cli_command_sources, "List loaded sources", 1 }, + { "list-clients", pa_cli_command_clients, "List loaded clients", 1 }, + { "list-sink-inputs", pa_cli_command_sink_inputs, "List sink inputs", 1 }, + { "list-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-module", pa_cli_command_load, "Load a module (args: name, arguments)", 3}, + { "unload-module", pa_cli_command_unload, "Unload a module (args: index)", 2}, + { "set-sink-volume", pa_cli_command_sink_volume, "Set the volume of a sink (args: index|name, volume)", 3}, + { "set-sink-input-volume", pa_cli_command_sink_input_volume, "Set the volume of a sink input (args: index|name, volume)", 3}, + { "set-default-sink", pa_cli_command_sink_default, "Set the default sink (args: index|name)", 2}, + { "set-default-source", 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}, + { "list-samples", pa_cli_command_scache_list, "List all entries in the sample cache", 1}, + { "play-sample", pa_cli_command_scache_play, "Play a sample from the sample cache (args: name, sink|index)", 3}, + { "remove-sample", pa_cli_command_scache_remove, "Remove a sample from the sample cache (args: name)", 2}, + { "load-sample", pa_cli_command_scache_load, "Load a sound file into the sample cache (args: name, filename)", 3}, + { "load-sample-lazy", pa_cli_command_scache_load, "Lazily load a sound file into the sample cache (args: name, filename)", 3}, + { "load-sample-dir-lazy", pa_cli_command_scache_load_dir, "Lazily load all files in a directory into the sample cache (args: pathname)", 2}, + { "play-file", pa_cli_command_play_file, "Play a sound file (args: filename, sink|index)", 3}, + { "list-autoload", pa_cli_command_autoload_list, "List autoload entries", 1}, + { "add-autoload-sink", pa_cli_command_autoload_add, "Add autoload entry for a sink (args: sink, module name, arguments)", 4}, + { "add-autoload-source", pa_cli_command_autoload_add, "Add autoload entry for a source (args: source, module name, arguments)", 4}, + { "remove-autoload-sink", pa_cli_command_autoload_remove, "Remove autoload entry for a sink (args: name)", 2}, + { "remove-autoload-source", pa_cli_command_autoload_remove, "Remove autoload entry for a source (args: name)", 2}, + { "dump", pa_cli_command_dump, "Dump daemon configuration", 1}, + { "list-props", pa_cli_command_list_props, NULL, 1}, + { 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) { + uint32_t idx; + + if (pa_atou(n, &idx) < 0) + return (uint32_t) PA_IDXSET_INVALID; + + return idx; +} + +static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, PA_GCC_UNUSED pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + assert(c && c->mainloop && t); + c->mainloop->quit(c->mainloop, 0); + return 0; +} + +static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + 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, " %-25s %s\n", command->name, command->help); + return 0; +} + +static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + char *s; + assert(c && t); + s = pa_module_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + pa_xfree(s); + return 0; +} + +static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + char *s; + assert(c && t); + s = pa_client_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + pa_xfree(s); + return 0; +} + +static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + char *s; + assert(c && t); + s = pa_sink_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + pa_xfree(s); + return 0; +} + +static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + char *s; + assert(c && t); + s = pa_source_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + pa_xfree(s); + return 0; +} + +static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + char *s; + assert(c && t); + s = pa_sink_input_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + pa_xfree(s); + return 0; +} + +static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + char *s; + assert(c && t); + s = pa_source_output_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + pa_xfree(s); + return 0; +} + +static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + char s[256]; + assert(c && t); + + pa_bytes_snprint(s, sizeof(s), c->memblock_stat->total_size); + pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n", + c->memblock_stat->total, + s); + + pa_bytes_snprint(s, sizeof(s), c->memblock_stat->allocated_size); + pa_strbuf_printf(buf, "Memory blocks allocated during the whole lifetime: %u, size: %s.\n", + c->memblock_stat->allocated, + s); + + pa_bytes_snprint(s, sizeof(s), pa_scache_total_size(c)); + pa_strbuf_printf(buf, "Total sample cache size: %s.\n", s); + + pa_sample_spec_snprint(s, sizeof(s), &c->default_sample_spec); + pa_strbuf_printf(buf, "Default sample spec: %s\n", s); + + pa_strbuf_printf(buf, "Default sink name: %s\n" + "Default source name: %s\n", + pa_namereg_get_default_sink_name(c), + pa_namereg_get_default_source_name(c)); + + return 0; +} + +static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + assert(c && t); + pa_cli_command_stat(c, t, buf, fail); + pa_cli_command_modules(c, t, buf, fail); + pa_cli_command_sinks(c, t, buf, fail); + pa_cli_command_sources(c, t, buf, fail); + pa_cli_command_clients(c, t, buf, fail); + pa_cli_command_sink_inputs(c, t, buf, fail); + pa_cli_command_source_outputs(c, t, buf, fail); + pa_cli_command_scache_list(c, t, buf, fail); + pa_cli_command_autoload_list(c, t, buf, fail); + return 0; +} + +static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + pa_module *m; + const char *name; + 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; + } + + return 0; +} + +static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + pa_module *m; + uint32_t idx; + 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; + } + + idx = (uint32_t) strtoul(i, &e, 10); + if (*e || !(m = pa_idxset_get_by_index(c->modules, idx))) { + pa_strbuf_puts(buf, "Invalid module index.\n"); + return -1; + } + + pa_module_unload_request(m); + return 0; +} + +static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n, *v; + pa_sink *sink; + uint32_t volume; + pa_cvolume cvolume; + + 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; + } + + if (pa_atou(v, &volume) < 0) { + pa_strbuf_puts(buf, "Failed to parse volume.\n"); + return -1; + } + + if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) { + pa_strbuf_puts(buf, "No sink found by this name or index.\n"); + return -1; + } + + pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume); + pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &cvolume); + return 0; +} + +static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n, *v; + pa_sink_input *si; + pa_volume_t volume; + pa_cvolume cvolume; + uint32_t idx; + + 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 ((idx = 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; + } + + if (pa_atou(v, &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) idx))) { + pa_strbuf_puts(buf, "No sink input found with this index.\n"); + return -1; + } + + pa_cvolume_set(&cvolume, si->sample_spec.channels, volume); + pa_sink_input_set_volume(si, &cvolume); + return 0; +} + +static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n; + 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; + } + + pa_namereg_set_default(c, n, PA_NAMEREG_SINK); + return 0; +} + +static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n; + 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; + } + + pa_namereg_set_default(c, n, PA_NAMEREG_SOURCE); + return 0; +} + +static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n; + pa_client *client; + uint32_t idx; + 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 ((idx = 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, idx))) { + 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(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n; + pa_sink_input *sink_input; + uint32_t idx; + 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 ((idx = 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, idx))) { + 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(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n; + pa_source_output *source_output; + uint32_t idx; + 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 ((idx = 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, idx))) { + pa_strbuf_puts(buf, "No source output found by this index.\n"); + return -1; + } + + pa_source_output_kill(source_output); + return 0; +} + +static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + char *s; + assert(c && t); + s = pa_scache_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + pa_xfree(s); + return 0; +} + +static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *n, *sink_name; + pa_sink *sink; + assert(c && t && buf && fail); + + if (!(n = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a sample name and a sink name.\n"); + return -1; + } + + if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) { + pa_strbuf_puts(buf, "No sink by that name.\n"); + return -1; + } + + if (pa_scache_play_item(c, n, sink, NULL) < 0) { + pa_strbuf_puts(buf, "Failed to play sample.\n"); + return -1; + } + + return 0; +} + +static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *n; + assert(c && t && buf && fail); + + if (!(n = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a sample name.\n"); + return -1; + } + + if (pa_scache_remove_item(c, n) < 0) { + pa_strbuf_puts(buf, "Failed to remove sample.\n"); + return -1; + } + + return 0; +} + +static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *fname, *n; + int r; + assert(c && t && buf && fail); + + if (!(fname = pa_tokenizer_get(t, 2)) || !(n = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a file name and a sample name.\n"); + return -1; + } + + if (strstr(pa_tokenizer_get(t, 0), "lazy")) + r = pa_scache_add_file_lazy(c, n, fname, NULL); + else + r = pa_scache_add_file(c, n, fname, NULL); + + if (r < 0) + pa_strbuf_puts(buf, "Failed to load sound file.\n"); + + return 0; +} + +static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *pname; + assert(c && t && buf && fail); + + if (!(pname = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a path name.\n"); + return -1; + } + + if (pa_scache_add_directory_lazy(c, pname) < 0) { + pa_strbuf_puts(buf, "Failed to load directory.\n"); + return -1; + } + + return 0; +} + +static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *fname, *sink_name; + pa_sink *sink; + assert(c && t && buf && fail); + + if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a file name and a sink name.\n"); + return -1; + } + + if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) { + pa_strbuf_puts(buf, "No sink by that name.\n"); + return -1; + } + + + return pa_play_file(sink, fname, NULL); +} + +static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *a, *b; + assert(c && t && buf && fail); + + if (!(a = pa_tokenizer_get(t, 1)) || !(b = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a device name, a filename or a module name and optionally module arguments\n"); + return -1; + } + + pa_autoload_add(c, a, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, b, pa_tokenizer_get(t, 3), NULL); + + return 0; +} + +static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *name; + assert(c && t && buf && fail); + + if (!(name = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a device name\n"); + return -1; + } + + if (pa_autoload_remove_by_name(c, name, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE) < 0) { + pa_strbuf_puts(buf, "Failed to remove autload entry\n"); + return -1; + } + + return 0; +} + +static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + char *s; + assert(c && t); + s = pa_autoload_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + pa_xfree(s); + return 0; +} + +static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + assert(c && t); + pa_property_dump(c, buf); + return 0; +} + +static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + pa_module *m; + pa_sink *s; + int nl; + const char *p; + uint32_t idx; + char txt[256]; + time_t now; + void *i; + pa_autoload_entry *a; + + assert(c && t); + + time(&now); + +#ifdef HAVE_CTIME_R + pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime_r(&now, txt)); +#else + pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now)); +#endif + + + for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) { + if (m->auto_unload) + continue; + + pa_strbuf_printf(buf, "load-module %s", m->name); + + if (m->argument) + pa_strbuf_printf(buf, " %s", m->argument); + + pa_strbuf_puts(buf, "\n"); + } + + nl = 0; + + for (s = pa_idxset_first(c->sinks, &idx); s; s = pa_idxset_next(c->sinks, &idx)) { + if (s->owner && s->owner->auto_unload) + continue; + + if (!nl) { + pa_strbuf_puts(buf, "\n"); + nl = 1; + } + + pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", s->name, pa_cvolume_avg(pa_sink_get_volume(s, PA_MIXER_HARDWARE))); + } + + + if (c->autoload_hashmap) { + nl = 0; + + i = NULL; + while ((a = pa_hashmap_iterate(c->autoload_hashmap, &i, NULL))) { + + if (!nl) { + pa_strbuf_puts(buf, "\n"); + nl = 1; + } + + pa_strbuf_printf(buf, "add-autoload-%s %s %s", a->type == PA_NAMEREG_SINK ? "sink" : "source", a->name, a->module); + + if (a->argument) + pa_strbuf_printf(buf, " %s", a->argument); + + pa_strbuf_puts(buf, "\n"); + } + } + + nl = 0; + + if ((p = pa_namereg_get_default_sink_name(c))) { + if (!nl) { + pa_strbuf_puts(buf, "\n"); + nl = 1; + } + pa_strbuf_printf(buf, "set-default-sink %s\n", p); + } + + if ((p = pa_namereg_get_default_source_name(c))) { + if (!nl) { + pa_strbuf_puts(buf, "\n"); + nl = 1; + } + pa_strbuf_printf(buf, "set-default-source %s\n", p); + } + + pa_strbuf_puts(buf, "\n### EOF\n"); + + return 0; +} + + +int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { + const char *cs; + + cs = s+strspn(s, whitespace); + + if (*cs == '#' || !*cs) + return 0; + else if (*cs == '.') { + if (!strcmp(cs, FAIL_META)) + *fail = 1; + else if (!strcmp(cs, NOFAIL_META)) + *fail = 0; + else { + size_t l; + 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) < 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; + pa_tokenizer *t = pa_tokenizer_new(cs, command->args); + assert(t); + ret = command->proc(c, t, buf, fail); + 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(pa_core *c, const char *fn, pa_strbuf *buf, int *fail) { + 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; + } + + while (fgets(line, sizeof(line), f)) { + char *e = line + strcspn(line, linebreak); + *e = 0; + + if (pa_cli_command_execute_line(c, line, buf, fail) < 0 && *fail) + goto fail; + } + + ret = 0; + +fail: + if (f) + fclose(f); + + return ret; +} + +int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { + const char *p; + assert(c && s && buf && fail); + + p = s; + while (*p) { + size_t l = strcspn(p, linebreak); + char *line = pa_xstrndup(p, l); + + if (pa_cli_command_execute_line(c, line, buf, fail) < 0&& *fail) { + pa_xfree(line); + return -1; + } + pa_xfree(line); + + p += l; + p += strspn(p, linebreak); + } + + return 0; +} diff --git a/src/polypcore/cli-command.h b/src/polypcore/cli-command.h new file mode 100644 index 00000000..78b8d5c6 --- /dev/null +++ b/src/polypcore/cli-command.h @@ -0,0 +1,40 @@ +#ifndef fooclicommandhfoo +#define fooclicommandhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "strbuf.h" +#include "core.h" + +/* Execute a single CLI command. Write the results to the string + * buffer *buf. If *fail is non-zero the function will return -1 when + * one or more of the executed commands failed. *fail + * may be modified by the function call. */ +int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail); + +/* Execute a whole file of CLI commands */ +int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int *fail); + +/* Split the specified string into lines and run pa_cli_command_execute_line() for each. */ +int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail); + +#endif diff --git a/src/polypcore/cli-text.c b/src/polypcore/cli-text.c new file mode 100644 index 00000000..58248d8e --- /dev/null +++ b/src/polypcore/cli-text.c @@ -0,0 +1,385 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "cli-text.h" +#include "module.h" +#include "client.h" +#include "sink.h" +#include "source.h" +#include "sink-input.h" +#include "source-output.h" +#include "strbuf.h" +#include "sample-util.h" +#include "scache.h" +#include "autoload.h" +#include "xmalloc.h" +#include + +char *pa_module_list_to_string(pa_core *c) { + pa_strbuf *s; + pa_module *m; + uint32_t idx = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_size(c->modules)); + + for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) + pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\targument: <%s>\n\tused: %i\n\tauto unload: %s\n", m->index, m->name, m->argument, m->n_used, m->auto_unload ? "yes" : "no"); + + return pa_strbuf_tostring_free(s); +} + +char *pa_client_list_to_string(pa_core *c) { + pa_strbuf *s; + pa_client *client; + uint32_t idx = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u client(s) logged in.\n", pa_idxset_size(c->clients)); + + for (client = pa_idxset_first(c->clients, &idx); client; client = pa_idxset_next(c->clients, &idx)) { + pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\tdriver: <%s>\n", client->index, client->name, client->driver); + + if (client->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", client->owner->index); + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_sink_list_to_string(pa_core *c) { + pa_strbuf *s; + pa_sink *sink; + uint32_t idx = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_size(c->sinks)); + + for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) { + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + + pa_strbuf_printf( + s, + " %c index: %u\n" + "\tname: <%s>\n" + "\tdriver: <%s>\n" + "\tvolume: <%s>\n" + "\tlatency: <%0.0f usec>\n" + "\tmonitor_source: <%u>\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n", + c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ', + sink->index, sink->name, + sink->driver, + pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, PA_MIXER_HARDWARE)), + (double) pa_sink_get_latency(sink), + sink->monitor_source->index, + pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map)); + + if (sink->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", sink->owner->index); + if (sink->description) + pa_strbuf_printf(s, "\tdescription: <%s>\n", sink->description); + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_source_list_to_string(pa_core *c) { + pa_strbuf *s; + pa_source *source; + uint32_t idx = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_size(c->sources)); + + for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) { + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + + + pa_strbuf_printf( + s, + " %c index: %u\n" + "\tname: <%s>\n" + "\tdriver: <%s>\n" + "\tlatency: <%0.0f usec>\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n", + c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ', + source->index, + source->name, + source->driver, + (double) pa_source_get_latency(source), + pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map)); + + if (source->monitor_of) + pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index); + if (source->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", source->owner->index); + if (source->description) + pa_strbuf_printf(s, "\tdescription: <%s>\n", source->description); + } + + return pa_strbuf_tostring_free(s); +} + + +char *pa_source_output_list_to_string(pa_core *c) { + pa_strbuf *s; + pa_source_output *o; + uint32_t idx = PA_IDXSET_INVALID; + static const char* const state_table[] = { + "RUNNING", + "CORKED", + "DISCONNECTED" + }; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_size(c->source_outputs)); + + for (o = pa_idxset_first(c->source_outputs, &idx); o; o = pa_idxset_next(c->source_outputs, &idx)) { + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + + assert(o->source); + + pa_strbuf_printf( + s, + " index: %u\n" + "\tname: '%s'\n" + "\tdriver: <%s>\n" + "\tstate: %s\n" + "\tsource: <%u> '%s'\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n" + "\tresample method: %s\n", + o->index, + o->name, + o->driver, + state_table[o->state], + o->source->index, o->source->name, + pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map), + pa_resample_method_to_string(pa_source_output_get_resample_method(o))); + if (o->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", o->owner->index); + if (o->client) + pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", o->client->index, o->client->name); + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_sink_input_list_to_string(pa_core *c) { + pa_strbuf *s; + pa_sink_input *i; + uint32_t idx = PA_IDXSET_INVALID; + static const char* const state_table[] = { + "RUNNING", + "CORKED", + "DISCONNECTED" + }; + + assert(c); + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_size(c->sink_inputs)); + + for (i = pa_idxset_first(c->sink_inputs, &idx); i; i = pa_idxset_next(c->sink_inputs, &idx)) { + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + + assert(i->sink); + + pa_strbuf_printf( + s, + " index: %u\n" + "\tname: <%s>\n" + "\tdriver: <%s>\n" + "\tstate: %s\n" + "\tsink: <%u> '%s'\n" + "\tvolume: <%s>\n" + "\tlatency: <%0.0f usec>\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n" + "\tresample method: %s\n", + i->index, + i->name, + i->driver, + state_table[i->state], + i->sink->index, i->sink->name, + pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)), + (double) pa_sink_input_get_latency(i), + pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), + pa_resample_method_to_string(pa_sink_input_get_resample_method(i))); + + if (i->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", i->owner->index); + if (i->client) + pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", i->client->index, i->client->name); + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_scache_list_to_string(pa_core *c) { + pa_strbuf *s; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u cache entries available.\n", c->scache ? pa_idxset_size(c->scache) : 0); + + if (c->scache) { + pa_scache_entry *e; + uint32_t idx = PA_IDXSET_INVALID; + + for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) { + double l = 0; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = "n/a", cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + + if (e->memchunk.memblock) { + pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec); + pa_channel_map_snprint(cm, sizeof(cm), &e->channel_map); + l = (double) e->memchunk.length / pa_bytes_per_second(&e->sample_spec); + } + + pa_strbuf_printf( + s, + " name: <%s>\n" + "\tindex: <%u>\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n" + "\tlength: <%u>\n" + "\tduration: <%0.1fs>\n" + "\tvolume: <%s>\n" + "\tlazy: %s\n" + "\tfilename: %s\n", + e->name, + e->index, + ss, + cm, + e->memchunk.memblock ? e->memchunk.length : 0, + l, + pa_cvolume_snprint(cv, sizeof(cv), &e->volume), + e->lazy ? "yes" : "no", + e->filename ? e->filename : "n/a"); + } + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_autoload_list_to_string(pa_core *c) { + pa_strbuf *s; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u autoload entries available.\n", c->autoload_hashmap ? pa_hashmap_size(c->autoload_hashmap) : 0); + + if (c->autoload_hashmap) { + pa_autoload_entry *e; + void *state = NULL; + + while ((e = pa_hashmap_iterate(c->autoload_hashmap, &state, NULL))) { + pa_strbuf_printf( + s, " name: <%s>\n\ttype: <%s>\n\tindex: <%u>\n\tmodule_name: <%s>\n\targuments: <%s>\n", + e->name, + e->type == PA_NAMEREG_SOURCE ? "source" : "sink", + e->index, + e->module, + e->argument); + + } + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_full_status_string(pa_core *c) { + pa_strbuf *s; + int i; + + s = pa_strbuf_new(); + + for (i = 0; i < 8; i++) { + char *t = NULL; + + switch (i) { + case 0: + t = pa_sink_list_to_string(c); + break; + case 1: + t = pa_source_list_to_string(c); + break; + case 2: + t = pa_sink_input_list_to_string(c); + break; + case 3: + t = pa_source_output_list_to_string(c); + break; + case 4: + t = pa_client_list_to_string(c); + break; + case 5: + t = pa_module_list_to_string(c); + break; + case 6: + t = pa_scache_list_to_string(c); + break; + case 7: + t = pa_autoload_list_to_string(c); + break; + } + + pa_strbuf_puts(s, t); + pa_xfree(t); + } + + return pa_strbuf_tostring_free(s); +} diff --git a/src/polypcore/cli-text.h b/src/polypcore/cli-text.h new file mode 100644 index 00000000..7a1a0361 --- /dev/null +++ b/src/polypcore/cli-text.h @@ -0,0 +1,42 @@ +#ifndef fooclitexthfoo +#define fooclitexthfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" + +/* Some functions to generate pretty formatted listings of + * entities. The returned strings have to be freed manually. */ + +char *pa_sink_input_list_to_string(pa_core *c); +char *pa_source_output_list_to_string(pa_core *c); +char *pa_sink_list_to_string(pa_core *core); +char *pa_source_list_to_string(pa_core *c); +char *pa_client_list_to_string(pa_core *c); +char *pa_module_list_to_string(pa_core *c); +char *pa_scache_list_to_string(pa_core *c); +char *pa_autoload_list_to_string(pa_core *c); + +char *pa_full_status_string(pa_core *c); + +#endif + diff --git a/src/polypcore/cli.c b/src/polypcore/cli.c new file mode 100644 index 00000000..bc0c285d --- /dev/null +++ b/src/polypcore/cli.c @@ -0,0 +1,147 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "ioline.h" +#include "cli.h" +#include "module.h" +#include "sink.h" +#include "source.h" +#include "client.h" +#include "sink-input.h" +#include "source-output.h" +#include "tokenizer.h" +#include "strbuf.h" +#include "namereg.h" +#include "cli-text.h" +#include "cli-command.h" +#include "xmalloc.h" +#include "log.h" + +#define PROMPT ">>> " + +struct pa_cli { + pa_core *core; + pa_ioline *line; + + void (*eof_callback)(pa_cli *c, void *userdata); + void *userdata; + + pa_client *client; + + int fail, kill_requested, defer_kill; +}; + +static void line_callback(pa_ioline *line, const char *s, void *userdata); +static void client_kill(pa_client *c); + +pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m) { + char cname[256]; + pa_cli *c; + assert(io); + + c = pa_xmalloc(sizeof(pa_cli)); + c->core = core; + c->line = pa_ioline_new(io); + assert(c->line); + + c->userdata = NULL; + c->eof_callback = NULL; + + pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); + c->client = pa_client_new(core, __FILE__, cname); + assert(c->client); + c->client->kill = client_kill; + c->client->userdata = c; + c->client->owner = m; + + pa_ioline_set_callback(c->line, line_callback, c); + pa_ioline_puts(c->line, "Welcome to polypaudio! Use \"help\" for usage information.\n"PROMPT); + + c->fail = c->kill_requested = c->defer_kill = 0; + + return c; +} + +void pa_cli_free(pa_cli *c) { + assert(c); + pa_ioline_close(c->line); + pa_ioline_unref(c->line); + pa_client_free(c->client); + pa_xfree(c); +} + +static void client_kill(pa_client *client) { + pa_cli *c; + assert(client && client->userdata); + c = client->userdata; + + pa_log_debug(__FILE__": CLI client killed.\n"); + if (c->defer_kill) + c->kill_requested = 1; + else { + if (c->eof_callback) + c->eof_callback(c, c->userdata); + } +} + +static void line_callback(pa_ioline *line, const char *s, void *userdata) { + pa_strbuf *buf; + pa_cli *c = userdata; + char *p; + assert(line && c); + + if (!s) { + pa_log_debug(__FILE__": CLI got EOF from user.\n"); + if (c->eof_callback) + c->eof_callback(c, c->userdata); + + return; + } + + buf = pa_strbuf_new(); + assert(buf); + c->defer_kill++; + pa_cli_command_execute_line(c->core, s, buf, &c->fail); + c->defer_kill--; + pa_ioline_puts(line, p = pa_strbuf_tostring_free(buf)); + pa_xfree(p); + + 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(pa_cli *c, void (*cb)(pa_cli*c, void *userdata), void *userdata) { + assert(c); + c->eof_callback = cb; + c->userdata = userdata; +} diff --git a/src/polypcore/cli.h b/src/polypcore/cli.h new file mode 100644 index 00000000..03f31c22 --- /dev/null +++ b/src/polypcore/cli.h @@ -0,0 +1,38 @@ +#ifndef fooclihfoo +#define fooclihfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "iochannel.h" +#include "core.h" +#include "module.h" + +typedef struct pa_cli pa_cli; + +/* Create a new command line session on the specified io channel owned by the specified module */ +pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m); +void pa_cli_free(pa_cli *cli); + +/* Set a callback function that is called whenever the command line session is terminated */ +void pa_cli_set_eof_callback(pa_cli *cli, void (*cb)(pa_cli*c, void *userdata), void *userdata); + +#endif diff --git a/src/polypcore/client.c b/src/polypcore/client.c new file mode 100644 index 00000000..3c2084bf --- /dev/null +++ b/src/polypcore/client.c @@ -0,0 +1,91 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "client.h" +#include "xmalloc.h" +#include "subscribe.h" +#include "log.h" + +pa_client *pa_client_new(pa_core *core, const char *name, const char *driver) { + pa_client *c; + int r; + assert(core); + + c = pa_xmalloc(sizeof(pa_client)); + c->name = pa_xstrdup(name); + c->driver = pa_xstrdup(driver); + c->owner = NULL; + c->core = core; + + c->kill = NULL; + c->userdata = NULL; + + r = pa_idxset_put(core->clients, c, &c->index); + assert(c->index != PA_IDXSET_INVALID && r >= 0); + + pa_log_info(__FILE__": created %u \"%s\"\n", c->index, c->name); + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index); + + pa_core_check_quit(core); + + return c; +} + +void pa_client_free(pa_client *c) { + assert(c && c->core); + + pa_idxset_remove_by_data(c->core->clients, c, NULL); + + pa_core_check_quit(c->core); + + pa_log_info(__FILE__": freed %u \"%s\"\n", c->index, c->name); + pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index); + pa_xfree(c->name); + pa_xfree(c->driver); + pa_xfree(c); +} + +void pa_client_kill(pa_client *c) { + assert(c); + if (!c->kill) { + pa_log_warn(__FILE__": kill() operation not implemented for client %u\n", c->index); + return; + } + + c->kill(c); +} + +void pa_client_set_name(pa_client *c, const char *name) { + assert(c); + pa_xfree(c->name); + c->name = pa_xstrdup(name); + + pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->index); +} diff --git a/src/polypcore/client.h b/src/polypcore/client.h new file mode 100644 index 00000000..92430338 --- /dev/null +++ b/src/polypcore/client.h @@ -0,0 +1,57 @@ +#ifndef fooclienthfoo +#define fooclienthfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" +#include "module.h" + +/* Every connection to the server should have a pa_client + * attached. That way the user may generate a listing of all connected + * clients easily and kill them if he wants.*/ + +typedef struct pa_client pa_client; + +struct pa_client { + uint32_t index; + + pa_module *owner; + char *name, *driver; + pa_core *core; + + void (*kill)(pa_client *c); + void *userdata; +}; + +pa_client *pa_client_new(pa_core *c, const char *name, const char *driver); + +/* This function should be called only by the code that created the client */ +void pa_client_free(pa_client *c); + +/* Code that didn't create the client should call this function to + * request destruction of the client */ +void pa_client_kill(pa_client *c); + +/* Rename the client */ +void pa_client_set_name(pa_client *c, const char *name); + +#endif diff --git a/src/polypcore/conf-parser.c b/src/polypcore/conf-parser.c new file mode 100644 index 00000000..507f2bf1 --- /dev/null +++ b/src/polypcore/conf-parser.c @@ -0,0 +1,176 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "conf-parser.h" +#include "log.h" +#include "util.h" +#include "xmalloc.h" + +#define WHITESPACE " \t\n" +#define COMMENTS "#;\n" + +/* Run the user supplied parser for an assignment */ +static int next_assignment(const char *filename, unsigned line, const pa_config_item *t, const char *lvalue, const char *rvalue, void *userdata) { + assert(filename && t && lvalue && rvalue); + + for (; t->parse; t++) + if (!strcmp(lvalue, t->lvalue)) + return t->parse(filename, line, lvalue, rvalue, t->data, userdata); + + pa_log(__FILE__": [%s:%u] Unknown lvalue '%s'.\n", filename, line, lvalue); + + return -1; +} + +/* Returns non-zero when c is contained in s */ +static int in_string(char c, const char *s) { + assert(s); + + for (; *s; s++) + if (*s == c) + return 1; + + return 0; +} + +/* Remove all whitepsapce from the beginning and the end of *s. *s may + * be modified. */ +static char *strip(char *s) { + char *b = s+strspn(s, WHITESPACE); + char *e, *l = NULL; + + for (e = b; *e; e++) + if (!in_string(*e, WHITESPACE)) + l = e; + + if (l) + *(l+1) = 0; + + return b; +} + +/* Parse a variable assignment line */ +static int parse_line(const char *filename, unsigned line, const pa_config_item *t, char *l, void *userdata) { + char *e, *c, *b = l+strspn(l, WHITESPACE); + + if ((c = strpbrk(b, COMMENTS))) + *c = 0; + + if (!*b) + return 0; + + if (!(e = strchr(b, '='))) { + pa_log(__FILE__": [%s:%u] Missing '='.\n", filename, line); + return -1; + } + + *e = 0; + e++; + + return next_assignment(filename, line, t, strip(b), strip(e), userdata); +} + +/* Go through the file and parse each line */ +int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void *userdata) { + int r = -1; + unsigned line = 0; + int do_close = !f; + assert(filename && t); + + if (!f && !(f = fopen(filename, "r"))) { + if (errno == ENOENT) { + r = 0; + goto finish; + } + + pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno)); + goto finish; + } + + while (!feof(f)) { + char l[256]; + if (!fgets(l, sizeof(l), f)) { + if (feof(f)) + break; + + pa_log(__FILE__": WARNING: failed to read configuration file '%s': %s\n", filename, strerror(errno)); + goto finish; + } + + if (parse_line(filename, ++line, t, l, userdata) < 0) + goto finish; + } + + r = 0; + +finish: + + if (do_close && f) + fclose(f); + + return r; +} + +int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + int *i = data; + int32_t k; + assert(filename && lvalue && rvalue && data); + + if (pa_atoi(rvalue, &k) < 0) { + pa_log(__FILE__": [%s:%u] Failed to parse numeric value: %s\n", filename, line, rvalue); + return -1; + } + + *i = (int) k; + return 0; +} + +int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + int *b = data, k; + assert(filename && lvalue && rvalue && data); + + if ((k = pa_parse_boolean(rvalue)) < 0) { + pa_log(__FILE__": [%s:%u] Failed to parse boolean value: %s\n", filename, line, rvalue); + return -1; + } + + *b = k; + + return 0; +} + +int pa_config_parse_string(const char *filename, PA_GCC_UNUSED unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + char **s = data; + assert(filename && lvalue && rvalue && data); + + pa_xfree(*s); + *s = *rvalue ? pa_xstrdup(rvalue) : NULL; + return 0; +} diff --git a/src/polypcore/conf-parser.h b/src/polypcore/conf-parser.h new file mode 100644 index 00000000..2dca3bce --- /dev/null +++ b/src/polypcore/conf-parser.h @@ -0,0 +1,47 @@ +#ifndef fooconfparserhfoo +#define fooconfparserhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +/* An abstract parser for simple, line based, shallow configuration + * files consisting of variable assignments only. */ + +/* Wraps info for parsing a specific configuration variable */ +typedef struct pa_config_item { + const char *lvalue; /* name of the variable */ + int (*parse)(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); /* Function that is called to parse the variable's value */ + void *data; /* Where to store the variable's data */ +} pa_config_item; + +/* The configuration file parsing routine. Expects a table of + * pa_config_items in *t that is terminated by an item where lvalue is + * NULL */ +int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void *userdata); + +/* Generic parsers for integers, booleans and strings */ +int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); +int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); +int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); + +#endif diff --git a/src/polypcore/core.c b/src/polypcore/core.c new file mode 100644 index 00000000..678e8212 --- /dev/null +++ b/src/polypcore/core.c @@ -0,0 +1,157 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "core.h" +#include "module.h" +#include "sink.h" +#include "source.h" +#include "namereg.h" +#include "util.h" +#include "scache.h" +#include "autoload.h" +#include "xmalloc.h" +#include "subscribe.h" +#include "props.h" +#include "random.h" + +pa_core* pa_core_new(pa_mainloop_api *m) { + pa_core* c; + c = pa_xmalloc(sizeof(pa_core)); + + c->mainloop = m; + c->clients = pa_idxset_new(NULL, NULL); + c->sinks = pa_idxset_new(NULL, NULL); + c->sources = pa_idxset_new(NULL, NULL); + c->source_outputs = pa_idxset_new(NULL, NULL); + c->sink_inputs = pa_idxset_new(NULL, NULL); + + c->default_source_name = c->default_sink_name = NULL; + + c->modules = NULL; + c->namereg = NULL; + c->scache = NULL; + c->autoload_idxset = NULL; + c->autoload_hashmap = NULL; + c->running_as_daemon = 0; + + c->default_sample_spec.format = PA_SAMPLE_S16NE; + c->default_sample_spec.rate = 44100; + c->default_sample_spec.channels = 2; + + c->module_auto_unload_event = NULL; + c->module_defer_unload_event = NULL; + c->scache_auto_unload_event = NULL; + + c->subscription_defer_event = NULL; + c->subscription_event_queue = NULL; + c->subscriptions = NULL; + + c->memblock_stat = pa_memblock_stat_new(); + + c->disallow_module_loading = 0; + + c->quit_event = NULL; + + c->exit_idle_time = -1; + c->module_idle_time = 20; + c->scache_idle_time = 20; + + c->resample_method = PA_RESAMPLER_SRC_SINC_FASTEST; + + pa_property_init(c); + + pa_random(&c->cookie, sizeof(c->cookie)); + +#ifdef SIGPIPE + pa_check_signal_is_blocked(SIGPIPE); +#endif + return c; +} + +void pa_core_free(pa_core *c) { + assert(c); + + pa_module_unload_all(c); + assert(!c->modules); + + assert(pa_idxset_isempty(c->clients)); + pa_idxset_free(c->clients, NULL, NULL); + + assert(pa_idxset_isempty(c->sinks)); + pa_idxset_free(c->sinks, NULL, NULL); + + assert(pa_idxset_isempty(c->sources)); + pa_idxset_free(c->sources, NULL, NULL); + + assert(pa_idxset_isempty(c->source_outputs)); + pa_idxset_free(c->source_outputs, NULL, NULL); + + assert(pa_idxset_isempty(c->sink_inputs)); + pa_idxset_free(c->sink_inputs, NULL, NULL); + + pa_scache_free(c); + pa_namereg_free(c); + pa_autoload_free(c); + pa_subscription_free_all(c); + + if (c->quit_event) + c->mainloop->time_free(c->quit_event); + + pa_xfree(c->default_source_name); + pa_xfree(c->default_sink_name); + + pa_memblock_stat_unref(c->memblock_stat); + + pa_property_cleanup(c); + + pa_xfree(c); +} + +static void quit_callback(pa_mainloop_api*m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + pa_core *c = userdata; + assert(c->quit_event = e); + + m->quit(m, 0); +} + +void pa_core_check_quit(pa_core *c) { + assert(c); + + if (!c->quit_event && c->exit_idle_time >= 0 && pa_idxset_size(c->clients) == 0) { + struct timeval tv; + pa_gettimeofday(&tv); + tv.tv_sec+= c->exit_idle_time; + c->quit_event = c->mainloop->time_new(c->mainloop, &tv, quit_callback, c); + } else if (c->quit_event && pa_idxset_size(c->clients) > 0) { + c->mainloop->time_free(c->quit_event); + c->quit_event = NULL; + } +} + diff --git a/src/polypcore/core.h b/src/polypcore/core.h new file mode 100644 index 00000000..f7a90169 --- /dev/null +++ b/src/polypcore/core.h @@ -0,0 +1,82 @@ +#ifndef foocorehfoo +#define foocorehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef struct pa_core pa_core; + +#include "idxset.h" +#include "hashmap.h" +#include +#include +#include "memblock.h" +#include "resampler.h" +#include "queue.h" +#include "subscribe.h" + +/* The core structure of polypaudio. Every polypaudio daemon contains + * exactly one of these. It is used for storing kind of global + * variables for the daemon. */ + +struct pa_core { + /* A random value which may be used to identify this instance of + * polypaudio. Not cryptographically secure in any way. */ + uint32_t cookie; + + pa_mainloop_api *mainloop; + + /* idxset of all kinds of entities */ + pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache, *autoload_idxset; + + /* Some hashmaps for all sorts of entities */ + pa_hashmap *namereg, *autoload_hashmap, *properties; + + /* The name of the default sink/source */ + char *default_source_name, *default_sink_name; + + pa_sample_spec default_sample_spec; + pa_time_event *module_auto_unload_event; + pa_defer_event *module_defer_unload_event; + + pa_defer_event *subscription_defer_event; + pa_queue *subscription_event_queue; + pa_subscription *subscriptions; + + pa_memblock_stat *memblock_stat; + + int disallow_module_loading, running_as_daemon; + int exit_idle_time, module_idle_time, scache_idle_time; + + pa_time_event *quit_event; + + pa_time_event *scache_auto_unload_event; + + pa_resample_method_t resample_method; +}; + +pa_core* pa_core_new(pa_mainloop_api *m); +void pa_core_free(pa_core*c); + +/* Check whether noone is connected to this core */ +void pa_core_check_quit(pa_core *c); + +#endif diff --git a/src/polypcore/dllmain.c b/src/polypcore/dllmain.c new file mode 100644 index 00000000..d1d120ab --- /dev/null +++ b/src/polypcore/dllmain.c @@ -0,0 +1,46 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef OS_IS_WIN32 + +#include +#include +#include + +#include + +extern pa_set_root(HANDLE handle); + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { + if (fdwReason != DLL_PROCESS_ATTACH) + return TRUE; + + if (!pa_set_root(hinstDLL)) + return FALSE; + + return TRUE; +} + +#endif /* OS_IS_WIN32 */ diff --git a/src/polypcore/dynarray.c b/src/polypcore/dynarray.c new file mode 100644 index 00000000..435fd768 --- /dev/null +++ b/src/polypcore/dynarray.c @@ -0,0 +1,102 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "dynarray.h" +#include "xmalloc.h" + +/* If the array becomes to small, increase its size by 100 entries */ +#define INCREASE_BY 100 + +struct pa_dynarray { + void **data; + unsigned n_allocated, n_entries; +}; + +pa_dynarray* pa_dynarray_new(void) { + pa_dynarray *a; + a = pa_xnew(pa_dynarray, 1); + a->data = NULL; + a->n_entries = 0; + a->n_allocated = 0; + return a; +} + +void pa_dynarray_free(pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata) { + unsigned i; + assert(a); + + if (func) + for (i = 0; i < a->n_entries; i++) + if (a->data[i]) + func(a->data[i], userdata); + + pa_xfree(a->data); + pa_xfree(a); +} + +void pa_dynarray_put(pa_dynarray*a, unsigned i, void *p) { + assert(a); + + if (i >= a->n_allocated) { + unsigned n; + + if (!p) + return; + + n = i+INCREASE_BY; + a->data = pa_xrealloc(a->data, sizeof(void*)*n); + memset(a->data+a->n_allocated, 0, sizeof(void*)*(n-a->n_allocated)); + a->n_allocated = n; + } + + a->data[i] = p; + + if (i >= a->n_entries) + a->n_entries = i+1; +} + +unsigned pa_dynarray_append(pa_dynarray*a, void *p) { + unsigned i = a->n_entries; + pa_dynarray_put(a, i, p); + return i; +} + +void *pa_dynarray_get(pa_dynarray*a, unsigned i) { + assert(a); + if (i >= a->n_allocated) + return NULL; + + assert(a->data); + return a->data[i]; +} + +unsigned pa_dynarray_size(pa_dynarray*a) { + assert(a); + return a->n_entries; +} diff --git a/src/polypcore/dynarray.h b/src/polypcore/dynarray.h new file mode 100644 index 00000000..9b1601ba --- /dev/null +++ b/src/polypcore/dynarray.h @@ -0,0 +1,49 @@ +#ifndef foodynarrayhfoo +#define foodynarrayhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef struct pa_dynarray pa_dynarray; + +/* Implementation of a simple dynamically sized array. The array + * expands if required, but doesn't shrink if possible. Memory + * management of the array's entries is the user's job. */ + +pa_dynarray* pa_dynarray_new(void); + +/* Free the array calling the specified function for every entry in + * the array. The function may be NULL. */ +void pa_dynarray_free(pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata); + +/* Store p at position i in the array */ +void pa_dynarray_put(pa_dynarray*a, unsigned i, void *p); + +/* Store p a the first free position in the array. Returns the index + * of that entry. If entries are removed from the array their position + * are not filled any more by this function. */ +unsigned pa_dynarray_append(pa_dynarray*a, void *p); + +void *pa_dynarray_get(pa_dynarray*a, unsigned i); + +unsigned pa_dynarray_size(pa_dynarray*a); + +#endif diff --git a/src/polypcore/endianmacros.h b/src/polypcore/endianmacros.h new file mode 100644 index 00000000..3ab1826a --- /dev/null +++ b/src/polypcore/endianmacros.h @@ -0,0 +1,77 @@ +#ifndef fooendianmacroshfoo +#define fooendianmacroshfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define INT16_SWAP(x) ( (int16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) ) +#define UINT16_SWAP(x) ( (uint16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) ) +#define INT32_SWAP(x) ( (int32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) ) +#define UINT32_SWAP(x) ( (uint32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) ) + +#define MAYBE_INT32_SWAP(c,x) ((c) ? INT32_SWAP(x) : x) +#define MAYBE_UINT32_SWAP(c,x) ((c) ? UINT32_SWAP(x) : x) + +#ifdef WORDS_BIGENDIAN + #define INT16_FROM_LE(x) INT16_SWAP(x) + #define INT16_FROM_BE(x) ((int16_t)(x)) + + #define INT16_TO_LE(x) INT16_SWAP(x) + #define INT16_TO_BE(x) ((int16_t)(x)) + + #define UINT16_FROM_LE(x) UINT16_SWAP(x) + #define UINT16_FROM_BE(x) ((uint16_t)(x)) + + #define INT32_FROM_LE(x) INT32_SWAP(x) + #define INT32_FROM_BE(x) ((int32_t)(x)) + + #define UINT32_FROM_LE(x) UINT32_SWAP(x) + #define UINT32_FROM_BE(x) ((uint32_t)(x)) + + #define UINT32_TO_LE(x) UINT32_SWAP(x) + #define UINT32_TO_BE(x) ((uint32_t)(x)) +#else + #define INT16_FROM_LE(x) ((int16_t)(x)) + #define INT16_FROM_BE(x) INT16_SWAP(x) + + #define INT16_TO_LE(x) ((int16_t)(x)) + #define INT16_TO_BE(x) INT16_SWAP(x) + + #define UINT16_FROM_LE(x) ((uint16_t)(x)) + #define UINT16_FROM_BE(x) UINT16_SWAP(x) + + #define INT32_FROM_LE(x) ((int32_t)(x)) + #define INT32_FROM_BE(x) INT32_SWAP(x) + + #define UINT32_FROM_LE(x) ((uint32_t)(x)) + #define UINT32_FROM_BE(x) UINT32_SWAP(x) + + #define UINT32_TO_LE(x) ((uint32_t)(x)) + #define UINT32_TO_BE(x) UINT32_SWAP(x) +#endif + +#endif diff --git a/src/polypcore/esound.h b/src/polypcore/esound.h new file mode 100644 index 00000000..9c507ef9 --- /dev/null +++ b/src/polypcore/esound.h @@ -0,0 +1,209 @@ +#ifndef fooesoundhfoo +#define fooesoundhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* Most of the following is blatantly stolen from esound. */ + + +/* path and name of the default EsounD domain socket */ +#define ESD_UNIX_SOCKET_DIR "/tmp/.esd" +#define ESD_UNIX_SOCKET_NAME "/tmp/.esd/socket" + +/* length of the audio buffer size */ +#define ESD_BUF_SIZE (4 * 1024) +/* maximum size we can write(). Otherwise we might overflow */ +#define ESD_MAX_WRITE_SIZE (21 * 4096) + +/* length of the authorization key, octets */ +#define ESD_KEY_LEN (16) + +/* default port for the EsounD server */ +#define ESD_DEFAULT_PORT (16001) + +/* default sample rate for the EsounD server */ +#define ESD_DEFAULT_RATE (44100) + +/* maximum length of a stream/sample name */ +#define ESD_NAME_MAX (128) + +/* a magic number to identify the relative endianness of a client */ +#define ESD_ENDIAN_KEY ((uint32_t) (('E' << 24) + ('N' << 16) + ('D' << 8) + ('N'))) + +#define ESD_VOLUME_BASE (256) + + +/*************************************/ +/* what can we do to/with the EsounD */ +enum esd_proto { + ESD_PROTO_CONNECT, /* implied on inital client connection */ + + /* pseudo "security" functionality */ + ESD_PROTO_LOCK, /* disable "foreign" client connections */ + ESD_PROTO_UNLOCK, /* enable "foreign" client connections */ + + /* stream functionality: play, record, monitor */ + ESD_PROTO_STREAM_PLAY, /* play all following data as a stream */ + ESD_PROTO_STREAM_REC, /* record data from card as a stream */ + ESD_PROTO_STREAM_MON, /* send mixed buffer output as a stream */ + + /* sample functionality: cache, free, play, loop, EOL, kill */ + ESD_PROTO_SAMPLE_CACHE, /* cache a sample in the server */ + ESD_PROTO_SAMPLE_FREE, /* release a sample in the server */ + ESD_PROTO_SAMPLE_PLAY, /* play a cached sample */ + ESD_PROTO_SAMPLE_LOOP, /* loop a cached sample, til eoloop */ + ESD_PROTO_SAMPLE_STOP, /* stop a looping sample when done */ + ESD_PROTO_SAMPLE_KILL, /* stop the looping sample immed. */ + + /* free and reclaim /dev/dsp functionality */ + ESD_PROTO_STANDBY, /* release /dev/dsp and ignore all data */ + ESD_PROTO_RESUME, /* reclaim /dev/dsp and play sounds again */ + + /* TODO: move these to a more logical place. NOTE: will break the protocol */ + ESD_PROTO_SAMPLE_GETID, /* get the ID for an already-cached sample */ + ESD_PROTO_STREAM_FILT, /* filter mixed buffer output as a stream */ + + /* esd remote management */ + ESD_PROTO_SERVER_INFO, /* get server info (ver, sample rate, format) */ + ESD_PROTO_ALL_INFO, /* get all info (server info, players, samples) */ + ESD_PROTO_SUBSCRIBE, /* track new and removed players and samples */ + ESD_PROTO_UNSUBSCRIBE, /* stop tracking updates */ + + /* esd remote control */ + ESD_PROTO_STREAM_PAN, /* set stream panning */ + ESD_PROTO_SAMPLE_PAN, /* set default sample panning */ + + /* esd status */ + ESD_PROTO_STANDBY_MODE, /* see if server is in standby, autostandby, etc */ + + /* esd latency */ + ESD_PROTO_LATENCY, /* retrieve latency between write()'s and output */ + + ESD_PROTO_MAX /* for bounds checking */ +}; + +/******************/ +/* The EsounD api */ + +/* the properties of a sound buffer are logically or'd */ + +/* bits of stream/sample data */ +#define ESD_MASK_BITS ( 0x000F ) +#define ESD_BITS8 ( 0x0000 ) +#define ESD_BITS16 ( 0x0001 ) + +/* how many interleaved channels of data */ +#define ESD_MASK_CHAN ( 0x00F0 ) +#define ESD_MONO ( 0x0010 ) +#define ESD_STEREO ( 0x0020 ) + +/* whether it's a stream or a sample */ +#define ESD_MASK_MODE ( 0x0F00 ) +#define ESD_STREAM ( 0x0000 ) +#define ESD_SAMPLE ( 0x0100 ) +#define ESD_ADPCM ( 0x0200 ) /* TODO: anyone up for this? =P */ + +/* the function of the stream/sample, and common functions */ +#define ESD_MASK_FUNC ( 0xF000 ) +#define ESD_PLAY ( 0x1000 ) +/* functions for streams only */ +#define ESD_MONITOR ( 0x0000 ) +#define ESD_RECORD ( 0x2000 ) +/* functions for samples only */ +#define ESD_STOP ( 0x0000 ) +#define ESD_LOOP ( 0x2000 ) + +typedef int esd_format_t; +typedef int esd_proto_t; + +/*******************************************************************/ +/* esdmgr.c - functions to implement a "sound manager" for esd */ + +/* structures to retrieve information about streams/samples from the server */ +typedef struct esd_server_info { + + int version; /* server version encoded as an int */ + esd_format_t format; /* magic int with the format info */ + int rate; /* sample rate */ + +} esd_server_info_t; + +typedef struct esd_player_info { + + struct esd_player_info *next; /* point to next entry in list */ + esd_server_info_t *server; /* the server that contains this stream */ + + int source_id; /* either a stream fd or sample id */ + char name[ ESD_NAME_MAX ]; /* name of stream for remote control */ + int rate; /* sample rate */ + int left_vol_scale; /* volume scaling */ + int right_vol_scale; + + esd_format_t format; /* magic int with the format info */ + +} esd_player_info_t; + +typedef struct esd_sample_info { + + struct esd_sample_info *next; /* point to next entry in list */ + esd_server_info_t *server; /* the server that contains this sample */ + + int sample_id; /* either a stream fd or sample id */ + char name[ ESD_NAME_MAX ]; /* name of stream for remote control */ + int rate; /* sample rate */ + int left_vol_scale; /* volume scaling */ + int right_vol_scale; + + esd_format_t format; /* magic int with the format info */ + int length; /* total buffer length */ + +} esd_sample_info_t; + +typedef struct esd_info { + + esd_server_info_t *server; + esd_player_info_t *player_list; + esd_sample_info_t *sample_list; + +} esd_info_t; + +enum esd_standby_mode { + ESM_ERROR, ESM_ON_STANDBY, ESM_ON_AUTOSTANDBY, ESM_RUNNING +}; +typedef int esd_standby_mode_t; + +enum esd_client_state { + ESD_STREAMING_DATA, /* data from here on is streamed data */ + ESD_CACHING_SAMPLE, /* midway through caching a sample */ + ESD_NEEDS_REQDATA, /* more data needed to complere request */ + ESD_NEXT_REQUEST, /* proceed to next request */ + ESD_CLIENT_STATE_MAX /* place holder */ +}; +typedef int esd_client_state_t; + +/* the endian key is transferred in binary, if it's read into int, */ +/* and matches ESD_ENDIAN_KEY (ENDN), then the endianness of the */ +/* server and the client match; if it's SWAP_ENDIAN_KEY, swap data */ +#define ESD_SWAP_ENDIAN_KEY (UINT32_SWAP(ESD_ENDIAN_KEY)) + + +#endif diff --git a/src/polypcore/g711.c b/src/polypcore/g711.c new file mode 100644 index 00000000..55a82396 --- /dev/null +++ b/src/polypcore/g711.c @@ -0,0 +1,2531 @@ +/* + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * g711.c + * + * u-law, A-law and linear PCM conversions. + */ + +/* + * December 30, 1994: + * Functions linear2alaw, linear2ulaw have been updated to correctly + * convert unquantized 16 bit values. + * Tables for direct u- to A-law and A- to u-law conversions have been + * corrected. + * Borge Lindberg, Center for PersonKommunikation, Aalborg University. + * bli@cpk.auc.dk + * + */ + +#include "g711.h" + +#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ +#define QUANT_MASK (0xf) /* Quantization field mask. */ +#define NSEGS (8) /* Number of A-law segments. */ +#define SEG_SHIFT (4) /* Left shift for segment number. */ +#define SEG_MASK (0x70) /* Segment field mask. */ + +#if !defined(FAST_ALAW_CONVERSION) || !defined(FAST_ULAW_CONVERSION) +static int16_t seg_aend[8] = {0x1F, 0x3F, 0x7F, 0xFF, + 0x1FF, 0x3FF, 0x7FF, 0xFFF}; +static int16_t seg_uend[8] = {0x3F, 0x7F, 0xFF, 0x1FF, + 0x3FF, 0x7FF, 0xFFF, 0x1FFF}; + +static int16_t search( + int16_t val, + int16_t *table, + int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (val <= *table++) + return (i); + } + return (size); +} +#endif /* !FAST_*_CONVERSION */ + +#ifndef FAST_ALAW_CONVERSION +/* + * linear2alaw() accepts an 13-bit signed integer and encodes it as A-law data + * stored in a unsigned char. This function should only be called with + * the data shifted such that it only contains information in the lower + * 13-bits. + * + * Linear Input Code Compressed Code + * ------------------------ --------------- + * 0000000wxyza 000wxyz + * 0000001wxyza 001wxyz + * 000001wxyzab 010wxyz + * 00001wxyzabc 011wxyz + * 0001wxyzabcd 100wxyz + * 001wxyzabcde 101wxyz + * 01wxyzabcdef 110wxyz + * 1wxyzabcdefg 111wxyz + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ +unsigned char st_13linear2alaw( + int16_t pcm_val) /* 2's complement (13-bit range) */ +{ + int16_t mask; + short seg; + unsigned char aval; + + /* Have calling software do it since its already doing a shift + * from 32-bits down to 16-bits. + */ + /* pcm_val = pcm_val >> 3; */ + + /* A-law using even bit inversion */ + if (pcm_val >= 0) { + mask = 0xD5; /* sign (7th) bit = 1 */ + } else { + mask = 0x55; /* sign bit = 0 */ + pcm_val = -pcm_val - 1; + } + + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_aend, 8); + + /* Combine the sign, segment, and quantization bits. */ + + if (seg >= 8) /* out of range, return maximum value. */ + return (unsigned char) (0x7F ^ mask); + else { + aval = (unsigned char) seg << SEG_SHIFT; + if (seg < 2) + aval |= (pcm_val >> 1) & QUANT_MASK; + else + aval |= (pcm_val >> seg) & QUANT_MASK; + return (aval ^ mask); + } +} + +/* + * alaw2linear() - Convert an A-law value to 16-bit signed linear PCM + * + */ +int16_t st_alaw2linear16( + unsigned char a_val) +{ + int16_t t; + int16_t seg; + + a_val ^= 0x55; + + t = (a_val & QUANT_MASK) << 4; + seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT; + switch (seg) { + case 0: + t += 8; + break; + case 1: + t += 0x108; + break; + default: + t += 0x108; + t <<= seg - 1; + } + return ((a_val & SIGN_BIT) ? t : -t); +} +#endif /* !FAST_ALAW_CONVERSION */ + +#define BIAS (0x84) /* Bias for linear code. */ +#define CLIP 8159 + +#ifndef FAST_ULAW_CONVERSION +/* + * linear2ulaw() accepts a 14-bit signed integer and encodes it as u-law data + * stored in a unsigned char. This function should only be called with + * the data shifted such that it only contains information in the lower + * 14-bits. + * + * In order to simplify the encoding process, the original linear magnitude + * is biased by adding 33 which shifts the encoding range from (0 - 8158) to + * (33 - 8191). The result can be seen in the following encoding table: + * + * Biased Linear Input Code Compressed Code + * ------------------------ --------------- + * 00000001wxyza 000wxyz + * 0000001wxyzab 001wxyz + * 000001wxyzabc 010wxyz + * 00001wxyzabcd 011wxyz + * 0001wxyzabcde 100wxyz + * 001wxyzabcdef 101wxyz + * 01wxyzabcdefg 110wxyz + * 1wxyzabcdefgh 111wxyz + * + * Each biased linear code has a leading 1 which identifies the segment + * number. The value of the segment number is equal to 7 minus the number + * of leading 0's. The quantization interval is directly available as the + * four bits wxyz. * The trailing bits (a - h) are ignored. + * + * Ordinarily the complement of the resulting code word is used for + * transmission, and so the code word is complemented before it is returned. + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ +unsigned char st_14linear2ulaw( + int16_t pcm_val) /* 2's complement (14-bit range) */ +{ + int16_t mask; + int16_t seg; + unsigned char uval; + + /* Have calling software do it since its already doing a shift + * from 32-bits down to 16-bits. + */ + /* pcm_val = pcm_val >> 2; */ + + /* u-law inverts all bits */ + /* Get the sign and the magnitude of the value. */ + if (pcm_val < 0) { + pcm_val = -pcm_val; + mask = 0x7F; + } else { + mask = 0xFF; + } + if ( pcm_val > CLIP ) pcm_val = CLIP; /* clip the magnitude */ + pcm_val += (BIAS >> 2); + + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_uend, 8); + + /* + * Combine the sign, segment, quantization bits; + * and complement the code word. + */ + if (seg >= 8) /* out of range, return maximum value. */ + return (unsigned char) (0x7F ^ mask); + else { + uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF); + return (uval ^ mask); + } + +} + +/* + * ulaw2linear() - Convert a u-law value to 16-bit linear PCM + * + * First, a biased linear code is derived from the code word. An unbiased + * output can then be obtained by subtracting 33 from the biased code. + * + * Note that this function expects to be passed the complement of the + * original code word. This is in keeping with ISDN conventions. + */ +int16_t st_ulaw2linear16( + unsigned char u_val) +{ + int16_t t; + + /* Complement to obtain normal u-law value. */ + u_val = ~u_val; + + /* + * Extract and bias the quantization bits. Then + * shift up by the segment number and subtract out the bias. + */ + t = ((u_val & QUANT_MASK) << 3) + BIAS; + t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; + + return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); +} +#endif /* !FAST_ULAW_CONVERSION */ + +#ifdef FAST_ALAW_CONVERSION + +int16_t _st_alaw2linear16[256] = { + -5504, -5248, -6016, -5760, -4480, -4224, -4992, + -4736, -7552, -7296, -8064, -7808, -6528, -6272, + -7040, -6784, -2752, -2624, -3008, -2880, -2240, + -2112, -2496, -2368, -3776, -3648, -4032, -3904, + -3264, -3136, -3520, -3392, -22016, -20992, -24064, + -23040, -17920, -16896, -19968, -18944, -30208, -29184, + -32256, -31232, -26112, -25088, -28160, -27136, -11008, + -10496, -12032, -11520, -8960, -8448, -9984, -9472, + -15104, -14592, -16128, -15616, -13056, -12544, -14080, + -13568, -344, -328, -376, -360, -280, -264, + -312, -296, -472, -456, -504, -488, -408, + -392, -440, -424, -88, -72, -120, -104, + -24, -8, -56, -40, -216, -200, -248, + -232, -152, -136, -184, -168, -1376, -1312, + -1504, -1440, -1120, -1056, -1248, -1184, -1888, + -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, + -592, -944, -912, -1008, -976, -816, -784, + -880, -848, 5504, 5248, 6016, 5760, 4480, + 4224, 4992, 4736, 7552, 7296, 8064, 7808, + 6528, 6272, 7040, 6784, 2752, 2624, 3008, + 2880, 2240, 2112, 2496, 2368, 3776, 3648, + 4032, 3904, 3264, 3136, 3520, 3392, 22016, + 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, + 27136, 11008, 10496, 12032, 11520, 8960, 8448, + 9984, 9472, 15104, 14592, 16128, 15616, 13056, + 12544, 14080, 13568, 344, 328, 376, 360, + 280, 264, 312, 296, 472, 456, 504, + 488, 408, 392, 440, 424, 88, 72, + 120, 104, 24, 8, 56, 40, 216, + 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, + 1184, 1888, 1824, 2016, 1952, 1632, 1568, + 1760, 1696, 688, 656, 752, 720, 560, + 528, 624, 592, 944, 912, 1008, 976, + 816, 784, 880, 848 +}; + +uint8_t _st_13linear2alaw[0x2000] = { + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, + 0x6b, 0x6b, 0x6b, 0x6b, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, + 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x6e, 0x6e, 0x6e, 0x6e, + 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, + 0x6d, 0x6d, 0x6d, 0x6d, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x60, 0x60, 0x60, 0x60, + 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, + 0x67, 0x67, 0x67, 0x67, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, + 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x7a, 0x7a, 0x7a, 0x7a, + 0x7b, 0x7b, 0x7b, 0x7b, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7c, 0x7c, 0x7c, 0x7c, + 0x7d, 0x7d, 0x7d, 0x7d, 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x73, + 0x70, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x71, 0x76, 0x76, 0x76, 0x76, + 0x77, 0x77, 0x77, 0x77, 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x75, + 0x4a, 0x4a, 0x4b, 0x4b, 0x48, 0x48, 0x49, 0x49, 0x4e, 0x4e, 0x4f, 0x4f, + 0x4c, 0x4c, 0x4d, 0x4d, 0x42, 0x42, 0x43, 0x43, 0x40, 0x40, 0x41, 0x41, + 0x46, 0x46, 0x47, 0x47, 0x44, 0x44, 0x45, 0x45, 0x5a, 0x5a, 0x5b, 0x5b, + 0x58, 0x58, 0x59, 0x59, 0x5e, 0x5e, 0x5f, 0x5f, 0x5c, 0x5c, 0x5d, 0x5d, + 0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51, 0x56, 0x56, 0x57, 0x57, + 0x54, 0x54, 0x55, 0x55, 0xd5, 0xd5, 0xd4, 0xd4, 0xd7, 0xd7, 0xd6, 0xd6, + 0xd1, 0xd1, 0xd0, 0xd0, 0xd3, 0xd3, 0xd2, 0xd2, 0xdd, 0xdd, 0xdc, 0xdc, + 0xdf, 0xdf, 0xde, 0xde, 0xd9, 0xd9, 0xd8, 0xd8, 0xdb, 0xdb, 0xda, 0xda, + 0xc5, 0xc5, 0xc4, 0xc4, 0xc7, 0xc7, 0xc6, 0xc6, 0xc1, 0xc1, 0xc0, 0xc0, + 0xc3, 0xc3, 0xc2, 0xc2, 0xcd, 0xcd, 0xcc, 0xcc, 0xcf, 0xcf, 0xce, 0xce, + 0xc9, 0xc9, 0xc8, 0xc8, 0xcb, 0xcb, 0xca, 0xca, 0xf5, 0xf5, 0xf5, 0xf5, + 0xf4, 0xf4, 0xf4, 0xf4, 0xf7, 0xf7, 0xf7, 0xf7, 0xf6, 0xf6, 0xf6, 0xf6, + 0xf1, 0xf1, 0xf1, 0xf1, 0xf0, 0xf0, 0xf0, 0xf0, 0xf3, 0xf3, 0xf3, 0xf3, + 0xf2, 0xf2, 0xf2, 0xf2, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xf9, 0xf9, 0xf9, 0xf9, + 0xf8, 0xf8, 0xf8, 0xf8, 0xfb, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xfa, + 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4, + 0xe4, 0xe4, 0xe4, 0xe4, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, + 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe1, 0xe1, 0xe1, 0xe1, + 0xe1, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, + 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, + 0xe2, 0xe2, 0xe2, 0xe2, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, + 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xef, 0xef, 0xef, 0xef, + 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, + 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, + 0xe8, 0xe8, 0xe8, 0xe8, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa +}; + +#endif /* FAST_ALAW_CONVERSION */ + +#ifdef FAST_ULAW_CONVERSION + +int16_t _st_ulaw2linear16[256] = { + -32124, -31100, -30076, -29052, -28028, -27004, -25980, + -24956, -23932, -22908, -21884, -20860, -19836, -18812, + -17788, -16764, -15996, -15484, -14972, -14460, -13948, + -13436, -12924, -12412, -11900, -11388, -10876, -10364, + -9852, -9340, -8828, -8316, -7932, -7676, -7420, + -7164, -6908, -6652, -6396, -6140, -5884, -5628, + -5372, -5116, -4860, -4604, -4348, -4092, -3900, + -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, + -1980, -1884, -1820, -1756, -1692, -1628, -1564, + -1500, -1436, -1372, -1308, -1244, -1180, -1116, + -1052, -988, -924, -876, -844, -812, -780, + -748, -716, -684, -652, -620, -588, -556, + -524, -492, -460, -428, -396, -372, -356, + -340, -324, -308, -292, -276, -260, -244, + -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, + -64, -56, -48, -40, -32, -24, -16, + -8, 0, 32124, 31100, 30076, 29052, 28028, + 27004, 25980, 24956, 23932, 22908, 21884, 20860, + 19836, 18812, 17788, 16764, 15996, 15484, 14972, + 14460, 13948, 13436, 12924, 12412, 11900, 11388, + 10876, 10364, 9852, 9340, 8828, 8316, 7932, + 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, + 4092, 3900, 3772, 3644, 3516, 3388, 3260, + 3132, 3004, 2876, 2748, 2620, 2492, 2364, + 2236, 2108, 1980, 1884, 1820, 1756, 1692, + 1628, 1564, 1500, 1436, 1372, 1308, 1244, + 1180, 1116, 1052, 988, 924, 876, 844, + 812, 780, 748, 716, 684, 652, 620, + 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, + 260, 244, 228, 212, 196, 180, 164, + 148, 132, 120, 112, 104, 96, 88, + 80, 72, 64, 56, 48, 40, 32, + 24, 16, 8, 0 +}; + +uint8_t _st_14linear2ulaw[0x4000] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, + 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, + 0x43, 0x43, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, + 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, + 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, + 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, + 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, + 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, + 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, + 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, + 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, + 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, + 0x52, 0x52, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, + 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x57, 0x57, + 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a, 0x5a, + 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, + 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, + 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x60, 0x60, + 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x62, 0x63, 0x63, + 0x63, 0x63, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, + 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, + 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, + 0x6f, 0x6f, 0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x74, 0x74, + 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a, + 0x7b, 0x7b, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0xff, 0xfe, 0xfe, 0xfd, + 0xfd, 0xfc, 0xfc, 0xfb, 0xfb, 0xfa, 0xfa, 0xf9, 0xf9, 0xf8, 0xf8, 0xf7, + 0xf7, 0xf6, 0xf6, 0xf5, 0xf5, 0xf4, 0xf4, 0xf3, 0xf3, 0xf2, 0xf2, 0xf1, + 0xf1, 0xf0, 0xf0, 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xed, + 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xeb, 0xeb, 0xeb, 0xeb, 0xea, + 0xea, 0xea, 0xea, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, + 0xe4, 0xe4, 0xe4, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, 0xe1, + 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, + 0xdf, 0xdf, 0xdf, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, + 0xdc, 0xdc, 0xdc, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xda, + 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, + 0xd9, 0xd9, 0xd9, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd7, + 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, + 0xd6, 0xd6, 0xd6, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd4, + 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, + 0xd3, 0xd3, 0xd3, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd1, + 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, + 0xd0, 0xd0, 0xd0, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, + 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xce, 0xce, 0xce, 0xce, 0xce, + 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, + 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xca, + 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, + 0xca, 0xca, 0xca, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, + 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, + 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc7, + 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, + 0xc7, 0xc7, 0xc7, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, + 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, + 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc1, + 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, + 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, + 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80 +}; + +#endif /* FAST_ULAW_CONVERSION */ + +/* The following code was used to generate the lookup tables */ +#if 0 +int main() +{ + int x, y, find2a = 0; + + y = 0; + printf("int16_t _st_alaw2linear16[256] = {\n "); + for (x = 0; x < 256; x++) + { + printf("%8d,", st_alaw2linear16(x)); + y++; + if (y == 7) + { + y = 0; + printf("\n "); + } + } + + printf("\n};\n\nuint8_t _st_13linear2alaw[0x2000] = {\n "); + y = 0; + for (x = 0; x < 0x2000; x++) + { + printf(" 0x%02x,", st_13linear2alaw((-0x1000)+x)); + y++; + if (y == 12) + { + y = 0; + printf("\n "); + } + } + + printf("\n};\n\nint16_t _st_ulaw2linear16[256] = {\n "); + y = 0; + for (x = 0; x < 256; x++) + { + printf("%8d,", st_ulaw2linear16(x)); + y++; + if (y == 7) + { + y = 0; + printf("\n "); + } + } + + printf("\n};\n\nuint8_t _st_14linear2ulaw[0x4000] = {\n "); + y = 0; + for (x = 0; x < 0x4000; x++) + { + printf(" 0x%02x,", st_14linear2ulaw((-0x2000)+x)); + y++; + if (y == 12) + { + y = 0; + printf("\n "); + } + } + printf("\n};\n"); + +} +#endif + +/* The following is not used by SoX but kept for reference */ +#if 0 +/* copy from CCITT G.711 specifications */ +unsigned char _u2a[128] = { /* u- to A-law conversions */ + 1, 1, 2, 2, 3, 3, 4, 4, + 5, 5, 6, 6, 7, 7, 8, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 27, 29, 31, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, + 46, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, +/* corrected: + 81, 82, 83, 84, 85, 86, 87, 88, + should be: */ + 80, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128}; + +unsigned char _a2u[128] = { /* A- to u-law conversions */ + 1, 3, 5, 7, 9, 11, 13, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 32, 33, 33, 34, 34, 35, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 48, 49, 49, + 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 64, + 65, 66, 67, 68, 69, 70, 71, 72, +/* corrected: + 73, 74, 75, 76, 77, 78, 79, 79, + should be: */ + 73, 74, 75, 76, 77, 78, 79, 80, + + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127}; + +/* A-law to u-law conversion */ +unsigned char st_alaw2ulaw( + unsigned char aval) +{ + aval &= 0xff; + return (unsigned char) ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) : + (0x7F ^ _a2u[aval ^ 0x55])); +} + +/* u-law to A-law conversion */ +unsigned char st_ulaw2alaw( + unsigned char uval) +{ + uval &= 0xff; + return (unsigned char) ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) : + (unsigned char) (0x55 ^ (_u2a[0x7F ^ uval] - 1))); +} +#endif diff --git a/src/polypcore/g711.h b/src/polypcore/g711.h new file mode 100644 index 00000000..97cedf81 --- /dev/null +++ b/src/polypcore/g711.h @@ -0,0 +1,40 @@ +#ifndef foog711hfoo +#define foog711hfoo + +/* g711.h - include for G711 u-law and a-law conversion routines +** +** Copyright (C) 2001 Chris Bagwell +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +*/ + +/** Copied from sox -- Lennart Poettring*/ + +#include + +#ifdef FAST_ALAW_CONVERSION +extern uint8_t _st_13linear2alaw[0x2000]; +extern int16_t _st_alaw2linear16[256]; +#define st_13linear2alaw(sw) (_st_13linear2alaw[(sw + 0x1000)]) +#define st_alaw2linear16(uc) (_st_alaw2linear16[uc]) +#else +unsigned char st_13linear2alaw(int16_t pcm_val); +int16_t st_alaw2linear16(unsigned char); +#endif + +#ifdef FAST_ULAW_CONVERSION +extern uint8_t _st_14linear2ulaw[0x4000]; +extern int16_t _st_ulaw2linear16[256]; +#define st_14linear2ulaw(sw) (_st_14linear2ulaw[(sw + 0x2000)]) +#define st_ulaw2linear16(uc) (_st_ulaw2linear16[uc]) +#else +unsigned char st_14linear2ulaw(int16_t pcm_val); +int16_t st_ulaw2linear16(unsigned char); +#endif + +#endif diff --git a/src/polypcore/gccmacro.h b/src/polypcore/gccmacro.h new file mode 100644 index 00000000..9e212f2e --- /dev/null +++ b/src/polypcore/gccmacro.h @@ -0,0 +1,53 @@ +#ifndef foogccmacrohfoo +#define foogccmacrohfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef __GNUC__ +#define PA_GCC_PRINTF_ATTR(a,b) __attribute__ ((format (printf, a, b))) +#else +/** If we're in GNU C, use some magic for detecting invalid format strings */ +#define PA_GCC_PRINTF_ATTR(a,b) +#endif + +#if defined(__GNUC__) && (__GNUC__ >= 4) +#define PA_GCC_SENTINEL __attribute__ ((sentinel)) +#else +/** Macro for usage of GCC's sentinel compilation warnings */ +#define PA_GCC_SENTINEL +#endif + +#ifdef __GNUC__ +#define PA_GCC_NORETURN __attribute__((noreturn)) +#else +/** Macro for no-return functions */ +#define PA_GCC_NORETURN +#endif + +#ifdef __GNUC__ +#define PA_GCC_UNUSED __attribute__ ((unused)) +#else +/** Macro for not used parameter */ +#define PA_GCC_UNUSED +#endif + +#endif diff --git a/src/polypcore/hashmap.c b/src/polypcore/hashmap.c new file mode 100644 index 00000000..a37decb8 --- /dev/null +++ b/src/polypcore/hashmap.c @@ -0,0 +1,194 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "hashmap.h" +#include "idxset.h" +#include "xmalloc.h" +#include "log.h" + +#define BUCKETS 1023 + +struct hashmap_entry { + struct hashmap_entry *next, *previous, *bucket_next, *bucket_previous; + unsigned hash; + const void *key; + void *value; +}; + +struct pa_hashmap { + unsigned size; + struct hashmap_entry **data; + struct hashmap_entry *first_entry; + + unsigned n_entries; + unsigned (*hash_func) (const void *p); + int (*compare_func) (const void*a, const void*b); +}; + +pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { + pa_hashmap *h; + h = pa_xmalloc(sizeof(pa_hashmap)); + h->data = pa_xmalloc0(sizeof(struct hashmap_entry*)*(h->size = BUCKETS)); + h->first_entry = NULL; + h->n_entries = 0; + h->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; + h->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; + return h; +} + +static void remove(pa_hashmap *h, struct hashmap_entry *e) { + assert(e); + + if (e->next) + e->next->previous = e->previous; + if (e->previous) + e->previous->next = e->next; + else + h->first_entry = e->next; + + if (e->bucket_next) + e->bucket_next->bucket_previous = e->bucket_previous; + if (e->bucket_previous) + e->bucket_previous->bucket_next = e->bucket_next; + else { + assert(e->hash < h->size); + h->data[e->hash] = e->bucket_next; + } + + pa_xfree(e); + h->n_entries--; +} + +void pa_hashmap_free(pa_hashmap*h, void (*free_func)(void *p, void *userdata), void *userdata) { + assert(h); + + while (h->first_entry) { + if (free_func) + free_func(h->first_entry->value, userdata); + remove(h, h->first_entry); + } + + pa_xfree(h->data); + pa_xfree(h); +} + +static struct hashmap_entry *get(pa_hashmap *h, unsigned hash, const void *key) { + struct hashmap_entry *e; + assert(h && hash < h->size); + + for (e = h->data[hash]; e; e = e->bucket_next) + if (h->compare_func(e->key, key) == 0) + return e; + + return NULL; +} + +int pa_hashmap_put(pa_hashmap *h, const void *key, void *value) { + struct hashmap_entry *e; + unsigned hash; + assert(h); + + hash = h->hash_func(key) % h->size; + + if ((e = get(h, hash, key))) + return -1; + + e = pa_xmalloc(sizeof(struct hashmap_entry)); + e->hash = hash; + e->key = key; + e->value = value; + + e->previous = NULL; + e->next = h->first_entry; + if (h->first_entry) + h->first_entry->previous = e; + h->first_entry = e; + + e->bucket_previous = NULL; + e->bucket_next = h->data[hash]; + if (h->data[hash]) + h->data[hash]->bucket_previous = e; + h->data[hash] = e; + + h->n_entries ++; + return 0; +} + +void* pa_hashmap_get(pa_hashmap *h, const void *key) { + unsigned hash; + struct hashmap_entry *e; + assert(h && key); + + hash = h->hash_func(key) % h->size; + + if (!(e = get(h, hash, key))) + return NULL; + + return e->value; +} + +void* pa_hashmap_remove(pa_hashmap *h, const void *key) { + struct hashmap_entry *e; + unsigned hash; + void *data; + assert(h && key); + + hash = h->hash_func(key) % h->size; + + if (!(e = get(h, hash, key))) + return NULL; + + data = e->value; + remove(h, e); + return data; +} + +unsigned pa_hashmap_size(pa_hashmap *h) { + return h->n_entries; +} + +void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void **key) { + assert(h && state); + + if (!*state) + *state = h->first_entry; + else + *state = ((struct hashmap_entry*) *state)->next; + + if (!*state) { + if (key) + *key = NULL; + return NULL; + } + + if (key) + *key = ((struct hashmap_entry*) *state)->key; + + return ((struct hashmap_entry*) *state)->value; +} diff --git a/src/polypcore/hashmap.h b/src/polypcore/hashmap.h new file mode 100644 index 00000000..14f82705 --- /dev/null +++ b/src/polypcore/hashmap.h @@ -0,0 +1,53 @@ +#ifndef foohashmaphfoo +#define foohashmaphfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* Simple Implementation of a hash table. Memory management is the + * user's job. It's a good idea to have the key pointer point to a + * string in the value data. */ + +typedef struct pa_hashmap pa_hashmap; + +/* Create a new hashmap. Use the specified functions for hashing and comparing objects in the map */ +pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); + +/* Free the hash table. Calls the specified function for every value in the table. The function may be NULL */ +void pa_hashmap_free(pa_hashmap*, void (*free_func)(void *p, void *userdata), void *userdata); + +/* Returns non-zero when the entry already exists */ +int pa_hashmap_put(pa_hashmap *h, const void *key, void *value); +void* pa_hashmap_get(pa_hashmap *h, const void *key); + +/* Returns the data of the entry while removing */ +void* pa_hashmap_remove(pa_hashmap *h, const void *key); + +unsigned pa_hashmap_size(pa_hashmap *h); + +/* May be used to iterate through the hashmap. Initially the opaque + pointer *state has to be set to NULL. The hashmap may not be + modified during iteration. The key of the entry is returned in + *key, if key is non-NULL. After the last entry in the hashmap NULL + is returned. */ +void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void**key); + +#endif diff --git a/src/polypcore/howl-wrap.c b/src/polypcore/howl-wrap.c new file mode 100644 index 00000000..77d096ac --- /dev/null +++ b/src/polypcore/howl-wrap.c @@ -0,0 +1,116 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "howl-wrap.h" +#include "log.h" +#include "xmalloc.h" +#include "props.h" + +#define HOWL_PROPERTY "howl" + +pa_howl_wrapper { + pa_core *core; + int ref; + + pa_io_event *io_event; + sw_discovery discovery; + +}; + +static void howl_io_event(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata) { + pa_howl_wrapper *w = userdata; + assert(m && e && fd >= 0 && w && w->ref >= 1); + + if (f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) + goto fail; + + if (sw_discovery_read_socket(w->discovery) != SW_OKAY) + goto fail; + + return; + +fail: + pa_log(__FILE__": howl connection died.\n"); + w->core->mainloop->io_free(w->io_event); + w->io_event = NULL; +} + +static pa_howl_wrapper* howl_wrapper_new(pa_core *c) { + pa_howl_wrapper *h; + sw_discovery session; + assert(c); + + if (sw_discovery_init(&session) != SW_OKAY) { + pa_log("sw_discovery_init() failed.\n"); + return NULL; + } + + h = pa_xmalloc(sizeof(pa_howl_wrapper)); + h->core = c; + h->ref = 1; + h->discovery = session; + + h->io_event = c->mainloop->io_new(c->mainloop, sw_discovery_socket(session), PA_IO_EVENT_INPUT, howl_io_event, h); + + return h; +} + +static void howl_wrapper_free(pa_howl_wrapper *h) { + assert(h); + + sw_discovery_fina(h->discovery); + + if (h->io_event) + h->core->mainloop->io_free(h->io_event); + + pa_xfree(h); +} + +pa_howl_wrapper* pa_howl_wrapper_get(pa_core *c) { + pa_howl_wrapper *h; + assert(c); + + if ((h = pa_property_get(c, HOWL_PROPERTY))) + return pa_howl_wrapper_ref(h); + + return howl_wrapper_new(c); +} + +pa_howl_wrapper* pa_howl_wrapper_ref(pa_howl_wrapper *h) { + assert(h && h->ref >= 1); + h->ref++; + return h; +} + +void pa_howl_wrapper_unref(pa_howl_wrapper *h) { + assert(h && h->ref >= 1); + if (!(--h->ref)) + howl_wrapper_free(h); +} + +sw_discovery pa_howl_wrapper_get_discovery(pa_howl_wrapper *h) { + assert(h && h->ref >= 1); + + return h->discovery; +} + diff --git a/src/polypcore/howl-wrap.h b/src/polypcore/howl-wrap.h new file mode 100644 index 00000000..a670b082 --- /dev/null +++ b/src/polypcore/howl-wrap.h @@ -0,0 +1,37 @@ +#ifndef foohowlwrapperhfoo +#define foohowlwrapperhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "core.h" + +pa_howl_wrapper; + +pa_howl_wrapper* pa_howl_wrapper_get(pa_core *c); +pa_howl_wrapper* pa_howl_wrapper_ref(pa_howl_wrapper *h); +void pa_howl_wrapper_unref(pa_howl_wrapper *h); + +sw_discovery pa_howl_wrapper_get_discovery(pa_howl_wrapper *h); + +#endif diff --git a/src/polypcore/idxset.c b/src/polypcore/idxset.c new file mode 100644 index 00000000..409d1fab --- /dev/null +++ b/src/polypcore/idxset.c @@ -0,0 +1,390 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "idxset.h" +#include "xmalloc.h" + +typedef struct idxset_entry { + void *data; + uint32_t index; + unsigned hash_value; + + struct idxset_entry *hash_prev, *hash_next; + struct idxset_entry* iterate_prev, *iterate_next; +} idxset_entry; + +struct pa_idxset { + unsigned (*hash_func) (const void *p); + int (*compare_func)(const void *a, const void *b); + + unsigned hash_table_size, n_entries; + idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail; + uint32_t index, start_index, array_size; +}; + +unsigned pa_idxset_string_hash_func(const void *p) { + unsigned hash = 0; + const char *c; + + for (c = p; *c; c++) + hash = 31 * hash + *c; + + return hash; +} + +int pa_idxset_string_compare_func(const void *a, const void *b) { + return strcmp(a, b); +} + +unsigned pa_idxset_trivial_hash_func(const void *p) { + return (unsigned) p; +} + +int pa_idxset_trivial_compare_func(const void *a, const void *b) { + return a != b; +} + +pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { + pa_idxset *s; + + s = pa_xnew(pa_idxset, 1); + s->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; + s->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; + s->hash_table_size = 1023; + s->hash_table = pa_xmalloc0(sizeof(idxset_entry*)*s->hash_table_size); + s->array = NULL; + s->array_size = 0; + s->index = 0; + s->start_index = 0; + s->n_entries = 0; + + s->iterate_list_head = s->iterate_list_tail = NULL; + + return s; +} + +void pa_idxset_free(pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata) { + assert(s); + + while (s->iterate_list_head) { + idxset_entry *e = s->iterate_list_head; + s->iterate_list_head = s->iterate_list_head->iterate_next; + + if (free_func) + free_func(e->data, userdata); + pa_xfree(e); + } + + pa_xfree(s->hash_table); + pa_xfree(s->array); + pa_xfree(s); +} + +static idxset_entry* hash_scan(pa_idxset *s, idxset_entry* e, const void *p) { + assert(p); + + assert(s->compare_func); + for (; e; e = e->hash_next) + if (s->compare_func(e->data, p) == 0) + return e; + + return NULL; +} + +static void extend_array(pa_idxset *s, uint32_t idx) { + uint32_t i, j, l; + idxset_entry** n; + assert(idx >= s->start_index); + + if (idx < s->start_index + s->array_size) + return; + + for (i = 0; i < s->array_size; i++) + if (s->array[i]) + break; + + l = idx - s->start_index - i + 100; + n = pa_xnew0(idxset_entry*, l); + + for (j = 0; j < s->array_size-i; j++) + n[j] = s->array[i+j]; + + pa_xfree(s->array); + + s->array = n; + s->array_size = l; + s->start_index += i; +} + +static idxset_entry** array_index(pa_idxset*s, uint32_t idx) { + if (idx >= s->start_index + s->array_size) + return NULL; + + if (idx < s->start_index) + return NULL; + + return s->array + (idx - s->start_index); +} + +int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) { + unsigned h; + idxset_entry *e, **a; + assert(s && p); + + assert(s->hash_func); + h = s->hash_func(p) % s->hash_table_size; + + assert(s->hash_table); + if ((e = hash_scan(s, s->hash_table[h], p))) { + if (idx) + *idx = e->index; + + return -1; + } + + e = pa_xmalloc(sizeof(idxset_entry)); + e->data = p; + e->index = s->index++; + e->hash_value = h; + + /* Insert into hash table */ + e->hash_next = s->hash_table[h]; + e->hash_prev = NULL; + if (s->hash_table[h]) + s->hash_table[h]->hash_prev = e; + s->hash_table[h] = e; + + /* Insert into array */ + extend_array(s, e->index); + a = array_index(s, e->index); + assert(a && !*a); + *a = e; + + /* Insert into linked list */ + e->iterate_next = NULL; + e->iterate_prev = s->iterate_list_tail; + if (s->iterate_list_tail) { + assert(s->iterate_list_head); + s->iterate_list_tail->iterate_next = e; + } else { + assert(!s->iterate_list_head); + s->iterate_list_head = e; + } + s->iterate_list_tail = e; + + s->n_entries++; + assert(s->n_entries >= 1); + + if (idx) + *idx = e->index; + + return 0; +} + +void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx) { + idxset_entry **a; + assert(s); + + if (!(a = array_index(s, idx))) + return NULL; + + if (!*a) + return NULL; + + return (*a)->data; +} + +void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx) { + unsigned h; + idxset_entry *e; + assert(s && p); + + assert(s->hash_func); + h = s->hash_func(p) % s->hash_table_size; + + assert(s->hash_table); + if (!(e = hash_scan(s, s->hash_table[h], p))) + return NULL; + + if (idx) + *idx = e->index; + + return e->data; +} + +static void remove_entry(pa_idxset *s, idxset_entry *e) { + idxset_entry **a; + assert(s && e); + + /* Remove from array */ + a = array_index(s, e->index); + assert(a && *a && *a == e); + *a = NULL; + + /* Remove from linked list */ + if (e->iterate_next) + e->iterate_next->iterate_prev = e->iterate_prev; + else + s->iterate_list_tail = e->iterate_prev; + + if (e->iterate_prev) + e->iterate_prev->iterate_next = e->iterate_next; + else + s->iterate_list_head = e->iterate_next; + + /* Remove from hash table */ + if (e->hash_next) + e->hash_next->hash_prev = e->hash_prev; + + if (e->hash_prev) + e->hash_prev->hash_next = e->hash_next; + else + s->hash_table[e->hash_value] = e->hash_next; + + pa_xfree(e); + + assert(s->n_entries >= 1); + s->n_entries--; +} + +void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx) { + idxset_entry **a; + void *data; + + assert(s); + + if (!(a = array_index(s, idx))) + return NULL; + + data = (*a)->data; + remove_entry(s, *a); + + return data; +} + +void* pa_idxset_remove_by_data(pa_idxset*s, const void *data, uint32_t *idx) { + idxset_entry *e; + unsigned h; + void *r; + + assert(s->hash_func); + h = s->hash_func(data) % s->hash_table_size; + + assert(s->hash_table); + if (!(e = hash_scan(s, s->hash_table[h], data))) + return NULL; + + r = e->data; + if (idx) + *idx = e->index; + + remove_entry(s, e); + + return r; +} + +void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx) { + idxset_entry **a, *e = NULL; + assert(s && idx); + + if ((a = array_index(s, *idx)) && *a) + e = (*a)->iterate_next; + + if (!e) + e = s->iterate_list_head; + + if (!e) + return NULL; + + *idx = e->index; + return e->data; +} + +void* pa_idxset_first(pa_idxset *s, uint32_t *idx) { + assert(s); + + if (!s->iterate_list_head) + return NULL; + + if (idx) + *idx = s->iterate_list_head->index; + return s->iterate_list_head->data; +} + +void *pa_idxset_next(pa_idxset *s, uint32_t *idx) { + idxset_entry **a, *e = NULL; + assert(s && idx); + + if ((a = array_index(s, *idx)) && *a) + e = (*a)->iterate_next; + + if (e) { + *idx = e->index; + return e->data; + } else { + *idx = PA_IDXSET_INVALID; + return NULL; + } +} + + +int pa_idxset_foreach(pa_idxset*s, int (*func)(void *p, uint32_t idx, int *del, void*userdata), void *userdata) { + idxset_entry *e; + assert(s && func); + + e = s->iterate_list_head; + while (e) { + int del = 0, r; + idxset_entry *n = e->iterate_next; + + r = func(e->data, e->index, &del, userdata); + + if (del) + remove_entry(s, e); + + if (r < 0) + return r; + + e = n; + } + + return 0; +} + +unsigned pa_idxset_size(pa_idxset*s) { + assert(s); + return s->n_entries; +} + +int pa_idxset_isempty(pa_idxset *s) { + assert(s); + return s->n_entries == 0; +} + diff --git a/src/polypcore/idxset.h b/src/polypcore/idxset.h new file mode 100644 index 00000000..17ae16cb --- /dev/null +++ b/src/polypcore/idxset.h @@ -0,0 +1,94 @@ +#ifndef fooidxsethfoo +#define fooidxsethfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +/* A combination of a set and a dynamic array. Entries are indexable + * both through a numeric automatically generated index and the entry's + * data pointer. As usual, memory management is the user's job. */ + +/* A special index value denoting the invalid index. */ +#define PA_IDXSET_INVALID ((uint32_t) -1) + +/* Generic implementations for hash and comparison functions. Just + * compares the pointer or calculates the hash value directly from the + * pointer value. */ +unsigned pa_idxset_trivial_hash_func(const void *p); +int pa_idxset_trivial_compare_func(const void *a, const void *b); + +/* Generic implementations for hash and comparison functions for strings. */ +unsigned pa_idxset_string_hash_func(const void *p); +int pa_idxset_string_compare_func(const void *a, const void *b); + +typedef struct pa_idxset pa_idxset; + +/* Instantiate a new idxset with the specified hash and comparison functions */ +pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); + +/* Free the idxset. When the idxset is not empty the specified function is called for every entry contained */ +void pa_idxset_free(pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata); + +/* Store a new item in the idxset. The index of the item is returned in *idx */ +int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx); + +/* Get the entry by its idx */ +void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx); + +/* Get the entry by its data. The idx is returned in *index */ +void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx); + +/* Similar to pa_idxset_get_by_index(), but removes the entry from the idxset. */ +void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx); + +/* Similar to pa_idxset_get_by_data(), but removes the entry from the idxset */ +void* pa_idxset_remove_by_data(pa_idxset*s, const void *p, uint32_t *idx); + +/* This may be used to iterate through all entries. When called with + an invalid index value it returns the first entry, otherwise the + next following. The function is best called with *idx = + PA_IDXSET_VALID first. It is safe to manipulate the idxset between + the calls. It is not guaranteed that all entries have already been + returned before the an entry is returned the second time.*/ +void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx); + +/* Return the oldest entry in the idxset. Fill in its index in *idx. */ +void* pa_idxset_first(pa_idxset *s, uint32_t *idx); + +/* Return the entry following the entry indexed by *idx. After the + * call *index contains the index of the returned + * object. pa_idxset_first() and pa_idxset_next() may be used to + * iterate through the set.*/ +void *pa_idxset_next(pa_idxset *s, uint32_t *idx); + +/* Call a function for every item in the set. If the callback function + returns -1, the loop is terminated. If *del is set to non-zero that + specific item is removed. It is not safe to call any other + functions on the idxset while pa_idxset_foreach is executed. */ +int pa_idxset_foreach(pa_idxset*s, int (*func)(void *p, uint32_t idx, int *del, void*userdata), void *userdata); + +unsigned pa_idxset_size(pa_idxset*s); + +int pa_idxset_isempty(pa_idxset *s); + +#endif diff --git a/src/polypcore/inet_ntop.c b/src/polypcore/inet_ntop.c new file mode 100644 index 00000000..a25c3c95 --- /dev/null +++ b/src/polypcore/inet_ntop.c @@ -0,0 +1,80 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#ifndef HAVE_INET_NTOP + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#include "winsock.h" + +#include "inet_ntop.h" + +const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) { + struct in_addr *in = (struct in_addr*)src; + struct in6_addr *in6 = (struct in6_addr*)src; + + assert(src && dst); + + switch (af) { + case AF_INET: + snprintf(dst, cnt, "%d.%d.%d.%d", +#ifdef WORDS_BIGENDIAN + (int)(in->s_addr >> 24) & 0xff, + (int)(in->s_addr >> 16) & 0xff, + (int)(in->s_addr >> 8) & 0xff, + (int)(in->s_addr >> 0) & 0xff); +#else + (int)(in->s_addr >> 0) & 0xff, + (int)(in->s_addr >> 8) & 0xff, + (int)(in->s_addr >> 16) & 0xff, + (int)(in->s_addr >> 24) & 0xff); +#endif + break; + case AF_INET6: + snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x", + in6->s6_addr[ 0] << 8 | in6->s6_addr[ 1], + in6->s6_addr[ 2] << 8 | in6->s6_addr[ 3], + in6->s6_addr[ 4] << 8 | in6->s6_addr[ 5], + in6->s6_addr[ 6] << 8 | in6->s6_addr[ 7], + in6->s6_addr[ 8] << 8 | in6->s6_addr[ 9], + in6->s6_addr[10] << 8 | in6->s6_addr[11], + in6->s6_addr[12] << 8 | in6->s6_addr[13], + in6->s6_addr[14] << 8 | in6->s6_addr[15]); + break; + default: + errno = EAFNOSUPPORT; + return NULL; + } + + return dst; +} + +#endif /* INET_NTOP */ diff --git a/src/polypcore/inet_ntop.h b/src/polypcore/inet_ntop.h new file mode 100644 index 00000000..7fb67b44 --- /dev/null +++ b/src/polypcore/inet_ntop.h @@ -0,0 +1,12 @@ +#ifndef fooinet_ntophfoo +#define fooinet_ntophfoo + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#include "winsock.h" + +const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt); + +#endif diff --git a/src/polypcore/iochannel.c b/src/polypcore/iochannel.c new file mode 100644 index 00000000..273d47e0 --- /dev/null +++ b/src/polypcore/iochannel.c @@ -0,0 +1,292 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "winsock.h" + +#include "iochannel.h" +#include "util.h" +#include "socket-util.h" +#include "xmalloc.h" + +struct pa_iochannel { + int ifd, ofd; + pa_mainloop_api* mainloop; + + pa_iochannel_callback_t callback; + void*userdata; + + int readable; + int writable; + int hungup; + + int no_close; + + pa_io_event* input_event, *output_event; +}; + +static void enable_mainloop_sources(pa_iochannel *io) { + assert(io); + + if (io->input_event == io->output_event && io->input_event) { + pa_io_event_flags_t f = PA_IO_EVENT_NULL; + assert(io->input_event); + + if (!io->readable) + f |= PA_IO_EVENT_INPUT; + if (!io->writable) + f |= PA_IO_EVENT_OUTPUT; + + io->mainloop->io_enable(io->input_event, f); + } else { + if (io->input_event) + io->mainloop->io_enable(io->input_event, io->readable ? PA_IO_EVENT_NULL : PA_IO_EVENT_INPUT); + if (io->output_event) + io->mainloop->io_enable(io->output_event, io->writable ? PA_IO_EVENT_NULL : PA_IO_EVENT_OUTPUT); + } +} + +static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { + pa_iochannel *io = userdata; + int changed = 0; + + assert(m); + assert(e); + assert(fd >= 0); + assert(userdata); + + if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) { + io->hungup = 1; + changed = 1; + + if (e == io->input_event) { + io->mainloop->io_free(io->input_event); + io->input_event = NULL; + + if (io->output_event == e) + io->output_event = NULL; + } else if (e == io->output_event) { + io->mainloop->io_free(io->output_event); + io->output_event = NULL; + } + } else { + + if ((f & PA_IO_EVENT_INPUT) && !io->readable) { + io->readable = 1; + changed = 1; + assert(e == io->input_event); + } + + if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) { + io->writable = 1; + changed = 1; + assert(e == io->output_event); + } + } + + if (changed) { + enable_mainloop_sources(io); + + if (io->callback) + io->callback(io, io->userdata); + } +} + +pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) { + pa_iochannel *io; + + assert(m); + assert(ifd >= 0 || ofd >= 0); + + io = pa_xnew(pa_iochannel, 1); + io->ifd = ifd; + io->ofd = ofd; + io->mainloop = m; + + io->userdata = NULL; + io->callback = NULL; + io->readable = 0; + io->writable = 0; + io->hungup = 0; + io->no_close = 0; + + io->input_event = io->output_event = NULL; + + if (ifd == ofd) { + assert(ifd >= 0); + pa_make_nonblock_fd(io->ifd); + io->input_event = io->output_event = m->io_new(m, ifd, PA_IO_EVENT_INPUT|PA_IO_EVENT_OUTPUT, callback, io); + } else { + + if (ifd >= 0) { + pa_make_nonblock_fd(io->ifd); + io->input_event = m->io_new(m, ifd, PA_IO_EVENT_INPUT, callback, io); + } + + if (ofd >= 0) { + pa_make_nonblock_fd(io->ofd); + io->output_event = m->io_new(m, ofd, PA_IO_EVENT_OUTPUT, callback, io); + } + } + + return io; +} + +void pa_iochannel_free(pa_iochannel*io) { + assert(io); + + if (io->input_event) + io->mainloop->io_free(io->input_event); + + if (io->output_event && (io->output_event != io->input_event)) + io->mainloop->io_free(io->output_event); + + if (!io->no_close) { + if (io->ifd >= 0) + + close(io->ifd); + if (io->ofd >= 0 && io->ofd != io->ifd) + close(io->ofd); + } + + pa_xfree(io); +} + +int pa_iochannel_is_readable(pa_iochannel*io) { + assert(io); + + return io->readable || io->hungup; +} + +int pa_iochannel_is_writable(pa_iochannel*io) { + assert(io); + + return io->writable && !io->hungup; +} + +int pa_iochannel_is_hungup(pa_iochannel*io) { + assert(io); + + return io->hungup; +} + +ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) { + ssize_t r; + + assert(io); + assert(data); + assert(l); + assert(io->ofd >= 0); + +#ifdef OS_IS_WIN32 + r = send(io->ofd, data, l, 0); + if (r < 0) { + if (WSAGetLastError() != WSAENOTSOCK) { + errno = WSAGetLastError(); + return r; + } + } + + if (r < 0) +#endif + r = write(io->ofd, data, l); + if (r >= 0) { + io->writable = 0; + enable_mainloop_sources(io); + } + + return r; +} + +ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) { + ssize_t r; + + assert(io); + assert(data); + assert(io->ifd >= 0); + +#ifdef OS_IS_WIN32 + r = recv(io->ifd, data, l, 0); + if (r < 0) { + if (WSAGetLastError() != WSAENOTSOCK) { + errno = WSAGetLastError(); + return r; + } + } + + if (r < 0) +#endif + r = read(io->ifd, data, l); + + if (r >= 0) { + io->readable = 0; + enable_mainloop_sources(io); + } + + return r; +} + +void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_callback_t _callback, void *userdata) { + assert(io); + + io->callback = _callback; + io->userdata = userdata; +} + +void pa_iochannel_set_noclose(pa_iochannel*io, int b) { + assert(io); + + io->no_close = b; +} + +void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) { + assert(io); + assert(s); + assert(l); + + pa_socket_peer_to_string(io->ifd, s, l); +} + +int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) { + assert(io); + + return pa_socket_set_rcvbuf(io->ifd, l); +} + +int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) { + assert(io); + + return pa_socket_set_sndbuf(io->ofd, l); +} + +pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) { + assert(io); + + return io->mainloop; +} diff --git a/src/polypcore/iochannel.h b/src/polypcore/iochannel.h new file mode 100644 index 00000000..7d355d8f --- /dev/null +++ b/src/polypcore/iochannel.h @@ -0,0 +1,72 @@ +#ifndef fooiochannelhfoo +#define fooiochannelhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/* A wrapper around UNIX file descriptors for attaching them to the a + main event loop. Everytime new data may be read or be written to + the channel a callback function is called. It is safe to destroy + the calling iochannel object from the callback */ + +/* When pa_iochannel_is_readable() returns non-zero, the user has to + * call this function in a loop until it is no longer set or EOF + * reached. Otherwise strange things may happen when an EOF is + * reached. */ + +typedef struct pa_iochannel pa_iochannel; + +/* Create a new IO channel for the specified file descriptors for +input resp. output. It is safe to pass the same file descriptor for +both parameters (in case of full-duplex channels). For a simplex +channel specify -1 for the other direction. */ + +pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd); +void pa_iochannel_free(pa_iochannel*io); + +ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l); +ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l); + +int pa_iochannel_is_readable(pa_iochannel*io); +int pa_iochannel_is_writable(pa_iochannel*io); +int pa_iochannel_is_hungup(pa_iochannel*io); + +/* Don't close the file descirptors when the io channel is freed. By + * default the file descriptors are closed. */ +void pa_iochannel_set_noclose(pa_iochannel*io, int b); + +/* Set the callback function that is called whenever data becomes available for read or write */ +typedef void (*pa_iochannel_callback_t)(pa_iochannel*io, void *userdata); +void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_callback_t callback, void *userdata); + +/* In case the file descriptor is a socket, return a pretty-printed string in *s which describes the peer connected */ +void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l); + +/* Use setsockopt() to tune the recieve and send buffers of TCP sockets */ +int pa_iochannel_socket_set_rcvbuf(pa_iochannel*io, size_t l); +int pa_iochannel_socket_set_sndbuf(pa_iochannel*io, size_t l); + +pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io); + +#endif diff --git a/src/polypcore/ioline.c b/src/polypcore/ioline.c new file mode 100644 index 00000000..5b669f5c --- /dev/null +++ b/src/polypcore/ioline.c @@ -0,0 +1,368 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "ioline.h" +#include "xmalloc.h" +#include "log.h" + +#define BUFFER_LIMIT (64*1024) +#define READ_SIZE (1024) + +struct pa_ioline { + pa_iochannel *io; + pa_defer_event *defer_event; + pa_mainloop_api *mainloop; + int ref; + 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)(pa_ioline*io, const char *s, void *userdata); + void *userdata; + + int defer_close; +}; + +static void io_callback(pa_iochannel*io, void *userdata); +static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata); + +pa_ioline* pa_ioline_new(pa_iochannel *io) { + pa_ioline *l; + assert(io); + + l = pa_xmalloc(sizeof(pa_ioline)); + 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; + l->ref = 1; + + l->mainloop = pa_iochannel_get_mainloop_api(io); + + l->defer_event = l->mainloop->defer_new(l->mainloop, defer_callback, l); + l->mainloop->defer_enable(l->defer_event, 0); + + l->defer_close = 0; + + pa_iochannel_set_callback(io, io_callback, l); + + return l; +} + +static void ioline_free(pa_ioline *l) { + assert(l); + + if (l->io) + pa_iochannel_free(l->io); + + if (l->defer_event) + l->mainloop->defer_free(l->defer_event); + + pa_xfree(l->wbuf); + pa_xfree(l->rbuf); + pa_xfree(l); +} + +void pa_ioline_unref(pa_ioline *l) { + assert(l && l->ref >= 1); + + if ((--l->ref) <= 0) + ioline_free(l); +} + +pa_ioline* pa_ioline_ref(pa_ioline *l) { + assert(l && l->ref >= 1); + + l->ref++; + return l; +} + +void pa_ioline_close(pa_ioline *l) { + assert(l && l->ref >= 1); + + l->dead = 1; + if (l->io) { + pa_iochannel_free(l->io); + l->io = NULL; + } + + if (l->defer_event) { + l->mainloop->defer_free(l->defer_event); + l->defer_event = NULL; + } +} + +void pa_ioline_puts(pa_ioline *l, const char *c) { + size_t len; + assert(l && c && l->ref >= 1 && !l->dead); + + pa_ioline_ref(l); + + len = strlen(c); + if (len > BUFFER_LIMIT - l->wbuf_valid_length) + len = BUFFER_LIMIT - l->wbuf_valid_length; + + if (len) { + assert(l->wbuf_length >= l->wbuf_valid_length); + + /* In case the allocated buffer is too small, enlarge it. */ + if (l->wbuf_valid_length + len > l->wbuf_length) { + size_t n = l->wbuf_valid_length+len; + char *new = pa_xmalloc(n); + if (l->wbuf) { + memcpy(new, l->wbuf+l->wbuf_index, l->wbuf_valid_length); + pa_xfree(l->wbuf); + } + l->wbuf = new; + l->wbuf_length = n; + l->wbuf_index = 0; + } else if (l->wbuf_index + l->wbuf_valid_length + len > l->wbuf_length) { + + /* In case the allocated buffer fits, but the current index is too far from the start, move it to the front. */ + memmove(l->wbuf, l->wbuf+l->wbuf_index, l->wbuf_valid_length); + l->wbuf_index = 0; + } + + assert(l->wbuf_index + l->wbuf_valid_length + len <= l->wbuf_length); + + /* Append the new string */ + memcpy(l->wbuf + l->wbuf_index + l->wbuf_valid_length, c, len); + l->wbuf_valid_length += len; + + l->mainloop->defer_enable(l->defer_event, 1); + } + + pa_ioline_unref(l); +} + +void pa_ioline_set_callback(pa_ioline*l, void (*callback)(pa_ioline*io, const char *s, void *userdata), void *userdata) { + assert(l && l->ref >= 1); + l->callback = callback; + l->userdata = userdata; +} + +static void failure(pa_ioline *l) { + assert(l && l->ref >= 1 && !l->dead); + + pa_ioline_close(l); + + if (l->callback) { + l->callback(l, NULL, l->userdata); + l->callback = NULL; + } +} + +static void scan_for_lines(pa_ioline *l, size_t skip) { + assert(l && l->ref >= 1 && skip < l->rbuf_valid_length); + + while (!l->dead && l->rbuf_valid_length > skip) { + char *e, *p; + size_t m; + + if (!(e = memchr(l->rbuf + l->rbuf_index + skip, '\n', l->rbuf_valid_length - skip))) + break; + + *e = 0; + + p = l->rbuf + l->rbuf_index; + m = strlen(p); + + l->rbuf_index += m+1; + l->rbuf_valid_length -= m+1; + + /* A shortcut for the next time */ + if (l->rbuf_valid_length == 0) + l->rbuf_index = 0; + + if (l->callback) + l->callback(l, p, l->userdata); + + skip = 0; + } + + /* If the buffer became too large and still no newline was found, drop it. */ + if (l->rbuf_valid_length >= BUFFER_LIMIT) + l->rbuf_index = l->rbuf_valid_length = 0; +} + +static int do_write(pa_ioline *l); + +static int do_read(pa_ioline *l) { + assert(l && l->ref >= 1); + + while (!l->dead && pa_iochannel_is_readable(l->io)) { + ssize_t r; + size_t len; + + len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length; + + /* Check if we have to enlarge the read buffer */ + 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) { + /* The current buffer is large enough, let's just move the data to the front */ + if (l->rbuf_valid_length) + memmove(l->rbuf, l->rbuf+l->rbuf_index, l->rbuf_valid_length); + } else { + /* Enlarge the buffer */ + char *new = pa_xmalloc(n); + if (l->rbuf_valid_length) + memcpy(new, l->rbuf+l->rbuf_index, l->rbuf_valid_length); + pa_xfree(l->rbuf); + l->rbuf = new; + l->rbuf_length = n; + } + + l->rbuf_index = 0; + } + + len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length; + + assert(len >= READ_SIZE); + + /* Read some data */ + r = pa_iochannel_read(l->io, l->rbuf+l->rbuf_index+l->rbuf_valid_length, len); + if (r == 0) { + /* Got an EOF, so fake an exit command. */ + l->rbuf_index = 0; + snprintf (l->rbuf, l->rbuf_length, "exit\n"); + r = 5; + pa_ioline_puts(l, "\nExiting.\n"); + do_write(l); + } else if (r < 0) { + pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + failure(l); + return -1; + } + + l->rbuf_valid_length += r; + + /* Look if a line has been terminated in the newly read data */ + scan_for_lines(l, l->rbuf_valid_length - r); + } + + return 0; +} + +/* Try to flush the buffer */ +static int do_write(pa_ioline *l) { + ssize_t r; + assert(l && l->ref >= 1); + + while (!l->dead && pa_iochannel_is_writable(l->io) && l->wbuf_valid_length) { + + if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0) { + pa_log(__FILE__": write() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); + failure(l); + return -1; + } + + l->wbuf_index += r; + l->wbuf_valid_length -= r; + + /* A shortcut for the next time */ + if (l->wbuf_valid_length == 0) + l->wbuf_index = 0; + } + + return 0; +} + +/* Try to flush read/write data */ +static void do_work(pa_ioline *l) { + assert(l && l->ref >= 1); + + pa_ioline_ref(l); + + l->mainloop->defer_enable(l->defer_event, 0); + + if (!l->dead) + do_write(l); + + if (!l->dead) + do_read(l); + + if (l->defer_close && !l->wbuf_valid_length) + failure(l); + + pa_ioline_unref(l); +} + +static void io_callback(pa_iochannel*io, void *userdata) { + pa_ioline *l = userdata; + assert(io && l && l->ref >= 1); + + do_work(l); +} + +static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata) { + pa_ioline *l = userdata; + assert(l && l->ref >= 1 && l->mainloop == m && l->defer_event == e); + + do_work(l); +} + +void pa_ioline_defer_close(pa_ioline *l) { + assert(l); + + l->defer_close = 1; + + if (!l->wbuf_valid_length) + l->mainloop->defer_enable(l->defer_event, 1); +} + +void pa_ioline_printf(pa_ioline *s, const char *format, ...) { + char *t; + va_list ap; + + + va_start(ap, format); + t = pa_vsprintf_malloc(format, ap); + va_end(ap); + + pa_ioline_puts(s, t); + pa_xfree(t); +} diff --git a/src/polypcore/ioline.h b/src/polypcore/ioline.h new file mode 100644 index 00000000..84ccb47a --- /dev/null +++ b/src/polypcore/ioline.h @@ -0,0 +1,51 @@ +#ifndef fooiolinehfoo +#define fooiolinehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "iochannel.h" +#include "util.h" + +/* An ioline wraps an iochannel for line based communication. A + * callback function is called whenever a new line has been recieved + * from the client */ + +typedef struct pa_ioline pa_ioline; + +pa_ioline* pa_ioline_new(pa_iochannel *io); +void pa_ioline_unref(pa_ioline *l); +pa_ioline* pa_ioline_ref(pa_ioline *l); +void pa_ioline_close(pa_ioline *l); + +/* Write a string to the channel */ +void pa_ioline_puts(pa_ioline *s, const char *c); + +/* Write a string to the channel */ +void pa_ioline_printf(pa_ioline *s, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); + +/* Set the callback function that is called for every recieved line */ +void pa_ioline_set_callback(pa_ioline*io, void (*callback)(pa_ioline*io, const char *s, void *userdata), void *userdata); + +/* Make sure to close the ioline object as soon as the send buffer is emptied */ +void pa_ioline_defer_close(pa_ioline *io); + +#endif diff --git a/src/polypcore/llist.h b/src/polypcore/llist.h new file mode 100644 index 00000000..eb8cd017 --- /dev/null +++ b/src/polypcore/llist.h @@ -0,0 +1,69 @@ +#ifndef foollistfoo +#define foollistfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* Some macros for maintaining doubly linked lists */ + +/* The head of the linked list. Use this in the structure that shall + * contain the head of the linked list */ +#define PA_LLIST_HEAD(t,name) t *name + +/* The pointers in the linked list's items. Use this in the item structure */ +#define PA_LLIST_FIELDS(t) t *next, *prev + +/* Initialize the list's head */ +#define PA_LLIST_HEAD_INIT(t,item) do { (item) = NULL; } while(0) + +/* Initialize a list item */ +#define PA_LLIST_INIT(t,item) do { \ + t *_item = (item); \ + assert(_item); \ + _item->prev = _item->next = NULL; \ + } while(0) + +/* Prepend an item to the list */ +#define PA_LLIST_PREPEND(t,head,item) do { \ + t **_head = &(head), *_item = (item); \ + assert(_item); \ + if ((_item->next = *_head)) \ + _item->next->prev = _item; \ + _item->prev = NULL; \ + *_head = _item; \ + } while (0) + +/* Remove an item from the list */ +#define PA_LLIST_REMOVE(t,head,item) do { \ + t **_head = &(head), *_item = (item); \ + assert(_item); \ + if (_item->next) \ + _item->next->prev = _item->prev; \ + if (_item->prev) \ + _item->prev->next = _item->next; \ + else {\ + assert(*_head == _item); \ + *_head = _item->next; \ + } \ + _item->next = _item->prev = NULL; \ + } while(0) + +#endif diff --git a/src/polypcore/log.c b/src/polypcore/log.c new file mode 100644 index 00000000..97406f79 --- /dev/null +++ b/src/polypcore/log.c @@ -0,0 +1,150 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#ifdef HAVE_SYSLOG_H +#include +#endif + +#include "log.h" +#include "xmalloc.h" +#include "util.h" + +#define ENV_LOGLEVEL "POLYP_LOG" + +static char *log_ident = NULL; +static pa_log_target_t log_target = PA_LOG_STDERR; +static void (*user_log_func)(pa_log_level_t l, const char *s) = NULL; +static pa_log_level_t maximal_level = PA_LOG_NOTICE; + +#ifdef HAVE_SYSLOG_H +static const int level_to_syslog[] = { + [PA_LOG_ERROR] = LOG_ERR, + [PA_LOG_WARN] = LOG_WARNING, + [PA_LOG_NOTICE] = LOG_NOTICE, + [PA_LOG_INFO] = LOG_INFO, + [PA_LOG_DEBUG] = LOG_DEBUG +}; +#endif + +void pa_log_set_ident(const char *p) { + if (log_ident) + pa_xfree(log_ident); + + log_ident = pa_xstrdup(p); +} + +void pa_log_set_maximal_level(pa_log_level_t l) { + assert(l < PA_LOG_LEVEL_MAX); + maximal_level = l; +} + +void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t l, const char*s)) { + assert(t == PA_LOG_USER || !func); + log_target = t; + user_log_func = func; +} + +void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { + const char *e; + assert(level < PA_LOG_LEVEL_MAX); + + if ((e = getenv(ENV_LOGLEVEL))) + maximal_level = atoi(e); + + if (level > maximal_level) + return; + + switch (log_target) { + case PA_LOG_STDERR: + vfprintf(stderr, format, ap); + break; + +#ifdef HAVE_SYSLOG_H + case PA_LOG_SYSLOG: + openlog(log_ident ? log_ident : "???", LOG_PID, LOG_USER); + vsyslog(level_to_syslog[level], format, ap); + closelog(); + break; +#endif + + case PA_LOG_USER: { + char *t = pa_vsprintf_malloc(format, ap); + assert(user_log_func); + user_log_func(level, t); + pa_xfree(t); + } + + case PA_LOG_NULL: + default: + break; + } + +} + +void pa_log_level(pa_log_level_t level, const char *format, ...) { + va_list ap; + va_start(ap, format); + pa_log_levelv(level, format, ap); + va_end(ap); +} + +void pa_log_debug(const char *format, ...) { + va_list ap; + va_start(ap, format); + pa_log_levelv(PA_LOG_DEBUG, format, ap); + va_end(ap); +} + +void pa_log_info(const char *format, ...) { + va_list ap; + va_start(ap, format); + pa_log_levelv(PA_LOG_INFO, format, ap); + va_end(ap); +} + +void pa_log_notice(const char *format, ...) { + va_list ap; + va_start(ap, format); + pa_log_levelv(PA_LOG_INFO, format, ap); + va_end(ap); +} + +void pa_log_warn(const char *format, ...) { + va_list ap; + va_start(ap, format); + pa_log_levelv(PA_LOG_WARN, format, ap); + va_end(ap); +} + +void pa_log_error(const char *format, ...) { + va_list ap; + va_start(ap, format); + pa_log_levelv(PA_LOG_ERROR, format, ap); + va_end(ap); +} diff --git a/src/polypcore/log.h b/src/polypcore/log.h new file mode 100644 index 00000000..ce8aea98 --- /dev/null +++ b/src/polypcore/log.h @@ -0,0 +1,69 @@ +#ifndef foologhfoo +#define foologhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include "gccmacro.h" + +/* A simple logging subsystem */ + +/* Where to log to */ +typedef enum pa_log_target { + PA_LOG_STDERR, /* default */ + PA_LOG_SYSLOG, + PA_LOG_USER, /* to user specified function */ + PA_LOG_NULL /* to /dev/null */ +} pa_log_target_t; + +typedef enum pa_log_level { + PA_LOG_ERROR = 0, /* Error messages */ + PA_LOG_WARN = 1, /* Warning messages */ + PA_LOG_NOTICE = 2, /* Notice messages */ + PA_LOG_INFO = 3, /* Info messages */ + PA_LOG_DEBUG = 4, /* debug message */ + PA_LOG_LEVEL_MAX +} pa_log_level_t; + +/* Set an identification for the current daemon. Used when logging to syslog. */ +void pa_log_set_ident(const char *p); + +/* Set another log target. If t is PA_LOG_USER you may specify a function that is called every log string */ +void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t t, const char*s)); + +/* Minimal log level */ +void pa_log_set_maximal_level(pa_log_level_t l); + +/* Do a log line */ +void pa_log_debug(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +void pa_log_info(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +void pa_log_notice(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +void pa_log_warn(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +void pa_log_error(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); + +void pa_log_level(pa_log_level_t level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); + +void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap); + +#define pa_log pa_log_error + +#endif diff --git a/src/polypcore/mcalign.c b/src/polypcore/mcalign.c new file mode 100644 index 00000000..4d765625 --- /dev/null +++ b/src/polypcore/mcalign.c @@ -0,0 +1,188 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "mcalign.h" +#include "xmalloc.h" + +struct pa_mcalign { + size_t base; + pa_memchunk leftover, current; + pa_memblock_stat *memblock_stat; +}; + +pa_mcalign *pa_mcalign_new(size_t base, pa_memblock_stat *s) { + pa_mcalign *m; + assert(base); + + m = pa_xnew(pa_mcalign, 1); + m->base = base; + pa_memchunk_reset(&m->leftover); + pa_memchunk_reset(&m->current); + m->memblock_stat = s; + + return m; +} + +void pa_mcalign_free(pa_mcalign *m) { + assert(m); + + if (m->leftover.memblock) + pa_memblock_unref(m->leftover.memblock); + + if (m->current.memblock) + pa_memblock_unref(m->current.memblock); + + pa_xfree(m); +} + +void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { + assert(m && c && c->memblock && c->length); + + /* Append to the leftover memory block */ + if (m->leftover.memblock) { + assert(!m->current.memblock); + + /* Try to merge */ + if (m->leftover.memblock == c->memblock && + m->leftover.index + m->leftover.length == c->index) { + + /* Merge */ + m->leftover.length += c->length; + + /* If the new chunk is larger than m->base, move it to current */ + if (m->leftover.length >= m->base) { + m->current = m->leftover; + pa_memchunk_reset(&m->leftover); + } + + } else { + size_t l; + + /* We have to copy */ + assert(m->leftover.length < m->base); + l = m->base - m->leftover.length; + + if (l > c->length) + l = c->length; + + /* Can we use the current block? */ + pa_memchunk_make_writable(&m->leftover, m->memblock_stat, m->base); + + memcpy((uint8_t*) m->leftover.memblock->data + m->leftover.index + m->leftover.length, (uint8_t*) c->memblock->data + c->index, l); + m->leftover.length += l; + + assert(m->leftover.length <= m->base && m->leftover.length <= m->leftover.memblock->length); + + if (c->length > l) { + /* Save the remainder of the memory block */ + m->current = *c; + m->current.index += l; + m->current.length -= l; + pa_memblock_ref(m->current.memblock); + } + } + } else { + assert(!m->leftover.memblock && !m->current.memblock); + + /* Nothing to merge or copy, just store it */ + + if (c->length >= m->base) + m->current = *c; + else + m->leftover = *c; + + pa_memblock_ref(c->memblock); + } +} + +int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) { + assert(m && c); + + /* First test if there's a leftover memory block available */ + if (m->leftover.memblock) { + assert(m->leftover.length > 0 && m->leftover.length <= m->base); + + /* The leftover memory block is not yet complete */ + if (m->leftover.length < m->base) + return -1; + + /* Return the leftover memory block */ + *c = m->leftover; + pa_memchunk_reset(&m->leftover); + + /* If the current memblock is too small move it the leftover */ + if (m->current.memblock && m->current.length < m->base) { + m->leftover = m->current; + pa_memchunk_reset(&m->current); + } + + return 0; + } + + /* Now let's see if there is other data available */ + if (m->current.memblock) { + size_t l; + assert(m->current.length >= m->base); + + /* The length of the returned memory block */ + l = m->current.length; + l /= m->base; + l *= m->base; + assert(l > 0); + + /* Prepare the returned block */ + *c = m->current; + pa_memblock_ref(c->memblock); + c->length = l; + + /* Drop that from the current memory block */ + assert(l <= m->current.length); + m->current.index += l; + m->current.length -= l; + + /* In case the whole block was dropped ... */ + if (m->current.length == 0) + pa_memblock_unref(m->current.memblock); + else { + /* Move the raimainder to leftover */ + assert(m->current.length < m->base && !m->leftover.memblock); + + m->leftover = m->current; + } + + pa_memchunk_reset(&m->current); + + return 0; + } + + /* There's simply nothing */ + return -1; + +} diff --git a/src/polypcore/mcalign.h b/src/polypcore/mcalign.h new file mode 100644 index 00000000..5de75bc7 --- /dev/null +++ b/src/polypcore/mcalign.h @@ -0,0 +1,77 @@ +#ifndef foomcalignhfoo +#define foomcalignhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "memblock.h" +#include "memchunk.h" + +/* An alignment object, used for aligning memchunks to multiples of + * the frame size. */ + +/* Method of operation: the user creates a new mcalign object by + * calling pa_mcalign_new() with the appropriate aligning + * granularity. After that he may call pa_mcalign_push() for an input + * memchunk. After exactly one memchunk the user has to call + * pa_mcalign_pop() until it returns -1. If pa_mcalign_pop() returns + * 0, the memchunk *c is valid and aligned to the granularity. Some + * pseudocode illustrating this: + * + * pa_mcalign *a = pa_mcalign_new(4, NULL); + * + * for (;;) { + * pa_memchunk input; + * + * ... fill input ... + * + * pa_mcalign_push(m, &input); + * pa_memblock_unref(input.memblock); + * + * for (;;) { + * pa_memchunk output; + * + * if (pa_mcalign_pop(m, &output) < 0) + * break; + * + * ... consume output ... + * + * pa_memblock_unref(output.memblock); + * } + * } + * + * pa_memchunk_free(a); + * */ + +typedef struct pa_mcalign pa_mcalign; + +pa_mcalign *pa_mcalign_new(size_t base, pa_memblock_stat *s); +void pa_mcalign_free(pa_mcalign *m); + +/* Push a new memchunk into the aligner. The caller of this routine + * has to free the memchunk by himself. */ +void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c); + +/* Pop a new memchunk from the aligner. Returns 0 when sucessful, + * nonzero otherwise. */ +int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c); + +#endif diff --git a/src/polypcore/memblock.c b/src/polypcore/memblock.c new file mode 100644 index 00000000..8da53525 --- /dev/null +++ b/src/polypcore/memblock.c @@ -0,0 +1,169 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "memblock.h" +#include "xmalloc.h" + +static void stat_add(pa_memblock*m, pa_memblock_stat *s) { + assert(m); + + if (!s) { + m->stat = NULL; + return; + } + + m->stat = pa_memblock_stat_ref(s); + s->total++; + s->allocated++; + s->total_size += m->length; + s->allocated_size += m->length; +} + +static void stat_remove(pa_memblock *m) { + assert(m); + + if (!m->stat) + return; + + m->stat->total--; + m->stat->total_size -= m->length; + + pa_memblock_stat_unref(m->stat); + m->stat = NULL; +} + +pa_memblock *pa_memblock_new(size_t length, pa_memblock_stat*s) { + pa_memblock *b = pa_xmalloc(sizeof(pa_memblock)+length); + b->type = PA_MEMBLOCK_APPENDED; + b->ref = 1; + b->length = length; + b->data = b+1; + b->free_cb = NULL; + b->read_only = 0; + stat_add(b, s); + return b; +} + +pa_memblock *pa_memblock_new_dynamic(void *d, size_t length, pa_memblock_stat*s) { + pa_memblock *b = pa_xmalloc(sizeof(pa_memblock)); + b->type = PA_MEMBLOCK_DYNAMIC; + b->ref = 1; + b->length = length; + b->data = d; + b->free_cb = NULL; + b->read_only = 0; + stat_add(b, s); + return b; +} + +pa_memblock *pa_memblock_new_fixed(void *d, size_t length, int read_only, pa_memblock_stat*s) { + pa_memblock *b = pa_xmalloc(sizeof(pa_memblock)); + b->type = PA_MEMBLOCK_FIXED; + b->ref = 1; + b->length = length; + b->data = d; + b->free_cb = NULL; + b->read_only = read_only; + stat_add(b, s); + return b; +} + +pa_memblock *pa_memblock_new_user(void *d, size_t length, void (*free_cb)(void *p), int read_only, pa_memblock_stat*s) { + pa_memblock *b; + assert(d && length && free_cb); + b = pa_xmalloc(sizeof(pa_memblock)); + b->type = PA_MEMBLOCK_USER; + b->ref = 1; + b->length = length; + b->data = d; + b->free_cb = free_cb; + b->read_only = read_only; + stat_add(b, s); + return b; +} + +pa_memblock* pa_memblock_ref(pa_memblock*b) { + assert(b && b->ref >= 1); + b->ref++; + return b; +} + +void pa_memblock_unref(pa_memblock*b) { + assert(b && b->ref >= 1); + + if ((--(b->ref)) == 0) { + stat_remove(b); + + if (b->type == PA_MEMBLOCK_USER) { + assert(b->free_cb); + b->free_cb(b->data); + } else if (b->type == PA_MEMBLOCK_DYNAMIC) + pa_xfree(b->data); + + pa_xfree(b); + } +} + +void pa_memblock_unref_fixed(pa_memblock *b) { + assert(b && b->ref >= 1 && b->type == PA_MEMBLOCK_FIXED); + + if (b->ref == 1) + pa_memblock_unref(b); + else { + b->data = pa_xmemdup(b->data, b->length); + b->type = PA_MEMBLOCK_DYNAMIC; + b->ref--; + } +} + +pa_memblock_stat* pa_memblock_stat_new(void) { + pa_memblock_stat *s; + + s = pa_xmalloc(sizeof(pa_memblock_stat)); + s->ref = 1; + s->total = s->total_size = s->allocated = s->allocated_size = 0; + + return s; +} + +void pa_memblock_stat_unref(pa_memblock_stat *s) { + assert(s && s->ref >= 1); + + if (!(--(s->ref))) { + assert(!s->total); + pa_xfree(s); + } +} + +pa_memblock_stat * pa_memblock_stat_ref(pa_memblock_stat *s) { + assert(s); + s->ref++; + return s; +} diff --git a/src/polypcore/memblock.h b/src/polypcore/memblock.h new file mode 100644 index 00000000..c5751406 --- /dev/null +++ b/src/polypcore/memblock.h @@ -0,0 +1,87 @@ +#ifndef foomemblockhfoo +#define foomemblockhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/* A pa_memblock is a reference counted memory block. Polypaudio + * passed references to pa_memblocks around instead of copying + * data. See pa_memchunk for a structure that describes parts of + * memory blocks. */ + +/* The type of memory this block points to */ +typedef enum pa_memblock_type { + PA_MEMBLOCK_FIXED, /* data is a pointer to fixed memory that needs not to be freed */ + PA_MEMBLOCK_APPENDED, /* The most common kind: the data is appended to the memory block */ + PA_MEMBLOCK_DYNAMIC, /* data is a pointer to some memory allocated with pa_xmalloc() */ + PA_MEMBLOCK_USER /* User supplied memory, to be freed with free_cb */ +} pa_memblock_type_t; + +/* A structure of keeping memory block statistics */ +/* Maintains statistics about memory blocks */ +typedef struct pa_memblock_stat { + int ref; + unsigned total; + unsigned total_size; + unsigned allocated; + unsigned allocated_size; +} pa_memblock_stat; + +typedef struct pa_memblock { + pa_memblock_type_t type; + unsigned ref; /* the reference counter */ + int read_only; /* boolean */ + size_t length; + void *data; + void (*free_cb)(void *p); /* If type == PA_MEMBLOCK_USER this points to a function for freeing this memory block */ + pa_memblock_stat *stat; +} pa_memblock; + +/* Allocate a new memory block of type PA_MEMBLOCK_APPENDED */ +pa_memblock *pa_memblock_new(size_t length, pa_memblock_stat*s); + +/* Allocate a new memory block of type PA_MEMBLOCK_DYNAMIC. The pointer data is to be maintained be the memory block */ +pa_memblock *pa_memblock_new_dynamic(void *data, size_t length, pa_memblock_stat*s); + +/* Allocate a new memory block of type PA_MEMBLOCK_FIXED */ +pa_memblock *pa_memblock_new_fixed(void *data, size_t length, int read_only, pa_memblock_stat*s); + +/* Allocate a new memory block of type PA_MEMBLOCK_USER */ +pa_memblock *pa_memblock_new_user(void *data, size_t length, void (*free_cb)(void *p), int read_only, pa_memblock_stat*s); + +void pa_memblock_unref(pa_memblock*b); +pa_memblock* pa_memblock_ref(pa_memblock*b); + +/* This special unref function has to be called by the owner of the +memory of a static memory block when he wants to release all +references to the memory. This causes the memory to be copied and +converted into a PA_MEMBLOCK_DYNAMIC type memory block */ +void pa_memblock_unref_fixed(pa_memblock*b); + + +pa_memblock_stat* pa_memblock_stat_new(void); +void pa_memblock_stat_unref(pa_memblock_stat *s); +pa_memblock_stat * pa_memblock_stat_ref(pa_memblock_stat *s); + +#endif diff --git a/src/polypcore/memblockq.c b/src/polypcore/memblockq.c new file mode 100644 index 00000000..ba6b76ea --- /dev/null +++ b/src/polypcore/memblockq.c @@ -0,0 +1,343 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "memblockq.h" +#include "xmalloc.h" +#include "log.h" +#include "mcalign.h" + +struct memblock_list { + struct memblock_list *next, *prev; + pa_memchunk chunk; +}; + +struct pa_memblockq { + struct memblock_list *blocks, *blocks_tail; + unsigned n_blocks; + size_t current_length, maxlength, tlength, base, prebuf, orig_prebuf, minreq; + pa_mcalign *mcalign; + pa_memblock_stat *memblock_stat; +}; + +pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t base, size_t prebuf, size_t minreq, pa_memblock_stat *s) { + pa_memblockq* bq; + assert(maxlength && base && maxlength); + + bq = pa_xmalloc(sizeof(pa_memblockq)); + bq->blocks = bq->blocks_tail = 0; + bq->n_blocks = 0; + + bq->current_length = 0; + + pa_log_debug(__FILE__": memblockq requested: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", maxlength, tlength, base, prebuf, minreq); + + bq->base = base; + + bq->maxlength = ((maxlength+base-1)/base)*base; + assert(bq->maxlength >= base); + + bq->tlength = ((tlength+base-1)/base)*base; + if (!bq->tlength || bq->tlength >= bq->maxlength) + bq->tlength = bq->maxlength; + + bq->minreq = (minreq/base)*base; + if (bq->minreq == 0) + bq->minreq = 1; + + bq->prebuf = (prebuf == (size_t) -1) ? bq->maxlength/2 : prebuf; + bq->prebuf = (bq->prebuf/base)*base; + if (bq->prebuf > bq->maxlength) + bq->prebuf = bq->maxlength; + + if (bq->prebuf > bq->tlength - bq->minreq) + bq->prebuf = bq->tlength - bq->minreq; + + bq->orig_prebuf = bq->prebuf; + + pa_log_debug(__FILE__": memblockq sanitized: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", bq->maxlength, bq->tlength, bq->base, bq->prebuf, bq->minreq); + + bq->mcalign = NULL; + + bq->memblock_stat = s; + + return bq; +} + +void pa_memblockq_free(pa_memblockq* bq) { + assert(bq); + + pa_memblockq_flush(bq); + + if (bq->mcalign) + pa_mcalign_free(bq->mcalign); + + pa_xfree(bq); +} + +void pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *chunk, size_t delta) { + struct memblock_list *q; + assert(bq && chunk && chunk->memblock && chunk->length && (chunk->length % bq->base) == 0); + + pa_memblockq_seek(bq, delta); + + if (bq->blocks_tail && bq->blocks_tail->chunk.memblock == chunk->memblock) { + /* Try to merge memory chunks */ + + if (bq->blocks_tail->chunk.index+bq->blocks_tail->chunk.length == chunk->index) { + bq->blocks_tail->chunk.length += chunk->length; + bq->current_length += chunk->length; + return; + } + } + + q = pa_xmalloc(sizeof(struct memblock_list)); + + q->chunk = *chunk; + pa_memblock_ref(q->chunk.memblock); + assert(q->chunk.index+q->chunk.length <= q->chunk.memblock->length); + q->next = NULL; + if ((q->prev = bq->blocks_tail)) + bq->blocks_tail->next = q; + else + bq->blocks = q; + + bq->blocks_tail = q; + + bq->n_blocks++; + bq->current_length += chunk->length; + + pa_memblockq_shorten(bq, bq->maxlength); +} + +int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { + assert(bq && chunk); + + if (!bq->blocks || bq->current_length < bq->prebuf) + return -1; + + bq->prebuf = 0; + + *chunk = bq->blocks->chunk; + pa_memblock_ref(chunk->memblock); + + return 0; +} + +void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length) { + assert(bq && chunk && length); + + if (!bq->blocks || memcmp(&bq->blocks->chunk, chunk, sizeof(pa_memchunk))) + return; + + assert(length <= bq->blocks->chunk.length); + pa_memblockq_skip(bq, length); +} + +static void remove_block(pa_memblockq *bq, struct memblock_list *q) { + assert(bq && q); + + if (q->prev) + q->prev->next = q->next; + else { + assert(bq->blocks == q); + bq->blocks = q->next; + } + + if (q->next) + q->next->prev = q->prev; + else { + assert(bq->blocks_tail == q); + bq->blocks_tail = q->prev; + } + + pa_memblock_unref(q->chunk.memblock); + pa_xfree(q); + + bq->n_blocks--; +} + +void pa_memblockq_skip(pa_memblockq *bq, size_t length) { + assert(bq && length && (length % bq->base) == 0); + + while (length > 0) { + size_t l = length; + assert(bq->blocks && bq->current_length >= length); + + if (l > bq->blocks->chunk.length) + l = bq->blocks->chunk.length; + + bq->blocks->chunk.index += l; + bq->blocks->chunk.length -= l; + bq->current_length -= l; + + if (!bq->blocks->chunk.length) + remove_block(bq, bq->blocks); + + length -= l; + } +} + +void pa_memblockq_shorten(pa_memblockq *bq, size_t length) { + size_t l; + assert(bq); + + if (bq->current_length <= length) + return; + + /*pa_log(__FILE__": Warning! pa_memblockq_shorten()\n");*/ + + l = bq->current_length - length; + l /= bq->base; + l *= bq->base; + + pa_memblockq_skip(bq, l); +} + + +void pa_memblockq_empty(pa_memblockq *bq) { + assert(bq); + pa_memblockq_shorten(bq, 0); +} + +int pa_memblockq_is_readable(pa_memblockq *bq) { + assert(bq); + + return bq->current_length && (bq->current_length >= bq->prebuf); +} + +int pa_memblockq_is_writable(pa_memblockq *bq, size_t length) { + assert(bq); + + return bq->current_length + length <= bq->tlength; +} + +uint32_t pa_memblockq_get_length(pa_memblockq *bq) { + assert(bq); + return bq->current_length; +} + +uint32_t pa_memblockq_missing(pa_memblockq *bq) { + size_t l; + assert(bq); + + if (bq->current_length >= bq->tlength) + return 0; + + l = bq->tlength - bq->current_length; + assert(l); + + return (l >= bq->minreq) ? l : 0; +} + +void pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk, size_t delta) { + pa_memchunk rchunk; + assert(bq && chunk && bq->base); + + if (bq->base == 1) { + pa_memblockq_push(bq, chunk, delta); + return; + } + + if (!bq->mcalign) { + bq->mcalign = pa_mcalign_new(bq->base, bq->memblock_stat); + assert(bq->mcalign); + } + + pa_mcalign_push(bq->mcalign, chunk); + + while (pa_mcalign_pop(bq->mcalign, &rchunk) >= 0) { + pa_memblockq_push(bq, &rchunk, delta); + pa_memblock_unref(rchunk.memblock); + delta = 0; + } +} + +uint32_t pa_memblockq_get_minreq(pa_memblockq *bq) { + assert(bq); + return bq->minreq; +} + +void pa_memblockq_prebuf_disable(pa_memblockq *bq) { + assert(bq); + bq->prebuf = 0; +} + +void pa_memblockq_prebuf_reenable(pa_memblockq *bq) { + assert(bq); + bq->prebuf = bq->orig_prebuf; +} + +void pa_memblockq_seek(pa_memblockq *bq, size_t length) { + assert(bq); + + if (!length) + return; + + while (length >= bq->base) { + size_t l = length; + if (!bq->current_length) + return; + + assert(bq->blocks_tail); + + if (l > bq->blocks_tail->chunk.length) + l = bq->blocks_tail->chunk.length; + + bq->blocks_tail->chunk.length -= l; + bq->current_length -= l; + + if (bq->blocks_tail->chunk.length == 0) + remove_block(bq, bq->blocks); + + length -= l; + } +} + +void pa_memblockq_flush(pa_memblockq *bq) { + struct memblock_list *l; + assert(bq); + + while ((l = bq->blocks)) { + bq->blocks = l->next; + pa_memblock_unref(l->chunk.memblock); + pa_xfree(l); + } + + bq->blocks_tail = NULL; + bq->n_blocks = 0; + bq->current_length = 0; +} + +uint32_t pa_memblockq_get_tlength(pa_memblockq *bq) { + assert(bq); + return bq->tlength; +} diff --git a/src/polypcore/memblockq.h b/src/polypcore/memblockq.h new file mode 100644 index 00000000..1695daba --- /dev/null +++ b/src/polypcore/memblockq.h @@ -0,0 +1,104 @@ +#ifndef foomemblockqhfoo +#define foomemblockqhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "memblock.h" +#include "memchunk.h" + +/* A memblockq is a queue of pa_memchunks (yepp, the name is not + * perfect). It is similar to the ring buffers used by most other + * audio software. In contrast to a ring buffer this memblockq data + * type doesn't need to copy any data around, it just maintains + * references to reference counted memory blocks. */ + +typedef struct pa_memblockq pa_memblockq; + +/* Parameters: + - maxlength: maximum length of queue. If more data is pushed into the queue, data from the front is dropped + - length: the target length of the queue. + - base: a base value for all metrics. Only multiples of this value are popped from the queue + - prebuf: before passing the first byte out, make sure that enough bytes are in the queue + - minreq: pa_memblockq_missing() will only return values greater than this value +*/ +pa_memblockq* pa_memblockq_new(size_t maxlength, + size_t tlength, + size_t base, + size_t prebuf, + size_t minreq, + pa_memblock_stat *s); +void pa_memblockq_free(pa_memblockq*bq); + +/* Push a new memory chunk into the queue. Optionally specify a value for future cancellation. */ +void pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *chunk, size_t delta); + +/* Same as pa_memblockq_push(), however chunks are filtered through a mcalign object, and thus aligned to multiples of base */ +void pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk, size_t delta); + +/* Return a copy of the next memory chunk in the queue. It is not removed from the queue */ +int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk); + +/* Drop the specified bytes from the queue, only valid aufter pa_memblockq_peek() */ +void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length); + +/* Drop the specified bytes from the queue */ +void pa_memblockq_skip(pa_memblockq *bq, size_t length); + +/* Shorten the pa_memblockq to the specified length by dropping data at the end of the queue */ +void pa_memblockq_shorten(pa_memblockq *bq, size_t length); + +/* Empty the pa_memblockq */ +void pa_memblockq_empty(pa_memblockq *bq); + +/* Test if the pa_memblockq is currently readable, that is, more data than base */ +int pa_memblockq_is_readable(pa_memblockq *bq); + +/* Test if the pa_memblockq is currently writable for the specified amount of bytes */ +int pa_memblockq_is_writable(pa_memblockq *bq, size_t length); + +/* Return the length of the queue in bytes */ +uint32_t pa_memblockq_get_length(pa_memblockq *bq); + +/* Return how many bytes are missing in queue to the specified fill amount */ +uint32_t pa_memblockq_missing(pa_memblockq *bq); + +/* Returns the minimal request value */ +uint32_t pa_memblockq_get_minreq(pa_memblockq *bq); + +/* Force disabling of pre-buf even when the pre-buffer is not yet filled */ +void pa_memblockq_prebuf_disable(pa_memblockq *bq); + +/* Reenable pre-buf to the initial level */ +void pa_memblockq_prebuf_reenable(pa_memblockq *bq); + +/* Manipulate the write pointer */ +void pa_memblockq_seek(pa_memblockq *bq, size_t delta); + +/* Flush the queue */ +void pa_memblockq_flush(pa_memblockq *bq); + +/* Get Target length */ +uint32_t pa_memblockq_get_tlength(pa_memblockq *bq); + +#endif diff --git a/src/polypcore/memchunk.c b/src/polypcore/memchunk.c new file mode 100644 index 00000000..bfd74f9e --- /dev/null +++ b/src/polypcore/memchunk.c @@ -0,0 +1,58 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "memchunk.h" +#include "xmalloc.h" + +void pa_memchunk_make_writable(pa_memchunk *c, pa_memblock_stat *s, size_t min) { + pa_memblock *n; + size_t l; + assert(c && c->memblock && c->memblock->ref >= 1); + + if (c->memblock->ref == 1 && !c->memblock->read_only && c->memblock->length >= c->index+min) + return; + + l = c->length; + if (l < min) + l = min; + + n = pa_memblock_new(l, s); + memcpy(n->data, (uint8_t*) c->memblock->data + c->index, c->length); + pa_memblock_unref(c->memblock); + c->memblock = n; + c->index = 0; +} + +void pa_memchunk_reset(pa_memchunk *c) { + assert(c); + + c->memblock = NULL; + c->length = c->index = 0; +} diff --git a/src/polypcore/memchunk.h b/src/polypcore/memchunk.h new file mode 100644 index 00000000..4eefc8c1 --- /dev/null +++ b/src/polypcore/memchunk.h @@ -0,0 +1,45 @@ +#ifndef foomemchunkhfoo +#define foomemchunkhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "memblock.h" + +/* A memchunk describes a part of a memblock. In contrast to the memblock, a + * memchunk is not allocated dynamically or reference counted, instead + * it is usually stored on the stack and copied around */ + +typedef struct pa_memchunk { + pa_memblock *memblock; + size_t index, length; +} pa_memchunk; + +/* Make a memchunk writable, i.e. make sure that the caller may have + * exclusive access to the memblock and it is not read_only. If needed + * the memblock in the structure is replaced by a copy. */ +void pa_memchunk_make_writable(pa_memchunk *c, pa_memblock_stat *s, size_t min); + +/* Invalidate a memchunk. This does not free the cotaining memblock, + * but sets all members to zero. */ +void pa_memchunk_reset(pa_memchunk *c); + +#endif diff --git a/src/polypcore/modargs.c b/src/polypcore/modargs.c new file mode 100644 index 00000000..07062946 --- /dev/null +++ b/src/polypcore/modargs.c @@ -0,0 +1,260 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "hashmap.h" +#include "modargs.h" +#include "idxset.h" +#include "sample-util.h" +#include "namereg.h" +#include "sink.h" +#include "source.h" +#include "xmalloc.h" +#include "util.h" + +struct entry { + char *key, *value; +}; + +static int add_key_value(pa_hashmap *map, char *key, char *value, const char* const valid_keys[]) { + struct entry *e; + assert(map && key && value); + + if (valid_keys) { + const char*const* v; + for (v = valid_keys; *v; v++) + if (strcmp(*v, key) == 0) + break; + + if (!*v) { + pa_xfree(key); + pa_xfree(value); + return -1; + } + } + + e = pa_xmalloc(sizeof(struct entry)); + e->key = key; + e->value = value; + pa_hashmap_put(map, key, e); + return 0; +} + +pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) { + pa_hashmap *map = NULL; + + map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + assert(map); + + if (args) { + enum { WHITESPACE, KEY, VALUE_START, VALUE_SIMPLE, VALUE_DOUBLE_QUOTES, VALUE_TICKS } state; + const char *p, *key, *value; + size_t key_len = 0, value_len = 0; + + key = value = NULL; + state = WHITESPACE; + for (p = args; *p; p++) { + switch (state) { + case WHITESPACE: + if (*p == '=') + goto fail; + else if (!isspace(*p)) { + key = p; + state = KEY; + key_len = 1; + } + break; + case KEY: + if (*p == '=') + state = VALUE_START; + else + key_len++; + break; + case VALUE_START: + if (*p == '\'') { + state = VALUE_TICKS; + value = p+1; + value_len = 0; + } else if (*p == '"') { + state = VALUE_DOUBLE_QUOTES; + value = p+1; + value_len = 0; + } else if (isspace(*p)) { + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0) + goto fail; + state = WHITESPACE; + } else { + state = VALUE_SIMPLE; + value = p; + value_len = 1; + } + break; + case VALUE_SIMPLE: + if (isspace(*p)) { + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) + goto fail; + state = WHITESPACE; + } else + value_len++; + break; + case VALUE_DOUBLE_QUOTES: + if (*p == '"') { + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) + goto fail; + state = WHITESPACE; + } else + value_len++; + break; + case VALUE_TICKS: + if (*p == '\'') { + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) + goto fail; + state = WHITESPACE; + } else + value_len++; + break; + } + } + + if (state == VALUE_START) { + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0) + goto fail; + } else if (state == VALUE_SIMPLE) { + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(value), valid_keys) < 0) + goto fail; + } else if (state != WHITESPACE) + goto fail; + } + + return (pa_modargs*) map; + +fail: + + if (map) + pa_modargs_free((pa_modargs*) map); + + return NULL; +} + + +static void free_func(void *p, PA_GCC_UNUSED void*userdata) { + struct entry *e = p; + assert(e); + pa_xfree(e->key); + pa_xfree(e->value); + pa_xfree(e); +} + +void pa_modargs_free(pa_modargs*ma) { + pa_hashmap *map = (pa_hashmap*) ma; + pa_hashmap_free(map, free_func, NULL); +} + +const char *pa_modargs_get_value(pa_modargs *ma, const char *key, const char *def) { + pa_hashmap *map = (pa_hashmap*) ma; + struct entry*e; + + if (!(e = pa_hashmap_get(map, key))) + return def; + + return e->value; +} + +int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value) { + const char *v; + assert(ma && key && value); + + if (!(v = pa_modargs_get_value(ma, key, NULL))) + return 0; + + if (pa_atou(v, value) < 0) + return -1; + + return 0; +} + +int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value) { + const char *v; + assert(ma && key && value); + + if (!(v = pa_modargs_get_value(ma, key, NULL))) + return 0; + + if (pa_atoi(v, value) < 0) + return -1; + + return 0; +} + +int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value) { + const char *v; + int r; + assert(ma && key && value); + + if (!(v = pa_modargs_get_value(ma, key, NULL))) + return 0; + + if (!*v) + return -1; + + if ((r = pa_parse_boolean(v)) < 0) + return -1; + + *value = r; + return 0; +} + +int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) { + const char *format; + uint32_t channels; + pa_sample_spec ss; + assert(ma && rss); + +/* DEBUG_TRAP;*/ + + ss = *rss; + if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0) + return -1; + + channels = ss.channels; + if ((pa_modargs_get_value_u32(ma, "channels", &channels)) < 0) + return -1; + ss.channels = (uint8_t) channels; + + if ((format = pa_modargs_get_value(ma, "format", NULL))) + if ((ss.format = pa_parse_sample_format(format)) < 0) + return -1; + + if (!pa_sample_spec_valid(&ss)) + return -1; + + *rss = ss; + + return 0; +} diff --git a/src/polypcore/modargs.h b/src/polypcore/modargs.h new file mode 100644 index 00000000..678ea1a7 --- /dev/null +++ b/src/polypcore/modargs.h @@ -0,0 +1,49 @@ +#ifndef foomodargshfoo +#define foomodargshfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include "core.h" + +typedef struct pa_modargs pa_modargs; + +/* A generic parser for module arguments */ + +/* Parse the string args. The NULL-terminated array keys contains all valid arguments. */ +pa_modargs *pa_modargs_new(const char *args, const char* const keys[]); +void pa_modargs_free(pa_modargs*ma); + +/* Return the module argument for the specified name as a string. If + * the argument was not specified, return def instead.*/ +const char *pa_modargs_get_value(pa_modargs *ma, const char *key, const char *def); + +/* Return a module argument as unsigned 32bit value in *value */ +int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value); +int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value); +int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value); + +/* Return sample spec data from the three arguments "rate", "format" and "channels" */ +int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *ss); + +#endif diff --git a/src/polypcore/modinfo.c b/src/polypcore/modinfo.c new file mode 100644 index 00000000..53440612 --- /dev/null +++ b/src/polypcore/modinfo.c @@ -0,0 +1,84 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "xmalloc.h" +#include "util.h" +#include "modinfo.h" +#include "log.h" + +#define PA_SYMBOL_AUTHOR "pa__get_author" +#define PA_SYMBOL_DESCRIPTION "pa__get_description" +#define PA_SYMBOL_USAGE "pa__get_usage" +#define PA_SYMBOL_VERSION "pa__get_version" + +pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl) { + pa_modinfo *i; + const char* (*func)(void); + assert(dl); + + i = pa_xmalloc0(sizeof(pa_modinfo)); + + if ((func = (const char* (*)(void)) lt_dlsym(dl, PA_SYMBOL_AUTHOR))) + i->author = pa_xstrdup(func()); + + if ((func = (const char* (*)(void)) lt_dlsym(dl, PA_SYMBOL_DESCRIPTION))) + i->description = pa_xstrdup(func()); + + if ((func = (const char* (*)(void)) lt_dlsym(dl, PA_SYMBOL_USAGE))) + i->usage = pa_xstrdup(func()); + + if ((func = (const char* (*)(void)) lt_dlsym(dl, PA_SYMBOL_VERSION))) + i->version = pa_xstrdup(func()); + + return i; +} + +pa_modinfo *pa_modinfo_get_by_name(const char *name) { + lt_dlhandle dl; + pa_modinfo *i; + assert(name); + + if (!(dl = lt_dlopenext(name))) { + pa_log(__FILE__": Failed to open module \"%s\": %s\n", name, lt_dlerror()); + return NULL; + } + + i = pa_modinfo_get_by_handle(dl); + lt_dlclose(dl); + + return i; +} + +void pa_modinfo_free(pa_modinfo *i) { + assert(i); + pa_xfree(i->author); + pa_xfree(i->description); + pa_xfree(i->usage); + pa_xfree(i->version); + pa_xfree(i); +} diff --git a/src/polypcore/modinfo.h b/src/polypcore/modinfo.h new file mode 100644 index 00000000..53176147 --- /dev/null +++ b/src/polypcore/modinfo.h @@ -0,0 +1,43 @@ +#ifndef foomodinfohfoo +#define foomodinfohfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* Some functions for reading module meta data from Polypaudio modules */ + +typedef struct pa_modinfo { + char *author; + char *description; + char *usage; + char *version; +} pa_modinfo; + +/* Read meta data from an libtool handle */ +pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl); + +/* Read meta data from a module file */ +pa_modinfo *pa_modinfo_get_by_name(const char *name); + +/* Free meta data */ +void pa_modinfo_free(pa_modinfo *i); + +#endif diff --git a/src/polypcore/module.c b/src/polypcore/module.c new file mode 100644 index 00000000..499ea299 --- /dev/null +++ b/src/polypcore/module.c @@ -0,0 +1,275 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "module.h" +#include "xmalloc.h" +#include "subscribe.h" +#include "log.h" +#include "util.h" + +#define PA_SYMBOL_INIT "pa__init" +#define PA_SYMBOL_DONE "pa__done" + +#define UNLOAD_POLL_TIME 2 + +static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + pa_core *c = userdata; + struct timeval ntv; + assert(c && c->mainloop == m && c->module_auto_unload_event == e); + + pa_module_unload_unused(c); + + pa_gettimeofday(&ntv); + ntv.tv_sec += UNLOAD_POLL_TIME; + m->time_restart(e, &ntv); +} + +pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { + pa_module *m = NULL; + int r; + + assert(c && name); + + if (c->disallow_module_loading) + goto fail; + + m = pa_xmalloc(sizeof(pa_module)); + + m->name = pa_xstrdup(name); + m->argument = pa_xstrdup(argument); + + if (!(m->dl = lt_dlopenext(name))) { + pa_log(__FILE__": Failed to open module \"%s\": %s\n", name, lt_dlerror()); + goto fail; + } + + if (!(m->init = (int (*)(pa_core *_c, pa_module*_m)) lt_dlsym(m->dl, PA_SYMBOL_INIT))) { + pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.\n", name); + goto fail; + } + + if (!(m->done = (void (*)(pa_core *_c, pa_module*_m)) lt_dlsym(m->dl, PA_SYMBOL_DONE))) { + pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_DONE"\" not found.\n", name); + goto fail; + } + + m->userdata = NULL; + m->core = c; + m->n_used = -1; + m->auto_unload = 0; + m->unload_requested = 0; + + assert(m->init); + if (m->init(c, m) < 0) { + pa_log_error(__FILE__": Failed to load module \"%s\" (argument: \"%s\"): initialization failed.\n", name, argument ? argument : ""); + goto fail; + } + + if (!c->modules) + c->modules = pa_idxset_new(NULL, NULL); + + if (!c->module_auto_unload_event) { + struct timeval ntv; + pa_gettimeofday(&ntv); + ntv.tv_sec += UNLOAD_POLL_TIME; + c->module_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); + } + assert(c->module_auto_unload_event); + + assert(c->modules); + r = pa_idxset_put(c->modules, m, &m->index); + assert(r >= 0 && m->index != PA_IDXSET_INVALID); + + pa_log_info(__FILE__": Loaded \"%s\" (index: #%u; argument: \"%s\").\n", m->name, m->index, m->argument ? m->argument : ""); + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_NEW, m->index); + + return m; + +fail: + + if (m) { + pa_xfree(m->argument); + pa_xfree(m->name); + + if (m->dl) + lt_dlclose(m->dl); + + pa_xfree(m); + } + + return NULL; +} + +static void pa_module_free(pa_module *m) { + assert(m && m->done && m->core); + + if (m->core->disallow_module_loading) + return; + + pa_log_info(__FILE__": Unloading \"%s\" (index: #%u).\n", m->name, m->index); + + m->done(m->core, m); + + lt_dlclose(m->dl); + + pa_log_info(__FILE__": Unloaded \"%s\" (index: #%u).\n", m->name, m->index); + + pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_REMOVE, m->index); + + pa_xfree(m->name); + pa_xfree(m->argument); + pa_xfree(m); +} + +void pa_module_unload(pa_core *c, pa_module *m) { + assert(c && m); + + assert(c->modules); + if (!(m = pa_idxset_remove_by_data(c->modules, m, NULL))) + return; + + pa_module_free(m); +} + +void pa_module_unload_by_index(pa_core *c, uint32_t idx) { + pa_module *m; + assert(c && idx != PA_IDXSET_INVALID); + + assert(c->modules); + if (!(m = pa_idxset_remove_by_index(c->modules, idx))) + return; + + pa_module_free(m); +} + +static void free_callback(void *p, PA_GCC_UNUSED void *userdata) { + pa_module *m = p; + assert(m); + pa_module_free(m); +} + +void pa_module_unload_all(pa_core *c) { + assert(c); + + if (!c->modules) + return; + + pa_idxset_free(c->modules, free_callback, NULL); + c->modules = NULL; + + if (c->module_auto_unload_event) { + c->mainloop->time_free(c->module_auto_unload_event); + c->module_auto_unload_event = NULL; + } + + if (c->module_defer_unload_event) { + c->mainloop->defer_free(c->module_defer_unload_event); + c->module_defer_unload_event = NULL; + } +} + +static int unused_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void *userdata) { + pa_module *m = p; + time_t *now = userdata; + assert(p && del && now); + + if (m->n_used == 0 && m->auto_unload && m->last_used_time+m->core->module_idle_time <= *now) { + pa_module_free(m); + *del = 1; + } + + return 0; +} + +void pa_module_unload_unused(pa_core *c) { + time_t now; + assert(c); + + if (!c->modules) + return; + + time(&now); + pa_idxset_foreach(c->modules, unused_callback, &now); +} + +static int unload_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, PA_GCC_UNUSED void *userdata) { + pa_module *m = p; + assert(m); + + if (m->unload_requested) { + pa_module_free(m); + *del = 1; + } + + return 0; +} + +static void defer_cb(pa_mainloop_api*api, pa_defer_event *e, void *userdata) { + pa_core *core = userdata; + api->defer_enable(e, 0); + + if (!core->modules) + return; + + pa_idxset_foreach(core->modules, unload_callback, NULL); + +} + +void pa_module_unload_request(pa_module *m) { + assert(m); + + m->unload_requested = 1; + + if (!m->core->module_defer_unload_event) + m->core->module_defer_unload_event = m->core->mainloop->defer_new(m->core->mainloop, defer_cb, m->core); + + m->core->mainloop->defer_enable(m->core->module_defer_unload_event, 1); +} + +void pa_module_set_used(pa_module*m, int used) { + assert(m); + + if (m->n_used != used) + pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_CHANGE, m->index); + + if (m->n_used != used && used == 0) + time(&m->last_used_time); + + m->n_used = used; +} + +pa_modinfo *pa_module_get_info(pa_module *m) { + assert(m); + + return pa_modinfo_get_by_handle(m->dl); +} diff --git a/src/polypcore/module.h b/src/polypcore/module.h new file mode 100644 index 00000000..6f137c15 --- /dev/null +++ b/src/polypcore/module.h @@ -0,0 +1,70 @@ +#ifndef foomodulehfoo +#define foomodulehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include "core.h" +#include "modinfo.h" + +typedef struct pa_module pa_module; + +struct pa_module { + pa_core *core; + char *name, *argument; + uint32_t index; + + lt_dlhandle dl; + + int (*init)(pa_core *c, pa_module*m); + void (*done)(pa_core *c, pa_module*m); + + void *userdata; + + int n_used; + int auto_unload; + time_t last_used_time; + + int unload_requested; +}; + +pa_module* pa_module_load(pa_core *c, const char *name, const char*argument); +void pa_module_unload(pa_core *c, pa_module *m); +void pa_module_unload_by_index(pa_core *c, uint32_t idx); + +void pa_module_unload_all(pa_core *c); +void pa_module_unload_unused(pa_core *c); + +void pa_module_unload_request(pa_module *m); + +void pa_module_set_used(pa_module*m, int used); + +#define PA_MODULE_AUTHOR(s) const char * pa__get_author(void) { return s; } +#define PA_MODULE_DESCRIPTION(s) const char * pa__get_description(void) { return s; } +#define PA_MODULE_USAGE(s) const char * pa__get_usage(void) { return s; } +#define PA_MODULE_VERSION(s) const char * pa__get_version(void) { return s; } + +pa_modinfo *pa_module_get_info(pa_module *m); + +#endif diff --git a/src/polypcore/namereg.c b/src/polypcore/namereg.c new file mode 100644 index 00000000..07fb485c --- /dev/null +++ b/src/polypcore/namereg.c @@ -0,0 +1,212 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "namereg.h" +#include "autoload.h" +#include "source.h" +#include "sink.h" +#include "xmalloc.h" +#include "subscribe.h" +#include "util.h" + +struct namereg_entry { + pa_namereg_type_t type; + char *name; + void *data; +}; + +void pa_namereg_free(pa_core *c) { + assert(c); + if (!c->namereg) + return; + assert(pa_hashmap_size(c->namereg) == 0); + pa_hashmap_free(c->namereg, NULL, NULL); +} + +const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, int fail) { + struct namereg_entry *e; + char *n = NULL; + int r; + + assert(c && name && data); + + if (!c->namereg) { + c->namereg = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + assert(c->namereg); + } + + if ((e = pa_hashmap_get(c->namereg, name)) && fail) + return NULL; + + if (!e) + n = pa_xstrdup(name); + else { + unsigned i; + size_t l = strlen(name); + n = pa_xmalloc(l+3); + + for (i = 1; i <= 99; i++) { + snprintf(n, l+2, "%s%u", name, i); + + if (!(e = pa_hashmap_get(c->namereg, n))) + break; + } + + if (e) { + pa_xfree(n); + return NULL; + } + } + + assert(n); + e = pa_xmalloc(sizeof(struct namereg_entry)); + e->type = type; + e->name = n; + e->data = data; + + r = pa_hashmap_put(c->namereg, e->name, e); + assert (r >= 0); + + return e->name; + +} + +void pa_namereg_unregister(pa_core *c, const char *name) { + struct namereg_entry *e; + assert(c && name); + + e = pa_hashmap_remove(c->namereg, name); + assert(e); + + pa_xfree(e->name); + pa_xfree(e); +} + +void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int autoload) { + struct namereg_entry *e; + uint32_t idx; + assert(c); + + if (!name) { + if (type == PA_NAMEREG_SOURCE) + name = pa_namereg_get_default_source_name(c); + else if (type == PA_NAMEREG_SINK) + name = pa_namereg_get_default_sink_name(c); + } + + if (!name) + return NULL; + + if (c->namereg && (e = pa_hashmap_get(c->namereg, name))) + if (e->type == e->type) + return e->data; + + if (pa_atou(name, &idx) < 0) { + + if (autoload) { + pa_autoload_request(c, name, type); + + if (c->namereg && (e = pa_hashmap_get(c->namereg, name))) + if (e->type == e->type) + return e->data; + } + + return NULL; + } + + if (type == PA_NAMEREG_SINK) + return pa_idxset_get_by_index(c->sinks, idx); + else if (type == PA_NAMEREG_SOURCE) + return pa_idxset_get_by_index(c->sources, idx); + else if (type == PA_NAMEREG_SAMPLE && c->scache) + return pa_idxset_get_by_index(c->scache, idx); + + return NULL; +} + +void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type) { + char **s; + assert(c && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); + + s = type == PA_NAMEREG_SINK ? &c->default_sink_name : &c->default_source_name; + assert(s); + + if (!name && !*s) + return; + + if (name && *s && !strcmp(name, *s)) + return; + + pa_xfree(*s); + *s = pa_xstrdup(name); + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); +} + +const char *pa_namereg_get_default_sink_name(pa_core *c) { + pa_sink *s; + assert(c); + + if (c->default_sink_name) + return c->default_sink_name; + + if ((s = pa_idxset_first(c->sinks, NULL))) + pa_namereg_set_default(c, s->name, PA_NAMEREG_SINK); + + if (c->default_sink_name) + return c->default_sink_name; + + return NULL; +} + +const char *pa_namereg_get_default_source_name(pa_core *c) { + pa_source *s; + uint32_t idx; + + assert(c); + + if (c->default_source_name) + return c->default_source_name; + + for (s = pa_idxset_first(c->sources, &idx); s; s = pa_idxset_next(c->sources, &idx)) + if (!s->monitor_of) { + pa_namereg_set_default(c, s->name, PA_NAMEREG_SOURCE); + break; + } + + if (!c->default_source_name) + if ((s = pa_idxset_first(c->sources, NULL))) + pa_namereg_set_default(c, s->name, PA_NAMEREG_SOURCE); + + if (c->default_source_name) + return c->default_source_name; + + return NULL; +} diff --git a/src/polypcore/namereg.h b/src/polypcore/namereg.h new file mode 100644 index 00000000..961fd44b --- /dev/null +++ b/src/polypcore/namereg.h @@ -0,0 +1,43 @@ +#ifndef foonamereghfoo +#define foonamereghfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" + +typedef enum pa_namereg_type { + PA_NAMEREG_SINK, + PA_NAMEREG_SOURCE, + PA_NAMEREG_SAMPLE +} pa_namereg_type_t; + +void pa_namereg_free(pa_core *c); + +const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, int fail); +void pa_namereg_unregister(pa_core *c, const char *name); +void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int autoload); +void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type); + +const char *pa_namereg_get_default_sink_name(pa_core *c); +const char *pa_namereg_get_default_source_name(pa_core *c); + +#endif diff --git a/src/polypcore/native-common.h b/src/polypcore/native-common.h new file mode 100644 index 00000000..78ae721e --- /dev/null +++ b/src/polypcore/native-common.h @@ -0,0 +1,114 @@ +#ifndef foonativecommonhfoo +#define foonativecommonhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +PA_C_DECL_BEGIN + +enum { + PA_COMMAND_ERROR, + PA_COMMAND_TIMEOUT, /* pseudo command */ + PA_COMMAND_REPLY, + PA_COMMAND_CREATE_PLAYBACK_STREAM, + PA_COMMAND_DELETE_PLAYBACK_STREAM, + PA_COMMAND_CREATE_RECORD_STREAM, + PA_COMMAND_DELETE_RECORD_STREAM, + PA_COMMAND_EXIT, + PA_COMMAND_REQUEST, + PA_COMMAND_AUTH, + PA_COMMAND_SET_CLIENT_NAME, + PA_COMMAND_LOOKUP_SINK, + PA_COMMAND_LOOKUP_SOURCE, + PA_COMMAND_DRAIN_PLAYBACK_STREAM, + PA_COMMAND_PLAYBACK_STREAM_KILLED, + PA_COMMAND_RECORD_STREAM_KILLED, + PA_COMMAND_STAT, + PA_COMMAND_GET_PLAYBACK_LATENCY, + PA_COMMAND_CREATE_UPLOAD_STREAM, + PA_COMMAND_DELETE_UPLOAD_STREAM, + PA_COMMAND_FINISH_UPLOAD_STREAM, + PA_COMMAND_PLAY_SAMPLE, + PA_COMMAND_REMOVE_SAMPLE, + + PA_COMMAND_GET_SERVER_INFO, + PA_COMMAND_GET_SINK_INFO, + PA_COMMAND_GET_SINK_INFO_LIST, + PA_COMMAND_GET_SOURCE_INFO, + PA_COMMAND_GET_SOURCE_INFO_LIST, + PA_COMMAND_GET_MODULE_INFO, + PA_COMMAND_GET_MODULE_INFO_LIST, + PA_COMMAND_GET_CLIENT_INFO, + PA_COMMAND_GET_CLIENT_INFO_LIST, + PA_COMMAND_GET_SINK_INPUT_INFO, + PA_COMMAND_GET_SINK_INPUT_INFO_LIST, + PA_COMMAND_GET_SOURCE_OUTPUT_INFO, + PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, + PA_COMMAND_GET_SAMPLE_INFO, + PA_COMMAND_GET_SAMPLE_INFO_LIST, + PA_COMMAND_SUBSCRIBE, + PA_COMMAND_SUBSCRIBE_EVENT, + + PA_COMMAND_SET_SINK_VOLUME, + PA_COMMAND_SET_SINK_INPUT_VOLUME, + PA_COMMAND_CORK_PLAYBACK_STREAM, + PA_COMMAND_FLUSH_PLAYBACK_STREAM, + PA_COMMAND_TRIGGER_PLAYBACK_STREAM, + + PA_COMMAND_SET_DEFAULT_SINK, + PA_COMMAND_SET_DEFAULT_SOURCE, + + PA_COMMAND_SET_PLAYBACK_STREAM_NAME, + PA_COMMAND_SET_RECORD_STREAM_NAME, + + PA_COMMAND_KILL_CLIENT, + PA_COMMAND_KILL_SINK_INPUT, + PA_COMMAND_KILL_SOURCE_OUTPUT, + PA_COMMAND_LOAD_MODULE, + PA_COMMAND_UNLOAD_MODULE, + PA_COMMAND_ADD_AUTOLOAD, + PA_COMMAND_REMOVE_AUTOLOAD, + PA_COMMAND_GET_AUTOLOAD_INFO, + PA_COMMAND_GET_AUTOLOAD_INFO_LIST, + PA_COMMAND_GET_RECORD_LATENCY, + PA_COMMAND_CORK_RECORD_STREAM, + PA_COMMAND_FLUSH_RECORD_STREAM, + PA_COMMAND_PREBUF_PLAYBACK_STREAM, + PA_COMMAND_MAX +}; + +#define PA_NATIVE_COOKIE_LENGTH 256 +#define PA_NATIVE_COOKIE_FILE ".polypaudio-cookie" + +#define PA_NATIVE_DEFAULT_PORT 4713 + +#define PA_NATIVE_COOKIE_PROPERTY_NAME "protocol-native-cookie" +#define PA_NATIVE_SERVER_PROPERTY_NAME "protocol-native-server" + +#define PA_NATIVE_DEFAULT_UNIX_SOCKET "native" + + +PA_C_DECL_END + +#endif diff --git a/src/polypcore/oss-util.c b/src/polypcore/oss-util.c new file mode 100644 index 00000000..ae6772fd --- /dev/null +++ b/src/polypcore/oss-util.c @@ -0,0 +1,167 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "oss-util.h" +#include "util.h" +#include "log.h" + +int pa_oss_open(const char *device, int *mode, int* pcaps) { + int fd = -1; + assert(device && mode && (*mode == O_RDWR || *mode == O_RDONLY || *mode == O_WRONLY)); + + if (*mode == O_RDWR) { + if ((fd = open(device, O_RDWR|O_NDELAY)) >= 0) { + int dcaps, *tcaps; + ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0); + + tcaps = pcaps ? pcaps : &dcaps; + + if (ioctl(fd, SNDCTL_DSP_GETCAPS, tcaps) < 0) { + pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); + goto fail; + } + + if (*tcaps & DSP_CAP_DUPLEX) + return fd; + + goto fail; + } + + if ((fd = open(device, (*mode = O_WRONLY)|O_NDELAY)) < 0) { + if ((fd = open(device, (*mode = O_RDONLY)|O_NDELAY)) < 0) { + pa_log(__FILE__": open('%s'): %s\n", device, strerror(errno)); + goto fail; + } + } + } else { + if ((fd = open(device, *mode|O_NDELAY)) < 0) { + pa_log(__FILE__": open('%s'): %s\n", device, strerror(errno)); + goto fail; + } + } + + if (pcaps) { + if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { + pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); + goto fail; + } + } + + pa_fd_set_cloexec(fd, 1); + + return fd; + +fail: + if (fd >= 0) + close(fd); + return -1; +} + +int pa_oss_auto_format(int fd, pa_sample_spec *ss) { + int format, channels, speed, reqformat; + static const int format_trans[PA_SAMPLE_MAX] = { + [PA_SAMPLE_U8] = AFMT_U8, + [PA_SAMPLE_ALAW] = AFMT_A_LAW, + [PA_SAMPLE_ULAW] = AFMT_MU_LAW, + [PA_SAMPLE_S16LE] = AFMT_S16_LE, + [PA_SAMPLE_S16BE] = AFMT_S16_BE, + [PA_SAMPLE_FLOAT32LE] = AFMT_QUERY, /* not supported */ + [PA_SAMPLE_FLOAT32BE] = AFMT_QUERY, /* not supported */ + }; + + assert(fd >= 0 && ss); + + reqformat = format = format_trans[ss->format]; + if (reqformat == AFMT_QUERY || ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != reqformat) { + format = AFMT_S16_NE; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_S16_NE) { + int f = AFMT_S16_NE == AFMT_S16_LE ? AFMT_S16_BE : AFMT_S16_LE; + format = f; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != f) { + format = AFMT_U8; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_U8) { + pa_log(__FILE__": SNDCTL_DSP_SETFMT: %s\n", format != AFMT_U8 ? "No supported sample format" : strerror(errno)); + return -1; + } else + ss->format = PA_SAMPLE_U8; + } else + ss->format = f == AFMT_S16_LE ? PA_SAMPLE_S16LE : PA_SAMPLE_S16BE; + } else + ss->format = PA_SAMPLE_S16NE; + } + + channels = ss->channels; + if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) { + pa_log(__FILE__": SNDCTL_DSP_CHANNELS: %s\n", strerror(errno)); + return -1; + } + assert(channels); + ss->channels = channels; + + speed = ss->rate; + if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) { + pa_log(__FILE__": SNDCTL_DSP_SPEED: %s\n", strerror(errno)); + return -1; + } + assert(speed); + ss->rate = speed; + + return 0; +} + +static int simple_log2(int v) { + int k = 0; + + for (;;) { + v >>= 1; + if (!v) break; + k++; + } + + return k; +} + +int pa_oss_set_fragments(int fd, int nfrags, int frag_size) { + int arg; + arg = ((int) nfrags << 16) | simple_log2(frag_size); + + if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &arg) < 0) { + pa_log(__FILE__": SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno)); + return -1; + } + + return 0; +} diff --git a/src/polypcore/oss-util.h b/src/polypcore/oss-util.h new file mode 100644 index 00000000..6b2746cc --- /dev/null +++ b/src/polypcore/oss-util.h @@ -0,0 +1,32 @@ +#ifndef fooossutilhfoo +#define fooossutilhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +int pa_oss_open(const char *device, int *mode, int* pcaps); +int pa_oss_auto_format(int fd, pa_sample_spec *ss); + +int pa_oss_set_fragments(int fd, int frags, int frag_size); + +#endif diff --git a/src/polypcore/packet.c b/src/polypcore/packet.c new file mode 100644 index 00000000..b3a2e074 --- /dev/null +++ b/src/polypcore/packet.c @@ -0,0 +1,69 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "packet.h" +#include "xmalloc.h" + +pa_packet* pa_packet_new(size_t length) { + pa_packet *p; + assert(length); + p = pa_xmalloc(sizeof(pa_packet)+length); + p->ref = 1; + p->length = length; + p->data = (uint8_t*) (p+1); + p->type = PA_PACKET_APPENDED; + return p; +} + +pa_packet* pa_packet_new_dynamic(uint8_t* data, size_t length) { + pa_packet *p; + assert(data && length); + p = pa_xmalloc(sizeof(pa_packet)); + p->ref = 1; + p->length = length; + p->data = data; + p->type = PA_PACKET_DYNAMIC; + return p; +} + +pa_packet* pa_packet_ref(pa_packet *p) { + assert(p && p->ref >= 1); + p->ref++; + return p; +} + +void pa_packet_unref(pa_packet *p) { + assert(p && p->ref >= 1); + p->ref--; + + if (p->ref == 0) { + if (p->type == PA_PACKET_DYNAMIC) + pa_xfree(p->data); + pa_xfree(p); + } +} diff --git a/src/polypcore/packet.h b/src/polypcore/packet.h new file mode 100644 index 00000000..0ac47485 --- /dev/null +++ b/src/polypcore/packet.h @@ -0,0 +1,41 @@ +#ifndef foopackethfoo +#define foopackethfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +typedef struct pa_packet { + enum { PA_PACKET_APPENDED, PA_PACKET_DYNAMIC } type; + unsigned ref; + size_t length; + uint8_t *data; +} pa_packet; + +pa_packet* pa_packet_new(size_t length); +pa_packet* pa_packet_new_dynamic(uint8_t* data, size_t length); + +pa_packet* pa_packet_ref(pa_packet *p); +void pa_packet_unref(pa_packet *p); + +#endif diff --git a/src/polypcore/parseaddr.c b/src/polypcore/parseaddr.c new file mode 100644 index 00000000..5e4c689c --- /dev/null +++ b/src/polypcore/parseaddr.c @@ -0,0 +1,112 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "xmalloc.h" +#include "util.h" +#include "parseaddr.h" + +/* Parse addresses in one of the following forms: + * HOSTNAME + * HOSTNAME:PORT + * [HOSTNAME] + * [HOSTNAME]:PORT + * + * Return a newly allocated string of the hostname and fill in *ret_port if specified */ + +static char *parse_host(const char *s, uint16_t *ret_port) { + assert(s && ret_port); + if (*s == '[') { + char *e; + if (!(e = strchr(s+1, ']'))) + return NULL; + + if (e[1] == ':') + *ret_port = atoi(e+2); + else if (e[1] != 0) + return NULL; + + return pa_xstrndup(s+1, e-s-1); + } else { + char *e; + + if (!(e = strrchr(s, ':'))) + return pa_xstrdup(s); + + *ret_port = atoi(e+1); + return pa_xstrndup(s, e-s); + } +} + +int pa_parse_address(const char *name, pa_parsed_address *ret_p) { + const char *p; + assert(name && ret_p); + memset(ret_p, 0, sizeof(pa_parsed_address)); + ret_p->type = PA_PARSED_ADDRESS_TCP_AUTO; + + if (*name == '{') { + char hn[256], *pfx; + /* The URL starts with a host specification for detecting local connections */ + + if (!pa_get_host_name(hn, sizeof(hn))) + return -1; + + pfx = pa_sprintf_malloc("{%s}", hn); + if (!pa_startswith(name, pfx)) { + pa_xfree(pfx); + /* Not local */ + return -1; + } + + p = name + strlen(pfx); + pa_xfree(pfx); + } else + p = name; + + if (*p == '/') + ret_p->type = PA_PARSED_ADDRESS_UNIX; + else if (pa_startswith(p, "unix:")) { + ret_p->type = PA_PARSED_ADDRESS_UNIX; + p += sizeof("unix:")-1; + } else if (pa_startswith(p, "tcp:") || pa_startswith(p, "tcp4:")) { + ret_p->type = PA_PARSED_ADDRESS_TCP4; + p += sizeof("tcp:")-1; + } else if (pa_startswith(p, "tcp6:")) { + ret_p->type = PA_PARSED_ADDRESS_TCP6; + p += sizeof("tcp6:")-1; + } + + if (ret_p->type == PA_PARSED_ADDRESS_UNIX) + ret_p->path_or_host = pa_xstrdup(p); + else + if (!(ret_p->path_or_host = parse_host(p, &ret_p->port))) + return -1; + + + return 0; +} diff --git a/src/polypcore/parseaddr.h b/src/polypcore/parseaddr.h new file mode 100644 index 00000000..eff9dd3b --- /dev/null +++ b/src/polypcore/parseaddr.h @@ -0,0 +1,42 @@ +#ifndef fooparseaddrhfoo +#define fooparseaddrhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef enum pa_parsed_address_type { + PA_PARSED_ADDRESS_UNIX, + PA_PARSED_ADDRESS_TCP4, + PA_PARSED_ADDRESS_TCP6, + PA_PARSED_ADDRESS_TCP_AUTO +} pa_parsed_address_type_t; + +typedef struct pa_parsed_address { + pa_parsed_address_type_t type; + char *path_or_host; + uint16_t port; +} pa_parsed_address; + +int pa_parse_address(const char *a, pa_parsed_address *ret_p); + +#endif diff --git a/src/polypcore/pdispatch.c b/src/polypcore/pdispatch.c new file mode 100644 index 00000000..5a50a0d5 --- /dev/null +++ b/src/polypcore/pdispatch.c @@ -0,0 +1,295 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "pdispatch.h" +#include "native-common.h" +#include "xmalloc.h" +#include "llist.h" +#include "log.h" +#include "util.h" + +/*#define DEBUG_OPCODES */ + +#ifdef DEBUG_OPCODES + +static const char *command_names[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = "ERROR", + [PA_COMMAND_TIMEOUT] = "TIMEOUT", + [PA_COMMAND_REPLY] = "REPLY", + [PA_COMMAND_CREATE_PLAYBACK_STREAM] = "CREATE_PLAYBACK_STREAM", + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = "DELETE_PLAYBACK_STREAM", + [PA_COMMAND_CREATE_RECORD_STREAM] = "CREATE_RECORD_STREAM", + [PA_COMMAND_DELETE_RECORD_STREAM] = "DELETE_RECORD_STREAM", + [PA_COMMAND_AUTH] = "AUTH", + [PA_COMMAND_REQUEST] = "REQUEST", + [PA_COMMAND_EXIT] = "EXIT", + [PA_COMMAND_SET_CLIENT_NAME] = "SET_CLIENT_NAME", + [PA_COMMAND_LOOKUP_SINK] = "LOOKUP_SINK", + [PA_COMMAND_LOOKUP_SOURCE] = "LOOKUP_SOURCE", + [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = "DRAIN_PLAYBACK_STREAM", + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = "PLAYBACK_STREAM_KILLED", + [PA_COMMAND_RECORD_STREAM_KILLED] = "RECORD_STREAM_KILLED", + [PA_COMMAND_STAT] = "STAT", + [PA_COMMAND_GET_PLAYBACK_LATENCY] = "PLAYBACK_LATENCY", + [PA_COMMAND_CREATE_UPLOAD_STREAM] = "CREATE_UPLOAD_STREAM", + [PA_COMMAND_DELETE_UPLOAD_STREAM] = "DELETE_UPLOAD_STREAM", + [PA_COMMAND_FINISH_UPLOAD_STREAM] = "FINISH_UPLOAD_STREAM", + [PA_COMMAND_PLAY_SAMPLE] = "PLAY_SAMPLE", + [PA_COMMAND_REMOVE_SAMPLE] = "REMOVE_SAMPLE", + [PA_COMMAND_GET_SERVER_INFO] = "GET_SERVER_INFO", + [PA_COMMAND_GET_SINK_INFO] = "GET_SINK_INFO", + [PA_COMMAND_GET_SINK_INFO_LIST] = "GET_SINK_INFO_LIST", + [PA_COMMAND_GET_SOURCE_INFO] = "GET_SOURCE_INFO", + [PA_COMMAND_GET_SOURCE_INFO_LIST] = "GET_SOURCE_INFO_LIST", + [PA_COMMAND_GET_MODULE_INFO] = "GET_MODULE_INFO", + [PA_COMMAND_GET_MODULE_INFO_LIST] = "GET_MODULE_INFO_LIST", + [PA_COMMAND_GET_CLIENT_INFO] = "GET_CLIENT_INFO", + [PA_COMMAND_GET_CLIENT_INFO_LIST] = "GET_CLIENT_INFO_LIST", + [PA_COMMAND_GET_SAMPLE_INFO] = "GET_SAMPLE_INFO", + [PA_COMMAND_GET_SAMPLE_INFO_LIST] = "GET_SAMPLE_INFO_LIST", + [PA_COMMAND_GET_SINK_INPUT_INFO] = "GET_SINK_INPUT_INFO", + [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = "GET_SINK_INPUT_INFO_LIST", + [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = "GET_SOURCE_OUTPUT_INFO", + [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = "GET_SOURCE_OUTPUT_INFO_LIST", + [PA_COMMAND_SUBSCRIBE] = "SUBSCRIBE", + [PA_COMMAND_SUBSCRIBE_EVENT] = "SUBSCRIBE_EVENT", + [PA_COMMAND_SET_SINK_VOLUME] = "SET_SINK_VOLUME", + [PA_COMMAND_SET_SINK_INPUT_VOLUME] = "SET_SINK_INPUT_VOLUME", + [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = "TRIGGER_PLAYBACK_STREAM", + [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = "FLUSH_PLAYBACK_STREAM", + [PA_COMMAND_CORK_PLAYBACK_STREAM] = "CORK_PLAYBACK_STREAM", + [PA_COMMAND_GET_AUTOLOAD_INFO] = "GET_AUTOLOAD_INFO", + [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = "GET_AUTOLOAD_INFO_LIST", +}; + +#endif + +struct reply_info { + pa_pdispatch *pdispatch; + PA_LLIST_FIELDS(struct reply_info); + pa_pdispatch_callback callback; + void *userdata; + uint32_t tag; + pa_time_event *time_event; +}; + +struct pa_pdispatch { + int ref; + pa_mainloop_api *mainloop; + const pa_pdispatch_callback *callback_table; + unsigned n_commands; + PA_LLIST_HEAD(struct reply_info, replies); + pa_pdispatch_drain_callback drain_callback; + void *drain_userdata; +}; + +static void reply_info_free(struct reply_info *r) { + assert(r && r->pdispatch && r->pdispatch->mainloop); + + if (r->time_event) + r->pdispatch->mainloop->time_free(r->time_event); + + PA_LLIST_REMOVE(struct reply_info, r->pdispatch->replies, r); + + pa_xfree(r); +} + +pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_callback*table, unsigned entries) { + pa_pdispatch *pd; + assert(mainloop); + + assert((entries && table) || (!entries && !table)); + + pd = pa_xmalloc(sizeof(pa_pdispatch)); + pd->ref = 1; + pd->mainloop = mainloop; + pd->callback_table = table; + pd->n_commands = entries; + PA_LLIST_HEAD_INIT(pa_reply_info, pd->replies); + pd->drain_callback = NULL; + pd->drain_userdata = NULL; + + return pd; +} + +static void pdispatch_free(pa_pdispatch *pd) { + assert(pd); + + while (pd->replies) + reply_info_free(pd->replies); + + pa_xfree(pd); +} + +static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command, pa_tagstruct *ts) { + pa_pdispatch_callback callback; + void *userdata; + uint32_t tag; + assert(r); + + pa_pdispatch_ref(pd); + + callback = r->callback; + userdata = r->userdata; + tag = r->tag; + + reply_info_free(r); + + callback(pd, command, tag, ts, userdata); + + if (pd->drain_callback && !pa_pdispatch_is_pending(pd)) + pd->drain_callback(pd, pd->drain_userdata); + + pa_pdispatch_unref(pd); +} + +int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, void *userdata) { + uint32_t tag, command; + pa_tagstruct *ts = NULL; + int ret = -1; + assert(pd && packet && packet->data); + + pa_pdispatch_ref(pd); + + if (packet->length <= 8) + goto finish; + + ts = pa_tagstruct_new(packet->data, packet->length); + assert(ts); + + if (pa_tagstruct_getu32(ts, &command) < 0 || + pa_tagstruct_getu32(ts, &tag) < 0) + goto finish; + +#ifdef DEBUG_OPCODES +{ + char t[256]; + char const *p; + if (!(p = command_names[command])) + snprintf((char*) (p = t), sizeof(t), "%u", command); + + pa_log(__FILE__": Recieved opcode <%s>\n", p); +} +#endif + + if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) { + struct reply_info *r; + + for (r = pd->replies; r; r = r->next) + if (r->tag == tag) + break; + + if (r) + run_action(pd, r, command, ts); + + } else if (pd->callback_table && (command < pd->n_commands) && pd->callback_table[command]) { + const pa_pdispatch_callback *c = pd->callback_table+command; + + (*c)(pd, command, tag, ts, userdata); + } else { + pa_log(__FILE__": Recieved unsupported command %u\n", command); + goto finish; + } + + ret = 0; + +finish: + if (ts) + pa_tagstruct_free(ts); + + pa_pdispatch_unref(pd); + + return ret; +} + +static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + struct reply_info*r = userdata; + assert(r && r->time_event == e && r->pdispatch && r->pdispatch->mainloop == m && r->callback); + + run_action(r->pdispatch, r, PA_COMMAND_TIMEOUT, NULL); +} + +void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_callback cb, void *userdata) { + struct reply_info *r; + struct timeval tv; + assert(pd && pd->ref >= 1 && cb); + + r = pa_xmalloc(sizeof(struct reply_info)); + r->pdispatch = pd; + r->callback = cb; + r->userdata = userdata; + r->tag = tag; + + pa_gettimeofday(&tv); + tv.tv_sec += timeout; + + r->time_event = pd->mainloop->time_new(pd->mainloop, &tv, timeout_callback, r); + assert(r->time_event); + + PA_LLIST_PREPEND(struct reply_info, pd->replies, r); +} + +int pa_pdispatch_is_pending(pa_pdispatch *pd) { + assert(pd); + + return !!pd->replies; +} + +void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, void (*cb)(pa_pdispatch *pd, void *userdata), void *userdata) { + assert(pd); + assert(!cb || pa_pdispatch_is_pending(pd)); + + pd->drain_callback = cb; + pd->drain_userdata = userdata; +} + +void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata) { + struct reply_info *r, *n; + assert(pd); + + for (r = pd->replies; r; r = n) { + n = r->next; + + if (r->userdata == userdata) + reply_info_free(r); + } +} + +void pa_pdispatch_unref(pa_pdispatch *pd) { + assert(pd && pd->ref >= 1); + + if (!(--(pd->ref))) + pdispatch_free(pd); +} + +pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd) { + assert(pd && pd->ref >= 1); + pd->ref++; + return pd; +} diff --git a/src/polypcore/pdispatch.h b/src/polypcore/pdispatch.h new file mode 100644 index 00000000..fdd4d7f5 --- /dev/null +++ b/src/polypcore/pdispatch.h @@ -0,0 +1,50 @@ +#ifndef foopdispatchhfoo +#define foopdispatchhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include "tagstruct.h" +#include "packet.h" +#include + +typedef struct pa_pdispatch pa_pdispatch; + +typedef void (*pa_pdispatch_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); + +pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *m, const pa_pdispatch_callback*table, unsigned entries); +void pa_pdispatch_unref(pa_pdispatch *pd); +pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd); + +int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*p, void *userdata); + +void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_callback callback, void *userdata); + +int pa_pdispatch_is_pending(pa_pdispatch *pd); + +typedef void (*pa_pdispatch_drain_callback)(pa_pdispatch *pd, void *userdata); +void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, pa_pdispatch_drain_callback callback, void *userdata); + +/* Remove all reply slots with the give userdata parameter */ +void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata); + +#endif diff --git a/src/polypcore/pid.c b/src/polypcore/pid.c new file mode 100644 index 00000000..ae3dc7f5 --- /dev/null +++ b/src/polypcore/pid.c @@ -0,0 +1,286 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include "pid.h" +#include "util.h" +#include "log.h" + +/* Read the PID data from the file descriptor fd, and return it. If no + * pid could be read, return 0, on failure (pid_t) -1 */ +static pid_t read_pid(const char *fn, int fd) { + ssize_t r; + char t[20], *e; + uint32_t pid; + + assert(fn && fd >= 0); + + if ((r = pa_loop_read(fd, t, sizeof(t)-1)) < 0) { + pa_log(__FILE__": WARNING: failed to read PID file '%s': %s\n", fn, strerror(errno)); + return (pid_t) -1; + } + + if (r == 0) + return (pid_t) 0; + + t[r] = 0; + if ((e = strchr(t, '\n'))) + *e = 0; + + if (pa_atou(t, &pid) < 0) { + pa_log(__FILE__": WARNING: failed to parse PID file '%s'\n", fn); + return (pid_t) -1; + } + + return (pid_t) pid; +} + +static int open_pid_file(const char *fn, int mode) { + int fd = -1; + int lock = -1; + + for (;;) { + struct stat st; + + pa_make_secure_parent_dir(fn); + + if ((fd = open(fn, mode, S_IRUSR|S_IWUSR)) < 0) { + if (mode != O_RDONLY || errno != ENOENT) + pa_log(__FILE__": WARNING: failed to open PID file '%s': %s\n", fn, strerror(errno)); + goto fail; + } + + /* Try to lock the file. If that fails, go without */ + if (pa_lock_fd(fd, 1) < 0) + goto fail; + + if (fstat(fd, &st) < 0) { + pa_log(__FILE__": Failed to fstat() PID file '%s': %s\n", fn, strerror(errno)); + goto fail; + } + + /* Does the file still exist in the file system? When ye, w're done, otherwise restart */ + if (st.st_nlink >= 1) + break; + + if (pa_lock_fd(fd, 0) < 0) + goto fail; + + if (close(fd) < 0) { + pa_log(__FILE__": Failed to close file '%s': %s\n", fn, strerror(errno)); + goto fail; + } + + fd = -1; + } + + return fd; + +fail: + + if (fd < 0) { + if (lock >= 0) + pa_lock_fd(fd, 0); + + close(fd); + } + + return -1; +} + +/* Create a new PID file for the current process. */ +int pa_pid_file_create(void) { + int fd = -1; + int ret = -1; + char fn[PATH_MAX]; + char t[20]; + pid_t pid; + size_t l; + +#ifdef OS_IS_WIN32 + HANDLE process; +#endif + + pa_runtime_path("pid", fn, sizeof(fn)); + + if ((fd = open_pid_file(fn, O_CREAT|O_RDWR)) < 0) + goto fail; + + if ((pid = read_pid(fn, fd)) == (pid_t) -1) + pa_log(__FILE__": corrupt PID file, overwriting.\n"); + else if (pid > 0) { +#ifdef OS_IS_WIN32 + if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)) != NULL) { + CloseHandle(process); +#else + if (kill(pid, 0) >= 0 || errno != ESRCH) { +#endif + pa_log(__FILE__": daemon already running.\n"); + goto fail; + } + + pa_log(__FILE__": stale PID file, overwriting.\n"); + } + + /* Overwrite the current PID file */ + if (lseek(fd, 0, SEEK_SET) == (off_t) -1 || ftruncate(fd, 0) < 0) { + pa_log(__FILE__": failed to truncate PID fil: %s.\n", strerror(errno)); + goto fail; + } + + snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid()); + l = strlen(t); + + if (pa_loop_write(fd, t, l) != (ssize_t) l) { + pa_log(__FILE__": failed to write PID file.\n"); + goto fail; + } + + ret = 0; + +fail: + if (fd >= 0) { + pa_lock_fd(fd, 0); + close(fd); + } + + return ret; +} + +/* Remove the PID file, if it is ours */ +int pa_pid_file_remove(void) { + int fd = -1; + char fn[PATH_MAX]; + int ret = -1; + pid_t pid; + + pa_runtime_path("pid", fn, sizeof(fn)); + + if ((fd = open_pid_file(fn, O_RDWR)) < 0) { + pa_log(__FILE__": WARNING: failed to open PID file '%s': %s\n", fn, strerror(errno)); + goto fail; + } + + if ((pid = read_pid(fn, fd)) == (pid_t) -1) + goto fail; + + if (pid != getpid()) { + pa_log(__FILE__": WARNING: PID file '%s' not mine!\n", fn); + goto fail; + } + + if (ftruncate(fd, 0) < 0) { + pa_log(__FILE__": failed to truncate PID file '%s': %s\n", fn, strerror(errno)); + goto fail; + } + +#ifdef OS_IS_WIN32 + pa_lock_fd(fd, 0); + close(fd); + fd = -1; +#endif + + if (unlink(fn) < 0) { + pa_log(__FILE__": failed to remove PID file '%s': %s\n", fn, strerror(errno)); + goto fail; + } + + ret = 0; + +fail: + + if (fd >= 0) { + pa_lock_fd(fd, 0); + close(fd); + } + + return ret; +} + +/* Check whether the daemon is currently running, i.e. if a PID file + * exists and the PID therein too. Returns 0 on succcess, -1 + * otherwise. If pid is non-NULL and a running daemon was found, + * return its PID therein */ +int pa_pid_file_check_running(pid_t *pid) { + return pa_pid_file_kill(0, pid); +} + +#ifndef OS_IS_WIN32 + +/* Kill a current running daemon. Return non-zero on success, -1 + * otherwise. If successful *pid contains the PID of the daemon + * process. */ +int pa_pid_file_kill(int sig, pid_t *pid) { + int fd = -1; + char fn[PATH_MAX]; + int ret = -1; + pid_t _pid; + + if (!pid) + pid = &_pid; + + pa_runtime_path("pid", fn, sizeof(fn)); + + if ((fd = open_pid_file(fn, O_RDONLY)) < 0) + goto fail; + + if ((*pid = read_pid(fn, fd)) == (pid_t) -1) + goto fail; + + ret = kill(*pid, sig); + +fail: + + if (fd >= 0) { + pa_lock_fd(fd, 0); + close(fd); + } + + return ret; + +} + +#else /* OS_IS_WIN32 */ + +int pa_pid_file_kill(int sig, pid_t *pid) { + return -1; +} + +#endif diff --git a/src/polypcore/pid.h b/src/polypcore/pid.h new file mode 100644 index 00000000..906ab6da --- /dev/null +++ b/src/polypcore/pid.h @@ -0,0 +1,30 @@ +#ifndef foopidhfoo +#define foopidhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +int pa_pid_file_create(void); +int pa_pid_file_remove(void); +int pa_pid_file_check_running(pid_t *pid); +int pa_pid_file_kill(int sig, pid_t *pid); + +#endif diff --git a/src/polypcore/play-memchunk.c b/src/polypcore/play-memchunk.c new file mode 100644 index 00000000..e24d4427 --- /dev/null +++ b/src/polypcore/play-memchunk.c @@ -0,0 +1,118 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "play-memchunk.h" +#include "sink-input.h" +#include "xmalloc.h" +#include "gccmacro.h" + +static void sink_input_kill(pa_sink_input *i) { + pa_memchunk *c; + assert(i && i->userdata); + c = i->userdata; + + pa_sink_input_disconnect(i); + pa_sink_input_unref(i); + + pa_memblock_unref(c->memblock); + pa_xfree(c); +} + +static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { + pa_memchunk *c; + assert(i && chunk && i->userdata); + c = i->userdata; + + if (c->length <= 0) + return -1; + + assert(c->memblock && c->memblock->length); + *chunk = *c; + pa_memblock_ref(c->memblock); + + return 0; +} + +static void si_kill(PA_GCC_UNUSED pa_mainloop_api *m, void *i) { + sink_input_kill(i); +} + +static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) { + pa_memchunk *c; + assert(i && length && i->userdata); + c = i->userdata; + + assert(!memcmp(chunk, c, sizeof(chunk))); + assert(length <= c->length); + + c->length -= length; + c->index += length; + + if (c->length <= 0) + pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i); +} + +int pa_play_memchunk( + pa_sink *sink, + const char *name, + const pa_sample_spec *ss, + const pa_channel_map *map, + const pa_memchunk *chunk, + pa_cvolume *cvolume) { + + pa_sink_input *si; + pa_memchunk *nchunk; + + assert(sink); + assert(ss); + assert(chunk); + + if (cvolume && pa_cvolume_is_muted(cvolume)) + return 0; + + if (!(si = pa_sink_input_new(sink, name, __FILE__, ss, map, 0, PA_RESAMPLER_INVALID))) + return -1; + + if (cvolume) + si->volume = *cvolume; + + si->peek = sink_input_peek; + si->drop = sink_input_drop; + si->kill = sink_input_kill; + + si->userdata = nchunk = pa_xnew(pa_memchunk, 1); + *nchunk = *chunk; + + pa_memblock_ref(chunk->memblock); + + pa_sink_notify(sink); + + return 0; +} diff --git a/src/polypcore/play-memchunk.h b/src/polypcore/play-memchunk.h new file mode 100644 index 00000000..fc0654a6 --- /dev/null +++ b/src/polypcore/play-memchunk.h @@ -0,0 +1,36 @@ +#ifndef fooplaychunkhfoo +#define fooplaychunkhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "sink.h" +#include "memchunk.h" + +int pa_play_memchunk( + pa_sink *sink, + const char *name, + const pa_sample_spec *ss, + const pa_channel_map *map, + const pa_memchunk *chunk, + pa_cvolume *cvolume); + +#endif diff --git a/src/polypcore/poll.c b/src/polypcore/poll.c new file mode 100644 index 00000000..193fc812 --- /dev/null +++ b/src/polypcore/poll.c @@ -0,0 +1,190 @@ +/* $Id$ */ + +/*** + Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 2005, Cendio AB. + This file is part of polypaudio. + Based on work for the GNU C Library. + + polypaudio is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with polypaudio; If not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +***/ + +/* Poll the file descriptors described by the NFDS structures starting at + FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for + an event to occur; if TIMEOUT is -1, block until an event occurs. + Returns the number of file descriptors with events, zero if timed out, + or -1 for errors. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#include "winsock.h" + +#ifndef HAVE_SYS_POLL_H + +#include "util.h" +#include "poll.h" + +int poll (struct pollfd *fds, unsigned long int nfds, int timeout) { + struct timeval tv; + fd_set rset, wset, xset; + struct pollfd *f; + int ready; + int maxfd = 0; + char data[64]; + + FD_ZERO (&rset); + FD_ZERO (&wset); + FD_ZERO (&xset); + + if (nfds == 0) { + if (timeout >= 0) { + pa_msleep(timeout); + return 0; + } + +#ifdef OS_IS_WIN32 + /* + * Windows does not support signals properly so waiting for them would + * mean a deadlock. + */ + pa_msleep(100); + return 0; +#else + return select(0, NULL, NULL, NULL, NULL); +#endif + } + + for (f = fds; f < &fds[nfds]; ++f) { + if (f->fd != -1) { + if (f->events & POLLIN) + FD_SET (f->fd, &rset); + if (f->events & POLLOUT) + FD_SET (f->fd, &wset); + if (f->events & POLLPRI) + FD_SET (f->fd, &xset); + if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI))) + maxfd = f->fd; + } + } + + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + + ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset, + SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset, + SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv)); + if ((ready == -1) && (errno == EBADF)) { + ready = 0; + + FD_ZERO (&rset); + FD_ZERO (&wset); + FD_ZERO (&xset); + + maxfd = -1; + + for (f = fds; f < &fds[nfds]; ++f) { + if (f->fd != -1) { + fd_set sngl_rset, sngl_wset, sngl_xset; + + FD_ZERO (&sngl_rset); + FD_ZERO (&sngl_wset); + FD_ZERO (&sngl_xset); + + if (f->events & POLLIN) + FD_SET (f->fd, &sngl_rset); + if (f->events & POLLOUT) + FD_SET (f->fd, &sngl_wset); + if (f->events & POLLPRI) + FD_SET (f->fd, &sngl_xset); + if (f->events & (POLLIN|POLLOUT|POLLPRI)) { + struct timeval singl_tv; + + singl_tv.tv_sec = 0; + singl_tv.tv_usec = 0; + + if (select((SELECT_TYPE_ARG1) f->fd, SELECT_TYPE_ARG234 &rset, + SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset, + SELECT_TYPE_ARG5 &singl_tv) != -1) { + if (f->events & POLLIN) + FD_SET (f->fd, &rset); + if (f->events & POLLOUT) + FD_SET (f->fd, &wset); + if (f->events & POLLPRI) + FD_SET (f->fd, &xset); + if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI))) + maxfd = f->fd; + ++ready; + } else if (errno == EBADF) + f->revents |= POLLNVAL; + } + } + } + + if (ready) { + /* Linux alters the tv struct... but it shouldn't matter here ... + * as we're going to be a little bit out anyway as we've just eaten + * more than a couple of cpu cycles above */ + ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset, + SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset, + SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv)); + } + } + +#ifdef OS_IS_WIN32 + errno = WSAGetLastError(); +#endif + + if (ready > 0) { + ready = 0; + for (f = fds; f < &fds[nfds]; ++f) { + f->revents = 0; + if (f->fd != -1) { + if (FD_ISSET (f->fd, &rset)) { + /* support for POLLHUP. An hung up descriptor does not + increase the return value! */ + if (recv (f->fd, data, 64, MSG_PEEK) == -1) { + if (errno == ESHUTDOWN || errno == ECONNRESET || + errno == ECONNABORTED || errno == ENETRESET) { + fprintf(stderr, "Hangup\n"); + f->revents |= POLLHUP; + } + } + + if (f->revents == 0) + f->revents |= POLLIN; + } + if (FD_ISSET (f->fd, &wset)) + f->revents |= POLLOUT; + if (FD_ISSET (f->fd, &xset)) + f->revents |= POLLPRI; + } + if (f->revents) + ready++; + } + } + + return ready; +} + +#endif /* HAVE_SYS_POLL_H */ diff --git a/src/polypcore/poll.h b/src/polypcore/poll.h new file mode 100644 index 00000000..c201014e --- /dev/null +++ b/src/polypcore/poll.h @@ -0,0 +1,57 @@ +/* $Id$ */ + +/*** + Compatibility definitions for System V `poll' interface. + Copyright (C) 1994,96,97,98,99,2000,2001,2004 Free Software Foundation, Inc. + Copyright (C) 2005, Cendio AB. + This file is part of polypaudio. + Based on work for the GNU C Library. + + polypaudio is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with polypaudio; If not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +***/ + +/* Event types that can be polled for. These bits may be set in `events' + to indicate the interesting event types; they will appear in `revents' + to indicate the status of the file descriptor. */ +#define POLLIN 0x001 /* There is data to read. */ +#define POLLPRI 0x002 /* There is urgent data to read. */ +#define POLLOUT 0x004 /* Writing now will not block. */ + +/* Event types always implicitly polled for. These bits need not be set in + `events', but they will appear in `revents' to indicate the status of + the file descriptor. */ +#define POLLERR 0x008 /* Error condition. */ +#define POLLHUP 0x010 /* Hung up. */ +#define POLLNVAL 0x020 /* Invalid polling request. */ + + +/* Type used for the number of file descriptors. */ +typedef unsigned long int nfds_t; + +/* Data structure describing a polling request. */ +struct pollfd + { + int fd; /* File descriptor to poll. */ + short int events; /* Types of events poller cares about. */ + short int revents; /* Types of events that actually occurred. */ + }; + +/* Poll the file descriptors described by the NFDS structures starting at + FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for + an event to occur; if TIMEOUT is -1, block until an event occurs. + Returns the number of file descriptors with events, zero if timed out, + or -1 for errors. */ +extern int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout); diff --git a/src/polypcore/props.c b/src/polypcore/props.c new file mode 100644 index 00000000..df748c1e --- /dev/null +++ b/src/polypcore/props.c @@ -0,0 +1,119 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "xmalloc.h" +#include "props.h" +#include "log.h" + +typedef struct pa_property { + char *name; /* Points to memory allocated by the property subsystem */ + void *data; /* Points to memory maintained by the caller */ +} pa_property; + +/* Allocate a new property object */ +static pa_property* property_new(const char *name, void *data) { + pa_property* p; + assert(name && data); + + p = pa_xmalloc(sizeof(pa_property)); + p->name = pa_xstrdup(name); + p->data = data; + + return p; +} + +/* Free a property object */ +static void property_free(pa_property *p) { + assert(p); + + pa_xfree(p->name); + pa_xfree(p); +} + +void* pa_property_get(pa_core *c, const char *name) { + pa_property *p; + assert(c && name && c->properties); + + if (!(p = pa_hashmap_get(c->properties, name))) + return NULL; + + return p->data; +} + +int pa_property_set(pa_core *c, const char *name, void *data) { + pa_property *p; + assert(c && name && data && c->properties); + + if (pa_hashmap_get(c->properties, name)) + return -1; + + p = property_new(name, data); + pa_hashmap_put(c->properties, p->name, p); + return 0; +} + +int pa_property_remove(pa_core *c, const char *name) { + pa_property *p; + assert(c && name && c->properties); + + if (!(p = pa_hashmap_remove(c->properties, name))) + return -1; + + property_free(p); + return 0; +} + +void pa_property_init(pa_core *c) { + assert(c); + + c->properties = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); +} + +void pa_property_cleanup(pa_core *c) { + assert(c); + + if (!c->properties) + return; + + assert(!pa_hashmap_size(c->properties)); + + pa_hashmap_free(c->properties, NULL, NULL); + c->properties = NULL; + +} + +void pa_property_dump(pa_core *c, pa_strbuf *s) { + void *state = NULL; + pa_property *p; + assert(c && s); + + while ((p = pa_hashmap_iterate(c->properties, &state, NULL))) + pa_strbuf_printf(s, "[%s] -> [%p]\n", p->name, p->data); +} + +int pa_property_replace(pa_core *c, const char *name, void *data) { + assert(c && name); + + pa_property_remove(c, name); + return pa_property_set(c, name, data); +} diff --git a/src/polypcore/props.h b/src/polypcore/props.h new file mode 100644 index 00000000..5abf8787 --- /dev/null +++ b/src/polypcore/props.h @@ -0,0 +1,58 @@ +#ifndef foopropshfoo +#define foopropshfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" +#include "strbuf.h" + +/* The property subsystem is to be used to share data between + * modules. Consider them to be kind of "global" variables for a + * core. Why not use the hashmap functions directly? The hashmap + * functions copy neither the key nor value, while this property + * system copies the key. Users of this system have to think about + * reference counting themselves. */ + +/* Return a pointer to the value of the specified property. */ +void* pa_property_get(pa_core *c, const char *name); + +/* Set the property 'name' to 'data'. This function fails in case a + * property by this name already exists. The property data is not + * copied or reference counted. This is the caller's job. */ +int pa_property_set(pa_core *c, const char *name, void *data); + +/* Remove the specified property. Return non-zero on failure */ +int pa_property_remove(pa_core *c, const char *name); + +/* A combination of pa_property_remove() and pa_property_set() */ +int pa_property_replace(pa_core *c, const char *name, void *data); + +/* Free all memory used by the property system */ +void pa_property_cleanup(pa_core *c); + +/* Initialize the properties subsystem */ +void pa_property_init(pa_core *c); + +/* Dump the current set of properties */ +void pa_property_dump(pa_core *c, pa_strbuf *s); + +#endif diff --git a/src/polypcore/protocol-cli.c b/src/polypcore/protocol-cli.c new file mode 100644 index 00000000..d2d73550 --- /dev/null +++ b/src/polypcore/protocol-cli.c @@ -0,0 +1,95 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "protocol-cli.h" +#include "cli.h" +#include "xmalloc.h" +#include "log.h" + +/* Don't allow more than this many concurrent connections */ +#define MAX_CONNECTIONS 25 + +struct pa_protocol_cli { + pa_module *module; + pa_core *core; + pa_socket_server*server; + pa_idxset *connections; +}; + +static void cli_eof_cb(pa_cli*c, void*userdata) { + pa_protocol_cli *p = userdata; + assert(p); + pa_idxset_remove_by_data(p->connections, c, NULL); + pa_cli_free(c); +} + +static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { + pa_protocol_cli *p = userdata; + pa_cli *c; + assert(s && io && p); + + if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { + pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); + pa_iochannel_free(io); + return; + } + + c = pa_cli_new(p->core, io, p->module); + assert(c); + pa_cli_set_eof_callback(c, cli_eof_cb, p); + + pa_idxset_put(p->connections, c, NULL); +} + +pa_protocol_cli* pa_protocol_cli_new(pa_core *core, pa_socket_server *server, pa_module *m, PA_GCC_UNUSED pa_modargs *ma) { + pa_protocol_cli* p; + assert(core && server); + + p = pa_xmalloc(sizeof(pa_protocol_cli)); + p->module = m; + p->core = core; + p->server = server; + p->connections = pa_idxset_new(NULL, NULL); + + pa_socket_server_set_callback(p->server, on_connection, p); + + return p; +} + +static void free_connection(void *p, PA_GCC_UNUSED void *userdata) { + assert(p); + pa_cli_free(p); +} + +void pa_protocol_cli_free(pa_protocol_cli *p) { + assert(p); + + pa_idxset_free(p->connections, free_connection, NULL); + pa_socket_server_unref(p->server); + pa_xfree(p); +} diff --git a/src/polypcore/protocol-cli.h b/src/polypcore/protocol-cli.h new file mode 100644 index 00000000..aed733c1 --- /dev/null +++ b/src/polypcore/protocol-cli.h @@ -0,0 +1,35 @@ +#ifndef fooprotocolclihfoo +#define fooprotocolclihfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" +#include "socket-server.h" +#include "module.h" +#include "modargs.h" + +typedef struct pa_protocol_cli pa_protocol_cli; + +pa_protocol_cli* pa_protocol_cli_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma); +void pa_protocol_cli_free(pa_protocol_cli *n); + +#endif diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c new file mode 100644 index 00000000..14f237c7 --- /dev/null +++ b/src/polypcore/protocol-esound.c @@ -0,0 +1,1166 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "protocol-esound.h" +#include "esound.h" +#include "memblock.h" +#include "client.h" +#include "sink-input.h" +#include "sink.h" +#include "source-output.h" +#include "source.h" +#include +#include "scache.h" +#include "sample-util.h" +#include "authkey.h" +#include "namereg.h" +#include "xmalloc.h" +#include "log.h" +#include "util.h" +#include "endianmacros.h" + +/* Don't accept more connection than this */ +#define MAX_CONNECTIONS 10 + +/* Kick a client if it doesn't authenticate within this time */ +#define AUTH_TIMEOUT 5 + +#define DEFAULT_COOKIE_FILE ".esd_auth" + +#define PLAYBACK_BUFFER_SECONDS (.5) +#define PLAYBACK_BUFFER_FRAGMENTS (10) +#define RECORD_BUFFER_SECONDS (5) +#define RECORD_BUFFER_FRAGMENTS (100) + +#define MAX_CACHE_SAMPLE_SIZE (1024000) + +#define SCACHE_PREFIX "esound." + +/* This is heavily based on esound's code */ + +struct connection { + uint32_t index; + int dead; + pa_protocol_esound *protocol; + pa_iochannel *io; + pa_client *client; + int authorized, swap_byte_order; + void *write_data; + size_t write_data_alloc, write_data_index, write_data_length; + void *read_data; + size_t read_data_alloc, read_data_length; + esd_proto_t request; + esd_client_state_t state; + pa_sink_input *sink_input; + pa_source_output *source_output; + pa_memblockq *input_memblockq, *output_memblockq; + pa_defer_event *defer_event; + + struct { + pa_memblock *current_memblock; + size_t memblock_index, fragment_size; + } playback; + + struct { + pa_memchunk memchunk; + char *name; + pa_sample_spec sample_spec; + } scache; + + pa_time_event *auth_timeout_event; +}; + +struct pa_protocol_esound { + int public; + pa_module *module; + pa_core *core; + pa_socket_server *server; + pa_idxset *connections; + char *sink_name, *source_name; + unsigned n_player; + uint8_t esd_key[ESD_KEY_LEN]; +}; + +typedef struct proto_handler { + size_t data_length; + int (*proc)(struct connection *c, esd_proto_t request, const void *data, size_t length); + const char *description; +} esd_proto_handler_info_t; + +static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length); +static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk); +static void sink_input_kill_cb(pa_sink_input *i); +static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i); +static pa_usec_t source_output_get_latency_cb(pa_source_output *o); + +static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk); +static void source_output_kill_cb(pa_source_output *o); + +static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_play(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_get_latency(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_server_info(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_sample_get_id(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_standby_or_resume(struct connection *c, esd_proto_t request, const void *data, size_t length); + +/* the big map of protocol handler info */ +static struct proto_handler proto_map[ESD_PROTO_MAX] = { + { ESD_KEY_LEN + sizeof(int), esd_proto_connect, "connect" }, + { ESD_KEY_LEN + sizeof(int), NULL, "lock" }, + { ESD_KEY_LEN + sizeof(int), NULL, "unlock" }, + + { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_play, "stream play" }, + { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream rec" }, + { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream mon" }, + + { ESD_NAME_MAX + 3 * sizeof(int), esd_proto_sample_cache, "sample cache" }, /* 6 */ + { sizeof(int), esd_proto_sample_free_or_play, "sample free" }, + { sizeof(int), esd_proto_sample_free_or_play, "sample play" }, /* 8 */ + { sizeof(int), NULL, "sample loop" }, + { sizeof(int), NULL, "sample stop" }, + { -1, NULL, "TODO: sample kill" }, + + { ESD_KEY_LEN + sizeof(int), esd_proto_standby_or_resume, "standby" }, /* NOOP! */ + { ESD_KEY_LEN + sizeof(int), esd_proto_standby_or_resume, "resume" }, /* NOOP! */ /* 13 */ + + { ESD_NAME_MAX, esd_proto_sample_get_id, "sample getid" }, /* 14 */ + { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" }, + + { sizeof(int), esd_proto_server_info, "server info" }, + { sizeof(int), esd_proto_all_info, "all info" }, + { -1, NULL, "TODO: subscribe" }, + { -1, NULL, "TODO: unsubscribe" }, + + { 3 * sizeof(int), esd_proto_stream_pan, "stream pan"}, + { 3 * sizeof(int), NULL, "sample pan" }, + + { sizeof(int), NULL, "standby mode" }, + { 0, esd_proto_get_latency, "get latency" } +}; + + +static void connection_free(struct connection *c) { + assert(c); + pa_idxset_remove_by_data(c->protocol->connections, c, NULL); + + if (c->state == ESD_STREAMING_DATA) + c->protocol->n_player--; + + pa_client_free(c->client); + + if (c->sink_input) { + pa_sink_input_disconnect(c->sink_input); + pa_sink_input_unref(c->sink_input); + } + + if (c->source_output) { + pa_source_output_disconnect(c->source_output); + pa_source_output_unref(c->source_output); + } + + if (c->input_memblockq) + pa_memblockq_free(c->input_memblockq); + if (c->output_memblockq) + pa_memblockq_free(c->output_memblockq); + + if (c->playback.current_memblock) + pa_memblock_unref(c->playback.current_memblock); + + pa_xfree(c->read_data); + pa_xfree(c->write_data); + + if (c->io) + pa_iochannel_free(c->io); + + if (c->defer_event) + c->protocol->core->mainloop->defer_free(c->defer_event); + + if (c->scache.memchunk.memblock) + pa_memblock_unref(c->scache.memchunk.memblock); + pa_xfree(c->scache.name); + + if (c->auth_timeout_event) + c->protocol->core->mainloop->time_free(c->auth_timeout_event); + + pa_xfree(c); +} + +static void* connection_write(struct connection *c, size_t length) { + size_t t, i; + assert(c); + + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + + t = c->write_data_length+length; + + if (c->write_data_alloc < t) + c->write_data = pa_xrealloc(c->write_data, c->write_data_alloc = t); + + assert(c->write_data); + + i = c->write_data_length; + c->write_data_length += length; + + return (uint8_t*) c->write_data+i; +} + +static void format_esd2native(int format, int swap_bytes, pa_sample_spec *ss) { + assert(ss); + + ss->channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; + if ((format & ESD_MASK_BITS) == ESD_BITS16) + ss->format = swap_bytes ? PA_SAMPLE_S16RE : PA_SAMPLE_S16NE; + else + ss->format = PA_SAMPLE_U8; +} + +static int format_native2esd(pa_sample_spec *ss) { + int format = 0; + + format = (ss->format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16; + format |= (ss->channels >= 2) ? ESD_STEREO : ESD_MONO; + + return format; +} + +/*** esound commands ***/ + +static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + uint32_t ekey; + int *ok; + assert(length == (ESD_KEY_LEN + sizeof(uint32_t))); + + if (!c->authorized) { + if (memcmp(data, c->protocol->esd_key, ESD_KEY_LEN) != 0) { + pa_log(__FILE__": kicked client with invalid authorization key.\n"); + return -1; + } + + c->authorized = 1; + if (c->auth_timeout_event) { + c->protocol->core->mainloop->time_free(c->auth_timeout_event); + c->auth_timeout_event = NULL; + } + } + + ekey = *(const uint32_t*)((const uint8_t*) data+ESD_KEY_LEN); + if (ekey == ESD_ENDIAN_KEY) + c->swap_byte_order = 0; + else if (ekey == ESD_SWAP_ENDIAN_KEY) + c->swap_byte_order = 1; + else { + pa_log(__FILE__": client sent invalid endian key\n"); + return -1; + } + + ok = connection_write(c, sizeof(int)); + assert(ok); + *ok = 1; + return 0; +} + +static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + char name[ESD_NAME_MAX]; + int format, rate; + pa_sink *sink; + pa_sample_spec ss; + size_t l; + assert(c && length == (sizeof(int)*2+ESD_NAME_MAX)); + + format = MAYBE_INT32_SWAP(c->swap_byte_order, *(const int*)data); + rate = MAYBE_INT32_SWAP(c->swap_byte_order, *((const int*)data + 1)); + + ss.rate = rate; + format_esd2native(format, c->swap_byte_order, &ss); + + if (!pa_sample_spec_valid(&ss)) { + pa_log(__FILE__": invalid sample specification\n"); + return -1; + } + + if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { + pa_log(__FILE__": no such sink\n"); + return -1; + } + + strncpy(name, (const char*) data + sizeof(int)*2, sizeof(name)); + name[sizeof(name)-1] = 0; + + pa_client_set_name(c->client, name); + + assert(!c->sink_input && !c->input_memblockq); + + if (!(c->sink_input = pa_sink_input_new(sink, __FILE__, name, &ss, NULL, 0, -1))) { + pa_log(__FILE__": failed to create sink input.\n"); + return -1; + } + + l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); + c->input_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&ss), l/2, l/PLAYBACK_BUFFER_FRAGMENTS, c->protocol->core->memblock_stat); + pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2); + c->playback.fragment_size = l/10; + + c->sink_input->owner = c->protocol->module; + c->sink_input->client = c->client; + c->sink_input->peek = sink_input_peek_cb; + c->sink_input->drop = sink_input_drop_cb; + c->sink_input->kill = sink_input_kill_cb; + c->sink_input->get_latency = sink_input_get_latency_cb; + c->sink_input->userdata = c; + + c->state = ESD_STREAMING_DATA; + + c->protocol->n_player++; + + return 0; +} + +static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length) { + char name[ESD_NAME_MAX]; + int format, rate; + pa_source *source; + pa_sample_spec ss; + size_t l; + assert(c && length == (sizeof(int)*2+ESD_NAME_MAX)); + + format = MAYBE_INT32_SWAP(c->swap_byte_order, *(const int*)data); + rate = MAYBE_INT32_SWAP(c->swap_byte_order, *((const int*)data + 1)); + + ss.rate = rate; + format_esd2native(format, c->swap_byte_order, &ss); + + if (!pa_sample_spec_valid(&ss)) { + pa_log(__FILE__": invalid sample specification.\n"); + return -1; + } + + if (request == ESD_PROTO_STREAM_MON) { + pa_sink* sink; + + if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { + pa_log(__FILE__": no such sink.\n"); + return -1; + } + + if (!(source = sink->monitor_source)) { + pa_log(__FILE__": no such monitor source.\n"); + return -1; + } + } else { + assert(request == ESD_PROTO_STREAM_REC); + + if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) { + pa_log(__FILE__": no such source.\n"); + return -1; + } + } + + strncpy(name, (const char*) data + sizeof(int)*2, sizeof(name)); + name[sizeof(name)-1] = 0; + + pa_client_set_name(c->client, name); + + assert(!c->output_memblockq && !c->source_output); + + if (!(c->source_output = pa_source_output_new(source, __FILE__, name, &ss, NULL, -1))) { + pa_log(__FILE__": failed to create source output\n"); + return -1; + } + + l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); + c->output_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&ss), 0, 0, c->protocol->core->memblock_stat); + pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); + + c->source_output->owner = c->protocol->module; + c->source_output->client = c->client; + c->source_output->push = source_output_push_cb; + c->source_output->kill = source_output_kill_cb; + c->source_output->get_latency = source_output_get_latency_cb; + c->source_output->userdata = c; + + c->state = ESD_STREAMING_DATA; + + c->protocol->n_player++; + + return 0; +} + +static int esd_proto_get_latency(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + pa_sink *sink; + int latency, *lag; + assert(c && !data && length == 0); + + if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) + latency = 0; + else { + double usec = pa_sink_get_latency(sink); + latency = (int) ((usec*44100)/1000000); + } + + lag = connection_write(c, sizeof(int)); + assert(lag); + *lag = MAYBE_INT32_SWAP(c->swap_byte_order, latency); + return 0; +} + +static int esd_proto_server_info(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + int rate = 44100, format = ESD_STEREO|ESD_BITS16; + int *response; + pa_sink *sink; + assert(c && data && length == sizeof(int)); + + if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { + rate = sink->sample_spec.rate; + format = format_native2esd(&sink->sample_spec); + } + + response = connection_write(c, sizeof(int)*3); + assert(response); + *(response++) = 0; + *(response++) = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + *(response++) = MAYBE_INT32_SWAP(c->swap_byte_order, format); + return 0; +} + +static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length) { + uint8_t *response; + size_t t, k, s; + struct connection *conn; + size_t idx = PA_IDXSET_INVALID; + unsigned nsamples; + assert(c && data && length == sizeof(int)); + + if (esd_proto_server_info(c, request, data, length) < 0) + return -1; + + k = sizeof(int)*5+ESD_NAME_MAX; + s = sizeof(int)*6+ESD_NAME_MAX; + nsamples = c->protocol->core->scache ? pa_idxset_size(c->protocol->core->scache) : 0; + response = connection_write(c, (t = s*(nsamples+1) + k*(c->protocol->n_player+1))); + assert(k); + + for (conn = pa_idxset_first(c->protocol->connections, &idx); conn; conn = pa_idxset_next(c->protocol->connections, &idx)) { + int format = ESD_BITS16 | ESD_STEREO, rate = 44100, lvolume = ESD_VOLUME_BASE, rvolume = ESD_VOLUME_BASE; + + if (conn->state != ESD_STREAMING_DATA) + continue; + + assert(t >= s+k+k); + + if (conn->sink_input) { + rate = conn->sink_input->sample_spec.rate; + lvolume = (conn->sink_input->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; + rvolume = (conn->sink_input->volume.values[1]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; + format = format_native2esd(&conn->sink_input->sample_spec); + } + + /* id */ + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (int) (conn->index+1)); + response += sizeof(int); + + /* name */ + assert(conn->client); + strncpy((char*) response, conn->client->name, ESD_NAME_MAX); + response += ESD_NAME_MAX; + + /* rate */ + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + response += sizeof(int); + + /* left */ + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, lvolume); + response += sizeof(int); + + /*right*/ + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, rvolume); + response += sizeof(int); + + /*format*/ + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, format); + response += sizeof(int); + + t-= k; + } + + assert(t == s*(nsamples+1)+k); + memset(response, 0, k); + response += k; + t -= k; + + if (nsamples) { + pa_scache_entry *ce; + + idx = PA_IDXSET_INVALID; + for (ce = pa_idxset_first(c->protocol->core->scache, &idx); ce; ce = pa_idxset_next(c->protocol->core->scache, &idx)) { + assert(t >= s*2); + + /* id */ + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (int) (ce->index+1)); + response += sizeof(int); + + /* name */ + if (strncmp(ce->name, SCACHE_PREFIX, sizeof(SCACHE_PREFIX)-1) == 0) + strncpy((char*) response, ce->name+sizeof(SCACHE_PREFIX)-1, ESD_NAME_MAX); + else + snprintf((char*) response, ESD_NAME_MAX, "native.%s", ce->name); + response += ESD_NAME_MAX; + + /* rate */ + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, ce->sample_spec.rate); + response += sizeof(int); + + /* left */ + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); + response += sizeof(int); + + /*right*/ + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); + response += sizeof(int); + + /*format*/ + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, format_native2esd(&ce->sample_spec)); + response += sizeof(int); + + /*length*/ + *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (int) ce->memchunk.length); + response += sizeof(int); + + t -= s; + } + } + + assert(t == s); + memset(response, 0, s); + + return 0; +} + +static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + int *ok; + uint32_t idx; + pa_volume_t lvolume, rvolume; + struct connection *conn; + assert(c && data && length == sizeof(int)*3); + + idx = MAYBE_UINT32_SWAP(c->swap_byte_order, *(const int*)data)-1; + lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, *((const int*)data + 1)); + lvolume = (lvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; + rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, *((const int*)data + 2)); + rvolume = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; + + ok = connection_write(c, sizeof(int)); + assert(ok); + + if ((conn = pa_idxset_get_by_index(c->protocol->connections, idx))) { + assert(conn->sink_input); + conn->sink_input->volume.values[0] = lvolume; + conn->sink_input->volume.values[1] = rvolume; + conn->sink_input->volume.channels = 2; + *ok = 1; + } else + *ok = 0; + + return 0; +} + +static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + pa_sample_spec ss; + int format, rate; + size_t sc_length; + uint32_t idx; + int *ok; + char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; + assert(c && data && length == (ESD_NAME_MAX+3*sizeof(int))); + + format = MAYBE_INT32_SWAP(c->swap_byte_order, *(const int*)data); + rate = MAYBE_INT32_SWAP(c->swap_byte_order, *((const int*)data + 1)); + + ss.rate = rate; + format_esd2native(format, c->swap_byte_order, &ss); + + sc_length = (size_t) MAYBE_INT32_SWAP(c->swap_byte_order, (*((const int*)data + 2))); + + if (sc_length >= MAX_CACHE_SAMPLE_SIZE) + return -1; + + strcpy(name, SCACHE_PREFIX); + strncpy(name+sizeof(SCACHE_PREFIX)-1, (const char*) data+3*sizeof(int), ESD_NAME_MAX); + name[sizeof(name)-1] = 0; + + assert(!c->scache.memchunk.memblock); + c->scache.memchunk.memblock = pa_memblock_new(sc_length, c->protocol->core->memblock_stat); + c->scache.memchunk.index = 0; + c->scache.memchunk.length = sc_length; + c->scache.sample_spec = ss; + assert(!c->scache.name); + c->scache.name = pa_xstrdup(name); + + c->state = ESD_CACHING_SAMPLE; + + pa_scache_add_item(c->protocol->core, c->scache.name, NULL, NULL, NULL, &idx); + + ok = connection_write(c, sizeof(int)); + assert(ok); + + *ok = idx+1; + + return 0; +} + +static int esd_proto_sample_get_id(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + int *ok; + uint32_t idx; + char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; + assert(c && data && length == ESD_NAME_MAX); + + ok = connection_write(c, sizeof(int)); + assert(ok); + + *ok = -1; + + strcpy(name, SCACHE_PREFIX); + strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX); + name[sizeof(name)-1] = 0; + + if ((idx = pa_scache_get_id_by_name(c->protocol->core, name)) != PA_IDXSET_INVALID) + *ok = (int) idx +1; + + return 0; +} + +static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length) { + int *ok; + const char *name; + uint32_t idx; + assert(c && data && length == sizeof(int)); + + idx = (uint32_t) MAYBE_INT32_SWAP(c->swap_byte_order, *(const int*)data)-1; + + ok = connection_write(c, sizeof(int)); + assert(ok); + + *ok = 0; + + if ((name = pa_scache_get_name_by_id(c->protocol->core, idx))) { + if (request == ESD_PROTO_SAMPLE_PLAY) { + pa_sink *sink; + + if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) + if (pa_scache_play_item(c->protocol->core, name, sink, NULL) >= 0) + *ok = (int) idx+1; + } else { + assert(request == ESD_PROTO_SAMPLE_FREE); + + if (pa_scache_remove_item(c->protocol->core, name) >= 0) + *ok = (int) idx+1; + } + } + + return 0; +} + +static int esd_proto_standby_or_resume(struct connection *c, PA_GCC_UNUSED esd_proto_t request, PA_GCC_UNUSED const void *data, PA_GCC_UNUSED size_t length) { + int *ok; + ok = connection_write(c, sizeof(int)*2); + assert(ok); + ok[0] = 1; + ok[1] = 1; + return 0; +} + +/*** client callbacks ***/ + +static void client_kill_cb(pa_client *c) { + assert(c && c->userdata); + connection_free(c->userdata); +} + +/*** pa_iochannel callbacks ***/ + +static int do_read(struct connection *c) { + assert(c && c->io); + +/* pa_log("READ\n"); */ + + if (c->state == ESD_NEXT_REQUEST) { + ssize_t r; + assert(c->read_data_length < sizeof(c->request)); + + if ((r = pa_iochannel_read(c->io, ((uint8_t*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { + if (r != 0) + pa_log_warn(__FILE__": read() failed: %s\n", strerror(errno)); + return -1; + } + + if ((c->read_data_length+= r) >= sizeof(c->request)) { + struct proto_handler *handler; + + c->request = MAYBE_INT32_SWAP(c->swap_byte_order, c->request); + + if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) { + pa_log(__FILE__": recieved invalid request.\n"); + return -1; + } + + handler = proto_map+c->request; + +/* pa_log(__FILE__": executing request #%u\n", c->request); */ + + if (!handler->proc) { + pa_log(__FILE__": recieved unimplemented request #%u.\n", c->request); + return -1; + } + + if (handler->data_length == 0) { + c->read_data_length = 0; + + if (handler->proc(c, c->request, NULL, 0) < 0) + return -1; + + } else { + if (c->read_data_alloc < handler->data_length) + c->read_data = pa_xrealloc(c->read_data, c->read_data_alloc = handler->data_length); + assert(c->read_data); + + c->state = ESD_NEEDS_REQDATA; + c->read_data_length = 0; + } + } + + } else if (c->state == ESD_NEEDS_REQDATA) { + ssize_t r; + struct proto_handler *handler = proto_map+c->request; + + assert(handler->proc); + + assert(c->read_data && c->read_data_length < handler->data_length); + + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { + if (r != 0) + pa_log_warn(__FILE__": read() failed: %s\n", strerror(errno)); + return -1; + } + + if ((c->read_data_length+= r) >= handler->data_length) { + size_t l = c->read_data_length; + assert(handler->proc); + + c->state = ESD_NEXT_REQUEST; + c->read_data_length = 0; + + if (handler->proc(c, c->request, c->read_data, l) < 0) + return -1; + } + } else if (c->state == ESD_CACHING_SAMPLE) { + ssize_t r; + + assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); + + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { + if (r!= 0) + pa_log_warn(__FILE__": read() failed: %s\n", strerror(errno)); + return -1; + } + + c->scache.memchunk.index += r; + assert(c->scache.memchunk.index <= c->scache.memchunk.length); + + if (c->scache.memchunk.index == c->scache.memchunk.length) { + uint32_t idx; + int *ok; + + c->scache.memchunk.index = 0; + pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, NULL, &c->scache.memchunk, &idx); + + pa_memblock_unref(c->scache.memchunk.memblock); + c->scache.memchunk.memblock = NULL; + c->scache.memchunk.index = c->scache.memchunk.length = 0; + + pa_xfree(c->scache.name); + c->scache.name = NULL; + + c->state = ESD_NEXT_REQUEST; + + ok = connection_write(c, sizeof(int)); + assert(ok); + *ok = idx+1; + } + + } else if (c->state == ESD_STREAMING_DATA && c->sink_input) { + pa_memchunk chunk; + ssize_t r; + size_t l; + + assert(c->input_memblockq); + +/* pa_log("STREAMING_DATA\n"); */ + + if (!(l = pa_memblockq_missing(c->input_memblockq))) + return 0; + + if (l > c->playback.fragment_size) + l = c->playback.fragment_size; + + if (c->playback.current_memblock) + if (c->playback.current_memblock->length - c->playback.memblock_index < l) { + pa_memblock_unref(c->playback.current_memblock); + c->playback.current_memblock = NULL; + c->playback.memblock_index = 0; + } + + if (!c->playback.current_memblock) { + c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2, c->protocol->core->memblock_stat); + assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); + c->playback.memblock_index = 0; + } + + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { + if (r != 0) + pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + return -1; + } + +/* pa_log(__FILE__": read %u\n", r); */ + + chunk.memblock = c->playback.current_memblock; + chunk.index = c->playback.memblock_index; + chunk.length = r; + assert(chunk.memblock); + + c->playback.memblock_index += r; + + assert(c->input_memblockq); + pa_memblockq_push_align(c->input_memblockq, &chunk, 0); + assert(c->sink_input); + pa_sink_notify(c->sink_input->sink); + } + + return 0; +} + +static int do_write(struct connection *c) { + assert(c && c->io); + +/* pa_log("WRITE\n"); */ + + if (c->write_data_length) { + ssize_t r; + + assert(c->write_data_index < c->write_data_length); + if ((r = pa_iochannel_write(c->io, (uint8_t*) c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + return -1; + } + + if ((c->write_data_index +=r) >= c->write_data_length) + c->write_data_length = c->write_data_index = 0; + + } else if (c->state == ESD_STREAMING_DATA && c->source_output) { + pa_memchunk chunk; + ssize_t r; + + assert(c->output_memblockq); + if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) + return 0; + + assert(chunk.memblock && chunk.length); + + if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { + pa_memblock_unref(chunk.memblock); + pa_log(__FILE__": write(): %s\n", strerror(errno)); + return -1; + } + + pa_memblockq_drop(c->output_memblockq, &chunk, r); + pa_memblock_unref(chunk.memblock); + } + + return 0; +} + +static void do_work(struct connection *c) { + assert(c); + + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 0); + +/* pa_log("DOWORK %i\n", pa_iochannel_is_hungup(c->io)); */ + + if (!c->dead && pa_iochannel_is_readable(c->io)) + if (do_read(c) < 0) + goto fail; + + if (!c->dead && pa_iochannel_is_writable(c->io)) + if (do_write(c) < 0) + goto fail; + + /* In case the line was hungup, make sure to rerun this function + as soon as possible, until all data has been read. */ + + if (!c->dead && pa_iochannel_is_hungup(c->io)) + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + + return; + +fail: + + if (c->state == ESD_STREAMING_DATA && c->sink_input) { + c->dead = 1; + pa_memblockq_prebuf_disable(c->input_memblockq); + + pa_iochannel_free(c->io); + c->io = NULL; + + } else + connection_free(c); +} + +static void io_callback(pa_iochannel*io, void *userdata) { + struct connection *c = userdata; + assert(io && c && c->io == io); + +/* pa_log("IO\n"); */ + + do_work(c); +} + +/*** defer callback ***/ + +static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { + struct connection *c = userdata; + assert(a && c && c->defer_event == e); + +/* pa_log("DEFER\n"); */ + + do_work(c); +} + +/*** sink_input callbacks ***/ + +static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { + struct connection*c; + assert(i && i->userdata && chunk); + c = i->userdata; + + if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) { + + if (c->dead) + connection_free(c); + + return -1; + } + + return 0; +} + +static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { + struct connection*c = i->userdata; + assert(i && c && length); + +/* pa_log("DROP\n"); */ + + pa_memblockq_drop(c->input_memblockq, chunk, length); + + /* do something */ + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + + if (!c->dead) + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + +/* assert(pa_memblockq_get_length(c->input_memblockq) > 2048); */ +} + +static void sink_input_kill_cb(pa_sink_input *i) { + assert(i && i->userdata); + connection_free((struct connection *) i->userdata); +} + +static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { + struct connection*c = i->userdata; + assert(i && c); + return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); +} + +/*** source_output callbacks ***/ + +static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { + struct connection *c = o->userdata; + assert(o && c && chunk); + + pa_memblockq_push(c->output_memblockq, chunk, 0); + + /* do something */ + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + + if (!c->dead) + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); +} + +static void source_output_kill_cb(pa_source_output *o) { + assert(o && o->userdata); + connection_free((struct connection *) o->userdata); +} + +static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { + struct connection*c = o->userdata; + assert(o && c); + return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec); +} + +/*** socket server callback ***/ + +static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { + struct connection *c = userdata; + assert(m && tv && c && c->auth_timeout_event == e); + + if (!c->authorized) + connection_free(c); +} + +static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { + struct connection *c; + pa_protocol_esound *p = userdata; + char cname[256]; + assert(s && io && p); + + if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { + pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); + pa_iochannel_free(io); + return; + } + + c = pa_xmalloc(sizeof(struct connection)); + c->protocol = p; + c->io = io; + pa_iochannel_set_callback(c->io, io_callback, c); + + pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); + assert(p->core); + c->client = pa_client_new(p->core, __FILE__, cname); + assert(c->client); + c->client->owner = p->module; + c->client->kill = client_kill_cb; + c->client->userdata = c; + + c->authorized = p->public; + c->swap_byte_order = 0; + c->dead = 0; + + c->read_data_length = 0; + c->read_data = pa_xmalloc(c->read_data_alloc = proto_map[ESD_PROTO_CONNECT].data_length); + + c->write_data_length = c->write_data_index = c->write_data_alloc = 0; + c->write_data = NULL; + + c->state = ESD_NEEDS_REQDATA; + c->request = ESD_PROTO_CONNECT; + + c->sink_input = NULL; + c->input_memblockq = NULL; + + c->source_output = NULL; + c->output_memblockq = NULL; + + c->playback.current_memblock = NULL; + c->playback.memblock_index = 0; + c->playback.fragment_size = 0; + + c->scache.memchunk.length = c->scache.memchunk.index = 0; + c->scache.memchunk.memblock = NULL; + c->scache.name = NULL; + + if (!c->authorized) { + struct timeval tv; + pa_gettimeofday(&tv); + tv.tv_sec += AUTH_TIMEOUT; + c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c); + } else + c->auth_timeout_event = NULL; + + c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c); + assert(c->defer_event); + p->core->mainloop->defer_enable(c->defer_event, 0); + + pa_idxset_put(p->connections, c, &c->index); +} + +/*** entry points ***/ + +pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { + pa_protocol_esound *p; + int public = 0; + assert(core && server && ma); + + p = pa_xmalloc(sizeof(pa_protocol_esound)); + + if (pa_modargs_get_value_boolean(ma, "public", &public) < 0) { + pa_log(__FILE__": public= expects a boolean argument.\n"); + return NULL; + } + + if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", DEFAULT_COOKIE_FILE), p->esd_key, sizeof(p->esd_key)) < 0) { + pa_xfree(p); + return NULL; + } + + p->module = m; + p->public = public; + p->server = server; + pa_socket_server_set_callback(p->server, on_connection, p); + p->core = core; + p->connections = pa_idxset_new(NULL, NULL); + assert(p->connections); + + p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); + p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL)); + p->n_player = 0; + + return p; +} + +void pa_protocol_esound_free(pa_protocol_esound *p) { + struct connection *c; + assert(p); + + while ((c = pa_idxset_first(p->connections, NULL))) + connection_free(c); + + pa_idxset_free(p->connections, NULL, NULL); + pa_socket_server_unref(p->server); + pa_xfree(p); +} diff --git a/src/polypcore/protocol-esound.h b/src/polypcore/protocol-esound.h new file mode 100644 index 00000000..71d58464 --- /dev/null +++ b/src/polypcore/protocol-esound.h @@ -0,0 +1,35 @@ +#ifndef fooprotocolesoundhfoo +#define fooprotocolesoundhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" +#include "socket-server.h" +#include "module.h" +#include "modargs.h" + +typedef struct pa_protocol_esound pa_protocol_esound; + +pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma); +void pa_protocol_esound_free(pa_protocol_esound *p); + +#endif diff --git a/src/polypcore/protocol-http.c b/src/polypcore/protocol-http.c new file mode 100644 index 00000000..3e55df03 --- /dev/null +++ b/src/polypcore/protocol-http.c @@ -0,0 +1,265 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "protocol-http.h" +#include "ioline.h" +#include "xmalloc.h" +#include "log.h" +#include "namereg.h" +#include "cli-text.h" + +/* Don't allow more than this many concurrent connections */ +#define MAX_CONNECTIONS 10 + +#define internal_server_error(c) http_message((c), 500, "Internal Server Error", NULL) + +#define URL_ROOT "/" +#define URL_CSS "/style" +#define URL_STATUS "/status" + +struct connection { + pa_protocol_http *protocol; + pa_ioline *line; + enum { REQUEST_LINE, MIME_HEADER, DATA } state; + char *url; +}; + +struct pa_protocol_http { + pa_module *module; + pa_core *core; + pa_socket_server*server; + pa_idxset *connections; +}; + +static void http_response(struct connection *c, int code, const char *msg, const char *mime) { + char s[256]; + assert(c); + assert(msg); + assert(mime); + + snprintf(s, sizeof(s), + "HTTP/1.0 %i %s\n" + "Connection: close\n" + "Content-Type: %s\n" + "Cache-Control: no-cache\n" + "Expires: 0\n" + "Server: "PACKAGE_NAME"/"PACKAGE_VERSION"\n" + "\n", code, msg, mime); + + pa_ioline_puts(c->line, s); +} + +static void http_message(struct connection *c, int code, const char *msg, const char *text) { + char s[256]; + assert(c); + + http_response(c, code, msg, "text/html"); + + if (!text) + text = msg; + + snprintf(s, sizeof(s), + "\n" + "\n" + "%s\n" + "%s\n", + text, text); + + pa_ioline_puts(c->line, s); + pa_ioline_defer_close(c->line); +} + + +static void connection_free(struct connection *c, int del) { + assert(c); + + if (c->url) + pa_xfree(c->url); + + if (del) + pa_idxset_remove_by_data(c->protocol->connections, c, NULL); + pa_ioline_unref(c->line); + pa_xfree(c); +} + +static void line_callback(pa_ioline *line, const char *s, void *userdata) { + struct connection *c = userdata; + assert(line); + assert(c); + + if (!s) { + /* EOF */ + connection_free(c, 1); + return; + } + + switch (c->state) { + case REQUEST_LINE: { + if (memcmp(s, "GET ", 4)) + goto fail; + + s +=4; + + c->url = pa_xstrndup(s, strcspn(s, " \r\n\t?")); + c->state = MIME_HEADER; + break; + + } + + case MIME_HEADER: { + + /* Ignore MIME headers */ + if (strcspn(s, " \r\n") != 0) + break; + + /* We're done */ + c->state = DATA; + + pa_log_info(__FILE__": request for %s\n", c->url); + + if (!strcmp(c->url, URL_ROOT)) { + char txt[256]; + http_response(c, 200, "OK", "text/html"); + + pa_ioline_puts(c->line, + "\n" + "\n" + ""PACKAGE_NAME" "PACKAGE_VERSION"\n" + "\n"); + + pa_ioline_puts(c->line, + "

    "PACKAGE_NAME" "PACKAGE_VERSION"

    \n" + ""); + +#define PRINTF_FIELD(a,b) pa_ioline_printf(c->line, "\n",(a),(b)) + + PRINTF_FIELD("User Name:", pa_get_user_name(txt, sizeof(txt))); + PRINTF_FIELD("Fully Qualified Domain Name:", pa_get_fqdn(txt, sizeof(txt))); + PRINTF_FIELD("Default Sample Specification:", pa_sample_spec_snprint(txt, sizeof(txt), &c->protocol->core->default_sample_spec)); + PRINTF_FIELD("Default Sink:", pa_namereg_get_default_sink_name(c->protocol->core)); + PRINTF_FIELD("Default Source:", pa_namereg_get_default_source_name(c->protocol->core)); + + pa_ioline_puts(c->line, "
    %s%s
    "); + + pa_ioline_puts(c->line, "

    Click here for an extensive server status report.

    "); + + pa_ioline_puts(c->line, "\n"); + + pa_ioline_defer_close(c->line); + } else if (!strcmp(c->url, URL_CSS)) { + http_response(c, 200, "OK", "text/css"); + + pa_ioline_puts(c->line, + "body { color: black; background-color: white; margin: 0.5cm; }\n" + "a:link, a:visited { color: #900000; }\n" + "p { margin-left: 0.5cm; margin-right: 0.5cm; }\n" + "h1 { color: #00009F; }\n" + "h2 { color: #00009F; }\n" + "ul { margin-left: .5cm; }\n" + "ol { margin-left: .5cm; }\n" + "pre { margin-left: .5cm; background-color: #f0f0f0; padding: 0.4cm;}\n" + ".grey { color: #afafaf; }\n" + "table { margin-left: 1cm; border:1px solid lightgrey; padding: 0.2cm; }\n" + "td { padding-left:10px; padding-right:10px; }\n"); + + pa_ioline_defer_close(c->line); + } else if (!strcmp(c->url, URL_STATUS)) { + char *r; + + http_response(c, 200, "OK", "text/plain"); + r = pa_full_status_string(c->protocol->core); + pa_ioline_puts(c->line, r); + pa_xfree(r); + + pa_ioline_defer_close(c->line); + } else + http_message(c, 404, "Not Found", NULL); + + break; + } + + default: + ; + } + + return; + +fail: + internal_server_error(c); +} + +static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { + pa_protocol_http *p = userdata; + struct connection *c; + assert(s && io && p); + + if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { + pa_log_warn(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); + pa_iochannel_free(io); + return; + } + + c = pa_xmalloc(sizeof(struct connection)); + c->protocol = p; + c->line = pa_ioline_new(io); + c->state = REQUEST_LINE; + c->url = NULL; + + pa_ioline_set_callback(c->line, line_callback, c); + pa_idxset_put(p->connections, c, NULL); +} + +pa_protocol_http* pa_protocol_http_new(pa_core *core, pa_socket_server *server, pa_module *m, PA_GCC_UNUSED pa_modargs *ma) { + pa_protocol_http* p; + assert(core && server); + + p = pa_xmalloc(sizeof(pa_protocol_http)); + p->module = m; + p->core = core; + p->server = server; + p->connections = pa_idxset_new(NULL, NULL); + + pa_socket_server_set_callback(p->server, on_connection, p); + + return p; +} + +static void free_connection(void *p, PA_GCC_UNUSED void *userdata) { + assert(p); + connection_free(p, 0); +} + +void pa_protocol_http_free(pa_protocol_http *p) { + assert(p); + + pa_idxset_free(p->connections, free_connection, NULL); + pa_socket_server_unref(p->server); + pa_xfree(p); +} diff --git a/src/polypcore/protocol-http.h b/src/polypcore/protocol-http.h new file mode 100644 index 00000000..0a1855e9 --- /dev/null +++ b/src/polypcore/protocol-http.h @@ -0,0 +1,35 @@ +#ifndef fooprotocolhttphfoo +#define fooprotocolhttphfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" +#include "socket-server.h" +#include "module.h" +#include "modargs.h" + +typedef struct pa_protocol_http pa_protocol_http; + +pa_protocol_http* pa_protocol_http_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma); +void pa_protocol_http_free(pa_protocol_http *n); + +#endif diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c new file mode 100644 index 00000000..b94903d9 --- /dev/null +++ b/src/polypcore/protocol-native.c @@ -0,0 +1,2216 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "protocol-native.h" +#include "native-common.h" +#include "packet.h" +#include "client.h" +#include "source-output.h" +#include "sink-input.h" +#include "pstream.h" +#include "tagstruct.h" +#include "pdispatch.h" +#include "pstream-util.h" +#include "authkey.h" +#include "namereg.h" +#include "scache.h" +#include "xmalloc.h" +#include "util.h" +#include "subscribe.h" +#include "log.h" +#include "autoload.h" +#include "authkey-prop.h" +#include "strlist.h" +#include "props.h" + +/* Kick a client if it doesn't authenticate within this time */ +#define AUTH_TIMEOUT 5 + +/* Don't accept more connection than this */ +#define MAX_CONNECTIONS 10 + +struct connection; +struct pa_protocol_native; + +struct record_stream { + struct connection *connection; + uint32_t index; + pa_source_output *source_output; + pa_memblockq *memblockq; + size_t fragment_size; +}; + +struct playback_stream { + int type; + struct connection *connection; + uint32_t index; + pa_sink_input *sink_input; + pa_memblockq *memblockq; + size_t requested_bytes; + int drain_request; + uint32_t drain_tag; +}; + +struct upload_stream { + int type; + struct connection *connection; + uint32_t index; + pa_memchunk memchunk; + size_t length; + char *name; + pa_sample_spec sample_spec; + pa_channel_map channel_map; +}; + +struct output_stream { + int type; +}; + +enum { + UPLOAD_STREAM, + PLAYBACK_STREAM +}; + +struct connection { + int authorized; + pa_protocol_native *protocol; + pa_client *client; + pa_pstream *pstream; + pa_pdispatch *pdispatch; + pa_idxset *record_streams, *output_streams; + uint32_t rrobin_index; + pa_subscription *subscription; + pa_time_event *auth_timeout_event; +}; + +struct pa_protocol_native { + pa_module *module; + int public; + pa_core *core; + pa_socket_server *server; + pa_idxset *connections; + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; + int auth_cookie_in_property; +}; + +static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk); +static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length); +static void sink_input_kill_cb(pa_sink_input *i); +static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i); + +static void request_bytes(struct playback_stream*s); + +static void source_output_kill_cb(pa_source_output *o); +static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk); +static pa_usec_t source_output_get_latency_cb(pa_source_output *o); + +static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_flush_or_trigger_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_add_autoload(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_remove_autoload(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_autoload_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_autoload_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); + +static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = NULL, + [PA_COMMAND_TIMEOUT] = NULL, + [PA_COMMAND_REPLY] = NULL, + [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream, + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream, + [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream, + [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream, + [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream, + [PA_COMMAND_AUTH] = command_auth, + [PA_COMMAND_REQUEST] = NULL, + [PA_COMMAND_EXIT] = command_exit, + [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name, + [PA_COMMAND_LOOKUP_SINK] = command_lookup, + [PA_COMMAND_LOOKUP_SOURCE] = command_lookup, + [PA_COMMAND_STAT] = command_stat, + [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency, + [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency, + [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream, + [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream, + [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream, + [PA_COMMAND_PLAY_SAMPLE] = command_play_sample, + [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample, + [PA_COMMAND_GET_SINK_INFO] = command_get_info, + [PA_COMMAND_GET_SOURCE_INFO] = command_get_info, + [PA_COMMAND_GET_CLIENT_INFO] = command_get_info, + [PA_COMMAND_GET_MODULE_INFO] = command_get_info, + [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info, + [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info, + [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info, + [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info, + [PA_COMMAND_SUBSCRIBE] = command_subscribe, + + [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume, + [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume, + + [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream, + [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_flush_or_trigger_playback_stream, + [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_flush_or_trigger_playback_stream, + [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_flush_or_trigger_playback_stream, + + [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream, + [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream, + + [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source, + [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source, + [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name, + [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name, + [PA_COMMAND_KILL_CLIENT] = command_kill, + [PA_COMMAND_KILL_SINK_INPUT] = command_kill, + [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill, + [PA_COMMAND_LOAD_MODULE] = command_load_module, + [PA_COMMAND_UNLOAD_MODULE] = command_unload_module, + [PA_COMMAND_GET_AUTOLOAD_INFO] = command_get_autoload_info, + [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = command_get_autoload_info_list, + [PA_COMMAND_ADD_AUTOLOAD] = command_add_autoload, + [PA_COMMAND_REMOVE_AUTOLOAD] = command_remove_autoload, + +}; + +/* structure management */ + +static struct upload_stream* upload_stream_new( + struct connection *c, + const pa_sample_spec *ss, + const pa_channel_map *map, + const char *name, size_t length) { + + struct upload_stream *s; + assert(c && ss && name && length); + + s = pa_xmalloc(sizeof(struct upload_stream)); + s->type = UPLOAD_STREAM; + s->connection = c; + s->sample_spec = *ss; + s->channel_map = *map; + s->name = pa_xstrdup(name); + + s->memchunk.memblock = NULL; + s->memchunk.index = 0; + s->memchunk.length = 0; + + s->length = length; + + pa_idxset_put(c->output_streams, s, &s->index); + return s; +} + +static void upload_stream_free(struct upload_stream *o) { + assert(o && o->connection); + + pa_idxset_remove_by_data(o->connection->output_streams, o, NULL); + + pa_xfree(o->name); + + if (o->memchunk.memblock) + pa_memblock_unref(o->memchunk.memblock); + + pa_xfree(o); +} + +static struct record_stream* record_stream_new( + struct connection *c, + pa_source *source, + const pa_sample_spec *ss, + const pa_channel_map *map, + const char *name, + size_t maxlength, + size_t fragment_size) { + + struct record_stream *s; + pa_source_output *source_output; + size_t base; + assert(c && source && ss && name && maxlength); + + if (!(source_output = pa_source_output_new(source, __FILE__, name, ss, map, -1))) + return NULL; + + s = pa_xmalloc(sizeof(struct record_stream)); + s->connection = c; + s->source_output = source_output; + s->source_output->push = source_output_push_cb; + s->source_output->kill = source_output_kill_cb; + s->source_output->get_latency = source_output_get_latency_cb; + s->source_output->userdata = s; + s->source_output->owner = c->protocol->module; + s->source_output->client = c->client; + + s->memblockq = pa_memblockq_new(maxlength, 0, base = pa_frame_size(ss), 0, 0, c->protocol->core->memblock_stat); + assert(s->memblockq); + + s->fragment_size = (fragment_size/base)*base; + if (!s->fragment_size) + s->fragment_size = base; + + pa_idxset_put(c->record_streams, s, &s->index); + return s; +} + +static void record_stream_free(struct record_stream* r) { + assert(r && r->connection); + + pa_idxset_remove_by_data(r->connection->record_streams, r, NULL); + pa_source_output_disconnect(r->source_output); + pa_source_output_unref(r->source_output); + pa_memblockq_free(r->memblockq); + pa_xfree(r); +} + +static struct playback_stream* playback_stream_new( + struct connection *c, + pa_sink *sink, + const pa_sample_spec *ss, + const pa_channel_map *map, + const char *name, + size_t maxlength, + size_t tlength, + size_t prebuf, + size_t minreq, + pa_cvolume *volume) { + + struct playback_stream *s; + pa_sink_input *sink_input; + assert(c && sink && ss && name && maxlength); + + if (!(sink_input = pa_sink_input_new(sink, __FILE__, name, ss, map, 0, -1))) + return NULL; + + s = pa_xmalloc(sizeof(struct playback_stream)); + s->type = PLAYBACK_STREAM; + s->connection = c; + s->sink_input = sink_input; + + s->sink_input->peek = sink_input_peek_cb; + s->sink_input->drop = sink_input_drop_cb; + s->sink_input->kill = sink_input_kill_cb; + s->sink_input->get_latency = sink_input_get_latency_cb; + s->sink_input->userdata = s; + s->sink_input->owner = c->protocol->module; + s->sink_input->client = c->client; + + s->memblockq = pa_memblockq_new(maxlength, tlength, pa_frame_size(ss), prebuf, minreq, c->protocol->core->memblock_stat); + assert(s->memblockq); + + s->requested_bytes = 0; + s->drain_request = 0; + + s->sink_input->volume = *volume; + + pa_idxset_put(c->output_streams, s, &s->index); + return s; +} + +static void playback_stream_free(struct playback_stream* p) { + assert(p && p->connection); + + if (p->drain_request) + pa_pstream_send_error(p->connection->pstream, p->drain_tag, PA_ERROR_NOENTITY); + + pa_idxset_remove_by_data(p->connection->output_streams, p, NULL); + pa_sink_input_disconnect(p->sink_input); + pa_sink_input_unref(p->sink_input); + pa_memblockq_free(p->memblockq); + pa_xfree(p); +} + +static void connection_free(struct connection *c) { + struct record_stream *r; + struct output_stream *o; + assert(c && c->protocol); + + pa_idxset_remove_by_data(c->protocol->connections, c, NULL); + while ((r = pa_idxset_first(c->record_streams, NULL))) + record_stream_free(r); + pa_idxset_free(c->record_streams, NULL, NULL); + + while ((o = pa_idxset_first(c->output_streams, NULL))) + if (o->type == PLAYBACK_STREAM) + playback_stream_free((struct playback_stream*) o); + else + upload_stream_free((struct upload_stream*) o); + pa_idxset_free(c->output_streams, NULL, NULL); + + pa_pdispatch_unref(c->pdispatch); + pa_pstream_close(c->pstream); + pa_pstream_unref(c->pstream); + pa_client_free(c->client); + + if (c->subscription) + pa_subscription_free(c->subscription); + + if (c->auth_timeout_event) + c->protocol->core->mainloop->time_free(c->auth_timeout_event); + + pa_xfree(c); +} + +static void request_bytes(struct playback_stream *s) { + pa_tagstruct *t; + size_t l; + assert(s); + + if (!(l = pa_memblockq_missing(s->memblockq))) + return; + + if (l <= s->requested_bytes) + return; + + l -= s->requested_bytes; + + if (l < pa_memblockq_get_minreq(s->memblockq)) + return; + + s->requested_bytes += l; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_REQUEST); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, s->index); + pa_tagstruct_putu32(t, l); + pa_pstream_send_tagstruct(s->connection->pstream, t); + +/* pa_log(__FILE__": Requesting %u bytes\n", l); */ +} + +static void send_memblock(struct connection *c) { + uint32_t start; + struct record_stream *r; + + start = PA_IDXSET_INVALID; + for (;;) { + pa_memchunk chunk; + + if (!(r = pa_idxset_rrobin(c->record_streams, &c->rrobin_index))) + return; + + if (start == PA_IDXSET_INVALID) + start = c->rrobin_index; + else if (start == c->rrobin_index) + return; + + if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) { + pa_memchunk schunk = chunk; + + if (schunk.length > r->fragment_size) + schunk.length = r->fragment_size; + + pa_pstream_send_memblock(c->pstream, r->index, 0, &schunk); + pa_memblockq_drop(r->memblockq, &chunk, schunk.length); + pa_memblock_unref(schunk.memblock); + + return; + } + } +} + +static void send_playback_stream_killed(struct playback_stream *p) { + pa_tagstruct *t; + assert(p); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, p->index); + pa_pstream_send_tagstruct(p->connection->pstream, t); +} + +static void send_record_stream_killed(struct record_stream *r) { + pa_tagstruct *t; + assert(r); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, r->index); + pa_pstream_send_tagstruct(r->connection->pstream, t); +} + +/*** sinkinput callbacks ***/ + +static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { + struct playback_stream *s; + assert(i && i->userdata && chunk); + s = i->userdata; + + if (pa_memblockq_peek(s->memblockq, chunk) < 0) + return -1; + + return 0; +} + +static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { + struct playback_stream *s; + assert(i && i->userdata && length); + s = i->userdata; + + pa_memblockq_drop(s->memblockq, chunk, length); + request_bytes(s); + + if (s->drain_request && !pa_memblockq_is_readable(s->memblockq)) { + pa_pstream_send_simple_ack(s->connection->pstream, s->drain_tag); + s->drain_request = 0; + } + +/* pa_log(__FILE__": after_drop: %u\n", pa_memblockq_get_length(s->memblockq)); */ +} + +static void sink_input_kill_cb(pa_sink_input *i) { + assert(i && i->userdata); + send_playback_stream_killed((struct playback_stream *) i->userdata); + playback_stream_free((struct playback_stream *) i->userdata); +} + +static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { + struct playback_stream *s; + assert(i && i->userdata); + s = i->userdata; + + /*pa_log(__FILE__": get_latency: %u\n", pa_memblockq_get_length(s->memblockq));*/ + + return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec); +} + +/*** source_output callbacks ***/ + +static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { + struct record_stream *s; + assert(o && o->userdata && chunk); + s = o->userdata; + + pa_memblockq_push_align(s->memblockq, chunk, 0); + if (!pa_pstream_is_pending(s->connection->pstream)) + send_memblock(s->connection); +} + +static void source_output_kill_cb(pa_source_output *o) { + assert(o && o->userdata); + send_record_stream_killed((struct record_stream *) o->userdata); + record_stream_free((struct record_stream *) o->userdata); +} + +static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { + struct record_stream *s; + assert(o && o->userdata); + s = o->userdata; + + /*pa_log(__FILE__": get_latency: %u\n", pa_memblockq_get_length(s->memblockq));*/ + + return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec); +} + +/*** pdispatch callbacks ***/ + +static void protocol_error(struct connection *c) { + pa_log(__FILE__": protocol error, kicking client\n"); + connection_free(c); +} + +static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + struct playback_stream *s; + size_t maxlength, tlength, prebuf, minreq; + uint32_t sink_index; + const char *name, *sink_name; + pa_sample_spec ss; + pa_channel_map map; + pa_tagstruct *reply; + pa_sink *sink; + pa_cvolume volume; + int corked; + + assert(c && t && c->protocol && c->protocol->core); + + if (pa_tagstruct_get( + t, + PA_TAG_STRING, &name, + PA_TAG_SAMPLE_SPEC, &ss, + PA_TAG_CHANNEL_MAP, &map, + PA_TAG_U32, &sink_index, + PA_TAG_STRING, &sink_name, + PA_TAG_U32, &maxlength, + PA_TAG_BOOLEAN, &corked, + PA_TAG_U32, &tlength, + PA_TAG_U32, &prebuf, + PA_TAG_U32, &minreq, + PA_TAG_CVOLUME, &volume, + PA_TAG_INVALID) < 0 || + !pa_tagstruct_eof(t) || + !name) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (sink_index != (uint32_t) -1) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); + else + sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1); + + if (!sink) { + pa_log("%s: Can't find a suitable sink.\n", __FILE__); + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + if (!(s = playback_stream_new(c, sink, &ss, &map, name, maxlength, tlength, prebuf, minreq, &volume))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); + return; + } + + pa_sink_input_cork(s->sink_input, corked); + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, s->index); + assert(s->sink_input); + pa_tagstruct_putu32(reply, s->sink_input->index); + pa_tagstruct_putu32(reply, s->requested_bytes = pa_memblockq_missing(s->memblockq)); + pa_pstream_send_tagstruct(c->pstream, reply); + request_bytes(s); +} + +static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t channel; + assert(c && t); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (command == PA_COMMAND_DELETE_PLAYBACK_STREAM) { + struct playback_stream *s; + if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != PLAYBACK_STREAM)) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + return; + } + + playback_stream_free(s); + } else if (command == PA_COMMAND_DELETE_RECORD_STREAM) { + struct record_stream *s; + if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + return; + } + + record_stream_free(s); + } else { + struct upload_stream *s; + assert(command == PA_COMMAND_DELETE_UPLOAD_STREAM); + if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != UPLOAD_STREAM)) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + return; + } + + upload_stream_free(s); + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + struct record_stream *s; + size_t maxlength, fragment_size; + uint32_t source_index; + const char *name, *source_name; + pa_sample_spec ss; + pa_channel_map map; + pa_tagstruct *reply; + pa_source *source; + int corked; + assert(c && t && c->protocol && c->protocol->core); + + if (pa_tagstruct_gets(t, &name) < 0 || !name || + pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_get_channel_map(t, &map) < 0 || + pa_tagstruct_getu32(t, &source_index) < 0 || + pa_tagstruct_gets(t, &source_name) < 0 || + pa_tagstruct_getu32(t, &maxlength) < 0 || + pa_tagstruct_get_boolean(t, &corked) < 0 || + pa_tagstruct_getu32(t, &fragment_size) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (source_index != (uint32_t) -1) + source = pa_idxset_get_by_index(c->protocol->core->sources, source_index); + else + source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE, 1); + + if (!source) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + if (!(s = record_stream_new(c, source, &ss, &map, name, maxlength, fragment_size))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); + return; + } + + pa_source_output_cork(s->source_output, corked); + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, s->index); + assert(s->source_output); + pa_tagstruct_putu32(reply, s->source_output->index); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_exit(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + assert(c && t); + + if (!pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop); + c->protocol->core->mainloop->quit(c->protocol->core->mainloop, 0); + pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */ + return; +} + +static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const void*cookie; + assert(c && t); + + if (pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) != 0) { + pa_log(__FILE__": Denied access to client with invalid authorization key.\n"); + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + c->authorized = 1; + if (c->auth_timeout_event) { + c->protocol->core->mainloop->time_free(c->auth_timeout_event); + c->auth_timeout_event = NULL; + } + } + + pa_pstream_send_simple_ack(c->pstream, tag); + return; +} + +static void command_set_client_name(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const char *name; + assert(c && t); + + if (pa_tagstruct_gets(t, &name) < 0 || !name || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + pa_client_set_name(c->client, name); + pa_pstream_send_simple_ack(c->pstream, tag); + return; +} + +static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const char *name; + uint32_t idx = PA_IDXSET_INVALID; + assert(c && t); + + if (pa_tagstruct_gets(t, &name) < 0 || !name || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (command == PA_COMMAND_LOOKUP_SINK) { + pa_sink *sink; + if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1))) + idx = sink->index; + } else { + pa_source *source; + assert(command == PA_COMMAND_LOOKUP_SOURCE); + if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1))) + idx = source->index; + } + + if (idx == PA_IDXSET_INVALID) + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + else { + pa_tagstruct *reply; + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, idx); + pa_pstream_send_tagstruct(c->pstream, reply); + } +} + +static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + struct playback_stream *s; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + s->drain_request = 0; + + pa_memblockq_prebuf_disable(s->memblockq); + + if (!pa_memblockq_is_readable(s->memblockq)) { +/* pa_log("immediate drain: %u\n", pa_memblockq_get_length(s->memblockq)); */ + pa_pstream_send_simple_ack(c->pstream, tag); + } else { +/* pa_log("slow drain triggered\n"); */ + s->drain_request = 1; + s->drain_tag = tag; + + pa_sink_notify(s->sink_input->sink); + } +} + +static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + pa_tagstruct *reply; + assert(c && t); + + if (!pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->total); + pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->total_size); + pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->allocated); + pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->allocated_size); + pa_tagstruct_putu32(reply, pa_scache_total_size(c->protocol->core)); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + pa_tagstruct *reply; + struct playback_stream *s; + struct timeval tv, now; + uint64_t counter; + uint32_t idx; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_get_timeval(t, &tv) < 0 || + pa_tagstruct_getu64(t, &counter) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_put_usec(reply, pa_sink_input_get_latency(s->sink_input)); + pa_tagstruct_put_usec(reply, pa_sink_get_latency(s->sink_input->sink)); + pa_tagstruct_put_usec(reply, 0); + pa_tagstruct_put_boolean(reply, pa_memblockq_is_readable(s->memblockq)); + pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq)); + pa_tagstruct_put_timeval(reply, &tv); + pa_gettimeofday(&now); + pa_tagstruct_put_timeval(reply, &now); + pa_tagstruct_putu64(reply, counter); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + pa_tagstruct *reply; + struct record_stream *s; + struct timeval tv, now; + uint64_t counter; + uint32_t idx; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_get_timeval(t, &tv) < 0 || + pa_tagstruct_getu64(t, &counter) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_put_usec(reply, pa_source_output_get_latency(s->source_output)); + pa_tagstruct_put_usec(reply, s->source_output->source->monitor_of ? pa_sink_get_latency(s->source_output->source->monitor_of) : 0); + pa_tagstruct_put_usec(reply, pa_source_get_latency(s->source_output->source)); + pa_tagstruct_put_boolean(reply, 0); + pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq)); + pa_tagstruct_put_timeval(reply, &tv); + pa_gettimeofday(&now); + pa_tagstruct_put_timeval(reply, &now); + pa_tagstruct_putu64(reply, counter); + pa_pstream_send_tagstruct(c->pstream, reply); +} + + +static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + struct upload_stream *s; + size_t length; + const char *name; + pa_sample_spec ss; + pa_channel_map map; + pa_tagstruct *reply; + assert(c && t && c->protocol && c->protocol->core); + + if (pa_tagstruct_gets(t, &name) < 0 || !name || + pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_get_channel_map(t, &map) < 0 || + pa_tagstruct_getu32(t, &length) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if ((length % pa_frame_size(&ss)) != 0 || length <= 0 || !*name) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); + return; + } + + if (!(s = upload_stream_new(c, &ss, &map, name, length))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, s->index); + pa_tagstruct_putu32(reply, length); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t channel; + struct upload_stream *s; + uint32_t idx; + assert(c && t); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != UPLOAD_STREAM)) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + return; + } + + pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, &idx); + pa_pstream_send_simple_ack(c->pstream, tag); + upload_stream_free(s); +} + +static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t sink_index; + pa_cvolume volume; + pa_sink *sink; + const char *name, *sink_name; + assert(c && t); + + if (pa_tagstruct_getu32(t, &sink_index) < 0 || + pa_tagstruct_gets(t, &sink_name) < 0 || + pa_tagstruct_get_cvolume(t, &volume) < 0 || + pa_tagstruct_gets(t, &name) < 0 || !name || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (sink_index != (uint32_t) -1) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); + else + sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1); + + if (!sink) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + if (pa_scache_play_item(c->protocol->core, name, sink, &volume) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_remove_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const char *name; + assert(c && t); + + if (pa_tagstruct_gets(t, &name) < 0 || !name || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (pa_scache_remove_item(c->protocol->core, name) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void sink_fill_tagstruct(pa_tagstruct *t, pa_sink *sink) { + assert(t && sink); + pa_tagstruct_put( + t, + PA_TAG_U32, sink->index, + PA_TAG_STRING, sink->name, + PA_TAG_STRING, sink->description, + PA_TAG_SAMPLE_SPEC, &sink->sample_spec, + PA_TAG_CHANNEL_MAP, &sink->channel_map, + PA_TAG_U32, sink->owner ? sink->owner->index : PA_INVALID_INDEX, + PA_TAG_CVOLUME, pa_sink_get_volume(sink, PA_MIXER_HARDWARE), + PA_TAG_U32, sink->monitor_source->index, + PA_TAG_STRING, sink->monitor_source->name, + PA_TAG_USEC, pa_sink_get_latency(sink), + PA_TAG_STRING, sink->driver, + PA_TAG_INVALID); +} + +static void source_fill_tagstruct(pa_tagstruct *t, pa_source *source) { + assert(t && source); + pa_tagstruct_putu32(t, source->index); + pa_tagstruct_puts(t, source->name); + pa_tagstruct_puts(t, source->description); + pa_tagstruct_put_sample_spec(t, &source->sample_spec); + pa_tagstruct_put_channel_map(t, &source->channel_map); + pa_tagstruct_putu32(t, source->owner ? source->owner->index : (uint32_t) -1); + pa_tagstruct_putu32(t, source->monitor_of ? source->monitor_of->index : (uint32_t) -1); + pa_tagstruct_puts(t, source->monitor_of ? source->monitor_of->name : NULL); + pa_tagstruct_put_usec(t, pa_source_get_latency(source)); + pa_tagstruct_puts(t, source->driver); +} + +static void client_fill_tagstruct(pa_tagstruct *t, pa_client *client) { + assert(t && client); + pa_tagstruct_putu32(t, client->index); + pa_tagstruct_puts(t, client->name); + pa_tagstruct_putu32(t, client->owner ? client->owner->index : (uint32_t) -1); + pa_tagstruct_puts(t, client->driver); +} + +static void module_fill_tagstruct(pa_tagstruct *t, pa_module *module) { + assert(t && module); + pa_tagstruct_putu32(t, module->index); + pa_tagstruct_puts(t, module->name); + pa_tagstruct_puts(t, module->argument); + pa_tagstruct_putu32(t, module->n_used); + pa_tagstruct_put_boolean(t, module->auto_unload); +} + +static void sink_input_fill_tagstruct(pa_tagstruct *t, pa_sink_input *s) { + assert(t && s); + pa_tagstruct_putu32(t, s->index); + pa_tagstruct_puts(t, s->name); + pa_tagstruct_putu32(t, s->owner ? s->owner->index : (uint32_t) -1); + pa_tagstruct_putu32(t, s->client ? s->client->index : (uint32_t) -1); + pa_tagstruct_putu32(t, s->sink->index); + pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_put_channel_map(t, &s->channel_map); + pa_tagstruct_put_cvolume(t, &s->volume); + pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s)); + pa_tagstruct_put_usec(t, pa_sink_get_latency(s->sink)); + pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s))); + pa_tagstruct_puts(t, s->driver); +} + +static void source_output_fill_tagstruct(pa_tagstruct *t, pa_source_output *s) { + assert(t && s); + pa_tagstruct_putu32(t, s->index); + pa_tagstruct_puts(t, s->name); + pa_tagstruct_putu32(t, s->owner ? s->owner->index : (uint32_t) -1); + pa_tagstruct_putu32(t, s->client ? s->client->index : (uint32_t) -1); + pa_tagstruct_putu32(t, s->source->index); + pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_put_channel_map(t, &s->channel_map); + pa_tagstruct_put_usec(t, pa_source_output_get_latency(s)); + pa_tagstruct_put_usec(t, pa_source_get_latency(s->source)); + pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s))); + pa_tagstruct_puts(t, s->driver); +} + +static void scache_fill_tagstruct(pa_tagstruct *t, pa_scache_entry *e) { + assert(t && e); + pa_tagstruct_putu32(t, e->index); + pa_tagstruct_puts(t, e->name); + pa_tagstruct_put_cvolume(t, &e->volume); + pa_tagstruct_put_usec(t, pa_bytes_to_usec(e->memchunk.length, &e->sample_spec)); + pa_tagstruct_put_sample_spec(t, &e->sample_spec); + pa_tagstruct_put_channel_map(t, &e->channel_map); + pa_tagstruct_putu32(t, e->memchunk.length); + pa_tagstruct_put_boolean(t, e->lazy); + pa_tagstruct_puts(t, e->filename); +} + +static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + pa_sink *sink = NULL; + pa_source *source = NULL; + pa_client *client = NULL; + pa_module *module = NULL; + pa_sink_input *si = NULL; + pa_source_output *so = NULL; + pa_scache_entry *sce = NULL; + const char *name; + pa_tagstruct *reply; + assert(c && t); + + + if (pa_tagstruct_getu32(t, &idx) < 0 || + (command != PA_COMMAND_GET_CLIENT_INFO && + command != PA_COMMAND_GET_MODULE_INFO && + command != PA_COMMAND_GET_SINK_INPUT_INFO && + command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO && + pa_tagstruct_gets(t, &name) < 0) || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (command == PA_COMMAND_GET_SINK_INFO) { + if (idx != (uint32_t) -1) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); + else + sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); + } else if (command == PA_COMMAND_GET_SOURCE_INFO) { + if (idx != (uint32_t) -1) + source = pa_idxset_get_by_index(c->protocol->core->sources, idx); + else + source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); + } else if (command == PA_COMMAND_GET_CLIENT_INFO) + client = pa_idxset_get_by_index(c->protocol->core->clients, idx); + else if (command == PA_COMMAND_GET_MODULE_INFO) + module = pa_idxset_get_by_index(c->protocol->core->modules, idx); + else if (command == PA_COMMAND_GET_SINK_INPUT_INFO) + si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); + else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO) + so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); + else { + assert(command == PA_COMMAND_GET_SAMPLE_INFO); + if (idx != (uint32_t) -1) + sce = pa_idxset_get_by_index(c->protocol->core->scache, idx); + else + sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE, 0); + } + + if (!sink && !source && !client && !module && !si && !so && !sce) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + if (sink) + sink_fill_tagstruct(reply, sink); + else if (source) + source_fill_tagstruct(reply, source); + else if (client) + client_fill_tagstruct(reply, client); + else if (module) + module_fill_tagstruct(reply, module); + else if (si) + sink_input_fill_tagstruct(reply, si); + else if (so) + source_output_fill_tagstruct(reply, so); + else + scache_fill_tagstruct(reply, sce); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + pa_idxset *i; + uint32_t idx; + void *p; + pa_tagstruct *reply; + assert(c && t); + + if (!pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + + if (command == PA_COMMAND_GET_SINK_INFO_LIST) + i = c->protocol->core->sinks; + else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST) + i = c->protocol->core->sources; + else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST) + i = c->protocol->core->clients; + else if (command == PA_COMMAND_GET_MODULE_INFO_LIST) + i = c->protocol->core->modules; + else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) + i = c->protocol->core->sink_inputs; + else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST) + i = c->protocol->core->source_outputs; + else { + assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); + i = c->protocol->core->scache; + } + + if (i) { + for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) { + if (command == PA_COMMAND_GET_SINK_INFO_LIST) + sink_fill_tagstruct(reply, p); + else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST) + source_fill_tagstruct(reply, p); + else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST) + client_fill_tagstruct(reply, p); + else if (command == PA_COMMAND_GET_MODULE_INFO_LIST) + module_fill_tagstruct(reply, p); + else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) + sink_input_fill_tagstruct(reply, p); + else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST) + source_output_fill_tagstruct(reply, p); + else { + assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); + scache_fill_tagstruct(reply, p); + } + } + } + + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_get_server_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + pa_tagstruct *reply; + char txt[256]; + const char *n; + assert(c && t); + + if (!pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_puts(reply, PACKAGE_NAME); + pa_tagstruct_puts(reply, PACKAGE_VERSION); + pa_tagstruct_puts(reply, pa_get_user_name(txt, sizeof(txt))); + pa_tagstruct_puts(reply, pa_get_fqdn(txt, sizeof(txt))); + pa_tagstruct_put_sample_spec(reply, &c->protocol->core->default_sample_spec); + + n = pa_namereg_get_default_sink_name(c->protocol->core); + pa_tagstruct_puts(reply, n); + n = pa_namereg_get_default_source_name(c->protocol->core); + pa_tagstruct_puts(reply, n); + + pa_tagstruct_putu32(reply, c->protocol->core->cookie); + + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) { + pa_tagstruct *t; + struct connection *c = userdata; + assert(c && core); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_putu32(t, e); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + pa_subscription_mask_t m; + assert(c && t); + + if (pa_tagstruct_getu32(t, &m) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (c->subscription) + pa_subscription_free(c->subscription); + + if (m != 0) { + c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c); + assert(c->subscription); + } else + c->subscription = NULL; + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_set_volume(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + pa_cvolume volume; + pa_sink *sink = NULL; + pa_sink_input *si = NULL; + const char *name = NULL; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) || + pa_tagstruct_get_cvolume(t, &volume) || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (command == PA_COMMAND_SET_SINK_VOLUME) { + if (idx != (uint32_t) -1) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); + else + sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); + } else { + assert(command == PA_COMMAND_SET_SINK_INPUT_VOLUME); + si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); + } + + if (!si && !sink) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + if (sink) + pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &volume); + else if (si) + pa_sink_input_set_volume(si, &volume); + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + int b; + struct playback_stream *s; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_get_boolean(t, &b) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_sink_input_cork(s->sink_input, b); + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_flush_or_trigger_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + struct playback_stream *s; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + if (command == PA_COMMAND_PREBUF_PLAYBACK_STREAM) + pa_memblockq_prebuf_reenable(s->memblockq); + else if (command == PA_COMMAND_TRIGGER_PLAYBACK_STREAM) + pa_memblockq_prebuf_disable(s->memblockq); + else { + assert(command == PA_COMMAND_FLUSH_PLAYBACK_STREAM); + pa_memblockq_flush(s->memblockq); + /*pa_log(__FILE__": flush: %u\n", pa_memblockq_get_length(s->memblockq));*/ + } + + pa_sink_notify(s->sink_input->sink); + pa_pstream_send_simple_ack(c->pstream, tag); + request_bytes(s); +} + +static void command_cork_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + struct record_stream *s; + int b; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_get_boolean(t, &b) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_source_output_cork(s->source_output, b); + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_flush_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + struct record_stream *s; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_memblockq_flush(s->memblockq); + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_set_default_sink_or_source(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + const char *s; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_gets(t, &s) < 0 || !s || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + pa_namereg_set_default(c->protocol->core, s, command == PA_COMMAND_SET_DEFAULT_SOURCE ? PA_NAMEREG_SOURCE : PA_NAMEREG_SINK); + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + const char *name; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_gets(t, &name) < 0 || !name || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) { + struct playback_stream *s; + + if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_sink_input_set_name(s->sink_input, name); + + } else { + struct record_stream *s; + + if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_source_output_set_name(s->source_output, name); + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (command == PA_COMMAND_KILL_CLIENT) { + pa_client *client; + + if (!(client = pa_idxset_get_by_index(c->protocol->core->clients, idx))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_client_kill(client); + } else if (command == PA_COMMAND_KILL_SINK_INPUT) { + pa_sink_input *s; + + if (!(s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_sink_input_kill(s); + } else { + pa_source_output *s; + + assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT); + + if (!(s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_source_output_kill(s); + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_load_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + pa_module *m; + const char *name, *argument; + pa_tagstruct *reply; + assert(c && t); + + if (pa_tagstruct_gets(t, &name) < 0 || !name || + pa_tagstruct_gets(t, &argument) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(m = pa_module_load(c->protocol->core, name, argument))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_INITFAILED); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, m->index); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_unload_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + pa_module *m; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (!(m = pa_idxset_get_by_index(c->protocol->core->modules, idx))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_module_unload_request(m); + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_add_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const char *name, *module, *argument; + uint32_t type; + uint32_t idx; + pa_tagstruct *reply; + assert(c && t); + + if (pa_tagstruct_gets(t, &name) < 0 || !name || + pa_tagstruct_getu32(t, &type) < 0 || type > 1 || + pa_tagstruct_gets(t, &module) < 0 || !module || + pa_tagstruct_gets(t, &argument) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (pa_autoload_add(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, module, argument, &idx) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, idx); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_remove_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const char *name = NULL; + uint32_t type, idx = PA_IDXSET_INVALID; + int r; + assert(c && t); + + if ((pa_tagstruct_getu32(t, &idx) < 0 && + (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_getu32(t, &type) < 0)) || + (!name && idx == PA_IDXSET_INVALID) || + (name && type > 1) || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (name) + r = pa_autoload_remove_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE); + else + r = pa_autoload_remove_by_index(c->protocol->core, idx); + + if (r < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void autoload_fill_tagstruct(pa_tagstruct *t, const pa_autoload_entry *e) { + assert(t && e); + + pa_tagstruct_putu32(t, e->index); + pa_tagstruct_puts(t, e->name); + pa_tagstruct_putu32(t, e->type == PA_NAMEREG_SINK ? 0 : 1); + pa_tagstruct_puts(t, e->module); + pa_tagstruct_puts(t, e->argument); +} + +static void command_get_autoload_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const pa_autoload_entry *a = NULL; + uint32_t type, idx; + const char *name; + pa_tagstruct *reply; + assert(c && t); + + if ((pa_tagstruct_getu32(t, &idx) < 0 && + (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_getu32(t, &type) < 0)) || + (!name && idx == PA_IDXSET_INVALID) || + (name && type > 1) || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + + if (name) + a = pa_autoload_get_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE); + else + a = pa_autoload_get_by_index(c->protocol->core, idx); + + if (!a) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + autoload_fill_tagstruct(reply, a); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + pa_tagstruct *reply; + assert(c && t); + + if (!pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + reply = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + + if (c->protocol->core->autoload_hashmap) { + pa_autoload_entry *a; + void *state = NULL; + + while ((a = pa_hashmap_iterate(c->protocol->core->autoload_hashmap, &state, NULL))) + autoload_fill_tagstruct(reply, a); + } + + pa_pstream_send_tagstruct(c->pstream, reply); +} + +/*** pstream callbacks ***/ + +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { + struct connection *c = userdata; + assert(p && packet && packet->data && c); + + if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { + pa_log(__FILE__": invalid packet.\n"); + connection_free(c); + } +} + +static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata) { + struct connection *c = userdata; + struct output_stream *stream; + assert(p && chunk && userdata); + + if (!(stream = pa_idxset_get_by_index(c->output_streams, channel))) { + pa_log(__FILE__": client sent block for invalid stream.\n"); + connection_free(c); + return; + } + + if (stream->type == PLAYBACK_STREAM) { + struct playback_stream *ps = (struct playback_stream*) stream; + if (chunk->length >= ps->requested_bytes) + ps->requested_bytes = 0; + else + ps->requested_bytes -= chunk->length; + + pa_memblockq_push_align(ps->memblockq, chunk, delta); + assert(ps->sink_input); +/* pa_log(__FILE__": after_recv: %u\n", pa_memblockq_get_length(p->memblockq)); */ + + pa_sink_notify(ps->sink_input->sink); +/* pa_log(__FILE__": Recieved %u bytes.\n", chunk->length); */ + + } else { + struct upload_stream *u = (struct upload_stream*) stream; + size_t l; + assert(u->type == UPLOAD_STREAM); + + if (!u->memchunk.memblock) { + if (u->length == chunk->length) { + u->memchunk = *chunk; + pa_memblock_ref(u->memchunk.memblock); + u->length = 0; + } else { + u->memchunk.memblock = pa_memblock_new(u->length, c->protocol->core->memblock_stat); + u->memchunk.index = u->memchunk.length = 0; + } + } + + assert(u->memchunk.memblock); + + l = u->length; + if (l > chunk->length) + l = chunk->length; + + if (l > 0) { + memcpy((uint8_t*) u->memchunk.memblock->data + u->memchunk.index + u->memchunk.length, + (uint8_t*) chunk->memblock->data+chunk->index, l); + u->memchunk.length += l; + u->length -= l; + } + } +} + +static void pstream_die_callback(pa_pstream *p, void *userdata) { + struct connection *c = userdata; + assert(p && c); + connection_free(c); + +/* pa_log(__FILE__": connection died.\n");*/ +} + + +static void pstream_drain_callback(pa_pstream *p, void *userdata) { + struct connection *c = userdata; + assert(p && c); + + send_memblock(c); +} + +/*** client callbacks ***/ + +static void client_kill_cb(pa_client *c) { + assert(c && c->userdata); + connection_free(c->userdata); +} + +/*** socket server callbacks ***/ + +static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { + struct connection *c = userdata; + assert(m && tv && c && c->auth_timeout_event == e); + + if (!c->authorized) + connection_free(c); +} + +static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, void *userdata) { + pa_protocol_native *p = userdata; + struct connection *c; + assert(io && p); + + if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { + pa_log_warn(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); + pa_iochannel_free(io); + return; + } + + c = pa_xmalloc(sizeof(struct connection)); + + c->authorized =!! p->public; + + if (!c->authorized) { + struct timeval tv; + pa_gettimeofday(&tv); + tv.tv_sec += AUTH_TIMEOUT; + c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c); + } else + c->auth_timeout_event = NULL; + + c->protocol = p; + assert(p->core); + c->client = pa_client_new(p->core, __FILE__, "Client"); + assert(c->client); + c->client->kill = client_kill_cb; + c->client->userdata = c; + c->client->owner = p->module; + + c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->memblock_stat); + assert(c->pstream); + + pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); + pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); + pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); + pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); + + c->pdispatch = pa_pdispatch_new(p->core->mainloop, command_table, PA_COMMAND_MAX); + assert(c->pdispatch); + + c->record_streams = pa_idxset_new(NULL, NULL); + c->output_streams = pa_idxset_new(NULL, NULL); + assert(c->record_streams && c->output_streams); + + c->rrobin_index = PA_IDXSET_INVALID; + c->subscription = NULL; + + pa_idxset_put(p->connections, c, NULL); +} + +/*** module entry points ***/ + +static int load_key(pa_protocol_native*p, const char*fn) { + assert(p); + + p->auth_cookie_in_property = 0; + + if (!fn && pa_authkey_prop_get(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) { + pa_log_info(__FILE__": using already loaded auth cookie.\n"); + pa_authkey_prop_ref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); + p->auth_cookie_in_property = 1; + return 0; + } + + if (!fn) + fn = PA_NATIVE_COOKIE_FILE; + + if (pa_authkey_load_auto(fn, p->auth_cookie, sizeof(p->auth_cookie)) < 0) + return -1; + + pa_log_info(__FILE__": loading cookie from disk.\n"); + + if (pa_authkey_prop_put(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) + p->auth_cookie_in_property = 1; + + return 0; +} + +static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_modargs *ma) { + pa_protocol_native *p; + int public = 0; + assert(c && ma); + + if (pa_modargs_get_value_boolean(ma, "public", &public) < 0) { + pa_log(__FILE__": public= expects a boolean argument.\n"); + return NULL; + } + + p = pa_xmalloc(sizeof(pa_protocol_native)); + p->core = c; + p->module = m; + p->public = public; + p->server = NULL; + + if (load_key(p, pa_modargs_get_value(ma, "cookie", NULL)) < 0) { + pa_xfree(p); + return NULL; + } + + p->connections = pa_idxset_new(NULL, NULL); + assert(p->connections); + + return p; +} + +pa_protocol_native* pa_protocol_native_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { + char t[256]; + pa_protocol_native *p; + + if (!(p = protocol_new_internal(core, m, ma))) + return NULL; + + p->server = server; + pa_socket_server_set_callback(p->server, on_connection, p); + + if (pa_socket_server_get_address(p->server, t, sizeof(t))) { + pa_strlist *l; + l = pa_property_get(core, PA_NATIVE_SERVER_PROPERTY_NAME); + l = pa_strlist_prepend(l, t); + pa_property_replace(core, PA_NATIVE_SERVER_PROPERTY_NAME, l); + } + + return p; +} + +void pa_protocol_native_free(pa_protocol_native *p) { + struct connection *c; + assert(p); + + while ((c = pa_idxset_first(p->connections, NULL))) + connection_free(c); + pa_idxset_free(p->connections, NULL, NULL); + + if (p->server) { + char t[256]; + + if (pa_socket_server_get_address(p->server, t, sizeof(t))) { + pa_strlist *l; + l = pa_property_get(p->core, PA_NATIVE_SERVER_PROPERTY_NAME); + l = pa_strlist_remove(l, t); + + if (l) + pa_property_replace(p->core, PA_NATIVE_SERVER_PROPERTY_NAME, l); + else + pa_property_remove(p->core, PA_NATIVE_SERVER_PROPERTY_NAME); + } + + pa_socket_server_unref(p->server); + } + + if (p->auth_cookie_in_property) + pa_authkey_prop_unref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); + + pa_xfree(p); +} + +pa_protocol_native* pa_protocol_native_new_iochannel(pa_core*core, pa_iochannel *io, pa_module *m, pa_modargs *ma) { + pa_protocol_native *p; + + if (!(p = protocol_new_internal(core, m, ma))) + return NULL; + + on_connection(NULL, io, p); + + return p; +} diff --git a/src/polypcore/protocol-native.h b/src/polypcore/protocol-native.h new file mode 100644 index 00000000..12e85d0b --- /dev/null +++ b/src/polypcore/protocol-native.h @@ -0,0 +1,37 @@ +#ifndef fooprotocolnativehfoo +#define fooprotocolnativehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" +#include "socket-server.h" +#include "module.h" +#include "modargs.h" + +typedef struct pa_protocol_native pa_protocol_native; + +pa_protocol_native* pa_protocol_native_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma); +void pa_protocol_native_free(pa_protocol_native *n); + +pa_protocol_native* pa_protocol_native_new_iochannel(pa_core*core, pa_iochannel *io, pa_module *m, pa_modargs *ma); + +#endif diff --git a/src/polypcore/protocol-simple.c b/src/polypcore/protocol-simple.c new file mode 100644 index 00000000..113919b3 --- /dev/null +++ b/src/polypcore/protocol-simple.c @@ -0,0 +1,453 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "sink-input.h" +#include "source-output.h" +#include "protocol-simple.h" +#include "client.h" +#include "sample-util.h" +#include "namereg.h" +#include "xmalloc.h" +#include "log.h" + +/* Don't allow more than this many concurrent connections */ +#define MAX_CONNECTIONS 10 + +struct connection { + pa_protocol_simple *protocol; + pa_iochannel *io; + pa_sink_input *sink_input; + pa_source_output *source_output; + pa_client *client; + pa_memblockq *input_memblockq, *output_memblockq; + pa_defer_event *defer_event; + + struct { + pa_memblock *current_memblock; + size_t memblock_index, fragment_size; + } playback; +}; + +struct pa_protocol_simple { + pa_module *module; + pa_core *core; + pa_socket_server*server; + pa_idxset *connections; + enum { + RECORD = 1, + PLAYBACK = 2, + DUPLEX = 3 + } mode; + pa_sample_spec sample_spec; + char *source_name, *sink_name; +}; + +#define PLAYBACK_BUFFER_SECONDS (.5) +#define PLAYBACK_BUFFER_FRAGMENTS (10) +#define RECORD_BUFFER_SECONDS (5) +#define RECORD_BUFFER_FRAGMENTS (100) + +static void connection_free(struct connection *c) { + assert(c); + + pa_idxset_remove_by_data(c->protocol->connections, c, NULL); + + if (c->playback.current_memblock) + pa_memblock_unref(c->playback.current_memblock); + if (c->sink_input) { + pa_sink_input_disconnect(c->sink_input); + pa_sink_input_unref(c->sink_input); + } + if (c->source_output) { + pa_source_output_disconnect(c->source_output); + pa_source_output_unref(c->source_output); + } + if (c->client) + pa_client_free(c->client); + if (c->io) + pa_iochannel_free(c->io); + if (c->input_memblockq) + pa_memblockq_free(c->input_memblockq); + if (c->output_memblockq) + pa_memblockq_free(c->output_memblockq); + if (c->defer_event) + c->protocol->core->mainloop->defer_free(c->defer_event); + pa_xfree(c); +} + +static int do_read(struct connection *c) { + pa_memchunk chunk; + ssize_t r; + size_t l; + + if (!c->sink_input || !(l = pa_memblockq_missing(c->input_memblockq))) + return 0; + + if (l > c->playback.fragment_size) + l = c->playback.fragment_size; + + if (c->playback.current_memblock) + if (c->playback.current_memblock->length - c->playback.memblock_index < l) { + pa_memblock_unref(c->playback.current_memblock); + c->playback.current_memblock = NULL; + c->playback.memblock_index = 0; + } + + if (!c->playback.current_memblock) { + c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2, c->protocol->core->memblock_stat); + assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); + c->playback.memblock_index = 0; + } + + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { + pa_log(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + return -1; + } + + chunk.memblock = c->playback.current_memblock; + chunk.index = c->playback.memblock_index; + chunk.length = r; + assert(chunk.memblock); + + c->playback.memblock_index += r; + + assert(c->input_memblockq); + pa_memblockq_push_align(c->input_memblockq, &chunk, 0); + assert(c->sink_input); + pa_sink_notify(c->sink_input->sink); + + return 0; +} + +static int do_write(struct connection *c) { + pa_memchunk chunk; + ssize_t r; + + if (!c->source_output) + return 0; + + assert(c->output_memblockq); + if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) + return 0; + + assert(chunk.memblock && chunk.length); + + if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { + pa_memblock_unref(chunk.memblock); + pa_log(__FILE__": write(): %s\n", strerror(errno)); + return -1; + } + + pa_memblockq_drop(c->output_memblockq, &chunk, r); + pa_memblock_unref(chunk.memblock); + + return 0; +} + + +static void do_work(struct connection *c) { + assert(c); + + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 0); + + if (pa_iochannel_is_writable(c->io)) + if (do_write(c) < 0) + goto fail; + + if (pa_iochannel_is_readable(c->io)) + if (do_read(c) < 0) + goto fail; + + if (pa_iochannel_is_hungup(c->io)) + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + + return; + +fail: + connection_free(c); +} + +/*** sink_input callbacks ***/ + +static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { + struct connection*c; + assert(i && i->userdata && chunk); + c = i->userdata; + + if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) + return -1; + + return 0; +} + +static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { + struct connection*c = i->userdata; + assert(i && c && length); + + pa_memblockq_drop(c->input_memblockq, chunk, length); + + /* do something */ + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); +} + +static void sink_input_kill_cb(pa_sink_input *i) { + assert(i && i->userdata); + connection_free((struct connection *) i->userdata); +} + + +static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { + struct connection*c = i->userdata; + assert(i && c); + return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); +} + +/*** source_output callbacks ***/ + +static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { + struct connection *c = o->userdata; + assert(o && c && chunk); + + pa_memblockq_push(c->output_memblockq, chunk, 0); + + /* do something */ + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); +} + +static void source_output_kill_cb(pa_source_output *o) { + assert(o && o->userdata); + connection_free((struct connection *) o->userdata); +} + +static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { + struct connection*c = o->userdata; + assert(o && c); + return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec); +} + +/*** client callbacks ***/ + +static void client_kill_cb(pa_client *c) { + assert(c && c->userdata); + connection_free((struct connection *) c->userdata); +} + +/*** pa_iochannel callbacks ***/ + +static void io_callback(pa_iochannel*io, void *userdata) { + struct connection *c = userdata; + assert(io && c && c->io == io); + + do_work(c); +} + +/*** fixed callback ***/ + +static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { + struct connection *c = userdata; + assert(a && c && c->defer_event == e); + + do_work(c); +} + +/*** socket_server callbacks ***/ + +static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { + pa_protocol_simple *p = userdata; + struct connection *c = NULL; + char cname[256]; + assert(s && io && p); + + if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { + pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); + pa_iochannel_free(io); + return; + } + + c = pa_xmalloc(sizeof(struct connection)); + c->io = io; + c->sink_input = NULL; + c->source_output = NULL; + c->defer_event = NULL; + c->input_memblockq = c->output_memblockq = NULL; + c->protocol = p; + c->playback.current_memblock = NULL; + c->playback.memblock_index = 0; + c->playback.fragment_size = 0; + + pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); + c->client = pa_client_new(p->core, __FILE__, cname); + assert(c->client); + c->client->owner = p->module; + c->client->kill = client_kill_cb; + c->client->userdata = c; + + if (p->mode & PLAYBACK) { + pa_sink *sink; + size_t l; + + if (!(sink = pa_namereg_get(p->core, p->sink_name, PA_NAMEREG_SINK, 1))) { + pa_log(__FILE__": Failed to get sink.\n"); + goto fail; + } + + if (!(c->sink_input = pa_sink_input_new(sink, __FILE__, c->client->name, &p->sample_spec, NULL, 0, -1))) { + pa_log(__FILE__": Failed to create sink input.\n"); + goto fail; + } + + c->sink_input->owner = p->module; + c->sink_input->client = c->client; + + c->sink_input->peek = sink_input_peek_cb; + c->sink_input->drop = sink_input_drop_cb; + c->sink_input->kill = sink_input_kill_cb; + c->sink_input->get_latency = sink_input_get_latency_cb; + c->sink_input->userdata = c; + + l = (size_t) (pa_bytes_per_second(&p->sample_spec)*PLAYBACK_BUFFER_SECONDS); + c->input_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&p->sample_spec), l/2, l/PLAYBACK_BUFFER_FRAGMENTS, p->core->memblock_stat); + assert(c->input_memblockq); + pa_iochannel_socket_set_rcvbuf(io, l/PLAYBACK_BUFFER_FRAGMENTS*5); + c->playback.fragment_size = l/10; + } + + if (p->mode & RECORD) { + pa_source *source; + size_t l; + + if (!(source = pa_namereg_get(p->core, p->source_name, PA_NAMEREG_SOURCE, 1))) { + pa_log(__FILE__": Failed to get source.\n"); + goto fail; + } + + c->source_output = pa_source_output_new(source, __FILE__, c->client->name, &p->sample_spec, NULL, -1); + if (!c->source_output) { + pa_log(__FILE__": Failed to create source output.\n"); + goto fail; + } + c->source_output->owner = p->module; + c->source_output->client = c->client; + + c->source_output->push = source_output_push_cb; + c->source_output->kill = source_output_kill_cb; + c->source_output->get_latency = source_output_get_latency_cb; + c->source_output->userdata = c; + + l = (size_t) (pa_bytes_per_second(&p->sample_spec)*RECORD_BUFFER_SECONDS); + c->output_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&p->sample_spec), 0, 0, p->core->memblock_stat); + pa_iochannel_socket_set_sndbuf(io, l/RECORD_BUFFER_FRAGMENTS*2); + } + + pa_iochannel_set_callback(c->io, io_callback, c); + pa_idxset_put(p->connections, c, NULL); + + c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c); + assert(c->defer_event); + p->core->mainloop->defer_enable(c->defer_event, 0); + + return; + +fail: + if (c) + connection_free(c); +} + +pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { + pa_protocol_simple* p = NULL; + int enable; + assert(core && server && ma); + + p = pa_xmalloc0(sizeof(pa_protocol_simple)); + p->module = m; + p->core = core; + p->server = server; + p->connections = pa_idxset_new(NULL, NULL); + + p->sample_spec = core->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &p->sample_spec) < 0) { + pa_log(__FILE__": Failed to parse sample type specification.\n"); + goto fail; + } + + p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL)); + p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); + + enable = 0; + if (pa_modargs_get_value_boolean(ma, "record", &enable) < 0) { + pa_log(__FILE__": record= expects a numeric argument.\n"); + goto fail; + } + p->mode = enable ? RECORD : 0; + + enable = 1; + if (pa_modargs_get_value_boolean(ma, "playback", &enable) < 0) { + pa_log(__FILE__": playback= expects a numeric argument.\n"); + goto fail; + } + p->mode |= enable ? PLAYBACK : 0; + + if ((p->mode & (RECORD|PLAYBACK)) == 0) { + pa_log(__FILE__": neither playback nor recording enabled for protocol.\n"); + goto fail; + } + + pa_socket_server_set_callback(p->server, on_connection, p); + + return p; + +fail: + if (p) + pa_protocol_simple_free(p); + return NULL; +} + + +void pa_protocol_simple_free(pa_protocol_simple *p) { + struct connection *c; + assert(p); + + if (p->connections) { + while((c = pa_idxset_first(p->connections, NULL))) + connection_free(c); + + pa_idxset_free(p->connections, NULL, NULL); + } + + if (p->server) + pa_socket_server_unref(p->server); + pa_xfree(p); +} + diff --git a/src/polypcore/protocol-simple.h b/src/polypcore/protocol-simple.h new file mode 100644 index 00000000..63455a53 --- /dev/null +++ b/src/polypcore/protocol-simple.h @@ -0,0 +1,35 @@ +#ifndef fooprotocolsimplehfoo +#define fooprotocolsimplehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "socket-server.h" +#include "module.h" +#include "core.h" +#include "modargs.h" + +typedef struct pa_protocol_simple pa_protocol_simple; + +pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma); +void pa_protocol_simple_free(pa_protocol_simple *n); + +#endif diff --git a/src/polypcore/pstream-util.c b/src/polypcore/pstream-util.c new file mode 100644 index 00000000..ecd63d15 --- /dev/null +++ b/src/polypcore/pstream-util.c @@ -0,0 +1,61 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "native-common.h" +#include "pstream-util.h" + +void pa_pstream_send_tagstruct(pa_pstream *p, pa_tagstruct *t) { + size_t length; + uint8_t *data; + pa_packet *packet; + assert(p); + assert(t); + + data = pa_tagstruct_free_data(t, &length); + assert(data && length); + packet = pa_packet_new_dynamic(data, length); + assert(packet); + pa_pstream_send_packet(p, packet); + pa_packet_unref(packet); +} + +void pa_pstream_send_error(pa_pstream *p, uint32_t tag, uint32_t error) { + pa_tagstruct *t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_ERROR); + pa_tagstruct_putu32(t, tag); + pa_tagstruct_putu32(t, error); + pa_pstream_send_tagstruct(p, t); +} + +void pa_pstream_send_simple_ack(pa_pstream *p, uint32_t tag) { + pa_tagstruct *t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_REPLY); + pa_tagstruct_putu32(t, tag); + pa_pstream_send_tagstruct(p, t); +} diff --git a/src/polypcore/pstream-util.h b/src/polypcore/pstream-util.h new file mode 100644 index 00000000..601a9e99 --- /dev/null +++ b/src/polypcore/pstream-util.h @@ -0,0 +1,35 @@ +#ifndef foopstreamutilhfoo +#define foopstreamutilhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include "pstream.h" +#include "tagstruct.h" + +/* The tagstruct is freed!*/ +void pa_pstream_send_tagstruct(pa_pstream *p, pa_tagstruct *t); + +void pa_pstream_send_error(pa_pstream *p, uint32_t tag, uint32_t error); +void pa_pstream_send_simple_ack(pa_pstream *p, uint32_t tag); + +#endif diff --git a/src/polypcore/pstream.c b/src/polypcore/pstream.c new file mode 100644 index 00000000..bd00ba4f --- /dev/null +++ b/src/polypcore/pstream.c @@ -0,0 +1,492 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#include "winsock.h" + +#include "pstream.h" +#include "queue.h" +#include "xmalloc.h" +#include "log.h" + +typedef enum pa_pstream_descriptor_index { + PA_PSTREAM_DESCRIPTOR_LENGTH, + PA_PSTREAM_DESCRIPTOR_CHANNEL, + PA_PSTREAM_DESCRIPTOR_DELTA, + PA_PSTREAM_DESCRIPTOR_MAX +} pa_pstream_descriptor_index; + +typedef uint32_t pa_pstream_descriptor[PA_PSTREAM_DESCRIPTOR_MAX]; + +#define PA_PSTREAM_DESCRIPTOR_SIZE (PA_PSTREAM_DESCRIPTOR_MAX*sizeof(uint32_t)) +#define FRAME_SIZE_MAX (1024*500) /* half a megabyte */ + +struct item_info { + enum { PA_PSTREAM_ITEM_PACKET, PA_PSTREAM_ITEM_MEMBLOCK } type; + + /* memblock info */ + pa_memchunk chunk; + uint32_t channel; + uint32_t delta; + + /* packet info */ + pa_packet *packet; +}; + +struct pa_pstream { + int ref; + + pa_mainloop_api *mainloop; + pa_defer_event *defer_event; + pa_iochannel *io; + pa_queue *send_queue; + + int dead; + void (*die_callback) (pa_pstream *p, void *userdata); + void *die_callback_userdata; + + struct { + struct item_info* current; + pa_pstream_descriptor descriptor; + void *data; + size_t index; + } write; + + struct { + pa_memblock *memblock; + pa_packet *packet; + pa_pstream_descriptor descriptor; + void *data; + size_t index; + } read; + + void (*recieve_packet_callback) (pa_pstream *p, pa_packet *packet, void *userdata); + void *recieve_packet_callback_userdata; + + void (*recieve_memblock_callback) (pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata); + void *recieve_memblock_callback_userdata; + + void (*drain_callback)(pa_pstream *p, void *userdata); + void *drain_userdata; + + pa_memblock_stat *memblock_stat; +}; + +static void do_write(pa_pstream *p); +static void do_read(pa_pstream *p); + +static void do_something(pa_pstream *p) { + assert(p); + + p->mainloop->defer_enable(p->defer_event, 0); + + pa_pstream_ref(p); + + if (!p->dead && pa_iochannel_is_readable(p->io)) + do_read(p); + + if (!p->dead && pa_iochannel_is_writable(p->io)) + do_write(p); + + /* In case the line was hungup, make sure to rerun this function + as soon as possible, until all data has been read. */ + + if (!p->dead && pa_iochannel_is_hungup(p->io)) + p->mainloop->defer_enable(p->defer_event, 1); + + pa_pstream_unref(p); +} + +static void io_callback(pa_iochannel*io, void *userdata) { + pa_pstream *p = userdata; + assert(p && p->io == io); + do_something(p); +} + +static void defer_callback(pa_mainloop_api *m, pa_defer_event *e, void*userdata) { + pa_pstream *p = userdata; + assert(p && p->defer_event == e && p->mainloop == m); + do_something(p); +} + +pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_stat *s) { + pa_pstream *p; + assert(io); + + p = pa_xmalloc(sizeof(pa_pstream)); + p->ref = 1; + p->io = io; + pa_iochannel_set_callback(io, io_callback, p); + + p->dead = 0; + p->die_callback = NULL; + p->die_callback_userdata = NULL; + + p->mainloop = m; + p->defer_event = m->defer_new(m, defer_callback, p); + m->defer_enable(p->defer_event, 0); + + p->send_queue = pa_queue_new(); + assert(p->send_queue); + + p->write.current = NULL; + p->write.index = 0; + + p->read.memblock = NULL; + p->read.packet = NULL; + p->read.index = 0; + + p->recieve_packet_callback = NULL; + p->recieve_packet_callback_userdata = NULL; + + p->recieve_memblock_callback = NULL; + p->recieve_memblock_callback_userdata = NULL; + + p->drain_callback = NULL; + p->drain_userdata = NULL; + + p->memblock_stat = s; + + pa_iochannel_socket_set_rcvbuf(io, 1024*8); + pa_iochannel_socket_set_sndbuf(io, 1024*8); + + return p; +} + +static void item_free(void *item, PA_GCC_UNUSED void *p) { + struct item_info *i = item; + assert(i); + + if (i->type == PA_PSTREAM_ITEM_MEMBLOCK) { + assert(i->chunk.memblock); + pa_memblock_unref(i->chunk.memblock); + } else { + assert(i->type == PA_PSTREAM_ITEM_PACKET); + assert(i->packet); + pa_packet_unref(i->packet); + } + + pa_xfree(i); +} + +static void pstream_free(pa_pstream *p) { + assert(p); + + pa_pstream_close(p); + + pa_queue_free(p->send_queue, item_free, NULL); + + if (p->write.current) + item_free(p->write.current, NULL); + + if (p->read.memblock) + pa_memblock_unref(p->read.memblock); + + if (p->read.packet) + pa_packet_unref(p->read.packet); + + pa_xfree(p); +} + +void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet) { + struct item_info *i; + assert(p && packet && p->ref >= 1); + + if (p->dead) + return; + +/* pa_log(__FILE__": push-packet %p\n", packet); */ + + i = pa_xmalloc(sizeof(struct item_info)); + i->type = PA_PSTREAM_ITEM_PACKET; + i->packet = pa_packet_ref(packet); + + pa_queue_push(p->send_queue, i); + p->mainloop->defer_enable(p->defer_event, 1); +} + +void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk) { + struct item_info *i; + assert(p && channel != (uint32_t) -1 && chunk && p->ref >= 1); + + if (p->dead) + return; + +/* pa_log(__FILE__": push-memblock %p\n", chunk); */ + + i = pa_xmalloc(sizeof(struct item_info)); + i->type = PA_PSTREAM_ITEM_MEMBLOCK; + i->chunk = *chunk; + i->channel = channel; + i->delta = delta; + + pa_memblock_ref(i->chunk.memblock); + + pa_queue_push(p->send_queue, i); + p->mainloop->defer_enable(p->defer_event, 1); +} + +void pa_pstream_set_recieve_packet_callback(pa_pstream *p, void (*callback) (pa_pstream *p, pa_packet *packet, void *userdata), void *userdata) { + assert(p && callback); + + p->recieve_packet_callback = callback; + p->recieve_packet_callback_userdata = userdata; +} + +void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, void (*callback) (pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata), void *userdata) { + assert(p && callback); + + p->recieve_memblock_callback = callback; + p->recieve_memblock_callback_userdata = userdata; +} + +static void prepare_next_write_item(pa_pstream *p) { + assert(p); + + if (!(p->write.current = pa_queue_pop(p->send_queue))) + return; + + p->write.index = 0; + + if (p->write.current->type == PA_PSTREAM_ITEM_PACKET) { + /*pa_log(__FILE__": pop-packet %p\n", p->write.current->packet);*/ + + assert(p->write.current->packet); + p->write.data = p->write.current->packet->data; + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->packet->length); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl((uint32_t) -1); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA] = 0; + } else { + assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK && p->write.current->chunk.memblock); + p->write.data = (uint8_t*) p->write.current->chunk.memblock->data + p->write.current->chunk.index; + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl(p->write.current->channel); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA] = htonl(p->write.current->delta); + } +} + +static void do_write(pa_pstream *p) { + void *d; + size_t l; + ssize_t r; + assert(p); + + if (!p->write.current) + prepare_next_write_item(p); + + if (!p->write.current) + return; + + assert(p->write.data); + + if (p->write.index < PA_PSTREAM_DESCRIPTOR_SIZE) { + d = (uint8_t*) p->write.descriptor + p->write.index; + l = PA_PSTREAM_DESCRIPTOR_SIZE - p->write.index; + } else { + d = (uint8_t*) p->write.data + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE; + l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE); + } + + if ((r = pa_iochannel_write(p->io, d, l)) < 0) + goto die; + + p->write.index += r; + + if (p->write.index >= PA_PSTREAM_DESCRIPTOR_SIZE+ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])) { + assert(p->write.current); + item_free(p->write.current, (void *) 1); + p->write.current = NULL; + + if (p->drain_callback && !pa_pstream_is_pending(p)) + p->drain_callback(p, p->drain_userdata); + } + + return; + +die: + p->dead = 1; + if (p->die_callback) + p->die_callback(p, p->die_callback_userdata); +} + +static void do_read(pa_pstream *p) { + void *d; + size_t l; + ssize_t r; + assert(p); + + if (p->read.index < PA_PSTREAM_DESCRIPTOR_SIZE) { + d = (uint8_t*) p->read.descriptor + p->read.index; + l = PA_PSTREAM_DESCRIPTOR_SIZE - p->read.index; + } else { + assert(p->read.data); + d = (uint8_t*) p->read.data + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE; + l = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE); + } + + if ((r = pa_iochannel_read(p->io, d, l)) <= 0) + goto die; + + p->read.index += r; + + if (p->read.index == PA_PSTREAM_DESCRIPTOR_SIZE) { + /* Reading of frame descriptor complete */ + + /* Frame size too large */ + if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) > FRAME_SIZE_MAX) { + pa_log(__FILE__": Frame size too large\n"); + goto die; + } + + assert(!p->read.packet && !p->read.memblock); + + if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]) == (uint32_t) -1) { + /* Frame is a packet frame */ + p->read.packet = pa_packet_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])); + assert(p->read.packet); + p->read.data = p->read.packet->data; + } else { + /* Frame is a memblock frame */ + p->read.memblock = pa_memblock_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]), p->memblock_stat); + assert(p->read.memblock); + p->read.data = p->read.memblock->data; + } + + } else if (p->read.index > PA_PSTREAM_DESCRIPTOR_SIZE) { + /* Frame payload available */ + + if (p->read.memblock && p->recieve_memblock_callback) { /* Is this memblock data? Than pass it to the user */ + l = (p->read.index - r) < PA_PSTREAM_DESCRIPTOR_SIZE ? p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE : (size_t) r; + + if (l > 0) { + pa_memchunk chunk; + + chunk.memblock = p->read.memblock; + chunk.index = p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE - l; + chunk.length = l; + + if (p->recieve_memblock_callback) + p->recieve_memblock_callback( + p, + ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]), + ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA]), + &chunk, + p->recieve_memblock_callback_userdata); + } + } + + /* Frame complete */ + if (p->read.index >= ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) + PA_PSTREAM_DESCRIPTOR_SIZE) { + if (p->read.memblock) { + assert(!p->read.packet); + + pa_memblock_unref(p->read.memblock); + p->read.memblock = NULL; + } else { + assert(p->read.packet); + + if (p->recieve_packet_callback) + p->recieve_packet_callback(p, p->read.packet, p->recieve_packet_callback_userdata); + + pa_packet_unref(p->read.packet); + p->read.packet = NULL; + } + + p->read.index = 0; + } + } + + return; + +die: + p->dead = 1; + if (p->die_callback) + p->die_callback(p, p->die_callback_userdata); + +} + +void pa_pstream_set_die_callback(pa_pstream *p, void (*callback)(pa_pstream *p, void *userdata), void *userdata) { + assert(p && callback); + p->die_callback = callback; + p->die_callback_userdata = userdata; +} + +int pa_pstream_is_pending(pa_pstream *p) { + assert(p); + + if (p->dead) + return 0; + + return p->write.current || !pa_queue_is_empty(p->send_queue); +} + +void pa_pstream_set_drain_callback(pa_pstream *p, void (*cb)(pa_pstream *p, void *userdata), void *userdata) { + assert(p); + + p->drain_callback = cb; + p->drain_userdata = userdata; +} + +void pa_pstream_unref(pa_pstream*p) { + assert(p && p->ref >= 1); + + if (!(--(p->ref))) + pstream_free(p); +} + +pa_pstream* pa_pstream_ref(pa_pstream*p) { + assert(p && p->ref >= 1); + p->ref++; + return p; +} + +void pa_pstream_close(pa_pstream *p) { + assert(p); + + p->dead = 1; + + if (p->io) { + pa_iochannel_free(p->io); + p->io = NULL; + } + + if (p->defer_event) { + p->mainloop->defer_free(p->defer_event); + p->defer_event = NULL; + } + + p->die_callback = NULL; + p->drain_callback = NULL; + p->recieve_packet_callback = NULL; + p->recieve_memblock_callback = NULL; +} diff --git a/src/polypcore/pstream.h b/src/polypcore/pstream.h new file mode 100644 index 00000000..ec63a98e --- /dev/null +++ b/src/polypcore/pstream.h @@ -0,0 +1,52 @@ +#ifndef foopstreamhfoo +#define foopstreamhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "packet.h" +#include "memblock.h" +#include "iochannel.h" +#include +#include "memchunk.h" + +typedef struct pa_pstream pa_pstream; + +pa_pstream* pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_stat *s); +void pa_pstream_unref(pa_pstream*p); +pa_pstream* pa_pstream_ref(pa_pstream*p); + +void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet); +void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk); + +void pa_pstream_set_recieve_packet_callback(pa_pstream *p, void (*callback) (pa_pstream *p, pa_packet *packet, void *userdata), void *userdata); +void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, void (*callback) (pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata), void *userdata); +void pa_pstream_set_drain_callback(pa_pstream *p, void (*cb)(pa_pstream *p, void *userdata), void *userdata); + +void pa_pstream_set_die_callback(pa_pstream *p, void (*callback)(pa_pstream *p, void *userdata), void *userdata); + +int pa_pstream_is_pending(pa_pstream *p); + +void pa_pstream_close(pa_pstream *p); + +#endif diff --git a/src/polypcore/queue.c b/src/polypcore/queue.c new file mode 100644 index 00000000..80ec0068 --- /dev/null +++ b/src/polypcore/queue.c @@ -0,0 +1,108 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "queue.h" +#include "xmalloc.h" + +struct queue_entry { + struct queue_entry *next; + void *data; +}; + +struct pa_queue { + struct queue_entry *front, *back; + unsigned length; +}; + +pa_queue* pa_queue_new(void) { + pa_queue *q = pa_xnew(pa_queue, 1); + q->front = q->back = NULL; + q->length = 0; + return q; +} + +void pa_queue_free(pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata) { + struct queue_entry *e; + assert(q); + + e = q->front; + while (e) { + struct queue_entry *n = e->next; + + if (destroy) + destroy(e->data, userdata); + + pa_xfree(e); + e = n; + } + + pa_xfree(q); +} + +void pa_queue_push(pa_queue *q, void *p) { + struct queue_entry *e; + + e = pa_xnew(struct queue_entry, 1); + e->data = p; + e->next = NULL; + + if (q->back) + q->back->next = e; + else { + assert(!q->front); + q->front = e; + } + + q->back = e; + q->length++; +} + +void* pa_queue_pop(pa_queue *q) { + void *p; + struct queue_entry *e; + assert(q); + + if (!(e = q->front)) + return NULL; + + q->front = e->next; + if (q->back == e) + q->back = NULL; + + p = e->data; + pa_xfree(e); + + q->length--; + + return p; +} + +int pa_queue_is_empty(pa_queue *q) { + assert(q); + return q->length == 0; +} diff --git a/src/polypcore/queue.h b/src/polypcore/queue.h new file mode 100644 index 00000000..3edcfb63 --- /dev/null +++ b/src/polypcore/queue.h @@ -0,0 +1,40 @@ +#ifndef fooqueuehfoo +#define fooqueuehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef struct pa_queue pa_queue; + +/* A simple implementation of the abstract data type queue. Stores + * pointers as members. The memory has to be managed by the caller. */ + +pa_queue* pa_queue_new(void); + +/* Free the queue and run the specified callback function for every remaining entry. The callback function may be NULL. */ +void pa_queue_free(pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata); + +void pa_queue_push(pa_queue *q, void *p); +void* pa_queue_pop(pa_queue *q); + +int pa_queue_is_empty(pa_queue *q); + +#endif diff --git a/src/polypcore/random.c b/src/polypcore/random.c new file mode 100644 index 00000000..12f27bfd --- /dev/null +++ b/src/polypcore/random.c @@ -0,0 +1,71 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "random.h" +#include "util.h" +#include "log.h" + +#ifndef OS_IS_WIN32 +#define RANDOM_DEVICE "/dev/urandom" +#endif + +void pa_random(void *ret_data, size_t length) { + int fd; + ssize_t r = 0; + assert(ret_data && length); + +#ifdef RANDOM_DEVICE + if ((fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) { + + if ((r = pa_loop_read(fd, ret_data, length)) < 0 || (size_t) r != length) + pa_log_error(__FILE__": failed to read entropy from '%s'\n", RANDOM_DEVICE); + + close(fd); + } +#endif + + if ((size_t) r != length) { + uint8_t *p; + size_t l; + +#ifdef RANDOM_DEVICE + pa_log_warn(__FILE__": WARNING: Failed to open entropy device '"RANDOM_DEVICE"': %s" + ", falling back to unsecure pseudo RNG.\n", strerror(errno)); +#endif + + srand(time(NULL)); + + for (p = ret_data, l = length; l > 0; p++, l--) + *p = (uint8_t) rand(); + } +} diff --git a/src/polypcore/random.h b/src/polypcore/random.h new file mode 100644 index 00000000..bfb3df08 --- /dev/null +++ b/src/polypcore/random.h @@ -0,0 +1,27 @@ +#ifndef foorandomhfoo +#define foorandomhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +void pa_random(void *ret_data, size_t length); + +#endif diff --git a/src/polypcore/resampler.c b/src/polypcore/resampler.c new file mode 100644 index 00000000..0417e44e --- /dev/null +++ b/src/polypcore/resampler.c @@ -0,0 +1,614 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include + +#include "resampler.h" +#include "sconv.h" +#include "xmalloc.h" +#include "log.h" + +struct pa_resampler { + pa_resample_method_t resample_method; + pa_sample_spec i_ss, o_ss; + pa_channel_map i_cm, o_cm; + size_t i_fz, o_fz; + pa_memblock_stat *memblock_stat; + + void (*impl_free)(pa_resampler *r); + void (*impl_update_input_rate)(pa_resampler *r, uint32_t rate); + void (*impl_run)(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out); + void *impl_data; +}; + +struct impl_libsamplerate { + float* buf1, *buf2, *buf3, *buf4; + unsigned buf1_samples, buf2_samples, buf3_samples, buf4_samples; + + pa_convert_to_float32ne_func_t to_float32ne_func; + pa_convert_from_float32ne_func_t from_float32ne_func; + SRC_STATE *src_state; + + int map_table[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; + int map_required; +}; + +struct impl_trivial { + unsigned o_counter; + unsigned i_counter; +}; + +static int libsamplerate_init(pa_resampler*r); +static int trivial_init(pa_resampler*r); + +pa_resampler* pa_resampler_new( + const pa_sample_spec *a, + const pa_channel_map *am, + const pa_sample_spec *b, + const pa_channel_map *bm, + pa_memblock_stat *s, + pa_resample_method_t resample_method) { + + pa_resampler *r = NULL; + + assert(a); + assert(b); + assert(pa_sample_spec_valid(a)); + assert(pa_sample_spec_valid(b)); + assert(resample_method != PA_RESAMPLER_INVALID); + + r = pa_xnew(pa_resampler, 1); + r->impl_data = NULL; + r->memblock_stat = s; + r->resample_method = resample_method; + + r->impl_free = NULL; + r->impl_update_input_rate = NULL; + r->impl_run = NULL; + + /* Fill sample specs */ + r->i_ss = *a; + r->o_ss = *b; + + if (am) + r->i_cm = *am; + else + pa_channel_map_init_auto(&r->i_cm, r->i_ss.channels); + + if (bm) + r->o_cm = *bm; + else + pa_channel_map_init_auto(&r->o_cm, r->o_ss.channels); + + r->i_fz = pa_frame_size(a); + r->o_fz = pa_frame_size(b); + + /* Choose implementation */ + if (a->channels != b->channels || + a->format != b->format || + !pa_channel_map_equal(&r->i_cm, &r->o_cm) || + resample_method != PA_RESAMPLER_TRIVIAL) { + + /* Use the libsamplerate based resampler for the complicated cases */ + if (resample_method == PA_RESAMPLER_TRIVIAL) + r->resample_method = PA_RESAMPLER_SRC_ZERO_ORDER_HOLD; + + if (libsamplerate_init(r) < 0) + goto fail; + + } else { + /* Use our own simple non-fp resampler for the trivial cases and when the user selects it */ + if (trivial_init(r) < 0) + goto fail; + } + + return r; + +fail: + if (r) + pa_xfree(r); + + return NULL; +} + +void pa_resampler_free(pa_resampler *r) { + assert(r); + + if (r->impl_free) + r->impl_free(r); + + pa_xfree(r); +} + +void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate) { + assert(r); + assert(rate > 0); + + if (r->i_ss.rate == rate) + return; + + r->i_ss.rate = rate; + + if (r->impl_update_input_rate) + r->impl_update_input_rate(r, rate); +} + +void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { + assert(r && in && out && r->impl_run); + + r->impl_run(r, in, out); +} + +size_t pa_resampler_request(pa_resampler *r, size_t out_length) { + assert(r && (out_length % r->o_fz) == 0); + return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz; +} + +pa_resample_method_t pa_resampler_get_method(pa_resampler *r) { + assert(r); + return r->resample_method; +} + +static const char * const resample_methods[] = { + "src-sinc-best-quality", + "src-sinc-medium-quality", + "src-sinc-fastest", + "src-zero-order-hold", + "src-linear", + "trivial" +}; + +const char *pa_resample_method_to_string(pa_resample_method_t m) { + + if (m < 0 || m >= PA_RESAMPLER_MAX) + return NULL; + + return resample_methods[m]; +} + +pa_resample_method_t pa_parse_resample_method(const char *string) { + pa_resample_method_t m; + + assert(string); + + for (m = 0; m < PA_RESAMPLER_MAX; m++) + if (!strcmp(string, resample_methods[m])) + return m; + + return PA_RESAMPLER_INVALID; +} + + +/*** libsamplerate based implementation ***/ + +static void libsamplerate_free(pa_resampler *r) { + struct impl_libsamplerate *u; + + assert(r); + assert(r->impl_data); + + u = r->impl_data; + + if (u->src_state) + src_delete(u->src_state); + + pa_xfree(u->buf1); + pa_xfree(u->buf2); + pa_xfree(u->buf3); + pa_xfree(u->buf4); + pa_xfree(u); +} + +static void calc_map_table(pa_resampler *r) { + struct impl_libsamplerate *u; + unsigned oc; + assert(r); + assert(r->impl_data); + + u = r->impl_data; + + if (!(u->map_required = (!pa_channel_map_equal(&r->i_cm, &r->o_cm) || r->i_ss.channels != r->o_ss.channels))) + return; + + for (oc = 0; oc < r->o_ss.channels; oc++) { + unsigned ic, i = 0; + + for (ic = 0; ic < r->i_ss.channels; ic++) { + pa_channel_position_t a, b; + + a = r->i_cm.map[ic]; + b = r->o_cm.map[oc]; + + if (a == b || + (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_LEFT) || + (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_RIGHT) || + (a == PA_CHANNEL_POSITION_LEFT && b == PA_CHANNEL_POSITION_MONO) || + (a == PA_CHANNEL_POSITION_RIGHT && b == PA_CHANNEL_POSITION_MONO)) + + u->map_table[oc][i++] = ic; + } + + /* Add an end marker */ + if (i < PA_CHANNELS_MAX) + u->map_table[oc][i] = -1; + } +} + +static float * convert_to_float(pa_resampler *r, float *input, unsigned n_frames) { + struct impl_libsamplerate *u; + unsigned n_samples; + + assert(r); + assert(input); + assert(r->impl_data); + u = r->impl_data; + + /* Convert the incoming sample into floats and place them in buf1 */ + + if (!u->to_float32ne_func) + return input; + + n_samples = n_frames * r->i_ss.channels; + + if (u->buf1_samples < n_samples) + u->buf1 = pa_xrealloc(u->buf1, sizeof(float) * (u->buf1_samples = n_samples)); + + u->to_float32ne_func(n_samples, input, u->buf1); + + return u->buf1; +} + +static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) { + struct impl_libsamplerate *u; + unsigned n_samples; + int i_skip, o_skip; + unsigned oc; + + assert(r); + assert(input); + assert(r->impl_data); + u = r->impl_data; + + /* Remap channels and place the result int buf2 */ + + if (!u->map_required) + return input; + + n_samples = n_frames * r->o_ss.channels; + + if (u->buf2_samples < n_samples) + u->buf2 = pa_xrealloc(u->buf2, sizeof(float) * (u->buf2_samples = n_samples)); + + memset(u->buf2, 0, n_samples * sizeof(float)); + + o_skip = sizeof(float) * r->o_ss.channels; + i_skip = sizeof(float) * r->i_ss.channels; + + for (oc = 0; oc < r->o_ss.channels; oc++) { + unsigned i; + static const float one = 1.0; + + for (i = 0; i < PA_CHANNELS_MAX && u->map_table[oc][i] >= 0; i++) + oil_vectoradd_f32( + u->buf2 + oc, o_skip, + u->buf2 + oc, o_skip, + input + u->map_table[oc][i], i_skip, + n_frames, + &one, &one); + } + + return u->buf2; +} + +static float *resample(pa_resampler *r, float *input, unsigned *n_frames) { + struct impl_libsamplerate *u; + SRC_DATA data; + unsigned out_n_frames, out_n_samples; + int ret; + + assert(r); + assert(input); + assert(n_frames); + assert(r->impl_data); + u = r->impl_data; + + /* Resample the data and place the result in buf3 */ + + if (!u->src_state) + return input; + + out_n_frames = (*n_frames*r->o_ss.rate/r->i_ss.rate)+1024; + out_n_samples = out_n_frames * r->o_ss.channels; + + if (u->buf3_samples < out_n_samples) + u->buf3 = pa_xrealloc(u->buf3, sizeof(float) * (u->buf3_samples = out_n_samples)); + + data.data_in = input; + data.input_frames = *n_frames; + + data.data_out = u->buf3; + data.output_frames = out_n_frames; + + data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate; + data.end_of_input = 0; + + ret = src_process(u->src_state, &data); + assert(ret == 0); + assert((unsigned) data.input_frames_used == *n_frames); + + *n_frames = data.output_frames_gen; + + return u->buf3; +} + +static float *convert_from_float(pa_resampler *r, float *input, unsigned n_frames) { + struct impl_libsamplerate *u; + unsigned n_samples; + + assert(r); + assert(input); + assert(r->impl_data); + u = r->impl_data; + + /* Convert the data into the correct sample type and place the result in buf4 */ + + if (!u->from_float32ne_func) + return input; + + n_samples = n_frames * r->o_ss.channels; + + if (u->buf4_samples < n_samples) + u->buf4 = pa_xrealloc(u->buf4, sizeof(float) * (u->buf4_samples = n_samples)); + + u->from_float32ne_func(n_samples, input, u->buf4); + + return u->buf4; +} + +static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { + struct impl_libsamplerate *u; + float *buf, *input; + unsigned n_frames; + + assert(r); + assert(in); + assert(out); + assert(in->length); + assert(in->memblock); + assert(in->length % r->i_fz == 0); + assert(r->impl_data); + + u = r->impl_data; + + buf = input = (float*) ((uint8_t*) in->memblock->data + in->index); + n_frames = in->length / r->i_fz; + assert(n_frames > 0); + + buf = convert_to_float(r, buf, n_frames); + buf = remap_channels(r, buf, n_frames); + buf = resample(r, buf, &n_frames); + + if (n_frames) { + buf = convert_from_float(r, buf, n_frames); + + if (buf == input) { + /* Mm, no adjustment has been necessary, so let's return the original block */ + out->memblock = pa_memblock_ref(in->memblock); + out->index = in->index; + out->length = in->length; + } else { + float **p = NULL; + + out->length = n_frames * r->o_fz; + out->index = 0; + + if (buf == u->buf1) { + p = &u->buf1; + u->buf1_samples = 0; + } else if (buf == u->buf2) { + p = &u->buf2; + u->buf2_samples = 0; + } else if (buf == u->buf3) { + p = &u->buf3; + u->buf3_samples = 0; + } else if (buf == u->buf4) { + p = &u->buf4; + u->buf4_samples = 0; + } + + assert(p); + + /* Take the existing buffer and make it a memblock */ + out->memblock = pa_memblock_new_dynamic(*p, out->length, r->memblock_stat); + *p = NULL; + } + } else { + out->memblock = NULL; + out->index = out->length = 0; + } +} + +static void libsamplerate_update_input_rate(pa_resampler *r, uint32_t rate) { + struct impl_libsamplerate *u; + + assert(r); + assert(rate > 0); + assert(r->impl_data); + u = r->impl_data; + + if (!u->src_state) { + int err; + u->src_state = src_new(r->resample_method, r->o_ss.channels, &err); + assert(u->src_state); + } else { + int ret = src_set_ratio(u->src_state, (double) r->o_ss.rate / rate); + assert(ret == 0); + } +} + +static int libsamplerate_init(pa_resampler *r) { + struct impl_libsamplerate *u = NULL; + int err; + + r->impl_data = u = pa_xnew(struct impl_libsamplerate, 1); + + u->buf1 = u->buf2 = u->buf3 = u->buf4 = NULL; + u->buf1_samples = u->buf2_samples = u->buf3_samples = u->buf4_samples = 0; + + if (r->i_ss.format == PA_SAMPLE_FLOAT32NE) + u->to_float32ne_func = NULL; + else if (!(u->to_float32ne_func = pa_get_convert_to_float32ne_function(r->i_ss.format))) + goto fail; + + if (r->o_ss.format == PA_SAMPLE_FLOAT32NE) + u->from_float32ne_func = NULL; + else if (!(u->from_float32ne_func = pa_get_convert_from_float32ne_function(r->o_ss.format))) + goto fail; + + if (r->o_ss.rate == r->i_ss.rate) + u->src_state = NULL; + else if (!(u->src_state = src_new(r->resample_method, r->o_ss.channels, &err))) + goto fail; + + r->impl_free = libsamplerate_free; + r->impl_update_input_rate = libsamplerate_update_input_rate; + r->impl_run = libsamplerate_run; + + calc_map_table(r); + + return 0; + +fail: + pa_xfree(u); + return -1; +} + +/* Trivial implementation */ + +static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { + size_t fz; + unsigned n_frames; + struct impl_trivial *u; + + assert(r); + assert(in); + assert(out); + assert(r->impl_data); + + u = r->impl_data; + + fz = r->i_fz; + assert(fz == r->o_fz); + + n_frames = in->length/fz; + + if (r->i_ss.rate == r->o_ss.rate) { + + /* In case there's no diefference in sample types, do nothing */ + *out = *in; + pa_memblock_ref(out->memblock); + + u->o_counter += n_frames; + } else { + /* Do real resampling */ + size_t l; + unsigned o_index; + + /* The length of the new memory block rounded up */ + l = ((((n_frames+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz; + + out->index = 0; + out->memblock = pa_memblock_new(l, r->memblock_stat); + + for (o_index = 0;; o_index++, u->o_counter++) { + unsigned j; + + j = (u->o_counter * r->i_ss.rate / r->o_ss.rate); + j = j > u->i_counter ? j - u->i_counter : 0; + + if (j >= n_frames) + break; + + assert(o_index*fz < out->memblock->length); + + memcpy((uint8_t*) out->memblock->data + fz*o_index, + (uint8_t*) in->memblock->data + in->index + fz*j, fz); + + } + + out->length = o_index*fz; + } + + u->i_counter += n_frames; + + /* Normalize counters */ + while (u->i_counter >= r->i_ss.rate) { + u->i_counter -= r->i_ss.rate; + assert(u->o_counter >= r->o_ss.rate); + u->o_counter -= r->o_ss.rate; + } +} + +static void trivial_free(pa_resampler *r) { + assert(r); + + pa_xfree(r->impl_data); +} + +static void trivial_update_input_rate(pa_resampler *r, uint32_t rate) { + struct impl_trivial *u; + + assert(r); + assert(rate > 0); + assert(r->impl_data); + + u = r->impl_data; + u->i_counter = 0; + u->o_counter = 0; +} + +static int trivial_init(pa_resampler*r) { + struct impl_trivial *u; + + assert(r); + assert(r->i_ss.format == r->o_ss.format); + assert(r->i_ss.channels == r->o_ss.channels); + + r->impl_data = u = pa_xnew(struct impl_trivial, 1); + u->o_counter = u->i_counter = 0; + + r->impl_run = trivial_run; + r->impl_free = trivial_free; + r->impl_update_input_rate = trivial_update_input_rate; + + return 0; +} + + diff --git a/src/polypcore/resampler.h b/src/polypcore/resampler.h new file mode 100644 index 00000000..cad48be5 --- /dev/null +++ b/src/polypcore/resampler.h @@ -0,0 +1,73 @@ +#ifndef fooresamplerhfoo +#define fooresamplerhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include "memblock.h" +#include "memchunk.h" +#include + +typedef struct pa_resampler pa_resampler; + +typedef enum pa_resample_method { + PA_RESAMPLER_INVALID = -1, + PA_RESAMPLER_SRC_SINC_BEST_QUALITY = SRC_SINC_BEST_QUALITY, + PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY = SRC_SINC_MEDIUM_QUALITY, + PA_RESAMPLER_SRC_SINC_FASTEST = SRC_SINC_FASTEST, + PA_RESAMPLER_SRC_ZERO_ORDER_HOLD = SRC_ZERO_ORDER_HOLD, + PA_RESAMPLER_SRC_LINEAR = SRC_LINEAR, + PA_RESAMPLER_TRIVIAL, + PA_RESAMPLER_MAX +} pa_resample_method_t; + +pa_resampler* pa_resampler_new( + const pa_sample_spec *a, + const pa_channel_map *am, + const pa_sample_spec *b, + const pa_channel_map *bm, + pa_memblock_stat *s, + pa_resample_method_t resample_method); + +void pa_resampler_free(pa_resampler *r); + +/* Returns the size of an input memory block which is required to return the specified amount of output data */ +size_t pa_resampler_request(pa_resampler *r, size_t out_length); + +/* Pass the specified memory chunk to the resampler and return the newly resampled data */ +void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out); + +/* Change the input rate of the resampler object */ +void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate); + +/* Return the resampling method of the resampler object */ +pa_resample_method_t pa_resampler_get_method(pa_resampler *r); + +/* Try to parse the resampler method */ +pa_resample_method_t pa_parse_resample_method(const char *string); + +/* return a human readable string for the specified resampling method. Inverse of pa_parse_resample_method() */ +const char *pa_resample_method_to_string(pa_resample_method_t m); + +#endif diff --git a/src/polypcore/sample-util.c b/src/polypcore/sample-util.c new file mode 100644 index 00000000..52974c46 --- /dev/null +++ b/src/polypcore/sample-util.c @@ -0,0 +1,328 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include "log.h" +#include "sample-util.h" + +pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) { + assert(b && b->data && spec); + pa_silence_memory(b->data, b->length, spec); + return b; +} + +void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) { + assert(c && c->memblock && c->memblock->data && spec && c->length); + + pa_silence_memory((uint8_t*) c->memblock->data+c->index, c->length, spec); +} + +void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { + uint8_t c = 0; + assert(p && length && spec); + + switch (spec->format) { + case PA_SAMPLE_U8: + c = 0x80; + break; + case PA_SAMPLE_S16LE: + case PA_SAMPLE_S16BE: + case PA_SAMPLE_FLOAT32: + c = 0; + break; + case PA_SAMPLE_ALAW: + case PA_SAMPLE_ULAW: + c = 80; + break; + default: + assert(0); + } + + memset(p, c, length); +} + +size_t pa_mix( + const pa_mix_info streams[], + unsigned nstreams, + void *data, + size_t length, + const pa_sample_spec *spec, + const pa_cvolume *volume) { + + assert(streams && data && length && spec); + + switch (spec->format) { + case PA_SAMPLE_S16NE:{ + size_t d; + unsigned channel = 0; + + for (d = 0;; d += sizeof(int16_t)) { + int32_t sum = 0; + + if (d >= length) + return d; + + if (volume->values[channel] != PA_VOLUME_MUTED) { + unsigned i; + + for (i = 0; i < nstreams; i++) { + int32_t v; + pa_volume_t cvolume = streams[i].volume.values[channel]; + + if (d >= streams[i].chunk.length) + return d; + + if (cvolume == PA_VOLUME_MUTED) + v = 0; + else { + v = *((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); + + if (cvolume != PA_VOLUME_NORM) { + v *= cvolume; + v /= PA_VOLUME_NORM; + } + } + + sum += v; + } + + if (volume->values[channel] != PA_VOLUME_NORM) { + sum *= volume->values[channel]; + sum /= PA_VOLUME_NORM; + } + + if (sum < -0x8000) sum = -0x8000; + if (sum > 0x7FFF) sum = 0x7FFF; + + } + + *((int16_t*) data) = sum; + data = (uint8_t*) data + sizeof(int16_t); + + if (++channel >= spec->channels) + channel = 0; + } + } + + case PA_SAMPLE_U8: { + size_t d; + unsigned channel = 0; + + for (d = 0;; d ++) { + int32_t sum = 0; + + if (d >= length) + return d; + + if (volume->values[channel] != PA_VOLUME_MUTED) { + unsigned i; + + for (i = 0; i < nstreams; i++) { + int32_t v; + pa_volume_t cvolume = streams[i].volume.values[channel]; + + if (d >= streams[i].chunk.length) + return d; + + if (cvolume == PA_VOLUME_MUTED) + v = 0; + else { + v = (int32_t) *((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d) - 0x80; + + if (cvolume != PA_VOLUME_NORM) { + v *= cvolume; + v /= PA_VOLUME_NORM; + } + } + + sum += v; + } + + if (volume->values[channel] != PA_VOLUME_NORM) { + sum *= volume->values[channel]; + sum /= PA_VOLUME_NORM; + } + + if (sum < -0x80) sum = -0x80; + if (sum > 0x7F) sum = 0x7F; + + } + + *((uint8_t*) data) = (uint8_t) (sum + 0x80); + data = (uint8_t*) data + 1; + + if (++channel >= spec->channels) + channel = 0; + } + } + + case PA_SAMPLE_FLOAT32NE: { + size_t d; + unsigned channel = 0; + + for (d = 0;; d += sizeof(float)) { + float sum = 0; + + if (d >= length) + return d; + + if (volume->values[channel] != PA_VOLUME_MUTED) { + unsigned i; + + for (i = 0; i < nstreams; i++) { + float v; + pa_volume_t cvolume = streams[i].volume.values[channel]; + + if (d >= streams[i].chunk.length) + return d; + + if (cvolume == PA_VOLUME_MUTED) + v = 0; + else { + v = *((float*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); + + if (cvolume != PA_VOLUME_NORM) { + v *= cvolume; + v /= PA_VOLUME_NORM; + } + } + + sum += v; + } + + if (volume->values[channel] != PA_VOLUME_NORM) { + sum *= volume->values[channel]; + sum /= PA_VOLUME_NORM; + } + } + + *((float*) data) = sum; + data = (uint8_t*) data + sizeof(float); + + if (++channel >= spec->channels) + channel = 0; + } + } + + default: + abort(); + } +} + + +void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvolume *volume) { + assert(c && spec && (c->length % pa_frame_size(spec) == 0)); + assert(volume); + + if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM)) + return; + + if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) { + pa_silence_memchunk(c, spec); + return; + } + + switch (spec->format) { + case PA_SAMPLE_S16NE: { + int16_t *d; + size_t n; + unsigned channel = 0; + + for (d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { + int32_t t = (int32_t)(*d); + + t *= volume->values[channel]; + t /= PA_VOLUME_NORM; + + if (t < -0x8000) t = -0x8000; + if (t > 0x7FFF) t = 0x7FFF; + + *d = (int16_t) t; + + if (++channel >= spec->channels) + channel = 0; + } + break; + } + + case PA_SAMPLE_U8: { + uint8_t *d; + size_t n; + unsigned channel = 0; + + for (d = (uint8_t*) c->memblock->data + c->index, n = c->length; n > 0; d++, n--) { + int32_t t = (int32_t) *d - 0x80; + + t *= volume->values[channel]; + t /= PA_VOLUME_NORM; + + if (t < -0x80) t = -0x80; + if (t > 0x7F) t = 0x7F; + + *d = (uint8_t) (t + 0x80); + + if (++channel >= spec->channels) + channel = 0; + } + break; + } + + case PA_SAMPLE_FLOAT32NE: { + float *d; + int skip; + unsigned n; + unsigned channel; + + d = (float*) ((uint8_t*) c->memblock->data + c->index); + skip = spec->channels * sizeof(float); + n = c->length/sizeof(float)/spec->channels; + + for (channel = 0; channel < spec->channels ; channel ++) { + float v, *t; + + if (volume->values[channel] == PA_VOLUME_NORM) + continue; + + v = (float) volume->values[channel] / PA_VOLUME_NORM; + + t = d + channel; + oil_scalarmult_f32(t, skip, t, skip, &v, n); + } + break; + } + + default: + pa_log_error(__FILE__": ERROR: Unable to change volume of format %s.\n", + pa_sample_format_to_string(spec->format)); + abort(); + } +} + diff --git a/src/polypcore/sample-util.h b/src/polypcore/sample-util.h new file mode 100644 index 00000000..d0efbcc4 --- /dev/null +++ b/src/polypcore/sample-util.h @@ -0,0 +1,53 @@ +#ifndef foosampleutilhfoo +#define foosampleutilhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include "memblock.h" +#include "memchunk.h" +#include + +pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec); +void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec); +void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec); + +typedef struct pa_mix_info { + pa_memchunk chunk; + pa_cvolume volume; + void *userdata; +} pa_mix_info; + +size_t pa_mix( + const pa_mix_info channels[], + unsigned nchannels, + void *data, + size_t length, + const pa_sample_spec *spec, + const pa_cvolume *volume); + +void pa_volume_memchunk( + pa_memchunk*c, + const pa_sample_spec *spec, + const pa_cvolume *volume); + +#endif diff --git a/src/polypcore/scache.c b/src/polypcore/scache.c new file mode 100644 index 00000000..02c7d34f --- /dev/null +++ b/src/polypcore/scache.c @@ -0,0 +1,392 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_GLOB_H +#include +#endif + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include "scache.h" +#include "sink-input.h" +#include +#include "sample-util.h" +#include "play-memchunk.h" +#include "xmalloc.h" +#include "subscribe.h" +#include "namereg.h" +#include "sound-file.h" +#include "util.h" +#include "log.h" +#include +#include + +#define UNLOAD_POLL_TIME 2 + +static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + pa_core *c = userdata; + struct timeval ntv; + assert(c && c->mainloop == m && c->scache_auto_unload_event == e); + + pa_scache_unload_unused(c); + + pa_gettimeofday(&ntv); + ntv.tv_sec += UNLOAD_POLL_TIME; + m->time_restart(e, &ntv); +} + +static void free_entry(pa_scache_entry *e) { + assert(e); + pa_namereg_unregister(e->core, e->name); + pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_REMOVE, e->index); + pa_xfree(e->name); + pa_xfree(e->filename); + if (e->memchunk.memblock) + pa_memblock_unref(e->memchunk.memblock); + pa_xfree(e); +} + +static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { + pa_scache_entry *e; + assert(c && name); + + if ((e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) { + if (e->memchunk.memblock) + pa_memblock_unref(e->memchunk.memblock); + + pa_xfree(e->filename); + + assert(e->core == c); + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); + } else { + e = pa_xmalloc(sizeof(pa_scache_entry)); + + if (!pa_namereg_register(c, name, PA_NAMEREG_SAMPLE, e, 1)) { + pa_xfree(e); + return NULL; + } + + e->name = pa_xstrdup(name); + e->core = c; + + if (!c->scache) { + c->scache = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + assert(c->scache); + } + + pa_idxset_put(c->scache, e, &e->index); + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_NEW, e->index); + } + + pa_cvolume_reset(&e->volume, PA_CHANNELS_MAX); + e->last_used_time = 0; + e->memchunk.memblock = NULL; + e->memchunk.index = e->memchunk.length = 0; + e->filename = NULL; + e->lazy = 0; + e->last_used_time = 0; + + memset(&e->sample_spec, 0, sizeof(pa_sample_spec)); + + return e; +} + +int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx) { + pa_scache_entry *e; + assert(c && name); + + if (!(e = scache_add_item(c, name))) + return -1; + + if (ss) { + e->sample_spec = *ss; + pa_channel_map_init_auto(&e->channel_map, ss->channels); + } + + if (map) + e->channel_map = *map; + + if (chunk) { + e->memchunk = *chunk; + pa_memblock_ref(e->memchunk.memblock); + } + + if (idx) + *idx = e->index; + + return 0; +} + +int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint32_t *idx) { + pa_sample_spec ss; + pa_memchunk chunk; + int r; + +#ifdef OS_IS_WIN32 + char buf[MAX_PATH]; + + if (ExpandEnvironmentStrings(filename, buf, MAX_PATH)) + filename = buf; +#endif + + if (pa_sound_file_load(filename, &ss, &chunk, c->memblock_stat) < 0) + return -1; + + r = pa_scache_add_item(c, name, &ss, NULL, &chunk, idx); + pa_memblock_unref(chunk.memblock); + + return r; +} + +int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, uint32_t *idx) { + pa_scache_entry *e; + +#ifdef OS_IS_WIN32 + char buf[MAX_PATH]; + + if (ExpandEnvironmentStrings(filename, buf, MAX_PATH)) + filename = buf; +#endif + + assert(c && name); + + if (!(e = scache_add_item(c, name))) + return -1; + + e->lazy = 1; + e->filename = pa_xstrdup(filename); + + if (!c->scache_auto_unload_event) { + struct timeval ntv; + pa_gettimeofday(&ntv); + ntv.tv_sec += UNLOAD_POLL_TIME; + c->scache_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); + } + + if (idx) + *idx = e->index; + + return 0; +} + +int pa_scache_remove_item(pa_core *c, const char *name) { + pa_scache_entry *e; + assert(c && name); + + if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) + return -1; + + if (pa_idxset_remove_by_data(c->scache, e, NULL) != e) + assert(0); + + free_entry(e); + return 0; +} + +static void free_cb(void *p, PA_GCC_UNUSED void *userdata) { + pa_scache_entry *e = p; + assert(e); + free_entry(e); +} + +void pa_scache_free(pa_core *c) { + assert(c); + + if (c->scache) { + pa_idxset_free(c->scache, free_cb, NULL); + c->scache = NULL; + } + + if (c->scache_auto_unload_event) + c->mainloop->time_free(c->scache_auto_unload_event); +} + +int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, const pa_cvolume *volume) { + pa_scache_entry *e; + char *t; + pa_cvolume r; + assert(c && name && sink); + + if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1))) + return -1; + + if (e->lazy && !e->memchunk.memblock) { + if (pa_sound_file_load(e->filename, &e->sample_spec, &e->memchunk, c->memblock_stat) < 0) + return -1; + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); + } + + if (!e->memchunk.memblock) + return -1; + + t = pa_sprintf_malloc("sample:%s", name); + + if (pa_play_memchunk(sink, t, &e->sample_spec, &e->channel_map, &e->memchunk, pa_sw_cvolume_multiply(&r, volume, &e->volume)) < 0) { + free(t); + return -1; + } + + free(t); + + if (e->lazy) + time(&e->last_used_time); + + return 0; +} + +const char * pa_scache_get_name_by_id(pa_core *c, uint32_t id) { + pa_scache_entry *e; + assert(c && id != PA_IDXSET_INVALID); + + if (!c->scache || !(e = pa_idxset_get_by_index(c->scache, id))) + return NULL; + + return e->name; +} + +uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name) { + pa_scache_entry *e; + assert(c && name); + + if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) + return PA_IDXSET_INVALID; + + return e->index; +} + +uint32_t pa_scache_total_size(pa_core *c) { + pa_scache_entry *e; + uint32_t idx, sum = 0; + assert(c); + + if (!c->scache || !pa_idxset_size(c->scache)) + return 0; + + for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) + if (e->memchunk.memblock) + sum += e->memchunk.length; + + return sum; +} + +void pa_scache_unload_unused(pa_core *c) { + pa_scache_entry *e; + time_t now; + uint32_t idx; + assert(c); + + if (!c->scache || !pa_idxset_size(c->scache)) + return; + + time(&now); + + for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) { + + if (!e->lazy || !e->memchunk.memblock) + continue; + + if (e->last_used_time + c->scache_idle_time > now) + continue; + + pa_memblock_unref(e->memchunk.memblock); + e->memchunk.memblock = NULL; + e->memchunk.index = e->memchunk.length = 0; + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); + } +} + +static void add_file(pa_core *c, const char *pathname) { + struct stat st; + const char *e; + + e = pa_path_get_filename(pathname); + + if (stat(pathname, &st) < 0) { + pa_log(__FILE__": stat('%s') failed: %s\n", pathname, strerror(errno)); + return; + } + +#if defined(S_ISREG) && defined(S_ISLNK) + if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) +#endif + pa_scache_add_file_lazy(c, e, pathname, NULL); +} + +int pa_scache_add_directory_lazy(pa_core *c, const char *pathname) { + DIR *dir; + assert(c && pathname); + + /* First try to open this as directory */ + if (!(dir = opendir(pathname))) { +#ifdef HAVE_GLOB_H + glob_t p; + unsigned int i; + /* If that fails, try to open it as shell glob */ + + if (glob(pathname, GLOB_ERR|GLOB_NOSORT, NULL, &p) < 0) { + pa_log(__FILE__": Failed to open directory: %s\n", strerror(errno)); + return -1; + } + + for (i = 0; i < p.gl_pathc; i++) + add_file(c, p.gl_pathv[i]); + + globfree(&p); +#else + return -1; +#endif + } else { + struct dirent *e; + + while ((e = readdir(dir))) { + char p[PATH_MAX]; + + if (e->d_name[0] == '.') + continue; + + snprintf(p, sizeof(p), "%s/%s", pathname, e->d_name); + add_file(c, p); + } + } + + closedir(dir); + return 0; +} diff --git a/src/polypcore/scache.h b/src/polypcore/scache.h new file mode 100644 index 00000000..d667ae60 --- /dev/null +++ b/src/polypcore/scache.h @@ -0,0 +1,62 @@ +#ifndef fooscachehfoo +#define fooscachehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" +#include "memchunk.h" +#include "sink.h" + +typedef struct pa_scache_entry { + pa_core *core; + uint32_t index; + char *name; + + pa_cvolume volume; + pa_sample_spec sample_spec; + pa_channel_map channel_map; + pa_memchunk memchunk; + + char *filename; + + int lazy; + time_t last_used_time; +} pa_scache_entry; + +int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx); +int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint32_t *idx); +int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, uint32_t *idx); + +int pa_scache_add_directory_lazy(pa_core *c, const char *pathname); + +int pa_scache_remove_item(pa_core *c, const char *name); +int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, const pa_cvolume *cvolume); +void pa_scache_free(pa_core *c); + +const char *pa_scache_get_name_by_id(pa_core *c, uint32_t id); +uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name); + +uint32_t pa_scache_total_size(pa_core *c); + +void pa_scache_unload_unused(pa_core *c); + +#endif diff --git a/src/polypcore/sconv-s16be.c b/src/polypcore/sconv-s16be.c new file mode 100644 index 00000000..8b076f06 --- /dev/null +++ b/src/polypcore/sconv-s16be.c @@ -0,0 +1,41 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "endianmacros.h" + +#define INT16_FROM INT16_FROM_BE +#define INT16_TO INT16_TO_BE + +#define pa_sconv_s16le_to_float32ne pa_sconv_s16be_to_float32ne +#define pa_sconv_s16le_from_float32ne pa_sconv_s16be_from_float32ne + +#ifdef WORDS_BIGENDIAN +#define SWAP_WORDS 0 +#else +#define SWAP_WORDS 1 +#endif + +#include "sconv-s16le.h" +#include "sconv-s16le.c" diff --git a/src/polypcore/sconv-s16be.h b/src/polypcore/sconv-s16be.h new file mode 100644 index 00000000..b2b6a8c7 --- /dev/null +++ b/src/polypcore/sconv-s16be.h @@ -0,0 +1,28 @@ +#ifndef foosconv_s16befoo +#define foosconv_s16befoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +void pa_sconv_s16be_to_float32ne(unsigned n, const void *a, float *b); +void pa_sconv_s16be_from_float32ne(unsigned n, const float *a, void *b); + +#endif diff --git a/src/polypcore/sconv-s16le.c b/src/polypcore/sconv-s16le.c new file mode 100644 index 00000000..e47c5e8e --- /dev/null +++ b/src/polypcore/sconv-s16le.c @@ -0,0 +1,101 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include "endianmacros.h" +#include "sconv.h" +#include "sconv-s16le.h" +#include "log.h" + +#ifndef INT16_FROM +#define INT16_FROM INT16_FROM_LE +#endif + +#ifndef INT16_TO +#define INT16_TO INT16_TO_LE +#endif + +#ifndef SWAP_WORDS +#ifdef WORDS_BIGENDIAN +#define SWAP_WORDS 1 +#else +#define SWAP_WORDS 0 +#endif +#endif + +void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b) { + const int16_t *ca = a; + + assert(a); + assert(b); + +#if SWAP_WORDS == 1 + + for (; n > 0; n--) { + int16_t s = *(ca++); + *(b++) = ((float) INT16_FROM(s))/0x7FFF; + } + +#else +{ + static const double add = 0, factor = 1.0/0x7FFF; + oil_scaleconv_f32_s16(b, ca, n, &add, &factor); +} +#endif +} + +void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b) { + int16_t *cb = b; + + assert(a); + assert(b); + +#if SWAP_WORDS == 1 + + for (; n > 0; n--) { + int16_t s; + float v = *(a++); + + if (v > 1) + v = 1; + + if (v < -1) + v = -1; + + s = (int16_t) (v * 0x7FFF); + *(cb++) = INT16_TO(s); + } + +#else +{ + static const double add = 0, factor = 0x7FFF; + oil_scaleconv_s16_f32(cb, a, n, &add, &factor); +} +#endif +} diff --git a/src/polypcore/sconv-s16le.h b/src/polypcore/sconv-s16le.h new file mode 100644 index 00000000..ef5e31e8 --- /dev/null +++ b/src/polypcore/sconv-s16le.h @@ -0,0 +1,28 @@ +#ifndef foosconv_s16lefoo +#define foosconv_s16lefoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b); +void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b); + +#endif diff --git a/src/polypcore/sconv.c b/src/polypcore/sconv.c new file mode 100644 index 00000000..1fcb5a0c --- /dev/null +++ b/src/polypcore/sconv.c @@ -0,0 +1,168 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +#include "endianmacros.h" +#include "sconv.h" +#include "g711.h" + +#include "sconv-s16le.h" +#include "sconv-s16be.h" + +static void u8_to_float32ne(unsigned n, const void *a, float *b) { + const uint8_t *ca = a; + static const double add = -128.0/127.0, factor = 1.0/127.0; + + assert(a); + assert(b); + + oil_scaleconv_f32_u8(b, ca, n, &add, &factor); +} + +static void u8_from_float32ne(unsigned n, const float *a, void *b) { + uint8_t *cb = b; + static const double add = 128.0, factor = 127.0; + + assert(a); + assert(b); + + oil_scaleconv_u8_f32(cb, a, n, &add, &factor); +} + +static void float32ne_to_float32ne(unsigned n, const void *a, float *b) { + assert(a); + assert(b); + + oil_memcpy(b, a, sizeof(float) * n); +} + +static void float32ne_from_float32ne(unsigned n, const float *a, void *b) { + assert(a); + assert(b); + + oil_memcpy(b, a, sizeof(float) * n); +} + +static void ulaw_to_float32ne(unsigned n, const void *a, float *b) { + const uint8_t *ca = a; + + assert(a); + assert(b); + + for (; n > 0; n--) + *(b++) = st_ulaw2linear16(*(ca++)) * 1.0F / 0x7FFF; +} + +static void ulaw_from_float32ne(unsigned n, const float *a, void *b) { + uint8_t *cb = b; + + assert(a); + assert(b); + + for (; n > 0; n--) { + float v = *(a++); + + if (v > 1) + v = 1; + + if (v < -1) + v = -1; + + *(cb++) = st_14linear2ulaw((int16_t) (v * 0x1FFF)); + } +} + +static void alaw_to_float32ne(unsigned n, const void *a, float *b) { + const uint8_t *ca = a; + + assert(a); + assert(b); + + for (; n > 0; n--) + *(b++) = st_alaw2linear16(*(ca++)) * 1.0F / 0x7FFF; +} + +static void alaw_from_float32ne(unsigned n, const float *a, void *b) { + uint8_t *cb = b; + + assert(a); + assert(b); + + for (; n > 0; n--) { + float v = *(a++); + + if (v > 1) + v = 1; + + if (v < -1) + v = -1; + + *(cb++) = st_13linear2alaw((int16_t) (v * 0xFFF)); + } +} + +pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f) { + switch(f) { + case PA_SAMPLE_U8: + return u8_to_float32ne; + case PA_SAMPLE_S16LE: + return pa_sconv_s16le_to_float32ne; + case PA_SAMPLE_S16BE: + return pa_sconv_s16be_to_float32ne; + case PA_SAMPLE_FLOAT32NE: + return float32ne_to_float32ne; + case PA_SAMPLE_ALAW: + return alaw_to_float32ne; + case PA_SAMPLE_ULAW: + return ulaw_to_float32ne; + default: + return NULL; + } +} + +pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f) { + switch(f) { + case PA_SAMPLE_U8: + return u8_from_float32ne; + case PA_SAMPLE_S16LE: + return pa_sconv_s16le_from_float32ne; + case PA_SAMPLE_S16BE: + return pa_sconv_s16be_from_float32ne; + case PA_SAMPLE_FLOAT32NE: + return float32ne_from_float32ne; + case PA_SAMPLE_ALAW: + return alaw_from_float32ne; + case PA_SAMPLE_ULAW: + return ulaw_from_float32ne; + default: + return NULL; + } +} diff --git a/src/polypcore/sconv.h b/src/polypcore/sconv.h new file mode 100644 index 00000000..a0c15c24 --- /dev/null +++ b/src/polypcore/sconv.h @@ -0,0 +1,33 @@ +#ifndef foosconvhfoo +#define foosconvhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef void (*pa_convert_to_float32ne_func_t)(unsigned n, const void *a, float *b); +typedef void (*pa_convert_from_float32ne_func_t)(unsigned n, const float *a, void *b); + +pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f); +pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f); + +#endif diff --git a/src/polypcore/sink-input.c b/src/polypcore/sink-input.c new file mode 100644 index 00000000..f447b8cf --- /dev/null +++ b/src/polypcore/sink-input.c @@ -0,0 +1,368 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "sink-input.h" +#include "sample-util.h" +#include "xmalloc.h" +#include "subscribe.h" +#include "log.h" + +#define CONVERT_BUFFER_LENGTH 4096 + +pa_sink_input* pa_sink_input_new( + pa_sink *s, + const char *driver, + const char *name, + const pa_sample_spec *spec, + const pa_channel_map *map, + int variable_rate, + int resample_method) { + + pa_sink_input *i; + pa_resampler *resampler = NULL; + int r; + char st[256]; + pa_channel_map tmap; + + assert(s); + assert(spec); + assert(s->state == PA_SINK_RUNNING); + + if (pa_idxset_size(s->inputs) >= PA_MAX_INPUTS_PER_SINK) { + pa_log_warn(__FILE__": Failed to create sink input: too many inputs per sink.\n"); + return NULL; + } + + if (resample_method == PA_RESAMPLER_INVALID) + resample_method = s->core->resample_method; + + if (!map) { + pa_channel_map_init_auto(&tmap, spec->channels); + map = &tmap; + } + + if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec) || !pa_channel_map_equal(map, &s->channel_map)) + if (!(resampler = pa_resampler_new(spec, map, &s->sample_spec, &s->channel_map, s->core->memblock_stat, resample_method))) + return NULL; + + i = pa_xnew(pa_sink_input, 1); + i->ref = 1; + i->state = PA_SINK_INPUT_RUNNING; + i->name = pa_xstrdup(name); + i->driver = pa_xstrdup(driver); + i->owner = NULL; + i->sink = s; + i->client = NULL; + + i->sample_spec = *spec; + i->channel_map = *map; + + pa_cvolume_reset(&i->volume, spec->channels); + + i->peek = NULL; + i->drop = NULL; + i->kill = NULL; + i->get_latency = NULL; + i->underrun = NULL; + i->userdata = NULL; + + i->playing = 0; + + pa_memchunk_reset(&i->resampled_chunk); + i->resampler = resampler; + + assert(s->core); + r = pa_idxset_put(s->core->sink_inputs, i, &i->index); + assert(r == 0 && i->index != PA_IDXSET_INVALID); + r = pa_idxset_put(s->inputs, i, NULL); + assert(r == 0); + + pa_sample_spec_snprint(st, sizeof(st), spec); + pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"\n", i->index, i->name, s->index, st); + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index); + + return i; +} + +void pa_sink_input_disconnect(pa_sink_input *i) { + assert(i); + assert(i->state != PA_SINK_INPUT_DISCONNECTED); + assert(i->sink); + assert(i->sink->core); + + pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); + pa_idxset_remove_by_data(i->sink->inputs, i, NULL); + + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index); + i->sink = NULL; + + i->peek = NULL; + i->drop = NULL; + i->kill = NULL; + i->get_latency = NULL; + i->underrun = NULL; + + i->playing = 0; + i->state = PA_SINK_INPUT_DISCONNECTED; +} + +static void sink_input_free(pa_sink_input* i) { + assert(i); + + if (i->state != PA_SINK_INPUT_DISCONNECTED) + pa_sink_input_disconnect(i); + + pa_log_info(__FILE__": freed %u \"%s\"\n", i->index, i->name); + + if (i->resampled_chunk.memblock) + pa_memblock_unref(i->resampled_chunk.memblock); + + if (i->resampler) + pa_resampler_free(i->resampler); + + pa_xfree(i->name); + pa_xfree(i->driver); + pa_xfree(i); +} + +void pa_sink_input_unref(pa_sink_input *i) { + assert(i); + assert(i->ref >= 1); + + if (!(--i->ref)) + sink_input_free(i); +} + +pa_sink_input* pa_sink_input_ref(pa_sink_input *i) { + assert(i); + assert(i->ref >= 1); + + i->ref++; + return i; +} + +void pa_sink_input_kill(pa_sink_input*i) { + assert(i); + assert(i->ref >= 1); + + if (i->kill) + i->kill(i); +} + +pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) { + pa_usec_t r = 0; + + assert(i); + assert(i->ref >= 1); + + if (i->get_latency) + r += i->get_latency(i); + + if (i->resampled_chunk.memblock) + r += pa_bytes_to_usec(i->resampled_chunk.length, &i->sample_spec); + + return r; +} + +int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) { + int ret = -1; + int do_volume_adj_here; + + assert(i); + assert(i->ref >= 1); + assert(chunk); + assert(volume); + + pa_sink_input_ref(i); + + if (!i->peek || !i->drop || i->state == PA_SINK_INPUT_CORKED) + goto finish; + + if (!i->resampler) { + do_volume_adj_here = 0; + ret = i->peek(i, chunk); + goto finish; + } + + do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map); + + while (!i->resampled_chunk.memblock) { + pa_memchunk tchunk; + size_t l; + + if ((ret = i->peek(i, &tchunk)) < 0) + goto finish; + + assert(tchunk.length); + + l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); + + if (l > tchunk.length) + l = tchunk.length; + + i->drop(i, &tchunk, l); + tchunk.length = l; + + /* It might be necessary to adjust the volume here */ + if (do_volume_adj_here) { + pa_memchunk_make_writable(&tchunk, i->sink->core->memblock_stat, 0); + pa_volume_memchunk(&tchunk, &i->sample_spec, &i->volume); + } + + pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk); + pa_memblock_unref(tchunk.memblock); + } + + assert(i->resampled_chunk.memblock); + assert(i->resampled_chunk.length); + + *chunk = i->resampled_chunk; + pa_memblock_ref(i->resampled_chunk.memblock); + + ret = 0; + +finish: + + if (ret < 0 && i->playing && i->underrun) + i->underrun(i); + + i->playing = ret >= 0; + + if (ret >= 0) { + /* Let's see if we had to apply the volume adjustment + * ourselves, or if this can be done by the sink for us */ + + if (do_volume_adj_here) + /* We've both the same channel map, so let's have the sink do the adjustment for us*/ + + pa_cvolume_reset(volume, i->sample_spec.channels); + else + /* We had different channel maps, so we already did the adjustment */ + *volume = i->volume; + } + + pa_sink_input_unref(i); + + return ret; +} + +void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { + assert(i); + assert(i->ref >= 1); + assert(length > 0); + + if (!i->resampler) { + if (i->drop) + i->drop(i, chunk, length); + return; + } + + assert(i->resampled_chunk.memblock); + assert(i->resampled_chunk.length >= length); + + i->resampled_chunk.index += length; + i->resampled_chunk.length -= length; + + if (i->resampled_chunk.length <= 0) { + pa_memblock_unref(i->resampled_chunk.memblock); + i->resampled_chunk.memblock = NULL; + i->resampled_chunk.index = i->resampled_chunk.length = 0; + } +} + +void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) { + assert(i); + assert(i->ref >= 1); + assert(i->sink); + assert(i->sink->core); + + if (pa_cvolume_equal(&i->volume, volume)) + return; + + i->volume = *volume; + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); +} + +const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i) { + assert(i); + assert(i->ref >= 1); + + return &i->volume; +} + +void pa_sink_input_cork(pa_sink_input *i, int b) { + int n; + + assert(i); + assert(i->ref >= 1); + + if (i->state == PA_SINK_INPUT_DISCONNECTED) + return; + + n = i->state == PA_SINK_INPUT_CORKED && !b; + + i->state = b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING; + + if (n) + pa_sink_notify(i->sink); +} + +void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) { + assert(i); + assert(i->resampler); + assert(i->ref >= 1); + + if (i->sample_spec.rate == rate) + return; + + i->sample_spec.rate = rate; + pa_resampler_set_input_rate(i->resampler, rate); +} + +void pa_sink_input_set_name(pa_sink_input *i, const char *name) { + assert(i); + assert(i->ref >= 1); + + pa_xfree(i->name); + i->name = pa_xstrdup(name); + + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); +} + +pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) { + assert(i); + assert(i->ref >= 1); + + if (!i->resampler) + return PA_RESAMPLER_INVALID; + + return pa_resampler_get_method(i->resampler); +} diff --git a/src/polypcore/sink-input.h b/src/polypcore/sink-input.h new file mode 100644 index 00000000..a5ad1958 --- /dev/null +++ b/src/polypcore/sink-input.h @@ -0,0 +1,106 @@ +#ifndef foosinkinputhfoo +#define foosinkinputhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef struct pa_sink_input pa_sink_input; + +#include "sink.h" +#include +#include "memblockq.h" +#include "resampler.h" +#include "module.h" +#include "client.h" + +typedef enum pa_sink_input_state { + PA_SINK_INPUT_RUNNING, + PA_SINK_INPUT_CORKED, + PA_SINK_INPUT_DISCONNECTED +} pa_sink_input_state_t; + +struct pa_sink_input { + int ref; + uint32_t index; + pa_sink_input_state_t state; + + char *name, *driver; + pa_module *owner; + + pa_sink *sink; + pa_client *client; + + pa_sample_spec sample_spec; + pa_channel_map channel_map; + + pa_cvolume volume; + + int (*peek) (pa_sink_input *i, pa_memchunk *chunk); + void (*drop) (pa_sink_input *i, const pa_memchunk *chunk, size_t length); + void (*kill) (pa_sink_input *i); + pa_usec_t (*get_latency) (pa_sink_input *i); + void (*underrun) (pa_sink_input *i); + + void *userdata; + + int playing; + + pa_memchunk resampled_chunk; + pa_resampler *resampler; +}; + +pa_sink_input* pa_sink_input_new( + pa_sink *s, + const char *driver, + const char *name, + const pa_sample_spec *spec, + const pa_channel_map *map, + int variable_rate, + int resample_method); + +void pa_sink_input_unref(pa_sink_input* i); +pa_sink_input* pa_sink_input_ref(pa_sink_input* i); + +/* To be called by the implementing module only */ +void pa_sink_input_disconnect(pa_sink_input* i); + +/* External code may request disconnection with this funcion */ +void pa_sink_input_kill(pa_sink_input*i); + +pa_usec_t pa_sink_input_get_latency(pa_sink_input *i); + +int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume); +void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length); + +void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume); +const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i); + +void pa_sink_input_cork(pa_sink_input *i, int b); + +void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate); + +void pa_sink_input_set_name(pa_sink_input *i, const char *name); + +pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i); + +#endif diff --git a/src/polypcore/sink.c b/src/polypcore/sink.c new file mode 100644 index 00000000..411befe7 --- /dev/null +++ b/src/polypcore/sink.c @@ -0,0 +1,445 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "sink.h" +#include "sink-input.h" +#include "namereg.h" +#include "util.h" +#include "sample-util.h" +#include "xmalloc.h" +#include "subscribe.h" +#include "log.h" +#include + +#define MAX_MIX_CHANNELS 32 + +pa_sink* pa_sink_new( + pa_core *core, + const char *driver, + const char *name, + int fail, + const pa_sample_spec *spec, + const pa_channel_map *map) { + + pa_sink *s; + char *n = NULL; + char st[256]; + int r; + + assert(core); + assert(name); + assert(*name); + assert(spec); + + s = pa_xnew(pa_sink, 1); + + if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) { + pa_xfree(s); + return NULL; + } + + s->ref = 1; + s->core = core; + s->state = PA_SINK_RUNNING; + s->name = pa_xstrdup(name); + s->description = NULL; + s->driver = pa_xstrdup(driver); + s->owner = NULL; + + s->sample_spec = *spec; + if (map) + s->channel_map = *map; + else + pa_channel_map_init_auto(&s->channel_map, spec->channels); + + s->inputs = pa_idxset_new(NULL, NULL); + + pa_cvolume_reset(&s->sw_volume, spec->channels); + pa_cvolume_reset(&s->hw_volume, spec->channels); + + s->get_latency = NULL; + s->notify = NULL; + s->set_hw_volume = NULL; + s->get_hw_volume = NULL; + s->userdata = NULL; + + r = pa_idxset_put(core->sinks, s, &s->index); + assert(s->index != PA_IDXSET_INVALID && r >= 0); + + pa_sample_spec_snprint(st, sizeof(st), spec); + pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); + + n = pa_sprintf_malloc("%s_monitor", name); + s->monitor_source = pa_source_new(core, driver, n, 0, spec, map); + assert(s->monitor_source); + pa_xfree(n); + s->monitor_source->monitor_of = s; + s->monitor_source->description = pa_sprintf_malloc("Monitor source of sink '%s'", s->name); + + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index); + + return s; +} + +void pa_sink_disconnect(pa_sink* s) { + pa_sink_input *i, *j = NULL; + + assert(s); + assert(s->state == PA_SINK_RUNNING); + + pa_namereg_unregister(s->core, s->name); + + while ((i = pa_idxset_first(s->inputs, NULL))) { + assert(i != j); + pa_sink_input_kill(i); + j = i; + } + + pa_source_disconnect(s->monitor_source); + + pa_idxset_remove_by_data(s->core->sinks, s, NULL); + + s->get_latency = NULL; + s->notify = NULL; + s->get_hw_volume = NULL; + s->set_hw_volume = NULL; + + s->state = PA_SINK_DISCONNECTED; + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); +} + +static void sink_free(pa_sink *s) { + assert(s); + assert(!s->ref); + + if (s->state != PA_SINK_DISCONNECTED) + pa_sink_disconnect(s); + + pa_log_info(__FILE__": freed %u \"%s\"\n", s->index, s->name); + + pa_source_unref(s->monitor_source); + s->monitor_source = NULL; + + pa_idxset_free(s->inputs, NULL, NULL); + + pa_xfree(s->name); + pa_xfree(s->description); + pa_xfree(s->driver); + pa_xfree(s); +} + +void pa_sink_unref(pa_sink*s) { + assert(s); + assert(s->ref >= 1); + + if (!(--s->ref)) + sink_free(s); +} + +pa_sink* pa_sink_ref(pa_sink *s) { + assert(s); + assert(s->ref >= 1); + + s->ref++; + return s; +} + +void pa_sink_notify(pa_sink*s) { + assert(s); + assert(s->ref >= 1); + + if (s->notify) + s->notify(s); +} + +static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) { + uint32_t idx = PA_IDXSET_INVALID; + pa_sink_input *i; + unsigned n = 0; + + assert(s); + assert(s->ref >= 1); + assert(info); + + for (i = pa_idxset_first(s->inputs, &idx); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &idx)) { + /* Increase ref counter, to make sure that this input doesn't + * vanish while we still need it */ + pa_sink_input_ref(i); + + if (pa_sink_input_peek(i, &info->chunk, &info->volume) < 0) { + pa_sink_input_unref(i); + continue; + } + + info->userdata = i; + + assert(info->chunk.memblock); + assert(info->chunk.memblock->data); + assert(info->chunk.length); + + info++; + maxinfo--; + n++; + } + + return n; +} + +static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned maxinfo, size_t length) { + assert(s); + assert(s->ref >= 1); + assert(info); + + for (; maxinfo > 0; maxinfo--, info++) { + pa_sink_input *i = info->userdata; + + assert(i); + assert(info->chunk.memblock); + + /* Drop read data */ + pa_sink_input_drop(i, &info->chunk, length); + pa_memblock_unref(info->chunk.memblock); + + /* Decrease ref counter */ + pa_sink_input_unref(i); + info->userdata = NULL; + } +} + +int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { + pa_mix_info info[MAX_MIX_CHANNELS]; + unsigned n; + int r = -1; + + assert(s); + assert(s->ref >= 1); + assert(length); + assert(result); + + pa_sink_ref(s); + + n = fill_mix_info(s, info, MAX_MIX_CHANNELS); + + if (n <= 0) + goto finish; + + if (n == 1) { + pa_cvolume volume; + + *result = info[0].chunk; + pa_memblock_ref(result->memblock); + + if (result->length > length) + result->length = length; + + pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); + + if (!pa_cvolume_is_norm(&volume)) { + pa_memchunk_make_writable(result, s->core->memblock_stat, 0); + pa_volume_memchunk(result, &s->sample_spec, &volume); + } + } else { + result->memblock = pa_memblock_new(length, s->core->memblock_stat); + assert(result->memblock); + + result->length = pa_mix(info, n, result->memblock->data, length, &s->sample_spec, &s->sw_volume); + result->index = 0; + } + + inputs_drop(s, info, n, result->length); + pa_source_post(s->monitor_source, result); + + r = 0; + +finish: + pa_sink_unref(s); + + return r; +} + +int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { + pa_mix_info info[MAX_MIX_CHANNELS]; + unsigned n; + int r = -1; + + assert(s); + assert(s->ref >= 1); + assert(target); + assert(target->memblock); + assert(target->length); + assert(target->memblock->data); + + pa_sink_ref(s); + + n = fill_mix_info(s, info, MAX_MIX_CHANNELS); + + if (n <= 0) + goto finish; + + if (n == 1) { + pa_cvolume volume; + + if (target->length > info[0].chunk.length) + target->length = info[0].chunk.length; + + memcpy((uint8_t*) target->memblock->data + target->index, + (uint8_t*) info[0].chunk.memblock->data + info[0].chunk.index, + target->length); + + pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); + + if (!pa_cvolume_is_norm(&volume)) + pa_volume_memchunk(target, &s->sample_spec, &volume); + } else + target->length = pa_mix(info, n, + (uint8_t*) target->memblock->data + target->index, + target->length, + &s->sample_spec, + &s->sw_volume); + + inputs_drop(s, info, n, target->length); + pa_source_post(s->monitor_source, target); + + r = 0; + +finish: + pa_sink_unref(s); + + return r; +} + +void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { + pa_memchunk chunk; + size_t l, d; + + assert(s); + assert(s->ref >= 1); + assert(target); + assert(target->memblock); + assert(target->length); + assert(target->memblock->data); + + pa_sink_ref(s); + + l = target->length; + d = 0; + while (l > 0) { + chunk = *target; + chunk.index += d; + chunk.length -= d; + + if (pa_sink_render_into(s, &chunk) < 0) + break; + + d += chunk.length; + l -= chunk.length; + } + + if (l > 0) { + chunk = *target; + chunk.index += d; + chunk.length -= d; + pa_silence_memchunk(&chunk, &s->sample_spec); + } + + pa_sink_unref(s); +} + +void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { + assert(s); + assert(s->ref >= 1); + assert(length); + assert(result); + + /*** This needs optimization ***/ + + result->memblock = pa_memblock_new(result->length = length, s->core->memblock_stat); + result->index = 0; + + pa_sink_render_into_full(s, result); +} + +pa_usec_t pa_sink_get_latency(pa_sink *s) { + assert(s); + assert(s->ref >= 1); + + if (!s->get_latency) + return 0; + + return s->get_latency(s); +} + +void pa_sink_set_owner(pa_sink *s, pa_module *m) { + assert(s); + assert(s->ref >= 1); + + s->owner = m; + + if (s->monitor_source) + pa_source_set_owner(s->monitor_source, m); +} + +void pa_sink_set_volume(pa_sink *s, pa_mixer_t m, const pa_cvolume *volume) { + pa_cvolume *v; + + assert(s); + assert(s->ref >= 1); + assert(volume); + + if (m == PA_MIXER_HARDWARE && s->set_hw_volume) + v = &s->hw_volume; + else + v = &s->sw_volume; + + if (pa_cvolume_equal(v, volume)) + return; + + *v = *volume; + + if (v == &s->hw_volume) + if (s->set_hw_volume(s) < 0) + s->sw_volume = *volume; + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); +} + +const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_mixer_t m) { + assert(s); + assert(s->ref >= 1); + + if (m == PA_MIXER_HARDWARE && s->set_hw_volume) { + + if (s->get_hw_volume) + s->get_hw_volume(s); + + return &s->hw_volume; + } else + return &s->sw_volume; +} diff --git a/src/polypcore/sink.h b/src/polypcore/sink.h new file mode 100644 index 00000000..268461ef --- /dev/null +++ b/src/polypcore/sink.h @@ -0,0 +1,100 @@ +#ifndef foosinkhfoo +#define foosinkhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef struct pa_sink pa_sink; + +#include "core.h" +#include +#include "idxset.h" +#include "source.h" +#include +#include "module.h" +#include + +#define PA_MAX_INPUTS_PER_SINK 6 + +typedef enum pa_sink_state { + PA_SINK_RUNNING, + PA_SINK_DISCONNECTED +} pa_sink_state_t; + +typedef enum pa_mixer { + PA_MIXER_SOFTWARE, + PA_MIXER_HARDWARE +} pa_mixer_t; + +struct pa_sink { + int ref; + uint32_t index; + pa_core *core; + pa_sink_state_t state; + + char *name, *description, *driver; + pa_module *owner; + + pa_sample_spec sample_spec; + pa_channel_map channel_map; + + pa_idxset *inputs; + pa_source *monitor_source; + + pa_cvolume hw_volume, sw_volume; + + void (*notify)(pa_sink*sink); + pa_usec_t (*get_latency)(pa_sink *s); + int (*set_hw_volume)(pa_sink *s); + int (*get_hw_volume)(pa_sink *s); + + void *userdata; +}; + +pa_sink* pa_sink_new( + pa_core *core, + const char *driver, + const char *name, + int namereg_fail, + const pa_sample_spec *spec, + const pa_channel_map *map); + +void pa_sink_disconnect(pa_sink* s); +void pa_sink_unref(pa_sink*s); +pa_sink* pa_sink_ref(pa_sink *s); + +int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result); +void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result); +int pa_sink_render_into(pa_sink*s, pa_memchunk *target); +void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target); + +pa_usec_t pa_sink_get_latency(pa_sink *s); + +void pa_sink_notify(pa_sink*s); + +void pa_sink_set_owner(pa_sink *sink, pa_module *m); + +void pa_sink_set_volume(pa_sink *sink, pa_mixer_t m, const pa_cvolume *volume); +const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_mixer_t m); + +#endif diff --git a/src/polypcore/sioman.c b/src/polypcore/sioman.c new file mode 100644 index 00000000..8d7b136c --- /dev/null +++ b/src/polypcore/sioman.c @@ -0,0 +1,42 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#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/polypcore/sioman.h b/src/polypcore/sioman.h new file mode 100644 index 00000000..840d93f2 --- /dev/null +++ b/src/polypcore/sioman.h @@ -0,0 +1,28 @@ +#ifndef foosiomanhfoo +#define foosiomanhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +int pa_stdio_acquire(void); +void pa_stdio_release(void); + +#endif diff --git a/src/polypcore/socket-client.c b/src/polypcore/socket-client.c new file mode 100644 index 00000000..29c9775e --- /dev/null +++ b/src/polypcore/socket-client.c @@ -0,0 +1,513 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/* #undef HAVE_LIBASYNCNS */ + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_LIBASYNCNS +#include +#endif + +#include "winsock.h" + +#include "socket-client.h" +#include "socket-util.h" +#include "util.h" +#include "xmalloc.h" +#include "log.h" +#include "parseaddr.h" + +#define CONNECT_TIMEOUT 5 + +struct pa_socket_client { + int ref; + pa_mainloop_api *mainloop; + int fd; + pa_io_event *io_event; + pa_time_event *timeout_event; + pa_defer_event *defer_event; + void (*callback)(pa_socket_client*c, pa_iochannel *io, void *userdata); + void *userdata; + int local; +#ifdef HAVE_LIBASYNCNS + asyncns_t *asyncns; + asyncns_query_t * asyncns_query; + pa_io_event *asyncns_io_event; +#endif +}; + +static pa_socket_client*pa_socket_client_new(pa_mainloop_api *m) { + pa_socket_client *c; + assert(m); + + c = pa_xmalloc(sizeof(pa_socket_client)); + c->ref = 1; + c->mainloop = m; + c->fd = -1; + c->io_event = NULL; + c->defer_event = NULL; + c->timeout_event = NULL; + c->callback = NULL; + c->userdata = NULL; + c->local = 0; + +#ifdef HAVE_LIBASYNCNS + c->asyncns = NULL; + c->asyncns_io_event = NULL; + c->asyncns_query = NULL; +#endif + + return c; +} + +static void free_events(pa_socket_client *c) { + assert(c); + + if (c->io_event) { + c->mainloop->io_free(c->io_event); + c->io_event = NULL; + } + + if (c->defer_event) { + c->mainloop->defer_free(c->defer_event); + c->defer_event = NULL; + } + + if (c->timeout_event) { + c->mainloop->time_free(c->timeout_event); + c->timeout_event = NULL; + } +} + +static void do_call(pa_socket_client *c) { + pa_iochannel *io = NULL; + int error; + socklen_t lerror; + assert(c && c->callback); + + pa_socket_client_ref(c); + + if (c->fd < 0) + goto finish; + + lerror = sizeof(error); + if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &lerror) < 0) { + pa_log(__FILE__": getsockopt(): %s\n", strerror(errno)); + goto finish; + } + + if (lerror != sizeof(error)) { + pa_log(__FILE__": getsockopt() returned invalid size.\n"); + goto finish; + } + + if (error != 0) { + pa_log_debug(__FILE__": connect(): %s\n", strerror(error)); + errno = error; + goto finish; + } + + io = pa_iochannel_new(c->mainloop, c->fd, c->fd); + assert(io); + +finish: + if (!io && c->fd >= 0) + close(c->fd); + c->fd = -1; + + free_events(c); + + assert(c->callback); + c->callback(c, io, c->userdata); + + pa_socket_client_unref(c); +} + +static void connect_fixed_cb(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { + pa_socket_client *c = userdata; + assert(m && c && c->defer_event == e); + do_call(c); +} + +static void connect_io_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { + pa_socket_client *c = userdata; + assert(m && c && c->io_event == e && fd >= 0); + do_call(c); +} + +static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t len) { + int r; + assert(c && sa && len); + + pa_make_nonblock_fd(c->fd); + + if ((r = connect(c->fd, sa, len)) < 0) { + if (errno != EINPROGRESS) { + /*pa_log(__FILE__": connect(): %s\n", strerror(errno));*/ + return -1; + } + + c->io_event = c->mainloop->io_new(c->mainloop, c->fd, PA_IO_EVENT_OUTPUT, connect_io_cb, c); + assert(c->io_event); + } else { + c->defer_event = c->mainloop->defer_new(c->mainloop, connect_fixed_cb, c); + assert(c->defer_event); + } + + return 0; +} + +pa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port) { + struct sockaddr_in sa; + assert(m && port > 0); + + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(port); + sa.sin_addr.s_addr = htonl(address); + + return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); +} + +#ifdef HAVE_SYS_UN_H + +pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) { + struct sockaddr_un sa; + assert(m && filename); + + memset(&sa, 0, sizeof(sa)); + sa.sun_family = AF_UNIX; + strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); + sa.sun_path[sizeof(sa.sun_path) - 1] = 0; + + return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); +} + +#else /* HAVE_SYS_UN_H */ + +pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) { + return NULL; +} + +#endif /* HAVE_SYS_UN_H */ + +static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size_t salen) { + assert(c); + assert(sa); + assert(salen); + + switch (sa->sa_family) { + case AF_UNIX: + c->local = 1; + break; + + case AF_INET: + c->local = ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK; + break; + + case AF_INET6: + c->local = memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0; + break; + + default: + c->local = 0; + } + + if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) { + pa_log(__FILE__": socket(): %s\n", strerror(errno)); + return -1; + } + + pa_fd_set_cloexec(c->fd, 1); + if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) + pa_socket_tcp_low_delay(c->fd); + else + pa_socket_low_delay(c->fd); + + if (do_connect(c, sa, salen) < 0) + return -1; + + return 0; +} + +pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) { + pa_socket_client *c; + assert(m && sa); + c = pa_socket_client_new(m); + assert(c); + + if (sockaddr_prepare(c, sa, salen) < 0) + goto fail; + + return c; + +fail: + pa_socket_client_unref(c); + return NULL; + +} + +static void socket_client_free(pa_socket_client *c) { + assert(c && c->mainloop); + + + free_events(c); + + if (c->fd >= 0) + close(c->fd); + +#ifdef HAVE_LIBASYNCNS + if (c->asyncns_query) + asyncns_cancel(c->asyncns, c->asyncns_query); + if (c->asyncns) + asyncns_free(c->asyncns); + if (c->asyncns_io_event) + c->mainloop->io_free(c->asyncns_io_event); +#endif + + pa_xfree(c); +} + +void pa_socket_client_unref(pa_socket_client *c) { + assert(c && c->ref >= 1); + + if (!(--(c->ref))) + socket_client_free(c); +} + +pa_socket_client* pa_socket_client_ref(pa_socket_client *c) { + assert(c && c->ref >= 1); + c->ref++; + return c; +} + +void pa_socket_client_set_callback(pa_socket_client *c, void (*on_connection)(pa_socket_client *c, pa_iochannel*io, void *userdata), void *userdata) { + assert(c); + c->callback = on_connection; + c->userdata = userdata; +} + +pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[16], uint16_t port) { + struct sockaddr_in6 sa; + + memset(&sa, 0, sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons(port); + memcpy(&sa.sin6_addr, address, sizeof(sa.sin6_addr)); + + return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); +} + +#ifdef HAVE_LIBASYNCNS + +static void asyncns_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { + pa_socket_client *c = userdata; + struct addrinfo *res = NULL; + int ret; + assert(m && c && c->asyncns_io_event == e && fd >= 0); + + if (asyncns_wait(c->asyncns, 0) < 0) + goto fail; + + if (!asyncns_isdone(c->asyncns, c->asyncns_query)) + return; + + ret = asyncns_getaddrinfo_done(c->asyncns, c->asyncns_query, &res); + c->asyncns_query = NULL; + + if (ret != 0 || !res) + goto fail; + + if (res->ai_addr) + sockaddr_prepare(c, res->ai_addr, res->ai_addrlen); + + asyncns_freeaddrinfo(res); + + goto finish; + +fail: + errno == EHOSTUNREACH; + do_call(c); + +finish: + + m->io_free(c->asyncns_io_event); + c->asyncns_io_event = NULL; +} + +#endif + +static void timeout_cb(pa_mainloop_api *m, pa_time_event *e, const struct timeval *tv, void *userdata) { + pa_socket_client *c = userdata; + assert(m); + assert(e); + assert(tv); + assert(c); + + if (c->fd >= 0) { + close(c->fd); + c->fd = -1; + } + + errno = ETIMEDOUT; + do_call(c); +} + +static void start_timeout(pa_socket_client *c) { + struct timeval tv; + assert(c); + assert(!c->timeout_event); + + pa_gettimeofday(&tv); + pa_timeval_add(&tv, CONNECT_TIMEOUT * 1000000); + c->timeout_event = c->mainloop->time_new(c->mainloop, &tv, timeout_cb, c); +} + +pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*name, uint16_t default_port) { + pa_socket_client *c = NULL; + pa_parsed_address a; + assert(m && name); + + if (pa_parse_address(name, &a) < 0) + return NULL; + + if (!a.port) + a.port = default_port; + + switch (a.type) { + case PA_PARSED_ADDRESS_UNIX: + if ((c = pa_socket_client_new_unix(m, a.path_or_host))) + start_timeout(c); + break; + + case PA_PARSED_ADDRESS_TCP4: /* Fallthrough */ + case PA_PARSED_ADDRESS_TCP6: /* Fallthrough */ + case PA_PARSED_ADDRESS_TCP_AUTO:{ + + struct addrinfo hints; + char port[12]; + + snprintf(port, sizeof(port), "%u", (unsigned) a.port); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = a.type == PA_PARSED_ADDRESS_TCP4 ? PF_INET : (a.type == PA_PARSED_ADDRESS_TCP6 ? PF_INET6 : PF_UNSPEC); + hints.ai_socktype = SOCK_STREAM; + +#ifdef HAVE_LIBASYNCNS + { + asyncns_t *asyncns; + + if (!(asyncns = asyncns_new(1))) + goto finish; + + c = pa_socket_client_new(m); + c->asyncns = asyncns; + c->asyncns_io_event = m->io_new(m, asyncns_fd(c->asyncns), PA_IO_EVENT_INPUT, asyncns_cb, c); + c->asyncns_query = asyncns_getaddrinfo(c->asyncns, a.path_or_host, port, &hints); + assert(c->asyncns_query); + start_timeout(c); + } +#else /* HAVE_LIBASYNCNS */ + { +#ifdef HAVE_GETADDRINFO + int ret; + struct addrinfo *res = NULL; + + ret = getaddrinfo(a.path_or_host, port, &hints, &res); + + if (ret < 0 || !res) + goto finish; + + if (res->ai_addr) { + if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen))) + start_timeout(c); + } + + freeaddrinfo(res); +#else /* HAVE_GETADDRINFO */ + struct hostent *host = NULL; + struct sockaddr_in s; + + /* FIXME: PF_INET6 support */ + if (hints.ai_family != PF_INET) + goto finish; + + host = gethostbyname(a.path_or_host); + if (!host) { + unsigned int addr = inet_addr(a.path_or_host); + if (addr != INADDR_NONE) + host = gethostbyaddr((char*)&addr, 4, AF_INET); + } + + if (!host) + goto finish; + + s.sin_family = AF_INET; + memcpy(&s.sin_addr, host->h_addr, sizeof(struct in_addr)); + s.sin_port = port; + + if ((c = pa_socket_client_new_sockaddr(m, &s, sizeof(s)))) + start_timeout(c); +#endif /* HAVE_GETADDRINFO */ + } +#endif /* HAVE_LIBASYNCNS */ + } + } + +finish: + pa_xfree(a.path_or_host); + return c; + +} + +/* Return non-zero when the target sockaddr is considered + local. "local" means UNIX socket or TCP socket on localhost. Other + local IP addresses are not considered local. */ +int pa_socket_client_is_local(pa_socket_client *c) { + assert(c); + return c->local; +} diff --git a/src/polypcore/socket-client.h b/src/polypcore/socket-client.h new file mode 100644 index 00000000..624880d7 --- /dev/null +++ b/src/polypcore/socket-client.h @@ -0,0 +1,47 @@ +#ifndef foosocketclienthfoo +#define foosocketclienthfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include "iochannel.h" + +struct sockaddr; + +typedef struct pa_socket_client pa_socket_client; + +pa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port); +pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[16], uint16_t port); +pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename); +pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen); +pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char *a, uint16_t default_port); + +void pa_socket_client_unref(pa_socket_client *c); +pa_socket_client* pa_socket_client_ref(pa_socket_client *c); + +void pa_socket_client_set_callback(pa_socket_client *c, void (*on_connection)(pa_socket_client *c, pa_iochannel*io, void *userdata), void *userdata); + +int pa_socket_client_is_local(pa_socket_client *c); + +#endif diff --git a/src/polypcore/socket-server.c b/src/polypcore/socket-server.c new file mode 100644 index 00000000..262b32a7 --- /dev/null +++ b/src/polypcore/socket-server.c @@ -0,0 +1,432 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#ifndef SUN_LEN +#define SUN_LEN(ptr) \ + ((size_t)(((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path)) +#endif +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_LIBWRAP +#include +#endif + +#ifndef HAVE_INET_NTOP +#include "inet_ntop.h" +#endif + +#include "winsock.h" + +#include "socket-server.h" +#include "socket-util.h" +#include "xmalloc.h" +#include "util.h" +#include "log.h" + +struct pa_socket_server { + int ref; + int fd; + char *filename; + char *tcpwrap_service; + + void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata); + void *userdata; + + pa_io_event *io_event; + pa_mainloop_api *mainloop; + enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX, SOCKET_SERVER_IPV6 } type; +}; + +static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { + pa_socket_server *s = userdata; + pa_iochannel *io; + int nfd; + assert(s && s->mainloop == mainloop && s->io_event == e && e && fd >= 0 && fd == s->fd); + + pa_socket_server_ref(s); + + if ((nfd = accept(fd, NULL, NULL)) < 0) { + pa_log(__FILE__": accept(): %s\n", strerror(errno)); + goto finish; + } + + pa_fd_set_cloexec(nfd, 1); + + if (!s->on_connection) { + close(nfd); + goto finish; + } + +#ifdef HAVE_LIBWRAP + + if (s->type == SOCKET_SERVER_IPV4 && s->tcpwrap_service) { + struct request_info req; + + request_init(&req, RQ_DAEMON, s->tcpwrap_service, RQ_FILE, nfd, NULL); + fromhost(&req); + if (!hosts_access(&req)) { + pa_log(__FILE__": TCP connection refused by tcpwrap.\n"); + close(nfd); + goto finish; + } + + pa_log(__FILE__": TCP connection accepted by tcpwrap.\n"); + } +#endif + + /* There should be a check for socket type here */ + if (s->type == SOCKET_SERVER_IPV4) + pa_socket_tcp_low_delay(fd); + else + pa_socket_low_delay(fd); + + io = pa_iochannel_new(s->mainloop, nfd, nfd); + assert(io); + s->on_connection(s, io, s->userdata); + +finish: + pa_socket_server_unref(s); +} + +pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) { + pa_socket_server *s; + assert(m && fd >= 0); + + s = pa_xmalloc(sizeof(pa_socket_server)); + s->ref = 1; + s->fd = fd; + s->filename = NULL; + s->on_connection = NULL; + s->userdata = NULL; + s->tcpwrap_service = NULL; + + s->mainloop = m; + s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s); + assert(s->io_event); + + s->type = SOCKET_SERVER_GENERIC; + + return s; +} + +pa_socket_server* pa_socket_server_ref(pa_socket_server *s) { + assert(s && s->ref >= 1); + s->ref++; + return s; +} + +#ifdef HAVE_SYS_UN_H + +pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) { + int fd = -1; + struct sockaddr_un sa; + pa_socket_server *s; + + assert(m && filename); + + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + pa_log(__FILE__": socket(): %s\n", strerror(errno)); + goto fail; + } + + pa_fd_set_cloexec(fd, 1); + + sa.sun_family = AF_UNIX; + strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); + sa.sun_path[sizeof(sa.sun_path) - 1] = 0; + + pa_socket_low_delay(fd); + + if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) { + pa_log(__FILE__": bind(): %s\n", strerror(errno)); + goto fail; + } + + if (listen(fd, 5) < 0) { + pa_log(__FILE__": listen(): %s\n", strerror(errno)); + goto fail; + } + + s = pa_socket_server_new(m, fd); + assert(s); + + s->filename = pa_xstrdup(filename); + s->type = SOCKET_SERVER_UNIX; + + return s; + +fail: + if (fd >= 0) + close(fd); + + return NULL; +} + +#else /* HAVE_SYS_UN_H */ + +pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) { + return NULL; +} + +#endif /* HAVE_SYS_UN_H */ + +pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service) { + pa_socket_server *ss; + int fd = -1; + struct sockaddr_in sa; + int on = 1; + + assert(m && port); + + if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { + pa_log(__FILE__": socket(): %s\n", strerror(errno)); + goto fail; + } + + pa_fd_set_cloexec(fd, 1); + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0) + pa_log(__FILE__": setsockopt(): %s\n", strerror(errno)); + + pa_socket_tcp_low_delay(fd); + + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(port); + sa.sin_addr.s_addr = htonl(address); + + if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { + pa_log(__FILE__": bind(): %s\n", strerror(errno)); + goto fail; + } + + if (listen(fd, 5) < 0) { + pa_log(__FILE__": listen(): %s\n", strerror(errno)); + goto fail; + } + + if ((ss = pa_socket_server_new(m, fd))) { + ss->type = SOCKET_SERVER_IPV4; + ss->tcpwrap_service = pa_xstrdup(tcpwrap_service); + } + + return ss; + +fail: + if (fd >= 0) + close(fd); + + return NULL; +} + +pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port) { + pa_socket_server *ss; + int fd = -1; + struct sockaddr_in6 sa; + int on = 1; + + assert(m && port); + + if ((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) { + pa_log(__FILE__": socket(): %s\n", strerror(errno)); + goto fail; + } + + pa_fd_set_cloexec(fd, 1); + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0) + pa_log(__FILE__": setsockopt(): %s\n", strerror(errno)); + + pa_socket_tcp_low_delay(fd); + + memset(&sa, 0, sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons(port); + memcpy(sa.sin6_addr.s6_addr, address, 16); + + if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { + pa_log(__FILE__": bind(): %s\n", strerror(errno)); + goto fail; + } + + if (listen(fd, 5) < 0) { + pa_log(__FILE__": listen(): %s\n", strerror(errno)); + goto fail; + } + + if ((ss = pa_socket_server_new(m, fd))) + ss->type = SOCKET_SERVER_IPV6; + + return ss; + +fail: + if (fd >= 0) + close(fd); + + return NULL; +} + +static void socket_server_free(pa_socket_server*s) { + assert(s); + close(s->fd); + + if (s->filename) { + unlink(s->filename); + pa_xfree(s->filename); + } + + pa_xfree(s->tcpwrap_service); + + s->mainloop->io_free(s->io_event); + pa_xfree(s); +} + +void pa_socket_server_unref(pa_socket_server *s) { + assert(s && s->ref >= 1); + + if (!(--(s->ref))) + socket_server_free(s); +} + +void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata), void *userdata) { + assert(s && s->ref >= 1); + + s->on_connection = on_connection; + s->userdata = userdata; +} + + +char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { + assert(s && c && l > 0); + + switch (s->type) { + case SOCKET_SERVER_IPV6: { + struct sockaddr_in6 sa; + socklen_t sa_len = sizeof(sa); + + if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) { + pa_log(__FILE__": getsockname() failed: %s\n", strerror(errno)); + return NULL; + } + + if (memcmp(&in6addr_any, &sa.sin6_addr, sizeof(in6addr_any)) == 0) { + char fqdn[256]; + if (!pa_get_fqdn(fqdn, sizeof(fqdn))) + return NULL; + + snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port)); + + } else if (memcmp(&in6addr_loopback, &sa.sin6_addr, sizeof(in6addr_loopback)) == 0) { + char hn[256]; + if (!pa_get_host_name(hn, sizeof(hn))) + return NULL; + + snprintf(c, l, "{%s}tcp6:localhost:%u", hn, (unsigned) ntohs(sa.sin6_port)); + } else { + char ip[INET6_ADDRSTRLEN]; + + if (!inet_ntop(AF_INET6, &sa.sin6_addr, ip, sizeof(ip))) { + pa_log(__FILE__": inet_ntop() failed: %s\n", strerror(errno)); + return NULL; + } + + snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port)); + } + + return c; + } + + case SOCKET_SERVER_IPV4: { + struct sockaddr_in sa; + socklen_t sa_len = sizeof(sa); + + if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) { + pa_log(__FILE__": getsockname() failed: %s\n", strerror(errno)); + return NULL; + } + + if (sa.sin_addr.s_addr == INADDR_ANY) { + char fqdn[256]; + if (!pa_get_fqdn(fqdn, sizeof(fqdn))) + return NULL; + + snprintf(c, l, "tcp:%s:%u", fqdn, (unsigned) ntohs(sa.sin_port)); + } else if (sa.sin_addr.s_addr == INADDR_LOOPBACK) { + char hn[256]; + if (!pa_get_host_name(hn, sizeof(hn))) + return NULL; + + snprintf(c, l, "{%s}tcp:localhost:%u", hn, (unsigned) ntohs(sa.sin_port)); + } else { + char ip[INET_ADDRSTRLEN]; + + if (!inet_ntop(AF_INET, &sa.sin_addr, ip, sizeof(ip))) { + pa_log(__FILE__": inet_ntop() failed: %s\n", strerror(errno)); + return NULL; + } + + snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port)); + + } + + return c; + } + + case SOCKET_SERVER_UNIX: { + char hn[256]; + + if (!s->filename) + return NULL; + + if (!pa_get_host_name(hn, sizeof(hn))) + return NULL; + + snprintf(c, l, "{%s}unix:%s", hn, s->filename); + return c; + } + + default: + return NULL; + } +} diff --git a/src/polypcore/socket-server.h b/src/polypcore/socket-server.h new file mode 100644 index 00000000..4d8bfad5 --- /dev/null +++ b/src/polypcore/socket-server.h @@ -0,0 +1,45 @@ +#ifndef foosocketserverhfoo +#define foosocketserverhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include "iochannel.h" + +/* It is safe to destroy the calling socket_server object from the callback */ + +typedef struct pa_socket_server pa_socket_server; + +pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd); +pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename); +pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port); + +void pa_socket_server_unref(pa_socket_server*s); +pa_socket_server* pa_socket_server_ref(pa_socket_server *s); + +void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata), void *userdata); + +char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l); + +#endif diff --git a/src/polypcore/socket-util.c b/src/polypcore/socket-util.c new file mode 100644 index 00000000..032a3c91 --- /dev/null +++ b/src/polypcore/socket-util.c @@ -0,0 +1,246 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN_SYSTM_H +#include +#endif +#ifdef HAVE_NETINET_IP_H +#include +#endif +#ifdef HAVE_NETINET_TCP_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif + +#include "winsock.h" + +#include "socket-util.h" +#include "util.h" +#include "xmalloc.h" +#include "log.h" + +void pa_socket_peer_to_string(int fd, char *c, size_t l) { + struct stat st; + + assert(c && l && fd >= 0); + +#ifndef OS_IS_WIN32 + if (fstat(fd, &st) < 0) { + snprintf(c, l, "Invalid client fd"); + return; + } +#endif + +#ifndef OS_IS_WIN32 + if (S_ISSOCK(st.st_mode)) { +#endif + union { + struct sockaddr sa; + struct sockaddr_in in; +#ifdef HAVE_SYS_UN_H + struct sockaddr_un un; +#endif + } sa; + socklen_t sa_len = sizeof(sa); + + if (getpeername(fd, &sa.sa, &sa_len) >= 0) { + + if (sa.sa.sa_family == AF_INET) { + uint32_t ip = ntohl(sa.in.sin_addr.s_addr); + + snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u", + ip >> 24, + (ip >> 16) & 0xFF, + (ip >> 8) & 0xFF, + ip & 0xFF, + ntohs(sa.in.sin_port)); + return; +#ifdef HAVE_SYS_UN_H + } else if (sa.sa.sa_family == AF_UNIX) { + snprintf(c, l, "UNIX socket client"); + return; +#endif + } + + } +#ifndef OS_IS_WIN32 + snprintf(c, l, "Unknown network client"); + return; + } else if (S_ISCHR(st.st_mode) && (fd == 0 || fd == 1)) { + snprintf(c, l, "STDIN/STDOUT client"); + return; + } +#endif /* OS_IS_WIN32 */ + + snprintf(c, l, "Unknown client"); +} + +int pa_socket_low_delay(int fd) { +#ifdef SO_PRIORITY + int priority; + assert(fd >= 0); + + priority = 7; + if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (void*)&priority, sizeof(priority)) < 0) + return -1; +#endif + + return 0; +} + +int pa_socket_tcp_low_delay(int fd) { + int ret, tos, on; + + assert(fd >= 0); + + ret = pa_socket_low_delay(fd); + + on = 1; + tos = 0; + +#if defined(SOL_TCP) || defined(IPPROTO_TCP) +#if defined(SOL_TCP) + if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0) +#else + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0) +#endif + ret = -1; +#endif + +#if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || \ + defined(IPPROTO_IP)) + tos = IPTOS_LOWDELAY; +#ifdef SOL_IP + if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) +#else + if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) +#endif + ret = -1; +#endif + + return ret; + +} + +int pa_socket_set_rcvbuf(int fd, size_t l) { + assert(fd >= 0); + +/* if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&l, sizeof(l)) < 0) { */ +/* pa_log(__FILE__": SO_RCVBUF: %s\n", strerror(errno)); */ +/* return -1; */ +/* } */ + + return 0; +} + +int pa_socket_set_sndbuf(int fd, size_t l) { + assert(fd >= 0); + +/* if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&l, sizeof(l)) < 0) { */ +/* pa_log(__FILE__": SO_SNDBUF: %s\n", strerror(errno)); */ +/* return -1; */ +/* } */ + + return 0; +} + +#ifdef HAVE_SYS_UN_H + +int pa_unix_socket_is_stale(const char *fn) { + struct sockaddr_un sa; + int fd = -1, ret = -1; + + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + pa_log(__FILE__": socket(): %s\n", strerror(errno)); + goto finish; + } + + sa.sun_family = AF_UNIX; + strncpy(sa.sun_path, fn, sizeof(sa.sun_path)-1); + sa.sun_path[sizeof(sa.sun_path) - 1] = 0; + + if (connect(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) { + if (errno == ECONNREFUSED) + ret = 1; + } else + ret = 0; + +finish: + if (fd >= 0) + close(fd); + + return ret; +} + +int pa_unix_socket_remove_stale(const char *fn) { + int r; + + if ((r = pa_unix_socket_is_stale(fn)) < 0) + return errno != ENOENT ? -1 : 0; + + if (!r) + return 0; + + /* Yes, here is a race condition. But who cares? */ + if (unlink(fn) < 0) + return -1; + + return 0; +} + +#else /* HAVE_SYS_UN_H */ + +int pa_unix_socket_is_stale(const char *fn) { + return -1; +} + +int pa_unix_socket_remove_stale(const char *fn) { + return -1; +} + +#endif /* HAVE_SYS_UN_H */ diff --git a/src/polypcore/socket-util.h b/src/polypcore/socket-util.h new file mode 100644 index 00000000..ae16fb16 --- /dev/null +++ b/src/polypcore/socket-util.h @@ -0,0 +1,38 @@ +#ifndef foosocketutilhfoo +#define foosocketutilhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +void pa_socket_peer_to_string(int fd, char *c, size_t l); + +int pa_socket_low_delay(int fd); +int pa_socket_tcp_low_delay(int fd); + +int pa_socket_set_sndbuf(int fd, size_t l); +int pa_socket_set_rcvbuf(int fd, size_t l); + +int pa_unix_socket_is_stale(const char *fn); +int pa_unix_socket_remove_stale(const char *fn); + +#endif diff --git a/src/polypcore/sound-file-stream.c b/src/polypcore/sound-file-stream.c new file mode 100644 index 00000000..881e3077 --- /dev/null +++ b/src/polypcore/sound-file-stream.c @@ -0,0 +1,179 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include "sound-file-stream.h" +#include "sink-input.h" +#include "xmalloc.h" +#include "log.h" + +#define BUF_SIZE (1024*10) + +struct userdata { + SNDFILE *sndfile; + pa_sink_input *sink_input; + pa_memchunk memchunk; + sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames); +}; + +static void free_userdata(struct userdata *u) { + assert(u); + if (u->sink_input) { + pa_sink_input_disconnect(u->sink_input); + pa_sink_input_unref(u->sink_input); + } + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + if (u->sndfile) + sf_close(u->sndfile); + + pa_xfree(u); +} + +static void sink_input_kill(pa_sink_input *i) { + assert(i && i->userdata); + free_userdata(i->userdata); +} + +static void si_kill(PA_GCC_UNUSED pa_mainloop_api *m, void *i) { + sink_input_kill(i); +} + +static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { + struct userdata *u; + assert(i && chunk && i->userdata); + u = i->userdata; + + if (!u->memchunk.memblock) { + uint32_t fs = pa_frame_size(&i->sample_spec); + sf_count_t samples = BUF_SIZE/fs; + + u->memchunk.memblock = pa_memblock_new(BUF_SIZE, i->sink->core->memblock_stat); + u->memchunk.index = 0; + samples = u->readf_function(u->sndfile, u->memchunk.memblock->data, samples); + u->memchunk.length = samples*fs; + + if (!u->memchunk.length) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + u->memchunk.index = u->memchunk.length = 0; + pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i); + return -1; + } + } + + *chunk = u->memchunk; + pa_memblock_ref(chunk->memblock); + assert(chunk->length); + return 0; +} + +static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) { + struct userdata *u; + assert(i && chunk && length && i->userdata); + u = i->userdata; + + assert(!memcmp(chunk, &u->memchunk, sizeof(chunk))); + assert(length <= u->memchunk.length); + + u->memchunk.index += length; + u->memchunk.length -= length; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + u->memchunk.index = u->memchunk.length = 0; + } +} + +int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume) { + struct userdata *u = NULL; + SF_INFO sfinfo; + pa_sample_spec ss; + assert(sink && fname); + + u = pa_xmalloc(sizeof(struct userdata)); + u->sink_input = NULL; + u->memchunk.memblock = NULL; + u->memchunk.index = u->memchunk.length = 0; + u->sndfile = NULL; + + memset(&sfinfo, 0, sizeof(sfinfo)); + + if (!(u->sndfile = sf_open(fname, SFM_READ, &sfinfo))) { + pa_log(__FILE__": Failed to open file %s\n", fname); + goto fail; + } + + switch (sfinfo.format & 0xFF) { + case SF_FORMAT_PCM_16: + case SF_FORMAT_PCM_U8: + case SF_FORMAT_ULAW: + case SF_FORMAT_ALAW: + ss.format = PA_SAMPLE_S16NE; + u->readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_short; + break; + case SF_FORMAT_FLOAT: + default: + ss.format = PA_SAMPLE_FLOAT32NE; + u->readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_float; + break; + } + + ss.rate = sfinfo.samplerate; + ss.channels = sfinfo.channels; + + if (!pa_sample_spec_valid(&ss)) { + pa_log(__FILE__": Unsupported sample format in file %s\n", fname); + goto fail; + } + + if (!(u->sink_input = pa_sink_input_new(sink, __FILE__, fname, &ss, NULL, 0, -1))) + goto fail; + + if (volume) + u->sink_input->volume = *volume; + u->sink_input->peek = sink_input_peek; + u->sink_input->drop = sink_input_drop; + u->sink_input->kill = sink_input_kill; + u->sink_input->userdata = u; + + pa_sink_notify(sink); + + return 0; + +fail: + if (u) + free_userdata(u); + + return -1; +} diff --git a/src/polypcore/sound-file-stream.h b/src/polypcore/sound-file-stream.h new file mode 100644 index 00000000..2e56ef49 --- /dev/null +++ b/src/polypcore/sound-file-stream.h @@ -0,0 +1,29 @@ +#ifndef foosoundfilestreamhfoo +#define foosoundfilestreamhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "sink.h" + +int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume); + +#endif diff --git a/src/polypcore/sound-file.c b/src/polypcore/sound-file.c new file mode 100644 index 00000000..a81c283a --- /dev/null +++ b/src/polypcore/sound-file.c @@ -0,0 +1,139 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include "sound-file.h" +#include +#include "log.h" + +#define MAX_FILE_SIZE (1024*1024) + +int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_memchunk *chunk, pa_memblock_stat *s) { + SNDFILE*sf = NULL; + SF_INFO sfinfo; + int ret = -1; + size_t l; + sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames); + assert(fname && ss && chunk); + + chunk->memblock = NULL; + chunk->index = chunk->length = 0; + + memset(&sfinfo, 0, sizeof(sfinfo)); + + if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) { + pa_log(__FILE__": Failed to open file %s\n", fname); + goto finish; + } + + switch (sfinfo.format & SF_FORMAT_SUBMASK) { + case SF_FORMAT_FLOAT: + case SF_FORMAT_DOUBLE: + /* Only float and double need a special case. */ + ss->format = PA_SAMPLE_FLOAT32NE; + readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_float; + break; + default: + /* Everything else is cleanly converted to signed 16 bit. */ + ss->format = PA_SAMPLE_S16NE; + readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_short; + break; + } + + ss->rate = sfinfo.samplerate; + ss->channels = sfinfo.channels; + + if (!pa_sample_spec_valid(ss)) { + pa_log(__FILE__": Unsupported sample format in file %s\n", fname); + goto finish; + } + + if ((l = pa_frame_size(ss)*sfinfo.frames) > MAX_FILE_SIZE) { + pa_log(__FILE__": File too large\n"); + goto finish; + } + + chunk->memblock = pa_memblock_new(l, s); + assert(chunk->memblock); + chunk->index = 0; + chunk->length = l; + + if (readf_function(sf, chunk->memblock->data, sfinfo.frames) != sfinfo.frames) { + pa_log(__FILE__": Premature file end\n"); + goto finish; + } + + ret = 0; + +finish: + + if (sf) + sf_close(sf); + + if (ret != 0 && chunk->memblock) + pa_memblock_unref(chunk->memblock); + + return ret; + +} + +int pa_sound_file_too_big_to_cache(const char *fname) { + SNDFILE*sf = NULL; + SF_INFO sfinfo; + pa_sample_spec ss; + + if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) { + pa_log(__FILE__": Failed to open file %s\n", fname); + return 0; + } + + sf_close(sf); + + switch (sfinfo.format & SF_FORMAT_SUBMASK) { + case SF_FORMAT_FLOAT: + case SF_FORMAT_DOUBLE: + /* Only float and double need a special case. */ + ss.format = PA_SAMPLE_FLOAT32NE; + break; + default: + /* Everything else is cleanly converted to signed 16 bit. */ + ss.format = PA_SAMPLE_S16NE; + break; + } + + ss.rate = sfinfo.samplerate; + ss.channels = sfinfo.channels; + + if ((pa_frame_size(&ss) * sfinfo.frames) > MAX_FILE_SIZE) { + pa_log(__FILE__": File too large %s\n", fname); + return 1; + } + + return 0; +} diff --git a/src/polypcore/sound-file.h b/src/polypcore/sound-file.h new file mode 100644 index 00000000..f3003bb9 --- /dev/null +++ b/src/polypcore/sound-file.h @@ -0,0 +1,32 @@ +#ifndef soundfilehfoo +#define soundfilehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "memchunk.h" +#include + +int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_memchunk *chunk, pa_memblock_stat *s); + +int pa_sound_file_too_big_to_cache(const char *fname); + +#endif diff --git a/src/polypcore/source-output.c b/src/polypcore/source-output.c new file mode 100644 index 00000000..e1d8ccf7 --- /dev/null +++ b/src/polypcore/source-output.c @@ -0,0 +1,228 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "source-output.h" +#include "xmalloc.h" +#include "subscribe.h" +#include "log.h" + +pa_source_output* pa_source_output_new( + pa_source *s, + const char *driver, + const char *name, + const pa_sample_spec *spec, + const pa_channel_map *map, + int resample_method) { + + pa_source_output *o; + pa_resampler *resampler = NULL; + int r; + char st[256]; + pa_channel_map tmap; + + assert(s); + assert(spec); + assert(s->state == PA_SOURCE_RUNNING); + + if (pa_idxset_size(s->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { + pa_log(__FILE__": Failed to create source output: too many outputs per source.\n"); + return NULL; + } + + if (resample_method == PA_RESAMPLER_INVALID) + resample_method = s->core->resample_method; + + if (!map) { + pa_channel_map_init_auto(&tmap, spec->channels); + map = &tmap; + } + + if (!pa_sample_spec_equal(&s->sample_spec, spec) || !pa_channel_map_equal(&s->channel_map, map)) + if (!(resampler = pa_resampler_new(&s->sample_spec, &s->channel_map, spec, map, s->core->memblock_stat, resample_method))) + return NULL; + + o = pa_xmalloc(sizeof(pa_source_output)); + o->ref = 1; + o->state = PA_SOURCE_OUTPUT_RUNNING; + o->name = pa_xstrdup(name); + o->driver = pa_xstrdup(driver); + o->owner = NULL; + o->source = s; + o->client = NULL; + + o->sample_spec = *spec; + o->channel_map = *map; + + o->push = NULL; + o->kill = NULL; + o->get_latency = NULL; + o->userdata = NULL; + + o->resampler = resampler; + + assert(s->core); + r = pa_idxset_put(s->core->source_outputs, o, &o->index); + assert(r == 0 && o->index != PA_IDXSET_INVALID); + r = pa_idxset_put(s->outputs, o, NULL); + assert(r == 0); + + pa_sample_spec_snprint(st, sizeof(st), spec); + pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"\n", o->index, o->name, s->index, st); + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); + + return o; +} + +void pa_source_output_disconnect(pa_source_output*o) { + assert(o); + assert(o->state != PA_SOURCE_OUTPUT_DISCONNECTED); + assert(o->source); + assert(o->source->core); + + pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); + pa_idxset_remove_by_data(o->source->outputs, o, NULL); + + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); + o->source = NULL; + + o->push = NULL; + o->kill = NULL; + o->get_latency = NULL; + + o->state = PA_SOURCE_OUTPUT_DISCONNECTED; +} + +static void source_output_free(pa_source_output* o) { + assert(o); + + if (o->state != PA_SOURCE_OUTPUT_DISCONNECTED) + pa_source_output_disconnect(o); + + pa_log_info(__FILE__": freed %u \"%s\"\n", o->index, o->name); + + if (o->resampler) + pa_resampler_free(o->resampler); + + pa_xfree(o->name); + pa_xfree(o->driver); + pa_xfree(o); +} + + +void pa_source_output_unref(pa_source_output* o) { + assert(o); + assert(o->ref >= 1); + + if (!(--o->ref)) + source_output_free(o); +} + +pa_source_output* pa_source_output_ref(pa_source_output *o) { + assert(o); + assert(o->ref >= 1); + + o->ref++; + return o; +} + + +void pa_source_output_kill(pa_source_output*o) { + assert(o); + assert(o->ref >= 1); + + if (o->kill) + o->kill(o); +} + +void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { + pa_memchunk rchunk; + + assert(o); + assert(chunk); + assert(chunk->length); + assert(o->push); + + if (o->state == PA_SOURCE_OUTPUT_CORKED) + return; + + if (!o->resampler) { + o->push(o, chunk); + return; + } + + pa_resampler_run(o->resampler, chunk, &rchunk); + if (!rchunk.length) + return; + + assert(rchunk.memblock); + o->push(o, &rchunk); + pa_memblock_unref(rchunk.memblock); +} + +void pa_source_output_set_name(pa_source_output *o, const char *name) { + assert(o); + assert(o->ref >= 1); + + pa_xfree(o->name); + o->name = pa_xstrdup(name); + + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); +} + +pa_usec_t pa_source_output_get_latency(pa_source_output *o) { + assert(o); + assert(o->ref >= 1); + + if (o->get_latency) + return o->get_latency(o); + + return 0; +} + +void pa_source_output_cork(pa_source_output *o, int b) { + assert(o); + assert(o->ref >= 1); + + if (o->state == PA_SOURCE_OUTPUT_DISCONNECTED) + return; + + o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; +} + +pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { + assert(o); + assert(o->ref >= 1); + + if (!o->resampler) + return PA_RESAMPLER_INVALID; + + return pa_resampler_get_method(o->resampler); +} diff --git a/src/polypcore/source-output.h b/src/polypcore/source-output.h new file mode 100644 index 00000000..4b1cbf15 --- /dev/null +++ b/src/polypcore/source-output.h @@ -0,0 +1,92 @@ +#ifndef foosourceoutputhfoo +#define foosourceoutputhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef struct pa_source_output pa_source_output; + +#include "source.h" +#include +#include "memblockq.h" +#include "resampler.h" +#include "module.h" +#include "client.h" + +typedef enum { + PA_SOURCE_OUTPUT_RUNNING, + PA_SOURCE_OUTPUT_CORKED, + PA_SOURCE_OUTPUT_DISCONNECTED +} pa_source_output_state_t; + +struct pa_source_output { + int ref; + uint32_t index; + pa_source_output_state_t state; + + char *name, *driver; + pa_module *owner; + + pa_source *source; + pa_client *client; + + pa_sample_spec sample_spec; + pa_channel_map channel_map; + + void (*push)(pa_source_output *o, const pa_memchunk *chunk); + void (*kill)(pa_source_output* o); + pa_usec_t (*get_latency) (pa_source_output *i); + + pa_resampler* resampler; + + void *userdata; +}; + +pa_source_output* pa_source_output_new( + pa_source *s, + const char *driver, + const char *name, + const pa_sample_spec *spec, + const pa_channel_map *map, + int resample_method); + +void pa_source_output_unref(pa_source_output* o); +pa_source_output* pa_source_output_ref(pa_source_output *o); + +/* To be called by the implementing module only */ +void pa_source_output_disconnect(pa_source_output*o); + +/* External code may request disconnection with this funcion */ +void pa_source_output_kill(pa_source_output*o); + +void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk); + +void pa_source_output_set_name(pa_source_output *i, const char *name); + +pa_usec_t pa_source_output_get_latency(pa_source_output *i); + +void pa_source_output_cork(pa_source_output *i, int b); + +pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o); + +#endif diff --git a/src/polypcore/source.c b/src/polypcore/source.c new file mode 100644 index 00000000..6e377b20 --- /dev/null +++ b/src/polypcore/source.c @@ -0,0 +1,195 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "source.h" +#include "source-output.h" +#include "namereg.h" +#include "xmalloc.h" +#include "subscribe.h" +#include "log.h" + +pa_source* pa_source_new( + pa_core *core, + const char *driver, + const char *name, + int fail, + const pa_sample_spec *spec, + const pa_channel_map *map) { + + pa_source *s; + char st[256]; + int r; + + assert(core); + assert(name); + assert(*name); + assert(spec); + + s = pa_xnew(pa_source, 1); + + if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SOURCE, s, fail))) { + pa_xfree(s); + return NULL; + } + + s->ref = 1; + s->core = core; + s->state = PA_SOURCE_RUNNING; + s->name = pa_xstrdup(name); + s->description = NULL; + s->driver = pa_xstrdup(driver); + s->owner = NULL; + + s->sample_spec = *spec; + if (map) + s->channel_map = *map; + else + pa_channel_map_init_auto(&s->channel_map, spec->channels); + + s->outputs = pa_idxset_new(NULL, NULL); + s->monitor_of = NULL; + + s->get_latency = NULL; + s->notify = NULL; + s->userdata = NULL; + + r = pa_idxset_put(core->sources, s, &s->index); + assert(s->index != PA_IDXSET_INVALID && r >= 0); + + pa_sample_spec_snprint(st, sizeof(st), spec); + pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); + + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index); + + return s; +} + +void pa_source_disconnect(pa_source *s) { + pa_source_output *o, *j = NULL; + + assert(s); + assert(s->state == PA_SOURCE_RUNNING); + + pa_namereg_unregister(s->core, s->name); + + while ((o = pa_idxset_first(s->outputs, NULL))) { + assert(o != j); + pa_source_output_kill(o); + j = o; + } + + pa_idxset_remove_by_data(s->core->sources, s, NULL); + + s->get_latency = NULL; + s->notify = NULL; + + s->state = PA_SOURCE_DISCONNECTED; + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); +} + +static void source_free(pa_source *s) { + assert(s); + assert(!s->ref); + + if (s->state != PA_SOURCE_DISCONNECTED) + pa_source_disconnect(s); + + pa_log_info(__FILE__": freed %u \"%s\"\n", s->index, s->name); + + pa_idxset_free(s->outputs, NULL, NULL); + + pa_xfree(s->name); + pa_xfree(s->description); + pa_xfree(s->driver); + pa_xfree(s); +} + +void pa_source_unref(pa_source *s) { + assert(s); + assert(s->ref >= 1); + + if (!(--s->ref)) + source_free(s); +} + +pa_source* pa_source_ref(pa_source *s) { + assert(s); + assert(s->ref >= 1); + + s->ref++; + return s; +} + +void pa_source_notify(pa_source*s) { + assert(s); + assert(s->ref >= 1); + + if (s->notify) + s->notify(s); +} + +static int do_post(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void*userdata) { + pa_source_output *o = p; + const pa_memchunk *chunk = userdata; + + assert(o); + assert(chunk); + + pa_source_output_push(o, chunk); + return 0; +} + +void pa_source_post(pa_source*s, const pa_memchunk *chunk) { + assert(s); + assert(s->ref >= 1); + assert(chunk); + + pa_source_ref(s); + pa_idxset_foreach(s->outputs, do_post, (void*) chunk); + pa_source_unref(s); +} + +void pa_source_set_owner(pa_source *s, pa_module *m) { + assert(s); + assert(s->ref >= 1); + + s->owner = m; +} + +pa_usec_t pa_source_get_latency(pa_source *s) { + assert(s); + assert(s->ref >= 1); + + if (!s->get_latency) + return 0; + + return s->get_latency(s); +} + diff --git a/src/polypcore/source.h b/src/polypcore/source.h new file mode 100644 index 00000000..be2fb985 --- /dev/null +++ b/src/polypcore/source.h @@ -0,0 +1,86 @@ +#ifndef foosourcehfoo +#define foosourcehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef struct pa_source pa_source; + +#include +#include "core.h" +#include +#include "idxset.h" +#include "memblock.h" +#include "memchunk.h" +#include "sink.h" +#include +#include "module.h" + +#define PA_MAX_OUTPUTS_PER_SOURCE 16 + +typedef enum pa_source_state { + PA_SOURCE_RUNNING, + PA_SOURCE_DISCONNECTED +} pa_source_state_t; + +struct pa_source { + int ref; + uint32_t index; + pa_core *core; + pa_source_state_t state; + + char *name, *description, *driver; + pa_module *owner; + + pa_sample_spec sample_spec; + pa_channel_map channel_map; + + pa_idxset *outputs; + pa_sink *monitor_of; + + void (*notify)(pa_source*source); + pa_usec_t (*get_latency)(pa_source *s); + + void *userdata; +}; + +pa_source* pa_source_new( + pa_core *core, + const char *driver, + const char *name, + int namereg_fail, + const pa_sample_spec *spec, + const pa_channel_map *map); + +void pa_source_disconnect(pa_source *s); +void pa_source_unref(pa_source *s); +pa_source* pa_source_ref(pa_source *c); + +/* Pass a new memory block to all output streams */ +void pa_source_post(pa_source*s, const pa_memchunk *b); + +void pa_source_notify(pa_source *s); + +void pa_source_set_owner(pa_source *s, pa_module *m); + +pa_usec_t pa_source_get_latency(pa_source *s); + +#endif diff --git a/src/polypcore/strbuf.c b/src/polypcore/strbuf.c new file mode 100644 index 00000000..dcad5e78 --- /dev/null +++ b/src/polypcore/strbuf.c @@ -0,0 +1,167 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include "strbuf.h" + +/* A chunk of the linked list that makes up the string */ +struct chunk { + struct chunk *next; + size_t length; +}; + +#define CHUNK_TO_TEXT(c) ((char*) (c) + sizeof(struct chunk)) + +struct pa_strbuf { + size_t length; + struct chunk *head, *tail; +}; + +pa_strbuf *pa_strbuf_new(void) { + pa_strbuf *sb = pa_xmalloc(sizeof(pa_strbuf)); + sb->length = 0; + sb->head = sb->tail = NULL; + return sb; +} + +void pa_strbuf_free(pa_strbuf *sb) { + assert(sb); + while (sb->head) { + struct chunk *c = sb->head; + sb->head = sb->head->next; + pa_xfree(c); + } + + pa_xfree(sb); +} + +/* Make a C string from the string buffer. The caller has to free + * string with pa_xfree(). */ +char *pa_strbuf_tostring(pa_strbuf *sb) { + char *t, *e; + struct chunk *c; + assert(sb); + + e = t = pa_xmalloc(sb->length+1); + + for (c = sb->head; c; c = c->next) { + assert((size_t) (e-t) <= sb->length); + memcpy(e, CHUNK_TO_TEXT(c), c->length); + e += c->length; + } + + /* Trailing NUL */ + *e = 0; + + assert(e == t+sb->length); + + return t; +} + +/* Combination of pa_strbuf_free() and pa_strbuf_tostring() */ +char *pa_strbuf_tostring_free(pa_strbuf *sb) { + char *t; + assert(sb); + t = pa_strbuf_tostring(sb); + pa_strbuf_free(sb); + return t; +} + +/* Append a string to the string buffer */ +void pa_strbuf_puts(pa_strbuf *sb, const char *t) { + assert(sb && t); + pa_strbuf_putsn(sb, t, strlen(t)); +} + +/* Append a new chunk to the linked list */ +static void append(pa_strbuf *sb, struct chunk *c) { + assert(sb && c); + + if (sb->tail) { + assert(sb->head); + sb->tail->next = c; + } else { + assert(!sb->head); + sb->head = c; + } + + sb->tail = c; + sb->length += c->length; + c->next = NULL; +} + +/* Append up to l bytes of a string to the string buffer */ +void pa_strbuf_putsn(pa_strbuf *sb, const char *t, size_t l) { + struct chunk *c; + assert(sb && t); + + if (!l) + return; + + c = pa_xmalloc(sizeof(struct chunk)+l); + c->length = l; + memcpy(CHUNK_TO_TEXT(c), t, l); + + append(sb, c); +} + +/* Append a printf() style formatted string to the string buffer. */ +/* The following is based on an example from the GNU libc documentation */ +int pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) { + int size = 100; + struct chunk *c = NULL; + + assert(sb); + + for(;;) { + va_list ap; + int r; + + c = pa_xrealloc(c, sizeof(struct chunk)+size); + + va_start(ap, format); + r = vsnprintf(CHUNK_TO_TEXT(c), size, format, ap); + va_end(ap); + + if (r > -1 && r < size) { + c->length = r; + append(sb, c); + return r; + } + + if (r > -1) /* glibc 2.1 */ + size = r+1; + else /* glibc 2.0 */ + size *= 2; + } +} diff --git a/src/polypcore/strbuf.h b/src/polypcore/strbuf.h new file mode 100644 index 00000000..a88f5190 --- /dev/null +++ b/src/polypcore/strbuf.h @@ -0,0 +1,38 @@ +#ifndef foostrbufhfoo +#define foostrbufhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "gccmacro.h" + +typedef struct pa_strbuf pa_strbuf; + +pa_strbuf *pa_strbuf_new(void); +void pa_strbuf_free(pa_strbuf *sb); +char *pa_strbuf_tostring(pa_strbuf *sb); +char *pa_strbuf_tostring_free(pa_strbuf *sb); + +int pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); +void pa_strbuf_puts(pa_strbuf *sb, const char *t); +void pa_strbuf_putsn(pa_strbuf *sb, const char *t, size_t m); + +#endif diff --git a/src/polypcore/strlist.c b/src/polypcore/strlist.c new file mode 100644 index 00000000..09eb0c8a --- /dev/null +++ b/src/polypcore/strlist.c @@ -0,0 +1,137 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "strlist.h" +#include "xmalloc.h" +#include "strbuf.h" +#include "util.h" + +struct pa_strlist { + pa_strlist *next; + char *str; +}; + +pa_strlist* pa_strlist_prepend(pa_strlist *l, const char *s) { + pa_strlist *n; + assert(s); + n = pa_xmalloc(sizeof(pa_strlist)); + n->str = pa_xstrdup(s); + n->next = l; + return n; +} + +char *pa_strlist_tostring(pa_strlist *l) { + int first = 1; + pa_strbuf *b; + + b = pa_strbuf_new(); + for (; l; l = l->next) { + if (!first) + pa_strbuf_puts(b, " "); + first = 0; + pa_strbuf_puts(b, l->str); + } + + return pa_strbuf_tostring_free(b); +} + +pa_strlist* pa_strlist_remove(pa_strlist *l, const char *s) { + pa_strlist *ret = l, *prev = NULL; + assert(l && s); + + while (l) { + if (!strcmp(l->str, s)) { + pa_strlist *n = l->next; + + if (!prev) { + assert(ret == l); + ret = n; + } else + prev->next = n; + + pa_xfree(l->str); + pa_xfree(l); + + l = n; + + } else { + prev = l; + l = l->next; + } + } + + return ret; +} + +void pa_strlist_free(pa_strlist *l) { + while (l) { + pa_strlist *c = l; + l = l->next; + + pa_xfree(c->str); + pa_xfree(c); + } +} + +pa_strlist* pa_strlist_pop(pa_strlist *l, char **s) { + pa_strlist *r; + assert(s); + + if (!l) { + *s = NULL; + return NULL; + } + + *s = l->str; + r = l->next; + pa_xfree(l); + return r; +} + +pa_strlist* pa_strlist_parse(const char *s) { + pa_strlist *head = NULL, *p = NULL; + const char *state = NULL; + char *r; + + while ((r = pa_split_spaces(s, &state))) { + pa_strlist *n; + + n = pa_xmalloc(sizeof(pa_strlist)); + n->str = r; + n->next = NULL; + + if (p) + p->next = n; + else + head = n; + + p = n; + } + + return head; +} diff --git a/src/polypcore/strlist.h b/src/polypcore/strlist.h new file mode 100644 index 00000000..2c54dc74 --- /dev/null +++ b/src/polypcore/strlist.h @@ -0,0 +1,47 @@ +#ifndef foostrlisthfoo +#define foostrlisthfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef struct pa_strlist pa_strlist; + +/* Add the specified server string to the list, return the new linked list head */ +pa_strlist* pa_strlist_prepend(pa_strlist *l, const char *s); + +/* Remove the specified string from the list, return the new linked list head */ +pa_strlist* pa_strlist_remove(pa_strlist *l, const char *s); + +/* Make a whitespace separated string of all server stringes. Returned memory has to be freed with pa_xfree() */ +char *pa_strlist_tostring(pa_strlist *l); + +/* Free the entire list */ +void pa_strlist_free(pa_strlist *l); + +/* Return the next entry in the list in *string and remove it from + * the list. Returns the new list head. The memory *string points to + * has to be freed with pa_xfree() */ +pa_strlist* pa_strlist_pop(pa_strlist *l, char **s); + +/* Parse a whitespace separated server list */ +pa_strlist* pa_strlist_parse(const char *s); + +#endif diff --git a/src/polypcore/subscribe.c b/src/polypcore/subscribe.c new file mode 100644 index 00000000..e8b3c841 --- /dev/null +++ b/src/polypcore/subscribe.c @@ -0,0 +1,230 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "queue.h" +#include "subscribe.h" +#include "xmalloc.h" +#include "log.h" + +/* The subscription subsystem may be used to be notified whenever an + * entity (sink, source, ...) is created or deleted. Modules may + * register a callback function that is called whenever an event + * matching a subscription mask happens. The execution of the callback + * function is postponed to the next main loop iteration, i.e. is not + * called from within the stack frame the entity was created in. */ + +struct pa_subscription { + pa_core *core; + int dead; + void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata); + void *userdata; + pa_subscription_mask_t mask; + + pa_subscription *prev, *next; +}; + +struct pa_subscription_event { + pa_subscription_event_type_t type; + uint32_t index; +}; + +static void sched_event(pa_core *c); + +/* Allocate a new subscription object for the given subscription mask. Use the specified callback function and user data */ +pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata) { + pa_subscription *s; + assert(c); + + s = pa_xmalloc(sizeof(pa_subscription)); + s->core = c; + s->dead = 0; + s->callback = callback; + s->userdata = userdata; + s->mask = m; + + if ((s->next = c->subscriptions)) + s->next->prev = s; + s->prev = NULL; + c->subscriptions = s; + return s; +} + +/* Free a subscription object, effectively marking it for deletion */ +void pa_subscription_free(pa_subscription*s) { + assert(s && !s->dead); + s->dead = 1; + sched_event(s->core); +} + +static void free_item(pa_subscription *s) { + assert(s && s->core); + + if (s->prev) + s->prev->next = s->next; + else + s->core->subscriptions = s->next; + + if (s->next) + s->next->prev = s->prev; + + pa_xfree(s); +} + +/* Free all subscription objects */ +void pa_subscription_free_all(pa_core *c) { + pa_subscription_event *e; + assert(c); + + while (c->subscriptions) + free_item(c->subscriptions); + + if (c->subscription_event_queue) { + while ((e = pa_queue_pop(c->subscription_event_queue))) + pa_xfree(e); + + pa_queue_free(c->subscription_event_queue, NULL, NULL); + c->subscription_event_queue = NULL; + } + + if (c->subscription_defer_event) { + c->mainloop->defer_free(c->subscription_defer_event); + c->subscription_defer_event = NULL; + } +} + +/*static void dump_event(pa_subscription_event*e) { + switch (e->type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { + case PA_SUBSCRIPTION_EVENT_SINK: + pa_log(__FILE__": SINK_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_SOURCE: + pa_log(__FILE__": SOURCE_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_SINK_INPUT: + pa_log(__FILE__": SINK_INPUT_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: + pa_log(__FILE__": SOURCE_OUTPUT_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_MODULE: + pa_log(__FILE__": MODULE_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_CLIENT: + pa_log(__FILE__": CLIENT_EVENT"); + break; + default: + pa_log(__FILE__": OTHER"); + break; + } + + switch (e->type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) { + case PA_SUBSCRIPTION_EVENT_NEW: + pa_log(__FILE__": NEW"); + break; + case PA_SUBSCRIPTION_EVENT_CHANGE: + pa_log(__FILE__": CHANGE"); + break; + case PA_SUBSCRIPTION_EVENT_REMOVE: + pa_log(__FILE__": REMOVE"); + break; + default: + pa_log(__FILE__": OTHER"); + break; + } + + pa_log(__FILE__": %u\n", e->index); +}*/ + +/* Deferred callback for dispatching subscirption events */ +static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) { + pa_core *c = userdata; + pa_subscription *s; + assert(c && c->subscription_defer_event == de && c->mainloop == m); + + c->mainloop->defer_enable(c->subscription_defer_event, 0); + + + /* Dispatch queued events */ + + if (c->subscription_event_queue) { + pa_subscription_event *e; + + while ((e = pa_queue_pop(c->subscription_event_queue))) { + + for (s = c->subscriptions; s; s = s->next) { + + if (!s->dead && pa_subscription_match_flags(s->mask, e->type)) + s->callback(c, e->type, e->index, s->userdata); + } + + pa_xfree(e); + } + } + + /* Remove dead subscriptions */ + + s = c->subscriptions; + while (s) { + pa_subscription *n = s->next; + if (s->dead) + free_item(s); + s = n; + } +} + +/* Schedule an mainloop event so that a pending subscription event is dispatched */ +static void sched_event(pa_core *c) { + assert(c); + + if (!c->subscription_defer_event) { + c->subscription_defer_event = c->mainloop->defer_new(c->mainloop, defer_cb, c); + assert(c->subscription_defer_event); + } + + c->mainloop->defer_enable(c->subscription_defer_event, 1); +} + +/* Append a new subscription event to the subscription event queue and schedule a main loop event */ +void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t index) { + pa_subscription_event *e; + assert(c); + + e = pa_xmalloc(sizeof(pa_subscription_event)); + e->type = t; + e->index = index; + + if (!c->subscription_event_queue) { + c->subscription_event_queue = pa_queue_new(); + assert(c->subscription_event_queue); + } + + pa_queue_push(c->subscription_event_queue, e); + sched_event(c); +} + + diff --git a/src/polypcore/subscribe.h b/src/polypcore/subscribe.h new file mode 100644 index 00000000..625159e3 --- /dev/null +++ b/src/polypcore/subscribe.h @@ -0,0 +1,37 @@ +#ifndef foosubscribehfoo +#define foosubscribehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef struct pa_subscription pa_subscription; +typedef struct pa_subscription_event pa_subscription_event; + +#include "core.h" +#include "native-common.h" + +pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata); +void pa_subscription_free(pa_subscription*s); +void pa_subscription_free_all(pa_core *c); + +void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t idx); + +#endif diff --git a/src/polypcore/tagstruct.c b/src/polypcore/tagstruct.c new file mode 100644 index 00000000..676f67de --- /dev/null +++ b/src/polypcore/tagstruct.c @@ -0,0 +1,609 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#include "winsock.h" + +#include "tagstruct.h" +#include "xmalloc.h" + + +struct pa_tagstruct { + uint8_t *data; + size_t length, allocated; + size_t rindex; + + int dynamic; +}; + +pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) { + pa_tagstruct*t; + + assert(!data || (data && length)); + + t = pa_xmalloc(sizeof(pa_tagstruct)); + t->data = (uint8_t*) data; + t->allocated = t->length = data ? length : 0; + t->rindex = 0; + t->dynamic = !data; + return t; +} + +void pa_tagstruct_free(pa_tagstruct*t) { + assert(t); + if (t->dynamic) + pa_xfree(t->data); + pa_xfree(t); +} + +uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l) { + uint8_t *p; + assert(t && t->dynamic && l); + p = t->data; + *l = t->length; + pa_xfree(t); + return p; +} + +static void extend(pa_tagstruct*t, size_t l) { + assert(t && t->dynamic); + + if (t->length+l <= t->allocated) + return; + + t->data = pa_xrealloc(t->data, t->allocated = t->length+l+100); +} + + +void pa_tagstruct_puts(pa_tagstruct*t, const char *s) { + size_t l; + assert(t); + if (s) { + l = strlen(s)+2; + extend(t, l); + t->data[t->length] = PA_TAG_STRING; + strcpy((char*) (t->data+t->length+1), s); + t->length += l; + } else { + extend(t, 1); + t->data[t->length] = PA_TAG_STRING_NULL; + t->length += 1; + } +} + +void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i) { + assert(t); + extend(t, 5); + t->data[t->length] = PA_TAG_U32; + i = htonl(i); + memcpy(t->data+t->length+1, &i, 4); + t->length += 5; +} + +void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c) { + assert(t); + extend(t, 2); + t->data[t->length] = PA_TAG_U8; + *(t->data+t->length+1) = c; + t->length += 2; +} + +void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss) { + uint32_t rate; + assert(t && ss); + extend(t, 7); + t->data[t->length] = PA_TAG_SAMPLE_SPEC; + t->data[t->length+1] = (uint8_t) ss->format; + t->data[t->length+2] = ss->channels; + rate = htonl(ss->rate); + memcpy(t->data+t->length+3, &rate, 4); + t->length += 7; +} + +void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) { + uint32_t tmp; + assert(t && p); + + extend(t, 5+length); + t->data[t->length] = PA_TAG_ARBITRARY; + tmp = htonl(length); + memcpy(t->data+t->length+1, &tmp, 4); + if (length) + memcpy(t->data+t->length+5, p, length); + t->length += 5+length; +} + +void pa_tagstruct_put_boolean(pa_tagstruct*t, int b) { + assert(t); + extend(t, 1); + t->data[t->length] = b ? PA_TAG_BOOLEAN_TRUE : PA_TAG_BOOLEAN_FALSE; + t->length += 1; +} + +void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv) { + uint32_t tmp; + assert(t); + extend(t, 9); + t->data[t->length] = PA_TAG_TIMEVAL; + tmp = htonl(tv->tv_sec); + memcpy(t->data+t->length+1, &tmp, 4); + tmp = htonl(tv->tv_usec); + memcpy(t->data+t->length+5, &tmp, 4); + t->length += 9; +} + +void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u) { + uint32_t tmp; + assert(t); + extend(t, 9); + t->data[t->length] = PA_TAG_USEC; + tmp = htonl((uint32_t) (u >> 32)); + memcpy(t->data+t->length+1, &tmp, 4); + tmp = htonl((uint32_t) u); + memcpy(t->data+t->length+5, &tmp, 4); + t->length += 9; +} + +void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) { + uint32_t tmp; + assert(t); + extend(t, 9); + t->data[t->length] = PA_TAG_U64; + tmp = htonl((uint32_t) (u >> 32)); + memcpy(t->data+t->length+1, &tmp, 4); + tmp = htonl((uint32_t) u); + memcpy(t->data+t->length+5, &tmp, 4); + t->length += 9; +} + +void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) { + unsigned i; + + assert(t); + extend(t, 2 + map->channels); + + t->data[t->length++] = PA_TAG_CHANNEL_MAP; + t->data[t->length++] = map->channels; + + for (i = 0; i < map->channels; i ++) + t->data[t->length++] = (uint8_t) map->map[i]; +} + +void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) { + unsigned i; + pa_volume_t vol; + + assert(t); + extend(t, 2 + cvolume->channels * sizeof(pa_volume_t)); + + t->data[t->length++] = PA_TAG_CVOLUME; + t->data[t->length++] = cvolume->channels; + + for (i = 0; i < cvolume->channels; i ++) { + vol = htonl(cvolume->values[i]); + memcpy(t->data + t->length, &vol, sizeof(pa_volume_t)); + t->length += sizeof(pa_volume_t); + } +} + +int pa_tagstruct_gets(pa_tagstruct*t, const char **s) { + int error = 0; + size_t n; + char *c; + assert(t && s); + + if (t->rindex+1 > t->length) + return -1; + + if (t->data[t->rindex] == PA_TAG_STRING_NULL) { + t->rindex++; + *s = NULL; + return 0; + } + + if (t->rindex+2 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_STRING) + return -1; + + error = 1; + for (n = 0, c = (char*) (t->data+t->rindex+1); t->rindex+1+n < t->length; n++, c++) + if (!*c) { + error = 0; + break; + } + + if (error) + return -1; + + *s = (char*) (t->data+t->rindex+1); + + t->rindex += n+2; + return 0; +} + +int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) { + assert(t && i); + + if (t->rindex+5 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_U32) + return -1; + + memcpy(i, t->data+t->rindex+1, 4); + *i = ntohl(*i); + t->rindex += 5; + return 0; +} + +int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) { + assert(t && c); + + if (t->rindex+2 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_U8) + return -1; + + *c = t->data[t->rindex+1]; + t->rindex +=2; + return 0; +} + +int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) { + assert(t && ss); + + if (t->rindex+7 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_SAMPLE_SPEC) + return -1; + + ss->format = t->data[t->rindex+1]; + ss->channels = t->data[t->rindex+2]; + memcpy(&ss->rate, t->data+t->rindex+3, 4); + ss->rate = ntohl(ss->rate); + + if (!pa_sample_spec_valid(ss)) + return -1; + + t->rindex += 7; + return 0; +} + +int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) { + uint32_t len; + assert(t && p); + + if (t->rindex+5+length > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_ARBITRARY) + return -1; + + memcpy(&len, t->data+t->rindex+1, 4); + if (ntohl(len) != length) + return -1; + + *p = t->data+t->rindex+5; + t->rindex += 5+length; + return 0; +} + +int pa_tagstruct_eof(pa_tagstruct*t) { + assert(t); + return t->rindex >= t->length; +} + +const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) { + assert(t && t->dynamic && l); + *l = t->length; + return t->data; +} + +int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) { + assert(t && b); + + if (t->rindex+1 > t->length) + return -1; + + if (t->data[t->rindex] == PA_TAG_BOOLEAN_TRUE) + *b = 1; + else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE) + *b = 0; + else + return -1; + + t->rindex +=1; + return 0; +} + +int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) { + + if (t->rindex+9 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_TIMEVAL) + return -1; + + memcpy(&tv->tv_sec, t->data+t->rindex+1, 4); + tv->tv_sec = ntohl(tv->tv_sec); + memcpy(&tv->tv_usec, t->data+t->rindex+5, 4); + tv->tv_usec = ntohl(tv->tv_usec); + t->rindex += 9; + return 0; + +} + +int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) { + uint32_t tmp; + assert(t && u); + + if (t->rindex+9 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_USEC) + return -1; + + memcpy(&tmp, t->data+t->rindex+1, 4); + *u = (pa_usec_t) ntohl(tmp) << 32; + memcpy(&tmp, t->data+t->rindex+5, 4); + *u |= (pa_usec_t) ntohl(tmp); + t->rindex +=9; + return 0; +} + +int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) { + uint32_t tmp; + assert(t && u); + + if (t->rindex+9 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_U64) + return -1; + + memcpy(&tmp, t->data+t->rindex+1, 4); + *u = (pa_usec_t) ntohl(tmp) << 32; + memcpy(&tmp, t->data+t->rindex+5, 4); + *u |= (pa_usec_t) ntohl(tmp); + t->rindex +=9; + return 0; +} + +int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) { + unsigned i; + + assert(t); + assert(map); + + if (t->rindex+2 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_CHANNEL_MAP) + return -1; + + if ((map->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX) + return -1; + + if (t->rindex+2+map->channels > t->length) + return -1; + + for (i = 0; i < map->channels; i ++) + map->map[i] = (int8_t) t->data[t->rindex + 2 + i]; + + if (!pa_channel_map_valid(map)) + return -1; + + t->rindex += 2 + map->channels; + return 0; +} + +int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) { + unsigned i; + pa_volume_t vol; + + assert(t); + assert(cvolume); + + if (t->rindex+2 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_CVOLUME) + return -1; + + if ((cvolume->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX) + return -1; + + if (t->rindex+2+cvolume->channels*sizeof(pa_volume_t) > t->length) + return -1; + + for (i = 0; i < cvolume->channels; i ++) { + memcpy(&vol, t->data + t->rindex + 2 + i * sizeof(pa_volume_t), sizeof(pa_volume_t)); + cvolume->values[i] = (pa_volume_t) ntohl(vol); + } + + if (!pa_cvolume_valid(cvolume)) + return -1; + + t->rindex += 2 + cvolume->channels * sizeof(pa_volume_t); + return 0; +} + +void pa_tagstruct_put(pa_tagstruct *t, ...) { + va_list va; + assert(t); + + va_start(va, t); + + for (;;) { + int tag = va_arg(va, int); + + if (tag == PA_TAG_INVALID) + break; + + switch (tag) { + case PA_TAG_STRING: + case PA_TAG_STRING_NULL: + pa_tagstruct_puts(t, va_arg(va, char*)); + break; + + case PA_TAG_U32: + pa_tagstruct_putu32(t, va_arg(va, uint32_t)); + break; + + case PA_TAG_U8: + pa_tagstruct_putu8(t, (uint8_t) va_arg(va, int)); + break; + + case PA_TAG_U64: + pa_tagstruct_putu64(t, va_arg(va, uint64_t)); + break; + + case PA_TAG_SAMPLE_SPEC: + pa_tagstruct_put_sample_spec(t, va_arg(va, pa_sample_spec*)); + break; + + case PA_TAG_ARBITRARY: { + void *p = va_arg(va, void*); + size_t size = va_arg(va, size_t); + pa_tagstruct_put_arbitrary(t, p, size); + break; + } + + case PA_TAG_BOOLEAN_TRUE: + case PA_TAG_BOOLEAN_FALSE: + pa_tagstruct_put_boolean(t, va_arg(va, int)); + break; + + case PA_TAG_TIMEVAL: + pa_tagstruct_put_timeval(t, va_arg(va, struct timeval*)); + break; + + case PA_TAG_USEC: + pa_tagstruct_put_usec(t, va_arg(va, pa_usec_t)); + break; + + case PA_TAG_CHANNEL_MAP: + pa_tagstruct_put_channel_map(t, va_arg(va, pa_channel_map *)); + break; + + case PA_TAG_CVOLUME: + pa_tagstruct_put_cvolume(t, va_arg(va, pa_cvolume *)); + break; + + default: + abort(); + } + } + + va_end(va); +} + +int pa_tagstruct_get(pa_tagstruct *t, ...) { + va_list va; + int ret = 0; + + assert(t); + + va_start(va, t); + while (ret == 0) { + int tag = va_arg(va, int); + + if (tag == PA_TAG_INVALID) + break; + + switch (tag) { + case PA_TAG_STRING: + case PA_TAG_STRING_NULL: + ret = pa_tagstruct_gets(t, va_arg(va, const char**)); + break; + + case PA_TAG_U32: + ret = pa_tagstruct_getu32(t, va_arg(va, uint32_t*)); + break; + + case PA_TAG_U8: + ret = pa_tagstruct_getu8(t, va_arg(va, uint8_t*)); + break; + + case PA_TAG_U64: + ret = pa_tagstruct_getu64(t, va_arg(va, uint64_t*)); + break; + + case PA_TAG_SAMPLE_SPEC: + ret = pa_tagstruct_get_sample_spec(t, va_arg(va, pa_sample_spec*)); + break; + + case PA_TAG_ARBITRARY: { + const void **p = va_arg(va, const void**); + size_t size = va_arg(va, size_t); + ret = pa_tagstruct_get_arbitrary(t, p, size); + break; + } + + case PA_TAG_BOOLEAN_TRUE: + case PA_TAG_BOOLEAN_FALSE: + ret = pa_tagstruct_get_boolean(t, va_arg(va, int*)); + break; + + case PA_TAG_TIMEVAL: + ret = pa_tagstruct_get_timeval(t, va_arg(va, struct timeval*)); + break; + + case PA_TAG_USEC: + ret = pa_tagstruct_get_usec(t, va_arg(va, pa_usec_t*)); + break; + + case PA_TAG_CHANNEL_MAP: + ret = pa_tagstruct_get_channel_map(t, va_arg(va, pa_channel_map *)); + break; + + case PA_TAG_CVOLUME: + ret = pa_tagstruct_get_cvolume(t, va_arg(va, pa_cvolume *)); + break; + + + default: + abort(); + } + + } + + va_end(va); + return ret; +} diff --git a/src/polypcore/tagstruct.h b/src/polypcore/tagstruct.h new file mode 100644 index 00000000..59db67b0 --- /dev/null +++ b/src/polypcore/tagstruct.h @@ -0,0 +1,92 @@ +#ifndef footagstructhfoo +#define footagstructhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +#include +#include +#include + +typedef struct pa_tagstruct pa_tagstruct; + +enum { + PA_TAG_INVALID = 0, + PA_TAG_STRING = 't', + PA_TAG_STRING_NULL = 'N', + PA_TAG_U32 = 'L', + PA_TAG_U8 = 'B', + PA_TAG_U64 = 'R', + PA_TAG_SAMPLE_SPEC = 'a', + PA_TAG_ARBITRARY = 'x', + PA_TAG_BOOLEAN_TRUE = '1', + PA_TAG_BOOLEAN_FALSE = '0', + PA_TAG_BOOLEAN = PA_TAG_BOOLEAN_TRUE, + PA_TAG_TIMEVAL = 'T', + PA_TAG_USEC = 'U' /* 64bit unsigned */, + PA_TAG_CHANNEL_MAP = 'm', + PA_TAG_CVOLUME = 'v' +}; + + + +pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length); +void pa_tagstruct_free(pa_tagstruct*t); +uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l); + +int pa_tagstruct_eof(pa_tagstruct*t); +const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l); + +void pa_tagstruct_put(pa_tagstruct *t, ...); + +void pa_tagstruct_puts(pa_tagstruct*t, const char *s); +void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c); +void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i); +void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t i); +void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss); +void pa_tagstruct_put_arbitrary(pa_tagstruct*t, const void *p, size_t length); +void pa_tagstruct_put_boolean(pa_tagstruct*t, int b); +void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv); +void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u); +void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map); +void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume); + +int pa_tagstruct_get(pa_tagstruct *t, ...); + +int pa_tagstruct_gets(pa_tagstruct*t, const char **s); +int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c); +int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i); +int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *i); +int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss); +int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length); +int pa_tagstruct_get_boolean(pa_tagstruct *t, int *b); +int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv); +int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u); +int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map); +int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *v); + + +#endif diff --git a/src/polypcore/tokenizer.c b/src/polypcore/tokenizer.c new file mode 100644 index 00000000..5e0c1b16 --- /dev/null +++ b/src/polypcore/tokenizer.c @@ -0,0 +1,88 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "tokenizer.h" +#include "dynarray.h" +#include "xmalloc.h" +#include "gccmacro.h" + +struct pa_tokenizer { + pa_dynarray *dynarray; +}; + +static void token_free(void *p, PA_GCC_UNUSED void *userdata) { + pa_xfree(p); +} + +static void parse(pa_dynarray*a, const char *s, unsigned args) { + int infty = 0; + const char delimiter[] = " \t\n\r"; + const char *p; + assert(a && s); + + if (args == 0) + infty = 1; + + p = s+strspn(s, delimiter); + while (*p && (infty || args >= 2)) { + size_t l = strcspn(p, delimiter); + char *n = pa_xstrndup(p, l); + pa_dynarray_append(a, n); + p += l; + p += strspn(p, delimiter); + args--; + } + + if (args && *p) { + char *n = pa_xstrdup(p); + pa_dynarray_append(a, n); + } +} + +pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args) { + pa_tokenizer *t; + + t = pa_xmalloc(sizeof(pa_tokenizer)); + t->dynarray = pa_dynarray_new(); + assert(t->dynarray); + + parse(t->dynarray, s, args); + return t; +} + +void pa_tokenizer_free(pa_tokenizer *t) { + assert(t); + pa_dynarray_free(t->dynarray, token_free, NULL); + pa_xfree(t); +} + +const char *pa_tokenizer_get(pa_tokenizer *t, unsigned i) { + assert(t); + return pa_dynarray_get(t->dynarray, i); +} diff --git a/src/polypcore/tokenizer.h b/src/polypcore/tokenizer.h new file mode 100644 index 00000000..bedacb8a --- /dev/null +++ b/src/polypcore/tokenizer.h @@ -0,0 +1,32 @@ +#ifndef footokenizerhfoo +#define footokenizerhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef struct pa_tokenizer pa_tokenizer; + +pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args); +void pa_tokenizer_free(pa_tokenizer *t); + +const char *pa_tokenizer_get(pa_tokenizer *t, unsigned i); + +#endif diff --git a/src/polypcore/util.c b/src/polypcore/util.c new file mode 100644 index 00000000..4b6edb97 --- /dev/null +++ b/src/polypcore/util.c @@ -0,0 +1,1176 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SCHED_H +#include +#endif + +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif + +#ifdef HAVE_PTHREAD +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include + +#ifdef HAVE_PWD_H +#include +#endif +#ifdef HAVE_GRP_H +#include +#endif + +#include "winsock.h" + +#include "util.h" +#include "xmalloc.h" +#include "log.h" + +#ifndef OS_IS_WIN32 +#define PA_RUNTIME_PATH_PREFIX "/tmp/polypaudio-" +#define PATH_SEP '/' +#else +#define PA_RUNTIME_PATH_PREFIX "%TEMP%\\polypaudio-" +#define PATH_SEP '\\' +#endif + +#ifdef OS_IS_WIN32 + +#define POLYP_ROOTENV "POLYP_ROOT" + +int pa_set_root(HANDLE handle) { + char library_path[MAX_PATH + sizeof(POLYP_ROOTENV) + 1], *sep; + + strcpy(library_path, POLYP_ROOTENV "="); + + if (!GetModuleFileName(handle, library_path + sizeof(POLYP_ROOTENV), MAX_PATH)) + return 0; + + sep = strrchr(library_path, '\\'); + if (sep) + *sep = '\0'; + + if (_putenv(library_path) < 0) + return 0; + + return 1; +} + +#endif + +/** Make a file descriptor nonblock. Doesn't do any error checking */ +void pa_make_nonblock_fd(int fd) { +#ifdef O_NONBLOCK + int v; + assert(fd >= 0); + + if ((v = fcntl(fd, F_GETFL)) >= 0) + if (!(v & O_NONBLOCK)) + fcntl(fd, F_SETFL, v|O_NONBLOCK); +#elif defined(OS_IS_WIN32) + u_long arg = 1; + if (ioctlsocket(fd, FIONBIO, &arg) < 0) { + if (WSAGetLastError() == WSAENOTSOCK) + pa_log_warn(__FILE__": WARNING: Only sockets can be made non-blocking!\n"); + } +#else + pa_log_warn(__FILE__": WARNING: Non-blocking I/O not supported.!\n"); +#endif +} + +/** Creates a directory securely */ +int pa_make_secure_dir(const char* dir) { + struct stat st; + assert(dir); + +#ifdef OS_IS_WIN32 + if (mkdir(dir) < 0) +#else + if (mkdir(dir, 0700) < 0) +#endif + if (errno != EEXIST) + return -1; + +#ifdef HAVE_LSTAT + if (lstat(dir, &st) < 0) +#else + if (stat(dir, &st) < 0) +#endif + goto fail; + +#ifndef OS_IS_WIN32 + if (!S_ISDIR(st.st_mode) || (st.st_uid != getuid()) || ((st.st_mode & 0777) != 0700)) + goto fail; +#else + fprintf(stderr, "FIXME: pa_make_secure_dir()\n"); +#endif + + return 0; + +fail: + rmdir(dir); + return -1; +} + +/* Creates a the parent directory of the specified path securely */ +int pa_make_secure_parent_dir(const char *fn) { + int ret = -1; + char *slash, *dir = pa_xstrdup(fn); + + slash = pa_path_get_filename(dir); + if (slash == fn) + goto finish; + *(slash-1) = 0; + + if (pa_make_secure_dir(dir) < 0) + goto finish; + + ret = 0; + +finish: + pa_xfree(dir); + return ret; +} + + +/** Calls read() in a loop. Makes sure that as much as 'size' bytes, + * unless EOF is reached or an error occured */ +ssize_t pa_loop_read(int fd, void*data, size_t size) { + ssize_t ret = 0; + assert(fd >= 0 && data && size); + + while (size > 0) { + ssize_t r; + + if ((r = read(fd, data, size)) < 0) + return r; + + if (r == 0) + break; + + ret += r; + data = (uint8_t*) data + r; + size -= r; + } + + return ret; +} + +/** Similar to pa_loop_read(), but wraps write() */ +ssize_t pa_loop_write(int fd, const void*data, size_t size) { + ssize_t ret = 0; + assert(fd >= 0 && data && size); + + while (size > 0) { + ssize_t r; + + if ((r = write(fd, data, size)) < 0) + return r; + + if (r == 0) + break; + + ret += r; + data = (const uint8_t*) data + r; + size -= r; + } + + return ret; +} + +/* Print a warning messages in case that the given signal is not + * blocked or trapped */ +void pa_check_signal_is_blocked(int sig) { +#ifdef HAVE_SIGACTION + struct sigaction sa; + sigset_t set; + + /* If POSIX threads are supported use thread-aware + * pthread_sigmask() function, to check if the signal is + * blocked. Otherwise fall back to sigprocmask() */ + +#ifdef HAVE_PTHREAD + if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) { +#endif + if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) { + pa_log(__FILE__": sigprocmask() failed: %s\n", strerror(errno)); + return; + } +#ifdef HAVE_PTHREAD + } +#endif + + if (sigismember(&set, sig)) + return; + + /* Check whether the signal is trapped */ + + if (sigaction(sig, NULL, &sa) < 0) { + pa_log(__FILE__": sigaction() failed: %s\n", strerror(errno)); + return; + } + + if (sa.sa_handler != SIG_DFL) + return; + + pa_log(__FILE__": WARNING: %s is not trapped. This might cause malfunction!\n", pa_strsignal(sig)); +#else /* HAVE_SIGACTION */ + pa_log(__FILE__": WARNING: %s might not be trapped. This might cause malfunction!\n", pa_strsignal(sig)); +#endif +} + +/* The following function is based on an example from the GNU libc + * documentation. This function is similar to GNU's asprintf(). */ +char *pa_sprintf_malloc(const char *format, ...) { + int size = 100; + char *c = NULL; + + assert(format); + + for(;;) { + int r; + va_list ap; + + c = pa_xrealloc(c, size); + + va_start(ap, format); + r = vsnprintf(c, size, format, ap); + va_end(ap); + + if (r > -1 && r < size) + return c; + + if (r > -1) /* glibc 2.1 */ + size = r+1; + else /* glibc 2.0 */ + size *= 2; + } +} + +/* Same as the previous function, but use a va_list instead of an + * ellipsis */ +char *pa_vsprintf_malloc(const char *format, va_list ap) { + int size = 100; + char *c = NULL; + + assert(format); + + for(;;) { + int r; + c = pa_xrealloc(c, size); + r = vsnprintf(c, size, format, ap); + + if (r > -1 && r < size) + return c; + + if (r > -1) /* glibc 2.1 */ + size = r+1; + else /* glibc 2.0 */ + size *= 2; + } +} + +/* Return the current username in the specified string buffer. */ +char *pa_get_user_name(char *s, size_t l) { + char *p; + char buf[1024]; + +#ifdef HAVE_PWD_H + struct passwd pw, *r; +#endif + + assert(s && l > 0); + + if (!(p = getenv("USER")) && !(p = getenv("LOGNAME")) && !(p = getenv("USERNAME"))) { +#ifdef HAVE_PWD_H + +#ifdef HAVE_GETPWUID_R + if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { +#else + /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) + * that do not support getpwuid_r. */ + if ((r = getpwuid(getuid())) == NULL) { +#endif + snprintf(s, l, "%lu", (unsigned long) getuid()); + return s; + } + + p = r->pw_name; + +#elif defined(OS_IS_WIN32) /* HAVE_PWD_H */ + DWORD size = sizeof(buf); + + if (!GetUserName(buf, &size)) + return NULL; + + p = buf; + +#else /* HAVE_PWD_H */ + return NULL; +#endif /* HAVE_PWD_H */ + } + + return pa_strlcpy(s, p, l); +} + +/* Return the current hostname in the specified buffer. */ +char *pa_get_host_name(char *s, size_t l) { + assert(s && l > 0); + if (gethostname(s, l) < 0) { + pa_log(__FILE__": gethostname(): %s\n", strerror(errno)); + return NULL; + } + s[l-1] = 0; + return s; +} + +/* Return the home directory of the current user */ +char *pa_get_home_dir(char *s, size_t l) { + char *e; + +#ifdef HAVE_PWD_H + char buf[1024]; + struct passwd pw, *r; +#endif + + assert(s && l); + + if ((e = getenv("HOME"))) + return pa_strlcpy(s, e, l); + + if ((e = getenv("USERPROFILE"))) + return pa_strlcpy(s, e, l); + +#ifdef HAVE_PWD_H +#ifdef HAVE_GETPWUID_R + if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { + pa_log(__FILE__": getpwuid_r() failed\n"); +#else + /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) + * that do not support getpwuid_r. */ + if ((r = getpwuid(getuid())) == NULL) { + pa_log(__FILE__": getpwuid_r() failed\n"); +#endif + return NULL; + } + + return pa_strlcpy(s, r->pw_dir, l); +#else /* HAVE_PWD_H */ + return NULL; +#endif +} + +/* Similar to OpenBSD's strlcpy() function */ +char *pa_strlcpy(char *b, const char *s, size_t l) { + assert(b && s && l > 0); + + strncpy(b, s, l); + b[l-1] = 0; + return b; +} + +int pa_gettimeofday(struct timeval *tv) { +#ifdef HAVE_GETTIMEOFDAY + return gettimeofday(tv, NULL); +#elif defined(OS_IS_WIN32) + /* + * Copied from implementation by Steven Edwards (LGPL). + * Found on wine mailing list. + */ + +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define EPOCHFILETIME (116444736000000000i64) +#else +#define EPOCHFILETIME (116444736000000000LL) +#endif + + FILETIME ft; + LARGE_INTEGER li; + __int64 t; + + if (tv) { + GetSystemTimeAsFileTime(&ft); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + t = li.QuadPart; /* In 100-nanosecond intervals */ + t -= EPOCHFILETIME; /* Offset to the Epoch time */ + t /= 10; /* In microseconds */ + tv->tv_sec = (long)(t / 1000000); + tv->tv_usec = (long)(t % 1000000); + } + + return 0; +#else +#error "Platform lacks gettimeofday() or equivalent function." +#endif +} + +/* Calculate the difference between the two specfified timeval + * timestamsps. */ +pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { + pa_usec_t r; + assert(a && b); + + /* Check which whan is the earlier time and swap the two arguments if reuqired. */ + if (pa_timeval_cmp(a, b) < 0) { + const struct timeval *c; + c = a; + a = b; + b = c; + } + + /* Calculate the second difference*/ + r = ((pa_usec_t) a->tv_sec - b->tv_sec)* 1000000; + + /* Calculate the microsecond difference */ + if (a->tv_usec > b->tv_usec) + r += ((pa_usec_t) a->tv_usec - b->tv_usec); + else if (a->tv_usec < b->tv_usec) + r -= ((pa_usec_t) b->tv_usec - a->tv_usec); + + return r; +} + +/* Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwse */ +int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { + assert(a && b); + + if (a->tv_sec < b->tv_sec) + return -1; + + if (a->tv_sec > b->tv_sec) + return 1; + + if (a->tv_usec < b->tv_usec) + return -1; + + if (a->tv_usec > b->tv_usec) + return 1; + + return 0; +} + +/* Return the time difference between now and the specified timestamp */ +pa_usec_t pa_timeval_age(const struct timeval *tv) { + struct timeval now; + assert(tv); + pa_gettimeofday(&now); + return pa_timeval_diff(&now, tv); +} + +/* Add the specified time inmicroseconds to the specified timeval structure */ +void pa_timeval_add(struct timeval *tv, pa_usec_t v) { + unsigned long secs; + assert(tv); + + secs = (v/1000000); + tv->tv_sec += (unsigned long) secs; + v -= secs*1000000; + + tv->tv_usec += v; + + /* Normalize */ + while (tv->tv_usec >= 1000000) { + tv->tv_sec++; + tv->tv_usec -= 1000000; + } +} + +#define NICE_LEVEL (-15) + +/* Raise the priority of the current process as much as possible and +sensible: set the nice level to -15 and enable realtime scheduling if +supported.*/ +void pa_raise_priority(void) { + +#ifdef HAVE_SYS_RESOURCE_H + if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) + pa_log_warn(__FILE__": setpriority() failed: %s\n", strerror(errno)); + else + pa_log_info(__FILE__": Successfully gained nice level %i.\n", NICE_LEVEL); +#endif + +#ifdef _POSIX_PRIORITY_SCHEDULING + { + struct sched_param sp; + + if (sched_getparam(0, &sp) < 0) { + pa_log(__FILE__": sched_getparam() failed: %s\n", strerror(errno)); + return; + } + + sp.sched_priority = 1; + if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) { + pa_log_warn(__FILE__": sched_setscheduler() failed: %s\n", strerror(errno)); + return; + } + + pa_log_info(__FILE__": Successfully enabled SCHED_FIFO scheduling.\n"); + } +#endif + +#ifdef OS_IS_WIN32 + if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) + pa_log_warn(__FILE__": SetPriorityClass() failed: 0x%08X\n", GetLastError()); + else + pa_log_info(__FILE__": Successfully gained high priority class.\n"); +#endif +} + +/* Reset the priority to normal, inverting the changes made by pa_raise_priority() */ +void pa_reset_priority(void) { +#ifdef OS_IS_WIN32 + SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); +#endif + +#ifdef _POSIX_PRIORITY_SCHEDULING + { + struct sched_param sp; + sched_getparam(0, &sp); + sp.sched_priority = 0; + sched_setscheduler(0, SCHED_OTHER, &sp); + } +#endif + +#ifdef HAVE_SYS_RESOURCE_H + setpriority(PRIO_PROCESS, 0, 0); +#endif +} + +/* Set the FD_CLOEXEC flag for a fd */ +int pa_fd_set_cloexec(int fd, int b) { + +#ifdef FD_CLOEXEC + int v; + assert(fd >= 0); + + if ((v = fcntl(fd, F_GETFD, 0)) < 0) + return -1; + + v = (v & ~FD_CLOEXEC) | (b ? FD_CLOEXEC : 0); + + if (fcntl(fd, F_SETFD, v) < 0) + return -1; +#endif + + return 0; +} + +/* Return the binary file name of the current process. Works on Linux + * only. This shoul be used for eyecandy only, don't rely on return + * non-NULL! */ +char *pa_get_binary_name(char *s, size_t l) { + +#ifdef HAVE_READLINK + char path[PATH_MAX]; + int i; + assert(s && l); + + /* This works on Linux only */ + + snprintf(path, sizeof(path), "/proc/%u/exe", (unsigned) getpid()); + if ((i = readlink(path, s, l-1)) < 0) + return NULL; + + s[i] = 0; + return s; +#elif defined(OS_IS_WIN32) + char path[PATH_MAX]; + if (!GetModuleFileName(NULL, path, PATH_MAX)) + return NULL; + pa_strlcpy(s, pa_path_get_filename(path), l); + return s; +#else + return NULL; +#endif +} + +/* Return a pointer to the filename inside a path (which is the last + * component). */ +char *pa_path_get_filename(const char *p) { + char *fn; + + if ((fn = strrchr(p, PATH_SEP))) + return fn+1; + + return (char*) p; +} + +/* Try to parse a boolean string value.*/ +int pa_parse_boolean(const char *v) { + + if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on")) + return 1; + else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off")) + return 0; + + return -1; +} + +/* Split the specified string wherever one of the strings in delimiter + * occurs. Each time it is called returns a newly allocated string + * with pa_xmalloc(). The variable state points to, should be + * initiallized to NULL before the first call. */ +char *pa_split(const char *c, const char *delimiter, const char**state) { + const char *current = *state ? *state : c; + size_t l; + + if (!*current) + return NULL; + + l = strcspn(current, delimiter); + *state = current+l; + + if (**state) + (*state)++; + + return pa_xstrndup(current, l); +} + +/* What is interpreted as whitespace? */ +#define WHITESPACE " \t\n" + +/* Split a string into words. Otherwise similar to pa_split(). */ +char *pa_split_spaces(const char *c, const char **state) { + const char *current = *state ? *state : c; + size_t l; + + if (!*current || *c == 0) + return NULL; + + current += strspn(current, WHITESPACE); + l = strcspn(current, WHITESPACE); + + *state = current+l; + + return pa_xstrndup(current, l); +} + +/* Return the name of an UNIX signal. Similar to GNU's strsignal() */ +const char *pa_strsignal(int sig) { + switch(sig) { + case SIGINT: return "SIGINT"; + case SIGTERM: return "SIGTERM"; +#ifdef SIGUSR1 + case SIGUSR1: return "SIGUSR1"; +#endif +#ifdef SIGUSR2 + case SIGUSR2: return "SIGUSR2"; +#endif +#ifdef SIGXCPU + case SIGXCPU: return "SIGXCPU"; +#endif +#ifdef SIGPIPE + case SIGPIPE: return "SIGPIPE"; +#endif +#ifdef SIGCHLD + case SIGCHLD: return "SIGCHLD"; +#endif +#ifdef SIGHUP + case SIGHUP: return "SIGHUP"; +#endif + default: return "UNKNOWN SIGNAL"; + } +} + +#ifdef HAVE_GRP_H + +/* Check whether the specified GID and the group name match */ +static int is_group(gid_t gid, const char *name) { + struct group group, *result = NULL; + long n; + void *data; + int r = -1; + +#ifdef HAVE_GETGRGID_R +#ifdef _SC_GETGR_R_SIZE_MAX + n = sysconf(_SC_GETGR_R_SIZE_MAX); +#else + n = -1; +#endif + if (n < 0) n = 512; + data = pa_xmalloc(n); + + if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) { + pa_log(__FILE__ ": getgrgid_r(%u) failed: %s\n", gid, strerror(errno)); + goto finish; + } + + + r = strcmp(name, result->gr_name) == 0; + +finish: + pa_xfree(data); +#else + /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not + * support getgrgid_r. */ + if ((result = getgrgid(gid)) == NULL) { + pa_log(__FILE__ ": getgrgid(%u) failed: %s\n", gid, strerror(errno)); + goto finish; + } + + r = strcmp(name, result->gr_name) == 0; + +finish: +#endif + + return r; +} + +/* Check the current user is member of the specified group */ +int pa_uid_in_group(const char *name, gid_t *gid) { + GETGROUPS_T *gids, tgid; + int n = sysconf(_SC_NGROUPS_MAX); + int r = -1, i; + + assert(n > 0); + + gids = pa_xmalloc(sizeof(GETGROUPS_T)*n); + + if ((n = getgroups(n, gids)) < 0) { + pa_log(__FILE__": getgroups() failed: %s\n", strerror(errno)); + goto finish; + } + + for (i = 0; i < n; i++) { + if (is_group(gids[i], name) > 0) { + *gid = gids[i]; + r = 1; + goto finish; + } + } + + if (is_group(tgid = getgid(), name) > 0) { + *gid = tgid; + r = 1; + goto finish; + } + + r = 0; + +finish: + + pa_xfree(gids); + return r; +} + +#else /* HAVE_GRP_H */ + +int pa_uid_in_group(const char *name, gid_t *gid) { + return -1; +} + +#endif + +/* Lock or unlock a file entirely. + (advisory on UNIX, mandatory on Windows) */ +int pa_lock_fd(int fd, int b) { +#ifdef F_SETLKW + struct flock flock; + + /* Try a R/W lock first */ + + flock.l_type = b ? F_WRLCK : F_UNLCK; + flock.l_whence = SEEK_SET; + flock.l_start = 0; + flock.l_len = 0; + + if (fcntl(fd, F_SETLKW, &flock) >= 0) + return 0; + + /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */ + if (b && errno == EBADF) { + flock.l_type = F_RDLCK; + if (fcntl(fd, F_SETLKW, &flock) >= 0) + return 0; + } + + pa_log(__FILE__": %slock failed: %s\n", !b ? "un" : "", strerror(errno)); +#endif + +#ifdef OS_IS_WIN32 + HANDLE h = (HANDLE)_get_osfhandle(fd); + + if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) + return 0; + if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) + return 0; + + pa_log(__FILE__": %slock failed: 0x%08X\n", !b ? "un" : "", GetLastError()); +#endif + + return -1; +} + +/* Remove trailing newlines from a string */ +char* pa_strip_nl(char *s) { + assert(s); + + s[strcspn(s, "\r\n")] = 0; + return s; +} + +/* Create a temporary lock file and lock it. */ +int pa_lock_lockfile(const char *fn) { + int fd = -1; + assert(fn); + + for (;;) { + struct stat st; + + if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { + pa_log(__FILE__": failed to create lock file '%s': %s\n", fn, strerror(errno)); + goto fail; + } + + if (pa_lock_fd(fd, 1) < 0) { + pa_log(__FILE__": failed to lock file '%s'.\n", fn); + goto fail; + } + + if (fstat(fd, &st) < 0) { + pa_log(__FILE__": failed to fstat() file '%s'.\n", fn); + goto fail; + } + + /* Check wheter the file has been removed meanwhile. When yes, restart this loop, otherwise, we're done */ + if (st.st_nlink >= 1) + break; + + if (pa_lock_fd(fd, 0) < 0) { + pa_log(__FILE__": failed to unlock file '%s'.\n", fn); + goto fail; + } + + if (close(fd) < 0) { + pa_log(__FILE__": failed to close file '%s'.\n", fn); + goto fail; + } + + fd = -1; + } + + return fd; + +fail: + + if (fd >= 0) + close(fd); + + return -1; +} + +/* Unlock a temporary lcok file */ +int pa_unlock_lockfile(const char *fn, int fd) { + int r = 0; + assert(fn && fd >= 0); + + if (unlink(fn) < 0) { + pa_log_warn(__FILE__": WARNING: unable to remove lock file '%s': %s\n", fn, strerror(errno)); + r = -1; + } + + if (pa_lock_fd(fd, 0) < 0) { + pa_log_warn(__FILE__": WARNING: failed to unlock file '%s'.\n", fn); + r = -1; + } + + if (close(fd) < 0) { + pa_log_warn(__FILE__": WARNING: failed to close lock file '%s': %s\n", fn, strerror(errno)); + r = -1; + } + + return r; +} + +/* Try to open a configuration file. If "env" is specified, open the + * value of the specified environment variable. Otherwise look for a + * file "local" in the home directory or a file "global" in global + * file system. If "result" is non-NULL, a pointer to a newly + * allocated buffer containing the used configuration file is + * stored there.*/ +FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result) { + const char *fn; + char h[PATH_MAX]; + +#ifdef OS_IS_WIN32 + char buf[PATH_MAX]; + + if (!getenv(POLYP_ROOTENV)) + pa_set_root(NULL); +#endif + + if (env && (fn = getenv(env))) { +#ifdef OS_IS_WIN32 + if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX)) + return NULL; + fn = buf; +#endif + + if (result) + *result = pa_xstrdup(fn); + + return fopen(fn, "r"); + } + + if (local && pa_get_home_dir(h, sizeof(h))) { + FILE *f; + char *lfn; + + fn = lfn = pa_sprintf_malloc("%s/%s", h, local); + +#ifdef OS_IS_WIN32 + if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) + return NULL; + fn = buf; +#endif + + f = fopen(fn, "r"); + + if (f || errno != ENOENT) { + if (result) + *result = pa_xstrdup(fn); + pa_xfree(lfn); + return f; + } + + pa_xfree(lfn); + } + + if (!global) { + if (result) + *result = NULL; + errno = ENOENT; + return NULL; + } + +#ifdef OS_IS_WIN32 + if (!ExpandEnvironmentStrings(global, buf, PATH_MAX)) + return NULL; + global = buf; +#endif + + if (result) + *result = pa_xstrdup(global); + + return fopen(global, "r"); +} + +/* Format the specified data as a hexademical string */ +char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) { + size_t i = 0, j = 0; + const char hex[] = "0123456789abcdef"; + assert(d && s && slength > 0); + + while (i < dlength && j+3 <= slength) { + s[j++] = hex[*d >> 4]; + s[j++] = hex[*d & 0xF]; + + d++; + i++; + } + + s[j < slength ? j : slength] = 0; + return s; +} + +/* Convert a hexadecimal digit to a number or -1 if invalid */ +static int hexc(char c) { + if (c >= '0' && c <= '9') + return c - '0'; + + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + + return -1; +} + +/* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */ +size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) { + size_t j = 0; + assert(p && d); + + while (j < dlength && *p) { + int b; + + if ((b = hexc(*(p++))) < 0) + return (size_t) -1; + + d[j] = (uint8_t) (b << 4); + + if (!*p) + return (size_t) -1; + + if ((b = hexc(*(p++))) < 0) + return (size_t) -1; + + d[j] |= (uint8_t) b; + j++; + } + + return j; +} + +/* Return the fully qualified domain name in *s */ +char *pa_get_fqdn(char *s, size_t l) { + char hn[256]; +#ifdef HAVE_GETADDRINFO + struct addrinfo *a, hints; +#endif + + if (!pa_get_host_name(hn, sizeof(hn))) + return NULL; + +#ifdef HAVE_GETADDRINFO + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_CANONNAME; + + if (getaddrinfo(hn, NULL, &hints, &a) < 0 || !a || !a->ai_canonname || !*a->ai_canonname) + return pa_strlcpy(s, hn, l); + + pa_strlcpy(s, a->ai_canonname, l); + freeaddrinfo(a); + return s; +#else + return pa_strlcpy(s, hn, l); +#endif +} + +/* Returns nonzero when *s starts with *pfx */ +int pa_startswith(const char *s, const char *pfx) { + size_t l; + assert(s && pfx); + l = strlen(pfx); + + return strlen(s) >= l && strncmp(s, pfx, l) == 0; +} + +/* if fn is null return the polypaudio run time path in s (/tmp/polypaudio) + * if fn is non-null and starts with / return fn in s + * otherwise append fn to the run time path and return it in s */ +char *pa_runtime_path(const char *fn, char *s, size_t l) { + char u[256]; + +#ifndef OS_IS_WIN32 + if (fn && *fn == '/') +#else + if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\') +#endif + return pa_strlcpy(s, fn, l); + + if (fn) + snprintf(s, l, "%s%s%c%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn); + else + snprintf(s, l, "%s%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u))); + +#ifdef OS_IS_WIN32 + { + char buf[l]; + strcpy(buf, s); + ExpandEnvironmentStrings(buf, s, l); + } +#endif + + return s; +} + +/* Wait t milliseconds */ +int pa_msleep(unsigned long t) { +#ifdef OS_IS_WIN32 + Sleep(t); + return 0; +#elif defined(HAVE_NANOSLEEP) + struct timespec ts; + + ts.tv_sec = t/1000; + ts.tv_nsec = (t % 1000) * 1000000; + + return nanosleep(&ts, NULL); +#else +#error "Platform lacks a sleep function." +#endif +} + +/* Convert the string s to a signed integer in *ret_i */ +int pa_atoi(const char *s, int32_t *ret_i) { + char *x = NULL; + long l; + assert(s && ret_i); + + l = strtol(s, &x, 0); + + if (!x || *x) + return -1; + + *ret_i = (int32_t) l; + + return 0; +} + +/* Convert the string s to an unsigned integer in *ret_u */ +int pa_atou(const char *s, uint32_t *ret_u) { + char *x = NULL; + unsigned long l; + assert(s && ret_u); + + l = strtoul(s, &x, 0); + + if (!x || *x) + return -1; + + *ret_u = (uint32_t) l; + + return 0; +} diff --git a/src/polypcore/util.h b/src/polypcore/util.h new file mode 100644 index 00000000..3dc6c945 --- /dev/null +++ b/src/polypcore/util.h @@ -0,0 +1,99 @@ +#ifndef fooutilhfoo +#define fooutilhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +#include "gccmacro.h" +#include + +struct timeval; + +void pa_make_nonblock_fd(int fd); + +int pa_make_secure_dir(const char* dir); +int pa_make_secure_parent_dir(const char *fn); + +ssize_t pa_loop_read(int fd, void*data, size_t size); +ssize_t pa_loop_write(int fd, const void*data, size_t size); + +void pa_check_signal_is_blocked(int sig); + +char *pa_sprintf_malloc(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +char *pa_vsprintf_malloc(const char *format, va_list ap); + +char *pa_strlcpy(char *b, const char *s, size_t l); + +char *pa_get_user_name(char *s, size_t l); +char *pa_get_host_name(char *s, size_t l); +char *pa_get_fqdn(char *s, size_t l); +char *pa_get_binary_name(char *s, size_t l); +char *pa_get_home_dir(char *s, size_t l); + +char *pa_path_get_filename(const char *p); + +int pa_gettimeofday(struct timeval *tv); +pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); +int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); +pa_usec_t pa_timeval_age(const struct timeval *tv); +void pa_timeval_add(struct timeval *tv, pa_usec_t v); + +void pa_raise_priority(void); +void pa_reset_priority(void); + +int pa_fd_set_cloexec(int fd, int b); + +int pa_parse_boolean(const char *s); + +char *pa_split(const char *c, const char*delimiters, const char **state); +char *pa_split_spaces(const char *c, const char **state); + +char *pa_strip_nl(char *s); + +const char *pa_strsignal(int sig); + +int pa_uid_in_group(const char *name, gid_t *gid); + +int pa_lock_fd(int fd, int b); + +int pa_lock_lockfile(const char *fn); +int pa_unlock_lockfile(const char *fn, int fd); + +FILE *pa_open_config_file(const char *env, const char *global, const char *local, char **result); + +char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength); +size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength); + +int pa_startswith(const char *s, const char *pfx); + +char *pa_runtime_path(const char *fn, char *s, size_t l); + +int pa_msleep(unsigned long t); + +int pa_atoi(const char *s, int32_t *ret_i); +int pa_atou(const char *s, uint32_t *ret_u); + +#endif diff --git a/src/polypcore/winsock.h b/src/polypcore/winsock.h new file mode 100644 index 00000000..b1e0f7d4 --- /dev/null +++ b/src/polypcore/winsock.h @@ -0,0 +1,23 @@ +#ifndef foowinsockhfoo +#define foowinsockhfoo + +#ifdef HAVE_WINSOCK2_H +#include + +#define ESHUTDOWN WSAESHUTDOWN +#define ECONNRESET WSAECONNRESET +#define ECONNABORTED WSAECONNABORTED +#define ENETRESET WSAENETRESET +#define EINPROGRESS WSAEINPROGRESS +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define ETIMEDOUT WSAETIMEDOUT +#define ECONNREFUSED WSAECONNREFUSED +#define EHOSTUNREACH WSAEHOSTUNREACH + +#endif + +#ifdef HAVE_WS2TCPIP_H +#include +#endif + +#endif diff --git a/src/polypcore/x11prop.c b/src/polypcore/x11prop.c new file mode 100644 index 00000000..e57fc136 --- /dev/null +++ b/src/polypcore/x11prop.c @@ -0,0 +1,70 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include "x11prop.h" + + +void pa_x11_set_prop(Display *d, const char *name, const char *data) { + Atom a = XInternAtom(d, name, False); + XChangeProperty(d, RootWindow(d, 0), a, XA_STRING, 8, PropModeReplace, (const unsigned char*) data, strlen(data)+1); +} + +void pa_x11_del_prop(Display *d, const char *name) { + Atom a = XInternAtom(d, name, False); + XDeleteProperty(d, RootWindow(d, 0), a); +} + +char* pa_x11_get_prop(Display *d, const char *name, char *p, size_t l) { + Atom actual_type; + int actual_format; + unsigned long nitems; + unsigned long nbytes_after; + unsigned char *prop = NULL; + char *ret = NULL; + + Atom a = XInternAtom(d, name, False); + if (XGetWindowProperty(d, RootWindow(d, 0), a, 0, (l+2)/4, False, XA_STRING, &actual_type, &actual_format, &nitems, &nbytes_after, &prop) != Success) + goto finish; + + if (actual_type != XA_STRING) + goto finish; + + memcpy(p, prop, nitems); + p[nitems] = 0; + + ret = p; + +finish: + + if (prop) + XFree(prop); + + return ret; +} diff --git a/src/polypcore/x11prop.h b/src/polypcore/x11prop.h new file mode 100644 index 00000000..5531c640 --- /dev/null +++ b/src/polypcore/x11prop.h @@ -0,0 +1,33 @@ +#ifndef foox11prophfoo +#define foox11prophfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include + +void pa_x11_set_prop(Display *d, const char *name, const char *data); +void pa_x11_del_prop(Display *d, const char *name); +char* pa_x11_get_prop(Display *d, const char *name, char *p, size_t l); + +#endif diff --git a/src/polypcore/x11wrap.c b/src/polypcore/x11wrap.c new file mode 100644 index 00000000..e20a50a6 --- /dev/null +++ b/src/polypcore/x11wrap.c @@ -0,0 +1,235 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include "llist.h" +#include "x11wrap.h" +#include "xmalloc.h" +#include "log.h" +#include "props.h" + +typedef struct pa_x11_internal pa_x11_internal; + +struct pa_x11_internal { + PA_LLIST_FIELDS(pa_x11_internal); + pa_x11_wrapper *wrapper; + pa_io_event* io_event; + int fd; +}; + +struct pa_x11_wrapper { + pa_core *core; + int ref; + + char *property_name; + Display *display; + + pa_defer_event* defer_event; + pa_io_event* io_event; + + PA_LLIST_HEAD(pa_x11_client, clients); + PA_LLIST_HEAD(pa_x11_internal, internals); +}; + +struct pa_x11_client { + PA_LLIST_FIELDS(pa_x11_client); + pa_x11_wrapper *wrapper; + int (*callback)(pa_x11_wrapper *w, XEvent *e, void *userdata); + void *userdata; +}; + +/* Dispatch all pending X11 events */ +static void work(pa_x11_wrapper *w) { + assert(w && w->ref >= 1); + + while (XPending(w->display)) { + pa_x11_client *c; + XEvent e; + XNextEvent(w->display, &e); + + for (c = w->clients; c; c = c->next) { + assert(c->callback); + if (c->callback(w, &e, c->userdata) != 0) + break; + } + } +} + +/* IO notification event for the X11 display connection */ +static void display_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { + pa_x11_wrapper *w = userdata; + assert(m && e && fd >= 0 && w && w->ref >= 1); + work(w); +} + +/* Deferred notification event. Called once each main loop iteration */ +static void defer_event(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { + pa_x11_wrapper *w = userdata; + assert(m && e && w && w->ref >= 1); + work(w); +} + +/* IO notification event for X11 internal connections */ +static void internal_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { + pa_x11_wrapper *w = userdata; + assert(m && e && fd >= 0 && w && w->ref >= 1); + + XProcessInternalConnection(w->display, fd); +} + +/* Add a new IO source for the specified X11 internal connection */ +static pa_x11_internal* x11_internal_add(pa_x11_wrapper *w, int fd) { + pa_x11_internal *i; + assert(i && fd >= 0); + + i = pa_xmalloc(sizeof(pa_x11_internal)); + i->wrapper = w; + i->io_event = w->core->mainloop->io_new(w->core->mainloop, fd, PA_IO_EVENT_INPUT, internal_io_event, w); + i->fd = fd; + + PA_LLIST_PREPEND(pa_x11_internal, w->internals, i); + return i; +} + +/* Remove an IO source for an X11 internal connection */ +static void x11_internal_remove(pa_x11_wrapper *w, pa_x11_internal *i) { + assert(i); + + PA_LLIST_REMOVE(pa_x11_internal, w->internals, i); + w->core->mainloop->io_free(i->io_event); + pa_xfree(i); +} + +/* Implementation of XConnectionWatchProc */ +static void x11_watch(Display *display, XPointer userdata, int fd, Bool opening, XPointer *watch_data) { + pa_x11_wrapper *w = (pa_x11_wrapper*) userdata; + assert(display && w && fd >= 0); + + if (opening) + *watch_data = (XPointer) x11_internal_add(w, fd); + else + x11_internal_remove(w, (pa_x11_internal*) *watch_data); +} + +static pa_x11_wrapper* x11_wrapper_new(pa_core *c, const char *name, const char *t) { + pa_x11_wrapper*w; + Display *d; + int r; + + if (!(d = XOpenDisplay(name))) { + pa_log(__FILE__": XOpenDisplay() failed\n"); + return NULL; + } + + w = pa_xmalloc(sizeof(pa_x11_wrapper)); + w->core = c; + w->ref = 1; + w->property_name = pa_xstrdup(t); + w->display = d; + + PA_LLIST_HEAD_INIT(pa_x11_client, w->clients); + PA_LLIST_HEAD_INIT(pa_x11_internal, w->internals); + + w->defer_event = c->mainloop->defer_new(c->mainloop, defer_event, w); + w->io_event = c->mainloop->io_new(c->mainloop, ConnectionNumber(d), PA_IO_EVENT_INPUT, display_io_event, w); + + XAddConnectionWatch(d, x11_watch, (XPointer) w); + + r = pa_property_set(c, w->property_name, w); + assert(r >= 0); + + return w; +} + +static void x11_wrapper_free(pa_x11_wrapper*w) { + int r; + assert(w); + + r = pa_property_remove(w->core, w->property_name); + assert(r >= 0); + + assert(!w->clients); + + XRemoveConnectionWatch(w->display, x11_watch, (XPointer) w); + XCloseDisplay(w->display); + + w->core->mainloop->io_free(w->io_event); + w->core->mainloop->defer_free(w->defer_event); + + while (w->internals) + x11_internal_remove(w, w->internals); + + pa_xfree(w->property_name); + pa_xfree(w); +} + +pa_x11_wrapper* pa_x11_wrapper_get(pa_core *c, const char *name) { + char t[256]; + pa_x11_wrapper *w; + assert(c); + + snprintf(t, sizeof(t), "x11-wrapper%s%s", name ? "-" : "", name ? name : ""); + if ((w = pa_property_get(c, t))) + return pa_x11_wrapper_ref(w); + + return x11_wrapper_new(c, name, t); +} + +pa_x11_wrapper* pa_x11_wrapper_ref(pa_x11_wrapper *w) { + assert(w && w->ref >= 1); + w->ref++; + return w; +} + +void pa_x11_wrapper_unref(pa_x11_wrapper* w) { + assert(w && w->ref >= 1); + + if (!(--w->ref)) + x11_wrapper_free(w); +} + +Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w) { + assert(w && w->ref >= 1); + return w->display; +} + +pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata) { + pa_x11_client *c; + assert(w && w->ref >= 1); + + c = pa_xmalloc(sizeof(pa_x11_client)); + c->wrapper = w; + c->callback = cb; + c->userdata = userdata; + + PA_LLIST_PREPEND(pa_x11_client, w->clients, c); + + return c; +} + +void pa_x11_client_free(pa_x11_client *c) { + assert(c && c->wrapper && c->wrapper->ref >= 1); + + PA_LLIST_REMOVE(pa_x11_client, c->wrapper->clients, c); + pa_xfree(c); +} diff --git a/src/polypcore/x11wrap.h b/src/polypcore/x11wrap.h new file mode 100644 index 00000000..15645168 --- /dev/null +++ b/src/polypcore/x11wrap.h @@ -0,0 +1,52 @@ +#ifndef foox11wraphfoo +#define foox11wraphfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "core.h" + +typedef struct pa_x11_wrapper pa_x11_wrapper; + +/* Return the X11 wrapper for this core. In case no wrapper was + existant before, allocate a new one */ +pa_x11_wrapper* pa_x11_wrapper_get(pa_core *c, const char *name); + +/* Increase the wrapper's reference count by one */ +pa_x11_wrapper* pa_x11_wrapper_ref(pa_x11_wrapper *w); + +/* Decrease the reference counter of an X11 wrapper object */ +void pa_x11_wrapper_unref(pa_x11_wrapper* w); + +/* Return the X11 display object for this connection */ +Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w); + +typedef struct pa_x11_client pa_x11_client; + +/* Register an X11 client, that is called for each X11 event */ +pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata); + +/* Free an X11 client object */ +void pa_x11_client_free(pa_x11_client *c); + +#endif diff --git a/src/polypcore/xmalloc.c b/src/polypcore/xmalloc.c new file mode 100644 index 00000000..bf366347 --- /dev/null +++ b/src/polypcore/xmalloc.c @@ -0,0 +1,122 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "memory.h" +#include "util.h" +#include "xmalloc.h" +#include "gccmacro.h" + +/* Make sure not to allocate more than this much memory. */ +#define MAX_ALLOC_SIZE (1024*1024*20) /* 20MB */ + +/* #undef malloc */ +/* #undef free */ +/* #undef realloc */ +/* #undef strndup */ +/* #undef strdup */ + +static void oom(void) PA_GCC_NORETURN; + +/** called in case of an OOM situation. Prints an error message and + * exits */ +static void oom(void) { + static const char e[] = "Not enough memory\n"; + pa_loop_write(STDERR_FILENO, e, sizeof(e)-1); +#ifdef SIGQUIT + raise(SIGQUIT); +#endif + _exit(1); +} + +void* pa_xmalloc(size_t size) { + void *p; + assert(size > 0); + assert(size < MAX_ALLOC_SIZE); + + if (!(p = malloc(size))) + oom(); + + return p; +} + +void* pa_xmalloc0(size_t size) { + void *p; + assert(size > 0); + assert(size < MAX_ALLOC_SIZE); + + if (!(p = calloc(1, size))) + oom(); + + return p; +} + +void *pa_xrealloc(void *ptr, size_t size) { + void *p; + assert(size > 0); + assert(size < MAX_ALLOC_SIZE); + + if (!(p = realloc(ptr, size))) + oom(); + return p; +} + +void* pa_xmemdup(const void *p, size_t l) { + if (!p) + return NULL; + else { + char *r = pa_xmalloc(l); + memcpy(r, p, l); + return r; + } +} + +char *pa_xstrdup(const char *s) { + if (!s) + return NULL; + + return pa_xmemdup(s, strlen(s)+1); +} + +char *pa_xstrndup(const char *s, size_t l) { + if (!s) + return NULL; + else { + char *r; + size_t t = strlen(s); + + if (t > l) + t = l; + + r = pa_xmemdup(s, t+1); + r[t] = 0; + return r; + } +} + diff --git a/src/polypcore/xmalloc.h b/src/polypcore/xmalloc.h new file mode 100644 index 00000000..2946011a --- /dev/null +++ b/src/polypcore/xmalloc.h @@ -0,0 +1,58 @@ +#ifndef foomemoryhfoo +#define foomemoryhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +void* pa_xmalloc(size_t l); +void *pa_xmalloc0(size_t l); +void *pa_xrealloc(void *ptr, size_t size); +#define pa_xfree free + +char *pa_xstrdup(const char *s); +char *pa_xstrndup(const char *s, size_t l); + +void* pa_xmemdup(const void *p, size_t l); + +/** Internal helper for pa_xnew() */ +static inline void* pa_xnew_internal(unsigned n, size_t k) { + assert(n < INT_MAX/k); + return pa_xmalloc(n*k); +} + +/** Allocate n new structures of the specified type. */ +#define pa_xnew(type, n) ((type*) pa_xnew_internal((n), sizeof(type))) + +/** Internal helper for pa_xnew0() */ +static inline void* pa_xnew0_internal(unsigned n, size_t k) { + assert(n < INT_MAX/k); + return pa_xmalloc0(n*k); +} + +/** Same as pa_xnew() but set the memory to zero */ +#define pa_xnew0(type, n) ((type*) pa_xnew0_internal((n), sizeof(type))) + +#endif diff --git a/src/tests/cpulimit-test.c b/src/tests/cpulimit-test.c new file mode 100644 index 00000000..97a8a0dd --- /dev/null +++ b/src/tests/cpulimit-test.c @@ -0,0 +1,92 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "../daemon/cpulimit.h" +#include +#include + +#ifdef TEST2 +#include +#endif + +/* A simple example for testing the cpulimit subsystem */ + +static time_t start; + +#ifdef TEST2 + +static void func(pa_mainloop_api *m, PA_GCC_UNUSED pa_signal_event *e, PA_GCC_UNUSED int sig, PA_GCC_UNUSED void *userdata) { + time_t now; + time(&now); + + if ((now - start) >= 30) { + m->quit(m, 1); + fprintf(stderr, "Test failed\n"); + } else + raise(SIGUSR1); +} + +#endif + +int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { + pa_mainloop *m; + + m = pa_mainloop_new(); + assert(m); + + pa_cpu_limit_init(pa_mainloop_get_api(m)); + + time(&start); + +#ifdef TEST2 + pa_signal_init(pa_mainloop_get_api(m)); + pa_signal_new(SIGUSR1, func, NULL); + raise(SIGUSR1); + pa_mainloop_run(m, NULL); + pa_signal_done(); +#else + for (;;) { + time_t now; + time(&now); + + if ((now - start) >= 30) { + fprintf(stderr, "Test failed\n"); + break; + } + } +#endif + + pa_cpu_limit_done(); + + pa_mainloop_free(m); + + return 0; +} diff --git a/src/tests/mainloop-test.c b/src/tests/mainloop-test.c new file mode 100644 index 00000000..f62c9693 --- /dev/null +++ b/src/tests/mainloop-test.c @@ -0,0 +1,146 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include + +#ifdef GLIB_MAIN_LOOP + +#include +#include + +static GMainLoop* glib_main_loop = NULL; + +#if GLIB_MAJOR_VERSION >= 2 +#define GLIB20 +#else +#undef GLIB20 +#endif + + +#else /* GLIB_MAIN_LOOP */ +#include +#endif /* GLIB_MAIN_LOOP */ + +static pa_defer_event *de; + +static void iocb(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { + unsigned char c; + read(fd, &c, sizeof(c)); + fprintf(stderr, "IO EVENT: %c\n", c < 32 ? '.' : c); + a->defer_enable(de, 1); +} + +static void dcb(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { + fprintf(stderr, "DEFER EVENT\n"); + a->defer_enable(e, 0); +} + +static void tcb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) { + fprintf(stderr, "TIME EVENT\n"); + +#if defined(GLIB_MAIN_LOOP) && defined(GLIB20) + g_main_loop_quit(glib_main_loop); +#elif defined(GLIB_MAIN_LOOP) + g_main_quit(glib_main_loop); +#else + a->quit(a, 0); +#endif +} + +int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { + pa_mainloop_api *a; + pa_io_event *ioe; + pa_time_event *te; + struct timeval tv; + +#ifdef GLIB_MAIN_LOOP + pa_glib_mainloop *g; + +#ifdef GLIB20 + glib_main_loop = g_main_loop_new(NULL, FALSE); + assert(glib_main_loop); + + g = pa_glib_mainloop_new(NULL); +#else /* GLIB20 */ + glib_main_loop = g_main_new(FALSE); + assert(glib_main_loop); + + g = pa_glib_mainloop_new(); +#endif /* GLIB20 */ + assert(g); + + a = pa_glib_mainloop_get_api(g); + assert(a); +#else /* GLIB_MAIN_LOOP */ + pa_mainloop *m; + + m = pa_mainloop_new(); + assert(m); + + a = pa_mainloop_get_api(m); + assert(a); +#endif /* GLIB_MAIN_LOOP */ + + ioe = a->io_new(a, 0, PA_IO_EVENT_INPUT, iocb, NULL); + assert(ioe); + + de = a->defer_new(a, dcb, NULL); + assert(de); + + pa_gettimeofday(&tv); + tv.tv_sec += 10; + te = a->time_new(a, &tv, tcb, NULL); + +#if defined(GLIB_MAIN_LOOP) && defined(GLIB20) + g_main_loop_run(glib_main_loop); +#elif defined(GLIB_MAIN_LOOP) + g_main_run(glib_main_loop); +#else + pa_mainloop_run(m, NULL); +#endif + + a->time_free(te); + a->defer_free(de); + a->io_free(ioe); + +#ifdef GLIB_MAIN_LOOP + pa_glib_mainloop_free(g); +#ifdef GLIB20 + g_main_loop_unref(glib_main_loop); +#else + g_main_destroy(glib_main_loop); +#endif +#else + pa_mainloop_free(m); +#endif + + return 0; +} diff --git a/src/tests/mcalign-test.c b/src/tests/mcalign-test.c new file mode 100644 index 00000000..861c38c1 --- /dev/null +++ b/src/tests/mcalign-test.c @@ -0,0 +1,96 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* A simple program for testing pa_mcalign */ + +int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { + pa_mcalign *a = pa_mcalign_new(11, NULL); + pa_memchunk c; + + pa_memchunk_reset(&c); + + srand(time(NULL)); + + for (;;) { + ssize_t r; + size_t l; + + if (!c.memblock) { + c.memblock = pa_memblock_new(2048, NULL); + c.index = c.length = 0; + } + + assert(c.index < c.memblock->length); + + l = c.memblock->length - c.index; + + l = l <= 1 ? l : rand() % (l-1) +1 ; + + if ((r = read(STDIN_FILENO, (uint8_t*) c.memblock->data + c.index, l)) <= 0) { + fprintf(stderr, "read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); + break; + } + + c.length = r; + pa_mcalign_push(a, &c); + fprintf(stderr, "Read %d bytes\n", r); + + c.index += r; + + if (c.index >= c.memblock->length) { + pa_memblock_unref(c.memblock); + pa_memchunk_reset(&c); + } + + for (;;) { + pa_memchunk t; + + if (pa_mcalign_pop(a, &t) < 0) + break; + + pa_loop_write(STDOUT_FILENO, (uint8_t*) t.memblock->data + t.index, t.length); + fprintf(stderr, "Wrote %lu bytes.\n", (unsigned long) t.length); + + pa_memblock_unref(t.memblock); + } + } + + pa_mcalign_free(a); + + if (c.memblock) + pa_memblock_unref(c.memblock); +} diff --git a/src/tests/pacat-simple.c b/src/tests/pacat-simple.c new file mode 100644 index 00000000..8b3a7b22 --- /dev/null +++ b/src/tests/pacat-simple.c @@ -0,0 +1,101 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#define BUFSIZE 1024 + +int main(PA_GCC_UNUSED int argc, char*argv[]) { + + /* The Sample format to use */ + static const pa_sample_spec ss = { + .format = PA_SAMPLE_S16LE, + .rate = 44100, + .channels = 2 + }; + + pa_simple *s = NULL; + int ret = 1; + int error; + + /* Create a new playback stream */ + if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, &error))) { + fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); + goto finish; + } + + for (;;) { + uint8_t buf[BUFSIZE]; + ssize_t r; + +#if 0 + pa_usec_t latency; + + if ((latency = pa_simple_get_playback_latency(s, &error)) == (pa_usec_t) -1) { + fprintf(stderr, __FILE__": pa_simple_get_playback_latency() failed: %s\n", pa_strerror(error)); + goto finish; + } + + fprintf(stderr, "%0.0f usec \r", (float)latency); +#endif + + /* Read some data ... */ + if ((r = read(STDIN_FILENO, buf, sizeof(buf))) <= 0) { + if (r == 0) /* EOF */ + break; + + fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno)); + goto finish; + } + + /* ... and play it */ + if (pa_simple_write(s, buf, r, &error) < 0) { + fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error)); + goto finish; + } + } + + /* Make sure that every single sample was played */ + if (pa_simple_drain(s, &error) < 0) { + fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(error)); + goto finish; + } + + ret = 0; + +finish: + + if (s) + pa_simple_free(s); + + return ret; +} diff --git a/src/tests/parec-simple.c b/src/tests/parec-simple.c new file mode 100644 index 00000000..10eaea8d --- /dev/null +++ b/src/tests/parec-simple.c @@ -0,0 +1,100 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#define BUFSIZE 1024 + +/* A simple routine calling UNIX write() in a loop */ +static ssize_t loop_write(int fd, const void*data, size_t size) { + ssize_t ret = 0; + + while (size > 0) { + ssize_t r; + + if ((r = write(fd, data, size)) < 0) + return r; + + if (r == 0) + break; + + ret += r; + data = (const uint8_t*) data + r; + size -= r; + } + + return ret; +} + +int main(PA_GCC_UNUSED int argc, char*argv[]) { + /* The sample type to use */ + static const pa_sample_spec ss = { + .format = PA_SAMPLE_S16LE, + .rate = 44100, + .channels = 2 + }; + pa_simple *s = NULL; + int ret = 1; + int error; + + /* Create the recording stream */ + if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, &error))) { + fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); + goto finish; + } + + for (;;) { + uint8_t buf[BUFSIZE]; + ssize_t r; + + /* Record some data ... */ + if (pa_simple_read(s, buf, sizeof(buf), &error) < 0) { + fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error)); + goto finish; + } + + /* And write it to STDOUT */ + if ((r = loop_write(STDOUT_FILENO, buf, sizeof(buf))) <= 0) { + fprintf(stderr, __FILE__": write() failed: %s\n", strerror(errno)); + goto finish; + } + } + + ret = 0; + +finish: + + if (s) + pa_simple_free(s); + + return ret; +} diff --git a/src/tests/strlist-test.c b/src/tests/strlist-test.c new file mode 100644 index 00000000..14543112 --- /dev/null +++ b/src/tests/strlist-test.c @@ -0,0 +1,42 @@ +#include + +#include +#include +#include + +int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char* argv[]) { + char *t, *u; + pa_strlist *l = NULL; + + l = pa_strlist_prepend(l, "e"); + l = pa_strlist_prepend(l, "d"); + l = pa_strlist_prepend(l, "c"); + l = pa_strlist_prepend(l, "b"); + l = pa_strlist_prepend(l, "a"); + + t = pa_strlist_tostring(l); + pa_strlist_free(l); + + fprintf(stderr, "1: %s\n", t); + + l = pa_strlist_parse(t); + pa_xfree(t); + + t = pa_strlist_tostring(l); + fprintf(stderr, "2: %s\n", t); + pa_xfree(t); + + l = pa_strlist_pop(l, &u); + fprintf(stderr, "3: %s\n", u); + pa_xfree(u); + + l = pa_strlist_remove(l, "c"); + + t = pa_strlist_tostring(l); + fprintf(stderr, "4: %s\n", t); + pa_xfree(t); + + pa_strlist_free(l); + + return 0; +} diff --git a/src/tests/voltest.c b/src/tests/voltest.c new file mode 100644 index 00000000..58f1da00 --- /dev/null +++ b/src/tests/voltest.c @@ -0,0 +1,20 @@ +/* $Id$ */ + +#include + +#include +#include + +int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { + pa_volume_t v; + + for (v = PA_VOLUME_MUTED; v <= PA_VOLUME_NORM*2; v += 256) { + + double dB = pa_sw_volume_to_dB(v); + double f = pa_sw_volume_to_linear(v); + + printf("Volume: %3i; percent: %i%%; decibel %0.2f; linear = %0.2f; volume(decibel): %3i; volume(linear): %3i\n", + v, (v*100)/PA_VOLUME_NORM, dB, f, pa_sw_volume_from_dB(dB), pa_sw_volume_from_linear(f)); + + } +} diff --git a/src/utils/esdcompat.sh.in b/src/utils/esdcompat.sh.in new file mode 100755 index 00000000..76023f52 --- /dev/null +++ b/src/utils/esdcompat.sh.in @@ -0,0 +1,98 @@ +#!/bin/sh + +# $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +VERSION_STRING="@PACKAGE_NAME@ esd wrapper @PACKAGE_VERSION@" + +fail() { + echo "ERROR: $1" + exit 1 +} + +ARGS=" --log-target=syslog" + +for N in $(seq $#) ; do + + case "$1" in + "") + ;; + + -v|--version) + echo "$VERSION_STRING" + exit 0 + ;; + + -h|--help) + cat < +#endif + +#include +#include +#include + +#include +#include +#include +#include + +static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { + fprintf(stderr, "Got signal, exiting\n"); + m->quit(m, 0); +} + +static void dump_server(const pa_browse_info *i) { + char t[16]; + + if (i->cookie) + snprintf(t, sizeof(t), "0x%08x", *i->cookie); + + printf("server: %s\n" + "server-version: %s\n" + "user-name: %s\n" + "fqdn: %s\n" + "cookie: %s\n", + i->server, + i->server_version ? i->server_version : "n/a", + i->user_name ? i->user_name : "n/a", + i->fqdn ? i->fqdn : "n/a", + i->cookie ? t : "n/a"); +} + +static void dump_device(const pa_browse_info *i) { + char t[16], ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + if (i->sample_spec) + pa_sample_spec_snprint(ss, sizeof(ss), i->sample_spec); + + if (i->typeid) + pa_typeid_to_string(*i->typeid, t, sizeof(t)); + + printf("device: %s\n" + "description: %s\n" + "type: %s\n" + "sample spec: %s\n", + i->device, + i->description ? i->description : "n/a", + i->typeid ? t : "n/a", + i->sample_spec ? ss : "n/a"); + +} + +static void browser_callback(pa_browser *b, pa_browse_opcode c, const pa_browse_info *i, void *userdata) { + assert(b && i); + + switch (c) { + + case PA_BROWSE_NEW_SERVER: + printf("\n=> new server <%s>\n", i->name); + dump_server(i); + break; + + case PA_BROWSE_NEW_SINK: + printf("\n=> new sink <%s>\n", i->name); + dump_server(i); + dump_device(i); + break; + + case PA_BROWSE_NEW_SOURCE: + printf("\n=> new source <%s>\n", i->name); + dump_server(i); + dump_device(i); + break; + + case PA_BROWSE_REMOVE: + printf("\n=> removed service <%s>\n", i->name); + break; + + default: + ; + } +} + + +int main(int argc, char *argv[]) { + pa_mainloop *mainloop = NULL; + pa_browser *browser = NULL; + int ret = 1, r; + + if (!(mainloop = pa_mainloop_new())) + goto finish; + + r = pa_signal_init(pa_mainloop_get_api(mainloop)); + assert(r == 0); + pa_signal_new(SIGINT, exit_signal_callback, NULL); + pa_signal_new(SIGTERM, exit_signal_callback, NULL); + signal(SIGPIPE, SIG_IGN); + + if (!(browser = pa_browser_new(pa_mainloop_get_api(mainloop)))) + goto finish; + + pa_browser_set_callback(browser, browser_callback, NULL); + + ret = 0; + pa_mainloop_run(mainloop, &ret); + +finish: + if (mainloop) { + pa_signal_done(); + pa_mainloop_free(mainloop); + } + + return ret; +} diff --git a/src/utils/pacat.c b/src/utils/pacat.c new file mode 100644 index 00000000..bd2b64fd --- /dev/null +++ b/src/utils/pacat.c @@ -0,0 +1,541 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if PA_API_VERSION != 8 +#error Invalid Polypaudio API version +#endif + +static enum { RECORD, PLAYBACK } mode = PLAYBACK; + +static pa_context *context = NULL; +static pa_stream *stream = NULL; +static pa_mainloop_api *mainloop_api = NULL; + +static void *buffer = NULL; +static size_t buffer_length = 0, buffer_index = 0; + +static pa_io_event* stdio_event = NULL; + +static char *stream_name = NULL, *client_name = NULL, *device = NULL; + +static int verbose = 0; +static pa_volume_t volume = PA_VOLUME_NORM; + +static pa_sample_spec sample_spec = { + .format = PA_SAMPLE_S16LE, + .rate = 44100, + .channels = 2 +}; + +/* A shortcut for terminating the application */ +static void quit(int ret) { + assert(mainloop_api); + mainloop_api->quit(mainloop_api, ret); +} + +/* Write some data to the stream */ +static void do_stream_write(size_t length) { + size_t l; + assert(length); + + if (!buffer || !buffer_length) + return; + + l = length; + if (l > buffer_length) + l = buffer_length; + + pa_stream_write(stream, (uint8_t*) buffer + buffer_index, l, NULL, 0); + buffer_length -= l; + buffer_index += l; + + if (!buffer_length) { + free(buffer); + buffer = NULL; + buffer_index = buffer_length = 0; + } +} + +/* This is called whenever new data may be written to the stream */ +static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { + assert(s && length); + + if (stdio_event) + mainloop_api->io_enable(stdio_event, PA_IO_EVENT_INPUT); + + if (!buffer) + return; + + do_stream_write(length); +} + +/* This is called whenever new data may is available */ +static void stream_read_callback(pa_stream *s, const void*data, size_t length, void *userdata) { + assert(s && data && length); + + if (stdio_event) + mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT); + + if (buffer) { + fprintf(stderr, "Buffer overrun, dropping incoming data\n"); + return; + } + + buffer = malloc(buffer_length = length); + assert(buffer); + memcpy(buffer, data, length); + buffer_index = 0; +} + +/* This routine is called whenever the stream state changes */ +static void stream_state_callback(pa_stream *s, void *userdata) { + assert(s); + + switch (pa_stream_get_state(s)) { + case PA_STREAM_CREATING: + case PA_STREAM_TERMINATED: + break; + + case PA_STREAM_READY: + if (verbose) + fprintf(stderr, "Stream successfully created\n"); + break; + + case PA_STREAM_FAILED: + default: + fprintf(stderr, "Stream error: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + quit(1); + } +} + +/* This is called whenever the context status changes */ +static void context_state_callback(pa_context *c, void *userdata) { + assert(c); + + switch (pa_context_get_state(c)) { + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + + case PA_CONTEXT_READY: + + assert(c && !stream); + + if (verbose) + fprintf(stderr, "Connection established.\n"); + + stream = pa_stream_new(c, stream_name, &sample_spec, NULL); + assert(stream); + + pa_stream_set_state_callback(stream, stream_state_callback, NULL); + pa_stream_set_write_callback(stream, stream_write_callback, NULL); + pa_stream_set_read_callback(stream, stream_read_callback, NULL); + + if (mode == PLAYBACK) { + pa_cvolume cv; + pa_stream_connect_playback(stream, device, NULL, 0, pa_cvolume_set(&cv, PA_CHANNELS_MAX, volume)); + } else + pa_stream_connect_record(stream, device, NULL, 0); + + break; + + case PA_CONTEXT_TERMINATED: + quit(0); + break; + + case PA_CONTEXT_FAILED: + default: + fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + } +} + +/* Connection draining complete */ +static void context_drain_complete(pa_context*c, void *userdata) { + pa_context_disconnect(c); +} + +/* Stream draining complete */ +static void stream_drain_complete(pa_stream*s, int success, void *userdata) { + pa_operation *o; + + if (!success) { + fprintf(stderr, "Failed to drain stream: %s\n", pa_strerror(pa_context_errno(context))); + quit(1); + } + + if (verbose) + fprintf(stderr, "Playback stream drained.\n"); + + pa_stream_disconnect(stream); + pa_stream_unref(stream); + stream = NULL; + + if (!(o = pa_context_drain(context, context_drain_complete, NULL))) + pa_context_disconnect(context); + else { + pa_operation_unref(o); + + if (verbose) + fprintf(stderr, "Draining connection to server.\n"); + } +} + +/* New data on STDIN **/ +static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { + size_t l, w = 0; + ssize_t r; + assert(a == mainloop_api && e && stdio_event == e); + + if (buffer) { + mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL); + return; + } + + if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY || !(l = w = pa_stream_writable_size(stream))) + l = 4096; + + buffer = malloc(l); + assert(buffer); + if ((r = read(fd, buffer, l)) <= 0) { + if (r == 0) { + if (verbose) + fprintf(stderr, "Got EOF.\n"); + pa_operation_unref(pa_stream_drain(stream, stream_drain_complete, NULL)); + } else { + fprintf(stderr, "read() failed: %s\n", strerror(errno)); + quit(1); + } + + mainloop_api->io_free(stdio_event); + stdio_event = NULL; + return; + } + + buffer_length = r; + buffer_index = 0; + + if (w) + do_stream_write(w); +} + +/* Some data may be written to STDOUT */ +static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { + ssize_t r; + assert(a == mainloop_api && e && stdio_event == e); + + if (!buffer) { + mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL); + return; + } + + assert(buffer_length); + + if ((r = write(fd, (uint8_t*) buffer+buffer_index, buffer_length)) <= 0) { + fprintf(stderr, "write() failed: %s\n", strerror(errno)); + quit(1); + + mainloop_api->io_free(stdio_event); + stdio_event = NULL; + return; + } + + buffer_length -= r; + buffer_index += r; + + if (!buffer_length) { + free(buffer); + buffer = NULL; + buffer_length = buffer_index = 0; + } +} + +/* UNIX signal to quit recieved */ +static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { + if (verbose) + fprintf(stderr, "Got signal, exiting.\n"); + quit(0); + +} + +/* Show the current latency */ +static void stream_get_latency_callback(pa_stream *s, const pa_latency_info *i, void *userdata) { + pa_usec_t total; + int negative = 0; + assert(s); + + if (!i) { + fprintf(stderr, "Failed to get latency: %s\n", pa_strerror(pa_context_errno(context))); + quit(1); + return; + } + + total = pa_stream_get_latency(s, i, &negative); + + fprintf(stderr, "Latency: buffer: %0.0f usec; sink: %0.0f usec; source: %0.0f usec; transport: %0.0f usec; total: %0.0f usec; synchronized clocks: %s.\n", + (float) i->buffer_usec, (float) i->sink_usec, (float) i->source_usec, (float) i->transport_usec, (float) total * (negative?-1:1), + i->synchronized_clocks ? "yes" : "no"); +} + +/* Someone requested that the latency is shown */ +static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { + fprintf(stderr, "Got SIGUSR1, requesting latency.\n"); + pa_operation_unref(pa_stream_get_latency_info(stream, stream_get_latency_callback, NULL)); +} + + +static void help(const char *argv0) { + + printf("%s [options]\n\n" + " -h, --help Show this help\n" + " --version Show version\n\n" + " -r, --record Create a connection for recording\n" + " -p, --playback Create a connection for playback\n\n" + " -v, --verbose Enable verbose operations\n\n" + " -s, --server=SERVER The name of the server to connect to\n" + " -d, --device=DEVICE The name of the sink/source to connect to\n" + " -n, --client-name=NAME How to call this client on the server\n" + " --stream-name=NAME How to call this stream on the server\n" + " --volume=VOLUME Specify the initial (linear) volume in range 0...256\n" + " --rate=SAMPLERATE The sample rate in Hz (defaults to 44100)\n" + " --format=SAMPLEFORMAT The sample type, one of s16le, s16be, u8, float32le,\n" + " float32be, ulaw, alaw (defaults to s16ne)\n" + " --channels=CHANNELS The number of channels, 1 for mono, 2 for stereo\n" + " (defaults to 2)\n", + argv0); +} + +enum { + ARG_VERSION = 256, + ARG_STREAM_NAME, + ARG_VOLUME, + ARG_SAMPLERATE, + ARG_SAMPLEFORMAT, + ARG_CHANNELS +}; + +int main(int argc, char *argv[]) { + pa_mainloop* m = NULL; + int ret = 1, r, c; + char *bn, *server = NULL; + + static const struct option long_options[] = { + {"record", 0, NULL, 'r'}, + {"playback", 0, NULL, 'p'}, + {"device", 1, NULL, 'd'}, + {"server", 1, NULL, 's'}, + {"client-name", 1, NULL, 'n'}, + {"stream-name", 1, NULL, ARG_STREAM_NAME}, + {"version", 0, NULL, ARG_VERSION}, + {"help", 0, NULL, 'h'}, + {"verbose", 0, NULL, 'v'}, + {"volume", 1, NULL, ARG_VOLUME}, + {"rate", 1, NULL, ARG_SAMPLERATE}, + {"format", 1, NULL, ARG_SAMPLEFORMAT}, + {"channels", 1, NULL, ARG_CHANNELS}, + {NULL, 0, NULL, 0} + }; + + if (!(bn = strrchr(argv[0], '/'))) + bn = argv[0]; + else + bn++; + + if (strstr(bn, "rec") || strstr(bn, "mon")) + mode = RECORD; + else if (strstr(bn, "cat") || strstr(bn, "play")) + mode = PLAYBACK; + + while ((c = getopt_long(argc, argv, "rpd:s:n:hv", long_options, NULL)) != -1) { + + switch (c) { + case 'h' : + help(bn); + ret = 0; + goto quit; + + case ARG_VERSION: + printf("pacat "PACKAGE_VERSION"\nCompiled with libpolyp %s\nLinked with libpolyp %s\n", pa_get_headers_version(), pa_get_library_version()); + ret = 0; + goto quit; + + case 'r': + mode = RECORD; + break; + + case 'p': + mode = PLAYBACK; + break; + + case 'd': + free(device); + device = strdup(optarg); + break; + + case 's': + free(server); + server = strdup(optarg); + break; + + case 'n': + free(client_name); + client_name = strdup(optarg); + break; + + case ARG_STREAM_NAME: + free(stream_name); + stream_name = strdup(optarg); + break; + + case 'v': + verbose = 1; + break; + + case ARG_VOLUME: { + int v = atoi(optarg); + volume = v < 0 ? 0 : v; + break; + } + + case ARG_CHANNELS: + sample_spec.channels = atoi(optarg); + break; + + case ARG_SAMPLEFORMAT: + sample_spec.format = pa_parse_sample_format(optarg); + break; + + case ARG_SAMPLERATE: + sample_spec.rate = atoi(optarg); + break; + + default: + goto quit; + } + } + + if (!client_name) + client_name = strdup(bn); + + if (!stream_name) + stream_name = strdup(client_name); + + if (!pa_sample_spec_valid(&sample_spec)) { + fprintf(stderr, "Invalid sample specification\n"); + goto quit; + } + + if (verbose) { + char t[PA_SAMPLE_SPEC_SNPRINT_MAX]; + pa_sample_spec_snprint(t, sizeof(t), &sample_spec); + fprintf(stderr, "Opening a %s stream with sample specification '%s'.\n", mode == RECORD ? "recording" : "playback", t); + } + + /* Set up a new main loop */ + if (!(m = pa_mainloop_new())) { + fprintf(stderr, "pa_mainloop_new() failed.\n"); + goto quit; + } + + mainloop_api = pa_mainloop_get_api(m); + + r = pa_signal_init(mainloop_api); + assert(r == 0); + pa_signal_new(SIGINT, exit_signal_callback, NULL); + pa_signal_new(SIGTERM, exit_signal_callback, NULL); +#ifdef SIGUSR1 + pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL); +#endif +#ifdef SIGPIPE + signal(SIGPIPE, SIG_IGN); +#endif + + if (!(stdio_event = mainloop_api->io_new(mainloop_api, + mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO, + mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT, + mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) { + fprintf(stderr, "source_io() failed.\n"); + goto quit; + } + + /* Create a new connection context */ + if (!(context = pa_context_new(mainloop_api, client_name))) { + fprintf(stderr, "pa_context_new() failed.\n"); + goto quit; + } + + pa_context_set_state_callback(context, context_state_callback, NULL); + + /* Connect the context */ + pa_context_connect(context, server, 1, NULL); + + /* Run the main loop */ + if (pa_mainloop_run(m, &ret) < 0) { + fprintf(stderr, "pa_mainloop_run() failed.\n"); + goto quit; + } + +quit: + if (stream) + pa_stream_unref(stream); + + if (context) + pa_context_unref(context); + + if (stdio_event) { + assert(mainloop_api); + mainloop_api->io_free(stdio_event); + } + + if (m) { + pa_signal_done(); + pa_mainloop_free(m); + } + + free(buffer); + + free(server); + free(device); + free(client_name); + free(stream_name); + + return ret; +} diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c new file mode 100644 index 00000000..4054bc2c --- /dev/null +++ b/src/utils/pacmd.c @@ -0,0 +1,183 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +int main(PA_GCC_UNUSED int main, PA_GCC_UNUSED char*argv[]) { + pid_t pid ; + int fd = -1; + int ret = 1, i; + struct sockaddr_un sa; + char ibuf[256], obuf[256]; + size_t ibuf_index, ibuf_length, obuf_index, obuf_length; + fd_set ifds, ofds; + + if (pa_pid_file_check_running(&pid) < 0) { + pa_log(__FILE__": no Polypaudio daemon running\n"); + goto fail; + } + + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + pa_log(__FILE__": socket(PF_UNIX, SOCK_STREAM, 0): %s\n", strerror(errno)); + goto fail; + } + + memset(&sa, 0, sizeof(sa)); + sa.sun_family = AF_UNIX; + pa_runtime_path("cli", sa.sun_path, sizeof(sa.sun_path)); + + for (i = 0; i < 5; i++) { + int r; + + if ((r = connect(fd, (struct sockaddr*) &sa, sizeof(sa))) < 0 && (errno != ECONNREFUSED && errno != ENOENT)) { + pa_log(__FILE__": connect() failed: %s\n", strerror(errno)); + goto fail; + } + + if (r >= 0) + break; + + if (pa_pid_file_kill(SIGUSR2, NULL) < 0) { + pa_log(__FILE__": failed to kill Polypaudio daemon.\n"); + goto fail; + } + + pa_msleep(50); + } + + if (i >= 5) { + pa_log(__FILE__": daemon not responding.\n"); + goto fail; + } + + ibuf_index = ibuf_length = obuf_index = obuf_length = 0; + + + FD_ZERO(&ifds); + FD_SET(0, &ifds); + FD_SET(fd, &ifds); + + FD_ZERO(&ofds); + + for (;;) { + if (select(FD_SETSIZE, &ifds, &ofds, NULL, NULL) < 0) { + pa_log(__FILE__": select() failed: %s\n", strerror(errno)); + goto fail; + } + + if (FD_ISSET(0, &ifds)) { + ssize_t r; + assert(!ibuf_length); + + if ((r = read(0, ibuf, sizeof(ibuf))) <= 0) { + if (r == 0) + break; + + pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + goto fail; + } + + ibuf_length = (size_t) r; + ibuf_index = 0; + } + + if (FD_ISSET(fd, &ifds)) { + ssize_t r; + assert(!obuf_length); + + if ((r = read(fd, obuf, sizeof(obuf))) <= 0) { + if (r == 0) + break; + + pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + goto fail; + } + + obuf_length = (size_t) r; + obuf_index = 0; + } + + if (FD_ISSET(1, &ofds)) { + ssize_t r; + assert(obuf_length); + + if ((r = write(1, obuf + obuf_index, obuf_length)) < 0) { + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + goto fail; + } + + obuf_length -= (size_t) r; + obuf_index += obuf_index; + + } + + if (FD_ISSET(fd, &ofds)) { + ssize_t r; + assert(ibuf_length); + + if ((r = write(fd, ibuf + ibuf_index, ibuf_length)) < 0) { + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + goto fail; + } + + ibuf_length -= (size_t) r; + ibuf_index += obuf_index; + + } + + FD_ZERO(&ifds); + FD_ZERO(&ofds); + + if (obuf_length <= 0) + FD_SET(fd, &ifds); + else + FD_SET(1, &ofds); + + if (ibuf_length <= 0) + FD_SET(0, &ifds); + else + FD_SET(fd, &ofds); + } + + + ret = 0; + +fail: + if (fd >= 0) + close(fd); + + return ret; +} diff --git a/src/utils/pactl.c b/src/utils/pactl.c new file mode 100644 index 00000000..23bd924b --- /dev/null +++ b/src/utils/pactl.c @@ -0,0 +1,784 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#if PA_API_VERSION != 8 +#error Invalid Polypaudio API version +#endif + +#define BUFSIZE 1024 + +static pa_context *context = NULL; +static pa_mainloop_api *mainloop_api = NULL; + +static char *device = NULL, *sample_name = NULL; + +static SNDFILE *sndfile = NULL; +static pa_stream *sample_stream = NULL; +static pa_sample_spec sample_spec; +static size_t sample_length = 0; + +static int actions = 1; + +static int nl = 0; + +static enum { + NONE, + EXIT, + STAT, + UPLOAD_SAMPLE, + PLAY_SAMPLE, + REMOVE_SAMPLE, + LIST +} action = NONE; + +static void quit(int ret) { + assert(mainloop_api); + mainloop_api->quit(mainloop_api, ret); +} + + +static void context_drain_complete(pa_context *c, void *userdata) { + pa_context_disconnect(c); +} + +static void drain(void) { + pa_operation *o; + if (!(o = pa_context_drain(context, context_drain_complete, NULL))) + pa_context_disconnect(context); + else + pa_operation_unref(o); +} + + +static void complete_action(void) { + assert(actions > 0); + + if (!(--actions)) + drain(); +} + +static void stat_callback(pa_context *c, const pa_stat_info *i, void *userdata) { + char s[128]; + if (!i) { + fprintf(stderr, "Failed to get statistics: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + pa_bytes_snprint(s, sizeof(s), i->memblock_total_size); + printf("Currently in use: %u blocks containing %s bytes total.\n", i->memblock_total, s); + + pa_bytes_snprint(s, sizeof(s), i->memblock_allocated_size); + printf("Allocated during whole lifetime: %u blocks containing %s bytes total.\n", i->memblock_allocated, s); + + pa_bytes_snprint(s, sizeof(s), i->scache_size); + printf("Sample cache size: %s\n", s); + + complete_action(); +} + +static void get_server_info_callback(pa_context *c, const pa_server_info *i, void *useerdata) { + char s[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + if (!i) { + fprintf(stderr, "Failed to get server information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); + + printf("User name: %s\n" + "Host Name: %s\n" + "Server Name: %s\n" + "Server Version: %s\n" + "Default Sample Specification: %s\n" + "Default Sink: %s\n" + "Default Source: %s\n" + "Cookie: %08x\n", + i->user_name, + i->host_name, + i->server_name, + i->server_version, + s, + i->default_sink_name, + i->default_source_name, + i->cookie); + + complete_action(); +} + +static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) { + char s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get sink information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + printf("*** Sink #%u ***\n" + "Name: %s\n" + "Driver: %s\n" + "Description: %s\n" + "Sample Specification: %s\n" + "Channel Map: %s\n" + "Owner Module: %u\n" + "Volume: %s\n" + "Monitor Source: %u\n" + "Latency: %0.0f usec\n", + i->index, + i->name, + i->driver, + i->description, + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), + i->owner_module, + pa_cvolume_snprint(cv, sizeof(cv), &i->volume), + i->monitor_source, + (double) i->latency); + +} + +static void get_source_info_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) { + char s[PA_SAMPLE_SPEC_SNPRINT_MAX], t[32], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get source information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + snprintf(t, sizeof(t), "%u", i->monitor_of_sink); + + printf("*** Source #%u ***\n" + "Name: %s\n" + "Driver: %s\n" + "Description: %s\n" + "Sample Specification: %s\n" + "Channel Map: %s\n" + "Owner Module: %u\n" + "Monitor of Sink: %s\n" + "Latency: %0.0f usec\n", + i->index, + i->driver, + i->name, + i->description, + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), + i->owner_module, + i->monitor_of_sink != PA_INVALID_INDEX ? t : "no", + (double) i->latency); + +} + +static void get_module_info_callback(pa_context *c, const pa_module_info *i, int is_last, void *userdata) { + char t[32]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get module information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + snprintf(t, sizeof(t), "%u", i->n_used); + + printf("*** Module #%u ***\n" + "Name: %s\n" + "Argument: %s\n" + "Usage counter: %s\n" + "Auto unload: %s\n", + i->index, + i->name, + i->argument, + i->n_used != PA_INVALID_INDEX ? t : "n/a", + i->auto_unload ? "yes" : "no"); +} + +static void get_client_info_callback(pa_context *c, const pa_client_info *i, int is_last, void *userdata) { + char t[32]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get client information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + snprintf(t, sizeof(t), "%u", i->owner_module); + + printf("*** Client #%u ***\n" + "Name: %s\n" + "Driver: %s\n" + "Owner Module: %s\n", + i->index, + i->name, + i->driver, + i->owner_module != PA_INVALID_INDEX ? t : "n/a"); +} + +static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) { + char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get sink input information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + snprintf(t, sizeof(t), "%u", i->owner_module); + snprintf(k, sizeof(k), "%u", i->client); + + printf("*** Sink Input #%u ***\n" + "Name: %s\n" + "Driver: %s\n" + "Owner Module: %s\n" + "Client: %s\n" + "Sink: %u\n" + "Sample Specification: %s\n" + "Channel Map: %s\n" + "Volume: %s\n" + "Buffer Latency: %0.0f usec\n" + "Sink Latency: %0.0f usec\n" + "Resample method: %s\n", + i->index, + i->name, + i->driver, + i->owner_module != PA_INVALID_INDEX ? t : "n/a", + i->client != PA_INVALID_INDEX ? k : "n/a", + i->sink, + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), + pa_cvolume_snprint(cv, sizeof(cv), &i->volume), + (double) i->buffer_usec, + (double) i->sink_usec, + i->resample_method ? i->resample_method : "n/a"); +} + + +static void get_source_output_info_callback(pa_context *c, const pa_source_output_info *i, int is_last, void *userdata) { + char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get source output information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + + snprintf(t, sizeof(t), "%u", i->owner_module); + snprintf(k, sizeof(k), "%u", i->client); + + printf("*** Source Output #%u ***\n" + "Name: %s\n" + "Driver: %s\n" + "Owner Module: %s\n" + "Client: %s\n" + "Source: %u\n" + "Sample Specification: %s\n" + "Channel Map: %s\n" + "Buffer Latency: %0.0f usec\n" + "Source Latency: %0.0f usec\n" + "Resample method: %s\n", + i->index, + i->name, + i->driver, + i->owner_module != PA_INVALID_INDEX ? t : "n/a", + i->client != PA_INVALID_INDEX ? k : "n/a", + i->source, + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), + (double) i->buffer_usec, + (double) i->source_usec, + i->resample_method ? i->resample_method : "n/a"); +} + +static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int is_last, void *userdata) { + char t[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get sample information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + + pa_bytes_snprint(t, sizeof(t), i->bytes); + + printf("*** Sample #%u ***\n" + "Name: %s\n" + "Volume: %s\n" + "Sample Specification: %s\n" + "Channel Map: %s\n" + "Duration: %0.1fs\n" + "Size: %s\n" + "Lazy: %s\n" + "Filename: %s\n", + i->index, + i->name, + pa_cvolume_snprint(cv, sizeof(cv), &i->volume), + pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : "n/a", + pa_sample_spec_valid(&i->sample_spec) ? pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map) : "n/a", + (double) i->duration/1000000, + t, + i->lazy ? "yes" : "no", + i->filename ? i->filename : "n/a"); +} + +static void get_autoload_info_callback(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata) { + if (is_last < 0) { + fprintf(stderr, "Failed to get autoload information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + printf("*** Autoload Entry #%u ***\n" + "Name: %s\n" + "Type: %s\n" + "Module: %s\n" + "Argument: %s\n", + i->index, + i->name, + i->type == PA_AUTOLOAD_SINK ? "sink" : "source", + i->module, + i->argument); +} + +static void simple_callback(pa_context *c, int success, void *userdata) { + if (!success) { + fprintf(stderr, "Failure: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + complete_action(); +} + +static void stream_state_callback(pa_stream *s, void *userdata) { + assert(s); + + switch (pa_stream_get_state(s)) { + case PA_STREAM_CREATING: + case PA_STREAM_READY: + break; + + case PA_STREAM_TERMINATED: + drain(); + break; + + case PA_STREAM_FAILED: + default: + fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + quit(1); + } +} + +static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { + sf_count_t l; + float *d; + assert(s && length && sndfile); + + d = malloc(length); + assert(d); + + assert(sample_length >= length); + l = length/pa_frame_size(&sample_spec); + + if ((sf_readf_float(sndfile, d, l)) != l) { + free(d); + fprintf(stderr, "Premature end of file\n"); + quit(1); + } + + pa_stream_write(s, d, length, free, 0); + + sample_length -= length; + + if (sample_length <= 0) { + pa_stream_set_write_callback(sample_stream, NULL, NULL); + pa_stream_finish_upload(sample_stream); + } +} + +static void context_state_callback(pa_context *c, void *userdata) { + assert(c); + switch (pa_context_get_state(c)) { + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + + case PA_CONTEXT_READY: + switch (action) { + case STAT: + actions = 2; + pa_operation_unref(pa_context_stat(c, stat_callback, NULL)); + pa_operation_unref(pa_context_get_server_info(c, get_server_info_callback, NULL)); + break; + + case PLAY_SAMPLE: + pa_operation_unref(pa_context_play_sample(c, sample_name, device, PA_VOLUME_NORM, simple_callback, NULL)); + break; + + case REMOVE_SAMPLE: + pa_operation_unref(pa_context_remove_sample(c, sample_name, simple_callback, NULL)); + break; + + case UPLOAD_SAMPLE: + sample_stream = pa_stream_new(c, sample_name, &sample_spec, NULL); + assert(sample_stream); + + pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL); + pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL); + pa_stream_connect_upload(sample_stream, sample_length); + break; + + case EXIT: + pa_context_exit_daemon(c); + drain(); + + case LIST: + actions = 8; + pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL)); + pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL)); + pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL)); + pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL)); + pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL)); + pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL)); + pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL)); + pa_operation_unref(pa_context_get_autoload_info_list(c, get_autoload_info_callback, NULL)); + break; + + default: + assert(0); + } + break; + + case PA_CONTEXT_TERMINATED: + quit(0); + break; + + case PA_CONTEXT_FAILED: + default: + fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + } +} + +static void exit_signal_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) { + fprintf(stderr, "Got SIGINT, exiting.\n"); + quit(0); +} + +static void help(const char *argv0) { + + printf("%s [options] stat\n" + "%s [options] list\n" + "%s [options] exit\n" + "%s [options] upload-sample FILENAME [NAME]\n" + "%s [options] play-sample NAME [SINK]\n" + "%s [options] remove-sample NAME\n\n" + " -h, --help Show this help\n" + " --version Show version\n\n" + " -s, --server=SERVER The name of the server to connect to\n" + " -n, --client-name=NAME How to call this client on the server\n", + argv0, argv0, argv0, argv0, argv0, argv0); +} + +enum { ARG_VERSION = 256 }; + +int main(int argc, char *argv[]) { + pa_mainloop* m = NULL; + char tmp[PATH_MAX]; + int ret = 1, r, c; + char *server = NULL, *client_name = NULL, *bn; + + static const struct option long_options[] = { + {"server", 1, NULL, 's'}, + {"client-name", 1, NULL, 'n'}, + {"version", 0, NULL, ARG_VERSION}, + {"help", 0, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + if (!(bn = strrchr(argv[0], '/'))) + bn = argv[0]; + else + bn++; + + while ((c = getopt_long(argc, argv, "s:n:h", long_options, NULL)) != -1) { + switch (c) { + case 'h' : + help(bn); + ret = 0; + goto quit; + + case ARG_VERSION: + printf("pactl "PACKAGE_VERSION"\nCompiled with libpolyp %s\nLinked with libpolyp %s\n", pa_get_headers_version(), pa_get_library_version()); + ret = 0; + goto quit; + + case 's': + free(server); + server = strdup(optarg); + break; + + case 'n': + free(client_name); + client_name = strdup(optarg); + break; + + default: + goto quit; + } + } + + if (!client_name) + client_name = strdup(bn); + + if (optind < argc) { + if (!strcmp(argv[optind], "stat")) + action = STAT; + else if (!strcmp(argv[optind], "exit")) + action = EXIT; + else if (!strcmp(argv[optind], "list")) + action = LIST; + else if (!strcmp(argv[optind], "upload-sample")) { + struct SF_INFO sfinfo; + action = UPLOAD_SAMPLE; + + if (optind+1 >= argc) { + fprintf(stderr, "Please specify a sample file to load\n"); + goto quit; + } + + if (optind+2 < argc) + sample_name = strdup(argv[optind+2]); + else { + char *f = strrchr(argv[optind+1], '/'); + size_t n; + if (f) + f++; + else + f = argv[optind]; + + n = strcspn(f, "."); + strncpy(tmp, f, n); + tmp[n] = 0; + sample_name = strdup(tmp); + } + + memset(&sfinfo, 0, sizeof(sfinfo)); + if (!(sndfile = sf_open(argv[optind+1], SFM_READ, &sfinfo))) { + fprintf(stderr, "Failed to open sound file.\n"); + goto quit; + } + + sample_spec.format = PA_SAMPLE_FLOAT32; + sample_spec.rate = sfinfo.samplerate; + sample_spec.channels = sfinfo.channels; + + sample_length = sfinfo.frames*pa_frame_size(&sample_spec); + } else if (!strcmp(argv[optind], "play-sample")) { + action = PLAY_SAMPLE; + if (optind+1 >= argc) { + fprintf(stderr, "You have to specify a sample name to play\n"); + goto quit; + } + + sample_name = strdup(argv[optind+1]); + + if (optind+2 < argc) + device = strdup(argv[optind+2]); + + } else if (!strcmp(argv[optind], "remove-sample")) { + action = REMOVE_SAMPLE; + if (optind+1 >= argc) { + fprintf(stderr, "You have to specify a sample name to remove\n"); + goto quit; + } + + sample_name = strdup(argv[optind+1]); + } + } + + if (action == NONE) { + fprintf(stderr, "No valid command specified.\n"); + goto quit; + } + + if (!(m = pa_mainloop_new())) { + fprintf(stderr, "pa_mainloop_new() failed.\n"); + goto quit; + } + + mainloop_api = pa_mainloop_get_api(m); + + r = pa_signal_init(mainloop_api); + assert(r == 0); + pa_signal_new(SIGINT, exit_signal_callback, NULL); +#ifdef SIGPIPE + signal(SIGPIPE, SIG_IGN); +#endif + + if (!(context = pa_context_new(mainloop_api, client_name))) { + fprintf(stderr, "pa_context_new() failed.\n"); + goto quit; + } + + pa_context_set_state_callback(context, context_state_callback, NULL); + pa_context_connect(context, server, 1, NULL); + + if (pa_mainloop_run(m, &ret) < 0) { + fprintf(stderr, "pa_mainloop_run() failed.\n"); + goto quit; + } + +quit: + if (sample_stream) + pa_stream_unref(sample_stream); + + if (context) + pa_context_unref(context); + + if (m) { + pa_signal_done(); + pa_mainloop_free(m); + } + + if (sndfile) + sf_close(sndfile); + + free(server); + free(device); + free(sample_name); + + return ret; +} diff --git a/src/utils/paplay.c b/src/utils/paplay.c new file mode 100644 index 00000000..ddc1cbc1 --- /dev/null +++ b/src/utils/paplay.c @@ -0,0 +1,386 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#if PA_API_VERSION != 8 +#error Invalid Polypaudio API version +#endif + +static pa_context *context = NULL; +static pa_stream *stream = NULL; +static pa_mainloop_api *mainloop_api = NULL; + +static char *stream_name = NULL, *client_name = NULL, *device = NULL; + +static int verbose = 0; +static pa_volume_t volume = PA_VOLUME_NORM; + +static SNDFILE* sndfile = NULL; + +static pa_sample_spec sample_spec = { 0, 0, 0 }; + +static sf_count_t (*readf_function)(SNDFILE *_sndfile, void *ptr, sf_count_t frames); + +/* A shortcut for terminating the application */ +static void quit(int ret) { + assert(mainloop_api); + mainloop_api->quit(mainloop_api, ret); +} + +/* Connection draining complete */ +static void context_drain_complete(pa_context*c, void *userdata) { + pa_context_disconnect(c); +} + +/* Stream draining complete */ +static void stream_drain_complete(pa_stream*s, int success, void *userdata) { + pa_operation *o; + + if (!success) { + fprintf(stderr, "Failed to drain stream: %s\n", pa_strerror(pa_context_errno(context))); + quit(1); + } + + if (verbose) + fprintf(stderr, "Playback stream drained.\n"); + + pa_stream_disconnect(stream); + pa_stream_unref(stream); + stream = NULL; + + if (!(o = pa_context_drain(context, context_drain_complete, NULL))) + pa_context_disconnect(context); + else { + pa_operation_unref(o); + + if (verbose) + fprintf(stderr, "Draining connection to server.\n"); + } +} + +/* This is called whenever new data may be written to the stream */ +static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { + size_t k; + sf_count_t f, n; + void *data; + assert(s && length); + + if (!sndfile) + return; + + k = pa_frame_size(&sample_spec); + + data = malloc(length); + + n = length/k; + + f = readf_function(sndfile, data, n); + + if (f > 0) + pa_stream_write(s, data, f*k, free, 0); + + if (f < n) { + sf_close(sndfile); + sndfile = NULL; + pa_operation_unref(pa_stream_drain(s, stream_drain_complete, NULL)); + } +} + +/* This routine is called whenever the stream state changes */ +static void stream_state_callback(pa_stream *s, void *userdata) { + assert(s); + + switch (pa_stream_get_state(s)) { + case PA_STREAM_CREATING: + case PA_STREAM_TERMINATED: + break; + + case PA_STREAM_READY: + if (verbose) + fprintf(stderr, "Stream successfully created\n"); + break; + + case PA_STREAM_FAILED: + default: + fprintf(stderr, "Stream errror: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + quit(1); + } +} + +/* This is called whenever the context status changes */ +static void context_state_callback(pa_context *c, void *userdata) { + assert(c); + + switch (pa_context_get_state(c)) { + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + + case PA_CONTEXT_READY: { + pa_cvolume cv; + + assert(c && !stream); + + if (verbose) + fprintf(stderr, "Connection established.\n"); + + stream = pa_stream_new(c, stream_name, &sample_spec, NULL); + assert(stream); + + pa_stream_set_state_callback(stream, stream_state_callback, NULL); + pa_stream_set_write_callback(stream, stream_write_callback, NULL); + pa_stream_connect_playback(stream, device, NULL, 0, pa_cvolume_set(&cv, PA_CHANNELS_MAX, volume)); + + break; + } + + case PA_CONTEXT_TERMINATED: + quit(0); + break; + + case PA_CONTEXT_FAILED: + default: + fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + } +} + +/* UNIX signal to quit recieved */ +static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { + if (verbose) + fprintf(stderr, "Got SIGINT, exiting.\n"); + quit(0); + +} + +static void help(const char *argv0) { + + printf("%s [options] [FILE]\n\n" + " -h, --help Show this help\n" + " --version Show version\n\n" + " -v, --verbose Enable verbose operations\n\n" + " -s, --server=SERVER The name of the server to connect to\n" + " -d, --device=DEVICE The name of the sink/source to connect to\n" + " -n, --client-name=NAME How to call this client on the server\n" + " --stream-name=NAME How to call this stream on the server\n" + " --volume=VOLUME Specify the initial (linear) volume in range 0...256\n", + argv0); +} + +enum { + ARG_VERSION = 256, + ARG_STREAM_NAME, + ARG_VOLUME +}; + +int main(int argc, char *argv[]) { + pa_mainloop* m = NULL; + int ret = 1, r, c; + char *bn, *server = NULL; + const char *filename; + SF_INFO sfinfo; + + static const struct option long_options[] = { + {"device", 1, NULL, 'd'}, + {"server", 1, NULL, 's'}, + {"client-name", 1, NULL, 'n'}, + {"stream-name", 1, NULL, ARG_STREAM_NAME}, + {"version", 0, NULL, ARG_VERSION}, + {"help", 0, NULL, 'h'}, + {"verbose", 0, NULL, 'v'}, + {"volume", 1, NULL, ARG_VOLUME}, + {NULL, 0, NULL, 0} + }; + + if (!(bn = strrchr(argv[0], '/'))) + bn = argv[0]; + else + bn++; + + while ((c = getopt_long(argc, argv, "d:s:n:hv", long_options, NULL)) != -1) { + + switch (c) { + case 'h' : + help(bn); + ret = 0; + goto quit; + + case ARG_VERSION: + printf("paplay "PACKAGE_VERSION"\nCompiled with libpolyp %s\nLinked with libpolyp %s\n", pa_get_headers_version(), pa_get_library_version()); + ret = 0; + goto quit; + + case 'd': + free(device); + device = strdup(optarg); + break; + + case 's': + free(server); + server = strdup(optarg); + break; + + case 'n': + free(client_name); + client_name = strdup(optarg); + break; + + case ARG_STREAM_NAME: + free(stream_name); + stream_name = strdup(optarg); + break; + + case 'v': + verbose = 1; + break; + + case ARG_VOLUME: { + int v = atoi(optarg); + volume = v < 0 ? 0 : v; + break; + } + + default: + goto quit; + } + } + + + filename = optind < argc ? argv[optind] : "STDIN"; + + + if (!client_name) + client_name = strdup(bn); + + if (!stream_name) + stream_name = strdup(filename); + + memset(&sfinfo, 0, sizeof(sfinfo)); + + if (optind < argc) + sndfile = sf_open(filename, SFM_READ, &sfinfo); + else + sndfile = sf_open_fd(STDIN_FILENO, SFM_READ, &sfinfo, 0); + + if (!sndfile) { + fprintf(stderr, "Failed to open file '%s'\n", filename); + goto quit; + } + + sample_spec.rate = sfinfo.samplerate; + sample_spec.channels = sfinfo.channels; + + switch (sfinfo.format & 0xFF) { + case SF_FORMAT_PCM_16: + case SF_FORMAT_PCM_U8: + case SF_FORMAT_ULAW: + case SF_FORMAT_ALAW: + sample_spec.format = PA_SAMPLE_S16NE; + readf_function = (sf_count_t (*)(SNDFILE *_sndfile, void *ptr, sf_count_t frames)) sf_readf_short; + break; + case SF_FORMAT_FLOAT: + default: + sample_spec.format = PA_SAMPLE_FLOAT32NE; + readf_function = (sf_count_t (*)(SNDFILE *_sndfile, void *ptr, sf_count_t frames)) sf_readf_float; + break; + } + + if (verbose) { + char t[PA_SAMPLE_SPEC_SNPRINT_MAX]; + pa_sample_spec_snprint(t, sizeof(t), &sample_spec); + fprintf(stderr, "Using sample spec '%s'\n", t); + } + + /* Set up a new main loop */ + if (!(m = pa_mainloop_new())) { + fprintf(stderr, "pa_mainloop_new() failed.\n"); + goto quit; + } + + mainloop_api = pa_mainloop_get_api(m); + + r = pa_signal_init(mainloop_api); + assert(r == 0); + pa_signal_new(SIGINT, exit_signal_callback, NULL); +#ifdef SIGPIPE + signal(SIGPIPE, SIG_IGN); +#endif + + /* Create a new connection context */ + if (!(context = pa_context_new(mainloop_api, client_name))) { + fprintf(stderr, "pa_context_new() failed.\n"); + goto quit; + } + + pa_context_set_state_callback(context, context_state_callback, NULL); + + /* Connect the context */ + pa_context_connect(context, server, 1, NULL); + + /* Run the main loop */ + if (pa_mainloop_run(m, &ret) < 0) { + fprintf(stderr, "pa_mainloop_run() failed.\n"); + goto quit; + } + +quit: + if (stream) + pa_stream_unref(stream); + + if (context) + pa_context_unref(context); + + if (m) { + pa_signal_done(); + pa_mainloop_free(m); + } + + free(server); + free(device); + free(client_name); + free(stream_name); + + if (sndfile) + sf_close(sndfile); + + return ret; +} diff --git a/src/utils/pax11publish.c b/src/utils/pax11publish.c new file mode 100644 index 00000000..63ee4821 --- /dev/null +++ b/src/utils/pax11publish.c @@ -0,0 +1,217 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + const char *dname = NULL, *sink = NULL, *source = NULL, *server = NULL, *cookie_file = PA_NATIVE_COOKIE_FILE; + int c, ret = 1; + Display *d = NULL; + enum { DUMP, EXPORT, IMPORT, REMOVE } mode = DUMP; + + while ((c = getopt(argc, argv, "deiD:S:O:I:c:hr")) != -1) { + switch (c) { + case 'D' : + dname = optarg; + break; + case 'h': + printf("%s [-D display] [-S server] [-O sink] [-I source] [-c file] [-d|-e|-i|-r]\n\n" + " -d Show current Polypaudio data attached to X11 display (default)\n" + " -e Export local Polypaudio data to X11 display\n" + " -i Import Polypaudio data from X11 display to local environment variables and cookie file.\n" + " -r Remove Polypaudio data from X11 display\n", + pa_path_get_filename(argv[0])); + ret = 0; + goto finish; + case 'd': + mode = DUMP; + break; + case 'e': + mode = EXPORT; + break; + case 'i': + mode = IMPORT; + break; + case 'r': + mode = REMOVE; + break; + case 'c': + cookie_file = optarg; + break; + case 'I': + source = optarg; + break; + case 'O': + sink = optarg; + break; + case 'S': + server = optarg; + break; + default: + fprintf(stderr, "Failed to parse command line.\n"); + goto finish; + } + } + + if (!(d = XOpenDisplay(dname))) { + pa_log(__FILE__": XOpenDisplay() failed\n"); + goto finish; + } + + switch (mode) { + case DUMP: { + char t[1024]; + if (pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) + printf("Server: %s\n", t); + if (pa_x11_get_prop(d, "POLYP_SOURCE", t, sizeof(t))) + printf("Source: %s\n", t); + if (pa_x11_get_prop(d, "POLYP_SINK", t, sizeof(t))) + printf("Sink: %s\n", t); + if (pa_x11_get_prop(d, "POLYP_COOKIE", t, sizeof(t))) + printf("Cookie: %s\n", t); + + break; + } + + case IMPORT: { + char t[1024]; + if (pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) + printf("POLYP_SERVER='%s'\nexport POLYP_SERVER\n", t); + if (pa_x11_get_prop(d, "POLYP_SOURCE", t, sizeof(t))) + printf("POLYP_SOURCE='%s'\nexport POLYP_SOURCE\n", t); + if (pa_x11_get_prop(d, "POLYP_SINK", t, sizeof(t))) + printf("POLYP_SINK='%s'\nexport POLYP_SINK\n", t); + + if (pa_x11_get_prop(d, "POLYP_COOKIE", t, sizeof(t))) { + uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; + size_t l; + if ((l = pa_parsehex(t, cookie, sizeof(cookie))) != sizeof(cookie)) { + fprintf(stderr, "Failed to parse cookie data\n"); + goto finish; + } + + if (pa_authkey_save(cookie_file, cookie, l) < 0) { + fprintf(stderr, "Failed to save cookie data\n"); + goto finish; + } + } + + break; + } + + case EXPORT: { + pa_client_conf *conf = pa_client_conf_new(); + uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; + char hx[PA_NATIVE_COOKIE_LENGTH*2+1]; + assert(conf); + + if (pa_client_conf_load(conf, NULL) < 0) { + fprintf(stderr, "Failed to load client configuration file.\n"); + goto finish; + } + + if (pa_client_conf_env(conf) < 0) { + fprintf(stderr, "Failed to read environment configuration data.\n"); + goto finish; + } + + pa_x11_del_prop(d, "POLYP_SERVER"); + pa_x11_del_prop(d, "POLYP_SINK"); + pa_x11_del_prop(d, "POLYP_SOURCE"); + pa_x11_del_prop(d, "POLYP_ID"); + pa_x11_del_prop(d, "POLYP_COOKIE"); + + if (server) + pa_x11_set_prop(d, "POLYP_SERVER", server); + else if (conf->default_server) + pa_x11_set_prop(d, "POLYP_SERVER", conf->default_server); + else { + char hn[256]; + if (!pa_get_fqdn(hn, sizeof(hn))) { + fprintf(stderr, "Failed to get FQDN.\n"); + goto finish; + } + + pa_x11_set_prop(d, "POLYP_SERVER", hn); + } + + if (sink) + pa_x11_set_prop(d, "POLYP_SINK", sink); + else if (conf->default_sink) + pa_x11_set_prop(d, "POLYP_SINK", conf->default_sink); + + if (source) + pa_x11_set_prop(d, "POLYP_SOURCE", source); + if (conf->default_source) + pa_x11_set_prop(d, "POLYP_SOURCE", conf->default_source); + + pa_client_conf_free(conf); + + if (pa_authkey_load_auto(cookie_file, cookie, sizeof(cookie)) < 0) { + fprintf(stderr, "Failed to load cookie data\n"); + goto finish; + } + + pa_x11_set_prop(d, "POLYP_COOKIE", pa_hexstr(cookie, sizeof(cookie), hx, sizeof(hx))); + break; + } + + case REMOVE: + pa_x11_del_prop(d, "POLYP_SERVER"); + pa_x11_del_prop(d, "POLYP_SINK"); + pa_x11_del_prop(d, "POLYP_SOURCE"); + pa_x11_del_prop(d, "POLYP_ID"); + pa_x11_del_prop(d, "POLYP_COOKIE"); + break; + + default: + fprintf(stderr, "No yet implemented.\n"); + goto finish; + } + + ret = 0; + +finish: + + if (d) { + XSync(d, False); + XCloseDisplay(d); + } + + return ret; +} -- cgit From b56b9e50e027c22fc56c805d8d0cd10d99a4cd5b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Feb 2006 21:37:20 +0000 Subject: * svn:ignore some files * move configuration files to the directories they belong to * built esd-compat.sh in the src/ dir git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@488 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 30 ++++++++------ src/client.conf.in | 39 ------------------ src/daemon.conf.in | 77 ----------------------------------- src/daemon/daemon.conf.in | 77 +++++++++++++++++++++++++++++++++++ src/daemon/default.pa.in | 66 ++++++++++++++++++++++++++++++ src/daemon/default.pa.win32 | 43 ++++++++++++++++++++ src/daemon/esdcompat.sh.in | 98 +++++++++++++++++++++++++++++++++++++++++++++ src/default.pa.in | 66 ------------------------------ src/default.pa.win32 | 43 -------------------- src/polyp/client.conf.in | 39 ++++++++++++++++++ src/utils/esdcompat.sh.in | 98 --------------------------------------------- 11 files changed, 340 insertions(+), 336 deletions(-) delete mode 100644 src/client.conf.in delete mode 100644 src/daemon.conf.in create mode 100644 src/daemon/daemon.conf.in create mode 100755 src/daemon/default.pa.in create mode 100644 src/daemon/default.pa.win32 create mode 100755 src/daemon/esdcompat.sh.in delete mode 100755 src/default.pa.in delete mode 100644 src/default.pa.win32 create mode 100644 src/polyp/client.conf.in delete mode 100755 src/utils/esdcompat.sh.in diff --git a/src/Makefile.am b/src/Makefile.am index 92c7dae1..8131794c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -75,16 +75,20 @@ endif ################################### EXTRA_DIST = \ - client.conf.in \ - daemon.conf.in \ - default.pa.in \ + polyp/client.conf.in \ + daemon/daemon.conf.in \ + daemon/default.pa.in \ depmod.py \ - utils/esdcompat.sh.in \ + daemon/esdcompat.sh.in \ modules/module-defs.h.m4 -polypconf_DATA = default.pa daemon.conf client.conf +polypconf_DATA = \ + default.pa \ + daemon.conf \ + client.conf -BUILT_SOURCES = polyp/polyplib-version.h +BUILT_SOURCES = \ + polyp/polyplib-version.h ################################### # Main daemon # @@ -131,10 +135,10 @@ bin_PROGRAMS += pax11publish endif if HAVE_HOWL -bin_PROGRAMS += pabrowse +bin_PROGRAMS += pabrowse endif -bin_SCRIPTS = utils/esdcompat.sh +bin_SCRIPTS = daemon/esdcompat.sh pacat_SOURCES = utils/pacat.c pacat_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la @@ -1035,23 +1039,23 @@ suid: polypaudio chown root $< chmod u+s $< -utils/esdcompat.sh: utils/esdcompat.sh.in Makefile +esdcompat.sh: daemon/esdcompat.sh.in Makefile sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ -client.conf: client.conf.in Makefile +client.conf: polyp/client.conf.in Makefile sed -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ if OS_IS_WIN32 -default.pa: default.pa.win32 +default.pa: daemon/default.pa.win32 cp $< $@ else -default.pa: default.pa.in Makefile +default.pa: daemon/default.pa.in Makefile sed -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ endif -daemon.conf: daemon.conf.in Makefile +daemon.conf: daemon/daemon.conf.in Makefile sed -e 's,@DLSEARCHPATH\@,$(modlibdir),g' \ -e 's,@DEFAULT_CONFIG_FILE\@,$(DEFAULT_CONFIG_DIR),g' < $< > $@ diff --git a/src/client.conf.in b/src/client.conf.in deleted file mode 100644 index fbf645a4..00000000 --- a/src/client.conf.in +++ /dev/null @@ -1,39 +0,0 @@ -# $Id$ -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -## Configuration file for polypaudio clients. Default values are -## commented out. Use either ; or # for commenting - -## Path to the polypaudio daemon to run when autospawning. -; daemon-binary = @POLYPAUDIO_BINARY@ - -## Extra arguments to pass to the polypaudio daemon -; extra-arguments = --log-target=syslog --exit-idle-time=5 - -## The default sink to connect to -; default-sink = - -## The default source to connect to -; default-source = - -## The default sever to connect to -; default-server = - -## Autospawn daemons? -; autospawn = 0 diff --git a/src/daemon.conf.in b/src/daemon.conf.in deleted file mode 100644 index d5373018..00000000 --- a/src/daemon.conf.in +++ /dev/null @@ -1,77 +0,0 @@ -# $Id$ -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -## Configuration file for the polypaudio daemon. Default values are -## commented out. Use either ; or # for commenting - -# Extra verbositiy -; verbose = 0 - -## Daemonize after startup -; daemonize = 0 - -## Quit if startup fails -; fail = 1 - -## Renice the daemon to level -15 and try to get SCHED_FIFO -## scheduling. This a good idea if you hear annyoing noise in the -## playback. However, this is a certain security issue, since it works -## when called SUID root only. root is dropped immediately after gaining -## the nice level and SCHED_FIFO scheduling on startup. -; high-priority = 0 - -## Disallow module loading after startup -; disallow-module-loading = 0 - -## Terminate the daemon after the last client quit and this time -## passed. Use a negative value to disable this feature. -; exit-idle-time = -1 - -## Unload autoloaded modules after being idle for this time -; module-idle-time = 20 - -## The path were to look for dynamic shared objects (DSOs aka -## plugins). You may specify more than one path seperated by -## colons. -; dl-search-path = @DLSEARCHPATH@ - -## The default script file to load. Specify an empty string for not -## loading a default script file. The -; default-script-file = @DEFAULT_CONFIG_FILE@ - -## The default log target. Use either "stderr", "syslog" or -## "auto". The latter is equivalent to "sylog" in case daemonize is -## true, otherwise to "stderr". -; log-target = auto - -## The resampling algorithm to use. Use one of src-sinc-best-quality, -## src-sinc-medium-quality, src-sinc-fastest, src-zero-order-hold, -## src-linear, trivial. See the documentation of libsamplerate for an -## explanation for the different methods. The method 'trivial' is the -## only algorithm implemented without usage of floating point -## numbers. If you're tight on CPU consider using this. On the other -## hand it has the worst quality of all. -; resample-method = sinc-fastest - -## Create a PID file in /tmp/polypaudio-$USER/pid. Of this is enabled -## you may use commands like "polypaudio --kill" or "polypaudio -## --check". If you are planning to start more than one polypaudio -## process per user, you better disable this option since it -## effectively disables multiple instances. -; use-pid-file = 1 diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in new file mode 100644 index 00000000..d5373018 --- /dev/null +++ b/src/daemon/daemon.conf.in @@ -0,0 +1,77 @@ +# $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +## Configuration file for the polypaudio daemon. Default values are +## commented out. Use either ; or # for commenting + +# Extra verbositiy +; verbose = 0 + +## Daemonize after startup +; daemonize = 0 + +## Quit if startup fails +; fail = 1 + +## Renice the daemon to level -15 and try to get SCHED_FIFO +## scheduling. This a good idea if you hear annyoing noise in the +## playback. However, this is a certain security issue, since it works +## when called SUID root only. root is dropped immediately after gaining +## the nice level and SCHED_FIFO scheduling on startup. +; high-priority = 0 + +## Disallow module loading after startup +; disallow-module-loading = 0 + +## Terminate the daemon after the last client quit and this time +## passed. Use a negative value to disable this feature. +; exit-idle-time = -1 + +## Unload autoloaded modules after being idle for this time +; module-idle-time = 20 + +## The path were to look for dynamic shared objects (DSOs aka +## plugins). You may specify more than one path seperated by +## colons. +; dl-search-path = @DLSEARCHPATH@ + +## The default script file to load. Specify an empty string for not +## loading a default script file. The +; default-script-file = @DEFAULT_CONFIG_FILE@ + +## The default log target. Use either "stderr", "syslog" or +## "auto". The latter is equivalent to "sylog" in case daemonize is +## true, otherwise to "stderr". +; log-target = auto + +## The resampling algorithm to use. Use one of src-sinc-best-quality, +## src-sinc-medium-quality, src-sinc-fastest, src-zero-order-hold, +## src-linear, trivial. See the documentation of libsamplerate for an +## explanation for the different methods. The method 'trivial' is the +## only algorithm implemented without usage of floating point +## numbers. If you're tight on CPU consider using this. On the other +## hand it has the worst quality of all. +; resample-method = sinc-fastest + +## Create a PID file in /tmp/polypaudio-$USER/pid. Of this is enabled +## you may use commands like "polypaudio --kill" or "polypaudio +## --check". If you are planning to start more than one polypaudio +## process per user, you better disable this option since it +## effectively disables multiple instances. +; use-pid-file = 1 diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in new file mode 100755 index 00000000..3aaeeaf0 --- /dev/null +++ b/src/daemon/default.pa.in @@ -0,0 +1,66 @@ +#!@POLYPAUDIO_BINARY@ -nF + +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with polypaudio; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + + +# Load audio drivers statically + +#load-module module-alsa-sink +# load-module module-alsa-source device=plughw:1,0 +load-module module-oss device="/dev/dsp" sink_name=output source_name=input +#load-module module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +load-module module-null-sink +#load-module module-pipe-sink + +# Load audio drivers automatically on access + +#add-autoload-sink output module-oss device="/dev/dsp" sink_name=output source_name=input +#add-autoload-source input module-oss device="/dev/dsp" sink_name=output source_name=input +#add-autoload-sink output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#add-autoload-source input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#add-autoload-sink output module-alsa-sink sink_name=output +#add-autoload-source input module-alsa-source source_name=input + +# Load several protocols +load-module module-esound-protocol-unix +#load-module module-esound-protocol-tcp +load-module module-native-protocol-unix +#load-module module-simple-protocol-tcp +#load-module module-cli-protocol-unix + +# Load the CLI module +load-module module-cli + +# Make some devices default +set-default-sink output +set-default-source input + +.nofail + +# Load something to the sample cache +load-sample x11-bell /usr/share/sounds/KDE_Notify.wav +load-sample-dir-lazy /usr/share/sounds/*.wav + +# Load X11 bell module +load-module module-x11-bell sample=x11-bell sink=output + +# Publish connection data in the X11 root window +load-module module-x11-publish + +#load-module module-pipe-source +#load-module module-pipe-sink diff --git a/src/daemon/default.pa.win32 b/src/daemon/default.pa.win32 new file mode 100644 index 00000000..3478adab --- /dev/null +++ b/src/daemon/default.pa.win32 @@ -0,0 +1,43 @@ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with polypaudio; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + + +# Load audio drivers statically + +load-module module-waveout sink_name=output source_name=input +load-module module-null-sink + +# Load audio drivers automatically on access + +#add-autoload-sink output module-waveout sink_name=output source_name=input +#add-autoload-source input module-waveout sink_name=output source_name=input + +# Load several protocols +#load-module module-esound-protocol-tcp +#load-module module-native-protocol-tcp +#load-module module-simple-protocol-tcp +#load-module module-cli-protocol-tcp + +# Make some devices default +set-default-sink output +set-default-source input + +.nofail + +# Load something to the sample cache +load-sample x11-bell %WINDIR%\Media\ding.wav +load-sample-dir-lazy %WINDIR%\Media\*.wav diff --git a/src/daemon/esdcompat.sh.in b/src/daemon/esdcompat.sh.in new file mode 100755 index 00000000..76023f52 --- /dev/null +++ b/src/daemon/esdcompat.sh.in @@ -0,0 +1,98 @@ +#!/bin/sh + +# $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +VERSION_STRING="@PACKAGE_NAME@ esd wrapper @PACKAGE_VERSION@" + +fail() { + echo "ERROR: $1" + exit 1 +} + +ARGS=" --log-target=syslog" + +for N in $(seq $#) ; do + + case "$1" in + "") + ;; + + -v|--version) + echo "$VERSION_STRING" + exit 0 + ;; + + -h|--help) + cat < Date: Thu, 16 Feb 2006 22:08:06 +0000 Subject: move alsa-util.[ch], oss-util.[ch] and howl-wrap.[ch] to the modules directory since they are just helper source used exclusively by the modules git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@489 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 8 +- src/modules/alsa-util.c | 125 +++++++++++++++++++++++++++++ src/modules/alsa-util.h | 35 ++++++++ src/modules/howl-wrap.c | 116 +++++++++++++++++++++++++++ src/modules/howl-wrap.h | 37 +++++++++ src/modules/module-alsa-sink.c | 2 +- src/modules/module-alsa-source.c | 2 +- src/modules/module-oss-mmap.c | 2 +- src/modules/module-oss.c | 2 +- src/modules/oss-util.c | 168 +++++++++++++++++++++++++++++++++++++++ src/modules/oss-util.h | 32 ++++++++ src/polypcore/alsa-util.c | 124 ----------------------------- src/polypcore/alsa-util.h | 35 -------- src/polypcore/howl-wrap.c | 116 --------------------------- src/polypcore/howl-wrap.h | 37 --------- src/polypcore/oss-util.c | 167 -------------------------------------- src/polypcore/oss-util.h | 32 -------- 17 files changed, 521 insertions(+), 519 deletions(-) create mode 100644 src/modules/alsa-util.c create mode 100644 src/modules/alsa-util.h create mode 100644 src/modules/howl-wrap.c create mode 100644 src/modules/howl-wrap.h create mode 100644 src/modules/oss-util.c create mode 100644 src/modules/oss-util.h delete mode 100644 src/polypcore/alsa-util.c delete mode 100644 src/polypcore/alsa-util.h delete mode 100644 src/polypcore/howl-wrap.c delete mode 100644 src/polypcore/howl-wrap.h delete mode 100644 src/polypcore/oss-util.c delete mode 100644 src/polypcore/oss-util.h diff --git a/src/Makefile.am b/src/Makefile.am index 8131794c..7e8e73b6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -138,7 +138,7 @@ if HAVE_HOWL bin_PROGRAMS += pabrowse endif -bin_SCRIPTS = daemon/esdcompat.sh +bin_SCRIPTS = esdcompat.sh pacat_SOURCES = utils/pacat.c pacat_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la @@ -651,19 +651,19 @@ libx11prop_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS # OSS -liboss_util_la_SOURCES = polypcore/oss-util.c polypcore/oss-util.h +liboss_util_la_SOURCES = modules/oss-util.c modules/oss-util.h liboss_util_la_LDFLAGS = -avoid-version # ALSA -libalsa_util_la_SOURCES = polypcore/alsa-util.c polypcore/alsa-util.h +libalsa_util_la_SOURCES = modules/alsa-util.c modules/alsa-util.h libalsa_util_la_LDFLAGS = -avoid-version libalsa_util_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) # HOWL -libhowl_wrap_la_SOURCES = polypcore/howl-wrap.c polypcore/howl-wrap.h +libhowl_wrap_la_SOURCES = modules/howl-wrap.c modules/howl-wrap.h libhowl_wrap_la_LDFLAGS = -avoid-version libhowl_wrap_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) libhowl_wrap_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c new file mode 100644 index 00000000..8318f945 --- /dev/null +++ b/src/modules/alsa-util.c @@ -0,0 +1,125 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include + +#include "alsa-util.h" + +/* Set the hardware parameters of the given ALSA device. Returns the + * selected fragment settings in *period and *period_size */ +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { + int ret = -1; + snd_pcm_uframes_t buffer_size; + snd_pcm_hw_params_t *hwparams = NULL; + static const snd_pcm_format_t format_trans[] = { + [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8, + [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW, + [PA_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW, + [PA_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE, + [PA_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE, + [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE, + [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, + }; + assert(pcm_handle && ss && periods && period_size); + + if (snd_pcm_hw_params_malloc(&hwparams) < 0 || + snd_pcm_hw_params_any(pcm_handle, hwparams) < 0 || + snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0 || + snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format]) < 0 || + snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &ss->rate, NULL) < 0 || + snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels) < 0 || + (*periods > 0 && snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, periods, NULL) < 0) || + (*period_size > 0 && snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL) < 0) || + snd_pcm_hw_params(pcm_handle, hwparams) < 0) + goto finish; + + if (snd_pcm_prepare(pcm_handle) < 0) + goto finish; + + if (snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size) < 0 || + snd_pcm_hw_params_get_period_size(hwparams, period_size, NULL) < 0) + goto finish; + + assert(buffer_size > 0); + assert(*period_size > 0); + *periods = buffer_size / *period_size; + assert(*periods > 0); + + ret = 0; + +finish: + if (hwparams) + snd_pcm_hw_params_free(hwparams); + + return ret; +} + +/* Allocate an IO event for every ALSA poll descriptor for the + * specified ALSA device. Return a pointer to such an array in + * *io_events. Store the length of that array in *n_io_events. Use the + * specified callback function and userdata. The array has to be freed + * with pa_free_io_events(). */ +int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api* m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata) { + unsigned i; + struct pollfd *pfds, *ppfd; + pa_io_event **ios; + assert(pcm_handle && m && io_events && n_io_events && cb); + + *n_io_events = snd_pcm_poll_descriptors_count(pcm_handle); + + pfds = pa_xmalloc(sizeof(struct pollfd) * *n_io_events); + if (snd_pcm_poll_descriptors(pcm_handle, pfds, *n_io_events) < 0) { + pa_xfree(pfds); + return -1; + } + + *io_events = pa_xmalloc(sizeof(void*) * *n_io_events); + + for (i = 0, ios = *io_events, ppfd = pfds; i < *n_io_events; i++, ios++, ppfd++) { + *ios = m->io_new(m, ppfd->fd, + ((ppfd->events & POLLIN) ? PA_IO_EVENT_INPUT : 0) | + ((ppfd->events & POLLOUT) ? PA_IO_EVENT_OUTPUT : 0), cb, userdata); + assert(*ios); + } + + pa_xfree(pfds); + return 0; +} + +/* Free the memory allocated by pa_create_io_events() */ +void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_events, unsigned n_io_events) { + unsigned i; + pa_io_event **ios; + assert(m && io_events); + + for (ios = io_events, i = 0; i < n_io_events; i++, ios++) + m->io_free(*ios); + pa_xfree(io_events); +} diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h new file mode 100644 index 00000000..5d6d6634 --- /dev/null +++ b/src/modules/alsa-util.h @@ -0,0 +1,35 @@ +#ifndef fooalsautilhfoo +#define fooalsautilhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include + +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size); + +int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api *m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata); +void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_sources, unsigned n_io_sources); + +#endif diff --git a/src/modules/howl-wrap.c b/src/modules/howl-wrap.c new file mode 100644 index 00000000..77d096ac --- /dev/null +++ b/src/modules/howl-wrap.c @@ -0,0 +1,116 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "howl-wrap.h" +#include "log.h" +#include "xmalloc.h" +#include "props.h" + +#define HOWL_PROPERTY "howl" + +pa_howl_wrapper { + pa_core *core; + int ref; + + pa_io_event *io_event; + sw_discovery discovery; + +}; + +static void howl_io_event(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata) { + pa_howl_wrapper *w = userdata; + assert(m && e && fd >= 0 && w && w->ref >= 1); + + if (f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) + goto fail; + + if (sw_discovery_read_socket(w->discovery) != SW_OKAY) + goto fail; + + return; + +fail: + pa_log(__FILE__": howl connection died.\n"); + w->core->mainloop->io_free(w->io_event); + w->io_event = NULL; +} + +static pa_howl_wrapper* howl_wrapper_new(pa_core *c) { + pa_howl_wrapper *h; + sw_discovery session; + assert(c); + + if (sw_discovery_init(&session) != SW_OKAY) { + pa_log("sw_discovery_init() failed.\n"); + return NULL; + } + + h = pa_xmalloc(sizeof(pa_howl_wrapper)); + h->core = c; + h->ref = 1; + h->discovery = session; + + h->io_event = c->mainloop->io_new(c->mainloop, sw_discovery_socket(session), PA_IO_EVENT_INPUT, howl_io_event, h); + + return h; +} + +static void howl_wrapper_free(pa_howl_wrapper *h) { + assert(h); + + sw_discovery_fina(h->discovery); + + if (h->io_event) + h->core->mainloop->io_free(h->io_event); + + pa_xfree(h); +} + +pa_howl_wrapper* pa_howl_wrapper_get(pa_core *c) { + pa_howl_wrapper *h; + assert(c); + + if ((h = pa_property_get(c, HOWL_PROPERTY))) + return pa_howl_wrapper_ref(h); + + return howl_wrapper_new(c); +} + +pa_howl_wrapper* pa_howl_wrapper_ref(pa_howl_wrapper *h) { + assert(h && h->ref >= 1); + h->ref++; + return h; +} + +void pa_howl_wrapper_unref(pa_howl_wrapper *h) { + assert(h && h->ref >= 1); + if (!(--h->ref)) + howl_wrapper_free(h); +} + +sw_discovery pa_howl_wrapper_get_discovery(pa_howl_wrapper *h) { + assert(h && h->ref >= 1); + + return h->discovery; +} + diff --git a/src/modules/howl-wrap.h b/src/modules/howl-wrap.h new file mode 100644 index 00000000..a670b082 --- /dev/null +++ b/src/modules/howl-wrap.h @@ -0,0 +1,37 @@ +#ifndef foohowlwrapperhfoo +#define foohowlwrapperhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "core.h" + +pa_howl_wrapper; + +pa_howl_wrapper* pa_howl_wrapper_get(pa_core *c); +pa_howl_wrapper* pa_howl_wrapper_ref(pa_howl_wrapper *h); +void pa_howl_wrapper_unref(pa_howl_wrapper *h); + +sw_discovery pa_howl_wrapper_get_discovery(pa_howl_wrapper *h); + +#endif diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 48e90e9f..d3fe71a5 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -41,11 +41,11 @@ #include #include #include -#include #include #include #include "module-alsa-sink-symdef.h" +#include "alsa-util.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ALSA Sink") diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index f03e51ad..9453f846 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -41,11 +41,11 @@ #include #include #include -#include #include #include #include "module-alsa-source-symdef.h" +#include "alsa-util.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ALSA Source") diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index 6986b03c..80c762f1 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -40,13 +40,13 @@ #include #include #include -#include #include #include #include #include #include +#include "oss-util.h" #include "module-oss-mmap-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 04458419..264e8792 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -47,6 +46,7 @@ #include #include "module-oss-symdef.h" +#include "oss-util.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("OSS Sink/Source") diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c new file mode 100644 index 00000000..e9a133f5 --- /dev/null +++ b/src/modules/oss-util.c @@ -0,0 +1,168 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "oss-util.h" + +int pa_oss_open(const char *device, int *mode, int* pcaps) { + int fd = -1; + assert(device && mode && (*mode == O_RDWR || *mode == O_RDONLY || *mode == O_WRONLY)); + + if (*mode == O_RDWR) { + if ((fd = open(device, O_RDWR|O_NDELAY)) >= 0) { + int dcaps, *tcaps; + ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0); + + tcaps = pcaps ? pcaps : &dcaps; + + if (ioctl(fd, SNDCTL_DSP_GETCAPS, tcaps) < 0) { + pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); + goto fail; + } + + if (*tcaps & DSP_CAP_DUPLEX) + return fd; + + goto fail; + } + + if ((fd = open(device, (*mode = O_WRONLY)|O_NDELAY)) < 0) { + if ((fd = open(device, (*mode = O_RDONLY)|O_NDELAY)) < 0) { + pa_log(__FILE__": open('%s'): %s\n", device, strerror(errno)); + goto fail; + } + } + } else { + if ((fd = open(device, *mode|O_NDELAY)) < 0) { + pa_log(__FILE__": open('%s'): %s\n", device, strerror(errno)); + goto fail; + } + } + + if (pcaps) { + if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { + pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); + goto fail; + } + } + + pa_fd_set_cloexec(fd, 1); + + return fd; + +fail: + if (fd >= 0) + close(fd); + return -1; +} + +int pa_oss_auto_format(int fd, pa_sample_spec *ss) { + int format, channels, speed, reqformat; + static const int format_trans[PA_SAMPLE_MAX] = { + [PA_SAMPLE_U8] = AFMT_U8, + [PA_SAMPLE_ALAW] = AFMT_A_LAW, + [PA_SAMPLE_ULAW] = AFMT_MU_LAW, + [PA_SAMPLE_S16LE] = AFMT_S16_LE, + [PA_SAMPLE_S16BE] = AFMT_S16_BE, + [PA_SAMPLE_FLOAT32LE] = AFMT_QUERY, /* not supported */ + [PA_SAMPLE_FLOAT32BE] = AFMT_QUERY, /* not supported */ + }; + + assert(fd >= 0 && ss); + + reqformat = format = format_trans[ss->format]; + if (reqformat == AFMT_QUERY || ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != reqformat) { + format = AFMT_S16_NE; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_S16_NE) { + int f = AFMT_S16_NE == AFMT_S16_LE ? AFMT_S16_BE : AFMT_S16_LE; + format = f; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != f) { + format = AFMT_U8; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_U8) { + pa_log(__FILE__": SNDCTL_DSP_SETFMT: %s\n", format != AFMT_U8 ? "No supported sample format" : strerror(errno)); + return -1; + } else + ss->format = PA_SAMPLE_U8; + } else + ss->format = f == AFMT_S16_LE ? PA_SAMPLE_S16LE : PA_SAMPLE_S16BE; + } else + ss->format = PA_SAMPLE_S16NE; + } + + channels = ss->channels; + if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) { + pa_log(__FILE__": SNDCTL_DSP_CHANNELS: %s\n", strerror(errno)); + return -1; + } + assert(channels); + ss->channels = channels; + + speed = ss->rate; + if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) { + pa_log(__FILE__": SNDCTL_DSP_SPEED: %s\n", strerror(errno)); + return -1; + } + assert(speed); + ss->rate = speed; + + return 0; +} + +static int simple_log2(int v) { + int k = 0; + + for (;;) { + v >>= 1; + if (!v) break; + k++; + } + + return k; +} + +int pa_oss_set_fragments(int fd, int nfrags, int frag_size) { + int arg; + arg = ((int) nfrags << 16) | simple_log2(frag_size); + + if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &arg) < 0) { + pa_log(__FILE__": SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno)); + return -1; + } + + return 0; +} diff --git a/src/modules/oss-util.h b/src/modules/oss-util.h new file mode 100644 index 00000000..6b2746cc --- /dev/null +++ b/src/modules/oss-util.h @@ -0,0 +1,32 @@ +#ifndef fooossutilhfoo +#define fooossutilhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +int pa_oss_open(const char *device, int *mode, int* pcaps); +int pa_oss_auto_format(int fd, pa_sample_spec *ss); + +int pa_oss_set_fragments(int fd, int frags, int frag_size); + +#endif diff --git a/src/polypcore/alsa-util.c b/src/polypcore/alsa-util.c deleted file mode 100644 index 7528ee0b..00000000 --- a/src/polypcore/alsa-util.c +++ /dev/null @@ -1,124 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "alsa-util.h" -#include -#include "xmalloc.h" -#include "log.h" - -/* Set the hardware parameters of the given ALSA device. Returns the - * selected fragment settings in *period and *period_size */ -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { - int ret = -1; - snd_pcm_uframes_t buffer_size; - snd_pcm_hw_params_t *hwparams = NULL; - static const snd_pcm_format_t format_trans[] = { - [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8, - [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW, - [PA_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW, - [PA_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE, - [PA_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE, - [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE, - [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, - }; - assert(pcm_handle && ss && periods && period_size); - - if (snd_pcm_hw_params_malloc(&hwparams) < 0 || - snd_pcm_hw_params_any(pcm_handle, hwparams) < 0 || - snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0 || - snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format]) < 0 || - snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &ss->rate, NULL) < 0 || - snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels) < 0 || - (*periods > 0 && snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, periods, NULL) < 0) || - (*period_size > 0 && snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL) < 0) || - snd_pcm_hw_params(pcm_handle, hwparams) < 0) - goto finish; - - if (snd_pcm_prepare(pcm_handle) < 0) - goto finish; - - if (snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size) < 0 || - snd_pcm_hw_params_get_period_size(hwparams, period_size, NULL) < 0) - goto finish; - - assert(buffer_size > 0); - assert(*period_size > 0); - *periods = buffer_size / *period_size; - assert(*periods > 0); - - ret = 0; - -finish: - if (hwparams) - snd_pcm_hw_params_free(hwparams); - - return ret; -} - -/* Allocate an IO event for every ALSA poll descriptor for the - * specified ALSA device. Return a pointer to such an array in - * *io_events. Store the length of that array in *n_io_events. Use the - * specified callback function and userdata. The array has to be freed - * with pa_free_io_events(). */ -int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api* m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata) { - unsigned i; - struct pollfd *pfds, *ppfd; - pa_io_event **ios; - assert(pcm_handle && m && io_events && n_io_events && cb); - - *n_io_events = snd_pcm_poll_descriptors_count(pcm_handle); - - pfds = pa_xmalloc(sizeof(struct pollfd) * *n_io_events); - if (snd_pcm_poll_descriptors(pcm_handle, pfds, *n_io_events) < 0) { - pa_xfree(pfds); - return -1; - } - - *io_events = pa_xmalloc(sizeof(void*) * *n_io_events); - - for (i = 0, ios = *io_events, ppfd = pfds; i < *n_io_events; i++, ios++, ppfd++) { - *ios = m->io_new(m, ppfd->fd, - ((ppfd->events & POLLIN) ? PA_IO_EVENT_INPUT : 0) | - ((ppfd->events & POLLOUT) ? PA_IO_EVENT_OUTPUT : 0), cb, userdata); - assert(*ios); - } - - pa_xfree(pfds); - return 0; -} - -/* Free the memory allocated by pa_create_io_events() */ -void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_events, unsigned n_io_events) { - unsigned i; - pa_io_event **ios; - assert(m && io_events); - - for (ios = io_events, i = 0; i < n_io_events; i++, ios++) - m->io_free(*ios); - pa_xfree(io_events); -} diff --git a/src/polypcore/alsa-util.h b/src/polypcore/alsa-util.h deleted file mode 100644 index 5d6d6634..00000000 --- a/src/polypcore/alsa-util.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef fooalsautilhfoo -#define fooalsautilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include -#include - -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size); - -int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api *m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata); -void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_sources, unsigned n_io_sources); - -#endif diff --git a/src/polypcore/howl-wrap.c b/src/polypcore/howl-wrap.c deleted file mode 100644 index 77d096ac..00000000 --- a/src/polypcore/howl-wrap.c +++ /dev/null @@ -1,116 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "howl-wrap.h" -#include "log.h" -#include "xmalloc.h" -#include "props.h" - -#define HOWL_PROPERTY "howl" - -pa_howl_wrapper { - pa_core *core; - int ref; - - pa_io_event *io_event; - sw_discovery discovery; - -}; - -static void howl_io_event(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata) { - pa_howl_wrapper *w = userdata; - assert(m && e && fd >= 0 && w && w->ref >= 1); - - if (f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) - goto fail; - - if (sw_discovery_read_socket(w->discovery) != SW_OKAY) - goto fail; - - return; - -fail: - pa_log(__FILE__": howl connection died.\n"); - w->core->mainloop->io_free(w->io_event); - w->io_event = NULL; -} - -static pa_howl_wrapper* howl_wrapper_new(pa_core *c) { - pa_howl_wrapper *h; - sw_discovery session; - assert(c); - - if (sw_discovery_init(&session) != SW_OKAY) { - pa_log("sw_discovery_init() failed.\n"); - return NULL; - } - - h = pa_xmalloc(sizeof(pa_howl_wrapper)); - h->core = c; - h->ref = 1; - h->discovery = session; - - h->io_event = c->mainloop->io_new(c->mainloop, sw_discovery_socket(session), PA_IO_EVENT_INPUT, howl_io_event, h); - - return h; -} - -static void howl_wrapper_free(pa_howl_wrapper *h) { - assert(h); - - sw_discovery_fina(h->discovery); - - if (h->io_event) - h->core->mainloop->io_free(h->io_event); - - pa_xfree(h); -} - -pa_howl_wrapper* pa_howl_wrapper_get(pa_core *c) { - pa_howl_wrapper *h; - assert(c); - - if ((h = pa_property_get(c, HOWL_PROPERTY))) - return pa_howl_wrapper_ref(h); - - return howl_wrapper_new(c); -} - -pa_howl_wrapper* pa_howl_wrapper_ref(pa_howl_wrapper *h) { - assert(h && h->ref >= 1); - h->ref++; - return h; -} - -void pa_howl_wrapper_unref(pa_howl_wrapper *h) { - assert(h && h->ref >= 1); - if (!(--h->ref)) - howl_wrapper_free(h); -} - -sw_discovery pa_howl_wrapper_get_discovery(pa_howl_wrapper *h) { - assert(h && h->ref >= 1); - - return h->discovery; -} - diff --git a/src/polypcore/howl-wrap.h b/src/polypcore/howl-wrap.h deleted file mode 100644 index a670b082..00000000 --- a/src/polypcore/howl-wrap.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef foohowlwrapperhfoo -#define foohowlwrapperhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "core.h" - -pa_howl_wrapper; - -pa_howl_wrapper* pa_howl_wrapper_get(pa_core *c); -pa_howl_wrapper* pa_howl_wrapper_ref(pa_howl_wrapper *h); -void pa_howl_wrapper_unref(pa_howl_wrapper *h); - -sw_discovery pa_howl_wrapper_get_discovery(pa_howl_wrapper *h); - -#endif diff --git a/src/polypcore/oss-util.c b/src/polypcore/oss-util.c deleted file mode 100644 index ae6772fd..00000000 --- a/src/polypcore/oss-util.c +++ /dev/null @@ -1,167 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "oss-util.h" -#include "util.h" -#include "log.h" - -int pa_oss_open(const char *device, int *mode, int* pcaps) { - int fd = -1; - assert(device && mode && (*mode == O_RDWR || *mode == O_RDONLY || *mode == O_WRONLY)); - - if (*mode == O_RDWR) { - if ((fd = open(device, O_RDWR|O_NDELAY)) >= 0) { - int dcaps, *tcaps; - ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0); - - tcaps = pcaps ? pcaps : &dcaps; - - if (ioctl(fd, SNDCTL_DSP_GETCAPS, tcaps) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); - goto fail; - } - - if (*tcaps & DSP_CAP_DUPLEX) - return fd; - - goto fail; - } - - if ((fd = open(device, (*mode = O_WRONLY)|O_NDELAY)) < 0) { - if ((fd = open(device, (*mode = O_RDONLY)|O_NDELAY)) < 0) { - pa_log(__FILE__": open('%s'): %s\n", device, strerror(errno)); - goto fail; - } - } - } else { - if ((fd = open(device, *mode|O_NDELAY)) < 0) { - pa_log(__FILE__": open('%s'): %s\n", device, strerror(errno)); - goto fail; - } - } - - if (pcaps) { - if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); - goto fail; - } - } - - pa_fd_set_cloexec(fd, 1); - - return fd; - -fail: - if (fd >= 0) - close(fd); - return -1; -} - -int pa_oss_auto_format(int fd, pa_sample_spec *ss) { - int format, channels, speed, reqformat; - static const int format_trans[PA_SAMPLE_MAX] = { - [PA_SAMPLE_U8] = AFMT_U8, - [PA_SAMPLE_ALAW] = AFMT_A_LAW, - [PA_SAMPLE_ULAW] = AFMT_MU_LAW, - [PA_SAMPLE_S16LE] = AFMT_S16_LE, - [PA_SAMPLE_S16BE] = AFMT_S16_BE, - [PA_SAMPLE_FLOAT32LE] = AFMT_QUERY, /* not supported */ - [PA_SAMPLE_FLOAT32BE] = AFMT_QUERY, /* not supported */ - }; - - assert(fd >= 0 && ss); - - reqformat = format = format_trans[ss->format]; - if (reqformat == AFMT_QUERY || ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != reqformat) { - format = AFMT_S16_NE; - if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_S16_NE) { - int f = AFMT_S16_NE == AFMT_S16_LE ? AFMT_S16_BE : AFMT_S16_LE; - format = f; - if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != f) { - format = AFMT_U8; - if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_U8) { - pa_log(__FILE__": SNDCTL_DSP_SETFMT: %s\n", format != AFMT_U8 ? "No supported sample format" : strerror(errno)); - return -1; - } else - ss->format = PA_SAMPLE_U8; - } else - ss->format = f == AFMT_S16_LE ? PA_SAMPLE_S16LE : PA_SAMPLE_S16BE; - } else - ss->format = PA_SAMPLE_S16NE; - } - - channels = ss->channels; - if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) { - pa_log(__FILE__": SNDCTL_DSP_CHANNELS: %s\n", strerror(errno)); - return -1; - } - assert(channels); - ss->channels = channels; - - speed = ss->rate; - if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) { - pa_log(__FILE__": SNDCTL_DSP_SPEED: %s\n", strerror(errno)); - return -1; - } - assert(speed); - ss->rate = speed; - - return 0; -} - -static int simple_log2(int v) { - int k = 0; - - for (;;) { - v >>= 1; - if (!v) break; - k++; - } - - return k; -} - -int pa_oss_set_fragments(int fd, int nfrags, int frag_size) { - int arg; - arg = ((int) nfrags << 16) | simple_log2(frag_size); - - if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &arg) < 0) { - pa_log(__FILE__": SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno)); - return -1; - } - - return 0; -} diff --git a/src/polypcore/oss-util.h b/src/polypcore/oss-util.h deleted file mode 100644 index 6b2746cc..00000000 --- a/src/polypcore/oss-util.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef fooossutilhfoo -#define fooossutilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -int pa_oss_open(const char *device, int *mode, int* pcaps); -int pa_oss_auto_format(int fd, pa_sample_spec *ss); - -int pa_oss_set_fragments(int fd, int frags, int frag_size); - -#endif -- cgit From 4ad2926eba724771ef29f5aae3757a588bf8818e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Feb 2006 22:11:35 +0000 Subject: add a bunch of simple Makefile in the subdirs, just to make compilation with emacs easier they are not intended to be distributed or anything. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@490 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/Makefile | 1 + src/modules/Makefile | 1 + src/polyp/Makefile | 13 +++++++++++++ src/polypcore/Makefile | 1 + src/tests/Makefile | 1 + src/utils/Makefile | 1 + 6 files changed, 18 insertions(+) create mode 120000 src/daemon/Makefile create mode 120000 src/modules/Makefile create mode 100644 src/polyp/Makefile create mode 120000 src/polypcore/Makefile create mode 120000 src/tests/Makefile create mode 120000 src/utils/Makefile diff --git a/src/daemon/Makefile b/src/daemon/Makefile new file mode 120000 index 00000000..cd2a5c9a --- /dev/null +++ b/src/daemon/Makefile @@ -0,0 +1 @@ +../polyp/Makefile \ No newline at end of file diff --git a/src/modules/Makefile b/src/modules/Makefile new file mode 120000 index 00000000..cd2a5c9a --- /dev/null +++ b/src/modules/Makefile @@ -0,0 +1 @@ +../polyp/Makefile \ No newline at end of file diff --git a/src/polyp/Makefile b/src/polyp/Makefile new file mode 100644 index 00000000..7c8875f3 --- /dev/null +++ b/src/polyp/Makefile @@ -0,0 +1,13 @@ +# This is a dirty trick just to ease compilation with emacs +# +# This file is not intended to be distributed or anything +# +# So: don't touch it, even better ignore it! + +all: + $(MAKE) -C .. + +clean: + $(MAKE) -C .. clean + +.PHONY: all clean diff --git a/src/polypcore/Makefile b/src/polypcore/Makefile new file mode 120000 index 00000000..cd2a5c9a --- /dev/null +++ b/src/polypcore/Makefile @@ -0,0 +1 @@ +../polyp/Makefile \ No newline at end of file diff --git a/src/tests/Makefile b/src/tests/Makefile new file mode 120000 index 00000000..cd2a5c9a --- /dev/null +++ b/src/tests/Makefile @@ -0,0 +1 @@ +../polyp/Makefile \ No newline at end of file diff --git a/src/utils/Makefile b/src/utils/Makefile new file mode 120000 index 00000000..cd2a5c9a --- /dev/null +++ b/src/utils/Makefile @@ -0,0 +1 @@ +../polyp/Makefile \ No newline at end of file -- cgit From f49b09df15221dc45526607af380990aebe1537b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Feb 2006 22:34:52 +0000 Subject: make channel naming somewhat RFC2551 compliant git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@491 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/channelmap.c | 36 ++++++++++++++++++++++++------------ src/polyp/channelmap.h | 5 +++-- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/polyp/channelmap.c b/src/polyp/channelmap.c index 7bfd21e6..bb47deb8 100644 --- a/src/polyp/channelmap.c +++ b/src/polyp/channelmap.c @@ -71,34 +71,46 @@ pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels) { pa_channel_map_init(m); m->channels = channels; + + /* This is somewhat compatible with RFC3551 */ switch (channels) { case 1: m->map[0] = PA_CHANNEL_POSITION_MONO; return m; - case 8: - m->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; - m->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; - /* Fall through */ - case 6: + m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + m->map[1] = PA_CHANNEL_POSITION_SIDE_LEFT; + m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; + m->map[3] = PA_CHANNEL_POSITION_FRONT_RIGHT; + m->map[4] = PA_CHANNEL_POSITION_SIDE_RIGHT; m->map[5] = PA_CHANNEL_POSITION_LFE; - /* Fall through */ + return m; case 5: - m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; - /* Fall through */ - - case 4: - m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT; - m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; + m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; + m->map[3] = PA_CHANNEL_POSITION_REAR_LEFT; + m->map[4] = PA_CHANNEL_POSITION_REAR_RIGHT; /* Fall through */ case 2: m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; return m; + + case 3: + m->map[0] = PA_CHANNEL_POSITION_LEFT; + m->map[1] = PA_CHANNEL_POSITION_RIGHT; + m->map[2] = PA_CHANNEL_POSITION_CENTER; + return m; + + case 4: + m->map[0] = PA_CHANNEL_POSITION_LEFT; + m->map[1] = PA_CHANNEL_POSITION_CENTER; + m->map[2] = PA_CHANNEL_POSITION_RIGHT; + m->map[3] = PA_CHANNEL_POSITION_LFE; + return m; default: return NULL; diff --git a/src/polyp/channelmap.h b/src/polyp/channelmap.h index 0b9f6e26..7c48b76b 100644 --- a/src/polyp/channelmap.h +++ b/src/polyp/channelmap.h @@ -36,10 +36,11 @@ typedef enum { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, - - PA_CHANNEL_POSITION_FRONT_CENTER, + PA_CHANNEL_POSITION_CENTER, + PA_CHANNEL_POSITION_FRONT_LEFT = PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT = PA_CHANNEL_POSITION_RIGHT, + PA_CHANNEL_POSITION_FRONT_CENTER = PA_CHANNEL_POSITION_CENTER, PA_CHANNEL_POSITION_REAR_CENTER, PA_CHANNEL_POSITION_REAR_LEFT, -- cgit From 22c8cebb858012e4e9c551bb54456237e7597697 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Feb 2006 22:43:59 +0000 Subject: drop polyplib- prefix from client library files git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@492 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- src/Makefile.am | 50 +- src/polyp/browser.c | 312 ++++++++++++ src/polyp/browser.h | 65 +++ src/polyp/context.c | 871 +++++++++++++++++++++++++++++++++ src/polyp/context.h | 117 +++++ src/polyp/def.h | 213 +++++++++ src/polyp/error.c | 54 +++ src/polyp/error.h | 38 ++ src/polyp/internal.h | 154 ++++++ src/polyp/introspect.c | 1003 +++++++++++++++++++++++++++++++++++++++ src/polyp/introspect.h | 279 +++++++++++ src/polyp/operation.c | 103 ++++ src/polyp/operation.h | 51 ++ src/polyp/polypaudio.h | 86 ++++ src/polyp/polyplib-browser.c | 312 ------------ src/polyp/polyplib-browser.h | 65 --- src/polyp/polyplib-context.c | 871 --------------------------------- src/polyp/polyplib-context.h | 117 ----- src/polyp/polyplib-def.h | 213 --------- src/polyp/polyplib-error.c | 54 --- src/polyp/polyplib-error.h | 38 -- src/polyp/polyplib-internal.h | 154 ------ src/polyp/polyplib-introspect.c | 1003 --------------------------------------- src/polyp/polyplib-introspect.h | 279 ----------- src/polyp/polyplib-operation.c | 103 ---- src/polyp/polyplib-operation.h | 51 -- src/polyp/polyplib-scache.c | 127 ----- src/polyp/polyplib-scache.h | 50 -- src/polyp/polyplib-simple.c | 393 --------------- src/polyp/polyplib-simple.h | 80 ---- src/polyp/polyplib-stream.c | 807 ------------------------------- src/polyp/polyplib-stream.h | 181 ------- src/polyp/polyplib-subscribe.c | 81 ---- src/polyp/polyplib-subscribe.h | 47 -- src/polyp/polyplib-version.h.in | 47 -- src/polyp/polyplib.h | 86 ---- src/polyp/scache.c | 127 +++++ src/polyp/scache.h | 50 ++ src/polyp/simple.c | 393 +++++++++++++++ src/polyp/simple.h | 80 ++++ src/polyp/stream.c | 807 +++++++++++++++++++++++++++++++ src/polyp/stream.h | 181 +++++++ src/polyp/subscribe.c | 81 ++++ src/polyp/subscribe.h | 47 ++ src/polyp/version.h.in | 47 ++ src/polypcore/native-common.h | 2 +- src/polypcore/sink.c | 2 +- src/tests/pacat-simple.c | 4 +- src/tests/parec-simple.c | 4 +- src/utils/pabrowse.c | 2 +- src/utils/pacat.c | 4 +- src/utils/pactl.c | 2 +- src/utils/paplay.c | 4 +- 54 files changed, 5197 insertions(+), 5197 deletions(-) create mode 100644 src/polyp/browser.c create mode 100644 src/polyp/browser.h create mode 100644 src/polyp/context.c create mode 100644 src/polyp/context.h create mode 100644 src/polyp/def.h create mode 100644 src/polyp/error.c create mode 100644 src/polyp/error.h create mode 100644 src/polyp/internal.h create mode 100644 src/polyp/introspect.c create mode 100644 src/polyp/introspect.h create mode 100644 src/polyp/operation.c create mode 100644 src/polyp/operation.h create mode 100644 src/polyp/polypaudio.h delete mode 100644 src/polyp/polyplib-browser.c delete mode 100644 src/polyp/polyplib-browser.h delete mode 100644 src/polyp/polyplib-context.c delete mode 100644 src/polyp/polyplib-context.h delete mode 100644 src/polyp/polyplib-def.h delete mode 100644 src/polyp/polyplib-error.c delete mode 100644 src/polyp/polyplib-error.h delete mode 100644 src/polyp/polyplib-internal.h delete mode 100644 src/polyp/polyplib-introspect.c delete mode 100644 src/polyp/polyplib-introspect.h delete mode 100644 src/polyp/polyplib-operation.c delete mode 100644 src/polyp/polyplib-operation.h delete mode 100644 src/polyp/polyplib-scache.c delete mode 100644 src/polyp/polyplib-scache.h delete mode 100644 src/polyp/polyplib-simple.c delete mode 100644 src/polyp/polyplib-simple.h delete mode 100644 src/polyp/polyplib-stream.c delete mode 100644 src/polyp/polyplib-stream.h delete mode 100644 src/polyp/polyplib-subscribe.c delete mode 100644 src/polyp/polyplib-subscribe.h delete mode 100644 src/polyp/polyplib-version.h.in delete mode 100644 src/polyp/polyplib.h create mode 100644 src/polyp/scache.c create mode 100644 src/polyp/scache.h create mode 100644 src/polyp/simple.c create mode 100644 src/polyp/simple.h create mode 100644 src/polyp/stream.c create mode 100644 src/polyp/stream.h create mode 100644 src/polyp/subscribe.c create mode 100644 src/polyp/subscribe.h create mode 100644 src/polyp/version.h.in diff --git a/configure.ac b/configure.ac index 182a2455..4261903f 100644 --- a/configure.ac +++ b/configure.ac @@ -407,7 +407,7 @@ doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf -src/polyp/polyplib-version.h +src/polyp/version.h doc/FAQ.html ]) AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am index 7e8e73b6..cfd4b751 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -88,7 +88,7 @@ polypconf_DATA = \ client.conf BUILT_SOURCES = \ - polyp/polyplib-version.h + polyp/version.h ################################### # Main daemon # @@ -259,23 +259,23 @@ polypinclude_HEADERS = \ polyp/mainloop.h \ polyp/mainloop-api.h \ polyp/mainloop-signal.h \ - polyp/polyplib.h \ - polyp/polyplib-context.h \ - polyp/polyplib-def.h \ - polyp/polyplib-error.h \ - polyp/polyplib-introspect.h \ - polyp/polyplib-operation.h \ - polyp/polyplib-scache.h \ - polyp/polyplib-simple.h \ - polyp/polyplib-stream.h \ - polyp/polyplib-subscribe.h \ - polyp/polyplib-version.h \ + polyp/polypaudio.h \ + polyp/context.h \ + polyp/def.h \ + polyp/error.h \ + polyp/introspect.h \ + polyp/operation.h \ + polyp/scache.h \ + polyp/simple.h \ + polyp/stream.h \ + polyp/subscribe.h \ + polyp/version.h \ polyp/sample.h \ polyp/volume.h if HAVE_HOWL polypinclude_HEADERS += \ - polyp/polyplib-browser.h + polyp/browser.h endif lib_LTLIBRARIES = \ @@ -306,15 +306,15 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = \ polyp/client-conf.c polyp/client-conf.h \ polyp/llist.h \ polyp/mainloop-api.c polyp/mainloop-api.h \ - polyp/polyplib.h \ - polyp/polyplib-context.c polyp/polyplib-context.h \ - polyp/polyplib-def.h \ - polyp/polyplib-internal.h \ - polyp/polyplib-introspect.c polyp/polyplib-introspect.h \ - polyp/polyplib-operation.c polyp/polyplib-operation.h \ - polyp/polyplib-scache.c polyp/polyplib-scache.h \ - polyp/polyplib-stream.c polyp/polyplib-stream.h \ - polyp/polyplib-subscribe.c polyp/polyplib-subscribe.h \ + polyp/polypaudio.h \ + polyp/context.c polyp/context.h \ + polyp/def.h \ + polyp/internal.h \ + polyp/introspect.c polyp/introspect.h \ + polyp/operation.c polyp/operation.h \ + polyp/scache.c polyp/scache.h \ + polyp/stream.c polyp/stream.h \ + polyp/subscribe.c polyp/subscribe.h \ polyp/sample.c polyp/sample.h \ polyp/volume.c polyp/volume.h @@ -368,7 +368,7 @@ libpolyp_@PA_MAJORMINOR@_la_CFLAGS += $(LIBASYNCNS_CFLAGS) libpolyp_@PA_MAJORMINOR@_la_LIBADD += $(LIBASYNCNS_LIBS) endif -libpolyp_error_@PA_MAJORMINOR@_la_SOURCES = polyp/polyplib-error.c polyp/polyplib-error.h +libpolyp_error_@PA_MAJORMINOR@_la_SOURCES = polyp/error.c polyp/error.h libpolyp_error_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) libpolyp_error_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la libpolyp_error_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 @@ -381,12 +381,12 @@ libpolyp_mainloop_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) libpolyp_mainloop_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la $(WINSOCK_LIBS) libpolyp_mainloop_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 -libpolyp_simple_@PA_MAJORMINOR@_la_SOURCES = polyp/polyplib-simple.c polyp/polyplib-simple.h +libpolyp_simple_@PA_MAJORMINOR@_la_SOURCES = polyp/simple.c polyp/simple.h libpolyp_simple_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) libpolyp_simple_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp_simple_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 -libpolyp_browse_@PA_MAJORMINOR@_la_SOURCES = polyp/polyplib-browser.c polyp/polyplib-browser.h +libpolyp_browse_@PA_MAJORMINOR@_la_SOURCES = polyp/browser.c polyp/browser.h libpolyp_browse_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) libpolyp_browse_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la $(HOWL_LIBS) libpolyp_browse_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 diff --git a/src/polyp/browser.c b/src/polyp/browser.c new file mode 100644 index 00000000..80051d54 --- /dev/null +++ b/src/polyp/browser.c @@ -0,0 +1,312 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include "browser.h" +#include +#include +#include + +#define SERVICE_NAME_SINK "_polypaudio-sink._tcp." +#define SERVICE_NAME_SOURCE "_polypaudio-source._tcp." +#define SERVICE_NAME_SERVER "_polypaudio-server._tcp." + +pa_browser { + int ref; + pa_mainloop_api *mainloop; + + void (*callback)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void *userdata); + void *callback_userdata; + + sw_discovery discovery; + pa_io_event *io_event; +}; + + +static void io_callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags events, void *userdata) { + pa_browser *b = userdata; + assert(a && b && b->mainloop == a); + + if (events != PA_IO_EVENT_INPUT || sw_discovery_read_socket(b->discovery) != SW_OKAY) { + pa_log(__FILE__": connection to HOWL daemon failed.\n"); + b->mainloop->io_free(b->io_event); + b->io_event = NULL; + return; + } +} + +static sw_result resolve_reply( + sw_discovery discovery, + sw_discovery_oid oid, + sw_uint32 interface_index, + sw_const_string name, + sw_const_string type, + sw_const_string domain, + sw_ipv4_address address, + sw_port port, + sw_octets text_record, + sw_ulong text_record_len, + sw_opaque extra) { + + pa_browser *b = extra; + pa_browse_info i; + char ip[256], a[256]; + pa_browse_opcode opcode; + int device_found = 0; + uint32_t cookie; + pa_typeid_t typeid; + pa_sample_spec ss; + int ss_valid = 0; + sw_text_record_iterator iterator; + int free_iterator = 0; + char *c = NULL; + + assert(b); + + sw_discovery_cancel(discovery, oid); + + memset(&i, 0, sizeof(i)); + i.name = name; + + if (!b->callback) + goto fail; + + if (!strcmp(type, SERVICE_NAME_SINK)) + opcode = PA_BROWSE_NEW_SINK; + else if (!strcmp(type, SERVICE_NAME_SOURCE)) + opcode = PA_BROWSE_NEW_SOURCE; + else if (!strcmp(type, SERVICE_NAME_SERVER)) + opcode = PA_BROWSE_NEW_SERVER; + else + goto fail; + + + snprintf(a, sizeof(a), "tcp:%s:%u", sw_ipv4_address_name(address, ip, sizeof(ip)), port); + i.server = a; + + if (text_record && text_record_len) { + char key[SW_TEXT_RECORD_MAX_LEN]; + uint8_t val[SW_TEXT_RECORD_MAX_LEN]; + uint32_t val_len; + + if (sw_text_record_iterator_init(&iterator, text_record, text_record_len) != SW_OKAY) { + pa_log("sw_text_record_string_iterator_init() failed.\n"); + goto fail; + } + + free_iterator = 1; + + while (sw_text_record_iterator_next(iterator, key, val, &val_len) == SW_OKAY) { + c = pa_xstrndup((char*) val, val_len); + + if (!strcmp(key, "device")) { + device_found = 1; + pa_xfree((char*) i.device); + i.device = c; + c = NULL; + } else if (!strcmp(key, "server-version")) { + pa_xfree((char*) i.server_version); + i.server_version = c; + c = NULL; + } else if (!strcmp(key, "user-name")) { + pa_xfree((char*) i.user_name); + i.user_name = c; + c = NULL; + } else if (!strcmp(key, "fqdn")) { + size_t l; + + pa_xfree((char*) i.fqdn); + i.fqdn = c; + c = NULL; + + l = strlen(a); + assert(l+1 <= sizeof(a)); + strncat(a, " ", sizeof(a)-l-1); + strncat(a, i.fqdn, sizeof(a)-l-2); + } else if (!strcmp(key, "cookie")) { + + if (pa_atou(c, &cookie) < 0) + goto fail; + + i.cookie = &cookie; + } else if (!strcmp(key, "description")) { + pa_xfree((char*) i.description); + i.description = c; + c = NULL; + } else if (!strcmp(key, "typeid")) { + + if (pa_atou(c, &typeid) < 0) + goto fail; + + i.typeid = &typeid; + } else if (!strcmp(key, "channels")) { + uint32_t ch; + + if (pa_atou(c, &ch) < 0 || ch <= 0 || ch > 255) + goto fail; + + ss.channels = (uint8_t) ch; + ss_valid |= 1; + + } else if (!strcmp(key, "rate")) { + if (pa_atou(c, &ss.rate) < 0) + goto fail; + ss_valid |= 2; + } else if (!strcmp(key, "format")) { + + if ((ss.format = pa_parse_sample_format(c)) == PA_SAMPLE_INVALID) + goto fail; + + ss_valid |= 4; + } + + pa_xfree(c); + c = NULL; + } + + } + + /* No device txt record was sent for a sink or source service */ + if (opcode != PA_BROWSE_NEW_SERVER && !device_found) + goto fail; + + if (ss_valid == 7) + i.sample_spec = &ss; + + + b->callback(b, opcode, &i, b->callback_userdata); + +fail: + pa_xfree((void*) i.device); + pa_xfree((void*) i.fqdn); + pa_xfree((void*) i.server_version); + pa_xfree((void*) i.user_name); + pa_xfree((void*) i.description); + pa_xfree(c); + + if (free_iterator) + sw_text_record_iterator_fina(iterator); + + + return SW_OKAY; +} + +static sw_result browse_reply( + sw_discovery discovery, + sw_discovery_oid id, + sw_discovery_browse_status status, + sw_uint32 interface_index, + sw_const_string name, + sw_const_string type, + sw_const_string domain, + sw_opaque extra) { + + pa_browser *b = extra; + assert(b); + + switch (status) { + case SW_DISCOVERY_BROWSE_ADD_SERVICE: { + sw_discovery_oid oid; + + if (sw_discovery_resolve(b->discovery, 0, name, type, domain, resolve_reply, b, &oid) != SW_OKAY) + pa_log("sw_discovery_resolve() failed\n"); + + break; + } + + case SW_DISCOVERY_BROWSE_REMOVE_SERVICE: + if (b->callback) { + pa_browse_info i; + memset(&i, 0, sizeof(i)); + i.name = name; + b->callback(b, PA_BROWSE_REMOVE, &i, b->callback_userdata); + } + break; + + default: + ; + } + + return SW_OKAY; +} + +pa_browser *pa_browser_new(pa_mainloop_api *mainloop) { + pa_browser *b; + sw_discovery_oid oid; + + b = pa_xmalloc(sizeof(pa_browser)); + b->mainloop = mainloop; + b->ref = 1; + b->callback = NULL; + b->callback_userdata = NULL; + + if (sw_discovery_init(&b->discovery) != SW_OKAY) { + pa_log("sw_discovery_init() failed.\n"); + pa_xfree(b); + return NULL; + } + + if (sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SERVER, NULL, browse_reply, b, &oid) != SW_OKAY || + sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SINK, NULL, browse_reply, b, &oid) != SW_OKAY || + sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SOURCE, NULL, browse_reply, b, &oid) != SW_OKAY) { + + pa_log("sw_discovery_browse() failed.\n"); + + sw_discovery_fina(b->discovery); + pa_xfree(b); + return NULL; + } + + b->io_event = mainloop->io_new(mainloop, sw_discovery_socket(b->discovery), PA_IO_EVENT_INPUT, io_callback, b); + return b; +} + +static void browser_free(pa_browser *b) { + assert(b && b->mainloop); + + if (b->io_event) + b->mainloop->io_free(b->io_event); + + sw_discovery_fina(b->discovery); + pa_xfree(b); +} + +pa_browser *pa_browser_ref(pa_browser *b) { + assert(b && b->ref >= 1); + b->ref++; + return b; +} + +void pa_browser_unref(pa_browser *b) { + assert(b && b->ref >= 1); + + if ((-- (b->ref)) <= 0) + browser_free(b); +} + +void pa_browser_set_callback(pa_browser *b, void (*cb)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void* userdata), void *userdata) { + assert(b); + + b->callback = cb; + b->callback_userdata = userdata; +} diff --git a/src/polyp/browser.h b/src/polyp/browser.h new file mode 100644 index 00000000..853304d7 --- /dev/null +++ b/src/polyp/browser.h @@ -0,0 +1,65 @@ +#ifndef foopolyplibbrowserhfoo +#define foopolyplibbrowserhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +PA_C_DECL_BEGIN + +pa_browser; + +pa_browse_opcode { + PA_BROWSE_NEW_SERVER, + PA_BROWSE_NEW_SINK, + PA_BROWSE_NEW_SOURCE, + PA_BROWSE_REMOVE +}; + +pa_browser *pa_browser_new(pa_mainloop_api *mainloop); +pa_browser *pa_browser_ref(pa_browser *z); +void pa_browser_unref(pa_browser *z); + +pa_browse_info { + /* Unique service name */ + const char *name; /* always available */ + + /* Server info */ + const char *server; /* always available */ + const char *server_version, *user_name, *fqdn; /* optional */ + const uint32_t *cookie; /* optional */ + + /* Device info */ + const char *device; /* always available when this information is of a sink/source */ + const char *description; /* optional */ + const pa_typeid_t *typeid; /* optional */ + const pa_sample_spec *sample_spec; /* optional */ +}; + +void pa_browser_set_callback(pa_browser *z, void (*cb)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void *userdata), void *userdata); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/context.c b/src/polyp/context.c new file mode 100644 index 00000000..4ac11caa --- /dev/null +++ b/src/polyp/context.c @@ -0,0 +1,871 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_WAIT_H +#include +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif + +#include + +#include "internal.h" +#include "context.h" +#include "version.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_X11 +#include "client-conf-x11.h" +#endif + +#define AUTOSPAWN_LOCK "autospawn.lock" + +static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_REQUEST] = pa_command_request, + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = pa_command_stream_killed, + [PA_COMMAND_RECORD_STREAM_KILLED] = pa_command_stream_killed, + [PA_COMMAND_SUBSCRIBE_EVENT] = pa_command_subscribe_event +}; + +static void unlock_autospawn_lock_file(pa_context *c) { + assert(c); + + if (c->autospawn_lock_fd >= 0) { + char lf[PATH_MAX]; + pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); + + pa_unlock_lockfile(lf, c->autospawn_lock_fd); + c->autospawn_lock_fd = -1; + } +} + +pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { + pa_context *c; + assert(mainloop && name); + + c = pa_xmalloc(sizeof(pa_context)); + c->ref = 1; + c->name = pa_xstrdup(name); + c->mainloop = mainloop; + c->client = NULL; + c->pstream = NULL; + c->pdispatch = NULL; + c->playback_streams = pa_dynarray_new(); + c->record_streams = pa_dynarray_new(); + assert(c->playback_streams && c->record_streams); + + PA_LLIST_HEAD_INIT(pa_stream, c->streams); + PA_LLIST_HEAD_INIT(pa_operation, c->operations); + + c->error = PA_ERROR_OK; + c->state = PA_CONTEXT_UNCONNECTED; + c->ctag = 0; + + c->state_callback = NULL; + c->state_userdata = NULL; + + c->subscribe_callback = NULL; + c->subscribe_userdata = NULL; + + c->memblock_stat = pa_memblock_stat_new(); + c->local = -1; + c->server_list = NULL; + c->server = NULL; + c->autospawn_lock_fd = -1; + memset(&c->spawn_api, 0, sizeof(c->spawn_api)); + c->do_autospawn = 0; + +#ifdef SIGPIPE + pa_check_signal_is_blocked(SIGPIPE); +#endif + + c->conf = pa_client_conf_new(); + pa_client_conf_load(c->conf, NULL); +#ifdef HAVE_X11 + pa_client_conf_from_x11(c->conf, NULL); +#endif + pa_client_conf_env(c->conf); + + return c; +} + +static void context_free(pa_context *c) { + assert(c); + + unlock_autospawn_lock_file(c); + + while (c->operations) + pa_operation_cancel(c->operations); + + while (c->streams) + pa_stream_set_state(c->streams, PA_STREAM_TERMINATED); + + if (c->client) + pa_socket_client_unref(c->client); + if (c->pdispatch) + pa_pdispatch_unref(c->pdispatch); + if (c->pstream) { + pa_pstream_close(c->pstream); + pa_pstream_unref(c->pstream); + } + + if (c->record_streams) + pa_dynarray_free(c->record_streams, NULL, NULL); + if (c->playback_streams) + pa_dynarray_free(c->playback_streams, NULL, NULL); + + pa_memblock_stat_unref(c->memblock_stat); + + if (c->conf) + pa_client_conf_free(c->conf); + + pa_strlist_free(c->server_list); + + pa_xfree(c->name); + pa_xfree(c->server); + pa_xfree(c); +} + +pa_context* pa_context_ref(pa_context *c) { + assert(c && c->ref >= 1); + c->ref++; + return c; +} + +void pa_context_unref(pa_context *c) { + assert(c && c->ref >= 1); + + if ((--(c->ref)) == 0) + context_free(c); +} + +void pa_context_set_state(pa_context *c, pa_context_state_t st) { + assert(c); + + if (c->state == st) + return; + + pa_context_ref(c); + + if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) { + pa_stream *s; + + s = c->streams ? pa_stream_ref(c->streams) : NULL; + while (s) { + pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL; + pa_stream_set_state(s, st == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED); + pa_stream_unref(s); + s = n; + } + + if (c->pdispatch) + pa_pdispatch_unref(c->pdispatch); + c->pdispatch = NULL; + + if (c->pstream) { + pa_pstream_close(c->pstream); + pa_pstream_unref(c->pstream); + } + c->pstream = NULL; + + if (c->client) + pa_socket_client_unref(c->client); + c->client = NULL; + } + + c->state = st; + if (c->state_callback) + c->state_callback(c, c->state_userdata); + + pa_context_unref(c); +} + +void pa_context_fail(pa_context *c, int error) { + assert(c); + c->error = error; + pa_context_set_state(c, PA_CONTEXT_FAILED); +} + +static void pstream_die_callback(pa_pstream *p, void *userdata) { + pa_context *c = userdata; + assert(p && c); + pa_context_fail(c, PA_ERROR_CONNECTIONTERMINATED); +} + +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { + pa_context *c = userdata; + assert(p && packet && c); + + pa_context_ref(c); + + if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { + pa_log(__FILE__": invalid packet.\n"); + pa_context_fail(c, PA_ERROR_PROTOCOL); + } + + pa_context_unref(c); +} + +static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, PA_GCC_UNUSED uint32_t delta, const pa_memchunk *chunk, void *userdata) { + pa_context *c = userdata; + pa_stream *s; + assert(p && chunk && c && chunk->memblock && chunk->memblock->data); + + pa_context_ref(c); + + if ((s = pa_dynarray_get(c->record_streams, channel))) { + pa_mcalign_push(s->mcalign, chunk); + + for (;;) { + pa_memchunk t; + + if (pa_mcalign_pop(s->mcalign, &t) < 0) + break; + + if (s->read_callback) { + s->read_callback(s, (uint8_t*) t.memblock->data + t.index, t.length, s->read_userdata); + s->counter += chunk->length; + } + + pa_memblock_unref(t.memblock); + } + } + + pa_context_unref(c); +} + +int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t) { + assert(c); + + if (command == PA_COMMAND_ERROR) { + assert(t); + + if (pa_tagstruct_getu32(t, &c->error) < 0) { + pa_context_fail(c, PA_ERROR_PROTOCOL); + return -1; + + } + } else if (command == PA_COMMAND_TIMEOUT) + c->error = PA_ERROR_TIMEOUT; + else { + pa_context_fail(c, PA_ERROR_PROTOCOL); + return -1; + } + + return 0; +} + +static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_context *c = userdata; + assert(pd && c && (c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME)); + + pa_context_ref(c); + + if (command != PA_COMMAND_REPLY) { + + if (pa_context_handle_error(c, command, t) < 0) + pa_context_fail(c, PA_ERROR_PROTOCOL); + + pa_context_fail(c, c->error); + goto finish; + } + + switch(c->state) { + case PA_CONTEXT_AUTHORIZING: { + pa_tagstruct *reply; + reply = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME); + pa_tagstruct_putu32(reply, tag = c->ctag++); + pa_tagstruct_puts(reply, c->name); + pa_pstream_send_tagstruct(c->pstream, reply); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + + pa_context_set_state(c, PA_CONTEXT_SETTING_NAME); + break; + } + + case PA_CONTEXT_SETTING_NAME : + pa_context_set_state(c, PA_CONTEXT_READY); + break; + + default: + assert(0); + } + +finish: + pa_context_unref(c); +} + +static void setup_context(pa_context *c, pa_iochannel *io) { + pa_tagstruct *t; + uint32_t tag; + assert(c && io); + + pa_context_ref(c); + + assert(!c->pstream); + c->pstream = pa_pstream_new(c->mainloop, io, c->memblock_stat); + assert(c->pstream); + + pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); + pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); + pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); + + assert(!c->pdispatch); + c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); + assert(c->pdispatch); + + if (!c->conf->cookie_valid) { + pa_context_fail(c, PA_ERROR_AUTHKEY); + goto finish; + } + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_AUTH); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie)); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + + pa_context_set_state(c, PA_CONTEXT_AUTHORIZING); + +finish: + + pa_context_unref(c); +} + +static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata); + +#ifndef OS_IS_WIN32 + +static int context_connect_spawn(pa_context *c) { + pid_t pid; + int status, r; + int fds[2] = { -1, -1} ; + pa_iochannel *io; + + pa_context_ref(c); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { + pa_log(__FILE__": socketpair() failed: %s\n", strerror(errno)); + pa_context_fail(c, PA_ERROR_INTERNAL); + goto fail; + } + + pa_fd_set_cloexec(fds[0], 1); + + pa_socket_low_delay(fds[0]); + pa_socket_low_delay(fds[1]); + + if (c->spawn_api.prefork) + c->spawn_api.prefork(); + + if ((pid = fork()) < 0) { + pa_log(__FILE__": fork() failed: %s\n", strerror(errno)); + pa_context_fail(c, PA_ERROR_INTERNAL); + + if (c->spawn_api.postfork) + c->spawn_api.postfork(); + + goto fail; + } else if (!pid) { + /* Child */ + + char t[128]; + const char *state = NULL; +#define MAX_ARGS 64 + const char * argv[MAX_ARGS+1]; + int n; + + /* Not required, since fds[0] has CLOEXEC enabled anyway */ + close(fds[0]); + + if (c->spawn_api.atfork) + c->spawn_api.atfork(); + + /* Setup argv */ + + n = 0; + + argv[n++] = c->conf->daemon_binary; + argv[n++] = "--daemonize=yes"; + + snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]); + argv[n++] = strdup(t); + + while (n < MAX_ARGS) { + char *a; + + if (!(a = pa_split_spaces(c->conf->extra_arguments, &state))) + break; + + argv[n++] = a; + } + + argv[n++] = NULL; + + execv(argv[0], (char * const *) argv); + _exit(1); +#undef MAX_ARGS + } + + /* Parent */ + + r = waitpid(pid, &status, 0); + + if (c->spawn_api.postfork) + c->spawn_api.postfork(); + + if (r < 0) { + pa_log(__FILE__": waitpid() failed: %s\n", strerror(errno)); + pa_context_fail(c, PA_ERROR_INTERNAL); + goto fail; + } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + goto fail; + } + + close(fds[1]); + + c->local = 1; + + io = pa_iochannel_new(c->mainloop, fds[0], fds[0]); + + setup_context(c, io); + unlock_autospawn_lock_file(c); + + pa_context_unref(c); + + return 0; + +fail: + if (fds[0] != -1) + close(fds[0]); + if (fds[1] != -1) + close(fds[1]); + + unlock_autospawn_lock_file(c); + + pa_context_unref(c); + + return -1; +} + +#endif /* OS_IS_WIN32 */ + +static int try_next_connection(pa_context *c) { + char *u = NULL; + int r = -1; + assert(c && !c->client); + + for (;;) { + if (u) + pa_xfree(u); + u = NULL; + + c->server_list = pa_strlist_pop(c->server_list, &u); + + if (!u) { + +#ifndef OS_IS_WIN32 + if (c->do_autospawn) { + r = context_connect_spawn(c); + goto finish; + } +#endif + + pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + goto finish; + } + + pa_log_debug(__FILE__": Trying to connect to %s...\n", u); + + pa_xfree(c->server); + c->server = pa_xstrdup(u); + + if (!(c->client = pa_socket_client_new_string(c->mainloop, u, PA_NATIVE_DEFAULT_PORT))) + continue; + + c->local = pa_socket_client_is_local(c->client); + pa_socket_client_set_callback(c->client, on_connection, c); + break; + } + + r = 0; + +finish: + if (u) + pa_xfree(u); + + return r; +} + +static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata) { + pa_context *c = userdata; + assert(client && c && c->state == PA_CONTEXT_CONNECTING); + + pa_context_ref(c); + + pa_socket_client_unref(client); + c->client = NULL; + + if (!io) { + /* Try the item in the list */ + if (errno == ECONNREFUSED || errno == ETIMEDOUT || errno == EHOSTUNREACH) { + try_next_connection(c); + goto finish; + } + + pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + goto finish; + } + + unlock_autospawn_lock_file(c); + setup_context(c, io); + +finish: + pa_context_unref(c); +} + +int pa_context_connect(pa_context *c, const char *server, int spawn, const pa_spawn_api *api) { + int r = -1; + assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED); + + if (!server) + server = c->conf->default_server; + + pa_context_ref(c); + + assert(!c->server_list); + + if (server) { + if (!(c->server_list = pa_strlist_parse(server))) { + pa_context_fail(c, PA_ERROR_INVALIDSERVER); + goto finish; + } + } else { + char *d; + char ufn[PATH_MAX]; + + /* Prepend in reverse order */ + + if ((d = getenv("DISPLAY"))) { + char *e; + d = pa_xstrdup(d); + if ((e = strchr(d, ':'))) + *e = 0; + + if (*d) + c->server_list = pa_strlist_prepend(c->server_list, d); + + pa_xfree(d); + } + + c->server_list = pa_strlist_prepend(c->server_list, "tcp6:localhost"); + c->server_list = pa_strlist_prepend(c->server_list, "localhost"); + c->server_list = pa_strlist_prepend(c->server_list, pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET, ufn, sizeof(ufn))); + + /* Wrap the connection attempts in a single transaction for sane autospawn locking */ + if (spawn && c->conf->autospawn) { + char lf[PATH_MAX]; + + pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); + pa_make_secure_parent_dir(lf); + assert(c->autospawn_lock_fd <= 0); + c->autospawn_lock_fd = pa_lock_lockfile(lf); + + if (api) + c->spawn_api = *api; + c->do_autospawn = 1; + } + + } + + pa_context_set_state(c, PA_CONTEXT_CONNECTING); + r = try_next_connection(c); + +finish: + pa_context_unref(c); + + return r; +} + +void pa_context_disconnect(pa_context *c) { + assert(c); + pa_context_set_state(c, PA_CONTEXT_TERMINATED); +} + +pa_context_state_t pa_context_get_state(pa_context *c) { + assert(c && c->ref >= 1); + return c->state; +} + +int pa_context_errno(pa_context *c) { + assert(c && c->ref >= 1); + return c->error; +} + +void pa_context_set_state_callback(pa_context *c, void (*cb)(pa_context *c, void *userdata), void *userdata) { + assert(c && c->ref >= 1); + c->state_callback = cb; + c->state_userdata = userdata; +} + +int pa_context_is_pending(pa_context *c) { + assert(c && c->ref >= 1); + +/* pa_log("pstream: %i\n", pa_pstream_is_pending(c->pstream)); */ +/* pa_log("pdispatch: %i\n", pa_pdispatch_is_pending(c->pdispatch)); */ + + return (c->pstream && pa_pstream_is_pending(c->pstream)) || + (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) || + c->client; +} + +static void set_dispatch_callbacks(pa_operation *o); + +static void pdispatch_drain_callback(PA_GCC_UNUSED pa_pdispatch*pd, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void pstream_drain_callback(PA_GCC_UNUSED pa_pstream *s, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void set_dispatch_callbacks(pa_operation *o) { + int done = 1; + assert(o && o->context && o->context->ref >= 1 && o->ref >= 1 && o->context->state == PA_CONTEXT_READY); + + pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL); + + if (pa_pdispatch_is_pending(o->context->pdispatch)) { + pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o); + done = 0; + } + + if (pa_pstream_is_pending(o->context->pstream)) { + pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o); + done = 0; + } + + if (!done) + pa_operation_ref(o); + else { + if (o->callback) { + void (*cb)(pa_context *c, void *userdata); + cb = (void (*)(pa_context*, void*)) o->callback; + cb(o->context, o->userdata); + } + + pa_operation_done(o); + } + + pa_operation_unref(o); +} + +pa_operation* pa_context_drain(pa_context *c, void (*cb) (pa_context*c, void *userdata), void *userdata) { + pa_operation *o; + assert(c && c->ref >= 1); + + if (c->state != PA_CONTEXT_READY) + return NULL; + + if (!pa_context_is_pending(c)) + return NULL; + + o = pa_operation_new(c, NULL); + assert(o); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + set_dispatch_callbacks(pa_operation_ref(o)); + + return o; +} + +void pa_context_exit_daemon(pa_context *c) { + pa_tagstruct *t; + assert(c && c->ref >= 1); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_EXIT); + pa_tagstruct_putu32(t, c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); +} + +void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int success = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + success = 0; + } else if (!pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *c, int _success, void *_userdata) = (void (*)(pa_context *c, int _success, void *_userdata)) o->callback; + cb(o->context, success, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, void (*internal_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata), void (*cb)(void), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, command); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_DEFAULT_SINK); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_set_default_source(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_DEFAULT_SOURCE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +int pa_context_is_local(pa_context *c) { + assert(c); + return c->local; +} + +pa_operation* pa_context_set_name(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && name && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_CLIENT_NAME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +const char* pa_get_library_version(void) { + return PACKAGE_VERSION; +} + +const char* pa_context_get_server(pa_context *c) { + + if (!c->server) + return NULL; + + if (*c->server == '{') { + char *e = strchr(c->server+1, '}'); + return e ? e+1 : c->server; + } + + return c->server; +} diff --git a/src/polyp/context.h b/src/polyp/context.h new file mode 100644 index 00000000..6496c703 --- /dev/null +++ b/src/polyp/context.h @@ -0,0 +1,117 @@ +#ifndef foopolyplibcontexthfoo +#define foopolyplibcontexthfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include +#include + +/** \file + * Connection contexts for asynchrononous communication with a + * server. A pa_context object wraps a connection to a polypaudio + * server using its native protocol. A context may be used to issue + * commands on the server or to create playback or recording + * streams. Multiple playback streams may be piped through a single + * connection context. Operations on the contect involving + * communication with the server are executed asynchronously: i.e. the + * client function do not implicitely wait for completion of the + * operation on the server. Instead the caller specifies a call back + * function that is called when the operation is completed. Currently + * running operations may be canceled using pa_operation_cancel(). */ + +/** \example pacat.c + * A playback and recording tool using the asynchronous API */ + +/** \example paplay.c + * A sound file playback tool using the asynchronous API, based on libsndfile */ + +PA_C_DECL_BEGIN + +/** \pa_context + * An opaque connection context to a daemon */ +typedef struct pa_context pa_context; + +/** Instantiate a new connection context with an abstract mainloop API + * and an application name */ +pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name); + +/** Decrease the reference counter of the context by one */ +void pa_context_unref(pa_context *c); + +/** Increase the reference counter of the context by one */ +pa_context* pa_context_ref(pa_context *c); + +typedef void (*pa_context_state_callback)(pa_context *c, void *userdata); + +/** Set a callback function that is called whenever the context status changes */ +void pa_context_set_state_callback(pa_context *c, pa_context_state_callback callback, void *userdata); + +/** Return the error number of the last failed operation */ +int pa_context_errno(pa_context *c); + +/** Return non-zero if some data is pending to be written to the connection */ +int pa_context_is_pending(pa_context *c); + +/** Return the current context status */ +pa_context_state_t pa_context_get_state(pa_context *c); + +/** Connect the context to the specified server. If server is NULL, +connect to the default server. This routine may but will not always +return synchronously on error. Use pa_context_set_state_callback() to +be notified when the connection is established. If spawn is non-zero +and no specific server is specified or accessible a new daemon is +spawned. If api is non-NULL, the functions specified in the structure +are used when forking a new child process. */ +int pa_context_connect(pa_context *c, const char *server, int spawn, const pa_spawn_api *api); + +/** Terminate the context connection immediately */ +void pa_context_disconnect(pa_context *c); + +/** Drain the context. If there is nothing to drain, the function returns NULL */ +pa_operation* pa_context_drain(pa_context *c, void (*cb) (pa_context*c, void *userdata), void *userdata); + +/** Tell the daemon to exit. No operation object is returned as the + * connection is terminated when the daemon quits, thus this operation + * would never complete. */ +void pa_context_exit_daemon(pa_context *c); + +/** Set the name of the default sink. \since 0.4 */ +pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata); + +/** Set the name of the default source. \since 0.4 */ +pa_operation* pa_context_set_default_source(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata); + +/** Returns 1 when the connection is to a local daemon. Returns negative when no connection has been made yet. \since 0.5 */ +int pa_context_is_local(pa_context *c); + +/** Set a different application name for context on the server. \since 0.5 */ +pa_operation* pa_context_set_name(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata); + +/** Return the server name this context is connected to. \since 0.7 */ +const char* pa_context_get_server(pa_context *c); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/def.h b/src/polyp/def.h new file mode 100644 index 00000000..0591ce6c --- /dev/null +++ b/src/polyp/def.h @@ -0,0 +1,213 @@ +#ifndef foopolyplibdefhfoo +#define foopolyplibdefhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include + +#include +#include + +/** \file + * Global definitions */ + +PA_C_DECL_BEGIN + +/** The state of a connection context */ +typedef enum pa_context_state { + PA_CONTEXT_UNCONNECTED, /**< The context hasn't been connected yet */ + PA_CONTEXT_CONNECTING, /**< A connection is being established */ + PA_CONTEXT_AUTHORIZING, /**< The client is authorizing itself to the daemon */ + PA_CONTEXT_SETTING_NAME, /**< The client is passing its application name to the daemon */ + PA_CONTEXT_READY, /**< The connection is established, the context is ready to execute operations */ + PA_CONTEXT_FAILED, /**< The connection failed or was disconnected */ + PA_CONTEXT_TERMINATED /**< The connection was terminated cleanly */ +} pa_context_state_t; + +/** The state of a stream */ +typedef enum pa_stream_state { + PA_STREAM_DISCONNECTED, /**< The stream is not yet connected to any sink or source */ + PA_STREAM_CREATING, /**< The stream is being created */ + PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */ + PA_STREAM_FAILED, /**< An error occured that made the stream invalid */ + PA_STREAM_TERMINATED /**< The stream has been terminated cleanly */ +} pa_stream_state_t; + +/** The state of an operation */ +typedef enum pa_operation_state { + PA_OPERATION_RUNNING, /**< The operation is still running */ + PA_OPERATION_DONE, /**< The operation has been completed */ + PA_OPERATION_CANCELED /**< The operation has been canceled */ +} pa_operation_state_t; + +/** An invalid index */ +#define PA_INVALID_INDEX ((uint32_t) -1) + +/** The direction of a pa_stream object */ +typedef enum pa_stream_direction { + PA_STREAM_NODIRECTION, /**< Invalid direction */ + PA_STREAM_PLAYBACK, /**< Playback stream */ + PA_STREAM_RECORD, /**< Record stream */ + PA_STREAM_UPLOAD /**< Sample upload stream */ +} pa_stream_direction_t; + +/** Some special flags for stream connections. \since 0.6 */ +typedef enum pa_stream_flags { + PA_STREAM_START_CORKED = 1, /**< Create the stream corked, requiring an explicit pa_stream_cork() call to uncork it. */ + PA_STREAM_INTERPOLATE_LATENCY = 2 /**< Interpolate the latency for + * this stream. When enabled, + * you can use + * pa_stream_interpolated_xxx() + * for synchronization. Using + * these functions instead of + * pa_stream_get_latency() has + * the advantage of not + * requiring a whole roundtrip + * for responses. Consider using + * this option when frequently + * requesting latency + * information. This is + * especially useful on long latency + * network connections. */ +} pa_stream_flags_t; + +/** Playback and record buffer metrics */ +typedef struct pa_buffer_attr { + uint32_t maxlength; /**< Maximum length of the buffer */ + uint32_t tlength; /**< Playback only: target length of the buffer. The server tries to assure that at least tlength bytes are always available in the buffer */ + uint32_t prebuf; /**< Playback only: pre-buffering. The server does not start with playback before at least prebug bytes are available in the buffer */ + uint32_t minreq; /**< Playback only: minimum request. The server does not request less than minreq bytes from the client, instead waints until the buffer is free enough to request more bytes at once */ + uint32_t fragsize; /**< Recording only: fragment size. The server sends data in blocks of fragsize bytes size. Large values deminish interactivity with other operations on the connection context but decrease control overhead. */ +} pa_buffer_attr; + +/** Error values as used by pa_context_errno(). Use pa_strerror() to convert these values to human readable strings */ +enum { + PA_ERROR_OK, /**< No error */ + PA_ERROR_ACCESS, /**< Access failure */ + PA_ERROR_COMMAND, /**< Unknown command */ + PA_ERROR_INVALID, /**< Invalid argument */ + PA_ERROR_EXIST, /**< Entity exists */ + PA_ERROR_NOENTITY, /**< No such entity */ + PA_ERROR_CONNECTIONREFUSED, /**< Connection refused */ + PA_ERROR_PROTOCOL, /**< Protocol error */ + PA_ERROR_TIMEOUT, /**< Timeout */ + PA_ERROR_AUTHKEY, /**< No authorization key */ + PA_ERROR_INTERNAL, /**< Internal error */ + PA_ERROR_CONNECTIONTERMINATED, /**< Connection terminated */ + PA_ERROR_KILLED, /**< Entity killed */ + PA_ERROR_INVALIDSERVER, /**< Invalid server */ + PA_ERROR_INITFAILED, /**< Module initialization failed */ + PA_ERROR_MAX /**< Not really an error but the first invalid error code */ +}; + +/** Subscription event mask, as used by pa_context_subscribe() */ +typedef enum pa_subscription_mask { + PA_SUBSCRIPTION_MASK_NULL = 0, /**< No events */ + PA_SUBSCRIPTION_MASK_SINK = 1, /**< Sink events */ + PA_SUBSCRIPTION_MASK_SOURCE = 2, /**< Source events */ + PA_SUBSCRIPTION_MASK_SINK_INPUT = 4, /**< Sink input events */ + PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8, /**< Source output events */ + PA_SUBSCRIPTION_MASK_MODULE = 16, /**< Module events */ + PA_SUBSCRIPTION_MASK_CLIENT = 32, /**< Client events */ + PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, /**< Sample cache events */ + PA_SUBSCRIPTION_MASK_SERVER = 128, /**< Other global server changes. \since 0.4 */ + PA_SUBSCRIPTION_MASK_AUTOLOAD = 256 /**< Autoload table events. \since 0.5 */ +} pa_subscription_mask_t; + +/** Subscription event types, as used by pa_context_subscribe() */ +typedef enum pa_subscription_event_type { + PA_SUBSCRIPTION_EVENT_SINK = 0, /**< Event type: Sink */ + PA_SUBSCRIPTION_EVENT_SOURCE = 1, /**< Event type: Source */ + PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2, /**< Event type: Sink input */ + PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 3, /**< Event type: Source output */ + PA_SUBSCRIPTION_EVENT_MODULE = 4, /**< Event type: Module */ + PA_SUBSCRIPTION_EVENT_CLIENT = 5, /**< Event type: Client */ + PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, /**< Event type: Sample cache item */ + PA_SUBSCRIPTION_EVENT_SERVER = 7, /**< Event type: Global server change, only occuring with PA_SUBSCRIPTION_EVENT_CHANGE. \since 0.4 */ + PA_SUBSCRIPTION_EVENT_AUTOLOAD = 8, /**< Event type: Autoload table changes. \since 0.5 */ + PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 15, /**< A mask to extract the event type from an event value */ + + PA_SUBSCRIPTION_EVENT_NEW = 0, /**< A new object was created */ + PA_SUBSCRIPTION_EVENT_CHANGE = 16, /**< A property of the object was modified */ + PA_SUBSCRIPTION_EVENT_REMOVE = 32, /**< An object was removed */ + PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32 /**< A mask to extract the event operation from an event value */ +} pa_subscription_event_type_t; + +/** Return one if an event type t matches an event mask bitfield */ +#define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) + +/** A structure for latency info. See pa_stream_get_latency(). The + * total output latency a sample that is written with + * pa_stream_write() takes to be played may be estimated by + * sink_usec+buffer_usec+transport_usec. The output buffer to which + * buffer_usec relates may be manipulated freely (with + * pa_stream_write()'s delta argument, pa_stream_flush() and friends), + * the buffers sink_usec/source_usec relates to is a first-in + * first-out buffer which cannot be flushed or manipulated in any + * way. The total input latency a sample that is recorded takes to be + * delivered to the application is: + * source_usec+buffer_usec+transport_usec-sink_usec. (Take care of + * sign issues!) When connected to a monitor source sink_usec contains + * the latency of the owning sink.*/ +typedef struct pa_latency_info { + pa_usec_t buffer_usec; /**< Time in usecs the current buffer takes to play. For both playback and record streams. */ + pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. For playback streams and record streams connected to a monitor source. */ + pa_usec_t source_usec; /**< Time in usecs a sample takes from being recorded to being delivered to the application. Only for record streams. \since 0.5*/ + pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to/from the daemon. For both playback and record streams. \since 0.5 */ + int playing; /**< Non-zero when the stream is currently playing. Only for playback streams. */ + uint32_t queue_length; /**< Queue size in bytes. For both playback and record streams. */ + int synchronized_clocks; /**< Non-zero if the local and the + * remote machine have synchronized + * clocks. If synchronized clocks are + * detected transport_usec becomes much + * more reliable. However, the code that + * detects synchronized clocks is very + * limited und unreliable itself. \since + * 0.5 */ + struct timeval timestamp; /**< The time when this latency info was current */ + uint64_t counter; /**< The byte counter current when the latency info was requested. \since 0.6 */ +} pa_latency_info; + +/** A structure for the spawn api. This may be used to integrate auto + * spawned daemons into your application. For more information see + * pa_context_connect(). When spawning a new child process the + * waitpid() is used on the child's PID. The spawn routine will not + * block or ignore SIGCHLD signals, since this cannot be done in a + * thread compatible way. You might have to do this in + * prefork/postfork. \since 0.4 */ +typedef struct pa_spawn_api { + void (*prefork)(void); /**< Is called just before the fork in the parent process. May be NULL. */ + void (*postfork)(void); /**< Is called immediately after the fork in the parent process. May be NULL.*/ + void (*atfork)(void); /**< Is called immediately after the + * fork in the child process. May be + * NULL. It is not safe to close all + * file descriptors in this function + * unconditionally, since a UNIX socket + * (created using socketpair()) is + * passed to the new process. */ +} pa_spawn_api; + +PA_C_DECL_END + +#endif diff --git a/src/polyp/error.c b/src/polyp/error.c new file mode 100644 index 00000000..a137ab49 --- /dev/null +++ b/src/polyp/error.c @@ -0,0 +1,54 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "error.h" +#include + +static const char* const errortab[PA_ERROR_MAX] = { + [PA_ERROR_OK] = "OK", + [PA_ERROR_ACCESS] = "Access denied", + [PA_ERROR_COMMAND] = "Unknown command", + [PA_ERROR_INVALID] = "Invalid argument", + [PA_ERROR_EXIST] = "Entity exists", + [PA_ERROR_NOENTITY] = "No such entity", + [PA_ERROR_CONNECTIONREFUSED] = "Connection refused", + [PA_ERROR_PROTOCOL] = "Protocol error", + [PA_ERROR_TIMEOUT] = "Timeout", + [PA_ERROR_AUTHKEY] = "No authorization key", + [PA_ERROR_INTERNAL] = "Internal error", + [PA_ERROR_CONNECTIONTERMINATED] = "Connection terminated", + [PA_ERROR_KILLED] = "Entity killed", + [PA_ERROR_INVALIDSERVER] = "Invalid server", +}; + +const char*pa_strerror(uint32_t error) { + if (error >= PA_ERROR_MAX) + return NULL; + + return errortab[error]; +} diff --git a/src/polyp/error.h b/src/polyp/error.h new file mode 100644 index 00000000..1bb97822 --- /dev/null +++ b/src/polyp/error.h @@ -0,0 +1,38 @@ +#ifndef foopolypliberrorhfoo +#define foopolypliberrorhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/** \file + * Error management */ + +PA_C_DECL_BEGIN + +/** Return a human readable error message for the specified numeric error code */ +const char* pa_strerror(uint32_t error); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/internal.h b/src/polyp/internal.h new file mode 100644 index 00000000..feb9f6f4 --- /dev/null +++ b/src/polyp/internal.h @@ -0,0 +1,154 @@ +#ifndef foopolyplibinternalhfoo +#define foopolyplibinternalhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include +#include + +#include "context.h" +#include "stream.h" +#include "operation.h" +#include +#include +#include +#include +#include + +#define DEFAULT_TIMEOUT (10) + +struct pa_context { + int ref; + + char *name; + pa_mainloop_api* mainloop; + + pa_socket_client *client; + pa_pstream *pstream; + pa_pdispatch *pdispatch; + + pa_dynarray *record_streams, *playback_streams; + PA_LLIST_HEAD(pa_stream, streams); + PA_LLIST_HEAD(pa_operation, operations); + + uint32_t ctag; + uint32_t error; + pa_context_state_t state; + + void (*state_callback)(pa_context*c, void *userdata); + void *state_userdata; + + void (*subscribe_callback)(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata); + void *subscribe_userdata; + + pa_memblock_stat *memblock_stat; + + int local; + int do_autospawn; + int autospawn_lock_fd; + pa_spawn_api spawn_api; + + pa_strlist *server_list; + + char *server; + + pa_client_conf *conf; +}; + +struct pa_stream { + int ref; + pa_context *context; + pa_mainloop_api *mainloop; + PA_LLIST_FIELDS(pa_stream); + + char *name; + pa_buffer_attr buffer_attr; + pa_sample_spec sample_spec; + pa_channel_map channel_map; + uint32_t channel; + int channel_valid; + uint32_t device_index; + pa_stream_direction_t direction; + uint32_t requested_bytes; + uint64_t counter; + pa_usec_t previous_time; + pa_usec_t previous_ipol_time; + pa_stream_state_t state; + pa_mcalign *mcalign; + + int interpolate; + int corked; + + uint32_t ipol_usec; + struct timeval ipol_timestamp; + pa_time_event *ipol_event; + int ipol_requested; + + void (*state_callback)(pa_stream*c, void *userdata); + void *state_userdata; + + void (*read_callback)(pa_stream *p, const void*data, size_t length, void *userdata); + void *read_userdata; + + void (*write_callback)(pa_stream *p, size_t length, void *userdata); + void *write_userdata; +}; + +typedef void (*pa_operation_callback)(void); + +struct pa_operation { + int ref; + pa_context *context; + pa_stream *stream; + PA_LLIST_FIELDS(pa_operation); + + pa_operation_state_t state; + void *userdata; + pa_operation_callback callback; +}; + +void pa_command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); + +pa_operation *pa_operation_new(pa_context *c, pa_stream *s); +void pa_operation_done(pa_operation *o); + +void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); + +void pa_context_fail(pa_context *c, int error); +void pa_context_set_state(pa_context *c, pa_context_state_t st); +int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t); +pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, void (*internal_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata), void (*cb)(void), void *userdata); + +void pa_stream_set_state(pa_stream *s, pa_stream_state_t st); + +void pa_stream_trash_ipol(pa_stream *s); + + +#endif diff --git a/src/polyp/introspect.c b/src/polyp/introspect.c new file mode 100644 index 00000000..d89eb9ed --- /dev/null +++ b/src/polyp/introspect.c @@ -0,0 +1,1003 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "introspect.h" +#include "context.h" +#include "internal.h" +#include +#include + +/*** Statistics ***/ + +static void context_stat_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + pa_stat_info i, *p = &i; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + p = NULL; + } else if (pa_tagstruct_getu32(t, &i.memblock_total) < 0 || + pa_tagstruct_getu32(t, &i.memblock_total_size) < 0 || + pa_tagstruct_getu32(t, &i.memblock_allocated) < 0 || + pa_tagstruct_getu32(t, &i.memblock_allocated_size) < 0 || + pa_tagstruct_getu32(t, &i.scache_size) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_stat_info*_i, void *_userdata) = (void (*)(pa_context *s, const pa_stat_info*_i, void *_userdata)) o->callback; + cb(o->context, p, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_stat(pa_context *c, void (*cb)(pa_context *c, const pa_stat_info*i, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_STAT, context_stat_callback, (pa_operation_callback) cb, userdata); +} + +/*** Server Info ***/ + +static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + pa_server_info i, *p = &i; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + p = NULL; + } else if (pa_tagstruct_gets(t, &i.server_name) < 0 || + pa_tagstruct_gets(t, &i.server_version) < 0 || + pa_tagstruct_gets(t, &i.user_name) < 0 || + pa_tagstruct_gets(t, &i.host_name) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_gets(t, &i.default_sink_name) < 0 || + pa_tagstruct_gets(t, &i.default_source_name) < 0 || + pa_tagstruct_getu32(t, &i.cookie) < 0 || + !pa_tagstruct_eof(t)) { + + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_server_info*_i, void *_userdata) = (void (*)(pa_context *s, const pa_server_info*_i, void *_userdata)) o->callback; + cb(o->context, p, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_server_info(pa_context *c, void (*cb)(pa_context *c, const pa_server_info*i, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SERVER_INFO, context_get_server_info_callback, (pa_operation_callback) cb, userdata); +} + +/*** Sink Info ***/ + +static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_sink_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_get_cvolume(t, &i.volume) < 0 || + pa_tagstruct_getu32(t, &i.monitor_source) < 0 || + pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || + pa_tagstruct_get_usec(t, &i.latency) < 0 || + pa_tagstruct_gets(t, &i.driver) < 0) { + + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_sink_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INFO_LIST, context_get_sink_info_callback, (pa_operation_callback) cb, userdata); +} + +pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, o); + + return pa_operation_ref(o); +} + +/*** Source info ***/ + +static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_source_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || + pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 || + pa_tagstruct_get_usec(t, &i.latency) < 0 || + pa_tagstruct_gets(t, &i.driver) < 0) { + + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_source_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_INFO_LIST, context_get_source_info_callback, (pa_operation_callback) cb, userdata); +} + +pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, o); + + return pa_operation_ref(o); +} + +/*** Client info ***/ + +static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_client_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_gets(t, &i.driver) < 0 ) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_client_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_CLIENT_INFO_LIST, context_get_client_info_callback, (pa_operation_callback) cb, userdata); +} + +/*** Module info ***/ + +static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_module_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.argument) < 0 || + pa_tagstruct_getu32(t, &i.n_used) < 0 || + pa_tagstruct_get_boolean(t, &i.auto_unload) < 0) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_module_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_MODULE_INFO_LIST, context_get_module_info_callback, (pa_operation_callback) cb, userdata); +} + +/*** Sink input info ***/ + +static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_sink_input_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.client) < 0 || + pa_tagstruct_getu32(t, &i.sink) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || + pa_tagstruct_get_cvolume(t, &i.volume) < 0 || + pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || + pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || + pa_tagstruct_gets(t, &i.resample_method) < 0 || + pa_tagstruct_gets(t, &i.driver) < 0) { + + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INPUT_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_input_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_sink_input_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INPUT_INFO_LIST, context_get_sink_input_info_callback, (pa_operation_callback) cb, userdata); +} + +/*** Source output info ***/ + +static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_source_output_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.client) < 0 || + pa_tagstruct_getu32(t, &i.source) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || + pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || + pa_tagstruct_get_usec(t, &i.source_usec) < 0 || + pa_tagstruct_gets(t, &i.resample_method) < 0 || + pa_tagstruct_gets(t, &i.driver) < 0) { + + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata))o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_OUTPUT_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_output_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_source_output_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, context_get_source_output_info_callback, (pa_operation_callback) cb, userdata); +} + +/*** Volume manipulation ***/ + +pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && idx != PA_INVALID_INDEX); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_tagstruct_put_cvolume(t, volume); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && name); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_tagstruct_put_cvolume(t, volume); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && idx != PA_INVALID_INDEX); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_put_cvolume(t, volume); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +/** Sample Cache **/ + +static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_sample_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_get_cvolume(t, &i.volume) < 0 || + pa_tagstruct_get_usec(t, &i.duration) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || + pa_tagstruct_getu32(t, &i.bytes) < 0 || + pa_tagstruct_get_boolean(t, &i.lazy) < 0 || + pa_tagstruct_gets(t, &i.filename) < 0) { + + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb && name); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SAMPLE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SAMPLE_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_sample_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SAMPLE_INFO_LIST, context_get_sample_info_callback, (pa_operation_callback) cb, userdata); +} + +static pa_operation* command_kill(pa_context *c, uint32_t command, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && idx != PA_INVALID_INDEX); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, command); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + return command_kill(c, PA_COMMAND_KILL_CLIENT, idx, cb, userdata); +} + +pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + return command_kill(c, PA_COMMAND_KILL_SINK_INPUT, idx, cb, userdata); +} + +pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + return command_kill(c, PA_COMMAND_KILL_SOURCE_OUTPUT, idx, cb, userdata); +} + +static void load_module_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + uint32_t idx = -1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + } else if (pa_tagstruct_getu32(t, &idx) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *c, uint32_t _idx, void *_userdata) = (void (*)(pa_context *c, uint32_t _idx, void *_userdata)) o->callback; + cb(o->context, idx, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, void (*cb)(pa_context *c, uint32_t idx, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && name && argument); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_LOAD_MODULE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_puts(t, argument); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, load_module_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + return command_kill(c, PA_COMMAND_UNLOAD_MODULE, idx, cb, userdata); +} + +/*** Autoload stuff ***/ + +static void context_get_autoload_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_autoload_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_getu32(t, &i.type) < 0 || + pa_tagstruct_gets(t, &i.module) < 0 || + pa_tagstruct_gets(t, &i.argument) < 0) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + void (*cb)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata)) o->callback; + cb(o->context, NULL, eof, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb && name); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_AUTOLOAD_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_putu32(t, type); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(c && cb && idx != PA_INVALID_INDEX); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_AUTOLOAD_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_get_autoload_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, context_get_autoload_info_callback, (pa_operation_callback) cb, userdata); +} + +static void context_add_autoload_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + uint32_t idx; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + idx = PA_INVALID_INDEX; + } else if (pa_tagstruct_getu32(t, &idx) || + !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_context *s, uint32_t _idx, void *_userdata) = (void (*)(pa_context *s, uint32_t _idx, void *_userdata)) o->callback; + cb(o->context, idx, o->userdata); + } + + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && name && module && argument); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_ADD_AUTOLOAD); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_putu32(t, type); + pa_tagstruct_puts(t, module); + pa_tagstruct_puts(t, argument); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_add_autoload_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && name); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_AUTOLOAD); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_tagstruct_putu32(t, type); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && idx != PA_INVALID_INDEX); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_AUTOLOAD); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} diff --git a/src/polyp/introspect.h b/src/polyp/introspect.h new file mode 100644 index 00000000..75dc027f --- /dev/null +++ b/src/polyp/introspect.h @@ -0,0 +1,279 @@ +#ifndef foopolyplibintrospecthfoo +#define foopolyplibintrospecthfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include +#include +#include +#include + +/** \file + * + * Routines for daemon introspection. When enumerating all entitites + * of a certain kind, use the pa_context_xxx_list() functions. The + * specified callback function is called once for each entry. The + * enumeration is finished by a call to the callback function with + * is_last=1 and i=NULL. Strings referenced in pa_xxx_info structures + * and the structures themselves point to internal memory that may not + * be modified. That memory is only valid during the call to the + * callback function. A deep copy is required if you need this data + * outside the callback functions. An error is signalled by a call to * the callback function with i=NULL and is_last=0. + * + * When using the routines that ask fo a single entry only, a callback + * with the same signature is used. However, no finishing call to the + * routine is issued. */ + +PA_C_DECL_BEGIN + +/** Stores information about sinks */ +typedef struct pa_sink_info { + const char *name; /**< Name of the sink */ + uint32_t index; /**< Index of the sink */ + const char *description; /**< Description of this sink */ + pa_sample_spec sample_spec; /**< Sample spec of this sink */ + pa_channel_map channel_map; /**< Channel map \since 0.9 */ + uint32_t owner_module; /**< Index of the owning module of this sink, or PA_INVALID_INDEX */ + pa_cvolume volume; /**< Volume of the sink */ + uint32_t monitor_source; /**< Index of the monitor source connected to this sink */ + const char *monitor_source_name; /**< The name of the monitor source */ + pa_usec_t latency; /**< Length of filled playback buffer of this sink */ + const char *driver; /**< Driver name. \since 0.9 */ +} pa_sink_info; + +/** Get information about a sink by its name */ +pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata); + +/** Get information about a sink by its index */ +pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t id, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata); + +/** Get the complete sink list */ +pa_operation* pa_context_get_sink_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata); + +/** Stores information about sources */ +typedef struct pa_source_info { + const char *name ; /**< Name of the source */ + uint32_t index; /**< Index of the source */ + const char *description; /**< Description of this source */ + pa_sample_spec sample_spec; /**< Sample spec of this source */ + pa_channel_map channel_map; /**< Channel map \since 0.9 */ + uint32_t owner_module; /**< Owning module index, or PA_INVALID_INDEX */ + uint32_t monitor_of_sink; /**< If this is a monitor source the index of the owning sink, otherwise PA_INVALID_INDEX */ + const char *monitor_of_sink_name; /**< Name of the owning sink, or PA_INVALID_INDEX */ + pa_usec_t latency; /**< Length of filled record buffer of this source. \since 0.5 */ + const char *driver; /**< Driver name \since 0.9 */ +} pa_source_info; + +/** Get information about a source by its name */ +pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata); + +/** Get information about a source by its index */ +pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t id, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata); + +/** Get the complete source list */ +pa_operation* pa_context_get_source_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata); + +/** Server information */ +typedef struct pa_server_info { + const char *user_name; /**< User name of the daemon process */ + const char *host_name; /**< Host name the daemon is running on */ + const char *server_version; /**< Version string of the daemon */ + const char *server_name; /**< Server package name (usually "polypaudio") */ + pa_sample_spec sample_spec; /**< Default sample specification */ + const char *default_sink_name; /**< Name of default sink. \since 0.4 */ + const char *default_source_name; /**< Name of default sink. \since 0.4*/ + uint32_t cookie; /**< A random cookie for identifying this instance of polypaudio. \since 0.8 */ +} pa_server_info; + +/** Get some information about the server */ +pa_operation* pa_context_get_server_info(pa_context *c, void (*cb)(pa_context *c, const pa_server_info*i, void *userdata), void *userdata); + +/** Stores information about modules */ +typedef struct pa_module_info { + uint32_t index; /**< Index of the module */ + const char*name, /**< Name of the module */ + *argument; /**< Argument string of the module */ + uint32_t n_used; /**< Usage counter or PA_INVALID_INDEX */ + int auto_unload; /**< Non-zero if this is an autoloaded module */ +} pa_module_info; + +/** Get some information about a module by its index */ +pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata); + +/** Get the complete list of currently loaded modules */ +pa_operation* pa_context_get_module_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata); + +/** Stores information about clients */ +typedef struct pa_client_info { + uint32_t index; /**< Index of this client */ + const char *name; /**< Name of this client */ + uint32_t owner_module; /**< Index of the owning module, or PA_INVALID_INDEX */ + const char *driver; /**< Driver name \since 0.9 */ +} pa_client_info; + +/** Get information about a client by its index */ +pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata); + +/** Get the complete client list */ +pa_operation* pa_context_get_client_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata); + +/** Stores information about sink inputs */ +typedef struct pa_sink_input_info { + uint32_t index; /**< Index of the sink input */ + const char *name; /**< Name of the sink input */ + uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ + uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ + uint32_t sink; /**< Index of the connected sink */ + pa_sample_spec sample_spec; /**< The sample specification of the sink input */ + pa_channel_map channel_map; /**< Channel map */ + pa_cvolume volume; /**< The volume of this sink input */ + pa_usec_t buffer_usec; /**< Latency due to buffering in sink input, see pa_latency_info for details */ + pa_usec_t sink_usec; /**< Latency of the sink device, see pa_latency_info for details */ + const char *resample_method; /**< Thre resampling method used by this sink input. \since 0.7 */ + const char *driver; /**< Driver name \since 0.9 */ +} pa_sink_input_info; + +/** Get some information about a sink input by its index */ +pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata); + +/** Get the complete sink input list */ +pa_operation* pa_context_get_sink_input_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata); + +/** Stores information about source outputs */ +typedef struct pa_source_output_info { + uint32_t index; /**< Index of the sink input */ + const char *name; /**< Name of the sink input */ + uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ + uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ + uint32_t source; /**< Index of the connected source */ + pa_sample_spec sample_spec; /**< The sample specification of the source output */ + pa_channel_map channel_map; /**< Channel map */ + pa_usec_t buffer_usec; /**< Latency due to buffering in the source output, see pa_latency_info for details. \since 0.5 */ + pa_usec_t source_usec; /**< Latency of the source device, see pa_latency_info for details. \since 0.5 */ + const char *resample_method; /**< Thre resampling method used by this source output. \since 0.7 */ + const char *driver; /**< Driver name \since 0.9 */ +} pa_source_output_info; + +/** Get information about a source output by its index */ +pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata); + +/** Get the complete list of source outputs */ +pa_operation* pa_context_get_source_output_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata); + +/** Set the volume of a sink device specified by its index */ +pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +/** Set the volume of a sink device specified by its name */ +pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +/** Set the volume of a sink input stream */ +pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +/** Memory block statistics */ +typedef struct pa_stat_info { + uint32_t memblock_total; /**< Currently allocated memory blocks */ + uint32_t memblock_total_size; /**< Currentl total size of allocated memory blocks */ + uint32_t memblock_allocated; /**< Allocated memory blocks during the whole lifetime of the daemon */ + uint32_t memblock_allocated_size; /**< Total size of all memory blocks allocated during the whole lifetime of the daemon */ + uint32_t scache_size; /**< Total size of all sample cache entries. \since 0.4 */ +} pa_stat_info; + +/** Get daemon memory block statistics */ +pa_operation* pa_context_stat(pa_context *c, void (*cb)(pa_context *c, const pa_stat_info *i, void *userdata), void *userdata); + +/** Stores information about sample cache entries */ +typedef struct pa_sample_info { + uint32_t index; /**< Index of this entry */ + const char *name; /**< Name of this entry */ + pa_cvolume volume; /**< Default volume of this entry */ + pa_sample_spec sample_spec; /**< Sample specification of the sample */ + pa_channel_map channel_map; /**< The channel map */ + pa_usec_t duration; /**< Duration of this entry */ + uint32_t bytes; /**< Length of this sample in bytes. \since 0.4 */ + int lazy; /**< Non-zero when this is a lazy cache entry. \since 0.5 */ + const char *filename; /**< In case this is a lazy cache entry, the filename for the sound file to be loaded on demand. \since 0.5 */ +} pa_sample_info; + +/** Get information about a sample by its name */ +pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata); + +/** Get information about a sample by its index */ +pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata); + +/** Get the complete list of samples stored in the daemon. */ +pa_operation* pa_context_get_sample_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata); + +/** Kill a client. \since 0.5 */ +pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +/** Kill a sink input. \since 0.5 */ +pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +/** Kill a source output. \since 0.5 */ +pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +/** Load a module. \since 0.5 */ +pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, void (*cb)(pa_context *c, uint32_t idx, void *userdata), void *userdata); + +/** Unload a module. \since 0.5 */ +pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +/** Type of an autoload entry. \since 0.5 */ +typedef enum pa_autoload_type { + PA_AUTOLOAD_SINK = 0, + PA_AUTOLOAD_SOURCE = 1 +} pa_autoload_type_t; + +/** Stores information about autoload entries. \since 0.5 */ +typedef struct pa_autoload_info { + uint32_t index; /**< Index of this autoload entry */ + const char *name; /**< Name of the sink or source */ + pa_autoload_type_t type; /**< Type of the autoload entry */ + const char *module; /**< Module name to load */ + const char *argument; /**< Argument string for module */ +} pa_autoload_info; + +/** Get info about a specific autoload entry. \since 0.6 */ +pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); + +/** Get info about a specific autoload entry. \since 0.6 */ +pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); + +/** Get the complete list of autoload entries. \since 0.5 */ +pa_operation* pa_context_get_autoload_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); + +/** Add a new autoload entry. \since 0.5 */ +pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, void (*cb)(pa_context *c, int idx, void *userdata), void* userdata); + +/** Remove an autoload entry. \since 0.6 */ +pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata); + +/** Remove an autoload entry. \since 0.6 */ +pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void* userdata); + + +PA_C_DECL_END + +#endif diff --git a/src/polyp/operation.c b/src/polyp/operation.c new file mode 100644 index 00000000..0baa661b --- /dev/null +++ b/src/polyp/operation.c @@ -0,0 +1,103 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include "internal.h" +#include "operation.h" + +pa_operation *pa_operation_new(pa_context *c, pa_stream *s) { + pa_operation *o; + assert(c); + + o = pa_xmalloc(sizeof(pa_operation)); + o->ref = 1; + o->context = pa_context_ref(c); + o->stream = s ? pa_stream_ref(s) : NULL; + + o->state = PA_OPERATION_RUNNING; + o->userdata = NULL; + o->callback = NULL; + + PA_LLIST_PREPEND(pa_operation, o->context->operations, o); + return pa_operation_ref(o); +} + +pa_operation *pa_operation_ref(pa_operation *o) { + assert(o && o->ref >= 1); + o->ref++; + return o; +} + +void pa_operation_unref(pa_operation *o) { + assert(o && o->ref >= 1); + + if ((--(o->ref)) == 0) { + assert(!o->context); + assert(!o->stream); + free(o); + } +} + +static void operation_set_state(pa_operation *o, pa_operation_state_t st) { + assert(o && o->ref >= 1); + + if (st == o->state) + return; + + if (!o->context) + return; + + o->state = st; + + if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) { + PA_LLIST_REMOVE(pa_operation, o->context->operations, o); + pa_context_unref(o->context); + if (o->stream) + pa_stream_unref(o->stream); + o->context = NULL; + o->stream = NULL; + o->callback = NULL; + o->userdata = NULL; + + pa_operation_unref(o); + } +} + +void pa_operation_cancel(pa_operation *o) { + assert(o && o->ref >= 1); + operation_set_state(o, PA_OPERATION_CANCELED); +} + +void pa_operation_done(pa_operation *o) { + assert(o && o->ref >= 1); + operation_set_state(o, PA_OPERATION_DONE); +} + +pa_operation_state_t pa_operation_get_state(pa_operation *o) { + assert(o && o->ref >= 1); + return o->state; +} diff --git a/src/polyp/operation.h b/src/polyp/operation.h new file mode 100644 index 00000000..fea82f10 --- /dev/null +++ b/src/polyp/operation.h @@ -0,0 +1,51 @@ +#ifndef foopolypliboperationhfoo +#define foopolypliboperationhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/** \file + * Asynchronous operations */ + +PA_C_DECL_BEGIN + +/** \pa_operation + * An asynchronous operation object */ +typedef struct pa_operation pa_operation; + +/** Increase the reference count by one */ +pa_operation *pa_operation_ref(pa_operation *o); + +/** Decrease the reference count by one */ +void pa_operation_unref(pa_operation *o); + +/** Cancel the operation. Beware! This will not necessarily cancel the execution of the operation on the server side. */ +void pa_operation_cancel(pa_operation *o); + +/** Return the current status of the operation */ +pa_operation_state_t pa_operation_get_state(pa_operation *o); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/polypaudio.h b/src/polyp/polypaudio.h new file mode 100644 index 00000000..23208526 --- /dev/null +++ b/src/polyp/polypaudio.h @@ -0,0 +1,86 @@ +#ifndef foopolyplibhfoo +#define foopolyplibhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** \file + * Include all polyplib header file at once. The following files are included: \ref mainloop-api.h, \ref sample.h, + * \ref def.h, \ref context.h, \ref stream.h, + * \ref introspect.h, \ref subscribe.h and \ref scache.h \ref version.h + * at once */ + +/** \mainpage + * + * \section intro_sec Introduction + * + * This document describes the client API for the polypaudio sound + * server. The API comes in two flavours: + * + * \li The complete but somewhat complicated to use asynchronous API + * \li And the simplified, easy to use, but limited synchronous API + * + * The polypaudio client libraries are thread safe as long as all + * objects created by any library function are accessed from the thread + * that created them only. + * + * \section simple_sec Simple API + * + * Use this if you develop your program in synchronous style and just + * need a way to play or record data on the sound server. See + * \ref simple.h for more details. + * + * \section async_api Asynchronous API + * + * Use this if you develop your programs in asynchronous, main loop + * based style or want to use advanced features of the polypaudio + * API. A good starting point is \ref context.h + * + * The asynchronous API relies on an abstract main loop API that is + * described in \ref mainloop-api.h. Two distinct implementations are + * available: + * + * \li \ref mainloop.h: a minimal but fast implementation based on poll() + * \li \ref glib-mainloop.h: a wrapper around GLIB's main loop + * + * UNIX signals may be hooked to a main loop using the functions from + * \ref mainloop-signal.h + * + * \section pkgconfig pkg-config + * + * The polypaudio libraries provide pkg-config snippets for the different modules. To use the + * asynchronous API use "polyplib" as pkg-config file. GLIB main loop + * support is available as "glib-mainloop". The simple + * synchronous API is available as "simple". + */ + +#endif diff --git a/src/polyp/polyplib-browser.c b/src/polyp/polyplib-browser.c deleted file mode 100644 index 9a389484..00000000 --- a/src/polyp/polyplib-browser.c +++ /dev/null @@ -1,312 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -#include "polyplib-browser.h" -#include -#include -#include - -#define SERVICE_NAME_SINK "_polypaudio-sink._tcp." -#define SERVICE_NAME_SOURCE "_polypaudio-source._tcp." -#define SERVICE_NAME_SERVER "_polypaudio-server._tcp." - -pa_browser { - int ref; - pa_mainloop_api *mainloop; - - void (*callback)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void *userdata); - void *callback_userdata; - - sw_discovery discovery; - pa_io_event *io_event; -}; - - -static void io_callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags events, void *userdata) { - pa_browser *b = userdata; - assert(a && b && b->mainloop == a); - - if (events != PA_IO_EVENT_INPUT || sw_discovery_read_socket(b->discovery) != SW_OKAY) { - pa_log(__FILE__": connection to HOWL daemon failed.\n"); - b->mainloop->io_free(b->io_event); - b->io_event = NULL; - return; - } -} - -static sw_result resolve_reply( - sw_discovery discovery, - sw_discovery_oid oid, - sw_uint32 interface_index, - sw_const_string name, - sw_const_string type, - sw_const_string domain, - sw_ipv4_address address, - sw_port port, - sw_octets text_record, - sw_ulong text_record_len, - sw_opaque extra) { - - pa_browser *b = extra; - pa_browse_info i; - char ip[256], a[256]; - pa_browse_opcode opcode; - int device_found = 0; - uint32_t cookie; - pa_typeid_t typeid; - pa_sample_spec ss; - int ss_valid = 0; - sw_text_record_iterator iterator; - int free_iterator = 0; - char *c = NULL; - - assert(b); - - sw_discovery_cancel(discovery, oid); - - memset(&i, 0, sizeof(i)); - i.name = name; - - if (!b->callback) - goto fail; - - if (!strcmp(type, SERVICE_NAME_SINK)) - opcode = PA_BROWSE_NEW_SINK; - else if (!strcmp(type, SERVICE_NAME_SOURCE)) - opcode = PA_BROWSE_NEW_SOURCE; - else if (!strcmp(type, SERVICE_NAME_SERVER)) - opcode = PA_BROWSE_NEW_SERVER; - else - goto fail; - - - snprintf(a, sizeof(a), "tcp:%s:%u", sw_ipv4_address_name(address, ip, sizeof(ip)), port); - i.server = a; - - if (text_record && text_record_len) { - char key[SW_TEXT_RECORD_MAX_LEN]; - uint8_t val[SW_TEXT_RECORD_MAX_LEN]; - uint32_t val_len; - - if (sw_text_record_iterator_init(&iterator, text_record, text_record_len) != SW_OKAY) { - pa_log("sw_text_record_string_iterator_init() failed.\n"); - goto fail; - } - - free_iterator = 1; - - while (sw_text_record_iterator_next(iterator, key, val, &val_len) == SW_OKAY) { - c = pa_xstrndup((char*) val, val_len); - - if (!strcmp(key, "device")) { - device_found = 1; - pa_xfree((char*) i.device); - i.device = c; - c = NULL; - } else if (!strcmp(key, "server-version")) { - pa_xfree((char*) i.server_version); - i.server_version = c; - c = NULL; - } else if (!strcmp(key, "user-name")) { - pa_xfree((char*) i.user_name); - i.user_name = c; - c = NULL; - } else if (!strcmp(key, "fqdn")) { - size_t l; - - pa_xfree((char*) i.fqdn); - i.fqdn = c; - c = NULL; - - l = strlen(a); - assert(l+1 <= sizeof(a)); - strncat(a, " ", sizeof(a)-l-1); - strncat(a, i.fqdn, sizeof(a)-l-2); - } else if (!strcmp(key, "cookie")) { - - if (pa_atou(c, &cookie) < 0) - goto fail; - - i.cookie = &cookie; - } else if (!strcmp(key, "description")) { - pa_xfree((char*) i.description); - i.description = c; - c = NULL; - } else if (!strcmp(key, "typeid")) { - - if (pa_atou(c, &typeid) < 0) - goto fail; - - i.typeid = &typeid; - } else if (!strcmp(key, "channels")) { - uint32_t ch; - - if (pa_atou(c, &ch) < 0 || ch <= 0 || ch > 255) - goto fail; - - ss.channels = (uint8_t) ch; - ss_valid |= 1; - - } else if (!strcmp(key, "rate")) { - if (pa_atou(c, &ss.rate) < 0) - goto fail; - ss_valid |= 2; - } else if (!strcmp(key, "format")) { - - if ((ss.format = pa_parse_sample_format(c)) == PA_SAMPLE_INVALID) - goto fail; - - ss_valid |= 4; - } - - pa_xfree(c); - c = NULL; - } - - } - - /* No device txt record was sent for a sink or source service */ - if (opcode != PA_BROWSE_NEW_SERVER && !device_found) - goto fail; - - if (ss_valid == 7) - i.sample_spec = &ss; - - - b->callback(b, opcode, &i, b->callback_userdata); - -fail: - pa_xfree((void*) i.device); - pa_xfree((void*) i.fqdn); - pa_xfree((void*) i.server_version); - pa_xfree((void*) i.user_name); - pa_xfree((void*) i.description); - pa_xfree(c); - - if (free_iterator) - sw_text_record_iterator_fina(iterator); - - - return SW_OKAY; -} - -static sw_result browse_reply( - sw_discovery discovery, - sw_discovery_oid id, - sw_discovery_browse_status status, - sw_uint32 interface_index, - sw_const_string name, - sw_const_string type, - sw_const_string domain, - sw_opaque extra) { - - pa_browser *b = extra; - assert(b); - - switch (status) { - case SW_DISCOVERY_BROWSE_ADD_SERVICE: { - sw_discovery_oid oid; - - if (sw_discovery_resolve(b->discovery, 0, name, type, domain, resolve_reply, b, &oid) != SW_OKAY) - pa_log("sw_discovery_resolve() failed\n"); - - break; - } - - case SW_DISCOVERY_BROWSE_REMOVE_SERVICE: - if (b->callback) { - pa_browse_info i; - memset(&i, 0, sizeof(i)); - i.name = name; - b->callback(b, PA_BROWSE_REMOVE, &i, b->callback_userdata); - } - break; - - default: - ; - } - - return SW_OKAY; -} - -pa_browser *pa_browser_new(pa_mainloop_api *mainloop) { - pa_browser *b; - sw_discovery_oid oid; - - b = pa_xmalloc(sizeof(pa_browser)); - b->mainloop = mainloop; - b->ref = 1; - b->callback = NULL; - b->callback_userdata = NULL; - - if (sw_discovery_init(&b->discovery) != SW_OKAY) { - pa_log("sw_discovery_init() failed.\n"); - pa_xfree(b); - return NULL; - } - - if (sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SERVER, NULL, browse_reply, b, &oid) != SW_OKAY || - sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SINK, NULL, browse_reply, b, &oid) != SW_OKAY || - sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SOURCE, NULL, browse_reply, b, &oid) != SW_OKAY) { - - pa_log("sw_discovery_browse() failed.\n"); - - sw_discovery_fina(b->discovery); - pa_xfree(b); - return NULL; - } - - b->io_event = mainloop->io_new(mainloop, sw_discovery_socket(b->discovery), PA_IO_EVENT_INPUT, io_callback, b); - return b; -} - -static void browser_free(pa_browser *b) { - assert(b && b->mainloop); - - if (b->io_event) - b->mainloop->io_free(b->io_event); - - sw_discovery_fina(b->discovery); - pa_xfree(b); -} - -pa_browser *pa_browser_ref(pa_browser *b) { - assert(b && b->ref >= 1); - b->ref++; - return b; -} - -void pa_browser_unref(pa_browser *b) { - assert(b && b->ref >= 1); - - if ((-- (b->ref)) <= 0) - browser_free(b); -} - -void pa_browser_set_callback(pa_browser *b, void (*cb)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void* userdata), void *userdata) { - assert(b); - - b->callback = cb; - b->callback_userdata = userdata; -} diff --git a/src/polyp/polyplib-browser.h b/src/polyp/polyplib-browser.h deleted file mode 100644 index 853304d7..00000000 --- a/src/polyp/polyplib-browser.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef foopolyplibbrowserhfoo -#define foopolyplibbrowserhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include - -PA_C_DECL_BEGIN - -pa_browser; - -pa_browse_opcode { - PA_BROWSE_NEW_SERVER, - PA_BROWSE_NEW_SINK, - PA_BROWSE_NEW_SOURCE, - PA_BROWSE_REMOVE -}; - -pa_browser *pa_browser_new(pa_mainloop_api *mainloop); -pa_browser *pa_browser_ref(pa_browser *z); -void pa_browser_unref(pa_browser *z); - -pa_browse_info { - /* Unique service name */ - const char *name; /* always available */ - - /* Server info */ - const char *server; /* always available */ - const char *server_version, *user_name, *fqdn; /* optional */ - const uint32_t *cookie; /* optional */ - - /* Device info */ - const char *device; /* always available when this information is of a sink/source */ - const char *description; /* optional */ - const pa_typeid_t *typeid; /* optional */ - const pa_sample_spec *sample_spec; /* optional */ -}; - -void pa_browser_set_callback(pa_browser *z, void (*cb)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void *userdata), void *userdata); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/polyplib-context.c b/src/polyp/polyplib-context.c deleted file mode 100644 index c392f0fc..00000000 --- a/src/polyp/polyplib-context.c +++ /dev/null @@ -1,871 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_WAIT_H -#include -#endif - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif - -#include - -#include "polyplib-internal.h" -#include "polyplib-context.h" -#include "polyplib-version.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_X11 -#include "client-conf-x11.h" -#endif - -#define AUTOSPAWN_LOCK "autospawn.lock" - -static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_REQUEST] = pa_command_request, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = pa_command_stream_killed, - [PA_COMMAND_RECORD_STREAM_KILLED] = pa_command_stream_killed, - [PA_COMMAND_SUBSCRIBE_EVENT] = pa_command_subscribe_event -}; - -static void unlock_autospawn_lock_file(pa_context *c) { - assert(c); - - if (c->autospawn_lock_fd >= 0) { - char lf[PATH_MAX]; - pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); - - pa_unlock_lockfile(lf, c->autospawn_lock_fd); - c->autospawn_lock_fd = -1; - } -} - -pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { - pa_context *c; - assert(mainloop && name); - - c = pa_xmalloc(sizeof(pa_context)); - c->ref = 1; - c->name = pa_xstrdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - c->record_streams = pa_dynarray_new(); - assert(c->playback_streams && c->record_streams); - - PA_LLIST_HEAD_INIT(pa_stream, c->streams); - PA_LLIST_HEAD_INIT(pa_operation, c->operations); - - c->error = PA_ERROR_OK; - c->state = PA_CONTEXT_UNCONNECTED; - c->ctag = 0; - - c->state_callback = NULL; - c->state_userdata = NULL; - - c->subscribe_callback = NULL; - c->subscribe_userdata = NULL; - - c->memblock_stat = pa_memblock_stat_new(); - c->local = -1; - c->server_list = NULL; - c->server = NULL; - c->autospawn_lock_fd = -1; - memset(&c->spawn_api, 0, sizeof(c->spawn_api)); - c->do_autospawn = 0; - -#ifdef SIGPIPE - pa_check_signal_is_blocked(SIGPIPE); -#endif - - c->conf = pa_client_conf_new(); - pa_client_conf_load(c->conf, NULL); -#ifdef HAVE_X11 - pa_client_conf_from_x11(c->conf, NULL); -#endif - pa_client_conf_env(c->conf); - - return c; -} - -static void context_free(pa_context *c) { - assert(c); - - unlock_autospawn_lock_file(c); - - while (c->operations) - pa_operation_cancel(c->operations); - - while (c->streams) - pa_stream_set_state(c->streams, PA_STREAM_TERMINATED); - - if (c->client) - pa_socket_client_unref(c->client); - if (c->pdispatch) - pa_pdispatch_unref(c->pdispatch); - if (c->pstream) { - pa_pstream_close(c->pstream); - pa_pstream_unref(c->pstream); - } - - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - pa_memblock_stat_unref(c->memblock_stat); - - if (c->conf) - pa_client_conf_free(c->conf); - - pa_strlist_free(c->server_list); - - pa_xfree(c->name); - pa_xfree(c->server); - pa_xfree(c); -} - -pa_context* pa_context_ref(pa_context *c) { - assert(c && c->ref >= 1); - c->ref++; - return c; -} - -void pa_context_unref(pa_context *c) { - assert(c && c->ref >= 1); - - if ((--(c->ref)) == 0) - context_free(c); -} - -void pa_context_set_state(pa_context *c, pa_context_state_t st) { - assert(c); - - if (c->state == st) - return; - - pa_context_ref(c); - - if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) { - pa_stream *s; - - s = c->streams ? pa_stream_ref(c->streams) : NULL; - while (s) { - pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL; - pa_stream_set_state(s, st == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED); - pa_stream_unref(s); - s = n; - } - - if (c->pdispatch) - pa_pdispatch_unref(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) { - pa_pstream_close(c->pstream); - pa_pstream_unref(c->pstream); - } - c->pstream = NULL; - - if (c->client) - pa_socket_client_unref(c->client); - c->client = NULL; - } - - c->state = st; - if (c->state_callback) - c->state_callback(c, c->state_userdata); - - pa_context_unref(c); -} - -void pa_context_fail(pa_context *c, int error) { - assert(c); - c->error = error; - pa_context_set_state(c, PA_CONTEXT_FAILED); -} - -static void pstream_die_callback(pa_pstream *p, void *userdata) { - pa_context *c = userdata; - assert(p && c); - pa_context_fail(c, PA_ERROR_CONNECTIONTERMINATED); -} - -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { - pa_context *c = userdata; - assert(p && packet && c); - - pa_context_ref(c); - - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - pa_log(__FILE__": invalid packet.\n"); - pa_context_fail(c, PA_ERROR_PROTOCOL); - } - - pa_context_unref(c); -} - -static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, PA_GCC_UNUSED uint32_t delta, const pa_memchunk *chunk, void *userdata) { - pa_context *c = userdata; - pa_stream *s; - assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - - pa_context_ref(c); - - if ((s = pa_dynarray_get(c->record_streams, channel))) { - pa_mcalign_push(s->mcalign, chunk); - - for (;;) { - pa_memchunk t; - - if (pa_mcalign_pop(s->mcalign, &t) < 0) - break; - - if (s->read_callback) { - s->read_callback(s, (uint8_t*) t.memblock->data + t.index, t.length, s->read_userdata); - s->counter += chunk->length; - } - - pa_memblock_unref(t.memblock); - } - } - - pa_context_unref(c); -} - -int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t) { - assert(c); - - if (command == PA_COMMAND_ERROR) { - assert(t); - - if (pa_tagstruct_getu32(t, &c->error) < 0) { - pa_context_fail(c, PA_ERROR_PROTOCOL); - return -1; - - } - } else if (command == PA_COMMAND_TIMEOUT) - c->error = PA_ERROR_TIMEOUT; - else { - pa_context_fail(c, PA_ERROR_PROTOCOL); - return -1; - } - - return 0; -} - -static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_context *c = userdata; - assert(pd && c && (c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME)); - - pa_context_ref(c); - - if (command != PA_COMMAND_REPLY) { - - if (pa_context_handle_error(c, command, t) < 0) - pa_context_fail(c, PA_ERROR_PROTOCOL); - - pa_context_fail(c, c->error); - goto finish; - } - - switch(c->state) { - case PA_CONTEXT_AUTHORIZING: { - pa_tagstruct *reply; - reply = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME); - pa_tagstruct_putu32(reply, tag = c->ctag++); - pa_tagstruct_puts(reply, c->name); - pa_pstream_send_tagstruct(c->pstream, reply); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - - pa_context_set_state(c, PA_CONTEXT_SETTING_NAME); - break; - } - - case PA_CONTEXT_SETTING_NAME : - pa_context_set_state(c, PA_CONTEXT_READY); - break; - - default: - assert(0); - } - -finish: - pa_context_unref(c); -} - -static void setup_context(pa_context *c, pa_iochannel *io) { - pa_tagstruct *t; - uint32_t tag; - assert(c && io); - - pa_context_ref(c); - - assert(!c->pstream); - c->pstream = pa_pstream_new(c->mainloop, io, c->memblock_stat); - assert(c->pstream); - - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - - assert(!c->pdispatch); - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); - - if (!c->conf->cookie_valid) { - pa_context_fail(c, PA_ERROR_AUTHKEY); - goto finish; - } - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie)); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - - pa_context_set_state(c, PA_CONTEXT_AUTHORIZING); - -finish: - - pa_context_unref(c); -} - -static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata); - -#ifndef OS_IS_WIN32 - -static int context_connect_spawn(pa_context *c) { - pid_t pid; - int status, r; - int fds[2] = { -1, -1} ; - pa_iochannel *io; - - pa_context_ref(c); - - if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { - pa_log(__FILE__": socketpair() failed: %s\n", strerror(errno)); - pa_context_fail(c, PA_ERROR_INTERNAL); - goto fail; - } - - pa_fd_set_cloexec(fds[0], 1); - - pa_socket_low_delay(fds[0]); - pa_socket_low_delay(fds[1]); - - if (c->spawn_api.prefork) - c->spawn_api.prefork(); - - if ((pid = fork()) < 0) { - pa_log(__FILE__": fork() failed: %s\n", strerror(errno)); - pa_context_fail(c, PA_ERROR_INTERNAL); - - if (c->spawn_api.postfork) - c->spawn_api.postfork(); - - goto fail; - } else if (!pid) { - /* Child */ - - char t[128]; - const char *state = NULL; -#define MAX_ARGS 64 - const char * argv[MAX_ARGS+1]; - int n; - - /* Not required, since fds[0] has CLOEXEC enabled anyway */ - close(fds[0]); - - if (c->spawn_api.atfork) - c->spawn_api.atfork(); - - /* Setup argv */ - - n = 0; - - argv[n++] = c->conf->daemon_binary; - argv[n++] = "--daemonize=yes"; - - snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]); - argv[n++] = strdup(t); - - while (n < MAX_ARGS) { - char *a; - - if (!(a = pa_split_spaces(c->conf->extra_arguments, &state))) - break; - - argv[n++] = a; - } - - argv[n++] = NULL; - - execv(argv[0], (char * const *) argv); - _exit(1); -#undef MAX_ARGS - } - - /* Parent */ - - r = waitpid(pid, &status, 0); - - if (c->spawn_api.postfork) - c->spawn_api.postfork(); - - if (r < 0) { - pa_log(__FILE__": waitpid() failed: %s\n", strerror(errno)); - pa_context_fail(c, PA_ERROR_INTERNAL); - goto fail; - } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); - goto fail; - } - - close(fds[1]); - - c->local = 1; - - io = pa_iochannel_new(c->mainloop, fds[0], fds[0]); - - setup_context(c, io); - unlock_autospawn_lock_file(c); - - pa_context_unref(c); - - return 0; - -fail: - if (fds[0] != -1) - close(fds[0]); - if (fds[1] != -1) - close(fds[1]); - - unlock_autospawn_lock_file(c); - - pa_context_unref(c); - - return -1; -} - -#endif /* OS_IS_WIN32 */ - -static int try_next_connection(pa_context *c) { - char *u = NULL; - int r = -1; - assert(c && !c->client); - - for (;;) { - if (u) - pa_xfree(u); - u = NULL; - - c->server_list = pa_strlist_pop(c->server_list, &u); - - if (!u) { - -#ifndef OS_IS_WIN32 - if (c->do_autospawn) { - r = context_connect_spawn(c); - goto finish; - } -#endif - - pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); - goto finish; - } - - pa_log_debug(__FILE__": Trying to connect to %s...\n", u); - - pa_xfree(c->server); - c->server = pa_xstrdup(u); - - if (!(c->client = pa_socket_client_new_string(c->mainloop, u, PA_NATIVE_DEFAULT_PORT))) - continue; - - c->local = pa_socket_client_is_local(c->client); - pa_socket_client_set_callback(c->client, on_connection, c); - break; - } - - r = 0; - -finish: - if (u) - pa_xfree(u); - - return r; -} - -static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata) { - pa_context *c = userdata; - assert(client && c && c->state == PA_CONTEXT_CONNECTING); - - pa_context_ref(c); - - pa_socket_client_unref(client); - c->client = NULL; - - if (!io) { - /* Try the item in the list */ - if (errno == ECONNREFUSED || errno == ETIMEDOUT || errno == EHOSTUNREACH) { - try_next_connection(c); - goto finish; - } - - pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); - goto finish; - } - - unlock_autospawn_lock_file(c); - setup_context(c, io); - -finish: - pa_context_unref(c); -} - -int pa_context_connect(pa_context *c, const char *server, int spawn, const pa_spawn_api *api) { - int r = -1; - assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED); - - if (!server) - server = c->conf->default_server; - - pa_context_ref(c); - - assert(!c->server_list); - - if (server) { - if (!(c->server_list = pa_strlist_parse(server))) { - pa_context_fail(c, PA_ERROR_INVALIDSERVER); - goto finish; - } - } else { - char *d; - char ufn[PATH_MAX]; - - /* Prepend in reverse order */ - - if ((d = getenv("DISPLAY"))) { - char *e; - d = pa_xstrdup(d); - if ((e = strchr(d, ':'))) - *e = 0; - - if (*d) - c->server_list = pa_strlist_prepend(c->server_list, d); - - pa_xfree(d); - } - - c->server_list = pa_strlist_prepend(c->server_list, "tcp6:localhost"); - c->server_list = pa_strlist_prepend(c->server_list, "localhost"); - c->server_list = pa_strlist_prepend(c->server_list, pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET, ufn, sizeof(ufn))); - - /* Wrap the connection attempts in a single transaction for sane autospawn locking */ - if (spawn && c->conf->autospawn) { - char lf[PATH_MAX]; - - pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); - pa_make_secure_parent_dir(lf); - assert(c->autospawn_lock_fd <= 0); - c->autospawn_lock_fd = pa_lock_lockfile(lf); - - if (api) - c->spawn_api = *api; - c->do_autospawn = 1; - } - - } - - pa_context_set_state(c, PA_CONTEXT_CONNECTING); - r = try_next_connection(c); - -finish: - pa_context_unref(c); - - return r; -} - -void pa_context_disconnect(pa_context *c) { - assert(c); - pa_context_set_state(c, PA_CONTEXT_TERMINATED); -} - -pa_context_state_t pa_context_get_state(pa_context *c) { - assert(c && c->ref >= 1); - return c->state; -} - -int pa_context_errno(pa_context *c) { - assert(c && c->ref >= 1); - return c->error; -} - -void pa_context_set_state_callback(pa_context *c, void (*cb)(pa_context *c, void *userdata), void *userdata) { - assert(c && c->ref >= 1); - c->state_callback = cb; - c->state_userdata = userdata; -} - -int pa_context_is_pending(pa_context *c) { - assert(c && c->ref >= 1); - -/* pa_log("pstream: %i\n", pa_pstream_is_pending(c->pstream)); */ -/* pa_log("pdispatch: %i\n", pa_pdispatch_is_pending(c->pdispatch)); */ - - return (c->pstream && pa_pstream_is_pending(c->pstream)) || - (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) || - c->client; -} - -static void set_dispatch_callbacks(pa_operation *o); - -static void pdispatch_drain_callback(PA_GCC_UNUSED pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void pstream_drain_callback(PA_GCC_UNUSED pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void set_dispatch_callbacks(pa_operation *o) { - int done = 1; - assert(o && o->context && o->context->ref >= 1 && o->ref >= 1 && o->context->state == PA_CONTEXT_READY); - - pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(o->context->pdispatch)) { - pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o); - done = 0; - } - - if (pa_pstream_is_pending(o->context->pstream)) { - pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o); - done = 0; - } - - if (!done) - pa_operation_ref(o); - else { - if (o->callback) { - void (*cb)(pa_context *c, void *userdata); - cb = (void (*)(pa_context*, void*)) o->callback; - cb(o->context, o->userdata); - } - - pa_operation_done(o); - } - - pa_operation_unref(o); -} - -pa_operation* pa_context_drain(pa_context *c, void (*cb) (pa_context*c, void *userdata), void *userdata) { - pa_operation *o; - assert(c && c->ref >= 1); - - if (c->state != PA_CONTEXT_READY) - return NULL; - - if (!pa_context_is_pending(c)) - return NULL; - - o = pa_operation_new(c, NULL); - assert(o); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - set_dispatch_callbacks(pa_operation_ref(o)); - - return o; -} - -void pa_context_exit_daemon(pa_context *c) { - pa_tagstruct *t; - assert(c && c->ref >= 1); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); -} - -void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int success = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - success = 0; - } else if (!pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *c, int _success, void *_userdata) = (void (*)(pa_context *c, int _success, void *_userdata)) o->callback; - cb(o->context, success, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, void (*internal_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata), void (*cb)(void), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, command); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_DEFAULT_SINK); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_set_default_source(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_DEFAULT_SOURCE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -int pa_context_is_local(pa_context *c) { - assert(c); - return c->local; -} - -pa_operation* pa_context_set_name(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && name && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_CLIENT_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -const char* pa_get_library_version(void) { - return PACKAGE_VERSION; -} - -const char* pa_context_get_server(pa_context *c) { - - if (!c->server) - return NULL; - - if (*c->server == '{') { - char *e = strchr(c->server+1, '}'); - return e ? e+1 : c->server; - } - - return c->server; -} diff --git a/src/polyp/polyplib-context.h b/src/polyp/polyplib-context.h deleted file mode 100644 index febb75f4..00000000 --- a/src/polyp/polyplib-context.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef foopolyplibcontexthfoo -#define foopolyplibcontexthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include -#include - -/** \file - * Connection contexts for asynchrononous communication with a - * server. A pa_context object wraps a connection to a polypaudio - * server using its native protocol. A context may be used to issue - * commands on the server or to create playback or recording - * streams. Multiple playback streams may be piped through a single - * connection context. Operations on the contect involving - * communication with the server are executed asynchronously: i.e. the - * client function do not implicitely wait for completion of the - * operation on the server. Instead the caller specifies a call back - * function that is called when the operation is completed. Currently - * running operations may be canceled using pa_operation_cancel(). */ - -/** \example pacat.c - * A playback and recording tool using the asynchronous API */ - -/** \example paplay.c - * A sound file playback tool using the asynchronous API, based on libsndfile */ - -PA_C_DECL_BEGIN - -/** \pa_context - * An opaque connection context to a daemon */ -typedef struct pa_context pa_context; - -/** Instantiate a new connection context with an abstract mainloop API - * and an application name */ -pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name); - -/** Decrease the reference counter of the context by one */ -void pa_context_unref(pa_context *c); - -/** Increase the reference counter of the context by one */ -pa_context* pa_context_ref(pa_context *c); - -typedef void (*pa_context_state_callback)(pa_context *c, void *userdata); - -/** Set a callback function that is called whenever the context status changes */ -void pa_context_set_state_callback(pa_context *c, pa_context_state_callback callback, void *userdata); - -/** Return the error number of the last failed operation */ -int pa_context_errno(pa_context *c); - -/** Return non-zero if some data is pending to be written to the connection */ -int pa_context_is_pending(pa_context *c); - -/** Return the current context status */ -pa_context_state_t pa_context_get_state(pa_context *c); - -/** Connect the context to the specified server. If server is NULL, -connect to the default server. This routine may but will not always -return synchronously on error. Use pa_context_set_state_callback() to -be notified when the connection is established. If spawn is non-zero -and no specific server is specified or accessible a new daemon is -spawned. If api is non-NULL, the functions specified in the structure -are used when forking a new child process. */ -int pa_context_connect(pa_context *c, const char *server, int spawn, const pa_spawn_api *api); - -/** Terminate the context connection immediately */ -void pa_context_disconnect(pa_context *c); - -/** Drain the context. If there is nothing to drain, the function returns NULL */ -pa_operation* pa_context_drain(pa_context *c, void (*cb) (pa_context*c, void *userdata), void *userdata); - -/** Tell the daemon to exit. No operation object is returned as the - * connection is terminated when the daemon quits, thus this operation - * would never complete. */ -void pa_context_exit_daemon(pa_context *c); - -/** Set the name of the default sink. \since 0.4 */ -pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata); - -/** Set the name of the default source. \since 0.4 */ -pa_operation* pa_context_set_default_source(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata); - -/** Returns 1 when the connection is to a local daemon. Returns negative when no connection has been made yet. \since 0.5 */ -int pa_context_is_local(pa_context *c); - -/** Set a different application name for context on the server. \since 0.5 */ -pa_operation* pa_context_set_name(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata); - -/** Return the server name this context is connected to. \since 0.7 */ -const char* pa_context_get_server(pa_context *c); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/polyplib-def.h b/src/polyp/polyplib-def.h deleted file mode 100644 index 0591ce6c..00000000 --- a/src/polyp/polyplib-def.h +++ /dev/null @@ -1,213 +0,0 @@ -#ifndef foopolyplibdefhfoo -#define foopolyplibdefhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include - -#include -#include - -/** \file - * Global definitions */ - -PA_C_DECL_BEGIN - -/** The state of a connection context */ -typedef enum pa_context_state { - PA_CONTEXT_UNCONNECTED, /**< The context hasn't been connected yet */ - PA_CONTEXT_CONNECTING, /**< A connection is being established */ - PA_CONTEXT_AUTHORIZING, /**< The client is authorizing itself to the daemon */ - PA_CONTEXT_SETTING_NAME, /**< The client is passing its application name to the daemon */ - PA_CONTEXT_READY, /**< The connection is established, the context is ready to execute operations */ - PA_CONTEXT_FAILED, /**< The connection failed or was disconnected */ - PA_CONTEXT_TERMINATED /**< The connection was terminated cleanly */ -} pa_context_state_t; - -/** The state of a stream */ -typedef enum pa_stream_state { - PA_STREAM_DISCONNECTED, /**< The stream is not yet connected to any sink or source */ - PA_STREAM_CREATING, /**< The stream is being created */ - PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */ - PA_STREAM_FAILED, /**< An error occured that made the stream invalid */ - PA_STREAM_TERMINATED /**< The stream has been terminated cleanly */ -} pa_stream_state_t; - -/** The state of an operation */ -typedef enum pa_operation_state { - PA_OPERATION_RUNNING, /**< The operation is still running */ - PA_OPERATION_DONE, /**< The operation has been completed */ - PA_OPERATION_CANCELED /**< The operation has been canceled */ -} pa_operation_state_t; - -/** An invalid index */ -#define PA_INVALID_INDEX ((uint32_t) -1) - -/** The direction of a pa_stream object */ -typedef enum pa_stream_direction { - PA_STREAM_NODIRECTION, /**< Invalid direction */ - PA_STREAM_PLAYBACK, /**< Playback stream */ - PA_STREAM_RECORD, /**< Record stream */ - PA_STREAM_UPLOAD /**< Sample upload stream */ -} pa_stream_direction_t; - -/** Some special flags for stream connections. \since 0.6 */ -typedef enum pa_stream_flags { - PA_STREAM_START_CORKED = 1, /**< Create the stream corked, requiring an explicit pa_stream_cork() call to uncork it. */ - PA_STREAM_INTERPOLATE_LATENCY = 2 /**< Interpolate the latency for - * this stream. When enabled, - * you can use - * pa_stream_interpolated_xxx() - * for synchronization. Using - * these functions instead of - * pa_stream_get_latency() has - * the advantage of not - * requiring a whole roundtrip - * for responses. Consider using - * this option when frequently - * requesting latency - * information. This is - * especially useful on long latency - * network connections. */ -} pa_stream_flags_t; - -/** Playback and record buffer metrics */ -typedef struct pa_buffer_attr { - uint32_t maxlength; /**< Maximum length of the buffer */ - uint32_t tlength; /**< Playback only: target length of the buffer. The server tries to assure that at least tlength bytes are always available in the buffer */ - uint32_t prebuf; /**< Playback only: pre-buffering. The server does not start with playback before at least prebug bytes are available in the buffer */ - uint32_t minreq; /**< Playback only: minimum request. The server does not request less than minreq bytes from the client, instead waints until the buffer is free enough to request more bytes at once */ - uint32_t fragsize; /**< Recording only: fragment size. The server sends data in blocks of fragsize bytes size. Large values deminish interactivity with other operations on the connection context but decrease control overhead. */ -} pa_buffer_attr; - -/** Error values as used by pa_context_errno(). Use pa_strerror() to convert these values to human readable strings */ -enum { - PA_ERROR_OK, /**< No error */ - PA_ERROR_ACCESS, /**< Access failure */ - PA_ERROR_COMMAND, /**< Unknown command */ - PA_ERROR_INVALID, /**< Invalid argument */ - PA_ERROR_EXIST, /**< Entity exists */ - PA_ERROR_NOENTITY, /**< No such entity */ - PA_ERROR_CONNECTIONREFUSED, /**< Connection refused */ - PA_ERROR_PROTOCOL, /**< Protocol error */ - PA_ERROR_TIMEOUT, /**< Timeout */ - PA_ERROR_AUTHKEY, /**< No authorization key */ - PA_ERROR_INTERNAL, /**< Internal error */ - PA_ERROR_CONNECTIONTERMINATED, /**< Connection terminated */ - PA_ERROR_KILLED, /**< Entity killed */ - PA_ERROR_INVALIDSERVER, /**< Invalid server */ - PA_ERROR_INITFAILED, /**< Module initialization failed */ - PA_ERROR_MAX /**< Not really an error but the first invalid error code */ -}; - -/** Subscription event mask, as used by pa_context_subscribe() */ -typedef enum pa_subscription_mask { - PA_SUBSCRIPTION_MASK_NULL = 0, /**< No events */ - PA_SUBSCRIPTION_MASK_SINK = 1, /**< Sink events */ - PA_SUBSCRIPTION_MASK_SOURCE = 2, /**< Source events */ - PA_SUBSCRIPTION_MASK_SINK_INPUT = 4, /**< Sink input events */ - PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8, /**< Source output events */ - PA_SUBSCRIPTION_MASK_MODULE = 16, /**< Module events */ - PA_SUBSCRIPTION_MASK_CLIENT = 32, /**< Client events */ - PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, /**< Sample cache events */ - PA_SUBSCRIPTION_MASK_SERVER = 128, /**< Other global server changes. \since 0.4 */ - PA_SUBSCRIPTION_MASK_AUTOLOAD = 256 /**< Autoload table events. \since 0.5 */ -} pa_subscription_mask_t; - -/** Subscription event types, as used by pa_context_subscribe() */ -typedef enum pa_subscription_event_type { - PA_SUBSCRIPTION_EVENT_SINK = 0, /**< Event type: Sink */ - PA_SUBSCRIPTION_EVENT_SOURCE = 1, /**< Event type: Source */ - PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2, /**< Event type: Sink input */ - PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 3, /**< Event type: Source output */ - PA_SUBSCRIPTION_EVENT_MODULE = 4, /**< Event type: Module */ - PA_SUBSCRIPTION_EVENT_CLIENT = 5, /**< Event type: Client */ - PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, /**< Event type: Sample cache item */ - PA_SUBSCRIPTION_EVENT_SERVER = 7, /**< Event type: Global server change, only occuring with PA_SUBSCRIPTION_EVENT_CHANGE. \since 0.4 */ - PA_SUBSCRIPTION_EVENT_AUTOLOAD = 8, /**< Event type: Autoload table changes. \since 0.5 */ - PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 15, /**< A mask to extract the event type from an event value */ - - PA_SUBSCRIPTION_EVENT_NEW = 0, /**< A new object was created */ - PA_SUBSCRIPTION_EVENT_CHANGE = 16, /**< A property of the object was modified */ - PA_SUBSCRIPTION_EVENT_REMOVE = 32, /**< An object was removed */ - PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32 /**< A mask to extract the event operation from an event value */ -} pa_subscription_event_type_t; - -/** Return one if an event type t matches an event mask bitfield */ -#define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) - -/** A structure for latency info. See pa_stream_get_latency(). The - * total output latency a sample that is written with - * pa_stream_write() takes to be played may be estimated by - * sink_usec+buffer_usec+transport_usec. The output buffer to which - * buffer_usec relates may be manipulated freely (with - * pa_stream_write()'s delta argument, pa_stream_flush() and friends), - * the buffers sink_usec/source_usec relates to is a first-in - * first-out buffer which cannot be flushed or manipulated in any - * way. The total input latency a sample that is recorded takes to be - * delivered to the application is: - * source_usec+buffer_usec+transport_usec-sink_usec. (Take care of - * sign issues!) When connected to a monitor source sink_usec contains - * the latency of the owning sink.*/ -typedef struct pa_latency_info { - pa_usec_t buffer_usec; /**< Time in usecs the current buffer takes to play. For both playback and record streams. */ - pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. For playback streams and record streams connected to a monitor source. */ - pa_usec_t source_usec; /**< Time in usecs a sample takes from being recorded to being delivered to the application. Only for record streams. \since 0.5*/ - pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to/from the daemon. For both playback and record streams. \since 0.5 */ - int playing; /**< Non-zero when the stream is currently playing. Only for playback streams. */ - uint32_t queue_length; /**< Queue size in bytes. For both playback and record streams. */ - int synchronized_clocks; /**< Non-zero if the local and the - * remote machine have synchronized - * clocks. If synchronized clocks are - * detected transport_usec becomes much - * more reliable. However, the code that - * detects synchronized clocks is very - * limited und unreliable itself. \since - * 0.5 */ - struct timeval timestamp; /**< The time when this latency info was current */ - uint64_t counter; /**< The byte counter current when the latency info was requested. \since 0.6 */ -} pa_latency_info; - -/** A structure for the spawn api. This may be used to integrate auto - * spawned daemons into your application. For more information see - * pa_context_connect(). When spawning a new child process the - * waitpid() is used on the child's PID. The spawn routine will not - * block or ignore SIGCHLD signals, since this cannot be done in a - * thread compatible way. You might have to do this in - * prefork/postfork. \since 0.4 */ -typedef struct pa_spawn_api { - void (*prefork)(void); /**< Is called just before the fork in the parent process. May be NULL. */ - void (*postfork)(void); /**< Is called immediately after the fork in the parent process. May be NULL.*/ - void (*atfork)(void); /**< Is called immediately after the - * fork in the child process. May be - * NULL. It is not safe to close all - * file descriptors in this function - * unconditionally, since a UNIX socket - * (created using socketpair()) is - * passed to the new process. */ -} pa_spawn_api; - -PA_C_DECL_END - -#endif diff --git a/src/polyp/polyplib-error.c b/src/polyp/polyplib-error.c deleted file mode 100644 index 188d6a93..00000000 --- a/src/polyp/polyplib-error.c +++ /dev/null @@ -1,54 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "polyplib-error.h" -#include - -static const char* const errortab[PA_ERROR_MAX] = { - [PA_ERROR_OK] = "OK", - [PA_ERROR_ACCESS] = "Access denied", - [PA_ERROR_COMMAND] = "Unknown command", - [PA_ERROR_INVALID] = "Invalid argument", - [PA_ERROR_EXIST] = "Entity exists", - [PA_ERROR_NOENTITY] = "No such entity", - [PA_ERROR_CONNECTIONREFUSED] = "Connection refused", - [PA_ERROR_PROTOCOL] = "Protocol error", - [PA_ERROR_TIMEOUT] = "Timeout", - [PA_ERROR_AUTHKEY] = "No authorization key", - [PA_ERROR_INTERNAL] = "Internal error", - [PA_ERROR_CONNECTIONTERMINATED] = "Connection terminated", - [PA_ERROR_KILLED] = "Entity killed", - [PA_ERROR_INVALIDSERVER] = "Invalid server", -}; - -const char*pa_strerror(uint32_t error) { - if (error >= PA_ERROR_MAX) - return NULL; - - return errortab[error]; -} diff --git a/src/polyp/polyplib-error.h b/src/polyp/polyplib-error.h deleted file mode 100644 index 1bb97822..00000000 --- a/src/polyp/polyplib-error.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef foopolypliberrorhfoo -#define foopolypliberrorhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -/** \file - * Error management */ - -PA_C_DECL_BEGIN - -/** Return a human readable error message for the specified numeric error code */ -const char* pa_strerror(uint32_t error); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/polyplib-internal.h b/src/polyp/polyplib-internal.h deleted file mode 100644 index b95a20f3..00000000 --- a/src/polyp/polyplib-internal.h +++ /dev/null @@ -1,154 +0,0 @@ -#ifndef foopolyplibinternalhfoo -#define foopolyplibinternalhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include -#include - -#include "polyplib-context.h" -#include "polyplib-stream.h" -#include "polyplib-operation.h" -#include -#include -#include -#include -#include - -#define DEFAULT_TIMEOUT (10) - -struct pa_context { - int ref; - - char *name; - pa_mainloop_api* mainloop; - - pa_socket_client *client; - pa_pstream *pstream; - pa_pdispatch *pdispatch; - - pa_dynarray *record_streams, *playback_streams; - PA_LLIST_HEAD(pa_stream, streams); - PA_LLIST_HEAD(pa_operation, operations); - - uint32_t ctag; - uint32_t error; - pa_context_state_t state; - - void (*state_callback)(pa_context*c, void *userdata); - void *state_userdata; - - void (*subscribe_callback)(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata); - void *subscribe_userdata; - - pa_memblock_stat *memblock_stat; - - int local; - int do_autospawn; - int autospawn_lock_fd; - pa_spawn_api spawn_api; - - pa_strlist *server_list; - - char *server; - - pa_client_conf *conf; -}; - -struct pa_stream { - int ref; - pa_context *context; - pa_mainloop_api *mainloop; - PA_LLIST_FIELDS(pa_stream); - - char *name; - pa_buffer_attr buffer_attr; - pa_sample_spec sample_spec; - pa_channel_map channel_map; - uint32_t channel; - int channel_valid; - uint32_t device_index; - pa_stream_direction_t direction; - uint32_t requested_bytes; - uint64_t counter; - pa_usec_t previous_time; - pa_usec_t previous_ipol_time; - pa_stream_state_t state; - pa_mcalign *mcalign; - - int interpolate; - int corked; - - uint32_t ipol_usec; - struct timeval ipol_timestamp; - pa_time_event *ipol_event; - int ipol_requested; - - void (*state_callback)(pa_stream*c, void *userdata); - void *state_userdata; - - void (*read_callback)(pa_stream *p, const void*data, size_t length, void *userdata); - void *read_userdata; - - void (*write_callback)(pa_stream *p, size_t length, void *userdata); - void *write_userdata; -}; - -typedef void (*pa_operation_callback)(void); - -struct pa_operation { - int ref; - pa_context *context; - pa_stream *stream; - PA_LLIST_FIELDS(pa_operation); - - pa_operation_state_t state; - void *userdata; - pa_operation_callback callback; -}; - -void pa_command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); - -pa_operation *pa_operation_new(pa_context *c, pa_stream *s); -void pa_operation_done(pa_operation *o); - -void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); - -void pa_context_fail(pa_context *c, int error); -void pa_context_set_state(pa_context *c, pa_context_state_t st); -int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t); -pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, void (*internal_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata), void (*cb)(void), void *userdata); - -void pa_stream_set_state(pa_stream *s, pa_stream_state_t st); - -void pa_stream_trash_ipol(pa_stream *s); - - -#endif diff --git a/src/polyp/polyplib-introspect.c b/src/polyp/polyplib-introspect.c deleted file mode 100644 index 0bdffa35..00000000 --- a/src/polyp/polyplib-introspect.c +++ /dev/null @@ -1,1003 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "polyplib-introspect.h" -#include "polyplib-context.h" -#include "polyplib-internal.h" -#include -#include - -/*** Statistics ***/ - -static void context_stat_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - pa_stat_info i, *p = &i; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - p = NULL; - } else if (pa_tagstruct_getu32(t, &i.memblock_total) < 0 || - pa_tagstruct_getu32(t, &i.memblock_total_size) < 0 || - pa_tagstruct_getu32(t, &i.memblock_allocated) < 0 || - pa_tagstruct_getu32(t, &i.memblock_allocated_size) < 0 || - pa_tagstruct_getu32(t, &i.scache_size) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_stat_info*_i, void *_userdata) = (void (*)(pa_context *s, const pa_stat_info*_i, void *_userdata)) o->callback; - cb(o->context, p, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_stat(pa_context *c, void (*cb)(pa_context *c, const pa_stat_info*i, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_STAT, context_stat_callback, (pa_operation_callback) cb, userdata); -} - -/*** Server Info ***/ - -static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - pa_server_info i, *p = &i; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - p = NULL; - } else if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_gets(t, &i.default_sink_name) < 0 || - pa_tagstruct_gets(t, &i.default_source_name) < 0 || - pa_tagstruct_getu32(t, &i.cookie) < 0 || - !pa_tagstruct_eof(t)) { - - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_server_info*_i, void *_userdata) = (void (*)(pa_context *s, const pa_server_info*_i, void *_userdata)) o->callback; - cb(o->context, p, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_server_info(pa_context *c, void (*cb)(pa_context *c, const pa_server_info*i, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SERVER_INFO, context_get_server_info_callback, (pa_operation_callback) cb, userdata); -} - -/*** Sink Info ***/ - -static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eof = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_sink_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_get_cvolume(t, &i.volume) < 0 || - pa_tagstruct_getu32(t, &i.monitor_source) < 0 || - pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || - pa_tagstruct_get_usec(t, &i.latency) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0) { - - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_sink_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INFO_LIST, context_get_sink_info_callback, (pa_operation_callback) cb, userdata); -} - -pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, o); - - return pa_operation_ref(o); -} - -/*** Source info ***/ - -static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eof = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_source_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || - pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 || - pa_tagstruct_get_usec(t, &i.latency) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0) { - - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_source_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_INFO_LIST, context_get_source_info_callback, (pa_operation_callback) cb, userdata); -} - -pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, o); - - return pa_operation_ref(o); -} - -/*** Client info ***/ - -static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eof = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_client_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0 ) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_client_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_CLIENT_INFO_LIST, context_get_client_info_callback, (pa_operation_callback) cb, userdata); -} - -/*** Module info ***/ - -static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eof = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_module_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_get_boolean(t, &i.auto_unload) < 0) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_module_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_MODULE_INFO_LIST, context_get_module_info_callback, (pa_operation_callback) cb, userdata); -} - -/*** Sink input info ***/ - -static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eof = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_sink_input_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.client) < 0 || - pa_tagstruct_getu32(t, &i.sink) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_get_cvolume(t, &i.volume) < 0 || - pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || - pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || - pa_tagstruct_gets(t, &i.resample_method) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0) { - - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INPUT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_input_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_sink_input_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INPUT_INFO_LIST, context_get_sink_input_info_callback, (pa_operation_callback) cb, userdata); -} - -/*** Source output info ***/ - -static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eof = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_source_output_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.client) < 0 || - pa_tagstruct_getu32(t, &i.source) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || - pa_tagstruct_get_usec(t, &i.source_usec) < 0 || - pa_tagstruct_gets(t, &i.resample_method) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0) { - - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata))o->callback; - cb(o->context, NULL, eof, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_OUTPUT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_output_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_source_output_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, context_get_source_output_info_callback, (pa_operation_callback) cb, userdata); -} - -/*** Volume manipulation ***/ - -pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && idx != PA_INVALID_INDEX); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_tagstruct_put_cvolume(t, volume); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && name); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_cvolume(t, volume); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && idx != PA_INVALID_INDEX); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_put_cvolume(t, volume); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -/** Sample Cache **/ - -static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eof = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_sample_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_get_cvolume(t, &i.volume) < 0 || - pa_tagstruct_get_usec(t, &i.duration) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_getu32(t, &i.bytes) < 0 || - pa_tagstruct_get_boolean(t, &i.lazy) < 0 || - pa_tagstruct_gets(t, &i.filename) < 0) { - - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb && name); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SAMPLE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SAMPLE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_sample_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SAMPLE_INFO_LIST, context_get_sample_info_callback, (pa_operation_callback) cb, userdata); -} - -static pa_operation* command_kill(pa_context *c, uint32_t command, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && idx != PA_INVALID_INDEX); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, command); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - return command_kill(c, PA_COMMAND_KILL_CLIENT, idx, cb, userdata); -} - -pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - return command_kill(c, PA_COMMAND_KILL_SINK_INPUT, idx, cb, userdata); -} - -pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - return command_kill(c, PA_COMMAND_KILL_SOURCE_OUTPUT, idx, cb, userdata); -} - -static void load_module_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - uint32_t idx = -1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - } else if (pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *c, uint32_t _idx, void *_userdata) = (void (*)(pa_context *c, uint32_t _idx, void *_userdata)) o->callback; - cb(o->context, idx, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, void (*cb)(pa_context *c, uint32_t idx, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && name && argument); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_LOAD_MODULE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_puts(t, argument); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, load_module_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - return command_kill(c, PA_COMMAND_UNLOAD_MODULE, idx, cb, userdata); -} - -/*** Autoload stuff ***/ - -static void context_get_autoload_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eof = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_autoload_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_getu32(t, &i.type) < 0 || - pa_tagstruct_gets(t, &i.module) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - void (*cb)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb && name); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_AUTOLOAD_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_putu32(t, type); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(c && cb && idx != PA_INVALID_INDEX); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_AUTOLOAD_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_get_autoload_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, context_get_autoload_info_callback, (pa_operation_callback) cb, userdata); -} - -static void context_add_autoload_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - uint32_t idx; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - idx = PA_INVALID_INDEX; - } else if (pa_tagstruct_getu32(t, &idx) || - !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, uint32_t _idx, void *_userdata) = (void (*)(pa_context *s, uint32_t _idx, void *_userdata)) o->callback; - cb(o->context, idx, o->userdata); - } - - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && name && module && argument); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_ADD_AUTOLOAD); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_putu32(t, type); - pa_tagstruct_puts(t, module); - pa_tagstruct_puts(t, argument); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_add_autoload_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && name); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_AUTOLOAD); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_putu32(t, type); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && idx != PA_INVALID_INDEX); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_AUTOLOAD); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} diff --git a/src/polyp/polyplib-introspect.h b/src/polyp/polyplib-introspect.h deleted file mode 100644 index d3489908..00000000 --- a/src/polyp/polyplib-introspect.h +++ /dev/null @@ -1,279 +0,0 @@ -#ifndef foopolyplibintrospecthfoo -#define foopolyplibintrospecthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include -#include -#include -#include -#include - -/** \file - * - * Routines for daemon introspection. When enumerating all entitites - * of a certain kind, use the pa_context_xxx_list() functions. The - * specified callback function is called once for each entry. The - * enumeration is finished by a call to the callback function with - * is_last=1 and i=NULL. Strings referenced in pa_xxx_info structures - * and the structures themselves point to internal memory that may not - * be modified. That memory is only valid during the call to the - * callback function. A deep copy is required if you need this data - * outside the callback functions. An error is signalled by a call to * the callback function with i=NULL and is_last=0. - * - * When using the routines that ask fo a single entry only, a callback - * with the same signature is used. However, no finishing call to the - * routine is issued. */ - -PA_C_DECL_BEGIN - -/** Stores information about sinks */ -typedef struct pa_sink_info { - const char *name; /**< Name of the sink */ - uint32_t index; /**< Index of the sink */ - const char *description; /**< Description of this sink */ - pa_sample_spec sample_spec; /**< Sample spec of this sink */ - pa_channel_map channel_map; /**< Channel map \since 0.9 */ - uint32_t owner_module; /**< Index of the owning module of this sink, or PA_INVALID_INDEX */ - pa_cvolume volume; /**< Volume of the sink */ - uint32_t monitor_source; /**< Index of the monitor source connected to this sink */ - const char *monitor_source_name; /**< The name of the monitor source */ - pa_usec_t latency; /**< Length of filled playback buffer of this sink */ - const char *driver; /**< Driver name. \since 0.9 */ -} pa_sink_info; - -/** Get information about a sink by its name */ -pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata); - -/** Get information about a sink by its index */ -pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t id, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata); - -/** Get the complete sink list */ -pa_operation* pa_context_get_sink_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata); - -/** Stores information about sources */ -typedef struct pa_source_info { - const char *name ; /**< Name of the source */ - uint32_t index; /**< Index of the source */ - const char *description; /**< Description of this source */ - pa_sample_spec sample_spec; /**< Sample spec of this source */ - pa_channel_map channel_map; /**< Channel map \since 0.9 */ - uint32_t owner_module; /**< Owning module index, or PA_INVALID_INDEX */ - uint32_t monitor_of_sink; /**< If this is a monitor source the index of the owning sink, otherwise PA_INVALID_INDEX */ - const char *monitor_of_sink_name; /**< Name of the owning sink, or PA_INVALID_INDEX */ - pa_usec_t latency; /**< Length of filled record buffer of this source. \since 0.5 */ - const char *driver; /**< Driver name \since 0.9 */ -} pa_source_info; - -/** Get information about a source by its name */ -pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata); - -/** Get information about a source by its index */ -pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t id, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata); - -/** Get the complete source list */ -pa_operation* pa_context_get_source_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata); - -/** Server information */ -typedef struct pa_server_info { - const char *user_name; /**< User name of the daemon process */ - const char *host_name; /**< Host name the daemon is running on */ - const char *server_version; /**< Version string of the daemon */ - const char *server_name; /**< Server package name (usually "polypaudio") */ - pa_sample_spec sample_spec; /**< Default sample specification */ - const char *default_sink_name; /**< Name of default sink. \since 0.4 */ - const char *default_source_name; /**< Name of default sink. \since 0.4*/ - uint32_t cookie; /**< A random cookie for identifying this instance of polypaudio. \since 0.8 */ -} pa_server_info; - -/** Get some information about the server */ -pa_operation* pa_context_get_server_info(pa_context *c, void (*cb)(pa_context *c, const pa_server_info*i, void *userdata), void *userdata); - -/** Stores information about modules */ -typedef struct pa_module_info { - uint32_t index; /**< Index of the module */ - const char*name, /**< Name of the module */ - *argument; /**< Argument string of the module */ - uint32_t n_used; /**< Usage counter or PA_INVALID_INDEX */ - int auto_unload; /**< Non-zero if this is an autoloaded module */ -} pa_module_info; - -/** Get some information about a module by its index */ -pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata); - -/** Get the complete list of currently loaded modules */ -pa_operation* pa_context_get_module_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata); - -/** Stores information about clients */ -typedef struct pa_client_info { - uint32_t index; /**< Index of this client */ - const char *name; /**< Name of this client */ - uint32_t owner_module; /**< Index of the owning module, or PA_INVALID_INDEX */ - const char *driver; /**< Driver name \since 0.9 */ -} pa_client_info; - -/** Get information about a client by its index */ -pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata); - -/** Get the complete client list */ -pa_operation* pa_context_get_client_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata); - -/** Stores information about sink inputs */ -typedef struct pa_sink_input_info { - uint32_t index; /**< Index of the sink input */ - const char *name; /**< Name of the sink input */ - uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ - uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ - uint32_t sink; /**< Index of the connected sink */ - pa_sample_spec sample_spec; /**< The sample specification of the sink input */ - pa_channel_map channel_map; /**< Channel map */ - pa_cvolume volume; /**< The volume of this sink input */ - pa_usec_t buffer_usec; /**< Latency due to buffering in sink input, see pa_latency_info for details */ - pa_usec_t sink_usec; /**< Latency of the sink device, see pa_latency_info for details */ - const char *resample_method; /**< Thre resampling method used by this sink input. \since 0.7 */ - const char *driver; /**< Driver name \since 0.9 */ -} pa_sink_input_info; - -/** Get some information about a sink input by its index */ -pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata); - -/** Get the complete sink input list */ -pa_operation* pa_context_get_sink_input_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata); - -/** Stores information about source outputs */ -typedef struct pa_source_output_info { - uint32_t index; /**< Index of the sink input */ - const char *name; /**< Name of the sink input */ - uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ - uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ - uint32_t source; /**< Index of the connected source */ - pa_sample_spec sample_spec; /**< The sample specification of the source output */ - pa_channel_map channel_map; /**< Channel map */ - pa_usec_t buffer_usec; /**< Latency due to buffering in the source output, see pa_latency_info for details. \since 0.5 */ - pa_usec_t source_usec; /**< Latency of the source device, see pa_latency_info for details. \since 0.5 */ - const char *resample_method; /**< Thre resampling method used by this source output. \since 0.7 */ - const char *driver; /**< Driver name \since 0.9 */ -} pa_source_output_info; - -/** Get information about a source output by its index */ -pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata); - -/** Get the complete list of source outputs */ -pa_operation* pa_context_get_source_output_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata); - -/** Set the volume of a sink device specified by its index */ -pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -/** Set the volume of a sink device specified by its name */ -pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -/** Set the volume of a sink input stream */ -pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -/** Memory block statistics */ -typedef struct pa_stat_info { - uint32_t memblock_total; /**< Currently allocated memory blocks */ - uint32_t memblock_total_size; /**< Currentl total size of allocated memory blocks */ - uint32_t memblock_allocated; /**< Allocated memory blocks during the whole lifetime of the daemon */ - uint32_t memblock_allocated_size; /**< Total size of all memory blocks allocated during the whole lifetime of the daemon */ - uint32_t scache_size; /**< Total size of all sample cache entries. \since 0.4 */ -} pa_stat_info; - -/** Get daemon memory block statistics */ -pa_operation* pa_context_stat(pa_context *c, void (*cb)(pa_context *c, const pa_stat_info *i, void *userdata), void *userdata); - -/** Stores information about sample cache entries */ -typedef struct pa_sample_info { - uint32_t index; /**< Index of this entry */ - const char *name; /**< Name of this entry */ - pa_cvolume volume; /**< Default volume of this entry */ - pa_sample_spec sample_spec; /**< Sample specification of the sample */ - pa_channel_map channel_map; /**< The channel map */ - pa_usec_t duration; /**< Duration of this entry */ - uint32_t bytes; /**< Length of this sample in bytes. \since 0.4 */ - int lazy; /**< Non-zero when this is a lazy cache entry. \since 0.5 */ - const char *filename; /**< In case this is a lazy cache entry, the filename for the sound file to be loaded on demand. \since 0.5 */ -} pa_sample_info; - -/** Get information about a sample by its name */ -pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata); - -/** Get information about a sample by its index */ -pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata); - -/** Get the complete list of samples stored in the daemon. */ -pa_operation* pa_context_get_sample_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata); - -/** Kill a client. \since 0.5 */ -pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -/** Kill a sink input. \since 0.5 */ -pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -/** Kill a source output. \since 0.5 */ -pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -/** Load a module. \since 0.5 */ -pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, void (*cb)(pa_context *c, uint32_t idx, void *userdata), void *userdata); - -/** Unload a module. \since 0.5 */ -pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -/** Type of an autoload entry. \since 0.5 */ -typedef enum pa_autoload_type { - PA_AUTOLOAD_SINK = 0, - PA_AUTOLOAD_SOURCE = 1 -} pa_autoload_type_t; - -/** Stores information about autoload entries. \since 0.5 */ -typedef struct pa_autoload_info { - uint32_t index; /**< Index of this autoload entry */ - const char *name; /**< Name of the sink or source */ - pa_autoload_type_t type; /**< Type of the autoload entry */ - const char *module; /**< Module name to load */ - const char *argument; /**< Argument string for module */ -} pa_autoload_info; - -/** Get info about a specific autoload entry. \since 0.6 */ -pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); - -/** Get info about a specific autoload entry. \since 0.6 */ -pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); - -/** Get the complete list of autoload entries. \since 0.5 */ -pa_operation* pa_context_get_autoload_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); - -/** Add a new autoload entry. \since 0.5 */ -pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, void (*cb)(pa_context *c, int idx, void *userdata), void* userdata); - -/** Remove an autoload entry. \since 0.6 */ -pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata); - -/** Remove an autoload entry. \since 0.6 */ -pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void* userdata); - - -PA_C_DECL_END - -#endif diff --git a/src/polyp/polyplib-operation.c b/src/polyp/polyplib-operation.c deleted file mode 100644 index ea336c17..00000000 --- a/src/polyp/polyplib-operation.c +++ /dev/null @@ -1,103 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include -#include "polyplib-internal.h" -#include "polyplib-operation.h" - -pa_operation *pa_operation_new(pa_context *c, pa_stream *s) { - pa_operation *o; - assert(c); - - o = pa_xmalloc(sizeof(pa_operation)); - o->ref = 1; - o->context = pa_context_ref(c); - o->stream = s ? pa_stream_ref(s) : NULL; - - o->state = PA_OPERATION_RUNNING; - o->userdata = NULL; - o->callback = NULL; - - PA_LLIST_PREPEND(pa_operation, o->context->operations, o); - return pa_operation_ref(o); -} - -pa_operation *pa_operation_ref(pa_operation *o) { - assert(o && o->ref >= 1); - o->ref++; - return o; -} - -void pa_operation_unref(pa_operation *o) { - assert(o && o->ref >= 1); - - if ((--(o->ref)) == 0) { - assert(!o->context); - assert(!o->stream); - free(o); - } -} - -static void operation_set_state(pa_operation *o, pa_operation_state_t st) { - assert(o && o->ref >= 1); - - if (st == o->state) - return; - - if (!o->context) - return; - - o->state = st; - - if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) { - PA_LLIST_REMOVE(pa_operation, o->context->operations, o); - pa_context_unref(o->context); - if (o->stream) - pa_stream_unref(o->stream); - o->context = NULL; - o->stream = NULL; - o->callback = NULL; - o->userdata = NULL; - - pa_operation_unref(o); - } -} - -void pa_operation_cancel(pa_operation *o) { - assert(o && o->ref >= 1); - operation_set_state(o, PA_OPERATION_CANCELED); -} - -void pa_operation_done(pa_operation *o) { - assert(o && o->ref >= 1); - operation_set_state(o, PA_OPERATION_DONE); -} - -pa_operation_state_t pa_operation_get_state(pa_operation *o) { - assert(o && o->ref >= 1); - return o->state; -} diff --git a/src/polyp/polyplib-operation.h b/src/polyp/polyplib-operation.h deleted file mode 100644 index cac03e30..00000000 --- a/src/polyp/polyplib-operation.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef foopolypliboperationhfoo -#define foopolypliboperationhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -/** \file - * Asynchronous operations */ - -PA_C_DECL_BEGIN - -/** \pa_operation - * An asynchronous operation object */ -typedef struct pa_operation pa_operation; - -/** Increase the reference count by one */ -pa_operation *pa_operation_ref(pa_operation *o); - -/** Decrease the reference count by one */ -void pa_operation_unref(pa_operation *o); - -/** Cancel the operation. Beware! This will not necessarily cancel the execution of the operation on the server side. */ -void pa_operation_cancel(pa_operation *o); - -/** Return the current status of the operation */ -pa_operation_state_t pa_operation_get_state(pa_operation *o); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/polyplib-scache.c b/src/polyp/polyplib-scache.c deleted file mode 100644 index 1315af97..00000000 --- a/src/polyp/polyplib-scache.c +++ /dev/null @@ -1,127 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "polyplib-scache.h" -#include "polyplib-internal.h" -#include - -void pa_stream_connect_upload(pa_stream *s, size_t length) { - pa_tagstruct *t; - uint32_t tag; - - assert(s && length); - - pa_stream_ref(s); - - s->state = PA_STREAM_CREATING; - s->direction = PA_STREAM_UPLOAD; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, length); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s); - - pa_stream_unref(s); -} - -void pa_stream_finish_upload(pa_stream *s) { - pa_tagstruct *t; - uint32_t tag; - assert(s); - - if (!s->channel_valid || !s->context->state == PA_CONTEXT_READY) - return; - - pa_stream_ref(s); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s); - - pa_stream_unref(s); -} - -pa_operation * pa_context_play_sample(pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && name && *name && (!dev || *dev)); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - if (!dev) - dev = c->conf->default_sink; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev); - pa_tagstruct_putu32(t, volume); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_context_remove_sample(pa_context *c, const char *name, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c && name); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - diff --git a/src/polyp/polyplib-scache.h b/src/polyp/polyplib-scache.h deleted file mode 100644 index 89d27597..00000000 --- a/src/polyp/polyplib-scache.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef foopolyplibscachehfoo -#define foopolyplibscachehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include -#include -#include - -/** \file - * All sample cache related routines */ - -PA_C_DECL_BEGIN - -/** Make this stream a sample upload stream */ -void pa_stream_connect_upload(pa_stream *s, size_t length); - -/** Finish the sample upload, the stream name will become the sample name. You cancel a sample upload by issuing pa_stream_disconnect() */ -void pa_stream_finish_upload(pa_stream *s); - -/** Play a sample from the sample cache to the specified device. If the latter is NULL use the default sink. Returns an operation object */ -pa_operation* pa_context_play_sample(pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -/** Remove a sample from the sample cache. Returns an operation object which may be used to cancel the operation while it is running */ -pa_operation* pa_context_remove_sample(pa_context *c, const char *name, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/polyplib-simple.c b/src/polyp/polyplib-simple.c deleted file mode 100644 index 7436f007..00000000 --- a/src/polyp/polyplib-simple.c +++ /dev/null @@ -1,393 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "polyplib-simple.h" -#include "polyplib.h" -#include "mainloop.h" -#include -#include -#include - -struct pa_simple { - pa_mainloop *mainloop; - pa_context *context; - pa_stream *stream; - pa_stream_direction_t direction; - - int dead; - - void *read_data; - size_t read_index, read_length; - pa_usec_t latency; -}; - -static void read_callback(pa_stream *s, const void*data, size_t length, void *userdata); - -static int check_error(pa_simple *p, int *rerror) { - pa_context_state_t cst; - pa_stream_state_t sst; - assert(p); - - if ((cst = pa_context_get_state(p->context)) == PA_CONTEXT_FAILED) - goto fail; - - assert(cst != PA_CONTEXT_TERMINATED); - - if (p->stream) { - if ((sst = pa_stream_get_state(p->stream)) == PA_STREAM_FAILED) - goto fail; - - assert(sst != PA_STREAM_TERMINATED); - } - - return 0; - -fail: - if (rerror) - *rerror = pa_context_errno(p->context); - - p->dead = 1; - - return -1; -} - -static int iterate(pa_simple *p, int block, int *rerror) { - assert(p && p->context && p->mainloop); - - if (check_error(p, rerror) < 0) - return -1; - - if (!block && !pa_context_is_pending(p->context)) - return 0; - - do { - if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) { - if (rerror) - *rerror = PA_ERROR_INTERNAL; - return -1; - } - - if (check_error(p, rerror) < 0) - return -1; - - } while (pa_context_is_pending(p->context)); - - - while (pa_mainloop_deferred_pending(p->mainloop)) { - - if (pa_mainloop_iterate(p->mainloop, 0, NULL) < 0) { - if (rerror) - *rerror = PA_ERROR_INTERNAL; - return -1; - } - - if (check_error(p, rerror) < 0) - return -1; - } - - return 0; -} - -pa_simple* pa_simple_new( - const char *server, - const char *name, - pa_stream_direction_t dir, - const char *dev, - const char *stream_name, - const pa_sample_spec *ss, - const pa_buffer_attr *attr, - int *rerror) { - - pa_simple *p; - int error = PA_ERROR_INTERNAL; - assert(ss && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); - - p = pa_xmalloc(sizeof(pa_simple)); - p->context = NULL; - p->stream = NULL; - p->mainloop = pa_mainloop_new(); - assert(p->mainloop); - p->dead = 0; - p->direction = dir; - p->read_data = NULL; - p->read_index = p->read_length = 0; - p->latency = 0; - - if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name))) - goto fail; - - pa_context_connect(p->context, server, 1, NULL); - - /* Wait until the context is ready */ - while (pa_context_get_state(p->context) != PA_CONTEXT_READY) { - if (iterate(p, 1, &error) < 0) - goto fail; - } - - if (!(p->stream = pa_stream_new(p->context, stream_name, ss, NULL))) - goto fail; - - if (dir == PA_STREAM_PLAYBACK) - pa_stream_connect_playback(p->stream, dev, attr, 0, NULL); - else - pa_stream_connect_record(p->stream, dev, attr, 0); - - /* Wait until the stream is ready */ - while (pa_stream_get_state(p->stream) != PA_STREAM_READY) { - if (iterate(p, 1, &error) < 0) - goto fail; - } - - pa_stream_set_read_callback(p->stream, read_callback, p); - - return p; - -fail: - if (rerror) - *rerror = error; - pa_simple_free(p); - return NULL; -} - -void pa_simple_free(pa_simple *s) { - assert(s); - - pa_xfree(s->read_data); - - if (s->stream) - pa_stream_unref(s->stream); - - if (s->context) - pa_context_unref(s->context); - - if (s->mainloop) - pa_mainloop_free(s->mainloop); - - pa_xfree(s); -} - -int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { - assert(p && data && p->direction == PA_STREAM_PLAYBACK); - - if (p->dead) { - if (rerror) - *rerror = pa_context_errno(p->context); - - return -1; - } - - while (length > 0) { - size_t l; - - while (!(l = pa_stream_writable_size(p->stream))) - if (iterate(p, 1, rerror) < 0) - return -1; - - if (l > length) - l = length; - - pa_stream_write(p->stream, data, l, NULL, 0); - data = (const uint8_t*) data + l; - length -= l; - } - - /* Make sure that no data is pending for write */ - if (iterate(p, 0, rerror) < 0) - return -1; - - return 0; -} - -static void read_callback(pa_stream *s, const void*data, size_t length, void *userdata) { - pa_simple *p = userdata; - assert(s && data && length && p); - - if (p->read_data) { - pa_log(__FILE__": Buffer overflow, dropping incoming memory blocks.\n"); - pa_xfree(p->read_data); - } - - p->read_data = pa_xmemdup(data, p->read_length = length); - p->read_index = 0; -} - -int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { - assert(p && data && p->direction == PA_STREAM_RECORD); - - if (p->dead) { - if (rerror) - *rerror = pa_context_errno(p->context); - - return -1; - } - - while (length > 0) { - if (p->read_data) { - size_t l = length; - - if (p->read_length <= l) - l = p->read_length; - - memcpy(data, (uint8_t*) p->read_data+p->read_index, l); - - data = (uint8_t*) data + l; - length -= l; - - p->read_index += l; - p->read_length -= l; - - if (!p->read_length) { - pa_xfree(p->read_data); - p->read_data = NULL; - p->read_index = 0; - } - - if (!length) - return 0; - - assert(!p->read_data); - } - - if (iterate(p, 1, rerror) < 0) - return -1; - } - - return 0; -} - -static void drain_or_flush_complete(pa_stream *s, int success, void *userdata) { - pa_simple *p = userdata; - assert(s && p); - if (!success) - p->dead = 1; -} - -int pa_simple_drain(pa_simple *p, int *rerror) { - pa_operation *o; - assert(p && p->direction == PA_STREAM_PLAYBACK); - - if (p->dead) { - if (rerror) - *rerror = pa_context_errno(p->context); - - return -1; - } - - o = pa_stream_drain(p->stream, drain_or_flush_complete, p); - - while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { - if (iterate(p, 1, rerror) < 0) { - pa_operation_cancel(o); - pa_operation_unref(o); - return -1; - } - } - - pa_operation_unref(o); - - if (p->dead && rerror) - *rerror = pa_context_errno(p->context); - - return p->dead ? -1 : 0; -} - -static void latency_complete(pa_stream *s, const pa_latency_info *l, void *userdata) { - pa_simple *p = userdata; - assert(s && p); - - if (!l) - p->dead = 1; - else { - int negative = 0; - p->latency = pa_stream_get_latency(s, l, &negative); - if (negative) - p->latency = 0; - } -} - -pa_usec_t pa_simple_get_playback_latency(pa_simple *p, int *rerror) { - pa_operation *o; - assert(p && p->direction == PA_STREAM_PLAYBACK); - - if (p->dead) { - if (rerror) - *rerror = pa_context_errno(p->context); - - return (pa_usec_t) -1; - } - - p->latency = 0; - o = pa_stream_get_latency_info(p->stream, latency_complete, p); - - while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { - - if (iterate(p, 1, rerror) < 0) { - pa_operation_cancel(o); - pa_operation_unref(o); - return -1; - } - } - - pa_operation_unref(o); - - if (p->dead && rerror) - *rerror = pa_context_errno(p->context); - - return p->dead ? (pa_usec_t) -1 : p->latency; -} - -int pa_simple_flush(pa_simple *p, int *rerror) { - pa_operation *o; - assert(p && p->direction == PA_STREAM_PLAYBACK); - - if (p->dead) { - if (rerror) - *rerror = pa_context_errno(p->context); - - return -1; - } - - o = pa_stream_flush(p->stream, drain_or_flush_complete, p); - - while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { - if (iterate(p, 1, rerror) < 0) { - pa_operation_cancel(o); - pa_operation_unref(o); - return -1; - } - } - - pa_operation_unref(o); - - if (p->dead && rerror) - *rerror = pa_context_errno(p->context); - - return p->dead ? -1 : 0; -} diff --git a/src/polyp/polyplib-simple.h b/src/polyp/polyplib-simple.h deleted file mode 100644 index b01f30d5..00000000 --- a/src/polyp/polyplib-simple.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef foopolyplibsimplehfoo -#define foopolyplibsimplehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include "sample.h" -#include "polyplib-def.h" -#include - -/** \file - * A simple but limited synchronous playback and recording - * API. This is synchronouse, simplified wrapper around the standard - * asynchronous API. */ - -/** \example pacat-simple.c - * A simple playback tool using the simple API */ - -/** \example parec-simple.c - * A simple recording tool using the simple API */ - -PA_C_DECL_BEGIN - -/** \pa_simple - * An opaque simple connection object */ -typedef struct pa_simple pa_simple; - -/** Create a new connection to the server */ -pa_simple* pa_simple_new( - const char *server, /**< Server name, or NULL for default */ - const char *name, /**< A descriptive name for this client (application name, ...) */ - pa_stream_direction_t dir, /**< Open this stream for recording or playback? */ - const char *dev, /**< Sink (resp. source) name, or NULL for default */ - const char *stream_name, /**< A descriptive name for this client (application name, song title, ...) */ - const pa_sample_spec *ss, /**< The sample type to use */ - const pa_buffer_attr *attr, /**< Buffering attributes, or NULL for default */ - int *error /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */ - ); - -/** Close and free the connection to the server. The connection objects becomes invalid when this is called. */ -void pa_simple_free(pa_simple *s); - -/** Write some data to the server */ -int pa_simple_write(pa_simple *s, const void*data, size_t length, int *error); - -/** Wait until all data already written is played by the daemon */ -int pa_simple_drain(pa_simple *s, int *error); - -/** Read some data from the server */ -int pa_simple_read(pa_simple *s, void*data, size_t length, int *error); - -/** Return the playback latency. \since 0.5 */ -pa_usec_t pa_simple_get_playback_latency(pa_simple *s, int *error); - -/** Flush the playback buffer. \since 0.5 */ -int pa_simple_flush(pa_simple *s, int *error); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/polyplib-stream.c b/src/polyp/polyplib-stream.c deleted file mode 100644 index 63c9245b..00000000 --- a/src/polyp/polyplib-stream.c +++ /dev/null @@ -1,807 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "polyplib-internal.h" -#include -#include -#include -#include - -#define LATENCY_IPOL_INTERVAL_USEC (10000L) - -pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map) { - pa_stream *s; - assert(c); - assert(ss); - - if (!pa_sample_spec_valid(ss)) - return NULL; - - if (map && !pa_channel_map_valid(map)) - return NULL; - - s = pa_xnew(pa_stream, 1); - s->ref = 1; - s->context = c; - s->mainloop = c->mainloop; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->state_callback = NULL; - s->state_userdata = NULL; - - s->direction = PA_STREAM_NODIRECTION; - s->name = pa_xstrdup(name); - s->sample_spec = *ss; - - if (map) - s->channel_map = *map; - else - pa_channel_map_init_auto(&s->channel_map, ss->channels); - - s->channel = 0; - s->channel_valid = 0; - s->device_index = PA_INVALID_INDEX; - s->requested_bytes = 0; - s->state = PA_STREAM_DISCONNECTED; - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->mcalign = pa_mcalign_new(pa_frame_size(ss), c->memblock_stat); - - s->counter = 0; - s->previous_time = 0; - s->previous_ipol_time = 0; - - s->corked = 0; - s->interpolate = 0; - - s->ipol_usec = 0; - memset(&s->ipol_timestamp, 0, sizeof(s->ipol_timestamp)); - s->ipol_event = NULL; - s->ipol_requested = 0; - - PA_LLIST_PREPEND(pa_stream, c->streams, s); - - return pa_stream_ref(s); -} - -static void stream_free(pa_stream *s) { - assert(s); - - if (s->ipol_event) { - assert(s->mainloop); - s->mainloop->time_free(s->ipol_event); - } - - pa_mcalign_free(s->mcalign); - - pa_xfree(s->name); - pa_xfree(s); -} - -void pa_stream_unref(pa_stream *s) { - assert(s && s->ref >= 1); - - if (--(s->ref) == 0) - stream_free(s); -} - -pa_stream* pa_stream_ref(pa_stream *s) { - assert(s && s->ref >= 1); - s->ref++; - return s; -} - -pa_stream_state_t pa_stream_get_state(pa_stream *s) { - assert(s && s->ref >= 1); - return s->state; -} - -pa_context* pa_stream_get_context(pa_stream *s) { - assert(s && s->ref >= 1); - return s->context; -} - -uint32_t pa_stream_get_index(pa_stream *s) { - assert(s && s->ref >= 1); - return s->device_index; -} - -void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { - assert(s && s->ref >= 1); - - if (s->state == st) - return; - - pa_stream_ref(s); - - s->state = st; - - if ((st == PA_STREAM_FAILED || st == PA_STREAM_TERMINATED) && s->context) { - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - PA_LLIST_REMOVE(pa_stream, s->context->streams, s); - pa_stream_unref(s); - } - - if (s->state_callback) - s->state_callback(s, s->state_userdata); - - pa_stream_unref(s); -} - -void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_context *c = userdata; - pa_stream *s; - uint32_t channel; - assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); - - pa_context_ref(c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(c, PA_ERROR_PROTOCOL); - goto finish; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - goto finish; - - c->error = PA_ERROR_KILLED; - pa_stream_set_state(s, PA_STREAM_FAILED); - -finish: - pa_context_unref(c); -} - -void pa_command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_stream *s; - pa_context *c = userdata; - uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && c); - - pa_context_ref(c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(c, PA_ERROR_PROTOCOL); - goto finish; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - goto finish; - - if (s->state != PA_STREAM_READY) - goto finish; - - pa_stream_ref(s); - - s->requested_bytes += bytes; - - if (s->requested_bytes && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); - - pa_stream_unref(s); - -finish: - pa_context_unref(c); -} - -static void ipol_callback(pa_mainloop_api *m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - struct timeval tv2; - pa_stream *s = userdata; - - pa_stream_ref(s); - -/* pa_log("requesting new ipol data\n"); */ - - if (s->state == PA_STREAM_READY && !s->ipol_requested) { - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); - s->ipol_requested = 1; - } - - pa_gettimeofday(&tv2); - pa_timeval_add(&tv2, LATENCY_IPOL_INTERVAL_USEC); - - m->time_restart(e, &tv2); - - pa_stream_unref(s); -} - - -void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_stream *s = userdata; - assert(pd && s && s->state == PA_STREAM_CREATING); - - pa_stream_ref(s); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(s->context, command, t) < 0) - goto finish; - - pa_stream_set_state(s, PA_STREAM_FAILED); - goto finish; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - ((s->direction != PA_STREAM_RECORD) && pa_tagstruct_getu32(t, &s->requested_bytes) < 0) || - !pa_tagstruct_eof(t)) { - pa_context_fail(s->context, PA_ERROR_PROTOCOL); - goto finish; - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - pa_stream_set_state(s, PA_STREAM_READY); - - if (s->interpolate) { - struct timeval tv; - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); - - pa_gettimeofday(&tv); - tv.tv_usec += LATENCY_IPOL_INTERVAL_USEC; /* every 100 ms */ - - assert(!s->ipol_event); - s->ipol_event = s->mainloop->time_new(s->mainloop, &tv, &ipol_callback, s); - } - - if (s->requested_bytes && s->ref > 1 && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); - -finish: - pa_stream_unref(s); -} - -static void create_stream(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags, const pa_cvolume *volume) { - pa_tagstruct *t; - uint32_t tag; - assert(s && s->ref >= 1 && s->state == PA_STREAM_DISCONNECTED); - - pa_stream_ref(s); - - s->interpolate = !!(flags & PA_STREAM_INTERPOLATE_LATENCY); - pa_stream_trash_ipol(s); - - if (attr) - s->buffer_attr = *attr; - else { - /* half a second */ - s->buffer_attr.tlength = pa_bytes_per_second(&s->sample_spec)/2; - s->buffer_attr.maxlength = (s->buffer_attr.tlength*3)/2; - s->buffer_attr.minreq = s->buffer_attr.tlength/100; - s->buffer_attr.prebuf = s->buffer_attr.tlength - s->buffer_attr.minreq; - s->buffer_attr.fragsize = s->buffer_attr.tlength/100; - } - - pa_stream_set_state(s, PA_STREAM_CREATING); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - if (!dev) { - if (s->direction == PA_STREAM_PLAYBACK) - dev = s->context->conf->default_sink; - else - dev = s->context->conf->default_source; - } - - pa_tagstruct_put(t, - PA_TAG_U32, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM, - PA_TAG_U32, tag = s->context->ctag++, - PA_TAG_STRING, s->name, - PA_TAG_SAMPLE_SPEC, &s->sample_spec, - PA_TAG_CHANNEL_MAP, &s->channel_map, - PA_TAG_U32, PA_INVALID_INDEX, - PA_TAG_STRING, dev, - PA_TAG_U32, s->buffer_attr.maxlength, - PA_TAG_BOOLEAN, !!(flags & PA_STREAM_START_CORKED), - PA_TAG_INVALID); - - if (s->direction == PA_STREAM_PLAYBACK) { - pa_cvolume cv; - pa_tagstruct_put(t, - PA_TAG_U32, s->buffer_attr.tlength, - PA_TAG_U32, s->buffer_attr.prebuf, - PA_TAG_U32, s->buffer_attr.minreq, - PA_TAG_INVALID); - - if (!volume) { - pa_cvolume_reset(&cv, s->sample_spec.channels); - volume = &cv; - } - - pa_tagstruct_put_cvolume(t, volume); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s); - - pa_stream_unref(s); -} - -void pa_stream_connect_playback(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags, pa_cvolume *volume) { - assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); - s->direction = PA_STREAM_PLAYBACK; - create_stream(s, dev, attr, flags, volume); -} - -void pa_stream_connect_record(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags) { - assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); - s->direction = PA_STREAM_RECORD; - create_stream(s, dev, attr, flags, 0); -} - -void pa_stream_write(pa_stream *s, const void *data, size_t length, void (*free_cb)(void *p), size_t delta) { - pa_memchunk chunk; - assert(s && s->context && data && length && s->state == PA_STREAM_READY && s->ref >= 1); - - if (free_cb) { - chunk.memblock = pa_memblock_new_user((void*) data, length, free_cb, 1, s->context->memblock_stat); - assert(chunk.memblock && chunk.memblock->data); - } else { - chunk.memblock = pa_memblock_new(length, s->context->memblock_stat); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); - } - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, delta, &chunk); - pa_memblock_unref(chunk.memblock); - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; - - s->counter += length; -} - -size_t pa_stream_writable_size(pa_stream *s) { - assert(s && s->ref >= 1); - return s->state == PA_STREAM_READY ? s->requested_bytes : 0; -} - -pa_operation * pa_stream_drain(pa_stream *s, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); - - o = pa_operation_new(s->context, s); - assert(o); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -static void stream_get_latency_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - pa_latency_info i, *p = NULL; - struct timeval local, remote, now; - assert(pd && o && o->stream && o->context); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - } else if (pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || - pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || - pa_tagstruct_get_usec(t, &i.source_usec) < 0 || - pa_tagstruct_get_boolean(t, &i.playing) < 0 || - pa_tagstruct_getu32(t, &i.queue_length) < 0 || - pa_tagstruct_get_timeval(t, &local) < 0 || - pa_tagstruct_get_timeval(t, &remote) < 0 || - pa_tagstruct_getu64(t, &i.counter) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } else { - pa_gettimeofday(&now); - - if (pa_timeval_cmp(&local, &remote) <= 0 && pa_timeval_cmp(&remote, &now) <= 0) { - /* local and remote seem to have synchronized clocks */ - - if (o->stream->direction == PA_STREAM_PLAYBACK) - i.transport_usec = pa_timeval_diff(&remote, &local); - else - i.transport_usec = pa_timeval_diff(&now, &remote); - - i.synchronized_clocks = 1; - i.timestamp = remote; - } else { - /* clocks are not synchronized, let's estimate latency then */ - i.transport_usec = pa_timeval_diff(&now, &local)/2; - i.synchronized_clocks = 0; - i.timestamp = local; - pa_timeval_add(&i.timestamp, i.transport_usec); - } - - if (o->stream->interpolate) { -/* pa_log("new interpol data\n"); */ - o->stream->ipol_timestamp = i.timestamp; - o->stream->ipol_usec = pa_stream_get_time(o->stream, &i); - o->stream->ipol_requested = 0; - } - - p = &i; - } - - if (o->callback) { - void (*cb)(pa_stream *s, const pa_latency_info *_i, void *_userdata) = (void (*)(pa_stream *s, const pa_latency_info *_i, void *_userdata)) o->callback; - cb(o->stream, p, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_stream_get_latency_info(pa_stream *s, void (*cb)(pa_stream *p, const pa_latency_info*i, void *userdata), void *userdata) { - uint32_t tag; - pa_operation *o; - pa_tagstruct *t; - struct timeval now; - assert(s && s->direction != PA_STREAM_UPLOAD); - - o = pa_operation_new(s->context, s); - assert(o); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_GET_PLAYBACK_LATENCY : PA_COMMAND_GET_RECORD_LATENCY); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - - pa_gettimeofday(&now); - pa_tagstruct_put_timeval(t, &now); - pa_tagstruct_putu64(t, s->counter); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_info_callback, o); - - return pa_operation_ref(o); -} - -void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_stream *s = userdata; - assert(pd && s && s->ref >= 1); - - pa_stream_ref(s); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(s->context, command, t) < 0) - goto finish; - - pa_stream_set_state(s, PA_STREAM_FAILED); - goto finish; - } else if (!pa_tagstruct_eof(t)) { - pa_context_fail(s->context, PA_ERROR_PROTOCOL); - goto finish; - } - - pa_stream_set_state(s, PA_STREAM_TERMINATED); - -finish: - pa_stream_unref(s); -} - -void pa_stream_disconnect(pa_stream *s) { - pa_tagstruct *t; - uint32_t tag; - assert(s && s->ref >= 1); - - if (!s->channel_valid || !s->context->state == PA_CONTEXT_READY) - return; - - pa_stream_ref(s); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s); - - pa_stream_unref(s); -} - -void pa_stream_set_read_callback(pa_stream *s, void (*cb)(pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && s->ref >= 1); - s->read_callback = cb; - s->read_userdata = userdata; -} - -void pa_stream_set_write_callback(pa_stream *s, void (*cb)(pa_stream *p, size_t length, void *userdata), void *userdata) { - assert(s && s->ref >= 1); - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_set_state_callback(pa_stream *s, void (*cb)(pa_stream *s, void *userdata), void *userdata) { - assert(s && s->ref >= 1); - s->state_callback = cb; - s->state_userdata = userdata; -} - -void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int success = 1; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - success = 0; - } else if (!pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_stream *s, int _success, void *_userdata) = (void (*)(pa_stream *s, int _success, void *_userdata)) o->callback; - cb(o->stream, success, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_stream_cork(pa_stream *s, int b, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); - - if (s->interpolate) { - if (!s->corked && b) - /* Pausing */ - s->ipol_usec = pa_stream_get_interpolated_time(s); - else if (s->corked && !b) - /* Unpausing */ - pa_gettimeofday(&s->ipol_timestamp); - } - - s->corked = b; - - o = pa_operation_new(s->context, s); - assert(o); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CORK_PLAYBACK_STREAM : PA_COMMAND_CORK_RECORD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_tagstruct_put_boolean(t, !!b); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); - - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); - - return pa_operation_ref(o); -} - -static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); - - o = pa_operation_new(s->context, s); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, command); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -pa_operation* pa_stream_flush(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { - pa_operation *o; - o = stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata); - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); - return o; -} - -pa_operation* pa_stream_prebuf(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { - pa_operation *o; - o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata); - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); - return o; -} - -pa_operation* pa_stream_trigger(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { - pa_operation *o; - o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata); - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); - return o; -} - -pa_operation* pa_stream_set_name(pa_stream *s, const char *name, void(*cb)(pa_stream*c, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(s && s->ref >= 1 && s->state == PA_STREAM_READY && name && s->direction != PA_STREAM_UPLOAD); - - o = pa_operation_new(s->context, s); - assert(o); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, s->direction == PA_STREAM_RECORD ? PA_COMMAND_SET_RECORD_STREAM_NAME : PA_COMMAND_SET_PLAYBACK_STREAM_NAME); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -uint64_t pa_stream_get_counter(pa_stream *s) { - assert(s); - return s->counter; -} - -pa_usec_t pa_stream_get_time(pa_stream *s, const pa_latency_info *i) { - pa_usec_t usec; - assert(s); - - usec = pa_bytes_to_usec(i->counter, &s->sample_spec); - - if (i) { - if (s->direction == PA_STREAM_PLAYBACK) { - pa_usec_t latency = i->transport_usec + i->buffer_usec + i->sink_usec; - if (usec < latency) - usec = 0; - else - usec -= latency; - - } else if (s->direction == PA_STREAM_RECORD) { - usec += i->source_usec + i->buffer_usec + i->transport_usec; - - if (usec > i->sink_usec) - usec -= i->sink_usec; - else - usec = 0; - } - } - - if (usec < s->previous_time) - usec = s->previous_time; - - s->previous_time = usec; - - return usec; -} - -static pa_usec_t time_counter_diff(pa_stream *s, pa_usec_t t, pa_usec_t c, int *negative) { - assert(s); - - if (negative) - *negative = 0; - - if (c < t) { - if (s->direction == PA_STREAM_RECORD) { - if (negative) - *negative = 1; - - return t-c; - } else - return 0; - } else - return c-t; -} - -pa_usec_t pa_stream_get_latency(pa_stream *s, const pa_latency_info *i, int *negative) { - pa_usec_t t, c; - assert(s && i); - - t = pa_stream_get_time(s, i); - c = pa_bytes_to_usec(s->counter, &s->sample_spec); - - return time_counter_diff(s, t, c, negative); -} - -const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) { - assert(s); - return &s->sample_spec; -} - -void pa_stream_trash_ipol(pa_stream *s) { - assert(s); - - if (!s->interpolate) - return; - - memset(&s->ipol_timestamp, 0, sizeof(s->ipol_timestamp)); - s->ipol_usec = 0; -} - -pa_usec_t pa_stream_get_interpolated_time(pa_stream *s) { - pa_usec_t usec; - assert(s && s->interpolate); - - if (s->corked) - usec = s->ipol_usec; - else { - if (s->ipol_timestamp.tv_sec == 0) - usec = 0; - else - usec = s->ipol_usec + pa_timeval_age(&s->ipol_timestamp); - } - - if (usec < s->previous_ipol_time) - usec = s->previous_ipol_time; - - s->previous_ipol_time = usec; - - return usec; -} - -pa_usec_t pa_stream_get_interpolated_latency(pa_stream *s, int *negative) { - pa_usec_t t, c; - assert(s && s->interpolate); - - t = pa_stream_get_interpolated_time(s); - c = pa_bytes_to_usec(s->counter, &s->sample_spec); - return time_counter_diff(s, t, c, negative); -} diff --git a/src/polyp/polyplib-stream.h b/src/polyp/polyplib-stream.h deleted file mode 100644 index bc828b71..00000000 --- a/src/polyp/polyplib-stream.h +++ /dev/null @@ -1,181 +0,0 @@ -#ifndef foopolyplibstreamhfoo -#define foopolyplibstreamhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include -#include -#include -#include -#include -#include - -/** \file - * Audio streams for input, output and sample upload */ - -PA_C_DECL_BEGIN - -/** \pa_stream - * An opaque stream for playback or recording */ -typedef struct pa_stream pa_stream; - -/** Create a new, unconnected stream with the specified name and sample type */ -pa_stream* pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map); - -/** Decrease the reference counter by one */ -void pa_stream_unref(pa_stream *s); - -/** Increase the reference counter by one */ -pa_stream *pa_stream_ref(pa_stream *s); - -/** Return the current state of the stream */ -pa_stream_state_t pa_stream_get_state(pa_stream *p); - -/** Return the context this stream is attached to */ -pa_context* pa_stream_get_context(pa_stream *p); - -/** Return the device (sink input or source output) index this stream is connected to */ -uint32_t pa_stream_get_index(pa_stream *s); - -/** Connect the stream to a sink */ -void pa_stream_connect_playback( - pa_stream *s, - const char *dev, - const pa_buffer_attr *attr, - pa_stream_flags_t flags, - pa_cvolume *volume); - -/** Connect the stream to a source */ -void pa_stream_connect_record( - pa_stream *s, - const char *dev, - const pa_buffer_attr *attr, - pa_stream_flags_t flags); - -/** Disconnect a stream from a source/sink */ -void pa_stream_disconnect(pa_stream *s); - -/** Write some data to the server (for playback sinks), if free_cb is - * non-NULL this routine is called when all data has been written out - * and an internal reference to the specified data is kept, the data - * is not copied. If NULL, the data is copied into an internal - * buffer. */ -void pa_stream_write(pa_stream *p /**< The stream to use */, - const void *data /**< The data to write */, - size_t length /**< The length of the data to write */, - void (*free_cb)(void *p) /**< A cleanup routine for the data or NULL to request an internal copy */, - size_t delta /**< Drop this many - bytes in the playback - buffer before writing - this data. Use - (size_t) -1 for - clearing the whole - playback - buffer. Normally you - will specify 0 here, - i.e. append to the - playback buffer. If - the value given here - is greater than the - buffered data length - the buffer is cleared - and the data is - written to the - buffer's start. This - value is ignored on - upload streams. */); - -/** Return the amount of bytes that may be written using pa_stream_write() */ -size_t pa_stream_writable_size(pa_stream *p); - -/** Drain a playback stream */ -pa_operation* pa_stream_drain(pa_stream *s, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata); - -/** Get the playback latency of a stream */ -pa_operation* pa_stream_get_latency_info(pa_stream *p, void (*cb)(pa_stream *p, const pa_latency_info *i, void *userdata), void *userdata); - -/** Set the callback function that is called whenever the state of the stream changes */ -void pa_stream_set_state_callback(pa_stream *s, void (*cb)(pa_stream *s, void *userdata), void *userdata); - -/** Set the callback function that is called when new data may be - * written to the stream. */ -void pa_stream_set_write_callback(pa_stream *p, void (*cb)(pa_stream *p, size_t length, void *userdata), void *userdata); - -/** Set the callback function that is called when new data is available from the stream */ -void pa_stream_set_read_callback(pa_stream *p, void (*cb)(pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); - -/** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. \since 0.3 */ -pa_operation* pa_stream_cork(pa_stream *s, int b, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata); - -/** Flush the playback buffer of this stream. Most of the time you're - * better off using the parameter delta of pa_stream_write() instead of this - * function. Available on both playback and recording streams. \since 0.3 */ -pa_operation* pa_stream_flush(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata); - -/** Reenable prebuffering. Available for playback streams only. \since 0.6 */ -pa_operation* pa_stream_prebuf(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata); - -/** Request immediate start of playback on this stream. This disables - * prebuffering as specified in the pa_buffer_attr structure. Available for playback streams only. \since - * 0.3 */ -pa_operation* pa_stream_trigger(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata); - -/** Rename the stream. \since 0.5 */ -pa_operation* pa_stream_set_name(pa_stream *s, const char *name, void(*cb)(pa_stream*c, int success, void *userdata), void *userdata); - -/** Return the total number of bytes written to/read from the - * stream. This counter is not reset on pa_stream_flush(), you may do - * this yourself using pa_stream_reset_counter(). \since 0.6 */ -uint64_t pa_stream_get_counter(pa_stream *s); - -/** Return the current playback/recording time. This is based on the - * counter accessible with pa_stream_get_counter(). This function - * requires a pa_latency_info structure as argument, which should be - * acquired using pa_stream_get_latency(). \since 0.6 */ -pa_usec_t pa_stream_get_time(pa_stream *s, const pa_latency_info *i); - -/** Return the total stream latency. Thus function requires a - * pa_latency_info structure as argument, which should be aquired - * using pa_stream_get_latency(). In case the stream is a monitoring - * stream the result can be negative, i.e. the captured samples are - * not yet played. In this case *negative is set to 1. \since 0.6 */ -pa_usec_t pa_stream_get_latency(pa_stream *s, const pa_latency_info *i, int *negative); - -/** Return the interpolated playback/recording time. Requires the - * PA_STREAM_INTERPOLATE_LATENCY bit set when creating the stream. In - * contrast to pa_stream_get_latency() this function doesn't require - * a whole roundtrip for response. \since 0.6 */ -pa_usec_t pa_stream_get_interpolated_time(pa_stream *s); - -/** Return the interpolated playback/recording latency. Requires the - * PA_STREAM_INTERPOLATE_LATENCY bit set when creating the - * stream. \since 0.6 */ -pa_usec_t pa_stream_get_interpolated_latency(pa_stream *s, int *negative); - -/** Return a pointer to the streams sample specification. \since 0.6 */ -const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/polyplib-subscribe.c b/src/polyp/polyplib-subscribe.c deleted file mode 100644 index 13fcfb42..00000000 --- a/src/polyp/polyplib-subscribe.c +++ /dev/null @@ -1,81 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "polyplib-subscribe.h" -#include "polyplib-internal.h" -#include -#include - -void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_context *c = userdata; - pa_subscription_event_type_t e; - uint32_t index; - assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); - - pa_context_ref(c); - - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &index) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(c, PA_ERROR_PROTOCOL); - goto finish; - } - - if (c->subscribe_callback) - c->subscribe_callback(c, e, index, c->subscribe_userdata); - -finish: - pa_context_unref(c); -} - - -pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - assert(c); - - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; - o->userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, m); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - - return pa_operation_ref(o); -} - -void pa_context_set_subscribe_callback(pa_context *c, void (*cb)(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata) { - assert(c); - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; -} diff --git a/src/polyp/polyplib-subscribe.h b/src/polyp/polyplib-subscribe.h deleted file mode 100644 index 920c9853..00000000 --- a/src/polyp/polyplib-subscribe.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef foopolyplibsubscribehfoo -#define foopolyplibsubscribehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include -#include -#include - -/** \file - * Daemon introspection event subscription subsystem. Use this - * to be notified whenever the internal layout of daemon changes: - * i.e. entities such as sinks or sources are create, removed or - * modified. */ - -PA_C_DECL_BEGIN - -/** Enable event notification */ -pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); - -/** Set the context specific call back function that is called whenever the state of the daemon changes */ -void pa_context_set_subscribe_callback(pa_context *c, void (*cb)(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/polyplib-version.h.in b/src/polyp/polyplib-version.h.in deleted file mode 100644 index 89e0a0e5..00000000 --- a/src/polyp/polyplib-version.h.in +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef foopolyplibversionhfoo /*-*-C-*-*/ -#define foopolyplibversionhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -/* WARNING: Make sure to edit the real source file polyplib-version.h.in! */ - -/** \file - * Define header version */ - -PA_C_DECL_BEGIN - -/** Return the version of the header files. Keep in mind that this is -a macro and not a function, so it is impossible to get the pointer of -it. */ -#define pa_get_headers_version() ("@PACKAGE_VERSION@") - -/** Return the version of the library the current application is linked to. */ -const char* pa_get_library_version(void); - -/** The current API version. Version 6 relates to polypaudio - * 0.6. Prior versions (i.e. Polypaudio 0.5.1 and older) have - * PA_API_VERSION undefined. */ -#define PA_API_VERSION @PA_API_VERSION@ - -PA_C_DECL_END - -#endif diff --git a/src/polyp/polyplib.h b/src/polyp/polyplib.h deleted file mode 100644 index b9b9b447..00000000 --- a/src/polyp/polyplib.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** \file - * Include all polyplib header file at once. The following files are included: \ref mainloop-api.h, \ref sample.h, - * \ref polyplib-def.h, \ref polyplib-context.h, \ref polyplib-stream.h, - * \ref polyplib-introspect.h, \ref polyplib-subscribe.h and \ref polyplib-scache.h \ref polyplib-version.h - * at once */ - -/** \mainpage - * - * \section intro_sec Introduction - * - * This document describes the client API for the polypaudio sound - * server. The API comes in two flavours: - * - * \li The complete but somewhat complicated to use asynchronous API - * \li And the simplified, easy to use, but limited synchronous API - * - * The polypaudio client libraries are thread safe as long as all - * objects created by any library function are accessed from the thread - * that created them only. - * - * \section simple_sec Simple API - * - * Use this if you develop your program in synchronous style and just - * need a way to play or record data on the sound server. See - * \ref polyplib-simple.h for more details. - * - * \section async_api Asynchronous API - * - * Use this if you develop your programs in asynchronous, main loop - * based style or want to use advanced features of the polypaudio - * API. A good starting point is \ref polyplib-context.h - * - * The asynchronous API relies on an abstract main loop API that is - * described in \ref mainloop-api.h. Two distinct implementations are - * available: - * - * \li \ref mainloop.h: a minimal but fast implementation based on poll() - * \li \ref glib-mainloop.h: a wrapper around GLIB's main loop - * - * UNIX signals may be hooked to a main loop using the functions from - * \ref mainloop-signal.h - * - * \section pkgconfig pkg-config - * - * The polypaudio libraries provide pkg-config snippets for the different modules. To use the - * asynchronous API use "polyplib" as pkg-config file. GLIB main loop - * support is available as "polyplib-glib-mainloop". The simple - * synchronous API is available as "polyplib-simple". - */ - -#endif diff --git a/src/polyp/scache.c b/src/polyp/scache.c new file mode 100644 index 00000000..c274e359 --- /dev/null +++ b/src/polyp/scache.c @@ -0,0 +1,127 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "scache.h" +#include "internal.h" +#include + +void pa_stream_connect_upload(pa_stream *s, size_t length) { + pa_tagstruct *t; + uint32_t tag; + + assert(s && length); + + pa_stream_ref(s); + + s->state = PA_STREAM_CREATING; + s->direction = PA_STREAM_UPLOAD; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_puts(t, s->name); + pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_putu32(t, length); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s); + + pa_stream_unref(s); +} + +void pa_stream_finish_upload(pa_stream *s) { + pa_tagstruct *t; + uint32_t tag; + assert(s); + + if (!s->channel_valid || !s->context->state == PA_CONTEXT_READY) + return; + + pa_stream_ref(s); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s); + + pa_stream_unref(s); +} + +pa_operation * pa_context_play_sample(pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && name && *name && (!dev || *dev)); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + if (!dev) + dev = c->conf->default_sink; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_puts(t, dev); + pa_tagstruct_putu32(t, volume); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_context_remove_sample(pa_context *c, const char *name, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c && name); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + diff --git a/src/polyp/scache.h b/src/polyp/scache.h new file mode 100644 index 00000000..41b956d2 --- /dev/null +++ b/src/polyp/scache.h @@ -0,0 +1,50 @@ +#ifndef foopolyplibscachehfoo +#define foopolyplibscachehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include +#include + +/** \file + * All sample cache related routines */ + +PA_C_DECL_BEGIN + +/** Make this stream a sample upload stream */ +void pa_stream_connect_upload(pa_stream *s, size_t length); + +/** Finish the sample upload, the stream name will become the sample name. You cancel a sample upload by issuing pa_stream_disconnect() */ +void pa_stream_finish_upload(pa_stream *s); + +/** Play a sample from the sample cache to the specified device. If the latter is NULL use the default sink. Returns an operation object */ +pa_operation* pa_context_play_sample(pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +/** Remove a sample from the sample cache. Returns an operation object which may be used to cancel the operation while it is running */ +pa_operation* pa_context_remove_sample(pa_context *c, const char *name, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/simple.c b/src/polyp/simple.c new file mode 100644 index 00000000..6f20da89 --- /dev/null +++ b/src/polyp/simple.c @@ -0,0 +1,393 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "simple.h" +#include "polyplib.h" +#include "mainloop.h" +#include +#include +#include + +struct pa_simple { + pa_mainloop *mainloop; + pa_context *context; + pa_stream *stream; + pa_stream_direction_t direction; + + int dead; + + void *read_data; + size_t read_index, read_length; + pa_usec_t latency; +}; + +static void read_callback(pa_stream *s, const void*data, size_t length, void *userdata); + +static int check_error(pa_simple *p, int *rerror) { + pa_context_state_t cst; + pa_stream_state_t sst; + assert(p); + + if ((cst = pa_context_get_state(p->context)) == PA_CONTEXT_FAILED) + goto fail; + + assert(cst != PA_CONTEXT_TERMINATED); + + if (p->stream) { + if ((sst = pa_stream_get_state(p->stream)) == PA_STREAM_FAILED) + goto fail; + + assert(sst != PA_STREAM_TERMINATED); + } + + return 0; + +fail: + if (rerror) + *rerror = pa_context_errno(p->context); + + p->dead = 1; + + return -1; +} + +static int iterate(pa_simple *p, int block, int *rerror) { + assert(p && p->context && p->mainloop); + + if (check_error(p, rerror) < 0) + return -1; + + if (!block && !pa_context_is_pending(p->context)) + return 0; + + do { + if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) { + if (rerror) + *rerror = PA_ERROR_INTERNAL; + return -1; + } + + if (check_error(p, rerror) < 0) + return -1; + + } while (pa_context_is_pending(p->context)); + + + while (pa_mainloop_deferred_pending(p->mainloop)) { + + if (pa_mainloop_iterate(p->mainloop, 0, NULL) < 0) { + if (rerror) + *rerror = PA_ERROR_INTERNAL; + return -1; + } + + if (check_error(p, rerror) < 0) + return -1; + } + + return 0; +} + +pa_simple* pa_simple_new( + const char *server, + const char *name, + pa_stream_direction_t dir, + const char *dev, + const char *stream_name, + const pa_sample_spec *ss, + const pa_buffer_attr *attr, + int *rerror) { + + pa_simple *p; + int error = PA_ERROR_INTERNAL; + assert(ss && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); + + p = pa_xmalloc(sizeof(pa_simple)); + p->context = NULL; + p->stream = NULL; + p->mainloop = pa_mainloop_new(); + assert(p->mainloop); + p->dead = 0; + p->direction = dir; + p->read_data = NULL; + p->read_index = p->read_length = 0; + p->latency = 0; + + if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name))) + goto fail; + + pa_context_connect(p->context, server, 1, NULL); + + /* Wait until the context is ready */ + while (pa_context_get_state(p->context) != PA_CONTEXT_READY) { + if (iterate(p, 1, &error) < 0) + goto fail; + } + + if (!(p->stream = pa_stream_new(p->context, stream_name, ss, NULL))) + goto fail; + + if (dir == PA_STREAM_PLAYBACK) + pa_stream_connect_playback(p->stream, dev, attr, 0, NULL); + else + pa_stream_connect_record(p->stream, dev, attr, 0); + + /* Wait until the stream is ready */ + while (pa_stream_get_state(p->stream) != PA_STREAM_READY) { + if (iterate(p, 1, &error) < 0) + goto fail; + } + + pa_stream_set_read_callback(p->stream, read_callback, p); + + return p; + +fail: + if (rerror) + *rerror = error; + pa_simple_free(p); + return NULL; +} + +void pa_simple_free(pa_simple *s) { + assert(s); + + pa_xfree(s->read_data); + + if (s->stream) + pa_stream_unref(s->stream); + + if (s->context) + pa_context_unref(s->context); + + if (s->mainloop) + pa_mainloop_free(s->mainloop); + + pa_xfree(s); +} + +int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { + assert(p && data && p->direction == PA_STREAM_PLAYBACK); + + if (p->dead) { + if (rerror) + *rerror = pa_context_errno(p->context); + + return -1; + } + + while (length > 0) { + size_t l; + + while (!(l = pa_stream_writable_size(p->stream))) + if (iterate(p, 1, rerror) < 0) + return -1; + + if (l > length) + l = length; + + pa_stream_write(p->stream, data, l, NULL, 0); + data = (const uint8_t*) data + l; + length -= l; + } + + /* Make sure that no data is pending for write */ + if (iterate(p, 0, rerror) < 0) + return -1; + + return 0; +} + +static void read_callback(pa_stream *s, const void*data, size_t length, void *userdata) { + pa_simple *p = userdata; + assert(s && data && length && p); + + if (p->read_data) { + pa_log(__FILE__": Buffer overflow, dropping incoming memory blocks.\n"); + pa_xfree(p->read_data); + } + + p->read_data = pa_xmemdup(data, p->read_length = length); + p->read_index = 0; +} + +int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { + assert(p && data && p->direction == PA_STREAM_RECORD); + + if (p->dead) { + if (rerror) + *rerror = pa_context_errno(p->context); + + return -1; + } + + while (length > 0) { + if (p->read_data) { + size_t l = length; + + if (p->read_length <= l) + l = p->read_length; + + memcpy(data, (uint8_t*) p->read_data+p->read_index, l); + + data = (uint8_t*) data + l; + length -= l; + + p->read_index += l; + p->read_length -= l; + + if (!p->read_length) { + pa_xfree(p->read_data); + p->read_data = NULL; + p->read_index = 0; + } + + if (!length) + return 0; + + assert(!p->read_data); + } + + if (iterate(p, 1, rerror) < 0) + return -1; + } + + return 0; +} + +static void drain_or_flush_complete(pa_stream *s, int success, void *userdata) { + pa_simple *p = userdata; + assert(s && p); + if (!success) + p->dead = 1; +} + +int pa_simple_drain(pa_simple *p, int *rerror) { + pa_operation *o; + assert(p && p->direction == PA_STREAM_PLAYBACK); + + if (p->dead) { + if (rerror) + *rerror = pa_context_errno(p->context); + + return -1; + } + + o = pa_stream_drain(p->stream, drain_or_flush_complete, p); + + while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { + if (iterate(p, 1, rerror) < 0) { + pa_operation_cancel(o); + pa_operation_unref(o); + return -1; + } + } + + pa_operation_unref(o); + + if (p->dead && rerror) + *rerror = pa_context_errno(p->context); + + return p->dead ? -1 : 0; +} + +static void latency_complete(pa_stream *s, const pa_latency_info *l, void *userdata) { + pa_simple *p = userdata; + assert(s && p); + + if (!l) + p->dead = 1; + else { + int negative = 0; + p->latency = pa_stream_get_latency(s, l, &negative); + if (negative) + p->latency = 0; + } +} + +pa_usec_t pa_simple_get_playback_latency(pa_simple *p, int *rerror) { + pa_operation *o; + assert(p && p->direction == PA_STREAM_PLAYBACK); + + if (p->dead) { + if (rerror) + *rerror = pa_context_errno(p->context); + + return (pa_usec_t) -1; + } + + p->latency = 0; + o = pa_stream_get_latency_info(p->stream, latency_complete, p); + + while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { + + if (iterate(p, 1, rerror) < 0) { + pa_operation_cancel(o); + pa_operation_unref(o); + return -1; + } + } + + pa_operation_unref(o); + + if (p->dead && rerror) + *rerror = pa_context_errno(p->context); + + return p->dead ? (pa_usec_t) -1 : p->latency; +} + +int pa_simple_flush(pa_simple *p, int *rerror) { + pa_operation *o; + assert(p && p->direction == PA_STREAM_PLAYBACK); + + if (p->dead) { + if (rerror) + *rerror = pa_context_errno(p->context); + + return -1; + } + + o = pa_stream_flush(p->stream, drain_or_flush_complete, p); + + while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { + if (iterate(p, 1, rerror) < 0) { + pa_operation_cancel(o); + pa_operation_unref(o); + return -1; + } + } + + pa_operation_unref(o); + + if (p->dead && rerror) + *rerror = pa_context_errno(p->context); + + return p->dead ? -1 : 0; +} diff --git a/src/polyp/simple.h b/src/polyp/simple.h new file mode 100644 index 00000000..31dcaef4 --- /dev/null +++ b/src/polyp/simple.h @@ -0,0 +1,80 @@ +#ifndef foopolyplibsimplehfoo +#define foopolyplibsimplehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "sample.h" +#include "def.h" +#include + +/** \file + * A simple but limited synchronous playback and recording + * API. This is synchronouse, simplified wrapper around the standard + * asynchronous API. */ + +/** \example pacat-simple.c + * A simple playback tool using the simple API */ + +/** \example parec-simple.c + * A simple recording tool using the simple API */ + +PA_C_DECL_BEGIN + +/** \pa_simple + * An opaque simple connection object */ +typedef struct pa_simple pa_simple; + +/** Create a new connection to the server */ +pa_simple* pa_simple_new( + const char *server, /**< Server name, or NULL for default */ + const char *name, /**< A descriptive name for this client (application name, ...) */ + pa_stream_direction_t dir, /**< Open this stream for recording or playback? */ + const char *dev, /**< Sink (resp. source) name, or NULL for default */ + const char *stream_name, /**< A descriptive name for this client (application name, song title, ...) */ + const pa_sample_spec *ss, /**< The sample type to use */ + const pa_buffer_attr *attr, /**< Buffering attributes, or NULL for default */ + int *error /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */ + ); + +/** Close and free the connection to the server. The connection objects becomes invalid when this is called. */ +void pa_simple_free(pa_simple *s); + +/** Write some data to the server */ +int pa_simple_write(pa_simple *s, const void*data, size_t length, int *error); + +/** Wait until all data already written is played by the daemon */ +int pa_simple_drain(pa_simple *s, int *error); + +/** Read some data from the server */ +int pa_simple_read(pa_simple *s, void*data, size_t length, int *error); + +/** Return the playback latency. \since 0.5 */ +pa_usec_t pa_simple_get_playback_latency(pa_simple *s, int *error); + +/** Flush the playback buffer. \since 0.5 */ +int pa_simple_flush(pa_simple *s, int *error); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/stream.c b/src/polyp/stream.c new file mode 100644 index 00000000..007d5e24 --- /dev/null +++ b/src/polyp/stream.c @@ -0,0 +1,807 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "internal.h" +#include +#include +#include +#include + +#define LATENCY_IPOL_INTERVAL_USEC (10000L) + +pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map) { + pa_stream *s; + assert(c); + assert(ss); + + if (!pa_sample_spec_valid(ss)) + return NULL; + + if (map && !pa_channel_map_valid(map)) + return NULL; + + s = pa_xnew(pa_stream, 1); + s->ref = 1; + s->context = c; + s->mainloop = c->mainloop; + + s->read_callback = NULL; + s->read_userdata = NULL; + s->write_callback = NULL; + s->write_userdata = NULL; + s->state_callback = NULL; + s->state_userdata = NULL; + + s->direction = PA_STREAM_NODIRECTION; + s->name = pa_xstrdup(name); + s->sample_spec = *ss; + + if (map) + s->channel_map = *map; + else + pa_channel_map_init_auto(&s->channel_map, ss->channels); + + s->channel = 0; + s->channel_valid = 0; + s->device_index = PA_INVALID_INDEX; + s->requested_bytes = 0; + s->state = PA_STREAM_DISCONNECTED; + memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); + + s->mcalign = pa_mcalign_new(pa_frame_size(ss), c->memblock_stat); + + s->counter = 0; + s->previous_time = 0; + s->previous_ipol_time = 0; + + s->corked = 0; + s->interpolate = 0; + + s->ipol_usec = 0; + memset(&s->ipol_timestamp, 0, sizeof(s->ipol_timestamp)); + s->ipol_event = NULL; + s->ipol_requested = 0; + + PA_LLIST_PREPEND(pa_stream, c->streams, s); + + return pa_stream_ref(s); +} + +static void stream_free(pa_stream *s) { + assert(s); + + if (s->ipol_event) { + assert(s->mainloop); + s->mainloop->time_free(s->ipol_event); + } + + pa_mcalign_free(s->mcalign); + + pa_xfree(s->name); + pa_xfree(s); +} + +void pa_stream_unref(pa_stream *s) { + assert(s && s->ref >= 1); + + if (--(s->ref) == 0) + stream_free(s); +} + +pa_stream* pa_stream_ref(pa_stream *s) { + assert(s && s->ref >= 1); + s->ref++; + return s; +} + +pa_stream_state_t pa_stream_get_state(pa_stream *s) { + assert(s && s->ref >= 1); + return s->state; +} + +pa_context* pa_stream_get_context(pa_stream *s) { + assert(s && s->ref >= 1); + return s->context; +} + +uint32_t pa_stream_get_index(pa_stream *s) { + assert(s && s->ref >= 1); + return s->device_index; +} + +void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { + assert(s && s->ref >= 1); + + if (s->state == st) + return; + + pa_stream_ref(s); + + s->state = st; + + if ((st == PA_STREAM_FAILED || st == PA_STREAM_TERMINATED) && s->context) { + if (s->channel_valid) + pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); + + PA_LLIST_REMOVE(pa_stream, s->context->streams, s); + pa_stream_unref(s); + } + + if (s->state_callback) + s->state_callback(s, s->state_userdata); + + pa_stream_unref(s); +} + +void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_context *c = userdata; + pa_stream *s; + uint32_t channel; + assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); + + pa_context_ref(c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(c, PA_ERROR_PROTOCOL); + goto finish; + } + + if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) + goto finish; + + c->error = PA_ERROR_KILLED; + pa_stream_set_state(s, PA_STREAM_FAILED); + +finish: + pa_context_unref(c); +} + +void pa_command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_stream *s; + pa_context *c = userdata; + uint32_t bytes, channel; + assert(pd && command == PA_COMMAND_REQUEST && t && c); + + pa_context_ref(c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + pa_tagstruct_getu32(t, &bytes) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(c, PA_ERROR_PROTOCOL); + goto finish; + } + + if (!(s = pa_dynarray_get(c->playback_streams, channel))) + goto finish; + + if (s->state != PA_STREAM_READY) + goto finish; + + pa_stream_ref(s); + + s->requested_bytes += bytes; + + if (s->requested_bytes && s->write_callback) + s->write_callback(s, s->requested_bytes, s->write_userdata); + + pa_stream_unref(s); + +finish: + pa_context_unref(c); +} + +static void ipol_callback(pa_mainloop_api *m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + struct timeval tv2; + pa_stream *s = userdata; + + pa_stream_ref(s); + +/* pa_log("requesting new ipol data\n"); */ + + if (s->state == PA_STREAM_READY && !s->ipol_requested) { + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + s->ipol_requested = 1; + } + + pa_gettimeofday(&tv2); + pa_timeval_add(&tv2, LATENCY_IPOL_INTERVAL_USEC); + + m->time_restart(e, &tv2); + + pa_stream_unref(s); +} + + +void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_stream *s = userdata; + assert(pd && s && s->state == PA_STREAM_CREATING); + + pa_stream_ref(s); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(s->context, command, t) < 0) + goto finish; + + pa_stream_set_state(s, PA_STREAM_FAILED); + goto finish; + } + + if (pa_tagstruct_getu32(t, &s->channel) < 0 || + ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || + ((s->direction != PA_STREAM_RECORD) && pa_tagstruct_getu32(t, &s->requested_bytes) < 0) || + !pa_tagstruct_eof(t)) { + pa_context_fail(s->context, PA_ERROR_PROTOCOL); + goto finish; + } + + s->channel_valid = 1; + pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); + pa_stream_set_state(s, PA_STREAM_READY); + + if (s->interpolate) { + struct timeval tv; + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + + pa_gettimeofday(&tv); + tv.tv_usec += LATENCY_IPOL_INTERVAL_USEC; /* every 100 ms */ + + assert(!s->ipol_event); + s->ipol_event = s->mainloop->time_new(s->mainloop, &tv, &ipol_callback, s); + } + + if (s->requested_bytes && s->ref > 1 && s->write_callback) + s->write_callback(s, s->requested_bytes, s->write_userdata); + +finish: + pa_stream_unref(s); +} + +static void create_stream(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags, const pa_cvolume *volume) { + pa_tagstruct *t; + uint32_t tag; + assert(s && s->ref >= 1 && s->state == PA_STREAM_DISCONNECTED); + + pa_stream_ref(s); + + s->interpolate = !!(flags & PA_STREAM_INTERPOLATE_LATENCY); + pa_stream_trash_ipol(s); + + if (attr) + s->buffer_attr = *attr; + else { + /* half a second */ + s->buffer_attr.tlength = pa_bytes_per_second(&s->sample_spec)/2; + s->buffer_attr.maxlength = (s->buffer_attr.tlength*3)/2; + s->buffer_attr.minreq = s->buffer_attr.tlength/100; + s->buffer_attr.prebuf = s->buffer_attr.tlength - s->buffer_attr.minreq; + s->buffer_attr.fragsize = s->buffer_attr.tlength/100; + } + + pa_stream_set_state(s, PA_STREAM_CREATING); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + if (!dev) { + if (s->direction == PA_STREAM_PLAYBACK) + dev = s->context->conf->default_sink; + else + dev = s->context->conf->default_source; + } + + pa_tagstruct_put(t, + PA_TAG_U32, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM, + PA_TAG_U32, tag = s->context->ctag++, + PA_TAG_STRING, s->name, + PA_TAG_SAMPLE_SPEC, &s->sample_spec, + PA_TAG_CHANNEL_MAP, &s->channel_map, + PA_TAG_U32, PA_INVALID_INDEX, + PA_TAG_STRING, dev, + PA_TAG_U32, s->buffer_attr.maxlength, + PA_TAG_BOOLEAN, !!(flags & PA_STREAM_START_CORKED), + PA_TAG_INVALID); + + if (s->direction == PA_STREAM_PLAYBACK) { + pa_cvolume cv; + pa_tagstruct_put(t, + PA_TAG_U32, s->buffer_attr.tlength, + PA_TAG_U32, s->buffer_attr.prebuf, + PA_TAG_U32, s->buffer_attr.minreq, + PA_TAG_INVALID); + + if (!volume) { + pa_cvolume_reset(&cv, s->sample_spec.channels); + volume = &cv; + } + + pa_tagstruct_put_cvolume(t, volume); + } else + pa_tagstruct_putu32(t, s->buffer_attr.fragsize); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s); + + pa_stream_unref(s); +} + +void pa_stream_connect_playback(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags, pa_cvolume *volume) { + assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); + s->direction = PA_STREAM_PLAYBACK; + create_stream(s, dev, attr, flags, volume); +} + +void pa_stream_connect_record(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags) { + assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); + s->direction = PA_STREAM_RECORD; + create_stream(s, dev, attr, flags, 0); +} + +void pa_stream_write(pa_stream *s, const void *data, size_t length, void (*free_cb)(void *p), size_t delta) { + pa_memchunk chunk; + assert(s && s->context && data && length && s->state == PA_STREAM_READY && s->ref >= 1); + + if (free_cb) { + chunk.memblock = pa_memblock_new_user((void*) data, length, free_cb, 1, s->context->memblock_stat); + assert(chunk.memblock && chunk.memblock->data); + } else { + chunk.memblock = pa_memblock_new(length, s->context->memblock_stat); + assert(chunk.memblock && chunk.memblock->data); + memcpy(chunk.memblock->data, data, length); + } + chunk.index = 0; + chunk.length = length; + + pa_pstream_send_memblock(s->context->pstream, s->channel, delta, &chunk); + pa_memblock_unref(chunk.memblock); + + if (length < s->requested_bytes) + s->requested_bytes -= length; + else + s->requested_bytes = 0; + + s->counter += length; +} + +size_t pa_stream_writable_size(pa_stream *s) { + assert(s && s->ref >= 1); + return s->state == PA_STREAM_READY ? s->requested_bytes : 0; +} + +pa_operation * pa_stream_drain(pa_stream *s, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); + + o = pa_operation_new(s->context, s); + assert(o); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +static void stream_get_latency_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + pa_latency_info i, *p = NULL; + struct timeval local, remote, now; + assert(pd && o && o->stream && o->context); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + } else if (pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || + pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || + pa_tagstruct_get_usec(t, &i.source_usec) < 0 || + pa_tagstruct_get_boolean(t, &i.playing) < 0 || + pa_tagstruct_getu32(t, &i.queue_length) < 0 || + pa_tagstruct_get_timeval(t, &local) < 0 || + pa_tagstruct_get_timeval(t, &remote) < 0 || + pa_tagstruct_getu64(t, &i.counter) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } else { + pa_gettimeofday(&now); + + if (pa_timeval_cmp(&local, &remote) <= 0 && pa_timeval_cmp(&remote, &now) <= 0) { + /* local and remote seem to have synchronized clocks */ + + if (o->stream->direction == PA_STREAM_PLAYBACK) + i.transport_usec = pa_timeval_diff(&remote, &local); + else + i.transport_usec = pa_timeval_diff(&now, &remote); + + i.synchronized_clocks = 1; + i.timestamp = remote; + } else { + /* clocks are not synchronized, let's estimate latency then */ + i.transport_usec = pa_timeval_diff(&now, &local)/2; + i.synchronized_clocks = 0; + i.timestamp = local; + pa_timeval_add(&i.timestamp, i.transport_usec); + } + + if (o->stream->interpolate) { +/* pa_log("new interpol data\n"); */ + o->stream->ipol_timestamp = i.timestamp; + o->stream->ipol_usec = pa_stream_get_time(o->stream, &i); + o->stream->ipol_requested = 0; + } + + p = &i; + } + + if (o->callback) { + void (*cb)(pa_stream *s, const pa_latency_info *_i, void *_userdata) = (void (*)(pa_stream *s, const pa_latency_info *_i, void *_userdata)) o->callback; + cb(o->stream, p, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_stream_get_latency_info(pa_stream *s, void (*cb)(pa_stream *p, const pa_latency_info*i, void *userdata), void *userdata) { + uint32_t tag; + pa_operation *o; + pa_tagstruct *t; + struct timeval now; + assert(s && s->direction != PA_STREAM_UPLOAD); + + o = pa_operation_new(s->context, s); + assert(o); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_GET_PLAYBACK_LATENCY : PA_COMMAND_GET_RECORD_LATENCY); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + + pa_gettimeofday(&now); + pa_tagstruct_put_timeval(t, &now); + pa_tagstruct_putu64(t, s->counter); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_info_callback, o); + + return pa_operation_ref(o); +} + +void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_stream *s = userdata; + assert(pd && s && s->ref >= 1); + + pa_stream_ref(s); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(s->context, command, t) < 0) + goto finish; + + pa_stream_set_state(s, PA_STREAM_FAILED); + goto finish; + } else if (!pa_tagstruct_eof(t)) { + pa_context_fail(s->context, PA_ERROR_PROTOCOL); + goto finish; + } + + pa_stream_set_state(s, PA_STREAM_TERMINATED); + +finish: + pa_stream_unref(s); +} + +void pa_stream_disconnect(pa_stream *s) { + pa_tagstruct *t; + uint32_t tag; + assert(s && s->ref >= 1); + + if (!s->channel_valid || !s->context->state == PA_CONTEXT_READY) + return; + + pa_stream_ref(s); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : + (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s); + + pa_stream_unref(s); +} + +void pa_stream_set_read_callback(pa_stream *s, void (*cb)(pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { + assert(s && s->ref >= 1); + s->read_callback = cb; + s->read_userdata = userdata; +} + +void pa_stream_set_write_callback(pa_stream *s, void (*cb)(pa_stream *p, size_t length, void *userdata), void *userdata) { + assert(s && s->ref >= 1); + s->write_callback = cb; + s->write_userdata = userdata; +} + +void pa_stream_set_state_callback(pa_stream *s, void (*cb)(pa_stream *s, void *userdata), void *userdata) { + assert(s && s->ref >= 1); + s->state_callback = cb; + s->state_userdata = userdata; +} + +void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int success = 1; + assert(pd && o && o->context && o->ref >= 1); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + success = 0; + } else if (!pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(pa_stream *s, int _success, void *_userdata) = (void (*)(pa_stream *s, int _success, void *_userdata)) o->callback; + cb(o->stream, success, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_stream_cork(pa_stream *s, int b, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); + + if (s->interpolate) { + if (!s->corked && b) + /* Pausing */ + s->ipol_usec = pa_stream_get_interpolated_time(s); + else if (s->corked && !b) + /* Unpausing */ + pa_gettimeofday(&s->ipol_timestamp); + } + + s->corked = b; + + o = pa_operation_new(s->context, s); + assert(o); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CORK_PLAYBACK_STREAM : PA_COMMAND_CORK_RECORD_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_tagstruct_put_boolean(t, !!b); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); + + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + + return pa_operation_ref(o); +} + +static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); + + o = pa_operation_new(s->context, s); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, command); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +pa_operation* pa_stream_flush(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { + pa_operation *o; + o = stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata); + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + return o; +} + +pa_operation* pa_stream_prebuf(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { + pa_operation *o; + o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata); + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + return o; +} + +pa_operation* pa_stream_trigger(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { + pa_operation *o; + o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata); + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + return o; +} + +pa_operation* pa_stream_set_name(pa_stream *s, const char *name, void(*cb)(pa_stream*c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(s && s->ref >= 1 && s->state == PA_STREAM_READY && name && s->direction != PA_STREAM_UPLOAD); + + o = pa_operation_new(s->context, s); + assert(o); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, s->direction == PA_STREAM_RECORD ? PA_COMMAND_SET_RECORD_STREAM_NAME : PA_COMMAND_SET_PLAYBACK_STREAM_NAME); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +uint64_t pa_stream_get_counter(pa_stream *s) { + assert(s); + return s->counter; +} + +pa_usec_t pa_stream_get_time(pa_stream *s, const pa_latency_info *i) { + pa_usec_t usec; + assert(s); + + usec = pa_bytes_to_usec(i->counter, &s->sample_spec); + + if (i) { + if (s->direction == PA_STREAM_PLAYBACK) { + pa_usec_t latency = i->transport_usec + i->buffer_usec + i->sink_usec; + if (usec < latency) + usec = 0; + else + usec -= latency; + + } else if (s->direction == PA_STREAM_RECORD) { + usec += i->source_usec + i->buffer_usec + i->transport_usec; + + if (usec > i->sink_usec) + usec -= i->sink_usec; + else + usec = 0; + } + } + + if (usec < s->previous_time) + usec = s->previous_time; + + s->previous_time = usec; + + return usec; +} + +static pa_usec_t time_counter_diff(pa_stream *s, pa_usec_t t, pa_usec_t c, int *negative) { + assert(s); + + if (negative) + *negative = 0; + + if (c < t) { + if (s->direction == PA_STREAM_RECORD) { + if (negative) + *negative = 1; + + return t-c; + } else + return 0; + } else + return c-t; +} + +pa_usec_t pa_stream_get_latency(pa_stream *s, const pa_latency_info *i, int *negative) { + pa_usec_t t, c; + assert(s && i); + + t = pa_stream_get_time(s, i); + c = pa_bytes_to_usec(s->counter, &s->sample_spec); + + return time_counter_diff(s, t, c, negative); +} + +const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) { + assert(s); + return &s->sample_spec; +} + +void pa_stream_trash_ipol(pa_stream *s) { + assert(s); + + if (!s->interpolate) + return; + + memset(&s->ipol_timestamp, 0, sizeof(s->ipol_timestamp)); + s->ipol_usec = 0; +} + +pa_usec_t pa_stream_get_interpolated_time(pa_stream *s) { + pa_usec_t usec; + assert(s && s->interpolate); + + if (s->corked) + usec = s->ipol_usec; + else { + if (s->ipol_timestamp.tv_sec == 0) + usec = 0; + else + usec = s->ipol_usec + pa_timeval_age(&s->ipol_timestamp); + } + + if (usec < s->previous_ipol_time) + usec = s->previous_ipol_time; + + s->previous_ipol_time = usec; + + return usec; +} + +pa_usec_t pa_stream_get_interpolated_latency(pa_stream *s, int *negative) { + pa_usec_t t, c; + assert(s && s->interpolate); + + t = pa_stream_get_interpolated_time(s); + c = pa_bytes_to_usec(s->counter, &s->sample_spec); + return time_counter_diff(s, t, c, negative); +} diff --git a/src/polyp/stream.h b/src/polyp/stream.h new file mode 100644 index 00000000..d8409b3b --- /dev/null +++ b/src/polyp/stream.h @@ -0,0 +1,181 @@ +#ifndef foopolyplibstreamhfoo +#define foopolyplibstreamhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include +#include +#include +#include +#include + +/** \file + * Audio streams for input, output and sample upload */ + +PA_C_DECL_BEGIN + +/** \pa_stream + * An opaque stream for playback or recording */ +typedef struct pa_stream pa_stream; + +/** Create a new, unconnected stream with the specified name and sample type */ +pa_stream* pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map); + +/** Decrease the reference counter by one */ +void pa_stream_unref(pa_stream *s); + +/** Increase the reference counter by one */ +pa_stream *pa_stream_ref(pa_stream *s); + +/** Return the current state of the stream */ +pa_stream_state_t pa_stream_get_state(pa_stream *p); + +/** Return the context this stream is attached to */ +pa_context* pa_stream_get_context(pa_stream *p); + +/** Return the device (sink input or source output) index this stream is connected to */ +uint32_t pa_stream_get_index(pa_stream *s); + +/** Connect the stream to a sink */ +void pa_stream_connect_playback( + pa_stream *s, + const char *dev, + const pa_buffer_attr *attr, + pa_stream_flags_t flags, + pa_cvolume *volume); + +/** Connect the stream to a source */ +void pa_stream_connect_record( + pa_stream *s, + const char *dev, + const pa_buffer_attr *attr, + pa_stream_flags_t flags); + +/** Disconnect a stream from a source/sink */ +void pa_stream_disconnect(pa_stream *s); + +/** Write some data to the server (for playback sinks), if free_cb is + * non-NULL this routine is called when all data has been written out + * and an internal reference to the specified data is kept, the data + * is not copied. If NULL, the data is copied into an internal + * buffer. */ +void pa_stream_write(pa_stream *p /**< The stream to use */, + const void *data /**< The data to write */, + size_t length /**< The length of the data to write */, + void (*free_cb)(void *p) /**< A cleanup routine for the data or NULL to request an internal copy */, + size_t delta /**< Drop this many + bytes in the playback + buffer before writing + this data. Use + (size_t) -1 for + clearing the whole + playback + buffer. Normally you + will specify 0 here, + i.e. append to the + playback buffer. If + the value given here + is greater than the + buffered data length + the buffer is cleared + and the data is + written to the + buffer's start. This + value is ignored on + upload streams. */); + +/** Return the amount of bytes that may be written using pa_stream_write() */ +size_t pa_stream_writable_size(pa_stream *p); + +/** Drain a playback stream */ +pa_operation* pa_stream_drain(pa_stream *s, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata); + +/** Get the playback latency of a stream */ +pa_operation* pa_stream_get_latency_info(pa_stream *p, void (*cb)(pa_stream *p, const pa_latency_info *i, void *userdata), void *userdata); + +/** Set the callback function that is called whenever the state of the stream changes */ +void pa_stream_set_state_callback(pa_stream *s, void (*cb)(pa_stream *s, void *userdata), void *userdata); + +/** Set the callback function that is called when new data may be + * written to the stream. */ +void pa_stream_set_write_callback(pa_stream *p, void (*cb)(pa_stream *p, size_t length, void *userdata), void *userdata); + +/** Set the callback function that is called when new data is available from the stream */ +void pa_stream_set_read_callback(pa_stream *p, void (*cb)(pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); + +/** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. \since 0.3 */ +pa_operation* pa_stream_cork(pa_stream *s, int b, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata); + +/** Flush the playback buffer of this stream. Most of the time you're + * better off using the parameter delta of pa_stream_write() instead of this + * function. Available on both playback and recording streams. \since 0.3 */ +pa_operation* pa_stream_flush(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata); + +/** Reenable prebuffering. Available for playback streams only. \since 0.6 */ +pa_operation* pa_stream_prebuf(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata); + +/** Request immediate start of playback on this stream. This disables + * prebuffering as specified in the pa_buffer_attr structure. Available for playback streams only. \since + * 0.3 */ +pa_operation* pa_stream_trigger(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata); + +/** Rename the stream. \since 0.5 */ +pa_operation* pa_stream_set_name(pa_stream *s, const char *name, void(*cb)(pa_stream*c, int success, void *userdata), void *userdata); + +/** Return the total number of bytes written to/read from the + * stream. This counter is not reset on pa_stream_flush(), you may do + * this yourself using pa_stream_reset_counter(). \since 0.6 */ +uint64_t pa_stream_get_counter(pa_stream *s); + +/** Return the current playback/recording time. This is based on the + * counter accessible with pa_stream_get_counter(). This function + * requires a pa_latency_info structure as argument, which should be + * acquired using pa_stream_get_latency(). \since 0.6 */ +pa_usec_t pa_stream_get_time(pa_stream *s, const pa_latency_info *i); + +/** Return the total stream latency. Thus function requires a + * pa_latency_info structure as argument, which should be aquired + * using pa_stream_get_latency(). In case the stream is a monitoring + * stream the result can be negative, i.e. the captured samples are + * not yet played. In this case *negative is set to 1. \since 0.6 */ +pa_usec_t pa_stream_get_latency(pa_stream *s, const pa_latency_info *i, int *negative); + +/** Return the interpolated playback/recording time. Requires the + * PA_STREAM_INTERPOLATE_LATENCY bit set when creating the stream. In + * contrast to pa_stream_get_latency() this function doesn't require + * a whole roundtrip for response. \since 0.6 */ +pa_usec_t pa_stream_get_interpolated_time(pa_stream *s); + +/** Return the interpolated playback/recording latency. Requires the + * PA_STREAM_INTERPOLATE_LATENCY bit set when creating the + * stream. \since 0.6 */ +pa_usec_t pa_stream_get_interpolated_latency(pa_stream *s, int *negative); + +/** Return a pointer to the streams sample specification. \since 0.6 */ +const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/subscribe.c b/src/polyp/subscribe.c new file mode 100644 index 00000000..c481f525 --- /dev/null +++ b/src/polyp/subscribe.c @@ -0,0 +1,81 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "subscribe.h" +#include "internal.h" +#include +#include + +void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_context *c = userdata; + pa_subscription_event_type_t e; + uint32_t index; + assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); + + pa_context_ref(c); + + if (pa_tagstruct_getu32(t, &e) < 0 || + pa_tagstruct_getu32(t, &index) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(c, PA_ERROR_PROTOCOL); + goto finish; + } + + if (c->subscribe_callback) + c->subscribe_callback(c, e, index, c->subscribe_userdata); + +finish: + pa_context_unref(c); +} + + +pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + assert(c); + + o = pa_operation_new(c, NULL); + o->callback = (pa_operation_callback) cb; + o->userdata = userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, m); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + + return pa_operation_ref(o); +} + +void pa_context_set_subscribe_callback(pa_context *c, void (*cb)(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata) { + assert(c); + c->subscribe_callback = cb; + c->subscribe_userdata = userdata; +} diff --git a/src/polyp/subscribe.h b/src/polyp/subscribe.h new file mode 100644 index 00000000..4986272d --- /dev/null +++ b/src/polyp/subscribe.h @@ -0,0 +1,47 @@ +#ifndef foopolyplibsubscribehfoo +#define foopolyplibsubscribehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include +#include + +/** \file + * Daemon introspection event subscription subsystem. Use this + * to be notified whenever the internal layout of daemon changes: + * i.e. entities such as sinks or sources are create, removed or + * modified. */ + +PA_C_DECL_BEGIN + +/** Enable event notification */ +pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); + +/** Set the context specific call back function that is called whenever the state of the daemon changes */ +void pa_context_set_subscribe_callback(pa_context *c, void (*cb)(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/version.h.in b/src/polyp/version.h.in new file mode 100644 index 00000000..36cafb70 --- /dev/null +++ b/src/polyp/version.h.in @@ -0,0 +1,47 @@ +#ifndef foopolyplibversionhfoo /*-*-C-*-*/ +#define foopolyplibversionhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* WARNING: Make sure to edit the real source file version.h.in! */ + +/** \file + * Define header version */ + +PA_C_DECL_BEGIN + +/** Return the version of the header files. Keep in mind that this is +a macro and not a function, so it is impossible to get the pointer of +it. */ +#define pa_get_headers_version() ("@PACKAGE_VERSION@") + +/** Return the version of the library the current application is linked to. */ +const char* pa_get_library_version(void); + +/** The current API version. Version 6 relates to polypaudio + * 0.6. Prior versions (i.e. Polypaudio 0.5.1 and older) have + * PA_API_VERSION undefined. */ +#define PA_API_VERSION @PA_API_VERSION@ + +PA_C_DECL_END + +#endif diff --git a/src/polypcore/native-common.h b/src/polypcore/native-common.h index 78ae721e..ac3ea823 100644 --- a/src/polypcore/native-common.h +++ b/src/polypcore/native-common.h @@ -23,7 +23,7 @@ ***/ #include -#include +#include PA_C_DECL_BEGIN diff --git a/src/polypcore/sink.c b/src/polypcore/sink.c index 411befe7..f29afba7 100644 --- a/src/polypcore/sink.c +++ b/src/polypcore/sink.c @@ -36,7 +36,7 @@ #include "xmalloc.h" #include "subscribe.h" #include "log.h" -#include +#include #define MAX_MIX_CHANNELS 32 diff --git a/src/tests/pacat-simple.c b/src/tests/pacat-simple.c index 8b3a7b22..0382ec06 100644 --- a/src/tests/pacat-simple.c +++ b/src/tests/pacat-simple.c @@ -28,8 +28,8 @@ #include #include -#include -#include +#include +#include #include #define BUFSIZE 1024 diff --git a/src/tests/parec-simple.c b/src/tests/parec-simple.c index 10eaea8d..fc2314ac 100644 --- a/src/tests/parec-simple.c +++ b/src/tests/parec-simple.c @@ -28,8 +28,8 @@ #include #include -#include -#include +#include +#include #include #define BUFSIZE 1024 diff --git a/src/utils/pabrowse.c b/src/utils/pabrowse.c index 634c308a..290531e6 100644 --- a/src/utils/pabrowse.c +++ b/src/utils/pabrowse.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { diff --git a/src/utils/pacat.c b/src/utils/pacat.c index bd2b64fd..a4f3d3af 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -33,10 +33,10 @@ #include #include -#include +#include #include #include -#include +#include #if PA_API_VERSION != 8 #error Invalid Polypaudio API version diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 23bd924b..7d903eb8 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -36,7 +36,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/utils/paplay.c b/src/utils/paplay.c index ddc1cbc1..1b3697fa 100644 --- a/src/utils/paplay.c +++ b/src/utils/paplay.c @@ -35,10 +35,10 @@ #include #include -#include +#include #include #include -#include +#include #if PA_API_VERSION != 8 #error Invalid Polypaudio API version -- cgit From 45b1eeec6b3fa829dc08e61449105ca93566c4a0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Feb 2006 23:10:33 +0000 Subject: fix compilation of simple API git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@493 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/simple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polyp/simple.c b/src/polyp/simple.c index 6f20da89..19c49c9b 100644 --- a/src/polyp/simple.c +++ b/src/polyp/simple.c @@ -29,7 +29,7 @@ #include #include "simple.h" -#include "polyplib.h" +#include "polypaudio.h" #include "mainloop.h" #include #include -- cgit From 19b5b71feb51544a442b71af725d26aae2c55527 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Feb 2006 23:11:28 +0000 Subject: * drop polylib prefix from #define * include error.h from polypaudio.h git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@494 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/browser.h | 4 ++-- src/polyp/context.h | 4 ++-- src/polyp/def.h | 4 ++-- src/polyp/error.h | 4 ++-- src/polyp/internal.h | 4 ++-- src/polyp/introspect.h | 4 ++-- src/polyp/operation.h | 4 ++-- src/polyp/polypaudio.h | 7 ++++--- src/polyp/scache.h | 4 ++-- src/polyp/simple.h | 4 ++-- src/polyp/stream.h | 4 ++-- src/polyp/subscribe.h | 4 ++-- src/polyp/version.h.in | 4 ++-- 13 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/polyp/browser.h b/src/polyp/browser.h index 853304d7..3bb0d264 100644 --- a/src/polyp/browser.h +++ b/src/polyp/browser.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibbrowserhfoo -#define foopolyplibbrowserhfoo +#ifndef foobrowserhfoo +#define foobrowserhfoo /* $Id$ */ diff --git a/src/polyp/context.h b/src/polyp/context.h index 6496c703..216d7d87 100644 --- a/src/polyp/context.h +++ b/src/polyp/context.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibcontexthfoo -#define foopolyplibcontexthfoo +#ifndef foocontexthfoo +#define foocontexthfoo /* $Id$ */ diff --git a/src/polyp/def.h b/src/polyp/def.h index 0591ce6c..ba35b31e 100644 --- a/src/polyp/def.h +++ b/src/polyp/def.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibdefhfoo -#define foopolyplibdefhfoo +#ifndef foodefhfoo +#define foodefhfoo /* $Id$ */ diff --git a/src/polyp/error.h b/src/polyp/error.h index 1bb97822..ff2507b2 100644 --- a/src/polyp/error.h +++ b/src/polyp/error.h @@ -1,5 +1,5 @@ -#ifndef foopolypliberrorhfoo -#define foopolypliberrorhfoo +#ifndef fooerrorhfoo +#define fooerrorhfoo /* $Id$ */ diff --git a/src/polyp/internal.h b/src/polyp/internal.h index feb9f6f4..bdfd5d8e 100644 --- a/src/polyp/internal.h +++ b/src/polyp/internal.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibinternalhfoo -#define foopolyplibinternalhfoo +#ifndef foointernalhfoo +#define foointernalhfoo /* $Id$ */ diff --git a/src/polyp/introspect.h b/src/polyp/introspect.h index 75dc027f..0abb54cf 100644 --- a/src/polyp/introspect.h +++ b/src/polyp/introspect.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibintrospecthfoo -#define foopolyplibintrospecthfoo +#ifndef foointrospecthfoo +#define foointrospecthfoo /* $Id$ */ diff --git a/src/polyp/operation.h b/src/polyp/operation.h index fea82f10..6a24d649 100644 --- a/src/polyp/operation.h +++ b/src/polyp/operation.h @@ -1,5 +1,5 @@ -#ifndef foopolypliboperationhfoo -#define foopolypliboperationhfoo +#ifndef foooperationhfoo +#define foooperationhfoo /* $Id$ */ diff --git a/src/polyp/polypaudio.h b/src/polyp/polypaudio.h index 23208526..c6014bbb 100644 --- a/src/polyp/polypaudio.h +++ b/src/polyp/polypaudio.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo +#ifndef foopolypaudiohfoo +#define foopolypaudiohfoo /* $Id$ */ @@ -32,11 +32,12 @@ #include #include #include +#include /** \file * Include all polyplib header file at once. The following files are included: \ref mainloop-api.h, \ref sample.h, * \ref def.h, \ref context.h, \ref stream.h, - * \ref introspect.h, \ref subscribe.h and \ref scache.h \ref version.h + * \ref introspect.h, \ref subscribe.h, \ref scache.h, \ref version.h \ref error.h * at once */ /** \mainpage diff --git a/src/polyp/scache.h b/src/polyp/scache.h index 41b956d2..5bf004d0 100644 --- a/src/polyp/scache.h +++ b/src/polyp/scache.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibscachehfoo -#define foopolyplibscachehfoo +#ifndef fooscachehfoo +#define fooscachehfoo /* $Id$ */ diff --git a/src/polyp/simple.h b/src/polyp/simple.h index 31dcaef4..270cbb24 100644 --- a/src/polyp/simple.h +++ b/src/polyp/simple.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibsimplehfoo -#define foopolyplibsimplehfoo +#ifndef foosimplehfoo +#define foosimplehfoo /* $Id$ */ diff --git a/src/polyp/stream.h b/src/polyp/stream.h index d8409b3b..e2cab19e 100644 --- a/src/polyp/stream.h +++ b/src/polyp/stream.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibstreamhfoo -#define foopolyplibstreamhfoo +#ifndef foostreamhfoo +#define foostreamhfoo /* $Id$ */ diff --git a/src/polyp/subscribe.h b/src/polyp/subscribe.h index 4986272d..f1f0642d 100644 --- a/src/polyp/subscribe.h +++ b/src/polyp/subscribe.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibsubscribehfoo -#define foopolyplibsubscribehfoo +#ifndef foosubscribehfoo +#define foosubscribehfoo /* $Id$ */ diff --git a/src/polyp/version.h.in b/src/polyp/version.h.in index 36cafb70..c727381f 100644 --- a/src/polyp/version.h.in +++ b/src/polyp/version.h.in @@ -1,5 +1,5 @@ -#ifndef foopolyplibversionhfoo /*-*-C-*-*/ -#define foopolyplibversionhfoo +#ifndef fooversionhfoo /*-*-C-*-*/ +#define fooversionhfoo /* $Id$ */ -- cgit From b4cb249d704cbb0458640526a07e1f541b899d3e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Feb 2006 23:12:10 +0000 Subject: shorten include list of utils a little git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@495 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pabrowse.c | 1 - src/utils/pacat.c | 4 +--- src/utils/pactl.c | 4 +--- src/utils/paplay.c | 4 +--- src/utils/pax11publish.c | 2 +- 5 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/utils/pabrowse.c b/src/utils/pabrowse.c index 290531e6..344e3281 100644 --- a/src/utils/pabrowse.c +++ b/src/utils/pabrowse.c @@ -30,7 +30,6 @@ #include #include #include -#include static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { fprintf(stderr, "Got signal, exiting\n"); diff --git a/src/utils/pacat.c b/src/utils/pacat.c index a4f3d3af..3c50402f 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -32,11 +32,9 @@ #include #include -#include -#include +#include #include #include -#include #if PA_API_VERSION != 8 #error Invalid Polypaudio API version diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 7d903eb8..4c22c925 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -35,11 +35,9 @@ #include -#include -#include +#include #include #include -#include #if PA_API_VERSION != 8 #error Invalid Polypaudio API version diff --git a/src/utils/paplay.c b/src/utils/paplay.c index 1b3697fa..9f73b834 100644 --- a/src/utils/paplay.c +++ b/src/utils/paplay.c @@ -34,11 +34,9 @@ #include -#include -#include +#include #include #include -#include #if PA_API_VERSION != 8 #error Invalid Polypaudio API version diff --git a/src/utils/pax11publish.c b/src/utils/pax11publish.c index 63ee4821..908a3507 100644 --- a/src/utils/pax11publish.c +++ b/src/utils/pax11publish.c @@ -35,8 +35,8 @@ #include #include #include -#include #include +#include int main(int argc, char *argv[]) { const char *dname = NULL, *sink = NULL, *source = NULL, *server = NULL, *cookie_file = PA_NATIVE_COOKIE_FILE; -- cgit From 5ccf4145bcf1760d30962c32f0f4749047c6cae8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Feb 2006 23:13:27 +0000 Subject: * rename polypcore/subscribe.[ch] to polypcore/core-subscribe.[ch] to avoid confusion with polyp/subscribe.[ch] * same for scache.[ch] git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@496 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 4 +- src/modules/module-match.c | 2 +- src/modules/module-tunnel.c | 2 +- src/modules/module-x11-bell.c | 2 +- src/modules/module-x11-publish.c | 2 +- src/polypcore/autoload.c | 4 +- src/polypcore/cli-command.c | 2 +- src/polypcore/cli-text.c | 2 +- src/polypcore/client.c | 2 +- src/polypcore/core-scache.c | 392 +++++++++++++++++++++++++++++++++++++++ src/polypcore/core-scache.h | 62 +++++++ src/polypcore/core-subscribe.c | 230 +++++++++++++++++++++++ src/polypcore/core-subscribe.h | 37 ++++ src/polypcore/core.c | 4 +- src/polypcore/core.h | 2 +- src/polypcore/module.c | 2 +- src/polypcore/namereg.c | 2 +- src/polypcore/protocol-esound.c | 2 +- src/polypcore/protocol-native.c | 4 +- src/polypcore/scache.c | 392 --------------------------------------- src/polypcore/scache.h | 62 ------- src/polypcore/sink-input.c | 2 +- src/polypcore/sink.c | 2 +- src/polypcore/source-output.c | 2 +- src/polypcore/source.c | 2 +- src/polypcore/subscribe.c | 230 ----------------------- src/polypcore/subscribe.h | 37 ---- 27 files changed, 744 insertions(+), 744 deletions(-) create mode 100644 src/polypcore/core-scache.c create mode 100644 src/polypcore/core-scache.h create mode 100644 src/polypcore/core-subscribe.c create mode 100644 src/polypcore/core-subscribe.h delete mode 100644 src/polypcore/scache.c delete mode 100644 src/polypcore/scache.h delete mode 100644 src/polypcore/subscribe.c delete mode 100644 src/polypcore/subscribe.h diff --git a/src/Makefile.am b/src/Makefile.am index cfd4b751..7d87a119 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -479,7 +479,7 @@ libpolypcore_la_SOURCES += \ polypcore/random.c polypcore/random.h \ polypcore/resampler.c polypcore/resampler.h \ polypcore/sample-util.c polypcore/sample-util.h \ - polypcore/scache.c polypcore/scache.h \ + polypcore/core-scache.c polypcore/core-scache.h \ polypcore/sconv.c polypcore/sconv.h \ polypcore/sconv-s16be.c polypcore/sconv-s16be.h \ polypcore/sconv-s16le.c polypcore/sconv-s16le.h \ @@ -491,7 +491,7 @@ libpolypcore_la_SOURCES += \ polypcore/source.c polypcore/source.h \ polypcore/source-output.c polypcore/source-output.h \ polypcore/strbuf.c polypcore/strbuf.h \ - polypcore/subscribe.c polypcore/subscribe.h \ + polypcore/core-subscribe.c polypcore/core-subscribe.h \ polypcore/tokenizer.c polypcore/tokenizer.h \ polypcore/util.c polypcore/util.h \ polypcore/winsock.h \ diff --git a/src/modules/module-match.c b/src/modules/module-match.c index 10ceb75e..1fb7233c 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 5ee10fda..61b9bb3b 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/modules/module-x11-bell.c b/src/modules/module-x11-bell.c index d722b732..d59f3f59 100644 --- a/src/modules/module-x11-bell.c +++ b/src/modules/module-x11-bell.c @@ -33,7 +33,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c index dca5d049..6d9036f5 100644 --- a/src/modules/module-x11-publish.c +++ b/src/modules/module-x11-publish.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/polypcore/autoload.c b/src/polypcore/autoload.c index ff2916cb..83df8ef7 100644 --- a/src/polypcore/autoload.c +++ b/src/polypcore/autoload.c @@ -33,8 +33,8 @@ #include "memchunk.h" #include "sound-file.h" #include "log.h" -#include "scache.h" -#include "subscribe.h" +#include "core-scache.h" +#include "core-subscribe.h" static void entry_free(pa_autoload_entry *e) { assert(e); diff --git a/src/polypcore/cli-command.c b/src/polypcore/cli-command.c index f6192bf8..dd4cbe46 100644 --- a/src/polypcore/cli-command.c +++ b/src/polypcore/cli-command.c @@ -40,7 +40,7 @@ #include "strbuf.h" #include "namereg.h" #include "cli-text.h" -#include "scache.h" +#include "core-scache.h" #include "sample-util.h" #include "sound-file.h" #include "play-memchunk.h" diff --git a/src/polypcore/cli-text.c b/src/polypcore/cli-text.c index 58248d8e..d8446b06 100644 --- a/src/polypcore/cli-text.c +++ b/src/polypcore/cli-text.c @@ -35,7 +35,7 @@ #include "source-output.h" #include "strbuf.h" #include "sample-util.h" -#include "scache.h" +#include "core-scache.h" #include "autoload.h" #include "xmalloc.h" #include diff --git a/src/polypcore/client.c b/src/polypcore/client.c index 3c2084bf..9b256794 100644 --- a/src/polypcore/client.c +++ b/src/polypcore/client.c @@ -30,7 +30,7 @@ #include "client.h" #include "xmalloc.h" -#include "subscribe.h" +#include "core-subscribe.h" #include "log.h" pa_client *pa_client_new(pa_core *core, const char *name, const char *driver) { diff --git a/src/polypcore/core-scache.c b/src/polypcore/core-scache.c new file mode 100644 index 00000000..0d926aba --- /dev/null +++ b/src/polypcore/core-scache.c @@ -0,0 +1,392 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_GLOB_H +#include +#endif + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include "core-scache.h" +#include "sink-input.h" +#include +#include "sample-util.h" +#include "play-memchunk.h" +#include "xmalloc.h" +#include "core-subscribe.h" +#include "namereg.h" +#include "sound-file.h" +#include "util.h" +#include "log.h" +#include +#include + +#define UNLOAD_POLL_TIME 2 + +static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + pa_core *c = userdata; + struct timeval ntv; + assert(c && c->mainloop == m && c->scache_auto_unload_event == e); + + pa_scache_unload_unused(c); + + pa_gettimeofday(&ntv); + ntv.tv_sec += UNLOAD_POLL_TIME; + m->time_restart(e, &ntv); +} + +static void free_entry(pa_scache_entry *e) { + assert(e); + pa_namereg_unregister(e->core, e->name); + pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_REMOVE, e->index); + pa_xfree(e->name); + pa_xfree(e->filename); + if (e->memchunk.memblock) + pa_memblock_unref(e->memchunk.memblock); + pa_xfree(e); +} + +static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { + pa_scache_entry *e; + assert(c && name); + + if ((e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) { + if (e->memchunk.memblock) + pa_memblock_unref(e->memchunk.memblock); + + pa_xfree(e->filename); + + assert(e->core == c); + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); + } else { + e = pa_xmalloc(sizeof(pa_scache_entry)); + + if (!pa_namereg_register(c, name, PA_NAMEREG_SAMPLE, e, 1)) { + pa_xfree(e); + return NULL; + } + + e->name = pa_xstrdup(name); + e->core = c; + + if (!c->scache) { + c->scache = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + assert(c->scache); + } + + pa_idxset_put(c->scache, e, &e->index); + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_NEW, e->index); + } + + pa_cvolume_reset(&e->volume, PA_CHANNELS_MAX); + e->last_used_time = 0; + e->memchunk.memblock = NULL; + e->memchunk.index = e->memchunk.length = 0; + e->filename = NULL; + e->lazy = 0; + e->last_used_time = 0; + + memset(&e->sample_spec, 0, sizeof(pa_sample_spec)); + + return e; +} + +int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx) { + pa_scache_entry *e; + assert(c && name); + + if (!(e = scache_add_item(c, name))) + return -1; + + if (ss) { + e->sample_spec = *ss; + pa_channel_map_init_auto(&e->channel_map, ss->channels); + } + + if (map) + e->channel_map = *map; + + if (chunk) { + e->memchunk = *chunk; + pa_memblock_ref(e->memchunk.memblock); + } + + if (idx) + *idx = e->index; + + return 0; +} + +int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint32_t *idx) { + pa_sample_spec ss; + pa_memchunk chunk; + int r; + +#ifdef OS_IS_WIN32 + char buf[MAX_PATH]; + + if (ExpandEnvironmentStrings(filename, buf, MAX_PATH)) + filename = buf; +#endif + + if (pa_sound_file_load(filename, &ss, &chunk, c->memblock_stat) < 0) + return -1; + + r = pa_scache_add_item(c, name, &ss, NULL, &chunk, idx); + pa_memblock_unref(chunk.memblock); + + return r; +} + +int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, uint32_t *idx) { + pa_scache_entry *e; + +#ifdef OS_IS_WIN32 + char buf[MAX_PATH]; + + if (ExpandEnvironmentStrings(filename, buf, MAX_PATH)) + filename = buf; +#endif + + assert(c && name); + + if (!(e = scache_add_item(c, name))) + return -1; + + e->lazy = 1; + e->filename = pa_xstrdup(filename); + + if (!c->scache_auto_unload_event) { + struct timeval ntv; + pa_gettimeofday(&ntv); + ntv.tv_sec += UNLOAD_POLL_TIME; + c->scache_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); + } + + if (idx) + *idx = e->index; + + return 0; +} + +int pa_scache_remove_item(pa_core *c, const char *name) { + pa_scache_entry *e; + assert(c && name); + + if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) + return -1; + + if (pa_idxset_remove_by_data(c->scache, e, NULL) != e) + assert(0); + + free_entry(e); + return 0; +} + +static void free_cb(void *p, PA_GCC_UNUSED void *userdata) { + pa_scache_entry *e = p; + assert(e); + free_entry(e); +} + +void pa_scache_free(pa_core *c) { + assert(c); + + if (c->scache) { + pa_idxset_free(c->scache, free_cb, NULL); + c->scache = NULL; + } + + if (c->scache_auto_unload_event) + c->mainloop->time_free(c->scache_auto_unload_event); +} + +int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, const pa_cvolume *volume) { + pa_scache_entry *e; + char *t; + pa_cvolume r; + assert(c && name && sink); + + if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1))) + return -1; + + if (e->lazy && !e->memchunk.memblock) { + if (pa_sound_file_load(e->filename, &e->sample_spec, &e->memchunk, c->memblock_stat) < 0) + return -1; + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); + } + + if (!e->memchunk.memblock) + return -1; + + t = pa_sprintf_malloc("sample:%s", name); + + if (pa_play_memchunk(sink, t, &e->sample_spec, &e->channel_map, &e->memchunk, pa_sw_cvolume_multiply(&r, volume, &e->volume)) < 0) { + free(t); + return -1; + } + + free(t); + + if (e->lazy) + time(&e->last_used_time); + + return 0; +} + +const char * pa_scache_get_name_by_id(pa_core *c, uint32_t id) { + pa_scache_entry *e; + assert(c && id != PA_IDXSET_INVALID); + + if (!c->scache || !(e = pa_idxset_get_by_index(c->scache, id))) + return NULL; + + return e->name; +} + +uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name) { + pa_scache_entry *e; + assert(c && name); + + if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) + return PA_IDXSET_INVALID; + + return e->index; +} + +uint32_t pa_scache_total_size(pa_core *c) { + pa_scache_entry *e; + uint32_t idx, sum = 0; + assert(c); + + if (!c->scache || !pa_idxset_size(c->scache)) + return 0; + + for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) + if (e->memchunk.memblock) + sum += e->memchunk.length; + + return sum; +} + +void pa_scache_unload_unused(pa_core *c) { + pa_scache_entry *e; + time_t now; + uint32_t idx; + assert(c); + + if (!c->scache || !pa_idxset_size(c->scache)) + return; + + time(&now); + + for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) { + + if (!e->lazy || !e->memchunk.memblock) + continue; + + if (e->last_used_time + c->scache_idle_time > now) + continue; + + pa_memblock_unref(e->memchunk.memblock); + e->memchunk.memblock = NULL; + e->memchunk.index = e->memchunk.length = 0; + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); + } +} + +static void add_file(pa_core *c, const char *pathname) { + struct stat st; + const char *e; + + e = pa_path_get_filename(pathname); + + if (stat(pathname, &st) < 0) { + pa_log(__FILE__": stat('%s') failed: %s\n", pathname, strerror(errno)); + return; + } + +#if defined(S_ISREG) && defined(S_ISLNK) + if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) +#endif + pa_scache_add_file_lazy(c, e, pathname, NULL); +} + +int pa_scache_add_directory_lazy(pa_core *c, const char *pathname) { + DIR *dir; + assert(c && pathname); + + /* First try to open this as directory */ + if (!(dir = opendir(pathname))) { +#ifdef HAVE_GLOB_H + glob_t p; + unsigned int i; + /* If that fails, try to open it as shell glob */ + + if (glob(pathname, GLOB_ERR|GLOB_NOSORT, NULL, &p) < 0) { + pa_log(__FILE__": Failed to open directory: %s\n", strerror(errno)); + return -1; + } + + for (i = 0; i < p.gl_pathc; i++) + add_file(c, p.gl_pathv[i]); + + globfree(&p); +#else + return -1; +#endif + } else { + struct dirent *e; + + while ((e = readdir(dir))) { + char p[PATH_MAX]; + + if (e->d_name[0] == '.') + continue; + + snprintf(p, sizeof(p), "%s/%s", pathname, e->d_name); + add_file(c, p); + } + } + + closedir(dir); + return 0; +} diff --git a/src/polypcore/core-scache.h b/src/polypcore/core-scache.h new file mode 100644 index 00000000..0918ebe4 --- /dev/null +++ b/src/polypcore/core-scache.h @@ -0,0 +1,62 @@ +#ifndef foocorescachehfoo +#define foocorescachehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" +#include "memchunk.h" +#include "sink.h" + +typedef struct pa_scache_entry { + pa_core *core; + uint32_t index; + char *name; + + pa_cvolume volume; + pa_sample_spec sample_spec; + pa_channel_map channel_map; + pa_memchunk memchunk; + + char *filename; + + int lazy; + time_t last_used_time; +} pa_scache_entry; + +int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx); +int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint32_t *idx); +int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, uint32_t *idx); + +int pa_scache_add_directory_lazy(pa_core *c, const char *pathname); + +int pa_scache_remove_item(pa_core *c, const char *name); +int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, const pa_cvolume *cvolume); +void pa_scache_free(pa_core *c); + +const char *pa_scache_get_name_by_id(pa_core *c, uint32_t id); +uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name); + +uint32_t pa_scache_total_size(pa_core *c); + +void pa_scache_unload_unused(pa_core *c); + +#endif diff --git a/src/polypcore/core-subscribe.c b/src/polypcore/core-subscribe.c new file mode 100644 index 00000000..2a258604 --- /dev/null +++ b/src/polypcore/core-subscribe.c @@ -0,0 +1,230 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "queue.h" +#include "core-subscribe.h" +#include "xmalloc.h" +#include "log.h" + +/* The subscription subsystem may be used to be notified whenever an + * entity (sink, source, ...) is created or deleted. Modules may + * register a callback function that is called whenever an event + * matching a subscription mask happens. The execution of the callback + * function is postponed to the next main loop iteration, i.e. is not + * called from within the stack frame the entity was created in. */ + +struct pa_subscription { + pa_core *core; + int dead; + void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata); + void *userdata; + pa_subscription_mask_t mask; + + pa_subscription *prev, *next; +}; + +struct pa_subscription_event { + pa_subscription_event_type_t type; + uint32_t index; +}; + +static void sched_event(pa_core *c); + +/* Allocate a new subscription object for the given subscription mask. Use the specified callback function and user data */ +pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata) { + pa_subscription *s; + assert(c); + + s = pa_xmalloc(sizeof(pa_subscription)); + s->core = c; + s->dead = 0; + s->callback = callback; + s->userdata = userdata; + s->mask = m; + + if ((s->next = c->subscriptions)) + s->next->prev = s; + s->prev = NULL; + c->subscriptions = s; + return s; +} + +/* Free a subscription object, effectively marking it for deletion */ +void pa_subscription_free(pa_subscription*s) { + assert(s && !s->dead); + s->dead = 1; + sched_event(s->core); +} + +static void free_item(pa_subscription *s) { + assert(s && s->core); + + if (s->prev) + s->prev->next = s->next; + else + s->core->subscriptions = s->next; + + if (s->next) + s->next->prev = s->prev; + + pa_xfree(s); +} + +/* Free all subscription objects */ +void pa_subscription_free_all(pa_core *c) { + pa_subscription_event *e; + assert(c); + + while (c->subscriptions) + free_item(c->subscriptions); + + if (c->subscription_event_queue) { + while ((e = pa_queue_pop(c->subscription_event_queue))) + pa_xfree(e); + + pa_queue_free(c->subscription_event_queue, NULL, NULL); + c->subscription_event_queue = NULL; + } + + if (c->subscription_defer_event) { + c->mainloop->defer_free(c->subscription_defer_event); + c->subscription_defer_event = NULL; + } +} + +/*static void dump_event(pa_subscription_event*e) { + switch (e->type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { + case PA_SUBSCRIPTION_EVENT_SINK: + pa_log(__FILE__": SINK_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_SOURCE: + pa_log(__FILE__": SOURCE_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_SINK_INPUT: + pa_log(__FILE__": SINK_INPUT_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: + pa_log(__FILE__": SOURCE_OUTPUT_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_MODULE: + pa_log(__FILE__": MODULE_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_CLIENT: + pa_log(__FILE__": CLIENT_EVENT"); + break; + default: + pa_log(__FILE__": OTHER"); + break; + } + + switch (e->type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) { + case PA_SUBSCRIPTION_EVENT_NEW: + pa_log(__FILE__": NEW"); + break; + case PA_SUBSCRIPTION_EVENT_CHANGE: + pa_log(__FILE__": CHANGE"); + break; + case PA_SUBSCRIPTION_EVENT_REMOVE: + pa_log(__FILE__": REMOVE"); + break; + default: + pa_log(__FILE__": OTHER"); + break; + } + + pa_log(__FILE__": %u\n", e->index); +}*/ + +/* Deferred callback for dispatching subscirption events */ +static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) { + pa_core *c = userdata; + pa_subscription *s; + assert(c && c->subscription_defer_event == de && c->mainloop == m); + + c->mainloop->defer_enable(c->subscription_defer_event, 0); + + + /* Dispatch queued events */ + + if (c->subscription_event_queue) { + pa_subscription_event *e; + + while ((e = pa_queue_pop(c->subscription_event_queue))) { + + for (s = c->subscriptions; s; s = s->next) { + + if (!s->dead && pa_subscription_match_flags(s->mask, e->type)) + s->callback(c, e->type, e->index, s->userdata); + } + + pa_xfree(e); + } + } + + /* Remove dead subscriptions */ + + s = c->subscriptions; + while (s) { + pa_subscription *n = s->next; + if (s->dead) + free_item(s); + s = n; + } +} + +/* Schedule an mainloop event so that a pending subscription event is dispatched */ +static void sched_event(pa_core *c) { + assert(c); + + if (!c->subscription_defer_event) { + c->subscription_defer_event = c->mainloop->defer_new(c->mainloop, defer_cb, c); + assert(c->subscription_defer_event); + } + + c->mainloop->defer_enable(c->subscription_defer_event, 1); +} + +/* Append a new subscription event to the subscription event queue and schedule a main loop event */ +void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t index) { + pa_subscription_event *e; + assert(c); + + e = pa_xmalloc(sizeof(pa_subscription_event)); + e->type = t; + e->index = index; + + if (!c->subscription_event_queue) { + c->subscription_event_queue = pa_queue_new(); + assert(c->subscription_event_queue); + } + + pa_queue_push(c->subscription_event_queue, e); + sched_event(c); +} + + diff --git a/src/polypcore/core-subscribe.h b/src/polypcore/core-subscribe.h new file mode 100644 index 00000000..bc9dcba3 --- /dev/null +++ b/src/polypcore/core-subscribe.h @@ -0,0 +1,37 @@ +#ifndef foocoresubscribehfoo +#define foocoresubscribehfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef struct pa_subscription pa_subscription; +typedef struct pa_subscription_event pa_subscription_event; + +#include "core.h" +#include "native-common.h" + +pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata); +void pa_subscription_free(pa_subscription*s); +void pa_subscription_free_all(pa_core *c); + +void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t idx); + +#endif diff --git a/src/polypcore/core.c b/src/polypcore/core.c index 678e8212..9d040e68 100644 --- a/src/polypcore/core.c +++ b/src/polypcore/core.c @@ -34,10 +34,10 @@ #include "source.h" #include "namereg.h" #include "util.h" -#include "scache.h" +#include "core-scache.h" #include "autoload.h" #include "xmalloc.h" -#include "subscribe.h" +#include "core-subscribe.h" #include "props.h" #include "random.h" diff --git a/src/polypcore/core.h b/src/polypcore/core.h index f7a90169..29329025 100644 --- a/src/polypcore/core.h +++ b/src/polypcore/core.h @@ -31,7 +31,7 @@ typedef struct pa_core pa_core; #include "memblock.h" #include "resampler.h" #include "queue.h" -#include "subscribe.h" +#include "core-subscribe.h" /* The core structure of polypaudio. Every polypaudio daemon contains * exactly one of these. It is used for storing kind of global diff --git a/src/polypcore/module.c b/src/polypcore/module.c index 499ea299..73ec5bd4 100644 --- a/src/polypcore/module.c +++ b/src/polypcore/module.c @@ -32,7 +32,7 @@ #include "module.h" #include "xmalloc.h" -#include "subscribe.h" +#include "core-subscribe.h" #include "log.h" #include "util.h" diff --git a/src/polypcore/namereg.c b/src/polypcore/namereg.c index 07fb485c..ca03c455 100644 --- a/src/polypcore/namereg.c +++ b/src/polypcore/namereg.c @@ -34,7 +34,7 @@ #include "source.h" #include "sink.h" #include "xmalloc.h" -#include "subscribe.h" +#include "core-subscribe.h" #include "util.h" struct namereg_entry { diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index 14f237c7..d2c0f354 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -39,7 +39,7 @@ #include "source-output.h" #include "source.h" #include -#include "scache.h" +#include "core-scache.h" #include "sample-util.h" #include "authkey.h" #include "namereg.h" diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index b94903d9..31983bc2 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -40,10 +40,10 @@ #include "pstream-util.h" #include "authkey.h" #include "namereg.h" -#include "scache.h" +#include "core-scache.h" #include "xmalloc.h" #include "util.h" -#include "subscribe.h" +#include "core-subscribe.h" #include "log.h" #include "autoload.h" #include "authkey-prop.h" diff --git a/src/polypcore/scache.c b/src/polypcore/scache.c deleted file mode 100644 index 02c7d34f..00000000 --- a/src/polypcore/scache.c +++ /dev/null @@ -1,392 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_GLOB_H -#include -#endif - -#ifdef HAVE_WINDOWS_H -#include -#endif - -#include "scache.h" -#include "sink-input.h" -#include -#include "sample-util.h" -#include "play-memchunk.h" -#include "xmalloc.h" -#include "subscribe.h" -#include "namereg.h" -#include "sound-file.h" -#include "util.h" -#include "log.h" -#include -#include - -#define UNLOAD_POLL_TIME 2 - -static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - pa_core *c = userdata; - struct timeval ntv; - assert(c && c->mainloop == m && c->scache_auto_unload_event == e); - - pa_scache_unload_unused(c); - - pa_gettimeofday(&ntv); - ntv.tv_sec += UNLOAD_POLL_TIME; - m->time_restart(e, &ntv); -} - -static void free_entry(pa_scache_entry *e) { - assert(e); - pa_namereg_unregister(e->core, e->name); - pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_REMOVE, e->index); - pa_xfree(e->name); - pa_xfree(e->filename); - if (e->memchunk.memblock) - pa_memblock_unref(e->memchunk.memblock); - pa_xfree(e); -} - -static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { - pa_scache_entry *e; - assert(c && name); - - if ((e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) { - if (e->memchunk.memblock) - pa_memblock_unref(e->memchunk.memblock); - - pa_xfree(e->filename); - - assert(e->core == c); - - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); - } else { - e = pa_xmalloc(sizeof(pa_scache_entry)); - - if (!pa_namereg_register(c, name, PA_NAMEREG_SAMPLE, e, 1)) { - pa_xfree(e); - return NULL; - } - - e->name = pa_xstrdup(name); - e->core = c; - - if (!c->scache) { - c->scache = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - assert(c->scache); - } - - pa_idxset_put(c->scache, e, &e->index); - - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_NEW, e->index); - } - - pa_cvolume_reset(&e->volume, PA_CHANNELS_MAX); - e->last_used_time = 0; - e->memchunk.memblock = NULL; - e->memchunk.index = e->memchunk.length = 0; - e->filename = NULL; - e->lazy = 0; - e->last_used_time = 0; - - memset(&e->sample_spec, 0, sizeof(pa_sample_spec)); - - return e; -} - -int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx) { - pa_scache_entry *e; - assert(c && name); - - if (!(e = scache_add_item(c, name))) - return -1; - - if (ss) { - e->sample_spec = *ss; - pa_channel_map_init_auto(&e->channel_map, ss->channels); - } - - if (map) - e->channel_map = *map; - - if (chunk) { - e->memchunk = *chunk; - pa_memblock_ref(e->memchunk.memblock); - } - - if (idx) - *idx = e->index; - - return 0; -} - -int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint32_t *idx) { - pa_sample_spec ss; - pa_memchunk chunk; - int r; - -#ifdef OS_IS_WIN32 - char buf[MAX_PATH]; - - if (ExpandEnvironmentStrings(filename, buf, MAX_PATH)) - filename = buf; -#endif - - if (pa_sound_file_load(filename, &ss, &chunk, c->memblock_stat) < 0) - return -1; - - r = pa_scache_add_item(c, name, &ss, NULL, &chunk, idx); - pa_memblock_unref(chunk.memblock); - - return r; -} - -int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, uint32_t *idx) { - pa_scache_entry *e; - -#ifdef OS_IS_WIN32 - char buf[MAX_PATH]; - - if (ExpandEnvironmentStrings(filename, buf, MAX_PATH)) - filename = buf; -#endif - - assert(c && name); - - if (!(e = scache_add_item(c, name))) - return -1; - - e->lazy = 1; - e->filename = pa_xstrdup(filename); - - if (!c->scache_auto_unload_event) { - struct timeval ntv; - pa_gettimeofday(&ntv); - ntv.tv_sec += UNLOAD_POLL_TIME; - c->scache_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); - } - - if (idx) - *idx = e->index; - - return 0; -} - -int pa_scache_remove_item(pa_core *c, const char *name) { - pa_scache_entry *e; - assert(c && name); - - if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) - return -1; - - if (pa_idxset_remove_by_data(c->scache, e, NULL) != e) - assert(0); - - free_entry(e); - return 0; -} - -static void free_cb(void *p, PA_GCC_UNUSED void *userdata) { - pa_scache_entry *e = p; - assert(e); - free_entry(e); -} - -void pa_scache_free(pa_core *c) { - assert(c); - - if (c->scache) { - pa_idxset_free(c->scache, free_cb, NULL); - c->scache = NULL; - } - - if (c->scache_auto_unload_event) - c->mainloop->time_free(c->scache_auto_unload_event); -} - -int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, const pa_cvolume *volume) { - pa_scache_entry *e; - char *t; - pa_cvolume r; - assert(c && name && sink); - - if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1))) - return -1; - - if (e->lazy && !e->memchunk.memblock) { - if (pa_sound_file_load(e->filename, &e->sample_spec, &e->memchunk, c->memblock_stat) < 0) - return -1; - - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); - } - - if (!e->memchunk.memblock) - return -1; - - t = pa_sprintf_malloc("sample:%s", name); - - if (pa_play_memchunk(sink, t, &e->sample_spec, &e->channel_map, &e->memchunk, pa_sw_cvolume_multiply(&r, volume, &e->volume)) < 0) { - free(t); - return -1; - } - - free(t); - - if (e->lazy) - time(&e->last_used_time); - - return 0; -} - -const char * pa_scache_get_name_by_id(pa_core *c, uint32_t id) { - pa_scache_entry *e; - assert(c && id != PA_IDXSET_INVALID); - - if (!c->scache || !(e = pa_idxset_get_by_index(c->scache, id))) - return NULL; - - return e->name; -} - -uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name) { - pa_scache_entry *e; - assert(c && name); - - if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) - return PA_IDXSET_INVALID; - - return e->index; -} - -uint32_t pa_scache_total_size(pa_core *c) { - pa_scache_entry *e; - uint32_t idx, sum = 0; - assert(c); - - if (!c->scache || !pa_idxset_size(c->scache)) - return 0; - - for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) - if (e->memchunk.memblock) - sum += e->memchunk.length; - - return sum; -} - -void pa_scache_unload_unused(pa_core *c) { - pa_scache_entry *e; - time_t now; - uint32_t idx; - assert(c); - - if (!c->scache || !pa_idxset_size(c->scache)) - return; - - time(&now); - - for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) { - - if (!e->lazy || !e->memchunk.memblock) - continue; - - if (e->last_used_time + c->scache_idle_time > now) - continue; - - pa_memblock_unref(e->memchunk.memblock); - e->memchunk.memblock = NULL; - e->memchunk.index = e->memchunk.length = 0; - - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); - } -} - -static void add_file(pa_core *c, const char *pathname) { - struct stat st; - const char *e; - - e = pa_path_get_filename(pathname); - - if (stat(pathname, &st) < 0) { - pa_log(__FILE__": stat('%s') failed: %s\n", pathname, strerror(errno)); - return; - } - -#if defined(S_ISREG) && defined(S_ISLNK) - if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) -#endif - pa_scache_add_file_lazy(c, e, pathname, NULL); -} - -int pa_scache_add_directory_lazy(pa_core *c, const char *pathname) { - DIR *dir; - assert(c && pathname); - - /* First try to open this as directory */ - if (!(dir = opendir(pathname))) { -#ifdef HAVE_GLOB_H - glob_t p; - unsigned int i; - /* If that fails, try to open it as shell glob */ - - if (glob(pathname, GLOB_ERR|GLOB_NOSORT, NULL, &p) < 0) { - pa_log(__FILE__": Failed to open directory: %s\n", strerror(errno)); - return -1; - } - - for (i = 0; i < p.gl_pathc; i++) - add_file(c, p.gl_pathv[i]); - - globfree(&p); -#else - return -1; -#endif - } else { - struct dirent *e; - - while ((e = readdir(dir))) { - char p[PATH_MAX]; - - if (e->d_name[0] == '.') - continue; - - snprintf(p, sizeof(p), "%s/%s", pathname, e->d_name); - add_file(c, p); - } - } - - closedir(dir); - return 0; -} diff --git a/src/polypcore/scache.h b/src/polypcore/scache.h deleted file mode 100644 index d667ae60..00000000 --- a/src/polypcore/scache.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef fooscachehfoo -#define fooscachehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "core.h" -#include "memchunk.h" -#include "sink.h" - -typedef struct pa_scache_entry { - pa_core *core; - uint32_t index; - char *name; - - pa_cvolume volume; - pa_sample_spec sample_spec; - pa_channel_map channel_map; - pa_memchunk memchunk; - - char *filename; - - int lazy; - time_t last_used_time; -} pa_scache_entry; - -int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx); -int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint32_t *idx); -int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, uint32_t *idx); - -int pa_scache_add_directory_lazy(pa_core *c, const char *pathname); - -int pa_scache_remove_item(pa_core *c, const char *name); -int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, const pa_cvolume *cvolume); -void pa_scache_free(pa_core *c); - -const char *pa_scache_get_name_by_id(pa_core *c, uint32_t id); -uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name); - -uint32_t pa_scache_total_size(pa_core *c); - -void pa_scache_unload_unused(pa_core *c); - -#endif diff --git a/src/polypcore/sink-input.c b/src/polypcore/sink-input.c index f447b8cf..696c47a4 100644 --- a/src/polypcore/sink-input.c +++ b/src/polypcore/sink-input.c @@ -31,7 +31,7 @@ #include "sink-input.h" #include "sample-util.h" #include "xmalloc.h" -#include "subscribe.h" +#include "core-subscribe.h" #include "log.h" #define CONVERT_BUFFER_LENGTH 4096 diff --git a/src/polypcore/sink.c b/src/polypcore/sink.c index f29afba7..6c143463 100644 --- a/src/polypcore/sink.c +++ b/src/polypcore/sink.c @@ -34,7 +34,7 @@ #include "util.h" #include "sample-util.h" #include "xmalloc.h" -#include "subscribe.h" +#include "core-subscribe.h" #include "log.h" #include diff --git a/src/polypcore/source-output.c b/src/polypcore/source-output.c index e1d8ccf7..9b75a8b0 100644 --- a/src/polypcore/source-output.c +++ b/src/polypcore/source-output.c @@ -30,7 +30,7 @@ #include "source-output.h" #include "xmalloc.h" -#include "subscribe.h" +#include "core-subscribe.h" #include "log.h" pa_source_output* pa_source_output_new( diff --git a/src/polypcore/source.c b/src/polypcore/source.c index 6e377b20..c64f7b99 100644 --- a/src/polypcore/source.c +++ b/src/polypcore/source.c @@ -32,7 +32,7 @@ #include "source-output.h" #include "namereg.h" #include "xmalloc.h" -#include "subscribe.h" +#include "core-subscribe.h" #include "log.h" pa_source* pa_source_new( diff --git a/src/polypcore/subscribe.c b/src/polypcore/subscribe.c deleted file mode 100644 index e8b3c841..00000000 --- a/src/polypcore/subscribe.c +++ /dev/null @@ -1,230 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "queue.h" -#include "subscribe.h" -#include "xmalloc.h" -#include "log.h" - -/* The subscription subsystem may be used to be notified whenever an - * entity (sink, source, ...) is created or deleted. Modules may - * register a callback function that is called whenever an event - * matching a subscription mask happens. The execution of the callback - * function is postponed to the next main loop iteration, i.e. is not - * called from within the stack frame the entity was created in. */ - -struct pa_subscription { - pa_core *core; - int dead; - void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata); - void *userdata; - pa_subscription_mask_t mask; - - pa_subscription *prev, *next; -}; - -struct pa_subscription_event { - pa_subscription_event_type_t type; - uint32_t index; -}; - -static void sched_event(pa_core *c); - -/* Allocate a new subscription object for the given subscription mask. Use the specified callback function and user data */ -pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata) { - pa_subscription *s; - assert(c); - - s = pa_xmalloc(sizeof(pa_subscription)); - s->core = c; - s->dead = 0; - s->callback = callback; - s->userdata = userdata; - s->mask = m; - - if ((s->next = c->subscriptions)) - s->next->prev = s; - s->prev = NULL; - c->subscriptions = s; - return s; -} - -/* Free a subscription object, effectively marking it for deletion */ -void pa_subscription_free(pa_subscription*s) { - assert(s && !s->dead); - s->dead = 1; - sched_event(s->core); -} - -static void free_item(pa_subscription *s) { - assert(s && s->core); - - if (s->prev) - s->prev->next = s->next; - else - s->core->subscriptions = s->next; - - if (s->next) - s->next->prev = s->prev; - - pa_xfree(s); -} - -/* Free all subscription objects */ -void pa_subscription_free_all(pa_core *c) { - pa_subscription_event *e; - assert(c); - - while (c->subscriptions) - free_item(c->subscriptions); - - if (c->subscription_event_queue) { - while ((e = pa_queue_pop(c->subscription_event_queue))) - pa_xfree(e); - - pa_queue_free(c->subscription_event_queue, NULL, NULL); - c->subscription_event_queue = NULL; - } - - if (c->subscription_defer_event) { - c->mainloop->defer_free(c->subscription_defer_event); - c->subscription_defer_event = NULL; - } -} - -/*static void dump_event(pa_subscription_event*e) { - switch (e->type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { - case PA_SUBSCRIPTION_EVENT_SINK: - pa_log(__FILE__": SINK_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_SOURCE: - pa_log(__FILE__": SOURCE_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_SINK_INPUT: - pa_log(__FILE__": SINK_INPUT_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: - pa_log(__FILE__": SOURCE_OUTPUT_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_MODULE: - pa_log(__FILE__": MODULE_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_CLIENT: - pa_log(__FILE__": CLIENT_EVENT"); - break; - default: - pa_log(__FILE__": OTHER"); - break; - } - - switch (e->type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) { - case PA_SUBSCRIPTION_EVENT_NEW: - pa_log(__FILE__": NEW"); - break; - case PA_SUBSCRIPTION_EVENT_CHANGE: - pa_log(__FILE__": CHANGE"); - break; - case PA_SUBSCRIPTION_EVENT_REMOVE: - pa_log(__FILE__": REMOVE"); - break; - default: - pa_log(__FILE__": OTHER"); - break; - } - - pa_log(__FILE__": %u\n", e->index); -}*/ - -/* Deferred callback for dispatching subscirption events */ -static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) { - pa_core *c = userdata; - pa_subscription *s; - assert(c && c->subscription_defer_event == de && c->mainloop == m); - - c->mainloop->defer_enable(c->subscription_defer_event, 0); - - - /* Dispatch queued events */ - - if (c->subscription_event_queue) { - pa_subscription_event *e; - - while ((e = pa_queue_pop(c->subscription_event_queue))) { - - for (s = c->subscriptions; s; s = s->next) { - - if (!s->dead && pa_subscription_match_flags(s->mask, e->type)) - s->callback(c, e->type, e->index, s->userdata); - } - - pa_xfree(e); - } - } - - /* Remove dead subscriptions */ - - s = c->subscriptions; - while (s) { - pa_subscription *n = s->next; - if (s->dead) - free_item(s); - s = n; - } -} - -/* Schedule an mainloop event so that a pending subscription event is dispatched */ -static void sched_event(pa_core *c) { - assert(c); - - if (!c->subscription_defer_event) { - c->subscription_defer_event = c->mainloop->defer_new(c->mainloop, defer_cb, c); - assert(c->subscription_defer_event); - } - - c->mainloop->defer_enable(c->subscription_defer_event, 1); -} - -/* Append a new subscription event to the subscription event queue and schedule a main loop event */ -void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t index) { - pa_subscription_event *e; - assert(c); - - e = pa_xmalloc(sizeof(pa_subscription_event)); - e->type = t; - e->index = index; - - if (!c->subscription_event_queue) { - c->subscription_event_queue = pa_queue_new(); - assert(c->subscription_event_queue); - } - - pa_queue_push(c->subscription_event_queue, e); - sched_event(c); -} - - diff --git a/src/polypcore/subscribe.h b/src/polypcore/subscribe.h deleted file mode 100644 index 625159e3..00000000 --- a/src/polypcore/subscribe.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef foosubscribehfoo -#define foosubscribehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -typedef struct pa_subscription pa_subscription; -typedef struct pa_subscription_event pa_subscription_event; - -#include "core.h" -#include "native-common.h" - -pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata); -void pa_subscription_free(pa_subscription*s); -void pa_subscription_free_all(pa_core *c); - -void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t idx); - -#endif -- cgit From 2e0dcc4ff0cbe23d6ac5033f754692f9b4cff36f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Feb 2006 23:48:41 +0000 Subject: include header files in simple.h with <> instead of "" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@497 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/simple.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/polyp/simple.h b/src/polyp/simple.h index 270cbb24..afb25c8e 100644 --- a/src/polyp/simple.h +++ b/src/polyp/simple.h @@ -24,8 +24,8 @@ #include -#include "sample.h" -#include "def.h" +#include +#include #include /** \file -- cgit From b9513089f57d4ee692c12d911823e6f8f1cc6129 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 17 Feb 2006 00:11:54 +0000 Subject: fix doxygen git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@498 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doxygen/doxygen.conf.in | 12 ++++++------ src/polyp/context.h | 2 +- src/polyp/glib-mainloop.h | 2 +- src/polyp/mainloop-api.h | 6 +++--- src/polyp/mainloop-signal.h | 2 +- src/polyp/mainloop.h | 3 +-- src/polyp/operation.h | 2 +- src/polyp/polypaudio.h | 4 ++-- src/polyp/simple.h | 2 +- src/polyp/stream.h | 2 +- 10 files changed, 18 insertions(+), 19 deletions(-) diff --git a/doxygen/doxygen.conf.in b/doxygen/doxygen.conf.in index c0e122ea..fcda2194 100644 --- a/doxygen/doxygen.conf.in +++ b/doxygen/doxygen.conf.in @@ -170,7 +170,7 @@ DISTRIBUTE_GROUP_DOC = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. -TAB_SIZE = 8 +TAB_SIZE = 4 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". @@ -417,7 +417,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = ../polyp/polyplib-context.h ../polyp/polyplib-stream.h ../polyp/polyplib.h ../polyp/sample.h ../polyp/polyplib-def.h ../polyp/polyplib-subscribe.h ../polyp/polyplib-introspect.h ../polyp/polyplib-scache.h ../polyp/mainloop-api.h ../polyp/cdecl.h ../polyp/glib-mainloop.h ../polyp/mainloop.h ../polyp/mainloop-signal.h ../polyp/polyplib-error.h ../polyp/polyplib-operation.h ../polyp/polyplib-simple.h ../polyp/polyplib-version.h +INPUT = ../src/polyp/context.h ../src/polyp/stream.h ../src/polyp/polypaudio.h ../src/polyp/sample.h ../src/polyp/def.h ../src/polyp/subscribe.h ../src/polyp/introspect.h ../src/polyp/scache.h ../src/polyp/mainloop-api.h ../src/polyp/cdecl.h ../src/polyp/glib-mainloop.h ../src/polyp/mainloop.h ../src/polyp/mainloop-signal.h ../src/polyp/error.h ../src/polyp/operation.h ../src/polyp/simple.h ../src/polyp/version.h ../src/polyp/volume.h ../src/polyp/channelmap.h # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp @@ -455,7 +455,7 @@ EXCLUDE_PATTERNS = # directories that contain example code fragments that are included (see # the \include command). -EXAMPLE_PATH = ../polyp/ +EXAMPLE_PATH = ../src/utils ../src/tests # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp @@ -550,7 +550,7 @@ VERBATIM_HEADERS = YES # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. -ALPHABETICAL_INDEX = NO +ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns @@ -563,7 +563,7 @@ COLS_IN_ALPHA_INDEX = 5 # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. -IGNORE_PREFIX = +IGNORE_PREFIX = pa_ PA_ #--------------------------------------------------------------------------- # configuration options related to the HTML output @@ -660,7 +660,7 @@ DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. -ENUM_VALUES_PER_LINE = 4 +ENUM_VALUES_PER_LINE = 1 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that diff --git a/src/polyp/context.h b/src/polyp/context.h index 216d7d87..4efd5156 100644 --- a/src/polyp/context.h +++ b/src/polyp/context.h @@ -49,7 +49,7 @@ PA_C_DECL_BEGIN -/** \pa_context +/** \struct pa_context * An opaque connection context to a daemon */ typedef struct pa_context pa_context; diff --git a/src/polyp/glib-mainloop.h b/src/polyp/glib-mainloop.h index b4815ed9..e052cff3 100644 --- a/src/polyp/glib-mainloop.h +++ b/src/polyp/glib-mainloop.h @@ -32,7 +32,7 @@ PA_C_DECL_BEGIN -/** \pa_glib_mainloop +/** \struct pa_glib_mainloop * An opaque GLIB main loop object */ typedef struct pa_glib_mainloop pa_glib_mainloop; diff --git a/src/polyp/mainloop-api.h b/src/polyp/mainloop-api.h index 91ee4111..7bc7522c 100644 --- a/src/polyp/mainloop-api.h +++ b/src/polyp/mainloop-api.h @@ -53,15 +53,15 @@ typedef enum pa_io_event_flags { PA_IO_EVENT_ERROR = 8 /**< Error event */ } pa_io_event_flags_t; -/** \pa_io_event +/** \struct pa_io_event * An opaque IO event source object */ typedef struct pa_io_event pa_io_event; -/** \pa_defer_event +/** \struct pa_defer_event * An opaque deferred event source object. Events of this type are triggered once in every main loop iteration */ typedef struct pa_defer_event pa_defer_event; -/** \pa_time_event +/** \struct pa_time_event * An opaque timer event source object */ typedef struct pa_time_event pa_time_event; diff --git a/src/polyp/mainloop-signal.h b/src/polyp/mainloop-signal.h index 76065b22..0291f426 100644 --- a/src/polyp/mainloop-signal.h +++ b/src/polyp/mainloop-signal.h @@ -42,7 +42,7 @@ int pa_signal_init(pa_mainloop_api *api); /** Cleanup the signal subsystem */ void pa_signal_done(void); -/** \pa_signal_event +/** \struct pa_signal_event * An opaque UNIX signal event source object */ typedef struct pa_signal_event pa_signal_event; diff --git a/src/polyp/mainloop.h b/src/polyp/mainloop.h index 691f8c50..eeb23884 100644 --- a/src/polyp/mainloop.h +++ b/src/polyp/mainloop.h @@ -35,7 +35,7 @@ PA_C_DECL_BEGIN * defined in \ref mainloop-api.h. This implementation is thread safe * as long as you access the main loop object from a single thread only.*/ -/** \pa_mainloop +/** \struct pa_mainloop * An opaque main loop object */ typedef struct pa_mainloop pa_mainloop; @@ -46,7 +46,6 @@ pa_mainloop *pa_mainloop_new(void); /** Free a main loop object */ void pa_mainloop_free(pa_mainloop* m); - /** Prepare for a single iteration of the main loop. Returns a negative value on error or exit request. timeout specifies a maximum timeout for the subsequent poll, or -1 for blocking behaviour. Defer events are also dispatched when this diff --git a/src/polyp/operation.h b/src/polyp/operation.h index 6a24d649..d286b0c1 100644 --- a/src/polyp/operation.h +++ b/src/polyp/operation.h @@ -30,7 +30,7 @@ PA_C_DECL_BEGIN -/** \pa_operation +/** \struct pa_operation * An asynchronous operation object */ typedef struct pa_operation pa_operation; diff --git a/src/polyp/polypaudio.h b/src/polyp/polypaudio.h index c6014bbb..c81fdfdb 100644 --- a/src/polyp/polypaudio.h +++ b/src/polyp/polypaudio.h @@ -70,8 +70,8 @@ * described in \ref mainloop-api.h. Two distinct implementations are * available: * - * \li \ref mainloop.h: a minimal but fast implementation based on poll() - * \li \ref glib-mainloop.h: a wrapper around GLIB's main loop + * \li \ref mainloop.h : a minimal but fast implementation based on poll() + * \li \ref glib-mainloop.h : a wrapper around GLIB's main loop * * UNIX signals may be hooked to a main loop using the functions from * \ref mainloop-signal.h diff --git a/src/polyp/simple.h b/src/polyp/simple.h index afb25c8e..1a139005 100644 --- a/src/polyp/simple.h +++ b/src/polyp/simple.h @@ -41,7 +41,7 @@ PA_C_DECL_BEGIN -/** \pa_simple +/** \struct pa_simple * An opaque simple connection object */ typedef struct pa_simple pa_simple; diff --git a/src/polyp/stream.h b/src/polyp/stream.h index e2cab19e..e20cfdd4 100644 --- a/src/polyp/stream.h +++ b/src/polyp/stream.h @@ -36,7 +36,7 @@ PA_C_DECL_BEGIN -/** \pa_stream +/** \struct pa_stream * An opaque stream for playback or recording */ typedef struct pa_stream pa_stream; -- cgit From c278bc6c370faa5f38de0dcdffee4e301b5f9f1a Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 17 Feb 2006 09:12:06 +0000 Subject: Move the util libs to the modules section since they're in that directory. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@499 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 50 ++++++++++++++++---------------------------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 7d87a119..1e898a85 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -538,21 +538,6 @@ modlib_LTLIBRARIES += \ libx11prop.la endif -if HAVE_OSS -modlib_LTLIBRARIES += \ - liboss-util.la -endif - -if HAVE_ALSA -modlib_LTLIBRARIES += \ - libalsa-util.la -endif - -if HAVE_HOWL -modlib_LTLIBRARIES += \ - libhowl-wrap.la -endif - libprotocol_simple_la_SOURCES = polypcore/protocol-simple.c polypcore/protocol-simple.h libprotocol_simple_la_LDFLAGS = -avoid-version libprotocol_simple_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket-server.la libiochannel.la @@ -649,25 +634,6 @@ libx11prop_la_LDFLAGS = -avoid-version libx11prop_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) libx11prop_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) -# OSS - -liboss_util_la_SOURCES = modules/oss-util.c modules/oss-util.h -liboss_util_la_LDFLAGS = -avoid-version - -# ALSA - -libalsa_util_la_SOURCES = modules/alsa-util.c modules/alsa-util.h -libalsa_util_la_LDFLAGS = -avoid-version -libalsa_util_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) -libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) - -# HOWL - -libhowl_wrap_la_SOURCES = modules/howl-wrap.c modules/howl-wrap.h -libhowl_wrap_la_LDFLAGS = -avoid-version -libhowl_wrap_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) -libhowl_wrap_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) - ################################### # Plug-in libraries # ################################### @@ -727,12 +693,14 @@ endif if HAVE_OSS modlib_LTLIBRARIES += \ + liboss-util.la \ module-oss.la \ module-oss-mmap.la endif if HAVE_ALSA modlib_LTLIBRARIES += \ + libalsa-util.la \ module-alsa-sink.la \ module-alsa-source.la endif @@ -744,6 +712,7 @@ endif if HAVE_HOWL modlib_LTLIBRARIES += \ + libhowl-wrap.la \ module-zeroconf-publish.la endif @@ -971,6 +940,9 @@ module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EX # OSS +liboss_util_la_SOURCES = modules/oss-util.c modules/oss-util.h +liboss_util_la_LDFLAGS = -avoid-version + module_oss_la_SOURCES = modules/module-oss.c module_oss_la_LDFLAGS = -module -avoid-version module_oss_la_LIBADD = $(AM_LIBADD) libiochannel.la liboss-util.la @@ -981,6 +953,11 @@ module_oss_mmap_la_LIBADD = $(AM_LIBADD) liboss-util.la # ALSA +libalsa_util_la_SOURCES = modules/alsa-util.c modules/alsa-util.h +libalsa_util_la_LDFLAGS = -avoid-version +libalsa_util_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) +libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) + module_alsa_sink_la_SOURCES = modules/module-alsa-sink.c module_alsa_sink_la_LDFLAGS = -module -avoid-version module_alsa_sink_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la @@ -999,6 +976,11 @@ module_solaris_la_LIBADD = $(AM_LIBADD) libiochannel.la # HOWL +libhowl_wrap_la_SOURCES = modules/howl-wrap.c modules/howl-wrap.h +libhowl_wrap_la_LDFLAGS = -avoid-version +libhowl_wrap_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) +libhowl_wrap_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) + module_zeroconf_publish_la_SOURCES = modules/module-zeroconf-publish.c module_zeroconf_publish_la_LDFLAGS = -module -avoid-version module_zeroconf_publish_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) libhowl-wrap.la -- cgit From 5eda18bf608a325c136a450e58fa154eb0b270f4 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 17 Feb 2006 12:10:58 +0000 Subject: Cleaned up the includes after the restructuring. Indicate which headers are public and which are internal through <> vs "". git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@500 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/caps.c | 1 + src/daemon/cmdline.c | 3 ++- src/daemon/cpulimit.c | 3 ++- src/daemon/daemon-conf.c | 3 ++- src/daemon/dumpmodules.c | 3 ++- src/daemon/main.c | 18 ++++++++------- src/modules/howl-wrap.c | 7 +++--- src/modules/howl-wrap.h | 2 +- src/modules/module-alsa-sink.c | 2 +- src/modules/module-alsa-source.c | 2 +- src/modules/module-oss.c | 2 +- src/modules/module-protocol-stub.c | 2 +- src/modules/module-zeroconf-publish.c | 8 ++++--- src/polyp/browser.c | 3 ++- src/polyp/browser.h | 1 - src/polyp/client-conf-x11.c | 3 ++- src/polyp/client-conf-x11.h | 2 +- src/polyp/client-conf.c | 2 +- src/polyp/client-conf.h | 2 +- src/polyp/context.c | 14 +++++++----- src/polyp/error.c | 3 ++- src/polyp/glib-mainloop.c | 5 +++-- src/polyp/glib12-mainloop.c | 3 ++- src/polyp/internal.h | 11 +++++----- src/polyp/introspect.c | 11 ++++++---- src/polyp/mainloop-api.c | 5 +++-- src/polyp/mainloop-signal.c | 3 ++- src/polyp/mainloop.c | 5 +++-- src/polyp/operation.c | 2 ++ src/polyp/scache.c | 6 +++-- src/polyp/simple.c | 8 ++++--- src/polyp/stream.c | 3 ++- src/polyp/subscribe.c | 8 ++++--- src/polyp/version.h.in | 2 ++ src/polypcore/authkey-prop.c | 7 +++--- src/polypcore/authkey-prop.h | 2 +- src/polypcore/authkey.c | 7 +++--- src/polypcore/autoload.c | 15 +++++++------ src/polypcore/autoload.h | 2 +- src/polypcore/cli-command.c | 39 +++++++++++++++++---------------- src/polypcore/cli-command.h | 4 ++-- src/polypcore/cli-text.c | 25 +++++++++++---------- src/polypcore/cli-text.h | 2 +- src/polypcore/cli.c | 29 +++++++++++++------------ src/polypcore/cli.h | 6 ++--- src/polypcore/client.c | 7 +++--- src/polypcore/client.h | 4 ++-- src/polypcore/conf-parser.c | 7 +++--- src/polypcore/core-scache.c | 21 +++++++++--------- src/polypcore/core-scache.h | 6 ++--- src/polypcore/core-subscribe.c | 7 +++--- src/polypcore/core-subscribe.h | 4 ++-- src/polypcore/core.c | 23 ++++++++++---------- src/polypcore/core.h | 12 +++++----- src/polypcore/dynarray.c | 3 ++- src/polypcore/hashmap.c | 7 +++--- src/polypcore/idxset.c | 3 ++- src/polypcore/iochannel.c | 7 +++--- src/polypcore/ioline.c | 5 +++-- src/polypcore/ioline.h | 4 ++-- src/polypcore/log.c | 5 +++-- src/polypcore/log.h | 2 +- src/polypcore/mcalign.c | 3 ++- src/polypcore/mcalign.h | 4 ++-- src/polypcore/memblock.c | 3 ++- src/polypcore/memblockq.c | 7 +++--- src/polypcore/memblockq.h | 4 ++-- src/polypcore/memchunk.c | 3 ++- src/polypcore/memchunk.h | 2 +- src/polypcore/modargs.c | 17 ++++++++------- src/polypcore/modargs.h | 2 +- src/polypcore/modinfo.c | 7 +++--- src/polypcore/module.c | 9 ++++---- src/polypcore/module.h | 4 ++-- src/polypcore/namereg.c | 13 ++++++----- src/polypcore/namereg.h | 2 +- src/polypcore/packet.c | 3 ++- src/polypcore/parseaddr.c | 5 +++-- src/polypcore/pdispatch.c | 11 +++++----- src/polypcore/pdispatch.h | 4 ++-- src/polypcore/pid.c | 5 +++-- src/polypcore/play-memchunk.c | 7 +++--- src/polypcore/play-memchunk.h | 4 ++-- src/polypcore/poll.c | 3 ++- src/polypcore/props.c | 5 +++-- src/polypcore/props.h | 4 ++-- src/polypcore/protocol-cli.c | 7 +++--- src/polypcore/protocol-cli.h | 8 +++---- src/polypcore/protocol-esound.c | 32 ++++++++++++++------------- src/polypcore/protocol-esound.h | 8 +++---- src/polypcore/protocol-http.c | 11 +++++----- src/polypcore/protocol-http.h | 8 +++---- src/polypcore/protocol-native.c | 41 ++++++++++++++++++----------------- src/polypcore/protocol-native.h | 8 +++---- src/polypcore/protocol-simple.c | 15 +++++++------ src/polypcore/protocol-simple.h | 8 +++---- src/polypcore/pstream-util.c | 3 ++- src/polypcore/pstream-util.h | 4 ++-- src/polypcore/pstream.c | 7 +++--- src/polypcore/pstream.h | 8 +++---- src/polypcore/queue.c | 3 ++- src/polypcore/random.c | 5 +++-- src/polypcore/resampler.c | 7 +++--- src/polypcore/resampler.h | 4 ++-- src/polypcore/sample-util.c | 3 ++- src/polypcore/sample-util.h | 4 ++-- src/polypcore/sconv-s16le.c | 6 +++-- src/polypcore/sconv.c | 7 +++--- src/polypcore/sink-input.c | 9 ++++---- src/polypcore/sink-input.h | 10 ++++----- src/polypcore/sink.c | 17 ++++++++------- src/polypcore/sink.h | 8 +++---- src/polypcore/sioman.c | 1 + src/polypcore/socket-client.c | 11 +++++----- src/polypcore/socket-client.h | 2 +- src/polypcore/socket-server.c | 9 ++++---- src/polypcore/socket-server.h | 2 +- src/polypcore/socket-util.c | 7 +++--- src/polypcore/sound-file-stream.c | 7 +++--- src/polypcore/sound-file-stream.h | 2 +- src/polypcore/sound-file.c | 5 +++-- src/polypcore/sound-file.h | 2 +- src/polypcore/source-output.c | 7 +++--- src/polypcore/source-output.h | 10 ++++----- src/polypcore/source.c | 11 +++++----- src/polypcore/source.h | 13 ++++++----- src/polypcore/strbuf.h | 2 +- src/polypcore/strlist.c | 7 +++--- src/polypcore/tagstruct.c | 3 ++- src/polypcore/tokenizer.c | 7 +++--- src/polypcore/util.c | 5 +++-- src/polypcore/util.h | 2 +- src/polypcore/x11wrap.c | 9 ++++---- src/polypcore/x11wrap.h | 2 +- src/polypcore/xmalloc.c | 7 +++--- src/tests/cpulimit-test.c | 3 ++- src/utils/pax11publish.c | 3 ++- 137 files changed, 523 insertions(+), 421 deletions(-) diff --git a/src/daemon/caps.c b/src/daemon/caps.c index 8d429459..e12d33fb 100644 --- a/src/daemon/caps.c +++ b/src/daemon/caps.c @@ -33,6 +33,7 @@ #endif #include + #include "caps.h" #ifdef HAVE_GETUID diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c index 0b5f9ec7..b6ab1283 100644 --- a/src/daemon/cmdline.c +++ b/src/daemon/cmdline.c @@ -30,11 +30,12 @@ #include #include -#include "cmdline.h" #include #include #include +#include "cmdline.h" + /* Argument codes for getopt_long() */ enum { ARG_HELP = 256, diff --git a/src/daemon/cpulimit.c b/src/daemon/cpulimit.c index 6887796f..d7a24b8e 100644 --- a/src/daemon/cpulimit.c +++ b/src/daemon/cpulimit.c @@ -23,10 +23,11 @@ #include #endif -#include "cpulimit.h" #include #include +#include "cpulimit.h" + #ifdef HAVE_SIGXCPU #include diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 8fe3c4cc..ecabce40 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -29,13 +29,14 @@ #include #include -#include "daemon-conf.h" #include #include #include #include #include +#include "daemon-conf.h" + #ifndef DEFAULT_CONFIG_DIR # ifndef OS_IS_WIN32 # define DEFAULT_CONFIG_DIR "/etc/polypaudio" diff --git a/src/daemon/dumpmodules.c b/src/daemon/dumpmodules.c index 8d8eb0b9..bf29a681 100644 --- a/src/daemon/dumpmodules.c +++ b/src/daemon/dumpmodules.c @@ -29,10 +29,11 @@ #include #include -#include "dumpmodules.h" #include #include +#include "dumpmodules.h" + #define PREFIX "module-" static void short_info(const char *name, PA_GCC_UNUSED const char *path, pa_modinfo *i) { diff --git a/src/daemon/main.c b/src/daemon/main.c index 6be83d8c..638c2f3f 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -47,26 +47,28 @@ #include #endif -#include +#include "../polypcore/winsock.h" + +#include +#include #include #include -#include #include -#include -#include "cmdline.h" #include +#include #include #include #include +#include +#include +#include + +#include "cmdline.h" #include "cpulimit.h" -#include #include "daemon-conf.h" #include "dumpmodules.h" #include "caps.h" -#include -#include -#include #ifdef HAVE_LIBWRAP /* Only one instance of these variables */ diff --git a/src/modules/howl-wrap.c b/src/modules/howl-wrap.c index 77d096ac..b3acde55 100644 --- a/src/modules/howl-wrap.c +++ b/src/modules/howl-wrap.c @@ -21,10 +21,11 @@ #include +#include +#include +#include + #include "howl-wrap.h" -#include "log.h" -#include "xmalloc.h" -#include "props.h" #define HOWL_PROPERTY "howl" diff --git a/src/modules/howl-wrap.h b/src/modules/howl-wrap.h index a670b082..42c26ef2 100644 --- a/src/modules/howl-wrap.h +++ b/src/modules/howl-wrap.h @@ -24,7 +24,7 @@ #include -#include "core.h" +#include pa_howl_wrapper; diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index d3fe71a5..6ea1e137 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -44,8 +44,8 @@ #include #include -#include "module-alsa-sink-symdef.h" #include "alsa-util.h" +#include "module-alsa-sink-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ALSA Sink") diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 9453f846..4f281aa7 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -44,8 +44,8 @@ #include #include -#include "module-alsa-source-symdef.h" #include "alsa-util.h" +#include "module-alsa-source-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ALSA Source") diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 264e8792..fe43c45e 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -45,8 +45,8 @@ #include #include -#include "module-oss-symdef.h" #include "oss-util.h" +#include "module-oss-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("OSS Sink/Source") diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index 469ddcee..b69716cc 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -40,7 +40,7 @@ #include #endif -#include +#include "../polypcore/winsock.h" #include #include diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index 45d566ae..d2858aac 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -29,7 +29,6 @@ #include #include -#include #include #include #include @@ -37,11 +36,14 @@ #include #include #include -#include +#include #include -#include #include +#include "../polypcore/endianmacros.h" + +#include "howl-wrap.h" + #include "module-zeroconf-publish-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") diff --git a/src/polyp/browser.c b/src/polyp/browser.c index 80051d54..482bab81 100644 --- a/src/polyp/browser.c +++ b/src/polyp/browser.c @@ -22,11 +22,12 @@ #include #include -#include "browser.h" #include #include #include +#include "browser.h" + #define SERVICE_NAME_SINK "_polypaudio-sink._tcp." #define SERVICE_NAME_SOURCE "_polypaudio-source._tcp." #define SERVICE_NAME_SERVER "_polypaudio-server._tcp." diff --git a/src/polyp/browser.h b/src/polyp/browser.h index 3bb0d264..043b818a 100644 --- a/src/polyp/browser.h +++ b/src/polyp/browser.h @@ -25,7 +25,6 @@ #include #include #include -#include PA_C_DECL_BEGIN diff --git a/src/polyp/client-conf-x11.c b/src/polyp/client-conf-x11.c index 83d0bd2e..9e863bc7 100644 --- a/src/polyp/client-conf-x11.c +++ b/src/polyp/client-conf-x11.c @@ -29,12 +29,13 @@ #include #include -#include "client-conf-x11.h" #include #include #include #include +#include "client-conf-x11.h" + int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) { Display *d = NULL; int ret = -1; diff --git a/src/polyp/client-conf-x11.h b/src/polyp/client-conf-x11.h index 80841171..64459224 100644 --- a/src/polyp/client-conf-x11.h +++ b/src/polyp/client-conf-x11.h @@ -22,7 +22,7 @@ USA. ***/ -#include +#include "client-conf.h" /* Load client configuration data from the specified X11 display, * overwriting the current settings in *c */ diff --git a/src/polyp/client-conf.c b/src/polyp/client-conf.c index 2df201ce..328d01c9 100644 --- a/src/polyp/client-conf.c +++ b/src/polyp/client-conf.c @@ -35,7 +35,7 @@ #include #include -#include +#include "client-conf.h" #ifndef DEFAULT_CONFIG_DIR # ifndef OS_IS_WIN32 diff --git a/src/polyp/client-conf.h b/src/polyp/client-conf.h index 2d8a019f..de3efae7 100644 --- a/src/polyp/client-conf.h +++ b/src/polyp/client-conf.h @@ -22,7 +22,7 @@ USA. ***/ -#include "../polypcore/native-common.h" +#include /* A structure containing configuration data for polypaudio clients. */ diff --git a/src/polyp/context.c b/src/polyp/context.c index 4ac11caa..b7f7eb99 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -45,11 +45,10 @@ #include #endif -#include +#include "../polypcore/winsock.h" + +#include -#include "internal.h" -#include "context.h" -#include "version.h" #include #include #include @@ -59,13 +58,18 @@ #include #include #include -#include #include +#include "internal.h" + +#include "client-conf.h" + #ifdef HAVE_X11 #include "client-conf-x11.h" #endif +#include "context.h" + #define AUTOSPAWN_LOCK "autospawn.lock" static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { diff --git a/src/polyp/error.c b/src/polyp/error.c index a137ab49..ece77bf2 100644 --- a/src/polyp/error.c +++ b/src/polyp/error.c @@ -26,9 +26,10 @@ #include #include -#include "error.h" #include +#include "error.h" + static const char* const errortab[PA_ERROR_MAX] = { [PA_ERROR_OK] = "OK", [PA_ERROR_ACCESS] = "Access denied", diff --git a/src/polyp/glib-mainloop.c b/src/polyp/glib-mainloop.c index 962eb574..3937a1a9 100644 --- a/src/polyp/glib-mainloop.c +++ b/src/polyp/glib-mainloop.c @@ -25,12 +25,13 @@ #include -#include #include #include -#include "glib.h" #include +#include "glib.h" +#include "glib-mainloop.h" + struct pa_io_event { pa_glib_mainloop *mainloop; int dead; diff --git a/src/polyp/glib12-mainloop.c b/src/polyp/glib12-mainloop.c index 80a02b1c..5ad23adb 100644 --- a/src/polyp/glib12-mainloop.c +++ b/src/polyp/glib12-mainloop.c @@ -25,11 +25,12 @@ #include -#include #include #include #include +#include "glib-mainloop.h" + /* A mainloop implementation based on GLIB 1.2 */ struct pa_io_event { diff --git a/src/polyp/internal.h b/src/polyp/internal.h index bdfd5d8e..762688c9 100644 --- a/src/polyp/internal.h +++ b/src/polyp/internal.h @@ -23,20 +23,21 @@ ***/ #include +#include +#include +#include + #include #include #include #include - -#include "context.h" -#include "stream.h" -#include "operation.h" #include #include -#include #include #include +#include "client-conf.h" + #define DEFAULT_TIMEOUT (10) struct pa_context { diff --git a/src/polyp/introspect.c b/src/polyp/introspect.c index d89eb9ed..4af724b4 100644 --- a/src/polyp/introspect.c +++ b/src/polyp/introspect.c @@ -25,11 +25,14 @@ #include -#include "introspect.h" -#include "context.h" -#include "internal.h" -#include +#include + #include +#include + +#include "internal.h" + +#include "introspect.h" /*** Statistics ***/ diff --git a/src/polyp/mainloop-api.c b/src/polyp/mainloop-api.c index a3eaee9c..71f55c05 100644 --- a/src/polyp/mainloop-api.c +++ b/src/polyp/mainloop-api.c @@ -26,9 +26,10 @@ #include #include -#include "mainloop-api.h" -#include #include +#include + +#include "mainloop-api.h" struct once_info { void (*callback)(pa_mainloop_api*m, void *userdata); diff --git a/src/polyp/mainloop-signal.c b/src/polyp/mainloop-signal.c index a03c9159..e474f461 100644 --- a/src/polyp/mainloop-signal.c +++ b/src/polyp/mainloop-signal.c @@ -36,12 +36,13 @@ #include #endif -#include #include #include #include #include +#include "mainloop-signal.h" + struct pa_signal_event { int sig; #ifdef HAVE_SIGACTION diff --git a/src/polyp/mainloop.c b/src/polyp/mainloop.c index 3fa9245c..71ea9bc4 100644 --- a/src/polyp/mainloop.c +++ b/src/polyp/mainloop.c @@ -38,14 +38,15 @@ #include "poll.h" #endif -#include +#include "../polypcore/winsock.h" -#include "mainloop.h" #include #include #include #include +#include "mainloop.h" + struct pa_io_event { pa_mainloop *mainloop; int dead; diff --git a/src/polyp/operation.c b/src/polyp/operation.c index 0baa661b..5440cf9e 100644 --- a/src/polyp/operation.c +++ b/src/polyp/operation.c @@ -26,7 +26,9 @@ #include #include + #include "internal.h" + #include "operation.h" pa_operation *pa_operation_new(pa_context *c, pa_stream *s) { diff --git a/src/polyp/scache.c b/src/polyp/scache.c index c274e359..393b069e 100644 --- a/src/polyp/scache.c +++ b/src/polyp/scache.c @@ -28,10 +28,12 @@ #include #include -#include "scache.h" -#include "internal.h" #include +#include "internal.h" + +#include "scache.h" + void pa_stream_connect_upload(pa_stream *s, size_t length) { pa_tagstruct *t; uint32_t tag; diff --git a/src/polyp/simple.c b/src/polyp/simple.c index 19c49c9b..e14cab2e 100644 --- a/src/polyp/simple.c +++ b/src/polyp/simple.c @@ -28,13 +28,15 @@ #include #include -#include "simple.h" -#include "polypaudio.h" -#include "mainloop.h" +#include +#include + #include #include #include +#include "simple.h" + struct pa_simple { pa_mainloop *mainloop; pa_context *context; diff --git a/src/polyp/stream.c b/src/polyp/stream.c index 007d5e24..6e5bc067 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -28,12 +28,13 @@ #include #include -#include "internal.h" #include #include #include #include +#include "internal.h" + #define LATENCY_IPOL_INTERVAL_USEC (10000L) pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map) { diff --git a/src/polyp/subscribe.c b/src/polyp/subscribe.c index c481f525..b90e0bf1 100644 --- a/src/polyp/subscribe.c +++ b/src/polyp/subscribe.c @@ -26,10 +26,12 @@ #include #include -#include "subscribe.h" -#include "internal.h" -#include #include +#include + +#include "internal.h" + +#include "subscribe.h" void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_context *c = userdata; diff --git a/src/polyp/version.h.in b/src/polyp/version.h.in index c727381f..67b7495b 100644 --- a/src/polyp/version.h.in +++ b/src/polyp/version.h.in @@ -24,6 +24,8 @@ /* WARNING: Make sure to edit the real source file version.h.in! */ +#include + /** \file * Define header version */ diff --git a/src/polypcore/authkey-prop.c b/src/polypcore/authkey-prop.c index 8657f5a5..3faf0ef1 100644 --- a/src/polypcore/authkey-prop.c +++ b/src/polypcore/authkey-prop.c @@ -22,10 +22,11 @@ #include #include -#include "xmalloc.h" +#include +#include +#include + #include "authkey-prop.h" -#include "props.h" -#include "log.h" struct authkey_data { int ref; diff --git a/src/polypcore/authkey-prop.h b/src/polypcore/authkey-prop.h index 29b40bb2..63fde5d8 100644 --- a/src/polypcore/authkey-prop.h +++ b/src/polypcore/authkey-prop.h @@ -22,7 +22,7 @@ USA. ***/ -#include "core.h" +#include /* The authkey-prop uses a central property to store a previously * loaded cookie in memory. Useful for sharing the same cookie between diff --git a/src/polypcore/authkey.c b/src/polypcore/authkey.c index 969f09d9..e3fc9f60 100644 --- a/src/polypcore/authkey.c +++ b/src/polypcore/authkey.c @@ -35,10 +35,11 @@ #include #include +#include +#include +#include + #include "authkey.h" -#include "util.h" -#include "log.h" -#include "random.h" /* Generate a new authorization key, store it in file fd and return it in *data */ static int generate(int fd, void *ret_data, size_t length) { diff --git a/src/polypcore/autoload.c b/src/polypcore/autoload.c index 83df8ef7..8d2dca30 100644 --- a/src/polypcore/autoload.c +++ b/src/polypcore/autoload.c @@ -27,14 +27,15 @@ #include #include +#include +#include +#include +#include +#include +#include +#include + #include "autoload.h" -#include "module.h" -#include "xmalloc.h" -#include "memchunk.h" -#include "sound-file.h" -#include "log.h" -#include "core-scache.h" -#include "core-subscribe.h" static void entry_free(pa_autoload_entry *e) { assert(e); diff --git a/src/polypcore/autoload.h b/src/polypcore/autoload.h index 7350c16a..a8931fc7 100644 --- a/src/polypcore/autoload.h +++ b/src/polypcore/autoload.h @@ -22,7 +22,7 @@ USA. ***/ -#include "namereg.h" +#include /* Using the autoloading facility, modules by be loaded on-demand and * synchronously. The user may register a "ghost sink" or "ghost diff --git a/src/polypcore/cli-command.c b/src/polypcore/cli-command.c index dd4cbe46..6c9fc4b1 100644 --- a/src/polypcore/cli-command.c +++ b/src/polypcore/cli-command.c @@ -29,26 +29,27 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "cli-command.h" -#include "module.h" -#include "sink.h" -#include "source.h" -#include "client.h" -#include "sink-input.h" -#include "source-output.h" -#include "tokenizer.h" -#include "strbuf.h" -#include "namereg.h" -#include "cli-text.h" -#include "core-scache.h" -#include "sample-util.h" -#include "sound-file.h" -#include "play-memchunk.h" -#include "autoload.h" -#include "xmalloc.h" -#include "sound-file-stream.h" -#include "props.h" -#include "util.h" struct command { const char *name; diff --git a/src/polypcore/cli-command.h b/src/polypcore/cli-command.h index 78b8d5c6..e7c70ecf 100644 --- a/src/polypcore/cli-command.h +++ b/src/polypcore/cli-command.h @@ -22,8 +22,8 @@ USA. ***/ -#include "strbuf.h" -#include "core.h" +#include +#include /* Execute a single CLI command. Write the results to the string * buffer *buf. If *fail is non-zero the function will return -1 when diff --git a/src/polypcore/cli-text.c b/src/polypcore/cli-text.c index d8446b06..8bffd0a7 100644 --- a/src/polypcore/cli-text.c +++ b/src/polypcore/cli-text.c @@ -26,19 +26,20 @@ #include #include -#include "cli-text.h" -#include "module.h" -#include "client.h" -#include "sink.h" -#include "source.h" -#include "sink-input.h" -#include "source-output.h" -#include "strbuf.h" -#include "sample-util.h" -#include "core-scache.h" -#include "autoload.h" -#include "xmalloc.h" #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cli-text.h" char *pa_module_list_to_string(pa_core *c) { pa_strbuf *s; diff --git a/src/polypcore/cli-text.h b/src/polypcore/cli-text.h index 7a1a0361..a8f40003 100644 --- a/src/polypcore/cli-text.h +++ b/src/polypcore/cli-text.h @@ -22,7 +22,7 @@ USA. ***/ -#include "core.h" +#include /* Some functions to generate pretty formatted listings of * entities. The returned strings have to be freed manually. */ diff --git a/src/polypcore/cli.c b/src/polypcore/cli.c index bc0c285d..295ce625 100644 --- a/src/polypcore/cli.c +++ b/src/polypcore/cli.c @@ -28,21 +28,22 @@ #include #include -#include "ioline.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "cli.h" -#include "module.h" -#include "sink.h" -#include "source.h" -#include "client.h" -#include "sink-input.h" -#include "source-output.h" -#include "tokenizer.h" -#include "strbuf.h" -#include "namereg.h" -#include "cli-text.h" -#include "cli-command.h" -#include "xmalloc.h" -#include "log.h" #define PROMPT ">>> " diff --git a/src/polypcore/cli.h b/src/polypcore/cli.h index 03f31c22..12ffd848 100644 --- a/src/polypcore/cli.h +++ b/src/polypcore/cli.h @@ -22,9 +22,9 @@ USA. ***/ -#include "iochannel.h" -#include "core.h" -#include "module.h" +#include +#include +#include typedef struct pa_cli pa_cli; diff --git a/src/polypcore/client.c b/src/polypcore/client.c index 9b256794..7fe5a9fc 100644 --- a/src/polypcore/client.c +++ b/src/polypcore/client.c @@ -28,10 +28,11 @@ #include #include +#include +#include +#include + #include "client.h" -#include "xmalloc.h" -#include "core-subscribe.h" -#include "log.h" pa_client *pa_client_new(pa_core *core, const char *name, const char *driver) { pa_client *c; diff --git a/src/polypcore/client.h b/src/polypcore/client.h index 92430338..8ddc6d94 100644 --- a/src/polypcore/client.h +++ b/src/polypcore/client.h @@ -22,8 +22,8 @@ USA. ***/ -#include "core.h" -#include "module.h" +#include +#include /* Every connection to the server should have a pa_client * attached. That way the user may generate a listing of all connected diff --git a/src/polypcore/conf-parser.c b/src/polypcore/conf-parser.c index 507f2bf1..7eeda02b 100644 --- a/src/polypcore/conf-parser.c +++ b/src/polypcore/conf-parser.c @@ -28,10 +28,11 @@ #include #include +#include +#include +#include + #include "conf-parser.h" -#include "log.h" -#include "util.h" -#include "xmalloc.h" #define WHITESPACE " \t\n" #define COMMENTS "#;\n" diff --git a/src/polypcore/core-scache.c b/src/polypcore/core-scache.c index 0d926aba..69199a33 100644 --- a/src/polypcore/core-scache.c +++ b/src/polypcore/core-scache.c @@ -41,19 +41,20 @@ #include #endif -#include "core-scache.h" -#include "sink-input.h" #include -#include "sample-util.h" -#include "play-memchunk.h" -#include "xmalloc.h" -#include "core-subscribe.h" -#include "namereg.h" -#include "sound-file.h" -#include "util.h" -#include "log.h" #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core-scache.h" #define UNLOAD_POLL_TIME 2 diff --git a/src/polypcore/core-scache.h b/src/polypcore/core-scache.h index 0918ebe4..a383e50a 100644 --- a/src/polypcore/core-scache.h +++ b/src/polypcore/core-scache.h @@ -22,9 +22,9 @@ USA. ***/ -#include "core.h" -#include "memchunk.h" -#include "sink.h" +#include +#include +#include typedef struct pa_scache_entry { pa_core *core; diff --git a/src/polypcore/core-subscribe.c b/src/polypcore/core-subscribe.c index 2a258604..4d792966 100644 --- a/src/polypcore/core-subscribe.c +++ b/src/polypcore/core-subscribe.c @@ -26,10 +26,11 @@ #include #include -#include "queue.h" +#include +#include +#include + #include "core-subscribe.h" -#include "xmalloc.h" -#include "log.h" /* The subscription subsystem may be used to be notified whenever an * entity (sink, source, ...) is created or deleted. Modules may diff --git a/src/polypcore/core-subscribe.h b/src/polypcore/core-subscribe.h index bc9dcba3..7c856954 100644 --- a/src/polypcore/core-subscribe.h +++ b/src/polypcore/core-subscribe.h @@ -25,8 +25,8 @@ typedef struct pa_subscription pa_subscription; typedef struct pa_subscription_event pa_subscription_event; -#include "core.h" -#include "native-common.h" +#include +#include pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata); void pa_subscription_free(pa_subscription*s); diff --git a/src/polypcore/core.c b/src/polypcore/core.c index 9d040e68..0093aebd 100644 --- a/src/polypcore/core.c +++ b/src/polypcore/core.c @@ -28,18 +28,19 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "core.h" -#include "module.h" -#include "sink.h" -#include "source.h" -#include "namereg.h" -#include "util.h" -#include "core-scache.h" -#include "autoload.h" -#include "xmalloc.h" -#include "core-subscribe.h" -#include "props.h" -#include "random.h" pa_core* pa_core_new(pa_mainloop_api *m) { pa_core* c; diff --git a/src/polypcore/core.h b/src/polypcore/core.h index 29329025..a323ae8e 100644 --- a/src/polypcore/core.h +++ b/src/polypcore/core.h @@ -24,14 +24,14 @@ typedef struct pa_core pa_core; -#include "idxset.h" -#include "hashmap.h" +#include +#include #include #include -#include "memblock.h" -#include "resampler.h" -#include "queue.h" -#include "core-subscribe.h" +#include +#include +#include +#include /* The core structure of polypaudio. Every polypaudio daemon contains * exactly one of these. It is used for storing kind of global diff --git a/src/polypcore/dynarray.c b/src/polypcore/dynarray.c index 435fd768..1aff7f51 100644 --- a/src/polypcore/dynarray.c +++ b/src/polypcore/dynarray.c @@ -27,8 +27,9 @@ #include #include +#include + #include "dynarray.h" -#include "xmalloc.h" /* If the array becomes to small, increase its size by 100 entries */ #define INCREASE_BY 100 diff --git a/src/polypcore/hashmap.c b/src/polypcore/hashmap.c index a37decb8..8861fd3d 100644 --- a/src/polypcore/hashmap.c +++ b/src/polypcore/hashmap.c @@ -27,10 +27,11 @@ #include #include +#include +#include +#include + #include "hashmap.h" -#include "idxset.h" -#include "xmalloc.h" -#include "log.h" #define BUCKETS 1023 diff --git a/src/polypcore/idxset.c b/src/polypcore/idxset.c index 409d1fab..8d3a2370 100644 --- a/src/polypcore/idxset.c +++ b/src/polypcore/idxset.c @@ -28,8 +28,9 @@ #include #include +#include + #include "idxset.h" -#include "xmalloc.h" typedef struct idxset_entry { void *data; diff --git a/src/polypcore/iochannel.c b/src/polypcore/iochannel.c index 273d47e0..7fd09152 100644 --- a/src/polypcore/iochannel.c +++ b/src/polypcore/iochannel.c @@ -30,10 +30,11 @@ #include "winsock.h" +#include +#include +#include + #include "iochannel.h" -#include "util.h" -#include "socket-util.h" -#include "xmalloc.h" struct pa_iochannel { int ifd, ofd; diff --git a/src/polypcore/ioline.c b/src/polypcore/ioline.c index 5b669f5c..3f2de5a2 100644 --- a/src/polypcore/ioline.c +++ b/src/polypcore/ioline.c @@ -29,9 +29,10 @@ #include #include +#include +#include + #include "ioline.h" -#include "xmalloc.h" -#include "log.h" #define BUFFER_LIMIT (64*1024) #define READ_SIZE (1024) diff --git a/src/polypcore/ioline.h b/src/polypcore/ioline.h index 84ccb47a..e2dadf55 100644 --- a/src/polypcore/ioline.h +++ b/src/polypcore/ioline.h @@ -22,8 +22,8 @@ USA. ***/ -#include "iochannel.h" -#include "util.h" +#include +#include /* An ioline wraps an iochannel for line based communication. A * callback function is called whenever a new line has been recieved diff --git a/src/polypcore/log.c b/src/polypcore/log.c index 97406f79..c7bf7be9 100644 --- a/src/polypcore/log.c +++ b/src/polypcore/log.c @@ -31,9 +31,10 @@ #include #endif +#include +#include + #include "log.h" -#include "xmalloc.h" -#include "util.h" #define ENV_LOGLEVEL "POLYP_LOG" diff --git a/src/polypcore/log.h b/src/polypcore/log.h index ce8aea98..c306acaf 100644 --- a/src/polypcore/log.h +++ b/src/polypcore/log.h @@ -23,7 +23,7 @@ ***/ #include -#include "gccmacro.h" +#include /* A simple logging subsystem */ diff --git a/src/polypcore/mcalign.c b/src/polypcore/mcalign.c index 4d765625..0f229e28 100644 --- a/src/polypcore/mcalign.c +++ b/src/polypcore/mcalign.c @@ -28,8 +28,9 @@ #include #include +#include + #include "mcalign.h" -#include "xmalloc.h" struct pa_mcalign { size_t base; diff --git a/src/polypcore/mcalign.h b/src/polypcore/mcalign.h index 5de75bc7..a9107e0e 100644 --- a/src/polypcore/mcalign.h +++ b/src/polypcore/mcalign.h @@ -22,8 +22,8 @@ USA. ***/ -#include "memblock.h" -#include "memchunk.h" +#include +#include /* An alignment object, used for aligning memchunks to multiples of * the frame size. */ diff --git a/src/polypcore/memblock.c b/src/polypcore/memblock.c index 8da53525..2c0bef57 100644 --- a/src/polypcore/memblock.c +++ b/src/polypcore/memblock.c @@ -28,8 +28,9 @@ #include #include +#include + #include "memblock.h" -#include "xmalloc.h" static void stat_add(pa_memblock*m, pa_memblock_stat *s) { assert(m); diff --git a/src/polypcore/memblockq.c b/src/polypcore/memblockq.c index ba6b76ea..4a0225e5 100644 --- a/src/polypcore/memblockq.c +++ b/src/polypcore/memblockq.c @@ -30,10 +30,11 @@ #include #include +#include +#include +#include + #include "memblockq.h" -#include "xmalloc.h" -#include "log.h" -#include "mcalign.h" struct memblock_list { struct memblock_list *next, *prev; diff --git a/src/polypcore/memblockq.h b/src/polypcore/memblockq.h index 1695daba..7bb25f90 100644 --- a/src/polypcore/memblockq.h +++ b/src/polypcore/memblockq.h @@ -24,8 +24,8 @@ #include -#include "memblock.h" -#include "memchunk.h" +#include +#include /* A memblockq is a queue of pa_memchunks (yepp, the name is not * perfect). It is similar to the ring buffers used by most other diff --git a/src/polypcore/memchunk.c b/src/polypcore/memchunk.c index bfd74f9e..d6856ab8 100644 --- a/src/polypcore/memchunk.c +++ b/src/polypcore/memchunk.c @@ -28,8 +28,9 @@ #include #include +#include + #include "memchunk.h" -#include "xmalloc.h" void pa_memchunk_make_writable(pa_memchunk *c, pa_memblock_stat *s, size_t min) { pa_memblock *n; diff --git a/src/polypcore/memchunk.h b/src/polypcore/memchunk.h index 4eefc8c1..3ddb28ee 100644 --- a/src/polypcore/memchunk.h +++ b/src/polypcore/memchunk.h @@ -22,7 +22,7 @@ USA. ***/ -#include "memblock.h" +#include /* A memchunk describes a part of a memblock. In contrast to the memblock, a * memchunk is not allocated dynamically or reference counted, instead diff --git a/src/polypcore/modargs.c b/src/polypcore/modargs.c index 07062946..6bd13c3b 100644 --- a/src/polypcore/modargs.c +++ b/src/polypcore/modargs.c @@ -28,15 +28,16 @@ #include #include -#include "hashmap.h" +#include +#include +#include +#include +#include +#include +#include +#include + #include "modargs.h" -#include "idxset.h" -#include "sample-util.h" -#include "namereg.h" -#include "sink.h" -#include "source.h" -#include "xmalloc.h" -#include "util.h" struct entry { char *key, *value; diff --git a/src/polypcore/modargs.h b/src/polypcore/modargs.h index 678ea1a7..47e2d522 100644 --- a/src/polypcore/modargs.h +++ b/src/polypcore/modargs.h @@ -24,7 +24,7 @@ #include #include -#include "core.h" +#include typedef struct pa_modargs pa_modargs; diff --git a/src/polypcore/modinfo.c b/src/polypcore/modinfo.c index 53440612..4204bb34 100644 --- a/src/polypcore/modinfo.c +++ b/src/polypcore/modinfo.c @@ -26,10 +26,11 @@ #include #include -#include "xmalloc.h" -#include "util.h" +#include +#include +#include + #include "modinfo.h" -#include "log.h" #define PA_SYMBOL_AUTHOR "pa__get_author" #define PA_SYMBOL_DESCRIPTION "pa__get_description" diff --git a/src/polypcore/module.c b/src/polypcore/module.c index 73ec5bd4..75385354 100644 --- a/src/polypcore/module.c +++ b/src/polypcore/module.c @@ -30,11 +30,12 @@ #include #include +#include +#include +#include +#include + #include "module.h" -#include "xmalloc.h" -#include "core-subscribe.h" -#include "log.h" -#include "util.h" #define PA_SYMBOL_INIT "pa__init" #define PA_SYMBOL_DONE "pa__done" diff --git a/src/polypcore/module.h b/src/polypcore/module.h index 6f137c15..03b9bc87 100644 --- a/src/polypcore/module.h +++ b/src/polypcore/module.h @@ -25,8 +25,8 @@ #include #include -#include "core.h" -#include "modinfo.h" +#include +#include typedef struct pa_module pa_module; diff --git a/src/polypcore/namereg.c b/src/polypcore/namereg.c index ca03c455..d4dbd14b 100644 --- a/src/polypcore/namereg.c +++ b/src/polypcore/namereg.c @@ -29,13 +29,14 @@ #include #include +#include +#include +#include +#include +#include +#include + #include "namereg.h" -#include "autoload.h" -#include "source.h" -#include "sink.h" -#include "xmalloc.h" -#include "core-subscribe.h" -#include "util.h" struct namereg_entry { pa_namereg_type_t type; diff --git a/src/polypcore/namereg.h b/src/polypcore/namereg.h index 961fd44b..a98295ff 100644 --- a/src/polypcore/namereg.h +++ b/src/polypcore/namereg.h @@ -22,7 +22,7 @@ USA. ***/ -#include "core.h" +#include typedef enum pa_namereg_type { PA_NAMEREG_SINK, diff --git a/src/polypcore/packet.c b/src/polypcore/packet.c index b3a2e074..41803cf9 100644 --- a/src/polypcore/packet.c +++ b/src/polypcore/packet.c @@ -26,8 +26,9 @@ #include #include +#include + #include "packet.h" -#include "xmalloc.h" pa_packet* pa_packet_new(size_t length) { pa_packet *p; diff --git a/src/polypcore/parseaddr.c b/src/polypcore/parseaddr.c index 5e4c689c..c2b25c89 100644 --- a/src/polypcore/parseaddr.c +++ b/src/polypcore/parseaddr.c @@ -27,8 +27,9 @@ #include #include -#include "xmalloc.h" -#include "util.h" +#include +#include + #include "parseaddr.h" /* Parse addresses in one of the following forms: diff --git a/src/polypcore/pdispatch.c b/src/polypcore/pdispatch.c index 5a50a0d5..7941e4a8 100644 --- a/src/polypcore/pdispatch.c +++ b/src/polypcore/pdispatch.c @@ -27,12 +27,13 @@ #include #include +#include +#include +#include +#include +#include + #include "pdispatch.h" -#include "native-common.h" -#include "xmalloc.h" -#include "llist.h" -#include "log.h" -#include "util.h" /*#define DEBUG_OPCODES */ diff --git a/src/polypcore/pdispatch.h b/src/polypcore/pdispatch.h index fdd4d7f5..57666259 100644 --- a/src/polypcore/pdispatch.h +++ b/src/polypcore/pdispatch.h @@ -23,9 +23,9 @@ ***/ #include -#include "tagstruct.h" -#include "packet.h" #include +#include +#include typedef struct pa_pdispatch pa_pdispatch; diff --git a/src/polypcore/pid.c b/src/polypcore/pid.c index ae3dc7f5..3f33365a 100644 --- a/src/polypcore/pid.c +++ b/src/polypcore/pid.c @@ -39,9 +39,10 @@ #include #endif +#include +#include + #include "pid.h" -#include "util.h" -#include "log.h" /* Read the PID data from the file descriptor fd, and return it. If no * pid could be read, return 0, on failure (pid_t) -1 */ diff --git a/src/polypcore/play-memchunk.c b/src/polypcore/play-memchunk.c index e24d4427..ec79254b 100644 --- a/src/polypcore/play-memchunk.c +++ b/src/polypcore/play-memchunk.c @@ -28,10 +28,11 @@ #include #include +#include +#include +#include + #include "play-memchunk.h" -#include "sink-input.h" -#include "xmalloc.h" -#include "gccmacro.h" static void sink_input_kill(pa_sink_input *i) { pa_memchunk *c; diff --git a/src/polypcore/play-memchunk.h b/src/polypcore/play-memchunk.h index fc0654a6..72aeda95 100644 --- a/src/polypcore/play-memchunk.h +++ b/src/polypcore/play-memchunk.h @@ -22,8 +22,8 @@ USA. ***/ -#include "sink.h" -#include "memchunk.h" +#include +#include int pa_play_memchunk( pa_sink *sink, diff --git a/src/polypcore/poll.c b/src/polypcore/poll.c index 193fc812..6a29a953 100644 --- a/src/polypcore/poll.c +++ b/src/polypcore/poll.c @@ -42,7 +42,8 @@ #ifndef HAVE_SYS_POLL_H -#include "util.h" +#include + #include "poll.h" int poll (struct pollfd *fds, unsigned long int nfds, int timeout) { diff --git a/src/polypcore/props.c b/src/polypcore/props.c index df748c1e..96cdc4f2 100644 --- a/src/polypcore/props.c +++ b/src/polypcore/props.c @@ -21,9 +21,10 @@ #include -#include "xmalloc.h" +#include +#include + #include "props.h" -#include "log.h" typedef struct pa_property { char *name; /* Points to memory allocated by the property subsystem */ diff --git a/src/polypcore/props.h b/src/polypcore/props.h index 5abf8787..9430db5e 100644 --- a/src/polypcore/props.h +++ b/src/polypcore/props.h @@ -22,8 +22,8 @@ USA. ***/ -#include "core.h" -#include "strbuf.h" +#include +#include /* The property subsystem is to be used to share data between * modules. Consider them to be kind of "global" variables for a diff --git a/src/polypcore/protocol-cli.c b/src/polypcore/protocol-cli.c index d2d73550..cb7e8f6f 100644 --- a/src/polypcore/protocol-cli.c +++ b/src/polypcore/protocol-cli.c @@ -26,10 +26,11 @@ #include #include +#include +#include +#include + #include "protocol-cli.h" -#include "cli.h" -#include "xmalloc.h" -#include "log.h" /* Don't allow more than this many concurrent connections */ #define MAX_CONNECTIONS 25 diff --git a/src/polypcore/protocol-cli.h b/src/polypcore/protocol-cli.h index aed733c1..c47b14d6 100644 --- a/src/polypcore/protocol-cli.h +++ b/src/polypcore/protocol-cli.h @@ -22,10 +22,10 @@ USA. ***/ -#include "core.h" -#include "socket-server.h" -#include "module.h" -#include "modargs.h" +#include +#include +#include +#include typedef struct pa_protocol_cli pa_protocol_cli; diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index d2c0f354..a16ac280 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -30,24 +30,26 @@ #include #include -#include "protocol-esound.h" -#include "esound.h" -#include "memblock.h" -#include "client.h" -#include "sink-input.h" -#include "sink.h" -#include "source-output.h" -#include "source.h" #include -#include "core-scache.h" -#include "sample-util.h" -#include "authkey.h" -#include "namereg.h" -#include "xmalloc.h" -#include "log.h" -#include "util.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "endianmacros.h" +#include "protocol-esound.h" + /* Don't accept more connection than this */ #define MAX_CONNECTIONS 10 diff --git a/src/polypcore/protocol-esound.h b/src/polypcore/protocol-esound.h index 71d58464..a94d1c72 100644 --- a/src/polypcore/protocol-esound.h +++ b/src/polypcore/protocol-esound.h @@ -22,10 +22,10 @@ USA. ***/ -#include "core.h" -#include "socket-server.h" -#include "module.h" -#include "modargs.h" +#include +#include +#include +#include typedef struct pa_protocol_esound pa_protocol_esound; diff --git a/src/polypcore/protocol-http.c b/src/polypcore/protocol-http.c index 3e55df03..f0b78124 100644 --- a/src/polypcore/protocol-http.c +++ b/src/polypcore/protocol-http.c @@ -28,12 +28,13 @@ #include #include +#include +#include +#include +#include +#include + #include "protocol-http.h" -#include "ioline.h" -#include "xmalloc.h" -#include "log.h" -#include "namereg.h" -#include "cli-text.h" /* Don't allow more than this many concurrent connections */ #define MAX_CONNECTIONS 10 diff --git a/src/polypcore/protocol-http.h b/src/polypcore/protocol-http.h index 0a1855e9..10dd656b 100644 --- a/src/polypcore/protocol-http.h +++ b/src/polypcore/protocol-http.h @@ -22,10 +22,10 @@ USA. ***/ -#include "core.h" -#include "socket-server.h" -#include "module.h" -#include "modargs.h" +#include +#include +#include +#include typedef struct pa_protocol_http pa_protocol_http; diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 31983bc2..1362fdf2 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -28,27 +28,28 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "protocol-native.h" -#include "native-common.h" -#include "packet.h" -#include "client.h" -#include "source-output.h" -#include "sink-input.h" -#include "pstream.h" -#include "tagstruct.h" -#include "pdispatch.h" -#include "pstream-util.h" -#include "authkey.h" -#include "namereg.h" -#include "core-scache.h" -#include "xmalloc.h" -#include "util.h" -#include "core-subscribe.h" -#include "log.h" -#include "autoload.h" -#include "authkey-prop.h" -#include "strlist.h" -#include "props.h" /* Kick a client if it doesn't authenticate within this time */ #define AUTH_TIMEOUT 5 diff --git a/src/polypcore/protocol-native.h b/src/polypcore/protocol-native.h index 12e85d0b..88aa8494 100644 --- a/src/polypcore/protocol-native.h +++ b/src/polypcore/protocol-native.h @@ -22,10 +22,10 @@ USA. ***/ -#include "core.h" -#include "socket-server.h" -#include "module.h" -#include "modargs.h" +#include +#include +#include +#include typedef struct pa_protocol_native pa_protocol_native; diff --git a/src/polypcore/protocol-simple.c b/src/polypcore/protocol-simple.c index 113919b3..4d3f8e1d 100644 --- a/src/polypcore/protocol-simple.c +++ b/src/polypcore/protocol-simple.c @@ -30,14 +30,15 @@ #include #include -#include "sink-input.h" -#include "source-output.h" +#include +#include +#include +#include +#include +#include +#include + #include "protocol-simple.h" -#include "client.h" -#include "sample-util.h" -#include "namereg.h" -#include "xmalloc.h" -#include "log.h" /* Don't allow more than this many concurrent connections */ #define MAX_CONNECTIONS 10 diff --git a/src/polypcore/protocol-simple.h b/src/polypcore/protocol-simple.h index 63455a53..f11c7759 100644 --- a/src/polypcore/protocol-simple.h +++ b/src/polypcore/protocol-simple.h @@ -22,10 +22,10 @@ USA. ***/ -#include "socket-server.h" -#include "module.h" -#include "core.h" -#include "modargs.h" +#include +#include +#include +#include typedef struct pa_protocol_simple pa_protocol_simple; diff --git a/src/polypcore/pstream-util.c b/src/polypcore/pstream-util.c index ecd63d15..62986456 100644 --- a/src/polypcore/pstream-util.c +++ b/src/polypcore/pstream-util.c @@ -25,7 +25,8 @@ #include -#include "native-common.h" +#include + #include "pstream-util.h" void pa_pstream_send_tagstruct(pa_pstream *p, pa_tagstruct *t) { diff --git a/src/polypcore/pstream-util.h b/src/polypcore/pstream-util.h index 601a9e99..c400c6d8 100644 --- a/src/polypcore/pstream-util.h +++ b/src/polypcore/pstream-util.h @@ -23,8 +23,8 @@ ***/ #include -#include "pstream.h" -#include "tagstruct.h" +#include +#include /* The tagstruct is freed!*/ void pa_pstream_send_tagstruct(pa_pstream *p, pa_tagstruct *t); diff --git a/src/polypcore/pstream.c b/src/polypcore/pstream.c index bd00ba4f..eec93a0f 100644 --- a/src/polypcore/pstream.c +++ b/src/polypcore/pstream.c @@ -34,10 +34,11 @@ #include "winsock.h" +#include +#include +#include + #include "pstream.h" -#include "queue.h" -#include "xmalloc.h" -#include "log.h" typedef enum pa_pstream_descriptor_index { PA_PSTREAM_DESCRIPTOR_LENGTH, diff --git a/src/polypcore/pstream.h b/src/polypcore/pstream.h index ec63a98e..10ce58f6 100644 --- a/src/polypcore/pstream.h +++ b/src/polypcore/pstream.h @@ -24,11 +24,11 @@ #include -#include "packet.h" -#include "memblock.h" -#include "iochannel.h" #include -#include "memchunk.h" +#include +#include +#include +#include typedef struct pa_pstream pa_pstream; diff --git a/src/polypcore/queue.c b/src/polypcore/queue.c index 80ec0068..77ca1ed3 100644 --- a/src/polypcore/queue.c +++ b/src/polypcore/queue.c @@ -26,8 +26,9 @@ #include #include +#include + #include "queue.h" -#include "xmalloc.h" struct queue_entry { struct queue_entry *next; diff --git a/src/polypcore/random.c b/src/polypcore/random.c index 12f27bfd..756c3218 100644 --- a/src/polypcore/random.c +++ b/src/polypcore/random.c @@ -31,9 +31,10 @@ #include #include +#include +#include + #include "random.h" -#include "util.h" -#include "log.h" #ifndef OS_IS_WIN32 #define RANDOM_DEVICE "/dev/urandom" diff --git a/src/polypcore/resampler.c b/src/polypcore/resampler.c index 0417e44e..c1740bf1 100644 --- a/src/polypcore/resampler.c +++ b/src/polypcore/resampler.c @@ -30,10 +30,11 @@ #include #include +#include +#include +#include + #include "resampler.h" -#include "sconv.h" -#include "xmalloc.h" -#include "log.h" struct pa_resampler { pa_resample_method_t resample_method; diff --git a/src/polypcore/resampler.h b/src/polypcore/resampler.h index cad48be5..2f4d3cbe 100644 --- a/src/polypcore/resampler.h +++ b/src/polypcore/resampler.h @@ -25,9 +25,9 @@ #include #include -#include "memblock.h" -#include "memchunk.h" #include +#include +#include typedef struct pa_resampler pa_resampler; diff --git a/src/polypcore/sample-util.c b/src/polypcore/sample-util.c index 52974c46..e3bb4aa6 100644 --- a/src/polypcore/sample-util.c +++ b/src/polypcore/sample-util.c @@ -30,7 +30,8 @@ #include -#include "log.h" +#include + #include "sample-util.h" pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) { diff --git a/src/polypcore/sample-util.h b/src/polypcore/sample-util.h index d0efbcc4..486d284b 100644 --- a/src/polypcore/sample-util.h +++ b/src/polypcore/sample-util.h @@ -23,9 +23,9 @@ ***/ #include -#include "memblock.h" -#include "memchunk.h" #include +#include +#include pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec); void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec); diff --git a/src/polypcore/sconv-s16le.c b/src/polypcore/sconv-s16le.c index e47c5e8e..0814c35b 100644 --- a/src/polypcore/sconv-s16le.c +++ b/src/polypcore/sconv-s16le.c @@ -28,10 +28,12 @@ #include +#include +#include + #include "endianmacros.h" -#include "sconv.h" + #include "sconv-s16le.h" -#include "log.h" #ifndef INT16_FROM #define INT16_FROM INT16_FROM_LE diff --git a/src/polypcore/sconv.c b/src/polypcore/sconv.c index 1fcb5a0c..c557be67 100644 --- a/src/polypcore/sconv.c +++ b/src/polypcore/sconv.c @@ -30,13 +30,14 @@ #include #include -#include "endianmacros.h" -#include "sconv.h" -#include "g711.h" +#include +#include "endianmacros.h" #include "sconv-s16le.h" #include "sconv-s16be.h" +#include "sconv.h" + static void u8_to_float32ne(unsigned n, const void *a, float *b) { const uint8_t *ca = a; static const double add = -128.0/127.0, factor = 1.0/127.0; diff --git a/src/polypcore/sink-input.c b/src/polypcore/sink-input.c index 696c47a4..1dc7df0f 100644 --- a/src/polypcore/sink-input.c +++ b/src/polypcore/sink-input.c @@ -28,11 +28,12 @@ #include #include +#include +#include +#include +#include + #include "sink-input.h" -#include "sample-util.h" -#include "xmalloc.h" -#include "core-subscribe.h" -#include "log.h" #define CONVERT_BUFFER_LENGTH 4096 diff --git a/src/polypcore/sink-input.h b/src/polypcore/sink-input.h index a5ad1958..e4b8bda4 100644 --- a/src/polypcore/sink-input.h +++ b/src/polypcore/sink-input.h @@ -26,12 +26,12 @@ typedef struct pa_sink_input pa_sink_input; -#include "sink.h" #include -#include "memblockq.h" -#include "resampler.h" -#include "module.h" -#include "client.h" +#include +#include +#include +#include +#include typedef enum pa_sink_input_state { PA_SINK_INPUT_RUNNING, diff --git a/src/polypcore/sink.c b/src/polypcore/sink.c index 6c143463..9bc478c3 100644 --- a/src/polypcore/sink.c +++ b/src/polypcore/sink.c @@ -28,15 +28,16 @@ #include #include -#include "sink.h" -#include "sink-input.h" -#include "namereg.h" -#include "util.h" -#include "sample-util.h" -#include "xmalloc.h" -#include "core-subscribe.h" -#include "log.h" #include +#include +#include +#include +#include +#include +#include +#include + +#include "sink.h" #define MAX_MIX_CHANNELS 32 diff --git a/src/polypcore/sink.h b/src/polypcore/sink.h index 268461ef..5fd9784f 100644 --- a/src/polypcore/sink.h +++ b/src/polypcore/sink.h @@ -26,13 +26,13 @@ typedef struct pa_sink pa_sink; -#include "core.h" #include -#include "idxset.h" -#include "source.h" #include -#include "module.h" #include +#include +#include +#include +#include #define PA_MAX_INPUTS_PER_SINK 6 diff --git a/src/polypcore/sioman.c b/src/polypcore/sioman.c index 8d7b136c..b389ecee 100644 --- a/src/polypcore/sioman.c +++ b/src/polypcore/sioman.c @@ -24,6 +24,7 @@ #endif #include + #include "sioman.h" static int stdio_inuse = 0; diff --git a/src/polypcore/socket-client.c b/src/polypcore/socket-client.c index 29c9775e..3662e89c 100644 --- a/src/polypcore/socket-client.c +++ b/src/polypcore/socket-client.c @@ -54,12 +54,13 @@ #include "winsock.h" +#include +#include +#include +#include +#include + #include "socket-client.h" -#include "socket-util.h" -#include "util.h" -#include "xmalloc.h" -#include "log.h" -#include "parseaddr.h" #define CONNECT_TIMEOUT 5 diff --git a/src/polypcore/socket-client.h b/src/polypcore/socket-client.h index 624880d7..d0005331 100644 --- a/src/polypcore/socket-client.h +++ b/src/polypcore/socket-client.h @@ -25,7 +25,7 @@ #include #include -#include "iochannel.h" +#include struct sockaddr; diff --git a/src/polypcore/socket-server.c b/src/polypcore/socket-server.c index 262b32a7..d1646984 100644 --- a/src/polypcore/socket-server.c +++ b/src/polypcore/socket-server.c @@ -58,11 +58,12 @@ #include "winsock.h" +#include +#include +#include +#include + #include "socket-server.h" -#include "socket-util.h" -#include "xmalloc.h" -#include "util.h" -#include "log.h" struct pa_socket_server { int ref; diff --git a/src/polypcore/socket-server.h b/src/polypcore/socket-server.h index 4d8bfad5..6bb83427 100644 --- a/src/polypcore/socket-server.h +++ b/src/polypcore/socket-server.h @@ -24,7 +24,7 @@ #include #include -#include "iochannel.h" +#include /* It is safe to destroy the calling socket_server object from the callback */ diff --git a/src/polypcore/socket-util.c b/src/polypcore/socket-util.c index 032a3c91..5ffe5302 100644 --- a/src/polypcore/socket-util.c +++ b/src/polypcore/socket-util.c @@ -59,10 +59,11 @@ #include "winsock.h" +#include +#include +#include + #include "socket-util.h" -#include "util.h" -#include "xmalloc.h" -#include "log.h" void pa_socket_peer_to_string(int fd, char *c, size_t l) { struct stat st; diff --git a/src/polypcore/sound-file-stream.c b/src/polypcore/sound-file-stream.c index 881e3077..644e578f 100644 --- a/src/polypcore/sound-file-stream.c +++ b/src/polypcore/sound-file-stream.c @@ -30,10 +30,11 @@ #include +#include +#include +#include + #include "sound-file-stream.h" -#include "sink-input.h" -#include "xmalloc.h" -#include "log.h" #define BUF_SIZE (1024*10) diff --git a/src/polypcore/sound-file-stream.h b/src/polypcore/sound-file-stream.h index 2e56ef49..5effc7f0 100644 --- a/src/polypcore/sound-file-stream.h +++ b/src/polypcore/sound-file-stream.h @@ -22,7 +22,7 @@ USA. ***/ -#include "sink.h" +#include int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume); diff --git a/src/polypcore/sound-file.c b/src/polypcore/sound-file.c index a81c283a..cf23e0ac 100644 --- a/src/polypcore/sound-file.c +++ b/src/polypcore/sound-file.c @@ -28,9 +28,10 @@ #include -#include "sound-file.h" #include -#include "log.h" +#include + +#include "sound-file.h" #define MAX_FILE_SIZE (1024*1024) diff --git a/src/polypcore/sound-file.h b/src/polypcore/sound-file.h index f3003bb9..ffa551b5 100644 --- a/src/polypcore/sound-file.h +++ b/src/polypcore/sound-file.h @@ -22,8 +22,8 @@ USA. ***/ -#include "memchunk.h" #include +#include int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_memchunk *chunk, pa_memblock_stat *s); diff --git a/src/polypcore/source-output.c b/src/polypcore/source-output.c index 9b75a8b0..d6201b4d 100644 --- a/src/polypcore/source-output.c +++ b/src/polypcore/source-output.c @@ -28,10 +28,11 @@ #include #include +#include +#include +#include + #include "source-output.h" -#include "xmalloc.h" -#include "core-subscribe.h" -#include "log.h" pa_source_output* pa_source_output_new( pa_source *s, diff --git a/src/polypcore/source-output.h b/src/polypcore/source-output.h index 4b1cbf15..98f6ab0c 100644 --- a/src/polypcore/source-output.h +++ b/src/polypcore/source-output.h @@ -26,12 +26,12 @@ typedef struct pa_source_output pa_source_output; -#include "source.h" #include -#include "memblockq.h" -#include "resampler.h" -#include "module.h" -#include "client.h" +#include +#include +#include +#include +#include typedef enum { PA_SOURCE_OUTPUT_RUNNING, diff --git a/src/polypcore/source.c b/src/polypcore/source.c index c64f7b99..b70cb129 100644 --- a/src/polypcore/source.c +++ b/src/polypcore/source.c @@ -28,12 +28,13 @@ #include #include +#include +#include +#include +#include +#include + #include "source.h" -#include "source-output.h" -#include "namereg.h" -#include "xmalloc.h" -#include "core-subscribe.h" -#include "log.h" pa_source* pa_source_new( pa_core *core, diff --git a/src/polypcore/source.h b/src/polypcore/source.h index be2fb985..a267e73c 100644 --- a/src/polypcore/source.h +++ b/src/polypcore/source.h @@ -25,14 +25,15 @@ typedef struct pa_source pa_source; #include -#include "core.h" + #include -#include "idxset.h" -#include "memblock.h" -#include "memchunk.h" -#include "sink.h" #include -#include "module.h" +#include +#include +#include +#include +#include +#include #define PA_MAX_OUTPUTS_PER_SOURCE 16 diff --git a/src/polypcore/strbuf.h b/src/polypcore/strbuf.h index a88f5190..4b06a7e6 100644 --- a/src/polypcore/strbuf.h +++ b/src/polypcore/strbuf.h @@ -22,7 +22,7 @@ USA. ***/ -#include "gccmacro.h" +#include typedef struct pa_strbuf pa_strbuf; diff --git a/src/polypcore/strlist.c b/src/polypcore/strlist.c index 09eb0c8a..e165aefd 100644 --- a/src/polypcore/strlist.c +++ b/src/polypcore/strlist.c @@ -26,10 +26,11 @@ #include #include +#include +#include +#include + #include "strlist.h" -#include "xmalloc.h" -#include "strbuf.h" -#include "util.h" struct pa_strlist { pa_strlist *next; diff --git a/src/polypcore/tagstruct.c b/src/polypcore/tagstruct.c index 676f67de..1f5f370b 100644 --- a/src/polypcore/tagstruct.c +++ b/src/polypcore/tagstruct.c @@ -36,8 +36,9 @@ #include "winsock.h" +#include + #include "tagstruct.h" -#include "xmalloc.h" struct pa_tagstruct { diff --git a/src/polypcore/tokenizer.c b/src/polypcore/tokenizer.c index 5e0c1b16..556a190a 100644 --- a/src/polypcore/tokenizer.c +++ b/src/polypcore/tokenizer.c @@ -27,10 +27,11 @@ #include #include +#include +#include +#include + #include "tokenizer.h" -#include "dynarray.h" -#include "xmalloc.h" -#include "gccmacro.h" struct pa_tokenizer { pa_dynarray *dynarray; diff --git a/src/polypcore/util.c b/src/polypcore/util.c index 4b6edb97..a53c36bc 100644 --- a/src/polypcore/util.c +++ b/src/polypcore/util.c @@ -70,9 +70,10 @@ #include "winsock.h" +#include +#include + #include "util.h" -#include "xmalloc.h" -#include "log.h" #ifndef OS_IS_WIN32 #define PA_RUNTIME_PATH_PREFIX "/tmp/polypaudio-" diff --git a/src/polypcore/util.h b/src/polypcore/util.h index 3dc6c945..14f763a3 100644 --- a/src/polypcore/util.h +++ b/src/polypcore/util.h @@ -27,8 +27,8 @@ #include #include -#include "gccmacro.h" #include +#include struct timeval; diff --git a/src/polypcore/x11wrap.c b/src/polypcore/x11wrap.c index e20a50a6..9414fbdf 100644 --- a/src/polypcore/x11wrap.c +++ b/src/polypcore/x11wrap.c @@ -22,11 +22,12 @@ #include #include -#include "llist.h" +#include +#include +#include +#include + #include "x11wrap.h" -#include "xmalloc.h" -#include "log.h" -#include "props.h" typedef struct pa_x11_internal pa_x11_internal; diff --git a/src/polypcore/x11wrap.h b/src/polypcore/x11wrap.h index 15645168..15969869 100644 --- a/src/polypcore/x11wrap.h +++ b/src/polypcore/x11wrap.h @@ -24,7 +24,7 @@ #include -#include "core.h" +#include typedef struct pa_x11_wrapper pa_x11_wrapper; diff --git a/src/polypcore/xmalloc.c b/src/polypcore/xmalloc.c index bf366347..4c8689a6 100644 --- a/src/polypcore/xmalloc.c +++ b/src/polypcore/xmalloc.c @@ -27,11 +27,12 @@ #include #include #include +#include + +#include +#include -#include "memory.h" -#include "util.h" #include "xmalloc.h" -#include "gccmacro.h" /* Make sure not to allocate more than this much memory. */ #define MAX_ALLOC_SIZE (1024*1024*20) /* 20MB */ diff --git a/src/tests/cpulimit-test.c b/src/tests/cpulimit-test.c index 97a8a0dd..b51014c8 100644 --- a/src/tests/cpulimit-test.c +++ b/src/tests/cpulimit-test.c @@ -29,7 +29,6 @@ #include #include -#include "../daemon/cpulimit.h" #include #include @@ -37,6 +36,8 @@ #include #endif +#include "../daemon/cpulimit.h" + /* A simple example for testing the cpulimit subsystem */ static time_t start; diff --git a/src/utils/pax11publish.c b/src/utils/pax11publish.c index 908a3507..56b62d37 100644 --- a/src/utils/pax11publish.c +++ b/src/utils/pax11publish.c @@ -36,7 +36,8 @@ #include #include #include -#include + +#include "../polyp/client-conf.h" int main(int argc, char *argv[]) { const char *dname = NULL, *sink = NULL, *source = NULL, *server = NULL, *cookie_file = PA_NATIVE_COOKIE_FILE; -- cgit From 1eae42f7ed6e5a3dffa896ecb266224854246206 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 17 Feb 2006 12:34:44 +0000 Subject: Make sure that all polypcore headers are installed. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@501 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 56 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 1e898a85..9fd24a05 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -406,36 +406,46 @@ libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 ################################### polypcoreinclude_HEADERS = \ + polypcore/autoload.h \ polypcore/cli-command.h \ + polypcore/cli-text.h \ polypcore/client.h \ polypcore/core.h \ + polypcore/core-scache.h \ + polypcore/core-subscribe.h \ + polypcore/conf-parser.h \ polypcore/dynarray.h \ - polypcore/endianmacros.h \ + polypcore/g711.h \ polypcore/hashmap.h \ polypcore/idxset.h \ - polypcore/iochannel.h \ polypcore/log.h \ + polypcore/mcalign.h \ polypcore/memblock.h \ polypcore/memblockq.h \ polypcore/memchunk.h \ polypcore/modargs.h \ + polypcore/modinfo.h \ polypcore/module.h \ polypcore/namereg.h \ + polypcore/pid.h \ + polypcore/play-memchunk.h \ + polypcore/props.h \ polypcore/queue.h \ + polypcore/random.h \ polypcore/resampler.h \ polypcore/sample-util.h \ + polypcore/sconv.h \ polypcore/sink.h \ polypcore/sink-input.h \ polypcore/sioman.h \ - polypcore/socket-server.h \ - polypcore/socket-client.h \ - polypcore/socket-util.h \ + polypcore/sound-file.h \ + polypcore/sound-file-stream.h \ polypcore/source.h \ polypcore/source-output.h \ polypcore/strbuf.h \ polypcore/tokenizer.h \ - polypcore/tagstruct.h \ - polypcore/util.h + polypcore/util.h \ + polypcore/xmalloc.h lib_LTLIBRARIES += libpolypcore.la @@ -456,6 +466,8 @@ libpolypcore_la_SOURCES += \ polypcore/client.c polypcore/client.h \ polypcore/conf-parser.c polypcore/conf-parser.h \ polypcore/core.c polypcore/core.h \ + polypcore/core-scache.c polypcore/core-scache.h \ + polypcore/core-subscribe.c polypcore/core-subscribe.h \ polypcore/dllmain.c \ polypcore/dynarray.c polypcore/dynarray.h \ polypcore/endianmacros.h \ @@ -479,7 +491,6 @@ libpolypcore_la_SOURCES += \ polypcore/random.c polypcore/random.h \ polypcore/resampler.c polypcore/resampler.h \ polypcore/sample-util.c polypcore/sample-util.h \ - polypcore/core-scache.c polypcore/core-scache.h \ polypcore/sconv.c polypcore/sconv.h \ polypcore/sconv-s16be.c polypcore/sconv-s16be.h \ polypcore/sconv-s16le.c polypcore/sconv-s16le.h \ @@ -491,7 +502,6 @@ libpolypcore_la_SOURCES += \ polypcore/source.c polypcore/source.h \ polypcore/source-output.c polypcore/source-output.h \ polypcore/strbuf.c polypcore/strbuf.h \ - polypcore/core-subscribe.c polypcore/core-subscribe.h \ polypcore/tokenizer.c polypcore/tokenizer.h \ polypcore/util.c polypcore/util.h \ polypcore/winsock.h \ @@ -505,6 +515,30 @@ libpolypcore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDF # Plug-in support libraries # ################################### +polypcoreinclude_HEADERS += \ + polypcore/socket-util.h \ + polypcore/iochannel.h \ + polypcore/socket-server.h \ + polypcore/socket-client.h \ + polypcore/parseaddr.h \ + polypcore/packet.h \ + polypcore/pstream.h \ + polypcore/ioline.h \ + polypcore/cli.h \ + polypcore/protocol-cli.h \ + polypcore/tagstruct.h \ + polypcore/pstream-util.h \ + polypcore/pdispatch.h \ + polypcore/authkey.h \ + polypcore/authkey-prop.h \ + polypcore/strlist.h \ + polypcore/protocol-simple.h \ + polypcore/esound.h \ + polypcore/protocol-esound.h \ + polypcore/native-common.h \ + polypcore/protocol-native.h \ + polypcore/protocol-http.h + ### Warning! Due to an obscure bug in libtool/automake it is required ### that the libraries in modlib_LTLIBRARIES are specified in-order, ### i.e. libraries near the end of the list depend on libraries near @@ -533,6 +567,10 @@ modlib_LTLIBRARIES = \ libprotocol-http.la if HAVE_X11 +polypcoreinclude_HEADERS += \ + polypcore/x11wrap.h \ + polypcore/x11prop.h + modlib_LTLIBRARIES += \ libx11wrap.la \ libx11prop.la -- cgit From da665d5e61d82e84a2ee5cda317a114143be0d12 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 17 Feb 2006 13:08:03 +0000 Subject: Integrate error routines into libpolyp. Not much point in having this as a separate library. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@502 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 9fd24a05..443a9793 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -141,17 +141,17 @@ endif bin_SCRIPTS = esdcompat.sh pacat_SOURCES = utils/pacat.c -pacat_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la +pacat_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la pacat_CFLAGS = $(AM_CFLAGS) pacat_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) paplay_SOURCES = utils/paplay.c -paplay_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) +paplay_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) paplay_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) paplay_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) pactl_SOURCES = utils/pactl.c -pactl_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) +pactl_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) pactl_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) pactl_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -166,7 +166,7 @@ pax11publish_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la $(X_PRE_LIBS) -lX11 pax11publish_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) pabrowse_SOURCES = utils/pabrowse.c -pabrowse_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-browse-@PA_MAJORMINOR@.la +pabrowse_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-browse-@PA_MAJORMINOR@.la pabrowse_CFLAGS = $(AM_CFLAGS) pabrowse_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -209,12 +209,12 @@ mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpolypcore.la mcalign_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) pacat_simple_SOURCES = tests/pacat-simple.c -pacat_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la +pacat_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la pacat_simple_CFLAGS = $(AM_CFLAGS) pacat_simple_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) parec_simple_SOURCES = tests/parec-simple.c -parec_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la +parec_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la parec_simple_CFLAGS = $(AM_CFLAGS) parec_simple_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -280,7 +280,6 @@ endif lib_LTLIBRARIES = \ libpolyp-@PA_MAJORMINOR@.la \ - libpolyp-error-@PA_MAJORMINOR@.la \ libpolyp-mainloop-@PA_MAJORMINOR@.la \ libpolyp-simple-@PA_MAJORMINOR@.la @@ -309,6 +308,7 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = \ polyp/polypaudio.h \ polyp/context.c polyp/context.h \ polyp/def.h \ + polyp/error.c polyp/error.h \ polyp/internal.h \ polyp/introspect.c polyp/introspect.h \ polyp/operation.c polyp/operation.h \ @@ -368,11 +368,6 @@ libpolyp_@PA_MAJORMINOR@_la_CFLAGS += $(LIBASYNCNS_CFLAGS) libpolyp_@PA_MAJORMINOR@_la_LIBADD += $(LIBASYNCNS_LIBS) endif -libpolyp_error_@PA_MAJORMINOR@_la_SOURCES = polyp/error.c polyp/error.h -libpolyp_error_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) -libpolyp_error_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la -libpolyp_error_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 - libpolyp_mainloop_@PA_MAJORMINOR@_la_SOURCES = \ polyp/mainloop.c polyp/mainloop.h \ polyp/mainloop-signal.c polyp/mainloop-signal.h \ -- cgit From c4cf7adacac03af50c52b6470bf620f76ce2f533 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 17 Feb 2006 13:11:37 +0000 Subject: Fix typo in #ifndef. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@503 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/mainloop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polyp/mainloop.c b/src/polyp/mainloop.c index 71ea9bc4..a694c144 100644 --- a/src/polyp/mainloop.c +++ b/src/polyp/mainloop.c @@ -323,7 +323,7 @@ pa_mainloop *pa_mainloop_new(void) { m = pa_xmalloc(sizeof(pa_mainloop)); -#ifndef OS_ISWIN32 +#ifndef OS_IS_WIN32 if (pipe(m->wakeup_pipe) < 0) { pa_xfree(m); return NULL; -- cgit From 2686857b8c4f512958a8bf2018f5394b16f1a2e4 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 17 Feb 2006 13:18:30 +0000 Subject: Fix path to poll.h. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@504 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/mainloop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polyp/mainloop.c b/src/polyp/mainloop.c index a694c144..e975d7d7 100644 --- a/src/polyp/mainloop.c +++ b/src/polyp/mainloop.c @@ -35,7 +35,7 @@ #ifdef HAVE_SYS_POLL_H #include #else -#include "poll.h" +#include "../polypcore/poll.h" #endif #include "../polypcore/winsock.h" -- cgit From 162a95d56631726cf7c142945da2a9660719df03 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 17 Feb 2006 13:18:53 +0000 Subject: Module needs stuff in libpolypcore. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@505 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index 443a9793..1be713ce 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1043,7 +1043,7 @@ module_waveout_la_CFLAGS = $(AM_CFLAGS) # Hardware autodetection module module_detect_la_SOURCES = modules/module-detect.c module_detect_la_LDFLAGS = -module -avoid-version -module_detect_la_LIBADD = $(AM_LIBADD) +module_detect_la_LIBADD = $(AM_LIBADD) libpolypcore.la module_detect_la_CFLAGS = $(AM_CFLAGS) ################################### -- cgit -- cgit From 45700da4ebf2986126d7a4d6889c028599fd3085 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 17 Feb 2006 15:42:47 +0000 Subject: Have a memblock queue on the client side during recording. This makes the record callback optional in stead of mandatory. For applications that wish to retain the old behaviour, simply call pa_stream_peek() followed by pa_stream_drop() in the callback. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@507 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 1 + src/polyp/context.c | 10 ++++----- src/polyp/internal.h | 5 ++++- src/polyp/stream.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/polyp/stream.h | 22 +++++++++++++++++-- src/utils/pacat.c | 10 +++++++-- 6 files changed, 98 insertions(+), 11 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 1be713ce..f973dc46 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -330,6 +330,7 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ polypcore/log.c polypcore/log.h \ polypcore/mcalign.c polypcore/mcalign.h \ polypcore/memblock.c polypcore/memblock.h \ + polypcore/memblockq.c polypcore/memblockq.h \ polypcore/memchunk.c polypcore/memchunk.h \ polypcore/native-common.h \ polypcore/packet.c polypcore/packet.h \ diff --git a/src/polyp/context.c b/src/polyp/context.c index b7f7eb99..c40041c5 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -273,11 +273,11 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, PA_GCC_UN if (pa_mcalign_pop(s->mcalign, &t) < 0) break; - - if (s->read_callback) { - s->read_callback(s, (uint8_t*) t.memblock->data + t.index, t.length, s->read_userdata); - s->counter += chunk->length; - } + + assert(s->record_memblockq); + pa_memblockq_push(s->record_memblockq, &t, t.length); + if (s->read_callback) + s->read_callback(s, pa_stream_readable_size(s), s->read_userdata); pa_memblock_unref(t.memblock); } diff --git a/src/polyp/internal.h b/src/polyp/internal.h index 762688c9..7f4d38ac 100644 --- a/src/polyp/internal.h +++ b/src/polyp/internal.h @@ -35,6 +35,7 @@ #include #include #include +#include #include "client-conf.h" @@ -98,6 +99,8 @@ struct pa_stream { pa_usec_t previous_ipol_time; pa_stream_state_t state; pa_mcalign *mcalign; + pa_memchunk peek_memchunk; + pa_memblockq *record_memblockq; int interpolate; int corked; @@ -110,7 +113,7 @@ struct pa_stream { void (*state_callback)(pa_stream*c, void *userdata); void *state_userdata; - void (*read_callback)(pa_stream *p, const void*data, size_t length, void *userdata); + void (*read_callback)(pa_stream *p, size_t length, void *userdata); void *read_userdata; void (*write_callback)(pa_stream *p, size_t length, void *userdata); diff --git a/src/polyp/stream.c b/src/polyp/stream.c index 6e5bc067..fef3c00f 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -103,6 +103,12 @@ static void stream_free(pa_stream *s) { s->mainloop->time_free(s->ipol_event); } + if (s->peek_memchunk.memblock) + pa_memblock_unref(s->peek_memchunk.memblock); + + if (s->record_memblockq) + pa_memblockq_free(s->record_memblockq); + pa_mcalign_free(s->mcalign); pa_xfree(s->name); @@ -263,6 +269,13 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED goto finish; } + if (s->direction == PA_STREAM_RECORD) { + assert(!s->record_memblockq); + s->record_memblockq = pa_memblockq_new(s->buffer_attr.maxlength, 0, + pa_frame_size(&s->sample_spec), 0, 0, s->context->memblock_stat); + assert(s->record_memblockq); + } + s->channel_valid = 1; pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); pa_stream_set_state(s, PA_STREAM_READY); @@ -391,11 +404,57 @@ void pa_stream_write(pa_stream *s, const void *data, size_t length, void (*free_ s->counter += length; } +void pa_stream_peek(pa_stream *s, void **data, size_t *length) { + assert(s && s->record_memblockq && data && length && s->state == PA_STREAM_READY && s->ref >= 1); + + if (!s->peek_memchunk.memblock) { + *data = NULL; + *length = 0; + + if (pa_memblockq_peek(s->record_memblockq, &s->peek_memchunk) < 0) + return; + + pa_memblockq_drop(s->record_memblockq, &s->peek_memchunk, s->peek_memchunk.length); + } + + *data = (char*)s->peek_memchunk.memblock->data + s->peek_memchunk.index; + *length = s->peek_memchunk.length; +} + +void pa_stream_drop(pa_stream *s) { + assert(s && s->peek_memchunk.memblock && s->state == PA_STREAM_READY && s->ref >= 1); + + s->counter += s->peek_memchunk.length; + + pa_memblock_unref(s->peek_memchunk.memblock); + + s->peek_memchunk.length = 0; + s->peek_memchunk.memblock = NULL; +} + size_t pa_stream_writable_size(pa_stream *s) { assert(s && s->ref >= 1); return s->state == PA_STREAM_READY ? s->requested_bytes : 0; } +size_t pa_stream_readable_size(pa_stream *s) { + size_t sz; + + assert(s && s->ref >= 1); + + if (s->state != PA_STREAM_READY) + return 0; + + assert(s->record_memblockq); + + sz = (size_t)pa_memblockq_get_length(s->record_memblockq); + + if (s->peek_memchunk.memblock) + sz += s->peek_memchunk.length; + + return sz; +} + pa_operation * pa_stream_drain(pa_stream *s, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata) { pa_operation *o; pa_tagstruct *t; @@ -554,7 +613,7 @@ void pa_stream_disconnect(pa_stream *s) { pa_stream_unref(s); } -void pa_stream_set_read_callback(pa_stream *s, void (*cb)(pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { +void pa_stream_set_read_callback(pa_stream *s, void (*cb)(pa_stream *p, size_t length, void *userdata), void *userdata) { assert(s && s->ref >= 1); s->read_callback = cb; s->read_userdata = userdata; diff --git a/src/polyp/stream.h b/src/polyp/stream.h index e20cfdd4..9bbda436 100644 --- a/src/polyp/stream.h +++ b/src/polyp/stream.h @@ -106,9 +106,25 @@ void pa_stream_write(pa_stream *p /**< The stream to use */, value is ignored on upload streams. */); +/** Read the next fragment from the buffer (for capture sources). + * data will point to the actual data and length will contain the size + * of the data in bytes (which can be less than a complete framgnet). + * Use pa_stream_drop() to actually remove the data from the buffer. + * \since 0.8 */ +void pa_stream_peek(pa_stream *p /**< The stream to use */, + void **data /**< Pointer to pointer that will point to data */, + size_t *length /**< The length of the data read */); + +/** Remove the current fragment. It is invalid to do this without first + * calling pa_stream_peek(). \since 0.8 */ +void pa_stream_drop(pa_stream *p); + /** Return the amount of bytes that may be written using pa_stream_write() */ size_t pa_stream_writable_size(pa_stream *p); +/** Return the ammount of bytes that may be read using pa_stream_read() \since 0.8 */ +size_t pa_stream_readable_size(pa_stream *p); + /** Drain a playback stream */ pa_operation* pa_stream_drain(pa_stream *s, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata); @@ -122,8 +138,10 @@ void pa_stream_set_state_callback(pa_stream *s, void (*cb)(pa_stream *s, void *u * written to the stream. */ void pa_stream_set_write_callback(pa_stream *p, void (*cb)(pa_stream *p, size_t length, void *userdata), void *userdata); -/** Set the callback function that is called when new data is available from the stream */ -void pa_stream_set_read_callback(pa_stream *p, void (*cb)(pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); +/** Set the callback function that is called when new data is available from the stream. + * Return the number of bytes read. \since 0.8 + */ +void pa_stream_set_read_callback(pa_stream *p, void (*cb)(pa_stream *p, size_t length, void *userdata), void *userdata); /** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. \since 0.3 */ pa_operation* pa_stream_cork(pa_stream *s, int b, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata); diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 3c50402f..a3c3f2c8 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -105,14 +105,19 @@ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { } /* This is called whenever new data may is available */ -static void stream_read_callback(pa_stream *s, const void*data, size_t length, void *userdata) { - assert(s && data && length); +static void stream_read_callback(pa_stream *s, size_t length, void *userdata) { + assert(s && length); + void *data; if (stdio_event) mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT); + pa_stream_peek(s, &data, &length); + assert(data && length); + if (buffer) { fprintf(stderr, "Buffer overrun, dropping incoming data\n"); + pa_stream_drop(s); return; } @@ -120,6 +125,7 @@ static void stream_read_callback(pa_stream *s, const void*data, size_t length, v assert(buffer); memcpy(buffer, data, length); buffer_index = 0; + pa_stream_drop(s); } /* This routine is called whenever the stream state changes */ -- cgit From d142c12c608b6fe594549961b1a5d845b60b1a1c Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 17 Feb 2006 16:48:44 +0000 Subject: That's a delta parameter, not a size parameter. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@508 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polyp/context.c b/src/polyp/context.c index c40041c5..6b778562 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -275,7 +275,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, PA_GCC_UN break; assert(s->record_memblockq); - pa_memblockq_push(s->record_memblockq, &t, t.length); + pa_memblockq_push(s->record_memblockq, &t, 0); if (s->read_callback) s->read_callback(s, pa_stream_readable_size(s), s->read_userdata); -- cgit From b26df7e4a0df6783d4b8ef4bb18d4d2ae5695912 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 17 Feb 2006 17:00:33 +0000 Subject: Properly clear members during init. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@509 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/stream.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/polyp/stream.c b/src/polyp/stream.c index fef3c00f..35de2d01 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -78,6 +78,11 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->mcalign = pa_mcalign_new(pa_frame_size(ss), c->memblock_stat); + s->peek_memchunk.length = 0; + s->peek_memchunk.memblock = NULL; + + s->record_memblockq = NULL; + s->counter = 0; s->previous_time = 0; s->previous_ipol_time = 0; -- cgit From 0876b1ba82ea9c988df90ca98d202765ac697313 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 18 Feb 2006 14:58:25 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@510 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/todo b/doc/todo index 345171a6..41333b75 100644 --- a/doc/todo +++ b/doc/todo @@ -3,7 +3,6 @@ Architectural changes: - add API for synchronizing multiple sinks/sources to a common clock - absolutely indexed write()s from client -- remove "polyplib-" prefix Fixes: - improve module-oss-mmap latency measurement @@ -13,11 +12,10 @@ Fixes: Features: - add radio module -- xmlrpc - dbus/hal -- rendezvous autotunnel module - polish for starting polypaudio as root/system-wide instance -- export connection fd +- add threading API +- add support for auth using SCM_CREDENTIALS Long term: - pass meta info for hearing impaired @@ -35,4 +33,5 @@ Done: - channel mapping ("left", "right", "rear", "subwoofer") - hardware volume support - alsa-lib +- remove "polyplib-" prefix -- cgit From 304449002cbc84fdcf235b5dfaec891278dd7085 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 04:05:16 +0000 Subject: 1) Add flexible seeking support (including absolute) for memory block queues and playback streams 2) Add support to synchronize multiple playback streams 3) add two tests for 1) and 2) 4) s/PA_ERROR/PA_ERR/ 5) s/PA_ERROR_OK/PA_OK/ 6) update simple API to deal properly with new peek/drop recording API 7) add beginnings of proper validity checking on API calls in client libs (needs to be extended) 8) report playback buffer overflows/underflows to the client 9) move client side recording mcalign stuff into the memblockq 10) create typedefs for a bunch of API callback prototypes 11) simplify handling of HUP poll() events Yes, i know, it's usually better to commit a lot of small patches instead of a single big one. In this case however, this would have contradicted the other rule: never commit broken or incomplete stuff. *** This stuff needs a lot of additional testing! *** git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@511 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 22 +- src/modules/module-combine.c | 12 +- src/modules/module-tunnel.c | 4 +- src/polyp/context.c | 73 +++-- src/polyp/def.h | 45 +-- src/polyp/error.c | 37 +-- src/polyp/error.h | 2 +- src/polyp/internal.h | 37 ++- src/polyp/introspect.c | 24 +- src/polyp/simple.c | 41 +-- src/polyp/stream.c | 366 ++++++++++++++++------- src/polyp/stream.h | 140 ++++----- src/polyp/subscribe.c | 2 +- src/polypcore/iochannel.c | 45 ++- src/polypcore/llist.h | 10 + src/polypcore/mcalign.c | 27 +- src/polypcore/mcalign.h | 3 + src/polypcore/memblock.c | 7 +- src/polypcore/memblock.h | 1 - src/polypcore/memblockq.c | 622 +++++++++++++++++++++++++++++----------- src/polypcore/memblockq.h | 102 ++++--- src/polypcore/native-common.h | 16 +- src/polypcore/packet.c | 25 +- src/polypcore/packet.h | 2 +- src/polypcore/protocol-esound.c | 62 ++-- src/polypcore/protocol-native.c | 388 ++++++++++++++++++------- src/polypcore/protocol-simple.c | 66 ++++- src/polypcore/pstream.c | 140 +++++---- src/polypcore/pstream.h | 5 +- src/polypcore/sample-util.c | 9 + src/polypcore/sample-util.h | 1 + src/polypcore/sink.c | 2 + src/polypcore/sink.h | 2 +- src/tests/memblockq-test.c | 147 ++++++++++ src/tests/sync-playback.c | 192 +++++++++++++ src/utils/pacat.c | 6 +- src/utils/pactl.c | 2 +- src/utils/paplay.c | 4 +- 38 files changed, 1939 insertions(+), 752 deletions(-) create mode 100644 src/tests/memblockq-test.c create mode 100644 src/tests/sync-playback.c diff --git a/src/Makefile.am b/src/Makefile.am index f973dc46..4cf61f27 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -180,7 +180,9 @@ noinst_PROGRAMS = \ pacat-simple \ parec-simple \ strlist-test \ - voltest + voltest \ + memblockq-test \ + sync-playback if HAVE_SIGXCPU noinst_PROGRAMS += \ @@ -248,6 +250,24 @@ mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MA mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12-@PA_MAJORMINOR@.la mainloop_test_glib12_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +memblockq_test_SOURCES = \ + tests/memblockq-test.c \ + polypcore/memblockq.c \ + polypcore/log.c \ + polypcore/memblock.c \ + polypcore/xmalloc.c \ + polypcore/util.c \ + polypcore/mcalign.c \ + polypcore/memchunk.c +memblockq_test_CFLAGS = $(AM_CFLAGS) +memblockq_test_LDADD = $(AM_LDADD) +memblockq_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +sync_playback_SOURCES = tests/sync-playback.c +sync_playback_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la +sync_playback_CFLAGS = $(AM_CFLAGS) +sync_playback_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + ################################### # Client library # ################################### diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index aabb8f28..750eca67 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -144,7 +144,7 @@ static void request_memblock(struct userdata *u) { return; for (o = u->outputs; o; o = o->next) - pa_memblockq_push_align(o->memblockq, &chunk, 0); + pa_memblockq_push_align(o->memblockq, &chunk); pa_memblock_unref(chunk.memblock); } @@ -212,7 +212,15 @@ static struct output *output_new(struct userdata *u, pa_sink *sink, int resample o->userdata = u; o->counter = 0; - o->memblockq = pa_memblockq_new(MEMBLOCKQ_MAXLENGTH, MEMBLOCKQ_MAXLENGTH, pa_frame_size(&u->sink->sample_spec), 0, 0, sink->core->memblock_stat); + o->memblockq = pa_memblockq_new( + 0, + MEMBLOCKQ_MAXLENGTH, + MEMBLOCKQ_MAXLENGTH, + pa_frame_size(&u->sink->sample_spec), + 1, + 0, + NULL, + sink->core->memblock_stat); snprintf(t, sizeof(t), "%s: output #%u", u->sink->name, u->n_outputs+1); if (!(o->sink_input = pa_sink_input_new(sink, __FILE__, t, &u->sink->sample_spec, &u->sink->channel_map, 1, resample_method))) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 61b9bb3b..67236588 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -214,7 +214,7 @@ static void send_bytes(struct userdata *u) { return; } - pa_pstream_send_memblock(u->pstream, u->channel, 0, &chunk); + pa_pstream_send_memblock(u->pstream, u->channel, 0, PA_SEEK_RELATIVE, &chunk); pa_memblock_unref(chunk.memblock); if (chunk.length > u->requested_bytes) @@ -442,7 +442,7 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *user } #ifndef TUNNEL_SINK -static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata) { +static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { struct userdata *u = userdata; assert(p && chunk && u); diff --git a/src/polyp/context.c b/src/polyp/context.c index 6b778562..eac5dd23 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -74,6 +74,8 @@ static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { [PA_COMMAND_REQUEST] = pa_command_request, + [PA_COMMAND_OVERFLOW] = pa_command_overflow_or_underflow, + [PA_COMMAND_UNDERFLOW] = pa_command_overflow_or_underflow, [PA_COMMAND_PLAYBACK_STREAM_KILLED] = pa_command_stream_killed, [PA_COMMAND_RECORD_STREAM_KILLED] = pa_command_stream_killed, [PA_COMMAND_SUBSCRIBE_EVENT] = pa_command_subscribe_event @@ -109,9 +111,10 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { PA_LLIST_HEAD_INIT(pa_stream, c->streams); PA_LLIST_HEAD_INIT(pa_operation, c->operations); - c->error = PA_ERROR_OK; + c->error = PA_OK; c->state = PA_CONTEXT_UNCONNECTED; c->ctag = 0; + c->csyncid = 0; c->state_callback = NULL; c->state_userdata = NULL; @@ -234,14 +237,24 @@ void pa_context_set_state(pa_context *c, pa_context_state_t st) { void pa_context_fail(pa_context *c, int error) { assert(c); - c->error = error; + + pa_context_set_error(c, error); pa_context_set_state(c, PA_CONTEXT_FAILED); } +int pa_context_set_error(pa_context *c, int error) { + assert(error >= 0 && error < PA_ERR_MAX); + + if (c) + c->error = error; + + return error; +} + static void pstream_die_callback(pa_pstream *p, void *userdata) { pa_context *c = userdata; assert(p && c); - pa_context_fail(c, PA_ERROR_CONNECTIONTERMINATED); + pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED); } static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { @@ -252,34 +265,34 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *user if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { pa_log(__FILE__": invalid packet.\n"); - pa_context_fail(c, PA_ERROR_PROTOCOL); + pa_context_fail(c, PA_ERR_PROTOCOL); } pa_context_unref(c); } -static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, PA_GCC_UNUSED uint32_t delta, const pa_memchunk *chunk, void *userdata) { +static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { pa_context *c = userdata; pa_stream *s; - assert(p && chunk && c && chunk->memblock && chunk->memblock->data); + + assert(p); + assert(chunk); + assert(chunk->memblock); + assert(chunk->length); + assert(c); pa_context_ref(c); if ((s = pa_dynarray_get(c->record_streams, channel))) { - pa_mcalign_push(s->mcalign, chunk); - for (;;) { - pa_memchunk t; - - if (pa_mcalign_pop(s->mcalign, &t) < 0) - break; + pa_memblockq_seek(s->record_memblockq, offset, seek); + pa_memblockq_push_align(s->record_memblockq, chunk); - assert(s->record_memblockq); - pa_memblockq_push(s->record_memblockq, &t, 0); - if (s->read_callback) - s->read_callback(s, pa_stream_readable_size(s), s->read_userdata); + if (s->read_callback) { + size_t l; - pa_memblock_unref(t.memblock); + if ((l = pa_memblockq_get_length(s->record_memblockq)) > 0) + s->read_callback(s, l, s->read_userdata); } } @@ -293,14 +306,14 @@ int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t) { assert(t); if (pa_tagstruct_getu32(t, &c->error) < 0) { - pa_context_fail(c, PA_ERROR_PROTOCOL); + pa_context_fail(c, PA_ERR_PROTOCOL); return -1; } } else if (command == PA_COMMAND_TIMEOUT) - c->error = PA_ERROR_TIMEOUT; + c->error = PA_ERR_TIMEOUT; else { - pa_context_fail(c, PA_ERROR_PROTOCOL); + pa_context_fail(c, PA_ERR_PROTOCOL); return -1; } @@ -316,7 +329,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(c, command, t) < 0) - pa_context_fail(c, PA_ERROR_PROTOCOL); + pa_context_fail(c, PA_ERR_PROTOCOL); pa_context_fail(c, c->error); goto finish; @@ -368,7 +381,7 @@ static void setup_context(pa_context *c, pa_iochannel *io) { assert(c->pdispatch); if (!c->conf->cookie_valid) { - pa_context_fail(c, PA_ERROR_AUTHKEY); + pa_context_fail(c, PA_ERR_AUTHKEY); goto finish; } @@ -401,7 +414,7 @@ static int context_connect_spawn(pa_context *c) { if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { pa_log(__FILE__": socketpair() failed: %s\n", strerror(errno)); - pa_context_fail(c, PA_ERROR_INTERNAL); + pa_context_fail(c, PA_ERR_INTERNAL); goto fail; } @@ -415,7 +428,7 @@ static int context_connect_spawn(pa_context *c) { if ((pid = fork()) < 0) { pa_log(__FILE__": fork() failed: %s\n", strerror(errno)); - pa_context_fail(c, PA_ERROR_INTERNAL); + pa_context_fail(c, PA_ERR_INTERNAL); if (c->spawn_api.postfork) c->spawn_api.postfork(); @@ -471,10 +484,10 @@ static int context_connect_spawn(pa_context *c) { if (r < 0) { pa_log(__FILE__": waitpid() failed: %s\n", strerror(errno)); - pa_context_fail(c, PA_ERROR_INTERNAL); + pa_context_fail(c, PA_ERR_INTERNAL); goto fail; } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); goto fail; } @@ -527,7 +540,7 @@ static int try_next_connection(pa_context *c) { } #endif - pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); goto finish; } @@ -569,7 +582,7 @@ static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userd goto finish; } - pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); goto finish; } @@ -593,7 +606,7 @@ int pa_context_connect(pa_context *c, const char *server, int spawn, const pa_sp if (server) { if (!(c->server_list = pa_strlist_parse(server))) { - pa_context_fail(c, PA_ERROR_INVALIDSERVER); + pa_context_fail(c, PA_ERR_INVALIDSERVER); goto finish; } } else { @@ -759,7 +772,7 @@ void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_U success = 0; } else if (!pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } diff --git a/src/polyp/def.h b/src/polyp/def.h index ba35b31e..f8e0bed4 100644 --- a/src/polyp/def.h +++ b/src/polyp/def.h @@ -47,7 +47,7 @@ typedef enum pa_context_state { /** The state of a stream */ typedef enum pa_stream_state { - PA_STREAM_DISCONNECTED, /**< The stream is not yet connected to any sink or source */ + PA_STREAM_UNCONNECTED, /**< The stream is not yet connected to any sink or source */ PA_STREAM_CREATING, /**< The stream is being created */ PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */ PA_STREAM_FAILED, /**< An error occured that made the stream invalid */ @@ -103,22 +103,24 @@ typedef struct pa_buffer_attr { /** Error values as used by pa_context_errno(). Use pa_strerror() to convert these values to human readable strings */ enum { - PA_ERROR_OK, /**< No error */ - PA_ERROR_ACCESS, /**< Access failure */ - PA_ERROR_COMMAND, /**< Unknown command */ - PA_ERROR_INVALID, /**< Invalid argument */ - PA_ERROR_EXIST, /**< Entity exists */ - PA_ERROR_NOENTITY, /**< No such entity */ - PA_ERROR_CONNECTIONREFUSED, /**< Connection refused */ - PA_ERROR_PROTOCOL, /**< Protocol error */ - PA_ERROR_TIMEOUT, /**< Timeout */ - PA_ERROR_AUTHKEY, /**< No authorization key */ - PA_ERROR_INTERNAL, /**< Internal error */ - PA_ERROR_CONNECTIONTERMINATED, /**< Connection terminated */ - PA_ERROR_KILLED, /**< Entity killed */ - PA_ERROR_INVALIDSERVER, /**< Invalid server */ - PA_ERROR_INITFAILED, /**< Module initialization failed */ - PA_ERROR_MAX /**< Not really an error but the first invalid error code */ + PA_OK = 0, /**< No error */ + PA_ERR_ACCESS, /**< Access failure */ + PA_ERR_COMMAND, /**< Unknown command */ + PA_ERR_INVALID, /**< Invalid argument */ + PA_ERR_EXIST, /**< Entity exists */ + PA_ERR_NOENTITY, /**< No such entity */ + PA_ERR_CONNECTIONREFUSED, /**< Connection refused */ + PA_ERR_PROTOCOL, /**< Protocol error */ + PA_ERR_TIMEOUT, /**< Timeout */ + PA_ERR_AUTHKEY, /**< No authorization key */ + PA_ERR_INTERNAL, /**< Internal error */ + PA_ERR_CONNECTIONTERMINATED, /**< Connection terminated */ + PA_ERR_KILLED, /**< Entity killed */ + PA_ERR_INVALIDSERVER, /**< Invalid server */ + PA_ERR_MODINITFAILED, /**< Module initialization failed */ + PA_ERR_BADSTATE, /**< Bad state */ + PA_ERR_NODATA, /**< No data */ + PA_ERR_MAX /**< Not really an error but the first invalid error code */ }; /** Subscription event mask, as used by pa_context_subscribe() */ @@ -208,6 +210,15 @@ typedef struct pa_spawn_api { * passed to the new process. */ } pa_spawn_api; +/** Seek type \since 0.8*/ +typedef enum pa_seek_mode { + PA_SEEK_RELATIVE = 0, /**< Seek relatively to the write index */ + PA_SEEK_ABSOLUTE = 1, /**< Seek relatively to the start of the buffer queue */ + PA_SEEK_RELATIVE_ON_READ = 2, /**< Seek relatively to the read index */ + PA_SEEK_RELATIVE_END = 3, /**< Seek relatively to the current end of the buffer queue */ +} pa_seek_mode_t; + + PA_C_DECL_END #endif diff --git a/src/polyp/error.c b/src/polyp/error.c index ece77bf2..eff37cc8 100644 --- a/src/polyp/error.c +++ b/src/polyp/error.c @@ -30,25 +30,28 @@ #include "error.h" -static const char* const errortab[PA_ERROR_MAX] = { - [PA_ERROR_OK] = "OK", - [PA_ERROR_ACCESS] = "Access denied", - [PA_ERROR_COMMAND] = "Unknown command", - [PA_ERROR_INVALID] = "Invalid argument", - [PA_ERROR_EXIST] = "Entity exists", - [PA_ERROR_NOENTITY] = "No such entity", - [PA_ERROR_CONNECTIONREFUSED] = "Connection refused", - [PA_ERROR_PROTOCOL] = "Protocol error", - [PA_ERROR_TIMEOUT] = "Timeout", - [PA_ERROR_AUTHKEY] = "No authorization key", - [PA_ERROR_INTERNAL] = "Internal error", - [PA_ERROR_CONNECTIONTERMINATED] = "Connection terminated", - [PA_ERROR_KILLED] = "Entity killed", - [PA_ERROR_INVALIDSERVER] = "Invalid server", +static const char* const errortab[PA_ERR_MAX] = { + [PA_OK] = "OK", + [PA_ERR_ACCESS] = "Access denied", + [PA_ERR_COMMAND] = "Unknown command", + [PA_ERR_INVALID] = "Invalid argument", + [PA_ERR_EXIST] = "Entity exists", + [PA_ERR_NOENTITY] = "No such entity", + [PA_ERR_CONNECTIONREFUSED] = "Connection refused", + [PA_ERR_PROTOCOL] = "Protocol error", + [PA_ERR_TIMEOUT] = "Timeout", + [PA_ERR_AUTHKEY] = "No authorization key", + [PA_ERR_INTERNAL] = "Internal error", + [PA_ERR_CONNECTIONTERMINATED] = "Connection terminated", + [PA_ERR_KILLED] = "Entity killed", + [PA_ERR_INVALIDSERVER] = "Invalid server", + [PA_ERR_MODINITFAILED] = "Module initalization failed", + [PA_ERR_BADSTATE] = "Bad state", + [PA_ERR_NODATA] = "No data", }; -const char*pa_strerror(uint32_t error) { - if (error >= PA_ERROR_MAX) +const char*pa_strerror(int error) { + if (error < 0 || error >= PA_ERR_MAX) return NULL; return errortab[error]; diff --git a/src/polyp/error.h b/src/polyp/error.h index ff2507b2..9856c1af 100644 --- a/src/polyp/error.h +++ b/src/polyp/error.h @@ -31,7 +31,7 @@ PA_C_DECL_BEGIN /** Return a human readable error message for the specified numeric error code */ -const char* pa_strerror(uint32_t error); +const char* pa_strerror(int error); PA_C_DECL_END diff --git a/src/polyp/internal.h b/src/polyp/internal.h index 7f4d38ac..578969ee 100644 --- a/src/polyp/internal.h +++ b/src/polyp/internal.h @@ -54,8 +54,9 @@ struct pa_context { pa_dynarray *record_streams, *playback_streams; PA_LLIST_HEAD(pa_stream, streams); PA_LLIST_HEAD(pa_operation, operations); - + uint32_t ctag; + uint32_t csyncid; uint32_t error; pa_context_state_t state; @@ -90,6 +91,7 @@ struct pa_stream { pa_sample_spec sample_spec; pa_channel_map channel_map; uint32_t channel; + uint32_t syncid; int channel_valid; uint32_t device_index; pa_stream_direction_t direction; @@ -98,7 +100,6 @@ struct pa_stream { pa_usec_t previous_time; pa_usec_t previous_ipol_time; pa_stream_state_t state; - pa_mcalign *mcalign; pa_memchunk peek_memchunk; pa_memblockq *record_memblockq; @@ -110,14 +111,20 @@ struct pa_stream { pa_time_event *ipol_event; int ipol_requested; - void (*state_callback)(pa_stream*c, void *userdata); + pa_stream_notify_cb_t state_callback; void *state_userdata; - void (*read_callback)(pa_stream *p, size_t length, void *userdata); + pa_stream_request_cb_t read_callback; void *read_userdata; - void (*write_callback)(pa_stream *p, size_t length, void *userdata); + pa_stream_request_cb_t write_callback; void *write_userdata; + + pa_stream_notify_cb_t overflow_callback; + void *overflow_userdata; + + pa_stream_notify_cb_t underflow_callback; + void *underflow_userdata; }; typedef void (*pa_operation_callback)(void); @@ -136,6 +143,7 @@ struct pa_operation { void pa_command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); pa_operation *pa_operation_new(pa_context *c, pa_stream *s); void pa_operation_done(pa_operation *o); @@ -146,6 +154,7 @@ void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); void pa_context_fail(pa_context *c, int error); +int pa_context_set_error(pa_context *c, int error); void pa_context_set_state(pa_context *c, pa_context_state_t st); int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t); pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, void (*internal_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata), void (*cb)(void), void *userdata); @@ -154,5 +163,23 @@ void pa_stream_set_state(pa_stream *s, pa_stream_state_t st); void pa_stream_trash_ipol(pa_stream *s); +#define PA_CHECK_VALIDITY(context, expression, error) do { \ + if (!(expression)) \ + return -pa_context_set_error((context), (error)); \ +} while(0) + +#define PA_CHECK_VALIDITY_RETURN_NULL(context, expression, error) do { \ + if (!(expression)) { \ + pa_context_set_error((context), (error)); \ + return NULL; \ + } \ +} while(0) + +#define PA_CHECK_VALIDITY_RETURN_ANY(context, expression, error, value) do { \ + if (!(expression)) { \ + pa_context_set_error((context), (error)); \ + return value; \ + } \ +} while(0) #endif diff --git a/src/polyp/introspect.c b/src/polyp/introspect.c index 4af724b4..75ce3ff9 100644 --- a/src/polyp/introspect.c +++ b/src/polyp/introspect.c @@ -52,7 +52,7 @@ static void context_stat_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNU pa_tagstruct_getu32(t, &i.memblock_allocated_size) < 0 || pa_tagstruct_getu32(t, &i.scache_size) < 0 || !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } @@ -92,7 +92,7 @@ static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command, pa_tagstruct_getu32(t, &i.cookie) < 0 || !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } @@ -139,7 +139,7 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P pa_tagstruct_get_usec(t, &i.latency) < 0 || pa_tagstruct_gets(t, &i.driver) < 0) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } @@ -234,7 +234,7 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, pa_tagstruct_get_usec(t, &i.latency) < 0 || pa_tagstruct_gets(t, &i.driver) < 0) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } @@ -322,7 +322,7 @@ static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_getu32(t, &i.owner_module) < 0 || pa_tagstruct_gets(t, &i.driver) < 0 ) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } @@ -389,7 +389,7 @@ static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command, pa_tagstruct_gets(t, &i.argument) < 0 || pa_tagstruct_getu32(t, &i.n_used) < 0 || pa_tagstruct_get_boolean(t, &i.auto_unload) < 0) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } @@ -464,7 +464,7 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm pa_tagstruct_gets(t, &i.resample_method) < 0 || pa_tagstruct_gets(t, &i.driver) < 0) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } @@ -538,7 +538,7 @@ static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t c pa_tagstruct_gets(t, &i.resample_method) < 0 || pa_tagstruct_gets(t, &i.driver) < 0) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } @@ -677,7 +677,7 @@ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, pa_tagstruct_get_boolean(t, &i.lazy) < 0 || pa_tagstruct_gets(t, &i.filename) < 0) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } @@ -787,7 +787,7 @@ static void load_module_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUS } else if (pa_tagstruct_getu32(t, &idx) < 0 || !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } @@ -848,7 +848,7 @@ static void context_get_autoload_info_callback(pa_pdispatch *pd, uint32_t comman pa_tagstruct_getu32(t, &i.type) < 0 || pa_tagstruct_gets(t, &i.module) < 0 || pa_tagstruct_gets(t, &i.argument) < 0) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } @@ -926,7 +926,7 @@ static void context_add_autoload_callback(pa_pdispatch *pd, uint32_t command, PA idx = PA_INVALID_INDEX; } else if (pa_tagstruct_getu32(t, &idx) || !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } diff --git a/src/polyp/simple.c b/src/polyp/simple.c index e14cab2e..8a20c223 100644 --- a/src/polyp/simple.c +++ b/src/polyp/simple.c @@ -45,13 +45,11 @@ struct pa_simple { int dead; - void *read_data; + const void *read_data; size_t read_index, read_length; pa_usec_t latency; }; -static void read_callback(pa_stream *s, const void*data, size_t length, void *userdata); - static int check_error(pa_simple *p, int *rerror) { pa_context_state_t cst; pa_stream_state_t sst; @@ -92,7 +90,7 @@ static int iterate(pa_simple *p, int block, int *rerror) { do { if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) { if (rerror) - *rerror = PA_ERROR_INTERNAL; + *rerror = PA_ERR_INTERNAL; return -1; } @@ -106,7 +104,7 @@ static int iterate(pa_simple *p, int block, int *rerror) { if (pa_mainloop_iterate(p->mainloop, 0, NULL) < 0) { if (rerror) - *rerror = PA_ERROR_INTERNAL; + *rerror = PA_ERR_INTERNAL; return -1; } @@ -128,7 +126,7 @@ pa_simple* pa_simple_new( int *rerror) { pa_simple *p; - int error = PA_ERROR_INTERNAL; + int error = PA_ERR_INTERNAL; assert(ss && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); p = pa_xmalloc(sizeof(pa_simple)); @@ -157,7 +155,7 @@ pa_simple* pa_simple_new( goto fail; if (dir == PA_STREAM_PLAYBACK) - pa_stream_connect_playback(p->stream, dev, attr, 0, NULL); + pa_stream_connect_playback(p->stream, dev, attr, 0, NULL, NULL); else pa_stream_connect_record(p->stream, dev, attr, 0); @@ -167,8 +165,6 @@ pa_simple* pa_simple_new( goto fail; } - pa_stream_set_read_callback(p->stream, read_callback, p); - return p; fail: @@ -181,8 +177,6 @@ fail: void pa_simple_free(pa_simple *s) { assert(s); - pa_xfree(s->read_data); - if (s->stream) pa_stream_unref(s->stream); @@ -215,7 +209,7 @@ int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { if (l > length) l = length; - pa_stream_write(p->stream, data, l, NULL, 0); + pa_stream_write(p->stream, data, l, NULL, 0, PA_SEEK_RELATIVE); data = (const uint8_t*) data + l; length -= l; } @@ -227,19 +221,6 @@ int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { return 0; } -static void read_callback(pa_stream *s, const void*data, size_t length, void *userdata) { - pa_simple *p = userdata; - assert(s && data && length && p); - - if (p->read_data) { - pa_log(__FILE__": Buffer overflow, dropping incoming memory blocks.\n"); - pa_xfree(p->read_data); - } - - p->read_data = pa_xmemdup(data, p->read_length = length); - p->read_index = 0; -} - int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { assert(p && data && p->direction == PA_STREAM_RECORD); @@ -251,13 +232,18 @@ int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { } while (length > 0) { + + if (!p->read_data) + if (pa_stream_peek(p->stream, &p->read_data, &p->read_length) >= 0) + p->read_index = 0; + if (p->read_data) { size_t l = length; if (p->read_length <= l) l = p->read_length; - memcpy(data, (uint8_t*) p->read_data+p->read_index, l); + memcpy(data, (const uint8_t*) p->read_data+p->read_index, l); data = (uint8_t*) data + l; length -= l; @@ -266,8 +252,9 @@ int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { p->read_length -= l; if (!p->read_length) { - pa_xfree(p->read_data); + pa_stream_drop(p->stream); p->read_data = NULL; + p->read_length = 0; p->read_index = 0; } diff --git a/src/polyp/stream.c b/src/polyp/stream.c index 35de2d01..5497f0c4 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -39,14 +40,11 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map) { pa_stream *s; + assert(c); - assert(ss); - - if (!pa_sample_spec_valid(ss)) - return NULL; - if (map && !pa_channel_map_valid(map)) - return NULL; + PA_CHECK_VALIDITY_RETURN_NULL(c, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, !map || pa_channel_map_valid(map), PA_ERR_INVALID); s = pa_xnew(pa_stream, 1); s->ref = 1; @@ -59,6 +57,10 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->write_userdata = NULL; s->state_callback = NULL; s->state_userdata = NULL; + s->overflow_callback = NULL; + s->overflow_userdata = NULL; + s->underflow_callback = NULL; + s->underflow_userdata = NULL; s->direction = PA_STREAM_NODIRECTION; s->name = pa_xstrdup(name); @@ -71,13 +73,13 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->channel = 0; s->channel_valid = 0; + s->syncid = c->csyncid++; s->device_index = PA_INVALID_INDEX; s->requested_bytes = 0; - s->state = PA_STREAM_DISCONNECTED; + s->state = PA_STREAM_UNCONNECTED; memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - s->mcalign = pa_mcalign_new(pa_frame_size(ss), c->memblock_stat); - + s->peek_memchunk.index = 0; s->peek_memchunk.length = 0; s->peek_memchunk.memblock = NULL; @@ -114,42 +116,52 @@ static void stream_free(pa_stream *s) { if (s->record_memblockq) pa_memblockq_free(s->record_memblockq); - pa_mcalign_free(s->mcalign); - pa_xfree(s->name); pa_xfree(s); } void pa_stream_unref(pa_stream *s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); if (--(s->ref) == 0) stream_free(s); } pa_stream* pa_stream_ref(pa_stream *s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); + s->ref++; return s; } pa_stream_state_t pa_stream_get_state(pa_stream *s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); + return s->state; } pa_context* pa_stream_get_context(pa_stream *s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); + return s->context; } uint32_t pa_stream_get_index(pa_stream *s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX); + return s->device_index; } void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); if (s->state == st) return; @@ -159,6 +171,8 @@ void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { s->state = st; if ((st == PA_STREAM_FAILED || st == PA_STREAM_TERMINATED) && s->context) { + /* Detach from context */ + if (s->channel_valid) pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); @@ -182,14 +196,14 @@ void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED if (pa_tagstruct_getu32(t, &channel) < 0 || !pa_tagstruct_eof(t)) { - pa_context_fail(c, PA_ERROR_PROTOCOL); + pa_context_fail(c, PA_ERR_PROTOCOL); goto finish; } if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) goto finish; - c->error = PA_ERROR_KILLED; + c->error = PA_ERR_KILLED; pa_stream_set_state(s, PA_STREAM_FAILED); finish: @@ -207,24 +221,55 @@ void pa_command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32 if (pa_tagstruct_getu32(t, &channel) < 0 || pa_tagstruct_getu32(t, &bytes) < 0 || !pa_tagstruct_eof(t)) { - pa_context_fail(c, PA_ERROR_PROTOCOL); + pa_context_fail(c, PA_ERR_PROTOCOL); goto finish; } if (!(s = pa_dynarray_get(c->playback_streams, channel))) goto finish; - if (s->state != PA_STREAM_READY) - goto finish; + if (s->state == PA_STREAM_READY) { + s->requested_bytes += bytes; + + if (s->requested_bytes > 0 && s->write_callback) + s->write_callback(s, s->requested_bytes, s->write_userdata); + } - pa_stream_ref(s); +finish: + pa_context_unref(c); +} + +void pa_command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_stream *s; + pa_context *c = userdata; + uint32_t channel; + + assert(pd); + assert(command == PA_COMMAND_OVERFLOW || command == PA_COMMAND_UNDERFLOW); + assert(t); + assert(c); + + pa_context_ref(c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(c, PA_ERR_PROTOCOL); + goto finish; + } - s->requested_bytes += bytes; + if (!(s = pa_dynarray_get(c->playback_streams, channel))) + goto finish; - if (s->requested_bytes && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); + if (s->state == PA_STREAM_READY) { - pa_stream_unref(s); + if (command == PA_COMMAND_OVERFLOW) { + if (s->overflow_callback) + s->overflow_callback(s, s->overflow_userdata); + } else if (command == PA_COMMAND_UNDERFLOW) { + if (s->underflow_callback) + s->underflow_callback(s, s->underflow_userdata); + } + } finish: pa_context_unref(c); @@ -270,14 +315,21 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || ((s->direction != PA_STREAM_RECORD) && pa_tagstruct_getu32(t, &s->requested_bytes) < 0) || !pa_tagstruct_eof(t)) { - pa_context_fail(s->context, PA_ERROR_PROTOCOL); + pa_context_fail(s->context, PA_ERR_PROTOCOL); goto finish; } if (s->direction == PA_STREAM_RECORD) { assert(!s->record_memblockq); - s->record_memblockq = pa_memblockq_new(s->buffer_attr.maxlength, 0, - pa_frame_size(&s->sample_spec), 0, 0, s->context->memblock_stat); + s->record_memblockq = pa_memblockq_new( + 0, + s->buffer_attr.maxlength, + 0, + pa_frame_size(&s->sample_spec), + 1, + 0, + NULL, + s->context->memblock_stat); assert(s->record_memblockq); } @@ -303,13 +355,32 @@ finish: pa_stream_unref(s); } -static void create_stream(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags, const pa_cvolume *volume) { +static int create_stream( + pa_stream_direction_t direction, + pa_stream *s, + const char *dev, + const pa_buffer_attr *attr, + pa_stream_flags_t flags, + const pa_cvolume *volume, + pa_stream *sync_stream) { + pa_tagstruct *t; uint32_t tag; - assert(s && s->ref >= 1 && s->state == PA_STREAM_DISCONNECTED); + + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, (flags & ~(PA_STREAM_START_CORKED|PA_STREAM_INTERPOLATE_LATENCY)) == 0, PA_ERR_INVALID); + PA_CHECK_VALIDITY(s->context, direction == PA_STREAM_PLAYBACK || flags == 0, PA_ERR_INVALID); pa_stream_ref(s); + s->direction = direction; + + if (sync_stream) + s->syncid = sync_stream->syncid; + s->interpolate = !!(flags & PA_STREAM_INTERPOLATE_LATENCY); pa_stream_trash_ipol(s); @@ -336,25 +407,28 @@ static void create_stream(pa_stream *s, const char *dev, const pa_buffer_attr *a dev = s->context->conf->default_source; } - pa_tagstruct_put(t, - PA_TAG_U32, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM, - PA_TAG_U32, tag = s->context->ctag++, - PA_TAG_STRING, s->name, - PA_TAG_SAMPLE_SPEC, &s->sample_spec, - PA_TAG_CHANNEL_MAP, &s->channel_map, - PA_TAG_U32, PA_INVALID_INDEX, - PA_TAG_STRING, dev, - PA_TAG_U32, s->buffer_attr.maxlength, - PA_TAG_BOOLEAN, !!(flags & PA_STREAM_START_CORKED), - PA_TAG_INVALID); + pa_tagstruct_put( + t, + PA_TAG_U32, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM, + PA_TAG_U32, tag = s->context->ctag++, + PA_TAG_STRING, s->name, + PA_TAG_SAMPLE_SPEC, &s->sample_spec, + PA_TAG_CHANNEL_MAP, &s->channel_map, + PA_TAG_U32, PA_INVALID_INDEX, + PA_TAG_STRING, dev, + PA_TAG_U32, s->buffer_attr.maxlength, + PA_TAG_BOOLEAN, !!(flags & PA_STREAM_START_CORKED), + PA_TAG_INVALID); if (s->direction == PA_STREAM_PLAYBACK) { pa_cvolume cv; - pa_tagstruct_put(t, - PA_TAG_U32, s->buffer_attr.tlength, - PA_TAG_U32, s->buffer_attr.prebuf, - PA_TAG_U32, s->buffer_attr.minreq, - PA_TAG_INVALID); + pa_tagstruct_put( + t, + PA_TAG_U32, s->buffer_attr.tlength, + PA_TAG_U32, s->buffer_attr.prebuf, + PA_TAG_U32, s->buffer_attr.minreq, + PA_TAG_U32, s->syncid, + PA_TAG_INVALID); if (!volume) { pa_cvolume_reset(&cv, s->sample_spec.channels); @@ -369,23 +443,57 @@ static void create_stream(pa_stream *s, const char *dev, const pa_buffer_attr *a pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s); pa_stream_unref(s); + return 0; } -void pa_stream_connect_playback(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags, pa_cvolume *volume) { - assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); - s->direction = PA_STREAM_PLAYBACK; - create_stream(s, dev, attr, flags, volume); +int pa_stream_connect_playback( + pa_stream *s, + const char *dev, + const pa_buffer_attr *attr, + pa_stream_flags_t flags, + pa_cvolume *volume, + pa_stream *sync_stream) { + + assert(s); + assert(s->ref >= 1); + + return create_stream(PA_STREAM_PLAYBACK, s, dev, attr, flags, volume, sync_stream); } -void pa_stream_connect_record(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags) { - assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); - s->direction = PA_STREAM_RECORD; - create_stream(s, dev, attr, flags, 0); +int pa_stream_connect_record( + pa_stream *s, + const char *dev, + const pa_buffer_attr *attr, + pa_stream_flags_t flags) { + + assert(s); + assert(s->ref >= 1); + + return create_stream(PA_STREAM_RECORD, s, dev, attr, flags, NULL, NULL); } -void pa_stream_write(pa_stream *s, const void *data, size_t length, void (*free_cb)(void *p), size_t delta) { +int pa_stream_write( + pa_stream *s, + const void *data, + size_t length, + void (*free_cb)(void *p), + int64_t offset, + pa_seek_mode_t seek) { + pa_memchunk chunk; - assert(s && s->context && data && length && s->state == PA_STREAM_READY && s->ref >= 1); + + assert(s); + assert(s->ref >= 1); + assert(s->context); + assert(data); + + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, seek <= PA_SEEK_RELATIVE_END, PA_ERR_INVALID); + PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || (seek == PA_SEEK_RELATIVE && offset == 0), PA_ERR_INVALID); + + if (length <= 0) + return 0; if (free_cb) { chunk.memblock = pa_memblock_new_user((void*) data, length, free_cb, 1, s->context->memblock_stat); @@ -398,7 +506,7 @@ void pa_stream_write(pa_stream *s, const void *data, size_t length, void (*free_ chunk.index = 0; chunk.length = length; - pa_pstream_send_memblock(s->context->pstream, s->channel, delta, &chunk); + pa_pstream_send_memblock(s->context->pstream, s->channel, offset, seek, &chunk); pa_memblock_unref(chunk.memblock); if (length < s->requested_bytes) @@ -407,72 +515,87 @@ void pa_stream_write(pa_stream *s, const void *data, size_t length, void (*free_ s->requested_bytes = 0; s->counter += length; + return 0; } -void pa_stream_peek(pa_stream *s, void **data, size_t *length) { - assert(s && s->record_memblockq && data && length && s->state == PA_STREAM_READY && s->ref >= 1); +int pa_stream_peek(pa_stream *s, const void **data, size_t *length) { + assert(s); + assert(s->ref >= 1); + assert(data); + assert(length); + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE); + if (!s->peek_memchunk.memblock) { - *data = NULL; - *length = 0; - - if (pa_memblockq_peek(s->record_memblockq, &s->peek_memchunk) < 0) - return; - pa_memblockq_drop(s->record_memblockq, &s->peek_memchunk, s->peek_memchunk.length); + if (pa_memblockq_peek(s->record_memblockq, &s->peek_memchunk) < 0) { + *data = NULL; + *length = 0; + return 0; + } } - *data = (char*)s->peek_memchunk.memblock->data + s->peek_memchunk.index; + *data = (const char*) s->peek_memchunk.memblock->data + s->peek_memchunk.index; *length = s->peek_memchunk.length; + return 0; } -void pa_stream_drop(pa_stream *s) { - assert(s && s->peek_memchunk.memblock && s->state == PA_STREAM_READY && s->ref >= 1); - - s->counter += s->peek_memchunk.length; +int pa_stream_drop(pa_stream *s) { + assert(s); + assert(s->ref >= 1); + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->peek_memchunk.memblock, PA_ERR_BADSTATE); + + pa_memblockq_drop(s->record_memblockq, &s->peek_memchunk, s->peek_memchunk.length); + pa_memblock_unref(s->peek_memchunk.memblock); - s->peek_memchunk.length = 0; + s->peek_memchunk.index = 0; s->peek_memchunk.memblock = NULL; + + s->counter += s->peek_memchunk.length; + return 0; } size_t pa_stream_writable_size(pa_stream *s) { - assert(s && s->ref >= 1); - return s->state == PA_STREAM_READY ? s->requested_bytes : 0; + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (size_t) -1); + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, (size_t) -1); + + return s->requested_bytes; } size_t pa_stream_readable_size(pa_stream *s) { - size_t sz; - - assert(s && s->ref >= 1); - - if (s->state != PA_STREAM_READY) - return 0; - - assert(s->record_memblockq); - - sz = (size_t)pa_memblockq_get_length(s->record_memblockq); + assert(s); + assert(s->ref >= 1); - if (s->peek_memchunk.memblock) - sz += s->peek_memchunk.length; + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (size_t) -1); + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, (size_t) -1); - return sz; + return pa_memblockq_get_length(s->record_memblockq); } pa_operation * pa_stream_drain(pa_stream *s, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; - assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); + + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); o = pa_operation_new(s->context, s); - assert(o); o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); - assert(t); pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); pa_tagstruct_putu32(t, tag = s->context->ctag++); pa_tagstruct_putu32(t, s->channel); @@ -501,7 +624,7 @@ static void stream_get_latency_info_callback(pa_pdispatch *pd, uint32_t command, pa_tagstruct_get_timeval(t, &remote) < 0 || pa_tagstruct_getu64(t, &i.counter) < 0 || !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } else { pa_gettimeofday(&now); @@ -549,15 +672,18 @@ pa_operation* pa_stream_get_latency_info(pa_stream *s, void (*cb)(pa_stream *p, pa_operation *o; pa_tagstruct *t; struct timeval now; - assert(s && s->direction != PA_STREAM_UPLOAD); + + assert(s); + assert(s->ref >= 1); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + o = pa_operation_new(s->context, s); - assert(o); o->callback = (pa_operation_callback) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); - assert(t); pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_GET_PLAYBACK_LATENCY : PA_COMMAND_GET_RECORD_LATENCY); pa_tagstruct_putu32(t, tag = s->context->ctag++); pa_tagstruct_putu32(t, s->channel); @@ -585,7 +711,7 @@ void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN pa_stream_set_state(s, PA_STREAM_FAILED); goto finish; } else if (!pa_tagstruct_eof(t)) { - pa_context_fail(s->context, PA_ERROR_PROTOCOL); + pa_context_fail(s->context, PA_ERR_PROTOCOL); goto finish; } @@ -595,18 +721,19 @@ finish: pa_stream_unref(s); } -void pa_stream_disconnect(pa_stream *s) { +int pa_stream_disconnect(pa_stream *s) { pa_tagstruct *t; uint32_t tag; - assert(s && s->ref >= 1); - if (!s->channel_valid || !s->context->state == PA_CONTEXT_READY) - return; + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY(s->context, s->channel_valid, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); pa_stream_ref(s); t = pa_tagstruct_new(NULL, 0); - assert(t); pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); @@ -616,26 +743,49 @@ void pa_stream_disconnect(pa_stream *s) { pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s); pa_stream_unref(s); + return 0; } -void pa_stream_set_read_callback(pa_stream *s, void (*cb)(pa_stream *p, size_t length, void *userdata), void *userdata) { - assert(s && s->ref >= 1); +void pa_stream_set_read_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) { + assert(s); + assert(s->ref >= 1); + s->read_callback = cb; s->read_userdata = userdata; } -void pa_stream_set_write_callback(pa_stream *s, void (*cb)(pa_stream *p, size_t length, void *userdata), void *userdata) { - assert(s && s->ref >= 1); +void pa_stream_set_write_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) { + assert(s); + assert(s->ref >= 1); + s->write_callback = cb; s->write_userdata = userdata; } -void pa_stream_set_state_callback(pa_stream *s, void (*cb)(pa_stream *s, void *userdata), void *userdata) { - assert(s && s->ref >= 1); +void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { + assert(s); + assert(s->ref >= 1); + s->state_callback = cb; s->state_userdata = userdata; } +void pa_stream_set_overflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { + assert(s); + assert(s->ref >= 1); + + s->overflow_callback = cb; + s->overflow_userdata = userdata; +} + +void pa_stream_set_underflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { + assert(s); + assert(s->ref >= 1); + + s->underflow_callback = cb; + s->underflow_userdata = userdata; +} + void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; int success = 1; @@ -647,7 +797,7 @@ void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN success = 0; } else if (!pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERROR_PROTOCOL); + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } diff --git a/src/polyp/stream.h b/src/polyp/stream.h index 9bbda436..ce535963 100644 --- a/src/polyp/stream.h +++ b/src/polyp/stream.h @@ -40,8 +40,27 @@ PA_C_DECL_BEGIN * An opaque stream for playback or recording */ typedef struct pa_stream pa_stream; +/** A generic callback for operation completion */ +typedef void (*pa_stream_success_cb_t) (pa_stream*s, int success, void *userdata); + +/** A generic free callback */ +typedef void (*pa_free_cb_t)(void *p); + +/** A generic request callback */ +typedef void (*pa_stream_request_cb_t)(pa_stream *p, size_t length, void *userdata); + +/** A generic notification callback */ +typedef void (*pa_stream_notify_cb_t)(pa_stream *p, void *userdata); + +/** Callback prototype for pa_stream_get_latency_info() */ +typedef void (*pa_stream_get_latency_info_cb_t)(pa_stream *p, const pa_latency_info *i, void *userdata); + /** Create a new, unconnected stream with the specified name and sample type */ -pa_stream* pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map); +pa_stream* pa_stream_new( + pa_context *c, + const char *name, + const pa_sample_spec *ss, + const pa_channel_map *map); /** Decrease the reference counter by one */ void pa_stream_unref(pa_stream *s); @@ -59,108 +78,101 @@ pa_context* pa_stream_get_context(pa_stream *p); uint32_t pa_stream_get_index(pa_stream *s); /** Connect the stream to a sink */ -void pa_stream_connect_playback( - pa_stream *s, - const char *dev, - const pa_buffer_attr *attr, - pa_stream_flags_t flags, - pa_cvolume *volume); +int pa_stream_connect_playback( + pa_stream *s /**< The stream to connect to a sink */, + const char *dev /**< Name of the sink to connect to, or NULL for default */ , + const pa_buffer_attr *attr /**< Buffering attributes, or NULL for default */, + pa_stream_flags_t flags /**< Additional flags, or 0 for default */, + pa_cvolume *volume /**< Initial volume, or NULL for default */, + pa_stream *sync_stream /**< Synchronize this stream with the specified one, or NULL for a standalone stream*/); /** Connect the stream to a source */ -void pa_stream_connect_record( - pa_stream *s, - const char *dev, - const pa_buffer_attr *attr, - pa_stream_flags_t flags); +int pa_stream_connect_record( + pa_stream *s, + const char *dev, + const pa_buffer_attr *attr, + pa_stream_flags_t flags); /** Disconnect a stream from a source/sink */ -void pa_stream_disconnect(pa_stream *s); +int pa_stream_disconnect(pa_stream *s); /** Write some data to the server (for playback sinks), if free_cb is * non-NULL this routine is called when all data has been written out * and an internal reference to the specified data is kept, the data * is not copied. If NULL, the data is copied into an internal - * buffer. */ -void pa_stream_write(pa_stream *p /**< The stream to use */, - const void *data /**< The data to write */, - size_t length /**< The length of the data to write */, - void (*free_cb)(void *p) /**< A cleanup routine for the data or NULL to request an internal copy */, - size_t delta /**< Drop this many - bytes in the playback - buffer before writing - this data. Use - (size_t) -1 for - clearing the whole - playback - buffer. Normally you - will specify 0 here, - i.e. append to the - playback buffer. If - the value given here - is greater than the - buffered data length - the buffer is cleared - and the data is - written to the - buffer's start. This - value is ignored on - upload streams. */); - -/** Read the next fragment from the buffer (for capture sources). + * buffer. The client my freely seek around in the output buffer. For + * most applications passing 0 and PA_SEEK_RELATIVE as arguments for + * offset and seek should be useful.*/ +int pa_stream_write( + pa_stream *p /**< The stream to use */, + const void *data /**< The data to write */, + size_t length /**< The length of the data to write */, + pa_free_cb_t free_cb /**< A cleanup routine for the data or NULL to request an internal copy */, + int64_t offset, /**< Offset for seeking, must be 0 for upload streams */ + pa_seek_mode_t seek /**< Seek mode, must be PA_SEEK_RELATIVE for upload streams */); + +/** Read the next fragment from the buffer (for recording). * data will point to the actual data and length will contain the size * of the data in bytes (which can be less than a complete framgnet). - * Use pa_stream_drop() to actually remove the data from the buffer. - * \since 0.8 */ -void pa_stream_peek(pa_stream *p /**< The stream to use */, - void **data /**< Pointer to pointer that will point to data */, - size_t *length /**< The length of the data read */); + * Use pa_stream_drop() to actually remove the data from the + * buffer. If no data is available will return a NULL pointer \since 0.8 */ +int pa_stream_peek( + pa_stream *p /**< The stream to use */, + const void **data /**< Pointer to pointer that will point to data */, + size_t *length /**< The length of the data read */); /** Remove the current fragment. It is invalid to do this without first * calling pa_stream_peek(). \since 0.8 */ -void pa_stream_drop(pa_stream *p); +int pa_stream_drop(pa_stream *p); -/** Return the amount of bytes that may be written using pa_stream_write() */ +/** Return the nember of bytes that may be written using pa_stream_write() */ size_t pa_stream_writable_size(pa_stream *p); -/** Return the ammount of bytes that may be read using pa_stream_read() \since 0.8 */ +/** Return the number of bytes that may be read using pa_stream_read() \since 0.8 */ size_t pa_stream_readable_size(pa_stream *p); -/** Drain a playback stream */ -pa_operation* pa_stream_drain(pa_stream *s, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata); +/** Drain a playback stream. Use this for notification when the buffer is empty */ +pa_operation* pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); /** Get the playback latency of a stream */ -pa_operation* pa_stream_get_latency_info(pa_stream *p, void (*cb)(pa_stream *p, const pa_latency_info *i, void *userdata), void *userdata); +pa_operation* pa_stream_get_latency_info(pa_stream *p, pa_stream_get_latency_info_cb_t cby, void *userdata); /** Set the callback function that is called whenever the state of the stream changes */ -void pa_stream_set_state_callback(pa_stream *s, void (*cb)(pa_stream *s, void *userdata), void *userdata); +void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata); /** Set the callback function that is called when new data may be * written to the stream. */ -void pa_stream_set_write_callback(pa_stream *p, void (*cb)(pa_stream *p, size_t length, void *userdata), void *userdata); +void pa_stream_set_write_callback(pa_stream *p, pa_stream_request_cb_t cb, void *userdata); /** Set the callback function that is called when new data is available from the stream. - * Return the number of bytes read. \since 0.8 - */ -void pa_stream_set_read_callback(pa_stream *p, void (*cb)(pa_stream *p, size_t length, void *userdata), void *userdata); + * Return the number of bytes read. \since 0.8 */ +void pa_stream_set_read_callback(pa_stream *p, pa_stream_request_cb_t cb, void *userdata); + +/** Set the callback function that is called when a buffer overflow happens. (Only for playback streams) \since 0.8 */ +void pa_stream_set_overflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); + +/** Set the callback function that is called when a buffer underflow happens. (Only for playback streams) \since 0.8 */ +void pa_stream_set_underflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); /** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. \since 0.3 */ -pa_operation* pa_stream_cork(pa_stream *s, int b, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata); +pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata); /** Flush the playback buffer of this stream. Most of the time you're * better off using the parameter delta of pa_stream_write() instead of this * function. Available on both playback and recording streams. \since 0.3 */ -pa_operation* pa_stream_flush(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata); +pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); -/** Reenable prebuffering. Available for playback streams only. \since 0.6 */ -pa_operation* pa_stream_prebuf(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata); +/** Reenable prebuffering as specified in the pa_buffer_attr + * structure. Available for playback streams only. \since 0.6 */ +pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); /** Request immediate start of playback on this stream. This disables - * prebuffering as specified in the pa_buffer_attr structure. Available for playback streams only. \since - * 0.3 */ -pa_operation* pa_stream_trigger(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata); + * prebuffering as specified in the pa_buffer_attr + * structure, temporarily. Available for playback streams only. \since 0.3 */ +pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); /** Rename the stream. \since 0.5 */ -pa_operation* pa_stream_set_name(pa_stream *s, const char *name, void(*cb)(pa_stream*c, int success, void *userdata), void *userdata); +pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata); /** Return the total number of bytes written to/read from the * stream. This counter is not reset on pa_stream_flush(), you may do diff --git a/src/polyp/subscribe.c b/src/polyp/subscribe.c index b90e0bf1..4e00997a 100644 --- a/src/polyp/subscribe.c +++ b/src/polyp/subscribe.c @@ -44,7 +44,7 @@ void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSE if (pa_tagstruct_getu32(t, &e) < 0 || pa_tagstruct_getu32(t, &index) < 0 || !pa_tagstruct_eof(t)) { - pa_context_fail(c, PA_ERROR_PROTOCOL); + pa_context_fail(c, PA_ERR_PROTOCOL); goto finish; } diff --git a/src/polypcore/iochannel.c b/src/polypcore/iochannel.c index 7fd09152..c33f593e 100644 --- a/src/polypcore/iochannel.c +++ b/src/polypcore/iochannel.c @@ -59,17 +59,17 @@ static void enable_mainloop_sources(pa_iochannel *io) { pa_io_event_flags_t f = PA_IO_EVENT_NULL; assert(io->input_event); - if (!io->readable) + if (!pa_iochannel_is_readable(io)) f |= PA_IO_EVENT_INPUT; - if (!io->writable) + if (!pa_iochannel_is_writable(io)) f |= PA_IO_EVENT_OUTPUT; io->mainloop->io_enable(io->input_event, f); } else { if (io->input_event) - io->mainloop->io_enable(io->input_event, io->readable ? PA_IO_EVENT_NULL : PA_IO_EVENT_INPUT); + io->mainloop->io_enable(io->input_event, pa_iochannel_is_readable(io) ? PA_IO_EVENT_NULL : PA_IO_EVENT_INPUT); if (io->output_event) - io->mainloop->io_enable(io->output_event, io->writable ? PA_IO_EVENT_NULL : PA_IO_EVENT_OUTPUT); + io->mainloop->io_enable(io->output_event, pa_iochannel_is_writable(io) ? PA_IO_EVENT_NULL : PA_IO_EVENT_OUTPUT); } } @@ -82,33 +82,21 @@ static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_fla assert(fd >= 0); assert(userdata); - if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) { + if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) & !io->hungup) { io->hungup = 1; changed = 1; + } - if (e == io->input_event) { - io->mainloop->io_free(io->input_event); - io->input_event = NULL; - - if (io->output_event == e) - io->output_event = NULL; - } else if (e == io->output_event) { - io->mainloop->io_free(io->output_event); - io->output_event = NULL; - } - } else { - - if ((f & PA_IO_EVENT_INPUT) && !io->readable) { - io->readable = 1; - changed = 1; - assert(e == io->input_event); - } - - if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) { - io->writable = 1; - changed = 1; - assert(e == io->output_event); - } + if ((f & PA_IO_EVENT_INPUT) && !io->readable) { + io->readable = 1; + changed = 1; + assert(e == io->input_event); + } + + if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) { + io->writable = 1; + changed = 1; + assert(e == io->output_event); } if (changed) { @@ -217,6 +205,7 @@ ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) { if (r < 0) #endif r = write(io->ofd, data, l); + if (r >= 0) { io->writable = 0; enable_mainloop_sources(io); diff --git a/src/polypcore/llist.h b/src/polypcore/llist.h index eb8cd017..c54742d3 100644 --- a/src/polypcore/llist.h +++ b/src/polypcore/llist.h @@ -66,4 +66,14 @@ _item->next = _item->prev = NULL; \ } while(0) +#define PA_LLIST_FIND_HEAD(t,item,head) \ +do { \ + t **_head = (head), *_item = (item); \ + *_head = _item; \ + assert(_head); \ + while ((*_head)->prev) \ + *_head = (*_head)->prev; \ +} while (0) \ + + #endif diff --git a/src/polypcore/mcalign.c b/src/polypcore/mcalign.c index 0f229e28..f90fd7e8 100644 --- a/src/polypcore/mcalign.c +++ b/src/polypcore/mcalign.c @@ -43,6 +43,7 @@ pa_mcalign *pa_mcalign_new(size_t base, pa_memblock_stat *s) { assert(base); m = pa_xnew(pa_mcalign, 1); + m->base = base; pa_memchunk_reset(&m->leftover); pa_memchunk_reset(&m->current); @@ -64,11 +65,16 @@ void pa_mcalign_free(pa_mcalign *m) { } void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { - assert(m && c && c->memblock && c->length); + assert(m); + assert(c); + + assert(c->memblock); + assert(c->length > 0); + + assert(!m->current.memblock); /* Append to the leftover memory block */ if (m->leftover.memblock) { - assert(!m->current.memblock); /* Try to merge */ if (m->leftover.memblock == c->memblock && @@ -110,8 +116,6 @@ void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { } } } else { - assert(!m->leftover.memblock && !m->current.memblock); - /* Nothing to merge or copy, just store it */ if (c->length >= m->base) @@ -124,7 +128,8 @@ void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { } int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) { - assert(m && c); + assert(m); + assert(c); /* First test if there's a leftover memory block available */ if (m->leftover.memblock) { @@ -187,3 +192,15 @@ int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) { return -1; } + +size_t pa_mcalign_csize(pa_mcalign *m, size_t l) { + assert(m); + assert(l > 0); + + assert(!m->current.memblock); + + if (m->leftover.memblock) + l += m->leftover.length; + + return (l/m->base)*m->base; +} diff --git a/src/polypcore/mcalign.h b/src/polypcore/mcalign.h index a9107e0e..58019462 100644 --- a/src/polypcore/mcalign.h +++ b/src/polypcore/mcalign.h @@ -74,4 +74,7 @@ void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c); * nonzero otherwise. */ int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c); +/* If we pass l bytes in now, how many bytes would we get out? */ +size_t pa_mcalign_csize(pa_mcalign *m, size_t l); + #endif diff --git a/src/polypcore/memblock.c b/src/polypcore/memblock.c index 2c0bef57..04e8436f 100644 --- a/src/polypcore/memblock.c +++ b/src/polypcore/memblock.c @@ -111,13 +111,16 @@ pa_memblock *pa_memblock_new_user(void *d, size_t length, void (*free_cb)(void * } pa_memblock* pa_memblock_ref(pa_memblock*b) { - assert(b && b->ref >= 1); + assert(b); + assert(b->ref >= 1); + b->ref++; return b; } void pa_memblock_unref(pa_memblock*b) { - assert(b && b->ref >= 1); + assert(b); + assert(b->ref >= 1); if ((--(b->ref)) == 0) { stat_remove(b); diff --git a/src/polypcore/memblock.h b/src/polypcore/memblock.h index c5751406..9471278a 100644 --- a/src/polypcore/memblock.h +++ b/src/polypcore/memblock.h @@ -79,7 +79,6 @@ references to the memory. This causes the memory to be copied and converted into a PA_MEMBLOCK_DYNAMIC type memory block */ void pa_memblock_unref_fixed(pa_memblock*b); - pa_memblock_stat* pa_memblock_stat_new(void); void pa_memblock_stat_unref(pa_memblock_stat *s); pa_memblock_stat * pa_memblock_stat_ref(pa_memblock_stat *s); diff --git a/src/polypcore/memblockq.c b/src/polypcore/memblockq.c index 4a0225e5..05c810bd 100644 --- a/src/polypcore/memblockq.c +++ b/src/polypcore/memblockq.c @@ -38,30 +38,45 @@ struct memblock_list { struct memblock_list *next, *prev; + int64_t index; pa_memchunk chunk; }; struct pa_memblockq { struct memblock_list *blocks, *blocks_tail; unsigned n_blocks; - size_t current_length, maxlength, tlength, base, prebuf, orig_prebuf, minreq; - pa_mcalign *mcalign; + size_t maxlength, tlength, base, prebuf, minreq; + int64_t read_index, write_index; + enum { PREBUF, RUNNING } state; pa_memblock_stat *memblock_stat; + pa_memblock *silence; + pa_mcalign *mcalign; }; -pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t base, size_t prebuf, size_t minreq, pa_memblock_stat *s) { +pa_memblockq* pa_memblockq_new( + int64_t idx, + size_t maxlength, + size_t tlength, + size_t base, + size_t prebuf, + size_t minreq, + pa_memblock *silence, + pa_memblock_stat *s) { + pa_memblockq* bq; - assert(maxlength && base && maxlength); - bq = pa_xmalloc(sizeof(pa_memblockq)); - bq->blocks = bq->blocks_tail = 0; + assert(base > 0); + assert(maxlength >= base); + + bq = pa_xnew(pa_memblockq, 1); + bq->blocks = bq->blocks_tail = NULL; bq->n_blocks = 0; - bq->current_length = 0; + bq->base = base; + bq->read_index = bq->write_index = idx; + bq->memblock_stat = s; pa_log_debug(__FILE__": memblockq requested: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", maxlength, tlength, base, prebuf, minreq); - - bq->base = base; bq->maxlength = ((maxlength+base-1)/base)*base; assert(bq->maxlength >= base); @@ -70,26 +85,25 @@ pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t base, si if (!bq->tlength || bq->tlength >= bq->maxlength) bq->tlength = bq->maxlength; - bq->minreq = (minreq/base)*base; - if (bq->minreq == 0) - bq->minreq = 1; - - bq->prebuf = (prebuf == (size_t) -1) ? bq->maxlength/2 : prebuf; - bq->prebuf = (bq->prebuf/base)*base; + bq->prebuf = (prebuf == (size_t) -1) ? bq->tlength/2 : prebuf; + bq->prebuf = ((bq->prebuf+base-1)/base)*base; if (bq->prebuf > bq->maxlength) bq->prebuf = bq->maxlength; - if (bq->prebuf > bq->tlength - bq->minreq) - bq->prebuf = bq->tlength - bq->minreq; + bq->minreq = (minreq/base)*base; + + if (bq->minreq > bq->tlength - bq->prebuf) + bq->minreq = bq->tlength - bq->prebuf; - bq->orig_prebuf = bq->prebuf; + if (!bq->minreq) + bq->minreq = 1; pa_log_debug(__FILE__": memblockq sanitized: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", bq->maxlength, bq->tlength, bq->base, bq->prebuf, bq->minreq); - - bq->mcalign = NULL; - - bq->memblock_stat = s; + bq->state = bq->prebuf ? PREBUF : RUNNING; + bq->silence = silence ? pa_memblock_ref(silence) : NULL; + bq->mcalign = NULL; + return bq; } @@ -97,248 +111,510 @@ void pa_memblockq_free(pa_memblockq* bq) { assert(bq); pa_memblockq_flush(bq); - + + if (bq->silence) + pa_memblock_unref(bq->silence); + if (bq->mcalign) pa_mcalign_free(bq->mcalign); - + pa_xfree(bq); } -void pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *chunk, size_t delta) { - struct memblock_list *q; - assert(bq && chunk && chunk->memblock && chunk->length && (chunk->length % bq->base) == 0); - - pa_memblockq_seek(bq, delta); - - if (bq->blocks_tail && bq->blocks_tail->chunk.memblock == chunk->memblock) { - /* Try to merge memory chunks */ +static void drop_block(pa_memblockq *bq, struct memblock_list *q) { + assert(bq); + assert(q); - if (bq->blocks_tail->chunk.index+bq->blocks_tail->chunk.length == chunk->index) { - bq->blocks_tail->chunk.length += chunk->length; - bq->current_length += chunk->length; - return; - } - } + assert(bq->n_blocks >= 1); - q = pa_xmalloc(sizeof(struct memblock_list)); - - q->chunk = *chunk; - pa_memblock_ref(q->chunk.memblock); - assert(q->chunk.index+q->chunk.length <= q->chunk.memblock->length); - q->next = NULL; - if ((q->prev = bq->blocks_tail)) - bq->blocks_tail->next = q; + if (q->prev) + q->prev->next = q->next; else - bq->blocks = q; + bq->blocks = q->next; - bq->blocks_tail = q; + if (q->next) + q->next->prev = q->prev; + else + bq->blocks_tail = q->prev; - bq->n_blocks++; - bq->current_length += chunk->length; + pa_memblock_unref(q->chunk.memblock); + pa_xfree(q); - pa_memblockq_shorten(bq, bq->maxlength); + bq->n_blocks--; } -int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { - assert(bq && chunk); +static int can_push(pa_memblockq *bq, size_t l) { + int64_t end; - if (!bq->blocks || bq->current_length < bq->prebuf) - return -1; + assert(bq); - bq->prebuf = 0; + if (bq->read_index > bq->write_index) { + int64_t d = bq->read_index - bq->write_index; - *chunk = bq->blocks->chunk; - pa_memblock_ref(chunk->memblock); + if (l > d) + l -= d; + else + return 1; + } - return 0; + end = bq->blocks_tail ? bq->blocks_tail->index + bq->blocks_tail->chunk.length : 0; + + /* Make sure that the list doesn't get too long */ + if (bq->write_index + l > end) + if (bq->write_index + l - bq->read_index > bq->maxlength) + return 0; + + return 1; } -void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length) { - assert(bq && chunk && length); +int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { + + struct memblock_list *q, *n; + pa_memchunk chunk; + + assert(bq); + assert(uchunk); + assert(uchunk->memblock); + assert(uchunk->length > 0); + assert(uchunk->index + uchunk->length <= uchunk->memblock->length); + + if (uchunk->length % bq->base) + return -1; + + if (!can_push(bq, uchunk->length)) + return -1; - if (!bq->blocks || memcmp(&bq->blocks->chunk, chunk, sizeof(pa_memchunk))) - return; + chunk = *uchunk; - assert(length <= bq->blocks->chunk.length); - pa_memblockq_skip(bq, length); -} + if (bq->read_index > bq->write_index) { -static void remove_block(pa_memblockq *bq, struct memblock_list *q) { - assert(bq && q); + /* We currently have a buffer underflow, we need to drop some + * incoming data */ - if (q->prev) - q->prev->next = q->next; - else { - assert(bq->blocks == q); - bq->blocks = q->next; + int64_t d = bq->read_index - bq->write_index; + + if (chunk.length > d) { + chunk.index += d; + chunk.length -= d; + bq->write_index = bq->read_index; + } else { + /* We drop the incoming data completely */ + bq->write_index += chunk.length; + return 0; + } } - if (q->next) - q->next->prev = q->prev; - else { - assert(bq->blocks_tail == q); - bq->blocks_tail = q->prev; + /* We go from back to front to look for the right place to add + * this new entry. Drop data we will overwrite on the way */ + + q = bq->blocks_tail; + while (q) { + + if (bq->write_index >= q->index + q->chunk.length) + /* We found the entry where we need to place the new entry immediately after */ + break; + else if (bq->write_index + chunk.length <= q->index) { + /* This entry isn't touched at all, let's skip it */ + q = q->prev; + } else if (bq->write_index <= q->index && + bq->write_index + chunk.length >= q->index + q->chunk.length) { + + /* This entry is fully replaced by the new entry, so let's drop it */ + + struct memblock_list *p; + p = q; + q = q->prev; + drop_block(bq, p); + } else if (bq->write_index >= q->index) { + /* The write index points into this memblock, so let's + * truncate or split it */ + + if (bq->write_index + chunk.length < q->index + q->chunk.length) { + + /* We need to save the end of this memchunk */ + struct memblock_list *p; + size_t d; + + /* Create a new list entry for the end of thie memchunk */ + p = pa_xnew(struct memblock_list, 1); + p->chunk = q->chunk; + pa_memblock_ref(p->chunk.memblock); + + /* Calculate offset */ + d = bq->write_index + chunk.length - q->index; + assert(d > 0); + + /* Drop it from the new entry */ + p->index = q->index + d; + p->chunk.length -= d; + + /* Add it to the list */ + p->prev = q; + if ((p->next = q->next)) + q->next->prev = p; + else + bq->blocks_tail = p; + q->next = p; + + bq->n_blocks++; + } + + /* Truncate the chunk */ + if (!(q->chunk.length = bq->write_index - q->index)) { + struct memblock_list *p; + p = q; + q = q->prev; + drop_block(bq, p); + } + + /* We had to truncate this block, hence we're now at the right position */ + break; + } else { + size_t d; + + assert(bq->write_index + chunk.length > q->index && + bq->write_index + chunk.length < q->index + q->chunk.length && + bq->write_index < q->index); + + /* The job overwrites the current entry at the end, so let's drop the beginning of this entry */ + + d = bq->write_index + chunk.length - q->index; + q->index += d; + q->chunk.index += d; + q->chunk.length -= d; + + q = q->prev; + } + } + + if (q) { + assert(bq->write_index >= q->index + q->chunk.length); + assert(!q->next || (bq->write_index+chunk.length <= q->next->index)); + + /* Try to merge memory blocks */ + + if (q->chunk.memblock == chunk.memblock && + q->chunk.index + q->chunk.length == chunk.index && + bq->write_index == q->index + q->chunk.length) { + + q->chunk.length += chunk.length; + bq->write_index += chunk.length; + return 0; + } + } else + assert(!bq->blocks || (bq->write_index+chunk.length <= bq->blocks->index)); + + + n = pa_xnew(struct memblock_list, 1); + n->chunk = chunk; + pa_memblock_ref(n->chunk.memblock); + n->index = bq->write_index; + bq->write_index += n->chunk.length; + + n->next = q ? q->next : bq->blocks; + n->prev = q; + + if (n->next) + n->next->prev = n; + else + bq->blocks_tail = n; + + if (n->prev) + n->prev->next = n; + else + bq->blocks = n; - pa_memblock_unref(q->chunk.memblock); - pa_xfree(q); - - bq->n_blocks--; + bq->n_blocks++; + return 0; } -void pa_memblockq_skip(pa_memblockq *bq, size_t length) { - assert(bq && length && (length % bq->base) == 0); +int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { + assert(bq); + assert(chunk); - while (length > 0) { - size_t l = length; - assert(bq->blocks && bq->current_length >= length); - - if (l > bq->blocks->chunk.length) - l = bq->blocks->chunk.length; + if (bq->state == PREBUF) { - bq->blocks->chunk.index += l; - bq->blocks->chunk.length -= l; - bq->current_length -= l; - - if (!bq->blocks->chunk.length) - remove_block(bq, bq->blocks); + /* We need to pre-buffer */ + if (pa_memblockq_get_length(bq) < bq->prebuf) + return -1; + + bq->state = RUNNING; - length -= l; + } else if (bq->prebuf > 0 && bq->read_index >= bq->write_index) { + + /* Buffer underflow protection */ + bq->state = PREBUF; + return -1; } -} + + /* Do we need to spit out silence? */ + if (!bq->blocks || bq->blocks->index > bq->read_index) { -void pa_memblockq_shorten(pa_memblockq *bq, size_t length) { - size_t l; - assert(bq); + size_t length; + + /* How much silence shall we return? */ + length = bq->blocks ? bq->blocks->index - bq->read_index : 0; + + /* We need to return silence, since no data is yet available */ + if (bq->silence) { + chunk->memblock = pa_memblock_ref(bq->silence); - if (bq->current_length <= length) - return; + if (!length || length > chunk->memblock->length) + length = chunk->memblock->length; + + chunk->length = length; + } else { + chunk->memblock = NULL; + chunk->length = length; + } + + chunk->index = 0; + return 0; + } - /*pa_log(__FILE__": Warning! pa_memblockq_shorten()\n");*/ + /* Ok, let's pass real data to the caller */ + assert(bq->blocks->index == bq->read_index); - l = bq->current_length - length; - l /= bq->base; - l *= bq->base; + *chunk = bq->blocks->chunk; + pa_memblock_ref(chunk->memblock); - pa_memblockq_skip(bq, l); + return 0; } - -void pa_memblockq_empty(pa_memblockq *bq) { +void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length) { assert(bq); - pa_memblockq_shorten(bq, 0); + assert(length % bq->base == 0); + + assert(!chunk || length <= chunk->length); + + if (chunk) { + + if (bq->blocks && bq->blocks->index == bq->read_index) { + /* The first item in queue is valid */ + + /* Does the chunk match with what the user supplied us? */ + if (memcmp(chunk, &bq->blocks->chunk, sizeof(pa_memchunk)) != 0) + return; + + } else { + size_t l; + + /* The first item in the queue is not yet relevant */ + + assert(!bq->blocks || bq->blocks->index > bq->read_index); + l = bq->blocks ? bq->blocks->index - bq->read_index : 0; + + if (bq->silence) { + + if (!l || l > bq->silence->length) + l = bq->silence->length; + + } + + /* Do the entries still match? */ + if (chunk->index != 0 || chunk->length != l || chunk->memblock != bq->silence) + return; + } + } + + while (length > 0) { + + if (bq->blocks) { + size_t d; + + assert(bq->blocks->index >= bq->read_index); + + d = (size_t) (bq->blocks->index - bq->read_index); + + if (d >= length) { + /* The first block is too far in the future */ + + bq->read_index += length; + break; + } else { + + length -= d; + bq->read_index += d; + } + + assert(bq->blocks->index == bq->read_index); + + if (bq->blocks->chunk.length <= length) { + /* We need to drop the full block */ + + length -= bq->blocks->chunk.length; + bq->read_index += bq->blocks->chunk.length; + + drop_block(bq, bq->blocks); + } else { + /* Only the start of this block needs to be dropped */ + + bq->blocks->chunk.index += length; + bq->blocks->chunk.length -= length; + bq->blocks->index += length; + bq->read_index += length; + break; + } + + } else { + + /* The list is empty, there's nothing we could drop */ + bq->read_index += length; + break; + } + } } int pa_memblockq_is_readable(pa_memblockq *bq) { assert(bq); - return bq->current_length && (bq->current_length >= bq->prebuf); + if (bq->prebuf > 0) { + size_t l = pa_memblockq_get_length(bq); + + if (bq->state == PREBUF && l < bq->prebuf) + return 0; + + if (l <= 0) + return 0; + } + + return 1; } int pa_memblockq_is_writable(pa_memblockq *bq, size_t length) { assert(bq); - return bq->current_length + length <= bq->tlength; + if (length % bq->base) + return 0; + + return pa_memblockq_get_length(bq) + length <= bq->tlength; } -uint32_t pa_memblockq_get_length(pa_memblockq *bq) { +size_t pa_memblockq_get_length(pa_memblockq *bq) { assert(bq); - return bq->current_length; + + if (bq->write_index <= bq->read_index) + return 0; + + return (size_t) (bq->write_index - bq->read_index); } -uint32_t pa_memblockq_missing(pa_memblockq *bq) { +size_t pa_memblockq_missing(pa_memblockq *bq) { size_t l; assert(bq); - if (bq->current_length >= bq->tlength) + if ((l = pa_memblockq_get_length(bq)) >= bq->tlength) return 0; - l = bq->tlength - bq->current_length; - assert(l); - + l = bq->tlength - l; return (l >= bq->minreq) ? l : 0; } -void pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk, size_t delta) { - pa_memchunk rchunk; - assert(bq && chunk && bq->base); +size_t pa_memblockq_get_minreq(pa_memblockq *bq) { + assert(bq); - if (bq->base == 1) { - pa_memblockq_push(bq, chunk, delta); - return; - } + return bq->minreq; +} - if (!bq->mcalign) { - bq->mcalign = pa_mcalign_new(bq->base, bq->memblock_stat); - assert(bq->mcalign); +void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek) { + assert(bq); + + switch (seek) { + case PA_SEEK_RELATIVE: + bq->write_index += offset; + return; + case PA_SEEK_ABSOLUTE: + bq->write_index = offset; + return; + case PA_SEEK_RELATIVE_ON_READ: + bq->write_index = bq->read_index + offset; + return; + case PA_SEEK_RELATIVE_END: + bq->write_index = (bq->blocks_tail ? bq->blocks_tail->index + bq->blocks_tail->chunk.length : bq->read_index) + offset; + return; } + + assert(0); +} + +void pa_memblockq_flush(pa_memblockq *bq) { + assert(bq); - pa_mcalign_push(bq->mcalign, chunk); + while (bq->blocks) + drop_block(bq, bq->blocks); - while (pa_mcalign_pop(bq->mcalign, &rchunk) >= 0) { - pa_memblockq_push(bq, &rchunk, delta); - pa_memblock_unref(rchunk.memblock); - delta = 0; - } + assert(bq->n_blocks == 0); + bq->write_index = bq->read_index; + + pa_memblockq_prebuf_force(bq); } -uint32_t pa_memblockq_get_minreq(pa_memblockq *bq) { +size_t pa_memblockq_get_tlength(pa_memblockq *bq) { assert(bq); - return bq->minreq; + + return bq->tlength; } -void pa_memblockq_prebuf_disable(pa_memblockq *bq) { +int64_t pa_memblockq_get_read_index(pa_memblockq *bq) { assert(bq); - bq->prebuf = 0; + return bq->read_index; } -void pa_memblockq_prebuf_reenable(pa_memblockq *bq) { +int64_t pa_memblockq_get_write_index(pa_memblockq *bq) { assert(bq); - bq->prebuf = bq->orig_prebuf; + return bq->write_index; } -void pa_memblockq_seek(pa_memblockq *bq, size_t length) { +int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk) { + pa_memchunk rchunk; + assert(bq); + assert(chunk && bq->base); + + if (bq->base == 1) + return pa_memblockq_push(bq, chunk); + + if (!bq->mcalign) + bq->mcalign = pa_mcalign_new(bq->base, bq->memblock_stat); - if (!length) - return; + if (!can_push(bq, pa_mcalign_csize(bq->mcalign, chunk->length))) + return -1; + + pa_mcalign_push(bq->mcalign, chunk); + + while (pa_mcalign_pop(bq->mcalign, &rchunk) >= 0) { + int r; + r = pa_memblockq_push(bq, &rchunk); + pa_memblock_unref(rchunk.memblock); - while (length >= bq->base) { - size_t l = length; - if (!bq->current_length) - return; + if (r < 0) + return -1; + } - assert(bq->blocks_tail); - - if (l > bq->blocks_tail->chunk.length) - l = bq->blocks_tail->chunk.length; + return 0; +} - bq->blocks_tail->chunk.length -= l; - bq->current_length -= l; - - if (bq->blocks_tail->chunk.length == 0) - remove_block(bq, bq->blocks); +void pa_memblockq_shorten(pa_memblockq *bq, size_t length) { + size_t l; + assert(bq); - length -= l; - } + l = pa_memblockq_get_length(bq); + + if (l > length) + pa_memblockq_drop(bq, NULL, l - length); } -void pa_memblockq_flush(pa_memblockq *bq) { - struct memblock_list *l; +void pa_memblockq_prebuf_disable(pa_memblockq *bq) { assert(bq); - - while ((l = bq->blocks)) { - bq->blocks = l->next; - pa_memblock_unref(l->chunk.memblock); - pa_xfree(l); - } - bq->blocks_tail = NULL; - bq->n_blocks = 0; - bq->current_length = 0; + if (bq->state == PREBUF) + bq->state = RUNNING; } -uint32_t pa_memblockq_get_tlength(pa_memblockq *bq) { +void pa_memblockq_prebuf_force(pa_memblockq *bq) { assert(bq); - return bq->tlength; + + if (bq->state == RUNNING && bq->prebuf > 0) + bq->state = PREBUF; } diff --git a/src/polypcore/memblockq.h b/src/polypcore/memblockq.h index 7bb25f90..210f1a07 100644 --- a/src/polypcore/memblockq.h +++ b/src/polypcore/memblockq.h @@ -23,9 +23,11 @@ ***/ #include +#include #include #include +#include /* A memblockq is a queue of pa_memchunks (yepp, the name is not * perfect). It is similar to the ring buffers used by most other @@ -35,42 +37,59 @@ typedef struct pa_memblockq pa_memblockq; + /* Parameters: - - maxlength: maximum length of queue. If more data is pushed into the queue, data from the front is dropped - - length: the target length of the queue. - - base: a base value for all metrics. Only multiples of this value are popped from the queue - - prebuf: before passing the first byte out, make sure that enough bytes are in the queue - - minreq: pa_memblockq_missing() will only return values greater than this value + + - idx: start value for both read and write index + + - maxlength: maximum length of queue. If more data is pushed into + the queue, the operation will fail. Must not be 0. + + - tlength: the target length of the queue. Pass 0 for the default. + + - base: a base value for all metrics. Only multiples of this value + are popped from the queue or should be pushed into + it. Must not be 0. + + - prebuf: If the queue runs empty wait until this many bytes are in + queue again before passing the first byte out. If set + to 0 pa_memblockq_pop() will return a silence memblock + if no data is in the queue and will never fail. Pass + (size_t) -1 for the default. + + - minreq: pa_memblockq_missing() will only return values greater + than this value. Pass 0 for the default. + + - silence: return this memblock whzen reading unitialized data */ -pa_memblockq* pa_memblockq_new(size_t maxlength, - size_t tlength, - size_t base, - size_t prebuf, - size_t minreq, - pa_memblock_stat *s); +pa_memblockq* pa_memblockq_new( + int64_t idx, + size_t maxlength, + size_t tlength, + size_t base, + size_t prebuf, + size_t minreq, + pa_memblock *silence, + pa_memblock_stat *s); + void pa_memblockq_free(pa_memblockq*bq); -/* Push a new memory chunk into the queue. Optionally specify a value for future cancellation. */ -void pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *chunk, size_t delta); +/* Push a new memory chunk into the queue. */ +int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *chunk); -/* Same as pa_memblockq_push(), however chunks are filtered through a mcalign object, and thus aligned to multiples of base */ -void pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk, size_t delta); +/* Push a new memory chunk into the queue, but filter it through a + * pa_mcalign object. Don't mix this with pa_memblockq_seek() unless + * you know what you do. */ +int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk); /* Return a copy of the next memory chunk in the queue. It is not removed from the queue */ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk); -/* Drop the specified bytes from the queue, only valid aufter pa_memblockq_peek() */ +/* Drop the specified bytes from the queue, but only if the first + * chunk in the queue matches the one passed here. If NULL is passed, + * this check isn't done. */ void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length); -/* Drop the specified bytes from the queue */ -void pa_memblockq_skip(pa_memblockq *bq, size_t length); - -/* Shorten the pa_memblockq to the specified length by dropping data at the end of the queue */ -void pa_memblockq_shorten(pa_memblockq *bq, size_t length); - -/* Empty the pa_memblockq */ -void pa_memblockq_empty(pa_memblockq *bq); - /* Test if the pa_memblockq is currently readable, that is, more data than base */ int pa_memblockq_is_readable(pa_memblockq *bq); @@ -78,27 +97,38 @@ int pa_memblockq_is_readable(pa_memblockq *bq); int pa_memblockq_is_writable(pa_memblockq *bq, size_t length); /* Return the length of the queue in bytes */ -uint32_t pa_memblockq_get_length(pa_memblockq *bq); +size_t pa_memblockq_get_length(pa_memblockq *bq); /* Return how many bytes are missing in queue to the specified fill amount */ -uint32_t pa_memblockq_missing(pa_memblockq *bq); +size_t pa_memblockq_missing(pa_memblockq *bq); /* Returns the minimal request value */ -uint32_t pa_memblockq_get_minreq(pa_memblockq *bq); - -/* Force disabling of pre-buf even when the pre-buffer is not yet filled */ -void pa_memblockq_prebuf_disable(pa_memblockq *bq); - -/* Reenable pre-buf to the initial level */ -void pa_memblockq_prebuf_reenable(pa_memblockq *bq); +size_t pa_memblockq_get_minreq(pa_memblockq *bq); /* Manipulate the write pointer */ -void pa_memblockq_seek(pa_memblockq *bq, size_t delta); +void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek); -/* Flush the queue */ +/* Set the queue to silence, set write index to read index */ void pa_memblockq_flush(pa_memblockq *bq); /* Get Target length */ uint32_t pa_memblockq_get_tlength(pa_memblockq *bq); +/* Return the current read index */ +int64_t pa_memblockq_get_read_index(pa_memblockq *bq); + +/* Return the current write index */ +int64_t pa_memblockq_get_write_index(pa_memblockq *bq); + +/* Shorten the pa_memblockq to the specified length by dropping data + * at the read end of the queue. The read index is increased until the + * queue has the specified length */ +void pa_memblockq_shorten(pa_memblockq *bq, size_t length); + +/* Ignore prebuf for now */ +void pa_memblockq_prebuf_disable(pa_memblockq *bq); + +/* Force prebuf */ +void pa_memblockq_prebuf_force(pa_memblockq *bq); + #endif diff --git a/src/polypcore/native-common.h b/src/polypcore/native-common.h index ac3ea823..0d17b022 100644 --- a/src/polypcore/native-common.h +++ b/src/polypcore/native-common.h @@ -28,22 +28,22 @@ PA_C_DECL_BEGIN enum { + /* Generic commands */ PA_COMMAND_ERROR, PA_COMMAND_TIMEOUT, /* pseudo command */ PA_COMMAND_REPLY, + + /* Commands from client to server */ PA_COMMAND_CREATE_PLAYBACK_STREAM, PA_COMMAND_DELETE_PLAYBACK_STREAM, PA_COMMAND_CREATE_RECORD_STREAM, PA_COMMAND_DELETE_RECORD_STREAM, PA_COMMAND_EXIT, - PA_COMMAND_REQUEST, PA_COMMAND_AUTH, PA_COMMAND_SET_CLIENT_NAME, PA_COMMAND_LOOKUP_SINK, PA_COMMAND_LOOKUP_SOURCE, PA_COMMAND_DRAIN_PLAYBACK_STREAM, - PA_COMMAND_PLAYBACK_STREAM_KILLED, - PA_COMMAND_RECORD_STREAM_KILLED, PA_COMMAND_STAT, PA_COMMAND_GET_PLAYBACK_LATENCY, PA_COMMAND_CREATE_UPLOAD_STREAM, @@ -68,7 +68,6 @@ enum { PA_COMMAND_GET_SAMPLE_INFO, PA_COMMAND_GET_SAMPLE_INFO_LIST, PA_COMMAND_SUBSCRIBE, - PA_COMMAND_SUBSCRIBE_EVENT, PA_COMMAND_SET_SINK_VOLUME, PA_COMMAND_SET_SINK_INPUT_VOLUME, @@ -95,6 +94,15 @@ enum { PA_COMMAND_CORK_RECORD_STREAM, PA_COMMAND_FLUSH_RECORD_STREAM, PA_COMMAND_PREBUF_PLAYBACK_STREAM, + + /* Commands from server to client */ + PA_COMMAND_REQUEST, + PA_COMMAND_OVERFLOW, + PA_COMMAND_UNDERFLOW, + PA_COMMAND_PLAYBACK_STREAM_KILLED, + PA_COMMAND_RECORD_STREAM_KILLED, + PA_COMMAND_SUBSCRIBE_EVENT, + PA_COMMAND_MAX }; diff --git a/src/polypcore/packet.c b/src/polypcore/packet.c index 41803cf9..31ddad95 100644 --- a/src/polypcore/packet.c +++ b/src/polypcore/packet.c @@ -32,37 +32,46 @@ pa_packet* pa_packet_new(size_t length) { pa_packet *p; + assert(length); + p = pa_xmalloc(sizeof(pa_packet)+length); p->ref = 1; p->length = length; p->data = (uint8_t*) (p+1); p->type = PA_PACKET_APPENDED; + return p; } -pa_packet* pa_packet_new_dynamic(uint8_t* data, size_t length) { +pa_packet* pa_packet_new_dynamic(void* data, size_t length) { pa_packet *p; - assert(data && length); - p = pa_xmalloc(sizeof(pa_packet)); + + assert(data); + assert(length); + + p = pa_xnew(pa_packet, 1); p->ref = 1; p->length = length; p->data = data; p->type = PA_PACKET_DYNAMIC; + return p; } pa_packet* pa_packet_ref(pa_packet *p) { - assert(p && p->ref >= 1); + assert(p); + assert(p->ref >= 1); + p->ref++; return p; } void pa_packet_unref(pa_packet *p) { - assert(p && p->ref >= 1); - p->ref--; - - if (p->ref == 0) { + assert(p); + assert(p->ref >= 1); + + if (--p->ref == 0) { if (p->type == PA_PACKET_DYNAMIC) pa_xfree(p->data); pa_xfree(p); diff --git a/src/polypcore/packet.h b/src/polypcore/packet.h index 0ac47485..fbc58232 100644 --- a/src/polypcore/packet.h +++ b/src/polypcore/packet.h @@ -33,7 +33,7 @@ typedef struct pa_packet { } pa_packet; pa_packet* pa_packet_new(size_t length); -pa_packet* pa_packet_new_dynamic(uint8_t* data, size_t length); +pa_packet* pa_packet_new_dynamic(void* data, size_t length); pa_packet* pa_packet_ref(pa_packet *p); void pa_packet_unref(pa_packet *p); diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index a16ac280..5adff57a 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -186,6 +186,7 @@ static void connection_free(struct connection *c) { if (c->sink_input) { pa_sink_input_disconnect(c->sink_input); + pa_log("disconnect\n"); pa_sink_input_unref(c->sink_input); } @@ -333,7 +334,15 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t } l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); - c->input_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&ss), l/2, l/PLAYBACK_BUFFER_FRAGMENTS, c->protocol->core->memblock_stat); + c->input_memblockq = pa_memblockq_new( + 0, + l, + 0, + pa_frame_size(&ss), + (size_t) -1, + l/PLAYBACK_BUFFER_FRAGMENTS, + NULL, + c->protocol->core->memblock_stat); pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2); c->playback.fragment_size = l/10; @@ -405,7 +414,15 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co } l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); - c->output_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&ss), 0, 0, c->protocol->core->memblock_stat); + c->output_memblockq = pa_memblockq_new( + 0, + l, + 0, + pa_frame_size(&ss), + 1, + 0, + NULL, + c->protocol->core->memblock_stat); pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); c->source_output->owner = c->protocol->module; @@ -724,8 +741,7 @@ static int do_read(struct connection *c) { assert(c->read_data_length < sizeof(c->request)); if ((r = pa_iochannel_read(c->io, ((uint8_t*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { - if (r != 0) - pa_log_warn(__FILE__": read() failed: %s\n", strerror(errno)); + pa_log_debug(__FILE__": read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); return -1; } @@ -773,8 +789,7 @@ static int do_read(struct connection *c) { assert(c->read_data && c->read_data_length < handler->data_length); if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { - if (r != 0) - pa_log_warn(__FILE__": read() failed: %s\n", strerror(errno)); + pa_log_debug(__FILE__": read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); return -1; } @@ -794,8 +809,7 @@ static int do_read(struct connection *c) { assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { - if (r!= 0) - pa_log_warn(__FILE__": read() failed: %s\n", strerror(errno)); + pa_log_debug(__FILE__": read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); return -1; } @@ -852,13 +866,10 @@ static int do_read(struct connection *c) { } if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { - if (r != 0) - pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + pa_log_debug(__FILE__": read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); return -1; } -/* pa_log(__FILE__": read %u\n", r); */ - chunk.memblock = c->playback.current_memblock; chunk.index = c->playback.memblock_index; chunk.length = r; @@ -867,7 +878,7 @@ static int do_read(struct connection *c) { c->playback.memblock_index += r; assert(c->input_memblockq); - pa_memblockq_push_align(c->input_memblockq, &chunk, 0); + pa_memblockq_push_align(c->input_memblockq, &chunk); assert(c->sink_input); pa_sink_notify(c->sink_input->sink); } @@ -910,6 +921,8 @@ static int do_write(struct connection *c) { pa_memblockq_drop(c->output_memblockq, &chunk, r); pa_memblock_unref(chunk.memblock); + + pa_source_notify(c->source_output->source); } return 0; @@ -921,21 +934,18 @@ static void do_work(struct connection *c) { assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); c->protocol->core->mainloop->defer_enable(c->defer_event, 0); -/* pa_log("DOWORK %i\n", pa_iochannel_is_hungup(c->io)); */ + if (c->dead) + return; - if (!c->dead && pa_iochannel_is_readable(c->io)) + if (pa_iochannel_is_readable(c->io)) { if (do_read(c) < 0) goto fail; + } else if (pa_iochannel_is_hungup(c->io)) + goto fail; - if (!c->dead && pa_iochannel_is_writable(c->io)) + if (pa_iochannel_is_writable(c->io)) if (do_write(c) < 0) goto fail; - - /* In case the line was hungup, make sure to rerun this function - as soon as possible, until all data has been read. */ - - if (!c->dead && pa_iochannel_is_hungup(c->io)) - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); return; @@ -943,15 +953,17 @@ fail: if (c->state == ESD_STREAMING_DATA && c->sink_input) { c->dead = 1; - pa_memblockq_prebuf_disable(c->input_memblockq); pa_iochannel_free(c->io); c->io = NULL; - + + pa_memblockq_prebuf_disable(c->input_memblockq); + pa_sink_notify(c->sink_input->sink); } else connection_free(c); } + static void io_callback(pa_iochannel*io, void *userdata) { struct connection *c = userdata; assert(io && c && c->io == io); @@ -1024,7 +1036,7 @@ static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) struct connection *c = o->userdata; assert(o && c && chunk); - pa_memblockq_push(c->output_memblockq, chunk, 0); + pa_memblockq_push(c->output_memblockq, chunk); /* do something */ assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 1362fdf2..aaa4fc48 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -48,6 +48,8 @@ #include #include #include +#include +#include #include "protocol-native.h" @@ -77,6 +79,11 @@ struct playback_stream { size_t requested_bytes; int drain_request; uint32_t drain_tag; + uint32_t syncid; + int underrun; + + /* Sync group members */ + PA_LLIST_FIELDS(struct playback_stream); }; struct upload_stream { @@ -153,7 +160,8 @@ static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_flush_or_trigger_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_flush_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_trigger_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); @@ -210,9 +218,9 @@ static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume, [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream, - [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_flush_or_trigger_playback_stream, - [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_flush_or_trigger_playback_stream, - [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_flush_or_trigger_playback_stream, + [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_flush_playback_stream, + [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_prebuf_playback_stream, + [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_prebuf_playback_stream, [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream, [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream, @@ -244,7 +252,7 @@ static struct upload_stream* upload_stream_new( struct upload_stream *s; assert(c && ss && name && length); - s = pa_xmalloc(sizeof(struct upload_stream)); + s = pa_xnew(struct upload_stream, 1); s->type = UPLOAD_STREAM; s->connection = c; s->sample_spec = *ss; @@ -291,7 +299,7 @@ static struct record_stream* record_stream_new( if (!(source_output = pa_source_output_new(source, __FILE__, name, ss, map, -1))) return NULL; - s = pa_xmalloc(sizeof(struct record_stream)); + s = pa_xnew(struct record_stream, 1); s->connection = c; s->source_output = source_output; s->source_output->push = source_output_push_cb; @@ -301,7 +309,15 @@ static struct record_stream* record_stream_new( s->source_output->owner = c->protocol->module; s->source_output->client = c->client; - s->memblockq = pa_memblockq_new(maxlength, 0, base = pa_frame_size(ss), 0, 0, c->protocol->core->memblock_stat); + s->memblockq = pa_memblockq_new( + 0, + maxlength, + 0, + base = pa_frame_size(ss), + 1, + 0, + NULL, + c->protocol->core->memblock_stat); assert(s->memblockq); s->fragment_size = (fragment_size/base)*base; @@ -332,19 +348,40 @@ static struct playback_stream* playback_stream_new( size_t tlength, size_t prebuf, size_t minreq, - pa_cvolume *volume) { + pa_cvolume *volume, + uint32_t syncid) { - struct playback_stream *s; + struct playback_stream *s, *sync; pa_sink_input *sink_input; + pa_memblock *silence; + uint32_t idx; + int64_t start_index; + assert(c && sink && ss && name && maxlength); + /* Find syncid group */ + for (sync = pa_idxset_first(c->output_streams, &idx); sync; sync = pa_idxset_next(c->output_streams, &idx)) { + + if (sync->type != PLAYBACK_STREAM) + continue; + + if (sync->syncid == syncid) + break; + } + + /* Synced streams must connect to the same sink */ + if (sync && sync->sink_input->sink != sink) + return NULL; + if (!(sink_input = pa_sink_input_new(sink, __FILE__, name, ss, map, 0, -1))) return NULL; - s = pa_xmalloc(sizeof(struct playback_stream)); + s = pa_xnew(struct playback_stream, 1); s->type = PLAYBACK_STREAM; s->connection = c; + s->syncid = syncid; s->sink_input = sink_input; + s->underrun = 1; s->sink_input->peek = sink_input_peek_cb; s->sink_input->drop = sink_input_drop_cb; @@ -353,24 +390,56 @@ static struct playback_stream* playback_stream_new( s->sink_input->userdata = s; s->sink_input->owner = c->protocol->module; s->sink_input->client = c->client; - - s->memblockq = pa_memblockq_new(maxlength, tlength, pa_frame_size(ss), prebuf, minreq, c->protocol->core->memblock_stat); - assert(s->memblockq); + if (sync) { + /* Sync id found, now find head of list */ + PA_LLIST_FIND_HEAD(struct playback_stream, sync, &sync); + + /* Prepend ourselves */ + PA_LLIST_PREPEND(struct playback_stream, sync, s); + + /* Set our start index to the current read index of the other grozp member(s) */ + assert(sync->next); + start_index = pa_memblockq_get_read_index(sync->next->memblockq); + } else { + /* This ia a new sync group */ + PA_LLIST_INIT(struct playback_stream, s); + start_index = 0; + } + + silence = pa_silence_memblock_new(ss, 0, c->protocol->core->memblock_stat); + + s->memblockq = pa_memblockq_new( + start_index, + maxlength, + tlength, + pa_frame_size(ss), + prebuf, + minreq, + silence, + c->protocol->core->memblock_stat); + + pa_memblock_unref(silence); + s->requested_bytes = 0; s->drain_request = 0; s->sink_input->volume = *volume; pa_idxset_put(c->output_streams, s, &s->index); + return s; } static void playback_stream_free(struct playback_stream* p) { + struct playback_stream *head; assert(p && p->connection); if (p->drain_request) - pa_pstream_send_error(p->connection->pstream, p->drain_tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(p->connection->pstream, p->drain_tag, PA_ERR_NOENTITY); + + PA_LLIST_FIND_HEAD(struct playback_stream, p, &head); + PA_LLIST_REMOVE(struct playback_stream, head, p); pa_idxset_remove_by_data(p->connection->output_streams, p, NULL); pa_sink_input_disconnect(p->sink_input); @@ -436,7 +505,7 @@ static void request_bytes(struct playback_stream *s) { pa_tagstruct_putu32(t, l); pa_pstream_send_tagstruct(s->connection->pstream, t); -/* pa_log(__FILE__": Requesting %u bytes\n", l); */ +/* pa_log(__FILE__": Requesting %u bytes\n", l); */ } static void send_memblock(struct connection *c) { @@ -461,7 +530,7 @@ static void send_memblock(struct connection *c) { if (schunk.length > r->fragment_size) schunk.length = r->fragment_size; - pa_pstream_send_memblock(c->pstream, r->index, 0, &schunk); + pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk); pa_memblockq_drop(r->memblockq, &chunk, schunk.length); pa_memblock_unref(schunk.memblock); @@ -501,9 +570,27 @@ static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { assert(i && i->userdata && chunk); s = i->userdata; - if (pa_memblockq_peek(s->memblockq, chunk) < 0) + if (pa_memblockq_get_length(s->memblockq) <= 0 && !s->underrun) { + pa_tagstruct *t; + + /* Report that we're empty */ + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, s->index); + pa_pstream_send_tagstruct(s->connection->pstream, t); + + s->underrun = 1; + } + + if (pa_memblockq_peek(s->memblockq, chunk) < 0) { + pa_log(__FILE__": peek: failure\n"); return -1; + } +/* pa_log(__FILE__": peek: %u\n", chunk->length); */ + return 0; } @@ -513,6 +600,7 @@ static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_ s = i->userdata; pa_memblockq_drop(s->memblockq, chunk, length); + request_bytes(s); if (s->drain_request && !pa_memblockq_is_readable(s->memblockq)) { @@ -520,7 +608,7 @@ static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_ s->drain_request = 0; } -/* pa_log(__FILE__": after_drop: %u\n", pa_memblockq_get_length(s->memblockq)); */ +/* pa_log(__FILE__": after_drop: %u %u\n", pa_memblockq_get_length(s->memblockq), pa_memblockq_is_readable(s->memblockq)); */ } static void sink_input_kill_cb(pa_sink_input *i) { @@ -546,7 +634,11 @@ static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) assert(o && o->userdata && chunk); s = o->userdata; - pa_memblockq_push_align(s->memblockq, chunk, 0); + if (pa_memblockq_push_align(s->memblockq, chunk) < 0) { + pa_log_warn(__FILE__": Failed to push data into output queue.\n"); + return; + } + if (!pa_pstream_is_pending(s->connection->pstream)) send_memblock(s->connection); } @@ -578,7 +670,7 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC struct connection *c = userdata; struct playback_stream *s; size_t maxlength, tlength, prebuf, minreq; - uint32_t sink_index; + uint32_t sink_index, syncid; const char *name, *sink_name; pa_sample_spec ss; pa_channel_map map; @@ -601,6 +693,7 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC PA_TAG_U32, &tlength, PA_TAG_U32, &prebuf, PA_TAG_U32, &minreq, + PA_TAG_U32, &syncid, PA_TAG_CVOLUME, &volume, PA_TAG_INVALID) < 0 || !pa_tagstruct_eof(t) || @@ -610,23 +703,23 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } - if (sink_index != (uint32_t) -1) + if (sink_index != PA_INVALID_INDEX) sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); else sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1); if (!sink) { - pa_log("%s: Can't find a suitable sink.\n", __FILE__); - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_log_warn(__FILE__": Can't find a suitable sink.\n"); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } - if (!(s = playback_stream_new(c, sink, &ss, &map, name, maxlength, tlength, prebuf, minreq, &volume))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); + if (!(s = playback_stream_new(c, sink, &ss, &map, name, maxlength, tlength, prebuf, minreq, &volume, syncid))) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); return; } @@ -656,14 +749,14 @@ static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } if (command == PA_COMMAND_DELETE_PLAYBACK_STREAM) { struct playback_stream *s; if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != PLAYBACK_STREAM)) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); return; } @@ -671,7 +764,7 @@ static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma } else if (command == PA_COMMAND_DELETE_RECORD_STREAM) { struct record_stream *s; if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); return; } @@ -680,7 +773,7 @@ static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma struct upload_stream *s; assert(command == PA_COMMAND_DELETE_UPLOAD_STREAM); if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != UPLOAD_STREAM)) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); return; } @@ -717,7 +810,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -727,12 +820,12 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE, 1); if (!source) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } if (!(s = record_stream_new(c, source, &ss, &map, name, maxlength, fragment_size))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); + pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); return; } @@ -758,7 +851,7 @@ static void command_exit(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -782,7 +875,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t if (!c->authorized) { if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) != 0) { pa_log(__FILE__": Denied access to client with invalid authorization key.\n"); - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -826,7 +919,7 @@ static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uin } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -842,7 +935,7 @@ static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uin } if (idx == PA_IDXSET_INVALID) - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); else { pa_tagstruct *reply; reply = pa_tagstruct_new(NULL, 0); @@ -867,12 +960,12 @@ static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } @@ -881,10 +974,10 @@ static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC pa_memblockq_prebuf_disable(s->memblockq); if (!pa_memblockq_is_readable(s->memblockq)) { -/* pa_log("immediate drain: %u\n", pa_memblockq_get_length(s->memblockq)); */ +/* pa_log("immediate drain: %u\n", pa_memblockq_get_length(s->memblockq)); */ pa_pstream_send_simple_ack(c->pstream, tag); } else { -/* pa_log("slow drain triggered\n"); */ +/* pa_log("slow drain triggered\n"); */ s->drain_request = 1; s->drain_tag = tag; @@ -903,7 +996,7 @@ static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -937,12 +1030,12 @@ static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } @@ -980,12 +1073,12 @@ static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } @@ -1026,17 +1119,17 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } if ((length % pa_frame_size(&ss)) != 0 || length <= 0 || !*name) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); + pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); return; } if (!(s = upload_stream_new(c, &ss, &map, name, length))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); + pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); return; } @@ -1063,12 +1156,12 @@ static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != UPLOAD_STREAM)) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); return; } @@ -1095,7 +1188,7 @@ static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -1105,12 +1198,12 @@ static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1); if (!sink) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } if (pa_scache_play_item(c->protocol->core, name, sink, &volume) < 0) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } @@ -1129,12 +1222,12 @@ static void command_remove_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } if (pa_scache_remove_item(c->protocol->core, name) < 0) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } @@ -1261,7 +1354,7 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -1292,7 +1385,7 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u } if (!sink && !source && !client && !module && !si && !so && !sce) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } @@ -1331,7 +1424,7 @@ static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -1394,7 +1487,7 @@ static void command_get_server_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -1444,7 +1537,7 @@ static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -1478,7 +1571,7 @@ static void command_set_volume(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -1493,7 +1586,7 @@ static void command_set_volume(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, } if (!si && !sink) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } @@ -1509,7 +1602,7 @@ static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ struct connection *c = userdata; uint32_t idx; int b; - struct playback_stream *s; + struct playback_stream *s, *sync; assert(c && t); if (pa_tagstruct_getu32(t, &idx) < 0 || @@ -1520,20 +1613,82 @@ static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } + fprintf(stderr, "Corking %i\n", b); + pa_sink_input_cork(s->sink_input, b); + pa_memblockq_prebuf_force(s->memblockq); + + /* Do the same for all other members in the sync group */ + for (sync = s->prev; sync; sync = sync->prev) { + pa_sink_input_cork(sync->sink_input, b); + pa_memblockq_prebuf_force(sync->memblockq); + } + + for (sync = s->next; sync; sync = sync->next) { + pa_sink_input_cork(sync->sink_input, b); + pa_memblockq_prebuf_force(sync->memblockq); + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_flush_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + struct playback_stream *s, *sync; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); + return; + } + + if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); + return; + } + + pa_memblockq_flush(s->memblockq); + s->underrun = 0; + + /* Do the same for all other members in the sync group */ + for (sync = s->prev; sync; sync = sync->prev) { + pa_memblockq_flush(sync->memblockq); + sync->underrun = 0; + } + + for (sync = s->next; sync; sync = sync->next) { + pa_memblockq_flush(sync->memblockq); + sync->underrun = 0; + } + pa_pstream_send_simple_ack(c->pstream, tag); + pa_sink_notify(s->sink_input->sink); + request_bytes(s); + + for (sync = s->prev; sync; sync = sync->prev) + request_bytes(sync); + + for (sync = s->next; sync; sync = sync->next) + request_bytes(sync); } -static void command_flush_or_trigger_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_trigger_or_prebuf_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; uint32_t idx; struct playback_stream *s; @@ -1546,23 +1701,26 @@ static void command_flush_or_trigger_playback_stream(PA_GCC_UNUSED pa_pdispatch } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } - if (command == PA_COMMAND_PREBUF_PLAYBACK_STREAM) - pa_memblockq_prebuf_reenable(s->memblockq); - else if (command == PA_COMMAND_TRIGGER_PLAYBACK_STREAM) - pa_memblockq_prebuf_disable(s->memblockq); - else { - assert(command == PA_COMMAND_FLUSH_PLAYBACK_STREAM); - pa_memblockq_flush(s->memblockq); - /*pa_log(__FILE__": flush: %u\n", pa_memblockq_get_length(s->memblockq));*/ + switch (command) { + case PA_COMMAND_PREBUF_PLAYBACK_STREAM: + pa_memblockq_prebuf_force(s->memblockq); + break; + + case PA_COMMAND_TRIGGER_PLAYBACK_STREAM: + pa_memblockq_prebuf_disable(s->memblockq); + break; + + default: + abort(); } pa_sink_notify(s->sink_input->sink); @@ -1585,16 +1743,17 @@ static void command_cork_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } pa_source_output_cork(s->source_output, b); + pa_memblockq_prebuf_force(s->memblockq); pa_pstream_send_simple_ack(c->pstream, tag); } @@ -1611,12 +1770,12 @@ static void command_flush_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_U } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } @@ -1638,7 +1797,7 @@ static void command_set_default_sink_or_source(PA_GCC_UNUSED pa_pdispatch *pd, u } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -1660,7 +1819,7 @@ static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t com } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -1668,7 +1827,7 @@ static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t com struct playback_stream *s; if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } @@ -1678,7 +1837,7 @@ static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t com struct record_stream *s; if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } @@ -1700,7 +1859,7 @@ static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint3 } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -1708,7 +1867,7 @@ static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint3 pa_client *client; if (!(client = pa_idxset_get_by_index(c->protocol->core->clients, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } @@ -1717,7 +1876,7 @@ static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint3 pa_sink_input *s; if (!(s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } @@ -1728,7 +1887,7 @@ static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint3 assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT); if (!(s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } @@ -1753,12 +1912,12 @@ static void command_load_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } if (!(m = pa_module_load(c->protocol->core, name, argument))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_INITFAILED); + pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED); return; } @@ -1782,12 +1941,12 @@ static void command_unload_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } if (!(m = pa_idxset_get_by_index(c->protocol->core->modules, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } @@ -1813,12 +1972,12 @@ static void command_add_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED u } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } if (pa_autoload_add(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, module, argument, &idx) < 0) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_EXIST); + pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); return; } @@ -1847,7 +2006,7 @@ static void command_remove_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -1857,7 +2016,7 @@ static void command_remove_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE r = pa_autoload_remove_by_index(c->protocol->core, idx); if (r < 0) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } @@ -1893,7 +2052,7 @@ static void command_get_autoload_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNU } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -1904,7 +2063,7 @@ static void command_get_autoload_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNU a = pa_autoload_get_by_index(c->protocol->core, idx); if (!a) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } @@ -1927,7 +2086,7 @@ static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC } if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -1958,7 +2117,7 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *user } } -static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata) { +static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { struct connection *c = userdata; struct output_stream *stream; assert(p && chunk && userdata); @@ -1975,13 +2134,30 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, uint32_t ps->requested_bytes = 0; else ps->requested_bytes -= chunk->length; - - pa_memblockq_push_align(ps->memblockq, chunk, delta); - assert(ps->sink_input); -/* pa_log(__FILE__": after_recv: %u\n", pa_memblockq_get_length(p->memblockq)); */ + pa_memblockq_seek(ps->memblockq, offset, seek); + + if (pa_memblockq_push_align(ps->memblockq, chunk) < 0) { + pa_tagstruct *t; + + pa_log_warn(__FILE__": failed to push data into queue\n"); + + /* Pushing this block into the queue failed, so we simulate + * it by skipping ahead */ + + pa_memblockq_seek(ps->memblockq, chunk->length, PA_SEEK_RELATIVE); + + /* Notify the user */ + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, ps->index); + pa_pstream_send_tagstruct(p, t); + } + + ps->underrun = 0; + pa_sink_notify(ps->sink_input->sink); -/* pa_log(__FILE__": Recieved %u bytes.\n", chunk->length); */ } else { struct upload_stream *u = (struct upload_stream*) stream; diff --git a/src/polypcore/protocol-simple.c b/src/polypcore/protocol-simple.c index 4d3f8e1d..fac54239 100644 --- a/src/polypcore/protocol-simple.c +++ b/src/polypcore/protocol-simple.c @@ -52,6 +52,8 @@ struct connection { pa_memblockq *input_memblockq, *output_memblockq; pa_defer_event *defer_event; + int dead; + struct { pa_memblock *current_memblock; size_t memblock_index, fragment_size; @@ -130,7 +132,7 @@ static int do_read(struct connection *c) { } if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { - pa_log(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + pa_log_debug(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } @@ -142,7 +144,7 @@ static int do_read(struct connection *c) { c->playback.memblock_index += r; assert(c->input_memblockq); - pa_memblockq_push_align(c->input_memblockq, &chunk, 0); + pa_memblockq_push_align(c->input_memblockq, &chunk); assert(c->sink_input); pa_sink_notify(c->sink_input->sink); @@ -170,32 +172,46 @@ static int do_write(struct connection *c) { pa_memblockq_drop(c->output_memblockq, &chunk, r); pa_memblock_unref(chunk.memblock); + + pa_source_notify(c->source_output->source); return 0; } - static void do_work(struct connection *c) { assert(c); assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); c->protocol->core->mainloop->defer_enable(c->defer_event, 0); - if (pa_iochannel_is_writable(c->io)) - if (do_write(c) < 0) - goto fail; + if (c->dead) + return; - if (pa_iochannel_is_readable(c->io)) + if (pa_iochannel_is_readable(c->io)) { if (do_read(c) < 0) goto fail; + } else if (pa_iochannel_is_hungup(c->io)) + goto fail; - if (pa_iochannel_is_hungup(c->io)) - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + if (pa_iochannel_is_writable(c->io)) { + if (do_write(c) < 0) + goto fail; + } return; fail: - connection_free(c); + + if (c->sink_input) { + c->dead = 1; + + pa_iochannel_free(c->io); + c->io = NULL; + + pa_memblockq_prebuf_disable(c->input_memblockq); + pa_sink_notify(c->sink_input->sink); + } else + connection_free(c); } /*** sink_input callbacks ***/ @@ -205,8 +221,13 @@ static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { assert(i && i->userdata && chunk); c = i->userdata; - if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) + if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) { + + if (c->dead) + connection_free(c); + return -1; + } return 0; } @@ -240,7 +261,7 @@ static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) struct connection *c = o->userdata; assert(o && c && chunk); - pa_memblockq_push(c->output_memblockq, chunk, 0); + pa_memblockq_push(c->output_memblockq, chunk); /* do something */ assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); @@ -307,6 +328,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->playback.current_memblock = NULL; c->playback.memblock_index = 0; c->playback.fragment_size = 0; + c->dead = 0; pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); c->client = pa_client_new(p->core, __FILE__, cname); @@ -339,7 +361,15 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->sink_input->userdata = c; l = (size_t) (pa_bytes_per_second(&p->sample_spec)*PLAYBACK_BUFFER_SECONDS); - c->input_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&p->sample_spec), l/2, l/PLAYBACK_BUFFER_FRAGMENTS, p->core->memblock_stat); + c->input_memblockq = pa_memblockq_new( + 0, + l, + 0, + pa_frame_size(&p->sample_spec), + (size_t) -1, + l/PLAYBACK_BUFFER_FRAGMENTS, + NULL, + p->core->memblock_stat); assert(c->input_memblockq); pa_iochannel_socket_set_rcvbuf(io, l/PLAYBACK_BUFFER_FRAGMENTS*5); c->playback.fragment_size = l/10; @@ -368,7 +398,15 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->source_output->userdata = c; l = (size_t) (pa_bytes_per_second(&p->sample_spec)*RECORD_BUFFER_SECONDS); - c->output_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&p->sample_spec), 0, 0, p->core->memblock_stat); + c->output_memblockq = pa_memblockq_new( + 0, + l, + 0, + pa_frame_size(&p->sample_spec), + 1, + 0, + NULL, + p->core->memblock_stat); pa_iochannel_socket_set_sndbuf(io, l/RECORD_BUFFER_FRAGMENTS*2); } diff --git a/src/polypcore/pstream.c b/src/polypcore/pstream.c index eec93a0f..c697dc3d 100644 --- a/src/polypcore/pstream.c +++ b/src/polypcore/pstream.c @@ -40,12 +40,14 @@ #include "pstream.h" -typedef enum pa_pstream_descriptor_index { +enum { PA_PSTREAM_DESCRIPTOR_LENGTH, PA_PSTREAM_DESCRIPTOR_CHANNEL, - PA_PSTREAM_DESCRIPTOR_DELTA, + PA_PSTREAM_DESCRIPTOR_OFFSET_HI, + PA_PSTREAM_DESCRIPTOR_OFFSET_LO, + PA_PSTREAM_DESCRIPTOR_SEEK, PA_PSTREAM_DESCRIPTOR_MAX -} pa_pstream_descriptor_index; +}; typedef uint32_t pa_pstream_descriptor[PA_PSTREAM_DESCRIPTOR_MAX]; @@ -58,7 +60,8 @@ struct item_info { /* memblock info */ pa_memchunk chunk; uint32_t channel; - uint32_t delta; + int64_t offset; + pa_seek_mode_t seek_mode; /* packet info */ pa_packet *packet; @@ -94,7 +97,7 @@ struct pa_pstream { void (*recieve_packet_callback) (pa_pstream *p, pa_packet *packet, void *userdata); void *recieve_packet_callback_userdata; - void (*recieve_memblock_callback) (pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata); + void (*recieve_memblock_callback) (pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata); void *recieve_memblock_callback_userdata; void (*drain_callback)(pa_pstream *p, void *userdata); @@ -103,8 +106,8 @@ struct pa_pstream { pa_memblock_stat *memblock_stat; }; -static void do_write(pa_pstream *p); -static void do_read(pa_pstream *p); +static int do_write(pa_pstream *p); +static int do_read(pa_pstream *p); static void do_something(pa_pstream *p) { assert(p); @@ -112,31 +115,47 @@ static void do_something(pa_pstream *p) { p->mainloop->defer_enable(p->defer_event, 0); pa_pstream_ref(p); - - if (!p->dead && pa_iochannel_is_readable(p->io)) - do_read(p); - if (!p->dead && pa_iochannel_is_writable(p->io)) - do_write(p); + if (!p->dead && pa_iochannel_is_readable(p->io)) { + if (do_read(p) < 0) + goto fail; + } else if (!p->dead && pa_iochannel_is_hungup(p->io)) + goto fail; + + if (!p->dead && pa_iochannel_is_writable(p->io)) { + if (do_write(p) < 0) + goto fail; + } + + pa_pstream_unref(p); + return; + +fail: - /* In case the line was hungup, make sure to rerun this function - as soon as possible, until all data has been read. */ + p->dead = 1; - if (!p->dead && pa_iochannel_is_hungup(p->io)) - p->mainloop->defer_enable(p->defer_event, 1); + if (p->die_callback) + p->die_callback(p, p->die_callback_userdata); pa_pstream_unref(p); } static void io_callback(pa_iochannel*io, void *userdata) { pa_pstream *p = userdata; - assert(p && p->io == io); + + assert(p); + assert(p->io == io); + do_something(p); } static void defer_callback(pa_mainloop_api *m, pa_defer_event *e, void*userdata) { pa_pstream *p = userdata; - assert(p && p->defer_event == e && p->mainloop == m); + + assert(p); + assert(p->defer_event == e); + assert(p->mainloop == m); + do_something(p); } @@ -144,7 +163,8 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_sta pa_pstream *p; assert(io); - p = pa_xmalloc(sizeof(pa_pstream)); + p = pa_xnew(pa_pstream, 1); + p->ref = 1; p->io = io; pa_iochannel_set_callback(io, io_callback, p); @@ -228,7 +248,7 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet) { /* pa_log(__FILE__": push-packet %p\n", packet); */ - i = pa_xmalloc(sizeof(struct item_info)); + i = pa_xnew(struct item_info, 1); i->type = PA_PSTREAM_ITEM_PACKET; i->packet = pa_packet_ref(packet); @@ -236,7 +256,7 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet) { p->mainloop->defer_enable(p->defer_event, 1); } -void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk) { +void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek_mode, const pa_memchunk *chunk) { struct item_info *i; assert(p && channel != (uint32_t) -1 && chunk && p->ref >= 1); @@ -245,11 +265,12 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, uint32_t delta, co /* pa_log(__FILE__": push-memblock %p\n", chunk); */ - i = pa_xmalloc(sizeof(struct item_info)); + i = pa_xnew(struct item_info, 1); i->type = PA_PSTREAM_ITEM_MEMBLOCK; i->chunk = *chunk; i->channel = channel; - i->delta = delta; + i->offset = offset; + i->seek_mode = seek_mode; pa_memblock_ref(i->chunk.memblock); @@ -264,7 +285,7 @@ void pa_pstream_set_recieve_packet_callback(pa_pstream *p, void (*callback) (pa_ p->recieve_packet_callback_userdata = userdata; } -void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, void (*callback) (pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata), void *userdata) { +void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, void (*callback) (pa_pstream *p, uint32_t channel, int64_t delta, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata), void *userdata) { assert(p && callback); p->recieve_memblock_callback = callback; @@ -286,17 +307,21 @@ static void prepare_next_write_item(pa_pstream *p) { p->write.data = p->write.current->packet->data; p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->packet->length); p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl((uint32_t) -1); - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA] = 0; + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = 0; + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = 0; + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK] = 0; } else { assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK && p->write.current->chunk.memblock); p->write.data = (uint8_t*) p->write.current->chunk.memblock->data + p->write.current->chunk.index; p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length); p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl(p->write.current->channel); - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA] = htonl(p->write.current->delta); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = htonl((uint32_t) (((uint64_t) p->write.current->offset) >> 32)); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = htonl((uint32_t) ((uint64_t) p->write.current->offset)); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK] = htonl(p->write.current->seek_mode); } } -static void do_write(pa_pstream *p) { +static int do_write(pa_pstream *p) { void *d; size_t l; ssize_t r; @@ -306,7 +331,7 @@ static void do_write(pa_pstream *p) { prepare_next_write_item(p); if (!p->write.current) - return; + return 0; assert(p->write.data); @@ -319,7 +344,7 @@ static void do_write(pa_pstream *p) { } if ((r = pa_iochannel_write(p->io, d, l)) < 0) - goto die; + return -1; p->write.index += r; @@ -332,15 +357,10 @@ static void do_write(pa_pstream *p) { p->drain_callback(p, p->drain_userdata); } - return; - -die: - p->dead = 1; - if (p->die_callback) - p->die_callback(p, p->die_callback_userdata); + return 0; } -static void do_read(pa_pstream *p) { +static int do_read(pa_pstream *p) { void *d; size_t l; ssize_t r; @@ -356,7 +376,7 @@ static void do_read(pa_pstream *p) { } if ((r = pa_iochannel_read(p->io, d, l)) <= 0) - goto die; + return -1; p->read.index += r; @@ -365,8 +385,8 @@ static void do_read(pa_pstream *p) { /* Frame size too large */ if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) > FRAME_SIZE_MAX) { - pa_log(__FILE__": Frame size too large\n"); - goto die; + pa_log_warn(__FILE__": Frame size too large\n"); + return -1; } assert(!p->read.packet && !p->read.memblock); @@ -374,13 +394,16 @@ static void do_read(pa_pstream *p) { if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]) == (uint32_t) -1) { /* Frame is a packet frame */ p->read.packet = pa_packet_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])); - assert(p->read.packet); p->read.data = p->read.packet->data; } else { /* Frame is a memblock frame */ p->read.memblock = pa_memblock_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]), p->memblock_stat); - assert(p->read.memblock); p->read.data = p->read.memblock->data; + + if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK]) > PA_SEEK_RELATIVE_END) { + pa_log_warn(__FILE__": Invalid seek mode\n"); + return -1; + } } } else if (p->read.index > PA_PSTREAM_DESCRIPTOR_SIZE) { @@ -396,13 +419,26 @@ static void do_read(pa_pstream *p) { chunk.index = p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE - l; chunk.length = l; - if (p->recieve_memblock_callback) + if (p->recieve_memblock_callback) { + int64_t offset; + + offset = (int64_t) ( + (((uint64_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])) << 32) | + (((uint64_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO])))); + p->recieve_memblock_callback( p, ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]), - ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_DELTA]), + offset, + ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK]), &chunk, p->recieve_memblock_callback_userdata); + } + + /* Drop seek info for following callbacks */ + p->read.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK] = + p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = + p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = 0; } } @@ -427,13 +463,7 @@ static void do_read(pa_pstream *p) { } } - return; - -die: - p->dead = 1; - if (p->die_callback) - p->die_callback(p, p->die_callback_userdata); - + return 0; } void pa_pstream_set_die_callback(pa_pstream *p, void (*callback)(pa_pstream *p, void *userdata), void *userdata) { @@ -453,20 +483,24 @@ int pa_pstream_is_pending(pa_pstream *p) { void pa_pstream_set_drain_callback(pa_pstream *p, void (*cb)(pa_pstream *p, void *userdata), void *userdata) { assert(p); + assert(p->ref >= 1); p->drain_callback = cb; p->drain_userdata = userdata; } void pa_pstream_unref(pa_pstream*p) { - assert(p && p->ref >= 1); + assert(p); + assert(p->ref >= 1); - if (!(--(p->ref))) + if (--p->ref == 0) pstream_free(p); } pa_pstream* pa_pstream_ref(pa_pstream*p) { - assert(p && p->ref >= 1); + assert(p); + assert(p->ref >= 1); + p->ref++; return p; } diff --git a/src/polypcore/pstream.h b/src/polypcore/pstream.h index 10ce58f6..741ba9b5 100644 --- a/src/polypcore/pstream.h +++ b/src/polypcore/pstream.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -37,10 +38,10 @@ void pa_pstream_unref(pa_pstream*p); pa_pstream* pa_pstream_ref(pa_pstream*p); void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet); -void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk); +void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk); void pa_pstream_set_recieve_packet_callback(pa_pstream *p, void (*callback) (pa_pstream *p, pa_packet *packet, void *userdata), void *userdata); -void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, void (*callback) (pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata), void *userdata); +void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, void (*callback) (pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata), void *userdata); void pa_pstream_set_drain_callback(pa_pstream *p, void (*cb)(pa_pstream *p, void *userdata), void *userdata); void pa_pstream_set_die_callback(pa_pstream *p, void (*callback)(pa_pstream *p, void *userdata), void *userdata); diff --git a/src/polypcore/sample-util.c b/src/polypcore/sample-util.c index e3bb4aa6..e588446d 100644 --- a/src/polypcore/sample-util.c +++ b/src/polypcore/sample-util.c @@ -34,6 +34,15 @@ #include "sample-util.h" +pa_memblock *pa_silence_memblock_new(const pa_sample_spec *spec, size_t length, pa_memblock_stat*s) { + assert(spec); + + if (length == 0) + length = pa_bytes_per_second(spec)/10; /* 100 ms */ + + return pa_silence_memblock(pa_memblock_new(length, s), spec); +} + pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) { assert(b && b->data && spec); pa_silence_memory(b->data, b->length, spec); diff --git a/src/polypcore/sample-util.h b/src/polypcore/sample-util.h index 486d284b..7ea01a30 100644 --- a/src/polypcore/sample-util.h +++ b/src/polypcore/sample-util.h @@ -28,6 +28,7 @@ #include pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec); +pa_memblock *pa_silence_memblock_new(const pa_sample_spec *spec, size_t length, pa_memblock_stat*s); void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec); void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec); diff --git a/src/polypcore/sink.c b/src/polypcore/sink.c index 9bc478c3..1f374f5e 100644 --- a/src/polypcore/sink.c +++ b/src/polypcore/sink.c @@ -270,6 +270,8 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { result->memblock = pa_memblock_new(length, s->core->memblock_stat); assert(result->memblock); +/* pa_log("mixing %i\n", n); */ + result->length = pa_mix(info, n, result->memblock->data, length, &s->sample_spec, &s->sw_volume); result->index = 0; } diff --git a/src/polypcore/sink.h b/src/polypcore/sink.h index 5fd9784f..fa120ebf 100644 --- a/src/polypcore/sink.h +++ b/src/polypcore/sink.h @@ -34,7 +34,7 @@ typedef struct pa_sink pa_sink; #include #include -#define PA_MAX_INPUTS_PER_SINK 6 +#define PA_MAX_INPUTS_PER_SINK 32 typedef enum pa_sink_state { PA_SINK_RUNNING, diff --git a/src/tests/memblockq-test.c b/src/tests/memblockq-test.c new file mode 100644 index 00000000..b01084da --- /dev/null +++ b/src/tests/memblockq-test.c @@ -0,0 +1,147 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +int main(int argc, char *argv[]) { + int ret; + pa_memblockq *bq; + pa_memchunk chunk1, chunk2, chunk3, chunk4; + pa_memblock *silence; + + pa_log_set_maximal_level(PA_LOG_DEBUG); + + silence = pa_memblock_new_fixed("__", 2, 1, NULL); + assert(silence); + + bq = pa_memblockq_new(0, 40, 10, 2, 4, 4, silence, NULL); + assert(bq); + + chunk1.memblock = pa_memblock_new_fixed("AA", 2, 1, NULL); + chunk1.index = 0; + chunk1.length = 2; + assert(chunk1.memblock); + + chunk2.memblock = pa_memblock_new_fixed("TTBB", 4, 1, NULL); + chunk2.index = 2; + chunk2.length = 2; + assert(chunk2.memblock); + + chunk3.memblock = pa_memblock_new_fixed("ZZZZ", 4, 1, NULL); + chunk3.index = 0; + chunk3.length = 4; + assert(chunk3.memblock); + + chunk4.memblock = pa_memblock_new_fixed("KKKKKKKK", 8, 1, NULL); + chunk4.index = 0; + chunk4.length = 8; + assert(chunk4.memblock); + + ret = pa_memblockq_push(bq, &chunk1); + assert(ret == 0); + + ret = pa_memblockq_push(bq, &chunk1); + assert(ret == 0); + + ret = pa_memblockq_push(bq, &chunk2); + assert(ret == 0); + + ret = pa_memblockq_push(bq, &chunk2); + assert(ret == 0); + + pa_memblockq_seek(bq, -6, 0); + ret = pa_memblockq_push(bq, &chunk3); + assert(ret == 0); + + pa_memblockq_seek(bq, -2, 0); + ret = pa_memblockq_push(bq, &chunk3); + assert(ret == 0); + + pa_memblockq_seek(bq, -10, 0); + ret = pa_memblockq_push(bq, &chunk4); + assert(ret == 0); + + pa_memblockq_seek(bq, 10, 0); + + ret = pa_memblockq_push(bq, &chunk1); + assert(ret == 0); + + pa_memblockq_seek(bq, -6, 0); + ret = pa_memblockq_push(bq, &chunk2); + assert(ret == 0); + + /* Test splitting */ + pa_memblockq_seek(bq, -12, 0); + ret = pa_memblockq_push(bq, &chunk1); + assert(ret == 0); + + pa_memblockq_seek(bq, 20, 0); + + /* Test merging */ + ret = pa_memblockq_push(bq, &chunk3); + assert(ret == 0); + pa_memblockq_seek(bq, -2, 0); + + chunk3.index += 2; + chunk3.length -= 2; + + ret = pa_memblockq_push(bq, &chunk3); + assert(ret == 0); + + printf(">"); + + pa_memblockq_shorten(bq, 6); + + for (;;) { + pa_memchunk out; + char *e; + size_t n; + + if (pa_memblockq_peek(bq, &out) < 0) + break; + + for (e = (char*) out.memblock->data + out.index, n = 0; n < out.length; n++) + printf("%c", *e); + + pa_memblock_unref(out.memblock); + pa_memblockq_drop(bq, &out, out.length); + } + + printf("<\n"); + + pa_memblockq_free(bq); + pa_memblock_unref(silence); + pa_memblock_unref(chunk1.memblock); + pa_memblock_unref(chunk2.memblock); + pa_memblock_unref(chunk3.memblock); + pa_memblock_unref(chunk4.memblock); + + return 0; +} diff --git a/src/tests/sync-playback.c b/src/tests/sync-playback.c new file mode 100644 index 00000000..5df790c9 --- /dev/null +++ b/src/tests/sync-playback.c @@ -0,0 +1,192 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define NSTREAMS 4 +#define SINE_HZ 440 +#define SAMPLE_HZ 8000 + +static pa_context *context = NULL; +static pa_stream *streams[NSTREAMS]; +static pa_mainloop_api *mainloop_api = NULL; + +static float data[SAMPLE_HZ]; /* one second space */ + +static int n_streams_ready = 0; + +static const pa_sample_spec sample_spec = { + .format = PA_SAMPLE_FLOAT32, + .rate = SAMPLE_HZ, + .channels = 1 +}; + +static const pa_buffer_attr buffer_attr = { + .maxlength = SAMPLE_HZ*sizeof(float)*NSTREAMS, /* exactly space for the entire play time */ + .tlength = 0, + .prebuf = 0, /* Setting prebuf to 0 guarantees us the the streams will run synchronously, no matter what */ + .minreq = 0 +}; + +static void nop_free_cb(void *p) {} + +static void underflow_cb(struct pa_stream *s, void *userdata) { + int i = (int) userdata; + + fprintf(stderr, "Stream %i finished\n", i); + + if (++n_streams_ready >= 2*NSTREAMS) { + fprintf(stderr, "We're done\n"); + mainloop_api->quit(mainloop_api, 0); + } +} + +/* This routine is called whenever the stream state changes */ +static void stream_state_callback(pa_stream *s, void *userdata) { + assert(s); + + switch (pa_stream_get_state(s)) { + case PA_STREAM_UNCONNECTED: + case PA_STREAM_CREATING: + case PA_STREAM_TERMINATED: + break; + + case PA_STREAM_READY: { + + int r, i = (int) userdata; + + fprintf(stderr, "Writing data to stream %i.\n", i); + + r = pa_stream_write(s, data, sizeof(data), nop_free_cb, sizeof(data) * i, PA_SEEK_ABSOLUTE); + assert(r == 0); + + /* Be notified when this stream is drained */ + pa_stream_set_underflow_callback(s, underflow_cb, userdata); + + /* All streams have been set up, let's go! */ + if (++n_streams_ready >= NSTREAMS) { + fprintf(stderr, "Uncorking\n"); + pa_operation_unref(pa_stream_cork(s, 0, NULL, NULL)); + } + + break; + } + + default: + case PA_STREAM_FAILED: + fprintf(stderr, "Stream error: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + abort(); + } +} + +/* This is called whenever the context status changes */ +static void context_state_callback(pa_context *c, void *userdata) { + assert(c); + + switch (pa_context_get_state(c)) { + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + + case PA_CONTEXT_READY: { + + int i; + fprintf(stderr, "Connection established.\n"); + + for (i = 0; i < NSTREAMS; i++) { + char name[64]; + + fprintf(stderr, "Creating stream %i\n", i); + + snprintf(name, sizeof(name), "stream #%i", i); + + streams[i] = pa_stream_new(c, name, &sample_spec, NULL); + assert(streams[i]); + pa_stream_set_state_callback(streams[i], stream_state_callback, (void*) i); + pa_stream_connect_playback(streams[i], NULL, &buffer_attr, PA_STREAM_START_CORKED, NULL, i == 0 ? NULL : streams[0]); + } + + break; + } + + case PA_CONTEXT_TERMINATED: + mainloop_api->quit(mainloop_api, 0); + break; + + case PA_CONTEXT_FAILED: + default: + fprintf(stderr, "Context error: %s\n", pa_strerror(pa_context_errno(c))); + abort(); + } +} + +int main(int argc, char *argv[]) { + pa_mainloop* m = NULL; + int i, ret = 0; + + for (i = 0; i < SAMPLE_HZ; i++) + data[i] = (float) sin(((double) i/SAMPLE_HZ)*2*M_PI*SINE_HZ)/2; + + for (i = 0; i < NSTREAMS; i++) + streams[i] = NULL; + + /* Set up a new main loop */ + m = pa_mainloop_new(); + assert(m); + + mainloop_api = pa_mainloop_get_api(m); + + context = pa_context_new(mainloop_api, argv[0]); + assert(context); + + pa_context_set_state_callback(context, context_state_callback, NULL); + + pa_context_connect(context, NULL, 1, NULL); + + if (pa_mainloop_run(m, &ret) < 0) + fprintf(stderr, "pa_mainloop_run() failed.\n"); + + pa_context_unref(context); + + for (i = 0; i < NSTREAMS; i++) + if (streams[i]) + pa_stream_unref(streams[i]); + + pa_mainloop_free(m); + + return ret; +} diff --git a/src/utils/pacat.c b/src/utils/pacat.c index a3c3f2c8..4e126c8a 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -80,7 +80,7 @@ static void do_stream_write(size_t length) { if (l > buffer_length) l = buffer_length; - pa_stream_write(stream, (uint8_t*) buffer + buffer_index, l, NULL, 0); + pa_stream_write(stream, (uint8_t*) buffer + buffer_index, l, NULL, 0, PA_SEEK_RELATIVE); buffer_length -= l; buffer_index += l; @@ -106,8 +106,8 @@ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { /* This is called whenever new data may is available */ static void stream_read_callback(pa_stream *s, size_t length, void *userdata) { + const void *data; assert(s && length); - void *data; if (stdio_event) mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT); @@ -175,7 +175,7 @@ static void context_state_callback(pa_context *c, void *userdata) { if (mode == PLAYBACK) { pa_cvolume cv; - pa_stream_connect_playback(stream, device, NULL, 0, pa_cvolume_set(&cv, PA_CHANNELS_MAX, volume)); + pa_stream_connect_playback(stream, device, NULL, 0, pa_cvolume_set(&cv, PA_CHANNELS_MAX, volume), NULL); } else pa_stream_connect_record(stream, device, NULL, 0); diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 4c22c925..e3305f0f 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -515,7 +515,7 @@ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { quit(1); } - pa_stream_write(s, d, length, free, 0); + pa_stream_write(s, d, length, free, 0, PA_SEEK_RELATIVE); sample_length -= length; diff --git a/src/utils/paplay.c b/src/utils/paplay.c index 9f73b834..5f985ee9 100644 --- a/src/utils/paplay.c +++ b/src/utils/paplay.c @@ -113,7 +113,7 @@ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { f = readf_function(sndfile, data, n); if (f > 0) - pa_stream_write(s, data, f*k, free, 0); + pa_stream_write(s, data, f*k, free, 0, PA_SEEK_RELATIVE); if (f < n) { sf_close(sndfile); @@ -166,7 +166,7 @@ static void context_state_callback(pa_context *c, void *userdata) { pa_stream_set_state_callback(stream, stream_state_callback, NULL); pa_stream_set_write_callback(stream, stream_write_callback, NULL); - pa_stream_connect_playback(stream, device, NULL, 0, pa_cvolume_set(&cv, PA_CHANNELS_MAX, volume)); + pa_stream_connect_playback(stream, device, NULL, 0, pa_cvolume_set(&cv, sample_spec.channels, volume), NULL); break; } -- cgit From 16285f9cc35a8fd4b8920fd65c309b3a419e3d0d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 04:05:59 +0000 Subject: make doxygen ignore PA_CDECL_BEGIN/PA_CDECL_END git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@512 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doxygen/doxygen.conf.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doxygen/doxygen.conf.in b/doxygen/doxygen.conf.in index fcda2194..747abbd9 100644 --- a/doxygen/doxygen.conf.in +++ b/doxygen/doxygen.conf.in @@ -950,14 +950,14 @@ INCLUDE_FILE_PATTERNS = # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. -PREDEFINED = PA_C_DECL_BEGIN=,PA_C_DECL_END +PREDEFINED = PA_C_DECL_BEGIN= PA_C_DECL_END= # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. -EXPAND_AS_DEFINED = PA_C_DECL_BEGIN, PA_C_DECL_END +#EXPAND_AS_DEFINED = PA_C_DECL_BEGIN, PA_C_DECL_END # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone -- cgit From 081fb74c00562acea32d0c8ce04317de5035dc0d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 04:06:13 +0000 Subject: update TODO git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@513 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/doc/todo b/doc/todo index 41333b75..550f392c 100644 --- a/doc/todo +++ b/doc/todo @@ -1,14 +1,16 @@ *** $Id$ *** -Architectural changes: -- add API for synchronizing multiple sinks/sources to a common clock -- absolutely indexed write()s from client +Test: +- module-combine +- latency foo Fixes: - improve module-oss-mmap latency measurement - module-tunnel: improve latency calculation - make alsa modules use mmap -- even more commenting +- better validity checking in libpolyp and protocol-{native,esound} +- don't build ipv4 and ipv6 modules seperately +- change pa_log to not require \n Features: - add radio module @@ -16,6 +18,12 @@ Features: - polish for starting polypaudio as root/system-wide instance - add threading API - add support for auth using SCM_CREDENTIALS +- include hw description in sink/source info +- use scatter/gather io for sockets +- hw volume support for alsa, oss-mmap, windows, solaris +- notifcation on hw volume change +- source volume control +- deal with underflows reported by OSS/ALSA properly Long term: - pass meta info for hearing impaired @@ -34,4 +42,5 @@ Done: - hardware volume support - alsa-lib - remove "polyplib-" prefix - +- add API for synchronizing multiple sinks/sources to a common clock +- absolutely indexed write()s from client -- cgit From e9658bb9972e693ed93d55f5bf767b660aa10dce Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 20 Feb 2006 10:38:57 +0000 Subject: util.c uses some socket functions so we need winsock on Windows. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@514 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index 4cf61f27..5581d77e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -260,7 +260,7 @@ memblockq_test_SOURCES = \ polypcore/mcalign.c \ polypcore/memchunk.c memblockq_test_CFLAGS = $(AM_CFLAGS) -memblockq_test_LDADD = $(AM_LDADD) +memblockq_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) memblockq_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) sync_playback_SOURCES = tests/sync-playback.c -- cgit From 0eed96d7649d63a24c2a251b143d26a46ab91742 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 20 Feb 2006 10:40:40 +0000 Subject: Remove a debug fprintf that was left in. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@515 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-waveout.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index 8809c31d..3a8600c7 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -319,8 +319,6 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { r += pa_bytes_to_usec((free_frags + 1) * u->fragment_size, &s->sample_spec); - fprintf(stderr, "Latency: %d us\n", (int)r); - return r; } -- cgit From d1bc972e6955601836c476093cb07ba961e51738 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 20 Feb 2006 12:42:28 +0000 Subject: Detect support for Solaris (/dev/audio). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@516 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 5 ++++- src/modules/module-detect.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4261903f..5ffea5ef 100644 --- a/configure.ac +++ b/configure.ac @@ -309,7 +309,10 @@ AM_CONDITIONAL([HAVE_ALSA], [test "x$HAVE_ALSA" = x1]) #### Solaris audio support (optional) #### -AC_CHECK_HEADERS([sys/audio.h], [HAVE_SOLARIS=1], [HAVE_SOLARIS=0]) +AC_CHECK_HEADERS([sys/audio.h], [ +HAVE_SOLARIS=1 +AC_DEFINE([HAVE_SOLARIS], 1, [Have Solaris audio?]) +], [HAVE_SOLARIS=0]) AC_SUBST(HAVE_SOLARIS) AM_CONDITIONAL([HAVE_SOLARIS], [test "x$HAVE_SOLARIS" = x1]) diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index e325b22c..4c0cdb4b 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -171,6 +171,34 @@ static int detect_oss(pa_core *c, int just_one) { } #endif +#ifdef HAVE_SOLARIS +static int detect_solaris(pa_core *c, int just_one) { + struct stat s; + const char *dev; + char args[64]; + + dev = getenv("AUDIODEV"); + if (!dev) + dev = "/dev/audio"; + + if (stat(dev, &s) < 0) { + if (errno != ENOENT) + pa_log_error(__FILE__": failed to open device %s: %s\n", dev, strerror(errno)); + return -1; + } + + if (!S_ISCHR(s)) + return 0; + + snprintf(args, sizeof(args), "device=%s", dev); + + if (!pa_module_load(c, "module-solaris", args)) + return 0; + + return 1; +} +#endif + int pa__init(pa_core *c, pa_module*m) { int just_one = 0, n = 0; pa_modargs *ma; @@ -198,6 +226,9 @@ int pa__init(pa_core *c, pa_module*m) { #endif #if HAVE_OSS if ((n = detect_oss(c, just_one)) <= 0) +#endif +#if HAVE_SOLARIS + if ((n = detect_solaris(c, just_one)) <= 0) #endif { pa_log_warn(__FILE__": failed to detect any sound hardware.\n"); -- cgit From 6c2d414e5879dccff78ebf1cb155fd1809fc785a Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 20 Feb 2006 12:47:03 +0000 Subject: Detect support for Windows' waveout. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@517 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-detect.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index 4c0cdb4b..718b2eb4 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -199,6 +199,19 @@ static int detect_solaris(pa_core *c, int just_one) { } #endif +#ifdef OS_IS_WIN32 +static int detect_waveout(pa_core *c, int just_one) { + /* + * FIXME: No point in enumerating devices until the plugin supports + * selecting anything but the first. + */ + if (!pa_module_load(c, "module-waveout", "")) + return 0; + + return 1; +} +#endif + int pa__init(pa_core *c, pa_module*m) { int just_one = 0, n = 0; pa_modargs *ma; @@ -229,6 +242,9 @@ int pa__init(pa_core *c, pa_module*m) { #endif #if HAVE_SOLARIS if ((n = detect_solaris(c, just_one)) <= 0) +#endif +#if OS_IS_WIN32 + if ((n = detect_waveout(c, just_one)) <= 0) #endif { pa_log_warn(__FILE__": failed to detect any sound hardware.\n"); -- cgit From 5cc0d0e68213a4ec49a3bb24001812dda1c4f665 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 20 Feb 2006 12:49:16 +0000 Subject: Add mute switch to todo. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@518 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/todo b/doc/todo index 550f392c..45989b45 100644 --- a/doc/todo +++ b/doc/todo @@ -24,6 +24,7 @@ Features: - notifcation on hw volume change - source volume control - deal with underflows reported by OSS/ALSA properly +- mute switch support (like ALSA does it) Long term: - pass meta info for hearing impaired -- cgit From f2292aeeff200e45b46929c9d02e5d4a91fe0124 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 20 Feb 2006 13:59:42 +0000 Subject: Fixes for the Solaris detection. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@519 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-detect.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index 718b2eb4..18e22de6 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include @@ -187,7 +189,7 @@ static int detect_solaris(pa_core *c, int just_one) { return -1; } - if (!S_ISCHR(s)) + if (!S_ISCHR(s.st_mode)) return 0; snprintf(args, sizeof(args), "device=%s", dev); -- cgit From b36ed4d23a70ecac070233eb47e374c94b735682 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 15:55:05 +0000 Subject: remove cdecl.h from doxygen docs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@520 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doxygen/doxygen.conf.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doxygen/doxygen.conf.in b/doxygen/doxygen.conf.in index 747abbd9..9e426027 100644 --- a/doxygen/doxygen.conf.in +++ b/doxygen/doxygen.conf.in @@ -417,7 +417,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = ../src/polyp/context.h ../src/polyp/stream.h ../src/polyp/polypaudio.h ../src/polyp/sample.h ../src/polyp/def.h ../src/polyp/subscribe.h ../src/polyp/introspect.h ../src/polyp/scache.h ../src/polyp/mainloop-api.h ../src/polyp/cdecl.h ../src/polyp/glib-mainloop.h ../src/polyp/mainloop.h ../src/polyp/mainloop-signal.h ../src/polyp/error.h ../src/polyp/operation.h ../src/polyp/simple.h ../src/polyp/version.h ../src/polyp/volume.h ../src/polyp/channelmap.h +INPUT = ../src/polyp/context.h ../src/polyp/stream.h ../src/polyp/polypaudio.h ../src/polyp/sample.h ../src/polyp/def.h ../src/polyp/subscribe.h ../src/polyp/introspect.h ../src/polyp/scache.h ../src/polyp/mainloop-api.h ../src/polyp/glib-mainloop.h ../src/polyp/mainloop.h ../src/polyp/mainloop-signal.h ../src/polyp/error.h ../src/polyp/operation.h ../src/polyp/simple.h ../src/polyp/version.h ../src/polyp/volume.h ../src/polyp/channelmap.h # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -- cgit From 4566d56e31c58211763ddbb4669c7f04152669d0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 16:01:53 +0000 Subject: * Make typdefs for the pa_context callback prototypes * s/pa_context_notify_cb/pa_context_notify_cb_t/g git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@521 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 2 +- src/polyp/context.c | 14 +++++++------- src/polyp/context.h | 18 +++++++++++------- src/polyp/internal.h | 4 ++-- src/polypcore/pdispatch.c | 12 ++++++------ src/polypcore/pdispatch.h | 6 +++--- src/polypcore/protocol-native.c | 2 +- 7 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 67236588..3ecca745 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -94,7 +94,7 @@ static void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t t static void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); #endif -static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { +static const pa_pdispatch_callback_t command_table[PA_COMMAND_MAX] = { #ifdef TUNNEL_SINK [PA_COMMAND_REQUEST] = command_request, #endif diff --git a/src/polyp/context.c b/src/polyp/context.c index eac5dd23..e2d9d33d 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -72,7 +72,7 @@ #define AUTOSPAWN_LOCK "autospawn.lock" -static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { +static const pa_pdispatch_callback_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_REQUEST] = pa_command_request, [PA_COMMAND_OVERFLOW] = pa_command_overflow_or_underflow, [PA_COMMAND_UNDERFLOW] = pa_command_overflow_or_underflow, @@ -671,7 +671,7 @@ int pa_context_errno(pa_context *c) { return c->error; } -void pa_context_set_state_callback(pa_context *c, void (*cb)(pa_context *c, void *userdata), void *userdata) { +void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) { assert(c && c->ref >= 1); c->state_callback = cb; c->state_userdata = userdata; @@ -730,7 +730,7 @@ static void set_dispatch_callbacks(pa_operation *o) { pa_operation_unref(o); } -pa_operation* pa_context_drain(pa_context *c, void (*cb) (pa_context*c, void *userdata), void *userdata) { +pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) { pa_operation *o; assert(c && c->ref >= 1); @@ -777,7 +777,7 @@ void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_U } if (o->callback) { - void (*cb)(pa_context *c, int _success, void *_userdata) = (void (*)(pa_context *c, int _success, void *_userdata)) o->callback; + pa_context_success_cb_t cb = (pa_context_success_cb_t) o->callback; cb(o->context, success, o->userdata); } @@ -805,7 +805,7 @@ pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, vo return pa_operation_ref(o); } -pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata) { +pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; @@ -825,7 +825,7 @@ pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, void( return pa_operation_ref(o); } -pa_operation* pa_context_set_default_source(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata) { +pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; @@ -850,7 +850,7 @@ int pa_context_is_local(pa_context *c) { return c->local; } -pa_operation* pa_context_set_name(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata) { +pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; diff --git a/src/polyp/context.h b/src/polyp/context.h index 4efd5156..1c06c434 100644 --- a/src/polyp/context.h +++ b/src/polyp/context.h @@ -53,6 +53,12 @@ PA_C_DECL_BEGIN * An opaque connection context to a daemon */ typedef struct pa_context pa_context; +/** Generic notification callback prototype */ +typedef void (*pa_context_notify_cb_t)(pa_context *c, void *userdata); + +/** A generic callback for operation completion */ +typedef void (*pa_context_success_cb_t) (pa_context *c, int success, void *userdata); + /** Instantiate a new connection context with an abstract mainloop API * and an application name */ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name); @@ -63,10 +69,8 @@ void pa_context_unref(pa_context *c); /** Increase the reference counter of the context by one */ pa_context* pa_context_ref(pa_context *c); -typedef void (*pa_context_state_callback)(pa_context *c, void *userdata); - /** Set a callback function that is called whenever the context status changes */ -void pa_context_set_state_callback(pa_context *c, pa_context_state_callback callback, void *userdata); +void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata); /** Return the error number of the last failed operation */ int pa_context_errno(pa_context *c); @@ -90,7 +94,7 @@ int pa_context_connect(pa_context *c, const char *server, int spawn, const pa_sp void pa_context_disconnect(pa_context *c); /** Drain the context. If there is nothing to drain, the function returns NULL */ -pa_operation* pa_context_drain(pa_context *c, void (*cb) (pa_context*c, void *userdata), void *userdata); +pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata); /** Tell the daemon to exit. No operation object is returned as the * connection is terminated when the daemon quits, thus this operation @@ -98,16 +102,16 @@ pa_operation* pa_context_drain(pa_context *c, void (*cb) (pa_context*c, void *us void pa_context_exit_daemon(pa_context *c); /** Set the name of the default sink. \since 0.4 */ -pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata); +pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata); /** Set the name of the default source. \since 0.4 */ -pa_operation* pa_context_set_default_source(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata); +pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata); /** Returns 1 when the connection is to a local daemon. Returns negative when no connection has been made yet. \since 0.5 */ int pa_context_is_local(pa_context *c); /** Set a different application name for context on the server. \since 0.5 */ -pa_operation* pa_context_set_name(pa_context *c, const char *name, void(*cb)(pa_context*c, int success, void *userdata), void *userdata); +pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata); /** Return the server name this context is connected to. \since 0.7 */ const char* pa_context_get_server(pa_context *c); diff --git a/src/polyp/internal.h b/src/polyp/internal.h index 578969ee..f0374b67 100644 --- a/src/polyp/internal.h +++ b/src/polyp/internal.h @@ -59,8 +59,8 @@ struct pa_context { uint32_t csyncid; uint32_t error; pa_context_state_t state; - - void (*state_callback)(pa_context*c, void *userdata); + + pa_context_notify_cb_t state_callback; void *state_userdata; void (*subscribe_callback)(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata); diff --git a/src/polypcore/pdispatch.c b/src/polypcore/pdispatch.c index 7941e4a8..fbb1b697 100644 --- a/src/polypcore/pdispatch.c +++ b/src/polypcore/pdispatch.c @@ -94,7 +94,7 @@ static const char *command_names[PA_COMMAND_MAX] = { struct reply_info { pa_pdispatch *pdispatch; PA_LLIST_FIELDS(struct reply_info); - pa_pdispatch_callback callback; + pa_pdispatch_callback_t callback; void *userdata; uint32_t tag; pa_time_event *time_event; @@ -103,7 +103,7 @@ struct reply_info { struct pa_pdispatch { int ref; pa_mainloop_api *mainloop; - const pa_pdispatch_callback *callback_table; + const pa_pdispatch_callback_t *callback_table; unsigned n_commands; PA_LLIST_HEAD(struct reply_info, replies); pa_pdispatch_drain_callback drain_callback; @@ -121,7 +121,7 @@ static void reply_info_free(struct reply_info *r) { pa_xfree(r); } -pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_callback*table, unsigned entries) { +pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_callback_t*table, unsigned entries) { pa_pdispatch *pd; assert(mainloop); @@ -149,7 +149,7 @@ static void pdispatch_free(pa_pdispatch *pd) { } static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command, pa_tagstruct *ts) { - pa_pdispatch_callback callback; + pa_pdispatch_callback_t callback; void *userdata; uint32_t tag; assert(r); @@ -210,7 +210,7 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, void *userdata) { run_action(pd, r, command, ts); } else if (pd->callback_table && (command < pd->n_commands) && pd->callback_table[command]) { - const pa_pdispatch_callback *c = pd->callback_table+command; + const pa_pdispatch_callback_t *c = pd->callback_table+command; (*c)(pd, command, tag, ts, userdata); } else { @@ -236,7 +236,7 @@ static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, PA_GCC_UNUSED c run_action(r->pdispatch, r, PA_COMMAND_TIMEOUT, NULL); } -void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_callback cb, void *userdata) { +void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_callback_t cb, void *userdata) { struct reply_info *r; struct timeval tv; assert(pd && pd->ref >= 1 && cb); diff --git a/src/polypcore/pdispatch.h b/src/polypcore/pdispatch.h index 57666259..27d2d61f 100644 --- a/src/polypcore/pdispatch.h +++ b/src/polypcore/pdispatch.h @@ -29,15 +29,15 @@ typedef struct pa_pdispatch pa_pdispatch; -typedef void (*pa_pdispatch_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +typedef void (*pa_pdispatch_callback_t)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *m, const pa_pdispatch_callback*table, unsigned entries); +pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *m, const pa_pdispatch_callback_t*table, unsigned entries); void pa_pdispatch_unref(pa_pdispatch *pd); pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd); int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*p, void *userdata); -void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_callback callback, void *userdata); +void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_callback_t callback, void *userdata); int pa_pdispatch_is_pending(pa_pdispatch *pd); diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index aaa4fc48..21800e6c 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -174,7 +174,7 @@ static void command_get_autoload_info_list(pa_pdispatch *pd, uint32_t command, u static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { +static const pa_pdispatch_callback_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = NULL, [PA_COMMAND_TIMEOUT] = NULL, [PA_COMMAND_REPLY] = NULL, -- cgit From e078f084e44de3c4a87bb4fd7a0be9dbda64b604 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 16:09:25 +0000 Subject: explcitily cast strings to make gcc shut up git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@522 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/tests/memblockq-test.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tests/memblockq-test.c b/src/tests/memblockq-test.c index b01084da..e9764627 100644 --- a/src/tests/memblockq-test.c +++ b/src/tests/memblockq-test.c @@ -38,28 +38,28 @@ int main(int argc, char *argv[]) { pa_log_set_maximal_level(PA_LOG_DEBUG); - silence = pa_memblock_new_fixed("__", 2, 1, NULL); + silence = pa_memblock_new_fixed((char*) "__", 2, 1, NULL); assert(silence); bq = pa_memblockq_new(0, 40, 10, 2, 4, 4, silence, NULL); assert(bq); - chunk1.memblock = pa_memblock_new_fixed("AA", 2, 1, NULL); + chunk1.memblock = pa_memblock_new_fixed((char*) "AA", 2, 1, NULL); chunk1.index = 0; chunk1.length = 2; assert(chunk1.memblock); - chunk2.memblock = pa_memblock_new_fixed("TTBB", 4, 1, NULL); + chunk2.memblock = pa_memblock_new_fixed((char*) "TTBB", 4, 1, NULL); chunk2.index = 2; chunk2.length = 2; assert(chunk2.memblock); - chunk3.memblock = pa_memblock_new_fixed("ZZZZ", 4, 1, NULL); + chunk3.memblock = pa_memblock_new_fixed((char*) "ZZZZ", 4, 1, NULL); chunk3.index = 0; chunk3.length = 4; assert(chunk3.memblock); - chunk4.memblock = pa_memblock_new_fixed("KKKKKKKK", 8, 1, NULL); + chunk4.memblock = pa_memblock_new_fixed((char*) "KKKKKKKK", 8, 1, NULL); chunk4.index = 0; chunk4.length = 8; assert(chunk4.memblock); -- cgit From 6d0960246036564a6a8bf36b0839158cacc6a81a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 16:10:20 +0000 Subject: replace "spawn" parameter of pa_context_new() with a proper flags parameter git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@523 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/context.c | 4 ++-- src/polyp/context.h | 10 +++++----- src/polyp/def.h | 5 +++++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/polyp/context.c b/src/polyp/context.c index e2d9d33d..b174b505 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -593,7 +593,7 @@ finish: pa_context_unref(c); } -int pa_context_connect(pa_context *c, const char *server, int spawn, const pa_spawn_api *api) { +int pa_context_connect(pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api) { int r = -1; assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED); @@ -632,7 +632,7 @@ int pa_context_connect(pa_context *c, const char *server, int spawn, const pa_sp c->server_list = pa_strlist_prepend(c->server_list, pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET, ufn, sizeof(ufn))); /* Wrap the connection attempts in a single transaction for sane autospawn locking */ - if (spawn && c->conf->autospawn) { + if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) { char lf[PATH_MAX]; pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); diff --git a/src/polyp/context.h b/src/polyp/context.h index 1c06c434..a299400a 100644 --- a/src/polyp/context.h +++ b/src/polyp/context.h @@ -84,11 +84,11 @@ pa_context_state_t pa_context_get_state(pa_context *c); /** Connect the context to the specified server. If server is NULL, connect to the default server. This routine may but will not always return synchronously on error. Use pa_context_set_state_callback() to -be notified when the connection is established. If spawn is non-zero -and no specific server is specified or accessible a new daemon is -spawned. If api is non-NULL, the functions specified in the structure -are used when forking a new child process. */ -int pa_context_connect(pa_context *c, const char *server, int spawn, const pa_spawn_api *api); +be notified when the connection is established. If flags doesn't have +PA_NOAUTOSPAWN set and no specific server is specified or accessible a +new daemon is spawned. If api is non-NULL, the functions specified in +the structure are used when forking a new child process. */ +int pa_context_connect(pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api); /** Terminate the context connection immediately */ void pa_context_disconnect(pa_context *c); diff --git a/src/polyp/def.h b/src/polyp/def.h index f8e0bed4..e94da253 100644 --- a/src/polyp/def.h +++ b/src/polyp/def.h @@ -64,6 +64,11 @@ typedef enum pa_operation_state { /** An invalid index */ #define PA_INVALID_INDEX ((uint32_t) -1) +/** Some special flags for contexts. \ since 0.8 */ +typedef enum pa_context_flags { + PA_CONTEXT_NOAUTOSPAWN = 1 /**< Disabled autospawning of the polypaudio daemon if required */ +} pa_context_flags_t; + /** The direction of a pa_stream object */ typedef enum pa_stream_direction { PA_STREAM_NODIRECTION, /**< Invalid direction */ -- cgit From 502d3f551bb8a168b6686b6d0c833a5f6e40c98c Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 20 Feb 2006 16:13:10 +0000 Subject: Hardware volume support for Solaris. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@524 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-solaris.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index e0745fc0..7356cb7b 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -258,6 +258,40 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { return r; } +static int sink_get_hw_volume_cb(pa_sink *s) { + struct userdata *u = s->userdata; + audio_info_t info; + int err; + + err = ioctl(u->fd, AUDIO_GETINFO, &info); + assert(err >= 0); + + pa_cvolume_set(&s->hw_volume, s->hw_volume.channels, + info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN); + + return 0; +} + +static int sink_set_hw_volume_cb(pa_sink *s) { + struct userdata *u = s->userdata; + audio_info_t info; + + AUDIO_INITINFO(&info); + + info.play.gain = pa_cvolume_avg(&s->hw_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM; + assert(info.play.gain <= AUDIO_MAX_GAIN); + + if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { + if (errno == EINVAL) + pa_log(__FILE__": AUDIO_SETINFO: Unsupported volume.\n"); + else + pa_log(__FILE__": AUDIO_SETINFO: %s\n", strerror(errno)); + return -1; + } + + return 0; +} + static int pa_solaris_auto_format(int fd, int mode, pa_sample_spec *ss) { audio_info_t info; @@ -411,6 +445,8 @@ int pa__init(pa_core *c, pa_module*m) { u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; + u->sink->get_hw_volume = sink_get_hw_volume_cb; + u->sink->set_hw_volume = sink_set_hw_volume_cb; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); u->sink->description = pa_sprintf_malloc("Solaris PCM on '%s'", p); -- cgit From 5d253cd30cd73dc8d159f198e2b63edbe1f971ab Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 20 Feb 2006 16:21:19 +0000 Subject: Fix some warnings by making sure we have the right signedness on things. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@525 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-esound.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index 5adff57a..4a5dd773 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -560,15 +560,15 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v response += ESD_NAME_MAX; /* rate */ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, ce->sample_spec.rate); + *((uint32_t*) response) = MAYBE_UINT32_SWAP(c->swap_byte_order, ce->sample_spec.rate); response += sizeof(int); /* left */ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); + *((uint32_t*) response) = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); response += sizeof(int); /*right*/ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); + *((uint32_t*) response) = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); response += sizeof(int); /*format*/ @@ -596,10 +596,10 @@ static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t struct connection *conn; assert(c && data && length == sizeof(int)*3); - idx = MAYBE_UINT32_SWAP(c->swap_byte_order, *(const int*)data)-1; - lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, *((const int*)data + 1)); + idx = MAYBE_UINT32_SWAP(c->swap_byte_order, *(const uint32_t*)data)-1; + lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, *((const uint32_t*)data + 1)); lvolume = (lvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; - rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, *((const int*)data + 2)); + rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, *((const uint32_t*)data + 2)); rvolume = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; ok = connection_write(c, sizeof(int)); -- cgit From 3bc09025edc8d1b7a86b3ca5d08b1c0146950707 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 16:23:12 +0000 Subject: minor doxygen fixes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@526 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/context.h | 3 +-- src/polyp/def.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/polyp/context.h b/src/polyp/context.h index a299400a..db268759 100644 --- a/src/polyp/context.h +++ b/src/polyp/context.h @@ -49,8 +49,7 @@ PA_C_DECL_BEGIN -/** \struct pa_context - * An opaque connection context to a daemon */ +/** An opaque connection context to a daemon */ typedef struct pa_context pa_context; /** Generic notification callback prototype */ diff --git a/src/polyp/def.h b/src/polyp/def.h index e94da253..2ce1bd0c 100644 --- a/src/polyp/def.h +++ b/src/polyp/def.h @@ -64,7 +64,7 @@ typedef enum pa_operation_state { /** An invalid index */ #define PA_INVALID_INDEX ((uint32_t) -1) -/** Some special flags for contexts. \ since 0.8 */ +/** Some special flags for contexts. \since 0.8 */ typedef enum pa_context_flags { PA_CONTEXT_NOAUTOSPAWN = 1 /**< Disabled autospawning of the polypaudio daemon if required */ } pa_context_flags_t; -- cgit From 7905e819ab6a6cc90e28c1e31f2ed957a1d00489 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 20 Feb 2006 16:24:02 +0000 Subject: Add aligment fix in esound to todo. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@527 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/todo b/doc/todo index 45989b45..744820c4 100644 --- a/doc/todo +++ b/doc/todo @@ -11,6 +11,7 @@ Fixes: - better validity checking in libpolyp and protocol-{native,esound} - don't build ipv4 and ipv6 modules seperately - change pa_log to not require \n +- proper use of memcpy in procotol-esound.c so we don't get alignment problems Features: - add radio module -- cgit From ddd51e2c6cba3fa1ba56193976a63306a10f7645 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 16:31:39 +0000 Subject: add doxygen docs for channel map git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@528 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/channelmap.h | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/polyp/channelmap.h b/src/polyp/channelmap.h index 7c48b76b..ae1d11c8 100644 --- a/src/polyp/channelmap.h +++ b/src/polyp/channelmap.h @@ -30,7 +30,8 @@ PA_C_DECL_BEGIN -typedef enum { +/** A list of channel labels */ +typedef enum pa_channel_position { PA_CHANNEL_POSITION_INVALID = -1, PA_CHANNEL_POSITION_MONO = 0, @@ -75,23 +76,39 @@ typedef enum { PA_CHANNEL_POSITION_MAX } pa_channel_position_t; +/** A channel map which can be used to attach labels to specific + * channels of a stream. These values are relevant for conversion and + * mixing of streams */ typedef struct pa_channel_map { - uint8_t channels; - pa_channel_position_t map[PA_CHANNELS_MAX]; + uint8_t channels; /**< Number of channels */ + pa_channel_position_t map[PA_CHANNELS_MAX]; /**< Channel labels */ } pa_channel_map; +/** Initialize the specified channel map and return a pointer to it */ pa_channel_map* pa_channel_map_init(pa_channel_map *m); + +/** Initialize the specified channel map for monoaural audio and return a pointer to it */ pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m); + +/** Initialize the specified channel map for stereophonic audio and return a pointer to it */ pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m); + +/** Initialize the specified channel map for the specified number of channels using default labels and return a pointer to it */ pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels); +/** Return a text label for the specified channel position */ const char* pa_channel_position_to_string(pa_channel_position_t pos); +/** The maximum length of strings returned by pa_channel_map_snprint() */ #define PA_CHANNEL_MAP_SNPRINT_MAX 64 + +/** Make a humand readable string from the specified channel map */ char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map); +/** Compare two channel maps. Return 0 if both match. */ int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b); +/** Return non-zero of the specified channel map is considered valid */ int pa_channel_map_valid(const pa_channel_map *map); PA_C_DECL_END -- cgit From 71e063a69533fedc283c55eed735332e5b00713e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 16:34:46 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@529 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/todo b/doc/todo index 744820c4..280747fe 100644 --- a/doc/todo +++ b/doc/todo @@ -26,6 +26,7 @@ Features: - source volume control - deal with underflows reported by OSS/ALSA properly - mute switch support (like ALSA does it) +- get rid of a seperate main loop lib Long term: - pass meta info for hearing impaired -- cgit From 98cb6aa4a30a993ddf2c15f0a03cb4d94383d4d9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 17:09:39 +0000 Subject: * a lot of doxygen updates * s/pa_operation_callback/pa_operation_callback_t/g * add more typedefs for function prototypes * add API to query the channel map used by a pa_stream git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@530 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/channelmap.h | 2 +- src/polyp/context.c | 8 +++--- src/polyp/glib-mainloop.h | 8 +++--- src/polyp/internal.h | 7 +++--- src/polyp/introspect.c | 60 ++++++++++++++++++++++----------------------- src/polyp/mainloop-api.h | 10 +++----- src/polyp/mainloop-signal.h | 3 +-- src/polyp/mainloop.h | 6 ++--- src/polyp/operation.h | 3 +-- src/polyp/polypaudio.h | 13 ++++++---- src/polyp/sample.h | 8 +++--- src/polyp/scache.c | 8 +++--- src/polyp/scache.h | 13 +++++++--- src/polyp/stream.c | 17 +++++++++---- src/polyp/stream.h | 24 +++++++++--------- src/polyp/subscribe.c | 6 ++--- src/polyp/subscribe.h | 7 ++++-- src/polyp/volume.h | 22 +++++++++++------ 18 files changed, 125 insertions(+), 100 deletions(-) diff --git a/src/polyp/channelmap.h b/src/polyp/channelmap.h index ae1d11c8..dd508abe 100644 --- a/src/polyp/channelmap.h +++ b/src/polyp/channelmap.h @@ -105,7 +105,7 @@ const char* pa_channel_position_to_string(pa_channel_position_t pos); /** Make a humand readable string from the specified channel map */ char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map); -/** Compare two channel maps. Return 0 if both match. */ +/** Compare two channel maps. Return 1 if both match. */ int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b); /** Return non-zero of the specified channel map is considered valid */ diff --git a/src/polyp/context.c b/src/polyp/context.c index b174b505..00c09710 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -742,7 +742,7 @@ pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *u o = pa_operation_new(c, NULL); assert(o); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; set_dispatch_callbacks(pa_operation_ref(o)); @@ -812,7 +812,7 @@ pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_co assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -832,7 +832,7 @@ pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_ assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -857,7 +857,7 @@ pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_su assert(c && name && cb); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); diff --git a/src/polyp/glib-mainloop.h b/src/polyp/glib-mainloop.h index e052cff3..b7717685 100644 --- a/src/polyp/glib-mainloop.h +++ b/src/polyp/glib-mainloop.h @@ -32,18 +32,18 @@ PA_C_DECL_BEGIN -/** \struct pa_glib_mainloop - * An opaque GLIB main loop object */ +/** An opaque GLIB main loop object */ typedef struct pa_glib_mainloop pa_glib_mainloop; -/** Create a new GLIB main loop object for the specified GLIB main loop context. If c is NULL the default context is used. */ +/** Create a new GLIB main loop object for the specified GLIB main + * loop context. The GLIB 2.0 version takes an argument c for the + * GMainContext to use. If c is NULL the default context is used. */ #if GLIB_MAJOR_VERSION >= 2 pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c); #else pa_glib_mainloop *pa_glib_mainloop_new(void); #endif - /** Free the GLIB main loop object */ void pa_glib_mainloop_free(pa_glib_mainloop* g); diff --git a/src/polyp/internal.h b/src/polyp/internal.h index f0374b67..e9e0246f 100644 --- a/src/polyp/internal.h +++ b/src/polyp/internal.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -63,7 +64,7 @@ struct pa_context { pa_context_notify_cb_t state_callback; void *state_userdata; - void (*subscribe_callback)(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata); + pa_context_subscribe_cb_t subscribe_callback; void *subscribe_userdata; pa_memblock_stat *memblock_stat; @@ -127,7 +128,7 @@ struct pa_stream { void *underflow_userdata; }; -typedef void (*pa_operation_callback)(void); +typedef void (*pa_operation_callback_t)(void); struct pa_operation { int ref; @@ -137,7 +138,7 @@ struct pa_operation { pa_operation_state_t state; void *userdata; - pa_operation_callback callback; + pa_operation_callback_t callback; }; void pa_command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); diff --git a/src/polyp/introspect.c b/src/polyp/introspect.c index 75ce3ff9..404cead5 100644 --- a/src/polyp/introspect.c +++ b/src/polyp/introspect.c @@ -67,7 +67,7 @@ finish: } pa_operation* pa_context_stat(pa_context *c, void (*cb)(pa_context *c, const pa_stat_info*i, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_STAT, context_stat_callback, (pa_operation_callback) cb, userdata); + return pa_context_send_simple_command(c, PA_COMMAND_STAT, context_stat_callback, (pa_operation_callback_t) cb, userdata); } /*** Server Info ***/ @@ -107,7 +107,7 @@ finish: } pa_operation* pa_context_get_server_info(pa_context *c, void (*cb)(pa_context *c, const pa_server_info*i, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SERVER_INFO, context_get_server_info_callback, (pa_operation_callback) cb, userdata); + return pa_context_send_simple_command(c, PA_COMMAND_GET_SERVER_INFO, context_get_server_info_callback, (pa_operation_callback_t) cb, userdata); } /*** Sink Info ***/ @@ -161,7 +161,7 @@ finish: } pa_operation* pa_context_get_sink_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INFO_LIST, context_get_sink_info_callback, (pa_operation_callback) cb, userdata); + return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INFO_LIST, context_get_sink_info_callback, (pa_operation_callback_t) cb, userdata); } pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { @@ -171,7 +171,7 @@ pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, voi assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -192,7 +192,7 @@ pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -256,7 +256,7 @@ finish: } pa_operation* pa_context_get_source_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_INFO_LIST, context_get_source_info_callback, (pa_operation_callback) cb, userdata); + return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_INFO_LIST, context_get_source_info_callback, (pa_operation_callback_t) cb, userdata); } pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { @@ -266,7 +266,7 @@ pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, v assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -287,7 +287,7 @@ pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -350,7 +350,7 @@ pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, void (*cb) assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -364,7 +364,7 @@ pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, void (*cb) } pa_operation* pa_context_get_client_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_CLIENT_INFO_LIST, context_get_client_info_callback, (pa_operation_callback) cb, userdata); + return pa_context_send_simple_command(c, PA_COMMAND_GET_CLIENT_INFO_LIST, context_get_client_info_callback, (pa_operation_callback_t) cb, userdata); } /*** Module info ***/ @@ -417,7 +417,7 @@ pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, void (*cb) assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -431,7 +431,7 @@ pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, void (*cb) } pa_operation* pa_context_get_module_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_MODULE_INFO_LIST, context_get_module_info_callback, (pa_operation_callback) cb, userdata); + return pa_context_send_simple_command(c, PA_COMMAND_GET_MODULE_INFO_LIST, context_get_module_info_callback, (pa_operation_callback_t) cb, userdata); } /*** Sink input info ***/ @@ -492,7 +492,7 @@ pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, void ( assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -506,7 +506,7 @@ pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, void ( } pa_operation* pa_context_get_sink_input_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INPUT_INFO_LIST, context_get_sink_input_info_callback, (pa_operation_callback) cb, userdata); + return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INPUT_INFO_LIST, context_get_sink_input_info_callback, (pa_operation_callback_t) cb, userdata); } /*** Source output info ***/ @@ -566,7 +566,7 @@ pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, voi assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -580,7 +580,7 @@ pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, voi } pa_operation* pa_context_get_source_output_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, context_get_source_output_info_callback, (pa_operation_callback) cb, userdata); + return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, context_get_source_output_info_callback, (pa_operation_callback_t) cb, userdata); } /*** Volume manipulation ***/ @@ -592,7 +592,7 @@ pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, c assert(c && idx != PA_INVALID_INDEX); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -614,7 +614,7 @@ pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name assert(c && name); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -636,7 +636,7 @@ pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, cons assert(c && idx != PA_INVALID_INDEX); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -705,7 +705,7 @@ pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name assert(c && cb && name); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -726,7 +726,7 @@ pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, v assert(c && cb); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -741,7 +741,7 @@ pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, v } pa_operation* pa_context_get_sample_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SAMPLE_INFO_LIST, context_get_sample_info_callback, (pa_operation_callback) cb, userdata); + return pa_context_send_simple_command(c, PA_COMMAND_GET_SAMPLE_INFO_LIST, context_get_sample_info_callback, (pa_operation_callback_t) cb, userdata); } static pa_operation* command_kill(pa_context *c, uint32_t command, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { @@ -751,7 +751,7 @@ static pa_operation* command_kill(pa_context *c, uint32_t command, uint32_t idx, assert(c && idx != PA_INVALID_INDEX); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -808,7 +808,7 @@ pa_operation* pa_context_load_module(pa_context *c, const char*name, const char assert(c && name && argument); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -876,7 +876,7 @@ pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *na assert(c && cb && name); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -897,7 +897,7 @@ pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, assert(c && cb && idx != PA_INVALID_INDEX); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -911,7 +911,7 @@ pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, } pa_operation* pa_context_get_autoload_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, context_get_autoload_info_callback, (pa_operation_callback) cb, userdata); + return pa_context_send_simple_command(c, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, context_get_autoload_info_callback, (pa_operation_callback_t) cb, userdata); } static void context_add_autoload_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -948,7 +948,7 @@ pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autolo assert(c && name && module && argument); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -971,7 +971,7 @@ pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name assert(c && name); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -992,7 +992,7 @@ pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, v assert(c && idx != PA_INVALID_INDEX); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); diff --git a/src/polyp/mainloop-api.h b/src/polyp/mainloop-api.h index 7bc7522c..12d74aa1 100644 --- a/src/polyp/mainloop-api.h +++ b/src/polyp/mainloop-api.h @@ -53,21 +53,19 @@ typedef enum pa_io_event_flags { PA_IO_EVENT_ERROR = 8 /**< Error event */ } pa_io_event_flags_t; -/** \struct pa_io_event - * An opaque IO event source object */ +/** An opaque IO event source object */ typedef struct pa_io_event pa_io_event; -/** \struct pa_defer_event - * An opaque deferred event source object. Events of this type are triggered once in every main loop iteration */ +/** An opaque deferred event source object. Events of this type are triggered once in every main loop iteration */ typedef struct pa_defer_event pa_defer_event; -/** \struct pa_time_event - * An opaque timer event source object */ +/** An opaque timer event source object */ typedef struct pa_time_event pa_time_event; /** An abstract mainloop API vtable */ typedef struct pa_mainloop_api pa_mainloop_api; +/** An abstract mainloop API vtable */ struct pa_mainloop_api { /** A pointer to some private, arbitrary data of the main loop implementation */ void *userdata; diff --git a/src/polyp/mainloop-signal.h b/src/polyp/mainloop-signal.h index 0291f426..20e97988 100644 --- a/src/polyp/mainloop-signal.h +++ b/src/polyp/mainloop-signal.h @@ -42,8 +42,7 @@ int pa_signal_init(pa_mainloop_api *api); /** Cleanup the signal subsystem */ void pa_signal_done(void); -/** \struct pa_signal_event - * An opaque UNIX signal event source object */ +/** An opaque UNIX signal event source object */ typedef struct pa_signal_event pa_signal_event; /** Create a new UNIX signal event source object */ diff --git a/src/polyp/mainloop.h b/src/polyp/mainloop.h index eeb23884..d0a40914 100644 --- a/src/polyp/mainloop.h +++ b/src/polyp/mainloop.h @@ -35,9 +35,7 @@ PA_C_DECL_BEGIN * defined in \ref mainloop-api.h. This implementation is thread safe * as long as you access the main loop object from a single thread only.*/ -/** \struct pa_mainloop - * An opaque main loop object - */ +/** An opaque main loop object */ typedef struct pa_mainloop pa_mainloop; /** Allocate a new main loop object */ @@ -52,8 +50,10 @@ poll, or -1 for blocking behaviour. Defer events are also dispatched when this function is called. On success returns the number of source dispatched in this iteration.*/ int pa_mainloop_prepare(pa_mainloop *m, int timeout); + /** Execute the previously prepared poll. Returns a negative value on error.*/ int pa_mainloop_poll(pa_mainloop *m); + /** Dispatch timeout and io events from the previously executed poll. Returns a negative value on error. On success returns the number of source dispatched. */ int pa_mainloop_dispatch(pa_mainloop *m); diff --git a/src/polyp/operation.h b/src/polyp/operation.h index d286b0c1..2fbac2e2 100644 --- a/src/polyp/operation.h +++ b/src/polyp/operation.h @@ -30,8 +30,7 @@ PA_C_DECL_BEGIN -/** \struct pa_operation - * An asynchronous operation object */ +/** An asynchronous operation object */ typedef struct pa_operation pa_operation; /** Increase the reference count by one */ diff --git a/src/polyp/polypaudio.h b/src/polyp/polypaudio.h index c81fdfdb..b70b8d70 100644 --- a/src/polyp/polypaudio.h +++ b/src/polyp/polypaudio.h @@ -22,7 +22,6 @@ USA. ***/ -#include #include #include #include @@ -33,12 +32,16 @@ #include #include #include +#include +#include +#include /** \file - * Include all polyplib header file at once. The following files are included: \ref mainloop-api.h, \ref sample.h, - * \ref def.h, \ref context.h, \ref stream.h, - * \ref introspect.h, \ref subscribe.h, \ref scache.h, \ref version.h \ref error.h - * at once */ + * Include all polyplib header file at once. The following + * files are included: \ref mainloop-api.h, \ref sample.h, \ref def.h, + * \ref context.h, \ref stream.h, \ref introspect.h, \ref subscribe.h, + * \ref scache.h, \ref version.h, \ref error.h, \ref channelmap.h, + * \ref operation.h and \ref volume.h at once */ /** \mainpage * diff --git a/src/polyp/sample.h b/src/polyp/sample.h index c1b98f1c..db4c6c70 100644 --- a/src/polyp/sample.h +++ b/src/polyp/sample.h @@ -33,7 +33,7 @@ PA_C_DECL_BEGIN -/* Maximum allowed channels */ +/** Maximum allowed channels */ #define PA_CHANNELS_MAX 16 /** Sample format */ @@ -43,8 +43,8 @@ typedef enum pa_sample_format { PA_SAMPLE_ULAW, /**< 8 Bit mu-Law */ PA_SAMPLE_S16LE, /**< Signed 16 Bit PCM, little endian (PC) */ PA_SAMPLE_S16BE, /**< Signed 16 Bit PCM, big endian */ - PA_SAMPLE_FLOAT32LE, /**< 32 Bit IEEE floating point, little endian, range -1..1 */ - PA_SAMPLE_FLOAT32BE, /**< 32 Bit IEEE floating point, big endian, range -1..1 */ + PA_SAMPLE_FLOAT32LE, /**< 32 Bit IEEE floating point, little endian, range -1 to 1 */ + PA_SAMPLE_FLOAT32BE, /**< 32 Bit IEEE floating point, big endian, range -1 to 1 */ PA_SAMPLE_MAX, /**< Upper limit of valid sample types */ PA_SAMPLE_INVALID = -1 /**< An invalid value */ } pa_sample_format_t; @@ -100,7 +100,7 @@ int pa_sample_spec_valid(const pa_sample_spec *spec); /** Return non-zero when the two sample type specifications match */ int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b); -/* Return a descriptive string for the specified sample format. \since 0.8 */ +/** Return a descriptive string for the specified sample format. \since 0.8 */ const char *pa_sample_format_to_string(pa_sample_format_t f); /** Parse a sample format text. Inverse of pa_sample_format_to_string() */ diff --git a/src/polyp/scache.c b/src/polyp/scache.c index 393b069e..f6a3a7e6 100644 --- a/src/polyp/scache.c +++ b/src/polyp/scache.c @@ -79,14 +79,14 @@ void pa_stream_finish_upload(pa_stream *s) { pa_stream_unref(s); } -pa_operation * pa_context_play_sample(pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { +pa_operation * pa_context_play_sample(pa_context *c, const char *name, const char *dev, uint32_t volume, pa_context_success_cb_t cb, void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; assert(c && name && *name && (!dev || *dev)); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; if (!dev) @@ -106,14 +106,14 @@ pa_operation * pa_context_play_sample(pa_context *c, const char *name, const cha return pa_operation_ref(o); } -pa_operation* pa_context_remove_sample(pa_context *c, const char *name, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { +pa_operation* pa_context_remove_sample(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; assert(c && name); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); diff --git a/src/polyp/scache.h b/src/polyp/scache.h index 5bf004d0..3480d876 100644 --- a/src/polyp/scache.h +++ b/src/polyp/scache.h @@ -36,14 +36,21 @@ PA_C_DECL_BEGIN /** Make this stream a sample upload stream */ void pa_stream_connect_upload(pa_stream *s, size_t length); -/** Finish the sample upload, the stream name will become the sample name. You cancel a sample upload by issuing pa_stream_disconnect() */ +/** Finish the sample upload, the stream name will become the sample name. You cancel a samp + * le upload by issuing pa_stream_disconnect() */ void pa_stream_finish_upload(pa_stream *s); /** Play a sample from the sample cache to the specified device. If the latter is NULL use the default sink. Returns an operation object */ -pa_operation* pa_context_play_sample(pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_play_sample( + pa_context *c /**< Context */, + const char *name /**< Name of the sample to play */, + const char *dev /**< Sink to play this sample on */, + pa_volume_t volume /**< Volume to play this sample with */ , + pa_context_success_cb_t cb /**< Call this function after successfully starting playback, or NULL */, + void *userdata /**< Userdata to pass to the callback */); /** Remove a sample from the sample cache. Returns an operation object which may be used to cancel the operation while it is running */ -pa_operation* pa_context_remove_sample(pa_context *c, const char *name, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_remove_sample(pa_context *c, const char *name, pa_context_success_cb_t, void *userdata); PA_C_DECL_END diff --git a/src/polyp/stream.c b/src/polyp/stream.c index 5497f0c4..88971085 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -592,7 +592,7 @@ pa_operation * pa_stream_drain(pa_stream *s, void (*cb) (pa_stream*s, int succes PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); o = pa_operation_new(s->context, s); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -680,7 +680,7 @@ pa_operation* pa_stream_get_latency_info(pa_stream *s, void (*cb)(pa_stream *p, PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); o = pa_operation_new(s->context, s); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -830,7 +830,7 @@ pa_operation* pa_stream_cork(pa_stream *s, int b, void (*cb) (pa_stream*s, int s o = pa_operation_new(s->context, s); assert(o); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -854,7 +854,7 @@ static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); o = pa_operation_new(s->context, s); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -896,7 +896,7 @@ pa_operation* pa_stream_set_name(pa_stream *s, const char *name, void(*cb)(pa_st o = pa_operation_new(s->context, s); assert(o); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -978,9 +978,16 @@ pa_usec_t pa_stream_get_latency(pa_stream *s, const pa_latency_info *i, int *neg const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) { assert(s); + return &s->sample_spec; } +const pa_channel_map* pa_stream_get_channel_map(pa_stream *s) { + assert(s); + + return &s->channel_map; +} + void pa_stream_trash_ipol(pa_stream *s) { assert(s); diff --git a/src/polyp/stream.h b/src/polyp/stream.h index ce535963..75b0a900 100644 --- a/src/polyp/stream.h +++ b/src/polyp/stream.h @@ -36,8 +36,7 @@ PA_C_DECL_BEGIN -/** \struct pa_stream - * An opaque stream for playback or recording */ +/** An opaque stream for playback or recording */ typedef struct pa_stream pa_stream; /** A generic callback for operation completion */ @@ -57,10 +56,10 @@ typedef void (*pa_stream_get_latency_info_cb_t)(pa_stream *p, const pa_latency_i /** Create a new, unconnected stream with the specified name and sample type */ pa_stream* pa_stream_new( - pa_context *c, - const char *name, - const pa_sample_spec *ss, - const pa_channel_map *map); + pa_context *c /**< The context to create this stream in */, + const char *name /**< A name for this stream */, + const pa_sample_spec *ss /**< The desired sample format */, + const pa_channel_map *map /**< The desired channel map, or NULL for default */); /** Decrease the reference counter by one */ void pa_stream_unref(pa_stream *s); @@ -88,10 +87,10 @@ int pa_stream_connect_playback( /** Connect the stream to a source */ int pa_stream_connect_record( - pa_stream *s, - const char *dev, - const pa_buffer_attr *attr, - pa_stream_flags_t flags); + pa_stream *s /**< The stream to connect to a source */ , + const char *dev /**< Name of the source to connect to, or NULL for default */, + const pa_buffer_attr *attr /**< Buffer attributes, or NULL for default */, + pa_stream_flags_t flags /**< Additional flags, or 0 for default */); /** Disconnect a stream from a source/sink */ int pa_stream_disconnect(pa_stream *s); @@ -203,9 +202,12 @@ pa_usec_t pa_stream_get_interpolated_time(pa_stream *s); * stream. \since 0.6 */ pa_usec_t pa_stream_get_interpolated_latency(pa_stream *s, int *negative); -/** Return a pointer to the streams sample specification. \since 0.6 */ +/** Return a pointer to the stream's sample specification. \since 0.6 */ const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s); +/** Return a pointer to the stream's channel map. \since 0.8 */ +const pa_channel_map* pa_stream_get_channel_map(pa_stream *s); + PA_C_DECL_END #endif diff --git a/src/polyp/subscribe.c b/src/polyp/subscribe.c index 4e00997a..97f76cb7 100644 --- a/src/polyp/subscribe.c +++ b/src/polyp/subscribe.c @@ -56,14 +56,14 @@ finish: } -pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { +pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_context_success_cb_t cb, void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; assert(c); o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback) cb; + o->callback = (pa_operation_callback_t) cb; o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); @@ -76,7 +76,7 @@ pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, void return pa_operation_ref(o); } -void pa_context_set_subscribe_callback(pa_context *c, void (*cb)(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata) { +void pa_context_set_subscribe_callback(pa_context *c, pa_context_subscribe_cb_t cb, void *userdata) { assert(c); c->subscribe_callback = cb; c->subscribe_userdata = userdata; diff --git a/src/polyp/subscribe.h b/src/polyp/subscribe.h index f1f0642d..5301739a 100644 --- a/src/polyp/subscribe.h +++ b/src/polyp/subscribe.h @@ -36,11 +36,14 @@ PA_C_DECL_BEGIN +/** Subscription event callback prototype */ +typedef void (*pa_context_subscribe_cb_t)(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata); + /** Enable event notification */ -pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_context_success_cb_t cb, void *userdata); /** Set the context specific call back function that is called whenever the state of the daemon changes */ -void pa_context_set_subscribe_callback(pa_context *c, void (*cb)(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata); +void pa_context_set_subscribe_callback(pa_context *c, pa_context_subscribe_cb_t cb, void *userdata); PA_C_DECL_END diff --git a/src/polyp/volume.h b/src/polyp/volume.h index b2a48084..d1e858c4 100644 --- a/src/polyp/volume.h +++ b/src/polyp/volume.h @@ -46,8 +46,8 @@ typedef uint32_t pa_volume_t; /** A structure encapsulating a per-channel volume */ typedef struct pa_cvolume { - uint8_t channels; - pa_volume_t values[PA_CHANNELS_MAX]; + uint8_t channels; /**< Number of channels */ + pa_volume_t values[PA_CHANNELS_MAX]; /**< Per-channel volume */ } pa_cvolume; /** Return non-zero when *a == *b */ @@ -62,8 +62,10 @@ int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b); /** Set the volume of all channels to the specified parameter */ pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v); -/** Pretty print a volume structure */ +/** Maximum length of the strings returned by pa_cvolume_snprint() */ #define PA_CVOLUME_SNPRINT_MAX 64 + +/** Pretty print a volume structure */ char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c); /** Return the average volume of all channels */ @@ -75,24 +77,28 @@ int pa_cvolume_valid(const pa_cvolume *v); /** Return non-zero if the volume of all channels is equal to the specified value */ int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v); +/** Return 1 if the specified volume has all channels muted */ #define pa_cvolume_is_muted(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_MUTED) + +/** Return 1 if the specified volume has all channels on normal level */ #define pa_cvolume_is_norm(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_NORM) -/** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. */ +/** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. This is only valid for software volumes! */ pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b); +/** Multiply to per-channel volumes and return the result in *dest. This is only valid for software volumes! */ pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b); -/** Convert a decibel value to a volume. \since 0.4 */ +/** Convert a decibel value to a volume. This is only valid for software volumes! \since 0.4 */ pa_volume_t pa_sw_volume_from_dB(double f); -/** Convert a volume to a decibel value. \since 0.4 */ +/** Convert a volume to a decibel value. This is only valid for software volumes! \since 0.4 */ double pa_sw_volume_to_dB(pa_volume_t v); -/** Convert a linear factor to a volume. \since 0.8 */ +/** Convert a linear factor to a volume. This is only valid for software volumes! \since 0.8 */ pa_volume_t pa_sw_volume_from_linear(double v); -/** Convert a volume to a linear factor. \since 0.8 */ +/** Convert a volume to a linear factor. This is only valid for software volumes! \since 0.8 */ double pa_sw_volume_to_linear(pa_volume_t v); #ifdef INFINITY -- cgit From 71b3bff6816b857a6a9613cc45b06f0b9e5a65e1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 22:41:02 +0000 Subject: * modify pa_context_exit_daemon() to return a pa_operation object * add callback prototypes to all introspection functions in client lib * add proper validity checking and error handling to all functions in the client lib * other minor cleanups * todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@531 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + src/Makefile.am | 4 +- src/modules/module-tunnel.c | 2 +- src/polyp/context.c | 228 ++++++++++------ src/polyp/context.h | 8 +- src/polyp/internal.h | 15 +- src/polyp/introspect.c | 591 +++++++++++++++++++++++----------------- src/polyp/introspect.h | 110 +++++--- src/polyp/operation.c | 6 +- src/polyp/scache.c | 57 ++-- src/polyp/scache.h | 4 +- src/polyp/stream.c | 217 +++++++++------ src/polyp/subscribe.c | 20 +- src/polypcore/iochannel.c | 4 +- src/polypcore/iochannel.h | 4 +- src/polypcore/pdispatch.c | 12 +- src/polypcore/pdispatch.h | 6 +- src/polypcore/protocol-native.c | 2 +- src/polypcore/tagstruct.h | 2 - src/utils/pactl.c | 2 +- 20 files changed, 782 insertions(+), 513 deletions(-) diff --git a/doc/todo b/doc/todo index 280747fe..1fc55df9 100644 --- a/doc/todo +++ b/doc/todo @@ -12,6 +12,7 @@ Fixes: - don't build ipv4 and ipv6 modules seperately - change pa_log to not require \n - proper use of memcpy in procotol-esound.c so we don't get alignment problems +- sigpipe Features: - add radio module diff --git a/src/Makefile.am b/src/Makefile.am index 5581d77e..ed97f490 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -47,8 +47,8 @@ AM_CFLAGS = -I$(top_srcdir)/src AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS AM_CFLAGS += $(LTDLINCL) AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) -AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" -#AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\" +#AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" +AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\" AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\" AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(POLYPAUDIO_BINARY)\" diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 3ecca745..136702fc 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -94,7 +94,7 @@ static void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t t static void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); #endif -static const pa_pdispatch_callback_t command_table[PA_COMMAND_MAX] = { +static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { #ifdef TUNNEL_SINK [PA_COMMAND_REQUEST] = command_request, #endif diff --git a/src/polyp/context.c b/src/polyp/context.c index 00c09710..2cb9e7e3 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -72,7 +72,7 @@ #define AUTOSPAWN_LOCK "autospawn.lock" -static const pa_pdispatch_callback_t command_table[PA_COMMAND_MAX] = { +static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_REQUEST] = pa_command_request, [PA_COMMAND_OVERFLOW] = pa_command_overflow_or_underflow, [PA_COMMAND_UNDERFLOW] = pa_command_overflow_or_underflow, @@ -95,9 +95,11 @@ static void unlock_autospawn_lock_file(pa_context *c) { pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { pa_context *c; - assert(mainloop && name); - c = pa_xmalloc(sizeof(pa_context)); + assert(mainloop); + assert(name); + + c = pa_xnew(pa_context, 1); c->ref = 1; c->name = pa_xstrdup(name); c->mainloop = mainloop; @@ -106,7 +108,6 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { c->pdispatch = NULL; c->playback_streams = pa_dynarray_new(); c->record_streams = pa_dynarray_new(); - assert(c->playback_streams && c->record_streams); PA_LLIST_HEAD_INIT(pa_stream, c->streams); PA_LLIST_HEAD_INIT(pa_operation, c->operations); @@ -182,20 +183,24 @@ static void context_free(pa_context *c) { } pa_context* pa_context_ref(pa_context *c) { - assert(c && c->ref >= 1); + assert(c); + assert(c->ref >= 1); + c->ref++; return c; } void pa_context_unref(pa_context *c) { - assert(c && c->ref >= 1); + assert(c); + assert(c->ref >= 1); - if ((--(c->ref)) == 0) + if (--c->ref <= 0) context_free(c); } void pa_context_set_state(pa_context *c, pa_context_state_t st) { assert(c); + assert(c->ref >= 1); if (c->state == st) return; @@ -237,13 +242,15 @@ void pa_context_set_state(pa_context *c, pa_context_state_t st) { void pa_context_fail(pa_context *c, int error) { assert(c); - + assert(c->ref >= 1); + pa_context_set_error(c, error); pa_context_set_state(c, PA_CONTEXT_FAILED); } int pa_context_set_error(pa_context *c, int error) { - assert(error >= 0 && error < PA_ERR_MAX); + assert(error >= 0); + assert(error < PA_ERR_MAX); if (c) c->error = error; @@ -253,20 +260,24 @@ int pa_context_set_error(pa_context *c, int error) { static void pstream_die_callback(pa_pstream *p, void *userdata) { pa_context *c = userdata; - assert(p && c); + + assert(p); + assert(c); + pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED); } static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { pa_context *c = userdata; - assert(p && packet && c); + + assert(p); + assert(packet); + assert(c); pa_context_ref(c); - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - pa_log(__FILE__": invalid packet.\n"); + if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) pa_context_fail(c, PA_ERR_PROTOCOL); - } pa_context_unref(c); } @@ -280,6 +291,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o assert(chunk->memblock); assert(chunk->length); assert(c); + assert(c->ref >= 1); pa_context_ref(c); @@ -301,6 +313,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t) { assert(c); + assert(c->ref >= 1); if (command == PA_COMMAND_ERROR) { assert(t); @@ -322,7 +335,10 @@ int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t) { static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_context *c = userdata; - assert(pd && c && (c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME)); + + assert(pd); + assert(c); + assert(c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME); pa_context_ref(c); @@ -364,13 +380,14 @@ finish: static void setup_context(pa_context *c, pa_iochannel *io) { pa_tagstruct *t; uint32_t tag; - assert(c && io); + + assert(c); + assert(io); pa_context_ref(c); assert(!c->pstream); c->pstream = pa_pstream_new(c->mainloop, io, c->memblock_stat); - assert(c->pstream); pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); @@ -378,7 +395,6 @@ static void setup_context(pa_context *c, pa_iochannel *io) { assert(!c->pdispatch); c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); if (!c->conf->cookie_valid) { pa_context_fail(c, PA_ERR_AUTHKEY); @@ -386,7 +402,6 @@ static void setup_context(pa_context *c, pa_iochannel *io) { } t = pa_tagstruct_new(NULL, 0); - assert(t); pa_tagstruct_putu32(t, PA_COMMAND_AUTH); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie)); @@ -522,11 +537,12 @@ fail: static int try_next_connection(pa_context *c) { char *u = NULL; int r = -1; - assert(c && !c->client); + + assert(c); + assert(!c->client); for (;;) { - if (u) - pa_xfree(u); + pa_xfree(u); u = NULL; c->server_list = pa_strlist_pop(c->server_list, &u); @@ -560,15 +576,17 @@ static int try_next_connection(pa_context *c) { r = 0; finish: - if (u) - pa_xfree(u); + pa_xfree(u); return r; } static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata) { pa_context *c = userdata; - assert(client && c && c->state == PA_CONTEXT_CONNECTING); + + assert(client); + assert(c); + assert(c->state == PA_CONTEXT_CONNECTING); pa_context_ref(c); @@ -593,9 +611,19 @@ finish: pa_context_unref(c); } -int pa_context_connect(pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api) { +int pa_context_connect( + pa_context *c, + const char *server, + pa_context_flags_t flags, + const pa_spawn_api *api) { + int r = -1; - assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED); + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_UNCONNECTED, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(c, !(flags & ~PA_CONTEXT_NOAUTOSPAWN), PA_ERR_INVALID); if (!server) server = c->conf->default_server; @@ -658,27 +686,36 @@ finish: void pa_context_disconnect(pa_context *c) { assert(c); + assert(c->ref >= 1); + pa_context_set_state(c, PA_CONTEXT_TERMINATED); } pa_context_state_t pa_context_get_state(pa_context *c) { - assert(c && c->ref >= 1); + assert(c); + assert(c->ref >= 1); + return c->state; } int pa_context_errno(pa_context *c) { - assert(c && c->ref >= 1); + assert(c); + assert(c->ref >= 1); + return c->error; } void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) { - assert(c && c->ref >= 1); + assert(c); + assert(c->ref >= 1); + c->state_callback = cb; c->state_userdata = userdata; } int pa_context_is_pending(pa_context *c) { - assert(c && c->ref >= 1); + assert(c); + assert(c->ref >= 1); /* pa_log("pstream: %i\n", pa_pstream_is_pending(c->pstream)); */ /* pa_log("pdispatch: %i\n", pa_pdispatch_is_pending(c->pdispatch)); */ @@ -700,7 +737,12 @@ static void pstream_drain_callback(PA_GCC_UNUSED pa_pstream *s, void *userdata) static void set_dispatch_callbacks(pa_operation *o) { int done = 1; - assert(o && o->context && o->context->ref >= 1 && o->ref >= 1 && o->context->state == PA_CONTEXT_READY); + + assert(o); + assert(o->ref >= 1); + assert(o->context); + assert(o->context->ref >= 1); + assert(o->context->state == PA_CONTEXT_READY); pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL); pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL); @@ -719,8 +761,7 @@ static void set_dispatch_callbacks(pa_operation *o) { pa_operation_ref(o); else { if (o->callback) { - void (*cb)(pa_context *c, void *userdata); - cb = (void (*)(pa_context*, void*)) o->callback; + pa_context_notify_cb_t cb = (pa_context_notify_cb_t) o->callback; cb(o->context, o->userdata); } @@ -732,39 +773,27 @@ static void set_dispatch_callbacks(pa_operation *o) { pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) { pa_operation *o; - assert(c && c->ref >= 1); - - if (c->state != PA_CONTEXT_READY) - return NULL; - - if (!pa_context_is_pending(c)) - return NULL; - - o = pa_operation_new(c, NULL); - assert(o); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + + assert(c); + assert(c->ref >= 1); + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, pa_context_is_pending(c), PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); set_dispatch_callbacks(pa_operation_ref(o)); return o; } -void pa_context_exit_daemon(pa_context *c) { - pa_tagstruct *t; - assert(c && c->ref >= 1); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); -} - void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; int success = 1; - assert(pd && o && o->context && o->ref >= 1); + + assert(pd); + assert(o); + assert(o->ref >= 1); + assert(o->context); if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) @@ -786,67 +815,95 @@ finish: pa_operation_unref(o); } -pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, void (*internal_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata), void (*cb)(void), void *userdata) { +pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; - assert(c && cb); - o = pa_operation_new(c, NULL); - o->callback = cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_EXIT); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + + return o; +} + +pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, pa_pdispatch_cb_t internal_cb, pa_operation_cb_t cb, void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, cb, o->userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, command); pa_tagstruct_putu32(t, tag = c->ctag++); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_cb, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; - assert(c && cb); + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_SET_DEFAULT_SINK); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; - assert(c && cb); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_SET_DEFAULT_SOURCE); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } int pa_context_is_local(pa_context *c) { assert(c); + return c->local; } @@ -854,20 +911,23 @@ pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_su pa_tagstruct *t; pa_operation *o; uint32_t tag; - assert(c && name && cb); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + assert(name); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_SET_CLIENT_NAME); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } const char* pa_get_library_version(void) { @@ -875,6 +935,8 @@ const char* pa_get_library_version(void) { } const char* pa_context_get_server(pa_context *c) { + assert(c); + assert(c->ref >= 1); if (!c->server) return NULL; diff --git a/src/polyp/context.h b/src/polyp/context.h index db268759..73bcb698 100644 --- a/src/polyp/context.h +++ b/src/polyp/context.h @@ -95,10 +95,10 @@ void pa_context_disconnect(pa_context *c); /** Drain the context. If there is nothing to drain, the function returns NULL */ pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata); -/** Tell the daemon to exit. No operation object is returned as the - * connection is terminated when the daemon quits, thus this operation - * would never complete. */ -void pa_context_exit_daemon(pa_context *c); +/** Tell the daemon to exit. The returned operation is unlikely to + * complete succesfully, since the daemon probably died before + * returning a success notification */ +pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata); /** Set the name of the default sink. \since 0.4 */ pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata); diff --git a/src/polyp/internal.h b/src/polyp/internal.h index e9e0246f..9907fae0 100644 --- a/src/polyp/internal.h +++ b/src/polyp/internal.h @@ -128,7 +128,7 @@ struct pa_stream { void *underflow_userdata; }; -typedef void (*pa_operation_callback_t)(void); +typedef void (*pa_operation_cb_t)(void); struct pa_operation { int ref; @@ -138,7 +138,7 @@ struct pa_operation { pa_operation_state_t state; void *userdata; - pa_operation_callback_t callback; + pa_operation_cb_t callback; }; void pa_command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); @@ -146,7 +146,7 @@ void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); void pa_command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -pa_operation *pa_operation_new(pa_context *c, pa_stream *s); +pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t callback, void *userdata); void pa_operation_done(pa_operation *o); void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); @@ -169,12 +169,6 @@ void pa_stream_trash_ipol(pa_stream *s); return -pa_context_set_error((context), (error)); \ } while(0) -#define PA_CHECK_VALIDITY_RETURN_NULL(context, expression, error) do { \ - if (!(expression)) { \ - pa_context_set_error((context), (error)); \ - return NULL; \ - } \ -} while(0) #define PA_CHECK_VALIDITY_RETURN_ANY(context, expression, error, value) do { \ if (!(expression)) { \ @@ -183,4 +177,7 @@ void pa_stream_trash_ipol(pa_stream *s); } \ } while(0) +#define PA_CHECK_VALIDITY_RETURN_NULL(context, expression, error) PA_CHECK_VALIDITY_RETURN_ANY(context, expression, error, NULL) + + #endif diff --git a/src/polyp/introspect.c b/src/polyp/introspect.c index 404cead5..043d2076 100644 --- a/src/polyp/introspect.c +++ b/src/polyp/introspect.c @@ -39,7 +39,11 @@ static void context_stat_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; pa_stat_info i, *p = &i; - assert(pd && o && o->context && o->ref >= 1); + + assert(pd); + assert(o); + assert(o->ref >= 1); + assert(o->context); if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) @@ -57,7 +61,7 @@ static void context_stat_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNU } if (o->callback) { - void (*cb)(pa_context *s, const pa_stat_info*_i, void *_userdata) = (void (*)(pa_context *s, const pa_stat_info*_i, void *_userdata)) o->callback; + pa_stat_info_cb_t cb = (pa_stat_info_cb_t) o->callback; cb(o->context, p, o->userdata); } @@ -66,8 +70,8 @@ finish: pa_operation_unref(o); } -pa_operation* pa_context_stat(pa_context *c, void (*cb)(pa_context *c, const pa_stat_info*i, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_STAT, context_stat_callback, (pa_operation_callback_t) cb, userdata); +pa_operation* pa_context_stat(pa_context *c, pa_stat_info_cb_t cb, void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_STAT, context_stat_callback, (pa_operation_cb_t) cb, userdata); } /*** Server Info ***/ @@ -75,7 +79,11 @@ pa_operation* pa_context_stat(pa_context *c, void (*cb)(pa_context *c, const pa_ static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; pa_server_info i, *p = &i; - assert(pd && o && o->context && o->ref >= 1); + + assert(pd); + assert(o); + assert(o->ref >= 1); + assert(o->context); if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) @@ -97,7 +105,7 @@ static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command, } if (o->callback) { - void (*cb)(pa_context *s, const pa_server_info*_i, void *_userdata) = (void (*)(pa_context *s, const pa_server_info*_i, void *_userdata)) o->callback; + pa_server_info_cb_t cb = (pa_server_info_cb_t) o->callback; cb(o->context, p, o->userdata); } @@ -106,22 +114,26 @@ finish: pa_operation_unref(o); } -pa_operation* pa_context_get_server_info(pa_context *c, void (*cb)(pa_context *c, const pa_server_info*i, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SERVER_INFO, context_get_server_info_callback, (pa_operation_callback_t) cb, userdata); +pa_operation* pa_context_get_server_info(pa_context *c, pa_server_info_cb_t cb, void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SERVER_INFO, context_get_server_info_callback, (pa_operation_cb_t) cb, userdata); } /*** Sink Info ***/ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); + int eol = 1; + + assert(pd); + assert(o); + assert(o->ref >= 1); + assert(o->context); if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; - eof = -1; + eol = -1; } else { while (!pa_tagstruct_eof(t)) { @@ -144,15 +156,15 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P } if (o->callback) { - void (*cb)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata)) o->callback; + pa_sink_info_cb_t cb = (pa_sink_info_cb_t) o->callback; cb(o->context, &i, 0, o->userdata); } } } if (o->callback) { - void (*cb)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); + pa_sink_info_cb_t cb = (pa_sink_info_cb_t) o->callback; + cb(o->context, NULL, eol, o->userdata); } finish: @@ -160,19 +172,22 @@ finish: pa_operation_unref(o); } -pa_operation* pa_context_get_sink_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INFO_LIST, context_get_sink_info_callback, (pa_operation_callback_t) cb, userdata); +pa_operation* pa_context_get_sink_info_list(pa_context *c, pa_sink_info_cb_t cb, void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INFO_LIST, context_get_sink_info_callback, (pa_operation_cb_t) cb, userdata); } -pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { +pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, pa_sink_info_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; - assert(c && cb); + + assert(c); + assert(c->ref >= 1); + assert(cb); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); @@ -180,20 +195,24 @@ pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, voi pa_tagstruct_putu32(t, idx); pa_tagstruct_puts(t, NULL); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } -pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata) { +pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, pa_sink_info_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; - assert(c && cb); + + assert(c); + assert(c->ref >= 1); + assert(cb); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); @@ -201,23 +220,27 @@ pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } /*** Source info ***/ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); + int eol = 1; + + assert(pd); + assert(o); + assert(o->ref >= 1); + assert(o->context); if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; - eof = -1; + eol = -1; } else { while (!pa_tagstruct_eof(t)) { @@ -239,15 +262,15 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, } if (o->callback) { - void (*cb)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata)) o->callback; + pa_source_info_cb_t cb = (pa_source_info_cb_t) o->callback; cb(o->context, &i, 0, o->userdata); } } } if (o->callback) { - void (*cb)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); + pa_source_info_cb_t cb = (pa_source_info_cb_t) o->callback; + cb(o->context, NULL, eol, o->userdata); } finish: @@ -255,40 +278,47 @@ finish: pa_operation_unref(o); } -pa_operation* pa_context_get_source_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_INFO_LIST, context_get_source_info_callback, (pa_operation_callback_t) cb, userdata); +pa_operation* pa_context_get_source_info_list(pa_context *c, pa_source_info_cb_t cb, void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_INFO_LIST, context_get_source_info_callback, (pa_operation_cb_t) cb, userdata); } -pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { +pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, pa_source_info_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; - assert(c && cb); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + assert(cb); + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, idx); pa_tagstruct_puts(t, NULL); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } -pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata) { +pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; - assert(c && cb); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); @@ -305,14 +335,18 @@ pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); + int eol = 1; + + assert(pd); + assert(o); + assert(o->ref >= 1); + assert(o->context); if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; - eof = -1; + eol = -1; } else { while (!pa_tagstruct_eof(t)) { @@ -327,15 +361,15 @@ static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, } if (o->callback) { - void (*cb)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata)) o->callback; + pa_client_info_cb_t cb = (pa_client_info_cb_t) o->callback; cb(o->context, &i, 0, o->userdata); } } } if (o->callback) { - void (*cb)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_client_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); + pa_client_info_cb_t cb = (pa_client_info_cb_t) o->callback; + cb(o->context, NULL, eol, o->userdata); } finish: @@ -343,42 +377,50 @@ finish: pa_operation_unref(o); } -pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata) { +pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, pa_client_info_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; - assert(c && cb); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } -pa_operation* pa_context_get_client_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_CLIENT_INFO_LIST, context_get_client_info_callback, (pa_operation_callback_t) cb, userdata); +pa_operation* pa_context_get_client_info_list(pa_context *c, pa_client_info_cb_t cb, void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_CLIENT_INFO_LIST, context_get_client_info_callback, (pa_operation_cb_t) cb, userdata); } /*** Module info ***/ static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); + int eol = 1; + assert(pd); + assert(o); + assert(o->ref >= 1); + assert(o->context); + if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; - eof = -1; + eol = -1; } else { while (!pa_tagstruct_eof(t)) { @@ -394,15 +436,15 @@ static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command, } if (o->callback) { - void (*cb)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata)) o->callback; + pa_module_info_cb_t cb = (pa_module_info_cb_t) o->callback; cb(o->context, &i, 0, o->userdata); } } } if (o->callback) { - void (*cb)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_module_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); + pa_module_info_cb_t cb = (pa_module_info_cb_t) o->callback; + cb(o->context, NULL, eol, o->userdata); } finish: @@ -410,42 +452,50 @@ finish: pa_operation_unref(o); } -pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata) { +pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_info_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; - assert(c && cb); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } -pa_operation* pa_context_get_module_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_MODULE_INFO_LIST, context_get_module_info_callback, (pa_operation_callback_t) cb, userdata); +pa_operation* pa_context_get_module_info_list(pa_context *c, pa_module_info_cb_t cb, void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_MODULE_INFO_LIST, context_get_module_info_callback, (pa_operation_cb_t) cb, userdata); } /*** Sink input info ***/ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); + int eol = 1; + + assert(pd); + assert(o); + assert(o->ref >= 1); + assert(o->context); if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; - eof = -1; + eol = -1; } else { while (!pa_tagstruct_eof(t)) { @@ -469,15 +519,15 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm } if (o->callback) { - void (*cb)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata)) o->callback; + pa_sink_input_info_cb_t cb = (pa_sink_input_info_cb_t) o->callback; cb(o->context, &i, 0, o->userdata); } } } if (o->callback) { - void (*cb)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sink_input_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); + pa_sink_input_info_cb_t cb = (pa_sink_input_info_cb_t) o->callback; + cb(o->context, NULL, eol, o->userdata); } finish: @@ -485,42 +535,50 @@ finish: pa_operation_unref(o); } -pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { +pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; - assert(c && cb); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INPUT_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_input_info_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_input_info_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } pa_operation* pa_context_get_sink_input_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INPUT_INFO_LIST, context_get_sink_input_info_callback, (pa_operation_callback_t) cb, userdata); + return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INPUT_INFO_LIST, context_get_sink_input_info_callback, (pa_operation_cb_t) cb, userdata); } /*** Source output info ***/ static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); + int eol = 1; + + assert(pd); + assert(o); + assert(o->ref >= 1); + assert(o->context); if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; - eof = -1; + eol = -1; } else { while (!pa_tagstruct_eof(t)) { @@ -543,15 +601,15 @@ static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t c } if (o->callback) { - void (*cb)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata)) o->callback; + pa_source_output_info_cb_t cb = (pa_source_output_info_cb_t) o->callback; cb(o->context, &i, 0, o->userdata); } } } if (o->callback) { - void (*cb)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_source_output_info*_i, int _eof, void *_userdata))o->callback; - cb(o->context, NULL, eof, o->userdata); + pa_source_output_info_cb_t cb = (pa_source_output_info_cb_t) o->callback; + cb(o->context, NULL, eol, o->userdata); } finish: @@ -559,41 +617,49 @@ finish: pa_operation_unref(o); } -pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata) { +pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, pa_source_output_info_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; - assert(c && cb); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_OUTPUT_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_output_info_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_output_info_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } -pa_operation* pa_context_get_source_output_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, context_get_source_output_info_callback, (pa_operation_callback_t) cb, userdata); +pa_operation* pa_context_get_source_output_info_list(pa_context *c, pa_source_output_info_cb_t cb, void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, context_get_source_output_info_callback, (pa_operation_cb_t) cb, userdata); } /*** Volume manipulation ***/ -pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { +pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; - assert(c && idx != PA_INVALID_INDEX); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + assert(volume); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); @@ -602,20 +668,26 @@ pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, c pa_tagstruct_puts(t, NULL); pa_tagstruct_put_cvolume(t, volume); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } -pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { +pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; - assert(c && name); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + assert(name); + assert(volume); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); @@ -624,20 +696,25 @@ pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name pa_tagstruct_puts(t, name); pa_tagstruct_put_cvolume(t, volume); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } -pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { +pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; - assert(c && idx != PA_INVALID_INDEX); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + assert(volume); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME); @@ -645,23 +722,27 @@ pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, cons pa_tagstruct_putu32(t, idx); pa_tagstruct_put_cvolume(t, volume); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } /** Sample Cache **/ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); + int eol = 1; + + assert(pd); + assert(o); + assert(o->ref >= 1); + assert(o->context); if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; - eof = -1; + eol = -1; } else { while (!pa_tagstruct_eof(t)) { @@ -682,15 +763,15 @@ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, } if (o->callback) { - void (*cb)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata)) o->callback; + pa_sample_info_cb_t cb = (pa_sample_info_cb_t) o->callback; cb(o->context, &i, 0, o->userdata); } } } if (o->callback) { - void (*cb)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_sample_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); + pa_sample_info_cb_t cb = (pa_sample_info_cb_t) o->callback; + cb(o->context, NULL, eol, o->userdata); } finish: @@ -698,15 +779,19 @@ finish: pa_operation_unref(o); } -pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata) { +pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, pa_sample_info_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; - assert(c && cb && name); + + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_SAMPLE_INFO); @@ -714,20 +799,24 @@ pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } -pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata) { +pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, pa_sample_info_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; - assert(c && cb); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_SAMPLE_INFO); @@ -735,81 +824,93 @@ pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, v pa_tagstruct_putu32(t, idx); pa_tagstruct_puts(t, NULL); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } -pa_operation* pa_context_get_sample_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SAMPLE_INFO_LIST, context_get_sample_info_callback, (pa_operation_callback_t) cb, userdata); +pa_operation* pa_context_get_sample_info_list(pa_context *c, pa_sample_info_cb_t cb, void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SAMPLE_INFO_LIST, context_get_sample_info_callback, (pa_operation_cb_t) cb, userdata); } -static pa_operation* command_kill(pa_context *c, uint32_t command, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { +static pa_operation* command_kill(pa_context *c, uint32_t command, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; - assert(c && idx != PA_INVALID_INDEX); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, command); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } -pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { +pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { return command_kill(c, PA_COMMAND_KILL_CLIENT, idx, cb, userdata); } -pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { +pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { return command_kill(c, PA_COMMAND_KILL_SINK_INPUT, idx, cb, userdata); } -pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { +pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { return command_kill(c, PA_COMMAND_KILL_SOURCE_OUTPUT, idx, cb, userdata); } -static void load_module_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { +static void context_index_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; - uint32_t idx = -1; - assert(pd && o && o->context && o->ref >= 1); + uint32_t idx; + assert(pd); + assert(o); + assert(o->ref >= 1); + assert(o->context); + if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; - } else if (pa_tagstruct_getu32(t, &idx) < 0 || + idx = PA_INVALID_INDEX; + } else if (pa_tagstruct_getu32(t, &idx) || !pa_tagstruct_eof(t)) { pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } - + if (o->callback) { - void (*cb)(pa_context *c, uint32_t _idx, void *_userdata) = (void (*)(pa_context *c, uint32_t _idx, void *_userdata)) o->callback; + pa_context_index_cb_t cb = (pa_context_index_cb_t) o->callback; cb(o->context, idx, o->userdata); } + finish: pa_operation_done(o); pa_operation_unref(o); } -pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, void (*cb)(pa_context *c, uint32_t idx, void *userdata), void *userdata) { +pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, pa_context_index_cb_t cb, void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; - assert(c && name && argument); + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_LOAD_MODULE); @@ -817,12 +918,12 @@ pa_operation* pa_context_load_module(pa_context *c, const char*name, const char pa_tagstruct_puts(t, name); pa_tagstruct_puts(t, argument); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, load_module_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_index_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } -pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { +pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { return command_kill(c, PA_COMMAND_UNLOAD_MODULE, idx, cb, userdata); } @@ -830,14 +931,18 @@ pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, void (*cb)(p static void context_get_autoload_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; - int eof = 1; - assert(pd && o && o->context && o->ref >= 1); + int eol = 1; + + assert(pd); + assert(o); + assert(o->ref >= 1); + assert(o->context); if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; - eof = -1; + eol = -1; } else { while (!pa_tagstruct_eof(t)) { @@ -853,15 +958,15 @@ static void context_get_autoload_info_callback(pa_pdispatch *pd, uint32_t comman } if (o->callback) { - void (*cb)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata)) o->callback; + pa_autoload_info_cb_t cb = (pa_autoload_info_cb_t) o->callback; cb(o->context, &i, 0, o->userdata); } } } if (o->callback) { - void (*cb)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata) = (void (*)(pa_context *s, const pa_autoload_info*_i, int _eof, void *_userdata)) o->callback; - cb(o->context, NULL, eof, o->userdata); + pa_autoload_info_cb_t cb = (pa_autoload_info_cb_t) o->callback; + cb(o->context, NULL, eol, o->userdata); } finish: @@ -869,15 +974,20 @@ finish: pa_operation_unref(o); } -pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { +pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_autoload_info_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; - assert(c && cb && name); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, type == PA_AUTOLOAD_SINK || type == PA_AUTOLOAD_SOURCE, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_AUTOLOAD_INFO); @@ -885,71 +995,53 @@ pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *na pa_tagstruct_puts(t, name); pa_tagstruct_putu32(t, type); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } -pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { +pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, pa_autoload_info_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; - assert(c && cb && idx != PA_INVALID_INDEX); + + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_AUTOLOAD_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, o); - - return pa_operation_ref(o); -} + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, pa_operation_ref(o)); -pa_operation* pa_context_get_autoload_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, context_get_autoload_info_callback, (pa_operation_callback_t) cb, userdata); + return o; } -static void context_add_autoload_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - uint32_t idx; - assert(pd && o && o->context && o->ref >= 1); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - idx = PA_INVALID_INDEX; - } else if (pa_tagstruct_getu32(t, &idx) || - !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - void (*cb)(pa_context *s, uint32_t _idx, void *_userdata) = (void (*)(pa_context *s, uint32_t _idx, void *_userdata)) o->callback; - cb(o->context, idx, o->userdata); - } - - -finish: - pa_operation_done(o); - pa_operation_unref(o); +pa_operation* pa_context_get_autoload_info_list(pa_context *c, pa_autoload_info_cb_t cb, void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, context_get_autoload_info_callback, (pa_operation_cb_t) cb, userdata); } -pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { +pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, pa_context_index_cb_t cb, void* userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; - assert(c && name && module && argument); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, type == PA_AUTOLOAD_SINK || type == PA_AUTOLOAD_SOURCE, PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, module && *module, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_ADD_AUTOLOAD); @@ -959,20 +1051,24 @@ pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autolo pa_tagstruct_puts(t, module); pa_tagstruct_puts(t, argument); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_add_autoload_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_index_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } -pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { +pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_context_success_cb_t cb, void* userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; - assert(c && name); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, type == PA_AUTOLOAD_SINK || type == PA_AUTOLOAD_SOURCE, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_AUTOLOAD); @@ -980,27 +1076,30 @@ pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name pa_tagstruct_puts(t, name); pa_tagstruct_putu32(t, type); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } -pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { +pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void* userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; - assert(c && idx != PA_INVALID_INDEX); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_AUTOLOAD); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } diff --git a/src/polyp/introspect.h b/src/polyp/introspect.h index 0abb54cf..d4ff65fb 100644 --- a/src/polyp/introspect.h +++ b/src/polyp/introspect.h @@ -36,11 +36,12 @@ * of a certain kind, use the pa_context_xxx_list() functions. The * specified callback function is called once for each entry. The * enumeration is finished by a call to the callback function with - * is_last=1 and i=NULL. Strings referenced in pa_xxx_info structures - * and the structures themselves point to internal memory that may not - * be modified. That memory is only valid during the call to the - * callback function. A deep copy is required if you need this data - * outside the callback functions. An error is signalled by a call to * the callback function with i=NULL and is_last=0. + * eol=1 and i=NULL. Strings referenced in pa_xxx_info structures and + * the structures themselves point to internal memory that may not be + * modified. That memory is only valid during the call to the callback + * function. A deep copy is required if you need this data outside the + * callback functions. An error is signalled by a call to the callback + * function with i=NULL and eol=0. * * When using the routines that ask fo a single entry only, a callback * with the same signature is used. However, no finishing call to the @@ -63,14 +64,17 @@ typedef struct pa_sink_info { const char *driver; /**< Driver name. \since 0.9 */ } pa_sink_info; +/** Callback prototype for pa_context_get_sink_info_by_name() and friends */ +typedef void (*pa_sink_info_cb_t)(pa_context *c, const pa_sink_info *i, int eol, void *userdata); + /** Get information about a sink by its name */ -pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, pa_sink_info_cb_t cb, void *userdata); /** Get information about a sink by its index */ -pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t id, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t id, pa_sink_info_cb_t cb, void *userdata); /** Get the complete sink list */ -pa_operation* pa_context_get_sink_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_sink_info_list(pa_context *c, pa_sink_info_cb_t cb, void *userdata); /** Stores information about sources */ typedef struct pa_source_info { @@ -86,14 +90,17 @@ typedef struct pa_source_info { const char *driver; /**< Driver name \since 0.9 */ } pa_source_info; +/** Callback prototype for pa_context_get_source_info_by_name() and friends */ +typedef void (*pa_source_info_cb_t)(pa_context *c, const pa_source_info *i, int eol, void *userdata); + /** Get information about a source by its name */ -pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata); /** Get information about a source by its index */ -pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t id, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t id, pa_source_info_cb_t cb, void *userdata); /** Get the complete source list */ -pa_operation* pa_context_get_source_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_source_info_list(pa_context *c, pa_source_info_cb_t cb, void *userdata); /** Server information */ typedef struct pa_server_info { @@ -107,8 +114,11 @@ typedef struct pa_server_info { uint32_t cookie; /**< A random cookie for identifying this instance of polypaudio. \since 0.8 */ } pa_server_info; +/** Callback prototype for pa_context_get_server_info() */ +typedef void (*pa_server_info_cb_t) (pa_context *c, const pa_server_info*i, void *userdata); + /** Get some information about the server */ -pa_operation* pa_context_get_server_info(pa_context *c, void (*cb)(pa_context *c, const pa_server_info*i, void *userdata), void *userdata); +pa_operation* pa_context_get_server_info(pa_context *c, pa_server_info_cb_t cb, void *userdata); /** Stores information about modules */ typedef struct pa_module_info { @@ -119,11 +129,14 @@ typedef struct pa_module_info { int auto_unload; /**< Non-zero if this is an autoloaded module */ } pa_module_info; +/** Callback prototype for pa_context_get_module_info() and firends*/ +typedef void (*pa_module_info_cb_t) (pa_context *c, const pa_module_info*i, int eol, void *userdata); + /** Get some information about a module by its index */ -pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_info_cb_t cb, void *userdata); /** Get the complete list of currently loaded modules */ -pa_operation* pa_context_get_module_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_module_info*i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_module_info_list(pa_context *c, pa_module_info_cb_t cb, void *userdata); /** Stores information about clients */ typedef struct pa_client_info { @@ -133,11 +146,14 @@ typedef struct pa_client_info { const char *driver; /**< Driver name \since 0.9 */ } pa_client_info; +/** Callback prototype for pa_context_get_client_info() and firends*/ +typedef void (*pa_client_info_cb_t) (pa_context *c, const pa_client_info*i, int eol, void *userdata); + /** Get information about a client by its index */ -pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, pa_client_info_cb_t cb, void *userdata); /** Get the complete client list */ -pa_operation* pa_context_get_client_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_client_info*i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_client_info_list(pa_context *c, pa_client_info_cb_t cb, void *userdata); /** Stores information about sink inputs */ typedef struct pa_sink_input_info { @@ -155,11 +171,14 @@ typedef struct pa_sink_input_info { const char *driver; /**< Driver name \since 0.9 */ } pa_sink_input_info; +/** Callback prototype for pa_context_get_sink_input_info() and firends*/ +typedef void (*pa_sink_input_info_cb_t) (pa_context *c, const pa_sink_input_info *i, int eol, void *userdata); + /** Get some information about a sink input by its index */ -pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata); /** Get the complete sink input list */ -pa_operation* pa_context_get_sink_input_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_sink_input_info_list(pa_context *c, pa_sink_input_info_cb_t cb, void *userdata); /** Stores information about source outputs */ typedef struct pa_source_output_info { @@ -176,20 +195,23 @@ typedef struct pa_source_output_info { const char *driver; /**< Driver name \since 0.9 */ } pa_source_output_info; +/** Callback prototype for pa_context_get_source_output_info() and firends*/ +typedef void (*pa_source_output_info_cb_t) (pa_context *c, const pa_source_output_info *i, int eol, void *userdata); + /** Get information about a source output by its index */ -pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, pa_source_output_info_cb_t cb, void *userdata); /** Get the complete list of source outputs */ -pa_operation* pa_context_get_source_output_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_source_output_info*i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_source_output_info_list(pa_context *c, pa_source_output_info_cb_t cb, void *userdata); /** Set the volume of a sink device specified by its index */ -pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); /** Set the volume of a sink device specified by its name */ -pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); /** Set the volume of a sink input stream */ -pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); /** Memory block statistics */ typedef struct pa_stat_info { @@ -200,8 +222,11 @@ typedef struct pa_stat_info { uint32_t scache_size; /**< Total size of all sample cache entries. \since 0.4 */ } pa_stat_info; +/** Callback prototype for pa_context_stat() */ +typedef void (*pa_stat_info_cb_t) (pa_context *c, const pa_stat_info *i, void *userdata); + /** Get daemon memory block statistics */ -pa_operation* pa_context_stat(pa_context *c, void (*cb)(pa_context *c, const pa_stat_info *i, void *userdata), void *userdata); +pa_operation* pa_context_stat(pa_context *c, pa_stat_info_cb_t cb, void *userdata); /** Stores information about sample cache entries */ typedef struct pa_sample_info { @@ -216,29 +241,35 @@ typedef struct pa_sample_info { const char *filename; /**< In case this is a lazy cache entry, the filename for the sound file to be loaded on demand. \since 0.5 */ } pa_sample_info; +/** Callback prototype for pa_context_get_sample_info_by_name() and firends */ +typedef void (*pa_sample_info_cb_t)(pa_context *c, const pa_sample_info *i, int eol, void *userdata); + /** Get information about a sample by its name */ -pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, pa_sample_info_cb_t cb, void *userdata); /** Get information about a sample by its index */ -pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, pa_sample_info_cb_t cb, void *userdata); /** Get the complete list of samples stored in the daemon. */ -pa_operation* pa_context_get_sample_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sample_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_sample_info_list(pa_context *c, pa_sample_info_cb_t cb, void *userdata); /** Kill a client. \since 0.5 */ -pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); /** Kill a sink input. \since 0.5 */ -pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); /** Kill a source output. \since 0.5 */ -pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); + +/** Callback prototype for pa_context_load_module() and pa_context_add_autoload() */ +typedef void (*pa_context_index_cb_t)(pa_context *c, uint32_t idx, void *userdata); /** Load a module. \since 0.5 */ -pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, void (*cb)(pa_context *c, uint32_t idx, void *userdata), void *userdata); +pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, pa_context_index_cb_t cb, void *userdata); /** Unload a module. \since 0.5 */ -pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); /** Type of an autoload entry. \since 0.5 */ typedef enum pa_autoload_type { @@ -255,23 +286,26 @@ typedef struct pa_autoload_info { const char *argument; /**< Argument string for module */ } pa_autoload_info; +/** Callback prototype for pa_context_get_autoload_info_by_name() and firends */ +typedef void (*pa_autoload_info_cb_t)(pa_context *c, const pa_autoload_info *i, int eol, void *userdata); + /** Get info about a specific autoload entry. \since 0.6 */ -pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_autoload_info_cb_t cb, void *userdata); /** Get info about a specific autoload entry. \since 0.6 */ -pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, pa_autoload_info_cb_t cb, void *userdata); /** Get the complete list of autoload entries. \since 0.5 */ -pa_operation* pa_context_get_autoload_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_autoload_info_list(pa_context *c, pa_autoload_info_cb_t cb, void *userdata); /** Add a new autoload entry. \since 0.5 */ -pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, void (*cb)(pa_context *c, int idx, void *userdata), void* userdata); +pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, pa_context_index_cb_t, void* userdata); /** Remove an autoload entry. \since 0.6 */ -pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata); +pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_context_success_cb_t cb, void* userdata); /** Remove an autoload entry. \since 0.6 */ -pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void* userdata); +pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void* userdata); PA_C_DECL_END diff --git a/src/polyp/operation.c b/src/polyp/operation.c index 5440cf9e..0216888c 100644 --- a/src/polyp/operation.c +++ b/src/polyp/operation.c @@ -31,7 +31,7 @@ #include "operation.h" -pa_operation *pa_operation_new(pa_context *c, pa_stream *s) { +pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t cb, void *userdata) { pa_operation *o; assert(c); @@ -41,8 +41,8 @@ pa_operation *pa_operation_new(pa_context *c, pa_stream *s) { o->stream = s ? pa_stream_ref(s) : NULL; o->state = PA_OPERATION_RUNNING; - o->userdata = NULL; - o->callback = NULL; + o->callback = cb; + o->userdata = userdata; PA_LLIST_PREPEND(pa_operation, o->context->operations, o); return pa_operation_ref(o); diff --git a/src/polyp/scache.c b/src/polyp/scache.c index f6a3a7e6..792d7cbf 100644 --- a/src/polyp/scache.c +++ b/src/polyp/scache.c @@ -34,15 +34,17 @@ #include "scache.h" -void pa_stream_connect_upload(pa_stream *s, size_t length) { +int pa_stream_connect_upload(pa_stream *s, size_t length) { pa_tagstruct *t; uint32_t tag; - assert(s && length); + assert(s); + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, length <= 0, PA_ERR_INVALID); + pa_stream_ref(s); - s->state = PA_STREAM_CREATING; s->direction = PA_STREAM_UPLOAD; t = pa_tagstruct_new(NULL, 0); @@ -54,22 +56,23 @@ void pa_stream_connect_upload(pa_stream *s, size_t length) { pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s); + pa_stream_set_state(s, PA_STREAM_CREATING); + pa_stream_unref(s); + return 0; } -void pa_stream_finish_upload(pa_stream *s) { +int pa_stream_finish_upload(pa_stream *s) { pa_tagstruct *t; uint32_t tag; assert(s); - if (!s->channel_valid || !s->context->state == PA_CONTEXT_READY) - return; + PA_CHECK_VALIDITY(s->context, s->channel_valid, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); pa_stream_ref(s); t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); pa_tagstruct_putu32(t, tag = s->context->ctag++); pa_tagstruct_putu32(t, s->channel); @@ -77,53 +80,59 @@ void pa_stream_finish_upload(pa_stream *s) { pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s); pa_stream_unref(s); + return 0; } -pa_operation * pa_context_play_sample(pa_context *c, const char *name, const char *dev, uint32_t volume, pa_context_success_cb_t cb, void *userdata) { +pa_operation *pa_context_play_sample(pa_context *c, const char *name, const char *dev, pa_volume_t volume, pa_context_success_cb_t cb, void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; - assert(c && name && *name && (!dev || *dev)); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, !dev || *dev, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); if (!dev) dev = c->conf->default_sink; t = pa_tagstruct_new(NULL, 0); - assert(t); pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, dev); pa_tagstruct_putu32(t, volume); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } pa_operation* pa_context_remove_sample(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; - assert(c && name); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); - assert(t); pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } diff --git a/src/polyp/scache.h b/src/polyp/scache.h index 3480d876..cdb47cab 100644 --- a/src/polyp/scache.h +++ b/src/polyp/scache.h @@ -34,11 +34,11 @@ PA_C_DECL_BEGIN /** Make this stream a sample upload stream */ -void pa_stream_connect_upload(pa_stream *s, size_t length); +int pa_stream_connect_upload(pa_stream *s, size_t length); /** Finish the sample upload, the stream name will become the sample name. You cancel a samp * le upload by issuing pa_stream_disconnect() */ -void pa_stream_finish_upload(pa_stream *s); +int pa_stream_finish_upload(pa_stream *s); /** Play a sample from the sample cache to the specified device. If the latter is NULL use the default sink. Returns an operation object */ pa_operation* pa_context_play_sample( diff --git a/src/polyp/stream.c b/src/polyp/stream.c index 88971085..1ffb4c16 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -44,7 +44,7 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * assert(c); PA_CHECK_VALIDITY_RETURN_NULL(c, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, !map || pa_channel_map_valid(map), PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID); s = pa_xnew(pa_stream, 1); s->ref = 1; @@ -190,7 +190,11 @@ void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED pa_context *c = userdata; pa_stream *s; uint32_t channel; - assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); + + assert(pd); + assert(command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED); + assert(t); + assert(c); pa_context_ref(c); @@ -203,7 +207,7 @@ void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) goto finish; - c->error = PA_ERR_KILLED; + pa_context_set_error(c, PA_ERR_KILLED); pa_stream_set_state(s, PA_STREAM_FAILED); finish: @@ -214,7 +218,11 @@ void pa_command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32 pa_stream *s; pa_context *c = userdata; uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && c); + + assert(pd); + assert(command == PA_COMMAND_REQUEST); + assert(t); + assert(c); pa_context_ref(c); @@ -276,7 +284,7 @@ finish: } static void ipol_callback(pa_mainloop_api *m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - struct timeval tv2; + struct timeval next; pa_stream *s = userdata; pa_stream_ref(s); @@ -288,10 +296,9 @@ static void ipol_callback(pa_mainloop_api *m, pa_time_event *e, PA_GCC_UNUSED co s->ipol_requested = 1; } - pa_gettimeofday(&tv2); - pa_timeval_add(&tv2, LATENCY_IPOL_INTERVAL_USEC); - - m->time_restart(e, &tv2); + pa_gettimeofday(&next); + pa_timeval_add(&next, LATENCY_IPOL_INTERVAL_USEC); + m->time_restart(e, &next); pa_stream_unref(s); } @@ -299,8 +306,12 @@ static void ipol_callback(pa_mainloop_api *m, pa_time_event *e, PA_GCC_UNUSED co void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_stream *s = userdata; - assert(pd && s && s->state == PA_STREAM_CREATING); - + + assert(pd); + assert(t); + assert(s); + assert(s->state == PA_STREAM_CREATING); + pa_stream_ref(s); if (command != PA_COMMAND_REPLY) { @@ -321,6 +332,7 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED if (s->direction == PA_STREAM_RECORD) { assert(!s->record_memblockq); + s->record_memblockq = pa_memblockq_new( 0, s->buffer_attr.maxlength, @@ -330,12 +342,10 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED 0, NULL, s->context->memblock_stat); - assert(s->record_memblockq); } s->channel_valid = 1; pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - pa_stream_set_state(s, PA_STREAM_READY); if (s->interpolate) { struct timeval tv; @@ -348,7 +358,9 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED s->ipol_event = s->mainloop->time_new(s->mainloop, &tv, &ipol_callback, s); } - if (s->requested_bytes && s->ref > 1 && s->write_callback) + pa_stream_set_state(s, PA_STREAM_READY); + + if (s->requested_bytes > 0 && s->ref > 1 && s->write_callback) s->write_callback(s, s->requested_bytes, s->write_userdata); finish: @@ -371,8 +383,10 @@ static int create_stream( assert(s->ref >= 1); PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, (flags & ~(PA_STREAM_START_CORKED|PA_STREAM_INTERPOLATE_LATENCY)) == 0, PA_ERR_INVALID); + PA_CHECK_VALIDITY(s->context, !(flags & ~(PA_STREAM_START_CORKED|PA_STREAM_INTERPOLATE_LATENCY)), PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, direction == PA_STREAM_PLAYBACK || flags == 0, PA_ERR_INVALID); + PA_CHECK_VALIDITY(s->context, !volume || volume->channels == s->sample_spec.channels, PA_ERR_INVALID); + PA_CHECK_VALIDITY(s->context, !sync_stream || (direction == PA_STREAM_PLAYBACK && sync_stream->direction == PA_STREAM_PLAYBACK), PA_ERR_INVALID); pa_stream_ref(s); @@ -395,17 +409,10 @@ static int create_stream( s->buffer_attr.fragsize = s->buffer_attr.tlength/100; } - pa_stream_set_state(s, PA_STREAM_CREATING); - t = pa_tagstruct_new(NULL, 0); - assert(t); - if (!dev) { - if (s->direction == PA_STREAM_PLAYBACK) - dev = s->context->conf->default_sink; - else - dev = s->context->conf->default_source; - } + if (!dev) + dev = s->direction == PA_STREAM_PLAYBACK ? s->context->conf->default_sink : s->context->conf->default_source; pa_tagstruct_put( t, @@ -422,6 +429,7 @@ static int create_stream( if (s->direction == PA_STREAM_PLAYBACK) { pa_cvolume cv; + pa_tagstruct_put( t, PA_TAG_U32, s->buffer_attr.tlength, @@ -430,10 +438,8 @@ static int create_stream( PA_TAG_U32, s->syncid, PA_TAG_INVALID); - if (!volume) { - pa_cvolume_reset(&cv, s->sample_spec.channels); - volume = &cv; - } + if (!volume) + volume = pa_cvolume_reset(&cv, s->sample_spec.channels); pa_tagstruct_put_cvolume(t, volume); } else @@ -442,6 +448,8 @@ static int create_stream( pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s); + pa_stream_set_state(s, PA_STREAM_CREATING); + pa_stream_unref(s); return 0; } @@ -484,7 +492,6 @@ int pa_stream_write( assert(s); assert(s->ref >= 1); - assert(s->context); assert(data); PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); @@ -495,14 +502,13 @@ int pa_stream_write( if (length <= 0) return 0; - if (free_cb) { + if (free_cb) chunk.memblock = pa_memblock_new_user((void*) data, length, free_cb, 1, s->context->memblock_stat); - assert(chunk.memblock && chunk.memblock->data); - } else { + else { chunk.memblock = pa_memblock_new(length, s->context->memblock_stat); - assert(chunk.memblock && chunk.memblock->data); memcpy(chunk.memblock->data, data, length); } + chunk.index = 0; chunk.length = length; @@ -580,7 +586,7 @@ size_t pa_stream_readable_size(pa_stream *s) { return pa_memblockq_get_length(s->record_memblockq); } -pa_operation * pa_stream_drain(pa_stream *s, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata) { +pa_operation * pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; @@ -591,9 +597,7 @@ pa_operation * pa_stream_drain(pa_stream *s, void (*cb) (pa_stream*s, int succes PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); - o = pa_operation_new(s->context, s); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); @@ -609,7 +613,11 @@ static void stream_get_latency_info_callback(pa_pdispatch *pd, uint32_t command, pa_operation *o = userdata; pa_latency_info i, *p = NULL; struct timeval local, remote, now; - assert(pd && o && o->stream && o->context); + + assert(pd); + assert(o); + assert(o->stream); + assert(o->context); if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) @@ -658,7 +666,7 @@ static void stream_get_latency_info_callback(pa_pdispatch *pd, uint32_t command, } if (o->callback) { - void (*cb)(pa_stream *s, const pa_latency_info *_i, void *_userdata) = (void (*)(pa_stream *s, const pa_latency_info *_i, void *_userdata)) o->callback; + pa_stream_get_latency_info_cb_t cb = (pa_stream_get_latency_info_cb_t) o->callback; cb(o->stream, p, o->userdata); } @@ -667,7 +675,7 @@ finish: pa_operation_unref(o); } -pa_operation* pa_stream_get_latency_info(pa_stream *s, void (*cb)(pa_stream *p, const pa_latency_info*i, void *userdata), void *userdata) { +pa_operation* pa_stream_get_latency_info(pa_stream *s, pa_stream_get_latency_info_cb_t cb, void *userdata) { uint32_t tag; pa_operation *o; pa_tagstruct *t; @@ -679,9 +687,7 @@ pa_operation* pa_stream_get_latency_info(pa_stream *s, void (*cb)(pa_stream *p, PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - o = pa_operation_new(s->context, s); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_GET_PLAYBACK_LATENCY : PA_COMMAND_GET_RECORD_LATENCY); @@ -700,7 +706,10 @@ pa_operation* pa_stream_get_latency_info(pa_stream *s, void (*cb)(pa_stream *p, void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_stream *s = userdata; - assert(pd && s && s->ref >= 1); + + assert(pd); + assert(s); + assert(s->ref >= 1); pa_stream_ref(s); @@ -789,7 +798,11 @@ void pa_stream_set_underflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, vo void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; int success = 1; - assert(pd && o && o->context && o->ref >= 1); + + assert(pd); + assert(o); + assert(o->context); + assert(o->ref >= 1); if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) @@ -802,7 +815,7 @@ void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN } if (o->callback) { - void (*cb)(pa_stream *s, int _success, void *_userdata) = (void (*)(pa_stream *s, int _success, void *_userdata)) o->callback; + pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback; cb(o->stream, success, o->userdata); } @@ -811,11 +824,16 @@ finish: pa_operation_unref(o); } -pa_operation* pa_stream_cork(pa_stream *s, int b, void (*cb) (pa_stream*s, int success, void *userdata), void *userdata) { +pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; - assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); + + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); if (s->interpolate) { if (!s->corked && b) @@ -828,13 +846,9 @@ pa_operation* pa_stream_cork(pa_stream *s, int b, void (*cb) (pa_stream*s, int s s->corked = b; - o = pa_operation_new(s->context, s); - assert(o); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); - assert(t); pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CORK_PLAYBACK_STREAM : PA_COMMAND_CORK_RECORD_STREAM); pa_tagstruct_putu32(t, tag = s->context->ctag++); pa_tagstruct_putu32(t, s->channel); @@ -847,15 +861,17 @@ pa_operation* pa_stream_cork(pa_stream *s, int b, void (*cb) (pa_stream*s, int s return pa_operation_ref(o); } -static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { +static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, pa_stream_success_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; - assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); - o = pa_operation_new(s->context, s); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, command); @@ -867,40 +883,54 @@ static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, return pa_operation_ref(o); } -pa_operation* pa_stream_flush(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { +pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { pa_operation *o; - o = stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata); - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + + if ((o = stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata))) + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + return o; } -pa_operation* pa_stream_prebuf(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { +pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { pa_operation *o; - o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata); - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); + + if ((o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata))) + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + return o; } -pa_operation* pa_stream_trigger(pa_stream *s, void (*cb)(pa_stream *s, int success, void *userdata), void *userdata) { +pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { pa_operation *o; - o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata); - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); + + if ((o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata))) + pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + return o; } -pa_operation* pa_stream_set_name(pa_stream *s, const char *name, void(*cb)(pa_stream*c, int success, void *userdata), void *userdata) { +pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; - assert(s && s->ref >= 1 && s->state == PA_STREAM_READY && name && s->direction != PA_STREAM_UPLOAD); + + assert(s); + assert(s->ref >= 1); + assert(name); - o = pa_operation_new(s->context, s); - assert(o); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); - assert(t); pa_tagstruct_putu32(t, s->direction == PA_STREAM_RECORD ? PA_COMMAND_SET_RECORD_STREAM_NAME : PA_COMMAND_SET_PLAYBACK_STREAM_NAME); pa_tagstruct_putu32(t, tag = s->context->ctag++); pa_tagstruct_putu32(t, s->channel); @@ -913,12 +943,21 @@ pa_operation* pa_stream_set_name(pa_stream *s, const char *name, void(*cb)(pa_st uint64_t pa_stream_get_counter(pa_stream *s) { assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (uint64_t) -1); + return s->counter; } pa_usec_t pa_stream_get_time(pa_stream *s, const pa_latency_info *i) { pa_usec_t usec; + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (pa_usec_t) -1); + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE, (pa_usec_t) -1); usec = pa_bytes_to_usec(i->counter, &s->sample_spec); @@ -950,6 +989,7 @@ pa_usec_t pa_stream_get_time(pa_stream *s, const pa_latency_info *i) { static pa_usec_t time_counter_diff(pa_stream *s, pa_usec_t t, pa_usec_t c, int *negative) { assert(s); + assert(s->ref >= 1); if (negative) *negative = 0; @@ -968,8 +1008,14 @@ static pa_usec_t time_counter_diff(pa_stream *s, pa_usec_t t, pa_usec_t c, int * pa_usec_t pa_stream_get_latency(pa_stream *s, const pa_latency_info *i, int *negative) { pa_usec_t t, c; - assert(s && i); + assert(s); + assert(s->ref >= 1); + assert(i); + + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (pa_usec_t) -1); + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE, (pa_usec_t) -1); + t = pa_stream_get_time(s, i); c = pa_bytes_to_usec(s->counter, &s->sample_spec); @@ -978,18 +1024,21 @@ pa_usec_t pa_stream_get_latency(pa_stream *s, const pa_latency_info *i, int *neg const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) { assert(s); - + assert(s->ref >= 1); + return &s->sample_spec; } const pa_channel_map* pa_stream_get_channel_map(pa_stream *s) { assert(s); + assert(s->ref >= 1); return &s->channel_map; } void pa_stream_trash_ipol(pa_stream *s) { assert(s); + assert(s->ref >= 1); if (!s->interpolate) return; @@ -1000,8 +1049,14 @@ void pa_stream_trash_ipol(pa_stream *s) { pa_usec_t pa_stream_get_interpolated_time(pa_stream *s) { pa_usec_t usec; - assert(s && s->interpolate); + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (pa_usec_t) -1); + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE, (pa_usec_t) -1); + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->interpolate, PA_ERR_BADSTATE, (pa_usec_t) -1); + if (s->corked) usec = s->ipol_usec; else { @@ -1021,8 +1076,14 @@ pa_usec_t pa_stream_get_interpolated_time(pa_stream *s) { pa_usec_t pa_stream_get_interpolated_latency(pa_stream *s, int *negative) { pa_usec_t t, c; - assert(s && s->interpolate); + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (pa_usec_t) -1); + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE, (pa_usec_t) -1); + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->interpolate, PA_ERR_BADSTATE, (pa_usec_t) -1); + t = pa_stream_get_interpolated_time(s); c = pa_bytes_to_usec(s->counter, &s->sample_spec); return time_counter_diff(s, t, c, negative); diff --git a/src/polyp/subscribe.c b/src/polyp/subscribe.c index 97f76cb7..65849b6d 100644 --- a/src/polyp/subscribe.c +++ b/src/polyp/subscribe.c @@ -37,7 +37,11 @@ void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSE pa_context *c = userdata; pa_subscription_event_type_t e; uint32_t index; - assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); + + assert(pd); + assert(command == PA_COMMAND_SUBSCRIBE_EVENT); + assert(t); + assert(c); pa_context_ref(c); @@ -60,24 +64,28 @@ pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_c pa_operation *o; pa_tagstruct *t; uint32_t tag; + assert(c); + assert(c->ref >= 1); - o = pa_operation_new(c, NULL); - o->callback = (pa_operation_callback_t) cb; - o->userdata = userdata; + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, m); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); - return pa_operation_ref(o); + return o; } void pa_context_set_subscribe_callback(pa_context *c, pa_context_subscribe_cb_t cb, void *userdata) { assert(c); + assert(c->ref >= 1); + c->subscribe_callback = cb; c->subscribe_userdata = userdata; } diff --git a/src/polypcore/iochannel.c b/src/polypcore/iochannel.c index c33f593e..89b061c2 100644 --- a/src/polypcore/iochannel.c +++ b/src/polypcore/iochannel.c @@ -40,7 +40,7 @@ struct pa_iochannel { int ifd, ofd; pa_mainloop_api* mainloop; - pa_iochannel_callback_t callback; + pa_iochannel_cb_t callback; void*userdata; int readable; @@ -242,7 +242,7 @@ ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) { return r; } -void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_callback_t _callback, void *userdata) { +void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) { assert(io); io->callback = _callback; diff --git a/src/polypcore/iochannel.h b/src/polypcore/iochannel.h index 7d355d8f..977fe2c3 100644 --- a/src/polypcore/iochannel.h +++ b/src/polypcore/iochannel.h @@ -57,8 +57,8 @@ int pa_iochannel_is_hungup(pa_iochannel*io); void pa_iochannel_set_noclose(pa_iochannel*io, int b); /* Set the callback function that is called whenever data becomes available for read or write */ -typedef void (*pa_iochannel_callback_t)(pa_iochannel*io, void *userdata); -void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_callback_t callback, void *userdata); +typedef void (*pa_iochannel_cb_t)(pa_iochannel*io, void *userdata); +void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t callback, void *userdata); /* In case the file descriptor is a socket, return a pretty-printed string in *s which describes the peer connected */ void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l); diff --git a/src/polypcore/pdispatch.c b/src/polypcore/pdispatch.c index fbb1b697..c082b8cc 100644 --- a/src/polypcore/pdispatch.c +++ b/src/polypcore/pdispatch.c @@ -94,7 +94,7 @@ static const char *command_names[PA_COMMAND_MAX] = { struct reply_info { pa_pdispatch *pdispatch; PA_LLIST_FIELDS(struct reply_info); - pa_pdispatch_callback_t callback; + pa_pdispatch_cb_t callback; void *userdata; uint32_t tag; pa_time_event *time_event; @@ -103,7 +103,7 @@ struct reply_info { struct pa_pdispatch { int ref; pa_mainloop_api *mainloop; - const pa_pdispatch_callback_t *callback_table; + const pa_pdispatch_cb_t *callback_table; unsigned n_commands; PA_LLIST_HEAD(struct reply_info, replies); pa_pdispatch_drain_callback drain_callback; @@ -121,7 +121,7 @@ static void reply_info_free(struct reply_info *r) { pa_xfree(r); } -pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_callback_t*table, unsigned entries) { +pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_cb_t*table, unsigned entries) { pa_pdispatch *pd; assert(mainloop); @@ -149,7 +149,7 @@ static void pdispatch_free(pa_pdispatch *pd) { } static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command, pa_tagstruct *ts) { - pa_pdispatch_callback_t callback; + pa_pdispatch_cb_t callback; void *userdata; uint32_t tag; assert(r); @@ -210,7 +210,7 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, void *userdata) { run_action(pd, r, command, ts); } else if (pd->callback_table && (command < pd->n_commands) && pd->callback_table[command]) { - const pa_pdispatch_callback_t *c = pd->callback_table+command; + const pa_pdispatch_cb_t *c = pd->callback_table+command; (*c)(pd, command, tag, ts, userdata); } else { @@ -236,7 +236,7 @@ static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, PA_GCC_UNUSED c run_action(r->pdispatch, r, PA_COMMAND_TIMEOUT, NULL); } -void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_callback_t cb, void *userdata) { +void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t cb, void *userdata) { struct reply_info *r; struct timeval tv; assert(pd && pd->ref >= 1 && cb); diff --git a/src/polypcore/pdispatch.h b/src/polypcore/pdispatch.h index 27d2d61f..31533d57 100644 --- a/src/polypcore/pdispatch.h +++ b/src/polypcore/pdispatch.h @@ -29,15 +29,15 @@ typedef struct pa_pdispatch pa_pdispatch; -typedef void (*pa_pdispatch_callback_t)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +typedef void (*pa_pdispatch_cb_t)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *m, const pa_pdispatch_callback_t*table, unsigned entries); +pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *m, const pa_pdispatch_cb_t*table, unsigned entries); void pa_pdispatch_unref(pa_pdispatch *pd); pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd); int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*p, void *userdata); -void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_callback_t callback, void *userdata); +void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t callback, void *userdata); int pa_pdispatch_is_pending(pa_pdispatch *pd); diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 21800e6c..1bca1c1e 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -174,7 +174,7 @@ static void command_get_autoload_info_list(pa_pdispatch *pd, uint32_t command, u static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static const pa_pdispatch_callback_t command_table[PA_COMMAND_MAX] = { +static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = NULL, [PA_COMMAND_TIMEOUT] = NULL, [PA_COMMAND_REPLY] = NULL, diff --git a/src/polypcore/tagstruct.h b/src/polypcore/tagstruct.h index 59db67b0..0ed75171 100644 --- a/src/polypcore/tagstruct.h +++ b/src/polypcore/tagstruct.h @@ -51,8 +51,6 @@ enum { PA_TAG_CVOLUME = 'v' }; - - pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length); void pa_tagstruct_free(pa_tagstruct*t); uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l); diff --git a/src/utils/pactl.c b/src/utils/pactl.c index e3305f0f..86c4e7be 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -559,7 +559,7 @@ static void context_state_callback(pa_context *c, void *userdata) { break; case EXIT: - pa_context_exit_daemon(c); + pa_operation_unref(pa_context_exit_daemon(c, NULL, NULL)); drain(); case LIST: -- cgit From b008941f821785b89f0b8914d4e08ee9c6ee97a5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 22:41:20 +0000 Subject: fix moddir git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@532 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index ed97f490..5581d77e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -47,8 +47,8 @@ AM_CFLAGS = -I$(top_srcdir)/src AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS AM_CFLAGS += $(LTDLINCL) AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) -#AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" -AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\" +AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" +#AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\" AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\" AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(POLYPAUDIO_BINARY)\" -- cgit From 31a027b78b5081903ecdde5cff1b42770c93b075 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 23:29:46 +0000 Subject: change calls of pa_context_connect() to pass flags arugment correctly git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@533 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pacat.c | 2 +- src/utils/pactl.c | 2 +- src/utils/paplay.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 4e126c8a..6efc3a47 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -509,7 +509,7 @@ int main(int argc, char *argv[]) { pa_context_set_state_callback(context, context_state_callback, NULL); /* Connect the context */ - pa_context_connect(context, server, 1, NULL); + pa_context_connect(context, server, 0, NULL); /* Run the main loop */ if (pa_mainloop_run(m, &ret) < 0) { diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 86c4e7be..907746aa 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -752,7 +752,7 @@ int main(int argc, char *argv[]) { } pa_context_set_state_callback(context, context_state_callback, NULL); - pa_context_connect(context, server, 1, NULL); + pa_context_connect(context, server, 0, NULL); if (pa_mainloop_run(m, &ret) < 0) { fprintf(stderr, "pa_mainloop_run() failed.\n"); diff --git a/src/utils/paplay.c b/src/utils/paplay.c index 5f985ee9..4efb4cf6 100644 --- a/src/utils/paplay.c +++ b/src/utils/paplay.c @@ -352,7 +352,7 @@ int main(int argc, char *argv[]) { pa_context_set_state_callback(context, context_state_callback, NULL); /* Connect the context */ - pa_context_connect(context, server, 1, NULL); + pa_context_connect(context, server, 0, NULL); /* Run the main loop */ if (pa_mainloop_run(m, &ret) < 0) { -- cgit From a8e85ba688db823ef79ab47b6b6c97214b1c417e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 23:30:15 +0000 Subject: remove a superfluous log line git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@534 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 1bca1c1e..e73ff761 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -585,7 +585,7 @@ static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { } if (pa_memblockq_peek(s->memblockq, chunk) < 0) { - pa_log(__FILE__": peek: failure\n"); +/* pa_log(__FILE__": peek: failure\n"); */ return -1; } -- cgit From 0858ef9bed00bf9cd14062e3980e495a01dafa66 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 23:30:53 +0000 Subject: fix yet another pa_context_connect() occurance with regards to the flags parameter git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@535 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/tests/sync-playback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/sync-playback.c b/src/tests/sync-playback.c index 5df790c9..4ac65c2f 100644 --- a/src/tests/sync-playback.c +++ b/src/tests/sync-playback.c @@ -175,7 +175,7 @@ int main(int argc, char *argv[]) { pa_context_set_state_callback(context, context_state_callback, NULL); - pa_context_connect(context, NULL, 1, NULL); + pa_context_connect(context, NULL, 0, NULL); if (pa_mainloop_run(m, &ret) < 0) fprintf(stderr, "pa_mainloop_run() failed.\n"); -- cgit From 2bdc07e2eabd791e48112593e0cec8baaa38a2fa Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 23:31:38 +0000 Subject: add validity check for the "server" parameter of pa_context_connect() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@536 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/context.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/polyp/context.c b/src/polyp/context.c index 2cb9e7e3..63acf19f 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -624,6 +624,7 @@ int pa_context_connect( PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_UNCONNECTED, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(c, !(flags & ~PA_CONTEXT_NOAUTOSPAWN), PA_ERR_INVALID); + PA_CHECK_VALIDITY(c, !server || *server, PA_ERR_INVALID); if (!server) server = c->conf->default_server; -- cgit From d48912ba04e30de6d997712c8c2e41664cd70484 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 23:32:12 +0000 Subject: improve error checking in simple API git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@537 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/simple.c | 90 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 72 insertions(+), 18 deletions(-) diff --git a/src/polyp/simple.c b/src/polyp/simple.c index 8a20c223..eabcf1ea 100644 --- a/src/polyp/simple.c +++ b/src/polyp/simple.c @@ -37,6 +37,14 @@ #include "simple.h" +#define CHECK_VALIDITY_RETURN_ANY(rerror, expression, error, ret) do { \ +if (!(expression)) { \ + if (rerror) \ + *(rerror) = error; \ + return ret; \ + } \ +} while(0); + struct pa_simple { pa_mainloop *mainloop; pa_context *context; @@ -126,10 +134,14 @@ pa_simple* pa_simple_new( int *rerror) { pa_simple *p; - int error = PA_ERR_INTERNAL; - assert(ss && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); + int error = PA_ERR_INTERNAL, r; + + CHECK_VALIDITY_RETURN_ANY(rerror, !server || *server, PA_ERR_INVALID, NULL); + CHECK_VALIDITY_RETURN_ANY(rerror, dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD, PA_ERR_INVALID, NULL); + CHECK_VALIDITY_RETURN_ANY(rerror, !dev || *dev, PA_ERR_INVALID, NULL); + CHECK_VALIDITY_RETURN_ANY(rerror, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID, NULL); - p = pa_xmalloc(sizeof(pa_simple)); + p = pa_xnew(pa_simple, 1); p->context = NULL; p->stream = NULL; p->mainloop = pa_mainloop_new(); @@ -143,21 +155,31 @@ pa_simple* pa_simple_new( if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name))) goto fail; - pa_context_connect(p->context, server, 1, NULL); - + if (pa_context_connect(p->context, server, 0, NULL) < 0) { + error = pa_context_errno(p->context); + goto fail; + } + /* Wait until the context is ready */ while (pa_context_get_state(p->context) != PA_CONTEXT_READY) { if (iterate(p, 1, &error) < 0) goto fail; } - if (!(p->stream = pa_stream_new(p->context, stream_name, ss, NULL))) + if (!(p->stream = pa_stream_new(p->context, stream_name, ss, NULL))) { + error = pa_context_errno(p->context); goto fail; + } if (dir == PA_STREAM_PLAYBACK) - pa_stream_connect_playback(p->stream, dev, attr, 0, NULL, NULL); + r = pa_stream_connect_playback(p->stream, dev, attr, 0, NULL, NULL); else - pa_stream_connect_record(p->stream, dev, attr, 0); + r = pa_stream_connect_record(p->stream, dev, attr, 0); + + if (r < 0) { + error = pa_context_errno(p->context); + goto fail; + } /* Wait until the stream is ready */ while (pa_stream_get_state(p->stream) != PA_STREAM_READY) { @@ -190,7 +212,10 @@ void pa_simple_free(pa_simple *s) { } int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { - assert(p && data && p->direction == PA_STREAM_PLAYBACK); + assert(p); + assert(data); + + CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); if (p->dead) { if (rerror) @@ -222,8 +247,11 @@ int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { } int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { - assert(p && data && p->direction == PA_STREAM_RECORD); + assert(p); + assert(data); + CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, -1); + if (p->dead) { if (rerror) *rerror = pa_context_errno(p->context); @@ -273,14 +301,20 @@ int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { static void drain_or_flush_complete(pa_stream *s, int success, void *userdata) { pa_simple *p = userdata; - assert(s && p); + + assert(s); + assert(p); + if (!success) p->dead = 1; } int pa_simple_drain(pa_simple *p, int *rerror) { pa_operation *o; - assert(p && p->direction == PA_STREAM_PLAYBACK); + + assert(p); + + CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); if (p->dead) { if (rerror) @@ -289,7 +323,11 @@ int pa_simple_drain(pa_simple *p, int *rerror) { return -1; } - o = pa_stream_drain(p->stream, drain_or_flush_complete, p); + if (!(o = pa_stream_drain(p->stream, drain_or_flush_complete, p))) { + if (rerror) + *rerror = pa_context_errno(p->context); + return -1; + } while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { if (iterate(p, 1, rerror) < 0) { @@ -309,7 +347,9 @@ int pa_simple_drain(pa_simple *p, int *rerror) { static void latency_complete(pa_stream *s, const pa_latency_info *l, void *userdata) { pa_simple *p = userdata; - assert(s && p); + + assert(s); + assert(p); if (!l) p->dead = 1; @@ -323,7 +363,10 @@ static void latency_complete(pa_stream *s, const pa_latency_info *l, void *userd pa_usec_t pa_simple_get_playback_latency(pa_simple *p, int *rerror) { pa_operation *o; - assert(p && p->direction == PA_STREAM_PLAYBACK); + + assert(p); + + CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); if (p->dead) { if (rerror) @@ -333,7 +376,11 @@ pa_usec_t pa_simple_get_playback_latency(pa_simple *p, int *rerror) { } p->latency = 0; - o = pa_stream_get_latency_info(p->stream, latency_complete, p); + if (!(o = pa_stream_get_latency_info(p->stream, latency_complete, p))) { + if (rerror) + *rerror = pa_context_errno(p->context); + return (pa_usec_t) -1; + } while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { @@ -354,7 +401,10 @@ pa_usec_t pa_simple_get_playback_latency(pa_simple *p, int *rerror) { int pa_simple_flush(pa_simple *p, int *rerror) { pa_operation *o; - assert(p && p->direction == PA_STREAM_PLAYBACK); + + assert(p); + + CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); if (p->dead) { if (rerror) @@ -363,7 +413,11 @@ int pa_simple_flush(pa_simple *p, int *rerror) { return -1; } - o = pa_stream_flush(p->stream, drain_or_flush_complete, p); + if (!(o = pa_stream_flush(p->stream, drain_or_flush_complete, p))) { + if (rerror) + *rerror = pa_context_errno(p->context); + return -1; + } while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { if (iterate(p, 1, rerror) < 0) { -- cgit From f5e8953d02283ae0adeda9474bb7d274aad528fa Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 23:32:44 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@538 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/todo b/doc/todo index 1fc55df9..35401abb 100644 --- a/doc/todo +++ b/doc/todo @@ -8,7 +8,7 @@ Fixes: - improve module-oss-mmap latency measurement - module-tunnel: improve latency calculation - make alsa modules use mmap -- better validity checking in libpolyp and protocol-{native,esound} +- better validity checking in protocol-{native,esound} - don't build ipv4 and ipv6 modules seperately - change pa_log to not require \n - proper use of memcpy in procotol-esound.c so we don't get alignment problems -- cgit From 56ce62a020c4a0261a72518ac950e1eeb04c206b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 23:40:49 +0000 Subject: build dllmain.c only on win32 (makes gcc shut up a little more) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@539 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 5581d77e..d3a10a3b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -342,7 +342,6 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = \ libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ polypcore/authkey.c polypcore/authkey.h \ polypcore/conf-parser.c polypcore/conf-parser.h \ - polypcore/dllmain.c \ polypcore/dynarray.c polypcore/dynarray.h \ polypcore/gccmacro.h \ polypcore/idxset.c polypcore/idxset.h \ @@ -369,6 +368,11 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ polypcore/winsock.h \ polypcore/xmalloc.c polypcore/xmalloc.h +if OS_IS_WIN32 +libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ + polypcore/dllmain.c +endif + if HAVE_X11 libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ polyp/client-conf-x11.c polyp/client-conf-x11.h \ @@ -484,7 +488,6 @@ libpolypcore_la_SOURCES += \ polypcore/core.c polypcore/core.h \ polypcore/core-scache.c polypcore/core-scache.h \ polypcore/core-subscribe.c polypcore/core-subscribe.h \ - polypcore/dllmain.c \ polypcore/dynarray.c polypcore/dynarray.h \ polypcore/endianmacros.h \ polypcore/g711.c polypcore/g711.h \ @@ -523,6 +526,11 @@ libpolypcore_la_SOURCES += \ polypcore/winsock.h \ polypcore/xmalloc.c polypcore/xmalloc.h +if OS_IS_WIN32 +libpolypcore_la_SOURCES += \ + polypcore/dllmain.c +endif + libpolypcore_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBOIL_CFLAGS) libpolypcore_la_LDFLAGS = -avoid-version libpolypcore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) $(LIBOIL_LIBS) -- cgit From 9bcb4134137902b886ae4debe34f2d5c372c177b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 23:47:46 +0000 Subject: fix snd_pcm_hw_params_set_rate_near() usage git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@540 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 8318f945..68e9f975 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -38,6 +38,8 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint3 int ret = -1; snd_pcm_uframes_t buffer_size; snd_pcm_hw_params_t *hwparams = NULL; + unsigned int r = ss->rate; + static const snd_pcm_format_t format_trans[] = { [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8, [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW, @@ -53,12 +55,15 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint3 snd_pcm_hw_params_any(pcm_handle, hwparams) < 0 || snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0 || snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format]) < 0 || - snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &ss->rate, NULL) < 0 || + snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL) < 0 || snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels) < 0 || (*periods > 0 && snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, periods, NULL) < 0) || (*period_size > 0 && snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL) < 0) || snd_pcm_hw_params(pcm_handle, hwparams) < 0) goto finish; + + if (ss->rate != r) + pa_log_info(__FILE__": device doesn't support %u Hz, changed to %u Hz.\n", ss->rate, r); if (snd_pcm_prepare(pcm_handle) < 0) goto finish; -- cgit From 1506c15a8ea8fd59bf97c5d41a0a99d59f86c656 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 23:50:46 +0000 Subject: build defer() function in src/polyp/mainloop-signal.c only on win32 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@541 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/mainloop-signal.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/polyp/mainloop-signal.c b/src/polyp/mainloop-signal.c index e474f461..00804324 100644 --- a/src/polyp/mainloop-signal.c +++ b/src/polyp/mainloop-signal.c @@ -91,17 +91,16 @@ static void dispatch(pa_mainloop_api*a, int sig) { } } +#ifdef OS_IS_WIN32 static void defer(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event*e, PA_GCC_UNUSED void *userdata) { ssize_t r; int sig; unsigned int sigs; -#ifdef OS_IS_WIN32 EnterCriticalSection(&crit); sigs = waiting_signals; waiting_signals = 0; LeaveCriticalSection(&crit); -#endif while (sigs) { if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) { @@ -119,6 +118,7 @@ static void defer(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event*e, PA_GCC_UNUS sigs--; } } +#endif static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags_t f, PA_GCC_UNUSED void *userdata) { ssize_t r; @@ -179,8 +179,7 @@ void pa_signal_done(void) { while (signals) pa_signal_free(signals); - - + #ifndef OS_IS_WIN32 api->io_free(io_event); io_event = NULL; -- cgit From cae2d8007650ac3bf9501177a389b69be7ae0eab Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 23:58:51 +0000 Subject: disable SIGPIPE before calling pa_core_new(), this way the warning message is not printed git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@542 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/main.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/daemon/main.c b/src/daemon/main.c index 638c2f3f..3124ad1d 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -357,6 +357,10 @@ int main(int argc, char *argv[]) { valid_pid_file = 1; } +#ifdef SIGPIPE + signal(SIGPIPE, SIG_IGN); +#endif + mainloop = pa_mainloop_new(); assert(mainloop); @@ -367,17 +371,6 @@ int main(int argc, char *argv[]) { assert(r == 0); pa_signal_new(SIGINT, signal_callback, c); pa_signal_new(SIGTERM, signal_callback, c); -#ifdef SIGPIPE - signal(SIGPIPE, SIG_IGN); -#endif - -#ifdef OS_IS_WIN32 - defer = pa_mainloop_get_api(mainloop)->defer_new(pa_mainloop_get_api(mainloop), message_cb, NULL); - assert(defer); -#endif - - if (conf->daemonize) - c->running_as_daemon = 1; #ifdef SIGUSR1 pa_signal_new(SIGUSR1, signal_callback, c); @@ -388,6 +381,14 @@ int main(int argc, char *argv[]) { #ifdef SIGHUP pa_signal_new(SIGHUP, signal_callback, c); #endif + +#ifdef OS_IS_WIN32 + defer = pa_mainloop_get_api(mainloop)->defer_new(pa_mainloop_get_api(mainloop), message_cb, NULL); + assert(defer); +#endif + + if (conf->daemonize) + c->running_as_daemon = 1; oil_init(); -- cgit From 86124abfe22016315729eebdabb280137480fbc5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 23:59:13 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@543 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index 35401abb..10a64ea5 100644 --- a/doc/todo +++ b/doc/todo @@ -12,7 +12,6 @@ Fixes: - don't build ipv4 and ipv6 modules seperately - change pa_log to not require \n - proper use of memcpy in procotol-esound.c so we don't get alignment problems -- sigpipe Features: - add radio module -- cgit From 893204fd5789acff9ca03fe4d46beec5d55a6aa4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Feb 2006 00:14:25 +0000 Subject: add hw volume control for module-oss-mmap git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@544 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss-mmap.c | 32 +++++++++++++++++++++++++++++++- src/modules/module-oss.c | 20 ++------------------ src/modules/oss-util.c | 36 ++++++++++++++++++++++++++++++++++++ src/modules/oss-util.h | 4 ++++ 4 files changed, 73 insertions(+), 19 deletions(-) diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index 80c762f1..617e51e2 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -221,6 +221,30 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { return pa_bytes_to_usec(u->out_fill, &s->sample_spec); } +static int sink_get_hw_volume(pa_sink *s) { + struct userdata *u = s->userdata; + + if (pa_oss_get_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + pa_log_info(__FILE__": device doesn't support reading mixer settings: %s\n", strerror(errno)); + s->get_hw_volume = NULL; + return -1; + } + + return 0; +} + +static int sink_set_hw_volume(pa_sink *s) { + struct userdata *u = s->userdata; + + if (pa_oss_set_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + pa_log_info(__FILE__": device doesn't support writing mixer settings: %s\n", strerror(errno)); + s->set_hw_volume = NULL; + return -1; + } + + return 0; +} + int pa__init(pa_core *c, pa_module*m) { struct audio_buf_info info; struct userdata *u = NULL; @@ -275,7 +299,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - pa_log(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + pa_log_info(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); if (nfrags >= 2 && frag_size >= 1) if (pa_oss_set_fragments(u->fd, nfrags, frag_size) < 0) @@ -338,6 +362,8 @@ int pa__init(pa_core *c, pa_module*m) { u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec, NULL); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; + u->sink->get_hw_volume = sink_get_hw_volume; + u->sink->set_hw_volume = sink_set_hw_volume; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); u->sink->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'", p); @@ -365,6 +391,10 @@ int pa__init(pa_core *c, pa_module*m) { assert(u->io_event); pa_modargs_free(ma); + + /* Read mixer settings */ + if (u->sink) + sink_get_hw_volume(u->sink); return 0; diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index fe43c45e..34743a1d 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -255,41 +255,25 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { static int sink_get_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; - char cv[PA_CVOLUME_SNPRINT_MAX]; - unsigned vol; - if (ioctl(u->fd, SOUND_MIXER_READ_PCM, &vol) < 0) { + if (pa_oss_get_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { pa_log_info(__FILE__": device doesn't support reading mixer settings: %s\n", strerror(errno)); s->get_hw_volume = NULL; return -1; } - s->hw_volume.values[0] = ((vol & 0xFF) * PA_VOLUME_NORM) / 100; - - if ((s->hw_volume.channels = s->sample_spec.channels) >= 2) - s->hw_volume.values[1] = (((vol >> 8) & 0xFF) * PA_VOLUME_NORM) / 100; - - pa_log_info(__FILE__": Read mixer settings: %s\n", pa_cvolume_snprint(cv, sizeof(cv), &s->hw_volume)); return 0; } static int sink_set_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; - char cv[PA_CVOLUME_SNPRINT_MAX]; - unsigned vol; - vol = (s->hw_volume.values[0]*100)/PA_VOLUME_NORM; - - if (s->sample_spec.channels >= 2) - vol |= ((s->hw_volume.values[1]*100)/PA_VOLUME_NORM) << 8; - - if (ioctl(u->fd, SOUND_MIXER_WRITE_PCM, &vol) < 0) { + if (pa_oss_set_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { pa_log_info(__FILE__": device doesn't support writing mixer settings: %s\n", strerror(errno)); s->set_hw_volume = NULL; return -1; } - pa_log_info(__FILE__": Wrote mixer settings: %s\n", pa_cvolume_snprint(cv, sizeof(cv), &s->hw_volume)); return 0; } diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index e9a133f5..597d16d7 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -166,3 +166,39 @@ int pa_oss_set_fragments(int fd, int nfrags, int frag_size) { return 0; } + +int pa_oss_get_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume) { + char cv[PA_CVOLUME_SNPRINT_MAX]; + unsigned vol; + + assert(fd >= 0); + assert(ss); + assert(volume); + + if (ioctl(fd, SOUND_MIXER_READ_PCM, &vol) < 0) + return -1; + + volume->values[0] = ((vol & 0xFF) * PA_VOLUME_NORM) / 100; + + if ((volume->channels = ss->channels) >= 2) + volume->values[1] = (((vol >> 8) & 0xFF) * PA_VOLUME_NORM) / 100; + + pa_log_debug(__FILE__": Read mixer settings: %s\n", pa_cvolume_snprint(cv, sizeof(cv), volume)); + return 0; +} + +int pa_oss_set_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume) { + char cv[PA_CVOLUME_SNPRINT_MAX]; + unsigned vol; + + vol = (volume->values[0]*100)/PA_VOLUME_NORM; + + if (ss->channels >= 2) + vol |= ((volume->values[1]*100)/PA_VOLUME_NORM) << 8; + + if (ioctl(fd, SOUND_MIXER_WRITE_PCM, &vol) < 0) + return -1; + + pa_log_debug(__FILE__": Wrote mixer settings: %s\n", pa_cvolume_snprint(cv, sizeof(cv), volume)); + return 0; +} diff --git a/src/modules/oss-util.h b/src/modules/oss-util.h index 6b2746cc..d8c36c56 100644 --- a/src/modules/oss-util.h +++ b/src/modules/oss-util.h @@ -23,10 +23,14 @@ ***/ #include +#include int pa_oss_open(const char *device, int *mode, int* pcaps); int pa_oss_auto_format(int fd, pa_sample_spec *ss); int pa_oss_set_fragments(int fd, int frags, int frag_size); +int pa_oss_get_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume); +int pa_oss_set_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume); + #endif -- cgit From f1a0ee78bf471bb271f9b05333da88e3621109bc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Feb 2006 00:16:52 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@545 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/todo b/doc/todo index 10a64ea5..2a9c4bb2 100644 --- a/doc/todo +++ b/doc/todo @@ -21,7 +21,7 @@ Features: - add support for auth using SCM_CREDENTIALS - include hw description in sink/source info - use scatter/gather io for sockets -- hw volume support for alsa, oss-mmap, windows, solaris +- hw volume support for alsa, windows - notifcation on hw volume change - source volume control - deal with underflows reported by OSS/ALSA properly -- cgit From 4f511bb7f0102b22862294ff4664ee07c4f6b9ca Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Feb 2006 00:37:22 +0000 Subject: * Get rid of libpolyp-mainloop * Remove pkg-config file of polyplib-error git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@546 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- configure.ac | 2 -- polyplib-error.pc.in | 10 ---------- polyplib-mainloop.pc.in | 10 ---------- src/Makefile.am | 40 +++++++++++++++++----------------------- 5 files changed, 18 insertions(+), 46 deletions(-) delete mode 100644 polyplib-error.pc.in delete mode 100644 polyplib-mainloop.pc.in diff --git a/Makefile.am b/Makefile.am index 9705d45d..d8032baa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,7 +24,7 @@ MAINTAINERCLEANFILES = noinst_DATA = pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc polyplib-browse.pc +pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-browse.pc if HAVE_GLIB20 pkgconfig_DATA += \ diff --git a/configure.ac b/configure.ac index 5ffea5ef..76b96425 100644 --- a/configure.ac +++ b/configure.ac @@ -398,9 +398,7 @@ Makefile src/Makefile polyplib.pc polyplib-simple.pc -polyplib-mainloop.pc polyplib-browse.pc -polyplib-error.pc polyplib-glib-mainloop.pc polyplib-glib12-mainloop.pc doc/Makefile diff --git a/polyplib-error.pc.in b/polyplib-error.pc.in deleted file mode 100644 index 45f69dbc..00000000 --- a/polyplib-error.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -prefix=@prefix@ -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: polyplib-error -Description: Error library for the polypaudio sound daemon -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpolyp-error-@PA_MAJORMINOR@ -Cflags: -D_REENTRANT -I${includedir} diff --git a/polyplib-mainloop.pc.in b/polyplib-mainloop.pc.in deleted file mode 100644 index ab9b3e69..00000000 --- a/polyplib-mainloop.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -prefix=@prefix@ -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: polyplib-mainloop -Description: Main loop support for polypaudio -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpolyp-mainloop-@PA_MAJORMINOR@ -Cflags: -D_REENTRANT -I${includedir} diff --git a/src/Makefile.am b/src/Makefile.am index d3a10a3b..1a179359 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -141,17 +141,17 @@ endif bin_SCRIPTS = esdcompat.sh pacat_SOURCES = utils/pacat.c -pacat_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la +pacat_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la pacat_CFLAGS = $(AM_CFLAGS) pacat_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) paplay_SOURCES = utils/paplay.c -paplay_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) +paplay_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) paplay_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) paplay_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) pactl_SOURCES = utils/pactl.c -pactl_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) +pactl_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) pactl_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) pactl_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -166,7 +166,7 @@ pax11publish_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la $(X_PRE_LIBS) -lX11 pax11publish_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) pabrowse_SOURCES = utils/pabrowse.c -pabrowse_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-browse-@PA_MAJORMINOR@.la +pabrowse_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-browse-@PA_MAJORMINOR@.la pabrowse_CFLAGS = $(AM_CFLAGS) pabrowse_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -202,7 +202,7 @@ endif mainloop_test_SOURCES = tests/mainloop-test.c mainloop_test_CFLAGS = $(AM_CFLAGS) -mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-@PA_MAJORMINOR@.la +mainloop_test_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la mainloop_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) mcalign_test_SOURCES = tests/mcalign-test.c @@ -211,12 +211,12 @@ mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpolypcore.la mcalign_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) pacat_simple_SOURCES = tests/pacat-simple.c -pacat_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la +pacat_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la pacat_simple_CFLAGS = $(AM_CFLAGS) pacat_simple_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) parec_simple_SOURCES = tests/parec-simple.c -parec_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la +parec_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la parec_simple_CFLAGS = $(AM_CFLAGS) parec_simple_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -232,12 +232,12 @@ voltest_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) cpulimit_test_SOURCES = tests/cpulimit-test.c daemon/cpulimit.c daemon/cpulimit.h cpulimit_test_CFLAGS = $(AM_CFLAGS) -cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la libpolypcore.la +cpulimit_test_LDADD = $(AM_LDADD) libpolypcore.la cpulimit_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) cpulimit_test2_SOURCES = tests/cpulimit-test.c daemon/cpulimit.c daemon/cpulimit.h cpulimit_test2_CFLAGS = $(AM_CFLAGS) -DTEST2 -cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la libpolypcore.la +cpulimit_test2_LDADD = $(AM_LDADD) libpolypcore.la cpulimit_test2_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) mainloop_test_glib_SOURCES = $(mainloop_test_SOURCES) @@ -264,7 +264,7 @@ memblockq_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) memblockq_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) sync_playback_SOURCES = tests/sync-playback.c -sync_playback_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la +sync_playback_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la sync_playback_CFLAGS = $(AM_CFLAGS) sync_playback_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -300,7 +300,6 @@ endif lib_LTLIBRARIES = \ libpolyp-@PA_MAJORMINOR@.la \ - libpolyp-mainloop-@PA_MAJORMINOR@.la \ libpolyp-simple-@PA_MAJORMINOR@.la if HAVE_HOWL @@ -336,7 +335,10 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = \ polyp/stream.c polyp/stream.h \ polyp/subscribe.c polyp/subscribe.h \ polyp/sample.c polyp/sample.h \ - polyp/volume.c polyp/volume.h + polyp/volume.c polyp/volume.h \ + polyp/mainloop.c polyp/mainloop.h \ + polyp/mainloop-signal.c polyp/mainloop-signal.h \ + polypcore/poll.c polypcore/poll.h # Internal stuff that is shared with libpolypcore libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ @@ -393,17 +395,9 @@ libpolyp_@PA_MAJORMINOR@_la_CFLAGS += $(LIBASYNCNS_CFLAGS) libpolyp_@PA_MAJORMINOR@_la_LIBADD += $(LIBASYNCNS_LIBS) endif -libpolyp_mainloop_@PA_MAJORMINOR@_la_SOURCES = \ - polyp/mainloop.c polyp/mainloop.h \ - polyp/mainloop-signal.c polyp/mainloop-signal.h \ - polypcore/poll.c polypcore/poll.h -libpolyp_mainloop_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) -libpolyp_mainloop_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la $(WINSOCK_LIBS) -libpolyp_mainloop_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 - libpolyp_simple_@PA_MAJORMINOR@_la_SOURCES = polyp/simple.c polyp/simple.h libpolyp_simple_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) -libpolyp_simple_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la +libpolyp_simple_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la libpolyp_simple_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 libpolyp_browse_@PA_MAJORMINOR@_la_SOURCES = polyp/browser.c polyp/browser.h @@ -413,12 +407,12 @@ libpolyp_browse_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_SOURCES = polyp/glib-mainloop.h polyp/glib-mainloop.c libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) -libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop-@PA_MAJORMINOR@.la $(GLIB20_LIBS) +libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la $(GLIB20_LIBS) libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_SOURCES = polyp/glib-mainloop.h polyp/glib12-mainloop.c libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS) -libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop-@PA_MAJORMINOR@.la $(GLIB12_LIBS) +libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la $(GLIB12_LIBS) libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 ################################### -- cgit From c07928a32dd5041c272be2e85581cc5773f81577 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Feb 2006 00:37:49 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@547 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/todo b/doc/todo index 2a9c4bb2..2e0ad893 100644 --- a/doc/todo +++ b/doc/todo @@ -3,6 +3,7 @@ Test: - module-combine - latency foo +- howl Fixes: - improve module-oss-mmap latency measurement @@ -26,7 +27,6 @@ Features: - source volume control - deal with underflows reported by OSS/ALSA properly - mute switch support (like ALSA does it) -- get rid of a seperate main loop lib Long term: - pass meta info for hearing impaired -- cgit From 8c80dd63025251d4f73997f24c68fdbe318b1f52 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Feb 2006 01:08:53 +0000 Subject: * Don't build seperate ipv4/ipv6 versions of the protocol plugins * Instead try IPv6 and if that fails fall back to IPv4 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@548 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 35 ------------------------------- src/modules/module-protocol-stub.c | 38 ++++++++++++--------------------- src/polypcore/socket-server.c | 43 +++++++++++++++++++++++++++++++------- src/polypcore/socket-server.h | 4 +++- 4 files changed, 51 insertions(+), 69 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 1a179359..410fd702 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -697,13 +697,9 @@ libx11prop_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS modlib_LTLIBRARIES += \ module-cli.la \ module-cli-protocol-tcp.la \ - module-cli-protocol-tcp6.la \ module-simple-protocol-tcp.la \ - module-simple-protocol-tcp6.la \ module-esound-protocol-tcp.la \ - module-esound-protocol-tcp6.la \ module-native-protocol-tcp.la \ - module-native-protocol-tcp6.la \ module-native-protocol-fd.la \ module-sine.la \ module-combine.la \ @@ -712,7 +708,6 @@ modlib_LTLIBRARIES += \ module-null-sink.la \ module-esound-sink.la \ module-http-protocol-tcp.la \ - module-http-protocol-tcp6.la \ module-detect.la if HAVE_AF_UNIX @@ -792,18 +787,14 @@ endif SYMDEF_FILES = \ modules/module-cli-symdef.h \ modules/module-cli-protocol-tcp-symdef.h \ - modules/module-cli-protocol-tcp6-symdef.h \ modules/module-cli-protocol-unix-symdef.h \ modules/module-pipe-sink-symdef.h \ modules/module-pipe-source-symdef.h \ modules/module-simple-protocol-tcp-symdef.h \ - modules/module-simple-protocol-tcp6-symdef.h \ modules/module-simple-protocol-unix-symdef.h \ modules/module-esound-protocol-tcp-symdef.h \ - modules/module-esound-protocol-tcp6-symdef.h \ modules/module-esound-protocol-unix-symdef.h \ modules/module-native-protocol-tcp-symdef.h \ - modules/module-native-protocol-tcp6-symdef.h \ modules/module-native-protocol-unix-symdef.h \ modules/module-native-protocol-fd-symdef.h \ modules/module-sine-symdef.h \ @@ -819,7 +810,6 @@ SYMDEF_FILES = \ modules/module-lirc-symdef.h \ modules/module-mmkbd-evdev-symdef.h \ modules/module-http-protocol-tcp-symdef.h \ - modules/module-http-protocol-tcp6-symdef.h \ modules/module-http-protocol-unix-symdef.h \ modules/module-x11-bell-symdef.h \ modules/module-x11-publish-symdef.h \ @@ -844,11 +834,6 @@ module_simple_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_SIMPLE $ module_simple_protocol_tcp_la_LDFLAGS = -module -avoid-version module_simple_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-simple.la libsocket-server.la -module_simple_protocol_tcp6_la_SOURCES = modules/module-protocol-stub.c -module_simple_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) -module_simple_protocol_tcp6_la_LDFLAGS = -module -avoid-version -module_simple_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-simple.la libsocket-server.la - module_simple_protocol_unix_la_SOURCES = modules/module-protocol-stub.c module_simple_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) module_simple_protocol_unix_la_LDFLAGS = -module -avoid-version @@ -865,11 +850,6 @@ module_cli_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CF module_cli_protocol_tcp_la_LDFLAGS = -module -avoid-version module_cli_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-cli.la libsocket-server.la -module_cli_protocol_tcp6_la_SOURCES = modules/module-protocol-stub.c -module_cli_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) -module_cli_protocol_tcp6_la_LDFLAGS = -module -avoid-version -module_cli_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-cli.la libsocket-server.la - module_cli_protocol_unix_la_SOURCES = modules/module-protocol-stub.c module_cli_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) module_cli_protocol_unix_la_LDFLAGS = -module -avoid-version @@ -882,11 +862,6 @@ module_http_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_ module_http_protocol_tcp_la_LDFLAGS = -module -avoid-version module_http_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-http.la libsocket-server.la -module_http_protocol_tcp6_la_SOURCES = modules/module-protocol-stub.c -module_http_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_CFLAGS) -module_http_protocol_tcp6_la_LDFLAGS = -module -avoid-version -module_http_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-http.la libsocket-server.la - module_http_protocol_unix_la_SOURCES = modules/module-protocol-stub.c module_http_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_CFLAGS) module_http_protocol_unix_la_LDFLAGS = -module -avoid-version @@ -899,11 +874,6 @@ module_native_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_NATIVE $ module_native_protocol_tcp_la_LDFLAGS = -module -avoid-version module_native_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la -module_native_protocol_tcp6_la_SOURCES = modules/module-protocol-stub.c -module_native_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) -module_native_protocol_tcp6_la_LDFLAGS = -module -avoid-version -module_native_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la - module_native_protocol_unix_la_SOURCES = modules/module-protocol-stub.c module_native_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) module_native_protocol_unix_la_LDFLAGS = -module -avoid-version @@ -921,11 +891,6 @@ module_esound_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_ESOUND $ module_esound_protocol_tcp_la_LDFLAGS = -module -avoid-version module_esound_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-esound.la libsocket-server.la -module_esound_protocol_tcp6_la_SOURCES = modules/module-protocol-stub.c -module_esound_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) -module_esound_protocol_tcp6_la_LDFLAGS = -module -avoid-version -module_esound_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-esound.la libsocket-server.la - module_esound_protocol_unix_la_SOURCES = modules/module-protocol-stub.c module_esound_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) module_esound_protocol_unix_la_LDFLAGS = -module -avoid-version diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index b69716cc..f72a68a5 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -53,9 +53,6 @@ #ifdef USE_TCP_SOCKETS #define SOCKET_DESCRIPTION "(TCP sockets)" #define SOCKET_USAGE "port= loopback=" -#elif defined(USE_TCP6_SOCKETS) -#define SOCKET_DESCRIPTION "(TCP/IPv6 sockets)" -#define SOCKET_USAGE "port= loopback=" #else #define SOCKET_DESCRIPTION "(UNIX sockets)" #define SOCKET_USAGE "socket=" @@ -71,8 +68,6 @@ #define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record", #if defined(USE_TCP_SOCKETS) #include "module-simple-protocol-tcp-symdef.h" - #elif defined(USE_TCP6_SOCKETS) - #include "module-simple-protocol-tcp6-symdef.h" #else #include "module-simple-protocol-unix-symdef.h" #endif @@ -88,8 +83,6 @@ #define MODULE_ARGUMENTS #ifdef USE_TCP_SOCKETS #include "module-cli-protocol-tcp-symdef.h" - #elif defined(USE_TCP6_SOCKETS) - #include "module-cli-protocol-tcp6-symdef.h" #else #include "module-cli-protocol-unix-symdef.h" #endif @@ -105,8 +98,6 @@ #define MODULE_ARGUMENTS #ifdef USE_TCP_SOCKETS #include "module-http-protocol-tcp-symdef.h" - #elif defined(USE_TCP6_SOCKETS) - #include "module-http-protocol-tcp6-symdef.h" #else #include "module-http-protocol-unix-symdef.h" #endif @@ -122,8 +113,6 @@ #define MODULE_ARGUMENTS "public", "cookie", #ifdef USE_TCP_SOCKETS #include "module-native-protocol-tcp-symdef.h" - #elif defined(USE_TCP6_SOCKETS) - #include "module-native-protocol-tcp6-symdef.h" #else #include "module-native-protocol-unix-symdef.h" #endif @@ -140,8 +129,6 @@ #define MODULE_ARGUMENTS "sink", "source", "public", "cookie", #ifdef USE_TCP_SOCKETS #include "module-esound-protocol-tcp-symdef.h" - #elif defined(USE_TCP6_SOCKETS) - #include "module-esound-protocol-tcp6-symdef.h" #else #include "module-esound-protocol-unix-symdef.h" #endif @@ -156,7 +143,7 @@ PA_MODULE_VERSION(PACKAGE_VERSION) static const char* const valid_modargs[] = { MODULE_ARGUMENTS -#if defined(USE_TCP_SOCKETS) || defined(USE_TCP6_SOCKETS) +#if defined(USE_TCP_SOCKETS) "port", "loopback", #else @@ -167,7 +154,7 @@ static const char* const valid_modargs[] = { static pa_socket_server *create_socket_server(pa_core *c, pa_modargs *ma) { pa_socket_server *s; -#if defined(USE_TCP_SOCKETS) || defined(USE_TCP6_SOCKETS) +#if defined(USE_TCP_SOCKETS) int loopback = 1; uint32_t port = IPV4_PORT; @@ -181,13 +168,14 @@ static pa_socket_server *create_socket_server(pa_core *c, pa_modargs *ma) { return NULL; } -#ifdef USE_TCP6_SOCKETS - if (!(s = pa_socket_server_new_ipv6(c->mainloop, loopback ? (const uint8_t*) &in6addr_loopback : (const uint8_t*) &in6addr_any, port))) - return NULL; -#else - if (!(s = pa_socket_server_new_ipv4(c->mainloop, loopback ? INADDR_LOOPBACK : INADDR_ANY, port, TCPWRAP_SERVICE))) - return NULL; -#endif + + if (loopback) { + if (!(s = pa_socket_server_new_ip_loopback(c->mainloop, port, TCPWRAP_SERVICE))) + return NULL; + } else { + if (!(s = pa_socket_server_new_ip_any(c->mainloop, port, TCPWRAP_SERVICE))) + return NULL; + } #else int r; @@ -250,10 +238,10 @@ finish: void pa__done(pa_core *c, pa_module*m) { assert(c && m); -#if defined(USE_PROTOCOL_ESOUND) - if (remove (ESD_UNIX_SOCKET_NAME) != 0) +#if defined(USE_PROTOCOL_ESOUND) && !defined(USE_TCP_SOCKETS) + if (remove(ESD_UNIX_SOCKET_NAME) != 0) pa_log("%s: Failed to remove %s : %s.\n", __FILE__, ESD_UNIX_SOCKET_NAME, strerror (errno)); - if (remove (ESD_UNIX_SOCKET_DIR) != 0) + if (remove(ESD_UNIX_SOCKET_DIR) != 0) pa_log("%s: Failed to remove %s : %s.\n", __FILE__, ESD_UNIX_SOCKET_DIR, strerror (errno)); #endif diff --git a/src/polypcore/socket-server.c b/src/polypcore/socket-server.c index d1646984..5f84911d 100644 --- a/src/polypcore/socket-server.c +++ b/src/polypcore/socket-server.c @@ -101,18 +101,18 @@ static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_U #ifdef HAVE_LIBWRAP - if (s->type == SOCKET_SERVER_IPV4 && s->tcpwrap_service) { + if (s->tcpwrap_service) { struct request_info req; request_init(&req, RQ_DAEMON, s->tcpwrap_service, RQ_FILE, nfd, NULL); fromhost(&req); if (!hosts_access(&req)) { - pa_log(__FILE__": TCP connection refused by tcpwrap.\n"); + pa_log_warn(__FILE__": TCP connection refused by tcpwrap.\n"); close(nfd); goto finish; } - pa_log(__FILE__": TCP connection accepted by tcpwrap.\n"); + pa_log_info(__FILE__": TCP connection accepted by tcpwrap.\n"); } #endif @@ -221,7 +221,7 @@ pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address assert(m && port); if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s\n", strerror(errno)); + pa_log(__FILE__": socket(PF_INET): %s\n", strerror(errno)); goto fail; } @@ -261,7 +261,7 @@ fail: return NULL; } -pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port) { +pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port, const char *tcpwrap_service) { pa_socket_server *ss; int fd = -1; struct sockaddr_in6 sa; @@ -270,7 +270,7 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad assert(m && port); if ((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s\n", strerror(errno)); + pa_log(__FILE__": socket(PF_INET6): %s\n", strerror(errno)); goto fail; } @@ -296,9 +296,11 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad goto fail; } - if ((ss = pa_socket_server_new(m, fd))) + if ((ss = pa_socket_server_new(m, fd))) { ss->type = SOCKET_SERVER_IPV6; - + ss->tcpwrap_service = pa_xstrdup(tcpwrap_service); + } + return ss; fail: @@ -308,6 +310,31 @@ fail: return NULL; } +pa_socket_server* pa_socket_server_new_ip_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { + pa_socket_server *s; + + assert(m); + assert(port > 0); + + if (!(s = pa_socket_server_new_ipv6(m, in6addr_loopback.s6_addr, port, tcpwrap_service))) + s = pa_socket_server_new_ipv4(m, INADDR_LOOPBACK, port, tcpwrap_service); + + return s; +} + +pa_socket_server* pa_socket_server_new_ip_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { + pa_socket_server *s; + + assert(m); + assert(port > 0); + + if (!(s = pa_socket_server_new_ipv6(m, in6addr_any.s6_addr, port, tcpwrap_service))) + s = pa_socket_server_new_ipv4(m, INADDR_ANY, port, tcpwrap_service); + + return s; +} + + static void socket_server_free(pa_socket_server*s) { assert(s); close(s->fd); diff --git a/src/polypcore/socket-server.h b/src/polypcore/socket-server.h index 6bb83427..d11cee49 100644 --- a/src/polypcore/socket-server.h +++ b/src/polypcore/socket-server.h @@ -33,7 +33,9 @@ typedef struct pa_socket_server pa_socket_server; pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd); pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename); pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service); -pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port); +pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ip_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ip_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); void pa_socket_server_unref(pa_socket_server*s); pa_socket_server* pa_socket_server_ref(pa_socket_server *s); -- cgit From 36c8861db6b8188b844d97b0910d32051f2530d9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Feb 2006 01:09:22 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@549 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index 2e0ad893..2c7f28b2 100644 --- a/doc/todo +++ b/doc/todo @@ -10,7 +10,6 @@ Fixes: - module-tunnel: improve latency calculation - make alsa modules use mmap - better validity checking in protocol-{native,esound} -- don't build ipv4 and ipv6 modules seperately - change pa_log to not require \n - proper use of memcpy in procotol-esound.c so we don't get alignment problems -- cgit From a10257d680d178d493ccae7a2f273ee6987c2dae Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Feb 2006 01:22:42 +0000 Subject: fix pacat git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@550 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pacat.c | 64 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 6efc3a47..43e67144 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -80,7 +80,12 @@ static void do_stream_write(size_t length) { if (l > buffer_length) l = buffer_length; - pa_stream_write(stream, (uint8_t*) buffer + buffer_index, l, NULL, 0, PA_SEEK_RELATIVE); + if (pa_stream_write(stream, (uint8_t*) buffer + buffer_index, l, NULL, 0, PA_SEEK_RELATIVE) < 0) { + fprintf(stderr, "pa_stream_write() failed: %s\n", pa_strerror(pa_context_errno(context))); + quit(1); + return; + } + buffer_length -= l; buffer_index += l; @@ -112,12 +117,20 @@ static void stream_read_callback(pa_stream *s, size_t length, void *userdata) { if (stdio_event) mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT); - pa_stream_peek(s, &data, &length); + if (pa_stream_peek(s, &data, &length) < 0) { + fprintf(stderr, "pa_stream_peek() failed: %s\n", pa_strerror(pa_context_errno(context))); + quit(1); + return; + } + assert(data && length); if (buffer) { fprintf(stderr, "Buffer overrun, dropping incoming data\n"); - pa_stream_drop(s); + if (pa_stream_drop(s) < 0) { + fprintf(stderr, "pa_stream_drop() failed: %s\n", pa_strerror(pa_context_errno(context))); + quit(1); + } return; } @@ -159,15 +172,18 @@ static void context_state_callback(pa_context *c, void *userdata) { case PA_CONTEXT_SETTING_NAME: break; - case PA_CONTEXT_READY: + case PA_CONTEXT_READY: { + int r; assert(c && !stream); if (verbose) fprintf(stderr, "Connection established.\n"); - stream = pa_stream_new(c, stream_name, &sample_spec, NULL); - assert(stream); + if (!(stream = pa_stream_new(c, stream_name, &sample_spec, NULL))) { + fprintf(stderr, "pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(c))); + goto fail; + } pa_stream_set_state_callback(stream, stream_state_callback, NULL); pa_stream_set_write_callback(stream, stream_write_callback, NULL); @@ -175,11 +191,20 @@ static void context_state_callback(pa_context *c, void *userdata) { if (mode == PLAYBACK) { pa_cvolume cv; - pa_stream_connect_playback(stream, device, NULL, 0, pa_cvolume_set(&cv, PA_CHANNELS_MAX, volume), NULL); - } else - pa_stream_connect_record(stream, device, NULL, 0); + if ((r = pa_stream_connect_playback(stream, device, NULL, 0, pa_cvolume_set(&cv, sample_spec.channels, volume), NULL)) < 0) { + fprintf(stderr, "pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(c))); + goto fail; + } + + } else { + if ((r = pa_stream_connect_record(stream, device, NULL, 0)) < 0) { + fprintf(stderr, "pa_stream_connect_record() failed: %s\n", pa_strerror(pa_context_errno(c))); + goto fail; + } + } break; + } case PA_CONTEXT_TERMINATED: quit(0); @@ -188,8 +213,14 @@ static void context_state_callback(pa_context *c, void *userdata) { case PA_CONTEXT_FAILED: default: fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c))); - quit(1); + goto fail; } + + return; + +fail: + quit(1); + } /* Connection draining complete */ @@ -216,8 +247,6 @@ static void stream_drain_complete(pa_stream*s, int success, void *userdata) { if (!(o = pa_context_drain(context, context_drain_complete, NULL))) pa_context_disconnect(context); else { - pa_operation_unref(o); - if (verbose) fprintf(stderr, "Draining connection to server.\n"); } @@ -241,9 +270,18 @@ static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_even assert(buffer); if ((r = read(fd, buffer, l)) <= 0) { if (r == 0) { + pa_operation *o; + if (verbose) fprintf(stderr, "Got EOF.\n"); - pa_operation_unref(pa_stream_drain(stream, stream_drain_complete, NULL)); + + if (!(o = pa_stream_drain(stream, stream_drain_complete, NULL))) { + fprintf(stderr, "pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(context))); + quit(1); + return; + } + + pa_operation_unref(o); } else { fprintf(stderr, "read() failed: %s\n", strerror(errno)); quit(1); -- cgit From 7e5123705a4811d168890e35cff2354922777c71 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 21 Feb 2006 16:35:12 +0000 Subject: Hardware volume support on Windows. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@551 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-waveout.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index 3a8600c7..2176e6e7 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -48,6 +48,8 @@ PA_MODULE_USAGE("sink_name= source_name= #define DEFAULT_SINK_NAME "wave_output" #define DEFAULT_SOURCE_NAME "wave_input" +#define WAVEOUT_MAX_VOLUME 0xFFFF + struct userdata { pa_sink *sink; pa_source *source; @@ -336,6 +338,42 @@ static void notify_source_cb(pa_source *s) { u->core->mainloop->defer_enable(u->defer, 1); } +static int sink_get_hw_volume_cb(pa_sink *s) { + struct userdata *u = s->userdata; + DWORD vol; + pa_volume_t left, right; + + if (waveOutGetVolume(u->hwo, &vol) != MMSYSERR_NOERROR) + return -1; + + left = (vol & 0xFFFF) * PA_VOLUME_NORM / WAVEOUT_MAX_VOLUME; + right = ((vol >> 16) & 0xFFFF) * PA_VOLUME_NORM / WAVEOUT_MAX_VOLUME; + + /* Windows supports > 2 channels, except for volume control */ + if (s->hw_volume.channels > 2) + pa_cvolume_set(&s->hw_volume, s->hw_volume.channels, (left + right)/2); + + s->hw_volume.values[0] = left; + if (s->hw_volume.channels > 1) + s->hw_volume.values[1] = right; + + return 0; +} + +static int sink_set_hw_volume_cb(pa_sink *s) { + struct userdata *u = s->userdata; + DWORD vol; + + vol = s->hw_volume.values[0] * WAVEOUT_MAX_VOLUME / PA_VOLUME_NORM; + if (s->hw_volume.channels > 1) + vol |= (s->hw_volume.values[0] * WAVEOUT_MAX_VOLUME / PA_VOLUME_NORM) << 16; + + if (waveOutSetVolume(u->hwo, vol) != MMSYSERR_NOERROR) + return -1; + + return 0; +} + static int ss_to_waveformat(pa_sample_spec *ss, LPWAVEFORMATEX wf) { wf->wFormatTag = WAVE_FORMAT_PCM; @@ -455,6 +493,8 @@ int pa__init(pa_core *c, pa_module*m) { assert(u->sink); u->sink->notify = notify_sink_cb; u->sink->get_latency = sink_get_latency_cb; + u->sink->get_hw_volume = sink_get_hw_volume_cb; + u->sink->set_hw_volume = sink_set_hw_volume_cb; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); u->sink->description = pa_sprintf_malloc("Windows waveOut PCM"); -- cgit From 48b2e1ab966c14d9fc08fbadf7bcf0980de47523 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 21 Feb 2006 16:35:53 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@552 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/todo b/doc/todo index 2c7f28b2..63da73ce 100644 --- a/doc/todo +++ b/doc/todo @@ -21,7 +21,7 @@ Features: - add support for auth using SCM_CREDENTIALS - include hw description in sink/source info - use scatter/gather io for sockets -- hw volume support for alsa, windows +- hw volume support for alsa - notifcation on hw volume change - source volume control - deal with underflows reported by OSS/ALSA properly -- cgit From 9d3dcefad1d052ce9cf7a7c769d008b72dad5879 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Feb 2006 20:28:41 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@553 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/todo b/doc/todo index 63da73ce..e23233e6 100644 --- a/doc/todo +++ b/doc/todo @@ -26,6 +26,7 @@ Features: - source volume control - deal with underflows reported by OSS/ALSA properly - mute switch support (like ALSA does it) +- add listen-on paramater to protocol modules Long term: - pass meta info for hearing impaired -- cgit From 13b421327483e6f97e5c6541815195f13778dbf2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Feb 2006 23:34:22 +0000 Subject: remove left-over log line in protocol-esound.c git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@554 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-esound.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index 4a5dd773..8a0a3356 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -186,7 +186,6 @@ static void connection_free(struct connection *c) { if (c->sink_input) { pa_sink_input_disconnect(c->sink_input); - pa_log("disconnect\n"); pa_sink_input_unref(c->sink_input); } -- cgit From 6169bd81aa405a4ef2632b6ceb26a7225118f7d9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Feb 2006 23:34:50 +0000 Subject: add new utility function pa_endswith() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@555 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/util.c | 18 +++++++++++++++++- src/polypcore/util.h | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/polypcore/util.c b/src/polypcore/util.c index a53c36bc..2ae94d25 100644 --- a/src/polypcore/util.c +++ b/src/polypcore/util.c @@ -1092,12 +1092,28 @@ char *pa_get_fqdn(char *s, size_t l) { /* Returns nonzero when *s starts with *pfx */ int pa_startswith(const char *s, const char *pfx) { size_t l; - assert(s && pfx); + + assert(s); + assert(pfx); + l = strlen(pfx); return strlen(s) >= l && strncmp(s, pfx, l) == 0; } +/* Returns nonzero when *s ends with *sfx */ +int pa_endswith(const char *s, const char *sfx) { + size_t l1, l2; + + assert(s); + assert(sfx); + + l1 = strlen(s); + l2 = strlen(sfx); + + return l1 >= l2 && strcmp(s+l1-l2, sfx) == 0; +} + /* if fn is null return the polypaudio run time path in s (/tmp/polypaudio) * if fn is non-null and starts with / return fn in s * otherwise append fn to the run time path and return it in s */ diff --git a/src/polypcore/util.h b/src/polypcore/util.h index 14f763a3..af4e14c8 100644 --- a/src/polypcore/util.h +++ b/src/polypcore/util.h @@ -88,6 +88,7 @@ char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength); size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength); int pa_startswith(const char *s, const char *pfx); +int pa_endswith(const char *s, const char *sfx); char *pa_runtime_path(const char *fn, char *s, size_t l); -- cgit From 5014db91d55ce1b4f6b3691f6fd75078da588a40 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Feb 2006 23:40:07 +0000 Subject: include hw description gathered from /dev/sndstat in sink/source description string git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@556 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 22 ++++++++++++--- src/modules/oss-util.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ src/modules/oss-util.h | 2 ++ 3 files changed, 90 insertions(+), 3 deletions(-) diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 34743a1d..0a3c6143 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -287,7 +287,10 @@ int pa__init(pa_core *c, pa_module*m) { int record = 1, playback = 1; pa_sample_spec ss; pa_modargs *ma = NULL; - assert(c && m); + char hwdesc[64]; + + assert(c); + assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": failed to parse module arguments.\n"); @@ -322,6 +325,11 @@ int pa__init(pa_core *c, pa_module*m) { if ((fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, NULL)) < 0) goto fail; + if (pa_oss_get_hw_description(p, hwdesc, sizeof(hwdesc)) >= 0) + pa_log_info(__FILE__": hardware name is '%s'.\n", hwdesc); + else + hwdesc[0] = 0; + pa_log_info(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); if (nfrags >= 2 && frag_size >= 1) @@ -361,7 +369,11 @@ int pa__init(pa_core *c, pa_module*m) { u->source->notify = source_notify_cb; u->source->get_latency = source_get_latency_cb; pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); + u->source->description = pa_sprintf_malloc("Open Sound System PCM on '%s'%s%s%s", + p, + hwdesc[0] ? " (" : "", + hwdesc[0] ? hwdesc : "", + hwdesc[0] ? ")" : ""); } else u->source = NULL; @@ -373,7 +385,11 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->set_hw_volume = sink_set_hw_volume; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); + u->sink->description = pa_sprintf_malloc("Open Sound System PCM on '%s'%s%s%s", + p, + hwdesc[0] ? " (" : "", + hwdesc[0] ? hwdesc : "", + hwdesc[0] ? ")" : ""); } else u->sink = NULL; diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index 597d16d7..9fb5d38a 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -202,3 +202,72 @@ int pa_oss_set_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume pa_log_debug(__FILE__": Wrote mixer settings: %s\n", pa_cvolume_snprint(cv, sizeof(cv), volume)); return 0; } + +int pa_oss_get_hw_description(const char *dev, char *name, size_t l) { + FILE *f; + const char *e = NULL; + int n, r = -1; + int b = 0; + + if (strncmp(dev, "/dev/dsp", 8) == 0) + e = dev+8; + else if (strncmp(dev, "/dev/adsp", 9) == 0) + e = dev+9; + else + return -1; + + if (*e == 0) + n = 0; + else if (*e >= '0' && *e <= '9' && *(e+1) == 0) + n = *e - '0'; + else + return -1; + + if (!(f = fopen("/dev/sndstat", "r")) && + !(f = fopen("/proc/sndstat", "r")) && + !(f = fopen("/proc/asound/oss/sndstat", "r"))) { + + if (errno != ENOENT) + pa_log_warn(__FILE__": failed to open OSS sndstat device: %s\n", strerror(errno)); + + return -1; + } + + while (!feof(f)) { + char line[64]; + int device; + + if (!fgets(line, sizeof(line), f)) + break; + + line[strcspn(line, "\r\n")] = 0; + + if (!b) { + b = strcmp(line, "Audio devices:") == 0; + continue; + } + + if (line[0] == 0) + break; + + if (sscanf(line, "%i: ", &device) != 1) + continue; + + if (device == n) { + char *k = strchr(line, ':'); + assert(k); + k++; + k += strspn(k, " "); + + if (pa_endswith(k, " (DUPLEX)")) + k[strlen(k)-9] = 0; + + pa_strlcpy(name, k, l); + r = 0; + break; + } + } + + fclose(f); + return r; +} diff --git a/src/modules/oss-util.h b/src/modules/oss-util.h index d8c36c56..3033c76f 100644 --- a/src/modules/oss-util.h +++ b/src/modules/oss-util.h @@ -33,4 +33,6 @@ int pa_oss_set_fragments(int fd, int frags, int frag_size); int pa_oss_get_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume); int pa_oss_set_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume); +int pa_oss_get_hw_description(const char *dev, char *name, size_t l); + #endif -- cgit From 8d882644be745509ee4cc1d02c8c524977195ebf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Feb 2006 23:56:46 +0000 Subject: add hw info to description for oss-mmap, too git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@557 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss-mmap.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index 617e51e2..82f65a3c 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -254,7 +254,10 @@ int pa__init(pa_core *c, pa_module*m) { int enable_bits = 0, zero = 0; int playback = 1, record = 1; pa_modargs *ma = NULL; - assert(c && m); + char hwdesc[64]; + + assert(c); + assert(m); m->userdata = u = pa_xmalloc0(sizeof(struct userdata)); u->module = m; @@ -294,6 +297,11 @@ int pa__init(pa_core *c, pa_module*m) { if ((u->fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0) goto fail; + if (pa_oss_get_hw_description(p, hwdesc, sizeof(hwdesc)) >= 0) + pa_log_info(__FILE__": hardware name is '%s'.\n", hwdesc); + else + hwdesc[0] = 0; + if (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_REALTIME) || !(caps & DSP_CAP_TRIGGER)) { pa_log(__FILE__": OSS device not mmap capable.\n"); goto fail; @@ -331,7 +339,11 @@ int pa__init(pa_core *c, pa_module*m) { assert(u->source); u->source->userdata = u; pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'", p); + u->source->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'%s%s%s", + p, + hwdesc[0] ? " (" : "", + hwdesc[0] ? hwdesc : "", + hwdesc[0] ? ")" : ""); u->in_memblocks = pa_xmalloc0(sizeof(pa_memblock *)*u->in_fragments); @@ -366,7 +378,11 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->set_hw_volume = sink_set_hw_volume; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'", p); + u->sink->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'%s%s%s", + p, + hwdesc[0] ? " (" : "", + hwdesc[0] ? hwdesc : "", + hwdesc[0] ? ")" : ""); u->out_memblocks = pa_xmalloc0(sizeof(struct memblock *)*u->out_fragments); -- cgit From bf013f89104c1a0d5561ce89185c6acbe0a3a72e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Feb 2006 00:06:16 +0000 Subject: todo update - outline what i consider pre-0.8 and post-0.8 issues git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@558 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 44 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/doc/todo b/doc/todo index e23233e6..feac0c75 100644 --- a/doc/todo +++ b/doc/todo @@ -2,31 +2,36 @@ Test: - module-combine -- latency foo +- module-tunnel - howl Fixes: -- improve module-oss-mmap latency measurement -- module-tunnel: improve latency calculation -- make alsa modules use mmap - better validity checking in protocol-{native,esound} - change pa_log to not require \n - proper use of memcpy in procotol-esound.c so we don't get alignment problems - -Features: -- add radio module -- dbus/hal -- polish for starting polypaudio as root/system-wide instance -- add threading API +- latency api for native protocol - add support for auth using SCM_CREDENTIALS -- include hw description in sink/source info - use scatter/gather io for sockets -- hw volume support for alsa -- notifcation on hw volume change +- notification on hw volume change - source volume control -- deal with underflows reported by OSS/ALSA properly - mute switch support (like ALSA does it) - add listen-on paramater to protocol modules +- module-oss-* love: + - deal with underflows propely + - improve latency measurement for mmap +- module-alsa-* love: + - volume control + - add hw driver name to sink/source description + - deal with underflows properly + +Post 0.8: +- alsa mmap driver +- add radio module +- dbus/hal +- polish for starting polypaudio as root/system-wide instance +- chroot() +- add threading API +- module-tunnel: improve latency calculation Long term: - pass meta info for hearing impaired @@ -36,14 +41,3 @@ Backends for: - portaudio (semi-done) - sdl - OSS (esddsp style) - ------------------- - -Done: -- per-channel volume -- channel mapping ("left", "right", "rear", "subwoofer") -- hardware volume support -- alsa-lib -- remove "polyplib-" prefix -- add API for synchronizing multiple sinks/sources to a common clock -- absolutely indexed write()s from client -- cgit From 6cd225010f3b740a7db95f4ca7dd051501fb55dc Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 22 Feb 2006 09:39:33 +0000 Subject: Remove polyplib-error and polyplib-mainloop for requirements. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@559 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyplib.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polyplib.pc.in b/polyplib.pc.in index c79d98d4..f495def2 100644 --- a/polyplib.pc.in +++ b/polyplib.pc.in @@ -8,4 +8,4 @@ Description: Client interface to polypaudio Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lpolyp-@PA_MAJORMINOR@ Cflags: -D_REENTRANT -I${includedir} -Requires: polyplib-error polyplib-mainloop +Requires: -- cgit From cc2178e5c39f0c2da2d4d5dff14210d5934bcc32 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 22 Feb 2006 14:11:23 +0000 Subject: Support for setting volume on sources. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@560 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 1 + src/polyp/introspect.c | 55 +++++++++++++++++++++++++++++++++++++++++ src/polyp/introspect.h | 7 ++++++ src/polypcore/cli-command.c | 54 +++++++++++++++++++++++++++++++++++++--- src/polypcore/core-def.h | 30 ++++++++++++++++++++++ src/polypcore/native-common.h | 2 ++ src/polypcore/pdispatch.c | 1 + src/polypcore/protocol-native.c | 36 ++++++++++++++++++--------- src/polypcore/sink.h | 6 +---- src/polypcore/source.c | 51 ++++++++++++++++++++++++++++++++++++++ src/polypcore/source.h | 9 +++++++ 11 files changed, 232 insertions(+), 20 deletions(-) create mode 100644 src/polypcore/core-def.h diff --git a/src/Makefile.am b/src/Makefile.am index 410fd702..f36630e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -425,6 +425,7 @@ polypcoreinclude_HEADERS = \ polypcore/cli-text.h \ polypcore/client.h \ polypcore/core.h \ + polypcore/core-def.h \ polypcore/core-scache.h \ polypcore/core-subscribe.h \ polypcore/conf-parser.h \ diff --git a/src/polyp/introspect.c b/src/polyp/introspect.c index 043d2076..4fa23841 100644 --- a/src/polyp/introspect.c +++ b/src/polyp/introspect.c @@ -252,6 +252,7 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_get_cvolume(t, &i.volume) < 0 || pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 || pa_tagstruct_get_usec(t, &i.latency) < 0 || @@ -727,6 +728,60 @@ pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, cons return o; } +pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(volume); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SOURCE_VOLUME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_tagstruct_put_cvolume(t, volume); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + + return o; +} + +pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(name); + assert(volume); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SOURCE_VOLUME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_tagstruct_put_cvolume(t, volume); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + + return o; +} + /** Sample Cache **/ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { diff --git a/src/polyp/introspect.h b/src/polyp/introspect.h index d4ff65fb..d7fad9c4 100644 --- a/src/polyp/introspect.h +++ b/src/polyp/introspect.h @@ -84,6 +84,7 @@ typedef struct pa_source_info { pa_sample_spec sample_spec; /**< Sample spec of this source */ pa_channel_map channel_map; /**< Channel map \since 0.9 */ uint32_t owner_module; /**< Owning module index, or PA_INVALID_INDEX */ + pa_cvolume volume; /**< Volume of the source \since 0.8 */ uint32_t monitor_of_sink; /**< If this is a monitor source the index of the owning sink, otherwise PA_INVALID_INDEX */ const char *monitor_of_sink_name; /**< Name of the owning sink, or PA_INVALID_INDEX */ pa_usec_t latency; /**< Length of filled record buffer of this source. \since 0.5 */ @@ -213,6 +214,12 @@ pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name /** Set the volume of a sink input stream */ pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); +/** Set the volume of a source device specified by its index \since 0.8 */ +pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); + +/** Set the volume of a source device specified by its name \since 0.8 */ +pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); + /** Memory block statistics */ typedef struct pa_stat_info { uint32_t memblock_total; /**< Currently allocated memory blocks */ diff --git a/src/polypcore/cli-command.c b/src/polypcore/cli-command.c index 6c9fc4b1..cd7993a8 100644 --- a/src/polypcore/cli-command.c +++ b/src/polypcore/cli-command.c @@ -77,6 +77,7 @@ static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); @@ -114,6 +115,7 @@ static const struct command commands[] = { { "unload-module", pa_cli_command_unload, "Unload a module (args: index)", 2}, { "set-sink-volume", pa_cli_command_sink_volume, "Set the volume of a sink (args: index|name, volume)", 3}, { "set-sink-input-volume", pa_cli_command_sink_input_volume, "Set the volume of a sink input (args: index|name, volume)", 3}, + { "set-source-volume", pa_cli_command_source_volume, "Set the volume of a source (args: index|name, volume)", 3}, { "set-default-sink", pa_cli_command_sink_default, "Set the default sink (args: index|name)", 2}, { "set-default-source", 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}, @@ -376,6 +378,37 @@ static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strb return 0; } +static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n, *v; + pa_source *source; + uint32_t volume; + pa_cvolume cvolume; + + 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 (!(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; + } + + if (pa_atou(v, &volume) < 0) { + pa_strbuf_puts(buf, "Failed to parse volume.\n"); + return -1; + } + + if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE, 1))) { + pa_strbuf_puts(buf, "No source found by this name or index.\n"); + return -1; + } + + pa_cvolume_set(&cvolume, source->sample_spec.channels, volume); + pa_source_set_volume(source, PA_MIXER_HARDWARE, &cvolume); + return 0; +} + static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { const char *n; assert(c && t); @@ -633,7 +666,8 @@ static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { pa_module *m; - pa_sink *s; + pa_sink *sink; + pa_source *source; int nl; const char *p; uint32_t idx; @@ -667,8 +701,20 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G nl = 0; - for (s = pa_idxset_first(c->sinks, &idx); s; s = pa_idxset_next(c->sinks, &idx)) { - if (s->owner && s->owner->auto_unload) + for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) { + if (sink->owner && sink->owner->auto_unload) + continue; + + if (!nl) { + pa_strbuf_puts(buf, "\n"); + nl = 1; + } + + pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, PA_MIXER_HARDWARE))); + } + + for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) { + if (source->owner && source->owner->auto_unload) continue; if (!nl) { @@ -676,7 +722,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G nl = 1; } - pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", s->name, pa_cvolume_avg(pa_sink_get_volume(s, PA_MIXER_HARDWARE))); + pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_avg(pa_source_get_volume(source, PA_MIXER_HARDWARE))); } diff --git a/src/polypcore/core-def.h b/src/polypcore/core-def.h new file mode 100644 index 00000000..89cc47f1 --- /dev/null +++ b/src/polypcore/core-def.h @@ -0,0 +1,30 @@ +#ifndef foocoredefhfoo +#define foocoredefhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef enum pa_mixer { + PA_MIXER_SOFTWARE, + PA_MIXER_HARDWARE +} pa_mixer_t; + +#endif diff --git a/src/polypcore/native-common.h b/src/polypcore/native-common.h index 0d17b022..a5ca5c96 100644 --- a/src/polypcore/native-common.h +++ b/src/polypcore/native-common.h @@ -71,6 +71,8 @@ enum { PA_COMMAND_SET_SINK_VOLUME, PA_COMMAND_SET_SINK_INPUT_VOLUME, + PA_COMMAND_SET_SOURCE_VOLUME, + PA_COMMAND_CORK_PLAYBACK_STREAM, PA_COMMAND_FLUSH_PLAYBACK_STREAM, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, diff --git a/src/polypcore/pdispatch.c b/src/polypcore/pdispatch.c index c082b8cc..2cc90bc2 100644 --- a/src/polypcore/pdispatch.c +++ b/src/polypcore/pdispatch.c @@ -82,6 +82,7 @@ static const char *command_names[PA_COMMAND_MAX] = { [PA_COMMAND_SUBSCRIBE_EVENT] = "SUBSCRIBE_EVENT", [PA_COMMAND_SET_SINK_VOLUME] = "SET_SINK_VOLUME", [PA_COMMAND_SET_SINK_INPUT_VOLUME] = "SET_SINK_INPUT_VOLUME", + [PA_COMMAND_SET_SOURCE_VOLUME] = "SET_SOURCE_VOLME", [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = "TRIGGER_PLAYBACK_STREAM", [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = "FLUSH_PLAYBACK_STREAM", [PA_COMMAND_CORK_PLAYBACK_STREAM] = "CORK_PLAYBACK_STREAM", diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index e73ff761..cd1a685f 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -216,6 +216,7 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume, [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume, + [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume, [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream, [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_flush_playback_stream, @@ -1254,16 +1255,20 @@ static void sink_fill_tagstruct(pa_tagstruct *t, pa_sink *sink) { static void source_fill_tagstruct(pa_tagstruct *t, pa_source *source) { assert(t && source); - pa_tagstruct_putu32(t, source->index); - pa_tagstruct_puts(t, source->name); - pa_tagstruct_puts(t, source->description); - pa_tagstruct_put_sample_spec(t, &source->sample_spec); - pa_tagstruct_put_channel_map(t, &source->channel_map); - pa_tagstruct_putu32(t, source->owner ? source->owner->index : (uint32_t) -1); - pa_tagstruct_putu32(t, source->monitor_of ? source->monitor_of->index : (uint32_t) -1); - pa_tagstruct_puts(t, source->monitor_of ? source->monitor_of->name : NULL); - pa_tagstruct_put_usec(t, pa_source_get_latency(source)); - pa_tagstruct_puts(t, source->driver); + pa_tagstruct_put( + t, + PA_TAG_U32, source->index, + PA_TAG_STRING, source->name, + PA_TAG_STRING, source->description, + PA_TAG_SAMPLE_SPEC, &source->sample_spec, + PA_TAG_CHANNEL_MAP, &source->channel_map, + PA_TAG_U32, source->owner ? source->owner->index : PA_INVALID_INDEX, + PA_TAG_CVOLUME, pa_source_get_volume(source, PA_MIXER_HARDWARE), + PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX, + PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL, + PA_TAG_USEC, pa_source_get_latency(source), + PA_TAG_STRING, source->driver, + PA_TAG_INVALID); } static void client_fill_tagstruct(pa_tagstruct *t, pa_client *client) { @@ -1558,12 +1563,14 @@ static void command_set_volume(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t idx; pa_cvolume volume; pa_sink *sink = NULL; + pa_source *source = NULL; pa_sink_input *si = NULL; const char *name = NULL; assert(c && t); if (pa_tagstruct_getu32(t, &idx) < 0 || (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) || + (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) || pa_tagstruct_get_cvolume(t, &volume) || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1580,18 +1587,25 @@ static void command_set_volume(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); else sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); + } else if (command == PA_COMMAND_SET_SOURCE_VOLUME) { + if (idx != (uint32_t) -1) + source = pa_idxset_get_by_index(c->protocol->core->sources, idx); + else + source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); } else { assert(command == PA_COMMAND_SET_SINK_INPUT_VOLUME); si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); } - if (!si && !sink) { + if (!si && !sink && !source) { pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } if (sink) pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &volume); + else if (source) + pa_source_set_volume(source, PA_MIXER_HARDWARE, &volume); else if (si) pa_sink_input_set_volume(si, &volume); diff --git a/src/polypcore/sink.h b/src/polypcore/sink.h index fa120ebf..5f1a6cc8 100644 --- a/src/polypcore/sink.h +++ b/src/polypcore/sink.h @@ -29,6 +29,7 @@ typedef struct pa_sink pa_sink; #include #include #include +#include #include #include #include @@ -41,11 +42,6 @@ typedef enum pa_sink_state { PA_SINK_DISCONNECTED } pa_sink_state_t; -typedef enum pa_mixer { - PA_MIXER_SOFTWARE, - PA_MIXER_HARDWARE -} pa_mixer_t; - struct pa_sink { int ref; uint32_t index; diff --git a/src/polypcore/source.c b/src/polypcore/source.c index b70cb129..47325a1b 100644 --- a/src/polypcore/source.c +++ b/src/polypcore/source.c @@ -77,8 +77,13 @@ pa_source* pa_source_new( s->outputs = pa_idxset_new(NULL, NULL); s->monitor_of = NULL; + pa_cvolume_reset(&s->sw_volume, spec->channels); + pa_cvolume_reset(&s->hw_volume, spec->channels); + s->get_latency = NULL; s->notify = NULL; + s->set_hw_volume = NULL; + s->get_hw_volume = NULL; s->userdata = NULL; r = pa_idxset_put(core->sources, s, &s->index); @@ -110,6 +115,8 @@ void pa_source_disconnect(pa_source *s) { s->get_latency = NULL; s->notify = NULL; + s->get_hw_volume = NULL; + s->set_hw_volume = NULL; s->state = PA_SOURCE_DISCONNECTED; pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); @@ -173,7 +180,14 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) { assert(chunk); pa_source_ref(s); + + if (!pa_cvolume_is_norm(&s->sw_volume)) { + pa_memchunk_make_writable(chunk, s->core->memblock_stat, 0); + pa_volume_memchunk(chunk, &s->sample_spec, &s->sw_volume); + } + pa_idxset_foreach(s->outputs, do_post, (void*) chunk); + pa_source_unref(s); } @@ -194,3 +208,40 @@ pa_usec_t pa_source_get_latency(pa_source *s) { return s->get_latency(s); } +void pa_source_set_volume(pa_source *s, pa_mixer_t m, const pa_cvolume *volume) { + pa_cvolume *v; + + assert(s); + assert(s->ref >= 1); + assert(volume); + + if (m == PA_MIXER_HARDWARE && s->set_hw_volume) + v = &s->hw_volume; + else + v = &s->sw_volume; + + if (pa_cvolume_equal(v, volume)) + return; + + *v = *volume; + + if (v == &s->hw_volume) + if (s->set_hw_volume(s) < 0) + s->sw_volume = *volume; + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); +} + +const pa_cvolume *pa_source_get_volume(pa_source *s, pa_mixer_t m) { + assert(s); + assert(s->ref >= 1); + + if (m == PA_MIXER_HARDWARE && s->set_hw_volume) { + + if (s->get_hw_volume) + s->get_hw_volume(s); + + return &s->hw_volume; + } else + return &s->sw_volume; +} diff --git a/src/polypcore/source.h b/src/polypcore/source.h index a267e73c..3c5bb6c4 100644 --- a/src/polypcore/source.h +++ b/src/polypcore/source.h @@ -28,6 +28,8 @@ typedef struct pa_source pa_source; #include #include +#include +#include #include #include #include @@ -56,9 +58,13 @@ struct pa_source { pa_idxset *outputs; pa_sink *monitor_of; + + pa_cvolume hw_volume, sw_volume; void (*notify)(pa_source*source); pa_usec_t (*get_latency)(pa_source *s); + int (*set_hw_volume)(pa_source *s); + int (*get_hw_volume)(pa_source *s); void *userdata; }; @@ -84,4 +90,7 @@ void pa_source_set_owner(pa_source *s, pa_module *m); pa_usec_t pa_source_get_latency(pa_source *s); +void pa_source_set_volume(pa_source *source, pa_mixer_t m, const pa_cvolume *volume); +const pa_cvolume *pa_source_get_volume(pa_source *source, pa_mixer_t m); + #endif -- cgit From 71fd26f895690f7e14b10b30a61b98f8ab7c8b24 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 22 Feb 2006 15:36:11 +0000 Subject: Wrong userdata used to init operation. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@561 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polyp/context.c b/src/polyp/context.c index 63acf19f..15e6cd76 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -847,7 +847,7 @@ pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, pa PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - o = pa_operation_new(c, NULL, cb, o->userdata); + o = pa_operation_new(c, NULL, cb, userdata); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, command); -- cgit From f62b66ae41ad9ae9c89c1aba3e55aa466fbe42df Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Feb 2006 18:43:26 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@562 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/todo b/doc/todo index feac0c75..a0ad6bbf 100644 --- a/doc/todo +++ b/doc/todo @@ -23,6 +23,7 @@ Fixes: - volume control - add hw driver name to sink/source description - deal with underflows properly +- multiline configuration statements Post 0.8: - alsa mmap driver @@ -32,6 +33,7 @@ Post 0.8: - chroot() - add threading API - module-tunnel: improve latency calculation +- port from howl to avahi Long term: - pass meta info for hearing impaired -- cgit From a99e46dd0b146d7f3d0c57821ccc26ead6b01f65 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Feb 2006 18:54:21 +0000 Subject: rework parameter validity checking in protocol-native server side git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@563 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/def.h | 3 +- src/polypcore/protocol-native.c | 522 ++++++++++++++-------------------------- 2 files changed, 182 insertions(+), 343 deletions(-) diff --git a/src/polyp/def.h b/src/polyp/def.h index 2ce1bd0c..0d095e9a 100644 --- a/src/polyp/def.h +++ b/src/polyp/def.h @@ -139,7 +139,8 @@ typedef enum pa_subscription_mask { PA_SUBSCRIPTION_MASK_CLIENT = 32, /**< Client events */ PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, /**< Sample cache events */ PA_SUBSCRIPTION_MASK_SERVER = 128, /**< Other global server changes. \since 0.4 */ - PA_SUBSCRIPTION_MASK_AUTOLOAD = 256 /**< Autoload table events. \since 0.5 */ + PA_SUBSCRIPTION_MASK_AUTOLOAD = 256, /**< Autoload table events. \since 0.5 */ + PA_SUBSCRIPTION_MASK_ALL = 511 /**< Catch all events \since 0.8 */ } pa_subscription_mask_t; /** Subscription event types, as used by pa_context_subscribe() */ diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index cd1a685f..34d3a247 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -545,7 +545,6 @@ static void send_playback_stream_killed(struct playback_stream *p) { assert(p); t = pa_tagstruct_new(NULL, 0); - assert(t); pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED); pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ pa_tagstruct_putu32(t, p->index); @@ -557,7 +556,6 @@ static void send_record_stream_killed(struct record_stream *r) { assert(r); t = pa_tagstruct_new(NULL, 0); - assert(t); pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED); pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ pa_tagstruct_putu32(t, r->index); @@ -667,6 +665,22 @@ static void protocol_error(struct connection *c) { connection_free(c); } +#define CHECK_VALIDITY(pstream, expression, tag, error) do { \ +if (!(expression)) { \ + pa_pstream_send_error((pstream), (tag), (error)); \ + return; \ +} \ +} while(0); + +static pa_tagstruct *reply_new(uint32_t tag) { + pa_tagstruct *reply; + + reply = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + return reply; +} + static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; struct playback_stream *s; @@ -703,33 +717,24 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, name, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, sink_index != PA_INVALID_INDEX || !sink_name || *sink_name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID); if (sink_index != PA_INVALID_INDEX) sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); else sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1); - if (!sink) { - pa_log_warn(__FILE__": Can't find a suitable sink.\n"); - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } - - if (!(s = playback_stream_new(c, sink, &ss, &map, name, maxlength, tlength, prebuf, minreq, &volume, syncid))) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); - return; - } + CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); + + s = playback_stream_new(c, sink, &ss, &map, name, maxlength, tlength, prebuf, minreq, &volume, syncid); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); pa_sink_input_cork(s->sink_input, corked); - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); + reply = reply_new(tag); pa_tagstruct_putu32(reply, s->index); assert(s->sink_input); pa_tagstruct_putu32(reply, s->sink_input->index); @@ -749,10 +754,7 @@ static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); if (command == PA_COMMAND_DELETE_PLAYBACK_STREAM) { struct playback_stream *s; @@ -797,7 +799,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ int corked; assert(c && t && c->protocol && c->protocol->core); - if (pa_tagstruct_gets(t, &name) < 0 || !name || + if (pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_get_sample_spec(t, &ss) < 0 || pa_tagstruct_get_channel_map(t, &map) < 0 || pa_tagstruct_getu32(t, &source_index) < 0 || @@ -810,32 +812,24 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, source_index != PA_INVALID_INDEX || !source_name || *source_name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID); - if (source_index != (uint32_t) -1) + if (source_index != PA_INVALID_INDEX) source = pa_idxset_get_by_index(c->protocol->core->sources, source_index); else source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE, 1); - if (!source) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } + CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY); + + s = record_stream_new(c, source, &ss, &map, name, maxlength, fragment_size); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); - if (!(s = record_stream_new(c, source, &ss, &map, name, maxlength, fragment_size))) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); - return; - } - pa_source_output_cork(s->source_output, corked); - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); + reply = reply_new(tag); pa_tagstruct_putu32(reply, s->index); assert(s->source_output); pa_tagstruct_putu32(reply, s->source_output->index); @@ -851,15 +845,11 @@ static void command_exit(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); assert(c->protocol && c->protocol->core && c->protocol->core->mainloop); c->protocol->core->mainloop->quit(c->protocol->core->mainloop, 0); pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */ - return; } static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -888,7 +878,6 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t } pa_pstream_send_simple_ack(c->pstream, tag); - return; } static void command_set_client_name(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -896,15 +885,16 @@ static void command_set_client_name(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE const char *name; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || !name || + if (pa_tagstruct_gets(t, &name) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; } + CHECK_VALIDITY(c->pstream, name, tag, PA_ERR_INVALID); + pa_client_set_name(c->client, name); pa_pstream_send_simple_ack(c->pstream, tag); - return; } static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -913,16 +903,14 @@ static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uin uint32_t idx = PA_IDXSET_INVALID; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || !name || + if (pa_tagstruct_gets(t, &name) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, name && *name, tag, PA_ERR_INVALID); if (command == PA_COMMAND_LOOKUP_SINK) { pa_sink *sink; @@ -939,10 +927,7 @@ static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uin pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); else { pa_tagstruct *reply; - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); + reply = reply_new(tag); pa_tagstruct_putu32(reply, idx); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -960,16 +945,11 @@ static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } - + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + s = pa_idxset_get_by_index(c->output_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); + s->drain_request = 0; pa_memblockq_prebuf_disable(s->memblockq); @@ -996,15 +976,9 @@ static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); + reply = reply_new(tag); pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->total); pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->total_size); pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->allocated); @@ -1030,20 +1004,12 @@ static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + s = pa_idxset_get_by_index(c->output_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); + reply = reply_new(tag); pa_tagstruct_put_usec(reply, pa_sink_input_get_latency(s->sink_input)); pa_tagstruct_put_usec(reply, pa_sink_get_latency(s->sink_input->sink)); pa_tagstruct_put_usec(reply, 0); @@ -1073,20 +1039,11 @@ static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + s = pa_idxset_get_by_index(c->record_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); + reply = reply_new(tag); pa_tagstruct_put_usec(reply, pa_source_output_get_latency(s->source_output)); pa_tagstruct_put_usec(reply, s->source_output->source->monitor_of ? pa_sink_get_latency(s->source_output->source->monitor_of) : 0); pa_tagstruct_put_usec(reply, pa_source_get_latency(s->source_output->source)); @@ -1099,7 +1056,6 @@ static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN pa_pstream_send_tagstruct(c->pstream, reply); } - static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; struct upload_stream *s; @@ -1110,7 +1066,7 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_tagstruct *reply; assert(c && t && c->protocol && c->protocol->core); - if (pa_tagstruct_gets(t, &name) < 0 || !name || + if (pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_get_sample_spec(t, &ss) < 0 || pa_tagstruct_get_channel_map(t, &map) < 0 || pa_tagstruct_getu32(t, &length) < 0 || @@ -1119,25 +1075,14 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } - - if ((length % pa_frame_size(&ss)) != 0 || length <= 0 || !*name) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && *name, tag, PA_ERR_INVALID); - if (!(s = upload_stream_new(c, &ss, &map, name, length))) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); - return; - } + s = upload_stream_new(c, &ss, &map, name, length); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); + reply = reply_new(tag); pa_tagstruct_putu32(reply, s->index); pa_tagstruct_putu32(reply, length); pa_pstream_send_tagstruct(c->pstream, reply); @@ -1156,15 +1101,11 @@ static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != UPLOAD_STREAM)) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); - return; - } + s = pa_idxset_get_by_index(c->output_streams, channel); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, s->type == UPLOAD_STREAM, tag, PA_ERR_NOENTITY); pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, &idx); pa_pstream_send_simple_ack(c->pstream, tag); @@ -1182,26 +1123,22 @@ static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui if (pa_tagstruct_getu32(t, &sink_index) < 0 || pa_tagstruct_gets(t, &sink_name) < 0 || pa_tagstruct_get_cvolume(t, &volume) < 0 || - pa_tagstruct_gets(t, &name) < 0 || !name || + pa_tagstruct_gets(t, &name) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, sink_index != PA_INVALID_INDEX || !sink_name || *sink_name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && *name, tag, PA_ERR_INVALID); - if (sink_index != (uint32_t) -1) + if (sink_index != PA_INVALID_INDEX) sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); else sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1); - if (!sink) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } + CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); if (pa_scache_play_item(c->protocol->core, name, sink, &volume) < 0) { pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); @@ -1216,16 +1153,14 @@ static void command_remove_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED const char *name; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || !name || + if (pa_tagstruct_gets(t, &name) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, name && *name, tag, PA_ERR_INVALID); if (pa_scache_remove_item(c->protocol->core, name) < 0) { pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); @@ -1275,7 +1210,7 @@ static void client_fill_tagstruct(pa_tagstruct *t, pa_client *client) { assert(t && client); pa_tagstruct_putu32(t, client->index); pa_tagstruct_puts(t, client->name); - pa_tagstruct_putu32(t, client->owner ? client->owner->index : (uint32_t) -1); + pa_tagstruct_putu32(t, client->owner ? client->owner->index : PA_INVALID_INDEX); pa_tagstruct_puts(t, client->driver); } @@ -1292,8 +1227,8 @@ static void sink_input_fill_tagstruct(pa_tagstruct *t, pa_sink_input *s) { assert(t && s); pa_tagstruct_putu32(t, s->index); pa_tagstruct_puts(t, s->name); - pa_tagstruct_putu32(t, s->owner ? s->owner->index : (uint32_t) -1); - pa_tagstruct_putu32(t, s->client ? s->client->index : (uint32_t) -1); + pa_tagstruct_putu32(t, s->owner ? s->owner->index : PA_INVALID_INDEX); + pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX); pa_tagstruct_putu32(t, s->sink->index); pa_tagstruct_put_sample_spec(t, &s->sample_spec); pa_tagstruct_put_channel_map(t, &s->channel_map); @@ -1308,8 +1243,8 @@ static void source_output_fill_tagstruct(pa_tagstruct *t, pa_source_output *s) { assert(t && s); pa_tagstruct_putu32(t, s->index); pa_tagstruct_puts(t, s->name); - pa_tagstruct_putu32(t, s->owner ? s->owner->index : (uint32_t) -1); - pa_tagstruct_putu32(t, s->client ? s->client->index : (uint32_t) -1); + pa_tagstruct_putu32(t, s->owner ? s->owner->index : PA_INVALID_INDEX); + pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX); pa_tagstruct_putu32(t, s->source->index); pa_tagstruct_put_sample_spec(t, &s->sample_spec); pa_tagstruct_put_channel_map(t, &s->channel_map); @@ -1357,19 +1292,16 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u protocol_error(c); return; } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); if (command == PA_COMMAND_GET_SINK_INFO) { - if (idx != (uint32_t) -1) + if (idx != PA_INVALID_INDEX) sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); else sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); } else if (command == PA_COMMAND_GET_SOURCE_INFO) { - if (idx != (uint32_t) -1) + if (idx != PA_INVALID_INDEX) source = pa_idxset_get_by_index(c->protocol->core->sources, idx); else source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); @@ -1383,7 +1315,7 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); else { assert(command == PA_COMMAND_GET_SAMPLE_INFO); - if (idx != (uint32_t) -1) + if (idx != PA_INVALID_INDEX) sce = pa_idxset_get_by_index(c->protocol->core->scache, idx); else sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE, 0); @@ -1394,10 +1326,7 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u return; } - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); + reply = reply_new(tag); if (sink) sink_fill_tagstruct(reply, sink); else if (source) @@ -1427,16 +1356,10 @@ static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma protocol_error(c); return; } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + + reply = reply_new(tag); if (command == PA_COMMAND_GET_SINK_INFO_LIST) i = c->protocol->core->sinks; @@ -1491,15 +1414,9 @@ static void command_get_server_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); + reply = reply_new(tag); pa_tagstruct_puts(reply, PACKAGE_NAME); pa_tagstruct_puts(reply, PACKAGE_VERSION); pa_tagstruct_puts(reply, pa_get_user_name(txt, sizeof(txt))); @@ -1522,7 +1439,6 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint3 assert(c && core); t = pa_tagstruct_new(NULL, 0); - assert(t); pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT); pa_tagstruct_putu32(t, (uint32_t) -1); pa_tagstruct_putu32(t, e); @@ -1540,12 +1456,10 @@ static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint protocol_error(c); return; } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID); + if (c->subscription) pa_subscription_free(c->subscription); @@ -1558,7 +1472,13 @@ static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_set_volume(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_set_volume( + PA_GCC_UNUSED pa_pdispatch *pd, + uint32_t command, + uint32_t tag, + pa_tagstruct *t, + void *userdata) { + struct connection *c = userdata; uint32_t idx; pa_cvolume volume; @@ -1577,13 +1497,11 @@ static void command_set_volume(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || *name, tag, PA_ERR_INVALID); if (command == PA_COMMAND_SET_SINK_VOLUME) { - if (idx != (uint32_t) -1) + if (idx != PA_INVALID_INDEX) sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); else sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); @@ -1597,10 +1515,7 @@ static void command_set_volume(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); } - if (!si && !sink && !source) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } + CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY); if (sink) pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &volume); @@ -1626,17 +1541,11 @@ static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } - - fprintf(stderr, "Corking %i\n", b); + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); + s = pa_idxset_get_by_index(c->output_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); pa_sink_input_cork(s->sink_input, b); pa_memblockq_prebuf_force(s->memblockq); @@ -1667,15 +1576,11 @@ static void command_flush_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); + s = pa_idxset_get_by_index(c->output_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); pa_memblockq_flush(s->memblockq); s->underrun = 0; @@ -1714,15 +1619,11 @@ static void command_trigger_or_prebuf_playback_stream(PA_GCC_UNUSED pa_pdispatch return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); + s = pa_idxset_get_by_index(c->output_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); switch (command) { case PA_COMMAND_PREBUF_PLAYBACK_STREAM: @@ -1756,15 +1657,9 @@ static void command_cork_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + s = pa_idxset_get_by_index(c->record_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); pa_source_output_cork(s->source_output, b); pa_memblockq_prebuf_force(s->memblockq); @@ -1783,15 +1678,9 @@ static void command_flush_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_U return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } - - if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + s = pa_idxset_get_by_index(c->record_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); pa_memblockq_flush(s->memblockq); pa_pstream_send_simple_ack(c->pstream, tag); @@ -1799,21 +1688,17 @@ static void command_flush_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_U static void command_set_default_sink_or_source(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - uint32_t idx; const char *s; assert(c && t); - if (pa_tagstruct_getu32(t, &idx) < 0 || - pa_tagstruct_gets(t, &s) < 0 || !s || + if (pa_tagstruct_gets(t, &s) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, !s || *s, tag, PA_ERR_INVALID); pa_namereg_set_default(c->protocol->core, s, command == PA_COMMAND_SET_DEFAULT_SOURCE ? PA_NAMEREG_SOURCE : PA_NAMEREG_SINK); pa_pstream_send_simple_ack(c->pstream, tag); @@ -1826,34 +1711,29 @@ static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t com assert(c && t); if (pa_tagstruct_getu32(t, &idx) < 0 || - pa_tagstruct_gets(t, &name) < 0 || !name || + pa_tagstruct_gets(t, &name) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, name, tag, PA_ERR_INVALID); if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) { struct playback_stream *s; - if (!(s = pa_idxset_get_by_index(c->output_streams, idx)) || s->type != PLAYBACK_STREAM) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } + s = pa_idxset_get_by_index(c->output_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); pa_sink_input_set_name(s->sink_input, name); } else { struct record_stream *s; - if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } + s = pa_idxset_get_by_index(c->record_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); pa_source_output_set_name(s->source_output, name); } @@ -1871,28 +1751,21 @@ static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint3 protocol_error(c); return; } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); if (command == PA_COMMAND_KILL_CLIENT) { pa_client *client; - if (!(client = pa_idxset_get_by_index(c->protocol->core->clients, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } - + client = pa_idxset_get_by_index(c->protocol->core->clients, idx); + CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY); pa_client_kill(client); + } else if (command == PA_COMMAND_KILL_SINK_INPUT) { pa_sink_input *s; - if (!(s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } + s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); pa_sink_input_kill(s); } else { @@ -1900,10 +1773,8 @@ static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint3 assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT); - if (!(s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } + s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); pa_source_output_kill(s); } @@ -1918,26 +1789,22 @@ static void command_load_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui pa_tagstruct *reply; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || !name || + if (pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_gets(t, &argument) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; } - - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, name && *name, tag, PA_ERR_INVALID); if (!(m = pa_module_load(c->protocol->core, name, argument))) { pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED); return; } - reply = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); + reply = reply_new(tag); pa_tagstruct_putu32(reply, m->index); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -1954,15 +1821,9 @@ static void command_unload_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } - - if (!(m = pa_idxset_get_by_index(c->protocol->core->modules, idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + m = pa_idxset_get_by_index(c->protocol->core->modules, idx); + CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY); pa_module_unload_request(m); pa_pstream_send_simple_ack(c->pstream, tag); @@ -1976,28 +1837,26 @@ static void command_add_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED u pa_tagstruct *reply; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || !name || - pa_tagstruct_getu32(t, &type) < 0 || type > 1 || - pa_tagstruct_gets(t, &module) < 0 || !module || + if (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_getu32(t, &type) < 0 || + pa_tagstruct_gets(t, &module) < 0 || pa_tagstruct_gets(t, &argument) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, name && *name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, type == 0 || type == 1, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, module && *module, tag, PA_ERR_INVALID); if (pa_autoload_add(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, module, argument, &idx) < 0) { pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); return; } - reply = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); + reply = reply_new(tag); pa_tagstruct_putu32(reply, idx); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -2012,27 +1871,21 @@ static void command_remove_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE if ((pa_tagstruct_getu32(t, &idx) < 0 && (pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_getu32(t, &type) < 0)) || - (!name && idx == PA_IDXSET_INVALID) || - (name && type > 1) || !pa_tagstruct_eof(t)) { protocol_error(c); return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, name || idx != PA_IDXSET_INVALID, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || (*name && (type == 0 || type == 1)), tag, PA_ERR_INVALID); if (name) r = pa_autoload_remove_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE); else r = pa_autoload_remove_by_index(c->protocol->core, idx); - if (r < 0) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } + CHECK_VALIDITY(c->pstream, r >= 0, tag, PA_ERR_NOENTITY); pa_pstream_send_simple_ack(c->pstream, tag); } @@ -2058,33 +1911,23 @@ static void command_get_autoload_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNU if ((pa_tagstruct_getu32(t, &idx) < 0 && (pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_getu32(t, &type) < 0)) || - (!name && idx == PA_IDXSET_INVALID) || - (name && type > 1) || !pa_tagstruct_eof(t)) { protocol_error(c); return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } - + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, name || idx != PA_IDXSET_INVALID, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || (*name && (type == 0 || type == 1)), tag, PA_ERR_INVALID); if (name) a = pa_autoload_get_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE); else a = pa_autoload_get_by_index(c->protocol->core, idx); - if (!a) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } + CHECK_VALIDITY(c->pstream, a, tag, PA_ERR_NOENTITY); - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); + reply = reply_new(tag); autoload_fill_tagstruct(reply, a); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -2099,14 +1942,9 @@ static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC return; } - if (!c->authorized) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - reply = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); + reply = reply_new(tag); if (c->protocol->core->autoload_hashmap) { pa_autoload_entry *a; @@ -2327,7 +2165,7 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo return NULL; } - p = pa_xmalloc(sizeof(pa_protocol_native)); + p = pa_xnew(pa_protocol_native, 1); p->core = c; p->module = m; p->public = public; -- cgit From 63165d83cb5ec9709cdf35b81fe90122e4bcb0a4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Feb 2006 18:59:27 +0000 Subject: todo test git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@564 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 +- src/Makefile.am | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/todo b/doc/todo index a0ad6bbf..ddefde48 100644 --- a/doc/todo +++ b/doc/todo @@ -6,7 +6,7 @@ Test: - howl Fixes: -- better validity checking in protocol-{native,esound} +- better validity checking in protocol-esound - change pa_log to not require \n - proper use of memcpy in procotol-esound.c so we don't get alignment problems - latency api for native protocol diff --git a/src/Makefile.am b/src/Makefile.am index f36630e7..ab50d825 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -47,8 +47,8 @@ AM_CFLAGS = -I$(top_srcdir)/src AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS AM_CFLAGS += $(LTDLINCL) AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) -AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" -#AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\" +#AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" +AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\" AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\" AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(POLYPAUDIO_BINARY)\" -- cgit From 361f16718f672e6627f74358540ab0a98e82857b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Feb 2006 19:00:27 +0000 Subject: unbreak Makefile.am git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@565 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index ab50d825..f36630e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -47,8 +47,8 @@ AM_CFLAGS = -I$(top_srcdir)/src AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS AM_CFLAGS += $(LTDLINCL) AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) -#AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" -AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\" +AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" +#AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\" AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\" AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(POLYPAUDIO_BINARY)\" -- cgit From 7f68c913f1c54114a538ccca680db3a3ba4d6e26 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Feb 2006 20:11:56 +0000 Subject: revive howl support git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@566 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/howl-wrap.c | 4 +- src/modules/howl-wrap.h | 2 +- src/modules/module-zeroconf-publish.c | 65 +++++++++---------- src/polyp/browser.c | 116 ++++++++++++++++++++-------------- src/polyp/browser.h | 22 ++++--- src/utils/pabrowse.c | 23 ++++--- 6 files changed, 126 insertions(+), 106 deletions(-) diff --git a/src/modules/howl-wrap.c b/src/modules/howl-wrap.c index b3acde55..b3fe8166 100644 --- a/src/modules/howl-wrap.c +++ b/src/modules/howl-wrap.c @@ -29,7 +29,7 @@ #define HOWL_PROPERTY "howl" -pa_howl_wrapper { +struct pa_howl_wrapper { pa_core *core; int ref; @@ -38,7 +38,7 @@ pa_howl_wrapper { }; -static void howl_io_event(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata) { +static void howl_io_event(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { pa_howl_wrapper *w = userdata; assert(m && e && fd >= 0 && w && w->ref >= 1); diff --git a/src/modules/howl-wrap.h b/src/modules/howl-wrap.h index 42c26ef2..a4b26490 100644 --- a/src/modules/howl-wrap.h +++ b/src/modules/howl-wrap.h @@ -26,7 +26,7 @@ #include -pa_howl_wrapper; +typedef struct pa_howl_wrapper pa_howl_wrapper; pa_howl_wrapper* pa_howl_wrapper_get(pa_core *c); pa_howl_wrapper* pa_howl_wrapper_ref(pa_howl_wrapper *h); diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index d2858aac..d79355ce 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -67,13 +67,13 @@ struct service { struct { int valid; - pa_namereg_type type; + pa_namereg_type_t type; uint32_t index; } loaded; struct { int valid; - pa_namereg_type type; + pa_namereg_type_t type; uint32_t index; } autoload; }; @@ -93,21 +93,19 @@ static sw_result publish_reply(sw_discovery discovery, sw_discovery_publish_stat return SW_OKAY; } -static void get_service_data(struct userdata *u, struct service *s, pa_sample_spec *ret_ss, char **ret_description, pa_typeid_t *ret_typeid) { - assert(u && s && s->loaded.valid && ret_ss && ret_description && ret_typeid); +static void get_service_data(struct userdata *u, struct service *s, pa_sample_spec *ret_ss, char **ret_description) { + assert(u && s && s->loaded.valid && ret_ss && ret_description); if (s->loaded.type == PA_NAMEREG_SINK) { pa_sink *sink = pa_idxset_get_by_index(u->core->sinks, s->loaded.index); assert(sink); *ret_ss = sink->sample_spec; *ret_description = sink->description; - *ret_typeid = sink->typeid; } else if (s->loaded.type == PA_NAMEREG_SOURCE) { pa_source *source = pa_idxset_get_by_index(u->core->sources, s->loaded.index); assert(source); *ret_ss = source->sample_spec; *ret_description = source->description; - *ret_typeid = source->typeid; } else assert(0); } @@ -154,10 +152,9 @@ static int publish_service(struct userdata *u, struct service *s) { if (s->loaded.valid) { char z[64], *description; - pa_typeid_t typeid; pa_sample_spec ss; - get_service_data(u, s, &ss, &description, &typeid); + get_service_data(u, s, &ss, &description); snprintf(z, sizeof(z), "%u", ss.rate); sw_text_record_add_key_and_string_value(txt, "rate", z); @@ -167,10 +164,6 @@ static int publish_service(struct userdata *u, struct service *s) { sw_text_record_add_key_and_string_value(txt, "description", description); - snprintf(z, sizeof(z), "0x%8x", typeid); - sw_text_record_add_key_and_string_value(txt, "typeid", z); - - if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t, s->loaded.type == PA_NAMEREG_SINK ? SERVICE_NAME_SINK : SERVICE_NAME_SOURCE, NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt), @@ -210,7 +203,7 @@ finish: return r; } -struct service *get_service(struct userdata *u, const char *name) { +static struct service *get_service(struct userdata *u, const char *name) { struct service *s; if ((s = pa_hashmap_get(u->services, name))) @@ -277,55 +270,55 @@ static int publish_autoload(struct userdata *u, pa_autoload_entry *s) { return publish_service(u, svc); } -static int remove_sink(struct userdata *u, uint32_t index) { +static int remove_sink(struct userdata *u, uint32_t idx) { struct service *svc; - assert(u && index != PA_INVALID_INDEX); + assert(u && idx != PA_INVALID_INDEX); - if (!(svc = pa_dynarray_get(u->sink_dynarray, index))) + if (!(svc = pa_dynarray_get(u->sink_dynarray, idx))) return 0; if (!svc->loaded.valid || svc->loaded.type != PA_NAMEREG_SINK) return 0; svc->loaded.valid = 0; - pa_dynarray_put(u->sink_dynarray, index, NULL); + pa_dynarray_put(u->sink_dynarray, idx, NULL); return publish_service(u, svc); } -static int remove_source(struct userdata *u, uint32_t index) { +static int remove_source(struct userdata *u, uint32_t idx) { struct service *svc; - assert(u && index != PA_INVALID_INDEX); + assert(u && idx != PA_INVALID_INDEX); - if (!(svc = pa_dynarray_get(u->source_dynarray, index))) + if (!(svc = pa_dynarray_get(u->source_dynarray, idx))) return 0; if (!svc->loaded.valid || svc->loaded.type != PA_NAMEREG_SOURCE) return 0; svc->loaded.valid = 0; - pa_dynarray_put(u->source_dynarray, index, NULL); + pa_dynarray_put(u->source_dynarray, idx, NULL); return publish_service(u, svc); } -static int remove_autoload(struct userdata *u, uint32_t index) { +static int remove_autoload(struct userdata *u, uint32_t idx) { struct service *svc; - assert(u && index != PA_INVALID_INDEX); + assert(u && idx != PA_INVALID_INDEX); - if (!(svc = pa_dynarray_get(u->autoload_dynarray, index))) + if (!(svc = pa_dynarray_get(u->autoload_dynarray, idx))) return 0; if (!svc->autoload.valid) return 0; svc->autoload.valid = 0; - pa_dynarray_put(u->autoload_dynarray, index, NULL); + pa_dynarray_put(u->autoload_dynarray, idx, NULL); return publish_service(u, svc); } -static void subscribe_callback(pa_core *c, pa_subscription_event_type t, uint32_t index, void *userdata) { +static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { struct userdata *u = userdata; assert(u && c); @@ -334,12 +327,12 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type t, uint32_ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { pa_sink *sink; - if ((sink = pa_idxset_get_by_index(c->sinks, index))) { + if ((sink = pa_idxset_get_by_index(c->sinks, idx))) { if (publish_sink(u, sink) < 0) goto fail; } } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - if (remove_sink(u, index) < 0) + if (remove_sink(u, idx) < 0) goto fail; } @@ -350,12 +343,12 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type t, uint32_ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { pa_source *source; - if ((source = pa_idxset_get_by_index(c->sources, index))) { + if ((source = pa_idxset_get_by_index(c->sources, idx))) { if (publish_source(u, source) < 0) goto fail; } } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - if (remove_source(u, index) < 0) + if (remove_source(u, idx) < 0) goto fail; } @@ -365,12 +358,12 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type t, uint32_ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { pa_autoload_entry *autoload; - if ((autoload = pa_idxset_get_by_index(c->autoload_idxset, index))) { + if ((autoload = pa_idxset_get_by_index(c->autoload_idxset, idx))) { if (publish_autoload(u, autoload) < 0) goto fail; } } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - if (remove_autoload(u, index) < 0) + if (remove_autoload(u, idx) < 0) goto fail; } @@ -388,7 +381,7 @@ fail: int pa__init(pa_core *c, pa_module*m) { struct userdata *u; - uint32_t index, port = PA_NATIVE_DEFAULT_PORT; + uint32_t idx, port = PA_NATIVE_DEFAULT_PORT; pa_sink *sink; pa_source *source; pa_autoload_entry *autoload; @@ -424,16 +417,16 @@ int pa__init(pa_core *c, pa_module*m) { PA_SUBSCRIPTION_MASK_SOURCE| PA_SUBSCRIPTION_MASK_AUTOLOAD, subscribe_callback, u); - for (sink = pa_idxset_first(c->sinks, &index); sink; sink = pa_idxset_next(c->sinks, &index)) + for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) if (publish_sink(u, sink) < 0) goto fail; - for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) + for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) if (publish_source(u, source) < 0) goto fail; if (c->autoload_idxset) - for (autoload = pa_idxset_first(c->autoload_idxset, &index); autoload; autoload = pa_idxset_next(c->autoload_idxset, &index)) + for (autoload = pa_idxset_first(c->autoload_idxset, &idx); autoload; autoload = pa_idxset_next(c->autoload_idxset, &idx)) if (publish_autoload(u, autoload) < 0) goto fail; diff --git a/src/polyp/browser.c b/src/polyp/browser.c index 482bab81..ce4c0103 100644 --- a/src/polyp/browser.c +++ b/src/polyp/browser.c @@ -32,19 +32,18 @@ #define SERVICE_NAME_SOURCE "_polypaudio-source._tcp." #define SERVICE_NAME_SERVER "_polypaudio-server._tcp." -pa_browser { +struct pa_browser { int ref; pa_mainloop_api *mainloop; - void (*callback)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void *userdata); - void *callback_userdata; + pa_browse_cb_t callback; + void *userdata; sw_discovery discovery; pa_io_event *io_event; }; - -static void io_callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags events, void *userdata) { +static void io_callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags_t events, void *userdata) { pa_browser *b = userdata; assert(a && b && b->mainloop == a); @@ -56,26 +55,54 @@ static void io_callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_fl } } +static int type_equal(const char *a, const char *b) { + size_t la, lb; + + if (strcasecmp(a, b) == 0) + return 1; + + la = strlen(a); + lb = strlen(b); + + if (la > 0 && a[la-1] == '.' && la == lb+1 && strncasecmp(a, b, la-1) == 0) + return 1; + + if (lb > 0 && b[lb-1] == '.' && lb == la+1 && strncasecmp(a, b, lb-1) == 0) + return 1; + + return 0; +} + +static int map_to_opcode(const char *type, int new) { + if (type_equal(type, SERVICE_NAME_SINK)) + return new ? PA_BROWSE_NEW_SINK : PA_BROWSE_REMOVE_SINK; + else if (type_equal(type, SERVICE_NAME_SOURCE)) + return new ? PA_BROWSE_NEW_SOURCE : PA_BROWSE_REMOVE_SOURCE; + else if (type_equal(type, SERVICE_NAME_SERVER)) + return new ? PA_BROWSE_NEW_SERVER : PA_BROWSE_REMOVE_SERVER; + + return -1; +} + static sw_result resolve_reply( - sw_discovery discovery, - sw_discovery_oid oid, - sw_uint32 interface_index, - sw_const_string name, - sw_const_string type, - sw_const_string domain, - sw_ipv4_address address, - sw_port port, - sw_octets text_record, - sw_ulong text_record_len, - sw_opaque extra) { + sw_discovery discovery, + sw_discovery_oid oid, + sw_uint32 interface_index, + sw_const_string name, + sw_const_string type, + sw_const_string domain, + sw_ipv4_address address, + sw_port port, + sw_octets text_record, + sw_ulong text_record_len, + sw_opaque extra) { pa_browser *b = extra; pa_browse_info i; char ip[256], a[256]; - pa_browse_opcode opcode; + int opcode; int device_found = 0; uint32_t cookie; - pa_typeid_t typeid; pa_sample_spec ss; int ss_valid = 0; sw_text_record_iterator iterator; @@ -91,17 +118,10 @@ static sw_result resolve_reply( if (!b->callback) goto fail; - - if (!strcmp(type, SERVICE_NAME_SINK)) - opcode = PA_BROWSE_NEW_SINK; - else if (!strcmp(type, SERVICE_NAME_SOURCE)) - opcode = PA_BROWSE_NEW_SOURCE; - else if (!strcmp(type, SERVICE_NAME_SERVER)) - opcode = PA_BROWSE_NEW_SERVER; - else - goto fail; - + opcode = map_to_opcode(type, 1); + assert(opcode >= 0); + snprintf(a, sizeof(a), "tcp:%s:%u", sw_ipv4_address_name(address, ip, sizeof(ip)), port); i.server = a; @@ -154,12 +174,6 @@ static sw_result resolve_reply( pa_xfree((char*) i.description); i.description = c; c = NULL; - } else if (!strcmp(key, "typeid")) { - - if (pa_atou(c, &typeid) < 0) - goto fail; - - i.typeid = &typeid; } else if (!strcmp(key, "channels")) { uint32_t ch; @@ -195,7 +209,7 @@ static sw_result resolve_reply( i.sample_spec = &ss; - b->callback(b, opcode, &i, b->callback_userdata); + b->callback(b, opcode, &i, b->userdata); fail: pa_xfree((void*) i.device); @@ -213,14 +227,14 @@ fail: } static sw_result browse_reply( - sw_discovery discovery, - sw_discovery_oid id, - sw_discovery_browse_status status, - sw_uint32 interface_index, - sw_const_string name, - sw_const_string type, - sw_const_string domain, - sw_opaque extra) { + sw_discovery discovery, + sw_discovery_oid id, + sw_discovery_browse_status status, + sw_uint32 interface_index, + sw_const_string name, + sw_const_string type, + sw_const_string domain, + sw_opaque extra) { pa_browser *b = extra; assert(b); @@ -238,9 +252,15 @@ static sw_result browse_reply( case SW_DISCOVERY_BROWSE_REMOVE_SERVICE: if (b->callback) { pa_browse_info i; + int opcode; + memset(&i, 0, sizeof(i)); i.name = name; - b->callback(b, PA_BROWSE_REMOVE, &i, b->callback_userdata); + + opcode = map_to_opcode(type, 0); + assert(opcode >= 0); + + b->callback(b, opcode, &i, b->userdata); } break; @@ -255,11 +275,11 @@ pa_browser *pa_browser_new(pa_mainloop_api *mainloop) { pa_browser *b; sw_discovery_oid oid; - b = pa_xmalloc(sizeof(pa_browser)); + b = pa_xnew(pa_browser, 1); b->mainloop = mainloop; b->ref = 1; b->callback = NULL; - b->callback_userdata = NULL; + b->userdata = NULL; if (sw_discovery_init(&b->discovery) != SW_OKAY) { pa_log("sw_discovery_init() failed.\n"); @@ -305,9 +325,9 @@ void pa_browser_unref(pa_browser *b) { browser_free(b); } -void pa_browser_set_callback(pa_browser *b, void (*cb)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void* userdata), void *userdata) { +void pa_browser_set_callback(pa_browser *b, pa_browse_cb_t cb, void *userdata) { assert(b); b->callback = cb; - b->callback_userdata = userdata; + b->userdata = userdata; } diff --git a/src/polyp/browser.h b/src/polyp/browser.h index 043b818a..1ff58d8c 100644 --- a/src/polyp/browser.h +++ b/src/polyp/browser.h @@ -24,24 +24,27 @@ #include #include +#include #include PA_C_DECL_BEGIN -pa_browser; +typedef struct pa_browser pa_browser; -pa_browse_opcode { - PA_BROWSE_NEW_SERVER, +typedef enum pa_browse_opcode { + PA_BROWSE_NEW_SERVER = 0, PA_BROWSE_NEW_SINK, PA_BROWSE_NEW_SOURCE, - PA_BROWSE_REMOVE -}; + PA_BROWSE_REMOVE_SERVER, + PA_BROWSE_REMOVE_SINK, + PA_BROWSE_REMOVE_SOURCE +} pa_browse_opcode_t; pa_browser *pa_browser_new(pa_mainloop_api *mainloop); pa_browser *pa_browser_ref(pa_browser *z); void pa_browser_unref(pa_browser *z); -pa_browse_info { +typedef struct pa_browse_info { /* Unique service name */ const char *name; /* always available */ @@ -53,11 +56,12 @@ pa_browse_info { /* Device info */ const char *device; /* always available when this information is of a sink/source */ const char *description; /* optional */ - const pa_typeid_t *typeid; /* optional */ const pa_sample_spec *sample_spec; /* optional */ -}; +} pa_browse_info; -void pa_browser_set_callback(pa_browser *z, void (*cb)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void *userdata), void *userdata); +typedef void (*pa_browse_cb_t)(pa_browser *z, pa_browse_opcode_t c, const pa_browse_info *i, void *userdata); + +void pa_browser_set_callback(pa_browser *z, pa_browse_cb_t cb, void *userdata); PA_C_DECL_END diff --git a/src/utils/pabrowse.c b/src/utils/pabrowse.c index 344e3281..c1bab6b1 100644 --- a/src/utils/pabrowse.c +++ b/src/utils/pabrowse.c @@ -55,26 +55,21 @@ static void dump_server(const pa_browse_info *i) { } static void dump_device(const pa_browse_info *i) { - char t[16], ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; if (i->sample_spec) pa_sample_spec_snprint(ss, sizeof(ss), i->sample_spec); - if (i->typeid) - pa_typeid_to_string(*i->typeid, t, sizeof(t)); - printf("device: %s\n" "description: %s\n" - "type: %s\n" "sample spec: %s\n", i->device, i->description ? i->description : "n/a", - i->typeid ? t : "n/a", i->sample_spec ? ss : "n/a"); } -static void browser_callback(pa_browser *b, pa_browse_opcode c, const pa_browse_info *i, void *userdata) { +static void browser_callback(pa_browser *b, pa_browse_opcode_t c, const pa_browse_info *i, void *userdata) { assert(b && i); switch (c) { @@ -96,10 +91,18 @@ static void browser_callback(pa_browser *b, pa_browse_opcode c, const pa_browse_ dump_device(i); break; - case PA_BROWSE_REMOVE: - printf("\n=> removed service <%s>\n", i->name); + case PA_BROWSE_REMOVE_SERVER: + printf("\n=> removed server <%s>\n", i->name); break; - + + case PA_BROWSE_REMOVE_SINK: + printf("\n=> removed sink <%s>\n", i->name); + break; + + case PA_BROWSE_REMOVE_SOURCE: + printf("\n=> removed source <%s>\n", i->name); + break; + default: ; } -- cgit From 5c7ab7746694ed08fbf3f290f338ca45231f1543 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Feb 2006 20:14:00 +0000 Subject: pkg-config update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@567 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyplib-browse.pc.in | 2 +- polyplib-glib-mainloop.pc.in | 2 +- polyplib-glib12-mainloop.pc.in | 2 +- polyplib-simple.pc.in | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/polyplib-browse.pc.in b/polyplib-browse.pc.in index b77967e0..b9d57eef 100644 --- a/polyplib-browse.pc.in +++ b/polyplib-browse.pc.in @@ -8,4 +8,4 @@ Description: Polypaudio network browsing API Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lpolyp-browse-@PA_MAJORMINOR@ Cflags: -D_REENTRANT -I${includedir} -Requires: polyplib-mainloop +Requires: polyplib diff --git a/polyplib-glib-mainloop.pc.in b/polyplib-glib-mainloop.pc.in index 431354e8..0e8b4d8c 100644 --- a/polyplib-glib-mainloop.pc.in +++ b/polyplib-glib-mainloop.pc.in @@ -8,4 +8,4 @@ Description: GLIB main loop wrapper for polypaudio Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lpolyp-mainloop-glib-@PA_MAJORMINOR@ Cflags: -D_REENTRANT -I${includedir} -Requires: polyplib-mainloop +Requires: polyplib-mainloop glib-2.0 diff --git a/polyplib-glib12-mainloop.pc.in b/polyplib-glib12-mainloop.pc.in index 5c5f4089..8687776b 100644 --- a/polyplib-glib12-mainloop.pc.in +++ b/polyplib-glib12-mainloop.pc.in @@ -8,4 +8,4 @@ Description: GLIB main loop wrapper for polypaudio Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lpolyp-mainloop-glib12-@PA_MAJORMINOR@ Cflags: -D_REENTRANT -I${includedir} -Requires: polyplib-mainloop +Requires: polyplib-mainloop glib diff --git a/polyplib-simple.pc.in b/polyplib-simple.pc.in index a2850349..94644df6 100644 --- a/polyplib-simple.pc.in +++ b/polyplib-simple.pc.in @@ -8,4 +8,4 @@ Description: Simplified synchronous client interface to polypaudio Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lpolyp-simple-@PA_MAJORMINOR@ Cflags: -D_REENTRANT -I${includedir} -Requires: polyplib polyplib-mainloop polyplib-error +Requires: polyplib -- cgit From 8df72bceb5c29aa0b5b974f0bc3a416b6733cbdb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Feb 2006 20:14:37 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@568 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index ddefde48..13600ce3 100644 --- a/doc/todo +++ b/doc/todo @@ -3,7 +3,6 @@ Test: - module-combine - module-tunnel -- howl Fixes: - better validity checking in protocol-esound -- cgit From ecd346fa9a3ebf786bff8c5a9579b5096f90fc04 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Feb 2006 20:44:37 +0000 Subject: add listen= parameter to tcp protocol modules git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@569 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-protocol-stub.c | 10 ++++++++-- src/polypcore/socket-server.c | 18 ++++++++++++++++++ src/polypcore/socket-server.h | 1 + 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index f72a68a5..641e3624 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -52,7 +52,7 @@ #ifdef USE_TCP_SOCKETS #define SOCKET_DESCRIPTION "(TCP sockets)" -#define SOCKET_USAGE "port= loopback=" +#define SOCKET_USAGE "port= loopback= listen=
    " #else #define SOCKET_DESCRIPTION "(UNIX sockets)" #define SOCKET_USAGE "socket=" @@ -146,6 +146,7 @@ static const char* const valid_modargs[] = { #if defined(USE_TCP_SOCKETS) "port", "loopback", + "listen", #else "socket", #endif @@ -157,6 +158,7 @@ static pa_socket_server *create_socket_server(pa_core *c, pa_modargs *ma) { #if defined(USE_TCP_SOCKETS) int loopback = 1; uint32_t port = IPV4_PORT; + const char *listen_on; if (pa_modargs_get_value_boolean(ma, "loopback", &loopback) < 0) { pa_log(__FILE__": loopback= expects a boolean argument.\n"); @@ -168,8 +170,12 @@ static pa_socket_server *create_socket_server(pa_core *c, pa_modargs *ma) { return NULL; } + listen_on = pa_modargs_get_value(ma, "listen", NULL); - if (loopback) { + if (listen_on) { + if (!(s = pa_socket_server_new_ip_string(c->mainloop, listen_on, port, TCPWRAP_SERVICE))) + return NULL; + } else if (loopback) { if (!(s = pa_socket_server_new_ip_loopback(c->mainloop, port, TCPWRAP_SERVICE))) return NULL; } else { diff --git a/src/polypcore/socket-server.c b/src/polypcore/socket-server.c index 5f84911d..b1297496 100644 --- a/src/polypcore/socket-server.c +++ b/src/polypcore/socket-server.c @@ -334,6 +334,24 @@ pa_socket_server* pa_socket_server_new_ip_any(pa_mainloop_api *m, uint16_t port, return s; } +pa_socket_server* pa_socket_server_new_ip_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) { + uint8_t ipv6[16]; + uint32_t ipv4; + + assert(m); + assert(name); + assert(port > 0); + + if (inet_pton(AF_INET6, name, ipv6) > 0) + return pa_socket_server_new_ipv6(m, ipv6, port, tcpwrap_service); + + if (inet_pton(AF_INET, name, &ipv4) > 0) + return pa_socket_server_new_ipv4(m, ntohl(ipv4), port, tcpwrap_service); + + pa_log_warn(__FILE__": failed to parse '%s'.\n", name); + + return NULL; +} static void socket_server_free(pa_socket_server*s) { assert(s); diff --git a/src/polypcore/socket-server.h b/src/polypcore/socket-server.h index d11cee49..3babbc14 100644 --- a/src/polypcore/socket-server.h +++ b/src/polypcore/socket-server.h @@ -36,6 +36,7 @@ pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port, const char *tcpwrap_service); pa_socket_server* pa_socket_server_new_ip_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); pa_socket_server* pa_socket_server_new_ip_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ip_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service); void pa_socket_server_unref(pa_socket_server*s); pa_socket_server* pa_socket_server_ref(pa_socket_server *s); -- cgit From bad8fd7cc0ab399786fb23cb39f824948947feba Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Feb 2006 20:45:42 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@570 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index 13600ce3..9abfd2d0 100644 --- a/doc/todo +++ b/doc/todo @@ -14,7 +14,6 @@ Fixes: - notification on hw volume change - source volume control - mute switch support (like ALSA does it) -- add listen-on paramater to protocol modules - module-oss-* love: - deal with underflows propely - improve latency measurement for mmap -- cgit From 708c650ad1366a0686d4c2b1932762205097081c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Feb 2006 21:02:27 +0000 Subject: enforce maximum memblockq length for clients git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@571 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-native.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 34d3a247..aba12036 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -59,6 +59,8 @@ /* Don't accept more connection than this */ #define MAX_CONNECTIONS 10 +#define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */ + struct connection; struct pa_protocol_native; @@ -238,8 +240,7 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_GET_AUTOLOAD_INFO] = command_get_autoload_info, [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = command_get_autoload_info_list, [PA_COMMAND_ADD_AUTOLOAD] = command_add_autoload, - [PA_COMMAND_REMOVE_AUTOLOAD] = command_remove_autoload, - + [PA_COMMAND_REMOVE_AUTOLOAD] = command_remove_autoload }; /* structure management */ @@ -721,6 +722,7 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC CHECK_VALIDITY(c->pstream, name, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, sink_index != PA_INVALID_INDEX || !sink_name || *sink_name, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); if (sink_index != PA_INVALID_INDEX) sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); @@ -816,6 +818,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ CHECK_VALIDITY(c->pstream, name, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, source_index != PA_INVALID_INDEX || !source_name || *source_name, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); if (source_index != PA_INVALID_INDEX) source = pa_idxset_get_by_index(c->protocol->core->sources, source_index); -- cgit From 57713350d7fc3c39c44aecd02c2eda6ff2041cb4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Feb 2006 01:17:54 +0000 Subject: fix source volume adjustment: copy memchunk before changing the volume of it git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@572 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/source.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/polypcore/source.c b/src/polypcore/source.c index 47325a1b..8bca8a1d 100644 --- a/src/polypcore/source.c +++ b/src/polypcore/source.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "source.h" @@ -182,11 +183,15 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) { pa_source_ref(s); if (!pa_cvolume_is_norm(&s->sw_volume)) { - pa_memchunk_make_writable(chunk, s->core->memblock_stat, 0); - pa_volume_memchunk(chunk, &s->sample_spec, &s->sw_volume); - } - - pa_idxset_foreach(s->outputs, do_post, (void*) chunk); + pa_memchunk vchunk = *chunk; + + pa_memblock_ref(vchunk.memblock); + pa_memchunk_make_writable(&vchunk, s->core->memblock_stat, 0); + pa_volume_memchunk(&vchunk, &s->sample_spec, &s->sw_volume); + pa_idxset_foreach(s->outputs, do_post, &vchunk); + pa_memblock_unref(vchunk.memblock); + } else + pa_idxset_foreach(s->outputs, do_post, (void*) chunk); pa_source_unref(s); } -- cgit From cb59817b4a2e1f640bd9279d0c7863e7a09c1fa6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Feb 2006 01:24:16 +0000 Subject: simplify tagstruct creation git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@573 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/context.c | 43 ++++++++++++------------ src/polyp/internal.h | 2 ++ src/polyp/introspect.c | 88 +++++++++++++------------------------------------- src/polyp/scache.c | 16 +++------ src/polyp/stream.c | 48 +++++++++++++-------------- src/polyp/subscribe.c | 4 +-- 6 files changed, 74 insertions(+), 127 deletions(-) diff --git a/src/polyp/context.c b/src/polyp/context.c index 15e6cd76..906a0d89 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -354,9 +354,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t switch(c->state) { case PA_CONTEXT_AUTHORIZING: { pa_tagstruct *reply; - reply = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME); - pa_tagstruct_putu32(reply, tag = c->ctag++); + reply = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag); pa_tagstruct_puts(reply, c->name); pa_pstream_send_tagstruct(c->pstream, reply); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); @@ -401,9 +399,7 @@ static void setup_context(pa_context *c, pa_iochannel *io) { goto finish; } - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_AUTH, &tag); pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie)); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); @@ -827,10 +823,8 @@ pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, tag = c->ctag++); + + t = pa_tagstruct_command(c, PA_COMMAND_EXIT, &tag); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); @@ -849,9 +843,7 @@ pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, pa o = pa_operation_new(c, NULL, cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, command); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, command, &tag); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_cb, pa_operation_ref(o)); @@ -870,9 +862,7 @@ pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_co o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_DEFAULT_SINK); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SINK, &tag); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); @@ -892,9 +882,7 @@ pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_ o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_DEFAULT_SOURCE); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SOURCE, &tag); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); @@ -921,9 +909,7 @@ pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_su o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_CLIENT_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); @@ -949,3 +935,16 @@ const char* pa_context_get_server(pa_context *c) { return c->server; } + +pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag) { + pa_tagstruct *t; + + assert(c); + assert(tag); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, command); + pa_tagstruct_putu32(t, *tag = c->ctag++); + + return t; +} diff --git a/src/polyp/internal.h b/src/polyp/internal.h index 9907fae0..2e4d859a 100644 --- a/src/polyp/internal.h +++ b/src/polyp/internal.h @@ -164,6 +164,8 @@ void pa_stream_set_state(pa_stream *s, pa_stream_state_t st); void pa_stream_trash_ipol(pa_stream *s); +pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag); + #define PA_CHECK_VALIDITY(context, expression, error) do { \ if (!(expression)) \ return -pa_context_set_error((context), (error)); \ diff --git a/src/polyp/introspect.c b/src/polyp/introspect.c index 4fa23841..6a9917a7 100644 --- a/src/polyp/introspect.c +++ b/src/polyp/introspect.c @@ -189,9 +189,7 @@ pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, pa_ o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_GET_SINK_INFO, &tag); pa_tagstruct_putu32(t, idx); pa_tagstruct_puts(t, NULL); pa_pstream_send_tagstruct(c->pstream, t); @@ -214,9 +212,7 @@ pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_GET_SINK_INFO, &tag); pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); @@ -296,9 +292,7 @@ pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, p o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_GET_SOURCE_INFO, &tag); pa_tagstruct_putu32(t, idx); pa_tagstruct_puts(t, NULL); pa_pstream_send_tagstruct(c->pstream, t); @@ -321,9 +315,7 @@ pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_GET_SOURCE_INFO, &tag); pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); @@ -392,9 +384,7 @@ pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, pa_client_ o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_GET_CLIENT_INFO, &tag); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, pa_operation_ref(o)); @@ -467,9 +457,7 @@ pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_ o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_GET_MODULE_INFO, &tag); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, pa_operation_ref(o)); @@ -550,9 +538,7 @@ pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sin o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INPUT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_GET_SINK_INPUT_INFO, &tag); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_input_info_callback, pa_operation_ref(o)); @@ -632,9 +618,7 @@ pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, pa_ o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_OUTPUT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO, &tag); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_output_info_callback, pa_operation_ref(o)); @@ -662,9 +646,7 @@ pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, c o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_VOLUME, &tag); pa_tagstruct_putu32(t, idx); pa_tagstruct_puts(t, NULL); pa_tagstruct_put_cvolume(t, volume); @@ -690,9 +672,7 @@ pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_VOLUME, &tag); pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, name); pa_tagstruct_put_cvolume(t, volume); @@ -717,9 +697,7 @@ pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, cons o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_INPUT_VOLUME, &tag); pa_tagstruct_putu32(t, idx); pa_tagstruct_put_cvolume(t, volume); pa_pstream_send_tagstruct(c->pstream, t); @@ -742,9 +720,7 @@ pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_SOURCE_VOLUME); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_VOLUME, &tag); pa_tagstruct_putu32(t, idx); pa_tagstruct_puts(t, NULL); pa_tagstruct_put_cvolume(t, volume); @@ -770,9 +746,7 @@ pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *na o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_SOURCE_VOLUME); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_VOLUME, &tag); pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, name); pa_tagstruct_put_cvolume(t, volume); @@ -848,9 +822,7 @@ pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SAMPLE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_GET_SAMPLE_INFO, &tag); pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); @@ -873,9 +845,7 @@ pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, p o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SAMPLE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_GET_SAMPLE_INFO, &tag); pa_tagstruct_putu32(t, idx); pa_tagstruct_puts(t, NULL); pa_pstream_send_tagstruct(c->pstream, t); @@ -901,9 +871,7 @@ static pa_operation* command_kill(pa_context *c, uint32_t command, uint32_t idx, o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, command); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, command, &tag); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); @@ -967,9 +935,7 @@ pa_operation* pa_context_load_module(pa_context *c, const char*name, const char o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_LOAD_MODULE); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_LOAD_MODULE, &tag); pa_tagstruct_puts(t, name); pa_tagstruct_puts(t, argument); pa_pstream_send_tagstruct(c->pstream, t); @@ -1044,9 +1010,7 @@ pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *na o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_AUTOLOAD_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_GET_AUTOLOAD_INFO, &tag); pa_tagstruct_puts(t, name); pa_tagstruct_putu32(t, type); pa_pstream_send_tagstruct(c->pstream, t); @@ -1069,9 +1033,7 @@ pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_GET_AUTOLOAD_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_GET_AUTOLOAD_INFO, &tag); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, pa_operation_ref(o)); @@ -1098,9 +1060,7 @@ pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autolo o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_ADD_AUTOLOAD); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_ADD_AUTOLOAD, &tag); pa_tagstruct_puts(t, name); pa_tagstruct_putu32(t, type); pa_tagstruct_puts(t, module); @@ -1125,9 +1085,7 @@ pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_AUTOLOAD); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_AUTOLOAD, &tag); pa_tagstruct_puts(t, name); pa_tagstruct_putu32(t, type); pa_pstream_send_tagstruct(c->pstream, t); @@ -1149,9 +1107,7 @@ pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, p o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_AUTOLOAD); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_AUTOLOAD, &tag); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); diff --git a/src/polyp/scache.c b/src/polyp/scache.c index 792d7cbf..891798fb 100644 --- a/src/polyp/scache.c +++ b/src/polyp/scache.c @@ -47,9 +47,7 @@ int pa_stream_connect_upload(pa_stream *s, size_t length) { s->direction = PA_STREAM_UPLOAD; - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); + t = pa_tagstruct_command(s->context, PA_COMMAND_CREATE_UPLOAD_STREAM, &tag); pa_tagstruct_puts(t, s->name); pa_tagstruct_put_sample_spec(t, &s->sample_spec); pa_tagstruct_putu32(t, length); @@ -72,9 +70,7 @@ int pa_stream_finish_upload(pa_stream *s) { pa_stream_ref(s); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); + t = pa_tagstruct_command(s->context, PA_COMMAND_FINISH_UPLOAD_STREAM, &tag); pa_tagstruct_putu32(t, s->channel); pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s); @@ -100,9 +96,7 @@ pa_operation *pa_context_play_sample(pa_context *c, const char *name, const char if (!dev) dev = c->conf->default_sink; - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_PLAY_SAMPLE, &tag); pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, dev); pa_tagstruct_putu32(t, volume); @@ -126,9 +120,7 @@ pa_operation* pa_context_remove_sample(pa_context *c, const char *name, pa_conte o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_SAMPLE, &tag); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); diff --git a/src/polyp/stream.c b/src/polyp/stream.c index 1ffb4c16..5ab91815 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -409,15 +409,16 @@ static int create_stream( s->buffer_attr.fragsize = s->buffer_attr.tlength/100; } - t = pa_tagstruct_new(NULL, 0); - if (!dev) dev = s->direction == PA_STREAM_PLAYBACK ? s->context->conf->default_sink : s->context->conf->default_source; + + t = pa_tagstruct_command( + s->context, + s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM, + &tag); pa_tagstruct_put( t, - PA_TAG_U32, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM, - PA_TAG_U32, tag = s->context->ctag++, PA_TAG_STRING, s->name, PA_TAG_SAMPLE_SPEC, &s->sample_spec, PA_TAG_CHANNEL_MAP, &s->channel_map, @@ -599,9 +600,7 @@ pa_operation * pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *us o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); + t = pa_tagstruct_command(s->context, PA_COMMAND_DRAIN_PLAYBACK_STREAM, &tag); pa_tagstruct_putu32(t, s->channel); pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); @@ -689,9 +688,10 @@ pa_operation* pa_stream_get_latency_info(pa_stream *s, pa_stream_get_latency_inf o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_GET_PLAYBACK_LATENCY : PA_COMMAND_GET_RECORD_LATENCY); - pa_tagstruct_putu32(t, tag = s->context->ctag++); + t = pa_tagstruct_command( + s->context, + s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_GET_PLAYBACK_LATENCY : PA_COMMAND_GET_RECORD_LATENCY, + &tag); pa_tagstruct_putu32(t, s->channel); pa_gettimeofday(&now); @@ -742,11 +742,11 @@ int pa_stream_disconnect(pa_stream *s) { pa_stream_ref(s); - t = pa_tagstruct_new(NULL, 0); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); - pa_tagstruct_putu32(t, tag = s->context->ctag++); + t = pa_tagstruct_command( + s->context, + s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : + (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM), + &tag); pa_tagstruct_putu32(t, s->channel); pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s); @@ -848,9 +848,10 @@ pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, voi o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CORK_PLAYBACK_STREAM : PA_COMMAND_CORK_RECORD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); + t = pa_tagstruct_command( + s->context, + s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CORK_PLAYBACK_STREAM : PA_COMMAND_CORK_RECORD_STREAM, + &tag); pa_tagstruct_putu32(t, s->channel); pa_tagstruct_put_boolean(t, !!b); pa_pstream_send_tagstruct(s->context->pstream, t); @@ -873,9 +874,7 @@ static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, command); - pa_tagstruct_putu32(t, tag = s->context->ctag++); + t = pa_tagstruct_command(s->context, command, &tag); pa_tagstruct_putu32(t, s->channel); pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); @@ -930,9 +929,10 @@ pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_succe o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, s->direction == PA_STREAM_RECORD ? PA_COMMAND_SET_RECORD_STREAM_NAME : PA_COMMAND_SET_PLAYBACK_STREAM_NAME); - pa_tagstruct_putu32(t, tag = s->context->ctag++); + t = pa_tagstruct_command( + s->context, + s->direction == PA_STREAM_RECORD ? PA_COMMAND_SET_RECORD_STREAM_NAME : PA_COMMAND_SET_PLAYBACK_STREAM_NAME, + &tag); pa_tagstruct_putu32(t, s->channel); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(s->context->pstream, t); diff --git a/src/polyp/subscribe.c b/src/polyp/subscribe.c index 65849b6d..a4eadbc6 100644 --- a/src/polyp/subscribe.c +++ b/src/polyp/subscribe.c @@ -72,9 +72,7 @@ pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_c o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, tag = c->ctag++); + t = pa_tagstruct_command(c, PA_COMMAND_SUBSCRIBE, &tag); pa_tagstruct_putu32(t, m); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); -- cgit From 4a64b0d1167e980d81b798d813f35209895f0674 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Feb 2006 02:27:19 +0000 Subject: change pa_log() and friends to not require a trailing \n on all logged strings git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@574 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/caps.c | 6 +-- src/daemon/cmdline.c | 16 +++---- src/daemon/cpulimit.c | 2 +- src/daemon/daemon-conf.c | 8 ++-- src/daemon/main.c | 45 ++++++++++---------- src/modules/alsa-util.c | 2 +- src/modules/howl-wrap.c | 5 +-- src/modules/module-alsa-sink.c | 22 +++++----- src/modules/module-alsa-source.c | 22 +++++----- src/modules/module-cli.c | 6 +-- src/modules/module-combine.c | 26 ++++++------ src/modules/module-detect.c | 14 +++--- src/modules/module-esound-compat-spawnfd.c | 4 +- src/modules/module-esound-compat-spawnpid.c | 4 +- src/modules/module-esound-sink.c | 24 +++++------ src/modules/module-lirc.c | 20 ++++----- src/modules/module-match.c | 12 +++--- src/modules/module-mmkbd-evdev.c | 28 ++++++------ src/modules/module-native-protocol-fd.c | 4 +- src/modules/module-null-sink.c | 6 +-- src/modules/module-oss-mmap.c | 44 +++++++++---------- src/modules/module-oss.c | 30 ++++++------- src/modules/module-pipe-sink.c | 14 +++--- src/modules/module-pipe-source.c | 14 +++--- src/modules/module-protocol-stub.c | 14 +++--- src/modules/module-sine.c | 6 +-- src/modules/module-solaris.c | 30 ++++++------- src/modules/module-tunnel.c | 48 ++++++++++----------- src/modules/module-waveout.c | 28 ++++++------ src/modules/module-x11-bell.c | 10 ++--- src/modules/module-x11-publish.c | 8 ++-- src/modules/module-zeroconf-publish.c | 14 +++--- src/modules/oss-util.c | 22 +++++----- src/polyp/browser.c | 10 ++--- src/polyp/client-conf-x11.c | 4 +- src/polyp/client-conf.c | 2 +- src/polyp/context.c | 12 +++--- src/polyp/mainloop-signal.c | 10 ++--- src/polyp/mainloop.c | 14 +++--- src/polyp/stream.c | 4 +- src/polypcore/authkey.c | 14 +++--- src/polypcore/cli.c | 4 +- src/polypcore/client.c | 6 +-- src/polypcore/conf-parser.c | 12 +++--- src/polypcore/core-scache.c | 4 +- src/polypcore/core-subscribe.c | 2 +- src/polypcore/ioline.c | 4 +- src/polypcore/log.c | 66 ++++++++++++++++++++--------- src/polypcore/memblockq.c | 4 +- src/polypcore/modinfo.c | 2 +- src/polypcore/module.c | 14 +++--- src/polypcore/pdispatch.c | 4 +- src/polypcore/pid.c | 28 ++++++------ src/polypcore/protocol-cli.c | 2 +- src/polypcore/protocol-esound.c | 54 +++++++++++------------ src/polypcore/protocol-http.c | 4 +- src/polypcore/protocol-native.c | 38 ++++++++--------- src/polypcore/protocol-simple.c | 22 +++++----- src/polypcore/pstream.c | 10 ++--- src/polypcore/random.c | 2 +- src/polypcore/sample-util.c | 2 +- src/polypcore/sink-input.c | 6 +-- src/polypcore/sink.c | 6 +-- src/polypcore/socket-client.c | 10 ++--- src/polypcore/socket-server.c | 38 ++++++++--------- src/polypcore/socket-util.c | 6 +-- src/polypcore/sound-file-stream.c | 4 +- src/polypcore/sound-file.c | 12 +++--- src/polypcore/source-output.c | 6 +-- src/polypcore/source.c | 4 +- src/polypcore/util.c | 58 ++++++++++++------------- src/polypcore/x11wrap.c | 2 +- src/utils/pacmd.c | 20 ++++----- src/utils/pax11publish.c | 2 +- 74 files changed, 556 insertions(+), 530 deletions(-) diff --git a/src/daemon/caps.c b/src/daemon/caps.c index e12d33fb..5c52b77a 100644 --- a/src/daemon/caps.c +++ b/src/daemon/caps.c @@ -45,7 +45,7 @@ void pa_drop_root(void) { if (uid == 0 || geteuid() != 0) return; - pa_log_info(__FILE__": dropping root rights.\n"); + pa_log_info(__FILE__": dropping root rights."); #if defined(HAVE_SETRESUID) setresuid(uid, uid, uid); @@ -83,7 +83,7 @@ int pa_limit_caps(void) { if (cap_set_proc(caps) < 0) goto fail; - pa_log_info(__FILE__": dropped capabilities successfully.\n"); + pa_log_info(__FILE__": dropped capabilities successfully."); r = 0; @@ -104,7 +104,7 @@ int pa_drop_caps(void) { cap_clear(caps); if (cap_set_proc(caps) < 0) { - pa_log(__FILE__": failed to drop capabilities: %s\n", strerror(errno)); + pa_log(__FILE__": failed to drop capabilities: %s", strerror(errno)); goto fail; } diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c index b6ab1283..a6b95a81 100644 --- a/src/daemon/cmdline.c +++ b/src/daemon/cmdline.c @@ -191,14 +191,14 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d case ARG_DAEMONIZE: case 'D': if ((conf->daemonize = optarg ? pa_parse_boolean(optarg) : 1) < 0) { - pa_log(__FILE__": --daemonize expects boolean argument\n"); + pa_log(__FILE__": --daemonize expects boolean argument"); goto fail; } break; case ARG_FAIL: if ((conf->fail = optarg ? pa_parse_boolean(optarg) : 1) < 0) { - pa_log(__FILE__": --fail expects boolean argument\n"); + pa_log(__FILE__": --fail expects boolean argument"); goto fail; } break; @@ -208,7 +208,7 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d if (optarg) { if (pa_daemon_conf_set_log_level(conf, optarg) < 0) { - pa_log(__FILE__": --log-level expects log level argument (either numeric in range 0..4 or one of debug, info, notice, warn, error).\n"); + pa_log(__FILE__": --log-level expects log level argument (either numeric in range 0..4 or one of debug, info, notice, warn, error)."); goto fail; } } else { @@ -220,21 +220,21 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d case ARG_HIGH_PRIORITY: if ((conf->high_priority = optarg ? pa_parse_boolean(optarg) : 1) < 0) { - pa_log(__FILE__": --high-priority expects boolean argument\n"); + pa_log(__FILE__": --high-priority expects boolean argument"); goto fail; } break; case ARG_DISALLOW_MODULE_LOADING: if ((conf->disallow_module_loading = optarg ? pa_parse_boolean(optarg) : 1) < 0) { - pa_log(__FILE__": --disallow-module-loading expects boolean argument\n"); + pa_log(__FILE__": --disallow-module-loading expects boolean argument"); goto fail; } break; case ARG_USE_PID_FILE: if ((conf->use_pid_file = optarg ? pa_parse_boolean(optarg) : 1) < 0) { - pa_log(__FILE__": --use-pid-file expects boolean argument\n"); + pa_log(__FILE__": --use-pid-file expects boolean argument"); goto fail; } break; @@ -252,7 +252,7 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d case ARG_LOG_TARGET: if (pa_daemon_conf_set_log_target(conf, optarg) < 0) { - pa_log(__FILE__": Invalid log target: use either 'syslog', 'stderr' or 'auto'.\n"); + pa_log(__FILE__": Invalid log target: use either 'syslog', 'stderr' or 'auto'."); goto fail; } break; @@ -271,7 +271,7 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d case ARG_RESAMPLE_METHOD: if (pa_daemon_conf_set_resample_method(conf, optarg) < 0) { - pa_log(__FILE__": Invalid resample method '%s'.\n", optarg); + pa_log(__FILE__": Invalid resample method '%s'.", optarg); goto fail; } break; diff --git a/src/daemon/cpulimit.c b/src/daemon/cpulimit.c index d7a24b8e..54f111da 100644 --- a/src/daemon/cpulimit.c +++ b/src/daemon/cpulimit.c @@ -169,7 +169,7 @@ int pa_cpu_limit_init(pa_mainloop_api *m) { /* Prepare the main loop pipe */ if (pipe(the_pipe) < 0) { - pa_log(__FILE__": pipe() failed: %s\n", strerror(errno)); + pa_log(__FILE__": pipe() failed: %s", strerror(errno)); return -1; } diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index ecabce40..ac5fbb16 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -160,7 +160,7 @@ static int parse_log_target(const char *filename, unsigned line, const char *lva assert(filename && lvalue && rvalue && data); if (pa_daemon_conf_set_log_target(c, rvalue) < 0) { - pa_log(__FILE__": [%s:%u] Invalid log target '%s'.\n", filename, line, rvalue); + pa_log(__FILE__": [%s:%u] Invalid log target '%s'.", filename, line, rvalue); return -1; } @@ -172,7 +172,7 @@ static int parse_log_level(const char *filename, unsigned line, const char *lval assert(filename && lvalue && rvalue && data); if (pa_daemon_conf_set_log_level(c, rvalue) < 0) { - pa_log(__FILE__": [%s:%u] Invalid log level '%s'.\n", filename, line, rvalue); + pa_log(__FILE__": [%s:%u] Invalid log level '%s'.", filename, line, rvalue); return -1; } @@ -184,7 +184,7 @@ static int parse_resample_method(const char *filename, unsigned line, const char assert(filename && lvalue && rvalue && data); if (pa_daemon_conf_set_resample_method(c, rvalue) < 0) { - pa_log(__FILE__": [%s:%u] Inavalid resample method '%s'.\n", filename, line, rvalue); + pa_log(__FILE__": [%s:%u] Inavalid resample method '%s'.", filename, line, rvalue); return -1; } @@ -236,7 +236,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { pa_open_config_file(DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file); if (!f && errno != ENOENT) { - pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno)); + pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", filename, strerror(errno)); goto finish; } diff --git a/src/daemon/main.c b/src/daemon/main.c index 3124ad1d..4b972fe2 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -94,7 +94,7 @@ static void message_cb(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { #endif static void signal_callback(pa_mainloop_api*m, PA_GCC_UNUSED pa_signal_event *e, int sig, void *userdata) { - pa_log_info(__FILE__": Got signal %s.\n", pa_strsignal(sig)); + pa_log_info(__FILE__": Got signal %s.", pa_strsignal(sig)); switch (sig) { #ifdef SIGUSR1 @@ -112,7 +112,7 @@ static void signal_callback(pa_mainloop_api*m, PA_GCC_UNUSED pa_signal_event *e, #ifdef SIGHUP case SIGHUP: { char *c = pa_full_status_string(userdata); - pa_log_notice(c); + pa_log_notice("%s", c); pa_xfree(c); return; } @@ -121,7 +121,7 @@ static void signal_callback(pa_mainloop_api*m, PA_GCC_UNUSED pa_signal_event *e, case SIGINT: case SIGTERM: default: - pa_log_info(__FILE__": Exiting.\n"); + pa_log_info(__FILE__": Exiting."); m->quit(m, 1); break; } @@ -161,7 +161,7 @@ int main(int argc, char *argv[]) { suid_root = getuid() != 0 && geteuid() == 0; if (suid_root && (pa_uid_in_group("realtime", &gid) <= 0 || gid >= 1000)) { - pa_log_warn(__FILE__": WARNING: called SUID root, but not in group 'realtime'.\n"); + pa_log_warn(__FILE__": WARNING: called SUID root, but not in group 'realtime'."); pa_drop_root(); } #else @@ -191,7 +191,7 @@ int main(int argc, char *argv[]) { goto finish; if (pa_cmdline_parse(conf, argc, argv, &d) < 0) { - pa_log(__FILE__": failed to parse command line.\n"); + pa_log(__FILE__": failed to parse command line."); goto finish; } @@ -237,9 +237,9 @@ int main(int argc, char *argv[]) { pid_t pid; if (pa_pid_file_check_running(&pid) < 0) { - pa_log_info(__FILE__": daemon not running\n"); + pa_log_info(__FILE__": daemon not running"); } else { - pa_log_info(__FILE__": daemon running as PID %u\n", pid); + pa_log_info(__FILE__": daemon running as PID %u", pid); retval = 0; } @@ -249,7 +249,7 @@ int main(int argc, char *argv[]) { case PA_CMD_KILL: if (pa_pid_file_kill(SIGINT, NULL) < 0) - pa_log(__FILE__": failed to kill daemon.\n"); + pa_log(__FILE__": failed to kill daemon."); else retval = 0; @@ -264,18 +264,18 @@ int main(int argc, char *argv[]) { int tty_fd; if (pa_stdio_acquire() < 0) { - pa_log(__FILE__": failed to acquire stdio.\n"); + pa_log(__FILE__": failed to acquire stdio."); goto finish; } #ifdef HAVE_FORK if (pipe(daemon_pipe) < 0) { - pa_log(__FILE__": failed to create pipe.\n"); + pa_log(__FILE__": failed to create pipe."); goto finish; } if ((child = fork()) < 0) { - pa_log(__FILE__": fork() failed: %s\n", strerror(errno)); + pa_log(__FILE__": fork() failed: %s", strerror(errno)); goto finish; } @@ -286,14 +286,14 @@ int main(int argc, char *argv[]) { daemon_pipe[1] = -1; if (pa_loop_read(daemon_pipe[0], &retval, sizeof(retval)) != sizeof(retval)) { - pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + pa_log(__FILE__": read() failed: %s", strerror(errno)); retval = 1; } if (retval) - pa_log(__FILE__": daemon startup failed.\n"); + pa_log(__FILE__": daemon startup failed."); else - pa_log_info(__FILE__": daemon startup successful.\n"); + pa_log_info(__FILE__": daemon startup successful."); goto finish; } @@ -346,7 +346,7 @@ int main(int argc, char *argv[]) { if (conf->use_pid_file) { if (pa_pid_file_create() < 0) { - pa_log(__FILE__": pa_pid_file_create() failed.\n"); + pa_log(__FILE__": pa_pid_file_create() failed."); #ifdef HAVE_FORK if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); @@ -396,23 +396,22 @@ int main(int argc, char *argv[]) { assert(r == 0); buf = pa_strbuf_new(); - assert(buf); if (conf->default_script_file) r = pa_cli_command_execute_file(c, conf->default_script_file, buf, &conf->fail); if (r >= 0) r = pa_cli_command_execute(c, conf->script_commands, buf, &conf->fail); - pa_log(s = pa_strbuf_tostring_free(buf)); + pa_log_error("%s", s = pa_strbuf_tostring_free(buf)); pa_xfree(s); if (r < 0 && conf->fail) { - pa_log(__FILE__": failed to initialize daemon.\n"); + pa_log(__FILE__": failed to initialize daemon."); #ifdef HAVE_FORK if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); #endif } else if (!c->modules || pa_idxset_size(c->modules) == 0) { - pa_log(__FILE__": daemon startup without any loaded modules, refusing to work.\n"); + pa_log(__FILE__": daemon startup without any loaded modules, refusing to work."); #ifdef HAVE_FORK if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); @@ -433,13 +432,13 @@ int main(int argc, char *argv[]) { if (c->default_sink_name && pa_namereg_get(c, c->default_sink_name, PA_NAMEREG_SINK, 1) == NULL) { - pa_log_error("%s : Fatal error. Default sink name (%s) does not exist in name register.\n", __FILE__, c->default_sink_name); + pa_log_error("%s : Fatal error. Default sink name (%s) does not exist in name register.", __FILE__, c->default_sink_name); retval = 1; } else { - pa_log_info(__FILE__": Daemon startup complete.\n"); + pa_log_info(__FILE__": Daemon startup complete."); if (pa_mainloop_run(mainloop, &retval) < 0) retval = 1; - pa_log_info(__FILE__": Daemon shutdown initiated.\n"); + pa_log_info(__FILE__": Daemon shutdown initiated."); } } @@ -453,7 +452,7 @@ int main(int argc, char *argv[]) { pa_signal_done(); pa_mainloop_free(mainloop); - pa_log_info(__FILE__": Daemon terminated.\n"); + pa_log_info(__FILE__": Daemon terminated."); finish: diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 68e9f975..1b254f51 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -63,7 +63,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint3 goto finish; if (ss->rate != r) - pa_log_info(__FILE__": device doesn't support %u Hz, changed to %u Hz.\n", ss->rate, r); + pa_log_info(__FILE__": device doesn't support %u Hz, changed to %u Hz.", ss->rate, r); if (snd_pcm_prepare(pcm_handle) < 0) goto finish; diff --git a/src/modules/howl-wrap.c b/src/modules/howl-wrap.c index b3fe8166..f4605fb2 100644 --- a/src/modules/howl-wrap.c +++ b/src/modules/howl-wrap.c @@ -35,7 +35,6 @@ struct pa_howl_wrapper { pa_io_event *io_event; sw_discovery discovery; - }; static void howl_io_event(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { @@ -51,7 +50,7 @@ static void howl_io_event(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event return; fail: - pa_log(__FILE__": howl connection died.\n"); + pa_log_error(__FILE__": howl connection died."); w->core->mainloop->io_free(w->io_event); w->io_event = NULL; } @@ -62,7 +61,7 @@ static pa_howl_wrapper* howl_wrapper_new(pa_core *c) { assert(c); if (sw_discovery_init(&session) != SW_OKAY) { - pa_log("sw_discovery_init() failed.\n"); + pa_log_error(__FILE__": sw_discovery_init() failed."); return NULL; } diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 6ea1e137..e37367c8 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -86,10 +86,10 @@ static void update_usage(struct userdata *u) { static void xrun_recovery(struct userdata *u) { assert(u); - pa_log(__FILE__": *** ALSA-XRUN (playback) ***\n"); + pa_log(__FILE__": *** ALSA-XRUN (playback) ***"); if (snd_pcm_prepare(u->pcm_handle) < 0) - pa_log(__FILE__": snd_pcm_prepare() failed\n"); + pa_log(__FILE__": snd_pcm_prepare() failed"); } static void do_write(struct userdata *u) { @@ -121,7 +121,7 @@ static void do_write(struct userdata *u) { continue; } - pa_log(__FILE__": snd_pcm_writei() failed\n"); + pa_log(__FILE__": snd_pcm_writei() failed"); return; } @@ -158,7 +158,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { assert(s && u && u->sink); if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { - pa_log(__FILE__": failed to get delay\n"); + pa_log(__FILE__": failed to get delay"); s->get_latency = NULL; return 0; } @@ -186,13 +186,13 @@ int pa__init(pa_core *c, pa_module*m) { int err; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); + pa_log(__FILE__": failed to parse module arguments"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": failed to parse sample specification\n"); + pa_log(__FILE__": failed to parse sample specification"); goto fail; } frame_size = pa_frame_size(&ss); @@ -200,7 +200,7 @@ int pa__init(pa_core *c, pa_module*m) { periods = 8; fragsize = 1024; if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { - pa_log(__FILE__": failed to parse buffer metrics\n"); + pa_log(__FILE__": failed to parse buffer metrics"); goto fail; } period_size = fragsize; @@ -211,12 +211,12 @@ int pa__init(pa_core *c, pa_module*m) { snd_config_update_free_global(); if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { - pa_log(__FILE__": Error opening PCM device %s: %s\n", dev, snd_strerror(err)); + pa_log(__FILE__": Error opening PCM device %s: %s", dev, snd_strerror(err)); goto fail; } if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) { - pa_log(__FILE__": Failed to set hardware parameters: %s\n", snd_strerror(err)); + pa_log(__FILE__": Failed to set hardware parameters: %s", snd_strerror(err)); goto fail; } @@ -229,14 +229,14 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); if (pa_create_io_events(u->pcm_handle, c->mainloop, &u->io_events, &u->n_io_events, io_callback, u) < 0) { - pa_log(__FILE__": failed to obtain file descriptors\n"); + pa_log(__FILE__": failed to obtain file descriptors"); goto fail; } u->frame_size = frame_size; u->fragment_size = period_size; - pa_log_info(__FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); + pa_log_info(__FILE__": using %u fragments of size %u bytes.", periods, u->fragment_size); u->silence.memblock = pa_memblock_new(u->silence.length = u->fragment_size, c->memblock_stat); assert(u->silence.memblock); diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 4f281aa7..bf031350 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -85,10 +85,10 @@ static void update_usage(struct userdata *u) { static void xrun_recovery(struct userdata *u) { assert(u); - pa_log(__FILE__": *** ALSA-XRUN (capture) ***\n"); + pa_log(__FILE__": *** ALSA-XRUN (capture) ***"); if (snd_pcm_prepare(u->pcm_handle) < 0) - pa_log(__FILE__": snd_pcm_prepare() failed\n"); + pa_log(__FILE__": snd_pcm_prepare() failed"); } static void do_read(struct userdata *u) { @@ -117,7 +117,7 @@ static void do_read(struct userdata *u) { continue; } - pa_log(__FILE__": snd_pcm_readi() failed: %s\n", strerror(-frames)); + pa_log(__FILE__": snd_pcm_readi() failed: %s", strerror(-frames)); return; } @@ -157,7 +157,7 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { assert(s && u && u->source); if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { - pa_log(__FILE__": failed to get delay\n"); + pa_log(__FILE__": failed to get delay"); s->get_latency = NULL; return 0; } @@ -177,13 +177,13 @@ int pa__init(pa_core *c, pa_module*m) { int err; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); + pa_log(__FILE__": failed to parse module arguments"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": failed to parse sample specification\n"); + pa_log(__FILE__": failed to parse sample specification"); goto fail; } frame_size = pa_frame_size(&ss); @@ -191,7 +191,7 @@ int pa__init(pa_core *c, pa_module*m) { periods = 12; fragsize = 1024; if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { - pa_log(__FILE__": failed to parse buffer metrics\n"); + pa_log(__FILE__": failed to parse buffer metrics"); goto fail; } period_size = fragsize; @@ -202,12 +202,12 @@ int pa__init(pa_core *c, pa_module*m) { snd_config_update_free_global(); if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { - pa_log(__FILE__": Error opening PCM device %s: %s\n", dev, snd_strerror(err)); + pa_log(__FILE__": Error opening PCM device %s: %s", dev, snd_strerror(err)); goto fail; } if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) { - pa_log(__FILE__": Failed to set hardware parameters: %s\n", snd_strerror(err)); + pa_log(__FILE__": Failed to set hardware parameters: %s", snd_strerror(err)); goto fail; } @@ -220,14 +220,14 @@ int pa__init(pa_core *c, pa_module*m) { u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); if (pa_create_io_events(u->pcm_handle, c->mainloop, &u->io_events, &u->n_io_events, io_callback, u) < 0) { - pa_log(__FILE__": failed to obtain file descriptors\n"); + pa_log(__FILE__": failed to obtain file descriptors"); goto fail; } u->frame_size = frame_size; u->fragment_size = period_size; - pa_log(__FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); + pa_log(__FILE__": using %u fragments of size %u bytes.", periods, u->fragment_size); u->memchunk.memblock = NULL; u->memchunk.index = u->memchunk.length = 0; diff --git a/src/modules/module-cli.c b/src/modules/module-cli.c index c782ff8d..41e33c7f 100644 --- a/src/modules/module-cli.c +++ b/src/modules/module-cli.c @@ -52,17 +52,17 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (c->running_as_daemon) { - pa_log_info(__FILE__": Running as daemon so won't load this module.\n"); + pa_log_info(__FILE__": Running as daemon so won't load this module."); return 0; } if (m->argument) { - pa_log(__FILE__": module doesn't accept arguments.\n"); + pa_log(__FILE__": module doesn't accept arguments."); return -1; } if (pa_stdio_acquire() < 0) { - pa_log(__FILE__": STDIN/STDUSE already in use.\n"); + pa_log(__FILE__": STDIN/STDUSE already in use."); return -1; } diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 750eca67..28e85427 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -112,7 +112,7 @@ static void adjust_rates(struct userdata *u) { target_latency = max_sink_latency > min_total_latency ? max_sink_latency : min_total_latency; - pa_log_info(__FILE__": [%s] target latency is %0.0f usec.\n", u->sink->name, (float) target_latency); + pa_log_info(__FILE__": [%s] target latency is %0.0f usec.", u->sink->name, (float) target_latency); base_rate = u->sink->sample_spec.rate; @@ -125,9 +125,9 @@ static void adjust_rates(struct userdata *u) { r += (uint32_t) (((((double) o->total_latency - target_latency))/u->adjust_time)*r/ 1000000); if (r < (uint32_t) (base_rate*0.9) || r > (uint32_t) (base_rate*1.1)) - pa_log_warn(__FILE__": [%s] sample rates too different, not adjusting (%u vs. %u).\n", o->sink_input->name, base_rate, r); + pa_log_warn(__FILE__": [%s] sample rates too different, not adjusting (%u vs. %u).", o->sink_input->name, base_rate, r); else { - pa_log_info(__FILE__": [%s] new rate is %u Hz; ratio is %0.3f; latency is %0.0f usec.\n", o->sink_input->name, r, (double) r / base_rate, (float) o->total_latency); + pa_log_info(__FILE__": [%s] new rate is %u Hz; ratio is %0.3f; latency is %0.0f usec.", o->sink_input->name, r, (double) r / base_rate, (float) o->total_latency); pa_sink_input_set_rate(o->sink_input, r); } } @@ -297,13 +297,13 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); + pa_log(__FILE__": failed to parse module arguments"); goto fail; } if ((rm = pa_modargs_get_value(ma, "resample_method", NULL))) { if ((resample_method = pa_parse_resample_method(rm)) < 0) { - pa_log(__FILE__": invalid resample method '%s'\n", rm); + pa_log(__FILE__": invalid resample method '%s'", rm); goto fail; } } @@ -320,22 +320,22 @@ int pa__init(pa_core *c, pa_module*m) { PA_LLIST_HEAD_INIT(struct output, u->outputs); if (pa_modargs_get_value_u32(ma, "adjust_time", &u->adjust_time) < 0) { - pa_log(__FILE__": failed to parse adjust_time value\n"); + pa_log(__FILE__": failed to parse adjust_time value"); goto fail; } if (!(master_name = pa_modargs_get_value(ma, "master", NULL)) || !(slaves = pa_modargs_get_value(ma, "slaves", NULL))) { - pa_log(__FILE__": no master or slave sinks specified\n"); + pa_log(__FILE__": no master or slave sinks specified"); goto fail; } if (!(master_sink = pa_namereg_get(c, master_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": invalid master sink '%s'\n", master_name); + pa_log(__FILE__": invalid master sink '%s'", master_name); goto fail; } if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &master_sink->sample_spec, &master_sink->channel_map))) { - pa_log(__FILE__": failed to create sink\n"); + pa_log(__FILE__": failed to create sink"); goto fail; } @@ -345,7 +345,7 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->userdata = u; if (!(u->master = output_new(u, master_sink, resample_method))) { - pa_log(__FILE__": failed to create master sink input on sink '%s'.\n", u->sink->name); + pa_log(__FILE__": failed to create master sink input on sink '%s'.", u->sink->name); goto fail; } @@ -354,20 +354,20 @@ int pa__init(pa_core *c, pa_module*m) { pa_sink *slave_sink; if (!(slave_sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": invalid slave sink '%s'\n", n); + pa_log(__FILE__": invalid slave sink '%s'", n); goto fail; } pa_xfree(n); if (!output_new(u, slave_sink, resample_method)) { - pa_log(__FILE__": failed to create slave sink input on sink '%s'.\n", slave_sink->name); + pa_log(__FILE__": failed to create slave sink input on sink '%s'.", slave_sink->name); goto fail; } } if (u->n_outputs <= 1) - pa_log_warn(__FILE__": WARNING: no slave sinks specified.\n"); + pa_log_warn(__FILE__": WARNING: no slave sinks specified."); if (u->adjust_time > 0) { pa_gettimeofday(&tv); diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index 18e22de6..b24d838b 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -66,7 +66,7 @@ static int detect_alsa(pa_core *c, int just_one) { if (!(f = fopen("/proc/asound/devices", "r"))) { if (errno != ENOENT) - pa_log_error(__FILE__": open(\"/proc/asound/devices\") failed: %s\n", strerror(errno)); + pa_log_error(__FILE__": open(\"/proc/asound/devices\") failed: %s", strerror(errno)); return -1; } @@ -129,7 +129,7 @@ static int detect_oss(pa_core *c, int just_one) { !(f = fopen("/proc/asound/oss/sndstat", "r"))) { if (errno != ENOENT) - pa_log_error(__FILE__": failed to open OSS sndstat device: %s\n", strerror(errno)); + pa_log_error(__FILE__": failed to open OSS sndstat device: %s", strerror(errno)); return -1; } @@ -185,7 +185,7 @@ static int detect_solaris(pa_core *c, int just_one) { if (stat(dev, &s) < 0) { if (errno != ENOENT) - pa_log_error(__FILE__": failed to open device %s: %s\n", dev, strerror(errno)); + pa_log_error(__FILE__": failed to open device %s: %s", dev, strerror(errno)); return -1; } @@ -227,12 +227,12 @@ int pa__init(pa_core *c, pa_module*m) { assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments\n"); + pa_log(__FILE__": Failed to parse module arguments"); goto fail; } if (pa_modargs_get_value_boolean(ma, "just-one", &just_one) < 0) { - pa_log(__FILE__": just_one= expects a boolean argument.\n"); + pa_log(__FILE__": just_one= expects a boolean argument."); goto fail; } @@ -249,11 +249,11 @@ int pa__init(pa_core *c, pa_module*m) { if ((n = detect_waveout(c, just_one)) <= 0) #endif { - pa_log_warn(__FILE__": failed to detect any sound hardware.\n"); + pa_log_warn(__FILE__": failed to detect any sound hardware."); goto fail; } - pa_log_info(__FILE__": loaded %i modules.\n", n); + pa_log_info(__FILE__": loaded %i modules.", n); /* We were successful and can unload ourselves now. */ pa_module_unload_request(m); diff --git a/src/modules/module-esound-compat-spawnfd.c b/src/modules/module-esound-compat-spawnfd.c index 5c656be9..9b72448f 100644 --- a/src/modules/module-esound-compat-spawnfd.c +++ b/src/modules/module-esound-compat-spawnfd.c @@ -54,12 +54,12 @@ int pa__init(pa_core *c, pa_module*m) { if (!(ma = pa_modargs_new(m->argument, valid_modargs)) || pa_modargs_get_value_s32(ma, "fd", &fd) < 0 || fd < 0) { - pa_log(__FILE__": Failed to parse module arguments\n"); + pa_log(__FILE__": Failed to parse module arguments"); goto finish; } if (pa_loop_write(fd, &x, sizeof(x)) != sizeof(x)) - pa_log(__FILE__": WARNING: write(%u, 1, 1) failed: %s\n", fd, strerror(errno)); + pa_log(__FILE__": WARNING: write(%u, 1, 1) failed: %s", fd, strerror(errno)); close(fd); diff --git a/src/modules/module-esound-compat-spawnpid.c b/src/modules/module-esound-compat-spawnpid.c index 5daa1297..f8c07d31 100644 --- a/src/modules/module-esound-compat-spawnpid.c +++ b/src/modules/module-esound-compat-spawnpid.c @@ -54,12 +54,12 @@ int pa__init(pa_core *c, pa_module*m) { if (!(ma = pa_modargs_new(m->argument, valid_modargs)) || pa_modargs_get_value_u32(ma, "pid", &pid) < 0 || !pid) { - pa_log(__FILE__": Failed to parse module arguments\n"); + pa_log(__FILE__": Failed to parse module arguments"); goto finish; } if (kill(pid, SIGUSR1) < 0) - pa_log(__FILE__": WARNING: kill(%u) failed: %s\n", pid, strerror(errno)); + pa_log(__FILE__": WARNING: kill(%u) failed: %s", pid, strerror(errno)); pa_module_unload_request(m); diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index 4f724811..1cc75502 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -127,7 +127,7 @@ static int do_write(struct userdata *u) { assert(u->write_index < u->write_length); if ((r = pa_iochannel_write(u->io, (uint8_t*) u->write_data + u->write_index, u->write_length - u->write_index)) <= 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + pa_log(__FILE__": write() failed: %s", strerror(errno)); return -1; } @@ -149,7 +149,7 @@ static int do_write(struct userdata *u) { assert(u->memchunk.memblock && u->memchunk.length); if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + pa_log(__FILE__": write() failed: %s", strerror(errno)); return -1; } @@ -174,7 +174,7 @@ static int handle_response(struct userdata *u) { /* Process auth data */ if (!*(int32_t*) u->read_data) { - pa_log(__FILE__": Authentication failed: %s\n", strerror(errno)); + pa_log(__FILE__": Authentication failed: %s", strerror(errno)); return -1; } @@ -199,7 +199,7 @@ static int handle_response(struct userdata *u) { /* Process latency info */ u->latency = (pa_usec_t) ((double) (*(int32_t*) u->read_data) * 1000000 / 44100); if (u->latency > 10000000) { - pa_log(__FILE__": WARNING! Invalid latency information received from server\n"); + pa_log(__FILE__": WARNING! Invalid latency information received from server"); u->latency = 0; } @@ -244,7 +244,7 @@ static int do_read(struct userdata *u) { assert(u->read_index < u->read_length); if ((r = pa_iochannel_read(u->io, (uint8_t*) u->read_data + u->read_index, u->read_length - u->read_index)) <= 0) { - pa_log(__FILE__": read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); + pa_log(__FILE__": read() failed: %s", r < 0 ? strerror(errno) : "EOF"); cancel(u); return -1; } @@ -304,7 +304,7 @@ static void on_connection(PA_GCC_UNUSED pa_socket_client *c, pa_iochannel*io, vo u->client = NULL; if (!io) { - pa_log(__FILE__": connection failed: %s\n", strerror(errno)); + pa_log(__FILE__": connection failed: %s", strerror(errno)); cancel(u); return; } @@ -321,19 +321,19 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); + pa_log(__FILE__": failed to parse module arguments"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": invalid sample format specification\n"); + pa_log(__FILE__": invalid sample format specification"); goto fail; } if ((ss.format != PA_SAMPLE_U8 && ss.format != PA_SAMPLE_S16NE) || (ss.channels > 2)) { - pa_log(__FILE__": esound sample type support is limited to mono/stereo and U8 or S16NE sample data\n"); + pa_log(__FILE__": esound sample type support is limited to mono/stereo and U8 or S16NE sample data"); goto fail; } @@ -354,12 +354,12 @@ int pa__init(pa_core *c, pa_module*m) { u->latency = 0; if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { - pa_log(__FILE__": failed to create sink.\n"); + pa_log(__FILE__": failed to create sink."); goto fail; } if (!(u->client = pa_socket_client_new_string(u->core->mainloop, p = pa_modargs_get_value(ma, "server", ESD_UNIX_SOCKET_NAME), ESD_DEFAULT_PORT))) { - pa_log(__FILE__": failed to connect to server.\n"); + pa_log(__FILE__": failed to connect to server."); goto fail; } pa_socket_client_set_callback(u->client, on_connection, u); @@ -367,7 +367,7 @@ int pa__init(pa_core *c, pa_module*m) { /* Prepare the initial request */ u->write_data = pa_xmalloc(u->write_length = ESD_KEY_LEN + sizeof(int32_t)); if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", ".esd_auth"), u->write_data, ESD_KEY_LEN) < 0) { - pa_log(__FILE__": failed to load cookie\n"); + pa_log(__FILE__": failed to load cookie"); goto fail; } *(int32_t*) ((uint8_t*) u->write_data + ESD_KEY_LEN) = ESD_ENDIAN_KEY; diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c index ea8a2bd2..3bb0dc74 100644 --- a/src/modules/module-lirc.c +++ b/src/modules/module-lirc.c @@ -69,7 +69,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC assert(u); if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { - pa_log(__FILE__": lost connection to LIRC daemon.\n"); + pa_log(__FILE__": lost connection to LIRC daemon."); goto fail; } @@ -77,19 +77,19 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC char *c; if (lirc_nextcode(&code) != 0 || !code) { - pa_log(__FILE__": lirc_nextcode() failed.\n"); + pa_log(__FILE__": lirc_nextcode() failed."); goto fail; } c = pa_xstrdup(code); c[strcspn(c, "\n\r")] = 0; - pa_log_debug(__FILE__": raw IR code '%s'\n", c); + pa_log_debug(__FILE__": raw IR code '%s'", c); pa_xfree(c); while (lirc_code2char(u->config, code, &name) == 0 && name) { enum { INVALID, UP, DOWN, MUTE, RESET, MUTE_TOGGLE } volchange = INVALID; - pa_log_info(__FILE__": translated IR code '%s'\n", name); + pa_log_info(__FILE__": translated IR code '%s'", name); if (strcasecmp(name, "volume-up") == 0) volchange = UP; @@ -103,12 +103,12 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC volchange = RESET; if (volchange == INVALID) - pa_log_warn(__FILE__": recieved unknown IR code '%s'\n", name); + pa_log_warn(__FILE__": recieved unknown IR code '%s'", name); else { pa_sink *s; if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) - pa_log(__FILE__": failed to get sink '%s'\n", u->sink_name); + pa_log(__FILE__": failed to get sink '%s'", u->sink_name); else { pa_volume_t v = pa_cvolume_avg(pa_sink_get_volume(s, PA_MIXER_HARDWARE)); pa_cvolume cv; @@ -173,12 +173,12 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (lirc_in_use) { - pa_log(__FILE__": module-lirc may no be loaded twice.\n"); + pa_log(__FILE__": module-lirc may no be loaded twice."); return -1; } if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments\n"); + pa_log(__FILE__": Failed to parse module arguments"); goto fail; } @@ -191,12 +191,12 @@ int pa__init(pa_core *c, pa_module*m) { u->mute_toggle_save = 0; if ((u->lirc_fd = lirc_init((char*) pa_modargs_get_value(ma, "appname", "polypaudio"), 1)) < 0) { - pa_log(__FILE__": lirc_init() failed.\n"); + pa_log(__FILE__": lirc_init() failed."); goto fail; } if (lirc_readconfig((char*) pa_modargs_get_value(ma, "config", NULL), &u->config, NULL) < 0) { - pa_log(__FILE__": lirc_readconfig() failed.\n"); + pa_log(__FILE__": lirc_readconfig() failed."); goto fail; } diff --git a/src/modules/module-match.c b/src/modules/module-match.c index 1fb7233c..59817517 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -84,7 +84,7 @@ static int load_rules(struct userdata *u, const char *filename) { pa_open_config_file(DEFAULT_MATCH_TABLE_FILE, DEFAULT_MATCH_TABLE_FILE_USER, NULL, &fn); if (!f) { - pa_log(__FILE__": failed to open file '%s': %s\n", fn, strerror(errno)); + pa_log(__FILE__": failed to open file '%s': %s", fn, strerror(errno)); goto finish; } @@ -111,13 +111,13 @@ static int load_rules(struct userdata *u, const char *filename) { if (!*v) { - pa_log(__FILE__ ": [%s:%u] failed to parse line - too few words\n", filename, n); + pa_log(__FILE__ ": [%s:%u] failed to parse line - too few words", filename, n); goto finish; } *d = 0; if (pa_atou(v, &k) < 0) { - pa_log(__FILE__": [%s:%u] failed to parse volume\n", filename, n); + pa_log(__FILE__": [%s:%u] failed to parse volume", filename, n); goto finish; } @@ -125,7 +125,7 @@ static int load_rules(struct userdata *u, const char *filename) { if (regcomp(®ex, ln, REG_EXTENDED|REG_NOSUB) != 0) { - pa_log(__FILE__": [%s:%u] invalid regular expression\n", filename, n); + pa_log(__FILE__": [%s:%u] invalid regular expression", filename, n); goto finish; } @@ -173,7 +173,7 @@ static void callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, v for (r = u->rules; r; r = r->next) { if (!regexec(&r->regex, si->name, 0, NULL, 0)) { pa_cvolume cv; - pa_log_debug(__FILE__": changing volume of sink input '%s' to 0x%03x\n", si->name, r->volume); + pa_log_debug(__FILE__": changing volume of sink input '%s' to 0x%03x", si->name, r->volume); pa_cvolume_set(&cv, r->volume, si->sample_spec.channels); pa_sink_input_set_volume(si, &cv); } @@ -186,7 +186,7 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments\n"); + pa_log(__FILE__": Failed to parse module arguments"); goto fail; } diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c index b60f786d..79194ad8 100644 --- a/src/modules/module-mmkbd-evdev.c +++ b/src/modules/module-mmkbd-evdev.c @@ -81,7 +81,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC assert(u); if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { - pa_log(__FILE__": lost connection to evdev device.\n"); + pa_log(__FILE__": lost connection to evdev device."); goto fail; } @@ -89,14 +89,14 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC struct input_event ev; if (pa_loop_read(u->fd, &ev, sizeof(ev)) <= 0) { - pa_log(__FILE__": failed to read from event device: %s\n", strerror(errno)); + pa_log(__FILE__": failed to read from event device: %s", strerror(errno)); goto fail; } if (ev.type == EV_KEY && (ev.value == 1 || ev.value == 2)) { enum { INVALID, UP, DOWN, MUTE_TOGGLE } volchange = INVALID; - pa_log_debug(__FILE__": key code=%u, value=%u\n", ev.code, ev.value); + pa_log_debug(__FILE__": key code=%u, value=%u", ev.code, ev.value); switch (ev.code) { case KEY_VOLUMEDOWN: volchange = DOWN; break; @@ -108,7 +108,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC pa_sink *s; if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) - pa_log(__FILE__": failed to get sink '%s'\n", u->sink_name); + pa_log(__FILE__": failed to get sink '%s'", u->sink_name); else { pa_volume_t v = pa_cvolume_avg(pa_sink_get_volume(s, PA_MIXER_HARDWARE)); pa_cvolume cv; @@ -167,7 +167,7 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments\n"); + pa_log(__FILE__": Failed to parse module arguments"); goto fail; } @@ -179,40 +179,40 @@ int pa__init(pa_core *c, pa_module*m) { u->mute_toggle_save = 0; if ((u->fd = open(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), O_RDONLY)) < 0) { - pa_log(__FILE__": failed to open evdev device: %s\n", strerror(errno)); + pa_log(__FILE__": failed to open evdev device: %s", strerror(errno)); goto fail; } if (ioctl(u->fd, EVIOCGVERSION, &version) < 0) { - pa_log(__FILE__": EVIOCGVERSION failed: %s\n", strerror(errno)); + pa_log(__FILE__": EVIOCGVERSION failed: %s", strerror(errno)); goto fail; } - pa_log_info(__FILE__": evdev driver version %i.%i.%i\n", version >> 16, (version >> 8) & 0xff, version & 0xff); + pa_log_info(__FILE__": evdev driver version %i.%i.%i", version >> 16, (version >> 8) & 0xff, version & 0xff); if(ioctl(u->fd, EVIOCGID, &input_id)) { - pa_log(__FILE__": EVIOCGID failed: %s\n", strerror(errno)); + pa_log(__FILE__": EVIOCGID failed: %s", strerror(errno)); goto fail; } - pa_log_info(__FILE__": evdev vendor 0x%04hx product 0x%04hx version 0x%04hx bustype %u\n", + pa_log_info(__FILE__": evdev vendor 0x%04hx product 0x%04hx version 0x%04hx bustype %u", input_id.vendor, input_id.product, input_id.version, input_id.bustype); if(ioctl(u->fd, EVIOCGNAME(sizeof(name)), name) < 0) { - pa_log(__FILE__": EVIOCGNAME failed: %s\n", strerror(errno)); + pa_log(__FILE__": EVIOCGNAME failed: %s", strerror(errno)); goto fail; } - pa_log_info(__FILE__": evdev device name: %s\n", name); + pa_log_info(__FILE__": evdev device name: %s", name); memset(evtype_bitmask, 0, sizeof(evtype_bitmask)); if (ioctl(u->fd, EVIOCGBIT(0, EV_MAX), evtype_bitmask) < 0) { - pa_log(__FILE__": EVIOCGBIT failed: %s\n", strerror(errno)); + pa_log(__FILE__": EVIOCGBIT failed: %s", strerror(errno)); goto fail; } if (!test_bit(EV_KEY, evtype_bitmask)) { - pa_log(__FILE__": device has no keys.\n"); + pa_log(__FILE__": device has no keys."); goto fail; } diff --git a/src/modules/module-native-protocol-fd.c b/src/modules/module-native-protocol-fd.c index abc531b3..e3caf55a 100644 --- a/src/modules/module-native-protocol-fd.c +++ b/src/modules/module-native-protocol-fd.c @@ -53,12 +53,12 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments.\n"); + pa_log(__FILE__": failed to parse module arguments."); goto finish; } if (pa_modargs_get_value_s32(ma, "fd", &fd) < 0) { - pa_log(__FILE__": invalid file descriptor.\n"); + pa_log(__FILE__": invalid file descriptor."); goto finish; } diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index 5731a403..61178239 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -92,13 +92,13 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments.\n"); + pa_log(__FILE__": failed to parse module arguments."); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": invalid sample format specification.\n"); + pa_log(__FILE__": invalid sample format specification."); goto fail; } @@ -108,7 +108,7 @@ int pa__init(pa_core *c, pa_module*m) { m->userdata = u; if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { - pa_log(__FILE__": failed to create sink.\n"); + pa_log(__FILE__": failed to create sink."); goto fail; } diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index 82f65a3c..9687c908 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -130,7 +130,7 @@ static void do_write(struct userdata *u) { update_usage(u); if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETOPTR: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETOPTR: %s", strerror(errno)); return; } @@ -192,7 +192,7 @@ static void do_read(struct userdata *u) { update_usage(u); if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETIPTR: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETIPTR: %s", strerror(errno)); return; } @@ -225,7 +225,7 @@ static int sink_get_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; if (pa_oss_get_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support reading mixer settings: %s\n", strerror(errno)); + pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", strerror(errno)); s->get_hw_volume = NULL; return -1; } @@ -237,7 +237,7 @@ static int sink_set_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; if (pa_oss_set_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support writing mixer settings: %s\n", strerror(errno)); + pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", strerror(errno)); s->set_hw_volume = NULL; return -1; } @@ -265,17 +265,17 @@ int pa__init(pa_core *c, pa_module*m) { u->core = c; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments.\n"); + pa_log(__FILE__": failed to parse module arguments."); goto fail; } if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { - pa_log(__FILE__": record= and playback= expect numeric arguments.\n"); + pa_log(__FILE__": record= and playback= expect numeric arguments."); goto fail; } if (!playback && !record) { - pa_log(__FILE__": neither playback nor record enabled for device.\n"); + pa_log(__FILE__": neither playback nor record enabled for device."); goto fail; } @@ -284,13 +284,13 @@ int pa__init(pa_core *c, pa_module*m) { nfrags = 12; frag_size = 1024; if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { - pa_log(__FILE__": failed to parse fragments arguments\n"); + pa_log(__FILE__": failed to parse fragments arguments"); goto fail; } u->sample_spec = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &u->sample_spec) < 0) { - pa_log(__FILE__": failed to parse sample specification\n"); + pa_log(__FILE__": failed to parse sample specification"); goto fail; } @@ -298,16 +298,16 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; if (pa_oss_get_hw_description(p, hwdesc, sizeof(hwdesc)) >= 0) - pa_log_info(__FILE__": hardware name is '%s'.\n", hwdesc); + pa_log_info(__FILE__": hardware name is '%s'.", hwdesc); else hwdesc[0] = 0; if (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_REALTIME) || !(caps & DSP_CAP_TRIGGER)) { - pa_log(__FILE__": OSS device not mmap capable.\n"); + pa_log(__FILE__": OSS device not mmap capable."); goto fail; } - pa_log_info(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + pa_log_info(__FILE__": device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); if (nfrags >= 2 && frag_size >= 1) if (pa_oss_set_fragments(u->fd, nfrags, frag_size) < 0) @@ -318,19 +318,19 @@ int pa__init(pa_core *c, pa_module*m) { if (mode != O_WRONLY) { if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETISPACE: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETISPACE: %s", strerror(errno)); goto fail; } - pa_log_info(__FILE__": input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + pa_log_info(__FILE__": input -- %u fragments of size %u.", info.fragstotal, info.fragsize); u->in_mmap_length = (u->in_fragment_size = info.fragsize) * (u->in_fragments = info.fragstotal); if ((u->in_mmap = mmap(NULL, u->in_mmap_length, PROT_READ, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { if (mode == O_RDWR) { - pa_log(__FILE__": mmap failed for input. Changing to O_WRONLY mode.\n"); + pa_log(__FILE__": mmap failed for input. Changing to O_WRONLY mode."); mode = O_WRONLY; } else { - pa_log(__FILE__": mmap(): %s\n", strerror(errno)); + pa_log(__FILE__": mmap(): %s", strerror(errno)); goto fail; } } else { @@ -353,19 +353,19 @@ int pa__init(pa_core *c, pa_module*m) { if (mode != O_RDONLY) { if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETOSPACE: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETOSPACE: %s", strerror(errno)); goto fail; } - pa_log_info(__FILE__": output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + pa_log_info(__FILE__": output -- %u fragments of size %u.", info.fragstotal, info.fragsize); u->out_mmap_length = (u->out_fragment_size = info.fragsize) * (u->out_fragments = info.fragstotal); if ((u->out_mmap = mmap(NULL, u->out_mmap_length, PROT_WRITE, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { if (mode == O_RDWR) { - pa_log(__FILE__": mmap filed for output. Changing to O_RDONLY mode.\n"); + pa_log(__FILE__": mmap filed for output. Changing to O_RDONLY mode."); mode = O_RDONLY; } else { - pa_log(__FILE__": mmap(): %s\n", strerror(errno)); + pa_log(__FILE__": mmap(): %s", strerror(errno)); goto fail; } } else { @@ -392,12 +392,12 @@ int pa__init(pa_core *c, pa_module*m) { zero = 0; if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero) < 0) { - pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s", strerror(errno)); goto fail; } if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0) { - pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s", strerror(errno)); goto fail; } diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 0a3c6143..67ece5a7 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -133,7 +133,7 @@ static void do_write(struct userdata *u) { assert(memchunk->length); if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + pa_log(__FILE__": write() failed: %s", strerror(errno)); break; } @@ -186,7 +186,7 @@ static void do_read(struct userdata *u) { if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); if (errno != EAGAIN) - pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + pa_log(__FILE__": read() failed: %s", strerror(errno)); break; } @@ -221,7 +221,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { assert(s && u && u->sink); if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { - pa_log_info(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY: %s\n", strerror(errno)); + pa_log_info(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY: %s", strerror(errno)); s->get_latency = NULL; return 0; } @@ -257,7 +257,7 @@ static int sink_get_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; if (pa_oss_get_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support reading mixer settings: %s\n", strerror(errno)); + pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", strerror(errno)); s->get_hw_volume = NULL; return -1; } @@ -269,7 +269,7 @@ static int sink_set_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; if (pa_oss_set_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support writing mixer settings: %s\n", strerror(errno)); + pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", strerror(errno)); s->set_hw_volume = NULL; return -1; } @@ -293,17 +293,17 @@ int pa__init(pa_core *c, pa_module*m) { assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments.\n"); + pa_log(__FILE__": failed to parse module arguments."); goto fail; } if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { - pa_log(__FILE__": record= and playback= expect numeric argument.\n"); + pa_log(__FILE__": record= and playback= expect numeric argument."); goto fail; } if (!playback && !record) { - pa_log(__FILE__": neither playback nor record enabled for device.\n"); + pa_log(__FILE__": neither playback nor record enabled for device."); goto fail; } @@ -312,13 +312,13 @@ int pa__init(pa_core *c, pa_module*m) { nfrags = 12; frag_size = 1024; if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { - pa_log(__FILE__": failed to parse fragments arguments\n"); + pa_log(__FILE__": failed to parse fragments arguments"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": failed to parse sample specification\n"); + pa_log(__FILE__": failed to parse sample specification"); goto fail; } @@ -326,11 +326,11 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; if (pa_oss_get_hw_description(p, hwdesc, sizeof(hwdesc)) >= 0) - pa_log_info(__FILE__": hardware name is '%s'.\n", hwdesc); + pa_log_info(__FILE__": hardware name is '%s'.", hwdesc); else hwdesc[0] = 0; - pa_log_info(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + pa_log_info(__FILE__": device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); if (nfrags >= 2 && frag_size >= 1) if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) @@ -340,7 +340,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETBLKSIZE: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETBLKSIZE: %s", strerror(errno)); goto fail; } assert(frag_size); @@ -351,13 +351,13 @@ int pa__init(pa_core *c, pa_module*m) { u->use_getospace = u->use_getispace = 0; if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { - pa_log_info(__FILE__": input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + pa_log_info(__FILE__": input -- %u fragments of size %u.", info.fragstotal, info.fragsize); in_frag_size = info.fragsize; u->use_getispace = 1; } if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) { - pa_log_info(__FILE__": output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + pa_log_info(__FILE__": output -- %u fragments of size %u.", info.fragstotal, info.fragsize); out_frag_size = info.fragsize; u->use_getospace = 1; } diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index 6ace377f..4ddf26ac 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -91,7 +91,7 @@ static void do_write(struct userdata *u) { assert(u->memchunk.memblock && u->memchunk.length); if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + pa_log(__FILE__": write() failed: %s", strerror(errno)); return; } @@ -141,32 +141,32 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); + pa_log(__FILE__": failed to parse module arguments"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": invalid sample format specification\n"); + pa_log(__FILE__": invalid sample format specification"); goto fail; } mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777); if ((fd = open(p, O_RDWR)) < 0) { - pa_log(__FILE__": open('%s'): %s\n", p, strerror(errno)); + pa_log(__FILE__": open('%s'): %s", p, strerror(errno)); goto fail; } pa_fd_set_cloexec(fd, 1); if (fstat(fd, &st) < 0) { - pa_log(__FILE__": fstat('%s'): %s\n", p, strerror(errno)); + pa_log(__FILE__": fstat('%s'): %s", p, strerror(errno)); goto fail; } if (!S_ISFIFO(st.st_mode)) { - pa_log(__FILE__": '%s' is not a FIFO.\n", p); + pa_log(__FILE__": '%s' is not a FIFO.", p); goto fail; } @@ -177,7 +177,7 @@ int pa__init(pa_core *c, pa_module*m) { m->userdata = u; if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { - pa_log(__FILE__": failed to create sink.\n"); + pa_log(__FILE__": failed to create sink."); goto fail; } u->sink->notify = notify_cb; diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index a7bb0ce7..d3753d25 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -88,7 +88,7 @@ static void do_read(struct userdata *u) { assert(u->chunk.memblock && u->chunk.memblock->length > u->chunk.index); if ((r = pa_iochannel_read(u->io, (uint8_t*) u->chunk.memblock->data + u->chunk.index, u->chunk.memblock->length - u->chunk.index)) <= 0) { - pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + pa_log(__FILE__": read() failed: %s", strerror(errno)); return; } @@ -119,32 +119,32 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); + pa_log(__FILE__": failed to parse module arguments"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": invalid sample format specification\n"); + pa_log(__FILE__": invalid sample format specification"); goto fail; } mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777); if ((fd = open(p, O_RDWR)) < 0) { - pa_log(__FILE__": open('%s'): %s\n", p, strerror(errno)); + pa_log(__FILE__": open('%s'): %s", p, strerror(errno)); goto fail; } pa_fd_set_cloexec(fd, 1); if (fstat(fd, &st) < 0) { - pa_log(__FILE__": fstat('%s'): %s\n", p, strerror(errno)); + pa_log(__FILE__": fstat('%s'): %s", p, strerror(errno)); goto fail; } if (!S_ISFIFO(st.st_mode)) { - pa_log(__FILE__": '%s' is not a FIFO.\n", p); + pa_log(__FILE__": '%s' is not a FIFO.", p); goto fail; } @@ -154,7 +154,7 @@ int pa__init(pa_core *c, pa_module*m) { u->core = c; if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL))) { - pa_log(__FILE__": failed to create source.\n"); + pa_log(__FILE__": failed to create source."); goto fail; } u->source->userdata = u; diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index 641e3624..749a7ace 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -161,12 +161,12 @@ static pa_socket_server *create_socket_server(pa_core *c, pa_modargs *ma) { const char *listen_on; if (pa_modargs_get_value_boolean(ma, "loopback", &loopback) < 0) { - pa_log(__FILE__": loopback= expects a boolean argument.\n"); + pa_log(__FILE__": loopback= expects a boolean argument."); return NULL; } if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) { - pa_log(__FILE__": port= expects a numerical argument between 1 and 65535.\n"); + pa_log(__FILE__": port= expects a numerical argument between 1 and 65535."); return NULL; } @@ -194,12 +194,12 @@ static pa_socket_server *create_socket_server(pa_core *c, pa_modargs *ma) { pa_runtime_path(v, tmp, sizeof(tmp)); if (pa_make_secure_parent_dir(tmp) < 0) { - pa_log(__FILE__": Failed to create secure socket directory.\n"); + pa_log(__FILE__": Failed to create secure socket directory."); return NULL; } if ((r = pa_unix_socket_remove_stale(tmp)) < 0) { - pa_log(__FILE__": Failed to remove stale UNIX socket '%s': %s\n", tmp, strerror(errno)); + pa_log(__FILE__": Failed to remove stale UNIX socket '%s': %s", tmp, strerror(errno)); return NULL; } @@ -220,7 +220,7 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments\n"); + pa_log(__FILE__": Failed to parse module arguments"); goto finish; } @@ -246,9 +246,9 @@ void pa__done(pa_core *c, pa_module*m) { #if defined(USE_PROTOCOL_ESOUND) && !defined(USE_TCP_SOCKETS) if (remove(ESD_UNIX_SOCKET_NAME) != 0) - pa_log("%s: Failed to remove %s : %s.\n", __FILE__, ESD_UNIX_SOCKET_NAME, strerror (errno)); + pa_log("%s: Failed to remove %s : %s.", __FILE__, ESD_UNIX_SOCKET_NAME, strerror (errno)); if (remove(ESD_UNIX_SOCKET_DIR) != 0) - pa_log("%s: Failed to remove %s : %s.\n", __FILE__, ESD_UNIX_SOCKET_DIR, strerror (errno)); + pa_log("%s: Failed to remove %s : %s.", __FILE__, ESD_UNIX_SOCKET_DIR, strerror (errno)); #endif protocol_free(m->userdata); diff --git a/src/modules/module-sine.c b/src/modules/module-sine.c index 446e3974..d5a0fa47 100644 --- a/src/modules/module-sine.c +++ b/src/modules/module-sine.c @@ -110,7 +110,7 @@ int pa__init(pa_core *c, pa_module*m) { char t[256]; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments\n"); + pa_log(__FILE__": Failed to parse module arguments"); goto fail; } @@ -123,7 +123,7 @@ int pa__init(pa_core *c, pa_module*m) { sink_name = pa_modargs_get_value(ma, "sink", NULL); if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": No such sink.\n"); + pa_log(__FILE__": No such sink."); goto fail; } @@ -133,7 +133,7 @@ int pa__init(pa_core *c, pa_module*m) { frequency = 440; if (pa_modargs_get_value_u32(ma, "frequency", &frequency) < 0 || frequency < 1 || frequency > ss.rate/2) { - pa_log(__FILE__": Invalid frequency specification\n"); + pa_log(__FILE__": Invalid frequency specification"); goto fail; } diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 7356cb7b..1de21aed 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -150,7 +150,7 @@ static void do_write(struct userdata *u) { len = memchunk->length; if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, len)) < 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + pa_log(__FILE__": write() failed: %s", strerror(errno)); return; } @@ -172,7 +172,7 @@ static void do_write(struct userdata *u) { * Write 0 bytes which will generate a SIGPOLL when "played". */ if (write(u->fd, NULL, 0) < 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + pa_log(__FILE__": write() failed: %s", strerror(errno)); return; } } @@ -196,7 +196,7 @@ static void do_read(struct userdata *u) { if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); if (errno != EAGAIN) - pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + pa_log(__FILE__": read() failed: %s", strerror(errno)); return; } @@ -283,9 +283,9 @@ static int sink_set_hw_volume_cb(pa_sink *s) { if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { if (errno == EINVAL) - pa_log(__FILE__": AUDIO_SETINFO: Unsupported volume.\n"); + pa_log(__FILE__": AUDIO_SETINFO: Unsupported volume."); else - pa_log(__FILE__": AUDIO_SETINFO: %s\n", strerror(errno)); + pa_log(__FILE__": AUDIO_SETINFO: %s", strerror(errno)); return -1; } @@ -349,9 +349,9 @@ static int pa_solaris_auto_format(int fd, int mode, pa_sample_spec *ss) { if (ioctl(fd, AUDIO_SETINFO, &info) < 0) { if (errno == EINVAL) - pa_log(__FILE__": AUDIO_SETINFO: Unsupported sample format.\n"); + pa_log(__FILE__": AUDIO_SETINFO: Unsupported sample format."); else - pa_log(__FILE__": AUDIO_SETINFO: %s\n", strerror(errno)); + pa_log(__FILE__": AUDIO_SETINFO: %s", strerror(errno)); return -1; } @@ -367,9 +367,9 @@ static int pa_solaris_set_buffer(int fd, int buffer_size) { if (ioctl(fd, AUDIO_SETINFO, &info) < 0) { if (errno == EINVAL) - pa_log(__FILE__": AUDIO_SETINFO: Unsupported buffer size.\n"); + pa_log(__FILE__": AUDIO_SETINFO: Unsupported buffer size."); else - pa_log(__FILE__": AUDIO_SETINFO: %s\n", strerror(errno)); + pa_log(__FILE__": AUDIO_SETINFO: %s", strerror(errno)); return -1; } @@ -388,17 +388,17 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments.\n"); + pa_log(__FILE__": failed to parse module arguments."); goto fail; } if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { - pa_log(__FILE__": record= and playback= expect numeric argument.\n"); + pa_log(__FILE__": record= and playback= expect numeric argument."); goto fail; } if (!playback && !record) { - pa_log(__FILE__": neither playback nor record enabled for device.\n"); + pa_log(__FILE__": neither playback nor record enabled for device."); goto fail; } @@ -406,20 +406,20 @@ int pa__init(pa_core *c, pa_module*m) { buffer_size = 16384; if (pa_modargs_get_value_s32(ma, "buffer_size", &buffer_size) < 0) { - pa_log(__FILE__": failed to parse buffer size argument\n"); + pa_log(__FILE__": failed to parse buffer size argument"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": failed to parse sample specification\n"); + pa_log(__FILE__": failed to parse sample specification"); goto fail; } if ((fd = open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), mode | O_NONBLOCK)) < 0) goto fail; - pa_log_info(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + pa_log_info(__FILE__": device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); if (pa_solaris_auto_format(fd, mode, &ss) < 0) goto fail; diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 136702fc..df9c51fb 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -182,7 +182,7 @@ static void command_stream_killed(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t comma struct userdata *u = userdata; assert(pd && t && u && u->pdispatch == pd); - pa_log(__FILE__": stream killed\n"); + pa_log(__FILE__": stream killed"); die(u); } @@ -232,13 +232,13 @@ static void command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED ui if (pa_tagstruct_getu32(t, &channel) < 0 || pa_tagstruct_getu32(t, &bytes) < 0 || !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid protocol reply\n"); + pa_log(__FILE__": invalid protocol reply"); die(u); return; } if (channel != u->channel) { - pa_log(__FILE__": recieved data for invalid channel\n"); + pa_log(__FILE__": recieved data for invalid channel"); die(u); return; } @@ -260,9 +260,9 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G if (command != PA_COMMAND_REPLY) { if (command == PA_COMMAND_ERROR) - pa_log(__FILE__": failed to get latency.\n"); + pa_log(__FILE__": failed to get latency."); else - pa_log(__FILE__": protocol error.\n"); + pa_log(__FILE__": protocol error."); die(u); return; } @@ -276,7 +276,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G pa_tagstruct_get_timeval(t, &remote) < 0 || pa_tagstruct_getu64(t, &counter) < 0 || !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid reply.\n"); + pa_log(__FILE__": invalid reply."); die(u); return; } @@ -303,7 +303,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G u->host_latency = 0; #endif -/* pa_log(__FILE__": estimated host latency: %0.0f usec\n", (double) u->host_latency); */ +/* pa_log(__FILE__": estimated host latency: %0.0f usec", (double) u->host_latency); */ } static void request_latency(struct userdata *u) { @@ -335,9 +335,9 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN if (command != PA_COMMAND_REPLY) { if (command == PA_COMMAND_ERROR) - pa_log(__FILE__": failed to create stream.\n"); + pa_log(__FILE__": failed to create stream."); else - pa_log(__FILE__": protocol error.\n"); + pa_log(__FILE__": protocol error."); die(u); return; } @@ -348,7 +348,7 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN pa_tagstruct_getu32(t, &u->requested_bytes) < 0 || #endif !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid reply.\n"); + pa_log(__FILE__": invalid reply."); die(u); return; } @@ -367,9 +367,9 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t if (command != PA_COMMAND_REPLY || !pa_tagstruct_eof(t)) { if (command == PA_COMMAND_ERROR) - pa_log(__FILE__": failed to authenticate\n"); + pa_log(__FILE__": failed to authenticate"); else - pa_log(__FILE__": protocol error.\n"); + pa_log(__FILE__": protocol error."); die(u); return; } @@ -426,7 +426,7 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { struct userdata *u = userdata; assert(p && u); - pa_log(__FILE__": stream died.\n"); + pa_log(__FILE__": stream died."); die(u); } @@ -436,7 +436,7 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *user assert(p && packet && u); if (pa_pdispatch_run(u->pdispatch, packet, u) < 0) { - pa_log(__FILE__": invalid packet\n"); + pa_log(__FILE__": invalid packet"); die(u); } } @@ -447,7 +447,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o assert(p && chunk && u); if (channel != u->channel) { - pa_log(__FILE__": recieved memory block on bad channel.\n"); + pa_log(__FILE__": recieved memory block on bad channel."); die(u); return; } @@ -466,7 +466,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata u->client = NULL; if (!io) { - pa_log(__FILE__": connection failed.\n"); + pa_log(__FILE__": connection failed."); pa_module_unload_request(u->module); return; } @@ -544,7 +544,7 @@ static int load_key(struct userdata *u, const char*fn) { u->auth_cookie_in_property = 0; if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { - pa_log_debug(__FILE__": using already loaded auth cookie.\n"); + pa_log_debug(__FILE__": using already loaded auth cookie."); pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); u->auth_cookie_in_property = 1; return 0; @@ -556,7 +556,7 @@ static int load_key(struct userdata *u, const char*fn) { if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) return -1; - pa_log_debug(__FILE__": loading cookie from disk.\n"); + pa_log_debug(__FILE__": loading cookie from disk."); if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) u->auth_cookie_in_property = 1; @@ -572,7 +572,7 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); + pa_log(__FILE__": failed to parse module arguments"); goto fail; } @@ -602,18 +602,18 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; if (!(u->server_name = pa_xstrdup(pa_modargs_get_value(ma, "server", NULL)))) { - pa_log(__FILE__": no server specified.\n"); + pa_log(__FILE__": no server specified."); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": invalid sample format specification\n"); + pa_log(__FILE__": invalid sample format specification"); goto fail; } if (!(u->client = pa_socket_client_new_string(c->mainloop, u->server_name, PA_NATIVE_DEFAULT_PORT))) { - pa_log(__FILE__": failed to connect to server '%s'\n", u->server_name); + pa_log(__FILE__": failed to connect to server '%s'", u->server_name); goto fail; } @@ -624,7 +624,7 @@ int pa__init(pa_core *c, pa_module*m) { #ifdef TUNNEL_SINK if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { - pa_log(__FILE__": failed to create sink.\n"); + pa_log(__FILE__": failed to create sink."); goto fail; } @@ -636,7 +636,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_sink_set_owner(u->sink, m); #else if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL))) { - pa_log(__FILE__": failed to create source.\n"); + pa_log(__FILE__": failed to create source."); goto fail; } diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index 2176e6e7..02f865c5 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -159,12 +159,12 @@ static void do_write(struct userdata *u) res = waveOutPrepareHeader(u->hwo, hdr, sizeof(WAVEHDR)); if (res != MMSYSERR_NOERROR) { - pa_log_error(__FILE__ ": ERROR: Unable to prepare waveOut block: %d\n", + pa_log_error(__FILE__ ": ERROR: Unable to prepare waveOut block: %d", res); } res = waveOutWrite(u->hwo, hdr, sizeof(WAVEHDR)); if (res != MMSYSERR_NOERROR) { - pa_log_error(__FILE__ ": ERROR: Unable to write waveOut block: %d\n", + pa_log_error(__FILE__ ": ERROR: Unable to write waveOut block: %d", res); } @@ -214,12 +214,12 @@ static void do_read(struct userdata *u) res = waveInPrepareHeader(u->hwi, hdr, sizeof(WAVEHDR)); if (res != MMSYSERR_NOERROR) { - pa_log_error(__FILE__ ": ERROR: Unable to prepare waveIn block: %d\n", + pa_log_error(__FILE__ ": ERROR: Unable to prepare waveIn block: %d", res); } res = waveInAddBuffer(u->hwi, hdr, sizeof(WAVEHDR)); if (res != MMSYSERR_NOERROR) { - pa_log_error(__FILE__ ": ERROR: Unable to add waveIn block: %d\n", + pa_log_error(__FILE__ ": ERROR: Unable to add waveIn block: %d", res); } @@ -378,7 +378,7 @@ static int ss_to_waveformat(pa_sample_spec *ss, LPWAVEFORMATEX wf) { wf->wFormatTag = WAVE_FORMAT_PCM; if (ss->channels > 2) { - pa_log_error(__FILE__": ERROR: More than two channels not supported.\n"); + pa_log_error(__FILE__": ERROR: More than two channels not supported."); return -1; } @@ -391,7 +391,7 @@ static int ss_to_waveformat(pa_sample_spec *ss, LPWAVEFORMATEX wf) { case 44100: break; default: - pa_log_error(__FILE__": ERROR: Unsupported sample rate.\n"); + pa_log_error(__FILE__": ERROR: Unsupported sample rate."); return -1; } @@ -402,7 +402,7 @@ static int ss_to_waveformat(pa_sample_spec *ss, LPWAVEFORMATEX wf) { else if (ss->format == PA_SAMPLE_S16NE) wf->wBitsPerSample = 16; else { - pa_log_error(__FILE__": ERROR: Unsupported sample format.\n"); + pa_log_error(__FILE__": ERROR: Unsupported sample format."); return -1; } @@ -429,30 +429,30 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments.\n"); + pa_log(__FILE__": failed to parse module arguments."); goto fail; } if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { - pa_log(__FILE__": record= and playback= expect boolean argument.\n"); + pa_log(__FILE__": record= and playback= expect boolean argument."); goto fail; } if (!playback && !record) { - pa_log(__FILE__": neither playback nor record enabled for device.\n"); + pa_log(__FILE__": neither playback nor record enabled for device."); goto fail; } nfrags = 20; frag_size = 1024; if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { - pa_log(__FILE__": failed to parse fragments arguments\n"); + pa_log(__FILE__": failed to parse fragments arguments"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": failed to parse sample specification\n"); + pa_log(__FILE__": failed to parse sample specification"); goto fail; } @@ -466,13 +466,13 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; if (waveInStart(hwi) != MMSYSERR_NOERROR) goto fail; - pa_log_debug(__FILE__": Opened waveIn subsystem.\n"); + pa_log_debug(__FILE__": Opened waveIn subsystem."); } if (playback) { if (waveOutOpen(&hwo, WAVE_MAPPER, &wf, (DWORD_PTR)chunk_done_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) goto fail; - pa_log_debug(__FILE__": Opened waveOut subsystem.\n"); + pa_log_debug(__FILE__": Opened waveOut subsystem."); } InitializeCriticalSection(&u->crit); diff --git a/src/modules/module-x11-bell.c b/src/modules/module-x11-bell.c index d59f3f59..27ceb7f9 100644 --- a/src/modules/module-x11-bell.c +++ b/src/modules/module-x11-bell.c @@ -71,7 +71,7 @@ static int ring_bell(struct userdata *u, int percent) { assert(u); if (!(s = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": Invalid sink: %s\n", u->sink_name); + pa_log(__FILE__": Invalid sink: %s", u->sink_name); return -1; } @@ -90,7 +90,7 @@ static int x11_event_callback(pa_x11_wrapper *w, XEvent *e, void *userdata) { bne = (XkbBellNotifyEvent*) e; if (ring_bell(u, bne->percent) < 0) { - pa_log_info(__FILE__": Ringing bell failed, reverting to X11 device bell.\n"); + pa_log_info(__FILE__": Ringing bell failed, reverting to X11 device bell."); XkbForceDeviceBell(pa_x11_wrapper_get_display(w), bne->device, bne->bell_class, bne->bell_id, bne->percent); } @@ -105,7 +105,7 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); + pa_log(__FILE__": failed to parse module arguments"); goto fail; } @@ -124,7 +124,7 @@ int pa__init(pa_core *c, pa_module*m) { minor = XkbMinorVersion; if (!XkbLibraryVersion(&major, &minor)) { - pa_log(__FILE__": XkbLibraryVersion() failed\n"); + pa_log(__FILE__": XkbLibraryVersion() failed"); goto fail; } @@ -133,7 +133,7 @@ int pa__init(pa_core *c, pa_module*m) { if (!XkbQueryExtension(u->display, NULL, &u->xkb_event_base, NULL, &major, &minor)) { - pa_log(__FILE__": XkbQueryExtension() failed\n"); + pa_log(__FILE__": XkbQueryExtension() failed"); goto fail; } diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c index 6d9036f5..cee9cb3f 100644 --- a/src/modules/module-x11-publish.c +++ b/src/modules/module-x11-publish.c @@ -78,7 +78,7 @@ static int load_key(struct userdata *u, const char*fn) { u->auth_cookie_in_property = 0; if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { - pa_log_debug(__FILE__": using already loaded auth cookie.\n"); + pa_log_debug(__FILE__": using already loaded auth cookie."); pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); u->auth_cookie_in_property = 1; return 0; @@ -90,7 +90,7 @@ static int load_key(struct userdata *u, const char*fn) { if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) return -1; - pa_log_debug(__FILE__": loading cookie from disk.\n"); + pa_log_debug(__FILE__": loading cookie from disk."); if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) u->auth_cookie_in_property = 1; @@ -108,7 +108,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_strlist *l; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); + pa_log(__FILE__": failed to parse module arguments"); goto fail; } @@ -169,7 +169,7 @@ void pa__done(pa_core *c, pa_module*m) { /* Yes, here is a race condition */ if (!pa_x11_get_prop(u->display, "POLYP_ID", t, sizeof(t)) || strcmp(t, u->id)) - pa_log("WARNING: Polypaudio information vanished from X11!\n"); + pa_log_warn(__FILE__": Polypaudio information vanished from X11!"); else { pa_x11_del_prop(u->display, "POLYP_ID"); pa_x11_del_prop(u->display, "POLYP_SERVER"); diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index d79355ce..f8607bef 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -141,7 +141,7 @@ static int publish_service(struct userdata *u, struct service *s) { snprintf(t, sizeof(t), "Networked Audio Device %s on %s", s->name, pa_get_host_name(hn, sizeof(hn))); if (sw_text_record_init(&txt) != SW_OKAY) { - pa_log(__FILE__": sw_text_record_init() failed\n"); + pa_log(__FILE__": sw_text_record_init() failed"); goto finish; } free_txt = 1; @@ -168,7 +168,7 @@ static int publish_service(struct userdata *u, struct service *s) { s->loaded.type == PA_NAMEREG_SINK ? SERVICE_NAME_SINK : SERVICE_NAME_SOURCE, NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt), publish_reply, s, &s->oid) != SW_OKAY) { - pa_log(__FILE__": failed to register sink on zeroconf.\n"); + pa_log(__FILE__": failed to register sink on zeroconf."); goto finish; } @@ -179,7 +179,7 @@ static int publish_service(struct userdata *u, struct service *s) { s->autoload.type == PA_NAMEREG_SINK ? SERVICE_NAME_SINK : SERVICE_NAME_SOURCE, NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt), publish_reply, s, &s->oid) != SW_OKAY) { - pa_log(__FILE__": failed to register sink on zeroconf.\n"); + pa_log(__FILE__": failed to register sink on zeroconf."); goto finish; } @@ -391,12 +391,12 @@ int pa__init(pa_core *c, pa_module*m) { sw_text_record txt; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments.\n"); + pa_log(__FILE__": failed to parse module arguments."); goto fail; } if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port == 0 || port >= 0xFFFF) { - pa_log(__FILE__": invalid port specified.\n"); + pa_log(__FILE__": invalid port specified."); goto fail; } @@ -433,7 +433,7 @@ int pa__init(pa_core *c, pa_module*m) { snprintf(t, sizeof(t), "Networked Audio Server on %s", pa_get_host_name(hn, sizeof(hn))); if (sw_text_record_init(&txt) != SW_OKAY) { - pa_log(__FILE__": sw_text_record_init() failed\n"); + pa_log(__FILE__": sw_text_record_init() failed"); goto fail; } free_txt = 1; @@ -444,7 +444,7 @@ int pa__init(pa_core *c, pa_module*m) { SERVICE_NAME_SERVER, NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt), publish_reply, u, &u->server_oid) != SW_OKAY) { - pa_log(__FILE__": failed to register server on zeroconf.\n"); + pa_log(__FILE__": failed to register server on zeroconf."); goto fail; } diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index 9fb5d38a..2c12e28d 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -51,7 +51,7 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { tcaps = pcaps ? pcaps : &dcaps; if (ioctl(fd, SNDCTL_DSP_GETCAPS, tcaps) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s", strerror(errno)); goto fail; } @@ -63,20 +63,20 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { if ((fd = open(device, (*mode = O_WRONLY)|O_NDELAY)) < 0) { if ((fd = open(device, (*mode = O_RDONLY)|O_NDELAY)) < 0) { - pa_log(__FILE__": open('%s'): %s\n", device, strerror(errno)); + pa_log(__FILE__": open('%s'): %s", device, strerror(errno)); goto fail; } } } else { if ((fd = open(device, *mode|O_NDELAY)) < 0) { - pa_log(__FILE__": open('%s'): %s\n", device, strerror(errno)); + pa_log(__FILE__": open('%s'): %s", device, strerror(errno)); goto fail; } } if (pcaps) { if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s", strerror(errno)); goto fail; } } @@ -114,7 +114,7 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss) { if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != f) { format = AFMT_U8; if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_U8) { - pa_log(__FILE__": SNDCTL_DSP_SETFMT: %s\n", format != AFMT_U8 ? "No supported sample format" : strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_SETFMT: %s", format != AFMT_U8 ? "No supported sample format" : strerror(errno)); return -1; } else ss->format = PA_SAMPLE_U8; @@ -126,7 +126,7 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss) { channels = ss->channels; if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) { - pa_log(__FILE__": SNDCTL_DSP_CHANNELS: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_CHANNELS: %s", strerror(errno)); return -1; } assert(channels); @@ -134,7 +134,7 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss) { speed = ss->rate; if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) { - pa_log(__FILE__": SNDCTL_DSP_SPEED: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_SPEED: %s", strerror(errno)); return -1; } assert(speed); @@ -160,7 +160,7 @@ int pa_oss_set_fragments(int fd, int nfrags, int frag_size) { arg = ((int) nfrags << 16) | simple_log2(frag_size); if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &arg) < 0) { - pa_log(__FILE__": SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_SETFRAGMENT: %s", strerror(errno)); return -1; } @@ -183,7 +183,7 @@ int pa_oss_get_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume) { if ((volume->channels = ss->channels) >= 2) volume->values[1] = (((vol >> 8) & 0xFF) * PA_VOLUME_NORM) / 100; - pa_log_debug(__FILE__": Read mixer settings: %s\n", pa_cvolume_snprint(cv, sizeof(cv), volume)); + pa_log_debug(__FILE__": Read mixer settings: %s", pa_cvolume_snprint(cv, sizeof(cv), volume)); return 0; } @@ -199,7 +199,7 @@ int pa_oss_set_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume if (ioctl(fd, SOUND_MIXER_WRITE_PCM, &vol) < 0) return -1; - pa_log_debug(__FILE__": Wrote mixer settings: %s\n", pa_cvolume_snprint(cv, sizeof(cv), volume)); + pa_log_debug(__FILE__": Wrote mixer settings: %s", pa_cvolume_snprint(cv, sizeof(cv), volume)); return 0; } @@ -228,7 +228,7 @@ int pa_oss_get_hw_description(const char *dev, char *name, size_t l) { !(f = fopen("/proc/asound/oss/sndstat", "r"))) { if (errno != ENOENT) - pa_log_warn(__FILE__": failed to open OSS sndstat device: %s\n", strerror(errno)); + pa_log_warn(__FILE__": failed to open OSS sndstat device: %s", strerror(errno)); return -1; } diff --git a/src/polyp/browser.c b/src/polyp/browser.c index ce4c0103..de5c751a 100644 --- a/src/polyp/browser.c +++ b/src/polyp/browser.c @@ -48,7 +48,7 @@ static void io_callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_fl assert(a && b && b->mainloop == a); if (events != PA_IO_EVENT_INPUT || sw_discovery_read_socket(b->discovery) != SW_OKAY) { - pa_log(__FILE__": connection to HOWL daemon failed.\n"); + pa_log(__FILE__": connection to HOWL daemon failed."); b->mainloop->io_free(b->io_event); b->io_event = NULL; return; @@ -131,7 +131,7 @@ static sw_result resolve_reply( uint32_t val_len; if (sw_text_record_iterator_init(&iterator, text_record, text_record_len) != SW_OKAY) { - pa_log("sw_text_record_string_iterator_init() failed.\n"); + pa_log_error(__FILE__": sw_text_record_string_iterator_init() failed."); goto fail; } @@ -244,7 +244,7 @@ static sw_result browse_reply( sw_discovery_oid oid; if (sw_discovery_resolve(b->discovery, 0, name, type, domain, resolve_reply, b, &oid) != SW_OKAY) - pa_log("sw_discovery_resolve() failed\n"); + pa_log_error(__FILE__": sw_discovery_resolve() failed"); break; } @@ -282,7 +282,7 @@ pa_browser *pa_browser_new(pa_mainloop_api *mainloop) { b->userdata = NULL; if (sw_discovery_init(&b->discovery) != SW_OKAY) { - pa_log("sw_discovery_init() failed.\n"); + pa_log_error(__FILE__": sw_discovery_init() failed."); pa_xfree(b); return NULL; } @@ -291,7 +291,7 @@ pa_browser *pa_browser_new(pa_mainloop_api *mainloop) { sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SINK, NULL, browse_reply, b, &oid) != SW_OKAY || sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SOURCE, NULL, browse_reply, b, &oid) != SW_OKAY) { - pa_log("sw_discovery_browse() failed.\n"); + pa_log_error(__FILE__": sw_discovery_browse() failed."); sw_discovery_fina(b->discovery); pa_xfree(b); diff --git a/src/polyp/client-conf-x11.c b/src/polyp/client-conf-x11.c index 9e863bc7..7187d86b 100644 --- a/src/polyp/client-conf-x11.c +++ b/src/polyp/client-conf-x11.c @@ -45,7 +45,7 @@ int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) { goto finish; if (!(d = XOpenDisplay(dname))) { - pa_log(__FILE__": XOpenDisplay() failed\n"); + pa_log(__FILE__": XOpenDisplay() failed"); goto finish; } @@ -68,7 +68,7 @@ int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) { uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; if (pa_parsehex(t, cookie, sizeof(cookie)) != sizeof(cookie)) { - pa_log(__FILE__": failed to parse cookie data\n"); + pa_log(__FILE__": failed to parse cookie data"); goto finish; } diff --git a/src/polyp/client-conf.c b/src/polyp/client-conf.c index 328d01c9..4202b14c 100644 --- a/src/polyp/client-conf.c +++ b/src/polyp/client-conf.c @@ -122,7 +122,7 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) { pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn); if (!f && errno != EINTR) { - pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno)); + pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", filename, strerror(errno)); goto finish; } diff --git a/src/polyp/context.c b/src/polyp/context.c index 906a0d89..8e999225 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -424,7 +424,7 @@ static int context_connect_spawn(pa_context *c) { pa_context_ref(c); if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { - pa_log(__FILE__": socketpair() failed: %s\n", strerror(errno)); + pa_log(__FILE__": socketpair() failed: %s", strerror(errno)); pa_context_fail(c, PA_ERR_INTERNAL); goto fail; } @@ -438,7 +438,7 @@ static int context_connect_spawn(pa_context *c) { c->spawn_api.prefork(); if ((pid = fork()) < 0) { - pa_log(__FILE__": fork() failed: %s\n", strerror(errno)); + pa_log(__FILE__": fork() failed: %s", strerror(errno)); pa_context_fail(c, PA_ERR_INTERNAL); if (c->spawn_api.postfork) @@ -494,7 +494,7 @@ static int context_connect_spawn(pa_context *c) { c->spawn_api.postfork(); if (r < 0) { - pa_log(__FILE__": waitpid() failed: %s\n", strerror(errno)); + pa_log(__FILE__": waitpid() failed: %s", strerror(errno)); pa_context_fail(c, PA_ERR_INTERNAL); goto fail; } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { @@ -556,7 +556,7 @@ static int try_next_connection(pa_context *c) { goto finish; } - pa_log_debug(__FILE__": Trying to connect to %s...\n", u); + pa_log_debug(__FILE__": Trying to connect to %s...", u); pa_xfree(c->server); c->server = pa_xstrdup(u); @@ -714,8 +714,8 @@ int pa_context_is_pending(pa_context *c) { assert(c); assert(c->ref >= 1); -/* pa_log("pstream: %i\n", pa_pstream_is_pending(c->pstream)); */ -/* pa_log("pdispatch: %i\n", pa_pdispatch_is_pending(c->pdispatch)); */ +/* pa_log("pstream: %i", pa_pstream_is_pending(c->pstream)); */ +/* pa_log("pdispatch: %i", pa_pdispatch_is_pending(c->pdispatch)); */ return (c->pstream && pa_pstream_is_pending(c->pstream)) || (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) || diff --git a/src/polyp/mainloop-signal.c b/src/polyp/mainloop-signal.c index 00804324..0b33c44b 100644 --- a/src/polyp/mainloop-signal.c +++ b/src/polyp/mainloop-signal.c @@ -104,12 +104,12 @@ static void defer(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event*e, PA_GCC_UNUS while (sigs) { if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) { - pa_log(__FILE__": read(): %s\n", strerror(errno)); + pa_log(__FILE__": read(): %s", strerror(errno)); return; } if (r != sizeof(sig)) { - pa_log(__FILE__": short read()\n"); + pa_log(__FILE__": short read()"); return; } @@ -130,12 +130,12 @@ static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags if (errno == EAGAIN) return; - pa_log(__FILE__": read(): %s\n", strerror(errno)); + pa_log(__FILE__": read(): %s", strerror(errno)); return; } if (r != sizeof(sig)) { - pa_log(__FILE__": short read()\n"); + pa_log(__FILE__": short read()"); return; } @@ -150,7 +150,7 @@ int pa_signal_init(pa_mainloop_api *a) { #else if (pipe(signal_pipe) < 0) { #endif - pa_log(__FILE__": pipe() failed: %s\n", strerror(errno)); + pa_log(__FILE__": pipe() failed: %s", strerror(errno)); return -1; } diff --git a/src/polyp/mainloop.c b/src/polyp/mainloop.c index e975d7d7..95c336e4 100644 --- a/src/polyp/mainloop.c +++ b/src/polyp/mainloop.c @@ -145,7 +145,7 @@ static pa_io_event* mainloop_io_new( if ((select((SELECT_TYPE_ARG1) fd, NULL, NULL, SELECT_TYPE_ARG234 &xset, SELECT_TYPE_ARG5 &tv) == -1) && (WSAGetLastError() == WSAENOTSOCK)) { - pa_log_warn(__FILE__": WARNING: cannot monitor non-socket file descriptors.\n"); + pa_log_warn(__FILE__": WARNING: cannot monitor non-socket file descriptors."); e->dead = 1; } } @@ -725,7 +725,7 @@ int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) { r = pa_mainloop_poll(m); if (r < 0) { - pa_log(__FILE__": poll(): %s\n", strerror(errno)); + pa_log(__FILE__": poll(): %s", strerror(errno)); return r; } @@ -774,7 +774,7 @@ int pa_mainloop_deferred_pending(pa_mainloop *m) { void pa_mainloop_dump(pa_mainloop *m) { assert(m); - pa_log(__FILE__": Dumping mainloop sources START\n"); + pa_log(__FILE__": Dumping mainloop sources START"); { uint32_t idx = PA_IDXSET_INVALID; @@ -783,7 +783,7 @@ void pa_mainloop_dump(pa_mainloop *m) { if (e->dead) continue; - pa_log(__FILE__": kind=io fd=%i events=%i callback=%p userdata=%p\n", e->fd, (int) e->events, (void*) e->callback, (void*) e->userdata); + pa_log(__FILE__": kind=io fd=%i events=%i callback=%p userdata=%p", e->fd, (int) e->events, (void*) e->callback, (void*) e->userdata); } } { @@ -793,7 +793,7 @@ void pa_mainloop_dump(pa_mainloop *m) { if (e->dead) continue; - pa_log(__FILE__": kind=defer enabled=%i callback=%p userdata=%p\n", e->enabled, (void*) e->callback, (void*) e->userdata); + pa_log(__FILE__": kind=defer enabled=%i callback=%p userdata=%p", e->enabled, (void*) e->callback, (void*) e->userdata); } } { @@ -803,11 +803,11 @@ void pa_mainloop_dump(pa_mainloop *m) { if (e->dead) continue; - pa_log(__FILE__": kind=time enabled=%i time=%lu.%lu callback=%p userdata=%p\n", e->enabled, (unsigned long) e->timeval.tv_sec, (unsigned long) e->timeval.tv_usec, (void*) e->callback, (void*) e->userdata); + pa_log(__FILE__": kind=time enabled=%i time=%lu.%lu callback=%p userdata=%p", e->enabled, (unsigned long) e->timeval.tv_sec, (unsigned long) e->timeval.tv_usec, (void*) e->callback, (void*) e->userdata); } } - pa_log(__FILE__": Dumping mainloop sources STOP\n"); + pa_log(__FILE__": Dumping mainloop sources STOP"); } #endif diff --git a/src/polyp/stream.c b/src/polyp/stream.c index 5ab91815..8bdb9059 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -289,7 +289,7 @@ static void ipol_callback(pa_mainloop_api *m, pa_time_event *e, PA_GCC_UNUSED co pa_stream_ref(s); -/* pa_log("requesting new ipol data\n"); */ +/* pa_log("requesting new ipol data"); */ if (s->state == PA_STREAM_READY && !s->ipol_requested) { pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); @@ -655,7 +655,7 @@ static void stream_get_latency_info_callback(pa_pdispatch *pd, uint32_t command, } if (o->stream->interpolate) { -/* pa_log("new interpol data\n"); */ +/* pa_log("new interpol data"); */ o->stream->ipol_timestamp = i.timestamp; o->stream->ipol_usec = pa_stream_get_time(o->stream, &i); o->stream->ipol_requested = 0; diff --git a/src/polypcore/authkey.c b/src/polypcore/authkey.c index e3fc9f60..80480c16 100644 --- a/src/polypcore/authkey.c +++ b/src/polypcore/authkey.c @@ -52,7 +52,7 @@ static int generate(int fd, void *ret_data, size_t length) { ftruncate(fd, 0); if ((r = pa_loop_write(fd, ret_data, length)) < 0 || (size_t) r != length) { - pa_log(__FILE__": failed to write cookie file: %s\n", strerror(errno)); + pa_log(__FILE__": failed to write cookie file: %s", strerror(errno)); return -1; } @@ -70,7 +70,7 @@ static int load(const char *fn, void *data, size_t length) { if ((fd = open(fn, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { if (errno != EACCES || (fd = open(fn, O_RDONLY)) < 0) { - pa_log(__FILE__": failed to open cookie file '%s': %s\n", fn, strerror(errno)); + pa_log(__FILE__": failed to open cookie file '%s': %s", fn, strerror(errno)); goto finish; } else writable = 0; @@ -79,14 +79,14 @@ static int load(const char *fn, void *data, size_t length) { unlock = pa_lock_fd(fd, 1) >= 0; if ((r = pa_loop_read(fd, data, length)) < 0) { - pa_log(__FILE__": failed to read cookie file '%s': %s\n", fn, strerror(errno)); + pa_log(__FILE__": failed to read cookie file '%s': %s", fn, strerror(errno)); goto finish; } if ((size_t) r != length) { if (!writable) { - pa_log(__FILE__": unable to write cookie to read only file\n"); + pa_log(__FILE__": unable to write cookie to read only file"); goto finish; } @@ -118,7 +118,7 @@ int pa_authkey_load(const char *path, void *data, size_t length) { ret = load(path, data, length); if (ret < 0) - pa_log(__FILE__": Failed to load authorization key '%s': %s\n", path, + pa_log(__FILE__": Failed to load authorization key '%s': %s", path, (ret == -1) ? strerror(errno) : "file corrupt"); return ret; @@ -175,14 +175,14 @@ int pa_authkey_save(const char *fn, const void *data, size_t length) { return -2; if ((fd = open(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { - pa_log(__FILE__": failed to open cookie file '%s': %s\n", fn, strerror(errno)); + pa_log(__FILE__": failed to open cookie file '%s': %s", fn, strerror(errno)); goto finish; } unlock = pa_lock_fd(fd, 1) >= 0; if ((r = pa_loop_write(fd, data, length)) < 0 || (size_t) r != length) { - pa_log(__FILE__": failed to read cookie file '%s': %s\n", fn, strerror(errno)); + pa_log(__FILE__": failed to read cookie file '%s': %s", fn, strerror(errno)); goto finish; } diff --git a/src/polypcore/cli.c b/src/polypcore/cli.c index 295ce625..583f6845 100644 --- a/src/polypcore/cli.c +++ b/src/polypcore/cli.c @@ -103,7 +103,7 @@ static void client_kill(pa_client *client) { assert(client && client->userdata); c = client->userdata; - pa_log_debug(__FILE__": CLI client killed.\n"); + pa_log_debug(__FILE__": CLI client killed."); if (c->defer_kill) c->kill_requested = 1; else { @@ -119,7 +119,7 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) { assert(line && c); if (!s) { - pa_log_debug(__FILE__": CLI got EOF from user.\n"); + pa_log_debug(__FILE__": CLI got EOF from user."); if (c->eof_callback) c->eof_callback(c, c->userdata); diff --git a/src/polypcore/client.c b/src/polypcore/client.c index 7fe5a9fc..852f87b0 100644 --- a/src/polypcore/client.c +++ b/src/polypcore/client.c @@ -51,7 +51,7 @@ pa_client *pa_client_new(pa_core *core, const char *name, const char *driver) { r = pa_idxset_put(core->clients, c, &c->index); assert(c->index != PA_IDXSET_INVALID && r >= 0); - pa_log_info(__FILE__": created %u \"%s\"\n", c->index, c->name); + pa_log_info(__FILE__": created %u \"%s\"", c->index, c->name); pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index); pa_core_check_quit(core); @@ -66,7 +66,7 @@ void pa_client_free(pa_client *c) { pa_core_check_quit(c->core); - pa_log_info(__FILE__": freed %u \"%s\"\n", c->index, c->name); + pa_log_info(__FILE__": freed %u \"%s\"", c->index, c->name); pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index); pa_xfree(c->name); pa_xfree(c->driver); @@ -76,7 +76,7 @@ void pa_client_free(pa_client *c) { void pa_client_kill(pa_client *c) { assert(c); if (!c->kill) { - pa_log_warn(__FILE__": kill() operation not implemented for client %u\n", c->index); + pa_log_warn(__FILE__": kill() operation not implemented for client %u", c->index); return; } diff --git a/src/polypcore/conf-parser.c b/src/polypcore/conf-parser.c index 7eeda02b..26fc33b5 100644 --- a/src/polypcore/conf-parser.c +++ b/src/polypcore/conf-parser.c @@ -45,7 +45,7 @@ static int next_assignment(const char *filename, unsigned line, const pa_config_ if (!strcmp(lvalue, t->lvalue)) return t->parse(filename, line, lvalue, rvalue, t->data, userdata); - pa_log(__FILE__": [%s:%u] Unknown lvalue '%s'.\n", filename, line, lvalue); + pa_log(__FILE__": [%s:%u] Unknown lvalue '%s'.", filename, line, lvalue); return -1; } @@ -88,7 +88,7 @@ static int parse_line(const char *filename, unsigned line, const pa_config_item return 0; if (!(e = strchr(b, '='))) { - pa_log(__FILE__": [%s:%u] Missing '='.\n", filename, line); + pa_log(__FILE__": [%s:%u] Missing '='.", filename, line); return -1; } @@ -111,7 +111,7 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void goto finish; } - pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno)); + pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", filename, strerror(errno)); goto finish; } @@ -121,7 +121,7 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void if (feof(f)) break; - pa_log(__FILE__": WARNING: failed to read configuration file '%s': %s\n", filename, strerror(errno)); + pa_log(__FILE__": WARNING: failed to read configuration file '%s': %s", filename, strerror(errno)); goto finish; } @@ -145,7 +145,7 @@ int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, assert(filename && lvalue && rvalue && data); if (pa_atoi(rvalue, &k) < 0) { - pa_log(__FILE__": [%s:%u] Failed to parse numeric value: %s\n", filename, line, rvalue); + pa_log(__FILE__": [%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); return -1; } @@ -158,7 +158,7 @@ int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue assert(filename && lvalue && rvalue && data); if ((k = pa_parse_boolean(rvalue)) < 0) { - pa_log(__FILE__": [%s:%u] Failed to parse boolean value: %s\n", filename, line, rvalue); + pa_log(__FILE__": [%s:%u] Failed to parse boolean value: %s", filename, line, rvalue); return -1; } diff --git a/src/polypcore/core-scache.c b/src/polypcore/core-scache.c index 69199a33..1803931e 100644 --- a/src/polypcore/core-scache.c +++ b/src/polypcore/core-scache.c @@ -341,7 +341,7 @@ static void add_file(pa_core *c, const char *pathname) { e = pa_path_get_filename(pathname); if (stat(pathname, &st) < 0) { - pa_log(__FILE__": stat('%s') failed: %s\n", pathname, strerror(errno)); + pa_log(__FILE__": stat('%s') failed: %s", pathname, strerror(errno)); return; } @@ -363,7 +363,7 @@ int pa_scache_add_directory_lazy(pa_core *c, const char *pathname) { /* If that fails, try to open it as shell glob */ if (glob(pathname, GLOB_ERR|GLOB_NOSORT, NULL, &p) < 0) { - pa_log(__FILE__": Failed to open directory: %s\n", strerror(errno)); + pa_log(__FILE__": Failed to open directory: %s", strerror(errno)); return -1; } diff --git a/src/polypcore/core-subscribe.c b/src/polypcore/core-subscribe.c index 4d792966..e2dd9ae3 100644 --- a/src/polypcore/core-subscribe.c +++ b/src/polypcore/core-subscribe.c @@ -158,7 +158,7 @@ void pa_subscription_free_all(pa_core *c) { break; } - pa_log(__FILE__": %u\n", e->index); + pa_log(__FILE__": %u", e->index); }*/ /* Deferred callback for dispatching subscirption events */ diff --git a/src/polypcore/ioline.c b/src/polypcore/ioline.c index 3f2de5a2..eb8fdda5 100644 --- a/src/polypcore/ioline.c +++ b/src/polypcore/ioline.c @@ -274,7 +274,7 @@ static int do_read(pa_ioline *l) { pa_ioline_puts(l, "\nExiting.\n"); do_write(l); } else if (r < 0) { - pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + pa_log(__FILE__": read() failed: %s", strerror(errno)); failure(l); return -1; } @@ -296,7 +296,7 @@ static int do_write(pa_ioline *l) { while (!l->dead && pa_iochannel_is_writable(l->io) && l->wbuf_valid_length) { if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0) { - pa_log(__FILE__": write() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); + pa_log(__FILE__": write() failed: %s", r < 0 ? strerror(errno) : "EOF"); failure(l); return -1; } diff --git a/src/polypcore/log.c b/src/polypcore/log.c index c7bf7be9..29c4c480 100644 --- a/src/polypcore/log.c +++ b/src/polypcore/log.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #ifdef HAVE_SYSLOG_H #include @@ -73,6 +75,8 @@ void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t l, const c void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { const char *e; + char *text, *t, *n; + assert(level < PA_LOG_LEVEL_MAX); if ((e = getenv(ENV_LOGLEVEL))) @@ -81,31 +85,55 @@ void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { if (level > maximal_level) return; - switch (log_target) { - case PA_LOG_STDERR: - vfprintf(stderr, format, ap); - break; + text = pa_vsprintf_malloc(format, ap); + + for (t = text; t; t = n) { + if ((n = strchr(t, '\n'))) { + *n = 0; + n++; + } + if (!*t) + continue; + + switch (log_target) { + case PA_LOG_STDERR: { + const char *prefix = "", *suffix = ""; + + /* Yes indeed. Useless, but fun! */ + if (isatty(STDERR_FILENO)) { + if (level <= PA_LOG_ERROR) { + prefix = "\x1B[1;31m"; + suffix = "\x1B[0m"; + } else if (level <= PA_LOG_WARN) { + prefix = "\x1B[1m"; + suffix = "\x1B[0m"; + } + } + fprintf(stderr, "%s%s%s\n", prefix, t, suffix); + break; + } + #ifdef HAVE_SYSLOG_H - case PA_LOG_SYSLOG: - openlog(log_ident ? log_ident : "???", LOG_PID, LOG_USER); - vsyslog(level_to_syslog[level], format, ap); - closelog(); - break; + case PA_LOG_SYSLOG: + openlog(log_ident ? log_ident : "???", LOG_PID, LOG_USER); + syslog(level_to_syslog[level], "%s", t); + closelog(); + break; #endif - - case PA_LOG_USER: { - char *t = pa_vsprintf_malloc(format, ap); - assert(user_log_func); - user_log_func(level, t); - pa_xfree(t); + + case PA_LOG_USER: + user_log_func(level, t); + break; + + case PA_LOG_NULL: + default: + break; } - - case PA_LOG_NULL: - default: - break; } + pa_xfree(text); + } void pa_log_level(pa_log_level_t level, const char *format, ...) { diff --git a/src/polypcore/memblockq.c b/src/polypcore/memblockq.c index 05c810bd..9b12a810 100644 --- a/src/polypcore/memblockq.c +++ b/src/polypcore/memblockq.c @@ -76,7 +76,7 @@ pa_memblockq* pa_memblockq_new( bq->read_index = bq->write_index = idx; bq->memblock_stat = s; - pa_log_debug(__FILE__": memblockq requested: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", maxlength, tlength, base, prebuf, minreq); + pa_log_debug(__FILE__": memblockq requested: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u", maxlength, tlength, base, prebuf, minreq); bq->maxlength = ((maxlength+base-1)/base)*base; assert(bq->maxlength >= base); @@ -98,7 +98,7 @@ pa_memblockq* pa_memblockq_new( if (!bq->minreq) bq->minreq = 1; - pa_log_debug(__FILE__": memblockq sanitized: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u\n", bq->maxlength, bq->tlength, bq->base, bq->prebuf, bq->minreq); + pa_log_debug(__FILE__": memblockq sanitized: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u", bq->maxlength, bq->tlength, bq->base, bq->prebuf, bq->minreq); bq->state = bq->prebuf ? PREBUF : RUNNING; bq->silence = silence ? pa_memblock_ref(silence) : NULL; diff --git a/src/polypcore/modinfo.c b/src/polypcore/modinfo.c index 4204bb34..e090a42f 100644 --- a/src/polypcore/modinfo.c +++ b/src/polypcore/modinfo.c @@ -65,7 +65,7 @@ pa_modinfo *pa_modinfo_get_by_name(const char *name) { assert(name); if (!(dl = lt_dlopenext(name))) { - pa_log(__FILE__": Failed to open module \"%s\": %s\n", name, lt_dlerror()); + pa_log(__FILE__": Failed to open module \"%s\": %s", name, lt_dlerror()); return NULL; } diff --git a/src/polypcore/module.c b/src/polypcore/module.c index 75385354..5412f397 100644 --- a/src/polypcore/module.c +++ b/src/polypcore/module.c @@ -69,17 +69,17 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { m->argument = pa_xstrdup(argument); if (!(m->dl = lt_dlopenext(name))) { - pa_log(__FILE__": Failed to open module \"%s\": %s\n", name, lt_dlerror()); + pa_log(__FILE__": Failed to open module \"%s\": %s", name, lt_dlerror()); goto fail; } if (!(m->init = (int (*)(pa_core *_c, pa_module*_m)) lt_dlsym(m->dl, PA_SYMBOL_INIT))) { - pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.\n", name); + pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.", name); goto fail; } if (!(m->done = (void (*)(pa_core *_c, pa_module*_m)) lt_dlsym(m->dl, PA_SYMBOL_DONE))) { - pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_DONE"\" not found.\n", name); + pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_DONE"\" not found.", name); goto fail; } @@ -91,7 +91,7 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { assert(m->init); if (m->init(c, m) < 0) { - pa_log_error(__FILE__": Failed to load module \"%s\" (argument: \"%s\"): initialization failed.\n", name, argument ? argument : ""); + pa_log_error(__FILE__": Failed to load module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : ""); goto fail; } @@ -110,7 +110,7 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { r = pa_idxset_put(c->modules, m, &m->index); assert(r >= 0 && m->index != PA_IDXSET_INVALID); - pa_log_info(__FILE__": Loaded \"%s\" (index: #%u; argument: \"%s\").\n", m->name, m->index, m->argument ? m->argument : ""); + pa_log_info(__FILE__": Loaded \"%s\" (index: #%u; argument: \"%s\").", m->name, m->index, m->argument ? m->argument : ""); pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_NEW, m->index); @@ -137,13 +137,13 @@ static void pa_module_free(pa_module *m) { if (m->core->disallow_module_loading) return; - pa_log_info(__FILE__": Unloading \"%s\" (index: #%u).\n", m->name, m->index); + pa_log_info(__FILE__": Unloading \"%s\" (index: #%u).", m->name, m->index); m->done(m->core, m); lt_dlclose(m->dl); - pa_log_info(__FILE__": Unloaded \"%s\" (index: #%u).\n", m->name, m->index); + pa_log_info(__FILE__": Unloaded \"%s\" (index: #%u).", m->name, m->index); pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_REMOVE, m->index); diff --git a/src/polypcore/pdispatch.c b/src/polypcore/pdispatch.c index 2cc90bc2..56a21bd6 100644 --- a/src/polypcore/pdispatch.c +++ b/src/polypcore/pdispatch.c @@ -196,7 +196,7 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, void *userdata) { if (!(p = command_names[command])) snprintf((char*) (p = t), sizeof(t), "%u", command); - pa_log(__FILE__": Recieved opcode <%s>\n", p); + pa_log(__FILE__": Recieved opcode <%s>", p); } #endif @@ -215,7 +215,7 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, void *userdata) { (*c)(pd, command, tag, ts, userdata); } else { - pa_log(__FILE__": Recieved unsupported command %u\n", command); + pa_log(__FILE__": Recieved unsupported command %u", command); goto finish; } diff --git a/src/polypcore/pid.c b/src/polypcore/pid.c index 3f33365a..374b5506 100644 --- a/src/polypcore/pid.c +++ b/src/polypcore/pid.c @@ -54,7 +54,7 @@ static pid_t read_pid(const char *fn, int fd) { assert(fn && fd >= 0); if ((r = pa_loop_read(fd, t, sizeof(t)-1)) < 0) { - pa_log(__FILE__": WARNING: failed to read PID file '%s': %s\n", fn, strerror(errno)); + pa_log(__FILE__": WARNING: failed to read PID file '%s': %s", fn, strerror(errno)); return (pid_t) -1; } @@ -66,7 +66,7 @@ static pid_t read_pid(const char *fn, int fd) { *e = 0; if (pa_atou(t, &pid) < 0) { - pa_log(__FILE__": WARNING: failed to parse PID file '%s'\n", fn); + pa_log(__FILE__": WARNING: failed to parse PID file '%s'", fn); return (pid_t) -1; } @@ -84,7 +84,7 @@ static int open_pid_file(const char *fn, int mode) { if ((fd = open(fn, mode, S_IRUSR|S_IWUSR)) < 0) { if (mode != O_RDONLY || errno != ENOENT) - pa_log(__FILE__": WARNING: failed to open PID file '%s': %s\n", fn, strerror(errno)); + pa_log(__FILE__": WARNING: failed to open PID file '%s': %s", fn, strerror(errno)); goto fail; } @@ -93,7 +93,7 @@ static int open_pid_file(const char *fn, int mode) { goto fail; if (fstat(fd, &st) < 0) { - pa_log(__FILE__": Failed to fstat() PID file '%s': %s\n", fn, strerror(errno)); + pa_log(__FILE__": Failed to fstat() PID file '%s': %s", fn, strerror(errno)); goto fail; } @@ -105,7 +105,7 @@ static int open_pid_file(const char *fn, int mode) { goto fail; if (close(fd) < 0) { - pa_log(__FILE__": Failed to close file '%s': %s\n", fn, strerror(errno)); + pa_log(__FILE__": Failed to close file '%s': %s", fn, strerror(errno)); goto fail; } @@ -145,7 +145,7 @@ int pa_pid_file_create(void) { goto fail; if ((pid = read_pid(fn, fd)) == (pid_t) -1) - pa_log(__FILE__": corrupt PID file, overwriting.\n"); + pa_log(__FILE__": corrupt PID file, overwriting."); else if (pid > 0) { #ifdef OS_IS_WIN32 if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)) != NULL) { @@ -153,16 +153,16 @@ int pa_pid_file_create(void) { #else if (kill(pid, 0) >= 0 || errno != ESRCH) { #endif - pa_log(__FILE__": daemon already running.\n"); + pa_log(__FILE__": daemon already running."); goto fail; } - pa_log(__FILE__": stale PID file, overwriting.\n"); + pa_log(__FILE__": stale PID file, overwriting."); } /* Overwrite the current PID file */ if (lseek(fd, 0, SEEK_SET) == (off_t) -1 || ftruncate(fd, 0) < 0) { - pa_log(__FILE__": failed to truncate PID fil: %s.\n", strerror(errno)); + pa_log(__FILE__": failed to truncate PID fil: %s.", strerror(errno)); goto fail; } @@ -170,7 +170,7 @@ int pa_pid_file_create(void) { l = strlen(t); if (pa_loop_write(fd, t, l) != (ssize_t) l) { - pa_log(__FILE__": failed to write PID file.\n"); + pa_log(__FILE__": failed to write PID file."); goto fail; } @@ -195,7 +195,7 @@ int pa_pid_file_remove(void) { pa_runtime_path("pid", fn, sizeof(fn)); if ((fd = open_pid_file(fn, O_RDWR)) < 0) { - pa_log(__FILE__": WARNING: failed to open PID file '%s': %s\n", fn, strerror(errno)); + pa_log(__FILE__": WARNING: failed to open PID file '%s': %s", fn, strerror(errno)); goto fail; } @@ -203,12 +203,12 @@ int pa_pid_file_remove(void) { goto fail; if (pid != getpid()) { - pa_log(__FILE__": WARNING: PID file '%s' not mine!\n", fn); + pa_log(__FILE__": WARNING: PID file '%s' not mine!", fn); goto fail; } if (ftruncate(fd, 0) < 0) { - pa_log(__FILE__": failed to truncate PID file '%s': %s\n", fn, strerror(errno)); + pa_log(__FILE__": failed to truncate PID file '%s': %s", fn, strerror(errno)); goto fail; } @@ -219,7 +219,7 @@ int pa_pid_file_remove(void) { #endif if (unlink(fn) < 0) { - pa_log(__FILE__": failed to remove PID file '%s': %s\n", fn, strerror(errno)); + pa_log(__FILE__": failed to remove PID file '%s': %s", fn, strerror(errno)); goto fail; } diff --git a/src/polypcore/protocol-cli.c b/src/polypcore/protocol-cli.c index cb7e8f6f..7dd489f7 100644 --- a/src/polypcore/protocol-cli.c +++ b/src/polypcore/protocol-cli.c @@ -55,7 +55,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) assert(s && io && p); if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); + pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); pa_iochannel_free(io); return; } diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index 8a0a3356..aa46e2b9 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -269,7 +269,7 @@ static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t req if (!c->authorized) { if (memcmp(data, c->protocol->esd_key, ESD_KEY_LEN) != 0) { - pa_log(__FILE__": kicked client with invalid authorization key.\n"); + pa_log(__FILE__": kicked client with invalid authorization key."); return -1; } @@ -286,7 +286,7 @@ static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t req else if (ekey == ESD_SWAP_ENDIAN_KEY) c->swap_byte_order = 1; else { - pa_log(__FILE__": client sent invalid endian key\n"); + pa_log(__FILE__": client sent invalid endian key"); return -1; } @@ -311,12 +311,12 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t format_esd2native(format, c->swap_byte_order, &ss); if (!pa_sample_spec_valid(&ss)) { - pa_log(__FILE__": invalid sample specification\n"); + pa_log(__FILE__": invalid sample specification"); return -1; } if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": no such sink\n"); + pa_log(__FILE__": no such sink"); return -1; } @@ -328,7 +328,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t assert(!c->sink_input && !c->input_memblockq); if (!(c->sink_input = pa_sink_input_new(sink, __FILE__, name, &ss, NULL, 0, -1))) { - pa_log(__FILE__": failed to create sink input.\n"); + pa_log(__FILE__": failed to create sink input."); return -1; } @@ -375,7 +375,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co format_esd2native(format, c->swap_byte_order, &ss); if (!pa_sample_spec_valid(&ss)) { - pa_log(__FILE__": invalid sample specification.\n"); + pa_log(__FILE__": invalid sample specification."); return -1; } @@ -383,19 +383,19 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co pa_sink* sink; if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": no such sink.\n"); + pa_log(__FILE__": no such sink."); return -1; } if (!(source = sink->monitor_source)) { - pa_log(__FILE__": no such monitor source.\n"); + pa_log(__FILE__": no such monitor source."); return -1; } } else { assert(request == ESD_PROTO_STREAM_REC); if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) { - pa_log(__FILE__": no such source.\n"); + pa_log(__FILE__": no such source."); return -1; } } @@ -408,7 +408,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co assert(!c->output_memblockq && !c->source_output); if (!(c->source_output = pa_source_output_new(source, __FILE__, name, &ss, NULL, -1))) { - pa_log(__FILE__": failed to create source output\n"); + pa_log(__FILE__": failed to create source output"); return -1; } @@ -733,14 +733,14 @@ static void client_kill_cb(pa_client *c) { static int do_read(struct connection *c) { assert(c && c->io); -/* pa_log("READ\n"); */ +/* pa_log("READ"); */ if (c->state == ESD_NEXT_REQUEST) { ssize_t r; assert(c->read_data_length < sizeof(c->request)); if ((r = pa_iochannel_read(c->io, ((uint8_t*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { - pa_log_debug(__FILE__": read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); + pa_log_debug(__FILE__": read() failed: %s", r < 0 ? strerror(errno) : "EOF"); return -1; } @@ -750,16 +750,16 @@ static int do_read(struct connection *c) { c->request = MAYBE_INT32_SWAP(c->swap_byte_order, c->request); if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) { - pa_log(__FILE__": recieved invalid request.\n"); + pa_log(__FILE__": recieved invalid request."); return -1; } handler = proto_map+c->request; -/* pa_log(__FILE__": executing request #%u\n", c->request); */ +/* pa_log(__FILE__": executing request #%u", c->request); */ if (!handler->proc) { - pa_log(__FILE__": recieved unimplemented request #%u.\n", c->request); + pa_log(__FILE__": recieved unimplemented request #%u.", c->request); return -1; } @@ -788,7 +788,7 @@ static int do_read(struct connection *c) { assert(c->read_data && c->read_data_length < handler->data_length); if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { - pa_log_debug(__FILE__": read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); + pa_log_debug(__FILE__": read() failed: %s", r < 0 ? strerror(errno) : "EOF"); return -1; } @@ -808,7 +808,7 @@ static int do_read(struct connection *c) { assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { - pa_log_debug(__FILE__": read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); + pa_log_debug(__FILE__": read() failed: %s", r < 0 ? strerror(errno) : "EOF"); return -1; } @@ -843,7 +843,7 @@ static int do_read(struct connection *c) { assert(c->input_memblockq); -/* pa_log("STREAMING_DATA\n"); */ +/* pa_log("STREAMING_DATA"); */ if (!(l = pa_memblockq_missing(c->input_memblockq))) return 0; @@ -865,7 +865,7 @@ static int do_read(struct connection *c) { } if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { - pa_log_debug(__FILE__": read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); + pa_log_debug(__FILE__": read() failed: %s", r < 0 ? strerror(errno) : "EOF"); return -1; } @@ -888,14 +888,14 @@ static int do_read(struct connection *c) { static int do_write(struct connection *c) { assert(c && c->io); -/* pa_log("WRITE\n"); */ +/* pa_log("WRITE"); */ if (c->write_data_length) { ssize_t r; assert(c->write_data_index < c->write_data_length); if ((r = pa_iochannel_write(c->io, (uint8_t*) c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + pa_log(__FILE__": write() failed: %s", strerror(errno)); return -1; } @@ -914,7 +914,7 @@ static int do_write(struct connection *c) { if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { pa_memblock_unref(chunk.memblock); - pa_log(__FILE__": write(): %s\n", strerror(errno)); + pa_log(__FILE__": write(): %s", strerror(errno)); return -1; } @@ -967,7 +967,7 @@ static void io_callback(pa_iochannel*io, void *userdata) { struct connection *c = userdata; assert(io && c && c->io == io); -/* pa_log("IO\n"); */ +/* pa_log("IO"); */ do_work(c); } @@ -978,7 +978,7 @@ static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) struct connection *c = userdata; assert(a && c && c->defer_event == e); -/* pa_log("DEFER\n"); */ +/* pa_log("DEFER"); */ do_work(c); } @@ -1005,7 +1005,7 @@ static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_ struct connection*c = i->userdata; assert(i && c && length); -/* pa_log("DROP\n"); */ +/* pa_log("DROP"); */ pa_memblockq_drop(c->input_memblockq, chunk, length); @@ -1072,7 +1072,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) assert(s && io && p); if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); + pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); pa_iochannel_free(io); return; } @@ -1142,7 +1142,7 @@ pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *serve p = pa_xmalloc(sizeof(pa_protocol_esound)); if (pa_modargs_get_value_boolean(ma, "public", &public) < 0) { - pa_log(__FILE__": public= expects a boolean argument.\n"); + pa_log(__FILE__": public= expects a boolean argument."); return NULL; } diff --git a/src/polypcore/protocol-http.c b/src/polypcore/protocol-http.c index f0b78124..85ddebee 100644 --- a/src/polypcore/protocol-http.c +++ b/src/polypcore/protocol-http.c @@ -143,7 +143,7 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) { /* We're done */ c->state = DATA; - pa_log_info(__FILE__": request for %s\n", c->url); + pa_log_info(__FILE__": request for %s", c->url); if (!strcmp(c->url, URL_ROOT)) { char txt[256]; @@ -222,7 +222,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) assert(s && io && p); if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log_warn(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); + pa_log_warn(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); pa_iochannel_free(io); return; } diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index aba12036..dce6b346 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -507,7 +507,7 @@ static void request_bytes(struct playback_stream *s) { pa_tagstruct_putu32(t, l); pa_pstream_send_tagstruct(s->connection->pstream, t); -/* pa_log(__FILE__": Requesting %u bytes\n", l); */ +/* pa_log(__FILE__": Requesting %u bytes", l); */ } static void send_memblock(struct connection *c) { @@ -585,11 +585,11 @@ static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { } if (pa_memblockq_peek(s->memblockq, chunk) < 0) { -/* pa_log(__FILE__": peek: failure\n"); */ +/* pa_log(__FILE__": peek: failure"); */ return -1; } -/* pa_log(__FILE__": peek: %u\n", chunk->length); */ +/* pa_log(__FILE__": peek: %u", chunk->length); */ return 0; } @@ -608,7 +608,7 @@ static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_ s->drain_request = 0; } -/* pa_log(__FILE__": after_drop: %u %u\n", pa_memblockq_get_length(s->memblockq), pa_memblockq_is_readable(s->memblockq)); */ +/* pa_log(__FILE__": after_drop: %u %u", pa_memblockq_get_length(s->memblockq), pa_memblockq_is_readable(s->memblockq)); */ } static void sink_input_kill_cb(pa_sink_input *i) { @@ -622,7 +622,7 @@ static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { assert(i && i->userdata); s = i->userdata; - /*pa_log(__FILE__": get_latency: %u\n", pa_memblockq_get_length(s->memblockq));*/ + /*pa_log(__FILE__": get_latency: %u", pa_memblockq_get_length(s->memblockq));*/ return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec); } @@ -635,7 +635,7 @@ static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) s = o->userdata; if (pa_memblockq_push_align(s->memblockq, chunk) < 0) { - pa_log_warn(__FILE__": Failed to push data into output queue.\n"); + pa_log_warn(__FILE__": Failed to push data into output queue."); return; } @@ -654,7 +654,7 @@ static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { assert(o && o->userdata); s = o->userdata; - /*pa_log(__FILE__": get_latency: %u\n", pa_memblockq_get_length(s->memblockq));*/ + /*pa_log(__FILE__": get_latency: %u", pa_memblockq_get_length(s->memblockq));*/ return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec); } @@ -662,7 +662,7 @@ static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { /*** pdispatch callbacks ***/ static void protocol_error(struct connection *c) { - pa_log(__FILE__": protocol error, kicking client\n"); + pa_log(__FILE__": protocol error, kicking client"); connection_free(c); } @@ -868,7 +868,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t if (!c->authorized) { if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) != 0) { - pa_log(__FILE__": Denied access to client with invalid authorization key.\n"); + pa_log(__FILE__": Denied access to client with invalid authorization key."); pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -958,10 +958,10 @@ static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC pa_memblockq_prebuf_disable(s->memblockq); if (!pa_memblockq_is_readable(s->memblockq)) { -/* pa_log("immediate drain: %u\n", pa_memblockq_get_length(s->memblockq)); */ +/* pa_log("immediate drain: %u", pa_memblockq_get_length(s->memblockq)); */ pa_pstream_send_simple_ack(c->pstream, tag); } else { -/* pa_log("slow drain triggered\n"); */ +/* pa_log("slow drain triggered"); */ s->drain_request = 1; s->drain_tag = tag; @@ -1967,7 +1967,7 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *user assert(p && packet && packet->data && c); if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - pa_log(__FILE__": invalid packet.\n"); + pa_log(__FILE__": invalid packet."); connection_free(c); } } @@ -1978,7 +1978,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o assert(p && chunk && userdata); if (!(stream = pa_idxset_get_by_index(c->output_streams, channel))) { - pa_log(__FILE__": client sent block for invalid stream.\n"); + pa_log(__FILE__": client sent block for invalid stream."); connection_free(c); return; } @@ -1995,7 +1995,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o if (pa_memblockq_push_align(ps->memblockq, chunk) < 0) { pa_tagstruct *t; - pa_log_warn(__FILE__": failed to push data into queue\n"); + pa_log_warn(__FILE__": failed to push data into queue"); /* Pushing this block into the queue failed, so we simulate * it by skipping ahead */ @@ -2050,7 +2050,7 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { assert(p && c); connection_free(c); -/* pa_log(__FILE__": connection died.\n");*/ +/* pa_log(__FILE__": connection died.");*/ } @@ -2084,7 +2084,7 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo assert(io && p); if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log_warn(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); + pa_log_warn(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); pa_iochannel_free(io); return; } @@ -2138,7 +2138,7 @@ static int load_key(pa_protocol_native*p, const char*fn) { p->auth_cookie_in_property = 0; if (!fn && pa_authkey_prop_get(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) { - pa_log_info(__FILE__": using already loaded auth cookie.\n"); + pa_log_info(__FILE__": using already loaded auth cookie."); pa_authkey_prop_ref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); p->auth_cookie_in_property = 1; return 0; @@ -2150,7 +2150,7 @@ static int load_key(pa_protocol_native*p, const char*fn) { if (pa_authkey_load_auto(fn, p->auth_cookie, sizeof(p->auth_cookie)) < 0) return -1; - pa_log_info(__FILE__": loading cookie from disk.\n"); + pa_log_info(__FILE__": loading cookie from disk."); if (pa_authkey_prop_put(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) p->auth_cookie_in_property = 1; @@ -2164,7 +2164,7 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo assert(c && ma); if (pa_modargs_get_value_boolean(ma, "public", &public) < 0) { - pa_log(__FILE__": public= expects a boolean argument.\n"); + pa_log(__FILE__": public= expects a boolean argument."); return NULL; } diff --git a/src/polypcore/protocol-simple.c b/src/polypcore/protocol-simple.c index fac54239..c2f53444 100644 --- a/src/polypcore/protocol-simple.c +++ b/src/polypcore/protocol-simple.c @@ -132,7 +132,7 @@ static int do_read(struct connection *c) { } if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { - pa_log_debug(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + pa_log_debug(__FILE__": read() failed: %s", r == 0 ? "EOF" : strerror(errno)); return -1; } @@ -166,7 +166,7 @@ static int do_write(struct connection *c) { if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { pa_memblock_unref(chunk.memblock); - pa_log(__FILE__": write(): %s\n", strerror(errno)); + pa_log(__FILE__": write(): %s", strerror(errno)); return -1; } @@ -313,7 +313,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) assert(s && io && p); if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.\n", MAX_CONNECTIONS); + pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); pa_iochannel_free(io); return; } @@ -342,12 +342,12 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) size_t l; if (!(sink = pa_namereg_get(p->core, p->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": Failed to get sink.\n"); + pa_log(__FILE__": Failed to get sink."); goto fail; } if (!(c->sink_input = pa_sink_input_new(sink, __FILE__, c->client->name, &p->sample_spec, NULL, 0, -1))) { - pa_log(__FILE__": Failed to create sink input.\n"); + pa_log(__FILE__": Failed to create sink input."); goto fail; } @@ -380,13 +380,13 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) size_t l; if (!(source = pa_namereg_get(p->core, p->source_name, PA_NAMEREG_SOURCE, 1))) { - pa_log(__FILE__": Failed to get source.\n"); + pa_log(__FILE__": Failed to get source."); goto fail; } c->source_output = pa_source_output_new(source, __FILE__, c->client->name, &p->sample_spec, NULL, -1); if (!c->source_output) { - pa_log(__FILE__": Failed to create source output.\n"); + pa_log(__FILE__": Failed to create source output."); goto fail; } c->source_output->owner = p->module; @@ -437,7 +437,7 @@ pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *serv p->sample_spec = core->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &p->sample_spec) < 0) { - pa_log(__FILE__": Failed to parse sample type specification.\n"); + pa_log(__FILE__": Failed to parse sample type specification."); goto fail; } @@ -446,20 +446,20 @@ pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *serv enable = 0; if (pa_modargs_get_value_boolean(ma, "record", &enable) < 0) { - pa_log(__FILE__": record= expects a numeric argument.\n"); + pa_log(__FILE__": record= expects a numeric argument."); goto fail; } p->mode = enable ? RECORD : 0; enable = 1; if (pa_modargs_get_value_boolean(ma, "playback", &enable) < 0) { - pa_log(__FILE__": playback= expects a numeric argument.\n"); + pa_log(__FILE__": playback= expects a numeric argument."); goto fail; } p->mode |= enable ? PLAYBACK : 0; if ((p->mode & (RECORD|PLAYBACK)) == 0) { - pa_log(__FILE__": neither playback nor recording enabled for protocol.\n"); + pa_log(__FILE__": neither playback nor recording enabled for protocol."); goto fail; } diff --git a/src/polypcore/pstream.c b/src/polypcore/pstream.c index c697dc3d..b1e8bd06 100644 --- a/src/polypcore/pstream.c +++ b/src/polypcore/pstream.c @@ -246,7 +246,7 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet) { if (p->dead) return; -/* pa_log(__FILE__": push-packet %p\n", packet); */ +/* pa_log(__FILE__": push-packet %p", packet); */ i = pa_xnew(struct item_info, 1); i->type = PA_PSTREAM_ITEM_PACKET; @@ -263,7 +263,7 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa if (p->dead) return; -/* pa_log(__FILE__": push-memblock %p\n", chunk); */ +/* pa_log(__FILE__": push-memblock %p", chunk); */ i = pa_xnew(struct item_info, 1); i->type = PA_PSTREAM_ITEM_MEMBLOCK; @@ -301,7 +301,7 @@ static void prepare_next_write_item(pa_pstream *p) { p->write.index = 0; if (p->write.current->type == PA_PSTREAM_ITEM_PACKET) { - /*pa_log(__FILE__": pop-packet %p\n", p->write.current->packet);*/ + /*pa_log(__FILE__": pop-packet %p", p->write.current->packet);*/ assert(p->write.current->packet); p->write.data = p->write.current->packet->data; @@ -385,7 +385,7 @@ static int do_read(pa_pstream *p) { /* Frame size too large */ if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) > FRAME_SIZE_MAX) { - pa_log_warn(__FILE__": Frame size too large\n"); + pa_log_warn(__FILE__": Frame size too large"); return -1; } @@ -401,7 +401,7 @@ static int do_read(pa_pstream *p) { p->read.data = p->read.memblock->data; if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK]) > PA_SEEK_RELATIVE_END) { - pa_log_warn(__FILE__": Invalid seek mode\n"); + pa_log_warn(__FILE__": Invalid seek mode"); return -1; } } diff --git a/src/polypcore/random.c b/src/polypcore/random.c index 756c3218..1c2280e3 100644 --- a/src/polypcore/random.c +++ b/src/polypcore/random.c @@ -49,7 +49,7 @@ void pa_random(void *ret_data, size_t length) { if ((fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) { if ((r = pa_loop_read(fd, ret_data, length)) < 0 || (size_t) r != length) - pa_log_error(__FILE__": failed to read entropy from '%s'\n", RANDOM_DEVICE); + pa_log_error(__FILE__": failed to read entropy from '%s'", RANDOM_DEVICE); close(fd); } diff --git a/src/polypcore/sample-util.c b/src/polypcore/sample-util.c index e588446d..2c3fbd79 100644 --- a/src/polypcore/sample-util.c +++ b/src/polypcore/sample-util.c @@ -330,7 +330,7 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol } default: - pa_log_error(__FILE__": ERROR: Unable to change volume of format %s.\n", + pa_log_error(__FILE__": ERROR: Unable to change volume of format %s.", pa_sample_format_to_string(spec->format)); abort(); } diff --git a/src/polypcore/sink-input.c b/src/polypcore/sink-input.c index 1dc7df0f..f12a85e1 100644 --- a/src/polypcore/sink-input.c +++ b/src/polypcore/sink-input.c @@ -57,7 +57,7 @@ pa_sink_input* pa_sink_input_new( assert(s->state == PA_SINK_RUNNING); if (pa_idxset_size(s->inputs) >= PA_MAX_INPUTS_PER_SINK) { - pa_log_warn(__FILE__": Failed to create sink input: too many inputs per sink.\n"); + pa_log_warn(__FILE__": Failed to create sink input: too many inputs per sink."); return NULL; } @@ -106,7 +106,7 @@ pa_sink_input* pa_sink_input_new( assert(r == 0); pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"\n", i->index, i->name, s->index, st); + pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"", i->index, i->name, s->index, st); pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index); @@ -141,7 +141,7 @@ static void sink_input_free(pa_sink_input* i) { if (i->state != PA_SINK_INPUT_DISCONNECTED) pa_sink_input_disconnect(i); - pa_log_info(__FILE__": freed %u \"%s\"\n", i->index, i->name); + pa_log_info(__FILE__": freed %u \"%s\"", i->index, i->name); if (i->resampled_chunk.memblock) pa_memblock_unref(i->resampled_chunk.memblock); diff --git a/src/polypcore/sink.c b/src/polypcore/sink.c index 1f374f5e..cb072c35 100644 --- a/src/polypcore/sink.c +++ b/src/polypcore/sink.c @@ -95,7 +95,7 @@ pa_sink* pa_sink_new( assert(s->index != PA_IDXSET_INVALID && r >= 0); pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); + pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"", s->index, s->name, st); n = pa_sprintf_malloc("%s_monitor", name); s->monitor_source = pa_source_new(core, driver, n, 0, spec, map); @@ -143,7 +143,7 @@ static void sink_free(pa_sink *s) { if (s->state != PA_SINK_DISCONNECTED) pa_sink_disconnect(s); - pa_log_info(__FILE__": freed %u \"%s\"\n", s->index, s->name); + pa_log_info(__FILE__": freed %u \"%s\"", s->index, s->name); pa_source_unref(s->monitor_source); s->monitor_source = NULL; @@ -270,7 +270,7 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { result->memblock = pa_memblock_new(length, s->core->memblock_stat); assert(result->memblock); -/* pa_log("mixing %i\n", n); */ +/* pa_log("mixing %i", n); */ result->length = pa_mix(info, n, result->memblock->data, length, &s->sample_spec, &s->sw_volume); result->index = 0; diff --git a/src/polypcore/socket-client.c b/src/polypcore/socket-client.c index 3662e89c..d73b22d1 100644 --- a/src/polypcore/socket-client.c +++ b/src/polypcore/socket-client.c @@ -137,17 +137,17 @@ static void do_call(pa_socket_client *c) { lerror = sizeof(error); if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &lerror) < 0) { - pa_log(__FILE__": getsockopt(): %s\n", strerror(errno)); + pa_log(__FILE__": getsockopt(): %s", strerror(errno)); goto finish; } if (lerror != sizeof(error)) { - pa_log(__FILE__": getsockopt() returned invalid size.\n"); + pa_log(__FILE__": getsockopt() returned invalid size."); goto finish; } if (error != 0) { - pa_log_debug(__FILE__": connect(): %s\n", strerror(error)); + pa_log_debug(__FILE__": connect(): %s", strerror(error)); errno = error; goto finish; } @@ -188,7 +188,7 @@ static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t if ((r = connect(c->fd, sa, len)) < 0) { if (errno != EINPROGRESS) { - /*pa_log(__FILE__": connect(): %s\n", strerror(errno));*/ + /*pa_log(__FILE__": connect(): %s", strerror(errno));*/ return -1; } @@ -259,7 +259,7 @@ static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size } if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s\n", strerror(errno)); + pa_log(__FILE__": socket(): %s", strerror(errno)); return -1; } diff --git a/src/polypcore/socket-server.c b/src/polypcore/socket-server.c index b1297496..f2e15085 100644 --- a/src/polypcore/socket-server.c +++ b/src/polypcore/socket-server.c @@ -88,7 +88,7 @@ static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_U pa_socket_server_ref(s); if ((nfd = accept(fd, NULL, NULL)) < 0) { - pa_log(__FILE__": accept(): %s\n", strerror(errno)); + pa_log(__FILE__": accept(): %s", strerror(errno)); goto finish; } @@ -107,12 +107,12 @@ static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_U request_init(&req, RQ_DAEMON, s->tcpwrap_service, RQ_FILE, nfd, NULL); fromhost(&req); if (!hosts_access(&req)) { - pa_log_warn(__FILE__": TCP connection refused by tcpwrap.\n"); + pa_log_warn(__FILE__": TCP connection refused by tcpwrap."); close(nfd); goto finish; } - pa_log_info(__FILE__": TCP connection accepted by tcpwrap.\n"); + pa_log_info(__FILE__": TCP connection accepted by tcpwrap."); } #endif @@ -167,7 +167,7 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file assert(m && filename); if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s\n", strerror(errno)); + pa_log(__FILE__": socket(): %s", strerror(errno)); goto fail; } @@ -180,12 +180,12 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file pa_socket_low_delay(fd); if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) { - pa_log(__FILE__": bind(): %s\n", strerror(errno)); + pa_log(__FILE__": bind(): %s", strerror(errno)); goto fail; } if (listen(fd, 5) < 0) { - pa_log(__FILE__": listen(): %s\n", strerror(errno)); + pa_log(__FILE__": listen(): %s", strerror(errno)); goto fail; } @@ -221,14 +221,14 @@ pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address assert(m && port); if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(PF_INET): %s\n", strerror(errno)); + pa_log(__FILE__": socket(PF_INET): %s", strerror(errno)); goto fail; } pa_fd_set_cloexec(fd, 1); if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0) - pa_log(__FILE__": setsockopt(): %s\n", strerror(errno)); + pa_log(__FILE__": setsockopt(): %s", strerror(errno)); pa_socket_tcp_low_delay(fd); @@ -238,12 +238,12 @@ pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address sa.sin_addr.s_addr = htonl(address); if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { - pa_log(__FILE__": bind(): %s\n", strerror(errno)); + pa_log(__FILE__": bind(): %s", strerror(errno)); goto fail; } if (listen(fd, 5) < 0) { - pa_log(__FILE__": listen(): %s\n", strerror(errno)); + pa_log(__FILE__": listen(): %s", strerror(errno)); goto fail; } @@ -270,14 +270,14 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad assert(m && port); if ((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(PF_INET6): %s\n", strerror(errno)); + pa_log(__FILE__": socket(PF_INET6): %s", strerror(errno)); goto fail; } pa_fd_set_cloexec(fd, 1); if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0) - pa_log(__FILE__": setsockopt(): %s\n", strerror(errno)); + pa_log(__FILE__": setsockopt(): %s", strerror(errno)); pa_socket_tcp_low_delay(fd); @@ -287,12 +287,12 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad memcpy(sa.sin6_addr.s6_addr, address, 16); if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { - pa_log(__FILE__": bind(): %s\n", strerror(errno)); + pa_log(__FILE__": bind(): %s", strerror(errno)); goto fail; } if (listen(fd, 5) < 0) { - pa_log(__FILE__": listen(): %s\n", strerror(errno)); + pa_log(__FILE__": listen(): %s", strerror(errno)); goto fail; } @@ -348,7 +348,7 @@ pa_socket_server* pa_socket_server_new_ip_string(pa_mainloop_api *m, const char if (inet_pton(AF_INET, name, &ipv4) > 0) return pa_socket_server_new_ipv4(m, ntohl(ipv4), port, tcpwrap_service); - pa_log_warn(__FILE__": failed to parse '%s'.\n", name); + pa_log_warn(__FILE__": failed to parse '%s'.", name); return NULL; } @@ -392,7 +392,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { socklen_t sa_len = sizeof(sa); if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) { - pa_log(__FILE__": getsockname() failed: %s\n", strerror(errno)); + pa_log(__FILE__": getsockname() failed: %s", strerror(errno)); return NULL; } @@ -413,7 +413,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { char ip[INET6_ADDRSTRLEN]; if (!inet_ntop(AF_INET6, &sa.sin6_addr, ip, sizeof(ip))) { - pa_log(__FILE__": inet_ntop() failed: %s\n", strerror(errno)); + pa_log(__FILE__": inet_ntop() failed: %s", strerror(errno)); return NULL; } @@ -428,7 +428,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { socklen_t sa_len = sizeof(sa); if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) { - pa_log(__FILE__": getsockname() failed: %s\n", strerror(errno)); + pa_log(__FILE__": getsockname() failed: %s", strerror(errno)); return NULL; } @@ -448,7 +448,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { char ip[INET_ADDRSTRLEN]; if (!inet_ntop(AF_INET, &sa.sin_addr, ip, sizeof(ip))) { - pa_log(__FILE__": inet_ntop() failed: %s\n", strerror(errno)); + pa_log(__FILE__": inet_ntop() failed: %s", strerror(errno)); return NULL; } diff --git a/src/polypcore/socket-util.c b/src/polypcore/socket-util.c index 5ffe5302..915c7f22 100644 --- a/src/polypcore/socket-util.c +++ b/src/polypcore/socket-util.c @@ -172,7 +172,7 @@ int pa_socket_set_rcvbuf(int fd, size_t l) { assert(fd >= 0); /* if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&l, sizeof(l)) < 0) { */ -/* pa_log(__FILE__": SO_RCVBUF: %s\n", strerror(errno)); */ +/* pa_log(__FILE__": SO_RCVBUF: %s", strerror(errno)); */ /* return -1; */ /* } */ @@ -183,7 +183,7 @@ int pa_socket_set_sndbuf(int fd, size_t l) { assert(fd >= 0); /* if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&l, sizeof(l)) < 0) { */ -/* pa_log(__FILE__": SO_SNDBUF: %s\n", strerror(errno)); */ +/* pa_log(__FILE__": SO_SNDBUF: %s", strerror(errno)); */ /* return -1; */ /* } */ @@ -197,7 +197,7 @@ int pa_unix_socket_is_stale(const char *fn) { int fd = -1, ret = -1; if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s\n", strerror(errno)); + pa_log(__FILE__": socket(): %s", strerror(errno)); goto finish; } diff --git a/src/polypcore/sound-file-stream.c b/src/polypcore/sound-file-stream.c index 644e578f..e242cfea 100644 --- a/src/polypcore/sound-file-stream.c +++ b/src/polypcore/sound-file-stream.c @@ -131,7 +131,7 @@ int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume) { memset(&sfinfo, 0, sizeof(sfinfo)); if (!(u->sndfile = sf_open(fname, SFM_READ, &sfinfo))) { - pa_log(__FILE__": Failed to open file %s\n", fname); + pa_log(__FILE__": Failed to open file %s", fname); goto fail; } @@ -154,7 +154,7 @@ int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume) { ss.channels = sfinfo.channels; if (!pa_sample_spec_valid(&ss)) { - pa_log(__FILE__": Unsupported sample format in file %s\n", fname); + pa_log(__FILE__": Unsupported sample format in file %s", fname); goto fail; } diff --git a/src/polypcore/sound-file.c b/src/polypcore/sound-file.c index cf23e0ac..d86141ce 100644 --- a/src/polypcore/sound-file.c +++ b/src/polypcore/sound-file.c @@ -49,7 +49,7 @@ int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_memchunk *chunk memset(&sfinfo, 0, sizeof(sfinfo)); if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) { - pa_log(__FILE__": Failed to open file %s\n", fname); + pa_log(__FILE__": Failed to open file %s", fname); goto finish; } @@ -71,12 +71,12 @@ int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_memchunk *chunk ss->channels = sfinfo.channels; if (!pa_sample_spec_valid(ss)) { - pa_log(__FILE__": Unsupported sample format in file %s\n", fname); + pa_log(__FILE__": Unsupported sample format in file %s", fname); goto finish; } if ((l = pa_frame_size(ss)*sfinfo.frames) > MAX_FILE_SIZE) { - pa_log(__FILE__": File too large\n"); + pa_log(__FILE__": File too large"); goto finish; } @@ -86,7 +86,7 @@ int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_memchunk *chunk chunk->length = l; if (readf_function(sf, chunk->memblock->data, sfinfo.frames) != sfinfo.frames) { - pa_log(__FILE__": Premature file end\n"); + pa_log(__FILE__": Premature file end"); goto finish; } @@ -110,7 +110,7 @@ int pa_sound_file_too_big_to_cache(const char *fname) { pa_sample_spec ss; if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) { - pa_log(__FILE__": Failed to open file %s\n", fname); + pa_log(__FILE__": Failed to open file %s", fname); return 0; } @@ -132,7 +132,7 @@ int pa_sound_file_too_big_to_cache(const char *fname) { ss.channels = sfinfo.channels; if ((pa_frame_size(&ss) * sfinfo.frames) > MAX_FILE_SIZE) { - pa_log(__FILE__": File too large %s\n", fname); + pa_log(__FILE__": File too large %s", fname); return 1; } diff --git a/src/polypcore/source-output.c b/src/polypcore/source-output.c index d6201b4d..0cb5f356 100644 --- a/src/polypcore/source-output.c +++ b/src/polypcore/source-output.c @@ -53,7 +53,7 @@ pa_source_output* pa_source_output_new( assert(s->state == PA_SOURCE_RUNNING); if (pa_idxset_size(s->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { - pa_log(__FILE__": Failed to create source output: too many outputs per source.\n"); + pa_log(__FILE__": Failed to create source output: too many outputs per source."); return NULL; } @@ -95,7 +95,7 @@ pa_source_output* pa_source_output_new( assert(r == 0); pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"\n", o->index, o->name, s->index, st); + pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"", o->index, o->name, s->index, st); pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); @@ -127,7 +127,7 @@ static void source_output_free(pa_source_output* o) { if (o->state != PA_SOURCE_OUTPUT_DISCONNECTED) pa_source_output_disconnect(o); - pa_log_info(__FILE__": freed %u \"%s\"\n", o->index, o->name); + pa_log_info(__FILE__": freed %u \"%s\"", o->index, o->name); if (o->resampler) pa_resampler_free(o->resampler); diff --git a/src/polypcore/source.c b/src/polypcore/source.c index 8bca8a1d..e97c31d8 100644 --- a/src/polypcore/source.c +++ b/src/polypcore/source.c @@ -91,7 +91,7 @@ pa_source* pa_source_new( assert(s->index != PA_IDXSET_INVALID && r >= 0); pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); + pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"", s->index, s->name, st); pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index); @@ -130,7 +130,7 @@ static void source_free(pa_source *s) { if (s->state != PA_SOURCE_DISCONNECTED) pa_source_disconnect(s); - pa_log_info(__FILE__": freed %u \"%s\"\n", s->index, s->name); + pa_log_info(__FILE__": freed %u \"%s\"", s->index, s->name); pa_idxset_free(s->outputs, NULL, NULL); diff --git a/src/polypcore/util.c b/src/polypcore/util.c index 2ae94d25..f53eef34 100644 --- a/src/polypcore/util.c +++ b/src/polypcore/util.c @@ -120,10 +120,10 @@ void pa_make_nonblock_fd(int fd) { u_long arg = 1; if (ioctlsocket(fd, FIONBIO, &arg) < 0) { if (WSAGetLastError() == WSAENOTSOCK) - pa_log_warn(__FILE__": WARNING: Only sockets can be made non-blocking!\n"); + pa_log_warn(__FILE__": WARNING: Only sockets can be made non-blocking!"); } #else - pa_log_warn(__FILE__": WARNING: Non-blocking I/O not supported.!\n"); + pa_log_warn(__FILE__": WARNING: Non-blocking I/O not supported.!"); #endif } @@ -242,7 +242,7 @@ void pa_check_signal_is_blocked(int sig) { if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) { #endif if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) { - pa_log(__FILE__": sigprocmask() failed: %s\n", strerror(errno)); + pa_log(__FILE__": sigprocmask() failed: %s", strerror(errno)); return; } #ifdef HAVE_PTHREAD @@ -255,16 +255,16 @@ void pa_check_signal_is_blocked(int sig) { /* Check whether the signal is trapped */ if (sigaction(sig, NULL, &sa) < 0) { - pa_log(__FILE__": sigaction() failed: %s\n", strerror(errno)); + pa_log(__FILE__": sigaction() failed: %s", strerror(errno)); return; } if (sa.sa_handler != SIG_DFL) return; - pa_log(__FILE__": WARNING: %s is not trapped. This might cause malfunction!\n", pa_strsignal(sig)); + pa_log(__FILE__": WARNING: %s is not trapped. This might cause malfunction!", pa_strsignal(sig)); #else /* HAVE_SIGACTION */ - pa_log(__FILE__": WARNING: %s might not be trapped. This might cause malfunction!\n", pa_strsignal(sig)); + pa_log(__FILE__": WARNING: %s might not be trapped. This might cause malfunction!", pa_strsignal(sig)); #endif } @@ -366,7 +366,7 @@ char *pa_get_user_name(char *s, size_t l) { char *pa_get_host_name(char *s, size_t l) { assert(s && l > 0); if (gethostname(s, l) < 0) { - pa_log(__FILE__": gethostname(): %s\n", strerror(errno)); + pa_log(__FILE__": gethostname(): %s", strerror(errno)); return NULL; } s[l-1] = 0; @@ -393,12 +393,12 @@ char *pa_get_home_dir(char *s, size_t l) { #ifdef HAVE_PWD_H #ifdef HAVE_GETPWUID_R if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { - pa_log(__FILE__": getpwuid_r() failed\n"); + pa_log(__FILE__": getpwuid_r() failed"); #else /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) * that do not support getpwuid_r. */ if ((r = getpwuid(getuid())) == NULL) { - pa_log(__FILE__": getpwuid_r() failed\n"); + pa_log(__FILE__": getpwuid_r() failed"); #endif return NULL; } @@ -534,9 +534,9 @@ void pa_raise_priority(void) { #ifdef HAVE_SYS_RESOURCE_H if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) - pa_log_warn(__FILE__": setpriority() failed: %s\n", strerror(errno)); + pa_log_warn(__FILE__": setpriority() failed: %s", strerror(errno)); else - pa_log_info(__FILE__": Successfully gained nice level %i.\n", NICE_LEVEL); + pa_log_info(__FILE__": Successfully gained nice level %i.", NICE_LEVEL); #endif #ifdef _POSIX_PRIORITY_SCHEDULING @@ -544,25 +544,25 @@ void pa_raise_priority(void) { struct sched_param sp; if (sched_getparam(0, &sp) < 0) { - pa_log(__FILE__": sched_getparam() failed: %s\n", strerror(errno)); + pa_log(__FILE__": sched_getparam() failed: %s", strerror(errno)); return; } sp.sched_priority = 1; if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) { - pa_log_warn(__FILE__": sched_setscheduler() failed: %s\n", strerror(errno)); + pa_log_warn(__FILE__": sched_setscheduler() failed: %s", strerror(errno)); return; } - pa_log_info(__FILE__": Successfully enabled SCHED_FIFO scheduling.\n"); + pa_log_info(__FILE__": Successfully enabled SCHED_FIFO scheduling."); } #endif #ifdef OS_IS_WIN32 if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) - pa_log_warn(__FILE__": SetPriorityClass() failed: 0x%08X\n", GetLastError()); + pa_log_warn(__FILE__": SetPriorityClass() failed: 0x%08X", GetLastError()); else - pa_log_info(__FILE__": Successfully gained high priority class.\n"); + pa_log_info(__FILE__": Successfully gained high priority class."); #endif } @@ -741,7 +741,7 @@ static int is_group(gid_t gid, const char *name) { data = pa_xmalloc(n); if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) { - pa_log(__FILE__ ": getgrgid_r(%u) failed: %s\n", gid, strerror(errno)); + pa_log(__FILE__ ": getgrgid_r(%u) failed: %s", gid, strerror(errno)); goto finish; } @@ -754,7 +754,7 @@ finish: /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not * support getgrgid_r. */ if ((result = getgrgid(gid)) == NULL) { - pa_log(__FILE__ ": getgrgid(%u) failed: %s\n", gid, strerror(errno)); + pa_log(__FILE__ ": getgrgid(%u) failed: %s", gid, strerror(errno)); goto finish; } @@ -777,7 +777,7 @@ int pa_uid_in_group(const char *name, gid_t *gid) { gids = pa_xmalloc(sizeof(GETGROUPS_T)*n); if ((n = getgroups(n, gids)) < 0) { - pa_log(__FILE__": getgroups() failed: %s\n", strerror(errno)); + pa_log(__FILE__": getgroups() failed: %s", strerror(errno)); goto finish; } @@ -834,7 +834,7 @@ int pa_lock_fd(int fd, int b) { return 0; } - pa_log(__FILE__": %slock failed: %s\n", !b ? "un" : "", strerror(errno)); + pa_log(__FILE__": %slock failed: %s", !b ? "un" : "", strerror(errno)); #endif #ifdef OS_IS_WIN32 @@ -845,7 +845,7 @@ int pa_lock_fd(int fd, int b) { if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) return 0; - pa_log(__FILE__": %slock failed: 0x%08X\n", !b ? "un" : "", GetLastError()); + pa_log(__FILE__": %slock failed: 0x%08X", !b ? "un" : "", GetLastError()); #endif return -1; @@ -868,17 +868,17 @@ int pa_lock_lockfile(const char *fn) { struct stat st; if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { - pa_log(__FILE__": failed to create lock file '%s': %s\n", fn, strerror(errno)); + pa_log(__FILE__": failed to create lock file '%s': %s", fn, strerror(errno)); goto fail; } if (pa_lock_fd(fd, 1) < 0) { - pa_log(__FILE__": failed to lock file '%s'.\n", fn); + pa_log(__FILE__": failed to lock file '%s'.", fn); goto fail; } if (fstat(fd, &st) < 0) { - pa_log(__FILE__": failed to fstat() file '%s'.\n", fn); + pa_log(__FILE__": failed to fstat() file '%s'.", fn); goto fail; } @@ -887,12 +887,12 @@ int pa_lock_lockfile(const char *fn) { break; if (pa_lock_fd(fd, 0) < 0) { - pa_log(__FILE__": failed to unlock file '%s'.\n", fn); + pa_log(__FILE__": failed to unlock file '%s'.", fn); goto fail; } if (close(fd) < 0) { - pa_log(__FILE__": failed to close file '%s'.\n", fn); + pa_log(__FILE__": failed to close file '%s'.", fn); goto fail; } @@ -915,17 +915,17 @@ int pa_unlock_lockfile(const char *fn, int fd) { assert(fn && fd >= 0); if (unlink(fn) < 0) { - pa_log_warn(__FILE__": WARNING: unable to remove lock file '%s': %s\n", fn, strerror(errno)); + pa_log_warn(__FILE__": WARNING: unable to remove lock file '%s': %s", fn, strerror(errno)); r = -1; } if (pa_lock_fd(fd, 0) < 0) { - pa_log_warn(__FILE__": WARNING: failed to unlock file '%s'.\n", fn); + pa_log_warn(__FILE__": WARNING: failed to unlock file '%s'.", fn); r = -1; } if (close(fd) < 0) { - pa_log_warn(__FILE__": WARNING: failed to close lock file '%s': %s\n", fn, strerror(errno)); + pa_log_warn(__FILE__": WARNING: failed to close lock file '%s': %s", fn, strerror(errno)); r = -1; } diff --git a/src/polypcore/x11wrap.c b/src/polypcore/x11wrap.c index 9414fbdf..21a7f307 100644 --- a/src/polypcore/x11wrap.c +++ b/src/polypcore/x11wrap.c @@ -138,7 +138,7 @@ static pa_x11_wrapper* x11_wrapper_new(pa_core *c, const char *name, const char int r; if (!(d = XOpenDisplay(name))) { - pa_log(__FILE__": XOpenDisplay() failed\n"); + pa_log(__FILE__": XOpenDisplay() failed"); return NULL; } diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c index 4054bc2c..a71e0e93 100644 --- a/src/utils/pacmd.c +++ b/src/utils/pacmd.c @@ -46,12 +46,12 @@ int main(PA_GCC_UNUSED int main, PA_GCC_UNUSED char*argv[]) { fd_set ifds, ofds; if (pa_pid_file_check_running(&pid) < 0) { - pa_log(__FILE__": no Polypaudio daemon running\n"); + pa_log(__FILE__": no Polypaudio daemon running"); goto fail; } if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(PF_UNIX, SOCK_STREAM, 0): %s\n", strerror(errno)); + pa_log(__FILE__": socket(PF_UNIX, SOCK_STREAM, 0): %s", strerror(errno)); goto fail; } @@ -63,7 +63,7 @@ int main(PA_GCC_UNUSED int main, PA_GCC_UNUSED char*argv[]) { int r; if ((r = connect(fd, (struct sockaddr*) &sa, sizeof(sa))) < 0 && (errno != ECONNREFUSED && errno != ENOENT)) { - pa_log(__FILE__": connect() failed: %s\n", strerror(errno)); + pa_log(__FILE__": connect() failed: %s", strerror(errno)); goto fail; } @@ -71,7 +71,7 @@ int main(PA_GCC_UNUSED int main, PA_GCC_UNUSED char*argv[]) { break; if (pa_pid_file_kill(SIGUSR2, NULL) < 0) { - pa_log(__FILE__": failed to kill Polypaudio daemon.\n"); + pa_log(__FILE__": failed to kill Polypaudio daemon."); goto fail; } @@ -79,7 +79,7 @@ int main(PA_GCC_UNUSED int main, PA_GCC_UNUSED char*argv[]) { } if (i >= 5) { - pa_log(__FILE__": daemon not responding.\n"); + pa_log(__FILE__": daemon not responding."); goto fail; } @@ -94,7 +94,7 @@ int main(PA_GCC_UNUSED int main, PA_GCC_UNUSED char*argv[]) { for (;;) { if (select(FD_SETSIZE, &ifds, &ofds, NULL, NULL) < 0) { - pa_log(__FILE__": select() failed: %s\n", strerror(errno)); + pa_log(__FILE__": select() failed: %s", strerror(errno)); goto fail; } @@ -106,7 +106,7 @@ int main(PA_GCC_UNUSED int main, PA_GCC_UNUSED char*argv[]) { if (r == 0) break; - pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + pa_log(__FILE__": read() failed: %s", strerror(errno)); goto fail; } @@ -122,7 +122,7 @@ int main(PA_GCC_UNUSED int main, PA_GCC_UNUSED char*argv[]) { if (r == 0) break; - pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + pa_log(__FILE__": read() failed: %s", strerror(errno)); goto fail; } @@ -135,7 +135,7 @@ int main(PA_GCC_UNUSED int main, PA_GCC_UNUSED char*argv[]) { assert(obuf_length); if ((r = write(1, obuf + obuf_index, obuf_length)) < 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + pa_log(__FILE__": write() failed: %s", strerror(errno)); goto fail; } @@ -149,7 +149,7 @@ int main(PA_GCC_UNUSED int main, PA_GCC_UNUSED char*argv[]) { assert(ibuf_length); if ((r = write(fd, ibuf + ibuf_index, ibuf_length)) < 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + pa_log(__FILE__": write() failed: %s", strerror(errno)); goto fail; } diff --git a/src/utils/pax11publish.c b/src/utils/pax11publish.c index 56b62d37..e4358894 100644 --- a/src/utils/pax11publish.c +++ b/src/utils/pax11publish.c @@ -90,7 +90,7 @@ int main(int argc, char *argv[]) { } if (!(d = XOpenDisplay(dname))) { - pa_log(__FILE__": XOpenDisplay() failed\n"); + pa_log(__FILE__": XOpenDisplay() failed"); goto finish; } -- cgit -- cgit -- cgit From c2290c52a4af1be39cb9ecbaa26eb524426f98dc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Feb 2006 02:29:52 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@577 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/todo b/doc/todo index 9abfd2d0..18a2218d 100644 --- a/doc/todo +++ b/doc/todo @@ -6,9 +6,8 @@ Test: Fixes: - better validity checking in protocol-esound -- change pa_log to not require \n - proper use of memcpy in procotol-esound.c so we don't get alignment problems -- latency api for native protocol +- latency api rework for native protocol - add support for auth using SCM_CREDENTIALS - use scatter/gather io for sockets - notification on hw volume change -- cgit From ce9b035b7bf2af53bbfcabbc474e62f422224f87 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 23 Feb 2006 08:59:31 +0000 Subject: Hardware source volume support in OSS. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@578 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss-mmap.c | 32 ++++++++++++++++++++++++++++++-- src/modules/module-oss.c | 32 ++++++++++++++++++++++++++++++-- src/modules/oss-util.c | 24 ++++++++++++++++++++---- src/modules/oss-util.h | 7 +++++-- 4 files changed, 85 insertions(+), 10 deletions(-) diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index 9687c908..e1e54fb5 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -224,7 +224,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { static int sink_get_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; - if (pa_oss_get_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + if (pa_oss_get_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", strerror(errno)); s->get_hw_volume = NULL; return -1; @@ -236,7 +236,31 @@ static int sink_get_hw_volume(pa_sink *s) { static int sink_set_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; - if (pa_oss_set_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + if (pa_oss_set_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", strerror(errno)); + s->set_hw_volume = NULL; + return -1; + } + + return 0; +} + +static int source_get_hw_volume(pa_source *s) { + struct userdata *u = s->userdata; + + if (pa_oss_get_imix_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", strerror(errno)); + s->get_hw_volume = NULL; + return -1; + } + + return 0; +} + +static int source_set_hw_volume(pa_source *s) { + struct userdata *u = s->userdata; + + if (pa_oss_set_imix_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", strerror(errno)); s->set_hw_volume = NULL; return -1; @@ -337,6 +361,8 @@ int pa__init(pa_core *c, pa_module*m) { u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec, NULL); assert(u->source); + u->source->get_hw_volume = source_get_hw_volume; + u->source->set_hw_volume = source_set_hw_volume; u->source->userdata = u; pa_source_set_owner(u->source, m); u->source->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'%s%s%s", @@ -409,6 +435,8 @@ int pa__init(pa_core *c, pa_module*m) { pa_modargs_free(ma); /* Read mixer settings */ + if (u->source) + source_get_hw_volume(u->source); if (u->sink) sink_get_hw_volume(u->sink); diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 67ece5a7..3a3f6b88 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -256,7 +256,7 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { static int sink_get_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; - if (pa_oss_get_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + if (pa_oss_get_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", strerror(errno)); s->get_hw_volume = NULL; return -1; @@ -268,7 +268,31 @@ static int sink_get_hw_volume(pa_sink *s) { static int sink_set_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; - if (pa_oss_set_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + if (pa_oss_set_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", strerror(errno)); + s->set_hw_volume = NULL; + return -1; + } + + return 0; +} + +static int source_get_hw_volume(pa_source *s) { + struct userdata *u = s->userdata; + + if (pa_oss_get_imix_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", strerror(errno)); + s->get_hw_volume = NULL; + return -1; + } + + return 0; +} + +static int source_set_hw_volume(pa_source *s) { + struct userdata *u = s->userdata; + + if (pa_oss_set_imix_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", strerror(errno)); s->set_hw_volume = NULL; return -1; @@ -368,6 +392,8 @@ int pa__init(pa_core *c, pa_module*m) { u->source->userdata = u; u->source->notify = source_notify_cb; u->source->get_latency = source_get_latency_cb; + u->source->get_hw_volume = source_get_hw_volume; + u->source->set_hw_volume = source_set_hw_volume; pa_source_set_owner(u->source, m); u->source->description = pa_sprintf_malloc("Open Sound System PCM on '%s'%s%s%s", p, @@ -426,6 +452,8 @@ int pa__init(pa_core *c, pa_module*m) { } /* Read mixer settings */ + if (u->source) + source_get_hw_volume(u->source); if (u->sink) sink_get_hw_volume(u->sink); diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index 2c12e28d..30a4b998 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -167,7 +167,7 @@ int pa_oss_set_fragments(int fd, int nfrags, int frag_size) { return 0; } -int pa_oss_get_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume) { +static int pa_oss_get_volume(int fd, int mixer, const pa_sample_spec *ss, pa_cvolume *volume) { char cv[PA_CVOLUME_SNPRINT_MAX]; unsigned vol; @@ -175,7 +175,7 @@ int pa_oss_get_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume) { assert(ss); assert(volume); - if (ioctl(fd, SOUND_MIXER_READ_PCM, &vol) < 0) + if (ioctl(fd, mixer, &vol) < 0) return -1; volume->values[0] = ((vol & 0xFF) * PA_VOLUME_NORM) / 100; @@ -187,7 +187,7 @@ int pa_oss_get_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume) { return 0; } -int pa_oss_set_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume) { +static int pa_oss_set_volume(int fd, int mixer, const pa_sample_spec *ss, const pa_cvolume *volume) { char cv[PA_CVOLUME_SNPRINT_MAX]; unsigned vol; @@ -196,13 +196,29 @@ int pa_oss_set_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume if (ss->channels >= 2) vol |= ((volume->values[1]*100)/PA_VOLUME_NORM) << 8; - if (ioctl(fd, SOUND_MIXER_WRITE_PCM, &vol) < 0) + if (ioctl(fd, mixer, &vol) < 0) return -1; pa_log_debug(__FILE__": Wrote mixer settings: %s", pa_cvolume_snprint(cv, sizeof(cv), volume)); return 0; } +int pa_oss_get_pcm_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume) { + return pa_oss_get_volume(fd, SOUND_MIXER_READ_PCM, ss, volume); +} + +int pa_oss_set_pcm_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume) { + return pa_oss_set_volume(fd, SOUND_MIXER_WRITE_PCM, ss, volume); +} + +int pa_oss_get_imix_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume) { + return pa_oss_get_volume(fd, SOUND_MIXER_READ_IMIX, ss, volume); +} + +int pa_oss_set_imix_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume) { + return pa_oss_set_volume(fd, SOUND_MIXER_WRITE_IMIX, ss, volume); +} + int pa_oss_get_hw_description(const char *dev, char *name, size_t l) { FILE *f; const char *e = NULL; diff --git a/src/modules/oss-util.h b/src/modules/oss-util.h index 3033c76f..dd494d0c 100644 --- a/src/modules/oss-util.h +++ b/src/modules/oss-util.h @@ -30,8 +30,11 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss); int pa_oss_set_fragments(int fd, int frags, int frag_size); -int pa_oss_get_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume); -int pa_oss_set_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume); +int pa_oss_get_pcm_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume); +int pa_oss_set_pcm_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume); + +int pa_oss_get_imix_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume); +int pa_oss_set_imix_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume); int pa_oss_get_hw_description(const char *dev, char *name, size_t l); -- cgit From 12e35c546c97e3b36d8c0656c571b6b3f2c7d46a Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 23 Feb 2006 09:07:49 +0000 Subject: Make sure hardware volume gets a correct initial value. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@579 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-solaris.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 1de21aed..76f50935 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -482,6 +482,10 @@ int pa__init(pa_core *c, pa_module*m) { pa_modargs_free(ma); + /* Read mixer settings */ + if (u->sink) + sink_get_hw_volume(u->sink); + return 0; fail: -- cgit From f8aca21379e6caf09ebcd1129ee90195c7e24714 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 23 Feb 2006 09:08:06 +0000 Subject: Wrong function name. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@580 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-solaris.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 76f50935..eb909e4f 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -484,7 +484,7 @@ int pa__init(pa_core *c, pa_module*m) { /* Read mixer settings */ if (u->sink) - sink_get_hw_volume(u->sink); + sink_get_hw_volume_cb(u->sink); return 0; -- cgit From 7050dbfdae212c56e23bbb42c9300e4c72726568 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 23 Feb 2006 09:28:39 +0000 Subject: Update hardware volume to a correct initial value. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@581 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-waveout.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index 02f865c5..45ed10b9 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -554,6 +554,10 @@ int pa__init(pa_core *c, pa_module*m) { pa_modargs_free(ma); + /* Read mixer settings */ + if (u->sink) + sink_get_hw_volume_cb(u->sink); + return 0; fail: -- cgit From adad7dc672361142fef33d73264e6c053a2a29ce Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 23 Feb 2006 09:30:31 +0000 Subject: Add inet_pton emulation for platforms that lack it. Only support IPv4 at this point. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@582 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- src/Makefile.am | 1 + src/polypcore/inet_pton.c | 62 +++++++++++++++++++++++++++++++++++++++++++ src/polypcore/inet_pton.h | 12 +++++++++ src/polypcore/socket-server.c | 4 +++ 5 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 src/polypcore/inet_pton.c create mode 100644 src/polypcore/inet_pton.h diff --git a/configure.ac b/configure.ac index 76b96425..25a89edc 100644 --- a/configure.ac +++ b/configure.ac @@ -206,7 +206,7 @@ AC_FUNC_FORK AC_FUNC_GETGROUPS AC_FUNC_SELECT_ARGTYPES AC_CHECK_FUNCS([getaddrinfo getgrgid_r getpwuid_r gettimeofday getuid \ - inet_ntop nanosleep setpgid setsid sigaction sleep]) + inet_ntop inet_pton nanosleep setpgid setsid sigaction sleep]) AC_CHECK_FUNCS([mkfifo], [HAVE_MKFIFO=1], [HAVE_MKFIFO=0]) AM_CONDITIONAL(HAVE_MKFIFO, test "x$HAVE_MKFIFO" = "x1") diff --git a/src/Makefile.am b/src/Makefile.am index f36630e7..01ec9ef7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -601,6 +601,7 @@ libprotocol_simple_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket-server.la libsocket_server_la_SOURCES = \ polypcore/inet_ntop.c polypcore/inet_ntop.h \ + polypcore/inet_pton.c polypcore/inet_pton.h \ polypcore/socket-server.c polypcore/socket-server.h libsocket_server_la_LDFLAGS = -avoid-version libsocket_server_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la libsocket-util.la $(LIBWRAP_LIBS) $(WINSOCK_LIBS) diff --git a/src/polypcore/inet_pton.c b/src/polypcore/inet_pton.c new file mode 100644 index 00000000..17860f6d --- /dev/null +++ b/src/polypcore/inet_pton.c @@ -0,0 +1,62 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#ifndef HAVE_INET_PTON + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#include "winsock.h" + +#include "inet_pton.h" + +int inet_pton(int af, const char *src, void *dst) { + struct in_addr *in = (struct in_addr*)dst; + struct in6_addr *in6 = (struct in6_addr*)dst; + + assert(src && dst); + + switch (af) { + case AF_INET: + in->s_addr = inet_addr(src); + if (in->s_addr == INADDR_NONE) + return 0; + break; + case AF_INET6: + /* FIXME */ + default: + errno = EAFNOSUPPORT; + return -1; + } + + return 1; +} + +#endif /* INET_PTON */ diff --git a/src/polypcore/inet_pton.h b/src/polypcore/inet_pton.h new file mode 100644 index 00000000..111b4a07 --- /dev/null +++ b/src/polypcore/inet_pton.h @@ -0,0 +1,12 @@ +#ifndef fooinet_ptonhfoo +#define fooinet_ptonhfoo + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#include "winsock.h" + +int inet_pton(int af, const char *src, void *dst); + +#endif diff --git a/src/polypcore/socket-server.c b/src/polypcore/socket-server.c index f2e15085..4e89c5d3 100644 --- a/src/polypcore/socket-server.c +++ b/src/polypcore/socket-server.c @@ -56,6 +56,10 @@ #include "inet_ntop.h" #endif +#ifndef HAVE_INET_PTON +#include "inet_pton.h" +#endif + #include "winsock.h" #include -- cgit From 4e8faa6debe0495a924aadb40ff033aeb93d0e4e Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 23 Feb 2006 09:37:44 +0000 Subject: inet_pton expects in[6]_addr structures, nothing else. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@583 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/socket-server.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/polypcore/socket-server.c b/src/polypcore/socket-server.c index 4e89c5d3..d457d626 100644 --- a/src/polypcore/socket-server.c +++ b/src/polypcore/socket-server.c @@ -339,18 +339,18 @@ pa_socket_server* pa_socket_server_new_ip_any(pa_mainloop_api *m, uint16_t port, } pa_socket_server* pa_socket_server_new_ip_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) { - uint8_t ipv6[16]; - uint32_t ipv4; + struct in6_addr ipv6; + struct in_addr ipv4; assert(m); assert(name); assert(port > 0); - if (inet_pton(AF_INET6, name, ipv6) > 0) - return pa_socket_server_new_ipv6(m, ipv6, port, tcpwrap_service); + if (inet_pton(AF_INET6, name, &ipv6) > 0) + return pa_socket_server_new_ipv6(m, ipv6.s6_addr, port, tcpwrap_service); if (inet_pton(AF_INET, name, &ipv4) > 0) - return pa_socket_server_new_ipv4(m, ntohl(ipv4), port, tcpwrap_service); + return pa_socket_server_new_ipv4(m, ntohl(ipv4.s_addr), port, tcpwrap_service); pa_log_warn(__FILE__": failed to parse '%s'.", name); -- cgit From 79e800904500fd3adcb14a19d7a8ec0436f9d5bf Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 23 Feb 2006 09:44:50 +0000 Subject: Hardware source volume support. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@584 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-solaris.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index eb909e4f..a74a70c2 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -292,6 +292,40 @@ static int sink_set_hw_volume_cb(pa_sink *s) { return 0; } +static int source_get_hw_volume_cb(pa_source *s) { + struct userdata *u = s->userdata; + audio_info_t info; + int err; + + err = ioctl(u->fd, AUDIO_GETINFO, &info); + assert(err >= 0); + + pa_cvolume_set(&s->hw_volume, s->hw_volume.channels, + info.record.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN); + + return 0; +} + +static int source_set_hw_volume_cb(pa_source *s) { + struct userdata *u = s->userdata; + audio_info_t info; + + AUDIO_INITINFO(&info); + + info.record.gain = pa_cvolume_avg(&s->hw_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM; + assert(info.record.gain <= AUDIO_MAX_GAIN); + + if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { + if (errno == EINVAL) + pa_log(__FILE__": AUDIO_SETINFO: Unsupported volume."); + else + pa_log(__FILE__": AUDIO_SETINFO: %s", strerror(errno)); + return -1; + } + + return 0; +} + static int pa_solaris_auto_format(int fd, int mode, pa_sample_spec *ss) { audio_info_t info; @@ -436,6 +470,8 @@ int pa__init(pa_core *c, pa_module*m) { assert(u->source); u->source->userdata = u; u->source->get_latency = source_get_latency_cb; + u->source->get_hw_volume = source_get_hw_volume_cb; + u->source->set_hw_volume = source_set_hw_volume_cb; pa_source_set_owner(u->source, m); u->source->description = pa_sprintf_malloc("Solaris PCM on '%s'", p); } else @@ -483,6 +519,8 @@ int pa__init(pa_core *c, pa_module*m) { pa_modargs_free(ma); /* Read mixer settings */ + if (u->source) + sink_get_hw_volume_cb(u->source); if (u->sink) sink_get_hw_volume_cb(u->sink); -- cgit From 607b2796dada282fd33fd9f075a1d7f339cd96ac Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 23 Feb 2006 09:45:32 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@585 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index 18a2218d..3bd0c716 100644 --- a/doc/todo +++ b/doc/todo @@ -11,7 +11,6 @@ Fixes: - add support for auth using SCM_CREDENTIALS - use scatter/gather io for sockets - notification on hw volume change -- source volume control - mute switch support (like ALSA does it) - module-oss-* love: - deal with underflows propely -- cgit From bd4ae44e9a4b4cf3071cbbbaf9bbb4f84397cd90 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 23 Feb 2006 12:00:58 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@586 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/todo b/doc/todo index 3bd0c716..3c478e50 100644 --- a/doc/todo +++ b/doc/todo @@ -20,6 +20,7 @@ Fixes: - add hw driver name to sink/source description - deal with underflows properly - multiline configuration statements +- module-tunnel volume support (sink, source, notify) Post 0.8: - alsa mmap driver -- cgit From 04c8926739cd5d979077b81b73a0ead0458594a7 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 23 Feb 2006 12:04:31 +0000 Subject: Mute switch for sinks and sources. This is independent of the volume setting (similar to ALSA). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@587 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/introspect.c | 94 +++++++++++++++++++++++++++++++++++++++++ src/polyp/introspect.h | 14 ++++++ src/polypcore/cli-command.c | 64 ++++++++++++++++++++++++++++ src/polypcore/native-common.h | 3 ++ src/polypcore/protocol-native.c | 55 ++++++++++++++++++++++++ src/polypcore/sample-util.c | 9 ++-- src/polypcore/sample-util.h | 3 +- src/polypcore/sink.c | 62 ++++++++++++++++++++++++--- src/polypcore/sink.h | 5 +++ src/polypcore/source.c | 50 +++++++++++++++++++++- src/polypcore/source.h | 5 +++ 11 files changed, 351 insertions(+), 13 deletions(-) diff --git a/src/polyp/introspect.c b/src/polyp/introspect.c index 6a9917a7..6a28998c 100644 --- a/src/polyp/introspect.c +++ b/src/polyp/introspect.c @@ -146,6 +146,7 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || pa_tagstruct_getu32(t, &i.owner_module) < 0 || pa_tagstruct_get_cvolume(t, &i.volume) < 0 || + pa_tagstruct_get_boolean(t, &i.mute) < 0 || pa_tagstruct_getu32(t, &i.monitor_source) < 0 || pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || pa_tagstruct_get_usec(t, &i.latency) < 0 || @@ -249,6 +250,7 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || pa_tagstruct_getu32(t, &i.owner_module) < 0 || pa_tagstruct_get_cvolume(t, &i.volume) < 0 || + pa_tagstruct_get_boolean(t, &i.mute) < 0 || pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 || pa_tagstruct_get_usec(t, &i.latency) < 0 || @@ -682,6 +684,52 @@ pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name return o; } +pa_operation* pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_MUTE, &tag); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_tagstruct_put_boolean(t, mute); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + + return o; +} + +pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(name); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_MUTE, &tag); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_tagstruct_put_boolean(t, mute); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + + return o; +} + pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { pa_operation *o; pa_tagstruct *t; @@ -756,6 +804,52 @@ pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *na return o; } +pa_operation* pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_MUTE, &tag); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_tagstruct_put_boolean(t, mute); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + + return o; +} + +pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(name); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_MUTE, &tag); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_tagstruct_put_boolean(t, mute); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + + return o; +} + /** Sample Cache **/ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { diff --git a/src/polyp/introspect.h b/src/polyp/introspect.h index d7fad9c4..4ef776f8 100644 --- a/src/polyp/introspect.h +++ b/src/polyp/introspect.h @@ -58,6 +58,7 @@ typedef struct pa_sink_info { pa_channel_map channel_map; /**< Channel map \since 0.9 */ uint32_t owner_module; /**< Index of the owning module of this sink, or PA_INVALID_INDEX */ pa_cvolume volume; /**< Volume of the sink */ + int mute; /**< Mute switch of the sink \since 0.8 */ uint32_t monitor_source; /**< Index of the monitor source connected to this sink */ const char *monitor_source_name; /**< The name of the monitor source */ pa_usec_t latency; /**< Length of filled playback buffer of this sink */ @@ -85,6 +86,7 @@ typedef struct pa_source_info { pa_channel_map channel_map; /**< Channel map \since 0.9 */ uint32_t owner_module; /**< Owning module index, or PA_INVALID_INDEX */ pa_cvolume volume; /**< Volume of the source \since 0.8 */ + int mute; /**< Mute switch of the sink \since 0.8 */ uint32_t monitor_of_sink; /**< If this is a monitor source the index of the owning sink, otherwise PA_INVALID_INDEX */ const char *monitor_of_sink_name; /**< Name of the owning sink, or PA_INVALID_INDEX */ pa_usec_t latency; /**< Length of filled record buffer of this source. \since 0.5 */ @@ -211,6 +213,12 @@ pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, c /** Set the volume of a sink device specified by its name */ pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); +/** Set the mute switch of a sink device specified by its index \since 0.8 */ +pa_operation* pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata); + +/** Set the mute switch of a sink device specified by its name \since 0.8 */ +pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata); + /** Set the volume of a sink input stream */ pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); @@ -220,6 +228,12 @@ pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, /** Set the volume of a source device specified by its name \since 0.8 */ pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); +/** Set the mute switch of a source device specified by its index \since 0.8 */ +pa_operation* pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata); + +/** Set the mute switch of a source device specified by its name \since 0.8 */ +pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata); + /** Memory block statistics */ typedef struct pa_stat_info { uint32_t memblock_total; /**< Currently allocated memory blocks */ diff --git a/src/polypcore/cli-command.c b/src/polypcore/cli-command.c index cd7993a8..0251ab0a 100644 --- a/src/polypcore/cli-command.c +++ b/src/polypcore/cli-command.c @@ -78,6 +78,8 @@ static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, in static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); @@ -116,6 +118,8 @@ static const struct command commands[] = { { "set-sink-volume", pa_cli_command_sink_volume, "Set the volume of a sink (args: index|name, volume)", 3}, { "set-sink-input-volume", pa_cli_command_sink_input_volume, "Set the volume of a sink input (args: index|name, volume)", 3}, { "set-source-volume", pa_cli_command_source_volume, "Set the volume of a source (args: index|name, volume)", 3}, + { "set-sink-mute", pa_cli_command_sink_mute, "Set the mute switch of a sink (args: index|name, mute)", 3}, + { "set-source-mute", pa_cli_command_source_mute, "Set the mute switch of a source (args: index|name, mute)", 3}, { "set-default-sink", pa_cli_command_sink_default, "Set the default sink (args: index|name)", 2}, { "set-default-source", 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}, @@ -409,6 +413,64 @@ static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf * return 0; } +static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n, *m; + pa_sink *sink; + int mute; + + 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 (!(m = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n"); + return -1; + } + + if (pa_atoi(m, &mute) < 0) { + pa_strbuf_puts(buf, "Failed to parse mute switch.\n"); + return -1; + } + + if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) { + pa_strbuf_puts(buf, "No sink found by this name or index.\n"); + return -1; + } + + pa_sink_set_mute(sink, PA_MIXER_HARDWARE, mute); + return 0; +} + +static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n, *m; + pa_source *source; + int mute; + + 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 (!(m = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n"); + return -1; + } + + if (pa_atoi(m, &mute) < 0) { + pa_strbuf_puts(buf, "Failed to parse mute switch.\n"); + return -1; + } + + if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE, 1))) { + pa_strbuf_puts(buf, "No sink found by this name or index.\n"); + return -1; + } + + pa_source_set_mute(source, PA_MIXER_HARDWARE, mute); + return 0; +} + static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { const char *n; assert(c && t); @@ -711,6 +773,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G } pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, PA_MIXER_HARDWARE))); + pa_strbuf_printf(buf, "set-sink-mute %s %d\n", sink->name, pa_sink_get_mute(sink, PA_MIXER_HARDWARE)); } for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) { @@ -723,6 +786,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G } pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_avg(pa_source_get_volume(source, PA_MIXER_HARDWARE))); + pa_strbuf_printf(buf, "set-source-mute %s %d\n", source->name, pa_source_get_mute(source, PA_MIXER_HARDWARE)); } diff --git a/src/polypcore/native-common.h b/src/polypcore/native-common.h index a5ca5c96..1107da55 100644 --- a/src/polypcore/native-common.h +++ b/src/polypcore/native-common.h @@ -72,6 +72,9 @@ enum { PA_COMMAND_SET_SINK_VOLUME, PA_COMMAND_SET_SINK_INPUT_VOLUME, PA_COMMAND_SET_SOURCE_VOLUME, + + PA_COMMAND_SET_SINK_MUTE, + PA_COMMAND_SET_SOURCE_MUTE, PA_COMMAND_CORK_PLAYBACK_STREAM, PA_COMMAND_FLUSH_PLAYBACK_STREAM, diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index dce6b346..52eaed4f 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -161,6 +161,7 @@ static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t t static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_set_mute(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_flush_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_trigger_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); @@ -220,6 +221,9 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume, [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume, + [PA_COMMAND_SET_SINK_MUTE] = command_set_mute, + [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute, + [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream, [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_flush_playback_stream, [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_prebuf_playback_stream, @@ -1184,6 +1188,7 @@ static void sink_fill_tagstruct(pa_tagstruct *t, pa_sink *sink) { PA_TAG_CHANNEL_MAP, &sink->channel_map, PA_TAG_U32, sink->owner ? sink->owner->index : PA_INVALID_INDEX, PA_TAG_CVOLUME, pa_sink_get_volume(sink, PA_MIXER_HARDWARE), + PA_TAG_BOOLEAN, pa_sink_get_mute(sink, PA_MIXER_HARDWARE), PA_TAG_U32, sink->monitor_source->index, PA_TAG_STRING, sink->monitor_source->name, PA_TAG_USEC, pa_sink_get_latency(sink), @@ -1202,6 +1207,7 @@ static void source_fill_tagstruct(pa_tagstruct *t, pa_source *source) { PA_TAG_CHANNEL_MAP, &source->channel_map, PA_TAG_U32, source->owner ? source->owner->index : PA_INVALID_INDEX, PA_TAG_CVOLUME, pa_source_get_volume(source, PA_MIXER_HARDWARE), + PA_TAG_BOOLEAN, pa_source_get_mute(source, PA_MIXER_HARDWARE), PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX, PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL, PA_TAG_USEC, pa_source_get_latency(source), @@ -1530,6 +1536,55 @@ static void command_set_volume( pa_pstream_send_simple_ack(c->pstream, tag); } +static void command_set_mute( + PA_GCC_UNUSED pa_pdispatch *pd, + uint32_t command, + uint32_t tag, + pa_tagstruct *t, + void *userdata) { + + struct connection *c = userdata; + uint32_t idx; + int mute; + pa_sink *sink = NULL; + pa_source *source = NULL; + const char *name = NULL; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_get_boolean(t, &mute) || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || *name, tag, PA_ERR_INVALID); + + if (command == PA_COMMAND_SET_SINK_MUTE) { + if (idx != PA_INVALID_INDEX) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); + else + sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); + } else { + assert(command == PA_COMMAND_SET_SOURCE_MUTE); + if (idx != (uint32_t) -1) + source = pa_idxset_get_by_index(c->protocol->core->sources, idx); + else + source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); + } + + CHECK_VALIDITY(c->pstream, sink || source, tag, PA_ERR_NOENTITY); + + if (sink) + pa_sink_set_mute(sink, PA_MIXER_HARDWARE, mute); + else if (source) + pa_source_set_mute(source, PA_MIXER_HARDWARE, mute); + + pa_pstream_send_simple_ack(c->pstream, tag); +} + static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; uint32_t idx; diff --git a/src/polypcore/sample-util.c b/src/polypcore/sample-util.c index 2c3fbd79..7afb9d11 100644 --- a/src/polypcore/sample-util.c +++ b/src/polypcore/sample-util.c @@ -85,7 +85,8 @@ size_t pa_mix( void *data, size_t length, const pa_sample_spec *spec, - const pa_cvolume *volume) { + const pa_cvolume *volume, + int mute) { assert(streams && data && length && spec); @@ -100,7 +101,7 @@ size_t pa_mix( if (d >= length) return d; - if (volume->values[channel] != PA_VOLUME_MUTED) { + if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { unsigned i; for (i = 0; i < nstreams; i++) { @@ -152,7 +153,7 @@ size_t pa_mix( if (d >= length) return d; - if (volume->values[channel] != PA_VOLUME_MUTED) { + if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { unsigned i; for (i = 0; i < nstreams; i++) { @@ -204,7 +205,7 @@ size_t pa_mix( if (d >= length) return d; - if (volume->values[channel] != PA_VOLUME_MUTED) { + if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { unsigned i; for (i = 0; i < nstreams; i++) { diff --git a/src/polypcore/sample-util.h b/src/polypcore/sample-util.h index 7ea01a30..da7f56e1 100644 --- a/src/polypcore/sample-util.h +++ b/src/polypcore/sample-util.h @@ -44,7 +44,8 @@ size_t pa_mix( void *data, size_t length, const pa_sample_spec *spec, - const pa_cvolume *volume); + const pa_cvolume *volume, + int mute); void pa_volume_memchunk( pa_memchunk*c, diff --git a/src/polypcore/sink.c b/src/polypcore/sink.c index cb072c35..17294059 100644 --- a/src/polypcore/sink.c +++ b/src/polypcore/sink.c @@ -84,11 +84,15 @@ pa_sink* pa_sink_new( pa_cvolume_reset(&s->sw_volume, spec->channels); pa_cvolume_reset(&s->hw_volume, spec->channels); + s->sw_muted = 0; + s->hw_muted = 0; s->get_latency = NULL; s->notify = NULL; s->set_hw_volume = NULL; s->get_hw_volume = NULL; + s->set_hw_mute = NULL; + s->get_hw_mute = NULL; s->userdata = NULL; r = pa_idxset_put(core->sinks, s, &s->index); @@ -131,6 +135,8 @@ void pa_sink_disconnect(pa_sink* s) { s->notify = NULL; s->get_hw_volume = NULL; s->set_hw_volume = NULL; + s->set_hw_mute = NULL; + s->get_hw_mute = NULL; s->state = PA_SINK_DISCONNECTED; pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); @@ -262,9 +268,12 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); - if (!pa_cvolume_is_norm(&volume)) { + if (s->sw_muted || !pa_cvolume_is_norm(&volume)) { pa_memchunk_make_writable(result, s->core->memblock_stat, 0); - pa_volume_memchunk(result, &s->sample_spec, &volume); + if (s->sw_muted) + pa_silence_memchunk(result, &s->sample_spec); + else + pa_volume_memchunk(result, &s->sample_spec, &volume); } } else { result->memblock = pa_memblock_new(length, s->core->memblock_stat); @@ -272,7 +281,8 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { /* pa_log("mixing %i", n); */ - result->length = pa_mix(info, n, result->memblock->data, length, &s->sample_spec, &s->sw_volume); + result->length = pa_mix(info, n, result->memblock->data, length, + &s->sample_spec, &s->sw_volume, s->sw_muted); result->index = 0; } @@ -317,15 +327,18 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { target->length); pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); - - if (!pa_cvolume_is_norm(&volume)) + + if (s->sw_muted) + pa_silence_memchunk(target, &s->sample_spec); + else if (!pa_cvolume_is_norm(&volume)) pa_volume_memchunk(target, &s->sample_spec, &volume); } else target->length = pa_mix(info, n, (uint8_t*) target->memblock->data + target->index, target->length, &s->sample_spec, - &s->sw_volume); + &s->sw_volume, + s->sw_muted); inputs_drop(s, info, n, target->length); pa_source_post(s->monitor_source, target); @@ -446,3 +459,40 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_mixer_t m) { } else return &s->sw_volume; } + +void pa_sink_set_mute(pa_sink *s, pa_mixer_t m, int mute) { + int *t; + + assert(s); + assert(s->ref >= 1); + + if (m == PA_MIXER_HARDWARE && s->set_hw_mute) + t = &s->hw_muted; + else + t = &s->sw_muted; + + if (!!*t == !!mute) + return; + + *t = !!mute; + + if (t == &s->hw_muted) + if (s->set_hw_mute(s) < 0) + s->sw_muted = !!mute; + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); +} + +int pa_sink_get_mute(pa_sink *s, pa_mixer_t m) { + assert(s); + assert(s->ref >= 1); + + if (m == PA_MIXER_HARDWARE && s->set_hw_mute) { + + if (s->get_hw_mute) + s->get_hw_mute(s); + + return s->hw_muted; + } else + return s->sw_muted; +} diff --git a/src/polypcore/sink.h b/src/polypcore/sink.h index 5f1a6cc8..59d45597 100644 --- a/src/polypcore/sink.h +++ b/src/polypcore/sink.h @@ -58,11 +58,14 @@ struct pa_sink { pa_source *monitor_source; pa_cvolume hw_volume, sw_volume; + int hw_muted, sw_muted; void (*notify)(pa_sink*sink); pa_usec_t (*get_latency)(pa_sink *s); int (*set_hw_volume)(pa_sink *s); int (*get_hw_volume)(pa_sink *s); + int (*set_hw_mute)(pa_sink *s); + int (*get_hw_mute)(pa_sink *s); void *userdata; }; @@ -92,5 +95,7 @@ void pa_sink_set_owner(pa_sink *sink, pa_module *m); void pa_sink_set_volume(pa_sink *sink, pa_mixer_t m, const pa_cvolume *volume); const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_mixer_t m); +void pa_sink_set_mute(pa_sink *sink, pa_mixer_t m, int mute); +int pa_sink_get_mute(pa_sink *sink, pa_mixer_t m); #endif diff --git a/src/polypcore/source.c b/src/polypcore/source.c index e97c31d8..9e9415b6 100644 --- a/src/polypcore/source.c +++ b/src/polypcore/source.c @@ -80,11 +80,15 @@ pa_source* pa_source_new( pa_cvolume_reset(&s->sw_volume, spec->channels); pa_cvolume_reset(&s->hw_volume, spec->channels); + s->sw_muted = 0; + s->hw_muted = 0; s->get_latency = NULL; s->notify = NULL; s->set_hw_volume = NULL; s->get_hw_volume = NULL; + s->set_hw_mute = NULL; + s->get_hw_mute = NULL; s->userdata = NULL; r = pa_idxset_put(core->sources, s, &s->index); @@ -118,6 +122,8 @@ void pa_source_disconnect(pa_source *s) { s->notify = NULL; s->get_hw_volume = NULL; s->set_hw_volume = NULL; + s->set_hw_mute = NULL; + s->get_hw_mute = NULL; s->state = PA_SOURCE_DISCONNECTED; pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); @@ -182,12 +188,15 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) { pa_source_ref(s); - if (!pa_cvolume_is_norm(&s->sw_volume)) { + if (s->sw_muted || !pa_cvolume_is_norm(&s->sw_volume)) { pa_memchunk vchunk = *chunk; pa_memblock_ref(vchunk.memblock); pa_memchunk_make_writable(&vchunk, s->core->memblock_stat, 0); - pa_volume_memchunk(&vchunk, &s->sample_spec, &s->sw_volume); + if (s->sw_muted) + pa_silence_memchunk(&vchunk, &s->sample_spec); + else + pa_volume_memchunk(&vchunk, &s->sample_spec, &s->sw_volume); pa_idxset_foreach(s->outputs, do_post, &vchunk); pa_memblock_unref(vchunk.memblock); } else @@ -250,3 +259,40 @@ const pa_cvolume *pa_source_get_volume(pa_source *s, pa_mixer_t m) { } else return &s->sw_volume; } + +void pa_source_set_mute(pa_source *s, pa_mixer_t m, int mute) { + int *t; + + assert(s); + assert(s->ref >= 1); + + if (m == PA_MIXER_HARDWARE && s->set_hw_mute) + t = &s->hw_muted; + else + t = &s->sw_muted; + + if (!!*t == !!mute) + return; + + *t = !!mute; + + if (t == &s->hw_muted) + if (s->set_hw_mute(s) < 0) + s->sw_muted = !!mute; + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); +} + +int pa_source_get_mute(pa_source *s, pa_mixer_t m) { + assert(s); + assert(s->ref >= 1); + + if (m == PA_MIXER_HARDWARE && s->set_hw_mute) { + + if (s->get_hw_mute) + s->get_hw_mute(s); + + return s->hw_muted; + } else + return s->sw_muted; +} diff --git a/src/polypcore/source.h b/src/polypcore/source.h index 3c5bb6c4..63b77624 100644 --- a/src/polypcore/source.h +++ b/src/polypcore/source.h @@ -60,11 +60,14 @@ struct pa_source { pa_sink *monitor_of; pa_cvolume hw_volume, sw_volume; + int hw_muted, sw_muted; void (*notify)(pa_source*source); pa_usec_t (*get_latency)(pa_source *s); int (*set_hw_volume)(pa_source *s); int (*get_hw_volume)(pa_source *s); + int (*set_hw_mute)(pa_source *s); + int (*get_hw_mute)(pa_source *s); void *userdata; }; @@ -92,5 +95,7 @@ pa_usec_t pa_source_get_latency(pa_source *s); void pa_source_set_volume(pa_source *source, pa_mixer_t m, const pa_cvolume *volume); const pa_cvolume *pa_source_get_volume(pa_source *source, pa_mixer_t m); +void pa_source_set_mute(pa_source *source, pa_mixer_t m, int mute); +int pa_source_get_mute(pa_source *source, pa_mixer_t m); #endif -- cgit From 65736a2651c6c182fbd6c9dcf7aa948291360534 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 23 Feb 2006 12:06:00 +0000 Subject: Some new additions were mislabeled as '\since 0.9'. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@588 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/introspect.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/polyp/introspect.h b/src/polyp/introspect.h index 4ef776f8..f1f0989c 100644 --- a/src/polyp/introspect.h +++ b/src/polyp/introspect.h @@ -55,14 +55,14 @@ typedef struct pa_sink_info { uint32_t index; /**< Index of the sink */ const char *description; /**< Description of this sink */ pa_sample_spec sample_spec; /**< Sample spec of this sink */ - pa_channel_map channel_map; /**< Channel map \since 0.9 */ + pa_channel_map channel_map; /**< Channel map \since 0.8 */ uint32_t owner_module; /**< Index of the owning module of this sink, or PA_INVALID_INDEX */ pa_cvolume volume; /**< Volume of the sink */ int mute; /**< Mute switch of the sink \since 0.8 */ uint32_t monitor_source; /**< Index of the monitor source connected to this sink */ const char *monitor_source_name; /**< The name of the monitor source */ pa_usec_t latency; /**< Length of filled playback buffer of this sink */ - const char *driver; /**< Driver name. \since 0.9 */ + const char *driver; /**< Driver name. \since 0.8 */ } pa_sink_info; /** Callback prototype for pa_context_get_sink_info_by_name() and friends */ @@ -83,14 +83,14 @@ typedef struct pa_source_info { uint32_t index; /**< Index of the source */ const char *description; /**< Description of this source */ pa_sample_spec sample_spec; /**< Sample spec of this source */ - pa_channel_map channel_map; /**< Channel map \since 0.9 */ + pa_channel_map channel_map; /**< Channel map \since 0.8 */ uint32_t owner_module; /**< Owning module index, or PA_INVALID_INDEX */ pa_cvolume volume; /**< Volume of the source \since 0.8 */ int mute; /**< Mute switch of the sink \since 0.8 */ uint32_t monitor_of_sink; /**< If this is a monitor source the index of the owning sink, otherwise PA_INVALID_INDEX */ const char *monitor_of_sink_name; /**< Name of the owning sink, or PA_INVALID_INDEX */ pa_usec_t latency; /**< Length of filled record buffer of this source. \since 0.5 */ - const char *driver; /**< Driver name \since 0.9 */ + const char *driver; /**< Driver name \since 0.8 */ } pa_source_info; /** Callback prototype for pa_context_get_source_info_by_name() and friends */ @@ -146,7 +146,7 @@ typedef struct pa_client_info { uint32_t index; /**< Index of this client */ const char *name; /**< Name of this client */ uint32_t owner_module; /**< Index of the owning module, or PA_INVALID_INDEX */ - const char *driver; /**< Driver name \since 0.9 */ + const char *driver; /**< Driver name \since 0.8 */ } pa_client_info; /** Callback prototype for pa_context_get_client_info() and firends*/ @@ -171,7 +171,7 @@ typedef struct pa_sink_input_info { pa_usec_t buffer_usec; /**< Latency due to buffering in sink input, see pa_latency_info for details */ pa_usec_t sink_usec; /**< Latency of the sink device, see pa_latency_info for details */ const char *resample_method; /**< Thre resampling method used by this sink input. \since 0.7 */ - const char *driver; /**< Driver name \since 0.9 */ + const char *driver; /**< Driver name \since 0.8 */ } pa_sink_input_info; /** Callback prototype for pa_context_get_sink_input_info() and firends*/ @@ -195,7 +195,7 @@ typedef struct pa_source_output_info { pa_usec_t buffer_usec; /**< Latency due to buffering in the source output, see pa_latency_info for details. \since 0.5 */ pa_usec_t source_usec; /**< Latency of the source device, see pa_latency_info for details. \since 0.5 */ const char *resample_method; /**< Thre resampling method used by this source output. \since 0.7 */ - const char *driver; /**< Driver name \since 0.9 */ + const char *driver; /**< Driver name \since 0.8 */ } pa_source_output_info; /** Callback prototype for pa_context_get_source_output_info() and firends*/ -- cgit From c2304d6872b1a60d5a1d6a2a58493ce5272729dd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Feb 2006 00:49:21 +0000 Subject: add a few more validity checks to protocol-esound git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@589 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-esound.c | 42 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index aa46e2b9..3ef1cd04 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -260,6 +260,13 @@ static int format_native2esd(pa_sample_spec *ss) { return format; } +#define CHECK_VALIDITY(expression, string) do { \ + if (!(expression)) { \ + pa_log_warn(__FILE__ ": " string); \ + return -1; \ + } \ +} while(0); + /*** esound commands ***/ static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { @@ -310,16 +317,10 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); - if (!pa_sample_spec_valid(&ss)) { - pa_log(__FILE__": invalid sample specification"); - return -1; - } + CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification"); + sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1); + CHECK_VALIDITY(sink, "No such sink"); - if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": no such sink"); - return -1; - } - strncpy(name, (const char*) data + sizeof(int)*2, sizeof(name)); name[sizeof(name)-1] = 0; @@ -327,10 +328,9 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t assert(!c->sink_input && !c->input_memblockq); - if (!(c->sink_input = pa_sink_input_new(sink, __FILE__, name, &ss, NULL, 0, -1))) { - pa_log(__FILE__": failed to create sink input."); - return -1; - } + c->sink_input = pa_sink_input_new(sink, __FILE__, name, &ss, NULL, 0, -1); + + CHECK_VALIDITY(c->sink_input, "Failed to create sink input."); l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); c->input_memblockq = pa_memblockq_new( @@ -374,10 +374,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); - if (!pa_sample_spec_valid(&ss)) { - pa_log(__FILE__": invalid sample specification."); - return -1; - } + CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification."); if (request == ESD_PROTO_STREAM_MON) { pa_sink* sink; @@ -631,10 +628,11 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); + CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification."); + sc_length = (size_t) MAYBE_INT32_SWAP(c->swap_byte_order, (*((const int*)data + 2))); - if (sc_length >= MAX_CACHE_SAMPLE_SIZE) - return -1; + CHECK_VALIDITY(sc_length <= MAX_CACHE_SAMPLE_SIZE, "Sample too large."); strcpy(name, SCACHE_PREFIX); strncpy(name+sizeof(SCACHE_PREFIX)-1, (const char*) data+3*sizeof(int), ESD_NAME_MAX); @@ -792,7 +790,7 @@ static int do_read(struct connection *c) { return -1; } - if ((c->read_data_length+= r) >= handler->data_length) { + if ((c->read_data_length += r) >= handler->data_length) { size_t l = c->read_data_length; assert(handler->proc); @@ -1077,7 +1075,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) return; } - c = pa_xmalloc(sizeof(struct connection)); + c = pa_xnew(struct connection, 1); c->protocol = p; c->io = io; pa_iochannel_set_callback(c->io, io_callback, c); @@ -1139,7 +1137,7 @@ pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *serve int public = 0; assert(core && server && ma); - p = pa_xmalloc(sizeof(pa_protocol_esound)); + p = pa_xnew(pa_protocol_esound, 1); if (pa_modargs_get_value_boolean(ma, "public", &public) < 0) { pa_log(__FILE__": public= expects a boolean argument."); -- cgit From 903b8c093b37f1a016aa4cbcc6cb86f72ba7993d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Feb 2006 00:49:39 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@590 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index 3c478e50..dd3bc87b 100644 --- a/doc/todo +++ b/doc/todo @@ -5,7 +5,6 @@ Test: - module-tunnel Fixes: -- better validity checking in protocol-esound - proper use of memcpy in procotol-esound.c so we don't get alignment problems - latency api rework for native protocol - add support for auth using SCM_CREDENTIALS -- cgit From b967aeb44a44b7f758541d5374c0e34460378027 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Feb 2006 01:07:55 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@591 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/todo b/doc/todo index dd3bc87b..354e66bd 100644 --- a/doc/todo +++ b/doc/todo @@ -18,7 +18,6 @@ Fixes: - volume control - add hw driver name to sink/source description - deal with underflows properly -- multiline configuration statements - module-tunnel volume support (sink, source, notify) Post 0.8: @@ -30,6 +29,7 @@ Post 0.8: - add threading API - module-tunnel: improve latency calculation - port from howl to avahi +- multiline configuration statements Long term: - pass meta info for hearing impaired -- cgit From 3374df571d281caffcfa304fb27b2e49c8e509c8 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 24 Feb 2006 09:12:15 +0000 Subject: IGAIN is a better choice than IMIX for source volume. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@592 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss-mmap.c | 4 ++-- src/modules/module-oss.c | 4 ++-- src/modules/oss-util.c | 8 ++++---- src/modules/oss-util.h | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index e1e54fb5..0ed2af93 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -248,7 +248,7 @@ static int sink_set_hw_volume(pa_sink *s) { static int source_get_hw_volume(pa_source *s) { struct userdata *u = s->userdata; - if (pa_oss_get_imix_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + if (pa_oss_get_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", strerror(errno)); s->get_hw_volume = NULL; return -1; @@ -260,7 +260,7 @@ static int source_get_hw_volume(pa_source *s) { static int source_set_hw_volume(pa_source *s) { struct userdata *u = s->userdata; - if (pa_oss_set_imix_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + if (pa_oss_set_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", strerror(errno)); s->set_hw_volume = NULL; return -1; diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 3a3f6b88..52427592 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -280,7 +280,7 @@ static int sink_set_hw_volume(pa_sink *s) { static int source_get_hw_volume(pa_source *s) { struct userdata *u = s->userdata; - if (pa_oss_get_imix_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + if (pa_oss_get_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", strerror(errno)); s->get_hw_volume = NULL; return -1; @@ -292,7 +292,7 @@ static int source_get_hw_volume(pa_source *s) { static int source_set_hw_volume(pa_source *s) { struct userdata *u = s->userdata; - if (pa_oss_set_imix_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + if (pa_oss_set_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", strerror(errno)); s->set_hw_volume = NULL; return -1; diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index 30a4b998..958bd547 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -211,12 +211,12 @@ int pa_oss_set_pcm_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *vo return pa_oss_set_volume(fd, SOUND_MIXER_WRITE_PCM, ss, volume); } -int pa_oss_get_imix_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume) { - return pa_oss_get_volume(fd, SOUND_MIXER_READ_IMIX, ss, volume); +int pa_oss_get_input_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume) { + return pa_oss_get_volume(fd, SOUND_MIXER_READ_IGAIN, ss, volume); } -int pa_oss_set_imix_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume) { - return pa_oss_set_volume(fd, SOUND_MIXER_WRITE_IMIX, ss, volume); +int pa_oss_set_input_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume) { + return pa_oss_set_volume(fd, SOUND_MIXER_WRITE_IGAIN, ss, volume); } int pa_oss_get_hw_description(const char *dev, char *name, size_t l) { diff --git a/src/modules/oss-util.h b/src/modules/oss-util.h index dd494d0c..c652d2a1 100644 --- a/src/modules/oss-util.h +++ b/src/modules/oss-util.h @@ -33,8 +33,8 @@ int pa_oss_set_fragments(int fd, int frags, int frag_size); int pa_oss_get_pcm_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume); int pa_oss_set_pcm_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume); -int pa_oss_get_imix_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume); -int pa_oss_set_imix_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume); +int pa_oss_get_input_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume); +int pa_oss_set_input_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume); int pa_oss_get_hw_description(const char *dev, char *name, size_t l); -- cgit From 9366ab9dc9acd687dc41e492d07413d36ba2f3ed Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 24 Feb 2006 10:17:41 +0000 Subject: Hardware sink mute support. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@593 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-solaris.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index a74a70c2..9015cfd2 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -292,6 +292,35 @@ static int sink_set_hw_volume_cb(pa_sink *s) { return 0; } +static int sink_get_hw_mute_cb(pa_sink *s) { + struct userdata *u = s->userdata; + audio_info_t info; + int err; + + err = ioctl(u->fd, AUDIO_GETINFO, &info); + assert(err >= 0); + + s->hw_muted = !!info.output_muted; + + return 0; +} + +static int sink_set_hw_mute_cb(pa_sink *s) { + struct userdata *u = s->userdata; + audio_info_t info; + + AUDIO_INITINFO(&info); + + info.output_muted = !!s->hw_muted; + + if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { + pa_log(__FILE__": AUDIO_SETINFO: %s", strerror(errno)); + return -1; + } + + return 0; +} + static int source_get_hw_volume_cb(pa_source *s) { struct userdata *u = s->userdata; audio_info_t info; @@ -483,6 +512,8 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->get_latency = sink_get_latency_cb; u->sink->get_hw_volume = sink_get_hw_volume_cb; u->sink->set_hw_volume = sink_set_hw_volume_cb; + u->sink->get_hw_mute = sink_get_hw_mute_cb; + u->sink->set_hw_mute = sink_set_hw_mute_cb; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); u->sink->description = pa_sprintf_malloc("Solaris PCM on '%s'", p); @@ -521,8 +552,10 @@ int pa__init(pa_core *c, pa_module*m) { /* Read mixer settings */ if (u->source) sink_get_hw_volume_cb(u->source); - if (u->sink) + if (u->sink) { sink_get_hw_volume_cb(u->sink); + sink_get_hw_mute_cb(u->sink); + } return 0; -- cgit From c205ea6ebe1b373fe6b84ee189528809e9fefc90 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 24 Feb 2006 10:18:24 +0000 Subject: Make local function static. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@594 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-solaris.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 9015cfd2..55ef1cd1 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -217,7 +217,7 @@ static void io_callback(pa_iochannel *io, void*userdata) { do_read(u); } -void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata) { +static void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata) { struct userdata *u = userdata; assert(u); do_write(u); -- cgit From a1f5573313e888d39dbe4015bdd993ad9eccb92f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 24 Feb 2006 10:18:53 +0000 Subject: Call correct function. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@595 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-solaris.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 55ef1cd1..94fa6d8c 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -551,7 +551,7 @@ int pa__init(pa_core *c, pa_module*m) { /* Read mixer settings */ if (u->source) - sink_get_hw_volume_cb(u->source); + source_get_hw_volume_cb(u->source); if (u->sink) { sink_get_hw_volume_cb(u->sink); sink_get_hw_mute_cb(u->sink); -- cgit From 3f264b2c4acfaaf8dd9c6b05526708a1d7648db0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Feb 2006 15:12:42 +0000 Subject: add support for authentication using SCM_CREDENTIALS git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@596 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 4 +- src/polyp/context.c | 6 +- src/polyp/subscribe.c | 6 +- src/polypcore/iochannel.c | 130 ++++++++++++++++++++++++++++++++++++++ src/polypcore/iochannel.h | 11 ++++ src/polypcore/pdispatch.c | 21 +++++-- src/polypcore/pdispatch.h | 6 +- src/polypcore/protocol-native.c | 93 ++++++++++++++++++---------- src/polypcore/pstream-util.c | 4 +- src/polypcore/pstream-util.h | 4 +- src/polypcore/pstream.c | 134 +++++++++++++++++++++++++++++----------- src/polypcore/pstream.h | 14 +++-- 12 files changed, 342 insertions(+), 91 deletions(-) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index df9c51fb..70bded6c 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -431,11 +431,11 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { } -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const void*creds, void *userdata) { struct userdata *u = userdata; assert(p && packet && u); - if (pa_pdispatch_run(u->pdispatch, packet, u) < 0) { + if (pa_pdispatch_run(u->pdispatch, packet, creds, u) < 0) { pa_log(__FILE__": invalid packet"); die(u); } diff --git a/src/polyp/context.c b/src/polyp/context.c index 8e999225..59079cb0 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -267,7 +267,7 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED); } -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const void *creds, void *userdata) { pa_context *c = userdata; assert(p); @@ -276,7 +276,7 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *user pa_context_ref(c); - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) + if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) pa_context_fail(c, PA_ERR_PROTOCOL); pa_context_unref(c); @@ -401,7 +401,7 @@ static void setup_context(pa_context *c, pa_iochannel *io) { t = pa_tagstruct_command(c, PA_COMMAND_AUTH, &tag); pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie)); - pa_pstream_send_tagstruct(c->pstream, t); + pa_pstream_send_tagstruct_with_creds(c->pstream, t, 1); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); pa_context_set_state(c, PA_CONTEXT_AUTHORIZING); diff --git a/src/polyp/subscribe.c b/src/polyp/subscribe.c index a4eadbc6..110d4e52 100644 --- a/src/polyp/subscribe.c +++ b/src/polyp/subscribe.c @@ -36,7 +36,7 @@ void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_context *c = userdata; pa_subscription_event_type_t e; - uint32_t index; + uint32_t idx; assert(pd); assert(command == PA_COMMAND_SUBSCRIBE_EVENT); @@ -46,14 +46,14 @@ void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSE pa_context_ref(c); if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &index) < 0 || + pa_tagstruct_getu32(t, &idx) < 0 || !pa_tagstruct_eof(t)) { pa_context_fail(c, PA_ERR_PROTOCOL); goto finish; } if (c->subscribe_callback) - c->subscribe_callback(c, e, index, c->subscribe_userdata); + c->subscribe_callback(c, e, idx, c->subscribe_userdata); finish: pa_context_unref(c); diff --git a/src/polypcore/iochannel.c b/src/polypcore/iochannel.c index 89b061c2..ea0ac988 100644 --- a/src/polypcore/iochannel.c +++ b/src/polypcore/iochannel.c @@ -27,12 +27,14 @@ #include #include #include +#include #include "winsock.h" #include #include #include +#include #include "iochannel.h" @@ -242,6 +244,134 @@ ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) { return r; } +#ifdef SCM_CREDENTIALS + +int pa_iochannel_creds_supported(pa_iochannel *io) { + struct sockaddr_un sa; + socklen_t l; + + assert(io); + assert(io->ifd >= 0); + assert(io->ofd == io->ifd); + + l = sizeof(sa); + + if (getsockname(io->ifd, (struct sockaddr*) &sa, &l) < 0) + return 0; + + return sa.sun_family == AF_UNIX; +} + +int pa_iochannel_creds_enable(pa_iochannel *io) { + int t = 1; + + assert(io); + assert(io->ifd >= 0); + + if (setsockopt(io->ifd, SOL_SOCKET, SO_PASSCRED, &t, sizeof(t)) < 0) { + pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", strerror(errno)); + return -1; + } + + return 0; +} + +ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l) { + ssize_t r; + struct msghdr mh; + struct iovec iov; + uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))]; + struct ucred *ucred; + struct cmsghdr *cmsg; + + assert(io); + assert(data); + assert(l); + assert(io->ofd >= 0); + + memset(&iov, 0, sizeof(iov)); + iov.iov_base = (void*) data; + iov.iov_len = l; + + memset(cmsg_data, 0, sizeof(cmsg_data)); + cmsg = (struct cmsghdr*) cmsg_data; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_CREDENTIALS; + + ucred = (struct ucred*) CMSG_DATA(cmsg); + ucred->pid = getpid(); + ucred->uid = getuid(); + ucred->gid = getgid(); + + memset(&mh, 0, sizeof(mh)); + mh.msg_name = NULL; + mh.msg_namelen = 0; + mh.msg_iov = &iov; + mh.msg_iovlen = 1; + mh.msg_control = cmsg_data; + mh.msg_controllen = sizeof(cmsg_data); + mh.msg_flags = 0; + + if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) { + io->writable = 0; + enable_mainloop_sources(io); + } + + return r; +} + +ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struct ucred *ucred, int *creds_valid) { + ssize_t r; + struct msghdr mh; + struct iovec iov; + uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))]; + + assert(io); + assert(data); + assert(l); + assert(io->ifd >= 0); + assert(ucred); + assert(creds_valid); + + memset(&iov, 0, sizeof(iov)); + iov.iov_base = data; + iov.iov_len = l; + + memset(cmsg_data, 0, sizeof(cmsg_data)); + + memset(&mh, 0, sizeof(mh)); + mh.msg_name = NULL; + mh.msg_namelen = 0; + mh.msg_iov = &iov; + mh.msg_iovlen = 1; + mh.msg_control = cmsg_data; + mh.msg_controllen = sizeof(cmsg_data); + mh.msg_flags = 0; + + if ((r = recvmsg(io->ifd, &mh, MSG_NOSIGNAL)) >= 0) { + struct cmsghdr *cmsg; + + *creds_valid = 0; + + for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { + + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) { + assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))); + memcpy(ucred, CMSG_DATA(cmsg), sizeof(struct ucred)); + *creds_valid = 1; + break; + } + } + + io->readable = 0; + enable_mainloop_sources(io); + } + + return r; +} +#endif + void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) { assert(io); diff --git a/src/polypcore/iochannel.h b/src/polypcore/iochannel.h index 977fe2c3..617ce086 100644 --- a/src/polypcore/iochannel.h +++ b/src/polypcore/iochannel.h @@ -23,6 +23,9 @@ ***/ #include +#include +#include + #include /* A wrapper around UNIX file descriptors for attaching them to the a @@ -48,6 +51,14 @@ void pa_iochannel_free(pa_iochannel*io); ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l); ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l); +#ifdef SCM_CREDENTIALS +int pa_iochannel_creds_supported(pa_iochannel *io); +int pa_iochannel_creds_enable(pa_iochannel *io); + +ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l); +ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struct ucred *ucred, int *creds_valid); +#endif + int pa_iochannel_is_readable(pa_iochannel*io); int pa_iochannel_is_writable(pa_iochannel*io); int pa_iochannel_is_hungup(pa_iochannel*io); diff --git a/src/polypcore/pdispatch.c b/src/polypcore/pdispatch.c index 56a21bd6..a4e58f8c 100644 --- a/src/polypcore/pdispatch.c +++ b/src/polypcore/pdispatch.c @@ -109,6 +109,7 @@ struct pa_pdispatch { PA_LLIST_HEAD(struct reply_info, replies); pa_pdispatch_drain_callback drain_callback; void *drain_userdata; + const void *creds; }; static void reply_info_free(struct reply_info *r) { @@ -136,7 +137,8 @@ pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_cb_ PA_LLIST_HEAD_INIT(pa_reply_info, pd->replies); pd->drain_callback = NULL; pd->drain_userdata = NULL; - + pd->creds = NULL; + return pd; } @@ -171,7 +173,7 @@ static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command, pa_pdispatch_unref(pd); } -int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, void *userdata) { +int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const void *creds, void *userdata) { uint32_t tag, command; pa_tagstruct *ts = NULL; int ret = -1; @@ -188,18 +190,20 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, void *userdata) { if (pa_tagstruct_getu32(ts, &command) < 0 || pa_tagstruct_getu32(ts, &tag) < 0) goto finish; - + #ifdef DEBUG_OPCODES { char t[256]; char const *p; if (!(p = command_names[command])) snprintf((char*) (p = t), sizeof(t), "%u", command); - + pa_log(__FILE__": Recieved opcode <%s>", p); } #endif + pd->creds = creds; + if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) { struct reply_info *r; @@ -222,6 +226,8 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, void *userdata) { ret = 0; finish: + pd->creds = NULL; + if (ts) pa_tagstruct_free(ts); @@ -295,3 +301,10 @@ pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd) { pd->ref++; return pd; } + +const void * pa_pdispatch_creds(pa_pdispatch *pd) { + assert(pd); + assert(pd->ref >= 1); + + return pd->creds; +} diff --git a/src/polypcore/pdispatch.h b/src/polypcore/pdispatch.h index 31533d57..aa898abf 100644 --- a/src/polypcore/pdispatch.h +++ b/src/polypcore/pdispatch.h @@ -30,21 +30,23 @@ typedef struct pa_pdispatch pa_pdispatch; typedef void (*pa_pdispatch_cb_t)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +typedef void (*pa_pdispatch_drain_callback)(pa_pdispatch *pd, void *userdata); pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *m, const pa_pdispatch_cb_t*table, unsigned entries); void pa_pdispatch_unref(pa_pdispatch *pd); pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd); -int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*p, void *userdata); +int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*p, const void*creds, void *userdata); void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t callback, void *userdata); int pa_pdispatch_is_pending(pa_pdispatch *pd); -typedef void (*pa_pdispatch_drain_callback)(pa_pdispatch *pd, void *userdata); void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, pa_pdispatch_drain_callback callback, void *userdata); /* Remove all reply slots with the give userdata parameter */ void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata); +const void * pa_pdispatch_creds(pa_pdispatch *pd); + #endif diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 52eaed4f..0fb9339b 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -357,7 +358,7 @@ static struct playback_stream* playback_stream_new( pa_cvolume *volume, uint32_t syncid) { - struct playback_stream *s, *sync; + struct playback_stream *s, *ssync; pa_sink_input *sink_input; pa_memblock *silence; uint32_t idx; @@ -366,17 +367,17 @@ static struct playback_stream* playback_stream_new( assert(c && sink && ss && name && maxlength); /* Find syncid group */ - for (sync = pa_idxset_first(c->output_streams, &idx); sync; sync = pa_idxset_next(c->output_streams, &idx)) { + for (ssync = pa_idxset_first(c->output_streams, &idx); ssync; ssync = pa_idxset_next(c->output_streams, &idx)) { - if (sync->type != PLAYBACK_STREAM) + if (ssync->type != PLAYBACK_STREAM) continue; - if (sync->syncid == syncid) + if (ssync->syncid == syncid) break; } /* Synced streams must connect to the same sink */ - if (sync && sync->sink_input->sink != sink) + if (ssync && ssync->sink_input->sink != sink) return NULL; if (!(sink_input = pa_sink_input_new(sink, __FILE__, name, ss, map, 0, -1))) @@ -397,16 +398,16 @@ static struct playback_stream* playback_stream_new( s->sink_input->owner = c->protocol->module; s->sink_input->client = c->client; - if (sync) { + if (ssync) { /* Sync id found, now find head of list */ - PA_LLIST_FIND_HEAD(struct playback_stream, sync, &sync); + PA_LLIST_FIND_HEAD(struct playback_stream, ssync, &ssync); /* Prepend ourselves */ - PA_LLIST_PREPEND(struct playback_stream, sync, s); + PA_LLIST_PREPEND(struct playback_stream, ssync, s); /* Set our start index to the current read index of the other grozp member(s) */ - assert(sync->next); - start_index = pa_memblockq_get_read_index(sync->next->memblockq); + assert(ssync->next); + start_index = pa_memblockq_get_read_index(ssync->next->memblockq); } else { /* This ia a new sync group */ PA_LLIST_INIT(struct playback_stream, s); @@ -871,8 +872,29 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t } if (!c->authorized) { - if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) != 0) { - pa_log(__FILE__": Denied access to client with invalid authorization key."); + int success = 0; + +#ifdef SCM_CREDENTIALS + const struct ucred *ucred = pa_pdispatch_creds(pd); + + if (ucred) { + if (ucred->uid == getuid()) + success = 1; + + pa_log_info(__FILE__": Got credentials: pid=%lu uid=%lu gid=%lu auth=%i", + (unsigned long) ucred->pid, + (unsigned long) ucred->uid, + (unsigned long) ucred->gid, + success); + + } +#endif + + if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) == 0) + success = 1; + + if (!success) { + pa_log_warn(__FILE__": Denied access to client with invalid authorization data."); pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -1589,7 +1611,7 @@ static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ struct connection *c = userdata; uint32_t idx; int b; - struct playback_stream *s, *sync; + struct playback_stream *s, *ssync; assert(c && t); if (pa_tagstruct_getu32(t, &idx) < 0 || @@ -1609,14 +1631,14 @@ static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_memblockq_prebuf_force(s->memblockq); /* Do the same for all other members in the sync group */ - for (sync = s->prev; sync; sync = sync->prev) { - pa_sink_input_cork(sync->sink_input, b); - pa_memblockq_prebuf_force(sync->memblockq); + for (ssync = s->prev; ssync; ssync = ssync->prev) { + pa_sink_input_cork(ssync->sink_input, b); + pa_memblockq_prebuf_force(ssync->memblockq); } - for (sync = s->next; sync; sync = sync->next) { - pa_sink_input_cork(sync->sink_input, b); - pa_memblockq_prebuf_force(sync->memblockq); + for (ssync = s->next; ssync; ssync = ssync->next) { + pa_sink_input_cork(ssync->sink_input, b); + pa_memblockq_prebuf_force(ssync->memblockq); } pa_pstream_send_simple_ack(c->pstream, tag); @@ -1625,7 +1647,7 @@ static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ static void command_flush_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; uint32_t idx; - struct playback_stream *s, *sync; + struct playback_stream *s, *ssync; assert(c && t); if (pa_tagstruct_getu32(t, &idx) < 0 || @@ -1644,25 +1666,25 @@ static void command_flush_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC s->underrun = 0; /* Do the same for all other members in the sync group */ - for (sync = s->prev; sync; sync = sync->prev) { - pa_memblockq_flush(sync->memblockq); - sync->underrun = 0; + for (ssync = s->prev; ssync; ssync = ssync->prev) { + pa_memblockq_flush(ssync->memblockq); + ssync->underrun = 0; } - for (sync = s->next; sync; sync = sync->next) { - pa_memblockq_flush(sync->memblockq); - sync->underrun = 0; + for (ssync = s->next; ssync; ssync = ssync->next) { + pa_memblockq_flush(ssync->memblockq); + ssync->underrun = 0; } pa_pstream_send_simple_ack(c->pstream, tag); pa_sink_notify(s->sink_input->sink); request_bytes(s); - for (sync = s->prev; sync; sync = sync->prev) - request_bytes(sync); + for (ssync = s->prev; ssync; ssync = ssync->prev) + request_bytes(ssync); - for (sync = s->next; sync; sync = sync->next) - request_bytes(sync); + for (ssync = s->next; ssync; ssync = ssync->next) + request_bytes(ssync); } static void command_trigger_or_prebuf_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -2017,11 +2039,11 @@ static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC /*** pstream callbacks ***/ -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const void *creds, void *userdata) { struct connection *c = userdata; assert(p && packet && packet->data && c); - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { + if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) { pa_log(__FILE__": invalid packet."); connection_free(c); } @@ -2183,6 +2205,13 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo c->subscription = NULL; pa_idxset_put(p->connections, c, NULL); + + +#ifdef SCM_CREDENTIALS + if (pa_iochannel_creds_supported(io)) + pa_iochannel_creds_enable(io); + +#endif } /*** module entry points ***/ diff --git a/src/polypcore/pstream-util.c b/src/polypcore/pstream-util.c index 62986456..bd1d1a87 100644 --- a/src/polypcore/pstream-util.c +++ b/src/polypcore/pstream-util.c @@ -29,7 +29,7 @@ #include "pstream-util.h" -void pa_pstream_send_tagstruct(pa_pstream *p, pa_tagstruct *t) { +void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, int creds) { size_t length; uint8_t *data; pa_packet *packet; @@ -40,7 +40,7 @@ void pa_pstream_send_tagstruct(pa_pstream *p, pa_tagstruct *t) { assert(data && length); packet = pa_packet_new_dynamic(data, length); assert(packet); - pa_pstream_send_packet(p, packet); + pa_pstream_send_packet(p, packet, creds); pa_packet_unref(packet); } diff --git a/src/polypcore/pstream-util.h b/src/polypcore/pstream-util.h index c400c6d8..f2677a44 100644 --- a/src/polypcore/pstream-util.h +++ b/src/polypcore/pstream-util.h @@ -27,7 +27,9 @@ #include /* The tagstruct is freed!*/ -void pa_pstream_send_tagstruct(pa_pstream *p, pa_tagstruct *t); +void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, int creds); + +#define pa_pstream_send_tagstruct(p, t) pa_pstream_send_tagstruct_with_creds((p), (t), 0) void pa_pstream_send_error(pa_pstream *p, uint32_t tag, uint32_t error); void pa_pstream_send_simple_ack(pa_pstream *p, uint32_t tag); diff --git a/src/polypcore/pstream.c b/src/polypcore/pstream.c index b1e8bd06..b93dca08 100644 --- a/src/polypcore/pstream.c +++ b/src/polypcore/pstream.c @@ -65,6 +65,9 @@ struct item_info { /* packet info */ pa_packet *packet; +#ifdef SCM_CREDENTIALS + int with_creds; +#endif }; struct pa_pstream { @@ -76,8 +79,6 @@ struct pa_pstream { pa_queue *send_queue; int dead; - void (*die_callback) (pa_pstream *p, void *userdata); - void *die_callback_userdata; struct { struct item_info* current; @@ -94,16 +95,25 @@ struct pa_pstream { size_t index; } read; - void (*recieve_packet_callback) (pa_pstream *p, pa_packet *packet, void *userdata); + pa_pstream_packet_cb_t recieve_packet_callback; void *recieve_packet_callback_userdata; - void (*recieve_memblock_callback) (pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata); + pa_pstream_memblock_cb_t recieve_memblock_callback; void *recieve_memblock_callback_userdata; - void (*drain_callback)(pa_pstream *p, void *userdata); - void *drain_userdata; + pa_pstream_notify_cb_t drain_callback; + void *drain_callback_userdata; + + pa_pstream_notify_cb_t die_callback; + void *die_callback_userdata; pa_memblock_stat *memblock_stat; + +#ifdef SCM_CREDENTIALS + int send_creds_now; + struct ucred ucred; + int creds_valid; +#endif }; static int do_write(pa_pstream *p); @@ -170,8 +180,6 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_sta pa_iochannel_set_callback(io, io_callback, p); p->dead = 0; - p->die_callback = NULL; - p->die_callback_userdata = NULL; p->mainloop = m; p->defer_event = m->defer_new(m, defer_callback, p); @@ -194,13 +202,20 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_sta p->recieve_memblock_callback_userdata = NULL; p->drain_callback = NULL; - p->drain_userdata = NULL; + p->drain_callback_userdata = NULL; + + p->die_callback = NULL; + p->die_callback_userdata = NULL; p->memblock_stat = s; pa_iochannel_socket_set_rcvbuf(io, 1024*8); - pa_iochannel_socket_set_sndbuf(io, 1024*8); + pa_iochannel_socket_set_sndbuf(io, 1024*8); +#ifdef SCM_CREDENTIALS + p->send_creds_now = 0; + p->creds_valid = 0; +#endif return p; } @@ -239,7 +254,7 @@ static void pstream_free(pa_pstream *p) { pa_xfree(p); } -void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet) { +void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, int with_creds) { struct item_info *i; assert(p && packet && p->ref >= 1); @@ -251,6 +266,9 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet) { i = pa_xnew(struct item_info, 1); i->type = PA_PSTREAM_ITEM_PACKET; i->packet = pa_packet_ref(packet); +#ifdef SCM_CREDENTIALS + i->with_creds = with_creds; +#endif pa_queue_push(p->send_queue, i); p->mainloop->defer_enable(p->defer_event, 1); @@ -278,20 +296,6 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa p->mainloop->defer_enable(p->defer_event, 1); } -void pa_pstream_set_recieve_packet_callback(pa_pstream *p, void (*callback) (pa_pstream *p, pa_packet *packet, void *userdata), void *userdata) { - assert(p && callback); - - p->recieve_packet_callback = callback; - p->recieve_packet_callback_userdata = userdata; -} - -void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, void (*callback) (pa_pstream *p, uint32_t channel, int64_t delta, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata), void *userdata) { - assert(p && callback); - - p->recieve_memblock_callback = callback; - p->recieve_memblock_callback_userdata = userdata; -} - static void prepare_next_write_item(pa_pstream *p) { assert(p); @@ -310,6 +314,11 @@ static void prepare_next_write_item(pa_pstream *p) { p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = 0; p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = 0; p->write.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK] = 0; + +#ifdef SCM_CREDENTIALS + p->send_creds_now = 1; +#endif + } else { assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK && p->write.current->chunk.memblock); p->write.data = (uint8_t*) p->write.current->chunk.memblock->data + p->write.current->chunk.index; @@ -318,6 +327,10 @@ static void prepare_next_write_item(pa_pstream *p) { p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = htonl((uint32_t) (((uint64_t) p->write.current->offset) >> 32)); p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = htonl((uint32_t) ((uint64_t) p->write.current->offset)); p->write.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK] = htonl(p->write.current->seek_mode); + +#ifdef SCM_CREDENTIALS + p->send_creds_now = 1; +#endif } } @@ -343,6 +356,16 @@ static int do_write(pa_pstream *p) { l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE); } +#ifdef SCM_CREDENTIALS + if (p->send_creds_now) { + + if ((r = pa_iochannel_write_with_creds(p->io, d, l)) < 0) + return -1; + + p->send_creds_now = 0; + } else +#endif + if ((r = pa_iochannel_write(p->io, d, l)) < 0) return -1; @@ -354,7 +377,7 @@ static int do_write(pa_pstream *p) { p->write.current = NULL; if (p->drain_callback && !pa_pstream_is_pending(p)) - p->drain_callback(p, p->drain_userdata); + p->drain_callback(p, p->drain_callback_userdata); } return 0; @@ -375,8 +398,19 @@ static int do_read(pa_pstream *p) { l = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE); } +#ifdef SCM_CREDENTIALS + { + int b; + + if ((r = pa_iochannel_read_with_creds(p->io, d, l, &p->ucred, &b)) <= 0) + return -1; + + p->creds_valid = p->creds_valid || b; + } +#else if ((r = pa_iochannel_read(p->io, d, l)) <= 0) return -1; +#endif p->read.index += r; @@ -453,40 +487,66 @@ static int do_read(pa_pstream *p) { assert(p->read.packet); if (p->recieve_packet_callback) - p->recieve_packet_callback(p, p->read.packet, p->recieve_packet_callback_userdata); +#ifdef SCM_CREDENTIALS + p->recieve_packet_callback(p, p->read.packet, p->creds_valid ? &p->ucred : NULL, p->recieve_packet_callback_userdata); +#else + p->recieve_packet_callback(p, p->read.packet, NULL, p->recieve_packet_callback_userdata); +#endif pa_packet_unref(p->read.packet); p->read.packet = NULL; } p->read.index = 0; +#ifdef SCM_CREDENTIALS + p->creds_valid = 0; +#endif } } return 0; } -void pa_pstream_set_die_callback(pa_pstream *p, void (*callback)(pa_pstream *p, void *userdata), void *userdata) { - assert(p && callback); - p->die_callback = callback; +void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) { + assert(p); + assert(p->ref >= 1); + + p->die_callback = cb; p->die_callback_userdata = userdata; } -int pa_pstream_is_pending(pa_pstream *p) { + +void pa_pstream_set_drain_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) { assert(p); + assert(p->ref >= 1); - if (p->dead) - return 0; + p->drain_callback = cb; + p->drain_callback_userdata = userdata; +} - return p->write.current || !pa_queue_is_empty(p->send_queue); +void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata) { + assert(p); + assert(p->ref >= 1); + + p->recieve_packet_callback = cb; + p->recieve_packet_callback_userdata = userdata; } -void pa_pstream_set_drain_callback(pa_pstream *p, void (*cb)(pa_pstream *p, void *userdata), void *userdata) { +void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, pa_pstream_memblock_cb_t cb, void *userdata) { assert(p); assert(p->ref >= 1); - p->drain_callback = cb; - p->drain_userdata = userdata; + p->recieve_memblock_callback = cb; + p->recieve_memblock_callback_userdata = userdata; +} + +int pa_pstream_is_pending(pa_pstream *p) { + assert(p); + + if (p->dead) + return 0; + + return p->write.current || !pa_queue_is_empty(p->send_queue); } void pa_pstream_unref(pa_pstream*p) { diff --git a/src/polypcore/pstream.h b/src/polypcore/pstream.h index 741ba9b5..feb1b151 100644 --- a/src/polypcore/pstream.h +++ b/src/polypcore/pstream.h @@ -33,18 +33,22 @@ typedef struct pa_pstream pa_pstream; +typedef void (*pa_pstream_packet_cb_t)(pa_pstream *p, pa_packet *packet, const void *creds, void *userdata); +typedef void (*pa_pstream_memblock_cb_t)(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata); +typedef void (*pa_pstream_notify_cb_t)(pa_pstream *p, void *userdata); + pa_pstream* pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_stat *s); void pa_pstream_unref(pa_pstream*p); pa_pstream* pa_pstream_ref(pa_pstream*p); -void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet); +void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, int with_creds); void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk); -void pa_pstream_set_recieve_packet_callback(pa_pstream *p, void (*callback) (pa_pstream *p, pa_packet *packet, void *userdata), void *userdata); -void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, void (*callback) (pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata), void *userdata); -void pa_pstream_set_drain_callback(pa_pstream *p, void (*cb)(pa_pstream *p, void *userdata), void *userdata); +void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata); +void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, pa_pstream_memblock_cb_t cb, void *userdata); +void pa_pstream_set_drain_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata); -void pa_pstream_set_die_callback(pa_pstream *p, void (*callback)(pa_pstream *p, void *userdata), void *userdata); +void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata); int pa_pstream_is_pending(pa_pstream *p); -- cgit From 9f1b79368909a57a9de40f98dacd306e15bda3bc Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 24 Feb 2006 16:27:39 +0000 Subject: Tweak the handling of missing credential support so that we minimise non-POSIX headers in our headers. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@597 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/iochannel.c | 29 ++++++++++++++++++++++++++++- src/polypcore/iochannel.h | 6 ++---- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/polypcore/iochannel.c b/src/polypcore/iochannel.c index ea0ac988..5da7a9a9 100644 --- a/src/polypcore/iochannel.c +++ b/src/polypcore/iochannel.c @@ -29,6 +29,13 @@ #include #include +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + #include "winsock.h" #include @@ -370,7 +377,27 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struc return r; } -#endif +#else /* SCM_CREDENTIALS */ + +int pa_iochannel_creds_supported(pa_iochannel *io) { + return 0; +} + +int pa_iochannel_creds_enable(pa_iochannel *io) { + return -1; +} + +ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l) { + pa_log_error("pa_iochannel_write_with_creds() not supported."); + return -1; +} + +ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struct ucred *ucred, int *creds_valid) { + pa_log_error("pa_iochannel_read_with_creds() not supported."); + return -1; +} + +#endif /* SCM_CREDENTIALS */ void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) { assert(io); diff --git a/src/polypcore/iochannel.h b/src/polypcore/iochannel.h index 617ce086..fe7cc0ce 100644 --- a/src/polypcore/iochannel.h +++ b/src/polypcore/iochannel.h @@ -23,8 +23,6 @@ ***/ #include -#include -#include #include @@ -51,13 +49,13 @@ void pa_iochannel_free(pa_iochannel*io); ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l); ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l); -#ifdef SCM_CREDENTIALS int pa_iochannel_creds_supported(pa_iochannel *io); int pa_iochannel_creds_enable(pa_iochannel *io); +struct ucred; + ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l); ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struct ucred *ucred, int *creds_valid); -#endif int pa_iochannel_is_readable(pa_iochannel*io); int pa_iochannel_is_writable(pa_iochannel*io); -- cgit From b418809da125bdd381ea3ac838d8a2bba5d3224b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 24 Feb 2006 16:28:02 +0000 Subject: Wrong variable used for port. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@598 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/socket-client.c | 2 +- src/polypcore/winsock.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/polypcore/socket-client.c b/src/polypcore/socket-client.c index d73b22d1..1888ecc1 100644 --- a/src/polypcore/socket-client.c +++ b/src/polypcore/socket-client.c @@ -489,7 +489,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam s.sin_family = AF_INET; memcpy(&s.sin_addr, host->h_addr, sizeof(struct in_addr)); - s.sin_port = port; + s.sin_port = htons(a.port); if ((c = pa_socket_client_new_sockaddr(m, &s, sizeof(s)))) start_timeout(c); diff --git a/src/polypcore/winsock.h b/src/polypcore/winsock.h index b1e0f7d4..89e6a4ed 100644 --- a/src/polypcore/winsock.h +++ b/src/polypcore/winsock.h @@ -18,6 +18,8 @@ #ifdef HAVE_WS2TCPIP_H #include +static const struct in6_addr in6addr_any = {{ IN6ADDR_ANY_INIT }}; +static const struct in6_addr in6addr_loopback = {{ IN6ADDR_LOOPBACK_INIT }}; #endif #endif -- cgit From c3a26709cb0c9af83f4713b807b76b30a5144bb2 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 24 Feb 2006 16:28:29 +0000 Subject: This wasn't supposed to be checked in. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@599 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/winsock.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/polypcore/winsock.h b/src/polypcore/winsock.h index 89e6a4ed..b1e0f7d4 100644 --- a/src/polypcore/winsock.h +++ b/src/polypcore/winsock.h @@ -18,8 +18,6 @@ #ifdef HAVE_WS2TCPIP_H #include -static const struct in6_addr in6addr_any = {{ IN6ADDR_ANY_INIT }}; -static const struct in6_addr in6addr_loopback = {{ IN6ADDR_LOOPBACK_INIT }}; #endif #endif -- cgit From 25bcc106d02b29db0b39e18c8519e4ca51d81310 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 24 Feb 2006 16:29:05 +0000 Subject: Do an explicit cast to shut up gcc. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@600 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/socket-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polypcore/socket-client.c b/src/polypcore/socket-client.c index 1888ecc1..1ee19a59 100644 --- a/src/polypcore/socket-client.c +++ b/src/polypcore/socket-client.c @@ -491,7 +491,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam memcpy(&s.sin_addr, host->h_addr, sizeof(struct in_addr)); s.sin_port = htons(a.port); - if ((c = pa_socket_client_new_sockaddr(m, &s, sizeof(s)))) + if ((c = pa_socket_client_new_sockaddr(m, (struct sockaddr*)&s, sizeof(s)))) start_timeout(c); #endif /* HAVE_GETADDRINFO */ } -- cgit From 435897741505fbdac30002b02c55a528f6ec8a40 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Feb 2006 17:14:23 +0000 Subject: * Add new "auth-group=" parameter to protocol-native-unix * Rename "public=" argument of protocol-{esound,native} to "auth-anonymous" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@601 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/main.c | 2 +- src/modules/module-protocol-stub.c | 17 ++++++++++--- src/polypcore/protocol-esound.c | 4 +-- src/polypcore/protocol-native.c | 25 +++++++++++++++--- src/polypcore/util.c | 52 +++++++++++++++++++++++++++++++++----- src/polypcore/util.h | 5 ++-- 6 files changed, 86 insertions(+), 19 deletions(-) diff --git a/src/daemon/main.c b/src/daemon/main.c index 4b972fe2..8457916a 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -160,7 +160,7 @@ int main(int argc, char *argv[]) { #ifdef HAVE_GETUID suid_root = getuid() != 0 && geteuid() == 0; - if (suid_root && (pa_uid_in_group("realtime", &gid) <= 0 || gid >= 1000)) { + if (suid_root && (pa_own_uid_in_group("realtime", &gid) <= 0 || gid >= 1000)) { pa_log_warn(__FILE__": WARNING: called SUID root, but not in group 'realtime'."); pa_drop_root(); } diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index 749a7ace..b02b9688 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -110,14 +110,23 @@ #define TCPWRAP_SERVICE "polypaudio-native" #define IPV4_PORT PA_NATIVE_DEFAULT_PORT #define UNIX_SOCKET PA_NATIVE_DEFAULT_UNIX_SOCKET - #define MODULE_ARGUMENTS "public", "cookie", + #define MODULE_ARGUMENTS_COMMON "cookie", "auth-anonymous", #ifdef USE_TCP_SOCKETS #include "module-native-protocol-tcp-symdef.h" #else #include "module-native-protocol-unix-symdef.h" #endif + + #if defined(SCM_CREDENTIALS) && !defined(USE_TCP_SOCKETS) + #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-group", + #define AUTH_USAGE "auth-group=" + #else + #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON + #define AUTH_USAGE + #endif + PA_MODULE_DESCRIPTION("Native protocol "SOCKET_DESCRIPTION) - PA_MODULE_USAGE("public= cookie= "SOCKET_USAGE) + PA_MODULE_USAGE("auth-anonymous= cookie= "AUTH_USAGE SOCKET_USAGE) #elif defined(USE_PROTOCOL_ESOUND) #include #include @@ -126,14 +135,14 @@ #define TCPWRAP_SERVICE "esound" #define IPV4_PORT ESD_DEFAULT_PORT #define UNIX_SOCKET ESD_UNIX_SOCKET_NAME - #define MODULE_ARGUMENTS "sink", "source", "public", "cookie", + #define MODULE_ARGUMENTS "sink", "source", "auth-anonymous", "cookie", #ifdef USE_TCP_SOCKETS #include "module-esound-protocol-tcp-symdef.h" #else #include "module-esound-protocol-unix-symdef.h" #endif PA_MODULE_DESCRIPTION("ESOUND protocol "SOCKET_DESCRIPTION) - PA_MODULE_USAGE("sink= source= public= cookie= "SOCKET_USAGE) + PA_MODULE_USAGE("sink= source= auth-anonymous= cookie= "SOCKET_USAGE) #else #error "Broken build system" #endif diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index 3ef1cd04..e30ff067 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -1139,8 +1139,8 @@ pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *serve p = pa_xnew(pa_protocol_esound, 1); - if (pa_modargs_get_value_boolean(ma, "public", &public) < 0) { - pa_log(__FILE__": public= expects a boolean argument."); + if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) { + pa_log(__FILE__": auth-anonymous= expects a boolean argument."); return NULL; } diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 0fb9339b..81d91f0c 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -129,6 +129,9 @@ struct pa_protocol_native { pa_idxset *connections; uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; int auth_cookie_in_property; +#ifdef SCM_CREDENTIALS + char *auth_group; +#endif }; static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk); @@ -878,15 +881,22 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t const struct ucred *ucred = pa_pdispatch_creds(pd); if (ucred) { - if (ucred->uid == getuid()) + if (ucred->uid == getuid()) success = 1; + else if (c->protocol->auth_group) { + int r; + + if ((r = pa_uid_in_group(ucred->uid, c->protocol->auth_group)) < 0) + pa_log_warn(__FILE__": failed to check group membership."); + else if (r > 0) + success = 1; + } pa_log_info(__FILE__": Got credentials: pid=%lu uid=%lu gid=%lu auth=%i", (unsigned long) ucred->pid, (unsigned long) ucred->uid, (unsigned long) ucred->gid, success); - } #endif @@ -2247,8 +2257,8 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo int public = 0; assert(c && ma); - if (pa_modargs_get_value_boolean(ma, "public", &public) < 0) { - pa_log(__FILE__": public= expects a boolean argument."); + if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) { + pa_log(__FILE__": auth-anonymous= expects a boolean argument."); return NULL; } @@ -2258,6 +2268,10 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo p->public = public; p->server = NULL; +#ifdef SCM_CREDENTIALS + p->auth_group = pa_xstrdup(pa_modargs_get_value(ma, "auth-group", NULL)); +#endif + if (load_key(p, pa_modargs_get_value(ma, "cookie", NULL)) < 0) { pa_xfree(p); return NULL; @@ -2317,6 +2331,9 @@ void pa_protocol_native_free(pa_protocol_native *p) { if (p->auth_cookie_in_property) pa_authkey_prop_unref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); +#ifdef SCM_CREDENTIALS + pa_xfree(p->auth_group); +#endif pa_xfree(p); } diff --git a/src/polypcore/util.c b/src/polypcore/util.c index f53eef34..f810b3bf 100644 --- a/src/polypcore/util.c +++ b/src/polypcore/util.c @@ -166,7 +166,7 @@ int pa_make_secure_parent_dir(const char *fn) { int ret = -1; char *slash, *dir = pa_xstrdup(fn); - slash = pa_path_get_filename(dir); + slash = (char*) pa_path_get_filename(dir); if (slash == fn) goto finish; *(slash-1) = 0; @@ -636,13 +636,13 @@ char *pa_get_binary_name(char *s, size_t l) { /* Return a pointer to the filename inside a path (which is the last * component). */ -char *pa_path_get_filename(const char *p) { +const char *pa_path_get_filename(const char *p) { char *fn; if ((fn = strrchr(p, PATH_SEP))) return fn+1; - return (char*) p; + return (const char*) p; } /* Try to parse a boolean string value.*/ @@ -745,7 +745,6 @@ static int is_group(gid_t gid, const char *name) { goto finish; } - r = strcmp(name, result->gr_name) == 0; finish: @@ -767,7 +766,7 @@ finish: } /* Check the current user is member of the specified group */ -int pa_uid_in_group(const char *name, gid_t *gid) { +int pa_own_uid_in_group(const char *name, gid_t *gid) { GETGROUPS_T *gids, tgid; int n = sysconf(_SC_NGROUPS_MAX); int r = -1, i; @@ -803,9 +802,50 @@ finish: return r; } +int pa_uid_in_group(uid_t uid, const char *name) { + char *g_buf, *p_buf; + long g_n, p_n; + struct group grbuf, *gr; + char **i; + int r = -1; + + g_n = sysconf(_SC_GETGR_R_SIZE_MAX); + g_buf = pa_xmalloc(g_n); + + p_n = sysconf(_SC_GETPW_R_SIZE_MAX); + p_buf = pa_xmalloc(p_n); + + if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) + goto finish; + + r = 0; + for (i = gr->gr_mem; *i; i++) { + struct passwd pwbuf, *pw; + + if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw) + continue; + + if (pw->pw_uid == uid) { + r = 1; + break; + } + } + +finish: + pa_xfree(g_buf); + pa_xfree(p_buf); + + return r; +} + #else /* HAVE_GRP_H */ -int pa_uid_in_group(const char *name, gid_t *gid) { +int pa_own_uid_in_group(const char *name, gid_t *gid) { + return -1; + +} + +int pa_uid_in_group(uid_t uid, const char *name) { return -1; } diff --git a/src/polypcore/util.h b/src/polypcore/util.h index af4e14c8..424283e7 100644 --- a/src/polypcore/util.h +++ b/src/polypcore/util.h @@ -53,7 +53,7 @@ char *pa_get_fqdn(char *s, size_t l); char *pa_get_binary_name(char *s, size_t l); char *pa_get_home_dir(char *s, size_t l); -char *pa_path_get_filename(const char *p); +const char *pa_path_get_filename(const char *p); int pa_gettimeofday(struct timeval *tv); pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); @@ -75,7 +75,8 @@ char *pa_strip_nl(char *s); const char *pa_strsignal(int sig); -int pa_uid_in_group(const char *name, gid_t *gid); +int pa_own_uid_in_group(const char *name, gid_t *gid); +int pa_uid_in_group(uid_t uid, const char *name); int pa_lock_fd(int fd, int b); -- cgit From 0d8da54f158d4bd10212d38e4a207e14f46946cd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Feb 2006 17:15:02 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@602 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index 354e66bd..e683cf8c 100644 --- a/doc/todo +++ b/doc/todo @@ -7,7 +7,6 @@ Test: Fixes: - proper use of memcpy in procotol-esound.c so we don't get alignment problems - latency api rework for native protocol -- add support for auth using SCM_CREDENTIALS - use scatter/gather io for sockets - notification on hw volume change - mute switch support (like ALSA does it) -- cgit From c5ec39d87f01716f0d4bb0c577c8d4e6d19ac665 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Feb 2006 17:27:55 +0000 Subject: move scatter/gather todo item to post-0.8, since it's impact on perfomance might not even be worth the effort. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@603 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/todo b/doc/todo index e683cf8c..598dfddd 100644 --- a/doc/todo +++ b/doc/todo @@ -7,7 +7,6 @@ Test: Fixes: - proper use of memcpy in procotol-esound.c so we don't get alignment problems - latency api rework for native protocol -- use scatter/gather io for sockets - notification on hw volume change - mute switch support (like ALSA does it) - module-oss-* love: @@ -29,6 +28,7 @@ Post 0.8: - module-tunnel: improve latency calculation - port from howl to avahi - multiline configuration statements +- use scatter/gather io for sockets Long term: - pass meta info for hearing impaired -- cgit From b125e1c9d579d47865fb0e4015b8e1f2d15b152b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 26 Feb 2006 17:57:58 +0000 Subject: Hardware volume support in ALSA modules. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@604 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 39 +++++++++++ src/modules/alsa-util.h | 3 + src/modules/module-alsa-sink.c | 140 +++++++++++++++++++++++++++++++++++++++ src/modules/module-alsa-source.c | 140 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 322 insertions(+) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 1b254f51..4e1db545 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -128,3 +128,42 @@ void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_events, unsigned n_i m->io_free(*ios); pa_xfree(io_events); } + +int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { + int err; + + assert(mixer && dev); + + if ((err = snd_mixer_attach(mixer, dev)) < 0) { + pa_log_warn(__FILE__": Unable to attach to mixer %s: %s", dev, snd_strerror(err)); + return -1; + } + + if ((err = snd_mixer_selem_register(mixer, NULL, NULL)) < 0) { + pa_log_warn(__FILE__": Unable to register mixer: %s", snd_strerror(err)); + return -1; + } + + if ((err = snd_mixer_load(mixer)) < 0) { + pa_log_warn(__FILE__": Unable to load mixer: %s", snd_strerror(err)); + return -1; + } + + return 0; +} + +snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name) { + snd_mixer_elem_t *elem; + snd_mixer_selem_id_t *sid; + snd_mixer_selem_id_alloca(&sid); + + assert(mixer && name); + + snd_mixer_selem_id_set_name(sid, name); + + elem = snd_mixer_find_selem(mixer, sid); + if (!elem) + pa_log_warn(__FILE__": Cannot find mixer control %s", snd_mixer_selem_id_get_name(sid)); + + return elem; +} diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h index 5d6d6634..489704c7 100644 --- a/src/modules/alsa-util.h +++ b/src/modules/alsa-util.h @@ -32,4 +32,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint3 int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api *m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata); void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_sources, unsigned n_io_sources); +int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev); +snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name); + #endif diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index e37367c8..68a03615 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -54,9 +54,12 @@ PA_MODULE_USAGE("sink_name= device= format=userdata; + long vol; + int err; + + assert(u && u->mixer_elem); + + if (snd_mixer_selem_has_playback_volume_joined(u->mixer_elem)) { + err = snd_mixer_selem_get_playback_volume(u->mixer_elem, 0, &vol); + if (err < 0) + goto fail; + pa_cvolume_set(&s->hw_volume, s->hw_volume.channels, + (vol - u->hw_volume_min) * PA_VOLUME_NORM / (u->hw_volume_max - u->hw_volume_min)); + } else { + int i; + + for (i = 0;i < s->hw_volume.channels;i++) { + err = snd_mixer_selem_get_playback_volume(u->mixer_elem, i, &vol); + if (err < 0) + goto fail; + s->hw_volume.values[i] = + (vol - u->hw_volume_min) * PA_VOLUME_NORM / (u->hw_volume_max - u->hw_volume_min); + } + } + + return 0; + +fail: + pa_log_error(__FILE__": Unable to read volume: %s", snd_strerror(err)); + s->get_hw_volume = NULL; + s->set_hw_volume = NULL; + return -1; +} + +static int sink_set_hw_volume_cb(pa_sink *s) { + struct userdata *u = s->userdata; + int err; + pa_volume_t vol; + + assert(u && u->mixer_elem); + + if (snd_mixer_selem_has_playback_volume_joined(u->mixer_elem)) { + vol = pa_cvolume_avg(&s->hw_volume) * (u->hw_volume_max - u->hw_volume_min) / + PA_VOLUME_NORM + u->hw_volume_min; + err = snd_mixer_selem_set_playback_volume_all(u->mixer_elem, vol); + if (err < 0) + goto fail; + } else { + int i; + + for (i = 0;i < s->hw_volume.channels;i++) { + vol = s->hw_volume.values[i] * (u->hw_volume_max - u->hw_volume_min) / + PA_VOLUME_NORM + u->hw_volume_min; + err = snd_mixer_selem_set_playback_volume(u->mixer_elem, i, vol); + if (err < 0) + goto fail; + } + } + + return 0; + +fail: + pa_log_error(__FILE__": Unable to set volume: %s", snd_strerror(err)); + s->get_hw_volume = NULL; + s->set_hw_volume = NULL; + return -1; +} + +static int sink_get_hw_mute_cb(pa_sink *s) { + struct userdata *u = s->userdata; + int err, sw; + + assert(u && u->mixer_elem); + + err = snd_mixer_selem_get_playback_switch(u->mixer_elem, 0, &sw); + if (err) { + pa_log_error(__FILE__": Unable to get switch: %s", snd_strerror(err)); + s->get_hw_mute = NULL; + s->set_hw_mute = NULL; + return -1; + } + + s->hw_muted = !sw; + + return 0; +} + +static int sink_set_hw_mute_cb(pa_sink *s) { + struct userdata *u = s->userdata; + int err; + + assert(u && u->mixer_elem); + + err = snd_mixer_selem_set_playback_switch_all(u->mixer_elem, !s->hw_muted); + if (err) { + pa_log_error(__FILE__": Unable to set switch: %s", snd_strerror(err)); + s->get_hw_mute = NULL; + s->set_hw_mute = NULL; + return -1; + } + + return 0; +} + int pa__init(pa_core *c, pa_module*m) { pa_modargs *ma = NULL; int ret = -1; @@ -220,10 +327,34 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } + if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) { + pa_log(__FILE__": Error opening mixer: %s", snd_strerror(err)); + goto fail; + } + + if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) || + !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "PCM"))) { + snd_mixer_close(u->mixer_handle); + u->mixer_handle = NULL; + } + u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; + if (u->mixer_handle) { + assert(u->mixer_elem); + if (snd_mixer_selem_has_playback_volume(u->mixer_elem)) { + u->sink->get_hw_volume = sink_get_hw_volume_cb; + u->sink->set_hw_volume = sink_set_hw_volume_cb; + snd_mixer_selem_get_playback_volume_range( + u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max); + } + if (snd_mixer_selem_has_playback_switch(u->mixer_elem)) { + u->sink->get_hw_mute = sink_get_hw_mute_cb; + u->sink->set_hw_mute = sink_set_hw_mute_cb; + } + } u->sink->userdata = u; pa_sink_set_owner(u->sink, m); u->sink->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); @@ -251,6 +382,12 @@ int pa__init(pa_core *c, pa_module*m) { finish: if (ma) pa_modargs_free(ma); + + /* Get initial mixer settings */ + if (u->sink->get_hw_volume) + u->sink->get_hw_volume(u->sink); + if (u->sink->get_hw_mute) + u->sink->get_hw_mute(u->sink); return ret; @@ -277,6 +414,9 @@ void pa__done(pa_core *c, pa_module*m) { if (u->io_events) pa_free_io_events(c->mainloop, u->io_events, u->n_io_events); + if (u->mixer_handle) + snd_mixer_close(u->mixer_handle); + if (u->pcm_handle) { snd_pcm_drop(u->pcm_handle); snd_pcm_close(u->pcm_handle); diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index bf031350..e2dbc8bf 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -54,9 +54,12 @@ PA_MODULE_USAGE("source_name= device= format=< struct userdata { snd_pcm_t *pcm_handle; + snd_mixer_t *mixer_handle; + snd_mixer_elem_t *mixer_elem; pa_source *source; pa_io_event **io_events; unsigned n_io_events; + long hw_volume_max, hw_volume_min; size_t frame_size, fragment_size; pa_memchunk memchunk; @@ -165,6 +168,110 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { return pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec); } +static int source_get_hw_volume_cb(pa_source *s) { + struct userdata *u = s->userdata; + long vol; + int err; + + assert(u && u->mixer_elem); + + if (snd_mixer_selem_has_capture_volume_joined(u->mixer_elem)) { + err = snd_mixer_selem_get_capture_volume(u->mixer_elem, 0, &vol); + if (err < 0) + goto fail; + pa_cvolume_set(&s->hw_volume, s->hw_volume.channels, + (vol - u->hw_volume_min) * PA_VOLUME_NORM / (u->hw_volume_max - u->hw_volume_min)); + } else { + int i; + + for (i = 0;i < s->hw_volume.channels;i++) { + err = snd_mixer_selem_get_capture_volume(u->mixer_elem, i, &vol); + if (err < 0) + goto fail; + s->hw_volume.values[i] = + (vol - u->hw_volume_min) * PA_VOLUME_NORM / (u->hw_volume_max - u->hw_volume_min); + } + } + + return 0; + +fail: + pa_log_error(__FILE__": Unable to read volume: %s", snd_strerror(err)); + s->get_hw_volume = NULL; + s->set_hw_volume = NULL; + return -1; +} + +static int source_set_hw_volume_cb(pa_source *s) { + struct userdata *u = s->userdata; + int err; + pa_volume_t vol; + + assert(u && u->mixer_elem); + + if (snd_mixer_selem_has_capture_volume_joined(u->mixer_elem)) { + vol = pa_cvolume_avg(&s->hw_volume) * (u->hw_volume_max - u->hw_volume_min) / + PA_VOLUME_NORM + u->hw_volume_min; + err = snd_mixer_selem_set_capture_volume_all(u->mixer_elem, vol); + if (err < 0) + goto fail; + } else { + int i; + + for (i = 0;i < s->hw_volume.channels;i++) { + vol = s->hw_volume.values[i] * (u->hw_volume_max - u->hw_volume_min) / + PA_VOLUME_NORM + u->hw_volume_min; + err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, vol); + if (err < 0) + goto fail; + } + } + + return 0; + +fail: + pa_log_error(__FILE__": Unable to set volume: %s", snd_strerror(err)); + s->get_hw_volume = NULL; + s->set_hw_volume = NULL; + return -1; +} + +static int source_get_hw_mute_cb(pa_source *s) { + struct userdata *u = s->userdata; + int err, sw; + + assert(u && u->mixer_elem); + + err = snd_mixer_selem_get_capture_switch(u->mixer_elem, 0, &sw); + if (err) { + pa_log_error(__FILE__": Unable to get switch: %s", snd_strerror(err)); + s->get_hw_mute = NULL; + s->set_hw_mute = NULL; + return -1; + } + + s->hw_muted = !sw; + + return 0; +} + +static int source_set_hw_mute_cb(pa_source *s) { + struct userdata *u = s->userdata; + int err; + + assert(u && u->mixer_elem); + + err = snd_mixer_selem_set_capture_switch_all(u->mixer_elem, !s->hw_muted); + if (err) { + pa_log_error(__FILE__": Unable to set switch: %s", snd_strerror(err)); + s->get_hw_mute = NULL; + s->set_hw_mute = NULL; + return -1; + } + + return 0; +} + int pa__init(pa_core *c, pa_module*m) { pa_modargs *ma = NULL; int ret = -1; @@ -211,11 +318,35 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } + if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) { + pa_log(__FILE__": Error opening mixer: %s", snd_strerror(err)); + goto fail; + } + + if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) || + !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture"))) { + snd_mixer_close(u->mixer_handle); + u->mixer_handle = NULL; + } + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); assert(u->source); u->source->userdata = u; u->source->get_latency = source_get_latency_cb; + if (u->mixer_handle) { + assert(u->mixer_elem); + if (snd_mixer_selem_has_capture_volume(u->mixer_elem)) { + u->source->get_hw_volume = source_get_hw_volume_cb; + u->source->set_hw_volume = source_set_hw_volume_cb; + snd_mixer_selem_get_capture_volume_range( + u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max); + } + if (snd_mixer_selem_has_capture_switch(u->mixer_elem)) { + u->source->get_hw_mute = source_get_hw_mute_cb; + u->source->set_hw_mute = source_set_hw_mute_cb; + } + } pa_source_set_owner(u->source, m); u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); @@ -239,6 +370,12 @@ int pa__init(pa_core *c, pa_module*m) { finish: if (ma) pa_modargs_free(ma); + + /* Get initial mixer settings */ + if (u->source->get_hw_volume) + u->source->get_hw_volume(u->source); + if (u->source->get_hw_mute) + u->source->get_hw_mute(u->source); return ret; @@ -264,6 +401,9 @@ void pa__done(pa_core *c, pa_module*m) { if (u->io_events) pa_free_io_events(c->mainloop, u->io_events, u->n_io_events); + + if (u->mixer_handle) + snd_mixer_close(u->mixer_handle); if (u->pcm_handle) { snd_pcm_drop(u->pcm_handle); -- cgit From c119996c73e540f0c0579c3a6aa45b9cd27c2509 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 26 Feb 2006 17:58:27 +0000 Subject: Fix correct default device. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@605 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index e2dbc8bf..a3570473 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -78,7 +78,7 @@ static const char* const valid_modargs[] = { }; #define DEFAULT_SOURCE_NAME "alsa_input" -#define DEFAULT_DEVICE "hw:0,0" +#define DEFAULT_DEVICE "default" static void update_usage(struct userdata *u) { pa_module_set_used(u->module, -- cgit From ae07d5abd5fe680367723cc6913eb759d22d8551 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 26 Feb 2006 19:09:26 +0000 Subject: Handle ALSA file descriptors more correctly. This means a bit more overhead, but following their API properly should avoid problems in the future. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@606 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 225 +++++++++++++++++++++++++++++++-------- src/modules/alsa-util.h | 10 +- src/modules/module-alsa-sink.c | 17 +-- src/modules/module-alsa-source.c | 17 +-- 4 files changed, 207 insertions(+), 62 deletions(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 4e1db545..5f4323f8 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -32,6 +32,188 @@ #include "alsa-util.h" +struct pa_alsa_fdlist { + int num_fds; + struct pollfd *fds; + /* This is a temporary buffer used to avoid lots of mallocs */ + struct pollfd *work_fds; + + snd_pcm_t *pcm; + + pa_mainloop_api *m; + pa_defer_event *defer; + pa_io_event **ios; + + int polled; + + void (*cb)(void *userdata); + void *userdata; +}; + +static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) { + struct pa_alsa_fdlist *fdl = (struct pa_alsa_fdlist*)userdata; + int err, i; + unsigned short revents; + + assert(a && fdl && fdl->pcm); + + if (fdl->polled) + return; + + fdl->polled = 1; + + memcpy(fdl->work_fds, fdl->fds, sizeof(struct pollfd) * fdl->num_fds); + + for (i = 0;i < fdl->num_fds;i++) { + if (e == fdl->ios[i]) { + if (events & PA_IO_EVENT_INPUT) + fdl->work_fds[i].revents |= POLLIN; + if (events & PA_IO_EVENT_OUTPUT) + fdl->work_fds[i].revents |= POLLOUT; + if (events & PA_IO_EVENT_ERROR) + fdl->work_fds[i].revents |= POLLERR; + if (events & PA_IO_EVENT_HANGUP) + fdl->work_fds[i].revents |= POLLHUP; + break; + } + } + + assert(i != fdl->num_fds); + + err = snd_pcm_poll_descriptors_revents(fdl->pcm, fdl->work_fds, fdl->num_fds, &revents); + if (err < 0) { + pa_log_error(__FILE__": Unable to get poll revent: %s", + snd_strerror(err)); + a->defer_enable(fdl->defer, 0); + return; + } + + if (revents) + fdl->cb(fdl->userdata); +} + +static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { + struct pa_alsa_fdlist *fdl = (struct pa_alsa_fdlist*)userdata; + int num_fds, i, err; + struct pollfd *temp; + + assert(a && fdl && fdl->pcm); + + num_fds = snd_pcm_poll_descriptors_count(fdl->pcm); + assert(num_fds > 0); + + if (num_fds != fdl->num_fds) { + if (fdl->fds) + pa_xfree(fdl->fds); + if (fdl->work_fds) + pa_xfree(fdl->work_fds); + fdl->fds = pa_xmalloc(sizeof(struct pollfd) * num_fds); + fdl->work_fds = pa_xmalloc(sizeof(struct pollfd) * num_fds); + } + + memset(fdl->work_fds, 0, sizeof(struct pollfd) * num_fds); + err = snd_pcm_poll_descriptors(fdl->pcm, fdl->work_fds, num_fds); + if (err < 0) { + pa_log_error(__FILE__": Unable to get poll descriptors: %s", + snd_strerror(err)); + a->defer_enable(fdl->defer, 0); + return; + } + + fdl->polled = 0; + + if (memcmp(fdl->fds, fdl->work_fds, sizeof(struct pollfd) * num_fds) == 0) + return; + + if (fdl->ios) { + for (i = 0;i < fdl->num_fds;i++) + a->io_free(fdl->ios[i]); + if (num_fds != fdl->num_fds) { + pa_xfree(fdl->ios); + fdl->ios = pa_xmalloc(sizeof(pa_io_event*) * num_fds); + assert(fdl->ios); + } + } else { + fdl->ios = pa_xmalloc(sizeof(pa_io_event*) * num_fds); + assert(fdl->ios); + } + + /* Swap pointers */ + temp = fdl->work_fds; + fdl->work_fds = fdl->fds; + fdl->fds = temp; + + fdl->num_fds = num_fds; + + for (i = 0;i < num_fds;i++) { + fdl->ios[i] = a->io_new(a, fdl->fds[i].fd, + ((fdl->fds[i].events & POLLIN) ? PA_IO_EVENT_INPUT : 0) | + ((fdl->fds[i].events & POLLOUT) ? PA_IO_EVENT_OUTPUT : 0), + io_cb, fdl); + assert(fdl->ios[i]); + } +} + +struct pa_alsa_fdlist *pa_alsa_fdlist_new(void) { + struct pa_alsa_fdlist *fdl; + + fdl = pa_xmalloc(sizeof(struct pa_alsa_fdlist)); + assert(fdl); + + fdl->num_fds = 0; + fdl->fds = NULL; + fdl->work_fds = NULL; + + fdl->pcm = NULL; + + fdl->m = NULL; + fdl->defer = NULL; + fdl->ios = NULL; + + fdl->polled = 0; + + return fdl; +} + +void pa_alsa_fdlist_free(struct pa_alsa_fdlist *fdl) { + assert(fdl); + + if (fdl->defer) { + assert(fdl->m); + fdl->m->defer_free(fdl->defer); + } + + if (fdl->ios) { + int i; + assert(fdl->m); + for (i = 0;i < fdl->num_fds;i++) + fdl->m->io_free(fdl->ios[0]); + pa_xfree(fdl->ios); + } + + if (fdl->fds) + pa_xfree(fdl->fds); + if (fdl->work_fds) + pa_xfree(fdl->work_fds); + + pa_xfree(fdl); +} + +int pa_alsa_fdlist_init_pcm(struct pa_alsa_fdlist *fdl, snd_pcm_t *pcm_handle, pa_mainloop_api* m, void (*cb)(void *userdata), void *userdata) { + assert(fdl && pcm_handle && m && !fdl->m && cb); + + fdl->pcm = pcm_handle; + fdl->m = m; + + fdl->defer = m->defer_new(m, defer_cb, fdl); + assert(fdl->defer); + + fdl->cb = cb; + fdl->userdata = userdata; + + return 0; +} + /* Set the hardware parameters of the given ALSA device. Returns the * selected fragment settings in *period and *period_size */ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { @@ -86,49 +268,6 @@ finish: return ret; } -/* Allocate an IO event for every ALSA poll descriptor for the - * specified ALSA device. Return a pointer to such an array in - * *io_events. Store the length of that array in *n_io_events. Use the - * specified callback function and userdata. The array has to be freed - * with pa_free_io_events(). */ -int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api* m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata) { - unsigned i; - struct pollfd *pfds, *ppfd; - pa_io_event **ios; - assert(pcm_handle && m && io_events && n_io_events && cb); - - *n_io_events = snd_pcm_poll_descriptors_count(pcm_handle); - - pfds = pa_xmalloc(sizeof(struct pollfd) * *n_io_events); - if (snd_pcm_poll_descriptors(pcm_handle, pfds, *n_io_events) < 0) { - pa_xfree(pfds); - return -1; - } - - *io_events = pa_xmalloc(sizeof(void*) * *n_io_events); - - for (i = 0, ios = *io_events, ppfd = pfds; i < *n_io_events; i++, ios++, ppfd++) { - *ios = m->io_new(m, ppfd->fd, - ((ppfd->events & POLLIN) ? PA_IO_EVENT_INPUT : 0) | - ((ppfd->events & POLLOUT) ? PA_IO_EVENT_OUTPUT : 0), cb, userdata); - assert(*ios); - } - - pa_xfree(pfds); - return 0; -} - -/* Free the memory allocated by pa_create_io_events() */ -void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_events, unsigned n_io_events) { - unsigned i; - pa_io_event **ios; - assert(m && io_events); - - for (ios = io_events, i = 0; i < n_io_events; i++, ios++) - m->io_free(*ios); - pa_xfree(io_events); -} - int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { int err; diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h index 489704c7..79f4c64b 100644 --- a/src/modules/alsa-util.h +++ b/src/modules/alsa-util.h @@ -27,10 +27,14 @@ #include #include -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size); +struct pa_alsa_fdlist; + +struct pa_alsa_fdlist *pa_alsa_fdlist_new(void); +void pa_alsa_fdlist_free(struct pa_alsa_fdlist *fdl); -int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api *m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata); -void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_sources, unsigned n_io_sources); +int pa_alsa_fdlist_init_pcm(struct pa_alsa_fdlist *fdl, snd_pcm_t *pcm_handle, pa_mainloop_api* m, void (*cb)(void *userdata), void *userdata); + +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size); int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev); snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name); diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 68a03615..ab4037b2 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -57,8 +57,7 @@ struct userdata { snd_mixer_t *mixer_handle; snd_mixer_elem_t *mixer_elem; pa_sink *sink; - pa_io_event **io_events; - unsigned n_io_events; + struct pa_alsa_fdlist *fdl; long hw_volume_max, hw_volume_min; size_t frame_size, fragment_size; @@ -144,9 +143,9 @@ static void do_write(struct userdata *u) { } } -static void io_callback(pa_mainloop_api*a, pa_io_event *e, PA_GCC_UNUSED int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { +static void fdl_callback(void *userdata) { struct userdata *u = userdata; - assert(u && a && e); + assert(u); if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) xrun_recovery(u); @@ -359,8 +358,10 @@ int pa__init(pa_core *c, pa_module*m) { pa_sink_set_owner(u->sink, m); u->sink->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); - if (pa_create_io_events(u->pcm_handle, c->mainloop, &u->io_events, &u->n_io_events, io_callback, u) < 0) { - pa_log(__FILE__": failed to obtain file descriptors"); + u->fdl = pa_alsa_fdlist_new(); + assert(u->fdl); + if (pa_alsa_fdlist_init_pcm(u->fdl, u->pcm_handle, c->mainloop, fdl_callback, u) < 0) { + pa_log(__FILE__": failed to initialise file descriptor monitoring"); goto fail; } @@ -411,8 +412,8 @@ void pa__done(pa_core *c, pa_module*m) { pa_sink_unref(u->sink); } - if (u->io_events) - pa_free_io_events(c->mainloop, u->io_events, u->n_io_events); + if (u->fdl) + pa_alsa_fdlist_free(u->fdl); if (u->mixer_handle) snd_mixer_close(u->mixer_handle); diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index a3570473..2adefa6a 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -57,8 +57,7 @@ struct userdata { snd_mixer_t *mixer_handle; snd_mixer_elem_t *mixer_elem; pa_source *source; - pa_io_event **io_events; - unsigned n_io_events; + struct pa_alsa_fdlist *fdl; long hw_volume_max, hw_volume_min; size_t frame_size, fragment_size; @@ -144,9 +143,9 @@ static void do_read(struct userdata *u) { } } -static void io_callback(pa_mainloop_api*a, pa_io_event *e, PA_GCC_UNUSED int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { +static void fdl_callback(void *userdata) { struct userdata *u = userdata; - assert(u && a && e); + assert(u); if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) xrun_recovery(u); @@ -350,8 +349,10 @@ int pa__init(pa_core *c, pa_module*m) { pa_source_set_owner(u->source, m); u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); - if (pa_create_io_events(u->pcm_handle, c->mainloop, &u->io_events, &u->n_io_events, io_callback, u) < 0) { - pa_log(__FILE__": failed to obtain file descriptors"); + u->fdl = pa_alsa_fdlist_new(); + assert(u->fdl); + if (pa_alsa_fdlist_init_pcm(u->fdl, u->pcm_handle, c->mainloop, fdl_callback, u) < 0) { + pa_log(__FILE__": failed to initialise file descriptor monitoring"); goto fail; } @@ -399,8 +400,8 @@ void pa__done(pa_core *c, pa_module*m) { pa_source_unref(u->source); } - if (u->io_events) - pa_free_io_events(c->mainloop, u->io_events, u->n_io_events); + if (u->fdl) + pa_alsa_fdlist_free(u->fdl); if (u->mixer_handle) snd_mixer_close(u->mixer_handle); -- cgit From 1e68539dc41f73722402f4678d002197289e37c5 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 26 Feb 2006 21:50:55 +0000 Subject: Get notifications about mixer changes from ALSA. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@607 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 44 +++++++++++++++++++++++++++++++++------- src/modules/alsa-util.h | 1 + src/modules/module-alsa-sink.c | 44 ++++++++++++++++++++++++++++++++++------ src/modules/module-alsa-source.c | 44 ++++++++++++++++++++++++++++++++++------ 4 files changed, 114 insertions(+), 19 deletions(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 5f4323f8..adb6f3f1 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -39,6 +39,7 @@ struct pa_alsa_fdlist { struct pollfd *work_fds; snd_pcm_t *pcm; + snd_mixer_t *mixer; pa_mainloop_api *m; pa_defer_event *defer; @@ -55,7 +56,7 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t int err, i; unsigned short revents; - assert(a && fdl && fdl->pcm); + assert(a && fdl && (fdl->pcm || fdl->mixer) && fdl->fds && fdl->work_fds); if (fdl->polled) return; @@ -80,7 +81,11 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t assert(i != fdl->num_fds); - err = snd_pcm_poll_descriptors_revents(fdl->pcm, fdl->work_fds, fdl->num_fds, &revents); + if (fdl->pcm) + err = snd_pcm_poll_descriptors_revents(fdl->pcm, fdl->work_fds, fdl->num_fds, &revents); + else + err = snd_mixer_poll_descriptors_revents(fdl->mixer, fdl->work_fds, fdl->num_fds, &revents); + if (err < 0) { pa_log_error(__FILE__": Unable to get poll revent: %s", snd_strerror(err)); @@ -88,8 +93,12 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t return; } - if (revents) - fdl->cb(fdl->userdata); + if (revents) { + if (fdl->pcm) + fdl->cb(fdl->userdata); + else + snd_mixer_handle_events(fdl->mixer); + } } static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { @@ -97,9 +106,12 @@ static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { int num_fds, i, err; struct pollfd *temp; - assert(a && fdl && fdl->pcm); + assert(a && fdl && (fdl->pcm || fdl->mixer)); - num_fds = snd_pcm_poll_descriptors_count(fdl->pcm); + if (fdl->pcm) + num_fds = snd_pcm_poll_descriptors_count(fdl->pcm); + else + num_fds = snd_mixer_poll_descriptors_count(fdl->mixer); assert(num_fds > 0); if (num_fds != fdl->num_fds) { @@ -112,7 +124,12 @@ static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { } memset(fdl->work_fds, 0, sizeof(struct pollfd) * num_fds); - err = snd_pcm_poll_descriptors(fdl->pcm, fdl->work_fds, num_fds); + + if (fdl->pcm) + err = snd_pcm_poll_descriptors(fdl->pcm, fdl->work_fds, num_fds); + else + err = snd_mixer_poll_descriptors(fdl->mixer, fdl->work_fds, num_fds); + if (err < 0) { pa_log_error(__FILE__": Unable to get poll descriptors: %s", snd_strerror(err)); @@ -165,6 +182,7 @@ struct pa_alsa_fdlist *pa_alsa_fdlist_new(void) { fdl->work_fds = NULL; fdl->pcm = NULL; + fdl->mixer = NULL; fdl->m = NULL; fdl->defer = NULL; @@ -214,6 +232,18 @@ int pa_alsa_fdlist_init_pcm(struct pa_alsa_fdlist *fdl, snd_pcm_t *pcm_handle, p return 0; } +int pa_alsa_fdlist_init_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, pa_mainloop_api* m) { + assert(fdl && mixer_handle && m && !fdl->m); + + fdl->mixer = mixer_handle; + fdl->m = m; + + fdl->defer = m->defer_new(m, defer_cb, fdl); + assert(fdl->defer); + + return 0; +} + /* Set the hardware parameters of the given ALSA device. Returns the * selected fragment settings in *period and *period_size */ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h index 79f4c64b..c908d7e0 100644 --- a/src/modules/alsa-util.h +++ b/src/modules/alsa-util.h @@ -33,6 +33,7 @@ struct pa_alsa_fdlist *pa_alsa_fdlist_new(void); void pa_alsa_fdlist_free(struct pa_alsa_fdlist *fdl); int pa_alsa_fdlist_init_pcm(struct pa_alsa_fdlist *fdl, snd_pcm_t *pcm_handle, pa_mainloop_api* m, void (*cb)(void *userdata), void *userdata); +int pa_alsa_fdlist_init_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, pa_mainloop_api* m); int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size); diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index ab4037b2..732612ef 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -57,7 +57,8 @@ struct userdata { snd_mixer_t *mixer_handle; snd_mixer_elem_t *mixer_elem; pa_sink *sink; - struct pa_alsa_fdlist *fdl; + struct pa_alsa_fdlist *pcm_fdl; + struct pa_alsa_fdlist *mixer_fdl; long hw_volume_max, hw_volume_min; size_t frame_size, fragment_size; @@ -153,6 +154,24 @@ static void fdl_callback(void *userdata) { do_write(u); } +static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { + struct userdata *u = snd_mixer_elem_get_callback_private(elem); + + assert(u && u->mixer_handle); + + if (mask & SND_CTL_EVENT_MASK_VALUE) { + if (u->sink->get_hw_volume) + u->sink->get_hw_volume(u->sink); + if (u->sink->get_hw_mute) + u->sink->get_hw_mute(u->sink); + pa_subscription_post(u->sink->core, + PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, + u->sink->index); + } + + return 0; +} + static pa_usec_t sink_get_latency_cb(pa_sink *s) { pa_usec_t r = 0; struct userdata *u = s->userdata; @@ -358,12 +377,23 @@ int pa__init(pa_core *c, pa_module*m) { pa_sink_set_owner(u->sink, m); u->sink->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); - u->fdl = pa_alsa_fdlist_new(); - assert(u->fdl); - if (pa_alsa_fdlist_init_pcm(u->fdl, u->pcm_handle, c->mainloop, fdl_callback, u) < 0) { + u->pcm_fdl = pa_alsa_fdlist_new(); + assert(u->pcm_fdl); + if (pa_alsa_fdlist_init_pcm(u->pcm_fdl, u->pcm_handle, c->mainloop, fdl_callback, u) < 0) { pa_log(__FILE__": failed to initialise file descriptor monitoring"); goto fail; } + + if (u->mixer_handle) { + u->mixer_fdl = pa_alsa_fdlist_new(); + assert(u->mixer_fdl); + if (pa_alsa_fdlist_init_mixer(u->mixer_fdl, u->mixer_handle, c->mainloop) < 0) { + pa_log(__FILE__": failed to initialise file descriptor monitoring"); + goto fail; + } + snd_mixer_elem_set_callback(u->mixer_elem, mixer_callback); + snd_mixer_elem_set_callback_private(u->mixer_elem, u); + } u->frame_size = frame_size; u->fragment_size = period_size; @@ -412,8 +442,10 @@ void pa__done(pa_core *c, pa_module*m) { pa_sink_unref(u->sink); } - if (u->fdl) - pa_alsa_fdlist_free(u->fdl); + if (u->pcm_fdl) + pa_alsa_fdlist_free(u->pcm_fdl); + if (u->mixer_fdl) + pa_alsa_fdlist_free(u->mixer_fdl); if (u->mixer_handle) snd_mixer_close(u->mixer_handle); diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 2adefa6a..1b7ae7d3 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -57,7 +57,8 @@ struct userdata { snd_mixer_t *mixer_handle; snd_mixer_elem_t *mixer_elem; pa_source *source; - struct pa_alsa_fdlist *fdl; + struct pa_alsa_fdlist *pcm_fdl; + struct pa_alsa_fdlist *mixer_fdl; long hw_volume_max, hw_volume_min; size_t frame_size, fragment_size; @@ -153,6 +154,24 @@ static void fdl_callback(void *userdata) { do_read(u); } +static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { + struct userdata *u = snd_mixer_elem_get_callback_private(elem); + + assert(u && u->mixer_handle); + + if (mask & SND_CTL_EVENT_MASK_VALUE) { + if (u->source->get_hw_volume) + u->source->get_hw_volume(u->source); + if (u->source->get_hw_mute) + u->source->get_hw_mute(u->source); + pa_subscription_post(u->source->core, + PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, + u->source->index); + } + + return 0; +} + static pa_usec_t source_get_latency_cb(pa_source *s) { struct userdata *u = s->userdata; snd_pcm_sframes_t frames; @@ -349,13 +368,24 @@ int pa__init(pa_core *c, pa_module*m) { pa_source_set_owner(u->source, m); u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); - u->fdl = pa_alsa_fdlist_new(); - assert(u->fdl); - if (pa_alsa_fdlist_init_pcm(u->fdl, u->pcm_handle, c->mainloop, fdl_callback, u) < 0) { + u->pcm_fdl = pa_alsa_fdlist_new(); + assert(u->pcm_fdl); + if (pa_alsa_fdlist_init_pcm(u->pcm_fdl, u->pcm_handle, c->mainloop, fdl_callback, u) < 0) { pa_log(__FILE__": failed to initialise file descriptor monitoring"); goto fail; } + if (u->mixer_handle) { + u->mixer_fdl = pa_alsa_fdlist_new(); + assert(u->mixer_fdl); + if (pa_alsa_fdlist_init_mixer(u->mixer_fdl, u->mixer_handle, c->mainloop) < 0) { + pa_log(__FILE__": failed to initialise file descriptor monitoring"); + goto fail; + } + snd_mixer_elem_set_callback(u->mixer_elem, mixer_callback); + snd_mixer_elem_set_callback_private(u->mixer_elem, u); + } + u->frame_size = frame_size; u->fragment_size = period_size; @@ -400,8 +430,10 @@ void pa__done(pa_core *c, pa_module*m) { pa_source_unref(u->source); } - if (u->fdl) - pa_alsa_fdlist_free(u->fdl); + if (u->pcm_fdl) + pa_alsa_fdlist_free(u->pcm_fdl); + if (u->mixer_fdl) + pa_alsa_fdlist_free(u->mixer_fdl); if (u->mixer_handle) snd_mixer_close(u->mixer_handle); -- cgit From 0c65922d3933d310f81e3f73b354e610d8e3cdf1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 26 Feb 2006 21:55:08 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@608 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index 598dfddd..a5ab5c42 100644 --- a/doc/todo +++ b/doc/todo @@ -13,7 +13,6 @@ Fixes: - deal with underflows propely - improve latency measurement for mmap - module-alsa-* love: - - volume control - add hw driver name to sink/source description - deal with underflows properly - module-tunnel volume support (sink, source, notify) -- cgit From e37f008a033a61feb0bc5a03d051a4ca3babf382 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 27 Feb 2006 08:57:41 +0000 Subject: Function prototype didn't match actual definition. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@609 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/memblockq.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polypcore/memblockq.h b/src/polypcore/memblockq.h index 210f1a07..302a5366 100644 --- a/src/polypcore/memblockq.h +++ b/src/polypcore/memblockq.h @@ -112,7 +112,7 @@ void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek); void pa_memblockq_flush(pa_memblockq *bq); /* Get Target length */ -uint32_t pa_memblockq_get_tlength(pa_memblockq *bq); +size_t pa_memblockq_get_tlength(pa_memblockq *bq); /* Return the current read index */ int64_t pa_memblockq_get_read_index(pa_memblockq *bq); -- cgit From f59bc1ff2b0dce8ec0a7aba4ac564019300fb7ab Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 27 Feb 2006 08:58:29 +0000 Subject: Fix some signed/unsigned warnings. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@610 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/memblockq.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/polypcore/memblockq.c b/src/polypcore/memblockq.c index 9b12a810..38403ec2 100644 --- a/src/polypcore/memblockq.c +++ b/src/polypcore/memblockq.c @@ -76,7 +76,8 @@ pa_memblockq* pa_memblockq_new( bq->read_index = bq->write_index = idx; bq->memblock_stat = s; - pa_log_debug(__FILE__": memblockq requested: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u", maxlength, tlength, base, prebuf, minreq); + pa_log_debug(__FILE__": memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", + (unsigned long)maxlength, (unsigned long)tlength, (unsigned long)base, (unsigned long)prebuf, (unsigned long)minreq); bq->maxlength = ((maxlength+base-1)/base)*base; assert(bq->maxlength >= base); @@ -98,7 +99,8 @@ pa_memblockq* pa_memblockq_new( if (!bq->minreq) bq->minreq = 1; - pa_log_debug(__FILE__": memblockq sanitized: maxlength=%u, tlength=%u, base=%u, prebuf=%u, minreq=%u", bq->maxlength, bq->tlength, bq->base, bq->prebuf, bq->minreq); + pa_log_debug(__FILE__": memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", + (unsigned long)bq->maxlength, (unsigned long)bq->tlength, (unsigned long)bq->base, (unsigned long)bq->prebuf, (unsigned long)bq->minreq); bq->state = bq->prebuf ? PREBUF : RUNNING; bq->silence = silence ? pa_memblock_ref(silence) : NULL; @@ -149,7 +151,7 @@ static int can_push(pa_memblockq *bq, size_t l) { assert(bq); if (bq->read_index > bq->write_index) { - int64_t d = bq->read_index - bq->write_index; + size_t d = bq->read_index - bq->write_index; if (l > d) l -= d; @@ -160,7 +162,7 @@ static int can_push(pa_memblockq *bq, size_t l) { end = bq->blocks_tail ? bq->blocks_tail->index + bq->blocks_tail->chunk.length : 0; /* Make sure that the list doesn't get too long */ - if (bq->write_index + l > end) + if (bq->write_index + (int64_t)l > end) if (bq->write_index + l - bq->read_index > bq->maxlength) return 0; @@ -191,7 +193,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { /* We currently have a buffer underflow, we need to drop some * incoming data */ - int64_t d = bq->read_index - bq->write_index; + size_t d = bq->read_index - bq->write_index; if (chunk.length > d) { chunk.index += d; @@ -210,10 +212,10 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { q = bq->blocks_tail; while (q) { - if (bq->write_index >= q->index + q->chunk.length) + if (bq->write_index >= q->index + (int64_t)q->chunk.length) /* We found the entry where we need to place the new entry immediately after */ break; - else if (bq->write_index + chunk.length <= q->index) { + else if (bq->write_index + (int64_t)chunk.length <= q->index) { /* This entry isn't touched at all, let's skip it */ q = q->prev; } else if (bq->write_index <= q->index && @@ -272,8 +274,8 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { } else { size_t d; - assert(bq->write_index + chunk.length > q->index && - bq->write_index + chunk.length < q->index + q->chunk.length && + assert(bq->write_index + (int64_t)chunk.length > q->index && + bq->write_index + (int64_t)chunk.length < q->index + (int64_t)q->chunk.length && bq->write_index < q->index); /* The job overwrites the current entry at the end, so let's drop the beginning of this entry */ @@ -289,21 +291,21 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { } if (q) { - assert(bq->write_index >= q->index + q->chunk.length); - assert(!q->next || (bq->write_index+chunk.length <= q->next->index)); + assert(bq->write_index >= q->index + (int64_t)q->chunk.length); + assert(!q->next || (bq->write_index + (int64_t)chunk.length <= q->next->index)); /* Try to merge memory blocks */ if (q->chunk.memblock == chunk.memblock && - q->chunk.index + q->chunk.length == chunk.index && - bq->write_index == q->index + q->chunk.length) { + q->chunk.index + (int64_t)q->chunk.length == chunk.index && + bq->write_index == q->index + (int64_t)q->chunk.length) { q->chunk.length += chunk.length; bq->write_index += chunk.length; return 0; } } else - assert(!bq->blocks || (bq->write_index+chunk.length <= bq->blocks->index)); + assert(!bq->blocks || (bq->write_index + (int64_t)chunk.length <= bq->blocks->index)); n = pa_xnew(struct memblock_list, 1); @@ -531,7 +533,7 @@ void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek) { bq->write_index = bq->read_index + offset; return; case PA_SEEK_RELATIVE_END: - bq->write_index = (bq->blocks_tail ? bq->blocks_tail->index + bq->blocks_tail->chunk.length : bq->read_index) + offset; + bq->write_index = (bq->blocks_tail ? bq->blocks_tail->index + (int64_t)bq->blocks_tail->chunk.length : bq->read_index) + offset; return; } -- cgit From 1bb14c3a1df2a9114a892df9bff10b6a2efc3388 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 27 Feb 2006 09:09:15 +0000 Subject: 64-bit fixes. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@611 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/idxset.c | 2 +- src/polypcore/protocol-esound.c | 2 +- src/polypcore/protocol-native.c | 4 ++-- src/tests/sync-playback.c | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/polypcore/idxset.c b/src/polypcore/idxset.c index 8d3a2370..f970ae5e 100644 --- a/src/polypcore/idxset.c +++ b/src/polypcore/idxset.c @@ -65,7 +65,7 @@ int pa_idxset_string_compare_func(const void *a, const void *b) { } unsigned pa_idxset_trivial_hash_func(const void *p) { - return (unsigned) p; + return (unsigned) (long) p; } int pa_idxset_trivial_compare_func(const void *a, const void *b) { diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index e30ff067..04fbc3e4 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -476,7 +476,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v uint8_t *response; size_t t, k, s; struct connection *conn; - size_t idx = PA_IDXSET_INVALID; + uint32_t idx = PA_IDXSET_INVALID; unsigned nsamples; assert(c && data && length == sizeof(int)); diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 81d91f0c..20ba5131 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -799,7 +799,7 @@ static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; struct record_stream *s; - size_t maxlength, fragment_size; + uint32_t maxlength, fragment_size; uint32_t source_index; const char *name, *source_name; pa_sample_spec ss; @@ -1098,7 +1098,7 @@ static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; struct upload_stream *s; - size_t length; + uint32_t length; const char *name; pa_sample_spec ss; pa_channel_map map; diff --git a/src/tests/sync-playback.c b/src/tests/sync-playback.c index 4ac65c2f..d675e01c 100644 --- a/src/tests/sync-playback.c +++ b/src/tests/sync-playback.c @@ -64,7 +64,7 @@ static const pa_buffer_attr buffer_attr = { static void nop_free_cb(void *p) {} static void underflow_cb(struct pa_stream *s, void *userdata) { - int i = (int) userdata; + int i = (int) (long) userdata; fprintf(stderr, "Stream %i finished\n", i); @@ -86,7 +86,7 @@ static void stream_state_callback(pa_stream *s, void *userdata) { case PA_STREAM_READY: { - int r, i = (int) userdata; + int r, i = (int) (long) userdata; fprintf(stderr, "Writing data to stream %i.\n", i); @@ -136,7 +136,7 @@ static void context_state_callback(pa_context *c, void *userdata) { streams[i] = pa_stream_new(c, name, &sample_spec, NULL); assert(streams[i]); - pa_stream_set_state_callback(streams[i], stream_state_callback, (void*) i); + pa_stream_set_state_callback(streams[i], stream_state_callback, (void*) (long) i); pa_stream_connect_playback(streams[i], NULL, &buffer_attr, PA_STREAM_START_CORKED, NULL, i == 0 ? NULL : streams[0]); } -- cgit From e8b3819ac87e96e6ad3442ca29eaecb1c57efcc4 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 27 Feb 2006 09:18:18 +0000 Subject: Catch volume update events. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@612 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-solaris.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 94fa6d8c..12d6719e 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -219,8 +219,20 @@ static void io_callback(pa_iochannel *io, void*userdata) { static void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata) { struct userdata *u = userdata; - assert(u); + pa_cvolume old_vol; + + assert(u && u->sink && u->sink->get_hw_volume); + do_write(u); + + memcpy(&old_vol, &u->sink->hw_volume, sizeof(pa_cvolume)); + if (u->sink->get_hw_volume(u->sink) < 0) + return; + if (memcmp(&old_vol, &u->sink->hw_volume, sizeof(pa_cvolume)) != 0) { + pa_subscription_post(u->sink->core, + PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, + u->sink->index); + } } static pa_usec_t sink_get_latency_cb(pa_sink *s) { -- cgit From 4756d186ab461322470a57b0f1e8ca5fdd4eb6fb Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 27 Feb 2006 09:20:25 +0000 Subject: We have both sink and source in this module. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@613 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-solaris.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 12d6719e..9f93f9d8 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -221,17 +221,32 @@ static void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void struct userdata *u = userdata; pa_cvolume old_vol; - assert(u && u->sink && u->sink->get_hw_volume); + assert(u); do_write(u); - memcpy(&old_vol, &u->sink->hw_volume, sizeof(pa_cvolume)); - if (u->sink->get_hw_volume(u->sink) < 0) - return; - if (memcmp(&old_vol, &u->sink->hw_volume, sizeof(pa_cvolume)) != 0) { - pa_subscription_post(u->sink->core, - PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, - u->sink->index); + if (u->sink) { + assert(u->sink->get_hw_volume); + memcpy(&old_vol, &u->sink->hw_volume, sizeof(pa_cvolume)); + if (u->sink->get_hw_volume(u->sink) < 0) + return; + if (memcmp(&old_vol, &u->sink->hw_volume, sizeof(pa_cvolume)) != 0) { + pa_subscription_post(u->sink->core, + PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, + u->sink->index); + } + } + + if (u->source) { + assert(u->source->get_hw_volume); + memcpy(&old_vol, &u->source->hw_volume, sizeof(pa_cvolume)); + if (u->source->get_hw_volume(u->source) < 0) + return; + if (memcmp(&old_vol, &u->source->hw_volume, sizeof(pa_cvolume)) != 0) { + pa_subscription_post(u->source->core, + PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, + u->source->index); + } } } -- cgit From 5b9849eaefeab3e87350e9e122502e6d4a1fa246 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 27 Feb 2006 09:21:38 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@614 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index a5ab5c42..530a980c 100644 --- a/doc/todo +++ b/doc/todo @@ -7,7 +7,6 @@ Test: Fixes: - proper use of memcpy in procotol-esound.c so we don't get alignment problems - latency api rework for native protocol -- notification on hw volume change - mute switch support (like ALSA does it) - module-oss-* love: - deal with underflows propely -- cgit From 76f56ab462e27b69ce5b1094da512de0259b5568 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 27 Feb 2006 09:22:33 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@615 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index 530a980c..df13e56f 100644 --- a/doc/todo +++ b/doc/todo @@ -7,7 +7,6 @@ Test: Fixes: - proper use of memcpy in procotol-esound.c so we don't get alignment problems - latency api rework for native protocol -- mute switch support (like ALSA does it) - module-oss-* love: - deal with underflows propely - improve latency measurement for mmap -- cgit From 8cf9b972e2bdb888b25506c312a7b44ba0af198c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 2 Mar 2006 14:22:25 +0000 Subject: protocol changes for new latency API (partial!) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@616 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/memblockq.c | 1 - src/polypcore/protocol-native.c | 10 ++++------ src/polypcore/tagstruct.c | 34 ++++++++++++++++++++++++++++++++-- src/polypcore/tagstruct.h | 3 +++ 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/polypcore/memblockq.c b/src/polypcore/memblockq.c index 38403ec2..517495eb 100644 --- a/src/polypcore/memblockq.c +++ b/src/polypcore/memblockq.c @@ -547,7 +547,6 @@ void pa_memblockq_flush(pa_memblockq *bq) { drop_block(bq, bq->blocks); assert(bq->n_blocks == 0); - bq->write_index = bq->read_index; pa_memblockq_prebuf_force(bq); } diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 20ba5131..76761b73 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -1031,13 +1031,11 @@ static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_tagstruct *reply; struct playback_stream *s; struct timeval tv, now; - uint64_t counter; uint32_t idx; assert(c && t); if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_get_timeval(t, &tv) < 0 || - pa_tagstruct_getu64(t, &counter) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1057,7 +1055,8 @@ static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_tagstruct_put_timeval(reply, &tv); pa_gettimeofday(&now); pa_tagstruct_put_timeval(reply, &now); - pa_tagstruct_putu64(reply, counter); + pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq)); + pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq)); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -1066,13 +1065,11 @@ static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN pa_tagstruct *reply; struct record_stream *s; struct timeval tv, now; - uint64_t counter; uint32_t idx; assert(c && t); if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_get_timeval(t, &tv) < 0 || - pa_tagstruct_getu64(t, &counter) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1091,7 +1088,8 @@ static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN pa_tagstruct_put_timeval(reply, &tv); pa_gettimeofday(&now); pa_tagstruct_put_timeval(reply, &now); - pa_tagstruct_putu64(reply, counter); + pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq)); + pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq)); pa_pstream_send_tagstruct(c->pstream, reply); } diff --git a/src/polypcore/tagstruct.c b/src/polypcore/tagstruct.c index 1f5f370b..3035626b 100644 --- a/src/polypcore/tagstruct.c +++ b/src/polypcore/tagstruct.c @@ -189,6 +189,18 @@ void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) { t->length += 9; } +void pa_tagstruct_puts64(pa_tagstruct*t, int64_t u) { + uint32_t tmp; + assert(t); + extend(t, 9); + t->data[t->length] = PA_TAG_S64; + tmp = htonl((uint32_t) ((uint64_t) u >> 32)); + memcpy(t->data+t->length+1, &tmp, 4); + tmp = htonl((uint32_t) ((uint64_t) u)); + memcpy(t->data+t->length+5, &tmp, 4); + t->length += 9; +} + void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) { unsigned i; @@ -399,9 +411,27 @@ int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) { return -1; memcpy(&tmp, t->data+t->rindex+1, 4); - *u = (pa_usec_t) ntohl(tmp) << 32; + *u = (uint64_t) ntohl(tmp) << 32; memcpy(&tmp, t->data+t->rindex+5, 4); - *u |= (pa_usec_t) ntohl(tmp); + *u |= (uin64_t) ntohl(tmp); + t->rindex +=9; + return 0; +} + +int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *u) { + uint32_t tmp; + assert(t && u); + + if (t->rindex+9 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_S64) + return -1; + + memcpy(&tmp, t->data+t->rindex+1, 4); + *u = (int64_t) ((uint64_t) ntohl(tmp) << 32); + memcpy(&tmp, t->data+t->rindex+5, 4); + *u |= (int64_t) ntohl(tmp); t->rindex +=9; return 0; } diff --git a/src/polypcore/tagstruct.h b/src/polypcore/tagstruct.h index 0ed75171..d5e6050b 100644 --- a/src/polypcore/tagstruct.h +++ b/src/polypcore/tagstruct.h @@ -40,6 +40,7 @@ enum { PA_TAG_U32 = 'L', PA_TAG_U8 = 'B', PA_TAG_U64 = 'R', + PA_TAG_S64 = 'r', PA_TAG_SAMPLE_SPEC = 'a', PA_TAG_ARBITRARY = 'x', PA_TAG_BOOLEAN_TRUE = '1', @@ -64,6 +65,7 @@ void pa_tagstruct_puts(pa_tagstruct*t, const char *s); void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c); void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i); void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t i); +void pa_tagstruct_puts64(pa_tagstruct*t, int64_t i); void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss); void pa_tagstruct_put_arbitrary(pa_tagstruct*t, const void *p, size_t length); void pa_tagstruct_put_boolean(pa_tagstruct*t, int b); @@ -78,6 +80,7 @@ int pa_tagstruct_gets(pa_tagstruct*t, const char **s); int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c); int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i); int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *i); +int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *i); int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss); int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length); int pa_tagstruct_get_boolean(pa_tagstruct *t, int *b); -- cgit From 7f04568444a10ae96f98787d9309cdbaed8a171b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 2 Mar 2006 14:46:31 +0000 Subject: typo fix git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@617 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/tagstruct.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polypcore/tagstruct.c b/src/polypcore/tagstruct.c index 3035626b..761f6d3d 100644 --- a/src/polypcore/tagstruct.c +++ b/src/polypcore/tagstruct.c @@ -413,7 +413,7 @@ int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) { memcpy(&tmp, t->data+t->rindex+1, 4); *u = (uint64_t) ntohl(tmp) << 32; memcpy(&tmp, t->data+t->rindex+5, 4); - *u |= (uin64_t) ntohl(tmp); + *u |= (uint64_t) ntohl(tmp); t->rindex +=9; return 0; } -- cgit From 6cc11fbfc3094cdda5502ef9374104f1d481ab71 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 2 Mar 2006 16:32:36 +0000 Subject: Handle the new latency protocol. This is just a quick fix and does not handle the new memblockq system. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@618 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 1 + src/polyp/def.h | 2 ++ src/polyp/internal.h | 3 +++ src/polyp/stream.c | 24 ++++++++++++++++++++++-- 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 01ec9ef7..a65938ef 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -346,6 +346,7 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ polypcore/conf-parser.c polypcore/conf-parser.h \ polypcore/dynarray.c polypcore/dynarray.h \ polypcore/gccmacro.h \ + polypcore/hashmap.c polypcore/hashmap.h \ polypcore/idxset.c polypcore/idxset.h \ polypcore/iochannel.c polypcore/iochannel.h \ polypcore/log.c polypcore/log.h \ diff --git a/src/polyp/def.h b/src/polyp/def.h index 0d095e9a..426a0c9b 100644 --- a/src/polyp/def.h +++ b/src/polyp/def.h @@ -195,6 +195,8 @@ typedef struct pa_latency_info { * 0.5 */ struct timeval timestamp; /**< The time when this latency info was current */ uint64_t counter; /**< The byte counter current when the latency info was requested. \since 0.6 */ + int64_t write_index; /**< Current absolute write index in the buffer. \since 0.8 */ + int64_t read_index; /**< Current absolute read index in the buffer. \since 0.8 */ } pa_latency_info; /** A structure for the spawn api. This may be used to integrate auto diff --git a/src/polyp/internal.h b/src/polyp/internal.h index 2e4d859a..1443f7a8 100644 --- a/src/polyp/internal.h +++ b/src/polyp/internal.h @@ -37,6 +37,7 @@ #include #include #include +#include #include "client-conf.h" @@ -104,6 +105,8 @@ struct pa_stream { pa_memchunk peek_memchunk; pa_memblockq *record_memblockq; + pa_hashmap *counter_hashmap; + int interpolate; int corked; diff --git a/src/polyp/stream.c b/src/polyp/stream.c index 8bdb9059..3ac026f1 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -33,10 +33,12 @@ #include #include #include +#include #include "internal.h" #define LATENCY_IPOL_INTERVAL_USEC (10000L) +#define COUNTER_HASHMAP_MAXSIZE (5) pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map) { pa_stream *s; @@ -85,6 +87,8 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->record_memblockq = NULL; + s->counter_hashmap = pa_hashmap_new(NULL, NULL); + s->counter = 0; s->previous_time = 0; s->previous_ipol_time = 0; @@ -102,6 +106,10 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * return pa_stream_ref(s); } +static void hashmap_free_func(void *p, void *userdata) { + pa_xfree(p); +} + static void stream_free(pa_stream *s) { assert(s); @@ -116,6 +124,9 @@ static void stream_free(pa_stream *s) { if (s->record_memblockq) pa_memblockq_free(s->record_memblockq); + if (s->counter_hashmap) + pa_hashmap_free(s->counter_hashmap, hashmap_free_func, NULL); + pa_xfree(s->name); pa_xfree(s); } @@ -618,6 +629,9 @@ static void stream_get_latency_info_callback(pa_pdispatch *pd, uint32_t command, assert(o->stream); assert(o->context); + i.counter = *(uint64_t*)pa_hashmap_get(o->stream->counter_hashmap, (void*)tag); + pa_xfree(pa_hashmap_remove(o->stream->counter_hashmap, (void*)tag)); + if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; @@ -629,7 +643,8 @@ static void stream_get_latency_info_callback(pa_pdispatch *pd, uint32_t command, pa_tagstruct_getu32(t, &i.queue_length) < 0 || pa_tagstruct_get_timeval(t, &local) < 0 || pa_tagstruct_get_timeval(t, &remote) < 0 || - pa_tagstruct_getu64(t, &i.counter) < 0 || + pa_tagstruct_gets64(t, &i.write_index) < 0 || + pa_tagstruct_gets64(t, &i.read_index) < 0 || !pa_tagstruct_eof(t)) { pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; @@ -679,12 +694,14 @@ pa_operation* pa_stream_get_latency_info(pa_stream *s, pa_stream_get_latency_inf pa_operation *o; pa_tagstruct *t; struct timeval now; + uint64_t *counter; assert(s); assert(s->ref >= 1); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, pa_hashmap_size(s->counter_hashmap) < COUNTER_HASHMAP_MAXSIZE, PA_ERR_INTERNAL); o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); @@ -696,11 +713,14 @@ pa_operation* pa_stream_get_latency_info(pa_stream *s, pa_stream_get_latency_inf pa_gettimeofday(&now); pa_tagstruct_put_timeval(t, &now); - pa_tagstruct_putu64(t, s->counter); pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_info_callback, o); + counter = pa_xmalloc(sizeof(uint64_t)); + *counter = s->counter; + pa_hashmap_put(s->counter_hashmap, (void*)tag, counter); + return pa_operation_ref(o); } -- cgit From 50268e0dd06f92da3d25137b78ddfa438e4d62de Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 2 Mar 2006 16:37:35 +0000 Subject: Fix warnings on 64-bit systems. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@619 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/stream.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/polyp/stream.c b/src/polyp/stream.c index 3ac026f1..1257f7e6 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -629,8 +629,8 @@ static void stream_get_latency_info_callback(pa_pdispatch *pd, uint32_t command, assert(o->stream); assert(o->context); - i.counter = *(uint64_t*)pa_hashmap_get(o->stream->counter_hashmap, (void*)tag); - pa_xfree(pa_hashmap_remove(o->stream->counter_hashmap, (void*)tag)); + i.counter = *(uint64_t*)pa_hashmap_get(o->stream->counter_hashmap, (void*)(unsigned long)tag); + pa_xfree(pa_hashmap_remove(o->stream->counter_hashmap, (void*)(unsigned long)tag)); if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) @@ -719,7 +719,7 @@ pa_operation* pa_stream_get_latency_info(pa_stream *s, pa_stream_get_latency_inf counter = pa_xmalloc(sizeof(uint64_t)); *counter = s->counter; - pa_hashmap_put(s->counter_hashmap, (void*)tag, counter); + pa_hashmap_put(s->counter_hashmap, (void*)(unsigned long)tag, counter); return pa_operation_ref(o); } -- cgit From fbaaf5acb7b391c605585971dac2b417b55f1100 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 2 Mar 2006 16:40:23 +0000 Subject: The tag argument is no longer unused. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@620 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polyp/stream.c b/src/polyp/stream.c index 1257f7e6..ab6ab408 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -619,7 +619,7 @@ pa_operation * pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *us return pa_operation_ref(o); } -static void stream_get_latency_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { +static void stream_get_latency_info_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; pa_latency_info i, *p = NULL; struct timeval local, remote, now; -- cgit From bc97b29447bf5c9932ceccb665fa57dd7f654b36 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 2 Mar 2006 21:56:15 +0000 Subject: Negotiate protocol version between server and client. Will allow smoother protocol modifications in the future. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@621 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 1 + src/polyp/context.c | 25 +++++++++++++++++++++++++ src/polyp/context.h | 6 ++++++ src/polyp/def.h | 1 + src/polyp/error.c | 1 + src/polyp/internal.h | 1 + src/polyp/version.h.in | 4 ++++ src/polypcore/protocol-native.c | 19 ++++++++++++++++--- 8 files changed, 55 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 25a89edc..a0b16573 100644 --- a/configure.ac +++ b/configure.ac @@ -29,6 +29,7 @@ AC_SUBST(PA_MAJORMINOR, "$PACKAGE_VERSION") AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/polypaudio/]) AC_SUBST(PA_API_VERSION, 8) +AC_SUBST(PA_PROTOCOL_VERSION, 8) if type -p stow > /dev/null && test -d /usr/local/stow ; then AC_MSG_NOTICE([*** Found /usr/local/stow: default install prefix set to /usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION} ***]) diff --git a/src/polyp/context.c b/src/polyp/context.c index 59079cb0..845e88d9 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -354,6 +354,19 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t switch(c->state) { case PA_CONTEXT_AUTHORIZING: { pa_tagstruct *reply; + + if (pa_tagstruct_getu32(t, &c->version) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(c, PA_ERR_PROTOCOL); + goto finish; + } + + /* Minimum supported version */ + if (c->version < 8) { + pa_context_fail(c, PA_ERR_VERSION); + goto finish; + } + reply = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag); pa_tagstruct_puts(reply, c->name); pa_pstream_send_tagstruct(c->pstream, reply); @@ -400,6 +413,7 @@ static void setup_context(pa_context *c, pa_iochannel *io) { } t = pa_tagstruct_command(c, PA_COMMAND_AUTH, &tag); + pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION); pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie)); pa_pstream_send_tagstruct_with_creds(c->pstream, t, 1); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); @@ -936,6 +950,17 @@ const char* pa_context_get_server(pa_context *c) { return c->server; } +uint32_t pa_context_get_protocol_version(pa_context *c) { + return PA_PROTOCOL_VERSION; +} + +uint32_t pa_context_get_server_protocol_version(pa_context *c) { + assert(c); + assert(c->ref >= 1); + + return c->version; +} + pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag) { pa_tagstruct *t; diff --git a/src/polyp/context.h b/src/polyp/context.h index 73bcb698..89febe92 100644 --- a/src/polyp/context.h +++ b/src/polyp/context.h @@ -115,6 +115,12 @@ pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_su /** Return the server name this context is connected to. \since 0.7 */ const char* pa_context_get_server(pa_context *c); +/** Return the protocol version of the library. \since 0.8 */ +uint32_t pa_context_get_protocol_version(pa_context *c); + +/** Return the protocol version of the connected server. \since 0.8 */ +uint32_t pa_context_get_server_protocol_version(pa_context *c); + PA_C_DECL_END #endif diff --git a/src/polyp/def.h b/src/polyp/def.h index 426a0c9b..98420bc0 100644 --- a/src/polyp/def.h +++ b/src/polyp/def.h @@ -125,6 +125,7 @@ enum { PA_ERR_MODINITFAILED, /**< Module initialization failed */ PA_ERR_BADSTATE, /**< Bad state */ PA_ERR_NODATA, /**< No data */ + PA_ERR_VERSION, /**< Incompatible protocol version \since 0.8 */ PA_ERR_MAX /**< Not really an error but the first invalid error code */ }; diff --git a/src/polyp/error.c b/src/polyp/error.c index eff37cc8..3f3e637f 100644 --- a/src/polyp/error.c +++ b/src/polyp/error.c @@ -48,6 +48,7 @@ static const char* const errortab[PA_ERR_MAX] = { [PA_ERR_MODINITFAILED] = "Module initalization failed", [PA_ERR_BADSTATE] = "Bad state", [PA_ERR_NODATA] = "No data", + [PA_ERR_VERSION] = "Incompatible protocol version", }; const char*pa_strerror(int error) { diff --git a/src/polyp/internal.h b/src/polyp/internal.h index 1443f7a8..82d8f7ce 100644 --- a/src/polyp/internal.h +++ b/src/polyp/internal.h @@ -57,6 +57,7 @@ struct pa_context { PA_LLIST_HEAD(pa_stream, streams); PA_LLIST_HEAD(pa_operation, operations); + uint32_t version; uint32_t ctag; uint32_t csyncid; uint32_t error; diff --git a/src/polyp/version.h.in b/src/polyp/version.h.in index 67b7495b..de7b9c1c 100644 --- a/src/polyp/version.h.in +++ b/src/polyp/version.h.in @@ -44,6 +44,10 @@ const char* pa_get_library_version(void); * PA_API_VERSION undefined. */ #define PA_API_VERSION @PA_API_VERSION@ +/** The current protocol version. Version 8 relates to polypaudio 0.8. + * \since 0.8 */ +#define PA_PROTOCOL_VERSION @PA_PROTOCOL_VERSION@ + PA_C_DECL_END #endif diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 76761b73..68dc6366 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -29,6 +29,8 @@ #include #include +#include + #include #include #include @@ -111,6 +113,7 @@ enum { struct connection { int authorized; + uint32_t version; pa_protocol_native *protocol; pa_client *client; pa_pstream *pstream; @@ -866,14 +869,22 @@ static void command_exit(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; const void*cookie; + pa_tagstruct *reply; assert(c && t); - if (pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 || + if (pa_tagstruct_getu32(t, &c->version) < 0 || + pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; } + /* Minimum supported version */ + if (c->version < 8) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION); + return; + } + if (!c->authorized) { int success = 0; @@ -915,8 +926,10 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t c->auth_timeout_event = NULL; } } - - pa_pstream_send_simple_ack(c->pstream, tag); + + reply = reply_new(tag); + pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION); + pa_pstream_send_tagstruct(c->pstream, reply); } static void command_set_client_name(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { -- cgit From 4e522940ff39b97f278309d4f1ca36ceb3ec73b3 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sat, 4 Mar 2006 13:55:40 +0000 Subject: Alignment safe protocol handling in esound module. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@622 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-esound.c | 300 +++++++++++++++++++++++----------------- 1 file changed, 174 insertions(+), 126 deletions(-) diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index 04fbc3e4..08b7c6f7 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -221,24 +221,33 @@ static void connection_free(struct connection *c) { pa_xfree(c); } -static void* connection_write(struct connection *c, size_t length) { - size_t t, i; +static void connection_write_prepare(struct connection *c, size_t length) { + size_t t; assert(c); - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); - t = c->write_data_length+length; - + if (c->write_data_alloc < t) c->write_data = pa_xrealloc(c->write_data, c->write_data_alloc = t); assert(c->write_data); +} + +static void connection_write(struct connection *c, const void *data, size_t length) { + size_t i; + assert(c); + + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + + connection_write_prepare(c, length); + + assert(c->write_data); i = c->write_data_length; c->write_data_length += length; - return (uint8_t*) c->write_data+i; + memcpy((char*)c->write_data + i, data, length); } static void format_esd2native(int format, int swap_bytes, pa_sample_spec *ss) { @@ -271,7 +280,8 @@ static int format_native2esd(pa_sample_spec *ss) { static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { uint32_t ekey; - int *ok; + int ok; + assert(length == (ESD_KEY_LEN + sizeof(uint32_t))); if (!c->authorized) { @@ -286,8 +296,10 @@ static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t req c->auth_timeout_event = NULL; } } - - ekey = *(const uint32_t*)((const uint8_t*) data+ESD_KEY_LEN); + + data = (char*)data + ESD_KEY_LEN; + + memcpy(&ekey, data, sizeof(uint32_t)); if (ekey == ESD_ENDIAN_KEY) c->swap_byte_order = 0; else if (ekey == ESD_SWAP_ENDIAN_KEY) @@ -297,22 +309,27 @@ static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t req return -1; } - ok = connection_write(c, sizeof(int)); - assert(ok); - *ok = 1; + ok = 1; + connection_write(c, &ok, sizeof(int)); return 0; } static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { char name[ESD_NAME_MAX]; - int format, rate; + int32_t format, rate; pa_sink *sink; pa_sample_spec ss; size_t l; - assert(c && length == (sizeof(int)*2+ESD_NAME_MAX)); + + assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); - format = MAYBE_INT32_SWAP(c->swap_byte_order, *(const int*)data); - rate = MAYBE_INT32_SWAP(c->swap_byte_order, *((const int*)data + 1)); + memcpy(&format, data, sizeof(int32_t)); + format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + data = (char*)data + sizeof(int32_t); + + memcpy(&rate, (char*)data, sizeof(int32_t)); + rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + data = (char*)data + sizeof(int32_t); ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); @@ -321,7 +338,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1); CHECK_VALIDITY(sink, "No such sink"); - strncpy(name, (const char*) data + sizeof(int)*2, sizeof(name)); + strncpy(name, data, sizeof(name)); name[sizeof(name)-1] = 0; pa_client_set_name(c->client, name); @@ -362,14 +379,20 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length) { char name[ESD_NAME_MAX]; - int format, rate; + int32_t format, rate; pa_source *source; pa_sample_spec ss; size_t l; - assert(c && length == (sizeof(int)*2+ESD_NAME_MAX)); + + assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); - format = MAYBE_INT32_SWAP(c->swap_byte_order, *(const int*)data); - rate = MAYBE_INT32_SWAP(c->swap_byte_order, *((const int*)data + 1)); + memcpy(&format, data, sizeof(int32_t)); + format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + data = (char*)data + sizeof(int32_t); + + memcpy(&rate, (char*)data, sizeof(int32_t)); + rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + data = (char*)data + sizeof(int32_t); ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); @@ -397,7 +420,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co } } - strncpy(name, (const char*) data + sizeof(int)*2, sizeof(name)); + strncpy(name, data, sizeof(name)); name[sizeof(name)-1] = 0; pa_client_set_name(c->client, name); @@ -437,7 +460,8 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co static int esd_proto_get_latency(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { pa_sink *sink; - int latency, *lag; + int32_t latency; + assert(c && !data && length == 0); if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) @@ -447,28 +471,32 @@ static int esd_proto_get_latency(struct connection *c, PA_GCC_UNUSED esd_proto_t latency = (int) ((usec*44100)/1000000); } - lag = connection_write(c, sizeof(int)); - assert(lag); - *lag = MAYBE_INT32_SWAP(c->swap_byte_order, latency); + latency = MAYBE_INT32_SWAP(c->swap_byte_order, latency); + connection_write(c, &latency, sizeof(int32_t)); return 0; } static int esd_proto_server_info(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { - int rate = 44100, format = ESD_STEREO|ESD_BITS16; - int *response; + int32_t rate = 44100, format = ESD_STEREO|ESD_BITS16; + int32_t response; pa_sink *sink; - assert(c && data && length == sizeof(int)); + + assert(c && data && length == sizeof(int32_t)); if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { rate = sink->sample_spec.rate; format = format_native2esd(&sink->sample_spec); } - - response = connection_write(c, sizeof(int)*3); - assert(response); - *(response++) = 0; - *(response++) = MAYBE_INT32_SWAP(c->swap_byte_order, rate); - *(response++) = MAYBE_INT32_SWAP(c->swap_byte_order, format); + + connection_write_prepare(c, sizeof(int32_t) * 3); + + response = 0; + connection_write(c, &response, sizeof(int32_t)); + rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + connection_write(c, &rate, sizeof(int32_t)); + format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + connection_write(c, &format, sizeof(int32_t)); + return 0; } @@ -478,24 +506,30 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v struct connection *conn; uint32_t idx = PA_IDXSET_INVALID; unsigned nsamples; - assert(c && data && length == sizeof(int)); + char terminator[sizeof(int32_t)*6+ESD_NAME_MAX]; + + assert(c && data && length == sizeof(int32_t)); if (esd_proto_server_info(c, request, data, length) < 0) return -1; - k = sizeof(int)*5+ESD_NAME_MAX; - s = sizeof(int)*6+ESD_NAME_MAX; + k = sizeof(int32_t)*5+ESD_NAME_MAX; + s = sizeof(int32_t)*6+ESD_NAME_MAX; nsamples = c->protocol->core->scache ? pa_idxset_size(c->protocol->core->scache) : 0; - response = connection_write(c, (t = s*(nsamples+1) + k*(c->protocol->n_player+1))); - assert(k); + t = s*(nsamples+1) + k*(c->protocol->n_player+1); + + connection_write_prepare(c, t); + + memset(terminator, 0, sizeof(terminator)); for (conn = pa_idxset_first(c->protocol->connections, &idx); conn; conn = pa_idxset_next(c->protocol->connections, &idx)) { - int format = ESD_BITS16 | ESD_STEREO, rate = 44100, lvolume = ESD_VOLUME_BASE, rvolume = ESD_VOLUME_BASE; + int32_t id, format = ESD_BITS16 | ESD_STEREO, rate = 44100, lvolume = ESD_VOLUME_BASE, rvolume = ESD_VOLUME_BASE; + char name[ESD_NAME_MAX]; if (conn->state != ESD_STREAMING_DATA) continue; - assert(t >= s+k+k); + assert(t >= k*2+s); if (conn->sink_input) { rate = conn->sink_input->sample_spec.rate; @@ -505,137 +539,152 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v } /* id */ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (int) (conn->index+1)); - response += sizeof(int); + id = MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) (conn->index+1)); + connection_write(c, &id, sizeof(int32_t)); /* name */ assert(conn->client); - strncpy((char*) response, conn->client->name, ESD_NAME_MAX); - response += ESD_NAME_MAX; + strncpy(name, conn->client->name, ESD_NAME_MAX); + connection_write(c, name, ESD_NAME_MAX); /* rate */ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, rate); - response += sizeof(int); + rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + connection_write(c, &rate, sizeof(int32_t)); /* left */ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, lvolume); - response += sizeof(int); + lvolume = MAYBE_INT32_SWAP(c->swap_byte_order, lvolume); + connection_write(c, &lvolume, sizeof(int32_t)); /*right*/ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, rvolume); - response += sizeof(int); + rvolume = MAYBE_INT32_SWAP(c->swap_byte_order, rvolume); + connection_write(c, &rvolume, sizeof(int32_t)); /*format*/ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, format); - response += sizeof(int); + format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + connection_write(c, &format, sizeof(int32_t)); - t-= k; + t -= k; } assert(t == s*(nsamples+1)+k); - memset(response, 0, k); response += k; t -= k; + connection_write(c, terminator, k); + if (nsamples) { pa_scache_entry *ce; idx = PA_IDXSET_INVALID; for (ce = pa_idxset_first(c->protocol->core->scache, &idx); ce; ce = pa_idxset_next(c->protocol->core->scache, &idx)) { + int32_t id, rate, lvolume, rvolume, format, len; + char name[ESD_NAME_MAX]; + assert(t >= s*2); - + /* id */ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (int) (ce->index+1)); - response += sizeof(int); + id = MAYBE_INT32_SWAP(c->swap_byte_order, (int) (ce->index+1)); + connection_write(c, &id, sizeof(int32_t)); /* name */ if (strncmp(ce->name, SCACHE_PREFIX, sizeof(SCACHE_PREFIX)-1) == 0) - strncpy((char*) response, ce->name+sizeof(SCACHE_PREFIX)-1, ESD_NAME_MAX); + strncpy(name, ce->name+sizeof(SCACHE_PREFIX)-1, ESD_NAME_MAX); else - snprintf((char*) response, ESD_NAME_MAX, "native.%s", ce->name); - response += ESD_NAME_MAX; + snprintf(name, ESD_NAME_MAX, "native.%s", ce->name); + connection_write(c, name, ESD_NAME_MAX); /* rate */ - *((uint32_t*) response) = MAYBE_UINT32_SWAP(c->swap_byte_order, ce->sample_spec.rate); - response += sizeof(int); + rate = MAYBE_UINT32_SWAP(c->swap_byte_order, ce->sample_spec.rate); + connection_write(c, &rate, sizeof(int32_t)); /* left */ - *((uint32_t*) response) = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); - response += sizeof(int); + lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); + connection_write(c, &lvolume, sizeof(int32_t)); /*right*/ - *((uint32_t*) response) = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); - response += sizeof(int); + rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); + connection_write(c, &rvolume, sizeof(int32_t)); /*format*/ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, format_native2esd(&ce->sample_spec)); - response += sizeof(int); + format = MAYBE_INT32_SWAP(c->swap_byte_order, format_native2esd(&ce->sample_spec)); + connection_write(c, &format, sizeof(int32_t)); /*length*/ - *((int*) response) = MAYBE_INT32_SWAP(c->swap_byte_order, (int) ce->memchunk.length); - response += sizeof(int); + len = MAYBE_INT32_SWAP(c->swap_byte_order, (int) ce->memchunk.length); + connection_write(c, &len, sizeof(int32_t)); t -= s; } } assert(t == s); - memset(response, 0, s); + + connection_write(c, terminator, s); return 0; } static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { - int *ok; - uint32_t idx; - pa_volume_t lvolume, rvolume; + int32_t ok; + uint32_t idx, lvolume, rvolume; struct connection *conn; - assert(c && data && length == sizeof(int)*3); + + assert(c && data && length == sizeof(int32_t)*3); - idx = MAYBE_UINT32_SWAP(c->swap_byte_order, *(const uint32_t*)data)-1; - lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, *((const uint32_t*)data + 1)); - lvolume = (lvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; - rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, *((const uint32_t*)data + 2)); - rvolume = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; + memcpy(&idx, data, sizeof(uint32_t)); + idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; + data = (char*)data + sizeof(uint32_t); - ok = connection_write(c, sizeof(int)); - assert(ok); + memcpy(&lvolume, data, sizeof(uint32_t)); + lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, lvolume); + data = (char*)data + sizeof(uint32_t); + + memcpy(&rvolume, data, sizeof(uint32_t)); + rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, rvolume); + data = (char*)data + sizeof(uint32_t); if ((conn = pa_idxset_get_by_index(c->protocol->connections, idx))) { assert(conn->sink_input); - conn->sink_input->volume.values[0] = lvolume; - conn->sink_input->volume.values[1] = rvolume; + conn->sink_input->volume.values[0] = (lvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; + conn->sink_input->volume.values[1] = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; conn->sink_input->volume.channels = 2; - *ok = 1; + ok = 1; } else - *ok = 0; + ok = 0; + + connection_write(c, &ok, sizeof(int32_t)); return 0; } static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { pa_sample_spec ss; - int format, rate; - size_t sc_length; + int32_t format, rate, sc_length; uint32_t idx; - int *ok; char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; - assert(c && data && length == (ESD_NAME_MAX+3*sizeof(int))); - format = MAYBE_INT32_SWAP(c->swap_byte_order, *(const int*)data); - rate = MAYBE_INT32_SWAP(c->swap_byte_order, *((const int*)data + 1)); + assert(c && data && length == (ESD_NAME_MAX+3*sizeof(int32_t))); + + memcpy(&format, data, sizeof(int32_t)); + format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + data = (char*)data + sizeof(int32_t); + + memcpy(&rate, (char*)data + sizeof(int32_t), sizeof(int32_t)); + rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + data = (char*)data + sizeof(int32_t); ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification."); - - sc_length = (size_t) MAYBE_INT32_SWAP(c->swap_byte_order, (*((const int*)data + 2))); + + memcpy(&sc_length, data, sizeof(int32_t)); + sc_length = MAYBE_INT32_SWAP(c->swap_byte_order, sc_length); CHECK_VALIDITY(sc_length <= MAX_CACHE_SAMPLE_SIZE, "Sample too large."); strcpy(name, SCACHE_PREFIX); - strncpy(name+sizeof(SCACHE_PREFIX)-1, (const char*) data+3*sizeof(int), ESD_NAME_MAX); + strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX); name[sizeof(name)-1] = 0; assert(!c->scache.memchunk.memblock); @@ -650,47 +699,43 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ pa_scache_add_item(c->protocol->core, c->scache.name, NULL, NULL, NULL, &idx); - ok = connection_write(c, sizeof(int)); - assert(ok); - - *ok = idx+1; + idx += 1; + connection_write(c, &idx, sizeof(uint32_t)); return 0; } static int esd_proto_sample_get_id(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { - int *ok; + int32_t ok; uint32_t idx; char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; - assert(c && data && length == ESD_NAME_MAX); - - ok = connection_write(c, sizeof(int)); - assert(ok); - *ok = -1; + assert(c && data && length == ESD_NAME_MAX); strcpy(name, SCACHE_PREFIX); strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX); name[sizeof(name)-1] = 0; + ok = -1; if ((idx = pa_scache_get_id_by_name(c->protocol->core, name)) != PA_IDXSET_INVALID) - *ok = (int) idx +1; + ok = idx + 1; + + connection_write(c, &ok, sizeof(int32_t)); return 0; } static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length) { - int *ok; + int32_t ok; const char *name; uint32_t idx; - assert(c && data && length == sizeof(int)); - idx = (uint32_t) MAYBE_INT32_SWAP(c->swap_byte_order, *(const int*)data)-1; + assert(c && data && length == sizeof(int32_t)); - ok = connection_write(c, sizeof(int)); - assert(ok); + memcpy(&idx, data, sizeof(uint32_t)); + idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; - *ok = 0; + ok = 0; if ((name = pa_scache_get_name_by_id(c->protocol->core, idx))) { if (request == ESD_PROTO_SAMPLE_PLAY) { @@ -698,24 +743,29 @@ static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t reque if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) if (pa_scache_play_item(c->protocol->core, name, sink, NULL) >= 0) - *ok = (int) idx+1; + ok = idx + 1; } else { assert(request == ESD_PROTO_SAMPLE_FREE); if (pa_scache_remove_item(c->protocol->core, name) >= 0) - *ok = (int) idx+1; + ok = idx + 1; } } + connection_write(c, &ok, sizeof(int32_t)); + return 0; } static int esd_proto_standby_or_resume(struct connection *c, PA_GCC_UNUSED esd_proto_t request, PA_GCC_UNUSED const void *data, PA_GCC_UNUSED size_t length) { - int *ok; - ok = connection_write(c, sizeof(int)*2); - assert(ok); - ok[0] = 1; - ok[1] = 1; + int32_t ok; + + connection_write_prepare(c, sizeof(int32_t) * 2); + + ok = 1; + connection_write(c, &ok, sizeof(int32_t)); + connection_write(c, &ok, sizeof(int32_t)); + return 0; } @@ -815,7 +865,6 @@ static int do_read(struct connection *c) { if (c->scache.memchunk.index == c->scache.memchunk.length) { uint32_t idx; - int *ok; c->scache.memchunk.index = 0; pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, NULL, &c->scache.memchunk, &idx); @@ -829,9 +878,8 @@ static int do_read(struct connection *c) { c->state = ESD_NEXT_REQUEST; - ok = connection_write(c, sizeof(int)); - assert(ok); - *ok = idx+1; + idx += 1; + connection_write(c, &idx, sizeof(uint32_t)); } } else if (c->state == ESD_STREAMING_DATA && c->sink_input) { -- cgit From ad7640b78982b6bed3999164e522f980e4deb3ac Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sat, 4 Mar 2006 13:56:09 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@623 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index df13e56f..d6df239f 100644 --- a/doc/todo +++ b/doc/todo @@ -5,7 +5,6 @@ Test: - module-tunnel Fixes: -- proper use of memcpy in procotol-esound.c so we don't get alignment problems - latency api rework for native protocol - module-oss-* love: - deal with underflows propely -- cgit From 45baa6958edccddd7264b11b8d48b5aec69418bf Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sat, 4 Mar 2006 17:31:23 +0000 Subject: Fix warning caused by missing return in main(). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@624 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/tests/mcalign-test.c | 2 ++ src/tests/voltest.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/tests/mcalign-test.c b/src/tests/mcalign-test.c index 861c38c1..eab5dc88 100644 --- a/src/tests/mcalign-test.c +++ b/src/tests/mcalign-test.c @@ -93,4 +93,6 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { if (c.memblock) pa_memblock_unref(c.memblock); + + return 0; } diff --git a/src/tests/voltest.c b/src/tests/voltest.c index 58f1da00..4db8ef28 100644 --- a/src/tests/voltest.c +++ b/src/tests/voltest.c @@ -17,4 +17,6 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { v, (v*100)/PA_VOLUME_NORM, dB, f, pa_sw_volume_from_dB(dB), pa_sw_volume_from_linear(f)); } + + return 0; } -- cgit From dcd202f8eb94ef14981f2b80c7f28a5936ba35a2 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sat, 4 Mar 2006 21:30:29 +0000 Subject: Update module-tunnel to the new protocol. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@625 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 70bded6c..ff1113cc 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -31,6 +31,8 @@ #include #include +#include + #include #include #include @@ -122,6 +124,7 @@ struct userdata { uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; + uint32_t version; uint32_t ctag; uint32_t device_index; uint32_t channel; @@ -254,7 +257,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G pa_usec_t buffer_usec, sink_usec, source_usec, transport_usec; int playing; uint32_t queue_length; - uint64_t counter; + int64_t write_index, read_index; struct timeval local, remote, now; assert(pd && u); @@ -274,7 +277,8 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G pa_tagstruct_getu32(t, &queue_length) < 0 || pa_tagstruct_get_timeval(t, &local) < 0 || pa_tagstruct_get_timeval(t, &remote) < 0 || - pa_tagstruct_getu64(t, &counter) < 0 || + pa_tagstruct_gets64(t, &write_index) < 0 || + pa_tagstruct_gets64(t, &read_index) < 0 || !pa_tagstruct_eof(t)) { pa_log(__FILE__": invalid reply."); die(u); @@ -323,7 +327,6 @@ static void request_latency(struct userdata *u) { pa_gettimeofday(&now); pa_tagstruct_put_timeval(t, &now); - pa_tagstruct_putu64(t, 0); pa_pstream_send_tagstruct(u->pstream, t); pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u); @@ -363,9 +366,14 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t struct userdata *u = userdata; pa_tagstruct *reply; char name[256], un[128], hn[128]; +#ifdef TUNNEL_SINK + pa_cvolume volume; +#endif assert(pd && u && u->pdispatch == pd); - if (command != PA_COMMAND_REPLY || !pa_tagstruct_eof(t)) { + if (command != PA_COMMAND_REPLY || + pa_tagstruct_getu32(t, &u->version) < 0 || + !pa_tagstruct_eof(t)) { if (command == PA_COMMAND_ERROR) pa_log(__FILE__": failed to authenticate"); else @@ -373,6 +381,14 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t die(u); return; } + + /* Minimum supported protocol version */ + if (u->version < 8) { + pa_log(__FILE__": incompatible protocol version"); + die(u); + return; + } + #ifdef TUNNEL_SINK snprintf(name, sizeof(name), "Tunnel from host '%s', user '%s', sink '%s'", pa_get_host_name(hn, sizeof(hn)), @@ -398,6 +414,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_tagstruct_putu32(reply, tag = u->ctag++); pa_tagstruct_puts(reply, name); pa_tagstruct_put_sample_spec(reply, &u->sink->sample_spec); + pa_tagstruct_put_channel_map(reply, &u->sink->channel_map); pa_tagstruct_putu32(reply, PA_INVALID_INDEX); pa_tagstruct_puts(reply, u->sink_name); pa_tagstruct_putu32(reply, DEFAULT_MAXLENGTH); @@ -405,12 +422,15 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_tagstruct_putu32(reply, DEFAULT_TLENGTH); pa_tagstruct_putu32(reply, DEFAULT_PREBUF); pa_tagstruct_putu32(reply, DEFAULT_MINREQ); - pa_tagstruct_putu32(reply, PA_VOLUME_NORM); + pa_tagstruct_putu32(reply, 0); + pa_cvolume_reset(&volume, u->sink->sample_spec.channels); + pa_tagstruct_put_cvolume(reply, &volume); #else pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_RECORD_STREAM); pa_tagstruct_putu32(reply, tag = u->ctag++); pa_tagstruct_puts(reply, name); pa_tagstruct_put_sample_spec(reply, &u->source->sample_spec); + pa_tagstruct_put_channel_map(reply, &u->source->channel_map); pa_tagstruct_putu32(reply, PA_INVALID_INDEX); pa_tagstruct_puts(reply, u->source_name); pa_tagstruct_putu32(reply, DEFAULT_MAXLENGTH); @@ -483,6 +503,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_AUTH); pa_tagstruct_putu32(t, tag = u->ctag++); + pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION); pa_tagstruct_put_arbitrary(t, u->auth_cookie, sizeof(u->auth_cookie)); pa_pstream_send_tagstruct(u->pstream, t); pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, u); -- cgit From 7b6a9c3829fe17dc836a3220bff1f9b4e35d3a57 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 5 Mar 2006 15:42:37 +0000 Subject: Tried to get the volume information even upon init failure. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@626 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-sink.c | 8 ++++---- src/modules/module-alsa-source.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 732612ef..0053acd2 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -409,16 +409,16 @@ int pa__init(pa_core *c, pa_module*m) { u->memchunk.index = u->memchunk.length = 0; ret = 0; - -finish: - if (ma) - pa_modargs_free(ma); /* Get initial mixer settings */ if (u->sink->get_hw_volume) u->sink->get_hw_volume(u->sink); if (u->sink->get_hw_mute) u->sink->get_hw_mute(u->sink); + +finish: + if (ma) + pa_modargs_free(ma); return ret; diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 1b7ae7d3..5a6dc144 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -398,15 +398,15 @@ int pa__init(pa_core *c, pa_module*m) { ret = 0; -finish: - if (ma) - pa_modargs_free(ma); - /* Get initial mixer settings */ if (u->source->get_hw_volume) u->source->get_hw_volume(u->source); if (u->source->get_hw_mute) u->source->get_hw_mute(u->source); + +finish: + if (ma) + pa_modargs_free(ma); return ret; -- cgit From f22d8ab3fe46e971f40bed21b159cf0c54d05f98 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 5 Mar 2006 18:35:45 +0000 Subject: Return the proper error code so that we get a correct error message. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@627 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index adb6f3f1..c7be4790 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -263,25 +263,25 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint3 }; assert(pcm_handle && ss && periods && period_size); - if (snd_pcm_hw_params_malloc(&hwparams) < 0 || - snd_pcm_hw_params_any(pcm_handle, hwparams) < 0 || - snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0 || - snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format]) < 0 || - snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL) < 0 || - snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels) < 0 || - (*periods > 0 && snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, periods, NULL) < 0) || - (*period_size > 0 && snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL) < 0) || - snd_pcm_hw_params(pcm_handle, hwparams) < 0) + if ((ret = snd_pcm_hw_params_malloc(&hwparams)) < 0 || + (ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 || + (ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0 || + (ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format])) < 0 || + (ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0 || + (ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels)) < 0 || + (*periods > 0 && (ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, periods, NULL)) < 0) || + (*period_size > 0 && (ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL)) < 0) || + (ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) goto finish; if (ss->rate != r) pa_log_info(__FILE__": device doesn't support %u Hz, changed to %u Hz.", ss->rate, r); - if (snd_pcm_prepare(pcm_handle) < 0) + if ((ret = snd_pcm_prepare(pcm_handle)) < 0) goto finish; - if (snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size) < 0 || - snd_pcm_hw_params_get_period_size(hwparams, period_size, NULL) < 0) + if ((ret = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size)) < 0 || + (ret = snd_pcm_hw_params_get_period_size(hwparams, period_size, NULL)) < 0) goto finish; assert(buffer_size > 0); -- cgit From 4e56725a60da8a1c80442ab16f7fe21147b143e9 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 5 Mar 2006 18:37:13 +0000 Subject: It's safer to set buffer size than to try setting number of periods. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@628 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index c7be4790..683db6c0 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -262,6 +262,8 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint3 [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, }; assert(pcm_handle && ss && periods && period_size); + + buffer_size = *periods * *period_size; if ((ret = snd_pcm_hw_params_malloc(&hwparams)) < 0 || (ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 || @@ -269,7 +271,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint3 (ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format])) < 0 || (ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0 || (ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels)) < 0 || - (*periods > 0 && (ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, periods, NULL)) < 0) || + (*periods > 0 && (ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0) || (*period_size > 0 && (ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL)) < 0) || (ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) goto finish; -- cgit From 738734244dc6b28d404953e9133f49c518f6a4e0 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 5 Mar 2006 20:18:04 +0000 Subject: Volume support in tunnel module. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@629 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 261 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 260 insertions(+), 1 deletion(-) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index ff1113cc..aa6b69f5 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -91,6 +91,7 @@ static const char* const valid_modargs[] = { }; static void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); #ifdef TUNNEL_SINK static void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); @@ -101,7 +102,8 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_REQUEST] = command_request, #endif [PA_COMMAND_PLAYBACK_STREAM_KILLED] = command_stream_killed, - [PA_COMMAND_RECORD_STREAM_KILLED] = command_stream_killed + [PA_COMMAND_RECORD_STREAM_KILLED] = command_stream_killed, + [PA_COMMAND_SUBSCRIBE_EVENT] = command_subscribe_event, }; struct userdata { @@ -189,6 +191,35 @@ static void command_stream_killed(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t comma die(u); } +static void request_info(struct userdata *u); + +static void command_subscribe_event(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + pa_subscription_event_type_t e; + uint32_t idx; + + assert(pd && t && u); + assert(command == PA_COMMAND_SUBSCRIBE_EVENT); + + if (pa_tagstruct_getu32(t, &e) < 0 || + pa_tagstruct_getu32(t, &idx) < 0 || + !pa_tagstruct_eof(t)) { + pa_log(__FILE__": invalid protocol reply"); + die(u); + return; + } + +#ifdef TUNNEL_SINK + if (e != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE)) + return; +#else + if (e != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE)) + return; +#endif + + request_info(u); +} + #ifdef TUNNEL_SINK static void send_prebuf_request(struct userdata *u) { pa_tagstruct *t; @@ -332,6 +363,115 @@ static void request_latency(struct userdata *u) { pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u); } +static void stream_get_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + uint32_t index, owner_module, monitor_source; + pa_usec_t latency; + const char *name, *description, *monitor_source_name, *driver; + int mute; + pa_sample_spec sample_spec; + pa_channel_map channel_map; + pa_cvolume volume; + assert(pd && u); + + if (command != PA_COMMAND_REPLY) { + if (command == PA_COMMAND_ERROR) + pa_log(__FILE__": failed to get info."); + else + pa_log(__FILE__": protocol error."); + die(u); + return; + } + + if (pa_tagstruct_getu32(t, &index) < 0 || + pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_gets(t, &description) < 0 || + pa_tagstruct_get_sample_spec(t, &sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &channel_map) < 0 || + pa_tagstruct_getu32(t, &owner_module) < 0 || + pa_tagstruct_get_cvolume(t, &volume) < 0 || + pa_tagstruct_get_boolean(t, &mute) < 0 || + pa_tagstruct_getu32(t, &monitor_source) < 0 || + pa_tagstruct_gets(t, &monitor_source_name) < 0 || + pa_tagstruct_get_usec(t, &latency) < 0 || + pa_tagstruct_gets(t, &driver) < 0 || + !pa_tagstruct_eof(t)) { + pa_log(__FILE__": invalid reply."); + die(u); + return; + } + +#ifdef TUNNEL_SINK + assert(u->sink); + if ((!!mute == !!u->sink->hw_muted) && + pa_cvolume_equal(&volume, &u->sink->hw_volume)) + return; +#else + assert(u->source); + if ((!!mute == !!u->source->hw_muted) && + pa_cvolume_equal(&volume, &u->source->hw_volume)) + return; +#endif + +#ifdef TUNNEL_SINK + memcpy(&u->sink->hw_volume, &volume, sizeof(pa_cvolume)); + u->sink->hw_muted = !!mute; + + pa_subscription_post(u->sink->core, + PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, + u->sink->index); +#else + memcpy(&u->source->hw_volume, &volume, sizeof(pa_cvolume)); + u->source->hw_muted = !!mute; + + pa_subscription_post(u->source->core, + PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, + u->source->index); +#endif +} + +static void request_info(struct userdata *u) { + pa_tagstruct *t; + uint32_t tag; + assert(u); + + t = pa_tagstruct_new(NULL, 0); +#ifdef TUNNEL_SINK + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); +#else + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); +#endif + pa_tagstruct_putu32(t, tag = u->ctag++); + + pa_tagstruct_putu32(t, PA_INVALID_INDEX); +#ifdef TUNNEL_SINK + pa_tagstruct_puts(t, u->sink_name); +#else + pa_tagstruct_puts(t, u->source_name); +#endif + + pa_pstream_send_tagstruct(u->pstream, t); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_info_callback, u); +} + +static void start_subscribe(struct userdata *u) { + pa_tagstruct *t; + uint32_t tag; + assert(u); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); + pa_tagstruct_putu32(t, tag = u->ctag++); + +#ifdef TUNNEL_SINK + pa_tagstruct_putu32(t, PA_SUBSCRIPTION_MASK_SINK); +#else + pa_tagstruct_putu32(t, PA_SUBSCRIPTION_MASK_SOURCE); +#endif + + pa_pstream_send_tagstruct(u->pstream, t); +} + static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; assert(pd && u && u->pdispatch == pd); @@ -356,6 +496,9 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN return; } + start_subscribe(u); + request_info(u); + request_latency(u); #ifdef TUNNEL_SINK send_bytes(u); @@ -537,6 +680,60 @@ static pa_usec_t sink_get_latency(pa_sink *sink) { return usec; } + +static int sink_get_hw_volume(pa_sink *sink) { + struct userdata *u; + assert(sink && sink->userdata); + u = sink->userdata; + + return 0; +} + +static int sink_set_hw_volume(pa_sink *sink) { + struct userdata *u; + pa_tagstruct *t; + uint32_t tag; + assert(sink && sink->userdata); + u = sink->userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); + pa_tagstruct_putu32(t, tag = u->ctag++); + + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, u->sink_name); + pa_tagstruct_put_cvolume(t, &sink->hw_volume); + pa_pstream_send_tagstruct(u->pstream, t); + + return 0; +} + +static int sink_get_hw_mute(pa_sink *sink) { + struct userdata *u; + assert(sink && sink->userdata); + u = sink->userdata; + + return 0; +} + +static int sink_set_hw_mute(pa_sink *sink) { + struct userdata *u; + pa_tagstruct *t; + uint32_t tag; + assert(sink && sink->userdata); + u = sink->userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_MUTE); + pa_tagstruct_putu32(t, tag = u->ctag++); + + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, u->sink_name); + pa_tagstruct_put_boolean(t, !!sink->hw_muted); + pa_pstream_send_tagstruct(u->pstream, t); + + return 0; +} #else static pa_usec_t source_get_latency(pa_source *source) { struct userdata *u; @@ -545,6 +742,60 @@ static pa_usec_t source_get_latency(pa_source *source) { return u->host_latency; } + +static int source_get_hw_volume(pa_source *source) { + struct userdata *u; + assert(source && source->userdata); + u = source->userdata; + + return 0; +} + +static int source_set_hw_volume(pa_source *source) { + struct userdata *u; + pa_tagstruct *t; + uint32_t tag; + assert(source && source->userdata); + u = source->userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SOURCE_VOLUME); + pa_tagstruct_putu32(t, tag = u->ctag++); + + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, u->source_name); + pa_tagstruct_put_cvolume(t, &source->hw_volume); + pa_pstream_send_tagstruct(u->pstream, t); + + return 0; +} + +static int source_get_hw_mute(pa_source *source) { + struct userdata *u; + assert(source && source->userdata); + u = source->userdata; + + return 0; +} + +static int source_set_hw_mute(pa_source *source) { + struct userdata *u; + pa_tagstruct *t; + uint32_t tag; + assert(source && source->userdata); + u = source->userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SOURCE_MUTE); + pa_tagstruct_putu32(t, tag = u->ctag++); + + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, u->source_name); + pa_tagstruct_put_boolean(t, !!source->hw_muted); + pa_pstream_send_tagstruct(u->pstream, t); + + return 0; +} #endif static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { @@ -651,6 +902,10 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->notify = sink_notify; u->sink->get_latency = sink_get_latency; + u->sink->get_hw_volume = sink_get_hw_volume; + u->sink->set_hw_volume = sink_set_hw_volume; + u->sink->get_hw_mute = sink_get_hw_mute; + u->sink->set_hw_mute = sink_set_hw_mute; u->sink->userdata = u; u->sink->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->sink_name ? u->sink_name : "", u->sink_name ? "@" : "", u->server_name); @@ -662,6 +917,10 @@ int pa__init(pa_core *c, pa_module*m) { } u->source->get_latency = source_get_latency; + u->source->get_hw_volume = source_get_hw_volume; + u->source->set_hw_volume = source_set_hw_volume; + u->source->get_hw_mute = source_get_hw_mute; + u->source->set_hw_mute = source_set_hw_mute; u->source->userdata = u; u->source->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->source_name ? u->source_name : "", u->source_name ? "@" : "", u->server_name); -- cgit From 06eaebf0b44fbad8c7a85616f6272661de5c1add Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 5 Mar 2006 20:18:35 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@630 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index d6df239f..8d79599e 100644 --- a/doc/todo +++ b/doc/todo @@ -12,7 +12,6 @@ Fixes: - module-alsa-* love: - add hw driver name to sink/source description - deal with underflows properly -- module-tunnel volume support (sink, source, notify) Post 0.8: - alsa mmap driver -- cgit From 53c266f6636afd3b9abb88148d7dd2349b1caf13 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 5 Mar 2006 20:59:57 +0000 Subject: Fetch sound card name into sink/source description. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@631 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-sink.c | 12 +++++++++++- src/modules/module-alsa-source.c | 12 +++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 0053acd2..6ace7aff 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -308,6 +308,7 @@ int pa__init(pa_core *c, pa_module*m) { uint32_t periods, fragsize; snd_pcm_uframes_t period_size; size_t frame_size; + snd_pcm_info_t *pcm_info = NULL; int err; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -340,6 +341,12 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } + if ((err = snd_pcm_info_malloc(&pcm_info)) < 0 || + (err = snd_pcm_info(u->pcm_handle, pcm_info)) < 0) { + pa_log(__FILE__": Error fetching PCM info: %s", snd_strerror(err)); + goto fail; + } + if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) { pa_log(__FILE__": Failed to set hardware parameters: %s", snd_strerror(err)); goto fail; @@ -375,7 +382,7 @@ int pa__init(pa_core *c, pa_module*m) { } u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); + u->sink->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s' (%s)", dev, snd_pcm_info_get_name(pcm_info)); u->pcm_fdl = pa_alsa_fdlist_new(); assert(u->pcm_fdl); @@ -419,6 +426,9 @@ int pa__init(pa_core *c, pa_module*m) { finish: if (ma) pa_modargs_free(ma); + + if (pcm_info) + snd_pcm_info_free(pcm_info); return ret; diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 5a6dc144..3343e0b6 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -299,6 +299,7 @@ int pa__init(pa_core *c, pa_module*m) { unsigned periods, fragsize; snd_pcm_uframes_t period_size; size_t frame_size; + snd_pcm_info_t *pcm_info = NULL; int err; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -331,6 +332,12 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } + if ((err = snd_pcm_info_malloc(&pcm_info)) < 0 || + (err = snd_pcm_info(u->pcm_handle, pcm_info)) < 0) { + pa_log(__FILE__": Error fetching PCM info: %s", snd_strerror(err)); + goto fail; + } + if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) { pa_log(__FILE__": Failed to set hardware parameters: %s", snd_strerror(err)); goto fail; @@ -366,7 +373,7 @@ int pa__init(pa_core *c, pa_module*m) { } } pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); + u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s' (%s)", dev, snd_pcm_info_get_name(pcm_info)); u->pcm_fdl = pa_alsa_fdlist_new(); assert(u->pcm_fdl); @@ -407,6 +414,9 @@ int pa__init(pa_core *c, pa_module*m) { finish: if (ma) pa_modargs_free(ma); + + if (pcm_info) + snd_pcm_info_free(pcm_info); return ret; -- cgit From 90d6a919fa1e358d1cffeb00b76d297dc9beb1e7 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 5 Mar 2006 21:00:31 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@632 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index 8d79599e..c1864746 100644 --- a/doc/todo +++ b/doc/todo @@ -10,7 +10,6 @@ Fixes: - deal with underflows propely - improve latency measurement for mmap - module-alsa-* love: - - add hw driver name to sink/source description - deal with underflows properly Post 0.8: -- cgit From 64571374b3d7941471838eecc1457046854ed4d9 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 7 Mar 2006 16:02:34 +0000 Subject: Trying to listen on an IPv6 socket by default and only do IPv4 if that fails (which it doesn't most of the time) is terribly confusing. What the user most likely wants is for it to listen to both IPv4 and IPv6 and gracefully continue if only of them succeed. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@633 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-protocol-stub.c | 143 +++++++++++++++++++++++++++---------- src/polypcore/socket-server.c | 49 ++++++++----- src/polypcore/socket-server.h | 9 ++- 3 files changed, 143 insertions(+), 58 deletions(-) diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index b02b9688..71e17cbc 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -49,6 +49,7 @@ #include #include #include +#include #ifdef USE_TCP_SOCKETS #define SOCKET_DESCRIPTION "(TCP sockets)" @@ -162,41 +163,71 @@ static const char* const valid_modargs[] = { NULL }; -static pa_socket_server *create_socket_server(pa_core *c, pa_modargs *ma) { - pa_socket_server *s; +struct userdata { +#if defined(USE_TCP_SOCKETS) + void *protocol_ipv4; + void *protocol_ipv6; +#else + void *protocol_unix; +#endif +}; + +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; + int ret = -1; + + struct userdata *u = NULL; + #if defined(USE_TCP_SOCKETS) + pa_socket_server *s_ipv4 = NULL; + pa_socket_server *s_ipv6 = NULL; int loopback = 1; uint32_t port = IPV4_PORT; const char *listen_on; +#else + pa_socket_server *s; + int r; + const char *v; + char tmp[PATH_MAX]; +#endif + + assert(c && m); + +#if defined(USE_TCP_SOCKETS) + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": Failed to parse module arguments"); + goto finish; + } if (pa_modargs_get_value_boolean(ma, "loopback", &loopback) < 0) { pa_log(__FILE__": loopback= expects a boolean argument."); - return NULL; + goto fail; } if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) { pa_log(__FILE__": port= expects a numerical argument between 1 and 65535."); - return NULL; + goto fail; } listen_on = pa_modargs_get_value(ma, "listen", NULL); if (listen_on) { - if (!(s = pa_socket_server_new_ip_string(c->mainloop, listen_on, port, TCPWRAP_SERVICE))) - return NULL; + s_ipv4 = pa_socket_server_new_ipv4_string(c->mainloop, listen_on, port, TCPWRAP_SERVICE); + s_ipv6 = pa_socket_server_new_ipv6_string(c->mainloop, listen_on, port, TCPWRAP_SERVICE); + if (!s_ipv4 && !s_ipv6) + goto fail; } else if (loopback) { - if (!(s = pa_socket_server_new_ip_loopback(c->mainloop, port, TCPWRAP_SERVICE))) - return NULL; + s_ipv4 = pa_socket_server_new_ipv4_loopback(c->mainloop, port, TCPWRAP_SERVICE); + s_ipv6 = pa_socket_server_new_ipv6_loopback(c->mainloop, port, TCPWRAP_SERVICE); + if (!s_ipv4 && !s_ipv6) + goto fail; } else { - if (!(s = pa_socket_server_new_ip_any(c->mainloop, port, TCPWRAP_SERVICE))) - return NULL; + s_ipv4 = pa_socket_server_new_ipv4_any(c->mainloop, port, TCPWRAP_SERVICE); + s_ipv6 = pa_socket_server_new_ipv6_any(c->mainloop, port, TCPWRAP_SERVICE); + if (!s_ipv4 && !s_ipv6) + goto fail; } - #else - int r; - const char *v; - char tmp[PATH_MAX]; - v = pa_modargs_get_value(ma, "socket", UNIX_SOCKET); assert(v); @@ -204,43 +235,43 @@ static pa_socket_server *create_socket_server(pa_core *c, pa_modargs *ma) { if (pa_make_secure_parent_dir(tmp) < 0) { pa_log(__FILE__": Failed to create secure socket directory."); - return NULL; + goto fail; } if ((r = pa_unix_socket_remove_stale(tmp)) < 0) { pa_log(__FILE__": Failed to remove stale UNIX socket '%s': %s", tmp, strerror(errno)); - return NULL; + goto fail; } if (r) pa_log(__FILE__": Removed stale UNIX socket '%s'.", tmp); if (!(s = pa_socket_server_new_unix(c->mainloop, tmp))) - return NULL; - + goto fail; #endif - return s; -} -int pa__init(pa_core *c, pa_module*m) { - pa_socket_server *s; - pa_modargs *ma = NULL; - int ret = -1; - assert(c && m); + u = pa_xmalloc0(sizeof(struct userdata)); - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments"); - goto finish; +#if defined(USE_TCP_SOCKETS) + if (s_ipv4) { + u->protocol_ipv4 = protocol_new(c, s_ipv4, m, ma); + if (!u->protocol_ipv4) + pa_socket_server_unref(s_ipv4); } - if (!(s = create_socket_server(c, ma))) - goto finish; - - if (!(m->userdata = protocol_new(c, s, m, ma))) { - pa_socket_server_unref(s); - goto finish; + if (s_ipv6) { + u->protocol_ipv6 = protocol_new(c, s_ipv4, m, ma); + if (!u->protocol_ipv6) + pa_socket_server_unref(s_ipv6); } + if (!u->protocol_ipv4 && !u->protocol_ipv6) + goto fail; +#else + if (!(u->protocol_unix = protocol_new(c, s, m, ma))) + goto fail; +#endif + ret = 0; finish: @@ -248,9 +279,36 @@ finish: pa_modargs_free(ma); return ret; + +fail: + if (u) { +#if defined(USE_TCP_SOCKETS) + if (u->protocol_ipv4) + protocol_free(u->protocol_ipv4); + if (u->protocol_ipv6) + protocol_free(u->protocol_ipv6); +#else + if (u->protocol_unix) + protocol_free(u->protocol_unix); +#endif + pa_xfree(u); + } else { +#if defined(USE_TCP_SOCKETS) + if (s_ipv4) + pa_socket_server_unref(s_ipv4); + if (s_ipv6) + pa_socket_server_unref(s_ipv6); +#else + if (s) + pa_socket_server_unref(s); +#endif + } + + goto finish; } void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; assert(c && m); #if defined(USE_PROTOCOL_ESOUND) && !defined(USE_TCP_SOCKETS) @@ -260,5 +318,18 @@ void pa__done(pa_core *c, pa_module*m) { pa_log("%s: Failed to remove %s : %s.", __FILE__, ESD_UNIX_SOCKET_DIR, strerror (errno)); #endif - protocol_free(m->userdata); + u = m->userdata; + assert(u); + +#if defined(USE_TCP_SOCKETS) + if (u->protocol_ipv4) + protocol_free(u->protocol_ipv4); + if (u->protocol_ipv6) + protocol_free(u->protocol_ipv6); +#else + if (u->protocol_unix) + protocol_free(u->protocol_unix); +#endif + + pa_xfree(u); } diff --git a/src/polypcore/socket-server.c b/src/polypcore/socket-server.c index d457d626..baa31e68 100644 --- a/src/polypcore/socket-server.c +++ b/src/polypcore/socket-server.c @@ -314,45 +314,56 @@ fail: return NULL; } -pa_socket_server* pa_socket_server_new_ip_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { - pa_socket_server *s; - +pa_socket_server* pa_socket_server_new_ipv4_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { assert(m); assert(port > 0); - - if (!(s = pa_socket_server_new_ipv6(m, in6addr_loopback.s6_addr, port, tcpwrap_service))) - s = pa_socket_server_new_ipv4(m, INADDR_LOOPBACK, port, tcpwrap_service); - return s; + return pa_socket_server_new_ipv4(m, INADDR_LOOPBACK, port, tcpwrap_service); } -pa_socket_server* pa_socket_server_new_ip_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { - pa_socket_server *s; - +pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { + assert(m); + assert(port > 0); + + return pa_socket_server_new_ipv6(m, in6addr_loopback.s6_addr, port, tcpwrap_service); +} + +pa_socket_server* pa_socket_server_new_ipv4_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { assert(m); assert(port > 0); - if (!(s = pa_socket_server_new_ipv6(m, in6addr_any.s6_addr, port, tcpwrap_service))) - s = pa_socket_server_new_ipv4(m, INADDR_ANY, port, tcpwrap_service); + return pa_socket_server_new_ipv4(m, INADDR_ANY, port, tcpwrap_service); +} - return s; +pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { + assert(m); + assert(port > 0); + + return pa_socket_server_new_ipv6(m, in6addr_any.s6_addr, port, tcpwrap_service); } -pa_socket_server* pa_socket_server_new_ip_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) { - struct in6_addr ipv6; +pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) { struct in_addr ipv4; assert(m); assert(name); assert(port > 0); - if (inet_pton(AF_INET6, name, &ipv6) > 0) - return pa_socket_server_new_ipv6(m, ipv6.s6_addr, port, tcpwrap_service); - if (inet_pton(AF_INET, name, &ipv4) > 0) return pa_socket_server_new_ipv4(m, ntohl(ipv4.s_addr), port, tcpwrap_service); - pa_log_warn(__FILE__": failed to parse '%s'.", name); + return NULL; +} + +pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) { + struct in6_addr ipv6; + + assert(m); + assert(name); + assert(port > 0); + + if (inet_pton(AF_INET6, name, &ipv6) > 0) + return pa_socket_server_new_ipv6(m, ipv6.s6_addr, port, tcpwrap_service); return NULL; } diff --git a/src/polypcore/socket-server.h b/src/polypcore/socket-server.h index 3babbc14..cd3276ad 100644 --- a/src/polypcore/socket-server.h +++ b/src/polypcore/socket-server.h @@ -34,9 +34,12 @@ pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd); pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename); pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service); pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port, const char *tcpwrap_service); -pa_socket_server* pa_socket_server_new_ip_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); -pa_socket_server* pa_socket_server_new_ip_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); -pa_socket_server* pa_socket_server_new_ip_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv4_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv4_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service); void pa_socket_server_unref(pa_socket_server*s); pa_socket_server* pa_socket_server_ref(pa_socket_server *s); -- cgit From b67963cec233f9c4d8c431f560475735e813c7b7 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 7 Mar 2006 16:04:32 +0000 Subject: We've already set an initial reference count of 1 so don't count it up again. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@634 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polyp/stream.c b/src/polyp/stream.c index ab6ab408..746ea9f9 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -103,7 +103,7 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * PA_LLIST_PREPEND(pa_stream, c->streams, s); - return pa_stream_ref(s); + return s; } static void hashmap_free_func(void *p, void *userdata) { -- cgit From 528d15095dd27d401be5d138d144a9df8ba7803a Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 7 Mar 2006 18:29:27 +0000 Subject: The extra stream ref actually did some good. Re-add it, but with some more symmetry, assertions and comments. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@635 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/stream.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/polyp/stream.c b/src/polyp/stream.c index 746ea9f9..f4436ff5 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -103,6 +103,10 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * PA_LLIST_PREPEND(pa_stream, c->streams, s); + /* The context and stream will point at each other. We cannot ref count + both though since that will create a loop. */ + pa_context_ref(s->context); + return s; } @@ -111,7 +115,11 @@ static void hashmap_free_func(void *p, void *userdata) { } static void stream_free(pa_stream *s) { - assert(s); + assert(s && s->context && !s->channel_valid); + + PA_LLIST_REMOVE(pa_stream, s->context->streams, s); + + pa_context_unref(s->context); if (s->ipol_event) { assert(s->mainloop); @@ -187,7 +195,10 @@ void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { if (s->channel_valid) pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - PA_LLIST_REMOVE(pa_stream, s->context->streams, s); + s->channel = 0; + s->channel_valid = 0; + + /* We keep a ref as long as we're connected */ pa_stream_unref(s); } @@ -358,6 +369,9 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED s->channel_valid = 1; pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); + /* We add an extra ref as long as we're connected (i.e. in the dynarray) */ + pa_stream_ref(s); + if (s->interpolate) { struct timeval tv; pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); -- cgit From 3ef49701428a4ddd135e173ea9beeb6d3931f876 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 8 Mar 2006 13:00:46 +0000 Subject: We filled the volume with the wrong channel count (we used the input, not the output) causing static. Also swapped the comments since they were misplaced. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@636 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/sink-input.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/polypcore/sink-input.c b/src/polypcore/sink-input.c index f12a85e1..e1703b97 100644 --- a/src/polypcore/sink-input.c +++ b/src/polypcore/sink-input.c @@ -262,11 +262,10 @@ finish: * ourselves, or if this can be done by the sink for us */ if (do_volume_adj_here) - /* We've both the same channel map, so let's have the sink do the adjustment for us*/ - - pa_cvolume_reset(volume, i->sample_spec.channels); - else /* We had different channel maps, so we already did the adjustment */ + pa_cvolume_reset(volume, i->sink->sample_spec.channels); + else + /* We've both the same channel map, so let's have the sink do the adjustment for us*/ *volume = i->volume; } -- cgit From da90b05785903af020cec289cdf4b377999c98bb Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sat, 11 Mar 2006 21:25:35 +0000 Subject: Remember to store the struct with module info. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@637 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-protocol-stub.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index 71e17cbc..3877b1cc 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -272,6 +272,8 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; #endif + m->userdata = u; + ret = 0; finish: -- cgit From dc5b2c58ddb52ae205e7d99e504b4386404df69e Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sat, 11 Mar 2006 21:26:40 +0000 Subject: We no longer guarantee that an operation object is returned. Need to tweak some parts to handle this. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@638 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/stream.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/polyp/stream.c b/src/polyp/stream.c index f4436ff5..672c376a 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -314,7 +314,10 @@ static void ipol_callback(pa_mainloop_api *m, pa_time_event *e, PA_GCC_UNUSED co /* pa_log("requesting new ipol data"); */ if (s->state == PA_STREAM_READY && !s->ipol_requested) { - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + pa_operation *o; + o = pa_stream_get_latency_info(s, NULL, NULL); + if (o) + pa_operation_unref(o); s->ipol_requested = 1; } @@ -374,7 +377,6 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED if (s->interpolate) { struct timeval tv; - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); pa_gettimeofday(&tv); tv.tv_usec += LATENCY_IPOL_INTERVAL_USEC; /* every 100 ms */ @@ -860,6 +862,7 @@ finish: pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata) { pa_operation *o; + pa_operation *lo; pa_tagstruct *t; uint32_t tag; @@ -891,7 +894,9 @@ pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, voi pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + lo = pa_stream_get_latency_info(s, NULL, NULL); + if (lo) + pa_operation_unref(lo); return pa_operation_ref(o); } @@ -921,8 +926,12 @@ pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *use PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - if ((o = stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata))) - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + if ((o = stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata))) { + pa_operation *lo; + lo = pa_stream_get_latency_info(s, NULL, NULL); + if (lo) + pa_operation_unref(lo); + } return o; } @@ -932,8 +941,12 @@ pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *us PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); - if ((o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata))) - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + if ((o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata))) { + pa_operation *lo; + lo = pa_stream_get_latency_info(s, NULL, NULL); + if (lo) + pa_operation_unref(lo); + } return o; } @@ -943,8 +956,12 @@ pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *u PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); - if ((o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata))) - pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL)); + if ((o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata))) { + pa_operation *lo; + lo = pa_stream_get_latency_info(s, NULL, NULL); + if (lo) + pa_operation_unref(lo); + } return o; } -- cgit From 8d4af80383f40f43221e46335004b0eb82e1ea80 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 17 Mar 2006 08:16:23 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@639 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/todo b/doc/todo index c1864746..d36b194e 100644 --- a/doc/todo +++ b/doc/todo @@ -23,6 +23,7 @@ Post 0.8: - port from howl to avahi - multiline configuration statements - use scatter/gather io for sockets +- add a synchronous API (base it on xmms-polyp) Long term: - pass meta info for hearing impaired @@ -32,3 +33,4 @@ Backends for: - portaudio (semi-done) - sdl - OSS (esddsp style) +- gstreamer (needs to be updated) -- cgit From 3285403d3c56e1d7ac9361ede675979b2d28fbf6 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 31 Mar 2006 08:34:41 +0000 Subject: Large file support. Polypaudio probably doesn't need it, but it causes warnings when linking libpolyp with applications that do. So this is just to make life easier for other applications. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@640 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configure.ac b/configure.ac index a0b16573..7d7f8f73 100644 --- a/configure.ac +++ b/configure.ac @@ -36,6 +36,10 @@ if type -p stow > /dev/null && test -d /usr/local/stow ; then ac_default_prefix="/usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION}" fi +#### Large File-Support (LFS) #### + +AC_SYS_LARGEFILE + #### Checks for programs. #### # CC -- cgit From acb96c96fde93dcd87c6509e7c64b403caa44f30 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 31 Mar 2006 08:54:24 +0000 Subject: Fix some warnings caused by size_t having varying size. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@641 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-sink.c | 2 +- src/modules/module-alsa-source.c | 2 +- src/polypcore/cli-text.c | 4 ++-- src/tests/mcalign-test.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 6ace7aff..2e9459e6 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -405,7 +405,7 @@ int pa__init(pa_core *c, pa_module*m) { u->frame_size = frame_size; u->fragment_size = period_size; - pa_log_info(__FILE__": using %u fragments of size %u bytes.", periods, u->fragment_size); + pa_log_info(__FILE__": using %u fragments of size %lu bytes.", periods, (long unsigned)u->fragment_size); u->silence.memblock = pa_memblock_new(u->silence.length = u->fragment_size, c->memblock_stat); assert(u->silence.memblock); diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 3343e0b6..14b35eb8 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -396,7 +396,7 @@ int pa__init(pa_core *c, pa_module*m) { u->frame_size = frame_size; u->fragment_size = period_size; - pa_log(__FILE__": using %u fragments of size %u bytes.", periods, u->fragment_size); + pa_log(__FILE__": using %u fragments of size %lu bytes.", periods, (long unsigned)u->fragment_size); u->memchunk.memblock = NULL; u->memchunk.index = u->memchunk.length = 0; diff --git a/src/polypcore/cli-text.c b/src/polypcore/cli-text.c index 8bffd0a7..d31d09c5 100644 --- a/src/polypcore/cli-text.c +++ b/src/polypcore/cli-text.c @@ -294,7 +294,7 @@ char *pa_scache_list_to_string(pa_core *c) { "\tindex: <%u>\n" "\tsample spec: <%s>\n" "\tchannel map: <%s>\n" - "\tlength: <%u>\n" + "\tlength: <%lu>\n" "\tduration: <%0.1fs>\n" "\tvolume: <%s>\n" "\tlazy: %s\n" @@ -303,7 +303,7 @@ char *pa_scache_list_to_string(pa_core *c) { e->index, ss, cm, - e->memchunk.memblock ? e->memchunk.length : 0, + (long unsigned)(e->memchunk.memblock ? e->memchunk.length : 0), l, pa_cvolume_snprint(cv, sizeof(cv), &e->volume), e->lazy ? "yes" : "no", diff --git a/src/tests/mcalign-test.c b/src/tests/mcalign-test.c index eab5dc88..2728def2 100644 --- a/src/tests/mcalign-test.c +++ b/src/tests/mcalign-test.c @@ -67,7 +67,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { c.length = r; pa_mcalign_push(a, &c); - fprintf(stderr, "Read %d bytes\n", r); + fprintf(stderr, "Read %ld bytes\n", (long)r); c.index += r; -- cgit From ac3d11f833ca7eb4ff3a1c0cb2e2cfd82da11813 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 6 Apr 2006 20:17:27 +0000 Subject: remove some GCC warnings introduced by improperly casting to (char*) instead of (const char*) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@642 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-esound.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index 08b7c6f7..e9871178 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -297,7 +297,7 @@ static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t req } } - data = (char*)data + ESD_KEY_LEN; + data = (const char*)data + ESD_KEY_LEN; memcpy(&ekey, data, sizeof(uint32_t)); if (ekey == ESD_ENDIAN_KEY) @@ -325,11 +325,11 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t memcpy(&format, data, sizeof(int32_t)); format = MAYBE_INT32_SWAP(c->swap_byte_order, format); - data = (char*)data + sizeof(int32_t); + data = (const char*)data + sizeof(int32_t); - memcpy(&rate, (char*)data, sizeof(int32_t)); + memcpy(&rate, data, sizeof(int32_t)); rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); - data = (char*)data + sizeof(int32_t); + data = (const char*)data + sizeof(int32_t); ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); @@ -388,11 +388,11 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co memcpy(&format, data, sizeof(int32_t)); format = MAYBE_INT32_SWAP(c->swap_byte_order, format); - data = (char*)data + sizeof(int32_t); + data = (const char*)data + sizeof(int32_t); - memcpy(&rate, (char*)data, sizeof(int32_t)); + memcpy(&rate, data, sizeof(int32_t)); rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); - data = (char*)data + sizeof(int32_t); + data = (const char*)data + sizeof(int32_t); ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); @@ -633,15 +633,15 @@ static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t memcpy(&idx, data, sizeof(uint32_t)); idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; - data = (char*)data + sizeof(uint32_t); + data = (const char*)data + sizeof(uint32_t); memcpy(&lvolume, data, sizeof(uint32_t)); lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, lvolume); - data = (char*)data + sizeof(uint32_t); + data = (const char*)data + sizeof(uint32_t); memcpy(&rvolume, data, sizeof(uint32_t)); rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, rvolume); - data = (char*)data + sizeof(uint32_t); + data = (const char*)data + sizeof(uint32_t); if ((conn = pa_idxset_get_by_index(c->protocol->connections, idx))) { assert(conn->sink_input); @@ -667,11 +667,11 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ memcpy(&format, data, sizeof(int32_t)); format = MAYBE_INT32_SWAP(c->swap_byte_order, format); - data = (char*)data + sizeof(int32_t); + data = (const char*)data + sizeof(int32_t); - memcpy(&rate, (char*)data + sizeof(int32_t), sizeof(int32_t)); + memcpy(&rate, (const char*)data + sizeof(int32_t), sizeof(int32_t)); rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); - data = (char*)data + sizeof(int32_t); + data = (const char*)data + sizeof(int32_t); ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); -- cgit From 73035a82a7abde862b171daf7b4cb77a50c8e14b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 6 Apr 2006 23:28:15 +0000 Subject: * set IPV6_V6ONLY for IPv6 sockets, to avoid warning when both ipv6 and the ipv4 sockets try to bind to the same port * enable SO_REUSEADDR only on platforms that support it git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@643 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/socket-server.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/polypcore/socket-server.c b/src/polypcore/socket-server.c index baa31e68..b27816d4 100644 --- a/src/polypcore/socket-server.c +++ b/src/polypcore/socket-server.c @@ -231,8 +231,10 @@ pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address pa_fd_set_cloexec(fd, 1); - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0) +#ifdef SO_REUSEADDR + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) pa_log(__FILE__": setsockopt(): %s", strerror(errno)); +#endif pa_socket_tcp_low_delay(fd); @@ -280,8 +282,15 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad pa_fd_set_cloexec(fd, 1); - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0) - pa_log(__FILE__": setsockopt(): %s", strerror(errno)); +#ifdef IPV6_V6ONLY + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) + pa_log(__FILE__": setsockopt(IPPROTO_IPV6, IPV6_V6ONLY): %s", strerror(errno)); +#endif + +#ifdef SO_REUSEADDR + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) + pa_log(__FILE__": setsockopt(SOL_SOCKET, SO_REUSEADDR, 1): %s", strerror(errno)); +#endif pa_socket_tcp_low_delay(fd); -- cgit From e872c751e1bde9dc996d967e32c457d9c8f0f0fc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 6 Apr 2006 23:28:56 +0000 Subject: s/index/idx/, to avoid gcc warning git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@644 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index aa6b69f5..8f5e66e6 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -365,7 +365,7 @@ static void request_latency(struct userdata *u) { static void stream_get_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; - uint32_t index, owner_module, monitor_source; + uint32_t idx, owner_module, monitor_source; pa_usec_t latency; const char *name, *description, *monitor_source_name, *driver; int mute; @@ -383,7 +383,7 @@ static void stream_get_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_ return; } - if (pa_tagstruct_getu32(t, &index) < 0 || + if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_gets(t, &description) < 0 || pa_tagstruct_get_sample_spec(t, &sample_spec) < 0 || -- cgit From 1be00173c134b837ddda2eba77b2d914ce244140 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 6 Apr 2006 23:31:40 +0000 Subject: change pa_gettimeofday() to return a pointer to the struct timeval*, instead of an int git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@645 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/util.c | 32 +++++++++++++++++--------------- src/polypcore/util.h | 2 +- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/polypcore/util.c b/src/polypcore/util.c index f810b3bf..b37a25a3 100644 --- a/src/polypcore/util.c +++ b/src/polypcore/util.c @@ -418,9 +418,11 @@ char *pa_strlcpy(char *b, const char *s, size_t l) { return b; } -int pa_gettimeofday(struct timeval *tv) { +struct timeval *pa_gettimeofday(struct timeval *tv) { #ifdef HAVE_GETTIMEOFDAY - return gettimeofday(tv, NULL); + assert(tv); + + return gettimeofday(tv, NULL) < 0 ? NULL : tv; #elif defined(OS_IS_WIN32) /* * Copied from implementation by Steven Edwards (LGPL). @@ -437,18 +439,18 @@ int pa_gettimeofday(struct timeval *tv) { LARGE_INTEGER li; __int64 t; - if (tv) { - GetSystemTimeAsFileTime(&ft); - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - t = li.QuadPart; /* In 100-nanosecond intervals */ - t -= EPOCHFILETIME; /* Offset to the Epoch time */ - t /= 10; /* In microseconds */ - tv->tv_sec = (long)(t / 1000000); - tv->tv_usec = (long)(t % 1000000); - } + assert(tv); - return 0; + GetSystemTimeAsFileTime(&ft); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + t = li.QuadPart; /* In 100-nanosecond intervals */ + t -= EPOCHFILETIME; /* Offset to the Epoch time */ + t /= 10; /* In microseconds */ + tv->tv_sec = (long)(t / 1000000); + tv->tv_usec = (long)(t % 1000000); + + return tv; #else #error "Platform lacks gettimeofday() or equivalent function." #endif @@ -503,8 +505,8 @@ int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { pa_usec_t pa_timeval_age(const struct timeval *tv) { struct timeval now; assert(tv); - pa_gettimeofday(&now); - return pa_timeval_diff(&now, tv); + + return pa_timeval_diff(pa_gettimeofday(&now), tv); } /* Add the specified time inmicroseconds to the specified timeval structure */ diff --git a/src/polypcore/util.h b/src/polypcore/util.h index 424283e7..f05339c4 100644 --- a/src/polypcore/util.h +++ b/src/polypcore/util.h @@ -55,7 +55,7 @@ char *pa_get_home_dir(char *s, size_t l); const char *pa_path_get_filename(const char *p); -int pa_gettimeofday(struct timeval *tv); +struct timeval *pa_gettimeofday(struct timeval *tv); pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); pa_usec_t pa_timeval_age(const struct timeval *tv); -- cgit From dd9605ba1f29f959e5d5b0c6f80cec4dcb1574db Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 6 Apr 2006 23:52:48 +0000 Subject: * really pass the ipv6 socket server to protocol_new in case of ipv6. * create the pa_modargs object properly when using TCP * other cleanups git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@646 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-protocol-stub.c | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index 3877b1cc..2f022b99 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -179,8 +179,7 @@ int pa__init(pa_core *c, pa_module*m) { struct userdata *u = NULL; #if defined(USE_TCP_SOCKETS) - pa_socket_server *s_ipv4 = NULL; - pa_socket_server *s_ipv6 = NULL; + pa_socket_server *s_ipv4 = NULL, *s_ipv6 = NULL; int loopback = 1; uint32_t port = IPV4_PORT; const char *listen_on; @@ -193,12 +192,12 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); -#if defined(USE_TCP_SOCKETS) if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": Failed to parse module arguments"); goto finish; } +#if defined(USE_TCP_SOCKETS) if (pa_modargs_get_value_boolean(ma, "loopback", &loopback) < 0) { pa_log(__FILE__": loopback= expects a boolean argument."); goto fail; @@ -214,19 +213,17 @@ int pa__init(pa_core *c, pa_module*m) { if (listen_on) { s_ipv4 = pa_socket_server_new_ipv4_string(c->mainloop, listen_on, port, TCPWRAP_SERVICE); s_ipv6 = pa_socket_server_new_ipv6_string(c->mainloop, listen_on, port, TCPWRAP_SERVICE); - if (!s_ipv4 && !s_ipv6) - goto fail; } else if (loopback) { s_ipv4 = pa_socket_server_new_ipv4_loopback(c->mainloop, port, TCPWRAP_SERVICE); s_ipv6 = pa_socket_server_new_ipv6_loopback(c->mainloop, port, TCPWRAP_SERVICE); - if (!s_ipv4 && !s_ipv6) - goto fail; } else { s_ipv4 = pa_socket_server_new_ipv4_any(c->mainloop, port, TCPWRAP_SERVICE); s_ipv6 = pa_socket_server_new_ipv6_any(c->mainloop, port, TCPWRAP_SERVICE); - if (!s_ipv4 && !s_ipv6) - goto fail; } + + if (!s_ipv4 && !s_ipv6) + goto fail; + #else v = pa_modargs_get_value(ma, "socket", UNIX_SOCKET); assert(v); @@ -250,20 +247,16 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; #endif - u = pa_xmalloc0(sizeof(struct userdata)); + u = pa_xnew0(struct userdata, 1); #if defined(USE_TCP_SOCKETS) - if (s_ipv4) { - u->protocol_ipv4 = protocol_new(c, s_ipv4, m, ma); - if (!u->protocol_ipv4) + if (s_ipv4) + if (!(u->protocol_ipv4 = protocol_new(c, s_ipv4, m, ma))) pa_socket_server_unref(s_ipv4); - } - if (s_ipv6) { - u->protocol_ipv6 = protocol_new(c, s_ipv4, m, ma); - if (!u->protocol_ipv6) + if (s_ipv6) + if (!(u->protocol_ipv6 = protocol_new(c, s_ipv6, m, ma))) pa_socket_server_unref(s_ipv6); - } if (!u->protocol_ipv4 && !u->protocol_ipv6) goto fail; @@ -314,10 +307,10 @@ void pa__done(pa_core *c, pa_module*m) { assert(c && m); #if defined(USE_PROTOCOL_ESOUND) && !defined(USE_TCP_SOCKETS) - if (remove(ESD_UNIX_SOCKET_NAME) != 0) - pa_log("%s: Failed to remove %s : %s.", __FILE__, ESD_UNIX_SOCKET_NAME, strerror (errno)); - if (remove(ESD_UNIX_SOCKET_DIR) != 0) - pa_log("%s: Failed to remove %s : %s.", __FILE__, ESD_UNIX_SOCKET_DIR, strerror (errno)); + if (remove(ESD_UNIX_SOCKET_NAME) != 0) + pa_log("%s: Failed to remove %s : %s.", __FILE__, ESD_UNIX_SOCKET_NAME, strerror (errno)); + if (remove(ESD_UNIX_SOCKET_DIR) != 0) + pa_log("%s: Failed to remove %s : %s.", __FILE__, ESD_UNIX_SOCKET_DIR, strerror (errno)); #endif u = m->userdata; -- cgit From cc302f2d17b172bec60b25d549a77b1cb3d17d99 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Apr 2006 00:23:38 +0000 Subject: remove queue length field from latency request (server side) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@647 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-native.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 68dc6366..763873c2 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -1064,10 +1064,8 @@ static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_tagstruct_put_usec(reply, pa_sink_get_latency(s->sink_input->sink)); pa_tagstruct_put_usec(reply, 0); pa_tagstruct_put_boolean(reply, pa_memblockq_is_readable(s->memblockq)); - pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq)); pa_tagstruct_put_timeval(reply, &tv); - pa_gettimeofday(&now); - pa_tagstruct_put_timeval(reply, &now); + pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now)); pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq)); pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq)); pa_pstream_send_tagstruct(c->pstream, reply); @@ -1097,10 +1095,8 @@ static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN pa_tagstruct_put_usec(reply, s->source_output->source->monitor_of ? pa_sink_get_latency(s->source_output->source->monitor_of) : 0); pa_tagstruct_put_usec(reply, pa_source_get_latency(s->source_output->source)); pa_tagstruct_put_boolean(reply, 0); - pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq)); pa_tagstruct_put_timeval(reply, &tv); - pa_gettimeofday(&now); - pa_tagstruct_put_timeval(reply, &now); + pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now)); pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq)); pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq)); pa_pstream_send_tagstruct(c->pstream, reply); -- cgit From 920f045380d70785d6ca483d901610d70daee361 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Apr 2006 00:24:48 +0000 Subject: rework latency querying API (this needs more testing) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@648 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/def.h | 44 ++++-- src/polyp/internal.h | 44 ++++-- src/polyp/stream.c | 425 +++++++++++++++++++++++++++++++-------------------- src/polyp/stream.h | 30 +--- 4 files changed, 323 insertions(+), 220 deletions(-) diff --git a/src/polyp/def.h b/src/polyp/def.h index 98420bc0..93d0996b 100644 --- a/src/polyp/def.h +++ b/src/polyp/def.h @@ -80,7 +80,7 @@ typedef enum pa_stream_direction { /** Some special flags for stream connections. \since 0.6 */ typedef enum pa_stream_flags { PA_STREAM_START_CORKED = 1, /**< Create the stream corked, requiring an explicit pa_stream_cork() call to uncork it. */ - PA_STREAM_INTERPOLATE_LATENCY = 2 /**< Interpolate the latency for + PA_STREAM_INTERPOLATE_LATENCY = 2, /**< Interpolate the latency for * this stream. When enabled, * you can use * pa_stream_interpolated_xxx() @@ -95,6 +95,7 @@ typedef enum pa_stream_flags { * information. This is * especially useful on long latency * network connections. */ + PA_STREAM_NOT_MONOTONOUS = 4, /**< Don't force the time to run monotonically */ } pa_stream_flags_t; /** Playback and record buffer metrics */ @@ -124,7 +125,7 @@ enum { PA_ERR_INVALIDSERVER, /**< Invalid server */ PA_ERR_MODINITFAILED, /**< Module initialization failed */ PA_ERR_BADSTATE, /**< Bad state */ - PA_ERR_NODATA, /**< No data */ + PA_ERR_NODATA, /**< No data */ PA_ERR_VERSION, /**< Incompatible protocol version \since 0.8 */ PA_ERR_MAX /**< Not really an error but the first invalid error code */ }; @@ -171,7 +172,7 @@ typedef enum pa_subscription_event_type { * pa_stream_write() takes to be played may be estimated by * sink_usec+buffer_usec+transport_usec. The output buffer to which * buffer_usec relates may be manipulated freely (with - * pa_stream_write()'s delta argument, pa_stream_flush() and friends), + * pa_stream_write()'s seek argument, pa_stream_flush() and friends), * the buffers sink_usec/source_usec relates to is a first-in * first-out buffer which cannot be flushed or manipulated in any * way. The total input latency a sample that is recorded takes to be @@ -180,12 +181,7 @@ typedef enum pa_subscription_event_type { * sign issues!) When connected to a monitor source sink_usec contains * the latency of the owning sink.*/ typedef struct pa_latency_info { - pa_usec_t buffer_usec; /**< Time in usecs the current buffer takes to play. For both playback and record streams. */ - pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. For playback streams and record streams connected to a monitor source. */ - pa_usec_t source_usec; /**< Time in usecs a sample takes from being recorded to being delivered to the application. Only for record streams. \since 0.5*/ - pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to/from the daemon. For both playback and record streams. \since 0.5 */ - int playing; /**< Non-zero when the stream is currently playing. Only for playback streams. */ - uint32_t queue_length; /**< Queue size in bytes. For both playback and record streams. */ + struct timeval timestamp; /**< The time when this latency info was current */ int synchronized_clocks; /**< Non-zero if the local and the * remote machine have synchronized * clocks. If synchronized clocks are @@ -194,10 +190,31 @@ typedef struct pa_latency_info { * detects synchronized clocks is very * limited und unreliable itself. \since * 0.5 */ - struct timeval timestamp; /**< The time when this latency info was current */ - uint64_t counter; /**< The byte counter current when the latency info was requested. \since 0.6 */ - int64_t write_index; /**< Current absolute write index in the buffer. \since 0.8 */ - int64_t read_index; /**< Current absolute read index in the buffer. \since 0.8 */ + + pa_usec_t buffer_usec; /**< Time in usecs the current buffer takes to play. For both playback and record streams. */ + pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. For playback streams and record streams connected to a monitor source. */ + pa_usec_t source_usec; /**< Time in usecs a sample takes from being recorded to being delivered to the application. Only for record streams. \since 0.5*/ + pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to/from the daemon. For both playback and record streams. \since 0.5 */ + + int playing; /**< Non-zero when the stream is currently playing. Only for playback streams. */ + + int write_index_corrupt; /**< Non-Zero if the write_index is not up to date because a local write command corrupted it */ + int64_t write_index; /**< Current write index into the + * playback buffer in bytes. Think twice before + * using this for seeking purposes: it + * might be out of date a the time you + * want to use it. Consider using + * PA_SEEK_RELATIVE instead. \since + * 0.8 */ + int64_t read_index; /**< Current read index into the + * playback buffer in bytes. Think twice before + * using this for seeking purposes: it + * might be out of date a the time you + * want to use it. Consider using + * PA_SEEK_RELATIVE_ON_READ + * instead. \since 0.8 */ + + uint32_t buffer_length; /* Current buffer length. This is usually identical to write_index-read_index. */ } pa_latency_info; /** A structure for the spawn api. This may be used to integrate auto @@ -227,7 +244,6 @@ typedef enum pa_seek_mode { PA_SEEK_RELATIVE_END = 3, /**< Seek relatively to the current end of the buffer queue */ } pa_seek_mode_t; - PA_C_DECL_END #endif diff --git a/src/polyp/internal.h b/src/polyp/internal.h index 82d8f7ce..8f1603b3 100644 --- a/src/polyp/internal.h +++ b/src/polyp/internal.h @@ -83,6 +83,15 @@ struct pa_context { pa_client_conf *conf; }; +#define PA_MAX_LATENCY_CORRECTIONS 10 + +typedef struct pa_latency_correction { + uint32_t tag; + int valid; + int64_t value; + int absolute, corrupt; +} pa_latency_correction; + struct pa_stream { int ref; pa_context *context; @@ -93,41 +102,48 @@ struct pa_stream { pa_buffer_attr buffer_attr; pa_sample_spec sample_spec; pa_channel_map channel_map; + pa_stream_flags_t flags; uint32_t channel; uint32_t syncid; int channel_valid; uint32_t device_index; pa_stream_direction_t direction; - uint32_t requested_bytes; - uint64_t counter; - pa_usec_t previous_time; - pa_usec_t previous_ipol_time; pa_stream_state_t state; + + uint32_t requested_bytes; + pa_memchunk peek_memchunk; pa_memblockq *record_memblockq; - pa_hashmap *counter_hashmap; - - int interpolate; int corked; - uint32_t ipol_usec; - struct timeval ipol_timestamp; + /* Store latest latency info */ + pa_latency_info latency_info; + int latency_info_valid; + + /* Use to make sure that time advances monotonically */ + pa_usec_t previous_time; + + /* Latency correction stuff */ + pa_latency_correction latency_corrections[PA_MAX_LATENCY_CORRECTIONS]; + int idx_latency_correction; + + /* Latency interpolation stuff */ pa_time_event *ipol_event; int ipol_requested; - + pa_usec_t ipol_usec; + int ipol_usec_valid; + struct timeval ipol_timestamp; + + /* Callbacks */ pa_stream_notify_cb_t state_callback; void *state_userdata; - pa_stream_request_cb_t read_callback; void *read_userdata; - pa_stream_request_cb_t write_callback; void *write_userdata; - pa_stream_notify_cb_t overflow_callback; void *overflow_userdata; - pa_stream_notify_cb_t underflow_callback; void *underflow_userdata; }; diff --git a/src/polyp/stream.c b/src/polyp/stream.c index 672c376a..d3599582 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -38,10 +38,10 @@ #include "internal.h" #define LATENCY_IPOL_INTERVAL_USEC (10000L) -#define COUNTER_HASHMAP_MAXSIZE (5) pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map) { pa_stream *s; + int i; assert(c); @@ -67,6 +67,7 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->direction = PA_STREAM_NODIRECTION; s->name = pa_xstrdup(name); s->sample_spec = *ss; + s->flags = 0; if (map) s->channel_map = *map; @@ -87,20 +88,21 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->record_memblockq = NULL; - s->counter_hashmap = pa_hashmap_new(NULL, NULL); - - s->counter = 0; s->previous_time = 0; - s->previous_ipol_time = 0; + s->latency_info_valid = 0; s->corked = 0; - s->interpolate = 0; - s->ipol_usec = 0; - memset(&s->ipol_timestamp, 0, sizeof(s->ipol_timestamp)); + s->ipol_usec_valid = 0; + s->ipol_timestamp.tv_sec = 0; + s->ipol_timestamp.tv_usec = 0; s->ipol_event = NULL; s->ipol_requested = 0; + for (i = 0; i < PA_MAX_LATENCY_CORRECTIONS; i++) + s->latency_corrections[i].valid = 0; + s->idx_latency_correction = 0; + PA_LLIST_PREPEND(pa_stream, c->streams, s); /* The context and stream will point at each other. We cannot ref count @@ -110,10 +112,6 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * return s; } -static void hashmap_free_func(void *p, void *userdata) { - pa_xfree(p); -} - static void stream_free(pa_stream *s) { assert(s && s->context && !s->channel_valid); @@ -132,9 +130,6 @@ static void stream_free(pa_stream *s) { if (s->record_memblockq) pa_memblockq_free(s->record_memblockq); - if (s->counter_hashmap) - pa_hashmap_free(s->counter_hashmap, hashmap_free_func, NULL); - pa_xfree(s->name); pa_xfree(s); } @@ -315,10 +310,11 @@ static void ipol_callback(pa_mainloop_api *m, pa_time_event *e, PA_GCC_UNUSED co if (s->state == PA_STREAM_READY && !s->ipol_requested) { pa_operation *o; - o = pa_stream_get_latency_info(s, NULL, NULL); - if (o) + + if ((o = pa_stream_update_latency_info(s, NULL, NULL))) { pa_operation_unref(o); - s->ipol_requested = 1; + s->ipol_requested = 1; + } } pa_gettimeofday(&next); @@ -375,7 +371,7 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED /* We add an extra ref as long as we're connected (i.e. in the dynarray) */ pa_stream_ref(s); - if (s->interpolate) { + if (s->flags & PA_STREAM_INTERPOLATE_LATENCY) { struct timeval tv; pa_gettimeofday(&tv); @@ -418,13 +414,11 @@ static int create_stream( pa_stream_ref(s); s->direction = direction; + s->flags = flags; if (sync_stream) s->syncid = sync_stream->syncid; - s->interpolate = !!(flags & PA_STREAM_INTERPOLATE_LATENCY); - pa_stream_trash_ipol(s); - if (attr) s->buffer_attr = *attr; else { @@ -548,7 +542,33 @@ int pa_stream_write( else s->requested_bytes = 0; - s->counter += length; + /* Update latency request correction */ + if (s->latency_corrections[s->idx_latency_correction].valid) { + + if (seek == PA_SEEK_ABSOLUTE) { + s->latency_corrections[s->idx_latency_correction].corrupt = 0; + s->latency_corrections[s->idx_latency_correction].absolute = 1; + s->latency_corrections[s->idx_latency_correction].value = offset + length; + } else if (seek == PA_SEEK_RELATIVE) { + if (!s->latency_corrections[s->idx_latency_correction].corrupt) + s->latency_corrections[s->idx_latency_correction].value += offset + length; + } else + s->latency_corrections[s->idx_latency_correction].corrupt = 1; + } + + /* Update the write index in the already available latency data */ + if (s->latency_info_valid) { + + if (seek == PA_SEEK_ABSOLUTE) { + s->latency_info.write_index_corrupt = 0; + s->latency_info.write_index = offset + length; + } else if (seek == PA_SEEK_RELATIVE) { + if (!s->latency_info.write_index_corrupt) + s->latency_info.write_index += offset + length; + } else + s->latency_info.write_index_corrupt = 1; + } + return 0; } @@ -590,7 +610,6 @@ int pa_stream_drop(pa_stream *s) { s->peek_memchunk.index = 0; s->peek_memchunk.memblock = NULL; - s->counter += s->peek_memchunk.length; return 0; } @@ -637,33 +656,34 @@ pa_operation * pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *us static void stream_get_latency_info_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; - pa_latency_info i, *p = NULL; struct timeval local, remote, now; + pa_latency_info *i; assert(pd); assert(o); assert(o->stream); assert(o->context); - i.counter = *(uint64_t*)pa_hashmap_get(o->stream->counter_hashmap, (void*)(unsigned long)tag); - pa_xfree(pa_hashmap_remove(o->stream->counter_hashmap, (void*)(unsigned long)tag)); + i = &o->stream->latency_info; + o->stream->latency_info_valid = 0; + i->write_index_corrupt = 0; if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; - } else if (pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || - pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || - pa_tagstruct_get_usec(t, &i.source_usec) < 0 || - pa_tagstruct_get_boolean(t, &i.playing) < 0 || - pa_tagstruct_getu32(t, &i.queue_length) < 0 || + } else if (pa_tagstruct_get_usec(t, &i->buffer_usec) < 0 || + pa_tagstruct_get_usec(t, &i->sink_usec) < 0 || + pa_tagstruct_get_usec(t, &i->source_usec) < 0 || + pa_tagstruct_get_boolean(t, &i->playing) < 0 || pa_tagstruct_get_timeval(t, &local) < 0 || pa_tagstruct_get_timeval(t, &remote) < 0 || - pa_tagstruct_gets64(t, &i.write_index) < 0 || - pa_tagstruct_gets64(t, &i.read_index) < 0 || + pa_tagstruct_gets64(t, &i->write_index) < 0 || + pa_tagstruct_gets64(t, &i->read_index) < 0 || !pa_tagstruct_eof(t)) { pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; + } else { pa_gettimeofday(&now); @@ -671,72 +691,125 @@ static void stream_get_latency_info_callback(pa_pdispatch *pd, uint32_t command, /* local and remote seem to have synchronized clocks */ if (o->stream->direction == PA_STREAM_PLAYBACK) - i.transport_usec = pa_timeval_diff(&remote, &local); + i->transport_usec = pa_timeval_diff(&remote, &local); else - i.transport_usec = pa_timeval_diff(&now, &remote); + i->transport_usec = pa_timeval_diff(&now, &remote); - i.synchronized_clocks = 1; - i.timestamp = remote; + i->synchronized_clocks = 1; + i->timestamp = remote; } else { /* clocks are not synchronized, let's estimate latency then */ - i.transport_usec = pa_timeval_diff(&now, &local)/2; - i.synchronized_clocks = 0; - i.timestamp = local; - pa_timeval_add(&i.timestamp, i.transport_usec); + i->transport_usec = pa_timeval_diff(&now, &local)/2; + i->synchronized_clocks = 0; + i->timestamp = local; + pa_timeval_add(&i->timestamp, i->transport_usec); } - - if (o->stream->interpolate) { -/* pa_log("new interpol data"); */ - o->stream->ipol_timestamp = i.timestamp; - o->stream->ipol_usec = pa_stream_get_time(o->stream, &i); - o->stream->ipol_requested = 0; + + if (o->stream->direction == PA_STREAM_PLAYBACK) { + /* Write index correction */ + + int n, j; + uint32_t ctag = tag; + + /* Go through the saved correction values and add up the total correction.*/ + + for (n = 0, j = o->stream->idx_latency_correction; + n < PA_MAX_LATENCY_CORRECTIONS; + n++, j = (j + 1) % PA_MAX_LATENCY_CORRECTIONS) { + + /* Step over invalid data or out-of-date data */ + if (!o->stream->latency_corrections[j].valid || + o->stream->latency_corrections[j].tag < ctag) + continue; + + /* Make sure that everything is in order */ + ctag = o->stream->latency_corrections[j].tag+1; + + /* Now fix the write index */ + if (o->stream->latency_corrections[j].corrupt) { + /* A corrupting seek was made */ + i->write_index = 0; + i->write_index_corrupt = 1; + } else if (o->stream->latency_corrections[j].absolute) { + /* An absolute seek was made */ + i->write_index = o->stream->latency_corrections[j].value; + i->write_index_corrupt = 0; + } else if (!i->write_index_corrupt) { + /* A relative seek was made */ + i->write_index += o->stream->latency_corrections[j].value; + } + } } + + o->stream->latency_info_valid = 1; + + o->stream->ipol_timestamp = now; + o->stream->ipol_usec_valid = 0; + } - p = &i; + /* Clear old correction entries */ + if (o->stream->direction == PA_STREAM_PLAYBACK) { + int n; + + for (n = 0; n < PA_MAX_LATENCY_CORRECTIONS; n++) { + if (!o->stream->latency_corrections[n].valid) + continue; + + if (o->stream->latency_corrections[n].tag <= tag) + o->stream->latency_corrections[n].valid = 0; + } } if (o->callback) { - pa_stream_get_latency_info_cb_t cb = (pa_stream_get_latency_info_cb_t) o->callback; - cb(o->stream, p, o->userdata); + pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback; + cb(o->stream, o->stream->latency_info_valid, o->userdata); } - + finish: + pa_operation_done(o); pa_operation_unref(o); } -pa_operation* pa_stream_get_latency_info(pa_stream *s, pa_stream_get_latency_info_cb_t cb, void *userdata) { +pa_operation* pa_stream_update_latency_info(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { uint32_t tag; pa_operation *o; pa_tagstruct *t; struct timeval now; - uint64_t *counter; + int cidx; assert(s); assert(s->ref >= 1); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, pa_hashmap_size(s->counter_hashmap) < COUNTER_HASHMAP_MAXSIZE, PA_ERR_INTERNAL); + + /* Find a place to store the write_index correction data for this entry */ + cidx = (s->idx_latency_correction + 1) % PA_MAX_LATENCY_CORRECTIONS; + + /* Check if we could allocate a correction slot. If not, there are too many outstanding queries */ + PA_CHECK_VALIDITY_RETURN_NULL(s->context, !s->latency_corrections[cidx].valid, PA_ERR_INTERNAL); o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); - + t = pa_tagstruct_command( s->context, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_GET_PLAYBACK_LATENCY : PA_COMMAND_GET_RECORD_LATENCY, &tag); pa_tagstruct_putu32(t, s->channel); - - pa_gettimeofday(&now); - pa_tagstruct_put_timeval(t, &now); + pa_tagstruct_put_timeval(t, pa_gettimeofday(&now)); pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_info_callback, o); - counter = pa_xmalloc(sizeof(uint64_t)); - *counter = s->counter; - pa_hashmap_put(s->counter_hashmap, (void*)(unsigned long)tag, counter); - + /* Fill in initial correction data */ + o->stream->idx_latency_correction = cidx; + o->stream->latency_corrections[cidx].valid = 1; + o->stream->latency_corrections[cidx].tag = tag; + o->stream->latency_corrections[cidx].absolute = 0; + o->stream->latency_corrections[cidx].value = 0; + o->stream->latency_corrections[cidx].corrupt = 0; + return pa_operation_ref(o); } @@ -872,11 +945,11 @@ pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, voi PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - if (s->interpolate) { - if (!s->corked && b) - /* Pausing */ - s->ipol_usec = pa_stream_get_interpolated_time(s); - else if (s->corked && !b) + if (s->flags & PA_STREAM_INTERPOLATE_LATENCY) { + if (!s->corked && b) { + /* Refresh the interpolated data just befor pausing */ + pa_stream_get_time(s, NULL); + } else if (s->corked && !b) /* Unpausing */ pa_gettimeofday(&s->ipol_timestamp); } @@ -894,8 +967,7 @@ pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, voi pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); - lo = pa_stream_get_latency_info(s, NULL, NULL); - if (lo) + if ((lo = pa_stream_update_latency_info(s, NULL, NULL))) pa_operation_unref(lo); return pa_operation_ref(o); @@ -928,8 +1000,8 @@ pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *use if ((o = stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata))) { pa_operation *lo; - lo = pa_stream_get_latency_info(s, NULL, NULL); - if (lo) + + if ((lo = pa_stream_update_latency_info(s, NULL, NULL))) pa_operation_unref(lo); } @@ -943,8 +1015,8 @@ pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *us if ((o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata))) { pa_operation *lo; - lo = pa_stream_get_latency_info(s, NULL, NULL); - if (lo) + + if ((lo = pa_stream_update_latency_info(s, NULL, NULL))) pa_operation_unref(lo); } @@ -958,8 +1030,8 @@ pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *u if ((o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata))) { pa_operation *lo; - lo = pa_stream_get_latency_info(s, NULL, NULL); - if (lo) + + if ((lo = pa_stream_update_latency_info(s, NULL, NULL))) pa_operation_unref(lo); } @@ -992,150 +1064,165 @@ pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_succe return pa_operation_ref(o); } -uint64_t pa_stream_get_counter(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (uint64_t) -1); - - return s->counter; -} - -pa_usec_t pa_stream_get_time(pa_stream *s, const pa_latency_info *i) { - pa_usec_t usec; +int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) { + pa_usec_t usec = 0; assert(s); assert(s->ref >= 1); - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (pa_usec_t) -1); - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE, (pa_usec_t) -1); - - usec = pa_bytes_to_usec(i->counter, &s->sample_spec); + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->latency_info_valid, PA_ERR_NODATA); - if (i) { + if (s->flags & PA_STREAM_INTERPOLATE_LATENCY && s->ipol_usec_valid ) + usec = s->ipol_usec; + else { if (s->direction == PA_STREAM_PLAYBACK) { - pa_usec_t latency = i->transport_usec + i->buffer_usec + i->sink_usec; - if (usec < latency) + /* The last byte that was written into the output device + * had this time value associated */ + usec = pa_bytes_to_usec(s->latency_info.read_index < 0 ? 0 : (uint64_t) s->latency_info.read_index, &s->sample_spec); + + /* Because the latency info took a little time to come + * to us, we assume that the real output time is actually + * a little ahead */ + usec += s->latency_info.transport_usec; + + /* However, the output device usually maintains a buffer + too, hence the real sample currently played is a little + back */ + if (s->latency_info.sink_usec >= usec) usec = 0; else - usec -= latency; - + usec -= s->latency_info.sink_usec; + } else if (s->direction == PA_STREAM_RECORD) { - usec += i->source_usec + i->buffer_usec + i->transport_usec; - - if (usec > i->sink_usec) - usec -= i->sink_usec; - else + /* The last byte written into the server side queue had + * this time value associated */ + usec = pa_bytes_to_usec(s->latency_info.write_index < 0 ? 0 : (uint64_t) s->latency_info.write_index, &s->sample_spec); + + /* Add transport latency */ + usec += s->latency_info.transport_usec; + + /* Add latency of data in device buffer */ + usec += s->latency_info.source_usec; + + /* If this is a monitor source, we need to correct the + * time by the playback device buffer */ + if (s->latency_info.sink_usec >= usec) usec = 0; + else + usec -= s->latency_info.sink_usec; + } + + if (s->flags & PA_STREAM_INTERPOLATE_LATENCY) { + s->ipol_usec_valid = 1; + s->ipol_usec = usec; } } - if (usec < s->previous_time) - usec = s->previous_time; + /* Interpolate if requested */ + if (s->flags & PA_STREAM_INTERPOLATE_LATENCY) { - s->previous_time = usec; + /* We just add the time that passed since the latency info was + * current */ + if (!s->corked) { + struct timeval now; + + usec += pa_timeval_diff(pa_gettimeofday(&now), &s->ipol_timestamp); + s->ipol_timestamp = now; + } + } - return usec; + /* Make sure the time runs monotonically */ + if (!(s->flags & PA_STREAM_NOT_MONOTONOUS)) { + if (usec < s->previous_time) + usec = s->previous_time; + else + s->previous_time = usec; + } + + if (r_usec) + *r_usec = usec; + + return 0; } -static pa_usec_t time_counter_diff(pa_stream *s, pa_usec_t t, pa_usec_t c, int *negative) { +static pa_usec_t time_counter_diff(pa_stream *s, pa_usec_t a, pa_usec_t b, int *negative) { assert(s); assert(s->ref >= 1); if (negative) *negative = 0; - if (c < t) { - if (s->direction == PA_STREAM_RECORD) { - if (negative) - *negative = 1; - - return t-c; + if (a >= b) + return a-b; + else { + if (negative && s->direction == PA_STREAM_RECORD) { + *negative = 1; + return b-a; } else return 0; - } else - return c-t; + } } -pa_usec_t pa_stream_get_latency(pa_stream *s, const pa_latency_info *i, int *negative) { +int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative) { pa_usec_t t, c; + int r; + int64_t cindex; assert(s); assert(s->ref >= 1); - assert(i); + assert(r_usec); - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (pa_usec_t) -1); - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE, (pa_usec_t) -1); + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->latency_info_valid, PA_ERR_NODATA); + PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_PLAYBACK || !s->latency_info.write_index_corrupt, PA_ERR_NODATA); - t = pa_stream_get_time(s, i); - c = pa_bytes_to_usec(s->counter, &s->sample_spec); - - return time_counter_diff(s, t, c, negative); -} + if ((r = pa_stream_get_time(s, &t)) < 0) + return r; -const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) { - assert(s); - assert(s->ref >= 1); + if (s->direction == PA_STREAM_PLAYBACK) + cindex = s->latency_info.write_index; + else + cindex = s->latency_info.read_index; - return &s->sample_spec; -} + if (cindex < 0) + cindex = 0; + + c = pa_bytes_to_usec(cindex, &s->sample_spec); -const pa_channel_map* pa_stream_get_channel_map(pa_stream *s) { - assert(s); - assert(s->ref >= 1); + if (s->direction == PA_STREAM_PLAYBACK) + *r_usec = time_counter_diff(s, c, t, negative); + else + *r_usec = time_counter_diff(s, t, c, negative); - return &s->channel_map; + return 0; } -void pa_stream_trash_ipol(pa_stream *s) { +const pa_latency_info* pa_stream_get_latency_info(pa_stream *s) { assert(s); assert(s->ref >= 1); - if (!s->interpolate) - return; + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->latency_info_valid, PA_ERR_BADSTATE); - memset(&s->ipol_timestamp, 0, sizeof(s->ipol_timestamp)); - s->ipol_usec = 0; + return &s->latency_info; } -pa_usec_t pa_stream_get_interpolated_time(pa_stream *s) { - pa_usec_t usec; - +const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) { assert(s); assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (pa_usec_t) -1); - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE, (pa_usec_t) -1); - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->interpolate, PA_ERR_BADSTATE, (pa_usec_t) -1); - - if (s->corked) - usec = s->ipol_usec; - else { - if (s->ipol_timestamp.tv_sec == 0) - usec = 0; - else - usec = s->ipol_usec + pa_timeval_age(&s->ipol_timestamp); - } - - if (usec < s->previous_ipol_time) - usec = s->previous_ipol_time; - - s->previous_ipol_time = usec; - return usec; + return &s->sample_spec; } -pa_usec_t pa_stream_get_interpolated_latency(pa_stream *s, int *negative) { - pa_usec_t t, c; - +const pa_channel_map* pa_stream_get_channel_map(pa_stream *s) { assert(s); assert(s->ref >= 1); - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (pa_usec_t) -1); - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE, (pa_usec_t) -1); - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->interpolate, PA_ERR_BADSTATE, (pa_usec_t) -1); - - t = pa_stream_get_interpolated_time(s); - c = pa_bytes_to_usec(s->counter, &s->sample_spec); - return time_counter_diff(s, t, c, negative); + return &s->channel_map; } + + diff --git a/src/polyp/stream.h b/src/polyp/stream.h index 75b0a900..99284ba3 100644 --- a/src/polyp/stream.h +++ b/src/polyp/stream.h @@ -51,9 +51,6 @@ typedef void (*pa_stream_request_cb_t)(pa_stream *p, size_t length, void *userda /** A generic notification callback */ typedef void (*pa_stream_notify_cb_t)(pa_stream *p, void *userdata); -/** Callback prototype for pa_stream_get_latency_info() */ -typedef void (*pa_stream_get_latency_info_cb_t)(pa_stream *p, const pa_latency_info *i, void *userdata); - /** Create a new, unconnected stream with the specified name and sample type */ pa_stream* pa_stream_new( pa_context *c /**< The context to create this stream in */, @@ -133,8 +130,8 @@ size_t pa_stream_readable_size(pa_stream *p); /** Drain a playback stream. Use this for notification when the buffer is empty */ pa_operation* pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); -/** Get the playback latency of a stream */ -pa_operation* pa_stream_get_latency_info(pa_stream *p, pa_stream_get_latency_info_cb_t cby, void *userdata); +/** Update the latency info of a stream */ +pa_operation* pa_stream_update_latency_info(pa_stream *p, pa_stream_success_cb_t cb, void *userdata); /** Set the callback function that is called whenever the state of the stream changes */ void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata); @@ -173,34 +170,21 @@ pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *u /** Rename the stream. \since 0.5 */ pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata); -/** Return the total number of bytes written to/read from the - * stream. This counter is not reset on pa_stream_flush(), you may do - * this yourself using pa_stream_reset_counter(). \since 0.6 */ -uint64_t pa_stream_get_counter(pa_stream *s); - /** Return the current playback/recording time. This is based on the * counter accessible with pa_stream_get_counter(). This function * requires a pa_latency_info structure as argument, which should be * acquired using pa_stream_get_latency(). \since 0.6 */ -pa_usec_t pa_stream_get_time(pa_stream *s, const pa_latency_info *i); +int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec); /** Return the total stream latency. Thus function requires a * pa_latency_info structure as argument, which should be aquired * using pa_stream_get_latency(). In case the stream is a monitoring * stream the result can be negative, i.e. the captured samples are * not yet played. In this case *negative is set to 1. \since 0.6 */ -pa_usec_t pa_stream_get_latency(pa_stream *s, const pa_latency_info *i, int *negative); - -/** Return the interpolated playback/recording time. Requires the - * PA_STREAM_INTERPOLATE_LATENCY bit set when creating the stream. In - * contrast to pa_stream_get_latency() this function doesn't require - * a whole roundtrip for response. \since 0.6 */ -pa_usec_t pa_stream_get_interpolated_time(pa_stream *s); - -/** Return the interpolated playback/recording latency. Requires the - * PA_STREAM_INTERPOLATE_LATENCY bit set when creating the - * stream. \since 0.6 */ -pa_usec_t pa_stream_get_interpolated_latency(pa_stream *s, int *negative); +int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative); + +/** Return the latest latency data. \since 0.8 */ +const pa_latency_info* pa_stream_get_latency_info(pa_stream *s); /** Return a pointer to the stream's sample specification. \since 0.6 */ const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s); -- cgit From 53a0056cdf3467cc98740e61b781935ef0ed5ac4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Apr 2006 00:25:05 +0000 Subject: update pacat.c for new latency API git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@649 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pacat.c | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 43e67144..8d9cff0b 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -339,28 +340,34 @@ static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, } /* Show the current latency */ -static void stream_get_latency_callback(pa_stream *s, const pa_latency_info *i, void *userdata) { +static void stream_update_latency_callback(pa_stream *s, int success, void *userdata) { pa_usec_t total; int negative = 0; + const pa_latency_info *i; + assert(s); - if (!i) { + if (!success || + !(i = pa_stream_get_latency_info(s)) || + pa_stream_get_latency(s, &total, &negative) < 0) { fprintf(stderr, "Failed to get latency: %s\n", pa_strerror(pa_context_errno(context))); quit(1); return; } - total = pa_stream_get_latency(s, i, &negative); - fprintf(stderr, "Latency: buffer: %0.0f usec; sink: %0.0f usec; source: %0.0f usec; transport: %0.0f usec; total: %0.0f usec; synchronized clocks: %s.\n", - (float) i->buffer_usec, (float) i->sink_usec, (float) i->source_usec, (float) i->transport_usec, (float) total * (negative?-1:1), + (float) i->buffer_usec, + (float) i->sink_usec, + (float) i->source_usec, + (float) i->transport_usec, + (float) total * (negative?-1:1), i->synchronized_clocks ? "yes" : "no"); } /* Someone requested that the latency is shown */ static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { fprintf(stderr, "Got SIGUSR1, requesting latency.\n"); - pa_operation_unref(pa_stream_get_latency_info(stream, stream_get_latency_callback, NULL)); + pa_operation_unref(pa_stream_update_latency_info(stream, stream_update_latency_callback, NULL)); } @@ -511,6 +518,27 @@ int main(int argc, char *argv[]) { fprintf(stderr, "Opening a %s stream with sample specification '%s'.\n", mode == RECORD ? "recording" : "playback", t); } + if (optind+1 < argc) { + fprintf(stderr, "Too many arguments.\n"); + goto quit; + } + + if (optind+1 == argc) { + int fd; + + if ((fd = open(argv[optind], O_RDONLY)) < 0) { + fprintf(stderr, "open(): %s\n", strerror(errno)); + goto quit; + } + + if (dup2(fd, 0) < 0) { + fprintf(stderr, "dup2(): %s\n", strerror(errno)); + goto quit; + } + + close(fd); + } + /* Set up a new main loop */ if (!(m = pa_mainloop_new())) { fprintf(stderr, "pa_mainloop_new() failed.\n"); -- cgit From c0592bb27c28b7b7902a6b780daf89344bc3516d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Apr 2006 00:25:19 +0000 Subject: update simple API for new latency API git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@650 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/simple.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/polyp/simple.c b/src/polyp/simple.c index eabcf1ea..2593d5fa 100644 --- a/src/polyp/simple.c +++ b/src/polyp/simple.c @@ -345,18 +345,19 @@ int pa_simple_drain(pa_simple *p, int *rerror) { return p->dead ? -1 : 0; } -static void latency_complete(pa_stream *s, const pa_latency_info *l, void *userdata) { +static void latency_complete(pa_stream *s, int success, void *userdata) { pa_simple *p = userdata; assert(s); assert(p); - if (!l) + if (!success) p->dead = 1; else { int negative = 0; - p->latency = pa_stream_get_latency(s, l, &negative); - if (negative) + if (pa_stream_get_latency(s, &p->latency, &negative) < 0) + p->dead = 1; + else if (negative) p->latency = 0; } } @@ -376,7 +377,7 @@ pa_usec_t pa_simple_get_playback_latency(pa_simple *p, int *rerror) { } p->latency = 0; - if (!(o = pa_stream_get_latency_info(p->stream, latency_complete, p))) { + if (!(o = pa_stream_update_latency_info(p->stream, latency_complete, p))) { if (rerror) *rerror = pa_context_errno(p->context); return (pa_usec_t) -1; -- cgit From b8a729a00f170241599e670ee3f3f65457b4320f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Apr 2006 01:29:33 +0000 Subject: * update docs for reworked latency API * rename pa_latency_info to pa_timing_info, since that describes better what it is. Most people will only use pa_stream_get_time() anyway git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@651 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/def.h | 85 ++++++++++++++++++++++++++++++++++----------------- src/polyp/internal.h | 6 ++-- src/polyp/simple.c | 4 +-- src/polyp/stream.c | 86 ++++++++++++++++++++++++++-------------------------- src/polyp/stream.h | 46 ++++++++++++++++++++-------- src/utils/pacat.c | 9 +++--- 6 files changed, 142 insertions(+), 94 deletions(-) diff --git a/src/polyp/def.h b/src/polyp/def.h index 93d0996b..659b943b 100644 --- a/src/polyp/def.h +++ b/src/polyp/def.h @@ -80,22 +80,44 @@ typedef enum pa_stream_direction { /** Some special flags for stream connections. \since 0.6 */ typedef enum pa_stream_flags { PA_STREAM_START_CORKED = 1, /**< Create the stream corked, requiring an explicit pa_stream_cork() call to uncork it. */ - PA_STREAM_INTERPOLATE_LATENCY = 2, /**< Interpolate the latency for + PA_STREAM_INTERPOLATE_TIMING = 2, /**< Interpolate the latency for * this stream. When enabled, - * you can use - * pa_stream_interpolated_xxx() - * for synchronization. Using - * these functions instead of - * pa_stream_get_latency() has - * the advantage of not - * requiring a whole roundtrip - * for responses. Consider using - * this option when frequently - * requesting latency - * information. This is - * especially useful on long latency - * network connections. */ - PA_STREAM_NOT_MONOTONOUS = 4, /**< Don't force the time to run monotonically */ + * pa_stream_get_latency() and pa_stream_get_time() + * will try to estimate the + * current record/playback time + * based on the local time that + * passed since the last timing + * info update. In addition + * timing update requests are + * issued periodically + * automatically. Using this + * option has the advantage of + * not requiring a whole + * roundtrip when the current + * playback/recording time is + * needed. Consider using this + * option when requesting + * latency information + * frequently. This is + * especially useful on long + * latency network + * connections. */ + PA_STREAM_NOT_MONOTONOUS = 4, /**< Don't force the time to + * increase monotonically. If + * this option is enabled, + * pa_stream_get_time() will not + * necessarily return always + * monotonically increasing time + * values on each call. This may + * confuse applications which + * cannot deal with time going + * 'backwards', but has the + * advantage that bad transport + * latency estimations that + * caused the time to to jump + * ahead can be corrected + * quickly, without the need to + * wait. */ } pa_stream_flags_t; /** Playback and record buffer metrics */ @@ -167,21 +189,23 @@ typedef enum pa_subscription_event_type { /** Return one if an event type t matches an event mask bitfield */ #define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) -/** A structure for latency info. See pa_stream_get_latency(). The +/** A structure for all kinds of timing information of a stream. See + * pa_stream_update_timing_info() and pa_stream_get_timing_info(). The * total output latency a sample that is written with * pa_stream_write() takes to be played may be estimated by * sink_usec+buffer_usec+transport_usec. The output buffer to which * buffer_usec relates may be manipulated freely (with * pa_stream_write()'s seek argument, pa_stream_flush() and friends), - * the buffers sink_usec/source_usec relates to is a first-in - * first-out buffer which cannot be flushed or manipulated in any + * the buffers sink_usec and source_usec relate to are first-in + * first-out (FIFO) buffers which cannot be flushed or manipulated in any * way. The total input latency a sample that is recorded takes to be * delivered to the application is: * source_usec+buffer_usec+transport_usec-sink_usec. (Take care of * sign issues!) When connected to a monitor source sink_usec contains - * the latency of the owning sink.*/ -typedef struct pa_latency_info { - struct timeval timestamp; /**< The time when this latency info was current */ + * the latency of the owning sink. The two latency estimations + * described here are implemented in pa_stream_get_latency().*/ +typedef struct pa_timing_info { + struct timeval timestamp; /**< The time when this timing info structure was current */ int synchronized_clocks; /**< Non-zero if the local and the * remote machine have synchronized * clocks. If synchronized clocks are @@ -198,7 +222,14 @@ typedef struct pa_latency_info { int playing; /**< Non-zero when the stream is currently playing. Only for playback streams. */ - int write_index_corrupt; /**< Non-Zero if the write_index is not up to date because a local write command corrupted it */ + int write_index_corrupt; /**< Non-zero if write_index is not + * up-to-date because a local write + * command that corrupted it has been + * issued in the time since this latency + * info was current . Only write + * commands with SEEK_RELATIVE_ON_READ + * and SEEK_RELATIVE_END can corrupt + * write_index. */ int64_t write_index; /**< Current write index into the * playback buffer in bytes. Think twice before * using this for seeking purposes: it @@ -213,9 +244,7 @@ typedef struct pa_latency_info { * want to use it. Consider using * PA_SEEK_RELATIVE_ON_READ * instead. \since 0.8 */ - - uint32_t buffer_length; /* Current buffer length. This is usually identical to write_index-read_index. */ -} pa_latency_info; +} pa_timing_info; /** A structure for the spawn api. This may be used to integrate auto * spawned daemons into your application. For more information see @@ -236,12 +265,12 @@ typedef struct pa_spawn_api { * passed to the new process. */ } pa_spawn_api; -/** Seek type \since 0.8*/ +/** Seek type for pa_stream_write(). \since 0.8*/ typedef enum pa_seek_mode { PA_SEEK_RELATIVE = 0, /**< Seek relatively to the write index */ PA_SEEK_ABSOLUTE = 1, /**< Seek relatively to the start of the buffer queue */ - PA_SEEK_RELATIVE_ON_READ = 2, /**< Seek relatively to the read index */ - PA_SEEK_RELATIVE_END = 3, /**< Seek relatively to the current end of the buffer queue */ + PA_SEEK_RELATIVE_ON_READ = 2, /**< Seek relatively to the read index. */ + PA_SEEK_RELATIVE_END = 3, /**< Seek relatively to the current end of the buffer queue. */ } pa_seek_mode_t; PA_C_DECL_END diff --git a/src/polyp/internal.h b/src/polyp/internal.h index 8f1603b3..3b85b3d1 100644 --- a/src/polyp/internal.h +++ b/src/polyp/internal.h @@ -118,8 +118,8 @@ struct pa_stream { int corked; /* Store latest latency info */ - pa_latency_info latency_info; - int latency_info_valid; + pa_timing_info timing_info; + int timing_info_valid; /* Use to make sure that time advances monotonically */ pa_usec_t previous_time; @@ -182,8 +182,6 @@ pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, vo void pa_stream_set_state(pa_stream *s, pa_stream_state_t st); -void pa_stream_trash_ipol(pa_stream *s); - pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag); #define PA_CHECK_VALIDITY(context, expression, error) do { \ diff --git a/src/polyp/simple.c b/src/polyp/simple.c index 2593d5fa..f48c0b17 100644 --- a/src/polyp/simple.c +++ b/src/polyp/simple.c @@ -345,7 +345,7 @@ int pa_simple_drain(pa_simple *p, int *rerror) { return p->dead ? -1 : 0; } -static void latency_complete(pa_stream *s, int success, void *userdata) { +static void timing_complete(pa_stream *s, int success, void *userdata) { pa_simple *p = userdata; assert(s); @@ -377,7 +377,7 @@ pa_usec_t pa_simple_get_playback_latency(pa_simple *p, int *rerror) { } p->latency = 0; - if (!(o = pa_stream_update_latency_info(p->stream, latency_complete, p))) { + if (!(o = pa_stream_update_timing_info(p->stream, timing_complete, p))) { if (rerror) *rerror = pa_context_errno(p->context); return (pa_usec_t) -1; diff --git a/src/polyp/stream.c b/src/polyp/stream.c index d3599582..de27954c 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -89,7 +89,7 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->record_memblockq = NULL; s->previous_time = 0; - s->latency_info_valid = 0; + s->timing_info_valid = 0; s->corked = 0; @@ -311,7 +311,7 @@ static void ipol_callback(pa_mainloop_api *m, pa_time_event *e, PA_GCC_UNUSED co if (s->state == PA_STREAM_READY && !s->ipol_requested) { pa_operation *o; - if ((o = pa_stream_update_latency_info(s, NULL, NULL))) { + if ((o = pa_stream_update_timing_info(s, NULL, NULL))) { pa_operation_unref(o); s->ipol_requested = 1; } @@ -371,7 +371,7 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED /* We add an extra ref as long as we're connected (i.e. in the dynarray) */ pa_stream_ref(s); - if (s->flags & PA_STREAM_INTERPOLATE_LATENCY) { + if (s->flags & PA_STREAM_INTERPOLATE_TIMING) { struct timeval tv; pa_gettimeofday(&tv); @@ -406,7 +406,7 @@ static int create_stream( assert(s->ref >= 1); PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, !(flags & ~(PA_STREAM_START_CORKED|PA_STREAM_INTERPOLATE_LATENCY)), PA_ERR_INVALID); + PA_CHECK_VALIDITY(s->context, !(flags & ~(PA_STREAM_START_CORKED|PA_STREAM_INTERPOLATE_TIMING)), PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, direction == PA_STREAM_PLAYBACK || flags == 0, PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, !volume || volume->channels == s->sample_spec.channels, PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, !sync_stream || (direction == PA_STREAM_PLAYBACK && sync_stream->direction == PA_STREAM_PLAYBACK), PA_ERR_INVALID); @@ -557,16 +557,16 @@ int pa_stream_write( } /* Update the write index in the already available latency data */ - if (s->latency_info_valid) { + if (s->timing_info_valid) { if (seek == PA_SEEK_ABSOLUTE) { - s->latency_info.write_index_corrupt = 0; - s->latency_info.write_index = offset + length; + s->timing_info.write_index_corrupt = 0; + s->timing_info.write_index = offset + length; } else if (seek == PA_SEEK_RELATIVE) { - if (!s->latency_info.write_index_corrupt) - s->latency_info.write_index += offset + length; + if (!s->timing_info.write_index_corrupt) + s->timing_info.write_index += offset + length; } else - s->latency_info.write_index_corrupt = 1; + s->timing_info.write_index_corrupt = 1; } return 0; @@ -654,18 +654,18 @@ pa_operation * pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *us return pa_operation_ref(o); } -static void stream_get_latency_info_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; struct timeval local, remote, now; - pa_latency_info *i; + pa_timing_info *i; assert(pd); assert(o); assert(o->stream); assert(o->context); - i = &o->stream->latency_info; - o->stream->latency_info_valid = 0; + i = &o->stream->timing_info; + o->stream->timing_info_valid = 0; i->write_index_corrupt = 0; if (command != PA_COMMAND_REPLY) { @@ -741,7 +741,7 @@ static void stream_get_latency_info_callback(pa_pdispatch *pd, uint32_t command, } } - o->stream->latency_info_valid = 1; + o->stream->timing_info_valid = 1; o->stream->ipol_timestamp = now; o->stream->ipol_usec_valid = 0; @@ -762,7 +762,7 @@ static void stream_get_latency_info_callback(pa_pdispatch *pd, uint32_t command, if (o->callback) { pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback; - cb(o->stream, o->stream->latency_info_valid, o->userdata); + cb(o->stream, o->stream->timing_info_valid, o->userdata); } finish: @@ -771,7 +771,7 @@ finish: pa_operation_unref(o); } -pa_operation* pa_stream_update_latency_info(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { +pa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { uint32_t tag; pa_operation *o; pa_tagstruct *t; @@ -800,7 +800,7 @@ pa_operation* pa_stream_update_latency_info(pa_stream *s, pa_stream_success_cb_t pa_tagstruct_put_timeval(t, pa_gettimeofday(&now)); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_info_callback, o); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_timing_info_callback, o); /* Fill in initial correction data */ o->stream->idx_latency_correction = cidx; @@ -945,7 +945,7 @@ pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, voi PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - if (s->flags & PA_STREAM_INTERPOLATE_LATENCY) { + if (s->flags & PA_STREAM_INTERPOLATE_TIMING) { if (!s->corked && b) { /* Refresh the interpolated data just befor pausing */ pa_stream_get_time(s, NULL); @@ -967,7 +967,7 @@ pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, voi pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); - if ((lo = pa_stream_update_latency_info(s, NULL, NULL))) + if ((lo = pa_stream_update_timing_info(s, NULL, NULL))) pa_operation_unref(lo); return pa_operation_ref(o); @@ -1001,7 +1001,7 @@ pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *use if ((o = stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata))) { pa_operation *lo; - if ((lo = pa_stream_update_latency_info(s, NULL, NULL))) + if ((lo = pa_stream_update_timing_info(s, NULL, NULL))) pa_operation_unref(lo); } @@ -1016,7 +1016,7 @@ pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *us if ((o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata))) { pa_operation *lo; - if ((lo = pa_stream_update_latency_info(s, NULL, NULL))) + if ((lo = pa_stream_update_timing_info(s, NULL, NULL))) pa_operation_unref(lo); } @@ -1031,7 +1031,7 @@ pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *u if ((o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata))) { pa_operation *lo; - if ((lo = pa_stream_update_latency_info(s, NULL, NULL))) + if ((lo = pa_stream_update_timing_info(s, NULL, NULL))) pa_operation_unref(lo); } @@ -1072,56 +1072,56 @@ int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) { PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->latency_info_valid, PA_ERR_NODATA); + PA_CHECK_VALIDITY(s->context, s->timing_info_valid, PA_ERR_NODATA); - if (s->flags & PA_STREAM_INTERPOLATE_LATENCY && s->ipol_usec_valid ) + if (s->flags & PA_STREAM_INTERPOLATE_TIMING && s->ipol_usec_valid ) usec = s->ipol_usec; else { if (s->direction == PA_STREAM_PLAYBACK) { /* The last byte that was written into the output device * had this time value associated */ - usec = pa_bytes_to_usec(s->latency_info.read_index < 0 ? 0 : (uint64_t) s->latency_info.read_index, &s->sample_spec); + usec = pa_bytes_to_usec(s->timing_info.read_index < 0 ? 0 : (uint64_t) s->timing_info.read_index, &s->sample_spec); /* Because the latency info took a little time to come * to us, we assume that the real output time is actually * a little ahead */ - usec += s->latency_info.transport_usec; + usec += s->timing_info.transport_usec; /* However, the output device usually maintains a buffer too, hence the real sample currently played is a little back */ - if (s->latency_info.sink_usec >= usec) + if (s->timing_info.sink_usec >= usec) usec = 0; else - usec -= s->latency_info.sink_usec; + usec -= s->timing_info.sink_usec; } else if (s->direction == PA_STREAM_RECORD) { /* The last byte written into the server side queue had * this time value associated */ - usec = pa_bytes_to_usec(s->latency_info.write_index < 0 ? 0 : (uint64_t) s->latency_info.write_index, &s->sample_spec); + usec = pa_bytes_to_usec(s->timing_info.write_index < 0 ? 0 : (uint64_t) s->timing_info.write_index, &s->sample_spec); /* Add transport latency */ - usec += s->latency_info.transport_usec; + usec += s->timing_info.transport_usec; /* Add latency of data in device buffer */ - usec += s->latency_info.source_usec; + usec += s->timing_info.source_usec; /* If this is a monitor source, we need to correct the * time by the playback device buffer */ - if (s->latency_info.sink_usec >= usec) + if (s->timing_info.sink_usec >= usec) usec = 0; else - usec -= s->latency_info.sink_usec; + usec -= s->timing_info.sink_usec; } - if (s->flags & PA_STREAM_INTERPOLATE_LATENCY) { + if (s->flags & PA_STREAM_INTERPOLATE_TIMING) { s->ipol_usec_valid = 1; s->ipol_usec = usec; } } /* Interpolate if requested */ - if (s->flags & PA_STREAM_INTERPOLATE_LATENCY) { + if (s->flags & PA_STREAM_INTERPOLATE_TIMING) { /* We just add the time that passed since the latency info was * current */ @@ -1176,16 +1176,16 @@ int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative) { PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->latency_info_valid, PA_ERR_NODATA); - PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_PLAYBACK || !s->latency_info.write_index_corrupt, PA_ERR_NODATA); + PA_CHECK_VALIDITY(s->context, s->timing_info_valid, PA_ERR_NODATA); + PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_PLAYBACK || !s->timing_info.write_index_corrupt, PA_ERR_NODATA); if ((r = pa_stream_get_time(s, &t)) < 0) return r; if (s->direction == PA_STREAM_PLAYBACK) - cindex = s->latency_info.write_index; + cindex = s->timing_info.write_index; else - cindex = s->latency_info.read_index; + cindex = s->timing_info.read_index; if (cindex < 0) cindex = 0; @@ -1200,15 +1200,15 @@ int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative) { return 0; } -const pa_latency_info* pa_stream_get_latency_info(pa_stream *s) { +const pa_timing_info* pa_stream_get_timing_info(pa_stream *s) { assert(s); assert(s->ref >= 1); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->latency_info_valid, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->timing_info_valid, PA_ERR_BADSTATE); - return &s->latency_info; + return &s->timing_info; } const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) { diff --git a/src/polyp/stream.h b/src/polyp/stream.h index 99284ba3..ce041986 100644 --- a/src/polyp/stream.h +++ b/src/polyp/stream.h @@ -130,8 +130,11 @@ size_t pa_stream_readable_size(pa_stream *p); /** Drain a playback stream. Use this for notification when the buffer is empty */ pa_operation* pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); -/** Update the latency info of a stream */ -pa_operation* pa_stream_update_latency_info(pa_stream *p, pa_stream_success_cb_t cb, void *userdata); +/** Request a timing info structure update for a stream. Use + * pa_stream_get_timing_info() to get access to the raw timing data, + * or pa_stream_get_time() or pa_stream_get_latency() to get cleaned + * up values. */ +pa_operation* pa_stream_update_timing_info(pa_stream *p, pa_stream_success_cb_t cb, void *userdata); /** Set the callback function that is called whenever the state of the stream changes */ void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata); @@ -171,20 +174,39 @@ pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *u pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata); /** Return the current playback/recording time. This is based on the - * counter accessible with pa_stream_get_counter(). This function - * requires a pa_latency_info structure as argument, which should be - * acquired using pa_stream_get_latency(). \since 0.6 */ + * data in the timing info structure returned by + * pa_stream_get_timing_info(). This function will usually only return + * new data if a timing info update has been recieved. Only if timing + * interpolation has been requested (PA_STREAM_INTERPOLATE_TIMING) + * the data from the last timing update is used for an estimation of + * the current playback/recording time based on the local time that + * passed since the timing info structure has been acquired. The time + * value returned by this function is guaranteed to increase + * monotonically. (that means: the returned value is always greater or + * equal to the value returned on the last call) This behaviour can + * be disabled by using PA_STREAM_NOT_MONOTONOUS. This may be + * desirable to deal better with bad estimations of transport + * latencies, but may have strange effects if the application is not + * able to deal with time going 'backwards'. \since 0.6 */ int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec); -/** Return the total stream latency. Thus function requires a - * pa_latency_info structure as argument, which should be aquired - * using pa_stream_get_latency(). In case the stream is a monitoring - * stream the result can be negative, i.e. the captured samples are - * not yet played. In this case *negative is set to 1. \since 0.6 */ +/** Return the total stream latency. This function is based on + * pa_stream_get_time(). In case the stream is a monitoring stream the + * result can be negative, i.e. the captured samples are not yet + * played. In this case *negative is set to 1. \since 0.6 */ int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative); -/** Return the latest latency data. \since 0.8 */ -const pa_latency_info* pa_stream_get_latency_info(pa_stream *s); +/** Return the latest raw timing data structure. The returned pointer + * points to an internal read-only instance of the timing + * structure. The user should make a copy of this structure if he + * wants to modify it. An in-place update to this data structure may + * be requested using pa_stream_update_timing_info(). If no + * pa_stream_update_timing_info() call was issued before, this + * function will fail with PA_ERR_NODATA. Please note that the + * write_index member field (and only this field) is updated on each + * pa_stream_write() call, not just when a timing update has been + * recieved. \since 0.8 */ +const pa_timing_info* pa_stream_get_timing_info(pa_stream *s); /** Return a pointer to the stream's sample specification. \since 0.6 */ const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s); diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 8d9cff0b..441e2607 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -340,15 +340,15 @@ static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, } /* Show the current latency */ -static void stream_update_latency_callback(pa_stream *s, int success, void *userdata) { +static void stream_update_timing_callback(pa_stream *s, int success, void *userdata) { pa_usec_t total; int negative = 0; - const pa_latency_info *i; + const pa_timing_info *i; assert(s); if (!success || - !(i = pa_stream_get_latency_info(s)) || + !(i = pa_stream_get_timing_info(s)) || pa_stream_get_latency(s, &total, &negative) < 0) { fprintf(stderr, "Failed to get latency: %s\n", pa_strerror(pa_context_errno(context))); quit(1); @@ -366,8 +366,7 @@ static void stream_update_latency_callback(pa_stream *s, int success, void *user /* Someone requested that the latency is shown */ static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { - fprintf(stderr, "Got SIGUSR1, requesting latency.\n"); - pa_operation_unref(pa_stream_update_latency_info(stream, stream_update_latency_callback, NULL)); + pa_operation_unref(pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL)); } -- cgit -- cgit From e5a5b56d6efd10279d4a2557f29fce9b5d7e956a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Apr 2006 01:32:33 +0000 Subject: remove yet another item from the todo list git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@653 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index d36b194e..2c2d7d0d 100644 --- a/doc/todo +++ b/doc/todo @@ -5,7 +5,6 @@ Test: - module-tunnel Fixes: -- latency api rework for native protocol - module-oss-* love: - deal with underflows propely - improve latency measurement for mmap -- cgit From add110bd10de93a8f42fc1449ce4e0ff6ee8d261 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 7 Apr 2006 06:29:59 +0000 Subject: Some memcpy arithmetic that wasn't removed when doing the redesign to update the data pointer instead. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@654 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-esound.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index e9871178..e29c44c9 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -669,7 +669,7 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ format = MAYBE_INT32_SWAP(c->swap_byte_order, format); data = (const char*)data + sizeof(int32_t); - memcpy(&rate, (const char*)data + sizeof(int32_t), sizeof(int32_t)); + memcpy(&rate, data, sizeof(int32_t)); rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); data = (const char*)data + sizeof(int32_t); -- cgit From 22558b5e0e6b185bea178ea3630dcdf1d4ec2bf7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Apr 2006 21:10:35 +0000 Subject: fix pkg-config files git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@655 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyplib-glib-mainloop.pc.in | 2 +- polyplib-glib12-mainloop.pc.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/polyplib-glib-mainloop.pc.in b/polyplib-glib-mainloop.pc.in index 0e8b4d8c..3d8f3931 100644 --- a/polyplib-glib-mainloop.pc.in +++ b/polyplib-glib-mainloop.pc.in @@ -8,4 +8,4 @@ Description: GLIB main loop wrapper for polypaudio Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lpolyp-mainloop-glib-@PA_MAJORMINOR@ Cflags: -D_REENTRANT -I${includedir} -Requires: polyplib-mainloop glib-2.0 +Requires: polyplib glib-2.0 diff --git a/polyplib-glib12-mainloop.pc.in b/polyplib-glib12-mainloop.pc.in index 8687776b..5ada2e5c 100644 --- a/polyplib-glib12-mainloop.pc.in +++ b/polyplib-glib12-mainloop.pc.in @@ -8,4 +8,4 @@ Description: GLIB main loop wrapper for polypaudio Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lpolyp-mainloop-glib12-@PA_MAJORMINOR@ Cflags: -D_REENTRANT -I${includedir} -Requires: polyplib-mainloop glib +Requires: polyplib glib -- cgit From fdb48b43401db4e15857be5239eff2f76abd8c7c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Apr 2006 21:55:55 +0000 Subject: * enable write_index correction and timing interpolation only for playback (and record) streams git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@656 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/stream.c | 85 +++++++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/src/polyp/stream.c b/src/polyp/stream.c index de27954c..4a98dd60 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -371,7 +371,8 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED /* We add an extra ref as long as we're connected (i.e. in the dynarray) */ pa_stream_ref(s); - if (s->flags & PA_STREAM_INTERPOLATE_TIMING) { + if (s->direction != PA_STREAM_UPLOAD && + s->flags & PA_STREAM_INTERPOLATE_TIMING) { struct timeval tv; pa_gettimeofday(&tv); @@ -542,31 +543,33 @@ int pa_stream_write( else s->requested_bytes = 0; - /* Update latency request correction */ - if (s->latency_corrections[s->idx_latency_correction].valid) { - - if (seek == PA_SEEK_ABSOLUTE) { - s->latency_corrections[s->idx_latency_correction].corrupt = 0; - s->latency_corrections[s->idx_latency_correction].absolute = 1; - s->latency_corrections[s->idx_latency_correction].value = offset + length; - } else if (seek == PA_SEEK_RELATIVE) { - if (!s->latency_corrections[s->idx_latency_correction].corrupt) - s->latency_corrections[s->idx_latency_correction].value += offset + length; - } else - s->latency_corrections[s->idx_latency_correction].corrupt = 1; - } - - /* Update the write index in the already available latency data */ - if (s->timing_info_valid) { - - if (seek == PA_SEEK_ABSOLUTE) { - s->timing_info.write_index_corrupt = 0; - s->timing_info.write_index = offset + length; - } else if (seek == PA_SEEK_RELATIVE) { - if (!s->timing_info.write_index_corrupt) - s->timing_info.write_index += offset + length; - } else - s->timing_info.write_index_corrupt = 1; + if (s->direction == PA_STREAM_PLAYBACK) { + /* Update latency request correction */ + if (s->latency_corrections[s->idx_latency_correction].valid) { + + if (seek == PA_SEEK_ABSOLUTE) { + s->latency_corrections[s->idx_latency_correction].corrupt = 0; + s->latency_corrections[s->idx_latency_correction].absolute = 1; + s->latency_corrections[s->idx_latency_correction].value = offset + length; + } else if (seek == PA_SEEK_RELATIVE) { + if (!s->latency_corrections[s->idx_latency_correction].corrupt) + s->latency_corrections[s->idx_latency_correction].value += offset + length; + } else + s->latency_corrections[s->idx_latency_correction].corrupt = 1; + } + + /* Update the write index in the already available latency data */ + if (s->timing_info_valid) { + + if (seek == PA_SEEK_ABSOLUTE) { + s->timing_info.write_index_corrupt = 0; + s->timing_info.write_index = offset + length; + } else if (seek == PA_SEEK_RELATIVE) { + if (!s->timing_info.write_index_corrupt) + s->timing_info.write_index += offset + length; + } else + s->timing_info.write_index_corrupt = 1; + } } return 0; @@ -759,7 +762,7 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, o->stream->latency_corrections[n].valid = 0; } } - + if (o->callback) { pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback; cb(o->stream, o->stream->timing_info_valid, o->userdata); @@ -784,11 +787,13 @@ pa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - /* Find a place to store the write_index correction data for this entry */ - cidx = (s->idx_latency_correction + 1) % PA_MAX_LATENCY_CORRECTIONS; - - /* Check if we could allocate a correction slot. If not, there are too many outstanding queries */ - PA_CHECK_VALIDITY_RETURN_NULL(s->context, !s->latency_corrections[cidx].valid, PA_ERR_INTERNAL); + if (s->direction == PA_STREAM_PLAYBACK) { + /* Find a place to store the write_index correction data for this entry */ + cidx = (s->idx_latency_correction + 1) % PA_MAX_LATENCY_CORRECTIONS; + + /* Check if we could allocate a correction slot. If not, there are too many outstanding queries */ + PA_CHECK_VALIDITY_RETURN_NULL(s->context, !s->latency_corrections[cidx].valid, PA_ERR_INTERNAL); + } o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); @@ -802,13 +807,15 @@ pa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_timing_info_callback, o); - /* Fill in initial correction data */ - o->stream->idx_latency_correction = cidx; - o->stream->latency_corrections[cidx].valid = 1; - o->stream->latency_corrections[cidx].tag = tag; - o->stream->latency_corrections[cidx].absolute = 0; - o->stream->latency_corrections[cidx].value = 0; - o->stream->latency_corrections[cidx].corrupt = 0; + if (s->direction == PA_STREAM_PLAYBACK) { + /* Fill in initial correction data */ + o->stream->idx_latency_correction = cidx; + o->stream->latency_corrections[cidx].valid = 1; + o->stream->latency_corrections[cidx].tag = tag; + o->stream->latency_corrections[cidx].absolute = 0; + o->stream->latency_corrections[cidx].value = 0; + o->stream->latency_corrections[cidx].corrupt = 0; + } return pa_operation_ref(o); } -- cgit From 2f918f0ede45480ecc355413f5a3ffbee3433e5a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Apr 2006 21:57:41 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@657 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/todo b/doc/todo index 2c2d7d0d..7249a561 100644 --- a/doc/todo +++ b/doc/todo @@ -11,6 +11,8 @@ Fixes: - module-alsa-* love: - deal with underflows properly +- introspection API: flag reflecting if sink/source supports hw volume control + Post 0.8: - alsa mmap driver - add radio module -- cgit From 7261494b840b0b9c0ae7bcd6422098e2d795c6c9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Apr 2006 22:28:13 +0000 Subject: remove item from TODO list, since it requires the SNDCTL_DSP_GETERROR ioctl() which isn't supported by the Linux kernel git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@658 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index 7249a561..7cd182a7 100644 --- a/doc/todo +++ b/doc/todo @@ -6,7 +6,6 @@ Test: Fixes: - module-oss-* love: - - deal with underflows propely - improve latency measurement for mmap - module-alsa-* love: - deal with underflows properly -- cgit From 4af16e43cb37eb4a0140f7105490e640512e7c13 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Apr 2006 22:45:08 +0000 Subject: minor cleanups git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@659 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-sink.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 2e9459e6..f930e615 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -124,7 +124,7 @@ static void do_write(struct userdata *u) { continue; } - pa_log(__FILE__": snd_pcm_writei() failed"); + pa_log(__FILE__": snd_pcm_writei() failed: %s", snd_strerror(frames)); return; } @@ -176,17 +176,19 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { pa_usec_t r = 0; struct userdata *u = s->userdata; snd_pcm_sframes_t frames; + int err; + assert(s && u && u->sink); - if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { - pa_log(__FILE__": failed to get delay"); + if ((err = snd_pcm_delay(u->pcm_handle, &frames)) < 0) { + pa_log(__FILE__": failed to get delay: %s", snd_strerror(err)); s->get_latency = NULL; return 0; } if (frames < 0) frames = 0; - + r += pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec); if (u->memchunk.memblock) -- cgit From 272ab200c24223a04efcc9f5a5df0e5e70b8de59 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Apr 2006 22:46:02 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@660 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/todo b/doc/todo index 7cd182a7..38d8b713 100644 --- a/doc/todo +++ b/doc/todo @@ -7,8 +7,6 @@ Test: Fixes: - module-oss-* love: - improve latency measurement for mmap -- module-alsa-* love: - - deal with underflows properly - introspection API: flag reflecting if sink/source supports hw volume control -- cgit From f6d95b7291f09f63f50d3b258f6a82580faf7bca Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Apr 2006 23:02:48 +0000 Subject: add new introspection data field for sinks/sources: a flags field which specifies whether the sink/source supports hw volume control and latency querying git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@661 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/def.h | 12 ++++++++++++ src/polyp/introspect.c | 12 ++++++++++-- src/polyp/introspect.h | 2 ++ src/polypcore/protocol-native.c | 2 ++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/polyp/def.h b/src/polyp/def.h index 659b943b..1a7a20c3 100644 --- a/src/polyp/def.h +++ b/src/polyp/def.h @@ -273,6 +273,18 @@ typedef enum pa_seek_mode { PA_SEEK_RELATIVE_END = 3, /**< Seek relatively to the current end of the buffer queue. */ } pa_seek_mode_t; +/** Special sink flags. \since 0.8 */ +typedef enum pa_sink_flags { + PA_SINK_HW_VOLUME_CTRL = 1, /**< Supports hardware volume control */ + PA_SINK_LATENCY = 2 /**< Supports latency querying */ +} pa_sink_flags_t; + +/** Special source flags. \since 0.8 */ +typedef enum pa_source_flags { + PA_SOURCE_HW_VOLUME_CTRL = 1, /**< Supports hardware volume control */ + PA_SOURCE_LATENCY = 2 /**< Supports latency querying */ +} pa_source_flags_t; + PA_C_DECL_END #endif diff --git a/src/polyp/introspect.c b/src/polyp/introspect.c index 6a28998c..ea6133e1 100644 --- a/src/polyp/introspect.c +++ b/src/polyp/introspect.c @@ -135,6 +135,7 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P eol = -1; } else { + uint32_t flags; while (!pa_tagstruct_eof(t)) { pa_sink_info i; @@ -150,12 +151,15 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P pa_tagstruct_getu32(t, &i.monitor_source) < 0 || pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || pa_tagstruct_get_usec(t, &i.latency) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0) { + pa_tagstruct_gets(t, &i.driver) < 0 || + pa_tagstruct_getu32(t, &flags) < 0) { pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } + i.flags = (pa_sink_flags_t) flags; + if (o->callback) { pa_sink_info_cb_t cb = (pa_sink_info_cb_t) o->callback; cb(o->context, &i, 0, o->userdata); @@ -242,6 +246,7 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, while (!pa_tagstruct_eof(t)) { pa_source_info i; + uint32_t flags; if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || @@ -254,12 +259,15 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 || pa_tagstruct_get_usec(t, &i.latency) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0) { + pa_tagstruct_gets(t, &i.driver) < 0 || + pa_tagstruct_getu32(t, &flags) < 0) { pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } + i.flags = (pa_source_flags_t) flags; + if (o->callback) { pa_source_info_cb_t cb = (pa_source_info_cb_t) o->callback; cb(o->context, &i, 0, o->userdata); diff --git a/src/polyp/introspect.h b/src/polyp/introspect.h index f1f0989c..fb05cfb9 100644 --- a/src/polyp/introspect.h +++ b/src/polyp/introspect.h @@ -63,6 +63,7 @@ typedef struct pa_sink_info { const char *monitor_source_name; /**< The name of the monitor source */ pa_usec_t latency; /**< Length of filled playback buffer of this sink */ const char *driver; /**< Driver name. \since 0.8 */ + pa_sink_flags_t flags; /**< Flags \since 0.8 */ } pa_sink_info; /** Callback prototype for pa_context_get_sink_info_by_name() and friends */ @@ -91,6 +92,7 @@ typedef struct pa_source_info { const char *monitor_of_sink_name; /**< Name of the owning sink, or PA_INVALID_INDEX */ pa_usec_t latency; /**< Length of filled record buffer of this source. \since 0.5 */ const char *driver; /**< Driver name \since 0.8 */ + pa_source_flags_t flags; /**< Flags \since 0.8 */ } pa_source_info; /** Callback prototype for pa_context_get_source_info_by_name() and friends */ diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 763873c2..51280c84 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -1232,6 +1232,7 @@ static void sink_fill_tagstruct(pa_tagstruct *t, pa_sink *sink) { PA_TAG_STRING, sink->monitor_source->name, PA_TAG_USEC, pa_sink_get_latency(sink), PA_TAG_STRING, sink->driver, + PA_TAG_U32, (sink->get_hw_volume ? PA_SINK_HW_VOLUME_CTRL : 0) | (sink->get_latency ? PA_SINK_LATENCY : 0), PA_TAG_INVALID); } @@ -1251,6 +1252,7 @@ static void source_fill_tagstruct(pa_tagstruct *t, pa_source *source) { PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL, PA_TAG_USEC, pa_source_get_latency(source), PA_TAG_STRING, source->driver, + PA_TAG_U32, (source->get_hw_volume ? PA_SOURCE_HW_VOLUME_CTRL : 0) | (source->get_latency ? PA_SOURCE_LATENCY : 0), PA_TAG_INVALID); } -- cgit From a546c76a1c0b85ec481d11e2f9a1524a7abde14b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Apr 2006 23:05:45 +0000 Subject: * show flags value when dumping sink/source info in pactl. * show volume for sources, too * show value of "mute" field for sinks/sources git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@662 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pactl.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 907746aa..fcc677d9 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -175,7 +175,8 @@ static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_ "Owner Module: %u\n" "Volume: %s\n" "Monitor Source: %u\n" - "Latency: %0.0f usec\n", + "Latency: %0.0f usec\n" + "Flags: %s%s\n", i->index, i->name, i->driver, @@ -183,14 +184,16 @@ static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_ pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), i->owner_module, - pa_cvolume_snprint(cv, sizeof(cv), &i->volume), + i->mute ? "muted" : pa_cvolume_snprint(cv, sizeof(cv), &i->volume), i->monitor_source, - (double) i->latency); + (double) i->latency, + i->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", + i->flags & PA_SINK_LATENCY ? "LATENCY" : ""); } static void get_source_info_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) { - char s[PA_SAMPLE_SPEC_SNPRINT_MAX], t[32], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + char s[PA_SAMPLE_SPEC_SNPRINT_MAX], t[32], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; if (is_last < 0) { fprintf(stderr, "Failed to get source information: %s\n", pa_strerror(pa_context_errno(c))); @@ -218,8 +221,10 @@ static void get_source_info_callback(pa_context *c, const pa_source_info *i, int "Sample Specification: %s\n" "Channel Map: %s\n" "Owner Module: %u\n" + "Volume: %s\n" "Monitor of Sink: %s\n" - "Latency: %0.0f usec\n", + "Latency: %0.0f usec\n" + "Flags: %s%s\n", i->index, i->driver, i->name, @@ -227,9 +232,12 @@ static void get_source_info_callback(pa_context *c, const pa_source_info *i, int pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), i->owner_module, + i->mute ? "muted" : pa_cvolume_snprint(cv, sizeof(cv), &i->volume), i->monitor_of_sink != PA_INVALID_INDEX ? t : "no", - (double) i->latency); - + (double) i->latency, + i->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", + i->flags & PA_SOURCE_LATENCY ? "LATENCY" : ""); + } static void get_module_info_callback(pa_context *c, const pa_module_info *i, int is_last, void *userdata) { -- cgit From 107525ce415edf2b37f867337869c8eeebc8d054 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Apr 2006 23:08:25 +0000 Subject: remove another item from the todo list git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@663 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/todo b/doc/todo index 38d8b713..5e635748 100644 --- a/doc/todo +++ b/doc/todo @@ -8,8 +8,6 @@ Fixes: - module-oss-* love: - improve latency measurement for mmap -- introspection API: flag reflecting if sink/source supports hw volume control - Post 0.8: - alsa mmap driver - add radio module -- cgit From b4a547419c0815add1fc91d35d2a483c5a0e7c20 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 8 Apr 2006 00:09:28 +0000 Subject: when doing software volume adjustments, don't use the volume value as linear factor, but pass it through pa_sw_volume_to_linear() first. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@664 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/sample-util.c | 44 +++++++++++++++----------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/src/polypcore/sample-util.c b/src/polypcore/sample-util.c index 7afb9d11..d06fa95f 100644 --- a/src/polypcore/sample-util.c +++ b/src/polypcore/sample-util.c @@ -116,19 +116,15 @@ size_t pa_mix( else { v = *((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); - if (cvolume != PA_VOLUME_NORM) { - v *= cvolume; - v /= PA_VOLUME_NORM; - } + if (cvolume != PA_VOLUME_NORM) + v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); } sum += v; } - if (volume->values[channel] != PA_VOLUME_NORM) { - sum *= volume->values[channel]; - sum /= PA_VOLUME_NORM; - } + if (volume->values[channel] != PA_VOLUME_NORM) + sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); if (sum < -0x8000) sum = -0x8000; if (sum > 0x7FFF) sum = 0x7FFF; @@ -168,19 +164,15 @@ size_t pa_mix( else { v = (int32_t) *((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d) - 0x80; - if (cvolume != PA_VOLUME_NORM) { - v *= cvolume; - v /= PA_VOLUME_NORM; - } + if (cvolume != PA_VOLUME_NORM) + v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); } sum += v; } - if (volume->values[channel] != PA_VOLUME_NORM) { - sum *= volume->values[channel]; - sum /= PA_VOLUME_NORM; - } + if (volume->values[channel] != PA_VOLUME_NORM) + sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); if (sum < -0x80) sum = -0x80; if (sum > 0x7F) sum = 0x7F; @@ -220,19 +212,15 @@ size_t pa_mix( else { v = *((float*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); - if (cvolume != PA_VOLUME_NORM) { - v *= cvolume; - v /= PA_VOLUME_NORM; - } + if (cvolume != PA_VOLUME_NORM) + v *= pa_sw_volume_to_linear(cvolume); } sum += v; } - if (volume->values[channel] != PA_VOLUME_NORM) { - sum *= volume->values[channel]; - sum /= PA_VOLUME_NORM; - } + if (volume->values[channel] != PA_VOLUME_NORM) + sum *= pa_sw_volume_to_linear(volume->values[channel]); } *((float*) data) = sum; @@ -270,8 +258,7 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol for (d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { int32_t t = (int32_t)(*d); - t *= volume->values[channel]; - t /= PA_VOLUME_NORM; + t = (int32_t) (t * pa_sw_volume_to_linear(volume->values[channel])); if (t < -0x8000) t = -0x8000; if (t > 0x7FFF) t = 0x7FFF; @@ -292,8 +279,7 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol for (d = (uint8_t*) c->memblock->data + c->index, n = c->length; n > 0; d++, n--) { int32_t t = (int32_t) *d - 0x80; - t *= volume->values[channel]; - t /= PA_VOLUME_NORM; + t = (int32_t) (t * pa_sw_volume_to_linear(volume->values[channel])); if (t < -0x80) t = -0x80; if (t > 0x7F) t = 0x7F; @@ -322,7 +308,7 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol if (volume->values[channel] == PA_VOLUME_NORM) continue; - v = (float) volume->values[channel] / PA_VOLUME_NORM; + v = (float) pa_sw_volume_to_linear(volume->values[channel]); t = d + channel; oil_scalarmult_f32(t, skip, t, skip, &v, n); -- cgit From 025228f957b9212f889168a61497b6b3470fca20 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 8 Apr 2006 00:19:29 +0000 Subject: add proper volume clipping support for OSS devices git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@665 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/oss-util.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index 958bd547..fac39e7b 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -190,11 +190,16 @@ static int pa_oss_get_volume(int fd, int mixer, const pa_sample_spec *ss, pa_cvo static int pa_oss_set_volume(int fd, int mixer, const pa_sample_spec *ss, const pa_cvolume *volume) { char cv[PA_CVOLUME_SNPRINT_MAX]; unsigned vol; + pa_volume_t l, r; - vol = (volume->values[0]*100)/PA_VOLUME_NORM; + l = volume->values[0] > PA_VOLUME_NORM ? PA_VOLUME_NORM : volume->values[0]; - if (ss->channels >= 2) - vol |= ((volume->values[1]*100)/PA_VOLUME_NORM) << 8; + vol = (l*100)/PA_VOLUME_NORM; + + if (ss->channels >= 2) { + r = volume->values[1] > PA_VOLUME_NORM ? PA_VOLUME_NORM : volume->values[1]; + vol |= ((r*100)/PA_VOLUME_NORM) << 8; + } if (ioctl(fd, mixer, &vol) < 0) return -1; -- cgit From a74253606f4f5556e58cb12336d8900dd73226cc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 8 Apr 2006 00:19:52 +0000 Subject: clip volume at PA_VOLUME_NORM for alsa devices git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@666 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-sink.c | 15 +++++++++++++-- src/modules/module-alsa-source.c | 14 ++++++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index f930e615..e2e593da 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -239,8 +239,14 @@ static int sink_set_hw_volume_cb(pa_sink *s) { assert(u && u->mixer_elem); if (snd_mixer_selem_has_playback_volume_joined(u->mixer_elem)) { - vol = pa_cvolume_avg(&s->hw_volume) * (u->hw_volume_max - u->hw_volume_min) / + vol = pa_cvolume_avg(&s->hw_volume); + + if (vol > PA_VOLUME_NORM) + vol = PA_VOLUME_NORM; + + vol = (vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM + u->hw_volume_min; + err = snd_mixer_selem_set_playback_volume_all(u->mixer_elem, vol); if (err < 0) goto fail; @@ -248,7 +254,12 @@ static int sink_set_hw_volume_cb(pa_sink *s) { int i; for (i = 0;i < s->hw_volume.channels;i++) { - vol = s->hw_volume.values[i] * (u->hw_volume_max - u->hw_volume_min) / + vol = s->hw_volume.values[i]; + + if (vol > PA_VOLUME_NORM) + vol = PA_VOLUME_NORM; + + vol = (vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM + u->hw_volume_min; err = snd_mixer_selem_set_playback_volume(u->mixer_elem, i, vol); if (err < 0) diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 14b35eb8..2ee16190 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -228,7 +228,12 @@ static int source_set_hw_volume_cb(pa_source *s) { assert(u && u->mixer_elem); if (snd_mixer_selem_has_capture_volume_joined(u->mixer_elem)) { - vol = pa_cvolume_avg(&s->hw_volume) * (u->hw_volume_max - u->hw_volume_min) / + vol = pa_cvolume_avg(&s->hw_volume); + + if (vol > PA_VOLUME_NORM) + vol = PA_VOLUME_NORM; + + vol = vol * (u->hw_volume_max - u->hw_volume_min) / PA_VOLUME_NORM + u->hw_volume_min; err = snd_mixer_selem_set_capture_volume_all(u->mixer_elem, vol); if (err < 0) @@ -237,7 +242,12 @@ static int source_set_hw_volume_cb(pa_source *s) { int i; for (i = 0;i < s->hw_volume.channels;i++) { - vol = s->hw_volume.values[i] * (u->hw_volume_max - u->hw_volume_min) / + vol = s->hw_volume.values[i]; + + if (vol > PA_VOLUME_NORM) + vol = PA_VOLUME_NORM; + + vol = vol * (u->hw_volume_max - u->hw_volume_min) / PA_VOLUME_NORM + u->hw_volume_min; err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, vol); if (err < 0) -- cgit From a6ce5c4b1d82870f5db7063680698cebb4ffe156 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 9 Apr 2006 19:31:09 +0000 Subject: Big documentation update. Describe the client API in a more tutorial like manner. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@667 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/channelmap.h | 34 +++++++++ src/polyp/context.h | 116 ++++++++++++++++++++++++++--- src/polyp/glib-mainloop.h | 11 +++ src/polyp/introspect.h | 184 ++++++++++++++++++++++++++++++++++++++++++---- src/polyp/mainloop.h | 35 +++++++++ src/polyp/polypaudio.h | 52 +++++++------ src/polyp/sample.h | 66 +++++++++++++++++ src/polyp/scache.h | 43 +++++++++++ src/polyp/simple.h | 65 +++++++++++++++- src/polyp/stream.h | 131 +++++++++++++++++++++++++++++++++ src/polyp/subscribe.h | 19 ++++- src/polyp/volume.h | 53 +++++++++++++ 12 files changed, 757 insertions(+), 52 deletions(-) diff --git a/src/polyp/channelmap.h b/src/polyp/channelmap.h index dd508abe..c74f2ceb 100644 --- a/src/polyp/channelmap.h +++ b/src/polyp/channelmap.h @@ -25,6 +25,40 @@ #include #include +/** \page channelmap Channel maps + * + * \section overv_sec Overview + * + * Channel maps provide a way to associate channels in a stream with a + * speaker. This relieves applications of having to make sure their channel + * order is identical to the final output. + * + * \section init_sec Initialisation + * + * A channel map consists of an array of \ref pa_channel_position values, + * one for each channel. This array is stored together with a channel count + * in a pa_channel_map structure. + * + * Before filling the structure, the application must initialise it using + * pa_channel_map_init(). There are also a number of convenience functions + * for standard channel mappings: + * + * \li pa_channel_map_init_mono() - Create a channel map with only mono audio. + * \li pa_channel_map_init_stereo() - Create a standard stereo mapping. + * \li pa_channel_map_init_auto() - Create a standard channel map for up to + * six channels. + * + * \section conv_sec Convenience functions + * + * The library contains a number of convenience functions for dealing with + * channel maps: + * + * \li pa_channel_map_valid() - Tests if a channel map is valid. + * \li pa_channel_map_equal() - Tests if two channel maps are identical. + * \li pa_channel_map_snprint() - Creates a textual description of a channel + * map. + */ + /** \file * Constants and routines for channel mapping handling */ diff --git a/src/polyp/context.h b/src/polyp/context.h index 89febe92..460034c1 100644 --- a/src/polyp/context.h +++ b/src/polyp/context.h @@ -28,18 +28,116 @@ #include #include +/** \page async Asynchronous API + * + * \section overv_sec Overview + * + * The asynchronous API is the native interface to the polypaudio library. + * It allows full access to all available functions. This also means that + * it is rather complex and can take some time to fully master. + * + * \section mainloop_sec Main loop abstraction + * + * The API is based around an asynchronous event loop, or main loop, + * abstraction. This abstraction contains three basic elements: + * + * \li Deferred events - Events that trigger each iteration of the main loop. + * \li I/O events - Events that trigger on file descriptor activities. + * \li Times events - Events that trigger after a fixed ammount of time. + * + * The abstraction is represented as a number of function pointers in the + * pa_mainloop_api structure. + * + * To actually be able to use these functions, an actual implementation + * be coupled to the abstraction. There are two of these shipped with + * polypaudio, but any other can be used with a minimal ammount of work, + * provided it supports the three basic events listed above. + * + * The implementations shipped with polypaudio are: + * + * \li \subpage mainloop - A minimal but fast implementation based on poll(). + * \li \subpage glib-mainloop - A wrapper around GLIB's main loop. Available + * for both GLIB 1.2 and GLIB 2.x. + * + * UNIX signals may be hooked to a main loop using the functions from + * \ref mainloop-signal.h. These rely only on the main loop abstraction + * and can therefore be used with any of the implementations. + * + * \section refcnt_sec Reference counting + * + * Almost all objects in polypaudio are reference counted. What that means + * is that you rarely malloc() or free() any objects. Instead you increase + * and decrease their reference counts. Whenever an object's reference + * count reaches zero, that object gets destroy and any resources it uses + * get freed. + * + * The benefit of this design is that an application need not worry about + * whether or not it needs to keep an object around in case the library is + * using it internally. If it is, then it has made sure it has its own + * reference to it. + * + * Whenever the library creates an object, it will have an initial + * reference count of one. Most of the time, this single reference will be + * sufficient for the application, so all required reference count + * interaction will be a single call to the objects unref function. + * + * \section context_sec Context + * + * A context is the basic object for a connection to a polypaudio server. + * It multiplexes commands, data streams and events through a single + * channel. + * + * There is no need for more than one context per application, unless + * connections to multiple servers is needed. + * + * \subsection ops_subsec Operations + * + * All operations on the context is performed asynchronously. I.e. the + * client will not wait for the server to complete the request. To keep + * track of all these in-flight operations, the application is given a + * pa_operation object for each asynchronous operation. + * + * There are only two actions (besides reference counting) that can be + * performed on a pa_operation: querying its state with + * pa_operation_get_state() and aborting it with pa_operation_cancel(). + * + * A pa_operation object is reference counted, so an application must + * make sure to unreference it, even if it has no intention of using it. + * + * \subsection conn_subsec Connecting + * + * A context must be connected to a server before any operation can be + * issued. Calling pa_context_connect() will initiate the connection + * procedure. Unlike most asynchronous operations, connecting does not + * result in a pa_operation object. Instead, the application should + * register a callback using pa_context_set_state_callback(). + * + * \subsection disc_subsec Disconnecting + * + * When the sound support is no longer needed, the connection needs to be + * closed using pa_context_disconnect(). This is an immediate function that + * works synchronously. + * + * Since the context object has references to other objects it must be + * disconnected after use or there is a high risk of memory leaks. If the + * connection has terminated by itself, then there is no need to explicitly + * disconnect the context using pa_context_disconnect(). + * + * \section Functions + * + * The sound server's functionality can be divided into a number of + * subsections: + * + * \li \subpage streams + * \li \subpage scache + * \li \subpage introspect + * \li \subpage subscribe + */ + /** \file * Connection contexts for asynchrononous communication with a * server. A pa_context object wraps a connection to a polypaudio - * server using its native protocol. A context may be used to issue - * commands on the server or to create playback or recording - * streams. Multiple playback streams may be piped through a single - * connection context. Operations on the contect involving - * communication with the server are executed asynchronously: i.e. the - * client function do not implicitely wait for completion of the - * operation on the server. Instead the caller specifies a call back - * function that is called when the operation is completed. Currently - * running operations may be canceled using pa_operation_cancel(). */ + * server using its native protocol. */ /** \example pacat.c * A playback and recording tool using the asynchronous API */ diff --git a/src/polyp/glib-mainloop.h b/src/polyp/glib-mainloop.h index b7717685..bc66409b 100644 --- a/src/polyp/glib-mainloop.h +++ b/src/polyp/glib-mainloop.h @@ -27,6 +27,17 @@ #include #include +/** \page glib-mainloop GLIB main loop bindings + * + * \section overv_sec Overview + * + * The GLIB main loop bindings are extremely easy to use. All that is + * required is to create a pa_glib_mainloop object using + * pa_glib_mainloop_new(). When the main loop abstraction is needed, it is + * provided by pa_glib_mainloop_get_api(). + * + */ + /** \file * GLIB main loop support */ diff --git a/src/polyp/introspect.h b/src/polyp/introspect.h index fb05cfb9..5d567836 100644 --- a/src/polyp/introspect.h +++ b/src/polyp/introspect.h @@ -30,22 +30,176 @@ #include #include +/** \page introspect Server query and control + * + * \section overv_sec Overview + * + * Sometimes it is necessary to query and modify global settings in the + * server. For this, Polypaudio has the introspection API. It can list sinks, + * sources, samples and other aspects of the server. It can also modify the + * attributes of the server that will affect operations on a global level, + * and not just the application's context. + * + * \section query_sec Querying + * + * All querying is done through callbacks. This design is necessary to + * maintain an asynchronous design. The client will request the information + * and some time later, the server will respond with the desired data. + * + * Some objects can have multiple entries at the server. When requesting all + * of these at once, the callback will be called multiple times, once for + * each object. When the list has been exhausted, the callback will be called + * without an information structure and the eol parameter set to a non-zero + * value. + * + * Note that even if a single object is requested, and not the entire list, + * the terminating call will still be made. + * + * If an error occurs, the callback will be called without and information + * structure and eol set to zero. + * + * Data members in the information structures are only valid during the + * duration of the callback. If they are required after the callback is + * finished, a deep copy must be performed. + * + * \subsection server_subsec Server information + * + * The server can be queried about its name, the environment it's running on + * and the currently active global defaults. Calling + * pa_context_get_server_info() will get access to a pa_server_info structure + * containing all of these. + * + * \subsection memstat_subsec Memory usage + * + * Statistics about memory usage can be fetched using pa_context_stat(), + * giving a pa_stat_info structure. + * + * \subsection sinksrc_subsec Sinks and sources + * + * The server can have an arbitrary number of sinks and sources. Each sink + * and source have both an index and a name associated with it. As such + * there are three ways to get access to them: + * + * \li By index - pa_context_get_sink_info_by_index() / + * pa_context_get_source_info_by_index() + * \li By name - pa_context_get_sink_info_by_name() / + * pa_context_get_source_info_by_name() + * \li All - pa_context_get_sink_info_list() / + * pa_context_get_source_info_list() + * + * All three method use the same callback and will provide a pa_sink_info or + * pa_source_info structure. + * + * \subsection siso_subsec Sink inputs and source outputs + * + * Sink inputs and source outputs are the representations of the client ends + * of streams inside the server. I.e. they connect a client stream to one of + * the global sinks or sources. + * + * Sink inputs and source outputs only have an index to identify them. As + * such, there are only two ways to get information about them: + * + * \li By index - pa_context_get_sink_input_info() / + * pa_context_get_source_output_info() + * \li All - pa_context_get_sink_input_info_list() / + * pa_context_get_source_output_info_list() + * + * The structure returned is the pa_sink_input_info or pa_source_output_info + * structure. + * + * \subsection samples_subsec Samples + * + * The list of cached samples can be retrieved from the server. Three methods + * exist for querying the sample cache list: + * + * \li By index - pa_context_get_sample_info_by_index() + * \li By name - pa_context_get_sample_info_by_name() + * \li All - pa_context_get_sample_info_list() + * + * Note that this only retrieves information about the sample, not the sample + * data itself. + * + * \subsection module_subsec Modules + * + * Polypaudio modules are identified by index and are retrieved using either + * pa_context_get_module_info() or pa_context_get_module_info_list(). The + * information structure is called pa_module_info. + * + * \subsection autoload_subsec Autoload entries + * + * Modules can be autoloaded as a result of a client requesting a certain + * sink or source. This mapping between sink/source names and modules can be + * queried from the server: + * + * \li By index - pa_context_get_autoload_info_by_index() + * \li By sink/source name - pa_context_get_autoload_info_by_name() + * \li All - pa_context_get_autoload_info_list() + * + * \subsection client_subsec Clients + * + * Polypaudio clients are also identified by index and are retrieved using + * either pa_context_get_client_info() or pa_context_get_client_info_list(). + * The information structure is called pa_client_info. + * + * \section ctrl_sec Control + * + * Some parts of the server are only possible to read, but most can also be + * modified in different ways. Note that these changes will affect all + * connected clients and not just the one issuing the request. + * + * \subsection sinksrc_subsec Sinks and sources + * + * The most common change one would want to do to sinks and sources is to + * modify the volume of the audio. Identical to how sinks and sources can + * be queried, there are two ways of identifying them: + * + * \li By index - pa_context_set_sink_volume_by_index() / + * pa_context_set_source_volume_by_index() + * \li By name - pa_context_set_sink_volume_by_name() / + * pa_context_set_source_volume_by_name() + * + * It is also possible to mute a sink or source: + * + * \li By index - pa_context_set_sink_mute_by_index() / + * pa_context_set_source_mute_by_index() + * \li By name - pa_context_set_sink_mute_by_name() / + * pa_context_set_source_mute_by_name() + * + * \subsection siso_subsec Sink inputs and source outputs + * + * If an application desires to modify the volume of just a single stream + * (commonly one of its own streams), this can be done by setting the volume + * of its associated sink input, using pa_context_set_sink_input_volume(). + * + * There is no support for modifying the volume of source outputs. + * + * It is also possible to remove sink inputs and source outputs, terminating + * the streams associated with them: + * + * \li Sink input - pa_context_kill_sink_input() + * \li Source output - pa_context_kill_source_output() + * + * \subsection module_subsec Modules + * + * Server modules can be remotely loaded and unloaded using + * pa_context_load_module() and pa_context_unload_module(). + * + * \subsection autoload_subsec Autoload entries + * + * New module autoloading rules can be added, and existing can be removed + * using pa_context_add_autoload() and pa_context_remove_autoload_by_index() + * / pa_context_remove_autoload_by_name(). + * + * \subsection client_subsec Clients + * + * The only operation supported on clients, is the possibility of kicking + * them off the server using pa_context_kill_client(). + */ + /** \file * - * Routines for daemon introspection. When enumerating all entitites - * of a certain kind, use the pa_context_xxx_list() functions. The - * specified callback function is called once for each entry. The - * enumeration is finished by a call to the callback function with - * eol=1 and i=NULL. Strings referenced in pa_xxx_info structures and - * the structures themselves point to internal memory that may not be - * modified. That memory is only valid during the call to the callback - * function. A deep copy is required if you need this data outside the - * callback functions. An error is signalled by a call to the callback - * function with i=NULL and eol=0. - * - * When using the routines that ask fo a single entry only, a callback - * with the same signature is used. However, no finishing call to the - * routine is issued. */ + * Routines for daemon introspection. + */ PA_C_DECL_BEGIN @@ -121,7 +275,7 @@ typedef struct pa_server_info { /** Callback prototype for pa_context_get_server_info() */ typedef void (*pa_server_info_cb_t) (pa_context *c, const pa_server_info*i, void *userdata); - +context_ /** Get some information about the server */ pa_operation* pa_context_get_server_info(pa_context *c, pa_server_info_cb_t cb, void *userdata); diff --git a/src/polyp/mainloop.h b/src/polyp/mainloop.h index d0a40914..c06b47d0 100644 --- a/src/polyp/mainloop.h +++ b/src/polyp/mainloop.h @@ -27,6 +27,41 @@ PA_C_DECL_BEGIN +/** \page mainloop Mainloop + * + * \section overv_sec Overview + * + * The built-in main loop implementation is based on the poll() system call. + * It supports the functions defined in the main loop abstraction and very + * little else. + * + * The main loop is created using pa_mainloop_new() and destroyed using + * pa_mainloop_free(). To get access to the main loop abstraction, + * pa_mainloop_get_api() is used. + * + * \section iter_sec Iteration + * + * The main loop is designed around the concept of iterations. Each iteration + * consists of three steps that repeat during the application's entire + * lifetime: + * + * -# Prepare - Dispatch deferred events, build a list of file descriptors + * that need to be monitored and calculate the next timeout. + * -# Poll - Execute the actuall poll() system call. + * -# Dispatch - Dispatch any timeouts and file descriptors that have fired. + * + * When using the main loop, the application can either execute each + * iteration, one at a time, using pa_mainloop_iterate(), or let the library + * iterate automatically using pa_mainloop_run(). + * + * \section thread_sec Threads + * + * The main loop functions are designed to be thread safe, but the objects + * are not. What this means is that multiple main loops can be used, but only + * one object per thread. + * + */ + /** \file * * A minimal main loop implementation based on the C library's poll() diff --git a/src/polyp/polypaudio.h b/src/polyp/polypaudio.h index b70b8d70..af80f9ea 100644 --- a/src/polyp/polypaudio.h +++ b/src/polyp/polypaudio.h @@ -48,43 +48,49 @@ * \section intro_sec Introduction * * This document describes the client API for the polypaudio sound - * server. The API comes in two flavours: + * server. The API comes in two flavours to accomodate different styles + * of applications and different needs in complexity: * * \li The complete but somewhat complicated to use asynchronous API - * \li And the simplified, easy to use, but limited synchronous API + * \li The simplified, easy to use, but limited synchronous API * - * The polypaudio client libraries are thread safe as long as all - * objects created by any library function are accessed from the thread - * that created them only. - * * \section simple_sec Simple API * * Use this if you develop your program in synchronous style and just * need a way to play or record data on the sound server. See - * \ref simple.h for more details. + * \subpage simple for more details. * - * \section async_api Asynchronous API + * \section async_sec Asynchronous API * - * Use this if you develop your programs in asynchronous, main loop - * based style or want to use advanced features of the polypaudio - * API. A good starting point is \ref context.h + * Use this if you develop your programs in asynchronous, event loop + * based style or if you want to use the advanced features of the + * polypaudio API. A guide can be found in \subpage async. * - * The asynchronous API relies on an abstract main loop API that is - * described in \ref mainloop-api.h. Two distinct implementations are - * available: - * - * \li \ref mainloop.h : a minimal but fast implementation based on poll() - * \li \ref glib-mainloop.h : a wrapper around GLIB's main loop + * \section thread_sec Threads + * + * The polypaudio client libraries are not designed to be used in a + * heavily threaded environment. They are however designed to be reentrant + * safe. * - * UNIX signals may be hooked to a main loop using the functions from - * \ref mainloop-signal.h + * To use a the libraries in a threaded environment, you must assure that + * all objects are only used in the same thread they were created in. + * Normally, this means that all objects belonging to a single context + * must be accessed from the same thread. + * + * The included main loop implementation is also not thread safe. Take care + * to make sure event lists are not manipulated when any library code is + * using the main loop. * * \section pkgconfig pkg-config * - * The polypaudio libraries provide pkg-config snippets for the different modules. To use the - * asynchronous API use "polyplib" as pkg-config file. GLIB main loop - * support is available as "glib-mainloop". The simple - * synchronous API is available as "simple". + * The polypaudio libraries provide pkg-config snippets for the different + * modules: + * + * \li polyplib - The asynchronous API and the internal main loop + * implementation. + * \li polyplib-glib12-mainloop - GLIB 1.2 main loop bindings. + * \li polyplib-glib-mainloop - GLIB 2.x main loop bindings. + * \li polyplib-simple - The simple polypaudio API. */ #endif diff --git a/src/polyp/sample.h b/src/polyp/sample.h index db4c6c70..a7abdc3e 100644 --- a/src/polyp/sample.h +++ b/src/polyp/sample.h @@ -28,6 +28,72 @@ #include +/** \page sample Sample format specifications + * + * \section overv_sec Overview + * + * Polypaudio is capable of handling a multitude of sample formats, rates + * and channels, transparently converting and mixing them as needed. + * + * \section format_sec Sample format + * + * Polypaudio supports the following sample formats: + * + * \li PA_SAMPLE_U8 - Unsigned 8 bit PCM. + * \li PA_SAMPLE_S16LE - Signed 16 bit PCM, little endian. + * \li PA_SAMPLE_S16BE - Signed 16 bit PCM, big endian. + * \li PA_SAMPLE_FLOAT32LE - 32 bit IEEE floating point PCM, little endian. + * \li PA_SAMPLE_FLOAT32BE - 32 bit IEEE floating point PCM, big endian. + * \li PA_SAMPLE_ALAW - 8 bit a-Law. + * \li PA_SAMPLE_ULAW - 8 bit mu-Law. + * + * The floating point sample formats have the range from -1 to 1. + * + * The sample formats that are sensitive to endianness have convenience + * macros for native endian (NE), and reverse endian (RE). + * + * \section rate_sec Sample rates + * + * Polypaudio supports any sample rate between 1 Hz and 4 GHz. There is no + * point trying to exceed the sample rate of the output device though as the + * signal will only get downsampled, consuming CPU on the machine running the + * server. + * + * \section chan_sec Channels + * + * Polypaudio supports up to 16 individiual channels. The order of the + * channels is up to the application, but they must be continous. To map + * channels to speakers, see \ref channelmap. + * + * \section calc_sec Calculations + * + * The Polypaudio library contains a number of convenience functions to do + * calculations on sample formats: + * + * \li pa_bytes_per_second() - The number of bytes one second of audio will + * take given a sample format. + * \li pa_frame_size() - The size, in bytes, of one frame (i.e. one set of + * samples, one for each channel). + * \li pa_sample_size() - The size, in bytes, of one sample. + * \li pa_bytes_to_usec() - Calculate the time it would take to play a buffer + * of a certain size. + * + * \section util_sec Convenience functions + * + * The library also contains a couple of other convenience functions: + * + * \li pa_sample_spec_valid() - Tests if a sample format specification is + * valid. + * \li pa_sample_spec_equal() - Tests if the sample format specifications are + * identical. + * \li pa_sample_format_to_string() - Return a textual description of a + * sample format. + * \li pa_parse_sample_format() - Parse a text string into a sample format. + * \li pa_sample_spec_snprint() - Create a textual description of a complete + * sample format specification. + * \li pa_bytes_snprint() - Pretty print a byte value (e.g. 2.5 MB). + */ + /** \file * Constants and routines for sample type handling */ diff --git a/src/polyp/scache.h b/src/polyp/scache.h index cdb47cab..a6b312f5 100644 --- a/src/polyp/scache.h +++ b/src/polyp/scache.h @@ -28,6 +28,49 @@ #include #include +/** \page scache Sample cache + * + * \section overv_sec Overview + * + * The sample cache provides a simple way of overcoming high network latencies + * and reducing bandwidth. Instead of streaming a sound precisely when it + * should be played, it is stored on the server and only the command to start + * playing it needs to be sent. + * + * \section create_sec Creation + * + * To create a sample, the normal stream API is used (see \ref streams). The + * function pa_stream_connect_upload() will make sure the stream is stored as + * a sample on the server. + * + * To complete the upload, pa_stream_finish_upload() is called and the sample + * will receive the same name as the stream. If the upload should be aborted, + * simply call pa_stream_disconnect(). + * + * \section play_sec Playing samples + * + * To play back a sample, simply call pa_context_play_sample(): + * + * \code + * pa_operation *o; + * + * o = pa_context_play_sample(my_context, + * "sample2", // Name of my sample + * NULL, // Use default sink + * PA_VOLUME_NORM, // Full volume + * NULL, // Don't need a callback + * NULL + * ); + * if (o) + * pa_operation_unref(o); + * \endcode + * + * \section rem_sec Removing samples + * + * When a sample is no longer needed, it should be removed on the server to + * save resources. The sample is deleted using pa_context_remove_sample(). + */ + /** \file * All sample cache related routines */ diff --git a/src/polyp/simple.h b/src/polyp/simple.h index 1a139005..d2adde02 100644 --- a/src/polyp/simple.h +++ b/src/polyp/simple.h @@ -28,9 +28,72 @@ #include #include +/** \page simple Simple API + * + * \section overv_sec Overview + * + * The simple API is designed for applications with very basic sound + * playback or capture needs. It can only support a single stream per + * connection and has no handling of complex features like events, channel + * mappings and volume control. It is, however, very simple to use and + * quite sufficent for many programs. + * + * \section conn_sec Connecting + * + * The first step before using the sound system is to connect to the + * server. This is normally done this way: + * + * \code + * pa_simple *s; + * pa_sample_spec ss; + * + * ss.format = S16_NE; + * ss.channels = 2; + * ss.rate = 44100; + * + * s = pa_simple_new(NULL, // Use the default server. + * "Fooapp", // Our application's name. + * PA_STREAM_PLAYBACK, + * NULL, // Use the default device. + * "Music", // Description of our stream. + * &ss, // Our sample format. + * NULL, // Use default buffering attributes. + * NULL, // Ignore error code. + * ); + * \endcode + * + * At this point a connected object is returned, or NULL if there was a + * problem connecting. + * + * \section transfer_sec Transferring data + * + * Once the connection is established to the server, data can start flowing. + * Using the connection is very similar to the normal read() and write() + * system calls. The main difference is that they're call pa_simple_read() + * and pa_simple_write(). Note that these operation are always blocking. + * + * \section ctrl_sec Buffer control + * + * If a playback stream is used then a few other operations are available: + * + * \li pa_simple_drain() - Will wait for all sent data to finish playing. + * \li pa_simple_flush() - Will throw away all data currently in buffers. + * \li pa_simple_get_playback_latency() - Will return the total latency of + * the playback pipeline. + * + * \section cleanup_sec Cleanup + * + * Once playback or capture is complete, the connection should be closed + * and resources freed. This is done through: + * + * \code + * pa_simple_free(s); + * \endcode + */ + /** \file * A simple but limited synchronous playback and recording - * API. This is synchronouse, simplified wrapper around the standard + * API. This is a synchronous, simplified wrapper around the standard * asynchronous API. */ /** \example pacat-simple.c diff --git a/src/polyp/stream.h b/src/polyp/stream.h index ce041986..bb5aa764 100644 --- a/src/polyp/stream.h +++ b/src/polyp/stream.h @@ -31,6 +31,137 @@ #include #include +/** \page streams Audio streams + * + * \section overv_sec Overview + * + * Audio streams form the central functionality of the sound server. Data is + * routed, converted and mixed from several sources before it is passed along + * to a final output. Currently, there are three forms of audio streams: + * + * \li Playback streams - Data flows from the client to the server. + * \li Record streams - Data flows from the server to the client. + * \li Upload streams - Similar to playback streams, but the data is stored in + * the sample cache. See \ref scache for more information + * about controlling the sample cache. + * + * \section create_sec Creating + * + * To access a stream, a pa_stream object must be created using + * pa_stream_new(). At this point the audio sample format and mapping of + * channels must be specified. See \ref sample and \ref channelmap for more + * information about those structures. + * + * This first step will only create a client-side object, representing the + * stream. To use the stream, a server-side object must be created and + * associated with the local object. Depending on which type of stream is + * desired, a different function is needed: + * + * \li Playback stream - pa_stream_connect_playback() + * \li Record stream - pa_stream_connect_record() + * \li Upload stream - pa_stream_connect_upload() (see \ref scache) + * + * Similar to how connections are done in contexts, connecting a stream will + * not generate a pa_operation object. Also like contexts, the application + * should register a state change callback, using + * pa_stream_set_state_callback(), and wait for the stream to enter an active + * state. + * + * \subsection bufattr_subsec Buffer attributes + * + * Playback and record streams always have a buffer as part of the data flow. + * The size of this buffer strikes a compromise between low latency and + * sensitivity for buffer overflows/underruns. + * + * The buffer is described with a pa_buffer_attr structure which contains a + * number of field: + * + * \li maxlength - The absolute maximum number of bytes that can be stored in + * the buffer. If this value is exceeded then data will be + * lost. + * \li tlength - The target length of a playback buffer. The server will only + * send requests for more data as long as the buffer has less + * than this number of bytes of data. + * \li prebuf - Number of bytes that need to be in the buffer before playback + * will commence. Start of playback can be forced using + * pa_stream_trigger() even though the prebuffer size hasn't been + * reached. + * \li minreq - Minimum free number of the bytes in the playback buffer before + * the server will request more data. + * \li fragsize - Maximum number of bytes that the server will push in one + * chunk for record streams. + * + * \section transfer_sec Transferring data + * + * Once the stream is up, data can start flowing between the client and the + * server. Two different access models can be used to transfer the data: + * + * \li Asynchronous - The application register a callback using + * pa_stream_set_write_callback() and + * pa_stream_set_read_callback() to receive notifications + * that data can either be written or read. + * \li Polled - Query the library for available data/space using + * pa_stream_writable_size() and pa_stream_readable_size() and + * transfer data as needed. The sizes are stored locally, in the + * client end, so there is no delay when reading them. + * + * It is also possible to mix the two models freely. + * + * Once there is data/space available, it can be transferred using either + * pa_stream_write() for playback, or pa_stream_peek() / pa_stream_drop() for + * record. Make sure you do not overflow the playback buffers as data will be + * dropped. + * + * \section bufctl_sec Buffer control + * + * The transfer buffers can be controlled through a number of operations: + * + * \li pa_stream_cork() - Start or stop the playback or recording. + * \li pa_stream_trigger() - Start playback immediatly and do not wait for + * the buffer to fill up to the set trigger level. + * \li pa_stream_prebuf() - Reenable the playback trigger level. + * \li pa_stream_drain() - Wait for the playback buffer to go empty. Will + * return a pa_operation object that will indicate when + * the buffer is completely drained. + * \li pa_stream_flush() - Drop all data from the playback buffer and do not + * wait for it to finish playing. + * + * \section latency_sec Latency + * + * A major problem with networked audio is the increased latency caused by + * the network. To remedy this, Polypaudio supports an advanced system of + * monitoring the current latency. + * + * To get the raw data needed to calculate latencies, call + * pa_stream_get_timing_info(). This will give you a pa_timing_info structure + * that contains everything that is known about buffers, transport delays + * and the backend active in the server. + * + * If a more simplistic interface is prefered, you can call + * pa_stream_get_time() or pa_stream_get_latency(). These will do all the + * necessary calculations for you. + * + * The latency information is constantly updated from the server. Be aware + * that between updates, old data will be returned. If you specify the flag + * PA_STREAM_INTERPOLATE_TIMING when creating the stream, pa_stream_get_time() + * and pa_stream_get_latency() will calculate the latency between updates + * based on the time elapsed. + * + * \section flow_sec Overflow and underflow + * + * Even with the best precautions, buffers will sometime over- or underflow. + * To handle this gracefully, the application can be notified when this + * happens. Callbacks are registered using pa_stream_set_overflow_callback() + * and pa_stream_set_underflow_callback(). + * + * \section disc_sec Disconnecting + * + * When a stream has served is purpose it must be disconnected with + * pa_stream_disconnect(). If you only unreference it, then it will live on + * and eat resources both locally and on the server until you disconnect the + * context. + */ + /** \file * Audio streams for input, output and sample upload */ diff --git a/src/polyp/subscribe.h b/src/polyp/subscribe.h index 5301739a..75b4696f 100644 --- a/src/polyp/subscribe.h +++ b/src/polyp/subscribe.h @@ -28,11 +28,22 @@ #include #include +/** \page subscribe Event subscription + * + * \section overv_sec Overview + * + * The application can be notified, asynchronously, whenever the internal + * layout of the server changes. Possible notifications are desribed in the + * \ref pa_subscription_event_type and \ref pa_subscription_mask + * enumerations. + * + * The application sets the notification mask using pa_context_subscribe() + * and the function that will be called whenever a notification occurs using + * pa_context_set_subscribe_callback(). + */ + /** \file - * Daemon introspection event subscription subsystem. Use this - * to be notified whenever the internal layout of daemon changes: - * i.e. entities such as sinks or sources are create, removed or - * modified. */ + * Daemon introspection event subscription subsystem. */ PA_C_DECL_BEGIN diff --git a/src/polyp/volume.h b/src/polyp/volume.h index d1e858c4..181784f4 100644 --- a/src/polyp/volume.h +++ b/src/polyp/volume.h @@ -26,6 +26,59 @@ #include #include +/** \page volume Volume control + * + * \section overv_sec Overview + * + * Sinks, sources, sink inputs and samples can all have their own volumes. + * To deal with these, The Polypaudio libray contains a number of functions + * that ease handling. + * + * The basic volume type in Polypaudio is the \ref pa_volume_t type. Most of + * the time, applications will use the aggregated pa_cvolume structure that + * can store the volume of all channels at once. + * + * Volumes commonly span between muted (0%), and normal (100%). It is possible + * to set volumes to higher than 100%, but clipping might occur. + * + * \section calc_sec Calculations + * + * The volumes in Polypaudio are logarithmic in nature and applications + * shouldn't perform calculations with them directly. Instead, they should + * be converted to and from either dB or a linear scale: + * + * \li dB - pa_sw_volume_from_dB() / pa_sw_volume_to_dB() + * \li Linear - pa_sw_volume_from_linear() / pa_sw_volume_to_linear() + * + * For simple multiplication, pa_sw_volume_multiply() and + * pa_sw_cvolume_multiply() can be used. + * + * Calculations can only be reliably be performed on software volumes as + * it is commonly unknown what scale hardware volumes use. + * + * \section conv_sec Convenience functions + * + * To handle the pa_cvolume structure, the Polypaudio library provides a + * number of convenienc functions: + * + * \li pa_cvolume_valid() - Tests if a pa_cvolume structure is valid. + * \li pa_cvolume_equal() - Tests if two pa_cvolume structures are identical. + * \li pa_cvolume_channels_equal_to() - Tests if all channels of a pa_cvolume + * structure have a given volume. + * \li pa_cvolume_is_muted() - Tests if all channels of a pa_cvolume + * structure are muted. + * \li pa_cvolume_is_norm() - Tests if all channels of a pa_cvolume structure + * are at a normal volume. + * \li pa_cvolume_set() - Set all channels of a pa_cvolume structure to a + * certain volume. + * \li pa_cvolume_reset() - Set all channels of a pa_cvolume structure to a + * normal volume. + * \li pa_cvolume_mute() - Set all channels of a pa_cvolume structure to a + * muted volume. + * \li pa_cvolume_avg() - Return the average volume of all channels. + * \li pa_cvolume_snprint() - Pretty print a pa_cvolume structure. + */ + /** \file * Constants and routines for volume handling */ -- cgit From 0d200ee74345367d5285db59fc32c190146bdcb5 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 9 Apr 2006 19:32:16 +0000 Subject: Use the modern Ki/Mi/Gi prefixes to clarify that 1024 is the base. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@668 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/sample.c | 6 +++--- src/polyp/sample.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/polyp/sample.c b/src/polyp/sample.c index d587170c..668a485e 100644 --- a/src/polyp/sample.c +++ b/src/polyp/sample.c @@ -115,11 +115,11 @@ char *pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec) { void pa_bytes_snprint(char *s, size_t l, unsigned v) { if (v >= ((unsigned) 1024)*1024*1024) - snprintf(s, l, "%0.1f GB", ((double) v)/1024/1024/1024); + snprintf(s, l, "%0.1f GiB", ((double) v)/1024/1024/1024); else if (v >= ((unsigned) 1024)*1024) - snprintf(s, l, "%0.1f MB", ((double) v)/1024/1024); + snprintf(s, l, "%0.1f MiB", ((double) v)/1024/1024); else if (v >= (unsigned) 1024) - snprintf(s, l, "%0.1f KB", ((double) v)/1024); + snprintf(s, l, "%0.1f KiB", ((double) v)/1024); else snprintf(s, l, "%u B", (unsigned) v); } diff --git a/src/polyp/sample.h b/src/polyp/sample.h index a7abdc3e..284b428b 100644 --- a/src/polyp/sample.h +++ b/src/polyp/sample.h @@ -91,7 +91,7 @@ * \li pa_parse_sample_format() - Parse a text string into a sample format. * \li pa_sample_spec_snprint() - Create a textual description of a complete * sample format specification. - * \li pa_bytes_snprint() - Pretty print a byte value (e.g. 2.5 MB). + * \li pa_bytes_snprint() - Pretty print a byte value (e.g. 2.5 MiB). */ /** \file @@ -178,7 +178,7 @@ pa_sample_format_t pa_parse_sample_format(const char *format); /** Pretty print a sample type specification to a string */ char* pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec); -/** Pretty print a byte size value. (i.e. "2.5 MB") */ +/** Pretty print a byte size value. (i.e. "2.5 MiB") */ void pa_bytes_snprint(char *s, size_t l, unsigned v); PA_C_DECL_END -- cgit From f4119adc8ed7a137a71d60010c129be286cb5a3f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 10 Apr 2006 16:40:29 +0000 Subject: unbreak last commit from ossman git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@669 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/introspect.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polyp/introspect.h b/src/polyp/introspect.h index 5d567836..a8292ba1 100644 --- a/src/polyp/introspect.h +++ b/src/polyp/introspect.h @@ -275,7 +275,7 @@ typedef struct pa_server_info { /** Callback prototype for pa_context_get_server_info() */ typedef void (*pa_server_info_cb_t) (pa_context *c, const pa_server_info*i, void *userdata); -context_ + /** Get some information about the server */ pa_operation* pa_context_get_server_info(pa_context *c, pa_server_info_cb_t cb, void *userdata); -- cgit From 35ea8aca7de8b513917feecee43967b8f030b43c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 10 Apr 2006 17:17:36 +0000 Subject: update TODO git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@670 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/todo b/doc/todo index 5e635748..205be4e5 100644 --- a/doc/todo +++ b/doc/todo @@ -7,6 +7,9 @@ Test: Fixes: - module-oss-* love: - improve latency measurement for mmap +- add a client API for setting the "muted" status of devices +- split PA_STREAM_INTERPOLATE_TIMING and PA_STREAM_AUTO_TIMING_UPDATE +- correct API docs regarding timing work Post 0.8: - alsa mmap driver -- cgit From 4496954514af459a74b6bca692780a64c5599106 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 10 Apr 2006 17:22:10 +0000 Subject: Lennart is blind git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@671 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index 205be4e5..a6d3f6c4 100644 --- a/doc/todo +++ b/doc/todo @@ -7,7 +7,6 @@ Test: Fixes: - module-oss-* love: - improve latency measurement for mmap -- add a client API for setting the "muted" status of devices - split PA_STREAM_INTERPOLATE_TIMING and PA_STREAM_AUTO_TIMING_UPDATE - correct API docs regarding timing work -- cgit From 190a8691326513d8d6e407b3fdded842f8661a52 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 10 Apr 2006 17:38:46 +0000 Subject: add new PA_STREAM_AUTO_TIMING_UPDATE git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@672 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/def.h | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/polyp/def.h b/src/polyp/def.h index 1a7a20c3..eadddf08 100644 --- a/src/polyp/def.h +++ b/src/polyp/def.h @@ -82,18 +82,16 @@ typedef enum pa_stream_flags { PA_STREAM_START_CORKED = 1, /**< Create the stream corked, requiring an explicit pa_stream_cork() call to uncork it. */ PA_STREAM_INTERPOLATE_TIMING = 2, /**< Interpolate the latency for * this stream. When enabled, - * pa_stream_get_latency() and pa_stream_get_time() - * will try to estimate the - * current record/playback time - * based on the local time that - * passed since the last timing - * info update. In addition - * timing update requests are - * issued periodically - * automatically. Using this - * option has the advantage of - * not requiring a whole - * roundtrip when the current + * pa_stream_get_latency() and + * pa_stream_get_time() will try + * to estimate the current + * record/playback time based on + * the local time that passed + * since the last timing info + * update. Using this option + * has the advantage of not + * requiring a whole roundtrip + * when the current * playback/recording time is * needed. Consider using this * option when requesting @@ -101,7 +99,10 @@ typedef enum pa_stream_flags { * frequently. This is * especially useful on long * latency network - * connections. */ + * connections. It makes a lot + * of sense to combine this + * option with + * PA_STREAM_AUTO_TIMING_UPDATE. */ PA_STREAM_NOT_MONOTONOUS = 4, /**< Don't force the time to * increase monotonically. If * this option is enabled, @@ -118,6 +119,16 @@ typedef enum pa_stream_flags { * ahead can be corrected * quickly, without the need to * wait. */ + PA_STREAM_AUTO_TIMING_UPDATE = 8 /** If set timing update requests + * are issued periodically + * automatically. Combined with + * PA_STREAM_INTERPOLATE_TIMING + * you will be able to query the + * current time and latency with + * pa_stream_get_time() and + * pa_stream_get_latency() at + * all times without a packet + * round trip.*/ } pa_stream_flags_t; /** Playback and record buffer metrics */ -- cgit From 137f0a7140271b1151b1d97e1863d237e8458316 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 10 Apr 2006 17:39:24 +0000 Subject: * implement PA_STREAM_AUTO_TIMING_UPDATE * accept PA_STREAM_NOT_MONOTONOUS properly git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@673 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/stream.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/polyp/stream.c b/src/polyp/stream.c index 4a98dd60..0fcc36b7 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -372,7 +372,7 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED pa_stream_ref(s); if (s->direction != PA_STREAM_UPLOAD && - s->flags & PA_STREAM_INTERPOLATE_TIMING) { + s->flags & PA_STREAM_AUTO_TIMING_UPDATE) { struct timeval tv; pa_gettimeofday(&tv); @@ -407,7 +407,11 @@ static int create_stream( assert(s->ref >= 1); PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, !(flags & ~(PA_STREAM_START_CORKED|PA_STREAM_INTERPOLATE_TIMING)), PA_ERR_INVALID); + PA_CHECK_VALIDITY(s->context, !(flags & ~((direction != PA_STREAM_UPLOAD ? + PA_STREAM_START_CORKED| + PA_STREAM_INTERPOLATE_TIMING| + PA_STREAM_NOT_MONOTONOUS| + PA_STREAM_AUTO_TIMING_UPDATE : 0))), PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, direction == PA_STREAM_PLAYBACK || flags == 0, PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, !volume || volume->channels == s->sample_spec.channels, PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, !sync_stream || (direction == PA_STREAM_PLAYBACK && sync_stream->direction == PA_STREAM_PLAYBACK), PA_ERR_INVALID); @@ -621,7 +625,7 @@ size_t pa_stream_writable_size(pa_stream *s) { assert(s->ref >= 1); PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (size_t) -1); - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, (size_t) -1); + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_RECORD, PA_ERR_BADSTATE, (size_t) -1); return s->requested_bytes; } @@ -952,7 +956,7 @@ pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, voi PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - if (s->flags & PA_STREAM_INTERPOLATE_TIMING) { + if (s->flags & PA_STREAM_AUTO_TIMING_UPDATE) { if (!s->corked && b) { /* Refresh the interpolated data just befor pausing */ pa_stream_get_time(s, NULL); -- cgit From 6a3b8aeb3fa43c69ca7ad1b89e35040fb5834751 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 10 Apr 2006 17:42:32 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@674 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index a6d3f6c4..81d4f863 100644 --- a/doc/todo +++ b/doc/todo @@ -7,7 +7,6 @@ Test: Fixes: - module-oss-* love: - improve latency measurement for mmap -- split PA_STREAM_INTERPOLATE_TIMING and PA_STREAM_AUTO_TIMING_UPDATE - correct API docs regarding timing work Post 0.8: -- cgit From 93327083d9273bcf2d6ce94b61449c181dcf6fa2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 10 Apr 2006 19:42:14 +0000 Subject: when using record mode, allow file to save data to to be passed on the command line git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@675 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pacat.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 441e2607..e721befa 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -517,25 +517,25 @@ int main(int argc, char *argv[]) { fprintf(stderr, "Opening a %s stream with sample specification '%s'.\n", mode == RECORD ? "recording" : "playback", t); } - if (optind+1 < argc) { - fprintf(stderr, "Too many arguments.\n"); - goto quit; - } - - if (optind+1 == argc) { - int fd; - - if ((fd = open(argv[optind], O_RDONLY)) < 0) { - fprintf(stderr, "open(): %s\n", strerror(errno)); - goto quit; - } - - if (dup2(fd, 0) < 0) { - fprintf(stderr, "dup2(): %s\n", strerror(errno)); + if (!(optind >= argc)) { + if (optind+1 == argc) { + int fd; + + if ((fd = open(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT)) < 0) { + fprintf(stderr, "open(): %s\n", strerror(errno)); + goto quit; + } + + if (dup2(fd, mode == PLAYBACK ? 0 : 1) < 0) { + fprintf(stderr, "dup2(): %s\n", strerror(errno)); + goto quit; + } + + close(fd); + } else { + fprintf(stderr, "Too many arguments.\n"); goto quit; } - - close(fd); } /* Set up a new main loop */ -- cgit From 8f2d9aeb9544b128249c2126e561d10ff5d498ad Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 10 Apr 2006 19:42:44 +0000 Subject: minor cleanups for OSS module git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@676 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 52427592..d9980d82 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -51,7 +51,17 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("OSS Sink/Source") PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= fragments= fragment_size=") +PA_MODULE_USAGE( + "sink_name= " + "source_name= " + "device= " + "record= " + "playback= " + "format= " + "channels= " + "rate= " + "fragments= " + "fragment_size=") struct userdata { pa_sink *sink; @@ -85,6 +95,8 @@ static const char* const valid_modargs[] = { #define DEFAULT_SINK_NAME "oss_output" #define DEFAULT_SOURCE_NAME "oss_input" #define DEFAULT_DEVICE "/dev/dsp" +#define DEFAULT_NFRAGS 12 +#define DEFAULT_FRAGSIZE 1024 static void update_usage(struct userdata *u) { pa_module_set_used(u->module, @@ -332,9 +344,9 @@ int pa__init(pa_core *c, pa_module*m) { } mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); - - nfrags = 12; - frag_size = 1024; + + nfrags = DEFAULT_NFRAGS; + frag_size = DEFAULT_FRAGSIZE; if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { pa_log(__FILE__": failed to parse fragments arguments"); goto fail; @@ -387,8 +399,9 @@ int pa__init(pa_core *c, pa_module*m) { } if (mode != O_WRONLY) { - u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); - assert(u->source); + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL))) + goto fail; + u->source->userdata = u; u->source->notify = source_notify_cb; u->source->get_latency = source_get_latency_cb; @@ -404,8 +417,9 @@ int pa__init(pa_core *c, pa_module*m) { u->source = NULL; if (mode != O_RDONLY) { - u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); - assert(u->sink); + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) + goto fail; + u->sink->get_latency = sink_get_latency_cb; u->sink->get_hw_volume = sink_get_hw_volume; u->sink->set_hw_volume = sink_set_hw_volume; @@ -471,7 +485,9 @@ fail: void pa__done(pa_core *c, pa_module*m) { struct userdata *u; - assert(c && m); + + assert(c); + assert(m); if (!(u = m->userdata)) return; -- cgit From 021744debbe2284085cd8eec3f3724f540e30551 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 10 Apr 2006 19:43:51 +0000 Subject: * Beef up latency calculation in module-oss-mmap * Add recording latency code for module-oss-mmap * other cleanups git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@677 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss-mmap.c | 102 +++++++++++++++++++++++++++++++++--------- 1 file changed, 81 insertions(+), 21 deletions(-) diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index 0ed2af93..5389a201 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -52,7 +52,17 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("OSS Sink/Source (mmap)") PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= fragments= fragment_size=") +PA_MODULE_USAGE( + "sink_name= " + "source_name= " + "device= " + "record= " + "playback= " + "format= " + "channels= " + "rate= " + "fragments= " + "fragment_size=") struct userdata { pa_sink *sink; @@ -60,7 +70,8 @@ struct userdata { pa_core *core; pa_sample_spec sample_spec; - size_t in_fragment_size, out_fragment_size, in_fragments, out_fragments, out_fill; + size_t in_fragment_size, out_fragment_size, in_fragments, out_fragments; + int out_blocks_saved, in_blocks_saved; int fd; @@ -91,6 +102,8 @@ static const char* const valid_modargs[] = { #define DEFAULT_SINK_NAME "oss_output" #define DEFAULT_SOURCE_NAME "oss_input" #define DEFAULT_DEVICE "/dev/dsp" +#define DEFAULT_NFRAGS 12 +#define DEFAULT_FRAGSIZE 1024 static void update_usage(struct userdata *u) { pa_module_set_used(u->module, @@ -134,8 +147,9 @@ static void do_write(struct userdata *u) { return; } - u->out_fill = (u->out_fragment_size * u->out_fragments) - (info.ptr % u->out_fragment_size); - + info.blocks += u->out_blocks_saved; + u->out_blocks_saved = 0; + if (!info.blocks) return; @@ -196,6 +210,9 @@ static void do_read(struct userdata *u) { return; } + info.blocks += u->in_blocks_saved; + u->in_blocks_saved = 0; + if (!info.blocks) return; @@ -215,10 +232,48 @@ static void io_callback(pa_mainloop_api *m, pa_io_event *e, PA_GCC_UNUSED int fd static pa_usec_t sink_get_latency_cb(pa_sink *s) { struct userdata *u = s->userdata; + struct count_info info; + size_t bpos, n; assert(s && u); - do_write(u); - return pa_bytes_to_usec(u->out_fill, &s->sample_spec); + if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { + pa_log(__FILE__": SNDCTL_DSP_GETOPTR: %s", strerror(errno)); + return 0; + } + + u->out_blocks_saved += info.blocks; + + bpos = ((u->out_current + u->out_blocks_saved) % u->out_fragments) * u->out_fragment_size; + + if (bpos < (size_t) info.ptr) + n = (u->out_fragments * u->out_fragment_size) - (info.ptr - bpos); + else + n = bpos - info.ptr; + + return pa_bytes_to_usec(n, &s->sample_spec); +} + +static pa_usec_t source_get_latency_cb(pa_source *s) { + struct userdata *u = s->userdata; + struct count_info info; + size_t bpos, n; + assert(s && u); + + if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { + pa_log(__FILE__": SNDCTL_DSP_GETIPTR: %s", strerror(errno)); + return 0; + } + + u->in_blocks_saved += info.blocks; + + bpos = ((u->in_current + u->in_blocks_saved) % u->in_fragments) * u->in_fragment_size; + + if (bpos < (size_t) info.ptr) + n = info.ptr - bpos; + else + n = (u->in_fragments * u->in_fragment_size) - bpos + info.ptr; + + return pa_bytes_to_usec(n, &s->sample_spec); } static int sink_get_hw_volume(pa_sink *s) { @@ -283,7 +338,7 @@ int pa__init(pa_core *c, pa_module*m) { assert(c); assert(m); - m->userdata = u = pa_xmalloc0(sizeof(struct userdata)); + m->userdata = u = pa_xnew0(struct userdata, 1); u->module = m; u->fd = -1; u->core = c; @@ -305,8 +360,8 @@ int pa__init(pa_core *c, pa_module*m) { mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); - nfrags = 12; - frag_size = 1024; + nfrags = DEFAULT_NFRAGS; + frag_size = DEFAULT_FRAGSIZE; if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { pa_log(__FILE__": failed to parse fragments arguments"); goto fail; @@ -321,11 +376,6 @@ int pa__init(pa_core *c, pa_module*m) { if ((u->fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0) goto fail; - if (pa_oss_get_hw_description(p, hwdesc, sizeof(hwdesc)) >= 0) - pa_log_info(__FILE__": hardware name is '%s'.", hwdesc); - else - hwdesc[0] = 0; - if (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_REALTIME) || !(caps & DSP_CAP_TRIGGER)) { pa_log(__FILE__": OSS device not mmap capable."); goto fail; @@ -333,6 +383,11 @@ int pa__init(pa_core *c, pa_module*m) { pa_log_info(__FILE__": device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + if (pa_oss_get_hw_description(p, hwdesc, sizeof(hwdesc)) >= 0) + pa_log_info(__FILE__": hardware name is '%s'.", hwdesc); + else + hwdesc[0] = 0; + if (nfrags >= 2 && frag_size >= 1) if (pa_oss_set_fragments(u->fd, nfrags, frag_size) < 0) goto fail; @@ -359,11 +414,13 @@ int pa__init(pa_core *c, pa_module*m) { } } else { - u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec, NULL); - assert(u->source); + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec, NULL))) + goto fail; + + u->source->userdata = u; + u->source->get_latency = source_get_latency_cb; u->source->get_hw_volume = source_get_hw_volume; u->source->set_hw_volume = source_set_hw_volume; - u->source->userdata = u; pa_source_set_owner(u->source, m); u->source->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'%s%s%s", p, @@ -371,7 +428,7 @@ int pa__init(pa_core *c, pa_module*m) { hwdesc[0] ? hwdesc : "", hwdesc[0] ? ")" : ""); - u->in_memblocks = pa_xmalloc0(sizeof(pa_memblock *)*u->in_fragments); + u->in_memblocks = pa_xnew0(pa_memblock*, u->in_fragments); enable_bits |= PCM_ENABLE_INPUT; } @@ -397,8 +454,9 @@ int pa__init(pa_core *c, pa_module*m) { } else { pa_silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec); - u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec, NULL); - assert(u->sink); + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec, NULL))) + goto fail; + u->sink->get_latency = sink_get_latency_cb; u->sink->get_hw_volume = sink_get_hw_volume; u->sink->set_hw_volume = sink_set_hw_volume; @@ -453,7 +511,9 @@ fail: void pa__done(pa_core *c, pa_module*m) { struct userdata *u; - assert(c && m); + + assert(c); + assert(m); if (!(u = m->userdata)) return; -- cgit From 09589a75a466e019a2d7dca99f6cae4a3d598e55 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 10 Apr 2006 19:44:11 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@678 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/todo b/doc/todo index 81d4f863..3613217c 100644 --- a/doc/todo +++ b/doc/todo @@ -5,8 +5,6 @@ Test: - module-tunnel Fixes: -- module-oss-* love: - - improve latency measurement for mmap - correct API docs regarding timing work Post 0.8: -- cgit From a81209f147c5aa701efda0c911229a0fd6948fc9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 10 Apr 2006 20:38:58 +0000 Subject: validity checks for pa_context_is_pending() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@679 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/context.c | 5 ++--- src/polyp/stream.c | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/polyp/context.c b/src/polyp/context.c index 845e88d9..6fe008ea 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -728,9 +728,8 @@ int pa_context_is_pending(pa_context *c) { assert(c); assert(c->ref >= 1); -/* pa_log("pstream: %i", pa_pstream_is_pending(c->pstream)); */ -/* pa_log("pdispatch: %i", pa_pdispatch_is_pending(c->pdispatch)); */ - + PA_CHECK_VALIDITY_RETURN_ANY(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE, -1); + return (c->pstream && pa_pstream_is_pending(c->pstream)) || (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) || c->client; diff --git a/src/polyp/stream.c b/src/polyp/stream.c index 0fcc36b7..ca107750 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -1235,5 +1235,3 @@ const pa_channel_map* pa_stream_get_channel_map(pa_stream *s) { return &s->channel_map; } - - -- cgit From b2668ca063bc37377c324d507a3986879d0dc614 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 10 Apr 2006 20:43:24 +0000 Subject: return the error code and not just -1 when pa_context_is_pending() fails git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@680 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polyp/context.c b/src/polyp/context.c index 6fe008ea..c16b54b4 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -728,7 +728,7 @@ int pa_context_is_pending(pa_context *c) { assert(c); assert(c->ref >= 1); - PA_CHECK_VALIDITY_RETURN_ANY(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE, -1); + PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); return (c->pstream && pa_pstream_is_pending(c->pstream)) || (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) || -- cgit From 268c857381810fcfc52da46acc617bbc7e97e5a8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 10 Apr 2006 21:15:39 +0000 Subject: unbreak fresh SVN builds git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@681 fefdeb5f-60dc-0310-8127-8f9354f1896f --- bootstrap.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap.sh b/bootstrap.sh index 7fa1dc9a..31f3868a 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -52,7 +52,7 @@ else test "x$LIBTOOLIZE" = "x" && LIBTOOLIZE=libtoolize - "$LIBTOOLIZE" -c --force + "$LIBTOOLIZE" -c --force --ltdl run_versioned aclocal "$VERSION" run_versioned autoconf 2.59 -Wall run_versioned autoheader 2.59 -- cgit From 64d0d9bfbfc3cd89f0d8843e2e9181568dac2914 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Apr 2006 17:09:22 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@682 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/todo b/doc/todo index 3613217c..10be043b 100644 --- a/doc/todo +++ b/doc/todo @@ -6,6 +6,7 @@ Test: Fixes: - correct API docs regarding timing work +- incorporate client memblockq into latency calculations for recording streamings Post 0.8: - alsa mmap driver -- cgit From a0c7ca00e73708844fdb68f63e616e843c828fd8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Apr 2006 17:09:51 +0000 Subject: when flushin a memblockq, set the write index to the read index git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@683 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/memblockq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/polypcore/memblockq.c b/src/polypcore/memblockq.c index 517495eb..90e1d9eb 100644 --- a/src/polypcore/memblockq.c +++ b/src/polypcore/memblockq.c @@ -548,6 +548,8 @@ void pa_memblockq_flush(pa_memblockq *bq) { assert(bq->n_blocks == 0); + bq->write_index = bq->read_index; + pa_memblockq_prebuf_force(bq); } -- cgit From b5d177d90bea33237bb8c55320c2595ba12b0550 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Apr 2006 17:10:25 +0000 Subject: proper validity checking for pa_context_is_pending() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@684 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/context.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/polyp/context.c b/src/polyp/context.c index c16b54b4..7c0ed190 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -728,7 +728,11 @@ int pa_context_is_pending(pa_context *c) { assert(c); assert(c->ref >= 1); - PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(c, + c->state == PA_CONTEXT_CONNECTING || + c->state == PA_CONTEXT_AUTHORIZING || + c->state == PA_CONTEXT_SETTING_NAME || + c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); return (c->pstream && pa_pstream_is_pending(c->pstream)) || (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) || -- cgit From 77c2a1f561e8995ad62a38dfe1586577d5e93377 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Apr 2006 17:12:16 +0000 Subject: protocol change: don't send stream buffer size in latency update. This data is redundant, since it can be calculated from write_index - read_index anyway git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@685 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-native.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 51280c84..2aedd390 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -1060,7 +1060,6 @@ static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); reply = reply_new(tag); - pa_tagstruct_put_usec(reply, pa_sink_input_get_latency(s->sink_input)); pa_tagstruct_put_usec(reply, pa_sink_get_latency(s->sink_input->sink)); pa_tagstruct_put_usec(reply, 0); pa_tagstruct_put_boolean(reply, pa_memblockq_is_readable(s->memblockq)); @@ -1091,7 +1090,6 @@ static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); reply = reply_new(tag); - pa_tagstruct_put_usec(reply, pa_source_output_get_latency(s->source_output)); pa_tagstruct_put_usec(reply, s->source_output->source->monitor_of ? pa_sink_get_latency(s->source_output->source->monitor_of) : 0); pa_tagstruct_put_usec(reply, pa_source_get_latency(s->source_output->source)); pa_tagstruct_put_boolean(reply, 0); -- cgit From 49b3150434ee97fbcee33948053ffbf33a7b5505 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Apr 2006 17:17:23 +0000 Subject: * rename "latency correction" to "write index correction" * add read index invalidation code * rename "ipol_event" stuff to "auto_timing_update" * remove buffer_usec field from pa_timing_info, since it can be easily calculated from write_index and read_index anyway * add read_index_corrupt field to "pa_timing_info", similar to the already existing write_index_corrupt field * restart automatic timing update event every time a query is issued, not just when the last event elapsed * proper invalidation code for pa_stream_flush() * do tarsnport/sink/source latency correction for playback time only when device is not corked git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@686 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/def.h | 23 ++-- src/polyp/internal.h | 21 ++-- src/polyp/stream.c | 306 +++++++++++++++++++++++++++++++-------------------- 3 files changed, 216 insertions(+), 134 deletions(-) diff --git a/src/polyp/def.h b/src/polyp/def.h index eadddf08..432bd8ce 100644 --- a/src/polyp/def.h +++ b/src/polyp/def.h @@ -204,13 +204,14 @@ typedef enum pa_subscription_event_type { * pa_stream_update_timing_info() and pa_stream_get_timing_info(). The * total output latency a sample that is written with * pa_stream_write() takes to be played may be estimated by - * sink_usec+buffer_usec+transport_usec. The output buffer to which - * buffer_usec relates may be manipulated freely (with + * sink_usec+buffer_usec+transport_usec. (where buffer_usec is defined + * as pa_bytes_to_usec(write_index-read_index)) The output buffer + * which buffer_usec relates to may be manipulated freely (with * pa_stream_write()'s seek argument, pa_stream_flush() and friends), * the buffers sink_usec and source_usec relate to are first-in - * first-out (FIFO) buffers which cannot be flushed or manipulated in any - * way. The total input latency a sample that is recorded takes to be - * delivered to the application is: + * first-out (FIFO) buffers which cannot be flushed or manipulated in + * any way. The total input latency a sample that is recorded takes to + * be delivered to the application is: * source_usec+buffer_usec+transport_usec-sink_usec. (Take care of * sign issues!) When connected to a monitor source sink_usec contains * the latency of the owning sink. The two latency estimations @@ -226,7 +227,6 @@ typedef struct pa_timing_info { * limited und unreliable itself. \since * 0.5 */ - pa_usec_t buffer_usec; /**< Time in usecs the current buffer takes to play. For both playback and record streams. */ pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. For playback streams and record streams connected to a monitor source. */ pa_usec_t source_usec; /**< Time in usecs a sample takes from being recorded to being delivered to the application. Only for record streams. \since 0.5*/ pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to/from the daemon. For both playback and record streams. \since 0.5 */ @@ -240,14 +240,21 @@ typedef struct pa_timing_info { * info was current . Only write * commands with SEEK_RELATIVE_ON_READ * and SEEK_RELATIVE_END can corrupt - * write_index. */ + * write_index. \since 0.8 */ int64_t write_index; /**< Current write index into the * playback buffer in bytes. Think twice before * using this for seeking purposes: it * might be out of date a the time you * want to use it. Consider using * PA_SEEK_RELATIVE instead. \since - * 0.8 */ + * 0.8 */ + + int read_index_corrupt; /**< Non-zero if read_index is not + * up-to-date because a local pause or + * flush request that corrupted it has + * been issued in the time since this + * latency info was current. \since 0.8 */ + int64_t read_index; /**< Current read index into the * playback buffer in bytes. Think twice before * using this for seeking purposes: it diff --git a/src/polyp/internal.h b/src/polyp/internal.h index 3b85b3d1..2bec0294 100644 --- a/src/polyp/internal.h +++ b/src/polyp/internal.h @@ -83,14 +83,14 @@ struct pa_context { pa_client_conf *conf; }; -#define PA_MAX_LATENCY_CORRECTIONS 10 +#define PA_MAX_WRITE_INDEX_CORRECTIONS 10 -typedef struct pa_latency_correction { +typedef struct pa_index_correction { uint32_t tag; int valid; int64_t value; int absolute, corrupt; -} pa_latency_correction; +} pa_index_correction; struct pa_stream { int ref; @@ -124,13 +124,18 @@ struct pa_stream { /* Use to make sure that time advances monotonically */ pa_usec_t previous_time; - /* Latency correction stuff */ - pa_latency_correction latency_corrections[PA_MAX_LATENCY_CORRECTIONS]; - int idx_latency_correction; + /* time updates with tags older than these are invalid */ + uint32_t write_index_not_before; + uint32_t read_index_not_before; + + /* Data about individual timing update correctoins */ + pa_index_correction write_index_corrections[PA_MAX_WRITE_INDEX_CORRECTIONS]; + int current_write_index_correction; /* Latency interpolation stuff */ - pa_time_event *ipol_event; - int ipol_requested; + pa_time_event *auto_timing_update_event; + int auto_timing_update_requested; + pa_usec_t ipol_usec; int ipol_usec_valid; struct timeval ipol_timestamp; diff --git a/src/polyp/stream.c b/src/polyp/stream.c index ca107750..b3f19d09 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -90,19 +90,22 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->previous_time = 0; s->timing_info_valid = 0; + s->read_index_not_before = 0; + s->write_index_not_before = 0; + for (i = 0; i < PA_MAX_WRITE_INDEX_CORRECTIONS; i++) + s->write_index_corrections[i].valid = 0; + s->current_write_index_correction = 0; + s->corked = 0; s->ipol_usec_valid = 0; s->ipol_timestamp.tv_sec = 0; s->ipol_timestamp.tv_usec = 0; - s->ipol_event = NULL; - s->ipol_requested = 0; - - for (i = 0; i < PA_MAX_LATENCY_CORRECTIONS; i++) - s->latency_corrections[i].valid = 0; - s->idx_latency_correction = 0; + s->auto_timing_update_event = NULL; + s->auto_timing_update_requested = 0; + PA_LLIST_PREPEND(pa_stream, c->streams, s); /* The context and stream will point at each other. We cannot ref count @@ -119,9 +122,9 @@ static void stream_free(pa_stream *s) { pa_context_unref(s->context); - if (s->ipol_event) { + if (s->auto_timing_update_event) { assert(s->mainloop); - s->mainloop->time_free(s->ipol_event); + s->mainloop->time_free(s->auto_timing_update_event); } if (s->peek_memchunk.memblock) @@ -296,34 +299,77 @@ void pa_command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, PA_GCC } } -finish: + finish: pa_context_unref(c); } -static void ipol_callback(pa_mainloop_api *m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { +static void request_auto_timing_update(pa_stream *s, int force) { struct timeval next; - pa_stream *s = userdata; - - pa_stream_ref(s); + assert(s); -/* pa_log("requesting new ipol data"); */ + if (!(s->flags & PA_STREAM_AUTO_TIMING_UPDATE)) + return; - if (s->state == PA_STREAM_READY && !s->ipol_requested) { + if (s->state == PA_STREAM_READY && + (force || !s->auto_timing_update_requested)) { pa_operation *o; +/* pa_log("automatically requesting new timing data"); */ + if ((o = pa_stream_update_timing_info(s, NULL, NULL))) { pa_operation_unref(o); - s->ipol_requested = 1; + s->auto_timing_update_requested = 1; } } - + pa_gettimeofday(&next); pa_timeval_add(&next, LATENCY_IPOL_INTERVAL_USEC); - m->time_restart(e, &next); + s->mainloop->time_restart(s->auto_timing_update_event, &next); +} + +static void invalidate_indexes(pa_stream *s, int r, int w) { + assert(s); + + pa_log("invalidate r:%u w:%u tag:%u", r, w, s->context->ctag); - pa_stream_unref(s); + if (s->state != PA_STREAM_READY) + return; + + if (w) { + s->write_index_not_before = s->context->ctag; + + if (s->timing_info_valid) + s->timing_info.write_index_corrupt = 1; + + pa_log("write_index invalidated"); + + } + + if (r) { + s->read_index_not_before = s->context->ctag; + + if (s->timing_info_valid) + s->timing_info.read_index_corrupt = 1; + + pa_log("read_index invalidated"); + } + + if ((s->direction == PA_STREAM_PLAYBACK && r) || + (s->direction == PA_STREAM_RECORD && w)) + s->ipol_usec_valid = 0; + + request_auto_timing_update(s, 1); } +static void auto_timing_update_callback(pa_mainloop_api *m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + pa_stream *s = userdata; + + pa_log("time event"); + + pa_stream_ref(s); + request_auto_timing_update(s, 0); + pa_stream_unref(s); +} void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_stream *s = userdata; @@ -371,6 +417,8 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED /* We add an extra ref as long as we're connected (i.e. in the dynarray) */ pa_stream_ref(s); + pa_stream_set_state(s, PA_STREAM_READY); + if (s->direction != PA_STREAM_UPLOAD && s->flags & PA_STREAM_AUTO_TIMING_UPDATE) { struct timeval tv; @@ -378,12 +426,12 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED pa_gettimeofday(&tv); tv.tv_usec += LATENCY_IPOL_INTERVAL_USEC; /* every 100 ms */ - assert(!s->ipol_event); - s->ipol_event = s->mainloop->time_new(s->mainloop, &tv, &ipol_callback, s); + assert(!s->auto_timing_update_event); + s->auto_timing_update_event = s->mainloop->time_new(s->mainloop, &tv, &auto_timing_update_callback, s); + + request_auto_timing_update(s, 1); } - pa_stream_set_state(s, PA_STREAM_READY); - if (s->requested_bytes > 0 && s->ref > 1 && s->write_callback) s->write_callback(s, s->requested_bytes, s->write_userdata); @@ -548,18 +596,19 @@ int pa_stream_write( s->requested_bytes = 0; if (s->direction == PA_STREAM_PLAYBACK) { + /* Update latency request correction */ - if (s->latency_corrections[s->idx_latency_correction].valid) { + if (s->write_index_corrections[s->current_write_index_correction].valid) { if (seek == PA_SEEK_ABSOLUTE) { - s->latency_corrections[s->idx_latency_correction].corrupt = 0; - s->latency_corrections[s->idx_latency_correction].absolute = 1; - s->latency_corrections[s->idx_latency_correction].value = offset + length; + s->write_index_corrections[s->current_write_index_correction].corrupt = 0; + s->write_index_corrections[s->current_write_index_correction].absolute = 1; + s->write_index_corrections[s->current_write_index_correction].value = offset + length; } else if (seek == PA_SEEK_RELATIVE) { - if (!s->latency_corrections[s->idx_latency_correction].corrupt) - s->latency_corrections[s->idx_latency_correction].value += offset + length; + if (!s->write_index_corrections[s->current_write_index_correction].corrupt) + s->write_index_corrections[s->current_write_index_correction].value += offset + length; } else - s->latency_corrections[s->idx_latency_correction].corrupt = 1; + s->write_index_corrections[s->current_write_index_correction].corrupt = 1; } /* Update the write index in the already available latency data */ @@ -574,6 +623,9 @@ int pa_stream_write( } else s->timing_info.write_index_corrupt = 1; } + + if (!s->timing_info_valid || s->timing_info.write_index_corrupt) + request_auto_timing_update(s, 1); } return 0; @@ -672,15 +724,20 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, assert(o->context); i = &o->stream->timing_info; + + pa_log("pre corrupt w:%u r:%u\n", !o->stream->timing_info_valid || i->write_index_corrupt,!o->stream->timing_info_valid || i->read_index_corrupt); + o->stream->timing_info_valid = 0; i->write_index_corrupt = 0; + i->read_index_corrupt = 0; + + pa_log("timing update %u\n", tag); if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; - } else if (pa_tagstruct_get_usec(t, &i->buffer_usec) < 0 || - pa_tagstruct_get_usec(t, &i->sink_usec) < 0 || + } else if (pa_tagstruct_get_usec(t, &i->sink_usec) < 0 || pa_tagstruct_get_usec(t, &i->source_usec) < 0 || pa_tagstruct_get_boolean(t, &i->playing) < 0 || pa_tagstruct_get_timeval(t, &local) < 0 || @@ -692,8 +749,11 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, goto finish; } else { + o->stream->timing_info_valid = 1; + pa_gettimeofday(&now); + /* Calculcate timestamps */ if (pa_timeval_cmp(&local, &remote) <= 0 && pa_timeval_cmp(&remote, &now) <= 0) { /* local and remote seem to have synchronized clocks */ @@ -712,6 +772,13 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, pa_timeval_add(&i->timestamp, i->transport_usec); } + /* Invalidate read and write indexes if necessary */ + if (tag < o->stream->read_index_not_before) + i->read_index_corrupt = 1; + + if (tag < o->stream->write_index_not_before) + i->write_index_corrupt = 1; + if (o->stream->direction == PA_STREAM_PLAYBACK) { /* Write index correction */ @@ -720,53 +787,54 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, /* Go through the saved correction values and add up the total correction.*/ - for (n = 0, j = o->stream->idx_latency_correction; - n < PA_MAX_LATENCY_CORRECTIONS; - n++, j = (j + 1) % PA_MAX_LATENCY_CORRECTIONS) { + for (n = 0, j = o->stream->current_write_index_correction+1; + n < PA_MAX_WRITE_INDEX_CORRECTIONS; + n++, j = (j + 1) % PA_MAX_WRITE_INDEX_CORRECTIONS) { /* Step over invalid data or out-of-date data */ - if (!o->stream->latency_corrections[j].valid || - o->stream->latency_corrections[j].tag < ctag) + if (!o->stream->write_index_corrections[j].valid || + o->stream->write_index_corrections[j].tag < ctag) continue; /* Make sure that everything is in order */ - ctag = o->stream->latency_corrections[j].tag+1; + ctag = o->stream->write_index_corrections[j].tag+1; /* Now fix the write index */ - if (o->stream->latency_corrections[j].corrupt) { + if (o->stream->write_index_corrections[j].corrupt) { /* A corrupting seek was made */ i->write_index = 0; i->write_index_corrupt = 1; - } else if (o->stream->latency_corrections[j].absolute) { + } else if (o->stream->write_index_corrections[j].absolute) { /* An absolute seek was made */ - i->write_index = o->stream->latency_corrections[j].value; + i->write_index = o->stream->write_index_corrections[j].value; i->write_index_corrupt = 0; } else if (!i->write_index_corrupt) { /* A relative seek was made */ - i->write_index += o->stream->latency_corrections[j].value; + i->write_index += o->stream->write_index_corrections[j].value; } } } - - o->stream->timing_info_valid = 1; - + o->stream->ipol_timestamp = now; o->stream->ipol_usec_valid = 0; } + o->stream->auto_timing_update_requested = 0; + pa_log("post corrupt w:%u r:%u\n", i->write_index_corrupt || !o->stream->timing_info_valid, i->read_index_corrupt || !o->stream->timing_info_valid); + /* Clear old correction entries */ if (o->stream->direction == PA_STREAM_PLAYBACK) { int n; - for (n = 0; n < PA_MAX_LATENCY_CORRECTIONS; n++) { - if (!o->stream->latency_corrections[n].valid) + for (n = 0; n < PA_MAX_WRITE_INDEX_CORRECTIONS; n++) { + if (!o->stream->write_index_corrections[n].valid) continue; - if (o->stream->latency_corrections[n].tag <= tag) - o->stream->latency_corrections[n].valid = 0; + if (o->stream->write_index_corrections[n].tag <= tag) + o->stream->write_index_corrections[n].valid = 0; } } - + if (o->callback) { pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback; cb(o->stream, o->stream->timing_info_valid, o->userdata); @@ -790,16 +858,15 @@ pa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - + if (s->direction == PA_STREAM_PLAYBACK) { /* Find a place to store the write_index correction data for this entry */ - cidx = (s->idx_latency_correction + 1) % PA_MAX_LATENCY_CORRECTIONS; + cidx = (s->current_write_index_correction + 1) % PA_MAX_WRITE_INDEX_CORRECTIONS; /* Check if we could allocate a correction slot. If not, there are too many outstanding queries */ - PA_CHECK_VALIDITY_RETURN_NULL(s->context, !s->latency_corrections[cidx].valid, PA_ERR_INTERNAL); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, !s->write_index_corrections[cidx].valid, PA_ERR_INTERNAL); } - - o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_command( s->context, @@ -813,14 +880,16 @@ pa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t if (s->direction == PA_STREAM_PLAYBACK) { /* Fill in initial correction data */ - o->stream->idx_latency_correction = cidx; - o->stream->latency_corrections[cidx].valid = 1; - o->stream->latency_corrections[cidx].tag = tag; - o->stream->latency_corrections[cidx].absolute = 0; - o->stream->latency_corrections[cidx].value = 0; - o->stream->latency_corrections[cidx].corrupt = 0; + o->stream->current_write_index_correction = cidx; + o->stream->write_index_corrections[cidx].valid = 1; + o->stream->write_index_corrections[cidx].tag = tag; + o->stream->write_index_corrections[cidx].absolute = 0; + o->stream->write_index_corrections[cidx].value = 0; + o->stream->write_index_corrections[cidx].corrupt = 0; } + pa_log("requesting update %u\n", tag); + return pa_operation_ref(o); } @@ -946,7 +1015,6 @@ finish: pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata) { pa_operation *o; - pa_operation *lo; pa_tagstruct *t; uint32_t tag; @@ -956,15 +1024,6 @@ pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, voi PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - if (s->flags & PA_STREAM_AUTO_TIMING_UPDATE) { - if (!s->corked && b) { - /* Refresh the interpolated data just befor pausing */ - pa_stream_get_time(s, NULL); - } else if (s->corked && !b) - /* Unpausing */ - pa_gettimeofday(&s->ipol_timestamp); - } - s->corked = b; o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); @@ -978,9 +1037,9 @@ pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, voi pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); - if ((lo = pa_stream_update_timing_info(s, NULL, NULL))) - pa_operation_unref(lo); - + if (s->direction == PA_STREAM_PLAYBACK) + invalidate_indexes(s, 1, 0); + return pa_operation_ref(o); } @@ -1006,14 +1065,24 @@ static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { pa_operation *o; - + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); if ((o = stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata))) { - pa_operation *lo; - if ((lo = pa_stream_update_timing_info(s, NULL, NULL))) - pa_operation_unref(lo); + if (s->direction == PA_STREAM_PLAYBACK) { + if (s->write_index_corrections[s->current_write_index_correction].valid) + s->write_index_corrections[s->current_write_index_correction].corrupt = 1; + + if (s->timing_info_valid) + s->timing_info.write_index_corrupt = 1; + + if (s->buffer_attr.prebuf > 0) + invalidate_indexes(s, 1, 0); + else + request_auto_timing_update(s, 1); + } else + invalidate_indexes(s, 0, 1); } return o; @@ -1023,14 +1092,11 @@ pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *us pa_operation *o; PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE); - if ((o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata))) { - pa_operation *lo; + if ((o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata))) + invalidate_indexes(s, 1, 0); - if ((lo = pa_stream_update_timing_info(s, NULL, NULL))) - pa_operation_unref(lo); - } - return o; } @@ -1038,13 +1104,10 @@ pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *u pa_operation *o; PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE); - if ((o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata))) { - pa_operation *lo; - - if ((lo = pa_stream_update_timing_info(s, NULL, NULL))) - pa_operation_unref(lo); - } + if ((o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata))) + invalidate_indexes(s, 1, 0); return o; } @@ -1084,50 +1147,56 @@ int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) { PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, s->timing_info_valid, PA_ERR_NODATA); + PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_PLAYBACK || !s->timing_info.read_index_corrupt, PA_ERR_NODATA); + PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_RECORD || !s->timing_info.write_index_corrupt, PA_ERR_NODATA); - if (s->flags & PA_STREAM_INTERPOLATE_TIMING && s->ipol_usec_valid ) + if (s->flags & PA_STREAM_INTERPOLATE_TIMING && s->ipol_usec_valid) usec = s->ipol_usec; else { if (s->direction == PA_STREAM_PLAYBACK) { /* The last byte that was written into the output device * had this time value associated */ usec = pa_bytes_to_usec(s->timing_info.read_index < 0 ? 0 : (uint64_t) s->timing_info.read_index, &s->sample_spec); - - /* Because the latency info took a little time to come - * to us, we assume that the real output time is actually - * a little ahead */ - usec += s->timing_info.transport_usec; - - /* However, the output device usually maintains a buffer - too, hence the real sample currently played is a little - back */ - if (s->timing_info.sink_usec >= usec) - usec = 0; - else - usec -= s->timing_info.sink_usec; + + if (!s->corked) { + /* Because the latency info took a little time to come + * to us, we assume that the real output time is actually + * a little ahead */ + usec += s->timing_info.transport_usec; + + /* However, the output device usually maintains a buffer + too, hence the real sample currently played is a little + back */ + if (s->timing_info.sink_usec >= usec) + usec = 0; + else + usec -= s->timing_info.sink_usec; + } } else if (s->direction == PA_STREAM_RECORD) { /* The last byte written into the server side queue had * this time value associated */ usec = pa_bytes_to_usec(s->timing_info.write_index < 0 ? 0 : (uint64_t) s->timing_info.write_index, &s->sample_spec); - - /* Add transport latency */ - usec += s->timing_info.transport_usec; - - /* Add latency of data in device buffer */ - usec += s->timing_info.source_usec; - - /* If this is a monitor source, we need to correct the - * time by the playback device buffer */ - if (s->timing_info.sink_usec >= usec) - usec = 0; - else - usec -= s->timing_info.sink_usec; + + if (!s->corked) { + /* Add transport latency */ + usec += s->timing_info.transport_usec; + + /* Add latency of data in device buffer */ + usec += s->timing_info.source_usec; + + /* If this is a monitor source, we need to correct the + * time by the playback device buffer */ + if (s->timing_info.sink_usec >= usec) + usec = 0; + else + usec -= s->timing_info.sink_usec; + } } if (s->flags & PA_STREAM_INTERPOLATE_TIMING) { - s->ipol_usec_valid = 1; s->ipol_usec = usec; + s->ipol_usec_valid = 1; } } @@ -1189,6 +1258,7 @@ int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative) { PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, s->timing_info_valid, PA_ERR_NODATA); PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_PLAYBACK || !s->timing_info.write_index_corrupt, PA_ERR_NODATA); + PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_RECORD || !s->timing_info.read_index_corrupt, PA_ERR_NODATA); if ((r = pa_stream_get_time(s, &t)) < 0) return r; -- cgit From d42794206db90b0a991c246d12afc409aafcafa5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Apr 2006 17:18:24 +0000 Subject: beefup pacat a little: * when -v is passed, show current playback time and latency * modify SIGUSR1 behaviour to show only playback time and latency git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@687 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pacat.c | 59 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/src/utils/pacat.c b/src/utils/pacat.c index e721befa..2c12dbb3 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -36,6 +36,9 @@ #include #include #include +#include + +#define TIME_EVENT_USEC 50000 #if PA_API_VERSION != 8 #error Invalid Polypaudio API version @@ -153,7 +156,7 @@ static void stream_state_callback(pa_stream *s, void *userdata) { case PA_STREAM_READY: if (verbose) - fprintf(stderr, "Stream successfully created\n"); + fprintf(stderr, "Stream successfully created.\n"); break; case PA_STREAM_FAILED: @@ -341,34 +344,46 @@ static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, /* Show the current latency */ static void stream_update_timing_callback(pa_stream *s, int success, void *userdata) { - pa_usec_t total; + pa_usec_t latency, usec; int negative = 0; - const pa_timing_info *i; assert(s); if (!success || - !(i = pa_stream_get_timing_info(s)) || - pa_stream_get_latency(s, &total, &negative) < 0) { + pa_stream_get_time(s, &usec) < 0 || + pa_stream_get_latency(s, &latency, &negative) < 0) { fprintf(stderr, "Failed to get latency: %s\n", pa_strerror(pa_context_errno(context))); quit(1); return; } - fprintf(stderr, "Latency: buffer: %0.0f usec; sink: %0.0f usec; source: %0.0f usec; transport: %0.0f usec; total: %0.0f usec; synchronized clocks: %s.\n", - (float) i->buffer_usec, - (float) i->sink_usec, - (float) i->source_usec, - (float) i->transport_usec, - (float) total * (negative?-1:1), - i->synchronized_clocks ? "yes" : "no"); + fprintf(stderr, "Time: %0.3f sec; Latency: %0.0f usec. \r", + (float) usec / 1000000, + (float) latency * (negative?-1:1)); } /* Someone requested that the latency is shown */ static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { + + if (!stream) + return; + pa_operation_unref(pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL)); } +static void time_event_callback(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { + struct timeval next; + + if (!stream) + return; + + pa_operation_unref(pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL)); + + pa_gettimeofday(&next); + pa_timeval_add(&next, TIME_EVENT_USEC); + + m->time_restart(e, &next); +} static void help(const char *argv0) { @@ -404,6 +419,7 @@ int main(int argc, char *argv[]) { pa_mainloop* m = NULL; int ret = 1, r, c; char *bn, *server = NULL; + pa_time_event *time_event = NULL; static const struct option long_options[] = { {"record", 0, NULL, 'r'}, @@ -561,7 +577,7 @@ int main(int argc, char *argv[]) { mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO, mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT, mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) { - fprintf(stderr, "source_io() failed.\n"); + fprintf(stderr, "io_new() failed.\n"); goto quit; } @@ -576,6 +592,18 @@ int main(int argc, char *argv[]) { /* Connect the context */ pa_context_connect(context, server, 0, NULL); + if (verbose) { + struct timeval tv; + + pa_gettimeofday(&tv); + pa_timeval_add(&tv, TIME_EVENT_USEC); + + if (!(time_event = mainloop_api->time_new(mainloop_api, &tv, time_event_callback, NULL))) { + fprintf(stderr, "time_new() failed.\n"); + goto quit; + } + } + /* Run the main loop */ if (pa_mainloop_run(m, &ret) < 0) { fprintf(stderr, "pa_mainloop_run() failed.\n"); @@ -593,6 +621,11 @@ quit: assert(mainloop_api); mainloop_api->io_free(stdio_event); } + + if (time_event) { + assert(mainloop_api); + mainloop_api->time_free(time_event); + } if (m) { pa_signal_done(); -- cgit From 0fa56f9b6f87ac230591fdaae70f0390161ab8d8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Apr 2006 17:26:24 +0000 Subject: remove a bunch of log messages git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@688 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/stream.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/polyp/stream.c b/src/polyp/stream.c index b3f19d09..fc8cc5cc 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -330,7 +330,7 @@ static void request_auto_timing_update(pa_stream *s, int force) { static void invalidate_indexes(pa_stream *s, int r, int w) { assert(s); - pa_log("invalidate r:%u w:%u tag:%u", r, w, s->context->ctag); +/* pa_log("invalidate r:%u w:%u tag:%u", r, w, s->context->ctag); */ if (s->state != PA_STREAM_READY) return; @@ -341,8 +341,7 @@ static void invalidate_indexes(pa_stream *s, int r, int w) { if (s->timing_info_valid) s->timing_info.write_index_corrupt = 1; - pa_log("write_index invalidated"); - +/* pa_log("write_index invalidated"); */ } if (r) { @@ -351,7 +350,7 @@ static void invalidate_indexes(pa_stream *s, int r, int w) { if (s->timing_info_valid) s->timing_info.read_index_corrupt = 1; - pa_log("read_index invalidated"); +/* pa_log("read_index invalidated"); */ } if ((s->direction == PA_STREAM_PLAYBACK && r) || @@ -364,7 +363,7 @@ static void invalidate_indexes(pa_stream *s, int r, int w) { static void auto_timing_update_callback(pa_mainloop_api *m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { pa_stream *s = userdata; - pa_log("time event"); +/* pa_log("time event"); */ pa_stream_ref(s); request_auto_timing_update(s, 0); @@ -725,13 +724,13 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, i = &o->stream->timing_info; - pa_log("pre corrupt w:%u r:%u\n", !o->stream->timing_info_valid || i->write_index_corrupt,!o->stream->timing_info_valid || i->read_index_corrupt); +/* pa_log("pre corrupt w:%u r:%u\n", !o->stream->timing_info_valid || i->write_index_corrupt,!o->stream->timing_info_valid || i->read_index_corrupt); */ o->stream->timing_info_valid = 0; i->write_index_corrupt = 0; i->read_index_corrupt = 0; - pa_log("timing update %u\n", tag); +/* pa_log("timing update %u\n", tag); */ if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) @@ -820,7 +819,7 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, } o->stream->auto_timing_update_requested = 0; - pa_log("post corrupt w:%u r:%u\n", i->write_index_corrupt || !o->stream->timing_info_valid, i->read_index_corrupt || !o->stream->timing_info_valid); +/* pa_log("post corrupt w:%u r:%u\n", i->write_index_corrupt || !o->stream->timing_info_valid, i->read_index_corrupt || !o->stream->timing_info_valid); */ /* Clear old correction entries */ if (o->stream->direction == PA_STREAM_PLAYBACK) { @@ -888,7 +887,7 @@ pa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t o->stream->write_index_corrections[cidx].corrupt = 0; } - pa_log("requesting update %u\n", tag); +/* pa_log("requesting update %u\n", tag); */ return pa_operation_ref(o); } -- cgit From 853caf12740ed3ff4f4c64c2cb458cb0cc635d25 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Apr 2006 18:33:13 +0000 Subject: * fix latency calculation where a full playback buffer was erroneously taken as empty buffer and vice versa. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@689 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss-mmap.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index 5389a201..c487f40c 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -70,8 +70,9 @@ struct userdata { pa_core *core; pa_sample_spec sample_spec; - size_t in_fragment_size, out_fragment_size, in_fragments, out_fragments; - int out_blocks_saved, in_blocks_saved; + size_t in_fragment_size, out_fragment_size; + unsigned in_fragments, out_fragments; + unsigned out_blocks_saved, in_blocks_saved; int fd; @@ -121,7 +122,12 @@ static void out_fill_memblocks(struct userdata *u, unsigned n) { if (u->out_memblocks[u->out_current]) pa_memblock_unref_fixed(u->out_memblocks[u->out_current]); - chunk.memblock = u->out_memblocks[u->out_current] = pa_memblock_new_fixed((uint8_t*)u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size, 1, u->core->memblock_stat); + chunk.memblock = u->out_memblocks[u->out_current] = + pa_memblock_new_fixed( + (uint8_t*) u->out_mmap+u->out_fragment_size*u->out_current, + u->out_fragment_size, + 1, + u->core->memblock_stat); assert(chunk.memblock); chunk.length = chunk.memblock->length; chunk.index = 0; @@ -233,7 +239,7 @@ static void io_callback(pa_mainloop_api *m, pa_io_event *e, PA_GCC_UNUSED int fd static pa_usec_t sink_get_latency_cb(pa_sink *s) { struct userdata *u = s->userdata; struct count_info info; - size_t bpos, n; + size_t bpos, n, total; assert(s && u); if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { @@ -243,12 +249,15 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { u->out_blocks_saved += info.blocks; - bpos = ((u->out_current + u->out_blocks_saved) % u->out_fragments) * u->out_fragment_size; + total = u->out_fragments * u->out_fragment_size; + bpos = ((u->out_current + u->out_blocks_saved) * u->out_fragment_size) % total; - if (bpos < (size_t) info.ptr) - n = (u->out_fragments * u->out_fragment_size) - (info.ptr - bpos); + if (bpos <= (size_t) info.ptr) + n = total - (info.ptr - bpos); else n = bpos - info.ptr; + +/* pa_log("n = %u, bpos = %u, ptr = %u, total=%u, fragsize = %u, n_frags = %u\n", n, bpos, (unsigned) info.ptr, total, u->out_fragment_size, u->out_fragments); */ return pa_bytes_to_usec(n, &s->sample_spec); } @@ -256,7 +265,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { static pa_usec_t source_get_latency_cb(pa_source *s) { struct userdata *u = s->userdata; struct count_info info; - size_t bpos, n; + size_t bpos, n, total; assert(s && u); if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { @@ -266,12 +275,15 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { u->in_blocks_saved += info.blocks; - bpos = ((u->in_current + u->in_blocks_saved) % u->in_fragments) * u->in_fragment_size; + total = u->in_fragments * u->in_fragment_size; + bpos = ((u->in_current + u->in_blocks_saved) * u->in_fragment_size) % total; - if (bpos < (size_t) info.ptr) + if (bpos <= (size_t) info.ptr) n = info.ptr - bpos; else n = (u->in_fragments * u->in_fragment_size) - bpos + info.ptr; + +/* pa_log("n = %u, bpos = %u, ptr = %u, total=%u, fragsize = %u, n_frags = %u\n", n, bpos, (unsigned) info.ptr, total, u->in_fragment_size, u->in_fragments); */ return pa_bytes_to_usec(n, &s->sample_spec); } -- cgit From bf88854e60500f251fefbde8ab678b9d93280201 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Apr 2006 22:45:57 +0000 Subject: * dispatch defer events in pa_mainloop_dispatch() and not already in pa_mainloop_prepare() * fix the "timeout" parameter of pa_mainloop_prepare() * remove pa_mainloop_deferred_pending() and update the simple API accordingly git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@690 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/mainloop.c | 125 +++++++++++++++++++++++++-------------------------- src/polyp/mainloop.h | 5 +-- src/polyp/simple.c | 35 ++++++++------- 3 files changed, 80 insertions(+), 85 deletions(-) diff --git a/src/polyp/mainloop.c b/src/polyp/mainloop.c index 95c336e4..da3f57b2 100644 --- a/src/polyp/mainloop.c +++ b/src/polyp/mainloop.c @@ -624,83 +624,95 @@ static void clear_wakeup(pa_mainloop *m) { } int pa_mainloop_prepare(pa_mainloop *m, int timeout) { - int dispatched = 0; - - assert(m && (m->state == STATE_PASSIVE)); + assert(m); + assert(m->state == STATE_PASSIVE); clear_wakeup(m); - scan_dead(m); if (m->quit) goto quit; - dispatched += dispatch_defer(m); - - if (m->quit) - goto quit; - - if (m->rebuild_pollfds) - rebuild_pollfds(m); - - m->prepared_timeout = calc_next_timeout(m); - if ((timeout >= 0) && (m->prepared_timeout > timeout)) - m->prepared_timeout = timeout; + if (!m->deferred_pending) { + + if (m->rebuild_pollfds) + rebuild_pollfds(m); + + m->prepared_timeout = calc_next_timeout(m); + if (timeout >= 0 && (timeout < m->prepared_timeout || m->prepared_timeout < 0)) + m->prepared_timeout = timeout; + } m->state = STATE_PREPARED; - - return dispatched; + return 0; quit: - m->state = STATE_QUIT; - return -2; } int pa_mainloop_poll(pa_mainloop *m) { int r; - assert(m && (m->state == STATE_PREPARED)); + assert(m); + assert(m->state == STATE_PREPARED); - m->state = STATE_POLLING; + if (m->quit) + goto quit; - r = poll(m->pollfds, m->n_pollfds, m->prepared_timeout); + m->state = STATE_POLLING; - if ((r < 0) && (errno == EINTR)) - r = 0; + if (m->deferred_pending) + r = 0; + else { + r = poll(m->pollfds, m->n_pollfds, m->prepared_timeout); - if (r < 0) - m->state = STATE_PASSIVE; - else - m->state = STATE_POLLED; + if (r < 0) { + if (errno == EINTR) + r = 0; + else + pa_log(__FILE__": poll(): %s", strerror(errno)); + } + } + m->state = r < 0 ? STATE_PASSIVE : STATE_POLLED; return r; + +quit: + m->state = STATE_QUIT; + return -2; } int pa_mainloop_dispatch(pa_mainloop *m) { int dispatched = 0; - assert(m && (m->state == STATE_POLLED)); - - dispatched += dispatch_timeout(m); + assert(m); + assert(m->state == STATE_POLLED); if (m->quit) goto quit; - dispatched += dispatch_pollfds(m); + if (m->deferred_pending) + dispatched += dispatch_defer(m); + else { + dispatched += dispatch_timeout(m); + + if (m->quit) + goto quit; + + dispatched += dispatch_pollfds(m); + } + if (m->quit) goto quit; - + m->state = STATE_PASSIVE; return dispatched; quit: - m->state = STATE_QUIT; - return -2; } @@ -710,39 +722,30 @@ int pa_mainloop_get_retval(pa_mainloop *m) { } int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) { - int r, dispatched = 0; - + int r; assert(m); - r = pa_mainloop_prepare(m, block ? -1 : 0); - if (r < 0) { - if ((r == -2) && retval) - *retval = pa_mainloop_get_retval(m); - return r; - } - - dispatched += r; + if ((r = pa_mainloop_prepare(m, block ? -1 : 0)) < 0) + goto quit; - r = pa_mainloop_poll(m); - if (r < 0) { - pa_log(__FILE__": poll(): %s", strerror(errno)); - return r; - } + if ((r = pa_mainloop_poll(m)) < 0) + goto quit; - r = pa_mainloop_dispatch(m); - if (r < 0) { - if ((r == -2) && retval) - *retval = pa_mainloop_get_retval(m); - return r; - } + if ((r = pa_mainloop_dispatch(m)) < 0) + goto quit; - dispatched += r; + return r; - return dispatched; +quit: + + if ((r == -2) && retval) + *retval = pa_mainloop_get_retval(m); + return r; } int pa_mainloop_run(pa_mainloop *m, int *retval) { int r; + while ((r = pa_mainloop_iterate(m, 1, retval)) >= 0); if (r == -2) @@ -764,12 +767,6 @@ pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m) { return &m->api; } -int pa_mainloop_deferred_pending(pa_mainloop *m) { - assert(m); - return m->deferred_pending > 0; -} - - #if 0 void pa_mainloop_dump(pa_mainloop *m) { assert(m); diff --git a/src/polyp/mainloop.h b/src/polyp/mainloop.h index c06b47d0..82d1adc4 100644 --- a/src/polyp/mainloop.h +++ b/src/polyp/mainloop.h @@ -107,12 +107,9 @@ int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval); /** Run unlimited iterations of the main loop object until the main loop's quit() routine is called. */ int pa_mainloop_run(pa_mainloop *m, int *retval); -/** Return the abstract main loop abstraction layer vtable for this main loop. This calls pa_mainloop_iterate() iteratively.*/ +/** Return the abstract main loop abstraction layer vtable for this main loop. */ pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m); -/** Return non-zero when there are any deferred events pending. \since 0.5 */ -int pa_mainloop_deferred_pending(pa_mainloop *m); - /** Shutdown the main loop */ void pa_mainloop_quit(pa_mainloop *m, int r); diff --git a/src/polyp/simple.c b/src/polyp/simple.c index f48c0b17..dbf7a325 100644 --- a/src/polyp/simple.c +++ b/src/polyp/simple.c @@ -91,31 +91,32 @@ static int iterate(pa_simple *p, int block, int *rerror) { if (check_error(p, rerror) < 0) return -1; - - if (!block && !pa_context_is_pending(p->context)) - return 0; - - do { - if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) { - if (rerror) - *rerror = PA_ERR_INTERNAL; - return -1; - } - if (check_error(p, rerror) < 0) - return -1; - - } while (pa_context_is_pending(p->context)); + if (block || pa_context_is_pending(p->context)) { + do { + if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) { + if (rerror) + *rerror = PA_ERR_INTERNAL; + return -1; + } + + if (check_error(p, rerror) < 0) + return -1; + } while (pa_context_is_pending(p->context)); + } - - while (pa_mainloop_deferred_pending(p->mainloop)) { + for (;;) { + int r; - if (pa_mainloop_iterate(p->mainloop, 0, NULL) < 0) { + if ((r = pa_mainloop_iterate(p->mainloop, 0, NULL)) < 0) { if (rerror) *rerror = PA_ERR_INTERNAL; return -1; } + if (r == 0) + break; + if (check_error(p, rerror) < 0) return -1; } -- cgit From 0af582a8d6297f0e4b156001b49f38bba032b199 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Apr 2006 23:12:54 +0000 Subject: small fix to deal properly with slow links git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@691 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pacat.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 2c12dbb3..4d3302ab 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -374,10 +374,13 @@ static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int s static void time_event_callback(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { struct timeval next; - if (!stream) - return; - - pa_operation_unref(pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL)); + if (stream) { + pa_operation *o; + if (!(o = pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL))) + fprintf(stderr, "pa_stream_update_timing_info() failed: %s\n", pa_strerror(pa_context_errno(context))); + else + pa_operation_unref(o); + } pa_gettimeofday(&next); pa_timeval_add(&next, TIME_EVENT_USEC); -- cgit From 4a8d3185492f381c88c737097123638bf9f6ed29 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Apr 2006 23:19:07 +0000 Subject: yet anotrher fix for slow links git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@692 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pacat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 4d3302ab..1e22656d 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -374,7 +374,7 @@ static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int s static void time_event_callback(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { struct timeval next; - if (stream) { + if (stream && pa_stream_get_state(stream) == PA_STREAM_READY) { pa_operation *o; if (!(o = pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL))) fprintf(stderr, "pa_stream_update_timing_info() failed: %s\n", pa_strerror(pa_context_errno(context))); -- cgit From 06bd27b0433e06f3af573ddc213e2577127972e4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Apr 2006 23:55:21 +0000 Subject: when storing recording data in file, create file with proper access rights git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@693 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pacat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 1e22656d..cce97442 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -540,7 +540,7 @@ int main(int argc, char *argv[]) { if (optind+1 == argc) { int fd; - if ((fd = open(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT)) < 0) { + if ((fd = open(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) { fprintf(stderr, "open(): %s\n", strerror(errno)); goto quit; } -- cgit From 7fa8323453fab243192bacdae0aeae1e65146f13 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Apr 2006 23:57:25 +0000 Subject: include local record memblockq in latency calculations git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@694 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/context.c | 6 ++++-- src/polyp/stream.c | 11 +++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/polyp/context.c b/src/polyp/context.c index 7c0ed190..047b739f 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -294,12 +294,14 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o assert(c->ref >= 1); pa_context_ref(c); - + if ((s = pa_dynarray_get(c->record_streams, channel))) { + assert(seek == PA_SEEK_RELATIVE && offset == 0); + pa_memblockq_seek(s->record_memblockq, offset, seek); pa_memblockq_push_align(s->record_memblockq, chunk); - + if (s->read_callback) { size_t l; diff --git a/src/polyp/stream.c b/src/polyp/stream.c index fc8cc5cc..ce2470f6 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -662,6 +662,10 @@ int pa_stream_drop(pa_stream *s) { PA_CHECK_VALIDITY(s->context, s->peek_memchunk.memblock, PA_ERR_BADSTATE); pa_memblockq_drop(s->record_memblockq, &s->peek_memchunk, s->peek_memchunk.length); + + /* Fix the simulated local read index */ + if (s->timing_info_valid && !s->timing_info.read_index_corrupt) + s->timing_info.read_index += s->peek_memchunk.length; pa_memblock_unref(s->peek_memchunk.memblock); s->peek_memchunk.length = 0; @@ -814,6 +818,13 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, } } + if (o->stream->direction == PA_STREAM_RECORD) { + /* Read index correction */ + + if (!i->read_index_corrupt) + i->read_index -= pa_memblockq_get_length(o->stream->record_memblockq); + } + o->stream->ipol_timestamp = now; o->stream->ipol_usec_valid = 0; } -- cgit From b33ae7913a51b0a33030912ce789f0328f8caaf1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Apr 2006 23:58:19 +0000 Subject: remove yet another item from the todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@695 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index 10be043b..3613217c 100644 --- a/doc/todo +++ b/doc/todo @@ -6,7 +6,6 @@ Test: Fixes: - correct API docs regarding timing work -- incorporate client memblockq into latency calculations for recording streamings Post 0.8: - alsa mmap driver -- cgit From ceb09d8ae9bd11380ed3dc7d28054812ff0a0f04 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Apr 2006 00:56:10 +0000 Subject: Documentation updates git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@696 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/channelmap.h | 4 +-- src/polyp/context.h | 6 ++-- src/polyp/mainloop.h | 4 +-- src/polyp/sample.h | 2 +- src/polyp/simple.h | 4 +-- src/polyp/stream.h | 75 +++++++++++++++++++++++++++++++++++++++++--------- src/polyp/volume.h | 10 +++++-- 7 files changed, 80 insertions(+), 25 deletions(-) diff --git a/src/polyp/channelmap.h b/src/polyp/channelmap.h index c74f2ceb..99020583 100644 --- a/src/polyp/channelmap.h +++ b/src/polyp/channelmap.h @@ -30,8 +30,8 @@ * \section overv_sec Overview * * Channel maps provide a way to associate channels in a stream with a - * speaker. This relieves applications of having to make sure their channel - * order is identical to the final output. + * specific speaker position. This relieves applications of having to + * make sure their channel order is identical to the final output. * * \section init_sec Initialisation * diff --git a/src/polyp/context.h b/src/polyp/context.h index 460034c1..84830811 100644 --- a/src/polyp/context.h +++ b/src/polyp/context.h @@ -48,7 +48,7 @@ * The abstraction is represented as a number of function pointers in the * pa_mainloop_api structure. * - * To actually be able to use these functions, an actual implementation + * To actually be able to use these functions, an implementation needs to * be coupled to the abstraction. There are two of these shipped with * polypaudio, but any other can be used with a minimal ammount of work, * provided it supports the three basic events listed above. @@ -88,11 +88,11 @@ * channel. * * There is no need for more than one context per application, unless - * connections to multiple servers is needed. + * connections to multiple servers are needed. * * \subsection ops_subsec Operations * - * All operations on the context is performed asynchronously. I.e. the + * All operations on the context are performed asynchronously. I.e. the * client will not wait for the server to complete the request. To keep * track of all these in-flight operations, the application is given a * pa_operation object for each asynchronous operation. diff --git a/src/polyp/mainloop.h b/src/polyp/mainloop.h index 82d1adc4..6fb2a96c 100644 --- a/src/polyp/mainloop.h +++ b/src/polyp/mainloop.h @@ -45,10 +45,10 @@ PA_C_DECL_BEGIN * consists of three steps that repeat during the application's entire * lifetime: * - * -# Prepare - Dispatch deferred events, build a list of file descriptors + * -# Prepare - Build a list of file descriptors * that need to be monitored and calculate the next timeout. * -# Poll - Execute the actuall poll() system call. - * -# Dispatch - Dispatch any timeouts and file descriptors that have fired. + * -# Dispatch - Dispatch any events that have fired. * * When using the main loop, the application can either execute each * iteration, one at a time, using pa_mainloop_iterate(), or let the library diff --git a/src/polyp/sample.h b/src/polyp/sample.h index 284b428b..0706be5a 100644 --- a/src/polyp/sample.h +++ b/src/polyp/sample.h @@ -99,7 +99,7 @@ PA_C_DECL_BEGIN -/** Maximum allowed channels */ +/** Maximum number of allowed channels */ #define PA_CHANNELS_MAX 16 /** Sample format */ diff --git a/src/polyp/simple.h b/src/polyp/simple.h index d2adde02..9066826b 100644 --- a/src/polyp/simple.h +++ b/src/polyp/simple.h @@ -47,7 +47,7 @@ * pa_simple *s; * pa_sample_spec ss; * - * ss.format = S16_NE; + * ss.format = PA_SAMPLE_S16_NE; * ss.channels = 2; * ss.rate = 44100; * @@ -70,7 +70,7 @@ * Once the connection is established to the server, data can start flowing. * Using the connection is very similar to the normal read() and write() * system calls. The main difference is that they're call pa_simple_read() - * and pa_simple_write(). Note that these operation are always blocking. + * and pa_simple_write(). Note that these operations always block. * * \section ctrl_sec Buffer control * diff --git a/src/polyp/stream.h b/src/polyp/stream.h index bb5aa764..6367e868 100644 --- a/src/polyp/stream.h +++ b/src/polyp/stream.h @@ -69,7 +69,7 @@ * * \subsection bufattr_subsec Buffer attributes * - * Playback and record streams always have a buffer as part of the data flow. + * Playback and record streams always have a server side buffer as part of the data flow. * The size of this buffer strikes a compromise between low latency and * sensitivity for buffer overflows/underruns. * @@ -133,33 +133,82 @@ * monitoring the current latency. * * To get the raw data needed to calculate latencies, call - * pa_stream_get_timing_info(). This will give you a pa_timing_info structure - * that contains everything that is known about buffers, transport delays - * and the backend active in the server. + * pa_stream_get_timing_info(). This will give you a pa_timing_info + * structure that contains everything that is known about buffers, + * transport delays and the backend active in the server. * - * If a more simplistic interface is prefered, you can call - * pa_stream_get_time() or pa_stream_get_latency(). These will do all the - * necessary calculations for you. + * This structure is updated every time a + * pa_stream_update_timing_info() operation is executed. (i.e. before + * the first call to this function the timing information structure is + * not available!) Since it is a lot of work to keep this structure + * up-to-date manually, Polypaudio can do that automatically for you: + * if PA_STREAM_AUTO_TIMING_UPDATE is passed when connecting the + * stream Polypaudio will automatically update the structure every + * 100ms and every time a function is called that might invalidate the + * previously known timing data (such as pa_stream_write() or + * pa_stream_flush()). Please note however, that there always is a + * short time window when the data in the timing information structure + * is out-of-date. Polypaudio tries to mark these situations by + * setting the write_index_corrupt and read_index_corrupt fields + * accordingly. * - * The latency information is constantly updated from the server. Be aware - * that between updates, old data will be returned. If you specify the flag - * PA_STREAM_INTERPOLATE_TIMING when creating the stream, pa_stream_get_time() - * and pa_stream_get_latency() will calculate the latency between updates - * based on the time elapsed. + * The raw timing data in the pa_timing_info structure is usually hard + * to deal with. Therefore a more simplistic interface is available: + * you can call pa_stream_get_time() or pa_stream_get_latency(). The + * former will return the current playback time of the hardware since + * the stream has been started. The latter returns the time a sample + * that you write now takes to be played by the hardware. * + * Since updating the timing info structure usually requires a full + * round trip and some applications monitor the timing very often + * Polypaudio offers a timing interpolation system. If + * PA_STREAM_INTERPOLATE_TIMING is passed when connecting the stream, + * pa_stream_get_time() and pa_stream_get_latency() will try to + * interpolate the current playback time/latency by estimating the + * number of samples that have been played back by the hardware since + * the last regular timing update. It is espcially useful to combine + * this option with PA_STREAM_AUTO_TIMING_UPDATE, which will enable + * you to monitor the current playback time/latency very precisely + * without requiring a network round trip every time. + * * \section flow_sec Overflow and underflow * - * Even with the best precautions, buffers will sometime over- or underflow. + * Even with the best precautions, buffers will sometime over - or underflow. * To handle this gracefully, the application can be notified when this * happens. Callbacks are registered using pa_stream_set_overflow_callback() * and pa_stream_set_underflow_callback(). * + * \section sync_streams Sychronizing Multiple Playback Streams. + * + * Polypaudio allows applications to fully synchronize multiple playback + * streams that are connected to the same output device. That means + * the streams will always be played back sample-by-sample + * synchronously. If stream operations like pa_stream_cork() are + * issued on one of the synchronized streams, they are simultaneously + * issued on the others. + * + * To synchronize a stream to another, just pass the "master" stream + * as last argument to pa_stream_connect_playack(). To make sure that + * the freshly created stream doesn't start playback right-away, make + * sure to pass PA_STREAM_START_CORKED and - after all streams have + * been created - uncork them all with a single call to + * pa_stream_cork() for the master stream. + * + * To make sure that a particular stream doesn't stop to play when a + * server side buffer underrun happens on it while the other + * synchronized streams continue playing and hence deviate you need to + * pass a "prebuf" pa_buffer_attr of 0 when connecting it. + * + * \section seek_modes Seeking in the Playback Buffer + * + * T.B.D * \section disc_sec Disconnecting * * When a stream has served is purpose it must be disconnected with * pa_stream_disconnect(). If you only unreference it, then it will live on * and eat resources both locally and on the server until you disconnect the * context. + * */ /** \file diff --git a/src/polyp/volume.h b/src/polyp/volume.h index 181784f4..a72069eb 100644 --- a/src/polyp/volume.h +++ b/src/polyp/volume.h @@ -53,8 +53,14 @@ * For simple multiplication, pa_sw_volume_multiply() and * pa_sw_cvolume_multiply() can be used. * - * Calculations can only be reliably be performed on software volumes as - * it is commonly unknown what scale hardware volumes use. + * Calculations can only be reliably performed on software volumes + * as it is commonly unknown what scale hardware volumes relate to. + * + * The functions described above are only valid when used with + * software volumes. Hence it is usually a better idea to treat all + * volume values as opaque with a range from PA_VOLUME_MUTE (0%) to + * PA_VOLUME_NORM (100%) and to refrain from any calculations with + * them. * * \section conv_sec Convenience functions * -- cgit From 20f4ae65f2ec49cc0ef733b67c5194a0eb3d453b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Apr 2006 13:45:38 +0000 Subject: more documentation updates git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@697 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/channelmap.h | 4 +- src/polyp/context.h | 4 +- src/polyp/def.h | 2 +- src/polyp/glib-mainloop.h | 2 +- src/polyp/introspect.h | 22 +++++----- src/polyp/mainloop.h | 10 ++--- src/polyp/sample.h | 8 ++-- src/polyp/scache.h | 2 +- src/polyp/stream.h | 109 ++++++++++++++++++++++++++++++++-------------- src/polyp/subscribe.h | 2 +- src/polyp/volume.h | 4 +- 11 files changed, 106 insertions(+), 63 deletions(-) diff --git a/src/polyp/channelmap.h b/src/polyp/channelmap.h index 99020583..bb9f78b1 100644 --- a/src/polyp/channelmap.h +++ b/src/polyp/channelmap.h @@ -25,7 +25,7 @@ #include #include -/** \page channelmap Channel maps +/** \page channelmap Channel Maps * * \section overv_sec Overview * @@ -48,7 +48,7 @@ * \li pa_channel_map_init_auto() - Create a standard channel map for up to * six channels. * - * \section conv_sec Convenience functions + * \section conv_sec Convenience Functions * * The library contains a number of convenience functions for dealing with * channel maps: diff --git a/src/polyp/context.h b/src/polyp/context.h index 84830811..01c1b76a 100644 --- a/src/polyp/context.h +++ b/src/polyp/context.h @@ -36,7 +36,7 @@ * It allows full access to all available functions. This also means that * it is rather complex and can take some time to fully master. * - * \section mainloop_sec Main loop abstraction + * \section mainloop_sec Main Loop Abstraction * * The API is based around an asynchronous event loop, or main loop, * abstraction. This abstraction contains three basic elements: @@ -63,7 +63,7 @@ * \ref mainloop-signal.h. These rely only on the main loop abstraction * and can therefore be used with any of the implementations. * - * \section refcnt_sec Reference counting + * \section refcnt_sec Reference Counting * * Almost all objects in polypaudio are reference counted. What that means * is that you rarely malloc() or free() any objects. Instead you increase diff --git a/src/polyp/def.h b/src/polyp/def.h index 432bd8ce..80e3092b 100644 --- a/src/polyp/def.h +++ b/src/polyp/def.h @@ -119,7 +119,7 @@ typedef enum pa_stream_flags { * ahead can be corrected * quickly, without the need to * wait. */ - PA_STREAM_AUTO_TIMING_UPDATE = 8 /** If set timing update requests + PA_STREAM_AUTO_TIMING_UPDATE = 8 /**< If set timing update requests * are issued periodically * automatically. Combined with * PA_STREAM_INTERPOLATE_TIMING diff --git a/src/polyp/glib-mainloop.h b/src/polyp/glib-mainloop.h index bc66409b..ce885e13 100644 --- a/src/polyp/glib-mainloop.h +++ b/src/polyp/glib-mainloop.h @@ -27,7 +27,7 @@ #include #include -/** \page glib-mainloop GLIB main loop bindings +/** \page glib-mainloop GLIB Main Loop Bindings * * \section overv_sec Overview * diff --git a/src/polyp/introspect.h b/src/polyp/introspect.h index a8292ba1..9a0edb79 100644 --- a/src/polyp/introspect.h +++ b/src/polyp/introspect.h @@ -30,7 +30,7 @@ #include #include -/** \page introspect Server query and control +/** \page introspect Server Query and Control * * \section overv_sec Overview * @@ -62,19 +62,19 @@ * duration of the callback. If they are required after the callback is * finished, a deep copy must be performed. * - * \subsection server_subsec Server information + * \subsection server_subsec Server Information * * The server can be queried about its name, the environment it's running on * and the currently active global defaults. Calling * pa_context_get_server_info() will get access to a pa_server_info structure * containing all of these. * - * \subsection memstat_subsec Memory usage + * \subsection memstat_subsec Memory Usage * * Statistics about memory usage can be fetched using pa_context_stat(), * giving a pa_stat_info structure. * - * \subsection sinksrc_subsec Sinks and sources + * \subsection sinksrc_subsec Sinks and Sources * * The server can have an arbitrary number of sinks and sources. Each sink * and source have both an index and a name associated with it. As such @@ -90,7 +90,7 @@ * All three method use the same callback and will provide a pa_sink_info or * pa_source_info structure. * - * \subsection siso_subsec Sink inputs and source outputs + * \subsection siso_subsec Sink Inputs and Source Outputs * * Sink inputs and source outputs are the representations of the client ends * of streams inside the server. I.e. they connect a client stream to one of @@ -119,13 +119,13 @@ * Note that this only retrieves information about the sample, not the sample * data itself. * - * \subsection module_subsec Modules + * \subsection module_subsec Driver Modules * - * Polypaudio modules are identified by index and are retrieved using either + * Polypaudio driver modules are identified by index and are retrieved using either * pa_context_get_module_info() or pa_context_get_module_info_list(). The * information structure is called pa_module_info. * - * \subsection autoload_subsec Autoload entries + * \subsection autoload_subsec Autoload Entries * * Modules can be autoloaded as a result of a client requesting a certain * sink or source. This mapping between sink/source names and modules can be @@ -147,7 +147,7 @@ * modified in different ways. Note that these changes will affect all * connected clients and not just the one issuing the request. * - * \subsection sinksrc_subsec Sinks and sources + * \subsection sinksrc_subsec Sinks and Sources * * The most common change one would want to do to sinks and sources is to * modify the volume of the audio. Identical to how sinks and sources can @@ -165,7 +165,7 @@ * \li By name - pa_context_set_sink_mute_by_name() / * pa_context_set_source_mute_by_name() * - * \subsection siso_subsec Sink inputs and source outputs + * \subsection siso_subsec Sink Inputs and Source Outputs * * If an application desires to modify the volume of just a single stream * (commonly one of its own streams), this can be done by setting the volume @@ -184,7 +184,7 @@ * Server modules can be remotely loaded and unloaded using * pa_context_load_module() and pa_context_unload_module(). * - * \subsection autoload_subsec Autoload entries + * \subsection autoload_subsec Autoload Entries * * New module autoloading rules can be added, and existing can be removed * using pa_context_add_autoload() and pa_context_remove_autoload_by_index() diff --git a/src/polyp/mainloop.h b/src/polyp/mainloop.h index 6fb2a96c..fe2b4c5b 100644 --- a/src/polyp/mainloop.h +++ b/src/polyp/mainloop.h @@ -27,7 +27,7 @@ PA_C_DECL_BEGIN -/** \page mainloop Mainloop +/** \page mainloop Main Loop * * \section overv_sec Overview * @@ -81,15 +81,13 @@ void pa_mainloop_free(pa_mainloop* m); /** Prepare for a single iteration of the main loop. Returns a negative value on error or exit request. timeout specifies a maximum timeout for the subsequent -poll, or -1 for blocking behaviour. Defer events are also dispatched when this -function is called. On success returns the number of source dispatched in this -iteration.*/ +poll, or -1 for blocking behaviour. .*/ int pa_mainloop_prepare(pa_mainloop *m, int timeout); /** Execute the previously prepared poll. Returns a negative value on error.*/ int pa_mainloop_poll(pa_mainloop *m); -/** Dispatch timeout and io events from the previously executed poll. Returns +/** Dispatch timeout, io and deferred events from the previously executed poll. Returns a negative value on error. On success returns the number of source dispatched. */ int pa_mainloop_dispatch(pa_mainloop *m); @@ -101,7 +99,7 @@ for pa_mainloop_prepare(), pa_mainloop_poll() and pa_mainloop_dispatch(). Returns a negative value on error or exit request. If block is nonzero, block for events if none are queued. Optionally return the return value as specified with the main loop's quit() routine in the integer variable retval points -to. On success returns the number of source dispatched in this iteration. */ +to. On success returns the number of sources dispatched in this iteration. */ int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval); /** Run unlimited iterations of the main loop object until the main loop's quit() routine is called. */ diff --git a/src/polyp/sample.h b/src/polyp/sample.h index 0706be5a..4de84301 100644 --- a/src/polyp/sample.h +++ b/src/polyp/sample.h @@ -28,14 +28,14 @@ #include -/** \page sample Sample format specifications +/** \page sample Sample Format Specifications * * \section overv_sec Overview * * Polypaudio is capable of handling a multitude of sample formats, rates * and channels, transparently converting and mixing them as needed. * - * \section format_sec Sample format + * \section format_sec Sample Format * * Polypaudio supports the following sample formats: * @@ -52,7 +52,7 @@ * The sample formats that are sensitive to endianness have convenience * macros for native endian (NE), and reverse endian (RE). * - * \section rate_sec Sample rates + * \section rate_sec Sample Rates * * Polypaudio supports any sample rate between 1 Hz and 4 GHz. There is no * point trying to exceed the sample rate of the output device though as the @@ -78,7 +78,7 @@ * \li pa_bytes_to_usec() - Calculate the time it would take to play a buffer * of a certain size. * - * \section util_sec Convenience functions + * \section util_sec Convenience Functions * * The library also contains a couple of other convenience functions: * diff --git a/src/polyp/scache.h b/src/polyp/scache.h index a6b312f5..91890673 100644 --- a/src/polyp/scache.h +++ b/src/polyp/scache.h @@ -28,7 +28,7 @@ #include #include -/** \page scache Sample cache +/** \page scache Sample Cache * * \section overv_sec Overview * diff --git a/src/polyp/stream.h b/src/polyp/stream.h index 6367e868..a832fc66 100644 --- a/src/polyp/stream.h +++ b/src/polyp/stream.h @@ -31,7 +31,7 @@ #include #include -/** \page streams Audio streams +/** \page streams Audio Streams * * \section overv_sec Overview * @@ -67,14 +67,16 @@ * pa_stream_set_state_callback(), and wait for the stream to enter an active * state. * - * \subsection bufattr_subsec Buffer attributes + * \subsection bufattr_subsec Buffer Attributes * - * Playback and record streams always have a server side buffer as part of the data flow. - * The size of this buffer strikes a compromise between low latency and - * sensitivity for buffer overflows/underruns. + * Playback and record streams always have a server side buffer as + * part of the data flow. The size of this buffer strikes a + * compromise between low latency and sensitivity for buffer + * overflows/underruns. * - * The buffer is described with a pa_buffer_attr structure which contains a - * number of field: + * The buffer metrics may be controlled by the application. They are + * described with a pa_buffer_attr structure which contains a number + * of fields: * * \li maxlength - The absolute maximum number of bytes that can be stored in * the buffer. If this value is exceeded then data will be @@ -82,16 +84,37 @@ * \li tlength - The target length of a playback buffer. The server will only * send requests for more data as long as the buffer has less * than this number of bytes of data. - * \li prebuf - Number of bytes that need to be in the buffer before playback - * will commence. Start of playback can be forced using - * pa_stream_trigger() even though the prebuffer size hasn't been - * reached. + * \li prebuf - Number of bytes that need to be in the buffer before + * playback will commence. Start of playback can be forced using + * pa_stream_trigger() even though the prebuffer size hasn't been + * reached. If a buffer underrun occurs, this prebuffering will be + * again enabled. If the playback shall never stop in case of a buffer + * underrun, this value should be set to 0. In that case the read + * index of the output buffer overtakes the write index, and hence the + * fill level of the buffer is negative. * \li minreq - Minimum free number of the bytes in the playback buffer before * the server will request more data. * \li fragsize - Maximum number of bytes that the server will push in one * chunk for record streams. * - * \section transfer_sec Transferring data + * The server side playback buffers are indexed by a write and a read + * index. The application writes to the write index and the sound + * device reads from the read index. The read index is increased + * monotonically, while the write index may be freely controlled by + * the application. Substracting the read index from the write index + * will give you the current fill level of the buffer. The read/write + * indexes are 64bit values and measured in bytes, they will never + * wrap. The current read/write index may be queried using + * pa_stream_get_timing_info() (see below for more information). In + * case of a buffer underrun the read index is equal or larger than + * the write index. Unless the prebuf value is 0, Polypaudio will + * temporarily pause playback in such a case, and wait until the + * buffer is filled up to prebuf bytes again. If prebuf is 0, the + * read index may be larger than the write index, in which case + * silence is played. If the application writes data to indexes lower + * than the read index, the data is immediately lost. + * + * \section transfer_sec Transferring Data * * Once the stream is up, data can start flowing between the client and the * server. Two different access models can be used to transfer the data: @@ -112,7 +135,7 @@ * record. Make sure you do not overflow the playback buffers as data will be * dropped. * - * \section bufctl_sec Buffer control + * \section bufctl_sec Buffer Control * * The transfer buffers can be controlled through a number of operations: * @@ -126,6 +149,23 @@ * \li pa_stream_flush() - Drop all data from the playback buffer and do not * wait for it to finish playing. * + * \section seek_modes Seeking in the Playback Buffer + * + * A client application may freely seek in the playback buffer. To + * accomplish that the pa_stream_write() function takes a seek mode + * and an offset argument. The seek mode is one of: + * + * \li PA_SEEK_RELATIVE - seek relative to the current write index + * \li PA_SEEK_ABSOLUTE - seek relative to the beginning of the playback buffer, (i.e. the first that was ever played in the stream) + * \li PA_SEEK_RELATIVE_ON_READ - seek relative to the current read index. Use this to write data to the output buffer that should be played as soon as possible + * \li PA_SEEK_RELATIVE_END - seek relative to the last byte ever written. + * + * If an application just wants to append some data to the output + * buffer, PA_SEEK_RELATIVE and an offset of 0 should be used. + * + * After a call to pa_stream_write() the write index will be left at + * the position right after the last byte of the written data. + * * \section latency_sec Latency * * A major problem with networked audio is the increased latency caused by @@ -134,8 +174,10 @@ * * To get the raw data needed to calculate latencies, call * pa_stream_get_timing_info(). This will give you a pa_timing_info - * structure that contains everything that is known about buffers, - * transport delays and the backend active in the server. + * structure that contains everything that is known about the server + * side buffer transport delays and the backend active in the + * server. (Besides other things it contains the write and read index + * values mentioned above.) * * This structure is updated every time a * pa_stream_update_timing_info() operation is executed. (i.e. before @@ -157,32 +199,38 @@ * you can call pa_stream_get_time() or pa_stream_get_latency(). The * former will return the current playback time of the hardware since * the stream has been started. The latter returns the time a sample - * that you write now takes to be played by the hardware. + * that you write now takes to be played by the hardware. These two + * functions base their calculations on the same data that is returned + * by pa_stream_get_timing_info(). Hence the same rules for keeping + * the timing data up-to-date apply here. In case the write or read + * index is corrupted, these two functions will fail with + * PA_ERR_NODATA set. * * Since updating the timing info structure usually requires a full - * round trip and some applications monitor the timing very often - * Polypaudio offers a timing interpolation system. If + * network round trip and some applications monitor the timing very + * often Polypaudio offers a timing interpolation system. If * PA_STREAM_INTERPOLATE_TIMING is passed when connecting the stream, * pa_stream_get_time() and pa_stream_get_latency() will try to * interpolate the current playback time/latency by estimating the * number of samples that have been played back by the hardware since * the last regular timing update. It is espcially useful to combine * this option with PA_STREAM_AUTO_TIMING_UPDATE, which will enable - * you to monitor the current playback time/latency very precisely - * without requiring a network round trip every time. + * you to monitor the current playback time/latency very precisely and + * very frequently without requiring a network round trip every time. * * \section flow_sec Overflow and underflow * - * Even with the best precautions, buffers will sometime over - or underflow. - * To handle this gracefully, the application can be notified when this - * happens. Callbacks are registered using pa_stream_set_overflow_callback() - * and pa_stream_set_underflow_callback(). + * Even with the best precautions, buffers will sometime over - or + * underflow. To handle this gracefully, the application can be + * notified when this happens. Callbacks are registered using + * pa_stream_set_overflow_callback() and + * pa_stream_set_underflow_callback(). * - * \section sync_streams Sychronizing Multiple Playback Streams. + * \section sync_streams Sychronizing Multiple Playback Streams * - * Polypaudio allows applications to fully synchronize multiple playback - * streams that are connected to the same output device. That means - * the streams will always be played back sample-by-sample + * Polypaudio allows applications to fully synchronize multiple + * playback streams that are connected to the same output device. That + * means the streams will always be played back sample-by-sample * synchronously. If stream operations like pa_stream_cork() are * issued on one of the synchronized streams, they are simultaneously * issued on the others. @@ -199,9 +247,6 @@ * synchronized streams continue playing and hence deviate you need to * pass a "prebuf" pa_buffer_attr of 0 when connecting it. * - * \section seek_modes Seeking in the Playback Buffer - * - * T.B.D * \section disc_sec Disconnecting * * When a stream has served is purpose it must be disconnected with @@ -297,7 +342,7 @@ int pa_stream_peek( const void **data /**< Pointer to pointer that will point to data */, size_t *length /**< The length of the data read */); -/** Remove the current fragment. It is invalid to do this without first +/** Remove the current fragment on record streams. It is invalid to do this without first * calling pa_stream_peek(). \since 0.8 */ int pa_stream_drop(pa_stream *p); diff --git a/src/polyp/subscribe.h b/src/polyp/subscribe.h index 75b4696f..d8326e1c 100644 --- a/src/polyp/subscribe.h +++ b/src/polyp/subscribe.h @@ -28,7 +28,7 @@ #include #include -/** \page subscribe Event subscription +/** \page subscribe Event Subscription * * \section overv_sec Overview * diff --git a/src/polyp/volume.h b/src/polyp/volume.h index a72069eb..0da5f54f 100644 --- a/src/polyp/volume.h +++ b/src/polyp/volume.h @@ -26,7 +26,7 @@ #include #include -/** \page volume Volume control +/** \page volume Volume Control * * \section overv_sec Overview * @@ -62,7 +62,7 @@ * PA_VOLUME_NORM (100%) and to refrain from any calculations with * them. * - * \section conv_sec Convenience functions + * \section conv_sec Convenience Functions * * To handle the pa_cvolume structure, the Polypaudio library provides a * number of convenienc functions: -- cgit From 5639b7eb7f775738b89ba1af3a8d5ecdf646fb75 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Apr 2006 13:46:02 +0000 Subject: doc updates git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@698 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/todo b/doc/todo index 3613217c..101871c5 100644 --- a/doc/todo +++ b/doc/todo @@ -4,9 +4,6 @@ Test: - module-combine - module-tunnel -Fixes: -- correct API docs regarding timing work - Post 0.8: - alsa mmap driver - add radio module -- cgit From df108afe352a4f0e8d67510f923878e954714c94 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Apr 2006 15:10:55 +0000 Subject: update documentation for release 0.8 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@699 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/FAQ.html.in | 3 +-- doc/Makefile.am | 2 +- doc/README.html.in | 65 +++++++++++++++++++++++++++++++++++------------------ doc/cli.html.in | 20 +++++++++++------ doc/modules.html.in | 65 +++++++++++++++++++++++++++++++++++++++++++++++------ doc/style.css | 15 ++++--------- 6 files changed, 120 insertions(+), 50 deletions(-) diff --git a/doc/FAQ.html.in b/doc/FAQ.html.in index 9cacfb4c..0e738217 100644 --- a/doc/FAQ.html.in +++ b/doc/FAQ.html.in @@ -128,7 +128,6 @@ bidilink unix-client:/tmp/polypaudio/cli

    BTW: Someone should package that great tool for Debian!

    -

    New: There's now a tool pacmd that automates sending SIGUSR2 to the daemon and running a bidilink like tool for you.

    @@ -152,6 +151,6 @@ bidilink unix-client:/tmp/polypaudio/cli
    -
    Lennart Poettering <@PACKAGE_BUGREPORT@>, September 2004
    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, April 2006
    $Id$
    diff --git a/doc/Makefile.am b/doc/Makefile.am index c68c00f5..a5884abd 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -16,7 +16,7 @@ # along with polypaudio; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -noinst_DATA = README.html cli.html modules.html daemon.html +noinst_DATA = README.html cli.html modules.html daemon.html FAQ.html EXTRA_DIST = $(noinst_DATA) style.css README.html.in cli.html.in modules.html.in daemon.html.in todo FAQ.html.in MAINTAINERCLEANFILES = README.html cli.html modules.html daemon.html FAQ.html diff --git a/doc/README.html.in b/doc/README.html.in index eb57fdb7..dbf85411 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -10,13 +10,13 @@

    polypaudio @PACKAGE_VERSION@

    -

    Copyright 2004 Lennart Poettering <@PACKAGE_BUGREPORT@>

    +

    Copyright 2004-2006 Lennart Poettering <@PACKAGE_BUGREPORT@> and Pierre Ossman

    • License
    • News
    • Overview
    • -
    • Status
    • +
    • Current Status
    • Documentation
    • Requirements
    • Installation
    • @@ -42,6 +42,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

      News

      +
      Thu Apr 13 2006:

      Version 0.8 released; +changes include: too many to count; many, many minor fixes.

      +
      Sun Nov 21 2004:

      Version 0.7 released; changes include: IPv6 support; PID file support; publish credentials @@ -92,13 +96,12 @@ href="@PACKAGE_URL@polypaudio-0.1.tar.gz">Version 0.1 released

      Overview

      -

      polypaudio is a sound server for Linux and other Unix like -operating systems. It is intended to be an improved drop-in +

      polypaudio is a networked sound server for Linux and other +Unix like operating systems. It is intended to be an improved drop-in replacement for the Enlightened Sound -Daemon (ESOUND). It is my ultimate ambition to get Polypaudio into -Gnome as a replacement for ESOUND. In -addition to the features ESOUND provides polypaudio has:

      +Daemon (ESOUND). In addition to the features ESOUND provides +polypaudio has:

      • Extensible plugin architecture (by loading dynamic loadable modules with dlopen())
      • @@ -110,9 +113,10 @@ addition to the features ESOUND provides polypaudio has:

      • Flexible, implicit sample type conversion and resampling
      • "Zero-Copy" architecture
      • Module autoloading
      • -
      • Very accurate latency measurement for playback and recordin.
      • +
      • Very accurate latency measurement for playback and recording.
      • May be used to combine multiple sound cards to one (with sample rate adjustment)
      • Client side latency interpolation
      • +
      • Ability to fully synchronize multiple playback streams

      Both the core and the client API are completely asynchronous making @@ -129,19 +133,25 @@ available. A simple main loop implementation is available as well.

    • module-oss: driver for Open Sound System audio sinks and sources.
    • module-oss-mmap: same as above, but uses mmap() access to the audio buffer. Not as compatible
    • module-alsa-sink, module-alsa-source: drivers for ALSA sinks and sources
    • +
    • module-solaris: drivers for Solaris audio sinks and sources
    • +
    • module-waveout: drivers for Microsoft Windows audio sinks and sources
    • module-pipe-sink, module-pipe-source: demonstration module providing UNIX fifos backed sinks/sources
    • module-combine: combine multiple sinks into one.
    • module-sine: a sine generate sink input.
    • module-x11-bell: play a sample from the sample cache on every X11 bell event.
    • module-x11-publish: store Polypaudio credentials in the X11 root window.
    • -
    • module-esound-protocol-tcp, module-esound-protocol-tcp6, module-esound-protocol-unix: ESOUND compatibility modules (for TCP/IPv6 resp. TCP/IPv6 resp. UNIX domain sockets)
    • -
    • module-native-protocol-tcp, module-native-protocol-tcp6, module-native-protocol-unix: Native polypaudio protocol (for TCP/IPv4 resp. TCP/IPv6 resp. UNIX domain sockets)
    • -
    • module-simple-protocol-tcp, module-simple-protocol-tcp6, module-simple-protocol-unix: Simplistic protocol for playback/capture for usage with tools like netcat (for TCP/IP resp. UNIX domain sockets)
    • -
    • module-cli-protocol-tcp, module-cli-protocol-tcp6, module-cli-protocol-unix, module-cli: Expose polypaudio's internals whith a simple command line interface. (for TCP/IP resp. UNIX domain sockets resp. STDIN/STDOUT)
    • +
    • module-esound-protocol-tcp, module-esound-protocol-unix: ESOUND compatibility modules (for TCP/IP resp. UNIX domain sockets)
    • +
    • module-native-protocol-tcp, module-native-protocol-unix: Native polypaudio protocol (for TCP/IP resp. UNIX domain sockets)
    • +
    • module-simple-protocol-tcp, module-simple-protocol-unix: Simplistic protocol for playback/capture for usage with tools like netcat (for TCP/IP resp. UNIX domain sockets)
    • +
    • module-cli-protocol-tcp, module-cli-protocol-unix, module-cli: Expose polypaudio's internals whith a simple command line interface. (for TCP/IP resp. UNIX domain sockets resp. STDIN/STDOUT)
    • module-tunnel-sink, module-tunnel-source: make sinks/sources from other hosts available locally.
    • module-match: adjust volume automatically for newly created playback streams based on a regular expression matching table.
    • module-null-sink: a clocked sink similar to /dev/null.
    • module-esound-sink: a sink for forwarding audio data to an ESOUND server.
    • +
    • module-detect: a module which automatically detects what sound hardware is available locally and which loads the required driver modules.
    • +
    • module-lirc: a module to control the volume of a sink with infrared remote controls supported by LIRC.
    • +
    • module-mmkbd-evdev: a module to control the volume of a sink with the special volume keys of a multimeda keyboard.
    • +
    • module-zeroconf-publish: a module to publish local sources/sinks using mDNS zeroconf.

    polypaudio is the successor of my previous, ill-fated @@ -165,7 +175,7 @@ href="http://xine.sf.net/">Xine (merged in Xine CVS). Drivers for PortAudio will be released shortly.

    -

    Status

    +

    Current Status

    Version @PACKAGE_VERSION@ is quite usable. It matches and supersedes ESOUND's feature set in nearly all areas.

    @@ -178,7 +188,11 @@ release to release. The client API's library version number is currently fixed t

    There is some preliminary documentation available: modules.html, cli.html, daemon.html, FAQ.html, .

    +href="daemon.html">daemon.html and FAQ.html.

    + +

    There is a Trac based Wiki for Polypaudio available.

    + +

    First Steps

    @@ -231,7 +245,7 @@ questions.

    Requirements

    -

    Currently, polypaudio is tested on Linux and FreeBSD only. It requires an OSS or ALSA compatible soundcard.

    +

    Currently, polypaudio is tested on Linux, FreeBSD, Solaris and Microsoft Windows. It requires an OSS, ALSA, Win32 or Solaris compatible soundcard.

    polypaudio was developed and tested on Debian GNU/Linux "testing" from November 2004, it should work on most other Linux @@ -239,11 +253,16 @@ distributions (and maybe Unix versions) since it uses GNU autoconf and GNU libtool for source code configuration and shared library management.

    -

    polypaudio needs libwrap, polypaudio needs Secret Rabbit Code (aka libsamplerate), libsndfile, alsa-lib and liboil.

    + +

    Optionally it can make use of libwrap, alsa-lib, libasyncns, +lirc, HOWL (or preferably the compatibility layer included in its superior replacement Avahi) and GLIB. (The latter is required for building the GLIB main loop integration module only.)

    @@ -271,18 +290,20 @@ compilation and make install (as root) for installation of

    The current release is @PACKAGE_VERSION@

    -

    Get polypaudio's development sources from the Subversion repository (viewcvs):

    +

    Get polypaudio's development sources from the Subversion repository (viewcvs):

    -
    svn checkout svn://seth.intheinter.net/polypaudio/trunk polypaudio
    +
    svn checkout svn://0pointer.de/polypaudio/trunk polypaudio

    If you want to be notified whenever I release a new version of this software use the subscription feature of Freshmeat.

    -

    New! There is a general discussion mailing list for polypaudio available.

    +

    There is a general discussion mailing list for polypaudio available. In addition, you can subscribe to SVN changes and Trac Tickets.

    + +

    There is a Trac based Wiki for Polypaudio available.

    -

    New! There is now a Polypaudio wiki (based on trac) available.

    +

    Please report bugs to our Trac ticket system.


    -
    Lennart Poettering <@PACKAGE_BUGREPORT@>, November 2004
    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, April 2006
    $Id$
    diff --git a/doc/cli.html.in b/doc/cli.html.in index 61d29e5a..0db96c36 100644 --- a/doc/cli.html.in +++ b/doc/cli.html.in @@ -68,13 +68,19 @@ returned by modules.

    Configuration Commands

    -

    set-sink-volume

    +

    set-sink-volume/set-source-volume

    -

    Set the volume of the specified sink. You may specify the sink either -by its index in the sink list or by its name. The volume should be an -integer value greater or equal than 0 (= muted). Volume 256 -(0x100) is normal volume, values greater than this amplify -the audio signal with clipping.

    +

    Set the volume of the specified sink or source. You may specify the sink/source either +by its index in the sink/source list or by its name. The volume should be an +integer value greater or equal than 0 (= muted). Volume 65536 +(0x10000) is normal volume, values greater than this amplify +the audio signal (with clipping).

    + +

    set-sink-mute/set-source-mute

    + +

    Mute or unmute the specified sink our source. You may specify the +sink/source either by its index or by its name. The mute value is +either 0 or 1.

    set-sink-input-volume

    @@ -209,6 +215,6 @@ play-file /usr/share/sounds/startup3.wav combined
    -
    Lennart Poettering <@PACKAGE_BUGREPORT@>, November 2004
    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, April 2006
    $Id$
    diff --git a/doc/modules.html.in b/doc/modules.html.in index a549396d..64bc4bbc 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -100,6 +100,24 @@ compatible as module-oss.

    This module accepts exactly the same arguments as module-oss.

    +

    module-solaris

    + +

    Provides a sink and source for the Solaris audio device.

    + +

    In addition to the general device driver options described above this module supports:

    + + + + + +
    record=Accepts a binary numerical value for enabling (resp. disabling) the recording on this device. (defaults: to 1)
    playback=Accepts a binary numerical value for enabling (resp. disabling) the playback on this device. (defaults: to 1)
    buffer_size=Record buffer size
    + +

    module-waveout

    + +

    Provides a sink and source for the Win32 audio device.

    + +

    This module supports all arguments thet module-oss supports except device=.

    +

    module-combine

    This combines two or more sinks into one. A new virtual sink is @@ -168,7 +186,7 @@ module see cli.html. -

    module-cli-protocol-{unix,tcp,tcp6}

    +

    module-cli-protocol-{unix,tcp}

    An implemenation of a simple command line based protocol for controlling the polypaudio daemon. If loaded, the user may @@ -182,7 +200,7 @@ service.

    This module exists in two versions: with the suffix -unix the service will listen on an UNIX domain socket in the local file system. With the suffix -tcp it will listen on a network -transparent TCP/IP socket.

    +transparent TCP/IP socket. (Both IPv6 and IPv4 - if available)

    This module supports the following options:

    @@ -191,10 +209,11 @@ transparent TCP/IP socket.

    loopback=(only for -tcp) Accepts a numerical binary value. If 1 the socket is bound to the loopback device, i.e. not publicly accessible. (defaults to 1) + listen=(only for -tcp) The IP address to listen on. If specified, supersedes the value specified in loopback= socket=(only for -unix) The UNIX socket name (defaults to /tmp/polypaudio/cli) -

    module-simple-protocol-{unix,tcp,tcp6}

    +

    module-simple-protocol-{unix,tcp}

    An implementation of a simple protocol which allows playback by using simple tools like netcat. Just connect to the listening @@ -231,13 +250,13 @@ about the two possible suffixes of this module.

    - +
    sink=, source=Specify the sink/source this service connects to
    public=If set to 0 not authentication is required to connect to the service
    auth-anonymous=If set to 1 no authentication is required to connect to the service
    cookie=Name of the cookie file for authentication purposes

    This implementation misses some features the original ESOUND has: e.g. there is no sample cache yet. However: XMMS works fine.

    -

    module-native-protocol-{unix,tcp,tcp6}

    +

    module-native-protocol-{unix,tcp}

    The native protocol of polypaudio.

    @@ -247,7 +266,8 @@ about the two possible suffixes of this module.

    In addition to the options supported by module-cli-protocol-*, this module supports:

    - + +
    public=If set to 0 not authentication is required to connect to the service
    auth-anonymous=If set to 1 no authentication is required to connect to the service
    auth-group=(only for -unix): members of the specified unix group may access the server without further auhentication.
    cookie=Name of the cookie file for authentication purposes
    @@ -320,7 +340,38 @@ already loaded protocol module is used.

    The volumes of all streams with titles starting with sample: are automatically set to 25. (FYI: All sample cache streams start with sample:)

    +

    module-detect

    + +

    Automatically detect the available sound hardware and load modules for it. Supports OSS, ALSA, Solaris and Win32 output drivers. + + + +
    just-one=If set to 1 the module will only try to load a single sink/source and than stop.
    + +

    module-zeroconf-publish

    + +

    Publish all local sinks/sources using mDNS Zeroconf.

    + +

    module-mmkbd-evdev

    + +

    Adjust the volume of a sink when the special multimedia buttons of modern keyboards are pressed.

    + + + + +
    device=Linux input device ("evdev", defaults to /dev/input/event0)
    sink=The sink to control
    + +

    module-lirc

    + +

    Adjust the volume of a sink when the volume buttons of an infrared remote control are pressed (through LIRC).

    + + + + + +
    config=The LIRC configuration file
    appname=The application name to pass to LIRC (defaults to polypaudio)
    sink=The sink to control
    +
    -
    Lennart Poettering <@PACKAGE_BUGREPORT@>, November 2004
    +
    Lennart Poettering <@PACKAGE_BUGREPORT@>, April 2006
    $Id$
    diff --git a/doc/style.css b/doc/style.css index a46592a2..a606c08e 100644 --- a/doc/style.css +++ b/doc/style.css @@ -18,17 +18,10 @@ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ -body { color: black; background-color: white; margin: 0.5cm; } +body { color: black; background-color: white; } a:link, a:visited { color: #900000; } -p { margin-left: 0.5cm; margin-right: 0.5cm; } -div.news-date { margin-left: 0.5cm; font-size: 80%; color: #4f0000; } -p.news-text { margin-left: 1cm; } -h1 { color: #00009F; } -h2 { color: #00009F; } -h3 { color: #00004F; margin-left: 0.5cm; } -ul { margin-left: .5cm; } -ol { margin-left: .5cm; } -pre { margin-left: .5cm; background-color: #f0f0f0; padding: 0.4cm;} -.grey { color: #afafaf; } +div.news-date { font-size: 80%; font-style: italic; } +pre { background-color: #f0f0f0; padding: 0.4cm; } +.grey { color: #8f8f8f; font-size: 80%; } table { margin-left: 1cm; border:1px solid lightgrey; padding: 0.2cm; } td { padding-left:10px; padding-right:10px; } -- cgit From 1f7a008f4331bfe21e2de6f2ec9cab997f310465 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Apr 2006 17:32:10 +0000 Subject: add new configure option to enable preloading even on architectures that support dlopen(). Useful for debugging git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@700 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 6 ++++++ src/Makefile.am | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 7d7f8f73..6511137e 100644 --- a/configure.ac +++ b/configure.ac @@ -398,6 +398,12 @@ if test "x$PREOPEN_MODS" != "xall" ; then AC_SUBST(PREOPEN_MODS) fi +AC_ARG_ENABLE( + [force-preopen], + AC_HELP_STRING([--enable-force-preopen],[Preopen modules, even when dlopen() is supported.]), + [FORCE_PREOPEN=1], [FORCE_PREOPEN=0]) +AM_CONDITIONAL([FORCE_PREOPEN], [test "x$FORCE_PREOPEN" = "x1"]) + AC_CONFIG_FILES([ Makefile src/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index a65938ef..c5e4638b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -109,7 +109,6 @@ polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) polypaudio_CPPFLAGS = $(AM_CPPFLAGS) polypaudio_LDADD = $(AM_LDADD) libpolypcore.la $(LIBLTDL) \ $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) $(LIBOIL_LIBS) -polypaudio_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -dlopen force $(foreach f,$(PREOPEN_LIBS),-dlopen $(f)) if PREOPEN_MODS PREOPEN_LIBS = $(PREOPEN_MODS) @@ -117,6 +116,12 @@ else PREOPEN_LIBS = $(modlib_LTLIBRARIES) endif +if FORCE_PREOPEN +polypaudio_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -dlpreopen force $(foreach f,$(PREOPEN_LIBS),-dlpreopen $(f)) +else +polypaudio_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -dlopen force $(foreach f,$(PREOPEN_LIBS),-dlopen $(f)) +endif + ################################### # Utility programs # ################################### -- cgit From d4b22f3000316940a2229fb324989a81589d5aca Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Apr 2006 17:32:33 +0000 Subject: make --enable-force-preopen the default for SVN builds git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@701 fefdeb5f-60dc-0310-8127-8f9354f1896f --- bootstrap.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap.sh b/bootstrap.sh index 31f3868a..19acffb5 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -59,7 +59,7 @@ else run_versioned automake "$VERSION" -a -c --foreign if test "x$NOCONFIGURE" = "x"; then - CFLAGS="-g -O0" ./configure --sysconfdir=/etc "$@" + CFLAGS="-g -O0" ./configure --sysconfdir=/etc --enable-force-preopen "$@" make clean fi fi -- cgit From fe64b89fd846518efec535f1b567d3b2bfa9bd70 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Apr 2006 17:33:06 +0000 Subject: add code to allow polypaudio dump preloaded modules using "--dump-modules" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@702 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/dumpmodules.c | 51 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/src/daemon/dumpmodules.c b/src/daemon/dumpmodules.c index bf29a681..c541c168 100644 --- a/src/daemon/dumpmodules.c +++ b/src/daemon/dumpmodules.c @@ -78,15 +78,41 @@ static void show_info(const char *name, const char *path, void (*info)(const cha } } +extern const lt_dlsymlist lt_preloaded_symbols[]; + +static int is_preloaded(const char *name) { + const lt_dlsymlist *l; + + for (l = lt_preloaded_symbols; l->name; l++) { + char buf[64], *e; + + if (l->address) + continue; + + snprintf(buf, sizeof(buf), "%s", l->name); + if ((e = strrchr(buf, '.'))) + *e = 0; + + if (!strcmp(name, buf)) + return 1; + } + + return 0; +} + static int callback(const char *path, lt_ptr data) { const char *e; pa_daemon_conf *c = (data); e = pa_path_get_filename(path); - if (strlen(e) > sizeof(PREFIX)-1 && !strncmp(e, PREFIX, sizeof(PREFIX)-1)) - show_info(e, path, c->log_level >= PA_LOG_INFO ? long_info : short_info); + if (strlen(e) <= sizeof(PREFIX)-1 || strncmp(e, PREFIX, sizeof(PREFIX)-1)) + return 0; + + if (is_preloaded(e)) + return 0; + show_info(e, path, c->log_level >= PA_LOG_INFO ? long_info : short_info); return 0; } @@ -95,6 +121,25 @@ void pa_dump_modules(pa_daemon_conf *c, int argc, char * const argv[]) { int i; for (i = 0; i < argc; i++) show_info(argv[i], NULL, long_info); - } else + } else { + const lt_dlsymlist *l; + + for (l = lt_preloaded_symbols; l->name; l++) { + char buf[64], *e; + + if (l->address) + continue; + + if (strlen(l->name) <= sizeof(PREFIX)-1 || strncmp(l->name, PREFIX, sizeof(PREFIX)-1)) + continue; + + snprintf(buf, sizeof(buf), "%s", l->name); + if ((e = strrchr(buf, '.'))) + *e = 0; + + show_info(buf, NULL, c->log_level >= PA_LOG_INFO ? long_info : short_info); + } + lt_dlforeachfile(NULL, callback, c); + } } -- cgit From 9854cfc146b555bc0b28008e638d221fe2eecf43 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Apr 2006 17:53:43 +0000 Subject: hmm, nothing important git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@703 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/modinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polypcore/modinfo.c b/src/polypcore/modinfo.c index e090a42f..39186ceb 100644 --- a/src/polypcore/modinfo.c +++ b/src/polypcore/modinfo.c @@ -42,7 +42,7 @@ pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl) { const char* (*func)(void); assert(dl); - i = pa_xmalloc0(sizeof(pa_modinfo)); + i = pa_xnew0(pa_modinfo, 1); if ((func = (const char* (*)(void)) lt_dlsym(dl, PA_SYMBOL_AUTHOR))) i->author = pa_xstrdup(func()); -- cgit From c25c549c420fe450b259b2bdcb2e200bf5862147 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Apr 2006 18:20:05 +0000 Subject: fix latency calculations of module-combine git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@704 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-combine.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 28e85427..80153900 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -200,7 +200,9 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { struct userdata *u = s->userdata; assert(s && u && u->sink && u->master); - return pa_sink_input_get_latency(u->master->sink_input); + return + pa_sink_input_get_latency(u->master->sink_input) + + pa_sink_get_latency(u->master->sink_input->sink); } static struct output *output_new(struct userdata *u, pa_sink *sink, int resample_method) { -- cgit From 010c049db267870138ac6cd0996d4fadaa401a7b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Apr 2006 18:27:35 +0000 Subject: include in-flux resampled chunk in latency calculations of playback streams git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@705 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-native.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 2aedd390..3f1d5ca2 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -1045,6 +1045,7 @@ static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ struct playback_stream *s; struct timeval tv, now; uint32_t idx; + pa_usec_t latency; assert(c && t); if (pa_tagstruct_getu32(t, &idx) < 0 || @@ -1060,7 +1061,12 @@ static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); reply = reply_new(tag); - pa_tagstruct_put_usec(reply, pa_sink_get_latency(s->sink_input->sink)); + + latency = pa_sink_get_latency(s->sink_input->sink); + if (s->sink_input->resampled_chunk.memblock) + latency += pa_bytes_to_usec(s->sink_input->resampled_chunk.length, &s->sink_input->sample_spec); + pa_tagstruct_put_usec(reply, latency); + pa_tagstruct_put_usec(reply, 0); pa_tagstruct_put_boolean(reply, pa_memblockq_is_readable(s->memblockq)); pa_tagstruct_put_timeval(reply, &tv); -- cgit From d153fdadde1a7780496d0d49e4dcc5b9f2c74d6a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Apr 2006 18:28:37 +0000 Subject: remove yet another item from the todo list git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@706 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index 101871c5..e756a41b 100644 --- a/doc/todo +++ b/doc/todo @@ -1,7 +1,6 @@ *** $Id$ *** Test: -- module-combine - module-tunnel Post 0.8: -- cgit From 7e8d46e2bbb59876e18d84d701bf499938115e37 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Apr 2006 18:55:55 +0000 Subject: unbreak module-tunnel git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@707 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 8f5e66e6..70cc950c 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -240,7 +240,6 @@ static void send_bytes(struct userdata *u) { while (u->requested_bytes > 0) { pa_memchunk chunk; if (pa_sink_render(u->sink, u->requested_bytes, &chunk) < 0) { - if (u->requested_bytes >= DEFAULT_TLENGTH-DEFAULT_PREBUF) send_prebuf_request(u); @@ -285,9 +284,8 @@ static void command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED ui static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; - pa_usec_t buffer_usec, sink_usec, source_usec, transport_usec; + pa_usec_t sink_usec, source_usec, transport_usec; int playing; - uint32_t queue_length; int64_t write_index, read_index; struct timeval local, remote, now; assert(pd && u); @@ -301,17 +299,15 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G return; } - if (pa_tagstruct_get_usec(t, &buffer_usec) < 0 || - pa_tagstruct_get_usec(t, &sink_usec) < 0 || + if (pa_tagstruct_get_usec(t, &sink_usec) < 0 || pa_tagstruct_get_usec(t, &source_usec) < 0 || pa_tagstruct_get_boolean(t, &playing) < 0 || - pa_tagstruct_getu32(t, &queue_length) < 0 || pa_tagstruct_get_timeval(t, &local) < 0 || pa_tagstruct_get_timeval(t, &remote) < 0 || pa_tagstruct_gets64(t, &write_index) < 0 || pa_tagstruct_gets64(t, &read_index) < 0 || !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid reply."); + pa_log(__FILE__": invalid reply. (latency)"); die(u); return; } @@ -369,6 +365,7 @@ static void stream_get_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_ pa_usec_t latency; const char *name, *description, *monitor_source_name, *driver; int mute; + uint32_t flags; pa_sample_spec sample_spec; pa_channel_map channel_map; pa_cvolume volume; @@ -395,8 +392,9 @@ static void stream_get_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_ pa_tagstruct_gets(t, &monitor_source_name) < 0 || pa_tagstruct_get_usec(t, &latency) < 0 || pa_tagstruct_gets(t, &driver) < 0 || + pa_tagstruct_getu32(t, &flags) < 0 || !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid reply."); + pa_log(__FILE__": invalid reply. (get_info)"); die(u); return; } @@ -491,7 +489,7 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN pa_tagstruct_getu32(t, &u->requested_bytes) < 0 || #endif !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid reply."); + pa_log(__FILE__": invalid reply. (create stream)"); die(u); return; } -- cgit From d981acee2ba121ba7e56ae89dd4e3e470c70fe80 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Apr 2006 18:56:28 +0000 Subject: remove yet another item from the todo list! This means we are now read for 0.8! git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@708 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/todo b/doc/todo index e756a41b..4a84054f 100644 --- a/doc/todo +++ b/doc/todo @@ -1,8 +1,5 @@ *** $Id$ *** -Test: -- module-tunnel - Post 0.8: - alsa mmap driver - add radio module -- cgit From c383a4c1146edb17f8c55c01eaf32c2d83deac09 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Apr 2006 19:07:12 +0000 Subject: * add a link to Cendio to the README git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@709 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/README.html.in b/doc/README.html.in index dbf85411..66c44627 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -97,7 +97,7 @@ href="@PACKAGE_URL@polypaudio-0.1.tar.gz">Version 0.1 released

    Overview

    polypaudio is a networked sound server for Linux and other -Unix like operating systems. It is intended to be an improved drop-in +Unix like operating systems and Microsoft Windows. It is intended to be an improved drop-in replacement for the Enlightened Sound Daemon (ESOUND). In addition to the features ESOUND provides @@ -284,6 +284,8 @@ compilation and make install (as root) for installation of

    Joe Marcus Clarke for porting Polypaudio to FreeBSD

    +

    Cendio AB for paying for Pierre's work on Polypaudio

    +

    Download

    The newest release is always available from @PACKAGE_URL@

    -- cgit From 9539dc4db483f31a33da7c3ab5b3b1f1a56e1bca Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Apr 2006 19:31:02 +0000 Subject: minor doc updates git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@710 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 2 -- doc/modules.html.in | 8 ++++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/README.html.in b/doc/README.html.in index 66c44627..3847a9e8 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -192,8 +192,6 @@ href="daemon.html">daemon.html and FAQ.html<

    There is a Trac based Wiki for Polypaudio available.

    -

    -

    First Steps

    Simply start the polypaudio daemon with the argument -nC

    diff --git a/doc/modules.html.in b/doc/modules.html.in index 64bc4bbc..67f0e172 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -275,6 +275,14 @@ about the two possible suffixes of this module.

    This is used internally when auto spawning a new daemon. Don't use it directly.

    +

    module-http-protocol-tcp

    + +

    A proof-of-concept HTTP module, which can be used to introspect +the current status of the polypaudio daemon using HTTP. Just load this +module and point your browser to http://localhost:4714/. This module takes the same arguments +as module-cli-protocol-tcp.

    +

    Miscellaneous

    module-x11-bell

    -- cgit From 86ad60185ae90520269d384d90569d2402c25dd1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Apr 2006 23:46:32 +0000 Subject: minor beautification git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@711 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/source-output.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polypcore/source-output.h b/src/polypcore/source-output.h index 98f6ab0c..1c612052 100644 --- a/src/polypcore/source-output.h +++ b/src/polypcore/source-output.h @@ -55,7 +55,7 @@ struct pa_source_output { void (*push)(pa_source_output *o, const pa_memchunk *chunk); void (*kill)(pa_source_output* o); - pa_usec_t (*get_latency) (pa_source_output *i); + pa_usec_t (*get_latency) (pa_source_output *o); pa_resampler* resampler; -- cgit From 9522b4484206ef3a99fb5586831a27fdfea0c373 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Apr 2006 23:47:33 +0000 Subject: add an RTP sender module git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@712 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/rtp/Makefile | 13 + src/modules/rtp/module-rtp-monitor.c | 340 ++ src/modules/rtp/rfc2327.txt | 2355 ++++++++++++++ src/modules/rtp/rfc2974.txt | 1011 ++++++ src/modules/rtp/rfc3550.txt | 5827 ++++++++++++++++++++++++++++++++++ src/modules/rtp/rfc3551.txt | 2467 ++++++++++++++ src/modules/rtp/rtp.c | 193 ++ src/modules/rtp/rtp.h | 51 + src/modules/rtp/sap.c | 107 + src/modules/rtp/sap.h | 43 + src/modules/rtp/sdp.c | 87 + src/modules/rtp/sdp.h | 33 + 12 files changed, 12527 insertions(+) create mode 100644 src/modules/rtp/Makefile create mode 100644 src/modules/rtp/module-rtp-monitor.c create mode 100644 src/modules/rtp/rfc2327.txt create mode 100644 src/modules/rtp/rfc2974.txt create mode 100644 src/modules/rtp/rfc3550.txt create mode 100644 src/modules/rtp/rfc3551.txt create mode 100644 src/modules/rtp/rtp.c create mode 100644 src/modules/rtp/rtp.h create mode 100644 src/modules/rtp/sap.c create mode 100644 src/modules/rtp/sap.h create mode 100644 src/modules/rtp/sdp.c create mode 100644 src/modules/rtp/sdp.h diff --git a/src/modules/rtp/Makefile b/src/modules/rtp/Makefile new file mode 100644 index 00000000..316beb72 --- /dev/null +++ b/src/modules/rtp/Makefile @@ -0,0 +1,13 @@ +# This is a dirty trick just to ease compilation with emacs +# +# This file is not intended to be distributed or anything +# +# So: don't touch it, even better ignore it! + +all: + $(MAKE) -C ../.. + +clean: + $(MAKE) -C ../.. clean + +.PHONY: all clean diff --git a/src/modules/rtp/module-rtp-monitor.c b/src/modules/rtp/module-rtp-monitor.c new file mode 100644 index 00000000..66332093 --- /dev/null +++ b/src/modules/rtp/module-rtp-monitor.c @@ -0,0 +1,340 @@ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-rtp-monitor-symdef.h" + +#include "rtp.h" +#include "sdp.h" +#include "sap.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Read data from source and send it to the network via RTP") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE( + "source= " + "format= " + "channels= " + "rate= " + "destinaton= " + "port= " + "mtu= " +) + +#define DEFAULT_PORT 5666 +#define SAP_PORT 9875 +#define DEFAULT_DESTINATION "224.0.0.252" +#define MEMBLOCKQ_MAXLENGTH (1024*170) +#define DEFAULT_MTU 1024 +#define SAP_INTERVAL 5000000 + +static const char* const valid_modargs[] = { + "source", + "format", + "channels", + "rate", + "destination", + "port", + NULL +}; + +struct userdata { + pa_module *module; + pa_core *core; + + pa_source_output *source_output; + pa_memblockq *memblockq; + + pa_rtp_context rtp_context; + pa_sap_context sap_context; + size_t mtu; + + pa_time_event *sap_event; +}; + +static void source_output_push(pa_source_output *o, const pa_memchunk *chunk) { + struct userdata *u; + assert(o); + u = o->userdata; + + if (pa_memblockq_push(u->memblockq, chunk) < 0) { + pa_log(__FILE__": Failed to push chunk into memblockq."); + return; + } + + pa_rtp_send(&u->rtp_context, u->mtu, u->memblockq); +} + +static void source_output_kill(pa_source_output* o) { + struct userdata *u; + assert(o); + u = o->userdata; + + pa_module_unload_request(u->module); + + pa_source_output_disconnect(u->source_output); + pa_source_output_unref(u->source_output); + u->source_output = NULL; +} + +static pa_usec_t source_output_get_latency (pa_source_output *o) { + struct userdata *u; + assert(o); + u = o->userdata; + + return pa_bytes_to_usec(pa_memblockq_get_length(u->memblockq), &o->sample_spec); +} + +static void sap_event(pa_mainloop_api *m, pa_time_event *t, const struct timeval *tv, void *userdata) { + struct userdata *u = userdata; + struct timeval next; + + assert(m); + assert(t); + assert(tv); + assert(u); + + pa_sap_send(&u->sap_context, 0); + + pa_log("SAP update"); + pa_gettimeofday(&next); + pa_timeval_add(&next, SAP_INTERVAL); + m->time_restart(t, &next); +} + +int pa__init(pa_core *c, pa_module*m) { + struct userdata *u; + pa_modargs *ma = NULL; + const char *dest; + uint32_t port = DEFAULT_PORT, mtu; + int af, fd = -1, sap_fd = -1; + pa_source *s; + pa_sample_spec ss; + pa_channel_map cm; + struct sockaddr_in sa4, sap_sa4; + struct sockaddr_in6 sa6, sap_sa6; + struct sockaddr_storage sa_dst; + pa_source_output *o = NULL; + uint8_t payload; + char *p; + int r; + socklen_t k; + struct timeval tv; + + assert(c); + assert(m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments"); + goto fail; + } + + if (!(s = pa_namereg_get(m->core, pa_modargs_get_value(ma, "source", NULL), PA_NAMEREG_SOURCE, 1))) { + pa_log(__FILE__": source does not exist."); + goto fail; + } + + ss = s->sample_spec; + pa_rtp_sample_spec_fixup(&ss); + cm = s->channel_map; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": failed to parse sample specification"); + goto fail; + } + + if (!pa_rtp_sample_spec_valid(&ss)) { + pa_log(__FILE__": specified sample type not compatible with RTP"); + goto fail; + } + + if (ss.channels != cm.channels) + pa_channel_map_init_auto(&cm, ss.channels); + + payload = pa_rtp_payload_type(&ss); + + mtu = (DEFAULT_MTU/pa_frame_size(&ss))*pa_frame_size(&ss); + + if (pa_modargs_get_value_u32(ma, "mtu", &mtu) < 0 || mtu < 1 || mtu % pa_frame_size(&ss) != 0) { + pa_log(__FILE__": invalid mtu."); + goto fail; + } + + if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) { + pa_log(__FILE__": port= expects a numerical argument between 1 and 65535."); + goto fail; + } + + if ((dest = pa_modargs_get_value(ma, "destination", DEFAULT_DESTINATION))) { + if (inet_pton(AF_INET6, dest, &sa6.sin6_addr) > 0) { + sa6.sin6_family = af = AF_INET6; + sa6.sin6_port = htons(port); + sap_sa6 = sa6; + sap_sa6.sin6_port = htons(SAP_PORT); + } else if (inet_pton(AF_INET, dest, &sa4.sin_addr) > 0) { + sa4.sin_family = af = AF_INET; + sa4.sin_port = htons(port); + sap_sa4 = sa4; + sap_sa4.sin_port = htons(SAP_PORT); + } else { + pa_log(__FILE__": invalid destination '%s'", dest); + goto fail; + } + } + + if ((fd = socket(af, SOCK_DGRAM, 0)) < 0) { + pa_log(__FILE__": socket() failed: %s", strerror(errno)); + goto fail; + } + + if (connect(fd, af == AF_INET ? (struct sockaddr*) &sa4 : (struct sockaddr*) &sa6, af == AF_INET ? sizeof(sa4) : sizeof(sa6)) < 0) { + pa_log(__FILE__": connect() failed: %s", strerror(errno)); + goto fail; + } + + if ((sap_fd = socket(af, SOCK_DGRAM, 0)) < 0) { + pa_log(__FILE__": socket() failed: %s", strerror(errno)); + goto fail; + } + + if (connect(sap_fd, af == AF_INET ? (struct sockaddr*) &sap_sa4 : (struct sockaddr*) &sap_sa6, af == AF_INET ? sizeof(sap_sa4) : sizeof(sap_sa6)) < 0) { + pa_log(__FILE__": connect() failed: %s", strerror(errno)); + goto fail; + } + + if (!(o = pa_source_output_new(s, __FILE__, "RTP Monitor Stream", &ss, &cm, PA_RESAMPLER_INVALID))) { + pa_log(__FILE__": failed to create source output."); + goto fail; + } + + o->push = source_output_push; + o->kill = source_output_kill; + o->get_latency = source_output_get_latency; + o->owner = m; + + u = pa_xnew(struct userdata, 1); + m->userdata = u; + o->userdata = u; + + u->module = m; + u->core = c; + u->source_output = o; + + u->memblockq = pa_memblockq_new( + 0, + MEMBLOCKQ_MAXLENGTH, + MEMBLOCKQ_MAXLENGTH, + pa_frame_size(&ss), + 1, + 0, + NULL, + c->memblock_stat); + + u->mtu = mtu; + + k = sizeof(sa_dst); + r = getsockname(fd, (struct sockaddr*) &sa_dst, &k); + assert(r >= 0); + + p = pa_sdp_build(af, + af == AF_INET ? (void*) &((struct sockaddr_in*) &sa_dst)->sin_addr : (void*) &((struct sockaddr_in6*) &sa_dst)->sin6_addr, + af == AF_INET ? (void*) &sa4.sin_addr : (void*) &sa6.sin6_addr, + "Polypaudio RTP Stream", port, payload, &ss); + + pa_rtp_context_init_send(&u->rtp_context, fd, 0, payload); + pa_sap_context_init_send(&u->sap_context, sap_fd, p); + + pa_log_info("RTP stream initialized with mtu %u on %s:%u, SSRC=0x%08x, payload=%u, initial sequence #%u", mtu, dest, port, u->rtp_context.ssrc, payload, u->rtp_context.sequence); + pa_log_info("SDP-Data:\n%s\nEOF", p); + + pa_sap_send(&u->sap_context, 0); + + pa_gettimeofday(&tv); + pa_timeval_add(&tv, SAP_INTERVAL); + u->sap_event = c->mainloop->time_new(c->mainloop, &tv, sap_event, u); + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + if (fd >= 0) + close(fd); + + if (sap_fd >= 0) + close(sap_fd); + + if (o) { + pa_source_output_disconnect(o); + pa_source_output_unref(o); + } + + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c); + assert(m); + + if (!(u = m->userdata)) + return; + + c->mainloop->time_free(u->sap_event); + + if (u->source_output) { + pa_source_output_disconnect(u->source_output); + pa_source_output_unref(u->source_output); + } + + pa_rtp_context_destroy(&u->rtp_context); + + pa_sap_send(&u->sap_context, 1); + pa_sap_context_destroy(&u->sap_context); + + pa_memblockq_free(u->memblockq); + + pa_xfree(u); +} diff --git a/src/modules/rtp/rfc2327.txt b/src/modules/rtp/rfc2327.txt new file mode 100644 index 00000000..ce77de61 --- /dev/null +++ b/src/modules/rtp/rfc2327.txt @@ -0,0 +1,2355 @@ + + + + + + +Network Working Group M. Handley +Request for Comments: 2327 V. Jacobson +Category: Standards Track ISI/LBNL + April 1998 + + + SDP: Session Description Protocol + +Status of this Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (1998). All Rights Reserved. + +Abstract + + This document defines the Session Description Protocol, SDP. SDP is + intended for describing multimedia sessions for the purposes of + session announcement, session invitation, and other forms of + multimedia session initiation. + + This document is a product of the Multiparty Multimedia Session + Control (MMUSIC) working group of the Internet Engineering Task + Force. Comments are solicited and should be addressed to the working + group's mailing list at confctrl@isi.edu and/or the authors. + +1. Introduction + + On the Internet multicast backbone (Mbone), a session directory tool + is used to advertise multimedia conferences and communicate the + conference addresses and conference tool-specific information + necessary for participation. This document defines a session + description protocol for this purpose, and for general real-time + multimedia session description purposes. This memo does not describe + multicast address allocation or the distribution of SDP messages in + detail. These are described in accompanying memos. SDP is not + intended for negotiation of media encodings. + + + + + + + + +Handley & Jacobson Standards Track [Page 1] + +RFC 2327 SDP April 1998 + + +2. Background + + The Mbone is the part of the internet that supports IP multicast, and + thus permits efficient many-to-many communication. It is used + extensively for multimedia conferencing. Such conferences usually + have the property that tight coordination of conference membership is + not necessary; to receive a conference, a user at an Mbone site only + has to know the conference's multicast group address and the UDP + ports for the conference data streams. + + Session directories assist the advertisement of conference sessions + and communicate the relevant conference setup information to + prospective participants. SDP is designed to convey such information + to recipients. SDP is purely a format for session description - it + does not incorporate a transport protocol, and is intended to use + different transport protocols as appropriate including the Session + Announcement Protocol [4], Session Initiation Protocol [11], Real- + Time Streaming Protocol [12], electronic mail using the MIME + extensions, and the Hypertext Transport Protocol. + + SDP is intended to be general purpose so that it can be used for a + wider range of network environments and applications than just + multicast session directories. However, it is not intended to + support negotiation of session content or media encodings - this is + viewed as outside the scope of session description. + +3. Glossary of Terms + + The following terms are used in this document, and have specific + meaning within the context of this document. + + Conference + A multimedia conference is a set of two or more communicating users + along with the software they are using to communicate. + + Session + A multimedia session is a set of multimedia senders and receivers + and the data streams flowing from senders to receivers. A + multimedia conference is an example of a multimedia session. + + Session Advertisement + See session announcement. + + Session Announcement + A session announcement is a mechanism by which a session + description is conveyed to users in a proactive fashion, i.e., the + session description was not explicitly requested by the user. + + + + +Handley & Jacobson Standards Track [Page 2] + +RFC 2327 SDP April 1998 + + + Session Description + A well defined format for conveying sufficient information to + discover and participate in a multimedia session. + +3.1. Terminology + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119. + +4. SDP Usage + +4.1. Multicast Announcements + + SDP is a session description protocol for multimedia sessions. A + common mode of usage is for a client to announce a conference session + by periodically multicasting an announcement packet to a well known + multicast address and port using the Session Announcement Protocol + (SAP). + + SAP packets are UDP packets with the following format: + + |--------------------| + | SAP header | + |--------------------| + | text payload | + |////////// + + + The header is the Session Announcement Protocol header. SAP is + described in more detail in a companion memo [4] + + The text payload is an SDP session description, as described in this + memo. The text payload should be no greater than 1 Kbyte in length. + If announced by SAP, only one session announcement is permitted in a + single packet. + +4.2. Email and WWW Announcements + + Alternative means of conveying session descriptions include + electronic mail and the World Wide Web. For both email and WWW + distribution, the use of the MIME content type "application/sdp" + should be used. This enables the automatic launching of applications + for participation in the session from the WWW client or mail reader + in a standard manner. + + + + + + +Handley & Jacobson Standards Track [Page 3] + +RFC 2327 SDP April 1998 + + + Note that announcements of multicast sessions made only via email or + the World Wide Web (WWW) do not have the property that the receiver + of a session announcement can necessarily receive the session because + the multicast sessions may be restricted in scope, and access to the + WWW server or reception of email is possible outside this scope. SAP + announcements do not suffer from this mismatch. + +5. Requirements and Recommendations + + The purpose of SDP is to convey information about media streams in + multimedia sessions to allow the recipients of a session description + to participate in the session. SDP is primarily intended for use in + an internetwork, although it is sufficiently general that it can + describe conferences in other network environments. + + A multimedia session, for these purposes, is defined as a set of + media streams that exist for some duration of time. Media streams + can be many-to-many. The times during which the session is active + need not be continuous. + + Thus far, multicast based sessions on the Internet have differed from + many other forms of conferencing in that anyone receiving the traffic + can join the session (unless the session traffic is encrypted). In + such an environment, SDP serves two primary purposes. It is a means + to communicate the existence of a session, and is a means to convey + sufficient information to enable joining and participating in the + session. In a unicast environment, only the latter purpose is likely + to be relevant. + + Thus SDP includes: + + o Session name and purpose + + o Time(s) the session is active + + o The media comprising the session + + o Information to receive those media (addresses, ports, formats and + so on) + + As resources necessary to participate in a session may be limited, + some additional information may also be desirable: + + o Information about the bandwidth to be used by the conference + + o Contact information for the person responsible for the session + + + + + +Handley & Jacobson Standards Track [Page 4] + +RFC 2327 SDP April 1998 + + + In general, SDP must convey sufficient information to be able to join + a session (with the possible exception of encryption keys) and to + announce the resources to be used to non-participants that may need + to know. + +5.1. Media Information + + SDP includes: + + o The type of media (video, audio, etc) + + o The transport protocol (RTP/UDP/IP, H.320, etc) + + o The format of the media (H.261 video, MPEG video, etc) + + For an IP multicast session, the following are also conveyed: + + o Multicast address for media + + o Transport Port for media + + This address and port are the destination address and destination + port of the multicast stream, whether being sent, received, or both. + + For an IP unicast session, the following are conveyed: + + o Remote address for media + + o Transport port for contact address + + The semantics of this address and port depend on the media and + transport protocol defined. By default, this is the remote address + and remote port to which data is sent, and the remote address and + local port on which to receive data. However, some media may define + to use these to establish a control channel for the actual media + flow. + +5.2. Timing Information + + Sessions may either be bounded or unbounded in time. Whether or not + they are bounded, they may be only active at specific times. + + SDP can convey: + + o An arbitrary list of start and stop times bounding the session + + o For each bound, repeat times such as "every Wednesday at 10am for + one hour" + + + +Handley & Jacobson Standards Track [Page 5] + +RFC 2327 SDP April 1998 + + + This timing information is globally consistent, irrespective of local + time zone or daylight saving time. + +5.3. Private Sessions + + It is possible to create both public sessions and private sessions. + Private sessions will typically be conveyed by encrypting the session + description to distribute it. The details of how encryption is + performed are dependent on the mechanism used to convey SDP - see [4] + for how this is done for session announcements. + + If a session announcement is private it is possible to use that + private announcement to convey encryption keys necessary to decode + each of the media in a conference, including enough information to + know which encryption scheme is used for each media. + +5.4. Obtaining Further Information about a Session + + A session description should convey enough information to decide + whether or not to participate in a session. SDP may include + additional pointers in the form of Universal Resources Identifiers + (URIs) for more information about the session. + +5.5. Categorisation + + When many session descriptions are being distributed by SAP or any + other advertisement mechanism, it may be desirable to filter + announcements that are of interest from those that are not. SDP + supports a categorisation mechanism for sessions that is capable of + being automated. + +5.6. Internationalization + + The SDP specification recommends the use of the ISO 10646 character + sets in the UTF-8 encoding (RFC 2044) to allow many different + languages to be represented. However, to assist in compact + representations, SDP also allows other character sets such as ISO + 8859-1 to be used when desired. Internationalization only applies to + free-text fields (session name and background information), and not + to SDP as a whole. + +6. SDP Specification + + SDP session descriptions are entirely textual using the ISO 10646 + character set in UTF-8 encoding. SDP field names and attributes names + use only the US-ASCII subset of UTF-8, but textual fields and + attribute values may use the full ISO 10646 character set. The + textual form, as opposed to a binary encoding such as ASN/1 or XDR, + + + +Handley & Jacobson Standards Track [Page 6] + +RFC 2327 SDP April 1998 + + + was chosen to enhance portability, to enable a variety of transports + to be used (e.g, session description in a MIME email message) and to + allow flexible, text-based toolkits (e.g., Tcl/Tk ) to be used to + generate and to process session descriptions. However, since the + total bandwidth allocated to all SAP announcements is strictly + limited, the encoding is deliberately compact. Also, since + announcements may be transported via very unreliable means (e.g., + email) or damaged by an intermediate caching server, the encoding was + designed with strict order and formatting rules so that most errors + would result in malformed announcements which could be detected + easily and discarded. This also allows rapid discarding of encrypted + announcements for which a receiver does not have the correct key. + + An SDP session description consists of a number of lines of text of + the form = is always exactly one character and is + case-significant. is a structured text string whose format + depends on . It also will be case-significant unless a + specific field defines otherwise. Whitespace is not permitted either + side of the `=' sign. In general is either a number of fields + delimited by a single space character or a free format string. + + A session description consists of a session-level description + (details that apply to the whole session and all media streams) and + optionally several media-level descriptions (details that apply onto + to a single media stream). + + An announcement consists of a session-level section followed by zero + or more media-level sections. The session-level part starts with a + `v=' line and continues to the first media-level section. The media + description starts with an `m=' line and continues to the next media + description or end of the whole session description. In general, + session-level values are the default for all media unless overridden + by an equivalent media-level value. + + When SDP is conveyed by SAP, only one session description is allowed + per packet. When SDP is conveyed by other means, many SDP session + descriptions may be concatenated together (the `v=' line indicating + the start of a session description terminates the previous + description). Some lines in each description are required and some + are optional but all must appear in exactly the order given here (the + fixed order greatly enhances error detection and allows for a simple + parser). Optional items are marked with a `*'. + +Session description + v= (protocol version) + o= (owner/creator and session identifier). + s= (session name) + i=* (session information) + + + +Handley & Jacobson Standards Track [Page 7] + +RFC 2327 SDP April 1998 + + + u=* (URI of description) + e=* (email address) + p=* (phone number) + c=* (connection information - not required if included in all media) + b=* (bandwidth information) + One or more time descriptions (see below) + z=* (time zone adjustments) + k=* (encryption key) + a=* (zero or more session attribute lines) + Zero or more media descriptions (see below) + +Time description + t= (time the session is active) + r=* (zero or more repeat times) + +Media description + m= (media name and transport address) + i=* (media title) + c=* (connection information - optional if included at session-level) + b=* (bandwidth information) + k=* (encryption key) + a=* (zero or more media attribute lines) + + The set of `type' letters is deliberately small and not intended to + be extensible -- SDP parsers must completely ignore any announcement + that contains a `type' letter that it does not understand. The + `attribute' mechanism ("a=" described below) is the primary means for + extending SDP and tailoring it to particular applications or media. + Some attributes (the ones listed in this document) have a defined + meaning but others may be added on an application-, media- or + session-specific basis. A session directory must ignore any + attribute it doesn't understand. + + The connection (`c=') and attribute (`a=') information in the + session-level section applies to all the media of that session unless + overridden by connection information or an attribute of the same name + in the media description. For instance, in the example below, each + media behaves as if it were given a `recvonly' attribute. + + An example SDP description is: + + v=0 + o=mhandley 2890844526 2890842807 IN IP4 126.16.64.4 + s=SDP Seminar + i=A Seminar on the session description protocol + u=http://www.cs.ucl.ac.uk/staff/M.Handley/sdp.03.ps + e=mjh@isi.edu (Mark Handley) + c=IN IP4 224.2.17.12/127 + + + +Handley & Jacobson Standards Track [Page 8] + +RFC 2327 SDP April 1998 + + + t=2873397496 2873404696 + a=recvonly + m=audio 49170 RTP/AVP 0 + m=video 51372 RTP/AVP 31 + m=application 32416 udp wb + a=orient:portrait + + Text records such as the session name and information are bytes + strings which may contain any byte with the exceptions of 0x00 (Nul), + 0x0a (ASCII newline) and 0x0d (ASCII carriage return). The sequence + CRLF (0x0d0a) is used to end a record, although parsers should be + tolerant and also accept records terminated with a single newline + character. By default these byte strings contain ISO-10646 + characters in UTF-8 encoding, but this default may be changed using + the `charset' attribute. + + Protocol Version + + v=0 + + The "v=" field gives the version of the Session Description Protocol. + There is no minor version number. + + Origin + + o=
    +
    + + The "o=" field gives the originator of the session (their username + and the address of the user's host) plus a session id and session + version number. + + is the user's login on the originating host, or it is "-" + if the originating host does not support the concept of user ids. + must not contain spaces. is a numeric string + such that the tuple of , , , +
    and
    form a globally unique identifier for + the session. + + The method of allocation is up to the creating tool, but + it has been suggested that a Network Time Protocol (NTP) timestamp be + used to ensure uniqueness [1]. + + is a version number for this announcement. It is needed + for proxy announcements to detect which of several announcements for + the same session is the most recent. Again its usage is up to the + + + + + +Handley & Jacobson Standards Track [Page 9] + +RFC 2327 SDP April 1998 + + + creating tool, so long as is increased when a modification + is made to the session data. Again, it is recommended (but not + mandatory) that an NTP timestamp is used. + + is a text string giving the type of network. + Initially "IN" is defined to have the meaning "Internet".
    is a text string giving the type of the address that follows. + Initially "IP4" and "IP6" are defined.
    is the globally + unique address of the machine from which the session was created. + For an address type of IP4, this is either the fully-qualified domain + name of the machine, or the dotted-decimal representation of the IP + version 4 address of the machine. For an address type of IP6, this + is either the fully-qualified domain name of the machine, or the + compressed textual representation of the IP version 6 address of the + machine. For both IP4 and IP6, the fully-qualified domain name is + the form that SHOULD be given unless this is unavailable, in which + case the globally unique address may be substituted. A local IP + address MUST NOT be used in any context where the SDP description + might leave the scope in which the address is meaningful. + + In general, the "o=" field serves as a globally unique identifier for + this version of this session description, and the subfields excepting + the version taken together identify the session irrespective of any + modifications. + + Session Name + + s= + + The "s=" field is the session name. There must be one and only one + "s=" field per session description, and it must contain ISO 10646 + characters (but see also the `charset' attribute below). + + Session and Media Information + + i= + + The "i=" field is information about the session. There may be at + most one session-level "i=" field per session description, and at + most one "i=" field per media. Although it may be omitted, this is + discouraged for session announcements, and user interfaces for + composing sessions should require text to be entered. If it is + present it must contain ISO 10646 characters (but see also the + `charset' attribute below). + + A single "i=" field can also be used for each media definition. In + media definitions, "i=" fields are primarily intended for labeling + media streams. As such, they are most likely to be useful when a + + + +Handley & Jacobson Standards Track [Page 10] + +RFC 2327 SDP April 1998 + + + single session has more than one distinct media stream of the same + media type. An example would be two different whiteboards, one for + slides and one for feedback and questions. + + URI + + u= + + o A URI is a Universal Resource Identifier as used by WWW clients + + o The URI should be a pointer to additional information about the + conference + + o This field is optional, but if it is present it should be specified + before the first media field + + o No more than one URI field is allowed per session description + + + Email Address and Phone Number + + e= + p= + + o These specify contact information for the person responsible for + the conference. This is not necessarily the same person that + created the conference announcement. + + o Either an email field or a phone field must be specified. + Additional email and phone fields are allowed. + + o If these are present, they should be specified before the first + media field. + + o More than one email or phone field can be given for a session + description. + + o Phone numbers should be given in the conventional international + + format - preceded by a "+ and the international country code. + There must be a space or a hyphen ("-") between the country code + and the rest of the phone number. Spaces and hyphens may be used + to split up a phone field to aid readability if desired. For + example: + + p=+44-171-380-7777 or p=+1 617 253 6011 + + + + + +Handley & Jacobson Standards Track [Page 11] + +RFC 2327 SDP April 1998 + + + o Both email addresses and phone numbers can have an optional free + text string associated with them, normally giving the name of the + person who may be contacted. This should be enclosed in + parenthesis if it is present. For example: + + e=mjh@isi.edu (Mark Handley) + + The alternative RFC822 name quoting convention is also allowed for + both email addresses and phone numbers. For example, + + e=Mark Handley + + The free text string should be in the ISO-10646 character set with + UTF-8 encoding, or alternatively in ISO-8859-1 or other encodings + if the appropriate charset session-level attribute is set. + + Connection Data + + c=
    + + The "c=" field contains connection data. + + A session announcement must contain one "c=" field in each media + description (see below) or a "c=" field at the session-level. It may + contain a session-level "c=" field and one additional "c=" field per + media description, in which case the per-media values override the + session-level settings for the relevant media. + + The first sub-field is the network type, which is a text string + giving the type of network. Initially "IN" is defined to have the + meaning "Internet". + + The second sub-field is the address type. This allows SDP to be used + for sessions that are not IP based. Currently only IP4 is defined. + + The third sub-field is the connection address. Optional extra + subfields may be added after the connection address depending on the + value of the
    field. + + For IP4 addresses, the connection address is defined as follows: + + o Typically the connection address will be a class-D IP multicast + + group address. If the session is not multicast, then the + connection address contains the fully-qualified domain name or the + unicast IP address of the expected data source or data relay or + data sink as determined by additional attribute fields. It is not + expected that fully-qualified domain names or unicast addresses + + + +Handley & Jacobson Standards Track [Page 12] + +RFC 2327 SDP April 1998 + + + will be given in a session description that is communicated by a + multicast announcement, though this is not prohibited. If a + unicast data stream is to pass through a network address + translator, the use of a fully-qualified domain name rather than an + unicast IP address is RECOMMENDED. In other cases, the use of an + IP address to specify a particular interface on a multi-homed host + might be required. Thus this specification leaves the decision as + to which to use up to the individual application, but all + applications MUST be able to cope with receiving both formats. + + o Conferences using an IP multicast connection address must also have + a time to live (TTL) value present in addition to the multicast + address. The TTL and the address together define the scope with + which multicast packets sent in this conference will be sent. TTL + values must be in the range 0-255. + + The TTL for the session is appended to the address using a slash as + a separator. An example is: + + c=IN IP4 224.2.1.1/127 + + Hierarchical or layered encoding schemes are data streams where the + encoding from a single media source is split into a number of + layers. The receiver can choose the desired quality (and hence + bandwidth) by only subscribing to a subset of these layers. Such + layered encodings are normally transmitted in multiple multicast + groups to allow multicast pruning. This technique keeps unwanted + traffic from sites only requiring certain levels of the hierarchy. + For applications requiring multiple multicast groups, we allow the + following notation to be used for the connection address: + + // + + If the number of addresses is not given it is assumed to be one. + Multicast addresses so assigned are contiguously allocated above + the base address, so that, for example: + + c=IN IP4 224.2.1.1/127/3 + + would state that addresses 224.2.1.1, 224.2.1.2 and 224.2.1.3 are + to be used at a ttl of 127. This is semantically identical to + including multiple "c=" lines in a media description: + + c=IN IP4 224.2.1.1/127 + c=IN IP4 224.2.1.2/127 + c=IN IP4 224.2.1.3/127 + + + + + +Handley & Jacobson Standards Track [Page 13] + +RFC 2327 SDP April 1998 + + + Multiple addresses or "c=" lines can only be specified on a per- + media basis, and not for a session-level "c=" field. + + It is illegal for the slash notation described above to be used for + IP unicast addresses. + + Bandwidth + + b=: + + o This specifies the proposed bandwidth to be used by the session or + media, and is optional. + + o is in kilobits per second + + o is a single alphanumeric word giving the meaning of the + bandwidth figure. + + o Two modifiers are initially defined: + + CT Conference Total: An implicit maximum bandwidth is associated with + each TTL on the Mbone or within a particular multicast + administrative scope region (the Mbone bandwidth vs. TTL limits are + given in the MBone FAQ). If the bandwidth of a session or media in + a session is different from the bandwidth implicit from the scope, + a `b=CT:...' line should be supplied for the session giving the + proposed upper limit to the bandwidth used. The primary purpose of + this is to give an approximate idea as to whether two or more + conferences can co-exist simultaneously. + + AS Application-Specific Maximum: The bandwidth is interpreted to be + application-specific, i.e., will be the application's concept of + maximum bandwidth. Normally this will coincide with what is set on + the application's "maximum bandwidth" control if applicable. + + Note that CT gives a total bandwidth figure for all the media at + all sites. AS gives a bandwidth figure for a single media at a + single site, although there may be many sites sending + simultaneously. + + o Extension Mechanism: Tool writers can define experimental bandwidth + modifiers by prefixing their modifier with "X-". For example: + + b=X-YZ:128 + + SDP parsers should ignore bandwidth fields with unknown modifiers. + Modifiers should be alpha-numeric and, although no length limit is + given, they are recommended to be short. + + + +Handley & Jacobson Standards Track [Page 14] + +RFC 2327 SDP April 1998 + + + Times, Repeat Times and Time Zones + + t= + + o "t=" fields specify the start and stop times for a conference + session. Multiple "t=" fields may be used if a session is active + at multiple irregularly spaced times; each additional "t=" field + specifies an additional period of time for which the session will + be active. If the session is active at regular times, an "r=" + field (see below) should be used in addition to and following a + "t=" field - in which case the "t=" field specifies the start and + stop times of the repeat sequence. + + o The first and second sub-fields give the start and stop times for + the conference respectively. These values are the decimal + representation of Network Time Protocol (NTP) time values in + seconds [1]. To convert these values to UNIX time, subtract + decimal 2208988800. + + o If the stop-time is set to zero, then the session is not bounded, + though it will not become active until after the start-time. If + the start-time is also zero, the session is regarded as permanent. + + User interfaces should strongly discourage the creation of + unbounded and permanent sessions as they give no information about + when the session is actually going to terminate, and so make + scheduling difficult. + + The general assumption may be made, when displaying unbounded + sessions that have not timed out to the user, that an unbounded + session will only be active until half an hour from the current + time or the session start time, whichever is the later. If + behaviour other than this is required, an end-time should be given + and modified as appropriate when new information becomes available + about when the session should really end. + + Permanent sessions may be shown to the user as never being active + unless there are associated repeat times which state precisely when + the session will be active. In general, permanent sessions should + not be created for any session expected to have a duration of less + than 2 months, and should be discouraged for sessions expected to + have a duration of less than 6 months. + + r= + + o "r=" fields specify repeat times for a session. For example, if + a session is active at 10am on Monday and 11am on Tuesday for one + + + +Handley & Jacobson Standards Track [Page 15] + +RFC 2327 SDP April 1998 + + + hour each week for three months, then the in the + corresponding "t=" field would be the NTP representation of 10am on + the first Monday, the would be 1 week, the + would be 1 hour, and the offsets would be zero + and 25 hours. The corresponding "t=" field stop time would be the + NTP representation of the end of the last session three months + later. By default all fields are in seconds, so the "r=" and "t=" + fields might be: + + t=3034423619 3042462419 + r=604800 3600 0 90000 + + To make announcements more compact, times may also be given in units + of days, hours or minutes. The syntax for these is a number + immediately followed by a single case-sensitive character. + Fractional units are not allowed - a smaller unit should be used + instead. The following unit specification characters are allowed: + + d - days (86400 seconds) + h - minutes (3600 seconds) + m - minutes (60 seconds) + s - seconds (allowed for completeness but not recommended) + + Thus, the above announcement could also have been written: + + r=7d 1h 0 25h + + Monthly and yearly repeats cannot currently be directly specified + with a single SDP repeat time - instead separate "t" fields should + be used to explicitly list the session times. + + z= .... + + o To schedule a repeated session which spans a change from daylight- + saving time to standard time or vice-versa, it is necessary to + specify offsets from the base repeat times. This is required + because different time zones change time at different times of day, + different countries change to or from daylight time on different + dates, and some countries do not have daylight saving time at all. + + Thus in order to schedule a session that is at the same time winter + and summer, it must be possible to specify unambiguously by whose + time zone a session is scheduled. To simplify this task for + receivers, we allow the sender to specify the NTP time that a time + zone adjustment happens and the offset from the time when the + session was first scheduled. The "z" field allows the sender to + specify a list of these adjustment times and offsets from the base + time. + + + +Handley & Jacobson Standards Track [Page 16] + +RFC 2327 SDP April 1998 + + + An example might be: + + z=2882844526 -1h 2898848070 0 + + This specifies that at time 2882844526 the time base by which the + session's repeat times are calculated is shifted back by 1 hour, + and that at time 2898848070 the session's original time base is + restored. Adjustments are always relative to the specified start + time - they are not cumulative. + + o If a session is likely to last several years, it is expected + that + the session announcement will be modified periodically rather than + transmit several years worth of adjustments in one announcement. + + Encryption Keys + + k= + k=: + + o The session description protocol may be used to convey encryption + keys. A key field is permitted before the first media entry (in + which case it applies to all media in the session), or for each + media entry as required. + + o The format of keys and their usage is outside the scope of this + document, but see [3]. + + o The method indicates the mechanism to be used to obtain a usable + key by external means, or from the encoded encryption key given. + + The following methods are defined: + + k=clear: + The encryption key (as described in [3] for RTP media streams + under the AV profile) is included untransformed in this key + field. + + k=base64: + The encryption key (as described in [3] for RTP media streams + under the AV profile) is included in this key field but has been + base64 encoded because it includes characters that are + prohibited in SDP. + + k=uri: + A Universal Resource Identifier as used by WWW clients is + included in this key field. The URI refers to the data + containing the key, and may require additional authentication + + + +Handley & Jacobson Standards Track [Page 17] + +RFC 2327 SDP April 1998 + + + before the key can be returned. When a request is made to the + given URI, the MIME content-type of the reply specifies the + encoding for the key in the reply. The key should not be + obtained until the user wishes to join the session to reduce + synchronisation of requests to the WWW server(s). + + k=prompt + No key is included in this SDP description, but the session or + media stream referred to by this key field is encrypted. The + user should be prompted for the key when attempting to join the + session, and this user-supplied key should then be used to + decrypt the media streams. + + Attributes + + a= + a=: + + Attributes are the primary means for extending SDP. Attributes may + be defined to be used as "session-level" attributes, "media-level" + attributes, or both. + + A media description may have any number of attributes ("a=" fields) + which are media specific. These are referred to as "media-level" + attributes and add information about the media stream. Attribute + fields can also be added before the first media field; these + "session-level" attributes convey additional information that applies + to the conference as a whole rather than to individual media; an + example might be the conference's floor control policy. + + Attribute fields may be of two forms: + + o property attributes. A property attribute is simply of the form + "a=". These are binary attributes, and the presence of the + attribute conveys that the attribute is a property of the session. + An example might be "a=recvonly". + + o value attributes. A value attribute is of the form + "a=:". An example might be that a whiteboard + could have the value attribute "a=orient:landscape" + + Attribute interpretation depends on the media tool being invoked. + Thus receivers of session descriptions should be configurable in + their interpretation of announcements in general and of attributes in + particular. + + Attribute names must be in the US-ASCII subset of ISO-10646/UTF-8. + + + + +Handley & Jacobson Standards Track [Page 18] + +RFC 2327 SDP April 1998 + + + Attribute values are byte strings, and MAY use any byte value except + 0x00 (Nul), 0x0A (LF), and 0x0D (CR). By default, attribute values + are to be interpreted as in ISO-10646 character set with UTF-8 + encoding. Unlike other text fields, attribute values are NOT + normally affected by the `charset' attribute as this would make + comparisons against known values problematic. However, when an + attribute is defined, it can be defined to be charset-dependent, in + which case it's value should be interpreted in the session charset + rather than in ISO-10646. + + Attributes that will be commonly used can be registered with IANA + (see Appendix B). Unregistered attributes should begin with "X-" to + prevent inadvertent collision with registered attributes. In either + case, if an attribute is received that is not understood, it should + simply be ignored by the receiver. + + Media Announcements + + m= + + A session description may contain a number of media descriptions. + Each media description starts with an "m=" field, and is terminated + by either the next "m=" field or by the end of the session + description. A media field also has several sub-fields: + + o The first sub-field is the media type. Currently defined media are + "audio", "video", "application", "data" and "control", though this + list may be extended as new communication modalities emerge (e.g., + telepresense). The difference between "application" and "data" is + that the former is a media flow such as whiteboard information, and + the latter is bulk-data transfer such as multicasting of program + executables which will not typically be displayed to the user. + "control" is used to specify an additional conference control + channel for the session. + + o The second sub-field is the transport port to which the media + stream will be sent. The meaning of the transport port depends on + the network being used as specified in the relevant "c" field and + on the transport protocol defined in the third sub-field. Other + ports used by the media application (such as the RTCP port, see + [2]) should be derived algorithmically from the base media port. + + Note: For transports based on UDP, the value should be in the range + 1024 to 65535 inclusive. For RTP compliance it should be an even + number. + + + + + + +Handley & Jacobson Standards Track [Page 19] + +RFC 2327 SDP April 1998 + + + For applications where hierarchically encoded streams are being + sent to a unicast address, it may be necessary to specify multiple + transport ports. This is done using a similar notation to that + used for IP multicast addresses in the "c=" field: + + m= / + + In such a case, the ports used depend on the transport protocol. + For RTP, only the even ports are used for data and the + corresponding one-higher odd port is used for RTCP. For example: + + m=video 49170/2 RTP/AVP 31 + + would specify that ports 49170 and 49171 form one RTP/RTCP pair and + 49172 and 49173 form the second RTP/RTCP pair. RTP/AVP is the + transport protocol and 31 is the format (see below). + + It is illegal for both multiple addresses to be specified in the + "c=" field and for multiple ports to be specified in the "m=" field + in the same session description. + + o The third sub-field is the transport protocol. The transport + protocol values are dependent on the address-type field in the "c=" + fields. Thus a "c=" field of IP4 defines that the transport + protocol runs over IP4. For IP4, it is normally expected that most + media traffic will be carried as RTP over UDP. The following + transport protocols are preliminarily defined, but may be extended + through registration of new protocols with IANA: + + - RTP/AVP - the IETF's Realtime Transport Protocol using the + Audio/Video profile carried over UDP. + + - udp - User Datagram Protocol + + If an application uses a single combined proprietary media format + and transport protocol over UDP, then simply specifying the + transport protocol as udp and using the format field to distinguish + the combined protocol is recommended. If a transport protocol is + used over UDP to carry several distinct media types that need to be + distinguished by a session directory, then specifying the transport + protocol and media format separately is necessary. RTP is an + example of a transport-protocol that carries multiple payload + formats that must be distinguished by the session directory for it + to know how to start appropriate tools, relays, mixers or + recorders. + + + + + + +Handley & Jacobson Standards Track [Page 20] + +RFC 2327 SDP April 1998 + + + The main reason to specify the transport-protocol in addition to + the media format is that the same standard media formats may be + carried over different transport protocols even when the network + protocol is the same - a historical example is vat PCM audio and + RTP PCM audio. In addition, relays and monitoring tools that are + transport-protocol-specific but format-independent are possible. + + For RTP media streams operating under the RTP Audio/Video Profile + [3], the protocol field is "RTP/AVP". Should other RTP profiles be + defined in the future, their profiles will be specified in the same + way. For example, the protocol field "RTP/XYZ" would specify RTP + operating under a profile whose short name is "XYZ". + + o The fourth and subsequent sub-fields are media formats. For audio + and video, these will normally be a media payload type as defined + in the RTP Audio/Video Profile. + + When a list of payload formats is given, this implies that all of + these formats may be used in the session, but the first of these + formats is the default format for the session. + + For media whose transport protocol is not RTP or UDP the format + field is protocol specific. Such formats should be defined in an + additional specification document. + + For media whose transport protocol is RTP, SDP can be used to + provide a dynamic binding of media encoding to RTP payload type. + The encoding names in the RTP AV Profile do not specify unique + audio encodings (in terms of clock rate and number of audio + channels), and so they are not used directly in SDP format fields. + Instead, the payload type number should be used to specify the + format for static payload types and the payload type number along + with additional encoding information should be used for dynamically + allocated payload types. + + An example of a static payload type is u-law PCM coded single + channel audio sampled at 8KHz. This is completely defined in the + RTP Audio/Video profile as payload type 0, so the media field for + such a stream sent to UDP port 49232 is: + + m=video 49232 RTP/AVP 0 + + An example of a dynamic payload type is 16 bit linear encoded + stereo audio sampled at 16KHz. If we wish to use dynamic RTP/AVP + payload type 98 for such a stream, additional information is + required to decode it: + + m=video 49232 RTP/AVP 98 + + + +Handley & Jacobson Standards Track [Page 21] + +RFC 2327 SDP April 1998 + + + a=rtpmap:98 L16/16000/2 + + The general form of an rtpmap attribute is: + + a=rtpmap: /[/] + + For audio streams, may specify the number of + audio channels. This parameter may be omitted if the number of + channels is one provided no additional parameters are needed. For + video streams, no encoding parameters are currently specified. + + Additional parameters may be defined in the future, but + codecspecific parameters should not be added. Parameters added to + an rtpmap attribute should only be those required for a session + directory to make the choice of appropriate media too to + participate in a session. Codec-specific parameters should be + added in other attributes. + + Up to one rtpmap attribute can be defined for each media format + specified. Thus we might have: + + m=audio 49230 RTP/AVP 96 97 98 + a=rtpmap:96 L8/8000 + a=rtpmap:97 L16/8000 + a=rtpmap:98 L16/11025/2 + + RTP profiles that specify the use of dynamic payload types must + define the set of valid encoding names and/or a means to register + encoding names if that profile is to be used with SDP. + + Experimental encoding formats can also be specified using rtpmap. + RTP formats that are not registered as standard format names must + be preceded by "X-". Thus a new experimental redundant audio + stream called GSMLPC using dynamic payload type 99 could be + specified as: + + m=video 49232 RTP/AVP 99 + a=rtpmap:99 X-GSMLPC/8000 + + Such an experimental encoding requires that any site wishing to + receive the media stream has relevant configured state in its + session directory to know which tools are appropriate. + + Note that RTP audio formats typically do not include information + about the number of samples per packet. If a non-default (as + defined in the RTP Audio/Video Profile) packetisation is required, + the "ptime" attribute is used as given below. + + + +Handley & Jacobson Standards Track [Page 22] + +RFC 2327 SDP April 1998 + + + For more details on RTP audio and video formats, see [3]. + + o Formats for non-RTP media should be registered as MIME content + types as described in Appendix B. For example, the LBL whiteboard + application might be registered as MIME content-type application/wb + with encoding considerations specifying that it operates over UDP, + with no appropriate file format. In SDP this would then be + expressed using a combination of the "media" field and the "fmt" + field, as follows: + + m=application 32416 udp wb + + Suggested Attributes + + The following attributes are suggested. Since application writers + may add new attributes as they are required, this list is not + exhaustive. + + a=cat: + This attribute gives the dot-separated hierarchical category of + the session. This is to enable a receiver to filter unwanted + sessions by category. It would probably have been a compulsory + separate field, except for its experimental nature at this time. + It is a session-level attribute, and is not dependent on charset. + + a=keywds: + Like the cat attribute, this is to assist identifying wanted + sessions at the receiver. This allows a receiver to select + interesting session based on keywords describing the purpose of + the session. It is a session-level attribute. It is a charset + dependent attribute, meaning that its value should be interpreted + in the charset specified for the session description if one is + specified, or by default in ISO 10646/UTF-8. + + a=tool: + This gives the name and version number of the tool used to create + the session description. It is a session-level attribute, and is + not dependent on charset. + + a=ptime: + This gives the length of time in milliseconds represented by the + media in a packet. This is probably only meaningful for audio + data. It should not be necessary to know ptime to decode RTP or + vat audio, and it is intended as a recommendation for the + encoding/packetisation of audio. It is a media attribute, and is + not dependent on charset. + + + + + +Handley & Jacobson Standards Track [Page 23] + +RFC 2327 SDP April 1998 + + + a=recvonly + This specifies that the tools should be started in receive-only + mode where applicable. It can be either a session or media + attribute, and is not dependent on charset. + + a=sendrecv + This specifies that the tools should be started in send and + receive mode. This is necessary for interactive conferences with + tools such as wb which defaults to receive only mode. It can be + either a session or media attribute, and is not dependent on + charset. + + a=sendonly + This specifies that the tools should be started in send-only + mode. An example may be where a different unicast address is to + be used for a traffic destination than for a traffic source. In + such a case, two media descriptions may be use, one sendonly and + one recvonly. It can be either a session or media attribute, but + would normally only be used as a media attribute, and is not + dependent on charset. + + a=orient: + Normally this is only used in a whiteboard media specification. + It specifies the orientation of a the whiteboard on the screen. + It is a media attribute. Permitted values are `portrait', + `landscape' and `seascape' (upside down landscape). It is not + dependent on charset + + a=type: + This specifies the type of the conference. Suggested values are + `broadcast', `meeting', `moderated', `test' and `H332'. + `recvonly' should be the default for `type:broadcast' sessions, + `type:meeting' should imply `sendrecv' and `type:moderated' + should indicate the use of a floor control tool and that the + media tools are started so as to "mute" new sites joining the + conference. + + Specifying the attribute type:H332 indicates that this loosely + coupled session is part of a H.332 session as defined in the ITU + H.332 specification [10]. Media tools should be started + `recvonly'. + + Specifying the attribute type:test is suggested as a hint that, + unless explicitly requested otherwise, receivers can safely avoid + displaying this session description to users. + + The type attribute is a session-level attribute, and is not + dependent on charset. + + + +Handley & Jacobson Standards Track [Page 24] + +RFC 2327 SDP April 1998 + + + a=charset: + This specifies the character set to be used to display the + session name and information data. By default, the ISO-10646 + character set in UTF-8 encoding is used. If a more compact + representation is required, other character sets may be used such + as ISO-8859-1 for Northern European languages. In particular, + the ISO 8859-1 is specified with the following SDP attribute: + + a=charset:ISO-8859-1 + + This is a session-level attribute; if this attribute is present, + it must be before the first media field. The charset specified + MUST be one of those registered with IANA, such as ISO-8859-1. + The character set identifier is a US-ASCII string and MUST be + compared against the IANA identifiers using a case-insensitive + comparison. If the identifier is not recognised or not + supported, all strings that are affected by it SHOULD be regarded + as byte strings. + + Note that a character set specified MUST still prohibit the use + of bytes 0x00 (Nul), 0x0A (LF) and 0x0d (CR). Character sets + requiring the use of these characters MUST define a quoting + mechanism that prevents these bytes appearing within text fields. + + a=sdplang: + This can be a session level attribute or a media level attribute. + As a session level attribute, it specifies the language for the + session description. As a media level attribute, it specifies + the language for any media-level SDP information field associated + with that media. Multiple sdplang attributes can be provided + either at session or media level if multiple languages in the + session description or media use multiple languages, in which + case the order of the attributes indicates the order of + importance of the various languages in the session or media from + most important to least important. + + In general, sending session descriptions consisting of multiple + languages should be discouraged. Instead, multiple descriptions + should be sent describing the session, one in each language. + However this is not possible with all transport mechanisms, and + so multiple sdplang attributes are allowed although not + recommended. + + The sdplang attribute value must be a single RFC 1766 language + tag in US-ASCII. It is not dependent on the charset attribute. + An sdplang attribute SHOULD be specified when a session is of + + + + + +Handley & Jacobson Standards Track [Page 25] + +RFC 2327 SDP April 1998 + + + sufficient scope to cross geographic boundaries where the + language of recipients cannot be assumed, or where the session is + in a different language from the locally assumed norm. + + a=lang: + This can be a session level attribute or a media level attribute. + As a session level attribute, it specifies the default language + for the session being described. As a media level attribute, it + specifies the language for that media, overriding any session- + level language specified. Multiple lang attributes can be + provided either at session or media level if multiple languages + if the session description or media use multiple languages, in + which case the order of the attributes indicates the order of + importance of the various languages in the session or media from + most important to least important. + + The lang attribute value must be a single RFC 1766 language tag + in US-ASCII. It is not dependent on the charset attribute. A + lang attribute SHOULD be specified when a session is of + sufficient scope to cross geographic boundaries where the + language of recipients cannot be assumed, or where the session is + in a different language from the locally assumed norm. + + a=framerate: + This gives the maximum video frame rate in frames/sec. It is + intended as a recommendation for the encoding of video data. + Decimal representations of fractional values using the notation + "." are allowed. It is a media attribute, is + only defined for video media, and is not dependent on charset. + + a=quality: + This gives a suggestion for the quality of the encoding as an + integer value. + + The intention of the quality attribute for video is to specify a + non-default trade-off between frame-rate and still-image quality. + For video, the value in the range 0 to 10, with the following + suggested meaning: + + 10 - the best still-image quality the compression scheme can + give. + + 5 - the default behaviour given no quality suggestion. + + 0 - the worst still-image quality the codec designer thinks is + still usable. + + It is a media attribute, and is not dependent on charset. + + + +Handley & Jacobson Standards Track [Page 26] + +RFC 2327 SDP April 1998 + + + a=fmtp: + This attribute allows parameters that are specific to a + particular format to be conveyed in a way that SDP doesn't have + to understand them. The format must be one of the formats + specified for the media. Format-specific parameters may be any + set of parameters required to be conveyed by SDP and given + unchanged to the media tool that will use this format. + + It is a media attribute, and is not dependent on charset. + +6.1. Communicating Conference Control Policy + + There is some debate over the way conference control policy should be + communicated. In general, the authors believe that an implicit + declarative style of specifying conference control is desirable where + possible. + + A simple declarative style uses a single conference attribute field + before the first media field, possibly supplemented by properties + such as `recvonly' for some of the media tools. This conference + attribute conveys the conference control policy. An example might be: + + a=type:moderated + + In some cases, however, it is possible that this may be insufficient + to communicate the details of an unusual conference control policy. + If this is the case, then a conference attribute specifying external + control might be set, and then one or more "media" fields might be + used to specify the conference control tools and configuration data + for those tools. An example is an ITU H.332 session: + + c=IN IP4 224.5.6.7 + a=type:H332 + m=audio 49230 RTP/AVP 0 + m=video 49232 RTP/AVP 31 + m=application 12349 udp wb + m=control 49234 H323 mc + c=IN IP4 134.134.157.81 + + In this example, a general conference attribute (type:H332) is + specified stating that conference control will be provided by an + external H.332 tool, and a contact addresses for the H.323 session + multipoint controller is given. + + In this document, only the declarative style of conference control + declaration is specified. Other forms of conference control should + specify an appropriate type attribute, and should define the + implications this has for control media. + + + +Handley & Jacobson Standards Track [Page 27] + +RFC 2327 SDP April 1998 + + +7. Security Considerations + + SDP is a session description format that describes multimedia + sessions. A session description should not be trusted unless it has + been obtained by an authenticated transport protocol from a trusted + source. Many different transport protocols may be used to distribute + session description, and the nature of the authentication will differ + from transport to transport. + + One transport that will frequently be used to distribute session + descriptions is the Session Announcement Protocol (SAP). SAP + provides both encryption and authentication mechanisms but due to the + nature of session announcements it is likely that there are many + occasions where the originator of a session announcement cannot be + authenticated because they are previously unknown to the receiver of + the announcement and because no common public key infrastructure is + available. + + On receiving a session description over an unauthenticated transport + mechanism or from an untrusted party, software parsing the session + should take a few precautions. Session description contain + information required to start software on the receivers system. + Software that parses a session description MUST not be able to start + other software except that which is specifically configured as + appropriate software to participate in multimedia sessions. It is + normally considered INAPPROPRIATE for software parsing a session + description to start, on a user's system, software that is + appropriate to participate in multimedia sessions, without the user + first being informed that such software will be started and giving + their consent. Thus a session description arriving by session + announcement, email, session invitation, or WWW page SHOULD not + deliver the user into an {it interactive} multimedia session without + the user being aware that this will happen. As it is not always + simple to tell whether a session is interactive or not, applications + that are unsure should assume sessions are interactive. + + In this specification, there are no attributes which would allow the + recipient of a session description to be informed to start multimedia + tools in a mode where they default to transmitting. Under some + circumstances it might be appropriate to define such attributes. If + this is done an application parsing a session description containing + such attributes SHOULD either ignore them, or inform the user that + joining this session will result in the automatic transmission of + multimedia data. The default behaviour for an unknown attribute is + to ignore it. + + + + + + +Handley & Jacobson Standards Track [Page 28] + +RFC 2327 SDP April 1998 + + + Session descriptions may be parsed at intermediate systems such as + firewalls for the purposes of opening a hole in the firewall to allow + the participation in multimedia sessions. It is considered + INAPPROPRIATE for a firewall to open such holes for unicast data + streams unless the session description comes in a request from inside + the firewall. + + For multicast sessions, it is likely that local administrators will + apply their own policies, but the exclusive use of "local" or "site- + local" administrative scope within the firewall and the refusal of + the firewall to open a hole for such scopes will provide separation + of global multicast sessions from local ones. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Handley & Jacobson Standards Track [Page 29] + +RFC 2327 SDP April 1998 + + +Appendix A: SDP Grammar + + This appendix provides an Augmented BNF grammar for SDP. ABNF is + defined in RFC 2234. + + + announcement = proto-version + origin-field + session-name-field + information-field + uri-field + email-fields + phone-fields + connection-field + bandwidth-fields + time-fields + key-field + attribute-fields + media-descriptions + + proto-version = "v=" 1*DIGIT CRLF + ;this memo describes version 0 + + origin-field = "o=" username space + sess-id space sess-version space + nettype space addrtype space + addr CRLF + + session-name-field = "s=" text CRLF + + information-field = ["i=" text CRLF] + + uri-field = ["u=" uri CRLF] + + email-fields = *("e=" email-address CRLF) + + phone-fields = *("p=" phone-number CRLF) + + + connection-field = ["c=" nettype space addrtype space + connection-address CRLF] + ;a connection field must be present + ;in every media description or at the + ;session-level + + + bandwidth-fields = *("b=" bwtype ":" bandwidth CRLF) + + + + +Handley & Jacobson Standards Track [Page 30] + +RFC 2327 SDP April 1998 + + + time-fields = 1*( "t=" start-time space stop-time + *(CRLF repeat-fields) CRLF) + [zone-adjustments CRLF] + + + repeat-fields = "r=" repeat-interval space typed-time + 1*(space typed-time) + + + zone-adjustments = time space ["-"] typed-time + *(space time space ["-"] typed-time) + + + key-field = ["k=" key-type CRLF] + + + key-type = "prompt" | + "clear:" key-data | + "base64:" key-data | + "uri:" uri + + + key-data = email-safe | "~" | " + + + attribute-fields = *("a=" attribute CRLF) + + + media-descriptions = *( media-field + information-field + *(connection-field) + bandwidth-fields + key-field + attribute-fields ) + + + media-field = "m=" media space port ["/" integer] + space proto 1*(space fmt) CRLF + + + media = 1*(alpha-numeric) + ;typically "audio", "video", "application" + ;or "data" + + fmt = 1*(alpha-numeric) + ;typically an RTP payload type for audio + ;and video media + + + + +Handley & Jacobson Standards Track [Page 31] + +RFC 2327 SDP April 1998 + + + proto = 1*(alpha-numeric) + ;typically "RTP/AVP" or "udp" for IP4 + + + port = 1*(DIGIT) + ;should in the range "1024" to "65535" inclusive + ;for UDP based media + + + attribute = (att-field ":" att-value) | att-field + + + att-field = 1*(alpha-numeric) + + + att-value = byte-string + + + sess-id = 1*(DIGIT) + ;should be unique for this originating username/host + + + sess-version = 1*(DIGIT) + ;0 is a new session + + + connection-address = multicast-address + | addr + + + multicast-address = 3*(decimal-uchar ".") decimal-uchar "/" ttl + [ "/" integer ] + ;multicast addresses may be in the range + ;224.0.0.0 to 239.255.255.255 + + ttl = decimal-uchar + + start-time = time | "0" + + stop-time = time | "0" + + time = POS-DIGIT 9*(DIGIT) + ;sufficient for 2 more centuries + + + repeat-interval = typed-time + + + + + +Handley & Jacobson Standards Track [Page 32] + +RFC 2327 SDP April 1998 + + + typed-time = 1*(DIGIT) [fixed-len-time-unit] + + + fixed-len-time-unit = "d" | "h" | "m" | "s" + + + bwtype = 1*(alpha-numeric) + + bandwidth = 1*(DIGIT) + + + username = safe + ;pretty wide definition, but doesn't include space + + + email-address = email | email "(" email-safe ")" | + email-safe "<" email ">" + + + email = ;defined in RFC822 + + + uri= ;defined in RFC1630 + + + phone-number = phone | phone "(" email-safe ")" | + email-safe "<" phone ">" + + + phone = "+" POS-DIGIT 1*(space | "-" | DIGIT) + ;there must be a space or hyphen between the + ;international code and the rest of the number. + + + nettype = "IN" + ;list to be extended + + + addrtype = "IP4" | "IP6" + ;list to be extended + + + addr = FQDN | unicast-address + + + FQDN = 4*(alpha-numeric|"-"|".") + ;fully qualified domain name as specified in RFC1035 + + + + +Handley & Jacobson Standards Track [Page 33] + +RFC 2327 SDP April 1998 + + + unicast-address = IP4-address | IP6-address + + + IP4-address = b1 "." decimal-uchar "." decimal-uchar "." b4 + b1 = decimal-uchar + ;less than "224"; not "0" or "127" + b4 = decimal-uchar + ;not "0" + + IP6-address = ;to be defined + + + text = byte-string + ;default is to interpret this as IS0-10646 UTF8 + ;ISO 8859-1 requires a "a=charset:ISO-8859-1" + ;session-level attribute to be used + + + byte-string = 1*(0x01..0x09|0x0b|0x0c|0x0e..0xff) + ;any byte except NUL, CR or LF + + + decimal-uchar = DIGIT + | POS-DIGIT DIGIT + | ("1" 2*(DIGIT)) + | ("2" ("0"|"1"|"2"|"3"|"4") DIGIT) + | ("2" "5" ("0"|"1"|"2"|"3"|"4"|"5")) + + + integer = POS-DIGIT *(DIGIT) + + + alpha-numeric = ALPHA | DIGIT + + + DIGIT = "0" | POS-DIGIT + + + POS-DIGIT = "1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9" + + + ALPHA = "a"|"b"|"c"|"d"|"e"|"f"|"g"|"h"|"i"|"j"|"k"| + "l"|"m"|"n"|"o "|"p"|"q"|"r"|"s"|"t"|"u"|"v"| + "w"|"x"|"y"|"z"|"A"|"B"|"C "|"D"|"E"|"F"|"G"| + "H"|"I"|"J"|"K"|"L"|"M"|"N"|"O"|"P"|" Q"|"R"| + "S"|"T"|"U"|"V"|"W"|"X"|"Y"|"Z" + + + + + +Handley & Jacobson Standards Track [Page 34] + +RFC 2327 SDP April 1998 + + + email-safe = safe | space | tab + + + safe = alpha-numeric | + "'" | "'" | "-" | "." | "/" | ":" | "?" | """ | + "#" | "$" | "&" | "*" | ";" | "=" | "@" | "[" | + "]" | "^" | "_" | "`" | "{" | "|" | "}" | "+" | + "~" | " + + + space = %d32 + tab = %d9 + CRLF = %d13.10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Handley & Jacobson Standards Track [Page 35] + +RFC 2327 SDP April 1998 + + +Appendix B: Guidelines for registering SDP names with IANA + + There are seven field names that may be registered with IANA. Using + the terminology in the SDP specification BNF, they are "media", + "proto", "fmt", "att-field", "bwtype", "nettype" and "addrtype". + + "media" (eg, audio, video, application, data). + + Packetized media types, such as those used by RTP, share the + namespace used by media types registry [RFC 2048] (i.e. "MIME + types"). The list of valid media names is the set of top-level + MIME content types. The set of media is intended to be small and + not to be extended except under rare circumstances. (The MIME + subtype corresponds to the "fmt" parameter below). + + "proto" + + In general this should be an IETF standards-track transport + protocol identifier such as RTP/AVP (rfc 1889 under the rfc 1890 + profile). + + However, people will want to invent their own proprietary + transport protocols. Some of these should be registered as a + "fmt" using "udp" as the protocol and some of which probably + can't be. + + Where the protocol and the application are intimately linked, + such as with the LBL whiteboard wb which used a proprietary and + special purpose protocol over UDP, the protocol name should be + "udp" and the format name that should be registered is "wb". The + rules for formats (see below) apply to such registrations. + + Where the proprietary transport protocol really carries many + different data formats, it is possible to register a new protocol + name with IANA. In such a case, an RFC MUST be produced + describing the protocol and referenced in the registration. Such + an RFC MAY be informational, although it is preferable if it is + standards-track. + + "fmt" + + The format namespace is dependent on the context of the "proto" + field, so a format cannot be registered without specifying one or + more transport protocols that it applies to. + + Formats cover all the possible encodings that might want to be + transported in a multimedia session. + + + + +Handley & Jacobson Standards Track [Page 36] + +RFC 2327 SDP April 1998 + + + For RTP formats that have been assigned static payload types, the + payload type number is used. For RTP formats using a dynamic + payload type number, the dynamic payload type number is given as + the format and an additional "rtpmap" attribute specifies the + format and parameters. + + For non-RTP formats, any unregistered format name may be + registered through the MIME-type registration process [RFC 2048]. + The type given here is the MIME subtype only (the top-level MIME + content type is specified by the media parameter). The MIME type + registration SHOULD reference a standards-track RFC which + describes the transport protocol for this media type. If there + is an existing MIME type for this format, the MIME registration + should be augmented to reference the transport specification for + this media type. If there is not an existing MIME type for this + format, and there exists no appropriate file format, this should + be noted in the encoding considerations as "no appropriate file + format". + + "att-field" (Attribute names) + + Attribute field names MAY be registered with IANA, although this + is not compulsory, and unknown attributes are simply ignored. + + When an attribute is registered, it must be accompanied by a + brief specification stating the following: + + o contact name, email address and telephone number + + o attribute-name (as it will appear in SDP) + + o long-form attribute name in English + + o type of attribute (session level, media level, or both) + + o whether the attribute value is subject to the charset + attribute. + + o a one paragraph explanation of the purpose of the attribute. + + o a specification of appropriate attribute values for this + attribute. + + IANA will not sanity check such attribute registrations except to + ensure that they do not clash with existing registrations. + + + + + + +Handley & Jacobson Standards Track [Page 37] + +RFC 2327 SDP April 1998 + + + Although the above is the minimum that IANA will accept, if the + attribute is expected to see widespread use and interoperability + is an issue, authors are encouraged to produce a standards-track + RFC that specifies the attribute more precisely. + + Submitters of registrations should ensure that the specification + is in the spirit of SDP attributes, most notably that the + attribute is platform independent in the sense that it makes no + implicit assumptions about operating systems and does not name + specific pieces of software in a manner that might inhibit + interoperability. + + "bwtype" (bandwidth specifiers) + + A proliferation of bandwidth specifiers is strongly discouraged. + + New bandwidth specifiers may be registered with IANA. The + submission MUST reference a standards-track RFC specifying the + semantics of the bandwidth specifier precisely, and indicating + when it should be used, and why the existing registered bandwidth + specifiers do not suffice. + + "nettype" (Network Type) + + New network types may be registered with IANA if SDP needs to be + used in the context of non-internet environments. Whilst these + are not normally the preserve of IANA, there may be circumstances + when an Internet application needs to interoperate with a non- + internet application, such as when gatewaying an internet + telephony call into the PSTN. The number of network types should + be small and should be rarely extended. A new network type + cannot be registered without registering at least one address + type to be used with that network type. A new network type + registration MUST reference an RFC which gives details of the + network type and address type and specifies how and when they + would be used. Such an RFC MAY be Informational. + + "addrtype" (Address Type) + + New address types may be registered with IANA. An address type + is only meaningful in the context of a network type, and any + registration of an address type MUST specify a registered network + type, or be submitted along with a network type registration. A + new address type registration MUST reference an RFC giving + details of the syntax of the address type. Such an RFC MAY be + Informational. Address types are not expected to be registered + frequently. + + + + +Handley & Jacobson Standards Track [Page 38] + +RFC 2327 SDP April 1998 + + + Registration Procedure + + To register a name the above guidelines should be followed regarding + the required level of documentation that is required. The + registration itself should be sent to IANA. Attribute registrations + should include the information given above. Other registrations + should include the following additional information: + + o contact name, email address and telephone number + + o name being registered (as it will appear in SDP) + + o long-form name in English + + o type of name ("media", "proto", "fmt", "bwtype", "nettype", or + "addrtype") + + o a one paragraph explanation of the purpose of the registered name. + + o a reference to the specification (eg RFC number) of the registered + name. + + IANA may refer any registration to the IESG or to any appropriate + IETF working group for review, and may request revisions to be made + before a registration will be made. + + + + + + + + + + + + + + + + + + + + + + + + + + +Handley & Jacobson Standards Track [Page 39] + +RFC 2327 SDP April 1998 + + +Appendix C: Authors' Addresses + + Mark Handley + Information Sciences Institute + c/o MIT Laboratory for Computer Science + 545 Technology Square + Cambridge, MA 02139 + United States + electronic mail: mjh@isi.edu + + Van Jacobson + MS 46a-1121 + Lawrence Berkeley Laboratory + Berkeley, CA 94720 + United States + electronic mail: van@ee.lbl.gov + +Acknowledgments + + Many people in the IETF MMUSIC working group have made comments and + suggestions contributing to this document. In particular, we would + like to thank Eve Schooler, Steve Casner, Bill Fenner, Allison + Mankin, Ross Finlayson, Peter Parnes, Joerg Ott, Carsten Bormann, Rob + Lanphier and Steve Hanna. + +References + + [1] Mills, D., "Network Time Protocol (version 3) specification and + implementation", RFC 1305, March 1992. + + [2] Schulzrinne, H., Casner, S., Frederick, R. and V. Jacobson, "RTP: + A Transport Protocol for Real-Time Applications", RFC 1889, January + 1996. + + [3] Schulzrinne, H., "RTP Profile for Audio and Video Conferences + with Minimal Control", RFC 1890, January 1996 + + [4] Handley, M., "SAP - Session Announcement Protocol", Work in + Progress. + + [5] V. Jacobson, S. McCanne, "vat - X11-based audio teleconferencing + tool" vat manual page, Lawrence Berkeley Laboratory, 1994. + + [6] The Unicode Consortium, "The Unicode Standard -- Version 2.0", + Addison-Wesley, 1996. + + + + + + +Handley & Jacobson Standards Track [Page 40] + +RFC 2327 SDP April 1998 + + + [7] ISO/IEC 10646-1:1993. International Standard -- Information + technol- ogy -- Universal Multiple-Octet Coded Character Set (UCS) -- + Part 1: Architecture and Basic Multilingual Plane. Five amendments + and a techn- ical corrigendum have been published up to now. UTF-8 + is described in Annex R, published as Amendment 2. + + [8] Goldsmith, D., and M. Davis, "Using Unicode with MIME", RFC 1641, + July 1994. + + [9] Yergeau, F., "UTF-8, a transformation format of Unicode and ISO + 10646", RFC 2044, October 1996. + + [10] ITU-T Recommendation H.332 (1998): "Multimedia Terminal for + Receiving Internet-based H.323 Conferences", ITU, Geneva. + + [11] Handley, M., Schooler, E., and H. Schulzrinne, "Session + Initiation Protocol (SIP)", Work in Progress. + + [12] Schulzrinne, H., Rao, A., and R. Lanphier, "Real Time Streaming + Protocol (RTSP)", RFC 2326, April 1998. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Handley & Jacobson Standards Track [Page 41] + +RFC 2327 SDP April 1998 + + +Full Copyright Statement + + Copyright (C) The Internet Society (1998). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + + + + + + + + + + + + + + + + + + + + + + + +Handley & Jacobson Standards Track [Page 42] + diff --git a/src/modules/rtp/rfc2974.txt b/src/modules/rtp/rfc2974.txt new file mode 100644 index 00000000..4a5aa626 --- /dev/null +++ b/src/modules/rtp/rfc2974.txt @@ -0,0 +1,1011 @@ + + + + + + +Network Working Group M. Handley +Request for Comments: 2974 ACIRI +Category: Experimental C. Perkins + USC/ISI + E. Whelan + UCL + October 2000 + + + Session Announcement Protocol + +Status of this Memo + + This memo defines an Experimental Protocol for the Internet + community. It does not specify an Internet standard of any kind. + Discussion and suggestions for improvement are requested. + Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2000). All Rights Reserved. + +Abstract + + This document describes version 2 of the multicast session directory + announcement protocol, Session Announcement Protocol (SAP), and the + related issues affecting security and scalability that should be + taken into account by implementors. + +1 Introduction + + In order to assist the advertisement of multicast multimedia + conferences and other multicast sessions, and to communicate the + relevant session setup information to prospective participants, a + distributed session directory may be used. An instance of such a + session directory periodically multicasts packets containing a + description of the session, and these advertisements are received by + other session directories such that potential remote participants can + use the session description to start the tools required to + participate in the session. + + This memo describes the issues involved in the multicast announcement + of session description information and defines an announcement + protocol to be used. Sessions are described using the session + description protocol which is described in a companion memo [4]. + + + + + + +Handley, et al. Experimental [Page 1] + +RFC 2974 Session Announcement Protocol October 2000 + + +2 Terminology + + A SAP announcer periodically multicasts an announcement packet to a + well known multicast address and port. The announcement is multicast + with the same scope as the session it is announcing, ensuring that + the recipients of the announcement are within the scope of the + session the announcement describes (bandwidth and other such + constraints permitting). This is also important for the scalability + of the protocol, as it keeps local session announcements local. + + A SAP listener learns of the multicast scopes it is within (for + example, using the Multicast-Scope Zone Announcement Protocol [5]) + and listens on the well known SAP address and port for those scopes. + In this manner, it will eventually learn of all the sessions being + announced, allowing those sessions to be joined. + + The key words `MUST', `MUST NOT', `REQUIRED', `SHALL', `SHALL NOT', + `SHOULD', `SHOULD NOT', `RECOMMENDED', `MAY', and `OPTIONAL' in this + document are to be interpreted as described in [1]. + +3 Session Announcement + + As noted previously, a SAP announcer periodically sends an + announcement packet to a well known multicast address and port. + There is no rendezvous mechanism - the SAP announcer is not aware of + the presence or absence of any SAP listeners - and no additional + reliability is provided over the standard best-effort UDP/IP + semantics. + + That announcement contains a session description and SHOULD contain + an authentication header. The session description MAY be encrypted + although this is NOT RECOMMENDED (see section 7). + + A SAP announcement is multicast with the same scope as the session it + is announcing, ensuring that the recipients of the announcement are + within the scope of the session the announcement describes. There are + a number of possibilities: + + IPv4 global scope sessions use multicast addresses in the range + 224.2.128.0 - 224.2.255.255 with SAP announcements being sent to + 224.2.127.254 (note that 224.2.127.255 is used by the obsolete + SAPv0 and MUST NOT be used). + + + + + + + + + +Handley, et al. Experimental [Page 2] + +RFC 2974 Session Announcement Protocol October 2000 + + + IPv4 administrative scope sessions using administratively scoped IP + multicast as defined in [7]. The multicast address to be used for + announcements is the highest multicast address in the relevant + administrative scope zone. For example, if the scope range is + 239.16.32.0 - 239.16.33.255, then 239.16.33.255 is used for SAP + announcements. + + IPv6 sessions are announced on the address FF0X:0:0:0:0:0:2:7FFE + where X is the 4-bit scope value. For example, an announcement + for a link-local session assigned the address + FF02:0:0:0:0:0:1234:5678, should be advertised on SAP address + FF02:0:0:0:0:0:2:7FFE. + + Ensuring that a description is not used by a potential participant + outside the session scope is not addressed in this memo. + + SAP announcements MUST be sent on port 9875 and SHOULD be sent with + an IP time-to-live of 255 (the use of TTL scoping for multicast is + discouraged [7]). + + If a session uses addresses in multiple administrative scope ranges, + it is necessary for the announcer to send identical copies of the + announcement to each administrative scope range. It is up to the + listeners to parse such multiple announcements as the same session + (as identified by the SDP origin field, for example). The + announcement rate for each administrative scope range MUST be + calculated separately, as if the multiple announcements were + separate. + + Multiple announcers may announce a single session, as an aid to + robustness in the face of packet loss and failure of one or more + announcers. The rate at which each announcer repeats its + announcement MUST be scaled back such that the total announcement + rate is equal to that which a single server would choose. + Announcements made in this manner MUST be identical. + + If multiple announcements are being made for a session, then each + announcement MUST carry an authentication header signed by the same + key, or be treated as a completely separate announcement by + listeners. + + An IPv4 SAP listener SHOULD listen on the IPv4 global scope SAP + address and on the SAP addresses for each IPv4 administrative scope + zone it is within. The discovery of administrative scope zones is + outside the scope of this memo, but it is assumed that each SAP + listener within a particular scope zone is aware of that scope zone. + A SAP listener which supports IPv6 SHOULD also listen to the IPv6 SAP + addresses. + + + +Handley, et al. Experimental [Page 3] + +RFC 2974 Session Announcement Protocol October 2000 + + +3.1 Announcement Interval + + The time period between repetitions of an announcement is chosen such + that the total bandwidth used by all announcements on a single SAP + group remains below a preconfigured limit. If not otherwise + specified, the bandwidth limit SHOULD be assumed to be 4000 bits per + second. + + Each announcer is expected to listen to other announcements in order + to determine the total number of sessions being announced on a + particular group. Sessions are uniquely identified by the + combination of the message identifier hash and originating source + fields of the SAP header (note that SAP v0 announcers always set the + message identifier hash to zero, and if such an announcement is + received the entire message MUST be compared to determine + uniqueness). + + Announcements are made by periodic multicast to the group. The base + interval between announcements is derived from the number of + announcements being made in that group, the size of the announcement + and the configured bandwidth limit. The actual transmission time is + derived from this base interval as follows: + + 1. The announcer initializes the variable tp to be the last time a + particular announcement was transmitted (or the current time if + this is the first time this announcement is to be made). + + 2. Given a configured bandwidth limit in bits/second and an + announcement of ad_size bytes, the base announcement interval + in seconds is + + interval =max(300; (8*no_of_ads*ad_size)/limit) + + 3. An offset is calculated based on the base announcement interval + + offset= rand(interval* 2/3)-(interval/3) + + 4. The next transmission time for an announcement derived as + + tn =tp+ interval+ offset + + The announcer then sets a timer to expire at tn and waits. At time + tn the announcer SHOULD recalculate the next transmission time. If + the new value of tn is before the current time, the announcement is + sent immediately. Otherwise the transmission is rescheduled for the + new tn. This reconsideration prevents transient packet bursts on + startup and when a network partition heals. + + + + +Handley, et al. Experimental [Page 4] + +RFC 2974 Session Announcement Protocol October 2000 + + +4 Session Deletion + + Sessions may be deleted in one of several ways: + + Explicit Timeout The session description payload may contain + timestamp information specifying the start- and end-times of the + session. If the current time is later than the end-time of the + session, then the session SHOULD be deleted from the receiver's + session cache. + + Implicit Timeout A session announcement message should be received + periodically for each session description in a receiver's session + cache. The announcement period can be predicted by the receiver + from the set of sessions currently being announced. If a session + announcement message has not been received for ten times the + announcement period, or one hour, whichever is the greater, then + the session is deleted from the receiver's session cache. The one + hour minimum is to allow for transient network partitionings. + + Explicit Deletion A session deletion packet is received specifying + the session to be deleted. Session deletion packets SHOULD have a + valid authentication header, matching that used to authenticate + previous announcement packets. If this authentication is missing, + the deletion message SHOULD be ignored. + +5 Session Modification + + A pre-announced session can be modified by simply announcing the + modified session description. In this case, the version hash in the + SAP header MUST be changed to indicate to receivers that the packet + contents should be parsed (or decrypted and parsed if it is + encrypted). The session itself, as distinct from the session + announcement, is uniquely identified by the payload and not by the + message identifier hash in the header. + + The same rules apply for session modification as for session + deletion: + + o Either the modified announcement must contain an authentication + header signed by the same key as the cached session announcement + it is modifying, or: + + o The cached session announcement must not contain an authentication + header, and the session modification announcement must originate + from the same host as the session it is modifying. + + + + + + +Handley, et al. Experimental [Page 5] + +RFC 2974 Session Announcement Protocol October 2000 + + + If an announcement is received containing an authentication header + and the cached announcement did not contain an authentication header, + or it contained a different authentication header, then the modified + announcement MUST be treated as a new and different announcement, and + displayed in addition to the un-authenticated announcement. The same + should happen if a modified packet without an authentication header + is received from a different source than the original announcement. + + These rules prevent an announcement having an authentication header + added by a malicious user and then being deleted using that header, + and it also prevents a denial-of-service attack by someone putting + out a spoof announcement which, due to packet loss, reaches some + participants before the original announcement. Note that under such + circumstances, being able to authenticate the message originator is + the only way to discover which session is the correct session. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | V=1 |A|R|T|E|C| auth len | msg id hash | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + : originating source (32 or 128 bits) : + : : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | optional authentication data | + : .... : + *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* + | optional payload type | + + +-+- - - - - - - - - -+ + | |0| | + + - - - - - - - - - - - - - - - - - - - - +-+ | + | | + : payload : + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 1: Packet format + +6 Packet Format + + SAP data packets have the format described in figure 1. + + V: Version Number. The version number field MUST be set to 1 (SAPv2 + announcements which use only SAPv1 features are backwards + compatible, those which use new features can be detected by other + means, so the SAP version number doesn't need to change). + + + + +Handley, et al. Experimental [Page 6] + +RFC 2974 Session Announcement Protocol October 2000 + + + A: Address type. If the A bit is 0, the originating source field + contains a 32-bit IPv4 address. If the A bit is 1, the + originating source contains a 128-bit IPv6 address. + + R: Reserved. SAP announcers MUST set this to 0, SAP listeners MUST + ignore the contents of this field. + + T: Message Type. If the T field is set to 0 this is a session + announcement packet, if 1 this is a session deletion packet. + + E: Encryption Bit. If the encryption bit is set to 1, the payload of + the SAP packet is encrypted. If this bit is 0 the packet is not + encrypted. See section 7 for details of the encryption process. + + C: Compressed bit. If the compressed bit is set to 1, the payload is + compressed using the zlib compression algorithm [3]. If the + payload is to be compressed and encrypted, the compression MUST be + performed first. + + Authentication Length. An 8 bit unsigned quantity giving the number + of 32 bit words following the main SAP header that contain + authentication data. If it is zero, no authentication header is + present. + + Authentication data containing a digital signature of the packet, + with length as specified by the authentication length header + field. See section 8 for details of the authentication process. + + Message Identifier Hash. A 16 bit quantity that, used in combination + with the originating source, provides a globally unique identifier + indicating the precise version of this announcement. The choice + of value for this field is not specified here, except that it MUST + be unique for each session announced by a particular SAP announcer + and it MUST be changed if the session description is modified (and + a session deletion message SHOULD be sent for the old version of + the session). + + Earlier versions of SAP used a value of zero to mean that the hash + should be ignored and the payload should always be parsed. This + had the unfortunate side-effect that SAP announcers had to study + the payload data to determine how many unique sessions were being + advertised, making the calculation of the announcement interval + more complex that necessary. In order to decouple the session + announcement process from the contents of those announcements, SAP + announcers SHOULD NOT set the message identifier hash to zero. + + SAP listeners MAY silently discard messages if the message + identifier hash is set to zero. + + + +Handley, et al. Experimental [Page 7] + +RFC 2974 Session Announcement Protocol October 2000 + + + Originating Source. This gives the IP address of the original source + of the message. This is an IPv4 address if the A field is set to + zero, else it is an IPv6 address. The address is stored in + network byte order. + + SAPv0 permitted the originating source to be zero if the message + identifier hash was also zero. This practise is no longer legal, + and SAP announcers SHOULD NOT set the originating source to zero. + SAP listeners MAY silently discard packets with the originating + source set to zero. + + The header is followed by an optional payload type field and the + payload data itself. If the E or C bits are set in the header both + the payload type and payload are encrypted and/or compressed. + + The payload type field is a MIME content type specifier, describing + the format of the payload. This is a variable length ASCII text + string, followed by a single zero byte (ASCII NUL). The payload type + SHOULD be included in all packets. If the payload type is + `application/sdp' both the payload type and its terminating zero byte + MAY be omitted, although this is intended for backwards compatibility + with SAP v1 listeners only. + + The absence of a payload type field may be noted since the payload + section of such a packet will start with an SDP `v=0' field, which is + not a legal MIME content type specifier. + + All implementations MUST support payloads of type `application/sdp' + [4]. Other formats MAY be supported although since there is no + negotiation in SAP an announcer which chooses to use a session + description format other than SDP cannot know that the listeners are + able to understand the announcement. A proliferation of payload + types in announcements has the potential to lead to severe + interoperability problems, and for this reason, the use of non-SDP + payloads is NOT RECOMMENDED. + + If the packet is an announcement packet, the payload contains a + session description. + + If the packet is a session deletion packet, the payload contains a + session deletion message. If the payload format is `application/sdp' + the deletion message is a single SDP line consisting of the origin + field of the announcement to be deleted. + + It is desirable for the payload to be sufficiently small that SAP + packets do not get fragmented by the underlying network. + Fragmentation has a loss multiplier effect, which is known to + significantly affect the reliability of announcements. It is + + + +Handley, et al. Experimental [Page 8] + +RFC 2974 Session Announcement Protocol October 2000 + + + RECOMMENDED that SAP packets are smaller than 1kByte in length, + although if it is known that announcements will use a network with a + smaller MTU than this, then that SHOULD be used as the maximum + recommended packet size. + +7 Encrypted Announcements + + An announcement is received by all listeners in the scope to which it + is sent. If an announcement is encrypted, and many of the receivers + do not have the encryption key, there is a considerable waste of + bandwidth since those receivers cannot use the announcement they have + received. For this reason, the use of encrypted SAP announcements is + NOT RECOMMENDED on the global scope SAP group or on administrative + scope groups which may have many receivers which cannot decrypt those + announcements. + + The opinion of the authors is that encrypted SAP is useful in special + cases only, and that the vast majority of scenarios where encrypted + SAP has been proposed may be better served by distributing session + details using another mechanism. There are, however, certain + scenarios where encrypted announcements may be useful. For this + reason, the encryption bit is included in the SAP header to allow + experimentation with encrypted announcements. + + This memo does not specify details of the encryption algorithm to be + used or the means by which keys are generated and distributed. An + additional specification should define these, if it is desired to use + encrypted SAP. + + Note that if an encrypted announcement is being announced via a + proxy, then there may be no way for the proxy to discover that the + announcement has been superseded, and so it may continue to relay the + old announcement in addition to the new announcement. SAP provides + no mechanism to chain modified encrypted announcements, so it is + advisable to announce the unmodified session as deleted for a short + time after the modification has occurred. This does not guarantee + that all proxies have deleted the session, and so receivers of + encrypted sessions should be prepared to discard old versions of + session announcements that they may receive. In most cases however, + the only stateful proxy will be local to (and known to) the sender, + and an additional (local-area) protocol involving a handshake for + such session modifications can be used to avoid this problem. + + Session announcements that are encrypted with a symmetric algorithm + may allow a degree of privacy in the announcement of a session, but + it should be recognized that a user in possession of such a key can + pass it on to other users who should not be in possession of such a + key. Thus announcements to such a group of key holders cannot be + + + +Handley, et al. Experimental [Page 9] + +RFC 2974 Session Announcement Protocol October 2000 + + + assumed to have come from an authorized key holder unless there is an + appropriate authentication header signed by an authorized key holder. + In addition the recipients of such encrypted announcements cannot be + assumed to only be authorized key holders. Such encrypted + announcements do not provide any real security unless all of the + authorized key holders are trusted to maintain security of such + session directory keys. This property is shared by the multicast + session tools themselves, where it is possible for an un-trustworthy + member of the session to pass on encryption keys to un-authorized + users. However it is likely that keys used for the session tools + will be more short lived than those used for session directories. + + Similar considerations should apply when session announcements are + encrypted with an asymmetric algorithm, but then it is possible to + restrict the possessor(s) of the private key, so that announcements + to a key-holder group can not be made, even if one of the untrusted + members of the group proves to be un-trustworthy. + + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | V=1 |P| Auth | | + +-+-+-+-+-+-+-+-+ | + | Format specific authentication subheader | + : .................. : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 2: Format of the authentication data in the SAP header + +8 Authenticated Announcements + + The authentication header can be used for two purposes: + + o Verification that changes to a session description or deletion of + a session are permitted. + + o Authentication of the identity of the session creator. + + In some circumstances only verification is possible because a + certificate signed by a mutually trusted person or authority is not + available. However, under such circumstances, the session originator + may still be authenticated to be the same as the session originator + of previous sessions claiming to be from the same person. This may + or may not be sufficient depending on the purpose of the session and + the people involved. + + + + + + +Handley, et al. Experimental [Page 10] + +RFC 2974 Session Announcement Protocol October 2000 + + + Clearly the key used for the authentication should not be trusted to + belong to the session originator unless it has been separately + authenticated by some other means, such as being certified by a + trusted third party. Such certificates are not normally included in + an SAP header because they take more space than can normally be + afforded in an SAP packet, and such verification must therefore take + place by some other mechanism. However, as certified public keys are + normally locally cached, authentication of a particular key only has + to take place once, rather than every time the session directory + retransmits the announcement. + + SAP is not tied to any single authentication mechanism. + Authentication data in the header is self-describing, but the precise + format depends on the authentication mechanism in use. The generic + format of the authentication data is given in figure 2. The + structure of the format specific authentication subheader, using both + the PGP and the CMS formats, is discussed in sections 8.1 and 8.2 + respectively. Additional formats may be added in future. + + Version Number, V: The version number of the authentication format + specified by this memo is 1. + + Padding Bit, P: If necessary the authentication data is padded to be + a multiple of 32 bits and the padding bit is set. In this case + the last byte of the authentication data contains the number of + padding bytes (including the last byte) that must be discarded. + + Authentication Type, Auth: The authentication type is a 4 bit + encoded field that denotes the authentication infrastructure the + sender expects the recipients to use to check the authenticity and + integrity of the information. This defines the format of the + authentication subheader and can take the values: 0 = PGP format, + 1 = CMS format. All other values are undefined and SHOULD be + ignored. + + If a SAP packet is to be compressed or encrypted, this MUST be done + before the authentication is added. + + The digital signature in the authentication data MUST be calculated + over the entire packet, including the header. The authentication + length MUST be set to zero and the authentication data excluded when + calculating the digital signature. + + It is to be expected that sessions may be announced by a number of + different mechanisms, not only SAP. For example, a session + description may placed on a web page, sent by email or conveyed in a + + + + + +Handley, et al. Experimental [Page 11] + +RFC 2974 Session Announcement Protocol October 2000 + + + session initiation protocol. To ease interoperability with these + other mechanisms, application level security is employed, rather than + using IPsec authentication headers. + +8.1 PGP Authentication + + A full description of the PGP protocol can be found in [2]. When + using PGP for SAP authentication the basic format specific + authentication subheader comprises a digital signature packet as + described in [2]. The signature type MUST be 0x01 which means the + signature is that of a canonical text document. + +8.2 CMS Authentication + + A full description of the Cryptographic Message Syntax can be found + in [6]. The format specific authentication subheader will, in the + CMS case, have an ASN.1 ContentInfo type with the ContentType being + signedData. + + Use is made of the option available in PKCS#7 to leave the content + itself blank as the content which is signed is already present in the + packet. Inclusion of it within the SignedData type would duplicate + this data and increase the packet length unnecessarily. In addition + this allows recipients with either no interest in the authentication, + or with no mechanism for checking it, to more easily skip the + authentication information. + + There SHOULD be only one signerInfo and related fields corresponding + to the originator of the SAP announcement. The signingTime SHOULD be + present as a signedAttribute. However, due to the strict size + limitations on the size of SAP packets, certificates and CRLs SHOULD + NOT be included in the signedData structure. It is expected that + users of the protocol will have other methods for certificate and CRL + distribution. + +9 Scalability and caching + + SAP is intended to announce the existence of long-lived wide-area + multicast sessions. It is not an especially timely protocol: + sessions are announced by periodic multicast with a repeat rate on + the order of tens of minutes, and no enhanced reliability over UDP. + This leads to a long startup delay before a complete set of + announcements is heard by a listener. This delay is clearly + undesirable for interactive browsing of announced sessions. + + In order to reduce the delays inherent in SAP, it is recommended that + proxy caches are deployed. A SAP proxy cache is expected to listen + to all SAP groups in its scope, and to maintain an up-to-date list of + + + +Handley, et al. Experimental [Page 12] + +RFC 2974 Session Announcement Protocol October 2000 + + + all announced sessions along with the time each announcement was last + received. When a new SAP listeners starts, it should contact its + local proxy to download this information, which is then sufficient + for it to process future announcements directly, as if it has been + continually listening. + + The protocol by which a SAP listener contacts its local proxy cache + is not specified here. + +10 Security Considerations + + SAP contains mechanisms for ensuring integrity of session + announcements, for authenticating the origin of an announcement and + for encrypting such announcements (sections 7 and 8). + + As stated in section 5, if a session modification announcement is + received that contains a valid authentication header, but which is + not signed by the original creator of the session, then the session + must be treated as a new session in addition to the original session + with the same SDP origin information unless the originator of one of + the session descriptions can be authenticated using a certificate + signed by a trusted third party. If this were not done, there would + be a possible denial of service attack whereby a party listens for + new announcements, strips off the original authentication header, + modifies the session description, adds a new authentication header + and re-announces the session. If a rule was imposed that such spoof + announcements were ignored, then if packet loss or late starting of a + session directory instance caused the original announcement to fail + to arrive at a site, but the spoof announcement did so, this would + then prevent the original announcement from being accepted at that + site. + + A similar denial-of-service attack is possible if a session + announcement receiver relies completely on the originating source and + hash fields to indicate change, and fails to parse the remainder of + announcements for which it has seen the origin/hash combination + before. + + A denial of service attack is possible from a malicious site close to + a legitimate site which is making a session announcement. This can + happen if the malicious site floods the legitimate site with huge + numbers of (illegal) low TTL announcements describing high TTL + sessions. This may reduce the session announcement rate of the + legitimate announcement to below a tenth of the rate expected at + remote sites and therefore cause the session to time out. Such an + attack is likely to be easily detectable, and we do not provide any + mechanism here to prevent it. + + + + +Handley, et al. Experimental [Page 13] + +RFC 2974 Session Announcement Protocol October 2000 + + +A. Summary of differences between SAPv0 and SAPv1 + + For this purpose SAPv0 is defined as the protocol in use by version + 2.2 of the session directory tool, sdr. SAPv1 is the protocol + described in the 19 November 1996 version of this memo. The packet + headers of SAP messages are the same in V0 and V1 in that a V1 tool + can parse a V0 announcement header but not vice-versa. In SAPv0, the + fields have the following values: + + o Version Number: 0 + + o Message Type: 0 (Announcement) + + o Authentication Type: 0 (No Authentication) + + o Encryption Bit: 0 (No Encryption) + + o Compression Bit: 0 (No compression) + + o Message Id Hash: 0 (No Hash Specified) + + o Originating Source: 0 (No source specified, announcement has + not been relayed) + +B. Summary of differences between SAPv1 and SAPv2 + + The packet headers of SAP messages are the same in V1 and V2 in that + a V2 tool can parse a V1 announcement header but not necessarily + vice-versa. + + o The A bit has been added to the SAP header, replacing one of the + bits of the SAPv1 message type field. If set to zero the + announcement is of an IPv4 session, and the packet is backwards + compatible with SAPv1. If set to one the announcement is of an + IPv6 session, and SAPv1 listeners (which do not support IPv6) will + see this as an illegal message type (MT) field. + + o The second bit of the message type field in SAPv1 has been + replaced by a reserved, must-be-zero, bit. This bit was unused in + SAPv1, so this change just codifies existing usage. + + o SAPv1 specified encryption of the payload. SAPv2 includes the E + bit in the SAP header to indicate that the payload is encrypted, + but does not specify any details of the encryption. + + o SAPv1 allowed the message identifier hash and originating source + fields to be set to zero, for backwards compatibility. This is no + longer legal. + + + +Handley, et al. Experimental [Page 14] + +RFC 2974 Session Announcement Protocol October 2000 + + + o SAPv1 specified gzip compression. SAPv2 uses zlib (the only known + implementation of SAP compression used zlib, and gzip compression + was a mistake). + + o SAPv2 provides a more complete specification for authentication. + + o SAPv2 allows for non-SDP payloads to be transported. SAPv1 + required that the payload was SDP. + + o SAPv1 included a timeout field for encrypted announcement, SAPv2 + does not (and relies of explicit deletion messages or implicit + timeouts). + +C. Acknowledgements + + SAP and SDP were originally based on the protocol used by the sd + session directory from Van Jacobson at LBNL. Version 1 of SAP was + designed by Mark Handley as part of the European Commission MICE + (Esprit 7602) and MERCI (Telematics 1007) projects. Version 2 + includes authentication features developed by Edmund Whelan, Goli + Montasser-Kohsari and Peter Kirstein as part of the European + Commission ICE-TEL project (Telematics 1005), and support for IPv6 + developed by Maryann P. Maher and Colin Perkins. + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Handley, et al. Experimental [Page 15] + +RFC 2974 Session Announcement Protocol October 2000 + + +D. Authors' Addresses + + Mark Handley + AT&T Center for Internet Research at ICSI, + International Computer Science Institute, + 1947 Center Street, Suite 600, + Berkeley, CA 94704, USA + + EMail: mjh@aciri.org + + + Colin Perkins + USC Information Sciences Institute + 4350 N. Fairfax Drive, Suite 620 + Arlington, VA 22203, USA + + EMail: csp@isi.edu + + + Edmund Whelan + Department of Computer Science, + University College London, + Gower Street, + London, WC1E 6BT, UK + + EMail: e.whelan@cs.ucl.ac.uk + + + + + + + + + + + + + + + + + + + + + + + + + +Handley, et al. Experimental [Page 16] + +RFC 2974 Session Announcement Protocol October 2000 + + +References + + [1] Bradner, S., "Key words for use in RFCs to indicate requirement + levels", BCP 14, RFC 2119, March 1997. + + [2] Callas, J., Donnerhacke, L., Finney, H. and R. Thayer. "OpenPGP + message format", RFC 2440, November 1998. + + [3] Deutsch, P. and J.-L. Gailly, "Zlib compressed data format + specification version 3.3", RFC 1950, May 1996. + + [4] Handley, M. and V. Jacobson, "SDP: Session Description Protocol", + RFC 2327, April 1998. + + [5] Handley, M., Thaler, D. and R. Kermode, "Multicast-scope zone + announcement protocol (MZAP)", RFC 2776, February 2000. + + [6] Housley, R., "Cryptographic message syntax", RFC 2630, June 1999. + + [7] Mayer, D., "Administratively scoped IP multicast", RFC 2365, July + 1998. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Handley, et al. Experimental [Page 17] + +RFC 2974 Session Announcement Protocol October 2000 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2000). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Handley, et al. Experimental [Page 18] + diff --git a/src/modules/rtp/rfc3550.txt b/src/modules/rtp/rfc3550.txt new file mode 100644 index 00000000..165736cf --- /dev/null +++ b/src/modules/rtp/rfc3550.txt @@ -0,0 +1,5827 @@ + + + + + + +Network Working Group H. Schulzrinne +Request for Comments: 3550 Columbia University +Obsoletes: 1889 S. Casner +Category: Standards Track Packet Design + R. Frederick + Blue Coat Systems Inc. + V. Jacobson + Packet Design + July 2003 + + + RTP: A Transport Protocol for Real-Time Applications + +Status of this Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + +Abstract + + This memorandum describes RTP, the real-time transport protocol. RTP + provides end-to-end network transport functions suitable for + applications transmitting real-time data, such as audio, video or + simulation data, over multicast or unicast network services. RTP + does not address resource reservation and does not guarantee + quality-of-service for real-time services. The data transport is + augmented by a control protocol (RTCP) to allow monitoring of the + data delivery in a manner scalable to large multicast networks, and + to provide minimal control and identification functionality. RTP and + RTCP are designed to be independent of the underlying transport and + network layers. The protocol supports the use of RTP-level + translators and mixers. + + Most of the text in this memorandum is identical to RFC 1889 which it + obsoletes. There are no changes in the packet formats on the wire, + only changes to the rules and algorithms governing how the protocol + is used. The biggest change is an enhancement to the scalable timer + algorithm for calculating when to send RTCP packets in order to + minimize transmission in excess of the intended rate when many + participants join a session simultaneously. + + + + +Schulzrinne, et al. Standards Track [Page 1] + +RFC 3550 RTP July 2003 + + +Table of Contents + + 1. Introduction ................................................ 4 + 1.1 Terminology ............................................ 5 + 2. RTP Use Scenarios ........................................... 5 + 2.1 Simple Multicast Audio Conference ...................... 6 + 2.2 Audio and Video Conference ............................. 7 + 2.3 Mixers and Translators ................................. 7 + 2.4 Layered Encodings ...................................... 8 + 3. Definitions ................................................. 8 + 4. Byte Order, Alignment, and Time Format ...................... 12 + 5. RTP Data Transfer Protocol .................................. 13 + 5.1 RTP Fixed Header Fields ................................ 13 + 5.2 Multiplexing RTP Sessions .............................. 16 + 5.3 Profile-Specific Modifications to the RTP Header ....... 18 + 5.3.1 RTP Header Extension ............................ 18 + 6. RTP Control Protocol -- RTCP ................................ 19 + 6.1 RTCP Packet Format ..................................... 21 + 6.2 RTCP Transmission Interval ............................. 24 + 6.2.1 Maintaining the Number of Session Members ....... 28 + 6.3 RTCP Packet Send and Receive Rules ..................... 28 + 6.3.1 Computing the RTCP Transmission Interval ........ 29 + 6.3.2 Initialization .................................. 30 + 6.3.3 Receiving an RTP or Non-BYE RTCP Packet ......... 31 + 6.3.4 Receiving an RTCP BYE Packet .................... 31 + 6.3.5 Timing Out an SSRC .............................. 32 + 6.3.6 Expiration of Transmission Timer ................ 32 + 6.3.7 Transmitting a BYE Packet ....................... 33 + 6.3.8 Updating we_sent ................................ 34 + 6.3.9 Allocation of Source Description Bandwidth ...... 34 + 6.4 Sender and Receiver Reports ............................ 35 + 6.4.1 SR: Sender Report RTCP Packet ................... 36 + 6.4.2 RR: Receiver Report RTCP Packet ................. 42 + 6.4.3 Extending the Sender and Receiver Reports ....... 42 + 6.4.4 Analyzing Sender and Receiver Reports ........... 43 + 6.5 SDES: Source Description RTCP Packet ................... 45 + 6.5.1 CNAME: Canonical End-Point Identifier SDES Item . 46 + 6.5.2 NAME: User Name SDES Item ....................... 48 + 6.5.3 EMAIL: Electronic Mail Address SDES Item ........ 48 + 6.5.4 PHONE: Phone Number SDES Item ................... 49 + 6.5.5 LOC: Geographic User Location SDES Item ......... 49 + 6.5.6 TOOL: Application or Tool Name SDES Item ........ 49 + 6.5.7 NOTE: Notice/Status SDES Item ................... 50 + 6.5.8 PRIV: Private Extensions SDES Item .............. 50 + 6.6 BYE: Goodbye RTCP Packet ............................... 51 + 6.7 APP: Application-Defined RTCP Packet ................... 52 + 7. RTP Translators and Mixers .................................. 53 + 7.1 General Description .................................... 53 + + + +Schulzrinne, et al. Standards Track [Page 2] + +RFC 3550 RTP July 2003 + + + 7.2 RTCP Processing in Translators ......................... 55 + 7.3 RTCP Processing in Mixers .............................. 57 + 7.4 Cascaded Mixers ........................................ 58 + 8. SSRC Identifier Allocation and Use .......................... 59 + 8.1 Probability of Collision ............................... 59 + 8.2 Collision Resolution and Loop Detection ................ 60 + 8.3 Use with Layered Encodings ............................. 64 + 9. Security .................................................... 65 + 9.1 Confidentiality ........................................ 65 + 9.2 Authentication and Message Integrity ................... 67 + 10. Congestion Control .......................................... 67 + 11. RTP over Network and Transport Protocols .................... 68 + 12. Summary of Protocol Constants ............................... 69 + 12.1 RTCP Packet Types ...................................... 70 + 12.2 SDES Types ............................................. 70 + 13. RTP Profiles and Payload Format Specifications .............. 71 + 14. Security Considerations ..................................... 73 + 15. IANA Considerations ......................................... 73 + 16. Intellectual Property Rights Statement ...................... 74 + 17. Acknowledgments ............................................. 74 + Appendix A. Algorithms ........................................ 75 + Appendix A.1 RTP Data Header Validity Checks ................... 78 + Appendix A.2 RTCP Header Validity Checks ....................... 82 + Appendix A.3 Determining Number of Packets Expected and Lost ... 83 + Appendix A.4 Generating RTCP SDES Packets ...................... 84 + Appendix A.5 Parsing RTCP SDES Packets ......................... 85 + Appendix A.6 Generating a Random 32-bit Identifier ............. 85 + Appendix A.7 Computing the RTCP Transmission Interval .......... 87 + Appendix A.8 Estimating the Interarrival Jitter ................ 94 + Appendix B. Changes from RFC 1889 ............................. 95 + References ...................................................... 100 + Normative References ............................................ 100 + Informative References .......................................... 100 + Authors' Addresses .............................................. 103 + Full Copyright Statement ........................................ 104 + + + + + + + + + + + + + + + + +Schulzrinne, et al. Standards Track [Page 3] + +RFC 3550 RTP July 2003 + + +1. Introduction + + This memorandum specifies the real-time transport protocol (RTP), + which provides end-to-end delivery services for data with real-time + characteristics, such as interactive audio and video. Those services + include payload type identification, sequence numbering, timestamping + and delivery monitoring. Applications typically run RTP on top of + UDP to make use of its multiplexing and checksum services; both + protocols contribute parts of the transport protocol functionality. + However, RTP may be used with other suitable underlying network or + transport protocols (see Section 11). RTP supports data transfer to + multiple destinations using multicast distribution if provided by the + underlying network. + + Note that RTP itself does not provide any mechanism to ensure timely + delivery or provide other quality-of-service guarantees, but relies + on lower-layer services to do so. It does not guarantee delivery or + prevent out-of-order delivery, nor does it assume that the underlying + network is reliable and delivers packets in sequence. The sequence + numbers included in RTP allow the receiver to reconstruct the + sender's packet sequence, but sequence numbers might also be used to + determine the proper location of a packet, for example in video + decoding, without necessarily decoding packets in sequence. + + While RTP is primarily designed to satisfy the needs of multi- + participant multimedia conferences, it is not limited to that + particular application. Storage of continuous data, interactive + distributed simulation, active badge, and control and measurement + applications may also find RTP applicable. + + This document defines RTP, consisting of two closely-linked parts: + + o the real-time transport protocol (RTP), to carry data that has + real-time properties. + + o the RTP control protocol (RTCP), to monitor the quality of service + and to convey information about the participants in an on-going + session. The latter aspect of RTCP may be sufficient for "loosely + controlled" sessions, i.e., where there is no explicit membership + control and set-up, but it is not necessarily intended to support + all of an application's control communication requirements. This + functionality may be fully or partially subsumed by a separate + session control protocol, which is beyond the scope of this + document. + + RTP represents a new style of protocol following the principles of + application level framing and integrated layer processing proposed by + Clark and Tennenhouse [10]. That is, RTP is intended to be malleable + + + +Schulzrinne, et al. Standards Track [Page 4] + +RFC 3550 RTP July 2003 + + + to provide the information required by a particular application and + will often be integrated into the application processing rather than + being implemented as a separate layer. RTP is a protocol framework + that is deliberately not complete. This document specifies those + functions expected to be common across all the applications for which + RTP would be appropriate. Unlike conventional protocols in which + additional functions might be accommodated by making the protocol + more general or by adding an option mechanism that would require + parsing, RTP is intended to be tailored through modifications and/or + additions to the headers as needed. Examples are given in Sections + 5.3 and 6.4.3. + + Therefore, in addition to this document, a complete specification of + RTP for a particular application will require one or more companion + documents (see Section 13): + + o a profile specification document, which defines a set of payload + type codes and their mapping to payload formats (e.g., media + encodings). A profile may also define extensions or modifications + to RTP that are specific to a particular class of applications. + Typically an application will operate under only one profile. A + profile for audio and video data may be found in the companion RFC + 3551 [1]. + + o payload format specification documents, which define how a + particular payload, such as an audio or video encoding, is to be + carried in RTP. + + A discussion of real-time services and algorithms for their + implementation as well as background discussion on some of the RTP + design decisions can be found in [11]. + +1.1 Terminology + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 [2] + and indicate requirement levels for compliant RTP implementations. + +2. RTP Use Scenarios + + The following sections describe some aspects of the use of RTP. The + examples were chosen to illustrate the basic operation of + applications using RTP, not to limit what RTP may be used for. In + these examples, RTP is carried on top of IP and UDP, and follows the + conventions established by the profile for audio and video specified + in the companion RFC 3551. + + + + +Schulzrinne, et al. Standards Track [Page 5] + +RFC 3550 RTP July 2003 + + +2.1 Simple Multicast Audio Conference + + A working group of the IETF meets to discuss the latest protocol + document, using the IP multicast services of the Internet for voice + communications. Through some allocation mechanism the working group + chair obtains a multicast group address and pair of ports. One port + is used for audio data, and the other is used for control (RTCP) + packets. This address and port information is distributed to the + intended participants. If privacy is desired, the data and control + packets may be encrypted as specified in Section 9.1, in which case + an encryption key must also be generated and distributed. The exact + details of these allocation and distribution mechanisms are beyond + the scope of RTP. + + The audio conferencing application used by each conference + participant sends audio data in small chunks of, say, 20 ms duration. + Each chunk of audio data is preceded by an RTP header; RTP header and + data are in turn contained in a UDP packet. The RTP header indicates + what type of audio encoding (such as PCM, ADPCM or LPC) is contained + in each packet so that senders can change the encoding during a + conference, for example, to accommodate a new participant that is + connected through a low-bandwidth link or react to indications of + network congestion. + + The Internet, like other packet networks, occasionally loses and + reorders packets and delays them by variable amounts of time. To + cope with these impairments, the RTP header contains timing + information and a sequence number that allow the receivers to + reconstruct the timing produced by the source, so that in this + example, chunks of audio are contiguously played out the speaker + every 20 ms. This timing reconstruction is performed separately for + each source of RTP packets in the conference. The sequence number + can also be used by the receiver to estimate how many packets are + being lost. + + Since members of the working group join and leave during the + conference, it is useful to know who is participating at any moment + and how well they are receiving the audio data. For that purpose, + each instance of the audio application in the conference periodically + multicasts a reception report plus the name of its user on the RTCP + (control) port. The reception report indicates how well the current + speaker is being received and may be used to control adaptive + encodings. In addition to the user name, other identifying + information may also be included subject to control bandwidth limits. + A site sends the RTCP BYE packet (Section 6.6) when it leaves the + conference. + + + + + +Schulzrinne, et al. Standards Track [Page 6] + +RFC 3550 RTP July 2003 + + +2.2 Audio and Video Conference + + If both audio and video media are used in a conference, they are + transmitted as separate RTP sessions. That is, separate RTP and RTCP + packets are transmitted for each medium using two different UDP port + pairs and/or multicast addresses. There is no direct coupling at the + RTP level between the audio and video sessions, except that a user + participating in both sessions should use the same distinguished + (canonical) name in the RTCP packets for both so that the sessions + can be associated. + + One motivation for this separation is to allow some participants in + the conference to receive only one medium if they choose. Further + explanation is given in Section 5.2. Despite the separation, + synchronized playback of a source's audio and video can be achieved + using timing information carried in the RTCP packets for both + sessions. + +2.3 Mixers and Translators + + So far, we have assumed that all sites want to receive media data in + the same format. However, this may not always be appropriate. + Consider the case where participants in one area are connected + through a low-speed link to the majority of the conference + participants who enjoy high-speed network access. Instead of forcing + everyone to use a lower-bandwidth, reduced-quality audio encoding, an + RTP-level relay called a mixer may be placed near the low-bandwidth + area. This mixer resynchronizes incoming audio packets to + reconstruct the constant 20 ms spacing generated by the sender, mixes + these reconstructed audio streams into a single stream, translates + the audio encoding to a lower-bandwidth one and forwards the lower- + bandwidth packet stream across the low-speed link. These packets + might be unicast to a single recipient or multicast on a different + address to multiple recipients. The RTP header includes a means for + mixers to identify the sources that contributed to a mixed packet so + that correct talker indication can be provided at the receivers. + + Some of the intended participants in the audio conference may be + connected with high bandwidth links but might not be directly + reachable via IP multicast. For example, they might be behind an + application-level firewall that will not let any IP packets pass. + For these sites, mixing may not be necessary, in which case another + type of RTP-level relay called a translator may be used. Two + translators are installed, one on either side of the firewall, with + the outside one funneling all multicast packets received through a + secure connection to the translator inside the firewall. The + translator inside the firewall sends them again as multicast packets + to a multicast group restricted to the site's internal network. + + + +Schulzrinne, et al. Standards Track [Page 7] + +RFC 3550 RTP July 2003 + + + Mixers and translators may be designed for a variety of purposes. An + example is a video mixer that scales the images of individual people + in separate video streams and composites them into one video stream + to simulate a group scene. Other examples of translation include the + connection of a group of hosts speaking only IP/UDP to a group of + hosts that understand only ST-II, or the packet-by-packet encoding + translation of video streams from individual sources without + resynchronization or mixing. Details of the operation of mixers and + translators are given in Section 7. + +2.4 Layered Encodings + + Multimedia applications should be able to adjust the transmission + rate to match the capacity of the receiver or to adapt to network + congestion. Many implementations place the responsibility of rate- + adaptivity at the source. This does not work well with multicast + transmission because of the conflicting bandwidth requirements of + heterogeneous receivers. The result is often a least-common + denominator scenario, where the smallest pipe in the network mesh + dictates the quality and fidelity of the overall live multimedia + "broadcast". + + Instead, responsibility for rate-adaptation can be placed at the + receivers by combining a layered encoding with a layered transmission + system. In the context of RTP over IP multicast, the source can + stripe the progressive layers of a hierarchically represented signal + across multiple RTP sessions each carried on its own multicast group. + Receivers can then adapt to network heterogeneity and control their + reception bandwidth by joining only the appropriate subset of the + multicast groups. + + Details of the use of RTP with layered encodings are given in + Sections 6.3.9, 8.3 and 11. + +3. Definitions + + RTP payload: The data transported by RTP in a packet, for + example audio samples or compressed video data. The payload + format and interpretation are beyond the scope of this document. + + RTP packet: A data packet consisting of the fixed RTP header, a + possibly empty list of contributing sources (see below), and the + payload data. Some underlying protocols may require an + encapsulation of the RTP packet to be defined. Typically one + packet of the underlying protocol contains a single RTP packet, + but several RTP packets MAY be contained if permitted by the + encapsulation method (see Section 11). + + + + +Schulzrinne, et al. Standards Track [Page 8] + +RFC 3550 RTP July 2003 + + + RTCP packet: A control packet consisting of a fixed header part + similar to that of RTP data packets, followed by structured + elements that vary depending upon the RTCP packet type. The + formats are defined in Section 6. Typically, multiple RTCP + packets are sent together as a compound RTCP packet in a single + packet of the underlying protocol; this is enabled by the length + field in the fixed header of each RTCP packet. + + Port: The "abstraction that transport protocols use to + distinguish among multiple destinations within a given host + computer. TCP/IP protocols identify ports using small positive + integers." [12] The transport selectors (TSEL) used by the OSI + transport layer are equivalent to ports. RTP depends upon the + lower-layer protocol to provide some mechanism such as ports to + multiplex the RTP and RTCP packets of a session. + + Transport address: The combination of a network address and port + that identifies a transport-level endpoint, for example an IP + address and a UDP port. Packets are transmitted from a source + transport address to a destination transport address. + + RTP media type: An RTP media type is the collection of payload + types which can be carried within a single RTP session. The RTP + Profile assigns RTP media types to RTP payload types. + + Multimedia session: A set of concurrent RTP sessions among a + common group of participants. For example, a videoconference + (which is a multimedia session) may contain an audio RTP session + and a video RTP session. + + RTP session: An association among a set of participants + communicating with RTP. A participant may be involved in multiple + RTP sessions at the same time. In a multimedia session, each + medium is typically carried in a separate RTP session with its own + RTCP packets unless the the encoding itself multiplexes multiple + media into a single data stream. A participant distinguishes + multiple RTP sessions by reception of different sessions using + different pairs of destination transport addresses, where a pair + of transport addresses comprises one network address plus a pair + of ports for RTP and RTCP. All participants in an RTP session may + share a common destination transport address pair, as in the case + of IP multicast, or the pairs may be different for each + participant, as in the case of individual unicast network + addresses and port pairs. In the unicast case, a participant may + receive from all other participants in the session using the same + pair of ports, or may use a distinct pair of ports for each. + + + + + +Schulzrinne, et al. Standards Track [Page 9] + +RFC 3550 RTP July 2003 + + + The distinguishing feature of an RTP session is that each + maintains a full, separate space of SSRC identifiers (defined + next). The set of participants included in one RTP session + consists of those that can receive an SSRC identifier transmitted + by any one of the participants either in RTP as the SSRC or a CSRC + (also defined below) or in RTCP. For example, consider a three- + party conference implemented using unicast UDP with each + participant receiving from the other two on separate port pairs. + If each participant sends RTCP feedback about data received from + one other participant only back to that participant, then the + conference is composed of three separate point-to-point RTP + sessions. If each participant provides RTCP feedback about its + reception of one other participant to both of the other + participants, then the conference is composed of one multi-party + RTP session. The latter case simulates the behavior that would + occur with IP multicast communication among the three + participants. + + The RTP framework allows the variations defined here, but a + particular control protocol or application design will usually + impose constraints on these variations. + + Synchronization source (SSRC): The source of a stream of RTP + packets, identified by a 32-bit numeric SSRC identifier carried in + the RTP header so as not to be dependent upon the network address. + All packets from a synchronization source form part of the same + timing and sequence number space, so a receiver groups packets by + synchronization source for playback. Examples of synchronization + sources include the sender of a stream of packets derived from a + signal source such as a microphone or a camera, or an RTP mixer + (see below). A synchronization source may change its data format, + e.g., audio encoding, over time. The SSRC identifier is a + randomly chosen value meant to be globally unique within a + particular RTP session (see Section 8). A participant need not + use the same SSRC identifier for all the RTP sessions in a + multimedia session; the binding of the SSRC identifiers is + provided through RTCP (see Section 6.5.1). If a participant + generates multiple streams in one RTP session, for example from + separate video cameras, each MUST be identified as a different + SSRC. + + Contributing source (CSRC): A source of a stream of RTP packets + that has contributed to the combined stream produced by an RTP + mixer (see below). The mixer inserts a list of the SSRC + identifiers of the sources that contributed to the generation of a + particular packet into the RTP header of that packet. This list + is called the CSRC list. An example application is audio + conferencing where a mixer indicates all the talkers whose speech + + + +Schulzrinne, et al. Standards Track [Page 10] + +RFC 3550 RTP July 2003 + + + was combined to produce the outgoing packet, allowing the receiver + to indicate the current talker, even though all the audio packets + contain the same SSRC identifier (that of the mixer). + + End system: An application that generates the content to be sent + in RTP packets and/or consumes the content of received RTP + packets. An end system can act as one or more synchronization + sources in a particular RTP session, but typically only one. + + Mixer: An intermediate system that receives RTP packets from one + or more sources, possibly changes the data format, combines the + packets in some manner and then forwards a new RTP packet. Since + the timing among multiple input sources will not generally be + synchronized, the mixer will make timing adjustments among the + streams and generate its own timing for the combined stream. + Thus, all data packets originating from a mixer will be identified + as having the mixer as their synchronization source. + + Translator: An intermediate system that forwards RTP packets + with their synchronization source identifier intact. Examples of + translators include devices that convert encodings without mixing, + replicators from multicast to unicast, and application-level + filters in firewalls. + + Monitor: An application that receives RTCP packets sent by + participants in an RTP session, in particular the reception + reports, and estimates the current quality of service for + distribution monitoring, fault diagnosis and long-term statistics. + The monitor function is likely to be built into the application(s) + participating in the session, but may also be a separate + application that does not otherwise participate and does not send + or receive the RTP data packets (since they are on a separate + port). These are called third-party monitors. It is also + acceptable for a third-party monitor to receive the RTP data + packets but not send RTCP packets or otherwise be counted in the + session. + + Non-RTP means: Protocols and mechanisms that may be needed in + addition to RTP to provide a usable service. In particular, for + multimedia conferences, a control protocol may distribute + multicast addresses and keys for encryption, negotiate the + encryption algorithm to be used, and define dynamic mappings + between RTP payload type values and the payload formats they + represent for formats that do not have a predefined payload type + value. Examples of such protocols include the Session Initiation + Protocol (SIP) (RFC 3261 [13]), ITU Recommendation H.323 [14] and + applications using SDP (RFC 2327 [15]), such as RTSP (RFC 2326 + [16]). For simple + + + +Schulzrinne, et al. Standards Track [Page 11] + +RFC 3550 RTP July 2003 + + + applications, electronic mail or a conference database may also be + used. The specification of such protocols and mechanisms is + outside the scope of this document. + +4. Byte Order, Alignment, and Time Format + + All integer fields are carried in network byte order, that is, most + significant byte (octet) first. This byte order is commonly known as + big-endian. The transmission order is described in detail in [3]. + Unless otherwise noted, numeric constants are in decimal (base 10). + + All header data is aligned to its natural length, i.e., 16-bit fields + are aligned on even offsets, 32-bit fields are aligned at offsets + divisible by four, etc. Octets designated as padding have the value + zero. + + Wallclock time (absolute date and time) is represented using the + timestamp format of the Network Time Protocol (NTP), which is in + seconds relative to 0h UTC on 1 January 1900 [4]. The full + resolution NTP timestamp is a 64-bit unsigned fixed-point number with + the integer part in the first 32 bits and the fractional part in the + last 32 bits. In some fields where a more compact representation is + appropriate, only the middle 32 bits are used; that is, the low 16 + bits of the integer part and the high 16 bits of the fractional part. + The high 16 bits of the integer part must be determined + independently. + + An implementation is not required to run the Network Time Protocol in + order to use RTP. Other time sources, or none at all, may be used + (see the description of the NTP timestamp field in Section 6.4.1). + However, running NTP may be useful for synchronizing streams + transmitted from separate hosts. + + The NTP timestamp will wrap around to zero some time in the year + 2036, but for RTP purposes, only differences between pairs of NTP + timestamps are used. So long as the pairs of timestamps can be + assumed to be within 68 years of each other, using modular arithmetic + for subtractions and comparisons makes the wraparound irrelevant. + + + + + + + + + + + + + +Schulzrinne, et al. Standards Track [Page 12] + +RFC 3550 RTP July 2003 + + +5. RTP Data Transfer Protocol + +5.1 RTP Fixed Header Fields + + The RTP header has the following format: + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V=2|P|X| CC |M| PT | sequence number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | timestamp | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | synchronization source (SSRC) identifier | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | contributing source (CSRC) identifiers | + | .... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The first twelve octets are present in every RTP packet, while the + list of CSRC identifiers is present only when inserted by a mixer. + The fields have the following meaning: + + version (V): 2 bits + This field identifies the version of RTP. The version defined by + this specification is two (2). (The value 1 is used by the first + draft version of RTP and the value 0 is used by the protocol + initially implemented in the "vat" audio tool.) + + padding (P): 1 bit + If the padding bit is set, the packet contains one or more + additional padding octets at the end which are not part of the + payload. The last octet of the padding contains a count of how + many padding octets should be ignored, including itself. Padding + may be needed by some encryption algorithms with fixed block sizes + or for carrying several RTP packets in a lower-layer protocol data + unit. + + extension (X): 1 bit + If the extension bit is set, the fixed header MUST be followed by + exactly one header extension, with a format defined in Section + 5.3.1. + + CSRC count (CC): 4 bits + The CSRC count contains the number of CSRC identifiers that follow + the fixed header. + + + + + +Schulzrinne, et al. Standards Track [Page 13] + +RFC 3550 RTP July 2003 + + + marker (M): 1 bit + The interpretation of the marker is defined by a profile. It is + intended to allow significant events such as frame boundaries to + be marked in the packet stream. A profile MAY define additional + marker bits or specify that there is no marker bit by changing the + number of bits in the payload type field (see Section 5.3). + + payload type (PT): 7 bits + This field identifies the format of the RTP payload and determines + its interpretation by the application. A profile MAY specify a + default static mapping of payload type codes to payload formats. + Additional payload type codes MAY be defined dynamically through + non-RTP means (see Section 3). A set of default mappings for + audio and video is specified in the companion RFC 3551 [1]. An + RTP source MAY change the payload type during a session, but this + field SHOULD NOT be used for multiplexing separate media streams + (see Section 5.2). + + A receiver MUST ignore packets with payload types that it does not + understand. + + sequence number: 16 bits + The sequence number increments by one for each RTP data packet + sent, and may be used by the receiver to detect packet loss and to + restore packet sequence. The initial value of the sequence number + SHOULD be random (unpredictable) to make known-plaintext attacks + on encryption more difficult, even if the source itself does not + encrypt according to the method in Section 9.1, because the + packets may flow through a translator that does. Techniques for + choosing unpredictable numbers are discussed in [17]. + + timestamp: 32 bits + The timestamp reflects the sampling instant of the first octet in + the RTP data packet. The sampling instant MUST be derived from a + clock that increments monotonically and linearly in time to allow + synchronization and jitter calculations (see Section 6.4.1). The + resolution of the clock MUST be sufficient for the desired + synchronization accuracy and for measuring packet arrival jitter + (one tick per video frame is typically not sufficient). The clock + frequency is dependent on the format of data carried as payload + and is specified statically in the profile or payload format + specification that defines the format, or MAY be specified + dynamically for payload formats defined through non-RTP means. If + RTP packets are generated periodically, the nominal sampling + instant as determined from the sampling clock is to be used, not a + reading of the system clock. As an example, for fixed-rate audio + the timestamp clock would likely increment by one for each + sampling period. If an audio application reads blocks covering + + + +Schulzrinne, et al. Standards Track [Page 14] + +RFC 3550 RTP July 2003 + + + 160 sampling periods from the input device, the timestamp would be + increased by 160 for each such block, regardless of whether the + block is transmitted in a packet or dropped as silent. + + The initial value of the timestamp SHOULD be random, as for the + sequence number. Several consecutive RTP packets will have equal + timestamps if they are (logically) generated at once, e.g., belong + to the same video frame. Consecutive RTP packets MAY contain + timestamps that are not monotonic if the data is not transmitted + in the order it was sampled, as in the case of MPEG interpolated + video frames. (The sequence numbers of the packets as transmitted + will still be monotonic.) + + RTP timestamps from different media streams may advance at + different rates and usually have independent, random offsets. + Therefore, although these timestamps are sufficient to reconstruct + the timing of a single stream, directly comparing RTP timestamps + from different media is not effective for synchronization. + Instead, for each medium the RTP timestamp is related to the + sampling instant by pairing it with a timestamp from a reference + clock (wallclock) that represents the time when the data + corresponding to the RTP timestamp was sampled. The reference + clock is shared by all media to be synchronized. The timestamp + pairs are not transmitted in every data packet, but at a lower + rate in RTCP SR packets as described in Section 6.4. + + The sampling instant is chosen as the point of reference for the + RTP timestamp because it is known to the transmitting endpoint and + has a common definition for all media, independent of encoding + delays or other processing. The purpose is to allow synchronized + presentation of all media sampled at the same time. + + Applications transmitting stored data rather than data sampled in + real time typically use a virtual presentation timeline derived + from wallclock time to determine when the next frame or other unit + of each medium in the stored data should be presented. In this + case, the RTP timestamp would reflect the presentation time for + each unit. That is, the RTP timestamp for each unit would be + related to the wallclock time at which the unit becomes current on + the virtual presentation timeline. Actual presentation occurs + some time later as determined by the receiver. + + An example describing live audio narration of prerecorded video + illustrates the significance of choosing the sampling instant as + the reference point. In this scenario, the video would be + presented locally for the narrator to view and would be + simultaneously transmitted using RTP. The "sampling instant" of a + video frame transmitted in RTP would be established by referencing + + + +Schulzrinne, et al. Standards Track [Page 15] + +RFC 3550 RTP July 2003 + + + its timestamp to the wallclock time when that video frame was + presented to the narrator. The sampling instant for the audio RTP + packets containing the narrator's speech would be established by + referencing the same wallclock time when the audio was sampled. + The audio and video may even be transmitted by different hosts if + the reference clocks on the two hosts are synchronized by some + means such as NTP. A receiver can then synchronize presentation + of the audio and video packets by relating their RTP timestamps + using the timestamp pairs in RTCP SR packets. + + SSRC: 32 bits + The SSRC field identifies the synchronization source. This + identifier SHOULD be chosen randomly, with the intent that no two + synchronization sources within the same RTP session will have the + same SSRC identifier. An example algorithm for generating a + random identifier is presented in Appendix A.6. Although the + probability of multiple sources choosing the same identifier is + low, all RTP implementations must be prepared to detect and + resolve collisions. Section 8 describes the probability of + collision along with a mechanism for resolving collisions and + detecting RTP-level forwarding loops based on the uniqueness of + the SSRC identifier. If a source changes its source transport + address, it must also choose a new SSRC identifier to avoid being + interpreted as a looped source (see Section 8.2). + + CSRC list: 0 to 15 items, 32 bits each + The CSRC list identifies the contributing sources for the payload + contained in this packet. The number of identifiers is given by + the CC field. If there are more than 15 contributing sources, + only 15 can be identified. CSRC identifiers are inserted by + mixers (see Section 7.1), using the SSRC identifiers of + contributing sources. For example, for audio packets the SSRC + identifiers of all sources that were mixed together to create a + packet are listed, allowing correct talker indication at the + receiver. + +5.2 Multiplexing RTP Sessions + + For efficient protocol processing, the number of multiplexing points + should be minimized, as described in the integrated layer processing + design principle [10]. In RTP, multiplexing is provided by the + destination transport address (network address and port number) which + is different for each RTP session. For example, in a teleconference + composed of audio and video media encoded separately, each medium + SHOULD be carried in a separate RTP session with its own destination + transport address. + + + + + +Schulzrinne, et al. Standards Track [Page 16] + +RFC 3550 RTP July 2003 + + + Separate audio and video streams SHOULD NOT be carried in a single + RTP session and demultiplexed based on the payload type or SSRC + fields. Interleaving packets with different RTP media types but + using the same SSRC would introduce several problems: + + 1. If, say, two audio streams shared the same RTP session and the + same SSRC value, and one were to change encodings and thus acquire + a different RTP payload type, there would be no general way of + identifying which stream had changed encodings. + + 2. An SSRC is defined to identify a single timing and sequence number + space. Interleaving multiple payload types would require + different timing spaces if the media clock rates differ and would + require different sequence number spaces to tell which payload + type suffered packet loss. + + 3. The RTCP sender and receiver reports (see Section 6.4) can only + describe one timing and sequence number space per SSRC and do not + carry a payload type field. + + 4. An RTP mixer would not be able to combine interleaved streams of + incompatible media into one stream. + + 5. Carrying multiple media in one RTP session precludes: the use of + different network paths or network resource allocations if + appropriate; reception of a subset of the media if desired, for + example just audio if video would exceed the available bandwidth; + and receiver implementations that use separate processes for the + different media, whereas using separate RTP sessions permits + either single- or multiple-process implementations. + + Using a different SSRC for each medium but sending them in the same + RTP session would avoid the first three problems but not the last + two. + + On the other hand, multiplexing multiple related sources of the same + medium in one RTP session using different SSRC values is the norm for + multicast sessions. The problems listed above don't apply: an RTP + mixer can combine multiple audio sources, for example, and the same + treatment is applicable for all of them. It may also be appropriate + to multiplex streams of the same medium using different SSRC values + in other scenarios where the last two problems do not apply. + + + + + + + + + +Schulzrinne, et al. Standards Track [Page 17] + +RFC 3550 RTP July 2003 + + +5.3 Profile-Specific Modifications to the RTP Header + + The existing RTP data packet header is believed to be complete for + the set of functions required in common across all the application + classes that RTP might support. However, in keeping with the ALF + design principle, the header MAY be tailored through modifications or + additions defined in a profile specification while still allowing + profile-independent monitoring and recording tools to function. + + o The marker bit and payload type field carry profile-specific + information, but they are allocated in the fixed header since many + applications are expected to need them and might otherwise have to + add another 32-bit word just to hold them. The octet containing + these fields MAY be redefined by a profile to suit different + requirements, for example with more or fewer marker bits. If + there are any marker bits, one SHOULD be located in the most + significant bit of the octet since profile-independent monitors + may be able to observe a correlation between packet loss patterns + and the marker bit. + + o Additional information that is required for a particular payload + format, such as a video encoding, SHOULD be carried in the payload + section of the packet. This might be in a header that is always + present at the start of the payload section, or might be indicated + by a reserved value in the data pattern. + + o If a particular class of applications needs additional + functionality independent of payload format, the profile under + which those applications operate SHOULD define additional fixed + fields to follow immediately after the SSRC field of the existing + fixed header. Those applications will be able to quickly and + directly access the additional fields while profile-independent + monitors or recorders can still process the RTP packets by + interpreting only the first twelve octets. + + If it turns out that additional functionality is needed in common + across all profiles, then a new version of RTP should be defined to + make a permanent change to the fixed header. + +5.3.1 RTP Header Extension + + An extension mechanism is provided to allow individual + implementations to experiment with new payload-format-independent + functions that require additional information to be carried in the + RTP data packet header. This mechanism is designed so that the + header extension may be ignored by other interoperating + implementations that have not been extended. + + + + +Schulzrinne, et al. Standards Track [Page 18] + +RFC 3550 RTP July 2003 + + + Note that this header extension is intended only for limited use. + Most potential uses of this mechanism would be better done another + way, using the methods described in the previous section. For + example, a profile-specific extension to the fixed header is less + expensive to process because it is not conditional nor in a variable + location. Additional information required for a particular payload + format SHOULD NOT use this header extension, but SHOULD be carried in + the payload section of the packet. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | defined by profile | length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | header extension | + | .... | + + If the X bit in the RTP header is one, a variable-length header + extension MUST be appended to the RTP header, following the CSRC list + if present. The header extension contains a 16-bit length field that + counts the number of 32-bit words in the extension, excluding the + four-octet extension header (therefore zero is a valid length). Only + a single extension can be appended to the RTP data header. To allow + multiple interoperating implementations to each experiment + independently with different header extensions, or to allow a + particular implementation to experiment with more than one type of + header extension, the first 16 bits of the header extension are left + open for distinguishing identifiers or parameters. The format of + these 16 bits is to be defined by the profile specification under + which the implementations are operating. This RTP specification does + not define any header extensions itself. + +6. RTP Control Protocol -- RTCP + + The RTP control protocol (RTCP) is based on the periodic transmission + of control packets to all participants in the session, using the same + distribution mechanism as the data packets. The underlying protocol + MUST provide multiplexing of the data and control packets, for + example using separate port numbers with UDP. RTCP performs four + functions: + + 1. The primary function is to provide feedback on the quality of the + data distribution. This is an integral part of the RTP's role as + a transport protocol and is related to the flow and congestion + control functions of other transport protocols (see Section 10 on + the requirement for congestion control). The feedback may be + directly useful for control of adaptive encodings [18,19], but + experiments with IP multicasting have shown that it is also + + + +Schulzrinne, et al. Standards Track [Page 19] + +RFC 3550 RTP July 2003 + + + critical to get feedback from the receivers to diagnose faults in + the distribution. Sending reception feedback reports to all + participants allows one who is observing problems to evaluate + whether those problems are local or global. With a distribution + mechanism like IP multicast, it is also possible for an entity + such as a network service provider who is not otherwise involved + in the session to receive the feedback information and act as a + third-party monitor to diagnose network problems. This feedback + function is performed by the RTCP sender and receiver reports, + described below in Section 6.4. + + 2. RTCP carries a persistent transport-level identifier for an RTP + source called the canonical name or CNAME, Section 6.5.1. Since + the SSRC identifier may change if a conflict is discovered or a + program is restarted, receivers require the CNAME to keep track of + each participant. Receivers may also require the CNAME to + associate multiple data streams from a given participant in a set + of related RTP sessions, for example to synchronize audio and + video. Inter-media synchronization also requires the NTP and RTP + timestamps included in RTCP packets by data senders. + + 3. The first two functions require that all participants send RTCP + packets, therefore the rate must be controlled in order for RTP to + scale up to a large number of participants. By having each + participant send its control packets to all the others, each can + independently observe the number of participants. This number is + used to calculate the rate at which the packets are sent, as + explained in Section 6.2. + + 4. A fourth, OPTIONAL function is to convey minimal session control + information, for example participant identification to be + displayed in the user interface. This is most likely to be useful + in "loosely controlled" sessions where participants enter and + leave without membership control or parameter negotiation. RTCP + serves as a convenient channel to reach all the participants, but + it is not necessarily expected to support all the control + communication requirements of an application. A higher-level + session control protocol, which is beyond the scope of this + document, may be needed. + + Functions 1-3 SHOULD be used in all environments, but particularly in + the IP multicast environment. RTP application designers SHOULD avoid + mechanisms that can only work in unicast mode and will not scale to + larger numbers. Transmission of RTCP MAY be controlled separately + for senders and receivers, as described in Section 6.2, for cases + such as unidirectional links where feedback from receivers is not + possible. + + + + +Schulzrinne, et al. Standards Track [Page 20] + +RFC 3550 RTP July 2003 + + + Non-normative note: In the multicast routing approach + called Source-Specific Multicast (SSM), there is only one sender + per "channel" (a source address, group address pair), and + receivers (except for the channel source) cannot use multicast to + communicate directly with other channel members. The + recommendations here accommodate SSM only through Section 6.2's + option of turning off receivers' RTCP entirely. Future work will + specify adaptation of RTCP for SSM so that feedback from receivers + can be maintained. + +6.1 RTCP Packet Format + + This specification defines several RTCP packet types to carry a + variety of control information: + + SR: Sender report, for transmission and reception statistics from + participants that are active senders + + RR: Receiver report, for reception statistics from participants + that are not active senders and in combination with SR for + active senders reporting on more than 31 sources + + SDES: Source description items, including CNAME + + BYE: Indicates end of participation + + APP: Application-specific functions + + Each RTCP packet begins with a fixed part similar to that of RTP data + packets, followed by structured elements that MAY be of variable + length according to the packet type but MUST end on a 32-bit + boundary. The alignment requirement and a length field in the fixed + part of each packet are included to make RTCP packets "stackable". + Multiple RTCP packets can be concatenated without any intervening + separators to form a compound RTCP packet that is sent in a single + packet of the lower layer protocol, for example UDP. There is no + explicit count of individual RTCP packets in the compound packet + since the lower layer protocols are expected to provide an overall + length to determine the end of the compound packet. + + Each individual RTCP packet in the compound packet may be processed + independently with no requirements upon the order or combination of + packets. However, in order to perform the functions of the protocol, + the following constraints are imposed: + + + + + + + +Schulzrinne, et al. Standards Track [Page 21] + +RFC 3550 RTP July 2003 + + + o Reception statistics (in SR or RR) should be sent as often as + bandwidth constraints will allow to maximize the resolution of the + statistics, therefore each periodically transmitted compound RTCP + packet MUST include a report packet. + + o New receivers need to receive the CNAME for a source as soon as + possible to identify the source and to begin associating media for + purposes such as lip-sync, so each compound RTCP packet MUST also + include the SDES CNAME except when the compound RTCP packet is + split for partial encryption as described in Section 9.1. + + o The number of packet types that may appear first in the compound + packet needs to be limited to increase the number of constant bits + in the first word and the probability of successfully validating + RTCP packets against misaddressed RTP data packets or other + unrelated packets. + + Thus, all RTCP packets MUST be sent in a compound packet of at least + two individual packets, with the following format: + + Encryption prefix: If and only if the compound packet is to be + encrypted according to the method in Section 9.1, it MUST be + prefixed by a random 32-bit quantity redrawn for every compound + packet transmitted. If padding is required for the encryption, it + MUST be added to the last packet of the compound packet. + + SR or RR: The first RTCP packet in the compound packet MUST + always be a report packet to facilitate header validation as + described in Appendix A.2. This is true even if no data has been + sent or received, in which case an empty RR MUST be sent, and even + if the only other RTCP packet in the compound packet is a BYE. + + Additional RRs: If the number of sources for which reception + statistics are being reported exceeds 31, the number that will fit + into one SR or RR packet, then additional RR packets SHOULD follow + the initial report packet. + + SDES: An SDES packet containing a CNAME item MUST be included + in each compound RTCP packet, except as noted in Section 9.1. + Other source description items MAY optionally be included if + required by a particular application, subject to bandwidth + constraints (see Section 6.3.9). + + BYE or APP: Other RTCP packet types, including those yet to be + defined, MAY follow in any order, except that BYE SHOULD be the + last packet sent with a given SSRC/CSRC. Packet types MAY appear + more than once. + + + + +Schulzrinne, et al. Standards Track [Page 22] + +RFC 3550 RTP July 2003 + + + An individual RTP participant SHOULD send only one compound RTCP + packet per report interval in order for the RTCP bandwidth per + participant to be estimated correctly (see Section 6.2), except when + the compound RTCP packet is split for partial encryption as described + in Section 9.1. If there are too many sources to fit all the + necessary RR packets into one compound RTCP packet without exceeding + the maximum transmission unit (MTU) of the network path, then only + the subset that will fit into one MTU SHOULD be included in each + interval. The subsets SHOULD be selected round-robin across multiple + intervals so that all sources are reported. + + It is RECOMMENDED that translators and mixers combine individual RTCP + packets from the multiple sources they are forwarding into one + compound packet whenever feasible in order to amortize the packet + overhead (see Section 7). An example RTCP compound packet as might + be produced by a mixer is shown in Fig. 1. If the overall length of + a compound packet would exceed the MTU of the network path, it SHOULD + be segmented into multiple shorter compound packets to be transmitted + in separate packets of the underlying protocol. This does not impair + the RTCP bandwidth estimation because each compound packet represents + at least one distinct participant. Note that each of the compound + packets MUST begin with an SR or RR packet. + + An implementation SHOULD ignore incoming RTCP packets with types + unknown to it. Additional RTCP packet types may be registered with + the Internet Assigned Numbers Authority (IANA) as described in + Section 15. + + if encrypted: random 32-bit integer + | + |[--------- packet --------][---------- packet ----------][-packet-] + | + | receiver chunk chunk + V reports item item item item + -------------------------------------------------------------------- + R[SR #sendinfo #site1#site2][SDES #CNAME PHONE #CNAME LOC][BYE##why] + -------------------------------------------------------------------- + | | + |<----------------------- compound packet ----------------------->| + |<-------------------------- UDP packet ------------------------->| + + #: SSRC/CSRC identifier + + Figure 1: Example of an RTCP compound packet + + + + + + + +Schulzrinne, et al. Standards Track [Page 23] + +RFC 3550 RTP July 2003 + + +6.2 RTCP Transmission Interval + + RTP is designed to allow an application to scale automatically over + session sizes ranging from a few participants to thousands. For + example, in an audio conference the data traffic is inherently self- + limiting because only one or two people will speak at a time, so with + multicast distribution the data rate on any given link remains + relatively constant independent of the number of participants. + However, the control traffic is not self-limiting. If the reception + reports from each participant were sent at a constant rate, the + control traffic would grow linearly with the number of participants. + Therefore, the rate must be scaled down by dynamically calculating + the interval between RTCP packet transmissions. + + For each session, it is assumed that the data traffic is subject to + an aggregate limit called the "session bandwidth" to be divided among + the participants. This bandwidth might be reserved and the limit + enforced by the network. If there is no reservation, there may be + other constraints, depending on the environment, that establish the + "reasonable" maximum for the session to use, and that would be the + session bandwidth. The session bandwidth may be chosen based on some + cost or a priori knowledge of the available network bandwidth for the + session. It is somewhat independent of the media encoding, but the + encoding choice may be limited by the session bandwidth. Often, the + session bandwidth is the sum of the nominal bandwidths of the senders + expected to be concurrently active. For teleconference audio, this + number would typically be one sender's bandwidth. For layered + encodings, each layer is a separate RTP session with its own session + bandwidth parameter. + + The session bandwidth parameter is expected to be supplied by a + session management application when it invokes a media application, + but media applications MAY set a default based on the single-sender + data bandwidth for the encoding selected for the session. The + application MAY also enforce bandwidth limits based on multicast + scope rules or other criteria. All participants MUST use the same + value for the session bandwidth so that the same RTCP interval will + be calculated. + + Bandwidth calculations for control and data traffic include lower- + layer transport and network protocols (e.g., UDP and IP) since that + is what the resource reservation system would need to know. The + application can also be expected to know which of these protocols are + in use. Link level headers are not included in the calculation since + the packet will be encapsulated with different link level headers as + it travels. + + + + + +Schulzrinne, et al. Standards Track [Page 24] + +RFC 3550 RTP July 2003 + + + The control traffic should be limited to a small and known fraction + of the session bandwidth: small so that the primary function of the + transport protocol to carry data is not impaired; known so that the + control traffic can be included in the bandwidth specification given + to a resource reservation protocol, and so that each participant can + independently calculate its share. The control traffic bandwidth is + in addition to the session bandwidth for the data traffic. It is + RECOMMENDED that the fraction of the session bandwidth added for RTCP + be fixed at 5%. It is also RECOMMENDED that 1/4 of the RTCP + bandwidth be dedicated to participants that are sending data so that + in sessions with a large number of receivers but a small number of + senders, newly joining participants will more quickly receive the + CNAME for the sending sites. When the proportion of senders is + greater than 1/4 of the participants, the senders get their + proportion of the full RTCP bandwidth. While the values of these and + other constants in the interval calculation are not critical, all + participants in the session MUST use the same values so the same + interval will be calculated. Therefore, these constants SHOULD be + fixed for a particular profile. + + A profile MAY specify that the control traffic bandwidth may be a + separate parameter of the session rather than a strict percentage of + the session bandwidth. Using a separate parameter allows rate- + adaptive applications to set an RTCP bandwidth consistent with a + "typical" data bandwidth that is lower than the maximum bandwidth + specified by the session bandwidth parameter. + + The profile MAY further specify that the control traffic bandwidth + may be divided into two separate session parameters for those + participants which are active data senders and those which are not; + let us call the parameters S and R. Following the recommendation + that 1/4 of the RTCP bandwidth be dedicated to data senders, the + RECOMMENDED default values for these two parameters would be 1.25% + and 3.75%, respectively. When the proportion of senders is greater + than S/(S+R) of the participants, the senders get their proportion of + the sum of these parameters. Using two parameters allows RTCP + reception reports to be turned off entirely for a particular session + by setting the RTCP bandwidth for non-data-senders to zero while + keeping the RTCP bandwidth for data senders non-zero so that sender + reports can still be sent for inter-media synchronization. Turning + off RTCP reception reports is NOT RECOMMENDED because they are needed + for the functions listed at the beginning of Section 6, particularly + reception quality feedback and congestion control. However, doing so + may be appropriate for systems operating on unidirectional links or + for sessions that don't require feedback on the quality of reception + or liveness of receivers and that have other means to avoid + congestion. + + + + +Schulzrinne, et al. Standards Track [Page 25] + +RFC 3550 RTP July 2003 + + + The calculated interval between transmissions of compound RTCP + packets SHOULD also have a lower bound to avoid having bursts of + packets exceed the allowed bandwidth when the number of participants + is small and the traffic isn't smoothed according to the law of large + numbers. It also keeps the report interval from becoming too small + during transient outages like a network partition such that + adaptation is delayed when the partition heals. At application + startup, a delay SHOULD be imposed before the first compound RTCP + packet is sent to allow time for RTCP packets to be received from + other participants so the report interval will converge to the + correct value more quickly. This delay MAY be set to half the + minimum interval to allow quicker notification that the new + participant is present. The RECOMMENDED value for a fixed minimum + interval is 5 seconds. + + An implementation MAY scale the minimum RTCP interval to a smaller + value inversely proportional to the session bandwidth parameter with + the following limitations: + + o For multicast sessions, only active data senders MAY use the + reduced minimum value to calculate the interval for transmission + of compound RTCP packets. + + o For unicast sessions, the reduced value MAY be used by + participants that are not active data senders as well, and the + delay before sending the initial compound RTCP packet MAY be zero. + + o For all sessions, the fixed minimum SHOULD be used when + calculating the participant timeout interval (see Section 6.3.5) + so that implementations which do not use the reduced value for + transmitting RTCP packets are not timed out by other participants + prematurely. + + o The RECOMMENDED value for the reduced minimum in seconds is 360 + divided by the session bandwidth in kilobits/second. This minimum + is smaller than 5 seconds for bandwidths greater than 72 kb/s. + + The algorithm described in Section 6.3 and Appendix A.7 was designed + to meet the goals outlined in this section. It calculates the + interval between sending compound RTCP packets to divide the allowed + control traffic bandwidth among the participants. This allows an + application to provide fast response for small sessions where, for + example, identification of all participants is important, yet + automatically adapt to large sessions. The algorithm incorporates + the following characteristics: + + + + + + +Schulzrinne, et al. Standards Track [Page 26] + +RFC 3550 RTP July 2003 + + + o The calculated interval between RTCP packets scales linearly with + the number of members in the group. It is this linear factor + which allows for a constant amount of control traffic when summed + across all members. + + o The interval between RTCP packets is varied randomly over the + range [0.5,1.5] times the calculated interval to avoid unintended + synchronization of all participants [20]. The first RTCP packet + sent after joining a session is also delayed by a random variation + of half the minimum RTCP interval. + + o A dynamic estimate of the average compound RTCP packet size is + calculated, including all those packets received and sent, to + automatically adapt to changes in the amount of control + information carried. + + o Since the calculated interval is dependent on the number of + observed group members, there may be undesirable startup effects + when a new user joins an existing session, or many users + simultaneously join a new session. These new users will initially + have incorrect estimates of the group membership, and thus their + RTCP transmission interval will be too short. This problem can be + significant if many users join the session simultaneously. To + deal with this, an algorithm called "timer reconsideration" is + employed. This algorithm implements a simple back-off mechanism + which causes users to hold back RTCP packet transmission if the + group sizes are increasing. + + o When users leave a session, either with a BYE or by timeout, the + group membership decreases, and thus the calculated interval + should decrease. A "reverse reconsideration" algorithm is used to + allow members to more quickly reduce their intervals in response + to group membership decreases. + + o BYE packets are given different treatment than other RTCP packets. + When a user leaves a group, and wishes to send a BYE packet, it + may do so before its next scheduled RTCP packet. However, + transmission of BYEs follows a back-off algorithm which avoids + floods of BYE packets should a large number of members + simultaneously leave the session. + + This algorithm may be used for sessions in which all participants are + allowed to send. In that case, the session bandwidth parameter is + the product of the individual sender's bandwidth times the number of + participants, and the RTCP bandwidth is 5% of that. + + Details of the algorithm's operation are given in the sections that + follow. Appendix A.7 gives an example implementation. + + + +Schulzrinne, et al. Standards Track [Page 27] + +RFC 3550 RTP July 2003 + + +6.2.1 Maintaining the Number of Session Members + + Calculation of the RTCP packet interval depends upon an estimate of + the number of sites participating in the session. New sites are + added to the count when they are heard, and an entry for each SHOULD + be created in a table indexed by the SSRC or CSRC identifier (see + Section 8.2) to keep track of them. New entries MAY be considered + not valid until multiple packets carrying the new SSRC have been + received (see Appendix A.1), or until an SDES RTCP packet containing + a CNAME for that SSRC has been received. Entries MAY be deleted from + the table when an RTCP BYE packet with the corresponding SSRC + identifier is received, except that some straggler data packets might + arrive after the BYE and cause the entry to be recreated. Instead, + the entry SHOULD be marked as having received a BYE and then deleted + after an appropriate delay. + + A participant MAY mark another site inactive, or delete it if not yet + valid, if no RTP or RTCP packet has been received for a small number + of RTCP report intervals (5 is RECOMMENDED). This provides some + robustness against packet loss. All sites must have the same value + for this multiplier and must calculate roughly the same value for the + RTCP report interval in order for this timeout to work properly. + Therefore, this multiplier SHOULD be fixed for a particular profile. + + For sessions with a very large number of participants, it may be + impractical to maintain a table to store the SSRC identifier and + state information for all of them. An implementation MAY use SSRC + sampling, as described in [21], to reduce the storage requirements. + An implementation MAY use any other algorithm with similar + performance. A key requirement is that any algorithm considered + SHOULD NOT substantially underestimate the group size, although it + MAY overestimate. + +6.3 RTCP Packet Send and Receive Rules + + The rules for how to send, and what to do when receiving an RTCP + packet are outlined here. An implementation that allows operation in + a multicast environment or a multipoint unicast environment MUST meet + the requirements in Section 6.2. Such an implementation MAY use the + algorithm defined in this section to meet those requirements, or MAY + use some other algorithm so long as it provides equivalent or better + performance. An implementation which is constrained to two-party + unicast operation SHOULD still use randomization of the RTCP + transmission interval to avoid unintended synchronization of multiple + instances operating in the same environment, but MAY omit the "timer + reconsideration" and "reverse reconsideration" algorithms in Sections + 6.3.3, 6.3.6 and 6.3.7. + + + + +Schulzrinne, et al. Standards Track [Page 28] + +RFC 3550 RTP July 2003 + + + To execute these rules, a session participant must maintain several + pieces of state: + + tp: the last time an RTCP packet was transmitted; + + tc: the current time; + + tn: the next scheduled transmission time of an RTCP packet; + + pmembers: the estimated number of session members at the time tn + was last recomputed; + + members: the most current estimate for the number of session + members; + + senders: the most current estimate for the number of senders in + the session; + + rtcp_bw: The target RTCP bandwidth, i.e., the total bandwidth + that will be used for RTCP packets by all members of this session, + in octets per second. This will be a specified fraction of the + "session bandwidth" parameter supplied to the application at + startup. + + we_sent: Flag that is true if the application has sent data + since the 2nd previous RTCP report was transmitted. + + avg_rtcp_size: The average compound RTCP packet size, in octets, + over all RTCP packets sent and received by this participant. The + size includes lower-layer transport and network protocol headers + (e.g., UDP and IP) as explained in Section 6.2. + + initial: Flag that is true if the application has not yet sent + an RTCP packet. + + Many of these rules make use of the "calculated interval" between + packet transmissions. This interval is described in the following + section. + +6.3.1 Computing the RTCP Transmission Interval + + To maintain scalability, the average interval between packets from a + session participant should scale with the group size. This interval + is called the calculated interval. It is obtained by combining a + number of the pieces of state described above. The calculated + interval T is then determined as follows: + + + + + +Schulzrinne, et al. Standards Track [Page 29] + +RFC 3550 RTP July 2003 + + + 1. If the number of senders is less than or equal to 25% of the + membership (members), the interval depends on whether the + participant is a sender or not (based on the value of we_sent). + If the participant is a sender (we_sent true), the constant C is + set to the average RTCP packet size (avg_rtcp_size) divided by 25% + of the RTCP bandwidth (rtcp_bw), and the constant n is set to the + number of senders. If we_sent is not true, the constant C is set + to the average RTCP packet size divided by 75% of the RTCP + bandwidth. The constant n is set to the number of receivers + (members - senders). If the number of senders is greater than + 25%, senders and receivers are treated together. The constant C + is set to the average RTCP packet size divided by the total RTCP + bandwidth and n is set to the total number of members. As stated + in Section 6.2, an RTP profile MAY specify that the RTCP bandwidth + may be explicitly defined by two separate parameters (call them S + and R) for those participants which are senders and those which + are not. In that case, the 25% fraction becomes S/(S+R) and the + 75% fraction becomes R/(S+R). Note that if R is zero, the + percentage of senders is never greater than S/(S+R), and the + implementation must avoid division by zero. + + 2. If the participant has not yet sent an RTCP packet (the variable + initial is true), the constant Tmin is set to 2.5 seconds, else it + is set to 5 seconds. + + 3. The deterministic calculated interval Td is set to max(Tmin, n*C). + + 4. The calculated interval T is set to a number uniformly distributed + between 0.5 and 1.5 times the deterministic calculated interval. + + 5. The resulting value of T is divided by e-3/2=1.21828 to compensate + for the fact that the timer reconsideration algorithm converges to + a value of the RTCP bandwidth below the intended average. + + This procedure results in an interval which is random, but which, on + average, gives at least 25% of the RTCP bandwidth to senders and the + rest to receivers. If the senders constitute more than one quarter + of the membership, this procedure splits the bandwidth equally among + all participants, on average. + +6.3.2 Initialization + + Upon joining the session, the participant initializes tp to 0, tc to + 0, senders to 0, pmembers to 1, members to 1, we_sent to false, + rtcp_bw to the specified fraction of the session bandwidth, initial + to true, and avg_rtcp_size to the probable size of the first RTCP + packet that the application will later construct. The calculated + interval T is then computed, and the first packet is scheduled for + + + +Schulzrinne, et al. Standards Track [Page 30] + +RFC 3550 RTP July 2003 + + + time tn = T. This means that a transmission timer is set which + expires at time T. Note that an application MAY use any desired + approach for implementing this timer. + + The participant adds its own SSRC to the member table. + +6.3.3 Receiving an RTP or Non-BYE RTCP Packet + + When an RTP or RTCP packet is received from a participant whose SSRC + is not in the member table, the SSRC is added to the table, and the + value for members is updated once the participant has been validated + as described in Section 6.2.1. The same processing occurs for each + CSRC in a validated RTP packet. + + When an RTP packet is received from a participant whose SSRC is not + in the sender table, the SSRC is added to the table, and the value + for senders is updated. + + For each compound RTCP packet received, the value of avg_rtcp_size is + updated: + + avg_rtcp_size = (1/16) * packet_size + (15/16) * avg_rtcp_size + + where packet_size is the size of the RTCP packet just received. + +6.3.4 Receiving an RTCP BYE Packet + + Except as described in Section 6.3.7 for the case when an RTCP BYE is + to be transmitted, if the received packet is an RTCP BYE packet, the + SSRC is checked against the member table. If present, the entry is + removed from the table, and the value for members is updated. The + SSRC is then checked against the sender table. If present, the entry + is removed from the table, and the value for senders is updated. + + Furthermore, to make the transmission rate of RTCP packets more + adaptive to changes in group membership, the following "reverse + reconsideration" algorithm SHOULD be executed when a BYE packet is + received that reduces members to a value less than pmembers: + + o The value for tn is updated according to the following formula: + + tn = tc + (members/pmembers) * (tn - tc) + + o The value for tp is updated according the following formula: + + tp = tc - (members/pmembers) * (tc - tp). + + + + + +Schulzrinne, et al. Standards Track [Page 31] + +RFC 3550 RTP July 2003 + + + o The next RTCP packet is rescheduled for transmission at time tn, + which is now earlier. + + o The value of pmembers is set equal to members. + + This algorithm does not prevent the group size estimate from + incorrectly dropping to zero for a short time due to premature + timeouts when most participants of a large session leave at once but + some remain. The algorithm does make the estimate return to the + correct value more rapidly. This situation is unusual enough and the + consequences are sufficiently harmless that this problem is deemed + only a secondary concern. + +6.3.5 Timing Out an SSRC + + At occasional intervals, the participant MUST check to see if any of + the other participants time out. To do this, the participant + computes the deterministic (without the randomization factor) + calculated interval Td for a receiver, that is, with we_sent false. + Any other session member who has not sent an RTP or RTCP packet since + time tc - MTd (M is the timeout multiplier, and defaults to 5) is + timed out. This means that its SSRC is removed from the member list, + and members is updated. A similar check is performed on the sender + list. Any member on the sender list who has not sent an RTP packet + since time tc - 2T (within the last two RTCP report intervals) is + removed from the sender list, and senders is updated. + + If any members time out, the reverse reconsideration algorithm + described in Section 6.3.4 SHOULD be performed. + + The participant MUST perform this check at least once per RTCP + transmission interval. + +6.3.6 Expiration of Transmission Timer + + When the packet transmission timer expires, the participant performs + the following operations: + + o The transmission interval T is computed as described in Section + 6.3.1, including the randomization factor. + + o If tp + T is less than or equal to tc, an RTCP packet is + transmitted. tp is set to tc, then another value for T is + calculated as in the previous step and tn is set to tc + T. The + transmission timer is set to expire again at time tn. If tp + T + is greater than tc, tn is set to tp + T. No RTCP packet is + transmitted. The transmission timer is set to expire at time tn. + + + + +Schulzrinne, et al. Standards Track [Page 32] + +RFC 3550 RTP July 2003 + + + o pmembers is set to members. + + If an RTCP packet is transmitted, the value of initial is set to + FALSE. Furthermore, the value of avg_rtcp_size is updated: + + avg_rtcp_size = (1/16) * packet_size + (15/16) * avg_rtcp_size + + where packet_size is the size of the RTCP packet just transmitted. + +6.3.7 Transmitting a BYE Packet + + When a participant wishes to leave a session, a BYE packet is + transmitted to inform the other participants of the event. In order + to avoid a flood of BYE packets when many participants leave the + system, a participant MUST execute the following algorithm if the + number of members is more than 50 when the participant chooses to + leave. This algorithm usurps the normal role of the members variable + to count BYE packets instead: + + o When the participant decides to leave the system, tp is reset to + tc, the current time, members and pmembers are initialized to 1, + initial is set to 1, we_sent is set to false, senders is set to 0, + and avg_rtcp_size is set to the size of the compound BYE packet. + The calculated interval T is computed. The BYE packet is then + scheduled for time tn = tc + T. + + o Every time a BYE packet from another participant is received, + members is incremented by 1 regardless of whether that participant + exists in the member table or not, and when SSRC sampling is in + use, regardless of whether or not the BYE SSRC would be included + in the sample. members is NOT incremented when other RTCP packets + or RTP packets are received, but only for BYE packets. Similarly, + avg_rtcp_size is updated only for received BYE packets. senders + is NOT updated when RTP packets arrive; it remains 0. + + o Transmission of the BYE packet then follows the rules for + transmitting a regular RTCP packet, as above. + + This allows BYE packets to be sent right away, yet controls their + total bandwidth usage. In the worst case, this could cause RTCP + control packets to use twice the bandwidth as normal (10%) -- 5% for + non-BYE RTCP packets and 5% for BYE. + + A participant that does not want to wait for the above mechanism to + allow transmission of a BYE packet MAY leave the group without + sending a BYE at all. That participant will eventually be timed out + by the other group members. + + + + +Schulzrinne, et al. Standards Track [Page 33] + +RFC 3550 RTP July 2003 + + + If the group size estimate members is less than 50 when the + participant decides to leave, the participant MAY send a BYE packet + immediately. Alternatively, the participant MAY choose to execute + the above BYE backoff algorithm. + + In either case, a participant which never sent an RTP or RTCP packet + MUST NOT send a BYE packet when they leave the group. + +6.3.8 Updating we_sent + + The variable we_sent contains true if the participant has sent an RTP + packet recently, false otherwise. This determination is made by + using the same mechanisms as for managing the set of other + participants listed in the senders table. If the participant sends + an RTP packet when we_sent is false, it adds itself to the sender + table and sets we_sent to true. The reverse reconsideration + algorithm described in Section 6.3.4 SHOULD be performed to possibly + reduce the delay before sending an SR packet. Every time another RTP + packet is sent, the time of transmission of that packet is maintained + in the table. The normal sender timeout algorithm is then applied to + the participant -- if an RTP packet has not been transmitted since + time tc - 2T, the participant removes itself from the sender table, + decrements the sender count, and sets we_sent to false. + +6.3.9 Allocation of Source Description Bandwidth + + This specification defines several source description (SDES) items in + addition to the mandatory CNAME item, such as NAME (personal name) + and EMAIL (email address). It also provides a means to define new + application-specific RTCP packet types. Applications should exercise + caution in allocating control bandwidth to this additional + information because it will slow down the rate at which reception + reports and CNAME are sent, thus impairing the performance of the + protocol. It is RECOMMENDED that no more than 20% of the RTCP + bandwidth allocated to a single participant be used to carry the + additional information. Furthermore, it is not intended that all + SDES items will be included in every application. Those that are + included SHOULD be assigned a fraction of the bandwidth according to + their utility. Rather than estimate these fractions dynamically, it + is recommended that the percentages be translated statically into + report interval counts based on the typical length of an item. + + For example, an application may be designed to send only CNAME, NAME + and EMAIL and not any others. NAME might be given much higher + priority than EMAIL because the NAME would be displayed continuously + in the application's user interface, whereas EMAIL would be displayed + only when requested. At every RTCP interval, an RR packet and an + SDES packet with the CNAME item would be sent. For a small session + + + +Schulzrinne, et al. Standards Track [Page 34] + +RFC 3550 RTP July 2003 + + + operating at the minimum interval, that would be every 5 seconds on + the average. Every third interval (15 seconds), one extra item would + be included in the SDES packet. Seven out of eight times this would + be the NAME item, and every eighth time (2 minutes) it would be the + EMAIL item. + + When multiple applications operate in concert using cross-application + binding through a common CNAME for each participant, for example in a + multimedia conference composed of an RTP session for each medium, the + additional SDES information MAY be sent in only one RTP session. The + other sessions would carry only the CNAME item. In particular, this + approach should be applied to the multiple sessions of a layered + encoding scheme (see Section 2.4). + +6.4 Sender and Receiver Reports + + RTP receivers provide reception quality feedback using RTCP report + packets which may take one of two forms depending upon whether or not + the receiver is also a sender. The only difference between the + sender report (SR) and receiver report (RR) forms, besides the packet + type code, is that the sender report includes a 20-byte sender + information section for use by active senders. The SR is issued if a + site has sent any data packets during the interval since issuing the + last report or the previous one, otherwise the RR is issued. + + Both the SR and RR forms include zero or more reception report + blocks, one for each of the synchronization sources from which this + receiver has received RTP data packets since the last report. + Reports are not issued for contributing sources listed in the CSRC + list. Each reception report block provides statistics about the data + received from the particular source indicated in that block. Since a + maximum of 31 reception report blocks will fit in an SR or RR packet, + additional RR packets SHOULD be stacked after the initial SR or RR + packet as needed to contain the reception reports for all sources + heard during the interval since the last report. If there are too + many sources to fit all the necessary RR packets into one compound + RTCP packet without exceeding the MTU of the network path, then only + the subset that will fit into one MTU SHOULD be included in each + interval. The subsets SHOULD be selected round-robin across multiple + intervals so that all sources are reported. + + The next sections define the formats of the two reports, how they may + be extended in a profile-specific manner if an application requires + additional feedback information, and how the reports may be used. + Details of reception reporting by translators and mixers is given in + Section 7. + + + + + +Schulzrinne, et al. Standards Track [Page 35] + +RFC 3550 RTP July 2003 + + +6.4.1 SR: Sender Report RTCP Packet + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +header |V=2|P| RC | PT=SR=200 | length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SSRC of sender | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +sender | NTP timestamp, most significant word | +info +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | NTP timestamp, least significant word | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | RTP timestamp | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | sender's packet count | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | sender's octet count | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +report | SSRC_1 (SSRC of first source) | +block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 1 | fraction lost | cumulative number of packets lost | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | extended highest sequence number received | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | interarrival jitter | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | last SR (LSR) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | delay since last SR (DLSR) | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +report | SSRC_2 (SSRC of second source) | +block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 2 : ... : + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | profile-specific extensions | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The sender report packet consists of three sections, possibly + followed by a fourth profile-specific extension section if defined. + The first section, the header, is 8 octets long. The fields have the + following meaning: + + version (V): 2 bits + Identifies the version of RTP, which is the same in RTCP packets + as in RTP data packets. The version defined by this specification + is two (2). + + + + +Schulzrinne, et al. Standards Track [Page 36] + +RFC 3550 RTP July 2003 + + + padding (P): 1 bit + If the padding bit is set, this individual RTCP packet contains + some additional padding octets at the end which are not part of + the control information but are included in the length field. The + last octet of the padding is a count of how many padding octets + should be ignored, including itself (it will be a multiple of + four). Padding may be needed by some encryption algorithms with + fixed block sizes. In a compound RTCP packet, padding is only + required on one individual packet because the compound packet is + encrypted as a whole for the method in Section 9.1. Thus, padding + MUST only be added to the last individual packet, and if padding + is added to that packet, the padding bit MUST be set only on that + packet. This convention aids the header validity checks described + in Appendix A.2 and allows detection of packets from some early + implementations that incorrectly set the padding bit on the first + individual packet and add padding to the last individual packet. + + reception report count (RC): 5 bits + The number of reception report blocks contained in this packet. A + value of zero is valid. + + packet type (PT): 8 bits + Contains the constant 200 to identify this as an RTCP SR packet. + + length: 16 bits + The length of this RTCP packet in 32-bit words minus one, + including the header and any padding. (The offset of one makes + zero a valid length and avoids a possible infinite loop in + scanning a compound RTCP packet, while counting 32-bit words + avoids a validity check for a multiple of 4.) + + SSRC: 32 bits + The synchronization source identifier for the originator of this + SR packet. + + The second section, the sender information, is 20 octets long and is + present in every sender report packet. It summarizes the data + transmissions from this sender. The fields have the following + meaning: + + NTP timestamp: 64 bits + Indicates the wallclock time (see Section 4) when this report was + sent so that it may be used in combination with timestamps + returned in reception reports from other receivers to measure + round-trip propagation to those receivers. Receivers should + expect that the measurement accuracy of the timestamp may be + limited to far less than the resolution of the NTP timestamp. The + measurement uncertainty of the timestamp is not indicated as it + + + +Schulzrinne, et al. Standards Track [Page 37] + +RFC 3550 RTP July 2003 + + + may not be known. On a system that has no notion of wallclock + time but does have some system-specific clock such as "system + uptime", a sender MAY use that clock as a reference to calculate + relative NTP timestamps. It is important to choose a commonly + used clock so that if separate implementations are used to produce + the individual streams of a multimedia session, all + implementations will use the same clock. Until the year 2036, + relative and absolute timestamps will differ in the high bit so + (invalid) comparisons will show a large difference; by then one + hopes relative timestamps will no longer be needed. A sender that + has no notion of wallclock or elapsed time MAY set the NTP + timestamp to zero. + + RTP timestamp: 32 bits + Corresponds to the same time as the NTP timestamp (above), but in + the same units and with the same random offset as the RTP + timestamps in data packets. This correspondence may be used for + intra- and inter-media synchronization for sources whose NTP + timestamps are synchronized, and may be used by media-independent + receivers to estimate the nominal RTP clock frequency. Note that + in most cases this timestamp will not be equal to the RTP + timestamp in any adjacent data packet. Rather, it MUST be + calculated from the corresponding NTP timestamp using the + relationship between the RTP timestamp counter and real time as + maintained by periodically checking the wallclock time at a + sampling instant. + + sender's packet count: 32 bits + The total number of RTP data packets transmitted by the sender + since starting transmission up until the time this SR packet was + generated. The count SHOULD be reset if the sender changes its + SSRC identifier. + + sender's octet count: 32 bits + The total number of payload octets (i.e., not including header or + padding) transmitted in RTP data packets by the sender since + starting transmission up until the time this SR packet was + generated. The count SHOULD be reset if the sender changes its + SSRC identifier. This field can be used to estimate the average + payload data rate. + + The third section contains zero or more reception report blocks + depending on the number of other sources heard by this sender since + the last report. Each reception report block conveys statistics on + the reception of RTP packets from a single synchronization source. + Receivers SHOULD NOT carry over statistics when a source changes its + SSRC identifier due to a collision. These statistics are: + + + + +Schulzrinne, et al. Standards Track [Page 38] + +RFC 3550 RTP July 2003 + + + SSRC_n (source identifier): 32 bits + The SSRC identifier of the source to which the information in this + reception report block pertains. + + fraction lost: 8 bits + The fraction of RTP data packets from source SSRC_n lost since the + previous SR or RR packet was sent, expressed as a fixed point + number with the binary point at the left edge of the field. (That + is equivalent to taking the integer part after multiplying the + loss fraction by 256.) This fraction is defined to be the number + of packets lost divided by the number of packets expected, as + defined in the next paragraph. An implementation is shown in + Appendix A.3. If the loss is negative due to duplicates, the + fraction lost is set to zero. Note that a receiver cannot tell + whether any packets were lost after the last one received, and + that there will be no reception report block issued for a source + if all packets from that source sent during the last reporting + interval have been lost. + + cumulative number of packets lost: 24 bits + The total number of RTP data packets from source SSRC_n that have + been lost since the beginning of reception. This number is + defined to be the number of packets expected less the number of + packets actually received, where the number of packets received + includes any which are late or duplicates. Thus, packets that + arrive late are not counted as lost, and the loss may be negative + if there are duplicates. The number of packets expected is + defined to be the extended last sequence number received, as + defined next, less the initial sequence number received. This may + be calculated as shown in Appendix A.3. + + extended highest sequence number received: 32 bits + The low 16 bits contain the highest sequence number received in an + RTP data packet from source SSRC_n, and the most significant 16 + bits extend that sequence number with the corresponding count of + sequence number cycles, which may be maintained according to the + algorithm in Appendix A.1. Note that different receivers within + the same session will generate different extensions to the + sequence number if their start times differ significantly. + + interarrival jitter: 32 bits + An estimate of the statistical variance of the RTP data packet + interarrival time, measured in timestamp units and expressed as an + unsigned integer. The interarrival jitter J is defined to be the + mean deviation (smoothed absolute value) of the difference D in + packet spacing at the receiver compared to the sender for a pair + of packets. As shown in the equation below, this is equivalent to + the difference in the "relative transit time" for the two packets; + + + +Schulzrinne, et al. Standards Track [Page 39] + +RFC 3550 RTP July 2003 + + + the relative transit time is the difference between a packet's RTP + timestamp and the receiver's clock at the time of arrival, + measured in the same units. + + If Si is the RTP timestamp from packet i, and Ri is the time of + arrival in RTP timestamp units for packet i, then for two packets + i and j, D may be expressed as + + D(i,j) = (Rj - Ri) - (Sj - Si) = (Rj - Sj) - (Ri - Si) + + The interarrival jitter SHOULD be calculated continuously as each + data packet i is received from source SSRC_n, using this + difference D for that packet and the previous packet i-1 in order + of arrival (not necessarily in sequence), according to the formula + + J(i) = J(i-1) + (|D(i-1,i)| - J(i-1))/16 + + Whenever a reception report is issued, the current value of J is + sampled. + + The jitter calculation MUST conform to the formula specified here + in order to allow profile-independent monitors to make valid + interpretations of reports coming from different implementations. + This algorithm is the optimal first-order estimator and the gain + parameter 1/16 gives a good noise reduction ratio while + maintaining a reasonable rate of convergence [22]. A sample + implementation is shown in Appendix A.8. See Section 6.4.4 for a + discussion of the effects of varying packet duration and delay + before transmission. + + last SR timestamp (LSR): 32 bits + The middle 32 bits out of 64 in the NTP timestamp (as explained in + Section 4) received as part of the most recent RTCP sender report + (SR) packet from source SSRC_n. If no SR has been received yet, + the field is set to zero. + + delay since last SR (DLSR): 32 bits + The delay, expressed in units of 1/65536 seconds, between + receiving the last SR packet from source SSRC_n and sending this + reception report block. If no SR packet has been received yet + from SSRC_n, the DLSR field is set to zero. + + Let SSRC_r denote the receiver issuing this receiver report. + Source SSRC_n can compute the round-trip propagation delay to + SSRC_r by recording the time A when this reception report block is + received. It calculates the total round-trip time A-LSR using the + last SR timestamp (LSR) field, and then subtracting this field to + leave the round-trip propagation delay as (A - LSR - DLSR). This + + + +Schulzrinne, et al. Standards Track [Page 40] + +RFC 3550 RTP July 2003 + + + is illustrated in Fig. 2. Times are shown in both a hexadecimal + representation of the 32-bit fields and the equivalent floating- + point decimal representation. Colons indicate a 32-bit field + divided into a 16-bit integer part and 16-bit fraction part. + + This may be used as an approximate measure of distance to cluster + receivers, although some links have very asymmetric delays. + + [10 Nov 1995 11:33:25.125 UTC] [10 Nov 1995 11:33:36.5 UTC] + n SR(n) A=b710:8000 (46864.500 s) + ----------------------------------------------------------------> + v ^ + ntp_sec =0xb44db705 v ^ dlsr=0x0005:4000 ( 5.250s) + ntp_frac=0x20000000 v ^ lsr =0xb705:2000 (46853.125s) + (3024992005.125 s) v ^ + r v ^ RR(n) + ----------------------------------------------------------------> + |<-DLSR->| + (5.250 s) + + A 0xb710:8000 (46864.500 s) + DLSR -0x0005:4000 ( 5.250 s) + LSR -0xb705:2000 (46853.125 s) + ------------------------------- + delay 0x0006:2000 ( 6.125 s) + + Figure 2: Example for round-trip time computation + + + + + + + + + + + + + + + + + + + + + + + + +Schulzrinne, et al. Standards Track [Page 41] + +RFC 3550 RTP July 2003 + + +6.4.2 RR: Receiver Report RTCP Packet + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +header |V=2|P| RC | PT=RR=201 | length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SSRC of packet sender | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +report | SSRC_1 (SSRC of first source) | +block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 1 | fraction lost | cumulative number of packets lost | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | extended highest sequence number received | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | interarrival jitter | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | last SR (LSR) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | delay since last SR (DLSR) | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +report | SSRC_2 (SSRC of second source) | +block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 2 : ... : + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | profile-specific extensions | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The format of the receiver report (RR) packet is the same as that of + the SR packet except that the packet type field contains the constant + 201 and the five words of sender information are omitted (these are + the NTP and RTP timestamps and sender's packet and octet counts). + The remaining fields have the same meaning as for the SR packet. + + An empty RR packet (RC = 0) MUST be put at the head of a compound + RTCP packet when there is no data transmission or reception to + report. + +6.4.3 Extending the Sender and Receiver Reports + + A profile SHOULD define profile-specific extensions to the sender + report and receiver report if there is additional information that + needs to be reported regularly about the sender or receivers. This + method SHOULD be used in preference to defining another RTCP packet + type because it requires less overhead: + + o fewer octets in the packet (no RTCP header or SSRC field); + + + + +Schulzrinne, et al. Standards Track [Page 42] + +RFC 3550 RTP July 2003 + + + o simpler and faster parsing because applications running under that + profile would be programmed to always expect the extension fields + in the directly accessible location after the reception reports. + + The extension is a fourth section in the sender- or receiver-report + packet which comes at the end after the reception report blocks, if + any. If additional sender information is required, then for sender + reports it would be included first in the extension section, but for + receiver reports it would not be present. If information about + receivers is to be included, that data SHOULD be structured as an + array of blocks parallel to the existing array of reception report + blocks; that is, the number of blocks would be indicated by the RC + field. + +6.4.4 Analyzing Sender and Receiver Reports + + It is expected that reception quality feedback will be useful not + only for the sender but also for other receivers and third-party + monitors. The sender may modify its transmissions based on the + feedback; receivers can determine whether problems are local, + regional or global; network managers may use profile-independent + monitors that receive only the RTCP packets and not the corresponding + RTP data packets to evaluate the performance of their networks for + multicast distribution. + + Cumulative counts are used in both the sender information and + receiver report blocks so that differences may be calculated between + any two reports to make measurements over both short and long time + periods, and to provide resilience against the loss of a report. The + difference between the last two reports received can be used to + estimate the recent quality of the distribution. The NTP timestamp + is included so that rates may be calculated from these differences + over the interval between two reports. Since that timestamp is + independent of the clock rate for the data encoding, it is possible + to implement encoding- and profile-independent quality monitors. + + An example calculation is the packet loss rate over the interval + between two reception reports. The difference in the cumulative + number of packets lost gives the number lost during that interval. + The difference in the extended last sequence numbers received gives + the number of packets expected during the interval. The ratio of + these two is the packet loss fraction over the interval. This ratio + should equal the fraction lost field if the two reports are + consecutive, but otherwise it may not. The loss rate per second can + be obtained by dividing the loss fraction by the difference in NTP + timestamps, expressed in seconds. The number of packets received is + the number of packets expected minus the number lost. The number of + + + + +Schulzrinne, et al. Standards Track [Page 43] + +RFC 3550 RTP July 2003 + + + packets expected may also be used to judge the statistical validity + of any loss estimates. For example, 1 out of 5 packets lost has a + lower significance than 200 out of 1000. + + From the sender information, a third-party monitor can calculate the + average payload data rate and the average packet rate over an + interval without receiving the data. Taking the ratio of the two + gives the average payload size. If it can be assumed that packet + loss is independent of packet size, then the number of packets + received by a particular receiver times the average payload size (or + the corresponding packet size) gives the apparent throughput + available to that receiver. + + In addition to the cumulative counts which allow long-term packet + loss measurements using differences between reports, the fraction + lost field provides a short-term measurement from a single report. + This becomes more important as the size of a session scales up enough + that reception state information might not be kept for all receivers + or the interval between reports becomes long enough that only one + report might have been received from a particular receiver. + + The interarrival jitter field provides a second short-term measure of + network congestion. Packet loss tracks persistent congestion while + the jitter measure tracks transient congestion. The jitter measure + may indicate congestion before it leads to packet loss. The + interarrival jitter field is only a snapshot of the jitter at the + time of a report and is not intended to be taken quantitatively. + Rather, it is intended for comparison across a number of reports from + one receiver over time or from multiple receivers, e.g., within a + single network, at the same time. To allow comparison across + receivers, it is important the the jitter be calculated according to + the same formula by all receivers. + + Because the jitter calculation is based on the RTP timestamp which + represents the instant when the first data in the packet was sampled, + any variation in the delay between that sampling instant and the time + the packet is transmitted will affect the resulting jitter that is + calculated. Such a variation in delay would occur for audio packets + of varying duration. It will also occur for video encodings because + the timestamp is the same for all the packets of one frame but those + packets are not all transmitted at the same time. The variation in + delay until transmission does reduce the accuracy of the jitter + calculation as a measure of the behavior of the network by itself, + but it is appropriate to include considering that the receiver buffer + must accommodate it. When the jitter calculation is used as a + comparative measure, the (constant) component due to variation in + delay until transmission subtracts out so that a change in the + + + + +Schulzrinne, et al. Standards Track [Page 44] + +RFC 3550 RTP July 2003 + + + network jitter component can then be observed unless it is relatively + small. If the change is small, then it is likely to be + inconsequential. + +6.5 SDES: Source Description RTCP Packet + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +header |V=2|P| SC | PT=SDES=202 | length | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +chunk | SSRC/CSRC_1 | + 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SDES items | + | ... | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +chunk | SSRC/CSRC_2 | + 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SDES items | + | ... | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + + The SDES packet is a three-level structure composed of a header and + zero or more chunks, each of which is composed of items describing + the source identified in that chunk. The items are described + individually in subsequent sections. + + version (V), padding (P), length: + As described for the SR packet (see Section 6.4.1). + + packet type (PT): 8 bits + Contains the constant 202 to identify this as an RTCP SDES packet. + + source count (SC): 5 bits + The number of SSRC/CSRC chunks contained in this SDES packet. A + value of zero is valid but useless. + + Each chunk consists of an SSRC/CSRC identifier followed by a list of + zero or more items, which carry information about the SSRC/CSRC. + Each chunk starts on a 32-bit boundary. Each item consists of an 8- + bit type field, an 8-bit octet count describing the length of the + text (thus, not including this two-octet header), and the text + itself. Note that the text can be no longer than 255 octets, but + this is consistent with the need to limit RTCP bandwidth consumption. + + + + + + + +Schulzrinne, et al. Standards Track [Page 45] + +RFC 3550 RTP July 2003 + + + The text is encoded according to the UTF-8 encoding specified in RFC + 2279 [5]. US-ASCII is a subset of this encoding and requires no + additional encoding. The presence of multi-octet encodings is + indicated by setting the most significant bit of a character to a + value of one. + + Items are contiguous, i.e., items are not individually padded to a + 32-bit boundary. Text is not null terminated because some multi- + octet encodings include null octets. The list of items in each chunk + MUST be terminated by one or more null octets, the first of which is + interpreted as an item type of zero to denote the end of the list. + No length octet follows the null item type octet, but additional null + octets MUST be included if needed to pad until the next 32-bit + boundary. Note that this padding is separate from that indicated by + the P bit in the RTCP header. A chunk with zero items (four null + octets) is valid but useless. + + End systems send one SDES packet containing their own source + identifier (the same as the SSRC in the fixed RTP header). A mixer + sends one SDES packet containing a chunk for each contributing source + from which it is receiving SDES information, or multiple complete + SDES packets in the format above if there are more than 31 such + sources (see Section 7). + + The SDES items currently defined are described in the next sections. + Only the CNAME item is mandatory. Some items shown here may be + useful only for particular profiles, but the item types are all + assigned from one common space to promote shared use and to simplify + profile-independent applications. Additional items may be defined in + a profile by registering the type numbers with IANA as described in + Section 15. + +6.5.1 CNAME: Canonical End-Point Identifier SDES Item + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | CNAME=1 | length | user and domain name ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The CNAME identifier has the following properties: + + o Because the randomly allocated SSRC identifier may change if a + conflict is discovered or if a program is restarted, the CNAME + item MUST be included to provide the binding from the SSRC + identifier to an identifier for the source (sender or receiver) + that remains constant. + + + + +Schulzrinne, et al. Standards Track [Page 46] + +RFC 3550 RTP July 2003 + + + o Like the SSRC identifier, the CNAME identifier SHOULD also be + unique among all participants within one RTP session. + + o To provide a binding across multiple media tools used by one + participant in a set of related RTP sessions, the CNAME SHOULD be + fixed for that participant. + + o To facilitate third-party monitoring, the CNAME SHOULD be suitable + for either a program or a person to locate the source. + + Therefore, the CNAME SHOULD be derived algorithmically and not + entered manually, when possible. To meet these requirements, the + following format SHOULD be used unless a profile specifies an + alternate syntax or semantics. The CNAME item SHOULD have the format + "user@host", or "host" if a user name is not available as on single- + user systems. For both formats, "host" is either the fully qualified + domain name of the host from which the real-time data originates, + formatted according to the rules specified in RFC 1034 [6], RFC 1035 + [7] and Section 2.1 of RFC 1123 [8]; or the standard ASCII + representation of the host's numeric address on the interface used + for the RTP communication. For example, the standard ASCII + representation of an IP Version 4 address is "dotted decimal", also + known as dotted quad, and for IP Version 6, addresses are textually + represented as groups of hexadecimal digits separated by colons (with + variations as detailed in RFC 3513 [23]). Other address types are + expected to have ASCII representations that are mutually unique. The + fully qualified domain name is more convenient for a human observer + and may avoid the need to send a NAME item in addition, but it may be + difficult or impossible to obtain reliably in some operating + environments. Applications that may be run in such environments + SHOULD use the ASCII representation of the address instead. + + Examples are "doe@sleepy.example.com", "doe@192.0.2.89" or + "doe@2201:056D::112E:144A:1E24" for a multi-user system. On a system + with no user name, examples would be "sleepy.example.com", + "192.0.2.89" or "2201:056D::112E:144A:1E24". + + The user name SHOULD be in a form that a program such as "finger" or + "talk" could use, i.e., it typically is the login name rather than + the personal name. The host name is not necessarily identical to the + one in the participant's electronic mail address. + + This syntax will not provide unique identifiers for each source if an + application permits a user to generate multiple sources from one + host. Such an application would have to rely on the SSRC to further + identify the source, or the profile for that application would have + to specify additional syntax for the CNAME identifier. + + + + +Schulzrinne, et al. Standards Track [Page 47] + +RFC 3550 RTP July 2003 + + + If each application creates its CNAME independently, the resulting + CNAMEs may not be identical as would be required to provide a binding + across multiple media tools belonging to one participant in a set of + related RTP sessions. If cross-media binding is required, it may be + necessary for the CNAME of each tool to be externally configured with + the same value by a coordination tool. + + Application writers should be aware that private network address + assignments such as the Net-10 assignment proposed in RFC 1918 [24] + may create network addresses that are not globally unique. This + would lead to non-unique CNAMEs if hosts with private addresses and + no direct IP connectivity to the public Internet have their RTP + packets forwarded to the public Internet through an RTP-level + translator. (See also RFC 1627 [25].) To handle this case, + applications MAY provide a means to configure a unique CNAME, but the + burden is on the translator to translate CNAMEs from private + addresses to public addresses if necessary to keep private addresses + from being exposed. + +6.5.2 NAME: User Name SDES Item + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | NAME=2 | length | common name of source ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + This is the real name used to describe the source, e.g., "John Doe, + Bit Recycler". It may be in any form desired by the user. For + applications such as conferencing, this form of name may be the most + desirable for display in participant lists, and therefore might be + sent most frequently of those items other than CNAME. Profiles MAY + establish such priorities. The NAME value is expected to remain + constant at least for the duration of a session. It SHOULD NOT be + relied upon to be unique among all participants in the session. + +6.5.3 EMAIL: Electronic Mail Address SDES Item + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | EMAIL=3 | length | email address of source ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The email address is formatted according to RFC 2822 [9], for + example, "John.Doe@example.com". The EMAIL value is expected to + remain constant for the duration of a session. + + + + +Schulzrinne, et al. Standards Track [Page 48] + +RFC 3550 RTP July 2003 + + +6.5.4 PHONE: Phone Number SDES Item + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | PHONE=4 | length | phone number of source ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The phone number SHOULD be formatted with the plus sign replacing the + international access code. For example, "+1 908 555 1212" for a + number in the United States. + +6.5.5 LOC: Geographic User Location SDES Item + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | LOC=5 | length | geographic location of site ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Depending on the application, different degrees of detail are + appropriate for this item. For conference applications, a string + like "Murray Hill, New Jersey" may be sufficient, while, for an + active badge system, strings like "Room 2A244, AT&T BL MH" might be + appropriate. The degree of detail is left to the implementation + and/or user, but format and content MAY be prescribed by a profile. + The LOC value is expected to remain constant for the duration of a + session, except for mobile hosts. + +6.5.6 TOOL: Application or Tool Name SDES Item + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | TOOL=6 | length |name/version of source appl. ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + A string giving the name and possibly version of the application + generating the stream, e.g., "videotool 1.2". This information may + be useful for debugging purposes and is similar to the Mailer or + Mail-System-Version SMTP headers. The TOOL value is expected to + remain constant for the duration of the session. + + + + + + + + + +Schulzrinne, et al. Standards Track [Page 49] + +RFC 3550 RTP July 2003 + + +6.5.7 NOTE: Notice/Status SDES Item + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | NOTE=7 | length | note about the source ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The following semantics are suggested for this item, but these or + other semantics MAY be explicitly defined by a profile. The NOTE + item is intended for transient messages describing the current state + of the source, e.g., "on the phone, can't talk". Or, during a + seminar, this item might be used to convey the title of the talk. It + should be used only to carry exceptional information and SHOULD NOT + be included routinely by all participants because this would slow + down the rate at which reception reports and CNAME are sent, thus + impairing the performance of the protocol. In particular, it SHOULD + NOT be included as an item in a user's configuration file nor + automatically generated as in a quote-of-the-day. + + Since the NOTE item may be important to display while it is active, + the rate at which other non-CNAME items such as NAME are transmitted + might be reduced so that the NOTE item can take that part of the RTCP + bandwidth. When the transient message becomes inactive, the NOTE + item SHOULD continue to be transmitted a few times at the same + repetition rate but with a string of length zero to signal the + receivers. However, receivers SHOULD also consider the NOTE item + inactive if it is not received for a small multiple of the repetition + rate, or perhaps 20-30 RTCP intervals. + +6.5.8 PRIV: Private Extensions SDES Item + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | PRIV=8 | length | prefix length |prefix string... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ... | value string ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + This item is used to define experimental or application-specific SDES + extensions. The item contains a prefix consisting of a length-string + pair, followed by the value string filling the remainder of the item + and carrying the desired information. The prefix length field is 8 + bits long. The prefix string is a name chosen by the person defining + the PRIV item to be unique with respect to other PRIV items this + application might receive. The application creator might choose to + use the application name plus an additional subtype identification if + + + +Schulzrinne, et al. Standards Track [Page 50] + +RFC 3550 RTP July 2003 + + + needed. Alternatively, it is RECOMMENDED that others choose a name + based on the entity they represent, then coordinate the use of the + name within that entity. + + Note that the prefix consumes some space within the item's total + length of 255 octets, so the prefix should be kept as short as + possible. This facility and the constrained RTCP bandwidth SHOULD + NOT be overloaded; it is not intended to satisfy all the control + communication requirements of all applications. + + SDES PRIV prefixes will not be registered by IANA. If some form of + the PRIV item proves to be of general utility, it SHOULD instead be + assigned a regular SDES item type registered with IANA so that no + prefix is required. This simplifies use and increases transmission + efficiency. + +6.6 BYE: Goodbye RTCP Packet + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V=2|P| SC | PT=BYE=203 | length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SSRC/CSRC | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + : ... : + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +(opt) | length | reason for leaving ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The BYE packet indicates that one or more sources are no longer + active. + + version (V), padding (P), length: + As described for the SR packet (see Section 6.4.1). + + packet type (PT): 8 bits + Contains the constant 203 to identify this as an RTCP BYE packet. + + source count (SC): 5 bits + The number of SSRC/CSRC identifiers included in this BYE packet. + A count value of zero is valid, but useless. + + The rules for when a BYE packet should be sent are specified in + Sections 6.3.7 and 8.2. + + + + + + +Schulzrinne, et al. Standards Track [Page 51] + +RFC 3550 RTP July 2003 + + + If a BYE packet is received by a mixer, the mixer SHOULD forward the + BYE packet with the SSRC/CSRC identifier(s) unchanged. If a mixer + shuts down, it SHOULD send a BYE packet listing all contributing + sources it handles, as well as its own SSRC identifier. Optionally, + the BYE packet MAY include an 8-bit octet count followed by that many + octets of text indicating the reason for leaving, e.g., "camera + malfunction" or "RTP loop detected". The string has the same + encoding as that described for SDES. If the string fills the packet + to the next 32-bit boundary, the string is not null terminated. If + not, the BYE packet MUST be padded with null octets to the next 32- + bit boundary. This padding is separate from that indicated by the P + bit in the RTCP header. + +6.7 APP: Application-Defined RTCP Packet + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V=2|P| subtype | PT=APP=204 | length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SSRC/CSRC | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | name (ASCII) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | application-dependent data ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The APP packet is intended for experimental use as new applications + and new features are developed, without requiring packet type value + registration. APP packets with unrecognized names SHOULD be ignored. + After testing and if wider use is justified, it is RECOMMENDED that + each APP packet be redefined without the subtype and name fields and + registered with IANA using an RTCP packet type. + + version (V), padding (P), length: + As described for the SR packet (see Section 6.4.1). + + subtype: 5 bits + May be used as a subtype to allow a set of APP packets to be + defined under one unique name, or for any application-dependent + data. + + packet type (PT): 8 bits + Contains the constant 204 to identify this as an RTCP APP packet. + + + + + + + +Schulzrinne, et al. Standards Track [Page 52] + +RFC 3550 RTP July 2003 + + + name: 4 octets + A name chosen by the person defining the set of APP packets to be + unique with respect to other APP packets this application might + receive. The application creator might choose to use the + application name, and then coordinate the allocation of subtype + values to others who want to define new packet types for the + application. Alternatively, it is RECOMMENDED that others choose + a name based on the entity they represent, then coordinate the use + of the name within that entity. The name is interpreted as a + sequence of four ASCII characters, with uppercase and lowercase + characters treated as distinct. + + application-dependent data: variable length + Application-dependent data may or may not appear in an APP packet. + It is interpreted by the application and not RTP itself. It MUST + be a multiple of 32 bits long. + +7. RTP Translators and Mixers + + In addition to end systems, RTP supports the notion of "translators" + and "mixers", which could be considered as "intermediate systems" at + the RTP level. Although this support adds some complexity to the + protocol, the need for these functions has been clearly established + by experiments with multicast audio and video applications in the + Internet. Example uses of translators and mixers given in Section + 2.3 stem from the presence of firewalls and low bandwidth + connections, both of which are likely to remain. + +7.1 General Description + + An RTP translator/mixer connects two or more transport-level + "clouds". Typically, each cloud is defined by a common network and + transport protocol (e.g., IP/UDP) plus a multicast address and + transport level destination port or a pair of unicast addresses and + ports. (Network-level protocol translators, such as IP version 4 to + IP version 6, may be present within a cloud invisibly to RTP.) One + system may serve as a translator or mixer for a number of RTP + sessions, but each is considered a logically separate entity. + + In order to avoid creating a loop when a translator or mixer is + installed, the following rules MUST be observed: + + o Each of the clouds connected by translators and mixers + participating in one RTP session either MUST be distinct from all + the others in at least one of these parameters (protocol, address, + port), or MUST be isolated at the network level from the others. + + + + + +Schulzrinne, et al. Standards Track [Page 53] + +RFC 3550 RTP July 2003 + + + o A derivative of the first rule is that there MUST NOT be multiple + translators or mixers connected in parallel unless by some + arrangement they partition the set of sources to be forwarded. + + Similarly, all RTP end systems that can communicate through one or + more RTP translators or mixers share the same SSRC space, that is, + the SSRC identifiers MUST be unique among all these end systems. + Section 8.2 describes the collision resolution algorithm by which + SSRC identifiers are kept unique and loops are detected. + + There may be many varieties of translators and mixers designed for + different purposes and applications. Some examples are to add or + remove encryption, change the encoding of the data or the underlying + protocols, or replicate between a multicast address and one or more + unicast addresses. The distinction between translators and mixers is + that a translator passes through the data streams from different + sources separately, whereas a mixer combines them to form one new + stream: + + Translator: Forwards RTP packets with their SSRC identifier + intact; this makes it possible for receivers to identify + individual sources even though packets from all the sources pass + through the same translator and carry the translator's network + source address. Some kinds of translators will pass through the + data untouched, but others MAY change the encoding of the data and + thus the RTP data payload type and timestamp. If multiple data + packets are re-encoded into one, or vice versa, a translator MUST + assign new sequence numbers to the outgoing packets. Losses in + the incoming packet stream may induce corresponding gaps in the + outgoing sequence numbers. Receivers cannot detect the presence + of a translator unless they know by some other means what payload + type or transport address was used by the original source. + + Mixer: Receives streams of RTP data packets from one or more + sources, possibly changes the data format, combines the streams in + some manner and then forwards the combined stream. Since the + timing among multiple input sources will not generally be + synchronized, the mixer will make timing adjustments among the + streams and generate its own timing for the combined stream, so it + is the synchronization source. Thus, all data packets forwarded + by a mixer MUST be marked with the mixer's own SSRC identifier. + In order to preserve the identity of the original sources + contributing to the mixed packet, the mixer SHOULD insert their + SSRC identifiers into the CSRC identifier list following the fixed + RTP header of the packet. A mixer that is also itself a + contributing source for some packet SHOULD explicitly include its + own SSRC identifier in the CSRC list for that packet. + + + + +Schulzrinne, et al. Standards Track [Page 54] + +RFC 3550 RTP July 2003 + + + For some applications, it MAY be acceptable for a mixer not to + identify sources in the CSRC list. However, this introduces the + danger that loops involving those sources could not be detected. + + The advantage of a mixer over a translator for applications like + audio is that the output bandwidth is limited to that of one source + even when multiple sources are active on the input side. This may be + important for low-bandwidth links. The disadvantage is that + receivers on the output side don't have any control over which + sources are passed through or muted, unless some mechanism is + implemented for remote control of the mixer. The regeneration of + synchronization information by mixers also means that receivers can't + do inter-media synchronization of the original streams. A multi- + media mixer could do it. + + [E1] [E6] + | | + E1:17 | E6:15 | + | | E6:15 + V M1:48 (1,17) M1:48 (1,17) V M1:48 (1,17) + (M1)------------->----------------->-------------->[E7] + ^ ^ E4:47 ^ E4:47 + E2:1 | E4:47 | | M3:89 (64,45) + | | | + [E2] [E4] M3:89 (64,45) | + | legend: + [E3] --------->(M2)----------->(M3)------------| [End system] + E3:64 M2:12 (64) ^ (Mixer) + | E5:45 + | + [E5] source: SSRC (CSRCs) + -------------------> + + Figure 3: Sample RTP network with end systems, mixers and translators + + A collection of mixers and translators is shown in Fig. 3 to + illustrate their effect on SSRC and CSRC identifiers. In the figure, + end systems are shown as rectangles (named E), translators as + triangles (named T) and mixers as ovals (named M). The notation "M1: + 48(1,17)" designates a packet originating a mixer M1, identified by + M1's (random) SSRC value of 48 and two CSRC identifiers, 1 and 17, + copied from the SSRC identifiers of packets from E1 and E2. + +7.2 RTCP Processing in Translators + + In addition to forwarding data packets, perhaps modified, translators + and mixers MUST also process RTCP packets. In many cases, they will + take apart the compound RTCP packets received from end systems to + + + +Schulzrinne, et al. Standards Track [Page 55] + +RFC 3550 RTP July 2003 + + + aggregate SDES information and to modify the SR or RR packets. + Retransmission of this information may be triggered by the packet + arrival or by the RTCP interval timer of the translator or mixer + itself. + + A translator that does not modify the data packets, for example one + that just replicates between a multicast address and a unicast + address, MAY simply forward RTCP packets unmodified as well. A + translator that transforms the payload in some way MUST make + corresponding transformations in the SR and RR information so that it + still reflects the characteristics of the data and the reception + quality. These translators MUST NOT simply forward RTCP packets. In + general, a translator SHOULD NOT aggregate SR and RR packets from + different sources into one packet since that would reduce the + accuracy of the propagation delay measurements based on the LSR and + DLSR fields. + + SR sender information: A translator does not generate its own + sender information, but forwards the SR packets received from one + cloud to the others. The SSRC is left intact but the sender + information MUST be modified if required by the translation. If a + translator changes the data encoding, it MUST change the "sender's + byte count" field. If it also combines several data packets into + one output packet, it MUST change the "sender's packet count" + field. If it changes the timestamp frequency, it MUST change the + "RTP timestamp" field in the SR packet. + + SR/RR reception report blocks: A translator forwards reception + reports received from one cloud to the others. Note that these + flow in the direction opposite to the data. The SSRC is left + intact. If a translator combines several data packets into one + output packet, and therefore changes the sequence numbers, it MUST + make the inverse manipulation for the packet loss fields and the + "extended last sequence number" field. This may be complex. In + the extreme case, there may be no meaningful way to translate the + reception reports, so the translator MAY pass on no reception + report at all or a synthetic report based on its own reception. + The general rule is to do what makes sense for a particular + translation. + + A translator does not require an SSRC identifier of its own, but + MAY choose to allocate one for the purpose of sending reports + about what it has received. These would be sent to all the + connected clouds, each corresponding to the translation of the + data stream as sent to that cloud, since reception reports are + normally multicast to all participants. + + + + + +Schulzrinne, et al. Standards Track [Page 56] + +RFC 3550 RTP July 2003 + + + SDES: Translators typically forward without change the SDES + information they receive from one cloud to the others, but MAY, + for example, decide to filter non-CNAME SDES information if + bandwidth is limited. The CNAMEs MUST be forwarded to allow SSRC + identifier collision detection to work. A translator that + generates its own RR packets MUST send SDES CNAME information + about itself to the same clouds that it sends those RR packets. + + BYE: Translators forward BYE packets unchanged. A translator + that is about to cease forwarding packets SHOULD send a BYE packet + to each connected cloud containing all the SSRC identifiers that + were previously being forwarded to that cloud, including the + translator's own SSRC identifier if it sent reports of its own. + + APP: Translators forward APP packets unchanged. + +7.3 RTCP Processing in Mixers + + Since a mixer generates a new data stream of its own, it does not + pass through SR or RR packets at all and instead generates new + information for both sides. + + SR sender information: A mixer does not pass through sender + information from the sources it mixes because the characteristics + of the source streams are lost in the mix. As a synchronization + source, the mixer SHOULD generate its own SR packets with sender + information about the mixed data stream and send them in the same + direction as the mixed stream. + + SR/RR reception report blocks: A mixer generates its own + reception reports for sources in each cloud and sends them out + only to the same cloud. It MUST NOT send these reception reports + to the other clouds and MUST NOT forward reception reports from + one cloud to the others because the sources would not be SSRCs + there (only CSRCs). + + SDES: Mixers typically forward without change the SDES + information they receive from one cloud to the others, but MAY, + for example, decide to filter non-CNAME SDES information if + bandwidth is limited. The CNAMEs MUST be forwarded to allow SSRC + identifier collision detection to work. (An identifier in a CSRC + list generated by a mixer might collide with an SSRC identifier + generated by an end system.) A mixer MUST send SDES CNAME + information about itself to the same clouds that it sends SR or RR + packets. + + + + + + +Schulzrinne, et al. Standards Track [Page 57] + +RFC 3550 RTP July 2003 + + + Since mixers do not forward SR or RR packets, they will typically + be extracting SDES packets from a compound RTCP packet. To + minimize overhead, chunks from the SDES packets MAY be aggregated + into a single SDES packet which is then stacked on an SR or RR + packet originating from the mixer. A mixer which aggregates SDES + packets will use more RTCP bandwidth than an individual source + because the compound packets will be longer, but that is + appropriate since the mixer represents multiple sources. + Similarly, a mixer which passes through SDES packets as they are + received will be transmitting RTCP packets at higher than the + single source rate, but again that is correct since the packets + come from multiple sources. The RTCP packet rate may be different + on each side of the mixer. + + A mixer that does not insert CSRC identifiers MAY also refrain + from forwarding SDES CNAMEs. In this case, the SSRC identifier + spaces in the two clouds are independent. As mentioned earlier, + this mode of operation creates a danger that loops can't be + detected. + + BYE: Mixers MUST forward BYE packets. A mixer that is about to + cease forwarding packets SHOULD send a BYE packet to each + connected cloud containing all the SSRC identifiers that were + previously being forwarded to that cloud, including the mixer's + own SSRC identifier if it sent reports of its own. + + APP: The treatment of APP packets by mixers is application-specific. + +7.4 Cascaded Mixers + + An RTP session may involve a collection of mixers and translators as + shown in Fig. 3. If two mixers are cascaded, such as M2 and M3 in + the figure, packets received by a mixer may already have been mixed + and may include a CSRC list with multiple identifiers. The second + mixer SHOULD build the CSRC list for the outgoing packet using the + CSRC identifiers from already-mixed input packets and the SSRC + identifiers from unmixed input packets. This is shown in the output + arc from mixer M3 labeled M3:89(64,45) in the figure. As in the case + of mixers that are not cascaded, if the resulting CSRC list has more + than 15 identifiers, the remainder cannot be included. + + + + + + + + + + + +Schulzrinne, et al. Standards Track [Page 58] + +RFC 3550 RTP July 2003 + + +8. SSRC Identifier Allocation and Use + + The SSRC identifier carried in the RTP header and in various fields + of RTCP packets is a random 32-bit number that is required to be + globally unique within an RTP session. It is crucial that the number + be chosen with care in order that participants on the same network or + starting at the same time are not likely to choose the same number. + + It is not sufficient to use the local network address (such as an + IPv4 address) for the identifier because the address may not be + unique. Since RTP translators and mixers enable interoperation among + multiple networks with different address spaces, the allocation + patterns for addresses within two spaces might result in a much + higher rate of collision than would occur with random allocation. + + Multiple sources running on one host would also conflict. + + It is also not sufficient to obtain an SSRC identifier simply by + calling random() without carefully initializing the state. An + example of how to generate a random identifier is presented in + Appendix A.6. + +8.1 Probability of Collision + + Since the identifiers are chosen randomly, it is possible that two or + more sources will choose the same number. Collision occurs with the + highest probability when all sources are started simultaneously, for + example when triggered automatically by some session management + event. If N is the number of sources and L the length of the + identifier (here, 32 bits), the probability that two sources + independently pick the same value can be approximated for large N + [26] as 1 - exp(-N**2 / 2**(L+1)). For N=1000, the probability is + roughly 10**-4. + + The typical collision probability is much lower than the worst-case + above. When one new source joins an RTP session in which all the + other sources already have unique identifiers, the probability of + collision is just the fraction of numbers used out of the space. + Again, if N is the number of sources and L the length of the + identifier, the probability of collision is N / 2**L. For N=1000, + the probability is roughly 2*10**-7. + + The probability of collision is further reduced by the opportunity + for a new source to receive packets from other participants before + sending its first packet (either data or control). If the new source + keeps track of the other participants (by SSRC identifier), then + + + + + +Schulzrinne, et al. Standards Track [Page 59] + +RFC 3550 RTP July 2003 + + + before transmitting its first packet the new source can verify that + its identifier does not conflict with any that have been received, or + else choose again. + +8.2 Collision Resolution and Loop Detection + + Although the probability of SSRC identifier collision is low, all RTP + implementations MUST be prepared to detect collisions and take the + appropriate actions to resolve them. If a source discovers at any + time that another source is using the same SSRC identifier as its + own, it MUST send an RTCP BYE packet for the old identifier and + choose another random one. (As explained below, this step is taken + only once in case of a loop.) If a receiver discovers that two other + sources are colliding, it MAY keep the packets from one and discard + the packets from the other when this can be detected by different + source transport addresses or CNAMEs. The two sources are expected + to resolve the collision so that the situation doesn't last. + + Because the random SSRC identifiers are kept globally unique for each + RTP session, they can also be used to detect loops that may be + introduced by mixers or translators. A loop causes duplication of + data and control information, either unmodified or possibly mixed, as + in the following examples: + + o A translator may incorrectly forward a packet to the same + multicast group from which it has received the packet, either + directly or through a chain of translators. In that case, the + same packet appears several times, originating from different + network sources. + + o Two translators incorrectly set up in parallel, i.e., with the + same multicast groups on both sides, would both forward packets + from one multicast group to the other. Unidirectional translators + would produce two copies; bidirectional translators would form a + loop. + + o A mixer can close a loop by sending to the same transport + destination upon which it receives packets, either directly or + through another mixer or translator. In this case a source might + show up both as an SSRC on a data packet and a CSRC in a mixed + data packet. + + A source may discover that its own packets are being looped, or that + packets from another source are being looped (a third-party loop). + Both loops and collisions in the random selection of a source + identifier result in packets arriving with the same SSRC identifier + but a different source transport address, which may be that of the + end system originating the packet or an intermediate system. + + + +Schulzrinne, et al. Standards Track [Page 60] + +RFC 3550 RTP July 2003 + + + Therefore, if a source changes its source transport address, it MAY + also choose a new SSRC identifier to avoid being interpreted as a + looped source. (This is not MUST because in some applications of RTP + sources may be expected to change addresses during a session.) Note + that if a translator restarts and consequently changes the source + transport address (e.g., changes the UDP source port number) on which + it forwards packets, then all those packets will appear to receivers + to be looped because the SSRC identifiers are applied by the original + source and will not change. This problem can be avoided by keeping + the source transport address fixed across restarts, but in any case + will be resolved after a timeout at the receivers. + + Loops or collisions occurring on the far side of a translator or + mixer cannot be detected using the source transport address if all + copies of the packets go through the translator or mixer, however, + collisions may still be detected when chunks from two RTCP SDES + packets contain the same SSRC identifier but different CNAMEs. + + To detect and resolve these conflicts, an RTP implementation MUST + include an algorithm similar to the one described below, though the + implementation MAY choose a different policy for which packets from + colliding third-party sources are kept. The algorithm described + below ignores packets from a new source or loop that collide with an + established source. It resolves collisions with the participant's + own SSRC identifier by sending an RTCP BYE for the old identifier and + choosing a new one. However, when the collision was induced by a + loop of the participant's own packets, the algorithm will choose a + new identifier only once and thereafter ignore packets from the + looping source transport address. This is required to avoid a flood + of BYE packets. + + This algorithm requires keeping a table indexed by the source + identifier and containing the source transport addresses from the + first RTP packet and first RTCP packet received with that identifier, + along with other state for that source. Two source transport + addresses are required since, for example, the UDP source port + numbers may be different on RTP and RTCP packets. However, it may be + assumed that the network address is the same in both source transport + addresses. + + Each SSRC or CSRC identifier received in an RTP or RTCP packet is + looked up in the source identifier table in order to process that + data or control information. The source transport address from the + packet is compared to the corresponding source transport address in + the table to detect a loop or collision if they don't match. For + control packets, each element with its own SSRC identifier, for + example an SDES chunk, requires a separate lookup. (The SSRC + identifier in a reception report block is an exception because it + + + +Schulzrinne, et al. Standards Track [Page 61] + +RFC 3550 RTP July 2003 + + + identifies a source heard by the reporter, and that SSRC identifier + is unrelated to the source transport address of the RTCP packet sent + by the reporter.) If the SSRC or CSRC is not found, a new entry is + created. These table entries are removed when an RTCP BYE packet is + received with the corresponding SSRC identifier and validated by a + matching source transport address, or after no packets have arrived + for a relatively long time (see Section 6.2.1). + + Note that if two sources on the same host are transmitting with the + same source identifier at the time a receiver begins operation, it + would be possible that the first RTP packet received came from one of + the sources while the first RTCP packet received came from the other. + This would cause the wrong RTCP information to be associated with the + RTP data, but this situation should be sufficiently rare and harmless + that it may be disregarded. + + In order to track loops of the participant's own data packets, the + implementation MUST also keep a separate list of source transport + addresses (not identifiers) that have been found to be conflicting. + As in the source identifier table, two source transport addresses + MUST be kept to separately track conflicting RTP and RTCP packets. + Note that the conflicting address list should be short, usually + empty. Each element in this list stores the source addresses plus + the time when the most recent conflicting packet was received. An + element MAY be removed from the list when no conflicting packet has + arrived from that source for a time on the order of 10 RTCP report + intervals (see Section 6.2). + + For the algorithm as shown, it is assumed that the participant's own + source identifier and state are included in the source identifier + table. The algorithm could be restructured to first make a separate + comparison against the participant's own source identifier. + + if (SSRC or CSRC identifier is not found in the source + identifier table) { + create a new entry storing the data or control source + transport address, the SSRC or CSRC and other state; + } + + /* Identifier is found in the table */ + + else if (table entry was created on receipt of a control packet + and this is the first data packet or vice versa) { + store the source transport address from this packet; + } + else if (source transport address from the packet does not match + the one saved in the table entry for this identifier) { + + + + +Schulzrinne, et al. Standards Track [Page 62] + +RFC 3550 RTP July 2003 + + + /* An identifier collision or a loop is indicated */ + + if (source identifier is not the participant's own) { + /* OPTIONAL error counter step */ + if (source identifier is from an RTCP SDES chunk + containing a CNAME item that differs from the CNAME + in the table entry) { + count a third-party collision; + } else { + count a third-party loop; + } + abort processing of data packet or control element; + /* MAY choose a different policy to keep new source */ + } + + /* A collision or loop of the participant's own packets */ + + else if (source transport address is found in the list of + conflicting data or control source transport + addresses) { + /* OPTIONAL error counter step */ + if (source identifier is not from an RTCP SDES chunk + containing a CNAME item or CNAME is the + participant's own) { + count occurrence of own traffic looped; + } + mark current time in conflicting address list entry; + abort processing of data packet or control element; + } + + /* New collision, change SSRC identifier */ + + else { + log occurrence of a collision; + create a new entry in the conflicting data or control + source transport address list and mark current time; + send an RTCP BYE packet with the old SSRC identifier; + choose a new SSRC identifier; + create a new entry in the source identifier table with + the old SSRC plus the source transport address from + the data or control packet being processed; + } + } + + In this algorithm, packets from a newly conflicting source address + will be ignored and packets from the original source address will be + kept. If no packets arrive from the original source for an extended + period, the table entry will be timed out and the new source will be + + + +Schulzrinne, et al. Standards Track [Page 63] + +RFC 3550 RTP July 2003 + + + able to take over. This might occur if the original source detects + the collision and moves to a new source identifier, but in the usual + case an RTCP BYE packet will be received from the original source to + delete the state without having to wait for a timeout. + + If the original source address was received through a mixer (i.e., + learned as a CSRC) and later the same source is received directly, + the receiver may be well advised to switch to the new source address + unless other sources in the mix would be lost. Furthermore, for + applications such as telephony in which some sources such as mobile + entities may change addresses during the course of an RTP session, + the RTP implementation SHOULD modify the collision detection + algorithm to accept packets from the new source transport address. + To guard against flip-flopping between addresses if a genuine + collision does occur, the algorithm SHOULD include some means to + detect this case and avoid switching. + + When a new SSRC identifier is chosen due to a collision, the + candidate identifier SHOULD first be looked up in the source + identifier table to see if it was already in use by some other + source. If so, another candidate MUST be generated and the process + repeated. + + A loop of data packets to a multicast destination can cause severe + network flooding. All mixers and translators MUST implement a loop + detection algorithm like the one here so that they can break loops. + This should limit the excess traffic to no more than one duplicate + copy of the original traffic, which may allow the session to continue + so that the cause of the loop can be found and fixed. However, in + extreme cases where a mixer or translator does not properly break the + loop and high traffic levels result, it may be necessary for end + systems to cease transmitting data or control packets entirely. This + decision may depend upon the application. An error condition SHOULD + be indicated as appropriate. Transmission MAY be attempted again + periodically after a long, random time (on the order of minutes). + +8.3 Use with Layered Encodings + + For layered encodings transmitted on separate RTP sessions (see + Section 2.4), a single SSRC identifier space SHOULD be used across + the sessions of all layers and the core (base) layer SHOULD be used + for SSRC identifier allocation and collision resolution. When a + source discovers that it has collided, it transmits an RTCP BYE + packet on only the base layer but changes the SSRC identifier to the + new value in all layers. + + + + + + +Schulzrinne, et al. Standards Track [Page 64] + +RFC 3550 RTP July 2003 + + +9. Security + + Lower layer protocols may eventually provide all the security + services that may be desired for applications of RTP, including + authentication, integrity, and confidentiality. These services have + been specified for IP in [27]. Since the initial audio and video + applications using RTP needed a confidentiality service before such + services were available for the IP layer, the confidentiality service + described in the next section was defined for use with RTP and RTCP. + That description is included here to codify existing practice. New + applications of RTP MAY implement this RTP-specific confidentiality + service for backward compatibility, and/or they MAY implement + alternative security services. The overhead on the RTP protocol for + this confidentiality service is low, so the penalty will be minimal + if this service is obsoleted by other services in the future. + + Alternatively, other services, other implementations of services and + other algorithms may be defined for RTP in the future. In + particular, an RTP profile called Secure Real-time Transport Protocol + (SRTP) [28] is being developed to provide confidentiality of the RTP + payload while leaving the RTP header in the clear so that link-level + header compression algorithms can still operate. It is expected that + SRTP will be the correct choice for many applications. SRTP is based + on the Advanced Encryption Standard (AES) and provides stronger + security than the service described here. No claim is made that the + methods presented here are appropriate for a particular security + need. A profile may specify which services and algorithms should be + offered by applications, and may provide guidance as to their + appropriate use. + + Key distribution and certificates are outside the scope of this + document. + +9.1 Confidentiality + + Confidentiality means that only the intended receiver(s) can decode + the received packets; for others, the packet contains no useful + information. Confidentiality of the content is achieved by + encryption. + + When it is desired to encrypt RTP or RTCP according to the method + specified in this section, all the octets that will be encapsulated + for transmission in a single lower-layer packet are encrypted as a + unit. For RTCP, a 32-bit random number redrawn for each unit MUST be + prepended to the unit before encryption. For RTP, no prefix is + prepended; instead, the sequence number and timestamp fields are + initialized with random offsets. This is considered to be a weak + + + + +Schulzrinne, et al. Standards Track [Page 65] + +RFC 3550 RTP July 2003 + + + initialization vector (IV) because of poor randomness properties. In + addition, if the subsequent field, the SSRC, can be manipulated by an + enemy, there is further weakness of the encryption method. + + For RTCP, an implementation MAY segregate the individual RTCP packets + in a compound RTCP packet into two separate compound RTCP packets, + one to be encrypted and one to be sent in the clear. For example, + SDES information might be encrypted while reception reports were sent + in the clear to accommodate third-party monitors that are not privy + to the encryption key. In this example, depicted in Fig. 4, the SDES + information MUST be appended to an RR packet with no reports (and the + random number) to satisfy the requirement that all compound RTCP + packets begin with an SR or RR packet. The SDES CNAME item is + required in either the encrypted or unencrypted packet, but not both. + The same SDES information SHOULD NOT be carried in both packets as + this may compromise the encryption. + + UDP packet UDP packet + ----------------------------- ------------------------------ + [random][RR][SDES #CNAME ...] [SR #senderinfo #site1 #site2] + ----------------------------- ------------------------------ + encrypted not encrypted + + #: SSRC identifier + + Figure 4: Encrypted and non-encrypted RTCP packets + + The presence of encryption and the use of the correct key are + confirmed by the receiver through header or payload validity checks. + Examples of such validity checks for RTP and RTCP headers are given + in Appendices A.1 and A.2. + + To be consistent with existing implementations of the initial + specification of RTP in RFC 1889, the default encryption algorithm is + the Data Encryption Standard (DES) algorithm in cipher block chaining + (CBC) mode, as described in Section 1.1 of RFC 1423 [29], except that + padding to a multiple of 8 octets is indicated as described for the P + bit in Section 5.1. The initialization vector is zero because random + values are supplied in the RTP header or by the random prefix for + compound RTCP packets. For details on the use of CBC initialization + vectors, see [30]. + + Implementations that support the encryption method specified here + SHOULD always support the DES algorithm in CBC mode as the default + cipher for this method to maximize interoperability. This method was + chosen because it has been demonstrated to be easy and practical to + use in experimental audio and video tools in operation on the + Internet. However, DES has since been found to be too easily broken. + + + +Schulzrinne, et al. Standards Track [Page 66] + +RFC 3550 RTP July 2003 + + + It is RECOMMENDED that stronger encryption algorithms such as + Triple-DES be used in place of the default algorithm. Furthermore, + secure CBC mode requires that the first block of each packet be XORed + with a random, independent IV of the same size as the cipher's block + size. For RTCP, this is (partially) achieved by prepending each + packet with a 32-bit random number, independently chosen for each + packet. For RTP, the timestamp and sequence number start from random + values, but consecutive packets will not be independently randomized. + It should be noted that the randomness in both cases (RTP and RTCP) + is limited. High-security applications SHOULD consider other, more + conventional, protection means. Other encryption algorithms MAY be + specified dynamically for a session by non-RTP means. In particular, + the SRTP profile [28] based on AES is being developed to take into + account known plaintext and CBC plaintext manipulation concerns, and + will be the correct choice in the future. + + As an alternative to encryption at the IP level or at the RTP level + as described above, profiles MAY define additional payload types for + encrypted encodings. Those encodings MUST specify how padding and + other aspects of the encryption are to be handled. This method + allows encrypting only the data while leaving the headers in the + clear for applications where that is desired. It may be particularly + useful for hardware devices that will handle both decryption and + decoding. It is also valuable for applications where link-level + compression of RTP and lower-layer headers is desired and + confidentiality of the payload (but not addresses) is sufficient + since encryption of the headers precludes compression. + +9.2 Authentication and Message Integrity + + Authentication and message integrity services are not defined at the + RTP level since these services would not be directly feasible without + a key management infrastructure. It is expected that authentication + and integrity services will be provided by lower layer protocols. + +10. Congestion Control + + All transport protocols used on the Internet need to address + congestion control in some way [31]. RTP is not an exception, but + because the data transported over RTP is often inelastic (generated + at a fixed or controlled rate), the means to control congestion in + RTP may be quite different from those for other transport protocols + such as TCP. In one sense, inelasticity reduces the risk of + congestion because the RTP stream will not expand to consume all + available bandwidth as a TCP stream can. However, inelasticity also + means that the RTP stream cannot arbitrarily reduce its load on the + network to eliminate congestion when it occurs. + + + + +Schulzrinne, et al. Standards Track [Page 67] + +RFC 3550 RTP July 2003 + + + Since RTP may be used for a wide variety of applications in many + different contexts, there is no single congestion control mechanism + that will work for all. Therefore, congestion control SHOULD be + defined in each RTP profile as appropriate. For some profiles, it + may be sufficient to include an applicability statement restricting + the use of that profile to environments where congestion is avoided + by engineering. For other profiles, specific methods such as data + rate adaptation based on RTCP feedback may be required. + +11. RTP over Network and Transport Protocols + + This section describes issues specific to carrying RTP packets within + particular network and transport protocols. The following rules + apply unless superseded by protocol-specific definitions outside this + specification. + + RTP relies on the underlying protocol(s) to provide demultiplexing of + RTP data and RTCP control streams. For UDP and similar protocols, + RTP SHOULD use an even destination port number and the corresponding + RTCP stream SHOULD use the next higher (odd) destination port number. + For applications that take a single port number as a parameter and + derive the RTP and RTCP port pair from that number, if an odd number + is supplied then the application SHOULD replace that number with the + next lower (even) number to use as the base of the port pair. For + applications in which the RTP and RTCP destination port numbers are + specified via explicit, separate parameters (using a signaling + protocol or other means), the application MAY disregard the + restrictions that the port numbers be even/odd and consecutive + although the use of an even/odd port pair is still encouraged. The + RTP and RTCP port numbers MUST NOT be the same since RTP relies on + the port numbers to demultiplex the RTP data and RTCP control + streams. + + In a unicast session, both participants need to identify a port pair + for receiving RTP and RTCP packets. Both participants MAY use the + same port pair. A participant MUST NOT assume that the source port + of the incoming RTP or RTCP packet can be used as the destination + port for outgoing RTP or RTCP packets. When RTP data packets are + being sent in both directions, each participant's RTCP SR packets + MUST be sent to the port that the other participant has specified for + reception of RTCP. The RTCP SR packets combine sender information + for the outgoing data plus reception report information for the + incoming data. If a side is not actively sending data (see Section + 6.4), an RTCP RR packet is sent instead. + + It is RECOMMENDED that layered encoding applications (see Section + 2.4) use a set of contiguous port numbers. The port numbers MUST be + distinct because of a widespread deficiency in existing operating + + + +Schulzrinne, et al. Standards Track [Page 68] + +RFC 3550 RTP July 2003 + + + systems that prevents use of the same port with multiple multicast + addresses, and for unicast, there is only one permissible address. + Thus for layer n, the data port is P + 2n, and the control port is P + + 2n + 1. When IP multicast is used, the addresses MUST also be + distinct because multicast routing and group membership are managed + on an address granularity. However, allocation of contiguous IP + multicast addresses cannot be assumed because some groups may require + different scopes and may therefore be allocated from different + address ranges. + + The previous paragraph conflicts with the SDP specification, RFC 2327 + [15], which says that it is illegal for both multiple addresses and + multiple ports to be specified in the same session description + because the association of addresses with ports could be ambiguous. + It is intended that this restriction will be relaxed in a revision of + RFC 2327 to allow an equal number of addresses and ports to be + specified with a one-to-one mapping implied. + + RTP data packets contain no length field or other delineation, + therefore RTP relies on the underlying protocol(s) to provide a + length indication. The maximum length of RTP packets is limited only + by the underlying protocols. + + If RTP packets are to be carried in an underlying protocol that + provides the abstraction of a continuous octet stream rather than + messages (packets), an encapsulation of the RTP packets MUST be + defined to provide a framing mechanism. Framing is also needed if + the underlying protocol may contain padding so that the extent of the + RTP payload cannot be determined. The framing mechanism is not + defined here. + + A profile MAY specify a framing method to be used even when RTP is + carried in protocols that do provide framing in order to allow + carrying several RTP packets in one lower-layer protocol data unit, + such as a UDP packet. Carrying several RTP packets in one network or + transport packet reduces header overhead and may simplify + synchronization between different streams. + +12. Summary of Protocol Constants + + This section contains a summary listing of the constants defined in + this specification. + + The RTP payload type (PT) constants are defined in profiles rather + than this document. However, the octet of the RTP header which + contains the marker bit(s) and payload type MUST avoid the reserved + values 200 and 201 (decimal) to distinguish RTP packets from the RTCP + SR and RR packet types for the header validation procedure described + + + +Schulzrinne, et al. Standards Track [Page 69] + +RFC 3550 RTP July 2003 + + + in Appendix A.1. For the standard definition of one marker bit and a + 7-bit payload type field as shown in this specification, this + restriction means that payload types 72 and 73 are reserved. + +12.1 RTCP Packet Types + + abbrev. name value + SR sender report 200 + RR receiver report 201 + SDES source description 202 + BYE goodbye 203 + APP application-defined 204 + + These type values were chosen in the range 200-204 for improved + header validity checking of RTCP packets compared to RTP packets or + other unrelated packets. When the RTCP packet type field is compared + to the corresponding octet of the RTP header, this range corresponds + to the marker bit being 1 (which it usually is not in data packets) + and to the high bit of the standard payload type field being 1 (since + the static payload types are typically defined in the low half). + This range was also chosen to be some distance numerically from 0 and + 255 since all-zeros and all-ones are common data patterns. + + Since all compound RTCP packets MUST begin with SR or RR, these codes + were chosen as an even/odd pair to allow the RTCP validity check to + test the maximum number of bits with mask and value. + + Additional RTCP packet types may be registered through IANA (see + Section 15). + +12.2 SDES Types + + abbrev. name value + END end of SDES list 0 + CNAME canonical name 1 + NAME user name 2 + EMAIL user's electronic mail address 3 + PHONE user's phone number 4 + LOC geographic user location 5 + TOOL name of application or tool 6 + NOTE notice about the source 7 + PRIV private extensions 8 + + Additional SDES types may be registered through IANA (see Section + 15). + + + + + + +Schulzrinne, et al. Standards Track [Page 70] + +RFC 3550 RTP July 2003 + + +13. RTP Profiles and Payload Format Specifications + + A complete specification of RTP for a particular application will + require one or more companion documents of two types described here: + profiles, and payload format specifications. + + RTP may be used for a variety of applications with somewhat differing + requirements. The flexibility to adapt to those requirements is + provided by allowing multiple choices in the main protocol + specification, then selecting the appropriate choices or defining + extensions for a particular environment and class of applications in + a separate profile document. Typically an application will operate + under only one profile in a particular RTP session, so there is no + explicit indication within the RTP protocol itself as to which + profile is in use. A profile for audio and video applications may be + found in the companion RFC 3551. Profiles are typically titled "RTP + Profile for ...". + + The second type of companion document is a payload format + specification, which defines how a particular kind of payload data, + such as H.261 encoded video, should be carried in RTP. These + documents are typically titled "RTP Payload Format for XYZ + Audio/Video Encoding". Payload formats may be useful under multiple + profiles and may therefore be defined independently of any particular + profile. The profile documents are then responsible for assigning a + default mapping of that format to a payload type value if needed. + + Within this specification, the following items have been identified + for possible definition within a profile, but this list is not meant + to be exhaustive: + + RTP data header: The octet in the RTP data header that contains + the marker bit and payload type field MAY be redefined by a + profile to suit different requirements, for example with more or + fewer marker bits (Section 5.3, p. 18). + + Payload types: Assuming that a payload type field is included, + the profile will usually define a set of payload formats (e.g., + media encodings) and a default static mapping of those formats to + payload type values. Some of the payload formats may be defined + by reference to separate payload format specifications. For each + payload type defined, the profile MUST specify the RTP timestamp + clock rate to be used (Section 5.1, p. 14). + + RTP data header additions: Additional fields MAY be appended to + the fixed RTP data header if some additional functionality is + required across the profile's class of applications independent of + payload type (Section 5.3, p. 18). + + + +Schulzrinne, et al. Standards Track [Page 71] + +RFC 3550 RTP July 2003 + + + RTP data header extensions: The contents of the first 16 bits of + the RTP data header extension structure MUST be defined if use of + that mechanism is to be allowed under the profile for + implementation-specific extensions (Section 5.3.1, p. 18). + + RTCP packet types: New application-class-specific RTCP packet + types MAY be defined and registered with IANA. + + RTCP report interval: A profile SHOULD specify that the values + suggested in Section 6.2 for the constants employed in the + calculation of the RTCP report interval will be used. Those are + the RTCP fraction of session bandwidth, the minimum report + interval, and the bandwidth split between senders and receivers. + A profile MAY specify alternate values if they have been + demonstrated to work in a scalable manner. + + SR/RR extension: An extension section MAY be defined for the + RTCP SR and RR packets if there is additional information that + should be reported regularly about the sender or receivers + (Section 6.4.3, p. 42 and 43). + + SDES use: The profile MAY specify the relative priorities for + RTCP SDES items to be transmitted or excluded entirely (Section + 6.3.9); an alternate syntax or semantics for the CNAME item + (Section 6.5.1); the format of the LOC item (Section 6.5.5); the + semantics and use of the NOTE item (Section 6.5.7); or new SDES + item types to be registered with IANA. + + Security: A profile MAY specify which security services and + algorithms should be offered by applications, and MAY provide + guidance as to their appropriate use (Section 9, p. 65). + + String-to-key mapping: A profile MAY specify how a user-provided + password or pass phrase is mapped into an encryption key. + + Congestion: A profile SHOULD specify the congestion control + behavior appropriate for that profile. + + Underlying protocol: Use of a particular underlying network or + transport layer protocol to carry RTP packets MAY be required. + + Transport mapping: A mapping of RTP and RTCP to transport-level + addresses, e.g., UDP ports, other than the standard mapping + defined in Section 11, p. 68 may be specified. + + + + + + + +Schulzrinne, et al. Standards Track [Page 72] + +RFC 3550 RTP July 2003 + + + Encapsulation: An encapsulation of RTP packets may be defined to + allow multiple RTP data packets to be carried in one lower-layer + packet or to provide framing over underlying protocols that do not + already do so (Section 11, p. 69). + + It is not expected that a new profile will be required for every + application. Within one application class, it would be better to + extend an existing profile rather than make a new one in order to + facilitate interoperation among the applications since each will + typically run under only one profile. Simple extensions such as the + definition of additional payload type values or RTCP packet types may + be accomplished by registering them through IANA and publishing their + descriptions in an addendum to the profile or in a payload format + specification. + +14. Security Considerations + + RTP suffers from the same security liabilities as the underlying + protocols. For example, an impostor can fake source or destination + network addresses, or change the header or payload. Within RTCP, the + CNAME and NAME information may be used to impersonate another + participant. In addition, RTP may be sent via IP multicast, which + provides no direct means for a sender to know all the receivers of + the data sent and therefore no measure of privacy. Rightly or not, + users may be more sensitive to privacy concerns with audio and video + communication than they have been with more traditional forms of + network communication [33]. Therefore, the use of security + mechanisms with RTP is important. These mechanisms are discussed in + Section 9. + + RTP-level translators or mixers may be used to allow RTP traffic to + reach hosts behind firewalls. Appropriate firewall security + principles and practices, which are beyond the scope of this + document, should be followed in the design and installation of these + devices and in the admission of RTP applications for use behind the + firewall. + +15. IANA Considerations + + Additional RTCP packet types and SDES item types may be registered + through the Internet Assigned Numbers Authority (IANA). Since these + number spaces are small, allowing unconstrained registration of new + values would not be prudent. To facilitate review of requests and to + promote shared use of new types among multiple applications, requests + for registration of new values must be documented in an RFC or other + permanent and readily available reference such as the product of + another cooperative standards body (e.g., ITU-T). Other requests may + also be accepted, under the advice of a "designated expert." + + + +Schulzrinne, et al. Standards Track [Page 73] + +RFC 3550 RTP July 2003 + + + (Contact the IANA for the contact information of the current expert.) + + RTP profile specifications SHOULD register with IANA a name for the + profile in the form "RTP/xxx", where xxx is a short abbreviation of + the profile title. These names are for use by higher-level control + protocols, such as the Session Description Protocol (SDP), RFC 2327 + [15], to refer to transport methods. + +16. Intellectual Property Rights Statement + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; neither does it represent that it + has made any effort to identify any such rights. Information on the + IETF's procedures with respect to rights in standards-track and + standards-related documentation can be found in BCP-11. Copies of + claims of rights made available for publication and any assurances of + licenses to be made available, or the result of an attempt made to + obtain a general license or permission for the use of such + proprietary rights by implementors or users of this specification can + be obtained from the IETF Secretariat. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights which may cover technology that may be required to practice + this standard. Please address the information to the IETF Executive + Director. + +17. Acknowledgments + + This memorandum is based on discussions within the IETF Audio/Video + Transport working group chaired by Stephen Casner and Colin Perkins. + The current protocol has its origins in the Network Voice Protocol + and the Packet Video Protocol (Danny Cohen and Randy Cole) and the + protocol implemented by the vat application (Van Jacobson and Steve + McCanne). Christian Huitema provided ideas for the random identifier + generator. Extensive analysis and simulation of the timer + reconsideration algorithm was done by Jonathan Rosenberg. The + additions for layered encodings were specified by Michael Speer and + Steve McCanne. + + + + + + + + + +Schulzrinne, et al. Standards Track [Page 74] + +RFC 3550 RTP July 2003 + + +Appendix A - Algorithms + + We provide examples of C code for aspects of RTP sender and receiver + algorithms. There may be other implementation methods that are + faster in particular operating environments or have other advantages. + These implementation notes are for informational purposes only and + are meant to clarify the RTP specification. + + The following definitions are used for all examples; for clarity and + brevity, the structure definitions are only valid for 32-bit big- + endian (most significant octet first) architectures. Bit fields are + assumed to be packed tightly in big-endian bit order, with no + additional padding. Modifications would be required to construct a + portable implementation. + + /* + * rtp.h -- RTP header file + */ + #include + + /* + * The type definitions below are valid for 32-bit architectures and + * may have to be adjusted for 16- or 64-bit architectures. + */ + typedef unsigned char u_int8; + typedef unsigned short u_int16; + typedef unsigned int u_int32; + typedef short int16; + + /* + * Current protocol version. + */ + #define RTP_VERSION 2 + + #define RTP_SEQ_MOD (1<<16) + #define RTP_MAX_SDES 255 /* maximum text length for SDES */ + + typedef enum { + RTCP_SR = 200, + RTCP_RR = 201, + RTCP_SDES = 202, + RTCP_BYE = 203, + RTCP_APP = 204 + } rtcp_type_t; + + typedef enum { + RTCP_SDES_END = 0, + RTCP_SDES_CNAME = 1, + + + +Schulzrinne, et al. Standards Track [Page 75] + +RFC 3550 RTP July 2003 + + + RTCP_SDES_NAME = 2, + RTCP_SDES_EMAIL = 3, + RTCP_SDES_PHONE = 4, + RTCP_SDES_LOC = 5, + RTCP_SDES_TOOL = 6, + RTCP_SDES_NOTE = 7, + RTCP_SDES_PRIV = 8 + } rtcp_sdes_type_t; + + /* + * RTP data header + */ + typedef struct { + unsigned int version:2; /* protocol version */ + unsigned int p:1; /* padding flag */ + unsigned int x:1; /* header extension flag */ + unsigned int cc:4; /* CSRC count */ + unsigned int m:1; /* marker bit */ + unsigned int pt:7; /* payload type */ + unsigned int seq:16; /* sequence number */ + u_int32 ts; /* timestamp */ + u_int32 ssrc; /* synchronization source */ + u_int32 csrc[1]; /* optional CSRC list */ + } rtp_hdr_t; + + /* + * RTCP common header word + */ + typedef struct { + unsigned int version:2; /* protocol version */ + unsigned int p:1; /* padding flag */ + unsigned int count:5; /* varies by packet type */ + unsigned int pt:8; /* RTCP packet type */ + u_int16 length; /* pkt len in words, w/o this word */ + } rtcp_common_t; + + /* + * Big-endian mask for version, padding bit and packet type pair + */ + #define RTCP_VALID_MASK (0xc000 | 0x2000 | 0xfe) + #define RTCP_VALID_VALUE ((RTP_VERSION << 14) | RTCP_SR) + + /* + * Reception report block + */ + typedef struct { + u_int32 ssrc; /* data source being reported */ + unsigned int fraction:8; /* fraction lost since last SR/RR */ + + + +Schulzrinne, et al. Standards Track [Page 76] + +RFC 3550 RTP July 2003 + + + int lost:24; /* cumul. no. pkts lost (signed!) */ + u_int32 last_seq; /* extended last seq. no. received */ + u_int32 jitter; /* interarrival jitter */ + u_int32 lsr; /* last SR packet from this source */ + u_int32 dlsr; /* delay since last SR packet */ + } rtcp_rr_t; + + /* + * SDES item + */ + typedef struct { + u_int8 type; /* type of item (rtcp_sdes_type_t) */ + u_int8 length; /* length of item (in octets) */ + char data[1]; /* text, not null-terminated */ + } rtcp_sdes_item_t; + + /* + * One RTCP packet + */ + typedef struct { + rtcp_common_t common; /* common header */ + union { + /* sender report (SR) */ + struct { + u_int32 ssrc; /* sender generating this report */ + u_int32 ntp_sec; /* NTP timestamp */ + u_int32 ntp_frac; + u_int32 rtp_ts; /* RTP timestamp */ + u_int32 psent; /* packets sent */ + u_int32 osent; /* octets sent */ + rtcp_rr_t rr[1]; /* variable-length list */ + } sr; + + /* reception report (RR) */ + struct { + u_int32 ssrc; /* receiver generating this report */ + rtcp_rr_t rr[1]; /* variable-length list */ + } rr; + + /* source description (SDES) */ + struct rtcp_sdes { + u_int32 src; /* first SSRC/CSRC */ + rtcp_sdes_item_t item[1]; /* list of SDES items */ + } sdes; + + /* BYE */ + struct { + u_int32 src[1]; /* list of sources */ + + + +Schulzrinne, et al. Standards Track [Page 77] + +RFC 3550 RTP July 2003 + + + /* can't express trailing text for reason */ + } bye; + } r; + } rtcp_t; + + typedef struct rtcp_sdes rtcp_sdes_t; + + /* + * Per-source state information + */ + typedef struct { + u_int16 max_seq; /* highest seq. number seen */ + u_int32 cycles; /* shifted count of seq. number cycles */ + u_int32 base_seq; /* base seq number */ + u_int32 bad_seq; /* last 'bad' seq number + 1 */ + u_int32 probation; /* sequ. packets till source is valid */ + u_int32 received; /* packets received */ + u_int32 expected_prior; /* packet expected at last interval */ + u_int32 received_prior; /* packet received at last interval */ + u_int32 transit; /* relative trans time for prev pkt */ + u_int32 jitter; /* estimated jitter */ + /* ... */ + } source; + +A.1 RTP Data Header Validity Checks + + An RTP receiver should check the validity of the RTP header on + incoming packets since they might be encrypted or might be from a + different application that happens to be misaddressed. Similarly, if + encryption according to the method described in Section 9 is enabled, + the header validity check is needed to verify that incoming packets + have been correctly decrypted, although a failure of the header + validity check (e.g., unknown payload type) may not necessarily + indicate decryption failure. + + Only weak validity checks are possible on an RTP data packet from a + source that has not been heard before: + + o RTP version field must equal 2. + + o The payload type must be known, and in particular it must not be + equal to SR or RR. + + o If the P bit is set, then the last octet of the packet must + contain a valid octet count, in particular, less than the total + packet length minus the header size. + + + + + +Schulzrinne, et al. Standards Track [Page 78] + +RFC 3550 RTP July 2003 + + + o The X bit must be zero if the profile does not specify that the + header extension mechanism may be used. Otherwise, the extension + length field must be less than the total packet size minus the + fixed header length and padding. + + o The length of the packet must be consistent with CC and payload + type (if payloads have a known length). + + The last three checks are somewhat complex and not always possible, + leaving only the first two which total just a few bits. If the SSRC + identifier in the packet is one that has been received before, then + the packet is probably valid and checking if the sequence number is + in the expected range provides further validation. If the SSRC + identifier has not been seen before, then data packets carrying that + identifier may be considered invalid until a small number of them + arrive with consecutive sequence numbers. Those invalid packets MAY + be discarded or they MAY be stored and delivered once validation has + been achieved if the resulting delay is acceptable. + + The routine update_seq shown below ensures that a source is declared + valid only after MIN_SEQUENTIAL packets have been received in + sequence. It also validates the sequence number seq of a newly + received packet and updates the sequence state for the packet's + source in the structure to which s points. + + When a new source is heard for the first time, that is, its SSRC + identifier is not in the table (see Section 8.2), and the per-source + state is allocated for it, s->probation is set to the number of + sequential packets required before declaring a source valid + (parameter MIN_SEQUENTIAL) and other variables are initialized: + + init_seq(s, seq); + s->max_seq = seq - 1; + s->probation = MIN_SEQUENTIAL; + + A non-zero s->probation marks the source as not yet valid so the + state may be discarded after a short timeout rather than a long one, + as discussed in Section 6.2.1. + + After a source is considered valid, the sequence number is considered + valid if it is no more than MAX_DROPOUT ahead of s->max_seq nor more + than MAX_MISORDER behind. If the new sequence number is ahead of + max_seq modulo the RTP sequence number range (16 bits), but is + smaller than max_seq, it has wrapped around and the (shifted) count + of sequence number cycles is incremented. A value of one is returned + to indicate a valid sequence number. + + + + + +Schulzrinne, et al. Standards Track [Page 79] + +RFC 3550 RTP July 2003 + + + Otherwise, the value zero is returned to indicate that the validation + failed, and the bad sequence number plus 1 is stored. If the next + packet received carries the next higher sequence number, it is + considered the valid start of a new packet sequence presumably caused + by an extended dropout or a source restart. Since multiple complete + sequence number cycles may have been missed, the packet loss + statistics are reset. + + Typical values for the parameters are shown, based on a maximum + misordering time of 2 seconds at 50 packets/second and a maximum + dropout of 1 minute. The dropout parameter MAX_DROPOUT should be a + small fraction of the 16-bit sequence number space to give a + reasonable probability that new sequence numbers after a restart will + not fall in the acceptable range for sequence numbers from before the + restart. + + void init_seq(source *s, u_int16 seq) + { + s->base_seq = seq; + s->max_seq = seq; + s->bad_seq = RTP_SEQ_MOD + 1; /* so seq == bad_seq is false */ + s->cycles = 0; + s->received = 0; + s->received_prior = 0; + s->expected_prior = 0; + /* other initialization */ + } + + int update_seq(source *s, u_int16 seq) + { + u_int16 udelta = seq - s->max_seq; + const int MAX_DROPOUT = 3000; + const int MAX_MISORDER = 100; + const int MIN_SEQUENTIAL = 2; + + /* + * Source is not valid until MIN_SEQUENTIAL packets with + * sequential sequence numbers have been received. + */ + if (s->probation) { + /* packet is in sequence */ + if (seq == s->max_seq + 1) { + s->probation--; + s->max_seq = seq; + if (s->probation == 0) { + init_seq(s, seq); + s->received++; + return 1; + + + +Schulzrinne, et al. Standards Track [Page 80] + +RFC 3550 RTP July 2003 + + + } + } else { + s->probation = MIN_SEQUENTIAL - 1; + s->max_seq = seq; + } + return 0; + } else if (udelta < MAX_DROPOUT) { + /* in order, with permissible gap */ + if (seq < s->max_seq) { + /* + * Sequence number wrapped - count another 64K cycle. + */ + s->cycles += RTP_SEQ_MOD; + } + s->max_seq = seq; + } else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) { + /* the sequence number made a very large jump */ + if (seq == s->bad_seq) { + /* + * Two sequential packets -- assume that the other side + * restarted without telling us so just re-sync + * (i.e., pretend this was the first packet). + */ + init_seq(s, seq); + } + else { + s->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1); + return 0; + } + } else { + /* duplicate or reordered packet */ + } + s->received++; + return 1; + } + + The validity check can be made stronger requiring more than two + packets in sequence. The disadvantages are that a larger number of + initial packets will be discarded (or delayed in a queue) and that + high packet loss rates could prevent validation. However, because + the RTCP header validation is relatively strong, if an RTCP packet is + received from a source before the data packets, the count could be + adjusted so that only two packets are required in sequence. If + initial data loss for a few seconds can be tolerated, an application + MAY choose to discard all data packets from a source until a valid + RTCP packet has been received from that source. + + + + + +Schulzrinne, et al. Standards Track [Page 81] + +RFC 3550 RTP July 2003 + + + Depending on the application and encoding, algorithms may exploit + additional knowledge about the payload format for further validation. + For payload types where the timestamp increment is the same for all + packets, the timestamp values can be predicted from the previous + packet received from the same source using the sequence number + difference (assuming no change in payload type). + + A strong "fast-path" check is possible since with high probability + the first four octets in the header of a newly received RTP data + packet will be just the same as that of the previous packet from the + same SSRC except that the sequence number will have increased by one. + Similarly, a single-entry cache may be used for faster SSRC lookups + in applications where data is typically received from one source at a + time. + +A.2 RTCP Header Validity Checks + + The following checks should be applied to RTCP packets. + + o RTP version field must equal 2. + + o The payload type field of the first RTCP packet in a compound + packet must be equal to SR or RR. + + o The padding bit (P) should be zero for the first packet of a + compound RTCP packet because padding should only be applied, if it + is needed, to the last packet. + + o The length fields of the individual RTCP packets must add up to + the overall length of the compound RTCP packet as received. This + is a fairly strong check. + + The code fragment below performs all of these checks. The packet + type is not checked for subsequent packets since unknown packet types + may be present and should be ignored. + + u_int32 len; /* length of compound RTCP packet in words */ + rtcp_t *r; /* RTCP header */ + rtcp_t *end; /* end of compound RTCP packet */ + + if ((*(u_int16 *)r & RTCP_VALID_MASK) != RTCP_VALID_VALUE) { + /* something wrong with packet format */ + } + end = (rtcp_t *)((u_int32 *)r + len); + + do r = (rtcp_t *)((u_int32 *)r + r->common.length + 1); + while (r < end && r->common.version == 2); + + + + +Schulzrinne, et al. Standards Track [Page 82] + +RFC 3550 RTP July 2003 + + + if (r != end) { + /* something wrong with packet format */ + } + +A.3 Determining Number of Packets Expected and Lost + + In order to compute packet loss rates, the number of RTP packets + expected and actually received from each source needs to be known, + using per-source state information defined in struct source + referenced via pointer s in the code below. The number of packets + received is simply the count of packets as they arrive, including any + late or duplicate packets. The number of packets expected can be + computed by the receiver as the difference between the highest + sequence number received (s->max_seq) and the first sequence number + received (s->base_seq). Since the sequence number is only 16 bits + and will wrap around, it is necessary to extend the highest sequence + number with the (shifted) count of sequence number wraparounds + (s->cycles). Both the received packet count and the count of cycles + are maintained the RTP header validity check routine in Appendix A.1. + + extended_max = s->cycles + s->max_seq; + expected = extended_max - s->base_seq + 1; + + The number of packets lost is defined to be the number of packets + expected less the number of packets actually received: + + lost = expected - s->received; + + Since this signed number is carried in 24 bits, it should be clamped + at 0x7fffff for positive loss or 0x800000 for negative loss rather + than wrapping around. + + The fraction of packets lost during the last reporting interval + (since the previous SR or RR packet was sent) is calculated from + differences in the expected and received packet counts across the + interval, where expected_prior and received_prior are the values + saved when the previous reception report was generated: + + expected_interval = expected - s->expected_prior; + s->expected_prior = expected; + received_interval = s->received - s->received_prior; + s->received_prior = s->received; + lost_interval = expected_interval - received_interval; + if (expected_interval == 0 || lost_interval <= 0) fraction = 0; + else fraction = (lost_interval << 8) / expected_interval; + + The resulting fraction is an 8-bit fixed point number with the binary + point at the left edge. + + + +Schulzrinne, et al. Standards Track [Page 83] + +RFC 3550 RTP July 2003 + + +A.4 Generating RTCP SDES Packets + + This function builds one SDES chunk into buffer b composed of argc + items supplied in arrays type, value and length. It returns a + pointer to the next available location within b. + + char *rtp_write_sdes(char *b, u_int32 src, int argc, + rtcp_sdes_type_t type[], char *value[], + int length[]) + { + rtcp_sdes_t *s = (rtcp_sdes_t *)b; + rtcp_sdes_item_t *rsp; + int i; + int len; + int pad; + + /* SSRC header */ + s->src = src; + rsp = &s->item[0]; + + /* SDES items */ + for (i = 0; i < argc; i++) { + rsp->type = type[i]; + len = length[i]; + if (len > RTP_MAX_SDES) { + /* invalid length, may want to take other action */ + len = RTP_MAX_SDES; + } + rsp->length = len; + memcpy(rsp->data, value[i], len); + rsp = (rtcp_sdes_item_t *)&rsp->data[len]; + } + + /* terminate with end marker and pad to next 4-octet boundary */ + len = ((char *) rsp) - b; + pad = 4 - (len & 0x3); + b = (char *) rsp; + while (pad--) *b++ = RTCP_SDES_END; + + return b; + } + + + + + + + + + + +Schulzrinne, et al. Standards Track [Page 84] + +RFC 3550 RTP July 2003 + + +A.5 Parsing RTCP SDES Packets + + This function parses an SDES packet, calling functions find_member() + to find a pointer to the information for a session member given the + SSRC identifier and member_sdes() to store the new SDES information + for that member. This function expects a pointer to the header of + the RTCP packet. + + void rtp_read_sdes(rtcp_t *r) + { + int count = r->common.count; + rtcp_sdes_t *sd = &r->r.sdes; + rtcp_sdes_item_t *rsp, *rspn; + rtcp_sdes_item_t *end = (rtcp_sdes_item_t *) + ((u_int32 *)r + r->common.length + 1); + source *s; + + while (--count >= 0) { + rsp = &sd->item[0]; + if (rsp >= end) break; + s = find_member(sd->src); + + for (; rsp->type; rsp = rspn ) { + rspn = (rtcp_sdes_item_t *)((char*)rsp+rsp->length+2); + if (rspn >= end) { + rsp = rspn; + break; + } + member_sdes(s, rsp->type, rsp->data, rsp->length); + } + sd = (rtcp_sdes_t *) + ((u_int32 *)sd + (((char *)rsp - (char *)sd) >> 2)+1); + } + if (count >= 0) { + /* invalid packet format */ + } + } + +A.6 Generating a Random 32-bit Identifier + + The following subroutine generates a random 32-bit identifier using + the MD5 routines published in RFC 1321 [32]. The system routines may + not be present on all operating systems, but they should serve as + hints as to what kinds of information may be used. Other system + calls that may be appropriate include + + + + + + +Schulzrinne, et al. Standards Track [Page 85] + +RFC 3550 RTP July 2003 + + + o getdomainname(), + + o getwd(), or + + o getrusage(). + + "Live" video or audio samples are also a good source of random + numbers, but care must be taken to avoid using a turned-off + microphone or blinded camera as a source [17]. + + Use of this or a similar routine is recommended to generate the + initial seed for the random number generator producing the RTCP + period (as shown in Appendix A.7), to generate the initial values for + the sequence number and timestamp, and to generate SSRC values. + Since this routine is likely to be CPU-intensive, its direct use to + generate RTCP periods is inappropriate because predictability is not + an issue. Note that this routine produces the same result on + repeated calls until the value of the system clock changes unless + different values are supplied for the type argument. + + /* + * Generate a random 32-bit quantity. + */ + #include /* u_long */ + #include /* gettimeofday() */ + #include /* get..() */ + #include /* printf() */ + #include /* clock() */ + #include /* uname() */ + #include "global.h" /* from RFC 1321 */ + #include "md5.h" /* from RFC 1321 */ + + #define MD_CTX MD5_CTX + #define MDInit MD5Init + #define MDUpdate MD5Update + #define MDFinal MD5Final + + static u_long md_32(char *string, int length) + { + MD_CTX context; + union { + char c[16]; + u_long x[4]; + } digest; + u_long r; + int i; + + MDInit (&context); + + + +Schulzrinne, et al. Standards Track [Page 86] + +RFC 3550 RTP July 2003 + + + MDUpdate (&context, string, length); + MDFinal ((unsigned char *)&digest, &context); + r = 0; + for (i = 0; i < 3; i++) { + r ^= digest.x[i]; + } + return r; + } /* md_32 */ + + /* + * Return random unsigned 32-bit quantity. Use 'type' argument if + * you need to generate several different values in close succession. + */ + u_int32 random32(int type) + { + struct { + int type; + struct timeval tv; + clock_t cpu; + pid_t pid; + u_long hid; + uid_t uid; + gid_t gid; + struct utsname name; + } s; + + gettimeofday(&s.tv, 0); + uname(&s.name); + s.type = type; + s.cpu = clock(); + s.pid = getpid(); + s.hid = gethostid(); + s.uid = getuid(); + s.gid = getgid(); + /* also: system uptime */ + + return md_32((char *)&s, sizeof(s)); + } /* random32 */ + +A.7 Computing the RTCP Transmission Interval + + The following functions implement the RTCP transmission and reception + rules described in Section 6.2. These rules are coded in several + functions: + + o rtcp_interval() computes the deterministic calculated interval, + measured in seconds. The parameters are defined in Section 6.3. + + + + +Schulzrinne, et al. Standards Track [Page 87] + +RFC 3550 RTP July 2003 + + + o OnExpire() is called when the RTCP transmission timer expires. + + o OnReceive() is called whenever an RTCP packet is received. + + Both OnExpire() and OnReceive() have event e as an argument. This is + the next scheduled event for that participant, either an RTCP report + or a BYE packet. It is assumed that the following functions are + available: + + o Schedule(time t, event e) schedules an event e to occur at time t. + When time t arrives, the function OnExpire is called with e as an + argument. + + o Reschedule(time t, event e) reschedules a previously scheduled + event e for time t. + + o SendRTCPReport(event e) sends an RTCP report. + + o SendBYEPacket(event e) sends a BYE packet. + + o TypeOfEvent(event e) returns EVENT_BYE if the event being + processed is for a BYE packet to be sent, else it returns + EVENT_REPORT. + + o PacketType(p) returns PACKET_RTCP_REPORT if packet p is an RTCP + report (not BYE), PACKET_BYE if its a BYE RTCP packet, and + PACKET_RTP if its a regular RTP data packet. + + o ReceivedPacketSize() and SentPacketSize() return the size of the + referenced packet in octets. + + o NewMember(p) returns a 1 if the participant who sent packet p is + not currently in the member list, 0 otherwise. Note this function + is not sufficient for a complete implementation because each CSRC + identifier in an RTP packet and each SSRC in a BYE packet should + be processed. + + o NewSender(p) returns a 1 if the participant who sent packet p is + not currently in the sender sublist of the member list, 0 + otherwise. + + o AddMember() and RemoveMember() to add and remove participants from + the member list. + + o AddSender() and RemoveSender() to add and remove participants from + the sender sublist of the member list. + + + + + +Schulzrinne, et al. Standards Track [Page 88] + +RFC 3550 RTP July 2003 + + + These functions would have to be extended for an implementation that + allows the RTCP bandwidth fractions for senders and non-senders to be + specified as explicit parameters rather than fixed values of 25% and + 75%. The extended implementation of rtcp_interval() would need to + avoid division by zero if one of the parameters was zero. + + double rtcp_interval(int members, + int senders, + double rtcp_bw, + int we_sent, + double avg_rtcp_size, + int initial) + { + /* + * Minimum average time between RTCP packets from this site (in + * seconds). This time prevents the reports from `clumping' when + * sessions are small and the law of large numbers isn't helping + * to smooth out the traffic. It also keeps the report interval + * from becoming ridiculously small during transient outages like + * a network partition. + */ + double const RTCP_MIN_TIME = 5.; + /* + * Fraction of the RTCP bandwidth to be shared among active + * senders. (This fraction was chosen so that in a typical + * session with one or two active senders, the computed report + * time would be roughly equal to the minimum report time so that + * we don't unnecessarily slow down receiver reports.) The + * receiver fraction must be 1 - the sender fraction. + */ + double const RTCP_SENDER_BW_FRACTION = 0.25; + double const RTCP_RCVR_BW_FRACTION = (1-RTCP_SENDER_BW_FRACTION); + /* + /* To compensate for "timer reconsideration" converging to a + * value below the intended average. + */ + double const COMPENSATION = 2.71828 - 1.5; + + double t; /* interval */ + double rtcp_min_time = RTCP_MIN_TIME; + int n; /* no. of members for computation */ + + /* + * Very first call at application start-up uses half the min + * delay for quicker notification while still allowing some time + * before reporting for randomization and to learn about other + * sources so the report interval will converge to the correct + * interval more quickly. + + + +Schulzrinne, et al. Standards Track [Page 89] + +RFC 3550 RTP July 2003 + + + */ + if (initial) { + rtcp_min_time /= 2; + } + /* + * Dedicate a fraction of the RTCP bandwidth to senders unless + * the number of senders is large enough that their share is + * more than that fraction. + */ + n = members; + if (senders <= members * RTCP_SENDER_BW_FRACTION) { + if (we_sent) { + rtcp_bw *= RTCP_SENDER_BW_FRACTION; + n = senders; + } else { + rtcp_bw *= RTCP_RCVR_BW_FRACTION; + n -= senders; + } + } + + /* + * The effective number of sites times the average packet size is + * the total number of octets sent when each site sends a report. + * Dividing this by the effective bandwidth gives the time + * interval over which those packets must be sent in order to + * meet the bandwidth target, with a minimum enforced. In that + * time interval we send one report so this time is also our + * average time between reports. + */ + t = avg_rtcp_size * n / rtcp_bw; + if (t < rtcp_min_time) t = rtcp_min_time; + + /* + * To avoid traffic bursts from unintended synchronization with + * other sites, we then pick our actual next report interval as a + * random number uniformly distributed between 0.5*t and 1.5*t. + */ + t = t * (drand48() + 0.5); + t = t / COMPENSATION; + return t; + } + + void OnExpire(event e, + int members, + int senders, + double rtcp_bw, + int we_sent, + double *avg_rtcp_size, + + + +Schulzrinne, et al. Standards Track [Page 90] + +RFC 3550 RTP July 2003 + + + int *initial, + time_tp tc, + time_tp *tp, + int *pmembers) + { + /* This function is responsible for deciding whether to send an + * RTCP report or BYE packet now, or to reschedule transmission. + * It is also responsible for updating the pmembers, initial, tp, + * and avg_rtcp_size state variables. This function should be + * called upon expiration of the event timer used by Schedule(). + */ + + double t; /* Interval */ + double tn; /* Next transmit time */ + + /* In the case of a BYE, we use "timer reconsideration" to + * reschedule the transmission of the BYE if necessary */ + + if (TypeOfEvent(e) == EVENT_BYE) { + t = rtcp_interval(members, + senders, + rtcp_bw, + we_sent, + *avg_rtcp_size, + *initial); + tn = *tp + t; + if (tn <= tc) { + SendBYEPacket(e); + exit(1); + } else { + Schedule(tn, e); + } + + } else if (TypeOfEvent(e) == EVENT_REPORT) { + t = rtcp_interval(members, + senders, + rtcp_bw, + we_sent, + *avg_rtcp_size, + *initial); + tn = *tp + t; + if (tn <= tc) { + SendRTCPReport(e); + *avg_rtcp_size = (1./16.)*SentPacketSize(e) + + (15./16.)*(*avg_rtcp_size); + *tp = tc; + + /* We must redraw the interval. Don't reuse the + + + +Schulzrinne, et al. Standards Track [Page 91] + +RFC 3550 RTP July 2003 + + + one computed above, since its not actually + distributed the same, as we are conditioned + on it being small enough to cause a packet to + be sent */ + + t = rtcp_interval(members, + senders, + rtcp_bw, + we_sent, + *avg_rtcp_size, + *initial); + + Schedule(t+tc,e); + *initial = 0; + } else { + Schedule(tn, e); + } + *pmembers = members; + } + } + + void OnReceive(packet p, + event e, + int *members, + int *pmembers, + int *senders, + double *avg_rtcp_size, + double *tp, + double tc, + double tn) + { + /* What we do depends on whether we have left the group, and are + * waiting to send a BYE (TypeOfEvent(e) == EVENT_BYE) or an RTCP + * report. p represents the packet that was just received. */ + + if (PacketType(p) == PACKET_RTCP_REPORT) { + if (NewMember(p) && (TypeOfEvent(e) == EVENT_REPORT)) { + AddMember(p); + *members += 1; + } + *avg_rtcp_size = (1./16.)*ReceivedPacketSize(p) + + (15./16.)*(*avg_rtcp_size); + } else if (PacketType(p) == PACKET_RTP) { + if (NewMember(p) && (TypeOfEvent(e) == EVENT_REPORT)) { + AddMember(p); + *members += 1; + } + if (NewSender(p) && (TypeOfEvent(e) == EVENT_REPORT)) { + + + +Schulzrinne, et al. Standards Track [Page 92] + +RFC 3550 RTP July 2003 + + + AddSender(p); + *senders += 1; + } + } else if (PacketType(p) == PACKET_BYE) { + *avg_rtcp_size = (1./16.)*ReceivedPacketSize(p) + + (15./16.)*(*avg_rtcp_size); + + if (TypeOfEvent(e) == EVENT_REPORT) { + if (NewSender(p) == FALSE) { + RemoveSender(p); + *senders -= 1; + } + + if (NewMember(p) == FALSE) { + RemoveMember(p); + *members -= 1; + } + + if (*members < *pmembers) { + tn = tc + + (((double) *members)/(*pmembers))*(tn - tc); + *tp = tc - + (((double) *members)/(*pmembers))*(tc - *tp); + + /* Reschedule the next report for time tn */ + + Reschedule(tn, e); + *pmembers = *members; + } + + } else if (TypeOfEvent(e) == EVENT_BYE) { + *members += 1; + } + } + } + + + + + + + + + + + + + + + + +Schulzrinne, et al. Standards Track [Page 93] + +RFC 3550 RTP July 2003 + + +A.8 Estimating the Interarrival Jitter + + The code fragments below implement the algorithm given in Section + 6.4.1 for calculating an estimate of the statistical variance of the + RTP data interarrival time to be inserted in the interarrival jitter + field of reception reports. The inputs are r->ts, the timestamp from + the incoming packet, and arrival, the current time in the same units. + Here s points to state for the source; s->transit holds the relative + transit time for the previous packet, and s->jitter holds the + estimated jitter. The jitter field of the reception report is + measured in timestamp units and expressed as an unsigned integer, but + the jitter estimate is kept in a floating point. As each data packet + arrives, the jitter estimate is updated: + + int transit = arrival - r->ts; + int d = transit - s->transit; + s->transit = transit; + if (d < 0) d = -d; + s->jitter += (1./16.) * ((double)d - s->jitter); + + When a reception report block (to which rr points) is generated for + this member, the current jitter estimate is returned: + + rr->jitter = (u_int32) s->jitter; + + Alternatively, the jitter estimate can be kept as an integer, but + scaled to reduce round-off error. The calculation is the same except + for the last line: + + s->jitter += d - ((s->jitter + 8) >> 4); + + In this case, the estimate is sampled for the reception report as: + + rr->jitter = s->jitter >> 4; + + + + + + + + + + + + + + + + + +Schulzrinne, et al. Standards Track [Page 94] + +RFC 3550 RTP July 2003 + + +Appendix B - Changes from RFC 1889 + + Most of this RFC is identical to RFC 1889. There are no changes in + the packet formats on the wire, only changes to the rules and + algorithms governing how the protocol is used. The biggest change is + an enhancement to the scalable timer algorithm for calculating when + to send RTCP packets: + + o The algorithm for calculating the RTCP transmission interval + specified in Sections 6.2 and 6.3 and illustrated in Appendix A.7 + is augmented to include "reconsideration" to minimize transmission + in excess of the intended rate when many participants join a + session simultaneously, and "reverse reconsideration" to reduce + the incidence and duration of false participant timeouts when the + number of participants drops rapidly. Reverse reconsideration is + also used to possibly shorten the delay before sending RTCP SR + when transitioning from passive receiver to active sender mode. + + o Section 6.3.7 specifies new rules controlling when an RTCP BYE + packet should be sent in order to avoid a flood of packets when + many participants leave a session simultaneously. + + o The requirement to retain state for inactive participants for a + period long enough to span typical network partitions was removed + from Section 6.2.1. In a session where many participants join for + a brief time and fail to send BYE, this requirement would cause a + significant overestimate of the number of participants. The + reconsideration algorithm added in this revision compensates for + the large number of new participants joining simultaneously when a + partition heals. + + It should be noted that these enhancements only have a significant + effect when the number of session participants is large (thousands) + and most of the participants join or leave at the same time. This + makes testing in a live network difficult. However, the algorithm + was subjected to a thorough analysis and simulation to verify its + performance. Furthermore, the enhanced algorithm was designed to + interoperate with the algorithm in RFC 1889 such that the degree of + reduction in excess RTCP bandwidth during a step join is proportional + to the fraction of participants that implement the enhanced + algorithm. Interoperation of the two algorithms has been verified + experimentally on live networks. + + Other functional changes were: + + o Section 6.2.1 specifies that implementations may store only a + sampling of the participants' SSRC identifiers to allow scaling to + very large sessions. Algorithms are specified in RFC 2762 [21]. + + + +Schulzrinne, et al. Standards Track [Page 95] + +RFC 3550 RTP July 2003 + + + o In Section 6.2 it is specified that RTCP sender and non-sender + bandwidths may be set as separate parameters of the session rather + than a strict percentage of the session bandwidth, and may be set + to zero. The requirement that RTCP was mandatory for RTP sessions + using IP multicast was relaxed. However, a clarification was also + added that turning off RTCP is NOT RECOMMENDED. + + o In Sections 6.2, 6.3.1 and Appendix A.7, it is specified that the + fraction of participants below which senders get dedicated RTCP + bandwidth changes from the fixed 1/4 to a ratio based on the RTCP + sender and non-sender bandwidth parameters when those are given. + The condition that no bandwidth is dedicated to senders when there + are no senders was removed since that is expected to be a + transitory state. It also keeps non-senders from using sender + RTCP bandwidth when that is not intended. + + o Also in Section 6.2 it is specified that the minimum RTCP interval + may be scaled to smaller values for high bandwidth sessions, and + that the initial RTCP delay may be set to zero for unicast + sessions. + + o Timing out a participant is to be based on inactivity for a number + of RTCP report intervals calculated using the receiver RTCP + bandwidth fraction even for active senders. + + o Sections 7.2 and 7.3 specify that translators and mixers should + send BYE packets for the sources they are no longer forwarding. + + o Rule changes for layered encodings are defined in Sections 2.4, + 6.3.9, 8.3 and 11. In the last of these, it is noted that the + address and port assignment rule conflicts with the SDP + specification, RFC 2327 [15], but it is intended that this + restriction will be relaxed in a revision of RFC 2327. + + o The convention for using even/odd port pairs for RTP and RTCP in + Section 11 was clarified to refer to destination ports. The + requirement to use an even/odd port pair was removed if the two + ports are specified explicitly. For unicast RTP sessions, + distinct port pairs may be used for the two ends (Sections 3, 7.1 + and 11). + + o A new Section 10 was added to explain the requirement for + congestion control in applications using RTP. + + o In Section 8.2, the requirement that a new SSRC identifier MUST be + chosen whenever the source transport address is changed has been + relaxed to say that a new SSRC identifier MAY be chosen. + Correspondingly, it was clarified that an implementation MAY + + + +Schulzrinne, et al. Standards Track [Page 96] + +RFC 3550 RTP July 2003 + + + choose to keep packets from the new source address rather than the + existing source address when an SSRC collision occurs between two + other participants, and SHOULD do so for applications such as + telephony in which some sources such as mobile entities may change + addresses during the course of an RTP session. + + o An indentation bug in the RFC 1889 printing of the pseudo-code for + the collision detection and resolution algorithm in Section 8.2 + has been corrected by translating the syntax to pseudo C language, + and the algorithm has been modified to remove the restriction that + both RTP and RTCP must be sent from the same source port number. + + o The description of the padding mechanism for RTCP packets was + clarified and it is specified that padding MUST only be applied to + the last packet of a compound RTCP packet. + + o In Section A.1, initialization of base_seq was corrected to be seq + rather than seq - 1, and the text was corrected to say the bad + sequence number plus 1 is stored. The initialization of max_seq + and other variables for the algorithm was separated from the text + to make clear that this initialization must be done in addition to + calling the init_seq() function (and a few words lost in RFC 1889 + when processing the document from source to output form were + restored). + + o Clamping of number of packets lost in Section A.3 was corrected to + use both positive and negative limits. + + o The specification of "relative" NTP timestamp in the RTCP SR + section now defines these timestamps to be based on the most + common system-specific clock, such as system uptime, rather than + on session elapsed time which would not be the same for multiple + applications started on the same machine at different times. + + Non-functional changes: + + o It is specified that a receiver MUST ignore packets with payload + types it does not understand. + + o In Fig. 2, the floating point NTP timestamp value was corrected, + some missing leading zeros were added in a hex number, and the UTC + timezone was specified. + + o The inconsequence of NTP timestamps wrapping around in the year + 2036 is explained. + + + + + + +Schulzrinne, et al. Standards Track [Page 97] + +RFC 3550 RTP July 2003 + + + o The policy for registration of RTCP packet types and SDES types + was clarified in a new Section 15, IANA Considerations. The + suggestion that experimenters register the numbers they need and + then unregister those which prove to be unneeded has been removed + in favor of using APP and PRIV. Registration of profile names was + also specified. + + o The reference for the UTF-8 character set was changed from an + X/Open Preliminary Specification to be RFC 2279. + + o The reference for RFC 1597 was updated to RFC 1918 and the + reference for RFC 2543 was updated to RFC 3261. + + o The last paragraph of the introduction in RFC 1889, which + cautioned implementors to limit deployment in the Internet, was + removed because it was deemed no longer relevant. + + o A non-normative note regarding the use of RTP with Source-Specific + Multicast (SSM) was added in Section 6. + + o The definition of "RTP session" in Section 3 was expanded to + acknowledge that a single session may use multiple destination + transport addresses (as was always the case for a translator or + mixer) and to explain that the distinguishing feature of an RTP + session is that each corresponds to a separate SSRC identifier + space. A new definition of "multimedia session" was added to + reduce confusion about the word "session". + + o The meaning of "sampling instant" was explained in more detail as + part of the definition of the timestamp field of the RTP header in + Section 5.1. + + o Small clarifications of the text have been made in several places, + some in response to questions from readers. In particular: + + - In RFC 1889, the first five words of the second sentence of + Section 2.2 were lost in processing the document from source to + output form, but are now restored. + + - A definition for "RTP media type" was added in Section 3 to + allow the explanation of multiplexing RTP sessions in Section + 5.2 to be more clear regarding the multiplexing of multiple + media. That section also now explains that multiplexing + multiple sources of the same medium based on SSRC identifiers + may be appropriate and is the norm for multicast sessions. + + - The definition for "non-RTP means" was expanded to include + examples of other protocols constituting non-RTP means. + + + +Schulzrinne, et al. Standards Track [Page 98] + +RFC 3550 RTP July 2003 + + + - The description of the session bandwidth parameter is expanded + in Section 6.2, including a clarification that the control + traffic bandwidth is in addition to the session bandwidth for + the data traffic. + + - The effect of varying packet duration on the jitter calculation + was explained in Section 6.4.4. + + - The method for terminating and padding a sequence of SDES items + was clarified in Section 6.5. + + - IPv6 address examples were added in the description of SDES + CNAME in Section 6.5.1, and "example.com" was used in place of + other example domain names. + + - The Security section added a formal reference to IPSEC now that + it is available, and says that the confidentiality method + defined in this specification is primarily to codify existing + practice. It is RECOMMENDED that stronger encryption + algorithms such as Triple-DES be used in place of the default + algorithm, and noted that the SRTP profile based on AES will be + the correct choice in the future. A caution about the weakness + of the RTP header as an initialization vector was added. It + was also noted that payload-only encryption is necessary to + allow for header compression. + + - The method for partial encryption of RTCP was clarified; in + particular, SDES CNAME is carried in only one part when the + compound RTCP packet is split. + + - It is clarified that only one compound RTCP packet should be + sent per reporting interval and that if there are too many + active sources for the reports to fit in the MTU, then a subset + of the sources should be selected round-robin over multiple + intervals. + + - A note was added in Appendix A.1 that packets may be saved + during RTP header validation and delivered upon success. + + - Section 7.3 now explains that a mixer aggregating SDES packets + uses more RTCP bandwidth due to longer packets, and a mixer + passing through RTCP naturally sends packets at higher than the + single source rate, but both behaviors are valid. + + - Section 13 clarifies that an RTP application may use multiple + profiles but typically only one in a given session. + + + + + +Schulzrinne, et al. Standards Track [Page 99] + +RFC 3550 RTP July 2003 + + + - The terms MUST, SHOULD, MAY, etc. are used as defined in RFC + 2119. + + - The bibliography was divided into normative and informative + references. + +References + +Normative References + + [1] Schulzrinne, H. and S. Casner, "RTP Profile for Audio and Video + Conferences with Minimal Control", RFC 3551, July 2003. + + [2] Bradner, S., "Key Words for Use in RFCs to Indicate Requirement + Levels", BCP 14, RFC 2119, March 1997. + + [3] Postel, J., "Internet Protocol", STD 5, RFC 791, September 1981. + + [4] Mills, D., "Network Time Protocol (Version 3) Specification, + Implementation and Analysis", RFC 1305, March 1992. + + [5] Yergeau, F., "UTF-8, a Transformation Format of ISO 10646", RFC + 2279, January 1998. + + [6] Mockapetris, P., "Domain Names - Concepts and Facilities", STD + 13, RFC 1034, November 1987. + + [7] Mockapetris, P., "Domain Names - Implementation and + Specification", STD 13, RFC 1035, November 1987. + + [8] Braden, R., "Requirements for Internet Hosts - Application and + Support", STD 3, RFC 1123, October 1989. + + [9] Resnick, P., "Internet Message Format", RFC 2822, April 2001. + +Informative References + + [10] Clark, D. and D. Tennenhouse, "Architectural Considerations for + a New Generation of Protocols," in SIGCOMM Symposium on + Communications Architectures and Protocols , (Philadelphia, + Pennsylvania), pp. 200--208, IEEE Computer Communications + Review, Vol. 20(4), September 1990. + + [11] Schulzrinne, H., "Issues in designing a transport protocol for + audio and video conferences and other multiparticipant real-time + applications." expired Internet Draft, October 1993. + + + + + +Schulzrinne, et al. Standards Track [Page 100] + +RFC 3550 RTP July 2003 + + + [12] Comer, D., Internetworking with TCP/IP , vol. 1. Englewood + Cliffs, New Jersey: Prentice Hall, 1991. + + [13] Rosenberg, J., Schulzrinne, H., Camarillo, G., Johnston, A., + Peterson, J., Sparks, R., Handley, M. and E. Schooler, "SIP: + Session Initiation Protocol", RFC 3261, June 2002. + + [14] International Telecommunication Union, "Visual telephone systems + and equipment for local area networks which provide a non- + guaranteed quality of service", Recommendation H.323, + Telecommunication Standardization Sector of ITU, Geneva, + Switzerland, July 2003. + + [15] Handley, M. and V. Jacobson, "SDP: Session Description + Protocol", RFC 2327, April 1998. + + [16] Schulzrinne, H., Rao, A. and R. Lanphier, "Real Time Streaming + Protocol (RTSP)", RFC 2326, April 1998. + + [17] Eastlake 3rd, D., Crocker, S. and J. Schiller, "Randomness + Recommendations for Security", RFC 1750, December 1994. + + [18] Bolot, J.-C., Turletti, T. and I. Wakeman, "Scalable Feedback + Control for Multicast Video Distribution in the Internet", in + SIGCOMM Symposium on Communications Architectures and Protocols, + (London, England), pp. 58--67, ACM, August 1994. + + [19] Busse, I., Deffner, B. and H. Schulzrinne, "Dynamic QoS Control + of Multimedia Applications Based on RTP", Computer + Communications , vol. 19, pp. 49--58, January 1996. + + [20] Floyd, S. and V. Jacobson, "The Synchronization of Periodic + Routing Messages", in SIGCOMM Symposium on Communications + Architectures and Protocols (D. P. Sidhu, ed.), (San Francisco, + California), pp. 33--44, ACM, September 1993. Also in [34]. + + [21] Rosenberg, J. and H. Schulzrinne, "Sampling of the Group + Membership in RTP", RFC 2762, February 2000. + + [22] Cadzow, J., Foundations of Digital Signal Processing and Data + Analysis New York, New York: Macmillan, 1987. + + [23] Hinden, R. and S. Deering, "Internet Protocol Version 6 (IPv6) + Addressing Architecture", RFC 3513, April 2003. + + [24] Rekhter, Y., Moskowitz, B., Karrenberg, D., de Groot, G. and E. + Lear, "Address Allocation for Private Internets", RFC 1918, + February 1996. + + + +Schulzrinne, et al. Standards Track [Page 101] + +RFC 3550 RTP July 2003 + + + [25] Lear, E., Fair, E., Crocker, D. and T. Kessler, "Network 10 + Considered Harmful (Some Practices Shouldn't be Codified)", RFC + 1627, July 1994. + + [26] Feller, W., An Introduction to Probability Theory and its + Applications, vol. 1. New York, New York: John Wiley and Sons, + third ed., 1968. + + [27] Kent, S. and R. Atkinson, "Security Architecture for the + Internet Protocol", RFC 2401, November 1998. + + [28] Baugher, M., Blom, R., Carrara, E., McGrew, D., Naslund, M., + Norrman, K. and D. Oran, "Secure Real-time Transport Protocol", + Work in Progress, April 2003. + + [29] Balenson, D., "Privacy Enhancement for Internet Electronic Mail: + Part III", RFC 1423, February 1993. + + [30] Voydock, V. and S. Kent, "Security Mechanisms in High-Level + Network Protocols", ACM Computing Surveys, vol. 15, pp. 135-171, + June 1983. + + [31] Floyd, S., "Congestion Control Principles", BCP 41, RFC 2914, + September 2000. + + [32] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321, April + 1992. + + [33] Stubblebine, S., "Security Services for Multimedia + Conferencing", in 16th National Computer Security Conference, + (Baltimore, Maryland), pp. 391--395, September 1993. + + [34] Floyd, S. and V. Jacobson, "The Synchronization of Periodic + Routing Messages", IEEE/ACM Transactions on Networking, vol. 2, + pp. 122--136, April 1994. + + + + + + + + + + + + + + + + +Schulzrinne, et al. Standards Track [Page 102] + +RFC 3550 RTP July 2003 + + +Authors' Addresses + + Henning Schulzrinne + Department of Computer Science + Columbia University + 1214 Amsterdam Avenue + New York, NY 10027 + United States + + EMail: schulzrinne@cs.columbia.edu + + + Stephen L. Casner + Packet Design + 3400 Hillview Avenue, Building 3 + Palo Alto, CA 94304 + United States + + EMail: casner@acm.org + + + Ron Frederick + Blue Coat Systems Inc. + 650 Almanor Avenue + Sunnyvale, CA 94085 + United States + + EMail: ronf@bluecoat.com + + + Van Jacobson + Packet Design + 3400 Hillview Avenue, Building 3 + Palo Alto, CA 94304 + United States + + EMail: van@packetdesign.com + + + + + + + + + + + + + + +Schulzrinne, et al. Standards Track [Page 103] + +RFC 3550 RTP July 2003 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Schulzrinne, et al. Standards Track [Page 104] + diff --git a/src/modules/rtp/rfc3551.txt b/src/modules/rtp/rfc3551.txt new file mode 100644 index 00000000..c43ff34d --- /dev/null +++ b/src/modules/rtp/rfc3551.txt @@ -0,0 +1,2467 @@ + + + + + + +Network Working Group H. Schulzrinne +Request for Comments: 3551 Columbia University +Obsoletes: 1890 S. Casner +Category: Standards Track Packet Design + July 2003 + + + RTP Profile for Audio and Video Conferences + with Minimal Control + +Status of this Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + +Abstract + + This document describes a profile called "RTP/AVP" for the use of the + real-time transport protocol (RTP), version 2, and the associated + control protocol, RTCP, within audio and video multiparticipant + conferences with minimal control. It provides interpretations of + generic fields within the RTP specification suitable for audio and + video conferences. In particular, this document defines a set of + default mappings from payload type numbers to encodings. + + This document also describes how audio and video data may be carried + within RTP. It defines a set of standard encodings and their names + when used within RTP. The descriptions provide pointers to reference + implementations and the detailed standards. This document is meant + as an aid for implementors of audio, video and other real-time + multimedia applications. + + This memorandum obsoletes RFC 1890. It is mostly backwards- + compatible except for functions removed because two interoperable + implementations were not found. The additions to RFC 1890 codify + existing practice in the use of payload formats under this profile + and include new payload formats defined since RFC 1890 was published. + + + + + + + +Schulzrinne & Casner Standards Track [Page 1] + +RFC 3551 RTP A/V Profile July 2003 + + +Table of Contents + + 1. Introduction ................................................. 3 + 1.1 Terminology ............................................. 3 + 2. RTP and RTCP Packet Forms and Protocol Behavior .............. 4 + 3. Registering Additional Encodings ............................. 6 + 4. Audio ........................................................ 8 + 4.1 Encoding-Independent Rules .............................. 8 + 4.2 Operating Recommendations ............................... 9 + 4.3 Guidelines for Sample-Based Audio Encodings ............. 10 + 4.4 Guidelines for Frame-Based Audio Encodings .............. 11 + 4.5 Audio Encodings ......................................... 12 + 4.5.1 DVI4 ............................................ 13 + 4.5.2 G722 ............................................ 14 + 4.5.3 G723 ............................................ 14 + 4.5.4 G726-40, G726-32, G726-24, and G726-16 .......... 18 + 4.5.5 G728 ............................................ 19 + 4.5.6 G729 ............................................ 20 + 4.5.7 G729D and G729E ................................. 22 + 4.5.8 GSM ............................................. 24 + 4.5.9 GSM-EFR ......................................... 27 + 4.5.10 L8 .............................................. 27 + 4.5.11 L16 ............................................. 27 + 4.5.12 LPC ............................................. 27 + 4.5.13 MPA ............................................. 28 + 4.5.14 PCMA and PCMU ................................... 28 + 4.5.15 QCELP ........................................... 28 + 4.5.16 RED ............................................. 29 + 4.5.17 VDVI ............................................ 29 + 5. Video ........................................................ 30 + 5.1 CelB .................................................... 30 + 5.2 JPEG .................................................... 30 + 5.3 H261 .................................................... 30 + 5.4 H263 .................................................... 31 + 5.5 H263-1998 ............................................... 31 + 5.6 MPV ..................................................... 31 + 5.7 MP2T .................................................... 31 + 5.8 nv ...................................................... 32 + 6. Payload Type Definitions ..................................... 32 + 7. RTP over TCP and Similar Byte Stream Protocols ............... 34 + 8. Port Assignment .............................................. 34 + 9. Changes from RFC 1890 ........................................ 35 + 10. Security Considerations ...................................... 38 + 11. IANA Considerations .......................................... 39 + 12. References ................................................... 39 + 12.1 Normative References .................................... 39 + 12.2 Informative References .................................. 39 + 13. Current Locations of Related Resources ....................... 41 + + + +Schulzrinne & Casner Standards Track [Page 2] + +RFC 3551 RTP A/V Profile July 2003 + + + 14. Acknowledgments .............................................. 42 + 15. Intellectual Property Rights Statement ....................... 43 + 16. Authors' Addresses ........................................... 43 + 17. Full Copyright Statement ..................................... 44 + +1. Introduction + + This profile defines aspects of RTP left unspecified in the RTP + Version 2 protocol definition (RFC 3550) [1]. This profile is + intended for the use within audio and video conferences with minimal + session control. In particular, no support for the negotiation of + parameters or membership control is provided. The profile is + expected to be useful in sessions where no negotiation or membership + control are used (e.g., using the static payload types and the + membership indications provided by RTCP), but this profile may also + be useful in conjunction with a higher-level control protocol. + + Use of this profile may be implicit in the use of the appropriate + applications; there may be no explicit indication by port number, + protocol identifier or the like. Applications such as session + directories may use the name for this profile specified in Section + 11. + + Other profiles may make different choices for the items specified + here. + + This document also defines a set of encodings and payload formats for + audio and video. These payload format descriptions are included here + only as a matter of convenience since they are too small to warrant + separate documents. Use of these payload formats is NOT REQUIRED to + use this profile. Only the binding of some of the payload formats to + static payload type numbers in Tables 4 and 5 is normative. + +1.1 Terminology + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119 [2] and + indicate requirement levels for implementations compliant with this + RTP profile. + + This document defines the term media type as dividing encodings of + audio and video content into three classes: audio, video and + audio/video (interleaved). + + + + + + + +Schulzrinne & Casner Standards Track [Page 3] + +RFC 3551 RTP A/V Profile July 2003 + + +2. RTP and RTCP Packet Forms and Protocol Behavior + + The section "RTP Profiles and Payload Format Specifications" of RFC + 3550 enumerates a number of items that can be specified or modified + in a profile. This section addresses these items. Generally, this + profile follows the default and/or recommended aspects of the RTP + specification. + + RTP data header: The standard format of the fixed RTP data + header is used (one marker bit). + + Payload types: Static payload types are defined in Section 6. + + RTP data header additions: No additional fixed fields are + appended to the RTP data header. + + RTP data header extensions: No RTP header extensions are + defined, but applications operating under this profile MAY use + such extensions. Thus, applications SHOULD NOT assume that the + RTP header X bit is always zero and SHOULD be prepared to ignore + the header extension. If a header extension is defined in the + future, that definition MUST specify the contents of the first 16 + bits in such a way that multiple different extensions can be + identified. + + RTCP packet types: No additional RTCP packet types are defined + by this profile specification. + + RTCP report interval: The suggested constants are to be used for + the RTCP report interval calculation. Sessions operating under + this profile MAY specify a separate parameter for the RTCP traffic + bandwidth rather than using the default fraction of the session + bandwidth. The RTCP traffic bandwidth MAY be divided into two + separate session parameters for those participants which are + active data senders and those which are not. Following the + recommendation in the RTP specification [1] that 1/4 of the RTCP + bandwidth be dedicated to data senders, the RECOMMENDED default + values for these two parameters would be 1.25% and 3.75%, + respectively. For a particular session, the RTCP bandwidth for + non-data-senders MAY be set to zero when operating on + unidirectional links or for sessions that don't require feedback + on the quality of reception. The RTCP bandwidth for data senders + SHOULD be kept non-zero so that sender reports can still be sent + for inter-media synchronization and to identify the source by + CNAME. The means by which the one or two session parameters for + RTCP bandwidth are specified is beyond the scope of this memo. + + + + + +Schulzrinne & Casner Standards Track [Page 4] + +RFC 3551 RTP A/V Profile July 2003 + + + SR/RR extension: No extension section is defined for the RTCP SR + or RR packet. + + SDES use: Applications MAY use any of the SDES items described + in the RTP specification. While CNAME information MUST be sent + every reporting interval, other items SHOULD only be sent every + third reporting interval, with NAME sent seven out of eight times + within that slot and the remaining SDES items cyclically taking up + the eighth slot, as defined in Section 6.2.2 of the RTP + specification. In other words, NAME is sent in RTCP packets 1, 4, + 7, 10, 13, 16, 19, while, say, EMAIL is used in RTCP packet 22. + + Security: The RTP default security services are also the default + under this profile. + + String-to-key mapping: No mapping is specified by this profile. + + Congestion: RTP and this profile may be used in the context of + enhanced network service, for example, through Integrated Services + (RFC 1633) [4] or Differentiated Services (RFC 2475) [5], or they + may be used with best effort service. + + If enhanced service is being used, RTP receivers SHOULD monitor + packet loss to ensure that the service that was requested is + actually being delivered. If it is not, then they SHOULD assume + that they are receiving best-effort service and behave + accordingly. + + If best-effort service is being used, RTP receivers SHOULD monitor + packet loss to ensure that the packet loss rate is within + acceptable parameters. Packet loss is considered acceptable if a + TCP flow across the same network path and experiencing the same + network conditions would achieve an average throughput, measured + on a reasonable timescale, that is not less than the RTP flow is + achieving. This condition can be satisfied by implementing + congestion control mechanisms to adapt the transmission rate (or + the number of layers subscribed for a layered multicast session), + or by arranging for a receiver to leave the session if the loss + rate is unacceptably high. + + The comparison to TCP cannot be specified exactly, but is intended + as an "order-of-magnitude" comparison in timescale and throughput. + The timescale on which TCP throughput is measured is the round- + trip time of the connection. In essence, this requirement states + that it is not acceptable to deploy an application (using RTP or + any other transport protocol) on the best-effort Internet which + consumes bandwidth arbitrarily and does not compete fairly with + TCP within an order of magnitude. + + + +Schulzrinne & Casner Standards Track [Page 5] + +RFC 3551 RTP A/V Profile July 2003 + + + Underlying protocol: The profile specifies the use of RTP over + unicast and multicast UDP as well as TCP. (This does not preclude + the use of these definitions when RTP is carried by other lower- + layer protocols.) + + Transport mapping: The standard mapping of RTP and RTCP to + transport-level addresses is used. + + Encapsulation: This profile leaves to applications the + specification of RTP encapsulation in protocols other than UDP. + +3. Registering Additional Encodings + + This profile lists a set of encodings, each of which is comprised of + a particular media data compression or representation plus a payload + format for encapsulation within RTP. Some of those payload formats + are specified here, while others are specified in separate RFCs. It + is expected that additional encodings beyond the set listed here will + be created in the future and specified in additional payload format + RFCs. + + This profile also assigns to each encoding a short name which MAY be + used by higher-level control protocols, such as the Session + Description Protocol (SDP), RFC 2327 [6], to identify encodings + selected for a particular RTP session. + + In some contexts it may be useful to refer to these encodings in the + form of a MIME content-type. To facilitate this, RFC 3555 [7] + provides registrations for all of the encodings names listed here as + MIME subtype names under the "audio" and "video" MIME types through + the MIME registration procedure as specified in RFC 2048 [8]. + + Any additional encodings specified for use under this profile (or + others) may also be assigned names registered as MIME subtypes with + the Internet Assigned Numbers Authority (IANA). This registry + provides a means to insure that the names assigned to the additional + encodings are kept unique. RFC 3555 specifies the information that + is required for the registration of RTP encodings. + + In addition to assigning names to encodings, this profile also + assigns static RTP payload type numbers to some of them. However, + the payload type number space is relatively small and cannot + accommodate assignments for all existing and future encodings. + During the early stages of RTP development, it was necessary to use + statically assigned payload types because no other mechanism had been + specified to bind encodings to payload types. It was anticipated + that non-RTP means beyond the scope of this memo (such as directory + services or invitation protocols) would be specified to establish a + + + +Schulzrinne & Casner Standards Track [Page 6] + +RFC 3551 RTP A/V Profile July 2003 + + + dynamic mapping between a payload type and an encoding. Now, + mechanisms for defining dynamic payload type bindings have been + specified in the Session Description Protocol (SDP) and in other + protocols such as ITU-T Recommendation H.323/H.245. These mechanisms + associate the registered name of the encoding/payload format, along + with any additional required parameters, such as the RTP timestamp + clock rate and number of channels, with a payload type number. This + association is effective only for the duration of the RTP session in + which the dynamic payload type binding is made. This association + applies only to the RTP session for which it is made, thus the + numbers can be re-used for different encodings in different sessions + so the number space limitation is avoided. + + This profile reserves payload type numbers in the range 96-127 + exclusively for dynamic assignment. Applications SHOULD first use + values in this range for dynamic payload types. Those applications + which need to define more than 32 dynamic payload types MAY bind + codes below 96, in which case it is RECOMMENDED that unassigned + payload type numbers be used first. However, the statically assigned + payload types are default bindings and MAY be dynamically bound to + new encodings if needed. Redefining payload types below 96 may cause + incorrect operation if an attempt is made to join a session without + obtaining session description information that defines the dynamic + payload types. + + Dynamic payload types SHOULD NOT be used without a well-defined + mechanism to indicate the mapping. Systems that expect to + interoperate with others operating under this profile SHOULD NOT make + their own assignments of proprietary encodings to particular, fixed + payload types. + + This specification establishes the policy that no additional static + payload types will be assigned beyond the ones defined in this + document. Establishing this policy avoids the problem of trying to + create a set of criteria for accepting static assignments and + encourages the implementation and deployment of the dynamic payload + type mechanisms. + + The final set of static payload type assignments is provided in + Tables 4 and 5. + + + + + + + + + + + +Schulzrinne & Casner Standards Track [Page 7] + +RFC 3551 RTP A/V Profile July 2003 + + +4. Audio + +4.1 Encoding-Independent Rules + + Since the ability to suppress silence is one of the primary + motivations for using packets to transmit voice, the RTP header + carries both a sequence number and a timestamp to allow a receiver to + distinguish between lost packets and periods of time when no data was + transmitted. Discontiguous transmission (silence suppression) MAY be + used with any audio payload format. Receivers MUST assume that + senders may suppress silence unless this is restricted by signaling + specified elsewhere. (Even if the transmitter does not suppress + silence, the receiver should be prepared to handle periods when no + data is present since packets may be lost.) + + Some payload formats (see Sections 4.5.3 and 4.5.6) define a "silence + insertion descriptor" or "comfort noise" frame to specify parameters + for artificial noise that may be generated during a period of silence + to approximate the background noise at the source. For other payload + formats, a generic Comfort Noise (CN) payload format is specified in + RFC 3389 [9]. When the CN payload format is used with another + payload format, different values in the RTP payload type field + distinguish comfort-noise packets from those of the selected payload + format. + + For applications which send either no packets or occasional comfort- + noise packets during silence, the first packet of a talkspurt, that + is, the first packet after a silence period during which packets have + not been transmitted contiguously, SHOULD be distinguished by setting + the marker bit in the RTP data header to one. The marker bit in all + other packets is zero. The beginning of a talkspurt MAY be used to + adjust the playout delay to reflect changing network delays. + Applications without silence suppression MUST set the marker bit to + zero. + + The RTP clock rate used for generating the RTP timestamp is + independent of the number of channels and the encoding; it usually + equals the number of sampling periods per second. For N-channel + encodings, each sampling period (say, 1/8,000 of a second) generates + N samples. (This terminology is standard, but somewhat confusing, as + the total number of samples generated per second is then the sampling + rate times the channel count.) + + If multiple audio channels are used, channels are numbered left-to- + right, starting at one. In RTP audio packets, information from + lower-numbered channels precedes that from higher-numbered channels. + + + + + +Schulzrinne & Casner Standards Track [Page 8] + +RFC 3551 RTP A/V Profile July 2003 + + + For more than two channels, the convention followed by the AIFF-C + audio interchange format SHOULD be followed [3], using the following + notation, unless some other convention is specified for a particular + encoding or payload format: + + l left + r right + c center + S surround + F front + R rear + + channels description channel + 1 2 3 4 5 6 + _________________________________________________ + 2 stereo l r + 3 l r c + 4 l c r S + 5 Fl Fr Fc Sl Sr + 6 l lc c r rc S + + Note: RFC 1890 defined two conventions for the ordering of four + audio channels. Since the ordering is indicated implicitly by + the number of channels, this was ambiguous. In this revision, + the order described as "quadrophonic" has been eliminated to + remove the ambiguity. This choice was based on the observation + that quadrophonic consumer audio format did not become popular + whereas surround-sound subsequently has. + + Samples for all channels belonging to a single sampling instant MUST + be within the same packet. The interleaving of samples from + different channels depends on the encoding. General guidelines are + given in Section 4.3 and 4.4. + + The sampling frequency SHOULD be drawn from the set: 8,000, 11,025, + 16,000, 22,050, 24,000, 32,000, 44,100 and 48,000 Hz. (Older Apple + Macintosh computers had a native sample rate of 22,254.54 Hz, which + can be converted to 22,050 with acceptable quality by dropping 4 + samples in a 20 ms frame.) However, most audio encodings are defined + for a more restricted set of sampling frequencies. Receivers SHOULD + be prepared to accept multi-channel audio, but MAY choose to only + play a single channel. + +4.2 Operating Recommendations + + The following recommendations are default operating parameters. + Applications SHOULD be prepared to handle other values. The ranges + given are meant to give guidance to application writers, allowing a + + + +Schulzrinne & Casner Standards Track [Page 9] + +RFC 3551 RTP A/V Profile July 2003 + + + set of applications conforming to these guidelines to interoperate + without additional negotiation. These guidelines are not intended to + restrict operating parameters for applications that can negotiate a + set of interoperable parameters, e.g., through a conference control + protocol. + + For packetized audio, the default packetization interval SHOULD have + a duration of 20 ms or one frame, whichever is longer, unless + otherwise noted in Table 1 (column "ms/packet"). The packetization + interval determines the minimum end-to-end delay; longer packets + introduce less header overhead but higher delay and make packet loss + more noticeable. For non-interactive applications such as lectures + or for links with severe bandwidth constraints, a higher + packetization delay MAY be used. A receiver SHOULD accept packets + representing between 0 and 200 ms of audio data. (For framed audio + encodings, a receiver SHOULD accept packets with a number of frames + equal to 200 ms divided by the frame duration, rounded up.) This + restriction allows reasonable buffer sizing for the receiver. + +4.3 Guidelines for Sample-Based Audio Encodings + + In sample-based encodings, each audio sample is represented by a + fixed number of bits. Within the compressed audio data, codes for + individual samples may span octet boundaries. An RTP audio packet + may contain any number of audio samples, subject to the constraint + that the number of bits per sample times the number of samples per + packet yields an integral octet count. Fractional encodings produce + less than one octet per sample. + + The duration of an audio packet is determined by the number of + samples in the packet. + + For sample-based encodings producing one or more octets per sample, + samples from different channels sampled at the same sampling instant + SHOULD be packed in consecutive octets. For example, for a two- + channel encoding, the octet sequence is (left channel, first sample), + (right channel, first sample), (left channel, second sample), (right + channel, second sample), .... For multi-octet encodings, octets + SHOULD be transmitted in network byte order (i.e., most significant + octet first). + + The packing of sample-based encodings producing less than one octet + per sample is encoding-specific. + + The RTP timestamp reflects the instant at which the first sample in + the packet was sampled, that is, the oldest information in the + packet. + + + + +Schulzrinne & Casner Standards Track [Page 10] + +RFC 3551 RTP A/V Profile July 2003 + + +4.4 Guidelines for Frame-Based Audio Encodings + + Frame-based encodings encode a fixed-length block of audio into + another block of compressed data, typically also of fixed length. + For frame-based encodings, the sender MAY choose to combine several + such frames into a single RTP packet. The receiver can tell the + number of frames contained in an RTP packet, if all the frames have + the same length, by dividing the RTP payload length by the audio + frame size which is defined as part of the encoding. This does not + work when carrying frames of different sizes unless the frame sizes + are relatively prime. If not, the frames MUST indicate their size. + + For frame-based codecs, the channel order is defined for the whole + block. That is, for two-channel audio, right and left samples SHOULD + be coded independently, with the encoded frame for the left channel + preceding that for the right channel. + + All frame-oriented audio codecs SHOULD be able to encode and decode + several consecutive frames within a single packet. Since the frame + size for the frame-oriented codecs is given, there is no need to use + a separate designation for the same encoding, but with different + number of frames per packet. + + RTP packets SHALL contain a whole number of frames, with frames + inserted according to age within a packet, so that the oldest frame + (to be played first) occurs immediately after the RTP packet header. + The RTP timestamp reflects the instant at which the first sample in + the first frame was sampled, that is, the oldest information in the + packet. + + + + + + + + + + + + + + + + + + + + + + +Schulzrinne & Casner Standards Track [Page 11] + +RFC 3551 RTP A/V Profile July 2003 + + +4.5 Audio Encodings + + name of sampling default + encoding sample/frame bits/sample rate ms/frame ms/packet + __________________________________________________________________ + DVI4 sample 4 var. 20 + G722 sample 8 16,000 20 + G723 frame N/A 8,000 30 30 + G726-40 sample 5 8,000 20 + G726-32 sample 4 8,000 20 + G726-24 sample 3 8,000 20 + G726-16 sample 2 8,000 20 + G728 frame N/A 8,000 2.5 20 + G729 frame N/A 8,000 10 20 + G729D frame N/A 8,000 10 20 + G729E frame N/A 8,000 10 20 + GSM frame N/A 8,000 20 20 + GSM-EFR frame N/A 8,000 20 20 + L8 sample 8 var. 20 + L16 sample 16 var. 20 + LPC frame N/A 8,000 20 20 + MPA frame N/A var. var. + PCMA sample 8 var. 20 + PCMU sample 8 var. 20 + QCELP frame N/A 8,000 20 20 + VDVI sample var. var. 20 + + Table 1: Properties of Audio Encodings (N/A: not applicable; var.: + variable) + + The characteristics of the audio encodings described in this document + are shown in Table 1; they are listed in order of their payload type + in Table 4. While most audio codecs are only specified for a fixed + sampling rate, some sample-based algorithms (indicated by an entry of + "var." in the sampling rate column of Table 1) may be used with + different sampling rates, resulting in different coded bit rates. + When used with a sampling rate other than that for which a static + payload type is defined, non-RTP means beyond the scope of this memo + MUST be used to define a dynamic payload type and MUST indicate the + selected RTP timestamp clock rate, which is usually the same as the + sampling rate for audio. + + + + + + + + + + +Schulzrinne & Casner Standards Track [Page 12] + +RFC 3551 RTP A/V Profile July 2003 + + +4.5.1 DVI4 + + DVI4 uses an adaptive delta pulse code modulation (ADPCM) encoding + scheme that was specified by the Interactive Multimedia Association + (IMA) as the "IMA ADPCM wave type". However, the encoding defined + here as DVI4 differs in three respects from the IMA specification: + + o The RTP DVI4 header contains the predicted value rather than the + first sample value contained the IMA ADPCM block header. + + o IMA ADPCM blocks contain an odd number of samples, since the first + sample of a block is contained just in the header (uncompressed), + followed by an even number of compressed samples. DVI4 has an + even number of compressed samples only, using the `predict' word + from the header to decode the first sample. + + o For DVI4, the 4-bit samples are packed with the first sample in + the four most significant bits and the second sample in the four + least significant bits. In the IMA ADPCM codec, the samples are + packed in the opposite order. + + Each packet contains a single DVI block. This profile only defines + the 4-bit-per-sample version, while IMA also specified a 3-bit-per- + sample encoding. + + The "header" word for each channel has the following structure: + + int16 predict; /* predicted value of first sample + from the previous block (L16 format) */ + u_int8 index; /* current index into stepsize table */ + u_int8 reserved; /* set to zero by sender, ignored by receiver */ + + Each octet following the header contains two 4-bit samples, thus the + number of samples per packet MUST be even because there is no means + to indicate a partially filled last octet. + + Packing of samples for multiple channels is for further study. + + The IMA ADPCM algorithm was described in the document IMA Recommended + Practices for Enhancing Digital Audio Compatibility in Multimedia + Systems (version 3.0). However, the Interactive Multimedia + Association ceased operations in 1997. Resources for an archived + copy of that document and a software implementation of the RTP DVI4 + encoding are listed in Section 13. + + + + + + + +Schulzrinne & Casner Standards Track [Page 13] + +RFC 3551 RTP A/V Profile July 2003 + + +4.5.2 G722 + + G722 is specified in ITU-T Recommendation G.722, "7 kHz audio-coding + within 64 kbit/s". The G.722 encoder produces a stream of octets, + each of which SHALL be octet-aligned in an RTP packet. The first bit + transmitted in the G.722 octet, which is the most significant bit of + the higher sub-band sample, SHALL correspond to the most significant + bit of the octet in the RTP packet. + + Even though the actual sampling rate for G.722 audio is 16,000 Hz, + the RTP clock rate for the G722 payload format is 8,000 Hz because + that value was erroneously assigned in RFC 1890 and must remain + unchanged for backward compatibility. The octet rate or sample-pair + rate is 8,000 Hz. + +4.5.3 G723 + + G723 is specified in ITU Recommendation G.723.1, "Dual-rate speech + coder for multimedia communications transmitting at 5.3 and 6.3 + kbit/s". The G.723.1 5.3/6.3 kbit/s codec was defined by the ITU-T + as a mandatory codec for ITU-T H.324 GSTN videophone terminal + applications. The algorithm has a floating point specification in + Annex B to G.723.1, a silence compression algorithm in Annex A to + G.723.1 and a scalable channel coding scheme for wireless + applications in G.723.1 Annex C. + + This Recommendation specifies a coded representation that can be used + for compressing the speech signal component of multi-media services + at a very low bit rate. Audio is encoded in 30 ms frames, with an + additional delay of 7.5 ms due to look-ahead. A G.723.1 frame can be + one of three sizes: 24 octets (6.3 kb/s frame), 20 octets (5.3 kb/s + frame), or 4 octets. These 4-octet frames are called SID frames + (Silence Insertion Descriptor) and are used to specify comfort noise + parameters. There is no restriction on how 4, 20, and 24 octet + frames are intermixed. The least significant two bits of the first + octet in the frame determine the frame size and codec type: + + bits content octets/frame + 00 high-rate speech (6.3 kb/s) 24 + 01 low-rate speech (5.3 kb/s) 20 + 10 SID frame 4 + 11 reserved + + + + + + + + + +Schulzrinne & Casner Standards Track [Page 14] + +RFC 3551 RTP A/V Profile July 2003 + + + It is possible to switch between the two rates at any 30 ms frame + boundary. Both (5.3 kb/s and 6.3 kb/s) rates are a mandatory part of + the encoder and decoder. Receivers MUST accept both data rates and + MUST accept SID frames unless restriction of these capabilities has + been signaled. The MIME registration for G723 in RFC 3555 [7] + specifies parameters that MAY be used with MIME or SDP to restrict to + a single data rate or to restrict the use of SID frames. This coder + was optimized to represent speech with near-toll quality at the above + rates using a limited amount of complexity. + + The packing of the encoded bit stream into octets and the + transmission order of the octets is specified in Rec. G.723.1 and is + the same as that produced by the G.723 C code reference + implementation. For the 6.3 kb/s data rate, this packing is + illustrated as follows, where the header (HDR) bits are always "0 0" + as shown in Fig. 1 to indicate operation at 6.3 kb/s, and the Z bit + is always set to zero. The diagrams show the bit packing in "network + byte order", also known as big-endian order. The bits of each 32-bit + word are numbered 0 to 31, with the most significant bit on the left + and numbered 0. The octets (bytes) of each word are transmitted most + significant octet first. The bits of each data field are numbered in + the order of the bit stream representation of the encoding (least + significant bit first). The vertical bars indicate the boundaries + between field fragments. + + + + + + + + + + + + + + + + + + + + + + + + + + + +Schulzrinne & Casner Standards Track [Page 15] + +RFC 3551 RTP A/V Profile July 2003 + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | LPC |HDR| LPC | LPC | ACL0 |LPC| + | | | | | | | + |0 0 0 0 0 0|0 0|1 1 1 1 0 0 0 0|2 2 1 1 1 1 1 1|0 0 0 0 0 0|2 2| + |5 4 3 2 1 0| |3 2 1 0 9 8 7 6|1 0 9 8 7 6 5 4|5 4 3 2 1 0|3 2| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ACL2 |ACL|A| GAIN0 |ACL|ACL| GAIN0 | GAIN1 | + | | 1 |C| | 3 | 2 | | | + |0 0 0 0 0|0 0|0|0 0 0 0|0 0|0 0|1 1 0 0 0 0 0 0|0 0 0 0 0 0 0 0| + |4 3 2 1 0|1 0|6|3 2 1 0|1 0|6 5|1 0 9 8 7 6 5 4|7 6 5 4 3 2 1 0| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | GAIN2 | GAIN1 | GAIN2 | GAIN3 | GRID | GAIN3 | + | | | | | | | + |0 0 0 0|1 1 0 0|1 1 0 0 0 0 0 0|0 0 0 0 0 0 0 0|0 0 0 0|1 1 0 0| + |3 2 1 0|1 0 9 8|1 0 9 8 7 6 5 4|7 6 5 4 3 2 1 0|3 2 1 0|1 0 9 8| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | MSBPOS |Z|POS| MSBPOS | POS0 |POS| POS0 | + | | | 0 | | | 1 | | + |0 0 0 0 0 0 0|0|0 0|1 1 1 0 0 0|0 0 0 0 0 0 0 0|0 0|1 1 1 1 1 1| + |6 5 4 3 2 1 0| |1 0|2 1 0 9 8 7|9 8 7 6 5 4 3 2|1 0|5 4 3 2 1 0| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | POS1 | POS2 | POS1 | POS2 | POS3 | POS2 | + | | | | | | | + |0 0 0 0 0 0 0 0|0 0 0 0|1 1 1 1|1 1 0 0 0 0 0 0|0 0 0 0|1 1 1 1| + |9 8 7 6 5 4 3 2|3 2 1 0|3 2 1 0|1 0 9 8 7 6 5 4|3 2 1 0|5 4 3 2| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | POS3 | PSIG0 |POS|PSIG2| PSIG1 | PSIG3 |PSIG2| + | | | 3 | | | | | + |1 1 0 0 0 0 0 0|0 0 0 0 0 0|1 1|0 0 0|0 0 0 0 0|0 0 0 0 0|0 0 0| + |1 0 9 8 7 6 5 4|5 4 3 2 1 0|3 2|2 1 0|4 3 2 1 0|4 3 2 1 0|5 4 3| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 1: G.723 (6.3 kb/s) bit packing + + For the 5.3 kb/s data rate, the header (HDR) bits are always "0 1", + as shown in Fig. 2, to indicate operation at 5.3 kb/s. + + + + + + + + + + + + + +Schulzrinne & Casner Standards Track [Page 16] + +RFC 3551 RTP A/V Profile July 2003 + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | LPC |HDR| LPC | LPC | ACL0 |LPC| + | | | | | | | + |0 0 0 0 0 0|0 1|1 1 1 1 0 0 0 0|2 2 1 1 1 1 1 1|0 0 0 0 0 0|2 2| + |5 4 3 2 1 0| |3 2 1 0 9 8 7 6|1 0 9 8 7 6 5 4|5 4 3 2 1 0|3 2| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ACL2 |ACL|A| GAIN0 |ACL|ACL| GAIN0 | GAIN1 | + | | 1 |C| | 3 | 2 | | | + |0 0 0 0 0|0 0|0|0 0 0 0|0 0|0 0|1 1 0 0 0 0 0 0|0 0 0 0 0 0 0 0| + |4 3 2 1 0|1 0|6|3 2 1 0|1 0|6 5|1 0 9 8 7 6 5 4|7 6 5 4 3 2 1 0| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | GAIN2 | GAIN1 | GAIN2 | GAIN3 | GRID | GAIN3 | + | | | | | | | + |0 0 0 0|1 1 0 0|1 1 0 0 0 0 0 0|0 0 0 0 0 0 0 0|0 0 0 0|1 1 0 0| + |3 2 1 0|1 0 9 8|1 0 9 8 7 6 5 4|7 6 5 4 3 2 1 0|4 3 2 1|1 0 9 8| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | POS0 | POS1 | POS0 | POS1 | POS2 | + | | | | | | + |0 0 0 0 0 0 0 0|0 0 0 0|1 1 0 0|1 1 0 0 0 0 0 0|0 0 0 0 0 0 0 0| + |7 6 5 4 3 2 1 0|3 2 1 0|1 0 9 8|1 0 9 8 7 6 5 4|7 6 5 4 3 2 1 0| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | POS3 | POS2 | POS3 | PSIG1 | PSIG0 | PSIG3 | PSIG2 | + | | | | | | | | + |0 0 0 0|1 1 0 0|1 1 0 0 0 0 0 0|0 0 0 0|0 0 0 0|0 0 0 0|0 0 0 0| + |3 2 1 0|1 0 9 8|1 0 9 8 7 6 5 4|3 2 1 0|3 2 1 0|3 2 1 0|3 2 1 0| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 2: G.723 (5.3 kb/s) bit packing + + The packing of G.723.1 SID (silence) frames, which are indicated by + the header (HDR) bits having the pattern "1 0", is depicted in Fig. + 3. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | LPC |HDR| LPC | LPC | GAIN |LPC| + | | | | | | | + |0 0 0 0 0 0|1 0|1 1 1 1 0 0 0 0|2 2 1 1 1 1 1 1|0 0 0 0 0 0|2 2| + |5 4 3 2 1 0| |3 2 1 0 9 8 7 6|1 0 9 8 7 6 5 4|5 4 3 2 1 0|3 2| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 3: G.723 SID mode bit packing + + + + + + +Schulzrinne & Casner Standards Track [Page 17] + +RFC 3551 RTP A/V Profile July 2003 + + +4.5.4 G726-40, G726-32, G726-24, and G726-16 + + ITU-T Recommendation G.726 describes, among others, the algorithm + recommended for conversion of a single 64 kbit/s A-law or mu-law PCM + channel encoded at 8,000 samples/sec to and from a 40, 32, 24, or 16 + kbit/s channel. The conversion is applied to the PCM stream using an + Adaptive Differential Pulse Code Modulation (ADPCM) transcoding + technique. The ADPCM representation consists of a series of + codewords with a one-to-one correspondence to the samples in the PCM + stream. The G726 data rates of 40, 32, 24, and 16 kbit/s have + codewords of 5, 4, 3, and 2 bits, respectively. + + The 16 and 24 kbit/s encodings do not provide toll quality speech. + They are designed for used in overloaded Digital Circuit + Multiplication Equipment (DCME). ITU-T G.726 recommends that the 16 + and 24 kbit/s encodings should be alternated with higher data rate + encodings to provide an average sample size of between 3.5 and 3.7 + bits per sample. + + The encodings of G.726 are here denoted as G726-40, G726-32, G726-24, + and G726-16. Prior to 1990, G721 described the 32 kbit/s ADPCM + encoding, and G723 described the 40, 32, and 16 kbit/s encodings. + Thus, G726-32 designates the same algorithm as G721 in RFC 1890. + + A stream of G726 codewords contains no information on the encoding + being used, therefore transitions between G726 encoding types are not + permitted within a sequence of packed codewords. Applications MUST + determine the encoding type of packed codewords from the RTP payload + identifier. + + No payload-specific header information SHALL be included as part of + the audio data. A stream of G726 codewords MUST be packed into + octets as follows: the first codeword is placed into the first octet + such that the least significant bit of the codeword aligns with the + least significant bit in the octet, the second codeword is then + packed so that its least significant bit coincides with the least + significant unoccupied bit in the octet. When a complete codeword + cannot be placed into an octet, the bits overlapping the octet + boundary are placed into the least significant bits of the next + octet. Packing MUST end with a completely packed final octet. The + number of codewords packed will therefore be a multiple of 8, 2, 8, + and 4 for G726-40, G726-32, G726-24, and G726-16, respectively. An + example of the packing scheme for G726-32 codewords is as shown, + where bit 7 is the least significant bit of the first octet, and bit + A3 is the least significant bit of the first codeword: + + + + + + +Schulzrinne & Casner Standards Track [Page 18] + +RFC 3551 RTP A/V Profile July 2003 + + + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- + |B B B B|A A A A|D D D D|C C C C| ... + |0 1 2 3|0 1 2 3|0 1 2 3|0 1 2 3| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- + + An example of the packing scheme for G726-24 codewords follows, where + again bit 7 is the least significant bit of the first octet, and bit + A2 is the least significant bit of the first codeword: + + 0 1 2 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- + |C C|B B B|A A A|F|E E E|D D D|C|H H H|G G G|F F| ... + |1 2|0 1 2|0 1 2|2|0 1 2|0 1 2|0|0 1 2|0 1 2|0 1| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- + + Note that the "little-endian" direction in which samples are packed + into octets in the G726-16, -24, -32 and -40 payload formats + specified here is consistent with ITU-T Recommendation X.420, but is + the opposite of what is specified in ITU-T Recommendation I.366.2 + Annex E for ATM AAL2 transport. A second set of RTP payload formats + matching the packetization of I.366.2 Annex E and identified by MIME + subtypes AAL2-G726-16, -24, -32 and -40 will be specified in a + separate document. + +4.5.5 G728 + + G728 is specified in ITU-T Recommendation G.728, "Coding of speech at + 16 kbit/s using low-delay code excited linear prediction". + + A G.278 encoder translates 5 consecutive audio samples into a 10-bit + codebook index, resulting in a bit rate of 16 kb/s for audio sampled + at 8,000 samples per second. The group of five consecutive samples + is called a vector. Four consecutive vectors, labeled V1 to V4 + (where V1 is to be played first by the receiver), build one G.728 + frame. The four vectors of 40 bits are packed into 5 octets, labeled + B1 through B5. B1 SHALL be placed first in the RTP packet. + + Referring to the figure below, the principle for bit order is + "maintenance of bit significance". Bits from an older vector are + more significant than bits from newer vectors. The MSB of the frame + goes to the MSB of B1 and the LSB of the frame goes to LSB of B5. + + + + + + + +Schulzrinne & Casner Standards Track [Page 19] + +RFC 3551 RTP A/V Profile July 2003 + + + 1 2 3 3 + 0 0 0 0 9 + ++++++++++++++++++++++++++++++++++++++++ + <---V1---><---V2---><---V3---><---V4---> vectors + <--B1--><--B2--><--B3--><--B4--><--B5--> octets + <------------- frame 1 ----------------> + + In particular, B1 contains the eight most significant bits of V1, + with the MSB of V1 being the MSB of B1. B2 contains the two least + significant bits of V1, the more significant of the two in its MSB, + and the six most significant bits of V2. B1 SHALL be placed first in + the RTP packet and B5 last. + +4.5.6 G729 + + G729 is specified in ITU-T Recommendation G.729, "Coding of speech at + 8 kbit/s using conjugate structure-algebraic code excited linear + prediction (CS-ACELP)". A reduced-complexity version of the G.729 + algorithm is specified in Annex A to Rec. G.729. The speech coding + algorithms in the main body of G.729 and in G.729 Annex A are fully + interoperable with each other, so there is no need to further + distinguish between them. An implementation that signals or accepts + use of G729 payload format may implement either G.729 or G.729A + unless restricted by additional signaling specified elsewhere related + specifically to the encoding rather than the payload format. The + G.729 and G.729 Annex A codecs were optimized to represent speech + with high quality, where G.729 Annex A trades some speech quality for + an approximate 50% complexity reduction [10]. See the next Section + (4.5.7) for other data rates added in later G.729 Annexes. For all + data rates, the sampling frequency (and RTP timestamp clock rate) is + 8,000 Hz. + + A voice activity detector (VAD) and comfort noise generator (CNG) + algorithm in Annex B of G.729 is RECOMMENDED for digital simultaneous + voice and data applications and can be used in conjunction with G.729 + or G.729 Annex A. A G.729 or G.729 Annex A frame contains 10 octets, + while the G.729 Annex B comfort noise frame occupies 2 octets. + Receivers MUST accept comfort noise frames if restriction of their + use has not been signaled. The MIME registration for G729 in RFC + 3555 [7] specifies a parameter that MAY be used with MIME or SDP to + restrict the use of comfort noise frames. + + A G729 RTP packet may consist of zero or more G.729 or G.729 Annex A + frames, followed by zero or one G.729 Annex B frames. The presence + of a comfort noise frame can be deduced from the length of the RTP + payload. The default packetization interval is 20 ms (two frames), + but in some situations it may be desirable to send 10 ms packets. An + + + + +Schulzrinne & Casner Standards Track [Page 20] + +RFC 3551 RTP A/V Profile July 2003 + + + example would be a transition from speech to comfort noise in the + first 10 ms of the packet. For some applications, a longer + packetization interval may be required to reduce the packet rate. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |L| L1 | L2 | L3 | P1 |P| C1 | + |0| | | | |0| | + | |0 1 2 3 4 5 6|0 1 2 3 4|0 1 2 3 4|0 1 2 3 4 5 6 7| |0 1 2 3 4| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | C1 | S1 | GA1 | GB1 | P2 | C2 | + | 1 1 1| | | | | | + |5 6 7 8 9 0 1 2|0 1 2 3|0 1 2|0 1 2 3|0 1 2 3 4|0 1 2 3 4 5 6 7| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | C2 | S2 | GA2 | GB2 | + | 1 1 1| | | | + |8 9 0 1 2|0 1 2 3|0 1 2|0 1 2 3| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 4: G.729 and G.729A bit packing + + The transmitted parameters of a G.729/G.729A 10-ms frame, consisting + of 80 bits, are defined in Recommendation G.729, Table 8/G.729. The + mapping of the these parameters is given below in Fig. 4. The + diagrams show the bit packing in "network byte order", also known as + big-endian order. The bits of each 32-bit word are numbered 0 to 31, + with the most significant bit on the left and numbered 0. The octets + (bytes) of each word are transmitted most significant octet first. + The bits of each data field are numbered in the order as produced by + the G.729 C code reference implementation. + + The packing of the G.729 Annex B comfort noise frame is shown in Fig. + 5. + + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |L| LSF1 | LSF2 | GAIN |R| + |S| | | |E| + |F| | | |S| + |0|0 1 2 3 4|0 1 2 3|0 1 2 3 4|V| RESV = Reserved (zero) + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 5: G.729 Annex B bit packing + + + + + + +Schulzrinne & Casner Standards Track [Page 21] + +RFC 3551 RTP A/V Profile July 2003 + + +4.5.7 G729D and G729E + + Annexes D and E to ITU-T Recommendation G.729 provide additional data + rates. Because the data rate is not signaled in the bitstream, the + different data rates are given distinct RTP encoding names which are + mapped to distinct payload type numbers. G729D indicates a 6.4 + kbit/s coding mode (G.729 Annex D, for momentary reduction in channel + capacity), while G729E indicates an 11.8 kbit/s mode (G.729 Annex E, + for improved performance with a wide range of narrow-band input + signals, e.g., music and background noise). Annex E has two + operating modes, backward adaptive and forward adaptive, which are + signaled by the first two bits in each frame (the most significant + two bits of the first octet). + + The voice activity detector (VAD) and comfort noise generator (CNG) + algorithm specified in Annex B of G.729 may be used with Annex D and + Annex E frames in addition to G.729 and G.729 Annex A frames. The + algorithm details for the operation of Annexes D and E with the Annex + B CNG are specified in G.729 Annexes F and G. Note that Annexes F + and G do not introduce any new encodings. Receivers MUST accept + comfort noise frames if restriction of their use has not been + signaled. The MIME registrations for G729D and G729E in RFC 3555 [7] + specify a parameter that MAY be used with MIME or SDP to restrict the + use of comfort noise frames. + + For G729D, an RTP packet may consist of zero or more G.729 Annex D + frames, followed by zero or one G.729 Annex B frame. Similarly, for + G729E, an RTP packet may consist of zero or more G.729 Annex E + frames, followed by zero or one G.729 Annex B frame. The presence of + a comfort noise frame can be deduced from the length of the RTP + payload. + + A single RTP packet must contain frames of only one data rate, + optionally followed by one comfort noise frame. The data rate may be + changed from packet to packet by changing the payload type number. + G.729 Annexes D, E and H describe what the encoding and decoding + algorithms must do to accommodate a change in data rate. + + For G729D, the bits of a G.729 Annex D frame are formatted as shown + below in Fig. 6 (cf. Table D.1/G.729). The frame length is 64 bits. + + + + + + + + + + + +Schulzrinne & Casner Standards Track [Page 22] + +RFC 3551 RTP A/V Profile July 2003 + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |L| L1 | L2 | L3 | P1 | C1 | + |0| | | | | | + | |0 1 2 3 4 5 6|0 1 2 3 4|0 1 2 3 4|0 1 2 3 4 5 6 7|0 1 2 3 4 5| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | C1 |S1 | GA1 | GB1 | P2 | C2 |S2 | GA2 | GB2 | + | | | | | | | | | | + |6 7 8|0 1|0 1 2|0 1 2|0 1 2 3|0 1 2 3 4 5 6 7 8|0 1|0 1 2|0 1 2| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 6: G.729 Annex D bit packing + + The net bit rate for the G.729 Annex E algorithm is 11.8 kbit/s and a + total of 118 bits are used. Two bits are appended as "don't care" + bits to complete an integer number of octets for the frame. For + G729E, the bits of a data frame are formatted as shown in the next + two diagrams (cf. Table E.1/G.729). The fields for the G729E forward + adaptive mode are packed as shown in Fig. 7. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |0 0|L| L1 | L2 | L3 | P1 |P| C0_1| + | |0| | | | |0| | + | | |0 1 2 3 4 5 6|0 1 2 3 4|0 1 2 3 4|0 1 2 3 4 5 6 7| |0 1 2| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | C1_1 | C2_1 | C3_1 | C4_1 | + | | | | | | + |3 4 5 6|0 1 2 3 4 5 6|0 1 2 3 4 5 6|0 1 2 3 4 5 6|0 1 2 3 4 5 6| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | GA1 | GB1 | P2 | C0_2 | C1_2 | C2_2 | + | | | | | | | + |0 1 2|0 1 2 3|0 1 2 3 4|0 1 2 3 4 5 6|0 1 2 3 4 5 6|0 1 2 3 4 5| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | C3_2 | C4_2 | GA2 | GB2 |DC | + | | | | | | | + |6|0 1 2 3 4 5 6|0 1 2 3 4 5 6|0 1 2|0 1 2 3|0 1| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 7: G.729 Annex E (forward adaptive mode) bit packing + + The fields for the G729E backward adaptive mode are packed as shown + in Fig. 8. + + + + + + +Schulzrinne & Casner Standards Track [Page 23] + +RFC 3551 RTP A/V Profile July 2003 + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |1 1| P1 |P| C0_1 | C1_1 | + | | |0| 1 1 1| | + | |0 1 2 3 4 5 6 7|0|0 1 2 3 4 5 6 7 8 9 0 1 2|0 1 2 3 4 5 6 7| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | C2_1 | C3_1 | C4_1 |GA1 | GB1 |P2 | + | | | | | | | | + |8 9|0 1 2 3 4 5 6|0 1 2 3 4 5 6|0 1 2 3 4 5 6|0 1 2|0 1 2 3|0 1| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | C0_2 | C1_2 | C2_2 | + | | 1 1 1| | | + |2 3 4|0 1 2 3 4 5 6 7 8 9 0 1 2|0 1 2 3 4 5 6 7 8 9|0 1 2 3 4 5| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | C3_2 | C4_2 | GA2 | GB2 |DC | + | | | | | | | + |6|0 1 2 3 4 5 6|0 1 2 3 4 5 6|0 1 2|0 1 2 3|0 1| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 8: G.729 Annex E (backward adaptive mode) bit packing + +4.5.8 GSM + + GSM (Group Speciale Mobile) denotes the European GSM 06.10 standard + for full-rate speech transcoding, ETS 300 961, which is based on + RPE/LTP (residual pulse excitation/long term prediction) coding at a + rate of 13 kb/s [11,12,13]. The text of the standard can be obtained + from: + + ETSI (European Telecommunications Standards Institute) + ETSI Secretariat: B.P.152 + F-06561 Valbonne Cedex + France + Phone: +33 92 94 42 00 + Fax: +33 93 65 47 16 + + Blocks of 160 audio samples are compressed into 33 octets, for an + effective data rate of 13,200 b/s. + +4.5.8.1 General Packaging Issues + + The GSM standard (ETS 300 961) specifies the bit stream produced by + the codec, but does not specify how these bits should be packed for + transmission. The packetization specified here has subsequently been + adopted in ETSI Technical Specification TS 101 318. Some software + implementations of the GSM codec use a different packing than that + specified here. + + + +Schulzrinne & Casner Standards Track [Page 24] + +RFC 3551 RTP A/V Profile July 2003 + + + field field name bits field field name bits + ________________________________________________ + 1 LARc[0] 6 39 xmc[22] 3 + 2 LARc[1] 6 40 xmc[23] 3 + 3 LARc[2] 5 41 xmc[24] 3 + 4 LARc[3] 5 42 xmc[25] 3 + 5 LARc[4] 4 43 Nc[2] 7 + 6 LARc[5] 4 44 bc[2] 2 + 7 LARc[6] 3 45 Mc[2] 2 + 8 LARc[7] 3 46 xmaxc[2] 6 + 9 Nc[0] 7 47 xmc[26] 3 + 10 bc[0] 2 48 xmc[27] 3 + 11 Mc[0] 2 49 xmc[28] 3 + 12 xmaxc[0] 6 50 xmc[29] 3 + 13 xmc[0] 3 51 xmc[30] 3 + 14 xmc[1] 3 52 xmc[31] 3 + 15 xmc[2] 3 53 xmc[32] 3 + 16 xmc[3] 3 54 xmc[33] 3 + 17 xmc[4] 3 55 xmc[34] 3 + 18 xmc[5] 3 56 xmc[35] 3 + 19 xmc[6] 3 57 xmc[36] 3 + 20 xmc[7] 3 58 xmc[37] 3 + 21 xmc[8] 3 59 xmc[38] 3 + 22 xmc[9] 3 60 Nc[3] 7 + 23 xmc[10] 3 61 bc[3] 2 + 24 xmc[11] 3 62 Mc[3] 2 + 25 xmc[12] 3 63 xmaxc[3] 6 + 26 Nc[1] 7 64 xmc[39] 3 + 27 bc[1] 2 65 xmc[40] 3 + 28 Mc[1] 2 66 xmc[41] 3 + 29 xmaxc[1] 6 67 xmc[42] 3 + 30 xmc[13] 3 68 xmc[43] 3 + 31 xmc[14] 3 69 xmc[44] 3 + 32 xmc[15] 3 70 xmc[45] 3 + 33 xmc[16] 3 71 xmc[46] 3 + 34 xmc[17] 3 72 xmc[47] 3 + 35 xmc[18] 3 73 xmc[48] 3 + 36 xmc[19] 3 74 xmc[49] 3 + 37 xmc[20] 3 75 xmc[50] 3 + 38 xmc[21] 3 76 xmc[51] 3 + + Table 2: Ordering of GSM variables + + + + + + + + + +Schulzrinne & Casner Standards Track [Page 25] + +RFC 3551 RTP A/V Profile July 2003 + + + Octet Bit 0 Bit 1 Bit 2 Bit 3 Bit 4 Bit 5 Bit 6 Bit 7 + _____________________________________________________________________ + 0 1 1 0 1 LARc0.0 LARc0.1 LARc0.2 LARc0.3 + 1 LARc0.4 LARc0.5 LARc1.0 LARc1.1 LARc1.2 LARc1.3 LARc1.4 LARc1.5 + 2 LARc2.0 LARc2.1 LARc2.2 LARc2.3 LARc2.4 LARc3.0 LARc3.1 LARc3.2 + 3 LARc3.3 LARc3.4 LARc4.0 LARc4.1 LARc4.2 LARc4.3 LARc5.0 LARc5.1 + 4 LARc5.2 LARc5.3 LARc6.0 LARc6.1 LARc6.2 LARc7.0 LARc7.1 LARc7.2 + 5 Nc0.0 Nc0.1 Nc0.2 Nc0.3 Nc0.4 Nc0.5 Nc0.6 bc0.0 + 6 bc0.1 Mc0.0 Mc0.1 xmaxc00 xmaxc01 xmaxc02 xmaxc03 xmaxc04 + 7 xmaxc05 xmc0.0 xmc0.1 xmc0.2 xmc1.0 xmc1.1 xmc1.2 xmc2.0 + 8 xmc2.1 xmc2.2 xmc3.0 xmc3.1 xmc3.2 xmc4.0 xmc4.1 xmc4.2 + 9 xmc5.0 xmc5.1 xmc5.2 xmc6.0 xmc6.1 xmc6.2 xmc7.0 xmc7.1 + 10 xmc7.2 xmc8.0 xmc8.1 xmc8.2 xmc9.0 xmc9.1 xmc9.2 xmc10.0 + 11 xmc10.1 xmc10.2 xmc11.0 xmc11.1 xmc11.2 xmc12.0 xmc12.1 xcm12.2 + 12 Nc1.0 Nc1.1 Nc1.2 Nc1.3 Nc1.4 Nc1.5 Nc1.6 bc1.0 + 13 bc1.1 Mc1.0 Mc1.1 xmaxc10 xmaxc11 xmaxc12 xmaxc13 xmaxc14 + 14 xmax15 xmc13.0 xmc13.1 xmc13.2 xmc14.0 xmc14.1 xmc14.2 xmc15.0 + 15 xmc15.1 xmc15.2 xmc16.0 xmc16.1 xmc16.2 xmc17.0 xmc17.1 xmc17.2 + 16 xmc18.0 xmc18.1 xmc18.2 xmc19.0 xmc19.1 xmc19.2 xmc20.0 xmc20.1 + 17 xmc20.2 xmc21.0 xmc21.1 xmc21.2 xmc22.0 xmc22.1 xmc22.2 xmc23.0 + 18 xmc23.1 xmc23.2 xmc24.0 xmc24.1 xmc24.2 xmc25.0 xmc25.1 xmc25.2 + 19 Nc2.0 Nc2.1 Nc2.2 Nc2.3 Nc2.4 Nc2.5 Nc2.6 bc2.0 + 20 bc2.1 Mc2.0 Mc2.1 xmaxc20 xmaxc21 xmaxc22 xmaxc23 xmaxc24 + 21 xmaxc25 xmc26.0 xmc26.1 xmc26.2 xmc27.0 xmc27.1 xmc27.2 xmc28.0 + 22 xmc28.1 xmc28.2 xmc29.0 xmc29.1 xmc29.2 xmc30.0 xmc30.1 xmc30.2 + 23 xmc31.0 xmc31.1 xmc31.2 xmc32.0 xmc32.1 xmc32.2 xmc33.0 xmc33.1 + 24 xmc33.2 xmc34.0 xmc34.1 xmc34.2 xmc35.0 xmc35.1 xmc35.2 xmc36.0 + 25 Xmc36.1 xmc36.2 xmc37.0 xmc37.1 xmc37.2 xmc38.0 xmc38.1 xmc38.2 + 26 Nc3.0 Nc3.1 Nc3.2 Nc3.3 Nc3.4 Nc3.5 Nc3.6 bc3.0 + 27 bc3.1 Mc3.0 Mc3.1 xmaxc30 xmaxc31 xmaxc32 xmaxc33 xmaxc34 + 28 xmaxc35 xmc39.0 xmc39.1 xmc39.2 xmc40.0 xmc40.1 xmc40.2 xmc41.0 + 29 xmc41.1 xmc41.2 xmc42.0 xmc42.1 xmc42.2 xmc43.0 xmc43.1 xmc43.2 + 30 xmc44.0 xmc44.1 xmc44.2 xmc45.0 xmc45.1 xmc45.2 xmc46.0 xmc46.1 + 31 xmc46.2 xmc47.0 xmc47.1 xmc47.2 xmc48.0 xmc48.1 xmc48.2 xmc49.0 + 32 xmc49.1 xmc49.2 xmc50.0 xmc50.1 xmc50.2 xmc51.0 xmc51.1 xmc51.2 + + Table 3: GSM payload format + + In the GSM packing used by RTP, the bits SHALL be packed beginning + from the most significant bit. Every 160 sample GSM frame is coded + into one 33 octet (264 bit) buffer. Every such buffer begins with a + 4 bit signature (0xD), followed by the MSB encoding of the fields of + the frame. The first octet thus contains 1101 in the 4 most + significant bits (0-3) and the 4 most significant bits of F1 (0-3) in + the 4 least significant bits (4-7). The second octet contains the 2 + least significant bits of F1 in bits 0-1, and F2 in bits 2-7, and so + on. The order of the fields in the frame is described in Table 2. + + + + +Schulzrinne & Casner Standards Track [Page 26] + +RFC 3551 RTP A/V Profile July 2003 + + +4.5.8.2 GSM Variable Names and Numbers + + In the RTP encoding we have the bit pattern described in Table 3, + where F.i signifies the ith bit of the field F, bit 0 is the most + significant bit, and the bits of every octet are numbered from 0 to 7 + from most to least significant. + +4.5.9 GSM-EFR + + GSM-EFR denotes GSM 06.60 enhanced full rate speech transcoding, + specified in ETS 300 726 which is available from ETSI at the address + given in Section 4.5.8. This codec has a frame length of 244 bits. + For transmission in RTP, each codec frame is packed into a 31 octet + (248 bit) buffer beginning with a 4-bit signature 0xC in a manner + similar to that specified here for the original GSM 06.10 codec. The + packing is specified in ETSI Technical Specification TS 101 318. + +4.5.10 L8 + + L8 denotes linear audio data samples, using 8-bits of precision with + an offset of 128, that is, the most negative signal is encoded as + zero. + +4.5.11 L16 + + L16 denotes uncompressed audio data samples, using 16-bit signed + representation with 65,535 equally divided steps between minimum and + maximum signal level, ranging from -32,768 to 32,767. The value is + represented in two's complement notation and transmitted in network + byte order (most significant byte first). + + The MIME registration for L16 in RFC 3555 [7] specifies parameters + that MAY be used with MIME or SDP to indicate that analog pre- + emphasis was applied to the signal before quantization or to indicate + that a multiple-channel audio stream follows a different channel + ordering convention than is specified in Section 4.1. + +4.5.12 LPC + + LPC designates an experimental linear predictive encoding contributed + by Ron Frederick, which is based on an implementation written by Ron + Zuckerman posted to the Usenet group comp.dsp on June 26, 1992. The + codec generates 14 octets for every frame. The framesize is set to + 20 ms, resulting in a bit rate of 5,600 b/s. + + + + + + + +Schulzrinne & Casner Standards Track [Page 27] + +RFC 3551 RTP A/V Profile July 2003 + + +4.5.13 MPA + + MPA denotes MPEG-1 or MPEG-2 audio encapsulated as elementary + streams. The encoding is defined in ISO standards ISO/IEC 11172-3 + and 13818-3. The encapsulation is specified in RFC 2250 [14]. + + The encoding may be at any of three levels of complexity, called + Layer I, II and III. The selected layer as well as the sampling rate + and channel count are indicated in the payload. The RTP timestamp + clock rate is always 90,000, independent of the sampling rate. + MPEG-1 audio supports sampling rates of 32, 44.1, and 48 kHz (ISO/IEC + 11172-3, section 1.1; "Scope"). MPEG-2 supports sampling rates of + 16, 22.05 and 24 kHz. The number of samples per frame is fixed, but + the frame size will vary with the sampling rate and bit rate. + + The MIME registration for MPA in RFC 3555 [7] specifies parameters + that MAY be used with MIME or SDP to restrict the selection of layer, + channel count, sampling rate, and bit rate. + +4.5.14 PCMA and PCMU + + PCMA and PCMU are specified in ITU-T Recommendation G.711. Audio + data is encoded as eight bits per sample, after logarithmic scaling. + PCMU denotes mu-law scaling, PCMA A-law scaling. A detailed + description is given by Jayant and Noll [15]. Each G.711 octet SHALL + be octet-aligned in an RTP packet. The sign bit of each G.711 octet + SHALL correspond to the most significant bit of the octet in the RTP + packet (i.e., assuming the G.711 samples are handled as octets on the + host machine, the sign bit SHALL be the most significant bit of the + octet as defined by the host machine format). The 56 kb/s and 48 + kb/s modes of G.711 are not applicable to RTP, since PCMA and PCMU + MUST always be transmitted as 8-bit samples. + + See Section 4.1 regarding silence suppression. + +4.5.15 QCELP + + The Electronic Industries Association (EIA) & Telecommunications + Industry Association (TIA) standard IS-733, "TR45: High Rate Speech + Service Option for Wideband Spread Spectrum Communications Systems", + defines the QCELP audio compression algorithm for use in wireless + CDMA applications. The QCELP CODEC compresses each 20 milliseconds + of 8,000 Hz, 16-bit sampled input speech into one of four different + size output frames: Rate 1 (266 bits), Rate 1/2 (124 bits), Rate 1/4 + (54 bits) or Rate 1/8 (20 bits). For typical speech patterns, this + results in an average output of 6.8 kb/s for normal mode and 4.7 kb/s + for reduced rate mode. The packetization of the QCELP audio codec is + described in [16]. + + + +Schulzrinne & Casner Standards Track [Page 28] + +RFC 3551 RTP A/V Profile July 2003 + + +4.5.16 RED + + The redundant audio payload format "RED" is specified by RFC 2198 + [17]. It defines a means by which multiple redundant copies of an + audio packet may be transmitted in a single RTP stream. Each packet + in such a stream contains, in addition to the audio data for that + packetization interval, a (more heavily compressed) copy of the data + from a previous packetization interval. This allows an approximation + of the data from lost packets to be recovered upon decoding of a + subsequent packet, giving much improved sound quality when compared + with silence substitution for lost packets. + +4.5.17 VDVI + + VDVI is a variable-rate version of DVI4, yielding speech bit rates of + between 10 and 25 kb/s. It is specified for single-channel operation + only. Samples are packed into octets starting at the most- + significant bit. The last octet is padded with 1 bits if the last + sample does not fill the last octet. This padding is distinct from + the valid codewords. The receiver needs to detect the padding + because there is no explicit count of samples in the packet. + + It uses the following encoding: + + DVI4 codeword VDVI bit pattern + _______________________________ + 0 00 + 1 010 + 2 1100 + 3 11100 + 4 111100 + 5 1111100 + 6 11111100 + 7 11111110 + 8 10 + 9 011 + 10 1101 + 11 11101 + 12 111101 + 13 1111101 + 14 11111101 + 15 11111111 + + + + + + + + + +Schulzrinne & Casner Standards Track [Page 29] + +RFC 3551 RTP A/V Profile July 2003 + + +5. Video + + The following sections describe the video encodings that are defined + in this memo and give their abbreviated names used for + identification. These video encodings and their payload types are + listed in Table 5. + + All of these video encodings use an RTP timestamp frequency of 90,000 + Hz, the same as the MPEG presentation time stamp frequency. This + frequency yields exact integer timestamp increments for the typical + 24 (HDTV), 25 (PAL), and 29.97 (NTSC) and 30 Hz (HDTV) frame rates + and 50, 59.94 and 60 Hz field rates. While 90 kHz is the RECOMMENDED + rate for future video encodings used within this profile, other rates + MAY be used. However, it is not sufficient to use the video frame + rate (typically between 15 and 30 Hz) because that does not provide + adequate resolution for typical synchronization requirements when + calculating the RTP timestamp corresponding to the NTP timestamp in + an RTCP SR packet. The timestamp resolution MUST also be sufficient + for the jitter estimate contained in the receiver reports. + + For most of these video encodings, the RTP timestamp encodes the + sampling instant of the video image contained in the RTP data packet. + If a video image occupies more than one packet, the timestamp is the + same on all of those packets. Packets from different video images + are distinguished by their different timestamps. + + Most of these video encodings also specify that the marker bit of the + RTP header SHOULD be set to one in the last packet of a video frame + and otherwise set to zero. Thus, it is not necessary to wait for a + following packet with a different timestamp to detect that a new + frame should be displayed. + +5.1 CelB + + The CELL-B encoding is a proprietary encoding proposed by Sun + Microsystems. The byte stream format is described in RFC 2029 [18]. + +5.2 JPEG + + The encoding is specified in ISO Standards 10918-1 and 10918-2. The + RTP payload format is as specified in RFC 2435 [19]. + +5.3 H261 + + The encoding is specified in ITU-T Recommendation H.261, "Video codec + for audiovisual services at p x 64 kbit/s". The packetization and + RTP-specific properties are described in RFC 2032 [20]. + + + + +Schulzrinne & Casner Standards Track [Page 30] + +RFC 3551 RTP A/V Profile July 2003 + + +5.4 H263 + + The encoding is specified in the 1996 version of ITU-T Recommendation + H.263, "Video coding for low bit rate communication". The + packetization and RTP-specific properties are described in RFC 2190 + [21]. The H263-1998 payload format is RECOMMENDED over this one for + use by new implementations. + +5.5 H263-1998 + + The encoding is specified in the 1998 version of ITU-T Recommendation + H.263, "Video coding for low bit rate communication". The + packetization and RTP-specific properties are described in RFC 2429 + [22]. Because the 1998 version of H.263 is a superset of the 1996 + syntax, this payload format can also be used with the 1996 version of + H.263, and is RECOMMENDED for this use by new implementations. This + payload format does not replace RFC 2190, which continues to be used + by existing implementations, and may be required for backward + compatibility in new implementations. Implementations using the new + features of the 1998 version of H.263 MUST use the payload format + described in RFC 2429. + +5.6 MPV + + MPV designates the use of MPEG-1 and MPEG-2 video encoding elementary + streams as specified in ISO Standards ISO/IEC 11172 and 13818-2, + respectively. The RTP payload format is as specified in RFC 2250 + [14], Section 3. + + The MIME registration for MPV in RFC 3555 [7] specifies a parameter + that MAY be used with MIME or SDP to restrict the selection of the + type of MPEG video. + +5.7 MP2T + + MP2T designates the use of MPEG-2 transport streams, for either audio + or video. The RTP payload format is described in RFC 2250 [14], + Section 2. + + + + + + + + + + + + + +Schulzrinne & Casner Standards Track [Page 31] + +RFC 3551 RTP A/V Profile July 2003 + + +5.8 nv + + The encoding is implemented in the program `nv', version 4, developed + at Xerox PARC by Ron Frederick. Further information is available + from the author: + + Ron Frederick + Blue Coat Systems Inc. + 650 Almanor Avenue + Sunnyvale, CA 94085 + United States + EMail: ronf@bluecoat.com + +6. Payload Type Definitions + + Tables 4 and 5 define this profile's static payload type values for + the PT field of the RTP data header. In addition, payload type + values in the range 96-127 MAY be defined dynamically through a + conference control protocol, which is beyond the scope of this + document. For example, a session directory could specify that for a + given session, payload type 96 indicates PCMU encoding, 8,000 Hz + sampling rate, 2 channels. Entries in Tables 4 and 5 with payload + type "dyn" have no static payload type assigned and are only used + with a dynamic payload type. Payload type 2 was assigned to G721 in + RFC 1890 and to its equivalent successor G726-32 in draft versions of + this specification, but its use is now deprecated and that static + payload type is marked reserved due to conflicting use for the + payload formats G726-32 and AAL2-G726-32 (see Section 4.5.4). + Payload type 13 indicates the Comfort Noise (CN) payload format + specified in RFC 3389 [9]. Payload type 19 is marked "reserved" + because some draft versions of this specification assigned that + number to an earlier version of the comfort noise payload format. + The payload type range 72-76 is marked "reserved" so that RTCP and + RTP packets can be reliably distinguished (see Section "Summary of + Protocol Constants" of the RTP protocol specification). + + The payload types currently defined in this profile are assigned to + exactly one of three categories or media types: audio only, video + only and those combining audio and video. The media types are marked + in Tables 4 and 5 as "A", "V" and "AV", respectively. Payload types + of different media types SHALL NOT be interleaved or multiplexed + within a single RTP session, but multiple RTP sessions MAY be used in + parallel to send multiple media types. An RTP source MAY change + payload types within the same media type during a session. See the + section "Multiplexing RTP Sessions" of RFC 3550 for additional + explanation. + + + + + +Schulzrinne & Casner Standards Track [Page 32] + +RFC 3551 RTP A/V Profile July 2003 + + + PT encoding media type clock rate channels + name (Hz) + ___________________________________________________ + 0 PCMU A 8,000 1 + 1 reserved A + 2 reserved A + 3 GSM A 8,000 1 + 4 G723 A 8,000 1 + 5 DVI4 A 8,000 1 + 6 DVI4 A 16,000 1 + 7 LPC A 8,000 1 + 8 PCMA A 8,000 1 + 9 G722 A 8,000 1 + 10 L16 A 44,100 2 + 11 L16 A 44,100 1 + 12 QCELP A 8,000 1 + 13 CN A 8,000 1 + 14 MPA A 90,000 (see text) + 15 G728 A 8,000 1 + 16 DVI4 A 11,025 1 + 17 DVI4 A 22,050 1 + 18 G729 A 8,000 1 + 19 reserved A + 20 unassigned A + 21 unassigned A + 22 unassigned A + 23 unassigned A + dyn G726-40 A 8,000 1 + dyn G726-32 A 8,000 1 + dyn G726-24 A 8,000 1 + dyn G726-16 A 8,000 1 + dyn G729D A 8,000 1 + dyn G729E A 8,000 1 + dyn GSM-EFR A 8,000 1 + dyn L8 A var. var. + dyn RED A (see text) + dyn VDVI A var. 1 + + Table 4: Payload types (PT) for audio encodings + + + + + + + + + + + + +Schulzrinne & Casner Standards Track [Page 33] + +RFC 3551 RTP A/V Profile July 2003 + + + PT encoding media type clock rate + name (Hz) + _____________________________________________ + 24 unassigned V + 25 CelB V 90,000 + 26 JPEG V 90,000 + 27 unassigned V + 28 nv V 90,000 + 29 unassigned V + 30 unassigned V + 31 H261 V 90,000 + 32 MPV V 90,000 + 33 MP2T AV 90,000 + 34 H263 V 90,000 + 35-71 unassigned ? + 72-76 reserved N/A N/A + 77-95 unassigned ? + 96-127 dynamic ? + dyn H263-1998 V 90,000 + + Table 5: Payload types (PT) for video and combined + encodings + + Session participants agree through mechanisms beyond the scope of + this specification on the set of payload types allowed in a given + session. This set MAY, for example, be defined by the capabilities + of the applications used, negotiated by a conference control protocol + or established by agreement between the human participants. + + Audio applications operating under this profile SHOULD, at a minimum, + be able to send and/or receive payload types 0 (PCMU) and 5 (DVI4). + This allows interoperability without format negotiation and ensures + successful negotiation with a conference control protocol. + +7. RTP over TCP and Similar Byte Stream Protocols + + Under special circumstances, it may be necessary to carry RTP in + protocols offering a byte stream abstraction, such as TCP, possibly + multiplexed with other data. The application MUST define its own + method of delineating RTP and RTCP packets (RTSP [23] provides an + example of such an encapsulation specification). + +8. Port Assignment + + As specified in the RTP protocol definition, RTP data SHOULD be + carried on an even UDP port number and the corresponding RTCP packets + SHOULD be carried on the next higher (odd) port number. + + + + +Schulzrinne & Casner Standards Track [Page 34] + +RFC 3551 RTP A/V Profile July 2003 + + + Applications operating under this profile MAY use any such UDP port + pair. For example, the port pair MAY be allocated randomly by a + session management program. A single fixed port number pair cannot + be required because multiple applications using this profile are + likely to run on the same host, and there are some operating systems + that do not allow multiple processes to use the same UDP port with + different multicast addresses. + + However, port numbers 5004 and 5005 have been registered for use with + this profile for those applications that choose to use them as the + default pair. Applications that operate under multiple profiles MAY + use this port pair as an indication to select this profile if they + are not subject to the constraint of the previous paragraph. + Applications need not have a default and MAY require that the port + pair be explicitly specified. The particular port numbers were + chosen to lie in the range above 5000 to accommodate port number + allocation practice within some versions of the Unix operating + system, where port numbers below 1024 can only be used by privileged + processes and port numbers between 1024 and 5000 are automatically + assigned by the operating system. + +9. Changes from RFC 1890 + + This RFC revises RFC 1890. It is mostly backwards-compatible with + RFC 1890 except for functions removed because two interoperable + implementations were not found. The additions to RFC 1890 codify + existing practice in the use of payload formats under this profile. + Since this profile may be used without using any of the payload + formats listed here, the addition of new payload formats in this + revision does not affect backwards compatibility. The changes are + listed below, categorized into functional and non-functional changes. + + Functional changes: + + o Section 11, "IANA Considerations" was added to specify the + registration of the name for this profile. That appendix also + references a new Section 3 "Registering Additional Encodings" + which establishes a policy that no additional registration of + static payload types for this profile will be made beyond those + added in this revision and included in Tables 4 and 5. Instead, + additional encoding names may be registered as MIME subtypes for + binding to dynamic payload types. Non-normative references were + added to RFC 3555 [7] where MIME subtypes for all the listed + payload formats are registered, some with optional parameters for + use of the payload formats. + + + + + + +Schulzrinne & Casner Standards Track [Page 35] + +RFC 3551 RTP A/V Profile July 2003 + + + o Static payload types 4, 16, 17 and 34 were added to incorporate + IANA registrations made since the publication of RFC 1890, along + with the corresponding payload format descriptions for G723 and + H263. + + o Following working group discussion, static payload types 12 and 18 + were added along with the corresponding payload format + descriptions for QCELP and G729. Static payload type 13 was + assigned to the Comfort Noise (CN) payload format defined in RFC + 3389. Payload type 19 was marked reserved because it had been + temporarily allocated to an earlier version of Comfort Noise + present in some draft revisions of this document. + + o The payload format for G721 was renamed to G726-32 following the + ITU-T renumbering, and the payload format description for G726 was + expanded to include the -16, -24 and -40 data rates. Because of + confusion regarding draft revisions of this document, some + implementations of these G726 payload formats packed samples into + octets starting with the most significant bit rather than the + least significant bit as specified here. To partially resolve + this incompatibility, new payload formats named AAL2-G726-16, -24, + -32 and -40 will be specified in a separate document (see note in + Section 4.5.4), and use of static payload type 2 is deprecated as + explained in Section 6. + + o Payload formats G729D and G729E were added following the ITU-T + addition of Annexes D and E to Recommendation G.729. Listings + were added for payload formats GSM-EFR, RED, and H263-1998 + published in other documents subsequent to RFC 1890. These + additional payload formats are referenced only by dynamic payload + type numbers. + + o The descriptions of the payload formats for G722, G728, GSM, VDVI + were expanded. + + o The payload format for 1016 audio was removed and its static + payload type assignment 1 was marked "reserved" because two + interoperable implementations were not found. + + o Requirements for congestion control were added in Section 2. + + o This profile follows the suggestion in the revised RTP spec that + RTCP bandwidth may be specified separately from the session + bandwidth and separately for active senders and passive receivers. + + o The mapping of a user pass-phrase string into an encryption key + was deleted from Section 2 because two interoperable + implementations were not found. + + + +Schulzrinne & Casner Standards Track [Page 36] + +RFC 3551 RTP A/V Profile July 2003 + + + o The "quadrophonic" sample ordering convention for four-channel + audio was removed to eliminate an ambiguity as noted in Section + 4.1. + + Non-functional changes: + + o In Section 4.1, it is now explicitly stated that silence + suppression is allowed for all audio payload formats. (This has + always been the case and derives from a fundamental aspect of + RTP's design and the motivations for packet audio, but was not + explicit stated before.) The use of comfort noise is also + explained. + + o In Section 4.1, the requirement level for setting of the marker + bit on the first packet after silence for audio was changed from + "is" to "SHOULD be", and clarified that the marker bit is set only + when packets are intentionally not sent. + + o Similarly, text was added to specify that the marker bit SHOULD be + set to one on the last packet of a video frame, and that video + frames are distinguished by their timestamps. + + o RFC references are added for payload formats published after RFC + 1890. + + o The security considerations and full copyright sections were + added. + + o According to Peter Hoddie of Apple, only pre-1994 Macintosh used + the 22254.54 rate and none the 11127.27 rate, so the latter was + dropped from the discussion of suggested sampling frequencies. + + o Table 1 was corrected to move some values from the "ms/packet" + column to the "default ms/packet" column where they belonged. + + o Since the Interactive Multimedia Association ceased operations, an + alternate resource was provided for a referenced IMA document. + + o A note has been added for G722 to clarify a discrepancy between + the actual sampling rate and the RTP timestamp clock rate. + + o Small clarifications of the text have been made in several places, + some in response to questions from readers. In particular: + + - A definition for "media type" is given in Section 1.1 to allow + the explanation of multiplexing RTP sessions in Section 6 to be + more clear regarding the multiplexing of multiple media. + + + + +Schulzrinne & Casner Standards Track [Page 37] + +RFC 3551 RTP A/V Profile July 2003 + + + - The explanation of how to determine the number of audio frames + in a packet from the length was expanded. + + - More description of the allocation of bandwidth to SDES items + is given. + + - A note was added that the convention for the order of channels + specified in Section 4.1 may be overridden by a particular + encoding or payload format specification. + + - The terms MUST, SHOULD, MAY, etc. are used as defined in RFC + 2119. + + o A second author for this document was added. + +10. Security Considerations + + Implementations using the profile defined in this specification are + subject to the security considerations discussed in the RTP + specification [1]. This profile does not specify any different + security services. The primary function of this profile is to list a + set of data compression encodings for audio and video media. + + Confidentiality of the media streams is achieved by encryption. + Because the data compression used with the payload formats described + in this profile is applied end-to-end, encryption may be performed + after compression so there is no conflict between the two operations. + + A potential denial-of-service threat exists for data encodings using + compression techniques that have non-uniform receiver-end + computational load. The attacker can inject pathological datagrams + into the stream which are complex to decode and cause the receiver to + be overloaded. + + As with any IP-based protocol, in some circumstances a receiver may + be overloaded simply by the receipt of too many packets, either + desired or undesired. Network-layer authentication MAY be used to + discard packets from undesired sources, but the processing cost of + the authentication itself may be too high. In a multicast + environment, source pruning is implemented in IGMPv3 (RFC 3376) [24] + and in multicast routing protocols to allow a receiver to select + which sources are allowed to reach it. + + + + + + + + + +Schulzrinne & Casner Standards Track [Page 38] + +RFC 3551 RTP A/V Profile July 2003 + + +11. IANA Considerations + + The RTP specification establishes a registry of profile names for use + by higher-level control protocols, such as the Session Description + Protocol (SDP), RFC 2327 [6], to refer to transport methods. This + profile registers the name "RTP/AVP". + + Section 3 establishes the policy that no additional registration of + static RTP payload types for this profile will be made beyond those + added in this document revision and included in Tables 4 and 5. IANA + may reference that section in declining to accept any additional + registration requests. In Tables 4 and 5, note that types 1 and 2 + have been marked reserved and the set of "dyn" payload types included + has been updated. These changes are explained in Sections 6 and 9. + +12. References + +12.1 Normative References + + [1] Schulzrinne, H., Casner, S., Frederick, R. and V. Jacobson, + "RTP: A Transport Protocol for Real-Time Applications", RFC + 3550, July 2003. + + [2] Bradner, S., "Key Words for Use in RFCs to Indicate Requirement + Levels", BCP 14, RFC 2119, March 1997. + + [3] Apple Computer, "Audio Interchange File Format AIFF-C", August + 1991. (also ftp://ftp.sgi.com/sgi/aiff-c.9.26.91.ps.Z). + +12.2 Informative References + + [4] Braden, R., Clark, D. and S. Shenker, "Integrated Services in + the Internet Architecture: an Overview", RFC 1633, June 1994. + + [5] Blake, S., Black, D., Carlson, M., Davies, E., Wang, Z. and W. + Weiss, "An Architecture for Differentiated Service", RFC 2475, + December 1998. + + [6] Handley, M. and V. Jacobson, "SDP: Session Description + Protocol", RFC 2327, April 1998. + + [7] Casner, S. and P. Hoschka, "MIME Type Registration of RTP + Payload Types", RFC 3555, July 2003. + + [8] Freed, N., Klensin, J. and J. Postel, "Multipurpose Internet + Mail Extensions (MIME) Part Four: Registration Procedures", BCP + 13, RFC 2048, November 1996. + + + + +Schulzrinne & Casner Standards Track [Page 39] + +RFC 3551 RTP A/V Profile July 2003 + + + [9] Zopf, R., "Real-time Transport Protocol (RTP) Payload for + Comfort Noise (CN)", RFC 3389, September 2002. + + [10] Deleam, D. and J.-P. Petit, "Real-time implementations of the + recent ITU-T low bit rate speech coders on the TI TMS320C54X + DSP: results, methodology, and applications", in Proc. of + International Conference on Signal Processing, Technology, and + Applications (ICSPAT) , (Boston, Massachusetts), pp. 1656--1660, + October 1996. + + [11] Mouly, M. and M.-B. Pautet, The GSM system for mobile + communications Lassay-les-Chateaux, France: Europe Media + Duplication, 1993. + + [12] Degener, J., "Digital Speech Compression", Dr. Dobb's Journal, + December 1994. + + [13] Redl, S., Weber, M. and M. Oliphant, An Introduction to GSM + Boston: Artech House, 1995. + + [14] Hoffman, D., Fernando, G., Goyal, V. and M. Civanlar, "RTP + Payload Format for MPEG1/MPEG2 Video", RFC 2250, January 1998. + + [15] Jayant, N. and P. Noll, Digital Coding of Waveforms--Principles + and Applications to Speech and Video Englewood Cliffs, New + Jersey: Prentice-Hall, 1984. + + [16] McKay, K., "RTP Payload Format for PureVoice(tm) Audio", RFC + 2658, August 1999. + + [17] Perkins, C., Kouvelas, I., Hodson, O., Hardman, V., Handley, M., + Bolot, J.-C., Vega-Garcia, A. and S. Fosse-Parisis, "RTP Payload + for Redundant Audio Data", RFC 2198, September 1997. + + [18] Speer, M. and D. Hoffman, "RTP Payload Format of Sun's CellB + Video Encoding", RFC 2029, October 1996. + + [19] Berc, L., Fenner, W., Frederick, R., McCanne, S. and P. Stewart, + "RTP Payload Format for JPEG-Compressed Video", RFC 2435, + October 1998. + + [20] Turletti, T. and C. Huitema, "RTP Payload Format for H.261 Video + Streams", RFC 2032, October 1996. + + [21] Zhu, C., "RTP Payload Format for H.263 Video Streams", RFC 2190, + September 1997. + + + + + +Schulzrinne & Casner Standards Track [Page 40] + +RFC 3551 RTP A/V Profile July 2003 + + + [22] Bormann, C., Cline, L., Deisher, G., Gardos, T., Maciocco, C., + Newell, D., Ott, J., Sullivan, G., Wenger, S. and C. Zhu, "RTP + Payload Format for the 1998 Version of ITU-T Rec. H.263 Video + (H.263+)", RFC 2429, October 1998. + + [23] Schulzrinne, H., Rao, A. and R. Lanphier, "Real Time Streaming + Protocol (RTSP)", RFC 2326, April 1998. + + [24] Cain, B., Deering, S., Kouvelas, I., Fenner, B. and A. + Thyagarajan, "Internet Group Management Protocol, Version 3", + RFC 3376, October 2002. + +13. Current Locations of Related Resources + + Note: Several sections below refer to the ITU-T Software Tool + Library (STL). It is available from the ITU Sales Service, Place des + Nations, CH-1211 Geneve 20, Switzerland (also check + http://www.itu.int). The ITU-T STL is covered by a license defined + in ITU-T Recommendation G.191, "Software tools for speech and audio + coding standardization". + + DVI4 + + An archived copy of the document IMA Recommended Practices for + Enhancing Digital Audio Compatibility in Multimedia Systems (version + 3.0), which describes the IMA ADPCM algorithm, is available at: + + http://www.cs.columbia.edu/~hgs/audio/dvi/ + + An implementation is available from Jack Jansen at + + ftp://ftp.cwi.nl/local/pub/audio/adpcm.shar + + G722 + + An implementation of the G.722 algorithm is available as part of the + ITU-T STL, described above. + + G723 + + The reference C code implementation defining the G.723.1 algorithm + and its Annexes A, B, and C are available as an integral part of + Recommendation G.723.1 from the ITU Sales Service, address listed + above. Both the algorithm and C code are covered by a specific + license. The ITU-T Secretariat should be contacted to obtain such + licensing information. + + + + + +Schulzrinne & Casner Standards Track [Page 41] + +RFC 3551 RTP A/V Profile July 2003 + + + G726 + + G726 is specified in the ITU-T Recommendation G.726, "40, 32, 24, and + 16 kb/s Adaptive Differential Pulse Code Modulation (ADPCM)". An + implementation of the G.726 algorithm is available as part of the + ITU-T STL, described above. + + G729 + + The reference C code implementation defining the G.729 algorithm and + its Annexes A through I are available as an integral part of + Recommendation G.729 from the ITU Sales Service, listed above. Annex + I contains the integrated C source code for all G.729 operating + modes. The G.729 algorithm and associated C code are covered by a + specific license. The contact information for obtaining the license + is available from the ITU-T Secretariat. + + GSM + + A reference implementation was written by Carsten Bormann and Jutta + Degener (then at TU Berlin, Germany). It is available at + + http://www.dmn.tzi.org/software/gsm/ + + Although the RPE-LTP algorithm is not an ITU-T standard, there is a C + code implementation of the RPE-LTP algorithm available as part of the + ITU-T STL. The STL implementation is an adaptation of the TU Berlin + version. + + LPC + + An implementation is available at + + ftp://parcftp.xerox.com/pub/net-research/lpc.tar.Z + + PCMU, PCMA + + An implementation of these algorithms is available as part of the + ITU-T STL, described above. + +14. Acknowledgments + + The comments and careful review of Simao Campos, Richard Cox and AVT + Working Group participants are gratefully acknowledged. The GSM + description was adopted from the IMTC Voice over IP Forum Service + Interoperability Implementation Agreement (January 1997). Fred Burg + and Terry Lyons helped with the G.729 description. + + + + +Schulzrinne & Casner Standards Track [Page 42] + +RFC 3551 RTP A/V Profile July 2003 + + +15. Intellectual Property Rights Statement + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; neither does it represent that it + has made any effort to identify any such rights. Information on the + IETF's procedures with respect to rights in standards-track and + standards-related documentation can be found in BCP-11. Copies of + claims of rights made available for publication and any assurances of + licenses to be made available, or the result of an attempt made to + obtain a general license or permission for the use of such + proprietary rights by implementors or users of this specification can + be obtained from the IETF Secretariat. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights which may cover technology that may be required to practice + this standard. Please address the information to the IETF Executive + Director. + +16. Authors' Addresses + + Henning Schulzrinne + Department of Computer Science + Columbia University + 1214 Amsterdam Avenue + New York, NY 10027 + United States + + EMail: schulzrinne@cs.columbia.edu + + + Stephen L. Casner + Packet Design + 3400 Hillview Avenue, Building 3 + Palo Alto, CA 94304 + United States + + EMail: casner@acm.org + + + + + + + + + + +Schulzrinne & Casner Standards Track [Page 43] + +RFC 3551 RTP A/V Profile July 2003 + + +17. Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Schulzrinne & Casner Standards Track [Page 44] + diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c new file mode 100644 index 00000000..a3e78d84 --- /dev/null +++ b/src/modules/rtp/rtp.c @@ -0,0 +1,193 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "rtp.h" + +pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssrc, uint8_t payload) { + assert(c); + assert(fd >= 0); + + c->fd = fd; + c->sequence = (uint16_t) (rand()*rand()); + c->timestamp = 0; + c->ssrc = ssrc ? ssrc : (uint32_t) (rand()*rand()); + c->payload = payload & 127; + + return c; +} + +#define MAX_IOVECS 16 + +int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { + struct iovec iov[MAX_IOVECS]; + pa_memblock* mb[MAX_IOVECS]; + int iov_idx = 1; + size_t n = 0, skip = 0; + + assert(c); + assert(size > 0); + assert(q); + + if (pa_memblockq_get_length(q) < size) + return 0; + + for (;;) { + int r; + pa_memchunk chunk; + + if ((r = pa_memblockq_peek(q, &chunk)) >= 0) { + + size_t k = n + chunk.length > size ? size - n : chunk.length; + + if (chunk.memblock) { + iov[iov_idx].iov_base = (uint8_t*) chunk.memblock->data + chunk.index; + iov[iov_idx].iov_len = k; + mb[iov_idx] = chunk.memblock; + iov_idx ++; + + n += k; + } + + skip += k; + pa_memblockq_drop(q, &chunk, k); + } + + if (r < 0 || !chunk.memblock || n >= size || iov_idx >= MAX_IOVECS) { + uint32_t header[3]; + struct msghdr m; + int k, i; + + if (n > 0) { + header[0] = htonl(((uint32_t) 2 << 30) | ((uint32_t) c->payload << 16) | ((uint32_t) c->sequence)); + header[1] = htonl(c->timestamp); + header[2] = htonl(c->ssrc); + + iov[0].iov_base = header; + iov[0].iov_len = sizeof(header); + + m.msg_name = NULL; + m.msg_namelen = 0; + m.msg_iov = iov; + m.msg_iovlen = iov_idx; + m.msg_control = NULL; + m.msg_controllen = 0; + m.msg_flags = 0; + + k = sendmsg(c->fd, &m, MSG_DONTWAIT); + + for (i = 1; i < iov_idx; i++) + pa_memblock_unref(mb[i]); + + c->sequence++; + } else + k = 0; + + c->timestamp += skip; + + if (k < 0) { + if (errno != EAGAIN) /* If the queue is full, just ignore it */ + pa_log(__FILE__": sendmsg() failed: %s", strerror(errno)); + return -1; + } + + if (r < 0 || pa_memblockq_get_length(q) < size) + break; + + n = 0; + skip = 0; + iov_idx = 1; + } + } + + return 0; +} + +pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd) { + assert(c); + + c->fd = fd; + return c; +} + +int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk) { + assert(c); + assert(chunk); + + return 0; +} + +uint8_t pa_rtp_payload_type(const pa_sample_spec *ss) { + assert(ss); + + if (ss->format == PA_SAMPLE_ULAW && ss->rate == 8000 && ss->channels == 1) + return 0; + if (ss->format == PA_SAMPLE_ALAW && ss->rate == 8000 && ss->channels == 1) + return 0; + if (ss->format == PA_SAMPLE_S16BE && ss->rate == 44100 && ss->channels == 2) + return 10; + if (ss->format == PA_SAMPLE_S16BE && ss->rate == 44100 && ss->channels == 1) + return 11; + + return 127; +} + +pa_sample_spec *pa_rtp_sample_spec_fixup(pa_sample_spec * ss) { + assert(ss); + + if (!pa_rtp_sample_spec_valid(ss)) + ss->format = PA_SAMPLE_S16BE; + + assert(pa_rtp_sample_spec_valid(ss)); + return ss; +} + +int pa_rtp_sample_spec_valid(const pa_sample_spec *ss) { + assert(ss); + + if (!pa_sample_spec_valid(ss)) + return 0; + + return + ss->format == PA_SAMPLE_U8 || + ss->format == PA_SAMPLE_ALAW || + ss->format == PA_SAMPLE_ULAW || + ss->format == PA_SAMPLE_S16BE; +} + +void pa_rtp_context_destroy(pa_rtp_context *c) { + assert(c); + + close(c->fd); +} diff --git a/src/modules/rtp/rtp.h b/src/modules/rtp/rtp.h new file mode 100644 index 00000000..e925cc0e --- /dev/null +++ b/src/modules/rtp/rtp.h @@ -0,0 +1,51 @@ +#ifndef foortphfoo +#define foortphfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include +#include + +typedef struct pa_rtp_context { + int fd; + uint16_t sequence; + uint32_t timestamp; + uint32_t ssrc; + uint8_t payload; +} pa_rtp_context; + +pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssrc, uint8_t payload); +int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q); + +pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd); +int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk); + +uint8_t pa_rtp_payload_type(const pa_sample_spec *ss); +pa_sample_spec* pa_rtp_sample_spec_fixup(pa_sample_spec *ss); +int pa_rtp_sample_spec_valid(const pa_sample_spec *ss); + +void pa_rtp_context_destroy(pa_rtp_context *c); + +#endif diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c new file mode 100644 index 00000000..ebf20bc4 --- /dev/null +++ b/src/modules/rtp/sap.c @@ -0,0 +1,107 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "sap.h" + +pa_sap_context* pa_sap_context_init_send(pa_sap_context *c, int fd, char *sdp_data) { + assert(c); + assert(fd >= 0); + assert(sdp_data); + + c->fd = fd; + c->sdp_data = sdp_data; + c->msg_id_hash = (uint16_t) (rand()*rand()); + + return c; +} + +void pa_sap_context_destroy(pa_sap_context *c) { + assert(c); + + close(c->fd); + pa_xfree(c->sdp_data); +} + +int pa_sap_send(pa_sap_context *c, int goodbye) { + uint32_t header; + const char mime[] = "application/sdp"; + struct sockaddr_storage sa_buf; + struct sockaddr *sa = (struct sockaddr*) &sa_buf; + socklen_t salen = sizeof(sa_buf); + struct iovec iov[4]; + struct msghdr m; + int k; + + if (getsockname(c->fd, sa, &salen) < 0) { + pa_log("getsockname() failed: %s\n", strerror(errno)); + return -1; + } + + assert(sa->sa_family == AF_INET || sa->sa_family == AF_INET6); + + header = htonl(((uint32_t) 1 << 29) | + (sa->sa_family == AF_INET6 ? (uint32_t) 1 << 28 : 0) | + (goodbye ? (uint32_t) 1 << 26 : 0) | + (c->msg_id_hash)); + + iov[0].iov_base = &header; + iov[0].iov_len = sizeof(header); + + iov[1].iov_base = sa->sa_family == AF_INET ? (void*) &((struct sockaddr_in*) sa)->sin_addr : (void*) &((struct sockaddr_in6*) sa)->sin6_addr; + iov[1].iov_len = sa->sa_family == AF_INET ? 4 : 16; + + iov[2].iov_base = (char*) mime; + iov[2].iov_len = sizeof(mime); + + iov[3].iov_base = c->sdp_data; + iov[3].iov_len = strlen(c->sdp_data); + + m.msg_name = NULL; + m.msg_namelen = 0; + m.msg_iov = iov; + m.msg_iovlen = 4; + m.msg_control = NULL; + m.msg_controllen = 0; + m.msg_flags = 0; + + if ((k = sendmsg(c->fd, &m, MSG_DONTWAIT)) < 0) + pa_log("sendmsg() failed: %s\n", strerror(errno)); + + return k; +} diff --git a/src/modules/rtp/sap.h b/src/modules/rtp/sap.h new file mode 100644 index 00000000..787b39f7 --- /dev/null +++ b/src/modules/rtp/sap.h @@ -0,0 +1,43 @@ +#ifndef foosaphfoo +#define foosaphfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include +#include + +typedef struct pa_sap_context { + int fd; + char *sdp_data; + + uint16_t msg_id_hash; +} pa_sap_context; + +pa_sap_context* pa_sap_context_init_send(pa_sap_context *c, int fd, char *sdp_data); +void pa_sap_context_destroy(pa_sap_context *c); + +int pa_sap_send(pa_sap_context *c, int goodbye); + +#endif diff --git a/src/modules/rtp/sdp.c b/src/modules/rtp/sdp.c new file mode 100644 index 00000000..99e8c12b --- /dev/null +++ b/src/modules/rtp/sdp.c @@ -0,0 +1,87 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include "sdp.h" + +static const char* map_format(pa_sample_format_t f) { + switch (f) { + case PA_SAMPLE_S16BE: return "L16"; + case PA_SAMPLE_U8: return "L8"; + case PA_SAMPLE_ALAW: return "PCMA"; + case PA_SAMPLE_ULAW: return "PCMU"; + default: + return NULL; + } +} + +char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, uint16_t port, uint8_t payload, const pa_sample_spec *ss) { + uint32_t ntp; + char buf_src[64], buf_dst[64]; + const char *u, *f, *a; + + assert(src); + assert(dst); + assert(af == AF_INET || af == AF_INET6); + + f = map_format(ss->format); + assert(f); + + if (!(u = getenv("USER"))) + if (!(u = getenv("USERNAME"))) + u = "-"; + + ntp = time(NULL) + 2208988800; + + a = inet_ntop(af, src, buf_src, sizeof(buf_src)); + assert(a); + a = inet_ntop(af, dst, buf_dst, sizeof(buf_dst)); + assert(a); + + return pa_sprintf_malloc( + "v=0\n" + "o=%s %lu 0 IN %s %s\n" + "s=%s\n" + "c=IN %s %s\n" + "t=%lu 0\n" + "a=recvonly\n" + "m=audio %u RTP/AVP %i\n" + "a=rtpmap:%i %s/%u/%u\n" + "a=type:broadcast\n", + u, (unsigned long) ntp, af == AF_INET ? "IP4" : "IP6", buf_src, + name, + af == AF_INET ? "IP4" : "IP6", buf_dst, + (unsigned long) ntp, + port, payload, + payload, f, ss->rate, ss->channels); +} diff --git a/src/modules/rtp/sdp.h b/src/modules/rtp/sdp.h new file mode 100644 index 00000000..10820067 --- /dev/null +++ b/src/modules/rtp/sdp.h @@ -0,0 +1,33 @@ +#ifndef foosdphfoo +#define foosdphfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include + +#include + +char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, uint16_t port, uint8_t payload, const pa_sample_spec *ss); + +#endif -- cgit From e0e2b8fdb6d0c4f7caa801206ed6488bb345d523 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Apr 2006 23:49:12 +0000 Subject: * ignore some more files * make necessary changes to Makefile to compile RTP module git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@713 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index c5e4638b..f23778d0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -589,7 +589,8 @@ modlib_LTLIBRARIES = \ libprotocol-simple.la \ libprotocol-esound.la \ libprotocol-native.la \ - libprotocol-http.la + libprotocol-http.la \ + librtp.la if HAVE_X11 polypcoreinclude_HEADERS += \ @@ -686,6 +687,10 @@ libsocket_util_la_SOURCES = polypcore/socket-util.c polypcore/socket-util.h libsocket_util_la_LDFLAGS = -avoid-version libsocket_util_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) +librtp_la_SOURCES = modules/rtp/rtp.c modules/rtp/rtp.h modules/rtp/sdp.c modules/rtp/sdp.h modules/rtp/sap.c modules/rtp/sap.h +librtp_la_LDFLAGS = -avoid-version +librtp_la_LIBADD = $(AM_LIBADD) libpolypcore.la + # X11 libx11wrap_la_SOURCES = polypcore/x11wrap.c polypcore/x11wrap.h @@ -716,7 +721,8 @@ modlib_LTLIBRARIES += \ module-null-sink.la \ module-esound-sink.la \ module-http-protocol-tcp.la \ - module-detect.la + module-detect.la \ + module-rtp-monitor.la if HAVE_AF_UNIX modlib_LTLIBRARIES += \ @@ -827,7 +833,8 @@ SYMDEF_FILES = \ modules/module-alsa-source-symdef.h \ modules/module-solaris-symdef.h \ modules/module-waveout-symdef.h \ - modules/module-detect-symdef.h + modules/module-detect-symdef.h \ + modules/rtp/module-rtp-monitor-symdef.h EXTRA_DIST += $(SYMDEF_FILES) BUILT_SOURCES += $(SYMDEF_FILES) @@ -1042,6 +1049,12 @@ module_detect_la_LDFLAGS = -module -avoid-version module_detect_la_LIBADD = $(AM_LIBADD) libpolypcore.la module_detect_la_CFLAGS = $(AM_CFLAGS) +# Hardware autodetection module +module_rtp_monitor_la_SOURCES = modules/rtp/module-rtp-monitor.c +module_rtp_monitor_la_LDFLAGS = -module -avoid-version +module_rtp_monitor_la_LIBADD = $(AM_LIBADD) libpolypcore.la +module_rtp_monitor_la_CFLAGS = $(AM_CFLAGS) + ################################### # Some minor stuff # ################################### -- cgit From 71227de8b233fd12568609a2ac393e432a7c4299 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Apr 2006 15:25:53 +0000 Subject: correct some types git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@714 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/resampler.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/polypcore/resampler.c b/src/polypcore/resampler.c index c1740bf1..a50b21bf 100644 --- a/src/polypcore/resampler.c +++ b/src/polypcore/resampler.c @@ -262,7 +262,7 @@ static void calc_map_table(pa_resampler *r) { } } -static float * convert_to_float(pa_resampler *r, float *input, unsigned n_frames) { +static float * convert_to_float(pa_resampler *r, void *input, unsigned n_frames) { struct impl_libsamplerate *u; unsigned n_samples; @@ -369,7 +369,7 @@ static float *resample(pa_resampler *r, float *input, unsigned *n_frames) { return u->buf3; } -static float *convert_from_float(pa_resampler *r, float *input, unsigned n_frames) { +static void *convert_from_float(pa_resampler *r, float *input, unsigned n_frames) { struct impl_libsamplerate *u; unsigned n_samples; @@ -395,7 +395,8 @@ static float *convert_from_float(pa_resampler *r, float *input, unsigned n_frame static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { struct impl_libsamplerate *u; - float *buf, *input; + float *buf; + void *input, *output; unsigned n_frames; assert(r); @@ -408,18 +409,18 @@ static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchun u = r->impl_data; - buf = input = (float*) ((uint8_t*) in->memblock->data + in->index); + input = ((uint8_t*) in->memblock->data + in->index); n_frames = in->length / r->i_fz; assert(n_frames > 0); - buf = convert_to_float(r, buf, n_frames); + buf = convert_to_float(r, input, n_frames); buf = remap_channels(r, buf, n_frames); buf = resample(r, buf, &n_frames); if (n_frames) { - buf = convert_from_float(r, buf, n_frames); + output = convert_from_float(r, buf, n_frames); - if (buf == input) { + if (output == input) { /* Mm, no adjustment has been necessary, so let's return the original block */ out->memblock = pa_memblock_ref(in->memblock); out->index = in->index; @@ -430,16 +431,16 @@ static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchun out->length = n_frames * r->o_fz; out->index = 0; - if (buf == u->buf1) { + if (output == u->buf1) { p = &u->buf1; u->buf1_samples = 0; - } else if (buf == u->buf2) { + } else if (output == u->buf2) { p = &u->buf2; u->buf2_samples = 0; - } else if (buf == u->buf3) { + } else if (output == u->buf3) { p = &u->buf3; u->buf3_samples = 0; - } else if (buf == u->buf4) { + } else if (output == u->buf4) { p = &u->buf4; u->buf4_samples = 0; } -- cgit From 1fec416db7db4ba8d2d2dd250187939f0b06dbd7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Apr 2006 15:26:42 +0000 Subject: * change default multicast address * fix timestamp calculation git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@715 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/rtp/module-rtp-monitor.c | 7 +++---- src/modules/rtp/rtp.c | 7 ++++--- src/modules/rtp/rtp.h | 3 ++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/modules/rtp/module-rtp-monitor.c b/src/modules/rtp/module-rtp-monitor.c index 66332093..c153a9d5 100644 --- a/src/modules/rtp/module-rtp-monitor.c +++ b/src/modules/rtp/module-rtp-monitor.c @@ -61,9 +61,9 @@ PA_MODULE_USAGE( "mtu= " ) -#define DEFAULT_PORT 5666 +#define DEFAULT_PORT 5004 #define SAP_PORT 9875 -#define DEFAULT_DESTINATION "224.0.0.252" +#define DEFAULT_DESTINATION "224.0.1.2" #define MEMBLOCKQ_MAXLENGTH (1024*170) #define DEFAULT_MTU 1024 #define SAP_INTERVAL 5000000 @@ -136,7 +136,6 @@ static void sap_event(pa_mainloop_api *m, pa_time_event *t, const struct timeval pa_sap_send(&u->sap_context, 0); - pa_log("SAP update"); pa_gettimeofday(&next); pa_timeval_add(&next, SAP_INTERVAL); m->time_restart(t, &next); @@ -280,7 +279,7 @@ int pa__init(pa_core *c, pa_module*m) { af == AF_INET ? (void*) &sa4.sin_addr : (void*) &sa6.sin6_addr, "Polypaudio RTP Stream", port, payload, &ss); - pa_rtp_context_init_send(&u->rtp_context, fd, 0, payload); + pa_rtp_context_init_send(&u->rtp_context, fd, 0, payload, pa_frame_size(&ss)); pa_sap_context_init_send(&u->sap_context, sap_fd, p); pa_log_info("RTP stream initialized with mtu %u on %s:%u, SSRC=0x%08x, payload=%u, initial sequence #%u", mtu, dest, port, u->rtp_context.ssrc, payload, u->rtp_context.sequence); diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c index a3e78d84..a3bce38b 100644 --- a/src/modules/rtp/rtp.c +++ b/src/modules/rtp/rtp.c @@ -35,7 +35,7 @@ #include "rtp.h" -pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssrc, uint8_t payload) { +pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssrc, uint8_t payload, size_t frame_size) { assert(c); assert(fd >= 0); @@ -44,7 +44,8 @@ pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssr c->timestamp = 0; c->ssrc = ssrc ? ssrc : (uint32_t) (rand()*rand()); c->payload = payload & 127; - + c->frame_size = frame_size; + return c; } @@ -114,7 +115,7 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { } else k = 0; - c->timestamp += skip; + c->timestamp += skip/c->frame_size; if (k < 0) { if (errno != EAGAIN) /* If the queue is full, just ignore it */ diff --git a/src/modules/rtp/rtp.h b/src/modules/rtp/rtp.h index e925cc0e..39288158 100644 --- a/src/modules/rtp/rtp.h +++ b/src/modules/rtp/rtp.h @@ -34,9 +34,10 @@ typedef struct pa_rtp_context { uint32_t timestamp; uint32_t ssrc; uint8_t payload; + size_t frame_size; } pa_rtp_context; -pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssrc, uint8_t payload); +pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssrc, uint8_t payload, size_t frame_size); int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q); pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd); -- cgit From f1ddf052368ad96cf157297a50ffe52ee8f7ca39 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Apr 2006 00:16:53 +0000 Subject: * add RTP/SAP/SDP reciever module * use server cookie as RTP SSRC * enable SVN keywords * add new option "loop" for RTP sender module git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@716 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 13 +- src/modules/rtp/module-rtp-monitor.c | 70 ++++-- src/modules/rtp/module-rtp-recv.c | 469 +++++++++++++++++++++++++++++++++++ src/modules/rtp/rtp.c | 162 +++++++++++- src/modules/rtp/rtp.h | 13 +- src/modules/rtp/sap.c | 116 ++++++++- src/modules/rtp/sap.h | 3 + src/modules/rtp/sdp.c | 198 ++++++++++++++- src/modules/rtp/sdp.h | 17 ++ 9 files changed, 1010 insertions(+), 51 deletions(-) create mode 100644 src/modules/rtp/module-rtp-recv.c diff --git a/src/Makefile.am b/src/Makefile.am index f23778d0..2ec62dca 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -722,7 +722,8 @@ modlib_LTLIBRARIES += \ module-esound-sink.la \ module-http-protocol-tcp.la \ module-detect.la \ - module-rtp-monitor.la + module-rtp-monitor.la \ + module-rtp-recv.la if HAVE_AF_UNIX modlib_LTLIBRARIES += \ @@ -834,7 +835,8 @@ SYMDEF_FILES = \ modules/module-solaris-symdef.h \ modules/module-waveout-symdef.h \ modules/module-detect-symdef.h \ - modules/rtp/module-rtp-monitor-symdef.h + modules/rtp/module-rtp-monitor-symdef.h \ + modules/rtp/module-rtp-recv-symdef.h EXTRA_DIST += $(SYMDEF_FILES) BUILT_SOURCES += $(SYMDEF_FILES) @@ -1049,12 +1051,17 @@ module_detect_la_LDFLAGS = -module -avoid-version module_detect_la_LIBADD = $(AM_LIBADD) libpolypcore.la module_detect_la_CFLAGS = $(AM_CFLAGS) -# Hardware autodetection module +# RTP modules module_rtp_monitor_la_SOURCES = modules/rtp/module-rtp-monitor.c module_rtp_monitor_la_LDFLAGS = -module -avoid-version module_rtp_monitor_la_LIBADD = $(AM_LIBADD) libpolypcore.la module_rtp_monitor_la_CFLAGS = $(AM_CFLAGS) +module_rtp_recv_la_SOURCES = modules/rtp/module-rtp-recv.c +module_rtp_recv_la_LDFLAGS = -module -avoid-version +module_rtp_recv_la_LIBADD = $(AM_LIBADD) libpolypcore.la +module_rtp_recv_la_CFLAGS = $(AM_CFLAGS) + ################################### # Some minor stuff # ################################### diff --git a/src/modules/rtp/module-rtp-monitor.c b/src/modules/rtp/module-rtp-monitor.c index c153a9d5..5ff25557 100644 --- a/src/modules/rtp/module-rtp-monitor.c +++ b/src/modules/rtp/module-rtp-monitor.c @@ -1,3 +1,4 @@ +/* $Id */ /*** This file is part of polypaudio. @@ -49,16 +50,17 @@ #include "sap.h" PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Read data from source and send it to the network via RTP") +PA_MODULE_DESCRIPTION("Read data from source and send it to the network via RTP/SAP/SDP") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE( - "source= " + "source= " "format= " "channels= " "rate= " "destinaton= " "port= " "mtu= " + "loop=" ) #define DEFAULT_PORT 5004 @@ -75,6 +77,7 @@ static const char* const valid_modargs[] = { "rate", "destination", "port", + "loop", NULL }; @@ -125,7 +128,7 @@ static pa_usec_t source_output_get_latency (pa_source_output *o) { return pa_bytes_to_usec(pa_memblockq_get_length(u->memblockq), &o->sample_spec); } -static void sap_event(pa_mainloop_api *m, pa_time_event *t, const struct timeval *tv, void *userdata) { +static void sap_event_cb(pa_mainloop_api *m, pa_time_event *t, const struct timeval *tv, void *userdata) { struct userdata *u = userdata; struct timeval next; @@ -159,6 +162,8 @@ int pa__init(pa_core *c, pa_module*m) { int r; socklen_t k; struct timeval tv; + char hn[128], *n; + int loop = 0; assert(c); assert(m); @@ -173,6 +178,11 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } + if (pa_modargs_get_value_boolean(ma, "loop", &loop) < 0) { + pa_log(__FILE__": failed to parse \"loop\" parameter."); + goto fail; + } + ss = s->sample_spec; pa_rtp_sample_spec_fixup(&ss); cm = s->channel_map; @@ -189,7 +199,7 @@ int pa__init(pa_core *c, pa_module*m) { if (ss.channels != cm.channels) pa_channel_map_init_auto(&cm, ss.channels); - payload = pa_rtp_payload_type(&ss); + payload = pa_rtp_payload_from_sample_spec(&ss); mtu = (DEFAULT_MTU/pa_frame_size(&ss))*pa_frame_size(&ss); @@ -203,21 +213,21 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - if ((dest = pa_modargs_get_value(ma, "destination", DEFAULT_DESTINATION))) { - if (inet_pton(AF_INET6, dest, &sa6.sin6_addr) > 0) { - sa6.sin6_family = af = AF_INET6; - sa6.sin6_port = htons(port); - sap_sa6 = sa6; - sap_sa6.sin6_port = htons(SAP_PORT); - } else if (inet_pton(AF_INET, dest, &sa4.sin_addr) > 0) { - sa4.sin_family = af = AF_INET; - sa4.sin_port = htons(port); - sap_sa4 = sa4; - sap_sa4.sin_port = htons(SAP_PORT); - } else { - pa_log(__FILE__": invalid destination '%s'", dest); - goto fail; - } + dest = pa_modargs_get_value(ma, "destination", DEFAULT_DESTINATION); + + if (inet_pton(AF_INET6, dest, &sa6.sin6_addr) > 0) { + sa6.sin6_family = af = AF_INET6; + sa6.sin6_port = htons(port); + sap_sa6 = sa6; + sap_sa6.sin6_port = htons(SAP_PORT); + } else if (inet_pton(AF_INET, dest, &sa4.sin_addr) > 0) { + sa4.sin_family = af = AF_INET; + sa4.sin_port = htons(port); + sap_sa4 = sa4; + sap_sa4.sin_port = htons(SAP_PORT); + } else { + pa_log(__FILE__": invalid destination '%s'", dest); + goto fail; } if ((fd = socket(af, SOCK_DGRAM, 0)) < 0) { @@ -240,6 +250,12 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } + if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0 || + setsockopt(sap_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) { + pa_log(__FILE__": IP_MULTICAST_LOOP failed: %s", strerror(errno)); + goto fail; + } + if (!(o = pa_source_output_new(s, __FILE__, "RTP Monitor Stream", &ss, &cm, PA_RESAMPLER_INVALID))) { pa_log(__FILE__": failed to create source output."); goto fail; @@ -273,23 +289,27 @@ int pa__init(pa_core *c, pa_module*m) { k = sizeof(sa_dst); r = getsockname(fd, (struct sockaddr*) &sa_dst, &k); assert(r >= 0); + + n = pa_sprintf_malloc("Polypaudio RTP Stream on %s", pa_get_fqdn(hn, sizeof(hn))); p = pa_sdp_build(af, af == AF_INET ? (void*) &((struct sockaddr_in*) &sa_dst)->sin_addr : (void*) &((struct sockaddr_in6*) &sa_dst)->sin6_addr, af == AF_INET ? (void*) &sa4.sin_addr : (void*) &sa6.sin6_addr, - "Polypaudio RTP Stream", port, payload, &ss); + n, port, payload, &ss); + + pa_xfree(n); - pa_rtp_context_init_send(&u->rtp_context, fd, 0, payload, pa_frame_size(&ss)); + pa_rtp_context_init_send(&u->rtp_context, fd, c->cookie, payload, pa_frame_size(&ss)); pa_sap_context_init_send(&u->sap_context, sap_fd, p); - pa_log_info("RTP stream initialized with mtu %u on %s:%u, SSRC=0x%08x, payload=%u, initial sequence #%u", mtu, dest, port, u->rtp_context.ssrc, payload, u->rtp_context.sequence); - pa_log_info("SDP-Data:\n%s\nEOF", p); - + pa_log_info(__FILE__": RTP stream initialized with mtu %u on %s:%u, SSRC=0x%08x, payload=%u, initial sequence #%u", mtu, dest, port, u->rtp_context.ssrc, payload, u->rtp_context.sequence); + pa_log_info(__FILE__": SDP-Data:\n%s\n"__FILE__": EOF", p); + pa_sap_send(&u->sap_context, 0); pa_gettimeofday(&tv); pa_timeval_add(&tv, SAP_INTERVAL); - u->sap_event = c->mainloop->time_new(c->mainloop, &tv, sap_event, u); + u->sap_event = c->mainloop->time_new(c->mainloop, &tv, sap_event_cb, u); pa_modargs_free(ma); diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c new file mode 100644 index 00000000..1ac057d0 --- /dev/null +++ b/src/modules/rtp/module-rtp-recv.c @@ -0,0 +1,469 @@ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-rtp-recv-symdef.h" + +#include "rtp.h" +#include "sdp.h" +#include "sap.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Recieve data from a network via RTP/SAP/SDP") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE( + "sink= " + "sap_address= " +) + +#define SAP_PORT 9875 +#define DEFAULT_SAP_ADDRESS "224.0.1.2" +#define MEMBLOCKQ_MAXLENGTH (1024*170) +#define MAX_SESSIONS 16 +#define DEATH_TIMEOUT 20000000 + +static const char* const valid_modargs[] = { + "sink", + "sap_address", + NULL +}; + +struct session { + struct userdata *userdata; + + pa_sink_input *sink_input; + pa_memblockq *memblockq; + + pa_time_event *death_event; + + int first_packet; + uint32_t ssrc; + uint32_t offset; + + struct pa_sdp_info sdp_info; + + pa_rtp_context rtp_context; + pa_io_event* rtp_event; +}; + +struct userdata { + pa_module *module; + pa_core *core; + + pa_sap_context sap_context; + pa_io_event* sap_event; + + pa_hashmap *by_origin; + + char *sink_name; +}; + +static void session_free(struct session *s, int from_hash); + +static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { + struct session *s; + assert(i); + s = i->userdata; + + return pa_memblockq_peek(s->memblockq, chunk); +} + +static void sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { + struct session *s; + assert(i); + s = i->userdata; + + pa_memblockq_drop(s->memblockq, chunk, length); +} + +static void sink_input_kill(pa_sink_input* i) { + struct session *s; + assert(i); + s = i->userdata; + + session_free(s, 1); +} + +static pa_usec_t sink_input_get_latency(pa_sink_input *i) { + struct session *s; + assert(i); + s = i->userdata; + + return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec); +} + +static void rtp_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) { + struct session *s = userdata; + pa_memchunk chunk; + int64_t k, j, delta; + struct timeval tv; + + assert(m); + assert(e); + assert(s); + assert(fd == s->rtp_context.fd); + assert(flags == PA_IO_EVENT_INPUT); + + if (pa_rtp_recv(&s->rtp_context, &chunk, s->userdata->core->memblock_stat) < 0) + return; + + if (s->sdp_info.payload != s->rtp_context.payload) { + pa_memblock_unref(chunk.memblock); + return; + } + + if (!s->first_packet) { + s->first_packet = 1; + + s->ssrc = s->rtp_context.ssrc; + s->offset = s->rtp_context.timestamp; + } else { + if (s->ssrc != s->rtp_context.ssrc) { + pa_memblock_unref(chunk.memblock); + return; + } + } + + /* Check wheter there was a timestamp overflow */ + k = (int64_t) s->rtp_context.timestamp - (int64_t) s->offset; + j = (int64_t) 0x100000000 - (int64_t) s->offset + (int64_t) s->rtp_context.timestamp; + + if ((k < 0 ? -k : k) < (j < 0 ? -j : j)) + delta = k; + else + delta = j; + + pa_memblockq_seek(s->memblockq, delta * s->rtp_context.frame_size, PA_SEEK_RELATIVE); + pa_memblockq_push(s->memblockq, &chunk); + + /* The next timestamp we expect */ + s->offset = s->rtp_context.timestamp + (chunk.length / s->rtp_context.frame_size); + + pa_memblock_unref(chunk.memblock); + + /* Reset death timer */ + pa_gettimeofday(&tv); + pa_timeval_add(&tv, DEATH_TIMEOUT); + m->time_restart(s->death_event, &tv); +} + +static void death_event_cb(pa_mainloop_api *m, pa_time_event *t, const struct timeval *tv, void *userdata) { + struct session *s = userdata; + + assert(m); + assert(t); + assert(tv); + assert(s); + + session_free(s, 1); +} + +static int mcast_socket(const struct sockaddr* sa, socklen_t salen) { + int af, fd = -1, r, one; + + af = sa->sa_family; + if ((fd = socket(af, SOCK_DGRAM, 0)) < 0) { + pa_log(__FILE__": Failed to create socket: %s", strerror(errno)); + goto fail; + } + + one = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) { + pa_log(__FILE__": SO_REUSEADDR failed: %s", strerror(errno)); + goto fail; + } + + if (af == AF_INET) { + struct ip_mreq mr4; + memset(&mr4, 0, sizeof(mr4)); + mr4.imr_multiaddr = ((const struct sockaddr_in*) sa)->sin_addr; + r = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mr4, sizeof(mr4)); + } else { + struct ipv6_mreq mr6; + memset(&mr6, 0, sizeof(mr6)); + mr6.ipv6mr_multiaddr = ((const struct sockaddr_in6*) sa)->sin6_addr; + r = setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mr6, sizeof(mr6)); + } + + if (r < 0) { + pa_log_info(__FILE__": Joining mcast group failed: %s", strerror(errno)); + goto fail; + } + + if (bind(fd, sa, salen) < 0) { + pa_log(__FILE__": bind() failed: %s", strerror(errno)); + goto fail; + } + + return fd; + +fail: + if (fd >= 0) + close(fd); + + return -1; +} + +static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_info) { + struct session *s = NULL; + struct timeval tv; + char *c; + pa_sink *sink; + int fd = -1; + + if (!(sink = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) { + pa_log(__FILE__": sink does not exist."); + goto fail; + } + + s = pa_xnew0(struct session, 1); + s->userdata = u; + s->first_packet = 0; + s->sdp_info = *sdp_info; + + if ((fd = mcast_socket((const struct sockaddr*) &sdp_info->sa, sdp_info->salen)) < 0) + goto fail; + + c = pa_sprintf_malloc("RTP Stream%s%s%s", + sdp_info->session_name ? " (" : "", + sdp_info->session_name ? sdp_info->session_name : "", + sdp_info->session_name ? ")" : ""); + + s->sink_input = pa_sink_input_new(sink, __FILE__, c, &sdp_info->sample_spec, NULL, 0, PA_RESAMPLER_INVALID); + pa_xfree(c); + + if (!s->sink_input) { + pa_log(__FILE__": failed to create sink input."); + goto fail; + } + + s->sink_input->userdata = s; + s->sink_input->owner = u->module; + + s->sink_input->peek = sink_input_peek; + s->sink_input->drop = sink_input_drop; + s->sink_input->kill = sink_input_kill; + s->sink_input->get_latency = sink_input_get_latency; + + s->memblockq = pa_memblockq_new( + 0, + MEMBLOCKQ_MAXLENGTH, + MEMBLOCKQ_MAXLENGTH, + pa_frame_size(&s->sink_input->sample_spec), + 1, + 0, + NULL, + u->core->memblock_stat); + + s->rtp_event = u->core->mainloop->io_new(u->core->mainloop, fd, PA_IO_EVENT_INPUT, rtp_event_cb, s); + + pa_gettimeofday(&tv); + pa_timeval_add(&tv, DEATH_TIMEOUT); + s->death_event = u->core->mainloop->time_new(u->core->mainloop, &tv, death_event_cb, s); + + pa_hashmap_put(s->userdata->by_origin, s->sdp_info.origin, s); + + pa_rtp_context_init_recv(&s->rtp_context, fd, pa_frame_size(&s->sdp_info.sample_spec)); + + pa_log_info(__FILE__": Found new session '%s'", s->sdp_info.session_name); + + return s; + +fail: + if (s) { + if (fd >= 0) + close(fd); + + pa_xfree(s); + } + + return NULL; +} + +static void session_free(struct session *s, int from_hash) { + assert(s); + + pa_log_info(__FILE__": Freeing session '%s'", s->sdp_info.session_name); + + s->userdata->core->mainloop->time_free(s->death_event); + s->userdata->core->mainloop->io_free(s->rtp_event); + + if (from_hash) + pa_hashmap_remove(s->userdata->by_origin, s->sdp_info.origin); + + pa_sink_input_disconnect(s->sink_input); + pa_sink_input_unref(s->sink_input); + + pa_memblockq_free(s->memblockq); + pa_sdp_info_destroy(&s->sdp_info); + pa_rtp_context_destroy(&s->rtp_context); + + pa_xfree(s); +} + +static void sap_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) { + struct userdata *u = userdata; + int goodbye; + pa_sdp_info info; + struct session *s; + + assert(m); + assert(e); + assert(u); + assert(fd == u->sap_context.fd); + assert(flags == PA_IO_EVENT_INPUT); + + if (pa_sap_recv(&u->sap_context, &goodbye) < 0) + return; + + if (!pa_sdp_parse(u->sap_context.sdp_data, &info, goodbye)) + return; + + if (goodbye) { + + if ((s = pa_hashmap_get(u->by_origin, info.origin))) + session_free(s, 1); + + pa_sdp_info_destroy(&info); + } else { + + if (!(s = pa_hashmap_get(u->by_origin, info.origin))) { + if (!(s = session_new(u, &info))) + pa_sdp_info_destroy(&info); + + } else { + struct timeval tv; + + pa_gettimeofday(&tv); + pa_timeval_add(&tv, DEATH_TIMEOUT); + m->time_restart(s->death_event, &tv); + + pa_sdp_info_destroy(&info); + } + } +} + +int pa__init(pa_core *c, pa_module*m) { + struct userdata *u; + pa_modargs *ma = NULL; + struct sockaddr_in sa4; + struct sockaddr_in6 sa6; + struct sockaddr *sa; + socklen_t salen; + const char *sap_address; + int fd = -1; + + assert(c); + assert(m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments"); + goto fail; + } + + sap_address = pa_modargs_get_value(ma, "sap_address", DEFAULT_SAP_ADDRESS); + + if (inet_pton(AF_INET6, sap_address, &sa6.sin6_addr) > 0) { + sa6.sin6_family = AF_INET6; + sa6.sin6_port = htons(SAP_PORT); + sa = (struct sockaddr*) &sa6; + salen = sizeof(sa6); + } else if (inet_pton(AF_INET, sap_address, &sa4.sin_addr) > 0) { + sa4.sin_family = AF_INET; + sa4.sin_port = htons(SAP_PORT); + sa = (struct sockaddr*) &sa4; + salen = sizeof(sa4); + } else { + pa_log(__FILE__": invalid SAP address '%s'", sap_address); + goto fail; + } + + if ((fd = mcast_socket(sa, salen)) < 0) + goto fail; + + u = pa_xnew(struct userdata, 1); + m->userdata = u; + u->module = m; + u->core = c; + u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); + + u->sap_event = c->mainloop->io_new(c->mainloop, fd, PA_IO_EVENT_INPUT, sap_event_cb, u); + + u->by_origin = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + + pa_sap_context_init_recv(&u->sap_context, fd); + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + if (fd >= 0) + close(fd); + + return -1; +} + +static void free_func(void *p, void *userdata) { + session_free(p, 0); +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c); + assert(m); + + if (!(u = m->userdata)) + return; + + c->mainloop->io_free(u->sap_event); + pa_sap_context_destroy(&u->sap_context); + + pa_hashmap_free(u->by_origin, free_func, NULL); + + pa_xfree(u->sink_name); + pa_xfree(u); +} diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c index a3bce38b..ccd3b6c3 100644 --- a/src/modules/rtp/rtp.c +++ b/src/modules/rtp/rtp.c @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -135,27 +136,114 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { return 0; } -pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd) { +pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd, size_t frame_size) { assert(c); c->fd = fd; + c->frame_size = frame_size; return c; } -int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk) { +int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_memblock_stat *st) { + int size; + struct msghdr m; + struct iovec iov; + uint32_t header; + int cc; + ssize_t r; + assert(c); assert(chunk); + chunk->memblock = NULL; + + if (ioctl(c->fd, FIONREAD, &size) < 0) { + pa_log(__FILE__": FIONREAD failed: %s", strerror(errno)); + goto fail; + } + + if (!size) + return 0; + + chunk->memblock = pa_memblock_new(size, st); + + iov.iov_base = chunk->memblock->data; + iov.iov_len = size; + + m.msg_name = NULL; + m.msg_namelen = 0; + m.msg_iov = &iov; + m.msg_iovlen = 1; + m.msg_control = NULL; + m.msg_controllen = 0; + m.msg_flags = 0; + + if ((r = recvmsg(c->fd, &m, 0)) != size) { + pa_log(__FILE__": recvmsg() failed: %s", r < 0 ? strerror(errno) : "size mismatch"); + goto fail; + } + + if (size < 12) { + pa_log(__FILE__": RTP packet too short."); + goto fail; + } + + memcpy(&header, chunk->memblock->data, sizeof(uint32_t)); + memcpy(&c->timestamp, (uint8_t*) chunk->memblock->data + 4, sizeof(uint32_t)); + memcpy(&c->ssrc, (uint8_t*) chunk->memblock->data + 8, sizeof(uint32_t)); + + header = ntohl(header); + c->timestamp = ntohl(c->timestamp); + c->ssrc = ntohl(c->ssrc); + + if ((header >> 30) != 2) { + pa_log(__FILE__": Unsupported RTP version."); + goto fail; + } + + if ((header >> 29) & 1) { + pa_log(__FILE__": RTP padding not supported."); + goto fail; + } + + if ((header >> 28) & 1) { + pa_log(__FILE__": RTP header extensions not supported."); + goto fail; + } + + cc = (header >> 24) & 0xF; + c->payload = (header >> 16) & 127; + c->sequence = header & 0xFFFF; + + if (12 + cc*4 > size) { + pa_log(__FILE__": RTP packet too short. (CSRC)"); + goto fail; + } + + chunk->index = 12 + cc*4; + chunk->length = size - chunk->index; + + if (chunk->length % c->frame_size != 0) { + pa_log(__FILE__": Vad RTP packet size."); + goto fail; + } + return 0; + +fail: + if (chunk->memblock) + pa_memblock_unref(chunk->memblock); + + return -1; } -uint8_t pa_rtp_payload_type(const pa_sample_spec *ss) { +uint8_t pa_rtp_payload_from_sample_spec(const pa_sample_spec *ss) { assert(ss); if (ss->format == PA_SAMPLE_ULAW && ss->rate == 8000 && ss->channels == 1) return 0; if (ss->format == PA_SAMPLE_ALAW && ss->rate == 8000 && ss->channels == 1) - return 0; + return 8; if (ss->format == PA_SAMPLE_S16BE && ss->rate == 44100 && ss->channels == 2) return 10; if (ss->format == PA_SAMPLE_S16BE && ss->rate == 44100 && ss->channels == 1) @@ -164,6 +252,41 @@ uint8_t pa_rtp_payload_type(const pa_sample_spec *ss) { return 127; } +pa_sample_spec *pa_rtp_sample_spec_from_payload(uint8_t payload, pa_sample_spec *ss) { + assert(ss); + + switch (payload) { + case 0: + ss->channels = 1; + ss->format = PA_SAMPLE_ULAW; + ss->rate = 8000; + break; + + case 8: + ss->channels = 1; + ss->format = PA_SAMPLE_ALAW; + ss->rate = 8000; + break; + + case 10: + ss->channels = 2; + ss->format = PA_SAMPLE_S16BE; + ss->rate = 44100; + break; + + case 11: + ss->channels = 1; + ss->format = PA_SAMPLE_S16BE; + ss->rate = 44100; + break; + + default: + return NULL; + } + + return ss; +} + pa_sample_spec *pa_rtp_sample_spec_fixup(pa_sample_spec * ss) { assert(ss); @@ -192,3 +315,34 @@ void pa_rtp_context_destroy(pa_rtp_context *c) { close(c->fd); } + +const char* pa_rtp_format_to_string(pa_sample_format_t f) { + switch (f) { + case PA_SAMPLE_S16BE: + return "L16"; + case PA_SAMPLE_U8: + return "L8"; + case PA_SAMPLE_ALAW: + return "PCMA"; + case PA_SAMPLE_ULAW: + return "PCMU"; + default: + return NULL; + } +} + +pa_sample_format_t pa_rtp_string_to_format(const char *s) { + assert(s); + + if (!(strcmp(s, "L16"))) + return PA_SAMPLE_S16BE; + else if (!strcmp(s, "L8")) + return PA_SAMPLE_U8; + else if (!strcmp(s, "PCMA")) + return PA_SAMPLE_ALAW; + else if (!strcmp(s, "PCMU")) + return PA_SAMPLE_ULAW; + else + return PA_SAMPLE_INVALID; +} + diff --git a/src/modules/rtp/rtp.h b/src/modules/rtp/rtp.h index 39288158..49da155b 100644 --- a/src/modules/rtp/rtp.h +++ b/src/modules/rtp/rtp.h @@ -40,13 +40,18 @@ typedef struct pa_rtp_context { pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssrc, uint8_t payload, size_t frame_size); int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q); -pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd); -int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk); +pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd, size_t frame_size); +int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_memblock_stat *st); + +void pa_rtp_context_destroy(pa_rtp_context *c); -uint8_t pa_rtp_payload_type(const pa_sample_spec *ss); pa_sample_spec* pa_rtp_sample_spec_fixup(pa_sample_spec *ss); int pa_rtp_sample_spec_valid(const pa_sample_spec *ss); -void pa_rtp_context_destroy(pa_rtp_context *c); +uint8_t pa_rtp_payload_from_sample_spec(const pa_sample_spec *ss); +pa_sample_spec *pa_rtp_sample_spec_from_payload(uint8_t payload, pa_sample_spec *ss); + +const char* pa_rtp_format_to_string(pa_sample_format_t f); +pa_sample_format_t pa_rtp_string_to_format(const char *s); #endif diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c index ebf20bc4..0c12322e 100644 --- a/src/modules/rtp/sap.c +++ b/src/modules/rtp/sap.c @@ -32,12 +32,16 @@ #include #include #include +#include #include #include #include #include "sap.h" +#include "sdp.h" + +#define MIME_TYPE "application/sdp" pa_sap_context* pa_sap_context_init_send(pa_sap_context *c, int fd, char *sdp_data) { assert(c); @@ -60,7 +64,6 @@ void pa_sap_context_destroy(pa_sap_context *c) { int pa_sap_send(pa_sap_context *c, int goodbye) { uint32_t header; - const char mime[] = "application/sdp"; struct sockaddr_storage sa_buf; struct sockaddr *sa = (struct sockaddr*) &sa_buf; socklen_t salen = sizeof(sa_buf); @@ -86,8 +89,8 @@ int pa_sap_send(pa_sap_context *c, int goodbye) { iov[1].iov_base = sa->sa_family == AF_INET ? (void*) &((struct sockaddr_in*) sa)->sin_addr : (void*) &((struct sockaddr_in6*) sa)->sin6_addr; iov[1].iov_len = sa->sa_family == AF_INET ? 4 : 16; - iov[2].iov_base = (char*) mime; - iov[2].iov_len = sizeof(mime); + iov[2].iov_base = (char*) MIME_TYPE; + iov[2].iov_len = sizeof(MIME_TYPE); iov[3].iov_base = c->sdp_data; iov[3].iov_len = strlen(c->sdp_data); @@ -105,3 +108,110 @@ int pa_sap_send(pa_sap_context *c, int goodbye) { return k; } + +pa_sap_context* pa_sap_context_init_recv(pa_sap_context *c, int fd) { + assert(c); + assert(fd >= 0); + + c->fd = fd; + c->sdp_data = NULL; + return c; +} + +int pa_sap_recv(pa_sap_context *c, int *goodbye) { + struct msghdr m; + struct iovec iov; + int size, k; + char *buf = NULL, *e; + uint32_t header; + int six, ac; + ssize_t r; + + assert(c); + assert(goodbye); + + if (ioctl(c->fd, FIONREAD, &size) < 0) { + pa_log(__FILE__": FIONREAD failed: %s", strerror(errno)); + goto fail; + } + + if (!size) + return 0; + + buf = pa_xnew(char, size+1); + buf[size] = 0; + + iov.iov_base = buf; + iov.iov_len = size; + + m.msg_name = NULL; + m.msg_namelen = 0; + m.msg_iov = &iov; + m.msg_iovlen = 1; + m.msg_control = NULL; + m.msg_controllen = 0; + m.msg_flags = 0; + + if ((r = recvmsg(c->fd, &m, 0)) != size) { + pa_log(__FILE__": recvmsg() failed: %s", r < 0 ? strerror(errno) : "size mismatch"); + goto fail; + } + + if (size < 4) { + pa_log(__FILE__": SAP packet too short."); + goto fail; + } + + memcpy(&header, buf, sizeof(uint32_t)); + header = ntohl(header); + + if (header >> 29 != 1) { + pa_log(__FILE__": Unsupported SAP version."); + goto fail; + } + + if ((header >> 25) & 1) { + pa_log(__FILE__": Encrypted SAP not supported."); + goto fail; + } + + if ((header >> 24) & 1) { + pa_log(__FILE__": Compressed SAP not supported."); + goto fail; + } + + six = (header >> 28) & 1; + ac = (header >> 16) & 0xFF; + + k = 4 + (six ? 16 : 4) + ac*4; + if (size < k) { + pa_log(__FILE__": SAP packet too short (AD)."); + goto fail; + } + + e = buf + k; + size -= k; + + if ((unsigned) size >= sizeof(MIME_TYPE) && !strcmp(e, MIME_TYPE)) { + e += sizeof(MIME_TYPE); + size -= sizeof(MIME_TYPE); + } else if ((unsigned) size < sizeof(PA_SDP_HEADER)-1 || strncmp(e, PA_SDP_HEADER, sizeof(PA_SDP_HEADER)-1)) { + pa_log(__FILE__": Invalid SDP header."); + goto fail; + } + + if (c->sdp_data) + pa_xfree(c->sdp_data); + + c->sdp_data = pa_xstrndup(e, size); + pa_xfree(buf); + + *goodbye = !!((header >> 26) & 1); + + return 0; + +fail: + pa_xfree(buf); + + return -1; +} diff --git a/src/modules/rtp/sap.h b/src/modules/rtp/sap.h index 787b39f7..b11b1dd7 100644 --- a/src/modules/rtp/sap.h +++ b/src/modules/rtp/sap.h @@ -40,4 +40,7 @@ void pa_sap_context_destroy(pa_sap_context *c); int pa_sap_send(pa_sap_context *c, int goodbye); +pa_sap_context* pa_sap_context_init_recv(pa_sap_context *c, int fd); +int pa_sap_recv(pa_sap_context *c, int *goodbye); + #endif diff --git a/src/modules/rtp/sdp.c b/src/modules/rtp/sdp.c index 99e8c12b..9dca15ba 100644 --- a/src/modules/rtp/sdp.c +++ b/src/modules/rtp/sdp.c @@ -29,21 +29,15 @@ #include #include #include +#include #include +#include +#include #include "sdp.h" +#include "rtp.h" -static const char* map_format(pa_sample_format_t f) { - switch (f) { - case PA_SAMPLE_S16BE: return "L16"; - case PA_SAMPLE_U8: return "L8"; - case PA_SAMPLE_ALAW: return "PCMA"; - case PA_SAMPLE_ULAW: return "PCMU"; - default: - return NULL; - } -} char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, uint16_t port, uint8_t payload, const pa_sample_spec *ss) { uint32_t ntp; @@ -54,7 +48,7 @@ char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, u assert(dst); assert(af == AF_INET || af == AF_INET6); - f = map_format(ss->format); + f = pa_rtp_format_to_string(ss->format); assert(f); if (!(u = getenv("USER"))) @@ -69,7 +63,7 @@ char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, u assert(a); return pa_sprintf_malloc( - "v=0\n" + PA_SDP_HEADER "o=%s %lu 0 IN %s %s\n" "s=%s\n" "c=IN %s %s\n" @@ -85,3 +79,183 @@ char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, u port, payload, payload, f, ss->rate, ss->channels); } + +static pa_sample_spec *parse_sdp_sample_spec(pa_sample_spec *ss, char *c) { + unsigned rate, channels; + assert(ss); + assert(c); + + if (pa_startswith(c, "L16/")) { + ss->format = PA_SAMPLE_S16BE; + c += 4; + } else if (pa_startswith(c, "L8/")) { + ss->format = PA_SAMPLE_U8; + c += 3; + } else if (pa_startswith(c, "PCMA/")) { + ss->format = PA_SAMPLE_ALAW; + c += 5; + } else if (pa_startswith(c, "PCMU/")) { + ss->format = PA_SAMPLE_ULAW; + c += 5; + } else + return NULL; + + if (sscanf(c, "%u/%u", &rate, &channels) == 2) { + ss->rate = rate; + ss->channels = channels; + } else if (sscanf(c, "%u", &rate) == 2) { + ss->rate = rate; + ss->channels = 1; + } else + return NULL; + + if (!pa_sample_spec_valid(ss)) + return NULL; + + return ss; +} + +pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { + uint16_t port = 0; + int ss_valid = 0; + + assert(t); + assert(i); + + i->origin = i->session_name = NULL; + i->salen = 0; + i->payload = 255; + + if (!pa_startswith(t, PA_SDP_HEADER)) { + pa_log(__FILE__": Failed to parse SDP data: invalid header."); + goto fail; + } + + t += sizeof(PA_SDP_HEADER)-1; + + while (*t) { + size_t l; + + l = strcspn(t, "\n"); + + if (l <= 2) { + pa_log(__FILE__": Failed to parse SDP data: line too short: >%s<.", t); + goto fail; + } + + if (pa_startswith(t, "o=")) + i->origin = pa_xstrndup(t+2, l-2); + else if (pa_startswith(t, "s=")) + i->session_name = pa_xstrndup(t+2, l-2); + else if (pa_startswith(t, "c=IN IP4 ")) { + char a[64]; + size_t k; + + k = l-8 > sizeof(a) ? sizeof(a) : l-8; + + pa_strlcpy(a, t+9, k); + a[strcspn(a, "/")] = 0; + + if (inet_pton(AF_INET, a, &((struct sockaddr_in*) &i->sa)->sin_addr) <= 0) { + pa_log(__FILE__": Failed to parse SDP data: bad address: >%s<.", a); + goto fail; + } + + ((struct sockaddr_in*) &i->sa)->sin_family = AF_INET; + ((struct sockaddr_in*) &i->sa)->sin_port = 0; + i->salen = sizeof(struct sockaddr_in); + } else if (pa_startswith(t, "c=IN IP6 ")) { + char a[64]; + size_t k; + + k = l-8 > sizeof(a) ? sizeof(a) : l-8; + + pa_strlcpy(a, t+9, k); + a[strcspn(a, "/")] = 0; + + if (inet_pton(AF_INET6, a, &((struct sockaddr_in6*) &i->sa)->sin6_addr) <= 0) { + pa_log(__FILE__": Failed to parse SDP data: bad address: >%s<.", a); + goto fail; + } + + ((struct sockaddr_in6*) &i->sa)->sin6_family = AF_INET6; + ((struct sockaddr_in6*) &i->sa)->sin6_port = 0; + i->salen = sizeof(struct sockaddr_in6); + } else if (pa_startswith(t, "m=audio ")) { + + if (i->payload > 127) { + int _port, _payload; + + if (sscanf(t+8, "%i RTP/AVP %i", &_port, &_payload) == 2) { + + if (_port <= 0 || _port > 0xFFFF) { + pa_log(__FILE__": Failed to parse SDP data: invalid port %i.", _port); + goto fail; + } + + if (_payload < 0 || _payload > 127) { + pa_log(__FILE__": Failed to parse SDP data: invalid payload %i.", _payload); + goto fail; + } + + port = (uint16_t) _port; + i->payload = (uint8_t) _payload; + + if (pa_rtp_sample_spec_from_payload(i->payload, &i->sample_spec)) + ss_valid = 1; + } + } + } else if (pa_startswith(t, "a=rtpmap:")) { + + if (i->payload <= 127) { + char c[64]; + int _payload; + + if (sscanf(t+9, "%i %64c", &_payload, c) == 2) { + + if (_payload < 0 || _payload > 127) { + pa_log(__FILE__": Failed to parse SDP data: invalid payload %i.", _payload); + goto fail; + } + if (_payload == i->payload) { + + c[strcspn(c, "\n")] = 0; + + if (parse_sdp_sample_spec(&i->sample_spec, c)) + ss_valid = 1; + } + } + } + } + + t += l; + + if (*t == '\n') + t++; + } + + if (!i->origin || (!is_goodbye && (!i->salen || i->payload > 127 || !ss_valid || port == 0))) { + pa_log(__FILE__": Failed to parse SDP data: missing data."); + goto fail; + } + + if (((struct sockaddr*) &i->sa)->sa_family == AF_INET) + ((struct sockaddr_in*) &i->sa)->sin_port = htons(port); + else + ((struct sockaddr_in6*) &i->sa)->sin6_port = htons(port); + + return i; + +fail: + pa_xfree(i->origin); + pa_xfree(i->session_name); + + return NULL; +} + +void pa_sdp_info_destroy(pa_sdp_info *i) { + assert(i); + + pa_xfree(i->origin); + pa_xfree(i->session_name); +} diff --git a/src/modules/rtp/sdp.h b/src/modules/rtp/sdp.h index 10820067..2aa18056 100644 --- a/src/modules/rtp/sdp.h +++ b/src/modules/rtp/sdp.h @@ -28,6 +28,23 @@ #include +#define PA_SDP_HEADER "v=0\n" + +typedef struct pa_sdp_info { + char *origin; + char *session_name; + + struct sockaddr_storage sa; + socklen_t salen; + + pa_sample_spec sample_spec; + uint8_t payload; +} pa_sdp_info; + char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, uint16_t port, uint8_t payload, const pa_sample_spec *ss); +pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *info, int is_goodbye); + +void pa_sdp_info_destroy(pa_sdp_info *i); + #endif -- cgit From a176d77b1bfc8c33a7af520c30dedda596961136 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Apr 2006 00:18:59 +0000 Subject: todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@717 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index 4a84054f..8688f05d 100644 --- a/doc/todo +++ b/doc/todo @@ -2,7 +2,6 @@ Post 0.8: - alsa mmap driver -- add radio module - dbus/hal - polish for starting polypaudio as root/system-wide instance - chroot() -- cgit From d50255ac1e8856943b9057a365e1b9be83ac9124 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Apr 2006 09:12:31 +0000 Subject: * add new check for $RANDOM_DEVICE * move AC_SYS_LARGEFILE to avoid autoconf warning git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@718 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 6511137e..e649e063 100644 --- a/configure.ac +++ b/configure.ac @@ -36,10 +36,6 @@ if type -p stow > /dev/null && test -d /usr/local/stow ; then ac_default_prefix="/usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION}" fi -#### Large File-Support (LFS) #### - -AC_SYS_LARGEFILE - #### Checks for programs. #### # CC @@ -234,6 +230,10 @@ AC_CHECK_FUNCS(setreuid) ACX_PTHREAD +#### Large File-Support (LFS) #### + +AC_SYS_LARGEFILE + ################################### # External libraries # ################################### @@ -374,6 +374,26 @@ AC_SUBST(LIRC_CFLAGS) AC_SUBST(LIRC_LIBS) AM_CONDITIONAL([HAVE_LIRC], [test "x$HAVE_LIRC" = x1]) +### /dev/random ### + +AC_MSG_CHECKING([whether a random device is available]) + +rnd="no" + +if test -e /dev/urandom ; then + rnd=/dev/urandom +else + if test -e /dev/random ; then + rnd=/dev/random + fi +fi + +if test "x$rnd" != "no" ; then + AC_DEFINE_UNQUOTED([RANDOM_DEVICE], ["$rnd"], [Random device]) +fi + +AC_MSG_RESULT([$rnd]) + ################################### # Output # ################################### -- cgit From 0990d8c796e9896e791d1ce23557e6d2f5ecf5b0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Apr 2006 09:13:09 +0000 Subject: initialize random seed globaly from $RANDOM_DEVICE git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@719 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/main.c | 25 +++++++++++++++++++++++++ src/polypcore/random.c | 6 ------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/daemon/main.c b/src/daemon/main.c index 8457916a..d783531a 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -135,6 +135,29 @@ static void close_pipe(int p[2]) { p[0] = p[1] = -1; } +static void set_random_seed(void) { + unsigned int seed = 0; + +#ifdef RANDOM_DEVICE + int fd; + + if ((fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) { + ssize_t r; + + if ((r = pa_loop_read(fd, &seed, sizeof(seed))) < 0 || (size_t) r != sizeof(seed)) { + pa_log_error(__FILE__": failed to read entropy from '"RANDOM_DEVICE"'"); + seed += (unsigned int) time(NULL); + } + + close(fd); + } +#else + seed = (unsigned int) time(NULL); +#endif + + srand(seed); +} + int main(int argc, char *argv[]) { pa_core *c; pa_strbuf *buf = NULL; @@ -180,6 +203,8 @@ int main(int argc, char *argv[]) { } #endif + set_random_seed(); + pa_log_set_ident("polypaudio"); conf = pa_daemon_conf_new(); diff --git a/src/polypcore/random.c b/src/polypcore/random.c index 1c2280e3..ffd40474 100644 --- a/src/polypcore/random.c +++ b/src/polypcore/random.c @@ -36,10 +36,6 @@ #include "random.h" -#ifndef OS_IS_WIN32 -#define RANDOM_DEVICE "/dev/urandom" -#endif - void pa_random(void *ret_data, size_t length) { int fd; ssize_t r = 0; @@ -64,8 +60,6 @@ void pa_random(void *ret_data, size_t length) { ", falling back to unsecure pseudo RNG.\n", strerror(errno)); #endif - srand(time(NULL)); - for (p = ret_data, l = length; l > 0; p++, l--) *p = (uint8_t) rand(); } -- cgit From 998affc9842f59bd637cafa2e2361a8000bddc7c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Apr 2006 09:13:41 +0000 Subject: replace homegrown endswith() with pa_endswith() from util.h git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@720 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-detect.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index b24d838b..6b2e2742 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "module-detect-symdef.h" @@ -45,20 +46,8 @@ PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("just-one=") -static const char *endswith(const char *haystack, const char *needle) { - size_t l, m; - const char *p; - - if ((l = strlen(haystack)) < (m = strlen(needle))) - return NULL; - - if (strcmp(p = haystack + l - m, needle)) - return NULL; - - return p; -} - #ifdef HAVE_ALSA + static int detect_alsa(pa_core *c, int just_one) { FILE *f; int n = 0, n_sink = 0, n_source = 0; @@ -81,9 +70,9 @@ static int detect_alsa(pa_core *c, int just_one) { line[strcspn(line, "\r\n")] = 0; - if (endswith(line, "digital audio playback")) + if (pa_endswith(line, "digital audio playback")) is_sink = 1; - else if (endswith(line, "digital audio capture")) + else if (pa_endswith(line, "digital audio capture")) is_sink = 0; else continue; -- cgit From 67b105bd7af57c14755fae7bed3efc38766d0c03 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Apr 2006 09:14:55 +0000 Subject: * increase default MTU * change default mcast address to 224.0.1.3 * randomize RTP ports by default git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@721 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/rtp/module-rtp-monitor.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/modules/rtp/module-rtp-monitor.c b/src/modules/rtp/module-rtp-monitor.c index 5ff25557..0a050ca5 100644 --- a/src/modules/rtp/module-rtp-monitor.c +++ b/src/modules/rtp/module-rtp-monitor.c @@ -63,11 +63,11 @@ PA_MODULE_USAGE( "loop=" ) -#define DEFAULT_PORT 5004 +#define DEFAULT_PORT 46000 #define SAP_PORT 9875 -#define DEFAULT_DESTINATION "224.0.1.2" +#define DEFAULT_DESTINATION "224.0.1.3" #define MEMBLOCKQ_MAXLENGTH (1024*170) -#define DEFAULT_MTU 1024 +#define DEFAULT_MTU 1280 #define SAP_INTERVAL 5000000 static const char* const valid_modargs[] = { @@ -207,7 +207,8 @@ int pa__init(pa_core *c, pa_module*m) { pa_log(__FILE__": invalid mtu."); goto fail; } - + + port = DEFAULT_PORT + (rand() % 512); if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) { pa_log(__FILE__": port= expects a numerical argument between 1 and 65535."); goto fail; -- cgit From c999fe40b841b035c7d0c873b4a4875e12e9c9a4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Apr 2006 09:15:51 +0000 Subject: * deal properly with underruns, overflows and packet losses * change default mcast address * detect RTP loops git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@722 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/rtp/module-rtp-recv.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index 1ac057d0..610dc6e2 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "module-rtp-recv-symdef.h" @@ -57,7 +58,7 @@ PA_MODULE_USAGE( ) #define SAP_PORT 9875 -#define DEFAULT_SAP_ADDRESS "224.0.1.2" +#define DEFAULT_SAP_ADDRESS "224.0.1.3" #define MEMBLOCKQ_MAXLENGTH (1024*170) #define MAX_SESSIONS 16 #define DEATH_TIMEOUT 20000000 @@ -157,6 +158,9 @@ static void rtp_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event s->ssrc = s->rtp_context.ssrc; s->offset = s->rtp_context.timestamp; + + if (s->ssrc == s->userdata->core->cookie) + pa_log_warn(__FILE__": WARNING! Detected RTP packet loop!"); } else { if (s->ssrc != s->rtp_context.ssrc) { pa_memblock_unref(chunk.memblock); @@ -174,7 +178,12 @@ static void rtp_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event delta = j; pa_memblockq_seek(s->memblockq, delta * s->rtp_context.frame_size, PA_SEEK_RELATIVE); - pa_memblockq_push(s->memblockq, &chunk); + + if (pa_memblockq_push(s->memblockq, &chunk) < 0) { + /* queue overflow, let's flush it and try again */ + pa_memblockq_flush(s->memblockq); + pa_memblockq_push(s->memblockq, &chunk); + } /* The next timestamp we expect */ s->offset = s->rtp_context.timestamp + (chunk.length / s->rtp_context.frame_size); @@ -250,6 +259,7 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in char *c; pa_sink *sink; int fd = -1; + pa_memblock *silence; if (!(sink = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) { pa_log(__FILE__": sink does not exist."); @@ -284,19 +294,26 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in s->sink_input->drop = sink_input_drop; s->sink_input->kill = sink_input_kill; s->sink_input->get_latency = sink_input_get_latency; + + silence = pa_silence_memblock_new(&s->sink_input->sample_spec, + (pa_bytes_per_second(&s->sink_input->sample_spec)/128/pa_frame_size(&s->sink_input->sample_spec))* + pa_frame_size(&s->sink_input->sample_spec), + s->userdata->core->memblock_stat); s->memblockq = pa_memblockq_new( 0, MEMBLOCKQ_MAXLENGTH, MEMBLOCKQ_MAXLENGTH, pa_frame_size(&s->sink_input->sample_spec), - 1, + pa_bytes_per_second(&s->sink_input->sample_spec)/10+1, 0, - NULL, + silence, u->core->memblock_stat); - s->rtp_event = u->core->mainloop->io_new(u->core->mainloop, fd, PA_IO_EVENT_INPUT, rtp_event_cb, s); + pa_memblock_unref(silence); + s->rtp_event = u->core->mainloop->io_new(u->core->mainloop, fd, PA_IO_EVENT_INPUT, rtp_event_cb, s); + pa_gettimeofday(&tv); pa_timeval_add(&tv, DEATH_TIMEOUT); s->death_event = u->core->mainloop->time_new(u->core->mainloop, &tv, death_event_cb, s); -- cgit From e8d9a5dbfb368ae0dc8a3d6aa497ee30ed30f454 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 16 Apr 2006 09:22:08 +0000 Subject: Clarify behaviour of deferred events. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@723 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/context.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/polyp/context.h b/src/polyp/context.h index 01c1b76a..ff93dd11 100644 --- a/src/polyp/context.h +++ b/src/polyp/context.h @@ -41,7 +41,9 @@ * The API is based around an asynchronous event loop, or main loop, * abstraction. This abstraction contains three basic elements: * - * \li Deferred events - Events that trigger each iteration of the main loop. + * \li Deferred events - Events that will trigger as soon as possible. Note + * that some implementations may block all other events + * when a deferred event is active. * \li I/O events - Events that trigger on file descriptor activities. * \li Times events - Events that trigger after a fixed ammount of time. * -- cgit From e75cc68685c598deb71fdd0de4b68d43c595362d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 16 Apr 2006 09:23:27 +0000 Subject: Fix ALSA fd handling to be compatible with blocking deferred events. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@724 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 683db6c0..2f9be07a 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -89,7 +89,6 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t if (err < 0) { pa_log_error(__FILE__": Unable to get poll revent: %s", snd_strerror(err)); - a->defer_enable(fdl->defer, 0); return; } @@ -99,6 +98,8 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t else snd_mixer_handle_events(fdl->mixer); } + + a->defer_enable(fdl->defer, 1); } static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { @@ -108,6 +109,8 @@ static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { assert(a && fdl && (fdl->pcm || fdl->mixer)); + a->defer_enable(fdl->defer, 0); + if (fdl->pcm) num_fds = snd_pcm_poll_descriptors_count(fdl->pcm); else @@ -133,7 +136,6 @@ static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { if (err < 0) { pa_log_error(__FILE__": Unable to get poll descriptors: %s", snd_strerror(err)); - a->defer_enable(fdl->defer, 0); return; } -- cgit From 3b803e7168a92bbc4c43e47a1db64bce1513ca8b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Apr 2006 10:53:27 +0000 Subject: * make sure RTP ports are chosen to be even git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@725 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/rtp/module-rtp-monitor.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/modules/rtp/module-rtp-monitor.c b/src/modules/rtp/module-rtp-monitor.c index 0a050ca5..f91849ee 100644 --- a/src/modules/rtp/module-rtp-monitor.c +++ b/src/modules/rtp/module-rtp-monitor.c @@ -208,12 +208,15 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - port = DEFAULT_PORT + (rand() % 512); + port = DEFAULT_PORT + ((rand() % 512) << 1); if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) { pa_log(__FILE__": port= expects a numerical argument between 1 and 65535."); goto fail; } + if (port & 1) + pa_log_warn(__FILE__": WARNING: port number not even as suggested in RFC3550!"); + dest = pa_modargs_get_value(ma, "destination", DEFAULT_DESTINATION); if (inet_pton(AF_INET6, dest, &sa6.sin6_addr) > 0) { -- cgit From b04a4e65cae6d0fc9e4403b6147db36556d68159 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Apr 2006 10:56:45 +0000 Subject: rename module-rtp-monitor to module-rtp-send git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@726 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 12 +- src/modules/rtp/module-rtp-monitor.c | 363 ----------------------------------- src/modules/rtp/module-rtp-send.c | 363 +++++++++++++++++++++++++++++++++++ 3 files changed, 369 insertions(+), 369 deletions(-) delete mode 100644 src/modules/rtp/module-rtp-monitor.c create mode 100644 src/modules/rtp/module-rtp-send.c diff --git a/src/Makefile.am b/src/Makefile.am index 2ec62dca..c30e24c3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -722,7 +722,7 @@ modlib_LTLIBRARIES += \ module-esound-sink.la \ module-http-protocol-tcp.la \ module-detect.la \ - module-rtp-monitor.la \ + module-rtp-send.la \ module-rtp-recv.la if HAVE_AF_UNIX @@ -835,7 +835,7 @@ SYMDEF_FILES = \ modules/module-solaris-symdef.h \ modules/module-waveout-symdef.h \ modules/module-detect-symdef.h \ - modules/rtp/module-rtp-monitor-symdef.h \ + modules/rtp/module-rtp-send-symdef.h \ modules/rtp/module-rtp-recv-symdef.h EXTRA_DIST += $(SYMDEF_FILES) @@ -1052,10 +1052,10 @@ module_detect_la_LIBADD = $(AM_LIBADD) libpolypcore.la module_detect_la_CFLAGS = $(AM_CFLAGS) # RTP modules -module_rtp_monitor_la_SOURCES = modules/rtp/module-rtp-monitor.c -module_rtp_monitor_la_LDFLAGS = -module -avoid-version -module_rtp_monitor_la_LIBADD = $(AM_LIBADD) libpolypcore.la -module_rtp_monitor_la_CFLAGS = $(AM_CFLAGS) +module_rtp_send_la_SOURCES = modules/rtp/module-rtp-send.c +module_rtp_send_la_LDFLAGS = -module -avoid-version +module_rtp_send_la_LIBADD = $(AM_LIBADD) libpolypcore.la +module_rtp_send_la_CFLAGS = $(AM_CFLAGS) module_rtp_recv_la_SOURCES = modules/rtp/module-rtp-recv.c module_rtp_recv_la_LDFLAGS = -module -avoid-version diff --git a/src/modules/rtp/module-rtp-monitor.c b/src/modules/rtp/module-rtp-monitor.c deleted file mode 100644 index f91849ee..00000000 --- a/src/modules/rtp/module-rtp-monitor.c +++ /dev/null @@ -1,363 +0,0 @@ -/* $Id */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "module-rtp-monitor-symdef.h" - -#include "rtp.h" -#include "sdp.h" -#include "sap.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Read data from source and send it to the network via RTP/SAP/SDP") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE( - "source= " - "format= " - "channels= " - "rate= " - "destinaton= " - "port= " - "mtu= " - "loop=" -) - -#define DEFAULT_PORT 46000 -#define SAP_PORT 9875 -#define DEFAULT_DESTINATION "224.0.1.3" -#define MEMBLOCKQ_MAXLENGTH (1024*170) -#define DEFAULT_MTU 1280 -#define SAP_INTERVAL 5000000 - -static const char* const valid_modargs[] = { - "source", - "format", - "channels", - "rate", - "destination", - "port", - "loop", - NULL -}; - -struct userdata { - pa_module *module; - pa_core *core; - - pa_source_output *source_output; - pa_memblockq *memblockq; - - pa_rtp_context rtp_context; - pa_sap_context sap_context; - size_t mtu; - - pa_time_event *sap_event; -}; - -static void source_output_push(pa_source_output *o, const pa_memchunk *chunk) { - struct userdata *u; - assert(o); - u = o->userdata; - - if (pa_memblockq_push(u->memblockq, chunk) < 0) { - pa_log(__FILE__": Failed to push chunk into memblockq."); - return; - } - - pa_rtp_send(&u->rtp_context, u->mtu, u->memblockq); -} - -static void source_output_kill(pa_source_output* o) { - struct userdata *u; - assert(o); - u = o->userdata; - - pa_module_unload_request(u->module); - - pa_source_output_disconnect(u->source_output); - pa_source_output_unref(u->source_output); - u->source_output = NULL; -} - -static pa_usec_t source_output_get_latency (pa_source_output *o) { - struct userdata *u; - assert(o); - u = o->userdata; - - return pa_bytes_to_usec(pa_memblockq_get_length(u->memblockq), &o->sample_spec); -} - -static void sap_event_cb(pa_mainloop_api *m, pa_time_event *t, const struct timeval *tv, void *userdata) { - struct userdata *u = userdata; - struct timeval next; - - assert(m); - assert(t); - assert(tv); - assert(u); - - pa_sap_send(&u->sap_context, 0); - - pa_gettimeofday(&next); - pa_timeval_add(&next, SAP_INTERVAL); - m->time_restart(t, &next); -} - -int pa__init(pa_core *c, pa_module*m) { - struct userdata *u; - pa_modargs *ma = NULL; - const char *dest; - uint32_t port = DEFAULT_PORT, mtu; - int af, fd = -1, sap_fd = -1; - pa_source *s; - pa_sample_spec ss; - pa_channel_map cm; - struct sockaddr_in sa4, sap_sa4; - struct sockaddr_in6 sa6, sap_sa6; - struct sockaddr_storage sa_dst; - pa_source_output *o = NULL; - uint8_t payload; - char *p; - int r; - socklen_t k; - struct timeval tv; - char hn[128], *n; - int loop = 0; - - assert(c); - assert(m); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments"); - goto fail; - } - - if (!(s = pa_namereg_get(m->core, pa_modargs_get_value(ma, "source", NULL), PA_NAMEREG_SOURCE, 1))) { - pa_log(__FILE__": source does not exist."); - goto fail; - } - - if (pa_modargs_get_value_boolean(ma, "loop", &loop) < 0) { - pa_log(__FILE__": failed to parse \"loop\" parameter."); - goto fail; - } - - ss = s->sample_spec; - pa_rtp_sample_spec_fixup(&ss); - cm = s->channel_map; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": failed to parse sample specification"); - goto fail; - } - - if (!pa_rtp_sample_spec_valid(&ss)) { - pa_log(__FILE__": specified sample type not compatible with RTP"); - goto fail; - } - - if (ss.channels != cm.channels) - pa_channel_map_init_auto(&cm, ss.channels); - - payload = pa_rtp_payload_from_sample_spec(&ss); - - mtu = (DEFAULT_MTU/pa_frame_size(&ss))*pa_frame_size(&ss); - - if (pa_modargs_get_value_u32(ma, "mtu", &mtu) < 0 || mtu < 1 || mtu % pa_frame_size(&ss) != 0) { - pa_log(__FILE__": invalid mtu."); - goto fail; - } - - port = DEFAULT_PORT + ((rand() % 512) << 1); - if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) { - pa_log(__FILE__": port= expects a numerical argument between 1 and 65535."); - goto fail; - } - - if (port & 1) - pa_log_warn(__FILE__": WARNING: port number not even as suggested in RFC3550!"); - - dest = pa_modargs_get_value(ma, "destination", DEFAULT_DESTINATION); - - if (inet_pton(AF_INET6, dest, &sa6.sin6_addr) > 0) { - sa6.sin6_family = af = AF_INET6; - sa6.sin6_port = htons(port); - sap_sa6 = sa6; - sap_sa6.sin6_port = htons(SAP_PORT); - } else if (inet_pton(AF_INET, dest, &sa4.sin_addr) > 0) { - sa4.sin_family = af = AF_INET; - sa4.sin_port = htons(port); - sap_sa4 = sa4; - sap_sa4.sin_port = htons(SAP_PORT); - } else { - pa_log(__FILE__": invalid destination '%s'", dest); - goto fail; - } - - if ((fd = socket(af, SOCK_DGRAM, 0)) < 0) { - pa_log(__FILE__": socket() failed: %s", strerror(errno)); - goto fail; - } - - if (connect(fd, af == AF_INET ? (struct sockaddr*) &sa4 : (struct sockaddr*) &sa6, af == AF_INET ? sizeof(sa4) : sizeof(sa6)) < 0) { - pa_log(__FILE__": connect() failed: %s", strerror(errno)); - goto fail; - } - - if ((sap_fd = socket(af, SOCK_DGRAM, 0)) < 0) { - pa_log(__FILE__": socket() failed: %s", strerror(errno)); - goto fail; - } - - if (connect(sap_fd, af == AF_INET ? (struct sockaddr*) &sap_sa4 : (struct sockaddr*) &sap_sa6, af == AF_INET ? sizeof(sap_sa4) : sizeof(sap_sa6)) < 0) { - pa_log(__FILE__": connect() failed: %s", strerror(errno)); - goto fail; - } - - if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0 || - setsockopt(sap_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) { - pa_log(__FILE__": IP_MULTICAST_LOOP failed: %s", strerror(errno)); - goto fail; - } - - if (!(o = pa_source_output_new(s, __FILE__, "RTP Monitor Stream", &ss, &cm, PA_RESAMPLER_INVALID))) { - pa_log(__FILE__": failed to create source output."); - goto fail; - } - - o->push = source_output_push; - o->kill = source_output_kill; - o->get_latency = source_output_get_latency; - o->owner = m; - - u = pa_xnew(struct userdata, 1); - m->userdata = u; - o->userdata = u; - - u->module = m; - u->core = c; - u->source_output = o; - - u->memblockq = pa_memblockq_new( - 0, - MEMBLOCKQ_MAXLENGTH, - MEMBLOCKQ_MAXLENGTH, - pa_frame_size(&ss), - 1, - 0, - NULL, - c->memblock_stat); - - u->mtu = mtu; - - k = sizeof(sa_dst); - r = getsockname(fd, (struct sockaddr*) &sa_dst, &k); - assert(r >= 0); - - n = pa_sprintf_malloc("Polypaudio RTP Stream on %s", pa_get_fqdn(hn, sizeof(hn))); - - p = pa_sdp_build(af, - af == AF_INET ? (void*) &((struct sockaddr_in*) &sa_dst)->sin_addr : (void*) &((struct sockaddr_in6*) &sa_dst)->sin6_addr, - af == AF_INET ? (void*) &sa4.sin_addr : (void*) &sa6.sin6_addr, - n, port, payload, &ss); - - pa_xfree(n); - - pa_rtp_context_init_send(&u->rtp_context, fd, c->cookie, payload, pa_frame_size(&ss)); - pa_sap_context_init_send(&u->sap_context, sap_fd, p); - - pa_log_info(__FILE__": RTP stream initialized with mtu %u on %s:%u, SSRC=0x%08x, payload=%u, initial sequence #%u", mtu, dest, port, u->rtp_context.ssrc, payload, u->rtp_context.sequence); - pa_log_info(__FILE__": SDP-Data:\n%s\n"__FILE__": EOF", p); - - pa_sap_send(&u->sap_context, 0); - - pa_gettimeofday(&tv); - pa_timeval_add(&tv, SAP_INTERVAL); - u->sap_event = c->mainloop->time_new(c->mainloop, &tv, sap_event_cb, u); - - pa_modargs_free(ma); - - return 0; - -fail: - if (ma) - pa_modargs_free(ma); - - if (fd >= 0) - close(fd); - - if (sap_fd >= 0) - close(sap_fd); - - if (o) { - pa_source_output_disconnect(o); - pa_source_output_unref(o); - } - - return -1; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u; - assert(c); - assert(m); - - if (!(u = m->userdata)) - return; - - c->mainloop->time_free(u->sap_event); - - if (u->source_output) { - pa_source_output_disconnect(u->source_output); - pa_source_output_unref(u->source_output); - } - - pa_rtp_context_destroy(&u->rtp_context); - - pa_sap_send(&u->sap_context, 1); - pa_sap_context_destroy(&u->sap_context); - - pa_memblockq_free(u->memblockq); - - pa_xfree(u); -} diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c new file mode 100644 index 00000000..d692cd1d --- /dev/null +++ b/src/modules/rtp/module-rtp-send.c @@ -0,0 +1,363 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-rtp-send-symdef.h" + +#include "rtp.h" +#include "sdp.h" +#include "sap.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Read data from source and send it to the network via RTP/SAP/SDP") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE( + "source= " + "format= " + "channels= " + "rate= " + "destinaton= " + "port= " + "mtu= " + "loop=" +) + +#define DEFAULT_PORT 46000 +#define SAP_PORT 9875 +#define DEFAULT_DESTINATION "224.0.1.3" +#define MEMBLOCKQ_MAXLENGTH (1024*170) +#define DEFAULT_MTU 1280 +#define SAP_INTERVAL 5000000 + +static const char* const valid_modargs[] = { + "source", + "format", + "channels", + "rate", + "destination", + "port", + "loop", + NULL +}; + +struct userdata { + pa_module *module; + pa_core *core; + + pa_source_output *source_output; + pa_memblockq *memblockq; + + pa_rtp_context rtp_context; + pa_sap_context sap_context; + size_t mtu; + + pa_time_event *sap_event; +}; + +static void source_output_push(pa_source_output *o, const pa_memchunk *chunk) { + struct userdata *u; + assert(o); + u = o->userdata; + + if (pa_memblockq_push(u->memblockq, chunk) < 0) { + pa_log(__FILE__": Failed to push chunk into memblockq."); + return; + } + + pa_rtp_send(&u->rtp_context, u->mtu, u->memblockq); +} + +static void source_output_kill(pa_source_output* o) { + struct userdata *u; + assert(o); + u = o->userdata; + + pa_module_unload_request(u->module); + + pa_source_output_disconnect(u->source_output); + pa_source_output_unref(u->source_output); + u->source_output = NULL; +} + +static pa_usec_t source_output_get_latency (pa_source_output *o) { + struct userdata *u; + assert(o); + u = o->userdata; + + return pa_bytes_to_usec(pa_memblockq_get_length(u->memblockq), &o->sample_spec); +} + +static void sap_event_cb(pa_mainloop_api *m, pa_time_event *t, const struct timeval *tv, void *userdata) { + struct userdata *u = userdata; + struct timeval next; + + assert(m); + assert(t); + assert(tv); + assert(u); + + pa_sap_send(&u->sap_context, 0); + + pa_gettimeofday(&next); + pa_timeval_add(&next, SAP_INTERVAL); + m->time_restart(t, &next); +} + +int pa__init(pa_core *c, pa_module*m) { + struct userdata *u; + pa_modargs *ma = NULL; + const char *dest; + uint32_t port = DEFAULT_PORT, mtu; + int af, fd = -1, sap_fd = -1; + pa_source *s; + pa_sample_spec ss; + pa_channel_map cm; + struct sockaddr_in sa4, sap_sa4; + struct sockaddr_in6 sa6, sap_sa6; + struct sockaddr_storage sa_dst; + pa_source_output *o = NULL; + uint8_t payload; + char *p; + int r; + socklen_t k; + struct timeval tv; + char hn[128], *n; + int loop = 0; + + assert(c); + assert(m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments"); + goto fail; + } + + if (!(s = pa_namereg_get(m->core, pa_modargs_get_value(ma, "source", NULL), PA_NAMEREG_SOURCE, 1))) { + pa_log(__FILE__": source does not exist."); + goto fail; + } + + if (pa_modargs_get_value_boolean(ma, "loop", &loop) < 0) { + pa_log(__FILE__": failed to parse \"loop\" parameter."); + goto fail; + } + + ss = s->sample_spec; + pa_rtp_sample_spec_fixup(&ss); + cm = s->channel_map; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": failed to parse sample specification"); + goto fail; + } + + if (!pa_rtp_sample_spec_valid(&ss)) { + pa_log(__FILE__": specified sample type not compatible with RTP"); + goto fail; + } + + if (ss.channels != cm.channels) + pa_channel_map_init_auto(&cm, ss.channels); + + payload = pa_rtp_payload_from_sample_spec(&ss); + + mtu = (DEFAULT_MTU/pa_frame_size(&ss))*pa_frame_size(&ss); + + if (pa_modargs_get_value_u32(ma, "mtu", &mtu) < 0 || mtu < 1 || mtu % pa_frame_size(&ss) != 0) { + pa_log(__FILE__": invalid mtu."); + goto fail; + } + + port = DEFAULT_PORT + ((rand() % 512) << 1); + if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) { + pa_log(__FILE__": port= expects a numerical argument between 1 and 65535."); + goto fail; + } + + if (port & 1) + pa_log_warn(__FILE__": WARNING: port number not even as suggested in RFC3550!"); + + dest = pa_modargs_get_value(ma, "destination", DEFAULT_DESTINATION); + + if (inet_pton(AF_INET6, dest, &sa6.sin6_addr) > 0) { + sa6.sin6_family = af = AF_INET6; + sa6.sin6_port = htons(port); + sap_sa6 = sa6; + sap_sa6.sin6_port = htons(SAP_PORT); + } else if (inet_pton(AF_INET, dest, &sa4.sin_addr) > 0) { + sa4.sin_family = af = AF_INET; + sa4.sin_port = htons(port); + sap_sa4 = sa4; + sap_sa4.sin_port = htons(SAP_PORT); + } else { + pa_log(__FILE__": invalid destination '%s'", dest); + goto fail; + } + + if ((fd = socket(af, SOCK_DGRAM, 0)) < 0) { + pa_log(__FILE__": socket() failed: %s", strerror(errno)); + goto fail; + } + + if (connect(fd, af == AF_INET ? (struct sockaddr*) &sa4 : (struct sockaddr*) &sa6, af == AF_INET ? sizeof(sa4) : sizeof(sa6)) < 0) { + pa_log(__FILE__": connect() failed: %s", strerror(errno)); + goto fail; + } + + if ((sap_fd = socket(af, SOCK_DGRAM, 0)) < 0) { + pa_log(__FILE__": socket() failed: %s", strerror(errno)); + goto fail; + } + + if (connect(sap_fd, af == AF_INET ? (struct sockaddr*) &sap_sa4 : (struct sockaddr*) &sap_sa6, af == AF_INET ? sizeof(sap_sa4) : sizeof(sap_sa6)) < 0) { + pa_log(__FILE__": connect() failed: %s", strerror(errno)); + goto fail; + } + + if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0 || + setsockopt(sap_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) { + pa_log(__FILE__": IP_MULTICAST_LOOP failed: %s", strerror(errno)); + goto fail; + } + + if (!(o = pa_source_output_new(s, __FILE__, "RTP Monitor Stream", &ss, &cm, PA_RESAMPLER_INVALID))) { + pa_log(__FILE__": failed to create source output."); + goto fail; + } + + o->push = source_output_push; + o->kill = source_output_kill; + o->get_latency = source_output_get_latency; + o->owner = m; + + u = pa_xnew(struct userdata, 1); + m->userdata = u; + o->userdata = u; + + u->module = m; + u->core = c; + u->source_output = o; + + u->memblockq = pa_memblockq_new( + 0, + MEMBLOCKQ_MAXLENGTH, + MEMBLOCKQ_MAXLENGTH, + pa_frame_size(&ss), + 1, + 0, + NULL, + c->memblock_stat); + + u->mtu = mtu; + + k = sizeof(sa_dst); + r = getsockname(fd, (struct sockaddr*) &sa_dst, &k); + assert(r >= 0); + + n = pa_sprintf_malloc("Polypaudio RTP Stream on %s", pa_get_fqdn(hn, sizeof(hn))); + + p = pa_sdp_build(af, + af == AF_INET ? (void*) &((struct sockaddr_in*) &sa_dst)->sin_addr : (void*) &((struct sockaddr_in6*) &sa_dst)->sin6_addr, + af == AF_INET ? (void*) &sa4.sin_addr : (void*) &sa6.sin6_addr, + n, port, payload, &ss); + + pa_xfree(n); + + pa_rtp_context_init_send(&u->rtp_context, fd, c->cookie, payload, pa_frame_size(&ss)); + pa_sap_context_init_send(&u->sap_context, sap_fd, p); + + pa_log_info(__FILE__": RTP stream initialized with mtu %u on %s:%u, SSRC=0x%08x, payload=%u, initial sequence #%u", mtu, dest, port, u->rtp_context.ssrc, payload, u->rtp_context.sequence); + pa_log_info(__FILE__": SDP-Data:\n%s\n"__FILE__": EOF", p); + + pa_sap_send(&u->sap_context, 0); + + pa_gettimeofday(&tv); + pa_timeval_add(&tv, SAP_INTERVAL); + u->sap_event = c->mainloop->time_new(c->mainloop, &tv, sap_event_cb, u); + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + if (fd >= 0) + close(fd); + + if (sap_fd >= 0) + close(sap_fd); + + if (o) { + pa_source_output_disconnect(o); + pa_source_output_unref(o); + } + + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c); + assert(m); + + if (!(u = m->userdata)) + return; + + c->mainloop->time_free(u->sap_event); + + if (u->source_output) { + pa_source_output_disconnect(u->source_output); + pa_source_output_unref(u->source_output); + } + + pa_rtp_context_destroy(&u->rtp_context); + + pa_sap_send(&u->sap_context, 1); + pa_sap_context_destroy(&u->sap_context); + + pa_memblockq_free(u->memblockq); + + pa_xfree(u); +} -- cgit -- cgit From e1887b552ceb324f70732c85c7458119e03718b7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Apr 2006 11:13:20 +0000 Subject: change default mcast address once again, to make sure our traffic doesn't leave the network by default git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@728 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/rtp/module-rtp-recv.c | 2 +- src/modules/rtp/module-rtp-send.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index 610dc6e2..e47ca95a 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -58,7 +58,7 @@ PA_MODULE_USAGE( ) #define SAP_PORT 9875 -#define DEFAULT_SAP_ADDRESS "224.0.1.3" +#define DEFAULT_SAP_ADDRESS "224.0.0.56" #define MEMBLOCKQ_MAXLENGTH (1024*170) #define MAX_SESSIONS 16 #define DEATH_TIMEOUT 20000000 diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index d692cd1d..69d8c6c6 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -65,7 +65,7 @@ PA_MODULE_USAGE( #define DEFAULT_PORT 46000 #define SAP_PORT 9875 -#define DEFAULT_DESTINATION "224.0.1.3" +#define DEFAULT_DESTINATION "224.0.0.56" #define MEMBLOCKQ_MAXLENGTH (1024*170) #define DEFAULT_MTU 1280 #define SAP_INTERVAL 5000000 -- cgit From 08397d98e23d3ec953c66bd8cd90efb316e4bad1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Apr 2006 12:44:15 +0000 Subject: fix typo in module description git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@729 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/rtp/module-rtp-send.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 69d8c6c6..0bb20979 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -57,7 +57,7 @@ PA_MODULE_USAGE( "format= " "channels= " "rate= " - "destinaton= " + "destination= " "port= " "mtu= " "loop=" -- cgit From 2f3fa42ca6dddc56c4ddab1d7d8ac89ff6eb75d6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Apr 2006 12:44:43 +0000 Subject: limit number of concurrent RTP streams git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@730 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/rtp/module-rtp-recv.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index e47ca95a..95d13c33 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -97,6 +97,8 @@ struct userdata { pa_hashmap *by_origin; char *sink_name; + + int n_sessions; }; static void session_free(struct session *s, int from_hash); @@ -261,6 +263,11 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in int fd = -1; pa_memblock *silence; + if (u->n_sessions >= MAX_SESSIONS) { + pa_log(__FILE__": session limit reached."); + goto fail; + } + if (!(sink = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) { pa_log(__FILE__": sink does not exist."); goto fail; @@ -323,6 +330,8 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in pa_rtp_context_init_recv(&s->rtp_context, fd, pa_frame_size(&s->sdp_info.sample_spec)); pa_log_info(__FILE__": Found new session '%s'", s->sdp_info.session_name); + + u->n_sessions++; return s; @@ -354,6 +363,9 @@ static void session_free(struct session *s, int from_hash) { pa_memblockq_free(s->memblockq); pa_sdp_info_destroy(&s->sdp_info); pa_rtp_context_destroy(&s->rtp_context); + + assert(s->userdata->n_sessions >= 1); + s->userdata->n_sessions--; pa_xfree(s); } -- cgit From 7871f41f2e49978b8c5451516e7a464b0985828b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Apr 2006 13:34:09 +0000 Subject: add documentation for the new RTP modules git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@731 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/FAQ.html.in | 97 ++++++++++++++++++++++++++++++++++++++++++++-- doc/README.html.in | 3 +- doc/modules.html.in | 108 +++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 184 insertions(+), 24 deletions(-) diff --git a/doc/FAQ.html.in b/doc/FAQ.html.in index 0e738217..7adc2441 100644 --- a/doc/FAQ.html.in +++ b/doc/FAQ.html.in @@ -67,7 +67,7 @@ realtime, or increase the fragment sizes of the audio drivers. The former will allow Polypaudio to activate SCHED_FIFO high priority scheduling (root rights are dropped - immediately after this) Keep in mind that this is a potential security hole!

    + immediately after this). Keep in mind that this is a potential security hole!

  • The polypaudio executable is installed SUID root by default. Why this? Isn't this a potential security hole?

    @@ -103,7 +103,12 @@ in ~/.polypaudio/.

  • How do I use polypaudio over the network?

    -

    Just set $POLYP_SERVER to the host name of the polypaudio server.

    +

    Just set $POLYP_SERVER to the host name of the polypaudio +server. For authentication you need the same auth cookies on all sides. For +that copy ~./polypaudio-cookie to all clients that shall +be allowed to connect.

    + +

    Alternatively the authorization cookies can be stored in the X11 server.

  • Is polypaudio capable of providing synchronized audio playback over the network for movie players like mplayer?

    @@ -126,7 +131,7 @@ connect to a running polypaudio daemon try using the following commands:

    killall -USR2 polypaudio
     bidilink unix-client:/tmp/polypaudio/cli
    -

    BTW: Someone should package that great tool for Debian!

    +

    BTW: Someone should package this great tool for Debian!

    New: There's now a tool pacmd that automates sending SIGUSR2 to the daemon and running a bidilink like tool for you.

  • @@ -146,7 +151,91 @@ bidilink unix-client:/tmp/polypaudio/cli
  • Why the heck does libpolyp link against libX11?

    -

    The Polypaudio client libraries look for some X11 root window properties for the credentials of the Polypaudio server to access. You may compile Polypaudio without X11 for disabling this.

  • +

    The Polypaudio client libraries look for some X11 root window +properties for the credentials of the Polypaudio server to access. You +may compile Polypaudio without X11 for disabling this feature.

    + +
  • How can I use Polypaudio as an RTP based N:N multicast +conferencing solution for the LAN?

    After loading all the +necessary audio drivers for recording and playback, just load the RTP +reciever and sender modules with default parameters:

    + +
    +load-module module-rtp-send
    +load-module module-rtp-recv
    +
    + +

    As long as the Polypaudio daemon runs, the microphone data will be +streamed to the network and the data from other hosts is played back +locally. Please note that this may cause quite a lot of traffic. Hence +consider passing rate=8000 format=ulaw channels=1 to the +sender module to save bandwith while still maintaining good quality +for speech transmission.

  • + +
  • What is this RTP/SDP/SAP thing all about?

    + +

    RTP is the Realtime Transfer Protocol. It is a well-known +protocol for transferring audio and video data over IP. SDP is the Session +Description Protocol and can be used to describe RTP sessions. SAP +is the Session Announcement Protocol and can be used to +announce RTP sessions that are described with SDP. (Modern SIP based VoIP phones use RTP/SDP for their sessions, too)

    + +

    All three protocols are defined in IETF RFCs (RFC3550, RFC3551, +RFC2327, RFC2327). They can be used in both multicast and unicast +fashions. Polypaudio exclusively uses multicast RTP/SDP/SAP containing audio data.

    + +

    For more information about using these technologies with Polypaudio have a look on the respective module's documentation. + +

  • How can I use Polypaudio to stream music from my main PC to my LAN with multiple PCs with speakers?

    + +

    On the sender side create an RTP sink:

    + +
    +load-module module-null-sink sink_name=rtp
    +load-module module-rtp-send source=rtp_monitor
    +set-default-sink rtp
    +
    + +

    This will make rtp the default sink, i.e. all applications will write to this virtual RTP device by default.

    + +

    On the client sides just load the reciever module:

    +
    +load-module module-rtp-recv
    +
    + +

    Now you can play your favourite music on the sender side and all clients will output it simultaneously.

    + + +

    BTW: You can have more than one sender machine set up like this. The audio data will be mixed on the client side.

  • + +
  • How can I use Polypaudio to share a single LINE-IN/MIC jack on the entire LAN?

    + +

    On the sender side simply load the RTP sender module:

    + +
    +load-module module-rtp-send
    +
    + +

    On the reciever sides, create an RTP source:

    + +
    +load-module module-null-sink sink_name=rtp
    +load-module module-rtp-recv sink=rtp
    +set-default-source rtp_monitor
    +
    + +

    Now the audio data will be available from the default source rtp_monitor.

    + +
  • When sending multicast RTP traffic it is recieved on the entire LAN but not by the sender machine itself!

    + +

    Pass loop=1 to the sender module!

  • + +
  • Can I have more than one multicast RTP group?

    + +

    Yes! Simply use a new multicast group address. Use +the destination/sap_address arguments of the RTP +modules to select them. Choose your group addresses from the range +225.0.0.x to make sure the audio data never leaves the LAN.

  • diff --git a/doc/README.html.in b/doc/README.html.in index 3847a9e8..0e9b8261 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -44,7 +44,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    Thu Apr 13 2006:

    Version 0.8 released; -changes include: too many to count; many, many minor fixes.

    +changes include: too many to count - consider reading this blog entry for more information; many, many minor fixes.

    Sun Nov 21 2004:

    Version 0.7 released; @@ -152,6 +152,7 @@ available. A simple main loop implementation is available as well.

  • module-lirc: a module to control the volume of a sink with infrared remote controls supported by LIRC.
  • module-mmkbd-evdev: a module to control the volume of a sink with the special volume keys of a multimeda keyboard.
  • module-zeroconf-publish: a module to publish local sources/sinks using mDNS zeroconf.
  • +
  • module-rtp-send, module-rtp-recv: a module to implement RTP/SAP/SDP based audio streaming.
  • polypaudio is the successor of my previous, ill-fated diff --git a/doc/modules.html.in b/doc/modules.html.in index 67f0e172..54cec804 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -283,7 +283,7 @@ module and point your browser to http://localhost:4714/. This module takes the same arguments as module-cli-protocol-tcp.

    -

    Miscellaneous

    +

    X Window System

    module-x11-bell

    @@ -315,6 +315,94 @@ and import credential data from/to the X11 display.

    cookie to store in the X11 display. If ommited the cookie of an already loaded protocol module is used. +

    Volume Control

    + +

    module-mmkbd-evdev

    + +

    Adjust the volume of a sink when the special multimedia buttons of modern keyboards are pressed.

    + + + + +
    device=Linux input device ("evdev", defaults to /dev/input/event0)
    sink=The sink to control
    + +

    module-lirc

    + +

    Adjust the volume of a sink when the volume buttons of an infrared remote control are pressed (through LIRC).

    + + + + + +
    config=The LIRC configuration file
    appname=The application name to pass to LIRC (defaults to polypaudio)
    sink=The sink to control
    + + +

    RTP/SDP/SAP Transport

    + +

    Polypaudio can stream audio data to an IP multicast group via the +standard protocols RTP, +SAP +and SDP +(RFC3550, RFC3551, RFC2327, RFC2327). This can be used for multiple +different purposes: for sharing a single microphone on multiple +computers on the local LAN, for streaming music from a single +controlling PC to multiple PCs with speakers or to implement a simple +"always-on" teleconferencing solution.

    + +

    The current implementation is designed to be used exlusively in +local area networks, though Internet multicasting is theoretically +supported. Only uncompressed audio is supported, hence you won't be +able to multicast more than a few streams at the same time over a +standard LAN.

    + +

    Polypaudio implements both a sender and a reciever for RTP +traffic. The sender announces itself via SAP/SDP on the same multicast +group as it sends the RTP data to. The reciever picks up the SAP/SDP +announcements and creates a playback stream for each +session. Alternatively you can use any RTP capable client to +recieve and play back the RTP data (such as mplayer).

    + +

    module-rtp-send

    + +

    This is the sender side of the RTP/SDP/SAP implementation. It reads +audio data from an existing source and forwards it to the network +encapsulated in RTP. In addition it sends SAP packets with an SDP +session description.

    + +

    In combination with the monitor source of module-null-sink +you can use this module to create an RTP sink.

    + + + + + + + + +
    source=The source to read the audio data from. If ommited defaults to the default source.
    format=, rate=, channels=Sample format to use, defaults to the source's.
    destination=Destination multicast group for both RTP and SAP packets, defaults to 224.0.0.56
    port=Destination port number of the RTP +traffic. If ommited defaults to a randomly chosen even port +number. Please keep in mind that the RFC suggests to use only even +port numbers for RTP traffic.
    mtu=Maximum payload size for RTP packets. If ommited defaults to 1280
    loop=Takes a boolean value, specifying whether locally generated RTP traffic should be looped back to the local host. Disabled by default.
    + +

    module-rtp-recv

    + +

    This is the reciever side of the RTP/SDP/SAP implementation. It +picks up SAP session announcements and creates an RTP playback stream +for each.

    + +

    In combination with module-null-sink you can use this +module to create an RTP source.

    + + + + +
    sink=The sink to connect to. If ommited defaults to the default sink.
    sap_address=The multicast group to join for SAP announcements, defaults to 224.0.0.56.
    + +

    Miscellaneous

    +

    module-sine

    Creates a sink input and generates a sine waveform stream.

    @@ -360,24 +448,6 @@ already loaded protocol module is used.

    Publish all local sinks/sources using mDNS Zeroconf.

    -

    module-mmkbd-evdev

    - -

    Adjust the volume of a sink when the special multimedia buttons of modern keyboards are pressed.

    - - - - -
    device=Linux input device ("evdev", defaults to /dev/input/event0)
    sink=The sink to control
    - -

    module-lirc

    - -

    Adjust the volume of a sink when the volume buttons of an infrared remote control are pressed (through LIRC).

    - - - - - -
    config=The LIRC configuration file
    appname=The application name to pass to LIRC (defaults to polypaudio)
    sink=The sink to control

    Lennart Poettering <@PACKAGE_BUGREPORT@>, April 2006
    -- cgit From a8bb073acc24c554ed3d8fcbd91b26b2799e641a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Apr 2006 16:45:47 +0000 Subject: properly initialize session counter git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@732 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/rtp/module-rtp-recv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index 95d13c33..525a8819 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -455,6 +455,7 @@ int pa__init(pa_core *c, pa_module*m) { u->module = m; u->core = c; u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); + u->n_sessions = 0; u->sap_event = c->mainloop->io_new(c->mainloop, fd, PA_IO_EVENT_INPUT, sap_event_cb, u); -- cgit From 76296ca8adccec12aa84163da55c6204d7667bf5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Apr 2006 16:46:26 +0000 Subject: add new API to replace the poll() function used by the main loop implementation git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@733 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/mainloop.c | 19 ++++++++++++++++++- src/polyp/mainloop.h | 8 ++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/polyp/mainloop.c b/src/polyp/mainloop.c index da3f57b2..87ef623e 100644 --- a/src/polyp/mainloop.c +++ b/src/polyp/mainloop.c @@ -101,6 +101,9 @@ struct pa_mainloop { STATE_POLLED, STATE_QUIT } state; + + pa_poll_func poll_func; + void *poll_func_userdata; }; /* IO events */ @@ -355,6 +358,9 @@ pa_mainloop *pa_mainloop_new(void) { m->deferred_pending = 0; m->state = STATE_PASSIVE; + + m->poll_func = NULL; + m->poll_func_userdata = NULL; return m; } @@ -665,7 +671,10 @@ int pa_mainloop_poll(pa_mainloop *m) { if (m->deferred_pending) r = 0; else { - r = poll(m->pollfds, m->n_pollfds, m->prepared_timeout); + if (m->poll_func) + r = m->poll_func(m->pollfds, m->n_pollfds, m->prepared_timeout, m->poll_func_userdata); + else + r = poll(m->pollfds, m->n_pollfds, m->prepared_timeout); if (r < 0) { if (errno == EINTR) @@ -767,6 +776,14 @@ pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m) { return &m->api; } +void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata) { + assert(m); + + m->poll_func = poll_func; + m->poll_func_userdata = userdata; +} + + #if 0 void pa_mainloop_dump(pa_mainloop *m) { assert(m); diff --git a/src/polyp/mainloop.h b/src/polyp/mainloop.h index fe2b4c5b..f60c355a 100644 --- a/src/polyp/mainloop.h +++ b/src/polyp/mainloop.h @@ -70,6 +70,8 @@ PA_C_DECL_BEGIN * defined in \ref mainloop-api.h. This implementation is thread safe * as long as you access the main loop object from a single thread only.*/ +#include + /** An opaque main loop object */ typedef struct pa_mainloop pa_mainloop; @@ -114,6 +116,12 @@ void pa_mainloop_quit(pa_mainloop *m, int r); /** Interrupt a running poll (for threaded systems) */ void pa_mainloop_wakeup(pa_mainloop *m); +/** Generic prototype of a poll() like function */ +typedef int (*pa_poll_func)(struct pollfd *ufds, nfds_t nfds, int timeout, void*userdata); + +/** Change the poll() implementation */ +void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata); + PA_C_DECL_END #endif -- cgit From 40f171f5de18b19b4ea1db40b2f1b2de9bbf73d9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Apr 2006 17:25:14 +0000 Subject: * add pa_mainloop_wakeup() calls for deferred events * place pa_mainloop_wakeup() calls a little bit more carfully, to minimize needless wakeups. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@734 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/mainloop.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/polyp/mainloop.c b/src/polyp/mainloop.c index 87ef623e..42a411d3 100644 --- a/src/polyp/mainloop.c +++ b/src/polyp/mainloop.c @@ -121,8 +121,6 @@ static pa_io_event* mainloop_io_new( m = a->userdata; assert(a == &m->api); - pa_mainloop_wakeup(m); - e = pa_xmalloc(sizeof(pa_io_event)); e->mainloop = m; e->dead = 0; @@ -156,24 +154,27 @@ static pa_io_event* mainloop_io_new( pa_idxset_put(m->io_events, e, NULL); m->rebuild_pollfds = 1; + + pa_mainloop_wakeup(m); + return e; } static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags_t events) { assert(e && e->mainloop); - pa_mainloop_wakeup(e->mainloop); - e->events = events; e->mainloop->rebuild_pollfds = 1; + + pa_mainloop_wakeup(e->mainloop); } static void mainloop_io_free(pa_io_event *e) { assert(e && e->mainloop); - pa_mainloop_wakeup(e->mainloop); - e->dead = e->mainloop->io_events_scan_dead = e->mainloop->rebuild_pollfds = 1; + + pa_mainloop_wakeup(e->mainloop); } static void mainloop_io_set_destroy(pa_io_event *e, void (*callback)(pa_mainloop_api*a, pa_io_event *e, void *userdata)) { @@ -202,6 +203,9 @@ static pa_defer_event* mainloop_defer_new(pa_mainloop_api*a, void (*callback) (p pa_idxset_put(m->defer_events, e, NULL); m->deferred_pending++; + + pa_mainloop_wakeup(e->mainloop); + return e; } @@ -211,8 +215,10 @@ static void mainloop_defer_enable(pa_defer_event *e, int b) { if (e->enabled && !b) { assert(e->mainloop->deferred_pending > 0); e->mainloop->deferred_pending--; - } else if (!e->enabled && b) + } else if (!e->enabled && b) { e->mainloop->deferred_pending++; + pa_mainloop_wakeup(e->mainloop); + } e->enabled = b; } @@ -242,8 +248,6 @@ static pa_time_event* mainloop_time_new(pa_mainloop_api*a, const struct timeval m = a->userdata; assert(a == &m->api); - pa_mainloop_wakeup(m); - e = pa_xmalloc(sizeof(pa_time_event)); e->mainloop = m; e->dead = 0; @@ -257,6 +261,9 @@ static pa_time_event* mainloop_time_new(pa_mainloop_api*a, const struct timeval e->destroy_callback = NULL; pa_idxset_put(m->time_events, e, NULL); + + if (e->enabled) + pa_mainloop_wakeup(m); return e; } @@ -264,11 +271,11 @@ static pa_time_event* mainloop_time_new(pa_mainloop_api*a, const struct timeval static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) { assert(e); - pa_mainloop_wakeup(e->mainloop); - if (tv) { e->enabled = 1; e->timeval = *tv; + + pa_mainloop_wakeup(e->mainloop); } else e->enabled = 0; } @@ -276,9 +283,9 @@ static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) { static void mainloop_time_free(pa_time_event *e) { assert(e); - pa_mainloop_wakeup(e->mainloop); - e->dead = e->mainloop->time_events_scan_dead = 1; + + /* no wakeup needed here. Think about it! */ } static void mainloop_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*a, pa_time_event *e, void *userdata)) { @@ -294,10 +301,10 @@ static void mainloop_quit(pa_mainloop_api*a, int retval) { m = a->userdata; assert(a == &m->api); - pa_mainloop_wakeup(m); - m->quit = 1; m->retval = retval; + + pa_mainloop_wakeup(m); } static const pa_mainloop_api vtable = { -- cgit From 4482e6867df82e889f48a9e7c22f2e0887b1028c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 17 Apr 2006 00:11:04 +0000 Subject: add new JACK sink git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@735 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 9 + src/Makefile.am | 15 +- src/modules/module-jack-sink.c | 382 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 405 insertions(+), 1 deletion(-) create mode 100644 src/modules/module-jack-sink.c diff --git a/configure.ac b/configure.ac index e649e063..3fd32f82 100644 --- a/configure.ac +++ b/configure.ac @@ -345,11 +345,20 @@ AC_SUBST(HOWL_LIBS) AC_SUBST(HAVE_HOWL) AM_CONDITIONAL([HAVE_HOWL], [test "x$HAVE_HOWL" = x1]) +### LIBOIL #### PKG_CHECK_MODULES(LIBOIL, [ liboil-0.3 >= 0.3.0 ]) AC_SUBST(LIBOIL_CFLAGS) AC_SUBST(LIBOIL_LIBS) +### JACK #### + +PKG_CHECK_MODULES(JACK, [ jack >= 0.100 ], HAVE_JACK=1, HAVE_JACK=0) +AC_SUBST(JACK_CFLAGS) +AC_SUBST(JACK_LIBS) +AC_SUBST(HAVE_JACK) +AM_CONDITIONAL([HAVE_JACK], [test "x$HAVE_JACK" = x1]) + #### Async DNS support (optional) #### PKG_CHECK_MODULES(LIBASYNCNS, [ libasyncns >= 0.1 ], HAVE_LIBASYNCNS=1, HAVE_LIBASYNCNS=0) diff --git a/src/Makefile.am b/src/Makefile.am index c30e24c3..c5864373 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -792,6 +792,11 @@ modlib_LTLIBRARIES += \ module-mmkbd-evdev.la endif +if HAVE_JACK +modlib_LTLIBRARIES += \ + module-jack-sink.la +endif + if OS_IS_WIN32 modlib_LTLIBRARIES += \ module-waveout.la @@ -836,7 +841,8 @@ SYMDEF_FILES = \ modules/module-waveout-symdef.h \ modules/module-detect-symdef.h \ modules/rtp/module-rtp-send-symdef.h \ - modules/rtp/module-rtp-recv-symdef.h + modules/rtp/module-rtp-recv-symdef.h \ + modules/module-jack-sink-symdef.h EXTRA_DIST += $(SYMDEF_FILES) BUILT_SOURCES += $(SYMDEF_FILES) @@ -1062,6 +1068,13 @@ module_rtp_recv_la_LDFLAGS = -module -avoid-version module_rtp_recv_la_LIBADD = $(AM_LIBADD) libpolypcore.la module_rtp_recv_la_CFLAGS = $(AM_CFLAGS) +# JACK + +module_jack_sink_la_SOURCES = modules/module-jack-sink.c +module_jack_sink_la_LDFLAGS = -module -avoid-version +module_jack_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la $(JACK_LIBS) +module_jack_sink_la_CFLAGS = $(AM_LIBADD) libpolypcore.la $(JACK_CFLAGS) + ################################### # Some minor stuff # ################################### diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c new file mode 100644 index 00000000..3d372551 --- /dev/null +++ b/src/modules/module-jack-sink.c @@ -0,0 +1,382 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-jack-sink-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Jack Sink") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE( + "sink_name= " + "server_name= " + "channels= " + "connect=" + "port_prefix=" +) + +#define DEFAULT_SINK_NAME "jack_out" + +struct userdata { + pa_core *core; + pa_module *module; + + pa_sink *sink; + + unsigned channels; + + jack_port_t* port[PA_CHANNELS_MAX]; + jack_client_t *client; + + pthread_mutex_t mutex; + pthread_cond_t cond; + + void * buffer[PA_CHANNELS_MAX]; + jack_nframes_t frames_requested; + int quit_requested; + + int pipe_fds[2]; + pa_io_event *io_event; + + jack_nframes_t frames_in_buffer; + struct timeval timestamp; +}; + +static const char* const valid_modargs[] = { + "sink_name", + "server_name", + "channels", + "connect", + "port_prefix", + NULL +}; + +static void stop_sink(struct userdata *u) { + assert (u); + + jack_client_close(u->client); + u->client = NULL; + u->core->mainloop->io_free(u->io_event); + u->io_event = NULL; + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + u->sink = NULL; + pa_module_unload_request(u->module); +} + +static void io_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) { + struct userdata *u = userdata; + char x; + + assert(m); + assert(flags == PA_IO_EVENT_INPUT); + assert(u); + assert(u->pipe_fds[0] == fd); + + read(fd, &x, 1); + + if (u->quit_requested) { + stop_sink(u); + u->quit_requested = 0; + return; + } + + pthread_mutex_lock(&u->mutex); + + if (u->frames_requested > 0) { + unsigned fs; + jack_nframes_t frame_idx; + pa_memchunk chunk; + + fs = pa_frame_size(&u->sink->sample_spec); + + pa_sink_render_full(u->sink, u->frames_requested * fs, &chunk); + + for (frame_idx = 0; frame_idx < u->frames_requested; frame_idx ++) { + unsigned c; + + for (c = 0; c < u->channels; c++) { + float *s = ((float*) ((uint8_t*) chunk.memblock->data + chunk.index)) + (frame_idx * u->channels) + c; + float *d = ((float*) u->buffer[c]) + frame_idx; + + *d = *s; + } + } + + pa_memblock_unref(chunk.memblock); + + u->frames_requested = 0; + + pthread_cond_signal(&u->cond); + } + + pthread_mutex_unlock(&u->mutex); +} + +static void request_render(struct userdata *u) { + char c = 'x'; + assert(u); + + assert(u->pipe_fds[1] >= 0); + write(u->pipe_fds[1], &c, 1); +} + +static void jack_shutdown(void *arg) { + struct userdata *u = arg; + assert(u); + + u->quit_requested = 1; + request_render(u); +} + +static int jack_process(jack_nframes_t nframes, void *arg) { + struct userdata *u = arg; + assert(u); + + if (jack_transport_query(u->client, NULL) == JackTransportRolling) { + unsigned c; + + pthread_mutex_lock(&u->mutex); + + u->frames_requested = nframes; + + for (c = 0; c < u->channels; c++) { + u->buffer[c] = jack_port_get_buffer(u->port[c], nframes); + assert(u->buffer[c]); + } + + request_render(u); + + pthread_cond_wait(&u->cond, &u->mutex); + + u->frames_in_buffer = nframes; + pa_gettimeofday(&u->timestamp); + + pthread_mutex_unlock(&u->mutex); + } + + return 0; +} + +static pa_usec_t sink_get_latency_cb(pa_sink *s) { + struct userdata *u; + pa_usec_t t, delta; + assert(s); + u = s->userdata; + + if (jack_transport_query(u->client, NULL) != JackTransportRolling) + return 0; + + delta = pa_timeval_age(&u->timestamp); + t = pa_bytes_to_usec(jack_port_get_total_latency(u->client, u->port[0]) * pa_frame_size(&s->sample_spec), &s->sample_spec); + + if (t > delta) + return t - delta; + else + return 0; +} + +static void jack_error_func(const char*t) { + pa_log_warn(__FILE__": JACK error >%s<", t); +} + +int pa__init(pa_core *c, pa_module*m) { + struct userdata *u = NULL; + pa_sample_spec ss; + pa_modargs *ma = NULL; + jack_status_t status; + const char *server_name; + uint32_t channels; + int connect = 1; + const char *pfx; + unsigned i; + + assert(c); + assert(m); + + jack_set_error_function(jack_error_func); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments."); + goto fail; + } + + channels = c->default_sample_spec.channels; + if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0 || channels <= 0 || channels >= PA_CHANNELS_MAX) { + pa_log(__FILE__": failed to parse channels= argument."); + goto fail; + } + + if (pa_modargs_get_value_boolean(ma, "connect", &connect) < 0) { + pa_log(__FILE__": failed to parse connect= argument."); + goto fail; + } + + server_name = pa_modargs_get_value(ma, "server_name", NULL); + + u = pa_xnew0(struct userdata, 1); + m->userdata = u; + u->core = c; + u->module = m; + u->pipe_fds[0] = u->pipe_fds[1] = -1; + + pthread_mutex_init(&u->mutex, NULL); + pthread_cond_init(&u->cond, NULL); + + if (pipe(u->pipe_fds) < 0) { + pa_log(__FILE__": pipe() failed: %s", strerror(errno)); + goto fail; + } + + pa_make_nonblock_fd(u->pipe_fds[1]); + + if (!(u->client = jack_client_open("polypaudio", server_name ? JackServerName : JackNullOption, &status, server_name))) { + pa_log(__FILE__": jack_client_open() failed."); + goto fail; + } + + pa_log_info(__FILE__": Successfully connected as '%s'", jack_get_client_name(u->client)); + + ss.channels = u->channels = channels; + ss.rate = jack_get_sample_rate(u->client); + ss.format = PA_SAMPLE_FLOAT32NE; + + assert(pa_sample_spec_valid(&ss)); + + pfx = pa_modargs_get_value(ma, "port_prefix", "channel"); + + for (i = 0; i < ss.channels; i++) { + char tmp[64]; + + snprintf(tmp, sizeof(tmp), "%s_%i", pfx, i+1); + + if (!(u->port[i] = jack_port_register(u->client, tmp, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput/*|JackPortIsTerminal*/, 0))) { + pa_log(__FILE__": jack_port_register() failed."); + goto fail; + } + } + + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { + pa_log(__FILE__": failed to create sink."); + goto fail; + } + + u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Jack sink (%s)", jack_get_client_name(u->client)); + u->sink->get_latency = sink_get_latency_cb; + + jack_set_process_callback(u->client, jack_process, u); + jack_on_shutdown(u->client, jack_shutdown, u); + + if (jack_activate(u->client)) { + pa_log(__FILE__": jack_activate() failed"); + goto fail; + } + + if (connect) { + const char **p, **ports = jack_get_ports(u->client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); + + for (i = 0, p = ports; i < ss.channels; i++, p++) { + + if (!p) { + pa_log(__FILE__": not enough physical output ports, leaving unconnected."); + break; + } + + pa_log_info(__FILE__": connecting %s to %s", jack_port_name(u->port[i]), *p); + + if (jack_connect(u->client, jack_port_name(u->port[i]), *p)) { + pa_log(__FILE__": failed to connect %s to %s, leaving unconnected.", jack_port_name(u->port[i]), *p); + break; + } + } + + free(ports); + } + + u->io_event = c->mainloop->io_new(c->mainloop, u->pipe_fds[0], PA_IO_EVENT_INPUT, io_event_cb, u); + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + pa__done(c, m); + + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->client) + jack_client_close(u->client); + + if (u->io_event) + c->mainloop->io_free(u->io_event); + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + } + + if (u->pipe_fds[0] >= 0) + close(u->pipe_fds[0]); + if (u->pipe_fds[1] >= 0) + close(u->pipe_fds[1]); + + pthread_mutex_destroy(&u->mutex); + pthread_cond_destroy(&u->cond); + pa_xfree(u); +} -- cgit From 8b99a067a842c439c9b24a2cb62c68447dd8f21f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 18 Apr 2006 12:46:03 +0000 Subject: C99 requires explicit marking of integer literals' size. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@736 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/rtp/module-rtp-recv.c | 2 +- src/modules/rtp/sdp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index 525a8819..a714e162 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -172,7 +172,7 @@ static void rtp_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event /* Check wheter there was a timestamp overflow */ k = (int64_t) s->rtp_context.timestamp - (int64_t) s->offset; - j = (int64_t) 0x100000000 - (int64_t) s->offset + (int64_t) s->rtp_context.timestamp; + j = (int64_t) 0x100000000LL - (int64_t) s->offset + (int64_t) s->rtp_context.timestamp; if ((k < 0 ? -k : k) < (j < 0 ? -j : j)) delta = k; diff --git a/src/modules/rtp/sdp.c b/src/modules/rtp/sdp.c index 9dca15ba..84bcd83b 100644 --- a/src/modules/rtp/sdp.c +++ b/src/modules/rtp/sdp.c @@ -55,7 +55,7 @@ char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, u if (!(u = getenv("USERNAME"))) u = "-"; - ntp = time(NULL) + 2208988800; + ntp = time(NULL) + 2208988800U; a = inet_ntop(af, src, buf_src, sizeof(buf_src)); assert(a); -- cgit From cf85794e2349631f6d997592bceca2174c044f0c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Apr 2006 13:20:50 +0000 Subject: * allow the user to set the jack client name * take the number of channels for the sink from the number of physical ports in the jack server * name the polypaudio ports in the jack server after their channel position in polypaudio git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@737 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-jack-sink.c | 76 ++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index 3d372551..4f7a66eb 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -52,10 +52,10 @@ PA_MODULE_DESCRIPTION("Jack Sink") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE( "sink_name= " - "server_name= " + "server_name= " + "client_name= " "channels= " "connect=" - "port_prefix=" ) #define DEFAULT_SINK_NAME "jack_out" @@ -82,15 +82,15 @@ struct userdata { pa_io_event *io_event; jack_nframes_t frames_in_buffer; - struct timeval timestamp; + jack_nframes_t timestamp; }; static const char* const valid_modargs[] = { "sink_name", "server_name", + "client_name", "channels", "connect", - "port_prefix", NULL }; @@ -193,7 +193,7 @@ static int jack_process(jack_nframes_t nframes, void *arg) { pthread_cond_wait(&u->cond, &u->mutex); u->frames_in_buffer = nframes; - pa_gettimeofday(&u->timestamp); + u->timestamp = jack_get_current_transport_frame(u->client); pthread_mutex_unlock(&u->mutex); } @@ -203,20 +203,26 @@ static int jack_process(jack_nframes_t nframes, void *arg) { static pa_usec_t sink_get_latency_cb(pa_sink *s) { struct userdata *u; - pa_usec_t t, delta; + jack_nframes_t n, l, d; + assert(s); u = s->userdata; if (jack_transport_query(u->client, NULL) != JackTransportRolling) return 0; - delta = pa_timeval_age(&u->timestamp); - t = pa_bytes_to_usec(jack_port_get_total_latency(u->client, u->port[0]) * pa_frame_size(&s->sample_spec), &s->sample_spec); + n = jack_get_current_transport_frame(u->client); + + if (n < u->timestamp) + return 0; + + d = n - u->timestamp; + l = jack_port_get_total_latency(u->client, u->port[0]) + u->frames_in_buffer; - if (t > delta) - return t - delta; - else + if (d >= l) return 0; + + return pa_bytes_to_usec((l - d) * pa_frame_size(&s->sample_spec), &s->sample_spec); } static void jack_error_func(const char*t) { @@ -226,13 +232,14 @@ static void jack_error_func(const char*t) { int pa__init(pa_core *c, pa_module*m) { struct userdata *u = NULL; pa_sample_spec ss; + pa_channel_map cm; pa_modargs *ma = NULL; jack_status_t status; - const char *server_name; - uint32_t channels; + const char *server_name, *client_name; + uint32_t channels = 0; int connect = 1; - const char *pfx; unsigned i; + const char **ports = NULL, **p; assert(c); assert(m); @@ -244,18 +251,13 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - channels = c->default_sample_spec.channels; - if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0 || channels <= 0 || channels >= PA_CHANNELS_MAX) { - pa_log(__FILE__": failed to parse channels= argument."); - goto fail; - } - if (pa_modargs_get_value_boolean(ma, "connect", &connect) < 0) { pa_log(__FILE__": failed to parse connect= argument."); goto fail; } server_name = pa_modargs_get_value(ma, "server_name", NULL); + client_name = pa_modargs_get_value(ma, "client_name", "polypaudio"); u = pa_xnew0(struct userdata, 1); m->userdata = u; @@ -273,11 +275,25 @@ int pa__init(pa_core *c, pa_module*m) { pa_make_nonblock_fd(u->pipe_fds[1]); - if (!(u->client = jack_client_open("polypaudio", server_name ? JackServerName : JackNullOption, &status, server_name))) { + if (!(u->client = jack_client_open(client_name, server_name ? JackServerName : JackNullOption, &status, server_name))) { pa_log(__FILE__": jack_client_open() failed."); goto fail; } + ports = jack_get_ports(u->client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); + + channels = 0; + for (p = ports; *p; p++) + channels++; + + if (!channels) + channels = c->default_sample_spec.channels; + + if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0 || channels <= 0 || channels >= PA_CHANNELS_MAX) { + pa_log(__FILE__": failed to parse channels= argument."); + goto fail; + } + pa_log_info(__FILE__": Successfully connected as '%s'", jack_get_client_name(u->client)); ss.channels = u->channels = channels; @@ -286,20 +302,16 @@ int pa__init(pa_core *c, pa_module*m) { assert(pa_sample_spec_valid(&ss)); - pfx = pa_modargs_get_value(ma, "port_prefix", "channel"); + pa_channel_map_init_auto(&cm, channels); for (i = 0; i < ss.channels; i++) { - char tmp[64]; - - snprintf(tmp, sizeof(tmp), "%s_%i", pfx, i+1); - - if (!(u->port[i] = jack_port_register(u->client, tmp, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput/*|JackPortIsTerminal*/, 0))) { + if (!(u->port[i] = jack_port_register(u->client, pa_channel_position_to_string(cm.map[i]), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput|JackPortIsTerminal, 0))) { pa_log(__FILE__": jack_port_register() failed."); goto fail; } } - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &cm))) { pa_log(__FILE__": failed to create sink."); goto fail; } @@ -318,11 +330,9 @@ int pa__init(pa_core *c, pa_module*m) { } if (connect) { - const char **p, **ports = jack_get_ports(u->client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); - for (i = 0, p = ports; i < ss.channels; i++, p++) { - if (!p) { + if (!*p) { pa_log(__FILE__": not enough physical output ports, leaving unconnected."); break; } @@ -335,11 +345,11 @@ int pa__init(pa_core *c, pa_module*m) { } } - free(ports); } u->io_event = c->mainloop->io_new(c->mainloop, u->pipe_fds[0], PA_IO_EVENT_INPUT, io_event_cb, u); + free(ports); pa_modargs_free(ma); return 0; @@ -347,6 +357,8 @@ int pa__init(pa_core *c, pa_module*m) { fail: if (ma) pa_modargs_free(ma); + + free(ports); pa__done(c, m); -- cgit From abea726d16eecbc0ecfb60c5e23958ed5275b779 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Apr 2006 13:22:41 +0000 Subject: add a jack source module git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@738 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-jack-source.c | 393 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 393 insertions(+) create mode 100644 src/modules/module-jack-source.c diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c new file mode 100644 index 00000000..eef416f6 --- /dev/null +++ b/src/modules/module-jack-source.c @@ -0,0 +1,393 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-jack-source-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Jack Source") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE( + "source_name= " + "server_name= " + "client_name= " + "channels= " + "connect=" +) + +#define DEFAULT_SOURCE_NAME "jack_in" + +struct userdata { + pa_core *core; + pa_module *module; + + pa_source *source; + + unsigned channels; + + jack_port_t* port[PA_CHANNELS_MAX]; + jack_client_t *client; + + pthread_mutex_t mutex; + pthread_cond_t cond; + + void * buffer[PA_CHANNELS_MAX]; + jack_nframes_t frames_posted; + int quit_requested; + + int pipe_fds[2]; + pa_io_event *io_event; + + jack_nframes_t frames_in_buffer; + jack_nframes_t timestamp; +}; + +static const char* const valid_modargs[] = { + "source_name", + "server_name", + "client_name", + "channels", + "connect", + NULL +}; + +static void stop_source(struct userdata *u) { + assert (u); + + jack_client_close(u->client); + u->client = NULL; + u->core->mainloop->io_free(u->io_event); + u->io_event = NULL; + pa_source_disconnect(u->source); + pa_source_unref(u->source); + u->source = NULL; + pa_module_unload_request(u->module); +} + +static void io_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) { + struct userdata *u = userdata; + char x; + + assert(m); + assert(flags == PA_IO_EVENT_INPUT); + assert(u); + assert(u->pipe_fds[0] == fd); + + read(fd, &x, 1); + + if (u->quit_requested) { + stop_source(u); + u->quit_requested = 0; + return; + } + + pthread_mutex_lock(&u->mutex); + + if (u->frames_posted > 0) { + unsigned fs; + jack_nframes_t frame_idx; + pa_memchunk chunk; + + fs = pa_frame_size(&u->source->sample_spec); + + chunk.memblock = pa_memblock_new(chunk.length = u->frames_posted * fs, u->core->memblock_stat); + chunk.index = 0; + + for (frame_idx = 0; frame_idx < u->frames_posted; frame_idx ++) { + unsigned c; + + for (c = 0; c < u->channels; c++) { + float *s = ((float*) u->buffer[c]) + frame_idx; + float *d = ((float*) ((uint8_t*) chunk.memblock->data + chunk.index)) + (frame_idx * u->channels) + c; + + *d = *s; + } + } + + pa_source_post(u->source, &chunk); + pa_memblock_unref(chunk.memblock); + + u->frames_posted = 0; + + pthread_cond_signal(&u->cond); + } + + pthread_mutex_unlock(&u->mutex); +} + +static void request_post(struct userdata *u) { + char c = 'x'; + assert(u); + + assert(u->pipe_fds[1] >= 0); + write(u->pipe_fds[1], &c, 1); +} + +static void jack_shutdown(void *arg) { + struct userdata *u = arg; + assert(u); + + u->quit_requested = 1; + request_post(u); +} + +static int jack_process(jack_nframes_t nframes, void *arg) { + struct userdata *u = arg; + assert(u); + + if (jack_transport_query(u->client, NULL) == JackTransportRolling) { + unsigned c; + + pthread_mutex_lock(&u->mutex); + + u->frames_posted = nframes; + + for (c = 0; c < u->channels; c++) { + u->buffer[c] = jack_port_get_buffer(u->port[c], nframes); + assert(u->buffer[c]); + } + + request_post(u); + + pthread_cond_wait(&u->cond, &u->mutex); + + u->frames_in_buffer = nframes; + u->timestamp = jack_get_current_transport_frame(u->client); + + pthread_mutex_unlock(&u->mutex); + } + + return 0; +} + +static pa_usec_t source_get_latency_cb(pa_source *s) { + struct userdata *u; + jack_nframes_t n, l, d; + + assert(s); + u = s->userdata; + + if (jack_transport_query(u->client, NULL) != JackTransportRolling) + return 0; + + n = jack_get_current_transport_frame(u->client); + + if (n < u->timestamp) + return 0; + + d = n - u->timestamp; + l = jack_port_get_total_latency(u->client, u->port[0]); + + return pa_bytes_to_usec((l + d) * pa_frame_size(&s->sample_spec), &s->sample_spec); +} + +static void jack_error_func(const char*t) { + pa_log_warn(__FILE__": JACK error >%s<", t); +} + +int pa__init(pa_core *c, pa_module*m) { + struct userdata *u = NULL; + pa_sample_spec ss; + pa_channel_map cm; + pa_modargs *ma = NULL; + jack_status_t status; + const char *server_name, *client_name; + uint32_t channels = 0; + int connect = 1; + unsigned i; + const char **ports = NULL, **p; + + assert(c); + assert(m); + + jack_set_error_function(jack_error_func); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments."); + goto fail; + } + + if (pa_modargs_get_value_boolean(ma, "connect", &connect) < 0) { + pa_log(__FILE__": failed to parse connect= argument."); + goto fail; + } + + server_name = pa_modargs_get_value(ma, "server_name", NULL); + client_name = pa_modargs_get_value(ma, "client_name", "polypaudio"); + + u = pa_xnew0(struct userdata, 1); + m->userdata = u; + u->core = c; + u->module = m; + u->pipe_fds[0] = u->pipe_fds[1] = -1; + + pthread_mutex_init(&u->mutex, NULL); + pthread_cond_init(&u->cond, NULL); + + if (pipe(u->pipe_fds) < 0) { + pa_log(__FILE__": pipe() failed: %s", strerror(errno)); + goto fail; + } + + pa_make_nonblock_fd(u->pipe_fds[1]); + + if (!(u->client = jack_client_open(client_name, server_name ? JackServerName : JackNullOption, &status, server_name))) { + pa_log(__FILE__": jack_client_open() failed."); + goto fail; + } + + ports = jack_get_ports(u->client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput); + + channels = 0; + for (p = ports; *p; p++) + channels++; + + if (!channels) + channels = c->default_sample_spec.channels; + + if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0 || channels <= 0 || channels >= PA_CHANNELS_MAX) { + pa_log(__FILE__": failed to parse channels= argument."); + goto fail; + } + + pa_log_info(__FILE__": Successfully connected as '%s'", jack_get_client_name(u->client)); + + ss.channels = u->channels = channels; + ss.rate = jack_get_sample_rate(u->client); + ss.format = PA_SAMPLE_FLOAT32NE; + + assert(pa_sample_spec_valid(&ss)); + + pa_channel_map_init_auto(&cm, channels); + + for (i = 0; i < ss.channels; i++) { + if (!(u->port[i] = jack_port_register(u->client, pa_channel_position_to_string(cm.map[i]), JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput|JackPortIsTerminal, 0))) { + pa_log(__FILE__": jack_port_register() failed."); + goto fail; + } + } + + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &cm))) { + pa_log(__FILE__": failed to create source."); + goto fail; + } + + u->source->userdata = u; + pa_source_set_owner(u->source, m); + u->source->description = pa_sprintf_malloc("Jack source (%s)", jack_get_client_name(u->client)); + u->source->get_latency = source_get_latency_cb; + + jack_set_process_callback(u->client, jack_process, u); + jack_on_shutdown(u->client, jack_shutdown, u); + + if (jack_activate(u->client)) { + pa_log(__FILE__": jack_activate() failed"); + goto fail; + } + + if (connect) { + for (i = 0, p = ports; i < ss.channels; i++, p++) { + + if (!*p) { + pa_log(__FILE__": not enough physical output ports, leaving unconnected."); + break; + } + + pa_log_info(__FILE__": connecting %s to %s", jack_port_name(u->port[i]), *p); + + if (jack_connect(u->client, jack_port_name(u->port[i]), *p)) { + pa_log(__FILE__": failed to connect %s to %s, leaving unconnected.", jack_port_name(u->port[i]), *p); + break; + } + } + + } + + u->io_event = c->mainloop->io_new(c->mainloop, u->pipe_fds[0], PA_IO_EVENT_INPUT, io_event_cb, u); + + free(ports); + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + free(ports); + + pa__done(c, m); + + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->client) + jack_client_close(u->client); + + if (u->io_event) + c->mainloop->io_free(u->io_event); + + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + } + + if (u->pipe_fds[0] >= 0) + close(u->pipe_fds[0]); + if (u->pipe_fds[1] >= 0) + close(u->pipe_fds[1]); + + pthread_mutex_destroy(&u->mutex); + pthread_cond_destroy(&u->cond); + pa_xfree(u); +} -- cgit From c3087d02ba272059f86f9b1794f792daf2cd8e89 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 18 Apr 2006 13:36:30 +0000 Subject: Avoid including non-portable header sys/poll.h. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@739 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/mainloop.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/polyp/mainloop.h b/src/polyp/mainloop.h index f60c355a..4681912b 100644 --- a/src/polyp/mainloop.h +++ b/src/polyp/mainloop.h @@ -27,6 +27,8 @@ PA_C_DECL_BEGIN +struct pollfd; + /** \page mainloop Main Loop * * \section overv_sec Overview @@ -70,8 +72,6 @@ PA_C_DECL_BEGIN * defined in \ref mainloop-api.h. This implementation is thread safe * as long as you access the main loop object from a single thread only.*/ -#include - /** An opaque main loop object */ typedef struct pa_mainloop pa_mainloop; @@ -117,7 +117,7 @@ void pa_mainloop_quit(pa_mainloop *m, int r); void pa_mainloop_wakeup(pa_mainloop *m); /** Generic prototype of a poll() like function */ -typedef int (*pa_poll_func)(struct pollfd *ufds, nfds_t nfds, int timeout, void*userdata); +typedef int (*pa_poll_func)(struct pollfd *ufds, unsigned long nfds, int timeout, void*userdata); /** Change the poll() implementation */ void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata); -- cgit From 2d6ab01fbb9c670b5b1831aea0681fd17fcdcf88 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 18 Apr 2006 13:36:59 +0000 Subject: We need to emulate sendmsg/recvmsg to support rtp on Windows. Will do this some time in the future. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@740 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index c5864373..f6fc509b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -589,8 +589,13 @@ modlib_LTLIBRARIES = \ libprotocol-simple.la \ libprotocol-esound.la \ libprotocol-native.la \ - libprotocol-http.la \ + libprotocol-http.la + +# We need to emulate sendmsg/recvmsg to support this on Win32 +if !OS_IS_WIN32 +modlib_LTLIBRARIES += \ librtp.la +endif if HAVE_X11 polypcoreinclude_HEADERS += \ @@ -721,9 +726,14 @@ modlib_LTLIBRARIES += \ module-null-sink.la \ module-esound-sink.la \ module-http-protocol-tcp.la \ - module-detect.la \ + module-detect.la + +# See comment at librtp.la above +if !OS_IS_WIN32 +modlib_LTLIBRARIES += \ module-rtp-send.la \ module-rtp-recv.la +endif if HAVE_AF_UNIX modlib_LTLIBRARIES += \ -- cgit From 18055e473c5763e9e391f0d956ff57f84002ba13 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 18 Apr 2006 13:37:34 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@741 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/todo b/doc/todo index 8688f05d..e7ba47c8 100644 --- a/doc/todo +++ b/doc/todo @@ -11,6 +11,7 @@ Post 0.8: - multiline configuration statements - use scatter/gather io for sockets - add a synchronous API (base it on xmms-polyp) +- rtp module ported to Win32 (sendmsg/recvmsg emulation) Long term: - pass meta info for hearing impaired -- cgit From 074b7c1df119e358361efb9c2a78b256b3a440ff Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 18 Apr 2006 14:09:56 +0000 Subject: More fixes caused by Sun's complete inability to follow any standard whatsoever. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@742 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 13 +++++++++++++ src/modules/rtp/rtp.c | 8 ++++++-- src/modules/rtp/sap.c | 4 ++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 3fd32f82..4f9b8823 100644 --- a/configure.ac +++ b/configure.ac @@ -36,6 +36,16 @@ if type -p stow > /dev/null && test -d /usr/local/stow ; then ac_default_prefix="/usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION}" fi +#### Platform hacks #### + +case $host in + *-*-solaris* ) + AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, Needed to get declarations for msg_control and msg_controllen on Solaris) + AC_DEFINE(_XOPEN_SOURCE, 2, Needed to get declarations for msg_control and msg_controllen on Solaris) + AC_DEFINE(__EXTENSIONS__, 1, Needed to get declarations for msg_control and msg_controllen on Solaris) + ;; +esac + #### Checks for programs. #### # CC @@ -158,6 +168,9 @@ AC_CHECK_HEADERS([linux/input.h], [HAVE_EVDEV=1], [HAVE_EVDEV=0]) AM_CONDITIONAL([HAVE_EVDEV], [test "x$HAVE_EVDEV" = "x1"]) +# Solaris +AC_CHECK_HEADERS([sys/filio.h]) + # Windows AC_CHECK_HEADERS([windows.h winsock2.h ws2tcpip.h]) diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c index ccd3b6c3..23e84eb3 100644 --- a/src/modules/rtp/rtp.c +++ b/src/modules/rtp/rtp.c @@ -32,6 +32,10 @@ #include #include +#ifdef HAVE_SYS_FILIO_H +#include +#endif + #include #include "rtp.h" @@ -74,7 +78,7 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { size_t k = n + chunk.length > size ? size - n : chunk.length; if (chunk.memblock) { - iov[iov_idx].iov_base = (uint8_t*) chunk.memblock->data + chunk.index; + iov[iov_idx].iov_base = (void*)((uint8_t*) chunk.memblock->data + chunk.index); iov[iov_idx].iov_len = k; mb[iov_idx] = chunk.memblock; iov_idx ++; @@ -96,7 +100,7 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { header[1] = htonl(c->timestamp); header[2] = htonl(c->ssrc); - iov[0].iov_base = header; + iov[0].iov_base = (void*)header; iov[0].iov_len = sizeof(header); m.msg_name = NULL; diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c index 0c12322e..d2bca04d 100644 --- a/src/modules/rtp/sap.c +++ b/src/modules/rtp/sap.c @@ -34,6 +34,10 @@ #include #include +#ifdef HAVE_SYS_FILIO_H +#include +#endif + #include #include #include -- cgit From e4b2a47bb1de0f457559510837c46707ef9f6d8b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 18 Apr 2006 14:11:02 +0000 Subject: Clarify that JACK libs are optional. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@743 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4f9b8823..c37abfcd 100644 --- a/configure.ac +++ b/configure.ac @@ -364,7 +364,7 @@ PKG_CHECK_MODULES(LIBOIL, [ liboil-0.3 >= 0.3.0 ]) AC_SUBST(LIBOIL_CFLAGS) AC_SUBST(LIBOIL_LIBS) -### JACK #### +### JACK (optional) #### PKG_CHECK_MODULES(JACK, [ jack >= 0.100 ], HAVE_JACK=1, HAVE_JACK=0) AC_SUBST(JACK_CFLAGS) -- cgit From c22a0c12e49181d6ea042993e6b4b47db69574b1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 18 Apr 2006 15:16:24 +0000 Subject: Make the probe for RNG sources at runtime since the configure script isn't compatible with cross-compiling. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@744 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 20 ------------- src/daemon/main.c | 26 ++--------------- src/polypcore/random.c | 77 ++++++++++++++++++++++++++++++++++++++------------ src/polypcore/random.h | 1 + 4 files changed, 62 insertions(+), 62 deletions(-) diff --git a/configure.ac b/configure.ac index c37abfcd..d6239f97 100644 --- a/configure.ac +++ b/configure.ac @@ -396,26 +396,6 @@ AC_SUBST(LIRC_CFLAGS) AC_SUBST(LIRC_LIBS) AM_CONDITIONAL([HAVE_LIRC], [test "x$HAVE_LIRC" = x1]) -### /dev/random ### - -AC_MSG_CHECKING([whether a random device is available]) - -rnd="no" - -if test -e /dev/urandom ; then - rnd=/dev/urandom -else - if test -e /dev/random ; then - rnd=/dev/random - fi -fi - -if test "x$rnd" != "no" ; then - AC_DEFINE_UNQUOTED([RANDOM_DEVICE], ["$rnd"], [Random device]) -fi - -AC_MSG_RESULT([$rnd]) - ################################### # Output # ################################### diff --git a/src/daemon/main.c b/src/daemon/main.c index d783531a..4ae9fbf1 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -63,6 +63,7 @@ #include #include #include +#include #include "cmdline.h" #include "cpulimit.h" @@ -135,29 +136,6 @@ static void close_pipe(int p[2]) { p[0] = p[1] = -1; } -static void set_random_seed(void) { - unsigned int seed = 0; - -#ifdef RANDOM_DEVICE - int fd; - - if ((fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) { - ssize_t r; - - if ((r = pa_loop_read(fd, &seed, sizeof(seed))) < 0 || (size_t) r != sizeof(seed)) { - pa_log_error(__FILE__": failed to read entropy from '"RANDOM_DEVICE"'"); - seed += (unsigned int) time(NULL); - } - - close(fd); - } -#else - seed = (unsigned int) time(NULL); -#endif - - srand(seed); -} - int main(int argc, char *argv[]) { pa_core *c; pa_strbuf *buf = NULL; @@ -203,7 +181,7 @@ int main(int argc, char *argv[]) { } #endif - set_random_seed(); + pa_random_seed(); pa_log_set_ident("polypaudio"); diff --git a/src/polypcore/random.c b/src/polypcore/random.c index ffd40474..ffe24994 100644 --- a/src/polypcore/random.c +++ b/src/polypcore/random.c @@ -36,31 +36,72 @@ #include "random.h" -void pa_random(void *ret_data, size_t length) { - int fd; - ssize_t r = 0; +static int has_whined = 0; + +static const char *devices[] = { "/dev/urandom", "/dev/random", NULL }; + +static int pa_random_proper(void *ret_data, size_t length) { assert(ret_data && length); -#ifdef RANDOM_DEVICE - if ((fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) { +#ifdef OS_IS_WIN32 - if ((r = pa_loop_read(fd, ret_data, length)) < 0 || (size_t) r != length) - pa_log_error(__FILE__": failed to read entropy from '%s'", RANDOM_DEVICE); + return -1; + +#else /* OS_IS_WIN32 */ + + int fd, ret; + ssize_t r = 0; + const char **device; - close(fd); + device = devices; + + while (*device) { + ret = 0; + + if ((fd = open(*device, O_RDONLY)) >= 0) { + + if ((r = pa_loop_read(fd, ret_data, length)) < 0 || (size_t) r != length) + ret = -1; + + close(fd); + } else + ret = -1; + + if (ret == 0) + break; } -#endif - if ((size_t) r != length) { - uint8_t *p; - size_t l; + return ret; +#endif /* OS_IS_WIN32 */ +} -#ifdef RANDOM_DEVICE - pa_log_warn(__FILE__": WARNING: Failed to open entropy device '"RANDOM_DEVICE"': %s" - ", falling back to unsecure pseudo RNG.\n", strerror(errno)); -#endif +void pa_random_seed() { + unsigned int seed; + + if (pa_random_proper(&seed, sizeof(unsigned int)) < 0) { + if (!has_whined) + pa_log_warn(__FILE__": failed to get proper entropy. Falling back to seeding with current time."); + has_whined = 1; - for (p = ret_data, l = length; l > 0; p++, l--) - *p = (uint8_t) rand(); + seed = (unsigned int) time(NULL); } + + srand(seed); +} + +void pa_random(void *ret_data, size_t length) { + uint8_t *p; + size_t l; + + assert(ret_data && length); + + if (pa_random_proper(ret_data, length) >= 0) + return; + + if (!has_whined) + pa_log_warn(__FILE__": failed to get proper entropy. Falling back to unsecure pseudo RNG."); + has_whined = 1; + + for (p = ret_data, l = length; l > 0; p++, l--) + *p = (uint8_t) rand(); } diff --git a/src/polypcore/random.h b/src/polypcore/random.h index bfb3df08..94a6d505 100644 --- a/src/polypcore/random.h +++ b/src/polypcore/random.h @@ -22,6 +22,7 @@ USA. ***/ +void pa_random_seed(); void pa_random(void *ret_data, size_t length); #endif -- cgit From f8dbc2f8f8155fcac20bf4aec703022c350a14bd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Apr 2006 15:40:36 +0000 Subject: * fix pa_random_seet() function prototype * drop pa_ prefix from pa_random_proper(), because it is a static function git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@745 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/random.c | 8 ++++---- src/polypcore/random.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/polypcore/random.c b/src/polypcore/random.c index ffe24994..fe75a614 100644 --- a/src/polypcore/random.c +++ b/src/polypcore/random.c @@ -40,7 +40,7 @@ static int has_whined = 0; static const char *devices[] = { "/dev/urandom", "/dev/random", NULL }; -static int pa_random_proper(void *ret_data, size_t length) { +static int random_proper(void *ret_data, size_t length) { assert(ret_data && length); #ifdef OS_IS_WIN32 @@ -75,10 +75,10 @@ static int pa_random_proper(void *ret_data, size_t length) { #endif /* OS_IS_WIN32 */ } -void pa_random_seed() { +void pa_random_seed(void) { unsigned int seed; - if (pa_random_proper(&seed, sizeof(unsigned int)) < 0) { + if (random_proper(&seed, sizeof(unsigned int)) < 0) { if (!has_whined) pa_log_warn(__FILE__": failed to get proper entropy. Falling back to seeding with current time."); has_whined = 1; @@ -95,7 +95,7 @@ void pa_random(void *ret_data, size_t length) { assert(ret_data && length); - if (pa_random_proper(ret_data, length) >= 0) + if (random_proper(ret_data, length) >= 0) return; if (!has_whined) diff --git a/src/polypcore/random.h b/src/polypcore/random.h index 94a6d505..1f152dc7 100644 --- a/src/polypcore/random.h +++ b/src/polypcore/random.h @@ -22,7 +22,7 @@ USA. ***/ -void pa_random_seed(); +void pa_random_seed(void); void pa_random(void *ret_data, size_t length); #endif -- cgit From 768a6f28e1345da1a0e8d51ae50455835ed8f677 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Apr 2006 16:33:17 +0000 Subject: fix code for pre-C99 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@746 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/random.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/polypcore/random.c b/src/polypcore/random.c index fe75a614..1221206f 100644 --- a/src/polypcore/random.c +++ b/src/polypcore/random.c @@ -41,9 +41,8 @@ static int has_whined = 0; static const char *devices[] = { "/dev/urandom", "/dev/random", NULL }; static int random_proper(void *ret_data, size_t length) { - assert(ret_data && length); - #ifdef OS_IS_WIN32 + assert(ret_data && length); return -1; @@ -53,6 +52,8 @@ static int random_proper(void *ret_data, size_t length) { ssize_t r = 0; const char **device; + assert(ret_data && length); + device = devices; while (*device) { -- cgit From a80912917b348f6371fed4154cb6f2bcfe3ea384 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Apr 2006 17:19:41 +0000 Subject: build jack source git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@747 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index f6fc509b..e02811b5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -804,7 +804,8 @@ endif if HAVE_JACK modlib_LTLIBRARIES += \ - module-jack-sink.la + module-jack-sink.la \ + module-jack-source.la endif if OS_IS_WIN32 @@ -852,7 +853,9 @@ SYMDEF_FILES = \ modules/module-detect-symdef.h \ modules/rtp/module-rtp-send-symdef.h \ modules/rtp/module-rtp-recv-symdef.h \ - modules/module-jack-sink-symdef.h + modules/module-jack-sink-symdef.h \ + modules/module-jack-source-symdef.h + EXTRA_DIST += $(SYMDEF_FILES) BUILT_SOURCES += $(SYMDEF_FILES) @@ -1085,6 +1088,11 @@ module_jack_sink_la_LDFLAGS = -module -avoid-version module_jack_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la $(JACK_LIBS) module_jack_sink_la_CFLAGS = $(AM_LIBADD) libpolypcore.la $(JACK_CFLAGS) +module_jack_source_la_SOURCES = modules/module-jack-source.c +module_jack_source_la_LDFLAGS = -module -avoid-version +module_jack_source_la_LIBADD = $(AM_LIBADD) libpolypcore.la $(JACK_LIBS) +module_jack_source_la_CFLAGS = $(AM_LIBADD) libpolypcore.la $(JACK_CFLAGS) + ################################### # Some minor stuff # ################################### -- cgit From a5100be08335822c9ab87310e12d0d7f1dea870b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Apr 2006 17:20:05 +0000 Subject: fix connecting of jack source in jack daemon git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@748 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-jack-source.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index eef416f6..5f0e560d 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -338,7 +338,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log_info(__FILE__": connecting %s to %s", jack_port_name(u->port[i]), *p); - if (jack_connect(u->client, jack_port_name(u->port[i]), *p)) { + if (jack_connect(u->client, *p, jack_port_name(u->port[i]))) { pa_log(__FILE__": failed to connect %s to %s, leaving unconnected.", jack_port_name(u->port[i]), *p); break; } -- cgit From c35052aa5a109013b8ed3326aaeede3bd5b2325e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Apr 2006 17:43:32 +0000 Subject: add JACK module documentation git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@749 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/modules.html.in | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/doc/modules.html.in b/doc/modules.html.in index 54cec804..3785912c 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -401,6 +401,32 @@ module to create an RTP source.

    sap_address=The multicast group to join for SAP announcements, defaults to 224.0.0.56. +

    JACK Connectivity

    + +

    Polypaudio can be hooked up to a JACK Audio Connection Kit server which is a specialized sound server used for professional audio production on Unix/Linux. Both a +Polypaudio sink and a source are available. For each channel a port is +created in the JACK server.

    + +

    module-jack-sink

    + +

    This module implements a Polypaudio sink that connects to JACK and registers as many output ports as requested.

    + + + + + + + +
    sink_name=The name for the Polypaudio sink. If ommited defaults to jack_out.
    server_name=The JACK server to connect to. If ommited defaults to the default server.
    client_name=The client name to tell the JACK server. If ommited defaults to polypaudio.
    channels=Number of channels to register. If ommited defaults to the number of physical playback ports of the JACK server.
    connect=Takes a boolean value. If enabled (the default) Polypaudio will try to connect its ports to the physicial playback ports of the JACK server
    + +

    module-jack-source

    + +

    This module implements a Polypaudio source that connects to JACK +and registers as many input ports as requested. Takes the same +arguments as module-jack-sink, except for sink_name +which is replaced by source_name (with a default of jack_in) for obvious reasons.

    +

    Miscellaneous

    module-sine

    -- cgit From e454bb1a47c303c119e77257b9c2f6e766416eb1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Apr 2006 17:52:37 +0000 Subject: Documentation updates git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@750 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 19 +++++++++++-------- doc/modules.html.in | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/doc/README.html.in b/doc/README.html.in index 0e9b8261..5dec5056 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -130,29 +130,32 @@ available. A simple main loop implementation is available as well.

    The following modules are currently available:

      -
    • module-oss: driver for Open Sound System audio sinks and sources.
    • -
    • module-oss-mmap: same as above, but uses mmap() access to the audio buffer. Not as compatible
    • -
    • module-alsa-sink, module-alsa-source: drivers for ALSA sinks and sources
    • +
    • module-oss: driver for Open Sound System (OSS) audio sinks and sources.
    • +
    • module-oss-mmap: same as above, but uses mmap() access to the audio buffer. Not as compatible bot more accurate in latency calculations
    • +
    • module-alsa-sink, module-alsa-source: drivers for Advanced Linux +Sound Architecture (ALSA) sinks and sources
    • module-solaris: drivers for Solaris audio sinks and sources
    • module-waveout: drivers for Microsoft Windows audio sinks and sources
    • -
    • module-pipe-sink, module-pipe-source: demonstration module providing UNIX fifos backed sinks/sources
    • -
    • module-combine: combine multiple sinks into one.
    • +
    • module-pipe-sink, module-pipe-source: demonstration module providing UNIX FIFOs backed sinks/sources
    • +
    • module-combine: combine multiple sinks into one, adjusting the sample rate if the their clocks deviate.
    • module-sine: a sine generate sink input.
    • module-x11-bell: play a sample from the sample cache on every X11 bell event.
    • module-x11-publish: store Polypaudio credentials in the X11 root window.
    • -
    • module-esound-protocol-tcp, module-esound-protocol-unix: ESOUND compatibility modules (for TCP/IP resp. UNIX domain sockets)
    • +
    • module-esound-protocol-tcp, module-esound-protocol-unix: ESOUND compatibility modules (for TCP/IP resp. UNIX domain sockets)
    • module-native-protocol-tcp, module-native-protocol-unix: Native polypaudio protocol (for TCP/IP resp. UNIX domain sockets)
    • module-simple-protocol-tcp, module-simple-protocol-unix: Simplistic protocol for playback/capture for usage with tools like netcat (for TCP/IP resp. UNIX domain sockets)
    • module-cli-protocol-tcp, module-cli-protocol-unix, module-cli: Expose polypaudio's internals whith a simple command line interface. (for TCP/IP resp. UNIX domain sockets resp. STDIN/STDOUT)
    • +
    • module-http-protocol-tcp: Spawns a small HTTP server which can be used to introspect the Polypaudio server with a web browser.
    • module-tunnel-sink, module-tunnel-source: make sinks/sources from other hosts available locally.
    • module-match: adjust volume automatically for newly created playback streams based on a regular expression matching table.
    • module-null-sink: a clocked sink similar to /dev/null.
    • -
    • module-esound-sink: a sink for forwarding audio data to an ESOUND server.
    • +
    • module-esound-sink: a sink for forwarding audio data to an ESOUND server.
    • module-detect: a module which automatically detects what sound hardware is available locally and which loads the required driver modules.
    • module-lirc: a module to control the volume of a sink with infrared remote controls supported by LIRC.
    • module-mmkbd-evdev: a module to control the volume of a sink with the special volume keys of a multimeda keyboard.
    • module-zeroconf-publish: a module to publish local sources/sinks using mDNS zeroconf.
    • -
    • module-rtp-send, module-rtp-recv: a module to implement RTP/SAP/SDP based audio streaming.
    • +
    • module-rtp-send, module-rtp-recv: modules to implement RTP/SAP/SDP based audio streaming.
    • +
    • module-jack-sink, module-jack-source: connect to a JACK Audio Connection Kit server. (A sound server for professional audio production)

    polypaudio is the successor of my previous, ill-fated diff --git a/doc/modules.html.in b/doc/modules.html.in index 3785912c..f7b6298f 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -158,7 +158,7 @@ buffer control is lost through this tunneling.

    module-esound-sink

    -

    Create a playback sink using an ESOUND server as backend. Whenever you can, try to omit this +

    Create a playback sink using an ESOUND server as backend. Whenever you can, try to omit this module since it has many disadvantages including bad latency and even worse latency measurement.

    -- cgit From 65fd9b315b8c5ace2774d255b268187bf52b246d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Apr 2006 18:18:28 +0000 Subject: fix make distcheck git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@751 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doxygen/Makefile.am | 8 +++++++- src/Makefile.am | 6 ++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/doxygen/Makefile.am b/doxygen/Makefile.am index 79354b21..a68db577 100644 --- a/doxygen/Makefile.am +++ b/doxygen/Makefile.am @@ -20,7 +20,13 @@ doxygen: doxygen.conf doxygen $< +distclean-local: + -rm -f doxygen.conf Makefile + +maintainerc-cleanlocal: + -rm -f Makefile.in + clean-local: - rm -rf html + -rm -rf html .PHONY: all doxygen diff --git a/src/Makefile.am b/src/Makefile.am index e02811b5..0705e152 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -327,7 +327,6 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = \ polyp/cdecl.h \ polyp/channelmap.c polyp/channelmap.h \ polyp/client-conf.c polyp/client-conf.h \ - polyp/llist.h \ polyp/mainloop-api.c polyp/mainloop-api.h \ polyp/polypaudio.h \ polyp/context.c polyp/context.h \ @@ -374,7 +373,8 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ polypcore/tagstruct.c polypcore/tagstruct.h \ polypcore/util.c polypcore/util.h \ polypcore/winsock.h \ - polypcore/xmalloc.c polypcore/xmalloc.h + polypcore/xmalloc.c polypcore/xmalloc.h \ + polypcore/llist.h if OS_IS_WIN32 libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ @@ -1101,6 +1101,8 @@ suid: polypaudio chown root $< chmod u+s $< +CLEANFILES=esdcompat.sh client.conf default.pa daemon.conf + esdcompat.sh: daemon/esdcompat.sh.in Makefile sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ -- cgit From 9ad753ed1f4114f2f1e1fa308958f3ff7815b70a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Apr 2006 18:44:44 +0000 Subject: fix "make distccheck" properly git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@752 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- doxygen/Makefile.am | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/Makefile.am b/Makefile.am index d8032baa..8d34ca89 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,7 +18,7 @@ # USA. EXTRA_DIST = bootstrap.sh LICENSE doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in libtool.m4 ltdl.m4 -SUBDIRS=libltdl src doc +SUBDIRS=libltdl src doc doxygen MAINTAINERCLEANFILES = noinst_DATA = diff --git a/doxygen/Makefile.am b/doxygen/Makefile.am index a68db577..8feec733 100644 --- a/doxygen/Makefile.am +++ b/doxygen/Makefile.am @@ -20,12 +20,6 @@ doxygen: doxygen.conf doxygen $< -distclean-local: - -rm -f doxygen.conf Makefile - -maintainerc-cleanlocal: - -rm -f Makefile.in - clean-local: -rm -rf html -- cgit From 60008cb1154696a875e69b7bcb739bc9f85ed378 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Apr 2006 19:12:53 +0000 Subject: fix CFLAGS for jack modules git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@753 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 0705e152..b646cff7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1086,12 +1086,12 @@ module_rtp_recv_la_CFLAGS = $(AM_CFLAGS) module_jack_sink_la_SOURCES = modules/module-jack-sink.c module_jack_sink_la_LDFLAGS = -module -avoid-version module_jack_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la $(JACK_LIBS) -module_jack_sink_la_CFLAGS = $(AM_LIBADD) libpolypcore.la $(JACK_CFLAGS) +module_jack_sink_la_CFLAGS = $(AM_LIBADD) $(JACK_CFLAGS) module_jack_source_la_SOURCES = modules/module-jack-source.c module_jack_source_la_LDFLAGS = -module -avoid-version module_jack_source_la_LIBADD = $(AM_LIBADD) libpolypcore.la $(JACK_LIBS) -module_jack_source_la_CFLAGS = $(AM_LIBADD) libpolypcore.la $(JACK_CFLAGS) +module_jack_source_la_CFLAGS = $(AM_LIBADD) $(JACK_CFLAGS) ################################### # Some minor stuff # -- cgit From 746adcfed5dc396bc4820724b2e951369fc63aeb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Apr 2006 19:31:50 +0000 Subject: fix a couple of issues I found when compiling polypaudio with gcc 2.95 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@754 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 4 ++-- src/modules/module-detect.c | 2 +- src/modules/module-jack-sink.c | 1 + src/modules/module-oss.c | 3 ++- src/modules/module-tunnel.c | 2 +- src/modules/rtp/module-rtp-recv.c | 2 +- src/polyp/browser.c | 2 +- src/polyp/context.c | 2 +- src/polyp/def.h | 2 +- src/polyp/stream.c | 2 +- src/polypcore/socket-client.c | 2 +- src/polypcore/source.c | 2 +- src/utils/pacmd.c | 2 +- 13 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 2f9be07a..dcc0e020 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -51,7 +51,7 @@ struct pa_alsa_fdlist { void *userdata; }; -static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) { +static void io_cb(pa_mainloop_api*a, pa_io_event* e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void *userdata) { struct pa_alsa_fdlist *fdl = (struct pa_alsa_fdlist*)userdata; int err, i; unsigned short revents; @@ -102,7 +102,7 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t a->defer_enable(fdl->defer, 1); } -static void defer_cb(pa_mainloop_api*a, pa_defer_event* e, void *userdata) { +static void defer_cb(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event* e, void *userdata) { struct pa_alsa_fdlist *fdl = (struct pa_alsa_fdlist*)userdata; int num_fds, i, err; struct pollfd *temp; diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index 6b2e2742..9cc13e81 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -259,7 +259,7 @@ fail: } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(PA_GCC_UNUSED pa_core *c, PA_GCC_UNUSED pa_module*m) { /* NOP */ } diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index 4f7a66eb..f340ab6d 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -112,6 +112,7 @@ static void io_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_ char x; assert(m); + assert(e); assert(flags == PA_IO_EVENT_INPUT); assert(u); assert(u->pipe_fds[0] == fd); diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index d9980d82..ccc3c7d9 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -461,8 +461,9 @@ int pa__init(pa_core *c, pa_module*m) { * Without this snippet, poll will never register the fd as ready. */ if (u->source) { - char buf[u->sample_size]; + char *buf = pa_xnew(char, u->sample_size); read(u->fd, buf, u->sample_size); + pa_xfree(buf); } /* Read mixer settings */ diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 70cc950c..b68bc485 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -603,7 +603,7 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const void } #ifndef TUNNEL_SINK -static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { +static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, PA_GCC_UNUSED int64_t offset, PA_GCC_UNUSED pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { struct userdata *u = userdata; assert(p && chunk && u); diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index a714e162..cd5f10e6 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -477,7 +477,7 @@ fail: return -1; } -static void free_func(void *p, void *userdata) { +static void free_func(void *p, PA_GCC_UNUSED void *userdata) { session_free(p, 0); } diff --git a/src/polyp/browser.c b/src/polyp/browser.c index de5c751a..cef680e4 100644 --- a/src/polyp/browser.c +++ b/src/polyp/browser.c @@ -43,7 +43,7 @@ struct pa_browser { pa_io_event *io_event; }; -static void io_callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags_t events, void *userdata) { +static void io_callback(pa_mainloop_api*a, PA_GCC_UNUSED pa_io_event*e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void *userdata) { pa_browser *b = userdata; assert(a && b && b->mainloop == a); diff --git a/src/polyp/context.c b/src/polyp/context.c index 047b739f..448e2e68 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -955,7 +955,7 @@ const char* pa_context_get_server(pa_context *c) { return c->server; } -uint32_t pa_context_get_protocol_version(pa_context *c) { +uint32_t pa_context_get_protocol_version(PA_GCC_UNUSED pa_context *c) { return PA_PROTOCOL_VERSION; } diff --git a/src/polyp/def.h b/src/polyp/def.h index 80e3092b..517dd422 100644 --- a/src/polyp/def.h +++ b/src/polyp/def.h @@ -288,7 +288,7 @@ typedef enum pa_seek_mode { PA_SEEK_RELATIVE = 0, /**< Seek relatively to the write index */ PA_SEEK_ABSOLUTE = 1, /**< Seek relatively to the start of the buffer queue */ PA_SEEK_RELATIVE_ON_READ = 2, /**< Seek relatively to the read index. */ - PA_SEEK_RELATIVE_END = 3, /**< Seek relatively to the current end of the buffer queue. */ + PA_SEEK_RELATIVE_END = 3 /**< Seek relatively to the current end of the buffer queue. */ } pa_seek_mode_t; /** Special sink flags. \since 0.8 */ diff --git a/src/polyp/stream.c b/src/polyp/stream.c index ce2470f6..e400415c 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -360,7 +360,7 @@ static void invalidate_indexes(pa_stream *s, int r, int w) { request_auto_timing_update(s, 1); } -static void auto_timing_update_callback(pa_mainloop_api *m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { +static void auto_timing_update_callback(PA_GCC_UNUSED pa_mainloop_api *m, PA_GCC_UNUSED pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { pa_stream *s = userdata; /* pa_log("time event"); */ diff --git a/src/polypcore/socket-client.c b/src/polypcore/socket-client.c index 1ee19a59..7c4f4d6b 100644 --- a/src/polypcore/socket-client.c +++ b/src/polypcore/socket-client.c @@ -371,7 +371,7 @@ static void asyncns_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED goto finish; fail: - errno == EHOSTUNREACH; + errno = EHOSTUNREACH; do_call(c); finish: diff --git a/src/polypcore/source.c b/src/polypcore/source.c index 9e9415b6..3a78825b 100644 --- a/src/polypcore/source.c +++ b/src/polypcore/source.c @@ -170,7 +170,7 @@ void pa_source_notify(pa_source*s) { s->notify(s); } -static int do_post(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void*userdata) { +static int do_post(void *p, PA_GCC_UNUSED uint32_t idx, PA_GCC_UNUSED int *del, void*userdata) { pa_source_output *o = p; const pa_memchunk *chunk = userdata; diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c index a71e0e93..e640ddaf 100644 --- a/src/utils/pacmd.c +++ b/src/utils/pacmd.c @@ -36,7 +36,7 @@ #include #include -int main(PA_GCC_UNUSED int main, PA_GCC_UNUSED char*argv[]) { +int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { pid_t pid ; int fd = -1; int ret = 1, i; -- cgit From 494f60207404dc3d155047fab3e3cc1d4870f4f5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Apr 2006 19:44:50 +0000 Subject: make proper use of the muting facility of sinks in module-mmkbd-evdev git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@755 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-mmkbd-evdev.c | 46 ++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c index 79194ad8..8ea56811 100644 --- a/src/modules/module-mmkbd-evdev.c +++ b/src/modules/module-mmkbd-evdev.c @@ -72,7 +72,6 @@ struct userdata { pa_io_event *io; char *sink_name; pa_module *module; - float mute_toggle_save; }; static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void*userdata) { @@ -110,37 +109,42 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) pa_log(__FILE__": failed to get sink '%s'", u->sink_name); else { - pa_volume_t v = pa_cvolume_avg(pa_sink_get_volume(s, PA_MIXER_HARDWARE)); - pa_cvolume cv; + int i; + pa_cvolume cv = *pa_sink_get_volume(s, PA_MIXER_HARDWARE); + #define DELTA (PA_VOLUME_NORM/20) switch (volchange) { case UP: - v += DELTA; + for (i = 0; i < cv.channels; i++) { + cv.values[i] += DELTA; + + if (cv.values[i] > PA_VOLUME_NORM) + cv.values[i] = PA_VOLUME_NORM; + } + + pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); break; case DOWN: - if (v > DELTA) - v -= DELTA; - else - v = PA_VOLUME_MUTED; + for (i = 0; i < cv.channels; i++) { + if (cv.values[i] >= DELTA) + cv.values[i] -= DELTA; + else + cv.values[i] = PA_VOLUME_MUTED; + } + pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); break; - case MUTE_TOGGLE: { - - if (v > 0) { - u->mute_toggle_save = v; - v = PA_VOLUME_MUTED; - } else - v = u->mute_toggle_save; - } - default: + case MUTE_TOGGLE: + + pa_sink_set_mute(s, PA_MIXER_HARDWARE, !pa_sink_get_mute(s, PA_MIXER_HARDWARE)); + break; + + case INVALID: ; } - - pa_cvolume_set(&cv, PA_CHANNELS_MAX, v); - pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); } } } @@ -176,7 +180,6 @@ int pa__init(pa_core *c, pa_module*m) { u->io = NULL; u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); u->fd = -1; - u->mute_toggle_save = 0; if ((u->fd = open(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), O_RDONLY)) < 0) { pa_log(__FILE__": failed to open evdev device: %s", strerror(errno)); @@ -198,6 +201,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log_info(__FILE__": evdev vendor 0x%04hx product 0x%04hx version 0x%04hx bustype %u", input_id.vendor, input_id.product, input_id.version, input_id.bustype); + memset(name, 0, sizeof(name)); if(ioctl(u->fd, EVIOCGNAME(sizeof(name)), name) < 0) { pa_log(__FILE__": EVIOCGNAME failed: %s", strerror(errno)); goto fail; -- cgit From 4bb58226189763b87abc5b5e0f297dd04f751d89 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 19 Apr 2006 07:31:11 +0000 Subject: Reverse order of IPv6/IPv4 binding to handle systems without IPV6_V6ONLY. System that always do IPV6_V6ONLY will now still bind to both sockets, just in another order. System that never do IPV6_V6ONLY will now fail to bind IPv4 instead of IPv6. But since they force IPv6 sockets to accept IPv4 connections, everything is peachy anyway. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@756 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-protocol-stub.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index 2f022b99..0ffd81df 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -211,14 +211,14 @@ int pa__init(pa_core *c, pa_module*m) { listen_on = pa_modargs_get_value(ma, "listen", NULL); if (listen_on) { - s_ipv4 = pa_socket_server_new_ipv4_string(c->mainloop, listen_on, port, TCPWRAP_SERVICE); s_ipv6 = pa_socket_server_new_ipv6_string(c->mainloop, listen_on, port, TCPWRAP_SERVICE); + s_ipv4 = pa_socket_server_new_ipv4_string(c->mainloop, listen_on, port, TCPWRAP_SERVICE); } else if (loopback) { - s_ipv4 = pa_socket_server_new_ipv4_loopback(c->mainloop, port, TCPWRAP_SERVICE); s_ipv6 = pa_socket_server_new_ipv6_loopback(c->mainloop, port, TCPWRAP_SERVICE); + s_ipv4 = pa_socket_server_new_ipv4_loopback(c->mainloop, port, TCPWRAP_SERVICE); } else { - s_ipv4 = pa_socket_server_new_ipv4_any(c->mainloop, port, TCPWRAP_SERVICE); s_ipv6 = pa_socket_server_new_ipv6_any(c->mainloop, port, TCPWRAP_SERVICE); + s_ipv4 = pa_socket_server_new_ipv4_any(c->mainloop, port, TCPWRAP_SERVICE); } if (!s_ipv4 && !s_ipv6) -- cgit From 6ae8511a66c0f937bdab2786ecdc7e158bd3934d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 19 Apr 2006 11:53:24 +0000 Subject: Having constant deferred events isn't allowed and causes problems. Use timers instead. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@757 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/main.c | 16 +++++++++++----- src/polyp/mainloop-signal.c | 24 ++++++++++++++++-------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/daemon/main.c b/src/daemon/main.c index 4ae9fbf1..e14837a9 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -79,8 +79,9 @@ int deny_severity = LOG_WARNING; #ifdef OS_IS_WIN32 -static void message_cb(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { +static void message_cb(pa_mainloop_api*a, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { MSG msg; + struct timeval tvnext; while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) @@ -90,6 +91,9 @@ static void message_cb(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { DispatchMessage(&msg); } } + + pa_timeval_add(pa_gettimeofday(&tvnext), 100000); + a->time_restart(e, &tvnext); } #endif @@ -153,7 +157,8 @@ int main(int argc, char *argv[]) { #endif #ifdef OS_IS_WIN32 - pa_defer_event *defer; + pa_time_event *timer; + struct timeval tv; #endif pa_limit_caps(); @@ -386,8 +391,9 @@ int main(int argc, char *argv[]) { #endif #ifdef OS_IS_WIN32 - defer = pa_mainloop_get_api(mainloop)->defer_new(pa_mainloop_get_api(mainloop), message_cb, NULL); - assert(defer); + timer = pa_mainloop_get_api(mainloop)->time_new( + pa_mainloop_get_api(mainloop), pa_gettimeofday(&tv), message_cb, NULL); + assert(timer); #endif if (conf->daemonize) @@ -446,7 +452,7 @@ int main(int argc, char *argv[]) { } #ifdef OS_IS_WIN32 - pa_mainloop_get_api(mainloop)->defer_free(defer); + pa_mainloop_get_api(mainloop)->time_free(timer); #endif pa_core_free(c); diff --git a/src/polyp/mainloop-signal.c b/src/polyp/mainloop-signal.c index 0b33c44b..73de0002 100644 --- a/src/polyp/mainloop-signal.c +++ b/src/polyp/mainloop-signal.c @@ -59,7 +59,7 @@ struct pa_signal_event { static pa_mainloop_api *api = NULL; static int signal_pipe[2] = { -1, -1 }; static pa_io_event* io_event = NULL; -static pa_defer_event *defer_event = NULL; +static pa_time_event *time_event = NULL; static pa_signal_event *signals = NULL; #ifdef OS_IS_WIN32 @@ -92,10 +92,11 @@ static void dispatch(pa_mainloop_api*a, int sig) { } #ifdef OS_IS_WIN32 -static void defer(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event*e, PA_GCC_UNUSED void *userdata) { +static void timer(pa_mainloop_api*a, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, PA_GCC_UNUSED void *userdata) { ssize_t r; int sig; unsigned int sigs; + struct timeval tvnext; EnterCriticalSection(&crit); sigs = waiting_signals; @@ -117,6 +118,9 @@ static void defer(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event*e, PA_GCC_UNUS sigs--; } + + pa_timeval_add(pa_gettimeofday(&tvnext), 100000); + a->time_restart(e, &tvnext); } #endif @@ -143,7 +147,11 @@ static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags } int pa_signal_init(pa_mainloop_api *a) { - assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event && !defer_event); +#ifdef OS_IS_WIN32 + struct timeval tv; +#endif + + assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event && !time_event); #ifdef OS_IS_WIN32 if (_pipe(signal_pipe, 200, _O_BINARY) < 0) { @@ -165,8 +173,8 @@ int pa_signal_init(pa_mainloop_api *a) { io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL); assert(io_event); #else - defer_event = api->defer_new(api, defer, NULL); - assert(defer_event); + time_event = api->time_new(api, pa_gettimeofday(&tv), timer, NULL); + assert(time_event); InitializeCriticalSection(&crit); #endif @@ -175,7 +183,7 @@ int pa_signal_init(pa_mainloop_api *a) { } void pa_signal_done(void) { - assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && (io_event || defer_event)); + assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && (io_event || time_event)); while (signals) pa_signal_free(signals); @@ -184,8 +192,8 @@ void pa_signal_done(void) { api->io_free(io_event); io_event = NULL; #else - api->defer_free(defer_event); - defer_event = NULL; + api->time_free(time_event); + time_event = NULL; DeleteCriticalSection(&crit); #endif -- cgit From 5342f3aef17f857dac1f6a4dd2329a301a568f1e Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 19 Apr 2006 11:54:43 +0000 Subject: Win32 needs to have the socket subsystem initialised. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@758 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/context.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/polyp/context.c b/src/polyp/context.c index 448e2e68..ff224547 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -141,6 +141,13 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { pa_client_conf_from_x11(c->conf, NULL); #endif pa_client_conf_env(c->conf); + +#ifdef OS_IS_WIN32 + { + WSADATA data; + WSAStartup(MAKEWORD(2, 0), &data); + } +#endif return c; } @@ -180,6 +187,10 @@ static void context_free(pa_context *c) { pa_xfree(c->name); pa_xfree(c->server); pa_xfree(c); + +#ifdef OS_IS_WIN32 + WSACleanup(); +#endif } pa_context* pa_context_ref(pa_context *c) { -- cgit From e1513ce68448aea2c1b21e782151a8be8f17f8e1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 19 Apr 2006 11:55:46 +0000 Subject: WaveOut needs to have rather large chunks. This is about as low as we can go without getting underflows. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@759 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-waveout.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index 45ed10b9..ef602e8d 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -113,6 +113,9 @@ static void do_write(struct userdata *u) LeaveCriticalSection(&u->crit); + if (free_frags == u->fragments) + pa_log_debug(__FILE__": WaveOut underflow!"); + while (free_frags) { hdr = &u->ohdrs[u->cur_ohdr]; if (hdr->dwFlags & WHDR_PREPARED) @@ -194,6 +197,9 @@ static void do_read(struct userdata *u) LeaveCriticalSection(&u->crit); + if (free_frags == u->fragments) + pa_log_debug(__FILE__": WaveIn overflow!"); + while (free_frags) { hdr = &u->ihdrs[u->cur_ihdr]; if (hdr->dwFlags & WHDR_PREPARED) @@ -443,8 +449,8 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - nfrags = 20; - frag_size = 1024; + nfrags = 5; + frag_size = 8192; if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { pa_log(__FILE__": failed to parse fragments arguments"); goto fail; @@ -516,7 +522,7 @@ int pa__init(pa_core *c, pa_module*m) { u->oremain = u->fragment_size; - u->poll_timeout = pa_bytes_to_usec(u->fragments * u->fragment_size / 3, &ss); + u->poll_timeout = pa_bytes_to_usec(u->fragments * u->fragment_size / 10, &ss); pa_gettimeofday(&tv); pa_timeval_add(&tv, u->poll_timeout); -- cgit From 1d512470be3d6b87ccb817e0d71aead0d98f497e Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 19 Apr 2006 11:56:26 +0000 Subject: Minor fixes for the way Windows handles sockets. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@760 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/socket-client.c | 15 +++++++++++---- src/polypcore/winsock.h | 1 + 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/polypcore/socket-client.c b/src/polypcore/socket-client.c index 7c4f4d6b..734b9dde 100644 --- a/src/polypcore/socket-client.c +++ b/src/polypcore/socket-client.c @@ -151,7 +151,7 @@ static void do_call(pa_socket_client *c) { errno = error; goto finish; } - + io = pa_iochannel_new(c->mainloop, c->fd, c->fd); assert(io); @@ -187,8 +187,13 @@ static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t pa_make_nonblock_fd(c->fd); if ((r = connect(c->fd, sa, len)) < 0) { +#ifdef OS_IS_WIN32 + if (WSAGetLastError() != EWOULDBLOCK) { + pa_log_debug(__FILE__": connect(): %d", WSAGetLastError()); +#else if (errno != EINPROGRESS) { - /*pa_log(__FILE__": connect(): %s", strerror(errno));*/ + pa_log_debug(__FILE__": connect(): %s (%d)", strerror(errno), errno); +#endif return -1; } @@ -473,9 +478,11 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam struct hostent *host = NULL; struct sockaddr_in s; - /* FIXME: PF_INET6 support */ - if (hints.ai_family != PF_INET) + /* FIXME: PF_INET6 support */ + if (hints.ai_family == PF_INET6) { + pa_log_error(__FILE__": IPv6 is not supported on Windows"); goto finish; + } host = gethostbyname(a.path_or_host); if (!host) { diff --git a/src/polypcore/winsock.h b/src/polypcore/winsock.h index b1e0f7d4..ae868b38 100644 --- a/src/polypcore/winsock.h +++ b/src/polypcore/winsock.h @@ -13,6 +13,7 @@ #define ETIMEDOUT WSAETIMEDOUT #define ECONNREFUSED WSAECONNREFUSED #define EHOSTUNREACH WSAEHOSTUNREACH +#define EWOULDBLOCK WSAEWOULDBLOCK #endif -- cgit From 989fa585b267fbd7b7e40f4dd6e4caf34708910c Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 19 Apr 2006 14:30:42 +0000 Subject: Sun's documentation about SIGPOLL on EOF:s is wrong, so use a timer based solution instead. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@761 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-solaris.c | 48 ++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 9f93f9d8..a2034f3e 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -64,6 +64,8 @@ struct userdata { pa_source *source; pa_iochannel *io; pa_core *core; + pa_time_event *timer; + pa_usec_t poll_timeout; pa_signal_event *sig; pa_memchunk memchunk, silence; @@ -111,7 +113,8 @@ static void do_write(struct userdata *u) { assert(u); - if (!u->sink || !pa_iochannel_is_writable(u->io)) + /* We cannot check pa_iochannel_is_writable() because of our buffer hack */ + if (!u->sink) return; update_usage(u); @@ -126,12 +129,8 @@ static void do_write(struct userdata *u) { len = u->buffer_size; len -= u->written_bytes - (info.play.samples * u->sample_size); - /* - * Do not fill more than half the buffer in one chunk since we only - * get notifications upon completion of entire chunks. - */ - if (len > (u->buffer_size / 2)) - len = u->buffer_size / 2; + if (len == u->buffer_size) + pa_log_debug(__FILE__": Solaris buffer underflow!"); if (len < u->sample_size) return; @@ -167,14 +166,6 @@ static void do_write(struct userdata *u) { } u->written_bytes += r; - - /* - * Write 0 bytes which will generate a SIGPOLL when "played". - */ - if (write(u->fd, NULL, 0) < 0) { - pa_log(__FILE__": write() failed: %s", strerror(errno)); - return; - } } static void do_read(struct userdata *u) { @@ -217,14 +208,26 @@ static void io_callback(pa_iochannel *io, void*userdata) { do_read(u); } +static void timer_cb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) { + struct userdata *u = userdata; + struct timeval ntv; + + assert(u); + + do_write(u); + + pa_gettimeofday(&ntv); + pa_timeval_add(&ntv, u->poll_timeout); + + a->time_restart(e, &ntv); +} + static void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata) { struct userdata *u = userdata; pa_cvolume old_vol; assert(u); - do_write(u); - if (u->sink) { assert(u->sink->get_hw_volume); memcpy(&old_vol, &u->sink->hw_volume, sizeof(pa_cvolume)); @@ -475,6 +478,7 @@ int pa__init(pa_core *c, pa_module*m) { int record = 1, playback = 1; pa_sample_spec ss; pa_modargs *ma = NULL; + struct timeval tv; assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -570,6 +574,14 @@ int pa__init(pa_core *c, pa_module*m) { u->module = m; m->userdata = u; + u->poll_timeout = pa_bytes_to_usec(u->buffer_size / 10, &ss); + + pa_gettimeofday(&tv); + pa_timeval_add(&tv, u->poll_timeout); + + u->timer = c->mainloop->time_new(c->mainloop, &tv, timer_cb, u); + assert(u->timer); + u->sig = pa_signal_new(SIGPOLL, sig_callback, u); assert(u->sig); ioctl(u->fd, I_SETSIG, S_MSG); @@ -603,6 +615,8 @@ void pa__done(pa_core *c, pa_module*m) { if (!(u = m->userdata)) return; + if (u->timer) + c->mainloop->time_free(u->timer); ioctl(u->fd, I_SETSIG, 0); pa_signal_free(u->sig); -- cgit From e4b53b2badbd3679df6154e6d6687fcc2aa57885 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 19 Apr 2006 15:37:52 +0000 Subject: Tweaks for the solaris module. The sound system requires complete frames to be written. Also, the sample counter can magically go backwards sometimes, causing havoc with our buffer handling. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@762 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-solaris.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index a2034f3e..e1a03272 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -70,7 +70,7 @@ struct userdata { pa_memchunk memchunk, silence; - uint32_t sample_size; + uint32_t frame_size; uint32_t buffer_size; unsigned int written_bytes, read_bytes; @@ -127,12 +127,18 @@ static void do_write(struct userdata *u) { * by not filling it more than u->buffer_size. */ len = u->buffer_size; - len -= u->written_bytes - (info.play.samples * u->sample_size); + len -= u->written_bytes - (info.play.samples * u->frame_size); + + /* The sample counter can sometimes go backwards :( */ + if (len > u->buffer_size) + len = 0; if (len == u->buffer_size) pa_log_debug(__FILE__": Solaris buffer underflow!"); - if (len < u->sample_size) + len -= len % u->frame_size; + + if (len == 0) return; memchunk = &u->memchunk; @@ -145,17 +151,20 @@ static void do_write(struct userdata *u) { assert(memchunk->memblock->data); assert(memchunk->length); - if (memchunk->length < len) + if (memchunk->length < len) { len = memchunk->length; - + len -= len % u->frame_size; + assert(len); + } + if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, len)) < 0) { pa_log(__FILE__": write() failed: %s", strerror(errno)); return; } + + assert(r % u->frame_size == 0); - if (memchunk == &u->silence) - assert(r % u->sample_size == 0); - else { + if (memchunk != &u->silence) { u->memchunk.index += r; u->memchunk.length -= r; @@ -264,7 +273,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { assert(err >= 0); r += pa_bytes_to_usec(u->written_bytes, &s->sample_spec); - r -= pa_bytes_to_usec(info.play.samples * u->sample_size, &s->sample_spec); + r -= pa_bytes_to_usec(info.play.samples * u->frame_size, &s->sample_spec); if (u->memchunk.memblock) r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec); @@ -282,7 +291,7 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { err = ioctl(u->fd, AUDIO_GETINFO, &info); assert(err >= 0); - r += pa_bytes_to_usec(info.record.samples * u->sample_size, &s->sample_spec); + r += pa_bytes_to_usec(info.record.samples * u->frame_size, &s->sample_spec); r -= pa_bytes_to_usec(u->read_bytes, &s->sample_spec); return r; @@ -560,7 +569,7 @@ int pa__init(pa_core *c, pa_module*m) { u->memchunk.memblock = NULL; u->memchunk.length = 0; - u->sample_size = pa_frame_size(&ss); + u->frame_size = pa_frame_size(&ss); u->buffer_size = buffer_size; u->silence.memblock = pa_memblock_new(u->silence.length = CHUNK_SIZE, u->core->memblock_stat); -- cgit From 1b4609774e51037c4f4ccbd591cccb9a9540b476 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 20 Apr 2006 07:44:47 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@763 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/todo b/doc/todo index e7ba47c8..bd8145fb 100644 --- a/doc/todo +++ b/doc/todo @@ -12,6 +12,8 @@ Post 0.8: - use scatter/gather io for sockets - add a synchronous API (base it on xmms-polyp) - rtp module ported to Win32 (sendmsg/recvmsg emulation) +- CODECs to reduce bandwidth usage (plug-in based) +- Remove symdef files and use macros (like most other projects) Long term: - pass meta info for hearing impaired -- cgit From 2decb6a5d31bf2338394b0288be4c3204f1703ee Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Apr 2006 12:33:00 +0000 Subject: * rename "LICENSE" to "LGPL" * add GPL text * update LGPL text in regards to FSF addresses git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@764 fefdeb5f-60dc-0310-8127-8f9354f1896f --- GPL | 340 +++++++++++++++++++++++++++++++++++++++++++ LGPL | 510 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ LICENSE | 510 ---------------------------------------------------------------- 3 files changed, 850 insertions(+), 510 deletions(-) create mode 100644 GPL create mode 100644 LGPL delete mode 100644 LICENSE diff --git a/GPL b/GPL new file mode 100644 index 00000000..b7b5f53d --- /dev/null +++ b/GPL @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/LGPL b/LGPL new file mode 100644 index 00000000..2d2d780e --- /dev/null +++ b/LGPL @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/LICENSE b/LICENSE deleted file mode 100644 index b124cf58..00000000 --- a/LICENSE +++ /dev/null @@ -1,510 +0,0 @@ - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations -below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it -becomes a de-facto standard. To achieve this, non-free programs must -be allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control -compilation and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at least - three years, to give the same user the materials specified in - Subsection 6a, above, for a charge no more than the cost of - performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply, and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License -may add an explicit geographical distribution limitation excluding those -countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms -of the ordinary General Public License). - - To apply these terms, attach the following notices to the library. -It is safest to attach them to the start of each source file to most -effectively convey the exclusion of warranty; and each file should -have at least the "copyright" line and a pointer to where the full -notice is found. - - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or -your school, if any, to sign a "copyright disclaimer" for the library, -if necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James - Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - -- cgit From 81381c4ee71b12d9022e6cbf83f63a95b704c32d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Apr 2006 12:40:10 +0000 Subject: add new explaining LICENSE file git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@765 fefdeb5f-60dc-0310-8127-8f9354f1896f --- LICENSE | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..a4990f69 --- /dev/null +++ b/LICENSE @@ -0,0 +1,11 @@ +All Polypaudio sources are licensed under the GNU Lesser General Public +License. (see file LGPL for details) + +However, the server side links to the GPL-only library 'libsamplerate' which +downgrades the license of the server part to GPL (see file GPL for details), +exercising section 3 of the LGPL. + +Hence you should treat the client library ('libpolyp') of Polypaudio as being +LGPL licensed and the server part ('libpolypcore') as being GPL licensed. + +-- Lennart Poettering, April 20th, 2006. -- cgit From 9c06f5a9599f6967499f79e0cc1f868d8d6e53c0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Apr 2006 12:40:54 +0000 Subject: ship GPL and LGPL files with the tarball git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@766 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 8d34ca89..be0f7016 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,7 +17,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -EXTRA_DIST = bootstrap.sh LICENSE doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in libtool.m4 ltdl.m4 +EXTRA_DIST = bootstrap.sh LICENSE GPL LGPL doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in libtool.m4 ltdl.m4 SUBDIRS=libltdl src doc doxygen MAINTAINERCLEANFILES = -- cgit From 5f804cb34c32b6e8209cff8a6627523b6cd148c0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Apr 2006 12:45:52 +0000 Subject: minor improvements to the LICENSE text git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@767 fefdeb5f-60dc-0310-8127-8f9354f1896f --- LICENSE | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/LICENSE b/LICENSE index a4990f69..0ef09512 100644 --- a/LICENSE +++ b/LICENSE @@ -1,11 +1,13 @@ -All Polypaudio sources are licensed under the GNU Lesser General Public +All Polypaudio source files are licensed under the GNU Lesser General Public License. (see file LGPL for details) However, the server side links to the GPL-only library 'libsamplerate' which -downgrades the license of the server part to GPL (see file GPL for details), -exercising section 3 of the LGPL. +practically downgrades the license of the server part to GPL (see file GPL for +details), exercising section 3 of the LGPL. Hence you should treat the client library ('libpolyp') of Polypaudio as being -LGPL licensed and the server part ('libpolypcore') as being GPL licensed. +LGPL licensed and the server part ('libpolypcore') as being GPL licensed. Since +the Polypaudio daemon and the modules link to 'libpolypcore' they are of course +also GPL licensed. -- Lennart Poettering, April 20th, 2006. -- cgit From a7c5ed19948915a1930ea19ae2c11b5486542cb0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Apr 2006 12:53:49 +0000 Subject: replace copy by symlink when installing homepage git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@768 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index be0f7016..c7ea54f3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -53,7 +53,7 @@ homepage: all dist doxygen cp polypaudio-@PACKAGE_VERSION@.tar.gz $$HOME/homepage/private/projects/polypaudio cp doc/README.html doc/FAQ.html doc/cli.html doc/daemon.html doc/modules.html doc/style.css $$HOME/homepage/private/projects/polypaudio cp -a doxygen/html/* $$HOME/homepage/private/projects/polypaudio/doxygen - cp $$HOME/homepage/private/projects/polypaudio/README.html $$HOME/homepage/private/projects/polypaudio/index.html + ln -sf $$HOME/homepage/private/projects/polypaudio/README.html $$HOME/homepage/private/projects/polypaudio/index.html #distcleancheck: # @: -- cgit From 0cc2e04157bd4fc6838b3690bd6387fcb3ee4587 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Apr 2006 14:31:47 +0000 Subject: chown() and chmod() /tmp/.esd/ before checking if everything is ok with it git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@770 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/util.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/polypcore/util.c b/src/polypcore/util.c index b37a25a3..8418a692 100644 --- a/src/polypcore/util.c +++ b/src/polypcore/util.c @@ -140,13 +140,16 @@ int pa_make_secure_dir(const char* dir) { if (errno != EEXIST) return -1; + chown(dir, getuid(), getgid()); + chmod(dir, 0700); + #ifdef HAVE_LSTAT if (lstat(dir, &st) < 0) #else if (stat(dir, &st) < 0) #endif goto fail; - + #ifndef OS_IS_WIN32 if (!S_ISDIR(st.st_mode) || (st.st_uid != getuid()) || ((st.st_mode & 0777) != 0700)) goto fail; -- cgit From b0059c679d1beb3ee2d45b689d3d52d051ad795d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Apr 2006 20:04:06 +0000 Subject: try to remove the directory where the PID file resides in after removing the PID file git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@771 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/pid.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/polypcore/pid.c b/src/polypcore/pid.c index 374b5506..b258290b 100644 --- a/src/polypcore/pid.c +++ b/src/polypcore/pid.c @@ -41,6 +41,7 @@ #include #include +#include #include "pid.h" @@ -191,6 +192,7 @@ int pa_pid_file_remove(void) { char fn[PATH_MAX]; int ret = -1; pid_t pid; + char *p; pa_runtime_path("pid", fn, sizeof(fn)); @@ -223,6 +225,11 @@ int pa_pid_file_remove(void) { goto fail; } + if ((p = pa_parent_dir(fn))) { + rmdir(p); + pa_xfree(p); + } + ret = 0; fail: -- cgit From 513df3b9f8af35d11bbdc44d0dcbc9ab35fd1465 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Apr 2006 20:04:25 +0000 Subject: first unlink the socket, the close it git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@772 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/socket-server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/polypcore/socket-server.c b/src/polypcore/socket-server.c index b27816d4..f7e0b647 100644 --- a/src/polypcore/socket-server.c +++ b/src/polypcore/socket-server.c @@ -379,13 +379,14 @@ pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const cha static void socket_server_free(pa_socket_server*s) { assert(s); - close(s->fd); if (s->filename) { unlink(s->filename); pa_xfree(s->filename); } + close(s->fd); + pa_xfree(s->tcpwrap_service); s->mainloop->io_free(s->io_event); @@ -406,7 +407,6 @@ void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_ s->userdata = userdata; } - char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { assert(s && c && l > 0); -- cgit From a4fedcf2dc67a946354ea003424deb3c2489f7fc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Apr 2006 20:05:01 +0000 Subject: add new function pa_parent_dir() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@773 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/util.c | 19 ++++++++++++++----- src/polypcore/util.h | 2 ++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/polypcore/util.c b/src/polypcore/util.c index 8418a692..615ea881 100644 --- a/src/polypcore/util.c +++ b/src/polypcore/util.c @@ -164,15 +164,25 @@ fail: return -1; } -/* Creates a the parent directory of the specified path securely */ -int pa_make_secure_parent_dir(const char *fn) { - int ret = -1; +/* Return a newly allocated sting containing the parent directory of the specified file */ +char *pa_parent_dir(const char *fn) { char *slash, *dir = pa_xstrdup(fn); slash = (char*) pa_path_get_filename(dir); if (slash == fn) - goto finish; + return NULL; + *(slash-1) = 0; + return dir; +} + +/* Creates a the parent directory of the specified path securely */ +int pa_make_secure_parent_dir(const char *fn) { + int ret = -1; + char *dir; + + if (!(dir = pa_parent_dir(fn))) + goto finish; if (pa_make_secure_dir(dir) < 0) goto finish; @@ -184,7 +194,6 @@ finish: return ret; } - /** Calls read() in a loop. Makes sure that as much as 'size' bytes, * unless EOF is reached or an error occured */ ssize_t pa_loop_read(int fd, void*data, size_t size) { diff --git a/src/polypcore/util.h b/src/polypcore/util.h index f05339c4..ca81b229 100644 --- a/src/polypcore/util.h +++ b/src/polypcore/util.h @@ -55,6 +55,8 @@ char *pa_get_home_dir(char *s, size_t l); const char *pa_path_get_filename(const char *p); +char *pa_parent_dir(const char *fn); + struct timeval *pa_gettimeofday(struct timeval *tv); pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); -- cgit From 0e02e844a283cbffe373e702668b88174631fb6e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Apr 2006 20:06:48 +0000 Subject: * for unix sockets: remove the right parent directory on shutdown * other cleanups git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@774 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-protocol-stub.c | 62 ++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index 0ffd81df..d5b5f63b 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -169,6 +169,7 @@ struct userdata { void *protocol_ipv6; #else void *protocol_unix; + char *socket_path; #endif }; @@ -197,6 +198,8 @@ int pa__init(pa_core *c, pa_module*m) { goto finish; } + u = pa_xnew0(struct userdata, 1); + #if defined(USE_TCP_SOCKETS) if (pa_modargs_get_value_boolean(ma, "loopback", &loopback) < 0) { pa_log(__FILE__": loopback= expects a boolean argument."); @@ -224,11 +227,21 @@ int pa__init(pa_core *c, pa_module*m) { if (!s_ipv4 && !s_ipv6) goto fail; + if (s_ipv4) + if (!(u->protocol_ipv4 = protocol_new(c, s_ipv4, m, ma))) + pa_socket_server_unref(s_ipv4); + + if (s_ipv6) + if (!(u->protocol_ipv6 = protocol_new(c, s_ipv6, m, ma))) + pa_socket_server_unref(s_ipv6); + + if (!u->protocol_ipv4 && !u->protocol_ipv6) + goto fail; + #else v = pa_modargs_get_value(ma, "socket", UNIX_SOCKET); - assert(v); - pa_runtime_path(v, tmp, sizeof(tmp)); + u->socket_path = pa_xstrdup(tmp); if (pa_make_secure_parent_dir(tmp) < 0) { pa_log(__FILE__": Failed to create secure socket directory."); @@ -245,24 +258,10 @@ int pa__init(pa_core *c, pa_module*m) { if (!(s = pa_socket_server_new_unix(c->mainloop, tmp))) goto fail; -#endif - - u = pa_xnew0(struct userdata, 1); - -#if defined(USE_TCP_SOCKETS) - if (s_ipv4) - if (!(u->protocol_ipv4 = protocol_new(c, s_ipv4, m, ma))) - pa_socket_server_unref(s_ipv4); - - if (s_ipv6) - if (!(u->protocol_ipv6 = protocol_new(c, s_ipv6, m, ma))) - pa_socket_server_unref(s_ipv6); - if (!u->protocol_ipv4 && !u->protocol_ipv6) - goto fail; -#else if (!(u->protocol_unix = protocol_new(c, s, m, ma))) goto fail; + #endif m->userdata = u; @@ -285,7 +284,11 @@ fail: #else if (u->protocol_unix) protocol_free(u->protocol_unix); + + if (u->socket_path) + pa_xfree(u->socket_path); #endif + pa_xfree(u); } else { #if defined(USE_TCP_SOCKETS) @@ -304,17 +307,11 @@ fail: void pa__done(pa_core *c, pa_module*m) { struct userdata *u; - assert(c && m); - -#if defined(USE_PROTOCOL_ESOUND) && !defined(USE_TCP_SOCKETS) - if (remove(ESD_UNIX_SOCKET_NAME) != 0) - pa_log("%s: Failed to remove %s : %s.", __FILE__, ESD_UNIX_SOCKET_NAME, strerror (errno)); - if (remove(ESD_UNIX_SOCKET_DIR) != 0) - pa_log("%s: Failed to remove %s : %s.", __FILE__, ESD_UNIX_SOCKET_DIR, strerror (errno)); -#endif + + assert(c); + assert(m); u = m->userdata; - assert(u); #if defined(USE_TCP_SOCKETS) if (u->protocol_ipv4) @@ -324,6 +321,19 @@ void pa__done(pa_core *c, pa_module*m) { #else if (u->protocol_unix) protocol_free(u->protocol_unix); + + if (u->socket_path) { + char *p; + + if ((p = pa_parent_dir(u->socket_path))) { + if (rmdir(p) < 0 && errno != ENOENT && errno != ENOTEMPTY) + pa_log(__FILE__": Failed to remove %s: %s.", u->socket_path, strerror(errno)); + + pa_xfree(p); + } + + pa_xfree(u->socket_path); + } #endif pa_xfree(u); -- cgit From 55e19cbc039be4481215d19b39452ab9fc9d0d11 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Apr 2006 21:04:35 +0000 Subject: fix sample cache git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@775 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/core-scache.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/polypcore/core-scache.c b/src/polypcore/core-scache.c index 1803931e..394bdab4 100644 --- a/src/polypcore/core-scache.c +++ b/src/polypcore/core-scache.c @@ -115,7 +115,6 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_NEW, e->index); } - pa_cvolume_reset(&e->volume, PA_CHANNELS_MAX); e->last_used_time = 0; e->memchunk.memblock = NULL; e->memchunk.index = e->memchunk.length = 0; @@ -124,6 +123,7 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { e->last_used_time = 0; memset(&e->sample_spec, 0, sizeof(pa_sample_spec)); + pa_cvolume_reset(&e->volume, PA_CHANNELS_MAX); return e; } @@ -138,6 +138,7 @@ int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, c if (ss) { e->sample_spec = *ss; pa_channel_map_init_auto(&e->channel_map, ss->channels); + e->volume.channels = e->sample_spec.channels; } if (map) @@ -242,7 +243,10 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, const pa_cv pa_scache_entry *e; char *t; pa_cvolume r; - assert(c && name && sink); + + assert(c); + assert(name); + assert(sink); if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1))) return -1; @@ -252,19 +256,27 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, const pa_cv return -1; pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); + e->volume.channels = e->sample_spec.channels; } if (!e->memchunk.memblock) return -1; t = pa_sprintf_malloc("sample:%s", name); - - if (pa_play_memchunk(sink, t, &e->sample_spec, &e->channel_map, &e->memchunk, pa_sw_cvolume_multiply(&r, volume, &e->volume)) < 0) { - free(t); + + if (volume) { + r = *volume; + r.channels = e->volume.channels; + pa_sw_cvolume_multiply(&r, &r, &e->volume); + } else + r = e->volume; + + if (pa_play_memchunk(sink, t, &e->sample_spec, &e->channel_map, &e->memchunk, &r) < 0) { + pa_xfree(t); return -1; } - free(t); + pa_xfree(t); if (e->lazy) time(&e->last_used_time); -- cgit From 5e50f84e71b948b4737fe8b5860e5fe414258570 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Apr 2006 21:49:30 +0000 Subject: fix x11 handling git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@776 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/x11wrap.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/polypcore/x11wrap.c b/src/polypcore/x11wrap.c index 21a7f307..c1ca83ca 100644 --- a/src/polypcore/x11wrap.c +++ b/src/polypcore/x11wrap.c @@ -87,6 +87,9 @@ static void display_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_ static void defer_event(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { pa_x11_wrapper *w = userdata; assert(m && e && w && w->ref >= 1); + + m->defer_enable(e, 0); + work(w); } @@ -96,6 +99,8 @@ static void internal_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC assert(m && e && fd >= 0 && w && w->ref >= 1); XProcessInternalConnection(w->display, fd); + + work(w); } /* Add a new IO source for the specified X11 internal connection */ @@ -211,6 +216,10 @@ void pa_x11_wrapper_unref(pa_x11_wrapper* w) { Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w) { assert(w && w->ref >= 1); + + /* Somebody is using us, schedule a output buffer flush */ + w->core->mainloop->defer_enable(w->defer_event, 1); + return w->display; } -- cgit From ec65ca6ae758610a46c95fbf589729fb15cf1daf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Apr 2006 21:50:15 +0000 Subject: when loading sound files, initialize channel map data properly git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@777 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/core-scache.c | 7 ++++--- src/polypcore/sound-file.c | 5 ++++- src/polypcore/sound-file.h | 3 ++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/polypcore/core-scache.c b/src/polypcore/core-scache.c index 394bdab4..6632a171 100644 --- a/src/polypcore/core-scache.c +++ b/src/polypcore/core-scache.c @@ -157,6 +157,7 @@ int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, c int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint32_t *idx) { pa_sample_spec ss; + pa_channel_map map; pa_memchunk chunk; int r; @@ -167,10 +168,10 @@ int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint3 filename = buf; #endif - if (pa_sound_file_load(filename, &ss, &chunk, c->memblock_stat) < 0) + if (pa_sound_file_load(filename, &ss, &map, &chunk, c->memblock_stat) < 0) return -1; - r = pa_scache_add_item(c, name, &ss, NULL, &chunk, idx); + r = pa_scache_add_item(c, name, &ss, &map, &chunk, idx); pa_memblock_unref(chunk.memblock); return r; @@ -252,7 +253,7 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, const pa_cv return -1; if (e->lazy && !e->memchunk.memblock) { - if (pa_sound_file_load(e->filename, &e->sample_spec, &e->memchunk, c->memblock_stat) < 0) + if (pa_sound_file_load(e->filename, &e->sample_spec, &e->channel_map, &e->memchunk, c->memblock_stat) < 0) return -1; pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); diff --git a/src/polypcore/sound-file.c b/src/polypcore/sound-file.c index d86141ce..7a4ef075 100644 --- a/src/polypcore/sound-file.c +++ b/src/polypcore/sound-file.c @@ -35,7 +35,7 @@ #define MAX_FILE_SIZE (1024*1024) -int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_memchunk *chunk, pa_memblock_stat *s) { +int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_channel_map *map, pa_memchunk *chunk, pa_memblock_stat *s) { SNDFILE*sf = NULL; SF_INFO sfinfo; int ret = -1; @@ -74,6 +74,9 @@ int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_memchunk *chunk pa_log(__FILE__": Unsupported sample format in file %s", fname); goto finish; } + + if (map) + pa_channel_map_init_auto(map, ss->channels); if ((l = pa_frame_size(ss)*sfinfo.frames) > MAX_FILE_SIZE) { pa_log(__FILE__": File too large"); diff --git a/src/polypcore/sound-file.h b/src/polypcore/sound-file.h index ffa551b5..9d687f90 100644 --- a/src/polypcore/sound-file.h +++ b/src/polypcore/sound-file.h @@ -23,9 +23,10 @@ ***/ #include +#include #include -int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_memchunk *chunk, pa_memblock_stat *s); +int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_channel_map *map, pa_memchunk *chunk, pa_memblock_stat *s); int pa_sound_file_too_big_to_cache(const char *fname); -- cgit From f6fc410a96c7b0ca8e393d20ffe5771da5b55604 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Apr 2006 21:51:30 +0000 Subject: modify x11 modules to not cache the Display variable since pa_x11wrap_get_display() is now used as notification that the x11 output buffer needs flushing git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@778 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-x11-bell.c | 13 +++++-------- src/modules/module-x11-publish.c | 27 ++++++++++++--------------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/modules/module-x11-bell.c b/src/modules/module-x11-bell.c index 27ceb7f9..fe1711a5 100644 --- a/src/modules/module-x11-bell.c +++ b/src/modules/module-x11-bell.c @@ -52,7 +52,6 @@ struct userdata { int xkb_event_base; char *sink_name; char *scache_item; - Display *display; pa_x11_wrapper *x11_wrapper; pa_x11_client *x11_client; @@ -75,7 +74,7 @@ static int ring_bell(struct userdata *u, int percent) { return -1; } - pa_scache_play_item(u->core, u->scache_item, s, pa_cvolume_set(&cv, PA_CHANNELS_MAX, percent*PA_VOLUME_NORM/100)); + pa_scache_play_item(u->core, u->scache_item, s, pa_cvolume_set(&cv, PA_CHANNELS_MAX, (percent*PA_VOLUME_NORM)/100)); return 0; } @@ -118,8 +117,6 @@ int pa__init(pa_core *c, pa_module*m) { if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL)))) goto fail; - u->display = pa_x11_wrapper_get_display(u->x11_wrapper); - major = XkbMajorVersion; minor = XkbMinorVersion; @@ -132,15 +129,15 @@ int pa__init(pa_core *c, pa_module*m) { minor = XkbMinorVersion; - if (!XkbQueryExtension(u->display, NULL, &u->xkb_event_base, NULL, &major, &minor)) { + if (!XkbQueryExtension(pa_x11_wrapper_get_display(u->x11_wrapper), NULL, &u->xkb_event_base, NULL, &major, &minor)) { pa_log(__FILE__": XkbQueryExtension() failed"); goto fail; } - XkbSelectEvents(u->display, XkbUseCoreKbd, XkbBellNotifyMask, XkbBellNotifyMask); + XkbSelectEvents(pa_x11_wrapper_get_display(u->x11_wrapper), XkbUseCoreKbd, XkbBellNotifyMask, XkbBellNotifyMask); auto_ctrls = auto_values = XkbAudibleBellMask; - XkbSetAutoResetControls(u->display, XkbAudibleBellMask, &auto_ctrls, &auto_values); - XkbChangeEnabledControls(u->display, XkbUseCoreKbd, XkbAudibleBellMask, 0); + XkbSetAutoResetControls(pa_x11_wrapper_get_display(u->x11_wrapper), XkbAudibleBellMask, &auto_ctrls, &auto_values); + XkbChangeEnabledControls(pa_x11_wrapper_get_display(u->x11_wrapper), XkbUseCoreKbd, XkbAudibleBellMask, 0); u->x11_client = pa_x11_client_new(u->x11_wrapper, x11_event_callback, u); diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c index cee9cb3f..7408b930 100644 --- a/src/modules/module-x11-publish.c +++ b/src/modules/module-x11-publish.c @@ -66,7 +66,6 @@ static const char* const valid_modargs[] = { struct userdata { pa_core *core; pa_x11_wrapper *x11_wrapper; - Display *display; char *id; uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; int auth_cookie_in_property; @@ -123,28 +122,26 @@ int pa__init(pa_core *c, pa_module*m) { if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL)))) goto fail; - u->display = pa_x11_wrapper_get_display(u->x11_wrapper); - if (!(l = pa_property_get(c, PA_NATIVE_SERVER_PROPERTY_NAME))) goto fail; s = pa_strlist_tostring(l); - pa_x11_set_prop(u->display, "POLYP_SERVER", s); + pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_SERVER", s); pa_xfree(s); if (!pa_get_fqdn(hn, sizeof(hn)) || !pa_get_user_name(un, sizeof(un))) goto fail; u->id = pa_sprintf_malloc("%s@%s/%u", un, hn, (unsigned) getpid()); - pa_x11_set_prop(u->display, "POLYP_ID", u->id); + pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_ID", u->id); if ((t = pa_modargs_get_value(ma, "source", NULL))) - pa_x11_set_prop(u->display, "POLYP_SOURCE", t); + pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_SOURCE", t); if ((t = pa_modargs_get_value(ma, "sink", NULL))) - pa_x11_set_prop(u->display, "POLYP_SINK", t); + pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_SINK", t); - pa_x11_set_prop(u->display, "POLYP_COOKIE", pa_hexstr(u->auth_cookie, sizeof(u->auth_cookie), hx, sizeof(hx))); + pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_COOKIE", pa_hexstr(u->auth_cookie, sizeof(u->auth_cookie), hx, sizeof(hx))); pa_modargs_free(ma); return 0; @@ -168,15 +165,15 @@ void pa__done(pa_core *c, pa_module*m) { char t[256]; /* Yes, here is a race condition */ - if (!pa_x11_get_prop(u->display, "POLYP_ID", t, sizeof(t)) || strcmp(t, u->id)) + if (!pa_x11_get_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_ID", t, sizeof(t)) || strcmp(t, u->id)) pa_log_warn(__FILE__": Polypaudio information vanished from X11!"); else { - pa_x11_del_prop(u->display, "POLYP_ID"); - pa_x11_del_prop(u->display, "POLYP_SERVER"); - pa_x11_del_prop(u->display, "POLYP_SINK"); - pa_x11_del_prop(u->display, "POLYP_SOURCE"); - pa_x11_del_prop(u->display, "POLYP_COOKIE"); - XSync(u->display, False); + pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_ID"); + pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_SERVER"); + pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_SINK"); + pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_SOURCE"); + pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_COOKIE"); + XSync(pa_x11_wrapper_get_display(u->x11_wrapper), False); } } -- cgit From 985da9bb5956fa7400e8f9ce861bf6fab2b3b6ce Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Apr 2006 21:53:18 +0000 Subject: require automake 1.9 in configure.ac git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@779 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index d6239f97..d73a6929 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ AC_PREREQ(2.57) AC_INIT([polypaudio],[0.8],[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([src/daemon/main.c]) AC_CONFIG_HEADERS([config.h]) -AM_INIT_AUTOMAKE([foreign -Wall]) +AM_INIT_AUTOMAKE([foreign 1.9 -Wall]) AC_SUBST(PA_MAJORMINOR, "$PACKAGE_VERSION") AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/polypaudio/]) -- cgit From 2bb8283a66a06282f23b55fc47b3d4c1cdb79704 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Apr 2006 21:53:35 +0000 Subject: remove superfluous "set -ex" line git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@780 fefdeb5f-60dc-0310-8127-8f9354f1896f --- bootstrap.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/bootstrap.sh b/bootstrap.sh index 19acffb5..ea6758a4 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -45,8 +45,6 @@ if [ "x$1" = "xam" ] ; then run_versioned automake "$VERSION" -a -c --foreign ./config.status else - set -ex - rm -rf autom4te.cache rm -f config.cache -- cgit From 834506318d70d2562cf28539ab922388001d4247 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 23 Apr 2006 14:29:32 +0000 Subject: * Merge build system patch from Igor Zubkov * Build libparseaddr.so before libsocket-client.so git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@781 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index b646cff7..2061b0ca 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -573,8 +573,8 @@ modlib_LTLIBRARIES = \ libsocket-util.la \ libiochannel.la \ libsocket-server.la \ - libsocket-client.la \ libparseaddr.la \ + libsocket-client.la \ libpacket.la \ libpstream.la \ libioline.la \ @@ -690,7 +690,7 @@ libauthkey_prop_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket_util_la_SOURCES = polypcore/socket-util.c polypcore/socket-util.h libsocket_util_la_LDFLAGS = -avoid-version -libsocket_util_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) +libsocket_util_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) libpolypcore.la librtp_la_SOURCES = modules/rtp/rtp.c modules/rtp/rtp.h modules/rtp/sdp.c modules/rtp/sdp.h modules/rtp/sap.c modules/rtp/sap.h librtp_la_LDFLAGS = -avoid-version @@ -701,7 +701,7 @@ librtp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libx11wrap_la_SOURCES = polypcore/x11wrap.c polypcore/x11wrap.h libx11wrap_la_LDFLAGS = -avoid-version libx11wrap_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) -libx11wrap_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) +libx11wrap_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libpolypcore.la libx11prop_la_SOURCES = polypcore/x11prop.c polypcore/x11prop.h libx11prop_la_LDFLAGS = -avoid-version @@ -988,7 +988,7 @@ module_tunnel_source_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket-client.l module_x11_bell_la_SOURCES = modules/module-x11-bell.c module_x11_bell_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) module_x11_bell_la_LDFLAGS = -module -avoid-version -module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la +module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la libpolypcore.la module_x11_publish_la_SOURCES = modules/module-x11-publish.c module_x11_publish_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) @@ -999,6 +999,7 @@ module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EX liboss_util_la_SOURCES = modules/oss-util.c modules/oss-util.h liboss_util_la_LDFLAGS = -avoid-version +liboss_util_la_LIBADD = libpolypcore.la module_oss_la_SOURCES = modules/module-oss.c module_oss_la_LDFLAGS = -module -avoid-version @@ -1006,23 +1007,23 @@ module_oss_la_LIBADD = $(AM_LIBADD) libiochannel.la liboss-util.la module_oss_mmap_la_SOURCES = modules/module-oss-mmap.c module_oss_mmap_la_LDFLAGS = -module -avoid-version -module_oss_mmap_la_LIBADD = $(AM_LIBADD) liboss-util.la +module_oss_mmap_la_LIBADD = $(AM_LIBADD) liboss-util.la libpolypcore.la # ALSA libalsa_util_la_SOURCES = modules/alsa-util.c modules/alsa-util.h libalsa_util_la_LDFLAGS = -avoid-version -libalsa_util_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) +libalsa_util_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libpolypcore.la libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) module_alsa_sink_la_SOURCES = modules/module-alsa-sink.c module_alsa_sink_la_LDFLAGS = -module -avoid-version -module_alsa_sink_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la +module_alsa_sink_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la libpolypcore.la module_alsa_sink_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) module_alsa_source_la_SOURCES = modules/module-alsa-source.c module_alsa_source_la_LDFLAGS = -module -avoid-version -module_alsa_source_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la +module_alsa_source_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la libpolypcore.la module_alsa_source_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) # Solaris @@ -1047,14 +1048,14 @@ module_zeroconf_publish_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) module_lirc_la_SOURCES = modules/module-lirc.c module_lirc_la_LDFLAGS = -module -avoid-version -module_lirc_la_LIBADD = $(AM_LIBADD) $(LIRC_LIBS) +module_lirc_la_LIBADD = $(AM_LIBADD) $(LIRC_LIBS) libpolypcore.la module_lirc_la_CFLAGS = $(AM_CFLAGS) $(LIRC_CFLAGS) # Linux evdev module_mmkbd_evdev_la_SOURCES = modules/module-mmkbd-evdev.c module_mmkbd_evdev_la_LDFLAGS = -module -avoid-version -module_mmkbd_evdev_la_LIBADD = $(AM_LIBADD) +module_mmkbd_evdev_la_LIBADD = $(AM_LIBADD) libpolypcore.la module_mmkbd_evdev_la_CFLAGS = $(AM_CFLAGS) # Windows waveout @@ -1073,12 +1074,12 @@ module_detect_la_CFLAGS = $(AM_CFLAGS) # RTP modules module_rtp_send_la_SOURCES = modules/rtp/module-rtp-send.c module_rtp_send_la_LDFLAGS = -module -avoid-version -module_rtp_send_la_LIBADD = $(AM_LIBADD) libpolypcore.la +module_rtp_send_la_LIBADD = $(AM_LIBADD) libpolypcore.la librtp.la module_rtp_send_la_CFLAGS = $(AM_CFLAGS) module_rtp_recv_la_SOURCES = modules/rtp/module-rtp-recv.c module_rtp_recv_la_LDFLAGS = -module -avoid-version -module_rtp_recv_la_LIBADD = $(AM_LIBADD) libpolypcore.la +module_rtp_recv_la_LIBADD = $(AM_LIBADD) libpolypcore.la librtp.la module_rtp_recv_la_CFLAGS = $(AM_CFLAGS) # JACK -- cgit From b4ac6d05d21742af2558acbdfebc83805750356f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 23 Apr 2006 19:42:58 +0000 Subject: allow recieving of invalid channel maps, volumes and sample specs. This makes handling of uninitialized data better, e.g. when sending info about lazy-load sample chache entries, where the channel mapping and sample spec is still unknown. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@782 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/tagstruct.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/polypcore/tagstruct.c b/src/polypcore/tagstruct.c index 761f6d3d..86b8368a 100644 --- a/src/polypcore/tagstruct.c +++ b/src/polypcore/tagstruct.c @@ -311,9 +311,6 @@ int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) { memcpy(&ss->rate, t->data+t->rindex+3, 4); ss->rate = ntohl(ss->rate); - if (!pa_sample_spec_valid(ss)) - return -1; - t->rindex += 7; return 0; } @@ -379,7 +376,6 @@ int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) { tv->tv_usec = ntohl(tv->tv_usec); t->rindex += 9; return 0; - } int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) { @@ -457,9 +453,6 @@ int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) { for (i = 0; i < map->channels; i ++) map->map[i] = (int8_t) t->data[t->rindex + 2 + i]; - if (!pa_channel_map_valid(map)) - return -1; - t->rindex += 2 + map->channels; return 0; } @@ -488,9 +481,6 @@ int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) { cvolume->values[i] = (pa_volume_t) ntohl(vol); } - if (!pa_cvolume_valid(cvolume)) - return -1; - t->rindex += 2 + cvolume->channels * sizeof(pa_volume_t); return 0; } -- cgit From 4e61ebb981b218637685d7edbf7faac89916a094 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 23 Apr 2006 19:46:16 +0000 Subject: fix multiplication of software pa_cvolumes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@783 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/volume.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polyp/volume.c b/src/polyp/volume.c index 0f153141..f10463c3 100644 --- a/src/polyp/volume.c +++ b/src/polyp/volume.c @@ -154,7 +154,7 @@ pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const assert(a); assert(b); - for (i = 0; i < a->channels || i < b->channels || i < PA_CHANNELS_MAX; i++) { + for (i = 0; i < a->channels && i < b->channels && i < PA_CHANNELS_MAX; i++) { dest->values[i] = pa_sw_volume_multiply( i < a->channels ? a->values[i] : PA_VOLUME_NORM, -- cgit From 335e23473fee2a6e40f838cd920ed13af3f93626 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 23 Apr 2006 19:49:01 +0000 Subject: * when playing back a sample from the sample cache, just take a pa_volume_t and not a pa_cvolume_t as argument for the volume. Usually it is not known to the player of theses samples how many channels it has, hence it doesn't make any sense to allow him to pass a by-channel volume structure here. * fix volume calculation when playing samples from the sample cache git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@784 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-x11-bell.c | 3 +-- src/polypcore/cli-command.c | 2 +- src/polypcore/core-scache.c | 17 ++++++++--------- src/polypcore/core-scache.h | 2 +- src/polypcore/protocol-esound.c | 2 +- src/polypcore/protocol-native.c | 8 ++++---- 6 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/modules/module-x11-bell.c b/src/modules/module-x11-bell.c index fe1711a5..e4d4020e 100644 --- a/src/modules/module-x11-bell.c +++ b/src/modules/module-x11-bell.c @@ -66,7 +66,6 @@ static const char* const valid_modargs[] = { static int ring_bell(struct userdata *u, int percent) { pa_sink *s; - pa_cvolume cv; assert(u); if (!(s = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) { @@ -74,7 +73,7 @@ static int ring_bell(struct userdata *u, int percent) { return -1; } - pa_scache_play_item(u->core, u->scache_item, s, pa_cvolume_set(&cv, PA_CHANNELS_MAX, (percent*PA_VOLUME_NORM)/100)); + pa_scache_play_item(u->core, u->scache_item, s, (percent*PA_VOLUME_NORM)/100); return 0; } diff --git a/src/polypcore/cli-command.c b/src/polypcore/cli-command.c index 0251ab0a..180c61e9 100644 --- a/src/polypcore/cli-command.c +++ b/src/polypcore/cli-command.c @@ -597,7 +597,7 @@ static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *bu return -1; } - if (pa_scache_play_item(c, n, sink, NULL) < 0) { + if (pa_scache_play_item(c, n, sink, PA_VOLUME_NORM) < 0) { pa_strbuf_puts(buf, "Failed to play sample.\n"); return -1; } diff --git a/src/polypcore/core-scache.c b/src/polypcore/core-scache.c index 6632a171..9c407623 100644 --- a/src/polypcore/core-scache.c +++ b/src/polypcore/core-scache.c @@ -122,7 +122,8 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { e->lazy = 0; e->last_used_time = 0; - memset(&e->sample_spec, 0, sizeof(pa_sample_spec)); + memset(&e->sample_spec, 0, sizeof(e->sample_spec)); + pa_channel_map_init(&e->channel_map); pa_cvolume_reset(&e->volume, PA_CHANNELS_MAX); return e; @@ -240,7 +241,7 @@ void pa_scache_free(pa_core *c) { c->mainloop->time_free(c->scache_auto_unload_event); } -int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, const pa_cvolume *volume) { +int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t volume) { pa_scache_entry *e; char *t; pa_cvolume r; @@ -257,7 +258,9 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, const pa_cv return -1; pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); - e->volume.channels = e->sample_spec.channels; + + if (e->volume.channels > e->sample_spec.channels) + e->volume.channels = e->sample_spec.channels; } if (!e->memchunk.memblock) @@ -265,12 +268,8 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, const pa_cv t = pa_sprintf_malloc("sample:%s", name); - if (volume) { - r = *volume; - r.channels = e->volume.channels; - pa_sw_cvolume_multiply(&r, &r, &e->volume); - } else - r = e->volume; + pa_cvolume_set(&r, e->volume.channels, volume); + pa_sw_cvolume_multiply(&r, &r, &e->volume); if (pa_play_memchunk(sink, t, &e->sample_spec, &e->channel_map, &e->memchunk, &r) < 0) { pa_xfree(t); diff --git a/src/polypcore/core-scache.h b/src/polypcore/core-scache.h index a383e50a..151d1761 100644 --- a/src/polypcore/core-scache.h +++ b/src/polypcore/core-scache.h @@ -49,7 +49,7 @@ int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, int pa_scache_add_directory_lazy(pa_core *c, const char *pathname); int pa_scache_remove_item(pa_core *c, const char *name); -int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, const pa_cvolume *cvolume); +int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t volume); void pa_scache_free(pa_core *c); const char *pa_scache_get_name_by_id(pa_core *c, uint32_t id); diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index e29c44c9..2c956a7e 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -742,7 +742,7 @@ static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t reque pa_sink *sink; if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) - if (pa_scache_play_item(c->protocol->core, name, sink, NULL) >= 0) + if (pa_scache_play_item(c->protocol->core, name, sink, PA_VOLUME_NORM) >= 0) ok = idx + 1; } else { assert(request == ESD_PROTO_SAMPLE_FREE); diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 3f1d5ca2..f8c2d166 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -57,7 +57,7 @@ #include "protocol-native.h" /* Kick a client if it doesn't authenticate within this time */ -#define AUTH_TIMEOUT 5 +#define AUTH_TIMEOUT 60 /* Don't accept more connection than this */ #define MAX_CONNECTIONS 10 @@ -1165,14 +1165,14 @@ static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; uint32_t sink_index; - pa_cvolume volume; + pa_volume_t volume; pa_sink *sink; const char *name, *sink_name; assert(c && t); if (pa_tagstruct_getu32(t, &sink_index) < 0 || pa_tagstruct_gets(t, &sink_name) < 0 || - pa_tagstruct_get_cvolume(t, &volume) < 0 || + pa_tagstruct_getu32(t, &volume) < 0 || pa_tagstruct_gets(t, &name) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1190,7 +1190,7 @@ static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); - if (pa_scache_play_item(c->protocol->core, name, sink, &volume) < 0) { + if (pa_scache_play_item(c->protocol->core, name, sink, volume) < 0) { pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; } -- cgit From 193fb122287256ff32e3761426207e2a3f224f3c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 23 Apr 2006 20:56:41 +0000 Subject: introduce a new error PA_ERR_TOOLARGE git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@785 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/def.h | 1 + src/polyp/error.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/polyp/def.h b/src/polyp/def.h index 517dd422..edada380 100644 --- a/src/polyp/def.h +++ b/src/polyp/def.h @@ -160,6 +160,7 @@ enum { PA_ERR_BADSTATE, /**< Bad state */ PA_ERR_NODATA, /**< No data */ PA_ERR_VERSION, /**< Incompatible protocol version \since 0.8 */ + PA_ERR_TOOLARGE, /**< Data too large \since 0.8.1 */ PA_ERR_MAX /**< Not really an error but the first invalid error code */ }; diff --git a/src/polyp/error.c b/src/polyp/error.c index 3f3e637f..e78d072e 100644 --- a/src/polyp/error.c +++ b/src/polyp/error.c @@ -49,6 +49,7 @@ static const char* const errortab[PA_ERR_MAX] = { [PA_ERR_BADSTATE] = "Bad state", [PA_ERR_NODATA] = "No data", [PA_ERR_VERSION] = "Incompatible protocol version", + [PA_ERR_TOOLARGE] = "Too large" }; const char*pa_strerror(int error) { -- cgit From cdba0527a8b33874816da339d06133ec7bc85918 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 23 Apr 2006 20:58:08 +0000 Subject: * fix ref counting of pa_stream: strictly refcount from context to stream and never vice versa to make sure that we never loose memory * don't hit an assert() in case of a timeout events git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@786 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/stream.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/polyp/stream.c b/src/polyp/stream.c index e400415c..f11ef493 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -195,9 +195,6 @@ void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { s->channel = 0; s->channel_valid = 0; - - /* We keep a ref as long as we're connected */ - pa_stream_unref(s); } if (s->state_callback) @@ -374,7 +371,6 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED pa_stream *s = userdata; assert(pd); - assert(t); assert(s); assert(s->state == PA_STREAM_CREATING); @@ -413,9 +409,6 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED s->channel_valid = 1; pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - /* We add an extra ref as long as we're connected (i.e. in the dynarray) */ - pa_stream_ref(s); - pa_stream_set_state(s, PA_STREAM_READY); if (s->direction != PA_STREAM_UPLOAD && -- cgit From e1ac42dd10e3085cdcc9ed9f0de60c8457c77701 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 23 Apr 2006 20:59:09 +0000 Subject: enforce maximum sample size in sample cache git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@787 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/core-scache.c | 3 +++ src/polypcore/core-scache.h | 2 ++ src/polypcore/pstream.c | 5 +++-- src/polypcore/sound-file.c | 7 +++---- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/polypcore/core-scache.c b/src/polypcore/core-scache.c index 9c407623..2e8d453c 100644 --- a/src/polypcore/core-scache.c +++ b/src/polypcore/core-scache.c @@ -133,6 +133,9 @@ int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, c pa_scache_entry *e; assert(c && name); + if (chunk->length > PA_SCACHE_ENTRY_SIZE_MAX) + return -1; + if (!(e = scache_add_item(c, name))) return -1; diff --git a/src/polypcore/core-scache.h b/src/polypcore/core-scache.h index 151d1761..9ca05f8f 100644 --- a/src/polypcore/core-scache.h +++ b/src/polypcore/core-scache.h @@ -26,6 +26,8 @@ #include #include +#define PA_SCACHE_ENTRY_SIZE_MAX (1024*1024*2) + typedef struct pa_scache_entry { pa_core *core; uint32_t index; diff --git a/src/polypcore/pstream.c b/src/polypcore/pstream.c index b93dca08..09bd1e27 100644 --- a/src/polypcore/pstream.c +++ b/src/polypcore/pstream.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "pstream.h" @@ -52,7 +53,7 @@ enum { typedef uint32_t pa_pstream_descriptor[PA_PSTREAM_DESCRIPTOR_MAX]; #define PA_PSTREAM_DESCRIPTOR_SIZE (PA_PSTREAM_DESCRIPTOR_MAX*sizeof(uint32_t)) -#define FRAME_SIZE_MAX (1024*500) /* half a megabyte */ +#define FRAME_SIZE_MAX PA_SCACHE_ENTRY_SIZE_MAX /* allow uploading a single sample in one frame at max */ struct item_info { enum { PA_PSTREAM_ITEM_PACKET, PA_PSTREAM_ITEM_MEMBLOCK } type; @@ -419,7 +420,7 @@ static int do_read(pa_pstream *p) { /* Frame size too large */ if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) > FRAME_SIZE_MAX) { - pa_log_warn(__FILE__": Frame size too large"); + pa_log_warn(__FILE__": Frame size too large: %lu > %lu", (unsigned long) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]), (unsigned long) FRAME_SIZE_MAX); return -1; } diff --git a/src/polypcore/sound-file.c b/src/polypcore/sound-file.c index 7a4ef075..a6ccb064 100644 --- a/src/polypcore/sound-file.c +++ b/src/polypcore/sound-file.c @@ -32,8 +32,7 @@ #include #include "sound-file.h" - -#define MAX_FILE_SIZE (1024*1024) +#include "core-scache.h" int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_channel_map *map, pa_memchunk *chunk, pa_memblock_stat *s) { SNDFILE*sf = NULL; @@ -78,7 +77,7 @@ int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_channel_map *ma if (map) pa_channel_map_init_auto(map, ss->channels); - if ((l = pa_frame_size(ss)*sfinfo.frames) > MAX_FILE_SIZE) { + if ((l = pa_frame_size(ss)*sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) { pa_log(__FILE__": File too large"); goto finish; } @@ -134,7 +133,7 @@ int pa_sound_file_too_big_to_cache(const char *fname) { ss.rate = sfinfo.samplerate; ss.channels = sfinfo.channels; - if ((pa_frame_size(&ss) * sfinfo.frames) > MAX_FILE_SIZE) { + if ((pa_frame_size(&ss) * sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) { pa_log(__FILE__": File too large %s", fname); return 1; } -- cgit From 9b52ac4b47f468ad79ef91e337fe727b58ac26ce Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 23 Apr 2006 20:59:31 +0000 Subject: fix sample uploading git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@788 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/scache.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/polyp/scache.c b/src/polyp/scache.c index 891798fb..2b9e9c8f 100644 --- a/src/polyp/scache.c +++ b/src/polyp/scache.c @@ -41,7 +41,7 @@ int pa_stream_connect_upload(pa_stream *s, size_t length) { assert(s); PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, length <= 0, PA_ERR_INVALID); + PA_CHECK_VALIDITY(s->context, length > 0, PA_ERR_INVALID); pa_stream_ref(s); @@ -50,6 +50,7 @@ int pa_stream_connect_upload(pa_stream *s, size_t length) { t = pa_tagstruct_command(s->context, PA_COMMAND_CREATE_UPLOAD_STREAM, &tag); pa_tagstruct_puts(t, s->name); pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_put_channel_map(t, &s->channel_map); pa_tagstruct_putu32(t, length); pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s); -- cgit From 286310a563ad52105676243326b6ec2c34d945c5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 23 Apr 2006 20:59:43 +0000 Subject: small optimization git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@789 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/context.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/polyp/context.c b/src/polyp/context.c index ff224547..1e78f97f 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -784,18 +784,15 @@ static void set_dispatch_callbacks(pa_operation *o) { done = 0; } - if (!done) - pa_operation_ref(o); - else { + if (done) { if (o->callback) { pa_context_notify_cb_t cb = (pa_context_notify_cb_t) o->callback; cb(o->context, o->userdata); } pa_operation_done(o); - } - - pa_operation_unref(o); + pa_operation_unref(o); + } } pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) { -- cgit From 3590ee7581df02152cb2924509752565cd1e3dea Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 23 Apr 2006 21:01:44 +0000 Subject: * add validity checking for sample_spec, channel_map and cvolume structures * return PA_ERR_TOOLARGE when the user tries to upload a over-sized sample * notify the user if uploading a simple faield due to some reason git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@790 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-native.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index f8c2d166..ace9db6f 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -732,6 +732,9 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, name, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, sink_index != PA_INVALID_INDEX || !sink_name || *sink_name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); @@ -827,6 +830,8 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, source_index != PA_INVALID_INDEX || !source_name || *source_name, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); @@ -1126,7 +1131,11 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE); CHECK_VALIDITY(c->pstream, name && *name, tag, PA_ERR_INVALID); s = upload_stream_new(c, &ss, &map, name, length); @@ -1157,8 +1166,11 @@ static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); CHECK_VALIDITY(c->pstream, s->type == UPLOAD_STREAM, tag, PA_ERR_NOENTITY); - pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, &idx); - pa_pstream_send_simple_ack(c->pstream, tag); + if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, &idx) < 0) + pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL); + else + pa_pstream_send_simple_ack(c->pstream, tag); + upload_stream_free(s); } @@ -1553,6 +1565,7 @@ static void command_set_volume( CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || *name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID); if (command == PA_COMMAND_SET_SINK_VOLUME) { if (idx != PA_INVALID_INDEX) -- cgit From b92344f3ec2e678c497397074cc1693e9098c0f1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 23 Apr 2006 21:25:27 +0000 Subject: fix a segfault when uploading samples with esound git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@791 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/core-scache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polypcore/core-scache.c b/src/polypcore/core-scache.c index 2e8d453c..82c61a1d 100644 --- a/src/polypcore/core-scache.c +++ b/src/polypcore/core-scache.c @@ -133,7 +133,7 @@ int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, c pa_scache_entry *e; assert(c && name); - if (chunk->length > PA_SCACHE_ENTRY_SIZE_MAX) + if (chunk && chunk->length > PA_SCACHE_ENTRY_SIZE_MAX) return -1; if (!(e = scache_add_item(c, name))) -- cgit From fade8b0883cc5a22a00e8fd9c1358d9628923355 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 24 Apr 2006 13:59:00 +0000 Subject: Undo invalid automake version requirement. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@792 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index d73a6929..d6239f97 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ AC_PREREQ(2.57) AC_INIT([polypaudio],[0.8],[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([src/daemon/main.c]) AC_CONFIG_HEADERS([config.h]) -AM_INIT_AUTOMAKE([foreign 1.9 -Wall]) +AM_INIT_AUTOMAKE([foreign -Wall]) AC_SUBST(PA_MAJORMINOR, "$PACKAGE_VERSION") AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/polypaudio/]) -- cgit From d26621371e6bf5040fe833f046ff81a1c7cac94b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 24 Apr 2006 15:07:09 +0000 Subject: chown() and chmod() aren't available on Windows. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@793 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 4 ++-- src/polypcore/util.c | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index d6239f97..87dc2aab 100644 --- a/configure.ac +++ b/configure.ac @@ -219,8 +219,8 @@ AC_CHECK_FUNCS([getopt_long], [], [AC_CHECK_LIB([iberty], [getopt_long])]) AC_FUNC_FORK AC_FUNC_GETGROUPS AC_FUNC_SELECT_ARGTYPES -AC_CHECK_FUNCS([getaddrinfo getgrgid_r getpwuid_r gettimeofday getuid \ - inet_ntop inet_pton nanosleep setpgid setsid sigaction sleep]) +AC_CHECK_FUNCS([chmod chown getaddrinfo getgrgid_r getpwuid_r gettimeofday \ + getuid inet_ntop inet_pton nanosleep setpgid setsid sigaction sleep]) AC_CHECK_FUNCS([mkfifo], [HAVE_MKFIFO=1], [HAVE_MKFIFO=0]) AM_CONDITIONAL(HAVE_MKFIFO, test "x$HAVE_MKFIFO" = "x1") diff --git a/src/polypcore/util.c b/src/polypcore/util.c index 615ea881..191fa809 100644 --- a/src/polypcore/util.c +++ b/src/polypcore/util.c @@ -140,8 +140,12 @@ int pa_make_secure_dir(const char* dir) { if (errno != EEXIST) return -1; +#ifdef HAVE_CHOWN chown(dir, getuid(), getgid()); +#endif +#ifdef HAVE_CHMOD chmod(dir, 0700); +#endif #ifdef HAVE_LSTAT if (lstat(dir, &st) < 0) -- cgit From 820c118f9c57c7a7767765efc802502632ad8da2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 24 Apr 2006 19:29:15 +0000 Subject: * rework reference counting in the client libraries: now refcounting goes strictly "one-way" - the "bigger" object refcounts the "smaller" one, never the other way round. * when registering for a reply packet in pdispatch, specify a function that is called when the pdispatch object is destroyed but the reply hasn't yet been recieved. * move prototype of pa_free_cb from stream.h to def.h git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@794 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 8 ++-- src/polyp/context.c | 28 +++++++------ src/polyp/def.h | 3 ++ src/polyp/internal.h | 1 + src/polyp/introspect.c | 98 +++++++++++++++++++++++++++------------------ src/polyp/operation.c | 55 +++++++++++++++---------- src/polyp/scache.c | 8 ++-- src/polyp/stream.c | 72 ++++++++++++++++++++------------- src/polyp/stream.h | 3 -- src/polyp/subscribe.c | 2 +- src/polypcore/pdispatch.c | 10 ++++- src/polypcore/pdispatch.h | 3 +- 12 files changed, 175 insertions(+), 116 deletions(-) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index b68bc485..abfa68a4 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -356,7 +356,7 @@ static void request_latency(struct userdata *u) { pa_tagstruct_put_timeval(t, &now); pa_pstream_send_tagstruct(u->pstream, t); - pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u, NULL); } static void stream_get_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -449,7 +449,7 @@ static void request_info(struct userdata *u) { #endif pa_pstream_send_tagstruct(u->pstream, t); - pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_info_callback, u); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_info_callback, u, NULL); } static void start_subscribe(struct userdata *u) { @@ -580,7 +580,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t #endif pa_pstream_send_tagstruct(u->pstream, reply); - pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, u); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, u, NULL); } static void pstream_die_callback(pa_pstream *p, void *userdata) { @@ -647,7 +647,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION); pa_tagstruct_put_arbitrary(t, u->auth_cookie, sizeof(u->auth_cookie)); pa_pstream_send_tagstruct(u->pstream, t); - pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, u); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, u, NULL); } diff --git a/src/polyp/context.c b/src/polyp/context.c index 1e78f97f..c9a65847 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -162,7 +162,7 @@ static void context_free(pa_context *c) { while (c->streams) pa_stream_set_state(c->streams, PA_STREAM_TERMINATED); - + if (c->client) pa_socket_client_unref(c->client); if (c->pdispatch) @@ -218,6 +218,10 @@ void pa_context_set_state(pa_context *c, pa_context_state_t st) { pa_context_ref(c); + c->state = st; + if (c->state_callback) + c->state_callback(c, c->state_userdata); + if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) { pa_stream *s; @@ -244,10 +248,6 @@ void pa_context_set_state(pa_context *c, pa_context_state_t st) { c->client = NULL; } - c->state = st; - if (c->state_callback) - c->state_callback(c, c->state_userdata); - pa_context_unref(c); } @@ -383,7 +383,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t reply = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag); pa_tagstruct_puts(reply, c->name); pa_pstream_send_tagstruct(c->pstream, reply); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL); pa_context_set_state(c, PA_CONTEXT_SETTING_NAME); break; @@ -429,7 +429,7 @@ static void setup_context(pa_context *c, pa_iochannel *io) { pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION); pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie)); pa_pstream_send_tagstruct_with_creds(c->pstream, t, 1); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL); pa_context_set_state(c, PA_CONTEXT_AUTHORIZING); @@ -817,7 +817,9 @@ void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_U assert(pd); assert(o); assert(o->ref >= 1); - assert(o->context); + + if (!o->context) + goto finish; if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) @@ -853,7 +855,7 @@ pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, t = pa_tagstruct_command(c, PA_COMMAND_EXIT, &tag); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -872,7 +874,7 @@ pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, pa t = pa_tagstruct_command(c, command, &tag); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_cb, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -892,7 +894,7 @@ pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_co t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SINK, &tag); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -912,7 +914,7 @@ pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_ t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SOURCE, &tag); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -939,7 +941,7 @@ pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_su t = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } diff --git a/src/polyp/def.h b/src/polyp/def.h index edada380..57997163 100644 --- a/src/polyp/def.h +++ b/src/polyp/def.h @@ -304,6 +304,9 @@ typedef enum pa_source_flags { PA_SOURCE_LATENCY = 2 /**< Supports latency querying */ } pa_source_flags_t; +/** A generic free() like callback prototype */ +typedef void (*pa_free_cb_t)(void *p); + PA_C_DECL_END #endif diff --git a/src/polyp/internal.h b/src/polyp/internal.h index 2bec0294..f41744ef 100644 --- a/src/polyp/internal.h +++ b/src/polyp/internal.h @@ -159,6 +159,7 @@ struct pa_operation { int ref; pa_context *context; pa_stream *stream; + PA_LLIST_FIELDS(pa_operation); pa_operation_state_t state; diff --git a/src/polyp/introspect.c b/src/polyp/introspect.c index ea6133e1..9d002669 100644 --- a/src/polyp/introspect.c +++ b/src/polyp/introspect.c @@ -43,7 +43,9 @@ static void context_stat_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNU assert(pd); assert(o); assert(o->ref >= 1); - assert(o->context); + + if (!o->context) + goto finish; if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) @@ -83,7 +85,9 @@ static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command, assert(pd); assert(o); assert(o->ref >= 1); - assert(o->context); + + if (!o->context) + goto finish; if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) @@ -127,8 +131,10 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P assert(pd); assert(o); assert(o->ref >= 1); - assert(o->context); + if (!o->context) + goto finish; + if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; @@ -198,7 +204,7 @@ pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, pa_ pa_tagstruct_putu32(t, idx); pa_tagstruct_puts(t, NULL); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -221,7 +227,7 @@ pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -235,7 +241,9 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, assert(pd); assert(o); assert(o->ref >= 1); - assert(o->context); + + if (!o->context) + goto finish; if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) @@ -306,7 +314,7 @@ pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, p pa_tagstruct_putu32(t, idx); pa_tagstruct_puts(t, NULL); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -329,9 +337,9 @@ pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, o); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - return pa_operation_ref(o); + return o; } /*** Client info ***/ @@ -343,7 +351,9 @@ static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, assert(pd); assert(o); assert(o->ref >= 1); - assert(o->context); + + if (!o->context) + goto finish; if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) @@ -397,7 +407,7 @@ pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, pa_client_ t = pa_tagstruct_command(c, PA_COMMAND_GET_CLIENT_INFO, &tag); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -415,7 +425,9 @@ static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command, assert(pd); assert(o); assert(o->ref >= 1); - assert(o->context); + + if (!o->context) + goto finish; if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) @@ -470,7 +482,7 @@ pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_ t = pa_tagstruct_command(c, PA_COMMAND_GET_MODULE_INFO, &tag); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -488,8 +500,10 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm assert(pd); assert(o); assert(o->ref >= 1); - assert(o->context); + if (!o->context) + goto finish; + if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; @@ -551,7 +565,7 @@ pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sin t = pa_tagstruct_command(c, PA_COMMAND_GET_SINK_INPUT_INFO, &tag); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_input_info_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_input_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -569,7 +583,9 @@ static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t c assert(pd); assert(o); assert(o->ref >= 1); - assert(o->context); + + if (!o->context) + goto finish; if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) @@ -631,7 +647,7 @@ pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, pa_ t = pa_tagstruct_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO, &tag); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_output_info_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_output_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -661,7 +677,7 @@ pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, c pa_tagstruct_puts(t, NULL); pa_tagstruct_put_cvolume(t, volume); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -687,7 +703,7 @@ pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name pa_tagstruct_puts(t, name); pa_tagstruct_put_cvolume(t, volume); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -709,7 +725,7 @@ pa_operation* pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int pa_tagstruct_puts(t, NULL); pa_tagstruct_put_boolean(t, mute); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -733,7 +749,7 @@ pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name, pa_tagstruct_puts(t, name); pa_tagstruct_put_boolean(t, mute); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -757,7 +773,7 @@ pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, cons pa_tagstruct_putu32(t, idx); pa_tagstruct_put_cvolume(t, volume); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -781,7 +797,7 @@ pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, pa_tagstruct_puts(t, NULL); pa_tagstruct_put_cvolume(t, volume); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -807,7 +823,7 @@ pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *na pa_tagstruct_puts(t, name); pa_tagstruct_put_cvolume(t, volume); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -829,7 +845,7 @@ pa_operation* pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, i pa_tagstruct_puts(t, NULL); pa_tagstruct_put_boolean(t, mute); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -853,7 +869,7 @@ pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name pa_tagstruct_puts(t, name); pa_tagstruct_put_boolean(t, mute); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -867,8 +883,10 @@ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, assert(pd); assert(o); assert(o->ref >= 1); - assert(o->context); + if (!o->context) + goto finish; + if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; @@ -928,7 +946,7 @@ pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -951,7 +969,7 @@ pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, p pa_tagstruct_putu32(t, idx); pa_tagstruct_puts(t, NULL); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -976,7 +994,7 @@ static pa_operation* command_kill(pa_context *c, uint32_t command, uint32_t idx, t = pa_tagstruct_command(c, command, &tag); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -1000,7 +1018,9 @@ static void context_index_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN assert(pd); assert(o); assert(o->ref >= 1); - assert(o->context); + + if (!o->context) + goto finish; if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) @@ -1041,7 +1061,7 @@ pa_operation* pa_context_load_module(pa_context *c, const char*name, const char pa_tagstruct_puts(t, name); pa_tagstruct_puts(t, argument); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_index_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_index_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -1059,7 +1079,9 @@ static void context_get_autoload_info_callback(pa_pdispatch *pd, uint32_t comman assert(pd); assert(o); assert(o->ref >= 1); - assert(o->context); + + if (!o->context) + goto finish; if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) @@ -1116,7 +1138,7 @@ pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *na pa_tagstruct_puts(t, name); pa_tagstruct_putu32(t, type); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -1138,7 +1160,7 @@ pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, t = pa_tagstruct_command(c, PA_COMMAND_GET_AUTOLOAD_INFO, &tag); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -1168,7 +1190,7 @@ pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autolo pa_tagstruct_puts(t, module); pa_tagstruct_puts(t, argument); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_index_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_index_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -1191,7 +1213,7 @@ pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name pa_tagstruct_puts(t, name); pa_tagstruct_putu32(t, type); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -1212,7 +1234,7 @@ pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, p t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_AUTOLOAD, &tag); pa_tagstruct_putu32(t, idx); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } diff --git a/src/polyp/operation.c b/src/polyp/operation.c index 0216888c..1c0cb99f 100644 --- a/src/polyp/operation.c +++ b/src/polyp/operation.c @@ -28,78 +28,89 @@ #include #include "internal.h" - #include "operation.h" pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t cb, void *userdata) { pa_operation *o; assert(c); - o = pa_xmalloc(sizeof(pa_operation)); + o = pa_xnew(pa_operation, 1); o->ref = 1; - o->context = pa_context_ref(c); - o->stream = s ? pa_stream_ref(s) : NULL; + o->context = c; + o->stream = s; o->state = PA_OPERATION_RUNNING; o->callback = cb; o->userdata = userdata; - PA_LLIST_PREPEND(pa_operation, o->context->operations, o); - return pa_operation_ref(o); + /* Refcounting is strictly one-way: from the "bigger" to the "smaller" object. */ + PA_LLIST_PREPEND(pa_operation, c->operations, o); + pa_operation_ref(o); + + return o; } pa_operation *pa_operation_ref(pa_operation *o) { - assert(o && o->ref >= 1); + assert(o); + assert(o->ref >= 1); + o->ref++; return o; } void pa_operation_unref(pa_operation *o) { - assert(o && o->ref >= 1); + assert(o); + assert(o->ref >= 1); if ((--(o->ref)) == 0) { assert(!o->context); assert(!o->stream); - free(o); + pa_xfree(o); } } static void operation_set_state(pa_operation *o, pa_operation_state_t st) { - assert(o && o->ref >= 1); + assert(o); + assert(o->ref >= 1); if (st == o->state) return; - if (!o->context) - return; - o->state = st; if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) { - PA_LLIST_REMOVE(pa_operation, o->context->operations, o); - pa_context_unref(o->context); - if (o->stream) - pa_stream_unref(o->stream); + + if (o->context) { + assert(o->ref >= 2); + + PA_LLIST_REMOVE(pa_operation, o->context->operations, o); + pa_operation_unref(o); + } + o->context = NULL; o->stream = NULL; o->callback = NULL; o->userdata = NULL; - - pa_operation_unref(o); } } void pa_operation_cancel(pa_operation *o) { - assert(o && o->ref >= 1); + assert(o); + assert(o->ref >= 1); + operation_set_state(o, PA_OPERATION_CANCELED); } void pa_operation_done(pa_operation *o) { - assert(o && o->ref >= 1); + assert(o); + assert(o->ref >= 1); + operation_set_state(o, PA_OPERATION_DONE); } pa_operation_state_t pa_operation_get_state(pa_operation *o) { - assert(o && o->ref >= 1); + assert(o); + assert(o->ref >= 1); + return o->state; } diff --git a/src/polyp/scache.c b/src/polyp/scache.c index 2b9e9c8f..22d8a545 100644 --- a/src/polyp/scache.c +++ b/src/polyp/scache.c @@ -53,7 +53,7 @@ int pa_stream_connect_upload(pa_stream *s, size_t length) { pa_tagstruct_put_channel_map(t, &s->channel_map); pa_tagstruct_putu32(t, length); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL); pa_stream_set_state(s, PA_STREAM_CREATING); @@ -74,7 +74,7 @@ int pa_stream_finish_upload(pa_stream *s) { t = pa_tagstruct_command(s->context, PA_COMMAND_FINISH_UPLOAD_STREAM, &tag); pa_tagstruct_putu32(t, s->channel); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s, NULL); pa_stream_unref(s); return 0; @@ -103,7 +103,7 @@ pa_operation *pa_context_play_sample(pa_context *c, const char *name, const char pa_tagstruct_putu32(t, volume); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } @@ -124,7 +124,7 @@ pa_operation* pa_context_remove_sample(pa_context *c, const char *name, pa_conte t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_SAMPLE, &tag); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } diff --git a/src/polyp/stream.c b/src/polyp/stream.c index f11ef493..c86a200a 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -106,21 +106,15 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->auto_timing_update_event = NULL; s->auto_timing_update_requested = 0; + /* Refcounting is strictly one-way: from the "bigger" to the "smaller" object. */ PA_LLIST_PREPEND(pa_stream, c->streams, s); - - /* The context and stream will point at each other. We cannot ref count - both though since that will create a loop. */ - pa_context_ref(s->context); + pa_stream_ref(s); return s; } static void stream_free(pa_stream *s) { - assert(s && s->context && !s->channel_valid); - - PA_LLIST_REMOVE(pa_stream, s->context->streams, s); - - pa_context_unref(s->context); + assert(s && !s->context && !s->channel_valid); if (s->auto_timing_update_event) { assert(s->mainloop); @@ -186,20 +180,38 @@ void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { pa_stream_ref(s); s->state = st; - + if (s->state_callback) + s->state_callback(s, s->state_userdata); + if ((st == PA_STREAM_FAILED || st == PA_STREAM_TERMINATED) && s->context) { + /* Detach from context */ + pa_operation *o, *n; + + /* Unref all operatio object that point to us */ + for (o = s->context->operations; o; o = n) { + n = o->next; + + if (o->stream == s) + pa_operation_cancel(o); + } + /* Drop all outstanding replies for this stream */ + if (s->context->pdispatch) + pa_pdispatch_unregister_reply(s->context->pdispatch, s); + if (s->channel_valid) pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); + + PA_LLIST_REMOVE(pa_stream, s->context->streams, s); + pa_stream_unref(s); s->channel = 0; s->channel_valid = 0; + + s->context = NULL; } - if (s->state_callback) - s->state_callback(s, s->state_userdata); - pa_stream_unref(s); } @@ -513,7 +525,7 @@ static int create_stream( pa_tagstruct_putu32(t, s->buffer_attr.fragsize); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL); pa_stream_set_state(s, PA_STREAM_CREATING); @@ -704,9 +716,9 @@ pa_operation * pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *us t = pa_tagstruct_command(s->context, PA_COMMAND_DRAIN_PLAYBACK_STREAM, &tag); pa_tagstruct_putu32(t, s->channel); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - return pa_operation_ref(o); + return o; } static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -717,7 +729,9 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, assert(pd); assert(o); assert(o->stream); - assert(o->context); + + if (!o->context) + goto finish; i = &o->stream->timing_info; @@ -869,7 +883,7 @@ pa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t /* Check if we could allocate a correction slot. If not, there are too many outstanding queries */ PA_CHECK_VALIDITY_RETURN_NULL(s->context, !s->write_index_corrections[cidx].valid, PA_ERR_INTERNAL); } - o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_command( s->context, @@ -879,7 +893,7 @@ pa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t pa_tagstruct_put_timeval(t, pa_gettimeofday(&now)); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_timing_info_callback, o); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_timing_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); if (s->direction == PA_STREAM_PLAYBACK) { /* Fill in initial correction data */ @@ -893,7 +907,7 @@ pa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t /* pa_log("requesting update %u\n", tag); */ - return pa_operation_ref(o); + return o; } void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -941,7 +955,7 @@ int pa_stream_disconnect(pa_stream *s) { &tag); pa_tagstruct_putu32(t, s->channel); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s, NULL); pa_stream_unref(s); return 0; @@ -993,9 +1007,11 @@ void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN assert(pd); assert(o); - assert(o->context); assert(o->ref >= 1); + if (!o->context) + goto finish; + if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; @@ -1038,12 +1054,12 @@ pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, voi pa_tagstruct_putu32(t, s->channel); pa_tagstruct_put_boolean(t, !!b); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); if (s->direction == PA_STREAM_PLAYBACK) invalidate_indexes(s, 1, 0); - return pa_operation_ref(o); + return o; } static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, pa_stream_success_cb_t cb, void *userdata) { @@ -1061,9 +1077,9 @@ static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, t = pa_tagstruct_command(s->context, command, &tag); pa_tagstruct_putu32(t, s->channel); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - return pa_operation_ref(o); + return o; } pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { @@ -1136,9 +1152,9 @@ pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_succe pa_tagstruct_putu32(t, s->channel); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - return pa_operation_ref(o); + return o; } int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) { diff --git a/src/polyp/stream.h b/src/polyp/stream.h index a832fc66..b6522efe 100644 --- a/src/polyp/stream.h +++ b/src/polyp/stream.h @@ -267,9 +267,6 @@ typedef struct pa_stream pa_stream; /** A generic callback for operation completion */ typedef void (*pa_stream_success_cb_t) (pa_stream*s, int success, void *userdata); -/** A generic free callback */ -typedef void (*pa_free_cb_t)(void *p); - /** A generic request callback */ typedef void (*pa_stream_request_cb_t)(pa_stream *p, size_t length, void *userdata); diff --git a/src/polyp/subscribe.c b/src/polyp/subscribe.c index 110d4e52..21f5f7a5 100644 --- a/src/polyp/subscribe.c +++ b/src/polyp/subscribe.c @@ -75,7 +75,7 @@ pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_c t = pa_tagstruct_command(c, PA_COMMAND_SUBSCRIBE, &tag); pa_tagstruct_putu32(t, m); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o)); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; } diff --git a/src/polypcore/pdispatch.c b/src/polypcore/pdispatch.c index a4e58f8c..b087f1a5 100644 --- a/src/polypcore/pdispatch.c +++ b/src/polypcore/pdispatch.c @@ -97,6 +97,7 @@ struct reply_info { PA_LLIST_FIELDS(struct reply_info); pa_pdispatch_cb_t callback; void *userdata; + pa_free_cb_t free_cb; uint32_t tag; pa_time_event *time_event; }; @@ -145,8 +146,12 @@ pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_cb_ static void pdispatch_free(pa_pdispatch *pd) { assert(pd); - while (pd->replies) + while (pd->replies) { + if (pd->replies->free_cb) + pd->replies->free_cb(pd->replies->userdata); + reply_info_free(pd->replies); + } pa_xfree(pd); } @@ -243,7 +248,7 @@ static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, PA_GCC_UNUSED c run_action(r->pdispatch, r, PA_COMMAND_TIMEOUT, NULL); } -void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t cb, void *userdata) { +void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t cb, void *userdata, pa_free_cb_t free_cb) { struct reply_info *r; struct timeval tv; assert(pd && pd->ref >= 1 && cb); @@ -252,6 +257,7 @@ void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa r->pdispatch = pd; r->callback = cb; r->userdata = userdata; + r->free_cb = free_cb; r->tag = tag; pa_gettimeofday(&tv); diff --git a/src/polypcore/pdispatch.h b/src/polypcore/pdispatch.h index aa898abf..0074e8b3 100644 --- a/src/polypcore/pdispatch.h +++ b/src/polypcore/pdispatch.h @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -38,7 +39,7 @@ pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd); int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*p, const void*creds, void *userdata); -void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t callback, void *userdata); +void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t callback, void *userdata, pa_free_cb_t free_cb); int pa_pdispatch_is_pending(pa_pdispatch *pd); -- cgit From f426b58e5c1c584aba8fd37fe7f2e523410b78bc Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 25 Apr 2006 07:13:44 +0000 Subject: glibc <= 2.2 has a broken unistd.h, lacking setresuid(). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@795 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/caps.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/daemon/caps.c b/src/daemon/caps.c index 5c52b77a..8740b7e8 100644 --- a/src/daemon/caps.c +++ b/src/daemon/caps.c @@ -36,6 +36,12 @@ #include "caps.h" +/* Glibc <= 2.2 has broken unistd.h */ +#if defined(linux) && (__GLIBC__ <= 2 && __GLIBC_MINOR__ <= 2) +int setresgid(gid_t r, gid_t e, gid_t s); +int setresuid(uid_t r, uid_t e, uid_t s); +#endif + #ifdef HAVE_GETUID /* Drop root rights when called SUID root */ -- cgit From 69096f27531381b57fa73dc8e85c812089915031 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 25 Apr 2006 07:54:49 +0000 Subject: Fall back to software volume if hardware mixer cannot control all channels. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@796 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-sink.c | 64 +++++++++++++++++----------------------- src/modules/module-alsa-source.c | 62 ++++++++++++++++---------------------- 2 files changed, 53 insertions(+), 73 deletions(-) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index e2e593da..ecdf8cb0 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -201,25 +201,18 @@ static int sink_get_hw_volume_cb(pa_sink *s) { struct userdata *u = s->userdata; long vol; int err; + int i; assert(u && u->mixer_elem); - if (snd_mixer_selem_has_playback_volume_joined(u->mixer_elem)) { - err = snd_mixer_selem_get_playback_volume(u->mixer_elem, 0, &vol); + for (i = 0;i < s->hw_volume.channels;i++) { + assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, i)); + + err = snd_mixer_selem_get_playback_volume(u->mixer_elem, i, &vol); if (err < 0) goto fail; - pa_cvolume_set(&s->hw_volume, s->hw_volume.channels, - (vol - u->hw_volume_min) * PA_VOLUME_NORM / (u->hw_volume_max - u->hw_volume_min)); - } else { - int i; - - for (i = 0;i < s->hw_volume.channels;i++) { - err = snd_mixer_selem_get_playback_volume(u->mixer_elem, i, &vol); - if (err < 0) - goto fail; - s->hw_volume.values[i] = - (vol - u->hw_volume_min) * PA_VOLUME_NORM / (u->hw_volume_max - u->hw_volume_min); - } + s->hw_volume.values[i] = + (vol - u->hw_volume_min) * PA_VOLUME_NORM / (u->hw_volume_max - u->hw_volume_min); } return 0; @@ -234,37 +227,25 @@ fail: static int sink_set_hw_volume_cb(pa_sink *s) { struct userdata *u = s->userdata; int err; + int i; pa_volume_t vol; assert(u && u->mixer_elem); - if (snd_mixer_selem_has_playback_volume_joined(u->mixer_elem)) { - vol = pa_cvolume_avg(&s->hw_volume); + for (i = 0;i < s->hw_volume.channels;i++) { + assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, i)); + + vol = s->hw_volume.values[i]; if (vol > PA_VOLUME_NORM) vol = PA_VOLUME_NORM; vol = (vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM + u->hw_volume_min; - - err = snd_mixer_selem_set_playback_volume_all(u->mixer_elem, vol); + + err = snd_mixer_selem_set_playback_volume(u->mixer_elem, i, vol); if (err < 0) goto fail; - } else { - int i; - - for (i = 0;i < s->hw_volume.channels;i++) { - vol = s->hw_volume.values[i]; - - if (vol > PA_VOLUME_NORM) - vol = PA_VOLUME_NORM; - - vol = (vol * (u->hw_volume_max - u->hw_volume_min)) / - PA_VOLUME_NORM + u->hw_volume_min; - err = snd_mixer_selem_set_playback_volume(u->mixer_elem, i, vol); - if (err < 0) - goto fail; - } } return 0; @@ -383,10 +364,19 @@ int pa__init(pa_core *c, pa_module*m) { if (u->mixer_handle) { assert(u->mixer_elem); if (snd_mixer_selem_has_playback_volume(u->mixer_elem)) { - u->sink->get_hw_volume = sink_get_hw_volume_cb; - u->sink->set_hw_volume = sink_set_hw_volume_cb; - snd_mixer_selem_get_playback_volume_range( - u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max); + int i; + + for (i = 0;i < ss.channels;i++) { + if (!snd_mixer_selem_has_playback_channel(u->mixer_elem, i)) + break; + } + + if (i == ss.channels) { + u->sink->get_hw_volume = sink_get_hw_volume_cb; + u->sink->set_hw_volume = sink_set_hw_volume_cb; + snd_mixer_selem_get_playback_volume_range( + u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max); + } } if (snd_mixer_selem_has_playback_switch(u->mixer_elem)) { u->sink->get_hw_mute = sink_get_hw_mute_cb; diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 2ee16190..7a365286 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -190,25 +190,18 @@ static int source_get_hw_volume_cb(pa_source *s) { struct userdata *u = s->userdata; long vol; int err; + int i; assert(u && u->mixer_elem); - if (snd_mixer_selem_has_capture_volume_joined(u->mixer_elem)) { - err = snd_mixer_selem_get_capture_volume(u->mixer_elem, 0, &vol); + for (i = 0;i < s->hw_volume.channels;i++) { + assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); + + err = snd_mixer_selem_get_capture_volume(u->mixer_elem, i, &vol); if (err < 0) goto fail; - pa_cvolume_set(&s->hw_volume, s->hw_volume.channels, - (vol - u->hw_volume_min) * PA_VOLUME_NORM / (u->hw_volume_max - u->hw_volume_min)); - } else { - int i; - - for (i = 0;i < s->hw_volume.channels;i++) { - err = snd_mixer_selem_get_capture_volume(u->mixer_elem, i, &vol); - if (err < 0) - goto fail; - s->hw_volume.values[i] = - (vol - u->hw_volume_min) * PA_VOLUME_NORM / (u->hw_volume_max - u->hw_volume_min); - } + s->hw_volume.values[i] = + (vol - u->hw_volume_min) * PA_VOLUME_NORM / (u->hw_volume_max - u->hw_volume_min); } return 0; @@ -224,35 +217,23 @@ static int source_set_hw_volume_cb(pa_source *s) { struct userdata *u = s->userdata; int err; pa_volume_t vol; + int i; assert(u && u->mixer_elem); - if (snd_mixer_selem_has_capture_volume_joined(u->mixer_elem)) { - vol = pa_cvolume_avg(&s->hw_volume); + for (i = 0;i < s->hw_volume.channels;i++) { + assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); + + vol = s->hw_volume.values[i]; if (vol > PA_VOLUME_NORM) vol = PA_VOLUME_NORM; vol = vol * (u->hw_volume_max - u->hw_volume_min) / PA_VOLUME_NORM + u->hw_volume_min; - err = snd_mixer_selem_set_capture_volume_all(u->mixer_elem, vol); + err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, vol); if (err < 0) goto fail; - } else { - int i; - - for (i = 0;i < s->hw_volume.channels;i++) { - vol = s->hw_volume.values[i]; - - if (vol > PA_VOLUME_NORM) - vol = PA_VOLUME_NORM; - - vol = vol * (u->hw_volume_max - u->hw_volume_min) / - PA_VOLUME_NORM + u->hw_volume_min; - err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, vol); - if (err < 0) - goto fail; - } } return 0; @@ -372,10 +353,19 @@ int pa__init(pa_core *c, pa_module*m) { if (u->mixer_handle) { assert(u->mixer_elem); if (snd_mixer_selem_has_capture_volume(u->mixer_elem)) { - u->source->get_hw_volume = source_get_hw_volume_cb; - u->source->set_hw_volume = source_set_hw_volume_cb; - snd_mixer_selem_get_capture_volume_range( - u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max); + int i; + + for (i = 0;i < ss.channels;i++) { + if (!snd_mixer_selem_has_capture_channel(u->mixer_elem, i)) + break; + } + + if (i == ss.channels) { + u->source->get_hw_volume = source_get_hw_volume_cb; + u->source->set_hw_volume = source_set_hw_volume_cb; + snd_mixer_selem_get_capture_volume_range( + u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max); + } } if (snd_mixer_selem_has_capture_switch(u->mixer_elem)) { u->source->get_hw_mute = source_get_hw_mute_cb; -- cgit From 129853f9a438c3522938736a99a3a192abd75d06 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 25 Apr 2006 07:55:14 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@797 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/todo b/doc/todo index bd8145fb..99a86be9 100644 --- a/doc/todo +++ b/doc/todo @@ -14,6 +14,8 @@ Post 0.8: - rtp module ported to Win32 (sendmsg/recvmsg emulation) - CODECs to reduce bandwidth usage (plug-in based) - Remove symdef files and use macros (like most other projects) +- use software volume when hardware doesn't support all channels (alsa done) +- double check channel maps for backends, including that mixer and pcm match Long term: - pass meta info for hearing impaired -- cgit From 31ad62fa4d464f4298bc8e1ad6fbe4b3c03115fa Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 26 Apr 2006 09:38:33 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@798 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/todo b/doc/todo index 99a86be9..f778d61c 100644 --- a/doc/todo +++ b/doc/todo @@ -16,6 +16,9 @@ Post 0.8: - Remove symdef files and use macros (like most other projects) - use software volume when hardware doesn't support all channels (alsa done) - double check channel maps for backends, including that mixer and pcm match +- paplay needs to set a channel map. our default is only correct for AIFF. + (for maximum compatiblity, we should let old files, which don't have a + well defined channel map, use the ALSA channel map) Long term: - pass meta info for hearing impaired -- cgit From 195e96912f062b3faa93547dde014c45ccb74628 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Apr 2006 14:33:45 +0000 Subject: * add new function pa_channel_map_parse() * increase PA_CHANNEL_MAP_SNPRINT_MAX * add "top" channel positions git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@799 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/channelmap.c | 144 ++++++++++++++++++++++++++++++++++++------------- src/polyp/channelmap.h | 15 +++++- 2 files changed, 122 insertions(+), 37 deletions(-) diff --git a/src/polyp/channelmap.c b/src/polyp/channelmap.c index bb47deb8..8d642a06 100644 --- a/src/polyp/channelmap.c +++ b/src/polyp/channelmap.c @@ -28,8 +28,57 @@ #include #include +#include +#include #include "channelmap.h" +const char *const table[] = { + [PA_CHANNEL_POSITION_MONO] = "mono", + + [PA_CHANNEL_POSITION_FRONT_CENTER] = "front-center", + [PA_CHANNEL_POSITION_FRONT_LEFT] = "front-left", + [PA_CHANNEL_POSITION_FRONT_RIGHT] = "front-right", + + [PA_CHANNEL_POSITION_REAR_CENTER] = "rear-center", + [PA_CHANNEL_POSITION_REAR_LEFT] = "rear-left", + [PA_CHANNEL_POSITION_REAR_RIGHT] = "rear-right", + + [PA_CHANNEL_POSITION_LFE] = "lfe", + + [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = "front-left-of-center", + [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = "front-right-of-center", + + [PA_CHANNEL_POSITION_SIDE_LEFT] = "side-left", + [PA_CHANNEL_POSITION_SIDE_RIGHT] = "side-right", + + [PA_CHANNEL_POSITION_AUX0] = "aux0", + [PA_CHANNEL_POSITION_AUX1] = "aux1", + [PA_CHANNEL_POSITION_AUX2] = "aux2", + [PA_CHANNEL_POSITION_AUX3] = "aux3", + [PA_CHANNEL_POSITION_AUX4] = "aux4", + [PA_CHANNEL_POSITION_AUX5] = "aux5", + [PA_CHANNEL_POSITION_AUX6] = "aux6", + [PA_CHANNEL_POSITION_AUX7] = "aux7", + [PA_CHANNEL_POSITION_AUX8] = "aux8", + [PA_CHANNEL_POSITION_AUX9] = "aux9", + [PA_CHANNEL_POSITION_AUX10] = "aux10", + [PA_CHANNEL_POSITION_AUX11] = "aux11", + [PA_CHANNEL_POSITION_AUX12] = "aux12", + [PA_CHANNEL_POSITION_AUX13] = "aux13", + [PA_CHANNEL_POSITION_AUX14] = "aux14", + [PA_CHANNEL_POSITION_AUX15] = "aux15", + + [PA_CHANNEL_POSITION_TOP_CENTER] = "top-center", + + [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = "top-front-left", + [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = "top-front-right", + [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = "top-front-center", + + [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = "top-rear-left", + [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = "top-rear-right", + [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = "top-rear-center" +}; + pa_channel_map* pa_channel_map_init(pa_channel_map *m) { unsigned c; assert(m); @@ -117,40 +166,8 @@ pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels) { } } -const char* pa_channel_position_to_string(pa_channel_position_t pos) { - - const char *const table[] = { - [PA_CHANNEL_POSITION_MONO] = "mono", - - [PA_CHANNEL_POSITION_FRONT_CENTER] = "front-center", - [PA_CHANNEL_POSITION_FRONT_LEFT] = "front-left", - [PA_CHANNEL_POSITION_FRONT_RIGHT] = "front-right", - - [PA_CHANNEL_POSITION_REAR_CENTER] = "rear-center", - [PA_CHANNEL_POSITION_REAR_LEFT] = "rear-left", - [PA_CHANNEL_POSITION_REAR_RIGHT] = "rear-right", - - [PA_CHANNEL_POSITION_LFE] = "lfe", - [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = "front-left-of-center", - [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = "front-right-of-center", - - [PA_CHANNEL_POSITION_SIDE_LEFT] = "side-left", - [PA_CHANNEL_POSITION_SIDE_RIGHT] = "side-right", - - [PA_CHANNEL_POSITION_AUX1] = "aux1", - [PA_CHANNEL_POSITION_AUX2] = "aux2", - [PA_CHANNEL_POSITION_AUX3] = "aux3", - [PA_CHANNEL_POSITION_AUX4] = "aux4", - [PA_CHANNEL_POSITION_AUX5] = "aux5", - [PA_CHANNEL_POSITION_AUX6] = "aux6", - [PA_CHANNEL_POSITION_AUX7] = "aux7", - [PA_CHANNEL_POSITION_AUX8] = "aux8", - [PA_CHANNEL_POSITION_AUX9] = "aux9", - [PA_CHANNEL_POSITION_AUX10] = "aux10", - [PA_CHANNEL_POSITION_AUX11] = "aux11", - [PA_CHANNEL_POSITION_AUX12] = "aux12" - }; +const char* pa_channel_position_to_string(pa_channel_position_t pos) { if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX) return NULL; @@ -186,9 +203,8 @@ char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) { *(e = s) = 0; for (channel = 0; channel < map->channels && l > 1; channel++) { - l -= snprintf(e, l, "%s%u:%s", - first ? "" : " ", - channel, + l -= snprintf(e, l, "%s%s", + first ? "" : ",", pa_channel_position_to_string(map->map[channel])); e = strchr(e, 0); @@ -198,6 +214,61 @@ char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) { return s; } +pa_channel_map *pa_channel_map_parse(pa_channel_map *map, const char *s) { + const char *state; + char *p; + + assert(map); + assert(s); + + memset(map, 0, sizeof(pa_channel_map)); + + if (strcmp(s, "stereo") == 0) { + map->channels = 2; + map->map[0] = PA_CHANNEL_POSITION_LEFT; + map->map[1] = PA_CHANNEL_POSITION_RIGHT; + return map; + } + + state = NULL; + map->channels = 0; + + while ((p = pa_split(s, ",", &state))) { + + /* Some special aliases */ + if (strcmp(p, "left") == 0) + map->map[map->channels++] = PA_CHANNEL_POSITION_LEFT; + else if (strcmp(p, "right") == 0) + map->map[map->channels++] = PA_CHANNEL_POSITION_RIGHT; + else if (strcmp(p, "center") == 0) + map->map[map->channels++] = PA_CHANNEL_POSITION_CENTER; + else if (strcmp(p, "subwoofer") == 0) + map->map[map->channels++] = PA_CHANNEL_POSITION_SUBWOOFER; + else { + pa_channel_position_t i; + + for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++) + if (strcmp(p, table[i]) == 0) { + map->map[map->channels++] = i; + break; + } + + if (i >= PA_CHANNEL_POSITION_MAX) { + pa_xfree(p); + return NULL; + } + } + + pa_xfree(p); + } + + if (!map->channels) + return NULL; + + return map; +} + + int pa_channel_map_valid(const pa_channel_map *map) { unsigned c; @@ -212,3 +283,4 @@ int pa_channel_map_valid(const pa_channel_map *map) { return 1; } + diff --git a/src/polyp/channelmap.h b/src/polyp/channelmap.h index bb9f78b1..76380b5f 100644 --- a/src/polyp/channelmap.h +++ b/src/polyp/channelmap.h @@ -107,6 +107,16 @@ typedef enum pa_channel_position { PA_CHANNEL_POSITION_AUX14, PA_CHANNEL_POSITION_AUX15, + PA_CHANNEL_POSITION_TOP_CENTER, + + PA_CHANNEL_POSITION_TOP_FRONT_LEFT, + PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, + PA_CHANNEL_POSITION_TOP_FRONT_CENTER, + + PA_CHANNEL_POSITION_TOP_REAR_LEFT, + PA_CHANNEL_POSITION_TOP_REAR_RIGHT, + PA_CHANNEL_POSITION_TOP_REAR_CENTER, + PA_CHANNEL_POSITION_MAX } pa_channel_position_t; @@ -134,11 +144,14 @@ pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels); const char* pa_channel_position_to_string(pa_channel_position_t pos); /** The maximum length of strings returned by pa_channel_map_snprint() */ -#define PA_CHANNEL_MAP_SNPRINT_MAX 64 +#define PA_CHANNEL_MAP_SNPRINT_MAX 336 /** Make a humand readable string from the specified channel map */ char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map); +/** Parse a channel position list into a channel map structure. \since 0.8.1 */ +pa_channel_map *pa_channel_map_parse(pa_channel_map *map, const char *s); + /** Compare two channel maps. Return 1 if both match. */ int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b); -- cgit From 5f7cc0c870ebe77dd457209503f75d65b35b8014 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Apr 2006 14:34:45 +0000 Subject: add new test 'channelmap-test' git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@800 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 8 +++++++- src/tests/channelmap-test.c | 25 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/tests/channelmap-test.c diff --git a/src/Makefile.am b/src/Makefile.am index 2061b0ca..fbb14702 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -187,7 +187,8 @@ noinst_PROGRAMS = \ strlist-test \ voltest \ memblockq-test \ - sync-playback + sync-playback \ + channelmap-test if HAVE_SIGXCPU noinst_PROGRAMS += \ @@ -235,6 +236,11 @@ voltest_CFLAGS = $(AM_CFLAGS) voltest_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la voltest_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +channelmap_test_SOURCES = tests/channelmap-test.c +channelmap_test_CFLAGS = $(AM_CFLAGS) +channelmap_test_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la +channelmap_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + cpulimit_test_SOURCES = tests/cpulimit-test.c daemon/cpulimit.c daemon/cpulimit.h cpulimit_test_CFLAGS = $(AM_CFLAGS) cpulimit_test_LDADD = $(AM_LDADD) libpolypcore.la diff --git a/src/tests/channelmap-test.c b/src/tests/channelmap-test.c new file mode 100644 index 00000000..522c136f --- /dev/null +++ b/src/tests/channelmap-test.c @@ -0,0 +1,25 @@ +/* $Id$ */ + +#include +#include + +#include +#include + +int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { + char cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + pa_channel_map map, map2; + + pa_channel_map_init_auto(&map, 5); + + fprintf(stderr, "map: <%s>\n", pa_channel_map_snprint(cm, sizeof(cm), &map)); + + pa_channel_map_parse(&map2, cm); + + assert(pa_channel_map_equal(&map, &map2)); + + pa_channel_map_parse(&map2, "left,test"); + + + return 0; +} -- cgit From 292b237e356371f827df7a7a0e52a7152b64bfe0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Apr 2006 15:37:13 +0000 Subject: don't allow channel positions to be specified twice in the same channelmap git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@801 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/channelmap.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/polyp/channelmap.c b/src/polyp/channelmap.c index 8d642a06..38349bfa 100644 --- a/src/polyp/channelmap.c +++ b/src/polyp/channelmap.c @@ -277,10 +277,19 @@ int pa_channel_map_valid(const pa_channel_map *map) { if (map->channels <= 0 || map->channels > PA_CHANNELS_MAX) return 0; - for (c = 0; c < map->channels; c++) + for (c = 0; c < map->channels; c++) { + unsigned k; + if (map->map[c] < 0 ||map->map[c] >= PA_CHANNEL_POSITION_MAX) return 0; + /* Don't allow positions to be specified twice */ + for (k = 0; k < c; k++) + if (map->map[k] == map->map[c]) + return 0; + + } + return 1; } -- cgit From fbb0d1436c5c415e3964d57b0dedaa0d8817c289 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Apr 2006 15:37:44 +0000 Subject: add support for parsing channel maps as module arguments git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@802 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/modargs.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/polypcore/modargs.h | 11 +++++++++++ 2 files changed, 58 insertions(+) diff --git a/src/polypcore/modargs.c b/src/polypcore/modargs.c index 6bd13c3b..6a02df0a 100644 --- a/src/polypcore/modargs.c +++ b/src/polypcore/modargs.c @@ -259,3 +259,50 @@ int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) { return 0; } + +int pa_modargs_get_channel_map(pa_modargs *ma, pa_channel_map *rmap) { + pa_channel_map map; + const char *cm; + + assert(ma); + assert(rmap); + + map = *rmap; + + if ((cm = pa_modargs_get_value(ma, "channel_map", NULL))) + if (!pa_channel_map_parse(&map, cm)) + return -1; + + if (!pa_channel_map_valid(&map)) + return -1; + + *rmap = map; + return 0; +} + +int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *rss, pa_channel_map *rmap) { + pa_sample_spec ss; + pa_channel_map map; + + assert(ma); + assert(rss); + assert(rmap); + + ss = *rss; + + if (pa_modargs_get_sample_spec(ma, &ss) < 0) + return -1; + + pa_channel_map_init_auto(&map, ss.channels); + + if (pa_modargs_get_channel_map(ma, &map) < 0) + return -1; + + if (map.channels != ss.channels) + return -1; + + *rmap = map; + *rss = ss; + + return 0; +} diff --git a/src/polypcore/modargs.h b/src/polypcore/modargs.h index 47e2d522..481ead99 100644 --- a/src/polypcore/modargs.h +++ b/src/polypcore/modargs.h @@ -24,6 +24,7 @@ #include #include +#include #include typedef struct pa_modargs pa_modargs; @@ -46,4 +47,14 @@ int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value); /* Return sample spec data from the three arguments "rate", "format" and "channels" */ int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *ss); +/* Return channel map data from the argument "channel_map" */ +int pa_modargs_get_channel_map(pa_modargs *ma, pa_channel_map *map); + +/* Combination of pa_modargs_get_sample_spec() and +pa_modargs_get_channel_map(). Not always suitable, since this routine +initializes the map parameter based on the channels field of the ss +structure if no channel_map is found, using pa_channel_map_init_auto() */ + +int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *ss, pa_channel_map *map); + #endif -- cgit From 185a57cadd7b4e8e85c7fbecc866d7c279704e12 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Apr 2006 15:40:14 +0000 Subject: support new channel_map argument in sink/source modules git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@803 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-sink.c | 16 +++++++++++++--- src/modules/module-alsa-source.c | 16 +++++++++++++--- src/modules/module-combine.c | 38 +++++++++++++++++++++++++++++++++++--- src/modules/module-jack-sink.c | 19 ++++++++++++------- src/modules/module-jack-source.c | 17 +++++++++++------ src/modules/module-null-sink.c | 15 +++++++++++---- src/modules/module-oss-mmap.c | 15 +++++++++------ src/modules/module-oss.c | 13 ++++++++----- src/modules/module-pipe-sink.c | 14 +++++++++++--- src/modules/module-pipe-source.c | 16 ++++++++++++---- src/modules/module-tunnel.c | 28 +++++++++++++++++++++++----- 11 files changed, 158 insertions(+), 49 deletions(-) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index ecdf8cb0..2c2f1f3e 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -50,7 +50,15 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ALSA Sink") PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= device= format= channels= rate= fragments= fragment_size=") +PA_MODULE_USAGE( + "sink_name= " + "device= " + "format= " + "channels= " + "rate= " + "fragments= " + "fragment_size= " + "channel_map=") struct userdata { snd_pcm_t *pcm_handle; @@ -74,6 +82,7 @@ static const char* const valid_modargs[] = { "rate", "fragments", "fragment_size", + "channel_map", NULL }; @@ -299,6 +308,7 @@ int pa__init(pa_core *c, pa_module*m) { struct userdata *u = NULL; const char *dev; pa_sample_spec ss; + pa_channel_map map; uint32_t periods, fragsize; snd_pcm_uframes_t period_size; size_t frame_size; @@ -311,7 +321,7 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { pa_log(__FILE__": failed to parse sample specification"); goto fail; } @@ -357,7 +367,7 @@ int pa__init(pa_core *c, pa_module*m) { u->mixer_handle = NULL; } - u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); + u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 7a365286..e4938917 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -50,7 +50,15 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ALSA Source") PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("source_name= device= format= channels= rate= fragments= fragment_size=") +PA_MODULE_USAGE( + "source_name= " + "device= " + "format= " + "channels= " + "rate= " + "fragments= " + "fragment_size= " + "channel_map=") struct userdata { snd_pcm_t *pcm_handle; @@ -74,6 +82,7 @@ static const char* const valid_modargs[] = { "format", "fragments", "fragment_size", + "channel_map", NULL }; @@ -287,6 +296,7 @@ int pa__init(pa_core *c, pa_module*m) { struct userdata *u = NULL; const char *dev; pa_sample_spec ss; + pa_channel_map map; unsigned periods, fragsize; snd_pcm_uframes_t period_size; size_t frame_size; @@ -299,7 +309,7 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { pa_log(__FILE__": failed to parse sample specification"); goto fail; } @@ -345,7 +355,7 @@ int pa__init(pa_core *c, pa_module*m) { u->mixer_handle = NULL; } - u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map); assert(u->source); u->source->userdata = u; diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 80153900..543fffa4 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -42,7 +42,16 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Combine multiple sinks to one") PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= master= slaves= adjust_time= resample_method=") +PA_MODULE_USAGE( + "sink_name= " + "master= " + "slaves= " + "adjust_time= " + "resample_method= " + "format= " + "channels= " + "rate= " + "channel_map= ") #define DEFAULT_SINK_NAME "combined" #define MEMBLOCKQ_MAXLENGTH (1024*170) @@ -56,6 +65,10 @@ static const char* const valid_modargs[] = { "slaves", "adjust_time", "resample_method", + "format", + "channels", + "rate", + "channel_map", NULL }; @@ -296,6 +309,9 @@ int pa__init(pa_core *c, pa_module*m) { const char*split_state; struct timeval tv; int resample_method = -1; + pa_sample_spec ss; + pa_channel_map map; + assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -310,7 +326,7 @@ int pa__init(pa_core *c, pa_module*m) { } } - u = pa_xmalloc(sizeof(struct userdata)); + u = pa_xnew(struct userdata, 1); m->userdata = u; u->sink = NULL; u->n_outputs = 0; @@ -336,7 +352,23 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &master_sink->sample_spec, &master_sink->channel_map))) { + ss = master_sink->sample_spec; + if ((pa_modargs_get_sample_spec(ma, &ss) < 0)) { + pa_log(__FILE__": invalid sample specification."); + goto fail; + } + + if (ss.channels == master_sink->sample_spec.channels) + map = master_sink->channel_map; + else + pa_channel_map_init_auto(&map, ss.channels); + + if ((pa_modargs_get_channel_map(ma, &map) < 0)) { + pa_log(__FILE__": invalid channel map."); + goto fail; + } + + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { pa_log(__FILE__": failed to create sink"); goto fail; } diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index f340ab6d..09030530 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -55,8 +55,8 @@ PA_MODULE_USAGE( "server_name= " "client_name= " "channels= " - "connect=" -) + "connect= " + "channel_map=") #define DEFAULT_SINK_NAME "jack_out" @@ -91,6 +91,7 @@ static const char* const valid_modargs[] = { "client_name", "channels", "connect", + "channel_map", NULL }; @@ -233,7 +234,7 @@ static void jack_error_func(const char*t) { int pa__init(pa_core *c, pa_module*m) { struct userdata *u = NULL; pa_sample_spec ss; - pa_channel_map cm; + pa_channel_map map; pa_modargs *ma = NULL; jack_status_t status; const char *server_name, *client_name; @@ -294,6 +295,12 @@ int pa__init(pa_core *c, pa_module*m) { pa_log(__FILE__": failed to parse channels= argument."); goto fail; } + + pa_channel_map_init_auto(&map, channels); + if (pa_modargs_get_channel_map(ma, &map) < 0 || map.channels != channels) { + pa_log(__FILE__": failed to parse channel_map= argument."); + goto fail; + } pa_log_info(__FILE__": Successfully connected as '%s'", jack_get_client_name(u->client)); @@ -303,16 +310,14 @@ int pa__init(pa_core *c, pa_module*m) { assert(pa_sample_spec_valid(&ss)); - pa_channel_map_init_auto(&cm, channels); - for (i = 0; i < ss.channels; i++) { - if (!(u->port[i] = jack_port_register(u->client, pa_channel_position_to_string(cm.map[i]), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput|JackPortIsTerminal, 0))) { + if (!(u->port[i] = jack_port_register(u->client, pa_channel_position_to_string(map.map[i]), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput|JackPortIsTerminal, 0))) { pa_log(__FILE__": jack_port_register() failed."); goto fail; } } - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &cm))) { + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { pa_log(__FILE__": failed to create sink."); goto fail; } diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index 5f0e560d..ad39b9dd 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -56,7 +56,7 @@ PA_MODULE_USAGE( "client_name= " "channels= " "connect=" -) + "channel_map=") #define DEFAULT_SOURCE_NAME "jack_in" @@ -91,6 +91,7 @@ static const char* const valid_modargs[] = { "client_name", "channels", "connect", + "channel_map", NULL }; @@ -231,7 +232,7 @@ static void jack_error_func(const char*t) { int pa__init(pa_core *c, pa_module*m) { struct userdata *u = NULL; pa_sample_spec ss; - pa_channel_map cm; + pa_channel_map map; pa_modargs *ma = NULL; jack_status_t status; const char *server_name, *client_name; @@ -292,6 +293,12 @@ int pa__init(pa_core *c, pa_module*m) { pa_log(__FILE__": failed to parse channels= argument."); goto fail; } + + pa_channel_map_init_auto(&map, channels); + if (pa_modargs_get_channel_map(ma, &map) < 0 || map.channels != channels) { + pa_log(__FILE__": failed to parse channel_map= argument."); + goto fail; + } pa_log_info(__FILE__": Successfully connected as '%s'", jack_get_client_name(u->client)); @@ -301,16 +308,14 @@ int pa__init(pa_core *c, pa_module*m) { assert(pa_sample_spec_valid(&ss)); - pa_channel_map_init_auto(&cm, channels); - for (i = 0; i < ss.channels; i++) { - if (!(u->port[i] = jack_port_register(u->client, pa_channel_position_to_string(cm.map[i]), JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput|JackPortIsTerminal, 0))) { + if (!(u->port[i] = jack_port_register(u->client, pa_channel_position_to_string(map.map[i]), JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput|JackPortIsTerminal, 0))) { pa_log(__FILE__": jack_port_register() failed."); goto fail; } } - if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &cm))) { + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) { pa_log(__FILE__": failed to create source."); goto fail; } diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index 61178239..9c564429 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -46,7 +46,12 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Clocked NULL sink") PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("format= channels= rate= sink_name=") +PA_MODULE_USAGE( + "format= " + "channels= " + "rate= " + "sink_name=" + "channel_map=") #define DEFAULT_SINK_NAME "null" @@ -63,6 +68,7 @@ static const char* const valid_modargs[] = { "format", "channels", "sink_name", + "channel_map", NULL }; @@ -87,6 +93,7 @@ static void time_callback(pa_mainloop_api *m, pa_time_event*e, const struct time int pa__init(pa_core *c, pa_module*m) { struct userdata *u = NULL; pa_sample_spec ss; + pa_channel_map map; pa_modargs *ma = NULL; struct timeval tv; assert(c && m); @@ -97,8 +104,8 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": invalid sample format specification."); + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { + pa_log(__FILE__": invalid sample format specification or channel map."); goto fail; } @@ -107,7 +114,7 @@ int pa__init(pa_core *c, pa_module*m) { u->module = m; m->userdata = u; - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { pa_log(__FILE__": failed to create sink."); goto fail; } diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index c487f40c..e032ce46 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -62,7 +62,8 @@ PA_MODULE_USAGE( "channels= " "rate= " "fragments= " - "fragment_size=") + "fragment_size= " + "channel_map=") struct userdata { pa_sink *sink; @@ -97,6 +98,7 @@ static const char* const valid_modargs[] = { "format", "rate", "channels", + "channel_map", NULL }; @@ -346,7 +348,8 @@ int pa__init(pa_core *c, pa_module*m) { int playback = 1, record = 1; pa_modargs *ma = NULL; char hwdesc[64]; - + pa_channel_map map; + assert(c); assert(m); @@ -380,8 +383,8 @@ int pa__init(pa_core *c, pa_module*m) { } u->sample_spec = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &u->sample_spec) < 0) { - pa_log(__FILE__": failed to parse sample specification"); + if (pa_modargs_get_sample_spec_and_channel_map(ma, &u->sample_spec, &map) < 0) { + pa_log(__FILE__": failed to parse sample specification or channel map"); goto fail; } @@ -426,7 +429,7 @@ int pa__init(pa_core *c, pa_module*m) { } } else { - if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec, NULL))) + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec, &map))) goto fail; u->source->userdata = u; @@ -466,7 +469,7 @@ int pa__init(pa_core *c, pa_module*m) { } else { pa_silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec); - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec, NULL))) + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec, &map))) goto fail; u->sink->get_latency = sink_get_latency_cb; diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index ccc3c7d9..0795ae39 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -61,7 +61,8 @@ PA_MODULE_USAGE( "channels= " "rate= " "fragments= " - "fragment_size=") + "fragment_size= " + "channel_map=") struct userdata { pa_sink *sink; @@ -89,6 +90,7 @@ static const char* const valid_modargs[] = { "format", "rate", "channels", + "channel_map", NULL }; @@ -322,6 +324,7 @@ int pa__init(pa_core *c, pa_module*m) { int mode; int record = 1, playback = 1; pa_sample_spec ss; + pa_channel_map map; pa_modargs *ma = NULL; char hwdesc[64]; @@ -353,8 +356,8 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": failed to parse sample specification"); + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { + pa_log(__FILE__": failed to parse sample specification or channel map"); goto fail; } @@ -399,7 +402,7 @@ int pa__init(pa_core *c, pa_module*m) { } if (mode != O_WRONLY) { - if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL))) + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) goto fail; u->source->userdata = u; @@ -417,7 +420,7 @@ int pa__init(pa_core *c, pa_module*m) { u->source = NULL; if (mode != O_RDONLY) { - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) goto fail; u->sink->get_latency = sink_get_latency_cb; diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index 4ddf26ac..2be1b297 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -46,7 +46,13 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("UNIX pipe sink") PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= file= format= channels= rate=") +PA_MODULE_USAGE( + "sink_name= " + "file= " + "format= " + "channels= " + "rate=" + "channel_map=") #define DEFAULT_FIFO_NAME "/tmp/music.output" #define DEFAULT_SINK_NAME "fifo_output" @@ -70,6 +76,7 @@ static const char* const valid_modargs[] = { "format", "channels", "sink_name", + "channel_map", NULL }; @@ -137,6 +144,7 @@ int pa__init(pa_core *c, pa_module*m) { const char *p; int fd = -1; pa_sample_spec ss; + pa_channel_map map; pa_modargs *ma = NULL; assert(c && m); @@ -146,7 +154,7 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { pa_log(__FILE__": invalid sample format specification"); goto fail; } @@ -176,7 +184,7 @@ int pa__init(pa_core *c, pa_module*m) { u->module = m; m->userdata = u; - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { pa_log(__FILE__": failed to create sink."); goto fail; } diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index d3753d25..c80bfd09 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -46,7 +46,13 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("UNIX pipe source") PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("source_name= file= format= channels= rate=") +PA_MODULE_USAGE( + "source_name= " + "file= " + "format= " + "channels= " + "rate= " + "channel_map=") #define DEFAULT_FIFO_NAME "/tmp/music.input" #define DEFAULT_SOURCE_NAME "fifo_input" @@ -68,6 +74,7 @@ static const char* const valid_modargs[] = { "channels", "format", "source_name", + "channel_map", NULL }; @@ -115,6 +122,7 @@ int pa__init(pa_core *c, pa_module*m) { const char *p; int fd = -1; pa_sample_spec ss; + pa_channel_map map; pa_modargs *ma = NULL; assert(c && m); @@ -124,8 +132,8 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": invalid sample format specification"); + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { + pa_log(__FILE__": invalid sample format specification or channel map"); goto fail; } @@ -153,7 +161,7 @@ int pa__init(pa_core *c, pa_module*m) { u->filename = pa_xstrdup(p); u->core = c; - if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL))) { + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) { pa_log(__FILE__": failed to create source."); goto fail; } diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index abfa68a4..bffcc7c0 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -51,11 +51,27 @@ #ifdef TUNNEL_SINK #include "module-tunnel-sink-symdef.h" PA_MODULE_DESCRIPTION("Tunnel module for sinks") -PA_MODULE_USAGE("server=
    sink= cookie= format= channels= rate= sink_name=") +PA_MODULE_USAGE( + "server=
    " + "sink= " + "cookie= " + "format= " + "channels= " + "rate= " + "sink_name= " + "channel_map=") #else #include "module-tunnel-source-symdef.h" PA_MODULE_DESCRIPTION("Tunnel module for sources") -PA_MODULE_USAGE("server=
    source= cookie= format= channels= rate= source_name=") +PA_MODULE_USAGE( + "server=
    " + "source= " + "cookie= " + "format= " + "channels= " + "rate= " + "source_name= " + "channel_map=") #endif PA_MODULE_AUTHOR("Lennart Poettering") @@ -87,6 +103,7 @@ static const char* const valid_modargs[] = { "source_name", "source", #endif + "channel_map", NULL, }; @@ -838,6 +855,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_modargs *ma = NULL; struct userdata *u = NULL; pa_sample_spec ss; + pa_channel_map map; struct timeval ntv; assert(c && m); @@ -877,7 +895,7 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { pa_log(__FILE__": invalid sample format specification"); goto fail; } @@ -893,7 +911,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_socket_client_set_callback(u->client, on_connection, u); #ifdef TUNNEL_SINK - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { pa_log(__FILE__": failed to create sink."); goto fail; } @@ -909,7 +927,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_sink_set_owner(u->sink, m); #else - if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL))) { + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) { pa_log(__FILE__": failed to create source."); goto fail; } -- cgit From c478b0f11867cda279d41135a97336f6976007ae Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Apr 2006 16:07:05 +0000 Subject: * make a validity check of parsed channel maps before rteurning theme * don't overwrite the return buffer unless the parsed channel map is known to be valid git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@804 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/channelmap.c | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/src/polyp/channelmap.c b/src/polyp/channelmap.c index 38349bfa..afe56170 100644 --- a/src/polyp/channelmap.c +++ b/src/polyp/channelmap.c @@ -214,42 +214,48 @@ char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) { return s; } -pa_channel_map *pa_channel_map_parse(pa_channel_map *map, const char *s) { +pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) { const char *state; + pa_channel_map map; char *p; - assert(map); + assert(rmap); assert(s); - memset(map, 0, sizeof(pa_channel_map)); + memset(&map, 0, sizeof(map)); if (strcmp(s, "stereo") == 0) { - map->channels = 2; - map->map[0] = PA_CHANNEL_POSITION_LEFT; - map->map[1] = PA_CHANNEL_POSITION_RIGHT; - return map; + map.channels = 2; + map.map[0] = PA_CHANNEL_POSITION_LEFT; + map.map[1] = PA_CHANNEL_POSITION_RIGHT; + goto finish; } state = NULL; - map->channels = 0; + map.channels = 0; while ((p = pa_split(s, ",", &state))) { + + if (map.channels >= PA_CHANNELS_MAX) { + pa_xfree(p); + return NULL; + } /* Some special aliases */ if (strcmp(p, "left") == 0) - map->map[map->channels++] = PA_CHANNEL_POSITION_LEFT; + map.map[map.channels++] = PA_CHANNEL_POSITION_LEFT; else if (strcmp(p, "right") == 0) - map->map[map->channels++] = PA_CHANNEL_POSITION_RIGHT; + map.map[map.channels++] = PA_CHANNEL_POSITION_RIGHT; else if (strcmp(p, "center") == 0) - map->map[map->channels++] = PA_CHANNEL_POSITION_CENTER; + map.map[map.channels++] = PA_CHANNEL_POSITION_CENTER; else if (strcmp(p, "subwoofer") == 0) - map->map[map->channels++] = PA_CHANNEL_POSITION_SUBWOOFER; + map.map[map.channels++] = PA_CHANNEL_POSITION_SUBWOOFER; else { pa_channel_position_t i; for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++) if (strcmp(p, table[i]) == 0) { - map->map[map->channels++] = i; + map.map[map.channels++] = i; break; } @@ -262,13 +268,15 @@ pa_channel_map *pa_channel_map_parse(pa_channel_map *map, const char *s) { pa_xfree(p); } - if (!map->channels) +finish: + + if (!pa_channel_map_valid(&map)) return NULL; - - return map; + + *rmap = map; + return rmap; } - int pa_channel_map_valid(const pa_channel_map *map) { unsigned c; -- cgit From c3cc14153a2f519b2333400bfa942f70bca58c95 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Apr 2006 16:07:33 +0000 Subject: allow specifying the channel map to use on the command line git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@805 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pacat.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/utils/pacat.c b/src/utils/pacat.c index cce97442..a823c88b 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -66,6 +66,9 @@ static pa_sample_spec sample_spec = { .channels = 2 }; +static pa_channel_map channel_map; +static int channel_map_set = 0; + /* A shortcut for terminating the application */ static void quit(int ret) { assert(mainloop_api); @@ -184,7 +187,7 @@ static void context_state_callback(pa_context *c, void *userdata) { if (verbose) fprintf(stderr, "Connection established.\n"); - if (!(stream = pa_stream_new(c, stream_name, &sample_spec, NULL))) { + if (!(stream = pa_stream_new(c, stream_name, &sample_spec, channel_map_set ? &channel_map : NULL))) { fprintf(stderr, "pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(c))); goto fail; } @@ -405,7 +408,8 @@ static void help(const char *argv0) { " --format=SAMPLEFORMAT The sample type, one of s16le, s16be, u8, float32le,\n" " float32be, ulaw, alaw (defaults to s16ne)\n" " --channels=CHANNELS The number of channels, 1 for mono, 2 for stereo\n" - " (defaults to 2)\n", + " (defaults to 2)\n" + " --channel-map=CHANNELMAP Channel map to use instead of the default\n", argv0); } @@ -415,7 +419,8 @@ enum { ARG_VOLUME, ARG_SAMPLERATE, ARG_SAMPLEFORMAT, - ARG_CHANNELS + ARG_CHANNELS, + ARG_CHANNELMAP, }; int main(int argc, char *argv[]) { @@ -438,6 +443,7 @@ int main(int argc, char *argv[]) { {"rate", 1, NULL, ARG_SAMPLERATE}, {"format", 1, NULL, ARG_SAMPLEFORMAT}, {"channels", 1, NULL, ARG_CHANNELS}, + {"channel-map", 1, NULL, ARG_CHANNELMAP}, {NULL, 0, NULL, 0} }; @@ -514,6 +520,16 @@ int main(int argc, char *argv[]) { sample_spec.rate = atoi(optarg); break; + case ARG_CHANNELMAP: + + if (!pa_channel_map_parse(&channel_map, optarg)) { + fprintf(stderr, "Invalid channel map\n"); + goto quit; + } + + channel_map_set = 1; + break; + default: goto quit; } @@ -529,6 +545,11 @@ int main(int argc, char *argv[]) { fprintf(stderr, "Invalid sample specification\n"); goto quit; } + + if (channel_map_set && channel_map.channels != sample_spec.channels) { + fprintf(stderr, "Channel map doesn't match sample specification\n"); + goto quit; + } if (verbose) { char t[PA_SAMPLE_SPEC_SNPRINT_MAX]; -- cgit From d4bad65e22d03a788c0e04ff90ec306d59caf9dc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Apr 2006 16:27:01 +0000 Subject: it was a bad idea to require that a channel map doesn't contain the same position twice git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@806 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/channelmap.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/polyp/channelmap.c b/src/polyp/channelmap.c index afe56170..794711ae 100644 --- a/src/polyp/channelmap.c +++ b/src/polyp/channelmap.c @@ -286,16 +286,10 @@ int pa_channel_map_valid(const pa_channel_map *map) { return 0; for (c = 0; c < map->channels; c++) { - unsigned k; if (map->map[c] < 0 ||map->map[c] >= PA_CHANNEL_POSITION_MAX) return 0; - /* Don't allow positions to be specified twice */ - for (k = 0; k < c; k++) - if (map->map[k] == map->map[c]) - return 0; - } return 1; -- cgit From 7b8390459b12081a2c3ae079d1acfb1fd93f1114 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Apr 2006 16:27:33 +0000 Subject: if a sample is not yet loaded, don't print rubbish about its channel map git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@807 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/cli-text.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polypcore/cli-text.c b/src/polypcore/cli-text.c index d31d09c5..74de5781 100644 --- a/src/polypcore/cli-text.c +++ b/src/polypcore/cli-text.c @@ -280,7 +280,7 @@ char *pa_scache_list_to_string(pa_core *c) { for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) { double l = 0; - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = "n/a", cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = "n/a", cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX] = "n/a"; if (e->memchunk.memblock) { pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec); -- cgit From d78e466a2839ac9d71993cf069f7df4360ecea1e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Apr 2006 16:27:59 +0000 Subject: fix volume range printed on --help git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@808 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pacat.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/utils/pacat.c b/src/utils/pacat.c index a823c88b..1ecc0db2 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -403,7 +403,7 @@ static void help(const char *argv0) { " -d, --device=DEVICE The name of the sink/source to connect to\n" " -n, --client-name=NAME How to call this client on the server\n" " --stream-name=NAME How to call this stream on the server\n" - " --volume=VOLUME Specify the initial (linear) volume in range 0...256\n" + " --volume=VOLUME Specify the initial (linear) volume in range 0...65536\n" " --rate=SAMPLERATE The sample rate in Hz (defaults to 44100)\n" " --format=SAMPLEFORMAT The sample type, one of s16le, s16be, u8, float32le,\n" " float32be, ulaw, alaw (defaults to s16ne)\n" @@ -521,7 +521,6 @@ int main(int argc, char *argv[]) { break; case ARG_CHANNELMAP: - if (!pa_channel_map_parse(&channel_map, optarg)) { fprintf(stderr, "Invalid channel map\n"); goto quit; -- cgit From c27b1407f8197230136158eae2aeb75f526a12f3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Apr 2006 16:28:29 +0000 Subject: allow the user to specify an alternative channel map in paplay too git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@809 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/paplay.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/utils/paplay.c b/src/utils/paplay.c index 4efb4cf6..7f665413 100644 --- a/src/utils/paplay.c +++ b/src/utils/paplay.c @@ -53,7 +53,9 @@ static pa_volume_t volume = PA_VOLUME_NORM; static SNDFILE* sndfile = NULL; -static pa_sample_spec sample_spec = { 0, 0, 0 }; +static pa_sample_spec sample_spec = { 0, 0, 0 }; +static pa_channel_map channel_map; +static int channel_map_set = 0; static sf_count_t (*readf_function)(SNDFILE *_sndfile, void *ptr, sf_count_t frames); @@ -161,7 +163,7 @@ static void context_state_callback(pa_context *c, void *userdata) { if (verbose) fprintf(stderr, "Connection established.\n"); - stream = pa_stream_new(c, stream_name, &sample_spec, NULL); + stream = pa_stream_new(c, stream_name, &sample_spec, channel_map_set ? &channel_map : NULL); assert(stream); pa_stream_set_state_callback(stream, stream_state_callback, NULL); @@ -200,14 +202,16 @@ static void help(const char *argv0) { " -d, --device=DEVICE The name of the sink/source to connect to\n" " -n, --client-name=NAME How to call this client on the server\n" " --stream-name=NAME How to call this stream on the server\n" - " --volume=VOLUME Specify the initial (linear) volume in range 0...256\n", + " --volume=VOLUME Specify the initial (linear) volume in range 0...65536\n" + " --channel-map=CHANNELMAP Set the channel map to the use\n", argv0); } enum { ARG_VERSION = 256, ARG_STREAM_NAME, - ARG_VOLUME + ARG_VOLUME, + ARG_CHANNELMAP }; int main(int argc, char *argv[]) { @@ -226,6 +230,7 @@ int main(int argc, char *argv[]) { {"help", 0, NULL, 'h'}, {"verbose", 0, NULL, 'v'}, {"volume", 1, NULL, ARG_VOLUME}, + {"channel-map", 1, NULL, ARG_CHANNELMAP}, {NULL, 0, NULL, 0} }; @@ -277,6 +282,15 @@ int main(int argc, char *argv[]) { break; } + case ARG_CHANNELMAP: + if (!pa_channel_map_parse(&channel_map, optarg)) { + fprintf(stderr, "Invalid channel map\n"); + goto quit; + } + + channel_map_set = 1; + break; + default: goto quit; } @@ -322,6 +336,13 @@ int main(int argc, char *argv[]) { break; } + assert(pa_sample_spec_valid(&sample_spec)); + + if (channel_map_set && channel_map.channels != sample_spec.channels) { + fprintf(stderr, "Channel map doesn't match file.\n"); + goto quit; + } + if (verbose) { char t[PA_SAMPLE_SPEC_SNPRINT_MAX]; pa_sample_spec_snprint(t, sizeof(t), &sample_spec); -- cgit From 9564cefdbf856d9a4ea9d4f3a57a6f53ddcb7085 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Apr 2006 16:50:36 +0000 Subject: fail if the channel map doesn't match the sample specs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@810 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-combine.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 543fffa4..47010497 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -367,6 +367,11 @@ int pa__init(pa_core *c, pa_module*m) { pa_log(__FILE__": invalid channel map."); goto fail; } + + if (ss.channels != map.channels) { + pa_log(__FILE__": channel map and sample specification don't match."); + goto fail; + } if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { pa_log(__FILE__": failed to create sink"); -- cgit From dff0822721c87884cd2185ac65c346a284b08542 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Apr 2006 19:24:32 +0000 Subject: bump version number git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@811 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 87dc2aab..22ab3962 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. AC_PREREQ(2.57) -AC_INIT([polypaudio],[0.8],[mzcbylcnhqvb (at) 0pointer (dot) de]) +AC_INIT([polypaudio],[0.8.1],[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([src/daemon/main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) -- cgit From c29b3f11e271757d60e72480030011913f778878 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Apr 2006 21:31:51 +0000 Subject: doc update for 0.8.1 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@812 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/FAQ.html.in | 48 +++++++++++++++++++++++++++++++++++++++++++++++- doc/README.html.in | 19 +++++++++++++++++++ doc/modules.html.in | 17 +++++++++++++++-- 3 files changed, 81 insertions(+), 3 deletions(-) diff --git a/doc/FAQ.html.in b/doc/FAQ.html.in index 7adc2441..a042dd7b 100644 --- a/doc/FAQ.html.in +++ b/doc/FAQ.html.in @@ -224,7 +224,7 @@ load-module module-rtp-recv sink=rtp set-default-source rtp_monitor -

    Now the audio data will be available from the default source rtp_monitor.

    +

    Now the audio data will be available from the default source rtp_monitor.

  • When sending multicast RTP traffic it is recieved on the entire LAN but not by the sender machine itself!

    @@ -237,6 +237,52 @@ the destination/sap_address arguments of the RTP modules to select them. Choose your group addresses from the range 225.0.0.x to make sure the audio data never leaves the LAN.

  • + +
  • Can I use Polypaudio to playback music on two sound cards simultaneously?

    + +

    Yes! Use module-combine for that.

    + +
    +load-module module-oss-mmap device="/dev/dsp" sink_name=output0
    +load-module module-oss-mmap device="/dev/dsp1" sink_name=output1
    +load-module module-combine sink_name=combined master=output0 slaves=output1
    +set-sink-default combined
    +
    + +

    This will combine the two sinks output0 and +output1 into a new sink combined. Every sample +written to the latter will be forwarded to the former two. Polypaudio +will make sure to adjust the sample rate of the slave device in case +it deviates from the master device. You can have more than one slave +sink attached to the combined sink, and hence combine even three and +more sound cards.

  • + +
  • Can I use Polypaudio to combine two stereo soundcards into a virtual surround sound card?

    + +

    Yes! You can use use module-combine for that.

    + +
    +load-module module-oss-mmap device="/dev/dsp" sink_name=output0 channel_map=left,right channels=2
    +load-module module-oss-mmap device="/dev/dsp1" sink_name=output1 channel_map=rear-left,rear-right channels=2
    +load-module module-combine sink_name=combined master=output0 slaves=output1 channel_map=left,right,rear-left,rear-right channels=4
    +
    + +

    This is mostly identical to the previous example. However, this +time we manually specify the channel mappings for the sinks to make +sure everything is routed correctly.

    + +

    Please keep in mind that Polypaudio will constantly adjust the +sample rate to compensate for the deviating quartzes of the sound +devices. This is not perfect, however. Deviations in a range of +1/44100s (or 1/48000s depending on the sampling frequency) can not be +compensated. The human ear will decode these deviations as minor +movements (less than 1cm) of the positions of the sound sources +you hear.

    + +
  • + + +
    diff --git a/doc/README.html.in b/doc/README.html.in index 5dec5056..2ed75edf 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -22,6 +22,7 @@
  • Installation
  • Acknowledgements
  • Download
  • +
  • Community
  • License

    @@ -42,6 +43,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    News

    +
    Wed Apr 26 2006:

    Version 0.8.1 +released; changes include: support for specifying the channel map on +the command lines of paplay and pacat and as +arguments to the driver modules; ALSA hardware mixer compatibility; +fix linking; properly remove PF_UNIX sockets when unloading +protocol modules; fix sample cache; many other fixes

    +
    Thu Apr 13 2006:

    Version 0.8 released; changes include: too many to count - consider reading this blog entry for more information; many, many minor fixes.

    @@ -288,6 +297,10 @@ compilation and make install (as root) for installation of

    Cendio AB for paying for Pierre's work on Polypaudio

    +

    Sebastien ESTIENNE for testing

    + +

    Igor Zubkov for some portability patches

    +

    Download

    The newest release is always available from @PACKAGE_URL@

    @@ -298,10 +311,16 @@ compilation and make install (as root) for installation of
    svn checkout svn://0pointer.de/polypaudio/trunk polypaudio
    +

    Community

    +

    If you want to be notified whenever I release a new version of this software use the subscription feature of Freshmeat.

    There is a general discussion mailing list for polypaudio available. In addition, you can subscribe to SVN changes and Trac Tickets.

    +

    Polypaudio is being tracked at CIA.

    + +

    There's a chance to meet the Polypaudio developers on our IRC channel #polypaudio on irc.freenode.org.

    +

    There is a Trac based Wiki for Polypaudio available.

    Please report bugs to our Trac ticket system.

    diff --git a/doc/modules.html.in b/doc/modules.html.in index f7b6298f..6a6b7887 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -20,7 +20,19 @@ rate=The sample rate (defaults to 44100) channels=Audio channels (defaults to 2) sink_name=, source_name=Name for the sink (resp. source) - + channel_map=Channel map. A list of +comma-seperated channel names. The currently defined channel names +are: left, right, mono, center, +front-left, front-right, front-center, +rear-center, rear-left, rear-right, +lfe, subwoofer, front-left-of-center, +front-right-of-center, side-left, +side-right, aux0, aux1 to aux15, +top-center, top-front-left, +top-front-right, top-front-center, +top-rear-left, top-rear-right, +top-rear-center, (Default depends on the number of channels +and the driver)

    module-pipe-sink

    @@ -118,12 +130,13 @@ compatible as module-oss.

    This module supports all arguments thet module-oss supports except device=.

    +

    module-combine

    This combines two or more sinks into one. A new virtual sink is allocated. All data written to it is forwarded to all connected sinks. In aequidistant intervals the sample rates of the output sinks -is recalculated: i.e. even when the sink's crystals deviate (which is +is recalculated: i.e. even when the sinks' crystals deviate (which is normally the case) output appears synchronously to the human ear. The resampling required for this may be very CPU intensive.

    -- cgit From 2c08180ec9ce9c7cb0b878a6deabb7fbb7b68128 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 27 Apr 2006 05:26:29 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@813 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/todo b/doc/todo index f778d61c..4d642286 100644 --- a/doc/todo +++ b/doc/todo @@ -17,8 +17,7 @@ Post 0.8: - use software volume when hardware doesn't support all channels (alsa done) - double check channel maps for backends, including that mixer and pcm match - paplay needs to set a channel map. our default is only correct for AIFF. - (for maximum compatiblity, we should let old files, which don't have a - well defined channel map, use the ALSA channel map) + (we need help from libsndfile for this) Long term: - pass meta info for hearing impaired @@ -29,3 +28,6 @@ Backends for: - sdl - OSS (esddsp style) - gstreamer (needs to be updated) +- fix channel maps in all external backends. Take care when doing volume + changes if you're modifying a sink/source since those might have a different + map. -- cgit From 0b95438f102be2f0ffdc08ea37a50558a68ce90f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 27 Apr 2006 05:39:11 +0000 Subject: Channel map argument support for waveout. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@814 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-waveout.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index ef602e8d..34607421 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -43,7 +43,17 @@ PA_MODULE_AUTHOR("Pierre Ossman") PA_MODULE_DESCRIPTION("Windows waveOut Sink/Source") PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= source_name= record= playback= format= channels= rate= fragments= fragment_size=") +PA_MODULE_USAGE( + "sink_name= " + "source_name=" + "record= " + "playback= " + "format= " + "channels= " + "rate= " + "fragments= " + "fragment_size= " + "channel_map=") #define DEFAULT_SINK_NAME "wave_output" #define DEFAULT_SOURCE_NAME "wave_input" @@ -86,6 +96,7 @@ static const char* const valid_modargs[] = { "format", "rate", "channels", + "channel_map", NULL }; @@ -428,6 +439,7 @@ int pa__init(pa_core *c, pa_module*m) { int nfrags, frag_size; int record = 1, playback = 1; pa_sample_spec ss; + pa_channel_map map; pa_modargs *ma = NULL; unsigned int i; struct timeval tv; @@ -457,7 +469,7 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { pa_log(__FILE__": failed to parse sample specification"); goto fail; } @@ -484,7 +496,7 @@ int pa__init(pa_core *c, pa_module*m) { InitializeCriticalSection(&u->crit); if (hwi != INVALID_HANDLE_VALUE) { - u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map); assert(u->source); u->source->userdata = u; u->source->notify = notify_source_cb; @@ -495,7 +507,7 @@ int pa__init(pa_core *c, pa_module*m) { u->source = NULL; if (hwo != INVALID_HANDLE_VALUE) { - u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); + u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map); assert(u->sink); u->sink->notify = notify_sink_cb; u->sink->get_latency = sink_get_latency_cb; -- cgit From 99612dd88dfee3abd072c3138231549594381ee7 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 27 Apr 2006 05:41:18 +0000 Subject: Channel map argument support for solaris. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@815 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-solaris.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index e1a03272..eaac9e6e 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -57,7 +57,16 @@ PA_MODULE_AUTHOR("Pierre Ossman") PA_MODULE_DESCRIPTION("Solaris Sink/Source") PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= buffer_size=") +PA_MODULE_USAGE( + "sink_name= " + "source_name= " + "device= record= " + "playback= " + "format= " + "channels= " + "rate= " + "buffer_size= " + "channel_map=") struct userdata { pa_sink *sink; @@ -88,6 +97,7 @@ static const char* const valid_modargs[] = { "format", "rate", "channels", + "channel_map", NULL }; @@ -486,6 +496,7 @@ int pa__init(pa_core *c, pa_module*m) { int mode; int record = 1, playback = 1; pa_sample_spec ss; + pa_channel_map map; pa_modargs *ma = NULL; struct timeval tv; assert(c && m); @@ -514,7 +525,7 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { pa_log(__FILE__": failed to parse sample specification"); goto fail; } @@ -535,7 +546,7 @@ int pa__init(pa_core *c, pa_module*m) { u->core = c; if (mode != O_WRONLY) { - u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map); assert(u->source); u->source->userdata = u; u->source->get_latency = source_get_latency_cb; @@ -547,7 +558,7 @@ int pa__init(pa_core *c, pa_module*m) { u->source = NULL; if (mode != O_RDONLY) { - u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); + u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; u->sink->get_hw_volume = sink_get_hw_volume_cb; -- cgit From 22c679e393b234158b953b04956c886cbf1a2a5d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 27 Apr 2006 05:43:27 +0000 Subject: Clarify how the automatic channel map is generated. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@816 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/channelmap.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/polyp/channelmap.h b/src/polyp/channelmap.h index 76380b5f..0fd1e593 100644 --- a/src/polyp/channelmap.h +++ b/src/polyp/channelmap.h @@ -137,7 +137,9 @@ pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m); /** Initialize the specified channel map for stereophonic audio and return a pointer to it */ pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m); -/** Initialize the specified channel map for the specified number of channels using default labels and return a pointer to it */ +/** Initialize the specified channel map for the specified number + * of channels using default labels and return a pointer to it. + * Uses the mapping from RFC3551, which is based on AIFF-C. */ pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels); /** Return a text label for the specified channel position */ -- cgit From cd93661dcbe04081617d932058f472bd496ad3d2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 27 Apr 2006 22:59:54 +0000 Subject: ouch! fix brown paperbag bug which was triggered when runnign "pavumeter" and specifying a sink on the command line. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@817 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/namereg.c | 4 ++-- src/polypcore/protocol-native.c | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/polypcore/namereg.c b/src/polypcore/namereg.c index d4dbd14b..9229a0f9 100644 --- a/src/polypcore/namereg.c +++ b/src/polypcore/namereg.c @@ -127,7 +127,7 @@ void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int a return NULL; if (c->namereg && (e = pa_hashmap_get(c->namereg, name))) - if (e->type == e->type) + if (e->type == type) return e->data; if (pa_atou(name, &idx) < 0) { @@ -136,7 +136,7 @@ void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int a pa_autoload_request(c, name, type); if (c->namereg && (e = pa_hashmap_get(c->namereg, name))) - if (e->type == e->type) + if (e->type == type) return e->data; } diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index ace9db6f..a0fc286d 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -1347,7 +1347,6 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u pa_tagstruct *reply; assert(c && t); - if (pa_tagstruct_getu32(t, &idx) < 0 || (command != PA_COMMAND_GET_CLIENT_INFO && command != PA_COMMAND_GET_MODULE_INFO && -- cgit From 53930f4455dddc44fd260b151839aef0c76ce433 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 28 Apr 2006 07:28:48 +0000 Subject: Zero the fd list since we do a memcmp on it later. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@818 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index dcc0e020..8bb33c2f 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -122,7 +122,7 @@ static void defer_cb(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event* e, void *u pa_xfree(fdl->fds); if (fdl->work_fds) pa_xfree(fdl->work_fds); - fdl->fds = pa_xmalloc(sizeof(struct pollfd) * num_fds); + fdl->fds = pa_xmalloc0(sizeof(struct pollfd) * num_fds); fdl->work_fds = pa_xmalloc(sizeof(struct pollfd) * num_fds); } -- cgit From 6060bff186e028dfc2d90ffb69869b93f9ec01f5 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 28 Apr 2006 07:29:32 +0000 Subject: When a control is removed, all bits are set so we need to test for that first. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@819 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-sink.c | 3 +++ src/modules/module-alsa-source.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 2c2f1f3e..84b506e1 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -168,6 +168,9 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { assert(u && u->mixer_handle); + if (mask == SND_CTL_EVENT_MASK_REMOVE) + return 0; + if (mask & SND_CTL_EVENT_MASK_VALUE) { if (u->sink->get_hw_volume) u->sink->get_hw_volume(u->sink); diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index e4938917..84ae992b 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -168,6 +168,9 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { assert(u && u->mixer_handle); + if (mask == SND_CTL_EVENT_MASK_REMOVE) + return 0; + if (mask & SND_CTL_EVENT_MASK_VALUE) { if (u->source->get_hw_volume) u->source->get_hw_volume(u->source); -- cgit From 19c9dbf3614ba911b7d831f362ac04598226a83d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 28 Apr 2006 11:33:22 +0000 Subject: fix date git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@820 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/README.html.in b/doc/README.html.in index 2ed75edf..5c6e49a7 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -43,7 +43,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    News

    -
    Wed Apr 26 2006:

    Fri Apr 28 2006:

    Version 0.8.1 released; changes include: support for specifying the channel map on the command lines of paplay and pacat and as -- cgit From f2fbceb333421afb98c7d63b8f417bb43442e80f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 30 Apr 2006 23:33:04 +0000 Subject: * make sure the wakeup fd is polled on wven when no other fd is registered for polling * initialize mainloop return value to -1 * some optimizations git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@822 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/mainloop.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/polyp/mainloop.c b/src/polyp/mainloop.c index 42a411d3..98b3f3c6 100644 --- a/src/polyp/mainloop.c +++ b/src/polyp/mainloop.c @@ -301,10 +301,7 @@ static void mainloop_quit(pa_mainloop_api*a, int retval) { m = a->userdata; assert(a == &m->api); - m->quit = 1; - m->retval = retval; - - pa_mainloop_wakeup(m); + pa_mainloop_quit(m, retval); } static const pa_mainloop_api vtable = { @@ -355,7 +352,8 @@ pa_mainloop *pa_mainloop_new(void) { m->io_events_scan_dead = m->defer_events_scan_dead = m->time_events_scan_dead = 0; m->pollfds = NULL; - m->max_pollfds = m->n_pollfds = m->rebuild_pollfds = 0; + m->max_pollfds = m->n_pollfds = 0; + m->rebuild_pollfds = 1; m->quit = m->retval = 0; @@ -368,6 +366,8 @@ pa_mainloop *pa_mainloop_new(void) { m->poll_func = NULL; m->poll_func_userdata = NULL; + + m->retval = -1; return m; } @@ -419,7 +419,7 @@ static int defer_foreach(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void*use void pa_mainloop_free(pa_mainloop* m) { int all = 1; - assert(m && (m->state != STATE_POLLING)); + assert(m); pa_idxset_foreach(m->io_events, io_foreach, &all); pa_idxset_foreach(m->time_events, time_foreach, &all); @@ -772,10 +772,12 @@ int pa_mainloop_run(pa_mainloop *m, int *retval) { return 0; } -void pa_mainloop_quit(pa_mainloop *m, int r) { +void pa_mainloop_quit(pa_mainloop *m, int retval) { assert(m); + + m->quit = 1; + m->retval = retval; pa_mainloop_wakeup(m); - m->quit = r; } pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m) { -- cgit From 9e60bad5c3cb938b250e04e2048fdc46353c5719 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 30 Apr 2006 23:34:17 +0000 Subject: add new threaded main loop implementation (with test/example) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@823 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 8 ++ src/polyp/thread-mainloop.c | 203 +++++++++++++++++++++++++++++++++++++++ src/polyp/thread-mainloop.h | 58 +++++++++++ src/tests/thread-mainloop-test.c | 73 ++++++++++++++ 4 files changed, 342 insertions(+) create mode 100644 src/polyp/thread-mainloop.c create mode 100644 src/polyp/thread-mainloop.h create mode 100644 src/tests/thread-mainloop-test.c diff --git a/src/Makefile.am b/src/Makefile.am index fbb14702..8ad4859e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -181,6 +181,7 @@ pabrowse_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) noinst_PROGRAMS = \ mainloop-test \ + thread-mainloop-test \ mcalign-test \ pacat-simple \ parec-simple \ @@ -211,6 +212,11 @@ mainloop_test_CFLAGS = $(AM_CFLAGS) mainloop_test_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la mainloop_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +thread_mainloop_test_SOURCES = tests/thread-mainloop-test.c +thread_mainloop_test_CFLAGS = $(AM_CFLAGS) +thread_mainloop_test_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la +thread_mainloop_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + mcalign_test_SOURCES = tests/mcalign-test.c mcalign_test_CFLAGS = $(AM_CFLAGS) mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpolypcore.la @@ -290,6 +296,7 @@ polypinclude_HEADERS = \ polyp/mainloop.h \ polyp/mainloop-api.h \ polyp/mainloop-signal.h \ + polyp/thread-mainloop.h \ polyp/polypaudio.h \ polyp/context.h \ polyp/def.h \ @@ -348,6 +355,7 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = \ polyp/volume.c polyp/volume.h \ polyp/mainloop.c polyp/mainloop.h \ polyp/mainloop-signal.c polyp/mainloop-signal.h \ + polyp/thread-mainloop.c polyp/thread-mainloop.h \ polypcore/poll.c polypcore/poll.h # Internal stuff that is shared with libpolypcore diff --git a/src/polyp/thread-mainloop.c b/src/polyp/thread-mainloop.c new file mode 100644 index 00000000..894e037f --- /dev/null +++ b/src/polyp/thread-mainloop.c @@ -0,0 +1,203 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include + +#include "mainloop.h" +#include "thread-mainloop.h" + +struct pa_threaded_mainloop { + pa_mainloop *real_mainloop; + pthread_t thread_id; + pthread_mutex_t mutex; + pthread_cond_t cond; + int thread_running; +}; + +static int poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) { + pthread_mutex_t *mutex = userdata; + int r; + + assert(mutex); + + /* Before entering poll() we unlock the mutex, so that + * avahi_simple_poll_quit() can succeed from another thread. */ + + pthread_mutex_unlock(mutex); + r = poll(ufds, nfds, timeout); + pthread_mutex_lock(mutex); + + return r; +} + +static void* thread(void *userdata){ + pa_threaded_mainloop *m = userdata; + sigset_t mask; + + /* Make sure that signals are delivered to the main thread */ + sigfillset(&mask); + pthread_sigmask(SIG_BLOCK, &mask, NULL); + + pthread_mutex_lock(&m->mutex); + pa_mainloop_run(m->real_mainloop, NULL); + pthread_mutex_unlock(&m->mutex); + + return NULL; +} + +pa_threaded_mainloop *pa_threaded_mainloop_new(void) { + pa_threaded_mainloop *m; + pthread_mutexattr_t a; + + m = pa_xnew(pa_threaded_mainloop, 1); + + if (!(m->real_mainloop = pa_mainloop_new())) { + pa_xfree(m); + return NULL; + } + + pa_mainloop_set_poll_func(m->real_mainloop, poll_func, &m->mutex); + + pthread_mutexattr_init(&a); + pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&m->mutex, NULL); + pthread_mutexattr_destroy(&a); + + pthread_cond_init(&m->cond, NULL); + m->thread_running = 0; + + return m; +} + +void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { + assert(m); + + /* Make sure that this function is not called from the helper thread */ + assert(!m->thread_running || !pthread_equal(pthread_self(), m->thread_id)); + + if (m->thread_running) + pa_threaded_mainloop_stop(m); + + if (m->real_mainloop) + pa_mainloop_free(m->real_mainloop); + + pthread_mutex_destroy(&m->mutex); + pthread_cond_destroy(&m->cond); + + pa_xfree(m); +} + +int pa_threaded_mainloop_start(pa_threaded_mainloop *m) { + assert(m); + + assert(!m->thread_running); + + pthread_mutex_lock(&m->mutex); + + if (pthread_create(&m->thread_id, NULL, thread, m) < 0) { + pthread_mutex_unlock(&m->mutex); + return -1; + } + + m->thread_running = 1; + + pthread_mutex_unlock(&m->mutex); + + return 0; +} + +void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) { + assert(m); + + if (!m->thread_running) + return; + + /* Make sure that this function is not called from the helper thread */ + assert(!pthread_equal(pthread_self(), m->thread_id)); + + pthread_mutex_lock(&m->mutex); + pa_mainloop_quit(m->real_mainloop, 0); + pthread_mutex_unlock(&m->mutex); + + pthread_join(m->thread_id, NULL); + m->thread_running = 0; + + return; +} + +void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) { + assert(m); + + /* Make sure that this function is not called from the helper thread */ + assert(!m->thread_running || !pthread_equal(pthread_self(), m->thread_id)); + + pthread_mutex_lock(&m->mutex); +} + +void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { + assert(m); + + /* Make sure that this function is not called from the helper thread */ + assert(!m->thread_running || !pthread_equal(pthread_self(), m->thread_id)); + + pthread_mutex_unlock(&m->mutex); +} + +void pa_threaded_mainloop_signal(pa_threaded_mainloop *m) { + assert(m); + + /* Make sure that this function is called from the helper thread */ + assert(m->thread_running && pthread_equal(pthread_self(), m->thread_id)); + + pthread_cond_broadcast(&m->cond); +} + +void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { + assert(m); + + /* Make sure that this function is not called from the helper thread */ + assert(!m->thread_running || !pthread_equal(pthread_self(), m->thread_id)); + + pthread_cond_wait(&m->cond, &m->mutex); +} + +int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) { + assert(m); + + return pa_mainloop_get_retval(m->real_mainloop); +} + +pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) { + assert(m); + + return pa_mainloop_get_api(m->real_mainloop); +} + diff --git a/src/polyp/thread-mainloop.h b/src/polyp/thread-mainloop.h new file mode 100644 index 00000000..8e53de58 --- /dev/null +++ b/src/polyp/thread-mainloop.h @@ -0,0 +1,58 @@ +#ifndef foothreadmainloophfoo +#define foothreadmainloophfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +PA_C_DECL_BEGIN + +/** \file + * + * A thread based main loop implementation based on pa_mainloop.*/ + +/** An opaque main loop object */ +typedef struct pa_threaded_mainloop pa_threaded_mainloop; + +/** Allocate a new main loop object */ +pa_threaded_mainloop *pa_threaded_mainloop_new(void); + +/** Free a main loop object */ +void pa_threaded_mainloop_free(pa_threaded_mainloop* m); + +int pa_threaded_mainloop_start(pa_threaded_mainloop *m); +void pa_threaded_mainloop_stop(pa_threaded_mainloop *m); +void pa_threaded_mainloop_lock(pa_threaded_mainloop *m); +void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m); +void pa_threaded_mainloop_signal(pa_threaded_mainloop *m); +void pa_threaded_mainloop_wait(pa_threaded_mainloop *m); + +/** Return the return value as specified with the main loop's quit() routine. */ +int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m); + +/** Return the abstract main loop abstraction layer vtable for this main loop. */ +pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m); + +PA_C_DECL_END + +#endif diff --git a/src/tests/thread-mainloop-test.c b/src/tests/thread-mainloop-test.c new file mode 100644 index 00000000..8232c4a3 --- /dev/null +++ b/src/tests/thread-mainloop-test.c @@ -0,0 +1,73 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include + +static void tcb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) { + fprintf(stderr, "TIME EVENT\n"); + pa_threaded_mainloop_signal(userdata); +} + +int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { + pa_mainloop_api *a; + pa_threaded_mainloop *m; + struct timeval tv; + + m = pa_threaded_mainloop_new(); + assert(m); + a = pa_threaded_mainloop_get_api(m); + assert(a); + + pa_threaded_mainloop_start(m); + + pa_threaded_mainloop_lock(m); + + pa_gettimeofday(&tv); + tv.tv_sec += 5; + a->time_new(a, &tv, tcb, m); + + fprintf(stderr, "waiting 5s (signal)\n"); + pa_threaded_mainloop_wait(m); + fprintf(stderr, "wait completed\n"); + + pa_threaded_mainloop_unlock(m); + + fprintf(stderr, "waiting 5s (sleep)\n"); + sleep(5); + + fprintf(stderr, "shutting down\n"); + + pa_threaded_mainloop_stop(m); + + pa_threaded_mainloop_free(m); + return 0; +} -- cgit From 1438bd49dc9bd5b7e57f9a75c6760ae769ee37bf Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 2 May 2006 08:41:41 +0000 Subject: Windows doesn't have POSIX thread. ifdef out things for now. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@824 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 7 ++++++- src/polyp/thread-mainloop.c | 19 +++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 8ad4859e..66e20af5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -181,7 +181,6 @@ pabrowse_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) noinst_PROGRAMS = \ mainloop-test \ - thread-mainloop-test \ mcalign-test \ pacat-simple \ parec-simple \ @@ -207,6 +206,12 @@ noinst_PROGRAMS += \ mainloop-test-glib12 endif +# FIXME: We need to make thread-mainloop win32-compatible first +if !OS_IS_WIN32 +noinst_PROGRAMS += \ + thread-mainloop-test +endif + mainloop_test_SOURCES = tests/mainloop-test.c mainloop_test_CFLAGS = $(AM_CFLAGS) mainloop_test_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la diff --git a/src/polyp/thread-mainloop.c b/src/polyp/thread-mainloop.c index 894e037f..32be494d 100644 --- a/src/polyp/thread-mainloop.c +++ b/src/polyp/thread-mainloop.c @@ -23,17 +23,27 @@ #include #endif -#include #include #include -#include #include +#ifdef HAVE_SYS_POLL_H +#include +#else +#include "../polypcore/poll.h" +#endif + +#ifdef HAVE_PTHREAD +#include +#endif + #include #include "mainloop.h" #include "thread-mainloop.h" +#ifndef OS_IS_WIN32 + struct pa_threaded_mainloop { pa_mainloop *real_mainloop; pthread_t thread_id; @@ -201,3 +211,8 @@ pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) { return pa_mainloop_get_api(m->real_mainloop); } +#else /* OS_IS_WIN32 */ + +// FIXME: Use Win32 primitives + +#endif /* OS_IS_WIN32 */ -- cgit From 27cee2ef52274fe0cb98eded2c7394a5069c3ce8 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 2 May 2006 09:50:37 +0000 Subject: We need to read the cookie in binary mode for things to work correctly. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@825 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/authkey.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/polypcore/authkey.c b/src/polypcore/authkey.c index 80480c16..6eafb672 100644 --- a/src/polypcore/authkey.c +++ b/src/polypcore/authkey.c @@ -59,6 +59,10 @@ static int generate(int fd, void *ret_data, size_t length) { return 0; } +#ifndef O_BINARY +#define O_BINARY 0 +#endif + /* Load an euthorization cookie from file fn and store it in data. If * the cookie file doesn't exist, create it */ static int load(const char *fn, void *data, size_t length) { @@ -68,8 +72,8 @@ static int load(const char *fn, void *data, size_t length) { ssize_t r; assert(fn && data && length); - if ((fd = open(fn, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { - if (errno != EACCES || (fd = open(fn, O_RDONLY)) < 0) { + if ((fd = open(fn, O_RDWR|O_CREAT|O_BINARY, S_IRUSR|S_IWUSR)) < 0) { + if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY)) < 0) { pa_log(__FILE__": failed to open cookie file '%s': %s", fn, strerror(errno)); goto finish; } else @@ -84,6 +88,7 @@ static int load(const char *fn, void *data, size_t length) { } if ((size_t) r != length) { + pa_log_debug(__FILE__": got %d bytes from cookie file '%s', expected %d", (int)r, fn, (int)length); if (!writable) { pa_log(__FILE__": unable to write cookie to read only file"); -- cgit From c2c9f251004f4f688d1a9a20d1ec19ea3513a60a Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 2 May 2006 11:27:24 +0000 Subject: Fix control flow in pa_oss_open(). Also fall back to half duplex when device doesn't support full. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@826 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/oss-util.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index fac39e7b..2c573b2f 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -56,9 +56,11 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { } if (*tcaps & DSP_CAP_DUPLEX) - return fd; + goto success; - goto fail; + pa_log_warn(__FILE__": '%s' doesn't support full duplex", device); + + close(fd); } if ((fd = open(device, (*mode = O_WRONLY)|O_NDELAY)) < 0) { @@ -74,6 +76,8 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { } } +success: + if (pcaps) { if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s", strerror(errno)); -- cgit From 4cff5d3150297830bc7b348dc9fe238cc663d97f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 3 May 2006 08:56:03 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@827 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/todo b/doc/todo index 4d642286..f7765cde 100644 --- a/doc/todo +++ b/doc/todo @@ -18,6 +18,11 @@ Post 0.8: - double check channel maps for backends, including that mixer and pcm match - paplay needs to set a channel map. our default is only correct for AIFF. (we need help from libsndfile for this) +- silence generation should be moved into the core to avoid races and code + duplication in the backends +- examine if it is possible to mimic esd's handling of half duplex cards + (switch to capture when a recording client connects and drop playback during + that time) Long term: - pass meta info for hearing impaired -- cgit From 3f92e3efa92d946e0410bc78d7329039b4ad6f47 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 6 May 2006 16:38:09 +0000 Subject: allow signalling from event loop thread git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@828 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/thread-mainloop.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/polyp/thread-mainloop.c b/src/polyp/thread-mainloop.c index 32be494d..51fafe92 100644 --- a/src/polyp/thread-mainloop.c +++ b/src/polyp/thread-mainloop.c @@ -184,9 +184,6 @@ void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { void pa_threaded_mainloop_signal(pa_threaded_mainloop *m) { assert(m); - /* Make sure that this function is called from the helper thread */ - assert(m->thread_running && pthread_equal(pthread_self(), m->thread_id)); - pthread_cond_broadcast(&m->cond); } -- cgit From bb6c45dee8b2627527429e65637354635cc98ea1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 6 May 2006 20:55:53 +0000 Subject: remove bogus check that disallowed latency interpolation and stuff for record streams git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@829 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/stream.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/polyp/stream.c b/src/polyp/stream.c index c86a200a..2c4e882c 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -464,7 +464,6 @@ static int create_stream( PA_STREAM_INTERPOLATE_TIMING| PA_STREAM_NOT_MONOTONOUS| PA_STREAM_AUTO_TIMING_UPDATE : 0))), PA_ERR_INVALID); - PA_CHECK_VALIDITY(s->context, direction == PA_STREAM_PLAYBACK || flags == 0, PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, !volume || volume->channels == s->sample_spec.channels, PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, !sync_stream || (direction == PA_STREAM_PLAYBACK && sync_stream->direction == PA_STREAM_PLAYBACK), PA_ERR_INVALID); -- cgit From 5f9bbf005a81a0f7d009e3fad3f6a4e8d4c5e6bb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 6 May 2006 20:56:43 +0000 Subject: add support for reading audio data from a file instead of plain STDIN in pacat-simple.c git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@830 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/tests/pacat-simple.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/tests/pacat-simple.c b/src/tests/pacat-simple.c index 0382ec06..6a75c790 100644 --- a/src/tests/pacat-simple.c +++ b/src/tests/pacat-simple.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,23 @@ int main(PA_GCC_UNUSED int argc, char*argv[]) { int ret = 1; int error; + /* replace STDIN with the specified file if needed */ + if (argc > 1) { + int fd; + + if ((fd = open(argv[1], O_RDONLY)) < 0) { + fprintf(stderr, __FILE__": open() failed: %s\n", strerror(errno)); + goto finish; + } + + if (dup2(fd, STDIN_FILENO) < 0) { + fprintf(stderr, __FILE__": dup2() failed: %s\n", strerror(errno)); + goto finish; + } + + close(fd); + } + /* Create a new playback stream */ if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, &error))) { fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); -- cgit From 4b4c8fd15293a332d3200f70d2244b0c1ed80874 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 6 May 2006 20:58:02 +0000 Subject: * optionally, make pa_threaded_mainloop_signal() wait until the main thread took over control * more header file comments git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@831 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/thread-mainloop.c | 17 ++++++++++++++--- src/polyp/thread-mainloop.h | 26 +++++++++++++++++++++++++- src/tests/thread-mainloop-test.c | 5 +++-- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/polyp/thread-mainloop.c b/src/polyp/thread-mainloop.c index 51fafe92..62813acd 100644 --- a/src/polyp/thread-mainloop.c +++ b/src/polyp/thread-mainloop.c @@ -48,7 +48,8 @@ struct pa_threaded_mainloop { pa_mainloop *real_mainloop; pthread_t thread_id; pthread_mutex_t mutex; - pthread_cond_t cond; + int n_waiting; + pthread_cond_t cond, release_cond; int thread_running; }; @@ -98,11 +99,13 @@ pa_threaded_mainloop *pa_threaded_mainloop_new(void) { pthread_mutexattr_init(&a); pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&m->mutex, NULL); + pthread_mutex_init(&m->mutex, &a); pthread_mutexattr_destroy(&a); pthread_cond_init(&m->cond, NULL); + pthread_cond_init(&m->release_cond, NULL); m->thread_running = 0; + m->n_waiting = 0; return m; } @@ -121,6 +124,7 @@ void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { pthread_mutex_destroy(&m->mutex); pthread_cond_destroy(&m->cond); + pthread_cond_destroy(&m->release_cond); pa_xfree(m); } @@ -181,10 +185,13 @@ void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { pthread_mutex_unlock(&m->mutex); } -void pa_threaded_mainloop_signal(pa_threaded_mainloop *m) { +void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_release) { assert(m); pthread_cond_broadcast(&m->cond); + + if (wait_for_release && m->n_waiting > 0) + pthread_cond_wait(&m->release_cond, &m->mutex); } void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { @@ -193,7 +200,11 @@ void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { /* Make sure that this function is not called from the helper thread */ assert(!m->thread_running || !pthread_equal(pthread_self(), m->thread_id)); + m->n_waiting ++; pthread_cond_wait(&m->cond, &m->mutex); + assert(m->n_waiting > 0); + m->n_waiting --; + pthread_cond_signal(&m->release_cond); } int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) { diff --git a/src/polyp/thread-mainloop.h b/src/polyp/thread-mainloop.h index 8e53de58..d4762e27 100644 --- a/src/polyp/thread-mainloop.h +++ b/src/polyp/thread-mainloop.h @@ -40,13 +40,37 @@ pa_threaded_mainloop *pa_threaded_mainloop_new(void); /** Free a main loop object */ void pa_threaded_mainloop_free(pa_threaded_mainloop* m); +/** Start the event loop thread. */ int pa_threaded_mainloop_start(pa_threaded_mainloop *m); + +/** Terminate the event loop thread cleanly */ void pa_threaded_mainloop_stop(pa_threaded_mainloop *m); + +/** Lock the event loop object, effectively blocking the event loop + * thread from processing events. You can use this to enforce + * exclusive access to all objects attached to the event loop. This + * function may not be called inside the event loop thread. */ void pa_threaded_mainloop_lock(pa_threaded_mainloop *m); + +/** Unlock the event loop object, inverse of pa_threaded_mainloop_lock() */ void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m); -void pa_threaded_mainloop_signal(pa_threaded_mainloop *m); + +/** Wait for an event to be signalled by the event loop thread. You + * can use this to pass data from the event loop thread to the main + * thread in synchronized fashion. This function may not be called + * inside the event loop thread. Prior to this call the event loop + * object needs to be locked using pa_threaded_mainloop_lock(). While + * waiting the lock will be released, immediately before returning it + * will be acquired again. */ void pa_threaded_mainloop_wait(pa_threaded_mainloop *m); +/** Signal all threads waiting for a signalling event in + * pa_threaded_mainloop_wait(). If wait_for_release is non-zero, do + * not return before the signal was accepted by a + * pa_threaded_mainloop_wait() call. While waiting for that condition + * the event loop object is unlocked. */ +void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_release); + /** Return the return value as specified with the main loop's quit() routine. */ int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m); diff --git a/src/tests/thread-mainloop-test.c b/src/tests/thread-mainloop-test.c index 8232c4a3..24e18b37 100644 --- a/src/tests/thread-mainloop-test.c +++ b/src/tests/thread-mainloop-test.c @@ -33,8 +33,9 @@ #include static void tcb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) { - fprintf(stderr, "TIME EVENT\n"); - pa_threaded_mainloop_signal(userdata); + fprintf(stderr, "TIME EVENT START\n"); + pa_threaded_mainloop_signal(userdata, 1); + fprintf(stderr, "TIME EVENT END\n"); } int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { -- cgit From df3306c4affdf31abce1bf2cf545b6ac8ecb0f10 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 6 May 2006 20:58:28 +0000 Subject: rework the simple API to make use of the new threaded mainloop implementation git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@832 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/simple.c | 452 ++++++++++++++++++++++++++--------------------------- 1 file changed, 226 insertions(+), 226 deletions(-) diff --git a/src/polyp/simple.c b/src/polyp/simple.c index dbf7a325..97dcaf11 100644 --- a/src/polyp/simple.c +++ b/src/polyp/simple.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include @@ -37,91 +37,92 @@ #include "simple.h" -#define CHECK_VALIDITY_RETURN_ANY(rerror, expression, error, ret) do { \ -if (!(expression)) { \ - if (rerror) \ - *(rerror) = error; \ - return ret; \ - } \ -} while(0); - struct pa_simple { - pa_mainloop *mainloop; + pa_threaded_mainloop *mainloop; pa_context *context; pa_stream *stream; pa_stream_direction_t direction; - int dead; - const void *read_data; size_t read_index, read_length; - pa_usec_t latency; -}; -static int check_error(pa_simple *p, int *rerror) { - pa_context_state_t cst; - pa_stream_state_t sst; - assert(p); - - if ((cst = pa_context_get_state(p->context)) == PA_CONTEXT_FAILED) - goto fail; - - assert(cst != PA_CONTEXT_TERMINATED); + int operation_success; +}; - if (p->stream) { - if ((sst = pa_stream_get_state(p->stream)) == PA_STREAM_FAILED) - goto fail; - - assert(sst != PA_STREAM_TERMINATED); - } - - return 0; - -fail: - if (rerror) - *rerror = pa_context_errno(p->context); +#define CHECK_VALIDITY_RETURN_ANY(rerror, expression, error, ret) do { \ +if (!(expression)) { \ + if (rerror) \ + *(rerror) = error; \ + return (ret); \ + } \ +} while(0); - p->dead = 1; +#define CHECK_SUCCESS_GOTO(p, rerror, expression, label) do { \ +if (!(expression)) { \ + if (rerror) \ + *(rerror) = pa_context_errno((p)->context); \ + goto label; \ + } \ +} while(0); - return -1; -} +#define CHECK_DEAD_GOTO(p, rerror, label) do { \ +if (!(p)->context || pa_context_get_state((p)->context) != PA_CONTEXT_READY || \ + !(p)->stream || pa_stream_get_state((p)->stream) != PA_STREAM_READY) { \ + if (((p)->context && pa_context_get_state((p)->context) == PA_CONTEXT_FAILED) || \ + ((p)->stream && pa_stream_get_state((p)->stream) == PA_STREAM_FAILED)) { \ + if (rerror) \ + *(rerror) = pa_context_errno((p)->context); \ + } else \ + if (rerror) \ + *(rerror) = PA_ERR_BADSTATE; \ + goto label; \ + } \ +} while(0); -static int iterate(pa_simple *p, int block, int *rerror) { - assert(p && p->context && p->mainloop); +static void context_state_cb(pa_context *c, void *userdata) { + pa_simple *p = userdata; + assert(c); + assert(p); - if (check_error(p, rerror) < 0) - return -1; + switch (pa_context_get_state(c)) { + case PA_CONTEXT_READY: + case PA_CONTEXT_TERMINATED: + case PA_CONTEXT_FAILED: + pa_threaded_mainloop_signal(p->mainloop, 0); + break; - if (block || pa_context_is_pending(p->context)) { - do { - if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) { - if (rerror) - *rerror = PA_ERR_INTERNAL; - return -1; - } - - if (check_error(p, rerror) < 0) - return -1; - } while (pa_context_is_pending(p->context)); + case PA_CONTEXT_UNCONNECTED: + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; } +} - for (;;) { - int r; +static void stream_state_cb(pa_stream *s, void * userdata) { + pa_simple *p = userdata; + assert(s); + assert(p); - if ((r = pa_mainloop_iterate(p->mainloop, 0, NULL)) < 0) { - if (rerror) - *rerror = PA_ERR_INTERNAL; - return -1; - } + switch (pa_stream_get_state(s)) { - if (r == 0) + case PA_STREAM_READY: + case PA_STREAM_FAILED: + case PA_STREAM_TERMINATED: + pa_threaded_mainloop_signal(p->mainloop, 0); break; - if (check_error(p, rerror) < 0) - return -1; + case PA_STREAM_UNCONNECTED: + case PA_STREAM_CREATING: + break; } - - return 0; +} + +static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { + pa_simple *p = userdata; + assert(p); + + pa_threaded_mainloop_signal(p->mainloop, 0); } pa_simple* pa_simple_new( @@ -145,50 +146,70 @@ pa_simple* pa_simple_new( p = pa_xnew(pa_simple, 1); p->context = NULL; p->stream = NULL; - p->mainloop = pa_mainloop_new(); - assert(p->mainloop); - p->dead = 0; p->direction = dir; p->read_data = NULL; p->read_index = p->read_length = 0; - p->latency = 0; - if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name))) + if (!(p->mainloop = pa_threaded_mainloop_new())) goto fail; + if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), name))) + goto fail; + + pa_context_set_state_callback(p->context, context_state_cb, p); + if (pa_context_connect(p->context, server, 0, NULL) < 0) { error = pa_context_errno(p->context); goto fail; } - + + pa_threaded_mainloop_lock(p->mainloop); + + if (pa_threaded_mainloop_start(p->mainloop) < 0) + goto unlock_and_fail; + /* Wait until the context is ready */ - while (pa_context_get_state(p->context) != PA_CONTEXT_READY) { - if (iterate(p, 1, &error) < 0) - goto fail; + pa_threaded_mainloop_wait(p->mainloop); + + if (pa_context_get_state(p->context) != PA_CONTEXT_READY) { + error = pa_context_errno(p->context); + goto unlock_and_fail; } if (!(p->stream = pa_stream_new(p->context, stream_name, ss, NULL))) { error = pa_context_errno(p->context); - goto fail; + goto unlock_and_fail; } + pa_stream_set_state_callback(p->stream, stream_state_cb, p); + pa_stream_set_read_callback(p->stream, stream_request_cb, p); + pa_stream_set_write_callback(p->stream, stream_request_cb, p); + if (dir == PA_STREAM_PLAYBACK) - r = pa_stream_connect_playback(p->stream, dev, attr, 0, NULL, NULL); + r = pa_stream_connect_playback(p->stream, dev, attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); else - r = pa_stream_connect_record(p->stream, dev, attr, 0); + r = pa_stream_connect_record(p->stream, dev, attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE); if (r < 0) { error = pa_context_errno(p->context); - goto fail; + goto unlock_and_fail; } /* Wait until the stream is ready */ - while (pa_stream_get_state(p->stream) != PA_STREAM_READY) { - if (iterate(p, 1, &error) < 0) - goto fail; + pa_threaded_mainloop_wait(p->mainloop); + + /* Wait until the stream is ready */ + if (pa_stream_get_state(p->stream) != PA_STREAM_READY) { + error = pa_context_errno(p->context); + goto unlock_and_fail; } + pa_threaded_mainloop_unlock(p->mainloop); + return p; + +unlock_and_fail: + pa_threaded_mainloop_unlock(p->mainloop); fail: if (rerror) @@ -200,6 +221,9 @@ fail: void pa_simple_free(pa_simple *s) { assert(s); + if (s->mainloop) + pa_threaded_mainloop_stop(s->mainloop); + if (s->stream) pa_stream_unref(s->stream); @@ -207,232 +231,208 @@ void pa_simple_free(pa_simple *s) { pa_context_unref(s->context); if (s->mainloop) - pa_mainloop_free(s->mainloop); + pa_threaded_mainloop_free(s->mainloop); pa_xfree(s); } int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { assert(p); - assert(data); - + CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); + CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1); - if (p->dead) { - if (rerror) - *rerror = pa_context_errno(p->context); - - return -1; - } + pa_threaded_mainloop_lock(p->mainloop); + + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); while (length > 0) { size_t l; + int r; - while (!(l = pa_stream_writable_size(p->stream))) - if (iterate(p, 1, rerror) < 0) - return -1; + while (!(l = pa_stream_writable_size(p->stream))) { + pa_threaded_mainloop_wait(p->mainloop); + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); + } + CHECK_SUCCESS_GOTO(p, rerror, l != (size_t) -1, unlock_and_fail); + if (l > length) l = length; - pa_stream_write(p->stream, data, l, NULL, 0, PA_SEEK_RELATIVE); + r = pa_stream_write(p->stream, data, l, NULL, 0, PA_SEEK_RELATIVE); + CHECK_SUCCESS_GOTO(p, rerror, r >= 0, unlock_and_fail); + data = (const uint8_t*) data + l; length -= l; } - /* Make sure that no data is pending for write */ - if (iterate(p, 0, rerror) < 0) - return -1; - + pa_threaded_mainloop_unlock(p->mainloop); return 0; + +unlock_and_fail: + pa_threaded_mainloop_unlock(p->mainloop); + return -1; } int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { assert(p); - assert(data); CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, -1); + CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1); + + pa_threaded_mainloop_lock(p->mainloop); - if (p->dead) { - if (rerror) - *rerror = pa_context_errno(p->context); - - return -1; - } - + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); + while (length > 0) { + size_t l; + + while (!p->read_data) { + int r; + + r = pa_stream_peek(p->stream, &p->read_data, &p->read_length); + CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail); - if (!p->read_data) - if (pa_stream_peek(p->stream, &p->read_data, &p->read_length) >= 0) + if (!p->read_data) { + pa_threaded_mainloop_wait(p->mainloop); + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); + } else p->read_index = 0; + } - if (p->read_data) { - size_t l = length; - - if (p->read_length <= l) - l = p->read_length; + l = p->read_length < length ? p->read_length : length; + memcpy(data, (const uint8_t*) p->read_data+p->read_index, l); - memcpy(data, (const uint8_t*) p->read_data+p->read_index, l); + data = (uint8_t*) data + l; + length -= l; + + p->read_index += l; + p->read_length -= l; - data = (uint8_t*) data + l; - length -= l; + if (!p->read_length) { + int r; - p->read_index += l; - p->read_length -= l; - - if (!p->read_length) { - pa_stream_drop(p->stream); - p->read_data = NULL; - p->read_length = 0; - p->read_index = 0; - } + r = pa_stream_drop(p->stream); + p->read_data = NULL; + p->read_length = 0; + p->read_index = 0; - if (!length) - return 0; - - assert(!p->read_data); + CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail); } - - if (iterate(p, 1, rerror) < 0) - return -1; } + pa_threaded_mainloop_unlock(p->mainloop); return 0; + +unlock_and_fail: + pa_threaded_mainloop_unlock(p->mainloop); + return -1; } -static void drain_or_flush_complete(pa_stream *s, int success, void *userdata) { +static void success_cb(pa_stream *s, int success, void *userdata) { pa_simple *p = userdata; assert(s); assert(p); - - if (!success) - p->dead = 1; + + p->operation_success = success; + pa_threaded_mainloop_signal(p->mainloop, 0); } int pa_simple_drain(pa_simple *p, int *rerror) { - pa_operation *o; + pa_operation *o = NULL; assert(p); CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); - if (p->dead) { - if (rerror) - *rerror = pa_context_errno(p->context); - - return -1; - } + pa_threaded_mainloop_lock(p->mainloop); + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - if (!(o = pa_stream_drain(p->stream, drain_or_flush_complete, p))) { - if (rerror) - *rerror = pa_context_errno(p->context); - return -1; - } + o = pa_stream_drain(p->stream, success_cb, p); + CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); - while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { - if (iterate(p, 1, rerror) < 0) { - pa_operation_cancel(o); - pa_operation_unref(o); - return -1; - } + p->operation_success = 0; + while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + pa_threaded_mainloop_wait(p->mainloop); + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); } - + CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail); + pa_operation_unref(o); + pa_threaded_mainloop_unlock(p->mainloop); - if (p->dead && rerror) - *rerror = pa_context_errno(p->context); - - return p->dead ? -1 : 0; -} - -static void timing_complete(pa_stream *s, int success, void *userdata) { - pa_simple *p = userdata; + return 0; - assert(s); - assert(p); +unlock_and_fail: - if (!success) - p->dead = 1; - else { - int negative = 0; - if (pa_stream_get_latency(s, &p->latency, &negative) < 0) - p->dead = 1; - else if (negative) - p->latency = 0; + if (o) { + pa_operation_cancel(o); + pa_operation_unref(o); } + + pa_threaded_mainloop_unlock(p->mainloop); + return -1; } -pa_usec_t pa_simple_get_playback_latency(pa_simple *p, int *rerror) { - pa_operation *o; +int pa_simple_flush(pa_simple *p, int *rerror) { + pa_operation *o = NULL; assert(p); - + CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); - if (p->dead) { - if (rerror) - *rerror = pa_context_errno(p->context); - - return (pa_usec_t) -1; - } + pa_threaded_mainloop_lock(p->mainloop); + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - p->latency = 0; - if (!(o = pa_stream_update_timing_info(p->stream, timing_complete, p))) { - if (rerror) - *rerror = pa_context_errno(p->context); - return (pa_usec_t) -1; - } + o = pa_stream_flush(p->stream, success_cb, p); + CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); - while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { - - if (iterate(p, 1, rerror) < 0) { - pa_operation_cancel(o); - pa_operation_unref(o); - return -1; - } + p->operation_success = 0; + while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + pa_threaded_mainloop_wait(p->mainloop); + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); } + CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail); pa_operation_unref(o); - - if (p->dead && rerror) - *rerror = pa_context_errno(p->context); + pa_threaded_mainloop_unlock(p->mainloop); + + return 0; - return p->dead ? (pa_usec_t) -1 : p->latency; +unlock_and_fail: + + if (o) { + pa_operation_cancel(o); + pa_operation_unref(o); + } + + pa_threaded_mainloop_unlock(p->mainloop); + return -1; } -int pa_simple_flush(pa_simple *p, int *rerror) { - pa_operation *o; +pa_usec_t pa_simple_get_playback_latency(pa_simple *p, int *rerror) { + pa_usec_t t; + int r, negative; assert(p); + + CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, (pa_usec_t) -1); - CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); - - if (p->dead) { - if (rerror) - *rerror = pa_context_errno(p->context); - - return -1; - } - - if (!(o = pa_stream_flush(p->stream, drain_or_flush_complete, p))) { - if (rerror) - *rerror = pa_context_errno(p->context); - return -1; - } + pa_threaded_mainloop_lock(p->mainloop); + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { - if (iterate(p, 1, rerror) < 0) { - pa_operation_cancel(o); - pa_operation_unref(o); - return -1; - } - } + r = pa_stream_get_latency(p->stream, &t, &negative); + CHECK_SUCCESS_GOTO(p, rerror, r >= 0, unlock_and_fail); + + pa_threaded_mainloop_unlock(p->mainloop); - pa_operation_unref(o); + return negative ? 0 : t; - if (p->dead && rerror) - *rerror = pa_context_errno(p->context); +unlock_and_fail: - return p->dead ? -1 : 0; + pa_threaded_mainloop_unlock(p->mainloop); + return (pa_usec_t) -1; } + -- cgit From 06e1867307777ffa8686762ff3e42143d88b46ed Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 9 May 2006 08:38:37 +0000 Subject: Use pa_msleep() to get platform independence. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@833 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/tests/thread-mainloop-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/thread-mainloop-test.c b/src/tests/thread-mainloop-test.c index 24e18b37..1434deb9 100644 --- a/src/tests/thread-mainloop-test.c +++ b/src/tests/thread-mainloop-test.c @@ -63,7 +63,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { pa_threaded_mainloop_unlock(m); fprintf(stderr, "waiting 5s (sleep)\n"); - sleep(5); + pa_msleep(5000); fprintf(stderr, "shutting down\n"); -- cgit From 4e71f20d6cecff245a45233d4953beb4e0b29178 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 9 May 2006 08:39:26 +0000 Subject: Add stubs for the threaded main loop so that we can compile it on non-supported platforms (still can't run it though). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@834 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 9 ++------ src/polyp/thread-mainloop.c | 50 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 66e20af5..ee7b2325 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -188,7 +188,8 @@ noinst_PROGRAMS = \ voltest \ memblockq-test \ sync-playback \ - channelmap-test + channelmap-test \ + thread-mainloop-test if HAVE_SIGXCPU noinst_PROGRAMS += \ @@ -206,12 +207,6 @@ noinst_PROGRAMS += \ mainloop-test-glib12 endif -# FIXME: We need to make thread-mainloop win32-compatible first -if !OS_IS_WIN32 -noinst_PROGRAMS += \ - thread-mainloop-test -endif - mainloop_test_SOURCES = tests/mainloop-test.c mainloop_test_CFLAGS = $(AM_CFLAGS) mainloop_test_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la diff --git a/src/polyp/thread-mainloop.c b/src/polyp/thread-mainloop.c index 62813acd..6c14a1d3 100644 --- a/src/polyp/thread-mainloop.c +++ b/src/polyp/thread-mainloop.c @@ -42,7 +42,8 @@ #include "mainloop.h" #include "thread-mainloop.h" -#ifndef OS_IS_WIN32 +/* FIXME: Add defined(OS_IS_WIN32) when support is added */ +#if defined(HAVE_PTHREAD) struct pa_threaded_mainloop { pa_mainloop *real_mainloop; @@ -219,8 +220,49 @@ pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) { return pa_mainloop_get_api(m->real_mainloop); } -#else /* OS_IS_WIN32 */ +#else /* defined(OS_IS_WIN32) || defined(HAVE_PTHREAD) */ -// FIXME: Use Win32 primitives +pa_threaded_mainloop *pa_threaded_mainloop_new(void) { + pa_log_error(__FILE__": Threaded main loop not supported on this platform"); + return NULL; +} + +void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { + assert(0); +} + +int pa_threaded_mainloop_start(pa_threaded_mainloop *m) { + assert(0); + return -1; +} + +void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) { + assert(0); +} + +void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) { + assert(0); +} + +void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { + assert(0); +} + +void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { + assert(0); +} + +void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_release) { + assert(0); +} + +int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) { + assert(0); +} + +pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) { + assert(0); + return NULL; +} -#endif /* OS_IS_WIN32 */ +#endif /* defined(OS_IS_WIN32) || defined(HAVE_PTHREAD) */ -- cgit From 9efc2062d6eabdee79be62a248f006eba813f75d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 9 May 2006 15:15:41 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@835 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/todo b/doc/todo index f7765cde..e6ad0d5f 100644 --- a/doc/todo +++ b/doc/todo @@ -23,6 +23,10 @@ Post 0.8: - examine if it is possible to mimic esd's handling of half duplex cards (switch to capture when a recording client connects and drop playback during that time) +- fix channel maps in all external backends. Take care when doing volume + changes if you're modifying a sink/source since those might have a different + map. +- don't install .a files of modules Long term: - pass meta info for hearing impaired @@ -33,6 +37,3 @@ Backends for: - sdl - OSS (esddsp style) - gstreamer (needs to be updated) -- fix channel maps in all external backends. Take care when doing volume - changes if you're modifying a sink/source since those might have a different - map. -- cgit From 26870176bae0b56d844aadedcfa1888e0c68e378 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 9 May 2006 15:16:12 +0000 Subject: fix handling of timing status requests git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@836 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/stream.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/polyp/stream.c b/src/polyp/stream.c index 2c4e882c..c67b3e51 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -727,9 +727,8 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, assert(pd); assert(o); - assert(o->stream); - if (!o->context) + if (!o->context || !o->stream) goto finish; i = &o->stream->timing_info; -- cgit From 6d2a9367bafb8ae4a98fe725bcb52b021f0fa4e6 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 11 May 2006 11:02:25 +0000 Subject: Do WSAStartup() in the DLL entry routine instead of at context creation. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@837 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/context.c | 11 ----------- src/polypcore/dllmain.c | 17 +++++++++++++---- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/polyp/context.c b/src/polyp/context.c index c9a65847..d5cf90f8 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -142,13 +142,6 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { #endif pa_client_conf_env(c->conf); -#ifdef OS_IS_WIN32 - { - WSADATA data; - WSAStartup(MAKEWORD(2, 0), &data); - } -#endif - return c; } @@ -187,10 +180,6 @@ static void context_free(pa_context *c) { pa_xfree(c->name); pa_xfree(c->server); pa_xfree(c); - -#ifdef OS_IS_WIN32 - WSACleanup(); -#endif } pa_context* pa_context_ref(pa_context *c) { diff --git a/src/polypcore/dllmain.c b/src/polypcore/dllmain.c index d1d120ab..95473b06 100644 --- a/src/polypcore/dllmain.c +++ b/src/polypcore/dllmain.c @@ -34,12 +34,21 @@ extern pa_set_root(HANDLE handle); BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { - if (fdwReason != DLL_PROCESS_ATTACH) - return TRUE; + WSADATA data; - if (!pa_set_root(hinstDLL)) - return FALSE; + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + if (!pa_set_root(hinstDLL)) + return FALSE; + WSAStartup(MAKEWORD(2, 0), &data); + break; + + case DLL_PROCESS_DETACH: + WSACleanup(); + break; + + } return TRUE; } -- cgit From 18c5340fb48bb6a56b8a9761628e24d2b236193b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 11 May 2006 11:03:17 +0000 Subject: ANSI codes aren't supported on Windows terminals. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@838 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/log.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/polypcore/log.c b/src/polypcore/log.c index 29c4c480..9c9ed2fd 100644 --- a/src/polypcore/log.c +++ b/src/polypcore/log.c @@ -99,7 +99,8 @@ void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { switch (log_target) { case PA_LOG_STDERR: { const char *prefix = "", *suffix = ""; - + +#ifndef OS_IS_WIN32 /* Yes indeed. Useless, but fun! */ if (isatty(STDERR_FILENO)) { if (level <= PA_LOG_ERROR) { @@ -110,6 +111,8 @@ void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { suffix = "\x1B[0m"; } } +#endif + fprintf(stderr, "%s%s%s\n", prefix, t, suffix); break; } -- cgit From 12d4b5d952c7a284fd081966a02d34d94dd6be10 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 11 May 2006 11:04:57 +0000 Subject: Include log header to get rid of warnings. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@839 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/thread-mainloop.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/polyp/thread-mainloop.c b/src/polyp/thread-mainloop.c index 6c14a1d3..577e0c2f 100644 --- a/src/polyp/thread-mainloop.c +++ b/src/polyp/thread-mainloop.c @@ -37,6 +37,7 @@ #include #endif +#include #include #include "mainloop.h" -- cgit From 48d66cd5e89764b00fe225db4823b3392a759942 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 11 May 2006 11:08:58 +0000 Subject: Handle pipes on platforms where they are non-existant of broken. We do this by creating a TCP socket pair instead of a normal pipe. Since Windows isn't UNIX-y enough to support read()/write() on sockets, we also need a wrapper to handle read() vs recv() and write() vs send(). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@840 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- src/Makefile.am | 2 + src/polyp/mainloop-signal.c | 81 +++------------------- src/polyp/mainloop.c | 14 ++-- src/polypcore/iochannel.c | 28 +------- src/polypcore/pipe.c | 160 ++++++++++++++++++++++++++++++++++++++++++++ src/polypcore/pipe.h | 22 ++++++ src/polypcore/util.c | 45 ++++++++++++- src/polypcore/util.h | 2 + 9 files changed, 249 insertions(+), 107 deletions(-) create mode 100644 src/polypcore/pipe.c create mode 100644 src/polypcore/pipe.h diff --git a/configure.ac b/configure.ac index 22ab3962..360249ea 100644 --- a/configure.ac +++ b/configure.ac @@ -220,7 +220,7 @@ AC_FUNC_FORK AC_FUNC_GETGROUPS AC_FUNC_SELECT_ARGTYPES AC_CHECK_FUNCS([chmod chown getaddrinfo getgrgid_r getpwuid_r gettimeofday \ - getuid inet_ntop inet_pton nanosleep setpgid setsid sigaction sleep]) + getuid inet_ntop inet_pton nanosleep pipe setpgid setsid sigaction sleep]) AC_CHECK_FUNCS([mkfifo], [HAVE_MKFIFO=1], [HAVE_MKFIFO=0]) AM_CONDITIONAL(HAVE_MKFIFO, test "x$HAVE_MKFIFO" = "x1") diff --git a/src/Makefile.am b/src/Makefile.am index ee7b2325..72e3c1eb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -356,6 +356,7 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = \ polyp/mainloop.c polyp/mainloop.h \ polyp/mainloop-signal.c polyp/mainloop-signal.h \ polyp/thread-mainloop.c polyp/thread-mainloop.h \ + polypcore/pipe.c polypcore/pipe.h \ polypcore/poll.c polypcore/poll.h # Internal stuff that is shared with libpolypcore @@ -518,6 +519,7 @@ libpolypcore_la_SOURCES += \ polypcore/module.c polypcore/module.h \ polypcore/namereg.c polypcore/namereg.h \ polypcore/pid.c polypcore/pid.h \ + polypcore/pipe.c polypcore/pipe.h \ polypcore/play-memchunk.c polypcore/play-memchunk.h \ polypcore/poll.c polypcore/poll.h \ polypcore/props.c polypcore/props.h \ diff --git a/src/polyp/mainloop-signal.c b/src/polyp/mainloop-signal.c index 73de0002..6073dbb3 100644 --- a/src/polyp/mainloop-signal.c +++ b/src/polyp/mainloop-signal.c @@ -59,25 +59,17 @@ struct pa_signal_event { static pa_mainloop_api *api = NULL; static int signal_pipe[2] = { -1, -1 }; static pa_io_event* io_event = NULL; -static pa_time_event *time_event = NULL; static pa_signal_event *signals = NULL; -#ifdef OS_IS_WIN32 -static unsigned int waiting_signals = 0; -static CRITICAL_SECTION crit; -#endif - static void signal_handler(int sig) { + int result; #ifndef HAVE_SIGACTION signal(sig, signal_handler); #endif - write(signal_pipe[1], &sig, sizeof(sig)); - -#ifdef OS_IS_WIN32 - EnterCriticalSection(&crit); - waiting_signals++; - LeaveCriticalSection(&crit); -#endif + pa_log(__FILE__": Got signal %d", sig); + result = pa_write(signal_pipe[1], &sig, sizeof(sig)); + if (result != sizeof(sig)) + pa_log(__FILE__": Bad write (%d, %d)", result, WSAGetLastError()); } static void dispatch(pa_mainloop_api*a, int sig) { @@ -91,46 +83,14 @@ static void dispatch(pa_mainloop_api*a, int sig) { } } -#ifdef OS_IS_WIN32 -static void timer(pa_mainloop_api*a, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, PA_GCC_UNUSED void *userdata) { - ssize_t r; - int sig; - unsigned int sigs; - struct timeval tvnext; - - EnterCriticalSection(&crit); - sigs = waiting_signals; - waiting_signals = 0; - LeaveCriticalSection(&crit); - - while (sigs) { - if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) { - pa_log(__FILE__": read(): %s", strerror(errno)); - return; - } - - if (r != sizeof(sig)) { - pa_log(__FILE__": short read()"); - return; - } - - dispatch(a, sig); - - sigs--; - } - - pa_timeval_add(pa_gettimeofday(&tvnext), 100000); - a->time_restart(e, &tvnext); -} -#endif - static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags_t f, PA_GCC_UNUSED void *userdata) { ssize_t r; int sig; assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]); - - if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) { + pa_log(__FILE__": Signal pipe callback"); + + if ((r = pa_read(signal_pipe[0], &sig, sizeof(sig))) < 0) { if (errno == EAGAIN) return; @@ -147,17 +107,10 @@ static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags } int pa_signal_init(pa_mainloop_api *a) { -#ifdef OS_IS_WIN32 - struct timeval tv; -#endif - assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event && !time_event); + assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event); -#ifdef OS_IS_WIN32 - if (_pipe(signal_pipe, 200, _O_BINARY) < 0) { -#else if (pipe(signal_pipe) < 0) { -#endif pa_log(__FILE__": pipe() failed: %s", strerror(errno)); return -1; } @@ -169,34 +122,20 @@ int pa_signal_init(pa_mainloop_api *a) { api = a; -#ifndef OS_IS_WIN32 io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL); assert(io_event); -#else - time_event = api->time_new(api, pa_gettimeofday(&tv), timer, NULL); - assert(time_event); - - InitializeCriticalSection(&crit); -#endif return 0; } void pa_signal_done(void) { - assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && (io_event || time_event)); + assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && io_event); while (signals) pa_signal_free(signals); -#ifndef OS_IS_WIN32 api->io_free(io_event); io_event = NULL; -#else - api->time_free(time_event); - time_event = NULL; - - DeleteCriticalSection(&crit); -#endif close(signal_pipe[0]); close(signal_pipe[1]); diff --git a/src/polyp/mainloop.c b/src/polyp/mainloop.c index 98b3f3c6..589fe77e 100644 --- a/src/polyp/mainloop.c +++ b/src/polyp/mainloop.c @@ -40,6 +40,10 @@ #include "../polypcore/winsock.h" +#ifndef HAVE_PIPE +#include "../polypcore/pipe.h" +#endif + #include #include #include @@ -330,18 +334,14 @@ pa_mainloop *pa_mainloop_new(void) { m = pa_xmalloc(sizeof(pa_mainloop)); -#ifndef OS_IS_WIN32 if (pipe(m->wakeup_pipe) < 0) { + pa_log_error(__FILE__": ERROR: cannot create wakeup pipe"); pa_xfree(m); return NULL; } pa_make_nonblock_fd(m->wakeup_pipe[0]); pa_make_nonblock_fd(m->wakeup_pipe[1]); -#else - m->wakeup_pipe[0] = -1; - m->wakeup_pipe[1] = -1; -#endif m->io_events = pa_idxset_new(NULL, NULL); m->defer_events = pa_idxset_new(NULL, NULL); @@ -622,7 +622,7 @@ void pa_mainloop_wakeup(pa_mainloop *m) { assert(m); if (m->wakeup_pipe[1] >= 0) - write(m->wakeup_pipe[1], &c, sizeof(c)); + pa_write(m->wakeup_pipe[1], &c, sizeof(c)); } static void clear_wakeup(pa_mainloop *m) { @@ -633,7 +633,7 @@ static void clear_wakeup(pa_mainloop *m) { if (m->wakeup_pipe[0] < 0) return; - while (read(m->wakeup_pipe[0], &c, sizeof(c)) == sizeof(c)); + while (pa_read(m->wakeup_pipe[0], &c, sizeof(c)) == sizeof(c)); } int pa_mainloop_prepare(pa_mainloop *m, int timeout) { diff --git a/src/polypcore/iochannel.c b/src/polypcore/iochannel.c index 5da7a9a9..623925ac 100644 --- a/src/polypcore/iochannel.c +++ b/src/polypcore/iochannel.c @@ -202,19 +202,7 @@ ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) { assert(l); assert(io->ofd >= 0); -#ifdef OS_IS_WIN32 - r = send(io->ofd, data, l, 0); - if (r < 0) { - if (WSAGetLastError() != WSAENOTSOCK) { - errno = WSAGetLastError(); - return r; - } - } - - if (r < 0) -#endif - r = write(io->ofd, data, l); - + r = pa_write(io->ofd, data, l); if (r >= 0) { io->writable = 0; enable_mainloop_sources(io); @@ -229,20 +217,8 @@ ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) { assert(io); assert(data); assert(io->ifd >= 0); - -#ifdef OS_IS_WIN32 - r = recv(io->ifd, data, l, 0); - if (r < 0) { - if (WSAGetLastError() != WSAENOTSOCK) { - errno = WSAGetLastError(); - return r; - } - } - if (r < 0) -#endif - r = read(io->ifd, data, l); - + r = pa_read(io->ifd, data, l); if (r >= 0) { io->readable = 0; enable_mainloop_sources(io); diff --git a/src/polypcore/pipe.c b/src/polypcore/pipe.c new file mode 100644 index 00000000..eef6d533 --- /dev/null +++ b/src/polypcore/pipe.c @@ -0,0 +1,160 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with polypaudio; If not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#include "winsock.h" + +#include "pipe.h" + +#ifndef HAVE_PIPE + +static int set_block(int fd, int blocking) { +#ifdef O_NONBLOCK + + int v; + + assert(fd >= 0); + + if ((v = fcntl(fd, F_GETFL)) < 0) + return -1; + + if (blocking) + v &= ~O_NONBLOCK; + else + v |= O_NONBLOCK; + + if (fcntl(fd, F_SETFL, v) < 0) + return -1; + + return 0; + +#elif defined(OS_IS_WIN32) + + u_long arg; + + arg = !blocking; + + if (ioctlsocket(fd, FIONBIO, &arg) < 0) + return -1; + + return 0; + +#else + + return -1; + +#endif +} + +int pipe(int filedes[2]) { + int listener; + struct sockaddr_in addr, peer; + socklen_t len; + + listener = -1; + filedes[0] = -1; + filedes[1] = -1; + + listener = socket(PF_INET, SOCK_STREAM, 0); + if (listener < 0) + goto error; + + filedes[0] = socket(PF_INET, SOCK_STREAM, 0); + if (filedes[0] < 0) + goto error; + + filedes[1] = socket(PF_INET, SOCK_STREAM, 0); + if (filedes[1] < 0) + goto error; + + /* Make non-blocking so that connect() won't block */ + if (set_block(filedes[0], 0) < 0) + goto error; + + addr.sin_family = AF_INET; + addr.sin_port = 0; + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + if (bind(listener, (struct sockaddr*)&addr, sizeof(addr)) < 0) + goto error; + + if (listen(listener, 1) < 0) + goto error; + + len = sizeof(addr); + if (getsockname(listener, (struct sockaddr*)&addr, &len) < 0) + goto error; + + if (connect(filedes[0], (struct sockaddr*)&addr, sizeof(addr)) < 0) { +#ifdef OS_IS_WIN32 + if (WSAGetLastError() != EWOULDBLOCK) +#else + if (errno != EINPROGRESS) +#endif + goto error; + } + + len = sizeof(peer); + filedes[1] = accept(listener, (struct sockaddr*)&peer, &len); + if (filedes[1] < 0) + goto error; + + /* Restore blocking */ + if (set_block(filedes[0], 1) < 0) + goto error; + + len = sizeof(addr); + if (getsockname(filedes[0], (struct sockaddr*)&addr, &len) < 0) + goto error; + + /* Check that someone else didn't steal the connection */ + if ((addr.sin_port != peer.sin_port) || (addr.sin_addr.s_addr != peer.sin_addr.s_addr)) + goto error; + + close(listener); + + return 0; + +error: + if (listener >= 0) + close(listener); + if (filedes[0] >= 0) + close(filedes[0]); + if (filedes[1] >= 0) + close(filedes[0]); + + return -1; +} + +#endif /* HAVE_PIPE */ diff --git a/src/polypcore/pipe.h b/src/polypcore/pipe.h new file mode 100644 index 00000000..a9b088b5 --- /dev/null +++ b/src/polypcore/pipe.h @@ -0,0 +1,22 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with polypaudio; If not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +***/ + +int pipe(int filedes[2]); diff --git a/src/polypcore/util.c b/src/polypcore/util.c index 191fa809..beb93f45 100644 --- a/src/polypcore/util.c +++ b/src/polypcore/util.c @@ -198,6 +198,47 @@ finish: return ret; } +/** Platform independent read function. Necessary since not all systems + * treat all file descriptors equal. */ +ssize_t pa_read(int fd, void *buf, size_t count) { + ssize_t r; + +#ifdef OS_IS_WIN32 + r = recv(fd, buf, count, 0); + if (r < 0) { + if (WSAGetLastError() != WSAENOTSOCK) { + errno = WSAGetLastError(); + return r; + } + } + + if (r < 0) +#endif + r = read(fd, buf, count); + + return r; +} + +/** Similar to pa_read(), but handles writes */ +ssize_t pa_write(int fd, void *buf, size_t count) { + ssize_t r; + +#ifdef OS_IS_WIN32 + r = send(fd, buf, count, 0); + if (r < 0) { + if (WSAGetLastError() != WSAENOTSOCK) { + errno = WSAGetLastError(); + return r; + } + } + + if (r < 0) +#endif + r = write(fd, buf, count); + + return r; +} + /** Calls read() in a loop. Makes sure that as much as 'size' bytes, * unless EOF is reached or an error occured */ ssize_t pa_loop_read(int fd, void*data, size_t size) { @@ -207,7 +248,7 @@ ssize_t pa_loop_read(int fd, void*data, size_t size) { while (size > 0) { ssize_t r; - if ((r = read(fd, data, size)) < 0) + if ((r = pa_read(fd, data, size)) < 0) return r; if (r == 0) @@ -229,7 +270,7 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size) { while (size > 0) { ssize_t r; - if ((r = write(fd, data, size)) < 0) + if ((r = pa_write(fd, data, size)) < 0) return r; if (r == 0) diff --git a/src/polypcore/util.h b/src/polypcore/util.h index ca81b229..a7c65381 100644 --- a/src/polypcore/util.h +++ b/src/polypcore/util.h @@ -37,6 +37,8 @@ void pa_make_nonblock_fd(int fd); int pa_make_secure_dir(const char* dir); int pa_make_secure_parent_dir(const char *fn); +ssize_t pa_read(int fd, void *buf, size_t count); +ssize_t pa_write(int fd, void *buf, size_t count); ssize_t pa_loop_read(int fd, void*data, size_t size); ssize_t pa_loop_write(int fd, const void*data, size_t size); -- cgit From 5328afe369b0a124bac4243abae4b53f1b3f58e2 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 11 May 2006 11:30:35 +0000 Subject: pa_write() should use a const pointer. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@841 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/util.c | 2 +- src/polypcore/util.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/polypcore/util.c b/src/polypcore/util.c index beb93f45..c1f82a20 100644 --- a/src/polypcore/util.c +++ b/src/polypcore/util.c @@ -220,7 +220,7 @@ ssize_t pa_read(int fd, void *buf, size_t count) { } /** Similar to pa_read(), but handles writes */ -ssize_t pa_write(int fd, void *buf, size_t count) { +ssize_t pa_write(int fd, const void *buf, size_t count) { ssize_t r; #ifdef OS_IS_WIN32 diff --git a/src/polypcore/util.h b/src/polypcore/util.h index a7c65381..2d5894c3 100644 --- a/src/polypcore/util.h +++ b/src/polypcore/util.h @@ -38,7 +38,7 @@ int pa_make_secure_dir(const char* dir); int pa_make_secure_parent_dir(const char *fn); ssize_t pa_read(int fd, void *buf, size_t count); -ssize_t pa_write(int fd, void *buf, size_t count); +ssize_t pa_write(int fd, const void *buf, size_t count); ssize_t pa_loop_read(int fd, void*data, size_t size); ssize_t pa_loop_write(int fd, const void*data, size_t size); -- cgit From 3890f0387fa75fa09da8938931c74cd88e070a53 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 11 May 2006 11:30:55 +0000 Subject: Remove some debug code that wasn't supposed to be committed. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@842 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/mainloop-signal.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/polyp/mainloop-signal.c b/src/polyp/mainloop-signal.c index 6073dbb3..2c9484e4 100644 --- a/src/polyp/mainloop-signal.c +++ b/src/polyp/mainloop-signal.c @@ -62,14 +62,10 @@ static pa_io_event* io_event = NULL; static pa_signal_event *signals = NULL; static void signal_handler(int sig) { - int result; #ifndef HAVE_SIGACTION signal(sig, signal_handler); #endif - pa_log(__FILE__": Got signal %d", sig); - result = pa_write(signal_pipe[1], &sig, sizeof(sig)); - if (result != sizeof(sig)) - pa_log(__FILE__": Bad write (%d, %d)", result, WSAGetLastError()); + pa_write(signal_pipe[1], &sig, sizeof(sig)); } static void dispatch(pa_mainloop_api*a, int sig) { -- cgit From dbf62d4bc5e984fb33b39292cb5268e73ec8a17a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 11 May 2006 12:59:58 +0000 Subject: add thread-mainloop.h to doxygen docs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@843 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doxygen/doxygen.conf.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doxygen/doxygen.conf.in b/doxygen/doxygen.conf.in index 9e426027..471c21dc 100644 --- a/doxygen/doxygen.conf.in +++ b/doxygen/doxygen.conf.in @@ -417,7 +417,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = ../src/polyp/context.h ../src/polyp/stream.h ../src/polyp/polypaudio.h ../src/polyp/sample.h ../src/polyp/def.h ../src/polyp/subscribe.h ../src/polyp/introspect.h ../src/polyp/scache.h ../src/polyp/mainloop-api.h ../src/polyp/glib-mainloop.h ../src/polyp/mainloop.h ../src/polyp/mainloop-signal.h ../src/polyp/error.h ../src/polyp/operation.h ../src/polyp/simple.h ../src/polyp/version.h ../src/polyp/volume.h ../src/polyp/channelmap.h +INPUT = ../src/polyp/context.h ../src/polyp/stream.h ../src/polyp/polypaudio.h ../src/polyp/sample.h ../src/polyp/def.h ../src/polyp/subscribe.h ../src/polyp/introspect.h ../src/polyp/scache.h ../src/polyp/mainloop-api.h ../src/polyp/glib-mainloop.h ../src/polyp/mainloop.h ../src/polyp/mainloop-signal.h ../src/polyp/error.h ../src/polyp/operation.h ../src/polyp/simple.h ../src/polyp/version.h ../src/polyp/volume.h ../src/polyp/channelmap.h ../src/polyp/thread-mainloop.h # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -- cgit From e929aabc032ee91705acc8571f09affe41e297ae Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 11 May 2006 13:01:24 +0000 Subject: split of signal releasing into its own function and name it pa_threaded_mainloop_accept() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@844 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/thread-mainloop.c | 23 ++++++++++++++++------- src/polyp/thread-mainloop.h | 7 +++++-- src/tests/thread-mainloop-test.c | 4 +++- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/polyp/thread-mainloop.c b/src/polyp/thread-mainloop.c index 577e0c2f..90274f1c 100644 --- a/src/polyp/thread-mainloop.c +++ b/src/polyp/thread-mainloop.c @@ -51,7 +51,7 @@ struct pa_threaded_mainloop { pthread_t thread_id; pthread_mutex_t mutex; int n_waiting; - pthread_cond_t cond, release_cond; + pthread_cond_t cond, accept_cond; int thread_running; }; @@ -105,7 +105,7 @@ pa_threaded_mainloop *pa_threaded_mainloop_new(void) { pthread_mutexattr_destroy(&a); pthread_cond_init(&m->cond, NULL); - pthread_cond_init(&m->release_cond, NULL); + pthread_cond_init(&m->accept_cond, NULL); m->thread_running = 0; m->n_waiting = 0; @@ -126,7 +126,7 @@ void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { pthread_mutex_destroy(&m->mutex); pthread_cond_destroy(&m->cond); - pthread_cond_destroy(&m->release_cond); + pthread_cond_destroy(&m->accept_cond); pa_xfree(m); } @@ -187,13 +187,13 @@ void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { pthread_mutex_unlock(&m->mutex); } -void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_release) { +void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept) { assert(m); pthread_cond_broadcast(&m->cond); - if (wait_for_release && m->n_waiting > 0) - pthread_cond_wait(&m->release_cond, &m->mutex); + if (wait_for_accept && m->n_waiting > 0) + pthread_cond_wait(&m->accept_cond, &m->mutex); } void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { @@ -206,7 +206,16 @@ void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { pthread_cond_wait(&m->cond, &m->mutex); assert(m->n_waiting > 0); m->n_waiting --; - pthread_cond_signal(&m->release_cond); + pthread_cond_signal(&m->accept_cond); +} + +void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) { + assert(m); + + /* Make sure that this function is not called from the helper thread */ + assert(!m->thread_running || !pthread_equal(pthread_self(), m->thread_id)); + + pthread_cond_signal(&m->accept_cond); } int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) { diff --git a/src/polyp/thread-mainloop.h b/src/polyp/thread-mainloop.h index d4762e27..d0bfd5ae 100644 --- a/src/polyp/thread-mainloop.h +++ b/src/polyp/thread-mainloop.h @@ -67,9 +67,12 @@ void pa_threaded_mainloop_wait(pa_threaded_mainloop *m); /** Signal all threads waiting for a signalling event in * pa_threaded_mainloop_wait(). If wait_for_release is non-zero, do * not return before the signal was accepted by a - * pa_threaded_mainloop_wait() call. While waiting for that condition + * pa_threaded_mainloop_accept() call. While waiting for that condition * the event loop object is unlocked. */ -void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_release); +void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept); + +/** Accept a signal from the event thread issued with pa_threaded_mainloop_signal() */ +void pa_threaded_mainloop_accept(pa_threaded_mainloop *m); /** Return the return value as specified with the main loop's quit() routine. */ int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m); diff --git a/src/tests/thread-mainloop-test.c b/src/tests/thread-mainloop-test.c index 1434deb9..8ca3f92f 100644 --- a/src/tests/thread-mainloop-test.c +++ b/src/tests/thread-mainloop-test.c @@ -59,7 +59,9 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { fprintf(stderr, "waiting 5s (signal)\n"); pa_threaded_mainloop_wait(m); fprintf(stderr, "wait completed\n"); - + pa_threaded_mainloop_accept(m); + fprintf(stderr, "signal accepted\n"); + pa_threaded_mainloop_unlock(m); fprintf(stderr, "waiting 5s (sleep)\n"); -- cgit From 68b98f711308ba09a35b78f23a0567f25090d620 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 11 May 2006 13:17:19 +0000 Subject: don't signal the accept_cond automatically when waiting for a signal event git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@845 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/thread-mainloop.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/polyp/thread-mainloop.c b/src/polyp/thread-mainloop.c index 90274f1c..916c89d8 100644 --- a/src/polyp/thread-mainloop.c +++ b/src/polyp/thread-mainloop.c @@ -206,7 +206,6 @@ void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { pthread_cond_wait(&m->cond, &m->mutex); assert(m->n_waiting > 0); m->n_waiting --; - pthread_cond_signal(&m->accept_cond); } void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) { -- cgit From f931486c5ded3bdaf1adfde9f98df4c1cfce48d9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 11 May 2006 13:17:27 +0000 Subject: update doxygen docs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@846 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/thread-mainloop.h | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/polyp/thread-mainloop.h b/src/polyp/thread-mainloop.h index d0bfd5ae..94a48d02 100644 --- a/src/polyp/thread-mainloop.h +++ b/src/polyp/thread-mainloop.h @@ -29,27 +29,37 @@ PA_C_DECL_BEGIN /** \file * - * A thread based main loop implementation based on pa_mainloop.*/ + * A thread based event loop implementation based on pa_mainloop. The + * event loop is run in a helper thread in the background. A few + * synchronization primitives are available to access the objects + * attached to the event loop safely. */ -/** An opaque main loop object */ +/** An opaque threaded main loop object */ typedef struct pa_threaded_mainloop pa_threaded_mainloop; -/** Allocate a new main loop object */ +/** Allocate a new threaded main loop object. You have to call + * pa_threaded_mainloop_start() before the event loop thread starts + * running. */ pa_threaded_mainloop *pa_threaded_mainloop_new(void); -/** Free a main loop object */ +/** Free a threaded main loop object. If the event loop thread is + * still running, it is terminated using pa_threaded_mainloop_stop() + * first. */ void pa_threaded_mainloop_free(pa_threaded_mainloop* m); /** Start the event loop thread. */ int pa_threaded_mainloop_start(pa_threaded_mainloop *m); -/** Terminate the event loop thread cleanly */ +/** Terminate the event loop thread cleanly. Make sure to unlock the + * mainloop object before calling this function. */ void pa_threaded_mainloop_stop(pa_threaded_mainloop *m); /** Lock the event loop object, effectively blocking the event loop * thread from processing events. You can use this to enforce * exclusive access to all objects attached to the event loop. This - * function may not be called inside the event loop thread. */ + * lock is recursive. This function may not be called inside the event + * loop thread. Events that are dispatched from the event loop thread + * are executed with this lock held. */ void pa_threaded_mainloop_lock(pa_threaded_mainloop *m); /** Unlock the event loop object, inverse of pa_threaded_mainloop_lock() */ @@ -71,7 +81,10 @@ void pa_threaded_mainloop_wait(pa_threaded_mainloop *m); * the event loop object is unlocked. */ void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept); -/** Accept a signal from the event thread issued with pa_threaded_mainloop_signal() */ +/** Accept a signal from the event thread issued with + * pa_threaded_mainloop_signal(). This call should only be used in + * conjunction with pa_threaded_mainloop_signal() with a non-zero + * wait_for_accept value. */ void pa_threaded_mainloop_accept(pa_threaded_mainloop *m); /** Return the return value as specified with the main loop's quit() routine. */ -- cgit From af54f9fcc71077fd215054ee3aa3d3a4e8b9f5ad Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 11 May 2006 14:57:24 +0000 Subject: Windows support for the threaded API. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@847 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/thread-mainloop.c | 216 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 202 insertions(+), 14 deletions(-) diff --git a/src/polyp/thread-mainloop.c b/src/polyp/thread-mainloop.c index 916c89d8..20639e9e 100644 --- a/src/polyp/thread-mainloop.c +++ b/src/polyp/thread-mainloop.c @@ -37,58 +37,117 @@ #include #endif +#ifdef HAVE_WINDOWS_H +#include +#endif + #include #include +#include #include "mainloop.h" #include "thread-mainloop.h" -/* FIXME: Add defined(OS_IS_WIN32) when support is added */ -#if defined(HAVE_PTHREAD) +#if defined(HAVE_PTHREAD) || defined(OS_IS_WIN32) struct pa_threaded_mainloop { pa_mainloop *real_mainloop; + int n_waiting; + int thread_running; + +#ifdef OS_IS_WIN32 + DWORD thread_id; + HANDLE thread; + CRITICAL_SECTION mutex; + pa_hashmap *cond_events; + HANDLE accept_cond; +#else pthread_t thread_id; pthread_mutex_t mutex; - int n_waiting; pthread_cond_t cond, accept_cond; - int thread_running; +#endif }; +static inline int in_worker(pa_threaded_mainloop *m) { +#ifdef OS_IS_WIN32 + return GetCurrentThreadId() == m->thread_id; +#else + return pthread_equal(pthread_self(), m->thread_id); +#endif +} + static int poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) { +#ifdef OS_IS_WIN32 + CRITICAL_SECTION *mutex = userdata; +#else pthread_mutex_t *mutex = userdata; +#endif + int r; assert(mutex); - + /* Before entering poll() we unlock the mutex, so that * avahi_simple_poll_quit() can succeed from another thread. */ +#ifdef OS_IS_WIN32 + LeaveCriticalSection(mutex); +#else pthread_mutex_unlock(mutex); +#endif + r = poll(ufds, nfds, timeout); + +#ifdef OS_IS_WIN32 + EnterCriticalSection(mutex); +#else pthread_mutex_lock(mutex); +#endif return r; } -static void* thread(void *userdata){ +#ifdef OS_IS_WIN32 +static DWORD WINAPI thread(void *userdata) { +#else +static void* thread(void *userdata) { +#endif pa_threaded_mainloop *m = userdata; + +#ifndef OS_IS_WIN32 sigset_t mask; /* Make sure that signals are delivered to the main thread */ sigfillset(&mask); pthread_sigmask(SIG_BLOCK, &mask, NULL); +#endif +#ifdef OS_IS_WIN32 + EnterCriticalSection(&m->mutex); +#else pthread_mutex_lock(&m->mutex); +#endif + pa_mainloop_run(m->real_mainloop, NULL); + +#ifdef OS_IS_WIN32 + LeaveCriticalSection(&m->mutex); +#else pthread_mutex_unlock(&m->mutex); +#endif +#ifdef OS_IS_WIN32 + return 0; +#else return NULL; +#endif } pa_threaded_mainloop *pa_threaded_mainloop_new(void) { pa_threaded_mainloop *m; +#ifndef OS_IS_WIN32 pthread_mutexattr_t a; +#endif m = pa_xnew(pa_threaded_mainloop, 1); @@ -99,6 +158,14 @@ pa_threaded_mainloop *pa_threaded_mainloop_new(void) { pa_mainloop_set_poll_func(m->real_mainloop, poll_func, &m->mutex); +#ifdef OS_IS_WIN32 + InitializeCriticalSection(&m->mutex); + + m->cond_events = pa_hashmap_new(NULL, NULL); + assert(m->cond_events); + m->accept_cond = CreateEvent(NULL, FALSE, FALSE, NULL); + assert(m->accept_cond); +#else pthread_mutexattr_init(&a); pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&m->mutex, &a); @@ -106,6 +173,8 @@ pa_threaded_mainloop *pa_threaded_mainloop_new(void) { pthread_cond_init(&m->cond, NULL); pthread_cond_init(&m->accept_cond, NULL); +#endif + m->thread_running = 0; m->n_waiting = 0; @@ -116,7 +185,7 @@ void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { assert(m); /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !pthread_equal(pthread_self(), m->thread_id)); + assert(!m->thread_running || !in_worker(m)); if (m->thread_running) pa_threaded_mainloop_stop(m); @@ -124,9 +193,14 @@ void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { if (m->real_mainloop) pa_mainloop_free(m->real_mainloop); +#ifdef OS_IS_WIN32 + pa_hashmap_free(m->cond_events, NULL, NULL); + CloseHandle(m->accept_cond); +#else pthread_mutex_destroy(&m->mutex); pthread_cond_destroy(&m->cond); pthread_cond_destroy(&m->accept_cond); +#endif pa_xfree(m); } @@ -136,6 +210,18 @@ int pa_threaded_mainloop_start(pa_threaded_mainloop *m) { assert(!m->thread_running); +#ifdef OS_IS_WIN32 + + EnterCriticalSection(&m->mutex); + + m->thread = CreateThread(NULL, 0, thread, m, 0, &m->thread_id); + if (!m->thread) { + LeaveCriticalSection(&m->mutex); + return -1; + } + +#else + pthread_mutex_lock(&m->mutex); if (pthread_create(&m->thread_id, NULL, thread, m) < 0) { @@ -143,9 +229,15 @@ int pa_threaded_mainloop_start(pa_threaded_mainloop *m) { return -1; } +#endif + m->thread_running = 1; +#ifdef OS_IS_WIN32 + LeaveCriticalSection(&m->mutex); +#else pthread_mutex_unlock(&m->mutex); +#endif return 0; } @@ -157,13 +249,29 @@ void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) { return; /* Make sure that this function is not called from the helper thread */ - assert(!pthread_equal(pthread_self(), m->thread_id)); + assert(!in_worker(m)); +#ifdef OS_IS_WIN32 + EnterCriticalSection(&m->mutex); +#else pthread_mutex_lock(&m->mutex); +#endif + pa_mainloop_quit(m->real_mainloop, 0); + +#ifdef OS_IS_WIN32 + LeaveCriticalSection(&m->mutex); +#else pthread_mutex_unlock(&m->mutex); +#endif +#ifdef OS_IS_WIN32 + WaitForSingleObject(m->thread, INFINITE); + CloseHandle(m->thread); +#else pthread_join(m->thread_id, NULL); +#endif + m->thread_running = 0; return; @@ -173,37 +281,113 @@ void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) { assert(m); /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !pthread_equal(pthread_self(), m->thread_id)); + assert(!m->thread_running || !in_worker(m)); +#ifdef OS_IS_WIN32 + EnterCriticalSection(&m->mutex); +#else pthread_mutex_lock(&m->mutex); +#endif } void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { assert(m); /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !pthread_equal(pthread_self(), m->thread_id)); + assert(!m->thread_running || !in_worker(m)); +#ifdef OS_IS_WIN32 + LeaveCriticalSection(&m->mutex); +#else pthread_mutex_unlock(&m->mutex); +#endif } void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept) { +#ifdef OS_IS_WIN32 + void *iter; + const void *key; + HANDLE event; +#endif + assert(m); - + +#ifdef OS_IS_WIN32 + + iter = NULL; + while (1) { + pa_hashmap_iterate(m->cond_events, &iter, &key); + if (key == NULL) + break; + event = (HANDLE)pa_hashmap_get(m->cond_events, key); + SetEvent(event); + } + +#else + pthread_cond_broadcast(&m->cond); - if (wait_for_accept && m->n_waiting > 0) +#endif + + if (wait_for_accept && m->n_waiting > 0) { + +#ifdef OS_IS_WIN32 + + /* This is just to make sure it's unsignaled */ + WaitForSingleObject(m->accept_cond, 0); + + LeaveCriticalSection(&m->mutex); + + WaitForSingleObject(m->accept_cond, INFINITE); + + EnterCriticalSection(&m->mutex); + +#else + pthread_cond_wait(&m->accept_cond, &m->mutex); + +#endif + + } } void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { +#ifdef OS_IS_WIN32 + HANDLE event; + DWORD result; +#endif + assert(m); /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !pthread_equal(pthread_self(), m->thread_id)); + assert(!m->thread_running || !in_worker(m)); m->n_waiting ++; + +#ifdef OS_IS_WIN32 + + event = CreateEvent(NULL, FALSE, FALSE, NULL); + assert(event); + + pa_hashmap_put(m->cond_events, event, event); + + LeaveCriticalSection(&m->mutex); + + result = WaitForSingleObject(event, INFINITE); + assert(result == WAIT_OBJECT_0); + + EnterCriticalSection(&m->mutex); + + pa_hashmap_remove(m->cond_events, event); + + CloseHandle(event); + +#else + pthread_cond_wait(&m->cond, &m->mutex); + +#endif + assert(m->n_waiting > 0); m->n_waiting --; } @@ -212,9 +396,13 @@ void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) { assert(m); /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !pthread_equal(pthread_self(), m->thread_id)); + assert(!m->thread_running || !in_worker(m)); +#ifdef OS_IS_WIN32 + SetEvent(m->accept_cond); +#else pthread_cond_signal(&m->accept_cond); +#endif } int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) { -- cgit From eecc04cf282392afb624fb14ab4f6a564bab4875 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 11 May 2006 21:38:16 +0000 Subject: fix iochannel for hangup signals git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@848 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/iochannel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polypcore/iochannel.c b/src/polypcore/iochannel.c index 623925ac..aba0399c 100644 --- a/src/polypcore/iochannel.c +++ b/src/polypcore/iochannel.c @@ -91,7 +91,7 @@ static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_fla assert(fd >= 0); assert(userdata); - if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) & !io->hungup) { + if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) { io->hungup = 1; changed = 1; } -- cgit From 11782f0b749e261a6241570dc160075e9baf0a93 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 11 May 2006 22:37:42 +0000 Subject: fix hangup detection for recording streams git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@849 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-esound.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index 2c956a7e..7a6861fd 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -58,7 +58,7 @@ #define DEFAULT_COOKIE_FILE ".esd_auth" -#define PLAYBACK_BUFFER_SECONDS (.5) +#define PLAYBACK_BUFFER_SECONDS (.25) #define PLAYBACK_BUFFER_FRAGMENTS (10) #define RECORD_BUFFER_SECONDS (5) #define RECORD_BUFFER_FRAGMENTS (100) @@ -985,7 +985,12 @@ static void do_work(struct connection *c) { if (pa_iochannel_is_readable(c->io)) { if (do_read(c) < 0) goto fail; - } else if (pa_iochannel_is_hungup(c->io)) + } + + if (c->state == ESD_STREAMING_DATA && c->source_output && pa_iochannel_is_hungup(c->io)) + /* In case we are in capture mode we will never call read() + * on the socket, hence we need to detect the hangup manually + * here, instead of simply waiting for read() to return 0. */ goto fail; if (pa_iochannel_is_writable(c->io)) @@ -1008,13 +1013,10 @@ fail: connection_free(c); } - static void io_callback(pa_iochannel*io, void *userdata) { struct connection *c = userdata; assert(io && c && c->io == io); -/* pa_log("IO"); */ - do_work(c); } -- cgit From afdec0532fc1fde7d53bce689d8da0b98dc04d3a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 May 2006 19:55:28 +0000 Subject: remove superfluous log message git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@850 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/mainloop-signal.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/polyp/mainloop-signal.c b/src/polyp/mainloop-signal.c index 2c9484e4..4ffa00ba 100644 --- a/src/polyp/mainloop-signal.c +++ b/src/polyp/mainloop-signal.c @@ -84,8 +84,6 @@ static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags int sig; assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]); - pa_log(__FILE__": Signal pipe callback"); - if ((r = pa_read(signal_pipe[0], &sig, sizeof(sig))) < 0) { if (errno == EAGAIN) return; -- cgit From b6812029ba32002aea1576339571eafde62f124a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 May 2006 20:29:32 +0000 Subject: use default alsa channel map for alsa devices git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@851 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 44 ++++++++++++++++++++++++++++++++++++++++ src/modules/alsa-util.h | 4 ++++ src/modules/module-alsa-sink.c | 14 ++++++++++++- src/modules/module-alsa-source.c | 14 ++++++++++++- 4 files changed, 74 insertions(+), 2 deletions(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 8bb33c2f..4c9cde9e 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -340,3 +340,47 @@ snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name) { return elem; } + +pa_channel_map* pa_alsa_channel_map_init_auto(pa_channel_map *m, unsigned channels) { + assert(m); + assert(channels > 0); + assert(channels <= PA_CHANNELS_MAX); + + pa_channel_map_init(m); + + m->channels = channels; + + /* The standard ALSA channel order */ + + switch (channels) { + case 1: + m->map[0] = PA_CHANNEL_POSITION_MONO; + return m; + + case 8: + m->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; + m->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; + /* Fall through */ + + case 6: + m->map[5] = PA_CHANNEL_POSITION_LFE; + /* Fall through */ + + case 5: + m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; + /* Fall through */ + + case 4: + m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT; + m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; + /* Fall through */ + + case 2: + m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + return m; + + default: + return NULL; + } +} diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h index c908d7e0..bad6e9bf 100644 --- a/src/modules/alsa-util.h +++ b/src/modules/alsa-util.h @@ -27,6 +27,8 @@ #include #include +#include + struct pa_alsa_fdlist; struct pa_alsa_fdlist *pa_alsa_fdlist_new(void); @@ -40,4 +42,6 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint3 int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev); snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name); +pa_channel_map* pa_alsa_channel_map_init_auto(pa_channel_map *m, unsigned channels); + #endif diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 84b506e1..2d90afaf 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -324,10 +324,22 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { pa_log(__FILE__": failed to parse sample specification"); goto fail; } + + pa_alsa_channel_map_init_auto(&map, ss.channels); + if ((pa_modargs_get_channel_map(ma, &map) < 0)) { + pa_log(__FILE__": invalid channel map."); + goto fail; + } + + if (ss.channels != map.channels) { + pa_log(__FILE__": channel map and sample specification don't match."); + goto fail; + } + frame_size = pa_frame_size(&ss); periods = 8; diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 84ae992b..ad52271c 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -312,10 +312,22 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { pa_log(__FILE__": failed to parse sample specification"); goto fail; } + + pa_alsa_channel_map_init_auto(&map, ss.channels); + if ((pa_modargs_get_channel_map(ma, &map) < 0)) { + pa_log(__FILE__": invalid channel map."); + goto fail; + } + + if (ss.channels != map.channels) { + pa_log(__FILE__": channel map and sample specification don't match."); + goto fail; + } + frame_size = pa_frame_size(&ss); periods = 12; -- cgit From 7abf17edcdae7d29231ff6619f22212b0ef9eee7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 May 2006 20:47:55 +0000 Subject: fix fragment size calculation for module-alsa-source git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@852 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index ad52271c..a47e0bc6 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -118,7 +118,11 @@ static void do_read(struct userdata *u) { u->memchunk.index = 0; } - assert(u->memchunk.memblock && u->memchunk.memblock->data && u->memchunk.length && u->memchunk.memblock->length && (u->memchunk.length % u->frame_size) == 0); + assert(u->memchunk.memblock); + assert(u->memchunk.length); + assert(u->memchunk.memblock->data); + assert(u->memchunk.memblock->length); + assert(u->memchunk.length % u->frame_size == 0); if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { if (frames == -EAGAIN) @@ -331,12 +335,12 @@ int pa__init(pa_core *c, pa_module*m) { frame_size = pa_frame_size(&ss); periods = 12; - fragsize = 1024; + fragsize = frame_size*1024; if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { pa_log(__FILE__": failed to parse buffer metrics"); goto fail; } - period_size = fragsize; + period_size = fragsize/frame_size; u = pa_xmalloc0(sizeof(struct userdata)); m->userdata = u; @@ -419,9 +423,9 @@ int pa__init(pa_core *c, pa_module*m) { } u->frame_size = frame_size; - u->fragment_size = period_size; + u->fragment_size = period_size * frame_size; - pa_log(__FILE__": using %u fragments of size %lu bytes.", periods, (long unsigned)u->fragment_size); + pa_log(__FILE__": using %u fragments of size %lu bytes.", periods, (long unsigned) u->fragment_size); u->memchunk.memblock = NULL; u->memchunk.index = u->memchunk.length = 0; -- cgit From c3b9c3dc73e73e5c671599f914408e9f8e903a1b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 May 2006 21:18:32 +0000 Subject: don't hit an assert when trying to resample data for 6channel audio git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@853 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/resampler.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/polypcore/resampler.c b/src/polypcore/resampler.c index a50b21bf..7e85e270 100644 --- a/src/polypcore/resampler.c +++ b/src/polypcore/resampler.c @@ -168,7 +168,8 @@ void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) } size_t pa_resampler_request(pa_resampler *r, size_t out_length) { - assert(r && (out_length % r->o_fz) == 0); + assert(r); + return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz; } -- cgit From 0231e6ea4100ccb6c525012c0dd51dbb88aab189 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 May 2006 21:19:02 +0000 Subject: first set buffer size, and afterwards period size git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@854 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 4c9cde9e..a8192165 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -273,8 +273,8 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint3 (ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format])) < 0 || (ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0 || (ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels)) < 0 || - (*periods > 0 && (ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0) || (*period_size > 0 && (ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL)) < 0) || + (*periods > 0 && (ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0) || (ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) goto finish; -- cgit From 0f22d63289779931cfc3ddd3d2cdfb579e4be3c7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 May 2006 21:20:34 +0000 Subject: * set default fragment metrics depending on the sample specs of the device in OSS and ALSA * fix fragment size calculation in module-alsa-sink git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@855 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-sink.c | 10 +++++++--- src/modules/module-alsa-source.c | 8 +++++--- src/modules/module-oss.c | 18 +++++++++--------- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 2d90afaf..ad6bbb70 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -342,13 +342,17 @@ int pa__init(pa_core *c, pa_module*m) { frame_size = pa_frame_size(&ss); + /* Fix latency to 100ms */ periods = 8; - fragsize = 1024; + fragsize = pa_bytes_per_second(&ss)/128; + + pa_log("req: %i %i", periods, fragsize); + if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { pa_log(__FILE__": failed to parse buffer metrics"); goto fail; } - period_size = fragsize; + period_size = fragsize/frame_size; u = pa_xmalloc0(sizeof(struct userdata)); m->userdata = u; @@ -431,7 +435,7 @@ int pa__init(pa_core *c, pa_module*m) { } u->frame_size = frame_size; - u->fragment_size = period_size; + u->fragment_size = period_size * frame_size; pa_log_info(__FILE__": using %u fragments of size %lu bytes.", periods, (long unsigned)u->fragment_size); diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index a47e0bc6..660bc83b 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -333,9 +333,11 @@ int pa__init(pa_core *c, pa_module*m) { } frame_size = pa_frame_size(&ss); - + + /* Fix latency to 100ms */ periods = 12; - fragsize = frame_size*1024; + fragsize = pa_bytes_per_second(&ss)/128; + if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { pa_log(__FILE__": failed to parse buffer metrics"); goto fail; @@ -425,7 +427,7 @@ int pa__init(pa_core *c, pa_module*m) { u->frame_size = frame_size; u->fragment_size = period_size * frame_size; - pa_log(__FILE__": using %u fragments of size %lu bytes.", periods, (long unsigned) u->fragment_size); + pa_log_info(__FILE__": using %u fragments of size %lu bytes.", periods, (long unsigned) u->fragment_size); u->memchunk.memblock = NULL; u->memchunk.index = u->memchunk.length = 0; diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 0795ae39..4d811a76 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -97,8 +97,6 @@ static const char* const valid_modargs[] = { #define DEFAULT_SINK_NAME "oss_output" #define DEFAULT_SOURCE_NAME "oss_input" #define DEFAULT_DEVICE "/dev/dsp" -#define DEFAULT_NFRAGS 12 -#define DEFAULT_FRAGSIZE 1024 static void update_usage(struct userdata *u) { pa_module_set_used(u->module, @@ -348,19 +346,21 @@ int pa__init(pa_core *c, pa_module*m) { mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); - nfrags = DEFAULT_NFRAGS; - frag_size = DEFAULT_FRAGSIZE; - if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { - pa_log(__FILE__": failed to parse fragments arguments"); - goto fail; - } - ss = c->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { pa_log(__FILE__": failed to parse sample specification or channel map"); goto fail; } + /* Fix latency to 100ms */ + nfrags = 12; + frag_size = pa_bytes_per_second(&ss)/128; + + if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { + pa_log(__FILE__": failed to parse fragments arguments"); + goto fail; + } + if ((fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, NULL)) < 0) goto fail; -- cgit From 682dfd7adb8aec8d17706a224c6ac24b9b2c08d9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 May 2006 21:40:38 +0000 Subject: fix esound sample cache names git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@856 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-esound.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index 7a6861fd..56a11365 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -680,6 +680,7 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ memcpy(&sc_length, data, sizeof(int32_t)); sc_length = MAYBE_INT32_SWAP(c->swap_byte_order, sc_length); + data = (const char*)data + sizeof(int32_t); CHECK_VALIDITY(sc_length <= MAX_CACHE_SAMPLE_SIZE, "Sample too large."); @@ -694,7 +695,7 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ c->scache.sample_spec = ss; assert(!c->scache.name); c->scache.name = pa_xstrdup(name); - + c->state = ESD_CACHING_SAMPLE; pa_scache_add_item(c->protocol->core, c->scache.name, NULL, NULL, NULL, &idx); -- cgit From e46f8f8eb3fd586f8728e43292509434e0e8b089 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 14 May 2006 00:36:06 +0000 Subject: modify argument order of pa_client_new() to actually match how it is usually called git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@857 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/client.c | 2 +- src/polypcore/client.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/polypcore/client.c b/src/polypcore/client.c index 852f87b0..be970470 100644 --- a/src/polypcore/client.c +++ b/src/polypcore/client.c @@ -34,7 +34,7 @@ #include "client.h" -pa_client *pa_client_new(pa_core *core, const char *name, const char *driver) { +pa_client *pa_client_new(pa_core *core, const char *driver, const char *name) { pa_client *c; int r; assert(core); diff --git a/src/polypcore/client.h b/src/polypcore/client.h index 8ddc6d94..f6ff935d 100644 --- a/src/polypcore/client.h +++ b/src/polypcore/client.h @@ -42,7 +42,7 @@ struct pa_client { void *userdata; }; -pa_client *pa_client_new(pa_core *c, const char *name, const char *driver); +pa_client *pa_client_new(pa_core *c, const char *driver, const char *name); /* This function should be called only by the code that created the client */ void pa_client_free(pa_client *c); -- cgit From be05b18c6fb6f0e2e2b74ffdf251692a45eaa045 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 14 May 2006 00:41:18 +0000 Subject: * add new parameter to pa_open_config_file() to specify open mode * modify pa_sink_input_new() to take initial volume settings as argument * call pa_sink_input_set_volume() when changing stream volume in protocol-esound.c to make sure that subscribe events are issued properly git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@858 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/daemon-conf.c | 4 ++-- src/modules/module-combine.c | 2 +- src/modules/module-match.c | 4 ++-- src/modules/module-sine.c | 2 +- src/modules/rtp/module-rtp-recv.c | 2 +- src/polyp/client-conf.c | 2 +- src/polypcore/play-memchunk.c | 5 +---- src/polypcore/protocol-esound.c | 18 ++++++++++-------- src/polypcore/protocol-native.c | 4 +--- src/polypcore/protocol-simple.c | 2 +- src/polypcore/sink-input.c | 17 +++++++++++++++-- src/polypcore/sink-input.h | 1 + src/polypcore/sound-file-stream.c | 4 +--- src/polypcore/util.c | 8 ++++---- src/polypcore/util.h | 2 +- 15 files changed, 43 insertions(+), 34 deletions(-) diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index ac5fbb16..f41bb4b1 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -84,7 +84,7 @@ pa_daemon_conf* pa_daemon_conf_new(void) { FILE *f; pa_daemon_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); - if ((f = pa_open_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE, &c->default_script_file))) + if ((f = pa_open_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE, &c->default_script_file, "r"))) fclose(f); #ifdef DLSEARCHPATH @@ -233,7 +233,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { f = filename ? fopen(c->config_file = pa_xstrdup(filename), "r") : - pa_open_config_file(DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file); + pa_open_config_file(DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file, "r"); if (!f && errno != ENOENT) { pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", filename, strerror(errno)); diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 47010497..3b927d13 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -238,7 +238,7 @@ static struct output *output_new(struct userdata *u, pa_sink *sink, int resample sink->core->memblock_stat); snprintf(t, sizeof(t), "%s: output #%u", u->sink->name, u->n_outputs+1); - if (!(o->sink_input = pa_sink_input_new(sink, __FILE__, t, &u->sink->sample_spec, &u->sink->channel_map, 1, resample_method))) + if (!(o->sink_input = pa_sink_input_new(sink, __FILE__, t, &u->sink->sample_spec, &u->sink->channel_map, NULL, 1, resample_method))) goto fail; o->sink_input->get_latency = sink_input_get_latency_cb; diff --git a/src/modules/module-match.c b/src/modules/module-match.c index 59817517..f6316b93 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -43,7 +43,7 @@ #include "module-match-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Sink input matching module") +PA_MODULE_DESCRIPTION("Playback stream expression matching module") PA_MODULE_USAGE("table=") PA_MODULE_VERSION(PACKAGE_VERSION) @@ -81,7 +81,7 @@ static int load_rules(struct userdata *u, const char *filename) { f = filename ? fopen(fn = pa_xstrdup(filename), "r") : - pa_open_config_file(DEFAULT_MATCH_TABLE_FILE, DEFAULT_MATCH_TABLE_FILE_USER, NULL, &fn); + pa_open_config_file(DEFAULT_MATCH_TABLE_FILE, DEFAULT_MATCH_TABLE_FILE_USER, NULL, &fn, "r"); if (!f) { pa_log(__FILE__": failed to open file '%s': %s", fn, strerror(errno)); diff --git a/src/modules/module-sine.c b/src/modules/module-sine.c index d5a0fa47..3267d49b 100644 --- a/src/modules/module-sine.c +++ b/src/modules/module-sine.c @@ -141,7 +141,7 @@ int pa__init(pa_core *c, pa_module*m) { calc_sine(u->memblock->data, u->memblock->length, frequency); snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency); - if (!(u->sink_input = pa_sink_input_new(sink, __FILE__, t, &ss, NULL, 0, -1))) + if (!(u->sink_input = pa_sink_input_new(sink, __FILE__, t, &ss, NULL, NULL, 0, -1))) goto fail; u->sink_input->peek = sink_input_peek; diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index cd5f10e6..925a1210 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -286,7 +286,7 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in sdp_info->session_name ? sdp_info->session_name : "", sdp_info->session_name ? ")" : ""); - s->sink_input = pa_sink_input_new(sink, __FILE__, c, &sdp_info->sample_spec, NULL, 0, PA_RESAMPLER_INVALID); + s->sink_input = pa_sink_input_new(sink, __FILE__, c, &sdp_info->sample_spec, NULL, NULL, 0, PA_RESAMPLER_INVALID); pa_xfree(c); if (!s->sink_input) { diff --git a/src/polyp/client-conf.c b/src/polyp/client-conf.c index 4202b14c..d3ad0767 100644 --- a/src/polyp/client-conf.c +++ b/src/polyp/client-conf.c @@ -119,7 +119,7 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) { f = filename ? fopen((fn = pa_xstrdup(filename)), "r") : - pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn); + pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn, "r"); if (!f && errno != EINTR) { pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", filename, strerror(errno)); diff --git a/src/polypcore/play-memchunk.c b/src/polypcore/play-memchunk.c index ec79254b..37ebdcf1 100644 --- a/src/polypcore/play-memchunk.c +++ b/src/polypcore/play-memchunk.c @@ -98,12 +98,9 @@ int pa_play_memchunk( if (cvolume && pa_cvolume_is_muted(cvolume)) return 0; - if (!(si = pa_sink_input_new(sink, name, __FILE__, ss, map, 0, PA_RESAMPLER_INVALID))) + if (!(si = pa_sink_input_new(sink, name, __FILE__, ss, map, cvolume, 0, PA_RESAMPLER_INVALID))) return -1; - if (cvolume) - si->volume = *cvolume; - si->peek = sink_input_peek; si->drop = sink_input_drop; si->kill = sink_input_kill; diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index 56a11365..50c8b6b5 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -345,7 +345,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t assert(!c->sink_input && !c->input_memblockq); - c->sink_input = pa_sink_input_new(sink, __FILE__, name, &ss, NULL, 0, -1); + c->sink_input = pa_sink_input_new(sink, __FILE__, name, &ss, NULL, NULL, 0, -1); CHECK_VALIDITY(c->sink_input, "Failed to create sink input."); @@ -532,9 +532,10 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v assert(t >= k*2+s); if (conn->sink_input) { + pa_cvolume volume = *pa_sink_input_get_volume(conn->sink_input); rate = conn->sink_input->sample_spec.rate; - lvolume = (conn->sink_input->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; - rvolume = (conn->sink_input->volume.values[1]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; + lvolume = (volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; + rvolume = (volume.values[1]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; format = format_native2esd(&conn->sink_input->sample_spec); } @@ -643,11 +644,12 @@ static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, rvolume); data = (const char*)data + sizeof(uint32_t); - if ((conn = pa_idxset_get_by_index(c->protocol->connections, idx))) { - assert(conn->sink_input); - conn->sink_input->volume.values[0] = (lvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; - conn->sink_input->volume.values[1] = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; - conn->sink_input->volume.channels = 2; + if ((conn = pa_idxset_get_by_index(c->protocol->connections, idx)) && conn->sink_input) { + pa_cvolume volume; + volume.values[0] = (lvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; + volume.values[1] = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; + volume.channels = 2; + pa_sink_input_set_volume(conn->sink_input, &volume); ok = 1; } else ok = 0; diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index a0fc286d..aa636072 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -386,7 +386,7 @@ static struct playback_stream* playback_stream_new( if (ssync && ssync->sink_input->sink != sink) return NULL; - if (!(sink_input = pa_sink_input_new(sink, __FILE__, name, ss, map, 0, -1))) + if (!(sink_input = pa_sink_input_new(sink, __FILE__, name, ss, map, volume, 0, -1))) return NULL; s = pa_xnew(struct playback_stream, 1); @@ -436,8 +436,6 @@ static struct playback_stream* playback_stream_new( s->requested_bytes = 0; s->drain_request = 0; - - s->sink_input->volume = *volume; pa_idxset_put(c->output_streams, s, &s->index); diff --git a/src/polypcore/protocol-simple.c b/src/polypcore/protocol-simple.c index c2f53444..1e3b169c 100644 --- a/src/polypcore/protocol-simple.c +++ b/src/polypcore/protocol-simple.c @@ -346,7 +346,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) goto fail; } - if (!(c->sink_input = pa_sink_input_new(sink, __FILE__, c->client->name, &p->sample_spec, NULL, 0, -1))) { + if (!(c->sink_input = pa_sink_input_new(sink, __FILE__, c->client->name, &p->sample_spec, NULL, NULL, 0, -1))) { pa_log(__FILE__": Failed to create sink input."); goto fail; } diff --git a/src/polypcore/sink-input.c b/src/polypcore/sink-input.c index e1703b97..26e63b85 100644 --- a/src/polypcore/sink-input.c +++ b/src/polypcore/sink-input.c @@ -43,6 +43,7 @@ pa_sink_input* pa_sink_input_new( const char *name, const pa_sample_spec *spec, const pa_channel_map *map, + const pa_cvolume *volume, int variable_rate, int resample_method) { @@ -56,6 +57,7 @@ pa_sink_input* pa_sink_input_new( assert(spec); assert(s->state == PA_SINK_RUNNING); + if (pa_idxset_size(s->inputs) >= PA_MAX_INPUTS_PER_SINK) { pa_log_warn(__FILE__": Failed to create sink input: too many inputs per sink."); return NULL; @@ -64,8 +66,16 @@ pa_sink_input* pa_sink_input_new( if (resample_method == PA_RESAMPLER_INVALID) resample_method = s->core->resample_method; + if (map && spec->channels != map->channels) + return NULL; + + if (volume && spec->channels != volume->channels) + return NULL; + if (!map) { - pa_channel_map_init_auto(&tmap, spec->channels); + if (!(pa_channel_map_init_auto(&tmap, spec->channels))) + return NULL; + map = &tmap; } @@ -85,7 +95,10 @@ pa_sink_input* pa_sink_input_new( i->sample_spec = *spec; i->channel_map = *map; - pa_cvolume_reset(&i->volume, spec->channels); + if (volume) + i->volume = *volume; + else + pa_cvolume_reset(&i->volume, spec->channels); i->peek = NULL; i->drop = NULL; diff --git a/src/polypcore/sink-input.h b/src/polypcore/sink-input.h index e4b8bda4..4cf4460a 100644 --- a/src/polypcore/sink-input.h +++ b/src/polypcore/sink-input.h @@ -75,6 +75,7 @@ pa_sink_input* pa_sink_input_new( const char *name, const pa_sample_spec *spec, const pa_channel_map *map, + const pa_cvolume *volume, int variable_rate, int resample_method); diff --git a/src/polypcore/sound-file-stream.c b/src/polypcore/sound-file-stream.c index e242cfea..ca762d6a 100644 --- a/src/polypcore/sound-file-stream.c +++ b/src/polypcore/sound-file-stream.c @@ -158,11 +158,9 @@ int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume) { goto fail; } - if (!(u->sink_input = pa_sink_input_new(sink, __FILE__, fname, &ss, NULL, 0, -1))) + if (!(u->sink_input = pa_sink_input_new(sink, __FILE__, fname, &ss, NULL, volume, 0, -1))) goto fail; - if (volume) - u->sink_input->volume = *volume; u->sink_input->peek = sink_input_peek; u->sink_input->drop = sink_input_drop; u->sink_input->kill = sink_input_kill; diff --git a/src/polypcore/util.c b/src/polypcore/util.c index c1f82a20..6f7f8819 100644 --- a/src/polypcore/util.c +++ b/src/polypcore/util.c @@ -1037,7 +1037,7 @@ int pa_unlock_lockfile(const char *fn, int fd) { * file system. If "result" is non-NULL, a pointer to a newly * allocated buffer containing the used configuration file is * stored there.*/ -FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result) { +FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode) { const char *fn; char h[PATH_MAX]; @@ -1058,7 +1058,7 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env if (result) *result = pa_xstrdup(fn); - return fopen(fn, "r"); + return fopen(fn, mode); } if (local && pa_get_home_dir(h, sizeof(h))) { @@ -1073,7 +1073,7 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env fn = buf; #endif - f = fopen(fn, "r"); + f = fopen(fn, mode); if (f || errno != ENOENT) { if (result) @@ -1101,7 +1101,7 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env if (result) *result = pa_xstrdup(global); - return fopen(global, "r"); + return fopen(global, mode); } /* Format the specified data as a hexademical string */ diff --git a/src/polypcore/util.h b/src/polypcore/util.h index 2d5894c3..df71672f 100644 --- a/src/polypcore/util.h +++ b/src/polypcore/util.h @@ -87,7 +87,7 @@ int pa_lock_fd(int fd, int b); int pa_lock_lockfile(const char *fn); int pa_unlock_lockfile(const char *fn, int fd); -FILE *pa_open_config_file(const char *env, const char *global, const char *local, char **result); +FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode); char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength); size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength); -- cgit From b3e16559fceaef151226b82408c118cef448993b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 14 May 2006 00:41:56 +0000 Subject: add new module module-volume-restore which saves and restores volume of playback streams git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@859 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 12 +- src/modules/module-volume-restore.c | 361 ++++++++++++++++++++++++++++++++++++ 2 files changed, 371 insertions(+), 2 deletions(-) create mode 100644 src/modules/module-volume-restore.c diff --git a/src/Makefile.am b/src/Makefile.am index 72e3c1eb..9e7b4a39 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -742,7 +742,8 @@ modlib_LTLIBRARIES += \ module-null-sink.la \ module-esound-sink.la \ module-http-protocol-tcp.la \ - module-detect.la + module-detect.la \ + module-volume-restore.la # See comment at librtp.la above if !OS_IS_WIN32 @@ -870,7 +871,8 @@ SYMDEF_FILES = \ modules/rtp/module-rtp-send-symdef.h \ modules/rtp/module-rtp-recv-symdef.h \ modules/module-jack-sink-symdef.h \ - modules/module-jack-source-symdef.h + modules/module-jack-source-symdef.h \ + modules/module-volume-restore-symdef.h EXTRA_DIST += $(SYMDEF_FILES) @@ -1087,6 +1089,12 @@ module_detect_la_LDFLAGS = -module -avoid-version module_detect_la_LIBADD = $(AM_LIBADD) libpolypcore.la module_detect_la_CFLAGS = $(AM_CFLAGS) +# Volume restore module +module_volume_restore_la_SOURCES = modules/module-volume-restore.c +module_volume_restore_la_LDFLAGS = -module -avoid-version +module_volume_restore_la_LIBADD = $(AM_LIBADD) libpolypcore.la +module_volume_restore_la_CFLAGS = $(AM_CFLAGS) + # RTP modules module_rtp_send_la_SOURCES = modules/rtp/module-rtp-send.c module_rtp_send_la_LDFLAGS = -module -avoid-version diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c new file mode 100644 index 00000000..c32bb3a9 --- /dev/null +++ b/src/modules/module-volume-restore.c @@ -0,0 +1,361 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-volume-restore-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Playback stream automatic volume restore module") +PA_MODULE_USAGE("table=") +PA_MODULE_VERSION(PACKAGE_VERSION) + +#define WHITESPACE "\n\r \t" + +#define DEFAULT_VOLUME_TABLE_FILE ".polypaudio/volume.table" + +static const char* const valid_modargs[] = { + "table", + NULL, +}; + +struct rule { + char* name; + pa_cvolume volume; +}; + +struct userdata { + pa_hashmap *hashmap; + pa_subscription *subscription; + int modified; + char *table_file; +}; + +static pa_cvolume* parse_volume(const char *s, pa_cvolume *v) { + char *p; + long k; + unsigned i; + + assert(s); + assert(v); + + if (!isdigit(*s)) + return NULL; + + k = strtol(s, &p, 0); + if (k <= 0 || k > PA_CHANNELS_MAX) + return NULL; + + v->channels = (unsigned) k; + + for (i = 0; i < v->channels; i++) { + p += strspn(p, WHITESPACE); + + if (!isdigit(*p)) + return NULL; + + k = strtol(p, &p, 0); + + if (k < PA_VOLUME_MUTED) + return NULL; + + v->values[i] = (pa_volume_t) k; + } + + if (*p != 0) + return NULL; + + return v; +} + +static int load_rules(struct userdata *u) { + FILE *f; + int n = 0; + int ret = -1; + char buf_name[256], buf_volume[256]; + char *ln = buf_name; + + f = u->table_file ? + fopen(u->table_file, "r") : + pa_open_config_file(NULL, DEFAULT_VOLUME_TABLE_FILE, NULL, &u->table_file, "r"); + + if (!f) { + if (errno == ENOENT) { + pa_log(__FILE__": starting with empty ruleset."); + ret = 0; + } else + pa_log(__FILE__": failed to open file '%s': %s", u->table_file, strerror(errno)); + + goto finish; + } + + while (!feof(f)) { + struct rule *rule; + pa_cvolume v; + + if (!fgets(ln, sizeof(buf_name), f)) + break; + + n++; + + pa_strip_nl(ln); + + if (ln[0] == '#' || !*ln ) + continue; + + if (ln == buf_name) { + ln = buf_volume; + continue; + } + + assert(ln == buf_volume); + + if (!parse_volume(buf_volume, &v)) { + pa_log(__FILE__": parse failure in %s:%u, stopping parsing", u->table_file, n); + goto finish; + } + + ln = buf_name; + + if (pa_hashmap_get(u->hashmap, buf_name)) { + pa_log(__FILE__": double entry in %s:%u, ignoring", u->table_file, n); + goto finish; + } + + rule = pa_xnew(struct rule, 1); + rule->name = pa_xstrdup(buf_name); + rule->volume = v; + + pa_hashmap_put(u->hashmap, rule->name, rule); + } + + if (ln == buf_volume) { + pa_log(__FILE__": invalid number of lines in %s.", u->table_file); + goto finish; + } + + ret = 0; + +finish: + if (f) + fclose(f); + + return ret; +} + +static int save_rules(struct userdata *u) { + FILE *f; + int ret = -1; + void *state = NULL; + struct rule *rule; + + f = u->table_file ? + fopen(u->table_file, "w") : + pa_open_config_file(NULL, DEFAULT_VOLUME_TABLE_FILE, NULL, &u->table_file, "w"); + + if (!f) { + pa_log(__FILE__": failed to open file '%s': %s", u->table_file, strerror(errno)); + goto finish; + } + + while ((rule = pa_hashmap_iterate(u->hashmap, &state, NULL))) { + unsigned i; + + fprintf(f, "%s\n%u", rule->name, rule->volume.channels); + + for (i = 0; i < rule->volume.channels; i++) + fprintf(f, " %u", rule->volume.values[i]); + + + fprintf(f, "\n"); + } + + ret = 0; + +finish: + if (f) + fclose(f); + + return ret; +} + +static char* client_name(pa_client *c) { + char *t, *e; + + if (!c->name || !c->driver) + return NULL; + + t = pa_sprintf_malloc("%s$%s", c->driver, c->name); + t[strcspn(t, "\n\r#")] = 0; + + if (!*t) + return NULL; + + if ((e = strrchr(t, '('))) { + char *k = e + 1 + strspn(e + 1, "0123456789-"); + + /* Dirty trick: truncate all trailing parens with numbers in + * between, since they are usually used to identify multiple + * sessions of the same application, which is something we + * explicitly don't want. Besides other stuff this makes xmms + * with esound work properly for us. */ + + if (*k == ')' && *(k+1) == 0) + *e = 0; + } + + return t; +} + +static void callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { + struct userdata *u = userdata; + pa_sink_input *si; + struct rule *r; + char *name; + + assert(c); + assert(u); + + if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW) && + t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE)) + return; + + if (!(si = pa_idxset_get_by_index(c->sink_inputs, idx))) + return; + + if (!si->client || !(name = client_name(si->client))) + return; + + if ((r = pa_hashmap_get(u->hashmap, name))) { + pa_xfree(name); + + if (((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) && si->sample_spec.channels == r->volume.channels) { + pa_log_info(__FILE__": Restoring volume for <%s>", r->name); + pa_sink_input_set_volume(si, &r->volume); + } else if (!pa_cvolume_equal(pa_sink_input_get_volume(si), &r->volume)) { + pa_log_info(__FILE__": Saving volume for <%s>", r->name); + r->volume = *pa_sink_input_get_volume(si); + u->modified = 1; + } + + } else { + pa_log_info(__FILE__": Creating new entry for <%s>", name); + + r = pa_xnew(struct rule, 1); + r->name = name; + r->volume = *pa_sink_input_get_volume(si); + pa_hashmap_put(u->hashmap, r->name, r); + + u->modified = 1; + } +} + +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; + struct userdata *u; + + assert(c); + assert(m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": Failed to parse module arguments"); + goto fail; + } + + u = pa_xnew(struct userdata, 1); + u->hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + u->subscription = NULL; + u->table_file = pa_xstrdup(pa_modargs_get_value(ma, "table", NULL)); + u->modified = 0; + + m->userdata = u; + + if (load_rules(u) < 0) + goto fail; + + u->subscription = pa_subscription_new(c, PA_SUBSCRIPTION_MASK_SINK_INPUT, callback, u); + + pa_modargs_free(ma); + return 0; + +fail: + pa__done(c, m); + + if (ma) + pa_modargs_free(ma); + + return -1; +} + +static void free_func(void *p, void *userdata) { + struct rule *r = p; + assert(r); + + pa_xfree(r->name); + pa_xfree(r); +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata* u; + + assert(c); + assert(m); + + if (!(u = m->userdata)) + return; + + if (u->subscription) + pa_subscription_free(u->subscription); + + if (u->hashmap) { + + if (u->modified) + save_rules(u); + + pa_hashmap_free(u->hashmap, free_func, NULL); + } + + pa_xfree(u->table_file); + pa_xfree(u); +} + + -- cgit From b10f2dc0ae0f592530c39ee72f05900cd3bbf426 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 14 May 2006 14:07:48 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@860 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + src/polypcore/core-subscribe.c | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/todo b/doc/todo index e6ad0d5f..7f31f0cf 100644 --- a/doc/todo +++ b/doc/todo @@ -27,6 +27,7 @@ Post 0.8: changes if you're modifying a sink/source since those might have a different map. - don't install .a files of modules +- check utf8 validity of strings Long term: - pass meta info for hearing impaired diff --git a/src/polypcore/core-subscribe.c b/src/polypcore/core-subscribe.c index e2dd9ae3..fa6c0e50 100644 --- a/src/polypcore/core-subscribe.c +++ b/src/polypcore/core-subscribe.c @@ -118,7 +118,8 @@ void pa_subscription_free_all(pa_core *c) { } } -/*static void dump_event(pa_subscription_event*e) { +#if 0 +static void dump_event(pa_subscription_event*e) { switch (e->type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { case PA_SUBSCRIPTION_EVENT_SINK: pa_log(__FILE__": SINK_EVENT"); @@ -159,7 +160,8 @@ void pa_subscription_free_all(pa_core *c) { } pa_log(__FILE__": %u", e->index); -}*/ +} +#endif /* Deferred callback for dispatching subscirption events */ static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) { @@ -169,7 +171,6 @@ static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) { c->mainloop->defer_enable(c->subscription_defer_event, 0); - /* Dispatch queued events */ if (c->subscription_event_queue) { -- cgit From bf52fb93b4fb5cd9e83963d9d2bf572022427eed Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 14 May 2006 16:02:09 +0000 Subject: add utf8 validity checking API git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@861 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 4 +- src/polypcore/utf8.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/polypcore/utf8.h | 27 ++++++++++++ 3 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 src/polypcore/utf8.c create mode 100644 src/polypcore/utf8.h diff --git a/src/Makefile.am b/src/Makefile.am index 9e7b4a39..903359ad 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -481,6 +481,7 @@ polypcoreinclude_HEADERS = \ polypcore/strbuf.h \ polypcore/tokenizer.h \ polypcore/util.h \ + polypcore/utf8.h \ polypcore/xmalloc.h lib_LTLIBRARIES += libpolypcore.la @@ -541,7 +542,8 @@ libpolypcore_la_SOURCES += \ polypcore/tokenizer.c polypcore/tokenizer.h \ polypcore/util.c polypcore/util.h \ polypcore/winsock.h \ - polypcore/xmalloc.c polypcore/xmalloc.h + polypcore/xmalloc.c polypcore/xmalloc.h \ + polypcore/utf8.c polypcore/utf8.h if OS_IS_WIN32 libpolypcore_la_SOURCES += \ diff --git a/src/polypcore/utf8.c b/src/polypcore/utf8.c new file mode 100644 index 00000000..b7758439 --- /dev/null +++ b/src/polypcore/utf8.c @@ -0,0 +1,115 @@ +/* $Id */ + +/* This file is based on the GLIB utf8 validation functions. The + * original license text follows. */ + +/* gutf8.c - Operations on UTF-8 strings. + * + * Copyright (C) 1999 Tom Tromey + * Copyright (C) 2000 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "utf8.h" + +#define UNICODE_VALID(Char) \ + ((Char) < 0x110000 && \ + (((Char) & 0xFFFFF800) != 0xD800) && \ + ((Char) < 0xFDD0 || (Char) > 0xFDEF) && \ + ((Char) & 0xFFFE) != 0xFFFE) + + +#define CONTINUATION_CHAR \ + do { \ + if ((*(const unsigned char *)p & 0xc0) != 0x80) /* 10xxxxxx */ \ + goto error; \ + val <<= 6; \ + val |= (*(const unsigned char *)p) & 0x3f; \ + } while(0) + + +const char * +pa_utf8_valid (const char *str) + +{ + unsigned val = 0; + unsigned min = 0; + const char *p; + + for (p = str; *p; p++) + { + if (*(const unsigned char *)p < 128) + /* done */; + else + { + const char *last; + + last = p; + if ((*(const unsigned char *)p & 0xe0) == 0xc0) /* 110xxxxx */ + { + if ( ((*(const unsigned char *)p & 0x1e) == 0)) + goto error; + p++; + if ( ((*(const unsigned char *)p & 0xc0) != 0x80)) /* 10xxxxxx */ + goto error; + } + else + { + if ((*(const unsigned char *)p & 0xf0) == 0xe0) /* 1110xxxx */ + { + min = (1 << 11); + val = *(const unsigned char *)p & 0x0f; + goto TWO_REMAINING; + } + else if ((*(const unsigned char *)p & 0xf8) == 0xf0) /* 11110xxx */ + { + min = (1 << 16); + val = *(const unsigned char *)p & 0x07; + } + else + goto error; + + p++; + CONTINUATION_CHAR; + TWO_REMAINING: + p++; + CONTINUATION_CHAR; + p++; + CONTINUATION_CHAR; + + if ( (val < min)) + goto error; + + if ( (!UNICODE_VALID(val))) + goto error; + } + + continue; + + error: + return NULL; + } + } + + return str; +} diff --git a/src/polypcore/utf8.h b/src/polypcore/utf8.h new file mode 100644 index 00000000..7f394978 --- /dev/null +++ b/src/polypcore/utf8.h @@ -0,0 +1,27 @@ +#ifndef fooutf8hfoo +#define fooutf8hfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +const char *pa_utf8_valid(const char *str); + +#endif -- cgit From a414cc2f32beb5cbdac60dc0e083be876ab28eb6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 14 May 2006 16:02:40 +0000 Subject: check for valid utf8 strings git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@862 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-native.c | 44 ++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index aa636072..3b904134 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -53,6 +53,7 @@ #include #include #include +#include #include "protocol-native.h" @@ -728,8 +729,8 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, sink_index != PA_INVALID_INDEX || !sink_name || *sink_name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, sink_index != PA_INVALID_INDEX || !sink_name || (*sink_name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID); @@ -827,10 +828,10 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, source_index != PA_INVALID_INDEX || !source_name || *source_name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, source_index != PA_INVALID_INDEX || !source_name || (*source_name && pa_utf8_valid(source_name)), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); @@ -946,7 +947,7 @@ static void command_set_client_name(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE return; } - CHECK_VALIDITY(c->pstream, name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID); pa_client_set_name(c->client, name); pa_pstream_send_simple_ack(c->pstream, tag); @@ -965,7 +966,7 @@ static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uin } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name && *name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); if (command == PA_COMMAND_LOOKUP_SINK) { pa_sink *sink; @@ -1134,7 +1135,7 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE); - CHECK_VALIDITY(c->pstream, name && *name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); s = upload_stream_new(c, &ss, &map, name, length); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); @@ -1190,8 +1191,8 @@ static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, sink_index != PA_INVALID_INDEX || !sink_name || *sink_name, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, name && *name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, sink_index != PA_INVALID_INDEX || !sink_name || (*sink_name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); if (sink_index != PA_INVALID_INDEX) sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); @@ -1220,7 +1221,7 @@ static void command_remove_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name && *name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); if (pa_scache_remove_item(c->protocol->core, name) < 0) { pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); @@ -1357,6 +1358,7 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); if (command == PA_COMMAND_GET_SINK_INFO) { if (idx != PA_INVALID_INDEX) @@ -1561,7 +1563,7 @@ static void command_set_volume( } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || *name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID); if (command == PA_COMMAND_SET_SINK_VOLUME) { @@ -1615,7 +1617,7 @@ static void command_set_mute( } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || *name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); if (command == PA_COMMAND_SET_SINK_MUTE) { if (idx != PA_INVALID_INDEX) @@ -1811,7 +1813,7 @@ static void command_set_default_sink_or_source(PA_GCC_UNUSED pa_pdispatch *pd, u } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, !s || *s, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !s || (*s && pa_utf8_valid(s)), tag, PA_ERR_INVALID); pa_namereg_set_default(c->protocol->core, s, command == PA_COMMAND_SET_DEFAULT_SOURCE ? PA_NAMEREG_SOURCE : PA_NAMEREG_SINK); pa_pstream_send_simple_ack(c->pstream, tag); @@ -1831,7 +1833,7 @@ static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t com } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID); if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) { struct playback_stream *s; @@ -1910,8 +1912,9 @@ static void command_load_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name && *name, tag, PA_ERR_INVALID); - + CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID); + if (!(m = pa_module_load(c->protocol->core, name, argument))) { pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED); return; @@ -1960,9 +1963,10 @@ static void command_add_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED u } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name && *name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, type == 0 || type == 1, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, module && *module, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, module && *module && pa_utf8_valid(module), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID); if (pa_autoload_add(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, module, argument, &idx) < 0) { pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); @@ -1991,7 +1995,7 @@ static void command_remove_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, name || idx != PA_IDXSET_INVALID, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, !name || (*name && (type == 0 || type == 1)), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || (*name && pa_utf8_valid(name) && (type == 0 || type == 1)), tag, PA_ERR_INVALID); if (name) r = pa_autoload_remove_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE); @@ -2031,7 +2035,7 @@ static void command_get_autoload_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNU CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, name || idx != PA_IDXSET_INVALID, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, !name || (*name && (type == 0 || type == 1)), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || (*name && (type == 0 || type == 1) && pa_utf8_valid(name)), tag, PA_ERR_INVALID); if (name) a = pa_autoload_get_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE); -- cgit From cfb082a67c5bfad24fd2d322028d3e87d7c58da6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 14 May 2006 16:17:17 +0000 Subject: take the filename specified on the command line as default stream name git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@863 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pacat.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 1ecc0db2..c8890bbb 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -534,12 +534,6 @@ int main(int argc, char *argv[]) { } } - if (!client_name) - client_name = strdup(bn); - - if (!stream_name) - stream_name = strdup(client_name); - if (!pa_sample_spec_valid(&sample_spec)) { fprintf(stderr, "Invalid sample specification\n"); goto quit; @@ -571,12 +565,22 @@ int main(int argc, char *argv[]) { } close(fd); + + if (!stream_name) + stream_name = strdup(argv[optind]); + } else { fprintf(stderr, "Too many arguments.\n"); goto quit; } } - + + if (!client_name) + client_name = strdup(bn); + + if (!stream_name) + stream_name = strdup(client_name); + /* Set up a new main loop */ if (!(m = pa_mainloop_new())) { fprintf(stderr, "pa_mainloop_new() failed.\n"); -- cgit From d419d87a7306d76e3d3f0b174c6af7d39e0d7837 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 14 May 2006 16:17:38 +0000 Subject: remove superfluous log line git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@864 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-sink.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index ad6bbb70..99e74bfc 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -346,8 +346,6 @@ int pa__init(pa_core *c, pa_module*m) { periods = 8; fragsize = pa_bytes_per_second(&ss)/128; - pa_log("req: %i %i", periods, fragsize); - if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { pa_log(__FILE__": failed to parse buffer metrics"); goto fail; -- cgit From 45bbb3499929726971d2ab84f468413f39f97cb0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 14 May 2006 16:18:00 +0000 Subject: add utf8 validity checking to esound protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@865 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-esound.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index 50c8b6b5..aba40856 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -341,6 +341,8 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t strncpy(name, data, sizeof(name)); name[sizeof(name)-1] = 0; + CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in stream name"); + pa_client_set_name(c->client, name); assert(!c->sink_input && !c->input_memblockq); @@ -423,6 +425,8 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co strncpy(name, data, sizeof(name)); name[sizeof(name)-1] = 0; + CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in stream name."); + pa_client_set_name(c->client, name); assert(!c->output_memblockq && !c->source_output); @@ -689,6 +693,8 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ strcpy(name, SCACHE_PREFIX); strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX); name[sizeof(name)-1] = 0; + + CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in sample name."); assert(!c->scache.memchunk.memblock); c->scache.memchunk.memblock = pa_memblock_new(sc_length, c->protocol->core->memblock_stat); @@ -719,6 +725,8 @@ static int esd_proto_sample_get_id(struct connection *c, PA_GCC_UNUSED esd_proto strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX); name[sizeof(name)-1] = 0; + CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in sample name."); + ok = -1; if ((idx = pa_scache_get_id_by_name(c->protocol->core, name)) != PA_IDXSET_INVALID) ok = idx + 1; -- cgit From 3f428784d2a0eba1f0be53318518484653150f7b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 14 May 2006 16:19:39 +0000 Subject: update TODO git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@866 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/todo b/doc/todo index 7f31f0cf..b94be1d9 100644 --- a/doc/todo +++ b/doc/todo @@ -27,7 +27,7 @@ Post 0.8: changes if you're modifying a sink/source since those might have a different map. - don't install .a files of modules -- check utf8 validity of strings +- in avahi-simple: sleep until latency data is available again if NODATA has happened Long term: - pass meta info for hearing impaired -- cgit From f468308e41ddeadaa1b85cb2c7a0ca1a332c31f8 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 15 May 2006 06:36:07 +0000 Subject: Include utf8.h for the validation function. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@867 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-esound.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index aba40856..0741d241 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -45,6 +45,7 @@ #include #include #include +#include #include "endianmacros.h" -- cgit From 9c38744cdd019ef48f321777db7ef7a14cc0fe88 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 15 May 2006 06:41:27 +0000 Subject: module-volume-restore uses regexp() so make sure it's only built on systems that have it. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@868 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 903359ad..e2880ace 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -744,8 +744,7 @@ modlib_LTLIBRARIES += \ module-null-sink.la \ module-esound-sink.la \ module-http-protocol-tcp.la \ - module-detect.la \ - module-volume-restore.la + module-detect.la # See comment at librtp.la above if !OS_IS_WIN32 @@ -777,7 +776,8 @@ endif if HAVE_REGEX modlib_LTLIBRARIES += \ - module-match.la + module-match.la \ + module-volume-restore.la endif if HAVE_X11 -- cgit From 147da3e36ff8c1ce07a14d44e9c8747069f90c18 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 15 May 2006 12:33:43 +0000 Subject: remove regex.h from include, since it is actually not used git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@869 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-volume-restore.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index c32bb3a9..b4606bc3 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include -- cgit From e91740f68ce6334935d9440c12f08e8c136d0b45 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 15 May 2006 12:44:44 +0000 Subject: Clean up the UTF-8 validation code. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@870 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/utf8.c | 154 +++++++++++++++++++++++++-------------------------- 1 file changed, 76 insertions(+), 78 deletions(-) diff --git a/src/polypcore/utf8.c b/src/polypcore/utf8.c index b7758439..a706b280 100644 --- a/src/polypcore/utf8.c +++ b/src/polypcore/utf8.c @@ -29,87 +29,85 @@ #endif #include +#include #include "utf8.h" -#define UNICODE_VALID(Char) \ - ((Char) < 0x110000 && \ - (((Char) & 0xFFFFF800) != 0xD800) && \ - ((Char) < 0xFDD0 || (Char) > 0xFDEF) && \ - ((Char) & 0xFFFE) != 0xFFFE) - - -#define CONTINUATION_CHAR \ - do { \ - if ((*(const unsigned char *)p & 0xc0) != 0x80) /* 10xxxxxx */ \ - goto error; \ - val <<= 6; \ - val |= (*(const unsigned char *)p) & 0x3f; \ - } while(0) - - -const char * -pa_utf8_valid (const char *str) - -{ - unsigned val = 0; - unsigned min = 0; - const char *p; - - for (p = str; *p; p++) - { - if (*(const unsigned char *)p < 128) - /* done */; - else - { - const char *last; - - last = p; - if ((*(const unsigned char *)p & 0xe0) == 0xc0) /* 110xxxxx */ - { - if ( ((*(const unsigned char *)p & 0x1e) == 0)) - goto error; - p++; - if ( ((*(const unsigned char *)p & 0xc0) != 0x80)) /* 10xxxxxx */ - goto error; - } - else - { - if ((*(const unsigned char *)p & 0xf0) == 0xe0) /* 1110xxxx */ - { - min = (1 << 11); - val = *(const unsigned char *)p & 0x0f; - goto TWO_REMAINING; - } - else if ((*(const unsigned char *)p & 0xf8) == 0xf0) /* 11110xxx */ - { - min = (1 << 16); - val = *(const unsigned char *)p & 0x07; - } - else - goto error; - - p++; - CONTINUATION_CHAR; - TWO_REMAINING: - p++; - CONTINUATION_CHAR; - p++; - CONTINUATION_CHAR; - - if ( (val < min)) - goto error; - - if ( (!UNICODE_VALID(val))) - goto error; - } - - continue; - - error: - return NULL; - } +static inline int is_unicode_valid(uint32_t ch) { + if (ch >= 0x110000) /* End of unicode space */ + return 0; + if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ + return 0; + if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ + return 0; + if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ + return 0; + return 1; +} + +static inline int is_continuation_char(uint8_t ch) { + if ((ch & 0xc0) != 0x80) /* 10xxxxxx */ + return 0; + return 1; +} + +static inline void merge_continuation_char(uint32_t *u_ch, uint8_t ch) { + *u_ch <<= 6; + *u_ch |= ch & 0x3f; +} + +const char* pa_utf8_valid (const char *str) { + uint32_t val = 0; + uint32_t min = 0; + const uint8_t *p, *last; + + for (p = (uint8_t*)str; *p; p++) { + if (*p < 128) + /* done */; + else { + last = p; + + if ((*p & 0xe0) == 0xc0) { /* 110xxxxx two-char seq. */ + min = 128; + val = *p & 0x1e; + goto ONE_REMAINING; + } else if ((*p & 0xf0) == 0xe0) { /* 1110xxxx three-char seq.*/ + min = (1 << 11); + val = *p & 0x0f; + goto TWO_REMAINING; + } else if ((*p & 0xf8) == 0xf0) { /* 11110xxx four-char seq */ + min = (1 << 16); + val = *p & 0x07; + } else + goto error; + + p++; + if (!is_continuation_char(*p)) + goto error; + merge_continuation_char(&val, *p); + +TWO_REMAINING: + p++; + if (!is_continuation_char(*p)) + goto error; + merge_continuation_char(&val, *p); + +ONE_REMAINING: + p++; + if (!is_continuation_char(*p)) + goto error; + merge_continuation_char(&val, *p); + + if (val < min) + goto error; + + if (!is_unicode_valid(val)) + goto error; + } } - return str; + return str; + +error: + return NULL; } -- cgit From 7a92f361c66821a6cf89a85876510c15f851fd1b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 15 May 2006 12:45:55 +0000 Subject: undo r868 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@871 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index e2880ace..903359ad 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -744,7 +744,8 @@ modlib_LTLIBRARIES += \ module-null-sink.la \ module-esound-sink.la \ module-http-protocol-tcp.la \ - module-detect.la + module-detect.la \ + module-volume-restore.la # See comment at librtp.la above if !OS_IS_WIN32 @@ -776,8 +777,7 @@ endif if HAVE_REGEX modlib_LTLIBRARIES += \ - module-match.la \ - module-volume-restore.la + module-match.la endif if HAVE_X11 -- cgit From 9c8661c675c92c15793b1f1005816d0d0531e6cf Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 15 May 2006 13:04:13 +0000 Subject: Add function to filter a string of any invalid UTF-8 sequences. User must free() the result. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@872 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/utf8.c | 61 +++++++++++++++++++++++++++++++++++++++++++++------- src/polypcore/utf8.h | 1 + 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/src/polypcore/utf8.c b/src/polypcore/utf8.c index a706b280..03865507 100644 --- a/src/polypcore/utf8.c +++ b/src/polypcore/utf8.c @@ -28,11 +28,15 @@ #include #endif +#include #include #include +#include #include "utf8.h" +#define FILTER_CHAR '_' + static inline int is_unicode_valid(uint32_t ch) { if (ch >= 0x110000) /* End of unicode space */ return 0; @@ -56,30 +60,39 @@ static inline void merge_continuation_char(uint32_t *u_ch, uint8_t ch) { *u_ch |= ch & 0x3f; } -const char* pa_utf8_valid (const char *str) { +static const char* utf8_validate (const char *str, char *output) { uint32_t val = 0; uint32_t min = 0; const uint8_t *p, *last; - - for (p = (uint8_t*)str; *p; p++) { - if (*p < 128) - /* done */; - else { + int size; + uint8_t *o; + + o = output; + for (p = (uint8_t*)str; *p; p++, o++) { + if (*p < 128) { + if (o) + *output = *p; + } else { last = p; if ((*p & 0xe0) == 0xc0) { /* 110xxxxx two-char seq. */ + size = 2; min = 128; val = *p & 0x1e; goto ONE_REMAINING; } else if ((*p & 0xf0) == 0xe0) { /* 1110xxxx three-char seq.*/ + size = 3; min = (1 << 11); val = *p & 0x0f; goto TWO_REMAINING; } else if ((*p & 0xf8) == 0xf0) { /* 11110xxx four-char seq */ + size = 4; min = (1 << 16); val = *p & 0x07; - } else + } else { + size = 1; goto error; + } p++; if (!is_continuation_char(*p)) @@ -103,11 +116,43 @@ ONE_REMAINING: if (!is_unicode_valid(val)) goto error; + + if (o) { + memcpy(o, last, size); + o += size - 1; + } + + continue; + +error: + if (o) { + *o = FILTER_CHAR; + p = last + 1; /* We retry at the next character */ + } else + goto failure; } } + if (o) { + *o = '\0'; + return output; + } + return str; -error: +failure: return NULL; } + +const char* pa_utf8_valid (const char *str) { + return utf8_validate(str, NULL); +} + +const char* pa_utf8_filter (const char *str) { + char *new_str; + + new_str = malloc(strlen(str) + 1); + assert(new_str); + + return utf8_validate(str, new_str); +} diff --git a/src/polypcore/utf8.h b/src/polypcore/utf8.h index 7f394978..5f1fc5df 100644 --- a/src/polypcore/utf8.h +++ b/src/polypcore/utf8.h @@ -23,5 +23,6 @@ ***/ const char *pa_utf8_valid(const char *str); +const char *pa_utf8_filter(const char *str); #endif -- cgit From 19167a1a2d9bdff5a6685f1d14dc47b2aa7dad5a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 15 May 2006 20:17:11 +0000 Subject: add notification callback which is called when new latency data becomes available git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@873 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/internal.h | 2 ++ src/polyp/stream.c | 15 ++++++++++++++- src/polyp/stream.h | 3 +++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/polyp/internal.h b/src/polyp/internal.h index f41744ef..80c28616 100644 --- a/src/polyp/internal.h +++ b/src/polyp/internal.h @@ -151,6 +151,8 @@ struct pa_stream { void *overflow_userdata; pa_stream_notify_cb_t underflow_callback; void *underflow_userdata; + pa_stream_notify_cb_t latency_update_callback; + void *latency_update_userdata; }; typedef void (*pa_operation_cb_t)(void); diff --git a/src/polyp/stream.c b/src/polyp/stream.c index c67b3e51..bccdebe5 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -63,6 +63,8 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->overflow_userdata = NULL; s->underflow_callback = NULL; s->underflow_userdata = NULL; + s->latency_update_callback = NULL; + s->latency_update_userdata = NULL; s->direction = PA_STREAM_NODIRECTION; s->name = pa_xstrdup(name); @@ -849,8 +851,11 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, o->stream->write_index_corrections[n].valid = 0; } } + + if (o->stream->latency_update_callback) + o->stream->latency_update_callback(o->stream, o->stream->latency_update_userdata); - if (o->callback) { + if (o->callback && o->stream && o->stream->state == PA_STREAM_READY) { pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback; cb(o->stream, o->stream->timing_info_valid, o->userdata); } @@ -999,6 +1004,14 @@ void pa_stream_set_underflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, vo s->underflow_userdata = userdata; } +void pa_stream_set_latency_update_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { + assert(s); + assert(s->ref >= 1); + + s->latency_update_callback = cb; + s->latency_update_userdata = userdata; +} + void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; int success = 1; diff --git a/src/polyp/stream.h b/src/polyp/stream.h index b6522efe..ad77d938 100644 --- a/src/polyp/stream.h +++ b/src/polyp/stream.h @@ -375,6 +375,9 @@ void pa_stream_set_overflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, voi /** Set the callback function that is called when a buffer underflow happens. (Only for playback streams) \since 0.8 */ void pa_stream_set_underflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); +/** Set the callback function that is called whenever a latency information update happens. Useful on PA_STREAM_AUTO_TIMING_UPDATE streams only. (Only for playback streams) \since 0.8.2 */ +void pa_stream_set_latency_update_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); + /** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. \since 0.3 */ pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata); -- cgit From 713637cf424a6b4b177c0d353d862ab0ea916d4e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 May 2006 00:04:14 +0000 Subject: * fix segfault in pa_utf8_validate() * remove some compiler warnings * use our own pa_xmalloc() implementation instead of libc's malloc() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@874 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/utf8.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/polypcore/utf8.c b/src/polypcore/utf8.c index 03865507..95b73d52 100644 --- a/src/polypcore/utf8.c +++ b/src/polypcore/utf8.c @@ -34,6 +34,7 @@ #include #include "utf8.h" +#include "xmalloc.h" #define FILTER_CHAR '_' @@ -67,11 +68,11 @@ static const char* utf8_validate (const char *str, char *output) { int size; uint8_t *o; - o = output; - for (p = (uint8_t*)str; *p; p++, o++) { + o = (uint8_t*) output; + for (p = (const uint8_t*) str; *p; p++) { if (*p < 128) { if (o) - *output = *p; + *o = *p; } else { last = p; @@ -122,6 +123,9 @@ ONE_REMAINING: o += size - 1; } + if (o) + o++; + continue; error: @@ -131,6 +135,9 @@ error: } else goto failure; } + + if (o) + o++; } if (o) { @@ -151,8 +158,7 @@ const char* pa_utf8_valid (const char *str) { const char* pa_utf8_filter (const char *str) { char *new_str; - new_str = malloc(strlen(str) + 1); - assert(new_str); + new_str = pa_xnew(char, strlen(str) + 1); return utf8_validate(str, new_str); } -- cgit From 724cd9d811c3847c6e46233185f27b4c5201c260 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 May 2006 00:04:47 +0000 Subject: downgrade a log message git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@875 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-volume-restore.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index b4606bc3..b379e53c 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -119,7 +119,7 @@ static int load_rules(struct userdata *u) { if (!f) { if (errno == ENOENT) { - pa_log(__FILE__": starting with empty ruleset."); + pa_log_info(__FILE__": starting with empty ruleset."); ret = 0; } else pa_log(__FILE__": failed to open file '%s': %s", u->table_file, strerror(errno)); @@ -204,7 +204,6 @@ static int save_rules(struct userdata *u) { for (i = 0; i < rule->volume.channels; i++) fprintf(f, " %u", rule->volume.values[i]); - fprintf(f, "\n"); } -- cgit From 23e74545adce1e23f6d3e09a0cbb9f1d98a7b933 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 May 2006 00:06:02 +0000 Subject: use the new latency update callback to be notified when latency data becomes available again after PA_ERR_NODATA is returned by pa_stream_get_latency() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@876 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/simple.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/polyp/simple.c b/src/polyp/simple.c index 97dcaf11..1f25869b 100644 --- a/src/polyp/simple.c +++ b/src/polyp/simple.c @@ -125,6 +125,14 @@ static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { pa_threaded_mainloop_signal(p->mainloop, 0); } +static void stream_latency_update_cb(pa_stream *s, void *userdata) { + pa_simple *p = userdata; + + assert(p); + + pa_threaded_mainloop_signal(p->mainloop, 0); +} + pa_simple* pa_simple_new( const char *server, const char *name, @@ -184,6 +192,7 @@ pa_simple* pa_simple_new( pa_stream_set_state_callback(p->stream, stream_state_cb, p); pa_stream_set_read_callback(p->stream, stream_request_cb, p); pa_stream_set_write_callback(p->stream, stream_request_cb, p); + pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p); if (dir == PA_STREAM_PLAYBACK) r = pa_stream_connect_playback(p->stream, dev, attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); @@ -414,17 +423,25 @@ unlock_and_fail: pa_usec_t pa_simple_get_playback_latency(pa_simple *p, int *rerror) { pa_usec_t t; - int r, negative; + int negative; assert(p); CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, (pa_usec_t) -1); pa_threaded_mainloop_lock(p->mainloop); - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - r = pa_stream_get_latency(p->stream, &t, &negative); - CHECK_SUCCESS_GOTO(p, rerror, r >= 0, unlock_and_fail); + for (;;) { + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); + + if (pa_stream_get_latency(p->stream, &t, &negative) >= 0) + break; + + CHECK_SUCCESS_GOTO(p, rerror, pa_context_errno(p->context) == PA_ERR_NODATA, unlock_and_fail); + + /* Wait until latency data is available again */ + pa_threaded_mainloop_wait(p->mainloop); + } pa_threaded_mainloop_unlock(p->mainloop); -- cgit From e8cc63d75685bd264efaea2b7bce894ba182e2a2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 May 2006 00:44:47 +0000 Subject: * remove "const" from return type of pa_utf8_filter() since it desn't make any sense * fix pa_utf8_filter() to not skip the next character too if it found an invalid one git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@877 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/utf8.c | 8 ++++---- src/polypcore/utf8.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/polypcore/utf8.c b/src/polypcore/utf8.c index 95b73d52..bb8621e2 100644 --- a/src/polypcore/utf8.c +++ b/src/polypcore/utf8.c @@ -61,7 +61,7 @@ static inline void merge_continuation_char(uint32_t *u_ch, uint8_t ch) { *u_ch |= ch & 0x3f; } -static const char* utf8_validate (const char *str, char *output) { +static char* utf8_validate(const char *str, char *output) { uint32_t val = 0; uint32_t min = 0; const uint8_t *p, *last; @@ -131,7 +131,7 @@ ONE_REMAINING: error: if (o) { *o = FILTER_CHAR; - p = last + 1; /* We retry at the next character */ + p = last; /* We retry at the next character */ } else goto failure; } @@ -145,7 +145,7 @@ error: return output; } - return str; + return (char*) str; failure: return NULL; @@ -155,7 +155,7 @@ const char* pa_utf8_valid (const char *str) { return utf8_validate(str, NULL); } -const char* pa_utf8_filter (const char *str) { +char* pa_utf8_filter (const char *str) { char *new_str; new_str = pa_xnew(char, strlen(str) + 1); diff --git a/src/polypcore/utf8.h b/src/polypcore/utf8.h index 5f1fc5df..6d1e4a7d 100644 --- a/src/polypcore/utf8.h +++ b/src/polypcore/utf8.h @@ -23,6 +23,6 @@ ***/ const char *pa_utf8_valid(const char *str); -const char *pa_utf8_filter(const char *str); +char *pa_utf8_filter(const char *str); #endif -- cgit From 78b23cc1b96c832265074cdab5265665fe7aefaf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 May 2006 00:45:21 +0000 Subject: add double include protection git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@878 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/pipe.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/polypcore/pipe.h b/src/polypcore/pipe.h index a9b088b5..e9167782 100644 --- a/src/polypcore/pipe.h +++ b/src/polypcore/pipe.h @@ -1,3 +1,6 @@ +#ifndef foopipehfoo +#define foopipehfoo + /* $Id$ */ /*** @@ -20,3 +23,5 @@ ***/ int pipe(int filedes[2]); + +#endif -- cgit -- cgit From 53595938d003411e6992e10b6a5c5e51b2a15d4f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 May 2006 00:46:03 +0000 Subject: add new test programme utf8-test.c git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@880 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 8 +++++++- src/tests/utf8-test.c | 26 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/tests/utf8-test.c diff --git a/src/Makefile.am b/src/Makefile.am index 903359ad..10dbf2f2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -189,7 +189,8 @@ noinst_PROGRAMS = \ memblockq-test \ sync-playback \ channelmap-test \ - thread-mainloop-test + thread-mainloop-test \ + utf8-test if HAVE_SIGXCPU noinst_PROGRAMS += \ @@ -217,6 +218,11 @@ thread_mainloop_test_CFLAGS = $(AM_CFLAGS) thread_mainloop_test_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la thread_mainloop_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +utf8_test_SOURCES = tests/utf8-test.c +utf8_test_CFLAGS = $(AM_CFLAGS) +utf8_test_LDADD = $(AM_LDADD) libpolypcore.la +utf8_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + mcalign_test_SOURCES = tests/mcalign-test.c mcalign_test_CFLAGS = $(AM_CFLAGS) mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpolypcore.la diff --git a/src/tests/utf8-test.c b/src/tests/utf8-test.c new file mode 100644 index 00000000..c8b2fabb --- /dev/null +++ b/src/tests/utf8-test.c @@ -0,0 +1,26 @@ +/* $Id$ */ + +#include +#include + +#include +#include + +int main(int argc, char *argv[]) { + char *c; + + assert(pa_utf8_valid("hallo")); + assert(pa_utf8_valid("hallo\n")); + assert(!pa_utf8_valid("hüpfburg\n")); + assert(pa_utf8_valid("hallo\n")); + assert(pa_utf8_valid("hüpfburg\n")); + + printf("LATIN1: %s\n", c = pa_utf8_filter("hüpfburg")); + pa_xfree(c); + printf("UTF8: %sx\n", c = pa_utf8_filter("hüpfburg")); + pa_xfree(c); + printf("LATIN1: %sx\n", c = pa_utf8_filter("üxknärzmörzeltörszß³§dsjkfh")); + pa_xfree(c); + + return 0; +} -- cgit From 56b685ab46ac673c559a1fb6ad25575b38c6cb9e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 May 2006 01:40:01 +0000 Subject: instead of kicking clients with invalid UTF8 stream names, filter invalid characters and use that instead git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@881 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-esound.c | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index 0741d241..fcbeba6d 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -87,6 +87,8 @@ struct connection { pa_source_output *source_output; pa_memblockq *input_memblockq, *output_memblockq; pa_defer_event *defer_event; + + char *original_name; struct { pa_memblock *current_memblock; @@ -175,7 +177,6 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = { { 0, esd_proto_get_latency, "get latency" } }; - static void connection_free(struct connection *c) { assert(c); pa_idxset_remove_by_data(c->protocol->connections, c, NULL); @@ -218,7 +219,8 @@ static void connection_free(struct connection *c) { if (c->auth_timeout_event) c->protocol->core->mainloop->time_free(c->auth_timeout_event); - + + pa_xfree(c->original_name); pa_xfree(c); } @@ -316,7 +318,7 @@ static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t req } static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { - char name[ESD_NAME_MAX]; + char name[ESD_NAME_MAX], *utf8_name; int32_t format, rate; pa_sink *sink; pa_sample_spec ss; @@ -341,14 +343,16 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t strncpy(name, data, sizeof(name)); name[sizeof(name)-1] = 0; - - CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in stream name"); + utf8_name = pa_utf8_filter(name); - pa_client_set_name(c->client, name); + pa_client_set_name(c->client, utf8_name); + c->original_name = pa_xstrdup(name); assert(!c->sink_input && !c->input_memblockq); - c->sink_input = pa_sink_input_new(sink, __FILE__, name, &ss, NULL, NULL, 0, -1); + c->sink_input = pa_sink_input_new(sink, __FILE__, utf8_name, &ss, NULL, NULL, 0, -1); + + pa_xfree(utf8_name); CHECK_VALIDITY(c->sink_input, "Failed to create sink input."); @@ -381,7 +385,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t } static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length) { - char name[ESD_NAME_MAX]; + char name[ESD_NAME_MAX], *utf8_name; int32_t format, rate; pa_source *source; pa_sample_spec ss; @@ -426,13 +430,15 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co strncpy(name, data, sizeof(name)); name[sizeof(name)-1] = 0; - CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in stream name."); - - pa_client_set_name(c->client, name); + utf8_name = pa_utf8_filter(name); + pa_client_set_name(c->client, utf8_name); + pa_xfree(utf8_name); + + c->original_name = pa_xstrdup(name); assert(!c->output_memblockq && !c->source_output); - if (!(c->source_output = pa_source_output_new(source, __FILE__, name, &ss, NULL, -1))) { + if (!(c->source_output = pa_source_output_new(source, __FILE__, c->client->name, &ss, NULL, -1))) { pa_log(__FILE__": failed to create source output"); return -1; } @@ -549,8 +555,11 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v connection_write(c, &id, sizeof(int32_t)); /* name */ - assert(conn->client); - strncpy(name, conn->client->name, ESD_NAME_MAX); + memset(name, 0, ESD_NAME_MAX); /* don't leak old data */ + if (conn->original_name) + strncpy(name, conn->original_name, ESD_NAME_MAX); + else if (conn->client && conn->client->name) + strncpy(name, conn->client->name, ESD_NAME_MAX); connection_write(c, name, ESD_NAME_MAX); /* rate */ @@ -593,6 +602,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v connection_write(c, &id, sizeof(int32_t)); /* name */ + memset(name, 0, ESD_NAME_MAX); /* don't leak old data */ if (strncmp(ce->name, SCACHE_PREFIX, sizeof(SCACHE_PREFIX)-1) == 0) strncpy(name, ce->name+sizeof(SCACHE_PREFIX)-1, ESD_NAME_MAX); else @@ -1177,6 +1187,8 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->scache.memchunk.memblock = NULL; c->scache.name = NULL; + c->original_name = NULL; + if (!c->authorized) { struct timeval tv; pa_gettimeofday(&tv); -- cgit -- cgit From c12206b864439ce3a38cccff1d3fcb9eec75c6d5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 May 2006 15:29:58 +0000 Subject: * remove .a files from the modules directory after installation * rename $(modlibdir) to $(modlibexecdir) in accordance with secion 11.2 of the automake docs ("The two parts of install") git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@883 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 10dbf2f2..02060e92 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,7 +26,7 @@ polypincludedir=$(includedir)/polyp polypcoreincludedir=$(includedir)/polypcore polypconfdir=$(sysconfdir)/polypaudio -modlibdir=$(libdir)/polypaudio +modlibexecdir=$(libdir)/polypaudio ################################### # Defines # @@ -47,7 +47,7 @@ AM_CFLAGS = -I$(top_srcdir)/src AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS AM_CFLAGS += $(LTDLINCL) AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) -AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" +AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibexecdir)\" #AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\" AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\" AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(POLYPAUDIO_BINARY)\" @@ -113,7 +113,7 @@ polypaudio_LDADD = $(AM_LDADD) libpolypcore.la $(LIBLTDL) \ if PREOPEN_MODS PREOPEN_LIBS = $(PREOPEN_MODS) else -PREOPEN_LIBS = $(modlib_LTLIBRARIES) +PREOPEN_LIBS = $(modlibexec_LTLIBRARIES) endif if FORCE_PREOPEN @@ -589,11 +589,11 @@ polypcoreinclude_HEADERS += \ polypcore/protocol-http.h ### Warning! Due to an obscure bug in libtool/automake it is required -### that the libraries in modlib_LTLIBRARIES are specified in-order, +### that the libraries in modlibexec_LTLIBRARIES are specified in-order, ### i.e. libraries near the end of the list depend on libraries near ### the head, and not the other way! -modlib_LTLIBRARIES = \ +modlibexec_LTLIBRARIES = \ libsocket-util.la \ libiochannel.la \ libsocket-server.la \ @@ -617,7 +617,7 @@ modlib_LTLIBRARIES = \ # We need to emulate sendmsg/recvmsg to support this on Win32 if !OS_IS_WIN32 -modlib_LTLIBRARIES += \ +modlibexec_LTLIBRARIES += \ librtp.la endif @@ -626,7 +626,7 @@ polypcoreinclude_HEADERS += \ polypcore/x11wrap.h \ polypcore/x11prop.h -modlib_LTLIBRARIES += \ +modlibexec_LTLIBRARIES += \ libx11wrap.la \ libx11prop.la endif @@ -736,7 +736,7 @@ libx11prop_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS # Plug-in libraries # ################################### -modlib_LTLIBRARIES += \ +modlibexec_LTLIBRARIES += \ module-cli.la \ module-cli-protocol-tcp.la \ module-simple-protocol-tcp.la \ @@ -755,13 +755,13 @@ modlib_LTLIBRARIES += \ # See comment at librtp.la above if !OS_IS_WIN32 -modlib_LTLIBRARIES += \ +modlibexec_LTLIBRARIES += \ module-rtp-send.la \ module-rtp-recv.la endif if HAVE_AF_UNIX -modlib_LTLIBRARIES += \ +modlibexec_LTLIBRARIES += \ module-cli-protocol-unix.la \ module-simple-protocol-unix.la \ module-esound-protocol-unix.la \ @@ -770,71 +770,71 @@ modlib_LTLIBRARIES += \ endif if HAVE_MKFIFO -modlib_LTLIBRARIES += \ +modlibexec_LTLIBRARIES += \ module-pipe-sink.la \ module-pipe-source.la endif if !OS_IS_WIN32 -modlib_LTLIBRARIES += \ +modlibexec_LTLIBRARIES += \ module-esound-compat-spawnfd.la \ module-esound-compat-spawnpid.la endif if HAVE_REGEX -modlib_LTLIBRARIES += \ +modlibexec_LTLIBRARIES += \ module-match.la endif if HAVE_X11 -modlib_LTLIBRARIES += \ +modlibexec_LTLIBRARIES += \ module-x11-bell.la \ module-x11-publish.la endif if HAVE_OSS -modlib_LTLIBRARIES += \ +modlibexec_LTLIBRARIES += \ liboss-util.la \ module-oss.la \ module-oss-mmap.la endif if HAVE_ALSA -modlib_LTLIBRARIES += \ +modlibexec_LTLIBRARIES += \ libalsa-util.la \ module-alsa-sink.la \ module-alsa-source.la endif if HAVE_SOLARIS -modlib_LTLIBRARIES += \ +modlibexec_LTLIBRARIES += \ module-solaris.la endif if HAVE_HOWL -modlib_LTLIBRARIES += \ +modlibexec_LTLIBRARIES += \ libhowl-wrap.la \ module-zeroconf-publish.la endif if HAVE_LIRC -modlib_LTLIBRARIES += \ +modlibexec_LTLIBRARIES += \ module-lirc.la endif if HAVE_EVDEV -modlib_LTLIBRARIES += \ +modlibexec_LTLIBRARIES += \ module-mmkbd-evdev.la endif if HAVE_JACK -modlib_LTLIBRARIES += \ +modlibexec_LTLIBRARIES += \ module-jack-sink.la \ module-jack-source.la endif if OS_IS_WIN32 -modlib_LTLIBRARIES += \ +modlibexec_LTLIBRARIES += \ module-waveout.la endif @@ -1153,10 +1153,11 @@ default.pa: daemon/default.pa.in Makefile endif daemon.conf: daemon/daemon.conf.in Makefile - sed -e 's,@DLSEARCHPATH\@,$(modlibdir),g' \ + sed -e 's,@DLSEARCHPATH\@,$(modlibexecdir),g' \ -e 's,@DEFAULT_CONFIG_FILE\@,$(DEFAULT_CONFIG_DIR),g' < $< > $@ install-exec-hook: chown root $(DESTDIR)$(bindir)/polypaudio ; true chmod u+s $(DESTDIR)$(bindir)/polypaudio ln -sf pacat $(DESTDIR)$(bindir)/parec + rm -f $(DESTDIR)$(modlibexecdir)/*.a -- cgit From 929899015d23f4af2b19b7b7c56fd8bbd50f519f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 May 2006 15:30:14 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@884 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index b94be1d9..8b5daefb 100644 --- a/doc/todo +++ b/doc/todo @@ -26,7 +26,6 @@ Post 0.8: - fix channel maps in all external backends. Take care when doing volume changes if you're modifying a sink/source since those might have a different map. -- don't install .a files of modules - in avahi-simple: sleep until latency data is available again if NODATA has happened Long term: -- cgit From 55215597c43e81da1560894645dcd27642cc0a47 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 May 2006 17:54:33 +0000 Subject: * add new configure option --with-module-dir= * drop version suffix from soname of libpolyp and friends * add version suffix by default to $(modlibexecdir) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@885 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 13 ++++++ polyplib-browse.pc.in | 2 +- polyplib-glib-mainloop.pc.in | 2 +- polyplib-glib12-mainloop.pc.in | 2 +- polyplib-simple.pc.in | 2 +- polyplib.pc.in | 2 +- src/Makefile.am | 98 +++++++++++++++++++++--------------------- 7 files changed, 66 insertions(+), 55 deletions(-) diff --git a/configure.ac b/configure.ac index 360249ea..cb8e42f5 100644 --- a/configure.ac +++ b/configure.ac @@ -31,6 +31,12 @@ AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/polypaudio/]) AC_SUBST(PA_API_VERSION, 8) AC_SUBST(PA_PROTOCOL_VERSION, 8) +AC_SUBST(LIBPOLYP_VERSION_INFO, [0:0:0]) +AC_SUBST(LIBPOLYPCORE_VERSION_INFO, [0:0:0]) +AC_SUBST(LIBPOLYP_SIMPLE_VERSION_INFO, [0:0:0]) +AC_SUBST(LIBPOLYP_BROWSE_VERSION_INFO, [0:0:0]) +AC_SUBST(LIBPOLYP_MAINLOOP_GLIB_VERSION_INFO, [0:0:0]) + if type -p stow > /dev/null && test -d /usr/local/stow ; then AC_MSG_NOTICE([*** Found /usr/local/stow: default install prefix set to /usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION} ***]) ac_default_prefix="/usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION}" @@ -420,6 +426,13 @@ if test "x$PREOPEN_MODS" != "xall" ; then AC_SUBST(PREOPEN_MODS) fi +AC_ARG_WITH( + [module-dir], + AC_HELP_STRING([--with-module-dir],[Directory where to install the modules to (defaults to ${libdir}/polypaudio-${PA_MAJORMINOR}]), + [modlibexecdir=$withval], [modlibexecdir="${libdir}/polypaudio-${PA_MAJORMINOR}"]) + +AC_SUBST(modlibexecdir) + AC_ARG_ENABLE( [force-preopen], AC_HELP_STRING([--enable-force-preopen],[Preopen modules, even when dlopen() is supported.]), diff --git a/polyplib-browse.pc.in b/polyplib-browse.pc.in index b9d57eef..952e28c1 100644 --- a/polyplib-browse.pc.in +++ b/polyplib-browse.pc.in @@ -6,6 +6,6 @@ includedir=${prefix}/include Name: polyplib-browse Description: Polypaudio network browsing API Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpolyp-browse-@PA_MAJORMINOR@ +Libs: -L${libdir} -lpolyp-browse Cflags: -D_REENTRANT -I${includedir} Requires: polyplib diff --git a/polyplib-glib-mainloop.pc.in b/polyplib-glib-mainloop.pc.in index 3d8f3931..03338c55 100644 --- a/polyplib-glib-mainloop.pc.in +++ b/polyplib-glib-mainloop.pc.in @@ -6,6 +6,6 @@ includedir=${prefix}/include Name: polyplib-glib-mainloop Description: GLIB main loop wrapper for polypaudio Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpolyp-mainloop-glib-@PA_MAJORMINOR@ +Libs: -L${libdir} -lpolyp-mainloop-glib Cflags: -D_REENTRANT -I${includedir} Requires: polyplib glib-2.0 diff --git a/polyplib-glib12-mainloop.pc.in b/polyplib-glib12-mainloop.pc.in index 5ada2e5c..c12a838b 100644 --- a/polyplib-glib12-mainloop.pc.in +++ b/polyplib-glib12-mainloop.pc.in @@ -6,6 +6,6 @@ includedir=${prefix}/include Name: polyplib-glib12-mainloop Description: GLIB main loop wrapper for polypaudio Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpolyp-mainloop-glib12-@PA_MAJORMINOR@ +Libs: -L${libdir} -lpolyp-mainloop-glib12 Cflags: -D_REENTRANT -I${includedir} Requires: polyplib glib diff --git a/polyplib-simple.pc.in b/polyplib-simple.pc.in index 94644df6..fa0ca0b9 100644 --- a/polyplib-simple.pc.in +++ b/polyplib-simple.pc.in @@ -6,6 +6,6 @@ includedir=${prefix}/include Name: polyplib-simple Description: Simplified synchronous client interface to polypaudio Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpolyp-simple-@PA_MAJORMINOR@ +Libs: -L${libdir} -lpolyp-simple Cflags: -D_REENTRANT -I${includedir} Requires: polyplib diff --git a/polyplib.pc.in b/polyplib.pc.in index f495def2..2d073a93 100644 --- a/polyplib.pc.in +++ b/polyplib.pc.in @@ -6,6 +6,6 @@ includedir=${prefix}/include Name: polyplib Description: Client interface to polypaudio Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpolyp-@PA_MAJORMINOR@ +Libs: -L${libdir} -lpolyp Cflags: -D_REENTRANT -I${includedir} Requires: diff --git a/src/Makefile.am b/src/Makefile.am index 02060e92..bd48a0fb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,8 +26,6 @@ polypincludedir=$(includedir)/polyp polypcoreincludedir=$(includedir)/polypcore polypconfdir=$(sysconfdir)/polypaudio -modlibexecdir=$(libdir)/polypaudio - ################################### # Defines # ################################### @@ -146,32 +144,32 @@ endif bin_SCRIPTS = esdcompat.sh pacat_SOURCES = utils/pacat.c -pacat_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la +pacat_LDADD = $(AM_LDADD) libpolyp.la pacat_CFLAGS = $(AM_CFLAGS) pacat_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) paplay_SOURCES = utils/paplay.c -paplay_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) +paplay_LDADD = $(AM_LDADD) libpolyp.la $(LIBSNDFILE_LIBS) paplay_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) paplay_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) pactl_SOURCES = utils/pactl.c -pactl_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS) +pactl_LDADD = $(AM_LDADD) libpolyp.la $(LIBSNDFILE_LIBS) pactl_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) pactl_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) pacmd_SOURCES = utils/pacmd.c polypcore/pid.c polypcore/pid.h pacmd_CFLAGS = $(AM_CFLAGS) -pacmd_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la +pacmd_LDADD = $(AM_LDADD) libpolyp.la pacmd_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) pax11publish_SOURCES = utils/pax11publish.c pax11publish_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) -pax11publish_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) +pax11publish_LDADD = $(AM_LDADD) libpolyp.la $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) pax11publish_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) pabrowse_SOURCES = utils/pabrowse.c -pabrowse_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-browse-@PA_MAJORMINOR@.la +pabrowse_LDADD = $(AM_LDADD) libpolyp.la libpolyp-browse.la pabrowse_CFLAGS = $(AM_CFLAGS) pabrowse_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -210,12 +208,12 @@ endif mainloop_test_SOURCES = tests/mainloop-test.c mainloop_test_CFLAGS = $(AM_CFLAGS) -mainloop_test_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la +mainloop_test_LDADD = $(AM_LDADD) libpolyp.la mainloop_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) thread_mainloop_test_SOURCES = tests/thread-mainloop-test.c thread_mainloop_test_CFLAGS = $(AM_CFLAGS) -thread_mainloop_test_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la +thread_mainloop_test_LDADD = $(AM_LDADD) libpolyp.la thread_mainloop_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) utf8_test_SOURCES = tests/utf8-test.c @@ -229,12 +227,12 @@ mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpolypcore.la mcalign_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) pacat_simple_SOURCES = tests/pacat-simple.c -pacat_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la +pacat_simple_LDADD = $(AM_LDADD) libpolyp.la libpolyp-simple.la pacat_simple_CFLAGS = $(AM_CFLAGS) pacat_simple_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) parec_simple_SOURCES = tests/parec-simple.c -parec_simple_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-simple-@PA_MAJORMINOR@.la +parec_simple_LDADD = $(AM_LDADD) libpolyp.la libpolyp-simple.la parec_simple_CFLAGS = $(AM_CFLAGS) parec_simple_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -245,12 +243,12 @@ strlist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) voltest_SOURCES = tests/voltest.c voltest_CFLAGS = $(AM_CFLAGS) -voltest_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la +voltest_LDADD = $(AM_LDADD) libpolyp.la voltest_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) channelmap_test_SOURCES = tests/channelmap-test.c channelmap_test_CFLAGS = $(AM_CFLAGS) -channelmap_test_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la +channelmap_test_LDADD = $(AM_LDADD) libpolyp.la channelmap_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) cpulimit_test_SOURCES = tests/cpulimit-test.c daemon/cpulimit.c daemon/cpulimit.h @@ -265,12 +263,12 @@ cpulimit_test2_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) mainloop_test_glib_SOURCES = $(mainloop_test_SOURCES) mainloop_test_glib_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB20_CFLAGS) -DGLIB_MAIN_LOOP -mainloop_test_glib_LDADD = $(mainloop_test_LDADD) $(GLIB20_LIBS) libpolyp-mainloop-glib-@PA_MAJORMINOR@.la +mainloop_test_glib_LDADD = $(mainloop_test_LDADD) $(GLIB20_LIBS) libpolyp-mainloop-glib.la mainloop_test_glib_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) mainloop_test_glib12_SOURCES = $(mainloop_test_SOURCES) mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MAIN_LOOP -mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12-@PA_MAJORMINOR@.la +mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12.la mainloop_test_glib12_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) memblockq_test_SOURCES = \ @@ -287,7 +285,7 @@ memblockq_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) memblockq_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) sync_playback_SOURCES = tests/sync-playback.c -sync_playback_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la +sync_playback_LDADD = $(AM_LDADD) libpolyp.la sync_playback_CFLAGS = $(AM_CFLAGS) sync_playback_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -323,26 +321,26 @@ polypinclude_HEADERS += \ endif lib_LTLIBRARIES = \ - libpolyp-@PA_MAJORMINOR@.la \ - libpolyp-simple-@PA_MAJORMINOR@.la + libpolyp.la \ + libpolyp-simple.la if HAVE_HOWL lib_LTLIBRARIES += \ - libpolyp-browse-@PA_MAJORMINOR@.la + libpolyp-browse.la endif if HAVE_GLIB20 lib_LTLIBRARIES += \ - libpolyp-mainloop-glib-@PA_MAJORMINOR@.la + libpolyp-mainloop-glib.la endif if HAVE_GLIB12 lib_LTLIBRARIES += \ - libpolyp-mainloop-glib12-@PA_MAJORMINOR@.la + libpolyp-mainloop-glib12.la endif # Public interface -libpolyp_@PA_MAJORMINOR@_la_SOURCES = \ +libpolyp_la_SOURCES = \ polyp/cdecl.h \ polyp/channelmap.c polyp/channelmap.h \ polyp/client-conf.c polyp/client-conf.h \ @@ -366,7 +364,7 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = \ polypcore/poll.c polypcore/poll.h # Internal stuff that is shared with libpolypcore -libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ +libpolyp_la_SOURCES += \ polypcore/authkey.c polypcore/authkey.h \ polypcore/conf-parser.c polypcore/conf-parser.h \ polypcore/dynarray.c polypcore/dynarray.h \ @@ -398,49 +396,49 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ polypcore/llist.h if OS_IS_WIN32 -libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ +libpolyp_la_SOURCES += \ polypcore/dllmain.c endif if HAVE_X11 -libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ +libpolyp_la_SOURCES += \ polyp/client-conf-x11.c polyp/client-conf-x11.h \ polypcore/x11prop.c polypcore/x11prop.h endif -libpolyp_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) -libpolyp_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 -libpolyp_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) +libpolyp_la_CFLAGS = $(AM_CFLAGS) +libpolyp_la_LDFLAGS = -version-info $(LIBPOLYP_VERSION_INFO) +libpolyp_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) if HAVE_X11 -libpolyp_@PA_MAJORMINOR@_la_CFLAGS += $(X_CFLAGS) -libpolyp_@PA_MAJORMINOR@_la_LDFLAGS += $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) +libpolyp_la_CFLAGS += $(X_CFLAGS) +libpolyp_la_LDFLAGS += $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) endif if HAVE_LIBASYNCNS -libpolyp_@PA_MAJORMINOR@_la_CFLAGS += $(LIBASYNCNS_CFLAGS) -libpolyp_@PA_MAJORMINOR@_la_LIBADD += $(LIBASYNCNS_LIBS) +libpolyp_la_CFLAGS += $(LIBASYNCNS_CFLAGS) +libpolyp_la_LIBADD += $(LIBASYNCNS_LIBS) endif -libpolyp_simple_@PA_MAJORMINOR@_la_SOURCES = polyp/simple.c polyp/simple.h -libpolyp_simple_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) -libpolyp_simple_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la -libpolyp_simple_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 +libpolyp_simple_la_SOURCES = polyp/simple.c polyp/simple.h +libpolyp_simple_la_CFLAGS = $(AM_CFLAGS) +libpolyp_simple_la_LIBADD = $(AM_LIBADD) libpolyp.la +libpolyp_simple_la_LDFLAGS = -version-info $(LIBPOLYP_SIMPLE_VERSION_INFO) -libpolyp_browse_@PA_MAJORMINOR@_la_SOURCES = polyp/browser.c polyp/browser.h -libpolyp_browse_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) -libpolyp_browse_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la $(HOWL_LIBS) -libpolyp_browse_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 +libpolyp_browse_la_SOURCES = polyp/browser.c polyp/browser.h +libpolyp_browse_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) +libpolyp_browse_la_LIBADD = $(AM_LIBADD) libpolyp.la $(HOWL_LIBS) +libpolyp_browse_la_LDFLAGS = -version-info $(LIBPOLYP_BROWSE_VERSION_INFO) -libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_SOURCES = polyp/glib-mainloop.h polyp/glib-mainloop.c -libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) -libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la $(GLIB20_LIBS) -libpolyp_mainloop_glib_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 +libpolyp_mainloop_glib_la_SOURCES = polyp/glib-mainloop.h polyp/glib-mainloop.c +libpolyp_mainloop_glib_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) +libpolyp_mainloop_glib_la_LIBADD = $(AM_LIBADD) libpolyp.la $(GLIB20_LIBS) +libpolyp_mainloop_glib_la_LDFLAGS = -version-info $(LIBPOLYP_MAINLOOP_GLIB_VERSION_INFO) -libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_SOURCES = polyp/glib-mainloop.h polyp/glib12-mainloop.c -libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS) -libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la $(GLIB12_LIBS) -libpolyp_mainloop_glib12_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 +libpolyp_mainloop_glib12_la_SOURCES = polyp/glib-mainloop.h polyp/glib12-mainloop.c +libpolyp_mainloop_glib12_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS) +libpolyp_mainloop_glib12_la_LIBADD = $(AM_LIBADD) libpolyp.la $(GLIB12_LIBS) +libpolyp_mainloop_glib12_la_LDFLAGS = -version-info $(LIBPOLYP_MAINLOOP_GLIB_VERSION_INFO) ################################### # Daemon core library # @@ -557,7 +555,7 @@ libpolypcore_la_SOURCES += \ endif libpolypcore_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBOIL_CFLAGS) -libpolypcore_la_LDFLAGS = -avoid-version +libpolypcore_la_LDFLAGS = -version-info $(LIBPOLYPCORE_VERSION_INFO) libpolypcore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) $(LIBOIL_LIBS) ################################### -- cgit From c2c8539201307cf8bf500ce7b77c8f09eaa655b7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 May 2006 18:28:03 +0000 Subject: bump version number to 0.9 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@886 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 4 ++-- src/utils/pacat.c | 2 +- src/utils/pactl.c | 2 +- src/utils/paplay.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index cb8e42f5..52b7a6e3 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. AC_PREREQ(2.57) -AC_INIT([polypaudio],[0.8.1],[mzcbylcnhqvb (at) 0pointer (dot) de]) +AC_INIT([polypaudio],[0.9],[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([src/daemon/main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) @@ -28,7 +28,7 @@ AM_INIT_AUTOMAKE([foreign -Wall]) AC_SUBST(PA_MAJORMINOR, "$PACKAGE_VERSION") AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/polypaudio/]) -AC_SUBST(PA_API_VERSION, 8) +AC_SUBST(PA_API_VERSION, 9) AC_SUBST(PA_PROTOCOL_VERSION, 8) AC_SUBST(LIBPOLYP_VERSION_INFO, [0:0:0]) diff --git a/src/utils/pacat.c b/src/utils/pacat.c index c8890bbb..529cebae 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -40,7 +40,7 @@ #define TIME_EVENT_USEC 50000 -#if PA_API_VERSION != 8 +#if PA_API_VERSION != 9 #error Invalid Polypaudio API version #endif diff --git a/src/utils/pactl.c b/src/utils/pactl.c index fcc677d9..7a3d3737 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -39,7 +39,7 @@ #include #include -#if PA_API_VERSION != 8 +#if PA_API_VERSION != 9 #error Invalid Polypaudio API version #endif diff --git a/src/utils/paplay.c b/src/utils/paplay.c index 7f665413..ad9d4553 100644 --- a/src/utils/paplay.c +++ b/src/utils/paplay.c @@ -38,7 +38,7 @@ #include #include -#if PA_API_VERSION != 8 +#if PA_API_VERSION != 9 #error Invalid Polypaudio API version #endif -- cgit From c63cc7bb79fb60b6493c3e80648501fbe8a83963 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 May 2006 19:15:06 +0000 Subject: change version number from "0.9" to "0.9.0" to make version comparisons easier git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@887 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 52b7a6e3..18332405 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. AC_PREREQ(2.57) -AC_INIT([polypaudio],[0.9],[mzcbylcnhqvb (at) 0pointer (dot) de]) +AC_INIT([polypaudio],[0.9.0],[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([src/daemon/main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) -- cgit From 4b6ab291a787ff597c938842b569a35434ab11d8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 May 2006 23:47:38 +0000 Subject: * modify pa_channel_map_init_auto() to take an extra argument specifying the standard to use (ALSA, AIFF, ...) * add some more validity checks to pa_source_new(),pa_sink_new(),pa_sink_input_new(),pa_source_output_new() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@888 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 44 -------------- src/modules/alsa-util.h | 2 - src/modules/module-alsa-sink.c | 15 +---- src/modules/module-alsa-source.c | 13 +--- src/modules/module-combine.c | 2 +- src/modules/module-jack-sink.c | 2 +- src/modules/module-jack-source.c | 2 +- src/modules/module-null-sink.c | 2 +- src/modules/module-oss-mmap.c | 2 +- src/modules/module-oss.c | 2 +- src/modules/module-pipe-sink.c | 2 +- src/modules/module-pipe-source.c | 2 +- src/modules/module-tunnel.c | 2 +- src/modules/rtp/module-rtp-send.c | 2 +- src/polyp/channelmap.c | 125 +++++++++++++++++++++++++++----------- src/polyp/channelmap.h | 14 ++++- src/polyp/stream.c | 2 +- src/polypcore/core-scache.c | 2 +- src/polypcore/modargs.c | 5 +- src/polypcore/modargs.h | 2 +- src/polypcore/resampler.c | 4 +- src/polypcore/sink-input.c | 58 ++++++++++-------- src/polypcore/sink.c | 37 +++++++---- src/polypcore/sound-file.c | 2 +- src/polypcore/source-output.c | 37 +++++++---- src/polypcore/source.c | 36 +++++++---- src/tests/channelmap-test.c | 10 ++- 27 files changed, 237 insertions(+), 191 deletions(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index a8192165..503b8efb 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -340,47 +340,3 @@ snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name) { return elem; } - -pa_channel_map* pa_alsa_channel_map_init_auto(pa_channel_map *m, unsigned channels) { - assert(m); - assert(channels > 0); - assert(channels <= PA_CHANNELS_MAX); - - pa_channel_map_init(m); - - m->channels = channels; - - /* The standard ALSA channel order */ - - switch (channels) { - case 1: - m->map[0] = PA_CHANNEL_POSITION_MONO; - return m; - - case 8: - m->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; - m->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; - /* Fall through */ - - case 6: - m->map[5] = PA_CHANNEL_POSITION_LFE; - /* Fall through */ - - case 5: - m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; - /* Fall through */ - - case 4: - m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT; - m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; - /* Fall through */ - - case 2: - m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - return m; - - default: - return NULL; - } -} diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h index bad6e9bf..69d4eddc 100644 --- a/src/modules/alsa-util.h +++ b/src/modules/alsa-util.h @@ -42,6 +42,4 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint3 int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev); snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name); -pa_channel_map* pa_alsa_channel_map_init_auto(pa_channel_map *m, unsigned channels); - #endif diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 99e74bfc..47065659 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -324,19 +324,8 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": failed to parse sample specification"); - goto fail; - } - - pa_alsa_channel_map_init_auto(&map, ss.channels); - if ((pa_modargs_get_channel_map(ma, &map) < 0)) { - pa_log(__FILE__": invalid channel map."); - goto fail; - } - - if (ss.channels != map.channels) { - pa_log(__FILE__": channel map and sample specification don't match."); + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) { + pa_log(__FILE__": failed to parse sample specification and channel map"); goto fail; } diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 660bc83b..d46f8e42 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -316,22 +316,11 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) { pa_log(__FILE__": failed to parse sample specification"); goto fail; } - pa_alsa_channel_map_init_auto(&map, ss.channels); - if ((pa_modargs_get_channel_map(ma, &map) < 0)) { - pa_log(__FILE__": invalid channel map."); - goto fail; - } - - if (ss.channels != map.channels) { - pa_log(__FILE__": channel map and sample specification don't match."); - goto fail; - } - frame_size = pa_frame_size(&ss); /* Fix latency to 100ms */ diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 3b927d13..369778a6 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -361,7 +361,7 @@ int pa__init(pa_core *c, pa_module*m) { if (ss.channels == master_sink->sample_spec.channels) map = master_sink->channel_map; else - pa_channel_map_init_auto(&map, ss.channels); + pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_DEFAULT); if ((pa_modargs_get_channel_map(ma, &map) < 0)) { pa_log(__FILE__": invalid channel map."); diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index 09030530..324a2cb3 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -296,7 +296,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - pa_channel_map_init_auto(&map, channels); + pa_channel_map_init_auto(&map, channels, PA_CHANNEL_MAP_ALSA); if (pa_modargs_get_channel_map(ma, &map) < 0 || map.channels != channels) { pa_log(__FILE__": failed to parse channel_map= argument."); goto fail; diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index ad39b9dd..94cabbea 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -294,7 +294,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - pa_channel_map_init_auto(&map, channels); + pa_channel_map_init_auto(&map, channels, PA_CHANNEL_MAP_ALSA); if (pa_modargs_get_channel_map(ma, &map) < 0 || map.channels != channels) { pa_log(__FILE__": failed to parse channel_map= argument."); goto fail; diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index 9c564429..5cdfeab8 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -104,7 +104,7 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { pa_log(__FILE__": invalid sample format specification or channel map."); goto fail; } diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index e032ce46..b8012214 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -383,7 +383,7 @@ int pa__init(pa_core *c, pa_module*m) { } u->sample_spec = c->default_sample_spec; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &u->sample_spec, &map) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &u->sample_spec, &map, PA_CHANNEL_MAP_ALSA) < 0) { pa_log(__FILE__": failed to parse sample specification or channel map"); goto fail; } diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 4d811a76..eab9a60a 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -347,7 +347,7 @@ int pa__init(pa_core *c, pa_module*m) { mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) { pa_log(__FILE__": failed to parse sample specification or channel map"); goto fail; } diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index 2be1b297..0fb73cd8 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -154,7 +154,7 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { pa_log(__FILE__": invalid sample format specification"); goto fail; } diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index c80bfd09..d999754a 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -132,7 +132,7 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { pa_log(__FILE__": invalid sample format specification or channel map"); goto fail; } diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index bffcc7c0..2e04b120 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -895,7 +895,7 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { pa_log(__FILE__": invalid sample format specification"); goto fail; } diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 0bb20979..d0def859 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -197,7 +197,7 @@ int pa__init(pa_core *c, pa_module*m) { } if (ss.channels != cm.channels) - pa_channel_map_init_auto(&cm, ss.channels); + pa_channel_map_init_auto(&cm, ss.channels, PA_CHANNEL_MAP_AIFF); payload = pa_rtp_payload_from_sample_spec(&ss); diff --git a/src/polyp/channelmap.c b/src/polyp/channelmap.c index 794711ae..8d16f7b3 100644 --- a/src/polyp/channelmap.c +++ b/src/polyp/channelmap.c @@ -112,7 +112,7 @@ pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m) { return m; } -pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels) { +pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) { assert(m); assert(channels > 0); assert(channels <= PA_CHANNELS_MAX); @@ -121,46 +121,99 @@ pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels) { m->channels = channels; - /* This is somewhat compatible with RFC3551 */ - - switch (channels) { - case 1: - m->map[0] = PA_CHANNEL_POSITION_MONO; - return m; - - case 6: - m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - m->map[1] = PA_CHANNEL_POSITION_SIDE_LEFT; - m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; - m->map[3] = PA_CHANNEL_POSITION_FRONT_RIGHT; - m->map[4] = PA_CHANNEL_POSITION_SIDE_RIGHT; - m->map[5] = PA_CHANNEL_POSITION_LFE; - return m; + switch (def) { + case PA_CHANNEL_MAP_AIFF: - case 5: - m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; - m->map[3] = PA_CHANNEL_POSITION_REAR_LEFT; - m->map[4] = PA_CHANNEL_POSITION_REAR_RIGHT; - /* Fall through */ + /* This is somewhat compatible with RFC3551 */ - case 2: - m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - return m; + switch (channels) { + case 1: + m->map[0] = PA_CHANNEL_POSITION_MONO; + return m; + + case 6: + m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + m->map[1] = PA_CHANNEL_POSITION_SIDE_LEFT; + m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; + m->map[3] = PA_CHANNEL_POSITION_FRONT_RIGHT; + m->map[4] = PA_CHANNEL_POSITION_SIDE_RIGHT; + m->map[5] = PA_CHANNEL_POSITION_LFE; + return m; + + case 5: + m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; + m->map[3] = PA_CHANNEL_POSITION_REAR_LEFT; + m->map[4] = PA_CHANNEL_POSITION_REAR_RIGHT; + /* Fall through */ + + case 2: + m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + return m; + + case 3: + m->map[0] = PA_CHANNEL_POSITION_LEFT; + m->map[1] = PA_CHANNEL_POSITION_RIGHT; + m->map[2] = PA_CHANNEL_POSITION_CENTER; + return m; + + case 4: + m->map[0] = PA_CHANNEL_POSITION_LEFT; + m->map[1] = PA_CHANNEL_POSITION_CENTER; + m->map[2] = PA_CHANNEL_POSITION_RIGHT; + m->map[3] = PA_CHANNEL_POSITION_LFE; + return m; + + default: + return NULL; + } - case 3: - m->map[0] = PA_CHANNEL_POSITION_LEFT; - m->map[1] = PA_CHANNEL_POSITION_RIGHT; - m->map[2] = PA_CHANNEL_POSITION_CENTER; - return m; + case PA_CHANNEL_MAP_ALSA: + + switch (channels) { + case 1: + m->map[0] = PA_CHANNEL_POSITION_MONO; + return m; + + case 8: + m->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; + m->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; + /* Fall through */ + + case 6: + m->map[5] = PA_CHANNEL_POSITION_LFE; + /* Fall through */ + + case 5: + m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; + /* Fall through */ + + case 4: + m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT; + m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; + /* Fall through */ + + case 2: + m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + return m; + + default: + return NULL; + } - case 4: - m->map[0] = PA_CHANNEL_POSITION_LEFT; - m->map[1] = PA_CHANNEL_POSITION_CENTER; - m->map[2] = PA_CHANNEL_POSITION_RIGHT; - m->map[3] = PA_CHANNEL_POSITION_LFE; - return m; + case PA_CHANNEL_MAP_AUX: { + unsigned i; + + if (channels >= PA_CHANNELS_MAX) + return NULL; + + for (i = 0; i < channels; i++) + m->map[i] = PA_CHANNEL_POSITION_AUX0 + i; + return m; + } + default: return NULL; } diff --git a/src/polyp/channelmap.h b/src/polyp/channelmap.h index 0fd1e593..8270a5b3 100644 --- a/src/polyp/channelmap.h +++ b/src/polyp/channelmap.h @@ -120,6 +120,15 @@ typedef enum pa_channel_position { PA_CHANNEL_POSITION_MAX } pa_channel_position_t; +/** A list of channel mapping definitions for pa_channel_map_init_auto() */ +typedef enum pa_channel_map_def { + PA_CHANNEL_MAP_AIFF, /**< The mapping from RFC3551, which is based on AIFF-C */ + PA_CHANNEL_MAP_ALSA, /**< The default mapping used by ALSA */ + PA_CHANNEL_MAP_AUX, /**< Only aux channels */ + + PA_CHANNEL_MAP_DEFAULT = PA_CHANNEL_MAP_AIFF /**< The default channel map */ +} pa_channel_map_def_t; + /** A channel map which can be used to attach labels to specific * channels of a stream. These values are relevant for conversion and * mixing of streams */ @@ -138,9 +147,8 @@ pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m); pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m); /** Initialize the specified channel map for the specified number - * of channels using default labels and return a pointer to it. - * Uses the mapping from RFC3551, which is based on AIFF-C. */ -pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels); + * of channels using default labels and return a pointer to it. */ +pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def); /** Return a text label for the specified channel position */ const char* pa_channel_position_to_string(pa_channel_position_t pos); diff --git a/src/polyp/stream.c b/src/polyp/stream.c index bccdebe5..b2711ce0 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -74,7 +74,7 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * if (map) s->channel_map = *map; else - pa_channel_map_init_auto(&s->channel_map, ss->channels); + pa_channel_map_init_auto(&s->channel_map, ss->channels, PA_CHANNEL_MAP_DEFAULT); s->channel = 0; s->channel_valid = 0; diff --git a/src/polypcore/core-scache.c b/src/polypcore/core-scache.c index 82c61a1d..3bba38ed 100644 --- a/src/polypcore/core-scache.c +++ b/src/polypcore/core-scache.c @@ -141,7 +141,7 @@ int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, c if (ss) { e->sample_spec = *ss; - pa_channel_map_init_auto(&e->channel_map, ss->channels); + pa_channel_map_init_auto(&e->channel_map, ss->channels, PA_CHANNEL_MAP_DEFAULT); e->volume.channels = e->sample_spec.channels; } diff --git a/src/polypcore/modargs.c b/src/polypcore/modargs.c index 6a02df0a..713326bf 100644 --- a/src/polypcore/modargs.c +++ b/src/polypcore/modargs.c @@ -280,7 +280,7 @@ int pa_modargs_get_channel_map(pa_modargs *ma, pa_channel_map *rmap) { return 0; } -int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *rss, pa_channel_map *rmap) { +int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *rss, pa_channel_map *rmap, pa_channel_map_def_t def) { pa_sample_spec ss; pa_channel_map map; @@ -293,7 +293,8 @@ int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *r if (pa_modargs_get_sample_spec(ma, &ss) < 0) return -1; - pa_channel_map_init_auto(&map, ss.channels); + if (!pa_channel_map_init_auto(&map, ss.channels, def)) + map.channels = 0; if (pa_modargs_get_channel_map(ma, &map) < 0) return -1; diff --git a/src/polypcore/modargs.h b/src/polypcore/modargs.h index 481ead99..b6977d37 100644 --- a/src/polypcore/modargs.h +++ b/src/polypcore/modargs.h @@ -55,6 +55,6 @@ pa_modargs_get_channel_map(). Not always suitable, since this routine initializes the map parameter based on the channels field of the ss structure if no channel_map is found, using pa_channel_map_init_auto() */ -int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *ss, pa_channel_map *map); +int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *ss, pa_channel_map *map, pa_channel_map_def_t def); #endif diff --git a/src/polypcore/resampler.c b/src/polypcore/resampler.c index 7e85e270..b2a8874b 100644 --- a/src/polypcore/resampler.c +++ b/src/polypcore/resampler.c @@ -101,12 +101,12 @@ pa_resampler* pa_resampler_new( if (am) r->i_cm = *am; else - pa_channel_map_init_auto(&r->i_cm, r->i_ss.channels); + pa_channel_map_init_auto(&r->i_cm, r->i_ss.channels, PA_CHANNEL_MAP_DEFAULT); if (bm) r->o_cm = *bm; else - pa_channel_map_init_auto(&r->o_cm, r->o_ss.channels); + pa_channel_map_init_auto(&r->o_cm, r->o_ss.channels, PA_CHANNEL_MAP_DEFAULT); r->i_fz = pa_frame_size(a); r->o_fz = pa_frame_size(b); diff --git a/src/polypcore/sink-input.c b/src/polypcore/sink-input.c index 26e63b85..c1026390 100644 --- a/src/polypcore/sink-input.c +++ b/src/polypcore/sink-input.c @@ -32,32 +32,53 @@ #include #include #include +#include #include "sink-input.h" #define CONVERT_BUFFER_LENGTH 4096 +#define CHECK_VALIDITY_RETURN_NULL(condition) \ +do {\ +if (!(condition)) \ + return NULL; \ +} while (0) + pa_sink_input* pa_sink_input_new( - pa_sink *s, - const char *driver, - const char *name, - const pa_sample_spec *spec, - const pa_channel_map *map, - const pa_cvolume *volume, - int variable_rate, - int resample_method) { + pa_sink *s, + const char *driver, + const char *name, + const pa_sample_spec *spec, + const pa_channel_map *map, + const pa_cvolume *volume, + int variable_rate, + int resample_method) { pa_sink_input *i; pa_resampler *resampler = NULL; int r; char st[256]; pa_channel_map tmap; + pa_cvolume tvol; assert(s); assert(spec); assert(s->state == PA_SINK_RUNNING); + CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec)); + + if (!map) + map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT); + if (!volume) + volume = pa_cvolume_reset(&tvol, spec->channels); + CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map)); + CHECK_VALIDITY_RETURN_NULL(volume && pa_cvolume_valid(volume)); + CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels); + CHECK_VALIDITY_RETURN_NULL(volume->channels == spec->channels); + CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver)); + CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name)); + if (pa_idxset_size(s->inputs) >= PA_MAX_INPUTS_PER_SINK) { pa_log_warn(__FILE__": Failed to create sink input: too many inputs per sink."); return NULL; @@ -66,19 +87,6 @@ pa_sink_input* pa_sink_input_new( if (resample_method == PA_RESAMPLER_INVALID) resample_method = s->core->resample_method; - if (map && spec->channels != map->channels) - return NULL; - - if (volume && spec->channels != volume->channels) - return NULL; - - if (!map) { - if (!(pa_channel_map_init_auto(&tmap, spec->channels))) - return NULL; - - map = &tmap; - } - if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec) || !pa_channel_map_equal(map, &s->channel_map)) if (!(resampler = pa_resampler_new(spec, map, &s->sample_spec, &s->channel_map, s->core->memblock_stat, resample_method))) return NULL; @@ -94,12 +102,8 @@ pa_sink_input* pa_sink_input_new( i->sample_spec = *spec; i->channel_map = *map; - - if (volume) - i->volume = *volume; - else - pa_cvolume_reset(&i->volume, spec->channels); - + i->volume = *volume; + i->peek = NULL; i->drop = NULL; i->kill = NULL; diff --git a/src/polypcore/sink.c b/src/polypcore/sink.c index 17294059..b59f1eaa 100644 --- a/src/polypcore/sink.c +++ b/src/polypcore/sink.c @@ -29,6 +29,7 @@ #include #include + #include #include #include @@ -36,29 +37,46 @@ #include #include #include +#include #include "sink.h" #define MAX_MIX_CHANNELS 32 +#define CHECK_VALIDITY_RETURN_NULL(condition) \ +do {\ +if (!(condition)) \ + return NULL; \ +} while (0) + pa_sink* pa_sink_new( - pa_core *core, - const char *driver, - const char *name, - int fail, - const pa_sample_spec *spec, - const pa_channel_map *map) { + pa_core *core, + const char *driver, + const char *name, + int fail, + const pa_sample_spec *spec, + const pa_channel_map *map) { pa_sink *s; char *n = NULL; char st[256]; int r; + pa_channel_map tmap; assert(core); assert(name); - assert(*name); assert(spec); + CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec)); + + if (!map) + map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT); + + CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map)); + CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels); + CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver)); + CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name) && *name); + s = pa_xnew(pa_sink, 1); if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) { @@ -75,10 +93,7 @@ pa_sink* pa_sink_new( s->owner = NULL; s->sample_spec = *spec; - if (map) - s->channel_map = *map; - else - pa_channel_map_init_auto(&s->channel_map, spec->channels); + s->channel_map = *map; s->inputs = pa_idxset_new(NULL, NULL); diff --git a/src/polypcore/sound-file.c b/src/polypcore/sound-file.c index a6ccb064..f0378009 100644 --- a/src/polypcore/sound-file.c +++ b/src/polypcore/sound-file.c @@ -75,7 +75,7 @@ int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_channel_map *ma } if (map) - pa_channel_map_init_auto(map, ss->channels); + pa_channel_map_init_auto(map, ss->channels, PA_CHANNEL_MAP_DEFAULT); if ((l = pa_frame_size(ss)*sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) { pa_log(__FILE__": File too large"); diff --git a/src/polypcore/source-output.c b/src/polypcore/source-output.c index 0cb5f356..b3113071 100644 --- a/src/polypcore/source-output.c +++ b/src/polypcore/source-output.c @@ -31,16 +31,23 @@ #include #include #include +#include #include "source-output.h" +#define CHECK_VALIDITY_RETURN_NULL(condition) \ +do {\ +if (!(condition)) \ + return NULL; \ +} while (0) + pa_source_output* pa_source_output_new( - pa_source *s, - const char *driver, - const char *name, - const pa_sample_spec *spec, - const pa_channel_map *map, - int resample_method) { + pa_source *s, + const char *driver, + const char *name, + const pa_sample_spec *spec, + const pa_channel_map *map, + int resample_method) { pa_source_output *o; pa_resampler *resampler = NULL; @@ -51,7 +58,17 @@ pa_source_output* pa_source_output_new( assert(s); assert(spec); assert(s->state == PA_SOURCE_RUNNING); + + CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec)); + + if (!map) + map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT); + CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map)); + CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels); + CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver)); + CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name)); + if (pa_idxset_size(s->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { pa_log(__FILE__": Failed to create source output: too many outputs per source."); return NULL; @@ -60,16 +77,11 @@ pa_source_output* pa_source_output_new( if (resample_method == PA_RESAMPLER_INVALID) resample_method = s->core->resample_method; - if (!map) { - pa_channel_map_init_auto(&tmap, spec->channels); - map = &tmap; - } - if (!pa_sample_spec_equal(&s->sample_spec, spec) || !pa_channel_map_equal(&s->channel_map, map)) if (!(resampler = pa_resampler_new(&s->sample_spec, &s->channel_map, spec, map, s->core->memblock_stat, resample_method))) return NULL; - o = pa_xmalloc(sizeof(pa_source_output)); + o = pa_xnew(pa_source_output, 1); o->ref = 1; o->state = PA_SOURCE_OUTPUT_RUNNING; o->name = pa_xstrdup(name); @@ -137,7 +149,6 @@ static void source_output_free(pa_source_output* o) { pa_xfree(o); } - void pa_source_output_unref(pa_source_output* o) { assert(o); assert(o->ref >= 1); diff --git a/src/polypcore/source.c b/src/polypcore/source.c index 3a78825b..fca281a7 100644 --- a/src/polypcore/source.c +++ b/src/polypcore/source.c @@ -34,26 +34,43 @@ #include #include #include +#include #include "source.h" +#define CHECK_VALIDITY_RETURN_NULL(condition) \ +do {\ +if (!(condition)) \ + return NULL; \ +} while (0) + pa_source* pa_source_new( - pa_core *core, - const char *driver, - const char *name, - int fail, - const pa_sample_spec *spec, - const pa_channel_map *map) { + pa_core *core, + const char *driver, + const char *name, + int fail, + const pa_sample_spec *spec, + const pa_channel_map *map) { pa_source *s; char st[256]; int r; + pa_channel_map tmap; assert(core); assert(name); - assert(*name); assert(spec); + CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec)); + + if (!map) + map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT); + + CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map)); + CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels); + CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver)); + CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name) && *name); + s = pa_xnew(pa_source, 1); if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SOURCE, s, fail))) { @@ -70,10 +87,7 @@ pa_source* pa_source_new( s->owner = NULL; s->sample_spec = *spec; - if (map) - s->channel_map = *map; - else - pa_channel_map_init_auto(&s->channel_map, spec->channels); + s->channel_map = *map; s->outputs = pa_idxset_new(NULL, NULL); s->monitor_of = NULL; diff --git a/src/tests/channelmap-test.c b/src/tests/channelmap-test.c index 522c136f..c6644229 100644 --- a/src/tests/channelmap-test.c +++ b/src/tests/channelmap-test.c @@ -10,10 +10,18 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { char cm[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_channel_map map, map2; - pa_channel_map_init_auto(&map, 5); + pa_channel_map_init_auto(&map, 6, PA_CHANNEL_MAP_AIFF); fprintf(stderr, "map: <%s>\n", pa_channel_map_snprint(cm, sizeof(cm), &map)); + pa_channel_map_init_auto(&map, 6, PA_CHANNEL_MAP_AUX); + + fprintf(stderr, "map: <%s>\n", pa_channel_map_snprint(cm, sizeof(cm), &map)); + + pa_channel_map_init_auto(&map, 6, PA_CHANNEL_MAP_ALSA); + + fprintf(stderr, "map: <%s>\n", pa_channel_map_snprint(cm, sizeof(cm), &map)); + pa_channel_map_parse(&map2, cm); assert(pa_channel_map_equal(&map, &map2)); -- cgit From 05c14685203b5ced74bfec0e6a3b3aa3f8721c51 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 17 May 2006 06:31:18 +0000 Subject: Use default channel map for Solaris module. There doesn't seem to be a standard for > 2 channels, so we'll have to rely on the user. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@889 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-solaris.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index eaac9e6e..3e7c2fb4 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -525,7 +525,7 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { pa_log(__FILE__": failed to parse sample specification"); goto fail; } -- cgit From c752e11c02b0059b0212c3c3358b3cc0ebe902ac Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 17 May 2006 06:58:43 +0000 Subject: Add Microsoft's WAVEFORMWATEEXTENSIBLE channel mapping. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@890 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/channelmap.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/polyp/channelmap.h | 1 + 2 files changed, 60 insertions(+) diff --git a/src/polyp/channelmap.c b/src/polyp/channelmap.c index 8d16f7b3..1e6347d6 100644 --- a/src/polyp/channelmap.c +++ b/src/polyp/channelmap.c @@ -214,6 +214,65 @@ pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, p return m; } + case PA_CHANNEL_MAP_WAVEEX: + + switch (channels) { + case 1: + m->map[0] = PA_CHANNEL_POSITION_MONO; + return m; + + case 18: + m->map[15] = PA_CHANNEL_POSITION_TOP_REAR_LEFT; + m->map[16] = PA_CHANNEL_POSITION_TOP_REAR_CENTER; + m->map[17] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT; + /* Fall through */ + + case 15: + m->map[12] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT; + m->map[13] = PA_CHANNEL_POSITION_TOP_FRONT_CENTER; + m->map[14] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT; + /* Fall through */ + + case 12: + m->map[11] = PA_CHANNEL_POSITION_TOP_CENTER; + /* Fall through */ + + case 11: + m->map[9] = PA_CHANNEL_POSITION_SIDE_LEFT; + m->map[10] = PA_CHANNEL_POSITION_SIDE_RIGHT; + /* Fall through */ + + case 9: + m->map[8] = PA_CHANNEL_POSITION_REAR_CENTER; + /* Fall through */ + + case 8: + m->map[6] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER; + m->map[7] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER; + /* Fall through */ + + case 6: + m->map[4] = PA_CHANNEL_POSITION_REAR_LEFT; + m->map[5] = PA_CHANNEL_POSITION_REAR_RIGHT; + /* Fall through */ + + case 4: + m->map[3] = PA_CHANNEL_POSITION_LFE; + /* Fall through */ + + case 3: + m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; + /* Fall through */ + + case 2: + m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + return m; + + default: + return NULL; + } + default: return NULL; } diff --git a/src/polyp/channelmap.h b/src/polyp/channelmap.h index 8270a5b3..c9fae17e 100644 --- a/src/polyp/channelmap.h +++ b/src/polyp/channelmap.h @@ -125,6 +125,7 @@ typedef enum pa_channel_map_def { PA_CHANNEL_MAP_AIFF, /**< The mapping from RFC3551, which is based on AIFF-C */ PA_CHANNEL_MAP_ALSA, /**< The default mapping used by ALSA */ PA_CHANNEL_MAP_AUX, /**< Only aux channels */ + PA_CHANNEL_MAP_WAVEEX, /**< Microsoft's WAVEFORMATEXTENSIBLE mapping */ PA_CHANNEL_MAP_DEFAULT = PA_CHANNEL_MAP_AIFF /**< The default channel map */ } pa_channel_map_def_t; -- cgit From 71f681aa43156056965a906101e07b27c94eef45 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 17 May 2006 06:58:58 +0000 Subject: Set default channel map system for waveout module. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@891 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-waveout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index 34607421..2d9c42eb 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -469,7 +469,7 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_WAVEEX) < 0) { pa_log(__FILE__": failed to parse sample specification"); goto fail; } -- cgit From d4d1e5edf7af01b0d0e32da9fa323702f5174232 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 17 May 2006 11:07:16 +0000 Subject: Documentation for the threaded main loop API. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@892 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/context.h | 6 +- src/polyp/polypaudio.h | 13 ++- src/polyp/thread-mainloop.h | 201 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 215 insertions(+), 5 deletions(-) diff --git a/src/polyp/context.h b/src/polyp/context.h index ff93dd11..04e2af4d 100644 --- a/src/polyp/context.h +++ b/src/polyp/context.h @@ -51,13 +51,17 @@ * pa_mainloop_api structure. * * To actually be able to use these functions, an implementation needs to - * be coupled to the abstraction. There are two of these shipped with + * be coupled to the abstraction. There are three of these shipped with * polypaudio, but any other can be used with a minimal ammount of work, * provided it supports the three basic events listed above. * * The implementations shipped with polypaudio are: * * \li \subpage mainloop - A minimal but fast implementation based on poll(). + * \li \subpage threaded_mainloop - A special version of the previous + * implementation where all of Polypaudio's + * internal handling runs in a separate + * thread. * \li \subpage glib-mainloop - A wrapper around GLIB's main loop. Available * for both GLIB 1.2 and GLIB 2.x. * diff --git a/src/polyp/polypaudio.h b/src/polyp/polypaudio.h index af80f9ea..5dd7aa10 100644 --- a/src/polyp/polypaudio.h +++ b/src/polyp/polypaudio.h @@ -66,6 +66,11 @@ * based style or if you want to use the advanced features of the * polypaudio API. A guide can be found in \subpage async. * + * By using the built-in threaded main loop, it is possible to acheive a + * pseudo-synchronous API, which can be useful in synchronous applications + * where the simple API is insufficient. See the \ref async page for + * details. + * * \section thread_sec Threads * * The polypaudio client libraries are not designed to be used in a @@ -73,12 +78,12 @@ * safe. * * To use a the libraries in a threaded environment, you must assure that - * all objects are only used in the same thread they were created in. - * Normally, this means that all objects belonging to a single context - * must be accessed from the same thread. + * all objects are only used in one thread at a time. Normally, this means + * that all objects belonging to a single context must be accessed from the + * same thread. * * The included main loop implementation is also not thread safe. Take care - * to make sure event lists are not manipulated when any library code is + * to make sure event lists are not manipulated when any other code is * using the main loop. * * \section pkgconfig pkg-config diff --git a/src/polyp/thread-mainloop.h b/src/polyp/thread-mainloop.h index 94a48d02..81e8d674 100644 --- a/src/polyp/thread-mainloop.h +++ b/src/polyp/thread-mainloop.h @@ -27,6 +27,207 @@ PA_C_DECL_BEGIN +/** \page threaded_mainloop Threaded Main Loop + * + * \section overv_sec Overview + * + * The threaded main loop implementation is a special version of the primary + * main loop implementation (see \ref mainloop). For the basic design, see + * its documentation. + * + * The added feature in the threaded main loop is that it spawns a new thread + * that runs the real main loop. This allows a synchronous application to use + * the asynchronous API without risking to stall the Polypaudio library. + * + * \section creat_sec Creation + * + * A pa_threaded_mainloop object is created using pa_threaded_mainloop_new(). + * This will only allocate the required structures though, so to use it the + * thread must also be started. This is done through + * pa_threaded_mainloop_start(), after which you can start using the main loop. + * + * \section destr_sec Destruction + * + * When the Polypaudio connection has been terminated, the thread must be + * stopped and the resources freed. Stopping the thread is done using + * pa_threaded_mainloop_stop(), which must be called without the lock (see + * below) held. When that function returns, the thread is stopped and the + * pa_threaded_mainloop object can be freed using pa_threaded_mainloop_free(). + * + * \section lock_sec Locking + * + * Since the Polypaudio API doesn't allow concurrent accesses to objects, + * a locking scheme must be used to guarantee safe usage. The threaded main + * loop API provides such a scheme through the functions + * pa_threaded_mainloop_lock() and pa_threaded_mainloop_unlock(). + * + * The lock is recursive, so it's safe to use it multiple times from the same + * thread. Just make sure you call pa_threaded_mainloop_unlock() the same + * number of times you called pa_threaded_mainloop_lock(). + * + * The lock needs to be held whenever you call any Polypaudio function that + * uses an object associated with this main loop. Make sure you do not hold + * on to the lock more than necessary though, as the threaded main loop stops + * while the lock is held. + * + * Example: + * + * \code + * void my_check_stream_func(pa_threaded_mainloop *m, pa_stream *s) { + * pa_stream_state_t state; + * + * pa_threaded_mainloop_lock(m); + * + * state = pa_stream_get_state(s); + * + * pa_threaded_mainloop_unlock(m); + * + * if (state == PA_STREAM_READY) + * printf("Stream is ready!"); + * else + * printf("Stream is not ready!"); + * } + * \endcode + * + * \section cb_sec Callbacks + * + * Callbacks in Polypaudio are asynchronous, so they require extra care when + * using them together with a threaded main loop. + * + * The easiest way to turn the callback based operations into synchronous + * ones, is to simply wait for the callback to be called and continue from + * there. This is the approach chosen in Polypaudio's threaded API. + * + * \subsection basic_subsec Basic callbacks + * + * For the basic case, where all that is required is to wait for the callback + * to be invoked, the code should look something like this: + * + * Example: + * + * \code + * static void my_drain_callback(pa_stream*s, int success, void *userdata) { + * pa_threaded_mainloop *m; + * + * m = (pa_threaded_mainloop*)userdata; + * assert(m); + * + * pa_threaded_mainloop_signal(m, 0); + * } + * + * void my_drain_stream_func(pa_threaded_mainloop *m, pa_stream *s) { + * pa_operation *o; + * + * pa_threaded_mainloop_lock(m); + * + * o = pa_stream_drain(s, my_drain_callback, m); + * assert(o); + * + * while (pa_operation_get_state(o) != OPERATION_DONE) + * pa_threaded_mainloop_wait(m); + * + * pa_operation_unref(o); + * + * pa_threaded_mainloop_unlock(m); + * } + * \endcode + * + * The main function, my_drain_stream_func(), will wait for the callback to + * be called using pa_threaded_mainloop_wait(). + * + * If your application is multi-threaded, then this waiting must be done + * inside a while loop. The reason for this is that multiple threads might be + * using pa_threaded_mainloop_wait() at the same time. Each thread must + * therefore verify that it was its callback that was invoked. + * + * The callback, my_drain_callback(), indicates to the main function that it + * has been called using pa_threaded_mainloop_signal(). + * + * As you can see, both pa_threaded_mainloop_wait() may only be called with + * the lock held. The same thing is true for pa_threaded_mainloop_signal(), + * but as the lock is held before the callback is invoked, you do not have to + * deal with that. + * + * The functions will not dead lock because the wait function will release + * the lock before waiting and then regrab it once it has been signaled. + * For those of you familiar with threads, the behaviour is that of a + * condition variable. + * + * \subsection data_subsec Data callbacks + * + * For many callbacks, simply knowing that they have been called is + * insufficient. The callback also receives some data that is desired. To + * access this data safely, we must extend our example a bit: + * + * \code + * static int *drain_result; + * + * static void my_drain_callback(pa_stream*s, int success, void *userdata) { + * pa_threaded_mainloop *m; + * + * m = (pa_threaded_mainloop*)userdata; + * assert(m); + * + * drain_result = &success; + * + * pa_threaded_mainloop_signal(m, 1); + * } + * + * void my_drain_stream_func(pa_threaded_mainloop *m, pa_stream *s) { + * pa_operation *o; + * + * pa_threaded_mainloop_lock(m); + * + * o = pa_stream_drain(s, my_drain_callback, m); + * assert(o); + * + * while (pa_operation_get_state(o) != OPERATION_DONE) + * pa_threaded_mainloop_wait(m); + * + * pa_operation_unref(o); + * + * if (*drain_result) + * printf("Success!"); + * else + * printf("Bitter defeat..."); + * + * pa_threaded_mainloop_accept(m); + * + * pa_threaded_mainloop_unlock(m); + * } + * \endcode + * + * The example is a bit silly as it would probably have been easier to just + * copy the contents of success, but for larger data structures this can be + * wasteful. + * + * The difference here compared to the basic callback is the 1 sent to + * pa_threaded_mainloop_signal() and the call to + * pa_threaded_mainloop_accept(). What will happen is that + * pa_threaded_mainloop_signal() will signal the main function and then stop. + * The main function is then free to use the data in the callback until + * pa_threaded_mainloop_accept() is called, which will allow the callback + * to continue. + * + * Note that pa_threaded_mainloop_accept() must be called some time between + * exiting the while loop and unlocking the main loop! Failure to do so will + * result in a race condition. I.e. it is not ok to release the lock and + * regrab it before calling pa_threaded_mainloop_accept(). + * + * \subsection async_subsec Asynchronous callbacks + * + * Polypaudio also has callbacks that are completely asynchronous, meaning + * that they can be called at any time. The threading main loop API provides + * the locking mechanism to handle concurrent accesses, but nothing else. + * Applications will have to handle communication from the callback to the + * main program through some own system. + * + * The callbacks that are completely asynchronous are: + * + * \li State callbacks for contexts, streams, etc. + * \li Subscription notifications + */ + /** \file * * A thread based event loop implementation based on pa_mainloop. The -- cgit From 6ab421381ab9047d92f2679b67a8a4e0ea611d11 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 17 May 2006 11:10:59 +0000 Subject: Update documentation to contain the UTF-8 requirement. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@893 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/polypaudio.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/polyp/polypaudio.h b/src/polyp/polypaudio.h index 5dd7aa10..1830dea8 100644 --- a/src/polyp/polypaudio.h +++ b/src/polyp/polypaudio.h @@ -54,6 +54,11 @@ * \li The complete but somewhat complicated to use asynchronous API * \li The simplified, easy to use, but limited synchronous API * + * All strings in Polypaudio are in the UTF-8 encoding, regardless of current + * locale. Some functions will filter invalid sequences from the string, some + * will simply fail. To ensure reliable behaviour, make sure everything you + * pass to the API is already in UTF-8. + * \section simple_sec Simple API * * Use this if you develop your program in synchronous style and just -- cgit From e767fda182739827c6e8a4b843c826409b8fbc80 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 17 May 2006 11:23:07 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@894 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/doc/todo b/doc/todo index 8b5daefb..369f7a26 100644 --- a/doc/todo +++ b/doc/todo @@ -5,17 +5,14 @@ Post 0.8: - dbus/hal - polish for starting polypaudio as root/system-wide instance - chroot() -- add threading API - module-tunnel: improve latency calculation - port from howl to avahi - multiline configuration statements - use scatter/gather io for sockets -- add a synchronous API (base it on xmms-polyp) - rtp module ported to Win32 (sendmsg/recvmsg emulation) - CODECs to reduce bandwidth usage (plug-in based) - Remove symdef files and use macros (like most other projects) - use software volume when hardware doesn't support all channels (alsa done) -- double check channel maps for backends, including that mixer and pcm match - paplay needs to set a channel map. our default is only correct for AIFF. (we need help from libsndfile for this) - silence generation should be moved into the core to avoid races and code @@ -23,10 +20,12 @@ Post 0.8: - examine if it is possible to mimic esd's handling of half duplex cards (switch to capture when a recording client connects and drop playback during that time) -- fix channel maps in all external backends. Take care when doing volume - changes if you're modifying a sink/source since those might have a different - map. - in avahi-simple: sleep until latency data is available again if NODATA has happened +- Fix a way for the threading API to handle state and subscription callbacks + in a nice way. +- iconv stuff sent from utils to server (UTF-8) +- iconv stuff leaving the server (e.g. syslog). Sample loading probably needs + help as well. Long term: - pass meta info for hearing impaired -- cgit From ed3606c88480de9b348dee451e7ebfd1f6bd15d7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 13:06:04 +0000 Subject: add new channel mapping standard PA_CHANNEL_MAP_OSS git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@895 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/channelmap.c | 35 +++++++++++++++++++++++++++++++++++ src/polyp/channelmap.h | 7 ++++--- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/polyp/channelmap.c b/src/polyp/channelmap.c index 1e6347d6..7266a0a0 100644 --- a/src/polyp/channelmap.c +++ b/src/polyp/channelmap.c @@ -273,6 +273,41 @@ pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, p return NULL; } + case PA_CHANNEL_MAP_OSS: + + switch (channels) { + case 1: + m->map[0] = PA_CHANNEL_POSITION_MONO; + return m; + + case 8: + m->map[6] = PA_CHANNEL_POSITION_REAR_LEFT; + m->map[7] = PA_CHANNEL_POSITION_REAR_RIGHT; + /* Fall through */ + + case 6: + m->map[4] = PA_CHANNEL_POSITION_SIDE_LEFT; + m->map[5] = PA_CHANNEL_POSITION_SIDE_RIGHT; + /* Fall through */ + + case 4: + m->map[3] = PA_CHANNEL_POSITION_LFE; + /* Fall through */ + + case 3: + m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; + /* Fall through */ + + case 2: + m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + return m; + + default: + return NULL; + } + + default: return NULL; } diff --git a/src/polyp/channelmap.h b/src/polyp/channelmap.h index c9fae17e..feccd284 100644 --- a/src/polyp/channelmap.h +++ b/src/polyp/channelmap.h @@ -122,10 +122,11 @@ typedef enum pa_channel_position { /** A list of channel mapping definitions for pa_channel_map_init_auto() */ typedef enum pa_channel_map_def { - PA_CHANNEL_MAP_AIFF, /**< The mapping from RFC3551, which is based on AIFF-C */ - PA_CHANNEL_MAP_ALSA, /**< The default mapping used by ALSA */ - PA_CHANNEL_MAP_AUX, /**< Only aux channels */ + PA_CHANNEL_MAP_AIFF, /**< The mapping from RFC3551, which is based on AIFF-C */ + PA_CHANNEL_MAP_ALSA, /**< The default mapping used by ALSA */ + PA_CHANNEL_MAP_AUX, /**< Only aux channels */ PA_CHANNEL_MAP_WAVEEX, /**< Microsoft's WAVEFORMATEXTENSIBLE mapping */ + PA_CHANNEL_MAP_OSS, /**< The default channel mapping used by OSS as defined in the OSS 4.0 API specs */ PA_CHANNEL_MAP_DEFAULT = PA_CHANNEL_MAP_AIFF /**< The default channel map */ } pa_channel_map_def_t; -- cgit From 270a409bf543f0ec7152f66e76d22445434aca4d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 13:09:46 +0000 Subject: use PA_CHANNEL_MAP_OSS in module-oss, module-oss-mmap git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@896 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss-mmap.c | 2 +- src/modules/module-oss.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index b8012214..ddf33532 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -383,7 +383,7 @@ int pa__init(pa_core *c, pa_module*m) { } u->sample_spec = c->default_sample_spec; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &u->sample_spec, &map, PA_CHANNEL_MAP_ALSA) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &u->sample_spec, &map, PA_CHANNEL_MAP_OSS) < 0) { pa_log(__FILE__": failed to parse sample specification or channel map"); goto fail; } diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index eab9a60a..f6d19544 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -347,7 +347,7 @@ int pa__init(pa_core *c, pa_module*m) { mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_OSS) < 0) { pa_log(__FILE__": failed to parse sample specification or channel map"); goto fail; } -- cgit From 106fb20d564b28802143f4916662fe0d10c1a1f0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 13:15:12 +0000 Subject: increase PA_CHANNELS_MAX to 32 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@897 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/channelmap.h | 16 ++++++++++++++++ src/polyp/sample.h | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/polyp/channelmap.h b/src/polyp/channelmap.h index feccd284..645a8a38 100644 --- a/src/polyp/channelmap.h +++ b/src/polyp/channelmap.h @@ -106,6 +106,22 @@ typedef enum pa_channel_position { PA_CHANNEL_POSITION_AUX13, PA_CHANNEL_POSITION_AUX14, PA_CHANNEL_POSITION_AUX15, + PA_CHANNEL_POSITION_AUX16, + PA_CHANNEL_POSITION_AUX17, + PA_CHANNEL_POSITION_AUX18, + PA_CHANNEL_POSITION_AUX19, + PA_CHANNEL_POSITION_AUX20, + PA_CHANNEL_POSITION_AUX21, + PA_CHANNEL_POSITION_AUX22, + PA_CHANNEL_POSITION_AUX23, + PA_CHANNEL_POSITION_AUX24, + PA_CHANNEL_POSITION_AUX25, + PA_CHANNEL_POSITION_AUX26, + PA_CHANNEL_POSITION_AUX27, + PA_CHANNEL_POSITION_AUX28, + PA_CHANNEL_POSITION_AUX29, + PA_CHANNEL_POSITION_AUX30, + PA_CHANNEL_POSITION_AUX31, PA_CHANNEL_POSITION_TOP_CENTER, diff --git a/src/polyp/sample.h b/src/polyp/sample.h index 4de84301..09b12fd7 100644 --- a/src/polyp/sample.h +++ b/src/polyp/sample.h @@ -100,7 +100,7 @@ PA_C_DECL_BEGIN /** Maximum number of allowed channels */ -#define PA_CHANNELS_MAX 16 +#define PA_CHANNELS_MAX 32 /** Sample format */ typedef enum pa_sample_format { -- cgit From 31a9d4fb301bdfed50bee2cf162cc98093bb19f6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 14:06:12 +0000 Subject: when playing an ULAW or ALAW audio file, do not convert to S16NE unconditionally, instead use sf_read_raw() to read raw audio data git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@898 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/paplay.c | 57 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/src/utils/paplay.c b/src/utils/paplay.c index ad9d4553..d4af95c1 100644 --- a/src/utils/paplay.c +++ b/src/utils/paplay.c @@ -57,7 +57,7 @@ static pa_sample_spec sample_spec = { 0, 0, 0 }; static pa_channel_map channel_map; static int channel_map_set = 0; -static sf_count_t (*readf_function)(SNDFILE *_sndfile, void *ptr, sf_count_t frames); +static sf_count_t (*readf_function)(SNDFILE *_sndfile, void *ptr, sf_count_t frames) = NULL; /* A shortcut for terminating the application */ static void quit(int ret) { @@ -98,26 +98,30 @@ static void stream_drain_complete(pa_stream*s, int success, void *userdata) { /* This is called whenever new data may be written to the stream */ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { - size_t k; - sf_count_t f, n; + sf_count_t bytes; void *data; assert(s && length); if (!sndfile) return; - - k = pa_frame_size(&sample_spec); data = malloc(length); - n = length/k; - - f = readf_function(sndfile, data, n); + if (readf_function) { + size_t k = pa_frame_size(&sample_spec); - if (f > 0) - pa_stream_write(s, data, f*k, free, 0, PA_SEEK_RELATIVE); + if ((bytes = readf_function(sndfile, data, length/k)) > 0) + bytes *= k; + + } else + bytes = sf_read_raw(sndfile, data, length); - if (f < n) { + if (bytes > 0) + pa_stream_write(s, data, bytes, free, 0, PA_SEEK_RELATIVE); + else + free(data); + + if (bytes < length) { sf_close(sndfile); sndfile = NULL; pa_operation_unref(pa_stream_drain(s, stream_drain_complete, NULL)); @@ -296,16 +300,8 @@ int main(int argc, char *argv[]) { } } - filename = optind < argc ? argv[optind] : "STDIN"; - - if (!client_name) - client_name = strdup(bn); - - if (!stream_name) - stream_name = strdup(filename); - memset(&sfinfo, 0, sizeof(sfinfo)); if (optind < argc) @@ -317,18 +313,27 @@ int main(int argc, char *argv[]) { fprintf(stderr, "Failed to open file '%s'\n", filename); goto quit; } - + sample_spec.rate = sfinfo.samplerate; sample_spec.channels = sfinfo.channels; switch (sfinfo.format & 0xFF) { case SF_FORMAT_PCM_16: case SF_FORMAT_PCM_U8: - case SF_FORMAT_ULAW: - case SF_FORMAT_ALAW: sample_spec.format = PA_SAMPLE_S16NE; readf_function = (sf_count_t (*)(SNDFILE *_sndfile, void *ptr, sf_count_t frames)) sf_readf_short; break; + + case SF_FORMAT_ULAW: + sample_spec.format = PA_SAMPLE_ULAW; + readf_function = NULL; + break; + + case SF_FORMAT_ALAW: + sample_spec.format = PA_SAMPLE_ALAW; + readf_function = NULL; + break; + case SF_FORMAT_FLOAT: default: sample_spec.format = PA_SAMPLE_FLOAT32NE; @@ -343,6 +348,14 @@ int main(int argc, char *argv[]) { goto quit; } + if (!client_name) + client_name = strdup(bn); + + if (!stream_name) { + const char *n = sf_get_string(sndfile, SF_STR_TITLE); + stream_name = strdup(n ? n : filename); + } + if (verbose) { char t[PA_SAMPLE_SPEC_SNPRINT_MAX]; pa_sample_spec_snprint(t, sizeof(t), &sample_spec); -- cgit From e6695538d721941132db2183e40f142b9e52076e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 14:54:41 +0000 Subject: * use S16NE for SF_FORMAT_PCM_S8 formats, too git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@899 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/paplay.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/utils/paplay.c b/src/utils/paplay.c index d4af95c1..5f203615 100644 --- a/src/utils/paplay.c +++ b/src/utils/paplay.c @@ -317,24 +317,26 @@ int main(int argc, char *argv[]) { sample_spec.rate = sfinfo.samplerate; sample_spec.channels = sfinfo.channels; + readf_function = NULL; + switch (sfinfo.format & 0xFF) { case SF_FORMAT_PCM_16: case SF_FORMAT_PCM_U8: + case SF_FORMAT_PCM_S8: sample_spec.format = PA_SAMPLE_S16NE; readf_function = (sf_count_t (*)(SNDFILE *_sndfile, void *ptr, sf_count_t frames)) sf_readf_short; break; case SF_FORMAT_ULAW: sample_spec.format = PA_SAMPLE_ULAW; - readf_function = NULL; break; case SF_FORMAT_ALAW: sample_spec.format = PA_SAMPLE_ALAW; - readf_function = NULL; break; case SF_FORMAT_FLOAT: + case SF_FORMAT_DOUBLE: default: sample_spec.format = PA_SAMPLE_FLOAT32NE; readf_function = (sf_count_t (*)(SNDFILE *_sndfile, void *ptr, sf_count_t frames)) sf_readf_float; -- cgit From b47b257a91441dbfb2c716d71f8008ad4f2db1d5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 14:55:17 +0000 Subject: support loading ULAW/ALAW files into ULAW/ALAW memchunks git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@900 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/sound-file.c | 51 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/src/polypcore/sound-file.c b/src/polypcore/sound-file.c index f0378009..bd0cf596 100644 --- a/src/polypcore/sound-file.c +++ b/src/polypcore/sound-file.c @@ -39,7 +39,7 @@ int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_channel_map *ma SF_INFO sfinfo; int ret = -1; size_t l; - sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames); + sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames) = NULL; assert(fname && ss && chunk); chunk->memblock = NULL; @@ -53,17 +53,27 @@ int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_channel_map *ma } switch (sfinfo.format & SF_FORMAT_SUBMASK) { + case SF_FORMAT_PCM_16: + case SF_FORMAT_PCM_U8: + case SF_FORMAT_PCM_S8: + ss->format = PA_SAMPLE_S16NE; + readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_short; + break; + + case SF_FORMAT_ULAW: + ss->format = PA_SAMPLE_ULAW; + break; + + case SF_FORMAT_ALAW: + ss->format = PA_SAMPLE_ALAW; + break; + case SF_FORMAT_FLOAT: case SF_FORMAT_DOUBLE: - /* Only float and double need a special case. */ + default: ss->format = PA_SAMPLE_FLOAT32NE; readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_float; break; - default: - /* Everything else is cleanly converted to signed 16 bit. */ - ss->format = PA_SAMPLE_S16NE; - readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_short; - break; } ss->rate = sfinfo.samplerate; @@ -87,11 +97,12 @@ int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_channel_map *ma chunk->index = 0; chunk->length = l; - if (readf_function(sf, chunk->memblock->data, sfinfo.frames) != sfinfo.frames) { + if ((readf_function && readf_function(sf, chunk->memblock->data, sfinfo.frames) != sfinfo.frames) || + (!readf_function && sf_read_raw(sf, chunk->memblock->data, l) != l)) { pa_log(__FILE__": Premature file end"); goto finish; } - + ret = 0; finish: @@ -119,14 +130,24 @@ int pa_sound_file_too_big_to_cache(const char *fname) { sf_close(sf); switch (sfinfo.format & SF_FORMAT_SUBMASK) { - case SF_FORMAT_FLOAT: - case SF_FORMAT_DOUBLE: - /* Only float and double need a special case. */ - ss.format = PA_SAMPLE_FLOAT32NE; + case SF_FORMAT_PCM_16: + case SF_FORMAT_PCM_U8: + case SF_FORMAT_PCM_S8: + ss.format = PA_SAMPLE_S16NE; + break; + + case SF_FORMAT_ULAW: + ss.format = PA_SAMPLE_ULAW; break; + + case SF_FORMAT_ALAW: + ss.format = PA_SAMPLE_ALAW; + break; + + case SF_FORMAT_DOUBLE: + case SF_FORMAT_FLOAT: default: - /* Everything else is cleanly converted to signed 16 bit. */ - ss.format = PA_SAMPLE_S16NE; + ss.format = PA_SAMPLE_FLOAT32NE; break; } -- cgit From fa53ed7aafc681c69aa9a6a28072fe398a845662 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 14:55:54 +0000 Subject: * support native ULAW/ALAW file streams * fix shutdown of file streams git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@901 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/sound-file-stream.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/polypcore/sound-file-stream.c b/src/polypcore/sound-file-stream.c index ca762d6a..fdacea54 100644 --- a/src/polypcore/sound-file-stream.c +++ b/src/polypcore/sound-file-stream.c @@ -65,10 +65,6 @@ static void sink_input_kill(pa_sink_input *i) { free_userdata(i->userdata); } -static void si_kill(PA_GCC_UNUSED pa_mainloop_api *m, void *i) { - sink_input_kill(i); -} - static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { struct userdata *u; assert(i && chunk && i->userdata); @@ -76,18 +72,25 @@ static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { if (!u->memchunk.memblock) { uint32_t fs = pa_frame_size(&i->sample_spec); - sf_count_t samples = BUF_SIZE/fs; + sf_count_t n; u->memchunk.memblock = pa_memblock_new(BUF_SIZE, i->sink->core->memblock_stat); u->memchunk.index = 0; - samples = u->readf_function(u->sndfile, u->memchunk.memblock->data, samples); - u->memchunk.length = samples*fs; + + if (u->readf_function) { + if ((n = u->readf_function(u->sndfile, u->memchunk.memblock->data, BUF_SIZE/fs)) <= 0) + n = 0; + + u->memchunk.length = n * fs; + } else { + if ((n = sf_read_raw(u->sndfile, u->memchunk.memblock->data, BUF_SIZE)) <= 0) + n = 0; + + u->memchunk.length = n; + } if (!u->memchunk.length) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - u->memchunk.index = u->memchunk.length = 0; - pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i); + free_userdata(u); return -1; } } @@ -135,14 +138,24 @@ int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume) { goto fail; } + u->readf_function = NULL; + switch (sfinfo.format & 0xFF) { case SF_FORMAT_PCM_16: case SF_FORMAT_PCM_U8: - case SF_FORMAT_ULAW: - case SF_FORMAT_ALAW: + case SF_FORMAT_PCM_S8: ss.format = PA_SAMPLE_S16NE; u->readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_short; break; + + case SF_FORMAT_ULAW: + ss.format = PA_SAMPLE_ULAW; + break; + + case SF_FORMAT_ALAW: + ss.format = PA_SAMPLE_ALAW; + break; + case SF_FORMAT_FLOAT: default: ss.format = PA_SAMPLE_FLOAT32NE; -- cgit From db242e11b2b7a07231238cbb70277cda48a64e2c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 14:58:50 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@902 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index 369f7a26..657f4bf3 100644 --- a/doc/todo +++ b/doc/todo @@ -20,7 +20,6 @@ Post 0.8: - examine if it is possible to mimic esd's handling of half duplex cards (switch to capture when a recording client connects and drop playback during that time) -- in avahi-simple: sleep until latency data is available again if NODATA has happened - Fix a way for the threading API to handle state and subscription callbacks in a nice way. - iconv stuff sent from utils to server (UTF-8) -- cgit From 6d281a57813794d9575b3f7088b8526bcae2e3bb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 15:19:15 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@903 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/todo b/doc/todo index 657f4bf3..79b1894a 100644 --- a/doc/todo +++ b/doc/todo @@ -34,4 +34,3 @@ Backends for: - portaudio (semi-done) - sdl - OSS (esddsp style) -- gstreamer (needs to be updated) -- cgit From 1267285257aaa60630b59f0f5c62c4c7f4a8d8df Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 15:19:30 +0000 Subject: add documentation for module-volume-restore git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@904 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/modules.html.in | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/doc/modules.html.in b/doc/modules.html.in index 6a6b7887..af6b6de6 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -464,16 +464,30 @@ which is replaced by source_name (with a default of jack_in) f

    Adjust the volume of a playback stream automatically based on its name.

    - +
    table=The regular expression matching table file to use
    table=The regular expression matching table file to use (defaults to ~/.polypaudio/match.table)

    The table file should contain a regexp and volume on each line, seperated by spaces. An example:

    -^sample: 25
    +^sample: 32000
     
    -

    The volumes of all streams with titles starting with sample: are automatically set to 25. (FYI: All sample cache streams start with sample:)

    +

    The volumes of all streams with titles starting with sample: are automatically set to 32000. (FYI: All sample cache streams start with sample:)

    + +

    module-volume-restore

    + +

    Adjust the volume of a playback stream automatically based on its name.

    + + + +
    table=The table file to use (defaults to ~/.polypaudio/volume.table)
    + +

    In contrast to module-match this module needs no explicit +configuration. Instead the volumes are saved and restored in a fully +automatical fashion depending on the client name to identify +streams. The volume for a stream is automatically saved every time it is +changed and than restored when a new stream is created.

    module-detect

    -- cgit From e0bf4a32f3ca7b9cf472a37c31be4a6202d39fa8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 15:21:08 +0000 Subject: add proper locking when accessing the file volume.table git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@905 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-volume-restore.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index b379e53c..f9e7d013 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include "module-volume-restore-symdef.h" @@ -116,7 +117,7 @@ static int load_rules(struct userdata *u) { f = u->table_file ? fopen(u->table_file, "r") : pa_open_config_file(NULL, DEFAULT_VOLUME_TABLE_FILE, NULL, &u->table_file, "r"); - + if (!f) { if (errno == ENOENT) { pa_log_info(__FILE__": starting with empty ruleset."); @@ -127,6 +128,8 @@ static int load_rules(struct userdata *u) { goto finish; } + pa_lock_fd(fileno(f), 1); + while (!feof(f)) { struct rule *rule; pa_cvolume v; @@ -175,8 +178,10 @@ static int load_rules(struct userdata *u) { ret = 0; finish: - if (f) + if (f) { + pa_lock_fd(fileno(f), 0); fclose(f); + } return ret; } @@ -196,6 +201,8 @@ static int save_rules(struct userdata *u) { goto finish; } + pa_lock_fd(fileno(f), 1); + while ((rule = pa_hashmap_iterate(u->hashmap, &state, NULL))) { unsigned i; @@ -210,8 +217,10 @@ static int save_rules(struct userdata *u) { ret = 0; finish: - if (f) + if (f) { + pa_lock_fd(fileno(f), 0); fclose(f); + } return ret; } -- cgit From 1cfb01ab0eff7b152125e3facdf6c65f98e2707b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 15:21:34 +0000 Subject: add proper locking when accessing the file match.table git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@906 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-match.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/modules/module-match.c b/src/modules/module-match.c index f6316b93..9e3edb70 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "module-match-symdef.h" @@ -88,6 +89,8 @@ static int load_rules(struct userdata *u, const char *filename) { goto finish; } + pa_lock_fd(fileno(f), 1); + while (!feof(f)) { char *d, *v; pa_volume_t volume; @@ -146,8 +149,10 @@ static int load_rules(struct userdata *u, const char *filename) { ret = 0; finish: - if (f) + if (f) { + pa_lock_fd(fileno(f), 0); fclose(f); + } if (fn) pa_xfree(fn); -- cgit From cdd3588f3a0fc9efeff7ce85215304bf33e2504e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 15:38:58 +0000 Subject: more sensible default.pa file git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@907 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/default.pa.in | 49 ++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in index 3aaeeaf0..cba0172f 100755 --- a/src/daemon/default.pa.in +++ b/src/daemon/default.pa.in @@ -18,17 +18,18 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -# Load audio drivers statically - +### Load audio drivers statically #load-module module-alsa-sink -# load-module module-alsa-source device=plughw:1,0 -load-module module-oss device="/dev/dsp" sink_name=output source_name=input +#load-module module-alsa-source device=plughw:1,0 +#load-module module-oss device="/dev/dsp" sink_name=output source_name=input #load-module module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -load-module module-null-sink +#load-module module-null-sink #load-module module-pipe-sink -# Load audio drivers automatically on access +### Automatically load driver modules depending on the hardware available +load-module module-detect +### Load audio drivers automatically on access #add-autoload-sink output module-oss device="/dev/dsp" sink_name=output source_name=input #add-autoload-source input module-oss device="/dev/dsp" sink_name=output source_name=input #add-autoload-sink output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input @@ -36,31 +37,35 @@ load-module module-null-sink #add-autoload-sink output module-alsa-sink sink_name=output #add-autoload-source input module-alsa-source source_name=input -# Load several protocols +### Load several protocols load-module module-esound-protocol-unix #load-module module-esound-protocol-tcp load-module module-native-protocol-unix -#load-module module-simple-protocol-tcp -#load-module module-cli-protocol-unix +#load-module module-native-protocol-tcp + +### Load the RTP reciever module +#load-module module-rtp-recv -# Load the CLI module -load-module module-cli +### Load the RTP sender module +#load-module module-null-sink sink_name=rtp +#load-module module-rtp-send source=rtp_monitor -# Make some devices default -set-default-sink output -set-default-source input +### Automatically restore the volume of playback streams +load-module module-volume-restore + +### Make some devices default +#set-default-sink output +#set-default-source input .nofail -# Load something to the sample cache -load-sample x11-bell /usr/share/sounds/KDE_Notify.wav -load-sample-dir-lazy /usr/share/sounds/*.wav +### Load something to the sample cache +load-sample x11-bell /usr/share/sounds/gtk-events/activate.wav +#load-sample-dir-lazy /usr/share/sounds/*.wav -# Load X11 bell module -load-module module-x11-bell sample=x11-bell sink=output +### Load X11 bell module +load-module module-x11-bell sample=x11-bell -# Publish connection data in the X11 root window +### Publish connection data in the X11 root window load-module module-x11-publish -#load-module module-pipe-source -#load-module module-pipe-sink -- cgit From d9cc2cfcb97c1b0449bcbfb6ab0301a58d77bd55 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 17 May 2006 16:34:18 +0000 Subject: Move xmalloc to the public side (libpolyp). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@908 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 14 ++-- src/daemon/cmdline.c | 3 +- src/daemon/daemon-conf.c | 3 +- src/daemon/main.c | 2 +- src/modules/alsa-util.c | 3 +- src/modules/howl-wrap.c | 3 +- src/modules/module-alsa-sink.c | 3 +- src/modules/module-alsa-source.c | 3 +- src/modules/module-combine.c | 3 +- src/modules/module-detect.c | 3 +- src/modules/module-esound-sink.c | 3 +- src/modules/module-jack-sink.c | 3 +- src/modules/module-jack-source.c | 3 +- src/modules/module-lirc.c | 3 +- src/modules/module-match.c | 3 +- src/modules/module-mmkbd-evdev.c | 3 +- src/modules/module-null-sink.c | 3 +- src/modules/module-oss-mmap.c | 3 +- src/modules/module-oss.c | 3 +- src/modules/module-pipe-sink.c | 3 +- src/modules/module-pipe-source.c | 3 +- src/modules/module-protocol-stub.c | 3 +- src/modules/module-sine.c | 3 +- src/modules/module-solaris.c | 2 +- src/modules/module-tunnel.c | 2 +- src/modules/module-volume-restore.c | 3 +- src/modules/module-waveout.c | 3 +- src/modules/module-x11-bell.c | 3 +- src/modules/module-x11-publish.c | 3 +- src/modules/module-zeroconf-publish.c | 3 +- src/modules/rtp/module-rtp-recv.c | 3 +- src/modules/rtp/module-rtp-send.c | 3 +- src/modules/rtp/sap.c | 3 +- src/modules/rtp/sdp.c | 3 +- src/polyp/browser.c | 3 +- src/polyp/channelmap.c | 4 +- src/polyp/client-conf-x11.c | 3 +- src/polyp/client-conf.c | 3 +- src/polyp/context.c | 2 +- src/polyp/glib-mainloop.c | 3 +- src/polyp/glib12-mainloop.c | 3 +- src/polyp/mainloop-api.c | 3 +- src/polyp/mainloop-signal.c | 3 +- src/polyp/mainloop.c | 3 +- src/polyp/operation.c | 2 +- src/polyp/simple.c | 2 +- src/polyp/stream.c | 3 +- src/polyp/thread-mainloop.c | 3 +- src/polyp/xmalloc.c | 123 ++++++++++++++++++++++++++++++++++ src/polyp/xmalloc.h | 58 ++++++++++++++++ src/polypcore/authkey-prop.c | 3 +- src/polypcore/autoload.c | 3 +- src/polypcore/cli-command.c | 3 +- src/polypcore/cli-text.c | 3 +- src/polypcore/cli.c | 3 +- src/polypcore/client.c | 3 +- src/polypcore/conf-parser.c | 3 +- src/polypcore/core-scache.c | 3 +- src/polypcore/core-subscribe.c | 3 +- src/polypcore/core.c | 3 +- src/polypcore/dynarray.c | 2 +- src/polypcore/hashmap.c | 3 +- src/polypcore/idxset.c | 2 +- src/polypcore/iochannel.c | 3 +- src/polypcore/ioline.c | 3 +- src/polypcore/log.c | 3 +- src/polypcore/mcalign.c | 2 +- src/polypcore/memblock.c | 2 +- src/polypcore/memblockq.c | 3 +- src/polypcore/memchunk.c | 2 +- src/polypcore/modargs.c | 3 +- src/polypcore/modinfo.c | 3 +- src/polypcore/module.c | 3 +- src/polypcore/namereg.c | 3 +- src/polypcore/packet.c | 2 +- src/polypcore/parseaddr.c | 3 +- src/polypcore/pdispatch.c | 3 +- src/polypcore/pid.c | 3 +- src/polypcore/play-memchunk.c | 3 +- src/polypcore/props.c | 3 +- src/polypcore/protocol-cli.c | 3 +- src/polypcore/protocol-esound.c | 3 +- src/polypcore/protocol-http.c | 3 +- src/polypcore/protocol-native.c | 2 +- src/polypcore/protocol-simple.c | 3 +- src/polypcore/pstream.c | 3 +- src/polypcore/queue.c | 2 +- src/polypcore/resampler.c | 3 +- src/polypcore/sink-input.c | 3 +- src/polypcore/sink.c | 2 +- src/polypcore/socket-client.c | 3 +- src/polypcore/socket-server.c | 3 +- src/polypcore/socket-util.c | 3 +- src/polypcore/sound-file-stream.c | 3 +- src/polypcore/source-output.c | 3 +- src/polypcore/source.c | 3 +- src/polypcore/strbuf.c | 2 +- src/polypcore/strlist.c | 3 +- src/polypcore/tagstruct.c | 2 +- src/polypcore/tokenizer.c | 3 +- src/polypcore/utf8.c | 3 +- src/polypcore/util.c | 3 +- src/polypcore/x11wrap.c | 3 +- src/polypcore/xmalloc.c | 123 ---------------------------------- src/polypcore/xmalloc.h | 58 ---------------- src/tests/strlist-test.c | 2 +- src/tests/utf8-test.c | 2 +- 107 files changed, 374 insertions(+), 290 deletions(-) create mode 100644 src/polyp/xmalloc.c create mode 100644 src/polyp/xmalloc.h delete mode 100644 src/polypcore/xmalloc.c delete mode 100644 src/polypcore/xmalloc.h diff --git a/src/Makefile.am b/src/Makefile.am index bd48a0fb..afbdedee 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -273,10 +273,10 @@ mainloop_test_glib12_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) memblockq_test_SOURCES = \ tests/memblockq-test.c \ + polyp/xmalloc.c \ polypcore/memblockq.c \ polypcore/log.c \ polypcore/memblock.c \ - polypcore/xmalloc.c \ polypcore/util.c \ polypcore/mcalign.c \ polypcore/memchunk.c @@ -313,7 +313,8 @@ polypinclude_HEADERS = \ polyp/subscribe.h \ polyp/version.h \ polyp/sample.h \ - polyp/volume.h + polyp/volume.h \ + polyp/xmalloc.h if HAVE_HOWL polypinclude_HEADERS += \ @@ -360,6 +361,7 @@ libpolyp_la_SOURCES = \ polyp/mainloop.c polyp/mainloop.h \ polyp/mainloop-signal.c polyp/mainloop-signal.h \ polyp/thread-mainloop.c polyp/thread-mainloop.h \ + polyp/xmalloc.c polyp/xmalloc.h \ polypcore/pipe.c polypcore/pipe.h \ polypcore/poll.c polypcore/poll.h @@ -392,7 +394,6 @@ libpolyp_la_SOURCES += \ polypcore/tagstruct.c polypcore/tagstruct.h \ polypcore/util.c polypcore/util.h \ polypcore/winsock.h \ - polypcore/xmalloc.c polypcore/xmalloc.h \ polypcore/llist.h if OS_IS_WIN32 @@ -485,8 +486,7 @@ polypcoreinclude_HEADERS = \ polypcore/strbuf.h \ polypcore/tokenizer.h \ polypcore/util.h \ - polypcore/utf8.h \ - polypcore/xmalloc.h + polypcore/utf8.h lib_LTLIBRARIES += libpolypcore.la @@ -497,7 +497,8 @@ libpolypcore_la_SOURCES = \ polyp/mainloop-api.c polyp/mainloop-api.h \ polyp/mainloop-signal.c polyp/mainloop-signal.h \ polyp/sample.c polyp/sample.h \ - polyp/volume.c polyp/volume.h + polyp/volume.c polyp/volume.h \ + polyp/xmalloc.c polyp/xmalloc.h # Pure core stuff (some are shared in libpolyp though). libpolypcore_la_SOURCES += \ @@ -546,7 +547,6 @@ libpolypcore_la_SOURCES += \ polypcore/tokenizer.c polypcore/tokenizer.h \ polypcore/util.c polypcore/util.h \ polypcore/winsock.h \ - polypcore/xmalloc.c polypcore/xmalloc.h \ polypcore/utf8.c polypcore/utf8.h if OS_IS_WIN32 diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c index a6b95a81..1ed16a69 100644 --- a/src/daemon/cmdline.c +++ b/src/daemon/cmdline.c @@ -30,9 +30,10 @@ #include #include +#include + #include #include -#include #include "cmdline.h" diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index f41bb4b1..f82d3d24 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -29,8 +29,9 @@ #include #include +#include + #include -#include #include #include #include diff --git a/src/daemon/main.c b/src/daemon/main.c index e14837a9..a7144eba 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -51,6 +51,7 @@ #include #include +#include #include #include @@ -59,7 +60,6 @@ #include #include #include -#include #include #include #include diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 503b8efb..122f4419 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -27,7 +27,8 @@ #include #include -#include +#include + #include #include "alsa-util.h" diff --git a/src/modules/howl-wrap.c b/src/modules/howl-wrap.c index f4605fb2..467ab9e2 100644 --- a/src/modules/howl-wrap.c +++ b/src/modules/howl-wrap.c @@ -21,8 +21,9 @@ #include +#include + #include -#include #include #include "howl-wrap.h" diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 47065659..94de771c 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -34,6 +34,8 @@ #include +#include + #include #include #include @@ -41,7 +43,6 @@ #include #include #include -#include #include #include "alsa-util.h" diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index d46f8e42..b9d1ff87 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -34,6 +34,8 @@ #include +#include + #include #include #include @@ -41,7 +43,6 @@ #include #include #include -#include #include #include "alsa-util.h" diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 369778a6..b31fe56e 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -26,6 +26,8 @@ #include #include +#include + #include #include #include @@ -33,7 +35,6 @@ #include #include #include -#include #include #include diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index 9cc13e81..ea14e68f 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -33,9 +33,10 @@ #include #include +#include + #include #include -#include #include #include diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index 1cc75502..1d61e01b 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -33,12 +33,13 @@ #include #include +#include + #include #include #include #include #include -#include #include #include #include diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index 324a2cb3..1aa73495 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -36,12 +36,13 @@ #include +#include + #include #include #include #include #include -#include #include #include diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index 94cabbea..29c46d85 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -36,12 +36,13 @@ #include +#include + #include #include #include #include #include -#include #include #include diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c index 3bb0dc74..918177a3 100644 --- a/src/modules/module-lirc.c +++ b/src/modules/module-lirc.c @@ -30,11 +30,12 @@ #include #include +#include + #include #include #include #include -#include #include #include "module-lirc-symdef.h" diff --git a/src/modules/module-match.c b/src/modules/module-match.c index 9e3edb70..1692b5d8 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -32,12 +32,13 @@ #include #include +#include + #include #include #include #include #include -#include #include #include diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c index 8ea56811..654fbaa4 100644 --- a/src/modules/module-mmkbd-evdev.c +++ b/src/modules/module-mmkbd-evdev.c @@ -33,11 +33,12 @@ #include +#include + #include #include #include #include -#include #include #include diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index 5cdfeab8..2cc49063 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -33,12 +33,13 @@ #include #include +#include + #include #include #include #include #include -#include #include #include "module-null-sink-symdef.h" diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index ddf33532..82e7d66d 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -36,6 +36,8 @@ #include #include +#include + #include #include #include @@ -43,7 +45,6 @@ #include #include #include -#include #include #include "oss-util.h" diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index f6d19544..46d100f1 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -35,6 +35,8 @@ #include #include +#include + #include #include #include @@ -42,7 +44,6 @@ #include #include #include -#include #include #include "oss-util.h" diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index 0fb73cd8..b59808fc 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -33,12 +33,13 @@ #include #include +#include + #include #include #include #include #include -#include #include #include "module-pipe-sink-symdef.h" diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index d999754a..4f3f9a6c 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -33,12 +33,13 @@ #include #include +#include + #include #include #include #include #include -#include #include #include "module-pipe-source-symdef.h" diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index d5b5f63b..79a59cd5 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -42,6 +42,8 @@ #include "../polypcore/winsock.h" +#include + #include #include #include @@ -49,7 +51,6 @@ #include #include #include -#include #ifdef USE_TCP_SOCKETS #define SOCKET_DESCRIPTION "(TCP sockets)" diff --git a/src/modules/module-sine.c b/src/modules/module-sine.c index 3267d49b..15b6c8a9 100644 --- a/src/modules/module-sine.c +++ b/src/modules/module-sine.c @@ -27,10 +27,11 @@ #include #include +#include + #include #include #include -#include #include #include diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 3e7c2fb4..d82e3362 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -41,6 +41,7 @@ #include #include +#include #include #include @@ -49,7 +50,6 @@ #include #include #include -#include #include #include "module-solaris-symdef.h" diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 2e04b120..a2a1e33d 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -32,13 +32,13 @@ #include #include +#include #include #include #include #include #include -#include #include #include #include diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index f9e7d013..ea40d862 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -32,12 +32,13 @@ #include #include +#include + #include #include #include #include #include -#include #include #include #include diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index 2d9c42eb..3d1f1b01 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -29,6 +29,8 @@ #include +#include + #include #include #include @@ -36,7 +38,6 @@ #include #include #include -#include #include "module-waveout-symdef.h" diff --git a/src/modules/module-x11-bell.c b/src/modules/module-x11-bell.c index e4d4020e..2b891bc1 100644 --- a/src/modules/module-x11-bell.c +++ b/src/modules/module-x11-bell.c @@ -31,11 +31,12 @@ #include #include +#include + #include #include #include #include -#include #include #include #include diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c index 7408b930..e974487d 100644 --- a/src/modules/module-x11-publish.c +++ b/src/modules/module-x11-publish.c @@ -32,11 +32,12 @@ #include #include +#include + #include #include #include #include -#include #include #include #include diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index f8607bef..e5dce755 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -29,7 +29,8 @@ #include #include -#include +#include + #include #include #include diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index 925a1210..89aa8983 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -31,6 +31,8 @@ #include #include +#include + #include #include #include @@ -38,7 +40,6 @@ #include #include #include -#include #include #include #include diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index d0def859..8fc1d7fe 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -32,6 +32,8 @@ #include #include +#include + #include #include #include @@ -39,7 +41,6 @@ #include #include #include -#include #include #include diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c index d2bca04d..e579b5c5 100644 --- a/src/modules/rtp/sap.c +++ b/src/modules/rtp/sap.c @@ -38,9 +38,10 @@ #include #endif +#include + #include #include -#include #include "sap.h" #include "sdp.h" diff --git a/src/modules/rtp/sdp.c b/src/modules/rtp/sdp.c index 84bcd83b..3cece711 100644 --- a/src/modules/rtp/sdp.c +++ b/src/modules/rtp/sdp.c @@ -31,9 +31,10 @@ #include #include +#include + #include #include -#include #include "sdp.h" #include "rtp.h" diff --git a/src/polyp/browser.c b/src/polyp/browser.c index cef680e4..5442fd4c 100644 --- a/src/polyp/browser.c +++ b/src/polyp/browser.c @@ -22,7 +22,8 @@ #include #include -#include +#include + #include #include diff --git a/src/polyp/channelmap.c b/src/polyp/channelmap.c index 7266a0a0..ddd7b3ce 100644 --- a/src/polyp/channelmap.c +++ b/src/polyp/channelmap.c @@ -28,8 +28,10 @@ #include #include +#include + #include -#include + #include "channelmap.h" const char *const table[] = { diff --git a/src/polyp/client-conf-x11.c b/src/polyp/client-conf-x11.c index 7187d86b..17ee2d6a 100644 --- a/src/polyp/client-conf-x11.c +++ b/src/polyp/client-conf-x11.c @@ -29,9 +29,10 @@ #include #include +#include + #include #include -#include #include #include "client-conf-x11.h" diff --git a/src/polyp/client-conf.c b/src/polyp/client-conf.c index d3ad0767..567d2ae4 100644 --- a/src/polyp/client-conf.c +++ b/src/polyp/client-conf.c @@ -29,7 +29,8 @@ #include #include -#include +#include + #include #include #include diff --git a/src/polyp/context.c b/src/polyp/context.c index d5cf90f8..3c46e2e8 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -48,6 +48,7 @@ #include "../polypcore/winsock.h" #include +#include #include #include @@ -56,7 +57,6 @@ #include #include #include -#include #include #include diff --git a/src/polyp/glib-mainloop.c b/src/polyp/glib-mainloop.c index 3937a1a9..bc5df3a9 100644 --- a/src/polyp/glib-mainloop.c +++ b/src/polyp/glib-mainloop.c @@ -25,8 +25,9 @@ #include +#include + #include -#include #include #include "glib.h" diff --git a/src/polyp/glib12-mainloop.c b/src/polyp/glib12-mainloop.c index 5ad23adb..7af21210 100644 --- a/src/polyp/glib12-mainloop.c +++ b/src/polyp/glib12-mainloop.c @@ -25,8 +25,9 @@ #include +#include + #include -#include #include #include "glib-mainloop.h" diff --git a/src/polyp/mainloop-api.c b/src/polyp/mainloop-api.c index 71f55c05..f29598dc 100644 --- a/src/polyp/mainloop-api.c +++ b/src/polyp/mainloop-api.c @@ -26,8 +26,9 @@ #include #include +#include + #include -#include #include "mainloop-api.h" diff --git a/src/polyp/mainloop-signal.c b/src/polyp/mainloop-signal.c index 4ffa00ba..a225f78b 100644 --- a/src/polyp/mainloop-signal.c +++ b/src/polyp/mainloop-signal.c @@ -36,8 +36,9 @@ #include #endif +#include + #include -#include #include #include diff --git a/src/polyp/mainloop.c b/src/polyp/mainloop.c index 589fe77e..82e789c5 100644 --- a/src/polyp/mainloop.c +++ b/src/polyp/mainloop.c @@ -44,9 +44,10 @@ #include "../polypcore/pipe.h" #endif +#include + #include #include -#include #include #include "mainloop.h" diff --git a/src/polyp/operation.c b/src/polyp/operation.c index 1c0cb99f..5af9ec0b 100644 --- a/src/polyp/operation.c +++ b/src/polyp/operation.c @@ -25,7 +25,7 @@ #include -#include +#include #include "internal.h" #include "operation.h" diff --git a/src/polyp/simple.c b/src/polyp/simple.c index 1f25869b..b56406c9 100644 --- a/src/polyp/simple.c +++ b/src/polyp/simple.c @@ -30,9 +30,9 @@ #include #include +#include #include -#include #include #include "simple.h" diff --git a/src/polyp/stream.c b/src/polyp/stream.c index b2711ce0..f188e788 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -29,7 +29,8 @@ #include #include -#include +#include + #include #include #include diff --git a/src/polyp/thread-mainloop.c b/src/polyp/thread-mainloop.c index 20639e9e..d036a232 100644 --- a/src/polyp/thread-mainloop.c +++ b/src/polyp/thread-mainloop.c @@ -41,8 +41,9 @@ #include #endif +#include + #include -#include #include #include "mainloop.h" diff --git a/src/polyp/xmalloc.c b/src/polyp/xmalloc.c new file mode 100644 index 00000000..4c8689a6 --- /dev/null +++ b/src/polyp/xmalloc.c @@ -0,0 +1,123 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include "xmalloc.h" + +/* Make sure not to allocate more than this much memory. */ +#define MAX_ALLOC_SIZE (1024*1024*20) /* 20MB */ + +/* #undef malloc */ +/* #undef free */ +/* #undef realloc */ +/* #undef strndup */ +/* #undef strdup */ + +static void oom(void) PA_GCC_NORETURN; + +/** called in case of an OOM situation. Prints an error message and + * exits */ +static void oom(void) { + static const char e[] = "Not enough memory\n"; + pa_loop_write(STDERR_FILENO, e, sizeof(e)-1); +#ifdef SIGQUIT + raise(SIGQUIT); +#endif + _exit(1); +} + +void* pa_xmalloc(size_t size) { + void *p; + assert(size > 0); + assert(size < MAX_ALLOC_SIZE); + + if (!(p = malloc(size))) + oom(); + + return p; +} + +void* pa_xmalloc0(size_t size) { + void *p; + assert(size > 0); + assert(size < MAX_ALLOC_SIZE); + + if (!(p = calloc(1, size))) + oom(); + + return p; +} + +void *pa_xrealloc(void *ptr, size_t size) { + void *p; + assert(size > 0); + assert(size < MAX_ALLOC_SIZE); + + if (!(p = realloc(ptr, size))) + oom(); + return p; +} + +void* pa_xmemdup(const void *p, size_t l) { + if (!p) + return NULL; + else { + char *r = pa_xmalloc(l); + memcpy(r, p, l); + return r; + } +} + +char *pa_xstrdup(const char *s) { + if (!s) + return NULL; + + return pa_xmemdup(s, strlen(s)+1); +} + +char *pa_xstrndup(const char *s, size_t l) { + if (!s) + return NULL; + else { + char *r; + size_t t = strlen(s); + + if (t > l) + t = l; + + r = pa_xmemdup(s, t+1); + r[t] = 0; + return r; + } +} + diff --git a/src/polyp/xmalloc.h b/src/polyp/xmalloc.h new file mode 100644 index 00000000..2946011a --- /dev/null +++ b/src/polyp/xmalloc.h @@ -0,0 +1,58 @@ +#ifndef foomemoryhfoo +#define foomemoryhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +void* pa_xmalloc(size_t l); +void *pa_xmalloc0(size_t l); +void *pa_xrealloc(void *ptr, size_t size); +#define pa_xfree free + +char *pa_xstrdup(const char *s); +char *pa_xstrndup(const char *s, size_t l); + +void* pa_xmemdup(const void *p, size_t l); + +/** Internal helper for pa_xnew() */ +static inline void* pa_xnew_internal(unsigned n, size_t k) { + assert(n < INT_MAX/k); + return pa_xmalloc(n*k); +} + +/** Allocate n new structures of the specified type. */ +#define pa_xnew(type, n) ((type*) pa_xnew_internal((n), sizeof(type))) + +/** Internal helper for pa_xnew0() */ +static inline void* pa_xnew0_internal(unsigned n, size_t k) { + assert(n < INT_MAX/k); + return pa_xmalloc0(n*k); +} + +/** Same as pa_xnew() but set the memory to zero */ +#define pa_xnew0(type, n) ((type*) pa_xnew0_internal((n), sizeof(type))) + +#endif diff --git a/src/polypcore/authkey-prop.c b/src/polypcore/authkey-prop.c index 3faf0ef1..6172d432 100644 --- a/src/polypcore/authkey-prop.c +++ b/src/polypcore/authkey-prop.c @@ -22,7 +22,8 @@ #include #include -#include +#include + #include #include diff --git a/src/polypcore/autoload.c b/src/polypcore/autoload.c index 8d2dca30..386de219 100644 --- a/src/polypcore/autoload.c +++ b/src/polypcore/autoload.c @@ -27,8 +27,9 @@ #include #include +#include + #include -#include #include #include #include diff --git a/src/polypcore/cli-command.c b/src/polypcore/cli-command.c index 180c61e9..5556bcb3 100644 --- a/src/polypcore/cli-command.c +++ b/src/polypcore/cli-command.c @@ -29,6 +29,8 @@ #include #include +#include + #include #include #include @@ -44,7 +46,6 @@ #include #include #include -#include #include #include #include diff --git a/src/polypcore/cli-text.c b/src/polypcore/cli-text.c index 74de5781..09ccaa00 100644 --- a/src/polypcore/cli-text.c +++ b/src/polypcore/cli-text.c @@ -27,6 +27,8 @@ #include #include +#include + #include #include #include @@ -37,7 +39,6 @@ #include #include #include -#include #include "cli-text.h" diff --git a/src/polypcore/cli.c b/src/polypcore/cli.c index 583f6845..683d29ec 100644 --- a/src/polypcore/cli.c +++ b/src/polypcore/cli.c @@ -28,6 +28,8 @@ #include #include +#include + #include #include #include @@ -40,7 +42,6 @@ #include #include #include -#include #include #include "cli.h" diff --git a/src/polypcore/client.c b/src/polypcore/client.c index be970470..b5ed2fd0 100644 --- a/src/polypcore/client.c +++ b/src/polypcore/client.c @@ -28,7 +28,8 @@ #include #include -#include +#include + #include #include diff --git a/src/polypcore/conf-parser.c b/src/polypcore/conf-parser.c index 26fc33b5..64e66c2e 100644 --- a/src/polypcore/conf-parser.c +++ b/src/polypcore/conf-parser.c @@ -28,9 +28,10 @@ #include #include +#include + #include #include -#include #include "conf-parser.h" diff --git a/src/polypcore/core-scache.c b/src/polypcore/core-scache.c index 3bba38ed..8080fcd6 100644 --- a/src/polypcore/core-scache.c +++ b/src/polypcore/core-scache.c @@ -44,10 +44,11 @@ #include #include #include +#include + #include #include #include -#include #include #include #include diff --git a/src/polypcore/core-subscribe.c b/src/polypcore/core-subscribe.c index fa6c0e50..52babb7a 100644 --- a/src/polypcore/core-subscribe.c +++ b/src/polypcore/core-subscribe.c @@ -26,8 +26,9 @@ #include #include +#include + #include -#include #include #include "core-subscribe.h" diff --git a/src/polypcore/core.c b/src/polypcore/core.c index 0093aebd..ff8ec081 100644 --- a/src/polypcore/core.c +++ b/src/polypcore/core.c @@ -28,6 +28,8 @@ #include #include +#include + #include #include #include @@ -35,7 +37,6 @@ #include #include #include -#include #include #include #include diff --git a/src/polypcore/dynarray.c b/src/polypcore/dynarray.c index 1aff7f51..234c2c03 100644 --- a/src/polypcore/dynarray.c +++ b/src/polypcore/dynarray.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include "dynarray.h" diff --git a/src/polypcore/hashmap.c b/src/polypcore/hashmap.c index 8861fd3d..adc322f0 100644 --- a/src/polypcore/hashmap.c +++ b/src/polypcore/hashmap.c @@ -27,8 +27,9 @@ #include #include +#include + #include -#include #include #include "hashmap.h" diff --git a/src/polypcore/idxset.c b/src/polypcore/idxset.c index f970ae5e..bde5c279 100644 --- a/src/polypcore/idxset.c +++ b/src/polypcore/idxset.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include "idxset.h" diff --git a/src/polypcore/iochannel.c b/src/polypcore/iochannel.c index aba0399c..a1ad5dea 100644 --- a/src/polypcore/iochannel.c +++ b/src/polypcore/iochannel.c @@ -38,9 +38,10 @@ #include "winsock.h" +#include + #include #include -#include #include #include "iochannel.h" diff --git a/src/polypcore/ioline.c b/src/polypcore/ioline.c index eb8fdda5..9bb610fe 100644 --- a/src/polypcore/ioline.c +++ b/src/polypcore/ioline.c @@ -29,7 +29,8 @@ #include #include -#include +#include + #include #include "ioline.h" diff --git a/src/polypcore/log.c b/src/polypcore/log.c index 9c9ed2fd..9908d168 100644 --- a/src/polypcore/log.c +++ b/src/polypcore/log.c @@ -33,7 +33,8 @@ #include #endif -#include +#include + #include #include "log.h" diff --git a/src/polypcore/mcalign.c b/src/polypcore/mcalign.c index f90fd7e8..d9267f99 100644 --- a/src/polypcore/mcalign.c +++ b/src/polypcore/mcalign.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include "mcalign.h" diff --git a/src/polypcore/memblock.c b/src/polypcore/memblock.c index 04e8436f..a0e5135b 100644 --- a/src/polypcore/memblock.c +++ b/src/polypcore/memblock.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include "memblock.h" diff --git a/src/polypcore/memblockq.c b/src/polypcore/memblockq.c index 90e1d9eb..caacd96f 100644 --- a/src/polypcore/memblockq.c +++ b/src/polypcore/memblockq.c @@ -30,7 +30,8 @@ #include #include -#include +#include + #include #include diff --git a/src/polypcore/memchunk.c b/src/polypcore/memchunk.c index d6856ab8..918b3f0f 100644 --- a/src/polypcore/memchunk.c +++ b/src/polypcore/memchunk.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include "memchunk.h" diff --git a/src/polypcore/modargs.c b/src/polypcore/modargs.c index 713326bf..63cc779d 100644 --- a/src/polypcore/modargs.c +++ b/src/polypcore/modargs.c @@ -28,13 +28,14 @@ #include #include +#include + #include #include #include #include #include #include -#include #include #include "modargs.h" diff --git a/src/polypcore/modinfo.c b/src/polypcore/modinfo.c index 39186ceb..241076c6 100644 --- a/src/polypcore/modinfo.c +++ b/src/polypcore/modinfo.c @@ -26,7 +26,8 @@ #include #include -#include +#include + #include #include diff --git a/src/polypcore/module.c b/src/polypcore/module.c index 5412f397..fe177a5b 100644 --- a/src/polypcore/module.c +++ b/src/polypcore/module.c @@ -30,7 +30,8 @@ #include #include -#include +#include + #include #include #include diff --git a/src/polypcore/namereg.c b/src/polypcore/namereg.c index 9229a0f9..cf11f5a4 100644 --- a/src/polypcore/namereg.c +++ b/src/polypcore/namereg.c @@ -29,10 +29,11 @@ #include #include +#include + #include #include #include -#include #include #include diff --git a/src/polypcore/packet.c b/src/polypcore/packet.c index 31ddad95..646b59e0 100644 --- a/src/polypcore/packet.c +++ b/src/polypcore/packet.c @@ -26,7 +26,7 @@ #include #include -#include +#include #include "packet.h" diff --git a/src/polypcore/parseaddr.c b/src/polypcore/parseaddr.c index c2b25c89..7e518a5d 100644 --- a/src/polypcore/parseaddr.c +++ b/src/polypcore/parseaddr.c @@ -27,7 +27,8 @@ #include #include -#include +#include + #include #include "parseaddr.h" diff --git a/src/polypcore/pdispatch.c b/src/polypcore/pdispatch.c index b087f1a5..21e3644e 100644 --- a/src/polypcore/pdispatch.c +++ b/src/polypcore/pdispatch.c @@ -27,8 +27,9 @@ #include #include +#include + #include -#include #include #include #include diff --git a/src/polypcore/pid.c b/src/polypcore/pid.c index b258290b..53b8ad0a 100644 --- a/src/polypcore/pid.c +++ b/src/polypcore/pid.c @@ -39,9 +39,10 @@ #include #endif +#include + #include #include -#include #include "pid.h" diff --git a/src/polypcore/play-memchunk.c b/src/polypcore/play-memchunk.c index 37ebdcf1..982cedc7 100644 --- a/src/polypcore/play-memchunk.c +++ b/src/polypcore/play-memchunk.c @@ -28,8 +28,9 @@ #include #include +#include + #include -#include #include #include "play-memchunk.h" diff --git a/src/polypcore/props.c b/src/polypcore/props.c index 96cdc4f2..1db44ee7 100644 --- a/src/polypcore/props.c +++ b/src/polypcore/props.c @@ -21,7 +21,8 @@ #include -#include +#include + #include #include "props.h" diff --git a/src/polypcore/protocol-cli.c b/src/polypcore/protocol-cli.c index 7dd489f7..076411cf 100644 --- a/src/polypcore/protocol-cli.c +++ b/src/polypcore/protocol-cli.c @@ -26,8 +26,9 @@ #include #include +#include + #include -#include #include #include "protocol-cli.h" diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index fcbeba6d..86a8c9e3 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -31,6 +31,8 @@ #include #include +#include + #include #include #include @@ -42,7 +44,6 @@ #include #include #include -#include #include #include #include diff --git a/src/polypcore/protocol-http.c b/src/polypcore/protocol-http.c index 85ddebee..68864237 100644 --- a/src/polypcore/protocol-http.c +++ b/src/polypcore/protocol-http.c @@ -28,8 +28,9 @@ #include #include +#include + #include -#include #include #include #include diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 3b904134..b0ad5955 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -43,7 +44,6 @@ #include #include #include -#include #include #include #include diff --git a/src/polypcore/protocol-simple.c b/src/polypcore/protocol-simple.c index 1e3b169c..caffd5c9 100644 --- a/src/polypcore/protocol-simple.c +++ b/src/polypcore/protocol-simple.c @@ -30,12 +30,13 @@ #include #include +#include + #include #include #include #include #include -#include #include #include "protocol-simple.h" diff --git a/src/polypcore/pstream.c b/src/polypcore/pstream.c index 09bd1e27..074cab91 100644 --- a/src/polypcore/pstream.c +++ b/src/polypcore/pstream.c @@ -34,8 +34,9 @@ #include "winsock.h" +#include + #include -#include #include #include diff --git a/src/polypcore/queue.c b/src/polypcore/queue.c index 77ca1ed3..01f957d9 100644 --- a/src/polypcore/queue.c +++ b/src/polypcore/queue.c @@ -26,7 +26,7 @@ #include #include -#include +#include #include "queue.h" diff --git a/src/polypcore/resampler.c b/src/polypcore/resampler.c index b2a8874b..33e8c295 100644 --- a/src/polypcore/resampler.c +++ b/src/polypcore/resampler.c @@ -30,8 +30,9 @@ #include #include +#include + #include -#include #include #include "resampler.h" diff --git a/src/polypcore/sink-input.c b/src/polypcore/sink-input.c index c1026390..5c0caa21 100644 --- a/src/polypcore/sink-input.c +++ b/src/polypcore/sink-input.c @@ -28,8 +28,9 @@ #include #include +#include + #include -#include #include #include #include diff --git a/src/polypcore/sink.c b/src/polypcore/sink.c index b59f1eaa..a873c00a 100644 --- a/src/polypcore/sink.c +++ b/src/polypcore/sink.c @@ -29,12 +29,12 @@ #include #include +#include #include #include #include #include -#include #include #include #include diff --git a/src/polypcore/socket-client.c b/src/polypcore/socket-client.c index 734b9dde..a61cf582 100644 --- a/src/polypcore/socket-client.c +++ b/src/polypcore/socket-client.c @@ -54,9 +54,10 @@ #include "winsock.h" +#include + #include #include -#include #include #include diff --git a/src/polypcore/socket-server.c b/src/polypcore/socket-server.c index f7e0b647..959173f2 100644 --- a/src/polypcore/socket-server.c +++ b/src/polypcore/socket-server.c @@ -62,8 +62,9 @@ #include "winsock.h" +#include + #include -#include #include #include diff --git a/src/polypcore/socket-util.c b/src/polypcore/socket-util.c index 915c7f22..0961db21 100644 --- a/src/polypcore/socket-util.c +++ b/src/polypcore/socket-util.c @@ -59,8 +59,9 @@ #include "winsock.h" +#include + #include -#include #include #include "socket-util.h" diff --git a/src/polypcore/sound-file-stream.c b/src/polypcore/sound-file-stream.c index fdacea54..68fd8a89 100644 --- a/src/polypcore/sound-file-stream.c +++ b/src/polypcore/sound-file-stream.c @@ -30,8 +30,9 @@ #include +#include + #include -#include #include #include "sound-file-stream.h" diff --git a/src/polypcore/source-output.c b/src/polypcore/source-output.c index b3113071..c8db870b 100644 --- a/src/polypcore/source-output.c +++ b/src/polypcore/source-output.c @@ -28,7 +28,8 @@ #include #include -#include +#include + #include #include #include diff --git a/src/polypcore/source.c b/src/polypcore/source.c index fca281a7..4d96622b 100644 --- a/src/polypcore/source.c +++ b/src/polypcore/source.c @@ -28,9 +28,10 @@ #include #include +#include + #include #include -#include #include #include #include diff --git a/src/polypcore/strbuf.c b/src/polypcore/strbuf.c index dcad5e78..d1517a11 100644 --- a/src/polypcore/strbuf.c +++ b/src/polypcore/strbuf.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include "strbuf.h" diff --git a/src/polypcore/strlist.c b/src/polypcore/strlist.c index e165aefd..4d70e9e9 100644 --- a/src/polypcore/strlist.c +++ b/src/polypcore/strlist.c @@ -26,7 +26,8 @@ #include #include -#include +#include + #include #include diff --git a/src/polypcore/tagstruct.c b/src/polypcore/tagstruct.c index 86b8368a..27582cae 100644 --- a/src/polypcore/tagstruct.c +++ b/src/polypcore/tagstruct.c @@ -36,7 +36,7 @@ #include "winsock.h" -#include +#include #include "tagstruct.h" diff --git a/src/polypcore/tokenizer.c b/src/polypcore/tokenizer.c index 556a190a..667643fe 100644 --- a/src/polypcore/tokenizer.c +++ b/src/polypcore/tokenizer.c @@ -27,8 +27,9 @@ #include #include +#include + #include -#include #include #include "tokenizer.h" diff --git a/src/polypcore/utf8.c b/src/polypcore/utf8.c index bb8621e2..01fbfccd 100644 --- a/src/polypcore/utf8.c +++ b/src/polypcore/utf8.c @@ -33,8 +33,9 @@ #include #include +#include + #include "utf8.h" -#include "xmalloc.h" #define FILTER_CHAR '_' diff --git a/src/polypcore/util.c b/src/polypcore/util.c index 6f7f8819..9783b746 100644 --- a/src/polypcore/util.c +++ b/src/polypcore/util.c @@ -70,7 +70,8 @@ #include "winsock.h" -#include +#include + #include #include "util.h" diff --git a/src/polypcore/x11wrap.c b/src/polypcore/x11wrap.c index c1ca83ca..41a40764 100644 --- a/src/polypcore/x11wrap.c +++ b/src/polypcore/x11wrap.c @@ -22,8 +22,9 @@ #include #include +#include + #include -#include #include #include diff --git a/src/polypcore/xmalloc.c b/src/polypcore/xmalloc.c deleted file mode 100644 index 4c8689a6..00000000 --- a/src/polypcore/xmalloc.c +++ /dev/null @@ -1,123 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include -#include - -#include "xmalloc.h" - -/* Make sure not to allocate more than this much memory. */ -#define MAX_ALLOC_SIZE (1024*1024*20) /* 20MB */ - -/* #undef malloc */ -/* #undef free */ -/* #undef realloc */ -/* #undef strndup */ -/* #undef strdup */ - -static void oom(void) PA_GCC_NORETURN; - -/** called in case of an OOM situation. Prints an error message and - * exits */ -static void oom(void) { - static const char e[] = "Not enough memory\n"; - pa_loop_write(STDERR_FILENO, e, sizeof(e)-1); -#ifdef SIGQUIT - raise(SIGQUIT); -#endif - _exit(1); -} - -void* pa_xmalloc(size_t size) { - void *p; - assert(size > 0); - assert(size < MAX_ALLOC_SIZE); - - if (!(p = malloc(size))) - oom(); - - return p; -} - -void* pa_xmalloc0(size_t size) { - void *p; - assert(size > 0); - assert(size < MAX_ALLOC_SIZE); - - if (!(p = calloc(1, size))) - oom(); - - return p; -} - -void *pa_xrealloc(void *ptr, size_t size) { - void *p; - assert(size > 0); - assert(size < MAX_ALLOC_SIZE); - - if (!(p = realloc(ptr, size))) - oom(); - return p; -} - -void* pa_xmemdup(const void *p, size_t l) { - if (!p) - return NULL; - else { - char *r = pa_xmalloc(l); - memcpy(r, p, l); - return r; - } -} - -char *pa_xstrdup(const char *s) { - if (!s) - return NULL; - - return pa_xmemdup(s, strlen(s)+1); -} - -char *pa_xstrndup(const char *s, size_t l) { - if (!s) - return NULL; - else { - char *r; - size_t t = strlen(s); - - if (t > l) - t = l; - - r = pa_xmemdup(s, t+1); - r[t] = 0; - return r; - } -} - diff --git a/src/polypcore/xmalloc.h b/src/polypcore/xmalloc.h deleted file mode 100644 index 2946011a..00000000 --- a/src/polypcore/xmalloc.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef foomemoryhfoo -#define foomemoryhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include - -void* pa_xmalloc(size_t l); -void *pa_xmalloc0(size_t l); -void *pa_xrealloc(void *ptr, size_t size); -#define pa_xfree free - -char *pa_xstrdup(const char *s); -char *pa_xstrndup(const char *s, size_t l); - -void* pa_xmemdup(const void *p, size_t l); - -/** Internal helper for pa_xnew() */ -static inline void* pa_xnew_internal(unsigned n, size_t k) { - assert(n < INT_MAX/k); - return pa_xmalloc(n*k); -} - -/** Allocate n new structures of the specified type. */ -#define pa_xnew(type, n) ((type*) pa_xnew_internal((n), sizeof(type))) - -/** Internal helper for pa_xnew0() */ -static inline void* pa_xnew0_internal(unsigned n, size_t k) { - assert(n < INT_MAX/k); - return pa_xmalloc0(n*k); -} - -/** Same as pa_xnew() but set the memory to zero */ -#define pa_xnew0(type, n) ((type*) pa_xnew0_internal((n), sizeof(type))) - -#endif diff --git a/src/tests/strlist-test.c b/src/tests/strlist-test.c index 14543112..415c94e6 100644 --- a/src/tests/strlist-test.c +++ b/src/tests/strlist-test.c @@ -1,7 +1,7 @@ #include +#include #include -#include #include int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char* argv[]) { diff --git a/src/tests/utf8-test.c b/src/tests/utf8-test.c index c8b2fabb..57f445c7 100644 --- a/src/tests/utf8-test.c +++ b/src/tests/utf8-test.c @@ -3,8 +3,8 @@ #include #include +#include #include -#include int main(int argc, char *argv[]) { char *c; -- cgit From 7ca25e58e99abb3d640b6012d7cbfc9bc9087849 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 17 May 2006 17:30:49 +0000 Subject: Move utf8 to the public part (libpolyp). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@909 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 9 ++- src/polyp/utf8.c | 164 +++++++++++++++++++++++++++++++++++++++ src/polyp/utf8.h | 28 +++++++ src/polypcore/protocol-esound.c | 2 +- src/polypcore/protocol-native.c | 2 +- src/polypcore/sink-input.c | 2 +- src/polypcore/sink.c | 2 +- src/polypcore/source-output.c | 2 +- src/polypcore/source.c | 2 +- src/polypcore/utf8.c | 165 ---------------------------------------- src/polypcore/utf8.h | 28 ------- src/tests/utf8-test.c | 2 +- 12 files changed, 204 insertions(+), 204 deletions(-) create mode 100644 src/polyp/utf8.c create mode 100644 src/polyp/utf8.h delete mode 100644 src/polypcore/utf8.c delete mode 100644 src/polypcore/utf8.h diff --git a/src/Makefile.am b/src/Makefile.am index afbdedee..72db5f80 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -313,6 +313,7 @@ polypinclude_HEADERS = \ polyp/subscribe.h \ polyp/version.h \ polyp/sample.h \ + polyp/utf8.h \ polyp/volume.h \ polyp/xmalloc.h @@ -358,6 +359,7 @@ libpolyp_la_SOURCES = \ polyp/subscribe.c polyp/subscribe.h \ polyp/sample.c polyp/sample.h \ polyp/volume.c polyp/volume.h \ + polyp/utf8.c polyp/utf8.h \ polyp/mainloop.c polyp/mainloop.h \ polyp/mainloop-signal.c polyp/mainloop-signal.h \ polyp/thread-mainloop.c polyp/thread-mainloop.h \ @@ -485,8 +487,7 @@ polypcoreinclude_HEADERS = \ polypcore/source-output.h \ polypcore/strbuf.h \ polypcore/tokenizer.h \ - polypcore/util.h \ - polypcore/utf8.h + polypcore/util.h lib_LTLIBRARIES += libpolypcore.la @@ -498,6 +499,7 @@ libpolypcore_la_SOURCES = \ polyp/mainloop-signal.c polyp/mainloop-signal.h \ polyp/sample.c polyp/sample.h \ polyp/volume.c polyp/volume.h \ + polyp/utf8.c polyp/utf8.h \ polyp/xmalloc.c polyp/xmalloc.h # Pure core stuff (some are shared in libpolyp though). @@ -546,8 +548,7 @@ libpolypcore_la_SOURCES += \ polypcore/strbuf.c polypcore/strbuf.h \ polypcore/tokenizer.c polypcore/tokenizer.h \ polypcore/util.c polypcore/util.h \ - polypcore/winsock.h \ - polypcore/utf8.c polypcore/utf8.h + polypcore/winsock.h if OS_IS_WIN32 libpolypcore_la_SOURCES += \ diff --git a/src/polyp/utf8.c b/src/polyp/utf8.c new file mode 100644 index 00000000..bb8621e2 --- /dev/null +++ b/src/polyp/utf8.c @@ -0,0 +1,164 @@ +/* $Id */ + +/* This file is based on the GLIB utf8 validation functions. The + * original license text follows. */ + +/* gutf8.c - Operations on UTF-8 strings. + * + * Copyright (C) 1999 Tom Tromey + * Copyright (C) 2000 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "utf8.h" +#include "xmalloc.h" + +#define FILTER_CHAR '_' + +static inline int is_unicode_valid(uint32_t ch) { + if (ch >= 0x110000) /* End of unicode space */ + return 0; + if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ + return 0; + if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ + return 0; + if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ + return 0; + return 1; +} + +static inline int is_continuation_char(uint8_t ch) { + if ((ch & 0xc0) != 0x80) /* 10xxxxxx */ + return 0; + return 1; +} + +static inline void merge_continuation_char(uint32_t *u_ch, uint8_t ch) { + *u_ch <<= 6; + *u_ch |= ch & 0x3f; +} + +static char* utf8_validate(const char *str, char *output) { + uint32_t val = 0; + uint32_t min = 0; + const uint8_t *p, *last; + int size; + uint8_t *o; + + o = (uint8_t*) output; + for (p = (const uint8_t*) str; *p; p++) { + if (*p < 128) { + if (o) + *o = *p; + } else { + last = p; + + if ((*p & 0xe0) == 0xc0) { /* 110xxxxx two-char seq. */ + size = 2; + min = 128; + val = *p & 0x1e; + goto ONE_REMAINING; + } else if ((*p & 0xf0) == 0xe0) { /* 1110xxxx three-char seq.*/ + size = 3; + min = (1 << 11); + val = *p & 0x0f; + goto TWO_REMAINING; + } else if ((*p & 0xf8) == 0xf0) { /* 11110xxx four-char seq */ + size = 4; + min = (1 << 16); + val = *p & 0x07; + } else { + size = 1; + goto error; + } + + p++; + if (!is_continuation_char(*p)) + goto error; + merge_continuation_char(&val, *p); + +TWO_REMAINING: + p++; + if (!is_continuation_char(*p)) + goto error; + merge_continuation_char(&val, *p); + +ONE_REMAINING: + p++; + if (!is_continuation_char(*p)) + goto error; + merge_continuation_char(&val, *p); + + if (val < min) + goto error; + + if (!is_unicode_valid(val)) + goto error; + + if (o) { + memcpy(o, last, size); + o += size - 1; + } + + if (o) + o++; + + continue; + +error: + if (o) { + *o = FILTER_CHAR; + p = last; /* We retry at the next character */ + } else + goto failure; + } + + if (o) + o++; + } + + if (o) { + *o = '\0'; + return output; + } + + return (char*) str; + +failure: + return NULL; +} + +const char* pa_utf8_valid (const char *str) { + return utf8_validate(str, NULL); +} + +char* pa_utf8_filter (const char *str) { + char *new_str; + + new_str = pa_xnew(char, strlen(str) + 1); + + return utf8_validate(str, new_str); +} diff --git a/src/polyp/utf8.h b/src/polyp/utf8.h new file mode 100644 index 00000000..6d1e4a7d --- /dev/null +++ b/src/polyp/utf8.h @@ -0,0 +1,28 @@ +#ifndef fooutf8hfoo +#define fooutf8hfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +const char *pa_utf8_valid(const char *str); +char *pa_utf8_filter(const char *str); + +#endif diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index 86a8c9e3..8f53694e 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -46,7 +47,6 @@ #include #include #include -#include #include "endianmacros.h" diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index b0ad5955..338db002 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -53,7 +54,6 @@ #include #include #include -#include #include "protocol-native.h" diff --git a/src/polypcore/sink-input.c b/src/polypcore/sink-input.c index 5c0caa21..bd2a1dcd 100644 --- a/src/polypcore/sink-input.c +++ b/src/polypcore/sink-input.c @@ -28,12 +28,12 @@ #include #include +#include #include #include #include #include -#include #include "sink-input.h" diff --git a/src/polypcore/sink.c b/src/polypcore/sink.c index a873c00a..6931d396 100644 --- a/src/polypcore/sink.c +++ b/src/polypcore/sink.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -37,7 +38,6 @@ #include #include #include -#include #include "sink.h" diff --git a/src/polypcore/source-output.c b/src/polypcore/source-output.c index c8db870b..8ac3a33d 100644 --- a/src/polypcore/source-output.c +++ b/src/polypcore/source-output.c @@ -28,11 +28,11 @@ #include #include +#include #include #include #include -#include #include "source-output.h" diff --git a/src/polypcore/source.c b/src/polypcore/source.c index 4d96622b..c53bf079 100644 --- a/src/polypcore/source.c +++ b/src/polypcore/source.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -35,7 +36,6 @@ #include #include #include -#include #include "source.h" diff --git a/src/polypcore/utf8.c b/src/polypcore/utf8.c deleted file mode 100644 index 01fbfccd..00000000 --- a/src/polypcore/utf8.c +++ /dev/null @@ -1,165 +0,0 @@ -/* $Id */ - -/* This file is based on the GLIB utf8 validation functions. The - * original license text follows. */ - -/* gutf8.c - Operations on UTF-8 strings. - * - * Copyright (C) 1999 Tom Tromey - * Copyright (C) 2000 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -#include "utf8.h" - -#define FILTER_CHAR '_' - -static inline int is_unicode_valid(uint32_t ch) { - if (ch >= 0x110000) /* End of unicode space */ - return 0; - if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ - return 0; - if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ - return 0; - if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ - return 0; - return 1; -} - -static inline int is_continuation_char(uint8_t ch) { - if ((ch & 0xc0) != 0x80) /* 10xxxxxx */ - return 0; - return 1; -} - -static inline void merge_continuation_char(uint32_t *u_ch, uint8_t ch) { - *u_ch <<= 6; - *u_ch |= ch & 0x3f; -} - -static char* utf8_validate(const char *str, char *output) { - uint32_t val = 0; - uint32_t min = 0; - const uint8_t *p, *last; - int size; - uint8_t *o; - - o = (uint8_t*) output; - for (p = (const uint8_t*) str; *p; p++) { - if (*p < 128) { - if (o) - *o = *p; - } else { - last = p; - - if ((*p & 0xe0) == 0xc0) { /* 110xxxxx two-char seq. */ - size = 2; - min = 128; - val = *p & 0x1e; - goto ONE_REMAINING; - } else if ((*p & 0xf0) == 0xe0) { /* 1110xxxx three-char seq.*/ - size = 3; - min = (1 << 11); - val = *p & 0x0f; - goto TWO_REMAINING; - } else if ((*p & 0xf8) == 0xf0) { /* 11110xxx four-char seq */ - size = 4; - min = (1 << 16); - val = *p & 0x07; - } else { - size = 1; - goto error; - } - - p++; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - -TWO_REMAINING: - p++; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - -ONE_REMAINING: - p++; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - - if (val < min) - goto error; - - if (!is_unicode_valid(val)) - goto error; - - if (o) { - memcpy(o, last, size); - o += size - 1; - } - - if (o) - o++; - - continue; - -error: - if (o) { - *o = FILTER_CHAR; - p = last; /* We retry at the next character */ - } else - goto failure; - } - - if (o) - o++; - } - - if (o) { - *o = '\0'; - return output; - } - - return (char*) str; - -failure: - return NULL; -} - -const char* pa_utf8_valid (const char *str) { - return utf8_validate(str, NULL); -} - -char* pa_utf8_filter (const char *str) { - char *new_str; - - new_str = pa_xnew(char, strlen(str) + 1); - - return utf8_validate(str, new_str); -} diff --git a/src/polypcore/utf8.h b/src/polypcore/utf8.h deleted file mode 100644 index 6d1e4a7d..00000000 --- a/src/polypcore/utf8.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef fooutf8hfoo -#define fooutf8hfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -const char *pa_utf8_valid(const char *str); -char *pa_utf8_filter(const char *str); - -#endif diff --git a/src/tests/utf8-test.c b/src/tests/utf8-test.c index 57f445c7..2c21613e 100644 --- a/src/tests/utf8-test.c +++ b/src/tests/utf8-test.c @@ -3,8 +3,8 @@ #include #include +#include #include -#include int main(int argc, char *argv[]) { char *c; -- cgit From 5f6d8c9c8b0f113dee34d3f3c17464a9c696a49b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 18:51:37 +0000 Subject: fix svn tag git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@910 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/utf8.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/polyp/utf8.c b/src/polyp/utf8.c index bb8621e2..300a54ca 100644 --- a/src/polyp/utf8.c +++ b/src/polyp/utf8.c @@ -1,4 +1,4 @@ -/* $Id */ +/* $Id$ */ /* This file is based on the GLIB utf8 validation functions. The * original license text follows. */ -- cgit From ee35a063b2c10564d43a611fcf6ada398851b1d6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 18:52:34 +0000 Subject: add new channel map argument to pa_simple_new() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@911 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/simple.c | 4 +++- src/polyp/simple.h | 9 ++++++--- src/tests/pacat-simple.c | 2 +- src/tests/parec-simple.c | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/polyp/simple.c b/src/polyp/simple.c index b56406c9..84c46bf1 100644 --- a/src/polyp/simple.c +++ b/src/polyp/simple.c @@ -140,6 +140,7 @@ pa_simple* pa_simple_new( const char *dev, const char *stream_name, const pa_sample_spec *ss, + const pa_channel_map *map, const pa_buffer_attr *attr, int *rerror) { @@ -150,6 +151,7 @@ pa_simple* pa_simple_new( CHECK_VALIDITY_RETURN_ANY(rerror, dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD, PA_ERR_INVALID, NULL); CHECK_VALIDITY_RETURN_ANY(rerror, !dev || *dev, PA_ERR_INVALID, NULL); CHECK_VALIDITY_RETURN_ANY(rerror, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID, NULL); + CHECK_VALIDITY_RETURN_ANY(rerror, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID, NULL) p = pa_xnew(pa_simple, 1); p->context = NULL; @@ -184,7 +186,7 @@ pa_simple* pa_simple_new( goto unlock_and_fail; } - if (!(p->stream = pa_stream_new(p->context, stream_name, ss, NULL))) { + if (!(p->stream = pa_stream_new(p->context, stream_name, ss, map))) { error = pa_context_errno(p->context); goto unlock_and_fail; } diff --git a/src/polyp/simple.h b/src/polyp/simple.h index 9066826b..bf3cc330 100644 --- a/src/polyp/simple.h +++ b/src/polyp/simple.h @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -57,6 +58,7 @@ * NULL, // Use the default device. * "Music", // Description of our stream. * &ss, // Our sample format. + * NULL, // Use default channel map * NULL, // Use default buffering attributes. * NULL, // Ignore error code. * ); @@ -112,11 +114,12 @@ typedef struct pa_simple pa_simple; pa_simple* pa_simple_new( const char *server, /**< Server name, or NULL for default */ const char *name, /**< A descriptive name for this client (application name, ...) */ - pa_stream_direction_t dir, /**< Open this stream for recording or playback? */ + pa_stream_direction_t dir, /**< Open this stream for recording or playback? */ const char *dev, /**< Sink (resp. source) name, or NULL for default */ const char *stream_name, /**< A descriptive name for this client (application name, song title, ...) */ - const pa_sample_spec *ss, /**< The sample type to use */ - const pa_buffer_attr *attr, /**< Buffering attributes, or NULL for default */ + const pa_sample_spec *ss, /**< The sample type to use */ + const pa_channel_map *map, /**< The channel map to use, or NULL for default */ + const pa_buffer_attr *attr, /**< Buffering attributes, or NULL for default */ int *error /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */ ); diff --git a/src/tests/pacat-simple.c b/src/tests/pacat-simple.c index 6a75c790..544c31e3 100644 --- a/src/tests/pacat-simple.c +++ b/src/tests/pacat-simple.c @@ -66,7 +66,7 @@ int main(PA_GCC_UNUSED int argc, char*argv[]) { } /* Create a new playback stream */ - if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, &error))) { + if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL, &error))) { fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); goto finish; } diff --git a/src/tests/parec-simple.c b/src/tests/parec-simple.c index fc2314ac..4463d549 100644 --- a/src/tests/parec-simple.c +++ b/src/tests/parec-simple.c @@ -67,7 +67,7 @@ int main(PA_GCC_UNUSED int argc, char*argv[]) { int error; /* Create the recording stream */ - if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, &error))) { + if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, NULL, &error))) { fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); goto finish; } -- cgit From 6e9f2d70937e9b8dc09a753e3d678fe11a5754ca Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 19:06:42 +0000 Subject: add utf8.h and xmalloc.h to doxygen docs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@912 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doxygen/doxygen.conf.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doxygen/doxygen.conf.in b/doxygen/doxygen.conf.in index 471c21dc..97040377 100644 --- a/doxygen/doxygen.conf.in +++ b/doxygen/doxygen.conf.in @@ -417,7 +417,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = ../src/polyp/context.h ../src/polyp/stream.h ../src/polyp/polypaudio.h ../src/polyp/sample.h ../src/polyp/def.h ../src/polyp/subscribe.h ../src/polyp/introspect.h ../src/polyp/scache.h ../src/polyp/mainloop-api.h ../src/polyp/glib-mainloop.h ../src/polyp/mainloop.h ../src/polyp/mainloop-signal.h ../src/polyp/error.h ../src/polyp/operation.h ../src/polyp/simple.h ../src/polyp/version.h ../src/polyp/volume.h ../src/polyp/channelmap.h ../src/polyp/thread-mainloop.h +INPUT = ../src/polyp/context.h ../src/polyp/stream.h ../src/polyp/polypaudio.h ../src/polyp/sample.h ../src/polyp/def.h ../src/polyp/subscribe.h ../src/polyp/introspect.h ../src/polyp/scache.h ../src/polyp/mainloop-api.h ../src/polyp/glib-mainloop.h ../src/polyp/mainloop.h ../src/polyp/mainloop-signal.h ../src/polyp/error.h ../src/polyp/operation.h ../src/polyp/simple.h ../src/polyp/version.h ../src/polyp/volume.h ../src/polyp/channelmap.h ../src/polyp/thread-mainloop.h ../src/polyp/xmalloc.h ../src/polyp/utf8.h # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -- cgit From 56d8e56431e988716ef5580f95ab4361b7a2ebe1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 19:07:30 +0000 Subject: * make pa_xfree() a real function * update doxygen docs for xmalloc.h git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@913 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/xmalloc.c | 6 ++++++ src/polyp/xmalloc.h | 17 ++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/polyp/xmalloc.c b/src/polyp/xmalloc.c index 4c8689a6..1deeebd8 100644 --- a/src/polyp/xmalloc.c +++ b/src/polyp/xmalloc.c @@ -121,3 +121,9 @@ char *pa_xstrndup(const char *s, size_t l) { } } +void pa_xfree(void *p) { + if (!p) + return; + + free(p); +} diff --git a/src/polyp/xmalloc.h b/src/polyp/xmalloc.h index 2946011a..9d91d8dc 100644 --- a/src/polyp/xmalloc.h +++ b/src/polyp/xmalloc.h @@ -27,14 +27,29 @@ #include #include +/** \file + * Memory allocation functions. + */ + +/** Allocate the specified number of bytes, just like malloc() does. However, in case of OOM, terminate */ void* pa_xmalloc(size_t l); + +/** Same as pa_xmalloc(), but initialize allocated memory to 0 */ void *pa_xmalloc0(size_t l); + +/** The combination of pa_xmalloc() and realloc() */ void *pa_xrealloc(void *ptr, size_t size); -#define pa_xfree free +/** Free allocated memory */ +void pa_xfree(void *p); + +/** Duplicate the specified string, allocating memory with pa_xmalloc() */ char *pa_xstrdup(const char *s); + +/** Duplicate the specified string, but truncate after l characters */ char *pa_xstrndup(const char *s, size_t l); +/** Duplicate the specified memory block */ void* pa_xmemdup(const void *p, size_t l); /** Internal helper for pa_xnew() */ -- cgit From 41badddbb9d47fbc82a8473c24bac6e8044642d5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 19:07:53 +0000 Subject: add doxygen docs for utf8.h git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@914 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/utf8.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/polyp/utf8.h b/src/polyp/utf8.h index 6d1e4a7d..e9a51533 100644 --- a/src/polyp/utf8.h +++ b/src/polyp/utf8.h @@ -22,7 +22,14 @@ USA. ***/ +/** \file + * UTF8 Validation functions + */ + +/** Test if the specified strings qualifies as valid UTF8. Return the string if so, otherwise NULL */ const char *pa_utf8_valid(const char *str); + +/** Filter all invalid UTF8 characters from the specified string, returning a new fully UTF8 valid string. Don't forget to free the returned string with pa_xfree() */ char *pa_utf8_filter(const char *str); #endif -- cgit From 43813dcce8119d6d988db7eb47ba587e953a5f21 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 19:26:14 +0000 Subject: include more files in polypaudio.h git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@915 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/polypaudio.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/polyp/polypaudio.h b/src/polyp/polypaudio.h index 1830dea8..fe25fe30 100644 --- a/src/polyp/polypaudio.h +++ b/src/polyp/polypaudio.h @@ -35,13 +35,19 @@ #include #include #include +#include +#include +#include +#include +#include /** \file - * Include all polyplib header file at once. The following + * Include all polyplib header files at once. The following * files are included: \ref mainloop-api.h, \ref sample.h, \ref def.h, * \ref context.h, \ref stream.h, \ref introspect.h, \ref subscribe.h, * \ref scache.h, \ref version.h, \ref error.h, \ref channelmap.h, - * \ref operation.h and \ref volume.h at once */ + * \ref operation.h,\ref volume.h, \ref xmalloc.h, \ref utf8.h, \ref + * thread-mainloop.h, \ref mainloop.h and \ref mainloop-signal.h at once */ /** \mainpage * -- cgit From fbdb06351385eb210c50ba6a1fc2b8c14575513e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 19:26:54 +0000 Subject: replace memory allocation function calls with pa_xXXXX() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@916 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pacat.c | 46 +++++++++++++++++++++------------------------- src/utils/pactl.c | 35 ++++++++++++++++------------------- src/utils/paplay.c | 36 +++++++++++++++++------------------- 3 files changed, 54 insertions(+), 63 deletions(-) diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 529cebae..51b3a48e 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -34,8 +34,6 @@ #include #include -#include -#include #include #define TIME_EVENT_USEC 50000 @@ -97,7 +95,7 @@ static void do_stream_write(size_t length) { buffer_index += l; if (!buffer_length) { - free(buffer); + pa_xfree(buffer); buffer = NULL; buffer_index = buffer_length = 0; } @@ -141,8 +139,7 @@ static void stream_read_callback(pa_stream *s, size_t length, void *userdata) { return; } - buffer = malloc(buffer_length = length); - assert(buffer); + buffer = pa_xmalloc(buffer_length = length); memcpy(buffer, data, length); buffer_index = 0; pa_stream_drop(s); @@ -273,8 +270,8 @@ static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_even if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY || !(l = w = pa_stream_writable_size(stream))) l = 4096; - buffer = malloc(l); - assert(buffer); + buffer = pa_xmalloc(l); + if ((r = read(fd, buffer, l)) <= 0) { if (r == 0) { pa_operation *o; @@ -331,7 +328,7 @@ static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_eve buffer_index += r; if (!buffer_length) { - free(buffer); + pa_xfree(buffer); buffer = NULL; buffer_length = buffer_index = 0; } @@ -342,7 +339,6 @@ static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, if (verbose) fprintf(stderr, "Got signal, exiting.\n"); quit(0); - } /* Show the current latency */ @@ -479,23 +475,23 @@ int main(int argc, char *argv[]) { break; case 'd': - free(device); - device = strdup(optarg); + pa_xfree(device); + device = pa_xstrdup(optarg); break; case 's': - free(server); - server = strdup(optarg); + pa_xfree(server); + server = pa_xstrdup(optarg); break; case 'n': - free(client_name); - client_name = strdup(optarg); + pa_xfree(client_name); + client_name = pa_xstrdup(optarg); break; case ARG_STREAM_NAME: - free(stream_name); - stream_name = strdup(optarg); + pa_xfree(stream_name); + stream_name = pa_xstrdup(optarg); break; case 'v': @@ -567,7 +563,7 @@ int main(int argc, char *argv[]) { close(fd); if (!stream_name) - stream_name = strdup(argv[optind]); + stream_name = pa_xstrdup(argv[optind]); } else { fprintf(stderr, "Too many arguments.\n"); @@ -576,10 +572,10 @@ int main(int argc, char *argv[]) { } if (!client_name) - client_name = strdup(bn); + client_name = pa_xstrdup(bn); if (!stream_name) - stream_name = strdup(client_name); + stream_name = pa_xstrdup(client_name); /* Set up a new main loop */ if (!(m = pa_mainloop_new())) { @@ -659,12 +655,12 @@ quit: pa_mainloop_free(m); } - free(buffer); + pa_xfree(buffer); - free(server); - free(device); - free(client_name); - free(stream_name); + pa_xfree(server); + pa_xfree(device); + pa_xfree(client_name); + pa_xfree(stream_name); return ret; } diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 7a3d3737..cc59e459 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -36,8 +36,6 @@ #include #include -#include -#include #if PA_API_VERSION != 9 #error Invalid Polypaudio API version @@ -511,19 +509,18 @@ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { float *d; assert(s && length && sndfile); - d = malloc(length); - assert(d); + d = pa_xmalloc(length); assert(sample_length >= length); l = length/pa_frame_size(&sample_spec); if ((sf_readf_float(sndfile, d, l)) != l) { - free(d); + pa_xfree(d); fprintf(stderr, "Premature end of file\n"); quit(1); } - pa_stream_write(s, d, length, free, 0, PA_SEEK_RELATIVE); + pa_stream_write(s, d, length, pa_xfree, 0, PA_SEEK_RELATIVE); sample_length -= length; @@ -652,13 +649,13 @@ int main(int argc, char *argv[]) { goto quit; case 's': - free(server); - server = strdup(optarg); + pa_xfree(server); + server = pa_xstrdup(optarg); break; case 'n': - free(client_name); - client_name = strdup(optarg); + pa_xfree(client_name); + client_name = pa_xstrdup(optarg); break; default: @@ -667,7 +664,7 @@ int main(int argc, char *argv[]) { } if (!client_name) - client_name = strdup(bn); + client_name = pa_xstrdup(bn); if (optind < argc) { if (!strcmp(argv[optind], "stat")) @@ -686,7 +683,7 @@ int main(int argc, char *argv[]) { } if (optind+2 < argc) - sample_name = strdup(argv[optind+2]); + sample_name = pa_xstrdup(argv[optind+2]); else { char *f = strrchr(argv[optind+1], '/'); size_t n; @@ -698,7 +695,7 @@ int main(int argc, char *argv[]) { n = strcspn(f, "."); strncpy(tmp, f, n); tmp[n] = 0; - sample_name = strdup(tmp); + sample_name = pa_xstrdup(tmp); } memset(&sfinfo, 0, sizeof(sfinfo)); @@ -719,10 +716,10 @@ int main(int argc, char *argv[]) { goto quit; } - sample_name = strdup(argv[optind+1]); + sample_name = pa_xstrdup(argv[optind+1]); if (optind+2 < argc) - device = strdup(argv[optind+2]); + device = pa_xstrdup(argv[optind+2]); } else if (!strcmp(argv[optind], "remove-sample")) { action = REMOVE_SAMPLE; @@ -731,7 +728,7 @@ int main(int argc, char *argv[]) { goto quit; } - sample_name = strdup(argv[optind+1]); + sample_name = pa_xstrdup(argv[optind+1]); } } @@ -782,9 +779,9 @@ quit: if (sndfile) sf_close(sndfile); - free(server); - free(device); - free(sample_name); + pa_xfree(server); + pa_xfree(device); + pa_xfree(sample_name); return ret; } diff --git a/src/utils/paplay.c b/src/utils/paplay.c index 5f203615..b66c13da 100644 --- a/src/utils/paplay.c +++ b/src/utils/paplay.c @@ -35,8 +35,6 @@ #include #include -#include -#include #if PA_API_VERSION != 9 #error Invalid Polypaudio API version @@ -105,7 +103,7 @@ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { if (!sndfile) return; - data = malloc(length); + data = pa_xmalloc(length); if (readf_function) { size_t k = pa_frame_size(&sample_spec); @@ -117,9 +115,9 @@ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { bytes = sf_read_raw(sndfile, data, length); if (bytes > 0) - pa_stream_write(s, data, bytes, free, 0, PA_SEEK_RELATIVE); + pa_stream_write(s, data, bytes, pa_xfree, 0, PA_SEEK_RELATIVE); else - free(data); + pa_xfree(data); if (bytes < length) { sf_close(sndfile); @@ -257,23 +255,23 @@ int main(int argc, char *argv[]) { goto quit; case 'd': - free(device); - device = strdup(optarg); + pa_xfree(device); + device = pa_xstrdup(optarg); break; case 's': - free(server); - server = strdup(optarg); + pa_xfree(server); + server = pa_xstrdup(optarg); break; case 'n': - free(client_name); - client_name = strdup(optarg); + pa_xfree(client_name); + client_name = pa_xstrdup(optarg); break; case ARG_STREAM_NAME: - free(stream_name); - stream_name = strdup(optarg); + pa_xfree(stream_name); + stream_name = pa_xstrdup(optarg); break; case 'v': @@ -351,11 +349,11 @@ int main(int argc, char *argv[]) { } if (!client_name) - client_name = strdup(bn); + client_name = pa_xstrdup(bn); if (!stream_name) { const char *n = sf_get_string(sndfile, SF_STR_TITLE); - stream_name = strdup(n ? n : filename); + stream_name = pa_xstrdup(n ? n : filename); } if (verbose) { @@ -408,10 +406,10 @@ quit: pa_mainloop_free(m); } - free(server); - free(device); - free(client_name); - free(stream_name); + pa_xfree(server); + pa_xfree(device); + pa_xfree(client_name); + pa_xfree(stream_name); if (sndfile) sf_close(sndfile); -- cgit From c47e937011f00eebab7230cedb58fd59f16487b4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 20:09:57 +0000 Subject: split polypcore/util.[ch] into polypcore/core-util.[ch] and polyp/util.[ch] git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@917 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 31 +- src/modules/module-alsa-sink.c | 2 +- src/modules/module-alsa-source.c | 2 +- src/modules/module-combine.c | 2 +- src/modules/module-detect.c | 2 +- src/modules/module-esound-compat-spawnfd.c | 2 +- src/modules/module-esound-compat-spawnpid.c | 2 +- src/modules/module-esound-sink.c | 2 +- src/modules/module-jack-sink.c | 2 +- src/modules/module-jack-source.c | 2 +- src/modules/module-match.c | 4 +- src/modules/module-mmkbd-evdev.c | 2 +- src/modules/module-null-sink.c | 2 +- src/modules/module-oss-mmap.c | 2 +- src/modules/module-oss.c | 2 +- src/modules/module-pipe-sink.c | 2 +- src/modules/module-pipe-source.c | 2 +- src/modules/module-protocol-stub.c | 2 +- src/modules/module-solaris.c | 2 +- src/modules/module-tunnel.c | 2 +- src/modules/module-volume-restore.c | 4 +- src/modules/module-waveout.c | 2 +- src/modules/module-x11-publish.c | 2 +- src/modules/module-zeroconf-publish.c | 2 +- src/modules/oss-util.c | 2 +- src/polyp/util.c | 350 ++++++++ src/polyp/util.h | 48 + src/polypcore/authkey.c | 2 +- src/polypcore/cli-command.c | 2 +- src/polypcore/conf-parser.c | 2 +- src/polypcore/core-scache.c | 2 +- src/polypcore/core-util.c | 1012 +++++++++++++++++++++ src/polypcore/core-util.h | 89 ++ src/polypcore/core.c | 2 +- src/polypcore/iochannel.c | 2 +- src/polypcore/log.c | 2 +- src/polypcore/modargs.c | 2 +- src/polypcore/modinfo.c | 2 +- src/polypcore/module.c | 2 +- src/polypcore/namereg.c | 2 +- src/polypcore/parseaddr.c | 2 +- src/polypcore/pdispatch.c | 2 +- src/polypcore/pid.c | 2 +- src/polypcore/poll.c | 2 +- src/polypcore/protocol-esound.c | 2 +- src/polypcore/protocol-native.c | 2 +- src/polypcore/random.c | 2 +- src/polypcore/sink.c | 2 +- src/polypcore/socket-client.c | 2 +- src/polypcore/socket-server.c | 2 +- src/polypcore/socket-util.c | 2 +- src/polypcore/strlist.c | 2 +- src/polypcore/util.c | 1293 --------------------------- src/polypcore/util.h | 105 --- src/utils/pabrowse.c | 4 +- 55 files changed, 1562 insertions(+), 1468 deletions(-) create mode 100644 src/polyp/util.c create mode 100644 src/polyp/util.h create mode 100644 src/polypcore/core-util.c create mode 100644 src/polypcore/core-util.h delete mode 100644 src/polypcore/util.c delete mode 100644 src/polypcore/util.h diff --git a/src/Makefile.am b/src/Makefile.am index 72db5f80..e7ad2fd4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -271,17 +271,9 @@ mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MA mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12.la mainloop_test_glib12_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -memblockq_test_SOURCES = \ - tests/memblockq-test.c \ - polyp/xmalloc.c \ - polypcore/memblockq.c \ - polypcore/log.c \ - polypcore/memblock.c \ - polypcore/util.c \ - polypcore/mcalign.c \ - polypcore/memchunk.c +memblockq_test_SOURCES = tests/memblockq-test.c memblockq_test_CFLAGS = $(AM_CFLAGS) -memblockq_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) +memblockq_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpolypcore.la memblockq_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) sync_playback_SOURCES = tests/sync-playback.c @@ -315,7 +307,8 @@ polypinclude_HEADERS = \ polyp/sample.h \ polyp/utf8.h \ polyp/volume.h \ - polyp/xmalloc.h + polyp/xmalloc.h \ + polyp/util.h if HAVE_HOWL polypinclude_HEADERS += \ @@ -364,8 +357,7 @@ libpolyp_la_SOURCES = \ polyp/mainloop-signal.c polyp/mainloop-signal.h \ polyp/thread-mainloop.c polyp/thread-mainloop.h \ polyp/xmalloc.c polyp/xmalloc.h \ - polypcore/pipe.c polypcore/pipe.h \ - polypcore/poll.c polypcore/poll.h + polyp/util.c polyp/util.h # Internal stuff that is shared with libpolypcore libpolyp_la_SOURCES += \ @@ -394,9 +386,11 @@ libpolyp_la_SOURCES += \ polypcore/strbuf.c polypcore/strbuf.h \ polypcore/strlist.c polypcore/strlist.h \ polypcore/tagstruct.c polypcore/tagstruct.h \ - polypcore/util.c polypcore/util.h \ + polypcore/core-util.c polypcore/core-util.h \ polypcore/winsock.h \ - polypcore/llist.h + polypcore/llist.h \ + polypcore/pipe.c polypcore/pipe.h \ + polypcore/poll.c polypcore/poll.h if OS_IS_WIN32 libpolyp_la_SOURCES += \ @@ -487,7 +481,7 @@ polypcoreinclude_HEADERS = \ polypcore/source-output.h \ polypcore/strbuf.h \ polypcore/tokenizer.h \ - polypcore/util.h + polypcore/core-util.h lib_LTLIBRARIES += libpolypcore.la @@ -500,7 +494,8 @@ libpolypcore_la_SOURCES = \ polyp/sample.c polyp/sample.h \ polyp/volume.c polyp/volume.h \ polyp/utf8.c polyp/utf8.h \ - polyp/xmalloc.c polyp/xmalloc.h + polyp/xmalloc.c polyp/xmalloc.h \ + polyp/util.c polyp/util.h # Pure core stuff (some are shared in libpolyp though). libpolypcore_la_SOURCES += \ @@ -547,7 +542,7 @@ libpolypcore_la_SOURCES += \ polypcore/source-output.c polypcore/source-output.h \ polypcore/strbuf.c polypcore/strbuf.h \ polypcore/tokenizer.c polypcore/tokenizer.h \ - polypcore/util.c polypcore/util.h \ + polypcore/core-util.c polypcore/core-util.h \ polypcore/winsock.h if OS_IS_WIN32 diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 94de771c..e768e16a 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index b9d1ff87..654f3e49 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index b31fe56e..5047fc30 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index ea14e68f..2edbea5e 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include "module-detect-symdef.h" diff --git a/src/modules/module-esound-compat-spawnfd.c b/src/modules/module-esound-compat-spawnfd.c index 9b72448f..bf89ca70 100644 --- a/src/modules/module-esound-compat-spawnfd.c +++ b/src/modules/module-esound-compat-spawnfd.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include "module-esound-compat-spawnfd-symdef.h" diff --git a/src/modules/module-esound-compat-spawnpid.c b/src/modules/module-esound-compat-spawnpid.c index f8c07d31..895abec3 100644 --- a/src/modules/module-esound-compat-spawnpid.c +++ b/src/modules/module-esound-compat-spawnpid.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index 1d61e01b..cf3ce807 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index 1aa73495..96db837a 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index 29c46d85..3d783145 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/modules/module-match.c b/src/modules/module-match.c index 1692b5d8..c7ca12a5 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -35,12 +35,12 @@ #include #include -#include +#include #include #include #include #include -#include +#include #include "module-match-symdef.h" diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c index 654fbaa4..55f0b2c8 100644 --- a/src/modules/module-mmkbd-evdev.c +++ b/src/modules/module-mmkbd-evdev.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include "module-mmkbd-evdev-symdef.h" diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index 2cc49063..78850011 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index 82e7d66d..a1b40389 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 46d100f1..9233420d 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index b59808fc..6492ba6a 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index 4f3f9a6c..9f755440 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index 79a59cd5..cfe661a3 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index d82e3362..77eb4e49 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -48,7 +48,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index a2a1e33d..81c32287 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index ea40d862..e74567bc 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -35,12 +35,12 @@ #include #include -#include +#include #include #include #include #include -#include +#include #include #include "module-volume-restore-symdef.h" diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index 3d1f1b01..ce9ea84d 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include "module-waveout-symdef.h" diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c index e974487d..eddcb3b8 100644 --- a/src/modules/module-x11-publish.c +++ b/src/modules/module-x11-publish.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index e5dce755..5c5db286 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index 2c573b2f..a84276f1 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include "oss-util.h" diff --git a/src/polyp/util.c b/src/polyp/util.c new file mode 100644 index 00000000..dd597322 --- /dev/null +++ b/src/polyp/util.c @@ -0,0 +1,350 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_PWD_H +#include +#endif + +#ifdef HAVE_GRP_H +#include +#endif + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include +#include +#include + +#include "util.h" + +#ifndef OS_IS_WIN32 +#define PATH_SEP '/' +#else +#define PATH_SEP '\\' +#endif + +/* Return the current username in the specified string buffer. */ +char *pa_get_user_name(char *s, size_t l) { + char *p; + char buf[1024]; + +#ifdef HAVE_PWD_H + struct passwd pw, *r; +#endif + + assert(s && l > 0); + + if (!(p = getenv("USER")) && !(p = getenv("LOGNAME")) && !(p = getenv("USERNAME"))) { +#ifdef HAVE_PWD_H + +#ifdef HAVE_GETPWUID_R + if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { +#else + /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) + * that do not support getpwuid_r. */ + if ((r = getpwuid(getuid())) == NULL) { +#endif + snprintf(s, l, "%lu", (unsigned long) getuid()); + return s; + } + + p = r->pw_name; + +#elif defined(OS_IS_WIN32) /* HAVE_PWD_H */ + DWORD size = sizeof(buf); + + if (!GetUserName(buf, &size)) + return NULL; + + p = buf; + +#else /* HAVE_PWD_H */ + return NULL; +#endif /* HAVE_PWD_H */ + } + + return pa_strlcpy(s, p, l); +} + +/* Return the current hostname in the specified buffer. */ +char *pa_get_host_name(char *s, size_t l) { + assert(s && l > 0); + if (gethostname(s, l) < 0) { + pa_log(__FILE__": gethostname(): %s", strerror(errno)); + return NULL; + } + s[l-1] = 0; + return s; +} + +/* Return the home directory of the current user */ +char *pa_get_home_dir(char *s, size_t l) { + char *e; + +#ifdef HAVE_PWD_H + char buf[1024]; + struct passwd pw, *r; +#endif + + assert(s && l); + + if ((e = getenv("HOME"))) + return pa_strlcpy(s, e, l); + + if ((e = getenv("USERPROFILE"))) + return pa_strlcpy(s, e, l); + +#ifdef HAVE_PWD_H +#ifdef HAVE_GETPWUID_R + if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { + pa_log(__FILE__": getpwuid_r() failed"); +#else + /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) + * that do not support getpwuid_r. */ + if ((r = getpwuid(getuid())) == NULL) { + pa_log(__FILE__": getpwuid_r() failed"); +#endif + return NULL; + } + + return pa_strlcpy(s, r->pw_dir, l); +#else /* HAVE_PWD_H */ + return NULL; +#endif +} + +struct timeval *pa_gettimeofday(struct timeval *tv) { +#ifdef HAVE_GETTIMEOFDAY + assert(tv); + + return gettimeofday(tv, NULL) < 0 ? NULL : tv; +#elif defined(OS_IS_WIN32) + /* + * Copied from implementation by Steven Edwards (LGPL). + * Found on wine mailing list. + */ + +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define EPOCHFILETIME (116444736000000000i64) +#else +#define EPOCHFILETIME (116444736000000000LL) +#endif + + FILETIME ft; + LARGE_INTEGER li; + __int64 t; + + assert(tv); + + GetSystemTimeAsFileTime(&ft); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + t = li.QuadPart; /* In 100-nanosecond intervals */ + t -= EPOCHFILETIME; /* Offset to the Epoch time */ + t /= 10; /* In microseconds */ + tv->tv_sec = (long)(t / 1000000); + tv->tv_usec = (long)(t % 1000000); + + return tv; +#else +#error "Platform lacks gettimeofday() or equivalent function." +#endif +} + +/* Calculate the difference between the two specfified timeval + * timestamsps. */ +pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { + pa_usec_t r; + assert(a && b); + + /* Check which whan is the earlier time and swap the two arguments if reuqired. */ + if (pa_timeval_cmp(a, b) < 0) { + const struct timeval *c; + c = a; + a = b; + b = c; + } + + /* Calculate the second difference*/ + r = ((pa_usec_t) a->tv_sec - b->tv_sec)* 1000000; + + /* Calculate the microsecond difference */ + if (a->tv_usec > b->tv_usec) + r += ((pa_usec_t) a->tv_usec - b->tv_usec); + else if (a->tv_usec < b->tv_usec) + r -= ((pa_usec_t) b->tv_usec - a->tv_usec); + + return r; +} + +/* Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwse */ +int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { + assert(a && b); + + if (a->tv_sec < b->tv_sec) + return -1; + + if (a->tv_sec > b->tv_sec) + return 1; + + if (a->tv_usec < b->tv_usec) + return -1; + + if (a->tv_usec > b->tv_usec) + return 1; + + return 0; +} + +/* Return the time difference between now and the specified timestamp */ +pa_usec_t pa_timeval_age(const struct timeval *tv) { + struct timeval now; + assert(tv); + + return pa_timeval_diff(pa_gettimeofday(&now), tv); +} + +/* Add the specified time inmicroseconds to the specified timeval structure */ +void pa_timeval_add(struct timeval *tv, pa_usec_t v) { + unsigned long secs; + assert(tv); + + secs = (v/1000000); + tv->tv_sec += (unsigned long) secs; + v -= secs*1000000; + + tv->tv_usec += v; + + /* Normalize */ + while (tv->tv_usec >= 1000000) { + tv->tv_sec++; + tv->tv_usec -= 1000000; + } +} + +/* Return the binary file name of the current process. Works on Linux + * only. This shoul be used for eyecandy only, don't rely on return + * non-NULL! */ +char *pa_get_binary_name(char *s, size_t l) { + +#ifdef HAVE_READLINK + char path[PATH_MAX]; + int i; + assert(s && l); + + /* This works on Linux only */ + + snprintf(path, sizeof(path), "/proc/%u/exe", (unsigned) getpid()); + if ((i = readlink(path, s, l-1)) < 0) + return NULL; + + s[i] = 0; + return s; +#elif defined(OS_IS_WIN32) + char path[PATH_MAX]; + if (!GetModuleFileName(NULL, path, PATH_MAX)) + return NULL; + pa_strlcpy(s, pa_path_get_filename(path), l); + return s; +#else + return NULL; +#endif +} + +/* Return a pointer to the filename inside a path (which is the last + * component). */ +const char *pa_path_get_filename(const char *p) { + char *fn; + + if ((fn = strrchr(p, PATH_SEP))) + return fn+1; + + return (const char*) p; +} + +/* Return the fully qualified domain name in *s */ +char *pa_get_fqdn(char *s, size_t l) { + char hn[256]; +#ifdef HAVE_GETADDRINFO + struct addrinfo *a, hints; +#endif + + if (!pa_get_host_name(hn, sizeof(hn))) + return NULL; + +#ifdef HAVE_GETADDRINFO + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_CANONNAME; + + if (getaddrinfo(hn, NULL, &hints, &a) < 0 || !a || !a->ai_canonname || !*a->ai_canonname) + return pa_strlcpy(s, hn, l); + + pa_strlcpy(s, a->ai_canonname, l); + freeaddrinfo(a); + return s; +#else + return pa_strlcpy(s, hn, l); +#endif +} + +/* Wait t milliseconds */ +int pa_msleep(unsigned long t) { +#ifdef OS_IS_WIN32 + Sleep(t); + return 0; +#elif defined(HAVE_NANOSLEEP) + struct timespec ts; + + ts.tv_sec = t/1000; + ts.tv_nsec = (t % 1000) * 1000000; + + return nanosleep(&ts, NULL); +#else +#error "Platform lacks a sleep function." +#endif +} diff --git a/src/polyp/util.h b/src/polyp/util.h new file mode 100644 index 00000000..37232d9f --- /dev/null +++ b/src/polyp/util.h @@ -0,0 +1,48 @@ +#ifndef fooutilhfoo +#define fooutilhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include + +struct timeval; + +char *pa_get_user_name(char *s, size_t l); +char *pa_get_host_name(char *s, size_t l); +char *pa_get_fqdn(char *s, size_t l); +char *pa_get_home_dir(char *s, size_t l); + +char *pa_get_binary_name(char *s, size_t l); +const char *pa_path_get_filename(const char *p); + +struct timeval *pa_gettimeofday(struct timeval *tv); +pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); +int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); +pa_usec_t pa_timeval_age(const struct timeval *tv); +void pa_timeval_add(struct timeval *tv, pa_usec_t v); + +int pa_msleep(unsigned long t); + +#endif diff --git a/src/polypcore/authkey.c b/src/polypcore/authkey.c index 6eafb672..1231c7a2 100644 --- a/src/polypcore/authkey.c +++ b/src/polypcore/authkey.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include diff --git a/src/polypcore/cli-command.c b/src/polypcore/cli-command.c index 5556bcb3..3adc9a21 100644 --- a/src/polypcore/cli-command.c +++ b/src/polypcore/cli-command.c @@ -48,7 +48,7 @@ #include #include #include -#include +#include #include "cli-command.h" diff --git a/src/polypcore/conf-parser.c b/src/polypcore/conf-parser.c index 64e66c2e..bc99b871 100644 --- a/src/polypcore/conf-parser.c +++ b/src/polypcore/conf-parser.c @@ -31,7 +31,7 @@ #include #include -#include +#include #include "conf-parser.h" diff --git a/src/polypcore/core-scache.c b/src/polypcore/core-scache.c index 8080fcd6..068f2361 100644 --- a/src/polypcore/core-scache.c +++ b/src/polypcore/core-scache.c @@ -52,7 +52,7 @@ #include #include #include -#include +#include #include #include "core-scache.h" diff --git a/src/polypcore/core-util.c b/src/polypcore/core-util.c new file mode 100644 index 00000000..36044c81 --- /dev/null +++ b/src/polypcore/core-util.c @@ -0,0 +1,1012 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SCHED_H +#include +#endif + +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif + +#ifdef HAVE_PTHREAD +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#ifdef HAVE_PWD_H +#include +#endif + +#ifdef HAVE_GRP_H +#include +#endif + +#include + +#include +#include + +#include +#include + +#include "core-util.h" + +#ifndef OS_IS_WIN32 +#define PA_RUNTIME_PATH_PREFIX "/tmp/polypaudio-" +#define PATH_SEP '/' +#else +#define PA_RUNTIME_PATH_PREFIX "%TEMP%\\polypaudio-" +#define PATH_SEP '\\' +#endif + +#ifdef OS_IS_WIN32 + +#define POLYP_ROOTENV "POLYP_ROOT" + +int pa_set_root(HANDLE handle) { + char library_path[MAX_PATH + sizeof(POLYP_ROOTENV) + 1], *sep; + + strcpy(library_path, POLYP_ROOTENV "="); + + if (!GetModuleFileName(handle, library_path + sizeof(POLYP_ROOTENV), MAX_PATH)) + return 0; + + sep = strrchr(library_path, '\\'); + if (sep) + *sep = '\0'; + + if (_putenv(library_path) < 0) + return 0; + + return 1; +} + +#endif + +/** Make a file descriptor nonblock. Doesn't do any error checking */ +void pa_make_nonblock_fd(int fd) { +#ifdef O_NONBLOCK + int v; + assert(fd >= 0); + + if ((v = fcntl(fd, F_GETFL)) >= 0) + if (!(v & O_NONBLOCK)) + fcntl(fd, F_SETFL, v|O_NONBLOCK); +#elif defined(OS_IS_WIN32) + u_long arg = 1; + if (ioctlsocket(fd, FIONBIO, &arg) < 0) { + if (WSAGetLastError() == WSAENOTSOCK) + pa_log_warn(__FILE__": WARNING: Only sockets can be made non-blocking!"); + } +#else + pa_log_warn(__FILE__": WARNING: Non-blocking I/O not supported.!"); +#endif +} + +/** Creates a directory securely */ +int pa_make_secure_dir(const char* dir) { + struct stat st; + assert(dir); + +#ifdef OS_IS_WIN32 + if (mkdir(dir) < 0) +#else + if (mkdir(dir, 0700) < 0) +#endif + if (errno != EEXIST) + return -1; + +#ifdef HAVE_CHOWN + chown(dir, getuid(), getgid()); +#endif +#ifdef HAVE_CHMOD + chmod(dir, 0700); +#endif + +#ifdef HAVE_LSTAT + if (lstat(dir, &st) < 0) +#else + if (stat(dir, &st) < 0) +#endif + goto fail; + +#ifndef OS_IS_WIN32 + if (!S_ISDIR(st.st_mode) || (st.st_uid != getuid()) || ((st.st_mode & 0777) != 0700)) + goto fail; +#else + fprintf(stderr, "FIXME: pa_make_secure_dir()\n"); +#endif + + return 0; + +fail: + rmdir(dir); + return -1; +} + +/* Return a newly allocated sting containing the parent directory of the specified file */ +char *pa_parent_dir(const char *fn) { + char *slash, *dir = pa_xstrdup(fn); + + slash = (char*) pa_path_get_filename(dir); + if (slash == fn) + return NULL; + + *(slash-1) = 0; + return dir; +} + +/* Creates a the parent directory of the specified path securely */ +int pa_make_secure_parent_dir(const char *fn) { + int ret = -1; + char *dir; + + if (!(dir = pa_parent_dir(fn))) + goto finish; + + if (pa_make_secure_dir(dir) < 0) + goto finish; + + ret = 0; + +finish: + pa_xfree(dir); + return ret; +} + +/** Platform independent read function. Necessary since not all systems + * treat all file descriptors equal. */ +ssize_t pa_read(int fd, void *buf, size_t count) { + ssize_t r; + +#ifdef OS_IS_WIN32 + r = recv(fd, buf, count, 0); + if (r < 0) { + if (WSAGetLastError() != WSAENOTSOCK) { + errno = WSAGetLastError(); + return r; + } + } + + if (r < 0) +#endif + r = read(fd, buf, count); + + return r; +} + +/** Similar to pa_read(), but handles writes */ +ssize_t pa_write(int fd, const void *buf, size_t count) { + ssize_t r; + +#ifdef OS_IS_WIN32 + r = send(fd, buf, count, 0); + if (r < 0) { + if (WSAGetLastError() != WSAENOTSOCK) { + errno = WSAGetLastError(); + return r; + } + } + + if (r < 0) +#endif + r = write(fd, buf, count); + + return r; +} + +/** Calls read() in a loop. Makes sure that as much as 'size' bytes, + * unless EOF is reached or an error occured */ +ssize_t pa_loop_read(int fd, void*data, size_t size) { + ssize_t ret = 0; + assert(fd >= 0 && data && size); + + while (size > 0) { + ssize_t r; + + if ((r = pa_read(fd, data, size)) < 0) + return r; + + if (r == 0) + break; + + ret += r; + data = (uint8_t*) data + r; + size -= r; + } + + return ret; +} + +/** Similar to pa_loop_read(), but wraps write() */ +ssize_t pa_loop_write(int fd, const void*data, size_t size) { + ssize_t ret = 0; + assert(fd >= 0 && data && size); + + while (size > 0) { + ssize_t r; + + if ((r = pa_write(fd, data, size)) < 0) + return r; + + if (r == 0) + break; + + ret += r; + data = (const uint8_t*) data + r; + size -= r; + } + + return ret; +} + +/* Print a warning messages in case that the given signal is not + * blocked or trapped */ +void pa_check_signal_is_blocked(int sig) { +#ifdef HAVE_SIGACTION + struct sigaction sa; + sigset_t set; + + /* If POSIX threads are supported use thread-aware + * pthread_sigmask() function, to check if the signal is + * blocked. Otherwise fall back to sigprocmask() */ + +#ifdef HAVE_PTHREAD + if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) { +#endif + if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) { + pa_log(__FILE__": sigprocmask() failed: %s", strerror(errno)); + return; + } +#ifdef HAVE_PTHREAD + } +#endif + + if (sigismember(&set, sig)) + return; + + /* Check whether the signal is trapped */ + + if (sigaction(sig, NULL, &sa) < 0) { + pa_log(__FILE__": sigaction() failed: %s", strerror(errno)); + return; + } + + if (sa.sa_handler != SIG_DFL) + return; + + pa_log(__FILE__": WARNING: %s is not trapped. This might cause malfunction!", pa_strsignal(sig)); +#else /* HAVE_SIGACTION */ + pa_log(__FILE__": WARNING: %s might not be trapped. This might cause malfunction!", pa_strsignal(sig)); +#endif +} + +/* The following function is based on an example from the GNU libc + * documentation. This function is similar to GNU's asprintf(). */ +char *pa_sprintf_malloc(const char *format, ...) { + int size = 100; + char *c = NULL; + + assert(format); + + for(;;) { + int r; + va_list ap; + + c = pa_xrealloc(c, size); + + va_start(ap, format); + r = vsnprintf(c, size, format, ap); + va_end(ap); + + if (r > -1 && r < size) + return c; + + if (r > -1) /* glibc 2.1 */ + size = r+1; + else /* glibc 2.0 */ + size *= 2; + } +} + +/* Same as the previous function, but use a va_list instead of an + * ellipsis */ +char *pa_vsprintf_malloc(const char *format, va_list ap) { + int size = 100; + char *c = NULL; + + assert(format); + + for(;;) { + int r; + c = pa_xrealloc(c, size); + r = vsnprintf(c, size, format, ap); + + if (r > -1 && r < size) + return c; + + if (r > -1) /* glibc 2.1 */ + size = r+1; + else /* glibc 2.0 */ + size *= 2; + } +} + +/* Similar to OpenBSD's strlcpy() function */ +char *pa_strlcpy(char *b, const char *s, size_t l) { + assert(b && s && l > 0); + + strncpy(b, s, l); + b[l-1] = 0; + return b; +} + +#define NICE_LEVEL (-15) + +/* Raise the priority of the current process as much as possible and +sensible: set the nice level to -15 and enable realtime scheduling if +supported.*/ +void pa_raise_priority(void) { + +#ifdef HAVE_SYS_RESOURCE_H + if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) + pa_log_warn(__FILE__": setpriority() failed: %s", strerror(errno)); + else + pa_log_info(__FILE__": Successfully gained nice level %i.", NICE_LEVEL); +#endif + +#ifdef _POSIX_PRIORITY_SCHEDULING + { + struct sched_param sp; + + if (sched_getparam(0, &sp) < 0) { + pa_log(__FILE__": sched_getparam() failed: %s", strerror(errno)); + return; + } + + sp.sched_priority = 1; + if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) { + pa_log_warn(__FILE__": sched_setscheduler() failed: %s", strerror(errno)); + return; + } + + pa_log_info(__FILE__": Successfully enabled SCHED_FIFO scheduling."); + } +#endif + +#ifdef OS_IS_WIN32 + if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) + pa_log_warn(__FILE__": SetPriorityClass() failed: 0x%08X", GetLastError()); + else + pa_log_info(__FILE__": Successfully gained high priority class."); +#endif +} + +/* Reset the priority to normal, inverting the changes made by pa_raise_priority() */ +void pa_reset_priority(void) { +#ifdef OS_IS_WIN32 + SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); +#endif + +#ifdef _POSIX_PRIORITY_SCHEDULING + { + struct sched_param sp; + sched_getparam(0, &sp); + sp.sched_priority = 0; + sched_setscheduler(0, SCHED_OTHER, &sp); + } +#endif + +#ifdef HAVE_SYS_RESOURCE_H + setpriority(PRIO_PROCESS, 0, 0); +#endif +} + +/* Set the FD_CLOEXEC flag for a fd */ +int pa_fd_set_cloexec(int fd, int b) { + +#ifdef FD_CLOEXEC + int v; + assert(fd >= 0); + + if ((v = fcntl(fd, F_GETFD, 0)) < 0) + return -1; + + v = (v & ~FD_CLOEXEC) | (b ? FD_CLOEXEC : 0); + + if (fcntl(fd, F_SETFD, v) < 0) + return -1; +#endif + + return 0; +} + +/* Try to parse a boolean string value.*/ +int pa_parse_boolean(const char *v) { + + if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on")) + return 1; + else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off")) + return 0; + + return -1; +} + +/* Split the specified string wherever one of the strings in delimiter + * occurs. Each time it is called returns a newly allocated string + * with pa_xmalloc(). The variable state points to, should be + * initiallized to NULL before the first call. */ +char *pa_split(const char *c, const char *delimiter, const char**state) { + const char *current = *state ? *state : c; + size_t l; + + if (!*current) + return NULL; + + l = strcspn(current, delimiter); + *state = current+l; + + if (**state) + (*state)++; + + return pa_xstrndup(current, l); +} + +/* What is interpreted as whitespace? */ +#define WHITESPACE " \t\n" + +/* Split a string into words. Otherwise similar to pa_split(). */ +char *pa_split_spaces(const char *c, const char **state) { + const char *current = *state ? *state : c; + size_t l; + + if (!*current || *c == 0) + return NULL; + + current += strspn(current, WHITESPACE); + l = strcspn(current, WHITESPACE); + + *state = current+l; + + return pa_xstrndup(current, l); +} + +/* Return the name of an UNIX signal. Similar to GNU's strsignal() */ +const char *pa_strsignal(int sig) { + switch(sig) { + case SIGINT: return "SIGINT"; + case SIGTERM: return "SIGTERM"; +#ifdef SIGUSR1 + case SIGUSR1: return "SIGUSR1"; +#endif +#ifdef SIGUSR2 + case SIGUSR2: return "SIGUSR2"; +#endif +#ifdef SIGXCPU + case SIGXCPU: return "SIGXCPU"; +#endif +#ifdef SIGPIPE + case SIGPIPE: return "SIGPIPE"; +#endif +#ifdef SIGCHLD + case SIGCHLD: return "SIGCHLD"; +#endif +#ifdef SIGHUP + case SIGHUP: return "SIGHUP"; +#endif + default: return "UNKNOWN SIGNAL"; + } +} + +#ifdef HAVE_GRP_H + +/* Check whether the specified GID and the group name match */ +static int is_group(gid_t gid, const char *name) { + struct group group, *result = NULL; + long n; + void *data; + int r = -1; + +#ifdef HAVE_GETGRGID_R +#ifdef _SC_GETGR_R_SIZE_MAX + n = sysconf(_SC_GETGR_R_SIZE_MAX); +#else + n = -1; +#endif + if (n < 0) n = 512; + data = pa_xmalloc(n); + + if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) { + pa_log(__FILE__ ": getgrgid_r(%u) failed: %s", gid, strerror(errno)); + goto finish; + } + + r = strcmp(name, result->gr_name) == 0; + +finish: + pa_xfree(data); +#else + /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not + * support getgrgid_r. */ + if ((result = getgrgid(gid)) == NULL) { + pa_log(__FILE__ ": getgrgid(%u) failed: %s", gid, strerror(errno)); + goto finish; + } + + r = strcmp(name, result->gr_name) == 0; + +finish: +#endif + + return r; +} + +/* Check the current user is member of the specified group */ +int pa_own_uid_in_group(const char *name, gid_t *gid) { + GETGROUPS_T *gids, tgid; + int n = sysconf(_SC_NGROUPS_MAX); + int r = -1, i; + + assert(n > 0); + + gids = pa_xmalloc(sizeof(GETGROUPS_T)*n); + + if ((n = getgroups(n, gids)) < 0) { + pa_log(__FILE__": getgroups() failed: %s", strerror(errno)); + goto finish; + } + + for (i = 0; i < n; i++) { + if (is_group(gids[i], name) > 0) { + *gid = gids[i]; + r = 1; + goto finish; + } + } + + if (is_group(tgid = getgid(), name) > 0) { + *gid = tgid; + r = 1; + goto finish; + } + + r = 0; + +finish: + + pa_xfree(gids); + return r; +} + +int pa_uid_in_group(uid_t uid, const char *name) { + char *g_buf, *p_buf; + long g_n, p_n; + struct group grbuf, *gr; + char **i; + int r = -1; + + g_n = sysconf(_SC_GETGR_R_SIZE_MAX); + g_buf = pa_xmalloc(g_n); + + p_n = sysconf(_SC_GETPW_R_SIZE_MAX); + p_buf = pa_xmalloc(p_n); + + if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) + goto finish; + + r = 0; + for (i = gr->gr_mem; *i; i++) { + struct passwd pwbuf, *pw; + + if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw) + continue; + + if (pw->pw_uid == uid) { + r = 1; + break; + } + } + +finish: + pa_xfree(g_buf); + pa_xfree(p_buf); + + return r; +} + +#else /* HAVE_GRP_H */ + +int pa_own_uid_in_group(const char *name, gid_t *gid) { + return -1; + +} + +int pa_uid_in_group(uid_t uid, const char *name) { + return -1; +} + +#endif + +/* Lock or unlock a file entirely. + (advisory on UNIX, mandatory on Windows) */ +int pa_lock_fd(int fd, int b) { +#ifdef F_SETLKW + struct flock flock; + + /* Try a R/W lock first */ + + flock.l_type = b ? F_WRLCK : F_UNLCK; + flock.l_whence = SEEK_SET; + flock.l_start = 0; + flock.l_len = 0; + + if (fcntl(fd, F_SETLKW, &flock) >= 0) + return 0; + + /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */ + if (b && errno == EBADF) { + flock.l_type = F_RDLCK; + if (fcntl(fd, F_SETLKW, &flock) >= 0) + return 0; + } + + pa_log(__FILE__": %slock failed: %s", !b ? "un" : "", strerror(errno)); +#endif + +#ifdef OS_IS_WIN32 + HANDLE h = (HANDLE)_get_osfhandle(fd); + + if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) + return 0; + if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) + return 0; + + pa_log(__FILE__": %slock failed: 0x%08X", !b ? "un" : "", GetLastError()); +#endif + + return -1; +} + +/* Remove trailing newlines from a string */ +char* pa_strip_nl(char *s) { + assert(s); + + s[strcspn(s, "\r\n")] = 0; + return s; +} + +/* Create a temporary lock file and lock it. */ +int pa_lock_lockfile(const char *fn) { + int fd = -1; + assert(fn); + + for (;;) { + struct stat st; + + if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { + pa_log(__FILE__": failed to create lock file '%s': %s", fn, strerror(errno)); + goto fail; + } + + if (pa_lock_fd(fd, 1) < 0) { + pa_log(__FILE__": failed to lock file '%s'.", fn); + goto fail; + } + + if (fstat(fd, &st) < 0) { + pa_log(__FILE__": failed to fstat() file '%s'.", fn); + goto fail; + } + + /* Check wheter the file has been removed meanwhile. When yes, restart this loop, otherwise, we're done */ + if (st.st_nlink >= 1) + break; + + if (pa_lock_fd(fd, 0) < 0) { + pa_log(__FILE__": failed to unlock file '%s'.", fn); + goto fail; + } + + if (close(fd) < 0) { + pa_log(__FILE__": failed to close file '%s'.", fn); + goto fail; + } + + fd = -1; + } + + return fd; + +fail: + + if (fd >= 0) + close(fd); + + return -1; +} + +/* Unlock a temporary lcok file */ +int pa_unlock_lockfile(const char *fn, int fd) { + int r = 0; + assert(fn && fd >= 0); + + if (unlink(fn) < 0) { + pa_log_warn(__FILE__": WARNING: unable to remove lock file '%s': %s", fn, strerror(errno)); + r = -1; + } + + if (pa_lock_fd(fd, 0) < 0) { + pa_log_warn(__FILE__": WARNING: failed to unlock file '%s'.", fn); + r = -1; + } + + if (close(fd) < 0) { + pa_log_warn(__FILE__": WARNING: failed to close lock file '%s': %s", fn, strerror(errno)); + r = -1; + } + + return r; +} + +/* Try to open a configuration file. If "env" is specified, open the + * value of the specified environment variable. Otherwise look for a + * file "local" in the home directory or a file "global" in global + * file system. If "result" is non-NULL, a pointer to a newly + * allocated buffer containing the used configuration file is + * stored there.*/ +FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode) { + const char *fn; + char h[PATH_MAX]; + +#ifdef OS_IS_WIN32 + char buf[PATH_MAX]; + + if (!getenv(POLYP_ROOTENV)) + pa_set_root(NULL); +#endif + + if (env && (fn = getenv(env))) { +#ifdef OS_IS_WIN32 + if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX)) + return NULL; + fn = buf; +#endif + + if (result) + *result = pa_xstrdup(fn); + + return fopen(fn, mode); + } + + if (local && pa_get_home_dir(h, sizeof(h))) { + FILE *f; + char *lfn; + + fn = lfn = pa_sprintf_malloc("%s/%s", h, local); + +#ifdef OS_IS_WIN32 + if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) + return NULL; + fn = buf; +#endif + + f = fopen(fn, mode); + + if (f || errno != ENOENT) { + if (result) + *result = pa_xstrdup(fn); + pa_xfree(lfn); + return f; + } + + pa_xfree(lfn); + } + + if (!global) { + if (result) + *result = NULL; + errno = ENOENT; + return NULL; + } + +#ifdef OS_IS_WIN32 + if (!ExpandEnvironmentStrings(global, buf, PATH_MAX)) + return NULL; + global = buf; +#endif + + if (result) + *result = pa_xstrdup(global); + + return fopen(global, mode); +} + +/* Format the specified data as a hexademical string */ +char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) { + size_t i = 0, j = 0; + const char hex[] = "0123456789abcdef"; + assert(d && s && slength > 0); + + while (i < dlength && j+3 <= slength) { + s[j++] = hex[*d >> 4]; + s[j++] = hex[*d & 0xF]; + + d++; + i++; + } + + s[j < slength ? j : slength] = 0; + return s; +} + +/* Convert a hexadecimal digit to a number or -1 if invalid */ +static int hexc(char c) { + if (c >= '0' && c <= '9') + return c - '0'; + + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + + return -1; +} + +/* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */ +size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) { + size_t j = 0; + assert(p && d); + + while (j < dlength && *p) { + int b; + + if ((b = hexc(*(p++))) < 0) + return (size_t) -1; + + d[j] = (uint8_t) (b << 4); + + if (!*p) + return (size_t) -1; + + if ((b = hexc(*(p++))) < 0) + return (size_t) -1; + + d[j] |= (uint8_t) b; + j++; + } + + return j; +} + +/* Returns nonzero when *s starts with *pfx */ +int pa_startswith(const char *s, const char *pfx) { + size_t l; + + assert(s); + assert(pfx); + + l = strlen(pfx); + + return strlen(s) >= l && strncmp(s, pfx, l) == 0; +} + +/* Returns nonzero when *s ends with *sfx */ +int pa_endswith(const char *s, const char *sfx) { + size_t l1, l2; + + assert(s); + assert(sfx); + + l1 = strlen(s); + l2 = strlen(sfx); + + return l1 >= l2 && strcmp(s+l1-l2, sfx) == 0; +} + +/* if fn is null return the polypaudio run time path in s (/tmp/polypaudio) + * if fn is non-null and starts with / return fn in s + * otherwise append fn to the run time path and return it in s */ +char *pa_runtime_path(const char *fn, char *s, size_t l) { + char u[256]; + +#ifndef OS_IS_WIN32 + if (fn && *fn == '/') +#else + if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\') +#endif + return pa_strlcpy(s, fn, l); + + if (fn) + snprintf(s, l, "%s%s%c%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn); + else + snprintf(s, l, "%s%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u))); + +#ifdef OS_IS_WIN32 + { + char buf[l]; + strcpy(buf, s); + ExpandEnvironmentStrings(buf, s, l); + } +#endif + + return s; +} + +/* Convert the string s to a signed integer in *ret_i */ +int pa_atoi(const char *s, int32_t *ret_i) { + char *x = NULL; + long l; + assert(s && ret_i); + + l = strtol(s, &x, 0); + + if (!x || *x) + return -1; + + *ret_i = (int32_t) l; + + return 0; +} + +/* Convert the string s to an unsigned integer in *ret_u */ +int pa_atou(const char *s, uint32_t *ret_u) { + char *x = NULL; + unsigned long l; + assert(s && ret_u); + + l = strtoul(s, &x, 0); + + if (!x || *x) + return -1; + + *ret_u = (uint32_t) l; + + return 0; +} diff --git a/src/polypcore/core-util.h b/src/polypcore/core-util.h new file mode 100644 index 00000000..d3db756f --- /dev/null +++ b/src/polypcore/core-util.h @@ -0,0 +1,89 @@ +#ifndef foocoreutilhfoo +#define foocoreutilhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +#include +#include + +struct timeval; + +void pa_make_nonblock_fd(int fd); + +int pa_make_secure_dir(const char* dir); +int pa_make_secure_parent_dir(const char *fn); + +ssize_t pa_read(int fd, void *buf, size_t count); +ssize_t pa_write(int fd, const void *buf, size_t count); +ssize_t pa_loop_read(int fd, void*data, size_t size); +ssize_t pa_loop_write(int fd, const void*data, size_t size); + +void pa_check_signal_is_blocked(int sig); + +char *pa_sprintf_malloc(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +char *pa_vsprintf_malloc(const char *format, va_list ap); + +char *pa_strlcpy(char *b, const char *s, size_t l); + +char *pa_parent_dir(const char *fn); + +void pa_raise_priority(void); +void pa_reset_priority(void); + +int pa_fd_set_cloexec(int fd, int b); + +int pa_parse_boolean(const char *s); + +char *pa_split(const char *c, const char*delimiters, const char **state); +char *pa_split_spaces(const char *c, const char **state); + +char *pa_strip_nl(char *s); + +const char *pa_strsignal(int sig); + +int pa_own_uid_in_group(const char *name, gid_t *gid); +int pa_uid_in_group(uid_t uid, const char *name); + +int pa_lock_fd(int fd, int b); + +int pa_lock_lockfile(const char *fn); +int pa_unlock_lockfile(const char *fn, int fd); + +FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode); + +char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength); +size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength); + +int pa_startswith(const char *s, const char *pfx); +int pa_endswith(const char *s, const char *sfx); + +char *pa_runtime_path(const char *fn, char *s, size_t l); + +int pa_atoi(const char *s, int32_t *ret_i); +int pa_atou(const char *s, uint32_t *ret_u); + +#endif diff --git a/src/polypcore/core.c b/src/polypcore/core.c index ff8ec081..43f7015e 100644 --- a/src/polypcore/core.c +++ b/src/polypcore/core.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/polypcore/iochannel.c b/src/polypcore/iochannel.c index a1ad5dea..b953a1d0 100644 --- a/src/polypcore/iochannel.c +++ b/src/polypcore/iochannel.c @@ -40,7 +40,7 @@ #include -#include +#include #include #include diff --git a/src/polypcore/log.c b/src/polypcore/log.c index 9908d168..3f5dfa08 100644 --- a/src/polypcore/log.c +++ b/src/polypcore/log.c @@ -35,7 +35,7 @@ #include -#include +#include #include "log.h" diff --git a/src/polypcore/modargs.c b/src/polypcore/modargs.c index 63cc779d..5d046d26 100644 --- a/src/polypcore/modargs.c +++ b/src/polypcore/modargs.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include "modargs.h" diff --git a/src/polypcore/modinfo.c b/src/polypcore/modinfo.c index 241076c6..4a9be0f0 100644 --- a/src/polypcore/modinfo.c +++ b/src/polypcore/modinfo.c @@ -28,7 +28,7 @@ #include -#include +#include #include #include "modinfo.h" diff --git a/src/polypcore/module.c b/src/polypcore/module.c index fe177a5b..52cde9c3 100644 --- a/src/polypcore/module.c +++ b/src/polypcore/module.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include "module.h" diff --git a/src/polypcore/namereg.c b/src/polypcore/namereg.c index cf11f5a4..17d75146 100644 --- a/src/polypcore/namereg.c +++ b/src/polypcore/namereg.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include "namereg.h" diff --git a/src/polypcore/parseaddr.c b/src/polypcore/parseaddr.c index 7e518a5d..b2c7d1c7 100644 --- a/src/polypcore/parseaddr.c +++ b/src/polypcore/parseaddr.c @@ -29,7 +29,7 @@ #include -#include +#include #include "parseaddr.h" diff --git a/src/polypcore/pdispatch.c b/src/polypcore/pdispatch.c index 21e3644e..4b0d1bb2 100644 --- a/src/polypcore/pdispatch.c +++ b/src/polypcore/pdispatch.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include "pdispatch.h" diff --git a/src/polypcore/pid.c b/src/polypcore/pid.c index 53b8ad0a..e98dc97b 100644 --- a/src/polypcore/pid.c +++ b/src/polypcore/pid.c @@ -41,7 +41,7 @@ #include -#include +#include #include #include "pid.h" diff --git a/src/polypcore/poll.c b/src/polypcore/poll.c index 6a29a953..7b1ed438 100644 --- a/src/polypcore/poll.c +++ b/src/polypcore/poll.c @@ -42,7 +42,7 @@ #ifndef HAVE_SYS_POLL_H -#include +#include #include "poll.h" diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index 8f53694e..98738728 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include "endianmacros.h" diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 338db002..f0e50ec5 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/polypcore/random.c b/src/polypcore/random.c index 1221206f..4bfce975 100644 --- a/src/polypcore/random.c +++ b/src/polypcore/random.c @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include "random.h" diff --git a/src/polypcore/sink.c b/src/polypcore/sink.c index 6931d396..dc27ca2e 100644 --- a/src/polypcore/sink.c +++ b/src/polypcore/sink.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/polypcore/socket-client.c b/src/polypcore/socket-client.c index a61cf582..4fb0a5d8 100644 --- a/src/polypcore/socket-client.c +++ b/src/polypcore/socket-client.c @@ -57,7 +57,7 @@ #include #include -#include +#include #include #include diff --git a/src/polypcore/socket-server.c b/src/polypcore/socket-server.c index 959173f2..96f8e073 100644 --- a/src/polypcore/socket-server.c +++ b/src/polypcore/socket-server.c @@ -65,7 +65,7 @@ #include #include -#include +#include #include #include "socket-server.h" diff --git a/src/polypcore/socket-util.c b/src/polypcore/socket-util.c index 0961db21..acbb7c1f 100644 --- a/src/polypcore/socket-util.c +++ b/src/polypcore/socket-util.c @@ -61,7 +61,7 @@ #include -#include +#include #include #include "socket-util.h" diff --git a/src/polypcore/strlist.c b/src/polypcore/strlist.c index 4d70e9e9..b9420749 100644 --- a/src/polypcore/strlist.c +++ b/src/polypcore/strlist.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include "strlist.h" diff --git a/src/polypcore/util.c b/src/polypcore/util.c deleted file mode 100644 index 9783b746..00000000 --- a/src/polypcore/util.c +++ /dev/null @@ -1,1293 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SCHED_H -#include -#endif - -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif - -#ifdef HAVE_PTHREAD -#include -#endif - -#ifdef HAVE_NETDB_H -#include -#endif - -#ifdef HAVE_WINDOWS_H -#include -#endif - -#include - -#ifdef HAVE_PWD_H -#include -#endif -#ifdef HAVE_GRP_H -#include -#endif - -#include "winsock.h" - -#include - -#include - -#include "util.h" - -#ifndef OS_IS_WIN32 -#define PA_RUNTIME_PATH_PREFIX "/tmp/polypaudio-" -#define PATH_SEP '/' -#else -#define PA_RUNTIME_PATH_PREFIX "%TEMP%\\polypaudio-" -#define PATH_SEP '\\' -#endif - -#ifdef OS_IS_WIN32 - -#define POLYP_ROOTENV "POLYP_ROOT" - -int pa_set_root(HANDLE handle) { - char library_path[MAX_PATH + sizeof(POLYP_ROOTENV) + 1], *sep; - - strcpy(library_path, POLYP_ROOTENV "="); - - if (!GetModuleFileName(handle, library_path + sizeof(POLYP_ROOTENV), MAX_PATH)) - return 0; - - sep = strrchr(library_path, '\\'); - if (sep) - *sep = '\0'; - - if (_putenv(library_path) < 0) - return 0; - - return 1; -} - -#endif - -/** Make a file descriptor nonblock. Doesn't do any error checking */ -void pa_make_nonblock_fd(int fd) { -#ifdef O_NONBLOCK - int v; - assert(fd >= 0); - - if ((v = fcntl(fd, F_GETFL)) >= 0) - if (!(v & O_NONBLOCK)) - fcntl(fd, F_SETFL, v|O_NONBLOCK); -#elif defined(OS_IS_WIN32) - u_long arg = 1; - if (ioctlsocket(fd, FIONBIO, &arg) < 0) { - if (WSAGetLastError() == WSAENOTSOCK) - pa_log_warn(__FILE__": WARNING: Only sockets can be made non-blocking!"); - } -#else - pa_log_warn(__FILE__": WARNING: Non-blocking I/O not supported.!"); -#endif -} - -/** Creates a directory securely */ -int pa_make_secure_dir(const char* dir) { - struct stat st; - assert(dir); - -#ifdef OS_IS_WIN32 - if (mkdir(dir) < 0) -#else - if (mkdir(dir, 0700) < 0) -#endif - if (errno != EEXIST) - return -1; - -#ifdef HAVE_CHOWN - chown(dir, getuid(), getgid()); -#endif -#ifdef HAVE_CHMOD - chmod(dir, 0700); -#endif - -#ifdef HAVE_LSTAT - if (lstat(dir, &st) < 0) -#else - if (stat(dir, &st) < 0) -#endif - goto fail; - -#ifndef OS_IS_WIN32 - if (!S_ISDIR(st.st_mode) || (st.st_uid != getuid()) || ((st.st_mode & 0777) != 0700)) - goto fail; -#else - fprintf(stderr, "FIXME: pa_make_secure_dir()\n"); -#endif - - return 0; - -fail: - rmdir(dir); - return -1; -} - -/* Return a newly allocated sting containing the parent directory of the specified file */ -char *pa_parent_dir(const char *fn) { - char *slash, *dir = pa_xstrdup(fn); - - slash = (char*) pa_path_get_filename(dir); - if (slash == fn) - return NULL; - - *(slash-1) = 0; - return dir; -} - -/* Creates a the parent directory of the specified path securely */ -int pa_make_secure_parent_dir(const char *fn) { - int ret = -1; - char *dir; - - if (!(dir = pa_parent_dir(fn))) - goto finish; - - if (pa_make_secure_dir(dir) < 0) - goto finish; - - ret = 0; - -finish: - pa_xfree(dir); - return ret; -} - -/** Platform independent read function. Necessary since not all systems - * treat all file descriptors equal. */ -ssize_t pa_read(int fd, void *buf, size_t count) { - ssize_t r; - -#ifdef OS_IS_WIN32 - r = recv(fd, buf, count, 0); - if (r < 0) { - if (WSAGetLastError() != WSAENOTSOCK) { - errno = WSAGetLastError(); - return r; - } - } - - if (r < 0) -#endif - r = read(fd, buf, count); - - return r; -} - -/** Similar to pa_read(), but handles writes */ -ssize_t pa_write(int fd, const void *buf, size_t count) { - ssize_t r; - -#ifdef OS_IS_WIN32 - r = send(fd, buf, count, 0); - if (r < 0) { - if (WSAGetLastError() != WSAENOTSOCK) { - errno = WSAGetLastError(); - return r; - } - } - - if (r < 0) -#endif - r = write(fd, buf, count); - - return r; -} - -/** Calls read() in a loop. Makes sure that as much as 'size' bytes, - * unless EOF is reached or an error occured */ -ssize_t pa_loop_read(int fd, void*data, size_t size) { - ssize_t ret = 0; - assert(fd >= 0 && data && size); - - while (size > 0) { - ssize_t r; - - if ((r = pa_read(fd, data, size)) < 0) - return r; - - if (r == 0) - break; - - ret += r; - data = (uint8_t*) data + r; - size -= r; - } - - return ret; -} - -/** Similar to pa_loop_read(), but wraps write() */ -ssize_t pa_loop_write(int fd, const void*data, size_t size) { - ssize_t ret = 0; - assert(fd >= 0 && data && size); - - while (size > 0) { - ssize_t r; - - if ((r = pa_write(fd, data, size)) < 0) - return r; - - if (r == 0) - break; - - ret += r; - data = (const uint8_t*) data + r; - size -= r; - } - - return ret; -} - -/* Print a warning messages in case that the given signal is not - * blocked or trapped */ -void pa_check_signal_is_blocked(int sig) { -#ifdef HAVE_SIGACTION - struct sigaction sa; - sigset_t set; - - /* If POSIX threads are supported use thread-aware - * pthread_sigmask() function, to check if the signal is - * blocked. Otherwise fall back to sigprocmask() */ - -#ifdef HAVE_PTHREAD - if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) { -#endif - if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) { - pa_log(__FILE__": sigprocmask() failed: %s", strerror(errno)); - return; - } -#ifdef HAVE_PTHREAD - } -#endif - - if (sigismember(&set, sig)) - return; - - /* Check whether the signal is trapped */ - - if (sigaction(sig, NULL, &sa) < 0) { - pa_log(__FILE__": sigaction() failed: %s", strerror(errno)); - return; - } - - if (sa.sa_handler != SIG_DFL) - return; - - pa_log(__FILE__": WARNING: %s is not trapped. This might cause malfunction!", pa_strsignal(sig)); -#else /* HAVE_SIGACTION */ - pa_log(__FILE__": WARNING: %s might not be trapped. This might cause malfunction!", pa_strsignal(sig)); -#endif -} - -/* The following function is based on an example from the GNU libc - * documentation. This function is similar to GNU's asprintf(). */ -char *pa_sprintf_malloc(const char *format, ...) { - int size = 100; - char *c = NULL; - - assert(format); - - for(;;) { - int r; - va_list ap; - - c = pa_xrealloc(c, size); - - va_start(ap, format); - r = vsnprintf(c, size, format, ap); - va_end(ap); - - if (r > -1 && r < size) - return c; - - if (r > -1) /* glibc 2.1 */ - size = r+1; - else /* glibc 2.0 */ - size *= 2; - } -} - -/* Same as the previous function, but use a va_list instead of an - * ellipsis */ -char *pa_vsprintf_malloc(const char *format, va_list ap) { - int size = 100; - char *c = NULL; - - assert(format); - - for(;;) { - int r; - c = pa_xrealloc(c, size); - r = vsnprintf(c, size, format, ap); - - if (r > -1 && r < size) - return c; - - if (r > -1) /* glibc 2.1 */ - size = r+1; - else /* glibc 2.0 */ - size *= 2; - } -} - -/* Return the current username in the specified string buffer. */ -char *pa_get_user_name(char *s, size_t l) { - char *p; - char buf[1024]; - -#ifdef HAVE_PWD_H - struct passwd pw, *r; -#endif - - assert(s && l > 0); - - if (!(p = getenv("USER")) && !(p = getenv("LOGNAME")) && !(p = getenv("USERNAME"))) { -#ifdef HAVE_PWD_H - -#ifdef HAVE_GETPWUID_R - if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { -#else - /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) - * that do not support getpwuid_r. */ - if ((r = getpwuid(getuid())) == NULL) { -#endif - snprintf(s, l, "%lu", (unsigned long) getuid()); - return s; - } - - p = r->pw_name; - -#elif defined(OS_IS_WIN32) /* HAVE_PWD_H */ - DWORD size = sizeof(buf); - - if (!GetUserName(buf, &size)) - return NULL; - - p = buf; - -#else /* HAVE_PWD_H */ - return NULL; -#endif /* HAVE_PWD_H */ - } - - return pa_strlcpy(s, p, l); -} - -/* Return the current hostname in the specified buffer. */ -char *pa_get_host_name(char *s, size_t l) { - assert(s && l > 0); - if (gethostname(s, l) < 0) { - pa_log(__FILE__": gethostname(): %s", strerror(errno)); - return NULL; - } - s[l-1] = 0; - return s; -} - -/* Return the home directory of the current user */ -char *pa_get_home_dir(char *s, size_t l) { - char *e; - -#ifdef HAVE_PWD_H - char buf[1024]; - struct passwd pw, *r; -#endif - - assert(s && l); - - if ((e = getenv("HOME"))) - return pa_strlcpy(s, e, l); - - if ((e = getenv("USERPROFILE"))) - return pa_strlcpy(s, e, l); - -#ifdef HAVE_PWD_H -#ifdef HAVE_GETPWUID_R - if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { - pa_log(__FILE__": getpwuid_r() failed"); -#else - /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) - * that do not support getpwuid_r. */ - if ((r = getpwuid(getuid())) == NULL) { - pa_log(__FILE__": getpwuid_r() failed"); -#endif - return NULL; - } - - return pa_strlcpy(s, r->pw_dir, l); -#else /* HAVE_PWD_H */ - return NULL; -#endif -} - -/* Similar to OpenBSD's strlcpy() function */ -char *pa_strlcpy(char *b, const char *s, size_t l) { - assert(b && s && l > 0); - - strncpy(b, s, l); - b[l-1] = 0; - return b; -} - -struct timeval *pa_gettimeofday(struct timeval *tv) { -#ifdef HAVE_GETTIMEOFDAY - assert(tv); - - return gettimeofday(tv, NULL) < 0 ? NULL : tv; -#elif defined(OS_IS_WIN32) - /* - * Copied from implementation by Steven Edwards (LGPL). - * Found on wine mailing list. - */ - -#if defined(_MSC_VER) || defined(__BORLANDC__) -#define EPOCHFILETIME (116444736000000000i64) -#else -#define EPOCHFILETIME (116444736000000000LL) -#endif - - FILETIME ft; - LARGE_INTEGER li; - __int64 t; - - assert(tv); - - GetSystemTimeAsFileTime(&ft); - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - t = li.QuadPart; /* In 100-nanosecond intervals */ - t -= EPOCHFILETIME; /* Offset to the Epoch time */ - t /= 10; /* In microseconds */ - tv->tv_sec = (long)(t / 1000000); - tv->tv_usec = (long)(t % 1000000); - - return tv; -#else -#error "Platform lacks gettimeofday() or equivalent function." -#endif -} - -/* Calculate the difference between the two specfified timeval - * timestamsps. */ -pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { - pa_usec_t r; - assert(a && b); - - /* Check which whan is the earlier time and swap the two arguments if reuqired. */ - if (pa_timeval_cmp(a, b) < 0) { - const struct timeval *c; - c = a; - a = b; - b = c; - } - - /* Calculate the second difference*/ - r = ((pa_usec_t) a->tv_sec - b->tv_sec)* 1000000; - - /* Calculate the microsecond difference */ - if (a->tv_usec > b->tv_usec) - r += ((pa_usec_t) a->tv_usec - b->tv_usec); - else if (a->tv_usec < b->tv_usec) - r -= ((pa_usec_t) b->tv_usec - a->tv_usec); - - return r; -} - -/* Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwse */ -int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { - assert(a && b); - - if (a->tv_sec < b->tv_sec) - return -1; - - if (a->tv_sec > b->tv_sec) - return 1; - - if (a->tv_usec < b->tv_usec) - return -1; - - if (a->tv_usec > b->tv_usec) - return 1; - - return 0; -} - -/* Return the time difference between now and the specified timestamp */ -pa_usec_t pa_timeval_age(const struct timeval *tv) { - struct timeval now; - assert(tv); - - return pa_timeval_diff(pa_gettimeofday(&now), tv); -} - -/* Add the specified time inmicroseconds to the specified timeval structure */ -void pa_timeval_add(struct timeval *tv, pa_usec_t v) { - unsigned long secs; - assert(tv); - - secs = (v/1000000); - tv->tv_sec += (unsigned long) secs; - v -= secs*1000000; - - tv->tv_usec += v; - - /* Normalize */ - while (tv->tv_usec >= 1000000) { - tv->tv_sec++; - tv->tv_usec -= 1000000; - } -} - -#define NICE_LEVEL (-15) - -/* Raise the priority of the current process as much as possible and -sensible: set the nice level to -15 and enable realtime scheduling if -supported.*/ -void pa_raise_priority(void) { - -#ifdef HAVE_SYS_RESOURCE_H - if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) - pa_log_warn(__FILE__": setpriority() failed: %s", strerror(errno)); - else - pa_log_info(__FILE__": Successfully gained nice level %i.", NICE_LEVEL); -#endif - -#ifdef _POSIX_PRIORITY_SCHEDULING - { - struct sched_param sp; - - if (sched_getparam(0, &sp) < 0) { - pa_log(__FILE__": sched_getparam() failed: %s", strerror(errno)); - return; - } - - sp.sched_priority = 1; - if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) { - pa_log_warn(__FILE__": sched_setscheduler() failed: %s", strerror(errno)); - return; - } - - pa_log_info(__FILE__": Successfully enabled SCHED_FIFO scheduling."); - } -#endif - -#ifdef OS_IS_WIN32 - if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) - pa_log_warn(__FILE__": SetPriorityClass() failed: 0x%08X", GetLastError()); - else - pa_log_info(__FILE__": Successfully gained high priority class."); -#endif -} - -/* Reset the priority to normal, inverting the changes made by pa_raise_priority() */ -void pa_reset_priority(void) { -#ifdef OS_IS_WIN32 - SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); -#endif - -#ifdef _POSIX_PRIORITY_SCHEDULING - { - struct sched_param sp; - sched_getparam(0, &sp); - sp.sched_priority = 0; - sched_setscheduler(0, SCHED_OTHER, &sp); - } -#endif - -#ifdef HAVE_SYS_RESOURCE_H - setpriority(PRIO_PROCESS, 0, 0); -#endif -} - -/* Set the FD_CLOEXEC flag for a fd */ -int pa_fd_set_cloexec(int fd, int b) { - -#ifdef FD_CLOEXEC - int v; - assert(fd >= 0); - - if ((v = fcntl(fd, F_GETFD, 0)) < 0) - return -1; - - v = (v & ~FD_CLOEXEC) | (b ? FD_CLOEXEC : 0); - - if (fcntl(fd, F_SETFD, v) < 0) - return -1; -#endif - - return 0; -} - -/* Return the binary file name of the current process. Works on Linux - * only. This shoul be used for eyecandy only, don't rely on return - * non-NULL! */ -char *pa_get_binary_name(char *s, size_t l) { - -#ifdef HAVE_READLINK - char path[PATH_MAX]; - int i; - assert(s && l); - - /* This works on Linux only */ - - snprintf(path, sizeof(path), "/proc/%u/exe", (unsigned) getpid()); - if ((i = readlink(path, s, l-1)) < 0) - return NULL; - - s[i] = 0; - return s; -#elif defined(OS_IS_WIN32) - char path[PATH_MAX]; - if (!GetModuleFileName(NULL, path, PATH_MAX)) - return NULL; - pa_strlcpy(s, pa_path_get_filename(path), l); - return s; -#else - return NULL; -#endif -} - -/* Return a pointer to the filename inside a path (which is the last - * component). */ -const char *pa_path_get_filename(const char *p) { - char *fn; - - if ((fn = strrchr(p, PATH_SEP))) - return fn+1; - - return (const char*) p; -} - -/* Try to parse a boolean string value.*/ -int pa_parse_boolean(const char *v) { - - if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on")) - return 1; - else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off")) - return 0; - - return -1; -} - -/* Split the specified string wherever one of the strings in delimiter - * occurs. Each time it is called returns a newly allocated string - * with pa_xmalloc(). The variable state points to, should be - * initiallized to NULL before the first call. */ -char *pa_split(const char *c, const char *delimiter, const char**state) { - const char *current = *state ? *state : c; - size_t l; - - if (!*current) - return NULL; - - l = strcspn(current, delimiter); - *state = current+l; - - if (**state) - (*state)++; - - return pa_xstrndup(current, l); -} - -/* What is interpreted as whitespace? */ -#define WHITESPACE " \t\n" - -/* Split a string into words. Otherwise similar to pa_split(). */ -char *pa_split_spaces(const char *c, const char **state) { - const char *current = *state ? *state : c; - size_t l; - - if (!*current || *c == 0) - return NULL; - - current += strspn(current, WHITESPACE); - l = strcspn(current, WHITESPACE); - - *state = current+l; - - return pa_xstrndup(current, l); -} - -/* Return the name of an UNIX signal. Similar to GNU's strsignal() */ -const char *pa_strsignal(int sig) { - switch(sig) { - case SIGINT: return "SIGINT"; - case SIGTERM: return "SIGTERM"; -#ifdef SIGUSR1 - case SIGUSR1: return "SIGUSR1"; -#endif -#ifdef SIGUSR2 - case SIGUSR2: return "SIGUSR2"; -#endif -#ifdef SIGXCPU - case SIGXCPU: return "SIGXCPU"; -#endif -#ifdef SIGPIPE - case SIGPIPE: return "SIGPIPE"; -#endif -#ifdef SIGCHLD - case SIGCHLD: return "SIGCHLD"; -#endif -#ifdef SIGHUP - case SIGHUP: return "SIGHUP"; -#endif - default: return "UNKNOWN SIGNAL"; - } -} - -#ifdef HAVE_GRP_H - -/* Check whether the specified GID and the group name match */ -static int is_group(gid_t gid, const char *name) { - struct group group, *result = NULL; - long n; - void *data; - int r = -1; - -#ifdef HAVE_GETGRGID_R -#ifdef _SC_GETGR_R_SIZE_MAX - n = sysconf(_SC_GETGR_R_SIZE_MAX); -#else - n = -1; -#endif - if (n < 0) n = 512; - data = pa_xmalloc(n); - - if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) { - pa_log(__FILE__ ": getgrgid_r(%u) failed: %s", gid, strerror(errno)); - goto finish; - } - - r = strcmp(name, result->gr_name) == 0; - -finish: - pa_xfree(data); -#else - /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not - * support getgrgid_r. */ - if ((result = getgrgid(gid)) == NULL) { - pa_log(__FILE__ ": getgrgid(%u) failed: %s", gid, strerror(errno)); - goto finish; - } - - r = strcmp(name, result->gr_name) == 0; - -finish: -#endif - - return r; -} - -/* Check the current user is member of the specified group */ -int pa_own_uid_in_group(const char *name, gid_t *gid) { - GETGROUPS_T *gids, tgid; - int n = sysconf(_SC_NGROUPS_MAX); - int r = -1, i; - - assert(n > 0); - - gids = pa_xmalloc(sizeof(GETGROUPS_T)*n); - - if ((n = getgroups(n, gids)) < 0) { - pa_log(__FILE__": getgroups() failed: %s", strerror(errno)); - goto finish; - } - - for (i = 0; i < n; i++) { - if (is_group(gids[i], name) > 0) { - *gid = gids[i]; - r = 1; - goto finish; - } - } - - if (is_group(tgid = getgid(), name) > 0) { - *gid = tgid; - r = 1; - goto finish; - } - - r = 0; - -finish: - - pa_xfree(gids); - return r; -} - -int pa_uid_in_group(uid_t uid, const char *name) { - char *g_buf, *p_buf; - long g_n, p_n; - struct group grbuf, *gr; - char **i; - int r = -1; - - g_n = sysconf(_SC_GETGR_R_SIZE_MAX); - g_buf = pa_xmalloc(g_n); - - p_n = sysconf(_SC_GETPW_R_SIZE_MAX); - p_buf = pa_xmalloc(p_n); - - if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) - goto finish; - - r = 0; - for (i = gr->gr_mem; *i; i++) { - struct passwd pwbuf, *pw; - - if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw) - continue; - - if (pw->pw_uid == uid) { - r = 1; - break; - } - } - -finish: - pa_xfree(g_buf); - pa_xfree(p_buf); - - return r; -} - -#else /* HAVE_GRP_H */ - -int pa_own_uid_in_group(const char *name, gid_t *gid) { - return -1; - -} - -int pa_uid_in_group(uid_t uid, const char *name) { - return -1; -} - -#endif - -/* Lock or unlock a file entirely. - (advisory on UNIX, mandatory on Windows) */ -int pa_lock_fd(int fd, int b) { -#ifdef F_SETLKW - struct flock flock; - - /* Try a R/W lock first */ - - flock.l_type = b ? F_WRLCK : F_UNLCK; - flock.l_whence = SEEK_SET; - flock.l_start = 0; - flock.l_len = 0; - - if (fcntl(fd, F_SETLKW, &flock) >= 0) - return 0; - - /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */ - if (b && errno == EBADF) { - flock.l_type = F_RDLCK; - if (fcntl(fd, F_SETLKW, &flock) >= 0) - return 0; - } - - pa_log(__FILE__": %slock failed: %s", !b ? "un" : "", strerror(errno)); -#endif - -#ifdef OS_IS_WIN32 - HANDLE h = (HANDLE)_get_osfhandle(fd); - - if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) - return 0; - if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) - return 0; - - pa_log(__FILE__": %slock failed: 0x%08X", !b ? "un" : "", GetLastError()); -#endif - - return -1; -} - -/* Remove trailing newlines from a string */ -char* pa_strip_nl(char *s) { - assert(s); - - s[strcspn(s, "\r\n")] = 0; - return s; -} - -/* Create a temporary lock file and lock it. */ -int pa_lock_lockfile(const char *fn) { - int fd = -1; - assert(fn); - - for (;;) { - struct stat st; - - if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { - pa_log(__FILE__": failed to create lock file '%s': %s", fn, strerror(errno)); - goto fail; - } - - if (pa_lock_fd(fd, 1) < 0) { - pa_log(__FILE__": failed to lock file '%s'.", fn); - goto fail; - } - - if (fstat(fd, &st) < 0) { - pa_log(__FILE__": failed to fstat() file '%s'.", fn); - goto fail; - } - - /* Check wheter the file has been removed meanwhile. When yes, restart this loop, otherwise, we're done */ - if (st.st_nlink >= 1) - break; - - if (pa_lock_fd(fd, 0) < 0) { - pa_log(__FILE__": failed to unlock file '%s'.", fn); - goto fail; - } - - if (close(fd) < 0) { - pa_log(__FILE__": failed to close file '%s'.", fn); - goto fail; - } - - fd = -1; - } - - return fd; - -fail: - - if (fd >= 0) - close(fd); - - return -1; -} - -/* Unlock a temporary lcok file */ -int pa_unlock_lockfile(const char *fn, int fd) { - int r = 0; - assert(fn && fd >= 0); - - if (unlink(fn) < 0) { - pa_log_warn(__FILE__": WARNING: unable to remove lock file '%s': %s", fn, strerror(errno)); - r = -1; - } - - if (pa_lock_fd(fd, 0) < 0) { - pa_log_warn(__FILE__": WARNING: failed to unlock file '%s'.", fn); - r = -1; - } - - if (close(fd) < 0) { - pa_log_warn(__FILE__": WARNING: failed to close lock file '%s': %s", fn, strerror(errno)); - r = -1; - } - - return r; -} - -/* Try to open a configuration file. If "env" is specified, open the - * value of the specified environment variable. Otherwise look for a - * file "local" in the home directory or a file "global" in global - * file system. If "result" is non-NULL, a pointer to a newly - * allocated buffer containing the used configuration file is - * stored there.*/ -FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode) { - const char *fn; - char h[PATH_MAX]; - -#ifdef OS_IS_WIN32 - char buf[PATH_MAX]; - - if (!getenv(POLYP_ROOTENV)) - pa_set_root(NULL); -#endif - - if (env && (fn = getenv(env))) { -#ifdef OS_IS_WIN32 - if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX)) - return NULL; - fn = buf; -#endif - - if (result) - *result = pa_xstrdup(fn); - - return fopen(fn, mode); - } - - if (local && pa_get_home_dir(h, sizeof(h))) { - FILE *f; - char *lfn; - - fn = lfn = pa_sprintf_malloc("%s/%s", h, local); - -#ifdef OS_IS_WIN32 - if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) - return NULL; - fn = buf; -#endif - - f = fopen(fn, mode); - - if (f || errno != ENOENT) { - if (result) - *result = pa_xstrdup(fn); - pa_xfree(lfn); - return f; - } - - pa_xfree(lfn); - } - - if (!global) { - if (result) - *result = NULL; - errno = ENOENT; - return NULL; - } - -#ifdef OS_IS_WIN32 - if (!ExpandEnvironmentStrings(global, buf, PATH_MAX)) - return NULL; - global = buf; -#endif - - if (result) - *result = pa_xstrdup(global); - - return fopen(global, mode); -} - -/* Format the specified data as a hexademical string */ -char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) { - size_t i = 0, j = 0; - const char hex[] = "0123456789abcdef"; - assert(d && s && slength > 0); - - while (i < dlength && j+3 <= slength) { - s[j++] = hex[*d >> 4]; - s[j++] = hex[*d & 0xF]; - - d++; - i++; - } - - s[j < slength ? j : slength] = 0; - return s; -} - -/* Convert a hexadecimal digit to a number or -1 if invalid */ -static int hexc(char c) { - if (c >= '0' && c <= '9') - return c - '0'; - - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - - return -1; -} - -/* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */ -size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) { - size_t j = 0; - assert(p && d); - - while (j < dlength && *p) { - int b; - - if ((b = hexc(*(p++))) < 0) - return (size_t) -1; - - d[j] = (uint8_t) (b << 4); - - if (!*p) - return (size_t) -1; - - if ((b = hexc(*(p++))) < 0) - return (size_t) -1; - - d[j] |= (uint8_t) b; - j++; - } - - return j; -} - -/* Return the fully qualified domain name in *s */ -char *pa_get_fqdn(char *s, size_t l) { - char hn[256]; -#ifdef HAVE_GETADDRINFO - struct addrinfo *a, hints; -#endif - - if (!pa_get_host_name(hn, sizeof(hn))) - return NULL; - -#ifdef HAVE_GETADDRINFO - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_flags = AI_CANONNAME; - - if (getaddrinfo(hn, NULL, &hints, &a) < 0 || !a || !a->ai_canonname || !*a->ai_canonname) - return pa_strlcpy(s, hn, l); - - pa_strlcpy(s, a->ai_canonname, l); - freeaddrinfo(a); - return s; -#else - return pa_strlcpy(s, hn, l); -#endif -} - -/* Returns nonzero when *s starts with *pfx */ -int pa_startswith(const char *s, const char *pfx) { - size_t l; - - assert(s); - assert(pfx); - - l = strlen(pfx); - - return strlen(s) >= l && strncmp(s, pfx, l) == 0; -} - -/* Returns nonzero when *s ends with *sfx */ -int pa_endswith(const char *s, const char *sfx) { - size_t l1, l2; - - assert(s); - assert(sfx); - - l1 = strlen(s); - l2 = strlen(sfx); - - return l1 >= l2 && strcmp(s+l1-l2, sfx) == 0; -} - -/* if fn is null return the polypaudio run time path in s (/tmp/polypaudio) - * if fn is non-null and starts with / return fn in s - * otherwise append fn to the run time path and return it in s */ -char *pa_runtime_path(const char *fn, char *s, size_t l) { - char u[256]; - -#ifndef OS_IS_WIN32 - if (fn && *fn == '/') -#else - if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\') -#endif - return pa_strlcpy(s, fn, l); - - if (fn) - snprintf(s, l, "%s%s%c%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn); - else - snprintf(s, l, "%s%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u))); - -#ifdef OS_IS_WIN32 - { - char buf[l]; - strcpy(buf, s); - ExpandEnvironmentStrings(buf, s, l); - } -#endif - - return s; -} - -/* Wait t milliseconds */ -int pa_msleep(unsigned long t) { -#ifdef OS_IS_WIN32 - Sleep(t); - return 0; -#elif defined(HAVE_NANOSLEEP) - struct timespec ts; - - ts.tv_sec = t/1000; - ts.tv_nsec = (t % 1000) * 1000000; - - return nanosleep(&ts, NULL); -#else -#error "Platform lacks a sleep function." -#endif -} - -/* Convert the string s to a signed integer in *ret_i */ -int pa_atoi(const char *s, int32_t *ret_i) { - char *x = NULL; - long l; - assert(s && ret_i); - - l = strtol(s, &x, 0); - - if (!x || *x) - return -1; - - *ret_i = (int32_t) l; - - return 0; -} - -/* Convert the string s to an unsigned integer in *ret_u */ -int pa_atou(const char *s, uint32_t *ret_u) { - char *x = NULL; - unsigned long l; - assert(s && ret_u); - - l = strtoul(s, &x, 0); - - if (!x || *x) - return -1; - - *ret_u = (uint32_t) l; - - return 0; -} diff --git a/src/polypcore/util.h b/src/polypcore/util.h deleted file mode 100644 index df71672f..00000000 --- a/src/polypcore/util.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef fooutilhfoo -#define fooutilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include - -#include -#include - -struct timeval; - -void pa_make_nonblock_fd(int fd); - -int pa_make_secure_dir(const char* dir); -int pa_make_secure_parent_dir(const char *fn); - -ssize_t pa_read(int fd, void *buf, size_t count); -ssize_t pa_write(int fd, const void *buf, size_t count); -ssize_t pa_loop_read(int fd, void*data, size_t size); -ssize_t pa_loop_write(int fd, const void*data, size_t size); - -void pa_check_signal_is_blocked(int sig); - -char *pa_sprintf_malloc(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); -char *pa_vsprintf_malloc(const char *format, va_list ap); - -char *pa_strlcpy(char *b, const char *s, size_t l); - -char *pa_get_user_name(char *s, size_t l); -char *pa_get_host_name(char *s, size_t l); -char *pa_get_fqdn(char *s, size_t l); -char *pa_get_binary_name(char *s, size_t l); -char *pa_get_home_dir(char *s, size_t l); - -const char *pa_path_get_filename(const char *p); - -char *pa_parent_dir(const char *fn); - -struct timeval *pa_gettimeofday(struct timeval *tv); -pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); -int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); -pa_usec_t pa_timeval_age(const struct timeval *tv); -void pa_timeval_add(struct timeval *tv, pa_usec_t v); - -void pa_raise_priority(void); -void pa_reset_priority(void); - -int pa_fd_set_cloexec(int fd, int b); - -int pa_parse_boolean(const char *s); - -char *pa_split(const char *c, const char*delimiters, const char **state); -char *pa_split_spaces(const char *c, const char **state); - -char *pa_strip_nl(char *s); - -const char *pa_strsignal(int sig); - -int pa_own_uid_in_group(const char *name, gid_t *gid); -int pa_uid_in_group(uid_t uid, const char *name); - -int pa_lock_fd(int fd, int b); - -int pa_lock_lockfile(const char *fn); -int pa_unlock_lockfile(const char *fn, int fd); - -FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode); - -char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength); -size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength); - -int pa_startswith(const char *s, const char *pfx); -int pa_endswith(const char *s, const char *sfx); - -char *pa_runtime_path(const char *fn, char *s, size_t l); - -int pa_msleep(unsigned long t); - -int pa_atoi(const char *s, int32_t *ret_i); -int pa_atou(const char *s, uint32_t *ret_u); - -#endif diff --git a/src/utils/pabrowse.c b/src/utils/pabrowse.c index c1bab6b1..8063a28b 100644 --- a/src/utils/pabrowse.c +++ b/src/utils/pabrowse.c @@ -27,8 +27,7 @@ #include #include -#include -#include +#include #include static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { @@ -108,7 +107,6 @@ static void browser_callback(pa_browser *b, pa_browse_opcode_t c, const pa_brows } } - int main(int argc, char *argv[]) { pa_mainloop *mainloop = NULL; pa_browser *browser = NULL; -- cgit From 813868e1cb98390b32f6ec3fbf3019a7d15f7ab9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 20:42:11 +0000 Subject: include util.h in polypaudio.h git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@918 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/polypaudio.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/polyp/polypaudio.h b/src/polyp/polypaudio.h index fe25fe30..51e3f970 100644 --- a/src/polyp/polypaudio.h +++ b/src/polyp/polypaudio.h @@ -40,6 +40,7 @@ #include #include #include +#include /** \file * Include all polyplib header files at once. The following @@ -47,7 +48,7 @@ * \ref context.h, \ref stream.h, \ref introspect.h, \ref subscribe.h, * \ref scache.h, \ref version.h, \ref error.h, \ref channelmap.h, * \ref operation.h,\ref volume.h, \ref xmalloc.h, \ref utf8.h, \ref - * thread-mainloop.h, \ref mainloop.h and \ref mainloop-signal.h at once */ + * thread-mainloop.h, \ref mainloop.h, \ref util.h and \ref mainloop-signal.h at once */ /** \mainpage * -- cgit From 6766a3ba21632ed7ffa869800a7ac28f839a63a3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 20:42:27 +0000 Subject: add util.h to doxygen git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@919 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doxygen/doxygen.conf.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doxygen/doxygen.conf.in b/doxygen/doxygen.conf.in index 97040377..3d7ad322 100644 --- a/doxygen/doxygen.conf.in +++ b/doxygen/doxygen.conf.in @@ -417,7 +417,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = ../src/polyp/context.h ../src/polyp/stream.h ../src/polyp/polypaudio.h ../src/polyp/sample.h ../src/polyp/def.h ../src/polyp/subscribe.h ../src/polyp/introspect.h ../src/polyp/scache.h ../src/polyp/mainloop-api.h ../src/polyp/glib-mainloop.h ../src/polyp/mainloop.h ../src/polyp/mainloop-signal.h ../src/polyp/error.h ../src/polyp/operation.h ../src/polyp/simple.h ../src/polyp/version.h ../src/polyp/volume.h ../src/polyp/channelmap.h ../src/polyp/thread-mainloop.h ../src/polyp/xmalloc.h ../src/polyp/utf8.h +INPUT = ../src/polyp/context.h ../src/polyp/stream.h ../src/polyp/polypaudio.h ../src/polyp/sample.h ../src/polyp/def.h ../src/polyp/subscribe.h ../src/polyp/introspect.h ../src/polyp/scache.h ../src/polyp/mainloop-api.h ../src/polyp/glib-mainloop.h ../src/polyp/mainloop.h ../src/polyp/mainloop-signal.h ../src/polyp/error.h ../src/polyp/operation.h ../src/polyp/simple.h ../src/polyp/version.h ../src/polyp/volume.h ../src/polyp/channelmap.h ../src/polyp/thread-mainloop.h ../src/polyp/xmalloc.h ../src/polyp/utf8.h ../src/polyp/util.h # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -- cgit From dc9151d35517d82769028c7dd81e0d7cc527a270 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 20:43:19 +0000 Subject: * add doxygen docs to header file * add C++ macros to header file git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@920 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/util.c | 21 ++++----------------- src/polyp/util.h | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/polyp/util.c b/src/polyp/util.c index dd597322..76b5c9b9 100644 --- a/src/polyp/util.c +++ b/src/polyp/util.c @@ -57,7 +57,7 @@ #include #include -#include +#include #include "util.h" @@ -67,7 +67,6 @@ #define PATH_SEP '\\' #endif -/* Return the current username in the specified string buffer. */ char *pa_get_user_name(char *s, size_t l) { char *p; char buf[1024]; @@ -110,7 +109,6 @@ char *pa_get_user_name(char *s, size_t l) { return pa_strlcpy(s, p, l); } -/* Return the current hostname in the specified buffer. */ char *pa_get_host_name(char *s, size_t l) { assert(s && l > 0); if (gethostname(s, l) < 0) { @@ -121,7 +119,6 @@ char *pa_get_host_name(char *s, size_t l) { return s; } -/* Return the home directory of the current user */ char *pa_get_home_dir(char *s, size_t l) { char *e; @@ -195,8 +192,6 @@ struct timeval *pa_gettimeofday(struct timeval *tv) { #endif } -/* Calculate the difference between the two specfified timeval - * timestamsps. */ pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { pa_usec_t r; assert(a && b); @@ -221,7 +216,6 @@ pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { return r; } -/* Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwse */ int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { assert(a && b); @@ -240,7 +234,6 @@ int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { return 0; } -/* Return the time difference between now and the specified timestamp */ pa_usec_t pa_timeval_age(const struct timeval *tv) { struct timeval now; assert(tv); @@ -248,8 +241,7 @@ pa_usec_t pa_timeval_age(const struct timeval *tv) { return pa_timeval_diff(pa_gettimeofday(&now), tv); } -/* Add the specified time inmicroseconds to the specified timeval structure */ -void pa_timeval_add(struct timeval *tv, pa_usec_t v) { +struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v) { unsigned long secs; assert(tv); @@ -264,11 +256,10 @@ void pa_timeval_add(struct timeval *tv, pa_usec_t v) { tv->tv_sec++; tv->tv_usec -= 1000000; } + + return tv; } -/* Return the binary file name of the current process. Works on Linux - * only. This shoul be used for eyecandy only, don't rely on return - * non-NULL! */ char *pa_get_binary_name(char *s, size_t l) { #ifdef HAVE_READLINK @@ -295,8 +286,6 @@ char *pa_get_binary_name(char *s, size_t l) { #endif } -/* Return a pointer to the filename inside a path (which is the last - * component). */ const char *pa_path_get_filename(const char *p) { char *fn; @@ -306,7 +295,6 @@ const char *pa_path_get_filename(const char *p) { return (const char*) p; } -/* Return the fully qualified domain name in *s */ char *pa_get_fqdn(char *s, size_t l) { char hn[256]; #ifdef HAVE_GETADDRINFO @@ -332,7 +320,6 @@ char *pa_get_fqdn(char *s, size_t l) { #endif } -/* Wait t milliseconds */ int pa_msleep(unsigned long t) { #ifdef OS_IS_WIN32 Sleep(t); diff --git a/src/polyp/util.h b/src/polyp/util.h index 37232d9f..8bd03f98 100644 --- a/src/polyp/util.h +++ b/src/polyp/util.h @@ -26,23 +26,54 @@ #include #include +#include + +/** \file + * Assorted utility functions */ + +PA_C_DECL_BEGIN struct timeval; +/** Return the current username in the specified string buffer. */ char *pa_get_user_name(char *s, size_t l); + +/** Return the current hostname in the specified buffer. */ char *pa_get_host_name(char *s, size_t l); + +/** Return the fully qualified domain name in s */ char *pa_get_fqdn(char *s, size_t l); + +/** Return the home directory of the current user */ char *pa_get_home_dir(char *s, size_t l); +/** Return the binary file name of the current process. This is not + * supported on all architectures, in which case NULL is returned. */ char *pa_get_binary_name(char *s, size_t l); + +/** Return a pointer to the filename inside a path (which is the last + * component). */ const char *pa_path_get_filename(const char *p); +/** Return the current timestamp, just like UNIX gettimeofday() */ struct timeval *pa_gettimeofday(struct timeval *tv); + +/** Calculate the difference between the two specified timeval + * structs. */ pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); + +/** Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwse */ int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); + +/** Return the time difference between now and the specified timestamp */ pa_usec_t pa_timeval_age(const struct timeval *tv); -void pa_timeval_add(struct timeval *tv, pa_usec_t v); +/** Add the specified time inmicroseconds to the specified timeval structure */ +struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v); + +/** Wait t milliseconds */ int pa_msleep(unsigned long t); +PA_C_DECL_END + #endif -- cgit From ee4d6b064fe9c872e008a37b5b8daf60752a27ae Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 20:43:49 +0000 Subject: add C++ macros to xmalloc.h git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@921 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/xmalloc.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/polyp/xmalloc.h b/src/polyp/xmalloc.h index 9d91d8dc..49b6d7bc 100644 --- a/src/polyp/xmalloc.h +++ b/src/polyp/xmalloc.h @@ -26,11 +26,14 @@ #include #include #include +#include /** \file * Memory allocation functions. */ +PA_C_DECL_BEGIN + /** Allocate the specified number of bytes, just like malloc() does. However, in case of OOM, terminate */ void* pa_xmalloc(size_t l); @@ -70,4 +73,6 @@ static inline void* pa_xnew0_internal(unsigned n, size_t k) { /** Same as pa_xnew() but set the memory to zero */ #define pa_xnew0(type, n) ((type*) pa_xnew0_internal((n), sizeof(type))) +PA_C_DECL_END + #endif -- cgit From 40feedb8bf53fe656946f376c044dbe4a1741082 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 20:44:19 +0000 Subject: add C++ macros to utf8.h git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@922 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/utf8.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/polyp/utf8.h b/src/polyp/utf8.h index e9a51533..3cc3a7d0 100644 --- a/src/polyp/utf8.h +++ b/src/polyp/utf8.h @@ -22,14 +22,20 @@ USA. ***/ +#include + /** \file * UTF8 Validation functions */ +PA_C_DECL_BEGIN + /** Test if the specified strings qualifies as valid UTF8. Return the string if so, otherwise NULL */ const char *pa_utf8_valid(const char *str); /** Filter all invalid UTF8 characters from the specified string, returning a new fully UTF8 valid string. Don't forget to free the returned string with pa_xfree() */ char *pa_utf8_filter(const char *str); +PA_C_DECL_END + #endif -- cgit From 53a285e75616281bcdd8b1dcf0e3b7ba59257516 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 20:44:55 +0000 Subject: fix include line for "core-util.h" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@923 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/cmdline.c | 2 +- src/daemon/cpulimit.c | 2 +- src/daemon/daemon-conf.c | 2 +- src/daemon/dumpmodules.c | 2 +- src/daemon/main.c | 2 +- src/modules/rtp/module-rtp-recv.c | 2 +- src/modules/rtp/module-rtp-send.c | 2 +- src/modules/rtp/sap.c | 2 +- src/modules/rtp/sdp.c | 2 +- src/polyp/browser.c | 2 +- src/polyp/channelmap.c | 3 +-- src/polyp/client-conf-x11.c | 2 +- src/polyp/client-conf.c | 2 +- src/polyp/context.c | 2 +- src/polyp/glib-mainloop.c | 2 +- src/polyp/glib12-mainloop.c | 2 +- src/polyp/mainloop-signal.c | 2 +- src/polyp/mainloop.c | 2 +- src/polyp/stream.c | 2 +- src/polyp/xmalloc.c | 2 +- src/polypcore/ioline.h | 2 +- src/tests/mainloop-test.c | 2 +- src/tests/mcalign-test.c | 2 +- src/tests/thread-mainloop-test.c | 2 +- src/utils/pacat.c | 1 - src/utils/pacmd.c | 2 +- src/utils/pax11publish.c | 2 +- 27 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c index 1ed16a69..21fd5a25 100644 --- a/src/daemon/cmdline.c +++ b/src/daemon/cmdline.c @@ -32,7 +32,7 @@ #include -#include +#include #include #include "cmdline.h" diff --git a/src/daemon/cpulimit.c b/src/daemon/cpulimit.c index 54f111da..69973384 100644 --- a/src/daemon/cpulimit.c +++ b/src/daemon/cpulimit.c @@ -23,7 +23,7 @@ #include #endif -#include +#include #include #include "cpulimit.h" diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index f82d3d24..0f4fcb97 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -31,7 +31,7 @@ #include -#include +#include #include #include #include diff --git a/src/daemon/dumpmodules.c b/src/daemon/dumpmodules.c index c541c168..b6a3bb7c 100644 --- a/src/daemon/dumpmodules.c +++ b/src/daemon/dumpmodules.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include "dumpmodules.h" diff --git a/src/daemon/main.c b/src/daemon/main.c index a7144eba..9b9ea180 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -58,7 +58,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index 89aa8983..a1196a2d 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 8fc1d7fe..a88ea76a 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c index e579b5c5..5b8f31fb 100644 --- a/src/modules/rtp/sap.c +++ b/src/modules/rtp/sap.c @@ -40,7 +40,7 @@ #include -#include +#include #include #include "sap.h" diff --git a/src/modules/rtp/sdp.c b/src/modules/rtp/sdp.c index 3cece711..5ec5090d 100644 --- a/src/modules/rtp/sdp.c +++ b/src/modules/rtp/sdp.c @@ -33,7 +33,7 @@ #include -#include +#include #include #include "sdp.h" diff --git a/src/polyp/browser.c b/src/polyp/browser.c index 5442fd4c..69760d8d 100644 --- a/src/polyp/browser.c +++ b/src/polyp/browser.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include "browser.h" diff --git a/src/polyp/channelmap.c b/src/polyp/channelmap.c index ddd7b3ce..653331ba 100644 --- a/src/polyp/channelmap.c +++ b/src/polyp/channelmap.c @@ -29,8 +29,7 @@ #include #include - -#include +#include #include "channelmap.h" diff --git a/src/polyp/client-conf-x11.c b/src/polyp/client-conf-x11.c index 17ee2d6a..fb67df2f 100644 --- a/src/polyp/client-conf-x11.c +++ b/src/polyp/client-conf-x11.c @@ -33,7 +33,7 @@ #include #include -#include +#include #include "client-conf-x11.h" diff --git a/src/polyp/client-conf.c b/src/polyp/client-conf.c index 567d2ae4..1ebcff43 100644 --- a/src/polyp/client-conf.c +++ b/src/polyp/client-conf.c @@ -33,7 +33,7 @@ #include #include -#include +#include #include #include "client-conf.h" diff --git a/src/polyp/context.c b/src/polyp/context.c index 3c46e2e8..a3b49d4b 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -56,7 +56,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/polyp/glib-mainloop.c b/src/polyp/glib-mainloop.c index bc5df3a9..51d437d2 100644 --- a/src/polyp/glib-mainloop.c +++ b/src/polyp/glib-mainloop.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include "glib.h" #include "glib-mainloop.h" diff --git a/src/polyp/glib12-mainloop.c b/src/polyp/glib12-mainloop.c index 7af21210..f7459f19 100644 --- a/src/polyp/glib12-mainloop.c +++ b/src/polyp/glib12-mainloop.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include "glib-mainloop.h" diff --git a/src/polyp/mainloop-signal.c b/src/polyp/mainloop-signal.c index a225f78b..c57437b6 100644 --- a/src/polyp/mainloop-signal.c +++ b/src/polyp/mainloop-signal.c @@ -38,7 +38,7 @@ #include -#include +#include #include #include diff --git a/src/polyp/mainloop.c b/src/polyp/mainloop.c index 82e789c5..8f44c180 100644 --- a/src/polyp/mainloop.c +++ b/src/polyp/mainloop.c @@ -46,7 +46,7 @@ #include -#include +#include #include #include diff --git a/src/polyp/stream.c b/src/polyp/stream.c index f188e788..ad6c9e43 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include diff --git a/src/polyp/xmalloc.c b/src/polyp/xmalloc.c index 1deeebd8..ffc7f7c8 100644 --- a/src/polyp/xmalloc.c +++ b/src/polyp/xmalloc.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include "xmalloc.h" diff --git a/src/polypcore/ioline.h b/src/polypcore/ioline.h index e2dadf55..77bf8761 100644 --- a/src/polypcore/ioline.h +++ b/src/polypcore/ioline.h @@ -23,7 +23,7 @@ ***/ #include -#include +#include /* An ioline wraps an iochannel for line based communication. A * callback function is called whenever a new line has been recieved diff --git a/src/tests/mainloop-test.c b/src/tests/mainloop-test.c index f62c9693..30088483 100644 --- a/src/tests/mainloop-test.c +++ b/src/tests/mainloop-test.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include #ifdef GLIB_MAIN_LOOP diff --git a/src/tests/mcalign-test.c b/src/tests/mcalign-test.c index 2728def2..765dcf94 100644 --- a/src/tests/mcalign-test.c +++ b/src/tests/mcalign-test.c @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/thread-mainloop-test.c b/src/tests/thread-mainloop-test.c index 8ca3f92f..676b8d37 100644 --- a/src/tests/thread-mainloop-test.c +++ b/src/tests/thread-mainloop-test.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include static void tcb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) { diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 51b3a48e..b1f5bf59 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -34,7 +34,6 @@ #include #include -#include #define TIME_EVENT_USEC 50000 diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c index e640ddaf..fefe7634 100644 --- a/src/utils/pacmd.c +++ b/src/utils/pacmd.c @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include diff --git a/src/utils/pax11publish.c b/src/utils/pax11publish.c index e4358894..ee0cb845 100644 --- a/src/utils/pax11publish.c +++ b/src/utils/pax11publish.c @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include #include -- cgit From 38cb1381156c7913118b76c5ddf3ae0e70f39163 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 21:07:46 +0000 Subject: modify lirc module to use pa_sink_mute() for muting and unmuting git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@924 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-lirc.c | 58 ++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c index 918177a3..009c2e46 100644 --- a/src/modules/module-lirc.c +++ b/src/modules/module-lirc.c @@ -88,7 +88,14 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC pa_xfree(c); while (lirc_code2char(u->config, code, &name) == 0 && name) { - enum { INVALID, UP, DOWN, MUTE, RESET, MUTE_TOGGLE } volchange = INVALID; + enum { + INVALID, + UP, + DOWN, + MUTE, + RESET, + MUTE_TOGGLE + } volchange = INVALID; pa_log_info(__FILE__": translated IR code '%s'", name); @@ -111,51 +118,56 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) pa_log(__FILE__": failed to get sink '%s'", u->sink_name); else { - pa_volume_t v = pa_cvolume_avg(pa_sink_get_volume(s, PA_MIXER_HARDWARE)); - pa_cvolume cv; + int i; + pa_cvolume cv = *pa_sink_get_volume(s, PA_MIXER_HARDWARE); + #define DELTA (PA_VOLUME_NORM/20) switch (volchange) { case UP: - v += PA_VOLUME_NORM/20; + for (i = 0; i < cv.channels; i++) { + cv.values[i] += DELTA; + + if (cv.values[i] > PA_VOLUME_NORM) + cv.values[i] = PA_VOLUME_NORM; + } + + pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); break; case DOWN: - if (v > DELTA) - v -= DELTA; - else - v = PA_VOLUME_MUTED; + for (i = 0; i < cv.channels; i++) { + if (cv.values[i] >= DELTA) + cv.values[i] -= DELTA; + else + cv.values[i] = PA_VOLUME_MUTED; + } + pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); break; case MUTE: - v = PA_VOLUME_MUTED; + pa_sink_set_mute(s, PA_MIXER_HARDWARE, 0); break; case RESET: - v = PA_VOLUME_NORM; + pa_sink_set_mute(s, PA_MIXER_HARDWARE, 1); break; - case MUTE_TOGGLE: { - - if (v > 0) { - u->mute_toggle_save = v; - v = PA_VOLUME_MUTED; - } else - v = u->mute_toggle_save; - } - default: + case MUTE_TOGGLE: + + pa_sink_set_mute(s, PA_MIXER_HARDWARE, !pa_sink_get_mute(s, PA_MIXER_HARDWARE)); + break; + + case INVALID: ; } - - pa_cvolume_set(&cv, PA_CHANNELS_MAX, v); - pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); } } } } - free(code); + pa_xfree(code); return; -- cgit From 5f458db84f38c52170af26be93156c24ac7831fc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 21:39:35 +0000 Subject: update README for 0.9.0 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@925 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/doc/README.html.in b/doc/README.html.in index 5c6e49a7..62a23b71 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -43,6 +43,15 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    News

    +
    Fri Apr 28 2006:

    Version 0.9.0 +released; changes include: new module module-volume-restore; +require valid UTF8 strings everywhere; properly support ALSA channel +maps for surround sound; increase maximum number of channels per +stream to 32; add new threaded main loop API for synchronous programs; +introduce real shared object versioning; a few API additions; many, +many bugfixes

    +
    Fri Apr 28 2006:

    Version 0.8.1 released; changes include: support for specifying the channel map on @@ -157,6 +166,7 @@ Sound Architecture (ALSA) sinks and sources

  • module-http-protocol-tcp: Spawns a small HTTP server which can be used to introspect the Polypaudio server with a web browser.
  • module-tunnel-sink, module-tunnel-source: make sinks/sources from other hosts available locally.
  • module-match: adjust volume automatically for newly created playback streams based on a regular expression matching table.
  • +
  • module-volume-restore: much like module-match, but create rules fully automatically based on the client name.
  • module-null-sink: a clocked sink similar to /dev/null.
  • module-esound-sink: a sink for forwarding audio data to an ESOUND server.
  • module-detect: a module which automatically detects what sound hardware is available locally and which loads the required driver modules.
  • @@ -167,15 +177,13 @@ Sound Architecture (ALSA) sinks and sources
  • module-jack-sink, module-jack-source: connect to a JACK Audio Connection Kit server. (A sound server for professional audio production)
  • -

    polypaudio is the successor of my previous, ill-fated -attempt to write a sound server, asd.

    -

    A GTK GUI manager application for polypaudio is the Polypaudio -Manager. Another GTK GUI tool for Polypaudio is the . Other GTK GUI tool for Polypaudio are the Polypaudio Volume -Meter.

    +Meter and the Polypaudio Volume +Control .

    There are output plugins for XMMS,

    Version @PACKAGE_VERSION@ is quite usable. It matches and supersedes ESOUND's feature set in nearly all areas.

    -

    Warning: polypaudio's client API and protocol are not stable -yet. The client interface is still a moving target and changes from -release to release. The client API's library version number is currently fixed to 0.0.0.

    -

    Documentation

    There is some preliminary documentation available: for the client API. (Run make doxygen to generate thi

    There are several reasons for writing loadable modules for polypaudio:

      -
    • Device driver support in addition to ALSA/OSS
    • +
    • Extended device driver support
    • Protocol support beyond ESOUND's protocol and the native protocol. (such as NAS or a subset of aRts)
    • New programming interfaces such as XMLRPC or DBUS for controlling the daemon.
    • Hooking audio event sources directly into polypaudio (similar to module-x11-bell)
    • @@ -326,7 +330,7 @@ compilation and make install (as root) for installation of

      Please report bugs to our Trac ticket system.


      -
      Lennart Poettering <@PACKAGE_BUGREPORT@>, April 2006
      +
      Lennart Poettering <@PACKAGE_BUGREPORT@>, May 2006
      $Id$
      -- cgit From 0796ead0db250f6a46a7531c9db471592ed6e129 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 18 May 2006 06:45:43 +0000 Subject: Move timeval calculation functions into their own file. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@926 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doxygen/doxygen.conf.in | 2 +- src/Makefile.am | 6 +- src/modules/module-combine.c | 1 + src/modules/module-null-sink.c | 1 + src/modules/module-tunnel.c | 1 + src/modules/rtp/module-rtp-recv.c | 1 + src/modules/rtp/module-rtp-send.c | 1 + src/polyp/glib12-mainloop.c | 1 + src/polyp/mainloop.c | 1 + src/polyp/polypaudio.h | 4 +- src/polyp/timeval.c | 142 ++++++++++++++++++++++++++++++++++++++ src/polyp/timeval.h | 53 ++++++++++++++ src/polyp/util.c | 136 ++++-------------------------------- src/polyp/util.h | 22 +----- src/polypcore/core-scache.c | 1 + src/polypcore/core.c | 1 + src/polypcore/module.c | 1 + src/polypcore/pdispatch.c | 1 + src/polypcore/protocol-esound.c | 1 + src/polypcore/protocol-native.c | 1 + src/polypcore/socket-client.c | 1 + src/tests/mainloop-test.c | 2 + src/tests/thread-mainloop-test.c | 2 + 23 files changed, 234 insertions(+), 149 deletions(-) create mode 100644 src/polyp/timeval.c create mode 100644 src/polyp/timeval.h diff --git a/doxygen/doxygen.conf.in b/doxygen/doxygen.conf.in index 3d7ad322..f466c9d4 100644 --- a/doxygen/doxygen.conf.in +++ b/doxygen/doxygen.conf.in @@ -417,7 +417,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = ../src/polyp/context.h ../src/polyp/stream.h ../src/polyp/polypaudio.h ../src/polyp/sample.h ../src/polyp/def.h ../src/polyp/subscribe.h ../src/polyp/introspect.h ../src/polyp/scache.h ../src/polyp/mainloop-api.h ../src/polyp/glib-mainloop.h ../src/polyp/mainloop.h ../src/polyp/mainloop-signal.h ../src/polyp/error.h ../src/polyp/operation.h ../src/polyp/simple.h ../src/polyp/version.h ../src/polyp/volume.h ../src/polyp/channelmap.h ../src/polyp/thread-mainloop.h ../src/polyp/xmalloc.h ../src/polyp/utf8.h ../src/polyp/util.h +INPUT = ../src/polyp/context.h ../src/polyp/stream.h ../src/polyp/polypaudio.h ../src/polyp/sample.h ../src/polyp/def.h ../src/polyp/subscribe.h ../src/polyp/introspect.h ../src/polyp/scache.h ../src/polyp/mainloop-api.h ../src/polyp/glib-mainloop.h ../src/polyp/mainloop.h ../src/polyp/mainloop-signal.h ../src/polyp/error.h ../src/polyp/operation.h ../src/polyp/simple.h ../src/polyp/version.h ../src/polyp/volume.h ../src/polyp/channelmap.h ../src/polyp/thread-mainloop.h ../src/polyp/xmalloc.h ../src/polyp/utf8.h ../src/polyp/util.h ../src/polyp/timeval.h # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp diff --git a/src/Makefile.am b/src/Makefile.am index e7ad2fd4..b0401e65 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -351,6 +351,7 @@ libpolyp_la_SOURCES = \ polyp/stream.c polyp/stream.h \ polyp/subscribe.c polyp/subscribe.h \ polyp/sample.c polyp/sample.h \ + polyp/timeval.c polyp/timeval.h \ polyp/volume.c polyp/volume.h \ polyp/utf8.c polyp/utf8.h \ polyp/mainloop.c polyp/mainloop.h \ @@ -493,9 +494,10 @@ libpolypcore_la_SOURCES = \ polyp/mainloop-signal.c polyp/mainloop-signal.h \ polyp/sample.c polyp/sample.h \ polyp/volume.c polyp/volume.h \ + polyp/timeval.c polyp/timeval.h \ polyp/utf8.c polyp/utf8.h \ - polyp/xmalloc.c polyp/xmalloc.h \ - polyp/util.c polyp/util.h + polyp/util.c polyp/util.h \ + polyp/xmalloc.c polyp/xmalloc.h # Pure core stuff (some are shared in libpolyp though). libpolypcore_la_SOURCES += \ diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 5047fc30..037cbaf7 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -26,6 +26,7 @@ #include #include +#include #include #include diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index 78850011..a1555e67 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -33,6 +33,7 @@ #include #include +#include #include #include diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 81c32287..758d1bd6 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -31,6 +31,7 @@ #include #include +#include #include #include diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index a1196a2d..56fc91ef 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -31,6 +31,7 @@ #include #include +#include #include #include diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index a88ea76a..4ca2b1e6 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -32,6 +32,7 @@ #include #include +#include #include #include diff --git a/src/polyp/glib12-mainloop.c b/src/polyp/glib12-mainloop.c index f7459f19..dfd6ff2f 100644 --- a/src/polyp/glib12-mainloop.c +++ b/src/polyp/glib12-mainloop.c @@ -25,6 +25,7 @@ #include +#include #include #include diff --git a/src/polyp/mainloop.c b/src/polyp/mainloop.c index 8f44c180..6b5b3b25 100644 --- a/src/polyp/mainloop.c +++ b/src/polyp/mainloop.c @@ -44,6 +44,7 @@ #include "../polypcore/pipe.h" #endif +#include #include #include diff --git a/src/polyp/polypaudio.h b/src/polyp/polypaudio.h index 51e3f970..c172315b 100644 --- a/src/polyp/polypaudio.h +++ b/src/polyp/polypaudio.h @@ -41,6 +41,7 @@ #include #include #include +#include /** \file * Include all polyplib header files at once. The following @@ -48,7 +49,8 @@ * \ref context.h, \ref stream.h, \ref introspect.h, \ref subscribe.h, * \ref scache.h, \ref version.h, \ref error.h, \ref channelmap.h, * \ref operation.h,\ref volume.h, \ref xmalloc.h, \ref utf8.h, \ref - * thread-mainloop.h, \ref mainloop.h, \ref util.h and \ref mainloop-signal.h at once */ + * thread-mainloop.h, \ref mainloop.h, \ref util.h, \ref timeval.h and + * \ref mainloop-signal.h at once */ /** \mainpage * diff --git a/src/polyp/timeval.c b/src/polyp/timeval.c new file mode 100644 index 00000000..6043d7fd --- /dev/null +++ b/src/polyp/timeval.c @@ -0,0 +1,142 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include "../polypcore/winsock.h" + +#include "timeval.h" + +struct timeval *pa_gettimeofday(struct timeval *tv) { +#ifdef HAVE_GETTIMEOFDAY + assert(tv); + + return gettimeofday(tv, NULL) < 0 ? NULL : tv; +#elif defined(OS_IS_WIN32) + /* + * Copied from implementation by Steven Edwards (LGPL). + * Found on wine mailing list. + */ + +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define EPOCHFILETIME (116444736000000000i64) +#else +#define EPOCHFILETIME (116444736000000000LL) +#endif + + FILETIME ft; + LARGE_INTEGER li; + __int64 t; + + assert(tv); + + GetSystemTimeAsFileTime(&ft); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + t = li.QuadPart; /* In 100-nanosecond intervals */ + t -= EPOCHFILETIME; /* Offset to the Epoch time */ + t /= 10; /* In microseconds */ + tv->tv_sec = (long)(t / 1000000); + tv->tv_usec = (long)(t % 1000000); + + return tv; +#else +#error "Platform lacks gettimeofday() or equivalent function." +#endif +} + +pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { + pa_usec_t r; + assert(a && b); + + /* Check which whan is the earlier time and swap the two arguments if reuqired. */ + if (pa_timeval_cmp(a, b) < 0) { + const struct timeval *c; + c = a; + a = b; + b = c; + } + + /* Calculate the second difference*/ + r = ((pa_usec_t) a->tv_sec - b->tv_sec)* 1000000; + + /* Calculate the microsecond difference */ + if (a->tv_usec > b->tv_usec) + r += ((pa_usec_t) a->tv_usec - b->tv_usec); + else if (a->tv_usec < b->tv_usec) + r -= ((pa_usec_t) b->tv_usec - a->tv_usec); + + return r; +} + +int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { + assert(a && b); + + if (a->tv_sec < b->tv_sec) + return -1; + + if (a->tv_sec > b->tv_sec) + return 1; + + if (a->tv_usec < b->tv_usec) + return -1; + + if (a->tv_usec > b->tv_usec) + return 1; + + return 0; +} + +pa_usec_t pa_timeval_age(const struct timeval *tv) { + struct timeval now; + assert(tv); + + return pa_timeval_diff(pa_gettimeofday(&now), tv); +} + +struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v) { + unsigned long secs; + assert(tv); + + secs = (v/1000000); + tv->tv_sec += (unsigned long) secs; + v -= secs*1000000; + + tv->tv_usec += v; + + /* Normalize */ + while (tv->tv_usec >= 1000000) { + tv->tv_sec++; + tv->tv_usec -= 1000000; + } + + return tv; +} diff --git a/src/polyp/timeval.h b/src/polyp/timeval.h new file mode 100644 index 00000000..9990d4ca --- /dev/null +++ b/src/polyp/timeval.h @@ -0,0 +1,53 @@ +#ifndef footimevalhfoo +#define footimevalhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/** \file + * Utility functions for handling timeval calculations */ + +PA_C_DECL_BEGIN + +struct timeval; + +/** Return the current timestamp, just like UNIX gettimeofday() */ +struct timeval *pa_gettimeofday(struct timeval *tv); + +/** Calculate the difference between the two specified timeval + * structs. */ +pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); + +/** Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwse */ +int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); + +/** Return the time difference between now and the specified timestamp */ +pa_usec_t pa_timeval_age(const struct timeval *tv); + +/** Add the specified time inmicroseconds to the specified timeval structure */ +struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v); + +PA_C_DECL_END + +#endif diff --git a/src/polyp/util.c b/src/polyp/util.c index 76b5c9b9..dcebff59 100644 --- a/src/polyp/util.c +++ b/src/polyp/util.c @@ -23,39 +23,33 @@ #include #endif -#include -#include -#include -#include #include -#include +#include #include -#include -#include -#include +#include +#include #include -#include +#include #include -#include -#include - -#ifdef HAVE_NETDB_H -#include -#endif #ifdef HAVE_PWD_H #include #endif -#ifdef HAVE_GRP_H -#include +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef HAVE_NETDB_H +#include #endif #ifdef HAVE_WINDOWS_H #include #endif -#include +#include "../polypcore/winsock.h" + #include #include @@ -154,112 +148,6 @@ char *pa_get_home_dir(char *s, size_t l) { #endif } -struct timeval *pa_gettimeofday(struct timeval *tv) { -#ifdef HAVE_GETTIMEOFDAY - assert(tv); - - return gettimeofday(tv, NULL) < 0 ? NULL : tv; -#elif defined(OS_IS_WIN32) - /* - * Copied from implementation by Steven Edwards (LGPL). - * Found on wine mailing list. - */ - -#if defined(_MSC_VER) || defined(__BORLANDC__) -#define EPOCHFILETIME (116444736000000000i64) -#else -#define EPOCHFILETIME (116444736000000000LL) -#endif - - FILETIME ft; - LARGE_INTEGER li; - __int64 t; - - assert(tv); - - GetSystemTimeAsFileTime(&ft); - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - t = li.QuadPart; /* In 100-nanosecond intervals */ - t -= EPOCHFILETIME; /* Offset to the Epoch time */ - t /= 10; /* In microseconds */ - tv->tv_sec = (long)(t / 1000000); - tv->tv_usec = (long)(t % 1000000); - - return tv; -#else -#error "Platform lacks gettimeofday() or equivalent function." -#endif -} - -pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { - pa_usec_t r; - assert(a && b); - - /* Check which whan is the earlier time and swap the two arguments if reuqired. */ - if (pa_timeval_cmp(a, b) < 0) { - const struct timeval *c; - c = a; - a = b; - b = c; - } - - /* Calculate the second difference*/ - r = ((pa_usec_t) a->tv_sec - b->tv_sec)* 1000000; - - /* Calculate the microsecond difference */ - if (a->tv_usec > b->tv_usec) - r += ((pa_usec_t) a->tv_usec - b->tv_usec); - else if (a->tv_usec < b->tv_usec) - r -= ((pa_usec_t) b->tv_usec - a->tv_usec); - - return r; -} - -int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { - assert(a && b); - - if (a->tv_sec < b->tv_sec) - return -1; - - if (a->tv_sec > b->tv_sec) - return 1; - - if (a->tv_usec < b->tv_usec) - return -1; - - if (a->tv_usec > b->tv_usec) - return 1; - - return 0; -} - -pa_usec_t pa_timeval_age(const struct timeval *tv) { - struct timeval now; - assert(tv); - - return pa_timeval_diff(pa_gettimeofday(&now), tv); -} - -struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v) { - unsigned long secs; - assert(tv); - - secs = (v/1000000); - tv->tv_sec += (unsigned long) secs; - v -= secs*1000000; - - tv->tv_usec += v; - - /* Normalize */ - while (tv->tv_usec >= 1000000) { - tv->tv_sec++; - tv->tv_usec -= 1000000; - } - - return tv; -} - char *pa_get_binary_name(char *s, size_t l) { #ifdef HAVE_READLINK diff --git a/src/polyp/util.h b/src/polyp/util.h index 8bd03f98..cd8aab0b 100644 --- a/src/polyp/util.h +++ b/src/polyp/util.h @@ -22,10 +22,8 @@ USA. ***/ -#include -#include +#include -#include #include /** \file @@ -33,8 +31,6 @@ PA_C_DECL_BEGIN -struct timeval; - /** Return the current username in the specified string buffer. */ char *pa_get_user_name(char *s, size_t l); @@ -55,22 +51,6 @@ char *pa_get_binary_name(char *s, size_t l); * component). */ const char *pa_path_get_filename(const char *p); -/** Return the current timestamp, just like UNIX gettimeofday() */ -struct timeval *pa_gettimeofday(struct timeval *tv); - -/** Calculate the difference between the two specified timeval - * structs. */ -pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); - -/** Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwse */ -int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); - -/** Return the time difference between now and the specified timestamp */ -pa_usec_t pa_timeval_age(const struct timeval *tv); - -/** Add the specified time inmicroseconds to the specified timeval structure */ -struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v); - /** Wait t milliseconds */ int pa_msleep(unsigned long t); diff --git a/src/polypcore/core-scache.c b/src/polypcore/core-scache.c index 068f2361..1ee3361f 100644 --- a/src/polypcore/core-scache.c +++ b/src/polypcore/core-scache.c @@ -43,6 +43,7 @@ #include #include +#include #include #include diff --git a/src/polypcore/core.c b/src/polypcore/core.c index 43f7015e..09d023dc 100644 --- a/src/polypcore/core.c +++ b/src/polypcore/core.c @@ -28,6 +28,7 @@ #include #include +#include #include #include diff --git a/src/polypcore/module.c b/src/polypcore/module.c index 52cde9c3..0286bba8 100644 --- a/src/polypcore/module.c +++ b/src/polypcore/module.c @@ -30,6 +30,7 @@ #include #include +#include #include #include diff --git a/src/polypcore/pdispatch.c b/src/polypcore/pdispatch.c index 4b0d1bb2..c6f90bac 100644 --- a/src/polypcore/pdispatch.c +++ b/src/polypcore/pdispatch.c @@ -27,6 +27,7 @@ #include #include +#include #include #include diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index 98738728..c11bdb21 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -31,6 +31,7 @@ #include #include +#include #include #include diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index f0e50ec5..0a408c6d 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include diff --git a/src/polypcore/socket-client.c b/src/polypcore/socket-client.c index 4fb0a5d8..ec2f9a9e 100644 --- a/src/polypcore/socket-client.c +++ b/src/polypcore/socket-client.c @@ -54,6 +54,7 @@ #include "winsock.h" +#include #include #include diff --git a/src/tests/mainloop-test.c b/src/tests/mainloop-test.c index 30088483..2936420c 100644 --- a/src/tests/mainloop-test.c +++ b/src/tests/mainloop-test.c @@ -28,6 +28,8 @@ #include #include +#include + #include #include diff --git a/src/tests/thread-mainloop-test.c b/src/tests/thread-mainloop-test.c index 676b8d37..70144431 100644 --- a/src/tests/thread-mainloop-test.c +++ b/src/tests/thread-mainloop-test.c @@ -28,6 +28,8 @@ #include #include +#include + #include #include #include -- cgit From 9ec9d2873eaf2ffcfa4214858eaad814a297b502 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 18 May 2006 06:46:27 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@927 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/todo b/doc/todo index 79b1894a..98db8194 100644 --- a/doc/todo +++ b/doc/todo @@ -25,6 +25,7 @@ Post 0.8: - iconv stuff sent from utils to server (UTF-8) - iconv stuff leaving the server (e.g. syslog). Sample loading probably needs help as well. +- Document utf8.h, timeval.h and util.h Long term: - pass meta info for hearing impaired -- cgit From 3ee205141280ff4246f9fe40521f666b6d598fc5 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 18 May 2006 06:53:54 +0000 Subject: PATH_MAX needs limits.h. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@928 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/util.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/polyp/util.c b/src/polyp/util.c index dcebff59..ed59a5c6 100644 --- a/src/polyp/util.c +++ b/src/polyp/util.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include -- cgit From 24a781992bad4d66bb7bc3a2d1deeba7e959dbb1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 18 May 2006 07:04:41 +0000 Subject: Don't include util.h from core-util.h as it is not needed by many users. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@929 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/dumpmodules.c | 3 ++- src/modules/module-tunnel.c | 1 + src/modules/rtp/module-rtp-send.c | 1 + src/polypcore/authkey.c | 1 + src/polypcore/core-scache.c | 1 + src/polypcore/core-util.h | 1 - src/polypcore/parseaddr.c | 1 + src/polypcore/protocol-native.c | 2 +- src/polypcore/socket-server.c | 1 + src/tests/thread-mainloop-test.c | 2 +- src/utils/pacmd.c | 2 ++ 11 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/daemon/dumpmodules.c b/src/daemon/dumpmodules.c index b6a3bb7c..d56bb798 100644 --- a/src/daemon/dumpmodules.c +++ b/src/daemon/dumpmodules.c @@ -29,8 +29,9 @@ #include #include +#include + #include -#include #include "dumpmodules.h" diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 758d1bd6..bf1fafb3 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -32,6 +32,7 @@ #include #include +#include #include #include diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 4ca2b1e6..1372414c 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -33,6 +33,7 @@ #include #include +#include #include #include diff --git a/src/polypcore/authkey.c b/src/polypcore/authkey.c index 1231c7a2..aee54fd4 100644 --- a/src/polypcore/authkey.c +++ b/src/polypcore/authkey.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include diff --git a/src/polypcore/core-scache.c b/src/polypcore/core-scache.c index 1ee3361f..5cb38bee 100644 --- a/src/polypcore/core-scache.c +++ b/src/polypcore/core-scache.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include diff --git a/src/polypcore/core-util.h b/src/polypcore/core-util.h index d3db756f..989f8c16 100644 --- a/src/polypcore/core-util.h +++ b/src/polypcore/core-util.h @@ -28,7 +28,6 @@ #include #include -#include struct timeval; diff --git a/src/polypcore/parseaddr.c b/src/polypcore/parseaddr.c index b2c7d1c7..d0687b05 100644 --- a/src/polypcore/parseaddr.c +++ b/src/polypcore/parseaddr.c @@ -29,6 +29,7 @@ #include +#include #include #include "parseaddr.h" diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 0a408c6d..a300c45d 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -46,7 +47,6 @@ #include #include #include -#include #include #include #include diff --git a/src/polypcore/socket-server.c b/src/polypcore/socket-server.c index 96f8e073..592b6a63 100644 --- a/src/polypcore/socket-server.c +++ b/src/polypcore/socket-server.c @@ -63,6 +63,7 @@ #include "winsock.h" #include +#include #include #include diff --git a/src/tests/thread-mainloop-test.c b/src/tests/thread-mainloop-test.c index 70144431..aef3aff0 100644 --- a/src/tests/thread-mainloop-test.c +++ b/src/tests/thread-mainloop-test.c @@ -29,9 +29,9 @@ #include #include +#include #include -#include #include static void tcb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) { diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c index fefe7634..539d205e 100644 --- a/src/utils/pacmd.c +++ b/src/utils/pacmd.c @@ -32,6 +32,8 @@ #include #include +#include + #include #include #include -- cgit From 40d9f5d00d99d55d3dbb20801c4842ae8d0d95ac Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 18 May 2006 07:07:27 +0000 Subject: Missing include of util.h. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@930 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-http.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/polypcore/protocol-http.c b/src/polypcore/protocol-http.c index 68864237..86ea3b15 100644 --- a/src/polypcore/protocol-http.c +++ b/src/polypcore/protocol-http.c @@ -28,6 +28,7 @@ #include #include +#include #include #include -- cgit From 4981092a797c18c1be8f2d5e0864c8b30f4130a0 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 18 May 2006 08:19:07 +0000 Subject: And functions for convertion to and from current locale and UTF-8. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@931 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- src/polyp/utf8.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/polyp/utf8.h | 6 +++++ 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 18332405..9974c29c 100644 --- a/configure.ac +++ b/configure.ac @@ -156,7 +156,7 @@ AM_CONDITIONAL(OS_IS_WIN32, test "x$os_is_win32" = "x1") AC_HEADER_STDC # POSIX -AC_CHECK_HEADERS([arpa/inet.h glob.h grp.h netdb.h netinet/in.h \ +AC_CHECK_HEADERS([arpa/inet.h glob.h grp.h iconv.h netdb.h netinet/in.h \ netinet/in_systm.h netinet/ip.h netinet/tcp.h pwd.h sched.h \ sys/resource.h sys/select.h sys/socket.h sys/wait.h \ syslog.h]) diff --git a/src/polyp/utf8.c b/src/polyp/utf8.c index 300a54ca..931328e5 100644 --- a/src/polyp/utf8.c +++ b/src/polyp/utf8.c @@ -29,10 +29,15 @@ #endif #include +#include #include #include #include +#ifdef HAVE_ICONV_H +#include +#endif + #include "utf8.h" #include "xmalloc.h" @@ -162,3 +167,70 @@ char* pa_utf8_filter (const char *str) { return utf8_validate(str, new_str); } + +#ifdef HAVE_ICONV_H + +static char* iconv_simple(const char *str, const char *to, const char *from) { + char *new_str; + size_t len, inlen; + + iconv_t cd; + char *inbuf, *outbuf; + size_t res, inbytes, outbytes; + + cd = iconv_open(to, from); + if (cd == (iconv_t)-1) + return NULL; + + inlen = len = strlen(str) + 1; + new_str = pa_xmalloc(len); + assert(new_str); + + while (1) { + inbuf = (char*)str; /* Brain dead prototype for iconv() */ + inbytes = inlen; + outbuf = new_str; + outbytes = len; + + res = iconv(cd, &inbuf, &inbytes, &outbuf, &outbytes); + + if (res != (size_t)-1) + break; + + if (errno != E2BIG) { + pa_xfree(new_str); + new_str = NULL; + break; + } + + assert(inbytes != 0); + + len += inbytes; + new_str = pa_xrealloc(new_str, len); + assert(new_str); + } + + iconv_close(cd); + + return new_str; +} + +char* pa_utf8_to_locale (const char *str) { + return iconv_simple(str, "", "UTF-8"); +} + +char* pa_locale_to_utf8 (const char *str) { + return iconv_simple(str, "UTF-8", ""); +} + +#else + +char* pa_utf8_to_locale (const char *str) { + return NULL; +} + +char* pa_locale_to_utf8 (const char *str) { + return NULL; +} + +#endif diff --git a/src/polyp/utf8.h b/src/polyp/utf8.h index 3cc3a7d0..55b8d2e4 100644 --- a/src/polyp/utf8.h +++ b/src/polyp/utf8.h @@ -36,6 +36,12 @@ const char *pa_utf8_valid(const char *str); /** Filter all invalid UTF8 characters from the specified string, returning a new fully UTF8 valid string. Don't forget to free the returned string with pa_xfree() */ char *pa_utf8_filter(const char *str); +/** Convert a UTF-8 string to the current locale. Free the string using pa_xfree(). */ +char* pa_utf8_to_locale (const char *str); + +/** Convert a string in the current locale to UTF-8. Free the string using pa_xfree(). */ +char* pa_locale_to_utf8 (const char *str); + PA_C_DECL_END #endif -- cgit From 83591883d8bcec475e74881b3f9cbcb84900c7ec Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 18 May 2006 08:21:41 +0000 Subject: Make paplay convert names to UTF-8 before sending to the server. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@932 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/paplay.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/utils/paplay.c b/src/utils/paplay.c index b66c13da..effc2a11 100644 --- a/src/utils/paplay.c +++ b/src/utils/paplay.c @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -236,6 +237,8 @@ int main(int argc, char *argv[]) { {NULL, 0, NULL, 0} }; + setlocale(LC_ALL, ""); + if (!(bn = strrchr(argv[0], '/'))) bn = argv[0]; else @@ -348,12 +351,23 @@ int main(int argc, char *argv[]) { goto quit; } - if (!client_name) - client_name = pa_xstrdup(bn); + if (!client_name) { + client_name = pa_locale_to_utf8(bn); + if (!client_name) + client_name = pa_utf8_filter(bn); + } if (!stream_name) { - const char *n = sf_get_string(sndfile, SF_STR_TITLE); - stream_name = pa_xstrdup(n ? n : filename); + const char *n; + + n = sf_get_string(sndfile, SF_STR_TITLE); + + if (!n) + n = filename; + + stream_name = pa_locale_to_utf8(n); + if (!stream_name) + stream_name = pa_utf8_filter(n); } if (verbose) { -- cgit From 13798312efde92a618a024064b1b2f2f69dfddaa Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 18 May 2006 10:36:36 +0000 Subject: Convert log text to current locale before passing it on to stderr or syslog. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@933 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/main.c | 3 +++ src/polypcore/log.c | 35 ++++++++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/daemon/main.c b/src/daemon/main.c index 9b9ea180..b4bc4e00 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -161,6 +162,8 @@ int main(int argc, char *argv[]) { struct timeval tv; #endif + setlocale(LC_ALL, ""); + pa_limit_caps(); #ifdef HAVE_GETUID diff --git a/src/polypcore/log.c b/src/polypcore/log.c index 3f5dfa08..ce9df1a9 100644 --- a/src/polypcore/log.c +++ b/src/polypcore/log.c @@ -33,6 +33,7 @@ #include #endif +#include #include #include @@ -41,7 +42,7 @@ #define ENV_LOGLEVEL "POLYP_LOG" -static char *log_ident = NULL; +static char *log_ident = NULL, *log_ident_local = NULL; static pa_log_target_t log_target = PA_LOG_STDERR; static void (*user_log_func)(pa_log_level_t l, const char *s) = NULL; static pa_log_level_t maximal_level = PA_LOG_NOTICE; @@ -59,8 +60,13 @@ static const int level_to_syslog[] = { void pa_log_set_ident(const char *p) { if (log_ident) pa_xfree(log_ident); + if (log_ident_local) + pa_xfree(log_ident_local); log_ident = pa_xstrdup(p); + log_ident_local = pa_utf8_to_locale(log_ident); + if (!log_ident_local) + log_ident_local = pa_xstrdup(log_ident); } void pa_log_set_maximal_level(pa_log_level_t l) { @@ -100,6 +106,7 @@ void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { switch (log_target) { case PA_LOG_STDERR: { const char *prefix = "", *suffix = ""; + char *local_t; #ifndef OS_IS_WIN32 /* Yes indeed. Useless, but fun! */ @@ -114,16 +121,34 @@ void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { } #endif - fprintf(stderr, "%s%s%s\n", prefix, t, suffix); + local_t = pa_utf8_to_locale(t); + if (!local_t) + fprintf(stderr, "%s%s%s\n", prefix, t, suffix); + else { + fprintf(stderr, "%s%s%s\n", prefix, local_t, suffix); + pa_xfree(local_t); + } + break; } #ifdef HAVE_SYSLOG_H - case PA_LOG_SYSLOG: - openlog(log_ident ? log_ident : "???", LOG_PID, LOG_USER); - syslog(level_to_syslog[level], "%s", t); + case PA_LOG_SYSLOG: { + char *local_t; + + openlog(log_ident_local ? log_ident_local : "???", LOG_PID, LOG_USER); + + local_t = pa_utf8_to_locale(t); + if (!local_t) + syslog(level_to_syslog[level], "%s", t); + else { + syslog(level_to_syslog[level], "%s", local_t); + pa_xfree(local_t); + } + closelog(); break; + } #endif case PA_LOG_USER: -- cgit From 1dfe8f83408d30837e8af7a1bc005c04dde2cc76 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 18 May 2006 10:36:50 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@934 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/todo b/doc/todo index 98db8194..80658d23 100644 --- a/doc/todo +++ b/doc/todo @@ -26,6 +26,8 @@ Post 0.8: - iconv stuff leaving the server (e.g. syslog). Sample loading probably needs help as well. - Document utf8.h, timeval.h and util.h +- strerror() needs to be wrapped as it returns stuff in the current locale + and we tend to pass it to functions that require UTF-8. Long term: - pass meta info for hearing impaired -- cgit From c811351d2823f1bad06050ef019930685c0d0c28 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 19 May 2006 07:29:34 +0000 Subject: Sort source files. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@935 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 56 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index b0401e65..5d7fde18 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -288,27 +288,27 @@ sync_playback_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) polypinclude_HEADERS = \ polyp/cdecl.h \ polyp/channelmap.h \ - polyp/glib-mainloop.h \ - polyp/mainloop.h \ - polyp/mainloop-api.h \ - polyp/mainloop-signal.h \ - polyp/thread-mainloop.h \ - polyp/polypaudio.h \ polyp/context.h \ polyp/def.h \ polyp/error.h \ + polyp/glib-mainloop.h \ polyp/introspect.h \ + polyp/mainloop.h \ + polyp/mainloop-api.h \ + polyp/mainloop-signal.h \ polyp/operation.h \ + polyp/polypaudio.h \ + polyp/sample.h \ polyp/scache.h \ polyp/simple.h \ polyp/stream.h \ polyp/subscribe.h \ - polyp/version.h \ - polyp/sample.h \ + polyp/thread-mainloop.h \ polyp/utf8.h \ + polyp/util.h \ + polyp/version.h \ polyp/volume.h \ - polyp/xmalloc.h \ - polyp/util.h + polyp/xmalloc.h if HAVE_HOWL polypinclude_HEADERS += \ @@ -339,36 +339,38 @@ libpolyp_la_SOURCES = \ polyp/cdecl.h \ polyp/channelmap.c polyp/channelmap.h \ polyp/client-conf.c polyp/client-conf.h \ - polyp/mainloop-api.c polyp/mainloop-api.h \ - polyp/polypaudio.h \ polyp/context.c polyp/context.h \ polyp/def.h \ polyp/error.c polyp/error.h \ polyp/internal.h \ polyp/introspect.c polyp/introspect.h \ + polyp/mainloop.c polyp/mainloop.h \ + polyp/mainloop-api.c polyp/mainloop-api.h \ + polyp/mainloop-signal.c polyp/mainloop-signal.h \ polyp/operation.c polyp/operation.h \ + polyp/polypaudio.h \ + polyp/sample.c polyp/sample.h \ polyp/scache.c polyp/scache.h \ polyp/stream.c polyp/stream.h \ polyp/subscribe.c polyp/subscribe.h \ - polyp/sample.c polyp/sample.h \ + polyp/thread-mainloop.c polyp/thread-mainloop.h \ polyp/timeval.c polyp/timeval.h \ - polyp/volume.c polyp/volume.h \ polyp/utf8.c polyp/utf8.h \ - polyp/mainloop.c polyp/mainloop.h \ - polyp/mainloop-signal.c polyp/mainloop-signal.h \ - polyp/thread-mainloop.c polyp/thread-mainloop.h \ - polyp/xmalloc.c polyp/xmalloc.h \ - polyp/util.c polyp/util.h + polyp/util.c polyp/util.h \ + polyp/volume.c polyp/volume.h \ + polyp/xmalloc.c polyp/xmalloc.h # Internal stuff that is shared with libpolypcore libpolyp_la_SOURCES += \ polypcore/authkey.c polypcore/authkey.h \ polypcore/conf-parser.c polypcore/conf-parser.h \ + polypcore/core-util.c polypcore/core-util.h \ polypcore/dynarray.c polypcore/dynarray.h \ polypcore/gccmacro.h \ polypcore/hashmap.c polypcore/hashmap.h \ polypcore/idxset.c polypcore/idxset.h \ polypcore/iochannel.c polypcore/iochannel.h \ + polypcore/llist.h \ polypcore/log.c polypcore/log.h \ polypcore/mcalign.c polypcore/mcalign.h \ polypcore/memblock.c polypcore/memblock.h \ @@ -378,6 +380,8 @@ libpolyp_la_SOURCES += \ polypcore/packet.c polypcore/packet.h \ polypcore/parseaddr.c polypcore/parseaddr.h \ polypcore/pdispatch.c polypcore/pdispatch.h \ + polypcore/pipe.c polypcore/pipe.h \ + polypcore/poll.c polypcore/poll.h \ polypcore/pstream.c polypcore/pstream.h \ polypcore/pstream-util.c polypcore/pstream-util.h \ polypcore/queue.c polypcore/queue.h \ @@ -387,11 +391,7 @@ libpolyp_la_SOURCES += \ polypcore/strbuf.c polypcore/strbuf.h \ polypcore/strlist.c polypcore/strlist.h \ polypcore/tagstruct.c polypcore/tagstruct.h \ - polypcore/core-util.c polypcore/core-util.h \ - polypcore/winsock.h \ - polypcore/llist.h \ - polypcore/pipe.c polypcore/pipe.h \ - polypcore/poll.c polypcore/poll.h + polypcore/winsock.h if OS_IS_WIN32 libpolyp_la_SOURCES += \ @@ -452,6 +452,7 @@ polypcoreinclude_HEADERS = \ polypcore/core-scache.h \ polypcore/core-subscribe.h \ polypcore/conf-parser.h \ + polypcore/core-util.h \ polypcore/dynarray.h \ polypcore/g711.h \ polypcore/hashmap.h \ @@ -481,8 +482,7 @@ polypcoreinclude_HEADERS = \ polypcore/source.h \ polypcore/source-output.h \ polypcore/strbuf.h \ - polypcore/tokenizer.h \ - polypcore/core-util.h + polypcore/tokenizer.h lib_LTLIBRARIES += libpolypcore.la @@ -493,10 +493,10 @@ libpolypcore_la_SOURCES = \ polyp/mainloop-api.c polyp/mainloop-api.h \ polyp/mainloop-signal.c polyp/mainloop-signal.h \ polyp/sample.c polyp/sample.h \ - polyp/volume.c polyp/volume.h \ polyp/timeval.c polyp/timeval.h \ polyp/utf8.c polyp/utf8.h \ polyp/util.c polyp/util.h \ + polyp/volume.c polyp/volume.h \ polyp/xmalloc.c polyp/xmalloc.h # Pure core stuff (some are shared in libpolyp though). @@ -509,6 +509,7 @@ libpolypcore_la_SOURCES += \ polypcore/core.c polypcore/core.h \ polypcore/core-scache.c polypcore/core-scache.h \ polypcore/core-subscribe.c polypcore/core-subscribe.h \ + polypcore/core-util.c polypcore/core-util.h \ polypcore/dynarray.c polypcore/dynarray.h \ polypcore/endianmacros.h \ polypcore/g711.c polypcore/g711.h \ @@ -544,7 +545,6 @@ libpolypcore_la_SOURCES += \ polypcore/source-output.c polypcore/source-output.h \ polypcore/strbuf.c polypcore/strbuf.h \ polypcore/tokenizer.c polypcore/tokenizer.h \ - polypcore/core-util.c polypcore/core-util.h \ polypcore/winsock.h if OS_IS_WIN32 -- cgit From a034b61eb5a9bd897349be425b28c42b87f63d65 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 19 May 2006 07:38:35 +0000 Subject: Fix which headers get installed for libpolyp. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@936 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index 5d7fde18..e93210aa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -291,7 +291,6 @@ polypinclude_HEADERS = \ polyp/context.h \ polyp/def.h \ polyp/error.h \ - polyp/glib-mainloop.h \ polyp/introspect.h \ polyp/mainloop.h \ polyp/mainloop-api.h \ @@ -304,6 +303,7 @@ polypinclude_HEADERS = \ polyp/stream.h \ polyp/subscribe.h \ polyp/thread-mainloop.h \ + polyp/timeval.h \ polyp/utf8.h \ polyp/util.h \ polyp/version.h \ @@ -315,6 +315,16 @@ polypinclude_HEADERS += \ polyp/browser.h endif +if HAVE_GLIB20 +polypinclude_HEADERS += \ + polyp/glib-mainloop.h +else +if HAVE_GLIB12 +polypinclude_HEADERS += \ + polyp/glib-mainloop.h +endif +endif + lib_LTLIBRARIES = \ libpolyp.la \ libpolyp-simple.la -- cgit From a3fe39ac4168d9521dc12c8e27eb8040ff078f5e Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 19 May 2006 11:32:32 +0000 Subject: Fix some missing headers. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@937 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-x11-publish.c | 1 + src/polyp/stream.c | 2 +- src/utils/pax11publish.c | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c index eddcb3b8..70d75038 100644 --- a/src/modules/module-x11-publish.c +++ b/src/modules/module-x11-publish.c @@ -32,6 +32,7 @@ #include #include +#include #include #include diff --git a/src/polyp/stream.c b/src/polyp/stream.c index ad6c9e43..2e168045 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -29,10 +29,10 @@ #include #include +#include #include #include -#include #include #include diff --git a/src/utils/pax11publish.c b/src/utils/pax11publish.c index ee0cb845..668361c6 100644 --- a/src/utils/pax11publish.c +++ b/src/utils/pax11publish.c @@ -31,6 +31,8 @@ #include #include +#include + #include #include #include -- cgit From acc655235663f223f10bd26c6e6d1ebc6331d9bd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 19 May 2006 17:40:44 +0000 Subject: generate PA_MAJORMINOR properly - only from major and minor, not from micro git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@938 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 9974c29c..445e26be 100644 --- a/configure.ac +++ b/configure.ac @@ -20,12 +20,17 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. AC_PREREQ(2.57) -AC_INIT([polypaudio],[0.9.0],[mzcbylcnhqvb (at) 0pointer (dot) de]) + +m4_define(PA_MAJOR, [0]) +m4_define(PA_MINOR, [9]) +m4_define(PA_MICRO, [0]) + +AC_INIT([polypaudio], PA_MAJOR.PA_MINOR.PA_MICRO,[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([src/daemon/main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) -AC_SUBST(PA_MAJORMINOR, "$PACKAGE_VERSION") +AC_SUBST(PA_MAJORMINOR, "PA_MAJOR.PA_MINOR") AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/polypaudio/]) AC_SUBST(PA_API_VERSION, 9) -- cgit From cc61b57a325ee688b74ca2cbd5e281e7f76b71c0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 20 May 2006 14:59:02 +0000 Subject: rename pa_simple_get_playback_latency() to pa_simple_get_latency() and allow its usage on capture streams git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@939 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/simple.c | 4 +--- src/polyp/simple.h | 2 +- src/tests/pacat-simple.c | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/polyp/simple.c b/src/polyp/simple.c index 84c46bf1..9c2c908c 100644 --- a/src/polyp/simple.c +++ b/src/polyp/simple.c @@ -423,14 +423,12 @@ unlock_and_fail: return -1; } -pa_usec_t pa_simple_get_playback_latency(pa_simple *p, int *rerror) { +pa_usec_t pa_simple_get_latency(pa_simple *p, int *rerror) { pa_usec_t t; int negative; assert(p); - CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, (pa_usec_t) -1); - pa_threaded_mainloop_lock(p->mainloop); for (;;) { diff --git a/src/polyp/simple.h b/src/polyp/simple.h index bf3cc330..b97e844b 100644 --- a/src/polyp/simple.h +++ b/src/polyp/simple.h @@ -136,7 +136,7 @@ int pa_simple_drain(pa_simple *s, int *error); int pa_simple_read(pa_simple *s, void*data, size_t length, int *error); /** Return the playback latency. \since 0.5 */ -pa_usec_t pa_simple_get_playback_latency(pa_simple *s, int *error); +pa_usec_t pa_simple_get_latency(pa_simple *s, int *error); /** Flush the playback buffer. \since 0.5 */ int pa_simple_flush(pa_simple *s, int *error); diff --git a/src/tests/pacat-simple.c b/src/tests/pacat-simple.c index 544c31e3..9d8cc921 100644 --- a/src/tests/pacat-simple.c +++ b/src/tests/pacat-simple.c @@ -78,8 +78,8 @@ int main(PA_GCC_UNUSED int argc, char*argv[]) { #if 0 pa_usec_t latency; - if ((latency = pa_simple_get_playback_latency(s, &error)) == (pa_usec_t) -1) { - fprintf(stderr, __FILE__": pa_simple_get_playback_latency() failed: %s\n", pa_strerror(error)); + if ((latency = pa_simple_get_latency(s, &error)) == (pa_usec_t) -1) { + fprintf(stderr, __FILE__": pa_simple_get_latency() failed: %s\n", pa_strerror(error)); goto finish; } -- cgit From 13329d36dfb5950c5917ab4b6d0939e7ae1100a0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 20 May 2006 15:00:16 +0000 Subject: fix long-standing buf that could cause polypaudio to eat 100% CPU: fix handling of event bits for pa_iochannel git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@940 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/iochannel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/polypcore/iochannel.c b/src/polypcore/iochannel.c index b953a1d0..10997d62 100644 --- a/src/polypcore/iochannel.c +++ b/src/polypcore/iochannel.c @@ -69,17 +69,17 @@ static void enable_mainloop_sources(pa_iochannel *io) { pa_io_event_flags_t f = PA_IO_EVENT_NULL; assert(io->input_event); - if (!pa_iochannel_is_readable(io)) + if (!io->readable) f |= PA_IO_EVENT_INPUT; - if (!pa_iochannel_is_writable(io)) + if (!io->writable) f |= PA_IO_EVENT_OUTPUT; io->mainloop->io_enable(io->input_event, f); } else { if (io->input_event) - io->mainloop->io_enable(io->input_event, pa_iochannel_is_readable(io) ? PA_IO_EVENT_NULL : PA_IO_EVENT_INPUT); + io->mainloop->io_enable(io->input_event, io->readable ? PA_IO_EVENT_NULL : PA_IO_EVENT_INPUT); if (io->output_event) - io->mainloop->io_enable(io->output_event, pa_iochannel_is_writable(io) ? PA_IO_EVENT_NULL : PA_IO_EVENT_OUTPUT); + io->mainloop->io_enable(io->output_event, io->writable ? PA_IO_EVENT_NULL : PA_IO_EVENT_OUTPUT); } } -- cgit From bc87137a8f26152a0589e94e0bc8ffc936566ed6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 20 May 2006 19:27:47 +0000 Subject: doc update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@941 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/todo b/doc/todo index 80658d23..c2d20a05 100644 --- a/doc/todo +++ b/doc/todo @@ -28,6 +28,7 @@ Post 0.8: - Document utf8.h, timeval.h and util.h - strerror() needs to be wrapped as it returns stuff in the current locale and we tend to pass it to functions that require UTF-8. +- fix clock of the NULL sink Long term: - pass meta info for hearing impaired -- cgit From 651e575575c307be75e050ed9600d35a43b7819c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 May 2006 14:06:33 +0000 Subject: add new function pa_usec_to_bytes() as inverse of pa_bytes_to_usec() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@942 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/sample.c | 6 ++++++ src/polyp/sample.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/src/polyp/sample.c b/src/polyp/sample.c index 668a485e..320e31a0 100644 --- a/src/polyp/sample.c +++ b/src/polyp/sample.c @@ -66,6 +66,12 @@ pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) { return (pa_usec_t) (((double) length/pa_frame_size(spec)*1000000)/spec->rate); } +size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec) { + assert(spec); + + return ((double) t * spec->rate / 1000000)*pa_frame_size(spec); +} + int pa_sample_spec_valid(const pa_sample_spec *spec) { assert(spec); diff --git a/src/polyp/sample.h b/src/polyp/sample.h index 09b12fd7..2a9a72fe 100644 --- a/src/polyp/sample.h +++ b/src/polyp/sample.h @@ -160,6 +160,9 @@ size_t pa_sample_size(const pa_sample_spec *spec); /** Calculate the time the specified bytes take to play with the specified sample type */ pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec); +/** Calculates the number of bytes that are required for the specified time. \since 0.9 */ +size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec); + /** Return non-zero when the sample type specification is valid */ int pa_sample_spec_valid(const pa_sample_spec *spec); -- cgit From cc84fc9e942daabe940dff20c7b46bfb132a2d22 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 May 2006 14:06:51 +0000 Subject: add missing #include git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@943 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/glib-mainloop.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/polyp/glib-mainloop.c b/src/polyp/glib-mainloop.c index 51d437d2..d5fce767 100644 --- a/src/polyp/glib-mainloop.c +++ b/src/polyp/glib-mainloop.c @@ -26,6 +26,7 @@ #include #include +#include #include #include -- cgit From bf09399d0e84c43fbae3d24b5c71dc8d85b62fe7 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 22 May 2006 15:19:50 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@944 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/todo b/doc/todo index c2d20a05..bf3365ab 100644 --- a/doc/todo +++ b/doc/todo @@ -29,6 +29,7 @@ Post 0.8: - strerror() needs to be wrapped as it returns stuff in the current locale and we tend to pass it to functions that require UTF-8. - fix clock of the NULL sink +- gettextify polypaudio Long term: - pass meta info for hearing impaired -- cgit From 4e3dc7ce68561c16254712d713b2ccd472b8afe7 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 22 May 2006 15:20:46 +0000 Subject: Wrap strerror() in a function that makes it thread safe and converts the output to UTF-8. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@945 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 3 + src/Makefile.am | 1 + src/daemon/caps.c | 4 +- src/daemon/cpulimit.c | 4 +- src/daemon/daemon-conf.c | 3 +- src/daemon/main.c | 5 +- src/modules/module-alsa-source.c | 3 +- src/modules/module-detect.c | 7 ++- src/modules/module-esound-compat-spawnfd.c | 4 +- src/modules/module-esound-compat-spawnpid.c | 4 +- src/modules/module-esound-sink.c | 11 ++-- src/modules/module-jack-sink.c | 3 +- src/modules/module-jack-source.c | 3 +- src/modules/module-match.c | 3 +- src/modules/module-mmkbd-evdev.c | 13 +++-- src/modules/module-oss-mmap.c | 29 +++++----- src/modules/module-oss.c | 17 +++--- src/modules/module-pipe-sink.c | 7 ++- src/modules/module-pipe-source.c | 7 ++- src/modules/module-protocol-stub.c | 5 +- src/modules/module-solaris.c | 15 ++--- src/modules/module-volume-restore.c | 5 +- src/modules/oss-util.c | 20 ++++--- src/modules/rtp/module-rtp-recv.c | 9 +-- src/modules/rtp/module-rtp-send.c | 11 ++-- src/modules/rtp/rtp.c | 8 ++- src/modules/rtp/sap.c | 9 +-- src/polyp/client-conf.c | 3 +- src/polyp/context.c | 7 ++- src/polyp/error.c | 90 +++++++++++++++++++++++++++++ src/polyp/error.h | 6 ++ src/polyp/mainloop-signal.c | 5 +- src/polyp/mainloop.c | 3 +- src/polyp/util.c | 4 +- src/polypcore/authkey.c | 13 +++-- src/polypcore/cli-command.c | 3 +- src/polypcore/conf-parser.c | 7 ++- src/polypcore/core-scache.c | 5 +- src/polypcore/core-util.c | 31 +++++----- src/polypcore/iochannel.c | 3 +- src/polypcore/ioline.c | 5 +- src/polypcore/log.c | 3 + src/polypcore/pid.c | 25 +++++--- src/polypcore/protocol-esound.c | 13 +++-- src/polypcore/protocol-simple.c | 5 +- src/polypcore/socket-client.c | 9 +-- src/polypcore/socket-server.c | 35 +++++------ src/polypcore/socket-util.c | 3 +- src/utils/pacmd.c | 15 ++--- 49 files changed, 337 insertions(+), 169 deletions(-) diff --git a/configure.ac b/configure.ac index 445e26be..fadc0219 100644 --- a/configure.ac +++ b/configure.ac @@ -242,6 +242,9 @@ AC_CHECK_FUNCS([readlink]) # SUSv2 AC_CHECK_FUNCS([ctime_r usleep]) +# SUSv3 +AC_CHECK_FUNCS([strerror_r]) + # BSD AC_CHECK_FUNCS([lstat]) diff --git a/src/Makefile.am b/src/Makefile.am index e93210aa..30e73512 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -499,6 +499,7 @@ lib_LTLIBRARIES += libpolypcore.la # Some public stuff is used even in the core. libpolypcore_la_SOURCES = \ polyp/channelmap.c polyp/channelmap.h \ + polyp/error.c polyp/error.h \ polyp/mainloop.c polyp/mainloop.h \ polyp/mainloop-api.c polyp/mainloop-api.h \ polyp/mainloop-signal.c polyp/mainloop-signal.h \ diff --git a/src/daemon/caps.c b/src/daemon/caps.c index 8740b7e8..4942868c 100644 --- a/src/daemon/caps.c +++ b/src/daemon/caps.c @@ -32,6 +32,8 @@ #include #endif +#include + #include #include "caps.h" @@ -110,7 +112,7 @@ int pa_drop_caps(void) { cap_clear(caps); if (cap_set_proc(caps) < 0) { - pa_log(__FILE__": failed to drop capabilities: %s", strerror(errno)); + pa_log(__FILE__": failed to drop capabilities: %s", pa_cstrerror(errno)); goto fail; } diff --git a/src/daemon/cpulimit.c b/src/daemon/cpulimit.c index 69973384..2cc37be6 100644 --- a/src/daemon/cpulimit.c +++ b/src/daemon/cpulimit.c @@ -23,6 +23,8 @@ #include #endif +#include + #include #include @@ -169,7 +171,7 @@ int pa_cpu_limit_init(pa_mainloop_api *m) { /* Prepare the main loop pipe */ if (pipe(the_pipe) < 0) { - pa_log(__FILE__": pipe() failed: %s", strerror(errno)); + pa_log(__FILE__": pipe() failed: %s", pa_cstrerror(errno)); return -1; } diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 0f4fcb97..809769f8 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -237,7 +238,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { pa_open_config_file(DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file, "r"); if (!f && errno != ENOENT) { - pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", filename, strerror(errno)); + pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", filename, pa_cstrerror(errno)); goto finish; } diff --git a/src/daemon/main.c b/src/daemon/main.c index b4bc4e00..2fadd496 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -50,6 +50,7 @@ #include "../polypcore/winsock.h" +#include #include #include #include @@ -286,7 +287,7 @@ int main(int argc, char *argv[]) { } if ((child = fork()) < 0) { - pa_log(__FILE__": fork() failed: %s", strerror(errno)); + pa_log(__FILE__": fork() failed: %s", pa_cstrerror(errno)); goto finish; } @@ -297,7 +298,7 @@ int main(int argc, char *argv[]) { daemon_pipe[1] = -1; if (pa_loop_read(daemon_pipe[0], &retval, sizeof(retval)) != sizeof(retval)) { - pa_log(__FILE__": read() failed: %s", strerror(errno)); + pa_log(__FILE__": read() failed: %s", pa_cstrerror(errno)); retval = 1; } diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 654f3e49..c72b0322 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -34,6 +34,7 @@ #include +#include #include #include @@ -134,7 +135,7 @@ static void do_read(struct userdata *u) { continue; } - pa_log(__FILE__": snd_pcm_readi() failed: %s", strerror(-frames)); + pa_log(__FILE__": snd_pcm_readi() failed: %s", pa_cstrerror(-frames)); return; } diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index 2edbea5e..e4f2e3f9 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -56,7 +57,7 @@ static int detect_alsa(pa_core *c, int just_one) { if (!(f = fopen("/proc/asound/devices", "r"))) { if (errno != ENOENT) - pa_log_error(__FILE__": open(\"/proc/asound/devices\") failed: %s", strerror(errno)); + pa_log_error(__FILE__": open(\"/proc/asound/devices\") failed: %s", pa_cstrerror(errno)); return -1; } @@ -119,7 +120,7 @@ static int detect_oss(pa_core *c, int just_one) { !(f = fopen("/proc/asound/oss/sndstat", "r"))) { if (errno != ENOENT) - pa_log_error(__FILE__": failed to open OSS sndstat device: %s", strerror(errno)); + pa_log_error(__FILE__": failed to open OSS sndstat device: %s", pa_cstrerror(errno)); return -1; } @@ -175,7 +176,7 @@ static int detect_solaris(pa_core *c, int just_one) { if (stat(dev, &s) < 0) { if (errno != ENOENT) - pa_log_error(__FILE__": failed to open device %s: %s", dev, strerror(errno)); + pa_log_error(__FILE__": failed to open device %s: %s", dev, pa_cstrerror(errno)); return -1; } diff --git a/src/modules/module-esound-compat-spawnfd.c b/src/modules/module-esound-compat-spawnfd.c index bf89ca70..f59e9e21 100644 --- a/src/modules/module-esound-compat-spawnfd.c +++ b/src/modules/module-esound-compat-spawnfd.c @@ -28,6 +28,8 @@ #include #include +#include + #include #include #include @@ -59,7 +61,7 @@ int pa__init(pa_core *c, pa_module*m) { } if (pa_loop_write(fd, &x, sizeof(x)) != sizeof(x)) - pa_log(__FILE__": WARNING: write(%u, 1, 1) failed: %s", fd, strerror(errno)); + pa_log(__FILE__": WARNING: write(%u, 1, 1) failed: %s", fd, pa_cstrerror(errno)); close(fd); diff --git a/src/modules/module-esound-compat-spawnpid.c b/src/modules/module-esound-compat-spawnpid.c index 895abec3..c14ce12a 100644 --- a/src/modules/module-esound-compat-spawnpid.c +++ b/src/modules/module-esound-compat-spawnpid.c @@ -28,6 +28,8 @@ #include #include +#include + #include #include #include @@ -59,7 +61,7 @@ int pa__init(pa_core *c, pa_module*m) { } if (kill(pid, SIGUSR1) < 0) - pa_log(__FILE__": WARNING: kill(%u) failed: %s", pid, strerror(errno)); + pa_log(__FILE__": WARNING: kill(%u) failed: %s", pid, pa_cstrerror(errno)); pa_module_unload_request(m); diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index cf3ce807..72298679 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -128,7 +129,7 @@ static int do_write(struct userdata *u) { assert(u->write_index < u->write_length); if ((r = pa_iochannel_write(u->io, (uint8_t*) u->write_data + u->write_index, u->write_length - u->write_index)) <= 0) { - pa_log(__FILE__": write() failed: %s", strerror(errno)); + pa_log(__FILE__": write() failed: %s", pa_cstrerror(errno)); return -1; } @@ -150,7 +151,7 @@ static int do_write(struct userdata *u) { assert(u->memchunk.memblock && u->memchunk.length); if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { - pa_log(__FILE__": write() failed: %s", strerror(errno)); + pa_log(__FILE__": write() failed: %s", pa_cstrerror(errno)); return -1; } @@ -175,7 +176,7 @@ static int handle_response(struct userdata *u) { /* Process auth data */ if (!*(int32_t*) u->read_data) { - pa_log(__FILE__": Authentication failed: %s", strerror(errno)); + pa_log(__FILE__": Authentication failed: %s", pa_cstrerror(errno)); return -1; } @@ -245,7 +246,7 @@ static int do_read(struct userdata *u) { assert(u->read_index < u->read_length); if ((r = pa_iochannel_read(u->io, (uint8_t*) u->read_data + u->read_index, u->read_length - u->read_index)) <= 0) { - pa_log(__FILE__": read() failed: %s", r < 0 ? strerror(errno) : "EOF"); + pa_log(__FILE__": read() failed: %s", r < 0 ? pa_cstrerror(errno) : "EOF"); cancel(u); return -1; } @@ -305,7 +306,7 @@ static void on_connection(PA_GCC_UNUSED pa_socket_client *c, pa_iochannel*io, vo u->client = NULL; if (!io) { - pa_log(__FILE__": connection failed: %s", strerror(errno)); + pa_log(__FILE__": connection failed: %s", pa_cstrerror(errno)); cancel(u); return; } diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index 96db837a..db2ba030 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -36,6 +36,7 @@ #include +#include #include #include @@ -272,7 +273,7 @@ int pa__init(pa_core *c, pa_module*m) { pthread_cond_init(&u->cond, NULL); if (pipe(u->pipe_fds) < 0) { - pa_log(__FILE__": pipe() failed: %s", strerror(errno)); + pa_log(__FILE__": pipe() failed: %s", pa_cstrerror(errno)); goto fail; } diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index 3d783145..8816fb8a 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -36,6 +36,7 @@ #include +#include #include #include @@ -270,7 +271,7 @@ int pa__init(pa_core *c, pa_module*m) { pthread_cond_init(&u->cond, NULL); if (pipe(u->pipe_fds) < 0) { - pa_log(__FILE__": pipe() failed: %s", strerror(errno)); + pa_log(__FILE__": pipe() failed: %s", pa_cstrerror(errno)); goto fail; } diff --git a/src/modules/module-match.c b/src/modules/module-match.c index c7ca12a5..f68f0c61 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -86,7 +87,7 @@ static int load_rules(struct userdata *u, const char *filename) { pa_open_config_file(DEFAULT_MATCH_TABLE_FILE, DEFAULT_MATCH_TABLE_FILE_USER, NULL, &fn, "r"); if (!f) { - pa_log(__FILE__": failed to open file '%s': %s", fn, strerror(errno)); + pa_log(__FILE__": failed to open file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c index 55f0b2c8..d6c91e2e 100644 --- a/src/modules/module-mmkbd-evdev.c +++ b/src/modules/module-mmkbd-evdev.c @@ -33,6 +33,7 @@ #include +#include #include #include @@ -89,7 +90,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC struct input_event ev; if (pa_loop_read(u->fd, &ev, sizeof(ev)) <= 0) { - pa_log(__FILE__": failed to read from event device: %s", strerror(errno)); + pa_log(__FILE__": failed to read from event device: %s", pa_cstrerror(errno)); goto fail; } @@ -183,19 +184,19 @@ int pa__init(pa_core *c, pa_module*m) { u->fd = -1; if ((u->fd = open(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), O_RDONLY)) < 0) { - pa_log(__FILE__": failed to open evdev device: %s", strerror(errno)); + pa_log(__FILE__": failed to open evdev device: %s", pa_cstrerror(errno)); goto fail; } if (ioctl(u->fd, EVIOCGVERSION, &version) < 0) { - pa_log(__FILE__": EVIOCGVERSION failed: %s", strerror(errno)); + pa_log(__FILE__": EVIOCGVERSION failed: %s", pa_cstrerror(errno)); goto fail; } pa_log_info(__FILE__": evdev driver version %i.%i.%i", version >> 16, (version >> 8) & 0xff, version & 0xff); if(ioctl(u->fd, EVIOCGID, &input_id)) { - pa_log(__FILE__": EVIOCGID failed: %s", strerror(errno)); + pa_log(__FILE__": EVIOCGID failed: %s", pa_cstrerror(errno)); goto fail; } @@ -204,7 +205,7 @@ int pa__init(pa_core *c, pa_module*m) { memset(name, 0, sizeof(name)); if(ioctl(u->fd, EVIOCGNAME(sizeof(name)), name) < 0) { - pa_log(__FILE__": EVIOCGNAME failed: %s", strerror(errno)); + pa_log(__FILE__": EVIOCGNAME failed: %s", pa_cstrerror(errno)); goto fail; } @@ -212,7 +213,7 @@ int pa__init(pa_core *c, pa_module*m) { memset(evtype_bitmask, 0, sizeof(evtype_bitmask)); if (ioctl(u->fd, EVIOCGBIT(0, EV_MAX), evtype_bitmask) < 0) { - pa_log(__FILE__": EVIOCGBIT failed: %s", strerror(errno)); + pa_log(__FILE__": EVIOCGBIT failed: %s", pa_cstrerror(errno)); goto fail; } diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index a1b40389..dac7d7f3 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -36,6 +36,7 @@ #include #include +#include #include #include @@ -152,7 +153,7 @@ static void do_write(struct userdata *u) { update_usage(u); if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETOPTR: %s", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno)); return; } @@ -215,7 +216,7 @@ static void do_read(struct userdata *u) { update_usage(u); if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETIPTR: %s", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno)); return; } @@ -246,7 +247,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { assert(s && u); if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETOPTR: %s", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno)); return 0; } @@ -272,7 +273,7 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { assert(s && u); if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETIPTR: %s", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno)); return 0; } @@ -295,7 +296,7 @@ static int sink_get_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; if (pa_oss_get_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", strerror(errno)); + pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); s->get_hw_volume = NULL; return -1; } @@ -307,7 +308,7 @@ static int sink_set_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; if (pa_oss_set_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", strerror(errno)); + pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); s->set_hw_volume = NULL; return -1; } @@ -319,7 +320,7 @@ static int source_get_hw_volume(pa_source *s) { struct userdata *u = s->userdata; if (pa_oss_get_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", strerror(errno)); + pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); s->get_hw_volume = NULL; return -1; } @@ -331,7 +332,7 @@ static int source_set_hw_volume(pa_source *s) { struct userdata *u = s->userdata; if (pa_oss_set_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", strerror(errno)); + pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); s->set_hw_volume = NULL; return -1; } @@ -413,7 +414,7 @@ int pa__init(pa_core *c, pa_module*m) { if (mode != O_WRONLY) { if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETISPACE: %s", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno)); goto fail; } @@ -425,7 +426,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log(__FILE__": mmap failed for input. Changing to O_WRONLY mode."); mode = O_WRONLY; } else { - pa_log(__FILE__": mmap(): %s", strerror(errno)); + pa_log(__FILE__": mmap(): %s", pa_cstrerror(errno)); goto fail; } } else { @@ -452,7 +453,7 @@ int pa__init(pa_core *c, pa_module*m) { if (mode != O_RDONLY) { if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETOSPACE: %s", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno)); goto fail; } @@ -464,7 +465,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log(__FILE__": mmap filed for output. Changing to O_RDONLY mode."); mode = O_RDONLY; } else { - pa_log(__FILE__": mmap(): %s", strerror(errno)); + pa_log(__FILE__": mmap(): %s", pa_cstrerror(errno)); goto fail; } } else { @@ -492,12 +493,12 @@ int pa__init(pa_core *c, pa_module*m) { zero = 0; if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero) < 0) { - pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno)); goto fail; } if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0) { - pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno)); goto fail; } diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 9233420d..8e217855 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -146,7 +147,7 @@ static void do_write(struct userdata *u) { assert(memchunk->length); if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { - pa_log(__FILE__": write() failed: %s", strerror(errno)); + pa_log(__FILE__": write() failed: %s", pa_cstrerror(errno)); break; } @@ -199,7 +200,7 @@ static void do_read(struct userdata *u) { if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); if (errno != EAGAIN) - pa_log(__FILE__": read() failed: %s", strerror(errno)); + pa_log(__FILE__": read() failed: %s", pa_cstrerror(errno)); break; } @@ -234,7 +235,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { assert(s && u && u->sink); if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { - pa_log_info(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY: %s", strerror(errno)); + pa_log_info(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY: %s", pa_cstrerror(errno)); s->get_latency = NULL; return 0; } @@ -270,7 +271,7 @@ static int sink_get_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; if (pa_oss_get_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", strerror(errno)); + pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); s->get_hw_volume = NULL; return -1; } @@ -282,7 +283,7 @@ static int sink_set_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; if (pa_oss_set_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", strerror(errno)); + pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); s->set_hw_volume = NULL; return -1; } @@ -294,7 +295,7 @@ static int source_get_hw_volume(pa_source *s) { struct userdata *u = s->userdata; if (pa_oss_get_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", strerror(errno)); + pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); s->get_hw_volume = NULL; return -1; } @@ -306,7 +307,7 @@ static int source_set_hw_volume(pa_source *s) { struct userdata *u = s->userdata; if (pa_oss_set_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", strerror(errno)); + pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); s->set_hw_volume = NULL; return -1; } @@ -380,7 +381,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETBLKSIZE: %s", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno)); goto fail; } assert(frag_size); diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index 6492ba6a..f0569ce9 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -99,7 +100,7 @@ static void do_write(struct userdata *u) { assert(u->memchunk.memblock && u->memchunk.length); if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { - pa_log(__FILE__": write() failed: %s", strerror(errno)); + pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); return; } @@ -163,14 +164,14 @@ int pa__init(pa_core *c, pa_module*m) { mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777); if ((fd = open(p, O_RDWR)) < 0) { - pa_log(__FILE__": open('%s'): %s", p, strerror(errno)); + pa_log(__FILE__": open('%s'): %s", p, pa_cstrerror(errno)); goto fail; } pa_fd_set_cloexec(fd, 1); if (fstat(fd, &st) < 0) { - pa_log(__FILE__": fstat('%s'): %s", p, strerror(errno)); + pa_log(__FILE__": fstat('%s'): %s", p, pa_cstrerror(errno)); goto fail; } diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index 9f755440..77212ce5 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -96,7 +97,7 @@ static void do_read(struct userdata *u) { assert(u->chunk.memblock && u->chunk.memblock->length > u->chunk.index); if ((r = pa_iochannel_read(u->io, (uint8_t*) u->chunk.memblock->data + u->chunk.index, u->chunk.memblock->length - u->chunk.index)) <= 0) { - pa_log(__FILE__": read() failed: %s", strerror(errno)); + pa_log(__FILE__": read(): %s", pa_cstrerror(errno)); return; } @@ -141,14 +142,14 @@ int pa__init(pa_core *c, pa_module*m) { mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777); if ((fd = open(p, O_RDWR)) < 0) { - pa_log(__FILE__": open('%s'): %s", p, strerror(errno)); + pa_log(__FILE__": open('%s'): %s", p, pa_cstrerror(errno)); goto fail; } pa_fd_set_cloexec(fd, 1); if (fstat(fd, &st) < 0) { - pa_log(__FILE__": fstat('%s'): %s", p, strerror(errno)); + pa_log(__FILE__": fstat('%s'): %s", p, pa_cstrerror(errno)); goto fail; } diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index cfe661a3..8eba352b 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -42,6 +42,7 @@ #include "../polypcore/winsock.h" +#include #include #include @@ -250,7 +251,7 @@ int pa__init(pa_core *c, pa_module*m) { } if ((r = pa_unix_socket_remove_stale(tmp)) < 0) { - pa_log(__FILE__": Failed to remove stale UNIX socket '%s': %s", tmp, strerror(errno)); + pa_log(__FILE__": Failed to remove stale UNIX socket '%s': %s", tmp, pa_cstrerror(errno)); goto fail; } @@ -328,7 +329,7 @@ void pa__done(pa_core *c, pa_module*m) { if ((p = pa_parent_dir(u->socket_path))) { if (rmdir(p) < 0 && errno != ENOENT && errno != ENOTEMPTY) - pa_log(__FILE__": Failed to remove %s: %s.", u->socket_path, strerror(errno)); + pa_log(__FILE__": Failed to remove %s: %s.", u->socket_path, pa_cstrerror(errno)); pa_xfree(p); } diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 77eb4e49..8670bb35 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -168,7 +169,7 @@ static void do_write(struct userdata *u) { } if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, len)) < 0) { - pa_log(__FILE__": write() failed: %s", strerror(errno)); + pa_log(__FILE__": write() failed: %s", pa_cstrerror(errno)); return; } @@ -206,7 +207,7 @@ static void do_read(struct userdata *u) { if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); if (errno != EAGAIN) - pa_log(__FILE__": read() failed: %s", strerror(errno)); + pa_log(__FILE__": read() failed: %s", pa_cstrerror(errno)); return; } @@ -334,7 +335,7 @@ static int sink_set_hw_volume_cb(pa_sink *s) { if (errno == EINVAL) pa_log(__FILE__": AUDIO_SETINFO: Unsupported volume."); else - pa_log(__FILE__": AUDIO_SETINFO: %s", strerror(errno)); + pa_log(__FILE__": AUDIO_SETINFO: %s", pa_cstrerror(errno)); return -1; } @@ -363,7 +364,7 @@ static int sink_set_hw_mute_cb(pa_sink *s) { info.output_muted = !!s->hw_muted; if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { - pa_log(__FILE__": AUDIO_SETINFO: %s", strerror(errno)); + pa_log(__FILE__": AUDIO_SETINFO: %s", pa_cstrerror(errno)); return -1; } @@ -397,7 +398,7 @@ static int source_set_hw_volume_cb(pa_source *s) { if (errno == EINVAL) pa_log(__FILE__": AUDIO_SETINFO: Unsupported volume."); else - pa_log(__FILE__": AUDIO_SETINFO: %s", strerror(errno)); + pa_log(__FILE__": AUDIO_SETINFO: %s", pa_cstrerror(errno)); return -1; } @@ -463,7 +464,7 @@ static int pa_solaris_auto_format(int fd, int mode, pa_sample_spec *ss) { if (errno == EINVAL) pa_log(__FILE__": AUDIO_SETINFO: Unsupported sample format."); else - pa_log(__FILE__": AUDIO_SETINFO: %s", strerror(errno)); + pa_log(__FILE__": AUDIO_SETINFO: %s", pa_cstrerror(errno)); return -1; } @@ -481,7 +482,7 @@ static int pa_solaris_set_buffer(int fd, int buffer_size) { if (errno == EINVAL) pa_log(__FILE__": AUDIO_SETINFO: Unsupported buffer size."); else - pa_log(__FILE__": AUDIO_SETINFO: %s", strerror(errno)); + pa_log(__FILE__": AUDIO_SETINFO: %s", pa_cstrerror(errno)); return -1; } diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index e74567bc..796e43a3 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -124,7 +125,7 @@ static int load_rules(struct userdata *u) { pa_log_info(__FILE__": starting with empty ruleset."); ret = 0; } else - pa_log(__FILE__": failed to open file '%s': %s", u->table_file, strerror(errno)); + pa_log(__FILE__": failed to open file '%s': %s", u->table_file, pa_cstrerror(errno)); goto finish; } @@ -198,7 +199,7 @@ static int save_rules(struct userdata *u) { pa_open_config_file(NULL, DEFAULT_VOLUME_TABLE_FILE, NULL, &u->table_file, "w"); if (!f) { - pa_log(__FILE__": failed to open file '%s': %s", u->table_file, strerror(errno)); + pa_log(__FILE__": failed to open file '%s': %s", u->table_file, pa_cstrerror(errno)); goto finish; } diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index a84276f1..027921c5 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -34,6 +34,8 @@ #include #include +#include + #include #include @@ -51,7 +53,7 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { tcaps = pcaps ? pcaps : &dcaps; if (ioctl(fd, SNDCTL_DSP_GETCAPS, tcaps) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s", pa_cstrerror(errno)); goto fail; } @@ -65,13 +67,13 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { if ((fd = open(device, (*mode = O_WRONLY)|O_NDELAY)) < 0) { if ((fd = open(device, (*mode = O_RDONLY)|O_NDELAY)) < 0) { - pa_log(__FILE__": open('%s'): %s", device, strerror(errno)); + pa_log(__FILE__": open('%s'): %s", device, pa_cstrerror(errno)); goto fail; } } } else { if ((fd = open(device, *mode|O_NDELAY)) < 0) { - pa_log(__FILE__": open('%s'): %s", device, strerror(errno)); + pa_log(__FILE__": open('%s'): %s", device, pa_cstrerror(errno)); goto fail; } } @@ -80,7 +82,7 @@ success: if (pcaps) { if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s", pa_cstrerror(errno)); goto fail; } } @@ -118,7 +120,7 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss) { if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != f) { format = AFMT_U8; if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_U8) { - pa_log(__FILE__": SNDCTL_DSP_SETFMT: %s", format != AFMT_U8 ? "No supported sample format" : strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_SETFMT: %s", format != AFMT_U8 ? "No supported sample format" : pa_cstrerror(errno)); return -1; } else ss->format = PA_SAMPLE_U8; @@ -130,7 +132,7 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss) { channels = ss->channels; if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) { - pa_log(__FILE__": SNDCTL_DSP_CHANNELS: %s", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_CHANNELS: %s", pa_cstrerror(errno)); return -1; } assert(channels); @@ -138,7 +140,7 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss) { speed = ss->rate; if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) { - pa_log(__FILE__": SNDCTL_DSP_SPEED: %s", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_SPEED: %s", pa_cstrerror(errno)); return -1; } assert(speed); @@ -164,7 +166,7 @@ int pa_oss_set_fragments(int fd, int nfrags, int frag_size) { arg = ((int) nfrags << 16) | simple_log2(frag_size); if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &arg) < 0) { - pa_log(__FILE__": SNDCTL_DSP_SETFRAGMENT: %s", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_SETFRAGMENT: %s", pa_cstrerror(errno)); return -1; } @@ -253,7 +255,7 @@ int pa_oss_get_hw_description(const char *dev, char *name, size_t l) { !(f = fopen("/proc/asound/oss/sndstat", "r"))) { if (errno != ENOENT) - pa_log_warn(__FILE__": failed to open OSS sndstat device: %s", strerror(errno)); + pa_log_warn(__FILE__": failed to open OSS sndstat device: %s", pa_cstrerror(errno)); return -1; } diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index 56fc91ef..8d9b33c2 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -216,13 +217,13 @@ static int mcast_socket(const struct sockaddr* sa, socklen_t salen) { af = sa->sa_family; if ((fd = socket(af, SOCK_DGRAM, 0)) < 0) { - pa_log(__FILE__": Failed to create socket: %s", strerror(errno)); + pa_log(__FILE__": Failed to create socket: %s", pa_cstrerror(errno)); goto fail; } one = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) { - pa_log(__FILE__": SO_REUSEADDR failed: %s", strerror(errno)); + pa_log(__FILE__": SO_REUSEADDR failed: %s", pa_cstrerror(errno)); goto fail; } @@ -239,12 +240,12 @@ static int mcast_socket(const struct sockaddr* sa, socklen_t salen) { } if (r < 0) { - pa_log_info(__FILE__": Joining mcast group failed: %s", strerror(errno)); + pa_log_info(__FILE__": Joining mcast group failed: %s", pa_cstrerror(errno)); goto fail; } if (bind(fd, sa, salen) < 0) { - pa_log(__FILE__": bind() failed: %s", strerror(errno)); + pa_log(__FILE__": bind() failed: %s", pa_cstrerror(errno)); goto fail; } diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 1372414c..c8b3899a 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -238,28 +239,28 @@ int pa__init(pa_core *c, pa_module*m) { } if ((fd = socket(af, SOCK_DGRAM, 0)) < 0) { - pa_log(__FILE__": socket() failed: %s", strerror(errno)); + pa_log(__FILE__": socket() failed: %s", pa_cstrerror(errno)); goto fail; } if (connect(fd, af == AF_INET ? (struct sockaddr*) &sa4 : (struct sockaddr*) &sa6, af == AF_INET ? sizeof(sa4) : sizeof(sa6)) < 0) { - pa_log(__FILE__": connect() failed: %s", strerror(errno)); + pa_log(__FILE__": connect() failed: %s", pa_cstrerror(errno)); goto fail; } if ((sap_fd = socket(af, SOCK_DGRAM, 0)) < 0) { - pa_log(__FILE__": socket() failed: %s", strerror(errno)); + pa_log(__FILE__": socket() failed: %s", pa_cstrerror(errno)); goto fail; } if (connect(sap_fd, af == AF_INET ? (struct sockaddr*) &sap_sa4 : (struct sockaddr*) &sap_sa6, af == AF_INET ? sizeof(sap_sa4) : sizeof(sap_sa6)) < 0) { - pa_log(__FILE__": connect() failed: %s", strerror(errno)); + pa_log(__FILE__": connect() failed: %s", pa_cstrerror(errno)); goto fail; } if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0 || setsockopt(sap_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) { - pa_log(__FILE__": IP_MULTICAST_LOOP failed: %s", strerror(errno)); + pa_log(__FILE__": IP_MULTICAST_LOOP failed: %s", pa_cstrerror(errno)); goto fail; } diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c index 23e84eb3..012d6578 100644 --- a/src/modules/rtp/rtp.c +++ b/src/modules/rtp/rtp.c @@ -36,6 +36,8 @@ #include #endif +#include + #include #include "rtp.h" @@ -124,7 +126,7 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { if (k < 0) { if (errno != EAGAIN) /* If the queue is full, just ignore it */ - pa_log(__FILE__": sendmsg() failed: %s", strerror(errno)); + pa_log(__FILE__": sendmsg() failed: %s", pa_cstrerror(errno)); return -1; } @@ -162,7 +164,7 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_memblock_stat *st) { chunk->memblock = NULL; if (ioctl(c->fd, FIONREAD, &size) < 0) { - pa_log(__FILE__": FIONREAD failed: %s", strerror(errno)); + pa_log(__FILE__": FIONREAD failed: %s", pa_cstrerror(errno)); goto fail; } @@ -183,7 +185,7 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_memblock_stat *st) { m.msg_flags = 0; if ((r = recvmsg(c->fd, &m, 0)) != size) { - pa_log(__FILE__": recvmsg() failed: %s", r < 0 ? strerror(errno) : "size mismatch"); + pa_log(__FILE__": recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch"); goto fail; } diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c index 5b8f31fb..238ee420 100644 --- a/src/modules/rtp/sap.c +++ b/src/modules/rtp/sap.c @@ -38,6 +38,7 @@ #include #endif +#include #include #include @@ -77,7 +78,7 @@ int pa_sap_send(pa_sap_context *c, int goodbye) { int k; if (getsockname(c->fd, sa, &salen) < 0) { - pa_log("getsockname() failed: %s\n", strerror(errno)); + pa_log("getsockname() failed: %s\n", pa_cstrerror(errno)); return -1; } @@ -109,7 +110,7 @@ int pa_sap_send(pa_sap_context *c, int goodbye) { m.msg_flags = 0; if ((k = sendmsg(c->fd, &m, MSG_DONTWAIT)) < 0) - pa_log("sendmsg() failed: %s\n", strerror(errno)); + pa_log("sendmsg() failed: %s\n", pa_cstrerror(errno)); return k; } @@ -136,7 +137,7 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) { assert(goodbye); if (ioctl(c->fd, FIONREAD, &size) < 0) { - pa_log(__FILE__": FIONREAD failed: %s", strerror(errno)); + pa_log(__FILE__": FIONREAD failed: %s", pa_cstrerror(errno)); goto fail; } @@ -158,7 +159,7 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) { m.msg_flags = 0; if ((r = recvmsg(c->fd, &m, 0)) != size) { - pa_log(__FILE__": recvmsg() failed: %s", r < 0 ? strerror(errno) : "size mismatch"); + pa_log(__FILE__": recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch"); goto fail; } diff --git a/src/polyp/client-conf.c b/src/polyp/client-conf.c index 1ebcff43..0b3154c8 100644 --- a/src/polyp/client-conf.c +++ b/src/polyp/client-conf.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -123,7 +124,7 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) { pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn, "r"); if (!f && errno != EINTR) { - pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", filename, strerror(errno)); + pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", filename, pa_cstrerror(errno)); goto finish; } diff --git a/src/polyp/context.c b/src/polyp/context.c index a3b49d4b..eb563819 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -47,6 +47,7 @@ #include "../polypcore/winsock.h" +#include #include #include @@ -440,7 +441,7 @@ static int context_connect_spawn(pa_context *c) { pa_context_ref(c); if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { - pa_log(__FILE__": socketpair() failed: %s", strerror(errno)); + pa_log(__FILE__": socketpair(): %s", pa_cstrerror(errno)); pa_context_fail(c, PA_ERR_INTERNAL); goto fail; } @@ -454,7 +455,7 @@ static int context_connect_spawn(pa_context *c) { c->spawn_api.prefork(); if ((pid = fork()) < 0) { - pa_log(__FILE__": fork() failed: %s", strerror(errno)); + pa_log(__FILE__": fork(): %s", pa_cstrerror(errno)); pa_context_fail(c, PA_ERR_INTERNAL); if (c->spawn_api.postfork) @@ -510,7 +511,7 @@ static int context_connect_spawn(pa_context *c) { c->spawn_api.postfork(); if (r < 0) { - pa_log(__FILE__": waitpid() failed: %s", strerror(errno)); + pa_log(__FILE__": waitpid(): %s", pa_cstrerror(errno)); pa_context_fail(c, PA_ERR_INTERNAL); goto fail; } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { diff --git a/src/polyp/error.c b/src/polyp/error.c index e78d072e..062b6f36 100644 --- a/src/polyp/error.c +++ b/src/polyp/error.c @@ -23,9 +23,23 @@ #include #endif +#include #include #include +#include +#ifdef HAVE_PTHREAD +#include +#endif + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include +#include + +#include #include #include "error.h" @@ -58,3 +72,79 @@ const char*pa_strerror(int error) { return errortab[error]; } + +#ifdef HAVE_PTHREAD + +static pthread_once_t cstrerror_once = PTHREAD_ONCE_INIT; +static pthread_key_t tlsstr_key; + +static void inittls(void) { + int ret; + + ret = pthread_key_create(&tlsstr_key, pa_xfree); + if (ret) { + fprintf(stderr, __FILE__ ": CRITICAL: Unable to allocate TLS key (%d)\n", errno); + exit(-1); + } +} + +#elif HAVE_WINDOWS_H + +static __declspec(thread) char *tlsstr; + +#else + +/* Unsafe, but we have no choice */ +static char *tlsstr; + +#endif + +char* pa_cstrerror(int errnum) { + const char *origbuf; + +#ifdef HAVE_STRERROR_R + char errbuf[128]; +#endif + +#ifdef HAVE_PTHREAD + char *tlsstr; + + pthread_once(&cstrerror_once, inittls); + + tlsstr = pthread_getspecific(tlsstr_key); +#endif + + if (tlsstr) + pa_xfree(tlsstr); + +#ifdef HAVE_STRERROR_R + +#ifdef __GLIBC__ + origbuf = strerror_r(errnum, errbuf, sizeof(errbuf)); + if (origbuf == NULL) + origbuf = ""; +#else + if (strerror_r(errnum, errbuf, sizeof(errbuf)) == 0) { + origbuf = errbuf; + errbuf[sizeof(errbuf) - 1] = '\0'; + } else + origbuf = ""; +#endif + +#else + /* This might not be thread safe, but we hope for the best */ + origbuf = strerror(errnum); +#endif + + tlsstr = pa_locale_to_utf8(origbuf); + if (!tlsstr) { + fprintf(stderr, "Unable to convert, filtering\n"); + tlsstr = pa_utf8_filter(origbuf); + } + +#ifdef HAVE_PTHREAD + pthread_setspecific(tlsstr_key, tlsstr); +#endif + + return tlsstr; +} diff --git a/src/polyp/error.h b/src/polyp/error.h index 9856c1af..33507bfd 100644 --- a/src/polyp/error.h +++ b/src/polyp/error.h @@ -33,6 +33,12 @@ PA_C_DECL_BEGIN /** Return a human readable error message for the specified numeric error code */ const char* pa_strerror(int error); +/** A wrapper around the standard strerror() function that converts the + * string to UTF-8. The function is thread safe but the returned string is + * only guaranteed to exist until the thread exits or pa_cstrerror() is + * called again from the same thread. */ +char* pa_cstrerror(int errnum); + PA_C_DECL_END #endif diff --git a/src/polyp/mainloop-signal.c b/src/polyp/mainloop-signal.c index c57437b6..c6ad431a 100644 --- a/src/polyp/mainloop-signal.c +++ b/src/polyp/mainloop-signal.c @@ -36,6 +36,7 @@ #include #endif +#include #include #include @@ -89,7 +90,7 @@ static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags if (errno == EAGAIN) return; - pa_log(__FILE__": read(): %s", strerror(errno)); + pa_log(__FILE__": read(): %s", pa_cstrerror(errno)); return; } @@ -106,7 +107,7 @@ int pa_signal_init(pa_mainloop_api *a) { assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event); if (pipe(signal_pipe) < 0) { - pa_log(__FILE__": pipe() failed: %s", strerror(errno)); + pa_log(__FILE__": pipe(): %s", pa_cstrerror(errno)); return -1; } diff --git a/src/polyp/mainloop.c b/src/polyp/mainloop.c index 6b5b3b25..6088fa4b 100644 --- a/src/polyp/mainloop.c +++ b/src/polyp/mainloop.c @@ -44,6 +44,7 @@ #include "../polypcore/pipe.h" #endif +#include #include #include @@ -689,7 +690,7 @@ int pa_mainloop_poll(pa_mainloop *m) { if (errno == EINTR) r = 0; else - pa_log(__FILE__": poll(): %s", strerror(errno)); + pa_log(__FILE__": poll(): %s", pa_cstrerror(errno)); } } diff --git a/src/polyp/util.c b/src/polyp/util.c index ed59a5c6..91054483 100644 --- a/src/polyp/util.c +++ b/src/polyp/util.c @@ -51,6 +51,8 @@ #include "../polypcore/winsock.h" +#include + #include #include @@ -107,7 +109,7 @@ char *pa_get_user_name(char *s, size_t l) { char *pa_get_host_name(char *s, size_t l) { assert(s && l > 0); if (gethostname(s, l) < 0) { - pa_log(__FILE__": gethostname(): %s", strerror(errno)); + pa_log(__FILE__": gethostname(): %s", pa_cstrerror(errno)); return NULL; } s[l-1] = 0; diff --git a/src/polypcore/authkey.c b/src/polypcore/authkey.c index aee54fd4..6b462a23 100644 --- a/src/polypcore/authkey.c +++ b/src/polypcore/authkey.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -53,7 +54,7 @@ static int generate(int fd, void *ret_data, size_t length) { ftruncate(fd, 0); if ((r = pa_loop_write(fd, ret_data, length)) < 0 || (size_t) r != length) { - pa_log(__FILE__": failed to write cookie file: %s", strerror(errno)); + pa_log(__FILE__": failed to write cookie file: %s", pa_cstrerror(errno)); return -1; } @@ -75,7 +76,7 @@ static int load(const char *fn, void *data, size_t length) { if ((fd = open(fn, O_RDWR|O_CREAT|O_BINARY, S_IRUSR|S_IWUSR)) < 0) { if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY)) < 0) { - pa_log(__FILE__": failed to open cookie file '%s': %s", fn, strerror(errno)); + pa_log(__FILE__": failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } else writable = 0; @@ -84,7 +85,7 @@ static int load(const char *fn, void *data, size_t length) { unlock = pa_lock_fd(fd, 1) >= 0; if ((r = pa_loop_read(fd, data, length)) < 0) { - pa_log(__FILE__": failed to read cookie file '%s': %s", fn, strerror(errno)); + pa_log(__FILE__": failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } @@ -125,7 +126,7 @@ int pa_authkey_load(const char *path, void *data, size_t length) { if (ret < 0) pa_log(__FILE__": Failed to load authorization key '%s': %s", path, - (ret == -1) ? strerror(errno) : "file corrupt"); + (ret == -1) ? pa_cstrerror(errno) : "file corrupt"); return ret; } @@ -181,14 +182,14 @@ int pa_authkey_save(const char *fn, const void *data, size_t length) { return -2; if ((fd = open(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { - pa_log(__FILE__": failed to open cookie file '%s': %s", fn, strerror(errno)); + pa_log(__FILE__": failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } unlock = pa_lock_fd(fd, 1) >= 0; if ((r = pa_loop_write(fd, data, length)) < 0 || (size_t) r != length) { - pa_log(__FILE__": failed to read cookie file '%s': %s", fn, strerror(errno)); + pa_log(__FILE__": failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } diff --git a/src/polypcore/cli-command.c b/src/polypcore/cli-command.c index 3adc9a21..039aa957 100644 --- a/src/polypcore/cli-command.c +++ b/src/polypcore/cli-command.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -900,7 +901,7 @@ int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int assert(c && fn && buf); if (!(f = fopen(fn, "r"))) { - pa_strbuf_printf(buf, "open('%s') failed: %s\n", fn, strerror(errno)); + pa_strbuf_printf(buf, "open('%s') failed: %s\n", fn, pa_cstrerror(errno)); if (!*fail) ret = 0; goto fail; diff --git a/src/polypcore/conf-parser.c b/src/polypcore/conf-parser.c index bc99b871..4bcb83dd 100644 --- a/src/polypcore/conf-parser.c +++ b/src/polypcore/conf-parser.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -112,7 +113,8 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void goto finish; } - pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", filename, strerror(errno)); + pa_log_warn(__FILE__": WARNING: failed to open configuration file '%s': %s", + filename, pa_cstrerror(errno)); goto finish; } @@ -122,7 +124,8 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void if (feof(f)) break; - pa_log(__FILE__": WARNING: failed to read configuration file '%s': %s", filename, strerror(errno)); + pa_log_warn(__FILE__": WARNING: failed to read configuration file '%s': %s", + filename, pa_cstrerror(errno)); goto finish; } diff --git a/src/polypcore/core-scache.c b/src/polypcore/core-scache.c index 5cb38bee..1d60a910 100644 --- a/src/polypcore/core-scache.c +++ b/src/polypcore/core-scache.c @@ -41,6 +41,7 @@ #include #endif +#include #include #include #include @@ -359,7 +360,7 @@ static void add_file(pa_core *c, const char *pathname) { e = pa_path_get_filename(pathname); if (stat(pathname, &st) < 0) { - pa_log(__FILE__": stat('%s') failed: %s", pathname, strerror(errno)); + pa_log(__FILE__": stat('%s'): %s", pathname, pa_cstrerror(errno)); return; } @@ -381,7 +382,7 @@ int pa_scache_add_directory_lazy(pa_core *c, const char *pathname) { /* If that fails, try to open it as shell glob */ if (glob(pathname, GLOB_ERR|GLOB_NOSORT, NULL, &p) < 0) { - pa_log(__FILE__": Failed to open directory: %s", strerror(errno)); + pa_log(__FILE__": failed to open directory '%s': %s", pathname, pa_cstrerror(errno)); return -1; } diff --git a/src/polypcore/core-util.c b/src/polypcore/core-util.c index 36044c81..0e7f77a4 100644 --- a/src/polypcore/core-util.c +++ b/src/polypcore/core-util.c @@ -69,6 +69,7 @@ #include +#include #include #include @@ -301,7 +302,7 @@ void pa_check_signal_is_blocked(int sig) { if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) { #endif if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) { - pa_log(__FILE__": sigprocmask() failed: %s", strerror(errno)); + pa_log(__FILE__": sigprocmask(): %s", pa_cstrerror(errno)); return; } #ifdef HAVE_PTHREAD @@ -314,7 +315,7 @@ void pa_check_signal_is_blocked(int sig) { /* Check whether the signal is trapped */ if (sigaction(sig, NULL, &sa) < 0) { - pa_log(__FILE__": sigaction() failed: %s", strerror(errno)); + pa_log(__FILE__": sigaction(): %s", pa_cstrerror(errno)); return; } @@ -396,7 +397,7 @@ void pa_raise_priority(void) { #ifdef HAVE_SYS_RESOURCE_H if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) - pa_log_warn(__FILE__": setpriority() failed: %s", strerror(errno)); + pa_log_warn(__FILE__": setpriority(): %s", pa_cstrerror(errno)); else pa_log_info(__FILE__": Successfully gained nice level %i.", NICE_LEVEL); #endif @@ -406,13 +407,13 @@ void pa_raise_priority(void) { struct sched_param sp; if (sched_getparam(0, &sp) < 0) { - pa_log(__FILE__": sched_getparam() failed: %s", strerror(errno)); + pa_log(__FILE__": sched_getparam(): %s", pa_cstrerror(errno)); return; } sp.sched_priority = 1; if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) { - pa_log_warn(__FILE__": sched_setscheduler() failed: %s", strerror(errno)); + pa_log_warn(__FILE__": sched_setscheduler(): %s", pa_cstrerror(errno)); return; } @@ -563,7 +564,7 @@ static int is_group(gid_t gid, const char *name) { data = pa_xmalloc(n); if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) { - pa_log(__FILE__ ": getgrgid_r(%u) failed: %s", gid, strerror(errno)); + pa_log(__FILE__": getgrgid_r(%u): %s", gid, pa_cstrerror(errno)); goto finish; } @@ -575,8 +576,8 @@ finish: /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not * support getgrgid_r. */ if ((result = getgrgid(gid)) == NULL) { - pa_log(__FILE__ ": getgrgid(%u) failed: %s", gid, strerror(errno)); - goto finish; + pa_log(__FILE__": getgrgid(%u): %s", gid, pa_cstrerror(errno)); + goto finish; } r = strcmp(name, result->gr_name) == 0; @@ -598,7 +599,7 @@ int pa_own_uid_in_group(const char *name, gid_t *gid) { gids = pa_xmalloc(sizeof(GETGROUPS_T)*n); if ((n = getgroups(n, gids)) < 0) { - pa_log(__FILE__": getgroups() failed: %s", strerror(errno)); + pa_log(__FILE__": getgroups(): %s", pa_cstrerror(errno)); goto finish; } @@ -696,7 +697,8 @@ int pa_lock_fd(int fd, int b) { return 0; } - pa_log(__FILE__": %slock failed: %s", !b ? "un" : "", strerror(errno)); + pa_log(__FILE__": %slock: %s", !b? "un" : "", + pa_cstrerror(errno)); #endif #ifdef OS_IS_WIN32 @@ -730,7 +732,8 @@ int pa_lock_lockfile(const char *fn) { struct stat st; if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { - pa_log(__FILE__": failed to create lock file '%s': %s", fn, strerror(errno)); + pa_log(__FILE__": failed to create lock file '%s': %s", fn, + pa_cstrerror(errno)); goto fail; } @@ -777,7 +780,8 @@ int pa_unlock_lockfile(const char *fn, int fd) { assert(fn && fd >= 0); if (unlink(fn) < 0) { - pa_log_warn(__FILE__": WARNING: unable to remove lock file '%s': %s", fn, strerror(errno)); + pa_log_warn(__FILE__": WARNING: unable to remove lock file '%s': %s", + fn, pa_cstrerror(errno)); r = -1; } @@ -787,7 +791,8 @@ int pa_unlock_lockfile(const char *fn, int fd) { } if (close(fd) < 0) { - pa_log_warn(__FILE__": WARNING: failed to close lock file '%s': %s", fn, strerror(errno)); + pa_log_warn(__FILE__": WARNING: failed to close lock file '%s': %s", + fn, pa_cstrerror(errno)); r = -1; } diff --git a/src/polypcore/iochannel.c b/src/polypcore/iochannel.c index 10997d62..8af6a36b 100644 --- a/src/polypcore/iochannel.c +++ b/src/polypcore/iochannel.c @@ -38,6 +38,7 @@ #include "winsock.h" +#include #include #include @@ -253,7 +254,7 @@ int pa_iochannel_creds_enable(pa_iochannel *io) { assert(io->ifd >= 0); if (setsockopt(io->ifd, SOL_SOCKET, SO_PASSCRED, &t, sizeof(t)) < 0) { - pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", strerror(errno)); + pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno)); return -1; } diff --git a/src/polypcore/ioline.c b/src/polypcore/ioline.c index 9bb610fe..2e0a3e1a 100644 --- a/src/polypcore/ioline.c +++ b/src/polypcore/ioline.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -275,7 +276,7 @@ static int do_read(pa_ioline *l) { pa_ioline_puts(l, "\nExiting.\n"); do_write(l); } else if (r < 0) { - pa_log(__FILE__": read() failed: %s", strerror(errno)); + pa_log(__FILE__": read(): %s", pa_cstrerror(errno)); failure(l); return -1; } @@ -297,7 +298,7 @@ static int do_write(pa_ioline *l) { while (!l->dead && pa_iochannel_is_writable(l->io) && l->wbuf_valid_length) { if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0) { - pa_log(__FILE__": write() failed: %s", r < 0 ? strerror(errno) : "EOF"); + pa_log(__FILE__": write(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); failure(l); return -1; } diff --git a/src/polypcore/log.c b/src/polypcore/log.c index ce9df1a9..6cdffa51 100644 --- a/src/polypcore/log.c +++ b/src/polypcore/log.c @@ -94,6 +94,9 @@ void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { text = pa_vsprintf_malloc(format, ap); + if (!pa_utf8_valid(text)) + pa_log_level(level, __FILE__": invalid UTF-8 string following below:"); + for (t = text; t; t = n) { if ((n = strchr(t, '\n'))) { *n = 0; diff --git a/src/polypcore/pid.c b/src/polypcore/pid.c index e98dc97b..b8f53955 100644 --- a/src/polypcore/pid.c +++ b/src/polypcore/pid.c @@ -39,6 +39,7 @@ #include #endif +#include #include #include @@ -56,7 +57,8 @@ static pid_t read_pid(const char *fn, int fd) { assert(fn && fd >= 0); if ((r = pa_loop_read(fd, t, sizeof(t)-1)) < 0) { - pa_log(__FILE__": WARNING: failed to read PID file '%s': %s", fn, strerror(errno)); + pa_log_warn(__FILE__": WARNING: failed to read PID file '%s': %s", + fn, pa_cstrerror(errno)); return (pid_t) -1; } @@ -86,7 +88,8 @@ static int open_pid_file(const char *fn, int mode) { if ((fd = open(fn, mode, S_IRUSR|S_IWUSR)) < 0) { if (mode != O_RDONLY || errno != ENOENT) - pa_log(__FILE__": WARNING: failed to open PID file '%s': %s", fn, strerror(errno)); + pa_log_warn(__FILE__": WARNING: failed to open PID file '%s': %s", + fn, pa_cstrerror(errno)); goto fail; } @@ -95,7 +98,8 @@ static int open_pid_file(const char *fn, int mode) { goto fail; if (fstat(fd, &st) < 0) { - pa_log(__FILE__": Failed to fstat() PID file '%s': %s", fn, strerror(errno)); + pa_log_warn(__FILE__": WARNING: failed to fstat() PID file '%s': %s", + fn, pa_cstrerror(errno)); goto fail; } @@ -107,7 +111,8 @@ static int open_pid_file(const char *fn, int mode) { goto fail; if (close(fd) < 0) { - pa_log(__FILE__": Failed to close file '%s': %s", fn, strerror(errno)); + pa_log_warn(__FILE__": WARNING: failed to close file '%s': %s", + fn, pa_cstrerror(errno)); goto fail; } @@ -164,7 +169,8 @@ int pa_pid_file_create(void) { /* Overwrite the current PID file */ if (lseek(fd, 0, SEEK_SET) == (off_t) -1 || ftruncate(fd, 0) < 0) { - pa_log(__FILE__": failed to truncate PID fil: %s.", strerror(errno)); + pa_log(__FILE__": failed to truncate PID file '%s': %s", + fn, pa_cstrerror(errno)); goto fail; } @@ -198,7 +204,8 @@ int pa_pid_file_remove(void) { pa_runtime_path("pid", fn, sizeof(fn)); if ((fd = open_pid_file(fn, O_RDWR)) < 0) { - pa_log(__FILE__": WARNING: failed to open PID file '%s': %s", fn, strerror(errno)); + pa_log_warn(__FILE__": WARNING: failed to open PID file '%s': %s", + fn, pa_cstrerror(errno)); goto fail; } @@ -211,7 +218,8 @@ int pa_pid_file_remove(void) { } if (ftruncate(fd, 0) < 0) { - pa_log(__FILE__": failed to truncate PID file '%s': %s", fn, strerror(errno)); + pa_log_warn(__FILE__": WARNING: failed to truncate PID file '%s': %s", + fn, pa_cstrerror(errno)); goto fail; } @@ -222,7 +230,8 @@ int pa_pid_file_remove(void) { #endif if (unlink(fn) < 0) { - pa_log(__FILE__": failed to remove PID file '%s': %s", fn, strerror(errno)); + pa_log_warn(__FILE__": WARNING: failed to remove PID file '%s': %s", + fn, pa_cstrerror(errno)); goto fail; } diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index c11bdb21..01a72e84 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -812,7 +813,7 @@ static int do_read(struct connection *c) { assert(c->read_data_length < sizeof(c->request)); if ((r = pa_iochannel_read(c->io, ((uint8_t*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { - pa_log_debug(__FILE__": read() failed: %s", r < 0 ? strerror(errno) : "EOF"); + pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } @@ -860,7 +861,7 @@ static int do_read(struct connection *c) { assert(c->read_data && c->read_data_length < handler->data_length); if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { - pa_log_debug(__FILE__": read() failed: %s", r < 0 ? strerror(errno) : "EOF"); + pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } @@ -880,7 +881,7 @@ static int do_read(struct connection *c) { assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { - pa_log_debug(__FILE__": read() failed: %s", r < 0 ? strerror(errno) : "EOF"); + pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } @@ -935,7 +936,7 @@ static int do_read(struct connection *c) { } if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { - pa_log_debug(__FILE__": read() failed: %s", r < 0 ? strerror(errno) : "EOF"); + pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } @@ -965,7 +966,7 @@ static int do_write(struct connection *c) { assert(c->write_data_index < c->write_data_length); if ((r = pa_iochannel_write(c->io, (uint8_t*) c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { - pa_log(__FILE__": write() failed: %s", strerror(errno)); + pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); return -1; } @@ -984,7 +985,7 @@ static int do_write(struct connection *c) { if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { pa_memblock_unref(chunk.memblock); - pa_log(__FILE__": write(): %s", strerror(errno)); + pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); return -1; } diff --git a/src/polypcore/protocol-simple.c b/src/polypcore/protocol-simple.c index caffd5c9..f15f882a 100644 --- a/src/polypcore/protocol-simple.c +++ b/src/polypcore/protocol-simple.c @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -133,7 +134,7 @@ static int do_read(struct connection *c) { } if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { - pa_log_debug(__FILE__": read() failed: %s", r == 0 ? "EOF" : strerror(errno)); + pa_log_debug(__FILE__": read(): %s", r == 0 ? "EOF" : pa_cstrerror(errno)); return -1; } @@ -167,7 +168,7 @@ static int do_write(struct connection *c) { if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { pa_memblock_unref(chunk.memblock); - pa_log(__FILE__": write(): %s", strerror(errno)); + pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); return -1; } diff --git a/src/polypcore/socket-client.c b/src/polypcore/socket-client.c index ec2f9a9e..aa885759 100644 --- a/src/polypcore/socket-client.c +++ b/src/polypcore/socket-client.c @@ -54,6 +54,7 @@ #include "winsock.h" +#include #include #include @@ -139,7 +140,7 @@ static void do_call(pa_socket_client *c) { lerror = sizeof(error); if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &lerror) < 0) { - pa_log(__FILE__": getsockopt(): %s", strerror(errno)); + pa_log(__FILE__": getsockopt(): %s", pa_cstrerror(errno)); goto finish; } @@ -149,7 +150,7 @@ static void do_call(pa_socket_client *c) { } if (error != 0) { - pa_log_debug(__FILE__": connect(): %s", strerror(error)); + pa_log_debug(__FILE__": connect(): %s", pa_cstrerror(errno)); errno = error; goto finish; } @@ -194,7 +195,7 @@ static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t pa_log_debug(__FILE__": connect(): %d", WSAGetLastError()); #else if (errno != EINPROGRESS) { - pa_log_debug(__FILE__": connect(): %s (%d)", strerror(errno), errno); + pa_log_debug(__FILE__": connect(): %s (%d)", pa_cstrerror(errno), errno); #endif return -1; } @@ -266,7 +267,7 @@ static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size } if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s", strerror(errno)); + pa_log(__FILE__": socket(): %s", pa_cstrerror(errno)); return -1; } diff --git a/src/polypcore/socket-server.c b/src/polypcore/socket-server.c index 592b6a63..871fac11 100644 --- a/src/polypcore/socket-server.c +++ b/src/polypcore/socket-server.c @@ -64,6 +64,7 @@ #include #include +#include #include #include @@ -94,7 +95,7 @@ static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_U pa_socket_server_ref(s); if ((nfd = accept(fd, NULL, NULL)) < 0) { - pa_log(__FILE__": accept(): %s", strerror(errno)); + pa_log(__FILE__": accept(): %s", pa_cstrerror(errno)); goto finish; } @@ -173,7 +174,7 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file assert(m && filename); if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s", strerror(errno)); + pa_log(__FILE__": socket(): %s", pa_cstrerror(errno)); goto fail; } @@ -186,12 +187,12 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file pa_socket_low_delay(fd); if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) { - pa_log(__FILE__": bind(): %s", strerror(errno)); + pa_log(__FILE__": bind(): %s", pa_cstrerror(errno)); goto fail; } if (listen(fd, 5) < 0) { - pa_log(__FILE__": listen(): %s", strerror(errno)); + pa_log(__FILE__": listen(): %s", pa_cstrerror(errno)); goto fail; } @@ -227,7 +228,7 @@ pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address assert(m && port); if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(PF_INET): %s", strerror(errno)); + pa_log(__FILE__": socket(PF_INET): %s", pa_cstrerror(errno)); goto fail; } @@ -235,7 +236,7 @@ pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address #ifdef SO_REUSEADDR if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) - pa_log(__FILE__": setsockopt(): %s", strerror(errno)); + pa_log(__FILE__": setsockopt(): %s", pa_cstrerror(errno)); #endif pa_socket_tcp_low_delay(fd); @@ -246,12 +247,12 @@ pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address sa.sin_addr.s_addr = htonl(address); if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { - pa_log(__FILE__": bind(): %s", strerror(errno)); + pa_log(__FILE__": bind(): %s", pa_cstrerror(errno)); goto fail; } if (listen(fd, 5) < 0) { - pa_log(__FILE__": listen(): %s", strerror(errno)); + pa_log(__FILE__": listen(): %s", pa_cstrerror(errno)); goto fail; } @@ -278,7 +279,7 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad assert(m && port); if ((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(PF_INET6): %s", strerror(errno)); + pa_log(__FILE__": socket(PF_INET6): %s", pa_cstrerror(errno)); goto fail; } @@ -286,12 +287,12 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad #ifdef IPV6_V6ONLY if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) - pa_log(__FILE__": setsockopt(IPPROTO_IPV6, IPV6_V6ONLY): %s", strerror(errno)); + pa_log(__FILE__": setsockopt(IPPROTO_IPV6, IPV6_V6ONLY): %s", pa_cstrerror(errno)); #endif #ifdef SO_REUSEADDR if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) - pa_log(__FILE__": setsockopt(SOL_SOCKET, SO_REUSEADDR, 1): %s", strerror(errno)); + pa_log(__FILE__": setsockopt(SOL_SOCKET, SO_REUSEADDR, 1): %s", pa_cstrerror(errno)); #endif pa_socket_tcp_low_delay(fd); @@ -302,12 +303,12 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad memcpy(sa.sin6_addr.s6_addr, address, 16); if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { - pa_log(__FILE__": bind(): %s", strerror(errno)); + pa_log(__FILE__": bind(): %s", pa_cstrerror(errno)); goto fail; } if (listen(fd, 5) < 0) { - pa_log(__FILE__": listen(): %s", strerror(errno)); + pa_log(__FILE__": listen(): %s", pa_cstrerror(errno)); goto fail; } @@ -418,7 +419,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { socklen_t sa_len = sizeof(sa); if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) { - pa_log(__FILE__": getsockname() failed: %s", strerror(errno)); + pa_log(__FILE__": getsockname(): %s", pa_cstrerror(errno)); return NULL; } @@ -439,7 +440,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { char ip[INET6_ADDRSTRLEN]; if (!inet_ntop(AF_INET6, &sa.sin6_addr, ip, sizeof(ip))) { - pa_log(__FILE__": inet_ntop() failed: %s", strerror(errno)); + pa_log(__FILE__": inet_ntop(): %s", pa_cstrerror(errno)); return NULL; } @@ -454,7 +455,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { socklen_t sa_len = sizeof(sa); if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) { - pa_log(__FILE__": getsockname() failed: %s", strerror(errno)); + pa_log(__FILE__": getsockname(): %s", pa_cstrerror(errno)); return NULL; } @@ -474,7 +475,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { char ip[INET_ADDRSTRLEN]; if (!inet_ntop(AF_INET, &sa.sin_addr, ip, sizeof(ip))) { - pa_log(__FILE__": inet_ntop() failed: %s", strerror(errno)); + pa_log(__FILE__": inet_ntop(): %s", pa_cstrerror(errno)); return NULL; } diff --git a/src/polypcore/socket-util.c b/src/polypcore/socket-util.c index acbb7c1f..06cdc625 100644 --- a/src/polypcore/socket-util.c +++ b/src/polypcore/socket-util.c @@ -59,6 +59,7 @@ #include "winsock.h" +#include #include #include @@ -198,7 +199,7 @@ int pa_unix_socket_is_stale(const char *fn) { int fd = -1, ret = -1; if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s", strerror(errno)); + pa_log(__FILE__": socket(): %s", pa_cstrerror(errno)); goto finish; } diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c index 539d205e..351d79da 100644 --- a/src/utils/pacmd.c +++ b/src/utils/pacmd.c @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -53,7 +54,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { } if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(PF_UNIX, SOCK_STREAM, 0): %s", strerror(errno)); + pa_log(__FILE__": socket(PF_UNIX, SOCK_STREAM, 0): %s", pa_cstrerror(errno)); goto fail; } @@ -65,7 +66,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { int r; if ((r = connect(fd, (struct sockaddr*) &sa, sizeof(sa))) < 0 && (errno != ECONNREFUSED && errno != ENOENT)) { - pa_log(__FILE__": connect() failed: %s", strerror(errno)); + pa_log(__FILE__": connect(): %s", pa_cstrerror(errno)); goto fail; } @@ -96,7 +97,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { for (;;) { if (select(FD_SETSIZE, &ifds, &ofds, NULL, NULL) < 0) { - pa_log(__FILE__": select() failed: %s", strerror(errno)); + pa_log(__FILE__": select(): %s", pa_cstrerror(errno)); goto fail; } @@ -108,7 +109,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { if (r == 0) break; - pa_log(__FILE__": read() failed: %s", strerror(errno)); + pa_log(__FILE__": read(): %s", pa_cstrerror(errno)); goto fail; } @@ -124,7 +125,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { if (r == 0) break; - pa_log(__FILE__": read() failed: %s", strerror(errno)); + pa_log(__FILE__": read(): %s", pa_cstrerror(errno)); goto fail; } @@ -137,7 +138,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { assert(obuf_length); if ((r = write(1, obuf + obuf_index, obuf_length)) < 0) { - pa_log(__FILE__": write() failed: %s", strerror(errno)); + pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); goto fail; } @@ -151,7 +152,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { assert(ibuf_length); if ((r = write(fd, ibuf + ibuf_index, ibuf_length)) < 0) { - pa_log(__FILE__": write() failed: %s", strerror(errno)); + pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); goto fail; } -- cgit From 97ec77c66060abac88305a0acd1c86312b8ae6f2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 22 May 2006 15:56:28 +0000 Subject: add missing #include git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@946 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-zeroconf-publish.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index 5c5db286..bd4a2d97 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -30,6 +30,7 @@ #include #include +#include #include #include -- cgit From d71dc9b022209480c2ddecdc8b1356ee02c69a55 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 22 May 2006 16:47:26 +0000 Subject: Fix TLS on Win32 to something a bit more safe and portable (compiler-wise). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@947 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/error.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/src/polyp/error.c b/src/polyp/error.c index 062b6f36..ee9ce51b 100644 --- a/src/polyp/error.c +++ b/src/polyp/error.c @@ -90,7 +90,78 @@ static void inittls(void) { #elif HAVE_WINDOWS_H -static __declspec(thread) char *tlsstr; +static DWORD tlsstr_key = TLS_OUT_OF_INDEXES; +static DWORD monitor_key = TLS_OUT_OF_INDEXES; + +static void inittls(void) { + HANDLE mutex; + char name[64]; + + sprintf(name, "polypaudio%d", (int)GetCurrentProcessId()); + + mutex = CreateMutex(NULL, FALSE, name); + if (!mutex) { + fprintf(stderr, __FILE__ ": CRITICAL: Unable to create named mutex (%d)\n", (int)GetLastError()); + exit(-1); + } + + WaitForSingleObject(mutex, INFINITE); + + if (tlsstr_key == TLS_OUT_OF_INDEXES) { + tlsstr_key = TlsAlloc(); + monitor_key = TlsAlloc(); + if ((tlsstr_key == TLS_OUT_OF_INDEXES) || (monitor_key == TLS_OUT_OF_INDEXES)) { + fprintf(stderr, __FILE__ ": CRITICAL: Unable to allocate TLS key (%d)\n", (int)GetLastError()); + exit(-1); + } + } + + ReleaseMutex(mutex); + + CloseHandle(mutex); +} + +/* + * This is incredibly brain dead, but this is necessary when dealing with + * the hell that is Win32. + */ +struct monitor_data { + HANDLE thread; + void *data; +}; + +static DWORD WINAPI monitor_thread(LPVOID param) { + struct monitor_data *data; + + data = (struct monitor_data*)param; + assert(data); + + WaitForSingleObject(data->thread, INFINITE); + + CloseHandle(data->thread); + pa_xfree(data->data); + pa_xfree(data); + + return 0; +} + +static void start_monitor(void) { + HANDLE thread; + struct monitor_data *data; + + data = pa_xnew(struct monitor_data, 1); + assert(data); + + DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), + GetCurrentProcess(), &data->thread, 0, FALSE, DUPLICATE_SAME_ACCESS); + + thread = CreateThread(NULL, 0, monitor_thread, data, 0, NULL); + assert(thread); + + TlsSetValue(monitor_key, data); + + CloseHandle(thread); +} #else @@ -112,6 +183,16 @@ char* pa_cstrerror(int errnum) { pthread_once(&cstrerror_once, inittls); tlsstr = pthread_getspecific(tlsstr_key); +#elif defined(HAVE_WINDOWS_H) + char *tlsstr; + struct monitor_data *data; + + inittls(); + + tlsstr = TlsGetValue(tlsstr_key); + if (!tlsstr) + start_monitor(); + data = TlsGetValue(monitor_key); #endif if (tlsstr) @@ -144,6 +225,9 @@ char* pa_cstrerror(int errnum) { #ifdef HAVE_PTHREAD pthread_setspecific(tlsstr_key, tlsstr); +#elif defined(HAVE_WINDOWS_H) + TlsSetValue(tlsstr_key, tlsstr); + data->data = tlsstr; #endif return tlsstr; -- cgit From 1b72d026344866f59ee2caaa66250d5932faea78 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 23 May 2006 07:33:33 +0000 Subject: Fix some warnings. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@948 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/sample.c | 1 + src/polypcore/core-util.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/polyp/sample.c b/src/polyp/sample.c index 320e31a0..9c3b9f91 100644 --- a/src/polyp/sample.c +++ b/src/polyp/sample.c @@ -46,6 +46,7 @@ size_t pa_sample_size(const pa_sample_spec *spec) { return 4; default: assert(0); + return 0; } } diff --git a/src/polypcore/core-util.c b/src/polypcore/core-util.c index 0e7f77a4..bb6a3d85 100644 --- a/src/polypcore/core-util.c +++ b/src/polypcore/core-util.c @@ -564,7 +564,7 @@ static int is_group(gid_t gid, const char *name) { data = pa_xmalloc(n); if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) { - pa_log(__FILE__": getgrgid_r(%u): %s", gid, pa_cstrerror(errno)); + pa_log(__FILE__": getgrgid_r(%u): %s", (unsigned)gid, pa_cstrerror(errno)); goto finish; } -- cgit From 8f111b0adde21ef75cdfb7d6cf30169219256b22 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 23 May 2006 14:39:15 +0000 Subject: change return type of pa_cstrerror() to "const char*" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@949 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/error.c | 2 +- src/polyp/error.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/polyp/error.c b/src/polyp/error.c index ee9ce51b..0e3b506f 100644 --- a/src/polyp/error.c +++ b/src/polyp/error.c @@ -170,7 +170,7 @@ static char *tlsstr; #endif -char* pa_cstrerror(int errnum) { +const char* pa_cstrerror(int errnum) { const char *origbuf; #ifdef HAVE_STRERROR_R diff --git a/src/polyp/error.h b/src/polyp/error.h index 33507bfd..1d7b2ca6 100644 --- a/src/polyp/error.h +++ b/src/polyp/error.h @@ -37,7 +37,7 @@ const char* pa_strerror(int error); * string to UTF-8. The function is thread safe but the returned string is * only guaranteed to exist until the thread exits or pa_cstrerror() is * called again from the same thread. */ -char* pa_cstrerror(int errnum); +const char* pa_cstrerror(int errnum); PA_C_DECL_END -- cgit From 103154940d09855b102ab823f032e854f5327ba1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 23 May 2006 14:42:23 +0000 Subject: add new padsp utility: a $LD_PRELOAD wrapper for using the OSS API with polypaudio git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@950 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 23 +- src/utils/padsp.c | 1284 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/utils/padsp.in | 30 ++ 3 files changed, 1335 insertions(+), 2 deletions(-) create mode 100644 src/utils/padsp.c create mode 100644 src/utils/padsp.in diff --git a/src/Makefile.am b/src/Makefile.am index 30e73512..6327d550 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -78,6 +78,7 @@ EXTRA_DIST = \ daemon/default.pa.in \ depmod.py \ daemon/esdcompat.sh.in \ + utils/padsp.in \ modules/module-defs.h.m4 polypconf_DATA = \ @@ -173,6 +174,24 @@ pabrowse_LDADD = $(AM_LDADD) libpolyp.la libpolyp-browse.la pabrowse_CFLAGS = $(AM_CFLAGS) pabrowse_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +lib_LTLIBRARIES = +CLEANFILES= + +if HAVE_OSS +lib_LTLIBRARIES += libpolypdsp.la +libpolypdsp_la_SOURCES = utils/padsp.c +libpolypdsp_la_CFLAGS = $(AM_CFLAGS) +libpolypdsp_la_LIBADD = $(AM_LIBADD) libpolyp.la +libpolypdsp_la_LDFLAGS = -avoid-version + +CLEANFILES+=padsp +bin_SCRIPTS += padsp + +padsp: utils/padsp.in Makefile + sed -e 's,@LIBPOLYPDSP\@,$(libdir)/libpolypdsp.so,g' < $< > $@ + +endif + ################################### # Test programs # ################################### @@ -325,7 +344,7 @@ polypinclude_HEADERS += \ endif endif -lib_LTLIBRARIES = \ +lib_LTLIBRARIES += \ libpolyp.la \ libpolyp-simple.la @@ -1141,7 +1160,7 @@ suid: polypaudio chown root $< chmod u+s $< -CLEANFILES=esdcompat.sh client.conf default.pa daemon.conf +CLEANFILES+=esdcompat.sh client.conf default.pa daemon.conf esdcompat.sh: daemon/esdcompat.sh.in Makefile sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ diff --git a/src/utils/padsp.c b/src/utils/padsp.c new file mode 100644 index 00000000..06bdd575 --- /dev/null +++ b/src/utils/padsp.c @@ -0,0 +1,1284 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef _FILE_OFFSET_BITS +#undef _FILE_OFFSET_BITS +#endif + +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE 1 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +typedef enum { + FD_INFO_MIXER, + FD_INFO_PLAYBACK +} fd_info_type_t; + +typedef struct fd_info fd_info; + +struct fd_info { + pthread_mutex_t mutex; + int ref; + + fd_info_type_t type; + int app_fd, thread_fd; + + pa_sample_spec sample_spec; + size_t fragment_size; + unsigned n_fragments; + + pa_threaded_mainloop *mainloop; + pa_context *context; + pa_stream *stream; + + pa_io_event *io_event; + + void *buf; + + int operation_success; + + PA_LLIST_FIELDS(fd_info); +}; + +static int dsp_drain(fd_info *i); + +static pthread_mutex_t fd_infos_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t func_mutex = PTHREAD_MUTEX_INITIALIZER; + +static PA_LLIST_HEAD(fd_info, fd_infos) = NULL; + +static int (*_ioctl)(int, int, void*) = NULL; +static int (*_close)(int) = NULL; +static int (*_open)(const char *, int, mode_t) = NULL; +static FILE* (*_fopen)(const char *path, const char *mode) = NULL; +static int (*_open64)(const char *, int, mode_t) = NULL; +static FILE* (*_fopen64)(const char *path, const char *mode) = NULL; +static int (*_fclose)(FILE *f) = NULL; + +#define LOAD_IOCTL_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_ioctl) \ + _ioctl = (int (*)(int, int, void*)) dlsym(RTLD_NEXT, "ioctl"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +#define LOAD_OPEN_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_open) \ + _open = (int (*)(const char *, int, mode_t)) dlsym(RTLD_NEXT, "open"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +#define LOAD_OPEN64_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_open64) \ + _open64 = (int (*)(const char *, int, mode_t)) dlsym(RTLD_NEXT, "open64"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +#define LOAD_CLOSE_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_close) \ + _close = (int (*)(int)) dlsym(RTLD_NEXT, "close"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +#define LOAD_FOPEN_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_fopen) \ + _fopen = (FILE* (*)(const char *, const char*)) dlsym(RTLD_NEXT, "fopen"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +#define LOAD_FOPEN64_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_fopen64) \ + _fopen64 = (FILE* (*)(const char *, const char*)) dlsym(RTLD_NEXT, "fopen64"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +#define LOAD_FCLOSE_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_fclose) \ + _fclose = (int (*)(FILE *)) dlsym(RTLD_NEXT, "fclose"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +static void debug(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); + +static void debug(const char *format, ...) { + va_list ap; + if (getenv("PADSP_DEBUG")) { + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + } +} + +static pthread_key_t recursion_key; + +static void recursion_key_alloc(void) { + pthread_key_create(&recursion_key, NULL); +} + +static int function_enter(void) { + /* Avoid recursive calls */ + static pthread_once_t recursion_key_once = PTHREAD_ONCE_INIT; + pthread_once(&recursion_key_once, recursion_key_alloc); + + if (pthread_getspecific(recursion_key)) + return 0; + + pthread_setspecific(recursion_key, (void*) 1); + return 1; +} + +static void function_exit(void) { + pthread_setspecific(recursion_key, NULL); +} + +static void fd_info_free(fd_info *i) { + assert(i); + + debug(__FILE__": freeing fd info (fd=%i)\n", i->app_fd); + + dsp_drain(i); + + if (i->mainloop) + pa_threaded_mainloop_stop(i->mainloop); + + if (i->stream) { + pa_stream_disconnect(i->stream); + pa_stream_unref(i->stream); + } + + if (i->context) { + pa_context_disconnect(i->context); + pa_context_unref(i->context); + } + + if (i->mainloop) + pa_threaded_mainloop_free(i->mainloop); + + if (i->app_fd >= 0) { + LOAD_CLOSE_FUNC(); + _close(i->app_fd); + } + + if (i->thread_fd >= 0) { + LOAD_CLOSE_FUNC(); + _close(i->thread_fd); + } + + free(i->buf); + + pthread_mutex_destroy(&i->mutex); + free(i); +} + +static fd_info *fd_info_ref(fd_info *i) { + assert(i); + + pthread_mutex_lock(&i->mutex); + assert(i->ref >= 1); + i->ref++; + +/* debug(__FILE__": ref++, now %i\n", i->ref); */ + pthread_mutex_unlock(&i->mutex); + + return i; +} + +static void fd_info_unref(fd_info *i) { + int r; + pthread_mutex_lock(&i->mutex); + assert(i->ref >= 1); + r = --i->ref; +/* debug(__FILE__": ref--, now %i\n", i->ref); */ + pthread_mutex_unlock(&i->mutex); + + if (r <= 0) + fd_info_free(i); +} + +static void context_state_cb(pa_context *c, void *userdata) { + fd_info *i = userdata; + assert(c); + + switch (pa_context_get_state(c)) { + case PA_CONTEXT_READY: + case PA_CONTEXT_TERMINATED: + case PA_CONTEXT_FAILED: + pa_threaded_mainloop_signal(i->mainloop, 0); + break; + + case PA_CONTEXT_UNCONNECTED: + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + } +} + +static void reset_params(fd_info *i) { + assert(i); + + i->sample_spec.format = PA_SAMPLE_ULAW; + i->sample_spec.channels = 1; + i->sample_spec.rate = 8000; + i->fragment_size = 1024; + i->n_fragments = 0; +} + +static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { + fd_info *i; + int sfds[2] = { -1, -1 }; + + debug(__FILE__": fd_info_new()\n"); + + signal(SIGPIPE, SIG_IGN); /* Yes, ugly as hell */ + + if (!(i = malloc(sizeof(fd_info)))) { + *_errno = ENOMEM; + goto fail; + } + + i->app_fd = i->thread_fd = -1; + i->type = type; + + i->mainloop = NULL; + i->context = NULL; + i->stream = NULL; + i->io_event = NULL; + pthread_mutex_init(&i->mutex, NULL); + i->ref = 1; + i->buf = NULL; + PA_LLIST_INIT(fd_info, i); + + reset_params(i); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfds) < 0) { + *_errno = errno; + debug(__FILE__": socket() failed: %s\n", strerror(errno)); + goto fail; + } + + i->app_fd = sfds[0]; + i->thread_fd = sfds[1]; + + if (!(i->mainloop = pa_threaded_mainloop_new())) { + *_errno = EIO; + debug(__FILE__": pa_threaded_mainloop_new() failed\n"); + goto fail; + } + + if (!(i->context = pa_context_new(pa_threaded_mainloop_get_api(i->mainloop), "oss"))) { + *_errno = EIO; + debug(__FILE__": pa_context_new() failed\n"); + goto fail; + } + + pa_context_set_state_callback(i->context, context_state_cb, i); + + if (pa_context_connect(i->context, NULL, 0, NULL) < 0) { + *_errno = ECONNREFUSED; + debug(__FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + pa_threaded_mainloop_lock(i->mainloop); + + if (pa_threaded_mainloop_start(i->mainloop) < 0) { + *_errno = EIO; + debug(__FILE__": pa_threaded_mainloop_start() failed\n"); + goto unlock_and_fail; + } + + /* Wait until the context is ready */ + pa_threaded_mainloop_wait(i->mainloop); + + if (pa_context_get_state(i->context) != PA_CONTEXT_READY) { + *_errno = ECONNREFUSED; + debug(__FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + goto unlock_and_fail; + } + + pa_threaded_mainloop_unlock(i->mainloop); + return i; + +unlock_and_fail: + + pa_threaded_mainloop_unlock(i->mainloop); + +fail: + + if (i) + fd_info_unref(i); + + return NULL; +} + +static void fd_info_add_to_list(fd_info *i) { + assert(i); + + pthread_mutex_lock(&fd_infos_mutex); + PA_LLIST_PREPEND(fd_info, fd_infos, i); + pthread_mutex_unlock(&fd_infos_mutex); + + fd_info_ref(i); +} + +static void fd_info_remove_from_list(fd_info *i) { + assert(i); + + pthread_mutex_lock(&fd_infos_mutex); + PA_LLIST_REMOVE(fd_info, fd_infos, i); + pthread_mutex_unlock(&fd_infos_mutex); + + fd_info_unref(i); +} + +static fd_info* fd_info_find(int fd) { + fd_info *i; + + pthread_mutex_lock(&fd_infos_mutex); + + for (i = fd_infos; i; i = i->next) + if (i->app_fd == fd) { + fd_info_ref(i); + break; + } + + pthread_mutex_unlock(&fd_infos_mutex); + + return i; +} + +static void fix_metrics(fd_info *i) { + size_t fs; + char t[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + fs = pa_frame_size(&i->sample_spec); + i->fragment_size = (i->fragment_size/fs)*fs; + + if (i->n_fragments < 2) + i->n_fragments = 12; + + if (i->fragment_size <= 0) + if ((i->fragment_size = pa_bytes_per_second(&i->sample_spec) / 2 / i->n_fragments) <= 0) + i->fragment_size = 1024; + + debug(__FILE__": sample spec: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); + debug(__FILE__": fixated metrics to %i fragments, %i bytes each.\n", i->n_fragments, i->fragment_size); +} + +static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { + fd_info *i = userdata; + assert(s); + + if (i->io_event) { + pa_mainloop_api *api; + api = pa_threaded_mainloop_get_api(i->mainloop); + api->io_enable(i->io_event, PA_IO_EVENT_INPUT); + } +} + +static void stream_latency_update_cb(pa_stream *s, void *userdata) { + fd_info *i = userdata; + assert(s); + + pa_threaded_mainloop_signal(i->mainloop, 0); +} + +static void fd_info_shutdown(fd_info *i) { + assert(i); + + if (i->io_event) { + pa_mainloop_api *api; + api = pa_threaded_mainloop_get_api(i->mainloop); + api->io_free(i->io_event); + i->io_event = NULL; + } + + if (i->thread_fd >= 0) { + close(i->thread_fd); + i->thread_fd = -1; + } +} + +static int fd_info_copy_data(fd_info *i, int force) { + size_t n; + + if (!i->stream) + return -1; + + if ((n = pa_stream_writable_size(i->stream)) == (size_t) -1) { + debug(__FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); + return -1; + } + + while (n >= i->fragment_size || force) { + ssize_t r; + + if (!i->buf) { + if (!(i->buf = malloc(i->fragment_size))) { + debug(__FILE__": malloc() failed.\n"); + return -1; + } + } + + if ((r = read(i->thread_fd, i->buf, i->fragment_size)) <= 0) { + + if (errno == EAGAIN) + break; + + debug(__FILE__": read(): %s\n", r == 0 ? "EOF" : strerror(errno)); + return -1; + } + + if (pa_stream_write(i->stream, i->buf, r, free, 0, PA_SEEK_RELATIVE) < 0) { + debug(__FILE__": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i->context))); + return -1; + } + + i->buf = NULL; + + assert(n >= (size_t) r); + n -= r; + } + + if (i->io_event) { + pa_mainloop_api *api; + api = pa_threaded_mainloop_get_api(i->mainloop); + api->io_enable(i->io_event, n >= i->fragment_size ? PA_IO_EVENT_INPUT : 0); + } + + return 0; +} + +static void stream_state_cb(pa_stream *s, void * userdata) { + fd_info *i = userdata; + assert(s); + + switch (pa_stream_get_state(s)) { + + case PA_STREAM_READY: + debug(__FILE__": stream established.\n"); + break; + + case PA_STREAM_FAILED: + debug(__FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + fd_info_shutdown(i); + break; + + case PA_STREAM_TERMINATED: + case PA_STREAM_UNCONNECTED: + case PA_STREAM_CREATING: + break; + } +} + +static int create_stream(fd_info *i) { + pa_buffer_attr attr; + int n; + + assert(i); + + fix_metrics(i); + + if (!(i->stream = pa_stream_new(i->context, "audio stream", &i->sample_spec, NULL))) { + debug(__FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + pa_stream_set_state_callback(i->stream, stream_state_cb, i); + pa_stream_set_write_callback(i->stream, stream_request_cb, i); + pa_stream_set_latency_update_callback(i->stream, stream_latency_update_cb, i); + + memset(&attr, 0, sizeof(attr)); + attr.maxlength = i->fragment_size * (i->n_fragments+1); + attr.tlength = i->fragment_size * i->n_fragments; + attr.prebuf = i->fragment_size; + attr.minreq = i->fragment_size; + + if (pa_stream_connect_playback(i->stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) { + debug(__FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + n = i->fragment_size; + setsockopt(i->app_fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)); + n = i->fragment_size; + setsockopt(i->thread_fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)); + + return 0; + +fail: + return -1; +} + +static void free_stream(fd_info *i) { + assert(i); + + if (i->stream) { + pa_stream_disconnect(i->stream); + pa_stream_unref(i->stream); + i->stream = NULL; + } +} + +static void io_event_cb(pa_mainloop_api *api, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) { + fd_info *i = userdata; + + pa_threaded_mainloop_signal(i->mainloop, 0); + + if (flags & PA_IO_EVENT_INPUT) { + + if (!i->stream) { + api->io_enable(e, 0); + + if (create_stream(i) < 0) + goto fail; + + } else { + if (fd_info_copy_data(i, 0) < 0) + goto fail; + } + + } else if (flags & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) + goto fail; + + return; + +fail: + /* We can't do anything better than removing the event source */ + fd_info_shutdown(i); +} + +static int dsp_open(int flags, int *_errno) { + fd_info *i; + pa_mainloop_api *api; + int ret; + int f; + + if ((flags != O_WRONLY) && (flags != (O_WRONLY|O_NONBLOCK))) { + *_errno = EACCES; + return -1; + } + + if (!(i = fd_info_new(FD_INFO_PLAYBACK, _errno))) + return -1; + + shutdown(i->thread_fd, SHUT_WR); + shutdown(i->app_fd, SHUT_RD); + + if ((flags & O_NONBLOCK) == O_NONBLOCK) { + if ((f = fcntl(i->app_fd, F_GETFL)) >= 0) + fcntl(i->app_fd, F_SETFL, f|O_NONBLOCK); + } + if ((f = fcntl(i->thread_fd, F_GETFL)) >= 0) + fcntl(i->thread_fd, F_SETFL, f|O_NONBLOCK); + + fcntl(i->app_fd, F_SETFD, FD_CLOEXEC); + fcntl(i->thread_fd, F_SETFD, FD_CLOEXEC); + + pa_threaded_mainloop_lock(i->mainloop); + api = pa_threaded_mainloop_get_api(i->mainloop); + if (!(i->io_event = api->io_new(api, i->thread_fd, PA_IO_EVENT_INPUT, io_event_cb, i))) + goto fail; + + pa_threaded_mainloop_unlock(i->mainloop); + + debug(__FILE__": dsp_open() succeeded, fd=%i\n", i->app_fd); + + fd_info_add_to_list(i); + ret = i->app_fd; + fd_info_unref(i); + + return ret; + +fail: + pa_threaded_mainloop_unlock(i->mainloop); + + if (i) + fd_info_unref(i); + + *_errno = EIO; + + debug(__FILE__": dsp_open() failed\n"); + + return -1; +} + +static int mixer_open(int flags, int *_errno) { +/* fd_info *i; */ + + *_errno = ENOSYS; + return -1; + +/* if (!(i = fd_info_new(FD_INFO_MIXER))) */ +/* return -1; */ + +} + +int open(const char *filename, int flags, ...) { + va_list args; + mode_t mode = 0; + int r, _errno = 0; + + va_start(args, flags); + if (flags & O_CREAT) + mode = va_arg(args, mode_t); + va_end(args); + + if (!function_enter()) { + LOAD_OPEN_FUNC(); + return _open(filename, flags, mode); + } + + debug(__FILE__": open()\n"); + + if (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0) { + r = dsp_open(flags, &_errno); + } else if (strcmp(filename, "/dev/mixer") == 0) { + r = mixer_open(flags, &_errno); + } else { + function_exit(); + LOAD_OPEN_FUNC(); + return _open(filename, flags, mode); + } + + function_exit(); + + if (_errno) + errno = _errno; + + return r; +} + +static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) { + *_errno = ENOSYS; + return -1; +} + +static int map_format(int *fmt, pa_sample_spec *ss) { + + switch (*fmt) { + case AFMT_MU_LAW: + ss->format = PA_SAMPLE_ULAW; + break; + + case AFMT_A_LAW: + ss->format = PA_SAMPLE_ALAW; + break; + + case AFMT_S8: + *fmt = AFMT_U8; + /* fall through */ + case AFMT_U8: + ss->format = PA_SAMPLE_U8; + break; + + case AFMT_U16_BE: + *fmt = AFMT_S16_BE; + /* fall through */ + case AFMT_S16_BE: + ss->format = PA_SAMPLE_S16BE; + break; + + case AFMT_U16_LE: + *fmt = AFMT_S16_LE; + /* fall through */ + case AFMT_S16_LE: + ss->format = PA_SAMPLE_S16LE; + break; + + default: + ss->format = PA_SAMPLE_S16NE; + *fmt = AFMT_S16_NE; + break; + } + + return 0; +} + +static int map_format_back(pa_sample_format_t format) { + switch (format) { + case PA_SAMPLE_S16LE: return AFMT_S16_LE; + case PA_SAMPLE_S16BE: return AFMT_S16_BE; + case PA_SAMPLE_ULAW: return AFMT_MU_LAW; + case PA_SAMPLE_ALAW: return AFMT_A_LAW; + case PA_SAMPLE_U8: return AFMT_U8; + default: + abort(); + } +} + +static void success_cb(pa_stream *s, int success, void *userdata) { + fd_info *i = userdata; + + assert(s); + assert(i); + + i->operation_success = success; + pa_threaded_mainloop_signal(i->mainloop, 0); +} + +static int dsp_empty_socket(fd_info *i) { + int ret = -1; + + /* Empty the socket */ + for (;;) { + int l; + + if (i->thread_fd < 0) + break; + + if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { + debug(__FILE__": SIOCINQ: %s\n", strerror(errno)); + break; + } + + if (!l) + break; + + pa_threaded_mainloop_wait(i->mainloop); + } + + return ret; +} + +static int dsp_drain(fd_info *i) { + pa_operation *o = NULL; + int r = -1; + + if (!i->mainloop) + return 0; + + debug(__FILE__": Draining.\n"); + + pa_threaded_mainloop_lock(i->mainloop); + + if (dsp_empty_socket(i) < 0) + goto fail; + + if (!i->stream) + goto fail; + + debug(__FILE__": Really draining.\n"); + + if (!(o = pa_stream_drain(i->stream, success_cb, i))) { + debug(__FILE__": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + i->operation_success = 0; + while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + if (!i->stream || pa_stream_get_state(i->stream) != PA_STREAM_READY) + goto fail; + + pa_threaded_mainloop_wait(i->mainloop); + } + + if (!i->operation_success) { + debug(__FILE__": pa_stream_drain() 2: %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + r = 0; + +fail: + + if (o) + pa_operation_unref(o); + + pa_threaded_mainloop_unlock(i->mainloop); + + return 0; +} + +static int dsp_trigger(fd_info *i) { + pa_operation *o = NULL; + int r = -1; + + fd_info_copy_data(i, 1); + + if (!i->stream) + return 0; + + pa_threaded_mainloop_lock(i->mainloop); + + if (dsp_empty_socket(i) < 0) + goto fail; + + debug(__FILE__": Triggering.\n"); + + if (!(o = pa_stream_trigger(i->stream, success_cb, i))) { + debug(__FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + i->operation_success = 0; + while (!pa_operation_get_state(o) != PA_OPERATION_DONE) { + if (!i->stream || pa_stream_get_state(i->stream) != PA_STREAM_READY) + goto fail; + + pa_threaded_mainloop_wait(i->mainloop); + } + + if (!i->operation_success) { + debug(__FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + r = 0; + +fail: + + if (o) + pa_operation_unref(o); + + pa_threaded_mainloop_unlock(i->mainloop); + + return 0; +} + +static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) { + int ret = -1; + + switch (request) { + case SNDCTL_DSP_SETFMT: { + debug(__FILE__": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp); + + pa_threaded_mainloop_lock(i->mainloop); + + if (*(int*) argp == AFMT_QUERY) + *(int*) argp = map_format_back(i->sample_spec.format); + else { + map_format((int*) argp, &i->sample_spec); + free_stream(i); + } + + pa_threaded_mainloop_unlock(i->mainloop); + break; + } + + case SNDCTL_DSP_SPEED: { + pa_sample_spec ss; + int valid; + + debug(__FILE__": SNDCTL_DSP_SPEED: %i\n", *(int*) argp); + + pa_threaded_mainloop_lock(i->mainloop); + + ss = i->sample_spec; + ss.rate = *(int*) argp; + + if ((valid = pa_sample_spec_valid(&ss))) { + i->sample_spec = ss; + free_stream(i); + } + + pa_threaded_mainloop_unlock(i->mainloop); + + if (!valid) { + *_errno = EINVAL; + goto fail; + } + + break; + } + + case SNDCTL_DSP_STEREO: + debug(__FILE__": SNDCTL_DSP_STEREO: %i\n", *(int*) argp); + + pa_threaded_mainloop_lock(i->mainloop); + + i->sample_spec.channels = *(int*) argp ? 2 : 1; + free_stream(i); + + pa_threaded_mainloop_unlock(i->mainloop); + return 0; + + case SNDCTL_DSP_CHANNELS: { + pa_sample_spec ss; + int valid; + + debug(__FILE__": SNDCTL_DSP_CHANNELS: %i\n", *(int*) argp); + + pa_threaded_mainloop_lock(i->mainloop); + + ss = i->sample_spec; + ss.channels = *(int*) argp; + + if ((valid = pa_sample_spec_valid(&ss))) { + i->sample_spec = ss; + free_stream(i); + } + + pa_threaded_mainloop_unlock(i->mainloop); + + if (!valid) { + *_errno = EINVAL; + goto fail; + } + + break; + } + + case SNDCTL_DSP_GETBLKSIZE: + debug(__FILE__": SNDCTL_DSP_GETBLKSIZE\n"); + + pa_threaded_mainloop_lock(i->mainloop); + + fix_metrics(i); + *(int*) argp = i->fragment_size; + + pa_threaded_mainloop_unlock(i->mainloop); + + break; + + case SNDCTL_DSP_SETFRAGMENT: + debug(__FILE__": SNDCTL_DSP_SETFRAGMENT: 0x%8x\n", *(int*) argp); + + pa_threaded_mainloop_lock(i->mainloop); + + i->fragment_size = 1 << (*(int*) argp); + i->n_fragments = (*(int*) argp) >> 16; + + free_stream(i); + + pa_threaded_mainloop_unlock(i->mainloop); + + break; + + case SNDCTL_DSP_GETCAPS: + debug(__FILE__": SNDCTL_DSP_CAPS\n"); + + *(int*) argp = DSP_CAP_MULTI; + break; + + case SNDCTL_DSP_GETODELAY: { + int l; + + debug(__FILE__": SNDCTL_DSP_GETODELAY\n"); + + pa_threaded_mainloop_lock(i->mainloop); + + *(int*) argp = 0; + + for (;;) { + pa_usec_t usec; + if (!i->stream || pa_stream_get_state(i->stream) != PA_STREAM_READY) + break; + + if (pa_stream_get_latency(i->stream, &usec, NULL) >= 0) { + *(int*) argp = pa_usec_to_bytes(usec, &i->sample_spec); + break; + } + + if (pa_context_errno(i->context) != PA_ERR_NODATA) { + debug(__FILE__": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i->context))); + break; + } + + pa_threaded_mainloop_wait(i->mainloop); + } + + if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) + debug(__FILE__": SIOCINQ failed: %s\n", strerror(errno)); + else + *(int*) argp += l; + + pa_threaded_mainloop_unlock(i->mainloop); + + debug(__FILE__": ODELAY: %i\n", *(int*) argp); + + break; + } + + case SNDCTL_DSP_RESET: { + debug(__FILE__": SNDCTL_DSP_RESET\n"); + + pa_threaded_mainloop_lock(i->mainloop); + + free_stream(i); + reset_params(i); + + pa_threaded_mainloop_unlock(i->mainloop); + break; + } + + case SNDCTL_DSP_GETFMTS: { + debug(__FILE__": SNDCTL_DSP_GETFMTS\n"); + + *(int*) argp = AFMT_MU_LAW|AFMT_A_LAW|AFMT_U8|AFMT_S16_LE|AFMT_S16_BE; + break; + } + + case SNDCTL_DSP_POST: + debug(__FILE__": SNDCTL_DSP_POST\n"); + + if (dsp_trigger(i) < 0) + *_errno = EIO; + break; + + case SNDCTL_DSP_SYNC: + debug(__FILE__": SNDCTL_DSP_SYNC\n"); + + if (dsp_drain(i) < 0) + *_errno = EIO; + + break; + + case SNDCTL_DSP_GETOSPACE: { + audio_buf_info *bi = (audio_buf_info*) argp; + int l; + size_t k = 0; + + debug(__FILE__": SNDCTL_DSP_GETOSPACE\n"); + + pa_threaded_mainloop_lock(i->mainloop); + + fix_metrics(i); + + if (i->stream) { + if ((k = pa_stream_writable_size(i->stream)) == (size_t) -1) + debug(__FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); + } else + k = i->fragment_size * i->n_fragments; + + if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { + debug(__FILE__": SIOCINQ failed: %s\n", strerror(errno)); + l = 0; + } + + bi->fragsize = i->fragment_size; + bi->fragstotal = i->n_fragments; + bi->bytes = k > (size_t) l ? k - l : 0; + bi->fragments = bi->bytes / bi->fragsize; + + pa_threaded_mainloop_unlock(i->mainloop); + + debug(__FILE__": fragsize=%i, fragstotal=%i, bytes=%i, fragments=%i\n", bi->fragsize, bi->fragstotal, bi->bytes, bi->fragments); + + break; + } + + default: + debug(__FILE__": unknwon ioctl 0x%08lx\n", request); + + *_errno = EINVAL; + goto fail; + } + + ret = 0; + +fail: + + return ret; +} + +int ioctl(int fd, unsigned long request, ...) { + fd_info *i; + va_list args; + void *argp; + int r, _errno = 0; + + debug(__FILE__": ioctl()\n"); + + va_start(args, request); + argp = va_arg(args, void *); + va_end(args); + + if (!function_enter()) { + LOAD_IOCTL_FUNC(); + return _ioctl(fd, request, argp); + } + + if (!(i = fd_info_find(fd))) { + function_exit(); + LOAD_IOCTL_FUNC(); + return _ioctl(fd, request, argp); + } + + if (i->type == FD_INFO_MIXER) + r = mixer_ioctl(i, request, argp, &_errno); + else + r = dsp_ioctl(i, request, argp, &_errno); + + fd_info_unref(i); + + if (_errno) + errno = _errno; + + function_exit(); + + return r; +} + +int close(int fd) { + fd_info *i; + + debug(__FILE__": close()\n"); + + if (!function_enter()) { + LOAD_CLOSE_FUNC(); + return _close(fd); + } + + if (!(i = fd_info_find(fd))) { + function_exit(); + LOAD_CLOSE_FUNC(); + return _close(fd); + } + + fd_info_remove_from_list(i); + fd_info_unref(i); + + function_exit(); + + return 0; +} + +int open64(const char *filename, int flags, ...) { + va_list args; + mode_t mode = 0; + + debug(__FILE__": open64()\n"); + + va_start(args, flags); + if (flags & O_CREAT) + mode = va_arg(args, mode_t); + va_end(args); + + if (strcmp(filename, "/dev/dsp") != 0 && + strcmp(filename, "/dev/adsp") != 0 && + strcmp(filename, "/dev/mixer") != 0) { + LOAD_OPEN64_FUNC(); + return _open64(filename, flags, mode); + } + + return open(filename, flags, mode); +} + +FILE* fopen(const char *filename, const char *mode) { + FILE *f = NULL; + int fd; + + debug(__FILE__": fopen()\n"); + + if (strcmp(filename, "/dev/dsp") != 0 && + strcmp(filename, "/dev/adsp") != 0 && + strcmp(filename, "/dev/mixer") != 0) { + LOAD_FOPEN_FUNC(); + return _fopen(filename, mode); + } + + if (strcmp(mode, "wb") != 0) { + errno = EACCES; + return NULL; + } + + if ((fd = open(filename, O_WRONLY)) < 0) + return NULL; + + if (!(f = fdopen(fd, "wb"))) { + close(fd); + return NULL; + } + + return f; +} + +FILE *fopen64(const char *filename, const char *mode) { + + debug(__FILE__": fopen64()\n"); + + if (strcmp(filename, "/dev/dsp") != 0 && + strcmp(filename, "/dev/adsp") != 0 && + strcmp(filename, "/dev/mixer") != 0) { + LOAD_FOPEN64_FUNC(); + return _fopen64(filename, mode); + } + + return fopen(filename, mode); +} + +int fclose(FILE *f) { + fd_info *i; + + debug(__FILE__": fclose()\n"); + + if (!function_enter()) { + LOAD_FCLOSE_FUNC(); + return _fclose(f); + } + + if (!(i = fd_info_find(fileno(f)))) { + function_exit(); + LOAD_FCLOSE_FUNC(); + return _fclose(f); + } + + fd_info_remove_from_list(i); + + /* Dirty trick to avoid that the fd is not freed twice, once by us + * and once by the real fclose() */ + i->app_fd = -1; + + fd_info_unref(i); + + function_exit(); + + LOAD_FCLOSE_FUNC(); + return _fclose(f); +} diff --git a/src/utils/padsp.in b/src/utils/padsp.in new file mode 100644 index 00000000..d82e92fe --- /dev/null +++ b/src/utils/padsp.in @@ -0,0 +1,30 @@ +#!/bin/sh + +# $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +if [ x"$LD_PRELOAD" = x ] ; then + LD_PRELOAD="@LIBPOLYPDSP@" +else + LD_PRELOAD="$LD_PRELOAD @LIBPOLYPDSP@" +fi + +export LD_PRELOAD + +exec "$@" -- cgit From 7906985d2af27a187eac7260f641a07c39bb705e Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 23 May 2006 15:24:29 +0000 Subject: Cast size_t to long to be more compatible with 64-bit systems. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@951 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 06bdd575..63f79eb1 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -417,7 +417,7 @@ static void fix_metrics(fd_info *i) { i->fragment_size = 1024; debug(__FILE__": sample spec: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); - debug(__FILE__": fixated metrics to %i fragments, %i bytes each.\n", i->n_fragments, i->fragment_size); + debug(__FILE__": fixated metrics to %i fragments, %li bytes each.\n", i->n_fragments, (long)i->fragment_size); } static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { -- cgit From e99afdae388018f119c16c3a331e01898ab9a90a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 23 May 2006 16:37:33 +0000 Subject: pass the binary name as client name to polypaudio git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@952 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 63f79eb1..ec073a28 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -278,9 +278,21 @@ static void reset_params(fd_info *i) { i->n_fragments = 0; } +static char *client_name(char *buf, size_t n) { + char p[PATH_MAX]; + + if (pa_get_binary_name(p, sizeof(p))) + snprintf(buf, n, "oss[%s]", pa_path_get_filename(p)); + else + snprintf(buf, n, "oss"); + + return buf; +} + static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { fd_info *i; int sfds[2] = { -1, -1 }; + char name[64]; debug(__FILE__": fd_info_new()\n"); @@ -320,7 +332,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { goto fail; } - if (!(i->context = pa_context_new(pa_threaded_mainloop_get_api(i->mainloop), "oss"))) { + if (!(i->context = pa_context_new(pa_threaded_mainloop_get_api(i->mainloop), client_name(name, sizeof(name))))) { *_errno = EIO; debug(__FILE__": pa_context_new() failed\n"); goto fail; -- cgit From 23b123d361959553fc9e467dd4b605adee00f07e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 23 May 2006 23:06:28 +0000 Subject: - use pthread_atfork() to disable open sound streams in the child after a fork. Obviusly sound won't work in child process but at least we don't leak fds from the parent. Now any operation on the device fd in the child will result in an EBADF error, which seems somewhat clean to me. - flush our unix socket properly on RESET ioctl git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@953 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 122 insertions(+), 6 deletions(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index ec073a28..a69676ab 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -60,6 +60,7 @@ typedef struct fd_info fd_info; struct fd_info { pthread_mutex_t mutex; int ref; + int unusable; fd_info_type_t type; int app_fd, thread_fd; @@ -82,6 +83,7 @@ struct fd_info { }; static int dsp_drain(fd_info *i); +static void fd_info_remove_from_list(fd_info *i); static pthread_mutex_t fd_infos_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t func_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -289,14 +291,101 @@ static char *client_name(char *buf, size_t n) { return buf; } +static void atfork_prepare(void) { + fd_info *i; + + debug(__FILE__": atfork_prepare() enter\n"); + + function_enter(); + + pthread_mutex_lock(&fd_infos_mutex); + + for (i = fd_infos; i; i = i->next) { + pthread_mutex_lock(&i->mutex); + pa_threaded_mainloop_lock(i->mainloop); + } + + pthread_mutex_lock(&func_mutex); + + + debug(__FILE__": atfork_prepare() exit\n"); +} + +static void atfork_parent(void) { + fd_info *i; + + debug(__FILE__": atfork_parent() enter\n"); + + pthread_mutex_unlock(&func_mutex); + + for (i = fd_infos; i; i = i->next) { + pa_threaded_mainloop_unlock(i->mainloop); + pthread_mutex_unlock(&i->mutex); + } + + pthread_mutex_unlock(&fd_infos_mutex); + + function_exit(); + + debug(__FILE__": atfork_parent() exit\n"); +} + +static void atfork_child(void) { + fd_info *i; + + debug(__FILE__": atfork_child() enter\n"); + + /* We do only the bare minimum to get all fds closed */ + pthread_mutex_init(&func_mutex, NULL); + pthread_mutex_init(&fd_infos_mutex, NULL); + + for (i = fd_infos; i; i = i->next) { + pthread_mutex_init(&i->mutex, NULL); + + if (i->context) { + pa_context_disconnect(i->context); + pa_context_unref(i->context); + i->context = NULL; + } + + if (i->stream) { + pa_stream_unref(i->stream); + i->stream = NULL; + } + + if (i->app_fd >= 0) { + close(i->app_fd); + i->app_fd = -1; + } + + if (i->thread_fd >= 0) { + close(i->thread_fd); + i->thread_fd = -1; + } + + i->unusable = 1; + } + + function_exit(); + + debug(__FILE__": atfork_child() exit\n"); +} + +static void install_atfork(void) { + pthread_atfork(atfork_prepare, atfork_parent, atfork_child); +} + static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { fd_info *i; int sfds[2] = { -1, -1 }; char name[64]; + static pthread_once_t install_atfork_once = PTHREAD_ONCE_INIT; debug(__FILE__": fd_info_new()\n"); signal(SIGPIPE, SIG_IGN); /* Yes, ugly as hell */ + + pthread_once(&install_atfork_once, install_atfork); if (!(i = malloc(sizeof(fd_info)))) { *_errno = ENOMEM; @@ -313,6 +402,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { pthread_mutex_init(&i->mutex, NULL); i->ref = 1; i->buf = NULL; + i->unusable = 0; PA_LLIST_INIT(fd_info, i); reset_params(i); @@ -404,7 +494,7 @@ static fd_info* fd_info_find(int fd) { pthread_mutex_lock(&fd_infos_mutex); for (i = fd_infos; i; i = i->next) - if (i->app_fd == fd) { + if (i->app_fd == fd && !i->unusable) { fd_info_ref(i); break; } @@ -546,7 +636,7 @@ static int create_stream(fd_info *i) { fix_metrics(i); - if (!(i->stream = pa_stream_new(i->context, "audio stream", &i->sample_spec, NULL))) { + if (!(i->stream = pa_stream_new(i->context, "Audio Stream", &i->sample_spec, NULL))) { debug(__FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -784,6 +874,30 @@ static void success_cb(pa_stream *s, int success, void *userdata) { pa_threaded_mainloop_signal(i->mainloop, 0); } +static int dsp_flush_socket(fd_info *i) { + int l; + + if (i->thread_fd < 0) + return -1; + + if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { + debug(__FILE__": SIOCINQ: %s\n", strerror(errno)); + return -1; + } + + while (l > 0) { + char buf[1024]; + size_t k; + + k = (size_t) l > sizeof(buf) ? sizeof(buf) : (size_t) l; + if (read(i->thread_fd, buf, k) < 0) + debug(__FILE__": read(): %s\n", strerror(errno)); + l -= k; + } + + return 0; +} + static int dsp_empty_socket(fd_info *i) { int ret = -1; @@ -791,7 +905,7 @@ static int dsp_empty_socket(fd_info *i) { for (;;) { int l; - if (i->thread_fd < 0) + if (i->thread_fd < 0 || !i->stream) break; if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { @@ -861,8 +975,6 @@ static int dsp_trigger(fd_info *i) { pa_operation *o = NULL; int r = -1; - fd_info_copy_data(i, 1); - if (!i->stream) return 0; @@ -926,6 +1038,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_SPEED: { pa_sample_spec ss; int valid; + char t[256]; debug(__FILE__": SNDCTL_DSP_SPEED: %i\n", *(int*) argp); @@ -939,13 +1052,15 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) free_stream(i); } + debug(__FILE__": ss: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); + pa_threaded_mainloop_unlock(i->mainloop); if (!valid) { *_errno = EINVAL; goto fail; } - + break; } @@ -1063,6 +1178,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_threaded_mainloop_lock(i->mainloop); free_stream(i); + dsp_flush_socket(i); reset_params(i); pa_threaded_mainloop_unlock(i->mainloop); -- cgit From 46fee4641864df8972beb95f9d9af5670198add9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 23 May 2006 23:57:50 +0000 Subject: implement emulation of /dev/sndstat git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@954 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 102 insertions(+), 15 deletions(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index a69676ab..ed34ac8a 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -771,11 +771,83 @@ static int mixer_open(int flags, int *_errno) { } +static int sndstat_open(int flags, int *_errno) { + static const char sndstat[] = + "Sound Driver:3.8.1a-980706 (Polypaudio Virtual OSS)\n" + "Kernel: POSIX\n" + "Config options: 0\n" + "\n" + "Installed drivers:\n" + "Type 255: Polypaudio Virtual OSS\n" + "\n" + "Card config:\n" + "Polypaudio Virtual OSS\n" + "\n" + "Audio devices:\n" + "0: Polypaudio Virtual OSS\n" + "\n" + "Synth devices: NOT ENABLED IN CONFIG\n" + "\n" + "Midi devices:\n" + "\n" + "Timers:\n" + "\n" + "\Mixers:\n" + "0: Polypaudio Virtual OSS\n"; + + char fn[] = "/tmp/padsp-sndstat-XXXXXX"; + mode_t u; + int fd = -1; + int e; + + debug(__FILE__": sndstat_open()\n"); + + if (flags != O_RDONLY && flags != (O_RDONLY|O_LARGEFILE)) { + *_errno = EACCES; + debug(__FILE__": bad access!\n"); + goto fail; + } + + u = umask(0077); + fd = mkstemp(fn); + e = errno; + umask(u); + + if (fd < 0) { + *_errno = e; + debug(__FILE__": mkstemp() failed: %s\n", strerror(errno)); + goto fail; + } + + unlink(fn); + + if (write(fd, sndstat, sizeof(sndstat) -1) != sizeof(sndstat)-1) { + *_errno = errno; + debug(__FILE__": write() failed: %s\n", strerror(errno)); + goto fail; + } + + if (lseek(fd, SEEK_SET, 0) < 0) { + *_errno = errno; + debug(__FILE__": lseek() failed: %s\n", strerror(errno)); + goto fail; + } + + return fd; + +fail: + if (fd >= 0) + close(fd); + return -1; +} + int open(const char *filename, int flags, ...) { va_list args; mode_t mode = 0; int r, _errno = 0; + debug(__FILE__": open(%s)\n", filename); + va_start(args, flags); if (flags & O_CREAT) mode = va_arg(args, mode_t); @@ -786,12 +858,12 @@ int open(const char *filename, int flags, ...) { return _open(filename, flags, mode); } - debug(__FILE__": open()\n"); - if (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0) { r = dsp_open(flags, &_errno); } else if (strcmp(filename, "/dev/mixer") == 0) { r = mixer_open(flags, &_errno); + } else if (strcmp(filename, "/dev/sndstat") == 0) { + r = sndstat_open(flags, &_errno); } else { function_exit(); LOAD_OPEN_FUNC(); @@ -1321,7 +1393,7 @@ int open64(const char *filename, int flags, ...) { va_list args; mode_t mode = 0; - debug(__FILE__": open64()\n"); + debug(__FILE__": open64(%s)\n", filename); va_start(args, flags); if (flags & O_CREAT) @@ -1330,6 +1402,7 @@ int open64(const char *filename, int flags, ...) { if (strcmp(filename, "/dev/dsp") != 0 && strcmp(filename, "/dev/adsp") != 0 && + strcmp(filename, "/dev/sndstat") != 0 && strcmp(filename, "/dev/mixer") != 0) { LOAD_OPEN64_FUNC(); return _open64(filename, flags, mode); @@ -1341,25 +1414,38 @@ int open64(const char *filename, int flags, ...) { FILE* fopen(const char *filename, const char *mode) { FILE *f = NULL; int fd; + mode_t m; + + debug(__FILE__": fopen(%s)\n", filename); - debug(__FILE__": fopen()\n"); + if (strcmp(filename, "/dev/dsp") == 0 || + strcmp(filename, "/dev/adsp") == 0) { - if (strcmp(filename, "/dev/dsp") != 0 && - strcmp(filename, "/dev/adsp") != 0 && - strcmp(filename, "/dev/mixer") != 0) { + if (strcmp(mode, "wb") != 0) { + errno = EACCES; + return NULL; + } + + m = O_WRONLY; + } else if (strcmp(filename, "/dev/sndstat") == 0) { + + if (strcmp(mode, "r") != 0) { + errno = EACCES; + return NULL; + } + + m = O_RDONLY; + } else if (strcmp(filename, "/dev/mixer") != 0) + m = O_RDWR; + else { LOAD_FOPEN_FUNC(); return _fopen(filename, mode); } - if (strcmp(mode, "wb") != 0) { - errno = EACCES; - return NULL; - } - - if ((fd = open(filename, O_WRONLY)) < 0) + if ((fd = open(filename, m)) < 0) return NULL; - if (!(f = fdopen(fd, "wb"))) { + if (!(f = fdopen(fd, mode))) { close(fd); return NULL; } @@ -1369,10 +1455,11 @@ FILE* fopen(const char *filename, const char *mode) { FILE *fopen64(const char *filename, const char *mode) { - debug(__FILE__": fopen64()\n"); + debug(__FILE__": fopen64(%s)\n", filename); if (strcmp(filename, "/dev/dsp") != 0 && strcmp(filename, "/dev/adsp") != 0 && + strcmp(filename, "/dev/sndstat") != 0 && strcmp(filename, "/dev/mixer") != 0) { LOAD_FOPEN64_FUNC(); return _fopen64(filename, mode); -- cgit From 440b901a4d445de6695e3fa41853a694d677516e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 24 May 2006 00:42:30 +0000 Subject: fix playback of small sound files git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@955 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index ed34ac8a..d9325df4 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -977,7 +977,7 @@ static int dsp_empty_socket(fd_info *i) { for (;;) { int l; - if (i->thread_fd < 0 || !i->stream) + if (i->thread_fd < 0) break; if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { @@ -985,8 +985,10 @@ static int dsp_empty_socket(fd_info *i) { break; } - if (!l) + if (!l) { + ret = 0; break; + } pa_threaded_mainloop_wait(i->mainloop); } -- cgit From ca08e57470d0a6ce1bcbfb853288aa7d3a08efe1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 24 May 2006 02:13:29 +0000 Subject: implement a /dev/mixer interface git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@956 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 286 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 261 insertions(+), 25 deletions(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index d9325df4..b85d9c4d 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -79,6 +79,10 @@ struct fd_info { int operation_success; + pa_cvolume volume; + uint32_t sink_index; + int volume_modify_count; + PA_LLIST_FIELDS(fd_info); }; @@ -154,6 +158,21 @@ do { \ pthread_mutex_unlock(&func_mutex); \ } while(0) +#define CONTEXT_CHECK_DEAD_GOTO(i, label) do { \ +if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY) { \ + debug(__FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ + goto label; \ +} \ +} while(0); + +#define STREAM_CHECK_DEAD_GOTO(i, label) do { \ +if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ + !(i)->stream || pa_stream_get_state((i)->stream) != PA_STREAM_READY) { \ + debug(__FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ + goto label; \ +} \ +} while(0); + static void debug(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); static void debug(const char *format, ...) { @@ -375,6 +394,26 @@ static void install_atfork(void) { pthread_atfork(atfork_prepare, atfork_parent, atfork_child); } +static void stream_success_cb(pa_stream *s, int success, void *userdata) { + fd_info *i = userdata; + + assert(s); + assert(i); + + i->operation_success = success; + pa_threaded_mainloop_signal(i->mainloop, 0); +} + +static void context_success_cb(pa_context *c, int success, void *userdata) { + fd_info *i = userdata; + + assert(c); + assert(i); + + i->operation_success = success; + pa_threaded_mainloop_signal(i->mainloop, 0); +} + static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { fd_info *i; int sfds[2] = { -1, -1 }; @@ -403,6 +442,9 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { i->ref = 1; i->buf = NULL; i->unusable = 0; + pa_cvolume_reset(&i->volume, 2); + i->volume_modify_count = 0; + i->sink_index = (uint32_t) -1; PA_LLIST_INIT(fd_info, i); reset_params(i); @@ -760,15 +802,118 @@ fail: return -1; } +static void sink_info_cb(pa_context *context, const pa_sink_info *si, int eol, void *userdata) { + fd_info *i = userdata; + + if (!si && eol < 0) { + i->operation_success = 0; + pa_threaded_mainloop_signal(i->mainloop, 0); + return; + } + + if (eol) + return; + + if (!pa_cvolume_equal(&i->volume, &si->volume)) + i->volume_modify_count++; + + i->volume = si->volume; + i->sink_index = si->index; + + i->operation_success = 1; + pa_threaded_mainloop_signal(i->mainloop, 0); +} + +static void subscribe_cb(pa_context *context, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { + fd_info *i = userdata; + pa_operation *o = NULL; + + if (i->sink_index != idx) + return; + + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE) + return; + + if (!(o = pa_context_get_sink_info_by_index(i->context, i->sink_index, sink_info_cb, i))) { + debug(__FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); + return; + } + + pa_operation_unref(o); +} + static int mixer_open(int flags, int *_errno) { -/* fd_info *i; */ + fd_info *i; + pa_operation *o; + int ret; - *_errno = ENOSYS; - return -1; + if (!(i = fd_info_new(FD_INFO_MIXER, _errno))) + return -1; + + pa_threaded_mainloop_lock(i->mainloop); + + pa_context_set_subscribe_callback(i->context, subscribe_cb, i); + + if (!(o = pa_context_subscribe(i->context, PA_SUBSCRIPTION_MASK_SINK, context_success_cb, i))) { + debug(__FILE__": Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context))); + *_errno = EIO; + goto fail; + } + + i->operation_success = 0; + while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + pa_threaded_mainloop_wait(i->mainloop); + CONTEXT_CHECK_DEAD_GOTO(i, fail); + } + + if (!i->operation_success) { + debug(__FILE__":Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context))); + *_errno = EIO; + goto fail; + } + + /* Get sink info */ + + pa_operation_unref(o); + if (!(o = pa_context_get_sink_info_by_name(i->context, NULL, sink_info_cb, i))) { + debug(__FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); + *_errno = EIO; + goto fail; + } -/* if (!(i = fd_info_new(FD_INFO_MIXER))) */ -/* return -1; */ + i->operation_success = 0; + while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + pa_threaded_mainloop_wait(i->mainloop); + CONTEXT_CHECK_DEAD_GOTO(i, fail); + } + + if (!i->operation_success) { + debug(__FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); + *_errno = EIO; + goto fail; + } + + pa_threaded_mainloop_unlock(i->mainloop); + + debug(__FILE__": mixer_open() succeeded, fd=%i\n", i->app_fd); + + fd_info_add_to_list(i); + ret = i->app_fd; + fd_info_unref(i); + + return ret; + +fail: + pa_threaded_mainloop_unlock(i->mainloop); + if (i) + fd_info_unref(i); + + *_errno = EIO; + + debug(__FILE__": mixer_open() failed\n"); + + return -1; } static int sndstat_open(int flags, int *_errno) { @@ -879,8 +1024,109 @@ int open(const char *filename, int flags, ...) { } static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) { - *_errno = ENOSYS; - return -1; + int ret = -1; + + switch (request) { + case SOUND_MIXER_READ_DEVMASK : + debug(__FILE__": SOUND_MIXER_READ_DEVMASK\n"); + + *(int*) argp = SOUND_MASK_PCM; + break; + + case SOUND_MIXER_READ_RECMASK : + debug(__FILE__": SOUND_MIXER_READ_RECMASK\n"); + + *(int*) argp = 0; + break; + + case SOUND_MIXER_READ_STEREODEVS: + debug(__FILE__": SOUND_MIXER_READ_STEREODEVS\n"); + + pa_threaded_mainloop_lock(i->mainloop); + *(int*) argp = i->volume.channels > 1 ? SOUND_MASK_PCM : 0; + pa_threaded_mainloop_unlock(i->mainloop); + + break; + + case SOUND_MIXER_READ_RECSRC: + debug(__FILE__": SOUND_MIXER_READ_RECSRC\n"); + + *(int*) argp = 0; + break; + + case SOUND_MIXER_CAPS: + debug(__FILE__": SOUND_MIXER_CAPS\n"); + + *(int*) argp = 0; + break; + + case SOUND_MIXER_READ_PCM: + + debug(__FILE__": SOUND_MIXER_READ_PCM\n"); + + pa_threaded_mainloop_lock(i->mainloop); + + *(int*) argp = + ((i->volume.values[0]*100/PA_VOLUME_NORM) << 8) | + ((i->volume.values[i->volume.channels > 1 ? 1 : 0]*100/PA_VOLUME_NORM)); + + pa_threaded_mainloop_unlock(i->mainloop); + + break; + + case SOUND_MIXER_WRITE_PCM: { + pa_cvolume v; + + debug(__FILE__": SOUND_MIXER_WRITE_PCM\n"); + + pa_threaded_mainloop_lock(i->mainloop); + + v = i->volume; + + i->volume.values[0] = ((*(int*) argp >> 8)*PA_VOLUME_NORM)/100; + i->volume.values[1] = ((*(int*) argp & 0xFF)*PA_VOLUME_NORM)/100; + + if (!pa_cvolume_equal(&i->volume, &v)) { + pa_operation *o; + + if (!(o = pa_context_set_sink_volume_by_index(i->context, i->sink_index, &i->volume, NULL, NULL))) + debug(__FILE__":Failed set volume: %s", pa_strerror(pa_context_errno(i->context))); + else + pa_operation_unref(o); + + /* We don't wait for completion here */ + i->volume_modify_count++; + } + + pa_threaded_mainloop_unlock(i->mainloop); + + break; + } + + case SOUND_MIXER_INFO: { + mixer_info *mi = argp; + + memset(mi, 0, sizeof(mixer_info)); + strncpy(mi->id, "POLYPAUDIO", sizeof(mi->id)); + strncpy(mi->name, "Polypaudio Virtual OSS", sizeof(mi->name)); + pa_threaded_mainloop_lock(i->mainloop); + mi->modify_counter = i->volume_modify_count; + pa_threaded_mainloop_unlock(i->mainloop); + break; + } + + default: + debug(__FILE__": unknwon ioctl 0x%08lx\n", request); + + *_errno = EINVAL; + goto fail; + } + + ret = 0; + +fail: + + return ret; } static int map_format(int *fmt, pa_sample_spec *ss) { @@ -936,16 +1182,6 @@ static int map_format_back(pa_sample_format_t format) { } } -static void success_cb(pa_stream *s, int success, void *userdata) { - fd_info *i = userdata; - - assert(s); - assert(i); - - i->operation_success = success; - pa_threaded_mainloop_signal(i->mainloop, 0); -} - static int dsp_flush_socket(fd_info *i) { int l; @@ -1015,15 +1251,14 @@ static int dsp_drain(fd_info *i) { debug(__FILE__": Really draining.\n"); - if (!(o = pa_stream_drain(i->stream, success_cb, i))) { + if (!(o = pa_stream_drain(i->stream, stream_success_cb, i))) { debug(__FILE__": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } i->operation_success = 0; while (pa_operation_get_state(o) != PA_OPERATION_DONE) { - if (!i->stream || pa_stream_get_state(i->stream) != PA_STREAM_READY) - goto fail; + STREAM_CHECK_DEAD_GOTO(i, fail); pa_threaded_mainloop_wait(i->mainloop); } @@ -1059,15 +1294,14 @@ static int dsp_trigger(fd_info *i) { debug(__FILE__": Triggering.\n"); - if (!(o = pa_stream_trigger(i->stream, success_cb, i))) { + if (!(o = pa_stream_trigger(i->stream, stream_success_cb, i))) { debug(__FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } i->operation_success = 0; while (!pa_operation_get_state(o) != PA_OPERATION_DONE) { - if (!i->stream || pa_stream_get_state(i->stream) != PA_STREAM_READY) - goto fail; + STREAM_CHECK_DEAD_GOTO(i, fail); pa_threaded_mainloop_wait(i->mainloop); } @@ -1218,8 +1452,8 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) for (;;) { pa_usec_t usec; - if (!i->stream || pa_stream_get_state(i->stream) != PA_STREAM_READY) - break; + + STREAM_CHECK_DEAD_GOTO(i, exit_loop); if (pa_stream_get_latency(i->stream, &usec, NULL) >= 0) { *(int*) argp = pa_usec_to_bytes(usec, &i->sample_spec); @@ -1234,6 +1468,8 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_threaded_mainloop_wait(i->mainloop); } + exit_loop: + if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) debug(__FILE__": SIOCINQ failed: %s\n", strerror(errno)); else -- cgit From c4328cdfddb16cf43ae4037b087cf2c58d7c531d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 24 May 2006 08:14:19 +0000 Subject: Fix stray \ git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@957 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index b85d9c4d..10b08eae 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -937,7 +937,7 @@ static int sndstat_open(int flags, int *_errno) { "\n" "Timers:\n" "\n" - "\Mixers:\n" + "Mixers:\n" "0: Polypaudio Virtual OSS\n"; char fn[] = "/tmp/padsp-sndstat-XXXXXX"; -- cgit From 2843b1a318aa1a01da465031d713ca2238b39d4c Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 24 May 2006 13:22:16 +0000 Subject: Remove the exceedingly anal warnings. It's impossible to write a non-trivial C program and not trigger these. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@958 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index fadc0219..18dba96d 100644 --- a/configure.ac +++ b/configure.ac @@ -87,7 +87,7 @@ if test "x$GCC" = "xyes" ; then # We use gnu99 instead of c99 because many have interpreted the standard # in a way that int64_t isn't defined on non-64 bit platforms. - DESIRED_FLAGS="-std=gnu99 -Wall -W -Wextra -pedantic -pipe -Wformat -Wold-style-definition -Wdeclaration-after-statement -Wfloat-equal -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-noreturn -Wshadow -Wendif-labels -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings -Winline -Wno-unused-parameter" + DESIRED_FLAGS="-std=gnu99 -Wall -W -Wextra -pedantic -pipe -Wformat -Wold-style-definition -Wdeclaration-after-statement -Wfloat-equal -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-noreturn -Wshadow -Wendif-labels -Wpointer-arith -Wcast-align -Wwrite-strings -Winline -Wno-unused-parameter" for flag in $DESIRED_FLAGS ; do AC_MSG_CHECKING([whether $CC accepts $flag]) -- cgit From 3fa19ab457ff71d148a6dff5eb7362582e82ce61 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 24 May 2006 13:23:15 +0000 Subject: Fix warnings. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@959 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/stream.c | 2 +- src/polypcore/modinfo.c | 15 +++++++++++---- src/polypcore/module.c | 11 +++++++++-- src/polypcore/pipe.h | 4 ++++ src/polypcore/protocol-esound.c | 2 -- src/polypcore/random.c | 2 +- src/polypcore/x11wrap.c | 3 ++- src/utils/padsp.c | 21 ++++++++++++++------- 8 files changed, 42 insertions(+), 18 deletions(-) diff --git a/src/polyp/stream.c b/src/polyp/stream.c index 2e168045..e41c588e 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -872,7 +872,7 @@ pa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t pa_operation *o; pa_tagstruct *t; struct timeval now; - int cidx; + int cidx = 0; assert(s); assert(s->ref >= 1); diff --git a/src/polypcore/modinfo.c b/src/polypcore/modinfo.c index 4a9be0f0..a2fffb01 100644 --- a/src/polypcore/modinfo.c +++ b/src/polypcore/modinfo.c @@ -38,6 +38,13 @@ #define PA_SYMBOL_USAGE "pa__get_usage" #define PA_SYMBOL_VERSION "pa__get_version" +/* lt_dlsym() violates ISO C, so confide the breakage into this function to + * avoid warnings. */ +typedef void (*fnptr)(void); +static inline fnptr lt_dlsym_fn(lt_dlhandle handle, const char *symbol) { + return (fnptr) (long) lt_dlsym(handle, symbol); +} + pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl) { pa_modinfo *i; const char* (*func)(void); @@ -45,16 +52,16 @@ pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl) { i = pa_xnew0(pa_modinfo, 1); - if ((func = (const char* (*)(void)) lt_dlsym(dl, PA_SYMBOL_AUTHOR))) + if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_AUTHOR))) i->author = pa_xstrdup(func()); - if ((func = (const char* (*)(void)) lt_dlsym(dl, PA_SYMBOL_DESCRIPTION))) + if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_DESCRIPTION))) i->description = pa_xstrdup(func()); - if ((func = (const char* (*)(void)) lt_dlsym(dl, PA_SYMBOL_USAGE))) + if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_USAGE))) i->usage = pa_xstrdup(func()); - if ((func = (const char* (*)(void)) lt_dlsym(dl, PA_SYMBOL_VERSION))) + if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_VERSION))) i->version = pa_xstrdup(func()); return i; diff --git a/src/polypcore/module.c b/src/polypcore/module.c index 0286bba8..b938750c 100644 --- a/src/polypcore/module.c +++ b/src/polypcore/module.c @@ -44,6 +44,13 @@ #define UNLOAD_POLL_TIME 2 +/* lt_dlsym() violates ISO C, so confide the breakage into this function to + * avoid warnings. */ +typedef void (*fnptr)(void); +static inline fnptr lt_dlsym_fn(lt_dlhandle handle, const char *symbol) { + return (fnptr) (long) lt_dlsym(handle, symbol); +} + static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { pa_core *c = userdata; struct timeval ntv; @@ -75,12 +82,12 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { goto fail; } - if (!(m->init = (int (*)(pa_core *_c, pa_module*_m)) lt_dlsym(m->dl, PA_SYMBOL_INIT))) { + if (!(m->init = (int (*)(pa_core *_c, pa_module*_m)) lt_dlsym_fn(m->dl, PA_SYMBOL_INIT))) { pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.", name); goto fail; } - if (!(m->done = (void (*)(pa_core *_c, pa_module*_m)) lt_dlsym(m->dl, PA_SYMBOL_DONE))) { + if (!(m->done = (void (*)(pa_core *_c, pa_module*_m)) lt_dlsym_fn(m->dl, PA_SYMBOL_DONE))) { pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_DONE"\" not found.", name); goto fail; } diff --git a/src/polypcore/pipe.h b/src/polypcore/pipe.h index e9167782..276b072d 100644 --- a/src/polypcore/pipe.h +++ b/src/polypcore/pipe.h @@ -22,6 +22,10 @@ USA. ***/ +#ifndef HAVE_PIPE + int pipe(int filedes[2]); #endif + +#endif diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index 01a72e84..d7c9475a 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -515,7 +515,6 @@ static int esd_proto_server_info(struct connection *c, PA_GCC_UNUSED esd_proto_t } static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length) { - uint8_t *response; size_t t, k, s; struct connection *conn; uint32_t idx = PA_IDXSET_INVALID; @@ -585,7 +584,6 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v } assert(t == s*(nsamples+1)+k); - response += k; t -= k; connection_write(c, terminator, k); diff --git a/src/polypcore/random.c b/src/polypcore/random.c index 4bfce975..d7a37b0b 100644 --- a/src/polypcore/random.c +++ b/src/polypcore/random.c @@ -48,7 +48,7 @@ static int random_proper(void *ret_data, size_t length) { #else /* OS_IS_WIN32 */ - int fd, ret; + int fd, ret = -1; ssize_t r = 0; const char **device; diff --git a/src/polypcore/x11wrap.c b/src/polypcore/x11wrap.c index 41a40764..b53a43b6 100644 --- a/src/polypcore/x11wrap.c +++ b/src/polypcore/x11wrap.c @@ -107,9 +107,10 @@ static void internal_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC /* Add a new IO source for the specified X11 internal connection */ static pa_x11_internal* x11_internal_add(pa_x11_wrapper *w, int fd) { pa_x11_internal *i; - assert(i && fd >= 0); + assert(fd >= 0); i = pa_xmalloc(sizeof(pa_x11_internal)); + assert(i); i->wrapper = w; i->io_event = w->core->mainloop->io_new(w->core->mainloop, fd, PA_IO_EVENT_INPUT, internal_io_event, w); i->fd = fd; diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 10b08eae..87d0b257 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -102,11 +102,18 @@ static int (*_open64)(const char *, int, mode_t) = NULL; static FILE* (*_fopen64)(const char *path, const char *mode) = NULL; static int (*_fclose)(FILE *f) = NULL; +/* dlsym() violates ISO C, so confide the breakage into this function to + * avoid warnings. */ +typedef void (*fnptr)(void); +static inline fnptr dlsym_fn(void *handle, const char *symbol) { + return (fnptr) (long) dlsym(handle, symbol); +} + #define LOAD_IOCTL_FUNC() \ do { \ pthread_mutex_lock(&func_mutex); \ if (!_ioctl) \ - _ioctl = (int (*)(int, int, void*)) dlsym(RTLD_NEXT, "ioctl"); \ + _ioctl = (int (*)(int, int, void*)) dlsym_fn(RTLD_NEXT, "ioctl"); \ pthread_mutex_unlock(&func_mutex); \ } while(0) @@ -114,7 +121,7 @@ do { \ do { \ pthread_mutex_lock(&func_mutex); \ if (!_open) \ - _open = (int (*)(const char *, int, mode_t)) dlsym(RTLD_NEXT, "open"); \ + _open = (int (*)(const char *, int, mode_t)) dlsym_fn(RTLD_NEXT, "open"); \ pthread_mutex_unlock(&func_mutex); \ } while(0) @@ -122,7 +129,7 @@ do { \ do { \ pthread_mutex_lock(&func_mutex); \ if (!_open64) \ - _open64 = (int (*)(const char *, int, mode_t)) dlsym(RTLD_NEXT, "open64"); \ + _open64 = (int (*)(const char *, int, mode_t)) dlsym_fn(RTLD_NEXT, "open64"); \ pthread_mutex_unlock(&func_mutex); \ } while(0) @@ -130,7 +137,7 @@ do { \ do { \ pthread_mutex_lock(&func_mutex); \ if (!_close) \ - _close = (int (*)(int)) dlsym(RTLD_NEXT, "close"); \ + _close = (int (*)(int)) dlsym_fn(RTLD_NEXT, "close"); \ pthread_mutex_unlock(&func_mutex); \ } while(0) @@ -138,7 +145,7 @@ do { \ do { \ pthread_mutex_lock(&func_mutex); \ if (!_fopen) \ - _fopen = (FILE* (*)(const char *, const char*)) dlsym(RTLD_NEXT, "fopen"); \ + _fopen = (FILE* (*)(const char *, const char*)) dlsym_fn(RTLD_NEXT, "fopen"); \ pthread_mutex_unlock(&func_mutex); \ } while(0) @@ -146,7 +153,7 @@ do { \ do { \ pthread_mutex_lock(&func_mutex); \ if (!_fopen64) \ - _fopen64 = (FILE* (*)(const char *, const char*)) dlsym(RTLD_NEXT, "fopen64"); \ + _fopen64 = (FILE* (*)(const char *, const char*)) dlsym_fn(RTLD_NEXT, "fopen64"); \ pthread_mutex_unlock(&func_mutex); \ } while(0) @@ -154,7 +161,7 @@ do { \ do { \ pthread_mutex_lock(&func_mutex); \ if (!_fclose) \ - _fclose = (int (*)(FILE *)) dlsym(RTLD_NEXT, "fclose"); \ + _fclose = (int (*)(FILE *)) dlsym_fn(RTLD_NEXT, "fclose"); \ pthread_mutex_unlock(&func_mutex); \ } while(0) -- cgit From 6a7172e91c942abcd999ed19074d1664aea6fec2 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 24 May 2006 15:38:11 +0000 Subject: padsp needs dlsym & co so make sure we get that lib included. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@960 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 18dba96d..004053c2 100644 --- a/configure.ac +++ b/configure.ac @@ -214,6 +214,7 @@ AC_SEARCH_LIBS([pow], [m]) # POSIX AC_SEARCH_LIBS([sched_setscheduler], [rt]) +AC_SEARCH_LIBS([dlopen], [dl]) # BSD AC_SEARCH_LIBS([connect], [socket]) -- cgit From 0fb63e7b0a0328319c4200074d3e54ef74e5948e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 00:12:06 +0000 Subject: update TODO git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@961 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/todo b/doc/todo index bf3365ab..b2c3577e 100644 --- a/doc/todo +++ b/doc/todo @@ -30,6 +30,8 @@ Post 0.8: and we tend to pass it to functions that require UTF-8. - fix clock of the NULL sink - gettextify polypaudio +- add API to query the bufferattrs after stream creation +- move libpadsp.so to /usr/lib/polypaudio/ or something, and move the modules to /usr/lib/polypaudio/modules/0.9.0/ Long term: - pass meta info for hearing impaired -- cgit From 59d00e2f49f709630cd3c55b28e752fa5d7919fb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 00:25:03 +0000 Subject: * issue volume updates syncrhonously * correct channel order of OSS volumes (swap left,right) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@962 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 87d0b257..d372b697 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1074,8 +1074,8 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno pa_threaded_mainloop_lock(i->mainloop); *(int*) argp = - ((i->volume.values[0]*100/PA_VOLUME_NORM) << 8) | - ((i->volume.values[i->volume.channels > 1 ? 1 : 0]*100/PA_VOLUME_NORM)); + ((i->volume.values[0]*100/PA_VOLUME_NORM)) | + ((i->volume.values[i->volume.channels > 1 ? 1 : 0]*100/PA_VOLUME_NORM) << 8); pa_threaded_mainloop_unlock(i->mainloop); @@ -1090,16 +1090,29 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno v = i->volume; - i->volume.values[0] = ((*(int*) argp >> 8)*PA_VOLUME_NORM)/100; - i->volume.values[1] = ((*(int*) argp & 0xFF)*PA_VOLUME_NORM)/100; + i->volume.values[0] = ((*(int*) argp & 0xFF)*PA_VOLUME_NORM)/100; + i->volume.values[1] = ((*(int*) argp >> 8)*PA_VOLUME_NORM)/100; if (!pa_cvolume_equal(&i->volume, &v)) { pa_operation *o; if (!(o = pa_context_set_sink_volume_by_index(i->context, i->sink_index, &i->volume, NULL, NULL))) debug(__FILE__":Failed set volume: %s", pa_strerror(pa_context_errno(i->context))); - else + else { + + i->operation_success = 0; + while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + CONTEXT_CHECK_DEAD_GOTO(i, exit_loop); + + pa_threaded_mainloop_wait(i->mainloop); + } + exit_loop: + + if (!i->operation_success) + debug(__FILE__": Failed to set volume: %s\n", pa_strerror(pa_context_errno(i->context))); + pa_operation_unref(o); + } /* We don't wait for completion here */ i->volume_modify_count++; -- cgit From 2bb05ea6678ff27f37ac082d01dcb9fd14889613 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 00:40:04 +0000 Subject: fix evil, evil typo that cause all gtk2 based apps to crash git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@963 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index d372b697..746965d7 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1693,7 +1693,7 @@ FILE* fopen(const char *filename, const char *mode) { } m = O_RDONLY; - } else if (strcmp(filename, "/dev/mixer") != 0) + } else if (strcmp(filename, "/dev/mixer") == 0) m = O_RDWR; else { LOAD_FOPEN_FUNC(); -- cgit From 2bbd7bac63a48361d3d848ba1d3838a0ef5eb2bd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 01:14:06 +0000 Subject: add support to disable emulation of /dev/dsp,/dev/mixer,/dev/sndstat selectively by either passing an environment variable or by defining a symbol __padsp_disable__ in the process git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@964 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 746965d7..2f0f7260 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -191,6 +191,61 @@ static void debug(const char *format, ...) { } } +static int padsp_disabled(void) { + static int *sym; + static int sym_resolved = 0; + + /* If the current process has a symbol __padsp_disabled__ we use + * it to detect whether we should enable our stuff or not. A + * program needs to be compiled with -rdynamic for this to work! + * The symbol must be an int containing a three bit bitmask: bit 1 + * -> disable /dev/dsp emulation, bit 2 -> disable /dev/sndstat + * emulation, bit 3 -> disable /dev/mixer emulation. Hence a value + * 7 disables padsp entirely. */ + + pthread_mutex_lock(&func_mutex); + if (!sym_resolved) { + sym = (int*) dlsym_fn(RTLD_DEFAULT, "__padsp_disabled__"); + sym_resolved = 1; + + } + pthread_mutex_unlock(&func_mutex); + + if (!sym) + return 0; + + return *sym; +} + +static int dsp_cloak_enable(void) { + if (padsp_disabled() & 1) + return 0; + + if (getenv("PADSP_NO_DSP")) + return 0; + + return 1; +} + +static int sndstat_cloak_enable(void) { + if (padsp_disabled() & 2) + return 0; + + if (getenv("PADSP_NO_SNDSTAT")) + return 0; + + return 1; +} + +static int mixer_cloak_enable(void) { + if (padsp_disabled() & 4) + return 0; + + if (getenv("PADSP_NO_MIXER")) + return 0; + + return 1; +} static pthread_key_t recursion_key; static void recursion_key_alloc(void) { @@ -1010,11 +1065,11 @@ int open(const char *filename, int flags, ...) { return _open(filename, flags, mode); } - if (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0) { + if (dsp_cloak_enable() && (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0)) { r = dsp_open(flags, &_errno); - } else if (strcmp(filename, "/dev/mixer") == 0) { + } else if (mixer_cloak_enable() && strcmp(filename, "/dev/mixer") == 0) { r = mixer_open(flags, &_errno); - } else if (strcmp(filename, "/dev/sndstat") == 0) { + } else if (sndstat_cloak_enable() && strcmp(filename, "/dev/sndstat") == 0) { r = sndstat_open(flags, &_errno); } else { function_exit(); -- cgit From ae80ab396e9aa764b16b436b7b7c66011dce513c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 01:19:56 +0000 Subject: read stream and client name from $PADSP_STREAM_NAME resp. $PADSP_CLIENT_NAME, if available git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@965 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 2f0f7260..5987ec5f 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -201,7 +201,7 @@ static int padsp_disabled(void) { * The symbol must be an int containing a three bit bitmask: bit 1 * -> disable /dev/dsp emulation, bit 2 -> disable /dev/sndstat * emulation, bit 3 -> disable /dev/mixer emulation. Hence a value - * 7 disables padsp entirely. */ + * of 7 disables padsp entirely. */ pthread_mutex_lock(&func_mutex); if (!sym_resolved) { @@ -363,15 +363,28 @@ static void reset_params(fd_info *i) { static char *client_name(char *buf, size_t n) { char p[PATH_MAX]; + const char *e; + + if ((e = getenv("PADSP_CLIENT_NAME"))) + return e; if (pa_get_binary_name(p, sizeof(p))) - snprintf(buf, n, "oss[%s]", pa_path_get_filename(p)); + snprintf(buf, n, "OSS Emulation[%s]", pa_path_get_filename(p)); else - snprintf(buf, n, "oss"); + snprintf(buf, n, "OSS"); return buf; } +static char *stream_name(void) { + const char *e; + + if ((e = getenv("PADSP_STREAM_NAME"))) + return e; + + return "Audio Stream"; +} + static void atfork_prepare(void) { fd_info *i; @@ -740,7 +753,7 @@ static int create_stream(fd_info *i) { fix_metrics(i); - if (!(i->stream = pa_stream_new(i->context, "Audio Stream", &i->sample_spec, NULL))) { + if (!(i->stream = pa_stream_new(i->context, stream_name(), &i->sample_spec, NULL))) { debug(__FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } -- cgit From e07b2620f3838d178cdc42c7ba6225277287f46e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 01:26:10 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@966 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/todo b/doc/todo index b2c3577e..8d73f25b 100644 --- a/doc/todo +++ b/doc/todo @@ -1,6 +1,11 @@ *** $Id$ *** -Post 0.8: +Pre 0.9.0 +- add API to query the bufferattrs after stream creation +- move libpadsp.so to /usr/lib/polypaudio/ or something, and move the modules to /usr/lib/polypaudio/modules/0.9.0/ +- add proper padsp script that makes $PADSP_xxx env vars from the command line arguments, just like esddsp does + +Post 0.9.0: - alsa mmap driver - dbus/hal - polish for starting polypaudio as root/system-wide instance @@ -30,8 +35,6 @@ Post 0.8: and we tend to pass it to functions that require UTF-8. - fix clock of the NULL sink - gettextify polypaudio -- add API to query the bufferattrs after stream creation -- move libpadsp.so to /usr/lib/polypaudio/ or something, and move the modules to /usr/lib/polypaudio/modules/0.9.0/ Long term: - pass meta info for hearing impaired @@ -40,4 +43,4 @@ Long term: Backends for: - portaudio (semi-done) - sdl -- OSS (esddsp style) +- xine (needs update) -- cgit From fc8a2c4a3616a9a97eeb60e22065615f5c13e888 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 13:29:36 +0000 Subject: add item about moving pa_cstrerror() to TODO git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@967 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/todo b/doc/todo index 8d73f25b..58b2fa6c 100644 --- a/doc/todo +++ b/doc/todo @@ -2,8 +2,9 @@ Pre 0.9.0 - add API to query the bufferattrs after stream creation -- move libpadsp.so to /usr/lib/polypaudio/ or something, and move the modules to /usr/lib/polypaudio/modules/0.9.0/ +- move the modules to /usr/lib/polypaudio-0.9.0/modules - add proper padsp script that makes $PADSP_xxx env vars from the command line arguments, just like esddsp does +- move pa_cstrerror() to polypcore/core-error.h Post 0.9.0: - alsa mmap driver -- cgit From 1799b7ac332e0309437c41c676358078cc1f659c Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 25 May 2006 13:31:28 +0000 Subject: Move libpolypdsp in the makefile to avoid the libtool bug where it must come after any things it depends on. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@968 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 6327d550..a298397b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -174,24 +174,6 @@ pabrowse_LDADD = $(AM_LDADD) libpolyp.la libpolyp-browse.la pabrowse_CFLAGS = $(AM_CFLAGS) pabrowse_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -lib_LTLIBRARIES = -CLEANFILES= - -if HAVE_OSS -lib_LTLIBRARIES += libpolypdsp.la -libpolypdsp_la_SOURCES = utils/padsp.c -libpolypdsp_la_CFLAGS = $(AM_CFLAGS) -libpolypdsp_la_LIBADD = $(AM_LIBADD) libpolyp.la -libpolypdsp_la_LDFLAGS = -avoid-version - -CLEANFILES+=padsp -bin_SCRIPTS += padsp - -padsp: utils/padsp.in Makefile - sed -e 's,@LIBPOLYPDSP\@,$(libdir)/libpolypdsp.so,g' < $< > $@ - -endif - ################################### # Test programs # ################################### @@ -344,7 +326,7 @@ polypinclude_HEADERS += \ endif endif -lib_LTLIBRARIES += \ +lib_LTLIBRARIES = \ libpolyp.la \ libpolyp-simple.la @@ -467,6 +449,29 @@ libpolyp_mainloop_glib12_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS) libpolyp_mainloop_glib12_la_LIBADD = $(AM_LIBADD) libpolyp.la $(GLIB12_LIBS) libpolyp_mainloop_glib12_la_LDFLAGS = -version-info $(LIBPOLYP_MAINLOOP_GLIB_VERSION_INFO) +################################### +# OSS emulation # +################################### + +CLEANFILES= + +if HAVE_OSS + +lib_LTLIBRARIES += libpolypdsp.la + +CLEANFILES += padsp +bin_SCRIPTS += padsp + +endif + +libpolypdsp_la_SOURCES = utils/padsp.c +libpolypdsp_la_CFLAGS = $(AM_CFLAGS) +libpolypdsp_la_LIBADD = $(AM_LIBADD) libpolyp.la +libpolypdsp_la_LDFLAGS = -avoid-version + +padsp: utils/padsp.in Makefile + sed -e 's,@LIBPOLYPDSP\@,$(libdir)/libpolypdsp.so,g' < $< > $@ + ################################### # Daemon core library # ################################### -- cgit From 0387b30994185a44e6df737c529ddda24325c671 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 25 May 2006 13:56:14 +0000 Subject: Use only the basename of libpolypdsp.so so that it will work on multi-arch systems. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@969 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 12 +++--------- src/utils/padsp | 30 ++++++++++++++++++++++++++++++ src/utils/padsp.in | 30 ------------------------------ 3 files changed, 33 insertions(+), 39 deletions(-) create mode 100644 src/utils/padsp delete mode 100644 src/utils/padsp.in diff --git a/src/Makefile.am b/src/Makefile.am index a298397b..16b5e9e3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -78,7 +78,7 @@ EXTRA_DIST = \ daemon/default.pa.in \ depmod.py \ daemon/esdcompat.sh.in \ - utils/padsp.in \ + utils/padsp \ modules/module-defs.h.m4 polypconf_DATA = \ @@ -453,14 +453,11 @@ libpolyp_mainloop_glib12_la_LDFLAGS = -version-info $(LIBPOLYP_MAINLOOP_GLIB_VER # OSS emulation # ################################### -CLEANFILES= - if HAVE_OSS lib_LTLIBRARIES += libpolypdsp.la -CLEANFILES += padsp -bin_SCRIPTS += padsp +bin_SCRIPTS += utils/padsp endif @@ -469,9 +466,6 @@ libpolypdsp_la_CFLAGS = $(AM_CFLAGS) libpolypdsp_la_LIBADD = $(AM_LIBADD) libpolyp.la libpolypdsp_la_LDFLAGS = -avoid-version -padsp: utils/padsp.in Makefile - sed -e 's,@LIBPOLYPDSP\@,$(libdir)/libpolypdsp.so,g' < $< > $@ - ################################### # Daemon core library # ################################### @@ -1165,7 +1159,7 @@ suid: polypaudio chown root $< chmod u+s $< -CLEANFILES+=esdcompat.sh client.conf default.pa daemon.conf +CLEANFILES = esdcompat.sh client.conf default.pa daemon.conf esdcompat.sh: daemon/esdcompat.sh.in Makefile sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ diff --git a/src/utils/padsp b/src/utils/padsp new file mode 100644 index 00000000..9f38cf3d --- /dev/null +++ b/src/utils/padsp @@ -0,0 +1,30 @@ +#!/bin/sh + +# $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +if [ x"$LD_PRELOAD" = x ] ; then + LD_PRELOAD="libpolypdsp.so" +else + LD_PRELOAD="$LD_PRELOAD libpolypdsp.so" +fi + +export LD_PRELOAD + +exec "$@" diff --git a/src/utils/padsp.in b/src/utils/padsp.in deleted file mode 100644 index d82e92fe..00000000 --- a/src/utils/padsp.in +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh - -# $Id$ -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -if [ x"$LD_PRELOAD" = x ] ; then - LD_PRELOAD="@LIBPOLYPDSP@" -else - LD_PRELOAD="$LD_PRELOAD @LIBPOLYPDSP@" -fi - -export LD_PRELOAD - -exec "$@" -- cgit From ea7995b764ed716bbe17576ebdba3a435de095d3 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 25 May 2006 15:44:24 +0000 Subject: Fix padsp script so that it accepts parameters, setting relevant environment variables as needed. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@970 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/utils/padsp b/src/utils/padsp index 9f38cf3d..dc89bfb7 100644 --- a/src/utils/padsp +++ b/src/utils/padsp @@ -19,6 +19,57 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. +while getopts 'hs:n:m:MSDd' param ; do + case $param in + s) + POLYP_SERVER="$OPTARG" + export POLYP_SERVER + ;; + n) + PA_CLIENT_NAME="$OPTARG" + export PA_CLIENT_NAME + ;; + m) + PA_STREAM_NAME="$OPTARG" + export PA_STREAM_NAME + ;; + M) + PA_NO_MIXER=1 + export PA_NO_MIXER + ;; + S) + PA_NO_SNDSTAT=1 + export PA_NO_SNDSTAT + ;; + D) + PA_NO_DSP=1 + export PA_NO_DSP + ;; + d) + PADSP_DEBUG=1 + export PADSP_DEBUG + ;; + *) + echo "$0 - redirect OSS audio devices to Polypaudio" + echo " " + echo "$0 [options] application [arguments]" + echo " " + echo "options:" + echo " -h show brief help" + echo " -s [:] contact a specific Polypaudio server" + echo " -n client name to report to the server" + echo " -m stream name to report to the server" + echo " -M disable /dev/mixer emulation" + echo " -S disable /dev/sndstat emulation" + echo " -D disable /dev/dsp emulation" + echo " -d enable debug output" + exit 0 + ;; + esac +done + +shift $(( $OPTIND - 1 )) + if [ x"$LD_PRELOAD" = x ] ; then LD_PRELOAD="libpolypdsp.so" else -- cgit From f8aa55c5ac1f21fec9e1a5f0351328fb33366f2a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 16:05:11 +0000 Subject: move modules to ${libdir}/polypaudio-${PA_MAJORMINOR}/modules/ git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@971 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 4 ++-- doc/todo | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 004053c2..157c01a4 100644 --- a/configure.ac +++ b/configure.ac @@ -437,8 +437,8 @@ fi AC_ARG_WITH( [module-dir], - AC_HELP_STRING([--with-module-dir],[Directory where to install the modules to (defaults to ${libdir}/polypaudio-${PA_MAJORMINOR}]), - [modlibexecdir=$withval], [modlibexecdir="${libdir}/polypaudio-${PA_MAJORMINOR}"]) + AC_HELP_STRING([--with-module-dir],[Directory where to install the modules to (defaults to ${libdir}/polypaudio-${PA_MAJORMINOR}/modules/]), + [modlibexecdir=$withval], [modlibexecdir="${libdir}/polypaudio-${PA_MAJORMINOR}/modules/"]) AC_SUBST(modlibexecdir) diff --git a/doc/todo b/doc/todo index 58b2fa6c..1d17d3cc 100644 --- a/doc/todo +++ b/doc/todo @@ -2,7 +2,6 @@ Pre 0.9.0 - add API to query the bufferattrs after stream creation -- move the modules to /usr/lib/polypaudio-0.9.0/modules - add proper padsp script that makes $PADSP_xxx env vars from the command line arguments, just like esddsp does - move pa_cstrerror() to polypcore/core-error.h -- cgit From 4413b89d7a45587b545a31463ad2196767f45563 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 17:16:55 +0000 Subject: * split pa_cstrerror() into its own file polypcore/core-error.[ch] * fix building of padsp * remove a warning when compiling padsp.c git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@972 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 - src/Makefile.am | 6 +- src/daemon/caps.c | 2 +- src/daemon/daemon-conf.c | 2 +- src/daemon/main.c | 2 +- src/modules/module-alsa-source.c | 2 +- src/modules/module-detect.c | 2 +- src/modules/module-esound-compat-spawnfd.c | 3 +- src/modules/module-esound-compat-spawnpid.c | 3 +- src/modules/module-esound-sink.c | 2 +- src/modules/module-jack-sink.c | 2 +- src/modules/module-jack-source.c | 2 +- src/modules/module-match.c | 2 +- src/modules/module-mmkbd-evdev.c | 2 +- src/modules/module-oss-mmap.c | 2 +- src/modules/module-oss.c | 2 +- src/modules/module-pipe-sink.c | 2 +- src/modules/module-pipe-source.c | 2 +- src/modules/module-protocol-stub.c | 2 +- src/modules/module-volume-restore.c | 2 +- src/modules/oss-util.c | 3 +- src/modules/rtp/module-rtp-recv.c | 2 +- src/modules/rtp/module-rtp-send.c | 2 +- src/modules/rtp/rtp.c | 3 +- src/modules/rtp/sap.c | 2 +- src/polyp/client-conf.c | 2 +- src/polyp/context.c | 2 +- src/polyp/error.c | 214 +++------------------------- src/polyp/error.h | 6 - src/polyp/mainloop-signal.c | 2 +- src/polyp/mainloop.c | 2 +- src/polyp/util.c | 3 +- src/polypcore/authkey.c | 2 +- src/polypcore/cli-command.c | 2 +- src/polypcore/conf-parser.c | 2 +- src/polypcore/core-error.c | 205 ++++++++++++++++++++++++++ src/polypcore/core-error.h | 41 ++++++ src/polypcore/core-scache.c | 2 +- src/polypcore/core-util.c | 2 +- src/polypcore/iochannel.c | 2 +- src/polypcore/ioline.c | 2 +- src/polypcore/pid.c | 2 +- src/polypcore/protocol-esound.c | 2 +- src/polypcore/protocol-simple.c | 2 +- src/polypcore/socket-client.c | 2 +- src/polypcore/socket-server.c | 2 +- src/polypcore/socket-util.c | 2 +- src/utils/pacmd.c | 14 +- src/utils/padsp.c | 4 +- 49 files changed, 324 insertions(+), 255 deletions(-) create mode 100644 src/polypcore/core-error.c create mode 100644 src/polypcore/core-error.h diff --git a/doc/todo b/doc/todo index 1d17d3cc..0b78ee93 100644 --- a/doc/todo +++ b/doc/todo @@ -2,8 +2,6 @@ Pre 0.9.0 - add API to query the bufferattrs after stream creation -- add proper padsp script that makes $PADSP_xxx env vars from the command line arguments, just like esddsp does -- move pa_cstrerror() to polypcore/core-error.h Post 0.9.0: - alsa mmap driver diff --git a/src/Makefile.am b/src/Makefile.am index 16b5e9e3..3a8c9bba 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -402,6 +402,7 @@ libpolyp_la_SOURCES += \ polypcore/strbuf.c polypcore/strbuf.h \ polypcore/strlist.c polypcore/strlist.h \ polypcore/tagstruct.c polypcore/tagstruct.h \ + polypcore/core-error.c polypcore/core-error.h \ polypcore/winsock.h if OS_IS_WIN32 @@ -574,7 +575,8 @@ libpolypcore_la_SOURCES += \ polypcore/source-output.c polypcore/source-output.h \ polypcore/strbuf.c polypcore/strbuf.h \ polypcore/tokenizer.c polypcore/tokenizer.h \ - polypcore/winsock.h + polypcore/winsock.h \ + polypcore/core-error.c polypcore/core-error.h if OS_IS_WIN32 libpolypcore_la_SOURCES += \ @@ -1186,3 +1188,5 @@ install-exec-hook: chmod u+s $(DESTDIR)$(bindir)/polypaudio ln -sf pacat $(DESTDIR)$(bindir)/parec rm -f $(DESTDIR)$(modlibexecdir)/*.a + +.PHONY: utils/padsp diff --git a/src/daemon/caps.c b/src/daemon/caps.c index 4942868c..5e24da82 100644 --- a/src/daemon/caps.c +++ b/src/daemon/caps.c @@ -32,7 +32,7 @@ #include #endif -#include +#include #include diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 809769f8..2d8d9558 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -29,9 +29,9 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/daemon/main.c b/src/daemon/main.c index 2fadd496..b88f932c 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -50,11 +50,11 @@ #include "../polypcore/winsock.h" -#include #include #include #include +#include #include #include #include diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index c72b0322..414efda8 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -34,9 +34,9 @@ #include -#include #include +#include #include #include #include diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index e4f2e3f9..d0a37733 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -33,9 +33,9 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/modules/module-esound-compat-spawnfd.c b/src/modules/module-esound-compat-spawnfd.c index f59e9e21..861e2570 100644 --- a/src/modules/module-esound-compat-spawnfd.c +++ b/src/modules/module-esound-compat-spawnfd.c @@ -28,8 +28,7 @@ #include #include -#include - +#include #include #include #include diff --git a/src/modules/module-esound-compat-spawnpid.c b/src/modules/module-esound-compat-spawnpid.c index c14ce12a..7b47bb0a 100644 --- a/src/modules/module-esound-compat-spawnpid.c +++ b/src/modules/module-esound-compat-spawnpid.c @@ -28,8 +28,7 @@ #include #include -#include - +#include #include #include #include diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index 72298679..53a9411a 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -33,9 +33,9 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index db2ba030..fc2bfc45 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -36,9 +36,9 @@ #include -#include #include +#include #include #include #include diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index 8816fb8a..ca9560a6 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -36,9 +36,9 @@ #include -#include #include +#include #include #include #include diff --git a/src/modules/module-match.c b/src/modules/module-match.c index f68f0c61..02d75e7e 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -32,9 +32,9 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c index d6c91e2e..ee2c6bff 100644 --- a/src/modules/module-mmkbd-evdev.c +++ b/src/modules/module-mmkbd-evdev.c @@ -33,9 +33,9 @@ #include -#include #include +#include #include #include #include diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index dac7d7f3..5cf6228f 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -36,9 +36,9 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 8e217855..88724673 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -35,9 +35,9 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index f0569ce9..01598e38 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -33,9 +33,9 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index 77212ce5..be2a28d5 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -33,9 +33,9 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index 8eba352b..2b4f303b 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -42,9 +42,9 @@ #include "../polypcore/winsock.h" -#include #include +#include #include #include #include diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index 796e43a3..435f0c96 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -32,9 +32,9 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index 027921c5..ff337a5c 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -34,8 +34,7 @@ #include #include -#include - +#include #include #include diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index 8d9b33c2..c448502e 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -31,10 +31,10 @@ #include #include -#include #include #include +#include #include #include #include diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index c8b3899a..4359d00d 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -32,11 +32,11 @@ #include #include -#include #include #include #include +#include #include #include #include diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c index 012d6578..52a1819c 100644 --- a/src/modules/rtp/rtp.c +++ b/src/modules/rtp/rtp.c @@ -36,8 +36,7 @@ #include #endif -#include - +#include #include #include "rtp.h" diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c index 238ee420..134bab09 100644 --- a/src/modules/rtp/sap.c +++ b/src/modules/rtp/sap.c @@ -38,9 +38,9 @@ #include #endif -#include #include +#include #include #include diff --git a/src/polyp/client-conf.c b/src/polyp/client-conf.c index 0b3154c8..e1934ce1 100644 --- a/src/polyp/client-conf.c +++ b/src/polyp/client-conf.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include diff --git a/src/polyp/context.c b/src/polyp/context.c index eb563819..68fb4bf3 100644 --- a/src/polyp/context.c +++ b/src/polyp/context.c @@ -47,7 +47,7 @@ #include "../polypcore/winsock.h" -#include +#include #include #include diff --git a/src/polyp/error.c b/src/polyp/error.c index 0e3b506f..27da7eae 100644 --- a/src/polyp/error.c +++ b/src/polyp/error.c @@ -28,15 +28,6 @@ #include #include -#ifdef HAVE_PTHREAD -#include -#endif - -#ifdef HAVE_WINDOWS_H -#include -#endif - -#include #include #include @@ -44,191 +35,32 @@ #include "error.h" -static const char* const errortab[PA_ERR_MAX] = { - [PA_OK] = "OK", - [PA_ERR_ACCESS] = "Access denied", - [PA_ERR_COMMAND] = "Unknown command", - [PA_ERR_INVALID] = "Invalid argument", - [PA_ERR_EXIST] = "Entity exists", - [PA_ERR_NOENTITY] = "No such entity", - [PA_ERR_CONNECTIONREFUSED] = "Connection refused", - [PA_ERR_PROTOCOL] = "Protocol error", - [PA_ERR_TIMEOUT] = "Timeout", - [PA_ERR_AUTHKEY] = "No authorization key", - [PA_ERR_INTERNAL] = "Internal error", - [PA_ERR_CONNECTIONTERMINATED] = "Connection terminated", - [PA_ERR_KILLED] = "Entity killed", - [PA_ERR_INVALIDSERVER] = "Invalid server", - [PA_ERR_MODINITFAILED] = "Module initalization failed", - [PA_ERR_BADSTATE] = "Bad state", - [PA_ERR_NODATA] = "No data", - [PA_ERR_VERSION] = "Incompatible protocol version", - [PA_ERR_TOOLARGE] = "Too large" -}; - const char*pa_strerror(int error) { + + static const char* const errortab[PA_ERR_MAX] = { + [PA_OK] = "OK", + [PA_ERR_ACCESS] = "Access denied", + [PA_ERR_COMMAND] = "Unknown command", + [PA_ERR_INVALID] = "Invalid argument", + [PA_ERR_EXIST] = "Entity exists", + [PA_ERR_NOENTITY] = "No such entity", + [PA_ERR_CONNECTIONREFUSED] = "Connection refused", + [PA_ERR_PROTOCOL] = "Protocol error", + [PA_ERR_TIMEOUT] = "Timeout", + [PA_ERR_AUTHKEY] = "No authorization key", + [PA_ERR_INTERNAL] = "Internal error", + [PA_ERR_CONNECTIONTERMINATED] = "Connection terminated", + [PA_ERR_KILLED] = "Entity killed", + [PA_ERR_INVALIDSERVER] = "Invalid server", + [PA_ERR_MODINITFAILED] = "Module initalization failed", + [PA_ERR_BADSTATE] = "Bad state", + [PA_ERR_NODATA] = "No data", + [PA_ERR_VERSION] = "Incompatible protocol version", + [PA_ERR_TOOLARGE] = "Too large" + }; + if (error < 0 || error >= PA_ERR_MAX) return NULL; return errortab[error]; } - -#ifdef HAVE_PTHREAD - -static pthread_once_t cstrerror_once = PTHREAD_ONCE_INIT; -static pthread_key_t tlsstr_key; - -static void inittls(void) { - int ret; - - ret = pthread_key_create(&tlsstr_key, pa_xfree); - if (ret) { - fprintf(stderr, __FILE__ ": CRITICAL: Unable to allocate TLS key (%d)\n", errno); - exit(-1); - } -} - -#elif HAVE_WINDOWS_H - -static DWORD tlsstr_key = TLS_OUT_OF_INDEXES; -static DWORD monitor_key = TLS_OUT_OF_INDEXES; - -static void inittls(void) { - HANDLE mutex; - char name[64]; - - sprintf(name, "polypaudio%d", (int)GetCurrentProcessId()); - - mutex = CreateMutex(NULL, FALSE, name); - if (!mutex) { - fprintf(stderr, __FILE__ ": CRITICAL: Unable to create named mutex (%d)\n", (int)GetLastError()); - exit(-1); - } - - WaitForSingleObject(mutex, INFINITE); - - if (tlsstr_key == TLS_OUT_OF_INDEXES) { - tlsstr_key = TlsAlloc(); - monitor_key = TlsAlloc(); - if ((tlsstr_key == TLS_OUT_OF_INDEXES) || (monitor_key == TLS_OUT_OF_INDEXES)) { - fprintf(stderr, __FILE__ ": CRITICAL: Unable to allocate TLS key (%d)\n", (int)GetLastError()); - exit(-1); - } - } - - ReleaseMutex(mutex); - - CloseHandle(mutex); -} - -/* - * This is incredibly brain dead, but this is necessary when dealing with - * the hell that is Win32. - */ -struct monitor_data { - HANDLE thread; - void *data; -}; - -static DWORD WINAPI monitor_thread(LPVOID param) { - struct monitor_data *data; - - data = (struct monitor_data*)param; - assert(data); - - WaitForSingleObject(data->thread, INFINITE); - - CloseHandle(data->thread); - pa_xfree(data->data); - pa_xfree(data); - - return 0; -} - -static void start_monitor(void) { - HANDLE thread; - struct monitor_data *data; - - data = pa_xnew(struct monitor_data, 1); - assert(data); - - DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), - GetCurrentProcess(), &data->thread, 0, FALSE, DUPLICATE_SAME_ACCESS); - - thread = CreateThread(NULL, 0, monitor_thread, data, 0, NULL); - assert(thread); - - TlsSetValue(monitor_key, data); - - CloseHandle(thread); -} - -#else - -/* Unsafe, but we have no choice */ -static char *tlsstr; - -#endif - -const char* pa_cstrerror(int errnum) { - const char *origbuf; - -#ifdef HAVE_STRERROR_R - char errbuf[128]; -#endif - -#ifdef HAVE_PTHREAD - char *tlsstr; - - pthread_once(&cstrerror_once, inittls); - - tlsstr = pthread_getspecific(tlsstr_key); -#elif defined(HAVE_WINDOWS_H) - char *tlsstr; - struct monitor_data *data; - - inittls(); - - tlsstr = TlsGetValue(tlsstr_key); - if (!tlsstr) - start_monitor(); - data = TlsGetValue(monitor_key); -#endif - - if (tlsstr) - pa_xfree(tlsstr); - -#ifdef HAVE_STRERROR_R - -#ifdef __GLIBC__ - origbuf = strerror_r(errnum, errbuf, sizeof(errbuf)); - if (origbuf == NULL) - origbuf = ""; -#else - if (strerror_r(errnum, errbuf, sizeof(errbuf)) == 0) { - origbuf = errbuf; - errbuf[sizeof(errbuf) - 1] = '\0'; - } else - origbuf = ""; -#endif - -#else - /* This might not be thread safe, but we hope for the best */ - origbuf = strerror(errnum); -#endif - - tlsstr = pa_locale_to_utf8(origbuf); - if (!tlsstr) { - fprintf(stderr, "Unable to convert, filtering\n"); - tlsstr = pa_utf8_filter(origbuf); - } - -#ifdef HAVE_PTHREAD - pthread_setspecific(tlsstr_key, tlsstr); -#elif defined(HAVE_WINDOWS_H) - TlsSetValue(tlsstr_key, tlsstr); - data->data = tlsstr; -#endif - - return tlsstr; -} diff --git a/src/polyp/error.h b/src/polyp/error.h index 1d7b2ca6..9856c1af 100644 --- a/src/polyp/error.h +++ b/src/polyp/error.h @@ -33,12 +33,6 @@ PA_C_DECL_BEGIN /** Return a human readable error message for the specified numeric error code */ const char* pa_strerror(int error); -/** A wrapper around the standard strerror() function that converts the - * string to UTF-8. The function is thread safe but the returned string is - * only guaranteed to exist until the thread exits or pa_cstrerror() is - * called again from the same thread. */ -const char* pa_cstrerror(int errnum); - PA_C_DECL_END #endif diff --git a/src/polyp/mainloop-signal.c b/src/polyp/mainloop-signal.c index c6ad431a..92702814 100644 --- a/src/polyp/mainloop-signal.c +++ b/src/polyp/mainloop-signal.c @@ -36,7 +36,7 @@ #include #endif -#include +#include #include #include diff --git a/src/polyp/mainloop.c b/src/polyp/mainloop.c index 6088fa4b..61d8b488 100644 --- a/src/polyp/mainloop.c +++ b/src/polyp/mainloop.c @@ -44,7 +44,7 @@ #include "../polypcore/pipe.h" #endif -#include +#include #include #include diff --git a/src/polyp/util.c b/src/polyp/util.c index 91054483..842b9e7f 100644 --- a/src/polyp/util.c +++ b/src/polyp/util.c @@ -51,8 +51,7 @@ #include "../polypcore/winsock.h" -#include - +#include #include #include diff --git a/src/polypcore/authkey.c b/src/polypcore/authkey.c index 6b462a23..54f4dd86 100644 --- a/src/polypcore/authkey.c +++ b/src/polypcore/authkey.c @@ -35,8 +35,8 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/polypcore/cli-command.c b/src/polypcore/cli-command.c index 039aa957..e25e464c 100644 --- a/src/polypcore/cli-command.c +++ b/src/polypcore/cli-command.c @@ -29,7 +29,6 @@ #include #include -#include #include #include @@ -50,6 +49,7 @@ #include #include #include +#include #include "cli-command.h" diff --git a/src/polypcore/conf-parser.c b/src/polypcore/conf-parser.c index 4bcb83dd..d59bc555 100644 --- a/src/polypcore/conf-parser.c +++ b/src/polypcore/conf-parser.c @@ -28,9 +28,9 @@ #include #include -#include #include +#include #include #include diff --git a/src/polypcore/core-error.c b/src/polypcore/core-error.c new file mode 100644 index 00000000..f2240a9f --- /dev/null +++ b/src/polypcore/core-error.c @@ -0,0 +1,205 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_PTHREAD +#include +#endif + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include +#include + +#include +#include + +#include "core-error.h" + +#ifdef HAVE_PTHREAD + +static pthread_once_t cstrerror_once = PTHREAD_ONCE_INIT; +static pthread_key_t tlsstr_key; + +static void inittls(void) { + int ret; + + ret = pthread_key_create(&tlsstr_key, pa_xfree); + if (ret) { + fprintf(stderr, __FILE__ ": CRITICAL: Unable to allocate TLS key (%d)\n", errno); + exit(-1); + } +} + +#elif HAVE_WINDOWS_H + +static DWORD tlsstr_key = TLS_OUT_OF_INDEXES; +static DWORD monitor_key = TLS_OUT_OF_INDEXES; + +static void inittls(void) { + HANDLE mutex; + char name[64]; + + sprintf(name, "polypaudio%d", (int)GetCurrentProcessId()); + + mutex = CreateMutex(NULL, FALSE, name); + if (!mutex) { + fprintf(stderr, __FILE__ ": CRITICAL: Unable to create named mutex (%d)\n", (int)GetLastError()); + exit(-1); + } + + WaitForSingleObject(mutex, INFINITE); + + if (tlsstr_key == TLS_OUT_OF_INDEXES) { + tlsstr_key = TlsAlloc(); + monitor_key = TlsAlloc(); + if ((tlsstr_key == TLS_OUT_OF_INDEXES) || (monitor_key == TLS_OUT_OF_INDEXES)) { + fprintf(stderr, __FILE__ ": CRITICAL: Unable to allocate TLS key (%d)\n", (int)GetLastError()); + exit(-1); + } + } + + ReleaseMutex(mutex); + + CloseHandle(mutex); +} + +/* + * This is incredibly brain dead, but this is necessary when dealing with + * the hell that is Win32. + */ +struct monitor_data { + HANDLE thread; + void *data; +}; + +static DWORD WINAPI monitor_thread(LPVOID param) { + struct monitor_data *data; + + data = (struct monitor_data*)param; + assert(data); + + WaitForSingleObject(data->thread, INFINITE); + + CloseHandle(data->thread); + pa_xfree(data->data); + pa_xfree(data); + + return 0; +} + +static void start_monitor(void) { + HANDLE thread; + struct monitor_data *data; + + data = pa_xnew(struct monitor_data, 1); + assert(data); + + DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), + GetCurrentProcess(), &data->thread, 0, FALSE, DUPLICATE_SAME_ACCESS); + + thread = CreateThread(NULL, 0, monitor_thread, data, 0, NULL); + assert(thread); + + TlsSetValue(monitor_key, data); + + CloseHandle(thread); +} + +#else + +/* Unsafe, but we have no choice */ +static char *tlsstr; + +#endif + +const char* pa_cstrerror(int errnum) { + const char *origbuf; + +#ifdef HAVE_STRERROR_R + char errbuf[128]; +#endif + +#ifdef HAVE_PTHREAD + char *tlsstr; + + pthread_once(&cstrerror_once, inittls); + + tlsstr = pthread_getspecific(tlsstr_key); +#elif defined(HAVE_WINDOWS_H) + char *tlsstr; + struct monitor_data *data; + + inittls(); + + tlsstr = TlsGetValue(tlsstr_key); + if (!tlsstr) + start_monitor(); + data = TlsGetValue(monitor_key); +#endif + + if (tlsstr) + pa_xfree(tlsstr); + +#ifdef HAVE_STRERROR_R + +#ifdef __GLIBC__ + origbuf = strerror_r(errnum, errbuf, sizeof(errbuf)); + if (origbuf == NULL) + origbuf = ""; +#else + if (strerror_r(errnum, errbuf, sizeof(errbuf)) == 0) { + origbuf = errbuf; + errbuf[sizeof(errbuf) - 1] = '\0'; + } else + origbuf = ""; +#endif + +#else + /* This might not be thread safe, but we hope for the best */ + origbuf = strerror(errnum); +#endif + + tlsstr = pa_locale_to_utf8(origbuf); + if (!tlsstr) { + fprintf(stderr, "Unable to convert, filtering\n"); + tlsstr = pa_utf8_filter(origbuf); + } + +#ifdef HAVE_PTHREAD + pthread_setspecific(tlsstr_key, tlsstr); +#elif defined(HAVE_WINDOWS_H) + TlsSetValue(tlsstr_key, tlsstr); + data->data = tlsstr; +#endif + + return tlsstr; +} diff --git a/src/polypcore/core-error.h b/src/polypcore/core-error.h new file mode 100644 index 00000000..17595c98 --- /dev/null +++ b/src/polypcore/core-error.h @@ -0,0 +1,41 @@ +#ifndef foocoreerrorhfoo +#define foocoreerrorhfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/** \file + * Error management */ + +PA_C_DECL_BEGIN + +/** A wrapper around the standard strerror() function that converts the + * string to UTF-8. The function is thread safe but the returned string is + * only guaranteed to exist until the thread exits or pa_cstrerror() is + * called again from the same thread. */ +const char* pa_cstrerror(int errnum); + +PA_C_DECL_END + +#endif diff --git a/src/polypcore/core-scache.c b/src/polypcore/core-scache.c index 1d60a910..b44a7e19 100644 --- a/src/polypcore/core-scache.c +++ b/src/polypcore/core-scache.c @@ -41,7 +41,6 @@ #include #endif -#include #include #include #include @@ -57,6 +56,7 @@ #include #include #include +#include #include "core-scache.h" diff --git a/src/polypcore/core-util.c b/src/polypcore/core-util.c index bb6a3d85..6cf281c5 100644 --- a/src/polypcore/core-util.c +++ b/src/polypcore/core-util.c @@ -69,10 +69,10 @@ #include -#include #include #include +#include #include #include diff --git a/src/polypcore/iochannel.c b/src/polypcore/iochannel.c index 8af6a36b..106c413e 100644 --- a/src/polypcore/iochannel.c +++ b/src/polypcore/iochannel.c @@ -38,9 +38,9 @@ #include "winsock.h" -#include #include +#include #include #include #include diff --git a/src/polypcore/ioline.c b/src/polypcore/ioline.c index 2e0a3e1a..6a2ef338 100644 --- a/src/polypcore/ioline.c +++ b/src/polypcore/ioline.c @@ -29,9 +29,9 @@ #include #include -#include #include +#include #include #include "ioline.h" diff --git a/src/polypcore/pid.c b/src/polypcore/pid.c index b8f53955..a5c0ef0b 100644 --- a/src/polypcore/pid.c +++ b/src/polypcore/pid.c @@ -39,9 +39,9 @@ #include #endif -#include #include +#include #include #include diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index d7c9475a..02e140b9 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -30,7 +30,6 @@ #include #include -#include #include #include #include @@ -49,6 +48,7 @@ #include #include #include +#include #include "endianmacros.h" diff --git a/src/polypcore/protocol-simple.c b/src/polypcore/protocol-simple.c index f15f882a..8b319d70 100644 --- a/src/polypcore/protocol-simple.c +++ b/src/polypcore/protocol-simple.c @@ -30,7 +30,6 @@ #include #include -#include #include #include @@ -39,6 +38,7 @@ #include #include #include +#include #include "protocol-simple.h" diff --git a/src/polypcore/socket-client.c b/src/polypcore/socket-client.c index aa885759..fd840ab5 100644 --- a/src/polypcore/socket-client.c +++ b/src/polypcore/socket-client.c @@ -54,10 +54,10 @@ #include "winsock.h" -#include #include #include +#include #include #include #include diff --git a/src/polypcore/socket-server.c b/src/polypcore/socket-server.c index 871fac11..17071ec2 100644 --- a/src/polypcore/socket-server.c +++ b/src/polypcore/socket-server.c @@ -64,11 +64,11 @@ #include #include -#include #include #include #include +#include #include "socket-server.h" diff --git a/src/polypcore/socket-util.c b/src/polypcore/socket-util.c index 06cdc625..aefcb5ef 100644 --- a/src/polypcore/socket-util.c +++ b/src/polypcore/socket-util.c @@ -59,9 +59,9 @@ #include "winsock.h" -#include #include +#include #include #include diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c index 351d79da..ad50c77c 100644 --- a/src/utils/pacmd.c +++ b/src/utils/pacmd.c @@ -54,7 +54,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { } if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(PF_UNIX, SOCK_STREAM, 0): %s", pa_cstrerror(errno)); + pa_log(__FILE__": socket(PF_UNIX, SOCK_STREAM, 0): %s", strerror(errno)); goto fail; } @@ -66,7 +66,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { int r; if ((r = connect(fd, (struct sockaddr*) &sa, sizeof(sa))) < 0 && (errno != ECONNREFUSED && errno != ENOENT)) { - pa_log(__FILE__": connect(): %s", pa_cstrerror(errno)); + pa_log(__FILE__": connect(): %s", strerror(errno)); goto fail; } @@ -97,7 +97,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { for (;;) { if (select(FD_SETSIZE, &ifds, &ofds, NULL, NULL) < 0) { - pa_log(__FILE__": select(): %s", pa_cstrerror(errno)); + pa_log(__FILE__": select(): %s", strerror(errno)); goto fail; } @@ -109,7 +109,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { if (r == 0) break; - pa_log(__FILE__": read(): %s", pa_cstrerror(errno)); + pa_log(__FILE__": read(): %s", strerror(errno)); goto fail; } @@ -125,7 +125,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { if (r == 0) break; - pa_log(__FILE__": read(): %s", pa_cstrerror(errno)); + pa_log(__FILE__": read(): %s", strerror(errno)); goto fail; } @@ -138,7 +138,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { assert(obuf_length); if ((r = write(1, obuf + obuf_index, obuf_length)) < 0) { - pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); + pa_log(__FILE__": write(): %s", strerror(errno)); goto fail; } @@ -152,7 +152,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { assert(ibuf_length); if ((r = write(fd, ibuf + ibuf_index, ibuf_length)) < 0) { - pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); + pa_log(__FILE__": write(): %s", strerror(errno)); goto fail; } diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 5987ec5f..c1cc9c92 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -361,7 +361,7 @@ static void reset_params(fd_info *i) { i->n_fragments = 0; } -static char *client_name(char *buf, size_t n) { +static const char *client_name(char *buf, size_t n) { char p[PATH_MAX]; const char *e; @@ -376,7 +376,7 @@ static char *client_name(char *buf, size_t n) { return buf; } -static char *stream_name(void) { +static const char *stream_name(void) { const char *e; if ((e = getenv("PADSP_STREAM_NAME"))) -- cgit From f3b72593b545c66eeb5c7858958f0b2c44fd730e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 17:18:42 +0000 Subject: really fix a superfluous warning when building padsp.c git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@973 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index c1cc9c92..5f3f9158 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -205,7 +205,7 @@ static int padsp_disabled(void) { pthread_mutex_lock(&func_mutex); if (!sym_resolved) { - sym = (int*) dlsym_fn(RTLD_DEFAULT, "__padsp_disabled__"); + sym = (int*) dlsym(RTLD_DEFAULT, "__padsp_disabled__"); sym_resolved = 1; } -- cgit From d39740fb6b5c1bf5f70f655451878ee5fb4edf5e Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 25 May 2006 17:26:02 +0000 Subject: We only need the so for libpolypdsp. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@974 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Makefile.am b/src/Makefile.am index 3a8c9bba..569b6561 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1188,5 +1188,7 @@ install-exec-hook: chmod u+s $(DESTDIR)$(bindir)/polypaudio ln -sf pacat $(DESTDIR)$(bindir)/parec rm -f $(DESTDIR)$(modlibexecdir)/*.a + rm -f $(DESTDIR)$(libdir)/libpolypdsp.a + rm -f $(DESTDIR)$(libdir)/libpolypdsp.la .PHONY: utils/padsp -- cgit From b754d5095e8c1bbf41e7c0147dfb2328145a2c83 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 25 May 2006 17:27:06 +0000 Subject: Wrong prefix used in the padsp script. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@975 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/utils/padsp b/src/utils/padsp index dc89bfb7..b43535b6 100644 --- a/src/utils/padsp +++ b/src/utils/padsp @@ -26,24 +26,24 @@ while getopts 'hs:n:m:MSDd' param ; do export POLYP_SERVER ;; n) - PA_CLIENT_NAME="$OPTARG" - export PA_CLIENT_NAME + PADSP_CLIENT_NAME="$OPTARG" + export PADSP_CLIENT_NAME ;; m) - PA_STREAM_NAME="$OPTARG" - export PA_STREAM_NAME + PADSP_STREAM_NAME="$OPTARG" + export PADSP_STREAM_NAME ;; M) - PA_NO_MIXER=1 - export PA_NO_MIXER + PADSP_NO_MIXER=1 + export PADSP_NO_MIXER ;; S) - PA_NO_SNDSTAT=1 - export PA_NO_SNDSTAT + PADSP_NO_SNDSTAT=1 + export PADSP_NO_SNDSTAT ;; D) - PA_NO_DSP=1 - export PA_NO_DSP + PADSP_NO_DSP=1 + export PADSP_NO_DSP ;; d) PADSP_DEBUG=1 -- cgit From 7d975345a555fc20e5019307c7dc01545552e42d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 23:20:28 +0000 Subject: * add new API function pa_stream_get_buffer_attr(). * modify pacat.c to make use of that new API * extend protocol to allow transfer of the necessary information * update protocol version accordingly git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@976 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- src/polyp/internal.h | 1 + src/polyp/stream.c | 47 +++++++++++++++++++++++++++++++++++++++-- src/polyp/stream.h | 5 +++++ src/polypcore/memblockq.c | 12 +++++++++++ src/polypcore/memblockq.h | 6 ++++++ src/polypcore/protocol-native.c | 21 +++++++++++++++++- src/utils/pacat.c | 20 +++++++++++++++++- 8 files changed, 109 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 157c01a4..7859d33f 100644 --- a/configure.ac +++ b/configure.ac @@ -34,7 +34,7 @@ AC_SUBST(PA_MAJORMINOR, "PA_MAJOR.PA_MINOR") AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/polypaudio/]) AC_SUBST(PA_API_VERSION, 9) -AC_SUBST(PA_PROTOCOL_VERSION, 8) +AC_SUBST(PA_PROTOCOL_VERSION, 9) AC_SUBST(LIBPOLYP_VERSION_INFO, [0:0:0]) AC_SUBST(LIBPOLYPCORE_VERSION_INFO, [0:0:0]) diff --git a/src/polyp/internal.h b/src/polyp/internal.h index 80c28616..d88a1e5b 100644 --- a/src/polyp/internal.h +++ b/src/polyp/internal.h @@ -100,6 +100,7 @@ struct pa_stream { char *name; pa_buffer_attr buffer_attr; + int buffer_attr_from_server; pa_sample_spec sample_spec; pa_channel_map channel_map; pa_stream_flags_t flags; diff --git a/src/polyp/stream.c b/src/polyp/stream.c index e41c588e..17884ed3 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -84,6 +84,7 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->requested_bytes = 0; s->state = PA_STREAM_UNCONNECTED; memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); + s->buffer_attr_from_server = 0; s->peek_memchunk.index = 0; s->peek_memchunk.length = 0; @@ -401,12 +402,43 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED if (pa_tagstruct_getu32(t, &s->channel) < 0 || ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - ((s->direction != PA_STREAM_RECORD) && pa_tagstruct_getu32(t, &s->requested_bytes) < 0) || - !pa_tagstruct_eof(t)) { + ((s->direction != PA_STREAM_RECORD) && pa_tagstruct_getu32(t, &s->requested_bytes) < 0)) { pa_context_fail(s->context, PA_ERR_PROTOCOL); goto finish; } + if (!pa_tagstruct_eof(t)) { + + if (s->direction == PA_STREAM_PLAYBACK) { + + /* This is a server 0.9.0 or later */ + if (pa_tagstruct_getu32(t, &s->buffer_attr.maxlength) < 0 || + pa_tagstruct_getu32(t, &s->buffer_attr.tlength) < 0 || + pa_tagstruct_getu32(t, &s->buffer_attr.prebuf) < 0 || + pa_tagstruct_getu32(t, &s->buffer_attr.minreq) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(s->context, PA_ERR_PROTOCOL); + goto finish; + } + + s->buffer_attr_from_server = 1; + } else if (s->direction == PA_STREAM_RECORD) { + + /* This is a server 0.9.0 or later */ + if (pa_tagstruct_getu32(t, &s->buffer_attr.maxlength) < 0 || + pa_tagstruct_getu32(t, &s->buffer_attr.fragsize) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(s->context, PA_ERR_PROTOCOL); + goto finish; + } + + s->buffer_attr_from_server = 1; + } else { + pa_context_fail(s->context, PA_ERR_PROTOCOL); + goto finish; + } + } + if (s->direction == PA_STREAM_RECORD) { assert(!s->record_memblockq); @@ -1336,3 +1368,14 @@ const pa_channel_map* pa_stream_get_channel_map(pa_stream *s) { return &s->channel_map; } + +const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s) { + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr_from_server, PA_ERR_NODATA); + + return &s->buffer_attr; +} diff --git a/src/polyp/stream.h b/src/polyp/stream.h index ad77d938..d1f558ae 100644 --- a/src/polyp/stream.h +++ b/src/polyp/stream.h @@ -439,6 +439,11 @@ const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s); /** Return a pointer to the stream's channel map. \since 0.8 */ const pa_channel_map* pa_stream_get_channel_map(pa_stream *s); +/** Return the buffer metrics of the stream. Only valid after the + * stream has been connected successfuly and if the server is at least + * Polypaudio 0.9. \since 0.9.0 */ +const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s); + PA_C_DECL_END #endif diff --git a/src/polypcore/memblockq.c b/src/polypcore/memblockq.c index caacd96f..8ed358fa 100644 --- a/src/polypcore/memblockq.c +++ b/src/polypcore/memblockq.c @@ -622,3 +622,15 @@ void pa_memblockq_prebuf_force(pa_memblockq *bq) { if (bq->state == RUNNING && bq->prebuf > 0) bq->state = PREBUF; } + +size_t pa_memblockq_get_maxlength(pa_memblockq *bq) { + assert(bq); + + return bq->maxlength; +} + +size_t pa_memblockq_get_prebuf(pa_memblockq *bq) { + assert(bq); + + return bq->prebuf; +} diff --git a/src/polypcore/memblockq.h b/src/polypcore/memblockq.h index 302a5366..74fb00ee 100644 --- a/src/polypcore/memblockq.h +++ b/src/polypcore/memblockq.h @@ -131,4 +131,10 @@ void pa_memblockq_prebuf_disable(pa_memblockq *bq); /* Force prebuf */ void pa_memblockq_prebuf_force(pa_memblockq *bq); +/* Return the maximum length of the queue in bytes */ +size_t pa_memblockq_get_maxlength(pa_memblockq *bq); + +/* Return the prebuffer length in bytes */ +size_t pa_memblockq_get_prebuf(pa_memblockq *bq); + #endif diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index a300c45d..7ab11209 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -755,6 +755,16 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC assert(s->sink_input); pa_tagstruct_putu32(reply, s->sink_input->index); pa_tagstruct_putu32(reply, s->requested_bytes = pa_memblockq_missing(s->memblockq)); + + if (c->version >= 9) { + /* Since 0.9 we support sending the buffer metrics back to the client */ + + pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_maxlength(s->memblockq)); + pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_tlength(s->memblockq)); + pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_prebuf(s->memblockq)); + pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_minreq(s->memblockq)); + } + pa_pstream_send_tagstruct(c->pstream, reply); request_bytes(s); } @@ -852,6 +862,14 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_tagstruct_putu32(reply, s->index); assert(s->source_output); pa_tagstruct_putu32(reply, s->source_output->index); + + if (c->version >= 9) { + /* Since 0.9 we support sending the buffer metrics back to the client */ + + pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_maxlength(s->memblockq)); + pa_tagstruct_putu32(reply, (uint32_t) s->fragment_size); + } + pa_pstream_send_tagstruct(c->pstream, reply); } @@ -2215,7 +2233,8 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c); } else c->auth_timeout_event = NULL; - + + c->version = 8; c->protocol = p; assert(p->core); c->client = pa_client_new(p->core, __FILE__, "Client"); diff --git a/src/utils/pacat.c b/src/utils/pacat.c index b1f5bf59..83c3d3ca 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -154,8 +154,26 @@ static void stream_state_callback(pa_stream *s, void *userdata) { break; case PA_STREAM_READY: - if (verbose) + if (verbose) { + pa_buffer_attr *a; + fprintf(stderr, "Stream successfully created.\n"); + + if (!(a = pa_stream_get_buffer_attr(s))) + fprintf(stderr, "pa_stream_get_buffer_attr() failed: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + else { + + if (mode == PLAYBACK) + fprintf(stderr, "Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u\n", a->maxlength, a->tlength, a->prebuf, a->minreq); + else { + assert(mode == RECORD); + fprintf(stderr, "Buffer metrics: maxlength=%u, fragsize=%u\n", a->maxlength, a->fragsize); + } + + } + + } + break; case PA_STREAM_FAILED: -- cgit From 099304a0d4604712261e66bffd32f0c5042329a0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 23:40:25 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@977 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/todo b/doc/todo index 0b78ee93..6301cc19 100644 --- a/doc/todo +++ b/doc/todo @@ -1,8 +1,5 @@ *** $Id$ *** -Pre 0.9.0 -- add API to query the bufferattrs after stream creation - Post 0.9.0: - alsa mmap driver - dbus/hal -- cgit From d142408f5c83d2fcdac802cfa9a5eeec14d88df1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 26 May 2006 07:24:25 +0000 Subject: Explicitly check version number when determining which fields are in a stream create response. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@978 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/internal.h | 1 - src/polyp/stream.c | 29 ++++++++++------------------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/polyp/internal.h b/src/polyp/internal.h index d88a1e5b..80c28616 100644 --- a/src/polyp/internal.h +++ b/src/polyp/internal.h @@ -100,7 +100,6 @@ struct pa_stream { char *name; pa_buffer_attr buffer_attr; - int buffer_attr_from_server; pa_sample_spec sample_spec; pa_channel_map channel_map; pa_stream_flags_t flags; diff --git a/src/polyp/stream.c b/src/polyp/stream.c index 17884ed3..e3f40a3f 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -84,7 +84,6 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->requested_bytes = 0; s->state = PA_STREAM_UNCONNECTED; memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - s->buffer_attr_from_server = 0; s->peek_memchunk.index = 0; s->peek_memchunk.length = 0; @@ -407,38 +406,29 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED goto finish; } - if (!pa_tagstruct_eof(t)) { - + if (pa_context_get_server_protocol_version(s->context) >= 9) { if (s->direction == PA_STREAM_PLAYBACK) { - - /* This is a server 0.9.0 or later */ if (pa_tagstruct_getu32(t, &s->buffer_attr.maxlength) < 0 || pa_tagstruct_getu32(t, &s->buffer_attr.tlength) < 0 || pa_tagstruct_getu32(t, &s->buffer_attr.prebuf) < 0 || - pa_tagstruct_getu32(t, &s->buffer_attr.minreq) < 0 || - !pa_tagstruct_eof(t)) { + pa_tagstruct_getu32(t, &s->buffer_attr.minreq) < 0) { pa_context_fail(s->context, PA_ERR_PROTOCOL); goto finish; } - - s->buffer_attr_from_server = 1; } else if (s->direction == PA_STREAM_RECORD) { - - /* This is a server 0.9.0 or later */ if (pa_tagstruct_getu32(t, &s->buffer_attr.maxlength) < 0 || - pa_tagstruct_getu32(t, &s->buffer_attr.fragsize) < 0 || - !pa_tagstruct_eof(t)) { + pa_tagstruct_getu32(t, &s->buffer_attr.fragsize) < 0) { pa_context_fail(s->context, PA_ERR_PROTOCOL); goto finish; } - - s->buffer_attr_from_server = 1; - } else { - pa_context_fail(s->context, PA_ERR_PROTOCOL); - goto finish; } } + if (!pa_tagstruct_eof(t)) { + pa_context_fail(s->context, PA_ERR_PROTOCOL); + goto finish; + } + if (s->direction == PA_STREAM_RECORD) { assert(!s->record_memblockq); @@ -1375,7 +1365,8 @@ const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s) { PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr_from_server, PA_ERR_NODATA); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, + pa_context_get_server_protocol_version(s->context) >= 9, PA_ERR_NODATA); return &s->buffer_attr; } -- cgit From 6aeaaf94a8af3c3b0607bc4a9f57923c569d71de Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 26 May 2006 07:24:47 +0000 Subject: Returned buffer attr is const. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@979 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pacat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 83c3d3ca..99e54e64 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -155,7 +155,7 @@ static void stream_state_callback(pa_stream *s, void *userdata) { case PA_STREAM_READY: if (verbose) { - pa_buffer_attr *a; + const pa_buffer_attr *a; fprintf(stderr, "Stream successfully created.\n"); -- cgit From 7d90e3a32d52a5d94b536c0286d3e87f4df01fd0 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 26 May 2006 09:21:03 +0000 Subject: Fix typos. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@980 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 5f3f9158..b3e443d3 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1129,8 +1129,8 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno *(int*) argp = 0; break; - case SOUND_MIXER_CAPS: - debug(__FILE__": SOUND_MIXER_CAPS\n"); + case SOUND_MIXER_READ_CAPS: + debug(__FILE__": SOUND_MIXER_READ_CAPS\n"); *(int*) argp = 0; break; @@ -1204,7 +1204,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno } default: - debug(__FILE__": unknwon ioctl 0x%08lx\n", request); + debug(__FILE__": unknown ioctl 0x%08lx\n", request); *_errno = EINVAL; goto fail; -- cgit From 12dc4c21ac4e31becf687513ac9852a3ae6893e5 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 26 May 2006 12:18:07 +0000 Subject: Fix the fix_metrics() function so that we don't get a tiny buffer by default. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@981 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index b3e443d3..8bad126b 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -357,7 +357,7 @@ static void reset_params(fd_info *i) { i->sample_spec.format = PA_SAMPLE_ULAW; i->sample_spec.channels = 1; i->sample_spec.rate = 8000; - i->fragment_size = 1024; + i->fragment_size = 0; i->n_fragments = 0; } @@ -627,13 +627,23 @@ static void fix_metrics(fd_info *i) { fs = pa_frame_size(&i->sample_spec); i->fragment_size = (i->fragment_size/fs)*fs; - - if (i->n_fragments < 2) - i->n_fragments = 12; - if (i->fragment_size <= 0) - if ((i->fragment_size = pa_bytes_per_second(&i->sample_spec) / 2 / i->n_fragments) <= 0) + /* Number of fragments set? */ + if (i->n_fragments < 2) { + if (i->fragment_size > 0) { + i->n_fragments = pa_bytes_per_second(&i->sample_spec) / 2 / i->fragment_size; + if (i->n_fragments < 2) + i->n_fragments = 2; + } else + i->n_fragments = 12; + } + + /* Fragment size set? */ + if (i->fragment_size <= 0) { + i->fragment_size = pa_bytes_per_second(&i->sample_spec) / 2 / i->n_fragments; + if (i->fragment_size < 1024) i->fragment_size = 1024; + } debug(__FILE__": sample spec: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); debug(__FILE__": fixated metrics to %i fragments, %li bytes each.\n", i->n_fragments, (long)i->fragment_size); -- cgit From c8e9fa36c5038b88adc684b578d8ec4c52381197 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 26 May 2006 12:24:37 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@982 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/doc/todo b/doc/todo index 6301cc19..f03c43a9 100644 --- a/doc/todo +++ b/doc/todo @@ -23,11 +23,8 @@ Post 0.9.0: - Fix a way for the threading API to handle state and subscription callbacks in a nice way. - iconv stuff sent from utils to server (UTF-8) -- iconv stuff leaving the server (e.g. syslog). Sample loading probably needs - help as well. +- iconv sample loading in server - Document utf8.h, timeval.h and util.h -- strerror() needs to be wrapped as it returns stuff in the current locale - and we tend to pass it to functions that require UTF-8. - fix clock of the NULL sink - gettextify polypaudio -- cgit From f5a888504fe70c0106c791e2d97caa3cd5675aef Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 26 May 2006 17:59:39 +0000 Subject: disable padsp for the polypaudio daemon itself by defining the __padsp_disabled__ symbol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@983 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/daemon/main.c b/src/daemon/main.c index b88f932c..16cc0f5e 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -79,6 +79,13 @@ int allow_severity = LOG_INFO; int deny_severity = LOG_WARNING; #endif +#ifdef HAVE_OSS +/* padsp looks for this symbol in the running process and disables + * itself if it finds it and it is set to 7 (which is actually a bit + * mask). For details see padsp. */ +int __padsp_disabled__ = 7; +#endif + #ifdef OS_IS_WIN32 static void message_cb(pa_mainloop_api*a, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { -- cgit From 3a868be9abdf3fdd4abc9017d2776474ac46e8a9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 26 May 2006 18:00:02 +0000 Subject: update README for 0.9.0 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@984 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/README.html.in b/doc/README.html.in index 62a23b71..f02c657d 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -43,14 +43,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

      News

      -
      Fri Apr 28 2006:

      Fri May 26 2006:

      Version 0.9.0 released; changes include: new module module-volume-restore; -require valid UTF8 strings everywhere; properly support ALSA channel -maps for surround sound; increase maximum number of channels per -stream to 32; add new threaded main loop API for synchronous programs; -introduce real shared object versioning; a few API additions; many, -many bugfixes

      +new OSS API emulation tool padsp; require valid UTF8 strings +everywhere; properly support ALSA channel maps for surround sound; +increase maximum number of channels per stream to 32; add new threaded +main loop API for synchronous programs; introduce real shared object +versioning; a few API additions; many, many bugfixes

      Fri Apr 28 2006:

      Version 0.8.1 -- cgit From 632f5b44f5149477462a9b59c832c59fe6eaa7ae Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 May 2006 12:59:10 +0000 Subject: drop the .sh suffix from esdcompat git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@986 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 8 ++-- src/daemon/esdcompat.in | 98 ++++++++++++++++++++++++++++++++++++++++++++++ src/daemon/esdcompat.sh.in | 98 ---------------------------------------------- 3 files changed, 102 insertions(+), 102 deletions(-) create mode 100755 src/daemon/esdcompat.in delete mode 100755 src/daemon/esdcompat.sh.in diff --git a/src/Makefile.am b/src/Makefile.am index 569b6561..ef9d825b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -77,7 +77,7 @@ EXTRA_DIST = \ daemon/daemon.conf.in \ daemon/default.pa.in \ depmod.py \ - daemon/esdcompat.sh.in \ + daemon/esdcompat.in \ utils/padsp \ modules/module-defs.h.m4 @@ -142,7 +142,7 @@ if HAVE_HOWL bin_PROGRAMS += pabrowse endif -bin_SCRIPTS = esdcompat.sh +bin_SCRIPTS = esdcompat pacat_SOURCES = utils/pacat.c pacat_LDADD = $(AM_LDADD) libpolyp.la @@ -1161,9 +1161,9 @@ suid: polypaudio chown root $< chmod u+s $< -CLEANFILES = esdcompat.sh client.conf default.pa daemon.conf +CLEANFILES = esdcompat client.conf default.pa daemon.conf -esdcompat.sh: daemon/esdcompat.sh.in Makefile +esdcompat: daemon/esdcompat.in Makefile sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ diff --git a/src/daemon/esdcompat.in b/src/daemon/esdcompat.in new file mode 100755 index 00000000..76023f52 --- /dev/null +++ b/src/daemon/esdcompat.in @@ -0,0 +1,98 @@ +#!/bin/sh + +# $Id$ +# +# This file is part of polypaudio. +# +# polypaudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# polypaudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with polypaudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +VERSION_STRING="@PACKAGE_NAME@ esd wrapper @PACKAGE_VERSION@" + +fail() { + echo "ERROR: $1" + exit 1 +} + +ARGS=" --log-target=syslog" + +for N in $(seq $#) ; do + + case "$1" in + "") + ;; + + -v|--version) + echo "$VERSION_STRING" + exit 0 + ;; + + -h|--help) + cat < Date: Mon, 29 May 2006 14:06:08 +0000 Subject: merge patch from Igor Zubkov, fixing linking of the HOWL modules git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@988 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index ef9d825b..de0c18df 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1089,12 +1089,12 @@ module_solaris_la_LIBADD = $(AM_LIBADD) libiochannel.la libhowl_wrap_la_SOURCES = modules/howl-wrap.c modules/howl-wrap.h libhowl_wrap_la_LDFLAGS = -avoid-version -libhowl_wrap_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) +libhowl_wrap_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) libpolypcore.la libhowl_wrap_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) module_zeroconf_publish_la_SOURCES = modules/module-zeroconf-publish.c module_zeroconf_publish_la_LDFLAGS = -module -avoid-version -module_zeroconf_publish_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) libhowl-wrap.la +module_zeroconf_publish_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) libhowl-wrap.la libpolypcore.la module_zeroconf_publish_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) # LIRC -- cgit From 6140619e61884afc85e64d834745fa59d61e93d9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 May 2006 00:25:51 +0000 Subject: fix amd64 portability issues git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@989 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/protocol-native.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index 7ab11209..f663dc35 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -696,8 +696,7 @@ static pa_tagstruct *reply_new(uint32_t tag) { static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; struct playback_stream *s; - size_t maxlength, tlength, prebuf, minreq; - uint32_t sink_index, syncid; + uint32_t maxlength, tlength, prebuf, minreq, sink_index, syncid; const char *name, *sink_name; pa_sample_spec ss; pa_channel_map map; @@ -736,7 +735,7 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, maxlength > 0 && maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); if (sink_index != PA_INVALID_INDEX) sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); -- cgit From 73eedcbaaec8ff6bbdde2b55eec3a83092044527 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 May 2006 12:23:37 +0000 Subject: load alsa modules with device string hw:0 instead of hw:0,0 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@990 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-detect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index d0a37733..3512e31c 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -92,7 +92,7 @@ static int detect_alsa(pa_core *c, int just_one) { if (subdevice != 0) continue; - snprintf(args, sizeof(args), "device=hw:%u,0", device); + snprintf(args, sizeof(args), "device=hw:%u", device); if (!pa_module_load(c, is_sink ? "module-alsa-sink" : "module-alsa-source", args)) continue; -- cgit From 821a49b96708986cbfb45de416f806ee5efed943 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 May 2006 15:28:46 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@991 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/todo b/doc/todo index f03c43a9..19e4f1a9 100644 --- a/doc/todo +++ b/doc/todo @@ -27,6 +27,7 @@ Post 0.9.0: - Document utf8.h, timeval.h and util.h - fix clock of the NULL sink - gettextify polypaudio +- use send() with MSG_NOSIGNAL instead of write() wherever possible, and than drop that SIGPIPE warning Long term: - pass meta info for hearing impaired -- cgit From bb820db4b5b9e928b4d7fe58bbab2f56b1897f64 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 May 2006 22:05:07 +0000 Subject: * if an ALSA device doesn't support the channel count requested, use what ALSA suggests instead * if an ALSA device doesn't support the sampling freq requested, use what ALSA suggests and resample if this deviates more than 10% from what we requested * fix segfault freeing an unitialized mixer_fdl field git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@992 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 17 ++++++++++++++--- src/modules/alsa-util.h | 2 +- src/modules/module-alsa-sink.c | 13 ++++++++++--- src/modules/module-alsa-source.c | 15 +++++++++++---- 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 122f4419..22e623f6 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -249,11 +249,12 @@ int pa_alsa_fdlist_init_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_han /* Set the hardware parameters of the given ALSA device. Returns the * selected fragment settings in *period and *period_size */ -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { int ret = -1; snd_pcm_uframes_t buffer_size; snd_pcm_hw_params_t *hwparams = NULL; unsigned int r = ss->rate; + unsigned int c = ss->channels; static const snd_pcm_format_t format_trans[] = { [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8, @@ -273,14 +274,24 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint3 (ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0 || (ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format])) < 0 || (ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0 || - (ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss->channels)) < 0 || + (ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0 || (*period_size > 0 && (ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL)) < 0) || (*periods > 0 && (ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0) || (ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) goto finish; - if (ss->rate != r) + if (ss->rate != r) { pa_log_info(__FILE__": device doesn't support %u Hz, changed to %u Hz.", ss->rate, r); + + /* If the sample rate deviates too much, we need to resample */ + if (r < ss->rate*.9 || r > ss->rate*1.1) + ss->rate = r; + } + + if (ss->channels != c) { + pa_log_info(__FILE__": device doesn't support %u channels, changed to %u.", ss->channels, c); + ss->channels = c; + } if ((ret = snd_pcm_prepare(pcm_handle)) < 0) goto finish; diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h index 69d4eddc..4bee8625 100644 --- a/src/modules/alsa-util.h +++ b/src/modules/alsa-util.h @@ -37,7 +37,7 @@ void pa_alsa_fdlist_free(struct pa_alsa_fdlist *fdl); int pa_alsa_fdlist_init_pcm(struct pa_alsa_fdlist *fdl, snd_pcm_t *pcm_handle, pa_mainloop_api* m, void (*cb)(void *userdata), void *userdata); int pa_alsa_fdlist_init_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, pa_mainloop_api* m); -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size); +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size); int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev); snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name); diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index e768e16a..a0b6dc08 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -363,6 +363,10 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } + if (ss.channels != map.channels) + /* Seems ALSA didn't like the channel number, so let's fix the channel map */ + pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); + if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) { pa_log(__FILE__": Error opening mixer: %s", snd_strerror(err)); goto fail; @@ -374,8 +378,10 @@ int pa__init(pa_core *c, pa_module*m) { u->mixer_handle = NULL; } - u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map); - assert(u->sink); + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { + pa_log(__FILE__": Failed to create sink object"); + goto fail; + } u->sink->get_latency = sink_get_latency_cb; if (u->mixer_handle) { @@ -420,7 +426,8 @@ int pa__init(pa_core *c, pa_module*m) { } snd_mixer_elem_set_callback(u->mixer_elem, mixer_callback); snd_mixer_elem_set_callback_private(u->mixer_elem, u); - } + } else + u->mixer_fdl = NULL; u->frame_size = frame_size; u->fragment_size = period_size * frame_size; diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 414efda8..10b98f75 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -335,7 +335,7 @@ int pa__init(pa_core *c, pa_module*m) { } period_size = fragsize/frame_size; - u = pa_xmalloc0(sizeof(struct userdata)); + u = pa_xnew(struct userdata, 1); m->userdata = u; u->module = m; @@ -356,6 +356,10 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } + if (ss.channels != map.channels) + /* Seems ALSA didn't like the channel number, so let's fix the channel map */ + pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); + if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) { pa_log(__FILE__": Error opening mixer: %s", snd_strerror(err)); goto fail; @@ -367,8 +371,10 @@ int pa__init(pa_core *c, pa_module*m) { u->mixer_handle = NULL; } - u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map); - assert(u->source); + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) { + pa_log(__FILE__": Failed to create source object"); + goto fail; + } u->source->userdata = u; u->source->get_latency = source_get_latency_cb; @@ -413,7 +419,8 @@ int pa__init(pa_core *c, pa_module*m) { } snd_mixer_elem_set_callback(u->mixer_elem, mixer_callback); snd_mixer_elem_set_callback_private(u->mixer_elem, u); - } + } else + u->mixer_fdl = NULL; u->frame_size = frame_size; u->fragment_size = period_size * frame_size; -- cgit From 64fa5b882f53b24d78fd3c84191150000e79b391 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 May 2006 22:48:17 +0000 Subject: * alsa-sink: if "PCM" is not found as mixer track name, fallback to "Master" * alsa-source: if "Capture" is not found as mixer track name, fallback to "Mic" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@993 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 23 +++++++++++++++++------ src/modules/alsa-util.h | 2 +- src/modules/module-alsa-sink.c | 2 +- src/modules/module-alsa-source.c | 2 +- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 22e623f6..be0fc064 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -337,18 +337,29 @@ int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { return 0; } -snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name) { +snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback) { snd_mixer_elem_t *elem; - snd_mixer_selem_id_t *sid; + snd_mixer_selem_id_t *sid = NULL; snd_mixer_selem_id_alloca(&sid); - assert(mixer && name); + assert(mixer); + assert(name); snd_mixer_selem_id_set_name(sid, name); - elem = snd_mixer_find_selem(mixer, sid); - if (!elem) - pa_log_warn(__FILE__": Cannot find mixer control %s", snd_mixer_selem_id_get_name(sid)); + if (!(elem = snd_mixer_find_selem(mixer, sid))) { + pa_log_warn(__FILE__": Cannot find mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); + + if (fallback) { + snd_mixer_selem_id_set_name(sid, fallback); + + if (!(elem = snd_mixer_find_selem(mixer, sid))) + pa_log_warn(__FILE__": Cannot find fallback mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); + } + } + + if (elem) + pa_log_warn(__FILE__": Using mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); return elem; } diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h index 4bee8625..83d1481f 100644 --- a/src/modules/alsa-util.h +++ b/src/modules/alsa-util.h @@ -40,6 +40,6 @@ int pa_alsa_fdlist_init_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_han int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size); int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev); -snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name); +snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback); #endif diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index a0b6dc08..620047b7 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -373,7 +373,7 @@ int pa__init(pa_core *c, pa_module*m) { } if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) || - !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "PCM"))) { + !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "PCM", "Master"))) { snd_mixer_close(u->mixer_handle); u->mixer_handle = NULL; } diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 10b98f75..0999c65f 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -366,7 +366,7 @@ int pa__init(pa_core *c, pa_module*m) { } if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) || - !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture"))) { + !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", "Mic"))) { snd_mixer_close(u->mixer_handle); u->mixer_handle = NULL; } -- cgit From 9f2026da05582c154b2cd833fce8e877fb9d5375 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 May 2006 22:57:41 +0000 Subject: downgrade a log message git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@994 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index be0fc064..99c1cfa3 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -359,7 +359,7 @@ snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const } if (elem) - pa_log_warn(__FILE__": Using mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); + pa_log_info(__FILE__": Using mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); return elem; } -- cgit From 79b6c31f2303e34f016363ced6dad3bc3ff35c54 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 31 May 2006 00:05:38 +0000 Subject: decrease maximum allowed sample frequency for ALSA devices to 5%, since 48000 would otherwise match with 44100 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@995 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 99c1cfa3..5b6d72e7 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -284,7 +284,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p pa_log_info(__FILE__": device doesn't support %u Hz, changed to %u Hz.", ss->rate, r); /* If the sample rate deviates too much, we need to resample */ - if (r < ss->rate*.9 || r > ss->rate*1.1) + if (r < ss->rate*.95 || r > ss->rate*1.05) ss->rate = r; } -- cgit From ac7213d7337bf878dc687c9d0dcbfc545a539ac1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 31 May 2006 15:07:37 +0000 Subject: update TODO git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@996 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/todo b/doc/todo index 19e4f1a9..de23c493 100644 --- a/doc/todo +++ b/doc/todo @@ -28,6 +28,9 @@ Post 0.9.0: - fix clock of the NULL sink - gettextify polypaudio - use send() with MSG_NOSIGNAL instead of write() wherever possible, and than drop that SIGPIPE warning +- drop dependency of libpolyp on libX11, instead use an external mini binary +- "hot" moving of streams between sinks +- check if using prctl(PR_GET_NAME) makes sense in pa_get_binary_name() Long term: - pass meta info for hearing impaired -- cgit From 8ca956892ef71cf93e97c8f94c4c64d979f9a128 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 31 May 2006 19:17:32 +0000 Subject: remove superfluous prefixes from service names git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@997 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-zeroconf-publish.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index bd4a2d97..c07c95f3 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -140,7 +140,7 @@ static int publish_service(struct userdata *u, struct service *s) { s->published = 0; } - snprintf(t, sizeof(t), "Networked Audio Device %s on %s", s->name, pa_get_host_name(hn, sizeof(hn))); + snprintf(t, sizeof(t), "%s on %s", s->name, pa_get_host_name(hn, sizeof(hn))); if (sw_text_record_init(&txt) != SW_OKAY) { pa_log(__FILE__": sw_text_record_init() failed"); @@ -432,7 +432,7 @@ int pa__init(pa_core *c, pa_module*m) { if (publish_autoload(u, autoload) < 0) goto fail; - snprintf(t, sizeof(t), "Networked Audio Server on %s", pa_get_host_name(hn, sizeof(hn))); + snprintf(t, sizeof(t), "%s", pa_get_host_name(hn, sizeof(hn))); if (sw_text_record_init(&txt) != SW_OKAY) { pa_log(__FILE__": sw_text_record_init() failed"); -- cgit From 7a52eab5968ff6974c3585659acadd0c0d04715e Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 1 Jun 2006 13:49:10 +0000 Subject: Try the ltdl mangled name ourselves so that .la files for modules are optional. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@998 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/module.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/polypcore/module.c b/src/polypcore/module.c index b938750c..47a878fb 100644 --- a/src/polypcore/module.c +++ b/src/polypcore/module.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,39 @@ static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED m->time_restart(e, &ntv); } +static inline fnptr load_sym(lt_dlhandle handle, const char *module, const char *symbol) { + char *buffer, *ch; + size_t buflen; + fnptr res; + + res = lt_dlsym_fn(handle, symbol); + if (res) + return res; + + /* As the .la files might have been cleansed from the system, we should + * try with the ltdl prefix as well. */ + + buflen = strlen(symbol) + strlen(module) + strlen("_LTX_") + 1; + buffer = pa_xmalloc(buflen); + assert(buffer); + + strcpy(buffer, module); + + for (ch = buffer;*ch != '\0';ch++) { + if (!isalnum(*ch)) + *ch = '_'; + } + + strcat(buffer, "_LTX_"); + strcat(buffer, symbol); + + res = lt_dlsym_fn(handle, buffer); + + pa_xfree(buffer); + + return res; +} + pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { pa_module *m = NULL; int r; @@ -82,12 +116,12 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { goto fail; } - if (!(m->init = (int (*)(pa_core *_c, pa_module*_m)) lt_dlsym_fn(m->dl, PA_SYMBOL_INIT))) { + if (!(m->init = (int (*)(pa_core *_c, pa_module*_m)) load_sym(m->dl, name, PA_SYMBOL_INIT))) { pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.", name); goto fail; } - if (!(m->done = (void (*)(pa_core *_c, pa_module*_m)) lt_dlsym_fn(m->dl, PA_SYMBOL_DONE))) { + if (!(m->done = (void (*)(pa_core *_c, pa_module*_m)) load_sym(m->dl, name, PA_SYMBOL_DONE))) { pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_DONE"\" not found.", name); goto fail; } -- cgit From 02bfa3c4492e7a9469948ba7d7c58e033b35dbe2 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 1 Jun 2006 13:49:17 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@999 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/todo b/doc/todo index de23c493..0569924c 100644 --- a/doc/todo +++ b/doc/todo @@ -12,6 +12,8 @@ Post 0.9.0: - rtp module ported to Win32 (sendmsg/recvmsg emulation) - CODECs to reduce bandwidth usage (plug-in based) - Remove symdef files and use macros (like most other projects) +- Use own name mangling scheme instead of ltdl's, which will eliminate the + need for .la files or extra trickery. - use software volume when hardware doesn't support all channels (alsa done) - paplay needs to set a channel map. our default is only correct for AIFF. (we need help from libsndfile for this) -- cgit From 7b961bd982dfcefecc25901d253e985c6a6eeea0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 2 Jun 2006 15:30:04 +0000 Subject: Add new configure options to disable/enable specific modules at configure time. Original patch by ed@catmur.co.uk. (Closes #16) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1000 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 114 ++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 90 insertions(+), 24 deletions(-) diff --git a/configure.ac b/configure.ac index 7859d33f..cf4bb0eb 100644 --- a/configure.ac +++ b/configure.ac @@ -107,13 +107,17 @@ AC_ARG_ENABLE(lynx, yes) lynx=yes ;; no) lynx=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-lynx) ;; -esac],[lynx=yes]) +esac],[lynx=auto]) -if test x$lynx = xyes ; then +if test x$lynx != xno ; then AC_CHECK_PROG(have_lynx, lynx, yes, no) if test x$have_lynx = xno ; then - AC_MSG_WARN([*** lynx not found, plain text README will not be built ***]) + if test x$lynx = xyes ; then + AC_MSG_ERROR([*** lynx not found]) + else + AC_MSG_WARN([*** lynx not found, plain text README will not be built ***]) + fi fi fi @@ -291,8 +295,14 @@ AC_ARG_WITH( AC_HELP_STRING([--without-caps],[Omit support for POSIX capabilities.])) if test "x${with_caps}" != "xno"; then - AC_SEARCH_LIBS([cap_init], [cap]) - AC_CHECK_HEADERS([sys/capability.h]) + AC_SEARCH_LIBS([cap_init], [cap], [], [ + if test "x${with_caps}" = "xyes" ; then + AC_MSG_ERROR([*** POSIX caps libraries not found]) + fi]) + AC_CHECK_HEADERS([sys/capability.h], [], [ + if test "x${with_caps}" = "xyes" ; then + AC_MSG_ERROR([*** POSIX caps headers not found]) + fi]) fi #### pkg-config #### @@ -321,20 +331,30 @@ AC_SUBST(LIBSNDFILE_LIBS) #### OSS support (optional) #### -AC_CHECK_HEADERS([sys/soundcard.h], [ -HAVE_OSS=1 -AC_DEFINE([HAVE_OSS], 1, [Have OSS?]) -], [HAVE_OSS=0]) +AC_ARG_ENABLE([oss], + AC_HELP_STRING([--disable-oss], [Disable optional OSS support]), + [case "${enableval}" in yes) oss=yes ;; no) oss=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-oss) ;; esac],[oss=auto]) +if test "x${oss}" != xno ; then + AC_CHECK_HEADERS([sys/soundcard.h], [ + HAVE_OSS=1 + AC_DEFINE([HAVE_OSS], 1, [Have OSS?]) + ], [HAVE_OSS=0 ; if test "x$oss" = xyes ; then AC_MSG_ERROR([*** OSS support not found]) ; fi]) +else HAVE_OSS=0; fi AC_SUBST(HAVE_OSS) AM_CONDITIONAL([HAVE_OSS], [test "x$HAVE_OSS" = x1]) #### ALSA support (optional) #### -PKG_CHECK_MODULES(ASOUNDLIB, [ alsa >= 1.0.0 ], [ -HAVE_ALSA=1 -AC_DEFINE([HAVE_ALSA], 1, [Have ALSA?]) -], [HAVE_ALSA=0]) +AC_ARG_ENABLE([alsa], + AC_HELP_STRING([--disable-alsa], [Disable optional ALSA support]), + [case "${enableval}" in yes) alsa=yes ;; no) alsa=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-alsa) ;; esac],[alsa=auto]) +if test "x${alsa}" != xno ; then + PKG_CHECK_MODULES(ASOUNDLIB, [ alsa >= 1.0.0 ], [ + HAVE_ALSA=1 + AC_DEFINE([HAVE_ALSA], 1, [Have ALSA?]) + ], [HAVE_ALSA=0 ; if test "x$alsa" = xyes ; then AC_MSG_ERROR([*** ALSA support not found]) ; fi]) +else HAVE_ALSA=0 ; fi AC_SUBST(ASOUNDLIB_CFLAGS) AC_SUBST(ASOUNDLIB_LIBS) AC_SUBST(HAVE_ALSA) @@ -342,16 +362,26 @@ AM_CONDITIONAL([HAVE_ALSA], [test "x$HAVE_ALSA" = x1]) #### Solaris audio support (optional) #### -AC_CHECK_HEADERS([sys/audio.h], [ -HAVE_SOLARIS=1 -AC_DEFINE([HAVE_SOLARIS], 1, [Have Solaris audio?]) -], [HAVE_SOLARIS=0]) +AC_ARG_ENABLE([solaris], + AC_HELP_STRING([--disable-solaris], [Disable optional Solaris audio support]), + [case "${enableval}" in yes) solaris=yes ;; no) solaris=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-solaris) ;; esac],[solaris=auto]) +if test "x${solaris}" != xno ; then + AC_CHECK_HEADERS([sys/audio.h], [ + HAVE_SOLARIS=1 + AC_DEFINE([HAVE_SOLARIS], 1, [Have Solaris audio?]) + ], [HAVE_SOLARIS=0 ; if test "x$solaris" = xyes ; then AC_MSG_ERROR([*** Solaris audio support not found]) ; fi]) +else HAVE_SOLARIS=0 ; fi AC_SUBST(HAVE_SOLARIS) AM_CONDITIONAL([HAVE_SOLARIS], [test "x$HAVE_SOLARIS" = x1]) #### GLib 2 support (optional) #### -PKG_CHECK_MODULES(GLIB20, [ glib-2.0 >= 2.4.0 ], HAVE_GLIB20=1, HAVE_GLIB20=0) +AC_ARG_ENABLE([glib2], + AC_HELP_STRING([--disable-glib2], [Disable optional GLib 2 support]), + [case "${enableval}" in yes) glib2=yes ;; no) glib2=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-glib2) ;; esac],[glib2=auto]) +if test "x${glib2}" != xno ; then + PKG_CHECK_MODULES(GLIB20, [ glib-2.0 >= 2.4.0 ], HAVE_GLIB20=1, [HAVE_GLIB20=0 ; if test "x$glib2" = xyes ; then AC_MSG_ERROR([*** GLib 2 support not found]) ; fi]) +else HAVE_GLIB20=0 ; fi AC_SUBST(GLIB20_CFLAGS) AC_SUBST(GLIB20_LIBS) AC_SUBST(HAVE_GLIB20) @@ -359,7 +389,12 @@ AM_CONDITIONAL([HAVE_GLIB20], [test "x$HAVE_GLIB20" = x1]) #### GLib 1 support (optional) #### -PKG_CHECK_MODULES(GLIB12, [ glib >= 1.2.0 ], HAVE_GLIB12=1, HAVE_GLIB12=0) +AC_ARG_ENABLE([glib1], + AC_HELP_STRING([--disable-glib1], [Disable optional GLib 1 support]), + [case "${enableval}" in yes) glib1=yes ;; no) glib1=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-glib1) ;; esac],[glib1=auto]) +if test "x${glib1}" != xno ; then + PKG_CHECK_MODULES(GLIB12, [ glib >= 1.2.0 ], HAVE_GLIB12=1, [HAVE_GLIB12=0 ; if test "x$glib1" = xyes ; then AC_MSG_ERROR([*** GLib 1 support not found]) ; fi]) +else HAVE_GLIB12=0 ; fi AC_SUBST(GLIB12_CFLAGS) AC_SUBST(GLIB12_LIBS) AC_SUBST(HAVE_GLIB12) @@ -367,7 +402,12 @@ AM_CONDITIONAL([HAVE_GLIB12], [test "x$HAVE_GLIB12" = x1]) #### Howl support (optional) #### -PKG_CHECK_MODULES(HOWL, [ howl >= 0.9.8 ], HAVE_HOWL=1, HAVE_HOWL=0) +AC_ARG_ENABLE([howl], + AC_HELP_STRING([--disable-howl], [Disable optional Howl support]), + [case "${enableval}" in yes) howl=yes ;; no) howl=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-howl) ;; esac],[howl=auto]) +if test "x${howl}" != xno ; then + PKG_CHECK_MODULES(HOWL, [ howl >= 0.9.8 ], HAVE_HOWL=1, PKG_CHECK_MODULES(HOWL, [ avahi-compat-howl >= 0.9.8 ], HAVE_HOWL=1, [HAVE_HOWL=0 ; if test "x$howl" = xyes ; then AC_MSG_ERROR([*** Howl support not found]) ; fi])) +else HAVE_HOWL=0 ; fi AC_SUBST(HOWL_CFLAGS) AC_SUBST(HOWL_LIBS) AC_SUBST(HAVE_HOWL) @@ -381,7 +421,12 @@ AC_SUBST(LIBOIL_LIBS) ### JACK (optional) #### -PKG_CHECK_MODULES(JACK, [ jack >= 0.100 ], HAVE_JACK=1, HAVE_JACK=0) +AC_ARG_ENABLE([jack], + AC_HELP_STRING([--disable-jack], [Disable optional JACK support]), + [case "${enableval}" in yes) jack=yes ;; no) jack=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-jack) ;; esac],[jack=auto]) +if test "x${jack}" != xno ; then + PKG_CHECK_MODULES(JACK, [ jack >= 0.100 ], HAVE_JACK=1, [HAVE_JACK=0 ; if test "x$jack" = xyes ; then AC_MSG_ERROR([*** JACK support not found]) ; fi]) +else HAVE_JACK=0 ; fi AC_SUBST(JACK_CFLAGS) AC_SUBST(JACK_LIBS) AC_SUBST(HAVE_JACK) @@ -389,7 +434,12 @@ AM_CONDITIONAL([HAVE_JACK], [test "x$HAVE_JACK" = x1]) #### Async DNS support (optional) #### -PKG_CHECK_MODULES(LIBASYNCNS, [ libasyncns >= 0.1 ], HAVE_LIBASYNCNS=1, HAVE_LIBASYNCNS=0) +AC_ARG_ENABLE([asyncns], + AC_HELP_STRING([--disable-asyncns], [Disable optional Async DNS support]), + [case "${enableval}" in yes) asyncns=yes ;; no) asyncns=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-asyncns) ;; esac],[asyncns=auto]) +if test "x${asyncns}" != xno ; then + PKG_CHECK_MODULES(LIBASYNCNS, [ libasyncns >= 0.1 ], HAVE_LIBASYNCNS=1, [HAVE_LIBASYNCNS=0 ; if test "x$asyncns" = xyes ; then AC_MSG_ERROR([*** Async DNS support not found]) ; fi]) +else HAVE_LIBASYNCNS=0 ; fi AC_SUBST(LIBASYNCNS_CFLAGS) AC_SUBST(LIBASYNCNS_LIBS) AC_SUBST(HAVE_LIBASYNCNS) @@ -401,12 +451,28 @@ fi #### TCP wrappers (optional) #### -ACX_LIBWRAP +AC_ARG_ENABLE([tcpwrap], + AC_HELP_STRING([--disable-tcpwrap], [Disable optional TCP wrappers support]), + [case "${enableval}" in yes) tcpwrap=yes ;; no) tcpwrap=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-tcpwrap) ;; esac],[tcpwrap=auto]) +if test "x${tcpwrap}" != xno ; then + ACX_LIBWRAP + if test "x${LIBWRAP_LIBS}" = x && test "x$tcpwrap" = xyes ; then + AC_MSG_ERROR([*** TCP wrappers support not found]) + fi +else LIBWRAP_LIBS= ; fi AC_SUBST(LIBWRAP_LIBS) #### LIRC support (optional) #### -ACX_LIRC +AC_ARG_ENABLE([lirc], + AC_HELP_STRING([--disable-lirc], [Disable optional LIRC support]), + [case "${enableval}" in yes) lirc=yes ;; no) lirc=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-lirc) ;; esac],[lirc=auto]) +if test "x${lirc}" != xno ; then + ACX_LIRC + if test "x${HAVE_LIRC}" = x0 && test "x$lirc" = xyes ; then + AC_MSG_ERROR([*** LIRC support not found]) + fi +else HAVE_LIRC=0 ; fi AC_SUBST(LIRC_CFLAGS) AC_SUBST(LIRC_LIBS) AM_CONDITIONAL([HAVE_LIRC], [test "x$HAVE_LIRC" = x1]) -- cgit From e09233664e9db152567c56ff047899c951c769fd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 2 Jun 2006 19:28:47 +0000 Subject: bump version and soname git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1001 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index cf4bb0eb..c389dd23 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ AC_PREREQ(2.57) m4_define(PA_MAJOR, [0]) m4_define(PA_MINOR, [9]) -m4_define(PA_MICRO, [0]) +m4_define(PA_MICRO, [1]) AC_INIT([polypaudio], PA_MAJOR.PA_MINOR.PA_MICRO,[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([src/daemon/main.c]) @@ -37,7 +37,7 @@ AC_SUBST(PA_API_VERSION, 9) AC_SUBST(PA_PROTOCOL_VERSION, 9) AC_SUBST(LIBPOLYP_VERSION_INFO, [0:0:0]) -AC_SUBST(LIBPOLYPCORE_VERSION_INFO, [0:0:0]) +AC_SUBST(LIBPOLYPCORE_VERSION_INFO, [0:1:0]) AC_SUBST(LIBPOLYP_SIMPLE_VERSION_INFO, [0:0:0]) AC_SUBST(LIBPOLYP_BROWSE_VERSION_INFO, [0:0:0]) AC_SUBST(LIBPOLYP_MAINLOOP_GLIB_VERSION_INFO, [0:0:0]) -- cgit From 8b0e6f6f66a6991ce42aa0ad743ac47dcf1e6f42 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 2 Jun 2006 19:49:05 +0000 Subject: update docs for 0.9.1 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1002 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/README.html.in b/doc/README.html.in index f02c657d..f35b2da9 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -43,6 +43,15 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

      News

      +
      Fri Jun 2 2006:

      Version 0.9.1 +released; changes include: load modules even when libtool .la +files are missing; generate better ALSA device names from +module-detect; if an ALSA device doesn't support the +requested number of channels or the frequency, accept what ALSA +suggests instead; amd64 portability; drop .sh suffix of +esdcompat.sh; build system fixes; No API or ABI changes were made

      +
      Fri May 26 2006:

      Version 0.9.0 released; changes include: new module module-volume-restore; @@ -330,7 +339,7 @@ compilation and make install (as root) for installation of

      Please report bugs to our Trac ticket system.


      -
      Lennart Poettering <@PACKAGE_BUGREPORT@>, May 2006
      +
      Lennart Poettering <@PACKAGE_BUGREPORT@>, June 2006
      $Id$
      -- cgit From 441362a50b8c7e190b98066198555832a95ef064 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 2 Jun 2006 21:06:38 +0000 Subject: fix ugly access-after-free bug when doing asyncronous NS lookups git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1004 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/socket-client.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/polypcore/socket-client.c b/src/polypcore/socket-client.c index fd840ab5..efb6de9a 100644 --- a/src/polypcore/socket-client.c +++ b/src/polypcore/socket-client.c @@ -376,16 +376,18 @@ static void asyncns_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED asyncns_freeaddrinfo(res); - goto finish; - + m->io_free(c->asyncns_io_event); + c->asyncns_io_event = NULL; + return; + fail: + m->io_free(c->asyncns_io_event); + c->asyncns_io_event = NULL; + errno = EHOSTUNREACH; do_call(c); + return; -finish: - - m->io_free(c->asyncns_io_event); - c->asyncns_io_event = NULL; } #endif -- cgit From 16a275a9fddcf9216941cae4a002f0902ae5df88 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 2 Jun 2006 22:56:20 +0000 Subject: actually build cpulimit support if SIGXCPU is available git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1005 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 5 ++++- src/daemon/cpulimit.c | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index c389dd23..7a2fdbf0 100644 --- a/configure.ac +++ b/configure.ac @@ -204,7 +204,10 @@ AC_TYPE_OFF_T AC_TYPE_SIGNAL AC_TYPE_UID_T -AC_CHECK_DEFINE([SIGXCPU], [signal.h], [HAVE_SIGXCPU=1], [HAVE_SIGXCPU=0]) +AC_CHECK_DEFINE([SIGXCPU], [signal.h], [ +HAVE_SIGXCPU=1 +AC_DEFINE([HAVE_SIGXCPU], 1, [Have SIGXCPU?]) +], [HAVE_SIGXCPU=0]) AM_CONDITIONAL(HAVE_SIGXCPU, test "x$HAVE_SIGXCPU" = "x1") # Solaris lacks this diff --git a/src/daemon/cpulimit.c b/src/daemon/cpulimit.c index 2cc37be6..d537b9db 100644 --- a/src/daemon/cpulimit.c +++ b/src/daemon/cpulimit.c @@ -26,6 +26,7 @@ #include #include +#include #include #include "cpulimit.h" @@ -62,8 +63,8 @@ /* Check every 10s */ #define CPUTIME_INTERVAL_SOFT (10) -/* Recheck after 2s */ -#define CPUTIME_INTERVAL_HARD (2) +/* Recheck after 5s */ +#define CPUTIME_INTERVAL_HARD (5) /* Time of the last CPU load check */ static time_t last_time = 0; @@ -155,7 +156,7 @@ static void signal_handler(int sig) { } /* Callback for IO events on the FIFO */ -static void callback(pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags f, void *userdata) { +static void callback(pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata) { char c; assert(m && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == the_pipe[0]); read(the_pipe[0], &c, sizeof(c)); -- cgit From 2fa08ba9aac87f75751bc57bf153a2905699584d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 3 Jun 2006 00:59:24 +0000 Subject: fix pa_xstrndup() implementation to not access potentially uninitialized memory git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1006 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/xmalloc.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/polyp/xmalloc.c b/src/polyp/xmalloc.c index ffc7f7c8..7f71a5ed 100644 --- a/src/polyp/xmalloc.c +++ b/src/polyp/xmalloc.c @@ -106,19 +106,18 @@ char *pa_xstrdup(const char *s) { } char *pa_xstrndup(const char *s, size_t l) { + char *e, *r; + if (!s) return NULL; - else { - char *r; - size_t t = strlen(s); - if (t > l) - t = l; - - r = pa_xmemdup(s, t+1); - r[t] = 0; - return r; - } + if ((e = memchr(s, 0, l))) + return pa_xmemdup(s, e-s+1); + + r = pa_xmalloc(l+1); + memcpy(r, s, l); + r[l] = 0; + return r; } void pa_xfree(void *p) { -- cgit From d8dafa0d5f4f52ad39f586572994eaf6d8005846 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 3 Jun 2006 01:15:21 +0000 Subject: rework ioline EOF handling to actually work properly git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1007 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/ioline.c | 87 +++++++++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 32 deletions(-) diff --git a/src/polypcore/ioline.c b/src/polypcore/ioline.c index 6a2ef338..b908f967 100644 --- a/src/polypcore/ioline.c +++ b/src/polypcore/ioline.c @@ -65,7 +65,7 @@ pa_ioline* pa_ioline_new(pa_iochannel *io) { pa_ioline *l; assert(io); - l = pa_xmalloc(sizeof(pa_ioline)); + l = pa_xnew(pa_ioline, 1); l->io = io; l->dead = 0; @@ -106,23 +106,27 @@ static void ioline_free(pa_ioline *l) { } void pa_ioline_unref(pa_ioline *l) { - assert(l && l->ref >= 1); + assert(l); + assert(l->ref >= 1); if ((--l->ref) <= 0) ioline_free(l); } pa_ioline* pa_ioline_ref(pa_ioline *l) { - assert(l && l->ref >= 1); + assert(l); + assert(l->ref >= 1); l->ref++; return l; } void pa_ioline_close(pa_ioline *l) { - assert(l && l->ref >= 1); + assert(l); + assert(l->ref >= 1); l->dead = 1; + if (l->io) { pa_iochannel_free(l->io); l->io = NULL; @@ -132,13 +136,20 @@ void pa_ioline_close(pa_ioline *l) { l->mainloop->defer_free(l->defer_event); l->defer_event = NULL; } + + if (l->callback) + l->callback = NULL; } void pa_ioline_puts(pa_ioline *l, const char *c) { size_t len; - assert(l && c && l->ref >= 1 && !l->dead); + + assert(l); + assert(l->ref >= 1); + assert(c); - pa_ioline_ref(l); + if (l->dead) + return; len = strlen(c); if (len > BUFFER_LIMIT - l->wbuf_valid_length) @@ -173,25 +184,37 @@ void pa_ioline_puts(pa_ioline *l, const char *c) { l->mainloop->defer_enable(l->defer_event, 1); } - - pa_ioline_unref(l); } void pa_ioline_set_callback(pa_ioline*l, void (*callback)(pa_ioline*io, const char *s, void *userdata), void *userdata) { - assert(l && l->ref >= 1); + assert(l); + assert(l->ref >= 1); + l->callback = callback; l->userdata = userdata; } -static void failure(pa_ioline *l) { - assert(l && l->ref >= 1 && !l->dead); +static void failure(pa_ioline *l, int process_leftover) { + assert(l); + assert(l->ref >= 1); + assert(!l->dead); - pa_ioline_close(l); + if (process_leftover && l->rbuf_valid_length > 0) { + /* Pass the last missing bit to the client */ + + if (l->callback) { + char *p = pa_xstrndup(l->rbuf+l->rbuf_index, l->rbuf_valid_length); + l->callback(l, p, l->userdata); + pa_xfree(p); + } + } if (l->callback) { l->callback(l, NULL, l->userdata); l->callback = NULL; } + + pa_ioline_close(l); } static void scan_for_lines(pa_ioline *l, size_t skip) { @@ -267,17 +290,13 @@ static int do_read(pa_ioline *l) { assert(len >= READ_SIZE); /* Read some data */ - r = pa_iochannel_read(l->io, l->rbuf+l->rbuf_index+l->rbuf_valid_length, len); - if (r == 0) { - /* Got an EOF, so fake an exit command. */ - l->rbuf_index = 0; - snprintf (l->rbuf, l->rbuf_length, "exit\n"); - r = 5; - pa_ioline_puts(l, "\nExiting.\n"); - do_write(l); - } else if (r < 0) { - pa_log(__FILE__": read(): %s", pa_cstrerror(errno)); - failure(l); + if ((r = pa_iochannel_read(l->io, l->rbuf+l->rbuf_index+l->rbuf_valid_length, len)) <= 0) { + if (r < 0) { + pa_log(__FILE__": read(): %s", pa_cstrerror(errno)); + failure(l, 0); + } else + failure(l, 1); + return -1; } @@ -299,7 +318,7 @@ static int do_write(pa_ioline *l) { if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0) { pa_log(__FILE__": write(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); - failure(l); + failure(l, 0); return -1; } @@ -316,20 +335,21 @@ static int do_write(pa_ioline *l) { /* Try to flush read/write data */ static void do_work(pa_ioline *l) { - assert(l && l->ref >= 1); + assert(l); + assert(l->ref >= 1); pa_ioline_ref(l); l->mainloop->defer_enable(l->defer_event, 0); if (!l->dead) - do_write(l); + do_read(l); if (!l->dead) - do_read(l); + do_write(l); if (l->defer_close && !l->wbuf_valid_length) - failure(l); + failure(l, 1); pa_ioline_unref(l); } @@ -350,22 +370,25 @@ static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata) void pa_ioline_defer_close(pa_ioline *l) { assert(l); - + assert(l->ref >= 1); + l->defer_close = 1; if (!l->wbuf_valid_length) l->mainloop->defer_enable(l->defer_event, 1); } -void pa_ioline_printf(pa_ioline *s, const char *format, ...) { +void pa_ioline_printf(pa_ioline *l, const char *format, ...) { char *t; va_list ap; - + assert(l); + assert(l->ref >= 1); + va_start(ap, format); t = pa_vsprintf_malloc(format, ap); va_end(ap); - pa_ioline_puts(s, t); + pa_ioline_puts(l, t); pa_xfree(t); } -- cgit From 75ac45b0de4cb03fa6eeea14081824c3cb6c8f67 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 11 Jun 2006 01:34:12 +0000 Subject: Add all the preopen libs to the polypaudio binary's dependency list as they aren't automatically detected. (Closes #17) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1008 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Makefile.am b/src/Makefile.am index de0c18df..2e68ed94 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -108,6 +108,8 @@ polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) polypaudio_CPPFLAGS = $(AM_CPPFLAGS) polypaudio_LDADD = $(AM_LDADD) libpolypcore.la $(LIBLTDL) \ $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) $(LIBOIL_LIBS) +# This is needed because automake doesn't properly expand the foreach below +polypaudio_DEPENDENCIES = libpolypcore.la $(PREOPEN_LIBS) if PREOPEN_MODS PREOPEN_LIBS = $(PREOPEN_MODS) -- cgit From 15a0b28ee64760d1199a9a28d627dc9780250bb9 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 12 Jun 2006 12:19:24 +0000 Subject: Properly escape the m4 macros and make the code a bit more readable. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1009 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 244 ++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 207 insertions(+), 37 deletions(-) diff --git a/configure.ac b/configure.ac index 7a2fdbf0..a6a8aa2c 100644 --- a/configure.ac +++ b/configure.ac @@ -336,13 +336,31 @@ AC_SUBST(LIBSNDFILE_LIBS) AC_ARG_ENABLE([oss], AC_HELP_STRING([--disable-oss], [Disable optional OSS support]), - [case "${enableval}" in yes) oss=yes ;; no) oss=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-oss) ;; esac],[oss=auto]) + [ + case "${enableval}" in + yes) oss=yes ;; + no) oss=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-oss) ;; + esac + ], + [oss=auto]) + if test "x${oss}" != xno ; then - AC_CHECK_HEADERS([sys/soundcard.h], [ - HAVE_OSS=1 - AC_DEFINE([HAVE_OSS], 1, [Have OSS?]) - ], [HAVE_OSS=0 ; if test "x$oss" = xyes ; then AC_MSG_ERROR([*** OSS support not found]) ; fi]) -else HAVE_OSS=0; fi + AC_CHECK_HEADERS([sys/soundcard.h], + [ + HAVE_OSS=1 + AC_DEFINE([HAVE_OSS], 1, [Have OSS?]) + ], + [ + HAVE_OSS=0 + if test "x$oss" = xyes ; then + AC_MSG_ERROR([*** OSS support not found]) + fi + ]) +else + HAVE_OSS=0 +fi + AC_SUBST(HAVE_OSS) AM_CONDITIONAL([HAVE_OSS], [test "x$HAVE_OSS" = x1]) @@ -351,13 +369,31 @@ AM_CONDITIONAL([HAVE_OSS], [test "x$HAVE_OSS" = x1]) AC_ARG_ENABLE([alsa], AC_HELP_STRING([--disable-alsa], [Disable optional ALSA support]), - [case "${enableval}" in yes) alsa=yes ;; no) alsa=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-alsa) ;; esac],[alsa=auto]) + [ + case "${enableval}" in + yes) alsa=yes ;; + no) alsa=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-alsa) ;; + esac + ], + [alsa=auto]) + if test "x${alsa}" != xno ; then - PKG_CHECK_MODULES(ASOUNDLIB, [ alsa >= 1.0.0 ], [ - HAVE_ALSA=1 - AC_DEFINE([HAVE_ALSA], 1, [Have ALSA?]) - ], [HAVE_ALSA=0 ; if test "x$alsa" = xyes ; then AC_MSG_ERROR([*** ALSA support not found]) ; fi]) -else HAVE_ALSA=0 ; fi + PKG_CHECK_MODULES(ASOUNDLIB, [ alsa >= 1.0.0 ], + [ + HAVE_ALSA=1 + AC_DEFINE([HAVE_ALSA], 1, [Have ALSA?]) + ], + [ + HAVE_ALSA=0 + if test "x$alsa" = xyes ; then + AC_MSG_ERROR([*** ALSA support not found]) + fi + ]) +else + HAVE_ALSA=0 +fi + AC_SUBST(ASOUNDLIB_CFLAGS) AC_SUBST(ASOUNDLIB_LIBS) AC_SUBST(HAVE_ALSA) @@ -367,13 +403,31 @@ AM_CONDITIONAL([HAVE_ALSA], [test "x$HAVE_ALSA" = x1]) AC_ARG_ENABLE([solaris], AC_HELP_STRING([--disable-solaris], [Disable optional Solaris audio support]), - [case "${enableval}" in yes) solaris=yes ;; no) solaris=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-solaris) ;; esac],[solaris=auto]) + [ + case "${enableval}" in + yes) solaris=yes ;; + no) solaris=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-solaris) ;; + esac + ], + [solaris=auto]) + if test "x${solaris}" != xno ; then - AC_CHECK_HEADERS([sys/audio.h], [ - HAVE_SOLARIS=1 - AC_DEFINE([HAVE_SOLARIS], 1, [Have Solaris audio?]) - ], [HAVE_SOLARIS=0 ; if test "x$solaris" = xyes ; then AC_MSG_ERROR([*** Solaris audio support not found]) ; fi]) -else HAVE_SOLARIS=0 ; fi + AC_CHECK_HEADERS([sys/audio.h], + [ + HAVE_SOLARIS=1 + AC_DEFINE([HAVE_SOLARIS], 1, [Have Solaris audio?]) + ], + [ + HAVE_SOLARIS=0 + if test "x$solaris" = xyes ; then + AC_MSG_ERROR([*** Solaris audio support not found]) + fi + ]) +else + HAVE_SOLARIS=0 +fi + AC_SUBST(HAVE_SOLARIS) AM_CONDITIONAL([HAVE_SOLARIS], [test "x$HAVE_SOLARIS" = x1]) @@ -381,10 +435,28 @@ AM_CONDITIONAL([HAVE_SOLARIS], [test "x$HAVE_SOLARIS" = x1]) AC_ARG_ENABLE([glib2], AC_HELP_STRING([--disable-glib2], [Disable optional GLib 2 support]), - [case "${enableval}" in yes) glib2=yes ;; no) glib2=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-glib2) ;; esac],[glib2=auto]) + [ + case "${enableval}" in + yes) glib2=yes ;; + no) glib2=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-glib2) ;; + esac + ], + [glib2=auto]) + if test "x${glib2}" != xno ; then - PKG_CHECK_MODULES(GLIB20, [ glib-2.0 >= 2.4.0 ], HAVE_GLIB20=1, [HAVE_GLIB20=0 ; if test "x$glib2" = xyes ; then AC_MSG_ERROR([*** GLib 2 support not found]) ; fi]) -else HAVE_GLIB20=0 ; fi + PKG_CHECK_MODULES(GLIB20, [ glib-2.0 >= 2.4.0 ], + HAVE_GLIB20=1, + [ + HAVE_GLIB20=0 + if test "x$glib2" = xyes ; then + AC_MSG_ERROR([*** GLib 2 support not found]) + fi + ]) +else + HAVE_GLIB20=0 +fi + AC_SUBST(GLIB20_CFLAGS) AC_SUBST(GLIB20_LIBS) AC_SUBST(HAVE_GLIB20) @@ -394,10 +466,28 @@ AM_CONDITIONAL([HAVE_GLIB20], [test "x$HAVE_GLIB20" = x1]) AC_ARG_ENABLE([glib1], AC_HELP_STRING([--disable-glib1], [Disable optional GLib 1 support]), - [case "${enableval}" in yes) glib1=yes ;; no) glib1=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-glib1) ;; esac],[glib1=auto]) + [ + case "${enableval}" in + yes) glib1=yes ;; + no) glib1=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-glib1) ;; + esac + ], + [glib1=auto]) + if test "x${glib1}" != xno ; then - PKG_CHECK_MODULES(GLIB12, [ glib >= 1.2.0 ], HAVE_GLIB12=1, [HAVE_GLIB12=0 ; if test "x$glib1" = xyes ; then AC_MSG_ERROR([*** GLib 1 support not found]) ; fi]) -else HAVE_GLIB12=0 ; fi + PKG_CHECK_MODULES(GLIB12, [ glib >= 1.2.0 ], + HAVE_GLIB12=1, + [ + HAVE_GLIB12=0 + if test "x$glib1" = xyes ; then + AC_MSG_ERROR([*** GLib 1 support not found]) + fi + ]) +else + HAVE_GLIB12=0 +fi + AC_SUBST(GLIB12_CFLAGS) AC_SUBST(GLIB12_LIBS) AC_SUBST(HAVE_GLIB12) @@ -407,10 +497,32 @@ AM_CONDITIONAL([HAVE_GLIB12], [test "x$HAVE_GLIB12" = x1]) AC_ARG_ENABLE([howl], AC_HELP_STRING([--disable-howl], [Disable optional Howl support]), - [case "${enableval}" in yes) howl=yes ;; no) howl=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-howl) ;; esac],[howl=auto]) + [ + case "${enableval}" in + yes) howl=yes ;; + no) howl=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-howl) ;; + esac + ], + [howl=auto]) + if test "x${howl}" != xno ; then - PKG_CHECK_MODULES(HOWL, [ howl >= 0.9.8 ], HAVE_HOWL=1, PKG_CHECK_MODULES(HOWL, [ avahi-compat-howl >= 0.9.8 ], HAVE_HOWL=1, [HAVE_HOWL=0 ; if test "x$howl" = xyes ; then AC_MSG_ERROR([*** Howl support not found]) ; fi])) -else HAVE_HOWL=0 ; fi + PKG_CHECK_MODULES(HOWL, [ howl >= 0.9.8 ], + HAVE_HOWL=1, + [ + PKG_CHECK_MODULES(HOWL, [ avahi-compat-howl >= 0.9.8 ], + HAVE_HOWL=1, + [ + HAVE_HOWL=0 + if test "x$howl" = xyes ; then + AC_MSG_ERROR([*** Howl support not found]) + fi + ]) + ]) +else + HAVE_HOWL=0 +fi + AC_SUBST(HOWL_CFLAGS) AC_SUBST(HOWL_LIBS) AC_SUBST(HAVE_HOWL) @@ -426,10 +538,28 @@ AC_SUBST(LIBOIL_LIBS) AC_ARG_ENABLE([jack], AC_HELP_STRING([--disable-jack], [Disable optional JACK support]), - [case "${enableval}" in yes) jack=yes ;; no) jack=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-jack) ;; esac],[jack=auto]) + [ + case "${enableval}" in + yes) jack=yes ;; + no) jack=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-jack) ;; + esac + ], + [jack=auto]) + if test "x${jack}" != xno ; then - PKG_CHECK_MODULES(JACK, [ jack >= 0.100 ], HAVE_JACK=1, [HAVE_JACK=0 ; if test "x$jack" = xyes ; then AC_MSG_ERROR([*** JACK support not found]) ; fi]) -else HAVE_JACK=0 ; fi + PKG_CHECK_MODULES(JACK, [ jack >= 0.100 ], + HAVE_JACK=1, + [ + HAVE_JACK=0 + if test "x$jack" = xyes ; then + AC_MSG_ERROR([*** JACK support not found]) + fi + ]) +else + HAVE_JACK=0 +fi + AC_SUBST(JACK_CFLAGS) AC_SUBST(JACK_LIBS) AC_SUBST(HAVE_JACK) @@ -439,10 +569,28 @@ AM_CONDITIONAL([HAVE_JACK], [test "x$HAVE_JACK" = x1]) AC_ARG_ENABLE([asyncns], AC_HELP_STRING([--disable-asyncns], [Disable optional Async DNS support]), - [case "${enableval}" in yes) asyncns=yes ;; no) asyncns=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-asyncns) ;; esac],[asyncns=auto]) + [ + case "${enableval}" in + yes) asyncns=yes ;; + no) asyncns=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-asyncns) ;; + esac + ], + [asyncns=auto]) + if test "x${asyncns}" != xno ; then - PKG_CHECK_MODULES(LIBASYNCNS, [ libasyncns >= 0.1 ], HAVE_LIBASYNCNS=1, [HAVE_LIBASYNCNS=0 ; if test "x$asyncns" = xyes ; then AC_MSG_ERROR([*** Async DNS support not found]) ; fi]) -else HAVE_LIBASYNCNS=0 ; fi + PKG_CHECK_MODULES(LIBASYNCNS, [ libasyncns >= 0.1 ], + HAVE_LIBASYNCNS=1, + [ + HAVE_LIBASYNCNS=0 + if test "x$asyncns" = xyes ; then + AC_MSG_ERROR([*** Async DNS support not found]) + fi + ]) +else + HAVE_LIBASYNCNS=0 +fi + AC_SUBST(LIBASYNCNS_CFLAGS) AC_SUBST(LIBASYNCNS_LIBS) AC_SUBST(HAVE_LIBASYNCNS) @@ -456,26 +604,48 @@ fi AC_ARG_ENABLE([tcpwrap], AC_HELP_STRING([--disable-tcpwrap], [Disable optional TCP wrappers support]), - [case "${enableval}" in yes) tcpwrap=yes ;; no) tcpwrap=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-tcpwrap) ;; esac],[tcpwrap=auto]) + [ + case "${enableval}" in + yes) tcpwrap=yes ;; + no) tcpwrap=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-tcpwrap) ;; + esac + ], + [tcpwrap=auto]) + if test "x${tcpwrap}" != xno ; then ACX_LIBWRAP if test "x${LIBWRAP_LIBS}" = x && test "x$tcpwrap" = xyes ; then AC_MSG_ERROR([*** TCP wrappers support not found]) fi -else LIBWRAP_LIBS= ; fi +else + LIBWRAP_LIBS= +fi + AC_SUBST(LIBWRAP_LIBS) #### LIRC support (optional) #### AC_ARG_ENABLE([lirc], AC_HELP_STRING([--disable-lirc], [Disable optional LIRC support]), - [case "${enableval}" in yes) lirc=yes ;; no) lirc=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-lirc) ;; esac],[lirc=auto]) + [ + case "${enableval}" in + yes) lirc=yes ;; + no) lirc=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-lirc) ;; + esac + ], + [lirc=auto]) + if test "x${lirc}" != xno ; then ACX_LIRC if test "x${HAVE_LIRC}" = x0 && test "x$lirc" = xyes ; then AC_MSG_ERROR([*** LIRC support not found]) fi -else HAVE_LIRC=0 ; fi +else + HAVE_LIRC=0 +fi + AC_SUBST(LIRC_CFLAGS) AC_SUBST(LIRC_LIBS) AM_CONDITIONAL([HAVE_LIRC], [test "x$HAVE_LIRC" = x1]) -- cgit From 7c770e22e453347e0d995f0b3c1c6c8986118a45 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 12 Jun 2006 12:52:37 +0000 Subject: Also look in winsock2.h for INADDR_NONE. (solves #18) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1010 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index a6a8aa2c..34ba78c6 100644 --- a/configure.ac +++ b/configure.ac @@ -212,7 +212,8 @@ AM_CONDITIONAL(HAVE_SIGXCPU, test "x$HAVE_SIGXCPU" = "x1") # Solaris lacks this AC_CHECK_DEFINE([INADDR_NONE], [netinet/in.h], [], - [AC_DEFINE([INADDR_NONE], [0xffffffff], [Define INADDR_NONE if not found in ])]) + [AC_CHECK_DEFINE([INADDR_NONE], [winsock2.h], [], + [AC_DEFINE([INADDR_NONE], [0xffffffff], [Define INADDR_NONE if not found in ])])]) #### Check for libs #### -- cgit From c32176b0ad0f94adc820de1b57aff8c89bd53d9f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 12 Jun 2006 13:56:30 +0000 Subject: Fix AC_CHECK_DEFINE so that we can look in different files for the same define. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1011 fefdeb5f-60dc-0310-8127-8f9354f1896f --- acinclude.m4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index 02f271b4..edd80344 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -199,8 +199,8 @@ AC_LANG_RESTORE ])dnl ACX_PTHREAD AC_DEFUN([AC_CHECK_DEFINE],[ -AS_VAR_PUSHDEF([ac_var],[ac_cv_defined_$1])dnl -AC_CACHE_CHECK([for $1 defined], ac_var, +AS_VAR_PUSHDEF([ac_var],[ac_cv_defined_$1_$2])dnl +AC_CACHE_CHECK([for $1 in $2], ac_var, AC_TRY_COMPILE([#include <$2>],[ #ifdef $1 int ok; -- cgit From 519aa9b2ef4ec1fdbbc746f753240113423e1b21 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 12 Jun 2006 14:18:19 +0000 Subject: Use AM_ICONV to determine what needs to be done for iconv support. (closes #19) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1012 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 6 +++++- src/Makefile.am | 4 ++-- src/polyp/utf8.c | 9 +++++---- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 34ba78c6..0ccbe4f3 100644 --- a/configure.ac +++ b/configure.ac @@ -165,7 +165,7 @@ AM_CONDITIONAL(OS_IS_WIN32, test "x$os_is_win32" = "x1") AC_HEADER_STDC # POSIX -AC_CHECK_HEADERS([arpa/inet.h glob.h grp.h iconv.h netdb.h netinet/in.h \ +AC_CHECK_HEADERS([arpa/inet.h glob.h grp.h netdb.h netinet/in.h \ netinet/in_systm.h netinet/ip.h netinet/tcp.h pwd.h sched.h \ sys/resource.h sys/select.h sys/socket.h sys/wait.h \ syslog.h]) @@ -270,6 +270,10 @@ ACX_PTHREAD AC_SYS_LARGEFILE +#### [lib]iconv #### + +AM_ICONV + ################################### # External libraries # ################################### diff --git a/src/Makefile.am b/src/Makefile.am index 2e68ed94..a98ea697 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -420,7 +420,7 @@ endif libpolyp_la_CFLAGS = $(AM_CFLAGS) libpolyp_la_LDFLAGS = -version-info $(LIBPOLYP_VERSION_INFO) -libpolyp_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) +libpolyp_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) $(LIBICONV) if HAVE_X11 libpolyp_la_CFLAGS += $(X_CFLAGS) @@ -587,7 +587,7 @@ endif libpolypcore_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBOIL_CFLAGS) libpolypcore_la_LDFLAGS = -version-info $(LIBPOLYPCORE_VERSION_INFO) -libpolypcore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) $(LIBOIL_LIBS) +libpolypcore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) $(LIBOIL_LIBS) $(LIBICONV) ################################### # Plug-in support libraries # diff --git a/src/polyp/utf8.c b/src/polyp/utf8.c index 931328e5..33fa7214 100644 --- a/src/polyp/utf8.c +++ b/src/polyp/utf8.c @@ -34,7 +34,7 @@ #include #include -#ifdef HAVE_ICONV_H +#ifdef HAVE_ICONV #include #endif @@ -168,14 +168,15 @@ char* pa_utf8_filter (const char *str) { return utf8_validate(str, new_str); } -#ifdef HAVE_ICONV_H +#ifdef HAVE_ICONV static char* iconv_simple(const char *str, const char *to, const char *from) { char *new_str; size_t len, inlen; iconv_t cd; - char *inbuf, *outbuf; + ICONV_CONST char *inbuf; + char *outbuf; size_t res, inbytes, outbytes; cd = iconv_open(to, from); @@ -187,7 +188,7 @@ static char* iconv_simple(const char *str, const char *to, const char *from) { assert(new_str); while (1) { - inbuf = (char*)str; /* Brain dead prototype for iconv() */ + inbuf = (ICONV_CONST char*)str; /* Brain dead prototype for iconv() */ inbytes = inlen; outbuf = new_str; outbytes = len; -- cgit From 7582f7493b4103dcc1442c511d856cb616409078 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 13 Jun 2006 09:33:04 +0000 Subject: Handle pretty printing of IPv6 socket names. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1013 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/socket-util.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/polypcore/socket-util.c b/src/polypcore/socket-util.c index aefcb5ef..3cd205db 100644 --- a/src/polypcore/socket-util.c +++ b/src/polypcore/socket-util.c @@ -56,6 +56,13 @@ #ifdef HAVE_NETDB_H #include #endif +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#ifndef HAVE_INET_NTOP +#include "inet_ntop.h" +#endif #include "winsock.h" @@ -85,6 +92,7 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) { union { struct sockaddr sa; struct sockaddr_in in; + struct sockaddr_in6 in6; #ifdef HAVE_SYS_UN_H struct sockaddr_un un; #endif @@ -103,6 +111,15 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) { ip & 0xFF, ntohs(sa.in.sin_port)); return; + } else if (sa.sa.sa_family == AF_INET6) { + char buf[INET6_ADDRSTRLEN]; + const char *res; + + res = inet_ntop(AF_INET6, &sa.in6.sin6_addr, buf, sizeof(buf)); + if (res) { + snprintf(c, l, "TCP/IP client from [%s]:%u", buf, ntohs(sa.in6.sin6_port)); + return; + } #ifdef HAVE_SYS_UN_H } else if (sa.sa.sa_family == AF_UNIX) { snprintf(c, l, "UNIX socket client"); -- cgit From 928847933891f1d47b87b66299d5d2b241107c48 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 13 Jun 2006 09:33:55 +0000 Subject: Tweak the printing of client connections a bit so that it's more apparent what and who it is that's connecting. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1014 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/client.c | 3 +++ src/polypcore/protocol-esound.c | 5 +++-- src/polypcore/protocol-native.c | 5 ++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/polypcore/client.c b/src/polypcore/client.c index b5ed2fd0..4ece07a8 100644 --- a/src/polypcore/client.c +++ b/src/polypcore/client.c @@ -86,6 +86,9 @@ void pa_client_kill(pa_client *c) { void pa_client_set_name(pa_client *c, const char *name) { assert(c); + + pa_log_info(__FILE__": client %u changed name from \"%s\" to \"%s\"", c->index, c->name, name); + pa_xfree(c->name); c->name = pa_xstrdup(name); diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c index 02e140b9..c9bc504d 100644 --- a/src/polypcore/protocol-esound.c +++ b/src/polypcore/protocol-esound.c @@ -1139,7 +1139,7 @@ static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timev static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { struct connection *c; pa_protocol_esound *p = userdata; - char cname[256]; + char cname[256], pname[128]; assert(s && io && p); if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { @@ -1153,7 +1153,8 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->io = io; pa_iochannel_set_callback(c->io, io_callback, c); - pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); + pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname)); + snprintf(cname, sizeof(cname), "EsounD client (%s)", pname); assert(p->core); c->client = pa_client_new(p->core, __FILE__, cname); assert(c->client); diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c index f663dc35..221601a6 100644 --- a/src/polypcore/protocol-native.c +++ b/src/polypcore/protocol-native.c @@ -2213,6 +2213,7 @@ static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timev static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, void *userdata) { pa_protocol_native *p = userdata; struct connection *c; + char cname[256], pname[128]; assert(io && p); if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { @@ -2235,8 +2236,10 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo c->version = 8; c->protocol = p; + pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname)); + snprintf(cname, sizeof(cname), "Native client (%s)", pname); assert(p->core); - c->client = pa_client_new(p->core, __FILE__, "Client"); + c->client = pa_client_new(p->core, __FILE__, cname); assert(c->client); c->client->kill = client_kill_cb; c->client->userdata = c; -- cgit From b5a8815ec96708426f3a2c81629355660cea376a Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 13 Jun 2006 10:53:49 +0000 Subject: Make sure our inet_ntop() implementation gets linked into the new users. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1015 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index a98ea697..2dc2c663 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -382,6 +382,7 @@ libpolyp_la_SOURCES += \ polypcore/gccmacro.h \ polypcore/hashmap.c polypcore/hashmap.h \ polypcore/idxset.c polypcore/idxset.h \ + polypcore/inet_ntop.c polypcore/inet_ntop.h \ polypcore/iochannel.c polypcore/iochannel.h \ polypcore/llist.h \ polypcore/log.c polypcore/log.h \ @@ -741,7 +742,9 @@ libauthkey_prop_la_SOURCES = polypcore/authkey-prop.c polypcore/authkey-prop.h libauthkey_prop_la_LDFLAGS = -avoid-version libauthkey_prop_la_LIBADD = $(AM_LIBADD) libpolypcore.la -libsocket_util_la_SOURCES = polypcore/socket-util.c polypcore/socket-util.h +libsocket_util_la_SOURCES = \ + polypcore/inet_ntop.c polypcor/inet_ntop.h \ + polypcore/socket-util.c polypcore/socket-util.h libsocket_util_la_LDFLAGS = -avoid-version libsocket_util_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) libpolypcore.la -- cgit From 0f13c43797dd291b02a6b0fa1c9933a35da95c01 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 13 Jun 2006 13:21:14 +0000 Subject: Catch the access() system call as some applications do this to test if they can open /dev/dsp. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1016 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 8bad126b..da8f6786 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -101,6 +101,7 @@ static FILE* (*_fopen)(const char *path, const char *mode) = NULL; static int (*_open64)(const char *, int, mode_t) = NULL; static FILE* (*_fopen64)(const char *path, const char *mode) = NULL; static int (*_fclose)(FILE *f) = NULL; +static int (*_access)(const char *, int) = NULL; /* dlsym() violates ISO C, so confide the breakage into this function to * avoid warnings. */ @@ -141,6 +142,14 @@ do { \ pthread_mutex_unlock(&func_mutex); \ } while(0) +#define LOAD_ACCESS_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_access) \ + _access = (int (*)(const char*, int)) dlsym_fn(RTLD_NEXT, "access"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + #define LOAD_FOPEN_FUNC() \ do { \ pthread_mutex_lock(&func_mutex); \ @@ -1725,6 +1734,25 @@ int close(int fd) { return 0; } +int access(const char *pathname, int mode) { + debug(__FILE__": access()\n"); + + if (strcmp(pathname, "/dev/dsp") != 0 && + strcmp(pathname, "/dev/adsp") != 0 && + strcmp(pathname, "/dev/sndstat") != 0 && + strcmp(pathname, "/dev/mixer") != 0) { + LOAD_ACCESS_FUNC(); + return _access(pathname, mode); + } + + if (mode & (W_OK | X_OK)) { + errno = EACCES; + return -1; + } + + return 0; +} + int open64(const char *filename, int flags, ...) { va_list args; mode_t mode = 0; -- cgit From dd0f80e3e28f2c4a0195d763f861594a9265ef1f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 13 Jun 2006 15:54:11 +0000 Subject: Make a copy of the va_list as vsnprintf() is free to change it. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1017 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/core-util.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/polypcore/core-util.c b/src/polypcore/core-util.c index 6cf281c5..dfa41f57 100644 --- a/src/polypcore/core-util.c +++ b/src/polypcore/core-util.c @@ -366,8 +366,14 @@ char *pa_vsprintf_malloc(const char *format, va_list ap) { for(;;) { int r; + va_list aq; + + va_copy(aq, ap); + c = pa_xrealloc(c, size); - r = vsnprintf(c, size, format, ap); + r = vsnprintf(c, size, format, aq); + + va_end(aq); if (r > -1 && r < size) return c; -- cgit From 3fa491dc905edb8f54b10bff0b896e8ad7f733c6 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 15 Jun 2006 14:47:14 +0000 Subject: Make debug output in padsp a bit less verbose. Specifying -d twice will give original output. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1018 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp | 6 +- src/utils/padsp.c | 258 +++++++++++++++++++++++++++++------------------------- 2 files changed, 146 insertions(+), 118 deletions(-) diff --git a/src/utils/padsp b/src/utils/padsp index b43535b6..27f99336 100644 --- a/src/utils/padsp +++ b/src/utils/padsp @@ -46,7 +46,11 @@ while getopts 'hs:n:m:MSDd' param ; do export PADSP_NO_DSP ;; d) - PADSP_DEBUG=1 + if [ x"$PADSP_DEBUG" = x ]; then + PADSP_DEBUG=1 + else + PADSP_DEBUG=$(( $PADSP_DEBUG + 1 )) + fi export PADSP_DEBUG ;; *) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index da8f6786..4fe8205e 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -176,7 +176,7 @@ do { \ #define CONTEXT_CHECK_DEAD_GOTO(i, label) do { \ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY) { \ - debug(__FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ + debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ goto label; \ } \ } while(0); @@ -184,20 +184,34 @@ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY) { \ #define STREAM_CHECK_DEAD_GOTO(i, label) do { \ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ !(i)->stream || pa_stream_get_state((i)->stream) != PA_STREAM_READY) { \ - debug(__FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ + debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ goto label; \ } \ } while(0); -static void debug(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +static void debug(int level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); -static void debug(const char *format, ...) { +#define DEBUG_LEVEL_ALWAYS 0 +#define DEBUG_LEVEL_NORMAL 1 +#define DEBUG_LEVEL_VERBOSE 2 + +static void debug(int level, const char *format, ...) { va_list ap; - if (getenv("PADSP_DEBUG")) { - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); - } + const char *dlevel_s; + int dlevel; + + dlevel_s = getenv("PADSP_DEBUG"); + if (!dlevel_s) + return; + + dlevel = atoi(dlevel_s); + + if (dlevel < level) + return; + + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); } static int padsp_disabled(void) { @@ -280,7 +294,7 @@ static void function_exit(void) { static void fd_info_free(fd_info *i) { assert(i); - debug(__FILE__": freeing fd info (fd=%i)\n", i->app_fd); + debug(DEBUG_LEVEL_NORMAL, __FILE__": freeing fd info (fd=%i)\n", i->app_fd); dsp_drain(i); @@ -323,7 +337,7 @@ static fd_info *fd_info_ref(fd_info *i) { assert(i->ref >= 1); i->ref++; -/* debug(__FILE__": ref++, now %i\n", i->ref); */ + debug(DEBUG_LEVEL_VERBOSE, __FILE__": ref++, now %i\n", i->ref); pthread_mutex_unlock(&i->mutex); return i; @@ -334,7 +348,7 @@ static void fd_info_unref(fd_info *i) { pthread_mutex_lock(&i->mutex); assert(i->ref >= 1); r = --i->ref; -/* debug(__FILE__": ref--, now %i\n", i->ref); */ + debug(DEBUG_LEVEL_VERBOSE, __FILE__": ref--, now %i\n", i->ref); pthread_mutex_unlock(&i->mutex); if (r <= 0) @@ -397,7 +411,7 @@ static const char *stream_name(void) { static void atfork_prepare(void) { fd_info *i; - debug(__FILE__": atfork_prepare() enter\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_prepare() enter\n"); function_enter(); @@ -411,13 +425,13 @@ static void atfork_prepare(void) { pthread_mutex_lock(&func_mutex); - debug(__FILE__": atfork_prepare() exit\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_prepare() exit\n"); } static void atfork_parent(void) { fd_info *i; - debug(__FILE__": atfork_parent() enter\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_parent() enter\n"); pthread_mutex_unlock(&func_mutex); @@ -430,13 +444,13 @@ static void atfork_parent(void) { function_exit(); - debug(__FILE__": atfork_parent() exit\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_parent() exit\n"); } static void atfork_child(void) { fd_info *i; - debug(__FILE__": atfork_child() enter\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_child() enter\n"); /* We do only the bare minimum to get all fds closed */ pthread_mutex_init(&func_mutex, NULL); @@ -471,7 +485,7 @@ static void atfork_child(void) { function_exit(); - debug(__FILE__": atfork_child() exit\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_child() exit\n"); } static void install_atfork(void) { @@ -504,7 +518,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { char name[64]; static pthread_once_t install_atfork_once = PTHREAD_ONCE_INIT; - debug(__FILE__": fd_info_new()\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": fd_info_new()\n"); signal(SIGPIPE, SIG_IGN); /* Yes, ugly as hell */ @@ -535,7 +549,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfds) < 0) { *_errno = errno; - debug(__FILE__": socket() failed: %s\n", strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": socket() failed: %s\n", strerror(errno)); goto fail; } @@ -544,13 +558,13 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { if (!(i->mainloop = pa_threaded_mainloop_new())) { *_errno = EIO; - debug(__FILE__": pa_threaded_mainloop_new() failed\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_threaded_mainloop_new() failed\n"); goto fail; } if (!(i->context = pa_context_new(pa_threaded_mainloop_get_api(i->mainloop), client_name(name, sizeof(name))))) { *_errno = EIO; - debug(__FILE__": pa_context_new() failed\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_context_new() failed\n"); goto fail; } @@ -558,7 +572,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { if (pa_context_connect(i->context, NULL, 0, NULL) < 0) { *_errno = ECONNREFUSED; - debug(__FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -566,7 +580,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { if (pa_threaded_mainloop_start(i->mainloop) < 0) { *_errno = EIO; - debug(__FILE__": pa_threaded_mainloop_start() failed\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_threaded_mainloop_start() failed\n"); goto unlock_and_fail; } @@ -575,7 +589,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { if (pa_context_get_state(i->context) != PA_CONTEXT_READY) { *_errno = ECONNREFUSED; - debug(__FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto unlock_and_fail; } @@ -654,8 +668,8 @@ static void fix_metrics(fd_info *i) { i->fragment_size = 1024; } - debug(__FILE__": sample spec: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); - debug(__FILE__": fixated metrics to %i fragments, %li bytes each.\n", i->n_fragments, (long)i->fragment_size); + debug(DEBUG_LEVEL_NORMAL, __FILE__": sample spec: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": fixated metrics to %i fragments, %li bytes each.\n", i->n_fragments, (long)i->fragment_size); } static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { @@ -699,7 +713,7 @@ static int fd_info_copy_data(fd_info *i, int force) { return -1; if ((n = pa_stream_writable_size(i->stream)) == (size_t) -1) { - debug(__FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); return -1; } @@ -708,7 +722,7 @@ static int fd_info_copy_data(fd_info *i, int force) { if (!i->buf) { if (!(i->buf = malloc(i->fragment_size))) { - debug(__FILE__": malloc() failed.\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": malloc() failed.\n"); return -1; } } @@ -718,12 +732,12 @@ static int fd_info_copy_data(fd_info *i, int force) { if (errno == EAGAIN) break; - debug(__FILE__": read(): %s\n", r == 0 ? "EOF" : strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": read(): %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } if (pa_stream_write(i->stream, i->buf, r, free, 0, PA_SEEK_RELATIVE) < 0) { - debug(__FILE__": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i->context))); return -1; } @@ -749,11 +763,11 @@ static void stream_state_cb(pa_stream *s, void * userdata) { switch (pa_stream_get_state(s)) { case PA_STREAM_READY: - debug(__FILE__": stream established.\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": stream established.\n"); break; case PA_STREAM_FAILED: - debug(__FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); fd_info_shutdown(i); break; @@ -773,7 +787,7 @@ static int create_stream(fd_info *i) { fix_metrics(i); if (!(i->stream = pa_stream_new(i->context, stream_name(), &i->sample_spec, NULL))) { - debug(__FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -788,7 +802,7 @@ static int create_stream(fd_info *i) { attr.minreq = i->fragment_size; if (pa_stream_connect_playback(i->stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) { - debug(__FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -847,7 +861,10 @@ static int dsp_open(int flags, int *_errno) { int ret; int f; + debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open()\n"); + if ((flags != O_WRONLY) && (flags != (O_WRONLY|O_NONBLOCK))) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": bad access flags: %x\n", flags); *_errno = EACCES; return -1; } @@ -875,7 +892,7 @@ static int dsp_open(int flags, int *_errno) { pa_threaded_mainloop_unlock(i->mainloop); - debug(__FILE__": dsp_open() succeeded, fd=%i\n", i->app_fd); + debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open() succeeded, fd=%i\n", i->app_fd); fd_info_add_to_list(i); ret = i->app_fd; @@ -891,7 +908,7 @@ fail: *_errno = EIO; - debug(__FILE__": dsp_open() failed\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open() failed\n"); return -1; } @@ -929,7 +946,7 @@ static void subscribe_cb(pa_context *context, pa_subscription_event_type_t t, ui return; if (!(o = pa_context_get_sink_info_by_index(i->context, i->sink_index, sink_info_cb, i))) { - debug(__FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); return; } @@ -941,6 +958,8 @@ static int mixer_open(int flags, int *_errno) { pa_operation *o; int ret; + debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open()\n"); + if (!(i = fd_info_new(FD_INFO_MIXER, _errno))) return -1; @@ -949,7 +968,7 @@ static int mixer_open(int flags, int *_errno) { pa_context_set_subscribe_callback(i->context, subscribe_cb, i); if (!(o = pa_context_subscribe(i->context, PA_SUBSCRIPTION_MASK_SINK, context_success_cb, i))) { - debug(__FILE__": Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context))); *_errno = EIO; goto fail; } @@ -961,7 +980,7 @@ static int mixer_open(int flags, int *_errno) { } if (!i->operation_success) { - debug(__FILE__":Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__":Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context))); *_errno = EIO; goto fail; } @@ -970,7 +989,7 @@ static int mixer_open(int flags, int *_errno) { pa_operation_unref(o); if (!(o = pa_context_get_sink_info_by_name(i->context, NULL, sink_info_cb, i))) { - debug(__FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); *_errno = EIO; goto fail; } @@ -982,14 +1001,14 @@ static int mixer_open(int flags, int *_errno) { } if (!i->operation_success) { - debug(__FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); *_errno = EIO; goto fail; } pa_threaded_mainloop_unlock(i->mainloop); - debug(__FILE__": mixer_open() succeeded, fd=%i\n", i->app_fd); + debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open() succeeded, fd=%i\n", i->app_fd); fd_info_add_to_list(i); ret = i->app_fd; @@ -1005,7 +1024,7 @@ fail: *_errno = EIO; - debug(__FILE__": mixer_open() failed\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open() failed\n"); return -1; } @@ -1039,11 +1058,11 @@ static int sndstat_open(int flags, int *_errno) { int fd = -1; int e; - debug(__FILE__": sndstat_open()\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": sndstat_open()\n"); if (flags != O_RDONLY && flags != (O_RDONLY|O_LARGEFILE)) { *_errno = EACCES; - debug(__FILE__": bad access!\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": bad access!\n"); goto fail; } @@ -1054,7 +1073,7 @@ static int sndstat_open(int flags, int *_errno) { if (fd < 0) { *_errno = e; - debug(__FILE__": mkstemp() failed: %s\n", strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": mkstemp() failed: %s\n", strerror(errno)); goto fail; } @@ -1062,13 +1081,13 @@ static int sndstat_open(int flags, int *_errno) { if (write(fd, sndstat, sizeof(sndstat) -1) != sizeof(sndstat)-1) { *_errno = errno; - debug(__FILE__": write() failed: %s\n", strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": write() failed: %s\n", strerror(errno)); goto fail; } if (lseek(fd, SEEK_SET, 0) < 0) { *_errno = errno; - debug(__FILE__": lseek() failed: %s\n", strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": lseek() failed: %s\n", strerror(errno)); goto fail; } @@ -1085,7 +1104,7 @@ int open(const char *filename, int flags, ...) { mode_t mode = 0; int r, _errno = 0; - debug(__FILE__": open(%s)\n", filename); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": open(%s)\n", filename); va_start(args, flags); if (flags & O_CREAT) @@ -1122,19 +1141,19 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno switch (request) { case SOUND_MIXER_READ_DEVMASK : - debug(__FILE__": SOUND_MIXER_READ_DEVMASK\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_DEVMASK\n"); *(int*) argp = SOUND_MASK_PCM; break; case SOUND_MIXER_READ_RECMASK : - debug(__FILE__": SOUND_MIXER_READ_RECMASK\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_RECMASK\n"); *(int*) argp = 0; break; case SOUND_MIXER_READ_STEREODEVS: - debug(__FILE__": SOUND_MIXER_READ_STEREODEVS\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_STEREODEVS\n"); pa_threaded_mainloop_lock(i->mainloop); *(int*) argp = i->volume.channels > 1 ? SOUND_MASK_PCM : 0; @@ -1143,20 +1162,20 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno break; case SOUND_MIXER_READ_RECSRC: - debug(__FILE__": SOUND_MIXER_READ_RECSRC\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_RECSRC\n"); *(int*) argp = 0; break; case SOUND_MIXER_READ_CAPS: - debug(__FILE__": SOUND_MIXER_READ_CAPS\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_CAPS\n"); *(int*) argp = 0; break; case SOUND_MIXER_READ_PCM: - debug(__FILE__": SOUND_MIXER_READ_PCM\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_PCM\n"); pa_threaded_mainloop_lock(i->mainloop); @@ -1171,7 +1190,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno case SOUND_MIXER_WRITE_PCM: { pa_cvolume v; - debug(__FILE__": SOUND_MIXER_WRITE_PCM\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_PCM\n"); pa_threaded_mainloop_lock(i->mainloop); @@ -1184,7 +1203,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno pa_operation *o; if (!(o = pa_context_set_sink_volume_by_index(i->context, i->sink_index, &i->volume, NULL, NULL))) - debug(__FILE__":Failed set volume: %s", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__":Failed set volume: %s", pa_strerror(pa_context_errno(i->context))); else { i->operation_success = 0; @@ -1196,7 +1215,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno exit_loop: if (!i->operation_success) - debug(__FILE__": Failed to set volume: %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to set volume: %s\n", pa_strerror(pa_context_errno(i->context))); pa_operation_unref(o); } @@ -1213,6 +1232,8 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno case SOUND_MIXER_INFO: { mixer_info *mi = argp; + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_INFO\n"); + memset(mi, 0, sizeof(mixer_info)); strncpy(mi->id, "POLYPAUDIO", sizeof(mi->id)); strncpy(mi->name, "Polypaudio Virtual OSS", sizeof(mi->name)); @@ -1223,7 +1244,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno } default: - debug(__FILE__": unknown ioctl 0x%08lx\n", request); + debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request); *_errno = EINVAL; goto fail; @@ -1296,7 +1317,7 @@ static int dsp_flush_socket(fd_info *i) { return -1; if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { - debug(__FILE__": SIOCINQ: %s\n", strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ: %s\n", strerror(errno)); return -1; } @@ -1306,7 +1327,7 @@ static int dsp_flush_socket(fd_info *i) { k = (size_t) l > sizeof(buf) ? sizeof(buf) : (size_t) l; if (read(i->thread_fd, buf, k) < 0) - debug(__FILE__": read(): %s\n", strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": read(): %s\n", strerror(errno)); l -= k; } @@ -1324,7 +1345,7 @@ static int dsp_empty_socket(fd_info *i) { break; if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { - debug(__FILE__": SIOCINQ: %s\n", strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ: %s\n", strerror(errno)); break; } @@ -1346,7 +1367,7 @@ static int dsp_drain(fd_info *i) { if (!i->mainloop) return 0; - debug(__FILE__": Draining.\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": Draining.\n"); pa_threaded_mainloop_lock(i->mainloop); @@ -1356,10 +1377,10 @@ static int dsp_drain(fd_info *i) { if (!i->stream) goto fail; - debug(__FILE__": Really draining.\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": Really draining.\n"); if (!(o = pa_stream_drain(i->stream, stream_success_cb, i))) { - debug(__FILE__": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -1371,7 +1392,7 @@ static int dsp_drain(fd_info *i) { } if (!i->operation_success) { - debug(__FILE__": pa_stream_drain() 2: %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drain() 2: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -1399,10 +1420,10 @@ static int dsp_trigger(fd_info *i) { if (dsp_empty_socket(i) < 0) goto fail; - debug(__FILE__": Triggering.\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": Triggering.\n"); if (!(o = pa_stream_trigger(i->stream, stream_success_cb, i))) { - debug(__FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -1414,7 +1435,7 @@ static int dsp_trigger(fd_info *i) { } if (!i->operation_success) { - debug(__FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -1435,7 +1456,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) switch (request) { case SNDCTL_DSP_SETFMT: { - debug(__FILE__": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp); pa_threaded_mainloop_lock(i->mainloop); @@ -1455,7 +1476,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) int valid; char t[256]; - debug(__FILE__": SNDCTL_DSP_SPEED: %i\n", *(int*) argp); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SPEED: %i\n", *(int*) argp); pa_threaded_mainloop_lock(i->mainloop); @@ -1467,7 +1488,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) free_stream(i); } - debug(__FILE__": ss: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": ss: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); pa_threaded_mainloop_unlock(i->mainloop); @@ -1480,7 +1501,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) } case SNDCTL_DSP_STEREO: - debug(__FILE__": SNDCTL_DSP_STEREO: %i\n", *(int*) argp); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_STEREO: %i\n", *(int*) argp); pa_threaded_mainloop_lock(i->mainloop); @@ -1494,7 +1515,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_sample_spec ss; int valid; - debug(__FILE__": SNDCTL_DSP_CHANNELS: %i\n", *(int*) argp); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CHANNELS: %i\n", *(int*) argp); pa_threaded_mainloop_lock(i->mainloop); @@ -1517,7 +1538,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) } case SNDCTL_DSP_GETBLKSIZE: - debug(__FILE__": SNDCTL_DSP_GETBLKSIZE\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETBLKSIZE\n"); pa_threaded_mainloop_lock(i->mainloop); @@ -1529,7 +1550,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) break; case SNDCTL_DSP_SETFRAGMENT: - debug(__FILE__": SNDCTL_DSP_SETFRAGMENT: 0x%8x\n", *(int*) argp); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFRAGMENT: 0x%8x\n", *(int*) argp); pa_threaded_mainloop_lock(i->mainloop); @@ -1543,7 +1564,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) break; case SNDCTL_DSP_GETCAPS: - debug(__FILE__": SNDCTL_DSP_CAPS\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CAPS\n"); *(int*) argp = DSP_CAP_MULTI; break; @@ -1551,7 +1572,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_GETODELAY: { int l; - debug(__FILE__": SNDCTL_DSP_GETODELAY\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETODELAY\n"); pa_threaded_mainloop_lock(i->mainloop); @@ -1568,7 +1589,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) } if (pa_context_errno(i->context) != PA_ERR_NODATA) { - debug(__FILE__": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i->context))); break; } @@ -1578,19 +1599,19 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) exit_loop: if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) - debug(__FILE__": SIOCINQ failed: %s\n", strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno)); else *(int*) argp += l; pa_threaded_mainloop_unlock(i->mainloop); - debug(__FILE__": ODELAY: %i\n", *(int*) argp); + debug(DEBUG_LEVEL_NORMAL, __FILE__": ODELAY: %i\n", *(int*) argp); break; } case SNDCTL_DSP_RESET: { - debug(__FILE__": SNDCTL_DSP_RESET\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_RESET\n"); pa_threaded_mainloop_lock(i->mainloop); @@ -1603,21 +1624,21 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) } case SNDCTL_DSP_GETFMTS: { - debug(__FILE__": SNDCTL_DSP_GETFMTS\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETFMTS\n"); *(int*) argp = AFMT_MU_LAW|AFMT_A_LAW|AFMT_U8|AFMT_S16_LE|AFMT_S16_BE; break; } case SNDCTL_DSP_POST: - debug(__FILE__": SNDCTL_DSP_POST\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_POST\n"); if (dsp_trigger(i) < 0) *_errno = EIO; break; case SNDCTL_DSP_SYNC: - debug(__FILE__": SNDCTL_DSP_SYNC\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SYNC\n"); if (dsp_drain(i) < 0) *_errno = EIO; @@ -1629,7 +1650,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) int l; size_t k = 0; - debug(__FILE__": SNDCTL_DSP_GETOSPACE\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETOSPACE\n"); pa_threaded_mainloop_lock(i->mainloop); @@ -1637,12 +1658,12 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) if (i->stream) { if ((k = pa_stream_writable_size(i->stream)) == (size_t) -1) - debug(__FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); } else k = i->fragment_size * i->n_fragments; if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { - debug(__FILE__": SIOCINQ failed: %s\n", strerror(errno)); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno)); l = 0; } @@ -1653,13 +1674,13 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_threaded_mainloop_unlock(i->mainloop); - debug(__FILE__": fragsize=%i, fragstotal=%i, bytes=%i, fragments=%i\n", bi->fragsize, bi->fragstotal, bi->bytes, bi->fragments); + debug(DEBUG_LEVEL_NORMAL, __FILE__": fragsize=%i, fragstotal=%i, bytes=%i, fragments=%i\n", bi->fragsize, bi->fragstotal, bi->bytes, bi->fragments); break; } default: - debug(__FILE__": unknwon ioctl 0x%08lx\n", request); + debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request); *_errno = EINVAL; goto fail; @@ -1678,7 +1699,7 @@ int ioctl(int fd, unsigned long request, ...) { void *argp; int r, _errno = 0; - debug(__FILE__": ioctl()\n"); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": ioctl()\n"); va_start(args, request); argp = va_arg(args, void *); @@ -1713,7 +1734,7 @@ int ioctl(int fd, unsigned long request, ...) { int close(int fd) { fd_info *i; - debug(__FILE__": close()\n"); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": close()\n"); if (!function_enter()) { LOAD_CLOSE_FUNC(); @@ -1735,7 +1756,7 @@ int close(int fd) { } int access(const char *pathname, int mode) { - debug(__FILE__": access()\n"); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": access(%s)\n", pathname); if (strcmp(pathname, "/dev/dsp") != 0 && strcmp(pathname, "/dev/adsp") != 0 && @@ -1746,10 +1767,13 @@ int access(const char *pathname, int mode) { } if (mode & (W_OK | X_OK)) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": access(%s, %x) = EACCESS\n", pathname, mode); errno = EACCES; return -1; } + debug(DEBUG_LEVEL_NORMAL, __FILE__": access(%s, %x) = OK\n", pathname, mode); + return 0; } @@ -1757,7 +1781,7 @@ int open64(const char *filename, int flags, ...) { va_list args; mode_t mode = 0; - debug(__FILE__": open64(%s)\n", filename); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": open64(%s)\n", filename); va_start(args, flags); if (flags & O_CREAT) @@ -1780,31 +1804,31 @@ FILE* fopen(const char *filename, const char *mode) { int fd; mode_t m; - debug(__FILE__": fopen(%s)\n", filename); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": fopen(%s)\n", filename); - if (strcmp(filename, "/dev/dsp") == 0 || - strcmp(filename, "/dev/adsp") == 0) { - - if (strcmp(mode, "wb") != 0) { - errno = EACCES; - return NULL; - } + if (strcmp(filename, "/dev/dsp") != 0 && + strcmp(filename, "/dev/adsp") != 0 && + strcmp(filename, "/dev/sndstat") != 0 && + strcmp(filename, "/dev/mixer") != 0) { + LOAD_FOPEN_FUNC(); + return _fopen(filename, mode); + } + switch (mode[0]) { + case 'r': + m = O_RDONLY; + break; + case 'w': + case 'a': m = O_WRONLY; - } else if (strcmp(filename, "/dev/sndstat") == 0) { - - if (strcmp(mode, "r") != 0) { - errno = EACCES; - return NULL; - } + break; + default: + errno = EINVAL; + return NULL; + } - m = O_RDONLY; - } else if (strcmp(filename, "/dev/mixer") == 0) + if ((((mode[1] == 'b') || (mode[1] == 't')) && (mode[2] == '+')) || (mode[1] == '+')) m = O_RDWR; - else { - LOAD_FOPEN_FUNC(); - return _fopen(filename, mode); - } if ((fd = open(filename, m)) < 0) return NULL; @@ -1819,7 +1843,7 @@ FILE* fopen(const char *filename, const char *mode) { FILE *fopen64(const char *filename, const char *mode) { - debug(__FILE__": fopen64(%s)\n", filename); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": fopen64(%s)\n", filename); if (strcmp(filename, "/dev/dsp") != 0 && strcmp(filename, "/dev/adsp") != 0 && @@ -1835,7 +1859,7 @@ FILE *fopen64(const char *filename, const char *mode) { int fclose(FILE *f) { fd_info *i; - debug(__FILE__": fclose()\n"); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": fclose()\n"); if (!function_enter()) { LOAD_FCLOSE_FUNC(); -- cgit From 8e37d68ae3206abb306b7cf00f0189e99edb4aa8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 15 Jun 2006 17:34:27 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1019 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/todo b/doc/todo index 0569924c..7b83ea98 100644 --- a/doc/todo +++ b/doc/todo @@ -33,6 +33,9 @@ Post 0.9.0: - drop dependency of libpolyp on libX11, instead use an external mini binary - "hot" moving of streams between sinks - check if using prctl(PR_GET_NAME) makes sense in pa_get_binary_name() +- gconf module + frontend +- hooks for creating sink inputs +- module-cli argument exit-on-eof Long term: - pass meta info for hearing impaired -- cgit From a529b281ebe32ee07f80f77aa13e24d65ee15eba Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Jun 2006 19:33:05 +0000 Subject: if S16NE is not supported, fall back to S16RE. If FLOAT32NE is not supported, fall back to FLOAT32NE. If still nothing is supported, try everything else in order git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1020 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 84 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 14 deletions(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 5b6d72e7..2ead58c8 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -247,15 +247,8 @@ int pa_alsa_fdlist_init_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_han return 0; } -/* Set the hardware parameters of the given ALSA device. Returns the - * selected fragment settings in *period and *period_size */ -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { - int ret = -1; - snd_pcm_uframes_t buffer_size; - snd_pcm_hw_params_t *hwparams = NULL; - unsigned int r = ss->rate; - unsigned int c = ss->channels; - +static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_sample_format_t *f) { + static const snd_pcm_format_t format_trans[] = { [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8, [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW, @@ -265,15 +258,73 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE, [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, }; - assert(pcm_handle && ss && periods && period_size); + + static const pa_sample_format_t try_order[] = { + PA_SAMPLE_S16NE, + PA_SAMPLE_S16RE, + PA_SAMPLE_FLOAT32NE, + PA_SAMPLE_FLOAT32RE, + PA_SAMPLE_ULAW, + PA_SAMPLE_ALAW, + PA_SAMPLE_U8, + PA_SAMPLE_INVALID + }; + + int i, ret; + + assert(pcm_handle); + assert(f); + + if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0) + return ret; + + if (*f == PA_SAMPLE_FLOAT32BE) + *f = PA_SAMPLE_FLOAT32LE; + else if (*f == PA_SAMPLE_FLOAT32LE) + *f = PA_SAMPLE_FLOAT32BE; + else if (*f == PA_SAMPLE_S16BE) + *f = PA_SAMPLE_S16LE; + else if (*f == PA_SAMPLE_S16LE) + *f = PA_SAMPLE_S16BE; + else + goto try_auto; + + if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0) + return ret; + +try_auto: + + for (i = 0; try_order[i] != PA_SAMPLE_INVALID; i++) { + *f = try_order[i]; + + if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0) + return ret; + } + + return -1; +} + +/* Set the hardware parameters of the given ALSA device. Returns the + * selected fragment settings in *period and *period_size */ +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { + int ret = -1; + snd_pcm_uframes_t buffer_size; + unsigned int r = ss->rate; + unsigned int c = ss->channels; + pa_sample_format_t f = ss->format; + snd_pcm_hw_params_t *hwparams; + + assert(pcm_handle); + assert(ss); + assert(periods); + assert(period_size); buffer_size = *periods * *period_size; if ((ret = snd_pcm_hw_params_malloc(&hwparams)) < 0 || (ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 || (ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0 || - (ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[ss->format])) < 0 || - (ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0 || + (ret = set_format(pcm_handle, hwparams, &f)) < 0 || (ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0 || (*period_size > 0 && (ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL)) < 0) || (*periods > 0 && (ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0) || @@ -281,7 +332,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p goto finish; if (ss->rate != r) { - pa_log_info(__FILE__": device doesn't support %u Hz, changed to %u Hz.", ss->rate, r); + pa_log_warn(__FILE__": device doesn't support %u Hz, changed to %u Hz.", ss->rate, r); /* If the sample rate deviates too much, we need to resample */ if (r < ss->rate*.95 || r > ss->rate*1.05) @@ -289,9 +340,14 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p } if (ss->channels != c) { - pa_log_info(__FILE__": device doesn't support %u channels, changed to %u.", ss->channels, c); + pa_log_warn(__FILE__": device doesn't support %u channels, changed to %u.", ss->channels, c); ss->channels = c; } + + if (ss->format != f) { + pa_log_warn(__FILE__": device doesn't support sample format %s, changed to %s.", pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f)); + ss->format = f; + } if ((ret = snd_pcm_prepare(pcm_handle)) < 0) goto finish; -- cgit From 6684264b69a17ec907c903c6f9ca9b99dbd29be2 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 16 Jun 2006 21:07:32 +0000 Subject: Record support. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1021 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 567 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 435 insertions(+), 132 deletions(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 4fe8205e..b0e76327 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -52,7 +52,7 @@ typedef enum { FD_INFO_MIXER, - FD_INFO_PLAYBACK + FD_INFO_STREAM, } fd_info_type_t; typedef struct fd_info fd_info; @@ -71,16 +71,18 @@ struct fd_info { pa_threaded_mainloop *mainloop; pa_context *context; - pa_stream *stream; + pa_stream *play_stream; + pa_stream *rec_stream; pa_io_event *io_event; void *buf; + size_t rec_offset; int operation_success; - pa_cvolume volume; - uint32_t sink_index; + pa_cvolume sink_volume, source_volume; + uint32_t sink_index, source_index; int volume_modify_count; PA_LLIST_FIELDS(fd_info); @@ -181,9 +183,17 @@ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY) { \ } \ } while(0); -#define STREAM_CHECK_DEAD_GOTO(i, label) do { \ +#define PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, label) do { \ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ - !(i)->stream || pa_stream_get_state((i)->stream) != PA_STREAM_READY) { \ + !(i)->play_stream || pa_stream_get_state((i)->play_stream) != PA_STREAM_READY) { \ + debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ + goto label; \ +} \ +} while(0); + +#define RECORD_STREAM_CHECK_DEAD_GOTO(i, label) do { \ +if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ + !(i)->rec_stream || pa_stream_get_state((i)->rec_stream) != PA_STREAM_READY) { \ debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ goto label; \ } \ @@ -301,9 +311,14 @@ static void fd_info_free(fd_info *i) { if (i->mainloop) pa_threaded_mainloop_stop(i->mainloop); - if (i->stream) { - pa_stream_disconnect(i->stream); - pa_stream_unref(i->stream); + if (i->play_stream) { + pa_stream_disconnect(i->play_stream); + pa_stream_unref(i->play_stream); + } + + if (i->rec_stream) { + pa_stream_disconnect(i->rec_stream); + pa_stream_unref(i->rec_stream); } if (i->context) { @@ -465,9 +480,14 @@ static void atfork_child(void) { i->context = NULL; } - if (i->stream) { - pa_stream_unref(i->stream); - i->stream = NULL; + if (i->play_stream) { + pa_stream_unref(i->play_stream); + i->play_stream = NULL; + } + + if (i->rec_stream) { + pa_stream_unref(i->rec_stream); + i->rec_stream = NULL; } if (i->app_fd >= 0) { @@ -534,15 +554,19 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { i->mainloop = NULL; i->context = NULL; - i->stream = NULL; + i->play_stream = NULL; + i->rec_stream = NULL; i->io_event = NULL; pthread_mutex_init(&i->mutex, NULL); i->ref = 1; i->buf = NULL; + i->rec_offset = 0; i->unusable = 0; - pa_cvolume_reset(&i->volume, 2); + pa_cvolume_reset(&i->sink_volume, 2); + pa_cvolume_reset(&i->source_volume, 2); i->volume_modify_count = 0; i->sink_index = (uint32_t) -1; + i->source_index = (uint32_t) -1; PA_LLIST_INIT(fd_info, i); reset_params(i); @@ -678,8 +702,36 @@ static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { if (i->io_event) { pa_mainloop_api *api; + pa_io_event_flags_t flags; + size_t n; + api = pa_threaded_mainloop_get_api(i->mainloop); - api->io_enable(i->io_event, PA_IO_EVENT_INPUT); + + flags = 0; + + if (s == i->play_stream) { + n = pa_stream_writable_size(i->play_stream); + if (n == (size_t)-1) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n", + pa_strerror(pa_context_errno(i->context))); + } + + if (n >= i->fragment_size) + flags |= PA_IO_EVENT_INPUT; + } + + if (s == i->rec_stream) { + n = pa_stream_readable_size(i->rec_stream); + if (n == (size_t)-1) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_readable_size(): %s\n", + pa_strerror(pa_context_errno(i->context))); + } + + if (n >= i->fragment_size) + flags |= PA_IO_EVENT_OUTPUT; + } + + api->io_enable(i->io_event, flags); } } @@ -708,49 +760,114 @@ static void fd_info_shutdown(fd_info *i) { static int fd_info_copy_data(fd_info *i, int force) { size_t n; + pa_io_event_flags_t flags; - if (!i->stream) + if (!i->play_stream && !i->rec_stream) return -1; - if ((n = pa_stream_writable_size(i->stream)) == (size_t) -1) { - debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); - return -1; - } - - while (n >= i->fragment_size || force) { - ssize_t r; - - if (!i->buf) { - if (!(i->buf = malloc(i->fragment_size))) { - debug(DEBUG_LEVEL_NORMAL, __FILE__": malloc() failed.\n"); + flags = 0; + + if (i->play_stream) { + n = pa_stream_writable_size(i->play_stream); + + if (n == (size_t)-1) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n", + pa_strerror(pa_context_errno(i->context))); + return -1; + } + + while (n >= i->fragment_size || force) { + ssize_t r; + + if (!i->buf) { + if (!(i->buf = malloc(i->fragment_size))) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": malloc() failed.\n"); + return -1; + } + } + + if ((r = read(i->thread_fd, i->buf, i->fragment_size)) <= 0) { + + if (errno == EAGAIN) + break; + + debug(DEBUG_LEVEL_NORMAL, __FILE__": read(): %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } - } - - if ((r = read(i->thread_fd, i->buf, i->fragment_size)) <= 0) { - if (errno == EAGAIN) - break; - - debug(DEBUG_LEVEL_NORMAL, __FILE__": read(): %s\n", r == 0 ? "EOF" : strerror(errno)); - return -1; + if (pa_stream_write(i->play_stream, i->buf, r, free, 0, PA_SEEK_RELATIVE) < 0) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i->context))); + return -1; + } + + i->buf = NULL; + + assert(n >= (size_t) r); + n -= r; } - - if (pa_stream_write(i->stream, i->buf, r, free, 0, PA_SEEK_RELATIVE) < 0) { - debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i->context))); + + if (n >= i->fragment_size) + flags |= PA_IO_EVENT_INPUT; + } + + if (i->rec_stream) { + n = pa_stream_readable_size(i->rec_stream); + + if (n == (size_t)-1) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_readable_size(): %s\n", + pa_strerror(pa_context_errno(i->context))); return -1; } - i->buf = NULL; + while (n >= i->fragment_size || force) { + ssize_t r; + const void *data; + const char *buf; + size_t len; + + if (pa_stream_peek(i->rec_stream, &data, &len) < 0) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_peek(): %s\n", pa_strerror(pa_context_errno(i->context))); + return -1; + } + + if (!data) + break; - assert(n >= (size_t) r); - n -= r; + buf = (const char*)data + i->rec_offset; + + if ((r = write(i->thread_fd, buf, len - i->rec_offset)) <= 0) { + + if (errno == EAGAIN) + break; + + debug(DEBUG_LEVEL_NORMAL, __FILE__": write(): %s\n", strerror(errno)); + return -1; + } + + assert((size_t)r <= len - i->rec_offset); + i->rec_offset += r; + + if (i->rec_offset == len) { + if (pa_stream_drop(i->rec_stream) < 0) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drop(): %s\n", pa_strerror(pa_context_errno(i->context))); + return -1; + } + i->rec_offset = 0; + } + + assert(n >= (size_t) r); + n -= r; + } + + if (n >= i->fragment_size) + flags |= PA_IO_EVENT_OUTPUT; } if (i->io_event) { pa_mainloop_api *api; + api = pa_threaded_mainloop_get_api(i->mainloop); - api->io_enable(i->io_event, n >= i->fragment_size ? PA_IO_EVENT_INPUT : 0); + api->io_enable(i->io_event, flags); } return 0; @@ -778,7 +895,7 @@ static void stream_state_cb(pa_stream *s, void * userdata) { } } -static int create_stream(fd_info *i) { +static int create_playback_stream(fd_info *i) { pa_buffer_attr attr; int n; @@ -786,14 +903,14 @@ static int create_stream(fd_info *i) { fix_metrics(i); - if (!(i->stream = pa_stream_new(i->context, stream_name(), &i->sample_spec, NULL))) { + if (!(i->play_stream = pa_stream_new(i->context, stream_name(), &i->sample_spec, NULL))) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } - pa_stream_set_state_callback(i->stream, stream_state_cb, i); - pa_stream_set_write_callback(i->stream, stream_request_cb, i); - pa_stream_set_latency_update_callback(i->stream, stream_latency_update_cb, i); + pa_stream_set_state_callback(i->play_stream, stream_state_cb, i); + pa_stream_set_write_callback(i->play_stream, stream_request_cb, i); + pa_stream_set_latency_update_callback(i->play_stream, stream_latency_update_cb, i); memset(&attr, 0, sizeof(attr)); attr.maxlength = i->fragment_size * (i->n_fragments+1); @@ -801,7 +918,7 @@ static int create_stream(fd_info *i) { attr.prebuf = i->fragment_size; attr.minreq = i->fragment_size; - if (pa_stream_connect_playback(i->stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) { + if (pa_stream_connect_playback(i->play_stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -817,13 +934,56 @@ fail: return -1; } -static void free_stream(fd_info *i) { +static int create_record_stream(fd_info *i) { + pa_buffer_attr attr; + int n; + assert(i); - if (i->stream) { - pa_stream_disconnect(i->stream); - pa_stream_unref(i->stream); - i->stream = NULL; + fix_metrics(i); + + if (!(i->rec_stream = pa_stream_new(i->context, stream_name(), &i->sample_spec, NULL))) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + pa_stream_set_state_callback(i->rec_stream, stream_state_cb, i); + pa_stream_set_read_callback(i->rec_stream, stream_request_cb, i); + pa_stream_set_latency_update_callback(i->rec_stream, stream_latency_update_cb, i); + + memset(&attr, 0, sizeof(attr)); + attr.maxlength = i->fragment_size * (i->n_fragments+1); + attr.fragsize = i->fragment_size; + + if (pa_stream_connect_record(i->rec_stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE) < 0) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + n = i->fragment_size; + setsockopt(i->app_fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)); + n = i->fragment_size; + setsockopt(i->thread_fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)); + + return 0; + +fail: + return -1; +} + +static void free_streams(fd_info *i) { + assert(i); + + if (i->play_stream) { + pa_stream_disconnect(i->play_stream); + pa_stream_unref(i->play_stream); + i->play_stream = NULL; + } + + if (i->rec_stream) { + pa_stream_disconnect(i->rec_stream); + pa_stream_unref(i->rec_stream); + i->rec_stream = NULL; } } @@ -834,17 +994,24 @@ static void io_event_cb(pa_mainloop_api *api, pa_io_event *e, int fd, pa_io_even if (flags & PA_IO_EVENT_INPUT) { - if (!i->stream) { - api->io_enable(e, 0); - - if (create_stream(i) < 0) + if (!i->play_stream) { + if (create_playback_stream(i) < 0) goto fail; - } else { if (fd_info_copy_data(i, 0) < 0) goto fail; } + } else if (flags & PA_IO_EVENT_OUTPUT) { + + if (!i->rec_stream) { + if (create_record_stream(i) < 0) + goto fail; + } else { + if (fd_info_copy_data(i, 0) < 0) + goto fail; + } + } else if (flags & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) goto fail; @@ -860,21 +1027,13 @@ static int dsp_open(int flags, int *_errno) { pa_mainloop_api *api; int ret; int f; + pa_io_event_flags_t ioflags; debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open()\n"); - if ((flags != O_WRONLY) && (flags != (O_WRONLY|O_NONBLOCK))) { - debug(DEBUG_LEVEL_NORMAL, __FILE__": bad access flags: %x\n", flags); - *_errno = EACCES; - return -1; - } - - if (!(i = fd_info_new(FD_INFO_PLAYBACK, _errno))) + if (!(i = fd_info_new(FD_INFO_STREAM, _errno))) return -1; - shutdown(i->thread_fd, SHUT_WR); - shutdown(i->app_fd, SHUT_RD); - if ((flags & O_NONBLOCK) == O_NONBLOCK) { if ((f = fcntl(i->app_fd, F_GETFL)) >= 0) fcntl(i->app_fd, F_SETFL, f|O_NONBLOCK); @@ -887,7 +1046,26 @@ static int dsp_open(int flags, int *_errno) { pa_threaded_mainloop_lock(i->mainloop); api = pa_threaded_mainloop_get_api(i->mainloop); - if (!(i->io_event = api->io_new(api, i->thread_fd, PA_IO_EVENT_INPUT, io_event_cb, i))) + + switch (flags & O_ACCMODE) { + case O_RDONLY: + ioflags = PA_IO_EVENT_OUTPUT; + shutdown(i->thread_fd, SHUT_RD); + shutdown(i->app_fd, SHUT_WR); + break; + case O_WRONLY: + ioflags = PA_IO_EVENT_INPUT; + shutdown(i->thread_fd, SHUT_WR); + shutdown(i->app_fd, SHUT_RD); + break; + case O_RDWR: + ioflags = PA_IO_EVENT_INPUT | PA_IO_EVENT_OUTPUT; + break; + default: + return -1; + } + + if (!(i->io_event = api->io_new(api, i->thread_fd, ioflags, io_event_cb, i))) goto fail; pa_threaded_mainloop_unlock(i->mainloop); @@ -925,16 +1103,38 @@ static void sink_info_cb(pa_context *context, const pa_sink_info *si, int eol, v if (eol) return; - if (!pa_cvolume_equal(&i->volume, &si->volume)) + if (!pa_cvolume_equal(&i->sink_volume, &si->volume)) i->volume_modify_count++; - i->volume = si->volume; + i->sink_volume = si->volume; i->sink_index = si->index; i->operation_success = 1; pa_threaded_mainloop_signal(i->mainloop, 0); } +static void source_info_cb(pa_context *context, const pa_source_info *si, int eol, void *userdata) { + fd_info *i = userdata; + + if (!si && eol < 0) { + i->operation_success = 0; + pa_threaded_mainloop_signal(i->mainloop, 0); + return; + } + + if (eol) + return; + + if (!pa_cvolume_equal(&i->source_volume, &si->volume)) + i->volume_modify_count++; + + i->source_volume = si->volume; + i->source_index = si->index; + + i->operation_success = 1; + pa_threaded_mainloop_signal(i->mainloop, 0); +} + static void subscribe_cb(pa_context *context, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { fd_info *i = userdata; pa_operation *o = NULL; @@ -955,7 +1155,7 @@ static void subscribe_cb(pa_context *context, pa_subscription_event_type_t t, ui static int mixer_open(int flags, int *_errno) { fd_info *i; - pa_operation *o; + pa_operation *o = NULL; int ret; debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open()\n"); @@ -967,7 +1167,7 @@ static int mixer_open(int flags, int *_errno) { pa_context_set_subscribe_callback(i->context, subscribe_cb, i); - if (!(o = pa_context_subscribe(i->context, PA_SUBSCRIPTION_MASK_SINK, context_success_cb, i))) { + if (!(o = pa_context_subscribe(i->context, PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE, context_success_cb, i))) { debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context))); *_errno = EIO; goto fail; @@ -979,6 +1179,9 @@ static int mixer_open(int flags, int *_errno) { CONTEXT_CHECK_DEAD_GOTO(i, fail); } + pa_operation_unref(o); + o = NULL; + if (!i->operation_success) { debug(DEBUG_LEVEL_NORMAL, __FILE__":Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context))); *_errno = EIO; @@ -987,7 +1190,6 @@ static int mixer_open(int flags, int *_errno) { /* Get sink info */ - pa_operation_unref(o); if (!(o = pa_context_get_sink_info_by_name(i->context, NULL, sink_info_cb, i))) { debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); *_errno = EIO; @@ -1000,12 +1202,38 @@ static int mixer_open(int flags, int *_errno) { CONTEXT_CHECK_DEAD_GOTO(i, fail); } + pa_operation_unref(o); + o = NULL; + if (!i->operation_success) { debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context))); *_errno = EIO; goto fail; } + /* Get source info */ + + if (!(o = pa_context_get_source_info_by_name(i->context, NULL, source_info_cb, i))) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get source info: %s", pa_strerror(pa_context_errno(i->context))); + *_errno = EIO; + goto fail; + } + + i->operation_success = 0; + while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + pa_threaded_mainloop_wait(i->mainloop); + CONTEXT_CHECK_DEAD_GOTO(i, fail); + } + + pa_operation_unref(o); + o = NULL; + + if (!i->operation_success) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get source info: %s", pa_strerror(pa_context_errno(i->context))); + *_errno = EIO; + goto fail; + } + pa_threaded_mainloop_unlock(i->mainloop); debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open() succeeded, fd=%i\n", i->app_fd); @@ -1017,6 +1245,9 @@ static int mixer_open(int flags, int *_errno) { return ret; fail: + if (o) + pa_operation_unref(o); + pa_threaded_mainloop_unlock(i->mainloop); if (i) @@ -1143,20 +1374,24 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno case SOUND_MIXER_READ_DEVMASK : debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_DEVMASK\n"); - *(int*) argp = SOUND_MASK_PCM; + *(int*) argp = SOUND_MASK_PCM | SOUND_MASK_IGAIN; break; case SOUND_MIXER_READ_RECMASK : debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_RECMASK\n"); - *(int*) argp = 0; + *(int*) argp = SOUND_MASK_IGAIN; break; case SOUND_MIXER_READ_STEREODEVS: debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_STEREODEVS\n"); pa_threaded_mainloop_lock(i->mainloop); - *(int*) argp = i->volume.channels > 1 ? SOUND_MASK_PCM : 0; + *(int*) argp = 0; + if (i->sink_volume.channels > 1) + *(int*) argp |= SOUND_MASK_PCM; + if (i->source_volume.channels > 1) + *(int*) argp |= SOUND_MASK_IGAIN; pa_threaded_mainloop_unlock(i->mainloop); break; @@ -1164,9 +1399,13 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno case SOUND_MIXER_READ_RECSRC: debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_RECSRC\n"); - *(int*) argp = 0; + *(int*) argp = SOUND_MASK_IGAIN; break; - + + case SOUND_MIXER_WRITE_RECSRC: + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_RECSRC\n"); + break; + case SOUND_MIXER_READ_CAPS: debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_CAPS\n"); @@ -1174,35 +1413,61 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno break; case SOUND_MIXER_READ_PCM: - - debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_PCM\n"); - + case SOUND_MIXER_READ_IGAIN: { + pa_cvolume *v; + + if (request == SOUND_MIXER_READ_PCM) + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_PCM\n"); + else + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_IGAIN\n"); + pa_threaded_mainloop_lock(i->mainloop); + if (request == SOUND_MIXER_READ_PCM) + v = &i->sink_volume; + else + v = &i->source_volume; + *(int*) argp = - ((i->volume.values[0]*100/PA_VOLUME_NORM)) | - ((i->volume.values[i->volume.channels > 1 ? 1 : 0]*100/PA_VOLUME_NORM) << 8); - + ((v->values[0]*100/PA_VOLUME_NORM)) | + ((v->values[v->channels > 1 ? 1 : 0]*100/PA_VOLUME_NORM) << 8); + pa_threaded_mainloop_unlock(i->mainloop); - + break; + } + + case SOUND_MIXER_WRITE_PCM: + case SOUND_MIXER_WRITE_IGAIN: { + pa_cvolume v, *pv; + + if (request == SOUND_MIXER_READ_PCM) + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_PCM\n"); + else + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_IGAIN\n"); - case SOUND_MIXER_WRITE_PCM: { - pa_cvolume v; - - debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_PCM\n"); - pa_threaded_mainloop_lock(i->mainloop); - v = i->volume; - - i->volume.values[0] = ((*(int*) argp & 0xFF)*PA_VOLUME_NORM)/100; - i->volume.values[1] = ((*(int*) argp >> 8)*PA_VOLUME_NORM)/100; + if (request == SOUND_MIXER_READ_PCM) { + v = i->sink_volume; + pv = &i->sink_volume; + } else { + v = i->source_volume; + pv = &i->source_volume; + } + + pv->values[0] = ((*(int*) argp & 0xFF)*PA_VOLUME_NORM)/100; + pv->values[1] = ((*(int*) argp >> 8)*PA_VOLUME_NORM)/100; - if (!pa_cvolume_equal(&i->volume, &v)) { + if (!pa_cvolume_equal(pv, &v)) { pa_operation *o; - - if (!(o = pa_context_set_sink_volume_by_index(i->context, i->sink_index, &i->volume, NULL, NULL))) + + if (request == SOUND_MIXER_READ_PCM) + o = pa_context_set_sink_volume_by_index(i->context, i->sink_index, pv, NULL, NULL); + else + o = pa_context_set_source_volume_by_index(i->context, i->source_index, pv, NULL, NULL); + + if (!o) debug(DEBUG_LEVEL_NORMAL, __FILE__":Failed set volume: %s", pa_strerror(pa_context_errno(i->context))); else { @@ -1310,13 +1575,10 @@ static int map_format_back(pa_sample_format_t format) { } } -static int dsp_flush_socket(fd_info *i) { +static int dsp_flush_fd(int fd) { int l; - - if (i->thread_fd < 0) - return -1; - if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { + if (ioctl(fd, SIOCINQ, &l) < 0) { debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ: %s\n", strerror(errno)); return -1; } @@ -1326,7 +1588,7 @@ static int dsp_flush_socket(fd_info *i) { size_t k; k = (size_t) l > sizeof(buf) ? sizeof(buf) : (size_t) l; - if (read(i->thread_fd, buf, k) < 0) + if (read(fd, buf, k) < 0) debug(DEBUG_LEVEL_NORMAL, __FILE__": read(): %s\n", strerror(errno)); l -= k; } @@ -1334,6 +1596,27 @@ static int dsp_flush_socket(fd_info *i) { return 0; } +static int dsp_flush_socket(fd_info *i) { + int res = 0; + + if ((i->thread_fd < 0) && (i->app_fd < 0)) + return -1; + + if (i->thread_fd >= 0) + res = dsp_flush_fd(i->thread_fd); + + if (res < 0) + return res; + + if (i->app_fd >= 0) + res = dsp_flush_fd(i->app_fd); + + if (res < 0) + return res; + + return 0; +} + static int dsp_empty_socket(fd_info *i) { int ret = -1; @@ -1374,19 +1657,19 @@ static int dsp_drain(fd_info *i) { if (dsp_empty_socket(i) < 0) goto fail; - if (!i->stream) + if (!i->play_stream) goto fail; debug(DEBUG_LEVEL_NORMAL, __FILE__": Really draining.\n"); - if (!(o = pa_stream_drain(i->stream, stream_success_cb, i))) { + if (!(o = pa_stream_drain(i->play_stream, stream_success_cb, i))) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } i->operation_success = 0; while (pa_operation_get_state(o) != PA_OPERATION_DONE) { - STREAM_CHECK_DEAD_GOTO(i, fail); + PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, fail); pa_threaded_mainloop_wait(i->mainloop); } @@ -1412,7 +1695,7 @@ static int dsp_trigger(fd_info *i) { pa_operation *o = NULL; int r = -1; - if (!i->stream) + if (!i->play_stream) return 0; pa_threaded_mainloop_lock(i->mainloop); @@ -1422,14 +1705,14 @@ static int dsp_trigger(fd_info *i) { debug(DEBUG_LEVEL_NORMAL, __FILE__": Triggering.\n"); - if (!(o = pa_stream_trigger(i->stream, stream_success_cb, i))) { + if (!(o = pa_stream_trigger(i->play_stream, stream_success_cb, i))) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } i->operation_success = 0; while (!pa_operation_get_state(o) != PA_OPERATION_DONE) { - STREAM_CHECK_DEAD_GOTO(i, fail); + PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, fail); pa_threaded_mainloop_wait(i->mainloop); } @@ -1464,7 +1747,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) *(int*) argp = map_format_back(i->sample_spec.format); else { map_format((int*) argp, &i->sample_spec); - free_stream(i); + free_streams(i); } pa_threaded_mainloop_unlock(i->mainloop); @@ -1485,7 +1768,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) if ((valid = pa_sample_spec_valid(&ss))) { i->sample_spec = ss; - free_stream(i); + free_streams(i); } debug(DEBUG_LEVEL_NORMAL, __FILE__": ss: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); @@ -1506,7 +1789,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_threaded_mainloop_lock(i->mainloop); i->sample_spec.channels = *(int*) argp ? 2 : 1; - free_stream(i); + free_streams(i); pa_threaded_mainloop_unlock(i->mainloop); return 0; @@ -1524,7 +1807,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) if ((valid = pa_sample_spec_valid(&ss))) { i->sample_spec = ss; - free_stream(i); + free_streams(i); } pa_threaded_mainloop_unlock(i->mainloop); @@ -1557,7 +1840,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) i->fragment_size = 1 << (*(int*) argp); i->n_fragments = (*(int*) argp) >> 16; - free_stream(i); + free_streams(i); pa_threaded_mainloop_unlock(i->mainloop); @@ -1566,7 +1849,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_GETCAPS: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CAPS\n"); - *(int*) argp = DSP_CAP_MULTI; + *(int*) argp = DSP_CAP_DUPLEX | DSP_CAP_MULTI; break; case SNDCTL_DSP_GETODELAY: { @@ -1581,9 +1864,9 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) for (;;) { pa_usec_t usec; - STREAM_CHECK_DEAD_GOTO(i, exit_loop); + PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, exit_loop); - if (pa_stream_get_latency(i->stream, &usec, NULL) >= 0) { + if (pa_stream_get_latency(i->play_stream, &usec, NULL) >= 0) { *(int*) argp = pa_usec_to_bytes(usec, &i->sample_spec); break; } @@ -1615,7 +1898,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_threaded_mainloop_lock(i->mainloop); - free_stream(i); + free_streams(i); dsp_flush_socket(i); reset_params(i); @@ -1645,31 +1928,51 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) break; - case SNDCTL_DSP_GETOSPACE: { + case SNDCTL_DSP_GETOSPACE: + case SNDCTL_DSP_GETISPACE: { audio_buf_info *bi = (audio_buf_info*) argp; int l; size_t k = 0; - debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETOSPACE\n"); + if (request == SNDCTL_DSP_GETOSPACE) + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETOSPACE\n"); + else + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETISPACE\n"); pa_threaded_mainloop_lock(i->mainloop); fix_metrics(i); - - if (i->stream) { - if ((k = pa_stream_writable_size(i->stream)) == (size_t) -1) - debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); - } else - k = i->fragment_size * i->n_fragments; - - if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { - debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno)); - l = 0; + + if (request == SNDCTL_DSP_GETOSPACE) { + if (i->play_stream) { + if ((k = pa_stream_writable_size(i->play_stream)) == (size_t) -1) + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); + } else + k = i->fragment_size * i->n_fragments; + + if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno)); + l = 0; + } + + bi->bytes = k > (size_t) l ? k - l : 0; + } else { + if (i->rec_stream) { + if ((k = pa_stream_readable_size(i->rec_stream)) == (size_t) -1) + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_readable_size(): %s\n", pa_strerror(pa_context_errno(i->context))); + } else + k = 0; + + if (ioctl(i->app_fd, SIOCINQ, &l) < 0) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno)); + l = 0; + } + + bi->bytes = k + l; } bi->fragsize = i->fragment_size; bi->fragstotal = i->n_fragments; - bi->bytes = k > (size_t) l ? k - l : 0; bi->fragments = bi->bytes / bi->fragsize; pa_threaded_mainloop_unlock(i->mainloop); -- cgit From e66b0e6d3f235a65913c17a549bed74fd414445a Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 16 Jun 2006 21:08:35 +0000 Subject: Creating a stream might take some time, so check that it's in the right state before transferring data. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1022 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index b0e76327..be935060 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -767,7 +767,7 @@ static int fd_info_copy_data(fd_info *i, int force) { flags = 0; - if (i->play_stream) { + if ((i->play_stream) && (pa_stream_get_state(i->play_stream) == PA_STREAM_READY)) { n = pa_stream_writable_size(i->play_stream); if (n == (size_t)-1) { @@ -810,7 +810,7 @@ static int fd_info_copy_data(fd_info *i, int force) { flags |= PA_IO_EVENT_INPUT; } - if (i->rec_stream) { + if ((i->rec_stream) && (pa_stream_get_state(i->rec_stream) == PA_STREAM_READY)) { n = pa_stream_readable_size(i->rec_stream); if (n == (size_t)-1) { -- cgit From 8485a477053f7ea9549a1ca588c32b5379ba2d36 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 16 Jun 2006 21:11:45 +0000 Subject: /dev/dsp should default to U8, not mulaw. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1023 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index be935060..e25fdfd8 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -392,7 +392,7 @@ static void context_state_cb(pa_context *c, void *userdata) { static void reset_params(fd_info *i) { assert(i); - i->sample_spec.format = PA_SAMPLE_ULAW; + i->sample_spec.format = PA_SAMPLE_U8; i->sample_spec.channels = 1; i->sample_spec.rate = 8000; i->fragment_size = 0; -- cgit From e26bd47282e679b384568f4dd916f13277b271fa Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 17 Jun 2006 23:36:03 +0000 Subject: * make hw param settings easier to debug by splitting up long if * actually set the sample rate * disable resampling done by ALSA git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1024 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 2ead58c8..fafcac48 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -323,12 +323,24 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p if ((ret = snd_pcm_hw_params_malloc(&hwparams)) < 0 || (ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 || - (ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0 || - (ret = set_format(pcm_handle, hwparams, &f)) < 0 || - (ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0 || - (*period_size > 0 && (ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL)) < 0) || - (*periods > 0 && (ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0) || - (ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) + (ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0 || + (ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) + goto finish; + + if ((ret = set_format(pcm_handle, hwparams, &f)) < 0) + goto finish; + + if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0) + goto finish; + + if ((ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0) + goto finish; + + if ((*period_size > 0 && (ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL)) < 0) || + (*periods > 0 && (ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0)) + goto finish; + + if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) goto finish; if (ss->rate != r) { -- cgit From 5e1127a2346857b93d66be15a29339ef3c572f7d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 17 Jun 2006 23:37:07 +0000 Subject: * implement volume adjusting and mixing for S16RE * some optimizations git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1025 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polypcore/sample-util.c | 86 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 3 deletions(-) diff --git a/src/polypcore/sample-util.c b/src/polypcore/sample-util.c index d06fa95f..7a75ce1c 100644 --- a/src/polypcore/sample-util.c +++ b/src/polypcore/sample-util.c @@ -33,6 +33,7 @@ #include #include "sample-util.h" +#include "endianmacros.h" pa_memblock *pa_silence_memblock_new(const pa_sample_spec *spec, size_t length, pa_memblock_stat*s) { assert(spec); @@ -138,6 +139,54 @@ size_t pa_mix( channel = 0; } } + + case PA_SAMPLE_S16RE:{ + size_t d; + unsigned channel = 0; + + for (d = 0;; d += sizeof(int16_t)) { + int32_t sum = 0; + + if (d >= length) + return d; + + if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { + unsigned i; + + for (i = 0; i < nstreams; i++) { + int32_t v; + pa_volume_t cvolume = streams[i].volume.values[channel]; + + if (d >= streams[i].chunk.length) + return d; + + if (cvolume == PA_VOLUME_MUTED) + v = 0; + else { + v = INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d))); + + if (cvolume != PA_VOLUME_NORM) + v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); + } + + sum += v; + } + + if (volume->values[channel] != PA_VOLUME_NORM) + sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); + + if (sum < -0x8000) sum = -0x8000; + if (sum > 0x7FFF) sum = 0x7FFF; + + } + + *((int16_t*) data) = INT16_SWAP(sum); + data = (uint8_t*) data + sizeof(int16_t); + + if (++channel >= spec->channels) + channel = 0; + } + } case PA_SAMPLE_U8: { size_t d; @@ -232,6 +281,7 @@ size_t pa_mix( } default: + pa_log_error(__FILE__": ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format)); abort(); } } @@ -253,12 +303,16 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol case PA_SAMPLE_S16NE: { int16_t *d; size_t n; - unsigned channel = 0; + unsigned channel; + double linear[PA_CHANNELS_MAX]; + + for (channel = 0; channel < spec->channels; channel++) + linear[channel] = pa_sw_volume_to_linear(volume->values[channel]); - for (d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { + for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { int32_t t = (int32_t)(*d); - t = (int32_t) (t * pa_sw_volume_to_linear(volume->values[channel])); + t = (int32_t) (t * linear[channel]); if (t < -0x8000) t = -0x8000; if (t > 0x7FFF) t = 0x7FFF; @@ -270,6 +324,32 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol } break; } + + case PA_SAMPLE_S16RE: { + int16_t *d; + size_t n; + unsigned channel; + double linear[PA_CHANNELS_MAX]; + + for (channel = 0; channel < spec->channels; channel++) + linear[channel] = pa_sw_volume_to_linear(volume->values[channel]); + + for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { + int32_t t = (int32_t)(INT16_SWAP(*d)); + + t = (int32_t) (t * linear[channel]); + + if (t < -0x8000) t = -0x8000; + if (t > 0x7FFF) t = 0x7FFF; + + *d = INT16_SWAP((int16_t) t); + + if (++channel >= spec->channels) + channel = 0; + } + + break; + } case PA_SAMPLE_U8: { uint8_t *d; -- cgit From bd432f0590bdda2c42887f1d6da07ff0bb571013 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 18 Jun 2006 11:10:45 +0000 Subject: * add new argument 'exit_on_eof' to module-cli and make use of it if "-C" is passed to the daemon git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1026 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/modules.html.in | 4 +++- doc/todo | 1 - src/daemon/cmdline.c | 2 +- src/modules/module-cli.c | 58 +++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 51 insertions(+), 14 deletions(-) diff --git a/doc/modules.html.in b/doc/modules.html.in index af6b6de6..85479523 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -193,7 +193,9 @@ once.

      For an explanation of the simple command line language used by this module see cli.html. -

      This module doesn't accept any arguments.

      + + +
      exit_on_eof=Accepts a binary numerical argument specifying whether the daemon shuld exit after an EOF was recieved from STDIN (default: 0)
      diff --git a/doc/todo b/doc/todo index 7b83ea98..1ea40d3e 100644 --- a/doc/todo +++ b/doc/todo @@ -35,7 +35,6 @@ Post 0.9.0: - check if using prctl(PR_GET_NAME) makes sense in pa_get_binary_name() - gconf module + frontend - hooks for creating sink inputs -- module-cli argument exit-on-eof Long term: - pass meta info for hearing impaired diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c index 21fd5a25..b71be2e6 100644 --- a/src/daemon/cmdline.c +++ b/src/daemon/cmdline.c @@ -186,7 +186,7 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d break; case 'C': - pa_strbuf_puts(buf, "load-module module-cli\n"); + pa_strbuf_puts(buf, "load-module module-cli exit_on_eof=1\n"); break; case ARG_DAEMONIZE: diff --git a/src/modules/module-cli.c b/src/modules/module-cli.c index 41e33c7f..ce50a46b 100644 --- a/src/modules/module-cli.c +++ b/src/modules/module-cli.c @@ -32,38 +32,64 @@ #include #include #include +#include #include "module-cli-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Command line interface") PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("No arguments") +PA_MODULE_USAGE("exit_on_eof=") -static void eof_cb(pa_cli*c, void *userdata) { +static const char* const valid_modargs[] = { + "exit_on_eof", + NULL +}; + +static void eof_and_unload_cb(pa_cli*c, void *userdata) { pa_module *m = userdata; - assert(c && m); + + assert(c); + assert(m); pa_module_unload_request(m); } +static void eof_and_exit_cb(pa_cli*c, void *userdata) { + pa_module *m = userdata; + + assert(c); + assert(m); + + m->core->mainloop->quit(m->core->mainloop, 0); +} + int pa__init(pa_core *c, pa_module*m) { pa_iochannel *io; - assert(c && m); + pa_modargs *ma; + int exit_on_eof = 0; + + assert(c); + assert(m); if (c->running_as_daemon) { - pa_log_info(__FILE__": Running as daemon so won't load this module."); + pa_log_info(__FILE__": Running as daemon, refusing to load this module."); return 0; } - if (m->argument) { - pa_log(__FILE__": module doesn't accept arguments."); - return -1; + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments."); + goto fail; } + if (pa_modargs_get_value_boolean(ma, "exit_on_eof", &exit_on_eof) < 0) { + pa_log(__FILE__": exit_on_eof= expects boolean argument."); + goto fail; + } + if (pa_stdio_acquire() < 0) { pa_log(__FILE__": STDIN/STDUSE already in use."); - return -1; + goto fail; } io = pa_iochannel_new(c->mainloop, STDIN_FILENO, STDOUT_FILENO); @@ -73,13 +99,23 @@ int pa__init(pa_core *c, pa_module*m) { m->userdata = pa_cli_new(c, io, m); assert(m->userdata); - pa_cli_set_eof_callback(m->userdata, eof_cb, m); + pa_cli_set_eof_callback(m->userdata, exit_on_eof ? eof_and_exit_cb : eof_and_unload_cb, m); + + pa_modargs_free(ma); return 0; + +fail: + + if (ma) + pa_modargs_free(ma); + + return -1; } void pa__done(pa_core *c, pa_module*m) { - assert(c && m); + assert(c); + assert(m); if (c->running_as_daemon == 0) { pa_cli_free(m->userdata); -- cgit From 9f59b4e1cd516dbbc8a4978146bc94f2a1ce75eb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 11:27:00 +0000 Subject: add new test "interpol-test" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1027 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 6 ++ src/tests/interpol-test.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 src/tests/interpol-test.c diff --git a/src/Makefile.am b/src/Makefile.am index 2dc2c663..6a2decb3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -189,6 +189,7 @@ noinst_PROGRAMS = \ voltest \ memblockq-test \ sync-playback \ + interpol-test \ channelmap-test \ thread-mainloop-test \ utf8-test @@ -284,6 +285,11 @@ sync_playback_LDADD = $(AM_LDADD) libpolyp.la sync_playback_CFLAGS = $(AM_CFLAGS) sync_playback_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +interpol_test_SOURCES = tests/interpol-test.c +interpol_test_LDADD = $(AM_LDADD) libpolyp.la +interpol_test_CFLAGS = $(AM_CFLAGS) +interpol_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + ################################### # Client library # ################################### diff --git a/src/tests/interpol-test.c b/src/tests/interpol-test.c new file mode 100644 index 00000000..26a92dbf --- /dev/null +++ b/src/tests/interpol-test.c @@ -0,0 +1,168 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static pa_context *context = NULL; +static pa_stream *stream = NULL; +static pa_mainloop_api *mainloop_api = NULL; + +static void stream_write_cb(pa_stream *p, size_t length, void *userdata) { + + /* Just some silence */ + pa_stream_write(p, pa_xmalloc0(length), length, pa_xfree, 0, PA_SEEK_RELATIVE); +} + +/* This is called whenever the context status changes */ +static void context_state_callback(pa_context *c, void *userdata) { + assert(c); + + switch (pa_context_get_state(c)) { + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + + case PA_CONTEXT_READY: { + + static const pa_sample_spec ss = { + .format = PA_SAMPLE_S16LE, + .rate = 44100, + .channels = 1 + }; + + fprintf(stderr, "Connection established.\n"); + + stream = pa_stream_new(c, "interpol-test", &ss, NULL); + assert(stream); + + pa_stream_connect_playback(stream, NULL, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); + pa_stream_set_write_callback(stream, stream_write_cb, NULL); + + break; + } + + case PA_CONTEXT_TERMINATED: + break; + + case PA_CONTEXT_FAILED: + default: + fprintf(stderr, "Context error: %s\n", pa_strerror(pa_context_errno(c))); + abort(); + } +} + +int main(int argc, char *argv[]) { + pa_threaded_mainloop* m = NULL; + int k, r; + struct timeval start, last_info = { 0, 0 }; + pa_usec_t old_t = 0, old_rtc = 0; + + /* Set up a new main loop */ + m = pa_threaded_mainloop_new(); + assert(m); + + mainloop_api = pa_threaded_mainloop_get_api(m); + + context = pa_context_new(mainloop_api, argv[0]); + assert(context); + + pa_context_set_state_callback(context, context_state_callback, NULL); + + r = pa_context_connect(context, NULL, 0, NULL); + assert(r >= 0); + + pa_gettimeofday(&start); + + pa_threaded_mainloop_start(m); + + for (k = 0; k < 5000; k++) { + int success = 0, changed = 0; + pa_usec_t t, rtc; + struct timeval now, tv; + + pa_threaded_mainloop_lock(m); + + if (stream) { + const pa_timing_info *info; + + if (pa_stream_get_time(stream, &t) >= 0) + success = 1; + + if ((info = pa_stream_get_timing_info(stream))) + if (last_info.tv_usec != info->timestamp.tv_usec || last_info.tv_sec != info->timestamp.tv_sec) { + changed = 1; + last_info = info->timestamp; + } + } + + pa_threaded_mainloop_unlock(m); + + if (success) { + pa_gettimeofday(&now); + + rtc = pa_timeval_diff(&now, &start); + printf("%i\t%llu\t%llu\t%llu\t%llu\t%u\n", k, rtc, t, rtc-old_rtc, t-old_t, changed*2000000); + old_t = t; + old_rtc = rtc; + } + + /* Spin loop, eerks but normal usleep is just to badly grained */ + + tv = now; + while (pa_timeval_diff(pa_gettimeofday(&now), &tv) < 1000) + pthread_yield(); + } + + if (m) + pa_threaded_mainloop_stop(m); + + if (stream) { + pa_stream_disconnect(stream); + pa_stream_unref(stream); + } + + if (context) { + pa_context_disconnect(context); + pa_context_unref(context); + } + + if (m) + pa_threaded_mainloop_free(m); + + return 0; +} -- cgit From 6eabab6e2b093933bf489e6c94b13433d03584d2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 12:20:10 +0000 Subject: minor cleanups git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1028 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/tests/interpol-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/interpol-test.c b/src/tests/interpol-test.c index 26a92dbf..fa5fae7d 100644 --- a/src/tests/interpol-test.c +++ b/src/tests/interpol-test.c @@ -136,12 +136,12 @@ int main(int argc, char *argv[]) { pa_gettimeofday(&now); rtc = pa_timeval_diff(&now, &start); - printf("%i\t%llu\t%llu\t%llu\t%llu\t%u\n", k, rtc, t, rtc-old_rtc, t-old_t, changed*2000000); + printf("%i\t%llu\t%llu\t%llu\t%llu\t%u\n", k, rtc, t, rtc-old_rtc, t-old_t, changed); old_t = t; old_rtc = rtc; } - /* Spin loop, eerks but normal usleep is just to badly grained */ + /* Spin loop, ugly but normal usleep() is just too badly grained */ tv = now; while (pa_timeval_diff(pa_gettimeofday(&now), &tv) < 1000) -- cgit From 40494c3bc1f109b0d0d2e9e04cda814e9856ff1f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 12:37:43 +0000 Subject: * rework latency interpolation to make it smoother * increase latency update interval to 100ms git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1029 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/polyp/internal.h | 5 ++--- src/polyp/stream.c | 26 ++++++++++---------------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/polyp/internal.h b/src/polyp/internal.h index 80c28616..e659553d 100644 --- a/src/polyp/internal.h +++ b/src/polyp/internal.h @@ -136,9 +136,8 @@ struct pa_stream { pa_time_event *auto_timing_update_event; int auto_timing_update_requested; - pa_usec_t ipol_usec; - int ipol_usec_valid; - struct timeval ipol_timestamp; + pa_usec_t cached_time; + int cached_time_valid; /* Callbacks */ pa_stream_notify_cb_t state_callback; diff --git a/src/polyp/stream.c b/src/polyp/stream.c index e3f40a3f..8927805e 100644 --- a/src/polyp/stream.c +++ b/src/polyp/stream.c @@ -38,7 +38,7 @@ #include "internal.h" -#define LATENCY_IPOL_INTERVAL_USEC (10000L) +#define LATENCY_IPOL_INTERVAL_USEC (100000L) pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map) { pa_stream *s; @@ -102,9 +102,7 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->corked = 0; - s->ipol_usec_valid = 0; - s->ipol_timestamp.tv_sec = 0; - s->ipol_timestamp.tv_usec = 0; + s->cached_time_valid = 0; s->auto_timing_update_event = NULL; s->auto_timing_update_requested = 0; @@ -367,7 +365,7 @@ static void invalidate_indexes(pa_stream *s, int r, int w) { if ((s->direction == PA_STREAM_PLAYBACK && r) || (s->direction == PA_STREAM_RECORD && w)) - s->ipol_usec_valid = 0; + s->cached_time_valid = 0; request_auto_timing_update(s, 1); } @@ -855,8 +853,7 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, i->read_index -= pa_memblockq_get_length(o->stream->record_memblockq); } - o->stream->ipol_timestamp = now; - o->stream->ipol_usec_valid = 0; + o->stream->cached_time_valid = 0; } o->stream->auto_timing_update_requested = 0; @@ -1203,8 +1200,9 @@ int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) { PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_PLAYBACK || !s->timing_info.read_index_corrupt, PA_ERR_NODATA); PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_RECORD || !s->timing_info.write_index_corrupt, PA_ERR_NODATA); - if (s->flags & PA_STREAM_INTERPOLATE_TIMING && s->ipol_usec_valid) - usec = s->ipol_usec; + if (s->cached_time_valid) + /* We alredy calculated the time value for this timing info, so let's reuse it */ + usec = s->cached_time; else { if (s->direction == PA_STREAM_PLAYBACK) { /* The last byte that was written into the output device @@ -1247,10 +1245,8 @@ int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) { } } - if (s->flags & PA_STREAM_INTERPOLATE_TIMING) { - s->ipol_usec = usec; - s->ipol_usec_valid = 1; - } + s->cached_time = usec; + s->cached_time_valid = 1; } /* Interpolate if requested */ @@ -1260,9 +1256,7 @@ int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) { * current */ if (!s->corked) { struct timeval now; - - usec += pa_timeval_diff(pa_gettimeofday(&now), &s->ipol_timestamp); - s->ipol_timestamp = now; + usec += pa_timeval_diff(pa_gettimeofday(&now), &s->timing_info.timestamp); } } -- cgit From c6d4cc0af9497a4376fa1dcb33a28c9a54264109 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 19 Jun 2006 16:39:28 +0000 Subject: Handle clients that just want to set fragment size (and not count). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1030 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index e25fdfd8..56acbb28 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1839,7 +1839,11 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) i->fragment_size = 1 << (*(int*) argp); i->n_fragments = (*(int*) argp) >> 16; - + + /* 0x7FFF means that we can set whatever we like */ + if (i->n_fragments == 0x7FFF) + i->n_fragments = 12; + free_streams(i); pa_threaded_mainloop_unlock(i->mainloop); -- cgit -- cgit -- cgit From f44ba092651aa75055e109e04b4164ea92ae7fdc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 21:53:48 +0000 Subject: big s/polyp/pulse/g git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1033 fefdeb5f-60dc-0310-8127-8f9354f1896f --- LICENSE | 8 +- Makefile.am | 29 +- bootstrap.sh | 8 +- configure.ac | 28 +- doc/FAQ.html.in | 52 +- doc/Makefile.am | 8 +- doc/README.html.in | 108 +- doc/cli.html.in | 6 +- doc/daemon.html.in | 8 +- doc/modules.html.in | 28 +- doc/style.css | 8 +- doxygen/Makefile.am | 8 +- doxygen/doxygen.conf.in | 4 +- libpulse-browse.pc.in | 11 + libpulse-glib-mainloop.pc.in | 11 + libpulse-glib12-mainloop.pc.in | 11 + libpulse-simple.pc.in | 11 + libpulse.pc.in | 11 + polyplib-browse.pc.in | 11 - polyplib-glib-mainloop.pc.in | 11 - polyplib-glib12-mainloop.pc.in | 11 - polyplib-simple.pc.in | 11 - polyplib.pc.in | 11 - src/Makefile.am | 796 ++++----- src/daemon/Makefile | 2 +- src/daemon/caps.c | 12 +- src/daemon/caps.h | 8 +- src/daemon/cmdline.c | 14 +- src/daemon/cmdline.h | 8 +- src/daemon/cpulimit.c | 16 +- src/daemon/cpulimit.h | 12 +- src/daemon/daemon-conf.c | 26 +- src/daemon/daemon-conf.h | 10 +- src/daemon/daemon.conf.in | 16 +- src/daemon/default.pa.in | 8 +- src/daemon/default.pa.win32 | 8 +- src/daemon/dumpmodules.c | 12 +- src/daemon/dumpmodules.h | 8 +- src/daemon/esdcompat.in | 8 +- src/daemon/main.c | 42 +- src/depmod.py | 8 +- src/modules/Makefile | 2 +- src/modules/alsa-util.c | 14 +- src/modules/alsa-util.h | 14 +- src/modules/howl-wrap.c | 14 +- src/modules/howl-wrap.h | 10 +- src/modules/module-alsa-sink.c | 26 +- src/modules/module-alsa-source.c | 30 +- src/modules/module-cli.c | 20 +- src/modules/module-combine.c | 32 +- src/modules/module-defs.h.m4 | 4 +- src/modules/module-detect.c | 20 +- src/modules/module-esound-compat-spawnfd.c | 18 +- src/modules/module-esound-compat-spawnpid.c | 18 +- src/modules/module-esound-sink.c | 32 +- src/modules/module-jack-sink.c | 28 +- src/modules/module-jack-source.c | 28 +- src/modules/module-lirc.c | 22 +- src/modules/module-match.c | 30 +- src/modules/module-mmkbd-evdev.c | 24 +- src/modules/module-native-protocol-fd.c | 18 +- src/modules/module-null-sink.c | 24 +- src/modules/module-oss-mmap.c | 30 +- src/modules/module-oss.c | 30 +- src/modules/module-pipe-sink.c | 24 +- src/modules/module-pipe-source.c | 24 +- src/modules/module-protocol-stub.c | 48 +- src/modules/module-sine.c | 20 +- src/modules/module-solaris.c | 32 +- src/modules/module-tunnel.c | 44 +- src/modules/module-volume-restore.c | 30 +- src/modules/module-waveout.c | 26 +- src/modules/module-x11-bell.c | 24 +- src/modules/module-x11-publish.c | 42 +- src/modules/module-zeroconf-publish.c | 38 +- src/modules/oss-util.c | 14 +- src/modules/oss-util.h | 12 +- src/modules/rtp/module-rtp-recv.c | 36 +- src/modules/rtp/module-rtp-send.c | 36 +- src/modules/rtp/rtp.c | 12 +- src/modules/rtp/rtp.h | 12 +- src/modules/rtp/sap.c | 16 +- src/modules/rtp/sap.h | 12 +- src/modules/rtp/sdp.c | 14 +- src/modules/rtp/sdp.h | 10 +- src/polyp/Makefile | 13 - src/polyp/browser.c | 334 ---- src/polyp/browser.h | 68 - src/polyp/cdecl.h | 42 - src/polyp/channelmap.c | 445 ----- src/polyp/channelmap.h | 191 -- src/polyp/client-conf-x11.c | 93 - src/polyp/client-conf-x11.h | 31 - src/polyp/client-conf.c | 193 -- src/polyp/client-conf.h | 52 - src/polyp/client.conf.in | 39 - src/polyp/context.c | 980 ----------- src/polyp/context.h | 230 --- src/polyp/def.h | 312 ---- src/polyp/error.c | 66 - src/polyp/error.h | 38 - src/polyp/glib-mainloop.c | 541 ------ src/polyp/glib-mainloop.h | 66 - src/polyp/glib12-mainloop.c | 503 ------ src/polyp/internal.h | 210 --- src/polyp/introspect.c | 1240 ------------- src/polyp/introspect.h | 490 ------ src/polyp/mainloop-api.c | 70 - src/polyp/mainloop-api.h | 118 -- src/polyp/mainloop-signal.c | 210 --- src/polyp/mainloop-signal.h | 59 - src/polyp/mainloop.c | 839 --------- src/polyp/mainloop.h | 127 -- src/polyp/operation.c | 116 -- src/polyp/operation.h | 50 - src/polyp/polypaudio.h | 115 -- src/polyp/sample.c | 156 -- src/polyp/sample.h | 189 -- src/polyp/scache.c | 131 -- src/polyp/scache.h | 100 -- src/polyp/simple.c | 455 ----- src/polyp/simple.h | 146 -- src/polyp/stream.c | 1366 --------------- src/polyp/stream.h | 449 ----- src/polyp/subscribe.c | 89 - src/polyp/subscribe.h | 61 - src/polyp/thread-mainloop.c | 466 ----- src/polyp/thread-mainloop.h | 299 ---- src/polyp/timeval.c | 142 -- src/polyp/timeval.h | 53 - src/polyp/utf8.c | 237 --- src/polyp/utf8.h | 47 - src/polyp/util.c | 227 --- src/polyp/util.h | 59 - src/polyp/version.h.in | 53 - src/polyp/volume.c | 176 -- src/polyp/volume.h | 172 -- src/polyp/xmalloc.c | 128 -- src/polyp/xmalloc.h | 78 - src/polypcore/Makefile | 1 - src/polypcore/authkey-prop.c | 89 - src/polypcore/authkey-prop.h | 43 - src/polypcore/authkey.c | 209 --- src/polypcore/authkey.h | 32 - src/polypcore/autoload.c | 182 -- src/polypcore/autoload.h | 58 - src/polypcore/cli-command.c | 947 ---------- src/polypcore/cli-command.h | 40 - src/polypcore/cli-text.c | 387 ---- src/polypcore/cli-text.h | 42 - src/polypcore/cli.c | 149 -- src/polypcore/cli.h | 38 - src/polypcore/client.c | 96 - src/polypcore/client.h | 57 - src/polypcore/conf-parser.c | 181 -- src/polypcore/conf-parser.h | 47 - src/polypcore/core-def.h | 30 - src/polypcore/core-error.c | 205 --- src/polypcore/core-error.h | 41 - src/polypcore/core-scache.c | 412 ----- src/polypcore/core-scache.h | 64 - src/polypcore/core-subscribe.c | 233 --- src/polypcore/core-subscribe.h | 37 - src/polypcore/core-util.c | 1023 ----------- src/polypcore/core-util.h | 88 - src/polypcore/core.c | 160 -- src/polypcore/core.h | 82 - src/polypcore/dllmain.c | 55 - src/polypcore/dynarray.c | 103 -- src/polypcore/dynarray.h | 49 - src/polypcore/endianmacros.h | 77 - src/polypcore/esound.h | 209 --- src/polypcore/g711.c | 2531 --------------------------- src/polypcore/g711.h | 40 - src/polypcore/gccmacro.h | 53 - src/polypcore/hashmap.c | 196 --- src/polypcore/hashmap.h | 53 - src/polypcore/idxset.c | 391 ----- src/polypcore/idxset.h | 94 - src/polypcore/inet_ntop.c | 80 - src/polypcore/inet_ntop.h | 12 - src/polypcore/inet_pton.c | 62 - src/polypcore/inet_pton.h | 12 - src/polypcore/iochannel.c | 417 ----- src/polypcore/iochannel.h | 81 - src/polypcore/ioline.c | 394 ----- src/polypcore/ioline.h | 51 - src/polypcore/llist.h | 79 - src/polypcore/log.c | 211 --- src/polypcore/log.h | 69 - src/polypcore/mcalign.c | 206 --- src/polypcore/mcalign.h | 80 - src/polypcore/memblock.c | 173 -- src/polypcore/memblock.h | 86 - src/polypcore/memblockq.c | 636 ------- src/polypcore/memblockq.h | 140 -- src/polypcore/memchunk.c | 59 - src/polypcore/memchunk.h | 45 - src/polypcore/modargs.c | 310 ---- src/polypcore/modargs.h | 60 - src/polypcore/modinfo.c | 93 - src/polypcore/modinfo.h | 43 - src/polypcore/module.c | 319 ---- src/polypcore/module.h | 70 - src/polypcore/namereg.c | 214 --- src/polypcore/namereg.h | 43 - src/polypcore/native-common.h | 127 -- src/polypcore/packet.c | 79 - src/polypcore/packet.h | 41 - src/polypcore/parseaddr.c | 115 -- src/polypcore/parseaddr.h | 42 - src/polypcore/pdispatch.c | 318 ---- src/polypcore/pdispatch.h | 53 - src/polypcore/pid.c | 304 ---- src/polypcore/pid.h | 30 - src/polypcore/pipe.c | 160 -- src/polypcore/pipe.h | 31 - src/polypcore/play-memchunk.c | 117 -- src/polypcore/play-memchunk.h | 36 - src/polypcore/poll.c | 191 -- src/polypcore/poll.h | 57 - src/polypcore/props.c | 121 -- src/polypcore/props.h | 58 - src/polypcore/protocol-cli.c | 97 - src/polypcore/protocol-cli.h | 35 - src/polypcore/protocol-esound.c | 1253 ------------- src/polypcore/protocol-esound.h | 35 - src/polypcore/protocol-http.c | 268 --- src/polypcore/protocol-http.h | 35 - src/polypcore/protocol-native.c | 2398 ------------------------- src/polypcore/protocol-native.h | 37 - src/polypcore/protocol-simple.c | 494 ------ src/polypcore/protocol-simple.h | 35 - src/polypcore/pstream-util.c | 62 - src/polypcore/pstream-util.h | 37 - src/polypcore/pstream.c | 589 ------- src/polypcore/pstream.h | 57 - src/polypcore/queue.c | 109 -- src/polypcore/queue.h | 40 - src/polypcore/random.c | 108 -- src/polypcore/random.h | 28 - src/polypcore/resampler.c | 618 ------- src/polypcore/resampler.h | 73 - src/polypcore/sample-util.c | 405 ----- src/polypcore/sample-util.h | 55 - src/polypcore/sconv-s16be.c | 41 - src/polypcore/sconv-s16be.h | 28 - src/polypcore/sconv-s16le.c | 103 -- src/polypcore/sconv-s16le.h | 28 - src/polypcore/sconv.c | 169 -- src/polypcore/sconv.h | 33 - src/polypcore/sink-input.c | 386 ---- src/polypcore/sink-input.h | 107 -- src/polypcore/sink.c | 513 ------ src/polypcore/sink.h | 101 -- src/polypcore/sioman.c | 43 - src/polypcore/sioman.h | 28 - src/polypcore/socket-client.c | 526 ------ src/polypcore/socket-client.h | 47 - src/polypcore/socket-server.c | 505 ------ src/polypcore/socket-server.h | 51 - src/polypcore/socket-util.c | 266 --- src/polypcore/socket-util.h | 38 - src/polypcore/sound-file-stream.c | 192 -- src/polypcore/sound-file-stream.h | 29 - src/polypcore/sound-file.c | 163 -- src/polypcore/sound-file.h | 33 - src/polypcore/source-output.c | 241 --- src/polypcore/source-output.h | 92 - src/polypcore/source.c | 313 ---- src/polypcore/source.h | 101 -- src/polypcore/strbuf.c | 167 -- src/polypcore/strbuf.h | 38 - src/polypcore/strlist.c | 139 -- src/polypcore/strlist.h | 47 - src/polypcore/tagstruct.c | 630 ------- src/polypcore/tagstruct.h | 93 - src/polypcore/tokenizer.c | 90 - src/polypcore/tokenizer.h | 32 - src/polypcore/winsock.h | 24 - src/polypcore/x11prop.c | 70 - src/polypcore/x11prop.h | 33 - src/polypcore/x11wrap.c | 247 --- src/polypcore/x11wrap.h | 52 - src/pulse/Makefile | 13 + src/pulse/browser.c | 334 ++++ src/pulse/browser.h | 68 + src/pulse/cdecl.h | 42 + src/pulse/channelmap.c | 445 +++++ src/pulse/channelmap.h | 191 ++ src/pulse/client-conf-x11.c | 93 + src/pulse/client-conf-x11.h | 31 + src/pulse/client-conf.c | 193 ++ src/pulse/client-conf.h | 52 + src/pulse/client.conf.in | 39 + src/pulse/context.c | 980 +++++++++++ src/pulse/context.h | 230 +++ src/pulse/def.h | 312 ++++ src/pulse/error.c | 66 + src/pulse/error.h | 38 + src/pulse/glib-mainloop.c | 541 ++++++ src/pulse/glib-mainloop.h | 66 + src/pulse/glib12-mainloop.c | 503 ++++++ src/pulse/internal.h | 210 +++ src/pulse/introspect.c | 1240 +++++++++++++ src/pulse/introspect.h | 490 ++++++ src/pulse/mainloop-api.c | 70 + src/pulse/mainloop-api.h | 118 ++ src/pulse/mainloop-signal.c | 210 +++ src/pulse/mainloop-signal.h | 59 + src/pulse/mainloop.c | 839 +++++++++ src/pulse/mainloop.h | 127 ++ src/pulse/operation.c | 116 ++ src/pulse/operation.h | 50 + src/pulse/polypaudio.h | 115 ++ src/pulse/sample.c | 156 ++ src/pulse/sample.h | 189 ++ src/pulse/scache.c | 131 ++ src/pulse/scache.h | 100 ++ src/pulse/simple.c | 455 +++++ src/pulse/simple.h | 146 ++ src/pulse/stream.c | 1366 +++++++++++++++ src/pulse/stream.h | 449 +++++ src/pulse/subscribe.c | 89 + src/pulse/subscribe.h | 61 + src/pulse/thread-mainloop.c | 466 +++++ src/pulse/thread-mainloop.h | 299 ++++ src/pulse/timeval.c | 142 ++ src/pulse/timeval.h | 53 + src/pulse/utf8.c | 237 +++ src/pulse/utf8.h | 47 + src/pulse/util.c | 227 +++ src/pulse/util.h | 59 + src/pulse/version.h.in | 53 + src/pulse/volume.c | 176 ++ src/pulse/volume.h | 172 ++ src/pulse/xmalloc.c | 128 ++ src/pulse/xmalloc.h | 78 + src/pulsecore/Makefile | 1 + src/pulsecore/authkey-prop.c | 89 + src/pulsecore/authkey-prop.h | 43 + src/pulsecore/authkey.c | 209 +++ src/pulsecore/authkey.h | 32 + src/pulsecore/autoload.c | 182 ++ src/pulsecore/autoload.h | 58 + src/pulsecore/cli-command.c | 947 ++++++++++ src/pulsecore/cli-command.h | 40 + src/pulsecore/cli-text.c | 387 ++++ src/pulsecore/cli-text.h | 42 + src/pulsecore/cli.c | 149 ++ src/pulsecore/cli.h | 38 + src/pulsecore/client.c | 96 + src/pulsecore/client.h | 57 + src/pulsecore/conf-parser.c | 181 ++ src/pulsecore/conf-parser.h | 47 + src/pulsecore/core-def.h | 30 + src/pulsecore/core-error.c | 205 +++ src/pulsecore/core-error.h | 41 + src/pulsecore/core-scache.c | 412 +++++ src/pulsecore/core-scache.h | 64 + src/pulsecore/core-subscribe.c | 233 +++ src/pulsecore/core-subscribe.h | 37 + src/pulsecore/core-util.c | 1023 +++++++++++ src/pulsecore/core-util.h | 88 + src/pulsecore/core.c | 160 ++ src/pulsecore/core.h | 82 + src/pulsecore/dllmain.c | 55 + src/pulsecore/dynarray.c | 103 ++ src/pulsecore/dynarray.h | 49 + src/pulsecore/endianmacros.h | 77 + src/pulsecore/esound.h | 209 +++ src/pulsecore/g711.c | 2531 +++++++++++++++++++++++++++ src/pulsecore/g711.h | 40 + src/pulsecore/gccmacro.h | 53 + src/pulsecore/hashmap.c | 196 +++ src/pulsecore/hashmap.h | 53 + src/pulsecore/idxset.c | 391 +++++ src/pulsecore/idxset.h | 94 + src/pulsecore/inet_ntop.c | 80 + src/pulsecore/inet_ntop.h | 12 + src/pulsecore/inet_pton.c | 62 + src/pulsecore/inet_pton.h | 12 + src/pulsecore/iochannel.c | 417 +++++ src/pulsecore/iochannel.h | 81 + src/pulsecore/ioline.c | 394 +++++ src/pulsecore/ioline.h | 51 + src/pulsecore/llist.h | 79 + src/pulsecore/log.c | 211 +++ src/pulsecore/log.h | 69 + src/pulsecore/mcalign.c | 206 +++ src/pulsecore/mcalign.h | 80 + src/pulsecore/memblock.c | 173 ++ src/pulsecore/memblock.h | 86 + src/pulsecore/memblockq.c | 636 +++++++ src/pulsecore/memblockq.h | 140 ++ src/pulsecore/memchunk.c | 59 + src/pulsecore/memchunk.h | 45 + src/pulsecore/modargs.c | 310 ++++ src/pulsecore/modargs.h | 60 + src/pulsecore/modinfo.c | 93 + src/pulsecore/modinfo.h | 43 + src/pulsecore/module.c | 319 ++++ src/pulsecore/module.h | 70 + src/pulsecore/namereg.c | 214 +++ src/pulsecore/namereg.h | 43 + src/pulsecore/native-common.h | 127 ++ src/pulsecore/packet.c | 79 + src/pulsecore/packet.h | 41 + src/pulsecore/parseaddr.c | 115 ++ src/pulsecore/parseaddr.h | 42 + src/pulsecore/pdispatch.c | 318 ++++ src/pulsecore/pdispatch.h | 53 + src/pulsecore/pid.c | 304 ++++ src/pulsecore/pid.h | 30 + src/pulsecore/pipe.c | 160 ++ src/pulsecore/pipe.h | 31 + src/pulsecore/play-memchunk.c | 117 ++ src/pulsecore/play-memchunk.h | 36 + src/pulsecore/poll.c | 191 ++ src/pulsecore/poll.h | 57 + src/pulsecore/props.c | 121 ++ src/pulsecore/props.h | 58 + src/pulsecore/protocol-cli.c | 97 + src/pulsecore/protocol-cli.h | 35 + src/pulsecore/protocol-esound.c | 1253 +++++++++++++ src/pulsecore/protocol-esound.h | 35 + src/pulsecore/protocol-http.c | 268 +++ src/pulsecore/protocol-http.h | 35 + src/pulsecore/protocol-native.c | 2398 +++++++++++++++++++++++++ src/pulsecore/protocol-native.h | 37 + src/pulsecore/protocol-simple.c | 494 ++++++ src/pulsecore/protocol-simple.h | 35 + src/pulsecore/pstream-util.c | 62 + src/pulsecore/pstream-util.h | 37 + src/pulsecore/pstream.c | 589 +++++++ src/pulsecore/pstream.h | 57 + src/pulsecore/queue.c | 109 ++ src/pulsecore/queue.h | 40 + src/pulsecore/random.c | 108 ++ src/pulsecore/random.h | 28 + src/pulsecore/resampler.c | 618 +++++++ src/pulsecore/resampler.h | 73 + src/pulsecore/sample-util.c | 405 +++++ src/pulsecore/sample-util.h | 55 + src/pulsecore/sconv-s16be.c | 41 + src/pulsecore/sconv-s16be.h | 28 + src/pulsecore/sconv-s16le.c | 103 ++ src/pulsecore/sconv-s16le.h | 28 + src/pulsecore/sconv.c | 169 ++ src/pulsecore/sconv.h | 33 + src/pulsecore/sink-input.c | 386 ++++ src/pulsecore/sink-input.h | 107 ++ src/pulsecore/sink.c | 513 ++++++ src/pulsecore/sink.h | 101 ++ src/pulsecore/sioman.c | 43 + src/pulsecore/sioman.h | 28 + src/pulsecore/socket-client.c | 526 ++++++ src/pulsecore/socket-client.h | 47 + src/pulsecore/socket-server.c | 505 ++++++ src/pulsecore/socket-server.h | 51 + src/pulsecore/socket-util.c | 266 +++ src/pulsecore/socket-util.h | 38 + src/pulsecore/sound-file-stream.c | 192 ++ src/pulsecore/sound-file-stream.h | 29 + src/pulsecore/sound-file.c | 163 ++ src/pulsecore/sound-file.h | 33 + src/pulsecore/source-output.c | 241 +++ src/pulsecore/source-output.h | 92 + src/pulsecore/source.c | 313 ++++ src/pulsecore/source.h | 101 ++ src/pulsecore/strbuf.c | 167 ++ src/pulsecore/strbuf.h | 38 + src/pulsecore/strlist.c | 139 ++ src/pulsecore/strlist.h | 47 + src/pulsecore/tagstruct.c | 630 +++++++ src/pulsecore/tagstruct.h | 93 + src/pulsecore/tokenizer.c | 90 + src/pulsecore/tokenizer.h | 32 + src/pulsecore/winsock.h | 24 + src/pulsecore/x11prop.c | 70 + src/pulsecore/x11prop.h | 33 + src/pulsecore/x11wrap.c | 247 +++ src/pulsecore/x11wrap.h | 52 + src/tests/Makefile | 2 +- src/tests/channelmap-test.c | 4 +- src/tests/cpulimit-test.c | 14 +- src/tests/interpol-test.c | 12 +- src/tests/mainloop-test.c | 18 +- src/tests/mcalign-test.c | 14 +- src/tests/memblockq-test.c | 12 +- src/tests/pacat-simple.c | 14 +- src/tests/parec-simple.c | 14 +- src/tests/strlist-test.c | 6 +- src/tests/sync-playback.c | 12 +- src/tests/thread-mainloop-test.c | 16 +- src/tests/utf8-test.c | 4 +- src/tests/voltest.c | 4 +- src/utils/Makefile | 2 +- src/utils/pabrowse.c | 12 +- src/utils/pacat.c | 12 +- src/utils/pacmd.c | 18 +- src/utils/pactl.c | 12 +- src/utils/padsp | 12 +- src/utils/padsp.c | 14 +- src/utils/paplay.c | 12 +- src/utils/pax11publish.c | 22 +- 506 files changed, 41970 insertions(+), 41965 deletions(-) create mode 100644 libpulse-browse.pc.in create mode 100644 libpulse-glib-mainloop.pc.in create mode 100644 libpulse-glib12-mainloop.pc.in create mode 100644 libpulse-simple.pc.in create mode 100644 libpulse.pc.in delete mode 100644 polyplib-browse.pc.in delete mode 100644 polyplib-glib-mainloop.pc.in delete mode 100644 polyplib-glib12-mainloop.pc.in delete mode 100644 polyplib-simple.pc.in delete mode 100644 polyplib.pc.in delete mode 100644 src/polyp/Makefile delete mode 100644 src/polyp/browser.c delete mode 100644 src/polyp/browser.h delete mode 100644 src/polyp/cdecl.h delete mode 100644 src/polyp/channelmap.c delete mode 100644 src/polyp/channelmap.h delete mode 100644 src/polyp/client-conf-x11.c delete mode 100644 src/polyp/client-conf-x11.h delete mode 100644 src/polyp/client-conf.c delete mode 100644 src/polyp/client-conf.h delete mode 100644 src/polyp/client.conf.in delete mode 100644 src/polyp/context.c delete mode 100644 src/polyp/context.h delete mode 100644 src/polyp/def.h delete mode 100644 src/polyp/error.c delete mode 100644 src/polyp/error.h delete mode 100644 src/polyp/glib-mainloop.c delete mode 100644 src/polyp/glib-mainloop.h delete mode 100644 src/polyp/glib12-mainloop.c delete mode 100644 src/polyp/internal.h delete mode 100644 src/polyp/introspect.c delete mode 100644 src/polyp/introspect.h delete mode 100644 src/polyp/mainloop-api.c delete mode 100644 src/polyp/mainloop-api.h delete mode 100644 src/polyp/mainloop-signal.c delete mode 100644 src/polyp/mainloop-signal.h delete mode 100644 src/polyp/mainloop.c delete mode 100644 src/polyp/mainloop.h delete mode 100644 src/polyp/operation.c delete mode 100644 src/polyp/operation.h delete mode 100644 src/polyp/polypaudio.h delete mode 100644 src/polyp/sample.c delete mode 100644 src/polyp/sample.h delete mode 100644 src/polyp/scache.c delete mode 100644 src/polyp/scache.h delete mode 100644 src/polyp/simple.c delete mode 100644 src/polyp/simple.h delete mode 100644 src/polyp/stream.c delete mode 100644 src/polyp/stream.h delete mode 100644 src/polyp/subscribe.c delete mode 100644 src/polyp/subscribe.h delete mode 100644 src/polyp/thread-mainloop.c delete mode 100644 src/polyp/thread-mainloop.h delete mode 100644 src/polyp/timeval.c delete mode 100644 src/polyp/timeval.h delete mode 100644 src/polyp/utf8.c delete mode 100644 src/polyp/utf8.h delete mode 100644 src/polyp/util.c delete mode 100644 src/polyp/util.h delete mode 100644 src/polyp/version.h.in delete mode 100644 src/polyp/volume.c delete mode 100644 src/polyp/volume.h delete mode 100644 src/polyp/xmalloc.c delete mode 100644 src/polyp/xmalloc.h delete mode 120000 src/polypcore/Makefile delete mode 100644 src/polypcore/authkey-prop.c delete mode 100644 src/polypcore/authkey-prop.h delete mode 100644 src/polypcore/authkey.c delete mode 100644 src/polypcore/authkey.h delete mode 100644 src/polypcore/autoload.c delete mode 100644 src/polypcore/autoload.h delete mode 100644 src/polypcore/cli-command.c delete mode 100644 src/polypcore/cli-command.h delete mode 100644 src/polypcore/cli-text.c delete mode 100644 src/polypcore/cli-text.h delete mode 100644 src/polypcore/cli.c delete mode 100644 src/polypcore/cli.h delete mode 100644 src/polypcore/client.c delete mode 100644 src/polypcore/client.h delete mode 100644 src/polypcore/conf-parser.c delete mode 100644 src/polypcore/conf-parser.h delete mode 100644 src/polypcore/core-def.h delete mode 100644 src/polypcore/core-error.c delete mode 100644 src/polypcore/core-error.h delete mode 100644 src/polypcore/core-scache.c delete mode 100644 src/polypcore/core-scache.h delete mode 100644 src/polypcore/core-subscribe.c delete mode 100644 src/polypcore/core-subscribe.h delete mode 100644 src/polypcore/core-util.c delete mode 100644 src/polypcore/core-util.h delete mode 100644 src/polypcore/core.c delete mode 100644 src/polypcore/core.h delete mode 100644 src/polypcore/dllmain.c delete mode 100644 src/polypcore/dynarray.c delete mode 100644 src/polypcore/dynarray.h delete mode 100644 src/polypcore/endianmacros.h delete mode 100644 src/polypcore/esound.h delete mode 100644 src/polypcore/g711.c delete mode 100644 src/polypcore/g711.h delete mode 100644 src/polypcore/gccmacro.h delete mode 100644 src/polypcore/hashmap.c delete mode 100644 src/polypcore/hashmap.h delete mode 100644 src/polypcore/idxset.c delete mode 100644 src/polypcore/idxset.h delete mode 100644 src/polypcore/inet_ntop.c delete mode 100644 src/polypcore/inet_ntop.h delete mode 100644 src/polypcore/inet_pton.c delete mode 100644 src/polypcore/inet_pton.h delete mode 100644 src/polypcore/iochannel.c delete mode 100644 src/polypcore/iochannel.h delete mode 100644 src/polypcore/ioline.c delete mode 100644 src/polypcore/ioline.h delete mode 100644 src/polypcore/llist.h delete mode 100644 src/polypcore/log.c delete mode 100644 src/polypcore/log.h delete mode 100644 src/polypcore/mcalign.c delete mode 100644 src/polypcore/mcalign.h delete mode 100644 src/polypcore/memblock.c delete mode 100644 src/polypcore/memblock.h delete mode 100644 src/polypcore/memblockq.c delete mode 100644 src/polypcore/memblockq.h delete mode 100644 src/polypcore/memchunk.c delete mode 100644 src/polypcore/memchunk.h delete mode 100644 src/polypcore/modargs.c delete mode 100644 src/polypcore/modargs.h delete mode 100644 src/polypcore/modinfo.c delete mode 100644 src/polypcore/modinfo.h delete mode 100644 src/polypcore/module.c delete mode 100644 src/polypcore/module.h delete mode 100644 src/polypcore/namereg.c delete mode 100644 src/polypcore/namereg.h delete mode 100644 src/polypcore/native-common.h delete mode 100644 src/polypcore/packet.c delete mode 100644 src/polypcore/packet.h delete mode 100644 src/polypcore/parseaddr.c delete mode 100644 src/polypcore/parseaddr.h delete mode 100644 src/polypcore/pdispatch.c delete mode 100644 src/polypcore/pdispatch.h delete mode 100644 src/polypcore/pid.c delete mode 100644 src/polypcore/pid.h delete mode 100644 src/polypcore/pipe.c delete mode 100644 src/polypcore/pipe.h delete mode 100644 src/polypcore/play-memchunk.c delete mode 100644 src/polypcore/play-memchunk.h delete mode 100644 src/polypcore/poll.c delete mode 100644 src/polypcore/poll.h delete mode 100644 src/polypcore/props.c delete mode 100644 src/polypcore/props.h delete mode 100644 src/polypcore/protocol-cli.c delete mode 100644 src/polypcore/protocol-cli.h delete mode 100644 src/polypcore/protocol-esound.c delete mode 100644 src/polypcore/protocol-esound.h delete mode 100644 src/polypcore/protocol-http.c delete mode 100644 src/polypcore/protocol-http.h delete mode 100644 src/polypcore/protocol-native.c delete mode 100644 src/polypcore/protocol-native.h delete mode 100644 src/polypcore/protocol-simple.c delete mode 100644 src/polypcore/protocol-simple.h delete mode 100644 src/polypcore/pstream-util.c delete mode 100644 src/polypcore/pstream-util.h delete mode 100644 src/polypcore/pstream.c delete mode 100644 src/polypcore/pstream.h delete mode 100644 src/polypcore/queue.c delete mode 100644 src/polypcore/queue.h delete mode 100644 src/polypcore/random.c delete mode 100644 src/polypcore/random.h delete mode 100644 src/polypcore/resampler.c delete mode 100644 src/polypcore/resampler.h delete mode 100644 src/polypcore/sample-util.c delete mode 100644 src/polypcore/sample-util.h delete mode 100644 src/polypcore/sconv-s16be.c delete mode 100644 src/polypcore/sconv-s16be.h delete mode 100644 src/polypcore/sconv-s16le.c delete mode 100644 src/polypcore/sconv-s16le.h delete mode 100644 src/polypcore/sconv.c delete mode 100644 src/polypcore/sconv.h delete mode 100644 src/polypcore/sink-input.c delete mode 100644 src/polypcore/sink-input.h delete mode 100644 src/polypcore/sink.c delete mode 100644 src/polypcore/sink.h delete mode 100644 src/polypcore/sioman.c delete mode 100644 src/polypcore/sioman.h delete mode 100644 src/polypcore/socket-client.c delete mode 100644 src/polypcore/socket-client.h delete mode 100644 src/polypcore/socket-server.c delete mode 100644 src/polypcore/socket-server.h delete mode 100644 src/polypcore/socket-util.c delete mode 100644 src/polypcore/socket-util.h delete mode 100644 src/polypcore/sound-file-stream.c delete mode 100644 src/polypcore/sound-file-stream.h delete mode 100644 src/polypcore/sound-file.c delete mode 100644 src/polypcore/sound-file.h delete mode 100644 src/polypcore/source-output.c delete mode 100644 src/polypcore/source-output.h delete mode 100644 src/polypcore/source.c delete mode 100644 src/polypcore/source.h delete mode 100644 src/polypcore/strbuf.c delete mode 100644 src/polypcore/strbuf.h delete mode 100644 src/polypcore/strlist.c delete mode 100644 src/polypcore/strlist.h delete mode 100644 src/polypcore/tagstruct.c delete mode 100644 src/polypcore/tagstruct.h delete mode 100644 src/polypcore/tokenizer.c delete mode 100644 src/polypcore/tokenizer.h delete mode 100644 src/polypcore/winsock.h delete mode 100644 src/polypcore/x11prop.c delete mode 100644 src/polypcore/x11prop.h delete mode 100644 src/polypcore/x11wrap.c delete mode 100644 src/polypcore/x11wrap.h create mode 100644 src/pulse/Makefile create mode 100644 src/pulse/browser.c create mode 100644 src/pulse/browser.h create mode 100644 src/pulse/cdecl.h create mode 100644 src/pulse/channelmap.c create mode 100644 src/pulse/channelmap.h create mode 100644 src/pulse/client-conf-x11.c create mode 100644 src/pulse/client-conf-x11.h create mode 100644 src/pulse/client-conf.c create mode 100644 src/pulse/client-conf.h create mode 100644 src/pulse/client.conf.in create mode 100644 src/pulse/context.c create mode 100644 src/pulse/context.h create mode 100644 src/pulse/def.h create mode 100644 src/pulse/error.c create mode 100644 src/pulse/error.h create mode 100644 src/pulse/glib-mainloop.c create mode 100644 src/pulse/glib-mainloop.h create mode 100644 src/pulse/glib12-mainloop.c create mode 100644 src/pulse/internal.h create mode 100644 src/pulse/introspect.c create mode 100644 src/pulse/introspect.h create mode 100644 src/pulse/mainloop-api.c create mode 100644 src/pulse/mainloop-api.h create mode 100644 src/pulse/mainloop-signal.c create mode 100644 src/pulse/mainloop-signal.h create mode 100644 src/pulse/mainloop.c create mode 100644 src/pulse/mainloop.h create mode 100644 src/pulse/operation.c create mode 100644 src/pulse/operation.h create mode 100644 src/pulse/polypaudio.h create mode 100644 src/pulse/sample.c create mode 100644 src/pulse/sample.h create mode 100644 src/pulse/scache.c create mode 100644 src/pulse/scache.h create mode 100644 src/pulse/simple.c create mode 100644 src/pulse/simple.h create mode 100644 src/pulse/stream.c create mode 100644 src/pulse/stream.h create mode 100644 src/pulse/subscribe.c create mode 100644 src/pulse/subscribe.h create mode 100644 src/pulse/thread-mainloop.c create mode 100644 src/pulse/thread-mainloop.h create mode 100644 src/pulse/timeval.c create mode 100644 src/pulse/timeval.h create mode 100644 src/pulse/utf8.c create mode 100644 src/pulse/utf8.h create mode 100644 src/pulse/util.c create mode 100644 src/pulse/util.h create mode 100644 src/pulse/version.h.in create mode 100644 src/pulse/volume.c create mode 100644 src/pulse/volume.h create mode 100644 src/pulse/xmalloc.c create mode 100644 src/pulse/xmalloc.h create mode 120000 src/pulsecore/Makefile create mode 100644 src/pulsecore/authkey-prop.c create mode 100644 src/pulsecore/authkey-prop.h create mode 100644 src/pulsecore/authkey.c create mode 100644 src/pulsecore/authkey.h create mode 100644 src/pulsecore/autoload.c create mode 100644 src/pulsecore/autoload.h create mode 100644 src/pulsecore/cli-command.c create mode 100644 src/pulsecore/cli-command.h create mode 100644 src/pulsecore/cli-text.c create mode 100644 src/pulsecore/cli-text.h create mode 100644 src/pulsecore/cli.c create mode 100644 src/pulsecore/cli.h create mode 100644 src/pulsecore/client.c create mode 100644 src/pulsecore/client.h create mode 100644 src/pulsecore/conf-parser.c create mode 100644 src/pulsecore/conf-parser.h create mode 100644 src/pulsecore/core-def.h create mode 100644 src/pulsecore/core-error.c create mode 100644 src/pulsecore/core-error.h create mode 100644 src/pulsecore/core-scache.c create mode 100644 src/pulsecore/core-scache.h create mode 100644 src/pulsecore/core-subscribe.c create mode 100644 src/pulsecore/core-subscribe.h create mode 100644 src/pulsecore/core-util.c create mode 100644 src/pulsecore/core-util.h create mode 100644 src/pulsecore/core.c create mode 100644 src/pulsecore/core.h create mode 100644 src/pulsecore/dllmain.c create mode 100644 src/pulsecore/dynarray.c create mode 100644 src/pulsecore/dynarray.h create mode 100644 src/pulsecore/endianmacros.h create mode 100644 src/pulsecore/esound.h create mode 100644 src/pulsecore/g711.c create mode 100644 src/pulsecore/g711.h create mode 100644 src/pulsecore/gccmacro.h create mode 100644 src/pulsecore/hashmap.c create mode 100644 src/pulsecore/hashmap.h create mode 100644 src/pulsecore/idxset.c create mode 100644 src/pulsecore/idxset.h create mode 100644 src/pulsecore/inet_ntop.c create mode 100644 src/pulsecore/inet_ntop.h create mode 100644 src/pulsecore/inet_pton.c create mode 100644 src/pulsecore/inet_pton.h create mode 100644 src/pulsecore/iochannel.c create mode 100644 src/pulsecore/iochannel.h create mode 100644 src/pulsecore/ioline.c create mode 100644 src/pulsecore/ioline.h create mode 100644 src/pulsecore/llist.h create mode 100644 src/pulsecore/log.c create mode 100644 src/pulsecore/log.h create mode 100644 src/pulsecore/mcalign.c create mode 100644 src/pulsecore/mcalign.h create mode 100644 src/pulsecore/memblock.c create mode 100644 src/pulsecore/memblock.h create mode 100644 src/pulsecore/memblockq.c create mode 100644 src/pulsecore/memblockq.h create mode 100644 src/pulsecore/memchunk.c create mode 100644 src/pulsecore/memchunk.h create mode 100644 src/pulsecore/modargs.c create mode 100644 src/pulsecore/modargs.h create mode 100644 src/pulsecore/modinfo.c create mode 100644 src/pulsecore/modinfo.h create mode 100644 src/pulsecore/module.c create mode 100644 src/pulsecore/module.h create mode 100644 src/pulsecore/namereg.c create mode 100644 src/pulsecore/namereg.h create mode 100644 src/pulsecore/native-common.h create mode 100644 src/pulsecore/packet.c create mode 100644 src/pulsecore/packet.h create mode 100644 src/pulsecore/parseaddr.c create mode 100644 src/pulsecore/parseaddr.h create mode 100644 src/pulsecore/pdispatch.c create mode 100644 src/pulsecore/pdispatch.h create mode 100644 src/pulsecore/pid.c create mode 100644 src/pulsecore/pid.h create mode 100644 src/pulsecore/pipe.c create mode 100644 src/pulsecore/pipe.h create mode 100644 src/pulsecore/play-memchunk.c create mode 100644 src/pulsecore/play-memchunk.h create mode 100644 src/pulsecore/poll.c create mode 100644 src/pulsecore/poll.h create mode 100644 src/pulsecore/props.c create mode 100644 src/pulsecore/props.h create mode 100644 src/pulsecore/protocol-cli.c create mode 100644 src/pulsecore/protocol-cli.h create mode 100644 src/pulsecore/protocol-esound.c create mode 100644 src/pulsecore/protocol-esound.h create mode 100644 src/pulsecore/protocol-http.c create mode 100644 src/pulsecore/protocol-http.h create mode 100644 src/pulsecore/protocol-native.c create mode 100644 src/pulsecore/protocol-native.h create mode 100644 src/pulsecore/protocol-simple.c create mode 100644 src/pulsecore/protocol-simple.h create mode 100644 src/pulsecore/pstream-util.c create mode 100644 src/pulsecore/pstream-util.h create mode 100644 src/pulsecore/pstream.c create mode 100644 src/pulsecore/pstream.h create mode 100644 src/pulsecore/queue.c create mode 100644 src/pulsecore/queue.h create mode 100644 src/pulsecore/random.c create mode 100644 src/pulsecore/random.h create mode 100644 src/pulsecore/resampler.c create mode 100644 src/pulsecore/resampler.h create mode 100644 src/pulsecore/sample-util.c create mode 100644 src/pulsecore/sample-util.h create mode 100644 src/pulsecore/sconv-s16be.c create mode 100644 src/pulsecore/sconv-s16be.h create mode 100644 src/pulsecore/sconv-s16le.c create mode 100644 src/pulsecore/sconv-s16le.h create mode 100644 src/pulsecore/sconv.c create mode 100644 src/pulsecore/sconv.h create mode 100644 src/pulsecore/sink-input.c create mode 100644 src/pulsecore/sink-input.h create mode 100644 src/pulsecore/sink.c create mode 100644 src/pulsecore/sink.h create mode 100644 src/pulsecore/sioman.c create mode 100644 src/pulsecore/sioman.h create mode 100644 src/pulsecore/socket-client.c create mode 100644 src/pulsecore/socket-client.h create mode 100644 src/pulsecore/socket-server.c create mode 100644 src/pulsecore/socket-server.h create mode 100644 src/pulsecore/socket-util.c create mode 100644 src/pulsecore/socket-util.h create mode 100644 src/pulsecore/sound-file-stream.c create mode 100644 src/pulsecore/sound-file-stream.h create mode 100644 src/pulsecore/sound-file.c create mode 100644 src/pulsecore/sound-file.h create mode 100644 src/pulsecore/source-output.c create mode 100644 src/pulsecore/source-output.h create mode 100644 src/pulsecore/source.c create mode 100644 src/pulsecore/source.h create mode 100644 src/pulsecore/strbuf.c create mode 100644 src/pulsecore/strbuf.h create mode 100644 src/pulsecore/strlist.c create mode 100644 src/pulsecore/strlist.h create mode 100644 src/pulsecore/tagstruct.c create mode 100644 src/pulsecore/tagstruct.h create mode 100644 src/pulsecore/tokenizer.c create mode 100644 src/pulsecore/tokenizer.h create mode 100644 src/pulsecore/winsock.h create mode 100644 src/pulsecore/x11prop.c create mode 100644 src/pulsecore/x11prop.h create mode 100644 src/pulsecore/x11wrap.c create mode 100644 src/pulsecore/x11wrap.h diff --git a/LICENSE b/LICENSE index 0ef09512..bc633bd1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,13 +1,13 @@ -All Polypaudio source files are licensed under the GNU Lesser General Public +All PulseAudio source files are licensed under the GNU Lesser General Public License. (see file LGPL for details) However, the server side links to the GPL-only library 'libsamplerate' which practically downgrades the license of the server part to GPL (see file GPL for details), exercising section 3 of the LGPL. -Hence you should treat the client library ('libpolyp') of Polypaudio as being -LGPL licensed and the server part ('libpolypcore') as being GPL licensed. Since -the Polypaudio daemon and the modules link to 'libpolypcore' they are of course +Hence you should treat the client library ('libpulse') of Polypaudio as being +LGPL licensed and the server part ('libpulsecore') as being GPL licensed. Since +the PulseAudio daemon and the modules link to 'libpulsecore' they are of course also GPL licensed. -- Lennart Poettering, April 20th, 2006. diff --git a/Makefile.am b/Makefile.am index c7ea54f3..4174a39b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,19 +1,19 @@ # $Id$ # -# This file is part of polypaudio. +# This file is part of PulseAudio. # -# polypaudio is free software; you can redistribute it and/or modify +# PulseAudio is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # -# polypaudio is distributed in the hope that it will be useful, but +# PulseAudio is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software +# along with PulseAudio; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. @@ -24,16 +24,21 @@ MAINTAINERCLEANFILES = noinst_DATA = pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-browse.pc +pkgconfig_DATA = libpulse.pc libpulse-simple.pc + +if HAVE_HOWL +pkgconfig_DATA += \ + libpulse-browse.pc +endif if HAVE_GLIB20 pkgconfig_DATA += \ - polyplib-glib-mainloop.pc + libpulse-glib-mainloop.pc endif if HAVE_GLIB12 pkgconfig_DATA += \ - polyplib-glib12-mainloop.pc + libpulse-glib12-mainloop.pc endif if USE_LYNX @@ -49,11 +54,11 @@ endif homepage: all dist doxygen test -d $$HOME/homepage/private - mkdir -p $$HOME/homepage/private/projects/polypaudio $$HOME/homepage/private/projects/polypaudio/doxygen - cp polypaudio-@PACKAGE_VERSION@.tar.gz $$HOME/homepage/private/projects/polypaudio - cp doc/README.html doc/FAQ.html doc/cli.html doc/daemon.html doc/modules.html doc/style.css $$HOME/homepage/private/projects/polypaudio - cp -a doxygen/html/* $$HOME/homepage/private/projects/polypaudio/doxygen - ln -sf $$HOME/homepage/private/projects/polypaudio/README.html $$HOME/homepage/private/projects/polypaudio/index.html + mkdir -p $$HOME/homepage/private/projects/pulseaudio $$HOME/homepage/private/projects/pulseaudio/doxygen + cp pulseaudio-@PACKAGE_VERSION@.tar.gz $$HOME/homepage/private/projects/pulseaudio + cp doc/README.html doc/FAQ.html doc/cli.html doc/daemon.html doc/modules.html doc/style.css $$HOME/homepage/private/projects/pulseaudio + cp -a doxygen/html/* $$HOME/homepage/private/projects/pulseaudio/doxygen + ln -sf $$HOME/homepage/private/projects/pulseaudio/README.html $$HOME/homepage/private/projects/pulseaudio/index.html #distcleancheck: # @: diff --git a/bootstrap.sh b/bootstrap.sh index ea6758a4..1f8b29d0 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -1,20 +1,20 @@ #!/bin/bash # $Id$ -# This file is part of polypaudio. +# This file is part of PulseAudio. # -# polypaudio is free software; you can redistribute it and/or modify it +# PulseAudio is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # -# polypaudio is distributed in the hope that it will be useful, but +# PulseAudio is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software Foundation, +# along with PulseAudio; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. VERSION=1.9 diff --git a/configure.ac b/configure.ac index 0ccbe4f3..4f530347 100644 --- a/configure.ac +++ b/configure.ac @@ -3,20 +3,20 @@ # $Id$ -# This file is part of polypaudio. +# This file is part of PulseAudio. # -# polypaudio is free software; you can redistribute it and/or modify it +# PulseAudio is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # -# polypaudio is distributed in the hope that it will be useful, but +# PulseAudio is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software Foundation, +# along with PulseAudio; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. AC_PREREQ(2.57) @@ -25,13 +25,13 @@ m4_define(PA_MAJOR, [0]) m4_define(PA_MINOR, [9]) m4_define(PA_MICRO, [1]) -AC_INIT([polypaudio], PA_MAJOR.PA_MINOR.PA_MICRO,[mzcbylcnhqvb (at) 0pointer (dot) de]) +AC_INIT([pulseaudio], PA_MAJOR.PA_MINOR.PA_MICRO,[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([src/daemon/main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) AC_SUBST(PA_MAJORMINOR, "PA_MAJOR.PA_MINOR") -AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/polypaudio/]) +AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/pulseaudio/]) AC_SUBST(PA_API_VERSION, 9) AC_SUBST(PA_PROTOCOL_VERSION, 9) @@ -681,8 +681,8 @@ fi AC_ARG_WITH( [module-dir], - AC_HELP_STRING([--with-module-dir],[Directory where to install the modules to (defaults to ${libdir}/polypaudio-${PA_MAJORMINOR}/modules/]), - [modlibexecdir=$withval], [modlibexecdir="${libdir}/polypaudio-${PA_MAJORMINOR}/modules/"]) + AC_HELP_STRING([--with-module-dir],[Directory where to install the modules to (defaults to ${libdir}/pulse-${PA_MAJORMINOR}/modules/]), + [modlibexecdir=$withval], [modlibexecdir="${libdir}/pulse-${PA_MAJORMINOR}/modules/"]) AC_SUBST(modlibexecdir) @@ -695,11 +695,11 @@ AM_CONDITIONAL([FORCE_PREOPEN], [test "x$FORCE_PREOPEN" = "x1"]) AC_CONFIG_FILES([ Makefile src/Makefile -polyplib.pc -polyplib-simple.pc -polyplib-browse.pc -polyplib-glib-mainloop.pc -polyplib-glib12-mainloop.pc +libpulse.pc +libpulse-simple.pc +libpulse-browse.pc +libpulse-glib-mainloop.pc +libpulse-glib12-mainloop.pc doc/Makefile doc/README.html doc/cli.html @@ -707,7 +707,7 @@ doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf -src/polyp/version.h +src/pulse/version.h doc/FAQ.html ]) AC_OUTPUT diff --git a/doc/FAQ.html.in b/doc/FAQ.html.in index a042dd7b..d9550e95 100644 --- a/doc/FAQ.html.in +++ b/doc/FAQ.html.in @@ -2,7 +2,7 @@ -polypaudio: FAQ +pulseaudio: FAQ @@ -57,64 +57,64 @@ reimplement very much code for Polypaudio. It should be easy to implement limited support for libartsc based applications. Noone has done this yet. It is probably a better idea to - run arts on top of Polypaudio (through a polypaudio driver + run arts on top of Polypaudio (through a pulseaudio driver for aRts, which nobody has written yet). Another solution would be to embed Polypaudio in the aRts process.

    • I often hear noises when playing back with Polypaudio, what can I do?

      -

      There are to possible solutions: run polypaudio with argument +

      There are to possible solutions: run pulseaudio with argument --high-priority=1 and make yourself member of the group realtime, or increase the fragment sizes of the audio drivers. The former will allow Polypaudio to activate SCHED_FIFO high priority scheduling (root rights are dropped immediately after this). Keep in mind that this is a potential security hole!

    • -
    • The polypaudio executable is installed SUID root by default. Why this? Isn't this a potential security hole?

      +
    • The pulseaudio executable is installed SUID root by default. Why this? Isn't this a potential security hole?

      Polypaudio activates SCHED_FIFO scheduling if the user passes --high-priority=1. This will only succeed when executed as root, therefore the binary is marked SUID root by -default. Yes, this is a potential security hole. However, polypaudio +default. Yes, this is a potential security hole. However, pulseaudio tries its best to minimize the security threat: immediately after -startup polypaudio drops all capabilities except +startup pulseaudio drops all capabilities except CAP_SYS_NICE (At least on systems that support it, like Linux; see man 7 capabilities for more information). If the calling user is not a member of the group realtime (which is required to have a GID < 1000), root rights are dropped immediately. This means, you can -install polypaudio SUID root, but only a subset of your users (the +install pulseaudio SUID root, but only a subset of your users (the members of the group realtime) may make use of realtime scheduling. Keep in mind that these users might load their own binary -modules into the polypaudio daemon which may freeze the machine. The +modules into the pulseaudio daemon which may freeze the machine. The daemon has a minimal protection against CPU hogging (the daemon is killed after hogging more than 70% CPU for 5 seconds), but this may be circumvented easily by evildoers.

    • -
    • I want to run polypaudio only when it is needed, how do I do this?

      +
    • I want to run pulseaudio only when it is needed, how do I do this?

      Set autospawn = yes in client.conf. That -configuration file may be found either in /etc/polypaudio/ or -in ~/.polypaudio/.

    • +configuration file may be found either in /etc/pulseaudio/ or +in ~/.pulseaudio/.

      -
    • How do I list all polypaudio modules installed?

      +
    • How do I list all pulseaudio modules installed?

      -

      polypaudio --dump-modules

      +

      pulseaudio --dump-modules

      Add -v for terse usage instructions.

      -
    • How do I use polypaudio over the network?

      +
    • How do I use pulseaudio over the network?

      -

      Just set $POLYP_SERVER to the host name of the polypaudio +

      Just set $POLYP_SERVER to the host name of the pulseaudio server. For authentication you need the same auth cookies on all sides. For -that copy ~./polypaudio-cookie to all clients that shall +that copy ~./pulseaudio-cookie to all clients that shall be allowed to connect.

      Alternatively the authorization cookies can be stored in the X11 server.

    • -
    • Is polypaudio capable of providing synchronized audio playback over the network for movie players like mplayer?

      +
    • Is pulseaudio capable of providing synchronized audio playback over the network for movie players like mplayer?

      Yes! Unless your network is congested in some way (i.e. transfer latencies vary strongly) it works perfectly. Drop me an email for experimental patches for MPlayer.

      -
    • What environment variables does polypaudio care about?

      +
    • What environment variables does pulseaudio care about?

      The client honors: POLYP_SINK (default sink to connect to), POLYP_SOURCE (default source to connect to), POLYP_SERVER (default server to connect to, like ESPEAKER), POLYP_BINARY (the binary to start when autospawning a daemon), POLYP_CLIENTCONFIG (path to the client configuration file).

      @@ -126,31 +126,31 @@ be allowed to connect.

      A brilliant guy named Lennart Poettering once wrote a nifty tool for that purpose: bidilink. To -connect to a running polypaudio daemon try using the following commands:

      +connect to a running pulseaudio daemon try using the following commands:

      -
      killall -USR2 polypaudio
      -bidilink unix-client:/tmp/polypaudio/cli
      +
      killall -USR2 pulseaudio
      +bidilink unix-client:/tmp/pulseaudio/cli

      BTW: Someone should package this great tool for Debian!

      New: There's now a tool pacmd that automates sending SIGUSR2 to the daemon and running a bidilink like tool for you.

    • -
    • How do the polypaudio libraries decide where to connect to?

      +
    • How do the pulseaudio libraries decide where to connect to?

      The following rule applies:

      1. If the the application using the library specifies a server to connect to it is used. If the connection fails, the library fails too.
      2. If the environment variable POLYP_SERVER is defined the library connects to that server. If the connection fails, the library fails too.
      3. If $DISPLAY is set, the library tries to connect to that server and looks for the root window property POYLP_SERVER for the host to connect to. If POLYP_COOKIE is set it is used as authentication cookie.
      4. -
      5. If the client configuration file (~/.polypaudio/client.conf or /etc/polypaudio/client.conf) sets the server address, the library connects to that server. If the connection fails, the library fails too.
      6. -
      7. The library tries to connect to the default local UNIX socket for polypaudio servers. If the connection fails, it proceeds with the next item.
      8. -
      9. The library tries to connect to the default local TCP socket for polypaudio servers. If the connection fails, it proceeds with the next item.
      10. +
      11. If the client configuration file (~/.pulseaudio/client.conf or /etc/pulseaudio/client.conf) sets the server address, the library connects to that server. If the connection fails, the library fails too.
      12. +
      13. The library tries to connect to the default local UNIX socket for pulseaudio servers. If the connection fails, it proceeds with the next item.
      14. +
      15. The library tries to connect to the default local TCP socket for pulseaudio servers. If the connection fails, it proceeds with the next item.
      16. If $DISPLAY is set, the library tries to connect to the default TCP port of that host. If the connection fails, it proceeds with the next item.
      17. The connection fails.
    • -
    • Why the heck does libpolyp link against libX11?

      +
    • Why the heck does libpulse link against libX11?

      The Polypaudio client libraries look for some X11 root window properties for the credentials of the Polypaudio server to access. You may compile Polypaudio without X11 for disabling this feature.

    • diff --git a/doc/Makefile.am b/doc/Makefile.am index a5884abd..a58911ad 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,19 +1,19 @@ # $Id$ -# This file is part of polypaudio. +# This file is part of PulseAudio. # -# polypaudio is free software; you can redistribute it and/or modify it +# PulseAudio is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # -# polypaudio is distributed in the hope that it will be useful, but +# PulseAudio is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software Foundation, +# along with PulseAudio; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. noinst_DATA = README.html cli.html modules.html daemon.html FAQ.html diff --git a/doc/README.html.in b/doc/README.html.in index f35b2da9..2f6ad448 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -3,12 +3,12 @@ -polypaudio @PACKAGE_VERSION@ +pulseaudio @PACKAGE_VERSION@ -

      polypaudio @PACKAGE_VERSION@

      +

      pulseaudio @PACKAGE_VERSION@

      Copyright 2004-2006 Lennart Poettering <@PACKAGE_BUGREPORT@> and Pierre Ossman

      @@ -44,7 +44,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

      News

      Fri Jun 2 2006:

      Version 0.9.1 +href="@PACKAGE_URL@pulseaudio-0.9.1.tar.gz">Version 0.9.1 released; changes include: load modules even when libtool .la files are missing; generate better ALSA device names from module-detect; if an ALSA device doesn't support the @@ -53,7 +53,7 @@ suggests instead; amd64 portability; drop .sh suffix of esdcompat.sh; build system fixes; No API or ABI changes were made

      Fri May 26 2006:

      Version 0.9.0 +href="@PACKAGE_URL@pulseaudio-0.9.0.tar.gz">Version 0.9.0 released; changes include: new module module-volume-restore; new OSS API emulation tool padsp; require valid UTF8 strings everywhere; properly support ALSA channel maps for surround sound; @@ -62,7 +62,7 @@ main loop API for synchronous programs; introduce real shared object versioning; a few API additions; many, many bugfixes

      Fri Apr 28 2006:

      Version 0.8.1 +href="@PACKAGE_URL@pulseaudio-0.8.1.tar.gz">Version 0.8.1 released; changes include: support for specifying the channel map on the command lines of paplay and pacat and as arguments to the driver modules; ALSA hardware mixer compatibility; @@ -70,16 +70,16 @@ fix linking; properly remove PF_UNIX sockets when unloading protocol modules; fix sample cache; many other fixes

      Thu Apr 13 2006:

      Version 0.8 released; -changes include: too many to count - consider reading this blog entry for more information; many, many minor fixes.

      +href="@PACKAGE_URL@pulseaudio-0.8.tar.gz">Version 0.8 released; +changes include: too many to count - consider reading this blog entry for more information; many, many minor fixes.

      Sun Nov 21 2004:

      Version 0.7 released; +href="@PACKAGE_URL@pulseaudio-0.7.tar.gz">Version 0.7 released; changes include: IPv6 support; PID file support; publish credentials in X11 root window (module-x11-publish; new tool pacmd; ESOUND backend; new command load-sample-dir-lazy; many, many minor fixes.

      Thu Oct 28 2004:

      Version 0.6 released; +href="@PACKAGE_URL@pulseaudio-0.6.tar.gz">Version 0.6 released; changes include: TCP wrappers support; don't load the complete sound file into memory when playing back using pa_play_file(); autoload API change; don't load all sound files as FLOAT32; shorten @@ -91,14 +91,14 @@ generation; correctly lock daemon autospawning; print daemon layout to STDERR on SIGHUP; new options for pacat: allow sample type specification.

      Mon Sep 24 2004:

      Version 0.5.1 released; +href="@PACKAGE_URL@pulseaudio-0.5.1.tar.gz">Version 0.5.1 released; changes include: improve esound protocol compatibility; fix autospawning via libesd; make use of POSIX capabilities; allow SCHED_FIFO scheduling only for users in group realtime; minor build system fix.

      Mon Sep 20 2004:

      Version 0.5 released; +href="@PACKAGE_URL@pulseaudio-0.5.tar.gz">Version 0.5 released; changes include: extensive API improvements, new module module-combine for combining multiple sound cards into one, gcc 2.95 compatibility, configuration files, add "lazy" samples, @@ -106,29 +106,29 @@ support for source and network latency measurements, add module-pipe-source, many other fixes and improvements.

      Wed Sep 8 2004:

      Version 0.4 released; +href="@PACKAGE_URL@pulseaudio-0.4.tar.gz">Version 0.4 released; changes include: daemon auto spawning, support for SCHED_FIFO scheduling, three new modules, proper logging, CPU load watchdog, many fixes.

      Fri Aug 27 2004:

      Version 0.3 released; +href="@PACKAGE_URL@pulseaudio-0.3.tar.gz">Version 0.3 released; changes include: support for both glib 2.0 and glib 1.2, future cancellation, API updates, many fixes, relicense client library to LGPL.

      Fri Aug 20 2004:

      Version 0.2 released; +href="@PACKAGE_URL@pulseaudio-0.2.tar.gz">Version 0.2 released; changes include: added sample cache, introspection API, client API documentation, module autoloading, glib support, a module for intercepting X11 bell events, and much more.

      Sat Jul 17 2004:

      Version 0.1 released

      +href="@PACKAGE_URL@pulseaudio-0.1.tar.gz">Version 0.1 released

      Overview

      -

      polypaudio is a networked sound server for Linux and other +

      pulseaudio is a networked sound server for Linux and other Unix like operating systems and Microsoft Windows. It is intended to be an improved drop-in replacement for the Enlightened Sound Daemon (ESOUND). In addition to the features ESOUND provides -polypaudio has:

      +pulseaudio has:

      • Extensible plugin architecture (by loading dynamic loadable modules with dlopen())
      • @@ -150,8 +150,8 @@ Daemon (ESOUND). In addition to the features ESOUND provides use of a simple main loop abstraction layer. This allows easy integration with asynchronous applications using the glib/gtk mainloop. Since the asynchronous API -available through polyplib is quite difficult to use there is -a simplified synchronous API wrapper polyplib-simple +available through pulselib is quite difficult to use there is +a simplified synchronous API wrapper pulselib-simple available. A simple main loop implementation is available as well.

        The following modules are currently available:

        @@ -169,9 +169,9 @@ Sound Architecture (ALSA) sinks and sources
      • module-x11-bell: play a sample from the sample cache on every X11 bell event.
      • module-x11-publish: store Polypaudio credentials in the X11 root window.
      • module-esound-protocol-tcp, module-esound-protocol-unix: ESOUND compatibility modules (for TCP/IP resp. UNIX domain sockets)
      • -
      • module-native-protocol-tcp, module-native-protocol-unix: Native polypaudio protocol (for TCP/IP resp. UNIX domain sockets)
      • +
      • module-native-protocol-tcp, module-native-protocol-unix: Native pulseaudio protocol (for TCP/IP resp. UNIX domain sockets)
      • module-simple-protocol-tcp, module-simple-protocol-unix: Simplistic protocol for playback/capture for usage with tools like netcat (for TCP/IP resp. UNIX domain sockets)
      • -
      • module-cli-protocol-tcp, module-cli-protocol-unix, module-cli: Expose polypaudio's internals whith a simple command line interface. (for TCP/IP resp. UNIX domain sockets resp. STDIN/STDOUT)
      • +
      • module-cli-protocol-tcp, module-cli-protocol-unix, module-cli: Expose pulseaudio's internals whith a simple command line interface. (for TCP/IP resp. UNIX domain sockets resp. STDIN/STDOUT)
      • module-http-protocol-tcp: Spawns a small HTTP server which can be used to introspect the Polypaudio server with a web browser.
      • module-tunnel-sink, module-tunnel-source: make sinks/sources from other hosts available locally.
      • module-match: adjust volume automatically for newly created playback streams based on a regular expression matching table.
      • @@ -186,7 +186,7 @@ Sound Architecture (ALSA) sinks and sources
      • module-jack-sink, module-jack-source: connect to a JACK Audio Connection Kit server. (A sound server for professional audio production)
      -

      A GTK GUI manager application for polypaudio is the A GTK GUI manager application for pulseaudio is the Polypaudio Manager. Other GTK GUI tool for Polypaudio are the Polypaudio Volume @@ -195,10 +195,10 @@ href="http://0pointer.de/lennart/projects/pavucontrol">Polypaudio Volume Control .

      There are output plugins for XMMS, libao +href="http://0pointer.de/lennart/projects/xmms-pulse/">XMMS, libao (merged in libao SVN) and gstreamer +href="http://0pointer.de/lennart/projects/gst-pulse/">gstreamer (merged in gstreamer-plugins CVS), MPlayer (merged in MPlayer CVS) and Xine (merged in Xine CVS). Drivers for @@ -216,68 +216,68 @@ href="modules.html">modules.html, cli.html, daemon.html and FAQ.html.

      -

      There is a Trac based Wiki for Polypaudio available.

      +

      There is a Trac based Wiki for Polypaudio available.

      First Steps

      -

      Simply start the polypaudio daemon with the argument -nC

      +

      Simply start the pulseaudio daemon with the argument -nC

      -
      polypaudio -nC
      +
      pulseaudio -nC

      This will present you a screen like this:

      -
      Welcome to polypaudio! Use "help" for usage information.
      +
      Welcome to pulseaudio! Use "help" for usage information.
       >>> 

      Now you can issue CLI commands as described in cli.html. Another way to start -polypaudio is by specifying a configuration script like that one included in the distribution on the +pulseaudio is by specifying a configuration script like that one included in the distribution on the command line :

      -
      polypaudio -nF polypaudio.pa
      +
      pulseaudio -nF pulseaudio.pa

      This will load some drivers and protocols automatically.

      -

      The best idea is to configure your daemon in /etc/polypaudio/daemon.conf and /etc/polypaudio/default.pa and to run polypaudio without any arguments.

      +

      The best idea is to configure your daemon in /etc/pulseaudio/daemon.conf and /etc/pulseaudio/default.pa and to run pulseaudio without any arguments.

      Beware! Unless you pass the option --sysconfdir=/etc to -configure, the directory /etc/polypaudio/ is really -/usr/local/etc/polypaudio/.

      +configure, the directory /etc/pulseaudio/ is really +/usr/local/etc/pulseaudio/.

      -

      Developing polypaudio Clients

      +

      Developing pulseaudio Clients

      You may browse the Doxygen generated programing +href="http://0pointer.de/lennart/projects/pulseaudio/doxygen/">programing documentation for the client API. (Run make doxygen to generate this documentation from the source tree)

      -

      Developing polypaudio Modules

      +

      Developing pulseaudio Modules

      -

      There are several reasons for writing loadable modules for polypaudio:

      +

      There are several reasons for writing loadable modules for pulseaudio:

      • Extended device driver support
      • Protocol support beyond ESOUND's protocol and the native protocol. (such as NAS or a subset of aRts)
      • New programming interfaces such as XMLRPC or DBUS for controlling the daemon.
      • -
      • Hooking audio event sources directly into polypaudio (similar to module-x11-bell)
      • -
      • For low latency applications such as VOIP: load the VOIP core directly into polypaudio and have a slim GUI frontend to control it.
      • +
      • Hooking audio event sources directly into pulseaudio (similar to module-x11-bell)
      • +
      • For low latency applications such as VOIP: load the VOIP core directly into pulseaudio and have a slim GUI frontend to control it.

      There is currently no documentation how to write loadable modules -for polypaudio. Read the source, Luke! If you are interested in +for pulseaudio. Read the source, Luke! If you are interested in writing new modules feel free to contact the author in case you have any questions.

      Requirements

      -

      Currently, polypaudio is tested on Linux, FreeBSD, Solaris and Microsoft Windows. It requires an OSS, ALSA, Win32 or Solaris compatible soundcard.

      +

      Currently, pulseaudio is tested on Linux, FreeBSD, Solaris and Microsoft Windows. It requires an OSS, ALSA, Win32 or Solaris compatible soundcard.

      -

      polypaudio was developed and tested on Debian GNU/Linux +

      pulseaudio was developed and tested on Debian GNU/Linux "testing" from November 2004, it should work on most other Linux distributions (and maybe Unix versions) since it uses GNU autoconf and GNU libtool for source code configuration and shared library management.

      -

      polypaudio needs pulseaudio needs Secret Rabbit Code (aka libsamplerate), libsndfile, ./configure inside the distribution directory for configuring the source tree. After that you should run make for compilation and make install (as root) for installation of -polypaudio.

      +pulseaudio.

      Acknowledgements

      @@ -318,25 +318,25 @@ compilation and make install (as root) for installation of

      The newest release is always available from @PACKAGE_URL@

      -

      The current release is @PACKAGE_VERSION@

      +

      The current release is @PACKAGE_VERSION@

      -

      Get polypaudio's development sources from the Subversion repository (viewcvs):

      +

      Get pulseaudio's development sources from the Subversion repository (viewcvs):

      -
      svn checkout svn://0pointer.de/polypaudio/trunk polypaudio
      +
      svn checkout svn://0pointer.de/pulseaudio/trunk pulseaudio

      Community

      -

      If you want to be notified whenever I release a new version of this software use the subscription feature of Freshmeat.

      +

      If you want to be notified whenever I release a new version of this software use the subscription feature of Freshmeat.

      -

      There is a general discussion mailing list for polypaudio available. In addition, you can subscribe to SVN changes and Trac Tickets.

      +

      There is a general discussion mailing list for pulseaudio available. In addition, you can subscribe to SVN changes and Trac Tickets.

      -

      Polypaudio is being tracked at CIA.

      +

      Polypaudio is being tracked at CIA.

      -

      There's a chance to meet the Polypaudio developers on our IRC channel #polypaudio on irc.freenode.org.

      +

      There's a chance to meet the Polypaudio developers on our IRC channel #pulseaudio on irc.freenode.org.

      -

      There is a Trac based Wiki for Polypaudio available.

      +

      There is a Trac based Wiki for Polypaudio available.

      -

      Please report bugs to our Trac ticket system.

      +

      Please report bugs to our Trac ticket system.


      Lennart Poettering <@PACKAGE_BUGREPORT@>, June 2006
      diff --git a/doc/cli.html.in b/doc/cli.html.in index 0db96c36..511f5964 100644 --- a/doc/cli.html.in +++ b/doc/cli.html.in @@ -2,14 +2,14 @@ -polypaudio: Simple Command Line Language +pulseaudio: Simple Command Line Language

      Simple Command Line Language

      -

      polypaudio provides a simple command line language used by +

      pulseaudio provides a simple command line language used by configuration scripts as well as the modules module-cli and module-cli-protocol-{unix,tcp}. Empty lines and lines beginning with a hashmark (#) are silently ignored. Several @@ -181,7 +181,7 @@ on the interactive command line.

      Example Configuration Script

      -

      Mark the following script as executable (chmod +x) and run it for a sensible polypaudio configuration.

      +

      Mark the following script as executable (chmod +x) and run it for a sensible pulseaudio configuration.

       #!/usr/bin/polaudio -nF
      diff --git a/doc/daemon.html.in b/doc/daemon.html.in
      index a4db0bd7..0d91e534 100644
      --- a/doc/daemon.html.in
      +++ b/doc/daemon.html.in
      @@ -2,7 +2,7 @@
       
       
       
      -polypaudio: Daemon
      +pulseaudio: Daemon
       
       
       
      @@ -11,7 +11,7 @@
       
       

      Command Line Arguments

      -The polypaudio daemon accepts several command line arguments: +The pulseaudio daemon accepts several command line arguments:
       COMMANDS:
      @@ -58,9 +58,9 @@ STARTUP SCRIPT:
       
       

      It is a good idea to run the daemon like this:

      -
      polypaudio -D
      +
      pulseaudio -D
      -

      This will run /etc/polypaudio/default.pa after startup. This should be a script written in the CLI language described in cli.html.

      +

      This will run /etc/pulseaudio/default.pa after startup. This should be a script written in the CLI language described in cli.html.

      Signals

      diff --git a/doc/modules.html.in b/doc/modules.html.in index 85479523..f004f084 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -2,7 +2,7 @@ -polypaudio: Loadable Modules +pulseaudio: Loadable Modules @@ -10,7 +10,7 @@

      Loadable Modules

      -

      The following loadable modules are provided with the polypaudio distribution:

      +

      The following loadable modules are provided with the pulseaudio distribution:

      Device Drivers

      @@ -157,7 +157,7 @@ will decrease output quality however. (defaults to

      module-tunnel-{sink,source}

      Tunnel a remote sink/source to a local "ghost" -sink/source. Requires a running polypaudio daemon on the remote server +sink/source. Requires a running pulseaudio daemon on the remote server with module-native-protocol-tcp loaded. It's probably a better idea to connect to the remote sink/source directly since some buffer control is lost through this tunneling.

      @@ -204,7 +204,7 @@ module see cli.html.

      module-cli-protocol-{unix,tcp}

      An implemenation of a simple command line based protocol for -controlling the polypaudio daemon. If loaded, the user may +controlling the pulseaudio daemon. If loaded, the user may connect with tools like netcat, telnet or bidilink to the listening sockets and execute commands the same way as with module-cli.

      @@ -225,7 +225,7 @@ transparent TCP/IP socket. (Both IPv6 and IPv4 - if available)

      a numerical binary value. If 1 the socket is bound to the loopback device, i.e. not publicly accessible. (defaults to 1) listen=(only for -tcp) The IP address to listen on. If specified, supersedes the value specified in loopback= - socket=(only for -unix) The UNIX socket name (defaults to /tmp/polypaudio/cli) + socket=(only for -unix) The UNIX socket name (defaults to /tmp/pulseaudio/cli)

      module-simple-protocol-{unix,tcp}

      @@ -254,7 +254,7 @@ about the two possible suffixes of this module.

      An implemenation of a protocol compatible with the Enlightened Sound Daemon (ESOUND, esd). When you load this module you may -access the polypaudio daemon with tools like esdcat, +access the pulseaudio daemon with tools like esdcat, esdrec or even esdctl. Many applications, such as XMMS, include support for this protocol.

      @@ -273,7 +273,7 @@ about the two possible suffixes of this module.

      module-native-protocol-{unix,tcp}

      -

      The native protocol of polypaudio.

      +

      The native protocol of pulseaudio.

      See module-cli-protocol-{unix,tcp} for more information about the two possible suffixes of this module.

      @@ -293,7 +293,7 @@ about the two possible suffixes of this module.

      module-http-protocol-tcp

      A proof-of-concept HTTP module, which can be used to introspect -the current status of the polypaudio daemon using HTTP. Just load this +the current status of the pulseaudio daemon using HTTP. Just load this module and point your browser to http://localhost:4714/. This module takes the same arguments as module-cli-protocol-tcp.

      @@ -347,7 +347,7 @@ already loaded protocol module is used. - +
      config=The LIRC configuration file
      appname=The application name to pass to LIRC (defaults to polypaudio)
      appname=The application name to pass to LIRC (defaults to pulseaudio)
      sink=The sink to control
      @@ -430,7 +430,7 @@ created in the JACK server.

      - +
      sink_name=The name for the Polypaudio sink. If ommited defaults to jack_out.
      server_name=The JACK server to connect to. If ommited defaults to the default server.
      client_name=The client name to tell the JACK server. If ommited defaults to polypaudio.
      client_name=The client name to tell the JACK server. If ommited defaults to pulseaudio.
      channels=Number of channels to register. If ommited defaults to the number of physical playback ports of the JACK server.
      connect=Takes a boolean value. If enabled (the default) Polypaudio will try to connect its ports to the physicial playback ports of the JACK server
      @@ -455,18 +455,18 @@ which is replaced by source_name (with a default of jack_in) f

      module-esound-compat-spawnfd

      -

      This is a compatibility module for libesd based autospawning of polypaudio. Don't use it directly.

      +

      This is a compatibility module for libesd based autospawning of pulseaudio. Don't use it directly.

      module-esound-compat-spawnpid

      -

      This is a compatibility module for libesd based autospawning of polypaudio. Don't use it directly.

      +

      This is a compatibility module for libesd based autospawning of pulseaudio. Don't use it directly.

      module-match

      Adjust the volume of a playback stream automatically based on its name.

      - +
      table=The regular expression matching table file to use (defaults to ~/.polypaudio/match.table)
      table=The regular expression matching table file to use (defaults to ~/.pulseaudio/match.table)

      The table file should contain a regexp and volume on each line, seperated by spaces. An example:

      @@ -482,7 +482,7 @@ which is replaced by source_name (with a default of jack_in) f

      Adjust the volume of a playback stream automatically based on its name.

      - +
      table=The table file to use (defaults to ~/.polypaudio/volume.table)
      table=The table file to use (defaults to ~/.pulseaudio/volume.table)

      In contrast to module-match this module needs no explicit diff --git a/doc/style.css b/doc/style.css index a606c08e..c5af0055 100644 --- a/doc/style.css +++ b/doc/style.css @@ -1,20 +1,20 @@ /* $Id$ */ /*** - * This file is part of polypaudio. + * This file is part of PulseAudio. * - * polypaudio is free software; you can redistribute it and/or modify it + * PulseAudio is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * polypaudio is distributed in the hope that it will be useful, but + * PulseAudio is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with polypaudio; if not, write to the Free Software Foundation, + * along with PulseAudio; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/doxygen/Makefile.am b/doxygen/Makefile.am index 8feec733..c4f66d83 100644 --- a/doxygen/Makefile.am +++ b/doxygen/Makefile.am @@ -1,19 +1,19 @@ # $Id$ # -# This file is part of polypaudio. +# This file is part of PulseAudio. # -# polypaudio is free software; you can redistribute it and/or modify +# PulseAudio is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # -# polypaudio is distributed in the hope that it will be useful, but +# PulseAudio is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software +# along with PulseAudio; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. diff --git a/doxygen/doxygen.conf.in b/doxygen/doxygen.conf.in index f466c9d4..8ccf667a 100644 --- a/doxygen/doxygen.conf.in +++ b/doxygen/doxygen.conf.in @@ -17,7 +17,7 @@ # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. -PROJECT_NAME = @PACKAGE_NAME@ +PROJECT_NAME = PulseAudio # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or @@ -417,7 +417,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = ../src/polyp/context.h ../src/polyp/stream.h ../src/polyp/polypaudio.h ../src/polyp/sample.h ../src/polyp/def.h ../src/polyp/subscribe.h ../src/polyp/introspect.h ../src/polyp/scache.h ../src/polyp/mainloop-api.h ../src/polyp/glib-mainloop.h ../src/polyp/mainloop.h ../src/polyp/mainloop-signal.h ../src/polyp/error.h ../src/polyp/operation.h ../src/polyp/simple.h ../src/polyp/version.h ../src/polyp/volume.h ../src/polyp/channelmap.h ../src/polyp/thread-mainloop.h ../src/polyp/xmalloc.h ../src/polyp/utf8.h ../src/polyp/util.h ../src/polyp/timeval.h +INPUT = ../src/pulse/context.h ../src/pulse/stream.h ../src/pulse/pulseaudio.h ../src/pulse/sample.h ../src/pulse/def.h ../src/pulse/subscribe.h ../src/pulse/introspect.h ../src/pulse/scache.h ../src/pulse/mainloop-api.h ../src/pulse/glib-mainloop.h ../src/pulse/mainloop.h ../src/pulse/mainloop-signal.h ../src/pulse/error.h ../src/pulse/operation.h ../src/pulse/simple.h ../src/pulse/version.h ../src/pulse/volume.h ../src/pulse/channelmap.h ../src/pulse/thread-mainloop.h ../src/pulse/xmalloc.h ../src/pulse/utf8.h ../src/pulse/util.h ../src/pulse/timeval.h # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp diff --git a/libpulse-browse.pc.in b/libpulse-browse.pc.in new file mode 100644 index 00000000..7bdedf2e --- /dev/null +++ b/libpulse-browse.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libpuls-browse +Description: PulseAudio Network Browsing API +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lpulse-browse +Cflags: -D_REENTRANT -I${includedir} +Requires: libpulse diff --git a/libpulse-glib-mainloop.pc.in b/libpulse-glib-mainloop.pc.in new file mode 100644 index 00000000..169910ba --- /dev/null +++ b/libpulse-glib-mainloop.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libpulse-glib-mainloop +Description: GLIB 2.0 Main Loop Wrapper for PulseAudio +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lpulse-mainloop-glib +Cflags: -D_REENTRANT -I${includedir} +Requires: libpulse glib-2.0 diff --git a/libpulse-glib12-mainloop.pc.in b/libpulse-glib12-mainloop.pc.in new file mode 100644 index 00000000..f525c370 --- /dev/null +++ b/libpulse-glib12-mainloop.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libpulse-glib12-mainloop +Description: GLIB 1.2 Main Loop Wrapper for PulseAudio +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lpulse-mainloop-glib12 +Cflags: -D_REENTRANT -I${includedir} +Requires: libpulse glib diff --git a/libpulse-simple.pc.in b/libpulse-simple.pc.in new file mode 100644 index 00000000..c35e83fa --- /dev/null +++ b/libpulse-simple.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libpulse-simple +Description: Simplified Synchronous Client Interface to PulseAudio +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lpulse-simple +Cflags: -D_REENTRANT -I${includedir} +Requires: libpulse diff --git a/libpulse.pc.in b/libpulse.pc.in new file mode 100644 index 00000000..8d0ffb85 --- /dev/null +++ b/libpulse.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libpulse +Description: Client Interface to PulseAudio +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lpulse +Cflags: -D_REENTRANT -I${includedir} +Requires: diff --git a/polyplib-browse.pc.in b/polyplib-browse.pc.in deleted file mode 100644 index 952e28c1..00000000 --- a/polyplib-browse.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: polyplib-browse -Description: Polypaudio network browsing API -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpolyp-browse -Cflags: -D_REENTRANT -I${includedir} -Requires: polyplib diff --git a/polyplib-glib-mainloop.pc.in b/polyplib-glib-mainloop.pc.in deleted file mode 100644 index 03338c55..00000000 --- a/polyplib-glib-mainloop.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: polyplib-glib-mainloop -Description: GLIB main loop wrapper for polypaudio -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpolyp-mainloop-glib -Cflags: -D_REENTRANT -I${includedir} -Requires: polyplib glib-2.0 diff --git a/polyplib-glib12-mainloop.pc.in b/polyplib-glib12-mainloop.pc.in deleted file mode 100644 index c12a838b..00000000 --- a/polyplib-glib12-mainloop.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: polyplib-glib12-mainloop -Description: GLIB main loop wrapper for polypaudio -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpolyp-mainloop-glib12 -Cflags: -D_REENTRANT -I${includedir} -Requires: polyplib glib diff --git a/polyplib-simple.pc.in b/polyplib-simple.pc.in deleted file mode 100644 index fa0ca0b9..00000000 --- a/polyplib-simple.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: polyplib-simple -Description: Simplified synchronous client interface to polypaudio -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpolyp-simple -Cflags: -D_REENTRANT -I${includedir} -Requires: polyplib diff --git a/polyplib.pc.in b/polyplib.pc.in deleted file mode 100644 index 2d073a93..00000000 --- a/polyplib.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: polyplib -Description: Client interface to polypaudio -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpolyp -Cflags: -D_REENTRANT -I${includedir} -Requires: diff --git a/src/Makefile.am b/src/Makefile.am index 6a2decb3..746f85ec 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,19 +1,19 @@ # $Id$ # -# This file is part of polypaudio. +# This file is part of PulseAudio. # -# polypaudio is free software; you can redistribute it and/or modify +# PulseAudio is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # -# polypaudio is distributed in the hope that it will be useful, but +# PulseAudio is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software +# along with PulseAudio; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. @@ -22,19 +22,19 @@ # Extra directories # ################################### -polypincludedir=$(includedir)/polyp -polypcoreincludedir=$(includedir)/polypcore -polypconfdir=$(sysconfdir)/polypaudio +pulseincludedir=$(includedir)/pulse +pulsecoreincludedir=$(includedir)/pulsecore +pulseconfdir=$(sysconfdir)/pulse ################################### # Defines # ################################### -POLYPAUDIO_BINARY=$(bindir)/polypaudio$(EXEEXT) +POLYPAUDIO_BINARY=$(bindir)/pulseaudio$(EXEEXT) if OS_IS_WIN32 DEFAULT_CONFIG_DIR=%POLYP_ROOT% else -DEFAULT_CONFIG_DIR=$(polypconfdir) +DEFAULT_CONFIG_DIR=$(pulseconfdir) endif ################################### @@ -73,7 +73,7 @@ endif ################################### EXTRA_DIST = \ - polyp/client.conf.in \ + pulse/client.conf.in \ daemon/daemon.conf.in \ daemon/default.pa.in \ depmod.py \ @@ -81,35 +81,35 @@ EXTRA_DIST = \ utils/padsp \ modules/module-defs.h.m4 -polypconf_DATA = \ +pulseconf_DATA = \ default.pa \ daemon.conf \ client.conf BUILT_SOURCES = \ - polyp/version.h + pulse/version.h ################################### # Main daemon # ################################### -bin_PROGRAMS = polypaudio +bin_PROGRAMS = pulseaudio -polypaudio_SOURCES = \ +pulseaudio_SOURCES = \ daemon/caps.h daemon/caps.c \ daemon/cmdline.c daemon/cmdline.h \ daemon/cpulimit.c daemon/cpulimit.h \ daemon/daemon-conf.c daemon/daemon-conf.h \ daemon/dumpmodules.c daemon/dumpmodules.h \ daemon/main.c \ - polypcore/gccmacro.h + pulsecore/gccmacro.h -polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) -polypaudio_CPPFLAGS = $(AM_CPPFLAGS) -polypaudio_LDADD = $(AM_LDADD) libpolypcore.la $(LIBLTDL) \ +pulseaudio_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) +pulseaudio_CPPFLAGS = $(AM_CPPFLAGS) +pulseaudio_LDADD = $(AM_LDADD) libpulsecore.la $(LIBLTDL) \ $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) $(LIBOIL_LIBS) # This is needed because automake doesn't properly expand the foreach below -polypaudio_DEPENDENCIES = libpolypcore.la $(PREOPEN_LIBS) +pulseaudio_DEPENDENCIES = libpulsecore.la $(PREOPEN_LIBS) if PREOPEN_MODS PREOPEN_LIBS = $(PREOPEN_MODS) @@ -118,9 +118,9 @@ PREOPEN_LIBS = $(modlibexec_LTLIBRARIES) endif if FORCE_PREOPEN -polypaudio_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -dlpreopen force $(foreach f,$(PREOPEN_LIBS),-dlpreopen $(f)) +pulseaudio_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -dlpreopen force $(foreach f,$(PREOPEN_LIBS),-dlpreopen $(f)) else -polypaudio_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -dlopen force $(foreach f,$(PREOPEN_LIBS),-dlopen $(f)) +pulseaudio_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -dlopen force $(foreach f,$(PREOPEN_LIBS),-dlopen $(f)) endif ################################### @@ -147,32 +147,32 @@ endif bin_SCRIPTS = esdcompat pacat_SOURCES = utils/pacat.c -pacat_LDADD = $(AM_LDADD) libpolyp.la +pacat_LDADD = $(AM_LDADD) libpulse.la pacat_CFLAGS = $(AM_CFLAGS) pacat_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) paplay_SOURCES = utils/paplay.c -paplay_LDADD = $(AM_LDADD) libpolyp.la $(LIBSNDFILE_LIBS) +paplay_LDADD = $(AM_LDADD) libpulse.la $(LIBSNDFILE_LIBS) paplay_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) paplay_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) pactl_SOURCES = utils/pactl.c -pactl_LDADD = $(AM_LDADD) libpolyp.la $(LIBSNDFILE_LIBS) +pactl_LDADD = $(AM_LDADD) libpulse.la $(LIBSNDFILE_LIBS) pactl_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) pactl_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -pacmd_SOURCES = utils/pacmd.c polypcore/pid.c polypcore/pid.h +pacmd_SOURCES = utils/pacmd.c pulsecore/pid.c pulsecore/pid.h pacmd_CFLAGS = $(AM_CFLAGS) -pacmd_LDADD = $(AM_LDADD) libpolyp.la +pacmd_LDADD = $(AM_LDADD) libpulse.la pacmd_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) pax11publish_SOURCES = utils/pax11publish.c pax11publish_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) -pax11publish_LDADD = $(AM_LDADD) libpolyp.la $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) +pax11publish_LDADD = $(AM_LDADD) libpulse.la $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) pax11publish_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) pabrowse_SOURCES = utils/pabrowse.c -pabrowse_LDADD = $(AM_LDADD) libpolyp.la libpolyp-browse.la +pabrowse_LDADD = $(AM_LDADD) libpulse.la libpulse-browse.la pabrowse_CFLAGS = $(AM_CFLAGS) pabrowse_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -212,81 +212,81 @@ endif mainloop_test_SOURCES = tests/mainloop-test.c mainloop_test_CFLAGS = $(AM_CFLAGS) -mainloop_test_LDADD = $(AM_LDADD) libpolyp.la +mainloop_test_LDADD = $(AM_LDADD) libpulse.la mainloop_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) thread_mainloop_test_SOURCES = tests/thread-mainloop-test.c thread_mainloop_test_CFLAGS = $(AM_CFLAGS) -thread_mainloop_test_LDADD = $(AM_LDADD) libpolyp.la +thread_mainloop_test_LDADD = $(AM_LDADD) libpulse.la thread_mainloop_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) utf8_test_SOURCES = tests/utf8-test.c utf8_test_CFLAGS = $(AM_CFLAGS) -utf8_test_LDADD = $(AM_LDADD) libpolypcore.la +utf8_test_LDADD = $(AM_LDADD) libpulsecore.la utf8_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) mcalign_test_SOURCES = tests/mcalign-test.c mcalign_test_CFLAGS = $(AM_CFLAGS) -mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpolypcore.la +mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpulsecore.la mcalign_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) pacat_simple_SOURCES = tests/pacat-simple.c -pacat_simple_LDADD = $(AM_LDADD) libpolyp.la libpolyp-simple.la +pacat_simple_LDADD = $(AM_LDADD) libpulse.la libpulse-simple.la pacat_simple_CFLAGS = $(AM_CFLAGS) pacat_simple_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) parec_simple_SOURCES = tests/parec-simple.c -parec_simple_LDADD = $(AM_LDADD) libpolyp.la libpolyp-simple.la +parec_simple_LDADD = $(AM_LDADD) libpulse.la libpulse-simple.la parec_simple_CFLAGS = $(AM_CFLAGS) parec_simple_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) strlist_test_SOURCES = tests/strlist-test.c strlist_test_CFLAGS = $(AM_CFLAGS) -strlist_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpolypcore.la libstrlist.la +strlist_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpulsecore.la libstrlist.la strlist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) voltest_SOURCES = tests/voltest.c voltest_CFLAGS = $(AM_CFLAGS) -voltest_LDADD = $(AM_LDADD) libpolyp.la +voltest_LDADD = $(AM_LDADD) libpulse.la voltest_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) channelmap_test_SOURCES = tests/channelmap-test.c channelmap_test_CFLAGS = $(AM_CFLAGS) -channelmap_test_LDADD = $(AM_LDADD) libpolyp.la +channelmap_test_LDADD = $(AM_LDADD) libpulse.la channelmap_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) cpulimit_test_SOURCES = tests/cpulimit-test.c daemon/cpulimit.c daemon/cpulimit.h cpulimit_test_CFLAGS = $(AM_CFLAGS) -cpulimit_test_LDADD = $(AM_LDADD) libpolypcore.la +cpulimit_test_LDADD = $(AM_LDADD) libpulsecore.la cpulimit_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) cpulimit_test2_SOURCES = tests/cpulimit-test.c daemon/cpulimit.c daemon/cpulimit.h cpulimit_test2_CFLAGS = $(AM_CFLAGS) -DTEST2 -cpulimit_test2_LDADD = $(AM_LDADD) libpolypcore.la +cpulimit_test2_LDADD = $(AM_LDADD) libpulsecore.la cpulimit_test2_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) mainloop_test_glib_SOURCES = $(mainloop_test_SOURCES) mainloop_test_glib_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB20_CFLAGS) -DGLIB_MAIN_LOOP -mainloop_test_glib_LDADD = $(mainloop_test_LDADD) $(GLIB20_LIBS) libpolyp-mainloop-glib.la +mainloop_test_glib_LDADD = $(mainloop_test_LDADD) $(GLIB20_LIBS) libpulse-mainloop-glib.la mainloop_test_glib_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) mainloop_test_glib12_SOURCES = $(mainloop_test_SOURCES) mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MAIN_LOOP -mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12.la +mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpulse-mainloop-glib12.la mainloop_test_glib12_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) memblockq_test_SOURCES = tests/memblockq-test.c memblockq_test_CFLAGS = $(AM_CFLAGS) -memblockq_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpolypcore.la +memblockq_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpulsecore.la memblockq_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) sync_playback_SOURCES = tests/sync-playback.c -sync_playback_LDADD = $(AM_LDADD) libpolyp.la +sync_playback_LDADD = $(AM_LDADD) libpulse.la sync_playback_CFLAGS = $(AM_CFLAGS) sync_playback_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) interpol_test_SOURCES = tests/interpol-test.c -interpol_test_LDADD = $(AM_LDADD) libpolyp.la +interpol_test_LDADD = $(AM_LDADD) libpulse.la interpol_test_CFLAGS = $(AM_CFLAGS) interpol_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -294,170 +294,170 @@ interpol_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) # Client library # ################################### -polypinclude_HEADERS = \ - polyp/cdecl.h \ - polyp/channelmap.h \ - polyp/context.h \ - polyp/def.h \ - polyp/error.h \ - polyp/introspect.h \ - polyp/mainloop.h \ - polyp/mainloop-api.h \ - polyp/mainloop-signal.h \ - polyp/operation.h \ - polyp/polypaudio.h \ - polyp/sample.h \ - polyp/scache.h \ - polyp/simple.h \ - polyp/stream.h \ - polyp/subscribe.h \ - polyp/thread-mainloop.h \ - polyp/timeval.h \ - polyp/utf8.h \ - polyp/util.h \ - polyp/version.h \ - polyp/volume.h \ - polyp/xmalloc.h +pulseinclude_HEADERS = \ + pulse/cdecl.h \ + pulse/channelmap.h \ + pulse/context.h \ + pulse/def.h \ + pulse/error.h \ + pulse/introspect.h \ + pulse/mainloop.h \ + pulse/mainloop-api.h \ + pulse/mainloop-signal.h \ + pulse/operation.h \ + pulse/pulseaudio.h \ + pulse/sample.h \ + pulse/scache.h \ + pulse/simple.h \ + pulse/stream.h \ + pulse/subscribe.h \ + pulse/thread-mainloop.h \ + pulse/timeval.h \ + pulse/utf8.h \ + pulse/util.h \ + pulse/version.h \ + pulse/volume.h \ + pulse/xmalloc.h if HAVE_HOWL -polypinclude_HEADERS += \ - polyp/browser.h +pulseinclude_HEADERS += \ + pulse/browser.h endif if HAVE_GLIB20 -polypinclude_HEADERS += \ - polyp/glib-mainloop.h +pulseinclude_HEADERS += \ + pulse/glib-mainloop.h else if HAVE_GLIB12 -polypinclude_HEADERS += \ - polyp/glib-mainloop.h +pulseinclude_HEADERS += \ + pulse/glib-mainloop.h endif endif lib_LTLIBRARIES = \ - libpolyp.la \ - libpolyp-simple.la + libpulse.la \ + libpulse-simple.la if HAVE_HOWL lib_LTLIBRARIES += \ - libpolyp-browse.la + libpulse-browse.la endif if HAVE_GLIB20 lib_LTLIBRARIES += \ - libpolyp-mainloop-glib.la + libpulse-mainloop-glib.la endif if HAVE_GLIB12 lib_LTLIBRARIES += \ - libpolyp-mainloop-glib12.la + libpulse-mainloop-glib12.la endif # Public interface -libpolyp_la_SOURCES = \ - polyp/cdecl.h \ - polyp/channelmap.c polyp/channelmap.h \ - polyp/client-conf.c polyp/client-conf.h \ - polyp/context.c polyp/context.h \ - polyp/def.h \ - polyp/error.c polyp/error.h \ - polyp/internal.h \ - polyp/introspect.c polyp/introspect.h \ - polyp/mainloop.c polyp/mainloop.h \ - polyp/mainloop-api.c polyp/mainloop-api.h \ - polyp/mainloop-signal.c polyp/mainloop-signal.h \ - polyp/operation.c polyp/operation.h \ - polyp/polypaudio.h \ - polyp/sample.c polyp/sample.h \ - polyp/scache.c polyp/scache.h \ - polyp/stream.c polyp/stream.h \ - polyp/subscribe.c polyp/subscribe.h \ - polyp/thread-mainloop.c polyp/thread-mainloop.h \ - polyp/timeval.c polyp/timeval.h \ - polyp/utf8.c polyp/utf8.h \ - polyp/util.c polyp/util.h \ - polyp/volume.c polyp/volume.h \ - polyp/xmalloc.c polyp/xmalloc.h - -# Internal stuff that is shared with libpolypcore -libpolyp_la_SOURCES += \ - polypcore/authkey.c polypcore/authkey.h \ - polypcore/conf-parser.c polypcore/conf-parser.h \ - polypcore/core-util.c polypcore/core-util.h \ - polypcore/dynarray.c polypcore/dynarray.h \ - polypcore/gccmacro.h \ - polypcore/hashmap.c polypcore/hashmap.h \ - polypcore/idxset.c polypcore/idxset.h \ - polypcore/inet_ntop.c polypcore/inet_ntop.h \ - polypcore/iochannel.c polypcore/iochannel.h \ - polypcore/llist.h \ - polypcore/log.c polypcore/log.h \ - polypcore/mcalign.c polypcore/mcalign.h \ - polypcore/memblock.c polypcore/memblock.h \ - polypcore/memblockq.c polypcore/memblockq.h \ - polypcore/memchunk.c polypcore/memchunk.h \ - polypcore/native-common.h \ - polypcore/packet.c polypcore/packet.h \ - polypcore/parseaddr.c polypcore/parseaddr.h \ - polypcore/pdispatch.c polypcore/pdispatch.h \ - polypcore/pipe.c polypcore/pipe.h \ - polypcore/poll.c polypcore/poll.h \ - polypcore/pstream.c polypcore/pstream.h \ - polypcore/pstream-util.c polypcore/pstream-util.h \ - polypcore/queue.c polypcore/queue.h \ - polypcore/random.c polypcore/random.h \ - polypcore/socket-client.c polypcore/socket-client.h \ - polypcore/socket-util.c polypcore/socket-util.h \ - polypcore/strbuf.c polypcore/strbuf.h \ - polypcore/strlist.c polypcore/strlist.h \ - polypcore/tagstruct.c polypcore/tagstruct.h \ - polypcore/core-error.c polypcore/core-error.h \ - polypcore/winsock.h +libpulse_la_SOURCES = \ + pulse/cdecl.h \ + pulse/channelmap.c pulse/channelmap.h \ + pulse/client-conf.c pulse/client-conf.h \ + pulse/context.c pulse/context.h \ + pulse/def.h \ + pulse/error.c pulse/error.h \ + pulse/internal.h \ + pulse/introspect.c pulse/introspect.h \ + pulse/mainloop.c pulse/mainloop.h \ + pulse/mainloop-api.c pulse/mainloop-api.h \ + pulse/mainloop-signal.c pulse/mainloop-signal.h \ + pulse/operation.c pulse/operation.h \ + pulse/pulseaudio.h \ + pulse/sample.c pulse/sample.h \ + pulse/scache.c pulse/scache.h \ + pulse/stream.c pulse/stream.h \ + pulse/subscribe.c pulse/subscribe.h \ + pulse/thread-mainloop.c pulse/thread-mainloop.h \ + pulse/timeval.c pulse/timeval.h \ + pulse/utf8.c pulse/utf8.h \ + pulse/util.c pulse/util.h \ + pulse/volume.c pulse/volume.h \ + pulse/xmalloc.c pulse/xmalloc.h + +# Internal stuff that is shared with libpulsecore +libpulse_la_SOURCES += \ + pulsecore/authkey.c pulsecore/authkey.h \ + pulsecore/conf-parser.c pulsecore/conf-parser.h \ + pulsecore/core-util.c pulsecore/core-util.h \ + pulsecore/dynarray.c pulsecore/dynarray.h \ + pulsecore/gccmacro.h \ + pulsecore/hashmap.c pulsecore/hashmap.h \ + pulsecore/idxset.c pulsecore/idxset.h \ + pulsecore/inet_ntop.c pulsecore/inet_ntop.h \ + pulsecore/iochannel.c pulsecore/iochannel.h \ + pulsecore/llist.h \ + pulsecore/log.c pulsecore/log.h \ + pulsecore/mcalign.c pulsecore/mcalign.h \ + pulsecore/memblock.c pulsecore/memblock.h \ + pulsecore/memblockq.c pulsecore/memblockq.h \ + pulsecore/memchunk.c pulsecore/memchunk.h \ + pulsecore/native-common.h \ + pulsecore/packet.c pulsecore/packet.h \ + pulsecore/parseaddr.c pulsecore/parseaddr.h \ + pulsecore/pdispatch.c pulsecore/pdispatch.h \ + pulsecore/pipe.c pulsecore/pipe.h \ + pulsecore/poll.c pulsecore/poll.h \ + pulsecore/pstream.c pulsecore/pstream.h \ + pulsecore/pstream-util.c pulsecore/pstream-util.h \ + pulsecore/queue.c pulsecore/queue.h \ + pulsecore/random.c pulsecore/random.h \ + pulsecore/socket-client.c pulsecore/socket-client.h \ + pulsecore/socket-util.c pulsecore/socket-util.h \ + pulsecore/strbuf.c pulsecore/strbuf.h \ + pulsecore/strlist.c pulsecore/strlist.h \ + pulsecore/tagstruct.c pulsecore/tagstruct.h \ + pulsecore/core-error.c pulsecore/core-error.h \ + pulsecore/winsock.h if OS_IS_WIN32 -libpolyp_la_SOURCES += \ - polypcore/dllmain.c +libpulse_la_SOURCES += \ + pulsecore/dllmain.c endif if HAVE_X11 -libpolyp_la_SOURCES += \ - polyp/client-conf-x11.c polyp/client-conf-x11.h \ - polypcore/x11prop.c polypcore/x11prop.h +libpulse_la_SOURCES += \ + pulse/client-conf-x11.c pulse/client-conf-x11.h \ + pulsecore/x11prop.c pulsecore/x11prop.h endif -libpolyp_la_CFLAGS = $(AM_CFLAGS) -libpolyp_la_LDFLAGS = -version-info $(LIBPOLYP_VERSION_INFO) -libpolyp_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) $(LIBICONV) +libpulse_la_CFLAGS = $(AM_CFLAGS) +libpulse_la_LDFLAGS = -version-info $(LIBPOLYP_VERSION_INFO) +libpulse_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) $(LIBICONV) if HAVE_X11 -libpolyp_la_CFLAGS += $(X_CFLAGS) -libpolyp_la_LDFLAGS += $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) +libpulse_la_CFLAGS += $(X_CFLAGS) +libpulse_la_LDFLAGS += $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) endif if HAVE_LIBASYNCNS -libpolyp_la_CFLAGS += $(LIBASYNCNS_CFLAGS) -libpolyp_la_LIBADD += $(LIBASYNCNS_LIBS) +libpulse_la_CFLAGS += $(LIBASYNCNS_CFLAGS) +libpulse_la_LIBADD += $(LIBASYNCNS_LIBS) endif -libpolyp_simple_la_SOURCES = polyp/simple.c polyp/simple.h -libpolyp_simple_la_CFLAGS = $(AM_CFLAGS) -libpolyp_simple_la_LIBADD = $(AM_LIBADD) libpolyp.la -libpolyp_simple_la_LDFLAGS = -version-info $(LIBPOLYP_SIMPLE_VERSION_INFO) +libpulse_simple_la_SOURCES = pulse/simple.c pulse/simple.h +libpulse_simple_la_CFLAGS = $(AM_CFLAGS) +libpulse_simple_la_LIBADD = $(AM_LIBADD) libpulse.la +libpulse_simple_la_LDFLAGS = -version-info $(LIBPOLYP_SIMPLE_VERSION_INFO) -libpolyp_browse_la_SOURCES = polyp/browser.c polyp/browser.h -libpolyp_browse_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) -libpolyp_browse_la_LIBADD = $(AM_LIBADD) libpolyp.la $(HOWL_LIBS) -libpolyp_browse_la_LDFLAGS = -version-info $(LIBPOLYP_BROWSE_VERSION_INFO) +libpulse_browse_la_SOURCES = pulse/browser.c pulse/browser.h +libpulse_browse_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) +libpulse_browse_la_LIBADD = $(AM_LIBADD) libpulse.la $(HOWL_LIBS) +libpulse_browse_la_LDFLAGS = -version-info $(LIBPOLYP_BROWSE_VERSION_INFO) -libpolyp_mainloop_glib_la_SOURCES = polyp/glib-mainloop.h polyp/glib-mainloop.c -libpolyp_mainloop_glib_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) -libpolyp_mainloop_glib_la_LIBADD = $(AM_LIBADD) libpolyp.la $(GLIB20_LIBS) -libpolyp_mainloop_glib_la_LDFLAGS = -version-info $(LIBPOLYP_MAINLOOP_GLIB_VERSION_INFO) +libpulse_mainloop_glib_la_SOURCES = pulse/glib-mainloop.h pulse/glib-mainloop.c +libpulse_mainloop_glib_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) +libpulse_mainloop_glib_la_LIBADD = $(AM_LIBADD) libpulse.la $(GLIB20_LIBS) +libpulse_mainloop_glib_la_LDFLAGS = -version-info $(LIBPOLYP_MAINLOOP_GLIB_VERSION_INFO) -libpolyp_mainloop_glib12_la_SOURCES = polyp/glib-mainloop.h polyp/glib12-mainloop.c -libpolyp_mainloop_glib12_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS) -libpolyp_mainloop_glib12_la_LIBADD = $(AM_LIBADD) libpolyp.la $(GLIB12_LIBS) -libpolyp_mainloop_glib12_la_LDFLAGS = -version-info $(LIBPOLYP_MAINLOOP_GLIB_VERSION_INFO) +libpulse_mainloop_glib12_la_SOURCES = pulse/glib-mainloop.h pulse/glib12-mainloop.c +libpulse_mainloop_glib12_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS) +libpulse_mainloop_glib12_la_LIBADD = $(AM_LIBADD) libpulse.la $(GLIB12_LIBS) +libpulse_mainloop_glib12_la_LDFLAGS = -version-info $(LIBPOLYP_MAINLOOP_GLIB_VERSION_INFO) ################################### # OSS emulation # @@ -465,164 +465,164 @@ libpolyp_mainloop_glib12_la_LDFLAGS = -version-info $(LIBPOLYP_MAINLOOP_GLIB_VER if HAVE_OSS -lib_LTLIBRARIES += libpolypdsp.la +lib_LTLIBRARIES += libpulsedsp.la bin_SCRIPTS += utils/padsp endif -libpolypdsp_la_SOURCES = utils/padsp.c -libpolypdsp_la_CFLAGS = $(AM_CFLAGS) -libpolypdsp_la_LIBADD = $(AM_LIBADD) libpolyp.la -libpolypdsp_la_LDFLAGS = -avoid-version +libpulsedsp_la_SOURCES = utils/padsp.c +libpulsedsp_la_CFLAGS = $(AM_CFLAGS) +libpulsedsp_la_LIBADD = $(AM_LIBADD) libpulse.la +libpulsedsp_la_LDFLAGS = -avoid-version ################################### # Daemon core library # ################################### -polypcoreinclude_HEADERS = \ - polypcore/autoload.h \ - polypcore/cli-command.h \ - polypcore/cli-text.h \ - polypcore/client.h \ - polypcore/core.h \ - polypcore/core-def.h \ - polypcore/core-scache.h \ - polypcore/core-subscribe.h \ - polypcore/conf-parser.h \ - polypcore/core-util.h \ - polypcore/dynarray.h \ - polypcore/g711.h \ - polypcore/hashmap.h \ - polypcore/idxset.h \ - polypcore/log.h \ - polypcore/mcalign.h \ - polypcore/memblock.h \ - polypcore/memblockq.h \ - polypcore/memchunk.h \ - polypcore/modargs.h \ - polypcore/modinfo.h \ - polypcore/module.h \ - polypcore/namereg.h \ - polypcore/pid.h \ - polypcore/play-memchunk.h \ - polypcore/props.h \ - polypcore/queue.h \ - polypcore/random.h \ - polypcore/resampler.h \ - polypcore/sample-util.h \ - polypcore/sconv.h \ - polypcore/sink.h \ - polypcore/sink-input.h \ - polypcore/sioman.h \ - polypcore/sound-file.h \ - polypcore/sound-file-stream.h \ - polypcore/source.h \ - polypcore/source-output.h \ - polypcore/strbuf.h \ - polypcore/tokenizer.h - -lib_LTLIBRARIES += libpolypcore.la +pulsecoreinclude_HEADERS = \ + pulsecore/autoload.h \ + pulsecore/cli-command.h \ + pulsecore/cli-text.h \ + pulsecore/client.h \ + pulsecore/core.h \ + pulsecore/core-def.h \ + pulsecore/core-scache.h \ + pulsecore/core-subscribe.h \ + pulsecore/conf-parser.h \ + pulsecore/core-util.h \ + pulsecore/dynarray.h \ + pulsecore/g711.h \ + pulsecore/hashmap.h \ + pulsecore/idxset.h \ + pulsecore/log.h \ + pulsecore/mcalign.h \ + pulsecore/memblock.h \ + pulsecore/memblockq.h \ + pulsecore/memchunk.h \ + pulsecore/modargs.h \ + pulsecore/modinfo.h \ + pulsecore/module.h \ + pulsecore/namereg.h \ + pulsecore/pid.h \ + pulsecore/play-memchunk.h \ + pulsecore/props.h \ + pulsecore/queue.h \ + pulsecore/random.h \ + pulsecore/resampler.h \ + pulsecore/sample-util.h \ + pulsecore/sconv.h \ + pulsecore/sink.h \ + pulsecore/sink-input.h \ + pulsecore/sioman.h \ + pulsecore/sound-file.h \ + pulsecore/sound-file-stream.h \ + pulsecore/source.h \ + pulsecore/source-output.h \ + pulsecore/strbuf.h \ + pulsecore/tokenizer.h + +lib_LTLIBRARIES += libpulsecore.la # Some public stuff is used even in the core. -libpolypcore_la_SOURCES = \ - polyp/channelmap.c polyp/channelmap.h \ - polyp/error.c polyp/error.h \ - polyp/mainloop.c polyp/mainloop.h \ - polyp/mainloop-api.c polyp/mainloop-api.h \ - polyp/mainloop-signal.c polyp/mainloop-signal.h \ - polyp/sample.c polyp/sample.h \ - polyp/timeval.c polyp/timeval.h \ - polyp/utf8.c polyp/utf8.h \ - polyp/util.c polyp/util.h \ - polyp/volume.c polyp/volume.h \ - polyp/xmalloc.c polyp/xmalloc.h - -# Pure core stuff (some are shared in libpolyp though). -libpolypcore_la_SOURCES += \ - polypcore/autoload.c polypcore/autoload.h \ - polypcore/cli-command.c polypcore/cli-command.h \ - polypcore/cli-text.c polypcore/cli-text.h \ - polypcore/client.c polypcore/client.h \ - polypcore/conf-parser.c polypcore/conf-parser.h \ - polypcore/core.c polypcore/core.h \ - polypcore/core-scache.c polypcore/core-scache.h \ - polypcore/core-subscribe.c polypcore/core-subscribe.h \ - polypcore/core-util.c polypcore/core-util.h \ - polypcore/dynarray.c polypcore/dynarray.h \ - polypcore/endianmacros.h \ - polypcore/g711.c polypcore/g711.h \ - polypcore/hashmap.c polypcore/hashmap.h \ - polypcore/idxset.c polypcore/idxset.h \ - polypcore/log.c polypcore/log.h \ - polypcore/mcalign.c polypcore/mcalign.h \ - polypcore/memblock.c polypcore/memblock.h \ - polypcore/memblockq.c polypcore/memblockq.h \ - polypcore/memchunk.c polypcore/memchunk.h \ - polypcore/modargs.c polypcore/modargs.h \ - polypcore/modinfo.c polypcore/modinfo.h \ - polypcore/module.c polypcore/module.h \ - polypcore/namereg.c polypcore/namereg.h \ - polypcore/pid.c polypcore/pid.h \ - polypcore/pipe.c polypcore/pipe.h \ - polypcore/play-memchunk.c polypcore/play-memchunk.h \ - polypcore/poll.c polypcore/poll.h \ - polypcore/props.c polypcore/props.h \ - polypcore/queue.c polypcore/queue.h \ - polypcore/random.c polypcore/random.h \ - polypcore/resampler.c polypcore/resampler.h \ - polypcore/sample-util.c polypcore/sample-util.h \ - polypcore/sconv.c polypcore/sconv.h \ - polypcore/sconv-s16be.c polypcore/sconv-s16be.h \ - polypcore/sconv-s16le.c polypcore/sconv-s16le.h \ - polypcore/sink.c polypcore/sink.h \ - polypcore/sink-input.c polypcore/sink-input.h \ - polypcore/sioman.c polypcore/sioman.h \ - polypcore/sound-file.c polypcore/sound-file.h \ - polypcore/sound-file-stream.c polypcore/sound-file-stream.h \ - polypcore/source.c polypcore/source.h \ - polypcore/source-output.c polypcore/source-output.h \ - polypcore/strbuf.c polypcore/strbuf.h \ - polypcore/tokenizer.c polypcore/tokenizer.h \ - polypcore/winsock.h \ - polypcore/core-error.c polypcore/core-error.h +libpulsecore_la_SOURCES = \ + pulse/channelmap.c pulse/channelmap.h \ + pulse/error.c pulse/error.h \ + pulse/mainloop.c pulse/mainloop.h \ + pulse/mainloop-api.c pulse/mainloop-api.h \ + pulse/mainloop-signal.c pulse/mainloop-signal.h \ + pulse/sample.c pulse/sample.h \ + pulse/timeval.c pulse/timeval.h \ + pulse/utf8.c pulse/utf8.h \ + pulse/util.c pulse/util.h \ + pulse/volume.c pulse/volume.h \ + pulse/xmalloc.c pulse/xmalloc.h + +# Pure core stuff (some are shared in libpulse though). +libpulsecore_la_SOURCES += \ + pulsecore/autoload.c pulsecore/autoload.h \ + pulsecore/cli-command.c pulsecore/cli-command.h \ + pulsecore/cli-text.c pulsecore/cli-text.h \ + pulsecore/client.c pulsecore/client.h \ + pulsecore/conf-parser.c pulsecore/conf-parser.h \ + pulsecore/core.c pulsecore/core.h \ + pulsecore/core-scache.c pulsecore/core-scache.h \ + pulsecore/core-subscribe.c pulsecore/core-subscribe.h \ + pulsecore/core-util.c pulsecore/core-util.h \ + pulsecore/dynarray.c pulsecore/dynarray.h \ + pulsecore/endianmacros.h \ + pulsecore/g711.c pulsecore/g711.h \ + pulsecore/hashmap.c pulsecore/hashmap.h \ + pulsecore/idxset.c pulsecore/idxset.h \ + pulsecore/log.c pulsecore/log.h \ + pulsecore/mcalign.c pulsecore/mcalign.h \ + pulsecore/memblock.c pulsecore/memblock.h \ + pulsecore/memblockq.c pulsecore/memblockq.h \ + pulsecore/memchunk.c pulsecore/memchunk.h \ + pulsecore/modargs.c pulsecore/modargs.h \ + pulsecore/modinfo.c pulsecore/modinfo.h \ + pulsecore/module.c pulsecore/module.h \ + pulsecore/namereg.c pulsecore/namereg.h \ + pulsecore/pid.c pulsecore/pid.h \ + pulsecore/pipe.c pulsecore/pipe.h \ + pulsecore/play-memchunk.c pulsecore/play-memchunk.h \ + pulsecore/poll.c pulsecore/poll.h \ + pulsecore/props.c pulsecore/props.h \ + pulsecore/queue.c pulsecore/queue.h \ + pulsecore/random.c pulsecore/random.h \ + pulsecore/resampler.c pulsecore/resampler.h \ + pulsecore/sample-util.c pulsecore/sample-util.h \ + pulsecore/sconv.c pulsecore/sconv.h \ + pulsecore/sconv-s16be.c pulsecore/sconv-s16be.h \ + pulsecore/sconv-s16le.c pulsecore/sconv-s16le.h \ + pulsecore/sink.c pulsecore/sink.h \ + pulsecore/sink-input.c pulsecore/sink-input.h \ + pulsecore/sioman.c pulsecore/sioman.h \ + pulsecore/sound-file.c pulsecore/sound-file.h \ + pulsecore/sound-file-stream.c pulsecore/sound-file-stream.h \ + pulsecore/source.c pulsecore/source.h \ + pulsecore/source-output.c pulsecore/source-output.h \ + pulsecore/strbuf.c pulsecore/strbuf.h \ + pulsecore/tokenizer.c pulsecore/tokenizer.h \ + pulsecore/winsock.h \ + pulsecore/core-error.c pulsecore/core-error.h if OS_IS_WIN32 -libpolypcore_la_SOURCES += \ - polypcore/dllmain.c +libpulsecore_la_SOURCES += \ + pulsecore/dllmain.c endif -libpolypcore_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBOIL_CFLAGS) -libpolypcore_la_LDFLAGS = -version-info $(LIBPOLYPCORE_VERSION_INFO) -libpolypcore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) $(LIBOIL_LIBS) $(LIBICONV) +libpulsecore_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBOIL_CFLAGS) +libpulsecore_la_LDFLAGS = -version-info $(LIBPOLYPCORE_VERSION_INFO) +libpulsecore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) $(LIBOIL_LIBS) $(LIBICONV) ################################### # Plug-in support libraries # ################################### -polypcoreinclude_HEADERS += \ - polypcore/socket-util.h \ - polypcore/iochannel.h \ - polypcore/socket-server.h \ - polypcore/socket-client.h \ - polypcore/parseaddr.h \ - polypcore/packet.h \ - polypcore/pstream.h \ - polypcore/ioline.h \ - polypcore/cli.h \ - polypcore/protocol-cli.h \ - polypcore/tagstruct.h \ - polypcore/pstream-util.h \ - polypcore/pdispatch.h \ - polypcore/authkey.h \ - polypcore/authkey-prop.h \ - polypcore/strlist.h \ - polypcore/protocol-simple.h \ - polypcore/esound.h \ - polypcore/protocol-esound.h \ - polypcore/native-common.h \ - polypcore/protocol-native.h \ - polypcore/protocol-http.h +pulsecoreinclude_HEADERS += \ + pulsecore/socket-util.h \ + pulsecore/iochannel.h \ + pulsecore/socket-server.h \ + pulsecore/socket-client.h \ + pulsecore/parseaddr.h \ + pulsecore/packet.h \ + pulsecore/pstream.h \ + pulsecore/ioline.h \ + pulsecore/cli.h \ + pulsecore/protocol-cli.h \ + pulsecore/tagstruct.h \ + pulsecore/pstream-util.h \ + pulsecore/pdispatch.h \ + pulsecore/authkey.h \ + pulsecore/authkey-prop.h \ + pulsecore/strlist.h \ + pulsecore/protocol-simple.h \ + pulsecore/esound.h \ + pulsecore/protocol-esound.h \ + pulsecore/native-common.h \ + pulsecore/protocol-native.h \ + pulsecore/protocol-http.h ### Warning! Due to an obscure bug in libtool/automake it is required ### that the libraries in modlibexec_LTLIBRARIES are specified in-order, @@ -658,114 +658,114 @@ modlibexec_LTLIBRARIES += \ endif if HAVE_X11 -polypcoreinclude_HEADERS += \ - polypcore/x11wrap.h \ - polypcore/x11prop.h +pulsecoreinclude_HEADERS += \ + pulsecore/x11wrap.h \ + pulsecore/x11prop.h modlibexec_LTLIBRARIES += \ libx11wrap.la \ libx11prop.la endif -libprotocol_simple_la_SOURCES = polypcore/protocol-simple.c polypcore/protocol-simple.h +libprotocol_simple_la_SOURCES = pulsecore/protocol-simple.c pulsecore/protocol-simple.h libprotocol_simple_la_LDFLAGS = -avoid-version -libprotocol_simple_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket-server.la libiochannel.la +libprotocol_simple_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-server.la libiochannel.la libsocket_server_la_SOURCES = \ - polypcore/inet_ntop.c polypcore/inet_ntop.h \ - polypcore/inet_pton.c polypcore/inet_pton.h \ - polypcore/socket-server.c polypcore/socket-server.h + pulsecore/inet_ntop.c pulsecore/inet_ntop.h \ + pulsecore/inet_pton.c pulsecore/inet_pton.h \ + pulsecore/socket-server.c pulsecore/socket-server.h libsocket_server_la_LDFLAGS = -avoid-version -libsocket_server_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la libsocket-util.la $(LIBWRAP_LIBS) $(WINSOCK_LIBS) +libsocket_server_la_LIBADD = $(AM_LIBADD) libpulsecore.la libiochannel.la libsocket-util.la $(LIBWRAP_LIBS) $(WINSOCK_LIBS) -libsocket_client_la_SOURCES = polypcore/socket-client.c polypcore/socket-client.h +libsocket_client_la_SOURCES = pulsecore/socket-client.c pulsecore/socket-client.h libsocket_client_la_LDFLAGS = -avoid-version -libsocket_client_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la libsocket-util.la libparseaddr.la $(LIBASYNCNS_LIBS) $(WINSOCK_LIBS) +libsocket_client_la_LIBADD = $(AM_LIBADD) libpulsecore.la libiochannel.la libsocket-util.la libparseaddr.la $(LIBASYNCNS_LIBS) $(WINSOCK_LIBS) libsocket_client_la_CFLAGS = $(AM_CFLAGS) $(LIBASYNCNS_CFLAGS) -libparseaddr_la_SOURCES = polypcore/parseaddr.c polypcore/parseaddr.h +libparseaddr_la_SOURCES = pulsecore/parseaddr.c pulsecore/parseaddr.h libparseaddr_la_LDFLAGS = -avoid-version -libparseaddr_la_LIBADD = $(AM_LIBADD) libpolypcore.la +libparseaddr_la_LIBADD = $(AM_LIBADD) libpulsecore.la -libpstream_la_SOURCES = polypcore/pstream.c polypcore/pstream.h +libpstream_la_SOURCES = pulsecore/pstream.c pulsecore/pstream.h libpstream_la_LDFLAGS = -avoid-version -libpstream_la_LIBADD = $(AM_LIBADD) libpolypcore.la libpacket.la libiochannel.la $(WINSOCK_LIBS) +libpstream_la_LIBADD = $(AM_LIBADD) libpulsecore.la libpacket.la libiochannel.la $(WINSOCK_LIBS) -libpstream_util_la_SOURCES = polypcore/pstream-util.c polypcore/pstream-util.h +libpstream_util_la_SOURCES = pulsecore/pstream-util.c pulsecore/pstream-util.h libpstream_util_la_LDFLAGS = -avoid-version libpstream_util_la_LIBADD = $(AM_LIBADD) libpacket.la libpstream.la libtagstruct.la -libpdispatch_la_SOURCES = polypcore/pdispatch.c polypcore/pdispatch.h +libpdispatch_la_SOURCES = pulsecore/pdispatch.c pulsecore/pdispatch.h libpdispatch_la_LDFLAGS = -avoid-version -libpdispatch_la_LIBADD = $(AM_LIBADD) libtagstruct.la libpolypcore.la +libpdispatch_la_LIBADD = $(AM_LIBADD) libtagstruct.la libpulsecore.la -libiochannel_la_SOURCES = polypcore/iochannel.c polypcore/iochannel.h +libiochannel_la_SOURCES = pulsecore/iochannel.c pulsecore/iochannel.h libiochannel_la_LDFLAGS = -avoid-version -libiochannel_la_LIBADD = $(AM_LIBADD) libsocket-util.la libpolypcore.la $(WINSOCK_LIBS) +libiochannel_la_LIBADD = $(AM_LIBADD) libsocket-util.la libpulsecore.la $(WINSOCK_LIBS) -libpacket_la_SOURCES = polypcore/packet.c polypcore/packet.h +libpacket_la_SOURCES = pulsecore/packet.c pulsecore/packet.h libpacket_la_LDFLAGS = -avoid-version -libpacket_la_LIBADD = $(AM_LIBADD) libpolypcore.la +libpacket_la_LIBADD = $(AM_LIBADD) libpulsecore.la -libioline_la_SOURCES = polypcore/ioline.c polypcore/ioline.h +libioline_la_SOURCES = pulsecore/ioline.c pulsecore/ioline.h libioline_la_LDFLAGS = -avoid-version -libioline_la_LIBADD = $(AM_LIBADD) libiochannel.la libpolypcore.la +libioline_la_LIBADD = $(AM_LIBADD) libiochannel.la libpulsecore.la -libcli_la_SOURCES = polypcore/cli.c polypcore/cli.h +libcli_la_SOURCES = pulsecore/cli.c pulsecore/cli.h libcli_la_CPPFLAGS = $(AM_CPPFLAGS) libcli_la_LDFLAGS = -avoid-version -libcli_la_LIBADD = $(AM_LIBADD) libiochannel.la libioline.la libpolypcore.la +libcli_la_LIBADD = $(AM_LIBADD) libiochannel.la libioline.la libpulsecore.la -libstrlist_la_SOURCES = polypcore/strlist.c polypcore/strlist.h +libstrlist_la_SOURCES = pulsecore/strlist.c pulsecore/strlist.h libstrlist_la_LDFLAGS = -avoid-version -libstrlist_la_LIBADD = $(AM_LIBADD) libpolypcore.la +libstrlist_la_LIBADD = $(AM_LIBADD) libpulsecore.la -libprotocol_cli_la_SOURCES = polypcore/protocol-cli.c polypcore/protocol-cli.h +libprotocol_cli_la_SOURCES = pulsecore/protocol-cli.c pulsecore/protocol-cli.h libprotocol_cli_la_LDFLAGS = -avoid-version -libprotocol_cli_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libcli.la libpolypcore.la +libprotocol_cli_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libcli.la libpulsecore.la -libprotocol_http_la_SOURCES = polypcore/protocol-http.c polypcore/protocol-http.h +libprotocol_http_la_SOURCES = pulsecore/protocol-http.c pulsecore/protocol-http.h libprotocol_http_la_LDFLAGS = -avoid-version -libprotocol_http_la_LIBADD = $(AM_LIBADD) libsocket-server.la libioline.la libpolypcore.la libiochannel.la +libprotocol_http_la_LIBADD = $(AM_LIBADD) libsocket-server.la libioline.la libpulsecore.la libiochannel.la -libprotocol_native_la_SOURCES = polypcore/protocol-native.c polypcore/protocol-native.h polypcore/native-common.h +libprotocol_native_la_SOURCES = pulsecore/protocol-native.c pulsecore/protocol-native.h pulsecore/native-common.h libprotocol_native_la_LDFLAGS = -avoid-version -libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libstrlist.la libpolypcore.la libiochannel.la +libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libstrlist.la libpulsecore.la libiochannel.la -libtagstruct_la_SOURCES = polypcore/tagstruct.c polypcore/tagstruct.h +libtagstruct_la_SOURCES = pulsecore/tagstruct.c pulsecore/tagstruct.h libtagstruct_la_LDFLAGS = -avoid-version -libtagstruct_la_LIBADD = $(AM_LIBADD) libpolypcore.la $(WINSOCK_LIBS) +libtagstruct_la_LIBADD = $(AM_LIBADD) libpulsecore.la $(WINSOCK_LIBS) -libprotocol_esound_la_SOURCES = polypcore/protocol-esound.c polypcore/protocol-esound.h polypcore/esound.h +libprotocol_esound_la_SOURCES = pulsecore/protocol-esound.c pulsecore/protocol-esound.h pulsecore/esound.h libprotocol_esound_la_LDFLAGS = -avoid-version -libprotocol_esound_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libauthkey.la libpolypcore.la +libprotocol_esound_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libauthkey.la libpulsecore.la -libauthkey_la_SOURCES = polypcore/authkey.c polypcore/authkey.h +libauthkey_la_SOURCES = pulsecore/authkey.c pulsecore/authkey.h libauthkey_la_LDFLAGS = -avoid-version -libauthkey_la_LIBADD = $(AM_LIBADD) libpolypcore.la +libauthkey_la_LIBADD = $(AM_LIBADD) libpulsecore.la -libauthkey_prop_la_SOURCES = polypcore/authkey-prop.c polypcore/authkey-prop.h +libauthkey_prop_la_SOURCES = pulsecore/authkey-prop.c pulsecore/authkey-prop.h libauthkey_prop_la_LDFLAGS = -avoid-version -libauthkey_prop_la_LIBADD = $(AM_LIBADD) libpolypcore.la +libauthkey_prop_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket_util_la_SOURCES = \ - polypcore/inet_ntop.c polypcor/inet_ntop.h \ - polypcore/socket-util.c polypcore/socket-util.h + pulsecore/inet_ntop.c pulsecor/inet_ntop.h \ + pulsecore/socket-util.c pulsecore/socket-util.h libsocket_util_la_LDFLAGS = -avoid-version -libsocket_util_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) libpolypcore.la +libsocket_util_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) libpulsecore.la librtp_la_SOURCES = modules/rtp/rtp.c modules/rtp/rtp.h modules/rtp/sdp.c modules/rtp/sdp.h modules/rtp/sap.c modules/rtp/sap.h librtp_la_LDFLAGS = -avoid-version -librtp_la_LIBADD = $(AM_LIBADD) libpolypcore.la +librtp_la_LIBADD = $(AM_LIBADD) libpulsecore.la # X11 -libx11wrap_la_SOURCES = polypcore/x11wrap.c polypcore/x11wrap.h +libx11wrap_la_SOURCES = pulsecore/x11wrap.c pulsecore/x11wrap.h libx11wrap_la_LDFLAGS = -avoid-version libx11wrap_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) -libx11wrap_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libpolypcore.la +libx11wrap_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libpulsecore.la -libx11prop_la_SOURCES = polypcore/x11prop.c polypcore/x11prop.h +libx11prop_la_SOURCES = pulsecore/x11prop.c pulsecore/x11prop.h libx11prop_la_LDFLAGS = -avoid-version libx11prop_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) libx11prop_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) @@ -932,127 +932,127 @@ $(SYMDEF_FILES): modules/module-defs.h.m4 module_simple_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c module_simple_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) module_simple_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_simple_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-simple.la libsocket-server.la +module_simple_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-simple.la libsocket-server.la module_simple_protocol_unix_la_SOURCES = modules/module-protocol-stub.c module_simple_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS) module_simple_protocol_unix_la_LDFLAGS = -module -avoid-version -module_simple_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-simple.la libsocket-server.la libsocket-util.la +module_simple_protocol_unix_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-simple.la libsocket-server.la libsocket-util.la # CLI protocol module_cli_la_SOURCES = modules/module-cli.c module_cli_la_LDFLAGS = -module -avoid-version -module_cli_la_LIBADD = $(AM_LIBADD) libcli.la libiochannel.la libpolypcore.la +module_cli_la_LIBADD = $(AM_LIBADD) libcli.la libiochannel.la libpulsecore.la module_cli_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c module_cli_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) module_cli_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_cli_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-cli.la libsocket-server.la +module_cli_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-cli.la libsocket-server.la module_cli_protocol_unix_la_SOURCES = modules/module-protocol-stub.c module_cli_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS) module_cli_protocol_unix_la_LDFLAGS = -module -avoid-version -module_cli_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-cli.la libsocket-server.la libsocket-util.la +module_cli_protocol_unix_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-cli.la libsocket-server.la libsocket-util.la # HTTP protocol module_http_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c module_http_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_CFLAGS) module_http_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_http_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-http.la libsocket-server.la +module_http_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-http.la libsocket-server.la module_http_protocol_unix_la_SOURCES = modules/module-protocol-stub.c module_http_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_CFLAGS) module_http_protocol_unix_la_LDFLAGS = -module -avoid-version -module_http_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-http.la libsocket-server.la libsocket-util.la +module_http_protocol_unix_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-http.la libsocket-server.la libsocket-util.la # Native protocol module_native_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c module_native_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) module_native_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_native_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la +module_native_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-native.la libsocket-server.la module_native_protocol_unix_la_SOURCES = modules/module-protocol-stub.c module_native_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS) module_native_protocol_unix_la_LDFLAGS = -module -avoid-version -module_native_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la libsocket-util.la +module_native_protocol_unix_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-native.la libsocket-server.la libsocket-util.la module_native_protocol_fd_la_SOURCES = modules/module-native-protocol-fd.c module_native_protocol_fd_la_CFLAGS = $(AM_CFLAGS) module_native_protocol_fd_la_LDFLAGS = -module -avoid-version -module_native_protocol_fd_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la libsocket-util.la libiochannel.la +module_native_protocol_fd_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-native.la libsocket-server.la libsocket-util.la libiochannel.la # EsounD protocol module_esound_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c module_esound_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) module_esound_protocol_tcp_la_LDFLAGS = -module -avoid-version -module_esound_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-esound.la libsocket-server.la +module_esound_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-esound.la libsocket-server.la module_esound_protocol_unix_la_SOURCES = modules/module-protocol-stub.c module_esound_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS) module_esound_protocol_unix_la_LDFLAGS = -module -avoid-version -module_esound_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-esound.la libsocket-server.la libsocket-util.la +module_esound_protocol_unix_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-esound.la libsocket-server.la libsocket-util.la module_esound_compat_spawnfd_la_SOURCES = modules/module-esound-compat-spawnfd.c module_esound_compat_spawnfd_la_LDFLAGS = -module -avoid-version -module_esound_compat_spawnfd_la_LIBADD = $(AM_LIBADD) libpolypcore.la +module_esound_compat_spawnfd_la_LIBADD = $(AM_LIBADD) libpulsecore.la module_esound_compat_spawnpid_la_SOURCES = modules/module-esound-compat-spawnpid.c module_esound_compat_spawnpid_la_LDFLAGS = -module -avoid-version -module_esound_compat_spawnpid_la_LIBADD = $(AM_LIBADD) libpolypcore.la +module_esound_compat_spawnpid_la_LIBADD = $(AM_LIBADD) libpulsecore.la module_esound_sink_la_SOURCES = modules/module-esound-sink.c module_esound_sink_la_LDFLAGS = -module -avoid-version -module_esound_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la libsocket-client.la libauthkey.la +module_esound_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la libiochannel.la libsocket-client.la libauthkey.la # Pipes module_pipe_sink_la_SOURCES = modules/module-pipe-sink.c module_pipe_sink_la_LDFLAGS = -module -avoid-version -module_pipe_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la +module_pipe_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la libiochannel.la module_pipe_source_la_SOURCES = modules/module-pipe-source.c module_pipe_source_la_LDFLAGS = -module -avoid-version -module_pipe_source_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la +module_pipe_source_la_LIBADD = $(AM_LIBADD) libpulsecore.la libiochannel.la # Fake sources/sinks module_sine_la_SOURCES = modules/module-sine.c module_sine_la_LDFLAGS = -module -avoid-version -module_sine_la_LIBADD = $(AM_LIBADD) libpolypcore.la +module_sine_la_LIBADD = $(AM_LIBADD) libpulsecore.la module_null_sink_la_SOURCES = modules/module-null-sink.c module_null_sink_la_LDFLAGS = -module -avoid-version -module_null_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la +module_null_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la # Couplings module_combine_la_SOURCES = modules/module-combine.c module_combine_la_LDFLAGS = -module -avoid-version -module_combine_la_LIBADD = $(AM_LIBADD) libpolypcore.la +module_combine_la_LIBADD = $(AM_LIBADD) libpulsecore.la module_match_la_SOURCES = modules/module-match.c module_match_la_LDFLAGS = -module -avoid-version -module_match_la_LIBADD = $(AM_LIBADD) libpolypcore.la +module_match_la_LIBADD = $(AM_LIBADD) libpulsecore.la module_tunnel_sink_la_SOURCES = modules/module-tunnel.c module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS) module_tunnel_sink_la_LDFLAGS = -module -avoid-version -module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la +module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la module_tunnel_source_la_SOURCES = modules/module-tunnel.c module_tunnel_source_la_LDFLAGS = -module -avoid-version -module_tunnel_source_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la +module_tunnel_source_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la # X11 module_x11_bell_la_SOURCES = modules/module-x11-bell.c module_x11_bell_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) module_x11_bell_la_LDFLAGS = -module -avoid-version -module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la libpolypcore.la +module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la libpulsecore.la module_x11_publish_la_SOURCES = modules/module-x11-publish.c module_x11_publish_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) @@ -1063,7 +1063,7 @@ module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EX liboss_util_la_SOURCES = modules/oss-util.c modules/oss-util.h liboss_util_la_LDFLAGS = -avoid-version -liboss_util_la_LIBADD = libpolypcore.la +liboss_util_la_LIBADD = libpulsecore.la module_oss_la_SOURCES = modules/module-oss.c module_oss_la_LDFLAGS = -module -avoid-version @@ -1071,23 +1071,23 @@ module_oss_la_LIBADD = $(AM_LIBADD) libiochannel.la liboss-util.la module_oss_mmap_la_SOURCES = modules/module-oss-mmap.c module_oss_mmap_la_LDFLAGS = -module -avoid-version -module_oss_mmap_la_LIBADD = $(AM_LIBADD) liboss-util.la libpolypcore.la +module_oss_mmap_la_LIBADD = $(AM_LIBADD) liboss-util.la libpulsecore.la # ALSA libalsa_util_la_SOURCES = modules/alsa-util.c modules/alsa-util.h libalsa_util_la_LDFLAGS = -avoid-version -libalsa_util_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libpolypcore.la +libalsa_util_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libpulsecore.la libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) module_alsa_sink_la_SOURCES = modules/module-alsa-sink.c module_alsa_sink_la_LDFLAGS = -module -avoid-version -module_alsa_sink_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la libpolypcore.la +module_alsa_sink_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la libpulsecore.la module_alsa_sink_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) module_alsa_source_la_SOURCES = modules/module-alsa-source.c module_alsa_source_la_LDFLAGS = -module -avoid-version -module_alsa_source_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la libpolypcore.la +module_alsa_source_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la libpulsecore.la module_alsa_source_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) # Solaris @@ -1100,75 +1100,75 @@ module_solaris_la_LIBADD = $(AM_LIBADD) libiochannel.la libhowl_wrap_la_SOURCES = modules/howl-wrap.c modules/howl-wrap.h libhowl_wrap_la_LDFLAGS = -avoid-version -libhowl_wrap_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) libpolypcore.la +libhowl_wrap_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) libpulsecore.la libhowl_wrap_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) module_zeroconf_publish_la_SOURCES = modules/module-zeroconf-publish.c module_zeroconf_publish_la_LDFLAGS = -module -avoid-version -module_zeroconf_publish_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) libhowl-wrap.la libpolypcore.la +module_zeroconf_publish_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) libhowl-wrap.la libpulsecore.la module_zeroconf_publish_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) # LIRC module_lirc_la_SOURCES = modules/module-lirc.c module_lirc_la_LDFLAGS = -module -avoid-version -module_lirc_la_LIBADD = $(AM_LIBADD) $(LIRC_LIBS) libpolypcore.la +module_lirc_la_LIBADD = $(AM_LIBADD) $(LIRC_LIBS) libpulsecore.la module_lirc_la_CFLAGS = $(AM_CFLAGS) $(LIRC_CFLAGS) # Linux evdev module_mmkbd_evdev_la_SOURCES = modules/module-mmkbd-evdev.c module_mmkbd_evdev_la_LDFLAGS = -module -avoid-version -module_mmkbd_evdev_la_LIBADD = $(AM_LIBADD) libpolypcore.la +module_mmkbd_evdev_la_LIBADD = $(AM_LIBADD) libpulsecore.la module_mmkbd_evdev_la_CFLAGS = $(AM_CFLAGS) # Windows waveout module_waveout_la_SOURCES = modules/module-waveout.c module_waveout_la_LDFLAGS = -module -avoid-version -module_waveout_la_LIBADD = $(AM_LIBADD) libpolypcore.la -lwinmm +module_waveout_la_LIBADD = $(AM_LIBADD) libpulsecore.la -lwinmm module_waveout_la_CFLAGS = $(AM_CFLAGS) # Hardware autodetection module module_detect_la_SOURCES = modules/module-detect.c module_detect_la_LDFLAGS = -module -avoid-version -module_detect_la_LIBADD = $(AM_LIBADD) libpolypcore.la +module_detect_la_LIBADD = $(AM_LIBADD) libpulsecore.la module_detect_la_CFLAGS = $(AM_CFLAGS) # Volume restore module module_volume_restore_la_SOURCES = modules/module-volume-restore.c module_volume_restore_la_LDFLAGS = -module -avoid-version -module_volume_restore_la_LIBADD = $(AM_LIBADD) libpolypcore.la +module_volume_restore_la_LIBADD = $(AM_LIBADD) libpulsecore.la module_volume_restore_la_CFLAGS = $(AM_CFLAGS) # RTP modules module_rtp_send_la_SOURCES = modules/rtp/module-rtp-send.c module_rtp_send_la_LDFLAGS = -module -avoid-version -module_rtp_send_la_LIBADD = $(AM_LIBADD) libpolypcore.la librtp.la +module_rtp_send_la_LIBADD = $(AM_LIBADD) libpulsecore.la librtp.la module_rtp_send_la_CFLAGS = $(AM_CFLAGS) module_rtp_recv_la_SOURCES = modules/rtp/module-rtp-recv.c module_rtp_recv_la_LDFLAGS = -module -avoid-version -module_rtp_recv_la_LIBADD = $(AM_LIBADD) libpolypcore.la librtp.la +module_rtp_recv_la_LIBADD = $(AM_LIBADD) libpulsecore.la librtp.la module_rtp_recv_la_CFLAGS = $(AM_CFLAGS) # JACK module_jack_sink_la_SOURCES = modules/module-jack-sink.c module_jack_sink_la_LDFLAGS = -module -avoid-version -module_jack_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la $(JACK_LIBS) +module_jack_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la $(JACK_LIBS) module_jack_sink_la_CFLAGS = $(AM_LIBADD) $(JACK_CFLAGS) module_jack_source_la_SOURCES = modules/module-jack-source.c module_jack_source_la_LDFLAGS = -module -avoid-version -module_jack_source_la_LIBADD = $(AM_LIBADD) libpolypcore.la $(JACK_LIBS) +module_jack_source_la_LIBADD = $(AM_LIBADD) libpulsecore.la $(JACK_LIBS) module_jack_source_la_CFLAGS = $(AM_LIBADD) $(JACK_CFLAGS) ################################### # Some minor stuff # ################################### -suid: polypaudio +suid: pulse chown root $< chmod u+s $< @@ -1179,7 +1179,7 @@ esdcompat: daemon/esdcompat.in Makefile -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ -client.conf: polyp/client.conf.in Makefile +client.conf: pulse/client.conf.in Makefile sed -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ if OS_IS_WIN32 @@ -1195,11 +1195,11 @@ daemon.conf: daemon/daemon.conf.in Makefile -e 's,@DEFAULT_CONFIG_FILE\@,$(DEFAULT_CONFIG_DIR),g' < $< > $@ install-exec-hook: - chown root $(DESTDIR)$(bindir)/polypaudio ; true - chmod u+s $(DESTDIR)$(bindir)/polypaudio + chown root $(DESTDIR)$(bindir)/pulseaudio ; true + chmod u+s $(DESTDIR)$(bindir)/pulseaudio ln -sf pacat $(DESTDIR)$(bindir)/parec rm -f $(DESTDIR)$(modlibexecdir)/*.a - rm -f $(DESTDIR)$(libdir)/libpolypdsp.a - rm -f $(DESTDIR)$(libdir)/libpolypdsp.la + rm -f $(DESTDIR)$(libdir)/libpulsedsp.a + rm -f $(DESTDIR)$(libdir)/libpulsedsp.la .PHONY: utils/padsp diff --git a/src/daemon/Makefile b/src/daemon/Makefile index cd2a5c9a..c110232d 120000 --- a/src/daemon/Makefile +++ b/src/daemon/Makefile @@ -1 +1 @@ -../polyp/Makefile \ No newline at end of file +../pulse/Makefile \ No newline at end of file diff --git a/src/daemon/caps.c b/src/daemon/caps.c index 5e24da82..dc74bc7d 100644 --- a/src/daemon/caps.c +++ b/src/daemon/caps.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -32,9 +32,9 @@ #include #endif -#include +#include -#include +#include #include "caps.h" diff --git a/src/daemon/caps.h b/src/daemon/caps.h index 3bb861d1..8a618286 100644 --- a/src/daemon/caps.h +++ b/src/daemon/caps.h @@ -4,20 +4,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c index b71be2e6..a106dc09 100644 --- a/src/daemon/cmdline.c +++ b/src/daemon/cmdline.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -30,10 +30,10 @@ #include #include -#include +#include -#include -#include +#include +#include #include "cmdline.h" diff --git a/src/daemon/cmdline.h b/src/daemon/cmdline.h index e2eaf0d2..25453e55 100644 --- a/src/daemon/cmdline.h +++ b/src/daemon/cmdline.h @@ -4,20 +4,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/src/daemon/cpulimit.c b/src/daemon/cpulimit.c index d537b9db..a8c9d3f5 100644 --- a/src/daemon/cpulimit.c +++ b/src/daemon/cpulimit.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software + License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -23,11 +23,11 @@ #include #endif -#include +#include -#include -#include -#include +#include +#include +#include #include "cpulimit.h" diff --git a/src/daemon/cpulimit.h b/src/daemon/cpulimit.h index f3c5534d..21bdd17b 100644 --- a/src/daemon/cpulimit.h +++ b/src/daemon/cpulimit.h @@ -4,27 +4,27 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ -#include +#include -/* This kills the polypaudio process if it eats more than 70% of the +/* This kills the pulseaudio process if it eats more than 70% of the * CPU time. This is build around setrlimit() and SIGXCPU. It is handy * in case of using SCHED_FIFO which may freeze the whole machine */ diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 2d8d9558..fd83f28f 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -29,19 +29,19 @@ #include #include -#include +#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include "daemon-conf.h" #ifndef DEFAULT_CONFIG_DIR # ifndef OS_IS_WIN32 -# define DEFAULT_CONFIG_DIR "/etc/polypaudio" +# define DEFAULT_CONFIG_DIR "/etc/pulseaudio" # else # define DEFAULT_CONFIG_DIR "%POLYP_ROOT%" # endif @@ -54,9 +54,9 @@ #endif #define DEFAULT_SCRIPT_FILE DEFAULT_CONFIG_DIR PATH_SEP "default.pa" -#define DEFAULT_SCRIPT_FILE_USER ".polypaudio" PATH_SEP "default.pa" +#define DEFAULT_SCRIPT_FILE_USER ".pulseaudio" PATH_SEP "default.pa" #define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "daemon.conf" -#define DEFAULT_CONFIG_FILE_USER ".polypaudio" PATH_SEP "daemon.conf" +#define DEFAULT_CONFIG_FILE_USER ".pulseaudio" PATH_SEP "daemon.conf" #define ENV_SCRIPT_FILE "POLYP_SCRIPT" #define ENV_CONFIG_FILE "POLYP_CONFIG" diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h index d5131419..dd5d7fb8 100644 --- a/src/daemon/daemon-conf.h +++ b/src/daemon/daemon-conf.h @@ -4,25 +4,25 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ -#include +#include /* The actual command to execute */ typedef enum pa_daemon_conf_cmd { diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in index d5373018..30bf3ca1 100644 --- a/src/daemon/daemon.conf.in +++ b/src/daemon/daemon.conf.in @@ -1,23 +1,23 @@ # $Id$ # -# This file is part of polypaudio. +# This file is part of PulseAudio. # -# polypaudio is free software; you can redistribute it and/or modify +# PulseAudio is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # -# polypaudio is distributed in the hope that it will be useful, but +# PulseAudio is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software +# along with PulseAudio; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -## Configuration file for the polypaudio daemon. Default values are +## Configuration file for the pulseaudio daemon. Default values are ## commented out. Use either ; or # for commenting # Extra verbositiy @@ -69,9 +69,9 @@ ## hand it has the worst quality of all. ; resample-method = sinc-fastest -## Create a PID file in /tmp/polypaudio-$USER/pid. Of this is enabled -## you may use commands like "polypaudio --kill" or "polypaudio -## --check". If you are planning to start more than one polypaudio +## Create a PID file in /tmp/pulseaudio-$USER/pid. Of this is enabled +## you may use commands like "pulseaudio --kill" or "pulseaudio +## --check". If you are planning to start more than one pulseaudio ## process per user, you better disable this option since it ## effectively disables multiple instances. ; use-pid-file = 1 diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in index cba0172f..623cd114 100755 --- a/src/daemon/default.pa.in +++ b/src/daemon/default.pa.in @@ -1,20 +1,20 @@ #!@POLYPAUDIO_BINARY@ -nF # -# This file is part of polypaudio. +# This file is part of PulseAudio. # -# polypaudio is free software; you can redistribute it and/or modify it +# PulseAudio is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # -# polypaudio is distributed in the hope that it will be useful, but +# PulseAudio is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software Foundation, +# along with PulseAudio; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/src/daemon/default.pa.win32 b/src/daemon/default.pa.win32 index 3478adab..d5a1e183 100644 --- a/src/daemon/default.pa.win32 +++ b/src/daemon/default.pa.win32 @@ -1,18 +1,18 @@ # -# This file is part of polypaudio. +# This file is part of PulseAudio. # -# polypaudio is free software; you can redistribute it and/or modify it +# PulseAudio is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # -# polypaudio is distributed in the hope that it will be useful, but +# PulseAudio is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software Foundation, +# along with PulseAudio; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. diff --git a/src/daemon/dumpmodules.c b/src/daemon/dumpmodules.c index d56bb798..06734ea6 100644 --- a/src/daemon/dumpmodules.c +++ b/src/daemon/dumpmodules.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -29,9 +29,9 @@ #include #include -#include +#include -#include +#include #include "dumpmodules.h" diff --git a/src/daemon/dumpmodules.h b/src/daemon/dumpmodules.h index 968d2de9..05cd86e0 100644 --- a/src/daemon/dumpmodules.h +++ b/src/daemon/dumpmodules.h @@ -4,20 +4,20 @@ /* $Id*/ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ diff --git a/src/daemon/esdcompat.in b/src/daemon/esdcompat.in index 76023f52..673f8c8a 100755 --- a/src/daemon/esdcompat.in +++ b/src/daemon/esdcompat.in @@ -2,20 +2,20 @@ # $Id$ # -# This file is part of polypaudio. +# This file is part of PulseAudio. # -# polypaudio is free software; you can redistribute it and/or modify +# PulseAudio is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # -# polypaudio is distributed in the hope that it will be useful, but +# PulseAudio is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software +# along with PulseAudio; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. diff --git a/src/daemon/main.c b/src/daemon/main.c index 16cc0f5e..5e7330a5 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -48,24 +48,24 @@ #include #endif -#include "../polypcore/winsock.h" +#include "../pulsecore/winsock.h" -#include -#include -#include +#include +#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "cmdline.h" #include "cpulimit.h" @@ -199,7 +199,7 @@ int main(int argc, char *argv[]) { pa_random_seed(); - pa_log_set_ident("polypaudio"); + pa_log_set_ident("pulseaudio"); conf = pa_daemon_conf_new(); diff --git a/src/depmod.py b/src/depmod.py index 7bb223b1..a20bc7c0 100755 --- a/src/depmod.py +++ b/src/depmod.py @@ -1,20 +1,20 @@ #!/usr/bin/python # $Id$ # -# This file is part of polypaudio. +# This file is part of PulseAudio. # -# polypaudio is free software; you can redistribute it and/or modify +# PulseAudio is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # -# polypaudio is distributed in the hope that it will be useful, but +# PulseAudio is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software +# along with PulseAudio; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. diff --git a/src/modules/Makefile b/src/modules/Makefile index cd2a5c9a..c110232d 120000 --- a/src/modules/Makefile +++ b/src/modules/Makefile @@ -1 +1 @@ -../polyp/Makefile \ No newline at end of file +../pulse/Makefile \ No newline at end of file diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index fafcac48..04a2d849 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -26,10 +26,10 @@ #include #include -#include -#include +#include +#include -#include +#include #include "alsa-util.h" diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h index 83d1481f..215844b4 100644 --- a/src/modules/alsa-util.h +++ b/src/modules/alsa-util.h @@ -4,30 +4,30 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include -#include -#include +#include +#include -#include +#include struct pa_alsa_fdlist; diff --git a/src/modules/howl-wrap.c b/src/modules/howl-wrap.c index 467ab9e2..e56fca3e 100644 --- a/src/modules/howl-wrap.c +++ b/src/modules/howl-wrap.c @@ -1,30 +1,30 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software + License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include -#include +#include -#include -#include +#include +#include #include "howl-wrap.h" diff --git a/src/modules/howl-wrap.h b/src/modules/howl-wrap.h index a4b26490..506c0b68 100644 --- a/src/modules/howl-wrap.h +++ b/src/modules/howl-wrap.h @@ -4,27 +4,27 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software + License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include -#include +#include typedef struct pa_howl_wrapper pa_howl_wrapper; diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 620047b7..d49b3407 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -34,16 +34,16 @@ #include -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include "alsa-util.h" #include "module-alsa-sink-symdef.h" diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 0999c65f..c4e8689c 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -34,17 +34,17 @@ #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "alsa-util.h" #include "module-alsa-source-symdef.h" diff --git a/src/modules/module-cli.c b/src/modules/module-cli.c index ce50a46b..2eef5c46 100644 --- a/src/modules/module-cli.c +++ b/src/modules/module-cli.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -27,12 +27,12 @@ #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include "module-cli-symdef.h" diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 037cbaf7..4e3dd555 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -26,18 +26,18 @@ #include #include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "module-combine-symdef.h" diff --git a/src/modules/module-defs.h.m4 b/src/modules/module-defs.h.m4 index 8f10d659..c961412d 100644 --- a/src/modules/module-defs.h.m4 +++ b/src/modules/module-defs.h.m4 @@ -8,8 +8,8 @@ define(`gen_symbol', `#define $1 'module_name`_LTX_$1')dnl #ifndef incmacro #define incmacro -#include -#include +#include +#include gen_symbol(pa__init) gen_symbol(pa__done) diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index 3512e31c..3e4d2bf6 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -33,13 +33,13 @@ #include #include -#include +#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include "module-detect-symdef.h" diff --git a/src/modules/module-esound-compat-spawnfd.c b/src/modules/module-esound-compat-spawnfd.c index 861e2570..c4bc342a 100644 --- a/src/modules/module-esound-compat-spawnfd.c +++ b/src/modules/module-esound-compat-spawnfd.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -28,11 +28,11 @@ #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include "module-esound-compat-spawnfd-symdef.h" diff --git a/src/modules/module-esound-compat-spawnpid.c b/src/modules/module-esound-compat-spawnpid.c index 7b47bb0a..3108baf7 100644 --- a/src/modules/module-esound-compat-spawnpid.c +++ b/src/modules/module-esound-compat-spawnpid.c @@ -1,19 +1,19 @@ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -28,11 +28,11 @@ #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include "module-esound-compat-spawnpid-symdef.h" diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index 53a9411a..75a47b04 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -33,18 +33,18 @@ #include #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "module-esound-sink-symdef.h" diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index fc2bfc45..c6a161ff 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -36,16 +36,16 @@ #include -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include "module-jack-sink-symdef.h" @@ -261,7 +261,7 @@ int pa__init(pa_core *c, pa_module*m) { } server_name = pa_modargs_get_value(ma, "server_name", NULL); - client_name = pa_modargs_get_value(ma, "client_name", "polypaudio"); + client_name = pa_modargs_get_value(ma, "client_name", "pulseaudio"); u = pa_xnew0(struct userdata, 1); m->userdata = u; diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index ca9560a6..6f31f6c3 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -36,16 +36,16 @@ #include -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include "module-jack-source-symdef.h" @@ -259,7 +259,7 @@ int pa__init(pa_core *c, pa_module*m) { } server_name = pa_modargs_get_value(ma, "server_name", NULL); - client_name = pa_modargs_get_value(ma, "client_name", "polypaudio"); + client_name = pa_modargs_get_value(ma, "client_name", "pulseaudio"); u = pa_xnew0(struct userdata, 1); m->userdata = u; diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c index 009c2e46..a93a3b92 100644 --- a/src/modules/module-lirc.c +++ b/src/modules/module-lirc.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -30,13 +30,13 @@ #include #include -#include +#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include "module-lirc-symdef.h" @@ -203,7 +203,7 @@ int pa__init(pa_core *c, pa_module*m) { u->lirc_fd = -1; u->mute_toggle_save = 0; - if ((u->lirc_fd = lirc_init((char*) pa_modargs_get_value(ma, "appname", "polypaudio"), 1)) < 0) { + if ((u->lirc_fd = lirc_init((char*) pa_modargs_get_value(ma, "appname", "pulseaudio"), 1)) < 0) { pa_log(__FILE__": lirc_init() failed."); goto fail; } diff --git a/src/modules/module-match.c b/src/modules/module-match.c index 02d75e7e..ddeda734 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -32,16 +32,16 @@ #include #include -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include "module-match-symdef.h" @@ -53,11 +53,11 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define WHITESPACE "\n\r \t" #ifndef DEFAULT_CONFIG_DIR -#define DEFAULT_CONFIG_DIR "/etc/polypaudio" +#define DEFAULT_CONFIG_DIR "/etc/pulseaudio" #endif #define DEFAULT_MATCH_TABLE_FILE DEFAULT_CONFIG_DIR"/match.table" -#define DEFAULT_MATCH_TABLE_FILE_USER ".polypaudio/match.table" +#define DEFAULT_MATCH_TABLE_FILE_USER ".pulseaudio/match.table" static const char* const valid_modargs[] = { "table", diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c index ee2c6bff..ddbf16d2 100644 --- a/src/modules/module-mmkbd-evdev.c +++ b/src/modules/module-mmkbd-evdev.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -33,15 +33,15 @@ #include -#include +#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include "module-mmkbd-evdev-symdef.h" diff --git a/src/modules/module-native-protocol-fd.c b/src/modules/module-native-protocol-fd.c index e3caf55a..9e1cac09 100644 --- a/src/modules/module-native-protocol-fd.c +++ b/src/modules/module-native-protocol-fd.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -27,11 +27,11 @@ #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include "module-native-protocol-fd-symdef.h" diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index a1555e67..8cfce8fe 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -33,15 +33,15 @@ #include #include -#include -#include +#include +#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include "module-null-sink-symdef.h" diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index 5cf6228f..fcc89c84 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -36,17 +36,17 @@ #include #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "oss-util.h" #include "module-oss-mmap-symdef.h" diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 88724673..5a80661e 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -35,17 +35,17 @@ #include #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "oss-util.h" #include "module-oss-symdef.h" diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index 01598e38..4878a1a1 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -33,15 +33,15 @@ #include #include -#include +#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include "module-pipe-sink-symdef.h" diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index be2a28d5..f2f214c7 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -33,15 +33,15 @@ #include #include -#include +#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include "module-pipe-source-symdef.h" diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index 2b4f303b..20728766 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -40,18 +40,18 @@ #include #endif -#include "../polypcore/winsock.h" +#include "../pulsecore/winsock.h" -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #ifdef USE_TCP_SOCKETS #define SOCKET_DESCRIPTION "(TCP sockets)" @@ -62,10 +62,10 @@ #endif #if defined(USE_PROTOCOL_SIMPLE) - #include + #include #define protocol_new pa_protocol_simple_new #define protocol_free pa_protocol_simple_free - #define TCPWRAP_SERVICE "polypaudio-simple" + #define TCPWRAP_SERVICE "pulseaudio-simple" #define IPV4_PORT 4711 #define UNIX_SOCKET "simple" #define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record", @@ -77,10 +77,10 @@ PA_MODULE_DESCRIPTION("Simple protocol "SOCKET_DESCRIPTION) PA_MODULE_USAGE("rate= format= channels= sink= source= playback= record= "SOCKET_USAGE) #elif defined(USE_PROTOCOL_CLI) - #include + #include #define protocol_new pa_protocol_cli_new #define protocol_free pa_protocol_cli_free - #define TCPWRAP_SERVICE "polypaudio-cli" + #define TCPWRAP_SERVICE "pulseaudio-cli" #define IPV4_PORT 4712 #define UNIX_SOCKET "cli" #define MODULE_ARGUMENTS @@ -92,10 +92,10 @@ PA_MODULE_DESCRIPTION("Command line interface protocol "SOCKET_DESCRIPTION) PA_MODULE_USAGE(SOCKET_USAGE) #elif defined(USE_PROTOCOL_HTTP) - #include + #include #define protocol_new pa_protocol_http_new #define protocol_free pa_protocol_http_free - #define TCPWRAP_SERVICE "polypaudio-http" + #define TCPWRAP_SERVICE "pulseaudio-http" #define IPV4_PORT 4714 #define UNIX_SOCKET "http" #define MODULE_ARGUMENTS @@ -107,10 +107,10 @@ PA_MODULE_DESCRIPTION("HTTP "SOCKET_DESCRIPTION) PA_MODULE_USAGE(SOCKET_USAGE) #elif defined(USE_PROTOCOL_NATIVE) - #include + #include #define protocol_new pa_protocol_native_new #define protocol_free pa_protocol_native_free - #define TCPWRAP_SERVICE "polypaudio-native" + #define TCPWRAP_SERVICE "pulseaudio-native" #define IPV4_PORT PA_NATIVE_DEFAULT_PORT #define UNIX_SOCKET PA_NATIVE_DEFAULT_UNIX_SOCKET #define MODULE_ARGUMENTS_COMMON "cookie", "auth-anonymous", @@ -131,8 +131,8 @@ PA_MODULE_DESCRIPTION("Native protocol "SOCKET_DESCRIPTION) PA_MODULE_USAGE("auth-anonymous= cookie= "AUTH_USAGE SOCKET_USAGE) #elif defined(USE_PROTOCOL_ESOUND) - #include - #include + #include + #include #define protocol_new pa_protocol_esound_new #define protocol_free pa_protocol_esound_free #define TCPWRAP_SERVICE "esound" diff --git a/src/modules/module-sine.c b/src/modules/module-sine.c index 15b6c8a9..f4392b9a 100644 --- a/src/modules/module-sine.c +++ b/src/modules/module-sine.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -27,13 +27,13 @@ #include #include -#include +#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include "module-sine-symdef.h" diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 8670bb35..12c4a3ff 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -40,18 +40,18 @@ #include #include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include #include "module-solaris-symdef.h" diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index bf1fafb3..bf2627a7 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -31,24 +31,24 @@ #include #include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #ifdef TUNNEL_SINK #include "module-tunnel-sink-symdef.h" diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index 435f0c96..ede2fcf2 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -32,17 +32,17 @@ #include #include -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "module-volume-restore-symdef.h" @@ -53,7 +53,7 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define WHITESPACE "\n\r \t" -#define DEFAULT_VOLUME_TABLE_FILE ".polypaudio/volume.table" +#define DEFAULT_VOLUME_TABLE_FILE ".pulseaudio/volume.table" static const char* const valid_modargs[] = { "table", diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index ce9ea84d..2bd4905a 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -27,17 +27,17 @@ #include #include -#include +#include -#include +#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include "module-waveout-symdef.h" diff --git a/src/modules/module-x11-bell.c b/src/modules/module-x11-bell.c index 2b891bc1..7ac5f558 100644 --- a/src/modules/module-x11-bell.c +++ b/src/modules/module-x11-bell.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -31,15 +31,15 @@ #include #include -#include +#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include "module-x11-bell-symdef.h" diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c index 70d75038..99163035 100644 --- a/src/modules/module-x11-publish.c +++ b/src/modules/module-x11-publish.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -32,23 +32,23 @@ #include #include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "module-x11-publish-symdef.h" diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index c07c95f3..14cbef46 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software + License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -29,20 +29,20 @@ #include #include -#include -#include +#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include "../polypcore/endianmacros.h" +#include "../pulsecore/endianmacros.h" #include "howl-wrap.h" @@ -53,9 +53,9 @@ PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Publisher") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("port=") -#define SERVICE_NAME_SINK "_polypaudio-sink._tcp" -#define SERVICE_NAME_SOURCE "_polypaudio-source._tcp" -#define SERVICE_NAME_SERVER "_polypaudio-server._tcp" +#define SERVICE_NAME_SINK "_pulseaudio-sink._tcp" +#define SERVICE_NAME_SOURCE "_pulseaudio-source._tcp" +#define SERVICE_NAME_SERVER "_pulseaudio-server._tcp" static const char* const valid_modargs[] = { "port", diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index ff337a5c..f4cc45de 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -34,9 +34,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include "oss-util.h" diff --git a/src/modules/oss-util.h b/src/modules/oss-util.h index c652d2a1..12855f4e 100644 --- a/src/modules/oss-util.h +++ b/src/modules/oss-util.h @@ -4,26 +4,26 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ -#include -#include +#include +#include int pa_oss_open(const char *device, int *mode, int* pcaps); int pa_oss_auto_format(int fd, pa_sample_spec *ss); diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index c448502e..932da849 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -1,19 +1,19 @@ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -31,20 +31,20 @@ #include #include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "module-rtp-recv-symdef.h" diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 4359d00d..00da64d5 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -32,20 +32,20 @@ #include #include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "module-rtp-send-symdef.h" diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c index 52a1819c..ee037d42 100644 --- a/src/modules/rtp/rtp.c +++ b/src/modules/rtp/rtp.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -36,8 +36,8 @@ #include #endif -#include -#include +#include +#include #include "rtp.h" diff --git a/src/modules/rtp/rtp.h b/src/modules/rtp/rtp.h index 49da155b..35fbbd35 100644 --- a/src/modules/rtp/rtp.h +++ b/src/modules/rtp/rtp.h @@ -4,20 +4,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -25,8 +25,8 @@ #include #include #include -#include -#include +#include +#include typedef struct pa_rtp_context { int fd; diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c index 134bab09..3814a1c3 100644 --- a/src/modules/rtp/sap.c +++ b/src/modules/rtp/sap.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -38,11 +38,11 @@ #include #endif -#include +#include -#include -#include -#include +#include +#include +#include #include "sap.h" #include "sdp.h" diff --git a/src/modules/rtp/sap.h b/src/modules/rtp/sap.h index b11b1dd7..987403e3 100644 --- a/src/modules/rtp/sap.h +++ b/src/modules/rtp/sap.h @@ -4,20 +4,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -25,8 +25,8 @@ #include #include #include -#include -#include +#include +#include typedef struct pa_sap_context { int fd; diff --git a/src/modules/rtp/sdp.c b/src/modules/rtp/sdp.c index 5ec5090d..cada636a 100644 --- a/src/modules/rtp/sdp.c +++ b/src/modules/rtp/sdp.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -31,10 +31,10 @@ #include #include -#include +#include -#include -#include +#include +#include #include "sdp.h" #include "rtp.h" diff --git a/src/modules/rtp/sdp.h b/src/modules/rtp/sdp.h index 2aa18056..b95ca633 100644 --- a/src/modules/rtp/sdp.h +++ b/src/modules/rtp/sdp.h @@ -4,20 +4,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -26,7 +26,7 @@ #include #include -#include +#include #define PA_SDP_HEADER "v=0\n" diff --git a/src/polyp/Makefile b/src/polyp/Makefile deleted file mode 100644 index 7c8875f3..00000000 --- a/src/polyp/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# This is a dirty trick just to ease compilation with emacs -# -# This file is not intended to be distributed or anything -# -# So: don't touch it, even better ignore it! - -all: - $(MAKE) -C .. - -clean: - $(MAKE) -C .. clean - -.PHONY: all clean diff --git a/src/polyp/browser.c b/src/polyp/browser.c deleted file mode 100644 index 69760d8d..00000000 --- a/src/polyp/browser.c +++ /dev/null @@ -1,334 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -#include - -#include -#include - -#include "browser.h" - -#define SERVICE_NAME_SINK "_polypaudio-sink._tcp." -#define SERVICE_NAME_SOURCE "_polypaudio-source._tcp." -#define SERVICE_NAME_SERVER "_polypaudio-server._tcp." - -struct pa_browser { - int ref; - pa_mainloop_api *mainloop; - - pa_browse_cb_t callback; - void *userdata; - - sw_discovery discovery; - pa_io_event *io_event; -}; - -static void io_callback(pa_mainloop_api*a, PA_GCC_UNUSED pa_io_event*e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void *userdata) { - pa_browser *b = userdata; - assert(a && b && b->mainloop == a); - - if (events != PA_IO_EVENT_INPUT || sw_discovery_read_socket(b->discovery) != SW_OKAY) { - pa_log(__FILE__": connection to HOWL daemon failed."); - b->mainloop->io_free(b->io_event); - b->io_event = NULL; - return; - } -} - -static int type_equal(const char *a, const char *b) { - size_t la, lb; - - if (strcasecmp(a, b) == 0) - return 1; - - la = strlen(a); - lb = strlen(b); - - if (la > 0 && a[la-1] == '.' && la == lb+1 && strncasecmp(a, b, la-1) == 0) - return 1; - - if (lb > 0 && b[lb-1] == '.' && lb == la+1 && strncasecmp(a, b, lb-1) == 0) - return 1; - - return 0; -} - -static int map_to_opcode(const char *type, int new) { - if (type_equal(type, SERVICE_NAME_SINK)) - return new ? PA_BROWSE_NEW_SINK : PA_BROWSE_REMOVE_SINK; - else if (type_equal(type, SERVICE_NAME_SOURCE)) - return new ? PA_BROWSE_NEW_SOURCE : PA_BROWSE_REMOVE_SOURCE; - else if (type_equal(type, SERVICE_NAME_SERVER)) - return new ? PA_BROWSE_NEW_SERVER : PA_BROWSE_REMOVE_SERVER; - - return -1; -} - -static sw_result resolve_reply( - sw_discovery discovery, - sw_discovery_oid oid, - sw_uint32 interface_index, - sw_const_string name, - sw_const_string type, - sw_const_string domain, - sw_ipv4_address address, - sw_port port, - sw_octets text_record, - sw_ulong text_record_len, - sw_opaque extra) { - - pa_browser *b = extra; - pa_browse_info i; - char ip[256], a[256]; - int opcode; - int device_found = 0; - uint32_t cookie; - pa_sample_spec ss; - int ss_valid = 0; - sw_text_record_iterator iterator; - int free_iterator = 0; - char *c = NULL; - - assert(b); - - sw_discovery_cancel(discovery, oid); - - memset(&i, 0, sizeof(i)); - i.name = name; - - if (!b->callback) - goto fail; - - opcode = map_to_opcode(type, 1); - assert(opcode >= 0); - - snprintf(a, sizeof(a), "tcp:%s:%u", sw_ipv4_address_name(address, ip, sizeof(ip)), port); - i.server = a; - - if (text_record && text_record_len) { - char key[SW_TEXT_RECORD_MAX_LEN]; - uint8_t val[SW_TEXT_RECORD_MAX_LEN]; - uint32_t val_len; - - if (sw_text_record_iterator_init(&iterator, text_record, text_record_len) != SW_OKAY) { - pa_log_error(__FILE__": sw_text_record_string_iterator_init() failed."); - goto fail; - } - - free_iterator = 1; - - while (sw_text_record_iterator_next(iterator, key, val, &val_len) == SW_OKAY) { - c = pa_xstrndup((char*) val, val_len); - - if (!strcmp(key, "device")) { - device_found = 1; - pa_xfree((char*) i.device); - i.device = c; - c = NULL; - } else if (!strcmp(key, "server-version")) { - pa_xfree((char*) i.server_version); - i.server_version = c; - c = NULL; - } else if (!strcmp(key, "user-name")) { - pa_xfree((char*) i.user_name); - i.user_name = c; - c = NULL; - } else if (!strcmp(key, "fqdn")) { - size_t l; - - pa_xfree((char*) i.fqdn); - i.fqdn = c; - c = NULL; - - l = strlen(a); - assert(l+1 <= sizeof(a)); - strncat(a, " ", sizeof(a)-l-1); - strncat(a, i.fqdn, sizeof(a)-l-2); - } else if (!strcmp(key, "cookie")) { - - if (pa_atou(c, &cookie) < 0) - goto fail; - - i.cookie = &cookie; - } else if (!strcmp(key, "description")) { - pa_xfree((char*) i.description); - i.description = c; - c = NULL; - } else if (!strcmp(key, "channels")) { - uint32_t ch; - - if (pa_atou(c, &ch) < 0 || ch <= 0 || ch > 255) - goto fail; - - ss.channels = (uint8_t) ch; - ss_valid |= 1; - - } else if (!strcmp(key, "rate")) { - if (pa_atou(c, &ss.rate) < 0) - goto fail; - ss_valid |= 2; - } else if (!strcmp(key, "format")) { - - if ((ss.format = pa_parse_sample_format(c)) == PA_SAMPLE_INVALID) - goto fail; - - ss_valid |= 4; - } - - pa_xfree(c); - c = NULL; - } - - } - - /* No device txt record was sent for a sink or source service */ - if (opcode != PA_BROWSE_NEW_SERVER && !device_found) - goto fail; - - if (ss_valid == 7) - i.sample_spec = &ss; - - - b->callback(b, opcode, &i, b->userdata); - -fail: - pa_xfree((void*) i.device); - pa_xfree((void*) i.fqdn); - pa_xfree((void*) i.server_version); - pa_xfree((void*) i.user_name); - pa_xfree((void*) i.description); - pa_xfree(c); - - if (free_iterator) - sw_text_record_iterator_fina(iterator); - - - return SW_OKAY; -} - -static sw_result browse_reply( - sw_discovery discovery, - sw_discovery_oid id, - sw_discovery_browse_status status, - sw_uint32 interface_index, - sw_const_string name, - sw_const_string type, - sw_const_string domain, - sw_opaque extra) { - - pa_browser *b = extra; - assert(b); - - switch (status) { - case SW_DISCOVERY_BROWSE_ADD_SERVICE: { - sw_discovery_oid oid; - - if (sw_discovery_resolve(b->discovery, 0, name, type, domain, resolve_reply, b, &oid) != SW_OKAY) - pa_log_error(__FILE__": sw_discovery_resolve() failed"); - - break; - } - - case SW_DISCOVERY_BROWSE_REMOVE_SERVICE: - if (b->callback) { - pa_browse_info i; - int opcode; - - memset(&i, 0, sizeof(i)); - i.name = name; - - opcode = map_to_opcode(type, 0); - assert(opcode >= 0); - - b->callback(b, opcode, &i, b->userdata); - } - break; - - default: - ; - } - - return SW_OKAY; -} - -pa_browser *pa_browser_new(pa_mainloop_api *mainloop) { - pa_browser *b; - sw_discovery_oid oid; - - b = pa_xnew(pa_browser, 1); - b->mainloop = mainloop; - b->ref = 1; - b->callback = NULL; - b->userdata = NULL; - - if (sw_discovery_init(&b->discovery) != SW_OKAY) { - pa_log_error(__FILE__": sw_discovery_init() failed."); - pa_xfree(b); - return NULL; - } - - if (sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SERVER, NULL, browse_reply, b, &oid) != SW_OKAY || - sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SINK, NULL, browse_reply, b, &oid) != SW_OKAY || - sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SOURCE, NULL, browse_reply, b, &oid) != SW_OKAY) { - - pa_log_error(__FILE__": sw_discovery_browse() failed."); - - sw_discovery_fina(b->discovery); - pa_xfree(b); - return NULL; - } - - b->io_event = mainloop->io_new(mainloop, sw_discovery_socket(b->discovery), PA_IO_EVENT_INPUT, io_callback, b); - return b; -} - -static void browser_free(pa_browser *b) { - assert(b && b->mainloop); - - if (b->io_event) - b->mainloop->io_free(b->io_event); - - sw_discovery_fina(b->discovery); - pa_xfree(b); -} - -pa_browser *pa_browser_ref(pa_browser *b) { - assert(b && b->ref >= 1); - b->ref++; - return b; -} - -void pa_browser_unref(pa_browser *b) { - assert(b && b->ref >= 1); - - if ((-- (b->ref)) <= 0) - browser_free(b); -} - -void pa_browser_set_callback(pa_browser *b, pa_browse_cb_t cb, void *userdata) { - assert(b); - - b->callback = cb; - b->userdata = userdata; -} diff --git a/src/polyp/browser.h b/src/polyp/browser.h deleted file mode 100644 index 1ff58d8c..00000000 --- a/src/polyp/browser.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef foobrowserhfoo -#define foobrowserhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include - -PA_C_DECL_BEGIN - -typedef struct pa_browser pa_browser; - -typedef enum pa_browse_opcode { - PA_BROWSE_NEW_SERVER = 0, - PA_BROWSE_NEW_SINK, - PA_BROWSE_NEW_SOURCE, - PA_BROWSE_REMOVE_SERVER, - PA_BROWSE_REMOVE_SINK, - PA_BROWSE_REMOVE_SOURCE -} pa_browse_opcode_t; - -pa_browser *pa_browser_new(pa_mainloop_api *mainloop); -pa_browser *pa_browser_ref(pa_browser *z); -void pa_browser_unref(pa_browser *z); - -typedef struct pa_browse_info { - /* Unique service name */ - const char *name; /* always available */ - - /* Server info */ - const char *server; /* always available */ - const char *server_version, *user_name, *fqdn; /* optional */ - const uint32_t *cookie; /* optional */ - - /* Device info */ - const char *device; /* always available when this information is of a sink/source */ - const char *description; /* optional */ - const pa_sample_spec *sample_spec; /* optional */ -} pa_browse_info; - -typedef void (*pa_browse_cb_t)(pa_browser *z, pa_browse_opcode_t c, const pa_browse_info *i, void *userdata); - -void pa_browser_set_callback(pa_browser *z, pa_browse_cb_t cb, void *userdata); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/cdecl.h b/src/polyp/cdecl.h deleted file mode 100644 index d51ae026..00000000 --- a/src/polyp/cdecl.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef foocdeclhfoo -#define foocdeclhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -/** \file - * C++ compatibility support */ - -#ifdef __cplusplus -/** If using C++ this macro enables C mode, otherwise does nothing */ -#define PA_C_DECL_BEGIN extern "C" { -/** If using C++ this macros switches back to C++ mode, otherwise does nothing */ -#define PA_C_DECL_END } - -#else -/** If using C++ this macro enables C mode, otherwise does nothing */ -#define PA_C_DECL_BEGIN -/** If using C++ this macros switches back to C++ mode, otherwise does nothing */ -#define PA_C_DECL_END - -#endif - -#endif diff --git a/src/polyp/channelmap.c b/src/polyp/channelmap.c deleted file mode 100644 index 653331ba..00000000 --- a/src/polyp/channelmap.c +++ /dev/null @@ -1,445 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include -#include - -#include "channelmap.h" - -const char *const table[] = { - [PA_CHANNEL_POSITION_MONO] = "mono", - - [PA_CHANNEL_POSITION_FRONT_CENTER] = "front-center", - [PA_CHANNEL_POSITION_FRONT_LEFT] = "front-left", - [PA_CHANNEL_POSITION_FRONT_RIGHT] = "front-right", - - [PA_CHANNEL_POSITION_REAR_CENTER] = "rear-center", - [PA_CHANNEL_POSITION_REAR_LEFT] = "rear-left", - [PA_CHANNEL_POSITION_REAR_RIGHT] = "rear-right", - - [PA_CHANNEL_POSITION_LFE] = "lfe", - - [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = "front-left-of-center", - [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = "front-right-of-center", - - [PA_CHANNEL_POSITION_SIDE_LEFT] = "side-left", - [PA_CHANNEL_POSITION_SIDE_RIGHT] = "side-right", - - [PA_CHANNEL_POSITION_AUX0] = "aux0", - [PA_CHANNEL_POSITION_AUX1] = "aux1", - [PA_CHANNEL_POSITION_AUX2] = "aux2", - [PA_CHANNEL_POSITION_AUX3] = "aux3", - [PA_CHANNEL_POSITION_AUX4] = "aux4", - [PA_CHANNEL_POSITION_AUX5] = "aux5", - [PA_CHANNEL_POSITION_AUX6] = "aux6", - [PA_CHANNEL_POSITION_AUX7] = "aux7", - [PA_CHANNEL_POSITION_AUX8] = "aux8", - [PA_CHANNEL_POSITION_AUX9] = "aux9", - [PA_CHANNEL_POSITION_AUX10] = "aux10", - [PA_CHANNEL_POSITION_AUX11] = "aux11", - [PA_CHANNEL_POSITION_AUX12] = "aux12", - [PA_CHANNEL_POSITION_AUX13] = "aux13", - [PA_CHANNEL_POSITION_AUX14] = "aux14", - [PA_CHANNEL_POSITION_AUX15] = "aux15", - - [PA_CHANNEL_POSITION_TOP_CENTER] = "top-center", - - [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = "top-front-left", - [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = "top-front-right", - [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = "top-front-center", - - [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = "top-rear-left", - [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = "top-rear-right", - [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = "top-rear-center" -}; - -pa_channel_map* pa_channel_map_init(pa_channel_map *m) { - unsigned c; - assert(m); - - m->channels = 0; - - for (c = 0; c < PA_CHANNELS_MAX; c++) - m->map[c] = PA_CHANNEL_POSITION_INVALID; - - return m; -} - -pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m) { - assert(m); - - pa_channel_map_init(m); - - m->channels = 1; - m->map[0] = PA_CHANNEL_POSITION_MONO; - return m; -} - -pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m) { - assert(m); - - pa_channel_map_init(m); - - m->channels = 2; - m->map[0] = PA_CHANNEL_POSITION_LEFT; - m->map[1] = PA_CHANNEL_POSITION_RIGHT; - return m; -} - -pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) { - assert(m); - assert(channels > 0); - assert(channels <= PA_CHANNELS_MAX); - - pa_channel_map_init(m); - - m->channels = channels; - - switch (def) { - case PA_CHANNEL_MAP_AIFF: - - /* This is somewhat compatible with RFC3551 */ - - switch (channels) { - case 1: - m->map[0] = PA_CHANNEL_POSITION_MONO; - return m; - - case 6: - m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - m->map[1] = PA_CHANNEL_POSITION_SIDE_LEFT; - m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; - m->map[3] = PA_CHANNEL_POSITION_FRONT_RIGHT; - m->map[4] = PA_CHANNEL_POSITION_SIDE_RIGHT; - m->map[5] = PA_CHANNEL_POSITION_LFE; - return m; - - case 5: - m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; - m->map[3] = PA_CHANNEL_POSITION_REAR_LEFT; - m->map[4] = PA_CHANNEL_POSITION_REAR_RIGHT; - /* Fall through */ - - case 2: - m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - return m; - - case 3: - m->map[0] = PA_CHANNEL_POSITION_LEFT; - m->map[1] = PA_CHANNEL_POSITION_RIGHT; - m->map[2] = PA_CHANNEL_POSITION_CENTER; - return m; - - case 4: - m->map[0] = PA_CHANNEL_POSITION_LEFT; - m->map[1] = PA_CHANNEL_POSITION_CENTER; - m->map[2] = PA_CHANNEL_POSITION_RIGHT; - m->map[3] = PA_CHANNEL_POSITION_LFE; - return m; - - default: - return NULL; - } - - case PA_CHANNEL_MAP_ALSA: - - switch (channels) { - case 1: - m->map[0] = PA_CHANNEL_POSITION_MONO; - return m; - - case 8: - m->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; - m->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; - /* Fall through */ - - case 6: - m->map[5] = PA_CHANNEL_POSITION_LFE; - /* Fall through */ - - case 5: - m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; - /* Fall through */ - - case 4: - m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT; - m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; - /* Fall through */ - - case 2: - m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - return m; - - default: - return NULL; - } - - case PA_CHANNEL_MAP_AUX: { - unsigned i; - - if (channels >= PA_CHANNELS_MAX) - return NULL; - - for (i = 0; i < channels; i++) - m->map[i] = PA_CHANNEL_POSITION_AUX0 + i; - - return m; - } - - case PA_CHANNEL_MAP_WAVEEX: - - switch (channels) { - case 1: - m->map[0] = PA_CHANNEL_POSITION_MONO; - return m; - - case 18: - m->map[15] = PA_CHANNEL_POSITION_TOP_REAR_LEFT; - m->map[16] = PA_CHANNEL_POSITION_TOP_REAR_CENTER; - m->map[17] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT; - /* Fall through */ - - case 15: - m->map[12] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT; - m->map[13] = PA_CHANNEL_POSITION_TOP_FRONT_CENTER; - m->map[14] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT; - /* Fall through */ - - case 12: - m->map[11] = PA_CHANNEL_POSITION_TOP_CENTER; - /* Fall through */ - - case 11: - m->map[9] = PA_CHANNEL_POSITION_SIDE_LEFT; - m->map[10] = PA_CHANNEL_POSITION_SIDE_RIGHT; - /* Fall through */ - - case 9: - m->map[8] = PA_CHANNEL_POSITION_REAR_CENTER; - /* Fall through */ - - case 8: - m->map[6] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER; - m->map[7] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER; - /* Fall through */ - - case 6: - m->map[4] = PA_CHANNEL_POSITION_REAR_LEFT; - m->map[5] = PA_CHANNEL_POSITION_REAR_RIGHT; - /* Fall through */ - - case 4: - m->map[3] = PA_CHANNEL_POSITION_LFE; - /* Fall through */ - - case 3: - m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; - /* Fall through */ - - case 2: - m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - return m; - - default: - return NULL; - } - - case PA_CHANNEL_MAP_OSS: - - switch (channels) { - case 1: - m->map[0] = PA_CHANNEL_POSITION_MONO; - return m; - - case 8: - m->map[6] = PA_CHANNEL_POSITION_REAR_LEFT; - m->map[7] = PA_CHANNEL_POSITION_REAR_RIGHT; - /* Fall through */ - - case 6: - m->map[4] = PA_CHANNEL_POSITION_SIDE_LEFT; - m->map[5] = PA_CHANNEL_POSITION_SIDE_RIGHT; - /* Fall through */ - - case 4: - m->map[3] = PA_CHANNEL_POSITION_LFE; - /* Fall through */ - - case 3: - m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; - /* Fall through */ - - case 2: - m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - return m; - - default: - return NULL; - } - - - default: - return NULL; - } -} - - -const char* pa_channel_position_to_string(pa_channel_position_t pos) { - - if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX) - return NULL; - - return table[pos]; -} - -int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) { - unsigned c; - - assert(a); - assert(b); - - if (a->channels != b->channels) - return 0; - - for (c = 0; c < a->channels; c++) - if (a->map[c] != b->map[c]) - return 0; - - return 1; -} - -char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) { - unsigned channel; - int first = 1; - char *e; - - assert(s); - assert(l > 0); - assert(map); - - *(e = s) = 0; - - for (channel = 0; channel < map->channels && l > 1; channel++) { - l -= snprintf(e, l, "%s%s", - first ? "" : ",", - pa_channel_position_to_string(map->map[channel])); - - e = strchr(e, 0); - first = 0; - } - - return s; -} - -pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) { - const char *state; - pa_channel_map map; - char *p; - - assert(rmap); - assert(s); - - memset(&map, 0, sizeof(map)); - - if (strcmp(s, "stereo") == 0) { - map.channels = 2; - map.map[0] = PA_CHANNEL_POSITION_LEFT; - map.map[1] = PA_CHANNEL_POSITION_RIGHT; - goto finish; - } - - state = NULL; - map.channels = 0; - - while ((p = pa_split(s, ",", &state))) { - - if (map.channels >= PA_CHANNELS_MAX) { - pa_xfree(p); - return NULL; - } - - /* Some special aliases */ - if (strcmp(p, "left") == 0) - map.map[map.channels++] = PA_CHANNEL_POSITION_LEFT; - else if (strcmp(p, "right") == 0) - map.map[map.channels++] = PA_CHANNEL_POSITION_RIGHT; - else if (strcmp(p, "center") == 0) - map.map[map.channels++] = PA_CHANNEL_POSITION_CENTER; - else if (strcmp(p, "subwoofer") == 0) - map.map[map.channels++] = PA_CHANNEL_POSITION_SUBWOOFER; - else { - pa_channel_position_t i; - - for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++) - if (strcmp(p, table[i]) == 0) { - map.map[map.channels++] = i; - break; - } - - if (i >= PA_CHANNEL_POSITION_MAX) { - pa_xfree(p); - return NULL; - } - } - - pa_xfree(p); - } - -finish: - - if (!pa_channel_map_valid(&map)) - return NULL; - - *rmap = map; - return rmap; -} - -int pa_channel_map_valid(const pa_channel_map *map) { - unsigned c; - - assert(map); - - if (map->channels <= 0 || map->channels > PA_CHANNELS_MAX) - return 0; - - for (c = 0; c < map->channels; c++) { - - if (map->map[c] < 0 ||map->map[c] >= PA_CHANNEL_POSITION_MAX) - return 0; - - } - - return 1; -} - diff --git a/src/polyp/channelmap.h b/src/polyp/channelmap.h deleted file mode 100644 index 645a8a38..00000000 --- a/src/polyp/channelmap.h +++ /dev/null @@ -1,191 +0,0 @@ -#ifndef foochannelmaphfoo -#define foochannelmaphfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -/** \page channelmap Channel Maps - * - * \section overv_sec Overview - * - * Channel maps provide a way to associate channels in a stream with a - * specific speaker position. This relieves applications of having to - * make sure their channel order is identical to the final output. - * - * \section init_sec Initialisation - * - * A channel map consists of an array of \ref pa_channel_position values, - * one for each channel. This array is stored together with a channel count - * in a pa_channel_map structure. - * - * Before filling the structure, the application must initialise it using - * pa_channel_map_init(). There are also a number of convenience functions - * for standard channel mappings: - * - * \li pa_channel_map_init_mono() - Create a channel map with only mono audio. - * \li pa_channel_map_init_stereo() - Create a standard stereo mapping. - * \li pa_channel_map_init_auto() - Create a standard channel map for up to - * six channels. - * - * \section conv_sec Convenience Functions - * - * The library contains a number of convenience functions for dealing with - * channel maps: - * - * \li pa_channel_map_valid() - Tests if a channel map is valid. - * \li pa_channel_map_equal() - Tests if two channel maps are identical. - * \li pa_channel_map_snprint() - Creates a textual description of a channel - * map. - */ - -/** \file - * Constants and routines for channel mapping handling */ - -PA_C_DECL_BEGIN - -/** A list of channel labels */ -typedef enum pa_channel_position { - PA_CHANNEL_POSITION_INVALID = -1, - PA_CHANNEL_POSITION_MONO = 0, - - PA_CHANNEL_POSITION_LEFT, - PA_CHANNEL_POSITION_RIGHT, - PA_CHANNEL_POSITION_CENTER, - - PA_CHANNEL_POSITION_FRONT_LEFT = PA_CHANNEL_POSITION_LEFT, - PA_CHANNEL_POSITION_FRONT_RIGHT = PA_CHANNEL_POSITION_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER = PA_CHANNEL_POSITION_CENTER, - - PA_CHANNEL_POSITION_REAR_CENTER, - PA_CHANNEL_POSITION_REAR_LEFT, - PA_CHANNEL_POSITION_REAR_RIGHT, - - PA_CHANNEL_POSITION_LFE, - PA_CHANNEL_POSITION_SUBWOOFER = PA_CHANNEL_POSITION_LFE, - - PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, - PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, - - PA_CHANNEL_POSITION_SIDE_LEFT, - PA_CHANNEL_POSITION_SIDE_RIGHT, - - PA_CHANNEL_POSITION_AUX0, - PA_CHANNEL_POSITION_AUX1, - PA_CHANNEL_POSITION_AUX2, - PA_CHANNEL_POSITION_AUX3, - PA_CHANNEL_POSITION_AUX4, - PA_CHANNEL_POSITION_AUX5, - PA_CHANNEL_POSITION_AUX6, - PA_CHANNEL_POSITION_AUX7, - PA_CHANNEL_POSITION_AUX8, - PA_CHANNEL_POSITION_AUX9, - PA_CHANNEL_POSITION_AUX10, - PA_CHANNEL_POSITION_AUX11, - PA_CHANNEL_POSITION_AUX12, - PA_CHANNEL_POSITION_AUX13, - PA_CHANNEL_POSITION_AUX14, - PA_CHANNEL_POSITION_AUX15, - PA_CHANNEL_POSITION_AUX16, - PA_CHANNEL_POSITION_AUX17, - PA_CHANNEL_POSITION_AUX18, - PA_CHANNEL_POSITION_AUX19, - PA_CHANNEL_POSITION_AUX20, - PA_CHANNEL_POSITION_AUX21, - PA_CHANNEL_POSITION_AUX22, - PA_CHANNEL_POSITION_AUX23, - PA_CHANNEL_POSITION_AUX24, - PA_CHANNEL_POSITION_AUX25, - PA_CHANNEL_POSITION_AUX26, - PA_CHANNEL_POSITION_AUX27, - PA_CHANNEL_POSITION_AUX28, - PA_CHANNEL_POSITION_AUX29, - PA_CHANNEL_POSITION_AUX30, - PA_CHANNEL_POSITION_AUX31, - - PA_CHANNEL_POSITION_TOP_CENTER, - - PA_CHANNEL_POSITION_TOP_FRONT_LEFT, - PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, - PA_CHANNEL_POSITION_TOP_FRONT_CENTER, - - PA_CHANNEL_POSITION_TOP_REAR_LEFT, - PA_CHANNEL_POSITION_TOP_REAR_RIGHT, - PA_CHANNEL_POSITION_TOP_REAR_CENTER, - - PA_CHANNEL_POSITION_MAX -} pa_channel_position_t; - -/** A list of channel mapping definitions for pa_channel_map_init_auto() */ -typedef enum pa_channel_map_def { - PA_CHANNEL_MAP_AIFF, /**< The mapping from RFC3551, which is based on AIFF-C */ - PA_CHANNEL_MAP_ALSA, /**< The default mapping used by ALSA */ - PA_CHANNEL_MAP_AUX, /**< Only aux channels */ - PA_CHANNEL_MAP_WAVEEX, /**< Microsoft's WAVEFORMATEXTENSIBLE mapping */ - PA_CHANNEL_MAP_OSS, /**< The default channel mapping used by OSS as defined in the OSS 4.0 API specs */ - - PA_CHANNEL_MAP_DEFAULT = PA_CHANNEL_MAP_AIFF /**< The default channel map */ -} pa_channel_map_def_t; - -/** A channel map which can be used to attach labels to specific - * channels of a stream. These values are relevant for conversion and - * mixing of streams */ -typedef struct pa_channel_map { - uint8_t channels; /**< Number of channels */ - pa_channel_position_t map[PA_CHANNELS_MAX]; /**< Channel labels */ -} pa_channel_map; - -/** Initialize the specified channel map and return a pointer to it */ -pa_channel_map* pa_channel_map_init(pa_channel_map *m); - -/** Initialize the specified channel map for monoaural audio and return a pointer to it */ -pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m); - -/** Initialize the specified channel map for stereophonic audio and return a pointer to it */ -pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m); - -/** Initialize the specified channel map for the specified number - * of channels using default labels and return a pointer to it. */ -pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def); - -/** Return a text label for the specified channel position */ -const char* pa_channel_position_to_string(pa_channel_position_t pos); - -/** The maximum length of strings returned by pa_channel_map_snprint() */ -#define PA_CHANNEL_MAP_SNPRINT_MAX 336 - -/** Make a humand readable string from the specified channel map */ -char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map); - -/** Parse a channel position list into a channel map structure. \since 0.8.1 */ -pa_channel_map *pa_channel_map_parse(pa_channel_map *map, const char *s); - -/** Compare two channel maps. Return 1 if both match. */ -int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b); - -/** Return non-zero of the specified channel map is considered valid */ -int pa_channel_map_valid(const pa_channel_map *map); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/client-conf-x11.c b/src/polyp/client-conf-x11.c deleted file mode 100644 index fb67df2f..00000000 --- a/src/polyp/client-conf-x11.c +++ /dev/null @@ -1,93 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-13071 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include -#include - -#include - -#include -#include -#include - -#include "client-conf-x11.h" - -int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) { - Display *d = NULL; - int ret = -1; - char t[1024]; - - if (!dname && !getenv("DISPLAY")) - goto finish; - - if (!(d = XOpenDisplay(dname))) { - pa_log(__FILE__": XOpenDisplay() failed"); - goto finish; - } - - if (pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) { - pa_xfree(c->default_server); - c->default_server = pa_xstrdup(t); - } - - if (pa_x11_get_prop(d, "POLYP_SINK", t, sizeof(t))) { - pa_xfree(c->default_sink); - c->default_sink = pa_xstrdup(t); - } - - if (pa_x11_get_prop(d, "POLYP_SOURCE", t, sizeof(t))) { - pa_xfree(c->default_source); - c->default_source = pa_xstrdup(t); - } - - if (pa_x11_get_prop(d, "POLYP_COOKIE", t, sizeof(t))) { - uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; - - if (pa_parsehex(t, cookie, sizeof(cookie)) != sizeof(cookie)) { - pa_log(__FILE__": failed to parse cookie data"); - goto finish; - } - - assert(sizeof(cookie) == sizeof(c->cookie)); - memcpy(c->cookie, cookie, sizeof(cookie)); - - c->cookie_valid = 1; - - pa_xfree(c->cookie_file); - c->cookie_file = NULL; - } - - ret = 0; - -finish: - if (d) - XCloseDisplay(d); - - return ret; - -} diff --git a/src/polyp/client-conf-x11.h b/src/polyp/client-conf-x11.h deleted file mode 100644 index 64459224..00000000 --- a/src/polyp/client-conf-x11.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef fooclientconfx11hfoo -#define fooclientconfx11hfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "client-conf.h" - -/* Load client configuration data from the specified X11 display, - * overwriting the current settings in *c */ -int pa_client_conf_from_x11(pa_client_conf *c, const char *display); - -#endif diff --git a/src/polyp/client-conf.c b/src/polyp/client-conf.c deleted file mode 100644 index e1934ce1..00000000 --- a/src/polyp/client-conf.c +++ /dev/null @@ -1,193 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include "client-conf.h" - -#ifndef DEFAULT_CONFIG_DIR -# ifndef OS_IS_WIN32 -# define DEFAULT_CONFIG_DIR "/etc/polypaudio" -# else -# define DEFAULT_CONFIG_DIR "%POLYP_ROOT%" -# endif -#endif - -#ifndef OS_IS_WIN32 -# define PATH_SEP "/" -#else -# define PATH_SEP "\\" -#endif - -#define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "client.conf" -#define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio" PATH_SEP "client.conf" - -#define ENV_CLIENT_CONFIG_FILE "POLYP_CLIENTCONFIG" -#define ENV_DEFAULT_SINK "POLYP_SINK" -#define ENV_DEFAULT_SOURCE "POLYP_SOURCE" -#define ENV_DEFAULT_SERVER "POLYP_SERVER" -#define ENV_DAEMON_BINARY "POLYP_BINARY" -#define ENV_COOKIE_FILE "POLYP_COOKIE" - -static const pa_client_conf default_conf = { - .daemon_binary = NULL, - .extra_arguments = NULL, - .default_sink = NULL, - .default_source = NULL, - .default_server = NULL, - .autospawn = 0, - .cookie_file = NULL, - .cookie_valid = 0 -}; - -pa_client_conf *pa_client_conf_new(void) { - pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); - - c->daemon_binary = pa_xstrdup(POLYPAUDIO_BINARY); - c->extra_arguments = pa_xstrdup("--log-target=syslog --exit-idle-time=5"); - c->cookie_file = pa_xstrdup(PA_NATIVE_COOKIE_FILE); - - return c; -} - -void pa_client_conf_free(pa_client_conf *c) { - assert(c); - pa_xfree(c->daemon_binary); - pa_xfree(c->extra_arguments); - pa_xfree(c->default_sink); - pa_xfree(c->default_source); - pa_xfree(c->default_server); - pa_xfree(c->cookie_file); - pa_xfree(c); -} -int pa_client_conf_load(pa_client_conf *c, const char *filename) { - FILE *f = NULL; - char *fn = NULL; - int r = -1; - - /* Prepare the configuration parse table */ - pa_config_item table[] = { - { "daemon-binary", pa_config_parse_string, NULL }, - { "extra-arguments", pa_config_parse_string, NULL }, - { "default-sink", pa_config_parse_string, NULL }, - { "default-source", pa_config_parse_string, NULL }, - { "default-server", pa_config_parse_string, NULL }, - { "autospawn", pa_config_parse_bool, NULL }, - { "cookie-file", pa_config_parse_string, NULL }, - { NULL, NULL, NULL }, - }; - - table[0].data = &c->daemon_binary; - table[1].data = &c->extra_arguments; - table[2].data = &c->default_sink; - table[3].data = &c->default_source; - table[4].data = &c->default_server; - table[5].data = &c->autospawn; - table[6].data = &c->cookie_file; - - f = filename ? - fopen((fn = pa_xstrdup(filename)), "r") : - pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn, "r"); - - if (!f && errno != EINTR) { - pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", filename, pa_cstrerror(errno)); - goto finish; - } - - r = f ? pa_config_parse(fn, f, table, NULL) : 0; - - if (!r) - r = pa_client_conf_load_cookie(c); - - -finish: - pa_xfree(fn); - - if (f) - fclose(f); - - return r; -} - -int pa_client_conf_env(pa_client_conf *c) { - char *e; - - if ((e = getenv(ENV_DEFAULT_SINK))) { - pa_xfree(c->default_sink); - c->default_sink = pa_xstrdup(e); - } - - if ((e = getenv(ENV_DEFAULT_SOURCE))) { - pa_xfree(c->default_source); - c->default_source = pa_xstrdup(e); - } - - if ((e = getenv(ENV_DEFAULT_SERVER))) { - pa_xfree(c->default_server); - c->default_server = pa_xstrdup(e); - } - - if ((e = getenv(ENV_DAEMON_BINARY))) { - pa_xfree(c->daemon_binary); - c->daemon_binary = pa_xstrdup(e); - } - - if ((e = getenv(ENV_COOKIE_FILE))) { - pa_xfree(c->cookie_file); - c->cookie_file = pa_xstrdup(e); - - return pa_client_conf_load_cookie(c); - } - - return 0; -} - -int pa_client_conf_load_cookie(pa_client_conf* c) { - assert(c); - - c->cookie_valid = 0; - - if (!c->cookie_file) - return -1; - - if (pa_authkey_load_auto(c->cookie_file, c->cookie, sizeof(c->cookie)) < 0) - return -1; - - c->cookie_valid = 1; - return 0; -} - diff --git a/src/polyp/client-conf.h b/src/polyp/client-conf.h deleted file mode 100644 index de3efae7..00000000 --- a/src/polyp/client-conf.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef fooclientconfhfoo -#define fooclientconfhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -/* A structure containing configuration data for polypaudio clients. */ - -typedef struct pa_client_conf { - char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server, *cookie_file; - int autospawn; - uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; - int cookie_valid; /* non-zero, when cookie is valid */ -} pa_client_conf; - -/* Create a new configuration data object and reset it to defaults */ -pa_client_conf *pa_client_conf_new(void); -void pa_client_conf_free(pa_client_conf *c); - -/* Load the configuration data from the speicified file, overwriting - * the current settings in *c. When the filename is NULL, the - * default client configuration file name is used. */ -int pa_client_conf_load(pa_client_conf *c, const char *filename); - -/* Load the configuration data from the environment of the current - process, overwriting the current settings in *c. */ -int pa_client_conf_env(pa_client_conf *c); - -/* Load cookie data from c->cookie_file into c->cookie */ -int pa_client_conf_load_cookie(pa_client_conf* c); - -#endif diff --git a/src/polyp/client.conf.in b/src/polyp/client.conf.in deleted file mode 100644 index fbf645a4..00000000 --- a/src/polyp/client.conf.in +++ /dev/null @@ -1,39 +0,0 @@ -# $Id$ -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -## Configuration file for polypaudio clients. Default values are -## commented out. Use either ; or # for commenting - -## Path to the polypaudio daemon to run when autospawning. -; daemon-binary = @POLYPAUDIO_BINARY@ - -## Extra arguments to pass to the polypaudio daemon -; extra-arguments = --log-target=syslog --exit-idle-time=5 - -## The default sink to connect to -; default-sink = - -## The default source to connect to -; default-source = - -## The default sever to connect to -; default-server = - -## Autospawn daemons? -; autospawn = 0 diff --git a/src/polyp/context.c b/src/polyp/context.c deleted file mode 100644 index 68fb4bf3..00000000 --- a/src/polyp/context.c +++ /dev/null @@ -1,980 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_WAIT_H -#include -#endif - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif - -#include "../polypcore/winsock.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -#include "client-conf.h" - -#ifdef HAVE_X11 -#include "client-conf-x11.h" -#endif - -#include "context.h" - -#define AUTOSPAWN_LOCK "autospawn.lock" - -static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_REQUEST] = pa_command_request, - [PA_COMMAND_OVERFLOW] = pa_command_overflow_or_underflow, - [PA_COMMAND_UNDERFLOW] = pa_command_overflow_or_underflow, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = pa_command_stream_killed, - [PA_COMMAND_RECORD_STREAM_KILLED] = pa_command_stream_killed, - [PA_COMMAND_SUBSCRIBE_EVENT] = pa_command_subscribe_event -}; - -static void unlock_autospawn_lock_file(pa_context *c) { - assert(c); - - if (c->autospawn_lock_fd >= 0) { - char lf[PATH_MAX]; - pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); - - pa_unlock_lockfile(lf, c->autospawn_lock_fd); - c->autospawn_lock_fd = -1; - } -} - -pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { - pa_context *c; - - assert(mainloop); - assert(name); - - c = pa_xnew(pa_context, 1); - c->ref = 1; - c->name = pa_xstrdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - c->record_streams = pa_dynarray_new(); - - PA_LLIST_HEAD_INIT(pa_stream, c->streams); - PA_LLIST_HEAD_INIT(pa_operation, c->operations); - - c->error = PA_OK; - c->state = PA_CONTEXT_UNCONNECTED; - c->ctag = 0; - c->csyncid = 0; - - c->state_callback = NULL; - c->state_userdata = NULL; - - c->subscribe_callback = NULL; - c->subscribe_userdata = NULL; - - c->memblock_stat = pa_memblock_stat_new(); - c->local = -1; - c->server_list = NULL; - c->server = NULL; - c->autospawn_lock_fd = -1; - memset(&c->spawn_api, 0, sizeof(c->spawn_api)); - c->do_autospawn = 0; - -#ifdef SIGPIPE - pa_check_signal_is_blocked(SIGPIPE); -#endif - - c->conf = pa_client_conf_new(); - pa_client_conf_load(c->conf, NULL); -#ifdef HAVE_X11 - pa_client_conf_from_x11(c->conf, NULL); -#endif - pa_client_conf_env(c->conf); - - return c; -} - -static void context_free(pa_context *c) { - assert(c); - - unlock_autospawn_lock_file(c); - - while (c->operations) - pa_operation_cancel(c->operations); - - while (c->streams) - pa_stream_set_state(c->streams, PA_STREAM_TERMINATED); - - if (c->client) - pa_socket_client_unref(c->client); - if (c->pdispatch) - pa_pdispatch_unref(c->pdispatch); - if (c->pstream) { - pa_pstream_close(c->pstream); - pa_pstream_unref(c->pstream); - } - - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - pa_memblock_stat_unref(c->memblock_stat); - - if (c->conf) - pa_client_conf_free(c->conf); - - pa_strlist_free(c->server_list); - - pa_xfree(c->name); - pa_xfree(c->server); - pa_xfree(c); -} - -pa_context* pa_context_ref(pa_context *c) { - assert(c); - assert(c->ref >= 1); - - c->ref++; - return c; -} - -void pa_context_unref(pa_context *c) { - assert(c); - assert(c->ref >= 1); - - if (--c->ref <= 0) - context_free(c); -} - -void pa_context_set_state(pa_context *c, pa_context_state_t st) { - assert(c); - assert(c->ref >= 1); - - if (c->state == st) - return; - - pa_context_ref(c); - - c->state = st; - if (c->state_callback) - c->state_callback(c, c->state_userdata); - - if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) { - pa_stream *s; - - s = c->streams ? pa_stream_ref(c->streams) : NULL; - while (s) { - pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL; - pa_stream_set_state(s, st == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED); - pa_stream_unref(s); - s = n; - } - - if (c->pdispatch) - pa_pdispatch_unref(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) { - pa_pstream_close(c->pstream); - pa_pstream_unref(c->pstream); - } - c->pstream = NULL; - - if (c->client) - pa_socket_client_unref(c->client); - c->client = NULL; - } - - pa_context_unref(c); -} - -void pa_context_fail(pa_context *c, int error) { - assert(c); - assert(c->ref >= 1); - - pa_context_set_error(c, error); - pa_context_set_state(c, PA_CONTEXT_FAILED); -} - -int pa_context_set_error(pa_context *c, int error) { - assert(error >= 0); - assert(error < PA_ERR_MAX); - - if (c) - c->error = error; - - return error; -} - -static void pstream_die_callback(pa_pstream *p, void *userdata) { - pa_context *c = userdata; - - assert(p); - assert(c); - - pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED); -} - -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const void *creds, void *userdata) { - pa_context *c = userdata; - - assert(p); - assert(packet); - assert(c); - - pa_context_ref(c); - - if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) - pa_context_fail(c, PA_ERR_PROTOCOL); - - pa_context_unref(c); -} - -static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { - pa_context *c = userdata; - pa_stream *s; - - assert(p); - assert(chunk); - assert(chunk->memblock); - assert(chunk->length); - assert(c); - assert(c->ref >= 1); - - pa_context_ref(c); - - if ((s = pa_dynarray_get(c->record_streams, channel))) { - - assert(seek == PA_SEEK_RELATIVE && offset == 0); - - pa_memblockq_seek(s->record_memblockq, offset, seek); - pa_memblockq_push_align(s->record_memblockq, chunk); - - if (s->read_callback) { - size_t l; - - if ((l = pa_memblockq_get_length(s->record_memblockq)) > 0) - s->read_callback(s, l, s->read_userdata); - } - } - - pa_context_unref(c); -} - -int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t) { - assert(c); - assert(c->ref >= 1); - - if (command == PA_COMMAND_ERROR) { - assert(t); - - if (pa_tagstruct_getu32(t, &c->error) < 0) { - pa_context_fail(c, PA_ERR_PROTOCOL); - return -1; - - } - } else if (command == PA_COMMAND_TIMEOUT) - c->error = PA_ERR_TIMEOUT; - else { - pa_context_fail(c, PA_ERR_PROTOCOL); - return -1; - } - - return 0; -} - -static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_context *c = userdata; - - assert(pd); - assert(c); - assert(c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME); - - pa_context_ref(c); - - if (command != PA_COMMAND_REPLY) { - - if (pa_context_handle_error(c, command, t) < 0) - pa_context_fail(c, PA_ERR_PROTOCOL); - - pa_context_fail(c, c->error); - goto finish; - } - - switch(c->state) { - case PA_CONTEXT_AUTHORIZING: { - pa_tagstruct *reply; - - if (pa_tagstruct_getu32(t, &c->version) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(c, PA_ERR_PROTOCOL); - goto finish; - } - - /* Minimum supported version */ - if (c->version < 8) { - pa_context_fail(c, PA_ERR_VERSION); - goto finish; - } - - reply = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag); - pa_tagstruct_puts(reply, c->name); - pa_pstream_send_tagstruct(c->pstream, reply); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL); - - pa_context_set_state(c, PA_CONTEXT_SETTING_NAME); - break; - } - - case PA_CONTEXT_SETTING_NAME : - pa_context_set_state(c, PA_CONTEXT_READY); - break; - - default: - assert(0); - } - -finish: - pa_context_unref(c); -} - -static void setup_context(pa_context *c, pa_iochannel *io) { - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(io); - - pa_context_ref(c); - - assert(!c->pstream); - c->pstream = pa_pstream_new(c->mainloop, io, c->memblock_stat); - - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - - assert(!c->pdispatch); - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - - if (!c->conf->cookie_valid) { - pa_context_fail(c, PA_ERR_AUTHKEY); - goto finish; - } - - t = pa_tagstruct_command(c, PA_COMMAND_AUTH, &tag); - pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION); - pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie)); - pa_pstream_send_tagstruct_with_creds(c->pstream, t, 1); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL); - - pa_context_set_state(c, PA_CONTEXT_AUTHORIZING); - -finish: - - pa_context_unref(c); -} - -static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata); - -#ifndef OS_IS_WIN32 - -static int context_connect_spawn(pa_context *c) { - pid_t pid; - int status, r; - int fds[2] = { -1, -1} ; - pa_iochannel *io; - - pa_context_ref(c); - - if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { - pa_log(__FILE__": socketpair(): %s", pa_cstrerror(errno)); - pa_context_fail(c, PA_ERR_INTERNAL); - goto fail; - } - - pa_fd_set_cloexec(fds[0], 1); - - pa_socket_low_delay(fds[0]); - pa_socket_low_delay(fds[1]); - - if (c->spawn_api.prefork) - c->spawn_api.prefork(); - - if ((pid = fork()) < 0) { - pa_log(__FILE__": fork(): %s", pa_cstrerror(errno)); - pa_context_fail(c, PA_ERR_INTERNAL); - - if (c->spawn_api.postfork) - c->spawn_api.postfork(); - - goto fail; - } else if (!pid) { - /* Child */ - - char t[128]; - const char *state = NULL; -#define MAX_ARGS 64 - const char * argv[MAX_ARGS+1]; - int n; - - /* Not required, since fds[0] has CLOEXEC enabled anyway */ - close(fds[0]); - - if (c->spawn_api.atfork) - c->spawn_api.atfork(); - - /* Setup argv */ - - n = 0; - - argv[n++] = c->conf->daemon_binary; - argv[n++] = "--daemonize=yes"; - - snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]); - argv[n++] = strdup(t); - - while (n < MAX_ARGS) { - char *a; - - if (!(a = pa_split_spaces(c->conf->extra_arguments, &state))) - break; - - argv[n++] = a; - } - - argv[n++] = NULL; - - execv(argv[0], (char * const *) argv); - _exit(1); -#undef MAX_ARGS - } - - /* Parent */ - - r = waitpid(pid, &status, 0); - - if (c->spawn_api.postfork) - c->spawn_api.postfork(); - - if (r < 0) { - pa_log(__FILE__": waitpid(): %s", pa_cstrerror(errno)); - pa_context_fail(c, PA_ERR_INTERNAL); - goto fail; - } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); - goto fail; - } - - close(fds[1]); - - c->local = 1; - - io = pa_iochannel_new(c->mainloop, fds[0], fds[0]); - - setup_context(c, io); - unlock_autospawn_lock_file(c); - - pa_context_unref(c); - - return 0; - -fail: - if (fds[0] != -1) - close(fds[0]); - if (fds[1] != -1) - close(fds[1]); - - unlock_autospawn_lock_file(c); - - pa_context_unref(c); - - return -1; -} - -#endif /* OS_IS_WIN32 */ - -static int try_next_connection(pa_context *c) { - char *u = NULL; - int r = -1; - - assert(c); - assert(!c->client); - - for (;;) { - pa_xfree(u); - u = NULL; - - c->server_list = pa_strlist_pop(c->server_list, &u); - - if (!u) { - -#ifndef OS_IS_WIN32 - if (c->do_autospawn) { - r = context_connect_spawn(c); - goto finish; - } -#endif - - pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); - goto finish; - } - - pa_log_debug(__FILE__": Trying to connect to %s...", u); - - pa_xfree(c->server); - c->server = pa_xstrdup(u); - - if (!(c->client = pa_socket_client_new_string(c->mainloop, u, PA_NATIVE_DEFAULT_PORT))) - continue; - - c->local = pa_socket_client_is_local(c->client); - pa_socket_client_set_callback(c->client, on_connection, c); - break; - } - - r = 0; - -finish: - pa_xfree(u); - - return r; -} - -static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata) { - pa_context *c = userdata; - - assert(client); - assert(c); - assert(c->state == PA_CONTEXT_CONNECTING); - - pa_context_ref(c); - - pa_socket_client_unref(client); - c->client = NULL; - - if (!io) { - /* Try the item in the list */ - if (errno == ECONNREFUSED || errno == ETIMEDOUT || errno == EHOSTUNREACH) { - try_next_connection(c); - goto finish; - } - - pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); - goto finish; - } - - unlock_autospawn_lock_file(c); - setup_context(c, io); - -finish: - pa_context_unref(c); -} - -int pa_context_connect( - pa_context *c, - const char *server, - pa_context_flags_t flags, - const pa_spawn_api *api) { - - int r = -1; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_UNCONNECTED, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(c, !(flags & ~PA_CONTEXT_NOAUTOSPAWN), PA_ERR_INVALID); - PA_CHECK_VALIDITY(c, !server || *server, PA_ERR_INVALID); - - if (!server) - server = c->conf->default_server; - - pa_context_ref(c); - - assert(!c->server_list); - - if (server) { - if (!(c->server_list = pa_strlist_parse(server))) { - pa_context_fail(c, PA_ERR_INVALIDSERVER); - goto finish; - } - } else { - char *d; - char ufn[PATH_MAX]; - - /* Prepend in reverse order */ - - if ((d = getenv("DISPLAY"))) { - char *e; - d = pa_xstrdup(d); - if ((e = strchr(d, ':'))) - *e = 0; - - if (*d) - c->server_list = pa_strlist_prepend(c->server_list, d); - - pa_xfree(d); - } - - c->server_list = pa_strlist_prepend(c->server_list, "tcp6:localhost"); - c->server_list = pa_strlist_prepend(c->server_list, "localhost"); - c->server_list = pa_strlist_prepend(c->server_list, pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET, ufn, sizeof(ufn))); - - /* Wrap the connection attempts in a single transaction for sane autospawn locking */ - if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) { - char lf[PATH_MAX]; - - pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); - pa_make_secure_parent_dir(lf); - assert(c->autospawn_lock_fd <= 0); - c->autospawn_lock_fd = pa_lock_lockfile(lf); - - if (api) - c->spawn_api = *api; - c->do_autospawn = 1; - } - - } - - pa_context_set_state(c, PA_CONTEXT_CONNECTING); - r = try_next_connection(c); - -finish: - pa_context_unref(c); - - return r; -} - -void pa_context_disconnect(pa_context *c) { - assert(c); - assert(c->ref >= 1); - - pa_context_set_state(c, PA_CONTEXT_TERMINATED); -} - -pa_context_state_t pa_context_get_state(pa_context *c) { - assert(c); - assert(c->ref >= 1); - - return c->state; -} - -int pa_context_errno(pa_context *c) { - assert(c); - assert(c->ref >= 1); - - return c->error; -} - -void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) { - assert(c); - assert(c->ref >= 1); - - c->state_callback = cb; - c->state_userdata = userdata; -} - -int pa_context_is_pending(pa_context *c) { - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY(c, - c->state == PA_CONTEXT_CONNECTING || - c->state == PA_CONTEXT_AUTHORIZING || - c->state == PA_CONTEXT_SETTING_NAME || - c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - return (c->pstream && pa_pstream_is_pending(c->pstream)) || - (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) || - c->client; -} - -static void set_dispatch_callbacks(pa_operation *o); - -static void pdispatch_drain_callback(PA_GCC_UNUSED pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void pstream_drain_callback(PA_GCC_UNUSED pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void set_dispatch_callbacks(pa_operation *o) { - int done = 1; - - assert(o); - assert(o->ref >= 1); - assert(o->context); - assert(o->context->ref >= 1); - assert(o->context->state == PA_CONTEXT_READY); - - pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(o->context->pdispatch)) { - pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o); - done = 0; - } - - if (pa_pstream_is_pending(o->context->pstream)) { - pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o); - done = 0; - } - - if (done) { - if (o->callback) { - pa_context_notify_cb_t cb = (pa_context_notify_cb_t) o->callback; - cb(o->context, o->userdata); - } - - pa_operation_done(o); - pa_operation_unref(o); - } -} - -pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) { - pa_operation *o; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, pa_context_is_pending(c), PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - set_dispatch_callbacks(pa_operation_ref(o)); - - return o; -} - -void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int success = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - success = 0; - } else if (!pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_context_success_cb_t cb = (pa_context_success_cb_t) o->callback; - cb(o->context, success, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_EXIT, &tag); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, pa_pdispatch_cb_t internal_cb, pa_operation_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, cb, userdata); - - t = pa_tagstruct_command(c, command, &tag); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SINK, &tag); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SOURCE, &tag); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -int pa_context_is_local(pa_context *c) { - assert(c); - - return c->local; -} - -pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(name); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -const char* pa_get_library_version(void) { - return PACKAGE_VERSION; -} - -const char* pa_context_get_server(pa_context *c) { - assert(c); - assert(c->ref >= 1); - - if (!c->server) - return NULL; - - if (*c->server == '{') { - char *e = strchr(c->server+1, '}'); - return e ? e+1 : c->server; - } - - return c->server; -} - -uint32_t pa_context_get_protocol_version(PA_GCC_UNUSED pa_context *c) { - return PA_PROTOCOL_VERSION; -} - -uint32_t pa_context_get_server_protocol_version(pa_context *c) { - assert(c); - assert(c->ref >= 1); - - return c->version; -} - -pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag) { - pa_tagstruct *t; - - assert(c); - assert(tag); - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, command); - pa_tagstruct_putu32(t, *tag = c->ctag++); - - return t; -} diff --git a/src/polyp/context.h b/src/polyp/context.h deleted file mode 100644 index 04e2af4d..00000000 --- a/src/polyp/context.h +++ /dev/null @@ -1,230 +0,0 @@ -#ifndef foocontexthfoo -#define foocontexthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include -#include - -/** \page async Asynchronous API - * - * \section overv_sec Overview - * - * The asynchronous API is the native interface to the polypaudio library. - * It allows full access to all available functions. This also means that - * it is rather complex and can take some time to fully master. - * - * \section mainloop_sec Main Loop Abstraction - * - * The API is based around an asynchronous event loop, or main loop, - * abstraction. This abstraction contains three basic elements: - * - * \li Deferred events - Events that will trigger as soon as possible. Note - * that some implementations may block all other events - * when a deferred event is active. - * \li I/O events - Events that trigger on file descriptor activities. - * \li Times events - Events that trigger after a fixed ammount of time. - * - * The abstraction is represented as a number of function pointers in the - * pa_mainloop_api structure. - * - * To actually be able to use these functions, an implementation needs to - * be coupled to the abstraction. There are three of these shipped with - * polypaudio, but any other can be used with a minimal ammount of work, - * provided it supports the three basic events listed above. - * - * The implementations shipped with polypaudio are: - * - * \li \subpage mainloop - A minimal but fast implementation based on poll(). - * \li \subpage threaded_mainloop - A special version of the previous - * implementation where all of Polypaudio's - * internal handling runs in a separate - * thread. - * \li \subpage glib-mainloop - A wrapper around GLIB's main loop. Available - * for both GLIB 1.2 and GLIB 2.x. - * - * UNIX signals may be hooked to a main loop using the functions from - * \ref mainloop-signal.h. These rely only on the main loop abstraction - * and can therefore be used with any of the implementations. - * - * \section refcnt_sec Reference Counting - * - * Almost all objects in polypaudio are reference counted. What that means - * is that you rarely malloc() or free() any objects. Instead you increase - * and decrease their reference counts. Whenever an object's reference - * count reaches zero, that object gets destroy and any resources it uses - * get freed. - * - * The benefit of this design is that an application need not worry about - * whether or not it needs to keep an object around in case the library is - * using it internally. If it is, then it has made sure it has its own - * reference to it. - * - * Whenever the library creates an object, it will have an initial - * reference count of one. Most of the time, this single reference will be - * sufficient for the application, so all required reference count - * interaction will be a single call to the objects unref function. - * - * \section context_sec Context - * - * A context is the basic object for a connection to a polypaudio server. - * It multiplexes commands, data streams and events through a single - * channel. - * - * There is no need for more than one context per application, unless - * connections to multiple servers are needed. - * - * \subsection ops_subsec Operations - * - * All operations on the context are performed asynchronously. I.e. the - * client will not wait for the server to complete the request. To keep - * track of all these in-flight operations, the application is given a - * pa_operation object for each asynchronous operation. - * - * There are only two actions (besides reference counting) that can be - * performed on a pa_operation: querying its state with - * pa_operation_get_state() and aborting it with pa_operation_cancel(). - * - * A pa_operation object is reference counted, so an application must - * make sure to unreference it, even if it has no intention of using it. - * - * \subsection conn_subsec Connecting - * - * A context must be connected to a server before any operation can be - * issued. Calling pa_context_connect() will initiate the connection - * procedure. Unlike most asynchronous operations, connecting does not - * result in a pa_operation object. Instead, the application should - * register a callback using pa_context_set_state_callback(). - * - * \subsection disc_subsec Disconnecting - * - * When the sound support is no longer needed, the connection needs to be - * closed using pa_context_disconnect(). This is an immediate function that - * works synchronously. - * - * Since the context object has references to other objects it must be - * disconnected after use or there is a high risk of memory leaks. If the - * connection has terminated by itself, then there is no need to explicitly - * disconnect the context using pa_context_disconnect(). - * - * \section Functions - * - * The sound server's functionality can be divided into a number of - * subsections: - * - * \li \subpage streams - * \li \subpage scache - * \li \subpage introspect - * \li \subpage subscribe - */ - -/** \file - * Connection contexts for asynchrononous communication with a - * server. A pa_context object wraps a connection to a polypaudio - * server using its native protocol. */ - -/** \example pacat.c - * A playback and recording tool using the asynchronous API */ - -/** \example paplay.c - * A sound file playback tool using the asynchronous API, based on libsndfile */ - -PA_C_DECL_BEGIN - -/** An opaque connection context to a daemon */ -typedef struct pa_context pa_context; - -/** Generic notification callback prototype */ -typedef void (*pa_context_notify_cb_t)(pa_context *c, void *userdata); - -/** A generic callback for operation completion */ -typedef void (*pa_context_success_cb_t) (pa_context *c, int success, void *userdata); - -/** Instantiate a new connection context with an abstract mainloop API - * and an application name */ -pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name); - -/** Decrease the reference counter of the context by one */ -void pa_context_unref(pa_context *c); - -/** Increase the reference counter of the context by one */ -pa_context* pa_context_ref(pa_context *c); - -/** Set a callback function that is called whenever the context status changes */ -void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata); - -/** Return the error number of the last failed operation */ -int pa_context_errno(pa_context *c); - -/** Return non-zero if some data is pending to be written to the connection */ -int pa_context_is_pending(pa_context *c); - -/** Return the current context status */ -pa_context_state_t pa_context_get_state(pa_context *c); - -/** Connect the context to the specified server. If server is NULL, -connect to the default server. This routine may but will not always -return synchronously on error. Use pa_context_set_state_callback() to -be notified when the connection is established. If flags doesn't have -PA_NOAUTOSPAWN set and no specific server is specified or accessible a -new daemon is spawned. If api is non-NULL, the functions specified in -the structure are used when forking a new child process. */ -int pa_context_connect(pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api); - -/** Terminate the context connection immediately */ -void pa_context_disconnect(pa_context *c); - -/** Drain the context. If there is nothing to drain, the function returns NULL */ -pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata); - -/** Tell the daemon to exit. The returned operation is unlikely to - * complete succesfully, since the daemon probably died before - * returning a success notification */ -pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata); - -/** Set the name of the default sink. \since 0.4 */ -pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata); - -/** Set the name of the default source. \since 0.4 */ -pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata); - -/** Returns 1 when the connection is to a local daemon. Returns negative when no connection has been made yet. \since 0.5 */ -int pa_context_is_local(pa_context *c); - -/** Set a different application name for context on the server. \since 0.5 */ -pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata); - -/** Return the server name this context is connected to. \since 0.7 */ -const char* pa_context_get_server(pa_context *c); - -/** Return the protocol version of the library. \since 0.8 */ -uint32_t pa_context_get_protocol_version(pa_context *c); - -/** Return the protocol version of the connected server. \since 0.8 */ -uint32_t pa_context_get_server_protocol_version(pa_context *c); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/def.h b/src/polyp/def.h deleted file mode 100644 index 57997163..00000000 --- a/src/polyp/def.h +++ /dev/null @@ -1,312 +0,0 @@ -#ifndef foodefhfoo -#define foodefhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include - -#include -#include - -/** \file - * Global definitions */ - -PA_C_DECL_BEGIN - -/** The state of a connection context */ -typedef enum pa_context_state { - PA_CONTEXT_UNCONNECTED, /**< The context hasn't been connected yet */ - PA_CONTEXT_CONNECTING, /**< A connection is being established */ - PA_CONTEXT_AUTHORIZING, /**< The client is authorizing itself to the daemon */ - PA_CONTEXT_SETTING_NAME, /**< The client is passing its application name to the daemon */ - PA_CONTEXT_READY, /**< The connection is established, the context is ready to execute operations */ - PA_CONTEXT_FAILED, /**< The connection failed or was disconnected */ - PA_CONTEXT_TERMINATED /**< The connection was terminated cleanly */ -} pa_context_state_t; - -/** The state of a stream */ -typedef enum pa_stream_state { - PA_STREAM_UNCONNECTED, /**< The stream is not yet connected to any sink or source */ - PA_STREAM_CREATING, /**< The stream is being created */ - PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */ - PA_STREAM_FAILED, /**< An error occured that made the stream invalid */ - PA_STREAM_TERMINATED /**< The stream has been terminated cleanly */ -} pa_stream_state_t; - -/** The state of an operation */ -typedef enum pa_operation_state { - PA_OPERATION_RUNNING, /**< The operation is still running */ - PA_OPERATION_DONE, /**< The operation has been completed */ - PA_OPERATION_CANCELED /**< The operation has been canceled */ -} pa_operation_state_t; - -/** An invalid index */ -#define PA_INVALID_INDEX ((uint32_t) -1) - -/** Some special flags for contexts. \since 0.8 */ -typedef enum pa_context_flags { - PA_CONTEXT_NOAUTOSPAWN = 1 /**< Disabled autospawning of the polypaudio daemon if required */ -} pa_context_flags_t; - -/** The direction of a pa_stream object */ -typedef enum pa_stream_direction { - PA_STREAM_NODIRECTION, /**< Invalid direction */ - PA_STREAM_PLAYBACK, /**< Playback stream */ - PA_STREAM_RECORD, /**< Record stream */ - PA_STREAM_UPLOAD /**< Sample upload stream */ -} pa_stream_direction_t; - -/** Some special flags for stream connections. \since 0.6 */ -typedef enum pa_stream_flags { - PA_STREAM_START_CORKED = 1, /**< Create the stream corked, requiring an explicit pa_stream_cork() call to uncork it. */ - PA_STREAM_INTERPOLATE_TIMING = 2, /**< Interpolate the latency for - * this stream. When enabled, - * pa_stream_get_latency() and - * pa_stream_get_time() will try - * to estimate the current - * record/playback time based on - * the local time that passed - * since the last timing info - * update. Using this option - * has the advantage of not - * requiring a whole roundtrip - * when the current - * playback/recording time is - * needed. Consider using this - * option when requesting - * latency information - * frequently. This is - * especially useful on long - * latency network - * connections. It makes a lot - * of sense to combine this - * option with - * PA_STREAM_AUTO_TIMING_UPDATE. */ - PA_STREAM_NOT_MONOTONOUS = 4, /**< Don't force the time to - * increase monotonically. If - * this option is enabled, - * pa_stream_get_time() will not - * necessarily return always - * monotonically increasing time - * values on each call. This may - * confuse applications which - * cannot deal with time going - * 'backwards', but has the - * advantage that bad transport - * latency estimations that - * caused the time to to jump - * ahead can be corrected - * quickly, without the need to - * wait. */ - PA_STREAM_AUTO_TIMING_UPDATE = 8 /**< If set timing update requests - * are issued periodically - * automatically. Combined with - * PA_STREAM_INTERPOLATE_TIMING - * you will be able to query the - * current time and latency with - * pa_stream_get_time() and - * pa_stream_get_latency() at - * all times without a packet - * round trip.*/ -} pa_stream_flags_t; - -/** Playback and record buffer metrics */ -typedef struct pa_buffer_attr { - uint32_t maxlength; /**< Maximum length of the buffer */ - uint32_t tlength; /**< Playback only: target length of the buffer. The server tries to assure that at least tlength bytes are always available in the buffer */ - uint32_t prebuf; /**< Playback only: pre-buffering. The server does not start with playback before at least prebug bytes are available in the buffer */ - uint32_t minreq; /**< Playback only: minimum request. The server does not request less than minreq bytes from the client, instead waints until the buffer is free enough to request more bytes at once */ - uint32_t fragsize; /**< Recording only: fragment size. The server sends data in blocks of fragsize bytes size. Large values deminish interactivity with other operations on the connection context but decrease control overhead. */ -} pa_buffer_attr; - -/** Error values as used by pa_context_errno(). Use pa_strerror() to convert these values to human readable strings */ -enum { - PA_OK = 0, /**< No error */ - PA_ERR_ACCESS, /**< Access failure */ - PA_ERR_COMMAND, /**< Unknown command */ - PA_ERR_INVALID, /**< Invalid argument */ - PA_ERR_EXIST, /**< Entity exists */ - PA_ERR_NOENTITY, /**< No such entity */ - PA_ERR_CONNECTIONREFUSED, /**< Connection refused */ - PA_ERR_PROTOCOL, /**< Protocol error */ - PA_ERR_TIMEOUT, /**< Timeout */ - PA_ERR_AUTHKEY, /**< No authorization key */ - PA_ERR_INTERNAL, /**< Internal error */ - PA_ERR_CONNECTIONTERMINATED, /**< Connection terminated */ - PA_ERR_KILLED, /**< Entity killed */ - PA_ERR_INVALIDSERVER, /**< Invalid server */ - PA_ERR_MODINITFAILED, /**< Module initialization failed */ - PA_ERR_BADSTATE, /**< Bad state */ - PA_ERR_NODATA, /**< No data */ - PA_ERR_VERSION, /**< Incompatible protocol version \since 0.8 */ - PA_ERR_TOOLARGE, /**< Data too large \since 0.8.1 */ - PA_ERR_MAX /**< Not really an error but the first invalid error code */ -}; - -/** Subscription event mask, as used by pa_context_subscribe() */ -typedef enum pa_subscription_mask { - PA_SUBSCRIPTION_MASK_NULL = 0, /**< No events */ - PA_SUBSCRIPTION_MASK_SINK = 1, /**< Sink events */ - PA_SUBSCRIPTION_MASK_SOURCE = 2, /**< Source events */ - PA_SUBSCRIPTION_MASK_SINK_INPUT = 4, /**< Sink input events */ - PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8, /**< Source output events */ - PA_SUBSCRIPTION_MASK_MODULE = 16, /**< Module events */ - PA_SUBSCRIPTION_MASK_CLIENT = 32, /**< Client events */ - PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, /**< Sample cache events */ - PA_SUBSCRIPTION_MASK_SERVER = 128, /**< Other global server changes. \since 0.4 */ - PA_SUBSCRIPTION_MASK_AUTOLOAD = 256, /**< Autoload table events. \since 0.5 */ - PA_SUBSCRIPTION_MASK_ALL = 511 /**< Catch all events \since 0.8 */ -} pa_subscription_mask_t; - -/** Subscription event types, as used by pa_context_subscribe() */ -typedef enum pa_subscription_event_type { - PA_SUBSCRIPTION_EVENT_SINK = 0, /**< Event type: Sink */ - PA_SUBSCRIPTION_EVENT_SOURCE = 1, /**< Event type: Source */ - PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2, /**< Event type: Sink input */ - PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 3, /**< Event type: Source output */ - PA_SUBSCRIPTION_EVENT_MODULE = 4, /**< Event type: Module */ - PA_SUBSCRIPTION_EVENT_CLIENT = 5, /**< Event type: Client */ - PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, /**< Event type: Sample cache item */ - PA_SUBSCRIPTION_EVENT_SERVER = 7, /**< Event type: Global server change, only occuring with PA_SUBSCRIPTION_EVENT_CHANGE. \since 0.4 */ - PA_SUBSCRIPTION_EVENT_AUTOLOAD = 8, /**< Event type: Autoload table changes. \since 0.5 */ - PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 15, /**< A mask to extract the event type from an event value */ - - PA_SUBSCRIPTION_EVENT_NEW = 0, /**< A new object was created */ - PA_SUBSCRIPTION_EVENT_CHANGE = 16, /**< A property of the object was modified */ - PA_SUBSCRIPTION_EVENT_REMOVE = 32, /**< An object was removed */ - PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32 /**< A mask to extract the event operation from an event value */ -} pa_subscription_event_type_t; - -/** Return one if an event type t matches an event mask bitfield */ -#define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) - -/** A structure for all kinds of timing information of a stream. See - * pa_stream_update_timing_info() and pa_stream_get_timing_info(). The - * total output latency a sample that is written with - * pa_stream_write() takes to be played may be estimated by - * sink_usec+buffer_usec+transport_usec. (where buffer_usec is defined - * as pa_bytes_to_usec(write_index-read_index)) The output buffer - * which buffer_usec relates to may be manipulated freely (with - * pa_stream_write()'s seek argument, pa_stream_flush() and friends), - * the buffers sink_usec and source_usec relate to are first-in - * first-out (FIFO) buffers which cannot be flushed or manipulated in - * any way. The total input latency a sample that is recorded takes to - * be delivered to the application is: - * source_usec+buffer_usec+transport_usec-sink_usec. (Take care of - * sign issues!) When connected to a monitor source sink_usec contains - * the latency of the owning sink. The two latency estimations - * described here are implemented in pa_stream_get_latency().*/ -typedef struct pa_timing_info { - struct timeval timestamp; /**< The time when this timing info structure was current */ - int synchronized_clocks; /**< Non-zero if the local and the - * remote machine have synchronized - * clocks. If synchronized clocks are - * detected transport_usec becomes much - * more reliable. However, the code that - * detects synchronized clocks is very - * limited und unreliable itself. \since - * 0.5 */ - - pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. For playback streams and record streams connected to a monitor source. */ - pa_usec_t source_usec; /**< Time in usecs a sample takes from being recorded to being delivered to the application. Only for record streams. \since 0.5*/ - pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to/from the daemon. For both playback and record streams. \since 0.5 */ - - int playing; /**< Non-zero when the stream is currently playing. Only for playback streams. */ - - int write_index_corrupt; /**< Non-zero if write_index is not - * up-to-date because a local write - * command that corrupted it has been - * issued in the time since this latency - * info was current . Only write - * commands with SEEK_RELATIVE_ON_READ - * and SEEK_RELATIVE_END can corrupt - * write_index. \since 0.8 */ - int64_t write_index; /**< Current write index into the - * playback buffer in bytes. Think twice before - * using this for seeking purposes: it - * might be out of date a the time you - * want to use it. Consider using - * PA_SEEK_RELATIVE instead. \since - * 0.8 */ - - int read_index_corrupt; /**< Non-zero if read_index is not - * up-to-date because a local pause or - * flush request that corrupted it has - * been issued in the time since this - * latency info was current. \since 0.8 */ - - int64_t read_index; /**< Current read index into the - * playback buffer in bytes. Think twice before - * using this for seeking purposes: it - * might be out of date a the time you - * want to use it. Consider using - * PA_SEEK_RELATIVE_ON_READ - * instead. \since 0.8 */ -} pa_timing_info; - -/** A structure for the spawn api. This may be used to integrate auto - * spawned daemons into your application. For more information see - * pa_context_connect(). When spawning a new child process the - * waitpid() is used on the child's PID. The spawn routine will not - * block or ignore SIGCHLD signals, since this cannot be done in a - * thread compatible way. You might have to do this in - * prefork/postfork. \since 0.4 */ -typedef struct pa_spawn_api { - void (*prefork)(void); /**< Is called just before the fork in the parent process. May be NULL. */ - void (*postfork)(void); /**< Is called immediately after the fork in the parent process. May be NULL.*/ - void (*atfork)(void); /**< Is called immediately after the - * fork in the child process. May be - * NULL. It is not safe to close all - * file descriptors in this function - * unconditionally, since a UNIX socket - * (created using socketpair()) is - * passed to the new process. */ -} pa_spawn_api; - -/** Seek type for pa_stream_write(). \since 0.8*/ -typedef enum pa_seek_mode { - PA_SEEK_RELATIVE = 0, /**< Seek relatively to the write index */ - PA_SEEK_ABSOLUTE = 1, /**< Seek relatively to the start of the buffer queue */ - PA_SEEK_RELATIVE_ON_READ = 2, /**< Seek relatively to the read index. */ - PA_SEEK_RELATIVE_END = 3 /**< Seek relatively to the current end of the buffer queue. */ -} pa_seek_mode_t; - -/** Special sink flags. \since 0.8 */ -typedef enum pa_sink_flags { - PA_SINK_HW_VOLUME_CTRL = 1, /**< Supports hardware volume control */ - PA_SINK_LATENCY = 2 /**< Supports latency querying */ -} pa_sink_flags_t; - -/** Special source flags. \since 0.8 */ -typedef enum pa_source_flags { - PA_SOURCE_HW_VOLUME_CTRL = 1, /**< Supports hardware volume control */ - PA_SOURCE_LATENCY = 2 /**< Supports latency querying */ -} pa_source_flags_t; - -/** A generic free() like callback prototype */ -typedef void (*pa_free_cb_t)(void *p); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/error.c b/src/polyp/error.c deleted file mode 100644 index 27da7eae..00000000 --- a/src/polyp/error.c +++ /dev/null @@ -1,66 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -#include -#include - -#include "error.h" - -const char*pa_strerror(int error) { - - static const char* const errortab[PA_ERR_MAX] = { - [PA_OK] = "OK", - [PA_ERR_ACCESS] = "Access denied", - [PA_ERR_COMMAND] = "Unknown command", - [PA_ERR_INVALID] = "Invalid argument", - [PA_ERR_EXIST] = "Entity exists", - [PA_ERR_NOENTITY] = "No such entity", - [PA_ERR_CONNECTIONREFUSED] = "Connection refused", - [PA_ERR_PROTOCOL] = "Protocol error", - [PA_ERR_TIMEOUT] = "Timeout", - [PA_ERR_AUTHKEY] = "No authorization key", - [PA_ERR_INTERNAL] = "Internal error", - [PA_ERR_CONNECTIONTERMINATED] = "Connection terminated", - [PA_ERR_KILLED] = "Entity killed", - [PA_ERR_INVALIDSERVER] = "Invalid server", - [PA_ERR_MODINITFAILED] = "Module initalization failed", - [PA_ERR_BADSTATE] = "Bad state", - [PA_ERR_NODATA] = "No data", - [PA_ERR_VERSION] = "Incompatible protocol version", - [PA_ERR_TOOLARGE] = "Too large" - }; - - if (error < 0 || error >= PA_ERR_MAX) - return NULL; - - return errortab[error]; -} diff --git a/src/polyp/error.h b/src/polyp/error.h deleted file mode 100644 index 9856c1af..00000000 --- a/src/polyp/error.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef fooerrorhfoo -#define fooerrorhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -/** \file - * Error management */ - -PA_C_DECL_BEGIN - -/** Return a human readable error message for the specified numeric error code */ -const char* pa_strerror(int error); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/glib-mainloop.c b/src/polyp/glib-mainloop.c deleted file mode 100644 index d5fce767..00000000 --- a/src/polyp/glib-mainloop.c +++ /dev/null @@ -1,541 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include -#include - -#include -#include - -#include "glib.h" -#include "glib-mainloop.h" - -struct pa_io_event { - pa_glib_mainloop *mainloop; - int dead; - GIOChannel *io_channel; - GSource *source; - GIOCondition io_condition; - int fd; - void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_io_event *e, void *userdata); - pa_io_event *next, *prev; -}; - -struct pa_time_event { - pa_glib_mainloop *mainloop; - int dead; - GSource *source; - struct timeval timeval; - void (*callback) (pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_time_event*e, void *userdata); - pa_time_event *next, *prev; -}; - -struct pa_defer_event { - pa_glib_mainloop *mainloop; - int dead; - GSource *source; - void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_defer_event*e, void *userdata); - pa_defer_event *next, *prev; -}; - -struct pa_glib_mainloop { - GMainContext *glib_main_context; - pa_mainloop_api api; - GSource *cleanup_source; - pa_io_event *io_events, *dead_io_events; - pa_time_event *time_events, *dead_time_events; - pa_defer_event *defer_events, *dead_defer_events; -}; - -static void schedule_free_dead_events(pa_glib_mainloop *g); - -static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f); - -static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags_t f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata), void *userdata) { - pa_io_event *e; - pa_glib_mainloop *g; - - assert(m && m->userdata && fd >= 0 && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_io_event)); - e->mainloop = m->userdata; - e->dead = 0; - e->fd = fd; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - - e->io_channel = g_io_channel_unix_new(e->fd); - assert(e->io_channel); - e->source = NULL; - e->io_condition = 0; - - glib_io_enable(e, f); - - e->next = g->io_events; - if (e->next) e->next->prev = e; - g->io_events = e; - e->prev = NULL; - - return e; -} - -/* The callback GLIB calls whenever an IO condition is met */ -static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { - pa_io_event *e = data; - pa_io_event_flags_t f; - assert(source && e && e->io_channel == source); - - f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | - (condition & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) | - (condition & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) | - (condition & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0); - - e->callback(&e->mainloop->api, e, e->fd, f, e->userdata); - return TRUE; -} - -static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { - GIOCondition c; - assert(e && !e->dead); - - c = (f & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | (f & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0); - - if (c == e->io_condition) - return; - - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); - } - - e->source = g_io_create_watch(e->io_channel, c | G_IO_ERR | G_IO_HUP); - assert(e->source); - - g_source_set_callback(e->source, (GSourceFunc) io_cb, e, NULL); - g_source_attach(e->source, e->mainloop->glib_main_context); - g_source_set_priority(e->source, G_PRIORITY_DEFAULT); - - e->io_condition = c; -} - -static void glib_io_free(pa_io_event*e) { - assert(e && !e->dead); - - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); - e->source = NULL; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->io_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_io_events)) - e->next->prev = e; - - e->mainloop->dead_io_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_io_set_destroy(pa_io_event*e, void (*callback)(pa_mainloop_api*m, pa_io_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Time sources */ - -static void glib_time_restart(pa_time_event*e, const struct timeval *tv); - -static pa_time_event* glib_time_new(pa_mainloop_api*m, const struct timeval *tv, void (*callback) (pa_mainloop_api*m, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { - pa_glib_mainloop *g; - pa_time_event *e; - - assert(m && m->userdata && tv && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_time_event)); - e->mainloop = g; - e->dead = 0; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - e->source = NULL; - - glib_time_restart(e, tv); - - e->next = g->time_events; - if (e->next) e->next->prev = e; - g->time_events = e; - e->prev = NULL; - - return e; -} - -static guint msec_diff(const struct timeval *a, const struct timeval *b) { - guint r; - assert(a && b); - - if (a->tv_sec < b->tv_sec) - return 0; - - if (a->tv_sec == b->tv_sec && a->tv_sec <= b->tv_sec) - return 0; - - r = (a->tv_sec-b->tv_sec)*1000; - - if (a->tv_usec >= b->tv_usec) - r += (a->tv_usec - b->tv_usec) / 1000; - else - r -= (b->tv_usec - a->tv_usec) / 1000; - - return r; -} - -static gboolean time_cb(gpointer data) { - pa_time_event* e = data; - assert(e && e->mainloop && e->source); - - g_source_unref(e->source); - e->source = NULL; - - e->callback(&e->mainloop->api, e, &e->timeval, e->userdata); - return FALSE; -} - -static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { - struct timeval now; - assert(e && e->mainloop && !e->dead); - - pa_gettimeofday(&now); - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); - } - - if (tv) { - e->timeval = *tv; - e->source = g_timeout_source_new(msec_diff(tv, &now)); - assert(e->source); - g_source_set_callback(e->source, time_cb, e, NULL); - g_source_set_priority(e->source, G_PRIORITY_DEFAULT); - g_source_attach(e->source, e->mainloop->glib_main_context); - } else - e->source = NULL; - } - -static void glib_time_free(pa_time_event *e) { - assert(e && e->mainloop && !e->dead); - - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); - e->source = NULL; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->time_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_time_events)) - e->next->prev = e; - - e->mainloop->dead_time_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*m, pa_time_event*e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Deferred sources */ - -static void glib_defer_enable(pa_defer_event *e, int b); - -static pa_defer_event* glib_defer_new(pa_mainloop_api*m, void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata), void *userdata) { - pa_defer_event *e; - pa_glib_mainloop *g; - - assert(m && m->userdata && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_defer_event)); - e->mainloop = g; - e->dead = 0; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - e->source = NULL; - - glib_defer_enable(e, 1); - - e->next = g->defer_events; - if (e->next) e->next->prev = e; - g->defer_events = e; - e->prev = NULL; - return e; -} - -static gboolean idle_cb(gpointer data) { - pa_defer_event* e = data; - assert(e && e->mainloop && e->source); - - e->callback(&e->mainloop->api, e, e->userdata); - return TRUE; -} - -static void glib_defer_enable(pa_defer_event *e, int b) { - assert(e && e->mainloop); - - if (e->source && !b) { - g_source_destroy(e->source); - g_source_unref(e->source); - e->source = NULL; - } else if (!e->source && b) { - e->source = g_idle_source_new(); - assert(e->source); - g_source_set_callback(e->source, idle_cb, e, NULL); - g_source_attach(e->source, e->mainloop->glib_main_context); - g_source_set_priority(e->source, G_PRIORITY_HIGH); - } -} - -static void glib_defer_free(pa_defer_event *e) { - assert(e && e->mainloop && !e->dead); - - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); - e->source = NULL; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->defer_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_defer_events)) - e->next->prev = e; - - e->mainloop->dead_defer_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api *m, pa_defer_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* quit() */ - -static void glib_quit(pa_mainloop_api*a, PA_GCC_UNUSED int retval) { - pa_glib_mainloop *g; - assert(a && a->userdata); - g = a->userdata; - - /* NOOP */ -} - -static const pa_mainloop_api vtable = { - .userdata = NULL, - - .io_new = glib_io_new, - .io_enable = glib_io_enable, - .io_free = glib_io_free, - .io_set_destroy= glib_io_set_destroy, - - .time_new = glib_time_new, - .time_restart = glib_time_restart, - .time_free = glib_time_free, - .time_set_destroy = glib_time_set_destroy, - - .defer_new = glib_defer_new, - .defer_enable = glib_defer_enable, - .defer_free = glib_defer_free, - .defer_set_destroy = glib_defer_set_destroy, - - .quit = glib_quit, -}; - -pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) { - pa_glib_mainloop *g; - - g = pa_xmalloc(sizeof(pa_glib_mainloop)); - if (c) { - g->glib_main_context = c; - g_main_context_ref(c); - } else - g->glib_main_context = g_main_context_default(); - - g->api = vtable; - g->api.userdata = g; - - g->io_events = g->dead_io_events = NULL; - g->time_events = g->dead_time_events = NULL; - g->defer_events = g->dead_defer_events = NULL; - - g->cleanup_source = NULL; - return g; -} - -static void free_io_events(pa_io_event *e) { - while (e) { - pa_io_event *r = e; - e = r->next; - - if (r->source) { - g_source_destroy(r->source); - g_source_unref(r->source); - } - - if (r->io_channel) - g_io_channel_unref(r->io_channel); - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -static void free_time_events(pa_time_event *e) { - while (e) { - pa_time_event *r = e; - e = r->next; - - if (r->source) { - g_source_destroy(r->source); - g_source_unref(r->source); - } - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -static void free_defer_events(pa_defer_event *e) { - while (e) { - pa_defer_event *r = e; - e = r->next; - - if (r->source) { - g_source_destroy(r->source); - g_source_unref(r->source); - } - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -void pa_glib_mainloop_free(pa_glib_mainloop* g) { - assert(g); - - free_io_events(g->io_events); - free_io_events(g->dead_io_events); - free_defer_events(g->defer_events); - free_defer_events(g->dead_defer_events); - free_time_events(g->time_events); - free_time_events(g->dead_time_events); - - if (g->cleanup_source) { - g_source_destroy(g->cleanup_source); - g_source_unref(g->cleanup_source); - } - - g_main_context_unref(g->glib_main_context); - pa_xfree(g); -} - -pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) { - assert(g); - return &g->api; -} - -static gboolean free_dead_events(gpointer p) { - pa_glib_mainloop *g = p; - assert(g); - - free_io_events(g->dead_io_events); - free_defer_events(g->dead_defer_events); - free_time_events(g->dead_time_events); - - g->dead_io_events = NULL; - g->dead_defer_events = NULL; - g->dead_time_events = NULL; - - g_source_destroy(g->cleanup_source); - g_source_unref(g->cleanup_source); - g->cleanup_source = NULL; - - return FALSE; -} - -static void schedule_free_dead_events(pa_glib_mainloop *g) { - assert(g && g->glib_main_context); - - if (g->cleanup_source) - return; - - g->cleanup_source = g_idle_source_new(); - assert(g->cleanup_source); - g_source_set_callback(g->cleanup_source, free_dead_events, g, NULL); - g_source_attach(g->cleanup_source, g->glib_main_context); -} diff --git a/src/polyp/glib-mainloop.h b/src/polyp/glib-mainloop.h deleted file mode 100644 index ce885e13..00000000 --- a/src/polyp/glib-mainloop.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef fooglibmainloophfoo -#define fooglibmainloophfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include -#include - -/** \page glib-mainloop GLIB Main Loop Bindings - * - * \section overv_sec Overview - * - * The GLIB main loop bindings are extremely easy to use. All that is - * required is to create a pa_glib_mainloop object using - * pa_glib_mainloop_new(). When the main loop abstraction is needed, it is - * provided by pa_glib_mainloop_get_api(). - * - */ - -/** \file - * GLIB main loop support */ - -PA_C_DECL_BEGIN - -/** An opaque GLIB main loop object */ -typedef struct pa_glib_mainloop pa_glib_mainloop; - -/** Create a new GLIB main loop object for the specified GLIB main - * loop context. The GLIB 2.0 version takes an argument c for the - * GMainContext to use. If c is NULL the default context is used. */ -#if GLIB_MAJOR_VERSION >= 2 -pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c); -#else -pa_glib_mainloop *pa_glib_mainloop_new(void); -#endif - -/** Free the GLIB main loop object */ -void pa_glib_mainloop_free(pa_glib_mainloop* g); - -/** Return the abstract main loop API vtable for the GLIB main loop object */ -pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/glib12-mainloop.c b/src/polyp/glib12-mainloop.c deleted file mode 100644 index dfd6ff2f..00000000 --- a/src/polyp/glib12-mainloop.c +++ /dev/null @@ -1,503 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include -#include - -#include -#include - -#include "glib-mainloop.h" - -/* A mainloop implementation based on GLIB 1.2 */ - -struct pa_io_event { - pa_glib_mainloop *mainloop; - int dead; - GIOChannel *io_channel; - guint source; - GIOCondition io_condition; - int fd; - void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_io_event*e, void *userdata); - pa_io_event *next, *prev; -}; - -struct pa_time_event { - pa_glib_mainloop *mainloop; - int dead; - guint source; - struct timeval timeval; - void (*callback) (pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_time_event*e, void *userdata); - pa_time_event *next, *prev; -}; - -struct pa_defer_event { - pa_glib_mainloop *mainloop; - int dead; - guint source; - void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_defer_event*e, void *userdata); - pa_defer_event *next, *prev; -}; - -struct pa_glib_mainloop { - pa_mainloop_api api; - guint cleanup_source; - pa_io_event *io_events, *dead_io_events; - pa_time_event *time_events, *dead_time_events; - pa_defer_event *defer_events, *dead_defer_events; -}; - -static void schedule_free_dead_events(pa_glib_mainloop *g); - -static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f); - -static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags_t f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata), void *userdata) { - pa_io_event *e; - pa_glib_mainloop *g; - - assert(m && m->userdata && fd >= 0 && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_io_event)); - e->mainloop = m->userdata; - e->dead = 0; - e->fd = fd; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - - e->io_channel = g_io_channel_unix_new(e->fd); - assert(e->io_channel); - e->source = (guint) -1; - e->io_condition = 0; - - glib_io_enable(e, f); - - e->next = g->io_events; - if (e->next) e->next->prev = e; - g->io_events = e; - e->prev = NULL; - - return e; -} - -static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { - pa_io_event *e = data; - pa_io_event_flags_t f; - assert(source && e && e->io_channel == source); - - f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | - (condition & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) | - (condition & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) | - (condition & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0); - - e->callback(&e->mainloop->api, e, e->fd, f, e->userdata); - return TRUE; -} - -static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { - GIOCondition c; - assert(e && !e->dead); - - c = (f & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | (f & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0); - - if (c == e->io_condition) - return; - - if (e->source != (guint) -1) - g_source_remove(e->source); - - e->source = g_io_add_watch_full(e->io_channel, G_PRIORITY_DEFAULT, c | G_IO_ERR | G_IO_HUP, io_cb, e, NULL); - assert(e->source != (guint) -1); - e->io_condition = c; -} - -static void glib_io_free(pa_io_event*e) { - assert(e && !e->dead); - - if (e->source != (guint) -1) { - g_source_remove(e->source); - e->source = (guint) -1; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->io_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_io_events)) - e->next->prev = e; - - e->mainloop->dead_io_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_io_set_destroy(pa_io_event*e, void (*callback)(pa_mainloop_api*m, pa_io_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Time sources */ - -static void glib_time_restart(pa_time_event*e, const struct timeval *tv); - -static pa_time_event* glib_time_new(pa_mainloop_api*m, const struct timeval *tv, void (*callback) (pa_mainloop_api*m, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { - pa_glib_mainloop *g; - pa_time_event *e; - - assert(m && m->userdata && tv && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_time_event)); - e->mainloop = g; - e->dead = 0; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - e->source = (guint) -1; - - glib_time_restart(e, tv); - - e->next = g->time_events; - if (e->next) e->next->prev = e; - g->time_events = e; - e->prev = NULL; - - return e; -} - -static guint msec_diff(const struct timeval *a, const struct timeval *b) { - guint r; - assert(a && b); - - if (a->tv_sec < b->tv_sec) - return 0; - - if (a->tv_sec == b->tv_sec && a->tv_sec <= b->tv_sec) - return 0; - - r = (a->tv_sec-b->tv_sec)*1000; - - if (a->tv_usec >= b->tv_usec) - r += (a->tv_usec - b->tv_usec) / 1000; - else - r -= (b->tv_usec - a->tv_usec) / 1000; - - return r; -} - -static gboolean time_cb(gpointer data) { - pa_time_event* e = data; - assert(e && e->mainloop && e->source != (guint) -1); - - g_source_remove(e->source); - e->source = (guint) -1; - - e->callback(&e->mainloop->api, e, &e->timeval, e->userdata); - return FALSE; -} - -static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { - struct timeval now; - assert(e && e->mainloop && !e->dead); - - pa_gettimeofday(&now); - if (e->source != (guint) -1) - g_source_remove(e->source); - - if (tv) { - e->timeval = *tv; - e->source = g_timeout_add_full(G_PRIORITY_DEFAULT, msec_diff(tv, &now), time_cb, e, NULL); - assert(e->source != (guint) -1); - } else - e->source = (guint) -1; - } - -static void glib_time_free(pa_time_event *e) { - assert(e && e->mainloop && !e->dead); - - if (e->source != (guint) -1) { - g_source_remove(e->source); - e->source = (guint) -1; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->time_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_time_events)) - e->next->prev = e; - - e->mainloop->dead_time_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*m, pa_time_event*e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Deferred sources */ - -static void glib_defer_enable(pa_defer_event *e, int b); - -static pa_defer_event* glib_defer_new(pa_mainloop_api*m, void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata), void *userdata) { - pa_defer_event *e; - pa_glib_mainloop *g; - - assert(m && m->userdata && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_defer_event)); - e->mainloop = g; - e->dead = 0; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - e->source = (guint) -1; - - glib_defer_enable(e, 1); - - e->next = g->defer_events; - if (e->next) e->next->prev = e; - g->defer_events = e; - e->prev = NULL; - return e; -} - -static gboolean idle_cb(gpointer data) { - pa_defer_event* e = data; - assert(e && e->mainloop && e->source != (guint) -1); - - e->callback(&e->mainloop->api, e, e->userdata); - return TRUE; -} - -static void glib_defer_enable(pa_defer_event *e, int b) { - assert(e && e->mainloop); - - if (e->source != (guint) -1 && !b) { - g_source_remove(e->source); - e->source = (guint) -1; - } else if (e->source == (guint) -1 && b) { - e->source = g_idle_add_full(G_PRIORITY_HIGH, idle_cb, e, NULL); - assert(e->source != (guint) -1); - } -} - -static void glib_defer_free(pa_defer_event *e) { - assert(e && e->mainloop && !e->dead); - - if (e->source != (guint) -1) { - g_source_remove(e->source); - e->source = (guint) -1; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->defer_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_defer_events)) - e->next->prev = e; - - e->mainloop->dead_defer_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api *m, pa_defer_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* quit() */ - -static void glib_quit(pa_mainloop_api*a, PA_GCC_UNUSED int retval) { - pa_glib_mainloop *g; - assert(a && a->userdata); - g = a->userdata; - - /* NOOP */ -} - -static const pa_mainloop_api vtable = { - .userdata = NULL, - - .io_new = glib_io_new, - .io_enable = glib_io_enable, - .io_free = glib_io_free, - .io_set_destroy= glib_io_set_destroy, - - .time_new = glib_time_new, - .time_restart = glib_time_restart, - .time_free = glib_time_free, - .time_set_destroy = glib_time_set_destroy, - - .defer_new = glib_defer_new, - .defer_enable = glib_defer_enable, - .defer_free = glib_defer_free, - .defer_set_destroy = glib_defer_set_destroy, - - .quit = glib_quit, -}; - -pa_glib_mainloop *pa_glib_mainloop_new(void) { - pa_glib_mainloop *g; - - g = pa_xmalloc(sizeof(pa_glib_mainloop)); - - g->api = vtable; - g->api.userdata = g; - - g->io_events = g->dead_io_events = NULL; - g->time_events = g->dead_time_events = NULL; - g->defer_events = g->dead_defer_events = NULL; - - g->cleanup_source = (guint) -1; - return g; -} - -static void free_io_events(pa_io_event *e) { - while (e) { - pa_io_event *r = e; - e = r->next; - - if (r->source != (guint) -1) - g_source_remove(r->source); - - if (r->io_channel) - g_io_channel_unref(r->io_channel); - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -static void free_time_events(pa_time_event *e) { - while (e) { - pa_time_event *r = e; - e = r->next; - - if (r->source != (guint) -1) - g_source_remove(r->source); - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -static void free_defer_events(pa_defer_event *e) { - while (e) { - pa_defer_event *r = e; - e = r->next; - - if (r->source != (guint) -1) - g_source_remove(r->source); - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -void pa_glib_mainloop_free(pa_glib_mainloop* g) { - assert(g); - - free_io_events(g->io_events); - free_io_events(g->dead_io_events); - free_defer_events(g->defer_events); - free_defer_events(g->dead_defer_events); - free_time_events(g->time_events); - free_time_events(g->dead_time_events); - - if (g->cleanup_source != (guint) -1) - g_source_remove(g->cleanup_source); - - pa_xfree(g); -} - -pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) { - assert(g); - return &g->api; -} - -static gboolean free_dead_events(gpointer p) { - pa_glib_mainloop *g = p; - assert(g); - - free_io_events(g->dead_io_events); - free_defer_events(g->dead_defer_events); - free_time_events(g->dead_time_events); - - g->dead_io_events = NULL; - g->dead_defer_events = NULL; - g->dead_time_events = NULL; - - g_source_remove(g->cleanup_source); - g->cleanup_source = (guint) -1; - - return FALSE; -} - -static void schedule_free_dead_events(pa_glib_mainloop *g) { - assert(g); - - if (g->cleanup_source != (guint) -1) - return; - - g->cleanup_source = g_idle_add_full(G_PRIORITY_HIGH, free_dead_events, g, NULL); -} diff --git a/src/polyp/internal.h b/src/polyp/internal.h deleted file mode 100644 index e659553d..00000000 --- a/src/polyp/internal.h +++ /dev/null @@ -1,210 +0,0 @@ -#ifndef foointernalhfoo -#define foointernalhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "client-conf.h" - -#define DEFAULT_TIMEOUT (10) - -struct pa_context { - int ref; - - char *name; - pa_mainloop_api* mainloop; - - pa_socket_client *client; - pa_pstream *pstream; - pa_pdispatch *pdispatch; - - pa_dynarray *record_streams, *playback_streams; - PA_LLIST_HEAD(pa_stream, streams); - PA_LLIST_HEAD(pa_operation, operations); - - uint32_t version; - uint32_t ctag; - uint32_t csyncid; - uint32_t error; - pa_context_state_t state; - - pa_context_notify_cb_t state_callback; - void *state_userdata; - - pa_context_subscribe_cb_t subscribe_callback; - void *subscribe_userdata; - - pa_memblock_stat *memblock_stat; - - int local; - int do_autospawn; - int autospawn_lock_fd; - pa_spawn_api spawn_api; - - pa_strlist *server_list; - - char *server; - - pa_client_conf *conf; -}; - -#define PA_MAX_WRITE_INDEX_CORRECTIONS 10 - -typedef struct pa_index_correction { - uint32_t tag; - int valid; - int64_t value; - int absolute, corrupt; -} pa_index_correction; - -struct pa_stream { - int ref; - pa_context *context; - pa_mainloop_api *mainloop; - PA_LLIST_FIELDS(pa_stream); - - char *name; - pa_buffer_attr buffer_attr; - pa_sample_spec sample_spec; - pa_channel_map channel_map; - pa_stream_flags_t flags; - uint32_t channel; - uint32_t syncid; - int channel_valid; - uint32_t device_index; - pa_stream_direction_t direction; - pa_stream_state_t state; - - uint32_t requested_bytes; - - pa_memchunk peek_memchunk; - pa_memblockq *record_memblockq; - - int corked; - - /* Store latest latency info */ - pa_timing_info timing_info; - int timing_info_valid; - - /* Use to make sure that time advances monotonically */ - pa_usec_t previous_time; - - /* time updates with tags older than these are invalid */ - uint32_t write_index_not_before; - uint32_t read_index_not_before; - - /* Data about individual timing update correctoins */ - pa_index_correction write_index_corrections[PA_MAX_WRITE_INDEX_CORRECTIONS]; - int current_write_index_correction; - - /* Latency interpolation stuff */ - pa_time_event *auto_timing_update_event; - int auto_timing_update_requested; - - pa_usec_t cached_time; - int cached_time_valid; - - /* Callbacks */ - pa_stream_notify_cb_t state_callback; - void *state_userdata; - pa_stream_request_cb_t read_callback; - void *read_userdata; - pa_stream_request_cb_t write_callback; - void *write_userdata; - pa_stream_notify_cb_t overflow_callback; - void *overflow_userdata; - pa_stream_notify_cb_t underflow_callback; - void *underflow_userdata; - pa_stream_notify_cb_t latency_update_callback; - void *latency_update_userdata; -}; - -typedef void (*pa_operation_cb_t)(void); - -struct pa_operation { - int ref; - pa_context *context; - pa_stream *stream; - - PA_LLIST_FIELDS(pa_operation); - - pa_operation_state_t state; - void *userdata; - pa_operation_cb_t callback; -}; - -void pa_command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); - -pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t callback, void *userdata); -void pa_operation_done(pa_operation *o); - -void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); - -void pa_context_fail(pa_context *c, int error); -int pa_context_set_error(pa_context *c, int error); -void pa_context_set_state(pa_context *c, pa_context_state_t st); -int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t); -pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, void (*internal_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata), void (*cb)(void), void *userdata); - -void pa_stream_set_state(pa_stream *s, pa_stream_state_t st); - -pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag); - -#define PA_CHECK_VALIDITY(context, expression, error) do { \ - if (!(expression)) \ - return -pa_context_set_error((context), (error)); \ -} while(0) - - -#define PA_CHECK_VALIDITY_RETURN_ANY(context, expression, error, value) do { \ - if (!(expression)) { \ - pa_context_set_error((context), (error)); \ - return value; \ - } \ -} while(0) - -#define PA_CHECK_VALIDITY_RETURN_NULL(context, expression, error) PA_CHECK_VALIDITY_RETURN_ANY(context, expression, error, NULL) - - -#endif diff --git a/src/polyp/introspect.c b/src/polyp/introspect.c deleted file mode 100644 index 9d002669..00000000 --- a/src/polyp/introspect.c +++ /dev/null @@ -1,1240 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include - -#include -#include - -#include "internal.h" - -#include "introspect.h" - -/*** Statistics ***/ - -static void context_stat_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - pa_stat_info i, *p = &i; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - p = NULL; - } else if (pa_tagstruct_getu32(t, &i.memblock_total) < 0 || - pa_tagstruct_getu32(t, &i.memblock_total_size) < 0 || - pa_tagstruct_getu32(t, &i.memblock_allocated) < 0 || - pa_tagstruct_getu32(t, &i.memblock_allocated_size) < 0 || - pa_tagstruct_getu32(t, &i.scache_size) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_stat_info_cb_t cb = (pa_stat_info_cb_t) o->callback; - cb(o->context, p, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_stat(pa_context *c, pa_stat_info_cb_t cb, void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_STAT, context_stat_callback, (pa_operation_cb_t) cb, userdata); -} - -/*** Server Info ***/ - -static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - pa_server_info i, *p = &i; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - p = NULL; - } else if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_gets(t, &i.default_sink_name) < 0 || - pa_tagstruct_gets(t, &i.default_source_name) < 0 || - pa_tagstruct_getu32(t, &i.cookie) < 0 || - !pa_tagstruct_eof(t)) { - - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_server_info_cb_t cb = (pa_server_info_cb_t) o->callback; - cb(o->context, p, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_server_info(pa_context *c, pa_server_info_cb_t cb, void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SERVER_INFO, context_get_server_info_callback, (pa_operation_cb_t) cb, userdata); -} - -/*** Sink Info ***/ - -static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eol = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eol = -1; - } else { - uint32_t flags; - - while (!pa_tagstruct_eof(t)) { - pa_sink_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_get_cvolume(t, &i.volume) < 0 || - pa_tagstruct_get_boolean(t, &i.mute) < 0 || - pa_tagstruct_getu32(t, &i.monitor_source) < 0 || - pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || - pa_tagstruct_get_usec(t, &i.latency) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0 || - pa_tagstruct_getu32(t, &flags) < 0) { - - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - i.flags = (pa_sink_flags_t) flags; - - if (o->callback) { - pa_sink_info_cb_t cb = (pa_sink_info_cb_t) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - pa_sink_info_cb_t cb = (pa_sink_info_cb_t) o->callback; - cb(o->context, NULL, eol, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_sink_info_list(pa_context *c, pa_sink_info_cb_t cb, void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INFO_LIST, context_get_sink_info_callback, (pa_operation_cb_t) cb, userdata); -} - -pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, pa_sink_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_SINK_INFO, &tag); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, pa_sink_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_SINK_INFO, &tag); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -/*** Source info ***/ - -static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eol = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eol = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_source_info i; - uint32_t flags; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_get_cvolume(t, &i.volume) < 0 || - pa_tagstruct_get_boolean(t, &i.mute) < 0 || - pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || - pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 || - pa_tagstruct_get_usec(t, &i.latency) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0 || - pa_tagstruct_getu32(t, &flags) < 0) { - - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - i.flags = (pa_source_flags_t) flags; - - if (o->callback) { - pa_source_info_cb_t cb = (pa_source_info_cb_t) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - pa_source_info_cb_t cb = (pa_source_info_cb_t) o->callback; - cb(o->context, NULL, eol, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_source_info_list(pa_context *c, pa_source_info_cb_t cb, void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_INFO_LIST, context_get_source_info_callback, (pa_operation_cb_t) cb, userdata); -} - -pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, pa_source_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_SOURCE_INFO, &tag); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_SOURCE_INFO, &tag); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -/*** Client info ***/ - -static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eol = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eol = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_client_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0 ) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_client_info_cb_t cb = (pa_client_info_cb_t) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - pa_client_info_cb_t cb = (pa_client_info_cb_t) o->callback; - cb(o->context, NULL, eol, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, pa_client_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_CLIENT_INFO, &tag); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_client_info_list(pa_context *c, pa_client_info_cb_t cb, void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_CLIENT_INFO_LIST, context_get_client_info_callback, (pa_operation_cb_t) cb, userdata); -} - -/*** Module info ***/ - -static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eol = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eol = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_module_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_get_boolean(t, &i.auto_unload) < 0) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_module_info_cb_t cb = (pa_module_info_cb_t) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - pa_module_info_cb_t cb = (pa_module_info_cb_t) o->callback; - cb(o->context, NULL, eol, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_MODULE_INFO, &tag); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_module_info_list(pa_context *c, pa_module_info_cb_t cb, void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_MODULE_INFO_LIST, context_get_module_info_callback, (pa_operation_cb_t) cb, userdata); -} - -/*** Sink input info ***/ - -static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eol = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eol = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_sink_input_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.client) < 0 || - pa_tagstruct_getu32(t, &i.sink) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_get_cvolume(t, &i.volume) < 0 || - pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || - pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || - pa_tagstruct_gets(t, &i.resample_method) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0) { - - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_sink_input_info_cb_t cb = (pa_sink_input_info_cb_t) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - pa_sink_input_info_cb_t cb = (pa_sink_input_info_cb_t) o->callback; - cb(o->context, NULL, eol, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_SINK_INPUT_INFO, &tag); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_input_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_sink_input_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INPUT_INFO_LIST, context_get_sink_input_info_callback, (pa_operation_cb_t) cb, userdata); -} - -/*** Source output info ***/ - -static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eol = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eol = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_source_output_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.client) < 0 || - pa_tagstruct_getu32(t, &i.source) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || - pa_tagstruct_get_usec(t, &i.source_usec) < 0 || - pa_tagstruct_gets(t, &i.resample_method) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0) { - - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_source_output_info_cb_t cb = (pa_source_output_info_cb_t) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - pa_source_output_info_cb_t cb = (pa_source_output_info_cb_t) o->callback; - cb(o->context, NULL, eol, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, pa_source_output_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO, &tag); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_output_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_source_output_info_list(pa_context *c, pa_source_output_info_cb_t cb, void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, context_get_source_output_info_callback, (pa_operation_cb_t) cb, userdata); -} - -/*** Volume manipulation ***/ - -pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(volume); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_VOLUME, &tag); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_tagstruct_put_cvolume(t, volume); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(name); - assert(volume); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_VOLUME, &tag); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_cvolume(t, volume); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_MUTE, &tag); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_tagstruct_put_boolean(t, mute); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(name); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_MUTE, &tag); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_boolean(t, mute); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(volume); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_INPUT_VOLUME, &tag); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_put_cvolume(t, volume); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(volume); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_VOLUME, &tag); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_tagstruct_put_cvolume(t, volume); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(name); - assert(volume); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_VOLUME, &tag); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_cvolume(t, volume); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_MUTE, &tag); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_tagstruct_put_boolean(t, mute); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(name); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_MUTE, &tag); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_boolean(t, mute); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -/** Sample Cache **/ - -static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eol = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eol = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_sample_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_get_cvolume(t, &i.volume) < 0 || - pa_tagstruct_get_usec(t, &i.duration) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_getu32(t, &i.bytes) < 0 || - pa_tagstruct_get_boolean(t, &i.lazy) < 0 || - pa_tagstruct_gets(t, &i.filename) < 0) { - - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_sample_info_cb_t cb = (pa_sample_info_cb_t) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - pa_sample_info_cb_t cb = (pa_sample_info_cb_t) o->callback; - cb(o->context, NULL, eol, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, pa_sample_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_SAMPLE_INFO, &tag); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, pa_sample_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_SAMPLE_INFO, &tag); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_sample_info_list(pa_context *c, pa_sample_info_cb_t cb, void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SAMPLE_INFO_LIST, context_get_sample_info_callback, (pa_operation_cb_t) cb, userdata); -} - -static pa_operation* command_kill(pa_context *c, uint32_t command, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, command, &tag); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { - return command_kill(c, PA_COMMAND_KILL_CLIENT, idx, cb, userdata); -} - -pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { - return command_kill(c, PA_COMMAND_KILL_SINK_INPUT, idx, cb, userdata); -} - -pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { - return command_kill(c, PA_COMMAND_KILL_SOURCE_OUTPUT, idx, cb, userdata); -} - -static void context_index_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - uint32_t idx; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - idx = PA_INVALID_INDEX; - } else if (pa_tagstruct_getu32(t, &idx) || - !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_context_index_cb_t cb = (pa_context_index_cb_t) o->callback; - cb(o->context, idx, o->userdata); - } - - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, pa_context_index_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_LOAD_MODULE, &tag); - pa_tagstruct_puts(t, name); - pa_tagstruct_puts(t, argument); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_index_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { - return command_kill(c, PA_COMMAND_UNLOAD_MODULE, idx, cb, userdata); -} - -/*** Autoload stuff ***/ - -static void context_get_autoload_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eol = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eol = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_autoload_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_getu32(t, &i.type) < 0 || - pa_tagstruct_gets(t, &i.module) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_autoload_info_cb_t cb = (pa_autoload_info_cb_t) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - pa_autoload_info_cb_t cb = (pa_autoload_info_cb_t) o->callback; - cb(o->context, NULL, eol, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_autoload_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, type == PA_AUTOLOAD_SINK || type == PA_AUTOLOAD_SOURCE, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_AUTOLOAD_INFO, &tag); - pa_tagstruct_puts(t, name); - pa_tagstruct_putu32(t, type); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, pa_autoload_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_AUTOLOAD_INFO, &tag); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_autoload_info_list(pa_context *c, pa_autoload_info_cb_t cb, void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, context_get_autoload_info_callback, (pa_operation_cb_t) cb, userdata); -} - -pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, pa_context_index_cb_t cb, void* userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, type == PA_AUTOLOAD_SINK || type == PA_AUTOLOAD_SOURCE, PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, module && *module, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_ADD_AUTOLOAD, &tag); - pa_tagstruct_puts(t, name); - pa_tagstruct_putu32(t, type); - pa_tagstruct_puts(t, module); - pa_tagstruct_puts(t, argument); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_index_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_context_success_cb_t cb, void* userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, type == PA_AUTOLOAD_SINK || type == PA_AUTOLOAD_SOURCE, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_AUTOLOAD, &tag); - pa_tagstruct_puts(t, name); - pa_tagstruct_putu32(t, type); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void* userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_AUTOLOAD, &tag); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} diff --git a/src/polyp/introspect.h b/src/polyp/introspect.h deleted file mode 100644 index 9a0edb79..00000000 --- a/src/polyp/introspect.h +++ /dev/null @@ -1,490 +0,0 @@ -#ifndef foointrospecthfoo -#define foointrospecthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include -#include -#include -#include -#include - -/** \page introspect Server Query and Control - * - * \section overv_sec Overview - * - * Sometimes it is necessary to query and modify global settings in the - * server. For this, Polypaudio has the introspection API. It can list sinks, - * sources, samples and other aspects of the server. It can also modify the - * attributes of the server that will affect operations on a global level, - * and not just the application's context. - * - * \section query_sec Querying - * - * All querying is done through callbacks. This design is necessary to - * maintain an asynchronous design. The client will request the information - * and some time later, the server will respond with the desired data. - * - * Some objects can have multiple entries at the server. When requesting all - * of these at once, the callback will be called multiple times, once for - * each object. When the list has been exhausted, the callback will be called - * without an information structure and the eol parameter set to a non-zero - * value. - * - * Note that even if a single object is requested, and not the entire list, - * the terminating call will still be made. - * - * If an error occurs, the callback will be called without and information - * structure and eol set to zero. - * - * Data members in the information structures are only valid during the - * duration of the callback. If they are required after the callback is - * finished, a deep copy must be performed. - * - * \subsection server_subsec Server Information - * - * The server can be queried about its name, the environment it's running on - * and the currently active global defaults. Calling - * pa_context_get_server_info() will get access to a pa_server_info structure - * containing all of these. - * - * \subsection memstat_subsec Memory Usage - * - * Statistics about memory usage can be fetched using pa_context_stat(), - * giving a pa_stat_info structure. - * - * \subsection sinksrc_subsec Sinks and Sources - * - * The server can have an arbitrary number of sinks and sources. Each sink - * and source have both an index and a name associated with it. As such - * there are three ways to get access to them: - * - * \li By index - pa_context_get_sink_info_by_index() / - * pa_context_get_source_info_by_index() - * \li By name - pa_context_get_sink_info_by_name() / - * pa_context_get_source_info_by_name() - * \li All - pa_context_get_sink_info_list() / - * pa_context_get_source_info_list() - * - * All three method use the same callback and will provide a pa_sink_info or - * pa_source_info structure. - * - * \subsection siso_subsec Sink Inputs and Source Outputs - * - * Sink inputs and source outputs are the representations of the client ends - * of streams inside the server. I.e. they connect a client stream to one of - * the global sinks or sources. - * - * Sink inputs and source outputs only have an index to identify them. As - * such, there are only two ways to get information about them: - * - * \li By index - pa_context_get_sink_input_info() / - * pa_context_get_source_output_info() - * \li All - pa_context_get_sink_input_info_list() / - * pa_context_get_source_output_info_list() - * - * The structure returned is the pa_sink_input_info or pa_source_output_info - * structure. - * - * \subsection samples_subsec Samples - * - * The list of cached samples can be retrieved from the server. Three methods - * exist for querying the sample cache list: - * - * \li By index - pa_context_get_sample_info_by_index() - * \li By name - pa_context_get_sample_info_by_name() - * \li All - pa_context_get_sample_info_list() - * - * Note that this only retrieves information about the sample, not the sample - * data itself. - * - * \subsection module_subsec Driver Modules - * - * Polypaudio driver modules are identified by index and are retrieved using either - * pa_context_get_module_info() or pa_context_get_module_info_list(). The - * information structure is called pa_module_info. - * - * \subsection autoload_subsec Autoload Entries - * - * Modules can be autoloaded as a result of a client requesting a certain - * sink or source. This mapping between sink/source names and modules can be - * queried from the server: - * - * \li By index - pa_context_get_autoload_info_by_index() - * \li By sink/source name - pa_context_get_autoload_info_by_name() - * \li All - pa_context_get_autoload_info_list() - * - * \subsection client_subsec Clients - * - * Polypaudio clients are also identified by index and are retrieved using - * either pa_context_get_client_info() or pa_context_get_client_info_list(). - * The information structure is called pa_client_info. - * - * \section ctrl_sec Control - * - * Some parts of the server are only possible to read, but most can also be - * modified in different ways. Note that these changes will affect all - * connected clients and not just the one issuing the request. - * - * \subsection sinksrc_subsec Sinks and Sources - * - * The most common change one would want to do to sinks and sources is to - * modify the volume of the audio. Identical to how sinks and sources can - * be queried, there are two ways of identifying them: - * - * \li By index - pa_context_set_sink_volume_by_index() / - * pa_context_set_source_volume_by_index() - * \li By name - pa_context_set_sink_volume_by_name() / - * pa_context_set_source_volume_by_name() - * - * It is also possible to mute a sink or source: - * - * \li By index - pa_context_set_sink_mute_by_index() / - * pa_context_set_source_mute_by_index() - * \li By name - pa_context_set_sink_mute_by_name() / - * pa_context_set_source_mute_by_name() - * - * \subsection siso_subsec Sink Inputs and Source Outputs - * - * If an application desires to modify the volume of just a single stream - * (commonly one of its own streams), this can be done by setting the volume - * of its associated sink input, using pa_context_set_sink_input_volume(). - * - * There is no support for modifying the volume of source outputs. - * - * It is also possible to remove sink inputs and source outputs, terminating - * the streams associated with them: - * - * \li Sink input - pa_context_kill_sink_input() - * \li Source output - pa_context_kill_source_output() - * - * \subsection module_subsec Modules - * - * Server modules can be remotely loaded and unloaded using - * pa_context_load_module() and pa_context_unload_module(). - * - * \subsection autoload_subsec Autoload Entries - * - * New module autoloading rules can be added, and existing can be removed - * using pa_context_add_autoload() and pa_context_remove_autoload_by_index() - * / pa_context_remove_autoload_by_name(). - * - * \subsection client_subsec Clients - * - * The only operation supported on clients, is the possibility of kicking - * them off the server using pa_context_kill_client(). - */ - -/** \file - * - * Routines for daemon introspection. - */ - -PA_C_DECL_BEGIN - -/** Stores information about sinks */ -typedef struct pa_sink_info { - const char *name; /**< Name of the sink */ - uint32_t index; /**< Index of the sink */ - const char *description; /**< Description of this sink */ - pa_sample_spec sample_spec; /**< Sample spec of this sink */ - pa_channel_map channel_map; /**< Channel map \since 0.8 */ - uint32_t owner_module; /**< Index of the owning module of this sink, or PA_INVALID_INDEX */ - pa_cvolume volume; /**< Volume of the sink */ - int mute; /**< Mute switch of the sink \since 0.8 */ - uint32_t monitor_source; /**< Index of the monitor source connected to this sink */ - const char *monitor_source_name; /**< The name of the monitor source */ - pa_usec_t latency; /**< Length of filled playback buffer of this sink */ - const char *driver; /**< Driver name. \since 0.8 */ - pa_sink_flags_t flags; /**< Flags \since 0.8 */ -} pa_sink_info; - -/** Callback prototype for pa_context_get_sink_info_by_name() and friends */ -typedef void (*pa_sink_info_cb_t)(pa_context *c, const pa_sink_info *i, int eol, void *userdata); - -/** Get information about a sink by its name */ -pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, pa_sink_info_cb_t cb, void *userdata); - -/** Get information about a sink by its index */ -pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t id, pa_sink_info_cb_t cb, void *userdata); - -/** Get the complete sink list */ -pa_operation* pa_context_get_sink_info_list(pa_context *c, pa_sink_info_cb_t cb, void *userdata); - -/** Stores information about sources */ -typedef struct pa_source_info { - const char *name ; /**< Name of the source */ - uint32_t index; /**< Index of the source */ - const char *description; /**< Description of this source */ - pa_sample_spec sample_spec; /**< Sample spec of this source */ - pa_channel_map channel_map; /**< Channel map \since 0.8 */ - uint32_t owner_module; /**< Owning module index, or PA_INVALID_INDEX */ - pa_cvolume volume; /**< Volume of the source \since 0.8 */ - int mute; /**< Mute switch of the sink \since 0.8 */ - uint32_t monitor_of_sink; /**< If this is a monitor source the index of the owning sink, otherwise PA_INVALID_INDEX */ - const char *monitor_of_sink_name; /**< Name of the owning sink, or PA_INVALID_INDEX */ - pa_usec_t latency; /**< Length of filled record buffer of this source. \since 0.5 */ - const char *driver; /**< Driver name \since 0.8 */ - pa_source_flags_t flags; /**< Flags \since 0.8 */ -} pa_source_info; - -/** Callback prototype for pa_context_get_source_info_by_name() and friends */ -typedef void (*pa_source_info_cb_t)(pa_context *c, const pa_source_info *i, int eol, void *userdata); - -/** Get information about a source by its name */ -pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata); - -/** Get information about a source by its index */ -pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t id, pa_source_info_cb_t cb, void *userdata); - -/** Get the complete source list */ -pa_operation* pa_context_get_source_info_list(pa_context *c, pa_source_info_cb_t cb, void *userdata); - -/** Server information */ -typedef struct pa_server_info { - const char *user_name; /**< User name of the daemon process */ - const char *host_name; /**< Host name the daemon is running on */ - const char *server_version; /**< Version string of the daemon */ - const char *server_name; /**< Server package name (usually "polypaudio") */ - pa_sample_spec sample_spec; /**< Default sample specification */ - const char *default_sink_name; /**< Name of default sink. \since 0.4 */ - const char *default_source_name; /**< Name of default sink. \since 0.4*/ - uint32_t cookie; /**< A random cookie for identifying this instance of polypaudio. \since 0.8 */ -} pa_server_info; - -/** Callback prototype for pa_context_get_server_info() */ -typedef void (*pa_server_info_cb_t) (pa_context *c, const pa_server_info*i, void *userdata); - -/** Get some information about the server */ -pa_operation* pa_context_get_server_info(pa_context *c, pa_server_info_cb_t cb, void *userdata); - -/** Stores information about modules */ -typedef struct pa_module_info { - uint32_t index; /**< Index of the module */ - const char*name, /**< Name of the module */ - *argument; /**< Argument string of the module */ - uint32_t n_used; /**< Usage counter or PA_INVALID_INDEX */ - int auto_unload; /**< Non-zero if this is an autoloaded module */ -} pa_module_info; - -/** Callback prototype for pa_context_get_module_info() and firends*/ -typedef void (*pa_module_info_cb_t) (pa_context *c, const pa_module_info*i, int eol, void *userdata); - -/** Get some information about a module by its index */ -pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_info_cb_t cb, void *userdata); - -/** Get the complete list of currently loaded modules */ -pa_operation* pa_context_get_module_info_list(pa_context *c, pa_module_info_cb_t cb, void *userdata); - -/** Stores information about clients */ -typedef struct pa_client_info { - uint32_t index; /**< Index of this client */ - const char *name; /**< Name of this client */ - uint32_t owner_module; /**< Index of the owning module, or PA_INVALID_INDEX */ - const char *driver; /**< Driver name \since 0.8 */ -} pa_client_info; - -/** Callback prototype for pa_context_get_client_info() and firends*/ -typedef void (*pa_client_info_cb_t) (pa_context *c, const pa_client_info*i, int eol, void *userdata); - -/** Get information about a client by its index */ -pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, pa_client_info_cb_t cb, void *userdata); - -/** Get the complete client list */ -pa_operation* pa_context_get_client_info_list(pa_context *c, pa_client_info_cb_t cb, void *userdata); - -/** Stores information about sink inputs */ -typedef struct pa_sink_input_info { - uint32_t index; /**< Index of the sink input */ - const char *name; /**< Name of the sink input */ - uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ - uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ - uint32_t sink; /**< Index of the connected sink */ - pa_sample_spec sample_spec; /**< The sample specification of the sink input */ - pa_channel_map channel_map; /**< Channel map */ - pa_cvolume volume; /**< The volume of this sink input */ - pa_usec_t buffer_usec; /**< Latency due to buffering in sink input, see pa_latency_info for details */ - pa_usec_t sink_usec; /**< Latency of the sink device, see pa_latency_info for details */ - const char *resample_method; /**< Thre resampling method used by this sink input. \since 0.7 */ - const char *driver; /**< Driver name \since 0.8 */ -} pa_sink_input_info; - -/** Callback prototype for pa_context_get_sink_input_info() and firends*/ -typedef void (*pa_sink_input_info_cb_t) (pa_context *c, const pa_sink_input_info *i, int eol, void *userdata); - -/** Get some information about a sink input by its index */ -pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata); - -/** Get the complete sink input list */ -pa_operation* pa_context_get_sink_input_info_list(pa_context *c, pa_sink_input_info_cb_t cb, void *userdata); - -/** Stores information about source outputs */ -typedef struct pa_source_output_info { - uint32_t index; /**< Index of the sink input */ - const char *name; /**< Name of the sink input */ - uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ - uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ - uint32_t source; /**< Index of the connected source */ - pa_sample_spec sample_spec; /**< The sample specification of the source output */ - pa_channel_map channel_map; /**< Channel map */ - pa_usec_t buffer_usec; /**< Latency due to buffering in the source output, see pa_latency_info for details. \since 0.5 */ - pa_usec_t source_usec; /**< Latency of the source device, see pa_latency_info for details. \since 0.5 */ - const char *resample_method; /**< Thre resampling method used by this source output. \since 0.7 */ - const char *driver; /**< Driver name \since 0.8 */ -} pa_source_output_info; - -/** Callback prototype for pa_context_get_source_output_info() and firends*/ -typedef void (*pa_source_output_info_cb_t) (pa_context *c, const pa_source_output_info *i, int eol, void *userdata); - -/** Get information about a source output by its index */ -pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, pa_source_output_info_cb_t cb, void *userdata); - -/** Get the complete list of source outputs */ -pa_operation* pa_context_get_source_output_info_list(pa_context *c, pa_source_output_info_cb_t cb, void *userdata); - -/** Set the volume of a sink device specified by its index */ -pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); - -/** Set the volume of a sink device specified by its name */ -pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); - -/** Set the mute switch of a sink device specified by its index \since 0.8 */ -pa_operation* pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata); - -/** Set the mute switch of a sink device specified by its name \since 0.8 */ -pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata); - -/** Set the volume of a sink input stream */ -pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); - -/** Set the volume of a source device specified by its index \since 0.8 */ -pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); - -/** Set the volume of a source device specified by its name \since 0.8 */ -pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); - -/** Set the mute switch of a source device specified by its index \since 0.8 */ -pa_operation* pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata); - -/** Set the mute switch of a source device specified by its name \since 0.8 */ -pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata); - -/** Memory block statistics */ -typedef struct pa_stat_info { - uint32_t memblock_total; /**< Currently allocated memory blocks */ - uint32_t memblock_total_size; /**< Currentl total size of allocated memory blocks */ - uint32_t memblock_allocated; /**< Allocated memory blocks during the whole lifetime of the daemon */ - uint32_t memblock_allocated_size; /**< Total size of all memory blocks allocated during the whole lifetime of the daemon */ - uint32_t scache_size; /**< Total size of all sample cache entries. \since 0.4 */ -} pa_stat_info; - -/** Callback prototype for pa_context_stat() */ -typedef void (*pa_stat_info_cb_t) (pa_context *c, const pa_stat_info *i, void *userdata); - -/** Get daemon memory block statistics */ -pa_operation* pa_context_stat(pa_context *c, pa_stat_info_cb_t cb, void *userdata); - -/** Stores information about sample cache entries */ -typedef struct pa_sample_info { - uint32_t index; /**< Index of this entry */ - const char *name; /**< Name of this entry */ - pa_cvolume volume; /**< Default volume of this entry */ - pa_sample_spec sample_spec; /**< Sample specification of the sample */ - pa_channel_map channel_map; /**< The channel map */ - pa_usec_t duration; /**< Duration of this entry */ - uint32_t bytes; /**< Length of this sample in bytes. \since 0.4 */ - int lazy; /**< Non-zero when this is a lazy cache entry. \since 0.5 */ - const char *filename; /**< In case this is a lazy cache entry, the filename for the sound file to be loaded on demand. \since 0.5 */ -} pa_sample_info; - -/** Callback prototype for pa_context_get_sample_info_by_name() and firends */ -typedef void (*pa_sample_info_cb_t)(pa_context *c, const pa_sample_info *i, int eol, void *userdata); - -/** Get information about a sample by its name */ -pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, pa_sample_info_cb_t cb, void *userdata); - -/** Get information about a sample by its index */ -pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, pa_sample_info_cb_t cb, void *userdata); - -/** Get the complete list of samples stored in the daemon. */ -pa_operation* pa_context_get_sample_info_list(pa_context *c, pa_sample_info_cb_t cb, void *userdata); - -/** Kill a client. \since 0.5 */ -pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); - -/** Kill a sink input. \since 0.5 */ -pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); - -/** Kill a source output. \since 0.5 */ -pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); - -/** Callback prototype for pa_context_load_module() and pa_context_add_autoload() */ -typedef void (*pa_context_index_cb_t)(pa_context *c, uint32_t idx, void *userdata); - -/** Load a module. \since 0.5 */ -pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, pa_context_index_cb_t cb, void *userdata); - -/** Unload a module. \since 0.5 */ -pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); - -/** Type of an autoload entry. \since 0.5 */ -typedef enum pa_autoload_type { - PA_AUTOLOAD_SINK = 0, - PA_AUTOLOAD_SOURCE = 1 -} pa_autoload_type_t; - -/** Stores information about autoload entries. \since 0.5 */ -typedef struct pa_autoload_info { - uint32_t index; /**< Index of this autoload entry */ - const char *name; /**< Name of the sink or source */ - pa_autoload_type_t type; /**< Type of the autoload entry */ - const char *module; /**< Module name to load */ - const char *argument; /**< Argument string for module */ -} pa_autoload_info; - -/** Callback prototype for pa_context_get_autoload_info_by_name() and firends */ -typedef void (*pa_autoload_info_cb_t)(pa_context *c, const pa_autoload_info *i, int eol, void *userdata); - -/** Get info about a specific autoload entry. \since 0.6 */ -pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_autoload_info_cb_t cb, void *userdata); - -/** Get info about a specific autoload entry. \since 0.6 */ -pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, pa_autoload_info_cb_t cb, void *userdata); - -/** Get the complete list of autoload entries. \since 0.5 */ -pa_operation* pa_context_get_autoload_info_list(pa_context *c, pa_autoload_info_cb_t cb, void *userdata); - -/** Add a new autoload entry. \since 0.5 */ -pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, pa_context_index_cb_t, void* userdata); - -/** Remove an autoload entry. \since 0.6 */ -pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_context_success_cb_t cb, void* userdata); - -/** Remove an autoload entry. \since 0.6 */ -pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void* userdata); - - -PA_C_DECL_END - -#endif diff --git a/src/polyp/mainloop-api.c b/src/polyp/mainloop-api.c deleted file mode 100644 index f29598dc..00000000 --- a/src/polyp/mainloop-api.c +++ /dev/null @@ -1,70 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include - -#include - -#include "mainloop-api.h" - -struct once_info { - void (*callback)(pa_mainloop_api*m, void *userdata); - void *userdata; -}; - -static void once_callback(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { - struct once_info *i = userdata; - assert(m && i && i->callback); - - i->callback(m, i->userdata); - - assert(m->defer_free); - m->defer_free(e); -} - -static void free_callback(pa_mainloop_api *m, PA_GCC_UNUSED pa_defer_event *e, void *userdata) { - struct once_info *i = userdata; - assert(m && i); - pa_xfree(i); -} - -void pa_mainloop_api_once(pa_mainloop_api* m, void (*callback)(pa_mainloop_api *m, void *userdata), void *userdata) { - struct once_info *i; - pa_defer_event *e; - assert(m && callback); - - i = pa_xnew(struct once_info, 1); - i->callback = callback; - i->userdata = userdata; - - assert(m->defer_new); - e = m->defer_new(m, once_callback, i); - assert(e); - m->defer_set_destroy(e, free_callback); -} - diff --git a/src/polyp/mainloop-api.h b/src/polyp/mainloop-api.h deleted file mode 100644 index 12d74aa1..00000000 --- a/src/polyp/mainloop-api.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef foomainloopapihfoo -#define foomainloopapihfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -#include - -/** \file - * - * Main loop abstraction layer. Both the polypaudio core and the - * polypaudio client library use a main loop abstraction layer. Due to - * this it is possible to embed polypaudio into other - * applications easily. Two main loop implemenations are - * currently available: - * \li A minimal implementation based on the C library's poll() function (See \ref mainloop.h) - * \li A wrapper around the GLIB main loop. Use this to embed polypaudio into your GLIB/GTK+/GNOME programs (See \ref glib-mainloop.h) - * - * The structure pa_mainloop_api is used as vtable for the main loop abstraction. - * - * This mainloop abstraction layer has no direct support for UNIX signals. Generic, mainloop implementation agnostic support is available throught \ref mainloop-signal.h. - * */ - -PA_C_DECL_BEGIN - -/** A bitmask for IO events */ -typedef enum pa_io_event_flags { - PA_IO_EVENT_NULL = 0, /**< No event */ - PA_IO_EVENT_INPUT = 1, /**< Input event */ - PA_IO_EVENT_OUTPUT = 2, /**< Output event */ - PA_IO_EVENT_HANGUP = 4, /**< Hangup event */ - PA_IO_EVENT_ERROR = 8 /**< Error event */ -} pa_io_event_flags_t; - -/** An opaque IO event source object */ -typedef struct pa_io_event pa_io_event; - -/** An opaque deferred event source object. Events of this type are triggered once in every main loop iteration */ -typedef struct pa_defer_event pa_defer_event; - -/** An opaque timer event source object */ -typedef struct pa_time_event pa_time_event; - -/** An abstract mainloop API vtable */ -typedef struct pa_mainloop_api pa_mainloop_api; - -/** An abstract mainloop API vtable */ -struct pa_mainloop_api { - /** A pointer to some private, arbitrary data of the main loop implementation */ - void *userdata; - - /** Create a new IO event source object */ - pa_io_event* (*io_new)(pa_mainloop_api*a, int fd, pa_io_event_flags_t events, void (*callback) (pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata); - - /** Enable or disable IO events on this object */ - void (*io_enable)(pa_io_event* e, pa_io_event_flags_t events); - - /** Free a IO event source object */ - void (*io_free)(pa_io_event* e); - - /** Set a function that is called when the IO event source is destroyed. Use this to free the userdata argument if required */ - void (*io_set_destroy)(pa_io_event *e, void (*callback) (pa_mainloop_api*a, pa_io_event *e, void *userdata)); - - /** Create a new timer event source object for the specified Unix time */ - pa_time_event* (*time_new)(pa_mainloop_api*a, const struct timeval *tv, void (*callback) (pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata), void *userdata); - - /** Restart a running or expired timer event source with a new Unix time */ - void (*time_restart)(pa_time_event* e, const struct timeval *tv); - - /** Free a deferred timer event source object */ - void (*time_free)(pa_time_event* e); - - /** Set a function that is called when the timer event source is destroyed. Use this to free the userdata argument if required */ - void (*time_set_destroy)(pa_time_event *e, void (*callback) (pa_mainloop_api*a, pa_time_event *e, void *userdata)); - - /** Create a new deferred event source object */ - pa_defer_event* (*defer_new)(pa_mainloop_api*a, void (*callback) (pa_mainloop_api*a, pa_defer_event* e, void *userdata), void *userdata); - - /** Enable or disable a deferred event source temporarily */ - void (*defer_enable)(pa_defer_event* e, int b); - - /** Free a deferred event source object */ - void (*defer_free)(pa_defer_event* e); - - /** Set a function that is called when the deferred event source is destroyed. Use this to free the userdata argument if required */ - void (*defer_set_destroy)(pa_defer_event *e, void (*callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata)); - - /** Exit the main loop and return the specfied retval*/ - void (*quit)(pa_mainloop_api*a, int retval); -}; - -/** Run the specified callback function once from the main loop using an anonymous defer event. */ -void pa_mainloop_api_once(pa_mainloop_api*m, void (*callback)(pa_mainloop_api*m, void *userdata), void *userdata); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/mainloop-signal.c b/src/polyp/mainloop-signal.c deleted file mode 100644 index 92702814..00000000 --- a/src/polyp/mainloop-signal.c +++ /dev/null @@ -1,210 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_WINDOWS_H -#include -#endif - -#include -#include - -#include -#include -#include - -#include "mainloop-signal.h" - -struct pa_signal_event { - int sig; -#ifdef HAVE_SIGACTION - struct sigaction saved_sigaction; -#else - void (*saved_handler)(int sig); -#endif - void (*callback) (pa_mainloop_api*a, pa_signal_event *e, int sig, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api*a, pa_signal_event*e, void *userdata); - pa_signal_event *previous, *next; -}; - -static pa_mainloop_api *api = NULL; -static int signal_pipe[2] = { -1, -1 }; -static pa_io_event* io_event = NULL; -static pa_signal_event *signals = NULL; - -static void signal_handler(int sig) { -#ifndef HAVE_SIGACTION - signal(sig, signal_handler); -#endif - pa_write(signal_pipe[1], &sig, sizeof(sig)); -} - -static void dispatch(pa_mainloop_api*a, int sig) { - pa_signal_event*s; - - for (s = signals; s; s = s->next) - if (s->sig == sig) { - assert(s->callback); - s->callback(a, s, sig, s->userdata); - break; - } -} - -static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags_t f, PA_GCC_UNUSED void *userdata) { - ssize_t r; - int sig; - assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]); - - if ((r = pa_read(signal_pipe[0], &sig, sizeof(sig))) < 0) { - if (errno == EAGAIN) - return; - - pa_log(__FILE__": read(): %s", pa_cstrerror(errno)); - return; - } - - if (r != sizeof(sig)) { - pa_log(__FILE__": short read()"); - return; - } - - dispatch(a, sig); -} - -int pa_signal_init(pa_mainloop_api *a) { - - assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event); - - if (pipe(signal_pipe) < 0) { - pa_log(__FILE__": pipe(): %s", pa_cstrerror(errno)); - return -1; - } - - pa_make_nonblock_fd(signal_pipe[0]); - pa_make_nonblock_fd(signal_pipe[1]); - pa_fd_set_cloexec(signal_pipe[0], 1); - pa_fd_set_cloexec(signal_pipe[1], 1); - - api = a; - - io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL); - assert(io_event); - - return 0; -} - -void pa_signal_done(void) { - assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && io_event); - - while (signals) - pa_signal_free(signals); - - api->io_free(io_event); - io_event = NULL; - - close(signal_pipe[0]); - close(signal_pipe[1]); - signal_pipe[0] = signal_pipe[1] = -1; - - api = NULL; -} - -pa_signal_event* pa_signal_new(int sig, void (*_callback) (pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata), void *userdata) { - pa_signal_event *e = NULL; - -#ifdef HAVE_SIGACTION - struct sigaction sa; -#endif - - assert(sig > 0 && _callback); - - for (e = signals; e; e = e->next) - if (e->sig == sig) - goto fail; - - e = pa_xmalloc(sizeof(pa_signal_event)); - e->sig = sig; - e->callback = _callback; - e->userdata = userdata; - e->destroy_callback = NULL; - -#ifdef HAVE_SIGACTION - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = signal_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - - if (sigaction(sig, &sa, &e->saved_sigaction) < 0) -#else - if ((e->saved_handler = signal(sig, signal_handler)) == SIG_ERR) -#endif - goto fail; - - e->previous = NULL; - e->next = signals; - signals = e; - - return e; -fail: - if (e) - pa_xfree(e); - return NULL; -} - -void pa_signal_free(pa_signal_event *e) { - assert(e); - - if (e->next) - e->next->previous = e->previous; - if (e->previous) - e->previous->next = e->next; - else - signals = e->next; - -#ifdef HAVE_SIGACTION - sigaction(e->sig, &e->saved_sigaction, NULL); -#else - signal(e->sig, e->saved_handler); -#endif - - if (e->destroy_callback) - e->destroy_callback(api, e, e->userdata); - - pa_xfree(e); -} - -void pa_signal_set_destroy(pa_signal_event *e, void (*_callback) (pa_mainloop_api *api, pa_signal_event*e, void *userdata)) { - assert(e); - e->destroy_callback = _callback; -} diff --git a/src/polyp/mainloop-signal.h b/src/polyp/mainloop-signal.h deleted file mode 100644 index 20e97988..00000000 --- a/src/polyp/mainloop-signal.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef foomainloopsignalhfoo -#define foomainloopsignalhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -PA_C_DECL_BEGIN - -/** \file - * UNIX signal support for main loops. In contrast to other - * main loop event sources such as timer and IO events, UNIX signal - * support requires modification of the global process - * environment. Due to this the generic main loop abstraction layer as - * defined in \ref mainloop-api.h doesn't have direct support for UNIX - * signals. However, you may hook signal support into an abstract main loop via the routines defined herein. - */ - -/** Initialize the UNIX signal subsystem and bind it to the specified main loop */ -int pa_signal_init(pa_mainloop_api *api); - -/** Cleanup the signal subsystem */ -void pa_signal_done(void); - -/** An opaque UNIX signal event source object */ -typedef struct pa_signal_event pa_signal_event; - -/** Create a new UNIX signal event source object */ -pa_signal_event* pa_signal_new(int sig, void (*callback) (pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata), void *userdata); - -/** Free a UNIX signal event source object */ -void pa_signal_free(pa_signal_event *e); - -/** Set a function that is called when the signal event source is destroyed. Use this to free the userdata argument if required */ -void pa_signal_set_destroy(pa_signal_event *e, void (*callback) (pa_mainloop_api *api, pa_signal_event*e, void *userdata)); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/mainloop.c b/src/polyp/mainloop.c deleted file mode 100644 index 61d8b488..00000000 --- a/src/polyp/mainloop.c +++ /dev/null @@ -1,839 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_POLL_H -#include -#else -#include "../polypcore/poll.h" -#endif - -#include "../polypcore/winsock.h" - -#ifndef HAVE_PIPE -#include "../polypcore/pipe.h" -#endif - -#include -#include -#include - -#include -#include -#include - -#include "mainloop.h" - -struct pa_io_event { - pa_mainloop *mainloop; - int dead; - int fd; - pa_io_event_flags_t events; - void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); - struct pollfd *pollfd; - void *userdata; - void (*destroy_callback) (pa_mainloop_api*a, pa_io_event *e, void *userdata); -}; - -struct pa_time_event { - pa_mainloop *mainloop; - int dead; - int enabled; - struct timeval timeval; - void (*callback)(pa_mainloop_api*a, pa_time_event *e, const struct timeval*tv, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api*a, pa_time_event *e, void *userdata); -}; - -struct pa_defer_event { - pa_mainloop *mainloop; - int dead; - int enabled; - void (*callback)(pa_mainloop_api*a, pa_defer_event*e, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata); -}; - -struct pa_mainloop { - pa_idxset *io_events, *time_events, *defer_events; - int io_events_scan_dead, defer_events_scan_dead, time_events_scan_dead; - - struct pollfd *pollfds; - unsigned max_pollfds, n_pollfds; - int rebuild_pollfds; - - int prepared_timeout; - - int quit, retval; - pa_mainloop_api api; - - int deferred_pending; - - int wakeup_pipe[2]; - - enum { - STATE_PASSIVE, - STATE_PREPARED, - STATE_POLLING, - STATE_POLLED, - STATE_QUIT - } state; - - pa_poll_func poll_func; - void *poll_func_userdata; -}; - -/* IO events */ -static pa_io_event* mainloop_io_new( - pa_mainloop_api*a, - int fd, - pa_io_event_flags_t events, - void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), - void *userdata) { - - pa_mainloop *m; - pa_io_event *e; - - assert(a && a->userdata && fd >= 0 && callback); - m = a->userdata; - assert(a == &m->api); - - e = pa_xmalloc(sizeof(pa_io_event)); - e->mainloop = m; - e->dead = 0; - - e->fd = fd; - e->events = events; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - e->pollfd = NULL; - -#ifdef OS_IS_WIN32 - { - fd_set xset; - struct timeval tv; - - tv.tv_sec = 0; - tv.tv_usec = 0; - - FD_ZERO (&xset); - FD_SET (fd, &xset); - - if ((select((SELECT_TYPE_ARG1) fd, NULL, NULL, SELECT_TYPE_ARG234 &xset, - SELECT_TYPE_ARG5 &tv) == -1) && - (WSAGetLastError() == WSAENOTSOCK)) { - pa_log_warn(__FILE__": WARNING: cannot monitor non-socket file descriptors."); - e->dead = 1; - } - } -#endif - - pa_idxset_put(m->io_events, e, NULL); - m->rebuild_pollfds = 1; - - pa_mainloop_wakeup(m); - - return e; -} - -static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags_t events) { - assert(e && e->mainloop); - - e->events = events; - e->mainloop->rebuild_pollfds = 1; - - pa_mainloop_wakeup(e->mainloop); -} - -static void mainloop_io_free(pa_io_event *e) { - assert(e && e->mainloop); - - e->dead = e->mainloop->io_events_scan_dead = e->mainloop->rebuild_pollfds = 1; - - pa_mainloop_wakeup(e->mainloop); -} - -static void mainloop_io_set_destroy(pa_io_event *e, void (*callback)(pa_mainloop_api*a, pa_io_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Defer events */ -static pa_defer_event* mainloop_defer_new(pa_mainloop_api*a, void (*callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata), void *userdata) { - pa_mainloop *m; - pa_defer_event *e; - - assert(a && a->userdata && callback); - m = a->userdata; - assert(a == &m->api); - - e = pa_xmalloc(sizeof(pa_defer_event)); - e->mainloop = m; - e->dead = 0; - - e->enabled = 1; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - - pa_idxset_put(m->defer_events, e, NULL); - - m->deferred_pending++; - - pa_mainloop_wakeup(e->mainloop); - - return e; -} - -static void mainloop_defer_enable(pa_defer_event *e, int b) { - assert(e); - - if (e->enabled && !b) { - assert(e->mainloop->deferred_pending > 0); - e->mainloop->deferred_pending--; - } else if (!e->enabled && b) { - e->mainloop->deferred_pending++; - pa_mainloop_wakeup(e->mainloop); - } - - e->enabled = b; -} - -static void mainloop_defer_free(pa_defer_event *e) { - assert(e); - e->dead = e->mainloop->defer_events_scan_dead = 1; - - if (e->enabled) { - e->enabled = 0; - assert(e->mainloop->deferred_pending > 0); - e->mainloop->deferred_pending--; - } -} - -static void mainloop_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api*a, pa_defer_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Time events */ -static pa_time_event* mainloop_time_new(pa_mainloop_api*a, const struct timeval *tv, void (*callback) (pa_mainloop_api*a, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { - pa_mainloop *m; - pa_time_event *e; - - assert(a && a->userdata && callback); - m = a->userdata; - assert(a == &m->api); - - e = pa_xmalloc(sizeof(pa_time_event)); - e->mainloop = m; - e->dead = 0; - - e->enabled = !!tv; - if (tv) - e->timeval = *tv; - - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - - pa_idxset_put(m->time_events, e, NULL); - - if (e->enabled) - pa_mainloop_wakeup(m); - - return e; -} - -static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) { - assert(e); - - if (tv) { - e->enabled = 1; - e->timeval = *tv; - - pa_mainloop_wakeup(e->mainloop); - } else - e->enabled = 0; -} - -static void mainloop_time_free(pa_time_event *e) { - assert(e); - - e->dead = e->mainloop->time_events_scan_dead = 1; - - /* no wakeup needed here. Think about it! */ -} - -static void mainloop_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*a, pa_time_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* quit() */ - -static void mainloop_quit(pa_mainloop_api*a, int retval) { - pa_mainloop *m; - assert(a && a->userdata); - m = a->userdata; - assert(a == &m->api); - - pa_mainloop_quit(m, retval); -} - -static const pa_mainloop_api vtable = { - .userdata = NULL, - - .io_new= mainloop_io_new, - .io_enable= mainloop_io_enable, - .io_free= mainloop_io_free, - .io_set_destroy= mainloop_io_set_destroy, - - .time_new = mainloop_time_new, - .time_restart = mainloop_time_restart, - .time_free = mainloop_time_free, - .time_set_destroy = mainloop_time_set_destroy, - - .defer_new = mainloop_defer_new, - .defer_enable = mainloop_defer_enable, - .defer_free = mainloop_defer_free, - .defer_set_destroy = mainloop_defer_set_destroy, - - .quit = mainloop_quit, -}; - -pa_mainloop *pa_mainloop_new(void) { - pa_mainloop *m; - - m = pa_xmalloc(sizeof(pa_mainloop)); - - if (pipe(m->wakeup_pipe) < 0) { - pa_log_error(__FILE__": ERROR: cannot create wakeup pipe"); - pa_xfree(m); - return NULL; - } - - pa_make_nonblock_fd(m->wakeup_pipe[0]); - pa_make_nonblock_fd(m->wakeup_pipe[1]); - - m->io_events = pa_idxset_new(NULL, NULL); - m->defer_events = pa_idxset_new(NULL, NULL); - m->time_events = pa_idxset_new(NULL, NULL); - - assert(m->io_events && m->defer_events && m->time_events); - - m->io_events_scan_dead = m->defer_events_scan_dead = m->time_events_scan_dead = 0; - - m->pollfds = NULL; - m->max_pollfds = m->n_pollfds = 0; - m->rebuild_pollfds = 1; - - m->quit = m->retval = 0; - - m->api = vtable; - m->api.userdata = m; - - m->deferred_pending = 0; - - m->state = STATE_PASSIVE; - - m->poll_func = NULL; - m->poll_func_userdata = NULL; - - m->retval = -1; - - return m; -} - -static int io_foreach(void *p, uint32_t PA_GCC_UNUSED idx, int *del, void*userdata) { - pa_io_event *e = p; - int *all = userdata; - assert(e && del && all); - - if (!*all && !e->dead) - return 0; - - if (e->destroy_callback) - e->destroy_callback(&e->mainloop->api, e, e->userdata); - pa_xfree(e); - *del = 1; - return 0; -} - -static int time_foreach(void *p, uint32_t PA_GCC_UNUSED idx, int *del, void*userdata) { - pa_time_event *e = p; - int *all = userdata; - assert(e && del && all); - - if (!*all && !e->dead) - return 0; - - if (e->destroy_callback) - e->destroy_callback(&e->mainloop->api, e, e->userdata); - pa_xfree(e); - *del = 1; - return 0; -} - -static int defer_foreach(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void*userdata) { - pa_defer_event *e = p; - int *all = userdata; - assert(e && del && all); - - if (!*all && !e->dead) - return 0; - - if (e->destroy_callback) - e->destroy_callback(&e->mainloop->api, e, e->userdata); - pa_xfree(e); - *del = 1; - return 0; -} - -void pa_mainloop_free(pa_mainloop* m) { - int all = 1; - assert(m); - - pa_idxset_foreach(m->io_events, io_foreach, &all); - pa_idxset_foreach(m->time_events, time_foreach, &all); - pa_idxset_foreach(m->defer_events, defer_foreach, &all); - - pa_idxset_free(m->io_events, NULL, NULL); - pa_idxset_free(m->time_events, NULL, NULL); - pa_idxset_free(m->defer_events, NULL, NULL); - - pa_xfree(m->pollfds); - - if (m->wakeup_pipe[0] >= 0) - close(m->wakeup_pipe[0]); - if (m->wakeup_pipe[1] >= 0) - close(m->wakeup_pipe[1]); - - pa_xfree(m); -} - -static void scan_dead(pa_mainloop *m) { - int all = 0; - assert(m); - - if (m->io_events_scan_dead) - pa_idxset_foreach(m->io_events, io_foreach, &all); - if (m->time_events_scan_dead) - pa_idxset_foreach(m->time_events, time_foreach, &all); - if (m->defer_events_scan_dead) - pa_idxset_foreach(m->defer_events, defer_foreach, &all); - - m->io_events_scan_dead = m->time_events_scan_dead = m->defer_events_scan_dead = 0; -} - -static void rebuild_pollfds(pa_mainloop *m) { - pa_io_event*e; - struct pollfd *p; - uint32_t idx = PA_IDXSET_INVALID; - unsigned l; - - l = pa_idxset_size(m->io_events) + 1; - if (m->max_pollfds < l) { - m->pollfds = pa_xrealloc(m->pollfds, sizeof(struct pollfd)*l); - m->max_pollfds = l; - } - - m->n_pollfds = 0; - p = m->pollfds; - - if (m->wakeup_pipe[0] >= 0) { - m->pollfds[0].fd = m->wakeup_pipe[0]; - m->pollfds[0].events = POLLIN; - m->pollfds[0].revents = 0; - p++; - m->n_pollfds++; - } - - for (e = pa_idxset_first(m->io_events, &idx); e; e = pa_idxset_next(m->io_events, &idx)) { - if (e->dead) { - e->pollfd = NULL; - continue; - } - - e->pollfd = p; - p->fd = e->fd; - p->events = - ((e->events & PA_IO_EVENT_INPUT) ? POLLIN : 0) | - ((e->events & PA_IO_EVENT_OUTPUT) ? POLLOUT : 0) | - POLLHUP | - POLLERR; - p->revents = 0; - - p++; - m->n_pollfds++; - } - - m->rebuild_pollfds = 0; -} - -static int dispatch_pollfds(pa_mainloop *m) { - uint32_t idx = PA_IDXSET_INVALID; - pa_io_event *e; - int r = 0; - - for (e = pa_idxset_first(m->io_events, &idx); e && !m->quit; e = pa_idxset_next(m->io_events, &idx)) { - if (e->dead || !e->pollfd || !e->pollfd->revents) - continue; - - assert(e->pollfd->fd == e->fd && e->callback); - e->callback(&m->api, e, e->fd, - (e->pollfd->revents & POLLHUP ? PA_IO_EVENT_HANGUP : 0) | - (e->pollfd->revents & POLLIN ? PA_IO_EVENT_INPUT : 0) | - (e->pollfd->revents & POLLOUT ? PA_IO_EVENT_OUTPUT : 0) | - (e->pollfd->revents & POLLERR ? PA_IO_EVENT_ERROR : 0), - e->userdata); - e->pollfd->revents = 0; - r++; - } - - return r; -} - -static int dispatch_defer(pa_mainloop *m) { - uint32_t idx; - pa_defer_event *e; - int r = 0; - - if (!m->deferred_pending) - return 0; - - for (e = pa_idxset_first(m->defer_events, &idx); e && !m->quit; e = pa_idxset_next(m->defer_events, &idx)) { - if (e->dead || !e->enabled) - continue; - - assert(e->callback); - e->callback(&m->api, e, e->userdata); - r++; - } - - return r; -} - -static int calc_next_timeout(pa_mainloop *m) { - uint32_t idx; - pa_time_event *e; - struct timeval now; - int t = -1; - int got_time = 0; - - if (pa_idxset_isempty(m->time_events)) - return -1; - - for (e = pa_idxset_first(m->time_events, &idx); e; e = pa_idxset_next(m->time_events, &idx)) { - int tmp; - - if (e->dead || !e->enabled) - continue; - - /* Let's save a system call */ - if (!got_time) { - pa_gettimeofday(&now); - got_time = 1; - } - - if (e->timeval.tv_sec < now.tv_sec || (e->timeval.tv_sec == now.tv_sec && e->timeval.tv_usec <= now.tv_usec)) - return 0; - - tmp = (e->timeval.tv_sec - now.tv_sec)*1000; - - if (e->timeval.tv_usec > now.tv_usec) - tmp += (e->timeval.tv_usec - now.tv_usec)/1000; - else - tmp -= (now.tv_usec - e->timeval.tv_usec)/1000; - - if (tmp == 0) - return 0; - else if (t == -1 || tmp < t) - t = tmp; - } - - return t; -} - -static int dispatch_timeout(pa_mainloop *m) { - uint32_t idx; - pa_time_event *e; - struct timeval now; - int got_time = 0; - int r = 0; - assert(m); - - if (pa_idxset_isempty(m->time_events)) - return 0; - - for (e = pa_idxset_first(m->time_events, &idx); e && !m->quit; e = pa_idxset_next(m->time_events, &idx)) { - - if (e->dead || !e->enabled) - continue; - - /* Let's save a system call */ - if (!got_time) { - pa_gettimeofday(&now); - got_time = 1; - } - - if (e->timeval.tv_sec < now.tv_sec || (e->timeval.tv_sec == now.tv_sec && e->timeval.tv_usec <= now.tv_usec)) { - assert(e->callback); - - e->enabled = 0; - e->callback(&m->api, e, &e->timeval, e->userdata); - - r++; - } - } - - return r; -} - -void pa_mainloop_wakeup(pa_mainloop *m) { - char c = 'W'; - assert(m); - - if (m->wakeup_pipe[1] >= 0) - pa_write(m->wakeup_pipe[1], &c, sizeof(c)); -} - -static void clear_wakeup(pa_mainloop *m) { - char c[10]; - - assert(m); - - if (m->wakeup_pipe[0] < 0) - return; - - while (pa_read(m->wakeup_pipe[0], &c, sizeof(c)) == sizeof(c)); -} - -int pa_mainloop_prepare(pa_mainloop *m, int timeout) { - assert(m); - assert(m->state == STATE_PASSIVE); - - clear_wakeup(m); - scan_dead(m); - - if (m->quit) - goto quit; - - if (!m->deferred_pending) { - - if (m->rebuild_pollfds) - rebuild_pollfds(m); - - m->prepared_timeout = calc_next_timeout(m); - if (timeout >= 0 && (timeout < m->prepared_timeout || m->prepared_timeout < 0)) - m->prepared_timeout = timeout; - } - - m->state = STATE_PREPARED; - return 0; - -quit: - m->state = STATE_QUIT; - return -2; -} - -int pa_mainloop_poll(pa_mainloop *m) { - int r; - - assert(m); - assert(m->state == STATE_PREPARED); - - if (m->quit) - goto quit; - - m->state = STATE_POLLING; - - if (m->deferred_pending) - r = 0; - else { - if (m->poll_func) - r = m->poll_func(m->pollfds, m->n_pollfds, m->prepared_timeout, m->poll_func_userdata); - else - r = poll(m->pollfds, m->n_pollfds, m->prepared_timeout); - - if (r < 0) { - if (errno == EINTR) - r = 0; - else - pa_log(__FILE__": poll(): %s", pa_cstrerror(errno)); - } - } - - m->state = r < 0 ? STATE_PASSIVE : STATE_POLLED; - return r; - -quit: - m->state = STATE_QUIT; - return -2; -} - -int pa_mainloop_dispatch(pa_mainloop *m) { - int dispatched = 0; - - assert(m); - assert(m->state == STATE_POLLED); - - if (m->quit) - goto quit; - - if (m->deferred_pending) - dispatched += dispatch_defer(m); - else { - dispatched += dispatch_timeout(m); - - if (m->quit) - goto quit; - - dispatched += dispatch_pollfds(m); - - } - - if (m->quit) - goto quit; - - m->state = STATE_PASSIVE; - - return dispatched; - -quit: - m->state = STATE_QUIT; - return -2; -} - -int pa_mainloop_get_retval(pa_mainloop *m) { - assert(m); - return m->retval; -} - -int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) { - int r; - assert(m); - - if ((r = pa_mainloop_prepare(m, block ? -1 : 0)) < 0) - goto quit; - - if ((r = pa_mainloop_poll(m)) < 0) - goto quit; - - if ((r = pa_mainloop_dispatch(m)) < 0) - goto quit; - - return r; - -quit: - - if ((r == -2) && retval) - *retval = pa_mainloop_get_retval(m); - return r; -} - -int pa_mainloop_run(pa_mainloop *m, int *retval) { - int r; - - while ((r = pa_mainloop_iterate(m, 1, retval)) >= 0); - - if (r == -2) - return 1; - else if (r < 0) - return -1; - else - return 0; -} - -void pa_mainloop_quit(pa_mainloop *m, int retval) { - assert(m); - - m->quit = 1; - m->retval = retval; - pa_mainloop_wakeup(m); -} - -pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m) { - assert(m); - return &m->api; -} - -void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata) { - assert(m); - - m->poll_func = poll_func; - m->poll_func_userdata = userdata; -} - - -#if 0 -void pa_mainloop_dump(pa_mainloop *m) { - assert(m); - - pa_log(__FILE__": Dumping mainloop sources START"); - - { - uint32_t idx = PA_IDXSET_INVALID; - pa_io_event *e; - for (e = pa_idxset_first(m->io_events, &idx); e; e = pa_idxset_next(m->io_events, &idx)) { - if (e->dead) - continue; - - pa_log(__FILE__": kind=io fd=%i events=%i callback=%p userdata=%p", e->fd, (int) e->events, (void*) e->callback, (void*) e->userdata); - } - } - { - uint32_t idx = PA_IDXSET_INVALID; - pa_defer_event *e; - for (e = pa_idxset_first(m->defer_events, &idx); e; e = pa_idxset_next(m->defer_events, &idx)) { - if (e->dead) - continue; - - pa_log(__FILE__": kind=defer enabled=%i callback=%p userdata=%p", e->enabled, (void*) e->callback, (void*) e->userdata); - } - } - { - uint32_t idx = PA_IDXSET_INVALID; - pa_time_event *e; - for (e = pa_idxset_first(m->time_events, &idx); e; e = pa_idxset_next(m->time_events, &idx)) { - if (e->dead) - continue; - - pa_log(__FILE__": kind=time enabled=%i time=%lu.%lu callback=%p userdata=%p", e->enabled, (unsigned long) e->timeval.tv_sec, (unsigned long) e->timeval.tv_usec, (void*) e->callback, (void*) e->userdata); - } - } - - pa_log(__FILE__": Dumping mainloop sources STOP"); - -} -#endif diff --git a/src/polyp/mainloop.h b/src/polyp/mainloop.h deleted file mode 100644 index 4681912b..00000000 --- a/src/polyp/mainloop.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef foomainloophfoo -#define foomainloophfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -PA_C_DECL_BEGIN - -struct pollfd; - -/** \page mainloop Main Loop - * - * \section overv_sec Overview - * - * The built-in main loop implementation is based on the poll() system call. - * It supports the functions defined in the main loop abstraction and very - * little else. - * - * The main loop is created using pa_mainloop_new() and destroyed using - * pa_mainloop_free(). To get access to the main loop abstraction, - * pa_mainloop_get_api() is used. - * - * \section iter_sec Iteration - * - * The main loop is designed around the concept of iterations. Each iteration - * consists of three steps that repeat during the application's entire - * lifetime: - * - * -# Prepare - Build a list of file descriptors - * that need to be monitored and calculate the next timeout. - * -# Poll - Execute the actuall poll() system call. - * -# Dispatch - Dispatch any events that have fired. - * - * When using the main loop, the application can either execute each - * iteration, one at a time, using pa_mainloop_iterate(), or let the library - * iterate automatically using pa_mainloop_run(). - * - * \section thread_sec Threads - * - * The main loop functions are designed to be thread safe, but the objects - * are not. What this means is that multiple main loops can be used, but only - * one object per thread. - * - */ - -/** \file - * - * A minimal main loop implementation based on the C library's poll() - * function. Using the routines defined herein you may create a simple - * main loop supporting the generic main loop abstraction layer as - * defined in \ref mainloop-api.h. This implementation is thread safe - * as long as you access the main loop object from a single thread only.*/ - -/** An opaque main loop object */ -typedef struct pa_mainloop pa_mainloop; - -/** Allocate a new main loop object */ -pa_mainloop *pa_mainloop_new(void); - -/** Free a main loop object */ -void pa_mainloop_free(pa_mainloop* m); - -/** Prepare for a single iteration of the main loop. Returns a negative value -on error or exit request. timeout specifies a maximum timeout for the subsequent -poll, or -1 for blocking behaviour. .*/ -int pa_mainloop_prepare(pa_mainloop *m, int timeout); - -/** Execute the previously prepared poll. Returns a negative value on error.*/ -int pa_mainloop_poll(pa_mainloop *m); - -/** Dispatch timeout, io and deferred events from the previously executed poll. Returns -a negative value on error. On success returns the number of source dispatched. */ -int pa_mainloop_dispatch(pa_mainloop *m); - -/** Return the return value as specified with the main loop's quit() routine. */ -int pa_mainloop_get_retval(pa_mainloop *m); - -/** Run a single iteration of the main loop. This is a convenience function -for pa_mainloop_prepare(), pa_mainloop_poll() and pa_mainloop_dispatch(). -Returns a negative value on error or exit request. If block is nonzero, -block for events if none are queued. Optionally return the return value as -specified with the main loop's quit() routine in the integer variable retval points -to. On success returns the number of sources dispatched in this iteration. */ -int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval); - -/** Run unlimited iterations of the main loop object until the main loop's quit() routine is called. */ -int pa_mainloop_run(pa_mainloop *m, int *retval); - -/** Return the abstract main loop abstraction layer vtable for this main loop. */ -pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m); - -/** Shutdown the main loop */ -void pa_mainloop_quit(pa_mainloop *m, int r); - -/** Interrupt a running poll (for threaded systems) */ -void pa_mainloop_wakeup(pa_mainloop *m); - -/** Generic prototype of a poll() like function */ -typedef int (*pa_poll_func)(struct pollfd *ufds, unsigned long nfds, int timeout, void*userdata); - -/** Change the poll() implementation */ -void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/operation.c b/src/polyp/operation.c deleted file mode 100644 index 5af9ec0b..00000000 --- a/src/polyp/operation.c +++ /dev/null @@ -1,116 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include - -#include "internal.h" -#include "operation.h" - -pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t cb, void *userdata) { - pa_operation *o; - assert(c); - - o = pa_xnew(pa_operation, 1); - o->ref = 1; - o->context = c; - o->stream = s; - - o->state = PA_OPERATION_RUNNING; - o->callback = cb; - o->userdata = userdata; - - /* Refcounting is strictly one-way: from the "bigger" to the "smaller" object. */ - PA_LLIST_PREPEND(pa_operation, c->operations, o); - pa_operation_ref(o); - - return o; -} - -pa_operation *pa_operation_ref(pa_operation *o) { - assert(o); - assert(o->ref >= 1); - - o->ref++; - return o; -} - -void pa_operation_unref(pa_operation *o) { - assert(o); - assert(o->ref >= 1); - - if ((--(o->ref)) == 0) { - assert(!o->context); - assert(!o->stream); - pa_xfree(o); - } -} - -static void operation_set_state(pa_operation *o, pa_operation_state_t st) { - assert(o); - assert(o->ref >= 1); - - if (st == o->state) - return; - - o->state = st; - - if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) { - - if (o->context) { - assert(o->ref >= 2); - - PA_LLIST_REMOVE(pa_operation, o->context->operations, o); - pa_operation_unref(o); - } - - o->context = NULL; - o->stream = NULL; - o->callback = NULL; - o->userdata = NULL; - } -} - -void pa_operation_cancel(pa_operation *o) { - assert(o); - assert(o->ref >= 1); - - operation_set_state(o, PA_OPERATION_CANCELED); -} - -void pa_operation_done(pa_operation *o) { - assert(o); - assert(o->ref >= 1); - - operation_set_state(o, PA_OPERATION_DONE); -} - -pa_operation_state_t pa_operation_get_state(pa_operation *o) { - assert(o); - assert(o->ref >= 1); - - return o->state; -} diff --git a/src/polyp/operation.h b/src/polyp/operation.h deleted file mode 100644 index 2fbac2e2..00000000 --- a/src/polyp/operation.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef foooperationhfoo -#define foooperationhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -/** \file - * Asynchronous operations */ - -PA_C_DECL_BEGIN - -/** An asynchronous operation object */ -typedef struct pa_operation pa_operation; - -/** Increase the reference count by one */ -pa_operation *pa_operation_ref(pa_operation *o); - -/** Decrease the reference count by one */ -void pa_operation_unref(pa_operation *o); - -/** Cancel the operation. Beware! This will not necessarily cancel the execution of the operation on the server side. */ -void pa_operation_cancel(pa_operation *o); - -/** Return the current status of the operation */ -pa_operation_state_t pa_operation_get_state(pa_operation *o); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/polypaudio.h b/src/polyp/polypaudio.h deleted file mode 100644 index c172315b..00000000 --- a/src/polyp/polypaudio.h +++ /dev/null @@ -1,115 +0,0 @@ -#ifndef foopolypaudiohfoo -#define foopolypaudiohfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** \file - * Include all polyplib header files at once. The following - * files are included: \ref mainloop-api.h, \ref sample.h, \ref def.h, - * \ref context.h, \ref stream.h, \ref introspect.h, \ref subscribe.h, - * \ref scache.h, \ref version.h, \ref error.h, \ref channelmap.h, - * \ref operation.h,\ref volume.h, \ref xmalloc.h, \ref utf8.h, \ref - * thread-mainloop.h, \ref mainloop.h, \ref util.h, \ref timeval.h and - * \ref mainloop-signal.h at once */ - -/** \mainpage - * - * \section intro_sec Introduction - * - * This document describes the client API for the polypaudio sound - * server. The API comes in two flavours to accomodate different styles - * of applications and different needs in complexity: - * - * \li The complete but somewhat complicated to use asynchronous API - * \li The simplified, easy to use, but limited synchronous API - * - * All strings in Polypaudio are in the UTF-8 encoding, regardless of current - * locale. Some functions will filter invalid sequences from the string, some - * will simply fail. To ensure reliable behaviour, make sure everything you - * pass to the API is already in UTF-8. - - * \section simple_sec Simple API - * - * Use this if you develop your program in synchronous style and just - * need a way to play or record data on the sound server. See - * \subpage simple for more details. - * - * \section async_sec Asynchronous API - * - * Use this if you develop your programs in asynchronous, event loop - * based style or if you want to use the advanced features of the - * polypaudio API. A guide can be found in \subpage async. - * - * By using the built-in threaded main loop, it is possible to acheive a - * pseudo-synchronous API, which can be useful in synchronous applications - * where the simple API is insufficient. See the \ref async page for - * details. - * - * \section thread_sec Threads - * - * The polypaudio client libraries are not designed to be used in a - * heavily threaded environment. They are however designed to be reentrant - * safe. - * - * To use a the libraries in a threaded environment, you must assure that - * all objects are only used in one thread at a time. Normally, this means - * that all objects belonging to a single context must be accessed from the - * same thread. - * - * The included main loop implementation is also not thread safe. Take care - * to make sure event lists are not manipulated when any other code is - * using the main loop. - * - * \section pkgconfig pkg-config - * - * The polypaudio libraries provide pkg-config snippets for the different - * modules: - * - * \li polyplib - The asynchronous API and the internal main loop - * implementation. - * \li polyplib-glib12-mainloop - GLIB 1.2 main loop bindings. - * \li polyplib-glib-mainloop - GLIB 2.x main loop bindings. - * \li polyplib-simple - The simple polypaudio API. - */ - -#endif diff --git a/src/polyp/sample.c b/src/polyp/sample.c deleted file mode 100644 index 9c3b9f91..00000000 --- a/src/polyp/sample.c +++ /dev/null @@ -1,156 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "sample.h" - -size_t pa_sample_size(const pa_sample_spec *spec) { - assert(spec); - - switch (spec->format) { - case PA_SAMPLE_U8: - case PA_SAMPLE_ULAW: - case PA_SAMPLE_ALAW: - return 1; - case PA_SAMPLE_S16LE: - case PA_SAMPLE_S16BE: - return 2; - case PA_SAMPLE_FLOAT32LE: - case PA_SAMPLE_FLOAT32BE: - return 4; - default: - assert(0); - return 0; - } -} - -size_t pa_frame_size(const pa_sample_spec *spec) { - assert(spec); - - return pa_sample_size(spec) * spec->channels; -} - -size_t pa_bytes_per_second(const pa_sample_spec *spec) { - assert(spec); - return spec->rate*pa_frame_size(spec); -} - -pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) { - assert(spec); - - return (pa_usec_t) (((double) length/pa_frame_size(spec)*1000000)/spec->rate); -} - -size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec) { - assert(spec); - - return ((double) t * spec->rate / 1000000)*pa_frame_size(spec); -} - -int pa_sample_spec_valid(const pa_sample_spec *spec) { - assert(spec); - - if (spec->rate <= 0 || - spec->channels <= 0 || - spec->channels > PA_CHANNELS_MAX || - spec->format >= PA_SAMPLE_MAX || - spec->format < 0) - return 0; - - return 1; -} - -int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b) { - assert(a && b); - - return (a->format == b->format) && (a->rate == b->rate) && (a->channels == b->channels); -} - -const char *pa_sample_format_to_string(pa_sample_format_t f) { - static const char* const table[]= { - [PA_SAMPLE_U8] = "u8", - [PA_SAMPLE_ALAW] = "aLaw", - [PA_SAMPLE_ULAW] = "uLaw", - [PA_SAMPLE_S16LE] = "s16le", - [PA_SAMPLE_S16BE] = "s16be", - [PA_SAMPLE_FLOAT32LE] = "float32le", - [PA_SAMPLE_FLOAT32BE] = "float32be", - }; - - if (f >= PA_SAMPLE_MAX) - return NULL; - - return table[f]; -} - -char *pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec) { - assert(s && l && spec); - - if (!pa_sample_spec_valid(spec)) - snprintf(s, l, "Invalid"); - else - snprintf(s, l, "%s %uch %uHz", pa_sample_format_to_string(spec->format), spec->channels, spec->rate); - - return s; -} - -void pa_bytes_snprint(char *s, size_t l, unsigned v) { - if (v >= ((unsigned) 1024)*1024*1024) - snprintf(s, l, "%0.1f GiB", ((double) v)/1024/1024/1024); - else if (v >= ((unsigned) 1024)*1024) - snprintf(s, l, "%0.1f MiB", ((double) v)/1024/1024); - else if (v >= (unsigned) 1024) - snprintf(s, l, "%0.1f KiB", ((double) v)/1024); - else - snprintf(s, l, "%u B", (unsigned) v); -} - -pa_sample_format_t pa_parse_sample_format(const char *format) { - - if (strcasecmp(format, "s16le") == 0) - return PA_SAMPLE_S16LE; - else if (strcasecmp(format, "s16be") == 0) - return PA_SAMPLE_S16BE; - else if (strcasecmp(format, "s16ne") == 0 || strcasecmp(format, "s16") == 0 || strcasecmp(format, "16") == 0) - return PA_SAMPLE_S16NE; - else if (strcasecmp(format, "u8") == 0 || strcasecmp(format, "8") == 0) - return PA_SAMPLE_U8; - else if (strcasecmp(format, "float32") == 0 || strcasecmp(format, "float32ne") == 0) - return PA_SAMPLE_FLOAT32; - else if (strcasecmp(format, "float32le") == 0) - return PA_SAMPLE_FLOAT32LE; - else if (strcasecmp(format, "float32be") == 0) - return PA_SAMPLE_FLOAT32BE; - else if (strcasecmp(format, "ulaw") == 0) - return PA_SAMPLE_ULAW; - else if (strcasecmp(format, "alaw") == 0) - return PA_SAMPLE_ALAW; - - return -1; -} diff --git a/src/polyp/sample.h b/src/polyp/sample.h deleted file mode 100644 index 2a9a72fe..00000000 --- a/src/polyp/sample.h +++ /dev/null @@ -1,189 +0,0 @@ -#ifndef foosamplehfoo -#define foosamplehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include - -#include - -/** \page sample Sample Format Specifications - * - * \section overv_sec Overview - * - * Polypaudio is capable of handling a multitude of sample formats, rates - * and channels, transparently converting and mixing them as needed. - * - * \section format_sec Sample Format - * - * Polypaudio supports the following sample formats: - * - * \li PA_SAMPLE_U8 - Unsigned 8 bit PCM. - * \li PA_SAMPLE_S16LE - Signed 16 bit PCM, little endian. - * \li PA_SAMPLE_S16BE - Signed 16 bit PCM, big endian. - * \li PA_SAMPLE_FLOAT32LE - 32 bit IEEE floating point PCM, little endian. - * \li PA_SAMPLE_FLOAT32BE - 32 bit IEEE floating point PCM, big endian. - * \li PA_SAMPLE_ALAW - 8 bit a-Law. - * \li PA_SAMPLE_ULAW - 8 bit mu-Law. - * - * The floating point sample formats have the range from -1 to 1. - * - * The sample formats that are sensitive to endianness have convenience - * macros for native endian (NE), and reverse endian (RE). - * - * \section rate_sec Sample Rates - * - * Polypaudio supports any sample rate between 1 Hz and 4 GHz. There is no - * point trying to exceed the sample rate of the output device though as the - * signal will only get downsampled, consuming CPU on the machine running the - * server. - * - * \section chan_sec Channels - * - * Polypaudio supports up to 16 individiual channels. The order of the - * channels is up to the application, but they must be continous. To map - * channels to speakers, see \ref channelmap. - * - * \section calc_sec Calculations - * - * The Polypaudio library contains a number of convenience functions to do - * calculations on sample formats: - * - * \li pa_bytes_per_second() - The number of bytes one second of audio will - * take given a sample format. - * \li pa_frame_size() - The size, in bytes, of one frame (i.e. one set of - * samples, one for each channel). - * \li pa_sample_size() - The size, in bytes, of one sample. - * \li pa_bytes_to_usec() - Calculate the time it would take to play a buffer - * of a certain size. - * - * \section util_sec Convenience Functions - * - * The library also contains a couple of other convenience functions: - * - * \li pa_sample_spec_valid() - Tests if a sample format specification is - * valid. - * \li pa_sample_spec_equal() - Tests if the sample format specifications are - * identical. - * \li pa_sample_format_to_string() - Return a textual description of a - * sample format. - * \li pa_parse_sample_format() - Parse a text string into a sample format. - * \li pa_sample_spec_snprint() - Create a textual description of a complete - * sample format specification. - * \li pa_bytes_snprint() - Pretty print a byte value (e.g. 2.5 MiB). - */ - -/** \file - * Constants and routines for sample type handling */ - -PA_C_DECL_BEGIN - -/** Maximum number of allowed channels */ -#define PA_CHANNELS_MAX 32 - -/** Sample format */ -typedef enum pa_sample_format { - PA_SAMPLE_U8, /**< Unsigned 8 Bit PCM */ - PA_SAMPLE_ALAW, /**< 8 Bit a-Law */ - PA_SAMPLE_ULAW, /**< 8 Bit mu-Law */ - PA_SAMPLE_S16LE, /**< Signed 16 Bit PCM, little endian (PC) */ - PA_SAMPLE_S16BE, /**< Signed 16 Bit PCM, big endian */ - PA_SAMPLE_FLOAT32LE, /**< 32 Bit IEEE floating point, little endian, range -1 to 1 */ - PA_SAMPLE_FLOAT32BE, /**< 32 Bit IEEE floating point, big endian, range -1 to 1 */ - PA_SAMPLE_MAX, /**< Upper limit of valid sample types */ - PA_SAMPLE_INVALID = -1 /**< An invalid value */ -} pa_sample_format_t; - -#ifdef WORDS_BIGENDIAN -/** Signed 16 Bit PCM, native endian */ -#define PA_SAMPLE_S16NE PA_SAMPLE_S16BE -/** 32 Bit IEEE floating point, native endian */ -#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32BE -/** Signed 16 Bit PCM reverse endian */ -#define PA_SAMPLE_S16RE PA_SAMPLE_S16LE -/** 32 Bit IEEE floating point, reverse endian */ -#define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32LE -#else -/** Signed 16 Bit PCM, native endian */ -#define PA_SAMPLE_S16NE PA_SAMPLE_S16LE -/** 32 Bit IEEE floating point, native endian */ -#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32LE -/** Signed 16 Bit PCM reverse endian */ -#define PA_SAMPLE_S16RE PA_SAMPLE_S16BE -/** 32 Bit IEEE floating point, reverse endian */ -#define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32BE -#endif - -/** A Shortcut for PA_SAMPLE_FLOAT32NE */ -#define PA_SAMPLE_FLOAT32 PA_SAMPLE_FLOAT32NE - -/** A sample format and attribute specification */ -typedef struct pa_sample_spec { - pa_sample_format_t format; /**< The sample format */ - uint32_t rate; /**< The sample rate. (e.g. 44100) */ - uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */ -} pa_sample_spec; - -/** Type for usec specifications (unsigned). May be either 32 or 64 bit, depending on the architecture */ -typedef uint64_t pa_usec_t; - -/** Return the amount of bytes playback of a second of audio with the specified sample type takes */ -size_t pa_bytes_per_second(const pa_sample_spec *spec); - -/** Return the size of a frame with the specific sample type */ -size_t pa_frame_size(const pa_sample_spec *spec); - -/** Return the size of a sample with the specific sample type */ -size_t pa_sample_size(const pa_sample_spec *spec); - -/** Calculate the time the specified bytes take to play with the specified sample type */ -pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec); - -/** Calculates the number of bytes that are required for the specified time. \since 0.9 */ -size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec); - -/** Return non-zero when the sample type specification is valid */ -int pa_sample_spec_valid(const pa_sample_spec *spec); - -/** Return non-zero when the two sample type specifications match */ -int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b); - -/** Return a descriptive string for the specified sample format. \since 0.8 */ -const char *pa_sample_format_to_string(pa_sample_format_t f); - -/** Parse a sample format text. Inverse of pa_sample_format_to_string() */ -pa_sample_format_t pa_parse_sample_format(const char *format); - -/** Maximum required string length for pa_sample_spec_snprint() */ -#define PA_SAMPLE_SPEC_SNPRINT_MAX 32 - -/** Pretty print a sample type specification to a string */ -char* pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec); - -/** Pretty print a byte size value. (i.e. "2.5 MiB") */ -void pa_bytes_snprint(char *s, size_t l, unsigned v); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/scache.c b/src/polyp/scache.c deleted file mode 100644 index 22d8a545..00000000 --- a/src/polyp/scache.c +++ /dev/null @@ -1,131 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -#include "internal.h" - -#include "scache.h" - -int pa_stream_connect_upload(pa_stream *s, size_t length) { - pa_tagstruct *t; - uint32_t tag; - - assert(s); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, length > 0, PA_ERR_INVALID); - - pa_stream_ref(s); - - s->direction = PA_STREAM_UPLOAD; - - t = pa_tagstruct_command(s->context, PA_COMMAND_CREATE_UPLOAD_STREAM, &tag); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_put_channel_map(t, &s->channel_map); - pa_tagstruct_putu32(t, length); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL); - - pa_stream_set_state(s, PA_STREAM_CREATING); - - pa_stream_unref(s); - return 0; -} - -int pa_stream_finish_upload(pa_stream *s) { - pa_tagstruct *t; - uint32_t tag; - assert(s); - - PA_CHECK_VALIDITY(s->context, s->channel_valid, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pa_stream_ref(s); - - t = pa_tagstruct_command(s->context, PA_COMMAND_FINISH_UPLOAD_STREAM, &tag); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s, NULL); - - pa_stream_unref(s); - return 0; -} - -pa_operation *pa_context_play_sample(pa_context *c, const char *name, const char *dev, pa_volume_t volume, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, !dev || *dev, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - if (!dev) - dev = c->conf->default_sink; - - t = pa_tagstruct_command(c, PA_COMMAND_PLAY_SAMPLE, &tag); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, dev); - pa_tagstruct_putu32(t, volume); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_remove_sample(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_SAMPLE, &tag); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - diff --git a/src/polyp/scache.h b/src/polyp/scache.h deleted file mode 100644 index 91890673..00000000 --- a/src/polyp/scache.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef fooscachehfoo -#define fooscachehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include -#include -#include - -/** \page scache Sample Cache - * - * \section overv_sec Overview - * - * The sample cache provides a simple way of overcoming high network latencies - * and reducing bandwidth. Instead of streaming a sound precisely when it - * should be played, it is stored on the server and only the command to start - * playing it needs to be sent. - * - * \section create_sec Creation - * - * To create a sample, the normal stream API is used (see \ref streams). The - * function pa_stream_connect_upload() will make sure the stream is stored as - * a sample on the server. - * - * To complete the upload, pa_stream_finish_upload() is called and the sample - * will receive the same name as the stream. If the upload should be aborted, - * simply call pa_stream_disconnect(). - * - * \section play_sec Playing samples - * - * To play back a sample, simply call pa_context_play_sample(): - * - * \code - * pa_operation *o; - * - * o = pa_context_play_sample(my_context, - * "sample2", // Name of my sample - * NULL, // Use default sink - * PA_VOLUME_NORM, // Full volume - * NULL, // Don't need a callback - * NULL - * ); - * if (o) - * pa_operation_unref(o); - * \endcode - * - * \section rem_sec Removing samples - * - * When a sample is no longer needed, it should be removed on the server to - * save resources. The sample is deleted using pa_context_remove_sample(). - */ - -/** \file - * All sample cache related routines */ - -PA_C_DECL_BEGIN - -/** Make this stream a sample upload stream */ -int pa_stream_connect_upload(pa_stream *s, size_t length); - -/** Finish the sample upload, the stream name will become the sample name. You cancel a samp - * le upload by issuing pa_stream_disconnect() */ -int pa_stream_finish_upload(pa_stream *s); - -/** Play a sample from the sample cache to the specified device. If the latter is NULL use the default sink. Returns an operation object */ -pa_operation* pa_context_play_sample( - pa_context *c /**< Context */, - const char *name /**< Name of the sample to play */, - const char *dev /**< Sink to play this sample on */, - pa_volume_t volume /**< Volume to play this sample with */ , - pa_context_success_cb_t cb /**< Call this function after successfully starting playback, or NULL */, - void *userdata /**< Userdata to pass to the callback */); - -/** Remove a sample from the sample cache. Returns an operation object which may be used to cancel the operation while it is running */ -pa_operation* pa_context_remove_sample(pa_context *c, const char *name, pa_context_success_cb_t, void *userdata); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/simple.c b/src/polyp/simple.c deleted file mode 100644 index 9c2c908c..00000000 --- a/src/polyp/simple.c +++ /dev/null @@ -1,455 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include "simple.h" - -struct pa_simple { - pa_threaded_mainloop *mainloop; - pa_context *context; - pa_stream *stream; - pa_stream_direction_t direction; - - const void *read_data; - size_t read_index, read_length; - - int operation_success; -}; - -#define CHECK_VALIDITY_RETURN_ANY(rerror, expression, error, ret) do { \ -if (!(expression)) { \ - if (rerror) \ - *(rerror) = error; \ - return (ret); \ - } \ -} while(0); - -#define CHECK_SUCCESS_GOTO(p, rerror, expression, label) do { \ -if (!(expression)) { \ - if (rerror) \ - *(rerror) = pa_context_errno((p)->context); \ - goto label; \ - } \ -} while(0); - -#define CHECK_DEAD_GOTO(p, rerror, label) do { \ -if (!(p)->context || pa_context_get_state((p)->context) != PA_CONTEXT_READY || \ - !(p)->stream || pa_stream_get_state((p)->stream) != PA_STREAM_READY) { \ - if (((p)->context && pa_context_get_state((p)->context) == PA_CONTEXT_FAILED) || \ - ((p)->stream && pa_stream_get_state((p)->stream) == PA_STREAM_FAILED)) { \ - if (rerror) \ - *(rerror) = pa_context_errno((p)->context); \ - } else \ - if (rerror) \ - *(rerror) = PA_ERR_BADSTATE; \ - goto label; \ - } \ -} while(0); - -static void context_state_cb(pa_context *c, void *userdata) { - pa_simple *p = userdata; - assert(c); - assert(p); - - switch (pa_context_get_state(c)) { - case PA_CONTEXT_READY: - case PA_CONTEXT_TERMINATED: - case PA_CONTEXT_FAILED: - pa_threaded_mainloop_signal(p->mainloop, 0); - break; - - case PA_CONTEXT_UNCONNECTED: - case PA_CONTEXT_CONNECTING: - case PA_CONTEXT_AUTHORIZING: - case PA_CONTEXT_SETTING_NAME: - break; - } -} - -static void stream_state_cb(pa_stream *s, void * userdata) { - pa_simple *p = userdata; - assert(s); - assert(p); - - switch (pa_stream_get_state(s)) { - - case PA_STREAM_READY: - case PA_STREAM_FAILED: - case PA_STREAM_TERMINATED: - pa_threaded_mainloop_signal(p->mainloop, 0); - break; - - case PA_STREAM_UNCONNECTED: - case PA_STREAM_CREATING: - break; - } -} - -static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { - pa_simple *p = userdata; - assert(p); - - pa_threaded_mainloop_signal(p->mainloop, 0); -} - -static void stream_latency_update_cb(pa_stream *s, void *userdata) { - pa_simple *p = userdata; - - assert(p); - - pa_threaded_mainloop_signal(p->mainloop, 0); -} - -pa_simple* pa_simple_new( - const char *server, - const char *name, - pa_stream_direction_t dir, - const char *dev, - const char *stream_name, - const pa_sample_spec *ss, - const pa_channel_map *map, - const pa_buffer_attr *attr, - int *rerror) { - - pa_simple *p; - int error = PA_ERR_INTERNAL, r; - - CHECK_VALIDITY_RETURN_ANY(rerror, !server || *server, PA_ERR_INVALID, NULL); - CHECK_VALIDITY_RETURN_ANY(rerror, dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD, PA_ERR_INVALID, NULL); - CHECK_VALIDITY_RETURN_ANY(rerror, !dev || *dev, PA_ERR_INVALID, NULL); - CHECK_VALIDITY_RETURN_ANY(rerror, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID, NULL); - CHECK_VALIDITY_RETURN_ANY(rerror, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID, NULL) - - p = pa_xnew(pa_simple, 1); - p->context = NULL; - p->stream = NULL; - p->direction = dir; - p->read_data = NULL; - p->read_index = p->read_length = 0; - - if (!(p->mainloop = pa_threaded_mainloop_new())) - goto fail; - - if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), name))) - goto fail; - - pa_context_set_state_callback(p->context, context_state_cb, p); - - if (pa_context_connect(p->context, server, 0, NULL) < 0) { - error = pa_context_errno(p->context); - goto fail; - } - - pa_threaded_mainloop_lock(p->mainloop); - - if (pa_threaded_mainloop_start(p->mainloop) < 0) - goto unlock_and_fail; - - /* Wait until the context is ready */ - pa_threaded_mainloop_wait(p->mainloop); - - if (pa_context_get_state(p->context) != PA_CONTEXT_READY) { - error = pa_context_errno(p->context); - goto unlock_and_fail; - } - - if (!(p->stream = pa_stream_new(p->context, stream_name, ss, map))) { - error = pa_context_errno(p->context); - goto unlock_and_fail; - } - - pa_stream_set_state_callback(p->stream, stream_state_cb, p); - pa_stream_set_read_callback(p->stream, stream_request_cb, p); - pa_stream_set_write_callback(p->stream, stream_request_cb, p); - pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p); - - if (dir == PA_STREAM_PLAYBACK) - r = pa_stream_connect_playback(p->stream, dev, attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); - else - r = pa_stream_connect_record(p->stream, dev, attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE); - - if (r < 0) { - error = pa_context_errno(p->context); - goto unlock_and_fail; - } - - /* Wait until the stream is ready */ - pa_threaded_mainloop_wait(p->mainloop); - - /* Wait until the stream is ready */ - if (pa_stream_get_state(p->stream) != PA_STREAM_READY) { - error = pa_context_errno(p->context); - goto unlock_and_fail; - } - - pa_threaded_mainloop_unlock(p->mainloop); - - return p; - -unlock_and_fail: - pa_threaded_mainloop_unlock(p->mainloop); - -fail: - if (rerror) - *rerror = error; - pa_simple_free(p); - return NULL; -} - -void pa_simple_free(pa_simple *s) { - assert(s); - - if (s->mainloop) - pa_threaded_mainloop_stop(s->mainloop); - - if (s->stream) - pa_stream_unref(s->stream); - - if (s->context) - pa_context_unref(s->context); - - if (s->mainloop) - pa_threaded_mainloop_free(s->mainloop); - - pa_xfree(s); -} - -int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { - assert(p); - - CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); - CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1); - - pa_threaded_mainloop_lock(p->mainloop); - - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - - while (length > 0) { - size_t l; - int r; - - while (!(l = pa_stream_writable_size(p->stream))) { - pa_threaded_mainloop_wait(p->mainloop); - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - } - - CHECK_SUCCESS_GOTO(p, rerror, l != (size_t) -1, unlock_and_fail); - - if (l > length) - l = length; - - r = pa_stream_write(p->stream, data, l, NULL, 0, PA_SEEK_RELATIVE); - CHECK_SUCCESS_GOTO(p, rerror, r >= 0, unlock_and_fail); - - data = (const uint8_t*) data + l; - length -= l; - } - - pa_threaded_mainloop_unlock(p->mainloop); - return 0; - -unlock_and_fail: - pa_threaded_mainloop_unlock(p->mainloop); - return -1; -} - -int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { - assert(p); - - CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, -1); - CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1); - - pa_threaded_mainloop_lock(p->mainloop); - - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - - while (length > 0) { - size_t l; - - while (!p->read_data) { - int r; - - r = pa_stream_peek(p->stream, &p->read_data, &p->read_length); - CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail); - - if (!p->read_data) { - pa_threaded_mainloop_wait(p->mainloop); - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - } else - p->read_index = 0; - } - - l = p->read_length < length ? p->read_length : length; - memcpy(data, (const uint8_t*) p->read_data+p->read_index, l); - - data = (uint8_t*) data + l; - length -= l; - - p->read_index += l; - p->read_length -= l; - - if (!p->read_length) { - int r; - - r = pa_stream_drop(p->stream); - p->read_data = NULL; - p->read_length = 0; - p->read_index = 0; - - CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail); - } - } - - pa_threaded_mainloop_unlock(p->mainloop); - return 0; - -unlock_and_fail: - pa_threaded_mainloop_unlock(p->mainloop); - return -1; -} - -static void success_cb(pa_stream *s, int success, void *userdata) { - pa_simple *p = userdata; - - assert(s); - assert(p); - - p->operation_success = success; - pa_threaded_mainloop_signal(p->mainloop, 0); -} - -int pa_simple_drain(pa_simple *p, int *rerror) { - pa_operation *o = NULL; - - assert(p); - - CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); - - pa_threaded_mainloop_lock(p->mainloop); - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - - o = pa_stream_drain(p->stream, success_cb, p); - CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); - - p->operation_success = 0; - while (pa_operation_get_state(o) != PA_OPERATION_DONE) { - pa_threaded_mainloop_wait(p->mainloop); - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - } - CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail); - - pa_operation_unref(o); - pa_threaded_mainloop_unlock(p->mainloop); - - return 0; - -unlock_and_fail: - - if (o) { - pa_operation_cancel(o); - pa_operation_unref(o); - } - - pa_threaded_mainloop_unlock(p->mainloop); - return -1; -} - -int pa_simple_flush(pa_simple *p, int *rerror) { - pa_operation *o = NULL; - - assert(p); - - CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); - - pa_threaded_mainloop_lock(p->mainloop); - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - - o = pa_stream_flush(p->stream, success_cb, p); - CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); - - p->operation_success = 0; - while (pa_operation_get_state(o) != PA_OPERATION_DONE) { - pa_threaded_mainloop_wait(p->mainloop); - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - } - CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail); - - pa_operation_unref(o); - pa_threaded_mainloop_unlock(p->mainloop); - - return 0; - -unlock_and_fail: - - if (o) { - pa_operation_cancel(o); - pa_operation_unref(o); - } - - pa_threaded_mainloop_unlock(p->mainloop); - return -1; -} - -pa_usec_t pa_simple_get_latency(pa_simple *p, int *rerror) { - pa_usec_t t; - int negative; - - assert(p); - - pa_threaded_mainloop_lock(p->mainloop); - - for (;;) { - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - - if (pa_stream_get_latency(p->stream, &t, &negative) >= 0) - break; - - CHECK_SUCCESS_GOTO(p, rerror, pa_context_errno(p->context) == PA_ERR_NODATA, unlock_and_fail); - - /* Wait until latency data is available again */ - pa_threaded_mainloop_wait(p->mainloop); - } - - pa_threaded_mainloop_unlock(p->mainloop); - - return negative ? 0 : t; - -unlock_and_fail: - - pa_threaded_mainloop_unlock(p->mainloop); - return (pa_usec_t) -1; -} - diff --git a/src/polyp/simple.h b/src/polyp/simple.h deleted file mode 100644 index b97e844b..00000000 --- a/src/polyp/simple.h +++ /dev/null @@ -1,146 +0,0 @@ -#ifndef foosimplehfoo -#define foosimplehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include -#include -#include -#include - -/** \page simple Simple API - * - * \section overv_sec Overview - * - * The simple API is designed for applications with very basic sound - * playback or capture needs. It can only support a single stream per - * connection and has no handling of complex features like events, channel - * mappings and volume control. It is, however, very simple to use and - * quite sufficent for many programs. - * - * \section conn_sec Connecting - * - * The first step before using the sound system is to connect to the - * server. This is normally done this way: - * - * \code - * pa_simple *s; - * pa_sample_spec ss; - * - * ss.format = PA_SAMPLE_S16_NE; - * ss.channels = 2; - * ss.rate = 44100; - * - * s = pa_simple_new(NULL, // Use the default server. - * "Fooapp", // Our application's name. - * PA_STREAM_PLAYBACK, - * NULL, // Use the default device. - * "Music", // Description of our stream. - * &ss, // Our sample format. - * NULL, // Use default channel map - * NULL, // Use default buffering attributes. - * NULL, // Ignore error code. - * ); - * \endcode - * - * At this point a connected object is returned, or NULL if there was a - * problem connecting. - * - * \section transfer_sec Transferring data - * - * Once the connection is established to the server, data can start flowing. - * Using the connection is very similar to the normal read() and write() - * system calls. The main difference is that they're call pa_simple_read() - * and pa_simple_write(). Note that these operations always block. - * - * \section ctrl_sec Buffer control - * - * If a playback stream is used then a few other operations are available: - * - * \li pa_simple_drain() - Will wait for all sent data to finish playing. - * \li pa_simple_flush() - Will throw away all data currently in buffers. - * \li pa_simple_get_playback_latency() - Will return the total latency of - * the playback pipeline. - * - * \section cleanup_sec Cleanup - * - * Once playback or capture is complete, the connection should be closed - * and resources freed. This is done through: - * - * \code - * pa_simple_free(s); - * \endcode - */ - -/** \file - * A simple but limited synchronous playback and recording - * API. This is a synchronous, simplified wrapper around the standard - * asynchronous API. */ - -/** \example pacat-simple.c - * A simple playback tool using the simple API */ - -/** \example parec-simple.c - * A simple recording tool using the simple API */ - -PA_C_DECL_BEGIN - -/** \struct pa_simple - * An opaque simple connection object */ -typedef struct pa_simple pa_simple; - -/** Create a new connection to the server */ -pa_simple* pa_simple_new( - const char *server, /**< Server name, or NULL for default */ - const char *name, /**< A descriptive name for this client (application name, ...) */ - pa_stream_direction_t dir, /**< Open this stream for recording or playback? */ - const char *dev, /**< Sink (resp. source) name, or NULL for default */ - const char *stream_name, /**< A descriptive name for this client (application name, song title, ...) */ - const pa_sample_spec *ss, /**< The sample type to use */ - const pa_channel_map *map, /**< The channel map to use, or NULL for default */ - const pa_buffer_attr *attr, /**< Buffering attributes, or NULL for default */ - int *error /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */ - ); - -/** Close and free the connection to the server. The connection objects becomes invalid when this is called. */ -void pa_simple_free(pa_simple *s); - -/** Write some data to the server */ -int pa_simple_write(pa_simple *s, const void*data, size_t length, int *error); - -/** Wait until all data already written is played by the daemon */ -int pa_simple_drain(pa_simple *s, int *error); - -/** Read some data from the server */ -int pa_simple_read(pa_simple *s, void*data, size_t length, int *error); - -/** Return the playback latency. \since 0.5 */ -pa_usec_t pa_simple_get_latency(pa_simple *s, int *error); - -/** Flush the playback buffer. \since 0.5 */ -int pa_simple_flush(pa_simple *s, int *error); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/stream.c b/src/polyp/stream.c deleted file mode 100644 index 8927805e..00000000 --- a/src/polyp/stream.c +++ /dev/null @@ -1,1366 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include "internal.h" - -#define LATENCY_IPOL_INTERVAL_USEC (100000L) - -pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map) { - pa_stream *s; - int i; - - assert(c); - - PA_CHECK_VALIDITY_RETURN_NULL(c, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID); - - s = pa_xnew(pa_stream, 1); - s->ref = 1; - s->context = c; - s->mainloop = c->mainloop; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->state_callback = NULL; - s->state_userdata = NULL; - s->overflow_callback = NULL; - s->overflow_userdata = NULL; - s->underflow_callback = NULL; - s->underflow_userdata = NULL; - s->latency_update_callback = NULL; - s->latency_update_userdata = NULL; - - s->direction = PA_STREAM_NODIRECTION; - s->name = pa_xstrdup(name); - s->sample_spec = *ss; - s->flags = 0; - - if (map) - s->channel_map = *map; - else - pa_channel_map_init_auto(&s->channel_map, ss->channels, PA_CHANNEL_MAP_DEFAULT); - - s->channel = 0; - s->channel_valid = 0; - s->syncid = c->csyncid++; - s->device_index = PA_INVALID_INDEX; - s->requested_bytes = 0; - s->state = PA_STREAM_UNCONNECTED; - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->peek_memchunk.index = 0; - s->peek_memchunk.length = 0; - s->peek_memchunk.memblock = NULL; - - s->record_memblockq = NULL; - - s->previous_time = 0; - s->timing_info_valid = 0; - s->read_index_not_before = 0; - s->write_index_not_before = 0; - - for (i = 0; i < PA_MAX_WRITE_INDEX_CORRECTIONS; i++) - s->write_index_corrections[i].valid = 0; - s->current_write_index_correction = 0; - - s->corked = 0; - - s->cached_time_valid = 0; - - s->auto_timing_update_event = NULL; - s->auto_timing_update_requested = 0; - - /* Refcounting is strictly one-way: from the "bigger" to the "smaller" object. */ - PA_LLIST_PREPEND(pa_stream, c->streams, s); - pa_stream_ref(s); - - return s; -} - -static void stream_free(pa_stream *s) { - assert(s && !s->context && !s->channel_valid); - - if (s->auto_timing_update_event) { - assert(s->mainloop); - s->mainloop->time_free(s->auto_timing_update_event); - } - - if (s->peek_memchunk.memblock) - pa_memblock_unref(s->peek_memchunk.memblock); - - if (s->record_memblockq) - pa_memblockq_free(s->record_memblockq); - - pa_xfree(s->name); - pa_xfree(s); -} - -void pa_stream_unref(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - if (--(s->ref) == 0) - stream_free(s); -} - -pa_stream* pa_stream_ref(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - s->ref++; - return s; -} - -pa_stream_state_t pa_stream_get_state(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - return s->state; -} - -pa_context* pa_stream_get_context(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - return s->context; -} - -uint32_t pa_stream_get_index(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX); - - return s->device_index; -} - -void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { - assert(s); - assert(s->ref >= 1); - - if (s->state == st) - return; - - pa_stream_ref(s); - - s->state = st; - if (s->state_callback) - s->state_callback(s, s->state_userdata); - - if ((st == PA_STREAM_FAILED || st == PA_STREAM_TERMINATED) && s->context) { - - /* Detach from context */ - pa_operation *o, *n; - - /* Unref all operatio object that point to us */ - for (o = s->context->operations; o; o = n) { - n = o->next; - - if (o->stream == s) - pa_operation_cancel(o); - } - - /* Drop all outstanding replies for this stream */ - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - PA_LLIST_REMOVE(pa_stream, s->context->streams, s); - pa_stream_unref(s); - - s->channel = 0; - s->channel_valid = 0; - - s->context = NULL; - } - - pa_stream_unref(s); -} - -void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_context *c = userdata; - pa_stream *s; - uint32_t channel; - - assert(pd); - assert(command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED); - assert(t); - assert(c); - - pa_context_ref(c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(c, PA_ERR_PROTOCOL); - goto finish; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - goto finish; - - pa_context_set_error(c, PA_ERR_KILLED); - pa_stream_set_state(s, PA_STREAM_FAILED); - -finish: - pa_context_unref(c); -} - -void pa_command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_stream *s; - pa_context *c = userdata; - uint32_t bytes, channel; - - assert(pd); - assert(command == PA_COMMAND_REQUEST); - assert(t); - assert(c); - - pa_context_ref(c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(c, PA_ERR_PROTOCOL); - goto finish; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - goto finish; - - if (s->state == PA_STREAM_READY) { - s->requested_bytes += bytes; - - if (s->requested_bytes > 0 && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); - } - -finish: - pa_context_unref(c); -} - -void pa_command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_stream *s; - pa_context *c = userdata; - uint32_t channel; - - assert(pd); - assert(command == PA_COMMAND_OVERFLOW || command == PA_COMMAND_UNDERFLOW); - assert(t); - assert(c); - - pa_context_ref(c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(c, PA_ERR_PROTOCOL); - goto finish; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - goto finish; - - if (s->state == PA_STREAM_READY) { - - if (command == PA_COMMAND_OVERFLOW) { - if (s->overflow_callback) - s->overflow_callback(s, s->overflow_userdata); - } else if (command == PA_COMMAND_UNDERFLOW) { - if (s->underflow_callback) - s->underflow_callback(s, s->underflow_userdata); - } - } - - finish: - pa_context_unref(c); -} - -static void request_auto_timing_update(pa_stream *s, int force) { - struct timeval next; - assert(s); - - if (!(s->flags & PA_STREAM_AUTO_TIMING_UPDATE)) - return; - - if (s->state == PA_STREAM_READY && - (force || !s->auto_timing_update_requested)) { - pa_operation *o; - -/* pa_log("automatically requesting new timing data"); */ - - if ((o = pa_stream_update_timing_info(s, NULL, NULL))) { - pa_operation_unref(o); - s->auto_timing_update_requested = 1; - } - } - - pa_gettimeofday(&next); - pa_timeval_add(&next, LATENCY_IPOL_INTERVAL_USEC); - s->mainloop->time_restart(s->auto_timing_update_event, &next); -} - -static void invalidate_indexes(pa_stream *s, int r, int w) { - assert(s); - -/* pa_log("invalidate r:%u w:%u tag:%u", r, w, s->context->ctag); */ - - if (s->state != PA_STREAM_READY) - return; - - if (w) { - s->write_index_not_before = s->context->ctag; - - if (s->timing_info_valid) - s->timing_info.write_index_corrupt = 1; - -/* pa_log("write_index invalidated"); */ - } - - if (r) { - s->read_index_not_before = s->context->ctag; - - if (s->timing_info_valid) - s->timing_info.read_index_corrupt = 1; - -/* pa_log("read_index invalidated"); */ - } - - if ((s->direction == PA_STREAM_PLAYBACK && r) || - (s->direction == PA_STREAM_RECORD && w)) - s->cached_time_valid = 0; - - request_auto_timing_update(s, 1); -} - -static void auto_timing_update_callback(PA_GCC_UNUSED pa_mainloop_api *m, PA_GCC_UNUSED pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - pa_stream *s = userdata; - -/* pa_log("time event"); */ - - pa_stream_ref(s); - request_auto_timing_update(s, 0); - pa_stream_unref(s); -} - -void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_stream *s = userdata; - - assert(pd); - assert(s); - assert(s->state == PA_STREAM_CREATING); - - pa_stream_ref(s); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(s->context, command, t) < 0) - goto finish; - - pa_stream_set_state(s, PA_STREAM_FAILED); - goto finish; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - ((s->direction != PA_STREAM_RECORD) && pa_tagstruct_getu32(t, &s->requested_bytes) < 0)) { - pa_context_fail(s->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (pa_context_get_server_protocol_version(s->context) >= 9) { - if (s->direction == PA_STREAM_PLAYBACK) { - if (pa_tagstruct_getu32(t, &s->buffer_attr.maxlength) < 0 || - pa_tagstruct_getu32(t, &s->buffer_attr.tlength) < 0 || - pa_tagstruct_getu32(t, &s->buffer_attr.prebuf) < 0 || - pa_tagstruct_getu32(t, &s->buffer_attr.minreq) < 0) { - pa_context_fail(s->context, PA_ERR_PROTOCOL); - goto finish; - } - } else if (s->direction == PA_STREAM_RECORD) { - if (pa_tagstruct_getu32(t, &s->buffer_attr.maxlength) < 0 || - pa_tagstruct_getu32(t, &s->buffer_attr.fragsize) < 0) { - pa_context_fail(s->context, PA_ERR_PROTOCOL); - goto finish; - } - } - } - - if (!pa_tagstruct_eof(t)) { - pa_context_fail(s->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (s->direction == PA_STREAM_RECORD) { - assert(!s->record_memblockq); - - s->record_memblockq = pa_memblockq_new( - 0, - s->buffer_attr.maxlength, - 0, - pa_frame_size(&s->sample_spec), - 1, - 0, - NULL, - s->context->memblock_stat); - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - - pa_stream_set_state(s, PA_STREAM_READY); - - if (s->direction != PA_STREAM_UPLOAD && - s->flags & PA_STREAM_AUTO_TIMING_UPDATE) { - struct timeval tv; - - pa_gettimeofday(&tv); - tv.tv_usec += LATENCY_IPOL_INTERVAL_USEC; /* every 100 ms */ - - assert(!s->auto_timing_update_event); - s->auto_timing_update_event = s->mainloop->time_new(s->mainloop, &tv, &auto_timing_update_callback, s); - - request_auto_timing_update(s, 1); - } - - if (s->requested_bytes > 0 && s->ref > 1 && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); - -finish: - pa_stream_unref(s); -} - -static int create_stream( - pa_stream_direction_t direction, - pa_stream *s, - const char *dev, - const pa_buffer_attr *attr, - pa_stream_flags_t flags, - const pa_cvolume *volume, - pa_stream *sync_stream) { - - pa_tagstruct *t; - uint32_t tag; - - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, !(flags & ~((direction != PA_STREAM_UPLOAD ? - PA_STREAM_START_CORKED| - PA_STREAM_INTERPOLATE_TIMING| - PA_STREAM_NOT_MONOTONOUS| - PA_STREAM_AUTO_TIMING_UPDATE : 0))), PA_ERR_INVALID); - PA_CHECK_VALIDITY(s->context, !volume || volume->channels == s->sample_spec.channels, PA_ERR_INVALID); - PA_CHECK_VALIDITY(s->context, !sync_stream || (direction == PA_STREAM_PLAYBACK && sync_stream->direction == PA_STREAM_PLAYBACK), PA_ERR_INVALID); - - pa_stream_ref(s); - - s->direction = direction; - s->flags = flags; - - if (sync_stream) - s->syncid = sync_stream->syncid; - - if (attr) - s->buffer_attr = *attr; - else { - /* half a second */ - s->buffer_attr.tlength = pa_bytes_per_second(&s->sample_spec)/2; - s->buffer_attr.maxlength = (s->buffer_attr.tlength*3)/2; - s->buffer_attr.minreq = s->buffer_attr.tlength/100; - s->buffer_attr.prebuf = s->buffer_attr.tlength - s->buffer_attr.minreq; - s->buffer_attr.fragsize = s->buffer_attr.tlength/100; - } - - if (!dev) - dev = s->direction == PA_STREAM_PLAYBACK ? s->context->conf->default_sink : s->context->conf->default_source; - - t = pa_tagstruct_command( - s->context, - s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM, - &tag); - - pa_tagstruct_put( - t, - PA_TAG_STRING, s->name, - PA_TAG_SAMPLE_SPEC, &s->sample_spec, - PA_TAG_CHANNEL_MAP, &s->channel_map, - PA_TAG_U32, PA_INVALID_INDEX, - PA_TAG_STRING, dev, - PA_TAG_U32, s->buffer_attr.maxlength, - PA_TAG_BOOLEAN, !!(flags & PA_STREAM_START_CORKED), - PA_TAG_INVALID); - - if (s->direction == PA_STREAM_PLAYBACK) { - pa_cvolume cv; - - pa_tagstruct_put( - t, - PA_TAG_U32, s->buffer_attr.tlength, - PA_TAG_U32, s->buffer_attr.prebuf, - PA_TAG_U32, s->buffer_attr.minreq, - PA_TAG_U32, s->syncid, - PA_TAG_INVALID); - - if (!volume) - volume = pa_cvolume_reset(&cv, s->sample_spec.channels); - - pa_tagstruct_put_cvolume(t, volume); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL); - - pa_stream_set_state(s, PA_STREAM_CREATING); - - pa_stream_unref(s); - return 0; -} - -int pa_stream_connect_playback( - pa_stream *s, - const char *dev, - const pa_buffer_attr *attr, - pa_stream_flags_t flags, - pa_cvolume *volume, - pa_stream *sync_stream) { - - assert(s); - assert(s->ref >= 1); - - return create_stream(PA_STREAM_PLAYBACK, s, dev, attr, flags, volume, sync_stream); -} - -int pa_stream_connect_record( - pa_stream *s, - const char *dev, - const pa_buffer_attr *attr, - pa_stream_flags_t flags) { - - assert(s); - assert(s->ref >= 1); - - return create_stream(PA_STREAM_RECORD, s, dev, attr, flags, NULL, NULL); -} - -int pa_stream_write( - pa_stream *s, - const void *data, - size_t length, - void (*free_cb)(void *p), - int64_t offset, - pa_seek_mode_t seek) { - - pa_memchunk chunk; - - assert(s); - assert(s->ref >= 1); - assert(data); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, seek <= PA_SEEK_RELATIVE_END, PA_ERR_INVALID); - PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || (seek == PA_SEEK_RELATIVE && offset == 0), PA_ERR_INVALID); - - if (length <= 0) - return 0; - - if (free_cb) - chunk.memblock = pa_memblock_new_user((void*) data, length, free_cb, 1, s->context->memblock_stat); - else { - chunk.memblock = pa_memblock_new(length, s->context->memblock_stat); - memcpy(chunk.memblock->data, data, length); - } - - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, offset, seek, &chunk); - pa_memblock_unref(chunk.memblock); - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; - - if (s->direction == PA_STREAM_PLAYBACK) { - - /* Update latency request correction */ - if (s->write_index_corrections[s->current_write_index_correction].valid) { - - if (seek == PA_SEEK_ABSOLUTE) { - s->write_index_corrections[s->current_write_index_correction].corrupt = 0; - s->write_index_corrections[s->current_write_index_correction].absolute = 1; - s->write_index_corrections[s->current_write_index_correction].value = offset + length; - } else if (seek == PA_SEEK_RELATIVE) { - if (!s->write_index_corrections[s->current_write_index_correction].corrupt) - s->write_index_corrections[s->current_write_index_correction].value += offset + length; - } else - s->write_index_corrections[s->current_write_index_correction].corrupt = 1; - } - - /* Update the write index in the already available latency data */ - if (s->timing_info_valid) { - - if (seek == PA_SEEK_ABSOLUTE) { - s->timing_info.write_index_corrupt = 0; - s->timing_info.write_index = offset + length; - } else if (seek == PA_SEEK_RELATIVE) { - if (!s->timing_info.write_index_corrupt) - s->timing_info.write_index += offset + length; - } else - s->timing_info.write_index_corrupt = 1; - } - - if (!s->timing_info_valid || s->timing_info.write_index_corrupt) - request_auto_timing_update(s, 1); - } - - return 0; -} - -int pa_stream_peek(pa_stream *s, const void **data, size_t *length) { - assert(s); - assert(s->ref >= 1); - assert(data); - assert(length); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE); - - if (!s->peek_memchunk.memblock) { - - if (pa_memblockq_peek(s->record_memblockq, &s->peek_memchunk) < 0) { - *data = NULL; - *length = 0; - return 0; - } - } - - *data = (const char*) s->peek_memchunk.memblock->data + s->peek_memchunk.index; - *length = s->peek_memchunk.length; - return 0; -} - -int pa_stream_drop(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->peek_memchunk.memblock, PA_ERR_BADSTATE); - - pa_memblockq_drop(s->record_memblockq, &s->peek_memchunk, s->peek_memchunk.length); - - /* Fix the simulated local read index */ - if (s->timing_info_valid && !s->timing_info.read_index_corrupt) - s->timing_info.read_index += s->peek_memchunk.length; - - pa_memblock_unref(s->peek_memchunk.memblock); - s->peek_memchunk.length = 0; - s->peek_memchunk.index = 0; - s->peek_memchunk.memblock = NULL; - - return 0; -} - -size_t pa_stream_writable_size(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (size_t) -1); - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_RECORD, PA_ERR_BADSTATE, (size_t) -1); - - return s->requested_bytes; -} - -size_t pa_stream_readable_size(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (size_t) -1); - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, (size_t) -1); - - return pa_memblockq_get_length(s->record_memblockq); -} - -pa_operation * pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); - - o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(s->context, PA_COMMAND_DRAIN_PLAYBACK_STREAM, &tag); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - struct timeval local, remote, now; - pa_timing_info *i; - - assert(pd); - assert(o); - - if (!o->context || !o->stream) - goto finish; - - i = &o->stream->timing_info; - -/* pa_log("pre corrupt w:%u r:%u\n", !o->stream->timing_info_valid || i->write_index_corrupt,!o->stream->timing_info_valid || i->read_index_corrupt); */ - - o->stream->timing_info_valid = 0; - i->write_index_corrupt = 0; - i->read_index_corrupt = 0; - -/* pa_log("timing update %u\n", tag); */ - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - } else if (pa_tagstruct_get_usec(t, &i->sink_usec) < 0 || - pa_tagstruct_get_usec(t, &i->source_usec) < 0 || - pa_tagstruct_get_boolean(t, &i->playing) < 0 || - pa_tagstruct_get_timeval(t, &local) < 0 || - pa_tagstruct_get_timeval(t, &remote) < 0 || - pa_tagstruct_gets64(t, &i->write_index) < 0 || - pa_tagstruct_gets64(t, &i->read_index) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - - } else { - o->stream->timing_info_valid = 1; - - pa_gettimeofday(&now); - - /* Calculcate timestamps */ - if (pa_timeval_cmp(&local, &remote) <= 0 && pa_timeval_cmp(&remote, &now) <= 0) { - /* local and remote seem to have synchronized clocks */ - - if (o->stream->direction == PA_STREAM_PLAYBACK) - i->transport_usec = pa_timeval_diff(&remote, &local); - else - i->transport_usec = pa_timeval_diff(&now, &remote); - - i->synchronized_clocks = 1; - i->timestamp = remote; - } else { - /* clocks are not synchronized, let's estimate latency then */ - i->transport_usec = pa_timeval_diff(&now, &local)/2; - i->synchronized_clocks = 0; - i->timestamp = local; - pa_timeval_add(&i->timestamp, i->transport_usec); - } - - /* Invalidate read and write indexes if necessary */ - if (tag < o->stream->read_index_not_before) - i->read_index_corrupt = 1; - - if (tag < o->stream->write_index_not_before) - i->write_index_corrupt = 1; - - if (o->stream->direction == PA_STREAM_PLAYBACK) { - /* Write index correction */ - - int n, j; - uint32_t ctag = tag; - - /* Go through the saved correction values and add up the total correction.*/ - - for (n = 0, j = o->stream->current_write_index_correction+1; - n < PA_MAX_WRITE_INDEX_CORRECTIONS; - n++, j = (j + 1) % PA_MAX_WRITE_INDEX_CORRECTIONS) { - - /* Step over invalid data or out-of-date data */ - if (!o->stream->write_index_corrections[j].valid || - o->stream->write_index_corrections[j].tag < ctag) - continue; - - /* Make sure that everything is in order */ - ctag = o->stream->write_index_corrections[j].tag+1; - - /* Now fix the write index */ - if (o->stream->write_index_corrections[j].corrupt) { - /* A corrupting seek was made */ - i->write_index = 0; - i->write_index_corrupt = 1; - } else if (o->stream->write_index_corrections[j].absolute) { - /* An absolute seek was made */ - i->write_index = o->stream->write_index_corrections[j].value; - i->write_index_corrupt = 0; - } else if (!i->write_index_corrupt) { - /* A relative seek was made */ - i->write_index += o->stream->write_index_corrections[j].value; - } - } - } - - if (o->stream->direction == PA_STREAM_RECORD) { - /* Read index correction */ - - if (!i->read_index_corrupt) - i->read_index -= pa_memblockq_get_length(o->stream->record_memblockq); - } - - o->stream->cached_time_valid = 0; - } - - o->stream->auto_timing_update_requested = 0; -/* pa_log("post corrupt w:%u r:%u\n", i->write_index_corrupt || !o->stream->timing_info_valid, i->read_index_corrupt || !o->stream->timing_info_valid); */ - - /* Clear old correction entries */ - if (o->stream->direction == PA_STREAM_PLAYBACK) { - int n; - - for (n = 0; n < PA_MAX_WRITE_INDEX_CORRECTIONS; n++) { - if (!o->stream->write_index_corrections[n].valid) - continue; - - if (o->stream->write_index_corrections[n].tag <= tag) - o->stream->write_index_corrections[n].valid = 0; - } - } - - if (o->stream->latency_update_callback) - o->stream->latency_update_callback(o->stream, o->stream->latency_update_userdata); - - if (o->callback && o->stream && o->stream->state == PA_STREAM_READY) { - pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback; - cb(o->stream, o->stream->timing_info_valid, o->userdata); - } - -finish: - - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { - uint32_t tag; - pa_operation *o; - pa_tagstruct *t; - struct timeval now; - int cidx = 0; - - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - if (s->direction == PA_STREAM_PLAYBACK) { - /* Find a place to store the write_index correction data for this entry */ - cidx = (s->current_write_index_correction + 1) % PA_MAX_WRITE_INDEX_CORRECTIONS; - - /* Check if we could allocate a correction slot. If not, there are too many outstanding queries */ - PA_CHECK_VALIDITY_RETURN_NULL(s->context, !s->write_index_corrections[cidx].valid, PA_ERR_INTERNAL); - } - o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command( - s->context, - s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_GET_PLAYBACK_LATENCY : PA_COMMAND_GET_RECORD_LATENCY, - &tag); - pa_tagstruct_putu32(t, s->channel); - pa_tagstruct_put_timeval(t, pa_gettimeofday(&now)); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_timing_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - if (s->direction == PA_STREAM_PLAYBACK) { - /* Fill in initial correction data */ - o->stream->current_write_index_correction = cidx; - o->stream->write_index_corrections[cidx].valid = 1; - o->stream->write_index_corrections[cidx].tag = tag; - o->stream->write_index_corrections[cidx].absolute = 0; - o->stream->write_index_corrections[cidx].value = 0; - o->stream->write_index_corrections[cidx].corrupt = 0; - } - -/* pa_log("requesting update %u\n", tag); */ - - return o; -} - -void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_stream *s = userdata; - - assert(pd); - assert(s); - assert(s->ref >= 1); - - pa_stream_ref(s); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(s->context, command, t) < 0) - goto finish; - - pa_stream_set_state(s, PA_STREAM_FAILED); - goto finish; - } else if (!pa_tagstruct_eof(t)) { - pa_context_fail(s->context, PA_ERR_PROTOCOL); - goto finish; - } - - pa_stream_set_state(s, PA_STREAM_TERMINATED); - -finish: - pa_stream_unref(s); -} - -int pa_stream_disconnect(pa_stream *s) { - pa_tagstruct *t; - uint32_t tag; - - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY(s->context, s->channel_valid, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pa_stream_ref(s); - - t = pa_tagstruct_command( - s->context, - s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM), - &tag); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s, NULL); - - pa_stream_unref(s); - return 0; -} - -void pa_stream_set_read_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) { - assert(s); - assert(s->ref >= 1); - - s->read_callback = cb; - s->read_userdata = userdata; -} - -void pa_stream_set_write_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) { - assert(s); - assert(s->ref >= 1); - - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { - assert(s); - assert(s->ref >= 1); - - s->state_callback = cb; - s->state_userdata = userdata; -} - -void pa_stream_set_overflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { - assert(s); - assert(s->ref >= 1); - - s->overflow_callback = cb; - s->overflow_userdata = userdata; -} - -void pa_stream_set_underflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { - assert(s); - assert(s->ref >= 1); - - s->underflow_callback = cb; - s->underflow_userdata = userdata; -} - -void pa_stream_set_latency_update_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { - assert(s); - assert(s->ref >= 1); - - s->latency_update_callback = cb; - s->latency_update_userdata = userdata; -} - -void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int success = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - success = 0; - } else if (!pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback; - cb(o->stream, success, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - s->corked = b; - - o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command( - s->context, - s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CORK_PLAYBACK_STREAM : PA_COMMAND_CORK_RECORD_STREAM, - &tag); - pa_tagstruct_putu32(t, s->channel); - pa_tagstruct_put_boolean(t, !!b); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - if (s->direction == PA_STREAM_PLAYBACK) - invalidate_indexes(s, 1, 0); - - return o; -} - -static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, pa_stream_success_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(s->context, command, &tag); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { - pa_operation *o; - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - if ((o = stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata))) { - - if (s->direction == PA_STREAM_PLAYBACK) { - if (s->write_index_corrections[s->current_write_index_correction].valid) - s->write_index_corrections[s->current_write_index_correction].corrupt = 1; - - if (s->timing_info_valid) - s->timing_info.write_index_corrupt = 1; - - if (s->buffer_attr.prebuf > 0) - invalidate_indexes(s, 1, 0); - else - request_auto_timing_update(s, 1); - } else - invalidate_indexes(s, 0, 1); - } - - return o; -} - -pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { - pa_operation *o; - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE); - - if ((o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata))) - invalidate_indexes(s, 1, 0); - - return o; -} - -pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { - pa_operation *o; - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE); - - if ((o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata))) - invalidate_indexes(s, 1, 0); - - return o; -} - -pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(s); - assert(s->ref >= 1); - assert(name); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command( - s->context, - s->direction == PA_STREAM_RECORD ? PA_COMMAND_SET_RECORD_STREAM_NAME : PA_COMMAND_SET_PLAYBACK_STREAM_NAME, - &tag); - pa_tagstruct_putu32(t, s->channel); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) { - pa_usec_t usec = 0; - - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->timing_info_valid, PA_ERR_NODATA); - PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_PLAYBACK || !s->timing_info.read_index_corrupt, PA_ERR_NODATA); - PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_RECORD || !s->timing_info.write_index_corrupt, PA_ERR_NODATA); - - if (s->cached_time_valid) - /* We alredy calculated the time value for this timing info, so let's reuse it */ - usec = s->cached_time; - else { - if (s->direction == PA_STREAM_PLAYBACK) { - /* The last byte that was written into the output device - * had this time value associated */ - usec = pa_bytes_to_usec(s->timing_info.read_index < 0 ? 0 : (uint64_t) s->timing_info.read_index, &s->sample_spec); - - if (!s->corked) { - /* Because the latency info took a little time to come - * to us, we assume that the real output time is actually - * a little ahead */ - usec += s->timing_info.transport_usec; - - /* However, the output device usually maintains a buffer - too, hence the real sample currently played is a little - back */ - if (s->timing_info.sink_usec >= usec) - usec = 0; - else - usec -= s->timing_info.sink_usec; - } - - } else if (s->direction == PA_STREAM_RECORD) { - /* The last byte written into the server side queue had - * this time value associated */ - usec = pa_bytes_to_usec(s->timing_info.write_index < 0 ? 0 : (uint64_t) s->timing_info.write_index, &s->sample_spec); - - if (!s->corked) { - /* Add transport latency */ - usec += s->timing_info.transport_usec; - - /* Add latency of data in device buffer */ - usec += s->timing_info.source_usec; - - /* If this is a monitor source, we need to correct the - * time by the playback device buffer */ - if (s->timing_info.sink_usec >= usec) - usec = 0; - else - usec -= s->timing_info.sink_usec; - } - } - - s->cached_time = usec; - s->cached_time_valid = 1; - } - - /* Interpolate if requested */ - if (s->flags & PA_STREAM_INTERPOLATE_TIMING) { - - /* We just add the time that passed since the latency info was - * current */ - if (!s->corked) { - struct timeval now; - usec += pa_timeval_diff(pa_gettimeofday(&now), &s->timing_info.timestamp); - } - } - - /* Make sure the time runs monotonically */ - if (!(s->flags & PA_STREAM_NOT_MONOTONOUS)) { - if (usec < s->previous_time) - usec = s->previous_time; - else - s->previous_time = usec; - } - - if (r_usec) - *r_usec = usec; - - return 0; -} - -static pa_usec_t time_counter_diff(pa_stream *s, pa_usec_t a, pa_usec_t b, int *negative) { - assert(s); - assert(s->ref >= 1); - - if (negative) - *negative = 0; - - if (a >= b) - return a-b; - else { - if (negative && s->direction == PA_STREAM_RECORD) { - *negative = 1; - return b-a; - } else - return 0; - } -} - -int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative) { - pa_usec_t t, c; - int r; - int64_t cindex; - - assert(s); - assert(s->ref >= 1); - assert(r_usec); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->timing_info_valid, PA_ERR_NODATA); - PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_PLAYBACK || !s->timing_info.write_index_corrupt, PA_ERR_NODATA); - PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_RECORD || !s->timing_info.read_index_corrupt, PA_ERR_NODATA); - - if ((r = pa_stream_get_time(s, &t)) < 0) - return r; - - if (s->direction == PA_STREAM_PLAYBACK) - cindex = s->timing_info.write_index; - else - cindex = s->timing_info.read_index; - - if (cindex < 0) - cindex = 0; - - c = pa_bytes_to_usec(cindex, &s->sample_spec); - - if (s->direction == PA_STREAM_PLAYBACK) - *r_usec = time_counter_diff(s, c, t, negative); - else - *r_usec = time_counter_diff(s, t, c, negative); - - return 0; -} - -const pa_timing_info* pa_stream_get_timing_info(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->timing_info_valid, PA_ERR_BADSTATE); - - return &s->timing_info; -} - -const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - return &s->sample_spec; -} - -const pa_channel_map* pa_stream_get_channel_map(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - return &s->channel_map; -} - -const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, - pa_context_get_server_protocol_version(s->context) >= 9, PA_ERR_NODATA); - - return &s->buffer_attr; -} diff --git a/src/polyp/stream.h b/src/polyp/stream.h deleted file mode 100644 index d1f558ae..00000000 --- a/src/polyp/stream.h +++ /dev/null @@ -1,449 +0,0 @@ -#ifndef foostreamhfoo -#define foostreamhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include -#include -#include -#include -#include -#include - -/** \page streams Audio Streams - * - * \section overv_sec Overview - * - * Audio streams form the central functionality of the sound server. Data is - * routed, converted and mixed from several sources before it is passed along - * to a final output. Currently, there are three forms of audio streams: - * - * \li Playback streams - Data flows from the client to the server. - * \li Record streams - Data flows from the server to the client. - * \li Upload streams - Similar to playback streams, but the data is stored in - * the sample cache. See \ref scache for more information - * about controlling the sample cache. - * - * \section create_sec Creating - * - * To access a stream, a pa_stream object must be created using - * pa_stream_new(). At this point the audio sample format and mapping of - * channels must be specified. See \ref sample and \ref channelmap for more - * information about those structures. - * - * This first step will only create a client-side object, representing the - * stream. To use the stream, a server-side object must be created and - * associated with the local object. Depending on which type of stream is - * desired, a different function is needed: - * - * \li Playback stream - pa_stream_connect_playback() - * \li Record stream - pa_stream_connect_record() - * \li Upload stream - pa_stream_connect_upload() (see \ref scache) - * - * Similar to how connections are done in contexts, connecting a stream will - * not generate a pa_operation object. Also like contexts, the application - * should register a state change callback, using - * pa_stream_set_state_callback(), and wait for the stream to enter an active - * state. - * - * \subsection bufattr_subsec Buffer Attributes - * - * Playback and record streams always have a server side buffer as - * part of the data flow. The size of this buffer strikes a - * compromise between low latency and sensitivity for buffer - * overflows/underruns. - * - * The buffer metrics may be controlled by the application. They are - * described with a pa_buffer_attr structure which contains a number - * of fields: - * - * \li maxlength - The absolute maximum number of bytes that can be stored in - * the buffer. If this value is exceeded then data will be - * lost. - * \li tlength - The target length of a playback buffer. The server will only - * send requests for more data as long as the buffer has less - * than this number of bytes of data. - * \li prebuf - Number of bytes that need to be in the buffer before - * playback will commence. Start of playback can be forced using - * pa_stream_trigger() even though the prebuffer size hasn't been - * reached. If a buffer underrun occurs, this prebuffering will be - * again enabled. If the playback shall never stop in case of a buffer - * underrun, this value should be set to 0. In that case the read - * index of the output buffer overtakes the write index, and hence the - * fill level of the buffer is negative. - * \li minreq - Minimum free number of the bytes in the playback buffer before - * the server will request more data. - * \li fragsize - Maximum number of bytes that the server will push in one - * chunk for record streams. - * - * The server side playback buffers are indexed by a write and a read - * index. The application writes to the write index and the sound - * device reads from the read index. The read index is increased - * monotonically, while the write index may be freely controlled by - * the application. Substracting the read index from the write index - * will give you the current fill level of the buffer. The read/write - * indexes are 64bit values and measured in bytes, they will never - * wrap. The current read/write index may be queried using - * pa_stream_get_timing_info() (see below for more information). In - * case of a buffer underrun the read index is equal or larger than - * the write index. Unless the prebuf value is 0, Polypaudio will - * temporarily pause playback in such a case, and wait until the - * buffer is filled up to prebuf bytes again. If prebuf is 0, the - * read index may be larger than the write index, in which case - * silence is played. If the application writes data to indexes lower - * than the read index, the data is immediately lost. - * - * \section transfer_sec Transferring Data - * - * Once the stream is up, data can start flowing between the client and the - * server. Two different access models can be used to transfer the data: - * - * \li Asynchronous - The application register a callback using - * pa_stream_set_write_callback() and - * pa_stream_set_read_callback() to receive notifications - * that data can either be written or read. - * \li Polled - Query the library for available data/space using - * pa_stream_writable_size() and pa_stream_readable_size() and - * transfer data as needed. The sizes are stored locally, in the - * client end, so there is no delay when reading them. - * - * It is also possible to mix the two models freely. - * - * Once there is data/space available, it can be transferred using either - * pa_stream_write() for playback, or pa_stream_peek() / pa_stream_drop() for - * record. Make sure you do not overflow the playback buffers as data will be - * dropped. - * - * \section bufctl_sec Buffer Control - * - * The transfer buffers can be controlled through a number of operations: - * - * \li pa_stream_cork() - Start or stop the playback or recording. - * \li pa_stream_trigger() - Start playback immediatly and do not wait for - * the buffer to fill up to the set trigger level. - * \li pa_stream_prebuf() - Reenable the playback trigger level. - * \li pa_stream_drain() - Wait for the playback buffer to go empty. Will - * return a pa_operation object that will indicate when - * the buffer is completely drained. - * \li pa_stream_flush() - Drop all data from the playback buffer and do not - * wait for it to finish playing. - * - * \section seek_modes Seeking in the Playback Buffer - * - * A client application may freely seek in the playback buffer. To - * accomplish that the pa_stream_write() function takes a seek mode - * and an offset argument. The seek mode is one of: - * - * \li PA_SEEK_RELATIVE - seek relative to the current write index - * \li PA_SEEK_ABSOLUTE - seek relative to the beginning of the playback buffer, (i.e. the first that was ever played in the stream) - * \li PA_SEEK_RELATIVE_ON_READ - seek relative to the current read index. Use this to write data to the output buffer that should be played as soon as possible - * \li PA_SEEK_RELATIVE_END - seek relative to the last byte ever written. - * - * If an application just wants to append some data to the output - * buffer, PA_SEEK_RELATIVE and an offset of 0 should be used. - * - * After a call to pa_stream_write() the write index will be left at - * the position right after the last byte of the written data. - * - * \section latency_sec Latency - * - * A major problem with networked audio is the increased latency caused by - * the network. To remedy this, Polypaudio supports an advanced system of - * monitoring the current latency. - * - * To get the raw data needed to calculate latencies, call - * pa_stream_get_timing_info(). This will give you a pa_timing_info - * structure that contains everything that is known about the server - * side buffer transport delays and the backend active in the - * server. (Besides other things it contains the write and read index - * values mentioned above.) - * - * This structure is updated every time a - * pa_stream_update_timing_info() operation is executed. (i.e. before - * the first call to this function the timing information structure is - * not available!) Since it is a lot of work to keep this structure - * up-to-date manually, Polypaudio can do that automatically for you: - * if PA_STREAM_AUTO_TIMING_UPDATE is passed when connecting the - * stream Polypaudio will automatically update the structure every - * 100ms and every time a function is called that might invalidate the - * previously known timing data (such as pa_stream_write() or - * pa_stream_flush()). Please note however, that there always is a - * short time window when the data in the timing information structure - * is out-of-date. Polypaudio tries to mark these situations by - * setting the write_index_corrupt and read_index_corrupt fields - * accordingly. - * - * The raw timing data in the pa_timing_info structure is usually hard - * to deal with. Therefore a more simplistic interface is available: - * you can call pa_stream_get_time() or pa_stream_get_latency(). The - * former will return the current playback time of the hardware since - * the stream has been started. The latter returns the time a sample - * that you write now takes to be played by the hardware. These two - * functions base their calculations on the same data that is returned - * by pa_stream_get_timing_info(). Hence the same rules for keeping - * the timing data up-to-date apply here. In case the write or read - * index is corrupted, these two functions will fail with - * PA_ERR_NODATA set. - * - * Since updating the timing info structure usually requires a full - * network round trip and some applications monitor the timing very - * often Polypaudio offers a timing interpolation system. If - * PA_STREAM_INTERPOLATE_TIMING is passed when connecting the stream, - * pa_stream_get_time() and pa_stream_get_latency() will try to - * interpolate the current playback time/latency by estimating the - * number of samples that have been played back by the hardware since - * the last regular timing update. It is espcially useful to combine - * this option with PA_STREAM_AUTO_TIMING_UPDATE, which will enable - * you to monitor the current playback time/latency very precisely and - * very frequently without requiring a network round trip every time. - * - * \section flow_sec Overflow and underflow - * - * Even with the best precautions, buffers will sometime over - or - * underflow. To handle this gracefully, the application can be - * notified when this happens. Callbacks are registered using - * pa_stream_set_overflow_callback() and - * pa_stream_set_underflow_callback(). - * - * \section sync_streams Sychronizing Multiple Playback Streams - * - * Polypaudio allows applications to fully synchronize multiple - * playback streams that are connected to the same output device. That - * means the streams will always be played back sample-by-sample - * synchronously. If stream operations like pa_stream_cork() are - * issued on one of the synchronized streams, they are simultaneously - * issued on the others. - * - * To synchronize a stream to another, just pass the "master" stream - * as last argument to pa_stream_connect_playack(). To make sure that - * the freshly created stream doesn't start playback right-away, make - * sure to pass PA_STREAM_START_CORKED and - after all streams have - * been created - uncork them all with a single call to - * pa_stream_cork() for the master stream. - * - * To make sure that a particular stream doesn't stop to play when a - * server side buffer underrun happens on it while the other - * synchronized streams continue playing and hence deviate you need to - * pass a "prebuf" pa_buffer_attr of 0 when connecting it. - * - * \section disc_sec Disconnecting - * - * When a stream has served is purpose it must be disconnected with - * pa_stream_disconnect(). If you only unreference it, then it will live on - * and eat resources both locally and on the server until you disconnect the - * context. - * - */ - -/** \file - * Audio streams for input, output and sample upload */ - -PA_C_DECL_BEGIN - -/** An opaque stream for playback or recording */ -typedef struct pa_stream pa_stream; - -/** A generic callback for operation completion */ -typedef void (*pa_stream_success_cb_t) (pa_stream*s, int success, void *userdata); - -/** A generic request callback */ -typedef void (*pa_stream_request_cb_t)(pa_stream *p, size_t length, void *userdata); - -/** A generic notification callback */ -typedef void (*pa_stream_notify_cb_t)(pa_stream *p, void *userdata); - -/** Create a new, unconnected stream with the specified name and sample type */ -pa_stream* pa_stream_new( - pa_context *c /**< The context to create this stream in */, - const char *name /**< A name for this stream */, - const pa_sample_spec *ss /**< The desired sample format */, - const pa_channel_map *map /**< The desired channel map, or NULL for default */); - -/** Decrease the reference counter by one */ -void pa_stream_unref(pa_stream *s); - -/** Increase the reference counter by one */ -pa_stream *pa_stream_ref(pa_stream *s); - -/** Return the current state of the stream */ -pa_stream_state_t pa_stream_get_state(pa_stream *p); - -/** Return the context this stream is attached to */ -pa_context* pa_stream_get_context(pa_stream *p); - -/** Return the device (sink input or source output) index this stream is connected to */ -uint32_t pa_stream_get_index(pa_stream *s); - -/** Connect the stream to a sink */ -int pa_stream_connect_playback( - pa_stream *s /**< The stream to connect to a sink */, - const char *dev /**< Name of the sink to connect to, or NULL for default */ , - const pa_buffer_attr *attr /**< Buffering attributes, or NULL for default */, - pa_stream_flags_t flags /**< Additional flags, or 0 for default */, - pa_cvolume *volume /**< Initial volume, or NULL for default */, - pa_stream *sync_stream /**< Synchronize this stream with the specified one, or NULL for a standalone stream*/); - -/** Connect the stream to a source */ -int pa_stream_connect_record( - pa_stream *s /**< The stream to connect to a source */ , - const char *dev /**< Name of the source to connect to, or NULL for default */, - const pa_buffer_attr *attr /**< Buffer attributes, or NULL for default */, - pa_stream_flags_t flags /**< Additional flags, or 0 for default */); - -/** Disconnect a stream from a source/sink */ -int pa_stream_disconnect(pa_stream *s); - -/** Write some data to the server (for playback sinks), if free_cb is - * non-NULL this routine is called when all data has been written out - * and an internal reference to the specified data is kept, the data - * is not copied. If NULL, the data is copied into an internal - * buffer. The client my freely seek around in the output buffer. For - * most applications passing 0 and PA_SEEK_RELATIVE as arguments for - * offset and seek should be useful.*/ -int pa_stream_write( - pa_stream *p /**< The stream to use */, - const void *data /**< The data to write */, - size_t length /**< The length of the data to write */, - pa_free_cb_t free_cb /**< A cleanup routine for the data or NULL to request an internal copy */, - int64_t offset, /**< Offset for seeking, must be 0 for upload streams */ - pa_seek_mode_t seek /**< Seek mode, must be PA_SEEK_RELATIVE for upload streams */); - -/** Read the next fragment from the buffer (for recording). - * data will point to the actual data and length will contain the size - * of the data in bytes (which can be less than a complete framgnet). - * Use pa_stream_drop() to actually remove the data from the - * buffer. If no data is available will return a NULL pointer \since 0.8 */ -int pa_stream_peek( - pa_stream *p /**< The stream to use */, - const void **data /**< Pointer to pointer that will point to data */, - size_t *length /**< The length of the data read */); - -/** Remove the current fragment on record streams. It is invalid to do this without first - * calling pa_stream_peek(). \since 0.8 */ -int pa_stream_drop(pa_stream *p); - -/** Return the nember of bytes that may be written using pa_stream_write() */ -size_t pa_stream_writable_size(pa_stream *p); - -/** Return the number of bytes that may be read using pa_stream_read() \since 0.8 */ -size_t pa_stream_readable_size(pa_stream *p); - -/** Drain a playback stream. Use this for notification when the buffer is empty */ -pa_operation* pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); - -/** Request a timing info structure update for a stream. Use - * pa_stream_get_timing_info() to get access to the raw timing data, - * or pa_stream_get_time() or pa_stream_get_latency() to get cleaned - * up values. */ -pa_operation* pa_stream_update_timing_info(pa_stream *p, pa_stream_success_cb_t cb, void *userdata); - -/** Set the callback function that is called whenever the state of the stream changes */ -void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata); - -/** Set the callback function that is called when new data may be - * written to the stream. */ -void pa_stream_set_write_callback(pa_stream *p, pa_stream_request_cb_t cb, void *userdata); - -/** Set the callback function that is called when new data is available from the stream. - * Return the number of bytes read. \since 0.8 */ -void pa_stream_set_read_callback(pa_stream *p, pa_stream_request_cb_t cb, void *userdata); - -/** Set the callback function that is called when a buffer overflow happens. (Only for playback streams) \since 0.8 */ -void pa_stream_set_overflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); - -/** Set the callback function that is called when a buffer underflow happens. (Only for playback streams) \since 0.8 */ -void pa_stream_set_underflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); - -/** Set the callback function that is called whenever a latency information update happens. Useful on PA_STREAM_AUTO_TIMING_UPDATE streams only. (Only for playback streams) \since 0.8.2 */ -void pa_stream_set_latency_update_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); - -/** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. \since 0.3 */ -pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata); - -/** Flush the playback buffer of this stream. Most of the time you're - * better off using the parameter delta of pa_stream_write() instead of this - * function. Available on both playback and recording streams. \since 0.3 */ -pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); - -/** Reenable prebuffering as specified in the pa_buffer_attr - * structure. Available for playback streams only. \since 0.6 */ -pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); - -/** Request immediate start of playback on this stream. This disables - * prebuffering as specified in the pa_buffer_attr - * structure, temporarily. Available for playback streams only. \since 0.3 */ -pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); - -/** Rename the stream. \since 0.5 */ -pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata); - -/** Return the current playback/recording time. This is based on the - * data in the timing info structure returned by - * pa_stream_get_timing_info(). This function will usually only return - * new data if a timing info update has been recieved. Only if timing - * interpolation has been requested (PA_STREAM_INTERPOLATE_TIMING) - * the data from the last timing update is used for an estimation of - * the current playback/recording time based on the local time that - * passed since the timing info structure has been acquired. The time - * value returned by this function is guaranteed to increase - * monotonically. (that means: the returned value is always greater or - * equal to the value returned on the last call) This behaviour can - * be disabled by using PA_STREAM_NOT_MONOTONOUS. This may be - * desirable to deal better with bad estimations of transport - * latencies, but may have strange effects if the application is not - * able to deal with time going 'backwards'. \since 0.6 */ -int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec); - -/** Return the total stream latency. This function is based on - * pa_stream_get_time(). In case the stream is a monitoring stream the - * result can be negative, i.e. the captured samples are not yet - * played. In this case *negative is set to 1. \since 0.6 */ -int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative); - -/** Return the latest raw timing data structure. The returned pointer - * points to an internal read-only instance of the timing - * structure. The user should make a copy of this structure if he - * wants to modify it. An in-place update to this data structure may - * be requested using pa_stream_update_timing_info(). If no - * pa_stream_update_timing_info() call was issued before, this - * function will fail with PA_ERR_NODATA. Please note that the - * write_index member field (and only this field) is updated on each - * pa_stream_write() call, not just when a timing update has been - * recieved. \since 0.8 */ -const pa_timing_info* pa_stream_get_timing_info(pa_stream *s); - -/** Return a pointer to the stream's sample specification. \since 0.6 */ -const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s); - -/** Return a pointer to the stream's channel map. \since 0.8 */ -const pa_channel_map* pa_stream_get_channel_map(pa_stream *s); - -/** Return the buffer metrics of the stream. Only valid after the - * stream has been connected successfuly and if the server is at least - * Polypaudio 0.9. \since 0.9.0 */ -const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/subscribe.c b/src/polyp/subscribe.c deleted file mode 100644 index 21f5f7a5..00000000 --- a/src/polyp/subscribe.c +++ /dev/null @@ -1,89 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include -#include - -#include "internal.h" - -#include "subscribe.h" - -void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_context *c = userdata; - pa_subscription_event_type_t e; - uint32_t idx; - - assert(pd); - assert(command == PA_COMMAND_SUBSCRIBE_EVENT); - assert(t); - assert(c); - - pa_context_ref(c); - - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(c, PA_ERR_PROTOCOL); - goto finish; - } - - if (c->subscribe_callback) - c->subscribe_callback(c, e, idx, c->subscribe_userdata); - -finish: - pa_context_unref(c); -} - - -pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SUBSCRIBE, &tag); - pa_tagstruct_putu32(t, m); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -void pa_context_set_subscribe_callback(pa_context *c, pa_context_subscribe_cb_t cb, void *userdata) { - assert(c); - assert(c->ref >= 1); - - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; -} diff --git a/src/polyp/subscribe.h b/src/polyp/subscribe.h deleted file mode 100644 index d8326e1c..00000000 --- a/src/polyp/subscribe.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef foosubscribehfoo -#define foosubscribehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include -#include -#include - -/** \page subscribe Event Subscription - * - * \section overv_sec Overview - * - * The application can be notified, asynchronously, whenever the internal - * layout of the server changes. Possible notifications are desribed in the - * \ref pa_subscription_event_type and \ref pa_subscription_mask - * enumerations. - * - * The application sets the notification mask using pa_context_subscribe() - * and the function that will be called whenever a notification occurs using - * pa_context_set_subscribe_callback(). - */ - -/** \file - * Daemon introspection event subscription subsystem. */ - -PA_C_DECL_BEGIN - -/** Subscription event callback prototype */ -typedef void (*pa_context_subscribe_cb_t)(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata); - -/** Enable event notification */ -pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_context_success_cb_t cb, void *userdata); - -/** Set the context specific call back function that is called whenever the state of the daemon changes */ -void pa_context_set_subscribe_callback(pa_context *c, pa_context_subscribe_cb_t cb, void *userdata); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/thread-mainloop.c b/src/polyp/thread-mainloop.c deleted file mode 100644 index d036a232..00000000 --- a/src/polyp/thread-mainloop.c +++ /dev/null @@ -1,466 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#ifdef HAVE_SYS_POLL_H -#include -#else -#include "../polypcore/poll.h" -#endif - -#ifdef HAVE_PTHREAD -#include -#endif - -#ifdef HAVE_WINDOWS_H -#include -#endif - -#include - -#include -#include - -#include "mainloop.h" -#include "thread-mainloop.h" - -#if defined(HAVE_PTHREAD) || defined(OS_IS_WIN32) - -struct pa_threaded_mainloop { - pa_mainloop *real_mainloop; - int n_waiting; - int thread_running; - -#ifdef OS_IS_WIN32 - DWORD thread_id; - HANDLE thread; - CRITICAL_SECTION mutex; - pa_hashmap *cond_events; - HANDLE accept_cond; -#else - pthread_t thread_id; - pthread_mutex_t mutex; - pthread_cond_t cond, accept_cond; -#endif -}; - -static inline int in_worker(pa_threaded_mainloop *m) { -#ifdef OS_IS_WIN32 - return GetCurrentThreadId() == m->thread_id; -#else - return pthread_equal(pthread_self(), m->thread_id); -#endif -} - -static int poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) { -#ifdef OS_IS_WIN32 - CRITICAL_SECTION *mutex = userdata; -#else - pthread_mutex_t *mutex = userdata; -#endif - - int r; - - assert(mutex); - - /* Before entering poll() we unlock the mutex, so that - * avahi_simple_poll_quit() can succeed from another thread. */ - -#ifdef OS_IS_WIN32 - LeaveCriticalSection(mutex); -#else - pthread_mutex_unlock(mutex); -#endif - - r = poll(ufds, nfds, timeout); - -#ifdef OS_IS_WIN32 - EnterCriticalSection(mutex); -#else - pthread_mutex_lock(mutex); -#endif - - return r; -} - -#ifdef OS_IS_WIN32 -static DWORD WINAPI thread(void *userdata) { -#else -static void* thread(void *userdata) { -#endif - pa_threaded_mainloop *m = userdata; - -#ifndef OS_IS_WIN32 - sigset_t mask; - - /* Make sure that signals are delivered to the main thread */ - sigfillset(&mask); - pthread_sigmask(SIG_BLOCK, &mask, NULL); -#endif - -#ifdef OS_IS_WIN32 - EnterCriticalSection(&m->mutex); -#else - pthread_mutex_lock(&m->mutex); -#endif - - pa_mainloop_run(m->real_mainloop, NULL); - -#ifdef OS_IS_WIN32 - LeaveCriticalSection(&m->mutex); -#else - pthread_mutex_unlock(&m->mutex); -#endif - -#ifdef OS_IS_WIN32 - return 0; -#else - return NULL; -#endif -} - -pa_threaded_mainloop *pa_threaded_mainloop_new(void) { - pa_threaded_mainloop *m; -#ifndef OS_IS_WIN32 - pthread_mutexattr_t a; -#endif - - m = pa_xnew(pa_threaded_mainloop, 1); - - if (!(m->real_mainloop = pa_mainloop_new())) { - pa_xfree(m); - return NULL; - } - - pa_mainloop_set_poll_func(m->real_mainloop, poll_func, &m->mutex); - -#ifdef OS_IS_WIN32 - InitializeCriticalSection(&m->mutex); - - m->cond_events = pa_hashmap_new(NULL, NULL); - assert(m->cond_events); - m->accept_cond = CreateEvent(NULL, FALSE, FALSE, NULL); - assert(m->accept_cond); -#else - pthread_mutexattr_init(&a); - pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&m->mutex, &a); - pthread_mutexattr_destroy(&a); - - pthread_cond_init(&m->cond, NULL); - pthread_cond_init(&m->accept_cond, NULL); -#endif - - m->thread_running = 0; - m->n_waiting = 0; - - return m; -} - -void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { - assert(m); - - /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); - - if (m->thread_running) - pa_threaded_mainloop_stop(m); - - if (m->real_mainloop) - pa_mainloop_free(m->real_mainloop); - -#ifdef OS_IS_WIN32 - pa_hashmap_free(m->cond_events, NULL, NULL); - CloseHandle(m->accept_cond); -#else - pthread_mutex_destroy(&m->mutex); - pthread_cond_destroy(&m->cond); - pthread_cond_destroy(&m->accept_cond); -#endif - - pa_xfree(m); -} - -int pa_threaded_mainloop_start(pa_threaded_mainloop *m) { - assert(m); - - assert(!m->thread_running); - -#ifdef OS_IS_WIN32 - - EnterCriticalSection(&m->mutex); - - m->thread = CreateThread(NULL, 0, thread, m, 0, &m->thread_id); - if (!m->thread) { - LeaveCriticalSection(&m->mutex); - return -1; - } - -#else - - pthread_mutex_lock(&m->mutex); - - if (pthread_create(&m->thread_id, NULL, thread, m) < 0) { - pthread_mutex_unlock(&m->mutex); - return -1; - } - -#endif - - m->thread_running = 1; - -#ifdef OS_IS_WIN32 - LeaveCriticalSection(&m->mutex); -#else - pthread_mutex_unlock(&m->mutex); -#endif - - return 0; -} - -void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) { - assert(m); - - if (!m->thread_running) - return; - - /* Make sure that this function is not called from the helper thread */ - assert(!in_worker(m)); - -#ifdef OS_IS_WIN32 - EnterCriticalSection(&m->mutex); -#else - pthread_mutex_lock(&m->mutex); -#endif - - pa_mainloop_quit(m->real_mainloop, 0); - -#ifdef OS_IS_WIN32 - LeaveCriticalSection(&m->mutex); -#else - pthread_mutex_unlock(&m->mutex); -#endif - -#ifdef OS_IS_WIN32 - WaitForSingleObject(m->thread, INFINITE); - CloseHandle(m->thread); -#else - pthread_join(m->thread_id, NULL); -#endif - - m->thread_running = 0; - - return; -} - -void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) { - assert(m); - - /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); - -#ifdef OS_IS_WIN32 - EnterCriticalSection(&m->mutex); -#else - pthread_mutex_lock(&m->mutex); -#endif -} - -void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { - assert(m); - - /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); - -#ifdef OS_IS_WIN32 - LeaveCriticalSection(&m->mutex); -#else - pthread_mutex_unlock(&m->mutex); -#endif -} - -void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept) { -#ifdef OS_IS_WIN32 - void *iter; - const void *key; - HANDLE event; -#endif - - assert(m); - -#ifdef OS_IS_WIN32 - - iter = NULL; - while (1) { - pa_hashmap_iterate(m->cond_events, &iter, &key); - if (key == NULL) - break; - event = (HANDLE)pa_hashmap_get(m->cond_events, key); - SetEvent(event); - } - -#else - - pthread_cond_broadcast(&m->cond); - -#endif - - if (wait_for_accept && m->n_waiting > 0) { - -#ifdef OS_IS_WIN32 - - /* This is just to make sure it's unsignaled */ - WaitForSingleObject(m->accept_cond, 0); - - LeaveCriticalSection(&m->mutex); - - WaitForSingleObject(m->accept_cond, INFINITE); - - EnterCriticalSection(&m->mutex); - -#else - - pthread_cond_wait(&m->accept_cond, &m->mutex); - -#endif - - } -} - -void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { -#ifdef OS_IS_WIN32 - HANDLE event; - DWORD result; -#endif - - assert(m); - - /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); - - m->n_waiting ++; - -#ifdef OS_IS_WIN32 - - event = CreateEvent(NULL, FALSE, FALSE, NULL); - assert(event); - - pa_hashmap_put(m->cond_events, event, event); - - LeaveCriticalSection(&m->mutex); - - result = WaitForSingleObject(event, INFINITE); - assert(result == WAIT_OBJECT_0); - - EnterCriticalSection(&m->mutex); - - pa_hashmap_remove(m->cond_events, event); - - CloseHandle(event); - -#else - - pthread_cond_wait(&m->cond, &m->mutex); - -#endif - - assert(m->n_waiting > 0); - m->n_waiting --; -} - -void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) { - assert(m); - - /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); - -#ifdef OS_IS_WIN32 - SetEvent(m->accept_cond); -#else - pthread_cond_signal(&m->accept_cond); -#endif -} - -int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) { - assert(m); - - return pa_mainloop_get_retval(m->real_mainloop); -} - -pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) { - assert(m); - - return pa_mainloop_get_api(m->real_mainloop); -} - -#else /* defined(OS_IS_WIN32) || defined(HAVE_PTHREAD) */ - -pa_threaded_mainloop *pa_threaded_mainloop_new(void) { - pa_log_error(__FILE__": Threaded main loop not supported on this platform"); - return NULL; -} - -void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { - assert(0); -} - -int pa_threaded_mainloop_start(pa_threaded_mainloop *m) { - assert(0); - return -1; -} - -void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) { - assert(0); -} - -void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) { - assert(0); -} - -void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { - assert(0); -} - -void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { - assert(0); -} - -void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_release) { - assert(0); -} - -int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) { - assert(0); -} - -pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) { - assert(0); - return NULL; -} - -#endif /* defined(OS_IS_WIN32) || defined(HAVE_PTHREAD) */ diff --git a/src/polyp/thread-mainloop.h b/src/polyp/thread-mainloop.h deleted file mode 100644 index 81e8d674..00000000 --- a/src/polyp/thread-mainloop.h +++ /dev/null @@ -1,299 +0,0 @@ -#ifndef foothreadmainloophfoo -#define foothreadmainloophfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -PA_C_DECL_BEGIN - -/** \page threaded_mainloop Threaded Main Loop - * - * \section overv_sec Overview - * - * The threaded main loop implementation is a special version of the primary - * main loop implementation (see \ref mainloop). For the basic design, see - * its documentation. - * - * The added feature in the threaded main loop is that it spawns a new thread - * that runs the real main loop. This allows a synchronous application to use - * the asynchronous API without risking to stall the Polypaudio library. - * - * \section creat_sec Creation - * - * A pa_threaded_mainloop object is created using pa_threaded_mainloop_new(). - * This will only allocate the required structures though, so to use it the - * thread must also be started. This is done through - * pa_threaded_mainloop_start(), after which you can start using the main loop. - * - * \section destr_sec Destruction - * - * When the Polypaudio connection has been terminated, the thread must be - * stopped and the resources freed. Stopping the thread is done using - * pa_threaded_mainloop_stop(), which must be called without the lock (see - * below) held. When that function returns, the thread is stopped and the - * pa_threaded_mainloop object can be freed using pa_threaded_mainloop_free(). - * - * \section lock_sec Locking - * - * Since the Polypaudio API doesn't allow concurrent accesses to objects, - * a locking scheme must be used to guarantee safe usage. The threaded main - * loop API provides such a scheme through the functions - * pa_threaded_mainloop_lock() and pa_threaded_mainloop_unlock(). - * - * The lock is recursive, so it's safe to use it multiple times from the same - * thread. Just make sure you call pa_threaded_mainloop_unlock() the same - * number of times you called pa_threaded_mainloop_lock(). - * - * The lock needs to be held whenever you call any Polypaudio function that - * uses an object associated with this main loop. Make sure you do not hold - * on to the lock more than necessary though, as the threaded main loop stops - * while the lock is held. - * - * Example: - * - * \code - * void my_check_stream_func(pa_threaded_mainloop *m, pa_stream *s) { - * pa_stream_state_t state; - * - * pa_threaded_mainloop_lock(m); - * - * state = pa_stream_get_state(s); - * - * pa_threaded_mainloop_unlock(m); - * - * if (state == PA_STREAM_READY) - * printf("Stream is ready!"); - * else - * printf("Stream is not ready!"); - * } - * \endcode - * - * \section cb_sec Callbacks - * - * Callbacks in Polypaudio are asynchronous, so they require extra care when - * using them together with a threaded main loop. - * - * The easiest way to turn the callback based operations into synchronous - * ones, is to simply wait for the callback to be called and continue from - * there. This is the approach chosen in Polypaudio's threaded API. - * - * \subsection basic_subsec Basic callbacks - * - * For the basic case, where all that is required is to wait for the callback - * to be invoked, the code should look something like this: - * - * Example: - * - * \code - * static void my_drain_callback(pa_stream*s, int success, void *userdata) { - * pa_threaded_mainloop *m; - * - * m = (pa_threaded_mainloop*)userdata; - * assert(m); - * - * pa_threaded_mainloop_signal(m, 0); - * } - * - * void my_drain_stream_func(pa_threaded_mainloop *m, pa_stream *s) { - * pa_operation *o; - * - * pa_threaded_mainloop_lock(m); - * - * o = pa_stream_drain(s, my_drain_callback, m); - * assert(o); - * - * while (pa_operation_get_state(o) != OPERATION_DONE) - * pa_threaded_mainloop_wait(m); - * - * pa_operation_unref(o); - * - * pa_threaded_mainloop_unlock(m); - * } - * \endcode - * - * The main function, my_drain_stream_func(), will wait for the callback to - * be called using pa_threaded_mainloop_wait(). - * - * If your application is multi-threaded, then this waiting must be done - * inside a while loop. The reason for this is that multiple threads might be - * using pa_threaded_mainloop_wait() at the same time. Each thread must - * therefore verify that it was its callback that was invoked. - * - * The callback, my_drain_callback(), indicates to the main function that it - * has been called using pa_threaded_mainloop_signal(). - * - * As you can see, both pa_threaded_mainloop_wait() may only be called with - * the lock held. The same thing is true for pa_threaded_mainloop_signal(), - * but as the lock is held before the callback is invoked, you do not have to - * deal with that. - * - * The functions will not dead lock because the wait function will release - * the lock before waiting and then regrab it once it has been signaled. - * For those of you familiar with threads, the behaviour is that of a - * condition variable. - * - * \subsection data_subsec Data callbacks - * - * For many callbacks, simply knowing that they have been called is - * insufficient. The callback also receives some data that is desired. To - * access this data safely, we must extend our example a bit: - * - * \code - * static int *drain_result; - * - * static void my_drain_callback(pa_stream*s, int success, void *userdata) { - * pa_threaded_mainloop *m; - * - * m = (pa_threaded_mainloop*)userdata; - * assert(m); - * - * drain_result = &success; - * - * pa_threaded_mainloop_signal(m, 1); - * } - * - * void my_drain_stream_func(pa_threaded_mainloop *m, pa_stream *s) { - * pa_operation *o; - * - * pa_threaded_mainloop_lock(m); - * - * o = pa_stream_drain(s, my_drain_callback, m); - * assert(o); - * - * while (pa_operation_get_state(o) != OPERATION_DONE) - * pa_threaded_mainloop_wait(m); - * - * pa_operation_unref(o); - * - * if (*drain_result) - * printf("Success!"); - * else - * printf("Bitter defeat..."); - * - * pa_threaded_mainloop_accept(m); - * - * pa_threaded_mainloop_unlock(m); - * } - * \endcode - * - * The example is a bit silly as it would probably have been easier to just - * copy the contents of success, but for larger data structures this can be - * wasteful. - * - * The difference here compared to the basic callback is the 1 sent to - * pa_threaded_mainloop_signal() and the call to - * pa_threaded_mainloop_accept(). What will happen is that - * pa_threaded_mainloop_signal() will signal the main function and then stop. - * The main function is then free to use the data in the callback until - * pa_threaded_mainloop_accept() is called, which will allow the callback - * to continue. - * - * Note that pa_threaded_mainloop_accept() must be called some time between - * exiting the while loop and unlocking the main loop! Failure to do so will - * result in a race condition. I.e. it is not ok to release the lock and - * regrab it before calling pa_threaded_mainloop_accept(). - * - * \subsection async_subsec Asynchronous callbacks - * - * Polypaudio also has callbacks that are completely asynchronous, meaning - * that they can be called at any time. The threading main loop API provides - * the locking mechanism to handle concurrent accesses, but nothing else. - * Applications will have to handle communication from the callback to the - * main program through some own system. - * - * The callbacks that are completely asynchronous are: - * - * \li State callbacks for contexts, streams, etc. - * \li Subscription notifications - */ - -/** \file - * - * A thread based event loop implementation based on pa_mainloop. The - * event loop is run in a helper thread in the background. A few - * synchronization primitives are available to access the objects - * attached to the event loop safely. */ - -/** An opaque threaded main loop object */ -typedef struct pa_threaded_mainloop pa_threaded_mainloop; - -/** Allocate a new threaded main loop object. You have to call - * pa_threaded_mainloop_start() before the event loop thread starts - * running. */ -pa_threaded_mainloop *pa_threaded_mainloop_new(void); - -/** Free a threaded main loop object. If the event loop thread is - * still running, it is terminated using pa_threaded_mainloop_stop() - * first. */ -void pa_threaded_mainloop_free(pa_threaded_mainloop* m); - -/** Start the event loop thread. */ -int pa_threaded_mainloop_start(pa_threaded_mainloop *m); - -/** Terminate the event loop thread cleanly. Make sure to unlock the - * mainloop object before calling this function. */ -void pa_threaded_mainloop_stop(pa_threaded_mainloop *m); - -/** Lock the event loop object, effectively blocking the event loop - * thread from processing events. You can use this to enforce - * exclusive access to all objects attached to the event loop. This - * lock is recursive. This function may not be called inside the event - * loop thread. Events that are dispatched from the event loop thread - * are executed with this lock held. */ -void pa_threaded_mainloop_lock(pa_threaded_mainloop *m); - -/** Unlock the event loop object, inverse of pa_threaded_mainloop_lock() */ -void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m); - -/** Wait for an event to be signalled by the event loop thread. You - * can use this to pass data from the event loop thread to the main - * thread in synchronized fashion. This function may not be called - * inside the event loop thread. Prior to this call the event loop - * object needs to be locked using pa_threaded_mainloop_lock(). While - * waiting the lock will be released, immediately before returning it - * will be acquired again. */ -void pa_threaded_mainloop_wait(pa_threaded_mainloop *m); - -/** Signal all threads waiting for a signalling event in - * pa_threaded_mainloop_wait(). If wait_for_release is non-zero, do - * not return before the signal was accepted by a - * pa_threaded_mainloop_accept() call. While waiting for that condition - * the event loop object is unlocked. */ -void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept); - -/** Accept a signal from the event thread issued with - * pa_threaded_mainloop_signal(). This call should only be used in - * conjunction with pa_threaded_mainloop_signal() with a non-zero - * wait_for_accept value. */ -void pa_threaded_mainloop_accept(pa_threaded_mainloop *m); - -/** Return the return value as specified with the main loop's quit() routine. */ -int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m); - -/** Return the abstract main loop abstraction layer vtable for this main loop. */ -pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/timeval.c b/src/polyp/timeval.c deleted file mode 100644 index 6043d7fd..00000000 --- a/src/polyp/timeval.c +++ /dev/null @@ -1,142 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#ifdef HAVE_WINDOWS_H -#include -#endif - -#include "../polypcore/winsock.h" - -#include "timeval.h" - -struct timeval *pa_gettimeofday(struct timeval *tv) { -#ifdef HAVE_GETTIMEOFDAY - assert(tv); - - return gettimeofday(tv, NULL) < 0 ? NULL : tv; -#elif defined(OS_IS_WIN32) - /* - * Copied from implementation by Steven Edwards (LGPL). - * Found on wine mailing list. - */ - -#if defined(_MSC_VER) || defined(__BORLANDC__) -#define EPOCHFILETIME (116444736000000000i64) -#else -#define EPOCHFILETIME (116444736000000000LL) -#endif - - FILETIME ft; - LARGE_INTEGER li; - __int64 t; - - assert(tv); - - GetSystemTimeAsFileTime(&ft); - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - t = li.QuadPart; /* In 100-nanosecond intervals */ - t -= EPOCHFILETIME; /* Offset to the Epoch time */ - t /= 10; /* In microseconds */ - tv->tv_sec = (long)(t / 1000000); - tv->tv_usec = (long)(t % 1000000); - - return tv; -#else -#error "Platform lacks gettimeofday() or equivalent function." -#endif -} - -pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { - pa_usec_t r; - assert(a && b); - - /* Check which whan is the earlier time and swap the two arguments if reuqired. */ - if (pa_timeval_cmp(a, b) < 0) { - const struct timeval *c; - c = a; - a = b; - b = c; - } - - /* Calculate the second difference*/ - r = ((pa_usec_t) a->tv_sec - b->tv_sec)* 1000000; - - /* Calculate the microsecond difference */ - if (a->tv_usec > b->tv_usec) - r += ((pa_usec_t) a->tv_usec - b->tv_usec); - else if (a->tv_usec < b->tv_usec) - r -= ((pa_usec_t) b->tv_usec - a->tv_usec); - - return r; -} - -int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { - assert(a && b); - - if (a->tv_sec < b->tv_sec) - return -1; - - if (a->tv_sec > b->tv_sec) - return 1; - - if (a->tv_usec < b->tv_usec) - return -1; - - if (a->tv_usec > b->tv_usec) - return 1; - - return 0; -} - -pa_usec_t pa_timeval_age(const struct timeval *tv) { - struct timeval now; - assert(tv); - - return pa_timeval_diff(pa_gettimeofday(&now), tv); -} - -struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v) { - unsigned long secs; - assert(tv); - - secs = (v/1000000); - tv->tv_sec += (unsigned long) secs; - v -= secs*1000000; - - tv->tv_usec += v; - - /* Normalize */ - while (tv->tv_usec >= 1000000) { - tv->tv_sec++; - tv->tv_usec -= 1000000; - } - - return tv; -} diff --git a/src/polyp/timeval.h b/src/polyp/timeval.h deleted file mode 100644 index 9990d4ca..00000000 --- a/src/polyp/timeval.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef footimevalhfoo -#define footimevalhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -/** \file - * Utility functions for handling timeval calculations */ - -PA_C_DECL_BEGIN - -struct timeval; - -/** Return the current timestamp, just like UNIX gettimeofday() */ -struct timeval *pa_gettimeofday(struct timeval *tv); - -/** Calculate the difference between the two specified timeval - * structs. */ -pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); - -/** Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwse */ -int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); - -/** Return the time difference between now and the specified timestamp */ -pa_usec_t pa_timeval_age(const struct timeval *tv); - -/** Add the specified time inmicroseconds to the specified timeval structure */ -struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/utf8.c b/src/polyp/utf8.c deleted file mode 100644 index 33fa7214..00000000 --- a/src/polyp/utf8.c +++ /dev/null @@ -1,237 +0,0 @@ -/* $Id$ */ - -/* This file is based on the GLIB utf8 validation functions. The - * original license text follows. */ - -/* gutf8.c - Operations on UTF-8 strings. - * - * Copyright (C) 1999 Tom Tromey - * Copyright (C) 2000 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#ifdef HAVE_ICONV -#include -#endif - -#include "utf8.h" -#include "xmalloc.h" - -#define FILTER_CHAR '_' - -static inline int is_unicode_valid(uint32_t ch) { - if (ch >= 0x110000) /* End of unicode space */ - return 0; - if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ - return 0; - if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ - return 0; - if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ - return 0; - return 1; -} - -static inline int is_continuation_char(uint8_t ch) { - if ((ch & 0xc0) != 0x80) /* 10xxxxxx */ - return 0; - return 1; -} - -static inline void merge_continuation_char(uint32_t *u_ch, uint8_t ch) { - *u_ch <<= 6; - *u_ch |= ch & 0x3f; -} - -static char* utf8_validate(const char *str, char *output) { - uint32_t val = 0; - uint32_t min = 0; - const uint8_t *p, *last; - int size; - uint8_t *o; - - o = (uint8_t*) output; - for (p = (const uint8_t*) str; *p; p++) { - if (*p < 128) { - if (o) - *o = *p; - } else { - last = p; - - if ((*p & 0xe0) == 0xc0) { /* 110xxxxx two-char seq. */ - size = 2; - min = 128; - val = *p & 0x1e; - goto ONE_REMAINING; - } else if ((*p & 0xf0) == 0xe0) { /* 1110xxxx three-char seq.*/ - size = 3; - min = (1 << 11); - val = *p & 0x0f; - goto TWO_REMAINING; - } else if ((*p & 0xf8) == 0xf0) { /* 11110xxx four-char seq */ - size = 4; - min = (1 << 16); - val = *p & 0x07; - } else { - size = 1; - goto error; - } - - p++; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - -TWO_REMAINING: - p++; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - -ONE_REMAINING: - p++; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - - if (val < min) - goto error; - - if (!is_unicode_valid(val)) - goto error; - - if (o) { - memcpy(o, last, size); - o += size - 1; - } - - if (o) - o++; - - continue; - -error: - if (o) { - *o = FILTER_CHAR; - p = last; /* We retry at the next character */ - } else - goto failure; - } - - if (o) - o++; - } - - if (o) { - *o = '\0'; - return output; - } - - return (char*) str; - -failure: - return NULL; -} - -const char* pa_utf8_valid (const char *str) { - return utf8_validate(str, NULL); -} - -char* pa_utf8_filter (const char *str) { - char *new_str; - - new_str = pa_xnew(char, strlen(str) + 1); - - return utf8_validate(str, new_str); -} - -#ifdef HAVE_ICONV - -static char* iconv_simple(const char *str, const char *to, const char *from) { - char *new_str; - size_t len, inlen; - - iconv_t cd; - ICONV_CONST char *inbuf; - char *outbuf; - size_t res, inbytes, outbytes; - - cd = iconv_open(to, from); - if (cd == (iconv_t)-1) - return NULL; - - inlen = len = strlen(str) + 1; - new_str = pa_xmalloc(len); - assert(new_str); - - while (1) { - inbuf = (ICONV_CONST char*)str; /* Brain dead prototype for iconv() */ - inbytes = inlen; - outbuf = new_str; - outbytes = len; - - res = iconv(cd, &inbuf, &inbytes, &outbuf, &outbytes); - - if (res != (size_t)-1) - break; - - if (errno != E2BIG) { - pa_xfree(new_str); - new_str = NULL; - break; - } - - assert(inbytes != 0); - - len += inbytes; - new_str = pa_xrealloc(new_str, len); - assert(new_str); - } - - iconv_close(cd); - - return new_str; -} - -char* pa_utf8_to_locale (const char *str) { - return iconv_simple(str, "", "UTF-8"); -} - -char* pa_locale_to_utf8 (const char *str) { - return iconv_simple(str, "UTF-8", ""); -} - -#else - -char* pa_utf8_to_locale (const char *str) { - return NULL; -} - -char* pa_locale_to_utf8 (const char *str) { - return NULL; -} - -#endif diff --git a/src/polyp/utf8.h b/src/polyp/utf8.h deleted file mode 100644 index 55b8d2e4..00000000 --- a/src/polyp/utf8.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef fooutf8hfoo -#define fooutf8hfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -/** \file - * UTF8 Validation functions - */ - -PA_C_DECL_BEGIN - -/** Test if the specified strings qualifies as valid UTF8. Return the string if so, otherwise NULL */ -const char *pa_utf8_valid(const char *str); - -/** Filter all invalid UTF8 characters from the specified string, returning a new fully UTF8 valid string. Don't forget to free the returned string with pa_xfree() */ -char *pa_utf8_filter(const char *str); - -/** Convert a UTF-8 string to the current locale. Free the string using pa_xfree(). */ -char* pa_utf8_to_locale (const char *str); - -/** Convert a string in the current locale to UTF-8. Free the string using pa_xfree(). */ -char* pa_locale_to_utf8 (const char *str); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/util.c b/src/polyp/util.c deleted file mode 100644 index 842b9e7f..00000000 --- a/src/polyp/util.c +++ /dev/null @@ -1,227 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_PWD_H -#include -#endif - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#ifdef HAVE_NETDB_H -#include -#endif - -#ifdef HAVE_WINDOWS_H -#include -#endif - -#include "../polypcore/winsock.h" - -#include -#include -#include - -#include "util.h" - -#ifndef OS_IS_WIN32 -#define PATH_SEP '/' -#else -#define PATH_SEP '\\' -#endif - -char *pa_get_user_name(char *s, size_t l) { - char *p; - char buf[1024]; - -#ifdef HAVE_PWD_H - struct passwd pw, *r; -#endif - - assert(s && l > 0); - - if (!(p = getenv("USER")) && !(p = getenv("LOGNAME")) && !(p = getenv("USERNAME"))) { -#ifdef HAVE_PWD_H - -#ifdef HAVE_GETPWUID_R - if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { -#else - /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) - * that do not support getpwuid_r. */ - if ((r = getpwuid(getuid())) == NULL) { -#endif - snprintf(s, l, "%lu", (unsigned long) getuid()); - return s; - } - - p = r->pw_name; - -#elif defined(OS_IS_WIN32) /* HAVE_PWD_H */ - DWORD size = sizeof(buf); - - if (!GetUserName(buf, &size)) - return NULL; - - p = buf; - -#else /* HAVE_PWD_H */ - return NULL; -#endif /* HAVE_PWD_H */ - } - - return pa_strlcpy(s, p, l); -} - -char *pa_get_host_name(char *s, size_t l) { - assert(s && l > 0); - if (gethostname(s, l) < 0) { - pa_log(__FILE__": gethostname(): %s", pa_cstrerror(errno)); - return NULL; - } - s[l-1] = 0; - return s; -} - -char *pa_get_home_dir(char *s, size_t l) { - char *e; - -#ifdef HAVE_PWD_H - char buf[1024]; - struct passwd pw, *r; -#endif - - assert(s && l); - - if ((e = getenv("HOME"))) - return pa_strlcpy(s, e, l); - - if ((e = getenv("USERPROFILE"))) - return pa_strlcpy(s, e, l); - -#ifdef HAVE_PWD_H -#ifdef HAVE_GETPWUID_R - if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { - pa_log(__FILE__": getpwuid_r() failed"); -#else - /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) - * that do not support getpwuid_r. */ - if ((r = getpwuid(getuid())) == NULL) { - pa_log(__FILE__": getpwuid_r() failed"); -#endif - return NULL; - } - - return pa_strlcpy(s, r->pw_dir, l); -#else /* HAVE_PWD_H */ - return NULL; -#endif -} - -char *pa_get_binary_name(char *s, size_t l) { - -#ifdef HAVE_READLINK - char path[PATH_MAX]; - int i; - assert(s && l); - - /* This works on Linux only */ - - snprintf(path, sizeof(path), "/proc/%u/exe", (unsigned) getpid()); - if ((i = readlink(path, s, l-1)) < 0) - return NULL; - - s[i] = 0; - return s; -#elif defined(OS_IS_WIN32) - char path[PATH_MAX]; - if (!GetModuleFileName(NULL, path, PATH_MAX)) - return NULL; - pa_strlcpy(s, pa_path_get_filename(path), l); - return s; -#else - return NULL; -#endif -} - -const char *pa_path_get_filename(const char *p) { - char *fn; - - if ((fn = strrchr(p, PATH_SEP))) - return fn+1; - - return (const char*) p; -} - -char *pa_get_fqdn(char *s, size_t l) { - char hn[256]; -#ifdef HAVE_GETADDRINFO - struct addrinfo *a, hints; -#endif - - if (!pa_get_host_name(hn, sizeof(hn))) - return NULL; - -#ifdef HAVE_GETADDRINFO - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_flags = AI_CANONNAME; - - if (getaddrinfo(hn, NULL, &hints, &a) < 0 || !a || !a->ai_canonname || !*a->ai_canonname) - return pa_strlcpy(s, hn, l); - - pa_strlcpy(s, a->ai_canonname, l); - freeaddrinfo(a); - return s; -#else - return pa_strlcpy(s, hn, l); -#endif -} - -int pa_msleep(unsigned long t) { -#ifdef OS_IS_WIN32 - Sleep(t); - return 0; -#elif defined(HAVE_NANOSLEEP) - struct timespec ts; - - ts.tv_sec = t/1000; - ts.tv_nsec = (t % 1000) * 1000000; - - return nanosleep(&ts, NULL); -#else -#error "Platform lacks a sleep function." -#endif -} diff --git a/src/polyp/util.h b/src/polyp/util.h deleted file mode 100644 index cd8aab0b..00000000 --- a/src/polyp/util.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef fooutilhfoo -#define fooutilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include - -/** \file - * Assorted utility functions */ - -PA_C_DECL_BEGIN - -/** Return the current username in the specified string buffer. */ -char *pa_get_user_name(char *s, size_t l); - -/** Return the current hostname in the specified buffer. */ -char *pa_get_host_name(char *s, size_t l); - -/** Return the fully qualified domain name in s */ -char *pa_get_fqdn(char *s, size_t l); - -/** Return the home directory of the current user */ -char *pa_get_home_dir(char *s, size_t l); - -/** Return the binary file name of the current process. This is not - * supported on all architectures, in which case NULL is returned. */ -char *pa_get_binary_name(char *s, size_t l); - -/** Return a pointer to the filename inside a path (which is the last - * component). */ -const char *pa_path_get_filename(const char *p); - -/** Wait t milliseconds */ -int pa_msleep(unsigned long t); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/version.h.in b/src/polyp/version.h.in deleted file mode 100644 index de7b9c1c..00000000 --- a/src/polyp/version.h.in +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef fooversionhfoo /*-*-C-*-*/ -#define fooversionhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -/* WARNING: Make sure to edit the real source file version.h.in! */ - -#include - -/** \file - * Define header version */ - -PA_C_DECL_BEGIN - -/** Return the version of the header files. Keep in mind that this is -a macro and not a function, so it is impossible to get the pointer of -it. */ -#define pa_get_headers_version() ("@PACKAGE_VERSION@") - -/** Return the version of the library the current application is linked to. */ -const char* pa_get_library_version(void); - -/** The current API version. Version 6 relates to polypaudio - * 0.6. Prior versions (i.e. Polypaudio 0.5.1 and older) have - * PA_API_VERSION undefined. */ -#define PA_API_VERSION @PA_API_VERSION@ - -/** The current protocol version. Version 8 relates to polypaudio 0.8. - * \since 0.8 */ -#define PA_PROTOCOL_VERSION @PA_PROTOCOL_VERSION@ - -PA_C_DECL_END - -#endif diff --git a/src/polyp/volume.c b/src/polyp/volume.c deleted file mode 100644 index f10463c3..00000000 --- a/src/polyp/volume.c +++ /dev/null @@ -1,176 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "volume.h" - -int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) { - int i; - assert(a); - assert(b); - - if (a->channels != b->channels) - return 0; - - for (i = 0; i < a->channels; i++) - if (a->values[i] != b->values[i]) - return 0; - - return 1; -} - -pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) { - int i; - - assert(a); - assert(channels > 0); - assert(channels <= PA_CHANNELS_MAX); - - a->channels = channels; - - for (i = 0; i < a->channels; i++) - a->values[i] = v; - - return a; -} - -pa_volume_t pa_cvolume_avg(const pa_cvolume *a) { - uint64_t sum = 0; - int i; - assert(a); - - for (i = 0; i < a->channels; i++) - sum += a->values[i]; - - sum /= a->channels; - - return (pa_volume_t) sum; -} - -pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) { - return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a)* pa_sw_volume_to_linear(b)); -} - -#define USER_DECIBEL_RANGE 30 - -pa_volume_t pa_sw_volume_from_dB(double dB) { - if (dB <= -USER_DECIBEL_RANGE) - return PA_VOLUME_MUTED; - - return (pa_volume_t) ((dB/USER_DECIBEL_RANGE+1)*PA_VOLUME_NORM); -} - -double pa_sw_volume_to_dB(pa_volume_t v) { - if (v == PA_VOLUME_MUTED) - return PA_DECIBEL_MININFTY; - - return ((double) v/PA_VOLUME_NORM-1)*USER_DECIBEL_RANGE; -} - -pa_volume_t pa_sw_volume_from_linear(double v) { - - if (v <= 0) - return PA_VOLUME_MUTED; - - if (v > .999 && v < 1.001) - return PA_VOLUME_NORM; - - return pa_sw_volume_from_dB(20*log10(v)); -} - -double pa_sw_volume_to_linear(pa_volume_t v) { - - if (v == PA_VOLUME_MUTED) - return 0; - - return pow(10, pa_sw_volume_to_dB(v)/20); -} - -char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) { - unsigned channel; - int first = 1; - char *e; - - assert(s); - assert(l > 0); - assert(c); - - *(e = s) = 0; - - for (channel = 0; channel < c->channels && l > 1; channel++) { - l -= snprintf(e, l, "%s%u: %3u%%", - first ? "" : " ", - channel, - (c->values[channel]*100)/PA_VOLUME_NORM); - - e = strchr(e, 0); - first = 0; - } - - return s; -} - -/** Return non-zero if the volume of all channels is equal to the specified value */ -int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) { - unsigned c; - assert(a); - - for (c = 0; c < a->channels; c++) - if (a->values[c] != v) - return 0; - - return 1; -} - -pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { - unsigned i; - - assert(dest); - assert(a); - assert(b); - - for (i = 0; i < a->channels && i < b->channels && i < PA_CHANNELS_MAX; i++) { - - dest->values[i] = pa_sw_volume_multiply( - i < a->channels ? a->values[i] : PA_VOLUME_NORM, - i < b->channels ? b->values[i] : PA_VOLUME_NORM); - } - - dest->channels = i; - - return dest; -} - -int pa_cvolume_valid(const pa_cvolume *v) { - assert(v); - - if (v->channels <= 0 || v->channels > PA_CHANNELS_MAX) - return 0; - - return 1; -} diff --git a/src/polyp/volume.h b/src/polyp/volume.h deleted file mode 100644 index 0da5f54f..00000000 --- a/src/polyp/volume.h +++ /dev/null @@ -1,172 +0,0 @@ -#ifndef foovolumehfoo -#define foovolumehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include - -/** \page volume Volume Control - * - * \section overv_sec Overview - * - * Sinks, sources, sink inputs and samples can all have their own volumes. - * To deal with these, The Polypaudio libray contains a number of functions - * that ease handling. - * - * The basic volume type in Polypaudio is the \ref pa_volume_t type. Most of - * the time, applications will use the aggregated pa_cvolume structure that - * can store the volume of all channels at once. - * - * Volumes commonly span between muted (0%), and normal (100%). It is possible - * to set volumes to higher than 100%, but clipping might occur. - * - * \section calc_sec Calculations - * - * The volumes in Polypaudio are logarithmic in nature and applications - * shouldn't perform calculations with them directly. Instead, they should - * be converted to and from either dB or a linear scale: - * - * \li dB - pa_sw_volume_from_dB() / pa_sw_volume_to_dB() - * \li Linear - pa_sw_volume_from_linear() / pa_sw_volume_to_linear() - * - * For simple multiplication, pa_sw_volume_multiply() and - * pa_sw_cvolume_multiply() can be used. - * - * Calculations can only be reliably performed on software volumes - * as it is commonly unknown what scale hardware volumes relate to. - * - * The functions described above are only valid when used with - * software volumes. Hence it is usually a better idea to treat all - * volume values as opaque with a range from PA_VOLUME_MUTE (0%) to - * PA_VOLUME_NORM (100%) and to refrain from any calculations with - * them. - * - * \section conv_sec Convenience Functions - * - * To handle the pa_cvolume structure, the Polypaudio library provides a - * number of convenienc functions: - * - * \li pa_cvolume_valid() - Tests if a pa_cvolume structure is valid. - * \li pa_cvolume_equal() - Tests if two pa_cvolume structures are identical. - * \li pa_cvolume_channels_equal_to() - Tests if all channels of a pa_cvolume - * structure have a given volume. - * \li pa_cvolume_is_muted() - Tests if all channels of a pa_cvolume - * structure are muted. - * \li pa_cvolume_is_norm() - Tests if all channels of a pa_cvolume structure - * are at a normal volume. - * \li pa_cvolume_set() - Set all channels of a pa_cvolume structure to a - * certain volume. - * \li pa_cvolume_reset() - Set all channels of a pa_cvolume structure to a - * normal volume. - * \li pa_cvolume_mute() - Set all channels of a pa_cvolume structure to a - * muted volume. - * \li pa_cvolume_avg() - Return the average volume of all channels. - * \li pa_cvolume_snprint() - Pretty print a pa_cvolume structure. - */ - -/** \file - * Constants and routines for volume handling */ - -PA_C_DECL_BEGIN - -/** Volume specification: - * PA_VOLUME_MUTED: silence; - * < PA_VOLUME_NORM: decreased volume; - * PA_VOLUME_NORM: normal volume; - * > PA_VOLUME_NORM: increased volume */ -typedef uint32_t pa_volume_t; - -/** Normal volume (100%) */ -#define PA_VOLUME_NORM (0x10000) - -/** Muted volume (0%) */ -#define PA_VOLUME_MUTED (0) - -/** A structure encapsulating a per-channel volume */ -typedef struct pa_cvolume { - uint8_t channels; /**< Number of channels */ - pa_volume_t values[PA_CHANNELS_MAX]; /**< Per-channel volume */ -} pa_cvolume; - -/** Return non-zero when *a == *b */ -int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b); - -/** Set the volume of all channels to PA_VOLUME_NORM */ -#define pa_cvolume_reset(a, n) pa_cvolume_set((a), (n), PA_VOLUME_NORM) - -/** Set the volume of all channels to PA_VOLUME_MUTED */ -#define pa_cvolume_mute(a, n) pa_cvolume_set((a), (n), PA_VOLUME_MUTED) - -/** Set the volume of all channels to the specified parameter */ -pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v); - -/** Maximum length of the strings returned by pa_cvolume_snprint() */ -#define PA_CVOLUME_SNPRINT_MAX 64 - -/** Pretty print a volume structure */ -char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c); - -/** Return the average volume of all channels */ -pa_volume_t pa_cvolume_avg(const pa_cvolume *a); - -/** Return TRUE when the passed cvolume structure is valid, FALSE otherwise */ -int pa_cvolume_valid(const pa_cvolume *v); - -/** Return non-zero if the volume of all channels is equal to the specified value */ -int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v); - -/** Return 1 if the specified volume has all channels muted */ -#define pa_cvolume_is_muted(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_MUTED) - -/** Return 1 if the specified volume has all channels on normal level */ -#define pa_cvolume_is_norm(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_NORM) - -/** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. This is only valid for software volumes! */ -pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b); - -/** Multiply to per-channel volumes and return the result in *dest. This is only valid for software volumes! */ -pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b); - -/** Convert a decibel value to a volume. This is only valid for software volumes! \since 0.4 */ -pa_volume_t pa_sw_volume_from_dB(double f); - -/** Convert a volume to a decibel value. This is only valid for software volumes! \since 0.4 */ -double pa_sw_volume_to_dB(pa_volume_t v); - -/** Convert a linear factor to a volume. This is only valid for software volumes! \since 0.8 */ -pa_volume_t pa_sw_volume_from_linear(double v); - -/** Convert a volume to a linear factor. This is only valid for software volumes! \since 0.8 */ -double pa_sw_volume_to_linear(pa_volume_t v); - -#ifdef INFINITY -#define PA_DECIBEL_MININFTY (-INFINITY) -#else -/** This value is used as minus infinity when using pa_volume_{to,from}_dB(). \since 0.4 */ -#define PA_DECIBEL_MININFTY (-200) -#endif - -PA_C_DECL_END - -#endif diff --git a/src/polyp/xmalloc.c b/src/polyp/xmalloc.c deleted file mode 100644 index 7f71a5ed..00000000 --- a/src/polyp/xmalloc.c +++ /dev/null @@ -1,128 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include -#include - -#include "xmalloc.h" - -/* Make sure not to allocate more than this much memory. */ -#define MAX_ALLOC_SIZE (1024*1024*20) /* 20MB */ - -/* #undef malloc */ -/* #undef free */ -/* #undef realloc */ -/* #undef strndup */ -/* #undef strdup */ - -static void oom(void) PA_GCC_NORETURN; - -/** called in case of an OOM situation. Prints an error message and - * exits */ -static void oom(void) { - static const char e[] = "Not enough memory\n"; - pa_loop_write(STDERR_FILENO, e, sizeof(e)-1); -#ifdef SIGQUIT - raise(SIGQUIT); -#endif - _exit(1); -} - -void* pa_xmalloc(size_t size) { - void *p; - assert(size > 0); - assert(size < MAX_ALLOC_SIZE); - - if (!(p = malloc(size))) - oom(); - - return p; -} - -void* pa_xmalloc0(size_t size) { - void *p; - assert(size > 0); - assert(size < MAX_ALLOC_SIZE); - - if (!(p = calloc(1, size))) - oom(); - - return p; -} - -void *pa_xrealloc(void *ptr, size_t size) { - void *p; - assert(size > 0); - assert(size < MAX_ALLOC_SIZE); - - if (!(p = realloc(ptr, size))) - oom(); - return p; -} - -void* pa_xmemdup(const void *p, size_t l) { - if (!p) - return NULL; - else { - char *r = pa_xmalloc(l); - memcpy(r, p, l); - return r; - } -} - -char *pa_xstrdup(const char *s) { - if (!s) - return NULL; - - return pa_xmemdup(s, strlen(s)+1); -} - -char *pa_xstrndup(const char *s, size_t l) { - char *e, *r; - - if (!s) - return NULL; - - if ((e = memchr(s, 0, l))) - return pa_xmemdup(s, e-s+1); - - r = pa_xmalloc(l+1); - memcpy(r, s, l); - r[l] = 0; - return r; -} - -void pa_xfree(void *p) { - if (!p) - return; - - free(p); -} diff --git a/src/polyp/xmalloc.h b/src/polyp/xmalloc.h deleted file mode 100644 index 49b6d7bc..00000000 --- a/src/polyp/xmalloc.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef foomemoryhfoo -#define foomemoryhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include -#include - -/** \file - * Memory allocation functions. - */ - -PA_C_DECL_BEGIN - -/** Allocate the specified number of bytes, just like malloc() does. However, in case of OOM, terminate */ -void* pa_xmalloc(size_t l); - -/** Same as pa_xmalloc(), but initialize allocated memory to 0 */ -void *pa_xmalloc0(size_t l); - -/** The combination of pa_xmalloc() and realloc() */ -void *pa_xrealloc(void *ptr, size_t size); - -/** Free allocated memory */ -void pa_xfree(void *p); - -/** Duplicate the specified string, allocating memory with pa_xmalloc() */ -char *pa_xstrdup(const char *s); - -/** Duplicate the specified string, but truncate after l characters */ -char *pa_xstrndup(const char *s, size_t l); - -/** Duplicate the specified memory block */ -void* pa_xmemdup(const void *p, size_t l); - -/** Internal helper for pa_xnew() */ -static inline void* pa_xnew_internal(unsigned n, size_t k) { - assert(n < INT_MAX/k); - return pa_xmalloc(n*k); -} - -/** Allocate n new structures of the specified type. */ -#define pa_xnew(type, n) ((type*) pa_xnew_internal((n), sizeof(type))) - -/** Internal helper for pa_xnew0() */ -static inline void* pa_xnew0_internal(unsigned n, size_t k) { - assert(n < INT_MAX/k); - return pa_xmalloc0(n*k); -} - -/** Same as pa_xnew() but set the memory to zero */ -#define pa_xnew0(type, n) ((type*) pa_xnew0_internal((n), sizeof(type))) - -PA_C_DECL_END - -#endif diff --git a/src/polypcore/Makefile b/src/polypcore/Makefile deleted file mode 120000 index cd2a5c9a..00000000 --- a/src/polypcore/Makefile +++ /dev/null @@ -1 +0,0 @@ -../polyp/Makefile \ No newline at end of file diff --git a/src/polypcore/authkey-prop.c b/src/polypcore/authkey-prop.c deleted file mode 100644 index 6172d432..00000000 --- a/src/polypcore/authkey-prop.c +++ /dev/null @@ -1,89 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -#include - -#include -#include - -#include "authkey-prop.h" - -struct authkey_data { - int ref; - size_t length; -}; - -int pa_authkey_prop_get(pa_core *c, const char *name, void *data, size_t len) { - struct authkey_data *a; - assert(c && name && data && len > 0); - - if (!(a = pa_property_get(c, name))) - return -1; - - assert(a->length == len); - memcpy(data, a+1, len); - return 0; -} - -int pa_authkey_prop_put(pa_core *c, const char *name, const void *data, size_t len) { - struct authkey_data *a; - assert(c && name); - - if (pa_property_get(c, name)) - return -1; - - a = pa_xmalloc(sizeof(struct authkey_data) + len); - a->ref = 1; - a->length = len; - memcpy(a+1, data, len); - - pa_property_set(c, name, a); - - return 0; -} - -void pa_authkey_prop_ref(pa_core *c, const char *name) { - struct authkey_data *a; - assert(c && name); - - a = pa_property_get(c, name); - assert(a && a->ref >= 1); - - a->ref++; -} - -void pa_authkey_prop_unref(pa_core *c, const char *name) { - struct authkey_data *a; - assert(c && name); - - a = pa_property_get(c, name); - assert(a && a->ref >= 1); - - if (!(--a->ref)) { - pa_property_remove(c, name); - pa_xfree(a); - } -} - - diff --git a/src/polypcore/authkey-prop.h b/src/polypcore/authkey-prop.h deleted file mode 100644 index 63fde5d8..00000000 --- a/src/polypcore/authkey-prop.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef fooauthkeyprophfoo -#define fooauthkeyprophfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -/* The authkey-prop uses a central property to store a previously - * loaded cookie in memory. Useful for sharing the same cookie between - * several modules. */ - -/* Return the data of the specified authorization key property. Doesn't alter the refernce count of the key */ -int pa_authkey_prop_get(pa_core *c, const char *name, void *data, size_t len); - -/* Store data in the specified authorization key property. The initial reference count is set to 1 */ -int pa_authkey_prop_put(pa_core *c, const char *name, const void *data, size_t len); - -/* Increase the reference count of the specified authorization key */ -void pa_authkey_prop_ref(pa_core *c, const char *name); - -/* Decrease the reference count of the specified authorization key */ -void pa_authkey_prop_unref(pa_core *c, const char *name); - -#endif diff --git a/src/polypcore/authkey.c b/src/polypcore/authkey.c deleted file mode 100644 index 54f4dd86..00000000 --- a/src/polypcore/authkey.c +++ /dev/null @@ -1,209 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "authkey.h" - -/* Generate a new authorization key, store it in file fd and return it in *data */ -static int generate(int fd, void *ret_data, size_t length) { - ssize_t r; - assert(fd >= 0 && ret_data && length); - - pa_random(ret_data, length); - - lseek(fd, 0, SEEK_SET); - ftruncate(fd, 0); - - if ((r = pa_loop_write(fd, ret_data, length)) < 0 || (size_t) r != length) { - pa_log(__FILE__": failed to write cookie file: %s", pa_cstrerror(errno)); - return -1; - } - - return 0; -} - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -/* Load an euthorization cookie from file fn and store it in data. If - * the cookie file doesn't exist, create it */ -static int load(const char *fn, void *data, size_t length) { - int fd = -1; - int writable = 1; - int unlock = 0, ret = -1; - ssize_t r; - assert(fn && data && length); - - if ((fd = open(fn, O_RDWR|O_CREAT|O_BINARY, S_IRUSR|S_IWUSR)) < 0) { - if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY)) < 0) { - pa_log(__FILE__": failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); - goto finish; - } else - writable = 0; - } - - unlock = pa_lock_fd(fd, 1) >= 0; - - if ((r = pa_loop_read(fd, data, length)) < 0) { - pa_log(__FILE__": failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); - goto finish; - } - - if ((size_t) r != length) { - pa_log_debug(__FILE__": got %d bytes from cookie file '%s', expected %d", (int)r, fn, (int)length); - - if (!writable) { - pa_log(__FILE__": unable to write cookie to read only file"); - goto finish; - } - - if (generate(fd, data, length) < 0) - goto finish; - } - - ret = 0; - -finish: - - if (fd >= 0) { - - if (unlock) - pa_lock_fd(fd, 0); - - close(fd); - } - - return ret; -} - -/* Load a cookie from a cookie file. If the file doesn't exist, create it. */ -int pa_authkey_load(const char *path, void *data, size_t length) { - int ret; - - assert(path && data && length); - - ret = load(path, data, length); - - if (ret < 0) - pa_log(__FILE__": Failed to load authorization key '%s': %s", path, - (ret == -1) ? pa_cstrerror(errno) : "file corrupt"); - - return ret; -} - -/* If the specified file path starts with / return it, otherwise - * return path prepended with home directory */ -static const char *normalize_path(const char *fn, char *s, size_t l) { - assert(fn && s && l > 0); - -#ifndef OS_IS_WIN32 - if (fn[0] != '/') { -#else - if (strlen(fn) < 3 || !isalpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') { -#endif - char homedir[PATH_MAX]; - if (!pa_get_home_dir(homedir, sizeof(homedir))) - return NULL; - -#ifndef OS_IS_WIN32 - snprintf(s, l, "%s/%s", homedir, fn); -#else - snprintf(s, l, "%s\\%s", homedir, fn); -#endif - return s; - } - - return fn; -} - -/* Load a cookie from a file in the home directory. If the specified - * path starts with /, use it as absolute path instead. */ -int pa_authkey_load_auto(const char *fn, void *data, size_t length) { - char path[PATH_MAX]; - const char *p; - assert(fn && data && length); - - if (!(p = normalize_path(fn, path, sizeof(path)))) - return -2; - - return pa_authkey_load(p, data, length); -} - -/* Store the specified cookie in the speicified cookie file */ -int pa_authkey_save(const char *fn, const void *data, size_t length) { - int fd = -1; - int unlock = 0, ret = -1; - ssize_t r; - char path[PATH_MAX]; - const char *p; - assert(fn && data && length); - - if (!(p = normalize_path(fn, path, sizeof(path)))) - return -2; - - if ((fd = open(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { - pa_log(__FILE__": failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); - goto finish; - } - - unlock = pa_lock_fd(fd, 1) >= 0; - - if ((r = pa_loop_write(fd, data, length)) < 0 || (size_t) r != length) { - pa_log(__FILE__": failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); - goto finish; - } - - ret = 0; - -finish: - - if (fd >= 0) { - - if (unlock) - pa_lock_fd(fd, 0); - - close(fd); - } - - return ret; -} diff --git a/src/polypcore/authkey.h b/src/polypcore/authkey.h deleted file mode 100644 index 81b1a578..00000000 --- a/src/polypcore/authkey.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef fooauthkeyhfoo -#define fooauthkeyhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -int pa_authkey_load(const char *path, void *data, size_t len); -int pa_authkey_load_auto(const char *fn, void *data, size_t length); - -int pa_authkey_save(const char *path, const void *data, size_t length); - -#endif diff --git a/src/polypcore/autoload.c b/src/polypcore/autoload.c deleted file mode 100644 index 386de219..00000000 --- a/src/polypcore/autoload.c +++ /dev/null @@ -1,182 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include "autoload.h" - -static void entry_free(pa_autoload_entry *e) { - assert(e); - pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_AUTOLOAD|PA_SUBSCRIPTION_EVENT_REMOVE, PA_INVALID_INDEX); - pa_xfree(e->name); - pa_xfree(e->module); - pa_xfree(e->argument); - pa_xfree(e); -} - -static void entry_remove_and_free(pa_autoload_entry *e) { - assert(e && e->core); - - pa_idxset_remove_by_data(e->core->autoload_idxset, e, NULL); - pa_hashmap_remove(e->core->autoload_hashmap, e->name); - entry_free(e); -} - -static pa_autoload_entry* entry_new(pa_core *c, const char *name) { - pa_autoload_entry *e = NULL; - assert(c && name); - - if (c->autoload_hashmap && (e = pa_hashmap_get(c->autoload_hashmap, name))) - return NULL; - - e = pa_xmalloc(sizeof(pa_autoload_entry)); - e->core = c; - e->name = pa_xstrdup(name); - e->module = e->argument = NULL; - e->in_action = 0; - - if (!c->autoload_hashmap) - c->autoload_hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - assert(c->autoload_hashmap); - - pa_hashmap_put(c->autoload_hashmap, e->name, e); - - if (!c->autoload_idxset) - c->autoload_idxset = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - pa_idxset_put(c->autoload_idxset, e, &e->index); - - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_AUTOLOAD|PA_SUBSCRIPTION_EVENT_NEW, e->index); - - return e; -} - -int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const char*module, const char *argument, uint32_t *idx) { - pa_autoload_entry *e = NULL; - assert(c && name && module && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); - - if (!(e = entry_new(c, name))) - return -1; - - e->module = pa_xstrdup(module); - e->argument = pa_xstrdup(argument); - e->type = type; - - if (idx) - *idx = e->index; - - return 0; -} - -int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type_t type) { - pa_autoload_entry *e; - assert(c && name && type); - - if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type) - return -1; - - entry_remove_and_free(e); - return 0; -} - -int pa_autoload_remove_by_index(pa_core *c, uint32_t idx) { - pa_autoload_entry *e; - assert(c && idx != PA_IDXSET_INVALID); - - if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, idx))) - return -1; - - entry_remove_and_free(e); - return 0; -} - -void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type_t type) { - pa_autoload_entry *e; - pa_module *m; - assert(c && name); - - if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || (e->type != type)) - return; - - if (e->in_action) - return; - - e->in_action = 1; - - if (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE) { - if ((m = pa_module_load(c, e->module, e->argument))) - m->auto_unload = 1; - } - - e->in_action = 0; -} - -static void free_func(void *p, PA_GCC_UNUSED void *userdata) { - pa_autoload_entry *e = p; - pa_idxset_remove_by_data(e->core->autoload_idxset, e, NULL); - entry_free(e); -} - -void pa_autoload_free(pa_core *c) { - if (c->autoload_hashmap) { - pa_hashmap_free(c->autoload_hashmap, free_func, NULL); - c->autoload_hashmap = NULL; - } - - if (c->autoload_idxset) { - pa_idxset_free(c->autoload_idxset, NULL, NULL); - c->autoload_idxset = NULL; - } -} - -const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type_t type) { - pa_autoload_entry *e; - assert(c && name); - - if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type) - return NULL; - - return e; -} - -const pa_autoload_entry* pa_autoload_get_by_index(pa_core *c, uint32_t idx) { - pa_autoload_entry *e; - assert(c && idx != PA_IDXSET_INVALID); - - if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, idx))) - return NULL; - - return e; -} diff --git a/src/polypcore/autoload.h b/src/polypcore/autoload.h deleted file mode 100644 index a8931fc7..00000000 --- a/src/polypcore/autoload.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef fooautoloadhfoo -#define fooautoloadhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -/* Using the autoloading facility, modules by be loaded on-demand and - * synchronously. The user may register a "ghost sink" or "ghost - * source". Whenever this sink/source is requested but not available a - * specified module is loaded. */ - -/* An autoload entry, or "ghost" sink/source */ -typedef struct pa_autoload_entry { - pa_core *core; - uint32_t index; - char *name; - pa_namereg_type_t type; /* Type of the autoload entry */ - int in_action; /* Currently loaded */ - char *module, *argument; -} pa_autoload_entry; - -/* Add a new autoload entry of the given time, with the speicified - * sink/source name, module name and argument. Return the entry's - * index in *index */ -int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const char*module, const char *argument, uint32_t *idx); - -/* Free all autoload entries */ -void pa_autoload_free(pa_core *c); -int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type_t type); -int pa_autoload_remove_by_index(pa_core *c, uint32_t idx); - -/* Request an autoload entry by its name, effectively causing a module to be loaded */ -void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type_t type); - -const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type_t type); -const pa_autoload_entry* pa_autoload_get_by_index(pa_core *c, uint32_t idx); - -#endif diff --git a/src/polypcore/cli-command.c b/src/polypcore/cli-command.c deleted file mode 100644 index e25e464c..00000000 --- a/src/polypcore/cli-command.c +++ /dev/null @@ -1,947 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cli-command.h" - -struct command { - const char *name; - int (*proc) (pa_core *c, pa_tokenizer*t, pa_strbuf *buf, int *fail); - const char *help; - unsigned args; -}; - -#define INCLUDE_META ".include" -#define FAIL_META ".fail" -#define NOFAIL_META ".nofail" - -/* Prototypes for all available commands */ -static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); - - -/* A method table for all available commands */ - -static const struct command commands[] = { - { "exit", pa_cli_command_exit, "Terminate the daemon", 1 }, - { "help", pa_cli_command_help, "Show this help", 1 }, - { "list-modules", pa_cli_command_modules, "List loaded modules", 1 }, - { "list-sinks", pa_cli_command_sinks, "List loaded sinks", 1 }, - { "list-sources", pa_cli_command_sources, "List loaded sources", 1 }, - { "list-clients", pa_cli_command_clients, "List loaded clients", 1 }, - { "list-sink-inputs", pa_cli_command_sink_inputs, "List sink inputs", 1 }, - { "list-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-module", pa_cli_command_load, "Load a module (args: name, arguments)", 3}, - { "unload-module", pa_cli_command_unload, "Unload a module (args: index)", 2}, - { "set-sink-volume", pa_cli_command_sink_volume, "Set the volume of a sink (args: index|name, volume)", 3}, - { "set-sink-input-volume", pa_cli_command_sink_input_volume, "Set the volume of a sink input (args: index|name, volume)", 3}, - { "set-source-volume", pa_cli_command_source_volume, "Set the volume of a source (args: index|name, volume)", 3}, - { "set-sink-mute", pa_cli_command_sink_mute, "Set the mute switch of a sink (args: index|name, mute)", 3}, - { "set-source-mute", pa_cli_command_source_mute, "Set the mute switch of a source (args: index|name, mute)", 3}, - { "set-default-sink", pa_cli_command_sink_default, "Set the default sink (args: index|name)", 2}, - { "set-default-source", 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}, - { "list-samples", pa_cli_command_scache_list, "List all entries in the sample cache", 1}, - { "play-sample", pa_cli_command_scache_play, "Play a sample from the sample cache (args: name, sink|index)", 3}, - { "remove-sample", pa_cli_command_scache_remove, "Remove a sample from the sample cache (args: name)", 2}, - { "load-sample", pa_cli_command_scache_load, "Load a sound file into the sample cache (args: name, filename)", 3}, - { "load-sample-lazy", pa_cli_command_scache_load, "Lazily load a sound file into the sample cache (args: name, filename)", 3}, - { "load-sample-dir-lazy", pa_cli_command_scache_load_dir, "Lazily load all files in a directory into the sample cache (args: pathname)", 2}, - { "play-file", pa_cli_command_play_file, "Play a sound file (args: filename, sink|index)", 3}, - { "list-autoload", pa_cli_command_autoload_list, "List autoload entries", 1}, - { "add-autoload-sink", pa_cli_command_autoload_add, "Add autoload entry for a sink (args: sink, module name, arguments)", 4}, - { "add-autoload-source", pa_cli_command_autoload_add, "Add autoload entry for a source (args: source, module name, arguments)", 4}, - { "remove-autoload-sink", pa_cli_command_autoload_remove, "Remove autoload entry for a sink (args: name)", 2}, - { "remove-autoload-source", pa_cli_command_autoload_remove, "Remove autoload entry for a source (args: name)", 2}, - { "dump", pa_cli_command_dump, "Dump daemon configuration", 1}, - { "list-props", pa_cli_command_list_props, NULL, 1}, - { 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) { - uint32_t idx; - - if (pa_atou(n, &idx) < 0) - return (uint32_t) PA_IDXSET_INVALID; - - return idx; -} - -static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, PA_GCC_UNUSED pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - assert(c && c->mainloop && t); - c->mainloop->quit(c->mainloop, 0); - return 0; -} - -static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - 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, " %-25s %s\n", command->name, command->help); - return 0; -} - -static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - char *s; - assert(c && t); - s = pa_module_list_to_string(c); - assert(s); - pa_strbuf_puts(buf, s); - pa_xfree(s); - return 0; -} - -static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - char *s; - assert(c && t); - s = pa_client_list_to_string(c); - assert(s); - pa_strbuf_puts(buf, s); - pa_xfree(s); - return 0; -} - -static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - char *s; - assert(c && t); - s = pa_sink_list_to_string(c); - assert(s); - pa_strbuf_puts(buf, s); - pa_xfree(s); - return 0; -} - -static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - char *s; - assert(c && t); - s = pa_source_list_to_string(c); - assert(s); - pa_strbuf_puts(buf, s); - pa_xfree(s); - return 0; -} - -static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - char *s; - assert(c && t); - s = pa_sink_input_list_to_string(c); - assert(s); - pa_strbuf_puts(buf, s); - pa_xfree(s); - return 0; -} - -static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - char *s; - assert(c && t); - s = pa_source_output_list_to_string(c); - assert(s); - pa_strbuf_puts(buf, s); - pa_xfree(s); - return 0; -} - -static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - char s[256]; - assert(c && t); - - pa_bytes_snprint(s, sizeof(s), c->memblock_stat->total_size); - pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n", - c->memblock_stat->total, - s); - - pa_bytes_snprint(s, sizeof(s), c->memblock_stat->allocated_size); - pa_strbuf_printf(buf, "Memory blocks allocated during the whole lifetime: %u, size: %s.\n", - c->memblock_stat->allocated, - s); - - pa_bytes_snprint(s, sizeof(s), pa_scache_total_size(c)); - pa_strbuf_printf(buf, "Total sample cache size: %s.\n", s); - - pa_sample_spec_snprint(s, sizeof(s), &c->default_sample_spec); - pa_strbuf_printf(buf, "Default sample spec: %s\n", s); - - pa_strbuf_printf(buf, "Default sink name: %s\n" - "Default source name: %s\n", - pa_namereg_get_default_sink_name(c), - pa_namereg_get_default_source_name(c)); - - return 0; -} - -static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { - assert(c && t); - pa_cli_command_stat(c, t, buf, fail); - pa_cli_command_modules(c, t, buf, fail); - pa_cli_command_sinks(c, t, buf, fail); - pa_cli_command_sources(c, t, buf, fail); - pa_cli_command_clients(c, t, buf, fail); - pa_cli_command_sink_inputs(c, t, buf, fail); - pa_cli_command_source_outputs(c, t, buf, fail); - pa_cli_command_scache_list(c, t, buf, fail); - pa_cli_command_autoload_list(c, t, buf, fail); - return 0; -} - -static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - pa_module *m; - const char *name; - 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; - } - - return 0; -} - -static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - pa_module *m; - uint32_t idx; - 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; - } - - idx = (uint32_t) strtoul(i, &e, 10); - if (*e || !(m = pa_idxset_get_by_index(c->modules, idx))) { - pa_strbuf_puts(buf, "Invalid module index.\n"); - return -1; - } - - pa_module_unload_request(m); - return 0; -} - -static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - const char *n, *v; - pa_sink *sink; - uint32_t volume; - pa_cvolume cvolume; - - 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; - } - - if (pa_atou(v, &volume) < 0) { - pa_strbuf_puts(buf, "Failed to parse volume.\n"); - return -1; - } - - if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) { - pa_strbuf_puts(buf, "No sink found by this name or index.\n"); - return -1; - } - - pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume); - pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &cvolume); - return 0; -} - -static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - const char *n, *v; - pa_sink_input *si; - pa_volume_t volume; - pa_cvolume cvolume; - uint32_t idx; - - 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 ((idx = 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; - } - - if (pa_atou(v, &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) idx))) { - pa_strbuf_puts(buf, "No sink input found with this index.\n"); - return -1; - } - - pa_cvolume_set(&cvolume, si->sample_spec.channels, volume); - pa_sink_input_set_volume(si, &cvolume); - return 0; -} - -static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - const char *n, *v; - pa_source *source; - uint32_t volume; - pa_cvolume cvolume; - - 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 (!(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; - } - - if (pa_atou(v, &volume) < 0) { - pa_strbuf_puts(buf, "Failed to parse volume.\n"); - return -1; - } - - if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE, 1))) { - pa_strbuf_puts(buf, "No source found by this name or index.\n"); - return -1; - } - - pa_cvolume_set(&cvolume, source->sample_spec.channels, volume); - pa_source_set_volume(source, PA_MIXER_HARDWARE, &cvolume); - return 0; -} - -static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - const char *n, *m; - pa_sink *sink; - int mute; - - 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 (!(m = pa_tokenizer_get(t, 2))) { - pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n"); - return -1; - } - - if (pa_atoi(m, &mute) < 0) { - pa_strbuf_puts(buf, "Failed to parse mute switch.\n"); - return -1; - } - - if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) { - pa_strbuf_puts(buf, "No sink found by this name or index.\n"); - return -1; - } - - pa_sink_set_mute(sink, PA_MIXER_HARDWARE, mute); - return 0; -} - -static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - const char *n, *m; - pa_source *source; - int mute; - - 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 (!(m = pa_tokenizer_get(t, 2))) { - pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n"); - return -1; - } - - if (pa_atoi(m, &mute) < 0) { - pa_strbuf_puts(buf, "Failed to parse mute switch.\n"); - return -1; - } - - if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE, 1))) { - pa_strbuf_puts(buf, "No sink found by this name or index.\n"); - return -1; - } - - pa_source_set_mute(source, PA_MIXER_HARDWARE, mute); - return 0; -} - -static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - const char *n; - 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; - } - - pa_namereg_set_default(c, n, PA_NAMEREG_SINK); - return 0; -} - -static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - const char *n; - 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; - } - - pa_namereg_set_default(c, n, PA_NAMEREG_SOURCE); - return 0; -} - -static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - const char *n; - pa_client *client; - uint32_t idx; - 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 ((idx = 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, idx))) { - 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(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - const char *n; - pa_sink_input *sink_input; - uint32_t idx; - 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 ((idx = 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, idx))) { - 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(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - const char *n; - pa_source_output *source_output; - uint32_t idx; - 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 ((idx = 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, idx))) { - pa_strbuf_puts(buf, "No source output found by this index.\n"); - return -1; - } - - pa_source_output_kill(source_output); - return 0; -} - -static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - char *s; - assert(c && t); - s = pa_scache_list_to_string(c); - assert(s); - pa_strbuf_puts(buf, s); - pa_xfree(s); - return 0; -} - -static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { - const char *n, *sink_name; - pa_sink *sink; - assert(c && t && buf && fail); - - if (!(n = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) { - pa_strbuf_puts(buf, "You need to specify a sample name and a sink name.\n"); - return -1; - } - - if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) { - pa_strbuf_puts(buf, "No sink by that name.\n"); - return -1; - } - - if (pa_scache_play_item(c, n, sink, PA_VOLUME_NORM) < 0) { - pa_strbuf_puts(buf, "Failed to play sample.\n"); - return -1; - } - - return 0; -} - -static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { - const char *n; - assert(c && t && buf && fail); - - if (!(n = pa_tokenizer_get(t, 1))) { - pa_strbuf_puts(buf, "You need to specify a sample name.\n"); - return -1; - } - - if (pa_scache_remove_item(c, n) < 0) { - pa_strbuf_puts(buf, "Failed to remove sample.\n"); - return -1; - } - - return 0; -} - -static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { - const char *fname, *n; - int r; - assert(c && t && buf && fail); - - if (!(fname = pa_tokenizer_get(t, 2)) || !(n = pa_tokenizer_get(t, 1))) { - pa_strbuf_puts(buf, "You need to specify a file name and a sample name.\n"); - return -1; - } - - if (strstr(pa_tokenizer_get(t, 0), "lazy")) - r = pa_scache_add_file_lazy(c, n, fname, NULL); - else - r = pa_scache_add_file(c, n, fname, NULL); - - if (r < 0) - pa_strbuf_puts(buf, "Failed to load sound file.\n"); - - return 0; -} - -static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { - const char *pname; - assert(c && t && buf && fail); - - if (!(pname = pa_tokenizer_get(t, 1))) { - pa_strbuf_puts(buf, "You need to specify a path name.\n"); - return -1; - } - - if (pa_scache_add_directory_lazy(c, pname) < 0) { - pa_strbuf_puts(buf, "Failed to load directory.\n"); - return -1; - } - - return 0; -} - -static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { - const char *fname, *sink_name; - pa_sink *sink; - assert(c && t && buf && fail); - - if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) { - pa_strbuf_puts(buf, "You need to specify a file name and a sink name.\n"); - return -1; - } - - if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) { - pa_strbuf_puts(buf, "No sink by that name.\n"); - return -1; - } - - - return pa_play_file(sink, fname, NULL); -} - -static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { - const char *a, *b; - assert(c && t && buf && fail); - - if (!(a = pa_tokenizer_get(t, 1)) || !(b = pa_tokenizer_get(t, 2))) { - pa_strbuf_puts(buf, "You need to specify a device name, a filename or a module name and optionally module arguments\n"); - return -1; - } - - pa_autoload_add(c, a, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, b, pa_tokenizer_get(t, 3), NULL); - - return 0; -} - -static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { - const char *name; - assert(c && t && buf && fail); - - if (!(name = pa_tokenizer_get(t, 1))) { - pa_strbuf_puts(buf, "You need to specify a device name\n"); - return -1; - } - - if (pa_autoload_remove_by_name(c, name, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE) < 0) { - pa_strbuf_puts(buf, "Failed to remove autload entry\n"); - return -1; - } - - return 0; -} - -static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - char *s; - assert(c && t); - s = pa_autoload_list_to_string(c); - assert(s); - pa_strbuf_puts(buf, s); - pa_xfree(s); - return 0; -} - -static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - assert(c && t); - pa_property_dump(c, buf); - return 0; -} - -static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - pa_module *m; - pa_sink *sink; - pa_source *source; - int nl; - const char *p; - uint32_t idx; - char txt[256]; - time_t now; - void *i; - pa_autoload_entry *a; - - assert(c && t); - - time(&now); - -#ifdef HAVE_CTIME_R - pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime_r(&now, txt)); -#else - pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now)); -#endif - - - for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) { - if (m->auto_unload) - continue; - - pa_strbuf_printf(buf, "load-module %s", m->name); - - if (m->argument) - pa_strbuf_printf(buf, " %s", m->argument); - - pa_strbuf_puts(buf, "\n"); - } - - nl = 0; - - for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) { - if (sink->owner && sink->owner->auto_unload) - continue; - - if (!nl) { - pa_strbuf_puts(buf, "\n"); - nl = 1; - } - - pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, PA_MIXER_HARDWARE))); - pa_strbuf_printf(buf, "set-sink-mute %s %d\n", sink->name, pa_sink_get_mute(sink, PA_MIXER_HARDWARE)); - } - - for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) { - if (source->owner && source->owner->auto_unload) - continue; - - if (!nl) { - pa_strbuf_puts(buf, "\n"); - nl = 1; - } - - pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_avg(pa_source_get_volume(source, PA_MIXER_HARDWARE))); - pa_strbuf_printf(buf, "set-source-mute %s %d\n", source->name, pa_source_get_mute(source, PA_MIXER_HARDWARE)); - } - - - if (c->autoload_hashmap) { - nl = 0; - - i = NULL; - while ((a = pa_hashmap_iterate(c->autoload_hashmap, &i, NULL))) { - - if (!nl) { - pa_strbuf_puts(buf, "\n"); - nl = 1; - } - - pa_strbuf_printf(buf, "add-autoload-%s %s %s", a->type == PA_NAMEREG_SINK ? "sink" : "source", a->name, a->module); - - if (a->argument) - pa_strbuf_printf(buf, " %s", a->argument); - - pa_strbuf_puts(buf, "\n"); - } - } - - nl = 0; - - if ((p = pa_namereg_get_default_sink_name(c))) { - if (!nl) { - pa_strbuf_puts(buf, "\n"); - nl = 1; - } - pa_strbuf_printf(buf, "set-default-sink %s\n", p); - } - - if ((p = pa_namereg_get_default_source_name(c))) { - if (!nl) { - pa_strbuf_puts(buf, "\n"); - nl = 1; - } - pa_strbuf_printf(buf, "set-default-source %s\n", p); - } - - pa_strbuf_puts(buf, "\n### EOF\n"); - - return 0; -} - - -int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { - const char *cs; - - cs = s+strspn(s, whitespace); - - if (*cs == '#' || !*cs) - return 0; - else if (*cs == '.') { - if (!strcmp(cs, FAIL_META)) - *fail = 1; - else if (!strcmp(cs, NOFAIL_META)) - *fail = 0; - else { - size_t l; - 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) < 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; - pa_tokenizer *t = pa_tokenizer_new(cs, command->args); - assert(t); - ret = command->proc(c, t, buf, fail); - 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(pa_core *c, const char *fn, pa_strbuf *buf, int *fail) { - 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, pa_cstrerror(errno)); - if (!*fail) - ret = 0; - goto fail; - } - - while (fgets(line, sizeof(line), f)) { - char *e = line + strcspn(line, linebreak); - *e = 0; - - if (pa_cli_command_execute_line(c, line, buf, fail) < 0 && *fail) - goto fail; - } - - ret = 0; - -fail: - if (f) - fclose(f); - - return ret; -} - -int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { - const char *p; - assert(c && s && buf && fail); - - p = s; - while (*p) { - size_t l = strcspn(p, linebreak); - char *line = pa_xstrndup(p, l); - - if (pa_cli_command_execute_line(c, line, buf, fail) < 0&& *fail) { - pa_xfree(line); - return -1; - } - pa_xfree(line); - - p += l; - p += strspn(p, linebreak); - } - - return 0; -} diff --git a/src/polypcore/cli-command.h b/src/polypcore/cli-command.h deleted file mode 100644 index e7c70ecf..00000000 --- a/src/polypcore/cli-command.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef fooclicommandhfoo -#define fooclicommandhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -/* Execute a single CLI command. Write the results to the string - * buffer *buf. If *fail is non-zero the function will return -1 when - * one or more of the executed commands failed. *fail - * may be modified by the function call. */ -int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail); - -/* Execute a whole file of CLI commands */ -int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int *fail); - -/* Split the specified string into lines and run pa_cli_command_execute_line() for each. */ -int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail); - -#endif diff --git a/src/polypcore/cli-text.c b/src/polypcore/cli-text.c deleted file mode 100644 index 09ccaa00..00000000 --- a/src/polypcore/cli-text.c +++ /dev/null @@ -1,387 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cli-text.h" - -char *pa_module_list_to_string(pa_core *c) { - pa_strbuf *s; - pa_module *m; - uint32_t idx = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_size(c->modules)); - - for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) - pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\targument: <%s>\n\tused: %i\n\tauto unload: %s\n", m->index, m->name, m->argument, m->n_used, m->auto_unload ? "yes" : "no"); - - return pa_strbuf_tostring_free(s); -} - -char *pa_client_list_to_string(pa_core *c) { - pa_strbuf *s; - pa_client *client; - uint32_t idx = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u client(s) logged in.\n", pa_idxset_size(c->clients)); - - for (client = pa_idxset_first(c->clients, &idx); client; client = pa_idxset_next(c->clients, &idx)) { - pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\tdriver: <%s>\n", client->index, client->name, client->driver); - - if (client->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", client->owner->index); - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_sink_list_to_string(pa_core *c) { - pa_strbuf *s; - pa_sink *sink; - uint32_t idx = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_size(c->sinks)); - - for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) { - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - - pa_strbuf_printf( - s, - " %c index: %u\n" - "\tname: <%s>\n" - "\tdriver: <%s>\n" - "\tvolume: <%s>\n" - "\tlatency: <%0.0f usec>\n" - "\tmonitor_source: <%u>\n" - "\tsample spec: <%s>\n" - "\tchannel map: <%s>\n", - c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ', - sink->index, sink->name, - sink->driver, - pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, PA_MIXER_HARDWARE)), - (double) pa_sink_get_latency(sink), - sink->monitor_source->index, - pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec), - pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map)); - - if (sink->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", sink->owner->index); - if (sink->description) - pa_strbuf_printf(s, "\tdescription: <%s>\n", sink->description); - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_source_list_to_string(pa_core *c) { - pa_strbuf *s; - pa_source *source; - uint32_t idx = PA_IDXSET_INVALID; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_size(c->sources)); - - for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) { - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - - - pa_strbuf_printf( - s, - " %c index: %u\n" - "\tname: <%s>\n" - "\tdriver: <%s>\n" - "\tlatency: <%0.0f usec>\n" - "\tsample spec: <%s>\n" - "\tchannel map: <%s>\n", - c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ', - source->index, - source->name, - source->driver, - (double) pa_source_get_latency(source), - pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec), - pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map)); - - if (source->monitor_of) - pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index); - if (source->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", source->owner->index); - if (source->description) - pa_strbuf_printf(s, "\tdescription: <%s>\n", source->description); - } - - return pa_strbuf_tostring_free(s); -} - - -char *pa_source_output_list_to_string(pa_core *c) { - pa_strbuf *s; - pa_source_output *o; - uint32_t idx = PA_IDXSET_INVALID; - static const char* const state_table[] = { - "RUNNING", - "CORKED", - "DISCONNECTED" - }; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_size(c->source_outputs)); - - for (o = pa_idxset_first(c->source_outputs, &idx); o; o = pa_idxset_next(c->source_outputs, &idx)) { - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - - assert(o->source); - - pa_strbuf_printf( - s, - " index: %u\n" - "\tname: '%s'\n" - "\tdriver: <%s>\n" - "\tstate: %s\n" - "\tsource: <%u> '%s'\n" - "\tsample spec: <%s>\n" - "\tchannel map: <%s>\n" - "\tresample method: %s\n", - o->index, - o->name, - o->driver, - state_table[o->state], - o->source->index, o->source->name, - pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec), - pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map), - pa_resample_method_to_string(pa_source_output_get_resample_method(o))); - if (o->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", o->owner->index); - if (o->client) - pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", o->client->index, o->client->name); - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_sink_input_list_to_string(pa_core *c) { - pa_strbuf *s; - pa_sink_input *i; - uint32_t idx = PA_IDXSET_INVALID; - static const char* const state_table[] = { - "RUNNING", - "CORKED", - "DISCONNECTED" - }; - - assert(c); - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_size(c->sink_inputs)); - - for (i = pa_idxset_first(c->sink_inputs, &idx); i; i = pa_idxset_next(c->sink_inputs, &idx)) { - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - - assert(i->sink); - - pa_strbuf_printf( - s, - " index: %u\n" - "\tname: <%s>\n" - "\tdriver: <%s>\n" - "\tstate: %s\n" - "\tsink: <%u> '%s'\n" - "\tvolume: <%s>\n" - "\tlatency: <%0.0f usec>\n" - "\tsample spec: <%s>\n" - "\tchannel map: <%s>\n" - "\tresample method: %s\n", - i->index, - i->name, - i->driver, - state_table[i->state], - i->sink->index, i->sink->name, - pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)), - (double) pa_sink_input_get_latency(i), - pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec), - pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), - pa_resample_method_to_string(pa_sink_input_get_resample_method(i))); - - if (i->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", i->owner->index); - if (i->client) - pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", i->client->index, i->client->name); - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_scache_list_to_string(pa_core *c) { - pa_strbuf *s; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u cache entries available.\n", c->scache ? pa_idxset_size(c->scache) : 0); - - if (c->scache) { - pa_scache_entry *e; - uint32_t idx = PA_IDXSET_INVALID; - - for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) { - double l = 0; - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = "n/a", cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX] = "n/a"; - - if (e->memchunk.memblock) { - pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec); - pa_channel_map_snprint(cm, sizeof(cm), &e->channel_map); - l = (double) e->memchunk.length / pa_bytes_per_second(&e->sample_spec); - } - - pa_strbuf_printf( - s, - " name: <%s>\n" - "\tindex: <%u>\n" - "\tsample spec: <%s>\n" - "\tchannel map: <%s>\n" - "\tlength: <%lu>\n" - "\tduration: <%0.1fs>\n" - "\tvolume: <%s>\n" - "\tlazy: %s\n" - "\tfilename: %s\n", - e->name, - e->index, - ss, - cm, - (long unsigned)(e->memchunk.memblock ? e->memchunk.length : 0), - l, - pa_cvolume_snprint(cv, sizeof(cv), &e->volume), - e->lazy ? "yes" : "no", - e->filename ? e->filename : "n/a"); - } - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_autoload_list_to_string(pa_core *c) { - pa_strbuf *s; - assert(c); - - s = pa_strbuf_new(); - assert(s); - - pa_strbuf_printf(s, "%u autoload entries available.\n", c->autoload_hashmap ? pa_hashmap_size(c->autoload_hashmap) : 0); - - if (c->autoload_hashmap) { - pa_autoload_entry *e; - void *state = NULL; - - while ((e = pa_hashmap_iterate(c->autoload_hashmap, &state, NULL))) { - pa_strbuf_printf( - s, " name: <%s>\n\ttype: <%s>\n\tindex: <%u>\n\tmodule_name: <%s>\n\targuments: <%s>\n", - e->name, - e->type == PA_NAMEREG_SOURCE ? "source" : "sink", - e->index, - e->module, - e->argument); - - } - } - - return pa_strbuf_tostring_free(s); -} - -char *pa_full_status_string(pa_core *c) { - pa_strbuf *s; - int i; - - s = pa_strbuf_new(); - - for (i = 0; i < 8; i++) { - char *t = NULL; - - switch (i) { - case 0: - t = pa_sink_list_to_string(c); - break; - case 1: - t = pa_source_list_to_string(c); - break; - case 2: - t = pa_sink_input_list_to_string(c); - break; - case 3: - t = pa_source_output_list_to_string(c); - break; - case 4: - t = pa_client_list_to_string(c); - break; - case 5: - t = pa_module_list_to_string(c); - break; - case 6: - t = pa_scache_list_to_string(c); - break; - case 7: - t = pa_autoload_list_to_string(c); - break; - } - - pa_strbuf_puts(s, t); - pa_xfree(t); - } - - return pa_strbuf_tostring_free(s); -} diff --git a/src/polypcore/cli-text.h b/src/polypcore/cli-text.h deleted file mode 100644 index a8f40003..00000000 --- a/src/polypcore/cli-text.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef fooclitexthfoo -#define fooclitexthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -/* Some functions to generate pretty formatted listings of - * entities. The returned strings have to be freed manually. */ - -char *pa_sink_input_list_to_string(pa_core *c); -char *pa_source_output_list_to_string(pa_core *c); -char *pa_sink_list_to_string(pa_core *core); -char *pa_source_list_to_string(pa_core *c); -char *pa_client_list_to_string(pa_core *c); -char *pa_module_list_to_string(pa_core *c); -char *pa_scache_list_to_string(pa_core *c); -char *pa_autoload_list_to_string(pa_core *c); - -char *pa_full_status_string(pa_core *c); - -#endif - diff --git a/src/polypcore/cli.c b/src/polypcore/cli.c deleted file mode 100644 index 683d29ec..00000000 --- a/src/polypcore/cli.c +++ /dev/null @@ -1,149 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cli.h" - -#define PROMPT ">>> " - -struct pa_cli { - pa_core *core; - pa_ioline *line; - - void (*eof_callback)(pa_cli *c, void *userdata); - void *userdata; - - pa_client *client; - - int fail, kill_requested, defer_kill; -}; - -static void line_callback(pa_ioline *line, const char *s, void *userdata); -static void client_kill(pa_client *c); - -pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m) { - char cname[256]; - pa_cli *c; - assert(io); - - c = pa_xmalloc(sizeof(pa_cli)); - c->core = core; - c->line = pa_ioline_new(io); - assert(c->line); - - c->userdata = NULL; - c->eof_callback = NULL; - - pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); - c->client = pa_client_new(core, __FILE__, cname); - assert(c->client); - c->client->kill = client_kill; - c->client->userdata = c; - c->client->owner = m; - - pa_ioline_set_callback(c->line, line_callback, c); - pa_ioline_puts(c->line, "Welcome to polypaudio! Use \"help\" for usage information.\n"PROMPT); - - c->fail = c->kill_requested = c->defer_kill = 0; - - return c; -} - -void pa_cli_free(pa_cli *c) { - assert(c); - pa_ioline_close(c->line); - pa_ioline_unref(c->line); - pa_client_free(c->client); - pa_xfree(c); -} - -static void client_kill(pa_client *client) { - pa_cli *c; - assert(client && client->userdata); - c = client->userdata; - - pa_log_debug(__FILE__": CLI client killed."); - if (c->defer_kill) - c->kill_requested = 1; - else { - if (c->eof_callback) - c->eof_callback(c, c->userdata); - } -} - -static void line_callback(pa_ioline *line, const char *s, void *userdata) { - pa_strbuf *buf; - pa_cli *c = userdata; - char *p; - assert(line && c); - - if (!s) { - pa_log_debug(__FILE__": CLI got EOF from user."); - if (c->eof_callback) - c->eof_callback(c, c->userdata); - - return; - } - - buf = pa_strbuf_new(); - assert(buf); - c->defer_kill++; - pa_cli_command_execute_line(c->core, s, buf, &c->fail); - c->defer_kill--; - pa_ioline_puts(line, p = pa_strbuf_tostring_free(buf)); - pa_xfree(p); - - 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(pa_cli *c, void (*cb)(pa_cli*c, void *userdata), void *userdata) { - assert(c); - c->eof_callback = cb; - c->userdata = userdata; -} diff --git a/src/polypcore/cli.h b/src/polypcore/cli.h deleted file mode 100644 index 12ffd848..00000000 --- a/src/polypcore/cli.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef fooclihfoo -#define fooclihfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include - -typedef struct pa_cli pa_cli; - -/* Create a new command line session on the specified io channel owned by the specified module */ -pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m); -void pa_cli_free(pa_cli *cli); - -/* Set a callback function that is called whenever the command line session is terminated */ -void pa_cli_set_eof_callback(pa_cli *cli, void (*cb)(pa_cli*c, void *userdata), void *userdata); - -#endif diff --git a/src/polypcore/client.c b/src/polypcore/client.c deleted file mode 100644 index 4ece07a8..00000000 --- a/src/polypcore/client.c +++ /dev/null @@ -1,96 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -#include -#include - -#include "client.h" - -pa_client *pa_client_new(pa_core *core, const char *driver, const char *name) { - pa_client *c; - int r; - assert(core); - - c = pa_xmalloc(sizeof(pa_client)); - c->name = pa_xstrdup(name); - c->driver = pa_xstrdup(driver); - c->owner = NULL; - c->core = core; - - c->kill = NULL; - c->userdata = NULL; - - r = pa_idxset_put(core->clients, c, &c->index); - assert(c->index != PA_IDXSET_INVALID && r >= 0); - - pa_log_info(__FILE__": created %u \"%s\"", c->index, c->name); - pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index); - - pa_core_check_quit(core); - - return c; -} - -void pa_client_free(pa_client *c) { - assert(c && c->core); - - pa_idxset_remove_by_data(c->core->clients, c, NULL); - - pa_core_check_quit(c->core); - - pa_log_info(__FILE__": freed %u \"%s\"", c->index, c->name); - pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index); - pa_xfree(c->name); - pa_xfree(c->driver); - pa_xfree(c); -} - -void pa_client_kill(pa_client *c) { - assert(c); - if (!c->kill) { - pa_log_warn(__FILE__": kill() operation not implemented for client %u", c->index); - return; - } - - c->kill(c); -} - -void pa_client_set_name(pa_client *c, const char *name) { - assert(c); - - pa_log_info(__FILE__": client %u changed name from \"%s\" to \"%s\"", c->index, c->name, name); - - pa_xfree(c->name); - c->name = pa_xstrdup(name); - - pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->index); -} diff --git a/src/polypcore/client.h b/src/polypcore/client.h deleted file mode 100644 index f6ff935d..00000000 --- a/src/polypcore/client.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef fooclienthfoo -#define fooclienthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -/* Every connection to the server should have a pa_client - * attached. That way the user may generate a listing of all connected - * clients easily and kill them if he wants.*/ - -typedef struct pa_client pa_client; - -struct pa_client { - uint32_t index; - - pa_module *owner; - char *name, *driver; - pa_core *core; - - void (*kill)(pa_client *c); - void *userdata; -}; - -pa_client *pa_client_new(pa_core *c, const char *driver, const char *name); - -/* This function should be called only by the code that created the client */ -void pa_client_free(pa_client *c); - -/* Code that didn't create the client should call this function to - * request destruction of the client */ -void pa_client_kill(pa_client *c); - -/* Rename the client */ -void pa_client_set_name(pa_client *c, const char *name); - -#endif diff --git a/src/polypcore/conf-parser.c b/src/polypcore/conf-parser.c deleted file mode 100644 index d59bc555..00000000 --- a/src/polypcore/conf-parser.c +++ /dev/null @@ -1,181 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "conf-parser.h" - -#define WHITESPACE " \t\n" -#define COMMENTS "#;\n" - -/* Run the user supplied parser for an assignment */ -static int next_assignment(const char *filename, unsigned line, const pa_config_item *t, const char *lvalue, const char *rvalue, void *userdata) { - assert(filename && t && lvalue && rvalue); - - for (; t->parse; t++) - if (!strcmp(lvalue, t->lvalue)) - return t->parse(filename, line, lvalue, rvalue, t->data, userdata); - - pa_log(__FILE__": [%s:%u] Unknown lvalue '%s'.", filename, line, lvalue); - - return -1; -} - -/* Returns non-zero when c is contained in s */ -static int in_string(char c, const char *s) { - assert(s); - - for (; *s; s++) - if (*s == c) - return 1; - - return 0; -} - -/* Remove all whitepsapce from the beginning and the end of *s. *s may - * be modified. */ -static char *strip(char *s) { - char *b = s+strspn(s, WHITESPACE); - char *e, *l = NULL; - - for (e = b; *e; e++) - if (!in_string(*e, WHITESPACE)) - l = e; - - if (l) - *(l+1) = 0; - - return b; -} - -/* Parse a variable assignment line */ -static int parse_line(const char *filename, unsigned line, const pa_config_item *t, char *l, void *userdata) { - char *e, *c, *b = l+strspn(l, WHITESPACE); - - if ((c = strpbrk(b, COMMENTS))) - *c = 0; - - if (!*b) - return 0; - - if (!(e = strchr(b, '='))) { - pa_log(__FILE__": [%s:%u] Missing '='.", filename, line); - return -1; - } - - *e = 0; - e++; - - return next_assignment(filename, line, t, strip(b), strip(e), userdata); -} - -/* Go through the file and parse each line */ -int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void *userdata) { - int r = -1; - unsigned line = 0; - int do_close = !f; - assert(filename && t); - - if (!f && !(f = fopen(filename, "r"))) { - if (errno == ENOENT) { - r = 0; - goto finish; - } - - pa_log_warn(__FILE__": WARNING: failed to open configuration file '%s': %s", - filename, pa_cstrerror(errno)); - goto finish; - } - - while (!feof(f)) { - char l[256]; - if (!fgets(l, sizeof(l), f)) { - if (feof(f)) - break; - - pa_log_warn(__FILE__": WARNING: failed to read configuration file '%s': %s", - filename, pa_cstrerror(errno)); - goto finish; - } - - if (parse_line(filename, ++line, t, l, userdata) < 0) - goto finish; - } - - r = 0; - -finish: - - if (do_close && f) - fclose(f); - - return r; -} - -int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { - int *i = data; - int32_t k; - assert(filename && lvalue && rvalue && data); - - if (pa_atoi(rvalue, &k) < 0) { - pa_log(__FILE__": [%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); - return -1; - } - - *i = (int) k; - return 0; -} - -int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { - int *b = data, k; - assert(filename && lvalue && rvalue && data); - - if ((k = pa_parse_boolean(rvalue)) < 0) { - pa_log(__FILE__": [%s:%u] Failed to parse boolean value: %s", filename, line, rvalue); - return -1; - } - - *b = k; - - return 0; -} - -int pa_config_parse_string(const char *filename, PA_GCC_UNUSED unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { - char **s = data; - assert(filename && lvalue && rvalue && data); - - pa_xfree(*s); - *s = *rvalue ? pa_xstrdup(rvalue) : NULL; - return 0; -} diff --git a/src/polypcore/conf-parser.h b/src/polypcore/conf-parser.h deleted file mode 100644 index 2dca3bce..00000000 --- a/src/polypcore/conf-parser.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef fooconfparserhfoo -#define fooconfparserhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -/* An abstract parser for simple, line based, shallow configuration - * files consisting of variable assignments only. */ - -/* Wraps info for parsing a specific configuration variable */ -typedef struct pa_config_item { - const char *lvalue; /* name of the variable */ - int (*parse)(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); /* Function that is called to parse the variable's value */ - void *data; /* Where to store the variable's data */ -} pa_config_item; - -/* The configuration file parsing routine. Expects a table of - * pa_config_items in *t that is terminated by an item where lvalue is - * NULL */ -int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void *userdata); - -/* Generic parsers for integers, booleans and strings */ -int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); -int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); -int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); - -#endif diff --git a/src/polypcore/core-def.h b/src/polypcore/core-def.h deleted file mode 100644 index 89cc47f1..00000000 --- a/src/polypcore/core-def.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef foocoredefhfoo -#define foocoredefhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -typedef enum pa_mixer { - PA_MIXER_SOFTWARE, - PA_MIXER_HARDWARE -} pa_mixer_t; - -#endif diff --git a/src/polypcore/core-error.c b/src/polypcore/core-error.c deleted file mode 100644 index f2240a9f..00000000 --- a/src/polypcore/core-error.c +++ /dev/null @@ -1,205 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#ifdef HAVE_PTHREAD -#include -#endif - -#ifdef HAVE_WINDOWS_H -#include -#endif - -#include -#include - -#include -#include - -#include "core-error.h" - -#ifdef HAVE_PTHREAD - -static pthread_once_t cstrerror_once = PTHREAD_ONCE_INIT; -static pthread_key_t tlsstr_key; - -static void inittls(void) { - int ret; - - ret = pthread_key_create(&tlsstr_key, pa_xfree); - if (ret) { - fprintf(stderr, __FILE__ ": CRITICAL: Unable to allocate TLS key (%d)\n", errno); - exit(-1); - } -} - -#elif HAVE_WINDOWS_H - -static DWORD tlsstr_key = TLS_OUT_OF_INDEXES; -static DWORD monitor_key = TLS_OUT_OF_INDEXES; - -static void inittls(void) { - HANDLE mutex; - char name[64]; - - sprintf(name, "polypaudio%d", (int)GetCurrentProcessId()); - - mutex = CreateMutex(NULL, FALSE, name); - if (!mutex) { - fprintf(stderr, __FILE__ ": CRITICAL: Unable to create named mutex (%d)\n", (int)GetLastError()); - exit(-1); - } - - WaitForSingleObject(mutex, INFINITE); - - if (tlsstr_key == TLS_OUT_OF_INDEXES) { - tlsstr_key = TlsAlloc(); - monitor_key = TlsAlloc(); - if ((tlsstr_key == TLS_OUT_OF_INDEXES) || (monitor_key == TLS_OUT_OF_INDEXES)) { - fprintf(stderr, __FILE__ ": CRITICAL: Unable to allocate TLS key (%d)\n", (int)GetLastError()); - exit(-1); - } - } - - ReleaseMutex(mutex); - - CloseHandle(mutex); -} - -/* - * This is incredibly brain dead, but this is necessary when dealing with - * the hell that is Win32. - */ -struct monitor_data { - HANDLE thread; - void *data; -}; - -static DWORD WINAPI monitor_thread(LPVOID param) { - struct monitor_data *data; - - data = (struct monitor_data*)param; - assert(data); - - WaitForSingleObject(data->thread, INFINITE); - - CloseHandle(data->thread); - pa_xfree(data->data); - pa_xfree(data); - - return 0; -} - -static void start_monitor(void) { - HANDLE thread; - struct monitor_data *data; - - data = pa_xnew(struct monitor_data, 1); - assert(data); - - DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), - GetCurrentProcess(), &data->thread, 0, FALSE, DUPLICATE_SAME_ACCESS); - - thread = CreateThread(NULL, 0, monitor_thread, data, 0, NULL); - assert(thread); - - TlsSetValue(monitor_key, data); - - CloseHandle(thread); -} - -#else - -/* Unsafe, but we have no choice */ -static char *tlsstr; - -#endif - -const char* pa_cstrerror(int errnum) { - const char *origbuf; - -#ifdef HAVE_STRERROR_R - char errbuf[128]; -#endif - -#ifdef HAVE_PTHREAD - char *tlsstr; - - pthread_once(&cstrerror_once, inittls); - - tlsstr = pthread_getspecific(tlsstr_key); -#elif defined(HAVE_WINDOWS_H) - char *tlsstr; - struct monitor_data *data; - - inittls(); - - tlsstr = TlsGetValue(tlsstr_key); - if (!tlsstr) - start_monitor(); - data = TlsGetValue(monitor_key); -#endif - - if (tlsstr) - pa_xfree(tlsstr); - -#ifdef HAVE_STRERROR_R - -#ifdef __GLIBC__ - origbuf = strerror_r(errnum, errbuf, sizeof(errbuf)); - if (origbuf == NULL) - origbuf = ""; -#else - if (strerror_r(errnum, errbuf, sizeof(errbuf)) == 0) { - origbuf = errbuf; - errbuf[sizeof(errbuf) - 1] = '\0'; - } else - origbuf = ""; -#endif - -#else - /* This might not be thread safe, but we hope for the best */ - origbuf = strerror(errnum); -#endif - - tlsstr = pa_locale_to_utf8(origbuf); - if (!tlsstr) { - fprintf(stderr, "Unable to convert, filtering\n"); - tlsstr = pa_utf8_filter(origbuf); - } - -#ifdef HAVE_PTHREAD - pthread_setspecific(tlsstr_key, tlsstr); -#elif defined(HAVE_WINDOWS_H) - TlsSetValue(tlsstr_key, tlsstr); - data->data = tlsstr; -#endif - - return tlsstr; -} diff --git a/src/polypcore/core-error.h b/src/polypcore/core-error.h deleted file mode 100644 index 17595c98..00000000 --- a/src/polypcore/core-error.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef foocoreerrorhfoo -#define foocoreerrorhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -/** \file - * Error management */ - -PA_C_DECL_BEGIN - -/** A wrapper around the standard strerror() function that converts the - * string to UTF-8. The function is thread safe but the returned string is - * only guaranteed to exist until the thread exits or pa_cstrerror() is - * called again from the same thread. */ -const char* pa_cstrerror(int errnum); - -PA_C_DECL_END - -#endif diff --git a/src/polypcore/core-scache.c b/src/polypcore/core-scache.c deleted file mode 100644 index b44a7e19..00000000 --- a/src/polypcore/core-scache.c +++ /dev/null @@ -1,412 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_GLOB_H -#include -#endif - -#ifdef HAVE_WINDOWS_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "core-scache.h" - -#define UNLOAD_POLL_TIME 2 - -static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - pa_core *c = userdata; - struct timeval ntv; - assert(c && c->mainloop == m && c->scache_auto_unload_event == e); - - pa_scache_unload_unused(c); - - pa_gettimeofday(&ntv); - ntv.tv_sec += UNLOAD_POLL_TIME; - m->time_restart(e, &ntv); -} - -static void free_entry(pa_scache_entry *e) { - assert(e); - pa_namereg_unregister(e->core, e->name); - pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_REMOVE, e->index); - pa_xfree(e->name); - pa_xfree(e->filename); - if (e->memchunk.memblock) - pa_memblock_unref(e->memchunk.memblock); - pa_xfree(e); -} - -static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { - pa_scache_entry *e; - assert(c && name); - - if ((e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) { - if (e->memchunk.memblock) - pa_memblock_unref(e->memchunk.memblock); - - pa_xfree(e->filename); - - assert(e->core == c); - - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); - } else { - e = pa_xmalloc(sizeof(pa_scache_entry)); - - if (!pa_namereg_register(c, name, PA_NAMEREG_SAMPLE, e, 1)) { - pa_xfree(e); - return NULL; - } - - e->name = pa_xstrdup(name); - e->core = c; - - if (!c->scache) { - c->scache = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - assert(c->scache); - } - - pa_idxset_put(c->scache, e, &e->index); - - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_NEW, e->index); - } - - e->last_used_time = 0; - e->memchunk.memblock = NULL; - e->memchunk.index = e->memchunk.length = 0; - e->filename = NULL; - e->lazy = 0; - e->last_used_time = 0; - - memset(&e->sample_spec, 0, sizeof(e->sample_spec)); - pa_channel_map_init(&e->channel_map); - pa_cvolume_reset(&e->volume, PA_CHANNELS_MAX); - - return e; -} - -int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx) { - pa_scache_entry *e; - assert(c && name); - - if (chunk && chunk->length > PA_SCACHE_ENTRY_SIZE_MAX) - return -1; - - if (!(e = scache_add_item(c, name))) - return -1; - - if (ss) { - e->sample_spec = *ss; - pa_channel_map_init_auto(&e->channel_map, ss->channels, PA_CHANNEL_MAP_DEFAULT); - e->volume.channels = e->sample_spec.channels; - } - - if (map) - e->channel_map = *map; - - if (chunk) { - e->memchunk = *chunk; - pa_memblock_ref(e->memchunk.memblock); - } - - if (idx) - *idx = e->index; - - return 0; -} - -int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint32_t *idx) { - pa_sample_spec ss; - pa_channel_map map; - pa_memchunk chunk; - int r; - -#ifdef OS_IS_WIN32 - char buf[MAX_PATH]; - - if (ExpandEnvironmentStrings(filename, buf, MAX_PATH)) - filename = buf; -#endif - - if (pa_sound_file_load(filename, &ss, &map, &chunk, c->memblock_stat) < 0) - return -1; - - r = pa_scache_add_item(c, name, &ss, &map, &chunk, idx); - pa_memblock_unref(chunk.memblock); - - return r; -} - -int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, uint32_t *idx) { - pa_scache_entry *e; - -#ifdef OS_IS_WIN32 - char buf[MAX_PATH]; - - if (ExpandEnvironmentStrings(filename, buf, MAX_PATH)) - filename = buf; -#endif - - assert(c && name); - - if (!(e = scache_add_item(c, name))) - return -1; - - e->lazy = 1; - e->filename = pa_xstrdup(filename); - - if (!c->scache_auto_unload_event) { - struct timeval ntv; - pa_gettimeofday(&ntv); - ntv.tv_sec += UNLOAD_POLL_TIME; - c->scache_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); - } - - if (idx) - *idx = e->index; - - return 0; -} - -int pa_scache_remove_item(pa_core *c, const char *name) { - pa_scache_entry *e; - assert(c && name); - - if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) - return -1; - - if (pa_idxset_remove_by_data(c->scache, e, NULL) != e) - assert(0); - - free_entry(e); - return 0; -} - -static void free_cb(void *p, PA_GCC_UNUSED void *userdata) { - pa_scache_entry *e = p; - assert(e); - free_entry(e); -} - -void pa_scache_free(pa_core *c) { - assert(c); - - if (c->scache) { - pa_idxset_free(c->scache, free_cb, NULL); - c->scache = NULL; - } - - if (c->scache_auto_unload_event) - c->mainloop->time_free(c->scache_auto_unload_event); -} - -int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t volume) { - pa_scache_entry *e; - char *t; - pa_cvolume r; - - assert(c); - assert(name); - assert(sink); - - if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1))) - return -1; - - if (e->lazy && !e->memchunk.memblock) { - if (pa_sound_file_load(e->filename, &e->sample_spec, &e->channel_map, &e->memchunk, c->memblock_stat) < 0) - return -1; - - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); - - if (e->volume.channels > e->sample_spec.channels) - e->volume.channels = e->sample_spec.channels; - } - - if (!e->memchunk.memblock) - return -1; - - t = pa_sprintf_malloc("sample:%s", name); - - pa_cvolume_set(&r, e->volume.channels, volume); - pa_sw_cvolume_multiply(&r, &r, &e->volume); - - if (pa_play_memchunk(sink, t, &e->sample_spec, &e->channel_map, &e->memchunk, &r) < 0) { - pa_xfree(t); - return -1; - } - - pa_xfree(t); - - if (e->lazy) - time(&e->last_used_time); - - return 0; -} - -const char * pa_scache_get_name_by_id(pa_core *c, uint32_t id) { - pa_scache_entry *e; - assert(c && id != PA_IDXSET_INVALID); - - if (!c->scache || !(e = pa_idxset_get_by_index(c->scache, id))) - return NULL; - - return e->name; -} - -uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name) { - pa_scache_entry *e; - assert(c && name); - - if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) - return PA_IDXSET_INVALID; - - return e->index; -} - -uint32_t pa_scache_total_size(pa_core *c) { - pa_scache_entry *e; - uint32_t idx, sum = 0; - assert(c); - - if (!c->scache || !pa_idxset_size(c->scache)) - return 0; - - for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) - if (e->memchunk.memblock) - sum += e->memchunk.length; - - return sum; -} - -void pa_scache_unload_unused(pa_core *c) { - pa_scache_entry *e; - time_t now; - uint32_t idx; - assert(c); - - if (!c->scache || !pa_idxset_size(c->scache)) - return; - - time(&now); - - for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) { - - if (!e->lazy || !e->memchunk.memblock) - continue; - - if (e->last_used_time + c->scache_idle_time > now) - continue; - - pa_memblock_unref(e->memchunk.memblock); - e->memchunk.memblock = NULL; - e->memchunk.index = e->memchunk.length = 0; - - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); - } -} - -static void add_file(pa_core *c, const char *pathname) { - struct stat st; - const char *e; - - e = pa_path_get_filename(pathname); - - if (stat(pathname, &st) < 0) { - pa_log(__FILE__": stat('%s'): %s", pathname, pa_cstrerror(errno)); - return; - } - -#if defined(S_ISREG) && defined(S_ISLNK) - if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) -#endif - pa_scache_add_file_lazy(c, e, pathname, NULL); -} - -int pa_scache_add_directory_lazy(pa_core *c, const char *pathname) { - DIR *dir; - assert(c && pathname); - - /* First try to open this as directory */ - if (!(dir = opendir(pathname))) { -#ifdef HAVE_GLOB_H - glob_t p; - unsigned int i; - /* If that fails, try to open it as shell glob */ - - if (glob(pathname, GLOB_ERR|GLOB_NOSORT, NULL, &p) < 0) { - pa_log(__FILE__": failed to open directory '%s': %s", pathname, pa_cstrerror(errno)); - return -1; - } - - for (i = 0; i < p.gl_pathc; i++) - add_file(c, p.gl_pathv[i]); - - globfree(&p); -#else - return -1; -#endif - } else { - struct dirent *e; - - while ((e = readdir(dir))) { - char p[PATH_MAX]; - - if (e->d_name[0] == '.') - continue; - - snprintf(p, sizeof(p), "%s/%s", pathname, e->d_name); - add_file(c, p); - } - } - - closedir(dir); - return 0; -} diff --git a/src/polypcore/core-scache.h b/src/polypcore/core-scache.h deleted file mode 100644 index 9ca05f8f..00000000 --- a/src/polypcore/core-scache.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef foocorescachehfoo -#define foocorescachehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include - -#define PA_SCACHE_ENTRY_SIZE_MAX (1024*1024*2) - -typedef struct pa_scache_entry { - pa_core *core; - uint32_t index; - char *name; - - pa_cvolume volume; - pa_sample_spec sample_spec; - pa_channel_map channel_map; - pa_memchunk memchunk; - - char *filename; - - int lazy; - time_t last_used_time; -} pa_scache_entry; - -int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx); -int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint32_t *idx); -int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, uint32_t *idx); - -int pa_scache_add_directory_lazy(pa_core *c, const char *pathname); - -int pa_scache_remove_item(pa_core *c, const char *name); -int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t volume); -void pa_scache_free(pa_core *c); - -const char *pa_scache_get_name_by_id(pa_core *c, uint32_t id); -uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name); - -uint32_t pa_scache_total_size(pa_core *c); - -void pa_scache_unload_unused(pa_core *c); - -#endif diff --git a/src/polypcore/core-subscribe.c b/src/polypcore/core-subscribe.c deleted file mode 100644 index 52babb7a..00000000 --- a/src/polypcore/core-subscribe.c +++ /dev/null @@ -1,233 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include - -#include -#include - -#include "core-subscribe.h" - -/* The subscription subsystem may be used to be notified whenever an - * entity (sink, source, ...) is created or deleted. Modules may - * register a callback function that is called whenever an event - * matching a subscription mask happens. The execution of the callback - * function is postponed to the next main loop iteration, i.e. is not - * called from within the stack frame the entity was created in. */ - -struct pa_subscription { - pa_core *core; - int dead; - void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata); - void *userdata; - pa_subscription_mask_t mask; - - pa_subscription *prev, *next; -}; - -struct pa_subscription_event { - pa_subscription_event_type_t type; - uint32_t index; -}; - -static void sched_event(pa_core *c); - -/* Allocate a new subscription object for the given subscription mask. Use the specified callback function and user data */ -pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata) { - pa_subscription *s; - assert(c); - - s = pa_xmalloc(sizeof(pa_subscription)); - s->core = c; - s->dead = 0; - s->callback = callback; - s->userdata = userdata; - s->mask = m; - - if ((s->next = c->subscriptions)) - s->next->prev = s; - s->prev = NULL; - c->subscriptions = s; - return s; -} - -/* Free a subscription object, effectively marking it for deletion */ -void pa_subscription_free(pa_subscription*s) { - assert(s && !s->dead); - s->dead = 1; - sched_event(s->core); -} - -static void free_item(pa_subscription *s) { - assert(s && s->core); - - if (s->prev) - s->prev->next = s->next; - else - s->core->subscriptions = s->next; - - if (s->next) - s->next->prev = s->prev; - - pa_xfree(s); -} - -/* Free all subscription objects */ -void pa_subscription_free_all(pa_core *c) { - pa_subscription_event *e; - assert(c); - - while (c->subscriptions) - free_item(c->subscriptions); - - if (c->subscription_event_queue) { - while ((e = pa_queue_pop(c->subscription_event_queue))) - pa_xfree(e); - - pa_queue_free(c->subscription_event_queue, NULL, NULL); - c->subscription_event_queue = NULL; - } - - if (c->subscription_defer_event) { - c->mainloop->defer_free(c->subscription_defer_event); - c->subscription_defer_event = NULL; - } -} - -#if 0 -static void dump_event(pa_subscription_event*e) { - switch (e->type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { - case PA_SUBSCRIPTION_EVENT_SINK: - pa_log(__FILE__": SINK_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_SOURCE: - pa_log(__FILE__": SOURCE_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_SINK_INPUT: - pa_log(__FILE__": SINK_INPUT_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: - pa_log(__FILE__": SOURCE_OUTPUT_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_MODULE: - pa_log(__FILE__": MODULE_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_CLIENT: - pa_log(__FILE__": CLIENT_EVENT"); - break; - default: - pa_log(__FILE__": OTHER"); - break; - } - - switch (e->type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) { - case PA_SUBSCRIPTION_EVENT_NEW: - pa_log(__FILE__": NEW"); - break; - case PA_SUBSCRIPTION_EVENT_CHANGE: - pa_log(__FILE__": CHANGE"); - break; - case PA_SUBSCRIPTION_EVENT_REMOVE: - pa_log(__FILE__": REMOVE"); - break; - default: - pa_log(__FILE__": OTHER"); - break; - } - - pa_log(__FILE__": %u", e->index); -} -#endif - -/* Deferred callback for dispatching subscirption events */ -static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) { - pa_core *c = userdata; - pa_subscription *s; - assert(c && c->subscription_defer_event == de && c->mainloop == m); - - c->mainloop->defer_enable(c->subscription_defer_event, 0); - - /* Dispatch queued events */ - - if (c->subscription_event_queue) { - pa_subscription_event *e; - - while ((e = pa_queue_pop(c->subscription_event_queue))) { - - for (s = c->subscriptions; s; s = s->next) { - - if (!s->dead && pa_subscription_match_flags(s->mask, e->type)) - s->callback(c, e->type, e->index, s->userdata); - } - - pa_xfree(e); - } - } - - /* Remove dead subscriptions */ - - s = c->subscriptions; - while (s) { - pa_subscription *n = s->next; - if (s->dead) - free_item(s); - s = n; - } -} - -/* Schedule an mainloop event so that a pending subscription event is dispatched */ -static void sched_event(pa_core *c) { - assert(c); - - if (!c->subscription_defer_event) { - c->subscription_defer_event = c->mainloop->defer_new(c->mainloop, defer_cb, c); - assert(c->subscription_defer_event); - } - - c->mainloop->defer_enable(c->subscription_defer_event, 1); -} - -/* Append a new subscription event to the subscription event queue and schedule a main loop event */ -void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t index) { - pa_subscription_event *e; - assert(c); - - e = pa_xmalloc(sizeof(pa_subscription_event)); - e->type = t; - e->index = index; - - if (!c->subscription_event_queue) { - c->subscription_event_queue = pa_queue_new(); - assert(c->subscription_event_queue); - } - - pa_queue_push(c->subscription_event_queue, e); - sched_event(c); -} - - diff --git a/src/polypcore/core-subscribe.h b/src/polypcore/core-subscribe.h deleted file mode 100644 index 7c856954..00000000 --- a/src/polypcore/core-subscribe.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef foocoresubscribehfoo -#define foocoresubscribehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -typedef struct pa_subscription pa_subscription; -typedef struct pa_subscription_event pa_subscription_event; - -#include -#include - -pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata); -void pa_subscription_free(pa_subscription*s); -void pa_subscription_free_all(pa_core *c); - -void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t idx); - -#endif diff --git a/src/polypcore/core-util.c b/src/polypcore/core-util.c deleted file mode 100644 index dfa41f57..00000000 --- a/src/polypcore/core-util.c +++ /dev/null @@ -1,1023 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SCHED_H -#include -#endif - -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif - -#ifdef HAVE_PTHREAD -#include -#endif - -#ifdef HAVE_NETDB_H -#include -#endif - -#ifdef HAVE_WINDOWS_H -#include -#endif - -#ifdef HAVE_PWD_H -#include -#endif - -#ifdef HAVE_GRP_H -#include -#endif - -#include - -#include -#include - -#include -#include -#include - -#include "core-util.h" - -#ifndef OS_IS_WIN32 -#define PA_RUNTIME_PATH_PREFIX "/tmp/polypaudio-" -#define PATH_SEP '/' -#else -#define PA_RUNTIME_PATH_PREFIX "%TEMP%\\polypaudio-" -#define PATH_SEP '\\' -#endif - -#ifdef OS_IS_WIN32 - -#define POLYP_ROOTENV "POLYP_ROOT" - -int pa_set_root(HANDLE handle) { - char library_path[MAX_PATH + sizeof(POLYP_ROOTENV) + 1], *sep; - - strcpy(library_path, POLYP_ROOTENV "="); - - if (!GetModuleFileName(handle, library_path + sizeof(POLYP_ROOTENV), MAX_PATH)) - return 0; - - sep = strrchr(library_path, '\\'); - if (sep) - *sep = '\0'; - - if (_putenv(library_path) < 0) - return 0; - - return 1; -} - -#endif - -/** Make a file descriptor nonblock. Doesn't do any error checking */ -void pa_make_nonblock_fd(int fd) { -#ifdef O_NONBLOCK - int v; - assert(fd >= 0); - - if ((v = fcntl(fd, F_GETFL)) >= 0) - if (!(v & O_NONBLOCK)) - fcntl(fd, F_SETFL, v|O_NONBLOCK); -#elif defined(OS_IS_WIN32) - u_long arg = 1; - if (ioctlsocket(fd, FIONBIO, &arg) < 0) { - if (WSAGetLastError() == WSAENOTSOCK) - pa_log_warn(__FILE__": WARNING: Only sockets can be made non-blocking!"); - } -#else - pa_log_warn(__FILE__": WARNING: Non-blocking I/O not supported.!"); -#endif -} - -/** Creates a directory securely */ -int pa_make_secure_dir(const char* dir) { - struct stat st; - assert(dir); - -#ifdef OS_IS_WIN32 - if (mkdir(dir) < 0) -#else - if (mkdir(dir, 0700) < 0) -#endif - if (errno != EEXIST) - return -1; - -#ifdef HAVE_CHOWN - chown(dir, getuid(), getgid()); -#endif -#ifdef HAVE_CHMOD - chmod(dir, 0700); -#endif - -#ifdef HAVE_LSTAT - if (lstat(dir, &st) < 0) -#else - if (stat(dir, &st) < 0) -#endif - goto fail; - -#ifndef OS_IS_WIN32 - if (!S_ISDIR(st.st_mode) || (st.st_uid != getuid()) || ((st.st_mode & 0777) != 0700)) - goto fail; -#else - fprintf(stderr, "FIXME: pa_make_secure_dir()\n"); -#endif - - return 0; - -fail: - rmdir(dir); - return -1; -} - -/* Return a newly allocated sting containing the parent directory of the specified file */ -char *pa_parent_dir(const char *fn) { - char *slash, *dir = pa_xstrdup(fn); - - slash = (char*) pa_path_get_filename(dir); - if (slash == fn) - return NULL; - - *(slash-1) = 0; - return dir; -} - -/* Creates a the parent directory of the specified path securely */ -int pa_make_secure_parent_dir(const char *fn) { - int ret = -1; - char *dir; - - if (!(dir = pa_parent_dir(fn))) - goto finish; - - if (pa_make_secure_dir(dir) < 0) - goto finish; - - ret = 0; - -finish: - pa_xfree(dir); - return ret; -} - -/** Platform independent read function. Necessary since not all systems - * treat all file descriptors equal. */ -ssize_t pa_read(int fd, void *buf, size_t count) { - ssize_t r; - -#ifdef OS_IS_WIN32 - r = recv(fd, buf, count, 0); - if (r < 0) { - if (WSAGetLastError() != WSAENOTSOCK) { - errno = WSAGetLastError(); - return r; - } - } - - if (r < 0) -#endif - r = read(fd, buf, count); - - return r; -} - -/** Similar to pa_read(), but handles writes */ -ssize_t pa_write(int fd, const void *buf, size_t count) { - ssize_t r; - -#ifdef OS_IS_WIN32 - r = send(fd, buf, count, 0); - if (r < 0) { - if (WSAGetLastError() != WSAENOTSOCK) { - errno = WSAGetLastError(); - return r; - } - } - - if (r < 0) -#endif - r = write(fd, buf, count); - - return r; -} - -/** Calls read() in a loop. Makes sure that as much as 'size' bytes, - * unless EOF is reached or an error occured */ -ssize_t pa_loop_read(int fd, void*data, size_t size) { - ssize_t ret = 0; - assert(fd >= 0 && data && size); - - while (size > 0) { - ssize_t r; - - if ((r = pa_read(fd, data, size)) < 0) - return r; - - if (r == 0) - break; - - ret += r; - data = (uint8_t*) data + r; - size -= r; - } - - return ret; -} - -/** Similar to pa_loop_read(), but wraps write() */ -ssize_t pa_loop_write(int fd, const void*data, size_t size) { - ssize_t ret = 0; - assert(fd >= 0 && data && size); - - while (size > 0) { - ssize_t r; - - if ((r = pa_write(fd, data, size)) < 0) - return r; - - if (r == 0) - break; - - ret += r; - data = (const uint8_t*) data + r; - size -= r; - } - - return ret; -} - -/* Print a warning messages in case that the given signal is not - * blocked or trapped */ -void pa_check_signal_is_blocked(int sig) { -#ifdef HAVE_SIGACTION - struct sigaction sa; - sigset_t set; - - /* If POSIX threads are supported use thread-aware - * pthread_sigmask() function, to check if the signal is - * blocked. Otherwise fall back to sigprocmask() */ - -#ifdef HAVE_PTHREAD - if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) { -#endif - if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) { - pa_log(__FILE__": sigprocmask(): %s", pa_cstrerror(errno)); - return; - } -#ifdef HAVE_PTHREAD - } -#endif - - if (sigismember(&set, sig)) - return; - - /* Check whether the signal is trapped */ - - if (sigaction(sig, NULL, &sa) < 0) { - pa_log(__FILE__": sigaction(): %s", pa_cstrerror(errno)); - return; - } - - if (sa.sa_handler != SIG_DFL) - return; - - pa_log(__FILE__": WARNING: %s is not trapped. This might cause malfunction!", pa_strsignal(sig)); -#else /* HAVE_SIGACTION */ - pa_log(__FILE__": WARNING: %s might not be trapped. This might cause malfunction!", pa_strsignal(sig)); -#endif -} - -/* The following function is based on an example from the GNU libc - * documentation. This function is similar to GNU's asprintf(). */ -char *pa_sprintf_malloc(const char *format, ...) { - int size = 100; - char *c = NULL; - - assert(format); - - for(;;) { - int r; - va_list ap; - - c = pa_xrealloc(c, size); - - va_start(ap, format); - r = vsnprintf(c, size, format, ap); - va_end(ap); - - if (r > -1 && r < size) - return c; - - if (r > -1) /* glibc 2.1 */ - size = r+1; - else /* glibc 2.0 */ - size *= 2; - } -} - -/* Same as the previous function, but use a va_list instead of an - * ellipsis */ -char *pa_vsprintf_malloc(const char *format, va_list ap) { - int size = 100; - char *c = NULL; - - assert(format); - - for(;;) { - int r; - va_list aq; - - va_copy(aq, ap); - - c = pa_xrealloc(c, size); - r = vsnprintf(c, size, format, aq); - - va_end(aq); - - if (r > -1 && r < size) - return c; - - if (r > -1) /* glibc 2.1 */ - size = r+1; - else /* glibc 2.0 */ - size *= 2; - } -} - -/* Similar to OpenBSD's strlcpy() function */ -char *pa_strlcpy(char *b, const char *s, size_t l) { - assert(b && s && l > 0); - - strncpy(b, s, l); - b[l-1] = 0; - return b; -} - -#define NICE_LEVEL (-15) - -/* Raise the priority of the current process as much as possible and -sensible: set the nice level to -15 and enable realtime scheduling if -supported.*/ -void pa_raise_priority(void) { - -#ifdef HAVE_SYS_RESOURCE_H - if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) - pa_log_warn(__FILE__": setpriority(): %s", pa_cstrerror(errno)); - else - pa_log_info(__FILE__": Successfully gained nice level %i.", NICE_LEVEL); -#endif - -#ifdef _POSIX_PRIORITY_SCHEDULING - { - struct sched_param sp; - - if (sched_getparam(0, &sp) < 0) { - pa_log(__FILE__": sched_getparam(): %s", pa_cstrerror(errno)); - return; - } - - sp.sched_priority = 1; - if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) { - pa_log_warn(__FILE__": sched_setscheduler(): %s", pa_cstrerror(errno)); - return; - } - - pa_log_info(__FILE__": Successfully enabled SCHED_FIFO scheduling."); - } -#endif - -#ifdef OS_IS_WIN32 - if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) - pa_log_warn(__FILE__": SetPriorityClass() failed: 0x%08X", GetLastError()); - else - pa_log_info(__FILE__": Successfully gained high priority class."); -#endif -} - -/* Reset the priority to normal, inverting the changes made by pa_raise_priority() */ -void pa_reset_priority(void) { -#ifdef OS_IS_WIN32 - SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); -#endif - -#ifdef _POSIX_PRIORITY_SCHEDULING - { - struct sched_param sp; - sched_getparam(0, &sp); - sp.sched_priority = 0; - sched_setscheduler(0, SCHED_OTHER, &sp); - } -#endif - -#ifdef HAVE_SYS_RESOURCE_H - setpriority(PRIO_PROCESS, 0, 0); -#endif -} - -/* Set the FD_CLOEXEC flag for a fd */ -int pa_fd_set_cloexec(int fd, int b) { - -#ifdef FD_CLOEXEC - int v; - assert(fd >= 0); - - if ((v = fcntl(fd, F_GETFD, 0)) < 0) - return -1; - - v = (v & ~FD_CLOEXEC) | (b ? FD_CLOEXEC : 0); - - if (fcntl(fd, F_SETFD, v) < 0) - return -1; -#endif - - return 0; -} - -/* Try to parse a boolean string value.*/ -int pa_parse_boolean(const char *v) { - - if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on")) - return 1; - else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off")) - return 0; - - return -1; -} - -/* Split the specified string wherever one of the strings in delimiter - * occurs. Each time it is called returns a newly allocated string - * with pa_xmalloc(). The variable state points to, should be - * initiallized to NULL before the first call. */ -char *pa_split(const char *c, const char *delimiter, const char**state) { - const char *current = *state ? *state : c; - size_t l; - - if (!*current) - return NULL; - - l = strcspn(current, delimiter); - *state = current+l; - - if (**state) - (*state)++; - - return pa_xstrndup(current, l); -} - -/* What is interpreted as whitespace? */ -#define WHITESPACE " \t\n" - -/* Split a string into words. Otherwise similar to pa_split(). */ -char *pa_split_spaces(const char *c, const char **state) { - const char *current = *state ? *state : c; - size_t l; - - if (!*current || *c == 0) - return NULL; - - current += strspn(current, WHITESPACE); - l = strcspn(current, WHITESPACE); - - *state = current+l; - - return pa_xstrndup(current, l); -} - -/* Return the name of an UNIX signal. Similar to GNU's strsignal() */ -const char *pa_strsignal(int sig) { - switch(sig) { - case SIGINT: return "SIGINT"; - case SIGTERM: return "SIGTERM"; -#ifdef SIGUSR1 - case SIGUSR1: return "SIGUSR1"; -#endif -#ifdef SIGUSR2 - case SIGUSR2: return "SIGUSR2"; -#endif -#ifdef SIGXCPU - case SIGXCPU: return "SIGXCPU"; -#endif -#ifdef SIGPIPE - case SIGPIPE: return "SIGPIPE"; -#endif -#ifdef SIGCHLD - case SIGCHLD: return "SIGCHLD"; -#endif -#ifdef SIGHUP - case SIGHUP: return "SIGHUP"; -#endif - default: return "UNKNOWN SIGNAL"; - } -} - -#ifdef HAVE_GRP_H - -/* Check whether the specified GID and the group name match */ -static int is_group(gid_t gid, const char *name) { - struct group group, *result = NULL; - long n; - void *data; - int r = -1; - -#ifdef HAVE_GETGRGID_R -#ifdef _SC_GETGR_R_SIZE_MAX - n = sysconf(_SC_GETGR_R_SIZE_MAX); -#else - n = -1; -#endif - if (n < 0) n = 512; - data = pa_xmalloc(n); - - if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) { - pa_log(__FILE__": getgrgid_r(%u): %s", (unsigned)gid, pa_cstrerror(errno)); - goto finish; - } - - r = strcmp(name, result->gr_name) == 0; - -finish: - pa_xfree(data); -#else - /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not - * support getgrgid_r. */ - if ((result = getgrgid(gid)) == NULL) { - pa_log(__FILE__": getgrgid(%u): %s", gid, pa_cstrerror(errno)); - goto finish; - } - - r = strcmp(name, result->gr_name) == 0; - -finish: -#endif - - return r; -} - -/* Check the current user is member of the specified group */ -int pa_own_uid_in_group(const char *name, gid_t *gid) { - GETGROUPS_T *gids, tgid; - int n = sysconf(_SC_NGROUPS_MAX); - int r = -1, i; - - assert(n > 0); - - gids = pa_xmalloc(sizeof(GETGROUPS_T)*n); - - if ((n = getgroups(n, gids)) < 0) { - pa_log(__FILE__": getgroups(): %s", pa_cstrerror(errno)); - goto finish; - } - - for (i = 0; i < n; i++) { - if (is_group(gids[i], name) > 0) { - *gid = gids[i]; - r = 1; - goto finish; - } - } - - if (is_group(tgid = getgid(), name) > 0) { - *gid = tgid; - r = 1; - goto finish; - } - - r = 0; - -finish: - - pa_xfree(gids); - return r; -} - -int pa_uid_in_group(uid_t uid, const char *name) { - char *g_buf, *p_buf; - long g_n, p_n; - struct group grbuf, *gr; - char **i; - int r = -1; - - g_n = sysconf(_SC_GETGR_R_SIZE_MAX); - g_buf = pa_xmalloc(g_n); - - p_n = sysconf(_SC_GETPW_R_SIZE_MAX); - p_buf = pa_xmalloc(p_n); - - if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) - goto finish; - - r = 0; - for (i = gr->gr_mem; *i; i++) { - struct passwd pwbuf, *pw; - - if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw) - continue; - - if (pw->pw_uid == uid) { - r = 1; - break; - } - } - -finish: - pa_xfree(g_buf); - pa_xfree(p_buf); - - return r; -} - -#else /* HAVE_GRP_H */ - -int pa_own_uid_in_group(const char *name, gid_t *gid) { - return -1; - -} - -int pa_uid_in_group(uid_t uid, const char *name) { - return -1; -} - -#endif - -/* Lock or unlock a file entirely. - (advisory on UNIX, mandatory on Windows) */ -int pa_lock_fd(int fd, int b) { -#ifdef F_SETLKW - struct flock flock; - - /* Try a R/W lock first */ - - flock.l_type = b ? F_WRLCK : F_UNLCK; - flock.l_whence = SEEK_SET; - flock.l_start = 0; - flock.l_len = 0; - - if (fcntl(fd, F_SETLKW, &flock) >= 0) - return 0; - - /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */ - if (b && errno == EBADF) { - flock.l_type = F_RDLCK; - if (fcntl(fd, F_SETLKW, &flock) >= 0) - return 0; - } - - pa_log(__FILE__": %slock: %s", !b? "un" : "", - pa_cstrerror(errno)); -#endif - -#ifdef OS_IS_WIN32 - HANDLE h = (HANDLE)_get_osfhandle(fd); - - if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) - return 0; - if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) - return 0; - - pa_log(__FILE__": %slock failed: 0x%08X", !b ? "un" : "", GetLastError()); -#endif - - return -1; -} - -/* Remove trailing newlines from a string */ -char* pa_strip_nl(char *s) { - assert(s); - - s[strcspn(s, "\r\n")] = 0; - return s; -} - -/* Create a temporary lock file and lock it. */ -int pa_lock_lockfile(const char *fn) { - int fd = -1; - assert(fn); - - for (;;) { - struct stat st; - - if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { - pa_log(__FILE__": failed to create lock file '%s': %s", fn, - pa_cstrerror(errno)); - goto fail; - } - - if (pa_lock_fd(fd, 1) < 0) { - pa_log(__FILE__": failed to lock file '%s'.", fn); - goto fail; - } - - if (fstat(fd, &st) < 0) { - pa_log(__FILE__": failed to fstat() file '%s'.", fn); - goto fail; - } - - /* Check wheter the file has been removed meanwhile. When yes, restart this loop, otherwise, we're done */ - if (st.st_nlink >= 1) - break; - - if (pa_lock_fd(fd, 0) < 0) { - pa_log(__FILE__": failed to unlock file '%s'.", fn); - goto fail; - } - - if (close(fd) < 0) { - pa_log(__FILE__": failed to close file '%s'.", fn); - goto fail; - } - - fd = -1; - } - - return fd; - -fail: - - if (fd >= 0) - close(fd); - - return -1; -} - -/* Unlock a temporary lcok file */ -int pa_unlock_lockfile(const char *fn, int fd) { - int r = 0; - assert(fn && fd >= 0); - - if (unlink(fn) < 0) { - pa_log_warn(__FILE__": WARNING: unable to remove lock file '%s': %s", - fn, pa_cstrerror(errno)); - r = -1; - } - - if (pa_lock_fd(fd, 0) < 0) { - pa_log_warn(__FILE__": WARNING: failed to unlock file '%s'.", fn); - r = -1; - } - - if (close(fd) < 0) { - pa_log_warn(__FILE__": WARNING: failed to close lock file '%s': %s", - fn, pa_cstrerror(errno)); - r = -1; - } - - return r; -} - -/* Try to open a configuration file. If "env" is specified, open the - * value of the specified environment variable. Otherwise look for a - * file "local" in the home directory or a file "global" in global - * file system. If "result" is non-NULL, a pointer to a newly - * allocated buffer containing the used configuration file is - * stored there.*/ -FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode) { - const char *fn; - char h[PATH_MAX]; - -#ifdef OS_IS_WIN32 - char buf[PATH_MAX]; - - if (!getenv(POLYP_ROOTENV)) - pa_set_root(NULL); -#endif - - if (env && (fn = getenv(env))) { -#ifdef OS_IS_WIN32 - if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX)) - return NULL; - fn = buf; -#endif - - if (result) - *result = pa_xstrdup(fn); - - return fopen(fn, mode); - } - - if (local && pa_get_home_dir(h, sizeof(h))) { - FILE *f; - char *lfn; - - fn = lfn = pa_sprintf_malloc("%s/%s", h, local); - -#ifdef OS_IS_WIN32 - if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) - return NULL; - fn = buf; -#endif - - f = fopen(fn, mode); - - if (f || errno != ENOENT) { - if (result) - *result = pa_xstrdup(fn); - pa_xfree(lfn); - return f; - } - - pa_xfree(lfn); - } - - if (!global) { - if (result) - *result = NULL; - errno = ENOENT; - return NULL; - } - -#ifdef OS_IS_WIN32 - if (!ExpandEnvironmentStrings(global, buf, PATH_MAX)) - return NULL; - global = buf; -#endif - - if (result) - *result = pa_xstrdup(global); - - return fopen(global, mode); -} - -/* Format the specified data as a hexademical string */ -char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) { - size_t i = 0, j = 0; - const char hex[] = "0123456789abcdef"; - assert(d && s && slength > 0); - - while (i < dlength && j+3 <= slength) { - s[j++] = hex[*d >> 4]; - s[j++] = hex[*d & 0xF]; - - d++; - i++; - } - - s[j < slength ? j : slength] = 0; - return s; -} - -/* Convert a hexadecimal digit to a number or -1 if invalid */ -static int hexc(char c) { - if (c >= '0' && c <= '9') - return c - '0'; - - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - - return -1; -} - -/* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */ -size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) { - size_t j = 0; - assert(p && d); - - while (j < dlength && *p) { - int b; - - if ((b = hexc(*(p++))) < 0) - return (size_t) -1; - - d[j] = (uint8_t) (b << 4); - - if (!*p) - return (size_t) -1; - - if ((b = hexc(*(p++))) < 0) - return (size_t) -1; - - d[j] |= (uint8_t) b; - j++; - } - - return j; -} - -/* Returns nonzero when *s starts with *pfx */ -int pa_startswith(const char *s, const char *pfx) { - size_t l; - - assert(s); - assert(pfx); - - l = strlen(pfx); - - return strlen(s) >= l && strncmp(s, pfx, l) == 0; -} - -/* Returns nonzero when *s ends with *sfx */ -int pa_endswith(const char *s, const char *sfx) { - size_t l1, l2; - - assert(s); - assert(sfx); - - l1 = strlen(s); - l2 = strlen(sfx); - - return l1 >= l2 && strcmp(s+l1-l2, sfx) == 0; -} - -/* if fn is null return the polypaudio run time path in s (/tmp/polypaudio) - * if fn is non-null and starts with / return fn in s - * otherwise append fn to the run time path and return it in s */ -char *pa_runtime_path(const char *fn, char *s, size_t l) { - char u[256]; - -#ifndef OS_IS_WIN32 - if (fn && *fn == '/') -#else - if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\') -#endif - return pa_strlcpy(s, fn, l); - - if (fn) - snprintf(s, l, "%s%s%c%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn); - else - snprintf(s, l, "%s%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u))); - -#ifdef OS_IS_WIN32 - { - char buf[l]; - strcpy(buf, s); - ExpandEnvironmentStrings(buf, s, l); - } -#endif - - return s; -} - -/* Convert the string s to a signed integer in *ret_i */ -int pa_atoi(const char *s, int32_t *ret_i) { - char *x = NULL; - long l; - assert(s && ret_i); - - l = strtol(s, &x, 0); - - if (!x || *x) - return -1; - - *ret_i = (int32_t) l; - - return 0; -} - -/* Convert the string s to an unsigned integer in *ret_u */ -int pa_atou(const char *s, uint32_t *ret_u) { - char *x = NULL; - unsigned long l; - assert(s && ret_u); - - l = strtoul(s, &x, 0); - - if (!x || *x) - return -1; - - *ret_u = (uint32_t) l; - - return 0; -} diff --git a/src/polypcore/core-util.h b/src/polypcore/core-util.h deleted file mode 100644 index 989f8c16..00000000 --- a/src/polypcore/core-util.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef foocoreutilhfoo -#define foocoreutilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include - -#include - -struct timeval; - -void pa_make_nonblock_fd(int fd); - -int pa_make_secure_dir(const char* dir); -int pa_make_secure_parent_dir(const char *fn); - -ssize_t pa_read(int fd, void *buf, size_t count); -ssize_t pa_write(int fd, const void *buf, size_t count); -ssize_t pa_loop_read(int fd, void*data, size_t size); -ssize_t pa_loop_write(int fd, const void*data, size_t size); - -void pa_check_signal_is_blocked(int sig); - -char *pa_sprintf_malloc(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); -char *pa_vsprintf_malloc(const char *format, va_list ap); - -char *pa_strlcpy(char *b, const char *s, size_t l); - -char *pa_parent_dir(const char *fn); - -void pa_raise_priority(void); -void pa_reset_priority(void); - -int pa_fd_set_cloexec(int fd, int b); - -int pa_parse_boolean(const char *s); - -char *pa_split(const char *c, const char*delimiters, const char **state); -char *pa_split_spaces(const char *c, const char **state); - -char *pa_strip_nl(char *s); - -const char *pa_strsignal(int sig); - -int pa_own_uid_in_group(const char *name, gid_t *gid); -int pa_uid_in_group(uid_t uid, const char *name); - -int pa_lock_fd(int fd, int b); - -int pa_lock_lockfile(const char *fn); -int pa_unlock_lockfile(const char *fn, int fd); - -FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode); - -char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength); -size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength); - -int pa_startswith(const char *s, const char *pfx); -int pa_endswith(const char *s, const char *sfx); - -char *pa_runtime_path(const char *fn, char *s, size_t l); - -int pa_atoi(const char *s, int32_t *ret_i); -int pa_atou(const char *s, uint32_t *ret_u); - -#endif diff --git a/src/polypcore/core.c b/src/polypcore/core.c deleted file mode 100644 index 09d023dc..00000000 --- a/src/polypcore/core.c +++ /dev/null @@ -1,160 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "core.h" - -pa_core* pa_core_new(pa_mainloop_api *m) { - pa_core* c; - c = pa_xmalloc(sizeof(pa_core)); - - c->mainloop = m; - c->clients = pa_idxset_new(NULL, NULL); - c->sinks = pa_idxset_new(NULL, NULL); - c->sources = pa_idxset_new(NULL, NULL); - c->source_outputs = pa_idxset_new(NULL, NULL); - c->sink_inputs = pa_idxset_new(NULL, NULL); - - c->default_source_name = c->default_sink_name = NULL; - - c->modules = NULL; - c->namereg = NULL; - c->scache = NULL; - c->autoload_idxset = NULL; - c->autoload_hashmap = NULL; - c->running_as_daemon = 0; - - c->default_sample_spec.format = PA_SAMPLE_S16NE; - c->default_sample_spec.rate = 44100; - c->default_sample_spec.channels = 2; - - c->module_auto_unload_event = NULL; - c->module_defer_unload_event = NULL; - c->scache_auto_unload_event = NULL; - - c->subscription_defer_event = NULL; - c->subscription_event_queue = NULL; - c->subscriptions = NULL; - - c->memblock_stat = pa_memblock_stat_new(); - - c->disallow_module_loading = 0; - - c->quit_event = NULL; - - c->exit_idle_time = -1; - c->module_idle_time = 20; - c->scache_idle_time = 20; - - c->resample_method = PA_RESAMPLER_SRC_SINC_FASTEST; - - pa_property_init(c); - - pa_random(&c->cookie, sizeof(c->cookie)); - -#ifdef SIGPIPE - pa_check_signal_is_blocked(SIGPIPE); -#endif - return c; -} - -void pa_core_free(pa_core *c) { - assert(c); - - pa_module_unload_all(c); - assert(!c->modules); - - assert(pa_idxset_isempty(c->clients)); - pa_idxset_free(c->clients, NULL, NULL); - - assert(pa_idxset_isempty(c->sinks)); - pa_idxset_free(c->sinks, NULL, NULL); - - assert(pa_idxset_isempty(c->sources)); - pa_idxset_free(c->sources, NULL, NULL); - - assert(pa_idxset_isempty(c->source_outputs)); - pa_idxset_free(c->source_outputs, NULL, NULL); - - assert(pa_idxset_isempty(c->sink_inputs)); - pa_idxset_free(c->sink_inputs, NULL, NULL); - - pa_scache_free(c); - pa_namereg_free(c); - pa_autoload_free(c); - pa_subscription_free_all(c); - - if (c->quit_event) - c->mainloop->time_free(c->quit_event); - - pa_xfree(c->default_source_name); - pa_xfree(c->default_sink_name); - - pa_memblock_stat_unref(c->memblock_stat); - - pa_property_cleanup(c); - - pa_xfree(c); -} - -static void quit_callback(pa_mainloop_api*m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - pa_core *c = userdata; - assert(c->quit_event = e); - - m->quit(m, 0); -} - -void pa_core_check_quit(pa_core *c) { - assert(c); - - if (!c->quit_event && c->exit_idle_time >= 0 && pa_idxset_size(c->clients) == 0) { - struct timeval tv; - pa_gettimeofday(&tv); - tv.tv_sec+= c->exit_idle_time; - c->quit_event = c->mainloop->time_new(c->mainloop, &tv, quit_callback, c); - } else if (c->quit_event && pa_idxset_size(c->clients) > 0) { - c->mainloop->time_free(c->quit_event); - c->quit_event = NULL; - } -} - diff --git a/src/polypcore/core.h b/src/polypcore/core.h deleted file mode 100644 index a323ae8e..00000000 --- a/src/polypcore/core.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef foocorehfoo -#define foocorehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -typedef struct pa_core pa_core; - -#include -#include -#include -#include -#include -#include -#include -#include - -/* The core structure of polypaudio. Every polypaudio daemon contains - * exactly one of these. It is used for storing kind of global - * variables for the daemon. */ - -struct pa_core { - /* A random value which may be used to identify this instance of - * polypaudio. Not cryptographically secure in any way. */ - uint32_t cookie; - - pa_mainloop_api *mainloop; - - /* idxset of all kinds of entities */ - pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache, *autoload_idxset; - - /* Some hashmaps for all sorts of entities */ - pa_hashmap *namereg, *autoload_hashmap, *properties; - - /* The name of the default sink/source */ - char *default_source_name, *default_sink_name; - - pa_sample_spec default_sample_spec; - pa_time_event *module_auto_unload_event; - pa_defer_event *module_defer_unload_event; - - pa_defer_event *subscription_defer_event; - pa_queue *subscription_event_queue; - pa_subscription *subscriptions; - - pa_memblock_stat *memblock_stat; - - int disallow_module_loading, running_as_daemon; - int exit_idle_time, module_idle_time, scache_idle_time; - - pa_time_event *quit_event; - - pa_time_event *scache_auto_unload_event; - - pa_resample_method_t resample_method; -}; - -pa_core* pa_core_new(pa_mainloop_api *m); -void pa_core_free(pa_core*c); - -/* Check whether noone is connected to this core */ -void pa_core_check_quit(pa_core *c); - -#endif diff --git a/src/polypcore/dllmain.c b/src/polypcore/dllmain.c deleted file mode 100644 index 95473b06..00000000 --- a/src/polypcore/dllmain.c +++ /dev/null @@ -1,55 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifdef OS_IS_WIN32 - -#include -#include -#include - -#include - -extern pa_set_root(HANDLE handle); - -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { - WSADATA data; - - switch (fdwReason) { - - case DLL_PROCESS_ATTACH: - if (!pa_set_root(hinstDLL)) - return FALSE; - WSAStartup(MAKEWORD(2, 0), &data); - break; - - case DLL_PROCESS_DETACH: - WSACleanup(); - break; - - } - return TRUE; -} - -#endif /* OS_IS_WIN32 */ diff --git a/src/polypcore/dynarray.c b/src/polypcore/dynarray.c deleted file mode 100644 index 234c2c03..00000000 --- a/src/polypcore/dynarray.c +++ /dev/null @@ -1,103 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include - -#include "dynarray.h" - -/* If the array becomes to small, increase its size by 100 entries */ -#define INCREASE_BY 100 - -struct pa_dynarray { - void **data; - unsigned n_allocated, n_entries; -}; - -pa_dynarray* pa_dynarray_new(void) { - pa_dynarray *a; - a = pa_xnew(pa_dynarray, 1); - a->data = NULL; - a->n_entries = 0; - a->n_allocated = 0; - return a; -} - -void pa_dynarray_free(pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata) { - unsigned i; - assert(a); - - if (func) - for (i = 0; i < a->n_entries; i++) - if (a->data[i]) - func(a->data[i], userdata); - - pa_xfree(a->data); - pa_xfree(a); -} - -void pa_dynarray_put(pa_dynarray*a, unsigned i, void *p) { - assert(a); - - if (i >= a->n_allocated) { - unsigned n; - - if (!p) - return; - - n = i+INCREASE_BY; - a->data = pa_xrealloc(a->data, sizeof(void*)*n); - memset(a->data+a->n_allocated, 0, sizeof(void*)*(n-a->n_allocated)); - a->n_allocated = n; - } - - a->data[i] = p; - - if (i >= a->n_entries) - a->n_entries = i+1; -} - -unsigned pa_dynarray_append(pa_dynarray*a, void *p) { - unsigned i = a->n_entries; - pa_dynarray_put(a, i, p); - return i; -} - -void *pa_dynarray_get(pa_dynarray*a, unsigned i) { - assert(a); - if (i >= a->n_allocated) - return NULL; - - assert(a->data); - return a->data[i]; -} - -unsigned pa_dynarray_size(pa_dynarray*a) { - assert(a); - return a->n_entries; -} diff --git a/src/polypcore/dynarray.h b/src/polypcore/dynarray.h deleted file mode 100644 index 9b1601ba..00000000 --- a/src/polypcore/dynarray.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef foodynarrayhfoo -#define foodynarrayhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -typedef struct pa_dynarray pa_dynarray; - -/* Implementation of a simple dynamically sized array. The array - * expands if required, but doesn't shrink if possible. Memory - * management of the array's entries is the user's job. */ - -pa_dynarray* pa_dynarray_new(void); - -/* Free the array calling the specified function for every entry in - * the array. The function may be NULL. */ -void pa_dynarray_free(pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata); - -/* Store p at position i in the array */ -void pa_dynarray_put(pa_dynarray*a, unsigned i, void *p); - -/* Store p a the first free position in the array. Returns the index - * of that entry. If entries are removed from the array their position - * are not filled any more by this function. */ -unsigned pa_dynarray_append(pa_dynarray*a, void *p); - -void *pa_dynarray_get(pa_dynarray*a, unsigned i); - -unsigned pa_dynarray_size(pa_dynarray*a); - -#endif diff --git a/src/polypcore/endianmacros.h b/src/polypcore/endianmacros.h deleted file mode 100644 index 3ab1826a..00000000 --- a/src/polypcore/endianmacros.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef fooendianmacroshfoo -#define fooendianmacroshfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define INT16_SWAP(x) ( (int16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) ) -#define UINT16_SWAP(x) ( (uint16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) ) -#define INT32_SWAP(x) ( (int32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) ) -#define UINT32_SWAP(x) ( (uint32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) ) - -#define MAYBE_INT32_SWAP(c,x) ((c) ? INT32_SWAP(x) : x) -#define MAYBE_UINT32_SWAP(c,x) ((c) ? UINT32_SWAP(x) : x) - -#ifdef WORDS_BIGENDIAN - #define INT16_FROM_LE(x) INT16_SWAP(x) - #define INT16_FROM_BE(x) ((int16_t)(x)) - - #define INT16_TO_LE(x) INT16_SWAP(x) - #define INT16_TO_BE(x) ((int16_t)(x)) - - #define UINT16_FROM_LE(x) UINT16_SWAP(x) - #define UINT16_FROM_BE(x) ((uint16_t)(x)) - - #define INT32_FROM_LE(x) INT32_SWAP(x) - #define INT32_FROM_BE(x) ((int32_t)(x)) - - #define UINT32_FROM_LE(x) UINT32_SWAP(x) - #define UINT32_FROM_BE(x) ((uint32_t)(x)) - - #define UINT32_TO_LE(x) UINT32_SWAP(x) - #define UINT32_TO_BE(x) ((uint32_t)(x)) -#else - #define INT16_FROM_LE(x) ((int16_t)(x)) - #define INT16_FROM_BE(x) INT16_SWAP(x) - - #define INT16_TO_LE(x) ((int16_t)(x)) - #define INT16_TO_BE(x) INT16_SWAP(x) - - #define UINT16_FROM_LE(x) ((uint16_t)(x)) - #define UINT16_FROM_BE(x) UINT16_SWAP(x) - - #define INT32_FROM_LE(x) ((int32_t)(x)) - #define INT32_FROM_BE(x) INT32_SWAP(x) - - #define UINT32_FROM_LE(x) ((uint32_t)(x)) - #define UINT32_FROM_BE(x) UINT32_SWAP(x) - - #define UINT32_TO_LE(x) ((uint32_t)(x)) - #define UINT32_TO_BE(x) UINT32_SWAP(x) -#endif - -#endif diff --git a/src/polypcore/esound.h b/src/polypcore/esound.h deleted file mode 100644 index 9c507ef9..00000000 --- a/src/polypcore/esound.h +++ /dev/null @@ -1,209 +0,0 @@ -#ifndef fooesoundhfoo -#define fooesoundhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -/* Most of the following is blatantly stolen from esound. */ - - -/* path and name of the default EsounD domain socket */ -#define ESD_UNIX_SOCKET_DIR "/tmp/.esd" -#define ESD_UNIX_SOCKET_NAME "/tmp/.esd/socket" - -/* length of the audio buffer size */ -#define ESD_BUF_SIZE (4 * 1024) -/* maximum size we can write(). Otherwise we might overflow */ -#define ESD_MAX_WRITE_SIZE (21 * 4096) - -/* length of the authorization key, octets */ -#define ESD_KEY_LEN (16) - -/* default port for the EsounD server */ -#define ESD_DEFAULT_PORT (16001) - -/* default sample rate for the EsounD server */ -#define ESD_DEFAULT_RATE (44100) - -/* maximum length of a stream/sample name */ -#define ESD_NAME_MAX (128) - -/* a magic number to identify the relative endianness of a client */ -#define ESD_ENDIAN_KEY ((uint32_t) (('E' << 24) + ('N' << 16) + ('D' << 8) + ('N'))) - -#define ESD_VOLUME_BASE (256) - - -/*************************************/ -/* what can we do to/with the EsounD */ -enum esd_proto { - ESD_PROTO_CONNECT, /* implied on inital client connection */ - - /* pseudo "security" functionality */ - ESD_PROTO_LOCK, /* disable "foreign" client connections */ - ESD_PROTO_UNLOCK, /* enable "foreign" client connections */ - - /* stream functionality: play, record, monitor */ - ESD_PROTO_STREAM_PLAY, /* play all following data as a stream */ - ESD_PROTO_STREAM_REC, /* record data from card as a stream */ - ESD_PROTO_STREAM_MON, /* send mixed buffer output as a stream */ - - /* sample functionality: cache, free, play, loop, EOL, kill */ - ESD_PROTO_SAMPLE_CACHE, /* cache a sample in the server */ - ESD_PROTO_SAMPLE_FREE, /* release a sample in the server */ - ESD_PROTO_SAMPLE_PLAY, /* play a cached sample */ - ESD_PROTO_SAMPLE_LOOP, /* loop a cached sample, til eoloop */ - ESD_PROTO_SAMPLE_STOP, /* stop a looping sample when done */ - ESD_PROTO_SAMPLE_KILL, /* stop the looping sample immed. */ - - /* free and reclaim /dev/dsp functionality */ - ESD_PROTO_STANDBY, /* release /dev/dsp and ignore all data */ - ESD_PROTO_RESUME, /* reclaim /dev/dsp and play sounds again */ - - /* TODO: move these to a more logical place. NOTE: will break the protocol */ - ESD_PROTO_SAMPLE_GETID, /* get the ID for an already-cached sample */ - ESD_PROTO_STREAM_FILT, /* filter mixed buffer output as a stream */ - - /* esd remote management */ - ESD_PROTO_SERVER_INFO, /* get server info (ver, sample rate, format) */ - ESD_PROTO_ALL_INFO, /* get all info (server info, players, samples) */ - ESD_PROTO_SUBSCRIBE, /* track new and removed players and samples */ - ESD_PROTO_UNSUBSCRIBE, /* stop tracking updates */ - - /* esd remote control */ - ESD_PROTO_STREAM_PAN, /* set stream panning */ - ESD_PROTO_SAMPLE_PAN, /* set default sample panning */ - - /* esd status */ - ESD_PROTO_STANDBY_MODE, /* see if server is in standby, autostandby, etc */ - - /* esd latency */ - ESD_PROTO_LATENCY, /* retrieve latency between write()'s and output */ - - ESD_PROTO_MAX /* for bounds checking */ -}; - -/******************/ -/* The EsounD api */ - -/* the properties of a sound buffer are logically or'd */ - -/* bits of stream/sample data */ -#define ESD_MASK_BITS ( 0x000F ) -#define ESD_BITS8 ( 0x0000 ) -#define ESD_BITS16 ( 0x0001 ) - -/* how many interleaved channels of data */ -#define ESD_MASK_CHAN ( 0x00F0 ) -#define ESD_MONO ( 0x0010 ) -#define ESD_STEREO ( 0x0020 ) - -/* whether it's a stream or a sample */ -#define ESD_MASK_MODE ( 0x0F00 ) -#define ESD_STREAM ( 0x0000 ) -#define ESD_SAMPLE ( 0x0100 ) -#define ESD_ADPCM ( 0x0200 ) /* TODO: anyone up for this? =P */ - -/* the function of the stream/sample, and common functions */ -#define ESD_MASK_FUNC ( 0xF000 ) -#define ESD_PLAY ( 0x1000 ) -/* functions for streams only */ -#define ESD_MONITOR ( 0x0000 ) -#define ESD_RECORD ( 0x2000 ) -/* functions for samples only */ -#define ESD_STOP ( 0x0000 ) -#define ESD_LOOP ( 0x2000 ) - -typedef int esd_format_t; -typedef int esd_proto_t; - -/*******************************************************************/ -/* esdmgr.c - functions to implement a "sound manager" for esd */ - -/* structures to retrieve information about streams/samples from the server */ -typedef struct esd_server_info { - - int version; /* server version encoded as an int */ - esd_format_t format; /* magic int with the format info */ - int rate; /* sample rate */ - -} esd_server_info_t; - -typedef struct esd_player_info { - - struct esd_player_info *next; /* point to next entry in list */ - esd_server_info_t *server; /* the server that contains this stream */ - - int source_id; /* either a stream fd or sample id */ - char name[ ESD_NAME_MAX ]; /* name of stream for remote control */ - int rate; /* sample rate */ - int left_vol_scale; /* volume scaling */ - int right_vol_scale; - - esd_format_t format; /* magic int with the format info */ - -} esd_player_info_t; - -typedef struct esd_sample_info { - - struct esd_sample_info *next; /* point to next entry in list */ - esd_server_info_t *server; /* the server that contains this sample */ - - int sample_id; /* either a stream fd or sample id */ - char name[ ESD_NAME_MAX ]; /* name of stream for remote control */ - int rate; /* sample rate */ - int left_vol_scale; /* volume scaling */ - int right_vol_scale; - - esd_format_t format; /* magic int with the format info */ - int length; /* total buffer length */ - -} esd_sample_info_t; - -typedef struct esd_info { - - esd_server_info_t *server; - esd_player_info_t *player_list; - esd_sample_info_t *sample_list; - -} esd_info_t; - -enum esd_standby_mode { - ESM_ERROR, ESM_ON_STANDBY, ESM_ON_AUTOSTANDBY, ESM_RUNNING -}; -typedef int esd_standby_mode_t; - -enum esd_client_state { - ESD_STREAMING_DATA, /* data from here on is streamed data */ - ESD_CACHING_SAMPLE, /* midway through caching a sample */ - ESD_NEEDS_REQDATA, /* more data needed to complere request */ - ESD_NEXT_REQUEST, /* proceed to next request */ - ESD_CLIENT_STATE_MAX /* place holder */ -}; -typedef int esd_client_state_t; - -/* the endian key is transferred in binary, if it's read into int, */ -/* and matches ESD_ENDIAN_KEY (ENDN), then the endianness of the */ -/* server and the client match; if it's SWAP_ENDIAN_KEY, swap data */ -#define ESD_SWAP_ENDIAN_KEY (UINT32_SWAP(ESD_ENDIAN_KEY)) - - -#endif diff --git a/src/polypcore/g711.c b/src/polypcore/g711.c deleted file mode 100644 index 55a82396..00000000 --- a/src/polypcore/g711.c +++ /dev/null @@ -1,2531 +0,0 @@ -/* - * This source code is a product of Sun Microsystems, Inc. and is provided - * for unrestricted use. Users may copy or modify this source code without - * charge. - * - * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING - * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR - * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * - * Sun source code is provided with no support and without any obligation on - * the part of Sun Microsystems, Inc. to assist in its use, correction, - * modification or enhancement. - * - * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE - * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE - * OR ANY PART THEREOF. - * - * In no event will Sun Microsystems, Inc. be liable for any lost revenue - * or profits or other special, indirect and consequential damages, even if - * Sun has been advised of the possibility of such damages. - * - * Sun Microsystems, Inc. - * 2550 Garcia Avenue - * Mountain View, California 94043 - */ - -/* - * g711.c - * - * u-law, A-law and linear PCM conversions. - */ - -/* - * December 30, 1994: - * Functions linear2alaw, linear2ulaw have been updated to correctly - * convert unquantized 16 bit values. - * Tables for direct u- to A-law and A- to u-law conversions have been - * corrected. - * Borge Lindberg, Center for PersonKommunikation, Aalborg University. - * bli@cpk.auc.dk - * - */ - -#include "g711.h" - -#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ -#define QUANT_MASK (0xf) /* Quantization field mask. */ -#define NSEGS (8) /* Number of A-law segments. */ -#define SEG_SHIFT (4) /* Left shift for segment number. */ -#define SEG_MASK (0x70) /* Segment field mask. */ - -#if !defined(FAST_ALAW_CONVERSION) || !defined(FAST_ULAW_CONVERSION) -static int16_t seg_aend[8] = {0x1F, 0x3F, 0x7F, 0xFF, - 0x1FF, 0x3FF, 0x7FF, 0xFFF}; -static int16_t seg_uend[8] = {0x3F, 0x7F, 0xFF, 0x1FF, - 0x3FF, 0x7FF, 0xFFF, 0x1FFF}; - -static int16_t search( - int16_t val, - int16_t *table, - int size) -{ - int i; - - for (i = 0; i < size; i++) { - if (val <= *table++) - return (i); - } - return (size); -} -#endif /* !FAST_*_CONVERSION */ - -#ifndef FAST_ALAW_CONVERSION -/* - * linear2alaw() accepts an 13-bit signed integer and encodes it as A-law data - * stored in a unsigned char. This function should only be called with - * the data shifted such that it only contains information in the lower - * 13-bits. - * - * Linear Input Code Compressed Code - * ------------------------ --------------- - * 0000000wxyza 000wxyz - * 0000001wxyza 001wxyz - * 000001wxyzab 010wxyz - * 00001wxyzabc 011wxyz - * 0001wxyzabcd 100wxyz - * 001wxyzabcde 101wxyz - * 01wxyzabcdef 110wxyz - * 1wxyzabcdefg 111wxyz - * - * For further information see John C. Bellamy's Digital Telephony, 1982, - * John Wiley & Sons, pps 98-111 and 472-476. - */ -unsigned char st_13linear2alaw( - int16_t pcm_val) /* 2's complement (13-bit range) */ -{ - int16_t mask; - short seg; - unsigned char aval; - - /* Have calling software do it since its already doing a shift - * from 32-bits down to 16-bits. - */ - /* pcm_val = pcm_val >> 3; */ - - /* A-law using even bit inversion */ - if (pcm_val >= 0) { - mask = 0xD5; /* sign (7th) bit = 1 */ - } else { - mask = 0x55; /* sign bit = 0 */ - pcm_val = -pcm_val - 1; - } - - /* Convert the scaled magnitude to segment number. */ - seg = search(pcm_val, seg_aend, 8); - - /* Combine the sign, segment, and quantization bits. */ - - if (seg >= 8) /* out of range, return maximum value. */ - return (unsigned char) (0x7F ^ mask); - else { - aval = (unsigned char) seg << SEG_SHIFT; - if (seg < 2) - aval |= (pcm_val >> 1) & QUANT_MASK; - else - aval |= (pcm_val >> seg) & QUANT_MASK; - return (aval ^ mask); - } -} - -/* - * alaw2linear() - Convert an A-law value to 16-bit signed linear PCM - * - */ -int16_t st_alaw2linear16( - unsigned char a_val) -{ - int16_t t; - int16_t seg; - - a_val ^= 0x55; - - t = (a_val & QUANT_MASK) << 4; - seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT; - switch (seg) { - case 0: - t += 8; - break; - case 1: - t += 0x108; - break; - default: - t += 0x108; - t <<= seg - 1; - } - return ((a_val & SIGN_BIT) ? t : -t); -} -#endif /* !FAST_ALAW_CONVERSION */ - -#define BIAS (0x84) /* Bias for linear code. */ -#define CLIP 8159 - -#ifndef FAST_ULAW_CONVERSION -/* - * linear2ulaw() accepts a 14-bit signed integer and encodes it as u-law data - * stored in a unsigned char. This function should only be called with - * the data shifted such that it only contains information in the lower - * 14-bits. - * - * In order to simplify the encoding process, the original linear magnitude - * is biased by adding 33 which shifts the encoding range from (0 - 8158) to - * (33 - 8191). The result can be seen in the following encoding table: - * - * Biased Linear Input Code Compressed Code - * ------------------------ --------------- - * 00000001wxyza 000wxyz - * 0000001wxyzab 001wxyz - * 000001wxyzabc 010wxyz - * 00001wxyzabcd 011wxyz - * 0001wxyzabcde 100wxyz - * 001wxyzabcdef 101wxyz - * 01wxyzabcdefg 110wxyz - * 1wxyzabcdefgh 111wxyz - * - * Each biased linear code has a leading 1 which identifies the segment - * number. The value of the segment number is equal to 7 minus the number - * of leading 0's. The quantization interval is directly available as the - * four bits wxyz. * The trailing bits (a - h) are ignored. - * - * Ordinarily the complement of the resulting code word is used for - * transmission, and so the code word is complemented before it is returned. - * - * For further information see John C. Bellamy's Digital Telephony, 1982, - * John Wiley & Sons, pps 98-111 and 472-476. - */ -unsigned char st_14linear2ulaw( - int16_t pcm_val) /* 2's complement (14-bit range) */ -{ - int16_t mask; - int16_t seg; - unsigned char uval; - - /* Have calling software do it since its already doing a shift - * from 32-bits down to 16-bits. - */ - /* pcm_val = pcm_val >> 2; */ - - /* u-law inverts all bits */ - /* Get the sign and the magnitude of the value. */ - if (pcm_val < 0) { - pcm_val = -pcm_val; - mask = 0x7F; - } else { - mask = 0xFF; - } - if ( pcm_val > CLIP ) pcm_val = CLIP; /* clip the magnitude */ - pcm_val += (BIAS >> 2); - - /* Convert the scaled magnitude to segment number. */ - seg = search(pcm_val, seg_uend, 8); - - /* - * Combine the sign, segment, quantization bits; - * and complement the code word. - */ - if (seg >= 8) /* out of range, return maximum value. */ - return (unsigned char) (0x7F ^ mask); - else { - uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF); - return (uval ^ mask); - } - -} - -/* - * ulaw2linear() - Convert a u-law value to 16-bit linear PCM - * - * First, a biased linear code is derived from the code word. An unbiased - * output can then be obtained by subtracting 33 from the biased code. - * - * Note that this function expects to be passed the complement of the - * original code word. This is in keeping with ISDN conventions. - */ -int16_t st_ulaw2linear16( - unsigned char u_val) -{ - int16_t t; - - /* Complement to obtain normal u-law value. */ - u_val = ~u_val; - - /* - * Extract and bias the quantization bits. Then - * shift up by the segment number and subtract out the bias. - */ - t = ((u_val & QUANT_MASK) << 3) + BIAS; - t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; - - return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); -} -#endif /* !FAST_ULAW_CONVERSION */ - -#ifdef FAST_ALAW_CONVERSION - -int16_t _st_alaw2linear16[256] = { - -5504, -5248, -6016, -5760, -4480, -4224, -4992, - -4736, -7552, -7296, -8064, -7808, -6528, -6272, - -7040, -6784, -2752, -2624, -3008, -2880, -2240, - -2112, -2496, -2368, -3776, -3648, -4032, -3904, - -3264, -3136, -3520, -3392, -22016, -20992, -24064, - -23040, -17920, -16896, -19968, -18944, -30208, -29184, - -32256, -31232, -26112, -25088, -28160, -27136, -11008, - -10496, -12032, -11520, -8960, -8448, -9984, -9472, - -15104, -14592, -16128, -15616, -13056, -12544, -14080, - -13568, -344, -328, -376, -360, -280, -264, - -312, -296, -472, -456, -504, -488, -408, - -392, -440, -424, -88, -72, -120, -104, - -24, -8, -56, -40, -216, -200, -248, - -232, -152, -136, -184, -168, -1376, -1312, - -1504, -1440, -1120, -1056, -1248, -1184, -1888, - -1824, -2016, -1952, -1632, -1568, -1760, -1696, - -688, -656, -752, -720, -560, -528, -624, - -592, -944, -912, -1008, -976, -816, -784, - -880, -848, 5504, 5248, 6016, 5760, 4480, - 4224, 4992, 4736, 7552, 7296, 8064, 7808, - 6528, 6272, 7040, 6784, 2752, 2624, 3008, - 2880, 2240, 2112, 2496, 2368, 3776, 3648, - 4032, 3904, 3264, 3136, 3520, 3392, 22016, - 20992, 24064, 23040, 17920, 16896, 19968, 18944, - 30208, 29184, 32256, 31232, 26112, 25088, 28160, - 27136, 11008, 10496, 12032, 11520, 8960, 8448, - 9984, 9472, 15104, 14592, 16128, 15616, 13056, - 12544, 14080, 13568, 344, 328, 376, 360, - 280, 264, 312, 296, 472, 456, 504, - 488, 408, 392, 440, 424, 88, 72, - 120, 104, 24, 8, 56, 40, 216, - 200, 248, 232, 152, 136, 184, 168, - 1376, 1312, 1504, 1440, 1120, 1056, 1248, - 1184, 1888, 1824, 2016, 1952, 1632, 1568, - 1760, 1696, 688, 656, 752, 720, 560, - 528, 624, 592, 944, 912, 1008, 976, - 816, 784, 880, 848 -}; - -uint8_t _st_13linear2alaw[0x2000] = { - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, - 0x6b, 0x6b, 0x6b, 0x6b, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, - 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x6e, 0x6e, 0x6e, 0x6e, - 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, - 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, - 0x6d, 0x6d, 0x6d, 0x6d, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x60, 0x60, 0x60, 0x60, - 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, - 0x67, 0x67, 0x67, 0x67, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, - 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x7a, 0x7a, 0x7a, 0x7a, - 0x7b, 0x7b, 0x7b, 0x7b, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, - 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7c, 0x7c, 0x7c, 0x7c, - 0x7d, 0x7d, 0x7d, 0x7d, 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x73, - 0x70, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x71, 0x76, 0x76, 0x76, 0x76, - 0x77, 0x77, 0x77, 0x77, 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x75, - 0x4a, 0x4a, 0x4b, 0x4b, 0x48, 0x48, 0x49, 0x49, 0x4e, 0x4e, 0x4f, 0x4f, - 0x4c, 0x4c, 0x4d, 0x4d, 0x42, 0x42, 0x43, 0x43, 0x40, 0x40, 0x41, 0x41, - 0x46, 0x46, 0x47, 0x47, 0x44, 0x44, 0x45, 0x45, 0x5a, 0x5a, 0x5b, 0x5b, - 0x58, 0x58, 0x59, 0x59, 0x5e, 0x5e, 0x5f, 0x5f, 0x5c, 0x5c, 0x5d, 0x5d, - 0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51, 0x56, 0x56, 0x57, 0x57, - 0x54, 0x54, 0x55, 0x55, 0xd5, 0xd5, 0xd4, 0xd4, 0xd7, 0xd7, 0xd6, 0xd6, - 0xd1, 0xd1, 0xd0, 0xd0, 0xd3, 0xd3, 0xd2, 0xd2, 0xdd, 0xdd, 0xdc, 0xdc, - 0xdf, 0xdf, 0xde, 0xde, 0xd9, 0xd9, 0xd8, 0xd8, 0xdb, 0xdb, 0xda, 0xda, - 0xc5, 0xc5, 0xc4, 0xc4, 0xc7, 0xc7, 0xc6, 0xc6, 0xc1, 0xc1, 0xc0, 0xc0, - 0xc3, 0xc3, 0xc2, 0xc2, 0xcd, 0xcd, 0xcc, 0xcc, 0xcf, 0xcf, 0xce, 0xce, - 0xc9, 0xc9, 0xc8, 0xc8, 0xcb, 0xcb, 0xca, 0xca, 0xf5, 0xf5, 0xf5, 0xf5, - 0xf4, 0xf4, 0xf4, 0xf4, 0xf7, 0xf7, 0xf7, 0xf7, 0xf6, 0xf6, 0xf6, 0xf6, - 0xf1, 0xf1, 0xf1, 0xf1, 0xf0, 0xf0, 0xf0, 0xf0, 0xf3, 0xf3, 0xf3, 0xf3, - 0xf2, 0xf2, 0xf2, 0xf2, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xf9, 0xf9, 0xf9, 0xf9, - 0xf8, 0xf8, 0xf8, 0xf8, 0xfb, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xfa, - 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4, - 0xe4, 0xe4, 0xe4, 0xe4, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, - 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe1, 0xe1, 0xe1, 0xe1, - 0xe1, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, - 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, - 0xe2, 0xe2, 0xe2, 0xe2, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, - 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xef, 0xef, 0xef, 0xef, - 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, - 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, - 0xe8, 0xe8, 0xe8, 0xe8, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, - 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa -}; - -#endif /* FAST_ALAW_CONVERSION */ - -#ifdef FAST_ULAW_CONVERSION - -int16_t _st_ulaw2linear16[256] = { - -32124, -31100, -30076, -29052, -28028, -27004, -25980, - -24956, -23932, -22908, -21884, -20860, -19836, -18812, - -17788, -16764, -15996, -15484, -14972, -14460, -13948, - -13436, -12924, -12412, -11900, -11388, -10876, -10364, - -9852, -9340, -8828, -8316, -7932, -7676, -7420, - -7164, -6908, -6652, -6396, -6140, -5884, -5628, - -5372, -5116, -4860, -4604, -4348, -4092, -3900, - -3772, -3644, -3516, -3388, -3260, -3132, -3004, - -2876, -2748, -2620, -2492, -2364, -2236, -2108, - -1980, -1884, -1820, -1756, -1692, -1628, -1564, - -1500, -1436, -1372, -1308, -1244, -1180, -1116, - -1052, -988, -924, -876, -844, -812, -780, - -748, -716, -684, -652, -620, -588, -556, - -524, -492, -460, -428, -396, -372, -356, - -340, -324, -308, -292, -276, -260, -244, - -228, -212, -196, -180, -164, -148, -132, - -120, -112, -104, -96, -88, -80, -72, - -64, -56, -48, -40, -32, -24, -16, - -8, 0, 32124, 31100, 30076, 29052, 28028, - 27004, 25980, 24956, 23932, 22908, 21884, 20860, - 19836, 18812, 17788, 16764, 15996, 15484, 14972, - 14460, 13948, 13436, 12924, 12412, 11900, 11388, - 10876, 10364, 9852, 9340, 8828, 8316, 7932, - 7676, 7420, 7164, 6908, 6652, 6396, 6140, - 5884, 5628, 5372, 5116, 4860, 4604, 4348, - 4092, 3900, 3772, 3644, 3516, 3388, 3260, - 3132, 3004, 2876, 2748, 2620, 2492, 2364, - 2236, 2108, 1980, 1884, 1820, 1756, 1692, - 1628, 1564, 1500, 1436, 1372, 1308, 1244, - 1180, 1116, 1052, 988, 924, 876, 844, - 812, 780, 748, 716, 684, 652, 620, - 588, 556, 524, 492, 460, 428, 396, - 372, 356, 340, 324, 308, 292, 276, - 260, 244, 228, 212, 196, 180, 164, - 148, 132, 120, 112, 104, 96, 88, - 80, 72, 64, 56, 48, 40, 32, - 24, 16, 8, 0 -}; - -uint8_t _st_14linear2ulaw[0x4000] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x40, 0x40, - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, - 0x40, 0x40, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, - 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, - 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, - 0x43, 0x43, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, - 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, - 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x46, 0x46, - 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, - 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, - 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, - 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, - 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, - 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, - 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, - 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, - 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, - 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, - 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, - 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, - 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, - 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, - 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, - 0x52, 0x52, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, - 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x57, 0x57, - 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, - 0x58, 0x58, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a, 0x5a, - 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, - 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, - 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, - 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x60, 0x60, - 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x62, 0x63, 0x63, - 0x63, 0x63, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, - 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, - 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, - 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, - 0x6f, 0x6f, 0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x74, 0x74, - 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a, - 0x7b, 0x7b, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0xff, 0xfe, 0xfe, 0xfd, - 0xfd, 0xfc, 0xfc, 0xfb, 0xfb, 0xfa, 0xfa, 0xf9, 0xf9, 0xf8, 0xf8, 0xf7, - 0xf7, 0xf6, 0xf6, 0xf5, 0xf5, 0xf4, 0xf4, 0xf3, 0xf3, 0xf2, 0xf2, 0xf1, - 0xf1, 0xf0, 0xf0, 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xed, - 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xeb, 0xeb, 0xeb, 0xeb, 0xea, - 0xea, 0xea, 0xea, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, 0xe7, - 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, - 0xe4, 0xe4, 0xe4, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, 0xe1, - 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, - 0xdf, 0xdf, 0xdf, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, - 0xdc, 0xdc, 0xdc, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xda, - 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, - 0xd9, 0xd9, 0xd9, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd7, - 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, - 0xd6, 0xd6, 0xd6, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd4, - 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, - 0xd3, 0xd3, 0xd3, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd1, - 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, - 0xd0, 0xd0, 0xd0, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, - 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xce, 0xce, 0xce, 0xce, 0xce, - 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xcd, - 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, - 0xcd, 0xcd, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, - 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, - 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xca, - 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, - 0xca, 0xca, 0xca, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, - 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, - 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc7, - 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, - 0xc7, 0xc7, 0xc7, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, - 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, - 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc4, - 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, - 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, - 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, - 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc1, - 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, - 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, - 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80 -}; - -#endif /* FAST_ULAW_CONVERSION */ - -/* The following code was used to generate the lookup tables */ -#if 0 -int main() -{ - int x, y, find2a = 0; - - y = 0; - printf("int16_t _st_alaw2linear16[256] = {\n "); - for (x = 0; x < 256; x++) - { - printf("%8d,", st_alaw2linear16(x)); - y++; - if (y == 7) - { - y = 0; - printf("\n "); - } - } - - printf("\n};\n\nuint8_t _st_13linear2alaw[0x2000] = {\n "); - y = 0; - for (x = 0; x < 0x2000; x++) - { - printf(" 0x%02x,", st_13linear2alaw((-0x1000)+x)); - y++; - if (y == 12) - { - y = 0; - printf("\n "); - } - } - - printf("\n};\n\nint16_t _st_ulaw2linear16[256] = {\n "); - y = 0; - for (x = 0; x < 256; x++) - { - printf("%8d,", st_ulaw2linear16(x)); - y++; - if (y == 7) - { - y = 0; - printf("\n "); - } - } - - printf("\n};\n\nuint8_t _st_14linear2ulaw[0x4000] = {\n "); - y = 0; - for (x = 0; x < 0x4000; x++) - { - printf(" 0x%02x,", st_14linear2ulaw((-0x2000)+x)); - y++; - if (y == 12) - { - y = 0; - printf("\n "); - } - } - printf("\n};\n"); - -} -#endif - -/* The following is not used by SoX but kept for reference */ -#if 0 -/* copy from CCITT G.711 specifications */ -unsigned char _u2a[128] = { /* u- to A-law conversions */ - 1, 1, 2, 2, 3, 3, 4, 4, - 5, 5, 6, 6, 7, 7, 8, 8, - 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, - 25, 27, 29, 31, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, - 46, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, - 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, -/* corrected: - 81, 82, 83, 84, 85, 86, 87, 88, - should be: */ - 80, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, 126, 127, 128}; - -unsigned char _a2u[128] = { /* A- to u-law conversions */ - 1, 3, 5, 7, 9, 11, 13, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 32, 33, 33, 34, 34, 35, 35, - 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 48, 49, 49, - 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 64, - 65, 66, 67, 68, 69, 70, 71, 72, -/* corrected: - 73, 74, 75, 76, 77, 78, 79, 79, - should be: */ - 73, 74, 75, 76, 77, 78, 79, 80, - - 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127}; - -/* A-law to u-law conversion */ -unsigned char st_alaw2ulaw( - unsigned char aval) -{ - aval &= 0xff; - return (unsigned char) ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) : - (0x7F ^ _a2u[aval ^ 0x55])); -} - -/* u-law to A-law conversion */ -unsigned char st_ulaw2alaw( - unsigned char uval) -{ - uval &= 0xff; - return (unsigned char) ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) : - (unsigned char) (0x55 ^ (_u2a[0x7F ^ uval] - 1))); -} -#endif diff --git a/src/polypcore/g711.h b/src/polypcore/g711.h deleted file mode 100644 index 97cedf81..00000000 --- a/src/polypcore/g711.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef foog711hfoo -#define foog711hfoo - -/* g711.h - include for G711 u-law and a-law conversion routines -** -** Copyright (C) 2001 Chris Bagwell -** -** Permission to use, copy, modify, and distribute this software and its -** documentation for any purpose and without fee is hereby granted, provided -** that the above copyright notice appear in all copies and that both that -** copyright notice and this permission notice appear in supporting -** documentation. This software is provided "as is" without express or -** implied warranty. -*/ - -/** Copied from sox -- Lennart Poettring*/ - -#include - -#ifdef FAST_ALAW_CONVERSION -extern uint8_t _st_13linear2alaw[0x2000]; -extern int16_t _st_alaw2linear16[256]; -#define st_13linear2alaw(sw) (_st_13linear2alaw[(sw + 0x1000)]) -#define st_alaw2linear16(uc) (_st_alaw2linear16[uc]) -#else -unsigned char st_13linear2alaw(int16_t pcm_val); -int16_t st_alaw2linear16(unsigned char); -#endif - -#ifdef FAST_ULAW_CONVERSION -extern uint8_t _st_14linear2ulaw[0x4000]; -extern int16_t _st_ulaw2linear16[256]; -#define st_14linear2ulaw(sw) (_st_14linear2ulaw[(sw + 0x2000)]) -#define st_ulaw2linear16(uc) (_st_ulaw2linear16[uc]) -#else -unsigned char st_14linear2ulaw(int16_t pcm_val); -int16_t st_ulaw2linear16(unsigned char); -#endif - -#endif diff --git a/src/polypcore/gccmacro.h b/src/polypcore/gccmacro.h deleted file mode 100644 index 9e212f2e..00000000 --- a/src/polypcore/gccmacro.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef foogccmacrohfoo -#define foogccmacrohfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef __GNUC__ -#define PA_GCC_PRINTF_ATTR(a,b) __attribute__ ((format (printf, a, b))) -#else -/** If we're in GNU C, use some magic for detecting invalid format strings */ -#define PA_GCC_PRINTF_ATTR(a,b) -#endif - -#if defined(__GNUC__) && (__GNUC__ >= 4) -#define PA_GCC_SENTINEL __attribute__ ((sentinel)) -#else -/** Macro for usage of GCC's sentinel compilation warnings */ -#define PA_GCC_SENTINEL -#endif - -#ifdef __GNUC__ -#define PA_GCC_NORETURN __attribute__((noreturn)) -#else -/** Macro for no-return functions */ -#define PA_GCC_NORETURN -#endif - -#ifdef __GNUC__ -#define PA_GCC_UNUSED __attribute__ ((unused)) -#else -/** Macro for not used parameter */ -#define PA_GCC_UNUSED -#endif - -#endif diff --git a/src/polypcore/hashmap.c b/src/polypcore/hashmap.c deleted file mode 100644 index adc322f0..00000000 --- a/src/polypcore/hashmap.c +++ /dev/null @@ -1,196 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include - -#include -#include - -#include "hashmap.h" - -#define BUCKETS 1023 - -struct hashmap_entry { - struct hashmap_entry *next, *previous, *bucket_next, *bucket_previous; - unsigned hash; - const void *key; - void *value; -}; - -struct pa_hashmap { - unsigned size; - struct hashmap_entry **data; - struct hashmap_entry *first_entry; - - unsigned n_entries; - unsigned (*hash_func) (const void *p); - int (*compare_func) (const void*a, const void*b); -}; - -pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { - pa_hashmap *h; - h = pa_xmalloc(sizeof(pa_hashmap)); - h->data = pa_xmalloc0(sizeof(struct hashmap_entry*)*(h->size = BUCKETS)); - h->first_entry = NULL; - h->n_entries = 0; - h->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; - h->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; - return h; -} - -static void remove(pa_hashmap *h, struct hashmap_entry *e) { - assert(e); - - if (e->next) - e->next->previous = e->previous; - if (e->previous) - e->previous->next = e->next; - else - h->first_entry = e->next; - - if (e->bucket_next) - e->bucket_next->bucket_previous = e->bucket_previous; - if (e->bucket_previous) - e->bucket_previous->bucket_next = e->bucket_next; - else { - assert(e->hash < h->size); - h->data[e->hash] = e->bucket_next; - } - - pa_xfree(e); - h->n_entries--; -} - -void pa_hashmap_free(pa_hashmap*h, void (*free_func)(void *p, void *userdata), void *userdata) { - assert(h); - - while (h->first_entry) { - if (free_func) - free_func(h->first_entry->value, userdata); - remove(h, h->first_entry); - } - - pa_xfree(h->data); - pa_xfree(h); -} - -static struct hashmap_entry *get(pa_hashmap *h, unsigned hash, const void *key) { - struct hashmap_entry *e; - assert(h && hash < h->size); - - for (e = h->data[hash]; e; e = e->bucket_next) - if (h->compare_func(e->key, key) == 0) - return e; - - return NULL; -} - -int pa_hashmap_put(pa_hashmap *h, const void *key, void *value) { - struct hashmap_entry *e; - unsigned hash; - assert(h); - - hash = h->hash_func(key) % h->size; - - if ((e = get(h, hash, key))) - return -1; - - e = pa_xmalloc(sizeof(struct hashmap_entry)); - e->hash = hash; - e->key = key; - e->value = value; - - e->previous = NULL; - e->next = h->first_entry; - if (h->first_entry) - h->first_entry->previous = e; - h->first_entry = e; - - e->bucket_previous = NULL; - e->bucket_next = h->data[hash]; - if (h->data[hash]) - h->data[hash]->bucket_previous = e; - h->data[hash] = e; - - h->n_entries ++; - return 0; -} - -void* pa_hashmap_get(pa_hashmap *h, const void *key) { - unsigned hash; - struct hashmap_entry *e; - assert(h && key); - - hash = h->hash_func(key) % h->size; - - if (!(e = get(h, hash, key))) - return NULL; - - return e->value; -} - -void* pa_hashmap_remove(pa_hashmap *h, const void *key) { - struct hashmap_entry *e; - unsigned hash; - void *data; - assert(h && key); - - hash = h->hash_func(key) % h->size; - - if (!(e = get(h, hash, key))) - return NULL; - - data = e->value; - remove(h, e); - return data; -} - -unsigned pa_hashmap_size(pa_hashmap *h) { - return h->n_entries; -} - -void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void **key) { - assert(h && state); - - if (!*state) - *state = h->first_entry; - else - *state = ((struct hashmap_entry*) *state)->next; - - if (!*state) { - if (key) - *key = NULL; - return NULL; - } - - if (key) - *key = ((struct hashmap_entry*) *state)->key; - - return ((struct hashmap_entry*) *state)->value; -} diff --git a/src/polypcore/hashmap.h b/src/polypcore/hashmap.h deleted file mode 100644 index 14f82705..00000000 --- a/src/polypcore/hashmap.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef foohashmaphfoo -#define foohashmaphfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -/* Simple Implementation of a hash table. Memory management is the - * user's job. It's a good idea to have the key pointer point to a - * string in the value data. */ - -typedef struct pa_hashmap pa_hashmap; - -/* Create a new hashmap. Use the specified functions for hashing and comparing objects in the map */ -pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); - -/* Free the hash table. Calls the specified function for every value in the table. The function may be NULL */ -void pa_hashmap_free(pa_hashmap*, void (*free_func)(void *p, void *userdata), void *userdata); - -/* Returns non-zero when the entry already exists */ -int pa_hashmap_put(pa_hashmap *h, const void *key, void *value); -void* pa_hashmap_get(pa_hashmap *h, const void *key); - -/* Returns the data of the entry while removing */ -void* pa_hashmap_remove(pa_hashmap *h, const void *key); - -unsigned pa_hashmap_size(pa_hashmap *h); - -/* May be used to iterate through the hashmap. Initially the opaque - pointer *state has to be set to NULL. The hashmap may not be - modified during iteration. The key of the entry is returned in - *key, if key is non-NULL. After the last entry in the hashmap NULL - is returned. */ -void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void**key); - -#endif diff --git a/src/polypcore/idxset.c b/src/polypcore/idxset.c deleted file mode 100644 index bde5c279..00000000 --- a/src/polypcore/idxset.c +++ /dev/null @@ -1,391 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -#include "idxset.h" - -typedef struct idxset_entry { - void *data; - uint32_t index; - unsigned hash_value; - - struct idxset_entry *hash_prev, *hash_next; - struct idxset_entry* iterate_prev, *iterate_next; -} idxset_entry; - -struct pa_idxset { - unsigned (*hash_func) (const void *p); - int (*compare_func)(const void *a, const void *b); - - unsigned hash_table_size, n_entries; - idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail; - uint32_t index, start_index, array_size; -}; - -unsigned pa_idxset_string_hash_func(const void *p) { - unsigned hash = 0; - const char *c; - - for (c = p; *c; c++) - hash = 31 * hash + *c; - - return hash; -} - -int pa_idxset_string_compare_func(const void *a, const void *b) { - return strcmp(a, b); -} - -unsigned pa_idxset_trivial_hash_func(const void *p) { - return (unsigned) (long) p; -} - -int pa_idxset_trivial_compare_func(const void *a, const void *b) { - return a != b; -} - -pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { - pa_idxset *s; - - s = pa_xnew(pa_idxset, 1); - s->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; - s->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; - s->hash_table_size = 1023; - s->hash_table = pa_xmalloc0(sizeof(idxset_entry*)*s->hash_table_size); - s->array = NULL; - s->array_size = 0; - s->index = 0; - s->start_index = 0; - s->n_entries = 0; - - s->iterate_list_head = s->iterate_list_tail = NULL; - - return s; -} - -void pa_idxset_free(pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata) { - assert(s); - - while (s->iterate_list_head) { - idxset_entry *e = s->iterate_list_head; - s->iterate_list_head = s->iterate_list_head->iterate_next; - - if (free_func) - free_func(e->data, userdata); - pa_xfree(e); - } - - pa_xfree(s->hash_table); - pa_xfree(s->array); - pa_xfree(s); -} - -static idxset_entry* hash_scan(pa_idxset *s, idxset_entry* e, const void *p) { - assert(p); - - assert(s->compare_func); - for (; e; e = e->hash_next) - if (s->compare_func(e->data, p) == 0) - return e; - - return NULL; -} - -static void extend_array(pa_idxset *s, uint32_t idx) { - uint32_t i, j, l; - idxset_entry** n; - assert(idx >= s->start_index); - - if (idx < s->start_index + s->array_size) - return; - - for (i = 0; i < s->array_size; i++) - if (s->array[i]) - break; - - l = idx - s->start_index - i + 100; - n = pa_xnew0(idxset_entry*, l); - - for (j = 0; j < s->array_size-i; j++) - n[j] = s->array[i+j]; - - pa_xfree(s->array); - - s->array = n; - s->array_size = l; - s->start_index += i; -} - -static idxset_entry** array_index(pa_idxset*s, uint32_t idx) { - if (idx >= s->start_index + s->array_size) - return NULL; - - if (idx < s->start_index) - return NULL; - - return s->array + (idx - s->start_index); -} - -int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) { - unsigned h; - idxset_entry *e, **a; - assert(s && p); - - assert(s->hash_func); - h = s->hash_func(p) % s->hash_table_size; - - assert(s->hash_table); - if ((e = hash_scan(s, s->hash_table[h], p))) { - if (idx) - *idx = e->index; - - return -1; - } - - e = pa_xmalloc(sizeof(idxset_entry)); - e->data = p; - e->index = s->index++; - e->hash_value = h; - - /* Insert into hash table */ - e->hash_next = s->hash_table[h]; - e->hash_prev = NULL; - if (s->hash_table[h]) - s->hash_table[h]->hash_prev = e; - s->hash_table[h] = e; - - /* Insert into array */ - extend_array(s, e->index); - a = array_index(s, e->index); - assert(a && !*a); - *a = e; - - /* Insert into linked list */ - e->iterate_next = NULL; - e->iterate_prev = s->iterate_list_tail; - if (s->iterate_list_tail) { - assert(s->iterate_list_head); - s->iterate_list_tail->iterate_next = e; - } else { - assert(!s->iterate_list_head); - s->iterate_list_head = e; - } - s->iterate_list_tail = e; - - s->n_entries++; - assert(s->n_entries >= 1); - - if (idx) - *idx = e->index; - - return 0; -} - -void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx) { - idxset_entry **a; - assert(s); - - if (!(a = array_index(s, idx))) - return NULL; - - if (!*a) - return NULL; - - return (*a)->data; -} - -void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx) { - unsigned h; - idxset_entry *e; - assert(s && p); - - assert(s->hash_func); - h = s->hash_func(p) % s->hash_table_size; - - assert(s->hash_table); - if (!(e = hash_scan(s, s->hash_table[h], p))) - return NULL; - - if (idx) - *idx = e->index; - - return e->data; -} - -static void remove_entry(pa_idxset *s, idxset_entry *e) { - idxset_entry **a; - assert(s && e); - - /* Remove from array */ - a = array_index(s, e->index); - assert(a && *a && *a == e); - *a = NULL; - - /* Remove from linked list */ - if (e->iterate_next) - e->iterate_next->iterate_prev = e->iterate_prev; - else - s->iterate_list_tail = e->iterate_prev; - - if (e->iterate_prev) - e->iterate_prev->iterate_next = e->iterate_next; - else - s->iterate_list_head = e->iterate_next; - - /* Remove from hash table */ - if (e->hash_next) - e->hash_next->hash_prev = e->hash_prev; - - if (e->hash_prev) - e->hash_prev->hash_next = e->hash_next; - else - s->hash_table[e->hash_value] = e->hash_next; - - pa_xfree(e); - - assert(s->n_entries >= 1); - s->n_entries--; -} - -void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx) { - idxset_entry **a; - void *data; - - assert(s); - - if (!(a = array_index(s, idx))) - return NULL; - - data = (*a)->data; - remove_entry(s, *a); - - return data; -} - -void* pa_idxset_remove_by_data(pa_idxset*s, const void *data, uint32_t *idx) { - idxset_entry *e; - unsigned h; - void *r; - - assert(s->hash_func); - h = s->hash_func(data) % s->hash_table_size; - - assert(s->hash_table); - if (!(e = hash_scan(s, s->hash_table[h], data))) - return NULL; - - r = e->data; - if (idx) - *idx = e->index; - - remove_entry(s, e); - - return r; -} - -void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx) { - idxset_entry **a, *e = NULL; - assert(s && idx); - - if ((a = array_index(s, *idx)) && *a) - e = (*a)->iterate_next; - - if (!e) - e = s->iterate_list_head; - - if (!e) - return NULL; - - *idx = e->index; - return e->data; -} - -void* pa_idxset_first(pa_idxset *s, uint32_t *idx) { - assert(s); - - if (!s->iterate_list_head) - return NULL; - - if (idx) - *idx = s->iterate_list_head->index; - return s->iterate_list_head->data; -} - -void *pa_idxset_next(pa_idxset *s, uint32_t *idx) { - idxset_entry **a, *e = NULL; - assert(s && idx); - - if ((a = array_index(s, *idx)) && *a) - e = (*a)->iterate_next; - - if (e) { - *idx = e->index; - return e->data; - } else { - *idx = PA_IDXSET_INVALID; - return NULL; - } -} - - -int pa_idxset_foreach(pa_idxset*s, int (*func)(void *p, uint32_t idx, int *del, void*userdata), void *userdata) { - idxset_entry *e; - assert(s && func); - - e = s->iterate_list_head; - while (e) { - int del = 0, r; - idxset_entry *n = e->iterate_next; - - r = func(e->data, e->index, &del, userdata); - - if (del) - remove_entry(s, e); - - if (r < 0) - return r; - - e = n; - } - - return 0; -} - -unsigned pa_idxset_size(pa_idxset*s) { - assert(s); - return s->n_entries; -} - -int pa_idxset_isempty(pa_idxset *s) { - assert(s); - return s->n_entries == 0; -} - diff --git a/src/polypcore/idxset.h b/src/polypcore/idxset.h deleted file mode 100644 index 17ae16cb..00000000 --- a/src/polypcore/idxset.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef fooidxsethfoo -#define fooidxsethfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -/* A combination of a set and a dynamic array. Entries are indexable - * both through a numeric automatically generated index and the entry's - * data pointer. As usual, memory management is the user's job. */ - -/* A special index value denoting the invalid index. */ -#define PA_IDXSET_INVALID ((uint32_t) -1) - -/* Generic implementations for hash and comparison functions. Just - * compares the pointer or calculates the hash value directly from the - * pointer value. */ -unsigned pa_idxset_trivial_hash_func(const void *p); -int pa_idxset_trivial_compare_func(const void *a, const void *b); - -/* Generic implementations for hash and comparison functions for strings. */ -unsigned pa_idxset_string_hash_func(const void *p); -int pa_idxset_string_compare_func(const void *a, const void *b); - -typedef struct pa_idxset pa_idxset; - -/* Instantiate a new idxset with the specified hash and comparison functions */ -pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); - -/* Free the idxset. When the idxset is not empty the specified function is called for every entry contained */ -void pa_idxset_free(pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata); - -/* Store a new item in the idxset. The index of the item is returned in *idx */ -int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx); - -/* Get the entry by its idx */ -void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx); - -/* Get the entry by its data. The idx is returned in *index */ -void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx); - -/* Similar to pa_idxset_get_by_index(), but removes the entry from the idxset. */ -void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx); - -/* Similar to pa_idxset_get_by_data(), but removes the entry from the idxset */ -void* pa_idxset_remove_by_data(pa_idxset*s, const void *p, uint32_t *idx); - -/* This may be used to iterate through all entries. When called with - an invalid index value it returns the first entry, otherwise the - next following. The function is best called with *idx = - PA_IDXSET_VALID first. It is safe to manipulate the idxset between - the calls. It is not guaranteed that all entries have already been - returned before the an entry is returned the second time.*/ -void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx); - -/* Return the oldest entry in the idxset. Fill in its index in *idx. */ -void* pa_idxset_first(pa_idxset *s, uint32_t *idx); - -/* Return the entry following the entry indexed by *idx. After the - * call *index contains the index of the returned - * object. pa_idxset_first() and pa_idxset_next() may be used to - * iterate through the set.*/ -void *pa_idxset_next(pa_idxset *s, uint32_t *idx); - -/* Call a function for every item in the set. If the callback function - returns -1, the loop is terminated. If *del is set to non-zero that - specific item is removed. It is not safe to call any other - functions on the idxset while pa_idxset_foreach is executed. */ -int pa_idxset_foreach(pa_idxset*s, int (*func)(void *p, uint32_t idx, int *del, void*userdata), void *userdata); - -unsigned pa_idxset_size(pa_idxset*s); - -int pa_idxset_isempty(pa_idxset *s); - -#endif diff --git a/src/polypcore/inet_ntop.c b/src/polypcore/inet_ntop.c deleted file mode 100644 index a25c3c95..00000000 --- a/src/polypcore/inet_ntop.c +++ /dev/null @@ -1,80 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#ifndef HAVE_INET_NTOP - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#include "winsock.h" - -#include "inet_ntop.h" - -const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) { - struct in_addr *in = (struct in_addr*)src; - struct in6_addr *in6 = (struct in6_addr*)src; - - assert(src && dst); - - switch (af) { - case AF_INET: - snprintf(dst, cnt, "%d.%d.%d.%d", -#ifdef WORDS_BIGENDIAN - (int)(in->s_addr >> 24) & 0xff, - (int)(in->s_addr >> 16) & 0xff, - (int)(in->s_addr >> 8) & 0xff, - (int)(in->s_addr >> 0) & 0xff); -#else - (int)(in->s_addr >> 0) & 0xff, - (int)(in->s_addr >> 8) & 0xff, - (int)(in->s_addr >> 16) & 0xff, - (int)(in->s_addr >> 24) & 0xff); -#endif - break; - case AF_INET6: - snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x", - in6->s6_addr[ 0] << 8 | in6->s6_addr[ 1], - in6->s6_addr[ 2] << 8 | in6->s6_addr[ 3], - in6->s6_addr[ 4] << 8 | in6->s6_addr[ 5], - in6->s6_addr[ 6] << 8 | in6->s6_addr[ 7], - in6->s6_addr[ 8] << 8 | in6->s6_addr[ 9], - in6->s6_addr[10] << 8 | in6->s6_addr[11], - in6->s6_addr[12] << 8 | in6->s6_addr[13], - in6->s6_addr[14] << 8 | in6->s6_addr[15]); - break; - default: - errno = EAFNOSUPPORT; - return NULL; - } - - return dst; -} - -#endif /* INET_NTOP */ diff --git a/src/polypcore/inet_ntop.h b/src/polypcore/inet_ntop.h deleted file mode 100644 index 7fb67b44..00000000 --- a/src/polypcore/inet_ntop.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef fooinet_ntophfoo -#define fooinet_ntophfoo - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#include "winsock.h" - -const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt); - -#endif diff --git a/src/polypcore/inet_pton.c b/src/polypcore/inet_pton.c deleted file mode 100644 index 17860f6d..00000000 --- a/src/polypcore/inet_pton.c +++ /dev/null @@ -1,62 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#ifndef HAVE_INET_PTON - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#include "winsock.h" - -#include "inet_pton.h" - -int inet_pton(int af, const char *src, void *dst) { - struct in_addr *in = (struct in_addr*)dst; - struct in6_addr *in6 = (struct in6_addr*)dst; - - assert(src && dst); - - switch (af) { - case AF_INET: - in->s_addr = inet_addr(src); - if (in->s_addr == INADDR_NONE) - return 0; - break; - case AF_INET6: - /* FIXME */ - default: - errno = EAFNOSUPPORT; - return -1; - } - - return 1; -} - -#endif /* INET_PTON */ diff --git a/src/polypcore/inet_pton.h b/src/polypcore/inet_pton.h deleted file mode 100644 index 111b4a07..00000000 --- a/src/polypcore/inet_pton.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef fooinet_ptonhfoo -#define fooinet_ptonhfoo - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#include "winsock.h" - -int inet_pton(int af, const char *src, void *dst); - -#endif diff --git a/src/polypcore/iochannel.c b/src/polypcore/iochannel.c deleted file mode 100644 index 106c413e..00000000 --- a/src/polypcore/iochannel.c +++ /dev/null @@ -1,417 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_SYS_UN_H -#include -#endif - -#include "winsock.h" - -#include - -#include -#include -#include -#include - -#include "iochannel.h" - -struct pa_iochannel { - int ifd, ofd; - pa_mainloop_api* mainloop; - - pa_iochannel_cb_t callback; - void*userdata; - - int readable; - int writable; - int hungup; - - int no_close; - - pa_io_event* input_event, *output_event; -}; - -static void enable_mainloop_sources(pa_iochannel *io) { - assert(io); - - if (io->input_event == io->output_event && io->input_event) { - pa_io_event_flags_t f = PA_IO_EVENT_NULL; - assert(io->input_event); - - if (!io->readable) - f |= PA_IO_EVENT_INPUT; - if (!io->writable) - f |= PA_IO_EVENT_OUTPUT; - - io->mainloop->io_enable(io->input_event, f); - } else { - if (io->input_event) - io->mainloop->io_enable(io->input_event, io->readable ? PA_IO_EVENT_NULL : PA_IO_EVENT_INPUT); - if (io->output_event) - io->mainloop->io_enable(io->output_event, io->writable ? PA_IO_EVENT_NULL : PA_IO_EVENT_OUTPUT); - } -} - -static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { - pa_iochannel *io = userdata; - int changed = 0; - - assert(m); - assert(e); - assert(fd >= 0); - assert(userdata); - - if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) { - io->hungup = 1; - changed = 1; - } - - if ((f & PA_IO_EVENT_INPUT) && !io->readable) { - io->readable = 1; - changed = 1; - assert(e == io->input_event); - } - - if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) { - io->writable = 1; - changed = 1; - assert(e == io->output_event); - } - - if (changed) { - enable_mainloop_sources(io); - - if (io->callback) - io->callback(io, io->userdata); - } -} - -pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) { - pa_iochannel *io; - - assert(m); - assert(ifd >= 0 || ofd >= 0); - - io = pa_xnew(pa_iochannel, 1); - io->ifd = ifd; - io->ofd = ofd; - io->mainloop = m; - - io->userdata = NULL; - io->callback = NULL; - io->readable = 0; - io->writable = 0; - io->hungup = 0; - io->no_close = 0; - - io->input_event = io->output_event = NULL; - - if (ifd == ofd) { - assert(ifd >= 0); - pa_make_nonblock_fd(io->ifd); - io->input_event = io->output_event = m->io_new(m, ifd, PA_IO_EVENT_INPUT|PA_IO_EVENT_OUTPUT, callback, io); - } else { - - if (ifd >= 0) { - pa_make_nonblock_fd(io->ifd); - io->input_event = m->io_new(m, ifd, PA_IO_EVENT_INPUT, callback, io); - } - - if (ofd >= 0) { - pa_make_nonblock_fd(io->ofd); - io->output_event = m->io_new(m, ofd, PA_IO_EVENT_OUTPUT, callback, io); - } - } - - return io; -} - -void pa_iochannel_free(pa_iochannel*io) { - assert(io); - - if (io->input_event) - io->mainloop->io_free(io->input_event); - - if (io->output_event && (io->output_event != io->input_event)) - io->mainloop->io_free(io->output_event); - - if (!io->no_close) { - if (io->ifd >= 0) - - close(io->ifd); - if (io->ofd >= 0 && io->ofd != io->ifd) - close(io->ofd); - } - - pa_xfree(io); -} - -int pa_iochannel_is_readable(pa_iochannel*io) { - assert(io); - - return io->readable || io->hungup; -} - -int pa_iochannel_is_writable(pa_iochannel*io) { - assert(io); - - return io->writable && !io->hungup; -} - -int pa_iochannel_is_hungup(pa_iochannel*io) { - assert(io); - - return io->hungup; -} - -ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) { - ssize_t r; - - assert(io); - assert(data); - assert(l); - assert(io->ofd >= 0); - - r = pa_write(io->ofd, data, l); - if (r >= 0) { - io->writable = 0; - enable_mainloop_sources(io); - } - - return r; -} - -ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) { - ssize_t r; - - assert(io); - assert(data); - assert(io->ifd >= 0); - - r = pa_read(io->ifd, data, l); - if (r >= 0) { - io->readable = 0; - enable_mainloop_sources(io); - } - - return r; -} - -#ifdef SCM_CREDENTIALS - -int pa_iochannel_creds_supported(pa_iochannel *io) { - struct sockaddr_un sa; - socklen_t l; - - assert(io); - assert(io->ifd >= 0); - assert(io->ofd == io->ifd); - - l = sizeof(sa); - - if (getsockname(io->ifd, (struct sockaddr*) &sa, &l) < 0) - return 0; - - return sa.sun_family == AF_UNIX; -} - -int pa_iochannel_creds_enable(pa_iochannel *io) { - int t = 1; - - assert(io); - assert(io->ifd >= 0); - - if (setsockopt(io->ifd, SOL_SOCKET, SO_PASSCRED, &t, sizeof(t)) < 0) { - pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno)); - return -1; - } - - return 0; -} - -ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l) { - ssize_t r; - struct msghdr mh; - struct iovec iov; - uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))]; - struct ucred *ucred; - struct cmsghdr *cmsg; - - assert(io); - assert(data); - assert(l); - assert(io->ofd >= 0); - - memset(&iov, 0, sizeof(iov)); - iov.iov_base = (void*) data; - iov.iov_len = l; - - memset(cmsg_data, 0, sizeof(cmsg_data)); - cmsg = (struct cmsghdr*) cmsg_data; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_CREDENTIALS; - - ucred = (struct ucred*) CMSG_DATA(cmsg); - ucred->pid = getpid(); - ucred->uid = getuid(); - ucred->gid = getgid(); - - memset(&mh, 0, sizeof(mh)); - mh.msg_name = NULL; - mh.msg_namelen = 0; - mh.msg_iov = &iov; - mh.msg_iovlen = 1; - mh.msg_control = cmsg_data; - mh.msg_controllen = sizeof(cmsg_data); - mh.msg_flags = 0; - - if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) { - io->writable = 0; - enable_mainloop_sources(io); - } - - return r; -} - -ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struct ucred *ucred, int *creds_valid) { - ssize_t r; - struct msghdr mh; - struct iovec iov; - uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))]; - - assert(io); - assert(data); - assert(l); - assert(io->ifd >= 0); - assert(ucred); - assert(creds_valid); - - memset(&iov, 0, sizeof(iov)); - iov.iov_base = data; - iov.iov_len = l; - - memset(cmsg_data, 0, sizeof(cmsg_data)); - - memset(&mh, 0, sizeof(mh)); - mh.msg_name = NULL; - mh.msg_namelen = 0; - mh.msg_iov = &iov; - mh.msg_iovlen = 1; - mh.msg_control = cmsg_data; - mh.msg_controllen = sizeof(cmsg_data); - mh.msg_flags = 0; - - if ((r = recvmsg(io->ifd, &mh, MSG_NOSIGNAL)) >= 0) { - struct cmsghdr *cmsg; - - *creds_valid = 0; - - for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { - - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) { - assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))); - memcpy(ucred, CMSG_DATA(cmsg), sizeof(struct ucred)); - *creds_valid = 1; - break; - } - } - - io->readable = 0; - enable_mainloop_sources(io); - } - - return r; -} -#else /* SCM_CREDENTIALS */ - -int pa_iochannel_creds_supported(pa_iochannel *io) { - return 0; -} - -int pa_iochannel_creds_enable(pa_iochannel *io) { - return -1; -} - -ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l) { - pa_log_error("pa_iochannel_write_with_creds() not supported."); - return -1; -} - -ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struct ucred *ucred, int *creds_valid) { - pa_log_error("pa_iochannel_read_with_creds() not supported."); - return -1; -} - -#endif /* SCM_CREDENTIALS */ - -void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) { - assert(io); - - io->callback = _callback; - io->userdata = userdata; -} - -void pa_iochannel_set_noclose(pa_iochannel*io, int b) { - assert(io); - - io->no_close = b; -} - -void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) { - assert(io); - assert(s); - assert(l); - - pa_socket_peer_to_string(io->ifd, s, l); -} - -int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) { - assert(io); - - return pa_socket_set_rcvbuf(io->ifd, l); -} - -int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) { - assert(io); - - return pa_socket_set_sndbuf(io->ofd, l); -} - -pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) { - assert(io); - - return io->mainloop; -} diff --git a/src/polypcore/iochannel.h b/src/polypcore/iochannel.h deleted file mode 100644 index fe7cc0ce..00000000 --- a/src/polypcore/iochannel.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef fooiochannelhfoo -#define fooiochannelhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include - -/* A wrapper around UNIX file descriptors for attaching them to the a - main event loop. Everytime new data may be read or be written to - the channel a callback function is called. It is safe to destroy - the calling iochannel object from the callback */ - -/* When pa_iochannel_is_readable() returns non-zero, the user has to - * call this function in a loop until it is no longer set or EOF - * reached. Otherwise strange things may happen when an EOF is - * reached. */ - -typedef struct pa_iochannel pa_iochannel; - -/* Create a new IO channel for the specified file descriptors for -input resp. output. It is safe to pass the same file descriptor for -both parameters (in case of full-duplex channels). For a simplex -channel specify -1 for the other direction. */ - -pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd); -void pa_iochannel_free(pa_iochannel*io); - -ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l); -ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l); - -int pa_iochannel_creds_supported(pa_iochannel *io); -int pa_iochannel_creds_enable(pa_iochannel *io); - -struct ucred; - -ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l); -ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struct ucred *ucred, int *creds_valid); - -int pa_iochannel_is_readable(pa_iochannel*io); -int pa_iochannel_is_writable(pa_iochannel*io); -int pa_iochannel_is_hungup(pa_iochannel*io); - -/* Don't close the file descirptors when the io channel is freed. By - * default the file descriptors are closed. */ -void pa_iochannel_set_noclose(pa_iochannel*io, int b); - -/* Set the callback function that is called whenever data becomes available for read or write */ -typedef void (*pa_iochannel_cb_t)(pa_iochannel*io, void *userdata); -void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t callback, void *userdata); - -/* In case the file descriptor is a socket, return a pretty-printed string in *s which describes the peer connected */ -void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l); - -/* Use setsockopt() to tune the recieve and send buffers of TCP sockets */ -int pa_iochannel_socket_set_rcvbuf(pa_iochannel*io, size_t l); -int pa_iochannel_socket_set_sndbuf(pa_iochannel*io, size_t l); - -pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io); - -#endif diff --git a/src/polypcore/ioline.c b/src/polypcore/ioline.c deleted file mode 100644 index b908f967..00000000 --- a/src/polypcore/ioline.c +++ /dev/null @@ -1,394 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "ioline.h" - -#define BUFFER_LIMIT (64*1024) -#define READ_SIZE (1024) - -struct pa_ioline { - pa_iochannel *io; - pa_defer_event *defer_event; - pa_mainloop_api *mainloop; - int ref; - 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)(pa_ioline*io, const char *s, void *userdata); - void *userdata; - - int defer_close; -}; - -static void io_callback(pa_iochannel*io, void *userdata); -static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata); - -pa_ioline* pa_ioline_new(pa_iochannel *io) { - pa_ioline *l; - assert(io); - - l = pa_xnew(pa_ioline, 1); - 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; - l->ref = 1; - - l->mainloop = pa_iochannel_get_mainloop_api(io); - - l->defer_event = l->mainloop->defer_new(l->mainloop, defer_callback, l); - l->mainloop->defer_enable(l->defer_event, 0); - - l->defer_close = 0; - - pa_iochannel_set_callback(io, io_callback, l); - - return l; -} - -static void ioline_free(pa_ioline *l) { - assert(l); - - if (l->io) - pa_iochannel_free(l->io); - - if (l->defer_event) - l->mainloop->defer_free(l->defer_event); - - pa_xfree(l->wbuf); - pa_xfree(l->rbuf); - pa_xfree(l); -} - -void pa_ioline_unref(pa_ioline *l) { - assert(l); - assert(l->ref >= 1); - - if ((--l->ref) <= 0) - ioline_free(l); -} - -pa_ioline* pa_ioline_ref(pa_ioline *l) { - assert(l); - assert(l->ref >= 1); - - l->ref++; - return l; -} - -void pa_ioline_close(pa_ioline *l) { - assert(l); - assert(l->ref >= 1); - - l->dead = 1; - - if (l->io) { - pa_iochannel_free(l->io); - l->io = NULL; - } - - if (l->defer_event) { - l->mainloop->defer_free(l->defer_event); - l->defer_event = NULL; - } - - if (l->callback) - l->callback = NULL; -} - -void pa_ioline_puts(pa_ioline *l, const char *c) { - size_t len; - - assert(l); - assert(l->ref >= 1); - assert(c); - - if (l->dead) - return; - - len = strlen(c); - if (len > BUFFER_LIMIT - l->wbuf_valid_length) - len = BUFFER_LIMIT - l->wbuf_valid_length; - - if (len) { - assert(l->wbuf_length >= l->wbuf_valid_length); - - /* In case the allocated buffer is too small, enlarge it. */ - if (l->wbuf_valid_length + len > l->wbuf_length) { - size_t n = l->wbuf_valid_length+len; - char *new = pa_xmalloc(n); - if (l->wbuf) { - memcpy(new, l->wbuf+l->wbuf_index, l->wbuf_valid_length); - pa_xfree(l->wbuf); - } - l->wbuf = new; - l->wbuf_length = n; - l->wbuf_index = 0; - } else if (l->wbuf_index + l->wbuf_valid_length + len > l->wbuf_length) { - - /* In case the allocated buffer fits, but the current index is too far from the start, move it to the front. */ - memmove(l->wbuf, l->wbuf+l->wbuf_index, l->wbuf_valid_length); - l->wbuf_index = 0; - } - - assert(l->wbuf_index + l->wbuf_valid_length + len <= l->wbuf_length); - - /* Append the new string */ - memcpy(l->wbuf + l->wbuf_index + l->wbuf_valid_length, c, len); - l->wbuf_valid_length += len; - - l->mainloop->defer_enable(l->defer_event, 1); - } -} - -void pa_ioline_set_callback(pa_ioline*l, void (*callback)(pa_ioline*io, const char *s, void *userdata), void *userdata) { - assert(l); - assert(l->ref >= 1); - - l->callback = callback; - l->userdata = userdata; -} - -static void failure(pa_ioline *l, int process_leftover) { - assert(l); - assert(l->ref >= 1); - assert(!l->dead); - - if (process_leftover && l->rbuf_valid_length > 0) { - /* Pass the last missing bit to the client */ - - if (l->callback) { - char *p = pa_xstrndup(l->rbuf+l->rbuf_index, l->rbuf_valid_length); - l->callback(l, p, l->userdata); - pa_xfree(p); - } - } - - if (l->callback) { - l->callback(l, NULL, l->userdata); - l->callback = NULL; - } - - pa_ioline_close(l); -} - -static void scan_for_lines(pa_ioline *l, size_t skip) { - assert(l && l->ref >= 1 && skip < l->rbuf_valid_length); - - while (!l->dead && l->rbuf_valid_length > skip) { - char *e, *p; - size_t m; - - if (!(e = memchr(l->rbuf + l->rbuf_index + skip, '\n', l->rbuf_valid_length - skip))) - break; - - *e = 0; - - p = l->rbuf + l->rbuf_index; - m = strlen(p); - - l->rbuf_index += m+1; - l->rbuf_valid_length -= m+1; - - /* A shortcut for the next time */ - if (l->rbuf_valid_length == 0) - l->rbuf_index = 0; - - if (l->callback) - l->callback(l, p, l->userdata); - - skip = 0; - } - - /* If the buffer became too large and still no newline was found, drop it. */ - if (l->rbuf_valid_length >= BUFFER_LIMIT) - l->rbuf_index = l->rbuf_valid_length = 0; -} - -static int do_write(pa_ioline *l); - -static int do_read(pa_ioline *l) { - assert(l && l->ref >= 1); - - while (!l->dead && pa_iochannel_is_readable(l->io)) { - ssize_t r; - size_t len; - - len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length; - - /* Check if we have to enlarge the read buffer */ - 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) { - /* The current buffer is large enough, let's just move the data to the front */ - if (l->rbuf_valid_length) - memmove(l->rbuf, l->rbuf+l->rbuf_index, l->rbuf_valid_length); - } else { - /* Enlarge the buffer */ - char *new = pa_xmalloc(n); - if (l->rbuf_valid_length) - memcpy(new, l->rbuf+l->rbuf_index, l->rbuf_valid_length); - pa_xfree(l->rbuf); - l->rbuf = new; - l->rbuf_length = n; - } - - l->rbuf_index = 0; - } - - len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length; - - assert(len >= READ_SIZE); - - /* Read some data */ - if ((r = pa_iochannel_read(l->io, l->rbuf+l->rbuf_index+l->rbuf_valid_length, len)) <= 0) { - if (r < 0) { - pa_log(__FILE__": read(): %s", pa_cstrerror(errno)); - failure(l, 0); - } else - failure(l, 1); - - return -1; - } - - l->rbuf_valid_length += r; - - /* Look if a line has been terminated in the newly read data */ - scan_for_lines(l, l->rbuf_valid_length - r); - } - - return 0; -} - -/* Try to flush the buffer */ -static int do_write(pa_ioline *l) { - ssize_t r; - assert(l && l->ref >= 1); - - while (!l->dead && pa_iochannel_is_writable(l->io) && l->wbuf_valid_length) { - - if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0) { - pa_log(__FILE__": write(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); - failure(l, 0); - return -1; - } - - l->wbuf_index += r; - l->wbuf_valid_length -= r; - - /* A shortcut for the next time */ - if (l->wbuf_valid_length == 0) - l->wbuf_index = 0; - } - - return 0; -} - -/* Try to flush read/write data */ -static void do_work(pa_ioline *l) { - assert(l); - assert(l->ref >= 1); - - pa_ioline_ref(l); - - l->mainloop->defer_enable(l->defer_event, 0); - - if (!l->dead) - do_read(l); - - if (!l->dead) - do_write(l); - - if (l->defer_close && !l->wbuf_valid_length) - failure(l, 1); - - pa_ioline_unref(l); -} - -static void io_callback(pa_iochannel*io, void *userdata) { - pa_ioline *l = userdata; - assert(io && l && l->ref >= 1); - - do_work(l); -} - -static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata) { - pa_ioline *l = userdata; - assert(l && l->ref >= 1 && l->mainloop == m && l->defer_event == e); - - do_work(l); -} - -void pa_ioline_defer_close(pa_ioline *l) { - assert(l); - assert(l->ref >= 1); - - l->defer_close = 1; - - if (!l->wbuf_valid_length) - l->mainloop->defer_enable(l->defer_event, 1); -} - -void pa_ioline_printf(pa_ioline *l, const char *format, ...) { - char *t; - va_list ap; - - assert(l); - assert(l->ref >= 1); - - va_start(ap, format); - t = pa_vsprintf_malloc(format, ap); - va_end(ap); - - pa_ioline_puts(l, t); - pa_xfree(t); -} diff --git a/src/polypcore/ioline.h b/src/polypcore/ioline.h deleted file mode 100644 index 77bf8761..00000000 --- a/src/polypcore/ioline.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef fooiolinehfoo -#define fooiolinehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -/* An ioline wraps an iochannel for line based communication. A - * callback function is called whenever a new line has been recieved - * from the client */ - -typedef struct pa_ioline pa_ioline; - -pa_ioline* pa_ioline_new(pa_iochannel *io); -void pa_ioline_unref(pa_ioline *l); -pa_ioline* pa_ioline_ref(pa_ioline *l); -void pa_ioline_close(pa_ioline *l); - -/* Write a string to the channel */ -void pa_ioline_puts(pa_ioline *s, const char *c); - -/* Write a string to the channel */ -void pa_ioline_printf(pa_ioline *s, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); - -/* Set the callback function that is called for every recieved line */ -void pa_ioline_set_callback(pa_ioline*io, void (*callback)(pa_ioline*io, const char *s, void *userdata), void *userdata); - -/* Make sure to close the ioline object as soon as the send buffer is emptied */ -void pa_ioline_defer_close(pa_ioline *io); - -#endif diff --git a/src/polypcore/llist.h b/src/polypcore/llist.h deleted file mode 100644 index c54742d3..00000000 --- a/src/polypcore/llist.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef foollistfoo -#define foollistfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -/* Some macros for maintaining doubly linked lists */ - -/* The head of the linked list. Use this in the structure that shall - * contain the head of the linked list */ -#define PA_LLIST_HEAD(t,name) t *name - -/* The pointers in the linked list's items. Use this in the item structure */ -#define PA_LLIST_FIELDS(t) t *next, *prev - -/* Initialize the list's head */ -#define PA_LLIST_HEAD_INIT(t,item) do { (item) = NULL; } while(0) - -/* Initialize a list item */ -#define PA_LLIST_INIT(t,item) do { \ - t *_item = (item); \ - assert(_item); \ - _item->prev = _item->next = NULL; \ - } while(0) - -/* Prepend an item to the list */ -#define PA_LLIST_PREPEND(t,head,item) do { \ - t **_head = &(head), *_item = (item); \ - assert(_item); \ - if ((_item->next = *_head)) \ - _item->next->prev = _item; \ - _item->prev = NULL; \ - *_head = _item; \ - } while (0) - -/* Remove an item from the list */ -#define PA_LLIST_REMOVE(t,head,item) do { \ - t **_head = &(head), *_item = (item); \ - assert(_item); \ - if (_item->next) \ - _item->next->prev = _item->prev; \ - if (_item->prev) \ - _item->prev->next = _item->next; \ - else {\ - assert(*_head == _item); \ - *_head = _item->next; \ - } \ - _item->next = _item->prev = NULL; \ - } while(0) - -#define PA_LLIST_FIND_HEAD(t,item,head) \ -do { \ - t **_head = (head), *_item = (item); \ - *_head = _item; \ - assert(_head); \ - while ((*_head)->prev) \ - *_head = (*_head)->prev; \ -} while (0) \ - - -#endif diff --git a/src/polypcore/log.c b/src/polypcore/log.c deleted file mode 100644 index 6cdffa51..00000000 --- a/src/polypcore/log.c +++ /dev/null @@ -1,211 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#ifdef HAVE_SYSLOG_H -#include -#endif - -#include -#include - -#include - -#include "log.h" - -#define ENV_LOGLEVEL "POLYP_LOG" - -static char *log_ident = NULL, *log_ident_local = NULL; -static pa_log_target_t log_target = PA_LOG_STDERR; -static void (*user_log_func)(pa_log_level_t l, const char *s) = NULL; -static pa_log_level_t maximal_level = PA_LOG_NOTICE; - -#ifdef HAVE_SYSLOG_H -static const int level_to_syslog[] = { - [PA_LOG_ERROR] = LOG_ERR, - [PA_LOG_WARN] = LOG_WARNING, - [PA_LOG_NOTICE] = LOG_NOTICE, - [PA_LOG_INFO] = LOG_INFO, - [PA_LOG_DEBUG] = LOG_DEBUG -}; -#endif - -void pa_log_set_ident(const char *p) { - if (log_ident) - pa_xfree(log_ident); - if (log_ident_local) - pa_xfree(log_ident_local); - - log_ident = pa_xstrdup(p); - log_ident_local = pa_utf8_to_locale(log_ident); - if (!log_ident_local) - log_ident_local = pa_xstrdup(log_ident); -} - -void pa_log_set_maximal_level(pa_log_level_t l) { - assert(l < PA_LOG_LEVEL_MAX); - maximal_level = l; -} - -void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t l, const char*s)) { - assert(t == PA_LOG_USER || !func); - log_target = t; - user_log_func = func; -} - -void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { - const char *e; - char *text, *t, *n; - - assert(level < PA_LOG_LEVEL_MAX); - - if ((e = getenv(ENV_LOGLEVEL))) - maximal_level = atoi(e); - - if (level > maximal_level) - return; - - text = pa_vsprintf_malloc(format, ap); - - if (!pa_utf8_valid(text)) - pa_log_level(level, __FILE__": invalid UTF-8 string following below:"); - - for (t = text; t; t = n) { - if ((n = strchr(t, '\n'))) { - *n = 0; - n++; - } - - if (!*t) - continue; - - switch (log_target) { - case PA_LOG_STDERR: { - const char *prefix = "", *suffix = ""; - char *local_t; - -#ifndef OS_IS_WIN32 - /* Yes indeed. Useless, but fun! */ - if (isatty(STDERR_FILENO)) { - if (level <= PA_LOG_ERROR) { - prefix = "\x1B[1;31m"; - suffix = "\x1B[0m"; - } else if (level <= PA_LOG_WARN) { - prefix = "\x1B[1m"; - suffix = "\x1B[0m"; - } - } -#endif - - local_t = pa_utf8_to_locale(t); - if (!local_t) - fprintf(stderr, "%s%s%s\n", prefix, t, suffix); - else { - fprintf(stderr, "%s%s%s\n", prefix, local_t, suffix); - pa_xfree(local_t); - } - - break; - } - -#ifdef HAVE_SYSLOG_H - case PA_LOG_SYSLOG: { - char *local_t; - - openlog(log_ident_local ? log_ident_local : "???", LOG_PID, LOG_USER); - - local_t = pa_utf8_to_locale(t); - if (!local_t) - syslog(level_to_syslog[level], "%s", t); - else { - syslog(level_to_syslog[level], "%s", local_t); - pa_xfree(local_t); - } - - closelog(); - break; - } -#endif - - case PA_LOG_USER: - user_log_func(level, t); - break; - - case PA_LOG_NULL: - default: - break; - } - } - - pa_xfree(text); - -} - -void pa_log_level(pa_log_level_t level, const char *format, ...) { - va_list ap; - va_start(ap, format); - pa_log_levelv(level, format, ap); - va_end(ap); -} - -void pa_log_debug(const char *format, ...) { - va_list ap; - va_start(ap, format); - pa_log_levelv(PA_LOG_DEBUG, format, ap); - va_end(ap); -} - -void pa_log_info(const char *format, ...) { - va_list ap; - va_start(ap, format); - pa_log_levelv(PA_LOG_INFO, format, ap); - va_end(ap); -} - -void pa_log_notice(const char *format, ...) { - va_list ap; - va_start(ap, format); - pa_log_levelv(PA_LOG_INFO, format, ap); - va_end(ap); -} - -void pa_log_warn(const char *format, ...) { - va_list ap; - va_start(ap, format); - pa_log_levelv(PA_LOG_WARN, format, ap); - va_end(ap); -} - -void pa_log_error(const char *format, ...) { - va_list ap; - va_start(ap, format); - pa_log_levelv(PA_LOG_ERROR, format, ap); - va_end(ap); -} diff --git a/src/polypcore/log.h b/src/polypcore/log.h deleted file mode 100644 index c306acaf..00000000 --- a/src/polypcore/log.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef foologhfoo -#define foologhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -/* A simple logging subsystem */ - -/* Where to log to */ -typedef enum pa_log_target { - PA_LOG_STDERR, /* default */ - PA_LOG_SYSLOG, - PA_LOG_USER, /* to user specified function */ - PA_LOG_NULL /* to /dev/null */ -} pa_log_target_t; - -typedef enum pa_log_level { - PA_LOG_ERROR = 0, /* Error messages */ - PA_LOG_WARN = 1, /* Warning messages */ - PA_LOG_NOTICE = 2, /* Notice messages */ - PA_LOG_INFO = 3, /* Info messages */ - PA_LOG_DEBUG = 4, /* debug message */ - PA_LOG_LEVEL_MAX -} pa_log_level_t; - -/* Set an identification for the current daemon. Used when logging to syslog. */ -void pa_log_set_ident(const char *p); - -/* Set another log target. If t is PA_LOG_USER you may specify a function that is called every log string */ -void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t t, const char*s)); - -/* Minimal log level */ -void pa_log_set_maximal_level(pa_log_level_t l); - -/* Do a log line */ -void pa_log_debug(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); -void pa_log_info(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); -void pa_log_notice(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); -void pa_log_warn(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); -void pa_log_error(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); - -void pa_log_level(pa_log_level_t level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); - -void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap); - -#define pa_log pa_log_error - -#endif diff --git a/src/polypcore/mcalign.c b/src/polypcore/mcalign.c deleted file mode 100644 index d9267f99..00000000 --- a/src/polypcore/mcalign.c +++ /dev/null @@ -1,206 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -#include "mcalign.h" - -struct pa_mcalign { - size_t base; - pa_memchunk leftover, current; - pa_memblock_stat *memblock_stat; -}; - -pa_mcalign *pa_mcalign_new(size_t base, pa_memblock_stat *s) { - pa_mcalign *m; - assert(base); - - m = pa_xnew(pa_mcalign, 1); - - m->base = base; - pa_memchunk_reset(&m->leftover); - pa_memchunk_reset(&m->current); - m->memblock_stat = s; - - return m; -} - -void pa_mcalign_free(pa_mcalign *m) { - assert(m); - - if (m->leftover.memblock) - pa_memblock_unref(m->leftover.memblock); - - if (m->current.memblock) - pa_memblock_unref(m->current.memblock); - - pa_xfree(m); -} - -void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { - assert(m); - assert(c); - - assert(c->memblock); - assert(c->length > 0); - - assert(!m->current.memblock); - - /* Append to the leftover memory block */ - if (m->leftover.memblock) { - - /* Try to merge */ - if (m->leftover.memblock == c->memblock && - m->leftover.index + m->leftover.length == c->index) { - - /* Merge */ - m->leftover.length += c->length; - - /* If the new chunk is larger than m->base, move it to current */ - if (m->leftover.length >= m->base) { - m->current = m->leftover; - pa_memchunk_reset(&m->leftover); - } - - } else { - size_t l; - - /* We have to copy */ - assert(m->leftover.length < m->base); - l = m->base - m->leftover.length; - - if (l > c->length) - l = c->length; - - /* Can we use the current block? */ - pa_memchunk_make_writable(&m->leftover, m->memblock_stat, m->base); - - memcpy((uint8_t*) m->leftover.memblock->data + m->leftover.index + m->leftover.length, (uint8_t*) c->memblock->data + c->index, l); - m->leftover.length += l; - - assert(m->leftover.length <= m->base && m->leftover.length <= m->leftover.memblock->length); - - if (c->length > l) { - /* Save the remainder of the memory block */ - m->current = *c; - m->current.index += l; - m->current.length -= l; - pa_memblock_ref(m->current.memblock); - } - } - } else { - /* Nothing to merge or copy, just store it */ - - if (c->length >= m->base) - m->current = *c; - else - m->leftover = *c; - - pa_memblock_ref(c->memblock); - } -} - -int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) { - assert(m); - assert(c); - - /* First test if there's a leftover memory block available */ - if (m->leftover.memblock) { - assert(m->leftover.length > 0 && m->leftover.length <= m->base); - - /* The leftover memory block is not yet complete */ - if (m->leftover.length < m->base) - return -1; - - /* Return the leftover memory block */ - *c = m->leftover; - pa_memchunk_reset(&m->leftover); - - /* If the current memblock is too small move it the leftover */ - if (m->current.memblock && m->current.length < m->base) { - m->leftover = m->current; - pa_memchunk_reset(&m->current); - } - - return 0; - } - - /* Now let's see if there is other data available */ - if (m->current.memblock) { - size_t l; - assert(m->current.length >= m->base); - - /* The length of the returned memory block */ - l = m->current.length; - l /= m->base; - l *= m->base; - assert(l > 0); - - /* Prepare the returned block */ - *c = m->current; - pa_memblock_ref(c->memblock); - c->length = l; - - /* Drop that from the current memory block */ - assert(l <= m->current.length); - m->current.index += l; - m->current.length -= l; - - /* In case the whole block was dropped ... */ - if (m->current.length == 0) - pa_memblock_unref(m->current.memblock); - else { - /* Move the raimainder to leftover */ - assert(m->current.length < m->base && !m->leftover.memblock); - - m->leftover = m->current; - } - - pa_memchunk_reset(&m->current); - - return 0; - } - - /* There's simply nothing */ - return -1; - -} - -size_t pa_mcalign_csize(pa_mcalign *m, size_t l) { - assert(m); - assert(l > 0); - - assert(!m->current.memblock); - - if (m->leftover.memblock) - l += m->leftover.length; - - return (l/m->base)*m->base; -} diff --git a/src/polypcore/mcalign.h b/src/polypcore/mcalign.h deleted file mode 100644 index 58019462..00000000 --- a/src/polypcore/mcalign.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef foomcalignhfoo -#define foomcalignhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -/* An alignment object, used for aligning memchunks to multiples of - * the frame size. */ - -/* Method of operation: the user creates a new mcalign object by - * calling pa_mcalign_new() with the appropriate aligning - * granularity. After that he may call pa_mcalign_push() for an input - * memchunk. After exactly one memchunk the user has to call - * pa_mcalign_pop() until it returns -1. If pa_mcalign_pop() returns - * 0, the memchunk *c is valid and aligned to the granularity. Some - * pseudocode illustrating this: - * - * pa_mcalign *a = pa_mcalign_new(4, NULL); - * - * for (;;) { - * pa_memchunk input; - * - * ... fill input ... - * - * pa_mcalign_push(m, &input); - * pa_memblock_unref(input.memblock); - * - * for (;;) { - * pa_memchunk output; - * - * if (pa_mcalign_pop(m, &output) < 0) - * break; - * - * ... consume output ... - * - * pa_memblock_unref(output.memblock); - * } - * } - * - * pa_memchunk_free(a); - * */ - -typedef struct pa_mcalign pa_mcalign; - -pa_mcalign *pa_mcalign_new(size_t base, pa_memblock_stat *s); -void pa_mcalign_free(pa_mcalign *m); - -/* Push a new memchunk into the aligner. The caller of this routine - * has to free the memchunk by himself. */ -void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c); - -/* Pop a new memchunk from the aligner. Returns 0 when sucessful, - * nonzero otherwise. */ -int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c); - -/* If we pass l bytes in now, how many bytes would we get out? */ -size_t pa_mcalign_csize(pa_mcalign *m, size_t l); - -#endif diff --git a/src/polypcore/memblock.c b/src/polypcore/memblock.c deleted file mode 100644 index a0e5135b..00000000 --- a/src/polypcore/memblock.c +++ /dev/null @@ -1,173 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -#include "memblock.h" - -static void stat_add(pa_memblock*m, pa_memblock_stat *s) { - assert(m); - - if (!s) { - m->stat = NULL; - return; - } - - m->stat = pa_memblock_stat_ref(s); - s->total++; - s->allocated++; - s->total_size += m->length; - s->allocated_size += m->length; -} - -static void stat_remove(pa_memblock *m) { - assert(m); - - if (!m->stat) - return; - - m->stat->total--; - m->stat->total_size -= m->length; - - pa_memblock_stat_unref(m->stat); - m->stat = NULL; -} - -pa_memblock *pa_memblock_new(size_t length, pa_memblock_stat*s) { - pa_memblock *b = pa_xmalloc(sizeof(pa_memblock)+length); - b->type = PA_MEMBLOCK_APPENDED; - b->ref = 1; - b->length = length; - b->data = b+1; - b->free_cb = NULL; - b->read_only = 0; - stat_add(b, s); - return b; -} - -pa_memblock *pa_memblock_new_dynamic(void *d, size_t length, pa_memblock_stat*s) { - pa_memblock *b = pa_xmalloc(sizeof(pa_memblock)); - b->type = PA_MEMBLOCK_DYNAMIC; - b->ref = 1; - b->length = length; - b->data = d; - b->free_cb = NULL; - b->read_only = 0; - stat_add(b, s); - return b; -} - -pa_memblock *pa_memblock_new_fixed(void *d, size_t length, int read_only, pa_memblock_stat*s) { - pa_memblock *b = pa_xmalloc(sizeof(pa_memblock)); - b->type = PA_MEMBLOCK_FIXED; - b->ref = 1; - b->length = length; - b->data = d; - b->free_cb = NULL; - b->read_only = read_only; - stat_add(b, s); - return b; -} - -pa_memblock *pa_memblock_new_user(void *d, size_t length, void (*free_cb)(void *p), int read_only, pa_memblock_stat*s) { - pa_memblock *b; - assert(d && length && free_cb); - b = pa_xmalloc(sizeof(pa_memblock)); - b->type = PA_MEMBLOCK_USER; - b->ref = 1; - b->length = length; - b->data = d; - b->free_cb = free_cb; - b->read_only = read_only; - stat_add(b, s); - return b; -} - -pa_memblock* pa_memblock_ref(pa_memblock*b) { - assert(b); - assert(b->ref >= 1); - - b->ref++; - return b; -} - -void pa_memblock_unref(pa_memblock*b) { - assert(b); - assert(b->ref >= 1); - - if ((--(b->ref)) == 0) { - stat_remove(b); - - if (b->type == PA_MEMBLOCK_USER) { - assert(b->free_cb); - b->free_cb(b->data); - } else if (b->type == PA_MEMBLOCK_DYNAMIC) - pa_xfree(b->data); - - pa_xfree(b); - } -} - -void pa_memblock_unref_fixed(pa_memblock *b) { - assert(b && b->ref >= 1 && b->type == PA_MEMBLOCK_FIXED); - - if (b->ref == 1) - pa_memblock_unref(b); - else { - b->data = pa_xmemdup(b->data, b->length); - b->type = PA_MEMBLOCK_DYNAMIC; - b->ref--; - } -} - -pa_memblock_stat* pa_memblock_stat_new(void) { - pa_memblock_stat *s; - - s = pa_xmalloc(sizeof(pa_memblock_stat)); - s->ref = 1; - s->total = s->total_size = s->allocated = s->allocated_size = 0; - - return s; -} - -void pa_memblock_stat_unref(pa_memblock_stat *s) { - assert(s && s->ref >= 1); - - if (!(--(s->ref))) { - assert(!s->total); - pa_xfree(s); - } -} - -pa_memblock_stat * pa_memblock_stat_ref(pa_memblock_stat *s) { - assert(s); - s->ref++; - return s; -} diff --git a/src/polypcore/memblock.h b/src/polypcore/memblock.h deleted file mode 100644 index 9471278a..00000000 --- a/src/polypcore/memblock.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef foomemblockhfoo -#define foomemblockhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -/* A pa_memblock is a reference counted memory block. Polypaudio - * passed references to pa_memblocks around instead of copying - * data. See pa_memchunk for a structure that describes parts of - * memory blocks. */ - -/* The type of memory this block points to */ -typedef enum pa_memblock_type { - PA_MEMBLOCK_FIXED, /* data is a pointer to fixed memory that needs not to be freed */ - PA_MEMBLOCK_APPENDED, /* The most common kind: the data is appended to the memory block */ - PA_MEMBLOCK_DYNAMIC, /* data is a pointer to some memory allocated with pa_xmalloc() */ - PA_MEMBLOCK_USER /* User supplied memory, to be freed with free_cb */ -} pa_memblock_type_t; - -/* A structure of keeping memory block statistics */ -/* Maintains statistics about memory blocks */ -typedef struct pa_memblock_stat { - int ref; - unsigned total; - unsigned total_size; - unsigned allocated; - unsigned allocated_size; -} pa_memblock_stat; - -typedef struct pa_memblock { - pa_memblock_type_t type; - unsigned ref; /* the reference counter */ - int read_only; /* boolean */ - size_t length; - void *data; - void (*free_cb)(void *p); /* If type == PA_MEMBLOCK_USER this points to a function for freeing this memory block */ - pa_memblock_stat *stat; -} pa_memblock; - -/* Allocate a new memory block of type PA_MEMBLOCK_APPENDED */ -pa_memblock *pa_memblock_new(size_t length, pa_memblock_stat*s); - -/* Allocate a new memory block of type PA_MEMBLOCK_DYNAMIC. The pointer data is to be maintained be the memory block */ -pa_memblock *pa_memblock_new_dynamic(void *data, size_t length, pa_memblock_stat*s); - -/* Allocate a new memory block of type PA_MEMBLOCK_FIXED */ -pa_memblock *pa_memblock_new_fixed(void *data, size_t length, int read_only, pa_memblock_stat*s); - -/* Allocate a new memory block of type PA_MEMBLOCK_USER */ -pa_memblock *pa_memblock_new_user(void *data, size_t length, void (*free_cb)(void *p), int read_only, pa_memblock_stat*s); - -void pa_memblock_unref(pa_memblock*b); -pa_memblock* pa_memblock_ref(pa_memblock*b); - -/* This special unref function has to be called by the owner of the -memory of a static memory block when he wants to release all -references to the memory. This causes the memory to be copied and -converted into a PA_MEMBLOCK_DYNAMIC type memory block */ -void pa_memblock_unref_fixed(pa_memblock*b); - -pa_memblock_stat* pa_memblock_stat_new(void); -void pa_memblock_stat_unref(pa_memblock_stat *s); -pa_memblock_stat * pa_memblock_stat_ref(pa_memblock_stat *s); - -#endif diff --git a/src/polypcore/memblockq.c b/src/polypcore/memblockq.c deleted file mode 100644 index 8ed358fa..00000000 --- a/src/polypcore/memblockq.c +++ /dev/null @@ -1,636 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "memblockq.h" - -struct memblock_list { - struct memblock_list *next, *prev; - int64_t index; - pa_memchunk chunk; -}; - -struct pa_memblockq { - struct memblock_list *blocks, *blocks_tail; - unsigned n_blocks; - size_t maxlength, tlength, base, prebuf, minreq; - int64_t read_index, write_index; - enum { PREBUF, RUNNING } state; - pa_memblock_stat *memblock_stat; - pa_memblock *silence; - pa_mcalign *mcalign; -}; - -pa_memblockq* pa_memblockq_new( - int64_t idx, - size_t maxlength, - size_t tlength, - size_t base, - size_t prebuf, - size_t minreq, - pa_memblock *silence, - pa_memblock_stat *s) { - - pa_memblockq* bq; - - assert(base > 0); - assert(maxlength >= base); - - bq = pa_xnew(pa_memblockq, 1); - bq->blocks = bq->blocks_tail = NULL; - bq->n_blocks = 0; - - bq->base = base; - bq->read_index = bq->write_index = idx; - bq->memblock_stat = s; - - pa_log_debug(__FILE__": memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", - (unsigned long)maxlength, (unsigned long)tlength, (unsigned long)base, (unsigned long)prebuf, (unsigned long)minreq); - - bq->maxlength = ((maxlength+base-1)/base)*base; - assert(bq->maxlength >= base); - - bq->tlength = ((tlength+base-1)/base)*base; - if (!bq->tlength || bq->tlength >= bq->maxlength) - bq->tlength = bq->maxlength; - - bq->prebuf = (prebuf == (size_t) -1) ? bq->tlength/2 : prebuf; - bq->prebuf = ((bq->prebuf+base-1)/base)*base; - if (bq->prebuf > bq->maxlength) - bq->prebuf = bq->maxlength; - - bq->minreq = (minreq/base)*base; - - if (bq->minreq > bq->tlength - bq->prebuf) - bq->minreq = bq->tlength - bq->prebuf; - - if (!bq->minreq) - bq->minreq = 1; - - pa_log_debug(__FILE__": memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", - (unsigned long)bq->maxlength, (unsigned long)bq->tlength, (unsigned long)bq->base, (unsigned long)bq->prebuf, (unsigned long)bq->minreq); - - bq->state = bq->prebuf ? PREBUF : RUNNING; - bq->silence = silence ? pa_memblock_ref(silence) : NULL; - bq->mcalign = NULL; - - return bq; -} - -void pa_memblockq_free(pa_memblockq* bq) { - assert(bq); - - pa_memblockq_flush(bq); - - if (bq->silence) - pa_memblock_unref(bq->silence); - - if (bq->mcalign) - pa_mcalign_free(bq->mcalign); - - pa_xfree(bq); -} - -static void drop_block(pa_memblockq *bq, struct memblock_list *q) { - assert(bq); - assert(q); - - assert(bq->n_blocks >= 1); - - if (q->prev) - q->prev->next = q->next; - else - bq->blocks = q->next; - - if (q->next) - q->next->prev = q->prev; - else - bq->blocks_tail = q->prev; - - pa_memblock_unref(q->chunk.memblock); - pa_xfree(q); - - bq->n_blocks--; -} - -static int can_push(pa_memblockq *bq, size_t l) { - int64_t end; - - assert(bq); - - if (bq->read_index > bq->write_index) { - size_t d = bq->read_index - bq->write_index; - - if (l > d) - l -= d; - else - return 1; - } - - end = bq->blocks_tail ? bq->blocks_tail->index + bq->blocks_tail->chunk.length : 0; - - /* Make sure that the list doesn't get too long */ - if (bq->write_index + (int64_t)l > end) - if (bq->write_index + l - bq->read_index > bq->maxlength) - return 0; - - return 1; -} - -int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { - - struct memblock_list *q, *n; - pa_memchunk chunk; - - assert(bq); - assert(uchunk); - assert(uchunk->memblock); - assert(uchunk->length > 0); - assert(uchunk->index + uchunk->length <= uchunk->memblock->length); - - if (uchunk->length % bq->base) - return -1; - - if (!can_push(bq, uchunk->length)) - return -1; - - chunk = *uchunk; - - if (bq->read_index > bq->write_index) { - - /* We currently have a buffer underflow, we need to drop some - * incoming data */ - - size_t d = bq->read_index - bq->write_index; - - if (chunk.length > d) { - chunk.index += d; - chunk.length -= d; - bq->write_index = bq->read_index; - } else { - /* We drop the incoming data completely */ - bq->write_index += chunk.length; - return 0; - } - } - - /* We go from back to front to look for the right place to add - * this new entry. Drop data we will overwrite on the way */ - - q = bq->blocks_tail; - while (q) { - - if (bq->write_index >= q->index + (int64_t)q->chunk.length) - /* We found the entry where we need to place the new entry immediately after */ - break; - else if (bq->write_index + (int64_t)chunk.length <= q->index) { - /* This entry isn't touched at all, let's skip it */ - q = q->prev; - } else if (bq->write_index <= q->index && - bq->write_index + chunk.length >= q->index + q->chunk.length) { - - /* This entry is fully replaced by the new entry, so let's drop it */ - - struct memblock_list *p; - p = q; - q = q->prev; - drop_block(bq, p); - } else if (bq->write_index >= q->index) { - /* The write index points into this memblock, so let's - * truncate or split it */ - - if (bq->write_index + chunk.length < q->index + q->chunk.length) { - - /* We need to save the end of this memchunk */ - struct memblock_list *p; - size_t d; - - /* Create a new list entry for the end of thie memchunk */ - p = pa_xnew(struct memblock_list, 1); - p->chunk = q->chunk; - pa_memblock_ref(p->chunk.memblock); - - /* Calculate offset */ - d = bq->write_index + chunk.length - q->index; - assert(d > 0); - - /* Drop it from the new entry */ - p->index = q->index + d; - p->chunk.length -= d; - - /* Add it to the list */ - p->prev = q; - if ((p->next = q->next)) - q->next->prev = p; - else - bq->blocks_tail = p; - q->next = p; - - bq->n_blocks++; - } - - /* Truncate the chunk */ - if (!(q->chunk.length = bq->write_index - q->index)) { - struct memblock_list *p; - p = q; - q = q->prev; - drop_block(bq, p); - } - - /* We had to truncate this block, hence we're now at the right position */ - break; - } else { - size_t d; - - assert(bq->write_index + (int64_t)chunk.length > q->index && - bq->write_index + (int64_t)chunk.length < q->index + (int64_t)q->chunk.length && - bq->write_index < q->index); - - /* The job overwrites the current entry at the end, so let's drop the beginning of this entry */ - - d = bq->write_index + chunk.length - q->index; - q->index += d; - q->chunk.index += d; - q->chunk.length -= d; - - q = q->prev; - } - - } - - if (q) { - assert(bq->write_index >= q->index + (int64_t)q->chunk.length); - assert(!q->next || (bq->write_index + (int64_t)chunk.length <= q->next->index)); - - /* Try to merge memory blocks */ - - if (q->chunk.memblock == chunk.memblock && - q->chunk.index + (int64_t)q->chunk.length == chunk.index && - bq->write_index == q->index + (int64_t)q->chunk.length) { - - q->chunk.length += chunk.length; - bq->write_index += chunk.length; - return 0; - } - } else - assert(!bq->blocks || (bq->write_index + (int64_t)chunk.length <= bq->blocks->index)); - - - n = pa_xnew(struct memblock_list, 1); - n->chunk = chunk; - pa_memblock_ref(n->chunk.memblock); - n->index = bq->write_index; - bq->write_index += n->chunk.length; - - n->next = q ? q->next : bq->blocks; - n->prev = q; - - if (n->next) - n->next->prev = n; - else - bq->blocks_tail = n; - - if (n->prev) - n->prev->next = n; - else - bq->blocks = n; - - bq->n_blocks++; - return 0; -} - -int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { - assert(bq); - assert(chunk); - - if (bq->state == PREBUF) { - - /* We need to pre-buffer */ - if (pa_memblockq_get_length(bq) < bq->prebuf) - return -1; - - bq->state = RUNNING; - - } else if (bq->prebuf > 0 && bq->read_index >= bq->write_index) { - - /* Buffer underflow protection */ - bq->state = PREBUF; - return -1; - } - - /* Do we need to spit out silence? */ - if (!bq->blocks || bq->blocks->index > bq->read_index) { - - size_t length; - - /* How much silence shall we return? */ - length = bq->blocks ? bq->blocks->index - bq->read_index : 0; - - /* We need to return silence, since no data is yet available */ - if (bq->silence) { - chunk->memblock = pa_memblock_ref(bq->silence); - - if (!length || length > chunk->memblock->length) - length = chunk->memblock->length; - - chunk->length = length; - } else { - chunk->memblock = NULL; - chunk->length = length; - } - - chunk->index = 0; - return 0; - } - - /* Ok, let's pass real data to the caller */ - assert(bq->blocks->index == bq->read_index); - - *chunk = bq->blocks->chunk; - pa_memblock_ref(chunk->memblock); - - return 0; -} - -void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length) { - assert(bq); - assert(length % bq->base == 0); - - assert(!chunk || length <= chunk->length); - - if (chunk) { - - if (bq->blocks && bq->blocks->index == bq->read_index) { - /* The first item in queue is valid */ - - /* Does the chunk match with what the user supplied us? */ - if (memcmp(chunk, &bq->blocks->chunk, sizeof(pa_memchunk)) != 0) - return; - - } else { - size_t l; - - /* The first item in the queue is not yet relevant */ - - assert(!bq->blocks || bq->blocks->index > bq->read_index); - l = bq->blocks ? bq->blocks->index - bq->read_index : 0; - - if (bq->silence) { - - if (!l || l > bq->silence->length) - l = bq->silence->length; - - } - - /* Do the entries still match? */ - if (chunk->index != 0 || chunk->length != l || chunk->memblock != bq->silence) - return; - } - } - - while (length > 0) { - - if (bq->blocks) { - size_t d; - - assert(bq->blocks->index >= bq->read_index); - - d = (size_t) (bq->blocks->index - bq->read_index); - - if (d >= length) { - /* The first block is too far in the future */ - - bq->read_index += length; - break; - } else { - - length -= d; - bq->read_index += d; - } - - assert(bq->blocks->index == bq->read_index); - - if (bq->blocks->chunk.length <= length) { - /* We need to drop the full block */ - - length -= bq->blocks->chunk.length; - bq->read_index += bq->blocks->chunk.length; - - drop_block(bq, bq->blocks); - } else { - /* Only the start of this block needs to be dropped */ - - bq->blocks->chunk.index += length; - bq->blocks->chunk.length -= length; - bq->blocks->index += length; - bq->read_index += length; - break; - } - - } else { - - /* The list is empty, there's nothing we could drop */ - bq->read_index += length; - break; - } - } -} - -int pa_memblockq_is_readable(pa_memblockq *bq) { - assert(bq); - - if (bq->prebuf > 0) { - size_t l = pa_memblockq_get_length(bq); - - if (bq->state == PREBUF && l < bq->prebuf) - return 0; - - if (l <= 0) - return 0; - } - - return 1; -} - -int pa_memblockq_is_writable(pa_memblockq *bq, size_t length) { - assert(bq); - - if (length % bq->base) - return 0; - - return pa_memblockq_get_length(bq) + length <= bq->tlength; -} - -size_t pa_memblockq_get_length(pa_memblockq *bq) { - assert(bq); - - if (bq->write_index <= bq->read_index) - return 0; - - return (size_t) (bq->write_index - bq->read_index); -} - -size_t pa_memblockq_missing(pa_memblockq *bq) { - size_t l; - assert(bq); - - if ((l = pa_memblockq_get_length(bq)) >= bq->tlength) - return 0; - - l = bq->tlength - l; - return (l >= bq->minreq) ? l : 0; -} - -size_t pa_memblockq_get_minreq(pa_memblockq *bq) { - assert(bq); - - return bq->minreq; -} - -void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek) { - assert(bq); - - switch (seek) { - case PA_SEEK_RELATIVE: - bq->write_index += offset; - return; - case PA_SEEK_ABSOLUTE: - bq->write_index = offset; - return; - case PA_SEEK_RELATIVE_ON_READ: - bq->write_index = bq->read_index + offset; - return; - case PA_SEEK_RELATIVE_END: - bq->write_index = (bq->blocks_tail ? bq->blocks_tail->index + (int64_t)bq->blocks_tail->chunk.length : bq->read_index) + offset; - return; - } - - assert(0); -} - -void pa_memblockq_flush(pa_memblockq *bq) { - assert(bq); - - while (bq->blocks) - drop_block(bq, bq->blocks); - - assert(bq->n_blocks == 0); - - bq->write_index = bq->read_index; - - pa_memblockq_prebuf_force(bq); -} - -size_t pa_memblockq_get_tlength(pa_memblockq *bq) { - assert(bq); - - return bq->tlength; -} - -int64_t pa_memblockq_get_read_index(pa_memblockq *bq) { - assert(bq); - return bq->read_index; -} - -int64_t pa_memblockq_get_write_index(pa_memblockq *bq) { - assert(bq); - return bq->write_index; -} - -int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk) { - pa_memchunk rchunk; - - assert(bq); - assert(chunk && bq->base); - - if (bq->base == 1) - return pa_memblockq_push(bq, chunk); - - if (!bq->mcalign) - bq->mcalign = pa_mcalign_new(bq->base, bq->memblock_stat); - - if (!can_push(bq, pa_mcalign_csize(bq->mcalign, chunk->length))) - return -1; - - pa_mcalign_push(bq->mcalign, chunk); - - while (pa_mcalign_pop(bq->mcalign, &rchunk) >= 0) { - int r; - r = pa_memblockq_push(bq, &rchunk); - pa_memblock_unref(rchunk.memblock); - - if (r < 0) - return -1; - } - - return 0; -} - -void pa_memblockq_shorten(pa_memblockq *bq, size_t length) { - size_t l; - assert(bq); - - l = pa_memblockq_get_length(bq); - - if (l > length) - pa_memblockq_drop(bq, NULL, l - length); -} - -void pa_memblockq_prebuf_disable(pa_memblockq *bq) { - assert(bq); - - if (bq->state == PREBUF) - bq->state = RUNNING; -} - -void pa_memblockq_prebuf_force(pa_memblockq *bq) { - assert(bq); - - if (bq->state == RUNNING && bq->prebuf > 0) - bq->state = PREBUF; -} - -size_t pa_memblockq_get_maxlength(pa_memblockq *bq) { - assert(bq); - - return bq->maxlength; -} - -size_t pa_memblockq_get_prebuf(pa_memblockq *bq) { - assert(bq); - - return bq->prebuf; -} diff --git a/src/polypcore/memblockq.h b/src/polypcore/memblockq.h deleted file mode 100644 index 74fb00ee..00000000 --- a/src/polypcore/memblockq.h +++ /dev/null @@ -1,140 +0,0 @@ -#ifndef foomemblockqhfoo -#define foomemblockqhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -#include -#include -#include - -/* A memblockq is a queue of pa_memchunks (yepp, the name is not - * perfect). It is similar to the ring buffers used by most other - * audio software. In contrast to a ring buffer this memblockq data - * type doesn't need to copy any data around, it just maintains - * references to reference counted memory blocks. */ - -typedef struct pa_memblockq pa_memblockq; - - -/* Parameters: - - - idx: start value for both read and write index - - - maxlength: maximum length of queue. If more data is pushed into - the queue, the operation will fail. Must not be 0. - - - tlength: the target length of the queue. Pass 0 for the default. - - - base: a base value for all metrics. Only multiples of this value - are popped from the queue or should be pushed into - it. Must not be 0. - - - prebuf: If the queue runs empty wait until this many bytes are in - queue again before passing the first byte out. If set - to 0 pa_memblockq_pop() will return a silence memblock - if no data is in the queue and will never fail. Pass - (size_t) -1 for the default. - - - minreq: pa_memblockq_missing() will only return values greater - than this value. Pass 0 for the default. - - - silence: return this memblock whzen reading unitialized data -*/ -pa_memblockq* pa_memblockq_new( - int64_t idx, - size_t maxlength, - size_t tlength, - size_t base, - size_t prebuf, - size_t minreq, - pa_memblock *silence, - pa_memblock_stat *s); - -void pa_memblockq_free(pa_memblockq*bq); - -/* Push a new memory chunk into the queue. */ -int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *chunk); - -/* Push a new memory chunk into the queue, but filter it through a - * pa_mcalign object. Don't mix this with pa_memblockq_seek() unless - * you know what you do. */ -int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk); - -/* Return a copy of the next memory chunk in the queue. It is not removed from the queue */ -int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk); - -/* Drop the specified bytes from the queue, but only if the first - * chunk in the queue matches the one passed here. If NULL is passed, - * this check isn't done. */ -void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length); - -/* Test if the pa_memblockq is currently readable, that is, more data than base */ -int pa_memblockq_is_readable(pa_memblockq *bq); - -/* Test if the pa_memblockq is currently writable for the specified amount of bytes */ -int pa_memblockq_is_writable(pa_memblockq *bq, size_t length); - -/* Return the length of the queue in bytes */ -size_t pa_memblockq_get_length(pa_memblockq *bq); - -/* Return how many bytes are missing in queue to the specified fill amount */ -size_t pa_memblockq_missing(pa_memblockq *bq); - -/* Returns the minimal request value */ -size_t pa_memblockq_get_minreq(pa_memblockq *bq); - -/* Manipulate the write pointer */ -void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek); - -/* Set the queue to silence, set write index to read index */ -void pa_memblockq_flush(pa_memblockq *bq); - -/* Get Target length */ -size_t pa_memblockq_get_tlength(pa_memblockq *bq); - -/* Return the current read index */ -int64_t pa_memblockq_get_read_index(pa_memblockq *bq); - -/* Return the current write index */ -int64_t pa_memblockq_get_write_index(pa_memblockq *bq); - -/* Shorten the pa_memblockq to the specified length by dropping data - * at the read end of the queue. The read index is increased until the - * queue has the specified length */ -void pa_memblockq_shorten(pa_memblockq *bq, size_t length); - -/* Ignore prebuf for now */ -void pa_memblockq_prebuf_disable(pa_memblockq *bq); - -/* Force prebuf */ -void pa_memblockq_prebuf_force(pa_memblockq *bq); - -/* Return the maximum length of the queue in bytes */ -size_t pa_memblockq_get_maxlength(pa_memblockq *bq); - -/* Return the prebuffer length in bytes */ -size_t pa_memblockq_get_prebuf(pa_memblockq *bq); - -#endif diff --git a/src/polypcore/memchunk.c b/src/polypcore/memchunk.c deleted file mode 100644 index 918b3f0f..00000000 --- a/src/polypcore/memchunk.c +++ /dev/null @@ -1,59 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -#include "memchunk.h" - -void pa_memchunk_make_writable(pa_memchunk *c, pa_memblock_stat *s, size_t min) { - pa_memblock *n; - size_t l; - assert(c && c->memblock && c->memblock->ref >= 1); - - if (c->memblock->ref == 1 && !c->memblock->read_only && c->memblock->length >= c->index+min) - return; - - l = c->length; - if (l < min) - l = min; - - n = pa_memblock_new(l, s); - memcpy(n->data, (uint8_t*) c->memblock->data + c->index, c->length); - pa_memblock_unref(c->memblock); - c->memblock = n; - c->index = 0; -} - -void pa_memchunk_reset(pa_memchunk *c) { - assert(c); - - c->memblock = NULL; - c->length = c->index = 0; -} diff --git a/src/polypcore/memchunk.h b/src/polypcore/memchunk.h deleted file mode 100644 index 3ddb28ee..00000000 --- a/src/polypcore/memchunk.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef foomemchunkhfoo -#define foomemchunkhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -/* A memchunk describes a part of a memblock. In contrast to the memblock, a - * memchunk is not allocated dynamically or reference counted, instead - * it is usually stored on the stack and copied around */ - -typedef struct pa_memchunk { - pa_memblock *memblock; - size_t index, length; -} pa_memchunk; - -/* Make a memchunk writable, i.e. make sure that the caller may have - * exclusive access to the memblock and it is not read_only. If needed - * the memblock in the structure is replaced by a copy. */ -void pa_memchunk_make_writable(pa_memchunk *c, pa_memblock_stat *s, size_t min); - -/* Invalidate a memchunk. This does not free the cotaining memblock, - * but sets all members to zero. */ -void pa_memchunk_reset(pa_memchunk *c); - -#endif diff --git a/src/polypcore/modargs.c b/src/polypcore/modargs.c deleted file mode 100644 index 5d046d26..00000000 --- a/src/polypcore/modargs.c +++ /dev/null @@ -1,310 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "modargs.h" - -struct entry { - char *key, *value; -}; - -static int add_key_value(pa_hashmap *map, char *key, char *value, const char* const valid_keys[]) { - struct entry *e; - assert(map && key && value); - - if (valid_keys) { - const char*const* v; - for (v = valid_keys; *v; v++) - if (strcmp(*v, key) == 0) - break; - - if (!*v) { - pa_xfree(key); - pa_xfree(value); - return -1; - } - } - - e = pa_xmalloc(sizeof(struct entry)); - e->key = key; - e->value = value; - pa_hashmap_put(map, key, e); - return 0; -} - -pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) { - pa_hashmap *map = NULL; - - map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - assert(map); - - if (args) { - enum { WHITESPACE, KEY, VALUE_START, VALUE_SIMPLE, VALUE_DOUBLE_QUOTES, VALUE_TICKS } state; - const char *p, *key, *value; - size_t key_len = 0, value_len = 0; - - key = value = NULL; - state = WHITESPACE; - for (p = args; *p; p++) { - switch (state) { - case WHITESPACE: - if (*p == '=') - goto fail; - else if (!isspace(*p)) { - key = p; - state = KEY; - key_len = 1; - } - break; - case KEY: - if (*p == '=') - state = VALUE_START; - else - key_len++; - break; - case VALUE_START: - if (*p == '\'') { - state = VALUE_TICKS; - value = p+1; - value_len = 0; - } else if (*p == '"') { - state = VALUE_DOUBLE_QUOTES; - value = p+1; - value_len = 0; - } else if (isspace(*p)) { - if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0) - goto fail; - state = WHITESPACE; - } else { - state = VALUE_SIMPLE; - value = p; - value_len = 1; - } - break; - case VALUE_SIMPLE: - if (isspace(*p)) { - if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) - goto fail; - state = WHITESPACE; - } else - value_len++; - break; - case VALUE_DOUBLE_QUOTES: - if (*p == '"') { - if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) - goto fail; - state = WHITESPACE; - } else - value_len++; - break; - case VALUE_TICKS: - if (*p == '\'') { - if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) - goto fail; - state = WHITESPACE; - } else - value_len++; - break; - } - } - - if (state == VALUE_START) { - if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0) - goto fail; - } else if (state == VALUE_SIMPLE) { - if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(value), valid_keys) < 0) - goto fail; - } else if (state != WHITESPACE) - goto fail; - } - - return (pa_modargs*) map; - -fail: - - if (map) - pa_modargs_free((pa_modargs*) map); - - return NULL; -} - - -static void free_func(void *p, PA_GCC_UNUSED void*userdata) { - struct entry *e = p; - assert(e); - pa_xfree(e->key); - pa_xfree(e->value); - pa_xfree(e); -} - -void pa_modargs_free(pa_modargs*ma) { - pa_hashmap *map = (pa_hashmap*) ma; - pa_hashmap_free(map, free_func, NULL); -} - -const char *pa_modargs_get_value(pa_modargs *ma, const char *key, const char *def) { - pa_hashmap *map = (pa_hashmap*) ma; - struct entry*e; - - if (!(e = pa_hashmap_get(map, key))) - return def; - - return e->value; -} - -int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value) { - const char *v; - assert(ma && key && value); - - if (!(v = pa_modargs_get_value(ma, key, NULL))) - return 0; - - if (pa_atou(v, value) < 0) - return -1; - - return 0; -} - -int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value) { - const char *v; - assert(ma && key && value); - - if (!(v = pa_modargs_get_value(ma, key, NULL))) - return 0; - - if (pa_atoi(v, value) < 0) - return -1; - - return 0; -} - -int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value) { - const char *v; - int r; - assert(ma && key && value); - - if (!(v = pa_modargs_get_value(ma, key, NULL))) - return 0; - - if (!*v) - return -1; - - if ((r = pa_parse_boolean(v)) < 0) - return -1; - - *value = r; - return 0; -} - -int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) { - const char *format; - uint32_t channels; - pa_sample_spec ss; - assert(ma && rss); - -/* DEBUG_TRAP;*/ - - ss = *rss; - if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0) - return -1; - - channels = ss.channels; - if ((pa_modargs_get_value_u32(ma, "channels", &channels)) < 0) - return -1; - ss.channels = (uint8_t) channels; - - if ((format = pa_modargs_get_value(ma, "format", NULL))) - if ((ss.format = pa_parse_sample_format(format)) < 0) - return -1; - - if (!pa_sample_spec_valid(&ss)) - return -1; - - *rss = ss; - - return 0; -} - -int pa_modargs_get_channel_map(pa_modargs *ma, pa_channel_map *rmap) { - pa_channel_map map; - const char *cm; - - assert(ma); - assert(rmap); - - map = *rmap; - - if ((cm = pa_modargs_get_value(ma, "channel_map", NULL))) - if (!pa_channel_map_parse(&map, cm)) - return -1; - - if (!pa_channel_map_valid(&map)) - return -1; - - *rmap = map; - return 0; -} - -int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *rss, pa_channel_map *rmap, pa_channel_map_def_t def) { - pa_sample_spec ss; - pa_channel_map map; - - assert(ma); - assert(rss); - assert(rmap); - - ss = *rss; - - if (pa_modargs_get_sample_spec(ma, &ss) < 0) - return -1; - - if (!pa_channel_map_init_auto(&map, ss.channels, def)) - map.channels = 0; - - if (pa_modargs_get_channel_map(ma, &map) < 0) - return -1; - - if (map.channels != ss.channels) - return -1; - - *rmap = map; - *rss = ss; - - return 0; -} diff --git a/src/polypcore/modargs.h b/src/polypcore/modargs.h deleted file mode 100644 index b6977d37..00000000 --- a/src/polypcore/modargs.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef foomodargshfoo -#define foomodargshfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include - -typedef struct pa_modargs pa_modargs; - -/* A generic parser for module arguments */ - -/* Parse the string args. The NULL-terminated array keys contains all valid arguments. */ -pa_modargs *pa_modargs_new(const char *args, const char* const keys[]); -void pa_modargs_free(pa_modargs*ma); - -/* Return the module argument for the specified name as a string. If - * the argument was not specified, return def instead.*/ -const char *pa_modargs_get_value(pa_modargs *ma, const char *key, const char *def); - -/* Return a module argument as unsigned 32bit value in *value */ -int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value); -int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value); -int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value); - -/* Return sample spec data from the three arguments "rate", "format" and "channels" */ -int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *ss); - -/* Return channel map data from the argument "channel_map" */ -int pa_modargs_get_channel_map(pa_modargs *ma, pa_channel_map *map); - -/* Combination of pa_modargs_get_sample_spec() and -pa_modargs_get_channel_map(). Not always suitable, since this routine -initializes the map parameter based on the channels field of the ss -structure if no channel_map is found, using pa_channel_map_init_auto() */ - -int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *ss, pa_channel_map *map, pa_channel_map_def_t def); - -#endif diff --git a/src/polypcore/modinfo.c b/src/polypcore/modinfo.c deleted file mode 100644 index a2fffb01..00000000 --- a/src/polypcore/modinfo.c +++ /dev/null @@ -1,93 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include - -#include -#include - -#include "modinfo.h" - -#define PA_SYMBOL_AUTHOR "pa__get_author" -#define PA_SYMBOL_DESCRIPTION "pa__get_description" -#define PA_SYMBOL_USAGE "pa__get_usage" -#define PA_SYMBOL_VERSION "pa__get_version" - -/* lt_dlsym() violates ISO C, so confide the breakage into this function to - * avoid warnings. */ -typedef void (*fnptr)(void); -static inline fnptr lt_dlsym_fn(lt_dlhandle handle, const char *symbol) { - return (fnptr) (long) lt_dlsym(handle, symbol); -} - -pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl) { - pa_modinfo *i; - const char* (*func)(void); - assert(dl); - - i = pa_xnew0(pa_modinfo, 1); - - if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_AUTHOR))) - i->author = pa_xstrdup(func()); - - if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_DESCRIPTION))) - i->description = pa_xstrdup(func()); - - if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_USAGE))) - i->usage = pa_xstrdup(func()); - - if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_VERSION))) - i->version = pa_xstrdup(func()); - - return i; -} - -pa_modinfo *pa_modinfo_get_by_name(const char *name) { - lt_dlhandle dl; - pa_modinfo *i; - assert(name); - - if (!(dl = lt_dlopenext(name))) { - pa_log(__FILE__": Failed to open module \"%s\": %s", name, lt_dlerror()); - return NULL; - } - - i = pa_modinfo_get_by_handle(dl); - lt_dlclose(dl); - - return i; -} - -void pa_modinfo_free(pa_modinfo *i) { - assert(i); - pa_xfree(i->author); - pa_xfree(i->description); - pa_xfree(i->usage); - pa_xfree(i->version); - pa_xfree(i); -} diff --git a/src/polypcore/modinfo.h b/src/polypcore/modinfo.h deleted file mode 100644 index 53176147..00000000 --- a/src/polypcore/modinfo.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef foomodinfohfoo -#define foomodinfohfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -/* Some functions for reading module meta data from Polypaudio modules */ - -typedef struct pa_modinfo { - char *author; - char *description; - char *usage; - char *version; -} pa_modinfo; - -/* Read meta data from an libtool handle */ -pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl); - -/* Read meta data from a module file */ -pa_modinfo *pa_modinfo_get_by_name(const char *name); - -/* Free meta data */ -void pa_modinfo_free(pa_modinfo *i); - -#endif diff --git a/src/polypcore/module.c b/src/polypcore/module.c deleted file mode 100644 index 47a878fb..00000000 --- a/src/polypcore/module.c +++ /dev/null @@ -1,319 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include "module.h" - -#define PA_SYMBOL_INIT "pa__init" -#define PA_SYMBOL_DONE "pa__done" - -#define UNLOAD_POLL_TIME 2 - -/* lt_dlsym() violates ISO C, so confide the breakage into this function to - * avoid warnings. */ -typedef void (*fnptr)(void); -static inline fnptr lt_dlsym_fn(lt_dlhandle handle, const char *symbol) { - return (fnptr) (long) lt_dlsym(handle, symbol); -} - -static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - pa_core *c = userdata; - struct timeval ntv; - assert(c && c->mainloop == m && c->module_auto_unload_event == e); - - pa_module_unload_unused(c); - - pa_gettimeofday(&ntv); - ntv.tv_sec += UNLOAD_POLL_TIME; - m->time_restart(e, &ntv); -} - -static inline fnptr load_sym(lt_dlhandle handle, const char *module, const char *symbol) { - char *buffer, *ch; - size_t buflen; - fnptr res; - - res = lt_dlsym_fn(handle, symbol); - if (res) - return res; - - /* As the .la files might have been cleansed from the system, we should - * try with the ltdl prefix as well. */ - - buflen = strlen(symbol) + strlen(module) + strlen("_LTX_") + 1; - buffer = pa_xmalloc(buflen); - assert(buffer); - - strcpy(buffer, module); - - for (ch = buffer;*ch != '\0';ch++) { - if (!isalnum(*ch)) - *ch = '_'; - } - - strcat(buffer, "_LTX_"); - strcat(buffer, symbol); - - res = lt_dlsym_fn(handle, buffer); - - pa_xfree(buffer); - - return res; -} - -pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { - pa_module *m = NULL; - int r; - - assert(c && name); - - if (c->disallow_module_loading) - goto fail; - - m = pa_xmalloc(sizeof(pa_module)); - - m->name = pa_xstrdup(name); - m->argument = pa_xstrdup(argument); - - if (!(m->dl = lt_dlopenext(name))) { - pa_log(__FILE__": Failed to open module \"%s\": %s", name, lt_dlerror()); - goto fail; - } - - if (!(m->init = (int (*)(pa_core *_c, pa_module*_m)) load_sym(m->dl, name, PA_SYMBOL_INIT))) { - pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.", name); - goto fail; - } - - if (!(m->done = (void (*)(pa_core *_c, pa_module*_m)) load_sym(m->dl, name, PA_SYMBOL_DONE))) { - pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_DONE"\" not found.", name); - goto fail; - } - - m->userdata = NULL; - m->core = c; - m->n_used = -1; - m->auto_unload = 0; - m->unload_requested = 0; - - assert(m->init); - if (m->init(c, m) < 0) { - pa_log_error(__FILE__": Failed to load module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : ""); - goto fail; - } - - if (!c->modules) - c->modules = pa_idxset_new(NULL, NULL); - - if (!c->module_auto_unload_event) { - struct timeval ntv; - pa_gettimeofday(&ntv); - ntv.tv_sec += UNLOAD_POLL_TIME; - c->module_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); - } - assert(c->module_auto_unload_event); - - assert(c->modules); - r = pa_idxset_put(c->modules, m, &m->index); - assert(r >= 0 && m->index != PA_IDXSET_INVALID); - - pa_log_info(__FILE__": Loaded \"%s\" (index: #%u; argument: \"%s\").", m->name, m->index, m->argument ? m->argument : ""); - - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_NEW, m->index); - - return m; - -fail: - - if (m) { - pa_xfree(m->argument); - pa_xfree(m->name); - - if (m->dl) - lt_dlclose(m->dl); - - pa_xfree(m); - } - - return NULL; -} - -static void pa_module_free(pa_module *m) { - assert(m && m->done && m->core); - - if (m->core->disallow_module_loading) - return; - - pa_log_info(__FILE__": Unloading \"%s\" (index: #%u).", m->name, m->index); - - m->done(m->core, m); - - lt_dlclose(m->dl); - - pa_log_info(__FILE__": Unloaded \"%s\" (index: #%u).", m->name, m->index); - - pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_REMOVE, m->index); - - pa_xfree(m->name); - pa_xfree(m->argument); - pa_xfree(m); -} - -void pa_module_unload(pa_core *c, pa_module *m) { - assert(c && m); - - assert(c->modules); - if (!(m = pa_idxset_remove_by_data(c->modules, m, NULL))) - return; - - pa_module_free(m); -} - -void pa_module_unload_by_index(pa_core *c, uint32_t idx) { - pa_module *m; - assert(c && idx != PA_IDXSET_INVALID); - - assert(c->modules); - if (!(m = pa_idxset_remove_by_index(c->modules, idx))) - return; - - pa_module_free(m); -} - -static void free_callback(void *p, PA_GCC_UNUSED void *userdata) { - pa_module *m = p; - assert(m); - pa_module_free(m); -} - -void pa_module_unload_all(pa_core *c) { - assert(c); - - if (!c->modules) - return; - - pa_idxset_free(c->modules, free_callback, NULL); - c->modules = NULL; - - if (c->module_auto_unload_event) { - c->mainloop->time_free(c->module_auto_unload_event); - c->module_auto_unload_event = NULL; - } - - if (c->module_defer_unload_event) { - c->mainloop->defer_free(c->module_defer_unload_event); - c->module_defer_unload_event = NULL; - } -} - -static int unused_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void *userdata) { - pa_module *m = p; - time_t *now = userdata; - assert(p && del && now); - - if (m->n_used == 0 && m->auto_unload && m->last_used_time+m->core->module_idle_time <= *now) { - pa_module_free(m); - *del = 1; - } - - return 0; -} - -void pa_module_unload_unused(pa_core *c) { - time_t now; - assert(c); - - if (!c->modules) - return; - - time(&now); - pa_idxset_foreach(c->modules, unused_callback, &now); -} - -static int unload_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, PA_GCC_UNUSED void *userdata) { - pa_module *m = p; - assert(m); - - if (m->unload_requested) { - pa_module_free(m); - *del = 1; - } - - return 0; -} - -static void defer_cb(pa_mainloop_api*api, pa_defer_event *e, void *userdata) { - pa_core *core = userdata; - api->defer_enable(e, 0); - - if (!core->modules) - return; - - pa_idxset_foreach(core->modules, unload_callback, NULL); - -} - -void pa_module_unload_request(pa_module *m) { - assert(m); - - m->unload_requested = 1; - - if (!m->core->module_defer_unload_event) - m->core->module_defer_unload_event = m->core->mainloop->defer_new(m->core->mainloop, defer_cb, m->core); - - m->core->mainloop->defer_enable(m->core->module_defer_unload_event, 1); -} - -void pa_module_set_used(pa_module*m, int used) { - assert(m); - - if (m->n_used != used) - pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_CHANGE, m->index); - - if (m->n_used != used && used == 0) - time(&m->last_used_time); - - m->n_used = used; -} - -pa_modinfo *pa_module_get_info(pa_module *m) { - assert(m); - - return pa_modinfo_get_by_handle(m->dl); -} diff --git a/src/polypcore/module.h b/src/polypcore/module.h deleted file mode 100644 index 03b9bc87..00000000 --- a/src/polypcore/module.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef foomodulehfoo -#define foomodulehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -#include -#include - -typedef struct pa_module pa_module; - -struct pa_module { - pa_core *core; - char *name, *argument; - uint32_t index; - - lt_dlhandle dl; - - int (*init)(pa_core *c, pa_module*m); - void (*done)(pa_core *c, pa_module*m); - - void *userdata; - - int n_used; - int auto_unload; - time_t last_used_time; - - int unload_requested; -}; - -pa_module* pa_module_load(pa_core *c, const char *name, const char*argument); -void pa_module_unload(pa_core *c, pa_module *m); -void pa_module_unload_by_index(pa_core *c, uint32_t idx); - -void pa_module_unload_all(pa_core *c); -void pa_module_unload_unused(pa_core *c); - -void pa_module_unload_request(pa_module *m); - -void pa_module_set_used(pa_module*m, int used); - -#define PA_MODULE_AUTHOR(s) const char * pa__get_author(void) { return s; } -#define PA_MODULE_DESCRIPTION(s) const char * pa__get_description(void) { return s; } -#define PA_MODULE_USAGE(s) const char * pa__get_usage(void) { return s; } -#define PA_MODULE_VERSION(s) const char * pa__get_version(void) { return s; } - -pa_modinfo *pa_module_get_info(pa_module *m); - -#endif diff --git a/src/polypcore/namereg.c b/src/polypcore/namereg.c deleted file mode 100644 index 17d75146..00000000 --- a/src/polypcore/namereg.c +++ /dev/null @@ -1,214 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include "namereg.h" - -struct namereg_entry { - pa_namereg_type_t type; - char *name; - void *data; -}; - -void pa_namereg_free(pa_core *c) { - assert(c); - if (!c->namereg) - return; - assert(pa_hashmap_size(c->namereg) == 0); - pa_hashmap_free(c->namereg, NULL, NULL); -} - -const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, int fail) { - struct namereg_entry *e; - char *n = NULL; - int r; - - assert(c && name && data); - - if (!c->namereg) { - c->namereg = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - assert(c->namereg); - } - - if ((e = pa_hashmap_get(c->namereg, name)) && fail) - return NULL; - - if (!e) - n = pa_xstrdup(name); - else { - unsigned i; - size_t l = strlen(name); - n = pa_xmalloc(l+3); - - for (i = 1; i <= 99; i++) { - snprintf(n, l+2, "%s%u", name, i); - - if (!(e = pa_hashmap_get(c->namereg, n))) - break; - } - - if (e) { - pa_xfree(n); - return NULL; - } - } - - assert(n); - e = pa_xmalloc(sizeof(struct namereg_entry)); - e->type = type; - e->name = n; - e->data = data; - - r = pa_hashmap_put(c->namereg, e->name, e); - assert (r >= 0); - - return e->name; - -} - -void pa_namereg_unregister(pa_core *c, const char *name) { - struct namereg_entry *e; - assert(c && name); - - e = pa_hashmap_remove(c->namereg, name); - assert(e); - - pa_xfree(e->name); - pa_xfree(e); -} - -void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int autoload) { - struct namereg_entry *e; - uint32_t idx; - assert(c); - - if (!name) { - if (type == PA_NAMEREG_SOURCE) - name = pa_namereg_get_default_source_name(c); - else if (type == PA_NAMEREG_SINK) - name = pa_namereg_get_default_sink_name(c); - } - - if (!name) - return NULL; - - if (c->namereg && (e = pa_hashmap_get(c->namereg, name))) - if (e->type == type) - return e->data; - - if (pa_atou(name, &idx) < 0) { - - if (autoload) { - pa_autoload_request(c, name, type); - - if (c->namereg && (e = pa_hashmap_get(c->namereg, name))) - if (e->type == type) - return e->data; - } - - return NULL; - } - - if (type == PA_NAMEREG_SINK) - return pa_idxset_get_by_index(c->sinks, idx); - else if (type == PA_NAMEREG_SOURCE) - return pa_idxset_get_by_index(c->sources, idx); - else if (type == PA_NAMEREG_SAMPLE && c->scache) - return pa_idxset_get_by_index(c->scache, idx); - - return NULL; -} - -void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type) { - char **s; - assert(c && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); - - s = type == PA_NAMEREG_SINK ? &c->default_sink_name : &c->default_source_name; - assert(s); - - if (!name && !*s) - return; - - if (name && *s && !strcmp(name, *s)) - return; - - pa_xfree(*s); - *s = pa_xstrdup(name); - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); -} - -const char *pa_namereg_get_default_sink_name(pa_core *c) { - pa_sink *s; - assert(c); - - if (c->default_sink_name) - return c->default_sink_name; - - if ((s = pa_idxset_first(c->sinks, NULL))) - pa_namereg_set_default(c, s->name, PA_NAMEREG_SINK); - - if (c->default_sink_name) - return c->default_sink_name; - - return NULL; -} - -const char *pa_namereg_get_default_source_name(pa_core *c) { - pa_source *s; - uint32_t idx; - - assert(c); - - if (c->default_source_name) - return c->default_source_name; - - for (s = pa_idxset_first(c->sources, &idx); s; s = pa_idxset_next(c->sources, &idx)) - if (!s->monitor_of) { - pa_namereg_set_default(c, s->name, PA_NAMEREG_SOURCE); - break; - } - - if (!c->default_source_name) - if ((s = pa_idxset_first(c->sources, NULL))) - pa_namereg_set_default(c, s->name, PA_NAMEREG_SOURCE); - - if (c->default_source_name) - return c->default_source_name; - - return NULL; -} diff --git a/src/polypcore/namereg.h b/src/polypcore/namereg.h deleted file mode 100644 index a98295ff..00000000 --- a/src/polypcore/namereg.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef foonamereghfoo -#define foonamereghfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -typedef enum pa_namereg_type { - PA_NAMEREG_SINK, - PA_NAMEREG_SOURCE, - PA_NAMEREG_SAMPLE -} pa_namereg_type_t; - -void pa_namereg_free(pa_core *c); - -const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, int fail); -void pa_namereg_unregister(pa_core *c, const char *name); -void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int autoload); -void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type); - -const char *pa_namereg_get_default_sink_name(pa_core *c); -const char *pa_namereg_get_default_source_name(pa_core *c); - -#endif diff --git a/src/polypcore/native-common.h b/src/polypcore/native-common.h deleted file mode 100644 index 1107da55..00000000 --- a/src/polypcore/native-common.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef foonativecommonhfoo -#define foonativecommonhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -PA_C_DECL_BEGIN - -enum { - /* Generic commands */ - PA_COMMAND_ERROR, - PA_COMMAND_TIMEOUT, /* pseudo command */ - PA_COMMAND_REPLY, - - /* Commands from client to server */ - PA_COMMAND_CREATE_PLAYBACK_STREAM, - PA_COMMAND_DELETE_PLAYBACK_STREAM, - PA_COMMAND_CREATE_RECORD_STREAM, - PA_COMMAND_DELETE_RECORD_STREAM, - PA_COMMAND_EXIT, - PA_COMMAND_AUTH, - PA_COMMAND_SET_CLIENT_NAME, - PA_COMMAND_LOOKUP_SINK, - PA_COMMAND_LOOKUP_SOURCE, - PA_COMMAND_DRAIN_PLAYBACK_STREAM, - PA_COMMAND_STAT, - PA_COMMAND_GET_PLAYBACK_LATENCY, - PA_COMMAND_CREATE_UPLOAD_STREAM, - PA_COMMAND_DELETE_UPLOAD_STREAM, - PA_COMMAND_FINISH_UPLOAD_STREAM, - PA_COMMAND_PLAY_SAMPLE, - PA_COMMAND_REMOVE_SAMPLE, - - PA_COMMAND_GET_SERVER_INFO, - PA_COMMAND_GET_SINK_INFO, - PA_COMMAND_GET_SINK_INFO_LIST, - PA_COMMAND_GET_SOURCE_INFO, - PA_COMMAND_GET_SOURCE_INFO_LIST, - PA_COMMAND_GET_MODULE_INFO, - PA_COMMAND_GET_MODULE_INFO_LIST, - PA_COMMAND_GET_CLIENT_INFO, - PA_COMMAND_GET_CLIENT_INFO_LIST, - PA_COMMAND_GET_SINK_INPUT_INFO, - PA_COMMAND_GET_SINK_INPUT_INFO_LIST, - PA_COMMAND_GET_SOURCE_OUTPUT_INFO, - PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, - PA_COMMAND_GET_SAMPLE_INFO, - PA_COMMAND_GET_SAMPLE_INFO_LIST, - PA_COMMAND_SUBSCRIBE, - - PA_COMMAND_SET_SINK_VOLUME, - PA_COMMAND_SET_SINK_INPUT_VOLUME, - PA_COMMAND_SET_SOURCE_VOLUME, - - PA_COMMAND_SET_SINK_MUTE, - PA_COMMAND_SET_SOURCE_MUTE, - - PA_COMMAND_CORK_PLAYBACK_STREAM, - PA_COMMAND_FLUSH_PLAYBACK_STREAM, - PA_COMMAND_TRIGGER_PLAYBACK_STREAM, - - PA_COMMAND_SET_DEFAULT_SINK, - PA_COMMAND_SET_DEFAULT_SOURCE, - - PA_COMMAND_SET_PLAYBACK_STREAM_NAME, - PA_COMMAND_SET_RECORD_STREAM_NAME, - - PA_COMMAND_KILL_CLIENT, - PA_COMMAND_KILL_SINK_INPUT, - PA_COMMAND_KILL_SOURCE_OUTPUT, - PA_COMMAND_LOAD_MODULE, - PA_COMMAND_UNLOAD_MODULE, - PA_COMMAND_ADD_AUTOLOAD, - PA_COMMAND_REMOVE_AUTOLOAD, - PA_COMMAND_GET_AUTOLOAD_INFO, - PA_COMMAND_GET_AUTOLOAD_INFO_LIST, - PA_COMMAND_GET_RECORD_LATENCY, - PA_COMMAND_CORK_RECORD_STREAM, - PA_COMMAND_FLUSH_RECORD_STREAM, - PA_COMMAND_PREBUF_PLAYBACK_STREAM, - - /* Commands from server to client */ - PA_COMMAND_REQUEST, - PA_COMMAND_OVERFLOW, - PA_COMMAND_UNDERFLOW, - PA_COMMAND_PLAYBACK_STREAM_KILLED, - PA_COMMAND_RECORD_STREAM_KILLED, - PA_COMMAND_SUBSCRIBE_EVENT, - - PA_COMMAND_MAX -}; - -#define PA_NATIVE_COOKIE_LENGTH 256 -#define PA_NATIVE_COOKIE_FILE ".polypaudio-cookie" - -#define PA_NATIVE_DEFAULT_PORT 4713 - -#define PA_NATIVE_COOKIE_PROPERTY_NAME "protocol-native-cookie" -#define PA_NATIVE_SERVER_PROPERTY_NAME "protocol-native-server" - -#define PA_NATIVE_DEFAULT_UNIX_SOCKET "native" - - -PA_C_DECL_END - -#endif diff --git a/src/polypcore/packet.c b/src/polypcore/packet.c deleted file mode 100644 index 646b59e0..00000000 --- a/src/polypcore/packet.c +++ /dev/null @@ -1,79 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include - -#include "packet.h" - -pa_packet* pa_packet_new(size_t length) { - pa_packet *p; - - assert(length); - - p = pa_xmalloc(sizeof(pa_packet)+length); - p->ref = 1; - p->length = length; - p->data = (uint8_t*) (p+1); - p->type = PA_PACKET_APPENDED; - - return p; -} - -pa_packet* pa_packet_new_dynamic(void* data, size_t length) { - pa_packet *p; - - assert(data); - assert(length); - - p = pa_xnew(pa_packet, 1); - p->ref = 1; - p->length = length; - p->data = data; - p->type = PA_PACKET_DYNAMIC; - - return p; -} - -pa_packet* pa_packet_ref(pa_packet *p) { - assert(p); - assert(p->ref >= 1); - - p->ref++; - return p; -} - -void pa_packet_unref(pa_packet *p) { - assert(p); - assert(p->ref >= 1); - - if (--p->ref == 0) { - if (p->type == PA_PACKET_DYNAMIC) - pa_xfree(p->data); - pa_xfree(p); - } -} diff --git a/src/polypcore/packet.h b/src/polypcore/packet.h deleted file mode 100644 index fbc58232..00000000 --- a/src/polypcore/packet.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef foopackethfoo -#define foopackethfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -typedef struct pa_packet { - enum { PA_PACKET_APPENDED, PA_PACKET_DYNAMIC } type; - unsigned ref; - size_t length; - uint8_t *data; -} pa_packet; - -pa_packet* pa_packet_new(size_t length); -pa_packet* pa_packet_new_dynamic(void* data, size_t length); - -pa_packet* pa_packet_ref(pa_packet *p); -void pa_packet_unref(pa_packet *p); - -#endif diff --git a/src/polypcore/parseaddr.c b/src/polypcore/parseaddr.c deleted file mode 100644 index d0687b05..00000000 --- a/src/polypcore/parseaddr.c +++ /dev/null @@ -1,115 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include - -#include -#include - -#include "parseaddr.h" - -/* Parse addresses in one of the following forms: - * HOSTNAME - * HOSTNAME:PORT - * [HOSTNAME] - * [HOSTNAME]:PORT - * - * Return a newly allocated string of the hostname and fill in *ret_port if specified */ - -static char *parse_host(const char *s, uint16_t *ret_port) { - assert(s && ret_port); - if (*s == '[') { - char *e; - if (!(e = strchr(s+1, ']'))) - return NULL; - - if (e[1] == ':') - *ret_port = atoi(e+2); - else if (e[1] != 0) - return NULL; - - return pa_xstrndup(s+1, e-s-1); - } else { - char *e; - - if (!(e = strrchr(s, ':'))) - return pa_xstrdup(s); - - *ret_port = atoi(e+1); - return pa_xstrndup(s, e-s); - } -} - -int pa_parse_address(const char *name, pa_parsed_address *ret_p) { - const char *p; - assert(name && ret_p); - memset(ret_p, 0, sizeof(pa_parsed_address)); - ret_p->type = PA_PARSED_ADDRESS_TCP_AUTO; - - if (*name == '{') { - char hn[256], *pfx; - /* The URL starts with a host specification for detecting local connections */ - - if (!pa_get_host_name(hn, sizeof(hn))) - return -1; - - pfx = pa_sprintf_malloc("{%s}", hn); - if (!pa_startswith(name, pfx)) { - pa_xfree(pfx); - /* Not local */ - return -1; - } - - p = name + strlen(pfx); - pa_xfree(pfx); - } else - p = name; - - if (*p == '/') - ret_p->type = PA_PARSED_ADDRESS_UNIX; - else if (pa_startswith(p, "unix:")) { - ret_p->type = PA_PARSED_ADDRESS_UNIX; - p += sizeof("unix:")-1; - } else if (pa_startswith(p, "tcp:") || pa_startswith(p, "tcp4:")) { - ret_p->type = PA_PARSED_ADDRESS_TCP4; - p += sizeof("tcp:")-1; - } else if (pa_startswith(p, "tcp6:")) { - ret_p->type = PA_PARSED_ADDRESS_TCP6; - p += sizeof("tcp6:")-1; - } - - if (ret_p->type == PA_PARSED_ADDRESS_UNIX) - ret_p->path_or_host = pa_xstrdup(p); - else - if (!(ret_p->path_or_host = parse_host(p, &ret_p->port))) - return -1; - - - return 0; -} diff --git a/src/polypcore/parseaddr.h b/src/polypcore/parseaddr.h deleted file mode 100644 index eff9dd3b..00000000 --- a/src/polypcore/parseaddr.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef fooparseaddrhfoo -#define fooparseaddrhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -typedef enum pa_parsed_address_type { - PA_PARSED_ADDRESS_UNIX, - PA_PARSED_ADDRESS_TCP4, - PA_PARSED_ADDRESS_TCP6, - PA_PARSED_ADDRESS_TCP_AUTO -} pa_parsed_address_type_t; - -typedef struct pa_parsed_address { - pa_parsed_address_type_t type; - char *path_or_host; - uint16_t port; -} pa_parsed_address; - -int pa_parse_address(const char *a, pa_parsed_address *ret_p); - -#endif diff --git a/src/polypcore/pdispatch.c b/src/polypcore/pdispatch.c deleted file mode 100644 index c6f90bac..00000000 --- a/src/polypcore/pdispatch.c +++ /dev/null @@ -1,318 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include "pdispatch.h" - -/*#define DEBUG_OPCODES */ - -#ifdef DEBUG_OPCODES - -static const char *command_names[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = "ERROR", - [PA_COMMAND_TIMEOUT] = "TIMEOUT", - [PA_COMMAND_REPLY] = "REPLY", - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = "CREATE_PLAYBACK_STREAM", - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = "DELETE_PLAYBACK_STREAM", - [PA_COMMAND_CREATE_RECORD_STREAM] = "CREATE_RECORD_STREAM", - [PA_COMMAND_DELETE_RECORD_STREAM] = "DELETE_RECORD_STREAM", - [PA_COMMAND_AUTH] = "AUTH", - [PA_COMMAND_REQUEST] = "REQUEST", - [PA_COMMAND_EXIT] = "EXIT", - [PA_COMMAND_SET_CLIENT_NAME] = "SET_CLIENT_NAME", - [PA_COMMAND_LOOKUP_SINK] = "LOOKUP_SINK", - [PA_COMMAND_LOOKUP_SOURCE] = "LOOKUP_SOURCE", - [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = "DRAIN_PLAYBACK_STREAM", - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = "PLAYBACK_STREAM_KILLED", - [PA_COMMAND_RECORD_STREAM_KILLED] = "RECORD_STREAM_KILLED", - [PA_COMMAND_STAT] = "STAT", - [PA_COMMAND_GET_PLAYBACK_LATENCY] = "PLAYBACK_LATENCY", - [PA_COMMAND_CREATE_UPLOAD_STREAM] = "CREATE_UPLOAD_STREAM", - [PA_COMMAND_DELETE_UPLOAD_STREAM] = "DELETE_UPLOAD_STREAM", - [PA_COMMAND_FINISH_UPLOAD_STREAM] = "FINISH_UPLOAD_STREAM", - [PA_COMMAND_PLAY_SAMPLE] = "PLAY_SAMPLE", - [PA_COMMAND_REMOVE_SAMPLE] = "REMOVE_SAMPLE", - [PA_COMMAND_GET_SERVER_INFO] = "GET_SERVER_INFO", - [PA_COMMAND_GET_SINK_INFO] = "GET_SINK_INFO", - [PA_COMMAND_GET_SINK_INFO_LIST] = "GET_SINK_INFO_LIST", - [PA_COMMAND_GET_SOURCE_INFO] = "GET_SOURCE_INFO", - [PA_COMMAND_GET_SOURCE_INFO_LIST] = "GET_SOURCE_INFO_LIST", - [PA_COMMAND_GET_MODULE_INFO] = "GET_MODULE_INFO", - [PA_COMMAND_GET_MODULE_INFO_LIST] = "GET_MODULE_INFO_LIST", - [PA_COMMAND_GET_CLIENT_INFO] = "GET_CLIENT_INFO", - [PA_COMMAND_GET_CLIENT_INFO_LIST] = "GET_CLIENT_INFO_LIST", - [PA_COMMAND_GET_SAMPLE_INFO] = "GET_SAMPLE_INFO", - [PA_COMMAND_GET_SAMPLE_INFO_LIST] = "GET_SAMPLE_INFO_LIST", - [PA_COMMAND_GET_SINK_INPUT_INFO] = "GET_SINK_INPUT_INFO", - [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = "GET_SINK_INPUT_INFO_LIST", - [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = "GET_SOURCE_OUTPUT_INFO", - [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = "GET_SOURCE_OUTPUT_INFO_LIST", - [PA_COMMAND_SUBSCRIBE] = "SUBSCRIBE", - [PA_COMMAND_SUBSCRIBE_EVENT] = "SUBSCRIBE_EVENT", - [PA_COMMAND_SET_SINK_VOLUME] = "SET_SINK_VOLUME", - [PA_COMMAND_SET_SINK_INPUT_VOLUME] = "SET_SINK_INPUT_VOLUME", - [PA_COMMAND_SET_SOURCE_VOLUME] = "SET_SOURCE_VOLME", - [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = "TRIGGER_PLAYBACK_STREAM", - [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = "FLUSH_PLAYBACK_STREAM", - [PA_COMMAND_CORK_PLAYBACK_STREAM] = "CORK_PLAYBACK_STREAM", - [PA_COMMAND_GET_AUTOLOAD_INFO] = "GET_AUTOLOAD_INFO", - [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = "GET_AUTOLOAD_INFO_LIST", -}; - -#endif - -struct reply_info { - pa_pdispatch *pdispatch; - PA_LLIST_FIELDS(struct reply_info); - pa_pdispatch_cb_t callback; - void *userdata; - pa_free_cb_t free_cb; - uint32_t tag; - pa_time_event *time_event; -}; - -struct pa_pdispatch { - int ref; - pa_mainloop_api *mainloop; - const pa_pdispatch_cb_t *callback_table; - unsigned n_commands; - PA_LLIST_HEAD(struct reply_info, replies); - pa_pdispatch_drain_callback drain_callback; - void *drain_userdata; - const void *creds; -}; - -static void reply_info_free(struct reply_info *r) { - assert(r && r->pdispatch && r->pdispatch->mainloop); - - if (r->time_event) - r->pdispatch->mainloop->time_free(r->time_event); - - PA_LLIST_REMOVE(struct reply_info, r->pdispatch->replies, r); - - pa_xfree(r); -} - -pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_cb_t*table, unsigned entries) { - pa_pdispatch *pd; - assert(mainloop); - - assert((entries && table) || (!entries && !table)); - - pd = pa_xmalloc(sizeof(pa_pdispatch)); - pd->ref = 1; - pd->mainloop = mainloop; - pd->callback_table = table; - pd->n_commands = entries; - PA_LLIST_HEAD_INIT(pa_reply_info, pd->replies); - pd->drain_callback = NULL; - pd->drain_userdata = NULL; - pd->creds = NULL; - - return pd; -} - -static void pdispatch_free(pa_pdispatch *pd) { - assert(pd); - - while (pd->replies) { - if (pd->replies->free_cb) - pd->replies->free_cb(pd->replies->userdata); - - reply_info_free(pd->replies); - } - - pa_xfree(pd); -} - -static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command, pa_tagstruct *ts) { - pa_pdispatch_cb_t callback; - void *userdata; - uint32_t tag; - assert(r); - - pa_pdispatch_ref(pd); - - callback = r->callback; - userdata = r->userdata; - tag = r->tag; - - reply_info_free(r); - - callback(pd, command, tag, ts, userdata); - - if (pd->drain_callback && !pa_pdispatch_is_pending(pd)) - pd->drain_callback(pd, pd->drain_userdata); - - pa_pdispatch_unref(pd); -} - -int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const void *creds, void *userdata) { - uint32_t tag, command; - pa_tagstruct *ts = NULL; - int ret = -1; - assert(pd && packet && packet->data); - - pa_pdispatch_ref(pd); - - if (packet->length <= 8) - goto finish; - - ts = pa_tagstruct_new(packet->data, packet->length); - assert(ts); - - if (pa_tagstruct_getu32(ts, &command) < 0 || - pa_tagstruct_getu32(ts, &tag) < 0) - goto finish; - -#ifdef DEBUG_OPCODES -{ - char t[256]; - char const *p; - if (!(p = command_names[command])) - snprintf((char*) (p = t), sizeof(t), "%u", command); - - pa_log(__FILE__": Recieved opcode <%s>", p); -} -#endif - - pd->creds = creds; - - if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) { - struct reply_info *r; - - for (r = pd->replies; r; r = r->next) - if (r->tag == tag) - break; - - if (r) - run_action(pd, r, command, ts); - - } else if (pd->callback_table && (command < pd->n_commands) && pd->callback_table[command]) { - const pa_pdispatch_cb_t *c = pd->callback_table+command; - - (*c)(pd, command, tag, ts, userdata); - } else { - pa_log(__FILE__": Recieved unsupported command %u", command); - goto finish; - } - - ret = 0; - -finish: - pd->creds = NULL; - - if (ts) - pa_tagstruct_free(ts); - - pa_pdispatch_unref(pd); - - return ret; -} - -static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - struct reply_info*r = userdata; - assert(r && r->time_event == e && r->pdispatch && r->pdispatch->mainloop == m && r->callback); - - run_action(r->pdispatch, r, PA_COMMAND_TIMEOUT, NULL); -} - -void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t cb, void *userdata, pa_free_cb_t free_cb) { - struct reply_info *r; - struct timeval tv; - assert(pd && pd->ref >= 1 && cb); - - r = pa_xmalloc(sizeof(struct reply_info)); - r->pdispatch = pd; - r->callback = cb; - r->userdata = userdata; - r->free_cb = free_cb; - r->tag = tag; - - pa_gettimeofday(&tv); - tv.tv_sec += timeout; - - r->time_event = pd->mainloop->time_new(pd->mainloop, &tv, timeout_callback, r); - assert(r->time_event); - - PA_LLIST_PREPEND(struct reply_info, pd->replies, r); -} - -int pa_pdispatch_is_pending(pa_pdispatch *pd) { - assert(pd); - - return !!pd->replies; -} - -void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, void (*cb)(pa_pdispatch *pd, void *userdata), void *userdata) { - assert(pd); - assert(!cb || pa_pdispatch_is_pending(pd)); - - pd->drain_callback = cb; - pd->drain_userdata = userdata; -} - -void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata) { - struct reply_info *r, *n; - assert(pd); - - for (r = pd->replies; r; r = n) { - n = r->next; - - if (r->userdata == userdata) - reply_info_free(r); - } -} - -void pa_pdispatch_unref(pa_pdispatch *pd) { - assert(pd && pd->ref >= 1); - - if (!(--(pd->ref))) - pdispatch_free(pd); -} - -pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd) { - assert(pd && pd->ref >= 1); - pd->ref++; - return pd; -} - -const void * pa_pdispatch_creds(pa_pdispatch *pd) { - assert(pd); - assert(pd->ref >= 1); - - return pd->creds; -} diff --git a/src/polypcore/pdispatch.h b/src/polypcore/pdispatch.h deleted file mode 100644 index 0074e8b3..00000000 --- a/src/polypcore/pdispatch.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef foopdispatchhfoo -#define foopdispatchhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include -#include - -typedef struct pa_pdispatch pa_pdispatch; - -typedef void (*pa_pdispatch_cb_t)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -typedef void (*pa_pdispatch_drain_callback)(pa_pdispatch *pd, void *userdata); - -pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *m, const pa_pdispatch_cb_t*table, unsigned entries); -void pa_pdispatch_unref(pa_pdispatch *pd); -pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd); - -int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*p, const void*creds, void *userdata); - -void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t callback, void *userdata, pa_free_cb_t free_cb); - -int pa_pdispatch_is_pending(pa_pdispatch *pd); - -void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, pa_pdispatch_drain_callback callback, void *userdata); - -/* Remove all reply slots with the give userdata parameter */ -void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata); - -const void * pa_pdispatch_creds(pa_pdispatch *pd); - -#endif diff --git a/src/polypcore/pid.c b/src/polypcore/pid.c deleted file mode 100644 index a5c0ef0b..00000000 --- a/src/polypcore/pid.c +++ /dev/null @@ -1,304 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_WINDOWS_H -#include -#endif - -#include - -#include -#include -#include - -#include "pid.h" - -/* Read the PID data from the file descriptor fd, and return it. If no - * pid could be read, return 0, on failure (pid_t) -1 */ -static pid_t read_pid(const char *fn, int fd) { - ssize_t r; - char t[20], *e; - uint32_t pid; - - assert(fn && fd >= 0); - - if ((r = pa_loop_read(fd, t, sizeof(t)-1)) < 0) { - pa_log_warn(__FILE__": WARNING: failed to read PID file '%s': %s", - fn, pa_cstrerror(errno)); - return (pid_t) -1; - } - - if (r == 0) - return (pid_t) 0; - - t[r] = 0; - if ((e = strchr(t, '\n'))) - *e = 0; - - if (pa_atou(t, &pid) < 0) { - pa_log(__FILE__": WARNING: failed to parse PID file '%s'", fn); - return (pid_t) -1; - } - - return (pid_t) pid; -} - -static int open_pid_file(const char *fn, int mode) { - int fd = -1; - int lock = -1; - - for (;;) { - struct stat st; - - pa_make_secure_parent_dir(fn); - - if ((fd = open(fn, mode, S_IRUSR|S_IWUSR)) < 0) { - if (mode != O_RDONLY || errno != ENOENT) - pa_log_warn(__FILE__": WARNING: failed to open PID file '%s': %s", - fn, pa_cstrerror(errno)); - goto fail; - } - - /* Try to lock the file. If that fails, go without */ - if (pa_lock_fd(fd, 1) < 0) - goto fail; - - if (fstat(fd, &st) < 0) { - pa_log_warn(__FILE__": WARNING: failed to fstat() PID file '%s': %s", - fn, pa_cstrerror(errno)); - goto fail; - } - - /* Does the file still exist in the file system? When ye, w're done, otherwise restart */ - if (st.st_nlink >= 1) - break; - - if (pa_lock_fd(fd, 0) < 0) - goto fail; - - if (close(fd) < 0) { - pa_log_warn(__FILE__": WARNING: failed to close file '%s': %s", - fn, pa_cstrerror(errno)); - goto fail; - } - - fd = -1; - } - - return fd; - -fail: - - if (fd < 0) { - if (lock >= 0) - pa_lock_fd(fd, 0); - - close(fd); - } - - return -1; -} - -/* Create a new PID file for the current process. */ -int pa_pid_file_create(void) { - int fd = -1; - int ret = -1; - char fn[PATH_MAX]; - char t[20]; - pid_t pid; - size_t l; - -#ifdef OS_IS_WIN32 - HANDLE process; -#endif - - pa_runtime_path("pid", fn, sizeof(fn)); - - if ((fd = open_pid_file(fn, O_CREAT|O_RDWR)) < 0) - goto fail; - - if ((pid = read_pid(fn, fd)) == (pid_t) -1) - pa_log(__FILE__": corrupt PID file, overwriting."); - else if (pid > 0) { -#ifdef OS_IS_WIN32 - if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)) != NULL) { - CloseHandle(process); -#else - if (kill(pid, 0) >= 0 || errno != ESRCH) { -#endif - pa_log(__FILE__": daemon already running."); - goto fail; - } - - pa_log(__FILE__": stale PID file, overwriting."); - } - - /* Overwrite the current PID file */ - if (lseek(fd, 0, SEEK_SET) == (off_t) -1 || ftruncate(fd, 0) < 0) { - pa_log(__FILE__": failed to truncate PID file '%s': %s", - fn, pa_cstrerror(errno)); - goto fail; - } - - snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid()); - l = strlen(t); - - if (pa_loop_write(fd, t, l) != (ssize_t) l) { - pa_log(__FILE__": failed to write PID file."); - goto fail; - } - - ret = 0; - -fail: - if (fd >= 0) { - pa_lock_fd(fd, 0); - close(fd); - } - - return ret; -} - -/* Remove the PID file, if it is ours */ -int pa_pid_file_remove(void) { - int fd = -1; - char fn[PATH_MAX]; - int ret = -1; - pid_t pid; - char *p; - - pa_runtime_path("pid", fn, sizeof(fn)); - - if ((fd = open_pid_file(fn, O_RDWR)) < 0) { - pa_log_warn(__FILE__": WARNING: failed to open PID file '%s': %s", - fn, pa_cstrerror(errno)); - goto fail; - } - - if ((pid = read_pid(fn, fd)) == (pid_t) -1) - goto fail; - - if (pid != getpid()) { - pa_log(__FILE__": WARNING: PID file '%s' not mine!", fn); - goto fail; - } - - if (ftruncate(fd, 0) < 0) { - pa_log_warn(__FILE__": WARNING: failed to truncate PID file '%s': %s", - fn, pa_cstrerror(errno)); - goto fail; - } - -#ifdef OS_IS_WIN32 - pa_lock_fd(fd, 0); - close(fd); - fd = -1; -#endif - - if (unlink(fn) < 0) { - pa_log_warn(__FILE__": WARNING: failed to remove PID file '%s': %s", - fn, pa_cstrerror(errno)); - goto fail; - } - - if ((p = pa_parent_dir(fn))) { - rmdir(p); - pa_xfree(p); - } - - ret = 0; - -fail: - - if (fd >= 0) { - pa_lock_fd(fd, 0); - close(fd); - } - - return ret; -} - -/* Check whether the daemon is currently running, i.e. if a PID file - * exists and the PID therein too. Returns 0 on succcess, -1 - * otherwise. If pid is non-NULL and a running daemon was found, - * return its PID therein */ -int pa_pid_file_check_running(pid_t *pid) { - return pa_pid_file_kill(0, pid); -} - -#ifndef OS_IS_WIN32 - -/* Kill a current running daemon. Return non-zero on success, -1 - * otherwise. If successful *pid contains the PID of the daemon - * process. */ -int pa_pid_file_kill(int sig, pid_t *pid) { - int fd = -1; - char fn[PATH_MAX]; - int ret = -1; - pid_t _pid; - - if (!pid) - pid = &_pid; - - pa_runtime_path("pid", fn, sizeof(fn)); - - if ((fd = open_pid_file(fn, O_RDONLY)) < 0) - goto fail; - - if ((*pid = read_pid(fn, fd)) == (pid_t) -1) - goto fail; - - ret = kill(*pid, sig); - -fail: - - if (fd >= 0) { - pa_lock_fd(fd, 0); - close(fd); - } - - return ret; - -} - -#else /* OS_IS_WIN32 */ - -int pa_pid_file_kill(int sig, pid_t *pid) { - return -1; -} - -#endif diff --git a/src/polypcore/pid.h b/src/polypcore/pid.h deleted file mode 100644 index 906ab6da..00000000 --- a/src/polypcore/pid.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef foopidhfoo -#define foopidhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -int pa_pid_file_create(void); -int pa_pid_file_remove(void); -int pa_pid_file_check_running(pid_t *pid); -int pa_pid_file_kill(int sig, pid_t *pid); - -#endif diff --git a/src/polypcore/pipe.c b/src/polypcore/pipe.c deleted file mode 100644 index eef6d533..00000000 --- a/src/polypcore/pipe.c +++ /dev/null @@ -1,160 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with polypaudio; If not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#include "winsock.h" - -#include "pipe.h" - -#ifndef HAVE_PIPE - -static int set_block(int fd, int blocking) { -#ifdef O_NONBLOCK - - int v; - - assert(fd >= 0); - - if ((v = fcntl(fd, F_GETFL)) < 0) - return -1; - - if (blocking) - v &= ~O_NONBLOCK; - else - v |= O_NONBLOCK; - - if (fcntl(fd, F_SETFL, v) < 0) - return -1; - - return 0; - -#elif defined(OS_IS_WIN32) - - u_long arg; - - arg = !blocking; - - if (ioctlsocket(fd, FIONBIO, &arg) < 0) - return -1; - - return 0; - -#else - - return -1; - -#endif -} - -int pipe(int filedes[2]) { - int listener; - struct sockaddr_in addr, peer; - socklen_t len; - - listener = -1; - filedes[0] = -1; - filedes[1] = -1; - - listener = socket(PF_INET, SOCK_STREAM, 0); - if (listener < 0) - goto error; - - filedes[0] = socket(PF_INET, SOCK_STREAM, 0); - if (filedes[0] < 0) - goto error; - - filedes[1] = socket(PF_INET, SOCK_STREAM, 0); - if (filedes[1] < 0) - goto error; - - /* Make non-blocking so that connect() won't block */ - if (set_block(filedes[0], 0) < 0) - goto error; - - addr.sin_family = AF_INET; - addr.sin_port = 0; - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - - if (bind(listener, (struct sockaddr*)&addr, sizeof(addr)) < 0) - goto error; - - if (listen(listener, 1) < 0) - goto error; - - len = sizeof(addr); - if (getsockname(listener, (struct sockaddr*)&addr, &len) < 0) - goto error; - - if (connect(filedes[0], (struct sockaddr*)&addr, sizeof(addr)) < 0) { -#ifdef OS_IS_WIN32 - if (WSAGetLastError() != EWOULDBLOCK) -#else - if (errno != EINPROGRESS) -#endif - goto error; - } - - len = sizeof(peer); - filedes[1] = accept(listener, (struct sockaddr*)&peer, &len); - if (filedes[1] < 0) - goto error; - - /* Restore blocking */ - if (set_block(filedes[0], 1) < 0) - goto error; - - len = sizeof(addr); - if (getsockname(filedes[0], (struct sockaddr*)&addr, &len) < 0) - goto error; - - /* Check that someone else didn't steal the connection */ - if ((addr.sin_port != peer.sin_port) || (addr.sin_addr.s_addr != peer.sin_addr.s_addr)) - goto error; - - close(listener); - - return 0; - -error: - if (listener >= 0) - close(listener); - if (filedes[0] >= 0) - close(filedes[0]); - if (filedes[1] >= 0) - close(filedes[0]); - - return -1; -} - -#endif /* HAVE_PIPE */ diff --git a/src/polypcore/pipe.h b/src/polypcore/pipe.h deleted file mode 100644 index 276b072d..00000000 --- a/src/polypcore/pipe.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef foopipehfoo -#define foopipehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with polypaudio; If not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. -***/ - -#ifndef HAVE_PIPE - -int pipe(int filedes[2]); - -#endif - -#endif diff --git a/src/polypcore/play-memchunk.c b/src/polypcore/play-memchunk.c deleted file mode 100644 index 982cedc7..00000000 --- a/src/polypcore/play-memchunk.c +++ /dev/null @@ -1,117 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -#include -#include - -#include "play-memchunk.h" - -static void sink_input_kill(pa_sink_input *i) { - pa_memchunk *c; - assert(i && i->userdata); - c = i->userdata; - - pa_sink_input_disconnect(i); - pa_sink_input_unref(i); - - pa_memblock_unref(c->memblock); - pa_xfree(c); -} - -static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { - pa_memchunk *c; - assert(i && chunk && i->userdata); - c = i->userdata; - - if (c->length <= 0) - return -1; - - assert(c->memblock && c->memblock->length); - *chunk = *c; - pa_memblock_ref(c->memblock); - - return 0; -} - -static void si_kill(PA_GCC_UNUSED pa_mainloop_api *m, void *i) { - sink_input_kill(i); -} - -static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) { - pa_memchunk *c; - assert(i && length && i->userdata); - c = i->userdata; - - assert(!memcmp(chunk, c, sizeof(chunk))); - assert(length <= c->length); - - c->length -= length; - c->index += length; - - if (c->length <= 0) - pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i); -} - -int pa_play_memchunk( - pa_sink *sink, - const char *name, - const pa_sample_spec *ss, - const pa_channel_map *map, - const pa_memchunk *chunk, - pa_cvolume *cvolume) { - - pa_sink_input *si; - pa_memchunk *nchunk; - - assert(sink); - assert(ss); - assert(chunk); - - if (cvolume && pa_cvolume_is_muted(cvolume)) - return 0; - - if (!(si = pa_sink_input_new(sink, name, __FILE__, ss, map, cvolume, 0, PA_RESAMPLER_INVALID))) - return -1; - - si->peek = sink_input_peek; - si->drop = sink_input_drop; - si->kill = sink_input_kill; - - si->userdata = nchunk = pa_xnew(pa_memchunk, 1); - *nchunk = *chunk; - - pa_memblock_ref(chunk->memblock); - - pa_sink_notify(sink); - - return 0; -} diff --git a/src/polypcore/play-memchunk.h b/src/polypcore/play-memchunk.h deleted file mode 100644 index 72aeda95..00000000 --- a/src/polypcore/play-memchunk.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef fooplaychunkhfoo -#define fooplaychunkhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -int pa_play_memchunk( - pa_sink *sink, - const char *name, - const pa_sample_spec *ss, - const pa_channel_map *map, - const pa_memchunk *chunk, - pa_cvolume *cvolume); - -#endif diff --git a/src/polypcore/poll.c b/src/polypcore/poll.c deleted file mode 100644 index 7b1ed438..00000000 --- a/src/polypcore/poll.c +++ /dev/null @@ -1,191 +0,0 @@ -/* $Id$ */ - -/*** - Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc. - Copyright (C) 2005, Cendio AB. - This file is part of polypaudio. - Based on work for the GNU C Library. - - polypaudio is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with polypaudio; If not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. -***/ - -/* Poll the file descriptors described by the NFDS structures starting at - FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for - an event to occur; if TIMEOUT is -1, block until an event occurs. - Returns the number of file descriptors with events, zero if timed out, - or -1 for errors. */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#ifdef HAVE_SYS_SELECT_H -#include -#endif - -#include "winsock.h" - -#ifndef HAVE_SYS_POLL_H - -#include - -#include "poll.h" - -int poll (struct pollfd *fds, unsigned long int nfds, int timeout) { - struct timeval tv; - fd_set rset, wset, xset; - struct pollfd *f; - int ready; - int maxfd = 0; - char data[64]; - - FD_ZERO (&rset); - FD_ZERO (&wset); - FD_ZERO (&xset); - - if (nfds == 0) { - if (timeout >= 0) { - pa_msleep(timeout); - return 0; - } - -#ifdef OS_IS_WIN32 - /* - * Windows does not support signals properly so waiting for them would - * mean a deadlock. - */ - pa_msleep(100); - return 0; -#else - return select(0, NULL, NULL, NULL, NULL); -#endif - } - - for (f = fds; f < &fds[nfds]; ++f) { - if (f->fd != -1) { - if (f->events & POLLIN) - FD_SET (f->fd, &rset); - if (f->events & POLLOUT) - FD_SET (f->fd, &wset); - if (f->events & POLLPRI) - FD_SET (f->fd, &xset); - if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI))) - maxfd = f->fd; - } - } - - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - - ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset, - SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset, - SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv)); - if ((ready == -1) && (errno == EBADF)) { - ready = 0; - - FD_ZERO (&rset); - FD_ZERO (&wset); - FD_ZERO (&xset); - - maxfd = -1; - - for (f = fds; f < &fds[nfds]; ++f) { - if (f->fd != -1) { - fd_set sngl_rset, sngl_wset, sngl_xset; - - FD_ZERO (&sngl_rset); - FD_ZERO (&sngl_wset); - FD_ZERO (&sngl_xset); - - if (f->events & POLLIN) - FD_SET (f->fd, &sngl_rset); - if (f->events & POLLOUT) - FD_SET (f->fd, &sngl_wset); - if (f->events & POLLPRI) - FD_SET (f->fd, &sngl_xset); - if (f->events & (POLLIN|POLLOUT|POLLPRI)) { - struct timeval singl_tv; - - singl_tv.tv_sec = 0; - singl_tv.tv_usec = 0; - - if (select((SELECT_TYPE_ARG1) f->fd, SELECT_TYPE_ARG234 &rset, - SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset, - SELECT_TYPE_ARG5 &singl_tv) != -1) { - if (f->events & POLLIN) - FD_SET (f->fd, &rset); - if (f->events & POLLOUT) - FD_SET (f->fd, &wset); - if (f->events & POLLPRI) - FD_SET (f->fd, &xset); - if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI))) - maxfd = f->fd; - ++ready; - } else if (errno == EBADF) - f->revents |= POLLNVAL; - } - } - } - - if (ready) { - /* Linux alters the tv struct... but it shouldn't matter here ... - * as we're going to be a little bit out anyway as we've just eaten - * more than a couple of cpu cycles above */ - ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset, - SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset, - SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv)); - } - } - -#ifdef OS_IS_WIN32 - errno = WSAGetLastError(); -#endif - - if (ready > 0) { - ready = 0; - for (f = fds; f < &fds[nfds]; ++f) { - f->revents = 0; - if (f->fd != -1) { - if (FD_ISSET (f->fd, &rset)) { - /* support for POLLHUP. An hung up descriptor does not - increase the return value! */ - if (recv (f->fd, data, 64, MSG_PEEK) == -1) { - if (errno == ESHUTDOWN || errno == ECONNRESET || - errno == ECONNABORTED || errno == ENETRESET) { - fprintf(stderr, "Hangup\n"); - f->revents |= POLLHUP; - } - } - - if (f->revents == 0) - f->revents |= POLLIN; - } - if (FD_ISSET (f->fd, &wset)) - f->revents |= POLLOUT; - if (FD_ISSET (f->fd, &xset)) - f->revents |= POLLPRI; - } - if (f->revents) - ready++; - } - } - - return ready; -} - -#endif /* HAVE_SYS_POLL_H */ diff --git a/src/polypcore/poll.h b/src/polypcore/poll.h deleted file mode 100644 index c201014e..00000000 --- a/src/polypcore/poll.h +++ /dev/null @@ -1,57 +0,0 @@ -/* $Id$ */ - -/*** - Compatibility definitions for System V `poll' interface. - Copyright (C) 1994,96,97,98,99,2000,2001,2004 Free Software Foundation, Inc. - Copyright (C) 2005, Cendio AB. - This file is part of polypaudio. - Based on work for the GNU C Library. - - polypaudio is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with polypaudio; If not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. -***/ - -/* Event types that can be polled for. These bits may be set in `events' - to indicate the interesting event types; they will appear in `revents' - to indicate the status of the file descriptor. */ -#define POLLIN 0x001 /* There is data to read. */ -#define POLLPRI 0x002 /* There is urgent data to read. */ -#define POLLOUT 0x004 /* Writing now will not block. */ - -/* Event types always implicitly polled for. These bits need not be set in - `events', but they will appear in `revents' to indicate the status of - the file descriptor. */ -#define POLLERR 0x008 /* Error condition. */ -#define POLLHUP 0x010 /* Hung up. */ -#define POLLNVAL 0x020 /* Invalid polling request. */ - - -/* Type used for the number of file descriptors. */ -typedef unsigned long int nfds_t; - -/* Data structure describing a polling request. */ -struct pollfd - { - int fd; /* File descriptor to poll. */ - short int events; /* Types of events poller cares about. */ - short int revents; /* Types of events that actually occurred. */ - }; - -/* Poll the file descriptors described by the NFDS structures starting at - FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for - an event to occur; if TIMEOUT is -1, block until an event occurs. - Returns the number of file descriptors with events, zero if timed out, - or -1 for errors. */ -extern int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout); diff --git a/src/polypcore/props.c b/src/polypcore/props.c deleted file mode 100644 index 1db44ee7..00000000 --- a/src/polypcore/props.c +++ /dev/null @@ -1,121 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include - -#include - -#include "props.h" - -typedef struct pa_property { - char *name; /* Points to memory allocated by the property subsystem */ - void *data; /* Points to memory maintained by the caller */ -} pa_property; - -/* Allocate a new property object */ -static pa_property* property_new(const char *name, void *data) { - pa_property* p; - assert(name && data); - - p = pa_xmalloc(sizeof(pa_property)); - p->name = pa_xstrdup(name); - p->data = data; - - return p; -} - -/* Free a property object */ -static void property_free(pa_property *p) { - assert(p); - - pa_xfree(p->name); - pa_xfree(p); -} - -void* pa_property_get(pa_core *c, const char *name) { - pa_property *p; - assert(c && name && c->properties); - - if (!(p = pa_hashmap_get(c->properties, name))) - return NULL; - - return p->data; -} - -int pa_property_set(pa_core *c, const char *name, void *data) { - pa_property *p; - assert(c && name && data && c->properties); - - if (pa_hashmap_get(c->properties, name)) - return -1; - - p = property_new(name, data); - pa_hashmap_put(c->properties, p->name, p); - return 0; -} - -int pa_property_remove(pa_core *c, const char *name) { - pa_property *p; - assert(c && name && c->properties); - - if (!(p = pa_hashmap_remove(c->properties, name))) - return -1; - - property_free(p); - return 0; -} - -void pa_property_init(pa_core *c) { - assert(c); - - c->properties = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); -} - -void pa_property_cleanup(pa_core *c) { - assert(c); - - if (!c->properties) - return; - - assert(!pa_hashmap_size(c->properties)); - - pa_hashmap_free(c->properties, NULL, NULL); - c->properties = NULL; - -} - -void pa_property_dump(pa_core *c, pa_strbuf *s) { - void *state = NULL; - pa_property *p; - assert(c && s); - - while ((p = pa_hashmap_iterate(c->properties, &state, NULL))) - pa_strbuf_printf(s, "[%s] -> [%p]\n", p->name, p->data); -} - -int pa_property_replace(pa_core *c, const char *name, void *data) { - assert(c && name); - - pa_property_remove(c, name); - return pa_property_set(c, name, data); -} diff --git a/src/polypcore/props.h b/src/polypcore/props.h deleted file mode 100644 index 9430db5e..00000000 --- a/src/polypcore/props.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef foopropshfoo -#define foopropshfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -/* The property subsystem is to be used to share data between - * modules. Consider them to be kind of "global" variables for a - * core. Why not use the hashmap functions directly? The hashmap - * functions copy neither the key nor value, while this property - * system copies the key. Users of this system have to think about - * reference counting themselves. */ - -/* Return a pointer to the value of the specified property. */ -void* pa_property_get(pa_core *c, const char *name); - -/* Set the property 'name' to 'data'. This function fails in case a - * property by this name already exists. The property data is not - * copied or reference counted. This is the caller's job. */ -int pa_property_set(pa_core *c, const char *name, void *data); - -/* Remove the specified property. Return non-zero on failure */ -int pa_property_remove(pa_core *c, const char *name); - -/* A combination of pa_property_remove() and pa_property_set() */ -int pa_property_replace(pa_core *c, const char *name, void *data); - -/* Free all memory used by the property system */ -void pa_property_cleanup(pa_core *c); - -/* Initialize the properties subsystem */ -void pa_property_init(pa_core *c); - -/* Dump the current set of properties */ -void pa_property_dump(pa_core *c, pa_strbuf *s); - -#endif diff --git a/src/polypcore/protocol-cli.c b/src/polypcore/protocol-cli.c deleted file mode 100644 index 076411cf..00000000 --- a/src/polypcore/protocol-cli.c +++ /dev/null @@ -1,97 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include - -#include -#include - -#include "protocol-cli.h" - -/* Don't allow more than this many concurrent connections */ -#define MAX_CONNECTIONS 25 - -struct pa_protocol_cli { - pa_module *module; - pa_core *core; - pa_socket_server*server; - pa_idxset *connections; -}; - -static void cli_eof_cb(pa_cli*c, void*userdata) { - pa_protocol_cli *p = userdata; - assert(p); - pa_idxset_remove_by_data(p->connections, c, NULL); - pa_cli_free(c); -} - -static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { - pa_protocol_cli *p = userdata; - pa_cli *c; - assert(s && io && p); - - if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); - pa_iochannel_free(io); - return; - } - - c = pa_cli_new(p->core, io, p->module); - assert(c); - pa_cli_set_eof_callback(c, cli_eof_cb, p); - - pa_idxset_put(p->connections, c, NULL); -} - -pa_protocol_cli* pa_protocol_cli_new(pa_core *core, pa_socket_server *server, pa_module *m, PA_GCC_UNUSED pa_modargs *ma) { - pa_protocol_cli* p; - assert(core && server); - - p = pa_xmalloc(sizeof(pa_protocol_cli)); - p->module = m; - p->core = core; - p->server = server; - p->connections = pa_idxset_new(NULL, NULL); - - pa_socket_server_set_callback(p->server, on_connection, p); - - return p; -} - -static void free_connection(void *p, PA_GCC_UNUSED void *userdata) { - assert(p); - pa_cli_free(p); -} - -void pa_protocol_cli_free(pa_protocol_cli *p) { - assert(p); - - pa_idxset_free(p->connections, free_connection, NULL); - pa_socket_server_unref(p->server); - pa_xfree(p); -} diff --git a/src/polypcore/protocol-cli.h b/src/polypcore/protocol-cli.h deleted file mode 100644 index c47b14d6..00000000 --- a/src/polypcore/protocol-cli.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef fooprotocolclihfoo -#define fooprotocolclihfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include - -typedef struct pa_protocol_cli pa_protocol_cli; - -pa_protocol_cli* pa_protocol_cli_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma); -void pa_protocol_cli_free(pa_protocol_cli *n); - -#endif diff --git a/src/polypcore/protocol-esound.c b/src/polypcore/protocol-esound.c deleted file mode 100644 index c9bc504d..00000000 --- a/src/polypcore/protocol-esound.c +++ /dev/null @@ -1,1253 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "endianmacros.h" - -#include "protocol-esound.h" - -/* Don't accept more connection than this */ -#define MAX_CONNECTIONS 10 - -/* Kick a client if it doesn't authenticate within this time */ -#define AUTH_TIMEOUT 5 - -#define DEFAULT_COOKIE_FILE ".esd_auth" - -#define PLAYBACK_BUFFER_SECONDS (.25) -#define PLAYBACK_BUFFER_FRAGMENTS (10) -#define RECORD_BUFFER_SECONDS (5) -#define RECORD_BUFFER_FRAGMENTS (100) - -#define MAX_CACHE_SAMPLE_SIZE (1024000) - -#define SCACHE_PREFIX "esound." - -/* This is heavily based on esound's code */ - -struct connection { - uint32_t index; - int dead; - pa_protocol_esound *protocol; - pa_iochannel *io; - pa_client *client; - int authorized, swap_byte_order; - void *write_data; - size_t write_data_alloc, write_data_index, write_data_length; - void *read_data; - size_t read_data_alloc, read_data_length; - esd_proto_t request; - esd_client_state_t state; - pa_sink_input *sink_input; - pa_source_output *source_output; - pa_memblockq *input_memblockq, *output_memblockq; - pa_defer_event *defer_event; - - char *original_name; - - struct { - pa_memblock *current_memblock; - size_t memblock_index, fragment_size; - } playback; - - struct { - pa_memchunk memchunk; - char *name; - pa_sample_spec sample_spec; - } scache; - - pa_time_event *auth_timeout_event; -}; - -struct pa_protocol_esound { - int public; - pa_module *module; - pa_core *core; - pa_socket_server *server; - pa_idxset *connections; - char *sink_name, *source_name; - unsigned n_player; - uint8_t esd_key[ESD_KEY_LEN]; -}; - -typedef struct proto_handler { - size_t data_length; - int (*proc)(struct connection *c, esd_proto_t request, const void *data, size_t length); - const char *description; -} esd_proto_handler_info_t; - -static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length); -static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk); -static void sink_input_kill_cb(pa_sink_input *i); -static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i); -static pa_usec_t source_output_get_latency_cb(pa_source_output *o); - -static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk); -static void source_output_kill_cb(pa_source_output *o); - -static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_stream_play(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_get_latency(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_server_info(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_sample_get_id(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_standby_or_resume(struct connection *c, esd_proto_t request, const void *data, size_t length); - -/* the big map of protocol handler info */ -static struct proto_handler proto_map[ESD_PROTO_MAX] = { - { ESD_KEY_LEN + sizeof(int), esd_proto_connect, "connect" }, - { ESD_KEY_LEN + sizeof(int), NULL, "lock" }, - { ESD_KEY_LEN + sizeof(int), NULL, "unlock" }, - - { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_play, "stream play" }, - { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream rec" }, - { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream mon" }, - - { ESD_NAME_MAX + 3 * sizeof(int), esd_proto_sample_cache, "sample cache" }, /* 6 */ - { sizeof(int), esd_proto_sample_free_or_play, "sample free" }, - { sizeof(int), esd_proto_sample_free_or_play, "sample play" }, /* 8 */ - { sizeof(int), NULL, "sample loop" }, - { sizeof(int), NULL, "sample stop" }, - { -1, NULL, "TODO: sample kill" }, - - { ESD_KEY_LEN + sizeof(int), esd_proto_standby_or_resume, "standby" }, /* NOOP! */ - { ESD_KEY_LEN + sizeof(int), esd_proto_standby_or_resume, "resume" }, /* NOOP! */ /* 13 */ - - { ESD_NAME_MAX, esd_proto_sample_get_id, "sample getid" }, /* 14 */ - { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" }, - - { sizeof(int), esd_proto_server_info, "server info" }, - { sizeof(int), esd_proto_all_info, "all info" }, - { -1, NULL, "TODO: subscribe" }, - { -1, NULL, "TODO: unsubscribe" }, - - { 3 * sizeof(int), esd_proto_stream_pan, "stream pan"}, - { 3 * sizeof(int), NULL, "sample pan" }, - - { sizeof(int), NULL, "standby mode" }, - { 0, esd_proto_get_latency, "get latency" } -}; - -static void connection_free(struct connection *c) { - assert(c); - pa_idxset_remove_by_data(c->protocol->connections, c, NULL); - - if (c->state == ESD_STREAMING_DATA) - c->protocol->n_player--; - - pa_client_free(c->client); - - if (c->sink_input) { - pa_sink_input_disconnect(c->sink_input); - pa_sink_input_unref(c->sink_input); - } - - if (c->source_output) { - pa_source_output_disconnect(c->source_output); - pa_source_output_unref(c->source_output); - } - - if (c->input_memblockq) - pa_memblockq_free(c->input_memblockq); - if (c->output_memblockq) - pa_memblockq_free(c->output_memblockq); - - if (c->playback.current_memblock) - pa_memblock_unref(c->playback.current_memblock); - - pa_xfree(c->read_data); - pa_xfree(c->write_data); - - if (c->io) - pa_iochannel_free(c->io); - - if (c->defer_event) - c->protocol->core->mainloop->defer_free(c->defer_event); - - if (c->scache.memchunk.memblock) - pa_memblock_unref(c->scache.memchunk.memblock); - pa_xfree(c->scache.name); - - if (c->auth_timeout_event) - c->protocol->core->mainloop->time_free(c->auth_timeout_event); - - pa_xfree(c->original_name); - pa_xfree(c); -} - -static void connection_write_prepare(struct connection *c, size_t length) { - size_t t; - assert(c); - - t = c->write_data_length+length; - - if (c->write_data_alloc < t) - c->write_data = pa_xrealloc(c->write_data, c->write_data_alloc = t); - - assert(c->write_data); -} - -static void connection_write(struct connection *c, const void *data, size_t length) { - size_t i; - assert(c); - - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); - - connection_write_prepare(c, length); - - assert(c->write_data); - - i = c->write_data_length; - c->write_data_length += length; - - memcpy((char*)c->write_data + i, data, length); -} - -static void format_esd2native(int format, int swap_bytes, pa_sample_spec *ss) { - assert(ss); - - ss->channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; - if ((format & ESD_MASK_BITS) == ESD_BITS16) - ss->format = swap_bytes ? PA_SAMPLE_S16RE : PA_SAMPLE_S16NE; - else - ss->format = PA_SAMPLE_U8; -} - -static int format_native2esd(pa_sample_spec *ss) { - int format = 0; - - format = (ss->format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16; - format |= (ss->channels >= 2) ? ESD_STEREO : ESD_MONO; - - return format; -} - -#define CHECK_VALIDITY(expression, string) do { \ - if (!(expression)) { \ - pa_log_warn(__FILE__ ": " string); \ - return -1; \ - } \ -} while(0); - -/*** esound commands ***/ - -static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { - uint32_t ekey; - int ok; - - assert(length == (ESD_KEY_LEN + sizeof(uint32_t))); - - if (!c->authorized) { - if (memcmp(data, c->protocol->esd_key, ESD_KEY_LEN) != 0) { - pa_log(__FILE__": kicked client with invalid authorization key."); - return -1; - } - - c->authorized = 1; - if (c->auth_timeout_event) { - c->protocol->core->mainloop->time_free(c->auth_timeout_event); - c->auth_timeout_event = NULL; - } - } - - data = (const char*)data + ESD_KEY_LEN; - - memcpy(&ekey, data, sizeof(uint32_t)); - if (ekey == ESD_ENDIAN_KEY) - c->swap_byte_order = 0; - else if (ekey == ESD_SWAP_ENDIAN_KEY) - c->swap_byte_order = 1; - else { - pa_log(__FILE__": client sent invalid endian key"); - return -1; - } - - ok = 1; - connection_write(c, &ok, sizeof(int)); - return 0; -} - -static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { - char name[ESD_NAME_MAX], *utf8_name; - int32_t format, rate; - pa_sink *sink; - pa_sample_spec ss; - size_t l; - - assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); - - memcpy(&format, data, sizeof(int32_t)); - format = MAYBE_INT32_SWAP(c->swap_byte_order, format); - data = (const char*)data + sizeof(int32_t); - - memcpy(&rate, data, sizeof(int32_t)); - rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); - data = (const char*)data + sizeof(int32_t); - - ss.rate = rate; - format_esd2native(format, c->swap_byte_order, &ss); - - CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification"); - sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1); - CHECK_VALIDITY(sink, "No such sink"); - - strncpy(name, data, sizeof(name)); - name[sizeof(name)-1] = 0; - utf8_name = pa_utf8_filter(name); - - pa_client_set_name(c->client, utf8_name); - c->original_name = pa_xstrdup(name); - - assert(!c->sink_input && !c->input_memblockq); - - c->sink_input = pa_sink_input_new(sink, __FILE__, utf8_name, &ss, NULL, NULL, 0, -1); - - pa_xfree(utf8_name); - - CHECK_VALIDITY(c->sink_input, "Failed to create sink input."); - - l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); - c->input_memblockq = pa_memblockq_new( - 0, - l, - 0, - pa_frame_size(&ss), - (size_t) -1, - l/PLAYBACK_BUFFER_FRAGMENTS, - NULL, - c->protocol->core->memblock_stat); - pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2); - c->playback.fragment_size = l/10; - - c->sink_input->owner = c->protocol->module; - c->sink_input->client = c->client; - c->sink_input->peek = sink_input_peek_cb; - c->sink_input->drop = sink_input_drop_cb; - c->sink_input->kill = sink_input_kill_cb; - c->sink_input->get_latency = sink_input_get_latency_cb; - c->sink_input->userdata = c; - - c->state = ESD_STREAMING_DATA; - - c->protocol->n_player++; - - return 0; -} - -static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length) { - char name[ESD_NAME_MAX], *utf8_name; - int32_t format, rate; - pa_source *source; - pa_sample_spec ss; - size_t l; - - assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); - - memcpy(&format, data, sizeof(int32_t)); - format = MAYBE_INT32_SWAP(c->swap_byte_order, format); - data = (const char*)data + sizeof(int32_t); - - memcpy(&rate, data, sizeof(int32_t)); - rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); - data = (const char*)data + sizeof(int32_t); - - ss.rate = rate; - format_esd2native(format, c->swap_byte_order, &ss); - - CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification."); - - if (request == ESD_PROTO_STREAM_MON) { - pa_sink* sink; - - if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": no such sink."); - return -1; - } - - if (!(source = sink->monitor_source)) { - pa_log(__FILE__": no such monitor source."); - return -1; - } - } else { - assert(request == ESD_PROTO_STREAM_REC); - - if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) { - pa_log(__FILE__": no such source."); - return -1; - } - } - - strncpy(name, data, sizeof(name)); - name[sizeof(name)-1] = 0; - - utf8_name = pa_utf8_filter(name); - pa_client_set_name(c->client, utf8_name); - pa_xfree(utf8_name); - - c->original_name = pa_xstrdup(name); - - assert(!c->output_memblockq && !c->source_output); - - if (!(c->source_output = pa_source_output_new(source, __FILE__, c->client->name, &ss, NULL, -1))) { - pa_log(__FILE__": failed to create source output"); - return -1; - } - - l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); - c->output_memblockq = pa_memblockq_new( - 0, - l, - 0, - pa_frame_size(&ss), - 1, - 0, - NULL, - c->protocol->core->memblock_stat); - pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); - - c->source_output->owner = c->protocol->module; - c->source_output->client = c->client; - c->source_output->push = source_output_push_cb; - c->source_output->kill = source_output_kill_cb; - c->source_output->get_latency = source_output_get_latency_cb; - c->source_output->userdata = c; - - c->state = ESD_STREAMING_DATA; - - c->protocol->n_player++; - - return 0; -} - -static int esd_proto_get_latency(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { - pa_sink *sink; - int32_t latency; - - assert(c && !data && length == 0); - - if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) - latency = 0; - else { - double usec = pa_sink_get_latency(sink); - latency = (int) ((usec*44100)/1000000); - } - - latency = MAYBE_INT32_SWAP(c->swap_byte_order, latency); - connection_write(c, &latency, sizeof(int32_t)); - return 0; -} - -static int esd_proto_server_info(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { - int32_t rate = 44100, format = ESD_STEREO|ESD_BITS16; - int32_t response; - pa_sink *sink; - - assert(c && data && length == sizeof(int32_t)); - - if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { - rate = sink->sample_spec.rate; - format = format_native2esd(&sink->sample_spec); - } - - connection_write_prepare(c, sizeof(int32_t) * 3); - - response = 0; - connection_write(c, &response, sizeof(int32_t)); - rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); - connection_write(c, &rate, sizeof(int32_t)); - format = MAYBE_INT32_SWAP(c->swap_byte_order, format); - connection_write(c, &format, sizeof(int32_t)); - - return 0; -} - -static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length) { - size_t t, k, s; - struct connection *conn; - uint32_t idx = PA_IDXSET_INVALID; - unsigned nsamples; - char terminator[sizeof(int32_t)*6+ESD_NAME_MAX]; - - assert(c && data && length == sizeof(int32_t)); - - if (esd_proto_server_info(c, request, data, length) < 0) - return -1; - - k = sizeof(int32_t)*5+ESD_NAME_MAX; - s = sizeof(int32_t)*6+ESD_NAME_MAX; - nsamples = c->protocol->core->scache ? pa_idxset_size(c->protocol->core->scache) : 0; - t = s*(nsamples+1) + k*(c->protocol->n_player+1); - - connection_write_prepare(c, t); - - memset(terminator, 0, sizeof(terminator)); - - for (conn = pa_idxset_first(c->protocol->connections, &idx); conn; conn = pa_idxset_next(c->protocol->connections, &idx)) { - int32_t id, format = ESD_BITS16 | ESD_STEREO, rate = 44100, lvolume = ESD_VOLUME_BASE, rvolume = ESD_VOLUME_BASE; - char name[ESD_NAME_MAX]; - - if (conn->state != ESD_STREAMING_DATA) - continue; - - assert(t >= k*2+s); - - if (conn->sink_input) { - pa_cvolume volume = *pa_sink_input_get_volume(conn->sink_input); - rate = conn->sink_input->sample_spec.rate; - lvolume = (volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; - rvolume = (volume.values[1]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; - format = format_native2esd(&conn->sink_input->sample_spec); - } - - /* id */ - id = MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) (conn->index+1)); - connection_write(c, &id, sizeof(int32_t)); - - /* name */ - memset(name, 0, ESD_NAME_MAX); /* don't leak old data */ - if (conn->original_name) - strncpy(name, conn->original_name, ESD_NAME_MAX); - else if (conn->client && conn->client->name) - strncpy(name, conn->client->name, ESD_NAME_MAX); - connection_write(c, name, ESD_NAME_MAX); - - /* rate */ - rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); - connection_write(c, &rate, sizeof(int32_t)); - - /* left */ - lvolume = MAYBE_INT32_SWAP(c->swap_byte_order, lvolume); - connection_write(c, &lvolume, sizeof(int32_t)); - - /*right*/ - rvolume = MAYBE_INT32_SWAP(c->swap_byte_order, rvolume); - connection_write(c, &rvolume, sizeof(int32_t)); - - /*format*/ - format = MAYBE_INT32_SWAP(c->swap_byte_order, format); - connection_write(c, &format, sizeof(int32_t)); - - t -= k; - } - - assert(t == s*(nsamples+1)+k); - t -= k; - - connection_write(c, terminator, k); - - if (nsamples) { - pa_scache_entry *ce; - - idx = PA_IDXSET_INVALID; - for (ce = pa_idxset_first(c->protocol->core->scache, &idx); ce; ce = pa_idxset_next(c->protocol->core->scache, &idx)) { - int32_t id, rate, lvolume, rvolume, format, len; - char name[ESD_NAME_MAX]; - - assert(t >= s*2); - - /* id */ - id = MAYBE_INT32_SWAP(c->swap_byte_order, (int) (ce->index+1)); - connection_write(c, &id, sizeof(int32_t)); - - /* name */ - memset(name, 0, ESD_NAME_MAX); /* don't leak old data */ - if (strncmp(ce->name, SCACHE_PREFIX, sizeof(SCACHE_PREFIX)-1) == 0) - strncpy(name, ce->name+sizeof(SCACHE_PREFIX)-1, ESD_NAME_MAX); - else - snprintf(name, ESD_NAME_MAX, "native.%s", ce->name); - connection_write(c, name, ESD_NAME_MAX); - - /* rate */ - rate = MAYBE_UINT32_SWAP(c->swap_byte_order, ce->sample_spec.rate); - connection_write(c, &rate, sizeof(int32_t)); - - /* left */ - lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); - connection_write(c, &lvolume, sizeof(int32_t)); - - /*right*/ - rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); - connection_write(c, &rvolume, sizeof(int32_t)); - - /*format*/ - format = MAYBE_INT32_SWAP(c->swap_byte_order, format_native2esd(&ce->sample_spec)); - connection_write(c, &format, sizeof(int32_t)); - - /*length*/ - len = MAYBE_INT32_SWAP(c->swap_byte_order, (int) ce->memchunk.length); - connection_write(c, &len, sizeof(int32_t)); - - t -= s; - } - } - - assert(t == s); - - connection_write(c, terminator, s); - - return 0; -} - -static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { - int32_t ok; - uint32_t idx, lvolume, rvolume; - struct connection *conn; - - assert(c && data && length == sizeof(int32_t)*3); - - memcpy(&idx, data, sizeof(uint32_t)); - idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; - data = (const char*)data + sizeof(uint32_t); - - memcpy(&lvolume, data, sizeof(uint32_t)); - lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, lvolume); - data = (const char*)data + sizeof(uint32_t); - - memcpy(&rvolume, data, sizeof(uint32_t)); - rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, rvolume); - data = (const char*)data + sizeof(uint32_t); - - if ((conn = pa_idxset_get_by_index(c->protocol->connections, idx)) && conn->sink_input) { - pa_cvolume volume; - volume.values[0] = (lvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; - volume.values[1] = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; - volume.channels = 2; - pa_sink_input_set_volume(conn->sink_input, &volume); - ok = 1; - } else - ok = 0; - - connection_write(c, &ok, sizeof(int32_t)); - - return 0; -} - -static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { - pa_sample_spec ss; - int32_t format, rate, sc_length; - uint32_t idx; - char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; - - assert(c && data && length == (ESD_NAME_MAX+3*sizeof(int32_t))); - - memcpy(&format, data, sizeof(int32_t)); - format = MAYBE_INT32_SWAP(c->swap_byte_order, format); - data = (const char*)data + sizeof(int32_t); - - memcpy(&rate, data, sizeof(int32_t)); - rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); - data = (const char*)data + sizeof(int32_t); - - ss.rate = rate; - format_esd2native(format, c->swap_byte_order, &ss); - - CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification."); - - memcpy(&sc_length, data, sizeof(int32_t)); - sc_length = MAYBE_INT32_SWAP(c->swap_byte_order, sc_length); - data = (const char*)data + sizeof(int32_t); - - CHECK_VALIDITY(sc_length <= MAX_CACHE_SAMPLE_SIZE, "Sample too large."); - - strcpy(name, SCACHE_PREFIX); - strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX); - name[sizeof(name)-1] = 0; - - CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in sample name."); - - assert(!c->scache.memchunk.memblock); - c->scache.memchunk.memblock = pa_memblock_new(sc_length, c->protocol->core->memblock_stat); - c->scache.memchunk.index = 0; - c->scache.memchunk.length = sc_length; - c->scache.sample_spec = ss; - assert(!c->scache.name); - c->scache.name = pa_xstrdup(name); - - c->state = ESD_CACHING_SAMPLE; - - pa_scache_add_item(c->protocol->core, c->scache.name, NULL, NULL, NULL, &idx); - - idx += 1; - connection_write(c, &idx, sizeof(uint32_t)); - - return 0; -} - -static int esd_proto_sample_get_id(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { - int32_t ok; - uint32_t idx; - char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; - - assert(c && data && length == ESD_NAME_MAX); - - strcpy(name, SCACHE_PREFIX); - strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX); - name[sizeof(name)-1] = 0; - - CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in sample name."); - - ok = -1; - if ((idx = pa_scache_get_id_by_name(c->protocol->core, name)) != PA_IDXSET_INVALID) - ok = idx + 1; - - connection_write(c, &ok, sizeof(int32_t)); - - return 0; -} - -static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length) { - int32_t ok; - const char *name; - uint32_t idx; - - assert(c && data && length == sizeof(int32_t)); - - memcpy(&idx, data, sizeof(uint32_t)); - idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; - - ok = 0; - - if ((name = pa_scache_get_name_by_id(c->protocol->core, idx))) { - if (request == ESD_PROTO_SAMPLE_PLAY) { - pa_sink *sink; - - if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) - if (pa_scache_play_item(c->protocol->core, name, sink, PA_VOLUME_NORM) >= 0) - ok = idx + 1; - } else { - assert(request == ESD_PROTO_SAMPLE_FREE); - - if (pa_scache_remove_item(c->protocol->core, name) >= 0) - ok = idx + 1; - } - } - - connection_write(c, &ok, sizeof(int32_t)); - - return 0; -} - -static int esd_proto_standby_or_resume(struct connection *c, PA_GCC_UNUSED esd_proto_t request, PA_GCC_UNUSED const void *data, PA_GCC_UNUSED size_t length) { - int32_t ok; - - connection_write_prepare(c, sizeof(int32_t) * 2); - - ok = 1; - connection_write(c, &ok, sizeof(int32_t)); - connection_write(c, &ok, sizeof(int32_t)); - - return 0; -} - -/*** client callbacks ***/ - -static void client_kill_cb(pa_client *c) { - assert(c && c->userdata); - connection_free(c->userdata); -} - -/*** pa_iochannel callbacks ***/ - -static int do_read(struct connection *c) { - assert(c && c->io); - -/* pa_log("READ"); */ - - if (c->state == ESD_NEXT_REQUEST) { - ssize_t r; - assert(c->read_data_length < sizeof(c->request)); - - if ((r = pa_iochannel_read(c->io, ((uint8_t*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { - pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); - return -1; - } - - if ((c->read_data_length+= r) >= sizeof(c->request)) { - struct proto_handler *handler; - - c->request = MAYBE_INT32_SWAP(c->swap_byte_order, c->request); - - if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) { - pa_log(__FILE__": recieved invalid request."); - return -1; - } - - handler = proto_map+c->request; - -/* pa_log(__FILE__": executing request #%u", c->request); */ - - if (!handler->proc) { - pa_log(__FILE__": recieved unimplemented request #%u.", c->request); - return -1; - } - - if (handler->data_length == 0) { - c->read_data_length = 0; - - if (handler->proc(c, c->request, NULL, 0) < 0) - return -1; - - } else { - if (c->read_data_alloc < handler->data_length) - c->read_data = pa_xrealloc(c->read_data, c->read_data_alloc = handler->data_length); - assert(c->read_data); - - c->state = ESD_NEEDS_REQDATA; - c->read_data_length = 0; - } - } - - } else if (c->state == ESD_NEEDS_REQDATA) { - ssize_t r; - struct proto_handler *handler = proto_map+c->request; - - assert(handler->proc); - - assert(c->read_data && c->read_data_length < handler->data_length); - - if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { - pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); - return -1; - } - - if ((c->read_data_length += r) >= handler->data_length) { - size_t l = c->read_data_length; - assert(handler->proc); - - c->state = ESD_NEXT_REQUEST; - c->read_data_length = 0; - - if (handler->proc(c, c->request, c->read_data, l) < 0) - return -1; - } - } else if (c->state == ESD_CACHING_SAMPLE) { - ssize_t r; - - assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); - - if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { - pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); - return -1; - } - - c->scache.memchunk.index += r; - assert(c->scache.memchunk.index <= c->scache.memchunk.length); - - if (c->scache.memchunk.index == c->scache.memchunk.length) { - uint32_t idx; - - c->scache.memchunk.index = 0; - pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, NULL, &c->scache.memchunk, &idx); - - pa_memblock_unref(c->scache.memchunk.memblock); - c->scache.memchunk.memblock = NULL; - c->scache.memchunk.index = c->scache.memchunk.length = 0; - - pa_xfree(c->scache.name); - c->scache.name = NULL; - - c->state = ESD_NEXT_REQUEST; - - idx += 1; - connection_write(c, &idx, sizeof(uint32_t)); - } - - } else if (c->state == ESD_STREAMING_DATA && c->sink_input) { - pa_memchunk chunk; - ssize_t r; - size_t l; - - assert(c->input_memblockq); - -/* pa_log("STREAMING_DATA"); */ - - if (!(l = pa_memblockq_missing(c->input_memblockq))) - return 0; - - if (l > c->playback.fragment_size) - l = c->playback.fragment_size; - - if (c->playback.current_memblock) - if (c->playback.current_memblock->length - c->playback.memblock_index < l) { - pa_memblock_unref(c->playback.current_memblock); - c->playback.current_memblock = NULL; - c->playback.memblock_index = 0; - } - - if (!c->playback.current_memblock) { - c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2, c->protocol->core->memblock_stat); - assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); - c->playback.memblock_index = 0; - } - - if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { - pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); - return -1; - } - - chunk.memblock = c->playback.current_memblock; - chunk.index = c->playback.memblock_index; - chunk.length = r; - assert(chunk.memblock); - - c->playback.memblock_index += r; - - assert(c->input_memblockq); - pa_memblockq_push_align(c->input_memblockq, &chunk); - assert(c->sink_input); - pa_sink_notify(c->sink_input->sink); - } - - return 0; -} - -static int do_write(struct connection *c) { - assert(c && c->io); - -/* pa_log("WRITE"); */ - - if (c->write_data_length) { - ssize_t r; - - assert(c->write_data_index < c->write_data_length); - if ((r = pa_iochannel_write(c->io, (uint8_t*) c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { - pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); - return -1; - } - - if ((c->write_data_index +=r) >= c->write_data_length) - c->write_data_length = c->write_data_index = 0; - - } else if (c->state == ESD_STREAMING_DATA && c->source_output) { - pa_memchunk chunk; - ssize_t r; - - assert(c->output_memblockq); - if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) - return 0; - - assert(chunk.memblock && chunk.length); - - if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { - pa_memblock_unref(chunk.memblock); - pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); - return -1; - } - - pa_memblockq_drop(c->output_memblockq, &chunk, r); - pa_memblock_unref(chunk.memblock); - - pa_source_notify(c->source_output->source); - } - - return 0; -} - -static void do_work(struct connection *c) { - assert(c); - - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - c->protocol->core->mainloop->defer_enable(c->defer_event, 0); - - if (c->dead) - return; - - if (pa_iochannel_is_readable(c->io)) { - if (do_read(c) < 0) - goto fail; - } - - if (c->state == ESD_STREAMING_DATA && c->source_output && pa_iochannel_is_hungup(c->io)) - /* In case we are in capture mode we will never call read() - * on the socket, hence we need to detect the hangup manually - * here, instead of simply waiting for read() to return 0. */ - goto fail; - - if (pa_iochannel_is_writable(c->io)) - if (do_write(c) < 0) - goto fail; - - return; - -fail: - - if (c->state == ESD_STREAMING_DATA && c->sink_input) { - c->dead = 1; - - pa_iochannel_free(c->io); - c->io = NULL; - - pa_memblockq_prebuf_disable(c->input_memblockq); - pa_sink_notify(c->sink_input->sink); - } else - connection_free(c); -} - -static void io_callback(pa_iochannel*io, void *userdata) { - struct connection *c = userdata; - assert(io && c && c->io == io); - - do_work(c); -} - -/*** defer callback ***/ - -static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { - struct connection *c = userdata; - assert(a && c && c->defer_event == e); - -/* pa_log("DEFER"); */ - - do_work(c); -} - -/*** sink_input callbacks ***/ - -static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { - struct connection*c; - assert(i && i->userdata && chunk); - c = i->userdata; - - if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) { - - if (c->dead) - connection_free(c); - - return -1; - } - - return 0; -} - -static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { - struct connection*c = i->userdata; - assert(i && c && length); - -/* pa_log("DROP"); */ - - pa_memblockq_drop(c->input_memblockq, chunk, length); - - /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - - if (!c->dead) - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); - -/* assert(pa_memblockq_get_length(c->input_memblockq) > 2048); */ -} - -static void sink_input_kill_cb(pa_sink_input *i) { - assert(i && i->userdata); - connection_free((struct connection *) i->userdata); -} - -static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { - struct connection*c = i->userdata; - assert(i && c); - return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); -} - -/*** source_output callbacks ***/ - -static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { - struct connection *c = o->userdata; - assert(o && c && chunk); - - pa_memblockq_push(c->output_memblockq, chunk); - - /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - - if (!c->dead) - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); -} - -static void source_output_kill_cb(pa_source_output *o) { - assert(o && o->userdata); - connection_free((struct connection *) o->userdata); -} - -static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { - struct connection*c = o->userdata; - assert(o && c); - return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec); -} - -/*** socket server callback ***/ - -static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { - struct connection *c = userdata; - assert(m && tv && c && c->auth_timeout_event == e); - - if (!c->authorized) - connection_free(c); -} - -static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { - struct connection *c; - pa_protocol_esound *p = userdata; - char cname[256], pname[128]; - assert(s && io && p); - - if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); - pa_iochannel_free(io); - return; - } - - c = pa_xnew(struct connection, 1); - c->protocol = p; - c->io = io; - pa_iochannel_set_callback(c->io, io_callback, c); - - pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname)); - snprintf(cname, sizeof(cname), "EsounD client (%s)", pname); - assert(p->core); - c->client = pa_client_new(p->core, __FILE__, cname); - assert(c->client); - c->client->owner = p->module; - c->client->kill = client_kill_cb; - c->client->userdata = c; - - c->authorized = p->public; - c->swap_byte_order = 0; - c->dead = 0; - - c->read_data_length = 0; - c->read_data = pa_xmalloc(c->read_data_alloc = proto_map[ESD_PROTO_CONNECT].data_length); - - c->write_data_length = c->write_data_index = c->write_data_alloc = 0; - c->write_data = NULL; - - c->state = ESD_NEEDS_REQDATA; - c->request = ESD_PROTO_CONNECT; - - c->sink_input = NULL; - c->input_memblockq = NULL; - - c->source_output = NULL; - c->output_memblockq = NULL; - - c->playback.current_memblock = NULL; - c->playback.memblock_index = 0; - c->playback.fragment_size = 0; - - c->scache.memchunk.length = c->scache.memchunk.index = 0; - c->scache.memchunk.memblock = NULL; - c->scache.name = NULL; - - c->original_name = NULL; - - if (!c->authorized) { - struct timeval tv; - pa_gettimeofday(&tv); - tv.tv_sec += AUTH_TIMEOUT; - c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c); - } else - c->auth_timeout_event = NULL; - - c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c); - assert(c->defer_event); - p->core->mainloop->defer_enable(c->defer_event, 0); - - pa_idxset_put(p->connections, c, &c->index); -} - -/*** entry points ***/ - -pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { - pa_protocol_esound *p; - int public = 0; - assert(core && server && ma); - - p = pa_xnew(pa_protocol_esound, 1); - - if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) { - pa_log(__FILE__": auth-anonymous= expects a boolean argument."); - return NULL; - } - - if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", DEFAULT_COOKIE_FILE), p->esd_key, sizeof(p->esd_key)) < 0) { - pa_xfree(p); - return NULL; - } - - p->module = m; - p->public = public; - p->server = server; - pa_socket_server_set_callback(p->server, on_connection, p); - p->core = core; - p->connections = pa_idxset_new(NULL, NULL); - assert(p->connections); - - p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); - p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL)); - p->n_player = 0; - - return p; -} - -void pa_protocol_esound_free(pa_protocol_esound *p) { - struct connection *c; - assert(p); - - while ((c = pa_idxset_first(p->connections, NULL))) - connection_free(c); - - pa_idxset_free(p->connections, NULL, NULL); - pa_socket_server_unref(p->server); - pa_xfree(p); -} diff --git a/src/polypcore/protocol-esound.h b/src/polypcore/protocol-esound.h deleted file mode 100644 index a94d1c72..00000000 --- a/src/polypcore/protocol-esound.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef fooprotocolesoundhfoo -#define fooprotocolesoundhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include - -typedef struct pa_protocol_esound pa_protocol_esound; - -pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma); -void pa_protocol_esound_free(pa_protocol_esound *p); - -#endif diff --git a/src/polypcore/protocol-http.c b/src/polypcore/protocol-http.c deleted file mode 100644 index 86ea3b15..00000000 --- a/src/polypcore/protocol-http.c +++ /dev/null @@ -1,268 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include "protocol-http.h" - -/* Don't allow more than this many concurrent connections */ -#define MAX_CONNECTIONS 10 - -#define internal_server_error(c) http_message((c), 500, "Internal Server Error", NULL) - -#define URL_ROOT "/" -#define URL_CSS "/style" -#define URL_STATUS "/status" - -struct connection { - pa_protocol_http *protocol; - pa_ioline *line; - enum { REQUEST_LINE, MIME_HEADER, DATA } state; - char *url; -}; - -struct pa_protocol_http { - pa_module *module; - pa_core *core; - pa_socket_server*server; - pa_idxset *connections; -}; - -static void http_response(struct connection *c, int code, const char *msg, const char *mime) { - char s[256]; - assert(c); - assert(msg); - assert(mime); - - snprintf(s, sizeof(s), - "HTTP/1.0 %i %s\n" - "Connection: close\n" - "Content-Type: %s\n" - "Cache-Control: no-cache\n" - "Expires: 0\n" - "Server: "PACKAGE_NAME"/"PACKAGE_VERSION"\n" - "\n", code, msg, mime); - - pa_ioline_puts(c->line, s); -} - -static void http_message(struct connection *c, int code, const char *msg, const char *text) { - char s[256]; - assert(c); - - http_response(c, code, msg, "text/html"); - - if (!text) - text = msg; - - snprintf(s, sizeof(s), - "\n" - "\n" - "%s\n" - "%s\n", - text, text); - - pa_ioline_puts(c->line, s); - pa_ioline_defer_close(c->line); -} - - -static void connection_free(struct connection *c, int del) { - assert(c); - - if (c->url) - pa_xfree(c->url); - - if (del) - pa_idxset_remove_by_data(c->protocol->connections, c, NULL); - pa_ioline_unref(c->line); - pa_xfree(c); -} - -static void line_callback(pa_ioline *line, const char *s, void *userdata) { - struct connection *c = userdata; - assert(line); - assert(c); - - if (!s) { - /* EOF */ - connection_free(c, 1); - return; - } - - switch (c->state) { - case REQUEST_LINE: { - if (memcmp(s, "GET ", 4)) - goto fail; - - s +=4; - - c->url = pa_xstrndup(s, strcspn(s, " \r\n\t?")); - c->state = MIME_HEADER; - break; - - } - - case MIME_HEADER: { - - /* Ignore MIME headers */ - if (strcspn(s, " \r\n") != 0) - break; - - /* We're done */ - c->state = DATA; - - pa_log_info(__FILE__": request for %s", c->url); - - if (!strcmp(c->url, URL_ROOT)) { - char txt[256]; - http_response(c, 200, "OK", "text/html"); - - pa_ioline_puts(c->line, - "\n" - "\n" - ""PACKAGE_NAME" "PACKAGE_VERSION"\n" - "\n"); - - pa_ioline_puts(c->line, - "

      "PACKAGE_NAME" "PACKAGE_VERSION"

      \n" - ""); - -#define PRINTF_FIELD(a,b) pa_ioline_printf(c->line, "\n",(a),(b)) - - PRINTF_FIELD("User Name:", pa_get_user_name(txt, sizeof(txt))); - PRINTF_FIELD("Fully Qualified Domain Name:", pa_get_fqdn(txt, sizeof(txt))); - PRINTF_FIELD("Default Sample Specification:", pa_sample_spec_snprint(txt, sizeof(txt), &c->protocol->core->default_sample_spec)); - PRINTF_FIELD("Default Sink:", pa_namereg_get_default_sink_name(c->protocol->core)); - PRINTF_FIELD("Default Source:", pa_namereg_get_default_source_name(c->protocol->core)); - - pa_ioline_puts(c->line, "
      %s%s
      "); - - pa_ioline_puts(c->line, "

      Click here for an extensive server status report.

      "); - - pa_ioline_puts(c->line, "\n"); - - pa_ioline_defer_close(c->line); - } else if (!strcmp(c->url, URL_CSS)) { - http_response(c, 200, "OK", "text/css"); - - pa_ioline_puts(c->line, - "body { color: black; background-color: white; margin: 0.5cm; }\n" - "a:link, a:visited { color: #900000; }\n" - "p { margin-left: 0.5cm; margin-right: 0.5cm; }\n" - "h1 { color: #00009F; }\n" - "h2 { color: #00009F; }\n" - "ul { margin-left: .5cm; }\n" - "ol { margin-left: .5cm; }\n" - "pre { margin-left: .5cm; background-color: #f0f0f0; padding: 0.4cm;}\n" - ".grey { color: #afafaf; }\n" - "table { margin-left: 1cm; border:1px solid lightgrey; padding: 0.2cm; }\n" - "td { padding-left:10px; padding-right:10px; }\n"); - - pa_ioline_defer_close(c->line); - } else if (!strcmp(c->url, URL_STATUS)) { - char *r; - - http_response(c, 200, "OK", "text/plain"); - r = pa_full_status_string(c->protocol->core); - pa_ioline_puts(c->line, r); - pa_xfree(r); - - pa_ioline_defer_close(c->line); - } else - http_message(c, 404, "Not Found", NULL); - - break; - } - - default: - ; - } - - return; - -fail: - internal_server_error(c); -} - -static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { - pa_protocol_http *p = userdata; - struct connection *c; - assert(s && io && p); - - if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log_warn(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); - pa_iochannel_free(io); - return; - } - - c = pa_xmalloc(sizeof(struct connection)); - c->protocol = p; - c->line = pa_ioline_new(io); - c->state = REQUEST_LINE; - c->url = NULL; - - pa_ioline_set_callback(c->line, line_callback, c); - pa_idxset_put(p->connections, c, NULL); -} - -pa_protocol_http* pa_protocol_http_new(pa_core *core, pa_socket_server *server, pa_module *m, PA_GCC_UNUSED pa_modargs *ma) { - pa_protocol_http* p; - assert(core && server); - - p = pa_xmalloc(sizeof(pa_protocol_http)); - p->module = m; - p->core = core; - p->server = server; - p->connections = pa_idxset_new(NULL, NULL); - - pa_socket_server_set_callback(p->server, on_connection, p); - - return p; -} - -static void free_connection(void *p, PA_GCC_UNUSED void *userdata) { - assert(p); - connection_free(p, 0); -} - -void pa_protocol_http_free(pa_protocol_http *p) { - assert(p); - - pa_idxset_free(p->connections, free_connection, NULL); - pa_socket_server_unref(p->server); - pa_xfree(p); -} diff --git a/src/polypcore/protocol-http.h b/src/polypcore/protocol-http.h deleted file mode 100644 index 10dd656b..00000000 --- a/src/polypcore/protocol-http.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef fooprotocolhttphfoo -#define fooprotocolhttphfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include - -typedef struct pa_protocol_http pa_protocol_http; - -pa_protocol_http* pa_protocol_http_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma); -void pa_protocol_http_free(pa_protocol_http *n); - -#endif diff --git a/src/polypcore/protocol-native.c b/src/polypcore/protocol-native.c deleted file mode 100644 index 221601a6..00000000 --- a/src/polypcore/protocol-native.c +++ /dev/null @@ -1,2398 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "protocol-native.h" - -/* Kick a client if it doesn't authenticate within this time */ -#define AUTH_TIMEOUT 60 - -/* Don't accept more connection than this */ -#define MAX_CONNECTIONS 10 - -#define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */ - -struct connection; -struct pa_protocol_native; - -struct record_stream { - struct connection *connection; - uint32_t index; - pa_source_output *source_output; - pa_memblockq *memblockq; - size_t fragment_size; -}; - -struct playback_stream { - int type; - struct connection *connection; - uint32_t index; - pa_sink_input *sink_input; - pa_memblockq *memblockq; - size_t requested_bytes; - int drain_request; - uint32_t drain_tag; - uint32_t syncid; - int underrun; - - /* Sync group members */ - PA_LLIST_FIELDS(struct playback_stream); -}; - -struct upload_stream { - int type; - struct connection *connection; - uint32_t index; - pa_memchunk memchunk; - size_t length; - char *name; - pa_sample_spec sample_spec; - pa_channel_map channel_map; -}; - -struct output_stream { - int type; -}; - -enum { - UPLOAD_STREAM, - PLAYBACK_STREAM -}; - -struct connection { - int authorized; - uint32_t version; - pa_protocol_native *protocol; - pa_client *client; - pa_pstream *pstream; - pa_pdispatch *pdispatch; - pa_idxset *record_streams, *output_streams; - uint32_t rrobin_index; - pa_subscription *subscription; - pa_time_event *auth_timeout_event; -}; - -struct pa_protocol_native { - pa_module *module; - int public; - pa_core *core; - pa_socket_server *server; - pa_idxset *connections; - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; - int auth_cookie_in_property; -#ifdef SCM_CREDENTIALS - char *auth_group; -#endif -}; - -static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk); -static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length); -static void sink_input_kill_cb(pa_sink_input *i); -static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i); - -static void request_bytes(struct playback_stream*s); - -static void source_output_kill_cb(pa_source_output *o); -static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk); -static pa_usec_t source_output_get_latency_cb(pa_source_output *o); - -static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_set_mute(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_flush_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_trigger_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_add_autoload(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_remove_autoload(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_get_autoload_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_get_autoload_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); - -static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = NULL, - [PA_COMMAND_TIMEOUT] = NULL, - [PA_COMMAND_REPLY] = NULL, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream, - [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream, - [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream, - [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream, - [PA_COMMAND_AUTH] = command_auth, - [PA_COMMAND_REQUEST] = NULL, - [PA_COMMAND_EXIT] = command_exit, - [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name, - [PA_COMMAND_LOOKUP_SINK] = command_lookup, - [PA_COMMAND_LOOKUP_SOURCE] = command_lookup, - [PA_COMMAND_STAT] = command_stat, - [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency, - [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency, - [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream, - [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream, - [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream, - [PA_COMMAND_PLAY_SAMPLE] = command_play_sample, - [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample, - [PA_COMMAND_GET_SINK_INFO] = command_get_info, - [PA_COMMAND_GET_SOURCE_INFO] = command_get_info, - [PA_COMMAND_GET_CLIENT_INFO] = command_get_info, - [PA_COMMAND_GET_MODULE_INFO] = command_get_info, - [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info, - [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info, - [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info, - [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list, - [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list, - [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list, - [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list, - [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list, - [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list, - [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list, - [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info, - [PA_COMMAND_SUBSCRIBE] = command_subscribe, - - [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume, - [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume, - [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume, - - [PA_COMMAND_SET_SINK_MUTE] = command_set_mute, - [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute, - - [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream, - [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_flush_playback_stream, - [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_prebuf_playback_stream, - [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_prebuf_playback_stream, - - [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream, - [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream, - - [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source, - [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source, - [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name, - [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name, - [PA_COMMAND_KILL_CLIENT] = command_kill, - [PA_COMMAND_KILL_SINK_INPUT] = command_kill, - [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill, - [PA_COMMAND_LOAD_MODULE] = command_load_module, - [PA_COMMAND_UNLOAD_MODULE] = command_unload_module, - [PA_COMMAND_GET_AUTOLOAD_INFO] = command_get_autoload_info, - [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = command_get_autoload_info_list, - [PA_COMMAND_ADD_AUTOLOAD] = command_add_autoload, - [PA_COMMAND_REMOVE_AUTOLOAD] = command_remove_autoload -}; - -/* structure management */ - -static struct upload_stream* upload_stream_new( - struct connection *c, - const pa_sample_spec *ss, - const pa_channel_map *map, - const char *name, size_t length) { - - struct upload_stream *s; - assert(c && ss && name && length); - - s = pa_xnew(struct upload_stream, 1); - s->type = UPLOAD_STREAM; - s->connection = c; - s->sample_spec = *ss; - s->channel_map = *map; - s->name = pa_xstrdup(name); - - s->memchunk.memblock = NULL; - s->memchunk.index = 0; - s->memchunk.length = 0; - - s->length = length; - - pa_idxset_put(c->output_streams, s, &s->index); - return s; -} - -static void upload_stream_free(struct upload_stream *o) { - assert(o && o->connection); - - pa_idxset_remove_by_data(o->connection->output_streams, o, NULL); - - pa_xfree(o->name); - - if (o->memchunk.memblock) - pa_memblock_unref(o->memchunk.memblock); - - pa_xfree(o); -} - -static struct record_stream* record_stream_new( - struct connection *c, - pa_source *source, - const pa_sample_spec *ss, - const pa_channel_map *map, - const char *name, - size_t maxlength, - size_t fragment_size) { - - struct record_stream *s; - pa_source_output *source_output; - size_t base; - assert(c && source && ss && name && maxlength); - - if (!(source_output = pa_source_output_new(source, __FILE__, name, ss, map, -1))) - return NULL; - - s = pa_xnew(struct record_stream, 1); - s->connection = c; - s->source_output = source_output; - s->source_output->push = source_output_push_cb; - s->source_output->kill = source_output_kill_cb; - s->source_output->get_latency = source_output_get_latency_cb; - s->source_output->userdata = s; - s->source_output->owner = c->protocol->module; - s->source_output->client = c->client; - - s->memblockq = pa_memblockq_new( - 0, - maxlength, - 0, - base = pa_frame_size(ss), - 1, - 0, - NULL, - c->protocol->core->memblock_stat); - assert(s->memblockq); - - s->fragment_size = (fragment_size/base)*base; - if (!s->fragment_size) - s->fragment_size = base; - - pa_idxset_put(c->record_streams, s, &s->index); - return s; -} - -static void record_stream_free(struct record_stream* r) { - assert(r && r->connection); - - pa_idxset_remove_by_data(r->connection->record_streams, r, NULL); - pa_source_output_disconnect(r->source_output); - pa_source_output_unref(r->source_output); - pa_memblockq_free(r->memblockq); - pa_xfree(r); -} - -static struct playback_stream* playback_stream_new( - struct connection *c, - pa_sink *sink, - const pa_sample_spec *ss, - const pa_channel_map *map, - const char *name, - size_t maxlength, - size_t tlength, - size_t prebuf, - size_t minreq, - pa_cvolume *volume, - uint32_t syncid) { - - struct playback_stream *s, *ssync; - pa_sink_input *sink_input; - pa_memblock *silence; - uint32_t idx; - int64_t start_index; - - assert(c && sink && ss && name && maxlength); - - /* Find syncid group */ - for (ssync = pa_idxset_first(c->output_streams, &idx); ssync; ssync = pa_idxset_next(c->output_streams, &idx)) { - - if (ssync->type != PLAYBACK_STREAM) - continue; - - if (ssync->syncid == syncid) - break; - } - - /* Synced streams must connect to the same sink */ - if (ssync && ssync->sink_input->sink != sink) - return NULL; - - if (!(sink_input = pa_sink_input_new(sink, __FILE__, name, ss, map, volume, 0, -1))) - return NULL; - - s = pa_xnew(struct playback_stream, 1); - s->type = PLAYBACK_STREAM; - s->connection = c; - s->syncid = syncid; - s->sink_input = sink_input; - s->underrun = 1; - - s->sink_input->peek = sink_input_peek_cb; - s->sink_input->drop = sink_input_drop_cb; - s->sink_input->kill = sink_input_kill_cb; - s->sink_input->get_latency = sink_input_get_latency_cb; - s->sink_input->userdata = s; - s->sink_input->owner = c->protocol->module; - s->sink_input->client = c->client; - - if (ssync) { - /* Sync id found, now find head of list */ - PA_LLIST_FIND_HEAD(struct playback_stream, ssync, &ssync); - - /* Prepend ourselves */ - PA_LLIST_PREPEND(struct playback_stream, ssync, s); - - /* Set our start index to the current read index of the other grozp member(s) */ - assert(ssync->next); - start_index = pa_memblockq_get_read_index(ssync->next->memblockq); - } else { - /* This ia a new sync group */ - PA_LLIST_INIT(struct playback_stream, s); - start_index = 0; - } - - silence = pa_silence_memblock_new(ss, 0, c->protocol->core->memblock_stat); - - s->memblockq = pa_memblockq_new( - start_index, - maxlength, - tlength, - pa_frame_size(ss), - prebuf, - minreq, - silence, - c->protocol->core->memblock_stat); - - pa_memblock_unref(silence); - - s->requested_bytes = 0; - s->drain_request = 0; - - pa_idxset_put(c->output_streams, s, &s->index); - - return s; -} - -static void playback_stream_free(struct playback_stream* p) { - struct playback_stream *head; - assert(p && p->connection); - - if (p->drain_request) - pa_pstream_send_error(p->connection->pstream, p->drain_tag, PA_ERR_NOENTITY); - - PA_LLIST_FIND_HEAD(struct playback_stream, p, &head); - PA_LLIST_REMOVE(struct playback_stream, head, p); - - pa_idxset_remove_by_data(p->connection->output_streams, p, NULL); - pa_sink_input_disconnect(p->sink_input); - pa_sink_input_unref(p->sink_input); - pa_memblockq_free(p->memblockq); - pa_xfree(p); -} - -static void connection_free(struct connection *c) { - struct record_stream *r; - struct output_stream *o; - assert(c && c->protocol); - - pa_idxset_remove_by_data(c->protocol->connections, c, NULL); - while ((r = pa_idxset_first(c->record_streams, NULL))) - record_stream_free(r); - pa_idxset_free(c->record_streams, NULL, NULL); - - while ((o = pa_idxset_first(c->output_streams, NULL))) - if (o->type == PLAYBACK_STREAM) - playback_stream_free((struct playback_stream*) o); - else - upload_stream_free((struct upload_stream*) o); - pa_idxset_free(c->output_streams, NULL, NULL); - - pa_pdispatch_unref(c->pdispatch); - pa_pstream_close(c->pstream); - pa_pstream_unref(c->pstream); - pa_client_free(c->client); - - if (c->subscription) - pa_subscription_free(c->subscription); - - if (c->auth_timeout_event) - c->protocol->core->mainloop->time_free(c->auth_timeout_event); - - pa_xfree(c); -} - -static void request_bytes(struct playback_stream *s) { - pa_tagstruct *t; - size_t l; - assert(s); - - if (!(l = pa_memblockq_missing(s->memblockq))) - return; - - if (l <= s->requested_bytes) - return; - - l -= s->requested_bytes; - - if (l < pa_memblockq_get_minreq(s->memblockq)) - return; - - s->requested_bytes += l; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REQUEST); - pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ - pa_tagstruct_putu32(t, s->index); - pa_tagstruct_putu32(t, l); - pa_pstream_send_tagstruct(s->connection->pstream, t); - -/* pa_log(__FILE__": Requesting %u bytes", l); */ -} - -static void send_memblock(struct connection *c) { - uint32_t start; - struct record_stream *r; - - start = PA_IDXSET_INVALID; - for (;;) { - pa_memchunk chunk; - - if (!(r = pa_idxset_rrobin(c->record_streams, &c->rrobin_index))) - return; - - if (start == PA_IDXSET_INVALID) - start = c->rrobin_index; - else if (start == c->rrobin_index) - return; - - if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) { - pa_memchunk schunk = chunk; - - if (schunk.length > r->fragment_size) - schunk.length = r->fragment_size; - - pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk); - pa_memblockq_drop(r->memblockq, &chunk, schunk.length); - pa_memblock_unref(schunk.memblock); - - return; - } - } -} - -static void send_playback_stream_killed(struct playback_stream *p) { - pa_tagstruct *t; - assert(p); - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED); - pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ - pa_tagstruct_putu32(t, p->index); - pa_pstream_send_tagstruct(p->connection->pstream, t); -} - -static void send_record_stream_killed(struct record_stream *r) { - pa_tagstruct *t; - assert(r); - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED); - pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ - pa_tagstruct_putu32(t, r->index); - pa_pstream_send_tagstruct(r->connection->pstream, t); -} - -/*** sinkinput callbacks ***/ - -static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { - struct playback_stream *s; - assert(i && i->userdata && chunk); - s = i->userdata; - - if (pa_memblockq_get_length(s->memblockq) <= 0 && !s->underrun) { - pa_tagstruct *t; - - /* Report that we're empty */ - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW); - pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ - pa_tagstruct_putu32(t, s->index); - pa_pstream_send_tagstruct(s->connection->pstream, t); - - s->underrun = 1; - } - - if (pa_memblockq_peek(s->memblockq, chunk) < 0) { -/* pa_log(__FILE__": peek: failure"); */ - return -1; - } - -/* pa_log(__FILE__": peek: %u", chunk->length); */ - - return 0; -} - -static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { - struct playback_stream *s; - assert(i && i->userdata && length); - s = i->userdata; - - pa_memblockq_drop(s->memblockq, chunk, length); - - request_bytes(s); - - if (s->drain_request && !pa_memblockq_is_readable(s->memblockq)) { - pa_pstream_send_simple_ack(s->connection->pstream, s->drain_tag); - s->drain_request = 0; - } - -/* pa_log(__FILE__": after_drop: %u %u", pa_memblockq_get_length(s->memblockq), pa_memblockq_is_readable(s->memblockq)); */ -} - -static void sink_input_kill_cb(pa_sink_input *i) { - assert(i && i->userdata); - send_playback_stream_killed((struct playback_stream *) i->userdata); - playback_stream_free((struct playback_stream *) i->userdata); -} - -static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { - struct playback_stream *s; - assert(i && i->userdata); - s = i->userdata; - - /*pa_log(__FILE__": get_latency: %u", pa_memblockq_get_length(s->memblockq));*/ - - return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec); -} - -/*** source_output callbacks ***/ - -static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { - struct record_stream *s; - assert(o && o->userdata && chunk); - s = o->userdata; - - if (pa_memblockq_push_align(s->memblockq, chunk) < 0) { - pa_log_warn(__FILE__": Failed to push data into output queue."); - return; - } - - if (!pa_pstream_is_pending(s->connection->pstream)) - send_memblock(s->connection); -} - -static void source_output_kill_cb(pa_source_output *o) { - assert(o && o->userdata); - send_record_stream_killed((struct record_stream *) o->userdata); - record_stream_free((struct record_stream *) o->userdata); -} - -static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { - struct record_stream *s; - assert(o && o->userdata); - s = o->userdata; - - /*pa_log(__FILE__": get_latency: %u", pa_memblockq_get_length(s->memblockq));*/ - - return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec); -} - -/*** pdispatch callbacks ***/ - -static void protocol_error(struct connection *c) { - pa_log(__FILE__": protocol error, kicking client"); - connection_free(c); -} - -#define CHECK_VALIDITY(pstream, expression, tag, error) do { \ -if (!(expression)) { \ - pa_pstream_send_error((pstream), (tag), (error)); \ - return; \ -} \ -} while(0); - -static pa_tagstruct *reply_new(uint32_t tag) { - pa_tagstruct *reply; - - reply = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); - pa_tagstruct_putu32(reply, tag); - return reply; -} - -static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - struct playback_stream *s; - uint32_t maxlength, tlength, prebuf, minreq, sink_index, syncid; - const char *name, *sink_name; - pa_sample_spec ss; - pa_channel_map map; - pa_tagstruct *reply; - pa_sink *sink; - pa_cvolume volume; - int corked; - - assert(c && t && c->protocol && c->protocol->core); - - if (pa_tagstruct_get( - t, - PA_TAG_STRING, &name, - PA_TAG_SAMPLE_SPEC, &ss, - PA_TAG_CHANNEL_MAP, &map, - PA_TAG_U32, &sink_index, - PA_TAG_STRING, &sink_name, - PA_TAG_U32, &maxlength, - PA_TAG_BOOLEAN, &corked, - PA_TAG_U32, &tlength, - PA_TAG_U32, &prebuf, - PA_TAG_U32, &minreq, - PA_TAG_U32, &syncid, - PA_TAG_CVOLUME, &volume, - PA_TAG_INVALID) < 0 || - !pa_tagstruct_eof(t) || - !name) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, sink_index != PA_INVALID_INDEX || !sink_name || (*sink_name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, maxlength > 0 && maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); - - if (sink_index != PA_INVALID_INDEX) - sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); - else - sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1); - - CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); - - s = playback_stream_new(c, sink, &ss, &map, name, maxlength, tlength, prebuf, minreq, &volume, syncid); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); - - pa_sink_input_cork(s->sink_input, corked); - - reply = reply_new(tag); - pa_tagstruct_putu32(reply, s->index); - assert(s->sink_input); - pa_tagstruct_putu32(reply, s->sink_input->index); - pa_tagstruct_putu32(reply, s->requested_bytes = pa_memblockq_missing(s->memblockq)); - - if (c->version >= 9) { - /* Since 0.9 we support sending the buffer metrics back to the client */ - - pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_maxlength(s->memblockq)); - pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_tlength(s->memblockq)); - pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_prebuf(s->memblockq)); - pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_minreq(s->memblockq)); - } - - pa_pstream_send_tagstruct(c->pstream, reply); - request_bytes(s); -} - -static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t channel; - assert(c && t); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - - if (command == PA_COMMAND_DELETE_PLAYBACK_STREAM) { - struct playback_stream *s; - if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != PLAYBACK_STREAM)) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); - return; - } - - playback_stream_free(s); - } else if (command == PA_COMMAND_DELETE_RECORD_STREAM) { - struct record_stream *s; - if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); - return; - } - - record_stream_free(s); - } else { - struct upload_stream *s; - assert(command == PA_COMMAND_DELETE_UPLOAD_STREAM); - if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != UPLOAD_STREAM)) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); - return; - } - - upload_stream_free(s); - } - - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - struct record_stream *s; - uint32_t maxlength, fragment_size; - uint32_t source_index; - const char *name, *source_name; - pa_sample_spec ss; - pa_channel_map map; - pa_tagstruct *reply; - pa_source *source; - int corked; - assert(c && t && c->protocol && c->protocol->core); - - if (pa_tagstruct_gets(t, &name) < 0 || - pa_tagstruct_get_sample_spec(t, &ss) < 0 || - pa_tagstruct_get_channel_map(t, &map) < 0 || - pa_tagstruct_getu32(t, &source_index) < 0 || - pa_tagstruct_gets(t, &source_name) < 0 || - pa_tagstruct_getu32(t, &maxlength) < 0 || - pa_tagstruct_get_boolean(t, &corked) < 0 || - pa_tagstruct_getu32(t, &fragment_size) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, source_index != PA_INVALID_INDEX || !source_name || (*source_name && pa_utf8_valid(source_name)), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); - - if (source_index != PA_INVALID_INDEX) - source = pa_idxset_get_by_index(c->protocol->core->sources, source_index); - else - source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE, 1); - - CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY); - - s = record_stream_new(c, source, &ss, &map, name, maxlength, fragment_size); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); - - pa_source_output_cork(s->source_output, corked); - - reply = reply_new(tag); - pa_tagstruct_putu32(reply, s->index); - assert(s->source_output); - pa_tagstruct_putu32(reply, s->source_output->index); - - if (c->version >= 9) { - /* Since 0.9 we support sending the buffer metrics back to the client */ - - pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_maxlength(s->memblockq)); - pa_tagstruct_putu32(reply, (uint32_t) s->fragment_size); - } - - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_exit(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - assert(c && t); - - if (!pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop); - c->protocol->core->mainloop->quit(c->protocol->core->mainloop, 0); - pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */ -} - -static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - const void*cookie; - pa_tagstruct *reply; - assert(c && t); - - if (pa_tagstruct_getu32(t, &c->version) < 0 || - pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - /* Minimum supported version */ - if (c->version < 8) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION); - return; - } - - if (!c->authorized) { - int success = 0; - -#ifdef SCM_CREDENTIALS - const struct ucred *ucred = pa_pdispatch_creds(pd); - - if (ucred) { - if (ucred->uid == getuid()) - success = 1; - else if (c->protocol->auth_group) { - int r; - - if ((r = pa_uid_in_group(ucred->uid, c->protocol->auth_group)) < 0) - pa_log_warn(__FILE__": failed to check group membership."); - else if (r > 0) - success = 1; - } - - pa_log_info(__FILE__": Got credentials: pid=%lu uid=%lu gid=%lu auth=%i", - (unsigned long) ucred->pid, - (unsigned long) ucred->uid, - (unsigned long) ucred->gid, - success); - } -#endif - - if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) == 0) - success = 1; - - if (!success) { - pa_log_warn(__FILE__": Denied access to client with invalid authorization data."); - pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); - return; - } - - c->authorized = 1; - if (c->auth_timeout_event) { - c->protocol->core->mainloop->time_free(c->auth_timeout_event); - c->auth_timeout_event = NULL; - } - } - - reply = reply_new(tag); - pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_set_client_name(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - const char *name; - assert(c && t); - - if (pa_tagstruct_gets(t, &name) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID); - - pa_client_set_name(c->client, name); - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - const char *name; - uint32_t idx = PA_IDXSET_INVALID; - assert(c && t); - - if (pa_tagstruct_gets(t, &name) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); - - if (command == PA_COMMAND_LOOKUP_SINK) { - pa_sink *sink; - if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1))) - idx = sink->index; - } else { - pa_source *source; - assert(command == PA_COMMAND_LOOKUP_SOURCE); - if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1))) - idx = source->index; - } - - if (idx == PA_IDXSET_INVALID) - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - else { - pa_tagstruct *reply; - reply = reply_new(tag); - pa_tagstruct_putu32(reply, idx); - pa_pstream_send_tagstruct(c->pstream, reply); - } -} - -static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - struct playback_stream *s; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - s = pa_idxset_get_by_index(c->output_streams, idx); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); - - s->drain_request = 0; - - pa_memblockq_prebuf_disable(s->memblockq); - - if (!pa_memblockq_is_readable(s->memblockq)) { -/* pa_log("immediate drain: %u", pa_memblockq_get_length(s->memblockq)); */ - pa_pstream_send_simple_ack(c->pstream, tag); - } else { -/* pa_log("slow drain triggered"); */ - s->drain_request = 1; - s->drain_tag = tag; - - pa_sink_notify(s->sink_input->sink); - } -} - -static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - pa_tagstruct *reply; - assert(c && t); - - if (!pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - - reply = reply_new(tag); - pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->total); - pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->total_size); - pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->allocated); - pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->allocated_size); - pa_tagstruct_putu32(reply, pa_scache_total_size(c->protocol->core)); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - pa_tagstruct *reply; - struct playback_stream *s; - struct timeval tv, now; - uint32_t idx; - pa_usec_t latency; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - pa_tagstruct_get_timeval(t, &tv) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - s = pa_idxset_get_by_index(c->output_streams, idx); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); - - reply = reply_new(tag); - - latency = pa_sink_get_latency(s->sink_input->sink); - if (s->sink_input->resampled_chunk.memblock) - latency += pa_bytes_to_usec(s->sink_input->resampled_chunk.length, &s->sink_input->sample_spec); - pa_tagstruct_put_usec(reply, latency); - - pa_tagstruct_put_usec(reply, 0); - pa_tagstruct_put_boolean(reply, pa_memblockq_is_readable(s->memblockq)); - pa_tagstruct_put_timeval(reply, &tv); - pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now)); - pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq)); - pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq)); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - pa_tagstruct *reply; - struct record_stream *s; - struct timeval tv, now; - uint32_t idx; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - pa_tagstruct_get_timeval(t, &tv) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - s = pa_idxset_get_by_index(c->record_streams, idx); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - - reply = reply_new(tag); - pa_tagstruct_put_usec(reply, s->source_output->source->monitor_of ? pa_sink_get_latency(s->source_output->source->monitor_of) : 0); - pa_tagstruct_put_usec(reply, pa_source_get_latency(s->source_output->source)); - pa_tagstruct_put_boolean(reply, 0); - pa_tagstruct_put_timeval(reply, &tv); - pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now)); - pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq)); - pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq)); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - struct upload_stream *s; - uint32_t length; - const char *name; - pa_sample_spec ss; - pa_channel_map map; - pa_tagstruct *reply; - assert(c && t && c->protocol && c->protocol->core); - - if (pa_tagstruct_gets(t, &name) < 0 || - pa_tagstruct_get_sample_spec(t, &ss) < 0 || - pa_tagstruct_get_channel_map(t, &map) < 0 || - pa_tagstruct_getu32(t, &length) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE); - CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); - - s = upload_stream_new(c, &ss, &map, name, length); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); - - reply = reply_new(tag); - pa_tagstruct_putu32(reply, s->index); - pa_tagstruct_putu32(reply, length); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t channel; - struct upload_stream *s; - uint32_t idx; - assert(c && t); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - - s = pa_idxset_get_by_index(c->output_streams, channel); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - CHECK_VALIDITY(c->pstream, s->type == UPLOAD_STREAM, tag, PA_ERR_NOENTITY); - - if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, &idx) < 0) - pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL); - else - pa_pstream_send_simple_ack(c->pstream, tag); - - upload_stream_free(s); -} - -static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t sink_index; - pa_volume_t volume; - pa_sink *sink; - const char *name, *sink_name; - assert(c && t); - - if (pa_tagstruct_getu32(t, &sink_index) < 0 || - pa_tagstruct_gets(t, &sink_name) < 0 || - pa_tagstruct_getu32(t, &volume) < 0 || - pa_tagstruct_gets(t, &name) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, sink_index != PA_INVALID_INDEX || !sink_name || (*sink_name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); - - if (sink_index != PA_INVALID_INDEX) - sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); - else - sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1); - - CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); - - if (pa_scache_play_item(c->protocol->core, name, sink, volume) < 0) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } - - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_remove_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - const char *name; - assert(c && t); - - if (pa_tagstruct_gets(t, &name) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); - - if (pa_scache_remove_item(c->protocol->core, name) < 0) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } - - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void sink_fill_tagstruct(pa_tagstruct *t, pa_sink *sink) { - assert(t && sink); - pa_tagstruct_put( - t, - PA_TAG_U32, sink->index, - PA_TAG_STRING, sink->name, - PA_TAG_STRING, sink->description, - PA_TAG_SAMPLE_SPEC, &sink->sample_spec, - PA_TAG_CHANNEL_MAP, &sink->channel_map, - PA_TAG_U32, sink->owner ? sink->owner->index : PA_INVALID_INDEX, - PA_TAG_CVOLUME, pa_sink_get_volume(sink, PA_MIXER_HARDWARE), - PA_TAG_BOOLEAN, pa_sink_get_mute(sink, PA_MIXER_HARDWARE), - PA_TAG_U32, sink->monitor_source->index, - PA_TAG_STRING, sink->monitor_source->name, - PA_TAG_USEC, pa_sink_get_latency(sink), - PA_TAG_STRING, sink->driver, - PA_TAG_U32, (sink->get_hw_volume ? PA_SINK_HW_VOLUME_CTRL : 0) | (sink->get_latency ? PA_SINK_LATENCY : 0), - PA_TAG_INVALID); -} - -static void source_fill_tagstruct(pa_tagstruct *t, pa_source *source) { - assert(t && source); - pa_tagstruct_put( - t, - PA_TAG_U32, source->index, - PA_TAG_STRING, source->name, - PA_TAG_STRING, source->description, - PA_TAG_SAMPLE_SPEC, &source->sample_spec, - PA_TAG_CHANNEL_MAP, &source->channel_map, - PA_TAG_U32, source->owner ? source->owner->index : PA_INVALID_INDEX, - PA_TAG_CVOLUME, pa_source_get_volume(source, PA_MIXER_HARDWARE), - PA_TAG_BOOLEAN, pa_source_get_mute(source, PA_MIXER_HARDWARE), - PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX, - PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL, - PA_TAG_USEC, pa_source_get_latency(source), - PA_TAG_STRING, source->driver, - PA_TAG_U32, (source->get_hw_volume ? PA_SOURCE_HW_VOLUME_CTRL : 0) | (source->get_latency ? PA_SOURCE_LATENCY : 0), - PA_TAG_INVALID); -} - -static void client_fill_tagstruct(pa_tagstruct *t, pa_client *client) { - assert(t && client); - pa_tagstruct_putu32(t, client->index); - pa_tagstruct_puts(t, client->name); - pa_tagstruct_putu32(t, client->owner ? client->owner->index : PA_INVALID_INDEX); - pa_tagstruct_puts(t, client->driver); -} - -static void module_fill_tagstruct(pa_tagstruct *t, pa_module *module) { - assert(t && module); - pa_tagstruct_putu32(t, module->index); - pa_tagstruct_puts(t, module->name); - pa_tagstruct_puts(t, module->argument); - pa_tagstruct_putu32(t, module->n_used); - pa_tagstruct_put_boolean(t, module->auto_unload); -} - -static void sink_input_fill_tagstruct(pa_tagstruct *t, pa_sink_input *s) { - assert(t && s); - pa_tagstruct_putu32(t, s->index); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_putu32(t, s->owner ? s->owner->index : PA_INVALID_INDEX); - pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX); - pa_tagstruct_putu32(t, s->sink->index); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_put_channel_map(t, &s->channel_map); - pa_tagstruct_put_cvolume(t, &s->volume); - pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s)); - pa_tagstruct_put_usec(t, pa_sink_get_latency(s->sink)); - pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s))); - pa_tagstruct_puts(t, s->driver); -} - -static void source_output_fill_tagstruct(pa_tagstruct *t, pa_source_output *s) { - assert(t && s); - pa_tagstruct_putu32(t, s->index); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_putu32(t, s->owner ? s->owner->index : PA_INVALID_INDEX); - pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX); - pa_tagstruct_putu32(t, s->source->index); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_put_channel_map(t, &s->channel_map); - pa_tagstruct_put_usec(t, pa_source_output_get_latency(s)); - pa_tagstruct_put_usec(t, pa_source_get_latency(s->source)); - pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s))); - pa_tagstruct_puts(t, s->driver); -} - -static void scache_fill_tagstruct(pa_tagstruct *t, pa_scache_entry *e) { - assert(t && e); - pa_tagstruct_putu32(t, e->index); - pa_tagstruct_puts(t, e->name); - pa_tagstruct_put_cvolume(t, &e->volume); - pa_tagstruct_put_usec(t, pa_bytes_to_usec(e->memchunk.length, &e->sample_spec)); - pa_tagstruct_put_sample_spec(t, &e->sample_spec); - pa_tagstruct_put_channel_map(t, &e->channel_map); - pa_tagstruct_putu32(t, e->memchunk.length); - pa_tagstruct_put_boolean(t, e->lazy); - pa_tagstruct_puts(t, e->filename); -} - -static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - pa_sink *sink = NULL; - pa_source *source = NULL; - pa_client *client = NULL; - pa_module *module = NULL; - pa_sink_input *si = NULL; - pa_source_output *so = NULL; - pa_scache_entry *sce = NULL; - const char *name; - pa_tagstruct *reply; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - (command != PA_COMMAND_GET_CLIENT_INFO && - command != PA_COMMAND_GET_MODULE_INFO && - command != PA_COMMAND_GET_SINK_INPUT_INFO && - command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO && - pa_tagstruct_gets(t, &name) < 0) || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); - - if (command == PA_COMMAND_GET_SINK_INFO) { - if (idx != PA_INVALID_INDEX) - sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); - else - sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); - } else if (command == PA_COMMAND_GET_SOURCE_INFO) { - if (idx != PA_INVALID_INDEX) - source = pa_idxset_get_by_index(c->protocol->core->sources, idx); - else - source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); - } else if (command == PA_COMMAND_GET_CLIENT_INFO) - client = pa_idxset_get_by_index(c->protocol->core->clients, idx); - else if (command == PA_COMMAND_GET_MODULE_INFO) - module = pa_idxset_get_by_index(c->protocol->core->modules, idx); - else if (command == PA_COMMAND_GET_SINK_INPUT_INFO) - si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); - else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO) - so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); - else { - assert(command == PA_COMMAND_GET_SAMPLE_INFO); - if (idx != PA_INVALID_INDEX) - sce = pa_idxset_get_by_index(c->protocol->core->scache, idx); - else - sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE, 0); - } - - if (!sink && !source && !client && !module && !si && !so && !sce) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); - return; - } - - reply = reply_new(tag); - if (sink) - sink_fill_tagstruct(reply, sink); - else if (source) - source_fill_tagstruct(reply, source); - else if (client) - client_fill_tagstruct(reply, client); - else if (module) - module_fill_tagstruct(reply, module); - else if (si) - sink_input_fill_tagstruct(reply, si); - else if (so) - source_output_fill_tagstruct(reply, so); - else - scache_fill_tagstruct(reply, sce); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - pa_idxset *i; - uint32_t idx; - void *p; - pa_tagstruct *reply; - assert(c && t); - - if (!pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - - reply = reply_new(tag); - - if (command == PA_COMMAND_GET_SINK_INFO_LIST) - i = c->protocol->core->sinks; - else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST) - i = c->protocol->core->sources; - else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST) - i = c->protocol->core->clients; - else if (command == PA_COMMAND_GET_MODULE_INFO_LIST) - i = c->protocol->core->modules; - else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) - i = c->protocol->core->sink_inputs; - else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST) - i = c->protocol->core->source_outputs; - else { - assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); - i = c->protocol->core->scache; - } - - if (i) { - for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) { - if (command == PA_COMMAND_GET_SINK_INFO_LIST) - sink_fill_tagstruct(reply, p); - else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST) - source_fill_tagstruct(reply, p); - else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST) - client_fill_tagstruct(reply, p); - else if (command == PA_COMMAND_GET_MODULE_INFO_LIST) - module_fill_tagstruct(reply, p); - else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) - sink_input_fill_tagstruct(reply, p); - else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST) - source_output_fill_tagstruct(reply, p); - else { - assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); - scache_fill_tagstruct(reply, p); - } - } - } - - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_get_server_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - pa_tagstruct *reply; - char txt[256]; - const char *n; - assert(c && t); - - if (!pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - - reply = reply_new(tag); - pa_tagstruct_puts(reply, PACKAGE_NAME); - pa_tagstruct_puts(reply, PACKAGE_VERSION); - pa_tagstruct_puts(reply, pa_get_user_name(txt, sizeof(txt))); - pa_tagstruct_puts(reply, pa_get_fqdn(txt, sizeof(txt))); - pa_tagstruct_put_sample_spec(reply, &c->protocol->core->default_sample_spec); - - n = pa_namereg_get_default_sink_name(c->protocol->core); - pa_tagstruct_puts(reply, n); - n = pa_namereg_get_default_source_name(c->protocol->core); - pa_tagstruct_puts(reply, n); - - pa_tagstruct_putu32(reply, c->protocol->core->cookie); - - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) { - pa_tagstruct *t; - struct connection *c = userdata; - assert(c && core); - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_putu32(t, e); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - pa_subscription_mask_t m; - assert(c && t); - - if (pa_tagstruct_getu32(t, &m) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID); - - if (c->subscription) - pa_subscription_free(c->subscription); - - if (m != 0) { - c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c); - assert(c->subscription); - } else - c->subscription = NULL; - - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_set_volume( - PA_GCC_UNUSED pa_pdispatch *pd, - uint32_t command, - uint32_t tag, - pa_tagstruct *t, - void *userdata) { - - struct connection *c = userdata; - uint32_t idx; - pa_cvolume volume; - pa_sink *sink = NULL; - pa_source *source = NULL; - pa_sink_input *si = NULL; - const char *name = NULL; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) || - (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) || - pa_tagstruct_get_cvolume(t, &volume) || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID); - - if (command == PA_COMMAND_SET_SINK_VOLUME) { - if (idx != PA_INVALID_INDEX) - sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); - else - sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); - } else if (command == PA_COMMAND_SET_SOURCE_VOLUME) { - if (idx != (uint32_t) -1) - source = pa_idxset_get_by_index(c->protocol->core->sources, idx); - else - source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); - } else { - assert(command == PA_COMMAND_SET_SINK_INPUT_VOLUME); - si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); - } - - CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY); - - if (sink) - pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &volume); - else if (source) - pa_source_set_volume(source, PA_MIXER_HARDWARE, &volume); - else if (si) - pa_sink_input_set_volume(si, &volume); - - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_set_mute( - PA_GCC_UNUSED pa_pdispatch *pd, - uint32_t command, - uint32_t tag, - pa_tagstruct *t, - void *userdata) { - - struct connection *c = userdata; - uint32_t idx; - int mute; - pa_sink *sink = NULL; - pa_source *source = NULL; - const char *name = NULL; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - pa_tagstruct_gets(t, &name) < 0 || - pa_tagstruct_get_boolean(t, &mute) || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); - - if (command == PA_COMMAND_SET_SINK_MUTE) { - if (idx != PA_INVALID_INDEX) - sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); - else - sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); - } else { - assert(command == PA_COMMAND_SET_SOURCE_MUTE); - if (idx != (uint32_t) -1) - source = pa_idxset_get_by_index(c->protocol->core->sources, idx); - else - source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); - } - - CHECK_VALIDITY(c->pstream, sink || source, tag, PA_ERR_NOENTITY); - - if (sink) - pa_sink_set_mute(sink, PA_MIXER_HARDWARE, mute); - else if (source) - pa_source_set_mute(source, PA_MIXER_HARDWARE, mute); - - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - int b; - struct playback_stream *s, *ssync; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - pa_tagstruct_get_boolean(t, &b) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); - s = pa_idxset_get_by_index(c->output_streams, idx); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); - - pa_sink_input_cork(s->sink_input, b); - pa_memblockq_prebuf_force(s->memblockq); - - /* Do the same for all other members in the sync group */ - for (ssync = s->prev; ssync; ssync = ssync->prev) { - pa_sink_input_cork(ssync->sink_input, b); - pa_memblockq_prebuf_force(ssync->memblockq); - } - - for (ssync = s->next; ssync; ssync = ssync->next) { - pa_sink_input_cork(ssync->sink_input, b); - pa_memblockq_prebuf_force(ssync->memblockq); - } - - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_flush_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - struct playback_stream *s, *ssync; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); - s = pa_idxset_get_by_index(c->output_streams, idx); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); - - pa_memblockq_flush(s->memblockq); - s->underrun = 0; - - /* Do the same for all other members in the sync group */ - for (ssync = s->prev; ssync; ssync = ssync->prev) { - pa_memblockq_flush(ssync->memblockq); - ssync->underrun = 0; - } - - for (ssync = s->next; ssync; ssync = ssync->next) { - pa_memblockq_flush(ssync->memblockq); - ssync->underrun = 0; - } - - pa_pstream_send_simple_ack(c->pstream, tag); - pa_sink_notify(s->sink_input->sink); - request_bytes(s); - - for (ssync = s->prev; ssync; ssync = ssync->prev) - request_bytes(ssync); - - for (ssync = s->next; ssync; ssync = ssync->next) - request_bytes(ssync); -} - -static void command_trigger_or_prebuf_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - struct playback_stream *s; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); - s = pa_idxset_get_by_index(c->output_streams, idx); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); - - switch (command) { - case PA_COMMAND_PREBUF_PLAYBACK_STREAM: - pa_memblockq_prebuf_force(s->memblockq); - break; - - case PA_COMMAND_TRIGGER_PLAYBACK_STREAM: - pa_memblockq_prebuf_disable(s->memblockq); - break; - - default: - abort(); - } - - pa_sink_notify(s->sink_input->sink); - pa_pstream_send_simple_ack(c->pstream, tag); - request_bytes(s); -} - -static void command_cork_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - struct record_stream *s; - int b; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - pa_tagstruct_get_boolean(t, &b) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - s = pa_idxset_get_by_index(c->record_streams, idx); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - - pa_source_output_cork(s->source_output, b); - pa_memblockq_prebuf_force(s->memblockq); - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_flush_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - struct record_stream *s; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - s = pa_idxset_get_by_index(c->record_streams, idx); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - - pa_memblockq_flush(s->memblockq); - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_set_default_sink_or_source(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - const char *s; - assert(c && t); - - if (pa_tagstruct_gets(t, &s) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, !s || (*s && pa_utf8_valid(s)), tag, PA_ERR_INVALID); - - pa_namereg_set_default(c->protocol->core, s, command == PA_COMMAND_SET_DEFAULT_SOURCE ? PA_NAMEREG_SOURCE : PA_NAMEREG_SINK); - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - const char *name; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - pa_tagstruct_gets(t, &name) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID); - - if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) { - struct playback_stream *s; - - s = pa_idxset_get_by_index(c->output_streams, idx); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); - - pa_sink_input_set_name(s->sink_input, name); - - } else { - struct record_stream *s; - - s = pa_idxset_get_by_index(c->record_streams, idx); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - - pa_source_output_set_name(s->source_output, name); - } - - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - - if (command == PA_COMMAND_KILL_CLIENT) { - pa_client *client; - - client = pa_idxset_get_by_index(c->protocol->core->clients, idx); - CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY); - pa_client_kill(client); - - } else if (command == PA_COMMAND_KILL_SINK_INPUT) { - pa_sink_input *s; - - s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - - pa_sink_input_kill(s); - } else { - pa_source_output *s; - - assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT); - - s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - - pa_source_output_kill(s); - } - - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_load_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - pa_module *m; - const char *name, *argument; - pa_tagstruct *reply; - assert(c && t); - - if (pa_tagstruct_gets(t, &name) < 0 || - pa_tagstruct_gets(t, &argument) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID); - - if (!(m = pa_module_load(c->protocol->core, name, argument))) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED); - return; - } - - reply = reply_new(tag); - pa_tagstruct_putu32(reply, m->index); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_unload_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - pa_module *m; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - m = pa_idxset_get_by_index(c->protocol->core->modules, idx); - CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY); - - pa_module_unload_request(m); - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void command_add_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - const char *name, *module, *argument; - uint32_t type; - uint32_t idx; - pa_tagstruct *reply; - assert(c && t); - - if (pa_tagstruct_gets(t, &name) < 0 || - pa_tagstruct_getu32(t, &type) < 0 || - pa_tagstruct_gets(t, &module) < 0 || - pa_tagstruct_gets(t, &argument) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, type == 0 || type == 1, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, module && *module && pa_utf8_valid(module), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID); - - if (pa_autoload_add(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, module, argument, &idx) < 0) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); - return; - } - - reply = reply_new(tag); - pa_tagstruct_putu32(reply, idx); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_remove_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - const char *name = NULL; - uint32_t type, idx = PA_IDXSET_INVALID; - int r; - assert(c && t); - - if ((pa_tagstruct_getu32(t, &idx) < 0 && - (pa_tagstruct_gets(t, &name) < 0 || - pa_tagstruct_getu32(t, &type) < 0)) || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name || idx != PA_IDXSET_INVALID, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, !name || (*name && pa_utf8_valid(name) && (type == 0 || type == 1)), tag, PA_ERR_INVALID); - - if (name) - r = pa_autoload_remove_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE); - else - r = pa_autoload_remove_by_index(c->protocol->core, idx); - - CHECK_VALIDITY(c->pstream, r >= 0, tag, PA_ERR_NOENTITY); - - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void autoload_fill_tagstruct(pa_tagstruct *t, const pa_autoload_entry *e) { - assert(t && e); - - pa_tagstruct_putu32(t, e->index); - pa_tagstruct_puts(t, e->name); - pa_tagstruct_putu32(t, e->type == PA_NAMEREG_SINK ? 0 : 1); - pa_tagstruct_puts(t, e->module); - pa_tagstruct_puts(t, e->argument); -} - -static void command_get_autoload_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - const pa_autoload_entry *a = NULL; - uint32_t type, idx; - const char *name; - pa_tagstruct *reply; - assert(c && t); - - if ((pa_tagstruct_getu32(t, &idx) < 0 && - (pa_tagstruct_gets(t, &name) < 0 || - pa_tagstruct_getu32(t, &type) < 0)) || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name || idx != PA_IDXSET_INVALID, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, !name || (*name && (type == 0 || type == 1) && pa_utf8_valid(name)), tag, PA_ERR_INVALID); - - if (name) - a = pa_autoload_get_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE); - else - a = pa_autoload_get_by_index(c->protocol->core, idx); - - CHECK_VALIDITY(c->pstream, a, tag, PA_ERR_NOENTITY); - - reply = reply_new(tag); - autoload_fill_tagstruct(reply, a); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - pa_tagstruct *reply; - assert(c && t); - - if (!pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - - reply = reply_new(tag); - - if (c->protocol->core->autoload_hashmap) { - pa_autoload_entry *a; - void *state = NULL; - - while ((a = pa_hashmap_iterate(c->protocol->core->autoload_hashmap, &state, NULL))) - autoload_fill_tagstruct(reply, a); - } - - pa_pstream_send_tagstruct(c->pstream, reply); -} - -/*** pstream callbacks ***/ - -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const void *creds, void *userdata) { - struct connection *c = userdata; - assert(p && packet && packet->data && c); - - if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) { - pa_log(__FILE__": invalid packet."); - connection_free(c); - } -} - -static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { - struct connection *c = userdata; - struct output_stream *stream; - assert(p && chunk && userdata); - - if (!(stream = pa_idxset_get_by_index(c->output_streams, channel))) { - pa_log(__FILE__": client sent block for invalid stream."); - connection_free(c); - return; - } - - if (stream->type == PLAYBACK_STREAM) { - struct playback_stream *ps = (struct playback_stream*) stream; - if (chunk->length >= ps->requested_bytes) - ps->requested_bytes = 0; - else - ps->requested_bytes -= chunk->length; - - pa_memblockq_seek(ps->memblockq, offset, seek); - - if (pa_memblockq_push_align(ps->memblockq, chunk) < 0) { - pa_tagstruct *t; - - pa_log_warn(__FILE__": failed to push data into queue"); - - /* Pushing this block into the queue failed, so we simulate - * it by skipping ahead */ - - pa_memblockq_seek(ps->memblockq, chunk->length, PA_SEEK_RELATIVE); - - /* Notify the user */ - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW); - pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ - pa_tagstruct_putu32(t, ps->index); - pa_pstream_send_tagstruct(p, t); - } - - ps->underrun = 0; - - pa_sink_notify(ps->sink_input->sink); - - } else { - struct upload_stream *u = (struct upload_stream*) stream; - size_t l; - assert(u->type == UPLOAD_STREAM); - - if (!u->memchunk.memblock) { - if (u->length == chunk->length) { - u->memchunk = *chunk; - pa_memblock_ref(u->memchunk.memblock); - u->length = 0; - } else { - u->memchunk.memblock = pa_memblock_new(u->length, c->protocol->core->memblock_stat); - u->memchunk.index = u->memchunk.length = 0; - } - } - - assert(u->memchunk.memblock); - - l = u->length; - if (l > chunk->length) - l = chunk->length; - - if (l > 0) { - memcpy((uint8_t*) u->memchunk.memblock->data + u->memchunk.index + u->memchunk.length, - (uint8_t*) chunk->memblock->data+chunk->index, l); - u->memchunk.length += l; - u->length -= l; - } - } -} - -static void pstream_die_callback(pa_pstream *p, void *userdata) { - struct connection *c = userdata; - assert(p && c); - connection_free(c); - -/* pa_log(__FILE__": connection died.");*/ -} - - -static void pstream_drain_callback(pa_pstream *p, void *userdata) { - struct connection *c = userdata; - assert(p && c); - - send_memblock(c); -} - -/*** client callbacks ***/ - -static void client_kill_cb(pa_client *c) { - assert(c && c->userdata); - connection_free(c->userdata); -} - -/*** socket server callbacks ***/ - -static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { - struct connection *c = userdata; - assert(m && tv && c && c->auth_timeout_event == e); - - if (!c->authorized) - connection_free(c); -} - -static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, void *userdata) { - pa_protocol_native *p = userdata; - struct connection *c; - char cname[256], pname[128]; - assert(io && p); - - if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log_warn(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); - pa_iochannel_free(io); - return; - } - - c = pa_xmalloc(sizeof(struct connection)); - - c->authorized =!! p->public; - - if (!c->authorized) { - struct timeval tv; - pa_gettimeofday(&tv); - tv.tv_sec += AUTH_TIMEOUT; - c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c); - } else - c->auth_timeout_event = NULL; - - c->version = 8; - c->protocol = p; - pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname)); - snprintf(cname, sizeof(cname), "Native client (%s)", pname); - assert(p->core); - c->client = pa_client_new(p->core, __FILE__, cname); - assert(c->client); - c->client->kill = client_kill_cb; - c->client->userdata = c; - c->client->owner = p->module; - - c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->memblock_stat); - assert(c->pstream); - - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - - c->pdispatch = pa_pdispatch_new(p->core->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); - - c->record_streams = pa_idxset_new(NULL, NULL); - c->output_streams = pa_idxset_new(NULL, NULL); - assert(c->record_streams && c->output_streams); - - c->rrobin_index = PA_IDXSET_INVALID; - c->subscription = NULL; - - pa_idxset_put(p->connections, c, NULL); - - -#ifdef SCM_CREDENTIALS - if (pa_iochannel_creds_supported(io)) - pa_iochannel_creds_enable(io); - -#endif -} - -/*** module entry points ***/ - -static int load_key(pa_protocol_native*p, const char*fn) { - assert(p); - - p->auth_cookie_in_property = 0; - - if (!fn && pa_authkey_prop_get(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) { - pa_log_info(__FILE__": using already loaded auth cookie."); - pa_authkey_prop_ref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); - p->auth_cookie_in_property = 1; - return 0; - } - - if (!fn) - fn = PA_NATIVE_COOKIE_FILE; - - if (pa_authkey_load_auto(fn, p->auth_cookie, sizeof(p->auth_cookie)) < 0) - return -1; - - pa_log_info(__FILE__": loading cookie from disk."); - - if (pa_authkey_prop_put(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) - p->auth_cookie_in_property = 1; - - return 0; -} - -static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_modargs *ma) { - pa_protocol_native *p; - int public = 0; - assert(c && ma); - - if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) { - pa_log(__FILE__": auth-anonymous= expects a boolean argument."); - return NULL; - } - - p = pa_xnew(pa_protocol_native, 1); - p->core = c; - p->module = m; - p->public = public; - p->server = NULL; - -#ifdef SCM_CREDENTIALS - p->auth_group = pa_xstrdup(pa_modargs_get_value(ma, "auth-group", NULL)); -#endif - - if (load_key(p, pa_modargs_get_value(ma, "cookie", NULL)) < 0) { - pa_xfree(p); - return NULL; - } - - p->connections = pa_idxset_new(NULL, NULL); - assert(p->connections); - - return p; -} - -pa_protocol_native* pa_protocol_native_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { - char t[256]; - pa_protocol_native *p; - - if (!(p = protocol_new_internal(core, m, ma))) - return NULL; - - p->server = server; - pa_socket_server_set_callback(p->server, on_connection, p); - - if (pa_socket_server_get_address(p->server, t, sizeof(t))) { - pa_strlist *l; - l = pa_property_get(core, PA_NATIVE_SERVER_PROPERTY_NAME); - l = pa_strlist_prepend(l, t); - pa_property_replace(core, PA_NATIVE_SERVER_PROPERTY_NAME, l); - } - - return p; -} - -void pa_protocol_native_free(pa_protocol_native *p) { - struct connection *c; - assert(p); - - while ((c = pa_idxset_first(p->connections, NULL))) - connection_free(c); - pa_idxset_free(p->connections, NULL, NULL); - - if (p->server) { - char t[256]; - - if (pa_socket_server_get_address(p->server, t, sizeof(t))) { - pa_strlist *l; - l = pa_property_get(p->core, PA_NATIVE_SERVER_PROPERTY_NAME); - l = pa_strlist_remove(l, t); - - if (l) - pa_property_replace(p->core, PA_NATIVE_SERVER_PROPERTY_NAME, l); - else - pa_property_remove(p->core, PA_NATIVE_SERVER_PROPERTY_NAME); - } - - pa_socket_server_unref(p->server); - } - - if (p->auth_cookie_in_property) - pa_authkey_prop_unref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); - -#ifdef SCM_CREDENTIALS - pa_xfree(p->auth_group); -#endif - pa_xfree(p); -} - -pa_protocol_native* pa_protocol_native_new_iochannel(pa_core*core, pa_iochannel *io, pa_module *m, pa_modargs *ma) { - pa_protocol_native *p; - - if (!(p = protocol_new_internal(core, m, ma))) - return NULL; - - on_connection(NULL, io, p); - - return p; -} diff --git a/src/polypcore/protocol-native.h b/src/polypcore/protocol-native.h deleted file mode 100644 index 88aa8494..00000000 --- a/src/polypcore/protocol-native.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef fooprotocolnativehfoo -#define fooprotocolnativehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include - -typedef struct pa_protocol_native pa_protocol_native; - -pa_protocol_native* pa_protocol_native_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma); -void pa_protocol_native_free(pa_protocol_native *n); - -pa_protocol_native* pa_protocol_native_new_iochannel(pa_core*core, pa_iochannel *io, pa_module *m, pa_modargs *ma); - -#endif diff --git a/src/polypcore/protocol-simple.c b/src/polypcore/protocol-simple.c deleted file mode 100644 index 8b319d70..00000000 --- a/src/polypcore/protocol-simple.c +++ /dev/null @@ -1,494 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "protocol-simple.h" - -/* Don't allow more than this many concurrent connections */ -#define MAX_CONNECTIONS 10 - -struct connection { - pa_protocol_simple *protocol; - pa_iochannel *io; - pa_sink_input *sink_input; - pa_source_output *source_output; - pa_client *client; - pa_memblockq *input_memblockq, *output_memblockq; - pa_defer_event *defer_event; - - int dead; - - struct { - pa_memblock *current_memblock; - size_t memblock_index, fragment_size; - } playback; -}; - -struct pa_protocol_simple { - pa_module *module; - pa_core *core; - pa_socket_server*server; - pa_idxset *connections; - enum { - RECORD = 1, - PLAYBACK = 2, - DUPLEX = 3 - } mode; - pa_sample_spec sample_spec; - char *source_name, *sink_name; -}; - -#define PLAYBACK_BUFFER_SECONDS (.5) -#define PLAYBACK_BUFFER_FRAGMENTS (10) -#define RECORD_BUFFER_SECONDS (5) -#define RECORD_BUFFER_FRAGMENTS (100) - -static void connection_free(struct connection *c) { - assert(c); - - pa_idxset_remove_by_data(c->protocol->connections, c, NULL); - - if (c->playback.current_memblock) - pa_memblock_unref(c->playback.current_memblock); - if (c->sink_input) { - pa_sink_input_disconnect(c->sink_input); - pa_sink_input_unref(c->sink_input); - } - if (c->source_output) { - pa_source_output_disconnect(c->source_output); - pa_source_output_unref(c->source_output); - } - if (c->client) - pa_client_free(c->client); - if (c->io) - pa_iochannel_free(c->io); - if (c->input_memblockq) - pa_memblockq_free(c->input_memblockq); - if (c->output_memblockq) - pa_memblockq_free(c->output_memblockq); - if (c->defer_event) - c->protocol->core->mainloop->defer_free(c->defer_event); - pa_xfree(c); -} - -static int do_read(struct connection *c) { - pa_memchunk chunk; - ssize_t r; - size_t l; - - if (!c->sink_input || !(l = pa_memblockq_missing(c->input_memblockq))) - return 0; - - if (l > c->playback.fragment_size) - l = c->playback.fragment_size; - - if (c->playback.current_memblock) - if (c->playback.current_memblock->length - c->playback.memblock_index < l) { - pa_memblock_unref(c->playback.current_memblock); - c->playback.current_memblock = NULL; - c->playback.memblock_index = 0; - } - - if (!c->playback.current_memblock) { - c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2, c->protocol->core->memblock_stat); - assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); - c->playback.memblock_index = 0; - } - - if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { - pa_log_debug(__FILE__": read(): %s", r == 0 ? "EOF" : pa_cstrerror(errno)); - return -1; - } - - chunk.memblock = c->playback.current_memblock; - chunk.index = c->playback.memblock_index; - chunk.length = r; - assert(chunk.memblock); - - c->playback.memblock_index += r; - - assert(c->input_memblockq); - pa_memblockq_push_align(c->input_memblockq, &chunk); - assert(c->sink_input); - pa_sink_notify(c->sink_input->sink); - - return 0; -} - -static int do_write(struct connection *c) { - pa_memchunk chunk; - ssize_t r; - - if (!c->source_output) - return 0; - - assert(c->output_memblockq); - if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) - return 0; - - assert(chunk.memblock && chunk.length); - - if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { - pa_memblock_unref(chunk.memblock); - pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); - return -1; - } - - pa_memblockq_drop(c->output_memblockq, &chunk, r); - pa_memblock_unref(chunk.memblock); - - pa_source_notify(c->source_output->source); - - return 0; -} - -static void do_work(struct connection *c) { - assert(c); - - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - c->protocol->core->mainloop->defer_enable(c->defer_event, 0); - - if (c->dead) - return; - - if (pa_iochannel_is_readable(c->io)) { - if (do_read(c) < 0) - goto fail; - } else if (pa_iochannel_is_hungup(c->io)) - goto fail; - - if (pa_iochannel_is_writable(c->io)) { - if (do_write(c) < 0) - goto fail; - } - - return; - -fail: - - if (c->sink_input) { - c->dead = 1; - - pa_iochannel_free(c->io); - c->io = NULL; - - pa_memblockq_prebuf_disable(c->input_memblockq); - pa_sink_notify(c->sink_input->sink); - } else - connection_free(c); -} - -/*** sink_input callbacks ***/ - -static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { - struct connection*c; - assert(i && i->userdata && chunk); - c = i->userdata; - - if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) { - - if (c->dead) - connection_free(c); - - return -1; - } - - return 0; -} - -static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { - struct connection*c = i->userdata; - assert(i && c && length); - - pa_memblockq_drop(c->input_memblockq, chunk, length); - - /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); -} - -static void sink_input_kill_cb(pa_sink_input *i) { - assert(i && i->userdata); - connection_free((struct connection *) i->userdata); -} - - -static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { - struct connection*c = i->userdata; - assert(i && c); - return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); -} - -/*** source_output callbacks ***/ - -static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { - struct connection *c = o->userdata; - assert(o && c && chunk); - - pa_memblockq_push(c->output_memblockq, chunk); - - /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); -} - -static void source_output_kill_cb(pa_source_output *o) { - assert(o && o->userdata); - connection_free((struct connection *) o->userdata); -} - -static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { - struct connection*c = o->userdata; - assert(o && c); - return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec); -} - -/*** client callbacks ***/ - -static void client_kill_cb(pa_client *c) { - assert(c && c->userdata); - connection_free((struct connection *) c->userdata); -} - -/*** pa_iochannel callbacks ***/ - -static void io_callback(pa_iochannel*io, void *userdata) { - struct connection *c = userdata; - assert(io && c && c->io == io); - - do_work(c); -} - -/*** fixed callback ***/ - -static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { - struct connection *c = userdata; - assert(a && c && c->defer_event == e); - - do_work(c); -} - -/*** socket_server callbacks ***/ - -static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { - pa_protocol_simple *p = userdata; - struct connection *c = NULL; - char cname[256]; - assert(s && io && p); - - if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); - pa_iochannel_free(io); - return; - } - - c = pa_xmalloc(sizeof(struct connection)); - c->io = io; - c->sink_input = NULL; - c->source_output = NULL; - c->defer_event = NULL; - c->input_memblockq = c->output_memblockq = NULL; - c->protocol = p; - c->playback.current_memblock = NULL; - c->playback.memblock_index = 0; - c->playback.fragment_size = 0; - c->dead = 0; - - pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); - c->client = pa_client_new(p->core, __FILE__, cname); - assert(c->client); - c->client->owner = p->module; - c->client->kill = client_kill_cb; - c->client->userdata = c; - - if (p->mode & PLAYBACK) { - pa_sink *sink; - size_t l; - - if (!(sink = pa_namereg_get(p->core, p->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": Failed to get sink."); - goto fail; - } - - if (!(c->sink_input = pa_sink_input_new(sink, __FILE__, c->client->name, &p->sample_spec, NULL, NULL, 0, -1))) { - pa_log(__FILE__": Failed to create sink input."); - goto fail; - } - - c->sink_input->owner = p->module; - c->sink_input->client = c->client; - - c->sink_input->peek = sink_input_peek_cb; - c->sink_input->drop = sink_input_drop_cb; - c->sink_input->kill = sink_input_kill_cb; - c->sink_input->get_latency = sink_input_get_latency_cb; - c->sink_input->userdata = c; - - l = (size_t) (pa_bytes_per_second(&p->sample_spec)*PLAYBACK_BUFFER_SECONDS); - c->input_memblockq = pa_memblockq_new( - 0, - l, - 0, - pa_frame_size(&p->sample_spec), - (size_t) -1, - l/PLAYBACK_BUFFER_FRAGMENTS, - NULL, - p->core->memblock_stat); - assert(c->input_memblockq); - pa_iochannel_socket_set_rcvbuf(io, l/PLAYBACK_BUFFER_FRAGMENTS*5); - c->playback.fragment_size = l/10; - } - - if (p->mode & RECORD) { - pa_source *source; - size_t l; - - if (!(source = pa_namereg_get(p->core, p->source_name, PA_NAMEREG_SOURCE, 1))) { - pa_log(__FILE__": Failed to get source."); - goto fail; - } - - c->source_output = pa_source_output_new(source, __FILE__, c->client->name, &p->sample_spec, NULL, -1); - if (!c->source_output) { - pa_log(__FILE__": Failed to create source output."); - goto fail; - } - c->source_output->owner = p->module; - c->source_output->client = c->client; - - c->source_output->push = source_output_push_cb; - c->source_output->kill = source_output_kill_cb; - c->source_output->get_latency = source_output_get_latency_cb; - c->source_output->userdata = c; - - l = (size_t) (pa_bytes_per_second(&p->sample_spec)*RECORD_BUFFER_SECONDS); - c->output_memblockq = pa_memblockq_new( - 0, - l, - 0, - pa_frame_size(&p->sample_spec), - 1, - 0, - NULL, - p->core->memblock_stat); - pa_iochannel_socket_set_sndbuf(io, l/RECORD_BUFFER_FRAGMENTS*2); - } - - pa_iochannel_set_callback(c->io, io_callback, c); - pa_idxset_put(p->connections, c, NULL); - - c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c); - assert(c->defer_event); - p->core->mainloop->defer_enable(c->defer_event, 0); - - return; - -fail: - if (c) - connection_free(c); -} - -pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { - pa_protocol_simple* p = NULL; - int enable; - assert(core && server && ma); - - p = pa_xmalloc0(sizeof(pa_protocol_simple)); - p->module = m; - p->core = core; - p->server = server; - p->connections = pa_idxset_new(NULL, NULL); - - p->sample_spec = core->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &p->sample_spec) < 0) { - pa_log(__FILE__": Failed to parse sample type specification."); - goto fail; - } - - p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL)); - p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); - - enable = 0; - if (pa_modargs_get_value_boolean(ma, "record", &enable) < 0) { - pa_log(__FILE__": record= expects a numeric argument."); - goto fail; - } - p->mode = enable ? RECORD : 0; - - enable = 1; - if (pa_modargs_get_value_boolean(ma, "playback", &enable) < 0) { - pa_log(__FILE__": playback= expects a numeric argument."); - goto fail; - } - p->mode |= enable ? PLAYBACK : 0; - - if ((p->mode & (RECORD|PLAYBACK)) == 0) { - pa_log(__FILE__": neither playback nor recording enabled for protocol."); - goto fail; - } - - pa_socket_server_set_callback(p->server, on_connection, p); - - return p; - -fail: - if (p) - pa_protocol_simple_free(p); - return NULL; -} - - -void pa_protocol_simple_free(pa_protocol_simple *p) { - struct connection *c; - assert(p); - - if (p->connections) { - while((c = pa_idxset_first(p->connections, NULL))) - connection_free(c); - - pa_idxset_free(p->connections, NULL, NULL); - } - - if (p->server) - pa_socket_server_unref(p->server); - pa_xfree(p); -} - diff --git a/src/polypcore/protocol-simple.h b/src/polypcore/protocol-simple.h deleted file mode 100644 index f11c7759..00000000 --- a/src/polypcore/protocol-simple.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef fooprotocolsimplehfoo -#define fooprotocolsimplehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include - -typedef struct pa_protocol_simple pa_protocol_simple; - -pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma); -void pa_protocol_simple_free(pa_protocol_simple *n); - -#endif diff --git a/src/polypcore/pstream-util.c b/src/polypcore/pstream-util.c deleted file mode 100644 index bd1d1a87..00000000 --- a/src/polypcore/pstream-util.c +++ /dev/null @@ -1,62 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include - -#include "pstream-util.h" - -void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, int creds) { - size_t length; - uint8_t *data; - pa_packet *packet; - assert(p); - assert(t); - - data = pa_tagstruct_free_data(t, &length); - assert(data && length); - packet = pa_packet_new_dynamic(data, length); - assert(packet); - pa_pstream_send_packet(p, packet, creds); - pa_packet_unref(packet); -} - -void pa_pstream_send_error(pa_pstream *p, uint32_t tag, uint32_t error) { - pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_ERROR); - pa_tagstruct_putu32(t, tag); - pa_tagstruct_putu32(t, error); - pa_pstream_send_tagstruct(p, t); -} - -void pa_pstream_send_simple_ack(pa_pstream *p, uint32_t tag) { - pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REPLY); - pa_tagstruct_putu32(t, tag); - pa_pstream_send_tagstruct(p, t); -} diff --git a/src/polypcore/pstream-util.h b/src/polypcore/pstream-util.h deleted file mode 100644 index f2677a44..00000000 --- a/src/polypcore/pstream-util.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef foopstreamutilhfoo -#define foopstreamutilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include - -/* The tagstruct is freed!*/ -void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, int creds); - -#define pa_pstream_send_tagstruct(p, t) pa_pstream_send_tagstruct_with_creds((p), (t), 0) - -void pa_pstream_send_error(pa_pstream *p, uint32_t tag, uint32_t error); -void pa_pstream_send_simple_ack(pa_pstream *p, uint32_t tag); - -#endif diff --git a/src/polypcore/pstream.c b/src/polypcore/pstream.c deleted file mode 100644 index 074cab91..00000000 --- a/src/polypcore/pstream.c +++ /dev/null @@ -1,589 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#ifdef HAVE_NETINET_IN_H -#include -#endif - -#include "winsock.h" - -#include - -#include -#include -#include - -#include "pstream.h" - -enum { - PA_PSTREAM_DESCRIPTOR_LENGTH, - PA_PSTREAM_DESCRIPTOR_CHANNEL, - PA_PSTREAM_DESCRIPTOR_OFFSET_HI, - PA_PSTREAM_DESCRIPTOR_OFFSET_LO, - PA_PSTREAM_DESCRIPTOR_SEEK, - PA_PSTREAM_DESCRIPTOR_MAX -}; - -typedef uint32_t pa_pstream_descriptor[PA_PSTREAM_DESCRIPTOR_MAX]; - -#define PA_PSTREAM_DESCRIPTOR_SIZE (PA_PSTREAM_DESCRIPTOR_MAX*sizeof(uint32_t)) -#define FRAME_SIZE_MAX PA_SCACHE_ENTRY_SIZE_MAX /* allow uploading a single sample in one frame at max */ - -struct item_info { - enum { PA_PSTREAM_ITEM_PACKET, PA_PSTREAM_ITEM_MEMBLOCK } type; - - /* memblock info */ - pa_memchunk chunk; - uint32_t channel; - int64_t offset; - pa_seek_mode_t seek_mode; - - /* packet info */ - pa_packet *packet; -#ifdef SCM_CREDENTIALS - int with_creds; -#endif -}; - -struct pa_pstream { - int ref; - - pa_mainloop_api *mainloop; - pa_defer_event *defer_event; - pa_iochannel *io; - pa_queue *send_queue; - - int dead; - - struct { - struct item_info* current; - pa_pstream_descriptor descriptor; - void *data; - size_t index; - } write; - - struct { - pa_memblock *memblock; - pa_packet *packet; - pa_pstream_descriptor descriptor; - void *data; - size_t index; - } read; - - pa_pstream_packet_cb_t recieve_packet_callback; - void *recieve_packet_callback_userdata; - - pa_pstream_memblock_cb_t recieve_memblock_callback; - void *recieve_memblock_callback_userdata; - - pa_pstream_notify_cb_t drain_callback; - void *drain_callback_userdata; - - pa_pstream_notify_cb_t die_callback; - void *die_callback_userdata; - - pa_memblock_stat *memblock_stat; - -#ifdef SCM_CREDENTIALS - int send_creds_now; - struct ucred ucred; - int creds_valid; -#endif -}; - -static int do_write(pa_pstream *p); -static int do_read(pa_pstream *p); - -static void do_something(pa_pstream *p) { - assert(p); - - p->mainloop->defer_enable(p->defer_event, 0); - - pa_pstream_ref(p); - - if (!p->dead && pa_iochannel_is_readable(p->io)) { - if (do_read(p) < 0) - goto fail; - } else if (!p->dead && pa_iochannel_is_hungup(p->io)) - goto fail; - - if (!p->dead && pa_iochannel_is_writable(p->io)) { - if (do_write(p) < 0) - goto fail; - } - - pa_pstream_unref(p); - return; - -fail: - - p->dead = 1; - - if (p->die_callback) - p->die_callback(p, p->die_callback_userdata); - - pa_pstream_unref(p); -} - -static void io_callback(pa_iochannel*io, void *userdata) { - pa_pstream *p = userdata; - - assert(p); - assert(p->io == io); - - do_something(p); -} - -static void defer_callback(pa_mainloop_api *m, pa_defer_event *e, void*userdata) { - pa_pstream *p = userdata; - - assert(p); - assert(p->defer_event == e); - assert(p->mainloop == m); - - do_something(p); -} - -pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_stat *s) { - pa_pstream *p; - assert(io); - - p = pa_xnew(pa_pstream, 1); - - p->ref = 1; - p->io = io; - pa_iochannel_set_callback(io, io_callback, p); - - p->dead = 0; - - p->mainloop = m; - p->defer_event = m->defer_new(m, defer_callback, p); - m->defer_enable(p->defer_event, 0); - - p->send_queue = pa_queue_new(); - assert(p->send_queue); - - p->write.current = NULL; - p->write.index = 0; - - p->read.memblock = NULL; - p->read.packet = NULL; - p->read.index = 0; - - p->recieve_packet_callback = NULL; - p->recieve_packet_callback_userdata = NULL; - - p->recieve_memblock_callback = NULL; - p->recieve_memblock_callback_userdata = NULL; - - p->drain_callback = NULL; - p->drain_callback_userdata = NULL; - - p->die_callback = NULL; - p->die_callback_userdata = NULL; - - p->memblock_stat = s; - - pa_iochannel_socket_set_rcvbuf(io, 1024*8); - pa_iochannel_socket_set_sndbuf(io, 1024*8); - -#ifdef SCM_CREDENTIALS - p->send_creds_now = 0; - p->creds_valid = 0; -#endif - return p; -} - -static void item_free(void *item, PA_GCC_UNUSED void *p) { - struct item_info *i = item; - assert(i); - - if (i->type == PA_PSTREAM_ITEM_MEMBLOCK) { - assert(i->chunk.memblock); - pa_memblock_unref(i->chunk.memblock); - } else { - assert(i->type == PA_PSTREAM_ITEM_PACKET); - assert(i->packet); - pa_packet_unref(i->packet); - } - - pa_xfree(i); -} - -static void pstream_free(pa_pstream *p) { - assert(p); - - pa_pstream_close(p); - - pa_queue_free(p->send_queue, item_free, NULL); - - if (p->write.current) - item_free(p->write.current, NULL); - - if (p->read.memblock) - pa_memblock_unref(p->read.memblock); - - if (p->read.packet) - pa_packet_unref(p->read.packet); - - pa_xfree(p); -} - -void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, int with_creds) { - struct item_info *i; - assert(p && packet && p->ref >= 1); - - if (p->dead) - return; - -/* pa_log(__FILE__": push-packet %p", packet); */ - - i = pa_xnew(struct item_info, 1); - i->type = PA_PSTREAM_ITEM_PACKET; - i->packet = pa_packet_ref(packet); -#ifdef SCM_CREDENTIALS - i->with_creds = with_creds; -#endif - - pa_queue_push(p->send_queue, i); - p->mainloop->defer_enable(p->defer_event, 1); -} - -void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek_mode, const pa_memchunk *chunk) { - struct item_info *i; - assert(p && channel != (uint32_t) -1 && chunk && p->ref >= 1); - - if (p->dead) - return; - -/* pa_log(__FILE__": push-memblock %p", chunk); */ - - i = pa_xnew(struct item_info, 1); - i->type = PA_PSTREAM_ITEM_MEMBLOCK; - i->chunk = *chunk; - i->channel = channel; - i->offset = offset; - i->seek_mode = seek_mode; - - pa_memblock_ref(i->chunk.memblock); - - pa_queue_push(p->send_queue, i); - p->mainloop->defer_enable(p->defer_event, 1); -} - -static void prepare_next_write_item(pa_pstream *p) { - assert(p); - - if (!(p->write.current = pa_queue_pop(p->send_queue))) - return; - - p->write.index = 0; - - if (p->write.current->type == PA_PSTREAM_ITEM_PACKET) { - /*pa_log(__FILE__": pop-packet %p", p->write.current->packet);*/ - - assert(p->write.current->packet); - p->write.data = p->write.current->packet->data; - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->packet->length); - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl((uint32_t) -1); - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = 0; - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = 0; - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK] = 0; - -#ifdef SCM_CREDENTIALS - p->send_creds_now = 1; -#endif - - } else { - assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK && p->write.current->chunk.memblock); - p->write.data = (uint8_t*) p->write.current->chunk.memblock->data + p->write.current->chunk.index; - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length); - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl(p->write.current->channel); - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = htonl((uint32_t) (((uint64_t) p->write.current->offset) >> 32)); - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = htonl((uint32_t) ((uint64_t) p->write.current->offset)); - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK] = htonl(p->write.current->seek_mode); - -#ifdef SCM_CREDENTIALS - p->send_creds_now = 1; -#endif - } -} - -static int do_write(pa_pstream *p) { - void *d; - size_t l; - ssize_t r; - assert(p); - - if (!p->write.current) - prepare_next_write_item(p); - - if (!p->write.current) - return 0; - - assert(p->write.data); - - if (p->write.index < PA_PSTREAM_DESCRIPTOR_SIZE) { - d = (uint8_t*) p->write.descriptor + p->write.index; - l = PA_PSTREAM_DESCRIPTOR_SIZE - p->write.index; - } else { - d = (uint8_t*) p->write.data + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE; - l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE); - } - -#ifdef SCM_CREDENTIALS - if (p->send_creds_now) { - - if ((r = pa_iochannel_write_with_creds(p->io, d, l)) < 0) - return -1; - - p->send_creds_now = 0; - } else -#endif - - if ((r = pa_iochannel_write(p->io, d, l)) < 0) - return -1; - - p->write.index += r; - - if (p->write.index >= PA_PSTREAM_DESCRIPTOR_SIZE+ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])) { - assert(p->write.current); - item_free(p->write.current, (void *) 1); - p->write.current = NULL; - - if (p->drain_callback && !pa_pstream_is_pending(p)) - p->drain_callback(p, p->drain_callback_userdata); - } - - return 0; -} - -static int do_read(pa_pstream *p) { - void *d; - size_t l; - ssize_t r; - assert(p); - - if (p->read.index < PA_PSTREAM_DESCRIPTOR_SIZE) { - d = (uint8_t*) p->read.descriptor + p->read.index; - l = PA_PSTREAM_DESCRIPTOR_SIZE - p->read.index; - } else { - assert(p->read.data); - d = (uint8_t*) p->read.data + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE; - l = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE); - } - -#ifdef SCM_CREDENTIALS - { - int b; - - if ((r = pa_iochannel_read_with_creds(p->io, d, l, &p->ucred, &b)) <= 0) - return -1; - - p->creds_valid = p->creds_valid || b; - } -#else - if ((r = pa_iochannel_read(p->io, d, l)) <= 0) - return -1; -#endif - - p->read.index += r; - - if (p->read.index == PA_PSTREAM_DESCRIPTOR_SIZE) { - /* Reading of frame descriptor complete */ - - /* Frame size too large */ - if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) > FRAME_SIZE_MAX) { - pa_log_warn(__FILE__": Frame size too large: %lu > %lu", (unsigned long) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]), (unsigned long) FRAME_SIZE_MAX); - return -1; - } - - assert(!p->read.packet && !p->read.memblock); - - if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]) == (uint32_t) -1) { - /* Frame is a packet frame */ - p->read.packet = pa_packet_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])); - p->read.data = p->read.packet->data; - } else { - /* Frame is a memblock frame */ - p->read.memblock = pa_memblock_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]), p->memblock_stat); - p->read.data = p->read.memblock->data; - - if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK]) > PA_SEEK_RELATIVE_END) { - pa_log_warn(__FILE__": Invalid seek mode"); - return -1; - } - } - - } else if (p->read.index > PA_PSTREAM_DESCRIPTOR_SIZE) { - /* Frame payload available */ - - if (p->read.memblock && p->recieve_memblock_callback) { /* Is this memblock data? Than pass it to the user */ - l = (p->read.index - r) < PA_PSTREAM_DESCRIPTOR_SIZE ? p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE : (size_t) r; - - if (l > 0) { - pa_memchunk chunk; - - chunk.memblock = p->read.memblock; - chunk.index = p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE - l; - chunk.length = l; - - if (p->recieve_memblock_callback) { - int64_t offset; - - offset = (int64_t) ( - (((uint64_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])) << 32) | - (((uint64_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO])))); - - p->recieve_memblock_callback( - p, - ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]), - offset, - ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK]), - &chunk, - p->recieve_memblock_callback_userdata); - } - - /* Drop seek info for following callbacks */ - p->read.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK] = - p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = - p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = 0; - } - } - - /* Frame complete */ - if (p->read.index >= ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) + PA_PSTREAM_DESCRIPTOR_SIZE) { - if (p->read.memblock) { - assert(!p->read.packet); - - pa_memblock_unref(p->read.memblock); - p->read.memblock = NULL; - } else { - assert(p->read.packet); - - if (p->recieve_packet_callback) -#ifdef SCM_CREDENTIALS - p->recieve_packet_callback(p, p->read.packet, p->creds_valid ? &p->ucred : NULL, p->recieve_packet_callback_userdata); -#else - p->recieve_packet_callback(p, p->read.packet, NULL, p->recieve_packet_callback_userdata); -#endif - - pa_packet_unref(p->read.packet); - p->read.packet = NULL; - } - - p->read.index = 0; -#ifdef SCM_CREDENTIALS - p->creds_valid = 0; -#endif - } - } - - return 0; -} - -void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) { - assert(p); - assert(p->ref >= 1); - - p->die_callback = cb; - p->die_callback_userdata = userdata; -} - - -void pa_pstream_set_drain_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) { - assert(p); - assert(p->ref >= 1); - - p->drain_callback = cb; - p->drain_callback_userdata = userdata; -} - -void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata) { - assert(p); - assert(p->ref >= 1); - - p->recieve_packet_callback = cb; - p->recieve_packet_callback_userdata = userdata; -} - -void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, pa_pstream_memblock_cb_t cb, void *userdata) { - assert(p); - assert(p->ref >= 1); - - p->recieve_memblock_callback = cb; - p->recieve_memblock_callback_userdata = userdata; -} - -int pa_pstream_is_pending(pa_pstream *p) { - assert(p); - - if (p->dead) - return 0; - - return p->write.current || !pa_queue_is_empty(p->send_queue); -} - -void pa_pstream_unref(pa_pstream*p) { - assert(p); - assert(p->ref >= 1); - - if (--p->ref == 0) - pstream_free(p); -} - -pa_pstream* pa_pstream_ref(pa_pstream*p) { - assert(p); - assert(p->ref >= 1); - - p->ref++; - return p; -} - -void pa_pstream_close(pa_pstream *p) { - assert(p); - - p->dead = 1; - - if (p->io) { - pa_iochannel_free(p->io); - p->io = NULL; - } - - if (p->defer_event) { - p->mainloop->defer_free(p->defer_event); - p->defer_event = NULL; - } - - p->die_callback = NULL; - p->drain_callback = NULL; - p->recieve_packet_callback = NULL; - p->recieve_memblock_callback = NULL; -} diff --git a/src/polypcore/pstream.h b/src/polypcore/pstream.h deleted file mode 100644 index feb1b151..00000000 --- a/src/polypcore/pstream.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef foopstreamhfoo -#define foopstreamhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include -#include -#include -#include -#include -#include - -typedef struct pa_pstream pa_pstream; - -typedef void (*pa_pstream_packet_cb_t)(pa_pstream *p, pa_packet *packet, const void *creds, void *userdata); -typedef void (*pa_pstream_memblock_cb_t)(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata); -typedef void (*pa_pstream_notify_cb_t)(pa_pstream *p, void *userdata); - -pa_pstream* pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_stat *s); -void pa_pstream_unref(pa_pstream*p); -pa_pstream* pa_pstream_ref(pa_pstream*p); - -void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, int with_creds); -void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk); - -void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata); -void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, pa_pstream_memblock_cb_t cb, void *userdata); -void pa_pstream_set_drain_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata); - -void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata); - -int pa_pstream_is_pending(pa_pstream *p); - -void pa_pstream_close(pa_pstream *p); - -#endif diff --git a/src/polypcore/queue.c b/src/polypcore/queue.c deleted file mode 100644 index 01f957d9..00000000 --- a/src/polypcore/queue.c +++ /dev/null @@ -1,109 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include - -#include "queue.h" - -struct queue_entry { - struct queue_entry *next; - void *data; -}; - -struct pa_queue { - struct queue_entry *front, *back; - unsigned length; -}; - -pa_queue* pa_queue_new(void) { - pa_queue *q = pa_xnew(pa_queue, 1); - q->front = q->back = NULL; - q->length = 0; - return q; -} - -void pa_queue_free(pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata) { - struct queue_entry *e; - assert(q); - - e = q->front; - while (e) { - struct queue_entry *n = e->next; - - if (destroy) - destroy(e->data, userdata); - - pa_xfree(e); - e = n; - } - - pa_xfree(q); -} - -void pa_queue_push(pa_queue *q, void *p) { - struct queue_entry *e; - - e = pa_xnew(struct queue_entry, 1); - e->data = p; - e->next = NULL; - - if (q->back) - q->back->next = e; - else { - assert(!q->front); - q->front = e; - } - - q->back = e; - q->length++; -} - -void* pa_queue_pop(pa_queue *q) { - void *p; - struct queue_entry *e; - assert(q); - - if (!(e = q->front)) - return NULL; - - q->front = e->next; - if (q->back == e) - q->back = NULL; - - p = e->data; - pa_xfree(e); - - q->length--; - - return p; -} - -int pa_queue_is_empty(pa_queue *q) { - assert(q); - return q->length == 0; -} diff --git a/src/polypcore/queue.h b/src/polypcore/queue.h deleted file mode 100644 index 3edcfb63..00000000 --- a/src/polypcore/queue.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef fooqueuehfoo -#define fooqueuehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -typedef struct pa_queue pa_queue; - -/* A simple implementation of the abstract data type queue. Stores - * pointers as members. The memory has to be managed by the caller. */ - -pa_queue* pa_queue_new(void); - -/* Free the queue and run the specified callback function for every remaining entry. The callback function may be NULL. */ -void pa_queue_free(pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata); - -void pa_queue_push(pa_queue *q, void *p); -void* pa_queue_pop(pa_queue *q); - -int pa_queue_is_empty(pa_queue *q); - -#endif diff --git a/src/polypcore/random.c b/src/polypcore/random.c deleted file mode 100644 index d7a37b0b..00000000 --- a/src/polypcore/random.c +++ /dev/null @@ -1,108 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "random.h" - -static int has_whined = 0; - -static const char *devices[] = { "/dev/urandom", "/dev/random", NULL }; - -static int random_proper(void *ret_data, size_t length) { -#ifdef OS_IS_WIN32 - assert(ret_data && length); - - return -1; - -#else /* OS_IS_WIN32 */ - - int fd, ret = -1; - ssize_t r = 0; - const char **device; - - assert(ret_data && length); - - device = devices; - - while (*device) { - ret = 0; - - if ((fd = open(*device, O_RDONLY)) >= 0) { - - if ((r = pa_loop_read(fd, ret_data, length)) < 0 || (size_t) r != length) - ret = -1; - - close(fd); - } else - ret = -1; - - if (ret == 0) - break; - } - - return ret; -#endif /* OS_IS_WIN32 */ -} - -void pa_random_seed(void) { - unsigned int seed; - - if (random_proper(&seed, sizeof(unsigned int)) < 0) { - if (!has_whined) - pa_log_warn(__FILE__": failed to get proper entropy. Falling back to seeding with current time."); - has_whined = 1; - - seed = (unsigned int) time(NULL); - } - - srand(seed); -} - -void pa_random(void *ret_data, size_t length) { - uint8_t *p; - size_t l; - - assert(ret_data && length); - - if (random_proper(ret_data, length) >= 0) - return; - - if (!has_whined) - pa_log_warn(__FILE__": failed to get proper entropy. Falling back to unsecure pseudo RNG."); - has_whined = 1; - - for (p = ret_data, l = length; l > 0; p++, l--) - *p = (uint8_t) rand(); -} diff --git a/src/polypcore/random.h b/src/polypcore/random.h deleted file mode 100644 index 1f152dc7..00000000 --- a/src/polypcore/random.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef foorandomhfoo -#define foorandomhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -void pa_random_seed(void); -void pa_random(void *ret_data, size_t length); - -#endif diff --git a/src/polypcore/resampler.c b/src/polypcore/resampler.c deleted file mode 100644 index 33e8c295..00000000 --- a/src/polypcore/resampler.c +++ /dev/null @@ -1,618 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include -#include -#include - -#include - -#include -#include - -#include "resampler.h" - -struct pa_resampler { - pa_resample_method_t resample_method; - pa_sample_spec i_ss, o_ss; - pa_channel_map i_cm, o_cm; - size_t i_fz, o_fz; - pa_memblock_stat *memblock_stat; - - void (*impl_free)(pa_resampler *r); - void (*impl_update_input_rate)(pa_resampler *r, uint32_t rate); - void (*impl_run)(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out); - void *impl_data; -}; - -struct impl_libsamplerate { - float* buf1, *buf2, *buf3, *buf4; - unsigned buf1_samples, buf2_samples, buf3_samples, buf4_samples; - - pa_convert_to_float32ne_func_t to_float32ne_func; - pa_convert_from_float32ne_func_t from_float32ne_func; - SRC_STATE *src_state; - - int map_table[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; - int map_required; -}; - -struct impl_trivial { - unsigned o_counter; - unsigned i_counter; -}; - -static int libsamplerate_init(pa_resampler*r); -static int trivial_init(pa_resampler*r); - -pa_resampler* pa_resampler_new( - const pa_sample_spec *a, - const pa_channel_map *am, - const pa_sample_spec *b, - const pa_channel_map *bm, - pa_memblock_stat *s, - pa_resample_method_t resample_method) { - - pa_resampler *r = NULL; - - assert(a); - assert(b); - assert(pa_sample_spec_valid(a)); - assert(pa_sample_spec_valid(b)); - assert(resample_method != PA_RESAMPLER_INVALID); - - r = pa_xnew(pa_resampler, 1); - r->impl_data = NULL; - r->memblock_stat = s; - r->resample_method = resample_method; - - r->impl_free = NULL; - r->impl_update_input_rate = NULL; - r->impl_run = NULL; - - /* Fill sample specs */ - r->i_ss = *a; - r->o_ss = *b; - - if (am) - r->i_cm = *am; - else - pa_channel_map_init_auto(&r->i_cm, r->i_ss.channels, PA_CHANNEL_MAP_DEFAULT); - - if (bm) - r->o_cm = *bm; - else - pa_channel_map_init_auto(&r->o_cm, r->o_ss.channels, PA_CHANNEL_MAP_DEFAULT); - - r->i_fz = pa_frame_size(a); - r->o_fz = pa_frame_size(b); - - /* Choose implementation */ - if (a->channels != b->channels || - a->format != b->format || - !pa_channel_map_equal(&r->i_cm, &r->o_cm) || - resample_method != PA_RESAMPLER_TRIVIAL) { - - /* Use the libsamplerate based resampler for the complicated cases */ - if (resample_method == PA_RESAMPLER_TRIVIAL) - r->resample_method = PA_RESAMPLER_SRC_ZERO_ORDER_HOLD; - - if (libsamplerate_init(r) < 0) - goto fail; - - } else { - /* Use our own simple non-fp resampler for the trivial cases and when the user selects it */ - if (trivial_init(r) < 0) - goto fail; - } - - return r; - -fail: - if (r) - pa_xfree(r); - - return NULL; -} - -void pa_resampler_free(pa_resampler *r) { - assert(r); - - if (r->impl_free) - r->impl_free(r); - - pa_xfree(r); -} - -void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate) { - assert(r); - assert(rate > 0); - - if (r->i_ss.rate == rate) - return; - - r->i_ss.rate = rate; - - if (r->impl_update_input_rate) - r->impl_update_input_rate(r, rate); -} - -void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { - assert(r && in && out && r->impl_run); - - r->impl_run(r, in, out); -} - -size_t pa_resampler_request(pa_resampler *r, size_t out_length) { - assert(r); - - return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz; -} - -pa_resample_method_t pa_resampler_get_method(pa_resampler *r) { - assert(r); - return r->resample_method; -} - -static const char * const resample_methods[] = { - "src-sinc-best-quality", - "src-sinc-medium-quality", - "src-sinc-fastest", - "src-zero-order-hold", - "src-linear", - "trivial" -}; - -const char *pa_resample_method_to_string(pa_resample_method_t m) { - - if (m < 0 || m >= PA_RESAMPLER_MAX) - return NULL; - - return resample_methods[m]; -} - -pa_resample_method_t pa_parse_resample_method(const char *string) { - pa_resample_method_t m; - - assert(string); - - for (m = 0; m < PA_RESAMPLER_MAX; m++) - if (!strcmp(string, resample_methods[m])) - return m; - - return PA_RESAMPLER_INVALID; -} - - -/*** libsamplerate based implementation ***/ - -static void libsamplerate_free(pa_resampler *r) { - struct impl_libsamplerate *u; - - assert(r); - assert(r->impl_data); - - u = r->impl_data; - - if (u->src_state) - src_delete(u->src_state); - - pa_xfree(u->buf1); - pa_xfree(u->buf2); - pa_xfree(u->buf3); - pa_xfree(u->buf4); - pa_xfree(u); -} - -static void calc_map_table(pa_resampler *r) { - struct impl_libsamplerate *u; - unsigned oc; - assert(r); - assert(r->impl_data); - - u = r->impl_data; - - if (!(u->map_required = (!pa_channel_map_equal(&r->i_cm, &r->o_cm) || r->i_ss.channels != r->o_ss.channels))) - return; - - for (oc = 0; oc < r->o_ss.channels; oc++) { - unsigned ic, i = 0; - - for (ic = 0; ic < r->i_ss.channels; ic++) { - pa_channel_position_t a, b; - - a = r->i_cm.map[ic]; - b = r->o_cm.map[oc]; - - if (a == b || - (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_LEFT) || - (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_RIGHT) || - (a == PA_CHANNEL_POSITION_LEFT && b == PA_CHANNEL_POSITION_MONO) || - (a == PA_CHANNEL_POSITION_RIGHT && b == PA_CHANNEL_POSITION_MONO)) - - u->map_table[oc][i++] = ic; - } - - /* Add an end marker */ - if (i < PA_CHANNELS_MAX) - u->map_table[oc][i] = -1; - } -} - -static float * convert_to_float(pa_resampler *r, void *input, unsigned n_frames) { - struct impl_libsamplerate *u; - unsigned n_samples; - - assert(r); - assert(input); - assert(r->impl_data); - u = r->impl_data; - - /* Convert the incoming sample into floats and place them in buf1 */ - - if (!u->to_float32ne_func) - return input; - - n_samples = n_frames * r->i_ss.channels; - - if (u->buf1_samples < n_samples) - u->buf1 = pa_xrealloc(u->buf1, sizeof(float) * (u->buf1_samples = n_samples)); - - u->to_float32ne_func(n_samples, input, u->buf1); - - return u->buf1; -} - -static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) { - struct impl_libsamplerate *u; - unsigned n_samples; - int i_skip, o_skip; - unsigned oc; - - assert(r); - assert(input); - assert(r->impl_data); - u = r->impl_data; - - /* Remap channels and place the result int buf2 */ - - if (!u->map_required) - return input; - - n_samples = n_frames * r->o_ss.channels; - - if (u->buf2_samples < n_samples) - u->buf2 = pa_xrealloc(u->buf2, sizeof(float) * (u->buf2_samples = n_samples)); - - memset(u->buf2, 0, n_samples * sizeof(float)); - - o_skip = sizeof(float) * r->o_ss.channels; - i_skip = sizeof(float) * r->i_ss.channels; - - for (oc = 0; oc < r->o_ss.channels; oc++) { - unsigned i; - static const float one = 1.0; - - for (i = 0; i < PA_CHANNELS_MAX && u->map_table[oc][i] >= 0; i++) - oil_vectoradd_f32( - u->buf2 + oc, o_skip, - u->buf2 + oc, o_skip, - input + u->map_table[oc][i], i_skip, - n_frames, - &one, &one); - } - - return u->buf2; -} - -static float *resample(pa_resampler *r, float *input, unsigned *n_frames) { - struct impl_libsamplerate *u; - SRC_DATA data; - unsigned out_n_frames, out_n_samples; - int ret; - - assert(r); - assert(input); - assert(n_frames); - assert(r->impl_data); - u = r->impl_data; - - /* Resample the data and place the result in buf3 */ - - if (!u->src_state) - return input; - - out_n_frames = (*n_frames*r->o_ss.rate/r->i_ss.rate)+1024; - out_n_samples = out_n_frames * r->o_ss.channels; - - if (u->buf3_samples < out_n_samples) - u->buf3 = pa_xrealloc(u->buf3, sizeof(float) * (u->buf3_samples = out_n_samples)); - - data.data_in = input; - data.input_frames = *n_frames; - - data.data_out = u->buf3; - data.output_frames = out_n_frames; - - data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate; - data.end_of_input = 0; - - ret = src_process(u->src_state, &data); - assert(ret == 0); - assert((unsigned) data.input_frames_used == *n_frames); - - *n_frames = data.output_frames_gen; - - return u->buf3; -} - -static void *convert_from_float(pa_resampler *r, float *input, unsigned n_frames) { - struct impl_libsamplerate *u; - unsigned n_samples; - - assert(r); - assert(input); - assert(r->impl_data); - u = r->impl_data; - - /* Convert the data into the correct sample type and place the result in buf4 */ - - if (!u->from_float32ne_func) - return input; - - n_samples = n_frames * r->o_ss.channels; - - if (u->buf4_samples < n_samples) - u->buf4 = pa_xrealloc(u->buf4, sizeof(float) * (u->buf4_samples = n_samples)); - - u->from_float32ne_func(n_samples, input, u->buf4); - - return u->buf4; -} - -static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { - struct impl_libsamplerate *u; - float *buf; - void *input, *output; - unsigned n_frames; - - assert(r); - assert(in); - assert(out); - assert(in->length); - assert(in->memblock); - assert(in->length % r->i_fz == 0); - assert(r->impl_data); - - u = r->impl_data; - - input = ((uint8_t*) in->memblock->data + in->index); - n_frames = in->length / r->i_fz; - assert(n_frames > 0); - - buf = convert_to_float(r, input, n_frames); - buf = remap_channels(r, buf, n_frames); - buf = resample(r, buf, &n_frames); - - if (n_frames) { - output = convert_from_float(r, buf, n_frames); - - if (output == input) { - /* Mm, no adjustment has been necessary, so let's return the original block */ - out->memblock = pa_memblock_ref(in->memblock); - out->index = in->index; - out->length = in->length; - } else { - float **p = NULL; - - out->length = n_frames * r->o_fz; - out->index = 0; - - if (output == u->buf1) { - p = &u->buf1; - u->buf1_samples = 0; - } else if (output == u->buf2) { - p = &u->buf2; - u->buf2_samples = 0; - } else if (output == u->buf3) { - p = &u->buf3; - u->buf3_samples = 0; - } else if (output == u->buf4) { - p = &u->buf4; - u->buf4_samples = 0; - } - - assert(p); - - /* Take the existing buffer and make it a memblock */ - out->memblock = pa_memblock_new_dynamic(*p, out->length, r->memblock_stat); - *p = NULL; - } - } else { - out->memblock = NULL; - out->index = out->length = 0; - } -} - -static void libsamplerate_update_input_rate(pa_resampler *r, uint32_t rate) { - struct impl_libsamplerate *u; - - assert(r); - assert(rate > 0); - assert(r->impl_data); - u = r->impl_data; - - if (!u->src_state) { - int err; - u->src_state = src_new(r->resample_method, r->o_ss.channels, &err); - assert(u->src_state); - } else { - int ret = src_set_ratio(u->src_state, (double) r->o_ss.rate / rate); - assert(ret == 0); - } -} - -static int libsamplerate_init(pa_resampler *r) { - struct impl_libsamplerate *u = NULL; - int err; - - r->impl_data = u = pa_xnew(struct impl_libsamplerate, 1); - - u->buf1 = u->buf2 = u->buf3 = u->buf4 = NULL; - u->buf1_samples = u->buf2_samples = u->buf3_samples = u->buf4_samples = 0; - - if (r->i_ss.format == PA_SAMPLE_FLOAT32NE) - u->to_float32ne_func = NULL; - else if (!(u->to_float32ne_func = pa_get_convert_to_float32ne_function(r->i_ss.format))) - goto fail; - - if (r->o_ss.format == PA_SAMPLE_FLOAT32NE) - u->from_float32ne_func = NULL; - else if (!(u->from_float32ne_func = pa_get_convert_from_float32ne_function(r->o_ss.format))) - goto fail; - - if (r->o_ss.rate == r->i_ss.rate) - u->src_state = NULL; - else if (!(u->src_state = src_new(r->resample_method, r->o_ss.channels, &err))) - goto fail; - - r->impl_free = libsamplerate_free; - r->impl_update_input_rate = libsamplerate_update_input_rate; - r->impl_run = libsamplerate_run; - - calc_map_table(r); - - return 0; - -fail: - pa_xfree(u); - return -1; -} - -/* Trivial implementation */ - -static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { - size_t fz; - unsigned n_frames; - struct impl_trivial *u; - - assert(r); - assert(in); - assert(out); - assert(r->impl_data); - - u = r->impl_data; - - fz = r->i_fz; - assert(fz == r->o_fz); - - n_frames = in->length/fz; - - if (r->i_ss.rate == r->o_ss.rate) { - - /* In case there's no diefference in sample types, do nothing */ - *out = *in; - pa_memblock_ref(out->memblock); - - u->o_counter += n_frames; - } else { - /* Do real resampling */ - size_t l; - unsigned o_index; - - /* The length of the new memory block rounded up */ - l = ((((n_frames+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz; - - out->index = 0; - out->memblock = pa_memblock_new(l, r->memblock_stat); - - for (o_index = 0;; o_index++, u->o_counter++) { - unsigned j; - - j = (u->o_counter * r->i_ss.rate / r->o_ss.rate); - j = j > u->i_counter ? j - u->i_counter : 0; - - if (j >= n_frames) - break; - - assert(o_index*fz < out->memblock->length); - - memcpy((uint8_t*) out->memblock->data + fz*o_index, - (uint8_t*) in->memblock->data + in->index + fz*j, fz); - - } - - out->length = o_index*fz; - } - - u->i_counter += n_frames; - - /* Normalize counters */ - while (u->i_counter >= r->i_ss.rate) { - u->i_counter -= r->i_ss.rate; - assert(u->o_counter >= r->o_ss.rate); - u->o_counter -= r->o_ss.rate; - } -} - -static void trivial_free(pa_resampler *r) { - assert(r); - - pa_xfree(r->impl_data); -} - -static void trivial_update_input_rate(pa_resampler *r, uint32_t rate) { - struct impl_trivial *u; - - assert(r); - assert(rate > 0); - assert(r->impl_data); - - u = r->impl_data; - u->i_counter = 0; - u->o_counter = 0; -} - -static int trivial_init(pa_resampler*r) { - struct impl_trivial *u; - - assert(r); - assert(r->i_ss.format == r->o_ss.format); - assert(r->i_ss.channels == r->o_ss.channels); - - r->impl_data = u = pa_xnew(struct impl_trivial, 1); - u->o_counter = u->i_counter = 0; - - r->impl_run = trivial_run; - r->impl_free = trivial_free; - r->impl_update_input_rate = trivial_update_input_rate; - - return 0; -} - - diff --git a/src/polypcore/resampler.h b/src/polypcore/resampler.h deleted file mode 100644 index 2f4d3cbe..00000000 --- a/src/polypcore/resampler.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef fooresamplerhfoo -#define fooresamplerhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include -#include -#include -#include - -typedef struct pa_resampler pa_resampler; - -typedef enum pa_resample_method { - PA_RESAMPLER_INVALID = -1, - PA_RESAMPLER_SRC_SINC_BEST_QUALITY = SRC_SINC_BEST_QUALITY, - PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY = SRC_SINC_MEDIUM_QUALITY, - PA_RESAMPLER_SRC_SINC_FASTEST = SRC_SINC_FASTEST, - PA_RESAMPLER_SRC_ZERO_ORDER_HOLD = SRC_ZERO_ORDER_HOLD, - PA_RESAMPLER_SRC_LINEAR = SRC_LINEAR, - PA_RESAMPLER_TRIVIAL, - PA_RESAMPLER_MAX -} pa_resample_method_t; - -pa_resampler* pa_resampler_new( - const pa_sample_spec *a, - const pa_channel_map *am, - const pa_sample_spec *b, - const pa_channel_map *bm, - pa_memblock_stat *s, - pa_resample_method_t resample_method); - -void pa_resampler_free(pa_resampler *r); - -/* Returns the size of an input memory block which is required to return the specified amount of output data */ -size_t pa_resampler_request(pa_resampler *r, size_t out_length); - -/* Pass the specified memory chunk to the resampler and return the newly resampled data */ -void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out); - -/* Change the input rate of the resampler object */ -void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate); - -/* Return the resampling method of the resampler object */ -pa_resample_method_t pa_resampler_get_method(pa_resampler *r); - -/* Try to parse the resampler method */ -pa_resample_method_t pa_parse_resample_method(const char *string); - -/* return a human readable string for the specified resampling method. Inverse of pa_parse_resample_method() */ -const char *pa_resample_method_to_string(pa_resample_method_t m); - -#endif diff --git a/src/polypcore/sample-util.c b/src/polypcore/sample-util.c deleted file mode 100644 index 7a75ce1c..00000000 --- a/src/polypcore/sample-util.c +++ /dev/null @@ -1,405 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -#include - -#include "sample-util.h" -#include "endianmacros.h" - -pa_memblock *pa_silence_memblock_new(const pa_sample_spec *spec, size_t length, pa_memblock_stat*s) { - assert(spec); - - if (length == 0) - length = pa_bytes_per_second(spec)/10; /* 100 ms */ - - return pa_silence_memblock(pa_memblock_new(length, s), spec); -} - -pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) { - assert(b && b->data && spec); - pa_silence_memory(b->data, b->length, spec); - return b; -} - -void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) { - assert(c && c->memblock && c->memblock->data && spec && c->length); - - pa_silence_memory((uint8_t*) c->memblock->data+c->index, c->length, spec); -} - -void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { - uint8_t c = 0; - assert(p && length && spec); - - switch (spec->format) { - case PA_SAMPLE_U8: - c = 0x80; - break; - case PA_SAMPLE_S16LE: - case PA_SAMPLE_S16BE: - case PA_SAMPLE_FLOAT32: - c = 0; - break; - case PA_SAMPLE_ALAW: - case PA_SAMPLE_ULAW: - c = 80; - break; - default: - assert(0); - } - - memset(p, c, length); -} - -size_t pa_mix( - const pa_mix_info streams[], - unsigned nstreams, - void *data, - size_t length, - const pa_sample_spec *spec, - const pa_cvolume *volume, - int mute) { - - assert(streams && data && length && spec); - - switch (spec->format) { - case PA_SAMPLE_S16NE:{ - size_t d; - unsigned channel = 0; - - for (d = 0;; d += sizeof(int16_t)) { - int32_t sum = 0; - - if (d >= length) - return d; - - if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { - unsigned i; - - for (i = 0; i < nstreams; i++) { - int32_t v; - pa_volume_t cvolume = streams[i].volume.values[channel]; - - if (d >= streams[i].chunk.length) - return d; - - if (cvolume == PA_VOLUME_MUTED) - v = 0; - else { - v = *((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); - - if (cvolume != PA_VOLUME_NORM) - v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); - } - - sum += v; - } - - if (volume->values[channel] != PA_VOLUME_NORM) - sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); - - if (sum < -0x8000) sum = -0x8000; - if (sum > 0x7FFF) sum = 0x7FFF; - - } - - *((int16_t*) data) = sum; - data = (uint8_t*) data + sizeof(int16_t); - - if (++channel >= spec->channels) - channel = 0; - } - } - - case PA_SAMPLE_S16RE:{ - size_t d; - unsigned channel = 0; - - for (d = 0;; d += sizeof(int16_t)) { - int32_t sum = 0; - - if (d >= length) - return d; - - if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { - unsigned i; - - for (i = 0; i < nstreams; i++) { - int32_t v; - pa_volume_t cvolume = streams[i].volume.values[channel]; - - if (d >= streams[i].chunk.length) - return d; - - if (cvolume == PA_VOLUME_MUTED) - v = 0; - else { - v = INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d))); - - if (cvolume != PA_VOLUME_NORM) - v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); - } - - sum += v; - } - - if (volume->values[channel] != PA_VOLUME_NORM) - sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); - - if (sum < -0x8000) sum = -0x8000; - if (sum > 0x7FFF) sum = 0x7FFF; - - } - - *((int16_t*) data) = INT16_SWAP(sum); - data = (uint8_t*) data + sizeof(int16_t); - - if (++channel >= spec->channels) - channel = 0; - } - } - - case PA_SAMPLE_U8: { - size_t d; - unsigned channel = 0; - - for (d = 0;; d ++) { - int32_t sum = 0; - - if (d >= length) - return d; - - if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { - unsigned i; - - for (i = 0; i < nstreams; i++) { - int32_t v; - pa_volume_t cvolume = streams[i].volume.values[channel]; - - if (d >= streams[i].chunk.length) - return d; - - if (cvolume == PA_VOLUME_MUTED) - v = 0; - else { - v = (int32_t) *((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d) - 0x80; - - if (cvolume != PA_VOLUME_NORM) - v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); - } - - sum += v; - } - - if (volume->values[channel] != PA_VOLUME_NORM) - sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); - - if (sum < -0x80) sum = -0x80; - if (sum > 0x7F) sum = 0x7F; - - } - - *((uint8_t*) data) = (uint8_t) (sum + 0x80); - data = (uint8_t*) data + 1; - - if (++channel >= spec->channels) - channel = 0; - } - } - - case PA_SAMPLE_FLOAT32NE: { - size_t d; - unsigned channel = 0; - - for (d = 0;; d += sizeof(float)) { - float sum = 0; - - if (d >= length) - return d; - - if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { - unsigned i; - - for (i = 0; i < nstreams; i++) { - float v; - pa_volume_t cvolume = streams[i].volume.values[channel]; - - if (d >= streams[i].chunk.length) - return d; - - if (cvolume == PA_VOLUME_MUTED) - v = 0; - else { - v = *((float*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); - - if (cvolume != PA_VOLUME_NORM) - v *= pa_sw_volume_to_linear(cvolume); - } - - sum += v; - } - - if (volume->values[channel] != PA_VOLUME_NORM) - sum *= pa_sw_volume_to_linear(volume->values[channel]); - } - - *((float*) data) = sum; - data = (uint8_t*) data + sizeof(float); - - if (++channel >= spec->channels) - channel = 0; - } - } - - default: - pa_log_error(__FILE__": ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format)); - abort(); - } -} - - -void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvolume *volume) { - assert(c && spec && (c->length % pa_frame_size(spec) == 0)); - assert(volume); - - if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM)) - return; - - if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) { - pa_silence_memchunk(c, spec); - return; - } - - switch (spec->format) { - case PA_SAMPLE_S16NE: { - int16_t *d; - size_t n; - unsigned channel; - double linear[PA_CHANNELS_MAX]; - - for (channel = 0; channel < spec->channels; channel++) - linear[channel] = pa_sw_volume_to_linear(volume->values[channel]); - - for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { - int32_t t = (int32_t)(*d); - - t = (int32_t) (t * linear[channel]); - - if (t < -0x8000) t = -0x8000; - if (t > 0x7FFF) t = 0x7FFF; - - *d = (int16_t) t; - - if (++channel >= spec->channels) - channel = 0; - } - break; - } - - case PA_SAMPLE_S16RE: { - int16_t *d; - size_t n; - unsigned channel; - double linear[PA_CHANNELS_MAX]; - - for (channel = 0; channel < spec->channels; channel++) - linear[channel] = pa_sw_volume_to_linear(volume->values[channel]); - - for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { - int32_t t = (int32_t)(INT16_SWAP(*d)); - - t = (int32_t) (t * linear[channel]); - - if (t < -0x8000) t = -0x8000; - if (t > 0x7FFF) t = 0x7FFF; - - *d = INT16_SWAP((int16_t) t); - - if (++channel >= spec->channels) - channel = 0; - } - - break; - } - - case PA_SAMPLE_U8: { - uint8_t *d; - size_t n; - unsigned channel = 0; - - for (d = (uint8_t*) c->memblock->data + c->index, n = c->length; n > 0; d++, n--) { - int32_t t = (int32_t) *d - 0x80; - - t = (int32_t) (t * pa_sw_volume_to_linear(volume->values[channel])); - - if (t < -0x80) t = -0x80; - if (t > 0x7F) t = 0x7F; - - *d = (uint8_t) (t + 0x80); - - if (++channel >= spec->channels) - channel = 0; - } - break; - } - - case PA_SAMPLE_FLOAT32NE: { - float *d; - int skip; - unsigned n; - unsigned channel; - - d = (float*) ((uint8_t*) c->memblock->data + c->index); - skip = spec->channels * sizeof(float); - n = c->length/sizeof(float)/spec->channels; - - for (channel = 0; channel < spec->channels ; channel ++) { - float v, *t; - - if (volume->values[channel] == PA_VOLUME_NORM) - continue; - - v = (float) pa_sw_volume_to_linear(volume->values[channel]); - - t = d + channel; - oil_scalarmult_f32(t, skip, t, skip, &v, n); - } - break; - } - - default: - pa_log_error(__FILE__": ERROR: Unable to change volume of format %s.", - pa_sample_format_to_string(spec->format)); - abort(); - } -} - diff --git a/src/polypcore/sample-util.h b/src/polypcore/sample-util.h deleted file mode 100644 index da7f56e1..00000000 --- a/src/polypcore/sample-util.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef foosampleutilhfoo -#define foosampleutilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include - -pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec); -pa_memblock *pa_silence_memblock_new(const pa_sample_spec *spec, size_t length, pa_memblock_stat*s); -void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec); -void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec); - -typedef struct pa_mix_info { - pa_memchunk chunk; - pa_cvolume volume; - void *userdata; -} pa_mix_info; - -size_t pa_mix( - const pa_mix_info channels[], - unsigned nchannels, - void *data, - size_t length, - const pa_sample_spec *spec, - const pa_cvolume *volume, - int mute); - -void pa_volume_memchunk( - pa_memchunk*c, - const pa_sample_spec *spec, - const pa_cvolume *volume); - -#endif diff --git a/src/polypcore/sconv-s16be.c b/src/polypcore/sconv-s16be.c deleted file mode 100644 index 8b076f06..00000000 --- a/src/polypcore/sconv-s16be.c +++ /dev/null @@ -1,41 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "endianmacros.h" - -#define INT16_FROM INT16_FROM_BE -#define INT16_TO INT16_TO_BE - -#define pa_sconv_s16le_to_float32ne pa_sconv_s16be_to_float32ne -#define pa_sconv_s16le_from_float32ne pa_sconv_s16be_from_float32ne - -#ifdef WORDS_BIGENDIAN -#define SWAP_WORDS 0 -#else -#define SWAP_WORDS 1 -#endif - -#include "sconv-s16le.h" -#include "sconv-s16le.c" diff --git a/src/polypcore/sconv-s16be.h b/src/polypcore/sconv-s16be.h deleted file mode 100644 index b2b6a8c7..00000000 --- a/src/polypcore/sconv-s16be.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef foosconv_s16befoo -#define foosconv_s16befoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -void pa_sconv_s16be_to_float32ne(unsigned n, const void *a, float *b); -void pa_sconv_s16be_from_float32ne(unsigned n, const float *a, void *b); - -#endif diff --git a/src/polypcore/sconv-s16le.c b/src/polypcore/sconv-s16le.c deleted file mode 100644 index 0814c35b..00000000 --- a/src/polypcore/sconv-s16le.c +++ /dev/null @@ -1,103 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include - -#include -#include - -#include "endianmacros.h" - -#include "sconv-s16le.h" - -#ifndef INT16_FROM -#define INT16_FROM INT16_FROM_LE -#endif - -#ifndef INT16_TO -#define INT16_TO INT16_TO_LE -#endif - -#ifndef SWAP_WORDS -#ifdef WORDS_BIGENDIAN -#define SWAP_WORDS 1 -#else -#define SWAP_WORDS 0 -#endif -#endif - -void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b) { - const int16_t *ca = a; - - assert(a); - assert(b); - -#if SWAP_WORDS == 1 - - for (; n > 0; n--) { - int16_t s = *(ca++); - *(b++) = ((float) INT16_FROM(s))/0x7FFF; - } - -#else -{ - static const double add = 0, factor = 1.0/0x7FFF; - oil_scaleconv_f32_s16(b, ca, n, &add, &factor); -} -#endif -} - -void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b) { - int16_t *cb = b; - - assert(a); - assert(b); - -#if SWAP_WORDS == 1 - - for (; n > 0; n--) { - int16_t s; - float v = *(a++); - - if (v > 1) - v = 1; - - if (v < -1) - v = -1; - - s = (int16_t) (v * 0x7FFF); - *(cb++) = INT16_TO(s); - } - -#else -{ - static const double add = 0, factor = 0x7FFF; - oil_scaleconv_s16_f32(cb, a, n, &add, &factor); -} -#endif -} diff --git a/src/polypcore/sconv-s16le.h b/src/polypcore/sconv-s16le.h deleted file mode 100644 index ef5e31e8..00000000 --- a/src/polypcore/sconv-s16le.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef foosconv_s16lefoo -#define foosconv_s16lefoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b); -void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b); - -#endif diff --git a/src/polypcore/sconv.c b/src/polypcore/sconv.c deleted file mode 100644 index c557be67..00000000 --- a/src/polypcore/sconv.c +++ /dev/null @@ -1,169 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include -#include - -#include - -#include "endianmacros.h" -#include "sconv-s16le.h" -#include "sconv-s16be.h" - -#include "sconv.h" - -static void u8_to_float32ne(unsigned n, const void *a, float *b) { - const uint8_t *ca = a; - static const double add = -128.0/127.0, factor = 1.0/127.0; - - assert(a); - assert(b); - - oil_scaleconv_f32_u8(b, ca, n, &add, &factor); -} - -static void u8_from_float32ne(unsigned n, const float *a, void *b) { - uint8_t *cb = b; - static const double add = 128.0, factor = 127.0; - - assert(a); - assert(b); - - oil_scaleconv_u8_f32(cb, a, n, &add, &factor); -} - -static void float32ne_to_float32ne(unsigned n, const void *a, float *b) { - assert(a); - assert(b); - - oil_memcpy(b, a, sizeof(float) * n); -} - -static void float32ne_from_float32ne(unsigned n, const float *a, void *b) { - assert(a); - assert(b); - - oil_memcpy(b, a, sizeof(float) * n); -} - -static void ulaw_to_float32ne(unsigned n, const void *a, float *b) { - const uint8_t *ca = a; - - assert(a); - assert(b); - - for (; n > 0; n--) - *(b++) = st_ulaw2linear16(*(ca++)) * 1.0F / 0x7FFF; -} - -static void ulaw_from_float32ne(unsigned n, const float *a, void *b) { - uint8_t *cb = b; - - assert(a); - assert(b); - - for (; n > 0; n--) { - float v = *(a++); - - if (v > 1) - v = 1; - - if (v < -1) - v = -1; - - *(cb++) = st_14linear2ulaw((int16_t) (v * 0x1FFF)); - } -} - -static void alaw_to_float32ne(unsigned n, const void *a, float *b) { - const uint8_t *ca = a; - - assert(a); - assert(b); - - for (; n > 0; n--) - *(b++) = st_alaw2linear16(*(ca++)) * 1.0F / 0x7FFF; -} - -static void alaw_from_float32ne(unsigned n, const float *a, void *b) { - uint8_t *cb = b; - - assert(a); - assert(b); - - for (; n > 0; n--) { - float v = *(a++); - - if (v > 1) - v = 1; - - if (v < -1) - v = -1; - - *(cb++) = st_13linear2alaw((int16_t) (v * 0xFFF)); - } -} - -pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f) { - switch(f) { - case PA_SAMPLE_U8: - return u8_to_float32ne; - case PA_SAMPLE_S16LE: - return pa_sconv_s16le_to_float32ne; - case PA_SAMPLE_S16BE: - return pa_sconv_s16be_to_float32ne; - case PA_SAMPLE_FLOAT32NE: - return float32ne_to_float32ne; - case PA_SAMPLE_ALAW: - return alaw_to_float32ne; - case PA_SAMPLE_ULAW: - return ulaw_to_float32ne; - default: - return NULL; - } -} - -pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f) { - switch(f) { - case PA_SAMPLE_U8: - return u8_from_float32ne; - case PA_SAMPLE_S16LE: - return pa_sconv_s16le_from_float32ne; - case PA_SAMPLE_S16BE: - return pa_sconv_s16be_from_float32ne; - case PA_SAMPLE_FLOAT32NE: - return float32ne_from_float32ne; - case PA_SAMPLE_ALAW: - return alaw_from_float32ne; - case PA_SAMPLE_ULAW: - return ulaw_from_float32ne; - default: - return NULL; - } -} diff --git a/src/polypcore/sconv.h b/src/polypcore/sconv.h deleted file mode 100644 index a0c15c24..00000000 --- a/src/polypcore/sconv.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef foosconvhfoo -#define foosconvhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -typedef void (*pa_convert_to_float32ne_func_t)(unsigned n, const void *a, float *b); -typedef void (*pa_convert_from_float32ne_func_t)(unsigned n, const float *a, void *b); - -pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f); -pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f); - -#endif diff --git a/src/polypcore/sink-input.c b/src/polypcore/sink-input.c deleted file mode 100644 index bd2a1dcd..00000000 --- a/src/polypcore/sink-input.c +++ /dev/null @@ -1,386 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include "sink-input.h" - -#define CONVERT_BUFFER_LENGTH 4096 - -#define CHECK_VALIDITY_RETURN_NULL(condition) \ -do {\ -if (!(condition)) \ - return NULL; \ -} while (0) - -pa_sink_input* pa_sink_input_new( - pa_sink *s, - const char *driver, - const char *name, - const pa_sample_spec *spec, - const pa_channel_map *map, - const pa_cvolume *volume, - int variable_rate, - int resample_method) { - - pa_sink_input *i; - pa_resampler *resampler = NULL; - int r; - char st[256]; - pa_channel_map tmap; - pa_cvolume tvol; - - assert(s); - assert(spec); - assert(s->state == PA_SINK_RUNNING); - - CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec)); - - if (!map) - map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT); - if (!volume) - volume = pa_cvolume_reset(&tvol, spec->channels); - - CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map)); - CHECK_VALIDITY_RETURN_NULL(volume && pa_cvolume_valid(volume)); - CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels); - CHECK_VALIDITY_RETURN_NULL(volume->channels == spec->channels); - CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver)); - CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name)); - - if (pa_idxset_size(s->inputs) >= PA_MAX_INPUTS_PER_SINK) { - pa_log_warn(__FILE__": Failed to create sink input: too many inputs per sink."); - return NULL; - } - - if (resample_method == PA_RESAMPLER_INVALID) - resample_method = s->core->resample_method; - - if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec) || !pa_channel_map_equal(map, &s->channel_map)) - if (!(resampler = pa_resampler_new(spec, map, &s->sample_spec, &s->channel_map, s->core->memblock_stat, resample_method))) - return NULL; - - i = pa_xnew(pa_sink_input, 1); - i->ref = 1; - i->state = PA_SINK_INPUT_RUNNING; - i->name = pa_xstrdup(name); - i->driver = pa_xstrdup(driver); - i->owner = NULL; - i->sink = s; - i->client = NULL; - - i->sample_spec = *spec; - i->channel_map = *map; - i->volume = *volume; - - i->peek = NULL; - i->drop = NULL; - i->kill = NULL; - i->get_latency = NULL; - i->underrun = NULL; - i->userdata = NULL; - - i->playing = 0; - - pa_memchunk_reset(&i->resampled_chunk); - i->resampler = resampler; - - assert(s->core); - r = pa_idxset_put(s->core->sink_inputs, i, &i->index); - assert(r == 0 && i->index != PA_IDXSET_INVALID); - r = pa_idxset_put(s->inputs, i, NULL); - assert(r == 0); - - pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"", i->index, i->name, s->index, st); - - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index); - - return i; -} - -void pa_sink_input_disconnect(pa_sink_input *i) { - assert(i); - assert(i->state != PA_SINK_INPUT_DISCONNECTED); - assert(i->sink); - assert(i->sink->core); - - pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); - pa_idxset_remove_by_data(i->sink->inputs, i, NULL); - - pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index); - i->sink = NULL; - - i->peek = NULL; - i->drop = NULL; - i->kill = NULL; - i->get_latency = NULL; - i->underrun = NULL; - - i->playing = 0; - i->state = PA_SINK_INPUT_DISCONNECTED; -} - -static void sink_input_free(pa_sink_input* i) { - assert(i); - - if (i->state != PA_SINK_INPUT_DISCONNECTED) - pa_sink_input_disconnect(i); - - pa_log_info(__FILE__": freed %u \"%s\"", i->index, i->name); - - if (i->resampled_chunk.memblock) - pa_memblock_unref(i->resampled_chunk.memblock); - - if (i->resampler) - pa_resampler_free(i->resampler); - - pa_xfree(i->name); - pa_xfree(i->driver); - pa_xfree(i); -} - -void pa_sink_input_unref(pa_sink_input *i) { - assert(i); - assert(i->ref >= 1); - - if (!(--i->ref)) - sink_input_free(i); -} - -pa_sink_input* pa_sink_input_ref(pa_sink_input *i) { - assert(i); - assert(i->ref >= 1); - - i->ref++; - return i; -} - -void pa_sink_input_kill(pa_sink_input*i) { - assert(i); - assert(i->ref >= 1); - - if (i->kill) - i->kill(i); -} - -pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) { - pa_usec_t r = 0; - - assert(i); - assert(i->ref >= 1); - - if (i->get_latency) - r += i->get_latency(i); - - if (i->resampled_chunk.memblock) - r += pa_bytes_to_usec(i->resampled_chunk.length, &i->sample_spec); - - return r; -} - -int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) { - int ret = -1; - int do_volume_adj_here; - - assert(i); - assert(i->ref >= 1); - assert(chunk); - assert(volume); - - pa_sink_input_ref(i); - - if (!i->peek || !i->drop || i->state == PA_SINK_INPUT_CORKED) - goto finish; - - if (!i->resampler) { - do_volume_adj_here = 0; - ret = i->peek(i, chunk); - goto finish; - } - - do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map); - - while (!i->resampled_chunk.memblock) { - pa_memchunk tchunk; - size_t l; - - if ((ret = i->peek(i, &tchunk)) < 0) - goto finish; - - assert(tchunk.length); - - l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); - - if (l > tchunk.length) - l = tchunk.length; - - i->drop(i, &tchunk, l); - tchunk.length = l; - - /* It might be necessary to adjust the volume here */ - if (do_volume_adj_here) { - pa_memchunk_make_writable(&tchunk, i->sink->core->memblock_stat, 0); - pa_volume_memchunk(&tchunk, &i->sample_spec, &i->volume); - } - - pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk); - pa_memblock_unref(tchunk.memblock); - } - - assert(i->resampled_chunk.memblock); - assert(i->resampled_chunk.length); - - *chunk = i->resampled_chunk; - pa_memblock_ref(i->resampled_chunk.memblock); - - ret = 0; - -finish: - - if (ret < 0 && i->playing && i->underrun) - i->underrun(i); - - i->playing = ret >= 0; - - if (ret >= 0) { - /* Let's see if we had to apply the volume adjustment - * ourselves, or if this can be done by the sink for us */ - - if (do_volume_adj_here) - /* We had different channel maps, so we already did the adjustment */ - pa_cvolume_reset(volume, i->sink->sample_spec.channels); - else - /* We've both the same channel map, so let's have the sink do the adjustment for us*/ - *volume = i->volume; - } - - pa_sink_input_unref(i); - - return ret; -} - -void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { - assert(i); - assert(i->ref >= 1); - assert(length > 0); - - if (!i->resampler) { - if (i->drop) - i->drop(i, chunk, length); - return; - } - - assert(i->resampled_chunk.memblock); - assert(i->resampled_chunk.length >= length); - - i->resampled_chunk.index += length; - i->resampled_chunk.length -= length; - - if (i->resampled_chunk.length <= 0) { - pa_memblock_unref(i->resampled_chunk.memblock); - i->resampled_chunk.memblock = NULL; - i->resampled_chunk.index = i->resampled_chunk.length = 0; - } -} - -void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) { - assert(i); - assert(i->ref >= 1); - assert(i->sink); - assert(i->sink->core); - - if (pa_cvolume_equal(&i->volume, volume)) - return; - - i->volume = *volume; - pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); -} - -const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i) { - assert(i); - assert(i->ref >= 1); - - return &i->volume; -} - -void pa_sink_input_cork(pa_sink_input *i, int b) { - int n; - - assert(i); - assert(i->ref >= 1); - - if (i->state == PA_SINK_INPUT_DISCONNECTED) - return; - - n = i->state == PA_SINK_INPUT_CORKED && !b; - - i->state = b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING; - - if (n) - pa_sink_notify(i->sink); -} - -void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) { - assert(i); - assert(i->resampler); - assert(i->ref >= 1); - - if (i->sample_spec.rate == rate) - return; - - i->sample_spec.rate = rate; - pa_resampler_set_input_rate(i->resampler, rate); -} - -void pa_sink_input_set_name(pa_sink_input *i, const char *name) { - assert(i); - assert(i->ref >= 1); - - pa_xfree(i->name); - i->name = pa_xstrdup(name); - - pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); -} - -pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) { - assert(i); - assert(i->ref >= 1); - - if (!i->resampler) - return PA_RESAMPLER_INVALID; - - return pa_resampler_get_method(i->resampler); -} diff --git a/src/polypcore/sink-input.h b/src/polypcore/sink-input.h deleted file mode 100644 index 4cf4460a..00000000 --- a/src/polypcore/sink-input.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef foosinkinputhfoo -#define foosinkinputhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -typedef struct pa_sink_input pa_sink_input; - -#include -#include -#include -#include -#include -#include - -typedef enum pa_sink_input_state { - PA_SINK_INPUT_RUNNING, - PA_SINK_INPUT_CORKED, - PA_SINK_INPUT_DISCONNECTED -} pa_sink_input_state_t; - -struct pa_sink_input { - int ref; - uint32_t index; - pa_sink_input_state_t state; - - char *name, *driver; - pa_module *owner; - - pa_sink *sink; - pa_client *client; - - pa_sample_spec sample_spec; - pa_channel_map channel_map; - - pa_cvolume volume; - - int (*peek) (pa_sink_input *i, pa_memchunk *chunk); - void (*drop) (pa_sink_input *i, const pa_memchunk *chunk, size_t length); - void (*kill) (pa_sink_input *i); - pa_usec_t (*get_latency) (pa_sink_input *i); - void (*underrun) (pa_sink_input *i); - - void *userdata; - - int playing; - - pa_memchunk resampled_chunk; - pa_resampler *resampler; -}; - -pa_sink_input* pa_sink_input_new( - pa_sink *s, - const char *driver, - const char *name, - const pa_sample_spec *spec, - const pa_channel_map *map, - const pa_cvolume *volume, - int variable_rate, - int resample_method); - -void pa_sink_input_unref(pa_sink_input* i); -pa_sink_input* pa_sink_input_ref(pa_sink_input* i); - -/* To be called by the implementing module only */ -void pa_sink_input_disconnect(pa_sink_input* i); - -/* External code may request disconnection with this funcion */ -void pa_sink_input_kill(pa_sink_input*i); - -pa_usec_t pa_sink_input_get_latency(pa_sink_input *i); - -int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume); -void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length); - -void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume); -const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i); - -void pa_sink_input_cork(pa_sink_input *i, int b); - -void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate); - -void pa_sink_input_set_name(pa_sink_input *i, const char *name); - -pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i); - -#endif diff --git a/src/polypcore/sink.c b/src/polypcore/sink.c deleted file mode 100644 index dc27ca2e..00000000 --- a/src/polypcore/sink.c +++ /dev/null @@ -1,513 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "sink.h" - -#define MAX_MIX_CHANNELS 32 - -#define CHECK_VALIDITY_RETURN_NULL(condition) \ -do {\ -if (!(condition)) \ - return NULL; \ -} while (0) - -pa_sink* pa_sink_new( - pa_core *core, - const char *driver, - const char *name, - int fail, - const pa_sample_spec *spec, - const pa_channel_map *map) { - - pa_sink *s; - char *n = NULL; - char st[256]; - int r; - pa_channel_map tmap; - - assert(core); - assert(name); - assert(spec); - - CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec)); - - if (!map) - map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT); - - CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map)); - CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels); - CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver)); - CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name) && *name); - - s = pa_xnew(pa_sink, 1); - - if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) { - pa_xfree(s); - return NULL; - } - - s->ref = 1; - s->core = core; - s->state = PA_SINK_RUNNING; - s->name = pa_xstrdup(name); - s->description = NULL; - s->driver = pa_xstrdup(driver); - s->owner = NULL; - - s->sample_spec = *spec; - s->channel_map = *map; - - s->inputs = pa_idxset_new(NULL, NULL); - - pa_cvolume_reset(&s->sw_volume, spec->channels); - pa_cvolume_reset(&s->hw_volume, spec->channels); - s->sw_muted = 0; - s->hw_muted = 0; - - s->get_latency = NULL; - s->notify = NULL; - s->set_hw_volume = NULL; - s->get_hw_volume = NULL; - s->set_hw_mute = NULL; - s->get_hw_mute = NULL; - s->userdata = NULL; - - r = pa_idxset_put(core->sinks, s, &s->index); - assert(s->index != PA_IDXSET_INVALID && r >= 0); - - pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"", s->index, s->name, st); - - n = pa_sprintf_malloc("%s_monitor", name); - s->monitor_source = pa_source_new(core, driver, n, 0, spec, map); - assert(s->monitor_source); - pa_xfree(n); - s->monitor_source->monitor_of = s; - s->monitor_source->description = pa_sprintf_malloc("Monitor source of sink '%s'", s->name); - - pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index); - - return s; -} - -void pa_sink_disconnect(pa_sink* s) { - pa_sink_input *i, *j = NULL; - - assert(s); - assert(s->state == PA_SINK_RUNNING); - - pa_namereg_unregister(s->core, s->name); - - while ((i = pa_idxset_first(s->inputs, NULL))) { - assert(i != j); - pa_sink_input_kill(i); - j = i; - } - - pa_source_disconnect(s->monitor_source); - - pa_idxset_remove_by_data(s->core->sinks, s, NULL); - - s->get_latency = NULL; - s->notify = NULL; - s->get_hw_volume = NULL; - s->set_hw_volume = NULL; - s->set_hw_mute = NULL; - s->get_hw_mute = NULL; - - s->state = PA_SINK_DISCONNECTED; - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); -} - -static void sink_free(pa_sink *s) { - assert(s); - assert(!s->ref); - - if (s->state != PA_SINK_DISCONNECTED) - pa_sink_disconnect(s); - - pa_log_info(__FILE__": freed %u \"%s\"", s->index, s->name); - - pa_source_unref(s->monitor_source); - s->monitor_source = NULL; - - pa_idxset_free(s->inputs, NULL, NULL); - - pa_xfree(s->name); - pa_xfree(s->description); - pa_xfree(s->driver); - pa_xfree(s); -} - -void pa_sink_unref(pa_sink*s) { - assert(s); - assert(s->ref >= 1); - - if (!(--s->ref)) - sink_free(s); -} - -pa_sink* pa_sink_ref(pa_sink *s) { - assert(s); - assert(s->ref >= 1); - - s->ref++; - return s; -} - -void pa_sink_notify(pa_sink*s) { - assert(s); - assert(s->ref >= 1); - - if (s->notify) - s->notify(s); -} - -static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) { - uint32_t idx = PA_IDXSET_INVALID; - pa_sink_input *i; - unsigned n = 0; - - assert(s); - assert(s->ref >= 1); - assert(info); - - for (i = pa_idxset_first(s->inputs, &idx); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &idx)) { - /* Increase ref counter, to make sure that this input doesn't - * vanish while we still need it */ - pa_sink_input_ref(i); - - if (pa_sink_input_peek(i, &info->chunk, &info->volume) < 0) { - pa_sink_input_unref(i); - continue; - } - - info->userdata = i; - - assert(info->chunk.memblock); - assert(info->chunk.memblock->data); - assert(info->chunk.length); - - info++; - maxinfo--; - n++; - } - - return n; -} - -static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned maxinfo, size_t length) { - assert(s); - assert(s->ref >= 1); - assert(info); - - for (; maxinfo > 0; maxinfo--, info++) { - pa_sink_input *i = info->userdata; - - assert(i); - assert(info->chunk.memblock); - - /* Drop read data */ - pa_sink_input_drop(i, &info->chunk, length); - pa_memblock_unref(info->chunk.memblock); - - /* Decrease ref counter */ - pa_sink_input_unref(i); - info->userdata = NULL; - } -} - -int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { - pa_mix_info info[MAX_MIX_CHANNELS]; - unsigned n; - int r = -1; - - assert(s); - assert(s->ref >= 1); - assert(length); - assert(result); - - pa_sink_ref(s); - - n = fill_mix_info(s, info, MAX_MIX_CHANNELS); - - if (n <= 0) - goto finish; - - if (n == 1) { - pa_cvolume volume; - - *result = info[0].chunk; - pa_memblock_ref(result->memblock); - - if (result->length > length) - result->length = length; - - pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); - - if (s->sw_muted || !pa_cvolume_is_norm(&volume)) { - pa_memchunk_make_writable(result, s->core->memblock_stat, 0); - if (s->sw_muted) - pa_silence_memchunk(result, &s->sample_spec); - else - pa_volume_memchunk(result, &s->sample_spec, &volume); - } - } else { - result->memblock = pa_memblock_new(length, s->core->memblock_stat); - assert(result->memblock); - -/* pa_log("mixing %i", n); */ - - result->length = pa_mix(info, n, result->memblock->data, length, - &s->sample_spec, &s->sw_volume, s->sw_muted); - result->index = 0; - } - - inputs_drop(s, info, n, result->length); - pa_source_post(s->monitor_source, result); - - r = 0; - -finish: - pa_sink_unref(s); - - return r; -} - -int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { - pa_mix_info info[MAX_MIX_CHANNELS]; - unsigned n; - int r = -1; - - assert(s); - assert(s->ref >= 1); - assert(target); - assert(target->memblock); - assert(target->length); - assert(target->memblock->data); - - pa_sink_ref(s); - - n = fill_mix_info(s, info, MAX_MIX_CHANNELS); - - if (n <= 0) - goto finish; - - if (n == 1) { - pa_cvolume volume; - - if (target->length > info[0].chunk.length) - target->length = info[0].chunk.length; - - memcpy((uint8_t*) target->memblock->data + target->index, - (uint8_t*) info[0].chunk.memblock->data + info[0].chunk.index, - target->length); - - pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); - - if (s->sw_muted) - pa_silence_memchunk(target, &s->sample_spec); - else if (!pa_cvolume_is_norm(&volume)) - pa_volume_memchunk(target, &s->sample_spec, &volume); - } else - target->length = pa_mix(info, n, - (uint8_t*) target->memblock->data + target->index, - target->length, - &s->sample_spec, - &s->sw_volume, - s->sw_muted); - - inputs_drop(s, info, n, target->length); - pa_source_post(s->monitor_source, target); - - r = 0; - -finish: - pa_sink_unref(s); - - return r; -} - -void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { - pa_memchunk chunk; - size_t l, d; - - assert(s); - assert(s->ref >= 1); - assert(target); - assert(target->memblock); - assert(target->length); - assert(target->memblock->data); - - pa_sink_ref(s); - - l = target->length; - d = 0; - while (l > 0) { - chunk = *target; - chunk.index += d; - chunk.length -= d; - - if (pa_sink_render_into(s, &chunk) < 0) - break; - - d += chunk.length; - l -= chunk.length; - } - - if (l > 0) { - chunk = *target; - chunk.index += d; - chunk.length -= d; - pa_silence_memchunk(&chunk, &s->sample_spec); - } - - pa_sink_unref(s); -} - -void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { - assert(s); - assert(s->ref >= 1); - assert(length); - assert(result); - - /*** This needs optimization ***/ - - result->memblock = pa_memblock_new(result->length = length, s->core->memblock_stat); - result->index = 0; - - pa_sink_render_into_full(s, result); -} - -pa_usec_t pa_sink_get_latency(pa_sink *s) { - assert(s); - assert(s->ref >= 1); - - if (!s->get_latency) - return 0; - - return s->get_latency(s); -} - -void pa_sink_set_owner(pa_sink *s, pa_module *m) { - assert(s); - assert(s->ref >= 1); - - s->owner = m; - - if (s->monitor_source) - pa_source_set_owner(s->monitor_source, m); -} - -void pa_sink_set_volume(pa_sink *s, pa_mixer_t m, const pa_cvolume *volume) { - pa_cvolume *v; - - assert(s); - assert(s->ref >= 1); - assert(volume); - - if (m == PA_MIXER_HARDWARE && s->set_hw_volume) - v = &s->hw_volume; - else - v = &s->sw_volume; - - if (pa_cvolume_equal(v, volume)) - return; - - *v = *volume; - - if (v == &s->hw_volume) - if (s->set_hw_volume(s) < 0) - s->sw_volume = *volume; - - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); -} - -const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_mixer_t m) { - assert(s); - assert(s->ref >= 1); - - if (m == PA_MIXER_HARDWARE && s->set_hw_volume) { - - if (s->get_hw_volume) - s->get_hw_volume(s); - - return &s->hw_volume; - } else - return &s->sw_volume; -} - -void pa_sink_set_mute(pa_sink *s, pa_mixer_t m, int mute) { - int *t; - - assert(s); - assert(s->ref >= 1); - - if (m == PA_MIXER_HARDWARE && s->set_hw_mute) - t = &s->hw_muted; - else - t = &s->sw_muted; - - if (!!*t == !!mute) - return; - - *t = !!mute; - - if (t == &s->hw_muted) - if (s->set_hw_mute(s) < 0) - s->sw_muted = !!mute; - - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); -} - -int pa_sink_get_mute(pa_sink *s, pa_mixer_t m) { - assert(s); - assert(s->ref >= 1); - - if (m == PA_MIXER_HARDWARE && s->set_hw_mute) { - - if (s->get_hw_mute) - s->get_hw_mute(s); - - return s->hw_muted; - } else - return s->sw_muted; -} diff --git a/src/polypcore/sink.h b/src/polypcore/sink.h deleted file mode 100644 index 59d45597..00000000 --- a/src/polypcore/sink.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef foosinkhfoo -#define foosinkhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -typedef struct pa_sink pa_sink; - -#include -#include -#include -#include -#include -#include -#include -#include - -#define PA_MAX_INPUTS_PER_SINK 32 - -typedef enum pa_sink_state { - PA_SINK_RUNNING, - PA_SINK_DISCONNECTED -} pa_sink_state_t; - -struct pa_sink { - int ref; - uint32_t index; - pa_core *core; - pa_sink_state_t state; - - char *name, *description, *driver; - pa_module *owner; - - pa_sample_spec sample_spec; - pa_channel_map channel_map; - - pa_idxset *inputs; - pa_source *monitor_source; - - pa_cvolume hw_volume, sw_volume; - int hw_muted, sw_muted; - - void (*notify)(pa_sink*sink); - pa_usec_t (*get_latency)(pa_sink *s); - int (*set_hw_volume)(pa_sink *s); - int (*get_hw_volume)(pa_sink *s); - int (*set_hw_mute)(pa_sink *s); - int (*get_hw_mute)(pa_sink *s); - - void *userdata; -}; - -pa_sink* pa_sink_new( - pa_core *core, - const char *driver, - const char *name, - int namereg_fail, - const pa_sample_spec *spec, - const pa_channel_map *map); - -void pa_sink_disconnect(pa_sink* s); -void pa_sink_unref(pa_sink*s); -pa_sink* pa_sink_ref(pa_sink *s); - -int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result); -void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result); -int pa_sink_render_into(pa_sink*s, pa_memchunk *target); -void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target); - -pa_usec_t pa_sink_get_latency(pa_sink *s); - -void pa_sink_notify(pa_sink*s); - -void pa_sink_set_owner(pa_sink *sink, pa_module *m); - -void pa_sink_set_volume(pa_sink *sink, pa_mixer_t m, const pa_cvolume *volume); -const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_mixer_t m); -void pa_sink_set_mute(pa_sink *sink, pa_mixer_t m, int mute); -int pa_sink_get_mute(pa_sink *sink, pa_mixer_t m); - -#endif diff --git a/src/polypcore/sioman.c b/src/polypcore/sioman.c deleted file mode 100644 index b389ecee..00000000 --- a/src/polypcore/sioman.c +++ /dev/null @@ -1,43 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#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/polypcore/sioman.h b/src/polypcore/sioman.h deleted file mode 100644 index 840d93f2..00000000 --- a/src/polypcore/sioman.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef foosiomanhfoo -#define foosiomanhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -int pa_stdio_acquire(void); -void pa_stdio_release(void); - -#endif diff --git a/src/polypcore/socket-client.c b/src/polypcore/socket-client.c deleted file mode 100644 index efb6de9a..00000000 --- a/src/polypcore/socket-client.c +++ /dev/null @@ -1,526 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -/* #undef HAVE_LIBASYNCNS */ - -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_SYS_UN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif - -#ifdef HAVE_LIBASYNCNS -#include -#endif - -#include "winsock.h" - -#include -#include - -#include -#include -#include -#include -#include - -#include "socket-client.h" - -#define CONNECT_TIMEOUT 5 - -struct pa_socket_client { - int ref; - pa_mainloop_api *mainloop; - int fd; - pa_io_event *io_event; - pa_time_event *timeout_event; - pa_defer_event *defer_event; - void (*callback)(pa_socket_client*c, pa_iochannel *io, void *userdata); - void *userdata; - int local; -#ifdef HAVE_LIBASYNCNS - asyncns_t *asyncns; - asyncns_query_t * asyncns_query; - pa_io_event *asyncns_io_event; -#endif -}; - -static pa_socket_client*pa_socket_client_new(pa_mainloop_api *m) { - pa_socket_client *c; - assert(m); - - c = pa_xmalloc(sizeof(pa_socket_client)); - c->ref = 1; - c->mainloop = m; - c->fd = -1; - c->io_event = NULL; - c->defer_event = NULL; - c->timeout_event = NULL; - c->callback = NULL; - c->userdata = NULL; - c->local = 0; - -#ifdef HAVE_LIBASYNCNS - c->asyncns = NULL; - c->asyncns_io_event = NULL; - c->asyncns_query = NULL; -#endif - - return c; -} - -static void free_events(pa_socket_client *c) { - assert(c); - - if (c->io_event) { - c->mainloop->io_free(c->io_event); - c->io_event = NULL; - } - - if (c->defer_event) { - c->mainloop->defer_free(c->defer_event); - c->defer_event = NULL; - } - - if (c->timeout_event) { - c->mainloop->time_free(c->timeout_event); - c->timeout_event = NULL; - } -} - -static void do_call(pa_socket_client *c) { - pa_iochannel *io = NULL; - int error; - socklen_t lerror; - assert(c && c->callback); - - pa_socket_client_ref(c); - - if (c->fd < 0) - goto finish; - - lerror = sizeof(error); - if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &lerror) < 0) { - pa_log(__FILE__": getsockopt(): %s", pa_cstrerror(errno)); - goto finish; - } - - if (lerror != sizeof(error)) { - pa_log(__FILE__": getsockopt() returned invalid size."); - goto finish; - } - - if (error != 0) { - pa_log_debug(__FILE__": connect(): %s", pa_cstrerror(errno)); - errno = error; - goto finish; - } - - io = pa_iochannel_new(c->mainloop, c->fd, c->fd); - assert(io); - -finish: - if (!io && c->fd >= 0) - close(c->fd); - c->fd = -1; - - free_events(c); - - assert(c->callback); - c->callback(c, io, c->userdata); - - pa_socket_client_unref(c); -} - -static void connect_fixed_cb(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { - pa_socket_client *c = userdata; - assert(m && c && c->defer_event == e); - do_call(c); -} - -static void connect_io_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { - pa_socket_client *c = userdata; - assert(m && c && c->io_event == e && fd >= 0); - do_call(c); -} - -static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t len) { - int r; - assert(c && sa && len); - - pa_make_nonblock_fd(c->fd); - - if ((r = connect(c->fd, sa, len)) < 0) { -#ifdef OS_IS_WIN32 - if (WSAGetLastError() != EWOULDBLOCK) { - pa_log_debug(__FILE__": connect(): %d", WSAGetLastError()); -#else - if (errno != EINPROGRESS) { - pa_log_debug(__FILE__": connect(): %s (%d)", pa_cstrerror(errno), errno); -#endif - return -1; - } - - c->io_event = c->mainloop->io_new(c->mainloop, c->fd, PA_IO_EVENT_OUTPUT, connect_io_cb, c); - assert(c->io_event); - } else { - c->defer_event = c->mainloop->defer_new(c->mainloop, connect_fixed_cb, c); - assert(c->defer_event); - } - - return 0; -} - -pa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port) { - struct sockaddr_in sa; - assert(m && port > 0); - - memset(&sa, 0, sizeof(sa)); - sa.sin_family = AF_INET; - sa.sin_port = htons(port); - sa.sin_addr.s_addr = htonl(address); - - return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); -} - -#ifdef HAVE_SYS_UN_H - -pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) { - struct sockaddr_un sa; - assert(m && filename); - - memset(&sa, 0, sizeof(sa)); - sa.sun_family = AF_UNIX; - strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); - sa.sun_path[sizeof(sa.sun_path) - 1] = 0; - - return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); -} - -#else /* HAVE_SYS_UN_H */ - -pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) { - return NULL; -} - -#endif /* HAVE_SYS_UN_H */ - -static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size_t salen) { - assert(c); - assert(sa); - assert(salen); - - switch (sa->sa_family) { - case AF_UNIX: - c->local = 1; - break; - - case AF_INET: - c->local = ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK; - break; - - case AF_INET6: - c->local = memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0; - break; - - default: - c->local = 0; - } - - if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s", pa_cstrerror(errno)); - return -1; - } - - pa_fd_set_cloexec(c->fd, 1); - if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) - pa_socket_tcp_low_delay(c->fd); - else - pa_socket_low_delay(c->fd); - - if (do_connect(c, sa, salen) < 0) - return -1; - - return 0; -} - -pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) { - pa_socket_client *c; - assert(m && sa); - c = pa_socket_client_new(m); - assert(c); - - if (sockaddr_prepare(c, sa, salen) < 0) - goto fail; - - return c; - -fail: - pa_socket_client_unref(c); - return NULL; - -} - -static void socket_client_free(pa_socket_client *c) { - assert(c && c->mainloop); - - - free_events(c); - - if (c->fd >= 0) - close(c->fd); - -#ifdef HAVE_LIBASYNCNS - if (c->asyncns_query) - asyncns_cancel(c->asyncns, c->asyncns_query); - if (c->asyncns) - asyncns_free(c->asyncns); - if (c->asyncns_io_event) - c->mainloop->io_free(c->asyncns_io_event); -#endif - - pa_xfree(c); -} - -void pa_socket_client_unref(pa_socket_client *c) { - assert(c && c->ref >= 1); - - if (!(--(c->ref))) - socket_client_free(c); -} - -pa_socket_client* pa_socket_client_ref(pa_socket_client *c) { - assert(c && c->ref >= 1); - c->ref++; - return c; -} - -void pa_socket_client_set_callback(pa_socket_client *c, void (*on_connection)(pa_socket_client *c, pa_iochannel*io, void *userdata), void *userdata) { - assert(c); - c->callback = on_connection; - c->userdata = userdata; -} - -pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[16], uint16_t port) { - struct sockaddr_in6 sa; - - memset(&sa, 0, sizeof(sa)); - sa.sin6_family = AF_INET6; - sa.sin6_port = htons(port); - memcpy(&sa.sin6_addr, address, sizeof(sa.sin6_addr)); - - return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); -} - -#ifdef HAVE_LIBASYNCNS - -static void asyncns_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { - pa_socket_client *c = userdata; - struct addrinfo *res = NULL; - int ret; - assert(m && c && c->asyncns_io_event == e && fd >= 0); - - if (asyncns_wait(c->asyncns, 0) < 0) - goto fail; - - if (!asyncns_isdone(c->asyncns, c->asyncns_query)) - return; - - ret = asyncns_getaddrinfo_done(c->asyncns, c->asyncns_query, &res); - c->asyncns_query = NULL; - - if (ret != 0 || !res) - goto fail; - - if (res->ai_addr) - sockaddr_prepare(c, res->ai_addr, res->ai_addrlen); - - asyncns_freeaddrinfo(res); - - m->io_free(c->asyncns_io_event); - c->asyncns_io_event = NULL; - return; - -fail: - m->io_free(c->asyncns_io_event); - c->asyncns_io_event = NULL; - - errno = EHOSTUNREACH; - do_call(c); - return; - -} - -#endif - -static void timeout_cb(pa_mainloop_api *m, pa_time_event *e, const struct timeval *tv, void *userdata) { - pa_socket_client *c = userdata; - assert(m); - assert(e); - assert(tv); - assert(c); - - if (c->fd >= 0) { - close(c->fd); - c->fd = -1; - } - - errno = ETIMEDOUT; - do_call(c); -} - -static void start_timeout(pa_socket_client *c) { - struct timeval tv; - assert(c); - assert(!c->timeout_event); - - pa_gettimeofday(&tv); - pa_timeval_add(&tv, CONNECT_TIMEOUT * 1000000); - c->timeout_event = c->mainloop->time_new(c->mainloop, &tv, timeout_cb, c); -} - -pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*name, uint16_t default_port) { - pa_socket_client *c = NULL; - pa_parsed_address a; - assert(m && name); - - if (pa_parse_address(name, &a) < 0) - return NULL; - - if (!a.port) - a.port = default_port; - - switch (a.type) { - case PA_PARSED_ADDRESS_UNIX: - if ((c = pa_socket_client_new_unix(m, a.path_or_host))) - start_timeout(c); - break; - - case PA_PARSED_ADDRESS_TCP4: /* Fallthrough */ - case PA_PARSED_ADDRESS_TCP6: /* Fallthrough */ - case PA_PARSED_ADDRESS_TCP_AUTO:{ - - struct addrinfo hints; - char port[12]; - - snprintf(port, sizeof(port), "%u", (unsigned) a.port); - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = a.type == PA_PARSED_ADDRESS_TCP4 ? PF_INET : (a.type == PA_PARSED_ADDRESS_TCP6 ? PF_INET6 : PF_UNSPEC); - hints.ai_socktype = SOCK_STREAM; - -#ifdef HAVE_LIBASYNCNS - { - asyncns_t *asyncns; - - if (!(asyncns = asyncns_new(1))) - goto finish; - - c = pa_socket_client_new(m); - c->asyncns = asyncns; - c->asyncns_io_event = m->io_new(m, asyncns_fd(c->asyncns), PA_IO_EVENT_INPUT, asyncns_cb, c); - c->asyncns_query = asyncns_getaddrinfo(c->asyncns, a.path_or_host, port, &hints); - assert(c->asyncns_query); - start_timeout(c); - } -#else /* HAVE_LIBASYNCNS */ - { -#ifdef HAVE_GETADDRINFO - int ret; - struct addrinfo *res = NULL; - - ret = getaddrinfo(a.path_or_host, port, &hints, &res); - - if (ret < 0 || !res) - goto finish; - - if (res->ai_addr) { - if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen))) - start_timeout(c); - } - - freeaddrinfo(res); -#else /* HAVE_GETADDRINFO */ - struct hostent *host = NULL; - struct sockaddr_in s; - - /* FIXME: PF_INET6 support */ - if (hints.ai_family == PF_INET6) { - pa_log_error(__FILE__": IPv6 is not supported on Windows"); - goto finish; - } - - host = gethostbyname(a.path_or_host); - if (!host) { - unsigned int addr = inet_addr(a.path_or_host); - if (addr != INADDR_NONE) - host = gethostbyaddr((char*)&addr, 4, AF_INET); - } - - if (!host) - goto finish; - - s.sin_family = AF_INET; - memcpy(&s.sin_addr, host->h_addr, sizeof(struct in_addr)); - s.sin_port = htons(a.port); - - if ((c = pa_socket_client_new_sockaddr(m, (struct sockaddr*)&s, sizeof(s)))) - start_timeout(c); -#endif /* HAVE_GETADDRINFO */ - } -#endif /* HAVE_LIBASYNCNS */ - } - } - -finish: - pa_xfree(a.path_or_host); - return c; - -} - -/* Return non-zero when the target sockaddr is considered - local. "local" means UNIX socket or TCP socket on localhost. Other - local IP addresses are not considered local. */ -int pa_socket_client_is_local(pa_socket_client *c) { - assert(c); - return c->local; -} diff --git a/src/polypcore/socket-client.h b/src/polypcore/socket-client.h deleted file mode 100644 index d0005331..00000000 --- a/src/polypcore/socket-client.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef foosocketclienthfoo -#define foosocketclienthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include -#include - -struct sockaddr; - -typedef struct pa_socket_client pa_socket_client; - -pa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port); -pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[16], uint16_t port); -pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename); -pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen); -pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char *a, uint16_t default_port); - -void pa_socket_client_unref(pa_socket_client *c); -pa_socket_client* pa_socket_client_ref(pa_socket_client *c); - -void pa_socket_client_set_callback(pa_socket_client *c, void (*on_connection)(pa_socket_client *c, pa_iochannel*io, void *userdata), void *userdata); - -int pa_socket_client_is_local(pa_socket_client *c); - -#endif diff --git a/src/polypcore/socket-server.c b/src/polypcore/socket-server.c deleted file mode 100644 index 17071ec2..00000000 --- a/src/polypcore/socket-server.c +++ /dev/null @@ -1,505 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_SYS_UN_H -#include -#ifndef SUN_LEN -#define SUN_LEN(ptr) \ - ((size_t)(((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path)) -#endif -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif - -#ifdef HAVE_LIBWRAP -#include -#endif - -#ifndef HAVE_INET_NTOP -#include "inet_ntop.h" -#endif - -#ifndef HAVE_INET_PTON -#include "inet_pton.h" -#endif - -#include "winsock.h" - -#include -#include - -#include -#include -#include -#include - -#include "socket-server.h" - -struct pa_socket_server { - int ref; - int fd; - char *filename; - char *tcpwrap_service; - - void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata); - void *userdata; - - pa_io_event *io_event; - pa_mainloop_api *mainloop; - enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX, SOCKET_SERVER_IPV6 } type; -}; - -static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { - pa_socket_server *s = userdata; - pa_iochannel *io; - int nfd; - assert(s && s->mainloop == mainloop && s->io_event == e && e && fd >= 0 && fd == s->fd); - - pa_socket_server_ref(s); - - if ((nfd = accept(fd, NULL, NULL)) < 0) { - pa_log(__FILE__": accept(): %s", pa_cstrerror(errno)); - goto finish; - } - - pa_fd_set_cloexec(nfd, 1); - - if (!s->on_connection) { - close(nfd); - goto finish; - } - -#ifdef HAVE_LIBWRAP - - if (s->tcpwrap_service) { - struct request_info req; - - request_init(&req, RQ_DAEMON, s->tcpwrap_service, RQ_FILE, nfd, NULL); - fromhost(&req); - if (!hosts_access(&req)) { - pa_log_warn(__FILE__": TCP connection refused by tcpwrap."); - close(nfd); - goto finish; - } - - pa_log_info(__FILE__": TCP connection accepted by tcpwrap."); - } -#endif - - /* There should be a check for socket type here */ - if (s->type == SOCKET_SERVER_IPV4) - pa_socket_tcp_low_delay(fd); - else - pa_socket_low_delay(fd); - - io = pa_iochannel_new(s->mainloop, nfd, nfd); - assert(io); - s->on_connection(s, io, s->userdata); - -finish: - pa_socket_server_unref(s); -} - -pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) { - pa_socket_server *s; - assert(m && fd >= 0); - - s = pa_xmalloc(sizeof(pa_socket_server)); - s->ref = 1; - s->fd = fd; - s->filename = NULL; - s->on_connection = NULL; - s->userdata = NULL; - s->tcpwrap_service = NULL; - - s->mainloop = m; - s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s); - assert(s->io_event); - - s->type = SOCKET_SERVER_GENERIC; - - return s; -} - -pa_socket_server* pa_socket_server_ref(pa_socket_server *s) { - assert(s && s->ref >= 1); - s->ref++; - return s; -} - -#ifdef HAVE_SYS_UN_H - -pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) { - int fd = -1; - struct sockaddr_un sa; - pa_socket_server *s; - - assert(m && filename); - - if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s", pa_cstrerror(errno)); - goto fail; - } - - pa_fd_set_cloexec(fd, 1); - - sa.sun_family = AF_UNIX; - strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); - sa.sun_path[sizeof(sa.sun_path) - 1] = 0; - - pa_socket_low_delay(fd); - - if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) { - pa_log(__FILE__": bind(): %s", pa_cstrerror(errno)); - goto fail; - } - - if (listen(fd, 5) < 0) { - pa_log(__FILE__": listen(): %s", pa_cstrerror(errno)); - goto fail; - } - - s = pa_socket_server_new(m, fd); - assert(s); - - s->filename = pa_xstrdup(filename); - s->type = SOCKET_SERVER_UNIX; - - return s; - -fail: - if (fd >= 0) - close(fd); - - return NULL; -} - -#else /* HAVE_SYS_UN_H */ - -pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) { - return NULL; -} - -#endif /* HAVE_SYS_UN_H */ - -pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service) { - pa_socket_server *ss; - int fd = -1; - struct sockaddr_in sa; - int on = 1; - - assert(m && port); - - if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(PF_INET): %s", pa_cstrerror(errno)); - goto fail; - } - - pa_fd_set_cloexec(fd, 1); - -#ifdef SO_REUSEADDR - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) - pa_log(__FILE__": setsockopt(): %s", pa_cstrerror(errno)); -#endif - - pa_socket_tcp_low_delay(fd); - - memset(&sa, 0, sizeof(sa)); - sa.sin_family = AF_INET; - sa.sin_port = htons(port); - sa.sin_addr.s_addr = htonl(address); - - if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { - pa_log(__FILE__": bind(): %s", pa_cstrerror(errno)); - goto fail; - } - - if (listen(fd, 5) < 0) { - pa_log(__FILE__": listen(): %s", pa_cstrerror(errno)); - goto fail; - } - - if ((ss = pa_socket_server_new(m, fd))) { - ss->type = SOCKET_SERVER_IPV4; - ss->tcpwrap_service = pa_xstrdup(tcpwrap_service); - } - - return ss; - -fail: - if (fd >= 0) - close(fd); - - return NULL; -} - -pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port, const char *tcpwrap_service) { - pa_socket_server *ss; - int fd = -1; - struct sockaddr_in6 sa; - int on = 1; - - assert(m && port); - - if ((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(PF_INET6): %s", pa_cstrerror(errno)); - goto fail; - } - - pa_fd_set_cloexec(fd, 1); - -#ifdef IPV6_V6ONLY - if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) - pa_log(__FILE__": setsockopt(IPPROTO_IPV6, IPV6_V6ONLY): %s", pa_cstrerror(errno)); -#endif - -#ifdef SO_REUSEADDR - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) - pa_log(__FILE__": setsockopt(SOL_SOCKET, SO_REUSEADDR, 1): %s", pa_cstrerror(errno)); -#endif - - pa_socket_tcp_low_delay(fd); - - memset(&sa, 0, sizeof(sa)); - sa.sin6_family = AF_INET6; - sa.sin6_port = htons(port); - memcpy(sa.sin6_addr.s6_addr, address, 16); - - if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { - pa_log(__FILE__": bind(): %s", pa_cstrerror(errno)); - goto fail; - } - - if (listen(fd, 5) < 0) { - pa_log(__FILE__": listen(): %s", pa_cstrerror(errno)); - goto fail; - } - - if ((ss = pa_socket_server_new(m, fd))) { - ss->type = SOCKET_SERVER_IPV6; - ss->tcpwrap_service = pa_xstrdup(tcpwrap_service); - } - - return ss; - -fail: - if (fd >= 0) - close(fd); - - return NULL; -} - -pa_socket_server* pa_socket_server_new_ipv4_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { - assert(m); - assert(port > 0); - - return pa_socket_server_new_ipv4(m, INADDR_LOOPBACK, port, tcpwrap_service); -} - -pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { - assert(m); - assert(port > 0); - - return pa_socket_server_new_ipv6(m, in6addr_loopback.s6_addr, port, tcpwrap_service); -} - -pa_socket_server* pa_socket_server_new_ipv4_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { - assert(m); - assert(port > 0); - - return pa_socket_server_new_ipv4(m, INADDR_ANY, port, tcpwrap_service); -} - -pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { - assert(m); - assert(port > 0); - - return pa_socket_server_new_ipv6(m, in6addr_any.s6_addr, port, tcpwrap_service); -} - -pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) { - struct in_addr ipv4; - - assert(m); - assert(name); - assert(port > 0); - - if (inet_pton(AF_INET, name, &ipv4) > 0) - return pa_socket_server_new_ipv4(m, ntohl(ipv4.s_addr), port, tcpwrap_service); - - return NULL; -} - -pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) { - struct in6_addr ipv6; - - assert(m); - assert(name); - assert(port > 0); - - if (inet_pton(AF_INET6, name, &ipv6) > 0) - return pa_socket_server_new_ipv6(m, ipv6.s6_addr, port, tcpwrap_service); - - return NULL; -} - -static void socket_server_free(pa_socket_server*s) { - assert(s); - - if (s->filename) { - unlink(s->filename); - pa_xfree(s->filename); - } - - close(s->fd); - - pa_xfree(s->tcpwrap_service); - - s->mainloop->io_free(s->io_event); - pa_xfree(s); -} - -void pa_socket_server_unref(pa_socket_server *s) { - assert(s && s->ref >= 1); - - if (!(--(s->ref))) - socket_server_free(s); -} - -void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata), void *userdata) { - assert(s && s->ref >= 1); - - s->on_connection = on_connection; - s->userdata = userdata; -} - -char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { - assert(s && c && l > 0); - - switch (s->type) { - case SOCKET_SERVER_IPV6: { - struct sockaddr_in6 sa; - socklen_t sa_len = sizeof(sa); - - if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) { - pa_log(__FILE__": getsockname(): %s", pa_cstrerror(errno)); - return NULL; - } - - if (memcmp(&in6addr_any, &sa.sin6_addr, sizeof(in6addr_any)) == 0) { - char fqdn[256]; - if (!pa_get_fqdn(fqdn, sizeof(fqdn))) - return NULL; - - snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port)); - - } else if (memcmp(&in6addr_loopback, &sa.sin6_addr, sizeof(in6addr_loopback)) == 0) { - char hn[256]; - if (!pa_get_host_name(hn, sizeof(hn))) - return NULL; - - snprintf(c, l, "{%s}tcp6:localhost:%u", hn, (unsigned) ntohs(sa.sin6_port)); - } else { - char ip[INET6_ADDRSTRLEN]; - - if (!inet_ntop(AF_INET6, &sa.sin6_addr, ip, sizeof(ip))) { - pa_log(__FILE__": inet_ntop(): %s", pa_cstrerror(errno)); - return NULL; - } - - snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port)); - } - - return c; - } - - case SOCKET_SERVER_IPV4: { - struct sockaddr_in sa; - socklen_t sa_len = sizeof(sa); - - if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) { - pa_log(__FILE__": getsockname(): %s", pa_cstrerror(errno)); - return NULL; - } - - if (sa.sin_addr.s_addr == INADDR_ANY) { - char fqdn[256]; - if (!pa_get_fqdn(fqdn, sizeof(fqdn))) - return NULL; - - snprintf(c, l, "tcp:%s:%u", fqdn, (unsigned) ntohs(sa.sin_port)); - } else if (sa.sin_addr.s_addr == INADDR_LOOPBACK) { - char hn[256]; - if (!pa_get_host_name(hn, sizeof(hn))) - return NULL; - - snprintf(c, l, "{%s}tcp:localhost:%u", hn, (unsigned) ntohs(sa.sin_port)); - } else { - char ip[INET_ADDRSTRLEN]; - - if (!inet_ntop(AF_INET, &sa.sin_addr, ip, sizeof(ip))) { - pa_log(__FILE__": inet_ntop(): %s", pa_cstrerror(errno)); - return NULL; - } - - snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port)); - - } - - return c; - } - - case SOCKET_SERVER_UNIX: { - char hn[256]; - - if (!s->filename) - return NULL; - - if (!pa_get_host_name(hn, sizeof(hn))) - return NULL; - - snprintf(c, l, "{%s}unix:%s", hn, s->filename); - return c; - } - - default: - return NULL; - } -} diff --git a/src/polypcore/socket-server.h b/src/polypcore/socket-server.h deleted file mode 100644 index cd3276ad..00000000 --- a/src/polypcore/socket-server.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef foosocketserverhfoo -#define foosocketserverhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include - -/* It is safe to destroy the calling socket_server object from the callback */ - -typedef struct pa_socket_server pa_socket_server; - -pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd); -pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename); -pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service); -pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port, const char *tcpwrap_service); -pa_socket_server* pa_socket_server_new_ipv4_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); -pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); -pa_socket_server* pa_socket_server_new_ipv4_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); -pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); -pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service); -pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service); - -void pa_socket_server_unref(pa_socket_server*s); -pa_socket_server* pa_socket_server_ref(pa_socket_server *s); - -void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata), void *userdata); - -char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l); - -#endif diff --git a/src/polypcore/socket-util.c b/src/polypcore/socket-util.c deleted file mode 100644 index 3cd205db..00000000 --- a/src/polypcore/socket-util.c +++ /dev/null @@ -1,266 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_SYS_UN_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_IN_SYSTM_H -#include -#endif -#ifdef HAVE_NETINET_IP_H -#include -#endif -#ifdef HAVE_NETINET_TCP_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif - -#ifndef HAVE_INET_NTOP -#include "inet_ntop.h" -#endif - -#include "winsock.h" - -#include - -#include -#include -#include - -#include "socket-util.h" - -void pa_socket_peer_to_string(int fd, char *c, size_t l) { - struct stat st; - - assert(c && l && fd >= 0); - -#ifndef OS_IS_WIN32 - if (fstat(fd, &st) < 0) { - snprintf(c, l, "Invalid client fd"); - return; - } -#endif - -#ifndef OS_IS_WIN32 - if (S_ISSOCK(st.st_mode)) { -#endif - union { - struct sockaddr sa; - struct sockaddr_in in; - struct sockaddr_in6 in6; -#ifdef HAVE_SYS_UN_H - struct sockaddr_un un; -#endif - } sa; - socklen_t sa_len = sizeof(sa); - - if (getpeername(fd, &sa.sa, &sa_len) >= 0) { - - if (sa.sa.sa_family == AF_INET) { - uint32_t ip = ntohl(sa.in.sin_addr.s_addr); - - snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u", - ip >> 24, - (ip >> 16) & 0xFF, - (ip >> 8) & 0xFF, - ip & 0xFF, - ntohs(sa.in.sin_port)); - return; - } else if (sa.sa.sa_family == AF_INET6) { - char buf[INET6_ADDRSTRLEN]; - const char *res; - - res = inet_ntop(AF_INET6, &sa.in6.sin6_addr, buf, sizeof(buf)); - if (res) { - snprintf(c, l, "TCP/IP client from [%s]:%u", buf, ntohs(sa.in6.sin6_port)); - return; - } -#ifdef HAVE_SYS_UN_H - } else if (sa.sa.sa_family == AF_UNIX) { - snprintf(c, l, "UNIX socket client"); - return; -#endif - } - - } -#ifndef OS_IS_WIN32 - snprintf(c, l, "Unknown network client"); - return; - } else if (S_ISCHR(st.st_mode) && (fd == 0 || fd == 1)) { - snprintf(c, l, "STDIN/STDOUT client"); - return; - } -#endif /* OS_IS_WIN32 */ - - snprintf(c, l, "Unknown client"); -} - -int pa_socket_low_delay(int fd) { -#ifdef SO_PRIORITY - int priority; - assert(fd >= 0); - - priority = 7; - if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (void*)&priority, sizeof(priority)) < 0) - return -1; -#endif - - return 0; -} - -int pa_socket_tcp_low_delay(int fd) { - int ret, tos, on; - - assert(fd >= 0); - - ret = pa_socket_low_delay(fd); - - on = 1; - tos = 0; - -#if defined(SOL_TCP) || defined(IPPROTO_TCP) -#if defined(SOL_TCP) - if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0) -#else - if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0) -#endif - ret = -1; -#endif - -#if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || \ - defined(IPPROTO_IP)) - tos = IPTOS_LOWDELAY; -#ifdef SOL_IP - if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) -#else - if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) -#endif - ret = -1; -#endif - - return ret; - -} - -int pa_socket_set_rcvbuf(int fd, size_t l) { - assert(fd >= 0); - -/* if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&l, sizeof(l)) < 0) { */ -/* pa_log(__FILE__": SO_RCVBUF: %s", strerror(errno)); */ -/* return -1; */ -/* } */ - - return 0; -} - -int pa_socket_set_sndbuf(int fd, size_t l) { - assert(fd >= 0); - -/* if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&l, sizeof(l)) < 0) { */ -/* pa_log(__FILE__": SO_SNDBUF: %s", strerror(errno)); */ -/* return -1; */ -/* } */ - - return 0; -} - -#ifdef HAVE_SYS_UN_H - -int pa_unix_socket_is_stale(const char *fn) { - struct sockaddr_un sa; - int fd = -1, ret = -1; - - if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s", pa_cstrerror(errno)); - goto finish; - } - - sa.sun_family = AF_UNIX; - strncpy(sa.sun_path, fn, sizeof(sa.sun_path)-1); - sa.sun_path[sizeof(sa.sun_path) - 1] = 0; - - if (connect(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) { - if (errno == ECONNREFUSED) - ret = 1; - } else - ret = 0; - -finish: - if (fd >= 0) - close(fd); - - return ret; -} - -int pa_unix_socket_remove_stale(const char *fn) { - int r; - - if ((r = pa_unix_socket_is_stale(fn)) < 0) - return errno != ENOENT ? -1 : 0; - - if (!r) - return 0; - - /* Yes, here is a race condition. But who cares? */ - if (unlink(fn) < 0) - return -1; - - return 0; -} - -#else /* HAVE_SYS_UN_H */ - -int pa_unix_socket_is_stale(const char *fn) { - return -1; -} - -int pa_unix_socket_remove_stale(const char *fn) { - return -1; -} - -#endif /* HAVE_SYS_UN_H */ diff --git a/src/polypcore/socket-util.h b/src/polypcore/socket-util.h deleted file mode 100644 index ae16fb16..00000000 --- a/src/polypcore/socket-util.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef foosocketutilhfoo -#define foosocketutilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -void pa_socket_peer_to_string(int fd, char *c, size_t l); - -int pa_socket_low_delay(int fd); -int pa_socket_tcp_low_delay(int fd); - -int pa_socket_set_sndbuf(int fd, size_t l); -int pa_socket_set_rcvbuf(int fd, size_t l); - -int pa_unix_socket_is_stale(const char *fn); -int pa_unix_socket_remove_stale(const char *fn); - -#endif diff --git a/src/polypcore/sound-file-stream.c b/src/polypcore/sound-file-stream.c deleted file mode 100644 index 68fd8a89..00000000 --- a/src/polypcore/sound-file-stream.c +++ /dev/null @@ -1,192 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -#include - -#include -#include - -#include "sound-file-stream.h" - -#define BUF_SIZE (1024*10) - -struct userdata { - SNDFILE *sndfile; - pa_sink_input *sink_input; - pa_memchunk memchunk; - sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames); -}; - -static void free_userdata(struct userdata *u) { - assert(u); - if (u->sink_input) { - pa_sink_input_disconnect(u->sink_input); - pa_sink_input_unref(u->sink_input); - } - - if (u->memchunk.memblock) - pa_memblock_unref(u->memchunk.memblock); - if (u->sndfile) - sf_close(u->sndfile); - - pa_xfree(u); -} - -static void sink_input_kill(pa_sink_input *i) { - assert(i && i->userdata); - free_userdata(i->userdata); -} - -static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { - struct userdata *u; - assert(i && chunk && i->userdata); - u = i->userdata; - - if (!u->memchunk.memblock) { - uint32_t fs = pa_frame_size(&i->sample_spec); - sf_count_t n; - - u->memchunk.memblock = pa_memblock_new(BUF_SIZE, i->sink->core->memblock_stat); - u->memchunk.index = 0; - - if (u->readf_function) { - if ((n = u->readf_function(u->sndfile, u->memchunk.memblock->data, BUF_SIZE/fs)) <= 0) - n = 0; - - u->memchunk.length = n * fs; - } else { - if ((n = sf_read_raw(u->sndfile, u->memchunk.memblock->data, BUF_SIZE)) <= 0) - n = 0; - - u->memchunk.length = n; - } - - if (!u->memchunk.length) { - free_userdata(u); - return -1; - } - } - - *chunk = u->memchunk; - pa_memblock_ref(chunk->memblock); - assert(chunk->length); - return 0; -} - -static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) { - struct userdata *u; - assert(i && chunk && length && i->userdata); - u = i->userdata; - - assert(!memcmp(chunk, &u->memchunk, sizeof(chunk))); - assert(length <= u->memchunk.length); - - u->memchunk.index += length; - u->memchunk.length -= length; - - if (u->memchunk.length <= 0) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - u->memchunk.index = u->memchunk.length = 0; - } -} - -int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume) { - struct userdata *u = NULL; - SF_INFO sfinfo; - pa_sample_spec ss; - assert(sink && fname); - - u = pa_xmalloc(sizeof(struct userdata)); - u->sink_input = NULL; - u->memchunk.memblock = NULL; - u->memchunk.index = u->memchunk.length = 0; - u->sndfile = NULL; - - memset(&sfinfo, 0, sizeof(sfinfo)); - - if (!(u->sndfile = sf_open(fname, SFM_READ, &sfinfo))) { - pa_log(__FILE__": Failed to open file %s", fname); - goto fail; - } - - u->readf_function = NULL; - - switch (sfinfo.format & 0xFF) { - case SF_FORMAT_PCM_16: - case SF_FORMAT_PCM_U8: - case SF_FORMAT_PCM_S8: - ss.format = PA_SAMPLE_S16NE; - u->readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_short; - break; - - case SF_FORMAT_ULAW: - ss.format = PA_SAMPLE_ULAW; - break; - - case SF_FORMAT_ALAW: - ss.format = PA_SAMPLE_ALAW; - break; - - case SF_FORMAT_FLOAT: - default: - ss.format = PA_SAMPLE_FLOAT32NE; - u->readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_float; - break; - } - - ss.rate = sfinfo.samplerate; - ss.channels = sfinfo.channels; - - if (!pa_sample_spec_valid(&ss)) { - pa_log(__FILE__": Unsupported sample format in file %s", fname); - goto fail; - } - - if (!(u->sink_input = pa_sink_input_new(sink, __FILE__, fname, &ss, NULL, volume, 0, -1))) - goto fail; - - u->sink_input->peek = sink_input_peek; - u->sink_input->drop = sink_input_drop; - u->sink_input->kill = sink_input_kill; - u->sink_input->userdata = u; - - pa_sink_notify(sink); - - return 0; - -fail: - if (u) - free_userdata(u); - - return -1; -} diff --git a/src/polypcore/sound-file-stream.h b/src/polypcore/sound-file-stream.h deleted file mode 100644 index 5effc7f0..00000000 --- a/src/polypcore/sound-file-stream.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef foosoundfilestreamhfoo -#define foosoundfilestreamhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume); - -#endif diff --git a/src/polypcore/sound-file.c b/src/polypcore/sound-file.c deleted file mode 100644 index bd0cf596..00000000 --- a/src/polypcore/sound-file.c +++ /dev/null @@ -1,163 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include - -#include -#include - -#include "sound-file.h" -#include "core-scache.h" - -int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_channel_map *map, pa_memchunk *chunk, pa_memblock_stat *s) { - SNDFILE*sf = NULL; - SF_INFO sfinfo; - int ret = -1; - size_t l; - sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames) = NULL; - assert(fname && ss && chunk); - - chunk->memblock = NULL; - chunk->index = chunk->length = 0; - - memset(&sfinfo, 0, sizeof(sfinfo)); - - if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) { - pa_log(__FILE__": Failed to open file %s", fname); - goto finish; - } - - switch (sfinfo.format & SF_FORMAT_SUBMASK) { - case SF_FORMAT_PCM_16: - case SF_FORMAT_PCM_U8: - case SF_FORMAT_PCM_S8: - ss->format = PA_SAMPLE_S16NE; - readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_short; - break; - - case SF_FORMAT_ULAW: - ss->format = PA_SAMPLE_ULAW; - break; - - case SF_FORMAT_ALAW: - ss->format = PA_SAMPLE_ALAW; - break; - - case SF_FORMAT_FLOAT: - case SF_FORMAT_DOUBLE: - default: - ss->format = PA_SAMPLE_FLOAT32NE; - readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_float; - break; - } - - ss->rate = sfinfo.samplerate; - ss->channels = sfinfo.channels; - - if (!pa_sample_spec_valid(ss)) { - pa_log(__FILE__": Unsupported sample format in file %s", fname); - goto finish; - } - - if (map) - pa_channel_map_init_auto(map, ss->channels, PA_CHANNEL_MAP_DEFAULT); - - if ((l = pa_frame_size(ss)*sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) { - pa_log(__FILE__": File too large"); - goto finish; - } - - chunk->memblock = pa_memblock_new(l, s); - assert(chunk->memblock); - chunk->index = 0; - chunk->length = l; - - if ((readf_function && readf_function(sf, chunk->memblock->data, sfinfo.frames) != sfinfo.frames) || - (!readf_function && sf_read_raw(sf, chunk->memblock->data, l) != l)) { - pa_log(__FILE__": Premature file end"); - goto finish; - } - - ret = 0; - -finish: - - if (sf) - sf_close(sf); - - if (ret != 0 && chunk->memblock) - pa_memblock_unref(chunk->memblock); - - return ret; - -} - -int pa_sound_file_too_big_to_cache(const char *fname) { - SNDFILE*sf = NULL; - SF_INFO sfinfo; - pa_sample_spec ss; - - if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) { - pa_log(__FILE__": Failed to open file %s", fname); - return 0; - } - - sf_close(sf); - - switch (sfinfo.format & SF_FORMAT_SUBMASK) { - case SF_FORMAT_PCM_16: - case SF_FORMAT_PCM_U8: - case SF_FORMAT_PCM_S8: - ss.format = PA_SAMPLE_S16NE; - break; - - case SF_FORMAT_ULAW: - ss.format = PA_SAMPLE_ULAW; - break; - - case SF_FORMAT_ALAW: - ss.format = PA_SAMPLE_ALAW; - break; - - case SF_FORMAT_DOUBLE: - case SF_FORMAT_FLOAT: - default: - ss.format = PA_SAMPLE_FLOAT32NE; - break; - } - - ss.rate = sfinfo.samplerate; - ss.channels = sfinfo.channels; - - if ((pa_frame_size(&ss) * sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) { - pa_log(__FILE__": File too large %s", fname); - return 1; - } - - return 0; -} diff --git a/src/polypcore/sound-file.h b/src/polypcore/sound-file.h deleted file mode 100644 index 9d687f90..00000000 --- a/src/polypcore/sound-file.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef soundfilehfoo -#define soundfilehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include - -int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_channel_map *map, pa_memchunk *chunk, pa_memblock_stat *s); - -int pa_sound_file_too_big_to_cache(const char *fname); - -#endif diff --git a/src/polypcore/source-output.c b/src/polypcore/source-output.c deleted file mode 100644 index 8ac3a33d..00000000 --- a/src/polypcore/source-output.c +++ /dev/null @@ -1,241 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "source-output.h" - -#define CHECK_VALIDITY_RETURN_NULL(condition) \ -do {\ -if (!(condition)) \ - return NULL; \ -} while (0) - -pa_source_output* pa_source_output_new( - pa_source *s, - const char *driver, - const char *name, - const pa_sample_spec *spec, - const pa_channel_map *map, - int resample_method) { - - pa_source_output *o; - pa_resampler *resampler = NULL; - int r; - char st[256]; - pa_channel_map tmap; - - assert(s); - assert(spec); - assert(s->state == PA_SOURCE_RUNNING); - - CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec)); - - if (!map) - map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT); - - CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map)); - CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels); - CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver)); - CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name)); - - if (pa_idxset_size(s->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { - pa_log(__FILE__": Failed to create source output: too many outputs per source."); - return NULL; - } - - if (resample_method == PA_RESAMPLER_INVALID) - resample_method = s->core->resample_method; - - if (!pa_sample_spec_equal(&s->sample_spec, spec) || !pa_channel_map_equal(&s->channel_map, map)) - if (!(resampler = pa_resampler_new(&s->sample_spec, &s->channel_map, spec, map, s->core->memblock_stat, resample_method))) - return NULL; - - o = pa_xnew(pa_source_output, 1); - o->ref = 1; - o->state = PA_SOURCE_OUTPUT_RUNNING; - o->name = pa_xstrdup(name); - o->driver = pa_xstrdup(driver); - o->owner = NULL; - o->source = s; - o->client = NULL; - - o->sample_spec = *spec; - o->channel_map = *map; - - o->push = NULL; - o->kill = NULL; - o->get_latency = NULL; - o->userdata = NULL; - - o->resampler = resampler; - - assert(s->core); - r = pa_idxset_put(s->core->source_outputs, o, &o->index); - assert(r == 0 && o->index != PA_IDXSET_INVALID); - r = pa_idxset_put(s->outputs, o, NULL); - assert(r == 0); - - pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"", o->index, o->name, s->index, st); - - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); - - return o; -} - -void pa_source_output_disconnect(pa_source_output*o) { - assert(o); - assert(o->state != PA_SOURCE_OUTPUT_DISCONNECTED); - assert(o->source); - assert(o->source->core); - - pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); - pa_idxset_remove_by_data(o->source->outputs, o, NULL); - - pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); - o->source = NULL; - - o->push = NULL; - o->kill = NULL; - o->get_latency = NULL; - - o->state = PA_SOURCE_OUTPUT_DISCONNECTED; -} - -static void source_output_free(pa_source_output* o) { - assert(o); - - if (o->state != PA_SOURCE_OUTPUT_DISCONNECTED) - pa_source_output_disconnect(o); - - pa_log_info(__FILE__": freed %u \"%s\"", o->index, o->name); - - if (o->resampler) - pa_resampler_free(o->resampler); - - pa_xfree(o->name); - pa_xfree(o->driver); - pa_xfree(o); -} - -void pa_source_output_unref(pa_source_output* o) { - assert(o); - assert(o->ref >= 1); - - if (!(--o->ref)) - source_output_free(o); -} - -pa_source_output* pa_source_output_ref(pa_source_output *o) { - assert(o); - assert(o->ref >= 1); - - o->ref++; - return o; -} - - -void pa_source_output_kill(pa_source_output*o) { - assert(o); - assert(o->ref >= 1); - - if (o->kill) - o->kill(o); -} - -void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { - pa_memchunk rchunk; - - assert(o); - assert(chunk); - assert(chunk->length); - assert(o->push); - - if (o->state == PA_SOURCE_OUTPUT_CORKED) - return; - - if (!o->resampler) { - o->push(o, chunk); - return; - } - - pa_resampler_run(o->resampler, chunk, &rchunk); - if (!rchunk.length) - return; - - assert(rchunk.memblock); - o->push(o, &rchunk); - pa_memblock_unref(rchunk.memblock); -} - -void pa_source_output_set_name(pa_source_output *o, const char *name) { - assert(o); - assert(o->ref >= 1); - - pa_xfree(o->name); - o->name = pa_xstrdup(name); - - pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); -} - -pa_usec_t pa_source_output_get_latency(pa_source_output *o) { - assert(o); - assert(o->ref >= 1); - - if (o->get_latency) - return o->get_latency(o); - - return 0; -} - -void pa_source_output_cork(pa_source_output *o, int b) { - assert(o); - assert(o->ref >= 1); - - if (o->state == PA_SOURCE_OUTPUT_DISCONNECTED) - return; - - o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; -} - -pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { - assert(o); - assert(o->ref >= 1); - - if (!o->resampler) - return PA_RESAMPLER_INVALID; - - return pa_resampler_get_method(o->resampler); -} diff --git a/src/polypcore/source-output.h b/src/polypcore/source-output.h deleted file mode 100644 index 1c612052..00000000 --- a/src/polypcore/source-output.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef foosourceoutputhfoo -#define foosourceoutputhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -typedef struct pa_source_output pa_source_output; - -#include -#include -#include -#include -#include -#include - -typedef enum { - PA_SOURCE_OUTPUT_RUNNING, - PA_SOURCE_OUTPUT_CORKED, - PA_SOURCE_OUTPUT_DISCONNECTED -} pa_source_output_state_t; - -struct pa_source_output { - int ref; - uint32_t index; - pa_source_output_state_t state; - - char *name, *driver; - pa_module *owner; - - pa_source *source; - pa_client *client; - - pa_sample_spec sample_spec; - pa_channel_map channel_map; - - void (*push)(pa_source_output *o, const pa_memchunk *chunk); - void (*kill)(pa_source_output* o); - pa_usec_t (*get_latency) (pa_source_output *o); - - pa_resampler* resampler; - - void *userdata; -}; - -pa_source_output* pa_source_output_new( - pa_source *s, - const char *driver, - const char *name, - const pa_sample_spec *spec, - const pa_channel_map *map, - int resample_method); - -void pa_source_output_unref(pa_source_output* o); -pa_source_output* pa_source_output_ref(pa_source_output *o); - -/* To be called by the implementing module only */ -void pa_source_output_disconnect(pa_source_output*o); - -/* External code may request disconnection with this funcion */ -void pa_source_output_kill(pa_source_output*o); - -void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk); - -void pa_source_output_set_name(pa_source_output *i, const char *name); - -pa_usec_t pa_source_output_get_latency(pa_source_output *i); - -void pa_source_output_cork(pa_source_output *i, int b); - -pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o); - -#endif diff --git a/src/polypcore/source.c b/src/polypcore/source.c deleted file mode 100644 index c53bf079..00000000 --- a/src/polypcore/source.c +++ /dev/null @@ -1,313 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include "source.h" - -#define CHECK_VALIDITY_RETURN_NULL(condition) \ -do {\ -if (!(condition)) \ - return NULL; \ -} while (0) - -pa_source* pa_source_new( - pa_core *core, - const char *driver, - const char *name, - int fail, - const pa_sample_spec *spec, - const pa_channel_map *map) { - - pa_source *s; - char st[256]; - int r; - pa_channel_map tmap; - - assert(core); - assert(name); - assert(spec); - - CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec)); - - if (!map) - map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT); - - CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map)); - CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels); - CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver)); - CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name) && *name); - - s = pa_xnew(pa_source, 1); - - if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SOURCE, s, fail))) { - pa_xfree(s); - return NULL; - } - - s->ref = 1; - s->core = core; - s->state = PA_SOURCE_RUNNING; - s->name = pa_xstrdup(name); - s->description = NULL; - s->driver = pa_xstrdup(driver); - s->owner = NULL; - - s->sample_spec = *spec; - s->channel_map = *map; - - s->outputs = pa_idxset_new(NULL, NULL); - s->monitor_of = NULL; - - pa_cvolume_reset(&s->sw_volume, spec->channels); - pa_cvolume_reset(&s->hw_volume, spec->channels); - s->sw_muted = 0; - s->hw_muted = 0; - - s->get_latency = NULL; - s->notify = NULL; - s->set_hw_volume = NULL; - s->get_hw_volume = NULL; - s->set_hw_mute = NULL; - s->get_hw_mute = NULL; - s->userdata = NULL; - - r = pa_idxset_put(core->sources, s, &s->index); - assert(s->index != PA_IDXSET_INVALID && r >= 0); - - pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"", s->index, s->name, st); - - pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index); - - return s; -} - -void pa_source_disconnect(pa_source *s) { - pa_source_output *o, *j = NULL; - - assert(s); - assert(s->state == PA_SOURCE_RUNNING); - - pa_namereg_unregister(s->core, s->name); - - while ((o = pa_idxset_first(s->outputs, NULL))) { - assert(o != j); - pa_source_output_kill(o); - j = o; - } - - pa_idxset_remove_by_data(s->core->sources, s, NULL); - - s->get_latency = NULL; - s->notify = NULL; - s->get_hw_volume = NULL; - s->set_hw_volume = NULL; - s->set_hw_mute = NULL; - s->get_hw_mute = NULL; - - s->state = PA_SOURCE_DISCONNECTED; - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); -} - -static void source_free(pa_source *s) { - assert(s); - assert(!s->ref); - - if (s->state != PA_SOURCE_DISCONNECTED) - pa_source_disconnect(s); - - pa_log_info(__FILE__": freed %u \"%s\"", s->index, s->name); - - pa_idxset_free(s->outputs, NULL, NULL); - - pa_xfree(s->name); - pa_xfree(s->description); - pa_xfree(s->driver); - pa_xfree(s); -} - -void pa_source_unref(pa_source *s) { - assert(s); - assert(s->ref >= 1); - - if (!(--s->ref)) - source_free(s); -} - -pa_source* pa_source_ref(pa_source *s) { - assert(s); - assert(s->ref >= 1); - - s->ref++; - return s; -} - -void pa_source_notify(pa_source*s) { - assert(s); - assert(s->ref >= 1); - - if (s->notify) - s->notify(s); -} - -static int do_post(void *p, PA_GCC_UNUSED uint32_t idx, PA_GCC_UNUSED int *del, void*userdata) { - pa_source_output *o = p; - const pa_memchunk *chunk = userdata; - - assert(o); - assert(chunk); - - pa_source_output_push(o, chunk); - return 0; -} - -void pa_source_post(pa_source*s, const pa_memchunk *chunk) { - assert(s); - assert(s->ref >= 1); - assert(chunk); - - pa_source_ref(s); - - if (s->sw_muted || !pa_cvolume_is_norm(&s->sw_volume)) { - pa_memchunk vchunk = *chunk; - - pa_memblock_ref(vchunk.memblock); - pa_memchunk_make_writable(&vchunk, s->core->memblock_stat, 0); - if (s->sw_muted) - pa_silence_memchunk(&vchunk, &s->sample_spec); - else - pa_volume_memchunk(&vchunk, &s->sample_spec, &s->sw_volume); - pa_idxset_foreach(s->outputs, do_post, &vchunk); - pa_memblock_unref(vchunk.memblock); - } else - pa_idxset_foreach(s->outputs, do_post, (void*) chunk); - - pa_source_unref(s); -} - -void pa_source_set_owner(pa_source *s, pa_module *m) { - assert(s); - assert(s->ref >= 1); - - s->owner = m; -} - -pa_usec_t pa_source_get_latency(pa_source *s) { - assert(s); - assert(s->ref >= 1); - - if (!s->get_latency) - return 0; - - return s->get_latency(s); -} - -void pa_source_set_volume(pa_source *s, pa_mixer_t m, const pa_cvolume *volume) { - pa_cvolume *v; - - assert(s); - assert(s->ref >= 1); - assert(volume); - - if (m == PA_MIXER_HARDWARE && s->set_hw_volume) - v = &s->hw_volume; - else - v = &s->sw_volume; - - if (pa_cvolume_equal(v, volume)) - return; - - *v = *volume; - - if (v == &s->hw_volume) - if (s->set_hw_volume(s) < 0) - s->sw_volume = *volume; - - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); -} - -const pa_cvolume *pa_source_get_volume(pa_source *s, pa_mixer_t m) { - assert(s); - assert(s->ref >= 1); - - if (m == PA_MIXER_HARDWARE && s->set_hw_volume) { - - if (s->get_hw_volume) - s->get_hw_volume(s); - - return &s->hw_volume; - } else - return &s->sw_volume; -} - -void pa_source_set_mute(pa_source *s, pa_mixer_t m, int mute) { - int *t; - - assert(s); - assert(s->ref >= 1); - - if (m == PA_MIXER_HARDWARE && s->set_hw_mute) - t = &s->hw_muted; - else - t = &s->sw_muted; - - if (!!*t == !!mute) - return; - - *t = !!mute; - - if (t == &s->hw_muted) - if (s->set_hw_mute(s) < 0) - s->sw_muted = !!mute; - - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); -} - -int pa_source_get_mute(pa_source *s, pa_mixer_t m) { - assert(s); - assert(s->ref >= 1); - - if (m == PA_MIXER_HARDWARE && s->set_hw_mute) { - - if (s->get_hw_mute) - s->get_hw_mute(s); - - return s->hw_muted; - } else - return s->sw_muted; -} diff --git a/src/polypcore/source.h b/src/polypcore/source.h deleted file mode 100644 index 63b77624..00000000 --- a/src/polypcore/source.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef foosourcehfoo -#define foosourcehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -typedef struct pa_source pa_source; - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PA_MAX_OUTPUTS_PER_SOURCE 16 - -typedef enum pa_source_state { - PA_SOURCE_RUNNING, - PA_SOURCE_DISCONNECTED -} pa_source_state_t; - -struct pa_source { - int ref; - uint32_t index; - pa_core *core; - pa_source_state_t state; - - char *name, *description, *driver; - pa_module *owner; - - pa_sample_spec sample_spec; - pa_channel_map channel_map; - - pa_idxset *outputs; - pa_sink *monitor_of; - - pa_cvolume hw_volume, sw_volume; - int hw_muted, sw_muted; - - void (*notify)(pa_source*source); - pa_usec_t (*get_latency)(pa_source *s); - int (*set_hw_volume)(pa_source *s); - int (*get_hw_volume)(pa_source *s); - int (*set_hw_mute)(pa_source *s); - int (*get_hw_mute)(pa_source *s); - - void *userdata; -}; - -pa_source* pa_source_new( - pa_core *core, - const char *driver, - const char *name, - int namereg_fail, - const pa_sample_spec *spec, - const pa_channel_map *map); - -void pa_source_disconnect(pa_source *s); -void pa_source_unref(pa_source *s); -pa_source* pa_source_ref(pa_source *c); - -/* Pass a new memory block to all output streams */ -void pa_source_post(pa_source*s, const pa_memchunk *b); - -void pa_source_notify(pa_source *s); - -void pa_source_set_owner(pa_source *s, pa_module *m); - -pa_usec_t pa_source_get_latency(pa_source *s); - -void pa_source_set_volume(pa_source *source, pa_mixer_t m, const pa_cvolume *volume); -const pa_cvolume *pa_source_get_volume(pa_source *source, pa_mixer_t m); -void pa_source_set_mute(pa_source *source, pa_mixer_t m, int mute); -int pa_source_get_mute(pa_source *source, pa_mixer_t m); - -#endif diff --git a/src/polypcore/strbuf.c b/src/polypcore/strbuf.c deleted file mode 100644 index d1517a11..00000000 --- a/src/polypcore/strbuf.c +++ /dev/null @@ -1,167 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include - -#include "strbuf.h" - -/* A chunk of the linked list that makes up the string */ -struct chunk { - struct chunk *next; - size_t length; -}; - -#define CHUNK_TO_TEXT(c) ((char*) (c) + sizeof(struct chunk)) - -struct pa_strbuf { - size_t length; - struct chunk *head, *tail; -}; - -pa_strbuf *pa_strbuf_new(void) { - pa_strbuf *sb = pa_xmalloc(sizeof(pa_strbuf)); - sb->length = 0; - sb->head = sb->tail = NULL; - return sb; -} - -void pa_strbuf_free(pa_strbuf *sb) { - assert(sb); - while (sb->head) { - struct chunk *c = sb->head; - sb->head = sb->head->next; - pa_xfree(c); - } - - pa_xfree(sb); -} - -/* Make a C string from the string buffer. The caller has to free - * string with pa_xfree(). */ -char *pa_strbuf_tostring(pa_strbuf *sb) { - char *t, *e; - struct chunk *c; - assert(sb); - - e = t = pa_xmalloc(sb->length+1); - - for (c = sb->head; c; c = c->next) { - assert((size_t) (e-t) <= sb->length); - memcpy(e, CHUNK_TO_TEXT(c), c->length); - e += c->length; - } - - /* Trailing NUL */ - *e = 0; - - assert(e == t+sb->length); - - return t; -} - -/* Combination of pa_strbuf_free() and pa_strbuf_tostring() */ -char *pa_strbuf_tostring_free(pa_strbuf *sb) { - char *t; - assert(sb); - t = pa_strbuf_tostring(sb); - pa_strbuf_free(sb); - return t; -} - -/* Append a string to the string buffer */ -void pa_strbuf_puts(pa_strbuf *sb, const char *t) { - assert(sb && t); - pa_strbuf_putsn(sb, t, strlen(t)); -} - -/* Append a new chunk to the linked list */ -static void append(pa_strbuf *sb, struct chunk *c) { - assert(sb && c); - - if (sb->tail) { - assert(sb->head); - sb->tail->next = c; - } else { - assert(!sb->head); - sb->head = c; - } - - sb->tail = c; - sb->length += c->length; - c->next = NULL; -} - -/* Append up to l bytes of a string to the string buffer */ -void pa_strbuf_putsn(pa_strbuf *sb, const char *t, size_t l) { - struct chunk *c; - assert(sb && t); - - if (!l) - return; - - c = pa_xmalloc(sizeof(struct chunk)+l); - c->length = l; - memcpy(CHUNK_TO_TEXT(c), t, l); - - append(sb, c); -} - -/* Append a printf() style formatted string to the string buffer. */ -/* The following is based on an example from the GNU libc documentation */ -int pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) { - int size = 100; - struct chunk *c = NULL; - - assert(sb); - - for(;;) { - va_list ap; - int r; - - c = pa_xrealloc(c, sizeof(struct chunk)+size); - - va_start(ap, format); - r = vsnprintf(CHUNK_TO_TEXT(c), size, format, ap); - va_end(ap); - - if (r > -1 && r < size) { - c->length = r; - append(sb, c); - return r; - } - - if (r > -1) /* glibc 2.1 */ - size = r+1; - else /* glibc 2.0 */ - size *= 2; - } -} diff --git a/src/polypcore/strbuf.h b/src/polypcore/strbuf.h deleted file mode 100644 index 4b06a7e6..00000000 --- a/src/polypcore/strbuf.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef foostrbufhfoo -#define foostrbufhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -typedef struct pa_strbuf pa_strbuf; - -pa_strbuf *pa_strbuf_new(void); -void pa_strbuf_free(pa_strbuf *sb); -char *pa_strbuf_tostring(pa_strbuf *sb); -char *pa_strbuf_tostring_free(pa_strbuf *sb); - -int pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); -void pa_strbuf_puts(pa_strbuf *sb, const char *t); -void pa_strbuf_putsn(pa_strbuf *sb, const char *t, size_t m); - -#endif diff --git a/src/polypcore/strlist.c b/src/polypcore/strlist.c deleted file mode 100644 index b9420749..00000000 --- a/src/polypcore/strlist.c +++ /dev/null @@ -1,139 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include - -#include -#include - -#include "strlist.h" - -struct pa_strlist { - pa_strlist *next; - char *str; -}; - -pa_strlist* pa_strlist_prepend(pa_strlist *l, const char *s) { - pa_strlist *n; - assert(s); - n = pa_xmalloc(sizeof(pa_strlist)); - n->str = pa_xstrdup(s); - n->next = l; - return n; -} - -char *pa_strlist_tostring(pa_strlist *l) { - int first = 1; - pa_strbuf *b; - - b = pa_strbuf_new(); - for (; l; l = l->next) { - if (!first) - pa_strbuf_puts(b, " "); - first = 0; - pa_strbuf_puts(b, l->str); - } - - return pa_strbuf_tostring_free(b); -} - -pa_strlist* pa_strlist_remove(pa_strlist *l, const char *s) { - pa_strlist *ret = l, *prev = NULL; - assert(l && s); - - while (l) { - if (!strcmp(l->str, s)) { - pa_strlist *n = l->next; - - if (!prev) { - assert(ret == l); - ret = n; - } else - prev->next = n; - - pa_xfree(l->str); - pa_xfree(l); - - l = n; - - } else { - prev = l; - l = l->next; - } - } - - return ret; -} - -void pa_strlist_free(pa_strlist *l) { - while (l) { - pa_strlist *c = l; - l = l->next; - - pa_xfree(c->str); - pa_xfree(c); - } -} - -pa_strlist* pa_strlist_pop(pa_strlist *l, char **s) { - pa_strlist *r; - assert(s); - - if (!l) { - *s = NULL; - return NULL; - } - - *s = l->str; - r = l->next; - pa_xfree(l); - return r; -} - -pa_strlist* pa_strlist_parse(const char *s) { - pa_strlist *head = NULL, *p = NULL; - const char *state = NULL; - char *r; - - while ((r = pa_split_spaces(s, &state))) { - pa_strlist *n; - - n = pa_xmalloc(sizeof(pa_strlist)); - n->str = r; - n->next = NULL; - - if (p) - p->next = n; - else - head = n; - - p = n; - } - - return head; -} diff --git a/src/polypcore/strlist.h b/src/polypcore/strlist.h deleted file mode 100644 index 2c54dc74..00000000 --- a/src/polypcore/strlist.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef foostrlisthfoo -#define foostrlisthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -typedef struct pa_strlist pa_strlist; - -/* Add the specified server string to the list, return the new linked list head */ -pa_strlist* pa_strlist_prepend(pa_strlist *l, const char *s); - -/* Remove the specified string from the list, return the new linked list head */ -pa_strlist* pa_strlist_remove(pa_strlist *l, const char *s); - -/* Make a whitespace separated string of all server stringes. Returned memory has to be freed with pa_xfree() */ -char *pa_strlist_tostring(pa_strlist *l); - -/* Free the entire list */ -void pa_strlist_free(pa_strlist *l); - -/* Return the next entry in the list in *string and remove it from - * the list. Returns the new list head. The memory *string points to - * has to be freed with pa_xfree() */ -pa_strlist* pa_strlist_pop(pa_strlist *l, char **s); - -/* Parse a whitespace separated server list */ -pa_strlist* pa_strlist_parse(const char *s); - -#endif diff --git a/src/polypcore/tagstruct.c b/src/polypcore/tagstruct.c deleted file mode 100644 index 27582cae..00000000 --- a/src/polypcore/tagstruct.c +++ /dev/null @@ -1,630 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_NETINET_IN_H -#include -#endif - -#include "winsock.h" - -#include - -#include "tagstruct.h" - - -struct pa_tagstruct { - uint8_t *data; - size_t length, allocated; - size_t rindex; - - int dynamic; -}; - -pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) { - pa_tagstruct*t; - - assert(!data || (data && length)); - - t = pa_xmalloc(sizeof(pa_tagstruct)); - t->data = (uint8_t*) data; - t->allocated = t->length = data ? length : 0; - t->rindex = 0; - t->dynamic = !data; - return t; -} - -void pa_tagstruct_free(pa_tagstruct*t) { - assert(t); - if (t->dynamic) - pa_xfree(t->data); - pa_xfree(t); -} - -uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l) { - uint8_t *p; - assert(t && t->dynamic && l); - p = t->data; - *l = t->length; - pa_xfree(t); - return p; -} - -static void extend(pa_tagstruct*t, size_t l) { - assert(t && t->dynamic); - - if (t->length+l <= t->allocated) - return; - - t->data = pa_xrealloc(t->data, t->allocated = t->length+l+100); -} - - -void pa_tagstruct_puts(pa_tagstruct*t, const char *s) { - size_t l; - assert(t); - if (s) { - l = strlen(s)+2; - extend(t, l); - t->data[t->length] = PA_TAG_STRING; - strcpy((char*) (t->data+t->length+1), s); - t->length += l; - } else { - extend(t, 1); - t->data[t->length] = PA_TAG_STRING_NULL; - t->length += 1; - } -} - -void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i) { - assert(t); - extend(t, 5); - t->data[t->length] = PA_TAG_U32; - i = htonl(i); - memcpy(t->data+t->length+1, &i, 4); - t->length += 5; -} - -void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c) { - assert(t); - extend(t, 2); - t->data[t->length] = PA_TAG_U8; - *(t->data+t->length+1) = c; - t->length += 2; -} - -void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss) { - uint32_t rate; - assert(t && ss); - extend(t, 7); - t->data[t->length] = PA_TAG_SAMPLE_SPEC; - t->data[t->length+1] = (uint8_t) ss->format; - t->data[t->length+2] = ss->channels; - rate = htonl(ss->rate); - memcpy(t->data+t->length+3, &rate, 4); - t->length += 7; -} - -void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) { - uint32_t tmp; - assert(t && p); - - extend(t, 5+length); - t->data[t->length] = PA_TAG_ARBITRARY; - tmp = htonl(length); - memcpy(t->data+t->length+1, &tmp, 4); - if (length) - memcpy(t->data+t->length+5, p, length); - t->length += 5+length; -} - -void pa_tagstruct_put_boolean(pa_tagstruct*t, int b) { - assert(t); - extend(t, 1); - t->data[t->length] = b ? PA_TAG_BOOLEAN_TRUE : PA_TAG_BOOLEAN_FALSE; - t->length += 1; -} - -void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv) { - uint32_t tmp; - assert(t); - extend(t, 9); - t->data[t->length] = PA_TAG_TIMEVAL; - tmp = htonl(tv->tv_sec); - memcpy(t->data+t->length+1, &tmp, 4); - tmp = htonl(tv->tv_usec); - memcpy(t->data+t->length+5, &tmp, 4); - t->length += 9; -} - -void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u) { - uint32_t tmp; - assert(t); - extend(t, 9); - t->data[t->length] = PA_TAG_USEC; - tmp = htonl((uint32_t) (u >> 32)); - memcpy(t->data+t->length+1, &tmp, 4); - tmp = htonl((uint32_t) u); - memcpy(t->data+t->length+5, &tmp, 4); - t->length += 9; -} - -void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) { - uint32_t tmp; - assert(t); - extend(t, 9); - t->data[t->length] = PA_TAG_U64; - tmp = htonl((uint32_t) (u >> 32)); - memcpy(t->data+t->length+1, &tmp, 4); - tmp = htonl((uint32_t) u); - memcpy(t->data+t->length+5, &tmp, 4); - t->length += 9; -} - -void pa_tagstruct_puts64(pa_tagstruct*t, int64_t u) { - uint32_t tmp; - assert(t); - extend(t, 9); - t->data[t->length] = PA_TAG_S64; - tmp = htonl((uint32_t) ((uint64_t) u >> 32)); - memcpy(t->data+t->length+1, &tmp, 4); - tmp = htonl((uint32_t) ((uint64_t) u)); - memcpy(t->data+t->length+5, &tmp, 4); - t->length += 9; -} - -void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) { - unsigned i; - - assert(t); - extend(t, 2 + map->channels); - - t->data[t->length++] = PA_TAG_CHANNEL_MAP; - t->data[t->length++] = map->channels; - - for (i = 0; i < map->channels; i ++) - t->data[t->length++] = (uint8_t) map->map[i]; -} - -void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) { - unsigned i; - pa_volume_t vol; - - assert(t); - extend(t, 2 + cvolume->channels * sizeof(pa_volume_t)); - - t->data[t->length++] = PA_TAG_CVOLUME; - t->data[t->length++] = cvolume->channels; - - for (i = 0; i < cvolume->channels; i ++) { - vol = htonl(cvolume->values[i]); - memcpy(t->data + t->length, &vol, sizeof(pa_volume_t)); - t->length += sizeof(pa_volume_t); - } -} - -int pa_tagstruct_gets(pa_tagstruct*t, const char **s) { - int error = 0; - size_t n; - char *c; - assert(t && s); - - if (t->rindex+1 > t->length) - return -1; - - if (t->data[t->rindex] == PA_TAG_STRING_NULL) { - t->rindex++; - *s = NULL; - return 0; - } - - if (t->rindex+2 > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_STRING) - return -1; - - error = 1; - for (n = 0, c = (char*) (t->data+t->rindex+1); t->rindex+1+n < t->length; n++, c++) - if (!*c) { - error = 0; - break; - } - - if (error) - return -1; - - *s = (char*) (t->data+t->rindex+1); - - t->rindex += n+2; - return 0; -} - -int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) { - assert(t && i); - - if (t->rindex+5 > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_U32) - return -1; - - memcpy(i, t->data+t->rindex+1, 4); - *i = ntohl(*i); - t->rindex += 5; - return 0; -} - -int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) { - assert(t && c); - - if (t->rindex+2 > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_U8) - return -1; - - *c = t->data[t->rindex+1]; - t->rindex +=2; - return 0; -} - -int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) { - assert(t && ss); - - if (t->rindex+7 > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_SAMPLE_SPEC) - return -1; - - ss->format = t->data[t->rindex+1]; - ss->channels = t->data[t->rindex+2]; - memcpy(&ss->rate, t->data+t->rindex+3, 4); - ss->rate = ntohl(ss->rate); - - t->rindex += 7; - return 0; -} - -int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) { - uint32_t len; - assert(t && p); - - if (t->rindex+5+length > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_ARBITRARY) - return -1; - - memcpy(&len, t->data+t->rindex+1, 4); - if (ntohl(len) != length) - return -1; - - *p = t->data+t->rindex+5; - t->rindex += 5+length; - return 0; -} - -int pa_tagstruct_eof(pa_tagstruct*t) { - assert(t); - return t->rindex >= t->length; -} - -const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) { - assert(t && t->dynamic && l); - *l = t->length; - return t->data; -} - -int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) { - assert(t && b); - - if (t->rindex+1 > t->length) - return -1; - - if (t->data[t->rindex] == PA_TAG_BOOLEAN_TRUE) - *b = 1; - else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE) - *b = 0; - else - return -1; - - t->rindex +=1; - return 0; -} - -int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) { - - if (t->rindex+9 > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_TIMEVAL) - return -1; - - memcpy(&tv->tv_sec, t->data+t->rindex+1, 4); - tv->tv_sec = ntohl(tv->tv_sec); - memcpy(&tv->tv_usec, t->data+t->rindex+5, 4); - tv->tv_usec = ntohl(tv->tv_usec); - t->rindex += 9; - return 0; -} - -int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) { - uint32_t tmp; - assert(t && u); - - if (t->rindex+9 > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_USEC) - return -1; - - memcpy(&tmp, t->data+t->rindex+1, 4); - *u = (pa_usec_t) ntohl(tmp) << 32; - memcpy(&tmp, t->data+t->rindex+5, 4); - *u |= (pa_usec_t) ntohl(tmp); - t->rindex +=9; - return 0; -} - -int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) { - uint32_t tmp; - assert(t && u); - - if (t->rindex+9 > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_U64) - return -1; - - memcpy(&tmp, t->data+t->rindex+1, 4); - *u = (uint64_t) ntohl(tmp) << 32; - memcpy(&tmp, t->data+t->rindex+5, 4); - *u |= (uint64_t) ntohl(tmp); - t->rindex +=9; - return 0; -} - -int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *u) { - uint32_t tmp; - assert(t && u); - - if (t->rindex+9 > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_S64) - return -1; - - memcpy(&tmp, t->data+t->rindex+1, 4); - *u = (int64_t) ((uint64_t) ntohl(tmp) << 32); - memcpy(&tmp, t->data+t->rindex+5, 4); - *u |= (int64_t) ntohl(tmp); - t->rindex +=9; - return 0; -} - -int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) { - unsigned i; - - assert(t); - assert(map); - - if (t->rindex+2 > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_CHANNEL_MAP) - return -1; - - if ((map->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX) - return -1; - - if (t->rindex+2+map->channels > t->length) - return -1; - - for (i = 0; i < map->channels; i ++) - map->map[i] = (int8_t) t->data[t->rindex + 2 + i]; - - t->rindex += 2 + map->channels; - return 0; -} - -int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) { - unsigned i; - pa_volume_t vol; - - assert(t); - assert(cvolume); - - if (t->rindex+2 > t->length) - return -1; - - if (t->data[t->rindex] != PA_TAG_CVOLUME) - return -1; - - if ((cvolume->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX) - return -1; - - if (t->rindex+2+cvolume->channels*sizeof(pa_volume_t) > t->length) - return -1; - - for (i = 0; i < cvolume->channels; i ++) { - memcpy(&vol, t->data + t->rindex + 2 + i * sizeof(pa_volume_t), sizeof(pa_volume_t)); - cvolume->values[i] = (pa_volume_t) ntohl(vol); - } - - t->rindex += 2 + cvolume->channels * sizeof(pa_volume_t); - return 0; -} - -void pa_tagstruct_put(pa_tagstruct *t, ...) { - va_list va; - assert(t); - - va_start(va, t); - - for (;;) { - int tag = va_arg(va, int); - - if (tag == PA_TAG_INVALID) - break; - - switch (tag) { - case PA_TAG_STRING: - case PA_TAG_STRING_NULL: - pa_tagstruct_puts(t, va_arg(va, char*)); - break; - - case PA_TAG_U32: - pa_tagstruct_putu32(t, va_arg(va, uint32_t)); - break; - - case PA_TAG_U8: - pa_tagstruct_putu8(t, (uint8_t) va_arg(va, int)); - break; - - case PA_TAG_U64: - pa_tagstruct_putu64(t, va_arg(va, uint64_t)); - break; - - case PA_TAG_SAMPLE_SPEC: - pa_tagstruct_put_sample_spec(t, va_arg(va, pa_sample_spec*)); - break; - - case PA_TAG_ARBITRARY: { - void *p = va_arg(va, void*); - size_t size = va_arg(va, size_t); - pa_tagstruct_put_arbitrary(t, p, size); - break; - } - - case PA_TAG_BOOLEAN_TRUE: - case PA_TAG_BOOLEAN_FALSE: - pa_tagstruct_put_boolean(t, va_arg(va, int)); - break; - - case PA_TAG_TIMEVAL: - pa_tagstruct_put_timeval(t, va_arg(va, struct timeval*)); - break; - - case PA_TAG_USEC: - pa_tagstruct_put_usec(t, va_arg(va, pa_usec_t)); - break; - - case PA_TAG_CHANNEL_MAP: - pa_tagstruct_put_channel_map(t, va_arg(va, pa_channel_map *)); - break; - - case PA_TAG_CVOLUME: - pa_tagstruct_put_cvolume(t, va_arg(va, pa_cvolume *)); - break; - - default: - abort(); - } - } - - va_end(va); -} - -int pa_tagstruct_get(pa_tagstruct *t, ...) { - va_list va; - int ret = 0; - - assert(t); - - va_start(va, t); - while (ret == 0) { - int tag = va_arg(va, int); - - if (tag == PA_TAG_INVALID) - break; - - switch (tag) { - case PA_TAG_STRING: - case PA_TAG_STRING_NULL: - ret = pa_tagstruct_gets(t, va_arg(va, const char**)); - break; - - case PA_TAG_U32: - ret = pa_tagstruct_getu32(t, va_arg(va, uint32_t*)); - break; - - case PA_TAG_U8: - ret = pa_tagstruct_getu8(t, va_arg(va, uint8_t*)); - break; - - case PA_TAG_U64: - ret = pa_tagstruct_getu64(t, va_arg(va, uint64_t*)); - break; - - case PA_TAG_SAMPLE_SPEC: - ret = pa_tagstruct_get_sample_spec(t, va_arg(va, pa_sample_spec*)); - break; - - case PA_TAG_ARBITRARY: { - const void **p = va_arg(va, const void**); - size_t size = va_arg(va, size_t); - ret = pa_tagstruct_get_arbitrary(t, p, size); - break; - } - - case PA_TAG_BOOLEAN_TRUE: - case PA_TAG_BOOLEAN_FALSE: - ret = pa_tagstruct_get_boolean(t, va_arg(va, int*)); - break; - - case PA_TAG_TIMEVAL: - ret = pa_tagstruct_get_timeval(t, va_arg(va, struct timeval*)); - break; - - case PA_TAG_USEC: - ret = pa_tagstruct_get_usec(t, va_arg(va, pa_usec_t*)); - break; - - case PA_TAG_CHANNEL_MAP: - ret = pa_tagstruct_get_channel_map(t, va_arg(va, pa_channel_map *)); - break; - - case PA_TAG_CVOLUME: - ret = pa_tagstruct_get_cvolume(t, va_arg(va, pa_cvolume *)); - break; - - - default: - abort(); - } - - } - - va_end(va); - return ret; -} diff --git a/src/polypcore/tagstruct.h b/src/polypcore/tagstruct.h deleted file mode 100644 index d5e6050b..00000000 --- a/src/polypcore/tagstruct.h +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef footagstructhfoo -#define footagstructhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include - -#include -#include -#include - -typedef struct pa_tagstruct pa_tagstruct; - -enum { - PA_TAG_INVALID = 0, - PA_TAG_STRING = 't', - PA_TAG_STRING_NULL = 'N', - PA_TAG_U32 = 'L', - PA_TAG_U8 = 'B', - PA_TAG_U64 = 'R', - PA_TAG_S64 = 'r', - PA_TAG_SAMPLE_SPEC = 'a', - PA_TAG_ARBITRARY = 'x', - PA_TAG_BOOLEAN_TRUE = '1', - PA_TAG_BOOLEAN_FALSE = '0', - PA_TAG_BOOLEAN = PA_TAG_BOOLEAN_TRUE, - PA_TAG_TIMEVAL = 'T', - PA_TAG_USEC = 'U' /* 64bit unsigned */, - PA_TAG_CHANNEL_MAP = 'm', - PA_TAG_CVOLUME = 'v' -}; - -pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length); -void pa_tagstruct_free(pa_tagstruct*t); -uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l); - -int pa_tagstruct_eof(pa_tagstruct*t); -const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l); - -void pa_tagstruct_put(pa_tagstruct *t, ...); - -void pa_tagstruct_puts(pa_tagstruct*t, const char *s); -void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c); -void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i); -void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t i); -void pa_tagstruct_puts64(pa_tagstruct*t, int64_t i); -void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss); -void pa_tagstruct_put_arbitrary(pa_tagstruct*t, const void *p, size_t length); -void pa_tagstruct_put_boolean(pa_tagstruct*t, int b); -void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv); -void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u); -void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map); -void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume); - -int pa_tagstruct_get(pa_tagstruct *t, ...); - -int pa_tagstruct_gets(pa_tagstruct*t, const char **s); -int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c); -int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i); -int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *i); -int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *i); -int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss); -int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length); -int pa_tagstruct_get_boolean(pa_tagstruct *t, int *b); -int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv); -int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u); -int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map); -int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *v); - - -#endif diff --git a/src/polypcore/tokenizer.c b/src/polypcore/tokenizer.c deleted file mode 100644 index 667643fe..00000000 --- a/src/polypcore/tokenizer.c +++ /dev/null @@ -1,90 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include - -#include -#include - -#include "tokenizer.h" - -struct pa_tokenizer { - pa_dynarray *dynarray; -}; - -static void token_free(void *p, PA_GCC_UNUSED void *userdata) { - pa_xfree(p); -} - -static void parse(pa_dynarray*a, const char *s, unsigned args) { - int infty = 0; - const char delimiter[] = " \t\n\r"; - const char *p; - assert(a && s); - - if (args == 0) - infty = 1; - - p = s+strspn(s, delimiter); - while (*p && (infty || args >= 2)) { - size_t l = strcspn(p, delimiter); - char *n = pa_xstrndup(p, l); - pa_dynarray_append(a, n); - p += l; - p += strspn(p, delimiter); - args--; - } - - if (args && *p) { - char *n = pa_xstrdup(p); - pa_dynarray_append(a, n); - } -} - -pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args) { - pa_tokenizer *t; - - t = pa_xmalloc(sizeof(pa_tokenizer)); - t->dynarray = pa_dynarray_new(); - assert(t->dynarray); - - parse(t->dynarray, s, args); - return t; -} - -void pa_tokenizer_free(pa_tokenizer *t) { - assert(t); - pa_dynarray_free(t->dynarray, token_free, NULL); - pa_xfree(t); -} - -const char *pa_tokenizer_get(pa_tokenizer *t, unsigned i) { - assert(t); - return pa_dynarray_get(t->dynarray, i); -} diff --git a/src/polypcore/tokenizer.h b/src/polypcore/tokenizer.h deleted file mode 100644 index bedacb8a..00000000 --- a/src/polypcore/tokenizer.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef footokenizerhfoo -#define footokenizerhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -typedef struct pa_tokenizer pa_tokenizer; - -pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args); -void pa_tokenizer_free(pa_tokenizer *t); - -const char *pa_tokenizer_get(pa_tokenizer *t, unsigned i); - -#endif diff --git a/src/polypcore/winsock.h b/src/polypcore/winsock.h deleted file mode 100644 index ae868b38..00000000 --- a/src/polypcore/winsock.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef foowinsockhfoo -#define foowinsockhfoo - -#ifdef HAVE_WINSOCK2_H -#include - -#define ESHUTDOWN WSAESHUTDOWN -#define ECONNRESET WSAECONNRESET -#define ECONNABORTED WSAECONNABORTED -#define ENETRESET WSAENETRESET -#define EINPROGRESS WSAEINPROGRESS -#define EAFNOSUPPORT WSAEAFNOSUPPORT -#define ETIMEDOUT WSAETIMEDOUT -#define ECONNREFUSED WSAECONNREFUSED -#define EHOSTUNREACH WSAEHOSTUNREACH -#define EWOULDBLOCK WSAEWOULDBLOCK - -#endif - -#ifdef HAVE_WS2TCPIP_H -#include -#endif - -#endif diff --git a/src/polypcore/x11prop.c b/src/polypcore/x11prop.c deleted file mode 100644 index e57fc136..00000000 --- a/src/polypcore/x11prop.c +++ /dev/null @@ -1,70 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include -#include - -#include "x11prop.h" - - -void pa_x11_set_prop(Display *d, const char *name, const char *data) { - Atom a = XInternAtom(d, name, False); - XChangeProperty(d, RootWindow(d, 0), a, XA_STRING, 8, PropModeReplace, (const unsigned char*) data, strlen(data)+1); -} - -void pa_x11_del_prop(Display *d, const char *name) { - Atom a = XInternAtom(d, name, False); - XDeleteProperty(d, RootWindow(d, 0), a); -} - -char* pa_x11_get_prop(Display *d, const char *name, char *p, size_t l) { - Atom actual_type; - int actual_format; - unsigned long nitems; - unsigned long nbytes_after; - unsigned char *prop = NULL; - char *ret = NULL; - - Atom a = XInternAtom(d, name, False); - if (XGetWindowProperty(d, RootWindow(d, 0), a, 0, (l+2)/4, False, XA_STRING, &actual_type, &actual_format, &nitems, &nbytes_after, &prop) != Success) - goto finish; - - if (actual_type != XA_STRING) - goto finish; - - memcpy(p, prop, nitems); - p[nitems] = 0; - - ret = p; - -finish: - - if (prop) - XFree(prop); - - return ret; -} diff --git a/src/polypcore/x11prop.h b/src/polypcore/x11prop.h deleted file mode 100644 index 5531c640..00000000 --- a/src/polypcore/x11prop.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef foox11prophfoo -#define foox11prophfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include - -void pa_x11_set_prop(Display *d, const char *name, const char *data); -void pa_x11_del_prop(Display *d, const char *name); -char* pa_x11_get_prop(Display *d, const char *name, char *p, size_t l); - -#endif diff --git a/src/polypcore/x11wrap.c b/src/polypcore/x11wrap.c deleted file mode 100644 index b53a43b6..00000000 --- a/src/polypcore/x11wrap.c +++ /dev/null @@ -1,247 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include - -#include - -#include -#include -#include - -#include "x11wrap.h" - -typedef struct pa_x11_internal pa_x11_internal; - -struct pa_x11_internal { - PA_LLIST_FIELDS(pa_x11_internal); - pa_x11_wrapper *wrapper; - pa_io_event* io_event; - int fd; -}; - -struct pa_x11_wrapper { - pa_core *core; - int ref; - - char *property_name; - Display *display; - - pa_defer_event* defer_event; - pa_io_event* io_event; - - PA_LLIST_HEAD(pa_x11_client, clients); - PA_LLIST_HEAD(pa_x11_internal, internals); -}; - -struct pa_x11_client { - PA_LLIST_FIELDS(pa_x11_client); - pa_x11_wrapper *wrapper; - int (*callback)(pa_x11_wrapper *w, XEvent *e, void *userdata); - void *userdata; -}; - -/* Dispatch all pending X11 events */ -static void work(pa_x11_wrapper *w) { - assert(w && w->ref >= 1); - - while (XPending(w->display)) { - pa_x11_client *c; - XEvent e; - XNextEvent(w->display, &e); - - for (c = w->clients; c; c = c->next) { - assert(c->callback); - if (c->callback(w, &e, c->userdata) != 0) - break; - } - } -} - -/* IO notification event for the X11 display connection */ -static void display_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { - pa_x11_wrapper *w = userdata; - assert(m && e && fd >= 0 && w && w->ref >= 1); - work(w); -} - -/* Deferred notification event. Called once each main loop iteration */ -static void defer_event(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { - pa_x11_wrapper *w = userdata; - assert(m && e && w && w->ref >= 1); - - m->defer_enable(e, 0); - - work(w); -} - -/* IO notification event for X11 internal connections */ -static void internal_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { - pa_x11_wrapper *w = userdata; - assert(m && e && fd >= 0 && w && w->ref >= 1); - - XProcessInternalConnection(w->display, fd); - - work(w); -} - -/* Add a new IO source for the specified X11 internal connection */ -static pa_x11_internal* x11_internal_add(pa_x11_wrapper *w, int fd) { - pa_x11_internal *i; - assert(fd >= 0); - - i = pa_xmalloc(sizeof(pa_x11_internal)); - assert(i); - i->wrapper = w; - i->io_event = w->core->mainloop->io_new(w->core->mainloop, fd, PA_IO_EVENT_INPUT, internal_io_event, w); - i->fd = fd; - - PA_LLIST_PREPEND(pa_x11_internal, w->internals, i); - return i; -} - -/* Remove an IO source for an X11 internal connection */ -static void x11_internal_remove(pa_x11_wrapper *w, pa_x11_internal *i) { - assert(i); - - PA_LLIST_REMOVE(pa_x11_internal, w->internals, i); - w->core->mainloop->io_free(i->io_event); - pa_xfree(i); -} - -/* Implementation of XConnectionWatchProc */ -static void x11_watch(Display *display, XPointer userdata, int fd, Bool opening, XPointer *watch_data) { - pa_x11_wrapper *w = (pa_x11_wrapper*) userdata; - assert(display && w && fd >= 0); - - if (opening) - *watch_data = (XPointer) x11_internal_add(w, fd); - else - x11_internal_remove(w, (pa_x11_internal*) *watch_data); -} - -static pa_x11_wrapper* x11_wrapper_new(pa_core *c, const char *name, const char *t) { - pa_x11_wrapper*w; - Display *d; - int r; - - if (!(d = XOpenDisplay(name))) { - pa_log(__FILE__": XOpenDisplay() failed"); - return NULL; - } - - w = pa_xmalloc(sizeof(pa_x11_wrapper)); - w->core = c; - w->ref = 1; - w->property_name = pa_xstrdup(t); - w->display = d; - - PA_LLIST_HEAD_INIT(pa_x11_client, w->clients); - PA_LLIST_HEAD_INIT(pa_x11_internal, w->internals); - - w->defer_event = c->mainloop->defer_new(c->mainloop, defer_event, w); - w->io_event = c->mainloop->io_new(c->mainloop, ConnectionNumber(d), PA_IO_EVENT_INPUT, display_io_event, w); - - XAddConnectionWatch(d, x11_watch, (XPointer) w); - - r = pa_property_set(c, w->property_name, w); - assert(r >= 0); - - return w; -} - -static void x11_wrapper_free(pa_x11_wrapper*w) { - int r; - assert(w); - - r = pa_property_remove(w->core, w->property_name); - assert(r >= 0); - - assert(!w->clients); - - XRemoveConnectionWatch(w->display, x11_watch, (XPointer) w); - XCloseDisplay(w->display); - - w->core->mainloop->io_free(w->io_event); - w->core->mainloop->defer_free(w->defer_event); - - while (w->internals) - x11_internal_remove(w, w->internals); - - pa_xfree(w->property_name); - pa_xfree(w); -} - -pa_x11_wrapper* pa_x11_wrapper_get(pa_core *c, const char *name) { - char t[256]; - pa_x11_wrapper *w; - assert(c); - - snprintf(t, sizeof(t), "x11-wrapper%s%s", name ? "-" : "", name ? name : ""); - if ((w = pa_property_get(c, t))) - return pa_x11_wrapper_ref(w); - - return x11_wrapper_new(c, name, t); -} - -pa_x11_wrapper* pa_x11_wrapper_ref(pa_x11_wrapper *w) { - assert(w && w->ref >= 1); - w->ref++; - return w; -} - -void pa_x11_wrapper_unref(pa_x11_wrapper* w) { - assert(w && w->ref >= 1); - - if (!(--w->ref)) - x11_wrapper_free(w); -} - -Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w) { - assert(w && w->ref >= 1); - - /* Somebody is using us, schedule a output buffer flush */ - w->core->mainloop->defer_enable(w->defer_event, 1); - - return w->display; -} - -pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata) { - pa_x11_client *c; - assert(w && w->ref >= 1); - - c = pa_xmalloc(sizeof(pa_x11_client)); - c->wrapper = w; - c->callback = cb; - c->userdata = userdata; - - PA_LLIST_PREPEND(pa_x11_client, w->clients, c); - - return c; -} - -void pa_x11_client_free(pa_x11_client *c) { - assert(c && c->wrapper && c->wrapper->ref >= 1); - - PA_LLIST_REMOVE(pa_x11_client, c->wrapper->clients, c); - pa_xfree(c); -} diff --git a/src/polypcore/x11wrap.h b/src/polypcore/x11wrap.h deleted file mode 100644 index 15969869..00000000 --- a/src/polypcore/x11wrap.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef foox11wraphfoo -#define foox11wraphfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include - -typedef struct pa_x11_wrapper pa_x11_wrapper; - -/* Return the X11 wrapper for this core. In case no wrapper was - existant before, allocate a new one */ -pa_x11_wrapper* pa_x11_wrapper_get(pa_core *c, const char *name); - -/* Increase the wrapper's reference count by one */ -pa_x11_wrapper* pa_x11_wrapper_ref(pa_x11_wrapper *w); - -/* Decrease the reference counter of an X11 wrapper object */ -void pa_x11_wrapper_unref(pa_x11_wrapper* w); - -/* Return the X11 display object for this connection */ -Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w); - -typedef struct pa_x11_client pa_x11_client; - -/* Register an X11 client, that is called for each X11 event */ -pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata); - -/* Free an X11 client object */ -void pa_x11_client_free(pa_x11_client *c); - -#endif diff --git a/src/pulse/Makefile b/src/pulse/Makefile new file mode 100644 index 00000000..7c8875f3 --- /dev/null +++ b/src/pulse/Makefile @@ -0,0 +1,13 @@ +# This is a dirty trick just to ease compilation with emacs +# +# This file is not intended to be distributed or anything +# +# So: don't touch it, even better ignore it! + +all: + $(MAKE) -C .. + +clean: + $(MAKE) -C .. clean + +.PHONY: all clean diff --git a/src/pulse/browser.c b/src/pulse/browser.c new file mode 100644 index 00000000..d063465d --- /dev/null +++ b/src/pulse/browser.c @@ -0,0 +1,334 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include + +#include +#include + +#include "browser.h" + +#define SERVICE_NAME_SINK "_pulseaudio-sink._tcp." +#define SERVICE_NAME_SOURCE "_pulseaudio-source._tcp." +#define SERVICE_NAME_SERVER "_pulseaudio-server._tcp." + +struct pa_browser { + int ref; + pa_mainloop_api *mainloop; + + pa_browse_cb_t callback; + void *userdata; + + sw_discovery discovery; + pa_io_event *io_event; +}; + +static void io_callback(pa_mainloop_api*a, PA_GCC_UNUSED pa_io_event*e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void *userdata) { + pa_browser *b = userdata; + assert(a && b && b->mainloop == a); + + if (events != PA_IO_EVENT_INPUT || sw_discovery_read_socket(b->discovery) != SW_OKAY) { + pa_log(__FILE__": connection to HOWL daemon failed."); + b->mainloop->io_free(b->io_event); + b->io_event = NULL; + return; + } +} + +static int type_equal(const char *a, const char *b) { + size_t la, lb; + + if (strcasecmp(a, b) == 0) + return 1; + + la = strlen(a); + lb = strlen(b); + + if (la > 0 && a[la-1] == '.' && la == lb+1 && strncasecmp(a, b, la-1) == 0) + return 1; + + if (lb > 0 && b[lb-1] == '.' && lb == la+1 && strncasecmp(a, b, lb-1) == 0) + return 1; + + return 0; +} + +static int map_to_opcode(const char *type, int new) { + if (type_equal(type, SERVICE_NAME_SINK)) + return new ? PA_BROWSE_NEW_SINK : PA_BROWSE_REMOVE_SINK; + else if (type_equal(type, SERVICE_NAME_SOURCE)) + return new ? PA_BROWSE_NEW_SOURCE : PA_BROWSE_REMOVE_SOURCE; + else if (type_equal(type, SERVICE_NAME_SERVER)) + return new ? PA_BROWSE_NEW_SERVER : PA_BROWSE_REMOVE_SERVER; + + return -1; +} + +static sw_result resolve_reply( + sw_discovery discovery, + sw_discovery_oid oid, + sw_uint32 interface_index, + sw_const_string name, + sw_const_string type, + sw_const_string domain, + sw_ipv4_address address, + sw_port port, + sw_octets text_record, + sw_ulong text_record_len, + sw_opaque extra) { + + pa_browser *b = extra; + pa_browse_info i; + char ip[256], a[256]; + int opcode; + int device_found = 0; + uint32_t cookie; + pa_sample_spec ss; + int ss_valid = 0; + sw_text_record_iterator iterator; + int free_iterator = 0; + char *c = NULL; + + assert(b); + + sw_discovery_cancel(discovery, oid); + + memset(&i, 0, sizeof(i)); + i.name = name; + + if (!b->callback) + goto fail; + + opcode = map_to_opcode(type, 1); + assert(opcode >= 0); + + snprintf(a, sizeof(a), "tcp:%s:%u", sw_ipv4_address_name(address, ip, sizeof(ip)), port); + i.server = a; + + if (text_record && text_record_len) { + char key[SW_TEXT_RECORD_MAX_LEN]; + uint8_t val[SW_TEXT_RECORD_MAX_LEN]; + uint32_t val_len; + + if (sw_text_record_iterator_init(&iterator, text_record, text_record_len) != SW_OKAY) { + pa_log_error(__FILE__": sw_text_record_string_iterator_init() failed."); + goto fail; + } + + free_iterator = 1; + + while (sw_text_record_iterator_next(iterator, key, val, &val_len) == SW_OKAY) { + c = pa_xstrndup((char*) val, val_len); + + if (!strcmp(key, "device")) { + device_found = 1; + pa_xfree((char*) i.device); + i.device = c; + c = NULL; + } else if (!strcmp(key, "server-version")) { + pa_xfree((char*) i.server_version); + i.server_version = c; + c = NULL; + } else if (!strcmp(key, "user-name")) { + pa_xfree((char*) i.user_name); + i.user_name = c; + c = NULL; + } else if (!strcmp(key, "fqdn")) { + size_t l; + + pa_xfree((char*) i.fqdn); + i.fqdn = c; + c = NULL; + + l = strlen(a); + assert(l+1 <= sizeof(a)); + strncat(a, " ", sizeof(a)-l-1); + strncat(a, i.fqdn, sizeof(a)-l-2); + } else if (!strcmp(key, "cookie")) { + + if (pa_atou(c, &cookie) < 0) + goto fail; + + i.cookie = &cookie; + } else if (!strcmp(key, "description")) { + pa_xfree((char*) i.description); + i.description = c; + c = NULL; + } else if (!strcmp(key, "channels")) { + uint32_t ch; + + if (pa_atou(c, &ch) < 0 || ch <= 0 || ch > 255) + goto fail; + + ss.channels = (uint8_t) ch; + ss_valid |= 1; + + } else if (!strcmp(key, "rate")) { + if (pa_atou(c, &ss.rate) < 0) + goto fail; + ss_valid |= 2; + } else if (!strcmp(key, "format")) { + + if ((ss.format = pa_parse_sample_format(c)) == PA_SAMPLE_INVALID) + goto fail; + + ss_valid |= 4; + } + + pa_xfree(c); + c = NULL; + } + + } + + /* No device txt record was sent for a sink or source service */ + if (opcode != PA_BROWSE_NEW_SERVER && !device_found) + goto fail; + + if (ss_valid == 7) + i.sample_spec = &ss; + + + b->callback(b, opcode, &i, b->userdata); + +fail: + pa_xfree((void*) i.device); + pa_xfree((void*) i.fqdn); + pa_xfree((void*) i.server_version); + pa_xfree((void*) i.user_name); + pa_xfree((void*) i.description); + pa_xfree(c); + + if (free_iterator) + sw_text_record_iterator_fina(iterator); + + + return SW_OKAY; +} + +static sw_result browse_reply( + sw_discovery discovery, + sw_discovery_oid id, + sw_discovery_browse_status status, + sw_uint32 interface_index, + sw_const_string name, + sw_const_string type, + sw_const_string domain, + sw_opaque extra) { + + pa_browser *b = extra; + assert(b); + + switch (status) { + case SW_DISCOVERY_BROWSE_ADD_SERVICE: { + sw_discovery_oid oid; + + if (sw_discovery_resolve(b->discovery, 0, name, type, domain, resolve_reply, b, &oid) != SW_OKAY) + pa_log_error(__FILE__": sw_discovery_resolve() failed"); + + break; + } + + case SW_DISCOVERY_BROWSE_REMOVE_SERVICE: + if (b->callback) { + pa_browse_info i; + int opcode; + + memset(&i, 0, sizeof(i)); + i.name = name; + + opcode = map_to_opcode(type, 0); + assert(opcode >= 0); + + b->callback(b, opcode, &i, b->userdata); + } + break; + + default: + ; + } + + return SW_OKAY; +} + +pa_browser *pa_browser_new(pa_mainloop_api *mainloop) { + pa_browser *b; + sw_discovery_oid oid; + + b = pa_xnew(pa_browser, 1); + b->mainloop = mainloop; + b->ref = 1; + b->callback = NULL; + b->userdata = NULL; + + if (sw_discovery_init(&b->discovery) != SW_OKAY) { + pa_log_error(__FILE__": sw_discovery_init() failed."); + pa_xfree(b); + return NULL; + } + + if (sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SERVER, NULL, browse_reply, b, &oid) != SW_OKAY || + sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SINK, NULL, browse_reply, b, &oid) != SW_OKAY || + sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SOURCE, NULL, browse_reply, b, &oid) != SW_OKAY) { + + pa_log_error(__FILE__": sw_discovery_browse() failed."); + + sw_discovery_fina(b->discovery); + pa_xfree(b); + return NULL; + } + + b->io_event = mainloop->io_new(mainloop, sw_discovery_socket(b->discovery), PA_IO_EVENT_INPUT, io_callback, b); + return b; +} + +static void browser_free(pa_browser *b) { + assert(b && b->mainloop); + + if (b->io_event) + b->mainloop->io_free(b->io_event); + + sw_discovery_fina(b->discovery); + pa_xfree(b); +} + +pa_browser *pa_browser_ref(pa_browser *b) { + assert(b && b->ref >= 1); + b->ref++; + return b; +} + +void pa_browser_unref(pa_browser *b) { + assert(b && b->ref >= 1); + + if ((-- (b->ref)) <= 0) + browser_free(b); +} + +void pa_browser_set_callback(pa_browser *b, pa_browse_cb_t cb, void *userdata) { + assert(b); + + b->callback = cb; + b->userdata = userdata; +} diff --git a/src/pulse/browser.h b/src/pulse/browser.h new file mode 100644 index 00000000..2d20c6c0 --- /dev/null +++ b/src/pulse/browser.h @@ -0,0 +1,68 @@ +#ifndef foobrowserhfoo +#define foobrowserhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +PA_C_DECL_BEGIN + +typedef struct pa_browser pa_browser; + +typedef enum pa_browse_opcode { + PA_BROWSE_NEW_SERVER = 0, + PA_BROWSE_NEW_SINK, + PA_BROWSE_NEW_SOURCE, + PA_BROWSE_REMOVE_SERVER, + PA_BROWSE_REMOVE_SINK, + PA_BROWSE_REMOVE_SOURCE +} pa_browse_opcode_t; + +pa_browser *pa_browser_new(pa_mainloop_api *mainloop); +pa_browser *pa_browser_ref(pa_browser *z); +void pa_browser_unref(pa_browser *z); + +typedef struct pa_browse_info { + /* Unique service name */ + const char *name; /* always available */ + + /* Server info */ + const char *server; /* always available */ + const char *server_version, *user_name, *fqdn; /* optional */ + const uint32_t *cookie; /* optional */ + + /* Device info */ + const char *device; /* always available when this information is of a sink/source */ + const char *description; /* optional */ + const pa_sample_spec *sample_spec; /* optional */ +} pa_browse_info; + +typedef void (*pa_browse_cb_t)(pa_browser *z, pa_browse_opcode_t c, const pa_browse_info *i, void *userdata); + +void pa_browser_set_callback(pa_browser *z, pa_browse_cb_t cb, void *userdata); + +PA_C_DECL_END + +#endif diff --git a/src/pulse/cdecl.h b/src/pulse/cdecl.h new file mode 100644 index 00000000..6ac96687 --- /dev/null +++ b/src/pulse/cdecl.h @@ -0,0 +1,42 @@ +#ifndef foocdeclhfoo +#define foocdeclhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/** \file + * C++ compatibility support */ + +#ifdef __cplusplus +/** If using C++ this macro enables C mode, otherwise does nothing */ +#define PA_C_DECL_BEGIN extern "C" { +/** If using C++ this macros switches back to C++ mode, otherwise does nothing */ +#define PA_C_DECL_END } + +#else +/** If using C++ this macro enables C mode, otherwise does nothing */ +#define PA_C_DECL_BEGIN +/** If using C++ this macros switches back to C++ mode, otherwise does nothing */ +#define PA_C_DECL_END + +#endif + +#endif diff --git a/src/pulse/channelmap.c b/src/pulse/channelmap.c new file mode 100644 index 00000000..a4f13372 --- /dev/null +++ b/src/pulse/channelmap.c @@ -0,0 +1,445 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include + +#include "channelmap.h" + +const char *const table[] = { + [PA_CHANNEL_POSITION_MONO] = "mono", + + [PA_CHANNEL_POSITION_FRONT_CENTER] = "front-center", + [PA_CHANNEL_POSITION_FRONT_LEFT] = "front-left", + [PA_CHANNEL_POSITION_FRONT_RIGHT] = "front-right", + + [PA_CHANNEL_POSITION_REAR_CENTER] = "rear-center", + [PA_CHANNEL_POSITION_REAR_LEFT] = "rear-left", + [PA_CHANNEL_POSITION_REAR_RIGHT] = "rear-right", + + [PA_CHANNEL_POSITION_LFE] = "lfe", + + [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = "front-left-of-center", + [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = "front-right-of-center", + + [PA_CHANNEL_POSITION_SIDE_LEFT] = "side-left", + [PA_CHANNEL_POSITION_SIDE_RIGHT] = "side-right", + + [PA_CHANNEL_POSITION_AUX0] = "aux0", + [PA_CHANNEL_POSITION_AUX1] = "aux1", + [PA_CHANNEL_POSITION_AUX2] = "aux2", + [PA_CHANNEL_POSITION_AUX3] = "aux3", + [PA_CHANNEL_POSITION_AUX4] = "aux4", + [PA_CHANNEL_POSITION_AUX5] = "aux5", + [PA_CHANNEL_POSITION_AUX6] = "aux6", + [PA_CHANNEL_POSITION_AUX7] = "aux7", + [PA_CHANNEL_POSITION_AUX8] = "aux8", + [PA_CHANNEL_POSITION_AUX9] = "aux9", + [PA_CHANNEL_POSITION_AUX10] = "aux10", + [PA_CHANNEL_POSITION_AUX11] = "aux11", + [PA_CHANNEL_POSITION_AUX12] = "aux12", + [PA_CHANNEL_POSITION_AUX13] = "aux13", + [PA_CHANNEL_POSITION_AUX14] = "aux14", + [PA_CHANNEL_POSITION_AUX15] = "aux15", + + [PA_CHANNEL_POSITION_TOP_CENTER] = "top-center", + + [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = "top-front-left", + [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = "top-front-right", + [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = "top-front-center", + + [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = "top-rear-left", + [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = "top-rear-right", + [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = "top-rear-center" +}; + +pa_channel_map* pa_channel_map_init(pa_channel_map *m) { + unsigned c; + assert(m); + + m->channels = 0; + + for (c = 0; c < PA_CHANNELS_MAX; c++) + m->map[c] = PA_CHANNEL_POSITION_INVALID; + + return m; +} + +pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m) { + assert(m); + + pa_channel_map_init(m); + + m->channels = 1; + m->map[0] = PA_CHANNEL_POSITION_MONO; + return m; +} + +pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m) { + assert(m); + + pa_channel_map_init(m); + + m->channels = 2; + m->map[0] = PA_CHANNEL_POSITION_LEFT; + m->map[1] = PA_CHANNEL_POSITION_RIGHT; + return m; +} + +pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) { + assert(m); + assert(channels > 0); + assert(channels <= PA_CHANNELS_MAX); + + pa_channel_map_init(m); + + m->channels = channels; + + switch (def) { + case PA_CHANNEL_MAP_AIFF: + + /* This is somewhat compatible with RFC3551 */ + + switch (channels) { + case 1: + m->map[0] = PA_CHANNEL_POSITION_MONO; + return m; + + case 6: + m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + m->map[1] = PA_CHANNEL_POSITION_SIDE_LEFT; + m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; + m->map[3] = PA_CHANNEL_POSITION_FRONT_RIGHT; + m->map[4] = PA_CHANNEL_POSITION_SIDE_RIGHT; + m->map[5] = PA_CHANNEL_POSITION_LFE; + return m; + + case 5: + m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; + m->map[3] = PA_CHANNEL_POSITION_REAR_LEFT; + m->map[4] = PA_CHANNEL_POSITION_REAR_RIGHT; + /* Fall through */ + + case 2: + m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + return m; + + case 3: + m->map[0] = PA_CHANNEL_POSITION_LEFT; + m->map[1] = PA_CHANNEL_POSITION_RIGHT; + m->map[2] = PA_CHANNEL_POSITION_CENTER; + return m; + + case 4: + m->map[0] = PA_CHANNEL_POSITION_LEFT; + m->map[1] = PA_CHANNEL_POSITION_CENTER; + m->map[2] = PA_CHANNEL_POSITION_RIGHT; + m->map[3] = PA_CHANNEL_POSITION_LFE; + return m; + + default: + return NULL; + } + + case PA_CHANNEL_MAP_ALSA: + + switch (channels) { + case 1: + m->map[0] = PA_CHANNEL_POSITION_MONO; + return m; + + case 8: + m->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; + m->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; + /* Fall through */ + + case 6: + m->map[5] = PA_CHANNEL_POSITION_LFE; + /* Fall through */ + + case 5: + m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; + /* Fall through */ + + case 4: + m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT; + m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; + /* Fall through */ + + case 2: + m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + return m; + + default: + return NULL; + } + + case PA_CHANNEL_MAP_AUX: { + unsigned i; + + if (channels >= PA_CHANNELS_MAX) + return NULL; + + for (i = 0; i < channels; i++) + m->map[i] = PA_CHANNEL_POSITION_AUX0 + i; + + return m; + } + + case PA_CHANNEL_MAP_WAVEEX: + + switch (channels) { + case 1: + m->map[0] = PA_CHANNEL_POSITION_MONO; + return m; + + case 18: + m->map[15] = PA_CHANNEL_POSITION_TOP_REAR_LEFT; + m->map[16] = PA_CHANNEL_POSITION_TOP_REAR_CENTER; + m->map[17] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT; + /* Fall through */ + + case 15: + m->map[12] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT; + m->map[13] = PA_CHANNEL_POSITION_TOP_FRONT_CENTER; + m->map[14] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT; + /* Fall through */ + + case 12: + m->map[11] = PA_CHANNEL_POSITION_TOP_CENTER; + /* Fall through */ + + case 11: + m->map[9] = PA_CHANNEL_POSITION_SIDE_LEFT; + m->map[10] = PA_CHANNEL_POSITION_SIDE_RIGHT; + /* Fall through */ + + case 9: + m->map[8] = PA_CHANNEL_POSITION_REAR_CENTER; + /* Fall through */ + + case 8: + m->map[6] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER; + m->map[7] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER; + /* Fall through */ + + case 6: + m->map[4] = PA_CHANNEL_POSITION_REAR_LEFT; + m->map[5] = PA_CHANNEL_POSITION_REAR_RIGHT; + /* Fall through */ + + case 4: + m->map[3] = PA_CHANNEL_POSITION_LFE; + /* Fall through */ + + case 3: + m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; + /* Fall through */ + + case 2: + m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + return m; + + default: + return NULL; + } + + case PA_CHANNEL_MAP_OSS: + + switch (channels) { + case 1: + m->map[0] = PA_CHANNEL_POSITION_MONO; + return m; + + case 8: + m->map[6] = PA_CHANNEL_POSITION_REAR_LEFT; + m->map[7] = PA_CHANNEL_POSITION_REAR_RIGHT; + /* Fall through */ + + case 6: + m->map[4] = PA_CHANNEL_POSITION_SIDE_LEFT; + m->map[5] = PA_CHANNEL_POSITION_SIDE_RIGHT; + /* Fall through */ + + case 4: + m->map[3] = PA_CHANNEL_POSITION_LFE; + /* Fall through */ + + case 3: + m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; + /* Fall through */ + + case 2: + m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + return m; + + default: + return NULL; + } + + + default: + return NULL; + } +} + + +const char* pa_channel_position_to_string(pa_channel_position_t pos) { + + if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX) + return NULL; + + return table[pos]; +} + +int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) { + unsigned c; + + assert(a); + assert(b); + + if (a->channels != b->channels) + return 0; + + for (c = 0; c < a->channels; c++) + if (a->map[c] != b->map[c]) + return 0; + + return 1; +} + +char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) { + unsigned channel; + int first = 1; + char *e; + + assert(s); + assert(l > 0); + assert(map); + + *(e = s) = 0; + + for (channel = 0; channel < map->channels && l > 1; channel++) { + l -= snprintf(e, l, "%s%s", + first ? "" : ",", + pa_channel_position_to_string(map->map[channel])); + + e = strchr(e, 0); + first = 0; + } + + return s; +} + +pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) { + const char *state; + pa_channel_map map; + char *p; + + assert(rmap); + assert(s); + + memset(&map, 0, sizeof(map)); + + if (strcmp(s, "stereo") == 0) { + map.channels = 2; + map.map[0] = PA_CHANNEL_POSITION_LEFT; + map.map[1] = PA_CHANNEL_POSITION_RIGHT; + goto finish; + } + + state = NULL; + map.channels = 0; + + while ((p = pa_split(s, ",", &state))) { + + if (map.channels >= PA_CHANNELS_MAX) { + pa_xfree(p); + return NULL; + } + + /* Some special aliases */ + if (strcmp(p, "left") == 0) + map.map[map.channels++] = PA_CHANNEL_POSITION_LEFT; + else if (strcmp(p, "right") == 0) + map.map[map.channels++] = PA_CHANNEL_POSITION_RIGHT; + else if (strcmp(p, "center") == 0) + map.map[map.channels++] = PA_CHANNEL_POSITION_CENTER; + else if (strcmp(p, "subwoofer") == 0) + map.map[map.channels++] = PA_CHANNEL_POSITION_SUBWOOFER; + else { + pa_channel_position_t i; + + for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++) + if (strcmp(p, table[i]) == 0) { + map.map[map.channels++] = i; + break; + } + + if (i >= PA_CHANNEL_POSITION_MAX) { + pa_xfree(p); + return NULL; + } + } + + pa_xfree(p); + } + +finish: + + if (!pa_channel_map_valid(&map)) + return NULL; + + *rmap = map; + return rmap; +} + +int pa_channel_map_valid(const pa_channel_map *map) { + unsigned c; + + assert(map); + + if (map->channels <= 0 || map->channels > PA_CHANNELS_MAX) + return 0; + + for (c = 0; c < map->channels; c++) { + + if (map->map[c] < 0 ||map->map[c] >= PA_CHANNEL_POSITION_MAX) + return 0; + + } + + return 1; +} + diff --git a/src/pulse/channelmap.h b/src/pulse/channelmap.h new file mode 100644 index 00000000..8a39ade8 --- /dev/null +++ b/src/pulse/channelmap.h @@ -0,0 +1,191 @@ +#ifndef foochannelmaphfoo +#define foochannelmaphfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/** \page channelmap Channel Maps + * + * \section overv_sec Overview + * + * Channel maps provide a way to associate channels in a stream with a + * specific speaker position. This relieves applications of having to + * make sure their channel order is identical to the final output. + * + * \section init_sec Initialisation + * + * A channel map consists of an array of \ref pa_channel_position values, + * one for each channel. This array is stored together with a channel count + * in a pa_channel_map structure. + * + * Before filling the structure, the application must initialise it using + * pa_channel_map_init(). There are also a number of convenience functions + * for standard channel mappings: + * + * \li pa_channel_map_init_mono() - Create a channel map with only mono audio. + * \li pa_channel_map_init_stereo() - Create a standard stereo mapping. + * \li pa_channel_map_init_auto() - Create a standard channel map for up to + * six channels. + * + * \section conv_sec Convenience Functions + * + * The library contains a number of convenience functions for dealing with + * channel maps: + * + * \li pa_channel_map_valid() - Tests if a channel map is valid. + * \li pa_channel_map_equal() - Tests if two channel maps are identical. + * \li pa_channel_map_snprint() - Creates a textual description of a channel + * map. + */ + +/** \file + * Constants and routines for channel mapping handling */ + +PA_C_DECL_BEGIN + +/** A list of channel labels */ +typedef enum pa_channel_position { + PA_CHANNEL_POSITION_INVALID = -1, + PA_CHANNEL_POSITION_MONO = 0, + + PA_CHANNEL_POSITION_LEFT, + PA_CHANNEL_POSITION_RIGHT, + PA_CHANNEL_POSITION_CENTER, + + PA_CHANNEL_POSITION_FRONT_LEFT = PA_CHANNEL_POSITION_LEFT, + PA_CHANNEL_POSITION_FRONT_RIGHT = PA_CHANNEL_POSITION_RIGHT, + PA_CHANNEL_POSITION_FRONT_CENTER = PA_CHANNEL_POSITION_CENTER, + + PA_CHANNEL_POSITION_REAR_CENTER, + PA_CHANNEL_POSITION_REAR_LEFT, + PA_CHANNEL_POSITION_REAR_RIGHT, + + PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_SUBWOOFER = PA_CHANNEL_POSITION_LFE, + + PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, + PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, + + PA_CHANNEL_POSITION_SIDE_LEFT, + PA_CHANNEL_POSITION_SIDE_RIGHT, + + PA_CHANNEL_POSITION_AUX0, + PA_CHANNEL_POSITION_AUX1, + PA_CHANNEL_POSITION_AUX2, + PA_CHANNEL_POSITION_AUX3, + PA_CHANNEL_POSITION_AUX4, + PA_CHANNEL_POSITION_AUX5, + PA_CHANNEL_POSITION_AUX6, + PA_CHANNEL_POSITION_AUX7, + PA_CHANNEL_POSITION_AUX8, + PA_CHANNEL_POSITION_AUX9, + PA_CHANNEL_POSITION_AUX10, + PA_CHANNEL_POSITION_AUX11, + PA_CHANNEL_POSITION_AUX12, + PA_CHANNEL_POSITION_AUX13, + PA_CHANNEL_POSITION_AUX14, + PA_CHANNEL_POSITION_AUX15, + PA_CHANNEL_POSITION_AUX16, + PA_CHANNEL_POSITION_AUX17, + PA_CHANNEL_POSITION_AUX18, + PA_CHANNEL_POSITION_AUX19, + PA_CHANNEL_POSITION_AUX20, + PA_CHANNEL_POSITION_AUX21, + PA_CHANNEL_POSITION_AUX22, + PA_CHANNEL_POSITION_AUX23, + PA_CHANNEL_POSITION_AUX24, + PA_CHANNEL_POSITION_AUX25, + PA_CHANNEL_POSITION_AUX26, + PA_CHANNEL_POSITION_AUX27, + PA_CHANNEL_POSITION_AUX28, + PA_CHANNEL_POSITION_AUX29, + PA_CHANNEL_POSITION_AUX30, + PA_CHANNEL_POSITION_AUX31, + + PA_CHANNEL_POSITION_TOP_CENTER, + + PA_CHANNEL_POSITION_TOP_FRONT_LEFT, + PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, + PA_CHANNEL_POSITION_TOP_FRONT_CENTER, + + PA_CHANNEL_POSITION_TOP_REAR_LEFT, + PA_CHANNEL_POSITION_TOP_REAR_RIGHT, + PA_CHANNEL_POSITION_TOP_REAR_CENTER, + + PA_CHANNEL_POSITION_MAX +} pa_channel_position_t; + +/** A list of channel mapping definitions for pa_channel_map_init_auto() */ +typedef enum pa_channel_map_def { + PA_CHANNEL_MAP_AIFF, /**< The mapping from RFC3551, which is based on AIFF-C */ + PA_CHANNEL_MAP_ALSA, /**< The default mapping used by ALSA */ + PA_CHANNEL_MAP_AUX, /**< Only aux channels */ + PA_CHANNEL_MAP_WAVEEX, /**< Microsoft's WAVEFORMATEXTENSIBLE mapping */ + PA_CHANNEL_MAP_OSS, /**< The default channel mapping used by OSS as defined in the OSS 4.0 API specs */ + + PA_CHANNEL_MAP_DEFAULT = PA_CHANNEL_MAP_AIFF /**< The default channel map */ +} pa_channel_map_def_t; + +/** A channel map which can be used to attach labels to specific + * channels of a stream. These values are relevant for conversion and + * mixing of streams */ +typedef struct pa_channel_map { + uint8_t channels; /**< Number of channels */ + pa_channel_position_t map[PA_CHANNELS_MAX]; /**< Channel labels */ +} pa_channel_map; + +/** Initialize the specified channel map and return a pointer to it */ +pa_channel_map* pa_channel_map_init(pa_channel_map *m); + +/** Initialize the specified channel map for monoaural audio and return a pointer to it */ +pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m); + +/** Initialize the specified channel map for stereophonic audio and return a pointer to it */ +pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m); + +/** Initialize the specified channel map for the specified number + * of channels using default labels and return a pointer to it. */ +pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def); + +/** Return a text label for the specified channel position */ +const char* pa_channel_position_to_string(pa_channel_position_t pos); + +/** The maximum length of strings returned by pa_channel_map_snprint() */ +#define PA_CHANNEL_MAP_SNPRINT_MAX 336 + +/** Make a humand readable string from the specified channel map */ +char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map); + +/** Parse a channel position list into a channel map structure. \since 0.8.1 */ +pa_channel_map *pa_channel_map_parse(pa_channel_map *map, const char *s); + +/** Compare two channel maps. Return 1 if both match. */ +int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b); + +/** Return non-zero of the specified channel map is considered valid */ +int pa_channel_map_valid(const pa_channel_map *map); + +PA_C_DECL_END + +#endif diff --git a/src/pulse/client-conf-x11.c b/src/pulse/client-conf-x11.c new file mode 100644 index 00000000..7eea5ae3 --- /dev/null +++ b/src/pulse/client-conf-x11.c @@ -0,0 +1,93 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-13071 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include "client-conf-x11.h" + +int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) { + Display *d = NULL; + int ret = -1; + char t[1024]; + + if (!dname && !getenv("DISPLAY")) + goto finish; + + if (!(d = XOpenDisplay(dname))) { + pa_log(__FILE__": XOpenDisplay() failed"); + goto finish; + } + + if (pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) { + pa_xfree(c->default_server); + c->default_server = pa_xstrdup(t); + } + + if (pa_x11_get_prop(d, "POLYP_SINK", t, sizeof(t))) { + pa_xfree(c->default_sink); + c->default_sink = pa_xstrdup(t); + } + + if (pa_x11_get_prop(d, "POLYP_SOURCE", t, sizeof(t))) { + pa_xfree(c->default_source); + c->default_source = pa_xstrdup(t); + } + + if (pa_x11_get_prop(d, "POLYP_COOKIE", t, sizeof(t))) { + uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; + + if (pa_parsehex(t, cookie, sizeof(cookie)) != sizeof(cookie)) { + pa_log(__FILE__": failed to parse cookie data"); + goto finish; + } + + assert(sizeof(cookie) == sizeof(c->cookie)); + memcpy(c->cookie, cookie, sizeof(cookie)); + + c->cookie_valid = 1; + + pa_xfree(c->cookie_file); + c->cookie_file = NULL; + } + + ret = 0; + +finish: + if (d) + XCloseDisplay(d); + + return ret; + +} diff --git a/src/pulse/client-conf-x11.h b/src/pulse/client-conf-x11.h new file mode 100644 index 00000000..02e808be --- /dev/null +++ b/src/pulse/client-conf-x11.h @@ -0,0 +1,31 @@ +#ifndef fooclientconfx11hfoo +#define fooclientconfx11hfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "client-conf.h" + +/* Load client configuration data from the specified X11 display, + * overwriting the current settings in *c */ +int pa_client_conf_from_x11(pa_client_conf *c, const char *display); + +#endif diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c new file mode 100644 index 00000000..752d0134 --- /dev/null +++ b/src/pulse/client-conf.c @@ -0,0 +1,193 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "client-conf.h" + +#ifndef DEFAULT_CONFIG_DIR +# ifndef OS_IS_WIN32 +# define DEFAULT_CONFIG_DIR "/etc/pulseaudio" +# else +# define DEFAULT_CONFIG_DIR "%POLYP_ROOT%" +# endif +#endif + +#ifndef OS_IS_WIN32 +# define PATH_SEP "/" +#else +# define PATH_SEP "\\" +#endif + +#define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "client.conf" +#define DEFAULT_CLIENT_CONFIG_FILE_USER ".pulseaudio" PATH_SEP "client.conf" + +#define ENV_CLIENT_CONFIG_FILE "POLYP_CLIENTCONFIG" +#define ENV_DEFAULT_SINK "POLYP_SINK" +#define ENV_DEFAULT_SOURCE "POLYP_SOURCE" +#define ENV_DEFAULT_SERVER "POLYP_SERVER" +#define ENV_DAEMON_BINARY "POLYP_BINARY" +#define ENV_COOKIE_FILE "POLYP_COOKIE" + +static const pa_client_conf default_conf = { + .daemon_binary = NULL, + .extra_arguments = NULL, + .default_sink = NULL, + .default_source = NULL, + .default_server = NULL, + .autospawn = 0, + .cookie_file = NULL, + .cookie_valid = 0 +}; + +pa_client_conf *pa_client_conf_new(void) { + pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); + + c->daemon_binary = pa_xstrdup(POLYPAUDIO_BINARY); + c->extra_arguments = pa_xstrdup("--log-target=syslog --exit-idle-time=5"); + c->cookie_file = pa_xstrdup(PA_NATIVE_COOKIE_FILE); + + return c; +} + +void pa_client_conf_free(pa_client_conf *c) { + assert(c); + pa_xfree(c->daemon_binary); + pa_xfree(c->extra_arguments); + pa_xfree(c->default_sink); + pa_xfree(c->default_source); + pa_xfree(c->default_server); + pa_xfree(c->cookie_file); + pa_xfree(c); +} +int pa_client_conf_load(pa_client_conf *c, const char *filename) { + FILE *f = NULL; + char *fn = NULL; + int r = -1; + + /* Prepare the configuration parse table */ + pa_config_item table[] = { + { "daemon-binary", pa_config_parse_string, NULL }, + { "extra-arguments", pa_config_parse_string, NULL }, + { "default-sink", pa_config_parse_string, NULL }, + { "default-source", pa_config_parse_string, NULL }, + { "default-server", pa_config_parse_string, NULL }, + { "autospawn", pa_config_parse_bool, NULL }, + { "cookie-file", pa_config_parse_string, NULL }, + { NULL, NULL, NULL }, + }; + + table[0].data = &c->daemon_binary; + table[1].data = &c->extra_arguments; + table[2].data = &c->default_sink; + table[3].data = &c->default_source; + table[4].data = &c->default_server; + table[5].data = &c->autospawn; + table[6].data = &c->cookie_file; + + f = filename ? + fopen((fn = pa_xstrdup(filename)), "r") : + pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn, "r"); + + if (!f && errno != EINTR) { + pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", filename, pa_cstrerror(errno)); + goto finish; + } + + r = f ? pa_config_parse(fn, f, table, NULL) : 0; + + if (!r) + r = pa_client_conf_load_cookie(c); + + +finish: + pa_xfree(fn); + + if (f) + fclose(f); + + return r; +} + +int pa_client_conf_env(pa_client_conf *c) { + char *e; + + if ((e = getenv(ENV_DEFAULT_SINK))) { + pa_xfree(c->default_sink); + c->default_sink = pa_xstrdup(e); + } + + if ((e = getenv(ENV_DEFAULT_SOURCE))) { + pa_xfree(c->default_source); + c->default_source = pa_xstrdup(e); + } + + if ((e = getenv(ENV_DEFAULT_SERVER))) { + pa_xfree(c->default_server); + c->default_server = pa_xstrdup(e); + } + + if ((e = getenv(ENV_DAEMON_BINARY))) { + pa_xfree(c->daemon_binary); + c->daemon_binary = pa_xstrdup(e); + } + + if ((e = getenv(ENV_COOKIE_FILE))) { + pa_xfree(c->cookie_file); + c->cookie_file = pa_xstrdup(e); + + return pa_client_conf_load_cookie(c); + } + + return 0; +} + +int pa_client_conf_load_cookie(pa_client_conf* c) { + assert(c); + + c->cookie_valid = 0; + + if (!c->cookie_file) + return -1; + + if (pa_authkey_load_auto(c->cookie_file, c->cookie, sizeof(c->cookie)) < 0) + return -1; + + c->cookie_valid = 1; + return 0; +} + diff --git a/src/pulse/client-conf.h b/src/pulse/client-conf.h new file mode 100644 index 00000000..9d45af47 --- /dev/null +++ b/src/pulse/client-conf.h @@ -0,0 +1,52 @@ +#ifndef fooclientconfhfoo +#define fooclientconfhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +/* A structure containing configuration data for pulseaudio clients. */ + +typedef struct pa_client_conf { + char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server, *cookie_file; + int autospawn; + uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; + int cookie_valid; /* non-zero, when cookie is valid */ +} pa_client_conf; + +/* Create a new configuration data object and reset it to defaults */ +pa_client_conf *pa_client_conf_new(void); +void pa_client_conf_free(pa_client_conf *c); + +/* Load the configuration data from the speicified file, overwriting + * the current settings in *c. When the filename is NULL, the + * default client configuration file name is used. */ +int pa_client_conf_load(pa_client_conf *c, const char *filename); + +/* Load the configuration data from the environment of the current + process, overwriting the current settings in *c. */ +int pa_client_conf_env(pa_client_conf *c); + +/* Load cookie data from c->cookie_file into c->cookie */ +int pa_client_conf_load_cookie(pa_client_conf* c); + +#endif diff --git a/src/pulse/client.conf.in b/src/pulse/client.conf.in new file mode 100644 index 00000000..d881c44e --- /dev/null +++ b/src/pulse/client.conf.in @@ -0,0 +1,39 @@ +# $Id$ +# +# This file is part of PulseAudio. +# +# PulseAudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# PulseAudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with PulseAudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +## Configuration file for pulseaudio clients. Default values are +## commented out. Use either ; or # for commenting + +## Path to the pulseaudio daemon to run when autospawning. +; daemon-binary = @POLYPAUDIO_BINARY@ + +## Extra arguments to pass to the pulseaudio daemon +; extra-arguments = --log-target=syslog --exit-idle-time=5 + +## The default sink to connect to +; default-sink = + +## The default source to connect to +; default-source = + +## The default sever to connect to +; default-server = + +## Autospawn daemons? +; autospawn = 0 diff --git a/src/pulse/context.c b/src/pulse/context.c new file mode 100644 index 00000000..648024c3 --- /dev/null +++ b/src/pulse/context.c @@ -0,0 +1,980 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_WAIT_H +#include +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif + +#include "../pulsecore/winsock.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + +#include "client-conf.h" + +#ifdef HAVE_X11 +#include "client-conf-x11.h" +#endif + +#include "context.h" + +#define AUTOSPAWN_LOCK "autospawn.lock" + +static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_REQUEST] = pa_command_request, + [PA_COMMAND_OVERFLOW] = pa_command_overflow_or_underflow, + [PA_COMMAND_UNDERFLOW] = pa_command_overflow_or_underflow, + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = pa_command_stream_killed, + [PA_COMMAND_RECORD_STREAM_KILLED] = pa_command_stream_killed, + [PA_COMMAND_SUBSCRIBE_EVENT] = pa_command_subscribe_event +}; + +static void unlock_autospawn_lock_file(pa_context *c) { + assert(c); + + if (c->autospawn_lock_fd >= 0) { + char lf[PATH_MAX]; + pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); + + pa_unlock_lockfile(lf, c->autospawn_lock_fd); + c->autospawn_lock_fd = -1; + } +} + +pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { + pa_context *c; + + assert(mainloop); + assert(name); + + c = pa_xnew(pa_context, 1); + c->ref = 1; + c->name = pa_xstrdup(name); + c->mainloop = mainloop; + c->client = NULL; + c->pstream = NULL; + c->pdispatch = NULL; + c->playback_streams = pa_dynarray_new(); + c->record_streams = pa_dynarray_new(); + + PA_LLIST_HEAD_INIT(pa_stream, c->streams); + PA_LLIST_HEAD_INIT(pa_operation, c->operations); + + c->error = PA_OK; + c->state = PA_CONTEXT_UNCONNECTED; + c->ctag = 0; + c->csyncid = 0; + + c->state_callback = NULL; + c->state_userdata = NULL; + + c->subscribe_callback = NULL; + c->subscribe_userdata = NULL; + + c->memblock_stat = pa_memblock_stat_new(); + c->local = -1; + c->server_list = NULL; + c->server = NULL; + c->autospawn_lock_fd = -1; + memset(&c->spawn_api, 0, sizeof(c->spawn_api)); + c->do_autospawn = 0; + +#ifdef SIGPIPE + pa_check_signal_is_blocked(SIGPIPE); +#endif + + c->conf = pa_client_conf_new(); + pa_client_conf_load(c->conf, NULL); +#ifdef HAVE_X11 + pa_client_conf_from_x11(c->conf, NULL); +#endif + pa_client_conf_env(c->conf); + + return c; +} + +static void context_free(pa_context *c) { + assert(c); + + unlock_autospawn_lock_file(c); + + while (c->operations) + pa_operation_cancel(c->operations); + + while (c->streams) + pa_stream_set_state(c->streams, PA_STREAM_TERMINATED); + + if (c->client) + pa_socket_client_unref(c->client); + if (c->pdispatch) + pa_pdispatch_unref(c->pdispatch); + if (c->pstream) { + pa_pstream_close(c->pstream); + pa_pstream_unref(c->pstream); + } + + if (c->record_streams) + pa_dynarray_free(c->record_streams, NULL, NULL); + if (c->playback_streams) + pa_dynarray_free(c->playback_streams, NULL, NULL); + + pa_memblock_stat_unref(c->memblock_stat); + + if (c->conf) + pa_client_conf_free(c->conf); + + pa_strlist_free(c->server_list); + + pa_xfree(c->name); + pa_xfree(c->server); + pa_xfree(c); +} + +pa_context* pa_context_ref(pa_context *c) { + assert(c); + assert(c->ref >= 1); + + c->ref++; + return c; +} + +void pa_context_unref(pa_context *c) { + assert(c); + assert(c->ref >= 1); + + if (--c->ref <= 0) + context_free(c); +} + +void pa_context_set_state(pa_context *c, pa_context_state_t st) { + assert(c); + assert(c->ref >= 1); + + if (c->state == st) + return; + + pa_context_ref(c); + + c->state = st; + if (c->state_callback) + c->state_callback(c, c->state_userdata); + + if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) { + pa_stream *s; + + s = c->streams ? pa_stream_ref(c->streams) : NULL; + while (s) { + pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL; + pa_stream_set_state(s, st == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED); + pa_stream_unref(s); + s = n; + } + + if (c->pdispatch) + pa_pdispatch_unref(c->pdispatch); + c->pdispatch = NULL; + + if (c->pstream) { + pa_pstream_close(c->pstream); + pa_pstream_unref(c->pstream); + } + c->pstream = NULL; + + if (c->client) + pa_socket_client_unref(c->client); + c->client = NULL; + } + + pa_context_unref(c); +} + +void pa_context_fail(pa_context *c, int error) { + assert(c); + assert(c->ref >= 1); + + pa_context_set_error(c, error); + pa_context_set_state(c, PA_CONTEXT_FAILED); +} + +int pa_context_set_error(pa_context *c, int error) { + assert(error >= 0); + assert(error < PA_ERR_MAX); + + if (c) + c->error = error; + + return error; +} + +static void pstream_die_callback(pa_pstream *p, void *userdata) { + pa_context *c = userdata; + + assert(p); + assert(c); + + pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED); +} + +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const void *creds, void *userdata) { + pa_context *c = userdata; + + assert(p); + assert(packet); + assert(c); + + pa_context_ref(c); + + if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) + pa_context_fail(c, PA_ERR_PROTOCOL); + + pa_context_unref(c); +} + +static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { + pa_context *c = userdata; + pa_stream *s; + + assert(p); + assert(chunk); + assert(chunk->memblock); + assert(chunk->length); + assert(c); + assert(c->ref >= 1); + + pa_context_ref(c); + + if ((s = pa_dynarray_get(c->record_streams, channel))) { + + assert(seek == PA_SEEK_RELATIVE && offset == 0); + + pa_memblockq_seek(s->record_memblockq, offset, seek); + pa_memblockq_push_align(s->record_memblockq, chunk); + + if (s->read_callback) { + size_t l; + + if ((l = pa_memblockq_get_length(s->record_memblockq)) > 0) + s->read_callback(s, l, s->read_userdata); + } + } + + pa_context_unref(c); +} + +int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t) { + assert(c); + assert(c->ref >= 1); + + if (command == PA_COMMAND_ERROR) { + assert(t); + + if (pa_tagstruct_getu32(t, &c->error) < 0) { + pa_context_fail(c, PA_ERR_PROTOCOL); + return -1; + + } + } else if (command == PA_COMMAND_TIMEOUT) + c->error = PA_ERR_TIMEOUT; + else { + pa_context_fail(c, PA_ERR_PROTOCOL); + return -1; + } + + return 0; +} + +static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_context *c = userdata; + + assert(pd); + assert(c); + assert(c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME); + + pa_context_ref(c); + + if (command != PA_COMMAND_REPLY) { + + if (pa_context_handle_error(c, command, t) < 0) + pa_context_fail(c, PA_ERR_PROTOCOL); + + pa_context_fail(c, c->error); + goto finish; + } + + switch(c->state) { + case PA_CONTEXT_AUTHORIZING: { + pa_tagstruct *reply; + + if (pa_tagstruct_getu32(t, &c->version) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(c, PA_ERR_PROTOCOL); + goto finish; + } + + /* Minimum supported version */ + if (c->version < 8) { + pa_context_fail(c, PA_ERR_VERSION); + goto finish; + } + + reply = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag); + pa_tagstruct_puts(reply, c->name); + pa_pstream_send_tagstruct(c->pstream, reply); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL); + + pa_context_set_state(c, PA_CONTEXT_SETTING_NAME); + break; + } + + case PA_CONTEXT_SETTING_NAME : + pa_context_set_state(c, PA_CONTEXT_READY); + break; + + default: + assert(0); + } + +finish: + pa_context_unref(c); +} + +static void setup_context(pa_context *c, pa_iochannel *io) { + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(io); + + pa_context_ref(c); + + assert(!c->pstream); + c->pstream = pa_pstream_new(c->mainloop, io, c->memblock_stat); + + pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); + pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); + pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); + + assert(!c->pdispatch); + c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); + + if (!c->conf->cookie_valid) { + pa_context_fail(c, PA_ERR_AUTHKEY); + goto finish; + } + + t = pa_tagstruct_command(c, PA_COMMAND_AUTH, &tag); + pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION); + pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie)); + pa_pstream_send_tagstruct_with_creds(c->pstream, t, 1); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL); + + pa_context_set_state(c, PA_CONTEXT_AUTHORIZING); + +finish: + + pa_context_unref(c); +} + +static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata); + +#ifndef OS_IS_WIN32 + +static int context_connect_spawn(pa_context *c) { + pid_t pid; + int status, r; + int fds[2] = { -1, -1} ; + pa_iochannel *io; + + pa_context_ref(c); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { + pa_log(__FILE__": socketpair(): %s", pa_cstrerror(errno)); + pa_context_fail(c, PA_ERR_INTERNAL); + goto fail; + } + + pa_fd_set_cloexec(fds[0], 1); + + pa_socket_low_delay(fds[0]); + pa_socket_low_delay(fds[1]); + + if (c->spawn_api.prefork) + c->spawn_api.prefork(); + + if ((pid = fork()) < 0) { + pa_log(__FILE__": fork(): %s", pa_cstrerror(errno)); + pa_context_fail(c, PA_ERR_INTERNAL); + + if (c->spawn_api.postfork) + c->spawn_api.postfork(); + + goto fail; + } else if (!pid) { + /* Child */ + + char t[128]; + const char *state = NULL; +#define MAX_ARGS 64 + const char * argv[MAX_ARGS+1]; + int n; + + /* Not required, since fds[0] has CLOEXEC enabled anyway */ + close(fds[0]); + + if (c->spawn_api.atfork) + c->spawn_api.atfork(); + + /* Setup argv */ + + n = 0; + + argv[n++] = c->conf->daemon_binary; + argv[n++] = "--daemonize=yes"; + + snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]); + argv[n++] = strdup(t); + + while (n < MAX_ARGS) { + char *a; + + if (!(a = pa_split_spaces(c->conf->extra_arguments, &state))) + break; + + argv[n++] = a; + } + + argv[n++] = NULL; + + execv(argv[0], (char * const *) argv); + _exit(1); +#undef MAX_ARGS + } + + /* Parent */ + + r = waitpid(pid, &status, 0); + + if (c->spawn_api.postfork) + c->spawn_api.postfork(); + + if (r < 0) { + pa_log(__FILE__": waitpid(): %s", pa_cstrerror(errno)); + pa_context_fail(c, PA_ERR_INTERNAL); + goto fail; + } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); + goto fail; + } + + close(fds[1]); + + c->local = 1; + + io = pa_iochannel_new(c->mainloop, fds[0], fds[0]); + + setup_context(c, io); + unlock_autospawn_lock_file(c); + + pa_context_unref(c); + + return 0; + +fail: + if (fds[0] != -1) + close(fds[0]); + if (fds[1] != -1) + close(fds[1]); + + unlock_autospawn_lock_file(c); + + pa_context_unref(c); + + return -1; +} + +#endif /* OS_IS_WIN32 */ + +static int try_next_connection(pa_context *c) { + char *u = NULL; + int r = -1; + + assert(c); + assert(!c->client); + + for (;;) { + pa_xfree(u); + u = NULL; + + c->server_list = pa_strlist_pop(c->server_list, &u); + + if (!u) { + +#ifndef OS_IS_WIN32 + if (c->do_autospawn) { + r = context_connect_spawn(c); + goto finish; + } +#endif + + pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); + goto finish; + } + + pa_log_debug(__FILE__": Trying to connect to %s...", u); + + pa_xfree(c->server); + c->server = pa_xstrdup(u); + + if (!(c->client = pa_socket_client_new_string(c->mainloop, u, PA_NATIVE_DEFAULT_PORT))) + continue; + + c->local = pa_socket_client_is_local(c->client); + pa_socket_client_set_callback(c->client, on_connection, c); + break; + } + + r = 0; + +finish: + pa_xfree(u); + + return r; +} + +static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata) { + pa_context *c = userdata; + + assert(client); + assert(c); + assert(c->state == PA_CONTEXT_CONNECTING); + + pa_context_ref(c); + + pa_socket_client_unref(client); + c->client = NULL; + + if (!io) { + /* Try the item in the list */ + if (errno == ECONNREFUSED || errno == ETIMEDOUT || errno == EHOSTUNREACH) { + try_next_connection(c); + goto finish; + } + + pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); + goto finish; + } + + unlock_autospawn_lock_file(c); + setup_context(c, io); + +finish: + pa_context_unref(c); +} + +int pa_context_connect( + pa_context *c, + const char *server, + pa_context_flags_t flags, + const pa_spawn_api *api) { + + int r = -1; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_UNCONNECTED, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(c, !(flags & ~PA_CONTEXT_NOAUTOSPAWN), PA_ERR_INVALID); + PA_CHECK_VALIDITY(c, !server || *server, PA_ERR_INVALID); + + if (!server) + server = c->conf->default_server; + + pa_context_ref(c); + + assert(!c->server_list); + + if (server) { + if (!(c->server_list = pa_strlist_parse(server))) { + pa_context_fail(c, PA_ERR_INVALIDSERVER); + goto finish; + } + } else { + char *d; + char ufn[PATH_MAX]; + + /* Prepend in reverse order */ + + if ((d = getenv("DISPLAY"))) { + char *e; + d = pa_xstrdup(d); + if ((e = strchr(d, ':'))) + *e = 0; + + if (*d) + c->server_list = pa_strlist_prepend(c->server_list, d); + + pa_xfree(d); + } + + c->server_list = pa_strlist_prepend(c->server_list, "tcp6:localhost"); + c->server_list = pa_strlist_prepend(c->server_list, "localhost"); + c->server_list = pa_strlist_prepend(c->server_list, pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET, ufn, sizeof(ufn))); + + /* Wrap the connection attempts in a single transaction for sane autospawn locking */ + if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) { + char lf[PATH_MAX]; + + pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); + pa_make_secure_parent_dir(lf); + assert(c->autospawn_lock_fd <= 0); + c->autospawn_lock_fd = pa_lock_lockfile(lf); + + if (api) + c->spawn_api = *api; + c->do_autospawn = 1; + } + + } + + pa_context_set_state(c, PA_CONTEXT_CONNECTING); + r = try_next_connection(c); + +finish: + pa_context_unref(c); + + return r; +} + +void pa_context_disconnect(pa_context *c) { + assert(c); + assert(c->ref >= 1); + + pa_context_set_state(c, PA_CONTEXT_TERMINATED); +} + +pa_context_state_t pa_context_get_state(pa_context *c) { + assert(c); + assert(c->ref >= 1); + + return c->state; +} + +int pa_context_errno(pa_context *c) { + assert(c); + assert(c->ref >= 1); + + return c->error; +} + +void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) { + assert(c); + assert(c->ref >= 1); + + c->state_callback = cb; + c->state_userdata = userdata; +} + +int pa_context_is_pending(pa_context *c) { + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY(c, + c->state == PA_CONTEXT_CONNECTING || + c->state == PA_CONTEXT_AUTHORIZING || + c->state == PA_CONTEXT_SETTING_NAME || + c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + return (c->pstream && pa_pstream_is_pending(c->pstream)) || + (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) || + c->client; +} + +static void set_dispatch_callbacks(pa_operation *o); + +static void pdispatch_drain_callback(PA_GCC_UNUSED pa_pdispatch*pd, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void pstream_drain_callback(PA_GCC_UNUSED pa_pstream *s, void *userdata) { + set_dispatch_callbacks(userdata); +} + +static void set_dispatch_callbacks(pa_operation *o) { + int done = 1; + + assert(o); + assert(o->ref >= 1); + assert(o->context); + assert(o->context->ref >= 1); + assert(o->context->state == PA_CONTEXT_READY); + + pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL); + + if (pa_pdispatch_is_pending(o->context->pdispatch)) { + pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o); + done = 0; + } + + if (pa_pstream_is_pending(o->context->pstream)) { + pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o); + done = 0; + } + + if (done) { + if (o->callback) { + pa_context_notify_cb_t cb = (pa_context_notify_cb_t) o->callback; + cb(o->context, o->userdata); + } + + pa_operation_done(o); + pa_operation_unref(o); + } +} + +pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) { + pa_operation *o; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, pa_context_is_pending(c), PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + set_dispatch_callbacks(pa_operation_ref(o)); + + return o; +} + +void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int success = 1; + + assert(pd); + assert(o); + assert(o->ref >= 1); + + if (!o->context) + goto finish; + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + success = 0; + } else if (!pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERR_PROTOCOL); + goto finish; + } + + if (o->callback) { + pa_context_success_cb_t cb = (pa_context_success_cb_t) o->callback; + cb(o->context, success, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_EXIT, &tag); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, pa_pdispatch_cb_t internal_cb, pa_operation_cb_t cb, void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, cb, userdata); + + t = pa_tagstruct_command(c, command, &tag); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SINK, &tag); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SOURCE, &tag); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +int pa_context_is_local(pa_context *c) { + assert(c); + + return c->local; +} + +pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(name); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +const char* pa_get_library_version(void) { + return PACKAGE_VERSION; +} + +const char* pa_context_get_server(pa_context *c) { + assert(c); + assert(c->ref >= 1); + + if (!c->server) + return NULL; + + if (*c->server == '{') { + char *e = strchr(c->server+1, '}'); + return e ? e+1 : c->server; + } + + return c->server; +} + +uint32_t pa_context_get_protocol_version(PA_GCC_UNUSED pa_context *c) { + return PA_PROTOCOL_VERSION; +} + +uint32_t pa_context_get_server_protocol_version(pa_context *c) { + assert(c); + assert(c->ref >= 1); + + return c->version; +} + +pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag) { + pa_tagstruct *t; + + assert(c); + assert(tag); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, command); + pa_tagstruct_putu32(t, *tag = c->ctag++); + + return t; +} diff --git a/src/pulse/context.h b/src/pulse/context.h new file mode 100644 index 00000000..65d70e8b --- /dev/null +++ b/src/pulse/context.h @@ -0,0 +1,230 @@ +#ifndef foocontexthfoo +#define foocontexthfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include +#include + +/** \page async Asynchronous API + * + * \section overv_sec Overview + * + * The asynchronous API is the native interface to the pulseaudio library. + * It allows full access to all available functions. This also means that + * it is rather complex and can take some time to fully master. + * + * \section mainloop_sec Main Loop Abstraction + * + * The API is based around an asynchronous event loop, or main loop, + * abstraction. This abstraction contains three basic elements: + * + * \li Deferred events - Events that will trigger as soon as possible. Note + * that some implementations may block all other events + * when a deferred event is active. + * \li I/O events - Events that trigger on file descriptor activities. + * \li Times events - Events that trigger after a fixed ammount of time. + * + * The abstraction is represented as a number of function pointers in the + * pa_mainloop_api structure. + * + * To actually be able to use these functions, an implementation needs to + * be coupled to the abstraction. There are three of these shipped with + * pulseaudio, but any other can be used with a minimal ammount of work, + * provided it supports the three basic events listed above. + * + * The implementations shipped with pulseaudio are: + * + * \li \subpage mainloop - A minimal but fast implementation based on poll(). + * \li \subpage threaded_mainloop - A special version of the previous + * implementation where all of Polypaudio's + * internal handling runs in a separate + * thread. + * \li \subpage glib-mainloop - A wrapper around GLIB's main loop. Available + * for both GLIB 1.2 and GLIB 2.x. + * + * UNIX signals may be hooked to a main loop using the functions from + * \ref mainloop-signal.h. These rely only on the main loop abstraction + * and can therefore be used with any of the implementations. + * + * \section refcnt_sec Reference Counting + * + * Almost all objects in pulseaudio are reference counted. What that means + * is that you rarely malloc() or free() any objects. Instead you increase + * and decrease their reference counts. Whenever an object's reference + * count reaches zero, that object gets destroy and any resources it uses + * get freed. + * + * The benefit of this design is that an application need not worry about + * whether or not it needs to keep an object around in case the library is + * using it internally. If it is, then it has made sure it has its own + * reference to it. + * + * Whenever the library creates an object, it will have an initial + * reference count of one. Most of the time, this single reference will be + * sufficient for the application, so all required reference count + * interaction will be a single call to the objects unref function. + * + * \section context_sec Context + * + * A context is the basic object for a connection to a pulseaudio server. + * It multiplexes commands, data streams and events through a single + * channel. + * + * There is no need for more than one context per application, unless + * connections to multiple servers are needed. + * + * \subsection ops_subsec Operations + * + * All operations on the context are performed asynchronously. I.e. the + * client will not wait for the server to complete the request. To keep + * track of all these in-flight operations, the application is given a + * pa_operation object for each asynchronous operation. + * + * There are only two actions (besides reference counting) that can be + * performed on a pa_operation: querying its state with + * pa_operation_get_state() and aborting it with pa_operation_cancel(). + * + * A pa_operation object is reference counted, so an application must + * make sure to unreference it, even if it has no intention of using it. + * + * \subsection conn_subsec Connecting + * + * A context must be connected to a server before any operation can be + * issued. Calling pa_context_connect() will initiate the connection + * procedure. Unlike most asynchronous operations, connecting does not + * result in a pa_operation object. Instead, the application should + * register a callback using pa_context_set_state_callback(). + * + * \subsection disc_subsec Disconnecting + * + * When the sound support is no longer needed, the connection needs to be + * closed using pa_context_disconnect(). This is an immediate function that + * works synchronously. + * + * Since the context object has references to other objects it must be + * disconnected after use or there is a high risk of memory leaks. If the + * connection has terminated by itself, then there is no need to explicitly + * disconnect the context using pa_context_disconnect(). + * + * \section Functions + * + * The sound server's functionality can be divided into a number of + * subsections: + * + * \li \subpage streams + * \li \subpage scache + * \li \subpage introspect + * \li \subpage subscribe + */ + +/** \file + * Connection contexts for asynchrononous communication with a + * server. A pa_context object wraps a connection to a pulseaudio + * server using its native protocol. */ + +/** \example pacat.c + * A playback and recording tool using the asynchronous API */ + +/** \example paplay.c + * A sound file playback tool using the asynchronous API, based on libsndfile */ + +PA_C_DECL_BEGIN + +/** An opaque connection context to a daemon */ +typedef struct pa_context pa_context; + +/** Generic notification callback prototype */ +typedef void (*pa_context_notify_cb_t)(pa_context *c, void *userdata); + +/** A generic callback for operation completion */ +typedef void (*pa_context_success_cb_t) (pa_context *c, int success, void *userdata); + +/** Instantiate a new connection context with an abstract mainloop API + * and an application name */ +pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name); + +/** Decrease the reference counter of the context by one */ +void pa_context_unref(pa_context *c); + +/** Increase the reference counter of the context by one */ +pa_context* pa_context_ref(pa_context *c); + +/** Set a callback function that is called whenever the context status changes */ +void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata); + +/** Return the error number of the last failed operation */ +int pa_context_errno(pa_context *c); + +/** Return non-zero if some data is pending to be written to the connection */ +int pa_context_is_pending(pa_context *c); + +/** Return the current context status */ +pa_context_state_t pa_context_get_state(pa_context *c); + +/** Connect the context to the specified server. If server is NULL, +connect to the default server. This routine may but will not always +return synchronously on error. Use pa_context_set_state_callback() to +be notified when the connection is established. If flags doesn't have +PA_NOAUTOSPAWN set and no specific server is specified or accessible a +new daemon is spawned. If api is non-NULL, the functions specified in +the structure are used when forking a new child process. */ +int pa_context_connect(pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api); + +/** Terminate the context connection immediately */ +void pa_context_disconnect(pa_context *c); + +/** Drain the context. If there is nothing to drain, the function returns NULL */ +pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata); + +/** Tell the daemon to exit. The returned operation is unlikely to + * complete succesfully, since the daemon probably died before + * returning a success notification */ +pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata); + +/** Set the name of the default sink. \since 0.4 */ +pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata); + +/** Set the name of the default source. \since 0.4 */ +pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata); + +/** Returns 1 when the connection is to a local daemon. Returns negative when no connection has been made yet. \since 0.5 */ +int pa_context_is_local(pa_context *c); + +/** Set a different application name for context on the server. \since 0.5 */ +pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata); + +/** Return the server name this context is connected to. \since 0.7 */ +const char* pa_context_get_server(pa_context *c); + +/** Return the protocol version of the library. \since 0.8 */ +uint32_t pa_context_get_protocol_version(pa_context *c); + +/** Return the protocol version of the connected server. \since 0.8 */ +uint32_t pa_context_get_server_protocol_version(pa_context *c); + +PA_C_DECL_END + +#endif diff --git a/src/pulse/def.h b/src/pulse/def.h new file mode 100644 index 00000000..3a17f43b --- /dev/null +++ b/src/pulse/def.h @@ -0,0 +1,312 @@ +#ifndef foodefhfoo +#define foodefhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include + +#include +#include + +/** \file + * Global definitions */ + +PA_C_DECL_BEGIN + +/** The state of a connection context */ +typedef enum pa_context_state { + PA_CONTEXT_UNCONNECTED, /**< The context hasn't been connected yet */ + PA_CONTEXT_CONNECTING, /**< A connection is being established */ + PA_CONTEXT_AUTHORIZING, /**< The client is authorizing itself to the daemon */ + PA_CONTEXT_SETTING_NAME, /**< The client is passing its application name to the daemon */ + PA_CONTEXT_READY, /**< The connection is established, the context is ready to execute operations */ + PA_CONTEXT_FAILED, /**< The connection failed or was disconnected */ + PA_CONTEXT_TERMINATED /**< The connection was terminated cleanly */ +} pa_context_state_t; + +/** The state of a stream */ +typedef enum pa_stream_state { + PA_STREAM_UNCONNECTED, /**< The stream is not yet connected to any sink or source */ + PA_STREAM_CREATING, /**< The stream is being created */ + PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */ + PA_STREAM_FAILED, /**< An error occured that made the stream invalid */ + PA_STREAM_TERMINATED /**< The stream has been terminated cleanly */ +} pa_stream_state_t; + +/** The state of an operation */ +typedef enum pa_operation_state { + PA_OPERATION_RUNNING, /**< The operation is still running */ + PA_OPERATION_DONE, /**< The operation has been completed */ + PA_OPERATION_CANCELED /**< The operation has been canceled */ +} pa_operation_state_t; + +/** An invalid index */ +#define PA_INVALID_INDEX ((uint32_t) -1) + +/** Some special flags for contexts. \since 0.8 */ +typedef enum pa_context_flags { + PA_CONTEXT_NOAUTOSPAWN = 1 /**< Disabled autospawning of the pulseaudio daemon if required */ +} pa_context_flags_t; + +/** The direction of a pa_stream object */ +typedef enum pa_stream_direction { + PA_STREAM_NODIRECTION, /**< Invalid direction */ + PA_STREAM_PLAYBACK, /**< Playback stream */ + PA_STREAM_RECORD, /**< Record stream */ + PA_STREAM_UPLOAD /**< Sample upload stream */ +} pa_stream_direction_t; + +/** Some special flags for stream connections. \since 0.6 */ +typedef enum pa_stream_flags { + PA_STREAM_START_CORKED = 1, /**< Create the stream corked, requiring an explicit pa_stream_cork() call to uncork it. */ + PA_STREAM_INTERPOLATE_TIMING = 2, /**< Interpolate the latency for + * this stream. When enabled, + * pa_stream_get_latency() and + * pa_stream_get_time() will try + * to estimate the current + * record/playback time based on + * the local time that passed + * since the last timing info + * update. Using this option + * has the advantage of not + * requiring a whole roundtrip + * when the current + * playback/recording time is + * needed. Consider using this + * option when requesting + * latency information + * frequently. This is + * especially useful on long + * latency network + * connections. It makes a lot + * of sense to combine this + * option with + * PA_STREAM_AUTO_TIMING_UPDATE. */ + PA_STREAM_NOT_MONOTONOUS = 4, /**< Don't force the time to + * increase monotonically. If + * this option is enabled, + * pa_stream_get_time() will not + * necessarily return always + * monotonically increasing time + * values on each call. This may + * confuse applications which + * cannot deal with time going + * 'backwards', but has the + * advantage that bad transport + * latency estimations that + * caused the time to to jump + * ahead can be corrected + * quickly, without the need to + * wait. */ + PA_STREAM_AUTO_TIMING_UPDATE = 8 /**< If set timing update requests + * are issued periodically + * automatically. Combined with + * PA_STREAM_INTERPOLATE_TIMING + * you will be able to query the + * current time and latency with + * pa_stream_get_time() and + * pa_stream_get_latency() at + * all times without a packet + * round trip.*/ +} pa_stream_flags_t; + +/** Playback and record buffer metrics */ +typedef struct pa_buffer_attr { + uint32_t maxlength; /**< Maximum length of the buffer */ + uint32_t tlength; /**< Playback only: target length of the buffer. The server tries to assure that at least tlength bytes are always available in the buffer */ + uint32_t prebuf; /**< Playback only: pre-buffering. The server does not start with playback before at least prebug bytes are available in the buffer */ + uint32_t minreq; /**< Playback only: minimum request. The server does not request less than minreq bytes from the client, instead waints until the buffer is free enough to request more bytes at once */ + uint32_t fragsize; /**< Recording only: fragment size. The server sends data in blocks of fragsize bytes size. Large values deminish interactivity with other operations on the connection context but decrease control overhead. */ +} pa_buffer_attr; + +/** Error values as used by pa_context_errno(). Use pa_strerror() to convert these values to human readable strings */ +enum { + PA_OK = 0, /**< No error */ + PA_ERR_ACCESS, /**< Access failure */ + PA_ERR_COMMAND, /**< Unknown command */ + PA_ERR_INVALID, /**< Invalid argument */ + PA_ERR_EXIST, /**< Entity exists */ + PA_ERR_NOENTITY, /**< No such entity */ + PA_ERR_CONNECTIONREFUSED, /**< Connection refused */ + PA_ERR_PROTOCOL, /**< Protocol error */ + PA_ERR_TIMEOUT, /**< Timeout */ + PA_ERR_AUTHKEY, /**< No authorization key */ + PA_ERR_INTERNAL, /**< Internal error */ + PA_ERR_CONNECTIONTERMINATED, /**< Connection terminated */ + PA_ERR_KILLED, /**< Entity killed */ + PA_ERR_INVALIDSERVER, /**< Invalid server */ + PA_ERR_MODINITFAILED, /**< Module initialization failed */ + PA_ERR_BADSTATE, /**< Bad state */ + PA_ERR_NODATA, /**< No data */ + PA_ERR_VERSION, /**< Incompatible protocol version \since 0.8 */ + PA_ERR_TOOLARGE, /**< Data too large \since 0.8.1 */ + PA_ERR_MAX /**< Not really an error but the first invalid error code */ +}; + +/** Subscription event mask, as used by pa_context_subscribe() */ +typedef enum pa_subscription_mask { + PA_SUBSCRIPTION_MASK_NULL = 0, /**< No events */ + PA_SUBSCRIPTION_MASK_SINK = 1, /**< Sink events */ + PA_SUBSCRIPTION_MASK_SOURCE = 2, /**< Source events */ + PA_SUBSCRIPTION_MASK_SINK_INPUT = 4, /**< Sink input events */ + PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8, /**< Source output events */ + PA_SUBSCRIPTION_MASK_MODULE = 16, /**< Module events */ + PA_SUBSCRIPTION_MASK_CLIENT = 32, /**< Client events */ + PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, /**< Sample cache events */ + PA_SUBSCRIPTION_MASK_SERVER = 128, /**< Other global server changes. \since 0.4 */ + PA_SUBSCRIPTION_MASK_AUTOLOAD = 256, /**< Autoload table events. \since 0.5 */ + PA_SUBSCRIPTION_MASK_ALL = 511 /**< Catch all events \since 0.8 */ +} pa_subscription_mask_t; + +/** Subscription event types, as used by pa_context_subscribe() */ +typedef enum pa_subscription_event_type { + PA_SUBSCRIPTION_EVENT_SINK = 0, /**< Event type: Sink */ + PA_SUBSCRIPTION_EVENT_SOURCE = 1, /**< Event type: Source */ + PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2, /**< Event type: Sink input */ + PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 3, /**< Event type: Source output */ + PA_SUBSCRIPTION_EVENT_MODULE = 4, /**< Event type: Module */ + PA_SUBSCRIPTION_EVENT_CLIENT = 5, /**< Event type: Client */ + PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, /**< Event type: Sample cache item */ + PA_SUBSCRIPTION_EVENT_SERVER = 7, /**< Event type: Global server change, only occuring with PA_SUBSCRIPTION_EVENT_CHANGE. \since 0.4 */ + PA_SUBSCRIPTION_EVENT_AUTOLOAD = 8, /**< Event type: Autoload table changes. \since 0.5 */ + PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 15, /**< A mask to extract the event type from an event value */ + + PA_SUBSCRIPTION_EVENT_NEW = 0, /**< A new object was created */ + PA_SUBSCRIPTION_EVENT_CHANGE = 16, /**< A property of the object was modified */ + PA_SUBSCRIPTION_EVENT_REMOVE = 32, /**< An object was removed */ + PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32 /**< A mask to extract the event operation from an event value */ +} pa_subscription_event_type_t; + +/** Return one if an event type t matches an event mask bitfield */ +#define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) + +/** A structure for all kinds of timing information of a stream. See + * pa_stream_update_timing_info() and pa_stream_get_timing_info(). The + * total output latency a sample that is written with + * pa_stream_write() takes to be played may be estimated by + * sink_usec+buffer_usec+transport_usec. (where buffer_usec is defined + * as pa_bytes_to_usec(write_index-read_index)) The output buffer + * which buffer_usec relates to may be manipulated freely (with + * pa_stream_write()'s seek argument, pa_stream_flush() and friends), + * the buffers sink_usec and source_usec relate to are first-in + * first-out (FIFO) buffers which cannot be flushed or manipulated in + * any way. The total input latency a sample that is recorded takes to + * be delivered to the application is: + * source_usec+buffer_usec+transport_usec-sink_usec. (Take care of + * sign issues!) When connected to a monitor source sink_usec contains + * the latency of the owning sink. The two latency estimations + * described here are implemented in pa_stream_get_latency().*/ +typedef struct pa_timing_info { + struct timeval timestamp; /**< The time when this timing info structure was current */ + int synchronized_clocks; /**< Non-zero if the local and the + * remote machine have synchronized + * clocks. If synchronized clocks are + * detected transport_usec becomes much + * more reliable. However, the code that + * detects synchronized clocks is very + * limited und unreliable itself. \since + * 0.5 */ + + pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. For playback streams and record streams connected to a monitor source. */ + pa_usec_t source_usec; /**< Time in usecs a sample takes from being recorded to being delivered to the application. Only for record streams. \since 0.5*/ + pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to/from the daemon. For both playback and record streams. \since 0.5 */ + + int playing; /**< Non-zero when the stream is currently playing. Only for playback streams. */ + + int write_index_corrupt; /**< Non-zero if write_index is not + * up-to-date because a local write + * command that corrupted it has been + * issued in the time since this latency + * info was current . Only write + * commands with SEEK_RELATIVE_ON_READ + * and SEEK_RELATIVE_END can corrupt + * write_index. \since 0.8 */ + int64_t write_index; /**< Current write index into the + * playback buffer in bytes. Think twice before + * using this for seeking purposes: it + * might be out of date a the time you + * want to use it. Consider using + * PA_SEEK_RELATIVE instead. \since + * 0.8 */ + + int read_index_corrupt; /**< Non-zero if read_index is not + * up-to-date because a local pause or + * flush request that corrupted it has + * been issued in the time since this + * latency info was current. \since 0.8 */ + + int64_t read_index; /**< Current read index into the + * playback buffer in bytes. Think twice before + * using this for seeking purposes: it + * might be out of date a the time you + * want to use it. Consider using + * PA_SEEK_RELATIVE_ON_READ + * instead. \since 0.8 */ +} pa_timing_info; + +/** A structure for the spawn api. This may be used to integrate auto + * spawned daemons into your application. For more information see + * pa_context_connect(). When spawning a new child process the + * waitpid() is used on the child's PID. The spawn routine will not + * block or ignore SIGCHLD signals, since this cannot be done in a + * thread compatible way. You might have to do this in + * prefork/postfork. \since 0.4 */ +typedef struct pa_spawn_api { + void (*prefork)(void); /**< Is called just before the fork in the parent process. May be NULL. */ + void (*postfork)(void); /**< Is called immediately after the fork in the parent process. May be NULL.*/ + void (*atfork)(void); /**< Is called immediately after the + * fork in the child process. May be + * NULL. It is not safe to close all + * file descriptors in this function + * unconditionally, since a UNIX socket + * (created using socketpair()) is + * passed to the new process. */ +} pa_spawn_api; + +/** Seek type for pa_stream_write(). \since 0.8*/ +typedef enum pa_seek_mode { + PA_SEEK_RELATIVE = 0, /**< Seek relatively to the write index */ + PA_SEEK_ABSOLUTE = 1, /**< Seek relatively to the start of the buffer queue */ + PA_SEEK_RELATIVE_ON_READ = 2, /**< Seek relatively to the read index. */ + PA_SEEK_RELATIVE_END = 3 /**< Seek relatively to the current end of the buffer queue. */ +} pa_seek_mode_t; + +/** Special sink flags. \since 0.8 */ +typedef enum pa_sink_flags { + PA_SINK_HW_VOLUME_CTRL = 1, /**< Supports hardware volume control */ + PA_SINK_LATENCY = 2 /**< Supports latency querying */ +} pa_sink_flags_t; + +/** Special source flags. \since 0.8 */ +typedef enum pa_source_flags { + PA_SOURCE_HW_VOLUME_CTRL = 1, /**< Supports hardware volume control */ + PA_SOURCE_LATENCY = 2 /**< Supports latency querying */ +} pa_source_flags_t; + +/** A generic free() like callback prototype */ +typedef void (*pa_free_cb_t)(void *p); + +PA_C_DECL_END + +#endif diff --git a/src/pulse/error.c b/src/pulse/error.c new file mode 100644 index 00000000..7bd31ead --- /dev/null +++ b/src/pulse/error.c @@ -0,0 +1,66 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include +#include + +#include "error.h" + +const char*pa_strerror(int error) { + + static const char* const errortab[PA_ERR_MAX] = { + [PA_OK] = "OK", + [PA_ERR_ACCESS] = "Access denied", + [PA_ERR_COMMAND] = "Unknown command", + [PA_ERR_INVALID] = "Invalid argument", + [PA_ERR_EXIST] = "Entity exists", + [PA_ERR_NOENTITY] = "No such entity", + [PA_ERR_CONNECTIONREFUSED] = "Connection refused", + [PA_ERR_PROTOCOL] = "Protocol error", + [PA_ERR_TIMEOUT] = "Timeout", + [PA_ERR_AUTHKEY] = "No authorization key", + [PA_ERR_INTERNAL] = "Internal error", + [PA_ERR_CONNECTIONTERMINATED] = "Connection terminated", + [PA_ERR_KILLED] = "Entity killed", + [PA_ERR_INVALIDSERVER] = "Invalid server", + [PA_ERR_MODINITFAILED] = "Module initalization failed", + [PA_ERR_BADSTATE] = "Bad state", + [PA_ERR_NODATA] = "No data", + [PA_ERR_VERSION] = "Incompatible protocol version", + [PA_ERR_TOOLARGE] = "Too large" + }; + + if (error < 0 || error >= PA_ERR_MAX) + return NULL; + + return errortab[error]; +} diff --git a/src/pulse/error.h b/src/pulse/error.h new file mode 100644 index 00000000..bfce023c --- /dev/null +++ b/src/pulse/error.h @@ -0,0 +1,38 @@ +#ifndef fooerrorhfoo +#define fooerrorhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/** \file + * Error management */ + +PA_C_DECL_BEGIN + +/** Return a human readable error message for the specified numeric error code */ +const char* pa_strerror(int error); + +PA_C_DECL_END + +#endif diff --git a/src/pulse/glib-mainloop.c b/src/pulse/glib-mainloop.c new file mode 100644 index 00000000..25848ece --- /dev/null +++ b/src/pulse/glib-mainloop.c @@ -0,0 +1,541 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include +#include + +#include "glib.h" +#include "glib-mainloop.h" + +struct pa_io_event { + pa_glib_mainloop *mainloop; + int dead; + GIOChannel *io_channel; + GSource *source; + GIOCondition io_condition; + int fd; + void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); + void *userdata; + void (*destroy_callback) (pa_mainloop_api *m, pa_io_event *e, void *userdata); + pa_io_event *next, *prev; +}; + +struct pa_time_event { + pa_glib_mainloop *mainloop; + int dead; + GSource *source; + struct timeval timeval; + void (*callback) (pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata); + void *userdata; + void (*destroy_callback) (pa_mainloop_api *m, pa_time_event*e, void *userdata); + pa_time_event *next, *prev; +}; + +struct pa_defer_event { + pa_glib_mainloop *mainloop; + int dead; + GSource *source; + void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata); + void *userdata; + void (*destroy_callback) (pa_mainloop_api *m, pa_defer_event*e, void *userdata); + pa_defer_event *next, *prev; +}; + +struct pa_glib_mainloop { + GMainContext *glib_main_context; + pa_mainloop_api api; + GSource *cleanup_source; + pa_io_event *io_events, *dead_io_events; + pa_time_event *time_events, *dead_time_events; + pa_defer_event *defer_events, *dead_defer_events; +}; + +static void schedule_free_dead_events(pa_glib_mainloop *g); + +static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f); + +static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags_t f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata), void *userdata) { + pa_io_event *e; + pa_glib_mainloop *g; + + assert(m && m->userdata && fd >= 0 && callback); + g = m->userdata; + + e = pa_xmalloc(sizeof(pa_io_event)); + e->mainloop = m->userdata; + e->dead = 0; + e->fd = fd; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + + e->io_channel = g_io_channel_unix_new(e->fd); + assert(e->io_channel); + e->source = NULL; + e->io_condition = 0; + + glib_io_enable(e, f); + + e->next = g->io_events; + if (e->next) e->next->prev = e; + g->io_events = e; + e->prev = NULL; + + return e; +} + +/* The callback GLIB calls whenever an IO condition is met */ +static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { + pa_io_event *e = data; + pa_io_event_flags_t f; + assert(source && e && e->io_channel == source); + + f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | + (condition & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) | + (condition & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) | + (condition & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0); + + e->callback(&e->mainloop->api, e, e->fd, f, e->userdata); + return TRUE; +} + +static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { + GIOCondition c; + assert(e && !e->dead); + + c = (f & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | (f & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0); + + if (c == e->io_condition) + return; + + if (e->source) { + g_source_destroy(e->source); + g_source_unref(e->source); + } + + e->source = g_io_create_watch(e->io_channel, c | G_IO_ERR | G_IO_HUP); + assert(e->source); + + g_source_set_callback(e->source, (GSourceFunc) io_cb, e, NULL); + g_source_attach(e->source, e->mainloop->glib_main_context); + g_source_set_priority(e->source, G_PRIORITY_DEFAULT); + + e->io_condition = c; +} + +static void glib_io_free(pa_io_event*e) { + assert(e && !e->dead); + + if (e->source) { + g_source_destroy(e->source); + g_source_unref(e->source); + e->source = NULL; + } + + if (e->prev) + e->prev->next = e->next; + else + e->mainloop->io_events = e->next; + + if (e->next) + e->next->prev = e->prev; + + if ((e->next = e->mainloop->dead_io_events)) + e->next->prev = e; + + e->mainloop->dead_io_events = e; + e->prev = NULL; + + e->dead = 1; + schedule_free_dead_events(e->mainloop); +} + +static void glib_io_set_destroy(pa_io_event*e, void (*callback)(pa_mainloop_api*m, pa_io_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* Time sources */ + +static void glib_time_restart(pa_time_event*e, const struct timeval *tv); + +static pa_time_event* glib_time_new(pa_mainloop_api*m, const struct timeval *tv, void (*callback) (pa_mainloop_api*m, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { + pa_glib_mainloop *g; + pa_time_event *e; + + assert(m && m->userdata && tv && callback); + g = m->userdata; + + e = pa_xmalloc(sizeof(pa_time_event)); + e->mainloop = g; + e->dead = 0; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + e->source = NULL; + + glib_time_restart(e, tv); + + e->next = g->time_events; + if (e->next) e->next->prev = e; + g->time_events = e; + e->prev = NULL; + + return e; +} + +static guint msec_diff(const struct timeval *a, const struct timeval *b) { + guint r; + assert(a && b); + + if (a->tv_sec < b->tv_sec) + return 0; + + if (a->tv_sec == b->tv_sec && a->tv_sec <= b->tv_sec) + return 0; + + r = (a->tv_sec-b->tv_sec)*1000; + + if (a->tv_usec >= b->tv_usec) + r += (a->tv_usec - b->tv_usec) / 1000; + else + r -= (b->tv_usec - a->tv_usec) / 1000; + + return r; +} + +static gboolean time_cb(gpointer data) { + pa_time_event* e = data; + assert(e && e->mainloop && e->source); + + g_source_unref(e->source); + e->source = NULL; + + e->callback(&e->mainloop->api, e, &e->timeval, e->userdata); + return FALSE; +} + +static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { + struct timeval now; + assert(e && e->mainloop && !e->dead); + + pa_gettimeofday(&now); + if (e->source) { + g_source_destroy(e->source); + g_source_unref(e->source); + } + + if (tv) { + e->timeval = *tv; + e->source = g_timeout_source_new(msec_diff(tv, &now)); + assert(e->source); + g_source_set_callback(e->source, time_cb, e, NULL); + g_source_set_priority(e->source, G_PRIORITY_DEFAULT); + g_source_attach(e->source, e->mainloop->glib_main_context); + } else + e->source = NULL; + } + +static void glib_time_free(pa_time_event *e) { + assert(e && e->mainloop && !e->dead); + + if (e->source) { + g_source_destroy(e->source); + g_source_unref(e->source); + e->source = NULL; + } + + if (e->prev) + e->prev->next = e->next; + else + e->mainloop->time_events = e->next; + + if (e->next) + e->next->prev = e->prev; + + if ((e->next = e->mainloop->dead_time_events)) + e->next->prev = e; + + e->mainloop->dead_time_events = e; + e->prev = NULL; + + e->dead = 1; + schedule_free_dead_events(e->mainloop); +} + +static void glib_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*m, pa_time_event*e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* Deferred sources */ + +static void glib_defer_enable(pa_defer_event *e, int b); + +static pa_defer_event* glib_defer_new(pa_mainloop_api*m, void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata), void *userdata) { + pa_defer_event *e; + pa_glib_mainloop *g; + + assert(m && m->userdata && callback); + g = m->userdata; + + e = pa_xmalloc(sizeof(pa_defer_event)); + e->mainloop = g; + e->dead = 0; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + e->source = NULL; + + glib_defer_enable(e, 1); + + e->next = g->defer_events; + if (e->next) e->next->prev = e; + g->defer_events = e; + e->prev = NULL; + return e; +} + +static gboolean idle_cb(gpointer data) { + pa_defer_event* e = data; + assert(e && e->mainloop && e->source); + + e->callback(&e->mainloop->api, e, e->userdata); + return TRUE; +} + +static void glib_defer_enable(pa_defer_event *e, int b) { + assert(e && e->mainloop); + + if (e->source && !b) { + g_source_destroy(e->source); + g_source_unref(e->source); + e->source = NULL; + } else if (!e->source && b) { + e->source = g_idle_source_new(); + assert(e->source); + g_source_set_callback(e->source, idle_cb, e, NULL); + g_source_attach(e->source, e->mainloop->glib_main_context); + g_source_set_priority(e->source, G_PRIORITY_HIGH); + } +} + +static void glib_defer_free(pa_defer_event *e) { + assert(e && e->mainloop && !e->dead); + + if (e->source) { + g_source_destroy(e->source); + g_source_unref(e->source); + e->source = NULL; + } + + if (e->prev) + e->prev->next = e->next; + else + e->mainloop->defer_events = e->next; + + if (e->next) + e->next->prev = e->prev; + + if ((e->next = e->mainloop->dead_defer_events)) + e->next->prev = e; + + e->mainloop->dead_defer_events = e; + e->prev = NULL; + + e->dead = 1; + schedule_free_dead_events(e->mainloop); +} + +static void glib_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api *m, pa_defer_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* quit() */ + +static void glib_quit(pa_mainloop_api*a, PA_GCC_UNUSED int retval) { + pa_glib_mainloop *g; + assert(a && a->userdata); + g = a->userdata; + + /* NOOP */ +} + +static const pa_mainloop_api vtable = { + .userdata = NULL, + + .io_new = glib_io_new, + .io_enable = glib_io_enable, + .io_free = glib_io_free, + .io_set_destroy= glib_io_set_destroy, + + .time_new = glib_time_new, + .time_restart = glib_time_restart, + .time_free = glib_time_free, + .time_set_destroy = glib_time_set_destroy, + + .defer_new = glib_defer_new, + .defer_enable = glib_defer_enable, + .defer_free = glib_defer_free, + .defer_set_destroy = glib_defer_set_destroy, + + .quit = glib_quit, +}; + +pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) { + pa_glib_mainloop *g; + + g = pa_xmalloc(sizeof(pa_glib_mainloop)); + if (c) { + g->glib_main_context = c; + g_main_context_ref(c); + } else + g->glib_main_context = g_main_context_default(); + + g->api = vtable; + g->api.userdata = g; + + g->io_events = g->dead_io_events = NULL; + g->time_events = g->dead_time_events = NULL; + g->defer_events = g->dead_defer_events = NULL; + + g->cleanup_source = NULL; + return g; +} + +static void free_io_events(pa_io_event *e) { + while (e) { + pa_io_event *r = e; + e = r->next; + + if (r->source) { + g_source_destroy(r->source); + g_source_unref(r->source); + } + + if (r->io_channel) + g_io_channel_unref(r->io_channel); + + if (r->destroy_callback) + r->destroy_callback(&r->mainloop->api, r, r->userdata); + + pa_xfree(r); + } +} + +static void free_time_events(pa_time_event *e) { + while (e) { + pa_time_event *r = e; + e = r->next; + + if (r->source) { + g_source_destroy(r->source); + g_source_unref(r->source); + } + + if (r->destroy_callback) + r->destroy_callback(&r->mainloop->api, r, r->userdata); + + pa_xfree(r); + } +} + +static void free_defer_events(pa_defer_event *e) { + while (e) { + pa_defer_event *r = e; + e = r->next; + + if (r->source) { + g_source_destroy(r->source); + g_source_unref(r->source); + } + + if (r->destroy_callback) + r->destroy_callback(&r->mainloop->api, r, r->userdata); + + pa_xfree(r); + } +} + +void pa_glib_mainloop_free(pa_glib_mainloop* g) { + assert(g); + + free_io_events(g->io_events); + free_io_events(g->dead_io_events); + free_defer_events(g->defer_events); + free_defer_events(g->dead_defer_events); + free_time_events(g->time_events); + free_time_events(g->dead_time_events); + + if (g->cleanup_source) { + g_source_destroy(g->cleanup_source); + g_source_unref(g->cleanup_source); + } + + g_main_context_unref(g->glib_main_context); + pa_xfree(g); +} + +pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) { + assert(g); + return &g->api; +} + +static gboolean free_dead_events(gpointer p) { + pa_glib_mainloop *g = p; + assert(g); + + free_io_events(g->dead_io_events); + free_defer_events(g->dead_defer_events); + free_time_events(g->dead_time_events); + + g->dead_io_events = NULL; + g->dead_defer_events = NULL; + g->dead_time_events = NULL; + + g_source_destroy(g->cleanup_source); + g_source_unref(g->cleanup_source); + g->cleanup_source = NULL; + + return FALSE; +} + +static void schedule_free_dead_events(pa_glib_mainloop *g) { + assert(g && g->glib_main_context); + + if (g->cleanup_source) + return; + + g->cleanup_source = g_idle_source_new(); + assert(g->cleanup_source); + g_source_set_callback(g->cleanup_source, free_dead_events, g, NULL); + g_source_attach(g->cleanup_source, g->glib_main_context); +} diff --git a/src/pulse/glib-mainloop.h b/src/pulse/glib-mainloop.h new file mode 100644 index 00000000..75de1cc7 --- /dev/null +++ b/src/pulse/glib-mainloop.h @@ -0,0 +1,66 @@ +#ifndef fooglibmainloophfoo +#define fooglibmainloophfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include + +/** \page glib-mainloop GLIB Main Loop Bindings + * + * \section overv_sec Overview + * + * The GLIB main loop bindings are extremely easy to use. All that is + * required is to create a pa_glib_mainloop object using + * pa_glib_mainloop_new(). When the main loop abstraction is needed, it is + * provided by pa_glib_mainloop_get_api(). + * + */ + +/** \file + * GLIB main loop support */ + +PA_C_DECL_BEGIN + +/** An opaque GLIB main loop object */ +typedef struct pa_glib_mainloop pa_glib_mainloop; + +/** Create a new GLIB main loop object for the specified GLIB main + * loop context. The GLIB 2.0 version takes an argument c for the + * GMainContext to use. If c is NULL the default context is used. */ +#if GLIB_MAJOR_VERSION >= 2 +pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c); +#else +pa_glib_mainloop *pa_glib_mainloop_new(void); +#endif + +/** Free the GLIB main loop object */ +void pa_glib_mainloop_free(pa_glib_mainloop* g); + +/** Return the abstract main loop API vtable for the GLIB main loop object */ +pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g); + +PA_C_DECL_END + +#endif diff --git a/src/pulse/glib12-mainloop.c b/src/pulse/glib12-mainloop.c new file mode 100644 index 00000000..ebaf87fc --- /dev/null +++ b/src/pulse/glib12-mainloop.c @@ -0,0 +1,503 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include +#include + +#include "glib-mainloop.h" + +/* A mainloop implementation based on GLIB 1.2 */ + +struct pa_io_event { + pa_glib_mainloop *mainloop; + int dead; + GIOChannel *io_channel; + guint source; + GIOCondition io_condition; + int fd; + void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); + void *userdata; + void (*destroy_callback) (pa_mainloop_api *m, pa_io_event*e, void *userdata); + pa_io_event *next, *prev; +}; + +struct pa_time_event { + pa_glib_mainloop *mainloop; + int dead; + guint source; + struct timeval timeval; + void (*callback) (pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata); + void *userdata; + void (*destroy_callback) (pa_mainloop_api *m, pa_time_event*e, void *userdata); + pa_time_event *next, *prev; +}; + +struct pa_defer_event { + pa_glib_mainloop *mainloop; + int dead; + guint source; + void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata); + void *userdata; + void (*destroy_callback) (pa_mainloop_api *m, pa_defer_event*e, void *userdata); + pa_defer_event *next, *prev; +}; + +struct pa_glib_mainloop { + pa_mainloop_api api; + guint cleanup_source; + pa_io_event *io_events, *dead_io_events; + pa_time_event *time_events, *dead_time_events; + pa_defer_event *defer_events, *dead_defer_events; +}; + +static void schedule_free_dead_events(pa_glib_mainloop *g); + +static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f); + +static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags_t f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata), void *userdata) { + pa_io_event *e; + pa_glib_mainloop *g; + + assert(m && m->userdata && fd >= 0 && callback); + g = m->userdata; + + e = pa_xmalloc(sizeof(pa_io_event)); + e->mainloop = m->userdata; + e->dead = 0; + e->fd = fd; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + + e->io_channel = g_io_channel_unix_new(e->fd); + assert(e->io_channel); + e->source = (guint) -1; + e->io_condition = 0; + + glib_io_enable(e, f); + + e->next = g->io_events; + if (e->next) e->next->prev = e; + g->io_events = e; + e->prev = NULL; + + return e; +} + +static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { + pa_io_event *e = data; + pa_io_event_flags_t f; + assert(source && e && e->io_channel == source); + + f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | + (condition & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) | + (condition & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) | + (condition & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0); + + e->callback(&e->mainloop->api, e, e->fd, f, e->userdata); + return TRUE; +} + +static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { + GIOCondition c; + assert(e && !e->dead); + + c = (f & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | (f & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0); + + if (c == e->io_condition) + return; + + if (e->source != (guint) -1) + g_source_remove(e->source); + + e->source = g_io_add_watch_full(e->io_channel, G_PRIORITY_DEFAULT, c | G_IO_ERR | G_IO_HUP, io_cb, e, NULL); + assert(e->source != (guint) -1); + e->io_condition = c; +} + +static void glib_io_free(pa_io_event*e) { + assert(e && !e->dead); + + if (e->source != (guint) -1) { + g_source_remove(e->source); + e->source = (guint) -1; + } + + if (e->prev) + e->prev->next = e->next; + else + e->mainloop->io_events = e->next; + + if (e->next) + e->next->prev = e->prev; + + if ((e->next = e->mainloop->dead_io_events)) + e->next->prev = e; + + e->mainloop->dead_io_events = e; + e->prev = NULL; + + e->dead = 1; + schedule_free_dead_events(e->mainloop); +} + +static void glib_io_set_destroy(pa_io_event*e, void (*callback)(pa_mainloop_api*m, pa_io_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* Time sources */ + +static void glib_time_restart(pa_time_event*e, const struct timeval *tv); + +static pa_time_event* glib_time_new(pa_mainloop_api*m, const struct timeval *tv, void (*callback) (pa_mainloop_api*m, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { + pa_glib_mainloop *g; + pa_time_event *e; + + assert(m && m->userdata && tv && callback); + g = m->userdata; + + e = pa_xmalloc(sizeof(pa_time_event)); + e->mainloop = g; + e->dead = 0; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + e->source = (guint) -1; + + glib_time_restart(e, tv); + + e->next = g->time_events; + if (e->next) e->next->prev = e; + g->time_events = e; + e->prev = NULL; + + return e; +} + +static guint msec_diff(const struct timeval *a, const struct timeval *b) { + guint r; + assert(a && b); + + if (a->tv_sec < b->tv_sec) + return 0; + + if (a->tv_sec == b->tv_sec && a->tv_sec <= b->tv_sec) + return 0; + + r = (a->tv_sec-b->tv_sec)*1000; + + if (a->tv_usec >= b->tv_usec) + r += (a->tv_usec - b->tv_usec) / 1000; + else + r -= (b->tv_usec - a->tv_usec) / 1000; + + return r; +} + +static gboolean time_cb(gpointer data) { + pa_time_event* e = data; + assert(e && e->mainloop && e->source != (guint) -1); + + g_source_remove(e->source); + e->source = (guint) -1; + + e->callback(&e->mainloop->api, e, &e->timeval, e->userdata); + return FALSE; +} + +static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { + struct timeval now; + assert(e && e->mainloop && !e->dead); + + pa_gettimeofday(&now); + if (e->source != (guint) -1) + g_source_remove(e->source); + + if (tv) { + e->timeval = *tv; + e->source = g_timeout_add_full(G_PRIORITY_DEFAULT, msec_diff(tv, &now), time_cb, e, NULL); + assert(e->source != (guint) -1); + } else + e->source = (guint) -1; + } + +static void glib_time_free(pa_time_event *e) { + assert(e && e->mainloop && !e->dead); + + if (e->source != (guint) -1) { + g_source_remove(e->source); + e->source = (guint) -1; + } + + if (e->prev) + e->prev->next = e->next; + else + e->mainloop->time_events = e->next; + + if (e->next) + e->next->prev = e->prev; + + if ((e->next = e->mainloop->dead_time_events)) + e->next->prev = e; + + e->mainloop->dead_time_events = e; + e->prev = NULL; + + e->dead = 1; + schedule_free_dead_events(e->mainloop); +} + +static void glib_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*m, pa_time_event*e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* Deferred sources */ + +static void glib_defer_enable(pa_defer_event *e, int b); + +static pa_defer_event* glib_defer_new(pa_mainloop_api*m, void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata), void *userdata) { + pa_defer_event *e; + pa_glib_mainloop *g; + + assert(m && m->userdata && callback); + g = m->userdata; + + e = pa_xmalloc(sizeof(pa_defer_event)); + e->mainloop = g; + e->dead = 0; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + e->source = (guint) -1; + + glib_defer_enable(e, 1); + + e->next = g->defer_events; + if (e->next) e->next->prev = e; + g->defer_events = e; + e->prev = NULL; + return e; +} + +static gboolean idle_cb(gpointer data) { + pa_defer_event* e = data; + assert(e && e->mainloop && e->source != (guint) -1); + + e->callback(&e->mainloop->api, e, e->userdata); + return TRUE; +} + +static void glib_defer_enable(pa_defer_event *e, int b) { + assert(e && e->mainloop); + + if (e->source != (guint) -1 && !b) { + g_source_remove(e->source); + e->source = (guint) -1; + } else if (e->source == (guint) -1 && b) { + e->source = g_idle_add_full(G_PRIORITY_HIGH, idle_cb, e, NULL); + assert(e->source != (guint) -1); + } +} + +static void glib_defer_free(pa_defer_event *e) { + assert(e && e->mainloop && !e->dead); + + if (e->source != (guint) -1) { + g_source_remove(e->source); + e->source = (guint) -1; + } + + if (e->prev) + e->prev->next = e->next; + else + e->mainloop->defer_events = e->next; + + if (e->next) + e->next->prev = e->prev; + + if ((e->next = e->mainloop->dead_defer_events)) + e->next->prev = e; + + e->mainloop->dead_defer_events = e; + e->prev = NULL; + + e->dead = 1; + schedule_free_dead_events(e->mainloop); +} + +static void glib_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api *m, pa_defer_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* quit() */ + +static void glib_quit(pa_mainloop_api*a, PA_GCC_UNUSED int retval) { + pa_glib_mainloop *g; + assert(a && a->userdata); + g = a->userdata; + + /* NOOP */ +} + +static const pa_mainloop_api vtable = { + .userdata = NULL, + + .io_new = glib_io_new, + .io_enable = glib_io_enable, + .io_free = glib_io_free, + .io_set_destroy= glib_io_set_destroy, + + .time_new = glib_time_new, + .time_restart = glib_time_restart, + .time_free = glib_time_free, + .time_set_destroy = glib_time_set_destroy, + + .defer_new = glib_defer_new, + .defer_enable = glib_defer_enable, + .defer_free = glib_defer_free, + .defer_set_destroy = glib_defer_set_destroy, + + .quit = glib_quit, +}; + +pa_glib_mainloop *pa_glib_mainloop_new(void) { + pa_glib_mainloop *g; + + g = pa_xmalloc(sizeof(pa_glib_mainloop)); + + g->api = vtable; + g->api.userdata = g; + + g->io_events = g->dead_io_events = NULL; + g->time_events = g->dead_time_events = NULL; + g->defer_events = g->dead_defer_events = NULL; + + g->cleanup_source = (guint) -1; + return g; +} + +static void free_io_events(pa_io_event *e) { + while (e) { + pa_io_event *r = e; + e = r->next; + + if (r->source != (guint) -1) + g_source_remove(r->source); + + if (r->io_channel) + g_io_channel_unref(r->io_channel); + + if (r->destroy_callback) + r->destroy_callback(&r->mainloop->api, r, r->userdata); + + pa_xfree(r); + } +} + +static void free_time_events(pa_time_event *e) { + while (e) { + pa_time_event *r = e; + e = r->next; + + if (r->source != (guint) -1) + g_source_remove(r->source); + + if (r->destroy_callback) + r->destroy_callback(&r->mainloop->api, r, r->userdata); + + pa_xfree(r); + } +} + +static void free_defer_events(pa_defer_event *e) { + while (e) { + pa_defer_event *r = e; + e = r->next; + + if (r->source != (guint) -1) + g_source_remove(r->source); + + if (r->destroy_callback) + r->destroy_callback(&r->mainloop->api, r, r->userdata); + + pa_xfree(r); + } +} + +void pa_glib_mainloop_free(pa_glib_mainloop* g) { + assert(g); + + free_io_events(g->io_events); + free_io_events(g->dead_io_events); + free_defer_events(g->defer_events); + free_defer_events(g->dead_defer_events); + free_time_events(g->time_events); + free_time_events(g->dead_time_events); + + if (g->cleanup_source != (guint) -1) + g_source_remove(g->cleanup_source); + + pa_xfree(g); +} + +pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) { + assert(g); + return &g->api; +} + +static gboolean free_dead_events(gpointer p) { + pa_glib_mainloop *g = p; + assert(g); + + free_io_events(g->dead_io_events); + free_defer_events(g->dead_defer_events); + free_time_events(g->dead_time_events); + + g->dead_io_events = NULL; + g->dead_defer_events = NULL; + g->dead_time_events = NULL; + + g_source_remove(g->cleanup_source); + g->cleanup_source = (guint) -1; + + return FALSE; +} + +static void schedule_free_dead_events(pa_glib_mainloop *g) { + assert(g); + + if (g->cleanup_source != (guint) -1) + return; + + g->cleanup_source = g_idle_add_full(G_PRIORITY_HIGH, free_dead_events, g, NULL); +} diff --git a/src/pulse/internal.h b/src/pulse/internal.h new file mode 100644 index 00000000..96028d83 --- /dev/null +++ b/src/pulse/internal.h @@ -0,0 +1,210 @@ +#ifndef foointernalhfoo +#define foointernalhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "client-conf.h" + +#define DEFAULT_TIMEOUT (10) + +struct pa_context { + int ref; + + char *name; + pa_mainloop_api* mainloop; + + pa_socket_client *client; + pa_pstream *pstream; + pa_pdispatch *pdispatch; + + pa_dynarray *record_streams, *playback_streams; + PA_LLIST_HEAD(pa_stream, streams); + PA_LLIST_HEAD(pa_operation, operations); + + uint32_t version; + uint32_t ctag; + uint32_t csyncid; + uint32_t error; + pa_context_state_t state; + + pa_context_notify_cb_t state_callback; + void *state_userdata; + + pa_context_subscribe_cb_t subscribe_callback; + void *subscribe_userdata; + + pa_memblock_stat *memblock_stat; + + int local; + int do_autospawn; + int autospawn_lock_fd; + pa_spawn_api spawn_api; + + pa_strlist *server_list; + + char *server; + + pa_client_conf *conf; +}; + +#define PA_MAX_WRITE_INDEX_CORRECTIONS 10 + +typedef struct pa_index_correction { + uint32_t tag; + int valid; + int64_t value; + int absolute, corrupt; +} pa_index_correction; + +struct pa_stream { + int ref; + pa_context *context; + pa_mainloop_api *mainloop; + PA_LLIST_FIELDS(pa_stream); + + char *name; + pa_buffer_attr buffer_attr; + pa_sample_spec sample_spec; + pa_channel_map channel_map; + pa_stream_flags_t flags; + uint32_t channel; + uint32_t syncid; + int channel_valid; + uint32_t device_index; + pa_stream_direction_t direction; + pa_stream_state_t state; + + uint32_t requested_bytes; + + pa_memchunk peek_memchunk; + pa_memblockq *record_memblockq; + + int corked; + + /* Store latest latency info */ + pa_timing_info timing_info; + int timing_info_valid; + + /* Use to make sure that time advances monotonically */ + pa_usec_t previous_time; + + /* time updates with tags older than these are invalid */ + uint32_t write_index_not_before; + uint32_t read_index_not_before; + + /* Data about individual timing update correctoins */ + pa_index_correction write_index_corrections[PA_MAX_WRITE_INDEX_CORRECTIONS]; + int current_write_index_correction; + + /* Latency interpolation stuff */ + pa_time_event *auto_timing_update_event; + int auto_timing_update_requested; + + pa_usec_t cached_time; + int cached_time_valid; + + /* Callbacks */ + pa_stream_notify_cb_t state_callback; + void *state_userdata; + pa_stream_request_cb_t read_callback; + void *read_userdata; + pa_stream_request_cb_t write_callback; + void *write_userdata; + pa_stream_notify_cb_t overflow_callback; + void *overflow_userdata; + pa_stream_notify_cb_t underflow_callback; + void *underflow_userdata; + pa_stream_notify_cb_t latency_update_callback; + void *latency_update_userdata; +}; + +typedef void (*pa_operation_cb_t)(void); + +struct pa_operation { + int ref; + pa_context *context; + pa_stream *stream; + + PA_LLIST_FIELDS(pa_operation); + + pa_operation_state_t state; + void *userdata; + pa_operation_cb_t callback; +}; + +void pa_command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); + +pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t callback, void *userdata); +void pa_operation_done(pa_operation *o); + +void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); + +void pa_context_fail(pa_context *c, int error); +int pa_context_set_error(pa_context *c, int error); +void pa_context_set_state(pa_context *c, pa_context_state_t st); +int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t); +pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, void (*internal_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata), void (*cb)(void), void *userdata); + +void pa_stream_set_state(pa_stream *s, pa_stream_state_t st); + +pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag); + +#define PA_CHECK_VALIDITY(context, expression, error) do { \ + if (!(expression)) \ + return -pa_context_set_error((context), (error)); \ +} while(0) + + +#define PA_CHECK_VALIDITY_RETURN_ANY(context, expression, error, value) do { \ + if (!(expression)) { \ + pa_context_set_error((context), (error)); \ + return value; \ + } \ +} while(0) + +#define PA_CHECK_VALIDITY_RETURN_NULL(context, expression, error) PA_CHECK_VALIDITY_RETURN_ANY(context, expression, error, NULL) + + +#endif diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c new file mode 100644 index 00000000..ed40c53d --- /dev/null +++ b/src/pulse/introspect.c @@ -0,0 +1,1240 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include +#include + +#include "internal.h" + +#include "introspect.h" + +/*** Statistics ***/ + +static void context_stat_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + pa_stat_info i, *p = &i; + + assert(pd); + assert(o); + assert(o->ref >= 1); + + if (!o->context) + goto finish; + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + p = NULL; + } else if (pa_tagstruct_getu32(t, &i.memblock_total) < 0 || + pa_tagstruct_getu32(t, &i.memblock_total_size) < 0 || + pa_tagstruct_getu32(t, &i.memblock_allocated) < 0 || + pa_tagstruct_getu32(t, &i.memblock_allocated_size) < 0 || + pa_tagstruct_getu32(t, &i.scache_size) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERR_PROTOCOL); + goto finish; + } + + if (o->callback) { + pa_stat_info_cb_t cb = (pa_stat_info_cb_t) o->callback; + cb(o->context, p, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_stat(pa_context *c, pa_stat_info_cb_t cb, void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_STAT, context_stat_callback, (pa_operation_cb_t) cb, userdata); +} + +/*** Server Info ***/ + +static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + pa_server_info i, *p = &i; + + assert(pd); + assert(o); + assert(o->ref >= 1); + + if (!o->context) + goto finish; + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + p = NULL; + } else if (pa_tagstruct_gets(t, &i.server_name) < 0 || + pa_tagstruct_gets(t, &i.server_version) < 0 || + pa_tagstruct_gets(t, &i.user_name) < 0 || + pa_tagstruct_gets(t, &i.host_name) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_gets(t, &i.default_sink_name) < 0 || + pa_tagstruct_gets(t, &i.default_source_name) < 0 || + pa_tagstruct_getu32(t, &i.cookie) < 0 || + !pa_tagstruct_eof(t)) { + + pa_context_fail(o->context, PA_ERR_PROTOCOL); + goto finish; + } + + if (o->callback) { + pa_server_info_cb_t cb = (pa_server_info_cb_t) o->callback; + cb(o->context, p, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_server_info(pa_context *c, pa_server_info_cb_t cb, void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SERVER_INFO, context_get_server_info_callback, (pa_operation_cb_t) cb, userdata); +} + +/*** Sink Info ***/ + +static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eol = 1; + + assert(pd); + assert(o); + assert(o->ref >= 1); + + if (!o->context) + goto finish; + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eol = -1; + } else { + uint32_t flags; + + while (!pa_tagstruct_eof(t)) { + pa_sink_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_get_cvolume(t, &i.volume) < 0 || + pa_tagstruct_get_boolean(t, &i.mute) < 0 || + pa_tagstruct_getu32(t, &i.monitor_source) < 0 || + pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || + pa_tagstruct_get_usec(t, &i.latency) < 0 || + pa_tagstruct_gets(t, &i.driver) < 0 || + pa_tagstruct_getu32(t, &flags) < 0) { + + pa_context_fail(o->context, PA_ERR_PROTOCOL); + goto finish; + } + + i.flags = (pa_sink_flags_t) flags; + + if (o->callback) { + pa_sink_info_cb_t cb = (pa_sink_info_cb_t) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + pa_sink_info_cb_t cb = (pa_sink_info_cb_t) o->callback; + cb(o->context, NULL, eol, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_sink_info_list(pa_context *c, pa_sink_info_cb_t cb, void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INFO_LIST, context_get_sink_info_callback, (pa_operation_cb_t) cb, userdata); +} + +pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, pa_sink_info_cb_t cb, void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_GET_SINK_INFO, &tag); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, pa_sink_info_cb_t cb, void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_GET_SINK_INFO, &tag); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +/*** Source info ***/ + +static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eol = 1; + + assert(pd); + assert(o); + assert(o->ref >= 1); + + if (!o->context) + goto finish; + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eol = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_source_info i; + uint32_t flags; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_get_cvolume(t, &i.volume) < 0 || + pa_tagstruct_get_boolean(t, &i.mute) < 0 || + pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || + pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 || + pa_tagstruct_get_usec(t, &i.latency) < 0 || + pa_tagstruct_gets(t, &i.driver) < 0 || + pa_tagstruct_getu32(t, &flags) < 0) { + + pa_context_fail(o->context, PA_ERR_PROTOCOL); + goto finish; + } + + i.flags = (pa_source_flags_t) flags; + + if (o->callback) { + pa_source_info_cb_t cb = (pa_source_info_cb_t) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + pa_source_info_cb_t cb = (pa_source_info_cb_t) o->callback; + cb(o->context, NULL, eol, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_source_info_list(pa_context *c, pa_source_info_cb_t cb, void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_INFO_LIST, context_get_source_info_callback, (pa_operation_cb_t) cb, userdata); +} + +pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, pa_source_info_cb_t cb, void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_GET_SOURCE_INFO, &tag); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_GET_SOURCE_INFO, &tag); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +/*** Client info ***/ + +static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eol = 1; + + assert(pd); + assert(o); + assert(o->ref >= 1); + + if (!o->context) + goto finish; + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eol = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_client_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_gets(t, &i.driver) < 0 ) { + pa_context_fail(o->context, PA_ERR_PROTOCOL); + goto finish; + } + + if (o->callback) { + pa_client_info_cb_t cb = (pa_client_info_cb_t) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + pa_client_info_cb_t cb = (pa_client_info_cb_t) o->callback; + cb(o->context, NULL, eol, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, pa_client_info_cb_t cb, void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_GET_CLIENT_INFO, &tag); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_get_client_info_list(pa_context *c, pa_client_info_cb_t cb, void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_CLIENT_INFO_LIST, context_get_client_info_callback, (pa_operation_cb_t) cb, userdata); +} + +/*** Module info ***/ + +static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eol = 1; + + assert(pd); + assert(o); + assert(o->ref >= 1); + + if (!o->context) + goto finish; + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eol = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_module_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.argument) < 0 || + pa_tagstruct_getu32(t, &i.n_used) < 0 || + pa_tagstruct_get_boolean(t, &i.auto_unload) < 0) { + pa_context_fail(o->context, PA_ERR_PROTOCOL); + goto finish; + } + + if (o->callback) { + pa_module_info_cb_t cb = (pa_module_info_cb_t) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + pa_module_info_cb_t cb = (pa_module_info_cb_t) o->callback; + cb(o->context, NULL, eol, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_info_cb_t cb, void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_GET_MODULE_INFO, &tag); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_get_module_info_list(pa_context *c, pa_module_info_cb_t cb, void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_MODULE_INFO_LIST, context_get_module_info_callback, (pa_operation_cb_t) cb, userdata); +} + +/*** Sink input info ***/ + +static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eol = 1; + + assert(pd); + assert(o); + assert(o->ref >= 1); + + if (!o->context) + goto finish; + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eol = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_sink_input_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.client) < 0 || + pa_tagstruct_getu32(t, &i.sink) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || + pa_tagstruct_get_cvolume(t, &i.volume) < 0 || + pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || + pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || + pa_tagstruct_gets(t, &i.resample_method) < 0 || + pa_tagstruct_gets(t, &i.driver) < 0) { + + pa_context_fail(o->context, PA_ERR_PROTOCOL); + goto finish; + } + + if (o->callback) { + pa_sink_input_info_cb_t cb = (pa_sink_input_info_cb_t) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + pa_sink_input_info_cb_t cb = (pa_sink_input_info_cb_t) o->callback; + cb(o->context, NULL, eol, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_GET_SINK_INPUT_INFO, &tag); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_input_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_get_sink_input_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INPUT_INFO_LIST, context_get_sink_input_info_callback, (pa_operation_cb_t) cb, userdata); +} + +/*** Source output info ***/ + +static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eol = 1; + + assert(pd); + assert(o); + assert(o->ref >= 1); + + if (!o->context) + goto finish; + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eol = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_source_output_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + pa_tagstruct_getu32(t, &i.client) < 0 || + pa_tagstruct_getu32(t, &i.source) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || + pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || + pa_tagstruct_get_usec(t, &i.source_usec) < 0 || + pa_tagstruct_gets(t, &i.resample_method) < 0 || + pa_tagstruct_gets(t, &i.driver) < 0) { + + pa_context_fail(o->context, PA_ERR_PROTOCOL); + goto finish; + } + + if (o->callback) { + pa_source_output_info_cb_t cb = (pa_source_output_info_cb_t) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + pa_source_output_info_cb_t cb = (pa_source_output_info_cb_t) o->callback; + cb(o->context, NULL, eol, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, pa_source_output_info_cb_t cb, void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO, &tag); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_output_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_get_source_output_info_list(pa_context *c, pa_source_output_info_cb_t cb, void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, context_get_source_output_info_callback, (pa_operation_cb_t) cb, userdata); +} + +/*** Volume manipulation ***/ + +pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(volume); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_VOLUME, &tag); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_tagstruct_put_cvolume(t, volume); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(name); + assert(volume); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_VOLUME, &tag); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_tagstruct_put_cvolume(t, volume); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_MUTE, &tag); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_tagstruct_put_boolean(t, mute); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(name); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_MUTE, &tag); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_tagstruct_put_boolean(t, mute); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(volume); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_INPUT_VOLUME, &tag); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_put_cvolume(t, volume); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(volume); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_VOLUME, &tag); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_tagstruct_put_cvolume(t, volume); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(name); + assert(volume); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_VOLUME, &tag); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_tagstruct_put_cvolume(t, volume); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_MUTE, &tag); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_tagstruct_put_boolean(t, mute); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(name); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_MUTE, &tag); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_tagstruct_put_boolean(t, mute); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +/** Sample Cache **/ + +static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eol = 1; + + assert(pd); + assert(o); + assert(o->ref >= 1); + + if (!o->context) + goto finish; + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eol = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_sample_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_get_cvolume(t, &i.volume) < 0 || + pa_tagstruct_get_usec(t, &i.duration) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || + pa_tagstruct_getu32(t, &i.bytes) < 0 || + pa_tagstruct_get_boolean(t, &i.lazy) < 0 || + pa_tagstruct_gets(t, &i.filename) < 0) { + + pa_context_fail(o->context, PA_ERR_PROTOCOL); + goto finish; + } + + if (o->callback) { + pa_sample_info_cb_t cb = (pa_sample_info_cb_t) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + pa_sample_info_cb_t cb = (pa_sample_info_cb_t) o->callback; + cb(o->context, NULL, eol, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, pa_sample_info_cb_t cb, void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_GET_SAMPLE_INFO, &tag); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, pa_sample_info_cb_t cb, void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_GET_SAMPLE_INFO, &tag); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_get_sample_info_list(pa_context *c, pa_sample_info_cb_t cb, void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SAMPLE_INFO_LIST, context_get_sample_info_callback, (pa_operation_cb_t) cb, userdata); +} + +static pa_operation* command_kill(pa_context *c, uint32_t command, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, command, &tag); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { + return command_kill(c, PA_COMMAND_KILL_CLIENT, idx, cb, userdata); +} + +pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { + return command_kill(c, PA_COMMAND_KILL_SINK_INPUT, idx, cb, userdata); +} + +pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { + return command_kill(c, PA_COMMAND_KILL_SOURCE_OUTPUT, idx, cb, userdata); +} + +static void context_index_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + uint32_t idx; + + assert(pd); + assert(o); + assert(o->ref >= 1); + + if (!o->context) + goto finish; + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + idx = PA_INVALID_INDEX; + } else if (pa_tagstruct_getu32(t, &idx) || + !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERR_PROTOCOL); + goto finish; + } + + if (o->callback) { + pa_context_index_cb_t cb = (pa_context_index_cb_t) o->callback; + cb(o->context, idx, o->userdata); + } + + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, pa_context_index_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_LOAD_MODULE, &tag); + pa_tagstruct_puts(t, name); + pa_tagstruct_puts(t, argument); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_index_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { + return command_kill(c, PA_COMMAND_UNLOAD_MODULE, idx, cb, userdata); +} + +/*** Autoload stuff ***/ + +static void context_get_autoload_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int eol = 1; + + assert(pd); + assert(o); + assert(o->ref >= 1); + + if (!o->context) + goto finish; + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + eol = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + pa_autoload_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_getu32(t, &i.type) < 0 || + pa_tagstruct_gets(t, &i.module) < 0 || + pa_tagstruct_gets(t, &i.argument) < 0) { + pa_context_fail(o->context, PA_ERR_PROTOCOL); + goto finish; + } + + if (o->callback) { + pa_autoload_info_cb_t cb = (pa_autoload_info_cb_t) o->callback; + cb(o->context, &i, 0, o->userdata); + } + } + } + + if (o->callback) { + pa_autoload_info_cb_t cb = (pa_autoload_info_cb_t) o->callback; + cb(o->context, NULL, eol, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_autoload_info_cb_t cb, void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, type == PA_AUTOLOAD_SINK || type == PA_AUTOLOAD_SOURCE, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_GET_AUTOLOAD_INFO, &tag); + pa_tagstruct_puts(t, name); + pa_tagstruct_putu32(t, type); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, pa_autoload_info_cb_t cb, void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + assert(cb); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_GET_AUTOLOAD_INFO, &tag); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_get_autoload_info_list(pa_context *c, pa_autoload_info_cb_t cb, void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, context_get_autoload_info_callback, (pa_operation_cb_t) cb, userdata); +} + +pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, pa_context_index_cb_t cb, void* userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, type == PA_AUTOLOAD_SINK || type == PA_AUTOLOAD_SOURCE, PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, module && *module, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_ADD_AUTOLOAD, &tag); + pa_tagstruct_puts(t, name); + pa_tagstruct_putu32(t, type); + pa_tagstruct_puts(t, module); + pa_tagstruct_puts(t, argument); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_index_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_context_success_cb_t cb, void* userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, type == PA_AUTOLOAD_SINK || type == PA_AUTOLOAD_SOURCE, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_AUTOLOAD, &tag); + pa_tagstruct_puts(t, name); + pa_tagstruct_putu32(t, type); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void* userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_AUTOLOAD, &tag); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h new file mode 100644 index 00000000..8fe218bc --- /dev/null +++ b/src/pulse/introspect.h @@ -0,0 +1,490 @@ +#ifndef foointrospecthfoo +#define foointrospecthfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include +#include +#include +#include + +/** \page introspect Server Query and Control + * + * \section overv_sec Overview + * + * Sometimes it is necessary to query and modify global settings in the + * server. For this, Polypaudio has the introspection API. It can list sinks, + * sources, samples and other aspects of the server. It can also modify the + * attributes of the server that will affect operations on a global level, + * and not just the application's context. + * + * \section query_sec Querying + * + * All querying is done through callbacks. This design is necessary to + * maintain an asynchronous design. The client will request the information + * and some time later, the server will respond with the desired data. + * + * Some objects can have multiple entries at the server. When requesting all + * of these at once, the callback will be called multiple times, once for + * each object. When the list has been exhausted, the callback will be called + * without an information structure and the eol parameter set to a non-zero + * value. + * + * Note that even if a single object is requested, and not the entire list, + * the terminating call will still be made. + * + * If an error occurs, the callback will be called without and information + * structure and eol set to zero. + * + * Data members in the information structures are only valid during the + * duration of the callback. If they are required after the callback is + * finished, a deep copy must be performed. + * + * \subsection server_subsec Server Information + * + * The server can be queried about its name, the environment it's running on + * and the currently active global defaults. Calling + * pa_context_get_server_info() will get access to a pa_server_info structure + * containing all of these. + * + * \subsection memstat_subsec Memory Usage + * + * Statistics about memory usage can be fetched using pa_context_stat(), + * giving a pa_stat_info structure. + * + * \subsection sinksrc_subsec Sinks and Sources + * + * The server can have an arbitrary number of sinks and sources. Each sink + * and source have both an index and a name associated with it. As such + * there are three ways to get access to them: + * + * \li By index - pa_context_get_sink_info_by_index() / + * pa_context_get_source_info_by_index() + * \li By name - pa_context_get_sink_info_by_name() / + * pa_context_get_source_info_by_name() + * \li All - pa_context_get_sink_info_list() / + * pa_context_get_source_info_list() + * + * All three method use the same callback and will provide a pa_sink_info or + * pa_source_info structure. + * + * \subsection siso_subsec Sink Inputs and Source Outputs + * + * Sink inputs and source outputs are the representations of the client ends + * of streams inside the server. I.e. they connect a client stream to one of + * the global sinks or sources. + * + * Sink inputs and source outputs only have an index to identify them. As + * such, there are only two ways to get information about them: + * + * \li By index - pa_context_get_sink_input_info() / + * pa_context_get_source_output_info() + * \li All - pa_context_get_sink_input_info_list() / + * pa_context_get_source_output_info_list() + * + * The structure returned is the pa_sink_input_info or pa_source_output_info + * structure. + * + * \subsection samples_subsec Samples + * + * The list of cached samples can be retrieved from the server. Three methods + * exist for querying the sample cache list: + * + * \li By index - pa_context_get_sample_info_by_index() + * \li By name - pa_context_get_sample_info_by_name() + * \li All - pa_context_get_sample_info_list() + * + * Note that this only retrieves information about the sample, not the sample + * data itself. + * + * \subsection module_subsec Driver Modules + * + * Polypaudio driver modules are identified by index and are retrieved using either + * pa_context_get_module_info() or pa_context_get_module_info_list(). The + * information structure is called pa_module_info. + * + * \subsection autoload_subsec Autoload Entries + * + * Modules can be autoloaded as a result of a client requesting a certain + * sink or source. This mapping between sink/source names and modules can be + * queried from the server: + * + * \li By index - pa_context_get_autoload_info_by_index() + * \li By sink/source name - pa_context_get_autoload_info_by_name() + * \li All - pa_context_get_autoload_info_list() + * + * \subsection client_subsec Clients + * + * Polypaudio clients are also identified by index and are retrieved using + * either pa_context_get_client_info() or pa_context_get_client_info_list(). + * The information structure is called pa_client_info. + * + * \section ctrl_sec Control + * + * Some parts of the server are only possible to read, but most can also be + * modified in different ways. Note that these changes will affect all + * connected clients and not just the one issuing the request. + * + * \subsection sinksrc_subsec Sinks and Sources + * + * The most common change one would want to do to sinks and sources is to + * modify the volume of the audio. Identical to how sinks and sources can + * be queried, there are two ways of identifying them: + * + * \li By index - pa_context_set_sink_volume_by_index() / + * pa_context_set_source_volume_by_index() + * \li By name - pa_context_set_sink_volume_by_name() / + * pa_context_set_source_volume_by_name() + * + * It is also possible to mute a sink or source: + * + * \li By index - pa_context_set_sink_mute_by_index() / + * pa_context_set_source_mute_by_index() + * \li By name - pa_context_set_sink_mute_by_name() / + * pa_context_set_source_mute_by_name() + * + * \subsection siso_subsec Sink Inputs and Source Outputs + * + * If an application desires to modify the volume of just a single stream + * (commonly one of its own streams), this can be done by setting the volume + * of its associated sink input, using pa_context_set_sink_input_volume(). + * + * There is no support for modifying the volume of source outputs. + * + * It is also possible to remove sink inputs and source outputs, terminating + * the streams associated with them: + * + * \li Sink input - pa_context_kill_sink_input() + * \li Source output - pa_context_kill_source_output() + * + * \subsection module_subsec Modules + * + * Server modules can be remotely loaded and unloaded using + * pa_context_load_module() and pa_context_unload_module(). + * + * \subsection autoload_subsec Autoload Entries + * + * New module autoloading rules can be added, and existing can be removed + * using pa_context_add_autoload() and pa_context_remove_autoload_by_index() + * / pa_context_remove_autoload_by_name(). + * + * \subsection client_subsec Clients + * + * The only operation supported on clients, is the possibility of kicking + * them off the server using pa_context_kill_client(). + */ + +/** \file + * + * Routines for daemon introspection. + */ + +PA_C_DECL_BEGIN + +/** Stores information about sinks */ +typedef struct pa_sink_info { + const char *name; /**< Name of the sink */ + uint32_t index; /**< Index of the sink */ + const char *description; /**< Description of this sink */ + pa_sample_spec sample_spec; /**< Sample spec of this sink */ + pa_channel_map channel_map; /**< Channel map \since 0.8 */ + uint32_t owner_module; /**< Index of the owning module of this sink, or PA_INVALID_INDEX */ + pa_cvolume volume; /**< Volume of the sink */ + int mute; /**< Mute switch of the sink \since 0.8 */ + uint32_t monitor_source; /**< Index of the monitor source connected to this sink */ + const char *monitor_source_name; /**< The name of the monitor source */ + pa_usec_t latency; /**< Length of filled playback buffer of this sink */ + const char *driver; /**< Driver name. \since 0.8 */ + pa_sink_flags_t flags; /**< Flags \since 0.8 */ +} pa_sink_info; + +/** Callback prototype for pa_context_get_sink_info_by_name() and friends */ +typedef void (*pa_sink_info_cb_t)(pa_context *c, const pa_sink_info *i, int eol, void *userdata); + +/** Get information about a sink by its name */ +pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, pa_sink_info_cb_t cb, void *userdata); + +/** Get information about a sink by its index */ +pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t id, pa_sink_info_cb_t cb, void *userdata); + +/** Get the complete sink list */ +pa_operation* pa_context_get_sink_info_list(pa_context *c, pa_sink_info_cb_t cb, void *userdata); + +/** Stores information about sources */ +typedef struct pa_source_info { + const char *name ; /**< Name of the source */ + uint32_t index; /**< Index of the source */ + const char *description; /**< Description of this source */ + pa_sample_spec sample_spec; /**< Sample spec of this source */ + pa_channel_map channel_map; /**< Channel map \since 0.8 */ + uint32_t owner_module; /**< Owning module index, or PA_INVALID_INDEX */ + pa_cvolume volume; /**< Volume of the source \since 0.8 */ + int mute; /**< Mute switch of the sink \since 0.8 */ + uint32_t monitor_of_sink; /**< If this is a monitor source the index of the owning sink, otherwise PA_INVALID_INDEX */ + const char *monitor_of_sink_name; /**< Name of the owning sink, or PA_INVALID_INDEX */ + pa_usec_t latency; /**< Length of filled record buffer of this source. \since 0.5 */ + const char *driver; /**< Driver name \since 0.8 */ + pa_source_flags_t flags; /**< Flags \since 0.8 */ +} pa_source_info; + +/** Callback prototype for pa_context_get_source_info_by_name() and friends */ +typedef void (*pa_source_info_cb_t)(pa_context *c, const pa_source_info *i, int eol, void *userdata); + +/** Get information about a source by its name */ +pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata); + +/** Get information about a source by its index */ +pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t id, pa_source_info_cb_t cb, void *userdata); + +/** Get the complete source list */ +pa_operation* pa_context_get_source_info_list(pa_context *c, pa_source_info_cb_t cb, void *userdata); + +/** Server information */ +typedef struct pa_server_info { + const char *user_name; /**< User name of the daemon process */ + const char *host_name; /**< Host name the daemon is running on */ + const char *server_version; /**< Version string of the daemon */ + const char *server_name; /**< Server package name (usually "pulseaudio") */ + pa_sample_spec sample_spec; /**< Default sample specification */ + const char *default_sink_name; /**< Name of default sink. \since 0.4 */ + const char *default_source_name; /**< Name of default sink. \since 0.4*/ + uint32_t cookie; /**< A random cookie for identifying this instance of pulseaudio. \since 0.8 */ +} pa_server_info; + +/** Callback prototype for pa_context_get_server_info() */ +typedef void (*pa_server_info_cb_t) (pa_context *c, const pa_server_info*i, void *userdata); + +/** Get some information about the server */ +pa_operation* pa_context_get_server_info(pa_context *c, pa_server_info_cb_t cb, void *userdata); + +/** Stores information about modules */ +typedef struct pa_module_info { + uint32_t index; /**< Index of the module */ + const char*name, /**< Name of the module */ + *argument; /**< Argument string of the module */ + uint32_t n_used; /**< Usage counter or PA_INVALID_INDEX */ + int auto_unload; /**< Non-zero if this is an autoloaded module */ +} pa_module_info; + +/** Callback prototype for pa_context_get_module_info() and firends*/ +typedef void (*pa_module_info_cb_t) (pa_context *c, const pa_module_info*i, int eol, void *userdata); + +/** Get some information about a module by its index */ +pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_info_cb_t cb, void *userdata); + +/** Get the complete list of currently loaded modules */ +pa_operation* pa_context_get_module_info_list(pa_context *c, pa_module_info_cb_t cb, void *userdata); + +/** Stores information about clients */ +typedef struct pa_client_info { + uint32_t index; /**< Index of this client */ + const char *name; /**< Name of this client */ + uint32_t owner_module; /**< Index of the owning module, or PA_INVALID_INDEX */ + const char *driver; /**< Driver name \since 0.8 */ +} pa_client_info; + +/** Callback prototype for pa_context_get_client_info() and firends*/ +typedef void (*pa_client_info_cb_t) (pa_context *c, const pa_client_info*i, int eol, void *userdata); + +/** Get information about a client by its index */ +pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, pa_client_info_cb_t cb, void *userdata); + +/** Get the complete client list */ +pa_operation* pa_context_get_client_info_list(pa_context *c, pa_client_info_cb_t cb, void *userdata); + +/** Stores information about sink inputs */ +typedef struct pa_sink_input_info { + uint32_t index; /**< Index of the sink input */ + const char *name; /**< Name of the sink input */ + uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ + uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ + uint32_t sink; /**< Index of the connected sink */ + pa_sample_spec sample_spec; /**< The sample specification of the sink input */ + pa_channel_map channel_map; /**< Channel map */ + pa_cvolume volume; /**< The volume of this sink input */ + pa_usec_t buffer_usec; /**< Latency due to buffering in sink input, see pa_latency_info for details */ + pa_usec_t sink_usec; /**< Latency of the sink device, see pa_latency_info for details */ + const char *resample_method; /**< Thre resampling method used by this sink input. \since 0.7 */ + const char *driver; /**< Driver name \since 0.8 */ +} pa_sink_input_info; + +/** Callback prototype for pa_context_get_sink_input_info() and firends*/ +typedef void (*pa_sink_input_info_cb_t) (pa_context *c, const pa_sink_input_info *i, int eol, void *userdata); + +/** Get some information about a sink input by its index */ +pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata); + +/** Get the complete sink input list */ +pa_operation* pa_context_get_sink_input_info_list(pa_context *c, pa_sink_input_info_cb_t cb, void *userdata); + +/** Stores information about source outputs */ +typedef struct pa_source_output_info { + uint32_t index; /**< Index of the sink input */ + const char *name; /**< Name of the sink input */ + uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ + uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ + uint32_t source; /**< Index of the connected source */ + pa_sample_spec sample_spec; /**< The sample specification of the source output */ + pa_channel_map channel_map; /**< Channel map */ + pa_usec_t buffer_usec; /**< Latency due to buffering in the source output, see pa_latency_info for details. \since 0.5 */ + pa_usec_t source_usec; /**< Latency of the source device, see pa_latency_info for details. \since 0.5 */ + const char *resample_method; /**< Thre resampling method used by this source output. \since 0.7 */ + const char *driver; /**< Driver name \since 0.8 */ +} pa_source_output_info; + +/** Callback prototype for pa_context_get_source_output_info() and firends*/ +typedef void (*pa_source_output_info_cb_t) (pa_context *c, const pa_source_output_info *i, int eol, void *userdata); + +/** Get information about a source output by its index */ +pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, pa_source_output_info_cb_t cb, void *userdata); + +/** Get the complete list of source outputs */ +pa_operation* pa_context_get_source_output_info_list(pa_context *c, pa_source_output_info_cb_t cb, void *userdata); + +/** Set the volume of a sink device specified by its index */ +pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); + +/** Set the volume of a sink device specified by its name */ +pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); + +/** Set the mute switch of a sink device specified by its index \since 0.8 */ +pa_operation* pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata); + +/** Set the mute switch of a sink device specified by its name \since 0.8 */ +pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata); + +/** Set the volume of a sink input stream */ +pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); + +/** Set the volume of a source device specified by its index \since 0.8 */ +pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); + +/** Set the volume of a source device specified by its name \since 0.8 */ +pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); + +/** Set the mute switch of a source device specified by its index \since 0.8 */ +pa_operation* pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata); + +/** Set the mute switch of a source device specified by its name \since 0.8 */ +pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata); + +/** Memory block statistics */ +typedef struct pa_stat_info { + uint32_t memblock_total; /**< Currently allocated memory blocks */ + uint32_t memblock_total_size; /**< Currentl total size of allocated memory blocks */ + uint32_t memblock_allocated; /**< Allocated memory blocks during the whole lifetime of the daemon */ + uint32_t memblock_allocated_size; /**< Total size of all memory blocks allocated during the whole lifetime of the daemon */ + uint32_t scache_size; /**< Total size of all sample cache entries. \since 0.4 */ +} pa_stat_info; + +/** Callback prototype for pa_context_stat() */ +typedef void (*pa_stat_info_cb_t) (pa_context *c, const pa_stat_info *i, void *userdata); + +/** Get daemon memory block statistics */ +pa_operation* pa_context_stat(pa_context *c, pa_stat_info_cb_t cb, void *userdata); + +/** Stores information about sample cache entries */ +typedef struct pa_sample_info { + uint32_t index; /**< Index of this entry */ + const char *name; /**< Name of this entry */ + pa_cvolume volume; /**< Default volume of this entry */ + pa_sample_spec sample_spec; /**< Sample specification of the sample */ + pa_channel_map channel_map; /**< The channel map */ + pa_usec_t duration; /**< Duration of this entry */ + uint32_t bytes; /**< Length of this sample in bytes. \since 0.4 */ + int lazy; /**< Non-zero when this is a lazy cache entry. \since 0.5 */ + const char *filename; /**< In case this is a lazy cache entry, the filename for the sound file to be loaded on demand. \since 0.5 */ +} pa_sample_info; + +/** Callback prototype for pa_context_get_sample_info_by_name() and firends */ +typedef void (*pa_sample_info_cb_t)(pa_context *c, const pa_sample_info *i, int eol, void *userdata); + +/** Get information about a sample by its name */ +pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, pa_sample_info_cb_t cb, void *userdata); + +/** Get information about a sample by its index */ +pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, pa_sample_info_cb_t cb, void *userdata); + +/** Get the complete list of samples stored in the daemon. */ +pa_operation* pa_context_get_sample_info_list(pa_context *c, pa_sample_info_cb_t cb, void *userdata); + +/** Kill a client. \since 0.5 */ +pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); + +/** Kill a sink input. \since 0.5 */ +pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); + +/** Kill a source output. \since 0.5 */ +pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); + +/** Callback prototype for pa_context_load_module() and pa_context_add_autoload() */ +typedef void (*pa_context_index_cb_t)(pa_context *c, uint32_t idx, void *userdata); + +/** Load a module. \since 0.5 */ +pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, pa_context_index_cb_t cb, void *userdata); + +/** Unload a module. \since 0.5 */ +pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); + +/** Type of an autoload entry. \since 0.5 */ +typedef enum pa_autoload_type { + PA_AUTOLOAD_SINK = 0, + PA_AUTOLOAD_SOURCE = 1 +} pa_autoload_type_t; + +/** Stores information about autoload entries. \since 0.5 */ +typedef struct pa_autoload_info { + uint32_t index; /**< Index of this autoload entry */ + const char *name; /**< Name of the sink or source */ + pa_autoload_type_t type; /**< Type of the autoload entry */ + const char *module; /**< Module name to load */ + const char *argument; /**< Argument string for module */ +} pa_autoload_info; + +/** Callback prototype for pa_context_get_autoload_info_by_name() and firends */ +typedef void (*pa_autoload_info_cb_t)(pa_context *c, const pa_autoload_info *i, int eol, void *userdata); + +/** Get info about a specific autoload entry. \since 0.6 */ +pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_autoload_info_cb_t cb, void *userdata); + +/** Get info about a specific autoload entry. \since 0.6 */ +pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, pa_autoload_info_cb_t cb, void *userdata); + +/** Get the complete list of autoload entries. \since 0.5 */ +pa_operation* pa_context_get_autoload_info_list(pa_context *c, pa_autoload_info_cb_t cb, void *userdata); + +/** Add a new autoload entry. \since 0.5 */ +pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, pa_context_index_cb_t, void* userdata); + +/** Remove an autoload entry. \since 0.6 */ +pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_context_success_cb_t cb, void* userdata); + +/** Remove an autoload entry. \since 0.6 */ +pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void* userdata); + + +PA_C_DECL_END + +#endif diff --git a/src/pulse/mainloop-api.c b/src/pulse/mainloop-api.c new file mode 100644 index 00000000..2e20b446 --- /dev/null +++ b/src/pulse/mainloop-api.c @@ -0,0 +1,70 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include + +#include "mainloop-api.h" + +struct once_info { + void (*callback)(pa_mainloop_api*m, void *userdata); + void *userdata; +}; + +static void once_callback(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { + struct once_info *i = userdata; + assert(m && i && i->callback); + + i->callback(m, i->userdata); + + assert(m->defer_free); + m->defer_free(e); +} + +static void free_callback(pa_mainloop_api *m, PA_GCC_UNUSED pa_defer_event *e, void *userdata) { + struct once_info *i = userdata; + assert(m && i); + pa_xfree(i); +} + +void pa_mainloop_api_once(pa_mainloop_api* m, void (*callback)(pa_mainloop_api *m, void *userdata), void *userdata) { + struct once_info *i; + pa_defer_event *e; + assert(m && callback); + + i = pa_xnew(struct once_info, 1); + i->callback = callback; + i->userdata = userdata; + + assert(m->defer_new); + e = m->defer_new(m, once_callback, i); + assert(e); + m->defer_set_destroy(e, free_callback); +} + diff --git a/src/pulse/mainloop-api.h b/src/pulse/mainloop-api.h new file mode 100644 index 00000000..a732b215 --- /dev/null +++ b/src/pulse/mainloop-api.h @@ -0,0 +1,118 @@ +#ifndef foomainloopapihfoo +#define foomainloopapihfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include + +/** \file + * + * Main loop abstraction layer. Both the pulseaudio core and the + * pulseaudio client library use a main loop abstraction layer. Due to + * this it is possible to embed pulseaudio into other + * applications easily. Two main loop implemenations are + * currently available: + * \li A minimal implementation based on the C library's poll() function (See \ref mainloop.h) + * \li A wrapper around the GLIB main loop. Use this to embed pulseaudio into your GLIB/GTK+/GNOME programs (See \ref glib-mainloop.h) + * + * The structure pa_mainloop_api is used as vtable for the main loop abstraction. + * + * This mainloop abstraction layer has no direct support for UNIX signals. Generic, mainloop implementation agnostic support is available throught \ref mainloop-signal.h. + * */ + +PA_C_DECL_BEGIN + +/** A bitmask for IO events */ +typedef enum pa_io_event_flags { + PA_IO_EVENT_NULL = 0, /**< No event */ + PA_IO_EVENT_INPUT = 1, /**< Input event */ + PA_IO_EVENT_OUTPUT = 2, /**< Output event */ + PA_IO_EVENT_HANGUP = 4, /**< Hangup event */ + PA_IO_EVENT_ERROR = 8 /**< Error event */ +} pa_io_event_flags_t; + +/** An opaque IO event source object */ +typedef struct pa_io_event pa_io_event; + +/** An opaque deferred event source object. Events of this type are triggered once in every main loop iteration */ +typedef struct pa_defer_event pa_defer_event; + +/** An opaque timer event source object */ +typedef struct pa_time_event pa_time_event; + +/** An abstract mainloop API vtable */ +typedef struct pa_mainloop_api pa_mainloop_api; + +/** An abstract mainloop API vtable */ +struct pa_mainloop_api { + /** A pointer to some private, arbitrary data of the main loop implementation */ + void *userdata; + + /** Create a new IO event source object */ + pa_io_event* (*io_new)(pa_mainloop_api*a, int fd, pa_io_event_flags_t events, void (*callback) (pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata); + + /** Enable or disable IO events on this object */ + void (*io_enable)(pa_io_event* e, pa_io_event_flags_t events); + + /** Free a IO event source object */ + void (*io_free)(pa_io_event* e); + + /** Set a function that is called when the IO event source is destroyed. Use this to free the userdata argument if required */ + void (*io_set_destroy)(pa_io_event *e, void (*callback) (pa_mainloop_api*a, pa_io_event *e, void *userdata)); + + /** Create a new timer event source object for the specified Unix time */ + pa_time_event* (*time_new)(pa_mainloop_api*a, const struct timeval *tv, void (*callback) (pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata), void *userdata); + + /** Restart a running or expired timer event source with a new Unix time */ + void (*time_restart)(pa_time_event* e, const struct timeval *tv); + + /** Free a deferred timer event source object */ + void (*time_free)(pa_time_event* e); + + /** Set a function that is called when the timer event source is destroyed. Use this to free the userdata argument if required */ + void (*time_set_destroy)(pa_time_event *e, void (*callback) (pa_mainloop_api*a, pa_time_event *e, void *userdata)); + + /** Create a new deferred event source object */ + pa_defer_event* (*defer_new)(pa_mainloop_api*a, void (*callback) (pa_mainloop_api*a, pa_defer_event* e, void *userdata), void *userdata); + + /** Enable or disable a deferred event source temporarily */ + void (*defer_enable)(pa_defer_event* e, int b); + + /** Free a deferred event source object */ + void (*defer_free)(pa_defer_event* e); + + /** Set a function that is called when the deferred event source is destroyed. Use this to free the userdata argument if required */ + void (*defer_set_destroy)(pa_defer_event *e, void (*callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata)); + + /** Exit the main loop and return the specfied retval*/ + void (*quit)(pa_mainloop_api*a, int retval); +}; + +/** Run the specified callback function once from the main loop using an anonymous defer event. */ +void pa_mainloop_api_once(pa_mainloop_api*m, void (*callback)(pa_mainloop_api*m, void *userdata), void *userdata); + +PA_C_DECL_END + +#endif diff --git a/src/pulse/mainloop-signal.c b/src/pulse/mainloop-signal.c new file mode 100644 index 00000000..c3cf362d --- /dev/null +++ b/src/pulse/mainloop-signal.c @@ -0,0 +1,210 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include +#include + +#include +#include +#include + +#include "mainloop-signal.h" + +struct pa_signal_event { + int sig; +#ifdef HAVE_SIGACTION + struct sigaction saved_sigaction; +#else + void (*saved_handler)(int sig); +#endif + void (*callback) (pa_mainloop_api*a, pa_signal_event *e, int sig, void *userdata); + void *userdata; + void (*destroy_callback) (pa_mainloop_api*a, pa_signal_event*e, void *userdata); + pa_signal_event *previous, *next; +}; + +static pa_mainloop_api *api = NULL; +static int signal_pipe[2] = { -1, -1 }; +static pa_io_event* io_event = NULL; +static pa_signal_event *signals = NULL; + +static void signal_handler(int sig) { +#ifndef HAVE_SIGACTION + signal(sig, signal_handler); +#endif + pa_write(signal_pipe[1], &sig, sizeof(sig)); +} + +static void dispatch(pa_mainloop_api*a, int sig) { + pa_signal_event*s; + + for (s = signals; s; s = s->next) + if (s->sig == sig) { + assert(s->callback); + s->callback(a, s, sig, s->userdata); + break; + } +} + +static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags_t f, PA_GCC_UNUSED void *userdata) { + ssize_t r; + int sig; + assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]); + + if ((r = pa_read(signal_pipe[0], &sig, sizeof(sig))) < 0) { + if (errno == EAGAIN) + return; + + pa_log(__FILE__": read(): %s", pa_cstrerror(errno)); + return; + } + + if (r != sizeof(sig)) { + pa_log(__FILE__": short read()"); + return; + } + + dispatch(a, sig); +} + +int pa_signal_init(pa_mainloop_api *a) { + + assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event); + + if (pipe(signal_pipe) < 0) { + pa_log(__FILE__": pipe(): %s", pa_cstrerror(errno)); + return -1; + } + + pa_make_nonblock_fd(signal_pipe[0]); + pa_make_nonblock_fd(signal_pipe[1]); + pa_fd_set_cloexec(signal_pipe[0], 1); + pa_fd_set_cloexec(signal_pipe[1], 1); + + api = a; + + io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL); + assert(io_event); + + return 0; +} + +void pa_signal_done(void) { + assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && io_event); + + while (signals) + pa_signal_free(signals); + + api->io_free(io_event); + io_event = NULL; + + close(signal_pipe[0]); + close(signal_pipe[1]); + signal_pipe[0] = signal_pipe[1] = -1; + + api = NULL; +} + +pa_signal_event* pa_signal_new(int sig, void (*_callback) (pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata), void *userdata) { + pa_signal_event *e = NULL; + +#ifdef HAVE_SIGACTION + struct sigaction sa; +#endif + + assert(sig > 0 && _callback); + + for (e = signals; e; e = e->next) + if (e->sig == sig) + goto fail; + + e = pa_xmalloc(sizeof(pa_signal_event)); + e->sig = sig; + e->callback = _callback; + e->userdata = userdata; + e->destroy_callback = NULL; + +#ifdef HAVE_SIGACTION + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = signal_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + + if (sigaction(sig, &sa, &e->saved_sigaction) < 0) +#else + if ((e->saved_handler = signal(sig, signal_handler)) == SIG_ERR) +#endif + goto fail; + + e->previous = NULL; + e->next = signals; + signals = e; + + return e; +fail: + if (e) + pa_xfree(e); + return NULL; +} + +void pa_signal_free(pa_signal_event *e) { + assert(e); + + if (e->next) + e->next->previous = e->previous; + if (e->previous) + e->previous->next = e->next; + else + signals = e->next; + +#ifdef HAVE_SIGACTION + sigaction(e->sig, &e->saved_sigaction, NULL); +#else + signal(e->sig, e->saved_handler); +#endif + + if (e->destroy_callback) + e->destroy_callback(api, e, e->userdata); + + pa_xfree(e); +} + +void pa_signal_set_destroy(pa_signal_event *e, void (*_callback) (pa_mainloop_api *api, pa_signal_event*e, void *userdata)) { + assert(e); + e->destroy_callback = _callback; +} diff --git a/src/pulse/mainloop-signal.h b/src/pulse/mainloop-signal.h new file mode 100644 index 00000000..0721c1f5 --- /dev/null +++ b/src/pulse/mainloop-signal.h @@ -0,0 +1,59 @@ +#ifndef foomainloopsignalhfoo +#define foomainloopsignalhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +PA_C_DECL_BEGIN + +/** \file + * UNIX signal support for main loops. In contrast to other + * main loop event sources such as timer and IO events, UNIX signal + * support requires modification of the global process + * environment. Due to this the generic main loop abstraction layer as + * defined in \ref mainloop-api.h doesn't have direct support for UNIX + * signals. However, you may hook signal support into an abstract main loop via the routines defined herein. + */ + +/** Initialize the UNIX signal subsystem and bind it to the specified main loop */ +int pa_signal_init(pa_mainloop_api *api); + +/** Cleanup the signal subsystem */ +void pa_signal_done(void); + +/** An opaque UNIX signal event source object */ +typedef struct pa_signal_event pa_signal_event; + +/** Create a new UNIX signal event source object */ +pa_signal_event* pa_signal_new(int sig, void (*callback) (pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata), void *userdata); + +/** Free a UNIX signal event source object */ +void pa_signal_free(pa_signal_event *e); + +/** Set a function that is called when the signal event source is destroyed. Use this to free the userdata argument if required */ +void pa_signal_set_destroy(pa_signal_event *e, void (*callback) (pa_mainloop_api *api, pa_signal_event*e, void *userdata)); + +PA_C_DECL_END + +#endif diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c new file mode 100644 index 00000000..32f1a845 --- /dev/null +++ b/src/pulse/mainloop.c @@ -0,0 +1,839 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_POLL_H +#include +#else +#include "../pulsecore/poll.h" +#endif + +#include "../pulsecore/winsock.h" + +#ifndef HAVE_PIPE +#include "../pulsecore/pipe.h" +#endif + +#include +#include +#include + +#include +#include +#include + +#include "mainloop.h" + +struct pa_io_event { + pa_mainloop *mainloop; + int dead; + int fd; + pa_io_event_flags_t events; + void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); + struct pollfd *pollfd; + void *userdata; + void (*destroy_callback) (pa_mainloop_api*a, pa_io_event *e, void *userdata); +}; + +struct pa_time_event { + pa_mainloop *mainloop; + int dead; + int enabled; + struct timeval timeval; + void (*callback)(pa_mainloop_api*a, pa_time_event *e, const struct timeval*tv, void *userdata); + void *userdata; + void (*destroy_callback) (pa_mainloop_api*a, pa_time_event *e, void *userdata); +}; + +struct pa_defer_event { + pa_mainloop *mainloop; + int dead; + int enabled; + void (*callback)(pa_mainloop_api*a, pa_defer_event*e, void *userdata); + void *userdata; + void (*destroy_callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata); +}; + +struct pa_mainloop { + pa_idxset *io_events, *time_events, *defer_events; + int io_events_scan_dead, defer_events_scan_dead, time_events_scan_dead; + + struct pollfd *pollfds; + unsigned max_pollfds, n_pollfds; + int rebuild_pollfds; + + int prepared_timeout; + + int quit, retval; + pa_mainloop_api api; + + int deferred_pending; + + int wakeup_pipe[2]; + + enum { + STATE_PASSIVE, + STATE_PREPARED, + STATE_POLLING, + STATE_POLLED, + STATE_QUIT + } state; + + pa_poll_func poll_func; + void *poll_func_userdata; +}; + +/* IO events */ +static pa_io_event* mainloop_io_new( + pa_mainloop_api*a, + int fd, + pa_io_event_flags_t events, + void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), + void *userdata) { + + pa_mainloop *m; + pa_io_event *e; + + assert(a && a->userdata && fd >= 0 && callback); + m = a->userdata; + assert(a == &m->api); + + e = pa_xmalloc(sizeof(pa_io_event)); + e->mainloop = m; + e->dead = 0; + + e->fd = fd; + e->events = events; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + e->pollfd = NULL; + +#ifdef OS_IS_WIN32 + { + fd_set xset; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 0; + + FD_ZERO (&xset); + FD_SET (fd, &xset); + + if ((select((SELECT_TYPE_ARG1) fd, NULL, NULL, SELECT_TYPE_ARG234 &xset, + SELECT_TYPE_ARG5 &tv) == -1) && + (WSAGetLastError() == WSAENOTSOCK)) { + pa_log_warn(__FILE__": WARNING: cannot monitor non-socket file descriptors."); + e->dead = 1; + } + } +#endif + + pa_idxset_put(m->io_events, e, NULL); + m->rebuild_pollfds = 1; + + pa_mainloop_wakeup(m); + + return e; +} + +static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags_t events) { + assert(e && e->mainloop); + + e->events = events; + e->mainloop->rebuild_pollfds = 1; + + pa_mainloop_wakeup(e->mainloop); +} + +static void mainloop_io_free(pa_io_event *e) { + assert(e && e->mainloop); + + e->dead = e->mainloop->io_events_scan_dead = e->mainloop->rebuild_pollfds = 1; + + pa_mainloop_wakeup(e->mainloop); +} + +static void mainloop_io_set_destroy(pa_io_event *e, void (*callback)(pa_mainloop_api*a, pa_io_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* Defer events */ +static pa_defer_event* mainloop_defer_new(pa_mainloop_api*a, void (*callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata), void *userdata) { + pa_mainloop *m; + pa_defer_event *e; + + assert(a && a->userdata && callback); + m = a->userdata; + assert(a == &m->api); + + e = pa_xmalloc(sizeof(pa_defer_event)); + e->mainloop = m; + e->dead = 0; + + e->enabled = 1; + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + + pa_idxset_put(m->defer_events, e, NULL); + + m->deferred_pending++; + + pa_mainloop_wakeup(e->mainloop); + + return e; +} + +static void mainloop_defer_enable(pa_defer_event *e, int b) { + assert(e); + + if (e->enabled && !b) { + assert(e->mainloop->deferred_pending > 0); + e->mainloop->deferred_pending--; + } else if (!e->enabled && b) { + e->mainloop->deferred_pending++; + pa_mainloop_wakeup(e->mainloop); + } + + e->enabled = b; +} + +static void mainloop_defer_free(pa_defer_event *e) { + assert(e); + e->dead = e->mainloop->defer_events_scan_dead = 1; + + if (e->enabled) { + e->enabled = 0; + assert(e->mainloop->deferred_pending > 0); + e->mainloop->deferred_pending--; + } +} + +static void mainloop_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api*a, pa_defer_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* Time events */ +static pa_time_event* mainloop_time_new(pa_mainloop_api*a, const struct timeval *tv, void (*callback) (pa_mainloop_api*a, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { + pa_mainloop *m; + pa_time_event *e; + + assert(a && a->userdata && callback); + m = a->userdata; + assert(a == &m->api); + + e = pa_xmalloc(sizeof(pa_time_event)); + e->mainloop = m; + e->dead = 0; + + e->enabled = !!tv; + if (tv) + e->timeval = *tv; + + e->callback = callback; + e->userdata = userdata; + e->destroy_callback = NULL; + + pa_idxset_put(m->time_events, e, NULL); + + if (e->enabled) + pa_mainloop_wakeup(m); + + return e; +} + +static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) { + assert(e); + + if (tv) { + e->enabled = 1; + e->timeval = *tv; + + pa_mainloop_wakeup(e->mainloop); + } else + e->enabled = 0; +} + +static void mainloop_time_free(pa_time_event *e) { + assert(e); + + e->dead = e->mainloop->time_events_scan_dead = 1; + + /* no wakeup needed here. Think about it! */ +} + +static void mainloop_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*a, pa_time_event *e, void *userdata)) { + assert(e); + e->destroy_callback = callback; +} + +/* quit() */ + +static void mainloop_quit(pa_mainloop_api*a, int retval) { + pa_mainloop *m; + assert(a && a->userdata); + m = a->userdata; + assert(a == &m->api); + + pa_mainloop_quit(m, retval); +} + +static const pa_mainloop_api vtable = { + .userdata = NULL, + + .io_new= mainloop_io_new, + .io_enable= mainloop_io_enable, + .io_free= mainloop_io_free, + .io_set_destroy= mainloop_io_set_destroy, + + .time_new = mainloop_time_new, + .time_restart = mainloop_time_restart, + .time_free = mainloop_time_free, + .time_set_destroy = mainloop_time_set_destroy, + + .defer_new = mainloop_defer_new, + .defer_enable = mainloop_defer_enable, + .defer_free = mainloop_defer_free, + .defer_set_destroy = mainloop_defer_set_destroy, + + .quit = mainloop_quit, +}; + +pa_mainloop *pa_mainloop_new(void) { + pa_mainloop *m; + + m = pa_xmalloc(sizeof(pa_mainloop)); + + if (pipe(m->wakeup_pipe) < 0) { + pa_log_error(__FILE__": ERROR: cannot create wakeup pipe"); + pa_xfree(m); + return NULL; + } + + pa_make_nonblock_fd(m->wakeup_pipe[0]); + pa_make_nonblock_fd(m->wakeup_pipe[1]); + + m->io_events = pa_idxset_new(NULL, NULL); + m->defer_events = pa_idxset_new(NULL, NULL); + m->time_events = pa_idxset_new(NULL, NULL); + + assert(m->io_events && m->defer_events && m->time_events); + + m->io_events_scan_dead = m->defer_events_scan_dead = m->time_events_scan_dead = 0; + + m->pollfds = NULL; + m->max_pollfds = m->n_pollfds = 0; + m->rebuild_pollfds = 1; + + m->quit = m->retval = 0; + + m->api = vtable; + m->api.userdata = m; + + m->deferred_pending = 0; + + m->state = STATE_PASSIVE; + + m->poll_func = NULL; + m->poll_func_userdata = NULL; + + m->retval = -1; + + return m; +} + +static int io_foreach(void *p, uint32_t PA_GCC_UNUSED idx, int *del, void*userdata) { + pa_io_event *e = p; + int *all = userdata; + assert(e && del && all); + + if (!*all && !e->dead) + return 0; + + if (e->destroy_callback) + e->destroy_callback(&e->mainloop->api, e, e->userdata); + pa_xfree(e); + *del = 1; + return 0; +} + +static int time_foreach(void *p, uint32_t PA_GCC_UNUSED idx, int *del, void*userdata) { + pa_time_event *e = p; + int *all = userdata; + assert(e && del && all); + + if (!*all && !e->dead) + return 0; + + if (e->destroy_callback) + e->destroy_callback(&e->mainloop->api, e, e->userdata); + pa_xfree(e); + *del = 1; + return 0; +} + +static int defer_foreach(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void*userdata) { + pa_defer_event *e = p; + int *all = userdata; + assert(e && del && all); + + if (!*all && !e->dead) + return 0; + + if (e->destroy_callback) + e->destroy_callback(&e->mainloop->api, e, e->userdata); + pa_xfree(e); + *del = 1; + return 0; +} + +void pa_mainloop_free(pa_mainloop* m) { + int all = 1; + assert(m); + + pa_idxset_foreach(m->io_events, io_foreach, &all); + pa_idxset_foreach(m->time_events, time_foreach, &all); + pa_idxset_foreach(m->defer_events, defer_foreach, &all); + + pa_idxset_free(m->io_events, NULL, NULL); + pa_idxset_free(m->time_events, NULL, NULL); + pa_idxset_free(m->defer_events, NULL, NULL); + + pa_xfree(m->pollfds); + + if (m->wakeup_pipe[0] >= 0) + close(m->wakeup_pipe[0]); + if (m->wakeup_pipe[1] >= 0) + close(m->wakeup_pipe[1]); + + pa_xfree(m); +} + +static void scan_dead(pa_mainloop *m) { + int all = 0; + assert(m); + + if (m->io_events_scan_dead) + pa_idxset_foreach(m->io_events, io_foreach, &all); + if (m->time_events_scan_dead) + pa_idxset_foreach(m->time_events, time_foreach, &all); + if (m->defer_events_scan_dead) + pa_idxset_foreach(m->defer_events, defer_foreach, &all); + + m->io_events_scan_dead = m->time_events_scan_dead = m->defer_events_scan_dead = 0; +} + +static void rebuild_pollfds(pa_mainloop *m) { + pa_io_event*e; + struct pollfd *p; + uint32_t idx = PA_IDXSET_INVALID; + unsigned l; + + l = pa_idxset_size(m->io_events) + 1; + if (m->max_pollfds < l) { + m->pollfds = pa_xrealloc(m->pollfds, sizeof(struct pollfd)*l); + m->max_pollfds = l; + } + + m->n_pollfds = 0; + p = m->pollfds; + + if (m->wakeup_pipe[0] >= 0) { + m->pollfds[0].fd = m->wakeup_pipe[0]; + m->pollfds[0].events = POLLIN; + m->pollfds[0].revents = 0; + p++; + m->n_pollfds++; + } + + for (e = pa_idxset_first(m->io_events, &idx); e; e = pa_idxset_next(m->io_events, &idx)) { + if (e->dead) { + e->pollfd = NULL; + continue; + } + + e->pollfd = p; + p->fd = e->fd; + p->events = + ((e->events & PA_IO_EVENT_INPUT) ? POLLIN : 0) | + ((e->events & PA_IO_EVENT_OUTPUT) ? POLLOUT : 0) | + POLLHUP | + POLLERR; + p->revents = 0; + + p++; + m->n_pollfds++; + } + + m->rebuild_pollfds = 0; +} + +static int dispatch_pollfds(pa_mainloop *m) { + uint32_t idx = PA_IDXSET_INVALID; + pa_io_event *e; + int r = 0; + + for (e = pa_idxset_first(m->io_events, &idx); e && !m->quit; e = pa_idxset_next(m->io_events, &idx)) { + if (e->dead || !e->pollfd || !e->pollfd->revents) + continue; + + assert(e->pollfd->fd == e->fd && e->callback); + e->callback(&m->api, e, e->fd, + (e->pollfd->revents & POLLHUP ? PA_IO_EVENT_HANGUP : 0) | + (e->pollfd->revents & POLLIN ? PA_IO_EVENT_INPUT : 0) | + (e->pollfd->revents & POLLOUT ? PA_IO_EVENT_OUTPUT : 0) | + (e->pollfd->revents & POLLERR ? PA_IO_EVENT_ERROR : 0), + e->userdata); + e->pollfd->revents = 0; + r++; + } + + return r; +} + +static int dispatch_defer(pa_mainloop *m) { + uint32_t idx; + pa_defer_event *e; + int r = 0; + + if (!m->deferred_pending) + return 0; + + for (e = pa_idxset_first(m->defer_events, &idx); e && !m->quit; e = pa_idxset_next(m->defer_events, &idx)) { + if (e->dead || !e->enabled) + continue; + + assert(e->callback); + e->callback(&m->api, e, e->userdata); + r++; + } + + return r; +} + +static int calc_next_timeout(pa_mainloop *m) { + uint32_t idx; + pa_time_event *e; + struct timeval now; + int t = -1; + int got_time = 0; + + if (pa_idxset_isempty(m->time_events)) + return -1; + + for (e = pa_idxset_first(m->time_events, &idx); e; e = pa_idxset_next(m->time_events, &idx)) { + int tmp; + + if (e->dead || !e->enabled) + continue; + + /* Let's save a system call */ + if (!got_time) { + pa_gettimeofday(&now); + got_time = 1; + } + + if (e->timeval.tv_sec < now.tv_sec || (e->timeval.tv_sec == now.tv_sec && e->timeval.tv_usec <= now.tv_usec)) + return 0; + + tmp = (e->timeval.tv_sec - now.tv_sec)*1000; + + if (e->timeval.tv_usec > now.tv_usec) + tmp += (e->timeval.tv_usec - now.tv_usec)/1000; + else + tmp -= (now.tv_usec - e->timeval.tv_usec)/1000; + + if (tmp == 0) + return 0; + else if (t == -1 || tmp < t) + t = tmp; + } + + return t; +} + +static int dispatch_timeout(pa_mainloop *m) { + uint32_t idx; + pa_time_event *e; + struct timeval now; + int got_time = 0; + int r = 0; + assert(m); + + if (pa_idxset_isempty(m->time_events)) + return 0; + + for (e = pa_idxset_first(m->time_events, &idx); e && !m->quit; e = pa_idxset_next(m->time_events, &idx)) { + + if (e->dead || !e->enabled) + continue; + + /* Let's save a system call */ + if (!got_time) { + pa_gettimeofday(&now); + got_time = 1; + } + + if (e->timeval.tv_sec < now.tv_sec || (e->timeval.tv_sec == now.tv_sec && e->timeval.tv_usec <= now.tv_usec)) { + assert(e->callback); + + e->enabled = 0; + e->callback(&m->api, e, &e->timeval, e->userdata); + + r++; + } + } + + return r; +} + +void pa_mainloop_wakeup(pa_mainloop *m) { + char c = 'W'; + assert(m); + + if (m->wakeup_pipe[1] >= 0) + pa_write(m->wakeup_pipe[1], &c, sizeof(c)); +} + +static void clear_wakeup(pa_mainloop *m) { + char c[10]; + + assert(m); + + if (m->wakeup_pipe[0] < 0) + return; + + while (pa_read(m->wakeup_pipe[0], &c, sizeof(c)) == sizeof(c)); +} + +int pa_mainloop_prepare(pa_mainloop *m, int timeout) { + assert(m); + assert(m->state == STATE_PASSIVE); + + clear_wakeup(m); + scan_dead(m); + + if (m->quit) + goto quit; + + if (!m->deferred_pending) { + + if (m->rebuild_pollfds) + rebuild_pollfds(m); + + m->prepared_timeout = calc_next_timeout(m); + if (timeout >= 0 && (timeout < m->prepared_timeout || m->prepared_timeout < 0)) + m->prepared_timeout = timeout; + } + + m->state = STATE_PREPARED; + return 0; + +quit: + m->state = STATE_QUIT; + return -2; +} + +int pa_mainloop_poll(pa_mainloop *m) { + int r; + + assert(m); + assert(m->state == STATE_PREPARED); + + if (m->quit) + goto quit; + + m->state = STATE_POLLING; + + if (m->deferred_pending) + r = 0; + else { + if (m->poll_func) + r = m->poll_func(m->pollfds, m->n_pollfds, m->prepared_timeout, m->poll_func_userdata); + else + r = poll(m->pollfds, m->n_pollfds, m->prepared_timeout); + + if (r < 0) { + if (errno == EINTR) + r = 0; + else + pa_log(__FILE__": poll(): %s", pa_cstrerror(errno)); + } + } + + m->state = r < 0 ? STATE_PASSIVE : STATE_POLLED; + return r; + +quit: + m->state = STATE_QUIT; + return -2; +} + +int pa_mainloop_dispatch(pa_mainloop *m) { + int dispatched = 0; + + assert(m); + assert(m->state == STATE_POLLED); + + if (m->quit) + goto quit; + + if (m->deferred_pending) + dispatched += dispatch_defer(m); + else { + dispatched += dispatch_timeout(m); + + if (m->quit) + goto quit; + + dispatched += dispatch_pollfds(m); + + } + + if (m->quit) + goto quit; + + m->state = STATE_PASSIVE; + + return dispatched; + +quit: + m->state = STATE_QUIT; + return -2; +} + +int pa_mainloop_get_retval(pa_mainloop *m) { + assert(m); + return m->retval; +} + +int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) { + int r; + assert(m); + + if ((r = pa_mainloop_prepare(m, block ? -1 : 0)) < 0) + goto quit; + + if ((r = pa_mainloop_poll(m)) < 0) + goto quit; + + if ((r = pa_mainloop_dispatch(m)) < 0) + goto quit; + + return r; + +quit: + + if ((r == -2) && retval) + *retval = pa_mainloop_get_retval(m); + return r; +} + +int pa_mainloop_run(pa_mainloop *m, int *retval) { + int r; + + while ((r = pa_mainloop_iterate(m, 1, retval)) >= 0); + + if (r == -2) + return 1; + else if (r < 0) + return -1; + else + return 0; +} + +void pa_mainloop_quit(pa_mainloop *m, int retval) { + assert(m); + + m->quit = 1; + m->retval = retval; + pa_mainloop_wakeup(m); +} + +pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m) { + assert(m); + return &m->api; +} + +void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata) { + assert(m); + + m->poll_func = poll_func; + m->poll_func_userdata = userdata; +} + + +#if 0 +void pa_mainloop_dump(pa_mainloop *m) { + assert(m); + + pa_log(__FILE__": Dumping mainloop sources START"); + + { + uint32_t idx = PA_IDXSET_INVALID; + pa_io_event *e; + for (e = pa_idxset_first(m->io_events, &idx); e; e = pa_idxset_next(m->io_events, &idx)) { + if (e->dead) + continue; + + pa_log(__FILE__": kind=io fd=%i events=%i callback=%p userdata=%p", e->fd, (int) e->events, (void*) e->callback, (void*) e->userdata); + } + } + { + uint32_t idx = PA_IDXSET_INVALID; + pa_defer_event *e; + for (e = pa_idxset_first(m->defer_events, &idx); e; e = pa_idxset_next(m->defer_events, &idx)) { + if (e->dead) + continue; + + pa_log(__FILE__": kind=defer enabled=%i callback=%p userdata=%p", e->enabled, (void*) e->callback, (void*) e->userdata); + } + } + { + uint32_t idx = PA_IDXSET_INVALID; + pa_time_event *e; + for (e = pa_idxset_first(m->time_events, &idx); e; e = pa_idxset_next(m->time_events, &idx)) { + if (e->dead) + continue; + + pa_log(__FILE__": kind=time enabled=%i time=%lu.%lu callback=%p userdata=%p", e->enabled, (unsigned long) e->timeval.tv_sec, (unsigned long) e->timeval.tv_usec, (void*) e->callback, (void*) e->userdata); + } + } + + pa_log(__FILE__": Dumping mainloop sources STOP"); + +} +#endif diff --git a/src/pulse/mainloop.h b/src/pulse/mainloop.h new file mode 100644 index 00000000..8abd8fe4 --- /dev/null +++ b/src/pulse/mainloop.h @@ -0,0 +1,127 @@ +#ifndef foomainloophfoo +#define foomainloophfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +PA_C_DECL_BEGIN + +struct pollfd; + +/** \page mainloop Main Loop + * + * \section overv_sec Overview + * + * The built-in main loop implementation is based on the poll() system call. + * It supports the functions defined in the main loop abstraction and very + * little else. + * + * The main loop is created using pa_mainloop_new() and destroyed using + * pa_mainloop_free(). To get access to the main loop abstraction, + * pa_mainloop_get_api() is used. + * + * \section iter_sec Iteration + * + * The main loop is designed around the concept of iterations. Each iteration + * consists of three steps that repeat during the application's entire + * lifetime: + * + * -# Prepare - Build a list of file descriptors + * that need to be monitored and calculate the next timeout. + * -# Poll - Execute the actuall poll() system call. + * -# Dispatch - Dispatch any events that have fired. + * + * When using the main loop, the application can either execute each + * iteration, one at a time, using pa_mainloop_iterate(), or let the library + * iterate automatically using pa_mainloop_run(). + * + * \section thread_sec Threads + * + * The main loop functions are designed to be thread safe, but the objects + * are not. What this means is that multiple main loops can be used, but only + * one object per thread. + * + */ + +/** \file + * + * A minimal main loop implementation based on the C library's poll() + * function. Using the routines defined herein you may create a simple + * main loop supporting the generic main loop abstraction layer as + * defined in \ref mainloop-api.h. This implementation is thread safe + * as long as you access the main loop object from a single thread only.*/ + +/** An opaque main loop object */ +typedef struct pa_mainloop pa_mainloop; + +/** Allocate a new main loop object */ +pa_mainloop *pa_mainloop_new(void); + +/** Free a main loop object */ +void pa_mainloop_free(pa_mainloop* m); + +/** Prepare for a single iteration of the main loop. Returns a negative value +on error or exit request. timeout specifies a maximum timeout for the subsequent +poll, or -1 for blocking behaviour. .*/ +int pa_mainloop_prepare(pa_mainloop *m, int timeout); + +/** Execute the previously prepared poll. Returns a negative value on error.*/ +int pa_mainloop_poll(pa_mainloop *m); + +/** Dispatch timeout, io and deferred events from the previously executed poll. Returns +a negative value on error. On success returns the number of source dispatched. */ +int pa_mainloop_dispatch(pa_mainloop *m); + +/** Return the return value as specified with the main loop's quit() routine. */ +int pa_mainloop_get_retval(pa_mainloop *m); + +/** Run a single iteration of the main loop. This is a convenience function +for pa_mainloop_prepare(), pa_mainloop_poll() and pa_mainloop_dispatch(). +Returns a negative value on error or exit request. If block is nonzero, +block for events if none are queued. Optionally return the return value as +specified with the main loop's quit() routine in the integer variable retval points +to. On success returns the number of sources dispatched in this iteration. */ +int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval); + +/** Run unlimited iterations of the main loop object until the main loop's quit() routine is called. */ +int pa_mainloop_run(pa_mainloop *m, int *retval); + +/** Return the abstract main loop abstraction layer vtable for this main loop. */ +pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m); + +/** Shutdown the main loop */ +void pa_mainloop_quit(pa_mainloop *m, int r); + +/** Interrupt a running poll (for threaded systems) */ +void pa_mainloop_wakeup(pa_mainloop *m); + +/** Generic prototype of a poll() like function */ +typedef int (*pa_poll_func)(struct pollfd *ufds, unsigned long nfds, int timeout, void*userdata); + +/** Change the poll() implementation */ +void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata); + +PA_C_DECL_END + +#endif diff --git a/src/pulse/operation.c b/src/pulse/operation.c new file mode 100644 index 00000000..24ddf69f --- /dev/null +++ b/src/pulse/operation.c @@ -0,0 +1,116 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include "internal.h" +#include "operation.h" + +pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t cb, void *userdata) { + pa_operation *o; + assert(c); + + o = pa_xnew(pa_operation, 1); + o->ref = 1; + o->context = c; + o->stream = s; + + o->state = PA_OPERATION_RUNNING; + o->callback = cb; + o->userdata = userdata; + + /* Refcounting is strictly one-way: from the "bigger" to the "smaller" object. */ + PA_LLIST_PREPEND(pa_operation, c->operations, o); + pa_operation_ref(o); + + return o; +} + +pa_operation *pa_operation_ref(pa_operation *o) { + assert(o); + assert(o->ref >= 1); + + o->ref++; + return o; +} + +void pa_operation_unref(pa_operation *o) { + assert(o); + assert(o->ref >= 1); + + if ((--(o->ref)) == 0) { + assert(!o->context); + assert(!o->stream); + pa_xfree(o); + } +} + +static void operation_set_state(pa_operation *o, pa_operation_state_t st) { + assert(o); + assert(o->ref >= 1); + + if (st == o->state) + return; + + o->state = st; + + if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) { + + if (o->context) { + assert(o->ref >= 2); + + PA_LLIST_REMOVE(pa_operation, o->context->operations, o); + pa_operation_unref(o); + } + + o->context = NULL; + o->stream = NULL; + o->callback = NULL; + o->userdata = NULL; + } +} + +void pa_operation_cancel(pa_operation *o) { + assert(o); + assert(o->ref >= 1); + + operation_set_state(o, PA_OPERATION_CANCELED); +} + +void pa_operation_done(pa_operation *o) { + assert(o); + assert(o->ref >= 1); + + operation_set_state(o, PA_OPERATION_DONE); +} + +pa_operation_state_t pa_operation_get_state(pa_operation *o) { + assert(o); + assert(o->ref >= 1); + + return o->state; +} diff --git a/src/pulse/operation.h b/src/pulse/operation.h new file mode 100644 index 00000000..b544e08e --- /dev/null +++ b/src/pulse/operation.h @@ -0,0 +1,50 @@ +#ifndef foooperationhfoo +#define foooperationhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/** \file + * Asynchronous operations */ + +PA_C_DECL_BEGIN + +/** An asynchronous operation object */ +typedef struct pa_operation pa_operation; + +/** Increase the reference count by one */ +pa_operation *pa_operation_ref(pa_operation *o); + +/** Decrease the reference count by one */ +void pa_operation_unref(pa_operation *o); + +/** Cancel the operation. Beware! This will not necessarily cancel the execution of the operation on the server side. */ +void pa_operation_cancel(pa_operation *o); + +/** Return the current status of the operation */ +pa_operation_state_t pa_operation_get_state(pa_operation *o); + +PA_C_DECL_END + +#endif diff --git a/src/pulse/polypaudio.h b/src/pulse/polypaudio.h new file mode 100644 index 00000000..5bbd4cc5 --- /dev/null +++ b/src/pulse/polypaudio.h @@ -0,0 +1,115 @@ +#ifndef foopulseaudiohfoo +#define foopulseaudiohfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** \file + * Include all pulselib header files at once. The following + * files are included: \ref mainloop-api.h, \ref sample.h, \ref def.h, + * \ref context.h, \ref stream.h, \ref introspect.h, \ref subscribe.h, + * \ref scache.h, \ref version.h, \ref error.h, \ref channelmap.h, + * \ref operation.h,\ref volume.h, \ref xmalloc.h, \ref utf8.h, \ref + * thread-mainloop.h, \ref mainloop.h, \ref util.h, \ref timeval.h and + * \ref mainloop-signal.h at once */ + +/** \mainpage + * + * \section intro_sec Introduction + * + * This document describes the client API for the pulseaudio sound + * server. The API comes in two flavours to accomodate different styles + * of applications and different needs in complexity: + * + * \li The complete but somewhat complicated to use asynchronous API + * \li The simplified, easy to use, but limited synchronous API + * + * All strings in Polypaudio are in the UTF-8 encoding, regardless of current + * locale. Some functions will filter invalid sequences from the string, some + * will simply fail. To ensure reliable behaviour, make sure everything you + * pass to the API is already in UTF-8. + + * \section simple_sec Simple API + * + * Use this if you develop your program in synchronous style and just + * need a way to play or record data on the sound server. See + * \subpage simple for more details. + * + * \section async_sec Asynchronous API + * + * Use this if you develop your programs in asynchronous, event loop + * based style or if you want to use the advanced features of the + * pulseaudio API. A guide can be found in \subpage async. + * + * By using the built-in threaded main loop, it is possible to acheive a + * pseudo-synchronous API, which can be useful in synchronous applications + * where the simple API is insufficient. See the \ref async page for + * details. + * + * \section thread_sec Threads + * + * The pulseaudio client libraries are not designed to be used in a + * heavily threaded environment. They are however designed to be reentrant + * safe. + * + * To use a the libraries in a threaded environment, you must assure that + * all objects are only used in one thread at a time. Normally, this means + * that all objects belonging to a single context must be accessed from the + * same thread. + * + * The included main loop implementation is also not thread safe. Take care + * to make sure event lists are not manipulated when any other code is + * using the main loop. + * + * \section pkgconfig pkg-config + * + * The pulseaudio libraries provide pkg-config snippets for the different + * modules: + * + * \li pulselib - The asynchronous API and the internal main loop + * implementation. + * \li pulselib-glib12-mainloop - GLIB 1.2 main loop bindings. + * \li pulselib-glib-mainloop - GLIB 2.x main loop bindings. + * \li pulselib-simple - The simple pulseaudio API. + */ + +#endif diff --git a/src/pulse/sample.c b/src/pulse/sample.c new file mode 100644 index 00000000..2e055bf1 --- /dev/null +++ b/src/pulse/sample.c @@ -0,0 +1,156 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "sample.h" + +size_t pa_sample_size(const pa_sample_spec *spec) { + assert(spec); + + switch (spec->format) { + case PA_SAMPLE_U8: + case PA_SAMPLE_ULAW: + case PA_SAMPLE_ALAW: + return 1; + case PA_SAMPLE_S16LE: + case PA_SAMPLE_S16BE: + return 2; + case PA_SAMPLE_FLOAT32LE: + case PA_SAMPLE_FLOAT32BE: + return 4; + default: + assert(0); + return 0; + } +} + +size_t pa_frame_size(const pa_sample_spec *spec) { + assert(spec); + + return pa_sample_size(spec) * spec->channels; +} + +size_t pa_bytes_per_second(const pa_sample_spec *spec) { + assert(spec); + return spec->rate*pa_frame_size(spec); +} + +pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) { + assert(spec); + + return (pa_usec_t) (((double) length/pa_frame_size(spec)*1000000)/spec->rate); +} + +size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec) { + assert(spec); + + return ((double) t * spec->rate / 1000000)*pa_frame_size(spec); +} + +int pa_sample_spec_valid(const pa_sample_spec *spec) { + assert(spec); + + if (spec->rate <= 0 || + spec->channels <= 0 || + spec->channels > PA_CHANNELS_MAX || + spec->format >= PA_SAMPLE_MAX || + spec->format < 0) + return 0; + + return 1; +} + +int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b) { + assert(a && b); + + return (a->format == b->format) && (a->rate == b->rate) && (a->channels == b->channels); +} + +const char *pa_sample_format_to_string(pa_sample_format_t f) { + static const char* const table[]= { + [PA_SAMPLE_U8] = "u8", + [PA_SAMPLE_ALAW] = "aLaw", + [PA_SAMPLE_ULAW] = "uLaw", + [PA_SAMPLE_S16LE] = "s16le", + [PA_SAMPLE_S16BE] = "s16be", + [PA_SAMPLE_FLOAT32LE] = "float32le", + [PA_SAMPLE_FLOAT32BE] = "float32be", + }; + + if (f >= PA_SAMPLE_MAX) + return NULL; + + return table[f]; +} + +char *pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec) { + assert(s && l && spec); + + if (!pa_sample_spec_valid(spec)) + snprintf(s, l, "Invalid"); + else + snprintf(s, l, "%s %uch %uHz", pa_sample_format_to_string(spec->format), spec->channels, spec->rate); + + return s; +} + +void pa_bytes_snprint(char *s, size_t l, unsigned v) { + if (v >= ((unsigned) 1024)*1024*1024) + snprintf(s, l, "%0.1f GiB", ((double) v)/1024/1024/1024); + else if (v >= ((unsigned) 1024)*1024) + snprintf(s, l, "%0.1f MiB", ((double) v)/1024/1024); + else if (v >= (unsigned) 1024) + snprintf(s, l, "%0.1f KiB", ((double) v)/1024); + else + snprintf(s, l, "%u B", (unsigned) v); +} + +pa_sample_format_t pa_parse_sample_format(const char *format) { + + if (strcasecmp(format, "s16le") == 0) + return PA_SAMPLE_S16LE; + else if (strcasecmp(format, "s16be") == 0) + return PA_SAMPLE_S16BE; + else if (strcasecmp(format, "s16ne") == 0 || strcasecmp(format, "s16") == 0 || strcasecmp(format, "16") == 0) + return PA_SAMPLE_S16NE; + else if (strcasecmp(format, "u8") == 0 || strcasecmp(format, "8") == 0) + return PA_SAMPLE_U8; + else if (strcasecmp(format, "float32") == 0 || strcasecmp(format, "float32ne") == 0) + return PA_SAMPLE_FLOAT32; + else if (strcasecmp(format, "float32le") == 0) + return PA_SAMPLE_FLOAT32LE; + else if (strcasecmp(format, "float32be") == 0) + return PA_SAMPLE_FLOAT32BE; + else if (strcasecmp(format, "ulaw") == 0) + return PA_SAMPLE_ULAW; + else if (strcasecmp(format, "alaw") == 0) + return PA_SAMPLE_ALAW; + + return -1; +} diff --git a/src/pulse/sample.h b/src/pulse/sample.h new file mode 100644 index 00000000..848fd16d --- /dev/null +++ b/src/pulse/sample.h @@ -0,0 +1,189 @@ +#ifndef foosamplehfoo +#define foosamplehfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include + +#include + +/** \page sample Sample Format Specifications + * + * \section overv_sec Overview + * + * Polypaudio is capable of handling a multitude of sample formats, rates + * and channels, transparently converting and mixing them as needed. + * + * \section format_sec Sample Format + * + * Polypaudio supports the following sample formats: + * + * \li PA_SAMPLE_U8 - Unsigned 8 bit PCM. + * \li PA_SAMPLE_S16LE - Signed 16 bit PCM, little endian. + * \li PA_SAMPLE_S16BE - Signed 16 bit PCM, big endian. + * \li PA_SAMPLE_FLOAT32LE - 32 bit IEEE floating point PCM, little endian. + * \li PA_SAMPLE_FLOAT32BE - 32 bit IEEE floating point PCM, big endian. + * \li PA_SAMPLE_ALAW - 8 bit a-Law. + * \li PA_SAMPLE_ULAW - 8 bit mu-Law. + * + * The floating point sample formats have the range from -1 to 1. + * + * The sample formats that are sensitive to endianness have convenience + * macros for native endian (NE), and reverse endian (RE). + * + * \section rate_sec Sample Rates + * + * Polypaudio supports any sample rate between 1 Hz and 4 GHz. There is no + * point trying to exceed the sample rate of the output device though as the + * signal will only get downsampled, consuming CPU on the machine running the + * server. + * + * \section chan_sec Channels + * + * Polypaudio supports up to 16 individiual channels. The order of the + * channels is up to the application, but they must be continous. To map + * channels to speakers, see \ref channelmap. + * + * \section calc_sec Calculations + * + * The Polypaudio library contains a number of convenience functions to do + * calculations on sample formats: + * + * \li pa_bytes_per_second() - The number of bytes one second of audio will + * take given a sample format. + * \li pa_frame_size() - The size, in bytes, of one frame (i.e. one set of + * samples, one for each channel). + * \li pa_sample_size() - The size, in bytes, of one sample. + * \li pa_bytes_to_usec() - Calculate the time it would take to play a buffer + * of a certain size. + * + * \section util_sec Convenience Functions + * + * The library also contains a couple of other convenience functions: + * + * \li pa_sample_spec_valid() - Tests if a sample format specification is + * valid. + * \li pa_sample_spec_equal() - Tests if the sample format specifications are + * identical. + * \li pa_sample_format_to_string() - Return a textual description of a + * sample format. + * \li pa_parse_sample_format() - Parse a text string into a sample format. + * \li pa_sample_spec_snprint() - Create a textual description of a complete + * sample format specification. + * \li pa_bytes_snprint() - Pretty print a byte value (e.g. 2.5 MiB). + */ + +/** \file + * Constants and routines for sample type handling */ + +PA_C_DECL_BEGIN + +/** Maximum number of allowed channels */ +#define PA_CHANNELS_MAX 32 + +/** Sample format */ +typedef enum pa_sample_format { + PA_SAMPLE_U8, /**< Unsigned 8 Bit PCM */ + PA_SAMPLE_ALAW, /**< 8 Bit a-Law */ + PA_SAMPLE_ULAW, /**< 8 Bit mu-Law */ + PA_SAMPLE_S16LE, /**< Signed 16 Bit PCM, little endian (PC) */ + PA_SAMPLE_S16BE, /**< Signed 16 Bit PCM, big endian */ + PA_SAMPLE_FLOAT32LE, /**< 32 Bit IEEE floating point, little endian, range -1 to 1 */ + PA_SAMPLE_FLOAT32BE, /**< 32 Bit IEEE floating point, big endian, range -1 to 1 */ + PA_SAMPLE_MAX, /**< Upper limit of valid sample types */ + PA_SAMPLE_INVALID = -1 /**< An invalid value */ +} pa_sample_format_t; + +#ifdef WORDS_BIGENDIAN +/** Signed 16 Bit PCM, native endian */ +#define PA_SAMPLE_S16NE PA_SAMPLE_S16BE +/** 32 Bit IEEE floating point, native endian */ +#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32BE +/** Signed 16 Bit PCM reverse endian */ +#define PA_SAMPLE_S16RE PA_SAMPLE_S16LE +/** 32 Bit IEEE floating point, reverse endian */ +#define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32LE +#else +/** Signed 16 Bit PCM, native endian */ +#define PA_SAMPLE_S16NE PA_SAMPLE_S16LE +/** 32 Bit IEEE floating point, native endian */ +#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32LE +/** Signed 16 Bit PCM reverse endian */ +#define PA_SAMPLE_S16RE PA_SAMPLE_S16BE +/** 32 Bit IEEE floating point, reverse endian */ +#define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32BE +#endif + +/** A Shortcut for PA_SAMPLE_FLOAT32NE */ +#define PA_SAMPLE_FLOAT32 PA_SAMPLE_FLOAT32NE + +/** A sample format and attribute specification */ +typedef struct pa_sample_spec { + pa_sample_format_t format; /**< The sample format */ + uint32_t rate; /**< The sample rate. (e.g. 44100) */ + uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */ +} pa_sample_spec; + +/** Type for usec specifications (unsigned). May be either 32 or 64 bit, depending on the architecture */ +typedef uint64_t pa_usec_t; + +/** Return the amount of bytes playback of a second of audio with the specified sample type takes */ +size_t pa_bytes_per_second(const pa_sample_spec *spec); + +/** Return the size of a frame with the specific sample type */ +size_t pa_frame_size(const pa_sample_spec *spec); + +/** Return the size of a sample with the specific sample type */ +size_t pa_sample_size(const pa_sample_spec *spec); + +/** Calculate the time the specified bytes take to play with the specified sample type */ +pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec); + +/** Calculates the number of bytes that are required for the specified time. \since 0.9 */ +size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec); + +/** Return non-zero when the sample type specification is valid */ +int pa_sample_spec_valid(const pa_sample_spec *spec); + +/** Return non-zero when the two sample type specifications match */ +int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b); + +/** Return a descriptive string for the specified sample format. \since 0.8 */ +const char *pa_sample_format_to_string(pa_sample_format_t f); + +/** Parse a sample format text. Inverse of pa_sample_format_to_string() */ +pa_sample_format_t pa_parse_sample_format(const char *format); + +/** Maximum required string length for pa_sample_spec_snprint() */ +#define PA_SAMPLE_SPEC_SNPRINT_MAX 32 + +/** Pretty print a sample type specification to a string */ +char* pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec); + +/** Pretty print a byte size value. (i.e. "2.5 MiB") */ +void pa_bytes_snprint(char *s, size_t l, unsigned v); + +PA_C_DECL_END + +#endif diff --git a/src/pulse/scache.c b/src/pulse/scache.c new file mode 100644 index 00000000..5d29c5b3 --- /dev/null +++ b/src/pulse/scache.c @@ -0,0 +1,131 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include "internal.h" + +#include "scache.h" + +int pa_stream_connect_upload(pa_stream *s, size_t length) { + pa_tagstruct *t; + uint32_t tag; + + assert(s); + + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, length > 0, PA_ERR_INVALID); + + pa_stream_ref(s); + + s->direction = PA_STREAM_UPLOAD; + + t = pa_tagstruct_command(s->context, PA_COMMAND_CREATE_UPLOAD_STREAM, &tag); + pa_tagstruct_puts(t, s->name); + pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_put_channel_map(t, &s->channel_map); + pa_tagstruct_putu32(t, length); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL); + + pa_stream_set_state(s, PA_STREAM_CREATING); + + pa_stream_unref(s); + return 0; +} + +int pa_stream_finish_upload(pa_stream *s) { + pa_tagstruct *t; + uint32_t tag; + assert(s); + + PA_CHECK_VALIDITY(s->context, s->channel_valid, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + pa_stream_ref(s); + + t = pa_tagstruct_command(s->context, PA_COMMAND_FINISH_UPLOAD_STREAM, &tag); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s, NULL); + + pa_stream_unref(s); + return 0; +} + +pa_operation *pa_context_play_sample(pa_context *c, const char *name, const char *dev, pa_volume_t volume, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, !dev || *dev, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + if (!dev) + dev = c->conf->default_sink; + + t = pa_tagstruct_command(c, PA_COMMAND_PLAY_SAMPLE, &tag); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, dev); + pa_tagstruct_putu32(t, volume); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_remove_sample(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_SAMPLE, &tag); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + diff --git a/src/pulse/scache.h b/src/pulse/scache.h new file mode 100644 index 00000000..e32703d4 --- /dev/null +++ b/src/pulse/scache.h @@ -0,0 +1,100 @@ +#ifndef fooscachehfoo +#define fooscachehfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include +#include + +/** \page scache Sample Cache + * + * \section overv_sec Overview + * + * The sample cache provides a simple way of overcoming high network latencies + * and reducing bandwidth. Instead of streaming a sound precisely when it + * should be played, it is stored on the server and only the command to start + * playing it needs to be sent. + * + * \section create_sec Creation + * + * To create a sample, the normal stream API is used (see \ref streams). The + * function pa_stream_connect_upload() will make sure the stream is stored as + * a sample on the server. + * + * To complete the upload, pa_stream_finish_upload() is called and the sample + * will receive the same name as the stream. If the upload should be aborted, + * simply call pa_stream_disconnect(). + * + * \section play_sec Playing samples + * + * To play back a sample, simply call pa_context_play_sample(): + * + * \code + * pa_operation *o; + * + * o = pa_context_play_sample(my_context, + * "sample2", // Name of my sample + * NULL, // Use default sink + * PA_VOLUME_NORM, // Full volume + * NULL, // Don't need a callback + * NULL + * ); + * if (o) + * pa_operation_unref(o); + * \endcode + * + * \section rem_sec Removing samples + * + * When a sample is no longer needed, it should be removed on the server to + * save resources. The sample is deleted using pa_context_remove_sample(). + */ + +/** \file + * All sample cache related routines */ + +PA_C_DECL_BEGIN + +/** Make this stream a sample upload stream */ +int pa_stream_connect_upload(pa_stream *s, size_t length); + +/** Finish the sample upload, the stream name will become the sample name. You cancel a samp + * le upload by issuing pa_stream_disconnect() */ +int pa_stream_finish_upload(pa_stream *s); + +/** Play a sample from the sample cache to the specified device. If the latter is NULL use the default sink. Returns an operation object */ +pa_operation* pa_context_play_sample( + pa_context *c /**< Context */, + const char *name /**< Name of the sample to play */, + const char *dev /**< Sink to play this sample on */, + pa_volume_t volume /**< Volume to play this sample with */ , + pa_context_success_cb_t cb /**< Call this function after successfully starting playback, or NULL */, + void *userdata /**< Userdata to pass to the callback */); + +/** Remove a sample from the sample cache. Returns an operation object which may be used to cancel the operation while it is running */ +pa_operation* pa_context_remove_sample(pa_context *c, const char *name, pa_context_success_cb_t, void *userdata); + +PA_C_DECL_END + +#endif diff --git a/src/pulse/simple.c b/src/pulse/simple.c new file mode 100644 index 00000000..a41881bb --- /dev/null +++ b/src/pulse/simple.c @@ -0,0 +1,455 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "simple.h" + +struct pa_simple { + pa_threaded_mainloop *mainloop; + pa_context *context; + pa_stream *stream; + pa_stream_direction_t direction; + + const void *read_data; + size_t read_index, read_length; + + int operation_success; +}; + +#define CHECK_VALIDITY_RETURN_ANY(rerror, expression, error, ret) do { \ +if (!(expression)) { \ + if (rerror) \ + *(rerror) = error; \ + return (ret); \ + } \ +} while(0); + +#define CHECK_SUCCESS_GOTO(p, rerror, expression, label) do { \ +if (!(expression)) { \ + if (rerror) \ + *(rerror) = pa_context_errno((p)->context); \ + goto label; \ + } \ +} while(0); + +#define CHECK_DEAD_GOTO(p, rerror, label) do { \ +if (!(p)->context || pa_context_get_state((p)->context) != PA_CONTEXT_READY || \ + !(p)->stream || pa_stream_get_state((p)->stream) != PA_STREAM_READY) { \ + if (((p)->context && pa_context_get_state((p)->context) == PA_CONTEXT_FAILED) || \ + ((p)->stream && pa_stream_get_state((p)->stream) == PA_STREAM_FAILED)) { \ + if (rerror) \ + *(rerror) = pa_context_errno((p)->context); \ + } else \ + if (rerror) \ + *(rerror) = PA_ERR_BADSTATE; \ + goto label; \ + } \ +} while(0); + +static void context_state_cb(pa_context *c, void *userdata) { + pa_simple *p = userdata; + assert(c); + assert(p); + + switch (pa_context_get_state(c)) { + case PA_CONTEXT_READY: + case PA_CONTEXT_TERMINATED: + case PA_CONTEXT_FAILED: + pa_threaded_mainloop_signal(p->mainloop, 0); + break; + + case PA_CONTEXT_UNCONNECTED: + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + } +} + +static void stream_state_cb(pa_stream *s, void * userdata) { + pa_simple *p = userdata; + assert(s); + assert(p); + + switch (pa_stream_get_state(s)) { + + case PA_STREAM_READY: + case PA_STREAM_FAILED: + case PA_STREAM_TERMINATED: + pa_threaded_mainloop_signal(p->mainloop, 0); + break; + + case PA_STREAM_UNCONNECTED: + case PA_STREAM_CREATING: + break; + } +} + +static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { + pa_simple *p = userdata; + assert(p); + + pa_threaded_mainloop_signal(p->mainloop, 0); +} + +static void stream_latency_update_cb(pa_stream *s, void *userdata) { + pa_simple *p = userdata; + + assert(p); + + pa_threaded_mainloop_signal(p->mainloop, 0); +} + +pa_simple* pa_simple_new( + const char *server, + const char *name, + pa_stream_direction_t dir, + const char *dev, + const char *stream_name, + const pa_sample_spec *ss, + const pa_channel_map *map, + const pa_buffer_attr *attr, + int *rerror) { + + pa_simple *p; + int error = PA_ERR_INTERNAL, r; + + CHECK_VALIDITY_RETURN_ANY(rerror, !server || *server, PA_ERR_INVALID, NULL); + CHECK_VALIDITY_RETURN_ANY(rerror, dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD, PA_ERR_INVALID, NULL); + CHECK_VALIDITY_RETURN_ANY(rerror, !dev || *dev, PA_ERR_INVALID, NULL); + CHECK_VALIDITY_RETURN_ANY(rerror, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID, NULL); + CHECK_VALIDITY_RETURN_ANY(rerror, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID, NULL) + + p = pa_xnew(pa_simple, 1); + p->context = NULL; + p->stream = NULL; + p->direction = dir; + p->read_data = NULL; + p->read_index = p->read_length = 0; + + if (!(p->mainloop = pa_threaded_mainloop_new())) + goto fail; + + if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), name))) + goto fail; + + pa_context_set_state_callback(p->context, context_state_cb, p); + + if (pa_context_connect(p->context, server, 0, NULL) < 0) { + error = pa_context_errno(p->context); + goto fail; + } + + pa_threaded_mainloop_lock(p->mainloop); + + if (pa_threaded_mainloop_start(p->mainloop) < 0) + goto unlock_and_fail; + + /* Wait until the context is ready */ + pa_threaded_mainloop_wait(p->mainloop); + + if (pa_context_get_state(p->context) != PA_CONTEXT_READY) { + error = pa_context_errno(p->context); + goto unlock_and_fail; + } + + if (!(p->stream = pa_stream_new(p->context, stream_name, ss, map))) { + error = pa_context_errno(p->context); + goto unlock_and_fail; + } + + pa_stream_set_state_callback(p->stream, stream_state_cb, p); + pa_stream_set_read_callback(p->stream, stream_request_cb, p); + pa_stream_set_write_callback(p->stream, stream_request_cb, p); + pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p); + + if (dir == PA_STREAM_PLAYBACK) + r = pa_stream_connect_playback(p->stream, dev, attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); + else + r = pa_stream_connect_record(p->stream, dev, attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE); + + if (r < 0) { + error = pa_context_errno(p->context); + goto unlock_and_fail; + } + + /* Wait until the stream is ready */ + pa_threaded_mainloop_wait(p->mainloop); + + /* Wait until the stream is ready */ + if (pa_stream_get_state(p->stream) != PA_STREAM_READY) { + error = pa_context_errno(p->context); + goto unlock_and_fail; + } + + pa_threaded_mainloop_unlock(p->mainloop); + + return p; + +unlock_and_fail: + pa_threaded_mainloop_unlock(p->mainloop); + +fail: + if (rerror) + *rerror = error; + pa_simple_free(p); + return NULL; +} + +void pa_simple_free(pa_simple *s) { + assert(s); + + if (s->mainloop) + pa_threaded_mainloop_stop(s->mainloop); + + if (s->stream) + pa_stream_unref(s->stream); + + if (s->context) + pa_context_unref(s->context); + + if (s->mainloop) + pa_threaded_mainloop_free(s->mainloop); + + pa_xfree(s); +} + +int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { + assert(p); + + CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); + CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1); + + pa_threaded_mainloop_lock(p->mainloop); + + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); + + while (length > 0) { + size_t l; + int r; + + while (!(l = pa_stream_writable_size(p->stream))) { + pa_threaded_mainloop_wait(p->mainloop); + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); + } + + CHECK_SUCCESS_GOTO(p, rerror, l != (size_t) -1, unlock_and_fail); + + if (l > length) + l = length; + + r = pa_stream_write(p->stream, data, l, NULL, 0, PA_SEEK_RELATIVE); + CHECK_SUCCESS_GOTO(p, rerror, r >= 0, unlock_and_fail); + + data = (const uint8_t*) data + l; + length -= l; + } + + pa_threaded_mainloop_unlock(p->mainloop); + return 0; + +unlock_and_fail: + pa_threaded_mainloop_unlock(p->mainloop); + return -1; +} + +int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { + assert(p); + + CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, -1); + CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1); + + pa_threaded_mainloop_lock(p->mainloop); + + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); + + while (length > 0) { + size_t l; + + while (!p->read_data) { + int r; + + r = pa_stream_peek(p->stream, &p->read_data, &p->read_length); + CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail); + + if (!p->read_data) { + pa_threaded_mainloop_wait(p->mainloop); + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); + } else + p->read_index = 0; + } + + l = p->read_length < length ? p->read_length : length; + memcpy(data, (const uint8_t*) p->read_data+p->read_index, l); + + data = (uint8_t*) data + l; + length -= l; + + p->read_index += l; + p->read_length -= l; + + if (!p->read_length) { + int r; + + r = pa_stream_drop(p->stream); + p->read_data = NULL; + p->read_length = 0; + p->read_index = 0; + + CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail); + } + } + + pa_threaded_mainloop_unlock(p->mainloop); + return 0; + +unlock_and_fail: + pa_threaded_mainloop_unlock(p->mainloop); + return -1; +} + +static void success_cb(pa_stream *s, int success, void *userdata) { + pa_simple *p = userdata; + + assert(s); + assert(p); + + p->operation_success = success; + pa_threaded_mainloop_signal(p->mainloop, 0); +} + +int pa_simple_drain(pa_simple *p, int *rerror) { + pa_operation *o = NULL; + + assert(p); + + CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); + + pa_threaded_mainloop_lock(p->mainloop); + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); + + o = pa_stream_drain(p->stream, success_cb, p); + CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); + + p->operation_success = 0; + while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + pa_threaded_mainloop_wait(p->mainloop); + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); + } + CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail); + + pa_operation_unref(o); + pa_threaded_mainloop_unlock(p->mainloop); + + return 0; + +unlock_and_fail: + + if (o) { + pa_operation_cancel(o); + pa_operation_unref(o); + } + + pa_threaded_mainloop_unlock(p->mainloop); + return -1; +} + +int pa_simple_flush(pa_simple *p, int *rerror) { + pa_operation *o = NULL; + + assert(p); + + CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); + + pa_threaded_mainloop_lock(p->mainloop); + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); + + o = pa_stream_flush(p->stream, success_cb, p); + CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); + + p->operation_success = 0; + while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + pa_threaded_mainloop_wait(p->mainloop); + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); + } + CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail); + + pa_operation_unref(o); + pa_threaded_mainloop_unlock(p->mainloop); + + return 0; + +unlock_and_fail: + + if (o) { + pa_operation_cancel(o); + pa_operation_unref(o); + } + + pa_threaded_mainloop_unlock(p->mainloop); + return -1; +} + +pa_usec_t pa_simple_get_latency(pa_simple *p, int *rerror) { + pa_usec_t t; + int negative; + + assert(p); + + pa_threaded_mainloop_lock(p->mainloop); + + for (;;) { + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); + + if (pa_stream_get_latency(p->stream, &t, &negative) >= 0) + break; + + CHECK_SUCCESS_GOTO(p, rerror, pa_context_errno(p->context) == PA_ERR_NODATA, unlock_and_fail); + + /* Wait until latency data is available again */ + pa_threaded_mainloop_wait(p->mainloop); + } + + pa_threaded_mainloop_unlock(p->mainloop); + + return negative ? 0 : t; + +unlock_and_fail: + + pa_threaded_mainloop_unlock(p->mainloop); + return (pa_usec_t) -1; +} + diff --git a/src/pulse/simple.h b/src/pulse/simple.h new file mode 100644 index 00000000..0438d319 --- /dev/null +++ b/src/pulse/simple.h @@ -0,0 +1,146 @@ +#ifndef foosimplehfoo +#define foosimplehfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include +#include +#include + +/** \page simple Simple API + * + * \section overv_sec Overview + * + * The simple API is designed for applications with very basic sound + * playback or capture needs. It can only support a single stream per + * connection and has no handling of complex features like events, channel + * mappings and volume control. It is, however, very simple to use and + * quite sufficent for many programs. + * + * \section conn_sec Connecting + * + * The first step before using the sound system is to connect to the + * server. This is normally done this way: + * + * \code + * pa_simple *s; + * pa_sample_spec ss; + * + * ss.format = PA_SAMPLE_S16_NE; + * ss.channels = 2; + * ss.rate = 44100; + * + * s = pa_simple_new(NULL, // Use the default server. + * "Fooapp", // Our application's name. + * PA_STREAM_PLAYBACK, + * NULL, // Use the default device. + * "Music", // Description of our stream. + * &ss, // Our sample format. + * NULL, // Use default channel map + * NULL, // Use default buffering attributes. + * NULL, // Ignore error code. + * ); + * \endcode + * + * At this point a connected object is returned, or NULL if there was a + * problem connecting. + * + * \section transfer_sec Transferring data + * + * Once the connection is established to the server, data can start flowing. + * Using the connection is very similar to the normal read() and write() + * system calls. The main difference is that they're call pa_simple_read() + * and pa_simple_write(). Note that these operations always block. + * + * \section ctrl_sec Buffer control + * + * If a playback stream is used then a few other operations are available: + * + * \li pa_simple_drain() - Will wait for all sent data to finish playing. + * \li pa_simple_flush() - Will throw away all data currently in buffers. + * \li pa_simple_get_playback_latency() - Will return the total latency of + * the playback pipeline. + * + * \section cleanup_sec Cleanup + * + * Once playback or capture is complete, the connection should be closed + * and resources freed. This is done through: + * + * \code + * pa_simple_free(s); + * \endcode + */ + +/** \file + * A simple but limited synchronous playback and recording + * API. This is a synchronous, simplified wrapper around the standard + * asynchronous API. */ + +/** \example pacat-simple.c + * A simple playback tool using the simple API */ + +/** \example parec-simple.c + * A simple recording tool using the simple API */ + +PA_C_DECL_BEGIN + +/** \struct pa_simple + * An opaque simple connection object */ +typedef struct pa_simple pa_simple; + +/** Create a new connection to the server */ +pa_simple* pa_simple_new( + const char *server, /**< Server name, or NULL for default */ + const char *name, /**< A descriptive name for this client (application name, ...) */ + pa_stream_direction_t dir, /**< Open this stream for recording or playback? */ + const char *dev, /**< Sink (resp. source) name, or NULL for default */ + const char *stream_name, /**< A descriptive name for this client (application name, song title, ...) */ + const pa_sample_spec *ss, /**< The sample type to use */ + const pa_channel_map *map, /**< The channel map to use, or NULL for default */ + const pa_buffer_attr *attr, /**< Buffering attributes, or NULL for default */ + int *error /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */ + ); + +/** Close and free the connection to the server. The connection objects becomes invalid when this is called. */ +void pa_simple_free(pa_simple *s); + +/** Write some data to the server */ +int pa_simple_write(pa_simple *s, const void*data, size_t length, int *error); + +/** Wait until all data already written is played by the daemon */ +int pa_simple_drain(pa_simple *s, int *error); + +/** Read some data from the server */ +int pa_simple_read(pa_simple *s, void*data, size_t length, int *error); + +/** Return the playback latency. \since 0.5 */ +pa_usec_t pa_simple_get_latency(pa_simple *s, int *error); + +/** Flush the playback buffer. \since 0.5 */ +int pa_simple_flush(pa_simple *s, int *error); + +PA_C_DECL_END + +#endif diff --git a/src/pulse/stream.c b/src/pulse/stream.c new file mode 100644 index 00000000..c8fc09d2 --- /dev/null +++ b/src/pulse/stream.c @@ -0,0 +1,1366 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "internal.h" + +#define LATENCY_IPOL_INTERVAL_USEC (100000L) + +pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map) { + pa_stream *s; + int i; + + assert(c); + + PA_CHECK_VALIDITY_RETURN_NULL(c, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID); + + s = pa_xnew(pa_stream, 1); + s->ref = 1; + s->context = c; + s->mainloop = c->mainloop; + + s->read_callback = NULL; + s->read_userdata = NULL; + s->write_callback = NULL; + s->write_userdata = NULL; + s->state_callback = NULL; + s->state_userdata = NULL; + s->overflow_callback = NULL; + s->overflow_userdata = NULL; + s->underflow_callback = NULL; + s->underflow_userdata = NULL; + s->latency_update_callback = NULL; + s->latency_update_userdata = NULL; + + s->direction = PA_STREAM_NODIRECTION; + s->name = pa_xstrdup(name); + s->sample_spec = *ss; + s->flags = 0; + + if (map) + s->channel_map = *map; + else + pa_channel_map_init_auto(&s->channel_map, ss->channels, PA_CHANNEL_MAP_DEFAULT); + + s->channel = 0; + s->channel_valid = 0; + s->syncid = c->csyncid++; + s->device_index = PA_INVALID_INDEX; + s->requested_bytes = 0; + s->state = PA_STREAM_UNCONNECTED; + memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); + + s->peek_memchunk.index = 0; + s->peek_memchunk.length = 0; + s->peek_memchunk.memblock = NULL; + + s->record_memblockq = NULL; + + s->previous_time = 0; + s->timing_info_valid = 0; + s->read_index_not_before = 0; + s->write_index_not_before = 0; + + for (i = 0; i < PA_MAX_WRITE_INDEX_CORRECTIONS; i++) + s->write_index_corrections[i].valid = 0; + s->current_write_index_correction = 0; + + s->corked = 0; + + s->cached_time_valid = 0; + + s->auto_timing_update_event = NULL; + s->auto_timing_update_requested = 0; + + /* Refcounting is strictly one-way: from the "bigger" to the "smaller" object. */ + PA_LLIST_PREPEND(pa_stream, c->streams, s); + pa_stream_ref(s); + + return s; +} + +static void stream_free(pa_stream *s) { + assert(s && !s->context && !s->channel_valid); + + if (s->auto_timing_update_event) { + assert(s->mainloop); + s->mainloop->time_free(s->auto_timing_update_event); + } + + if (s->peek_memchunk.memblock) + pa_memblock_unref(s->peek_memchunk.memblock); + + if (s->record_memblockq) + pa_memblockq_free(s->record_memblockq); + + pa_xfree(s->name); + pa_xfree(s); +} + +void pa_stream_unref(pa_stream *s) { + assert(s); + assert(s->ref >= 1); + + if (--(s->ref) == 0) + stream_free(s); +} + +pa_stream* pa_stream_ref(pa_stream *s) { + assert(s); + assert(s->ref >= 1); + + s->ref++; + return s; +} + +pa_stream_state_t pa_stream_get_state(pa_stream *s) { + assert(s); + assert(s->ref >= 1); + + return s->state; +} + +pa_context* pa_stream_get_context(pa_stream *s) { + assert(s); + assert(s->ref >= 1); + + return s->context; +} + +uint32_t pa_stream_get_index(pa_stream *s) { + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX); + + return s->device_index; +} + +void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { + assert(s); + assert(s->ref >= 1); + + if (s->state == st) + return; + + pa_stream_ref(s); + + s->state = st; + if (s->state_callback) + s->state_callback(s, s->state_userdata); + + if ((st == PA_STREAM_FAILED || st == PA_STREAM_TERMINATED) && s->context) { + + /* Detach from context */ + pa_operation *o, *n; + + /* Unref all operatio object that point to us */ + for (o = s->context->operations; o; o = n) { + n = o->next; + + if (o->stream == s) + pa_operation_cancel(o); + } + + /* Drop all outstanding replies for this stream */ + if (s->context->pdispatch) + pa_pdispatch_unregister_reply(s->context->pdispatch, s); + + if (s->channel_valid) + pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); + + PA_LLIST_REMOVE(pa_stream, s->context->streams, s); + pa_stream_unref(s); + + s->channel = 0; + s->channel_valid = 0; + + s->context = NULL; + } + + pa_stream_unref(s); +} + +void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_context *c = userdata; + pa_stream *s; + uint32_t channel; + + assert(pd); + assert(command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED); + assert(t); + assert(c); + + pa_context_ref(c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(c, PA_ERR_PROTOCOL); + goto finish; + } + + if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) + goto finish; + + pa_context_set_error(c, PA_ERR_KILLED); + pa_stream_set_state(s, PA_STREAM_FAILED); + +finish: + pa_context_unref(c); +} + +void pa_command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_stream *s; + pa_context *c = userdata; + uint32_t bytes, channel; + + assert(pd); + assert(command == PA_COMMAND_REQUEST); + assert(t); + assert(c); + + pa_context_ref(c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + pa_tagstruct_getu32(t, &bytes) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(c, PA_ERR_PROTOCOL); + goto finish; + } + + if (!(s = pa_dynarray_get(c->playback_streams, channel))) + goto finish; + + if (s->state == PA_STREAM_READY) { + s->requested_bytes += bytes; + + if (s->requested_bytes > 0 && s->write_callback) + s->write_callback(s, s->requested_bytes, s->write_userdata); + } + +finish: + pa_context_unref(c); +} + +void pa_command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_stream *s; + pa_context *c = userdata; + uint32_t channel; + + assert(pd); + assert(command == PA_COMMAND_OVERFLOW || command == PA_COMMAND_UNDERFLOW); + assert(t); + assert(c); + + pa_context_ref(c); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(c, PA_ERR_PROTOCOL); + goto finish; + } + + if (!(s = pa_dynarray_get(c->playback_streams, channel))) + goto finish; + + if (s->state == PA_STREAM_READY) { + + if (command == PA_COMMAND_OVERFLOW) { + if (s->overflow_callback) + s->overflow_callback(s, s->overflow_userdata); + } else if (command == PA_COMMAND_UNDERFLOW) { + if (s->underflow_callback) + s->underflow_callback(s, s->underflow_userdata); + } + } + + finish: + pa_context_unref(c); +} + +static void request_auto_timing_update(pa_stream *s, int force) { + struct timeval next; + assert(s); + + if (!(s->flags & PA_STREAM_AUTO_TIMING_UPDATE)) + return; + + if (s->state == PA_STREAM_READY && + (force || !s->auto_timing_update_requested)) { + pa_operation *o; + +/* pa_log("automatically requesting new timing data"); */ + + if ((o = pa_stream_update_timing_info(s, NULL, NULL))) { + pa_operation_unref(o); + s->auto_timing_update_requested = 1; + } + } + + pa_gettimeofday(&next); + pa_timeval_add(&next, LATENCY_IPOL_INTERVAL_USEC); + s->mainloop->time_restart(s->auto_timing_update_event, &next); +} + +static void invalidate_indexes(pa_stream *s, int r, int w) { + assert(s); + +/* pa_log("invalidate r:%u w:%u tag:%u", r, w, s->context->ctag); */ + + if (s->state != PA_STREAM_READY) + return; + + if (w) { + s->write_index_not_before = s->context->ctag; + + if (s->timing_info_valid) + s->timing_info.write_index_corrupt = 1; + +/* pa_log("write_index invalidated"); */ + } + + if (r) { + s->read_index_not_before = s->context->ctag; + + if (s->timing_info_valid) + s->timing_info.read_index_corrupt = 1; + +/* pa_log("read_index invalidated"); */ + } + + if ((s->direction == PA_STREAM_PLAYBACK && r) || + (s->direction == PA_STREAM_RECORD && w)) + s->cached_time_valid = 0; + + request_auto_timing_update(s, 1); +} + +static void auto_timing_update_callback(PA_GCC_UNUSED pa_mainloop_api *m, PA_GCC_UNUSED pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + pa_stream *s = userdata; + +/* pa_log("time event"); */ + + pa_stream_ref(s); + request_auto_timing_update(s, 0); + pa_stream_unref(s); +} + +void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_stream *s = userdata; + + assert(pd); + assert(s); + assert(s->state == PA_STREAM_CREATING); + + pa_stream_ref(s); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(s->context, command, t) < 0) + goto finish; + + pa_stream_set_state(s, PA_STREAM_FAILED); + goto finish; + } + + if (pa_tagstruct_getu32(t, &s->channel) < 0 || + ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || + ((s->direction != PA_STREAM_RECORD) && pa_tagstruct_getu32(t, &s->requested_bytes) < 0)) { + pa_context_fail(s->context, PA_ERR_PROTOCOL); + goto finish; + } + + if (pa_context_get_server_protocol_version(s->context) >= 9) { + if (s->direction == PA_STREAM_PLAYBACK) { + if (pa_tagstruct_getu32(t, &s->buffer_attr.maxlength) < 0 || + pa_tagstruct_getu32(t, &s->buffer_attr.tlength) < 0 || + pa_tagstruct_getu32(t, &s->buffer_attr.prebuf) < 0 || + pa_tagstruct_getu32(t, &s->buffer_attr.minreq) < 0) { + pa_context_fail(s->context, PA_ERR_PROTOCOL); + goto finish; + } + } else if (s->direction == PA_STREAM_RECORD) { + if (pa_tagstruct_getu32(t, &s->buffer_attr.maxlength) < 0 || + pa_tagstruct_getu32(t, &s->buffer_attr.fragsize) < 0) { + pa_context_fail(s->context, PA_ERR_PROTOCOL); + goto finish; + } + } + } + + if (!pa_tagstruct_eof(t)) { + pa_context_fail(s->context, PA_ERR_PROTOCOL); + goto finish; + } + + if (s->direction == PA_STREAM_RECORD) { + assert(!s->record_memblockq); + + s->record_memblockq = pa_memblockq_new( + 0, + s->buffer_attr.maxlength, + 0, + pa_frame_size(&s->sample_spec), + 1, + 0, + NULL, + s->context->memblock_stat); + } + + s->channel_valid = 1; + pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); + + pa_stream_set_state(s, PA_STREAM_READY); + + if (s->direction != PA_STREAM_UPLOAD && + s->flags & PA_STREAM_AUTO_TIMING_UPDATE) { + struct timeval tv; + + pa_gettimeofday(&tv); + tv.tv_usec += LATENCY_IPOL_INTERVAL_USEC; /* every 100 ms */ + + assert(!s->auto_timing_update_event); + s->auto_timing_update_event = s->mainloop->time_new(s->mainloop, &tv, &auto_timing_update_callback, s); + + request_auto_timing_update(s, 1); + } + + if (s->requested_bytes > 0 && s->ref > 1 && s->write_callback) + s->write_callback(s, s->requested_bytes, s->write_userdata); + +finish: + pa_stream_unref(s); +} + +static int create_stream( + pa_stream_direction_t direction, + pa_stream *s, + const char *dev, + const pa_buffer_attr *attr, + pa_stream_flags_t flags, + const pa_cvolume *volume, + pa_stream *sync_stream) { + + pa_tagstruct *t; + uint32_t tag; + + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, !(flags & ~((direction != PA_STREAM_UPLOAD ? + PA_STREAM_START_CORKED| + PA_STREAM_INTERPOLATE_TIMING| + PA_STREAM_NOT_MONOTONOUS| + PA_STREAM_AUTO_TIMING_UPDATE : 0))), PA_ERR_INVALID); + PA_CHECK_VALIDITY(s->context, !volume || volume->channels == s->sample_spec.channels, PA_ERR_INVALID); + PA_CHECK_VALIDITY(s->context, !sync_stream || (direction == PA_STREAM_PLAYBACK && sync_stream->direction == PA_STREAM_PLAYBACK), PA_ERR_INVALID); + + pa_stream_ref(s); + + s->direction = direction; + s->flags = flags; + + if (sync_stream) + s->syncid = sync_stream->syncid; + + if (attr) + s->buffer_attr = *attr; + else { + /* half a second */ + s->buffer_attr.tlength = pa_bytes_per_second(&s->sample_spec)/2; + s->buffer_attr.maxlength = (s->buffer_attr.tlength*3)/2; + s->buffer_attr.minreq = s->buffer_attr.tlength/100; + s->buffer_attr.prebuf = s->buffer_attr.tlength - s->buffer_attr.minreq; + s->buffer_attr.fragsize = s->buffer_attr.tlength/100; + } + + if (!dev) + dev = s->direction == PA_STREAM_PLAYBACK ? s->context->conf->default_sink : s->context->conf->default_source; + + t = pa_tagstruct_command( + s->context, + s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM, + &tag); + + pa_tagstruct_put( + t, + PA_TAG_STRING, s->name, + PA_TAG_SAMPLE_SPEC, &s->sample_spec, + PA_TAG_CHANNEL_MAP, &s->channel_map, + PA_TAG_U32, PA_INVALID_INDEX, + PA_TAG_STRING, dev, + PA_TAG_U32, s->buffer_attr.maxlength, + PA_TAG_BOOLEAN, !!(flags & PA_STREAM_START_CORKED), + PA_TAG_INVALID); + + if (s->direction == PA_STREAM_PLAYBACK) { + pa_cvolume cv; + + pa_tagstruct_put( + t, + PA_TAG_U32, s->buffer_attr.tlength, + PA_TAG_U32, s->buffer_attr.prebuf, + PA_TAG_U32, s->buffer_attr.minreq, + PA_TAG_U32, s->syncid, + PA_TAG_INVALID); + + if (!volume) + volume = pa_cvolume_reset(&cv, s->sample_spec.channels); + + pa_tagstruct_put_cvolume(t, volume); + } else + pa_tagstruct_putu32(t, s->buffer_attr.fragsize); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL); + + pa_stream_set_state(s, PA_STREAM_CREATING); + + pa_stream_unref(s); + return 0; +} + +int pa_stream_connect_playback( + pa_stream *s, + const char *dev, + const pa_buffer_attr *attr, + pa_stream_flags_t flags, + pa_cvolume *volume, + pa_stream *sync_stream) { + + assert(s); + assert(s->ref >= 1); + + return create_stream(PA_STREAM_PLAYBACK, s, dev, attr, flags, volume, sync_stream); +} + +int pa_stream_connect_record( + pa_stream *s, + const char *dev, + const pa_buffer_attr *attr, + pa_stream_flags_t flags) { + + assert(s); + assert(s->ref >= 1); + + return create_stream(PA_STREAM_RECORD, s, dev, attr, flags, NULL, NULL); +} + +int pa_stream_write( + pa_stream *s, + const void *data, + size_t length, + void (*free_cb)(void *p), + int64_t offset, + pa_seek_mode_t seek) { + + pa_memchunk chunk; + + assert(s); + assert(s->ref >= 1); + assert(data); + + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, seek <= PA_SEEK_RELATIVE_END, PA_ERR_INVALID); + PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || (seek == PA_SEEK_RELATIVE && offset == 0), PA_ERR_INVALID); + + if (length <= 0) + return 0; + + if (free_cb) + chunk.memblock = pa_memblock_new_user((void*) data, length, free_cb, 1, s->context->memblock_stat); + else { + chunk.memblock = pa_memblock_new(length, s->context->memblock_stat); + memcpy(chunk.memblock->data, data, length); + } + + chunk.index = 0; + chunk.length = length; + + pa_pstream_send_memblock(s->context->pstream, s->channel, offset, seek, &chunk); + pa_memblock_unref(chunk.memblock); + + if (length < s->requested_bytes) + s->requested_bytes -= length; + else + s->requested_bytes = 0; + + if (s->direction == PA_STREAM_PLAYBACK) { + + /* Update latency request correction */ + if (s->write_index_corrections[s->current_write_index_correction].valid) { + + if (seek == PA_SEEK_ABSOLUTE) { + s->write_index_corrections[s->current_write_index_correction].corrupt = 0; + s->write_index_corrections[s->current_write_index_correction].absolute = 1; + s->write_index_corrections[s->current_write_index_correction].value = offset + length; + } else if (seek == PA_SEEK_RELATIVE) { + if (!s->write_index_corrections[s->current_write_index_correction].corrupt) + s->write_index_corrections[s->current_write_index_correction].value += offset + length; + } else + s->write_index_corrections[s->current_write_index_correction].corrupt = 1; + } + + /* Update the write index in the already available latency data */ + if (s->timing_info_valid) { + + if (seek == PA_SEEK_ABSOLUTE) { + s->timing_info.write_index_corrupt = 0; + s->timing_info.write_index = offset + length; + } else if (seek == PA_SEEK_RELATIVE) { + if (!s->timing_info.write_index_corrupt) + s->timing_info.write_index += offset + length; + } else + s->timing_info.write_index_corrupt = 1; + } + + if (!s->timing_info_valid || s->timing_info.write_index_corrupt) + request_auto_timing_update(s, 1); + } + + return 0; +} + +int pa_stream_peek(pa_stream *s, const void **data, size_t *length) { + assert(s); + assert(s->ref >= 1); + assert(data); + assert(length); + + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE); + + if (!s->peek_memchunk.memblock) { + + if (pa_memblockq_peek(s->record_memblockq, &s->peek_memchunk) < 0) { + *data = NULL; + *length = 0; + return 0; + } + } + + *data = (const char*) s->peek_memchunk.memblock->data + s->peek_memchunk.index; + *length = s->peek_memchunk.length; + return 0; +} + +int pa_stream_drop(pa_stream *s) { + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->peek_memchunk.memblock, PA_ERR_BADSTATE); + + pa_memblockq_drop(s->record_memblockq, &s->peek_memchunk, s->peek_memchunk.length); + + /* Fix the simulated local read index */ + if (s->timing_info_valid && !s->timing_info.read_index_corrupt) + s->timing_info.read_index += s->peek_memchunk.length; + + pa_memblock_unref(s->peek_memchunk.memblock); + s->peek_memchunk.length = 0; + s->peek_memchunk.index = 0; + s->peek_memchunk.memblock = NULL; + + return 0; +} + +size_t pa_stream_writable_size(pa_stream *s) { + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (size_t) -1); + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_RECORD, PA_ERR_BADSTATE, (size_t) -1); + + return s->requested_bytes; +} + +size_t pa_stream_readable_size(pa_stream *s) { + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (size_t) -1); + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, (size_t) -1); + + return pa_memblockq_get_length(s->record_memblockq); +} + +pa_operation * pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); + + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(s->context, PA_COMMAND_DRAIN_PLAYBACK_STREAM, &tag); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + struct timeval local, remote, now; + pa_timing_info *i; + + assert(pd); + assert(o); + + if (!o->context || !o->stream) + goto finish; + + i = &o->stream->timing_info; + +/* pa_log("pre corrupt w:%u r:%u\n", !o->stream->timing_info_valid || i->write_index_corrupt,!o->stream->timing_info_valid || i->read_index_corrupt); */ + + o->stream->timing_info_valid = 0; + i->write_index_corrupt = 0; + i->read_index_corrupt = 0; + +/* pa_log("timing update %u\n", tag); */ + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + } else if (pa_tagstruct_get_usec(t, &i->sink_usec) < 0 || + pa_tagstruct_get_usec(t, &i->source_usec) < 0 || + pa_tagstruct_get_boolean(t, &i->playing) < 0 || + pa_tagstruct_get_timeval(t, &local) < 0 || + pa_tagstruct_get_timeval(t, &remote) < 0 || + pa_tagstruct_gets64(t, &i->write_index) < 0 || + pa_tagstruct_gets64(t, &i->read_index) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERR_PROTOCOL); + goto finish; + + } else { + o->stream->timing_info_valid = 1; + + pa_gettimeofday(&now); + + /* Calculcate timestamps */ + if (pa_timeval_cmp(&local, &remote) <= 0 && pa_timeval_cmp(&remote, &now) <= 0) { + /* local and remote seem to have synchronized clocks */ + + if (o->stream->direction == PA_STREAM_PLAYBACK) + i->transport_usec = pa_timeval_diff(&remote, &local); + else + i->transport_usec = pa_timeval_diff(&now, &remote); + + i->synchronized_clocks = 1; + i->timestamp = remote; + } else { + /* clocks are not synchronized, let's estimate latency then */ + i->transport_usec = pa_timeval_diff(&now, &local)/2; + i->synchronized_clocks = 0; + i->timestamp = local; + pa_timeval_add(&i->timestamp, i->transport_usec); + } + + /* Invalidate read and write indexes if necessary */ + if (tag < o->stream->read_index_not_before) + i->read_index_corrupt = 1; + + if (tag < o->stream->write_index_not_before) + i->write_index_corrupt = 1; + + if (o->stream->direction == PA_STREAM_PLAYBACK) { + /* Write index correction */ + + int n, j; + uint32_t ctag = tag; + + /* Go through the saved correction values and add up the total correction.*/ + + for (n = 0, j = o->stream->current_write_index_correction+1; + n < PA_MAX_WRITE_INDEX_CORRECTIONS; + n++, j = (j + 1) % PA_MAX_WRITE_INDEX_CORRECTIONS) { + + /* Step over invalid data or out-of-date data */ + if (!o->stream->write_index_corrections[j].valid || + o->stream->write_index_corrections[j].tag < ctag) + continue; + + /* Make sure that everything is in order */ + ctag = o->stream->write_index_corrections[j].tag+1; + + /* Now fix the write index */ + if (o->stream->write_index_corrections[j].corrupt) { + /* A corrupting seek was made */ + i->write_index = 0; + i->write_index_corrupt = 1; + } else if (o->stream->write_index_corrections[j].absolute) { + /* An absolute seek was made */ + i->write_index = o->stream->write_index_corrections[j].value; + i->write_index_corrupt = 0; + } else if (!i->write_index_corrupt) { + /* A relative seek was made */ + i->write_index += o->stream->write_index_corrections[j].value; + } + } + } + + if (o->stream->direction == PA_STREAM_RECORD) { + /* Read index correction */ + + if (!i->read_index_corrupt) + i->read_index -= pa_memblockq_get_length(o->stream->record_memblockq); + } + + o->stream->cached_time_valid = 0; + } + + o->stream->auto_timing_update_requested = 0; +/* pa_log("post corrupt w:%u r:%u\n", i->write_index_corrupt || !o->stream->timing_info_valid, i->read_index_corrupt || !o->stream->timing_info_valid); */ + + /* Clear old correction entries */ + if (o->stream->direction == PA_STREAM_PLAYBACK) { + int n; + + for (n = 0; n < PA_MAX_WRITE_INDEX_CORRECTIONS; n++) { + if (!o->stream->write_index_corrections[n].valid) + continue; + + if (o->stream->write_index_corrections[n].tag <= tag) + o->stream->write_index_corrections[n].valid = 0; + } + } + + if (o->stream->latency_update_callback) + o->stream->latency_update_callback(o->stream, o->stream->latency_update_userdata); + + if (o->callback && o->stream && o->stream->state == PA_STREAM_READY) { + pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback; + cb(o->stream, o->stream->timing_info_valid, o->userdata); + } + +finish: + + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { + uint32_t tag; + pa_operation *o; + pa_tagstruct *t; + struct timeval now; + int cidx = 0; + + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + + if (s->direction == PA_STREAM_PLAYBACK) { + /* Find a place to store the write_index correction data for this entry */ + cidx = (s->current_write_index_correction + 1) % PA_MAX_WRITE_INDEX_CORRECTIONS; + + /* Check if we could allocate a correction slot. If not, there are too many outstanding queries */ + PA_CHECK_VALIDITY_RETURN_NULL(s->context, !s->write_index_corrections[cidx].valid, PA_ERR_INTERNAL); + } + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command( + s->context, + s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_GET_PLAYBACK_LATENCY : PA_COMMAND_GET_RECORD_LATENCY, + &tag); + pa_tagstruct_putu32(t, s->channel); + pa_tagstruct_put_timeval(t, pa_gettimeofday(&now)); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_timing_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + if (s->direction == PA_STREAM_PLAYBACK) { + /* Fill in initial correction data */ + o->stream->current_write_index_correction = cidx; + o->stream->write_index_corrections[cidx].valid = 1; + o->stream->write_index_corrections[cidx].tag = tag; + o->stream->write_index_corrections[cidx].absolute = 0; + o->stream->write_index_corrections[cidx].value = 0; + o->stream->write_index_corrections[cidx].corrupt = 0; + } + +/* pa_log("requesting update %u\n", tag); */ + + return o; +} + +void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_stream *s = userdata; + + assert(pd); + assert(s); + assert(s->ref >= 1); + + pa_stream_ref(s); + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(s->context, command, t) < 0) + goto finish; + + pa_stream_set_state(s, PA_STREAM_FAILED); + goto finish; + } else if (!pa_tagstruct_eof(t)) { + pa_context_fail(s->context, PA_ERR_PROTOCOL); + goto finish; + } + + pa_stream_set_state(s, PA_STREAM_TERMINATED); + +finish: + pa_stream_unref(s); +} + +int pa_stream_disconnect(pa_stream *s) { + pa_tagstruct *t; + uint32_t tag; + + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY(s->context, s->channel_valid, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + pa_stream_ref(s); + + t = pa_tagstruct_command( + s->context, + s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : + (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM), + &tag); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s, NULL); + + pa_stream_unref(s); + return 0; +} + +void pa_stream_set_read_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) { + assert(s); + assert(s->ref >= 1); + + s->read_callback = cb; + s->read_userdata = userdata; +} + +void pa_stream_set_write_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) { + assert(s); + assert(s->ref >= 1); + + s->write_callback = cb; + s->write_userdata = userdata; +} + +void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { + assert(s); + assert(s->ref >= 1); + + s->state_callback = cb; + s->state_userdata = userdata; +} + +void pa_stream_set_overflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { + assert(s); + assert(s->ref >= 1); + + s->overflow_callback = cb; + s->overflow_userdata = userdata; +} + +void pa_stream_set_underflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { + assert(s); + assert(s->ref >= 1); + + s->underflow_callback = cb; + s->underflow_userdata = userdata; +} + +void pa_stream_set_latency_update_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { + assert(s); + assert(s->ref >= 1); + + s->latency_update_callback = cb; + s->latency_update_userdata = userdata; +} + +void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int success = 1; + + assert(pd); + assert(o); + assert(o->ref >= 1); + + if (!o->context) + goto finish; + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + success = 0; + } else if (!pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERR_PROTOCOL); + goto finish; + } + + if (o->callback) { + pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback; + cb(o->stream, success, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + +pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + + s->corked = b; + + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command( + s->context, + s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CORK_PLAYBACK_STREAM : PA_COMMAND_CORK_RECORD_STREAM, + &tag); + pa_tagstruct_putu32(t, s->channel); + pa_tagstruct_put_boolean(t, !!b); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + if (s->direction == PA_STREAM_PLAYBACK) + invalidate_indexes(s, 1, 0); + + return o; +} + +static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, pa_stream_success_cb_t cb, void *userdata) { + pa_tagstruct *t; + pa_operation *o; + uint32_t tag; + + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(s->context, command, &tag); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { + pa_operation *o; + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + + if ((o = stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata))) { + + if (s->direction == PA_STREAM_PLAYBACK) { + if (s->write_index_corrections[s->current_write_index_correction].valid) + s->write_index_corrections[s->current_write_index_correction].corrupt = 1; + + if (s->timing_info_valid) + s->timing_info.write_index_corrupt = 1; + + if (s->buffer_attr.prebuf > 0) + invalidate_indexes(s, 1, 0); + else + request_auto_timing_update(s, 1); + } else + invalidate_indexes(s, 0, 1); + } + + return o; +} + +pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { + pa_operation *o; + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE); + + if ((o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata))) + invalidate_indexes(s, 1, 0); + + return o; +} + +pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { + pa_operation *o; + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE); + + if ((o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata))) + invalidate_indexes(s, 1, 0); + + return o; +} + +pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(s); + assert(s->ref >= 1); + assert(name); + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command( + s->context, + s->direction == PA_STREAM_RECORD ? PA_COMMAND_SET_RECORD_STREAM_NAME : PA_COMMAND_SET_PLAYBACK_STREAM_NAME, + &tag); + pa_tagstruct_putu32(t, s->channel); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) { + pa_usec_t usec = 0; + + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->timing_info_valid, PA_ERR_NODATA); + PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_PLAYBACK || !s->timing_info.read_index_corrupt, PA_ERR_NODATA); + PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_RECORD || !s->timing_info.write_index_corrupt, PA_ERR_NODATA); + + if (s->cached_time_valid) + /* We alredy calculated the time value for this timing info, so let's reuse it */ + usec = s->cached_time; + else { + if (s->direction == PA_STREAM_PLAYBACK) { + /* The last byte that was written into the output device + * had this time value associated */ + usec = pa_bytes_to_usec(s->timing_info.read_index < 0 ? 0 : (uint64_t) s->timing_info.read_index, &s->sample_spec); + + if (!s->corked) { + /* Because the latency info took a little time to come + * to us, we assume that the real output time is actually + * a little ahead */ + usec += s->timing_info.transport_usec; + + /* However, the output device usually maintains a buffer + too, hence the real sample currently played is a little + back */ + if (s->timing_info.sink_usec >= usec) + usec = 0; + else + usec -= s->timing_info.sink_usec; + } + + } else if (s->direction == PA_STREAM_RECORD) { + /* The last byte written into the server side queue had + * this time value associated */ + usec = pa_bytes_to_usec(s->timing_info.write_index < 0 ? 0 : (uint64_t) s->timing_info.write_index, &s->sample_spec); + + if (!s->corked) { + /* Add transport latency */ + usec += s->timing_info.transport_usec; + + /* Add latency of data in device buffer */ + usec += s->timing_info.source_usec; + + /* If this is a monitor source, we need to correct the + * time by the playback device buffer */ + if (s->timing_info.sink_usec >= usec) + usec = 0; + else + usec -= s->timing_info.sink_usec; + } + } + + s->cached_time = usec; + s->cached_time_valid = 1; + } + + /* Interpolate if requested */ + if (s->flags & PA_STREAM_INTERPOLATE_TIMING) { + + /* We just add the time that passed since the latency info was + * current */ + if (!s->corked) { + struct timeval now; + usec += pa_timeval_diff(pa_gettimeofday(&now), &s->timing_info.timestamp); + } + } + + /* Make sure the time runs monotonically */ + if (!(s->flags & PA_STREAM_NOT_MONOTONOUS)) { + if (usec < s->previous_time) + usec = s->previous_time; + else + s->previous_time = usec; + } + + if (r_usec) + *r_usec = usec; + + return 0; +} + +static pa_usec_t time_counter_diff(pa_stream *s, pa_usec_t a, pa_usec_t b, int *negative) { + assert(s); + assert(s->ref >= 1); + + if (negative) + *negative = 0; + + if (a >= b) + return a-b; + else { + if (negative && s->direction == PA_STREAM_RECORD) { + *negative = 1; + return b-a; + } else + return 0; + } +} + +int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative) { + pa_usec_t t, c; + int r; + int64_t cindex; + + assert(s); + assert(s->ref >= 1); + assert(r_usec); + + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->timing_info_valid, PA_ERR_NODATA); + PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_PLAYBACK || !s->timing_info.write_index_corrupt, PA_ERR_NODATA); + PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_RECORD || !s->timing_info.read_index_corrupt, PA_ERR_NODATA); + + if ((r = pa_stream_get_time(s, &t)) < 0) + return r; + + if (s->direction == PA_STREAM_PLAYBACK) + cindex = s->timing_info.write_index; + else + cindex = s->timing_info.read_index; + + if (cindex < 0) + cindex = 0; + + c = pa_bytes_to_usec(cindex, &s->sample_spec); + + if (s->direction == PA_STREAM_PLAYBACK) + *r_usec = time_counter_diff(s, c, t, negative); + else + *r_usec = time_counter_diff(s, t, c, negative); + + return 0; +} + +const pa_timing_info* pa_stream_get_timing_info(pa_stream *s) { + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->timing_info_valid, PA_ERR_BADSTATE); + + return &s->timing_info; +} + +const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) { + assert(s); + assert(s->ref >= 1); + + return &s->sample_spec; +} + +const pa_channel_map* pa_stream_get_channel_map(pa_stream *s) { + assert(s); + assert(s->ref >= 1); + + return &s->channel_map; +} + +const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s) { + assert(s); + assert(s->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, + pa_context_get_server_protocol_version(s->context) >= 9, PA_ERR_NODATA); + + return &s->buffer_attr; +} diff --git a/src/pulse/stream.h b/src/pulse/stream.h new file mode 100644 index 00000000..d117ce4a --- /dev/null +++ b/src/pulse/stream.h @@ -0,0 +1,449 @@ +#ifndef foostreamhfoo +#define foostreamhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include +#include +#include +#include +#include + +/** \page streams Audio Streams + * + * \section overv_sec Overview + * + * Audio streams form the central functionality of the sound server. Data is + * routed, converted and mixed from several sources before it is passed along + * to a final output. Currently, there are three forms of audio streams: + * + * \li Playback streams - Data flows from the client to the server. + * \li Record streams - Data flows from the server to the client. + * \li Upload streams - Similar to playback streams, but the data is stored in + * the sample cache. See \ref scache for more information + * about controlling the sample cache. + * + * \section create_sec Creating + * + * To access a stream, a pa_stream object must be created using + * pa_stream_new(). At this point the audio sample format and mapping of + * channels must be specified. See \ref sample and \ref channelmap for more + * information about those structures. + * + * This first step will only create a client-side object, representing the + * stream. To use the stream, a server-side object must be created and + * associated with the local object. Depending on which type of stream is + * desired, a different function is needed: + * + * \li Playback stream - pa_stream_connect_playback() + * \li Record stream - pa_stream_connect_record() + * \li Upload stream - pa_stream_connect_upload() (see \ref scache) + * + * Similar to how connections are done in contexts, connecting a stream will + * not generate a pa_operation object. Also like contexts, the application + * should register a state change callback, using + * pa_stream_set_state_callback(), and wait for the stream to enter an active + * state. + * + * \subsection bufattr_subsec Buffer Attributes + * + * Playback and record streams always have a server side buffer as + * part of the data flow. The size of this buffer strikes a + * compromise between low latency and sensitivity for buffer + * overflows/underruns. + * + * The buffer metrics may be controlled by the application. They are + * described with a pa_buffer_attr structure which contains a number + * of fields: + * + * \li maxlength - The absolute maximum number of bytes that can be stored in + * the buffer. If this value is exceeded then data will be + * lost. + * \li tlength - The target length of a playback buffer. The server will only + * send requests for more data as long as the buffer has less + * than this number of bytes of data. + * \li prebuf - Number of bytes that need to be in the buffer before + * playback will commence. Start of playback can be forced using + * pa_stream_trigger() even though the prebuffer size hasn't been + * reached. If a buffer underrun occurs, this prebuffering will be + * again enabled. If the playback shall never stop in case of a buffer + * underrun, this value should be set to 0. In that case the read + * index of the output buffer overtakes the write index, and hence the + * fill level of the buffer is negative. + * \li minreq - Minimum free number of the bytes in the playback buffer before + * the server will request more data. + * \li fragsize - Maximum number of bytes that the server will push in one + * chunk for record streams. + * + * The server side playback buffers are indexed by a write and a read + * index. The application writes to the write index and the sound + * device reads from the read index. The read index is increased + * monotonically, while the write index may be freely controlled by + * the application. Substracting the read index from the write index + * will give you the current fill level of the buffer. The read/write + * indexes are 64bit values and measured in bytes, they will never + * wrap. The current read/write index may be queried using + * pa_stream_get_timing_info() (see below for more information). In + * case of a buffer underrun the read index is equal or larger than + * the write index. Unless the prebuf value is 0, Polypaudio will + * temporarily pause playback in such a case, and wait until the + * buffer is filled up to prebuf bytes again. If prebuf is 0, the + * read index may be larger than the write index, in which case + * silence is played. If the application writes data to indexes lower + * than the read index, the data is immediately lost. + * + * \section transfer_sec Transferring Data + * + * Once the stream is up, data can start flowing between the client and the + * server. Two different access models can be used to transfer the data: + * + * \li Asynchronous - The application register a callback using + * pa_stream_set_write_callback() and + * pa_stream_set_read_callback() to receive notifications + * that data can either be written or read. + * \li Polled - Query the library for available data/space using + * pa_stream_writable_size() and pa_stream_readable_size() and + * transfer data as needed. The sizes are stored locally, in the + * client end, so there is no delay when reading them. + * + * It is also possible to mix the two models freely. + * + * Once there is data/space available, it can be transferred using either + * pa_stream_write() for playback, or pa_stream_peek() / pa_stream_drop() for + * record. Make sure you do not overflow the playback buffers as data will be + * dropped. + * + * \section bufctl_sec Buffer Control + * + * The transfer buffers can be controlled through a number of operations: + * + * \li pa_stream_cork() - Start or stop the playback or recording. + * \li pa_stream_trigger() - Start playback immediatly and do not wait for + * the buffer to fill up to the set trigger level. + * \li pa_stream_prebuf() - Reenable the playback trigger level. + * \li pa_stream_drain() - Wait for the playback buffer to go empty. Will + * return a pa_operation object that will indicate when + * the buffer is completely drained. + * \li pa_stream_flush() - Drop all data from the playback buffer and do not + * wait for it to finish playing. + * + * \section seek_modes Seeking in the Playback Buffer + * + * A client application may freely seek in the playback buffer. To + * accomplish that the pa_stream_write() function takes a seek mode + * and an offset argument. The seek mode is one of: + * + * \li PA_SEEK_RELATIVE - seek relative to the current write index + * \li PA_SEEK_ABSOLUTE - seek relative to the beginning of the playback buffer, (i.e. the first that was ever played in the stream) + * \li PA_SEEK_RELATIVE_ON_READ - seek relative to the current read index. Use this to write data to the output buffer that should be played as soon as possible + * \li PA_SEEK_RELATIVE_END - seek relative to the last byte ever written. + * + * If an application just wants to append some data to the output + * buffer, PA_SEEK_RELATIVE and an offset of 0 should be used. + * + * After a call to pa_stream_write() the write index will be left at + * the position right after the last byte of the written data. + * + * \section latency_sec Latency + * + * A major problem with networked audio is the increased latency caused by + * the network. To remedy this, Polypaudio supports an advanced system of + * monitoring the current latency. + * + * To get the raw data needed to calculate latencies, call + * pa_stream_get_timing_info(). This will give you a pa_timing_info + * structure that contains everything that is known about the server + * side buffer transport delays and the backend active in the + * server. (Besides other things it contains the write and read index + * values mentioned above.) + * + * This structure is updated every time a + * pa_stream_update_timing_info() operation is executed. (i.e. before + * the first call to this function the timing information structure is + * not available!) Since it is a lot of work to keep this structure + * up-to-date manually, Polypaudio can do that automatically for you: + * if PA_STREAM_AUTO_TIMING_UPDATE is passed when connecting the + * stream Polypaudio will automatically update the structure every + * 100ms and every time a function is called that might invalidate the + * previously known timing data (such as pa_stream_write() or + * pa_stream_flush()). Please note however, that there always is a + * short time window when the data in the timing information structure + * is out-of-date. Polypaudio tries to mark these situations by + * setting the write_index_corrupt and read_index_corrupt fields + * accordingly. + * + * The raw timing data in the pa_timing_info structure is usually hard + * to deal with. Therefore a more simplistic interface is available: + * you can call pa_stream_get_time() or pa_stream_get_latency(). The + * former will return the current playback time of the hardware since + * the stream has been started. The latter returns the time a sample + * that you write now takes to be played by the hardware. These two + * functions base their calculations on the same data that is returned + * by pa_stream_get_timing_info(). Hence the same rules for keeping + * the timing data up-to-date apply here. In case the write or read + * index is corrupted, these two functions will fail with + * PA_ERR_NODATA set. + * + * Since updating the timing info structure usually requires a full + * network round trip and some applications monitor the timing very + * often Polypaudio offers a timing interpolation system. If + * PA_STREAM_INTERPOLATE_TIMING is passed when connecting the stream, + * pa_stream_get_time() and pa_stream_get_latency() will try to + * interpolate the current playback time/latency by estimating the + * number of samples that have been played back by the hardware since + * the last regular timing update. It is espcially useful to combine + * this option with PA_STREAM_AUTO_TIMING_UPDATE, which will enable + * you to monitor the current playback time/latency very precisely and + * very frequently without requiring a network round trip every time. + * + * \section flow_sec Overflow and underflow + * + * Even with the best precautions, buffers will sometime over - or + * underflow. To handle this gracefully, the application can be + * notified when this happens. Callbacks are registered using + * pa_stream_set_overflow_callback() and + * pa_stream_set_underflow_callback(). + * + * \section sync_streams Sychronizing Multiple Playback Streams + * + * Polypaudio allows applications to fully synchronize multiple + * playback streams that are connected to the same output device. That + * means the streams will always be played back sample-by-sample + * synchronously. If stream operations like pa_stream_cork() are + * issued on one of the synchronized streams, they are simultaneously + * issued on the others. + * + * To synchronize a stream to another, just pass the "master" stream + * as last argument to pa_stream_connect_playack(). To make sure that + * the freshly created stream doesn't start playback right-away, make + * sure to pass PA_STREAM_START_CORKED and - after all streams have + * been created - uncork them all with a single call to + * pa_stream_cork() for the master stream. + * + * To make sure that a particular stream doesn't stop to play when a + * server side buffer underrun happens on it while the other + * synchronized streams continue playing and hence deviate you need to + * pass a "prebuf" pa_buffer_attr of 0 when connecting it. + * + * \section disc_sec Disconnecting + * + * When a stream has served is purpose it must be disconnected with + * pa_stream_disconnect(). If you only unreference it, then it will live on + * and eat resources both locally and on the server until you disconnect the + * context. + * + */ + +/** \file + * Audio streams for input, output and sample upload */ + +PA_C_DECL_BEGIN + +/** An opaque stream for playback or recording */ +typedef struct pa_stream pa_stream; + +/** A generic callback for operation completion */ +typedef void (*pa_stream_success_cb_t) (pa_stream*s, int success, void *userdata); + +/** A generic request callback */ +typedef void (*pa_stream_request_cb_t)(pa_stream *p, size_t length, void *userdata); + +/** A generic notification callback */ +typedef void (*pa_stream_notify_cb_t)(pa_stream *p, void *userdata); + +/** Create a new, unconnected stream with the specified name and sample type */ +pa_stream* pa_stream_new( + pa_context *c /**< The context to create this stream in */, + const char *name /**< A name for this stream */, + const pa_sample_spec *ss /**< The desired sample format */, + const pa_channel_map *map /**< The desired channel map, or NULL for default */); + +/** Decrease the reference counter by one */ +void pa_stream_unref(pa_stream *s); + +/** Increase the reference counter by one */ +pa_stream *pa_stream_ref(pa_stream *s); + +/** Return the current state of the stream */ +pa_stream_state_t pa_stream_get_state(pa_stream *p); + +/** Return the context this stream is attached to */ +pa_context* pa_stream_get_context(pa_stream *p); + +/** Return the device (sink input or source output) index this stream is connected to */ +uint32_t pa_stream_get_index(pa_stream *s); + +/** Connect the stream to a sink */ +int pa_stream_connect_playback( + pa_stream *s /**< The stream to connect to a sink */, + const char *dev /**< Name of the sink to connect to, or NULL for default */ , + const pa_buffer_attr *attr /**< Buffering attributes, or NULL for default */, + pa_stream_flags_t flags /**< Additional flags, or 0 for default */, + pa_cvolume *volume /**< Initial volume, or NULL for default */, + pa_stream *sync_stream /**< Synchronize this stream with the specified one, or NULL for a standalone stream*/); + +/** Connect the stream to a source */ +int pa_stream_connect_record( + pa_stream *s /**< The stream to connect to a source */ , + const char *dev /**< Name of the source to connect to, or NULL for default */, + const pa_buffer_attr *attr /**< Buffer attributes, or NULL for default */, + pa_stream_flags_t flags /**< Additional flags, or 0 for default */); + +/** Disconnect a stream from a source/sink */ +int pa_stream_disconnect(pa_stream *s); + +/** Write some data to the server (for playback sinks), if free_cb is + * non-NULL this routine is called when all data has been written out + * and an internal reference to the specified data is kept, the data + * is not copied. If NULL, the data is copied into an internal + * buffer. The client my freely seek around in the output buffer. For + * most applications passing 0 and PA_SEEK_RELATIVE as arguments for + * offset and seek should be useful.*/ +int pa_stream_write( + pa_stream *p /**< The stream to use */, + const void *data /**< The data to write */, + size_t length /**< The length of the data to write */, + pa_free_cb_t free_cb /**< A cleanup routine for the data or NULL to request an internal copy */, + int64_t offset, /**< Offset for seeking, must be 0 for upload streams */ + pa_seek_mode_t seek /**< Seek mode, must be PA_SEEK_RELATIVE for upload streams */); + +/** Read the next fragment from the buffer (for recording). + * data will point to the actual data and length will contain the size + * of the data in bytes (which can be less than a complete framgnet). + * Use pa_stream_drop() to actually remove the data from the + * buffer. If no data is available will return a NULL pointer \since 0.8 */ +int pa_stream_peek( + pa_stream *p /**< The stream to use */, + const void **data /**< Pointer to pointer that will point to data */, + size_t *length /**< The length of the data read */); + +/** Remove the current fragment on record streams. It is invalid to do this without first + * calling pa_stream_peek(). \since 0.8 */ +int pa_stream_drop(pa_stream *p); + +/** Return the nember of bytes that may be written using pa_stream_write() */ +size_t pa_stream_writable_size(pa_stream *p); + +/** Return the number of bytes that may be read using pa_stream_read() \since 0.8 */ +size_t pa_stream_readable_size(pa_stream *p); + +/** Drain a playback stream. Use this for notification when the buffer is empty */ +pa_operation* pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); + +/** Request a timing info structure update for a stream. Use + * pa_stream_get_timing_info() to get access to the raw timing data, + * or pa_stream_get_time() or pa_stream_get_latency() to get cleaned + * up values. */ +pa_operation* pa_stream_update_timing_info(pa_stream *p, pa_stream_success_cb_t cb, void *userdata); + +/** Set the callback function that is called whenever the state of the stream changes */ +void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata); + +/** Set the callback function that is called when new data may be + * written to the stream. */ +void pa_stream_set_write_callback(pa_stream *p, pa_stream_request_cb_t cb, void *userdata); + +/** Set the callback function that is called when new data is available from the stream. + * Return the number of bytes read. \since 0.8 */ +void pa_stream_set_read_callback(pa_stream *p, pa_stream_request_cb_t cb, void *userdata); + +/** Set the callback function that is called when a buffer overflow happens. (Only for playback streams) \since 0.8 */ +void pa_stream_set_overflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); + +/** Set the callback function that is called when a buffer underflow happens. (Only for playback streams) \since 0.8 */ +void pa_stream_set_underflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); + +/** Set the callback function that is called whenever a latency information update happens. Useful on PA_STREAM_AUTO_TIMING_UPDATE streams only. (Only for playback streams) \since 0.8.2 */ +void pa_stream_set_latency_update_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); + +/** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. \since 0.3 */ +pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata); + +/** Flush the playback buffer of this stream. Most of the time you're + * better off using the parameter delta of pa_stream_write() instead of this + * function. Available on both playback and recording streams. \since 0.3 */ +pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); + +/** Reenable prebuffering as specified in the pa_buffer_attr + * structure. Available for playback streams only. \since 0.6 */ +pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); + +/** Request immediate start of playback on this stream. This disables + * prebuffering as specified in the pa_buffer_attr + * structure, temporarily. Available for playback streams only. \since 0.3 */ +pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); + +/** Rename the stream. \since 0.5 */ +pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata); + +/** Return the current playback/recording time. This is based on the + * data in the timing info structure returned by + * pa_stream_get_timing_info(). This function will usually only return + * new data if a timing info update has been recieved. Only if timing + * interpolation has been requested (PA_STREAM_INTERPOLATE_TIMING) + * the data from the last timing update is used for an estimation of + * the current playback/recording time based on the local time that + * passed since the timing info structure has been acquired. The time + * value returned by this function is guaranteed to increase + * monotonically. (that means: the returned value is always greater or + * equal to the value returned on the last call) This behaviour can + * be disabled by using PA_STREAM_NOT_MONOTONOUS. This may be + * desirable to deal better with bad estimations of transport + * latencies, but may have strange effects if the application is not + * able to deal with time going 'backwards'. \since 0.6 */ +int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec); + +/** Return the total stream latency. This function is based on + * pa_stream_get_time(). In case the stream is a monitoring stream the + * result can be negative, i.e. the captured samples are not yet + * played. In this case *negative is set to 1. \since 0.6 */ +int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative); + +/** Return the latest raw timing data structure. The returned pointer + * points to an internal read-only instance of the timing + * structure. The user should make a copy of this structure if he + * wants to modify it. An in-place update to this data structure may + * be requested using pa_stream_update_timing_info(). If no + * pa_stream_update_timing_info() call was issued before, this + * function will fail with PA_ERR_NODATA. Please note that the + * write_index member field (and only this field) is updated on each + * pa_stream_write() call, not just when a timing update has been + * recieved. \since 0.8 */ +const pa_timing_info* pa_stream_get_timing_info(pa_stream *s); + +/** Return a pointer to the stream's sample specification. \since 0.6 */ +const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s); + +/** Return a pointer to the stream's channel map. \since 0.8 */ +const pa_channel_map* pa_stream_get_channel_map(pa_stream *s); + +/** Return the buffer metrics of the stream. Only valid after the + * stream has been connected successfuly and if the server is at least + * Polypaudio 0.9. \since 0.9.0 */ +const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s); + +PA_C_DECL_END + +#endif diff --git a/src/pulse/subscribe.c b/src/pulse/subscribe.c new file mode 100644 index 00000000..c1d88912 --- /dev/null +++ b/src/pulse/subscribe.c @@ -0,0 +1,89 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include + +#include "internal.h" + +#include "subscribe.h" + +void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_context *c = userdata; + pa_subscription_event_type_t e; + uint32_t idx; + + assert(pd); + assert(command == PA_COMMAND_SUBSCRIBE_EVENT); + assert(t); + assert(c); + + pa_context_ref(c); + + if (pa_tagstruct_getu32(t, &e) < 0 || + pa_tagstruct_getu32(t, &idx) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(c, PA_ERR_PROTOCOL); + goto finish; + } + + if (c->subscribe_callback) + c->subscribe_callback(c, e, idx, c->subscribe_userdata); + +finish: + pa_context_unref(c); +} + + +pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SUBSCRIBE, &tag); + pa_tagstruct_putu32(t, m); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +void pa_context_set_subscribe_callback(pa_context *c, pa_context_subscribe_cb_t cb, void *userdata) { + assert(c); + assert(c->ref >= 1); + + c->subscribe_callback = cb; + c->subscribe_userdata = userdata; +} diff --git a/src/pulse/subscribe.h b/src/pulse/subscribe.h new file mode 100644 index 00000000..adbea680 --- /dev/null +++ b/src/pulse/subscribe.h @@ -0,0 +1,61 @@ +#ifndef foosubscribehfoo +#define foosubscribehfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include +#include + +/** \page subscribe Event Subscription + * + * \section overv_sec Overview + * + * The application can be notified, asynchronously, whenever the internal + * layout of the server changes. Possible notifications are desribed in the + * \ref pa_subscription_event_type and \ref pa_subscription_mask + * enumerations. + * + * The application sets the notification mask using pa_context_subscribe() + * and the function that will be called whenever a notification occurs using + * pa_context_set_subscribe_callback(). + */ + +/** \file + * Daemon introspection event subscription subsystem. */ + +PA_C_DECL_BEGIN + +/** Subscription event callback prototype */ +typedef void (*pa_context_subscribe_cb_t)(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata); + +/** Enable event notification */ +pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_context_success_cb_t cb, void *userdata); + +/** Set the context specific call back function that is called whenever the state of the daemon changes */ +void pa_context_set_subscribe_callback(pa_context *c, pa_context_subscribe_cb_t cb, void *userdata); + +PA_C_DECL_END + +#endif diff --git a/src/pulse/thread-mainloop.c b/src/pulse/thread-mainloop.c new file mode 100644 index 00000000..34f0f250 --- /dev/null +++ b/src/pulse/thread-mainloop.c @@ -0,0 +1,466 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#ifdef HAVE_SYS_POLL_H +#include +#else +#include "../pulsecore/poll.h" +#endif + +#ifdef HAVE_PTHREAD +#include +#endif + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include + +#include +#include + +#include "mainloop.h" +#include "thread-mainloop.h" + +#if defined(HAVE_PTHREAD) || defined(OS_IS_WIN32) + +struct pa_threaded_mainloop { + pa_mainloop *real_mainloop; + int n_waiting; + int thread_running; + +#ifdef OS_IS_WIN32 + DWORD thread_id; + HANDLE thread; + CRITICAL_SECTION mutex; + pa_hashmap *cond_events; + HANDLE accept_cond; +#else + pthread_t thread_id; + pthread_mutex_t mutex; + pthread_cond_t cond, accept_cond; +#endif +}; + +static inline int in_worker(pa_threaded_mainloop *m) { +#ifdef OS_IS_WIN32 + return GetCurrentThreadId() == m->thread_id; +#else + return pthread_equal(pthread_self(), m->thread_id); +#endif +} + +static int poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) { +#ifdef OS_IS_WIN32 + CRITICAL_SECTION *mutex = userdata; +#else + pthread_mutex_t *mutex = userdata; +#endif + + int r; + + assert(mutex); + + /* Before entering poll() we unlock the mutex, so that + * avahi_simple_poll_quit() can succeed from another thread. */ + +#ifdef OS_IS_WIN32 + LeaveCriticalSection(mutex); +#else + pthread_mutex_unlock(mutex); +#endif + + r = poll(ufds, nfds, timeout); + +#ifdef OS_IS_WIN32 + EnterCriticalSection(mutex); +#else + pthread_mutex_lock(mutex); +#endif + + return r; +} + +#ifdef OS_IS_WIN32 +static DWORD WINAPI thread(void *userdata) { +#else +static void* thread(void *userdata) { +#endif + pa_threaded_mainloop *m = userdata; + +#ifndef OS_IS_WIN32 + sigset_t mask; + + /* Make sure that signals are delivered to the main thread */ + sigfillset(&mask); + pthread_sigmask(SIG_BLOCK, &mask, NULL); +#endif + +#ifdef OS_IS_WIN32 + EnterCriticalSection(&m->mutex); +#else + pthread_mutex_lock(&m->mutex); +#endif + + pa_mainloop_run(m->real_mainloop, NULL); + +#ifdef OS_IS_WIN32 + LeaveCriticalSection(&m->mutex); +#else + pthread_mutex_unlock(&m->mutex); +#endif + +#ifdef OS_IS_WIN32 + return 0; +#else + return NULL; +#endif +} + +pa_threaded_mainloop *pa_threaded_mainloop_new(void) { + pa_threaded_mainloop *m; +#ifndef OS_IS_WIN32 + pthread_mutexattr_t a; +#endif + + m = pa_xnew(pa_threaded_mainloop, 1); + + if (!(m->real_mainloop = pa_mainloop_new())) { + pa_xfree(m); + return NULL; + } + + pa_mainloop_set_poll_func(m->real_mainloop, poll_func, &m->mutex); + +#ifdef OS_IS_WIN32 + InitializeCriticalSection(&m->mutex); + + m->cond_events = pa_hashmap_new(NULL, NULL); + assert(m->cond_events); + m->accept_cond = CreateEvent(NULL, FALSE, FALSE, NULL); + assert(m->accept_cond); +#else + pthread_mutexattr_init(&a); + pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&m->mutex, &a); + pthread_mutexattr_destroy(&a); + + pthread_cond_init(&m->cond, NULL); + pthread_cond_init(&m->accept_cond, NULL); +#endif + + m->thread_running = 0; + m->n_waiting = 0; + + return m; +} + +void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { + assert(m); + + /* Make sure that this function is not called from the helper thread */ + assert(!m->thread_running || !in_worker(m)); + + if (m->thread_running) + pa_threaded_mainloop_stop(m); + + if (m->real_mainloop) + pa_mainloop_free(m->real_mainloop); + +#ifdef OS_IS_WIN32 + pa_hashmap_free(m->cond_events, NULL, NULL); + CloseHandle(m->accept_cond); +#else + pthread_mutex_destroy(&m->mutex); + pthread_cond_destroy(&m->cond); + pthread_cond_destroy(&m->accept_cond); +#endif + + pa_xfree(m); +} + +int pa_threaded_mainloop_start(pa_threaded_mainloop *m) { + assert(m); + + assert(!m->thread_running); + +#ifdef OS_IS_WIN32 + + EnterCriticalSection(&m->mutex); + + m->thread = CreateThread(NULL, 0, thread, m, 0, &m->thread_id); + if (!m->thread) { + LeaveCriticalSection(&m->mutex); + return -1; + } + +#else + + pthread_mutex_lock(&m->mutex); + + if (pthread_create(&m->thread_id, NULL, thread, m) < 0) { + pthread_mutex_unlock(&m->mutex); + return -1; + } + +#endif + + m->thread_running = 1; + +#ifdef OS_IS_WIN32 + LeaveCriticalSection(&m->mutex); +#else + pthread_mutex_unlock(&m->mutex); +#endif + + return 0; +} + +void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) { + assert(m); + + if (!m->thread_running) + return; + + /* Make sure that this function is not called from the helper thread */ + assert(!in_worker(m)); + +#ifdef OS_IS_WIN32 + EnterCriticalSection(&m->mutex); +#else + pthread_mutex_lock(&m->mutex); +#endif + + pa_mainloop_quit(m->real_mainloop, 0); + +#ifdef OS_IS_WIN32 + LeaveCriticalSection(&m->mutex); +#else + pthread_mutex_unlock(&m->mutex); +#endif + +#ifdef OS_IS_WIN32 + WaitForSingleObject(m->thread, INFINITE); + CloseHandle(m->thread); +#else + pthread_join(m->thread_id, NULL); +#endif + + m->thread_running = 0; + + return; +} + +void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) { + assert(m); + + /* Make sure that this function is not called from the helper thread */ + assert(!m->thread_running || !in_worker(m)); + +#ifdef OS_IS_WIN32 + EnterCriticalSection(&m->mutex); +#else + pthread_mutex_lock(&m->mutex); +#endif +} + +void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { + assert(m); + + /* Make sure that this function is not called from the helper thread */ + assert(!m->thread_running || !in_worker(m)); + +#ifdef OS_IS_WIN32 + LeaveCriticalSection(&m->mutex); +#else + pthread_mutex_unlock(&m->mutex); +#endif +} + +void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept) { +#ifdef OS_IS_WIN32 + void *iter; + const void *key; + HANDLE event; +#endif + + assert(m); + +#ifdef OS_IS_WIN32 + + iter = NULL; + while (1) { + pa_hashmap_iterate(m->cond_events, &iter, &key); + if (key == NULL) + break; + event = (HANDLE)pa_hashmap_get(m->cond_events, key); + SetEvent(event); + } + +#else + + pthread_cond_broadcast(&m->cond); + +#endif + + if (wait_for_accept && m->n_waiting > 0) { + +#ifdef OS_IS_WIN32 + + /* This is just to make sure it's unsignaled */ + WaitForSingleObject(m->accept_cond, 0); + + LeaveCriticalSection(&m->mutex); + + WaitForSingleObject(m->accept_cond, INFINITE); + + EnterCriticalSection(&m->mutex); + +#else + + pthread_cond_wait(&m->accept_cond, &m->mutex); + +#endif + + } +} + +void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { +#ifdef OS_IS_WIN32 + HANDLE event; + DWORD result; +#endif + + assert(m); + + /* Make sure that this function is not called from the helper thread */ + assert(!m->thread_running || !in_worker(m)); + + m->n_waiting ++; + +#ifdef OS_IS_WIN32 + + event = CreateEvent(NULL, FALSE, FALSE, NULL); + assert(event); + + pa_hashmap_put(m->cond_events, event, event); + + LeaveCriticalSection(&m->mutex); + + result = WaitForSingleObject(event, INFINITE); + assert(result == WAIT_OBJECT_0); + + EnterCriticalSection(&m->mutex); + + pa_hashmap_remove(m->cond_events, event); + + CloseHandle(event); + +#else + + pthread_cond_wait(&m->cond, &m->mutex); + +#endif + + assert(m->n_waiting > 0); + m->n_waiting --; +} + +void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) { + assert(m); + + /* Make sure that this function is not called from the helper thread */ + assert(!m->thread_running || !in_worker(m)); + +#ifdef OS_IS_WIN32 + SetEvent(m->accept_cond); +#else + pthread_cond_signal(&m->accept_cond); +#endif +} + +int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) { + assert(m); + + return pa_mainloop_get_retval(m->real_mainloop); +} + +pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) { + assert(m); + + return pa_mainloop_get_api(m->real_mainloop); +} + +#else /* defined(OS_IS_WIN32) || defined(HAVE_PTHREAD) */ + +pa_threaded_mainloop *pa_threaded_mainloop_new(void) { + pa_log_error(__FILE__": Threaded main loop not supported on this platform"); + return NULL; +} + +void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { + assert(0); +} + +int pa_threaded_mainloop_start(pa_threaded_mainloop *m) { + assert(0); + return -1; +} + +void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) { + assert(0); +} + +void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) { + assert(0); +} + +void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { + assert(0); +} + +void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { + assert(0); +} + +void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_release) { + assert(0); +} + +int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) { + assert(0); +} + +pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) { + assert(0); + return NULL; +} + +#endif /* defined(OS_IS_WIN32) || defined(HAVE_PTHREAD) */ diff --git a/src/pulse/thread-mainloop.h b/src/pulse/thread-mainloop.h new file mode 100644 index 00000000..fb216c5a --- /dev/null +++ b/src/pulse/thread-mainloop.h @@ -0,0 +1,299 @@ +#ifndef foothreadmainloophfoo +#define foothreadmainloophfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +PA_C_DECL_BEGIN + +/** \page threaded_mainloop Threaded Main Loop + * + * \section overv_sec Overview + * + * The threaded main loop implementation is a special version of the primary + * main loop implementation (see \ref mainloop). For the basic design, see + * its documentation. + * + * The added feature in the threaded main loop is that it spawns a new thread + * that runs the real main loop. This allows a synchronous application to use + * the asynchronous API without risking to stall the Polypaudio library. + * + * \section creat_sec Creation + * + * A pa_threaded_mainloop object is created using pa_threaded_mainloop_new(). + * This will only allocate the required structures though, so to use it the + * thread must also be started. This is done through + * pa_threaded_mainloop_start(), after which you can start using the main loop. + * + * \section destr_sec Destruction + * + * When the Polypaudio connection has been terminated, the thread must be + * stopped and the resources freed. Stopping the thread is done using + * pa_threaded_mainloop_stop(), which must be called without the lock (see + * below) held. When that function returns, the thread is stopped and the + * pa_threaded_mainloop object can be freed using pa_threaded_mainloop_free(). + * + * \section lock_sec Locking + * + * Since the Polypaudio API doesn't allow concurrent accesses to objects, + * a locking scheme must be used to guarantee safe usage. The threaded main + * loop API provides such a scheme through the functions + * pa_threaded_mainloop_lock() and pa_threaded_mainloop_unlock(). + * + * The lock is recursive, so it's safe to use it multiple times from the same + * thread. Just make sure you call pa_threaded_mainloop_unlock() the same + * number of times you called pa_threaded_mainloop_lock(). + * + * The lock needs to be held whenever you call any Polypaudio function that + * uses an object associated with this main loop. Make sure you do not hold + * on to the lock more than necessary though, as the threaded main loop stops + * while the lock is held. + * + * Example: + * + * \code + * void my_check_stream_func(pa_threaded_mainloop *m, pa_stream *s) { + * pa_stream_state_t state; + * + * pa_threaded_mainloop_lock(m); + * + * state = pa_stream_get_state(s); + * + * pa_threaded_mainloop_unlock(m); + * + * if (state == PA_STREAM_READY) + * printf("Stream is ready!"); + * else + * printf("Stream is not ready!"); + * } + * \endcode + * + * \section cb_sec Callbacks + * + * Callbacks in Polypaudio are asynchronous, so they require extra care when + * using them together with a threaded main loop. + * + * The easiest way to turn the callback based operations into synchronous + * ones, is to simply wait for the callback to be called and continue from + * there. This is the approach chosen in Polypaudio's threaded API. + * + * \subsection basic_subsec Basic callbacks + * + * For the basic case, where all that is required is to wait for the callback + * to be invoked, the code should look something like this: + * + * Example: + * + * \code + * static void my_drain_callback(pa_stream*s, int success, void *userdata) { + * pa_threaded_mainloop *m; + * + * m = (pa_threaded_mainloop*)userdata; + * assert(m); + * + * pa_threaded_mainloop_signal(m, 0); + * } + * + * void my_drain_stream_func(pa_threaded_mainloop *m, pa_stream *s) { + * pa_operation *o; + * + * pa_threaded_mainloop_lock(m); + * + * o = pa_stream_drain(s, my_drain_callback, m); + * assert(o); + * + * while (pa_operation_get_state(o) != OPERATION_DONE) + * pa_threaded_mainloop_wait(m); + * + * pa_operation_unref(o); + * + * pa_threaded_mainloop_unlock(m); + * } + * \endcode + * + * The main function, my_drain_stream_func(), will wait for the callback to + * be called using pa_threaded_mainloop_wait(). + * + * If your application is multi-threaded, then this waiting must be done + * inside a while loop. The reason for this is that multiple threads might be + * using pa_threaded_mainloop_wait() at the same time. Each thread must + * therefore verify that it was its callback that was invoked. + * + * The callback, my_drain_callback(), indicates to the main function that it + * has been called using pa_threaded_mainloop_signal(). + * + * As you can see, both pa_threaded_mainloop_wait() may only be called with + * the lock held. The same thing is true for pa_threaded_mainloop_signal(), + * but as the lock is held before the callback is invoked, you do not have to + * deal with that. + * + * The functions will not dead lock because the wait function will release + * the lock before waiting and then regrab it once it has been signaled. + * For those of you familiar with threads, the behaviour is that of a + * condition variable. + * + * \subsection data_subsec Data callbacks + * + * For many callbacks, simply knowing that they have been called is + * insufficient. The callback also receives some data that is desired. To + * access this data safely, we must extend our example a bit: + * + * \code + * static int *drain_result; + * + * static void my_drain_callback(pa_stream*s, int success, void *userdata) { + * pa_threaded_mainloop *m; + * + * m = (pa_threaded_mainloop*)userdata; + * assert(m); + * + * drain_result = &success; + * + * pa_threaded_mainloop_signal(m, 1); + * } + * + * void my_drain_stream_func(pa_threaded_mainloop *m, pa_stream *s) { + * pa_operation *o; + * + * pa_threaded_mainloop_lock(m); + * + * o = pa_stream_drain(s, my_drain_callback, m); + * assert(o); + * + * while (pa_operation_get_state(o) != OPERATION_DONE) + * pa_threaded_mainloop_wait(m); + * + * pa_operation_unref(o); + * + * if (*drain_result) + * printf("Success!"); + * else + * printf("Bitter defeat..."); + * + * pa_threaded_mainloop_accept(m); + * + * pa_threaded_mainloop_unlock(m); + * } + * \endcode + * + * The example is a bit silly as it would probably have been easier to just + * copy the contents of success, but for larger data structures this can be + * wasteful. + * + * The difference here compared to the basic callback is the 1 sent to + * pa_threaded_mainloop_signal() and the call to + * pa_threaded_mainloop_accept(). What will happen is that + * pa_threaded_mainloop_signal() will signal the main function and then stop. + * The main function is then free to use the data in the callback until + * pa_threaded_mainloop_accept() is called, which will allow the callback + * to continue. + * + * Note that pa_threaded_mainloop_accept() must be called some time between + * exiting the while loop and unlocking the main loop! Failure to do so will + * result in a race condition. I.e. it is not ok to release the lock and + * regrab it before calling pa_threaded_mainloop_accept(). + * + * \subsection async_subsec Asynchronous callbacks + * + * Polypaudio also has callbacks that are completely asynchronous, meaning + * that they can be called at any time. The threading main loop API provides + * the locking mechanism to handle concurrent accesses, but nothing else. + * Applications will have to handle communication from the callback to the + * main program through some own system. + * + * The callbacks that are completely asynchronous are: + * + * \li State callbacks for contexts, streams, etc. + * \li Subscription notifications + */ + +/** \file + * + * A thread based event loop implementation based on pa_mainloop. The + * event loop is run in a helper thread in the background. A few + * synchronization primitives are available to access the objects + * attached to the event loop safely. */ + +/** An opaque threaded main loop object */ +typedef struct pa_threaded_mainloop pa_threaded_mainloop; + +/** Allocate a new threaded main loop object. You have to call + * pa_threaded_mainloop_start() before the event loop thread starts + * running. */ +pa_threaded_mainloop *pa_threaded_mainloop_new(void); + +/** Free a threaded main loop object. If the event loop thread is + * still running, it is terminated using pa_threaded_mainloop_stop() + * first. */ +void pa_threaded_mainloop_free(pa_threaded_mainloop* m); + +/** Start the event loop thread. */ +int pa_threaded_mainloop_start(pa_threaded_mainloop *m); + +/** Terminate the event loop thread cleanly. Make sure to unlock the + * mainloop object before calling this function. */ +void pa_threaded_mainloop_stop(pa_threaded_mainloop *m); + +/** Lock the event loop object, effectively blocking the event loop + * thread from processing events. You can use this to enforce + * exclusive access to all objects attached to the event loop. This + * lock is recursive. This function may not be called inside the event + * loop thread. Events that are dispatched from the event loop thread + * are executed with this lock held. */ +void pa_threaded_mainloop_lock(pa_threaded_mainloop *m); + +/** Unlock the event loop object, inverse of pa_threaded_mainloop_lock() */ +void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m); + +/** Wait for an event to be signalled by the event loop thread. You + * can use this to pass data from the event loop thread to the main + * thread in synchronized fashion. This function may not be called + * inside the event loop thread. Prior to this call the event loop + * object needs to be locked using pa_threaded_mainloop_lock(). While + * waiting the lock will be released, immediately before returning it + * will be acquired again. */ +void pa_threaded_mainloop_wait(pa_threaded_mainloop *m); + +/** Signal all threads waiting for a signalling event in + * pa_threaded_mainloop_wait(). If wait_for_release is non-zero, do + * not return before the signal was accepted by a + * pa_threaded_mainloop_accept() call. While waiting for that condition + * the event loop object is unlocked. */ +void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept); + +/** Accept a signal from the event thread issued with + * pa_threaded_mainloop_signal(). This call should only be used in + * conjunction with pa_threaded_mainloop_signal() with a non-zero + * wait_for_accept value. */ +void pa_threaded_mainloop_accept(pa_threaded_mainloop *m); + +/** Return the return value as specified with the main loop's quit() routine. */ +int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m); + +/** Return the abstract main loop abstraction layer vtable for this main loop. */ +pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m); + +PA_C_DECL_END + +#endif diff --git a/src/pulse/timeval.c b/src/pulse/timeval.c new file mode 100644 index 00000000..11285230 --- /dev/null +++ b/src/pulse/timeval.c @@ -0,0 +1,142 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include "../pulsecore/winsock.h" + +#include "timeval.h" + +struct timeval *pa_gettimeofday(struct timeval *tv) { +#ifdef HAVE_GETTIMEOFDAY + assert(tv); + + return gettimeofday(tv, NULL) < 0 ? NULL : tv; +#elif defined(OS_IS_WIN32) + /* + * Copied from implementation by Steven Edwards (LGPL). + * Found on wine mailing list. + */ + +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define EPOCHFILETIME (116444736000000000i64) +#else +#define EPOCHFILETIME (116444736000000000LL) +#endif + + FILETIME ft; + LARGE_INTEGER li; + __int64 t; + + assert(tv); + + GetSystemTimeAsFileTime(&ft); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + t = li.QuadPart; /* In 100-nanosecond intervals */ + t -= EPOCHFILETIME; /* Offset to the Epoch time */ + t /= 10; /* In microseconds */ + tv->tv_sec = (long)(t / 1000000); + tv->tv_usec = (long)(t % 1000000); + + return tv; +#else +#error "Platform lacks gettimeofday() or equivalent function." +#endif +} + +pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { + pa_usec_t r; + assert(a && b); + + /* Check which whan is the earlier time and swap the two arguments if reuqired. */ + if (pa_timeval_cmp(a, b) < 0) { + const struct timeval *c; + c = a; + a = b; + b = c; + } + + /* Calculate the second difference*/ + r = ((pa_usec_t) a->tv_sec - b->tv_sec)* 1000000; + + /* Calculate the microsecond difference */ + if (a->tv_usec > b->tv_usec) + r += ((pa_usec_t) a->tv_usec - b->tv_usec); + else if (a->tv_usec < b->tv_usec) + r -= ((pa_usec_t) b->tv_usec - a->tv_usec); + + return r; +} + +int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { + assert(a && b); + + if (a->tv_sec < b->tv_sec) + return -1; + + if (a->tv_sec > b->tv_sec) + return 1; + + if (a->tv_usec < b->tv_usec) + return -1; + + if (a->tv_usec > b->tv_usec) + return 1; + + return 0; +} + +pa_usec_t pa_timeval_age(const struct timeval *tv) { + struct timeval now; + assert(tv); + + return pa_timeval_diff(pa_gettimeofday(&now), tv); +} + +struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v) { + unsigned long secs; + assert(tv); + + secs = (v/1000000); + tv->tv_sec += (unsigned long) secs; + v -= secs*1000000; + + tv->tv_usec += v; + + /* Normalize */ + while (tv->tv_usec >= 1000000) { + tv->tv_sec++; + tv->tv_usec -= 1000000; + } + + return tv; +} diff --git a/src/pulse/timeval.h b/src/pulse/timeval.h new file mode 100644 index 00000000..e2dbbadb --- /dev/null +++ b/src/pulse/timeval.h @@ -0,0 +1,53 @@ +#ifndef footimevalhfoo +#define footimevalhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/** \file + * Utility functions for handling timeval calculations */ + +PA_C_DECL_BEGIN + +struct timeval; + +/** Return the current timestamp, just like UNIX gettimeofday() */ +struct timeval *pa_gettimeofday(struct timeval *tv); + +/** Calculate the difference between the two specified timeval + * structs. */ +pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); + +/** Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwse */ +int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); + +/** Return the time difference between now and the specified timestamp */ +pa_usec_t pa_timeval_age(const struct timeval *tv); + +/** Add the specified time inmicroseconds to the specified timeval structure */ +struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v); + +PA_C_DECL_END + +#endif diff --git a/src/pulse/utf8.c b/src/pulse/utf8.c new file mode 100644 index 00000000..33fa7214 --- /dev/null +++ b/src/pulse/utf8.c @@ -0,0 +1,237 @@ +/* $Id$ */ + +/* This file is based on the GLIB utf8 validation functions. The + * original license text follows. */ + +/* gutf8.c - Operations on UTF-8 strings. + * + * Copyright (C) 1999 Tom Tromey + * Copyright (C) 2000 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#ifdef HAVE_ICONV +#include +#endif + +#include "utf8.h" +#include "xmalloc.h" + +#define FILTER_CHAR '_' + +static inline int is_unicode_valid(uint32_t ch) { + if (ch >= 0x110000) /* End of unicode space */ + return 0; + if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ + return 0; + if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ + return 0; + if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ + return 0; + return 1; +} + +static inline int is_continuation_char(uint8_t ch) { + if ((ch & 0xc0) != 0x80) /* 10xxxxxx */ + return 0; + return 1; +} + +static inline void merge_continuation_char(uint32_t *u_ch, uint8_t ch) { + *u_ch <<= 6; + *u_ch |= ch & 0x3f; +} + +static char* utf8_validate(const char *str, char *output) { + uint32_t val = 0; + uint32_t min = 0; + const uint8_t *p, *last; + int size; + uint8_t *o; + + o = (uint8_t*) output; + for (p = (const uint8_t*) str; *p; p++) { + if (*p < 128) { + if (o) + *o = *p; + } else { + last = p; + + if ((*p & 0xe0) == 0xc0) { /* 110xxxxx two-char seq. */ + size = 2; + min = 128; + val = *p & 0x1e; + goto ONE_REMAINING; + } else if ((*p & 0xf0) == 0xe0) { /* 1110xxxx three-char seq.*/ + size = 3; + min = (1 << 11); + val = *p & 0x0f; + goto TWO_REMAINING; + } else if ((*p & 0xf8) == 0xf0) { /* 11110xxx four-char seq */ + size = 4; + min = (1 << 16); + val = *p & 0x07; + } else { + size = 1; + goto error; + } + + p++; + if (!is_continuation_char(*p)) + goto error; + merge_continuation_char(&val, *p); + +TWO_REMAINING: + p++; + if (!is_continuation_char(*p)) + goto error; + merge_continuation_char(&val, *p); + +ONE_REMAINING: + p++; + if (!is_continuation_char(*p)) + goto error; + merge_continuation_char(&val, *p); + + if (val < min) + goto error; + + if (!is_unicode_valid(val)) + goto error; + + if (o) { + memcpy(o, last, size); + o += size - 1; + } + + if (o) + o++; + + continue; + +error: + if (o) { + *o = FILTER_CHAR; + p = last; /* We retry at the next character */ + } else + goto failure; + } + + if (o) + o++; + } + + if (o) { + *o = '\0'; + return output; + } + + return (char*) str; + +failure: + return NULL; +} + +const char* pa_utf8_valid (const char *str) { + return utf8_validate(str, NULL); +} + +char* pa_utf8_filter (const char *str) { + char *new_str; + + new_str = pa_xnew(char, strlen(str) + 1); + + return utf8_validate(str, new_str); +} + +#ifdef HAVE_ICONV + +static char* iconv_simple(const char *str, const char *to, const char *from) { + char *new_str; + size_t len, inlen; + + iconv_t cd; + ICONV_CONST char *inbuf; + char *outbuf; + size_t res, inbytes, outbytes; + + cd = iconv_open(to, from); + if (cd == (iconv_t)-1) + return NULL; + + inlen = len = strlen(str) + 1; + new_str = pa_xmalloc(len); + assert(new_str); + + while (1) { + inbuf = (ICONV_CONST char*)str; /* Brain dead prototype for iconv() */ + inbytes = inlen; + outbuf = new_str; + outbytes = len; + + res = iconv(cd, &inbuf, &inbytes, &outbuf, &outbytes); + + if (res != (size_t)-1) + break; + + if (errno != E2BIG) { + pa_xfree(new_str); + new_str = NULL; + break; + } + + assert(inbytes != 0); + + len += inbytes; + new_str = pa_xrealloc(new_str, len); + assert(new_str); + } + + iconv_close(cd); + + return new_str; +} + +char* pa_utf8_to_locale (const char *str) { + return iconv_simple(str, "", "UTF-8"); +} + +char* pa_locale_to_utf8 (const char *str) { + return iconv_simple(str, "UTF-8", ""); +} + +#else + +char* pa_utf8_to_locale (const char *str) { + return NULL; +} + +char* pa_locale_to_utf8 (const char *str) { + return NULL; +} + +#endif diff --git a/src/pulse/utf8.h b/src/pulse/utf8.h new file mode 100644 index 00000000..2eac724d --- /dev/null +++ b/src/pulse/utf8.h @@ -0,0 +1,47 @@ +#ifndef fooutf8hfoo +#define fooutf8hfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +/** \file + * UTF8 Validation functions + */ + +PA_C_DECL_BEGIN + +/** Test if the specified strings qualifies as valid UTF8. Return the string if so, otherwise NULL */ +const char *pa_utf8_valid(const char *str); + +/** Filter all invalid UTF8 characters from the specified string, returning a new fully UTF8 valid string. Don't forget to free the returned string with pa_xfree() */ +char *pa_utf8_filter(const char *str); + +/** Convert a UTF-8 string to the current locale. Free the string using pa_xfree(). */ +char* pa_utf8_to_locale (const char *str); + +/** Convert a string in the current locale to UTF-8. Free the string using pa_xfree(). */ +char* pa_locale_to_utf8 (const char *str); + +PA_C_DECL_END + +#endif diff --git a/src/pulse/util.c b/src/pulse/util.c new file mode 100644 index 00000000..338607c4 --- /dev/null +++ b/src/pulse/util.c @@ -0,0 +1,227 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_PWD_H +#include +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include "../pulsecore/winsock.h" + +#include +#include +#include + +#include "util.h" + +#ifndef OS_IS_WIN32 +#define PATH_SEP '/' +#else +#define PATH_SEP '\\' +#endif + +char *pa_get_user_name(char *s, size_t l) { + char *p; + char buf[1024]; + +#ifdef HAVE_PWD_H + struct passwd pw, *r; +#endif + + assert(s && l > 0); + + if (!(p = getenv("USER")) && !(p = getenv("LOGNAME")) && !(p = getenv("USERNAME"))) { +#ifdef HAVE_PWD_H + +#ifdef HAVE_GETPWUID_R + if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { +#else + /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) + * that do not support getpwuid_r. */ + if ((r = getpwuid(getuid())) == NULL) { +#endif + snprintf(s, l, "%lu", (unsigned long) getuid()); + return s; + } + + p = r->pw_name; + +#elif defined(OS_IS_WIN32) /* HAVE_PWD_H */ + DWORD size = sizeof(buf); + + if (!GetUserName(buf, &size)) + return NULL; + + p = buf; + +#else /* HAVE_PWD_H */ + return NULL; +#endif /* HAVE_PWD_H */ + } + + return pa_strlcpy(s, p, l); +} + +char *pa_get_host_name(char *s, size_t l) { + assert(s && l > 0); + if (gethostname(s, l) < 0) { + pa_log(__FILE__": gethostname(): %s", pa_cstrerror(errno)); + return NULL; + } + s[l-1] = 0; + return s; +} + +char *pa_get_home_dir(char *s, size_t l) { + char *e; + +#ifdef HAVE_PWD_H + char buf[1024]; + struct passwd pw, *r; +#endif + + assert(s && l); + + if ((e = getenv("HOME"))) + return pa_strlcpy(s, e, l); + + if ((e = getenv("USERPROFILE"))) + return pa_strlcpy(s, e, l); + +#ifdef HAVE_PWD_H +#ifdef HAVE_GETPWUID_R + if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { + pa_log(__FILE__": getpwuid_r() failed"); +#else + /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) + * that do not support getpwuid_r. */ + if ((r = getpwuid(getuid())) == NULL) { + pa_log(__FILE__": getpwuid_r() failed"); +#endif + return NULL; + } + + return pa_strlcpy(s, r->pw_dir, l); +#else /* HAVE_PWD_H */ + return NULL; +#endif +} + +char *pa_get_binary_name(char *s, size_t l) { + +#ifdef HAVE_READLINK + char path[PATH_MAX]; + int i; + assert(s && l); + + /* This works on Linux only */ + + snprintf(path, sizeof(path), "/proc/%u/exe", (unsigned) getpid()); + if ((i = readlink(path, s, l-1)) < 0) + return NULL; + + s[i] = 0; + return s; +#elif defined(OS_IS_WIN32) + char path[PATH_MAX]; + if (!GetModuleFileName(NULL, path, PATH_MAX)) + return NULL; + pa_strlcpy(s, pa_path_get_filename(path), l); + return s; +#else + return NULL; +#endif +} + +const char *pa_path_get_filename(const char *p) { + char *fn; + + if ((fn = strrchr(p, PATH_SEP))) + return fn+1; + + return (const char*) p; +} + +char *pa_get_fqdn(char *s, size_t l) { + char hn[256]; +#ifdef HAVE_GETADDRINFO + struct addrinfo *a, hints; +#endif + + if (!pa_get_host_name(hn, sizeof(hn))) + return NULL; + +#ifdef HAVE_GETADDRINFO + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_CANONNAME; + + if (getaddrinfo(hn, NULL, &hints, &a) < 0 || !a || !a->ai_canonname || !*a->ai_canonname) + return pa_strlcpy(s, hn, l); + + pa_strlcpy(s, a->ai_canonname, l); + freeaddrinfo(a); + return s; +#else + return pa_strlcpy(s, hn, l); +#endif +} + +int pa_msleep(unsigned long t) { +#ifdef OS_IS_WIN32 + Sleep(t); + return 0; +#elif defined(HAVE_NANOSLEEP) + struct timespec ts; + + ts.tv_sec = t/1000; + ts.tv_nsec = (t % 1000) * 1000000; + + return nanosleep(&ts, NULL); +#else +#error "Platform lacks a sleep function." +#endif +} diff --git a/src/pulse/util.h b/src/pulse/util.h new file mode 100644 index 00000000..5c03b0a9 --- /dev/null +++ b/src/pulse/util.h @@ -0,0 +1,59 @@ +#ifndef fooutilhfoo +#define fooutilhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include + +/** \file + * Assorted utility functions */ + +PA_C_DECL_BEGIN + +/** Return the current username in the specified string buffer. */ +char *pa_get_user_name(char *s, size_t l); + +/** Return the current hostname in the specified buffer. */ +char *pa_get_host_name(char *s, size_t l); + +/** Return the fully qualified domain name in s */ +char *pa_get_fqdn(char *s, size_t l); + +/** Return the home directory of the current user */ +char *pa_get_home_dir(char *s, size_t l); + +/** Return the binary file name of the current process. This is not + * supported on all architectures, in which case NULL is returned. */ +char *pa_get_binary_name(char *s, size_t l); + +/** Return a pointer to the filename inside a path (which is the last + * component). */ +const char *pa_path_get_filename(const char *p); + +/** Wait t milliseconds */ +int pa_msleep(unsigned long t); + +PA_C_DECL_END + +#endif diff --git a/src/pulse/version.h.in b/src/pulse/version.h.in new file mode 100644 index 00000000..6c5492e8 --- /dev/null +++ b/src/pulse/version.h.in @@ -0,0 +1,53 @@ +#ifndef fooversionhfoo /*-*-C-*-*/ +#define fooversionhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* WARNING: Make sure to edit the real source file version.h.in! */ + +#include + +/** \file + * Define header version */ + +PA_C_DECL_BEGIN + +/** Return the version of the header files. Keep in mind that this is +a macro and not a function, so it is impossible to get the pointer of +it. */ +#define pa_get_headers_version() ("@PACKAGE_VERSION@") + +/** Return the version of the library the current application is linked to. */ +const char* pa_get_library_version(void); + +/** The current API version. Version 6 relates to pulseaudio + * 0.6. Prior versions (i.e. Polypaudio 0.5.1 and older) have + * PA_API_VERSION undefined. */ +#define PA_API_VERSION @PA_API_VERSION@ + +/** The current protocol version. Version 8 relates to pulseaudio 0.8. + * \since 0.8 */ +#define PA_PROTOCOL_VERSION @PA_PROTOCOL_VERSION@ + +PA_C_DECL_END + +#endif diff --git a/src/pulse/volume.c b/src/pulse/volume.c new file mode 100644 index 00000000..530814e0 --- /dev/null +++ b/src/pulse/volume.c @@ -0,0 +1,176 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "volume.h" + +int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) { + int i; + assert(a); + assert(b); + + if (a->channels != b->channels) + return 0; + + for (i = 0; i < a->channels; i++) + if (a->values[i] != b->values[i]) + return 0; + + return 1; +} + +pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) { + int i; + + assert(a); + assert(channels > 0); + assert(channels <= PA_CHANNELS_MAX); + + a->channels = channels; + + for (i = 0; i < a->channels; i++) + a->values[i] = v; + + return a; +} + +pa_volume_t pa_cvolume_avg(const pa_cvolume *a) { + uint64_t sum = 0; + int i; + assert(a); + + for (i = 0; i < a->channels; i++) + sum += a->values[i]; + + sum /= a->channels; + + return (pa_volume_t) sum; +} + +pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) { + return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a)* pa_sw_volume_to_linear(b)); +} + +#define USER_DECIBEL_RANGE 30 + +pa_volume_t pa_sw_volume_from_dB(double dB) { + if (dB <= -USER_DECIBEL_RANGE) + return PA_VOLUME_MUTED; + + return (pa_volume_t) ((dB/USER_DECIBEL_RANGE+1)*PA_VOLUME_NORM); +} + +double pa_sw_volume_to_dB(pa_volume_t v) { + if (v == PA_VOLUME_MUTED) + return PA_DECIBEL_MININFTY; + + return ((double) v/PA_VOLUME_NORM-1)*USER_DECIBEL_RANGE; +} + +pa_volume_t pa_sw_volume_from_linear(double v) { + + if (v <= 0) + return PA_VOLUME_MUTED; + + if (v > .999 && v < 1.001) + return PA_VOLUME_NORM; + + return pa_sw_volume_from_dB(20*log10(v)); +} + +double pa_sw_volume_to_linear(pa_volume_t v) { + + if (v == PA_VOLUME_MUTED) + return 0; + + return pow(10, pa_sw_volume_to_dB(v)/20); +} + +char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) { + unsigned channel; + int first = 1; + char *e; + + assert(s); + assert(l > 0); + assert(c); + + *(e = s) = 0; + + for (channel = 0; channel < c->channels && l > 1; channel++) { + l -= snprintf(e, l, "%s%u: %3u%%", + first ? "" : " ", + channel, + (c->values[channel]*100)/PA_VOLUME_NORM); + + e = strchr(e, 0); + first = 0; + } + + return s; +} + +/** Return non-zero if the volume of all channels is equal to the specified value */ +int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) { + unsigned c; + assert(a); + + for (c = 0; c < a->channels; c++) + if (a->values[c] != v) + return 0; + + return 1; +} + +pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { + unsigned i; + + assert(dest); + assert(a); + assert(b); + + for (i = 0; i < a->channels && i < b->channels && i < PA_CHANNELS_MAX; i++) { + + dest->values[i] = pa_sw_volume_multiply( + i < a->channels ? a->values[i] : PA_VOLUME_NORM, + i < b->channels ? b->values[i] : PA_VOLUME_NORM); + } + + dest->channels = i; + + return dest; +} + +int pa_cvolume_valid(const pa_cvolume *v) { + assert(v); + + if (v->channels <= 0 || v->channels > PA_CHANNELS_MAX) + return 0; + + return 1; +} diff --git a/src/pulse/volume.h b/src/pulse/volume.h new file mode 100644 index 00000000..d403a09e --- /dev/null +++ b/src/pulse/volume.h @@ -0,0 +1,172 @@ +#ifndef foovolumehfoo +#define foovolumehfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include + +/** \page volume Volume Control + * + * \section overv_sec Overview + * + * Sinks, sources, sink inputs and samples can all have their own volumes. + * To deal with these, The Polypaudio libray contains a number of functions + * that ease handling. + * + * The basic volume type in Polypaudio is the \ref pa_volume_t type. Most of + * the time, applications will use the aggregated pa_cvolume structure that + * can store the volume of all channels at once. + * + * Volumes commonly span between muted (0%), and normal (100%). It is possible + * to set volumes to higher than 100%, but clipping might occur. + * + * \section calc_sec Calculations + * + * The volumes in Polypaudio are logarithmic in nature and applications + * shouldn't perform calculations with them directly. Instead, they should + * be converted to and from either dB or a linear scale: + * + * \li dB - pa_sw_volume_from_dB() / pa_sw_volume_to_dB() + * \li Linear - pa_sw_volume_from_linear() / pa_sw_volume_to_linear() + * + * For simple multiplication, pa_sw_volume_multiply() and + * pa_sw_cvolume_multiply() can be used. + * + * Calculations can only be reliably performed on software volumes + * as it is commonly unknown what scale hardware volumes relate to. + * + * The functions described above are only valid when used with + * software volumes. Hence it is usually a better idea to treat all + * volume values as opaque with a range from PA_VOLUME_MUTE (0%) to + * PA_VOLUME_NORM (100%) and to refrain from any calculations with + * them. + * + * \section conv_sec Convenience Functions + * + * To handle the pa_cvolume structure, the Polypaudio library provides a + * number of convenienc functions: + * + * \li pa_cvolume_valid() - Tests if a pa_cvolume structure is valid. + * \li pa_cvolume_equal() - Tests if two pa_cvolume structures are identical. + * \li pa_cvolume_channels_equal_to() - Tests if all channels of a pa_cvolume + * structure have a given volume. + * \li pa_cvolume_is_muted() - Tests if all channels of a pa_cvolume + * structure are muted. + * \li pa_cvolume_is_norm() - Tests if all channels of a pa_cvolume structure + * are at a normal volume. + * \li pa_cvolume_set() - Set all channels of a pa_cvolume structure to a + * certain volume. + * \li pa_cvolume_reset() - Set all channels of a pa_cvolume structure to a + * normal volume. + * \li pa_cvolume_mute() - Set all channels of a pa_cvolume structure to a + * muted volume. + * \li pa_cvolume_avg() - Return the average volume of all channels. + * \li pa_cvolume_snprint() - Pretty print a pa_cvolume structure. + */ + +/** \file + * Constants and routines for volume handling */ + +PA_C_DECL_BEGIN + +/** Volume specification: + * PA_VOLUME_MUTED: silence; + * < PA_VOLUME_NORM: decreased volume; + * PA_VOLUME_NORM: normal volume; + * > PA_VOLUME_NORM: increased volume */ +typedef uint32_t pa_volume_t; + +/** Normal volume (100%) */ +#define PA_VOLUME_NORM (0x10000) + +/** Muted volume (0%) */ +#define PA_VOLUME_MUTED (0) + +/** A structure encapsulating a per-channel volume */ +typedef struct pa_cvolume { + uint8_t channels; /**< Number of channels */ + pa_volume_t values[PA_CHANNELS_MAX]; /**< Per-channel volume */ +} pa_cvolume; + +/** Return non-zero when *a == *b */ +int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b); + +/** Set the volume of all channels to PA_VOLUME_NORM */ +#define pa_cvolume_reset(a, n) pa_cvolume_set((a), (n), PA_VOLUME_NORM) + +/** Set the volume of all channels to PA_VOLUME_MUTED */ +#define pa_cvolume_mute(a, n) pa_cvolume_set((a), (n), PA_VOLUME_MUTED) + +/** Set the volume of all channels to the specified parameter */ +pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v); + +/** Maximum length of the strings returned by pa_cvolume_snprint() */ +#define PA_CVOLUME_SNPRINT_MAX 64 + +/** Pretty print a volume structure */ +char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c); + +/** Return the average volume of all channels */ +pa_volume_t pa_cvolume_avg(const pa_cvolume *a); + +/** Return TRUE when the passed cvolume structure is valid, FALSE otherwise */ +int pa_cvolume_valid(const pa_cvolume *v); + +/** Return non-zero if the volume of all channels is equal to the specified value */ +int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v); + +/** Return 1 if the specified volume has all channels muted */ +#define pa_cvolume_is_muted(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_MUTED) + +/** Return 1 if the specified volume has all channels on normal level */ +#define pa_cvolume_is_norm(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_NORM) + +/** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. This is only valid for software volumes! */ +pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b); + +/** Multiply to per-channel volumes and return the result in *dest. This is only valid for software volumes! */ +pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b); + +/** Convert a decibel value to a volume. This is only valid for software volumes! \since 0.4 */ +pa_volume_t pa_sw_volume_from_dB(double f); + +/** Convert a volume to a decibel value. This is only valid for software volumes! \since 0.4 */ +double pa_sw_volume_to_dB(pa_volume_t v); + +/** Convert a linear factor to a volume. This is only valid for software volumes! \since 0.8 */ +pa_volume_t pa_sw_volume_from_linear(double v); + +/** Convert a volume to a linear factor. This is only valid for software volumes! \since 0.8 */ +double pa_sw_volume_to_linear(pa_volume_t v); + +#ifdef INFINITY +#define PA_DECIBEL_MININFTY (-INFINITY) +#else +/** This value is used as minus infinity when using pa_volume_{to,from}_dB(). \since 0.4 */ +#define PA_DECIBEL_MININFTY (-200) +#endif + +PA_C_DECL_END + +#endif diff --git a/src/pulse/xmalloc.c b/src/pulse/xmalloc.c new file mode 100644 index 00000000..46871aeb --- /dev/null +++ b/src/pulse/xmalloc.c @@ -0,0 +1,128 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include "xmalloc.h" + +/* Make sure not to allocate more than this much memory. */ +#define MAX_ALLOC_SIZE (1024*1024*20) /* 20MB */ + +/* #undef malloc */ +/* #undef free */ +/* #undef realloc */ +/* #undef strndup */ +/* #undef strdup */ + +static void oom(void) PA_GCC_NORETURN; + +/** called in case of an OOM situation. Prints an error message and + * exits */ +static void oom(void) { + static const char e[] = "Not enough memory\n"; + pa_loop_write(STDERR_FILENO, e, sizeof(e)-1); +#ifdef SIGQUIT + raise(SIGQUIT); +#endif + _exit(1); +} + +void* pa_xmalloc(size_t size) { + void *p; + assert(size > 0); + assert(size < MAX_ALLOC_SIZE); + + if (!(p = malloc(size))) + oom(); + + return p; +} + +void* pa_xmalloc0(size_t size) { + void *p; + assert(size > 0); + assert(size < MAX_ALLOC_SIZE); + + if (!(p = calloc(1, size))) + oom(); + + return p; +} + +void *pa_xrealloc(void *ptr, size_t size) { + void *p; + assert(size > 0); + assert(size < MAX_ALLOC_SIZE); + + if (!(p = realloc(ptr, size))) + oom(); + return p; +} + +void* pa_xmemdup(const void *p, size_t l) { + if (!p) + return NULL; + else { + char *r = pa_xmalloc(l); + memcpy(r, p, l); + return r; + } +} + +char *pa_xstrdup(const char *s) { + if (!s) + return NULL; + + return pa_xmemdup(s, strlen(s)+1); +} + +char *pa_xstrndup(const char *s, size_t l) { + char *e, *r; + + if (!s) + return NULL; + + if ((e = memchr(s, 0, l))) + return pa_xmemdup(s, e-s+1); + + r = pa_xmalloc(l+1); + memcpy(r, s, l); + r[l] = 0; + return r; +} + +void pa_xfree(void *p) { + if (!p) + return; + + free(p); +} diff --git a/src/pulse/xmalloc.h b/src/pulse/xmalloc.h new file mode 100644 index 00000000..126c495c --- /dev/null +++ b/src/pulse/xmalloc.h @@ -0,0 +1,78 @@ +#ifndef foomemoryhfoo +#define foomemoryhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include +#include + +/** \file + * Memory allocation functions. + */ + +PA_C_DECL_BEGIN + +/** Allocate the specified number of bytes, just like malloc() does. However, in case of OOM, terminate */ +void* pa_xmalloc(size_t l); + +/** Same as pa_xmalloc(), but initialize allocated memory to 0 */ +void *pa_xmalloc0(size_t l); + +/** The combination of pa_xmalloc() and realloc() */ +void *pa_xrealloc(void *ptr, size_t size); + +/** Free allocated memory */ +void pa_xfree(void *p); + +/** Duplicate the specified string, allocating memory with pa_xmalloc() */ +char *pa_xstrdup(const char *s); + +/** Duplicate the specified string, but truncate after l characters */ +char *pa_xstrndup(const char *s, size_t l); + +/** Duplicate the specified memory block */ +void* pa_xmemdup(const void *p, size_t l); + +/** Internal helper for pa_xnew() */ +static inline void* pa_xnew_internal(unsigned n, size_t k) { + assert(n < INT_MAX/k); + return pa_xmalloc(n*k); +} + +/** Allocate n new structures of the specified type. */ +#define pa_xnew(type, n) ((type*) pa_xnew_internal((n), sizeof(type))) + +/** Internal helper for pa_xnew0() */ +static inline void* pa_xnew0_internal(unsigned n, size_t k) { + assert(n < INT_MAX/k); + return pa_xmalloc0(n*k); +} + +/** Same as pa_xnew() but set the memory to zero */ +#define pa_xnew0(type, n) ((type*) pa_xnew0_internal((n), sizeof(type))) + +PA_C_DECL_END + +#endif diff --git a/src/pulsecore/Makefile b/src/pulsecore/Makefile new file mode 120000 index 00000000..c110232d --- /dev/null +++ b/src/pulsecore/Makefile @@ -0,0 +1 @@ +../pulse/Makefile \ No newline at end of file diff --git a/src/pulsecore/authkey-prop.c b/src/pulsecore/authkey-prop.c new file mode 100644 index 00000000..7eda1e49 --- /dev/null +++ b/src/pulsecore/authkey-prop.c @@ -0,0 +1,89 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include + +#include +#include + +#include "authkey-prop.h" + +struct authkey_data { + int ref; + size_t length; +}; + +int pa_authkey_prop_get(pa_core *c, const char *name, void *data, size_t len) { + struct authkey_data *a; + assert(c && name && data && len > 0); + + if (!(a = pa_property_get(c, name))) + return -1; + + assert(a->length == len); + memcpy(data, a+1, len); + return 0; +} + +int pa_authkey_prop_put(pa_core *c, const char *name, const void *data, size_t len) { + struct authkey_data *a; + assert(c && name); + + if (pa_property_get(c, name)) + return -1; + + a = pa_xmalloc(sizeof(struct authkey_data) + len); + a->ref = 1; + a->length = len; + memcpy(a+1, data, len); + + pa_property_set(c, name, a); + + return 0; +} + +void pa_authkey_prop_ref(pa_core *c, const char *name) { + struct authkey_data *a; + assert(c && name); + + a = pa_property_get(c, name); + assert(a && a->ref >= 1); + + a->ref++; +} + +void pa_authkey_prop_unref(pa_core *c, const char *name) { + struct authkey_data *a; + assert(c && name); + + a = pa_property_get(c, name); + assert(a && a->ref >= 1); + + if (!(--a->ref)) { + pa_property_remove(c, name); + pa_xfree(a); + } +} + + diff --git a/src/pulsecore/authkey-prop.h b/src/pulsecore/authkey-prop.h new file mode 100644 index 00000000..b1da28be --- /dev/null +++ b/src/pulsecore/authkey-prop.h @@ -0,0 +1,43 @@ +#ifndef fooauthkeyprophfoo +#define fooauthkeyprophfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +/* The authkey-prop uses a central property to store a previously + * loaded cookie in memory. Useful for sharing the same cookie between + * several modules. */ + +/* Return the data of the specified authorization key property. Doesn't alter the refernce count of the key */ +int pa_authkey_prop_get(pa_core *c, const char *name, void *data, size_t len); + +/* Store data in the specified authorization key property. The initial reference count is set to 1 */ +int pa_authkey_prop_put(pa_core *c, const char *name, const void *data, size_t len); + +/* Increase the reference count of the specified authorization key */ +void pa_authkey_prop_ref(pa_core *c, const char *name); + +/* Decrease the reference count of the specified authorization key */ +void pa_authkey_prop_unref(pa_core *c, const char *name); + +#endif diff --git a/src/pulsecore/authkey.c b/src/pulsecore/authkey.c new file mode 100644 index 00000000..064209d9 --- /dev/null +++ b/src/pulsecore/authkey.c @@ -0,0 +1,209 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "authkey.h" + +/* Generate a new authorization key, store it in file fd and return it in *data */ +static int generate(int fd, void *ret_data, size_t length) { + ssize_t r; + assert(fd >= 0 && ret_data && length); + + pa_random(ret_data, length); + + lseek(fd, 0, SEEK_SET); + ftruncate(fd, 0); + + if ((r = pa_loop_write(fd, ret_data, length)) < 0 || (size_t) r != length) { + pa_log(__FILE__": failed to write cookie file: %s", pa_cstrerror(errno)); + return -1; + } + + return 0; +} + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +/* Load an euthorization cookie from file fn and store it in data. If + * the cookie file doesn't exist, create it */ +static int load(const char *fn, void *data, size_t length) { + int fd = -1; + int writable = 1; + int unlock = 0, ret = -1; + ssize_t r; + assert(fn && data && length); + + if ((fd = open(fn, O_RDWR|O_CREAT|O_BINARY, S_IRUSR|S_IWUSR)) < 0) { + if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY)) < 0) { + pa_log(__FILE__": failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); + goto finish; + } else + writable = 0; + } + + unlock = pa_lock_fd(fd, 1) >= 0; + + if ((r = pa_loop_read(fd, data, length)) < 0) { + pa_log(__FILE__": failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); + goto finish; + } + + if ((size_t) r != length) { + pa_log_debug(__FILE__": got %d bytes from cookie file '%s', expected %d", (int)r, fn, (int)length); + + if (!writable) { + pa_log(__FILE__": unable to write cookie to read only file"); + goto finish; + } + + if (generate(fd, data, length) < 0) + goto finish; + } + + ret = 0; + +finish: + + if (fd >= 0) { + + if (unlock) + pa_lock_fd(fd, 0); + + close(fd); + } + + return ret; +} + +/* Load a cookie from a cookie file. If the file doesn't exist, create it. */ +int pa_authkey_load(const char *path, void *data, size_t length) { + int ret; + + assert(path && data && length); + + ret = load(path, data, length); + + if (ret < 0) + pa_log(__FILE__": Failed to load authorization key '%s': %s", path, + (ret == -1) ? pa_cstrerror(errno) : "file corrupt"); + + return ret; +} + +/* If the specified file path starts with / return it, otherwise + * return path prepended with home directory */ +static const char *normalize_path(const char *fn, char *s, size_t l) { + assert(fn && s && l > 0); + +#ifndef OS_IS_WIN32 + if (fn[0] != '/') { +#else + if (strlen(fn) < 3 || !isalpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') { +#endif + char homedir[PATH_MAX]; + if (!pa_get_home_dir(homedir, sizeof(homedir))) + return NULL; + +#ifndef OS_IS_WIN32 + snprintf(s, l, "%s/%s", homedir, fn); +#else + snprintf(s, l, "%s\\%s", homedir, fn); +#endif + return s; + } + + return fn; +} + +/* Load a cookie from a file in the home directory. If the specified + * path starts with /, use it as absolute path instead. */ +int pa_authkey_load_auto(const char *fn, void *data, size_t length) { + char path[PATH_MAX]; + const char *p; + assert(fn && data && length); + + if (!(p = normalize_path(fn, path, sizeof(path)))) + return -2; + + return pa_authkey_load(p, data, length); +} + +/* Store the specified cookie in the speicified cookie file */ +int pa_authkey_save(const char *fn, const void *data, size_t length) { + int fd = -1; + int unlock = 0, ret = -1; + ssize_t r; + char path[PATH_MAX]; + const char *p; + assert(fn && data && length); + + if (!(p = normalize_path(fn, path, sizeof(path)))) + return -2; + + if ((fd = open(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { + pa_log(__FILE__": failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); + goto finish; + } + + unlock = pa_lock_fd(fd, 1) >= 0; + + if ((r = pa_loop_write(fd, data, length)) < 0 || (size_t) r != length) { + pa_log(__FILE__": failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); + goto finish; + } + + ret = 0; + +finish: + + if (fd >= 0) { + + if (unlock) + pa_lock_fd(fd, 0); + + close(fd); + } + + return ret; +} diff --git a/src/pulsecore/authkey.h b/src/pulsecore/authkey.h new file mode 100644 index 00000000..cc8a565c --- /dev/null +++ b/src/pulsecore/authkey.h @@ -0,0 +1,32 @@ +#ifndef fooauthkeyhfoo +#define fooauthkeyhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +int pa_authkey_load(const char *path, void *data, size_t len); +int pa_authkey_load_auto(const char *fn, void *data, size_t length); + +int pa_authkey_save(const char *path, const void *data, size_t length); + +#endif diff --git a/src/pulsecore/autoload.c b/src/pulsecore/autoload.c new file mode 100644 index 00000000..f6869097 --- /dev/null +++ b/src/pulsecore/autoload.c @@ -0,0 +1,182 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "autoload.h" + +static void entry_free(pa_autoload_entry *e) { + assert(e); + pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_AUTOLOAD|PA_SUBSCRIPTION_EVENT_REMOVE, PA_INVALID_INDEX); + pa_xfree(e->name); + pa_xfree(e->module); + pa_xfree(e->argument); + pa_xfree(e); +} + +static void entry_remove_and_free(pa_autoload_entry *e) { + assert(e && e->core); + + pa_idxset_remove_by_data(e->core->autoload_idxset, e, NULL); + pa_hashmap_remove(e->core->autoload_hashmap, e->name); + entry_free(e); +} + +static pa_autoload_entry* entry_new(pa_core *c, const char *name) { + pa_autoload_entry *e = NULL; + assert(c && name); + + if (c->autoload_hashmap && (e = pa_hashmap_get(c->autoload_hashmap, name))) + return NULL; + + e = pa_xmalloc(sizeof(pa_autoload_entry)); + e->core = c; + e->name = pa_xstrdup(name); + e->module = e->argument = NULL; + e->in_action = 0; + + if (!c->autoload_hashmap) + c->autoload_hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + assert(c->autoload_hashmap); + + pa_hashmap_put(c->autoload_hashmap, e->name, e); + + if (!c->autoload_idxset) + c->autoload_idxset = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + pa_idxset_put(c->autoload_idxset, e, &e->index); + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_AUTOLOAD|PA_SUBSCRIPTION_EVENT_NEW, e->index); + + return e; +} + +int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const char*module, const char *argument, uint32_t *idx) { + pa_autoload_entry *e = NULL; + assert(c && name && module && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); + + if (!(e = entry_new(c, name))) + return -1; + + e->module = pa_xstrdup(module); + e->argument = pa_xstrdup(argument); + e->type = type; + + if (idx) + *idx = e->index; + + return 0; +} + +int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type_t type) { + pa_autoload_entry *e; + assert(c && name && type); + + if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type) + return -1; + + entry_remove_and_free(e); + return 0; +} + +int pa_autoload_remove_by_index(pa_core *c, uint32_t idx) { + pa_autoload_entry *e; + assert(c && idx != PA_IDXSET_INVALID); + + if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, idx))) + return -1; + + entry_remove_and_free(e); + return 0; +} + +void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type_t type) { + pa_autoload_entry *e; + pa_module *m; + assert(c && name); + + if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || (e->type != type)) + return; + + if (e->in_action) + return; + + e->in_action = 1; + + if (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE) { + if ((m = pa_module_load(c, e->module, e->argument))) + m->auto_unload = 1; + } + + e->in_action = 0; +} + +static void free_func(void *p, PA_GCC_UNUSED void *userdata) { + pa_autoload_entry *e = p; + pa_idxset_remove_by_data(e->core->autoload_idxset, e, NULL); + entry_free(e); +} + +void pa_autoload_free(pa_core *c) { + if (c->autoload_hashmap) { + pa_hashmap_free(c->autoload_hashmap, free_func, NULL); + c->autoload_hashmap = NULL; + } + + if (c->autoload_idxset) { + pa_idxset_free(c->autoload_idxset, NULL, NULL); + c->autoload_idxset = NULL; + } +} + +const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type_t type) { + pa_autoload_entry *e; + assert(c && name); + + if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type) + return NULL; + + return e; +} + +const pa_autoload_entry* pa_autoload_get_by_index(pa_core *c, uint32_t idx) { + pa_autoload_entry *e; + assert(c && idx != PA_IDXSET_INVALID); + + if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, idx))) + return NULL; + + return e; +} diff --git a/src/pulsecore/autoload.h b/src/pulsecore/autoload.h new file mode 100644 index 00000000..65bdd6da --- /dev/null +++ b/src/pulsecore/autoload.h @@ -0,0 +1,58 @@ +#ifndef fooautoloadhfoo +#define fooautoloadhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +/* Using the autoloading facility, modules by be loaded on-demand and + * synchronously. The user may register a "ghost sink" or "ghost + * source". Whenever this sink/source is requested but not available a + * specified module is loaded. */ + +/* An autoload entry, or "ghost" sink/source */ +typedef struct pa_autoload_entry { + pa_core *core; + uint32_t index; + char *name; + pa_namereg_type_t type; /* Type of the autoload entry */ + int in_action; /* Currently loaded */ + char *module, *argument; +} pa_autoload_entry; + +/* Add a new autoload entry of the given time, with the speicified + * sink/source name, module name and argument. Return the entry's + * index in *index */ +int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const char*module, const char *argument, uint32_t *idx); + +/* Free all autoload entries */ +void pa_autoload_free(pa_core *c); +int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type_t type); +int pa_autoload_remove_by_index(pa_core *c, uint32_t idx); + +/* Request an autoload entry by its name, effectively causing a module to be loaded */ +void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type_t type); + +const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type_t type); +const pa_autoload_entry* pa_autoload_get_by_index(pa_core *c, uint32_t idx); + +#endif diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c new file mode 100644 index 00000000..4ba3e0af --- /dev/null +++ b/src/pulsecore/cli-command.c @@ -0,0 +1,947 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cli-command.h" + +struct command { + const char *name; + int (*proc) (pa_core *c, pa_tokenizer*t, pa_strbuf *buf, int *fail); + const char *help; + unsigned args; +}; + +#define INCLUDE_META ".include" +#define FAIL_META ".fail" +#define NOFAIL_META ".nofail" + +/* Prototypes for all available commands */ +static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); + + +/* A method table for all available commands */ + +static const struct command commands[] = { + { "exit", pa_cli_command_exit, "Terminate the daemon", 1 }, + { "help", pa_cli_command_help, "Show this help", 1 }, + { "list-modules", pa_cli_command_modules, "List loaded modules", 1 }, + { "list-sinks", pa_cli_command_sinks, "List loaded sinks", 1 }, + { "list-sources", pa_cli_command_sources, "List loaded sources", 1 }, + { "list-clients", pa_cli_command_clients, "List loaded clients", 1 }, + { "list-sink-inputs", pa_cli_command_sink_inputs, "List sink inputs", 1 }, + { "list-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-module", pa_cli_command_load, "Load a module (args: name, arguments)", 3}, + { "unload-module", pa_cli_command_unload, "Unload a module (args: index)", 2}, + { "set-sink-volume", pa_cli_command_sink_volume, "Set the volume of a sink (args: index|name, volume)", 3}, + { "set-sink-input-volume", pa_cli_command_sink_input_volume, "Set the volume of a sink input (args: index|name, volume)", 3}, + { "set-source-volume", pa_cli_command_source_volume, "Set the volume of a source (args: index|name, volume)", 3}, + { "set-sink-mute", pa_cli_command_sink_mute, "Set the mute switch of a sink (args: index|name, mute)", 3}, + { "set-source-mute", pa_cli_command_source_mute, "Set the mute switch of a source (args: index|name, mute)", 3}, + { "set-default-sink", pa_cli_command_sink_default, "Set the default sink (args: index|name)", 2}, + { "set-default-source", 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}, + { "list-samples", pa_cli_command_scache_list, "List all entries in the sample cache", 1}, + { "play-sample", pa_cli_command_scache_play, "Play a sample from the sample cache (args: name, sink|index)", 3}, + { "remove-sample", pa_cli_command_scache_remove, "Remove a sample from the sample cache (args: name)", 2}, + { "load-sample", pa_cli_command_scache_load, "Load a sound file into the sample cache (args: name, filename)", 3}, + { "load-sample-lazy", pa_cli_command_scache_load, "Lazily load a sound file into the sample cache (args: name, filename)", 3}, + { "load-sample-dir-lazy", pa_cli_command_scache_load_dir, "Lazily load all files in a directory into the sample cache (args: pathname)", 2}, + { "play-file", pa_cli_command_play_file, "Play a sound file (args: filename, sink|index)", 3}, + { "list-autoload", pa_cli_command_autoload_list, "List autoload entries", 1}, + { "add-autoload-sink", pa_cli_command_autoload_add, "Add autoload entry for a sink (args: sink, module name, arguments)", 4}, + { "add-autoload-source", pa_cli_command_autoload_add, "Add autoload entry for a source (args: source, module name, arguments)", 4}, + { "remove-autoload-sink", pa_cli_command_autoload_remove, "Remove autoload entry for a sink (args: name)", 2}, + { "remove-autoload-source", pa_cli_command_autoload_remove, "Remove autoload entry for a source (args: name)", 2}, + { "dump", pa_cli_command_dump, "Dump daemon configuration", 1}, + { "list-props", pa_cli_command_list_props, NULL, 1}, + { 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) { + uint32_t idx; + + if (pa_atou(n, &idx) < 0) + return (uint32_t) PA_IDXSET_INVALID; + + return idx; +} + +static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, PA_GCC_UNUSED pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + assert(c && c->mainloop && t); + c->mainloop->quit(c->mainloop, 0); + return 0; +} + +static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + 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, " %-25s %s\n", command->name, command->help); + return 0; +} + +static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + char *s; + assert(c && t); + s = pa_module_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + pa_xfree(s); + return 0; +} + +static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + char *s; + assert(c && t); + s = pa_client_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + pa_xfree(s); + return 0; +} + +static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + char *s; + assert(c && t); + s = pa_sink_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + pa_xfree(s); + return 0; +} + +static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + char *s; + assert(c && t); + s = pa_source_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + pa_xfree(s); + return 0; +} + +static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + char *s; + assert(c && t); + s = pa_sink_input_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + pa_xfree(s); + return 0; +} + +static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + char *s; + assert(c && t); + s = pa_source_output_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + pa_xfree(s); + return 0; +} + +static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + char s[256]; + assert(c && t); + + pa_bytes_snprint(s, sizeof(s), c->memblock_stat->total_size); + pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n", + c->memblock_stat->total, + s); + + pa_bytes_snprint(s, sizeof(s), c->memblock_stat->allocated_size); + pa_strbuf_printf(buf, "Memory blocks allocated during the whole lifetime: %u, size: %s.\n", + c->memblock_stat->allocated, + s); + + pa_bytes_snprint(s, sizeof(s), pa_scache_total_size(c)); + pa_strbuf_printf(buf, "Total sample cache size: %s.\n", s); + + pa_sample_spec_snprint(s, sizeof(s), &c->default_sample_spec); + pa_strbuf_printf(buf, "Default sample spec: %s\n", s); + + pa_strbuf_printf(buf, "Default sink name: %s\n" + "Default source name: %s\n", + pa_namereg_get_default_sink_name(c), + pa_namereg_get_default_source_name(c)); + + return 0; +} + +static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + assert(c && t); + pa_cli_command_stat(c, t, buf, fail); + pa_cli_command_modules(c, t, buf, fail); + pa_cli_command_sinks(c, t, buf, fail); + pa_cli_command_sources(c, t, buf, fail); + pa_cli_command_clients(c, t, buf, fail); + pa_cli_command_sink_inputs(c, t, buf, fail); + pa_cli_command_source_outputs(c, t, buf, fail); + pa_cli_command_scache_list(c, t, buf, fail); + pa_cli_command_autoload_list(c, t, buf, fail); + return 0; +} + +static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + pa_module *m; + const char *name; + 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; + } + + return 0; +} + +static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + pa_module *m; + uint32_t idx; + 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; + } + + idx = (uint32_t) strtoul(i, &e, 10); + if (*e || !(m = pa_idxset_get_by_index(c->modules, idx))) { + pa_strbuf_puts(buf, "Invalid module index.\n"); + return -1; + } + + pa_module_unload_request(m); + return 0; +} + +static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n, *v; + pa_sink *sink; + uint32_t volume; + pa_cvolume cvolume; + + 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; + } + + if (pa_atou(v, &volume) < 0) { + pa_strbuf_puts(buf, "Failed to parse volume.\n"); + return -1; + } + + if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) { + pa_strbuf_puts(buf, "No sink found by this name or index.\n"); + return -1; + } + + pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume); + pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &cvolume); + return 0; +} + +static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n, *v; + pa_sink_input *si; + pa_volume_t volume; + pa_cvolume cvolume; + uint32_t idx; + + 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 ((idx = 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; + } + + if (pa_atou(v, &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) idx))) { + pa_strbuf_puts(buf, "No sink input found with this index.\n"); + return -1; + } + + pa_cvolume_set(&cvolume, si->sample_spec.channels, volume); + pa_sink_input_set_volume(si, &cvolume); + return 0; +} + +static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n, *v; + pa_source *source; + uint32_t volume; + pa_cvolume cvolume; + + 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 (!(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; + } + + if (pa_atou(v, &volume) < 0) { + pa_strbuf_puts(buf, "Failed to parse volume.\n"); + return -1; + } + + if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE, 1))) { + pa_strbuf_puts(buf, "No source found by this name or index.\n"); + return -1; + } + + pa_cvolume_set(&cvolume, source->sample_spec.channels, volume); + pa_source_set_volume(source, PA_MIXER_HARDWARE, &cvolume); + return 0; +} + +static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n, *m; + pa_sink *sink; + int mute; + + 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 (!(m = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n"); + return -1; + } + + if (pa_atoi(m, &mute) < 0) { + pa_strbuf_puts(buf, "Failed to parse mute switch.\n"); + return -1; + } + + if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) { + pa_strbuf_puts(buf, "No sink found by this name or index.\n"); + return -1; + } + + pa_sink_set_mute(sink, PA_MIXER_HARDWARE, mute); + return 0; +} + +static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n, *m; + pa_source *source; + int mute; + + 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 (!(m = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n"); + return -1; + } + + if (pa_atoi(m, &mute) < 0) { + pa_strbuf_puts(buf, "Failed to parse mute switch.\n"); + return -1; + } + + if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE, 1))) { + pa_strbuf_puts(buf, "No sink found by this name or index.\n"); + return -1; + } + + pa_source_set_mute(source, PA_MIXER_HARDWARE, mute); + return 0; +} + +static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n; + 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; + } + + pa_namereg_set_default(c, n, PA_NAMEREG_SINK); + return 0; +} + +static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n; + 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; + } + + pa_namereg_set_default(c, n, PA_NAMEREG_SOURCE); + return 0; +} + +static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n; + pa_client *client; + uint32_t idx; + 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 ((idx = 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, idx))) { + 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(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n; + pa_sink_input *sink_input; + uint32_t idx; + 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 ((idx = 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, idx))) { + 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(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + const char *n; + pa_source_output *source_output; + uint32_t idx; + 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 ((idx = 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, idx))) { + pa_strbuf_puts(buf, "No source output found by this index.\n"); + return -1; + } + + pa_source_output_kill(source_output); + return 0; +} + +static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + char *s; + assert(c && t); + s = pa_scache_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + pa_xfree(s); + return 0; +} + +static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *n, *sink_name; + pa_sink *sink; + assert(c && t && buf && fail); + + if (!(n = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a sample name and a sink name.\n"); + return -1; + } + + if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) { + pa_strbuf_puts(buf, "No sink by that name.\n"); + return -1; + } + + if (pa_scache_play_item(c, n, sink, PA_VOLUME_NORM) < 0) { + pa_strbuf_puts(buf, "Failed to play sample.\n"); + return -1; + } + + return 0; +} + +static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *n; + assert(c && t && buf && fail); + + if (!(n = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a sample name.\n"); + return -1; + } + + if (pa_scache_remove_item(c, n) < 0) { + pa_strbuf_puts(buf, "Failed to remove sample.\n"); + return -1; + } + + return 0; +} + +static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *fname, *n; + int r; + assert(c && t && buf && fail); + + if (!(fname = pa_tokenizer_get(t, 2)) || !(n = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a file name and a sample name.\n"); + return -1; + } + + if (strstr(pa_tokenizer_get(t, 0), "lazy")) + r = pa_scache_add_file_lazy(c, n, fname, NULL); + else + r = pa_scache_add_file(c, n, fname, NULL); + + if (r < 0) + pa_strbuf_puts(buf, "Failed to load sound file.\n"); + + return 0; +} + +static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *pname; + assert(c && t && buf && fail); + + if (!(pname = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a path name.\n"); + return -1; + } + + if (pa_scache_add_directory_lazy(c, pname) < 0) { + pa_strbuf_puts(buf, "Failed to load directory.\n"); + return -1; + } + + return 0; +} + +static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *fname, *sink_name; + pa_sink *sink; + assert(c && t && buf && fail); + + if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a file name and a sink name.\n"); + return -1; + } + + if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) { + pa_strbuf_puts(buf, "No sink by that name.\n"); + return -1; + } + + + return pa_play_file(sink, fname, NULL); +} + +static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *a, *b; + assert(c && t && buf && fail); + + if (!(a = pa_tokenizer_get(t, 1)) || !(b = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a device name, a filename or a module name and optionally module arguments\n"); + return -1; + } + + pa_autoload_add(c, a, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, b, pa_tokenizer_get(t, 3), NULL); + + return 0; +} + +static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *name; + assert(c && t && buf && fail); + + if (!(name = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a device name\n"); + return -1; + } + + if (pa_autoload_remove_by_name(c, name, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE) < 0) { + pa_strbuf_puts(buf, "Failed to remove autload entry\n"); + return -1; + } + + return 0; +} + +static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + char *s; + assert(c && t); + s = pa_autoload_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + pa_xfree(s); + return 0; +} + +static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + assert(c && t); + pa_property_dump(c, buf); + return 0; +} + +static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { + pa_module *m; + pa_sink *sink; + pa_source *source; + int nl; + const char *p; + uint32_t idx; + char txt[256]; + time_t now; + void *i; + pa_autoload_entry *a; + + assert(c && t); + + time(&now); + +#ifdef HAVE_CTIME_R + pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime_r(&now, txt)); +#else + pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now)); +#endif + + + for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) { + if (m->auto_unload) + continue; + + pa_strbuf_printf(buf, "load-module %s", m->name); + + if (m->argument) + pa_strbuf_printf(buf, " %s", m->argument); + + pa_strbuf_puts(buf, "\n"); + } + + nl = 0; + + for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) { + if (sink->owner && sink->owner->auto_unload) + continue; + + if (!nl) { + pa_strbuf_puts(buf, "\n"); + nl = 1; + } + + pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, PA_MIXER_HARDWARE))); + pa_strbuf_printf(buf, "set-sink-mute %s %d\n", sink->name, pa_sink_get_mute(sink, PA_MIXER_HARDWARE)); + } + + for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) { + if (source->owner && source->owner->auto_unload) + continue; + + if (!nl) { + pa_strbuf_puts(buf, "\n"); + nl = 1; + } + + pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_avg(pa_source_get_volume(source, PA_MIXER_HARDWARE))); + pa_strbuf_printf(buf, "set-source-mute %s %d\n", source->name, pa_source_get_mute(source, PA_MIXER_HARDWARE)); + } + + + if (c->autoload_hashmap) { + nl = 0; + + i = NULL; + while ((a = pa_hashmap_iterate(c->autoload_hashmap, &i, NULL))) { + + if (!nl) { + pa_strbuf_puts(buf, "\n"); + nl = 1; + } + + pa_strbuf_printf(buf, "add-autoload-%s %s %s", a->type == PA_NAMEREG_SINK ? "sink" : "source", a->name, a->module); + + if (a->argument) + pa_strbuf_printf(buf, " %s", a->argument); + + pa_strbuf_puts(buf, "\n"); + } + } + + nl = 0; + + if ((p = pa_namereg_get_default_sink_name(c))) { + if (!nl) { + pa_strbuf_puts(buf, "\n"); + nl = 1; + } + pa_strbuf_printf(buf, "set-default-sink %s\n", p); + } + + if ((p = pa_namereg_get_default_source_name(c))) { + if (!nl) { + pa_strbuf_puts(buf, "\n"); + nl = 1; + } + pa_strbuf_printf(buf, "set-default-source %s\n", p); + } + + pa_strbuf_puts(buf, "\n### EOF\n"); + + return 0; +} + + +int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { + const char *cs; + + cs = s+strspn(s, whitespace); + + if (*cs == '#' || !*cs) + return 0; + else if (*cs == '.') { + if (!strcmp(cs, FAIL_META)) + *fail = 1; + else if (!strcmp(cs, NOFAIL_META)) + *fail = 0; + else { + size_t l; + 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) < 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; + pa_tokenizer *t = pa_tokenizer_new(cs, command->args); + assert(t); + ret = command->proc(c, t, buf, fail); + 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(pa_core *c, const char *fn, pa_strbuf *buf, int *fail) { + 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, pa_cstrerror(errno)); + if (!*fail) + ret = 0; + goto fail; + } + + while (fgets(line, sizeof(line), f)) { + char *e = line + strcspn(line, linebreak); + *e = 0; + + if (pa_cli_command_execute_line(c, line, buf, fail) < 0 && *fail) + goto fail; + } + + ret = 0; + +fail: + if (f) + fclose(f); + + return ret; +} + +int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { + const char *p; + assert(c && s && buf && fail); + + p = s; + while (*p) { + size_t l = strcspn(p, linebreak); + char *line = pa_xstrndup(p, l); + + if (pa_cli_command_execute_line(c, line, buf, fail) < 0&& *fail) { + pa_xfree(line); + return -1; + } + pa_xfree(line); + + p += l; + p += strspn(p, linebreak); + } + + return 0; +} diff --git a/src/pulsecore/cli-command.h b/src/pulsecore/cli-command.h new file mode 100644 index 00000000..c56c3ca0 --- /dev/null +++ b/src/pulsecore/cli-command.h @@ -0,0 +1,40 @@ +#ifndef fooclicommandhfoo +#define fooclicommandhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/* Execute a single CLI command. Write the results to the string + * buffer *buf. If *fail is non-zero the function will return -1 when + * one or more of the executed commands failed. *fail + * may be modified by the function call. */ +int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail); + +/* Execute a whole file of CLI commands */ +int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int *fail); + +/* Split the specified string into lines and run pa_cli_command_execute_line() for each. */ +int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail); + +#endif diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c new file mode 100644 index 00000000..eecf68ff --- /dev/null +++ b/src/pulsecore/cli-text.c @@ -0,0 +1,387 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cli-text.h" + +char *pa_module_list_to_string(pa_core *c) { + pa_strbuf *s; + pa_module *m; + uint32_t idx = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_size(c->modules)); + + for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) + pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\targument: <%s>\n\tused: %i\n\tauto unload: %s\n", m->index, m->name, m->argument, m->n_used, m->auto_unload ? "yes" : "no"); + + return pa_strbuf_tostring_free(s); +} + +char *pa_client_list_to_string(pa_core *c) { + pa_strbuf *s; + pa_client *client; + uint32_t idx = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u client(s) logged in.\n", pa_idxset_size(c->clients)); + + for (client = pa_idxset_first(c->clients, &idx); client; client = pa_idxset_next(c->clients, &idx)) { + pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\tdriver: <%s>\n", client->index, client->name, client->driver); + + if (client->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", client->owner->index); + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_sink_list_to_string(pa_core *c) { + pa_strbuf *s; + pa_sink *sink; + uint32_t idx = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_size(c->sinks)); + + for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) { + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + + pa_strbuf_printf( + s, + " %c index: %u\n" + "\tname: <%s>\n" + "\tdriver: <%s>\n" + "\tvolume: <%s>\n" + "\tlatency: <%0.0f usec>\n" + "\tmonitor_source: <%u>\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n", + c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ', + sink->index, sink->name, + sink->driver, + pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, PA_MIXER_HARDWARE)), + (double) pa_sink_get_latency(sink), + sink->monitor_source->index, + pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map)); + + if (sink->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", sink->owner->index); + if (sink->description) + pa_strbuf_printf(s, "\tdescription: <%s>\n", sink->description); + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_source_list_to_string(pa_core *c) { + pa_strbuf *s; + pa_source *source; + uint32_t idx = PA_IDXSET_INVALID; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_size(c->sources)); + + for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) { + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + + + pa_strbuf_printf( + s, + " %c index: %u\n" + "\tname: <%s>\n" + "\tdriver: <%s>\n" + "\tlatency: <%0.0f usec>\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n", + c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ', + source->index, + source->name, + source->driver, + (double) pa_source_get_latency(source), + pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map)); + + if (source->monitor_of) + pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index); + if (source->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", source->owner->index); + if (source->description) + pa_strbuf_printf(s, "\tdescription: <%s>\n", source->description); + } + + return pa_strbuf_tostring_free(s); +} + + +char *pa_source_output_list_to_string(pa_core *c) { + pa_strbuf *s; + pa_source_output *o; + uint32_t idx = PA_IDXSET_INVALID; + static const char* const state_table[] = { + "RUNNING", + "CORKED", + "DISCONNECTED" + }; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_size(c->source_outputs)); + + for (o = pa_idxset_first(c->source_outputs, &idx); o; o = pa_idxset_next(c->source_outputs, &idx)) { + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + + assert(o->source); + + pa_strbuf_printf( + s, + " index: %u\n" + "\tname: '%s'\n" + "\tdriver: <%s>\n" + "\tstate: %s\n" + "\tsource: <%u> '%s'\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n" + "\tresample method: %s\n", + o->index, + o->name, + o->driver, + state_table[o->state], + o->source->index, o->source->name, + pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map), + pa_resample_method_to_string(pa_source_output_get_resample_method(o))); + if (o->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", o->owner->index); + if (o->client) + pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", o->client->index, o->client->name); + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_sink_input_list_to_string(pa_core *c) { + pa_strbuf *s; + pa_sink_input *i; + uint32_t idx = PA_IDXSET_INVALID; + static const char* const state_table[] = { + "RUNNING", + "CORKED", + "DISCONNECTED" + }; + + assert(c); + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_size(c->sink_inputs)); + + for (i = pa_idxset_first(c->sink_inputs, &idx); i; i = pa_idxset_next(c->sink_inputs, &idx)) { + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + + assert(i->sink); + + pa_strbuf_printf( + s, + " index: %u\n" + "\tname: <%s>\n" + "\tdriver: <%s>\n" + "\tstate: %s\n" + "\tsink: <%u> '%s'\n" + "\tvolume: <%s>\n" + "\tlatency: <%0.0f usec>\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n" + "\tresample method: %s\n", + i->index, + i->name, + i->driver, + state_table[i->state], + i->sink->index, i->sink->name, + pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)), + (double) pa_sink_input_get_latency(i), + pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), + pa_resample_method_to_string(pa_sink_input_get_resample_method(i))); + + if (i->owner) + pa_strbuf_printf(s, "\towner module: <%u>\n", i->owner->index); + if (i->client) + pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", i->client->index, i->client->name); + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_scache_list_to_string(pa_core *c) { + pa_strbuf *s; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u cache entries available.\n", c->scache ? pa_idxset_size(c->scache) : 0); + + if (c->scache) { + pa_scache_entry *e; + uint32_t idx = PA_IDXSET_INVALID; + + for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) { + double l = 0; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = "n/a", cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX] = "n/a"; + + if (e->memchunk.memblock) { + pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec); + pa_channel_map_snprint(cm, sizeof(cm), &e->channel_map); + l = (double) e->memchunk.length / pa_bytes_per_second(&e->sample_spec); + } + + pa_strbuf_printf( + s, + " name: <%s>\n" + "\tindex: <%u>\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n" + "\tlength: <%lu>\n" + "\tduration: <%0.1fs>\n" + "\tvolume: <%s>\n" + "\tlazy: %s\n" + "\tfilename: %s\n", + e->name, + e->index, + ss, + cm, + (long unsigned)(e->memchunk.memblock ? e->memchunk.length : 0), + l, + pa_cvolume_snprint(cv, sizeof(cv), &e->volume), + e->lazy ? "yes" : "no", + e->filename ? e->filename : "n/a"); + } + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_autoload_list_to_string(pa_core *c) { + pa_strbuf *s; + assert(c); + + s = pa_strbuf_new(); + assert(s); + + pa_strbuf_printf(s, "%u autoload entries available.\n", c->autoload_hashmap ? pa_hashmap_size(c->autoload_hashmap) : 0); + + if (c->autoload_hashmap) { + pa_autoload_entry *e; + void *state = NULL; + + while ((e = pa_hashmap_iterate(c->autoload_hashmap, &state, NULL))) { + pa_strbuf_printf( + s, " name: <%s>\n\ttype: <%s>\n\tindex: <%u>\n\tmodule_name: <%s>\n\targuments: <%s>\n", + e->name, + e->type == PA_NAMEREG_SOURCE ? "source" : "sink", + e->index, + e->module, + e->argument); + + } + } + + return pa_strbuf_tostring_free(s); +} + +char *pa_full_status_string(pa_core *c) { + pa_strbuf *s; + int i; + + s = pa_strbuf_new(); + + for (i = 0; i < 8; i++) { + char *t = NULL; + + switch (i) { + case 0: + t = pa_sink_list_to_string(c); + break; + case 1: + t = pa_source_list_to_string(c); + break; + case 2: + t = pa_sink_input_list_to_string(c); + break; + case 3: + t = pa_source_output_list_to_string(c); + break; + case 4: + t = pa_client_list_to_string(c); + break; + case 5: + t = pa_module_list_to_string(c); + break; + case 6: + t = pa_scache_list_to_string(c); + break; + case 7: + t = pa_autoload_list_to_string(c); + break; + } + + pa_strbuf_puts(s, t); + pa_xfree(t); + } + + return pa_strbuf_tostring_free(s); +} diff --git a/src/pulsecore/cli-text.h b/src/pulsecore/cli-text.h new file mode 100644 index 00000000..cd3acdee --- /dev/null +++ b/src/pulsecore/cli-text.h @@ -0,0 +1,42 @@ +#ifndef fooclitexthfoo +#define fooclitexthfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +/* Some functions to generate pretty formatted listings of + * entities. The returned strings have to be freed manually. */ + +char *pa_sink_input_list_to_string(pa_core *c); +char *pa_source_output_list_to_string(pa_core *c); +char *pa_sink_list_to_string(pa_core *core); +char *pa_source_list_to_string(pa_core *c); +char *pa_client_list_to_string(pa_core *c); +char *pa_module_list_to_string(pa_core *c); +char *pa_scache_list_to_string(pa_core *c); +char *pa_autoload_list_to_string(pa_core *c); + +char *pa_full_status_string(pa_core *c); + +#endif + diff --git a/src/pulsecore/cli.c b/src/pulsecore/cli.c new file mode 100644 index 00000000..fbfa5009 --- /dev/null +++ b/src/pulsecore/cli.c @@ -0,0 +1,149 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cli.h" + +#define PROMPT ">>> " + +struct pa_cli { + pa_core *core; + pa_ioline *line; + + void (*eof_callback)(pa_cli *c, void *userdata); + void *userdata; + + pa_client *client; + + int fail, kill_requested, defer_kill; +}; + +static void line_callback(pa_ioline *line, const char *s, void *userdata); +static void client_kill(pa_client *c); + +pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m) { + char cname[256]; + pa_cli *c; + assert(io); + + c = pa_xmalloc(sizeof(pa_cli)); + c->core = core; + c->line = pa_ioline_new(io); + assert(c->line); + + c->userdata = NULL; + c->eof_callback = NULL; + + pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); + c->client = pa_client_new(core, __FILE__, cname); + assert(c->client); + c->client->kill = client_kill; + c->client->userdata = c; + c->client->owner = m; + + pa_ioline_set_callback(c->line, line_callback, c); + pa_ioline_puts(c->line, "Welcome to pulseaudio! Use \"help\" for usage information.\n"PROMPT); + + c->fail = c->kill_requested = c->defer_kill = 0; + + return c; +} + +void pa_cli_free(pa_cli *c) { + assert(c); + pa_ioline_close(c->line); + pa_ioline_unref(c->line); + pa_client_free(c->client); + pa_xfree(c); +} + +static void client_kill(pa_client *client) { + pa_cli *c; + assert(client && client->userdata); + c = client->userdata; + + pa_log_debug(__FILE__": CLI client killed."); + if (c->defer_kill) + c->kill_requested = 1; + else { + if (c->eof_callback) + c->eof_callback(c, c->userdata); + } +} + +static void line_callback(pa_ioline *line, const char *s, void *userdata) { + pa_strbuf *buf; + pa_cli *c = userdata; + char *p; + assert(line && c); + + if (!s) { + pa_log_debug(__FILE__": CLI got EOF from user."); + if (c->eof_callback) + c->eof_callback(c, c->userdata); + + return; + } + + buf = pa_strbuf_new(); + assert(buf); + c->defer_kill++; + pa_cli_command_execute_line(c->core, s, buf, &c->fail); + c->defer_kill--; + pa_ioline_puts(line, p = pa_strbuf_tostring_free(buf)); + pa_xfree(p); + + 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(pa_cli *c, void (*cb)(pa_cli*c, void *userdata), void *userdata) { + assert(c); + c->eof_callback = cb; + c->userdata = userdata; +} diff --git a/src/pulsecore/cli.h b/src/pulsecore/cli.h new file mode 100644 index 00000000..639fa952 --- /dev/null +++ b/src/pulsecore/cli.h @@ -0,0 +1,38 @@ +#ifndef fooclihfoo +#define fooclihfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include + +typedef struct pa_cli pa_cli; + +/* Create a new command line session on the specified io channel owned by the specified module */ +pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m); +void pa_cli_free(pa_cli *cli); + +/* Set a callback function that is called whenever the command line session is terminated */ +void pa_cli_set_eof_callback(pa_cli *cli, void (*cb)(pa_cli*c, void *userdata), void *userdata); + +#endif diff --git a/src/pulsecore/client.c b/src/pulsecore/client.c new file mode 100644 index 00000000..bf2b13df --- /dev/null +++ b/src/pulsecore/client.c @@ -0,0 +1,96 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include +#include + +#include "client.h" + +pa_client *pa_client_new(pa_core *core, const char *driver, const char *name) { + pa_client *c; + int r; + assert(core); + + c = pa_xmalloc(sizeof(pa_client)); + c->name = pa_xstrdup(name); + c->driver = pa_xstrdup(driver); + c->owner = NULL; + c->core = core; + + c->kill = NULL; + c->userdata = NULL; + + r = pa_idxset_put(core->clients, c, &c->index); + assert(c->index != PA_IDXSET_INVALID && r >= 0); + + pa_log_info(__FILE__": created %u \"%s\"", c->index, c->name); + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index); + + pa_core_check_quit(core); + + return c; +} + +void pa_client_free(pa_client *c) { + assert(c && c->core); + + pa_idxset_remove_by_data(c->core->clients, c, NULL); + + pa_core_check_quit(c->core); + + pa_log_info(__FILE__": freed %u \"%s\"", c->index, c->name); + pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index); + pa_xfree(c->name); + pa_xfree(c->driver); + pa_xfree(c); +} + +void pa_client_kill(pa_client *c) { + assert(c); + if (!c->kill) { + pa_log_warn(__FILE__": kill() operation not implemented for client %u", c->index); + return; + } + + c->kill(c); +} + +void pa_client_set_name(pa_client *c, const char *name) { + assert(c); + + pa_log_info(__FILE__": client %u changed name from \"%s\" to \"%s\"", c->index, c->name, name); + + pa_xfree(c->name); + c->name = pa_xstrdup(name); + + pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->index); +} diff --git a/src/pulsecore/client.h b/src/pulsecore/client.h new file mode 100644 index 00000000..1e72baf7 --- /dev/null +++ b/src/pulsecore/client.h @@ -0,0 +1,57 @@ +#ifndef fooclienthfoo +#define fooclienthfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/* Every connection to the server should have a pa_client + * attached. That way the user may generate a listing of all connected + * clients easily and kill them if he wants.*/ + +typedef struct pa_client pa_client; + +struct pa_client { + uint32_t index; + + pa_module *owner; + char *name, *driver; + pa_core *core; + + void (*kill)(pa_client *c); + void *userdata; +}; + +pa_client *pa_client_new(pa_core *c, const char *driver, const char *name); + +/* This function should be called only by the code that created the client */ +void pa_client_free(pa_client *c); + +/* Code that didn't create the client should call this function to + * request destruction of the client */ +void pa_client_kill(pa_client *c); + +/* Rename the client */ +void pa_client_set_name(pa_client *c, const char *name); + +#endif diff --git a/src/pulsecore/conf-parser.c b/src/pulsecore/conf-parser.c new file mode 100644 index 00000000..cc471ff9 --- /dev/null +++ b/src/pulsecore/conf-parser.c @@ -0,0 +1,181 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "conf-parser.h" + +#define WHITESPACE " \t\n" +#define COMMENTS "#;\n" + +/* Run the user supplied parser for an assignment */ +static int next_assignment(const char *filename, unsigned line, const pa_config_item *t, const char *lvalue, const char *rvalue, void *userdata) { + assert(filename && t && lvalue && rvalue); + + for (; t->parse; t++) + if (!strcmp(lvalue, t->lvalue)) + return t->parse(filename, line, lvalue, rvalue, t->data, userdata); + + pa_log(__FILE__": [%s:%u] Unknown lvalue '%s'.", filename, line, lvalue); + + return -1; +} + +/* Returns non-zero when c is contained in s */ +static int in_string(char c, const char *s) { + assert(s); + + for (; *s; s++) + if (*s == c) + return 1; + + return 0; +} + +/* Remove all whitepsapce from the beginning and the end of *s. *s may + * be modified. */ +static char *strip(char *s) { + char *b = s+strspn(s, WHITESPACE); + char *e, *l = NULL; + + for (e = b; *e; e++) + if (!in_string(*e, WHITESPACE)) + l = e; + + if (l) + *(l+1) = 0; + + return b; +} + +/* Parse a variable assignment line */ +static int parse_line(const char *filename, unsigned line, const pa_config_item *t, char *l, void *userdata) { + char *e, *c, *b = l+strspn(l, WHITESPACE); + + if ((c = strpbrk(b, COMMENTS))) + *c = 0; + + if (!*b) + return 0; + + if (!(e = strchr(b, '='))) { + pa_log(__FILE__": [%s:%u] Missing '='.", filename, line); + return -1; + } + + *e = 0; + e++; + + return next_assignment(filename, line, t, strip(b), strip(e), userdata); +} + +/* Go through the file and parse each line */ +int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void *userdata) { + int r = -1; + unsigned line = 0; + int do_close = !f; + assert(filename && t); + + if (!f && !(f = fopen(filename, "r"))) { + if (errno == ENOENT) { + r = 0; + goto finish; + } + + pa_log_warn(__FILE__": WARNING: failed to open configuration file '%s': %s", + filename, pa_cstrerror(errno)); + goto finish; + } + + while (!feof(f)) { + char l[256]; + if (!fgets(l, sizeof(l), f)) { + if (feof(f)) + break; + + pa_log_warn(__FILE__": WARNING: failed to read configuration file '%s': %s", + filename, pa_cstrerror(errno)); + goto finish; + } + + if (parse_line(filename, ++line, t, l, userdata) < 0) + goto finish; + } + + r = 0; + +finish: + + if (do_close && f) + fclose(f); + + return r; +} + +int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + int *i = data; + int32_t k; + assert(filename && lvalue && rvalue && data); + + if (pa_atoi(rvalue, &k) < 0) { + pa_log(__FILE__": [%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); + return -1; + } + + *i = (int) k; + return 0; +} + +int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + int *b = data, k; + assert(filename && lvalue && rvalue && data); + + if ((k = pa_parse_boolean(rvalue)) < 0) { + pa_log(__FILE__": [%s:%u] Failed to parse boolean value: %s", filename, line, rvalue); + return -1; + } + + *b = k; + + return 0; +} + +int pa_config_parse_string(const char *filename, PA_GCC_UNUSED unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + char **s = data; + assert(filename && lvalue && rvalue && data); + + pa_xfree(*s); + *s = *rvalue ? pa_xstrdup(rvalue) : NULL; + return 0; +} diff --git a/src/pulsecore/conf-parser.h b/src/pulsecore/conf-parser.h new file mode 100644 index 00000000..9c1a697a --- /dev/null +++ b/src/pulsecore/conf-parser.h @@ -0,0 +1,47 @@ +#ifndef fooconfparserhfoo +#define fooconfparserhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +/* An abstract parser for simple, line based, shallow configuration + * files consisting of variable assignments only. */ + +/* Wraps info for parsing a specific configuration variable */ +typedef struct pa_config_item { + const char *lvalue; /* name of the variable */ + int (*parse)(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); /* Function that is called to parse the variable's value */ + void *data; /* Where to store the variable's data */ +} pa_config_item; + +/* The configuration file parsing routine. Expects a table of + * pa_config_items in *t that is terminated by an item where lvalue is + * NULL */ +int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void *userdata); + +/* Generic parsers for integers, booleans and strings */ +int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); +int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); +int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); + +#endif diff --git a/src/pulsecore/core-def.h b/src/pulsecore/core-def.h new file mode 100644 index 00000000..718499d1 --- /dev/null +++ b/src/pulsecore/core-def.h @@ -0,0 +1,30 @@ +#ifndef foocoredefhfoo +#define foocoredefhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef enum pa_mixer { + PA_MIXER_SOFTWARE, + PA_MIXER_HARDWARE +} pa_mixer_t; + +#endif diff --git a/src/pulsecore/core-error.c b/src/pulsecore/core-error.c new file mode 100644 index 00000000..e42070d1 --- /dev/null +++ b/src/pulsecore/core-error.c @@ -0,0 +1,205 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_PTHREAD +#include +#endif + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include +#include + +#include +#include + +#include "core-error.h" + +#ifdef HAVE_PTHREAD + +static pthread_once_t cstrerror_once = PTHREAD_ONCE_INIT; +static pthread_key_t tlsstr_key; + +static void inittls(void) { + int ret; + + ret = pthread_key_create(&tlsstr_key, pa_xfree); + if (ret) { + fprintf(stderr, __FILE__ ": CRITICAL: Unable to allocate TLS key (%d)\n", errno); + exit(-1); + } +} + +#elif HAVE_WINDOWS_H + +static DWORD tlsstr_key = TLS_OUT_OF_INDEXES; +static DWORD monitor_key = TLS_OUT_OF_INDEXES; + +static void inittls(void) { + HANDLE mutex; + char name[64]; + + sprintf(name, "pulseaudio%d", (int)GetCurrentProcessId()); + + mutex = CreateMutex(NULL, FALSE, name); + if (!mutex) { + fprintf(stderr, __FILE__ ": CRITICAL: Unable to create named mutex (%d)\n", (int)GetLastError()); + exit(-1); + } + + WaitForSingleObject(mutex, INFINITE); + + if (tlsstr_key == TLS_OUT_OF_INDEXES) { + tlsstr_key = TlsAlloc(); + monitor_key = TlsAlloc(); + if ((tlsstr_key == TLS_OUT_OF_INDEXES) || (monitor_key == TLS_OUT_OF_INDEXES)) { + fprintf(stderr, __FILE__ ": CRITICAL: Unable to allocate TLS key (%d)\n", (int)GetLastError()); + exit(-1); + } + } + + ReleaseMutex(mutex); + + CloseHandle(mutex); +} + +/* + * This is incredibly brain dead, but this is necessary when dealing with + * the hell that is Win32. + */ +struct monitor_data { + HANDLE thread; + void *data; +}; + +static DWORD WINAPI monitor_thread(LPVOID param) { + struct monitor_data *data; + + data = (struct monitor_data*)param; + assert(data); + + WaitForSingleObject(data->thread, INFINITE); + + CloseHandle(data->thread); + pa_xfree(data->data); + pa_xfree(data); + + return 0; +} + +static void start_monitor(void) { + HANDLE thread; + struct monitor_data *data; + + data = pa_xnew(struct monitor_data, 1); + assert(data); + + DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), + GetCurrentProcess(), &data->thread, 0, FALSE, DUPLICATE_SAME_ACCESS); + + thread = CreateThread(NULL, 0, monitor_thread, data, 0, NULL); + assert(thread); + + TlsSetValue(monitor_key, data); + + CloseHandle(thread); +} + +#else + +/* Unsafe, but we have no choice */ +static char *tlsstr; + +#endif + +const char* pa_cstrerror(int errnum) { + const char *origbuf; + +#ifdef HAVE_STRERROR_R + char errbuf[128]; +#endif + +#ifdef HAVE_PTHREAD + char *tlsstr; + + pthread_once(&cstrerror_once, inittls); + + tlsstr = pthread_getspecific(tlsstr_key); +#elif defined(HAVE_WINDOWS_H) + char *tlsstr; + struct monitor_data *data; + + inittls(); + + tlsstr = TlsGetValue(tlsstr_key); + if (!tlsstr) + start_monitor(); + data = TlsGetValue(monitor_key); +#endif + + if (tlsstr) + pa_xfree(tlsstr); + +#ifdef HAVE_STRERROR_R + +#ifdef __GLIBC__ + origbuf = strerror_r(errnum, errbuf, sizeof(errbuf)); + if (origbuf == NULL) + origbuf = ""; +#else + if (strerror_r(errnum, errbuf, sizeof(errbuf)) == 0) { + origbuf = errbuf; + errbuf[sizeof(errbuf) - 1] = '\0'; + } else + origbuf = ""; +#endif + +#else + /* This might not be thread safe, but we hope for the best */ + origbuf = strerror(errnum); +#endif + + tlsstr = pa_locale_to_utf8(origbuf); + if (!tlsstr) { + fprintf(stderr, "Unable to convert, filtering\n"); + tlsstr = pa_utf8_filter(origbuf); + } + +#ifdef HAVE_PTHREAD + pthread_setspecific(tlsstr_key, tlsstr); +#elif defined(HAVE_WINDOWS_H) + TlsSetValue(tlsstr_key, tlsstr); + data->data = tlsstr; +#endif + + return tlsstr; +} diff --git a/src/pulsecore/core-error.h b/src/pulsecore/core-error.h new file mode 100644 index 00000000..32da8bf2 --- /dev/null +++ b/src/pulsecore/core-error.h @@ -0,0 +1,41 @@ +#ifndef foocoreerrorhfoo +#define foocoreerrorhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/** \file + * Error management */ + +PA_C_DECL_BEGIN + +/** A wrapper around the standard strerror() function that converts the + * string to UTF-8. The function is thread safe but the returned string is + * only guaranteed to exist until the thread exits or pa_cstrerror() is + * called again from the same thread. */ +const char* pa_cstrerror(int errnum); + +PA_C_DECL_END + +#endif diff --git a/src/pulsecore/core-scache.c b/src/pulsecore/core-scache.c new file mode 100644 index 00000000..377dd569 --- /dev/null +++ b/src/pulsecore/core-scache.c @@ -0,0 +1,412 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_GLOB_H +#include +#endif + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core-scache.h" + +#define UNLOAD_POLL_TIME 2 + +static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + pa_core *c = userdata; + struct timeval ntv; + assert(c && c->mainloop == m && c->scache_auto_unload_event == e); + + pa_scache_unload_unused(c); + + pa_gettimeofday(&ntv); + ntv.tv_sec += UNLOAD_POLL_TIME; + m->time_restart(e, &ntv); +} + +static void free_entry(pa_scache_entry *e) { + assert(e); + pa_namereg_unregister(e->core, e->name); + pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_REMOVE, e->index); + pa_xfree(e->name); + pa_xfree(e->filename); + if (e->memchunk.memblock) + pa_memblock_unref(e->memchunk.memblock); + pa_xfree(e); +} + +static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { + pa_scache_entry *e; + assert(c && name); + + if ((e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) { + if (e->memchunk.memblock) + pa_memblock_unref(e->memchunk.memblock); + + pa_xfree(e->filename); + + assert(e->core == c); + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); + } else { + e = pa_xmalloc(sizeof(pa_scache_entry)); + + if (!pa_namereg_register(c, name, PA_NAMEREG_SAMPLE, e, 1)) { + pa_xfree(e); + return NULL; + } + + e->name = pa_xstrdup(name); + e->core = c; + + if (!c->scache) { + c->scache = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + assert(c->scache); + } + + pa_idxset_put(c->scache, e, &e->index); + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_NEW, e->index); + } + + e->last_used_time = 0; + e->memchunk.memblock = NULL; + e->memchunk.index = e->memchunk.length = 0; + e->filename = NULL; + e->lazy = 0; + e->last_used_time = 0; + + memset(&e->sample_spec, 0, sizeof(e->sample_spec)); + pa_channel_map_init(&e->channel_map); + pa_cvolume_reset(&e->volume, PA_CHANNELS_MAX); + + return e; +} + +int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx) { + pa_scache_entry *e; + assert(c && name); + + if (chunk && chunk->length > PA_SCACHE_ENTRY_SIZE_MAX) + return -1; + + if (!(e = scache_add_item(c, name))) + return -1; + + if (ss) { + e->sample_spec = *ss; + pa_channel_map_init_auto(&e->channel_map, ss->channels, PA_CHANNEL_MAP_DEFAULT); + e->volume.channels = e->sample_spec.channels; + } + + if (map) + e->channel_map = *map; + + if (chunk) { + e->memchunk = *chunk; + pa_memblock_ref(e->memchunk.memblock); + } + + if (idx) + *idx = e->index; + + return 0; +} + +int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint32_t *idx) { + pa_sample_spec ss; + pa_channel_map map; + pa_memchunk chunk; + int r; + +#ifdef OS_IS_WIN32 + char buf[MAX_PATH]; + + if (ExpandEnvironmentStrings(filename, buf, MAX_PATH)) + filename = buf; +#endif + + if (pa_sound_file_load(filename, &ss, &map, &chunk, c->memblock_stat) < 0) + return -1; + + r = pa_scache_add_item(c, name, &ss, &map, &chunk, idx); + pa_memblock_unref(chunk.memblock); + + return r; +} + +int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, uint32_t *idx) { + pa_scache_entry *e; + +#ifdef OS_IS_WIN32 + char buf[MAX_PATH]; + + if (ExpandEnvironmentStrings(filename, buf, MAX_PATH)) + filename = buf; +#endif + + assert(c && name); + + if (!(e = scache_add_item(c, name))) + return -1; + + e->lazy = 1; + e->filename = pa_xstrdup(filename); + + if (!c->scache_auto_unload_event) { + struct timeval ntv; + pa_gettimeofday(&ntv); + ntv.tv_sec += UNLOAD_POLL_TIME; + c->scache_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); + } + + if (idx) + *idx = e->index; + + return 0; +} + +int pa_scache_remove_item(pa_core *c, const char *name) { + pa_scache_entry *e; + assert(c && name); + + if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) + return -1; + + if (pa_idxset_remove_by_data(c->scache, e, NULL) != e) + assert(0); + + free_entry(e); + return 0; +} + +static void free_cb(void *p, PA_GCC_UNUSED void *userdata) { + pa_scache_entry *e = p; + assert(e); + free_entry(e); +} + +void pa_scache_free(pa_core *c) { + assert(c); + + if (c->scache) { + pa_idxset_free(c->scache, free_cb, NULL); + c->scache = NULL; + } + + if (c->scache_auto_unload_event) + c->mainloop->time_free(c->scache_auto_unload_event); +} + +int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t volume) { + pa_scache_entry *e; + char *t; + pa_cvolume r; + + assert(c); + assert(name); + assert(sink); + + if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1))) + return -1; + + if (e->lazy && !e->memchunk.memblock) { + if (pa_sound_file_load(e->filename, &e->sample_spec, &e->channel_map, &e->memchunk, c->memblock_stat) < 0) + return -1; + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); + + if (e->volume.channels > e->sample_spec.channels) + e->volume.channels = e->sample_spec.channels; + } + + if (!e->memchunk.memblock) + return -1; + + t = pa_sprintf_malloc("sample:%s", name); + + pa_cvolume_set(&r, e->volume.channels, volume); + pa_sw_cvolume_multiply(&r, &r, &e->volume); + + if (pa_play_memchunk(sink, t, &e->sample_spec, &e->channel_map, &e->memchunk, &r) < 0) { + pa_xfree(t); + return -1; + } + + pa_xfree(t); + + if (e->lazy) + time(&e->last_used_time); + + return 0; +} + +const char * pa_scache_get_name_by_id(pa_core *c, uint32_t id) { + pa_scache_entry *e; + assert(c && id != PA_IDXSET_INVALID); + + if (!c->scache || !(e = pa_idxset_get_by_index(c->scache, id))) + return NULL; + + return e->name; +} + +uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name) { + pa_scache_entry *e; + assert(c && name); + + if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) + return PA_IDXSET_INVALID; + + return e->index; +} + +uint32_t pa_scache_total_size(pa_core *c) { + pa_scache_entry *e; + uint32_t idx, sum = 0; + assert(c); + + if (!c->scache || !pa_idxset_size(c->scache)) + return 0; + + for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) + if (e->memchunk.memblock) + sum += e->memchunk.length; + + return sum; +} + +void pa_scache_unload_unused(pa_core *c) { + pa_scache_entry *e; + time_t now; + uint32_t idx; + assert(c); + + if (!c->scache || !pa_idxset_size(c->scache)) + return; + + time(&now); + + for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) { + + if (!e->lazy || !e->memchunk.memblock) + continue; + + if (e->last_used_time + c->scache_idle_time > now) + continue; + + pa_memblock_unref(e->memchunk.memblock); + e->memchunk.memblock = NULL; + e->memchunk.index = e->memchunk.length = 0; + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); + } +} + +static void add_file(pa_core *c, const char *pathname) { + struct stat st; + const char *e; + + e = pa_path_get_filename(pathname); + + if (stat(pathname, &st) < 0) { + pa_log(__FILE__": stat('%s'): %s", pathname, pa_cstrerror(errno)); + return; + } + +#if defined(S_ISREG) && defined(S_ISLNK) + if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) +#endif + pa_scache_add_file_lazy(c, e, pathname, NULL); +} + +int pa_scache_add_directory_lazy(pa_core *c, const char *pathname) { + DIR *dir; + assert(c && pathname); + + /* First try to open this as directory */ + if (!(dir = opendir(pathname))) { +#ifdef HAVE_GLOB_H + glob_t p; + unsigned int i; + /* If that fails, try to open it as shell glob */ + + if (glob(pathname, GLOB_ERR|GLOB_NOSORT, NULL, &p) < 0) { + pa_log(__FILE__": failed to open directory '%s': %s", pathname, pa_cstrerror(errno)); + return -1; + } + + for (i = 0; i < p.gl_pathc; i++) + add_file(c, p.gl_pathv[i]); + + globfree(&p); +#else + return -1; +#endif + } else { + struct dirent *e; + + while ((e = readdir(dir))) { + char p[PATH_MAX]; + + if (e->d_name[0] == '.') + continue; + + snprintf(p, sizeof(p), "%s/%s", pathname, e->d_name); + add_file(c, p); + } + } + + closedir(dir); + return 0; +} diff --git a/src/pulsecore/core-scache.h b/src/pulsecore/core-scache.h new file mode 100644 index 00000000..d01aae9b --- /dev/null +++ b/src/pulsecore/core-scache.h @@ -0,0 +1,64 @@ +#ifndef foocorescachehfoo +#define foocorescachehfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include + +#define PA_SCACHE_ENTRY_SIZE_MAX (1024*1024*2) + +typedef struct pa_scache_entry { + pa_core *core; + uint32_t index; + char *name; + + pa_cvolume volume; + pa_sample_spec sample_spec; + pa_channel_map channel_map; + pa_memchunk memchunk; + + char *filename; + + int lazy; + time_t last_used_time; +} pa_scache_entry; + +int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx); +int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint32_t *idx); +int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, uint32_t *idx); + +int pa_scache_add_directory_lazy(pa_core *c, const char *pathname); + +int pa_scache_remove_item(pa_core *c, const char *name); +int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t volume); +void pa_scache_free(pa_core *c); + +const char *pa_scache_get_name_by_id(pa_core *c, uint32_t id); +uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name); + +uint32_t pa_scache_total_size(pa_core *c); + +void pa_scache_unload_unused(pa_core *c); + +#endif diff --git a/src/pulsecore/core-subscribe.c b/src/pulsecore/core-subscribe.c new file mode 100644 index 00000000..e865256a --- /dev/null +++ b/src/pulsecore/core-subscribe.c @@ -0,0 +1,233 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include +#include + +#include "core-subscribe.h" + +/* The subscription subsystem may be used to be notified whenever an + * entity (sink, source, ...) is created or deleted. Modules may + * register a callback function that is called whenever an event + * matching a subscription mask happens. The execution of the callback + * function is postponed to the next main loop iteration, i.e. is not + * called from within the stack frame the entity was created in. */ + +struct pa_subscription { + pa_core *core; + int dead; + void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata); + void *userdata; + pa_subscription_mask_t mask; + + pa_subscription *prev, *next; +}; + +struct pa_subscription_event { + pa_subscription_event_type_t type; + uint32_t index; +}; + +static void sched_event(pa_core *c); + +/* Allocate a new subscription object for the given subscription mask. Use the specified callback function and user data */ +pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata) { + pa_subscription *s; + assert(c); + + s = pa_xmalloc(sizeof(pa_subscription)); + s->core = c; + s->dead = 0; + s->callback = callback; + s->userdata = userdata; + s->mask = m; + + if ((s->next = c->subscriptions)) + s->next->prev = s; + s->prev = NULL; + c->subscriptions = s; + return s; +} + +/* Free a subscription object, effectively marking it for deletion */ +void pa_subscription_free(pa_subscription*s) { + assert(s && !s->dead); + s->dead = 1; + sched_event(s->core); +} + +static void free_item(pa_subscription *s) { + assert(s && s->core); + + if (s->prev) + s->prev->next = s->next; + else + s->core->subscriptions = s->next; + + if (s->next) + s->next->prev = s->prev; + + pa_xfree(s); +} + +/* Free all subscription objects */ +void pa_subscription_free_all(pa_core *c) { + pa_subscription_event *e; + assert(c); + + while (c->subscriptions) + free_item(c->subscriptions); + + if (c->subscription_event_queue) { + while ((e = pa_queue_pop(c->subscription_event_queue))) + pa_xfree(e); + + pa_queue_free(c->subscription_event_queue, NULL, NULL); + c->subscription_event_queue = NULL; + } + + if (c->subscription_defer_event) { + c->mainloop->defer_free(c->subscription_defer_event); + c->subscription_defer_event = NULL; + } +} + +#if 0 +static void dump_event(pa_subscription_event*e) { + switch (e->type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { + case PA_SUBSCRIPTION_EVENT_SINK: + pa_log(__FILE__": SINK_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_SOURCE: + pa_log(__FILE__": SOURCE_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_SINK_INPUT: + pa_log(__FILE__": SINK_INPUT_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: + pa_log(__FILE__": SOURCE_OUTPUT_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_MODULE: + pa_log(__FILE__": MODULE_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_CLIENT: + pa_log(__FILE__": CLIENT_EVENT"); + break; + default: + pa_log(__FILE__": OTHER"); + break; + } + + switch (e->type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) { + case PA_SUBSCRIPTION_EVENT_NEW: + pa_log(__FILE__": NEW"); + break; + case PA_SUBSCRIPTION_EVENT_CHANGE: + pa_log(__FILE__": CHANGE"); + break; + case PA_SUBSCRIPTION_EVENT_REMOVE: + pa_log(__FILE__": REMOVE"); + break; + default: + pa_log(__FILE__": OTHER"); + break; + } + + pa_log(__FILE__": %u", e->index); +} +#endif + +/* Deferred callback for dispatching subscirption events */ +static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) { + pa_core *c = userdata; + pa_subscription *s; + assert(c && c->subscription_defer_event == de && c->mainloop == m); + + c->mainloop->defer_enable(c->subscription_defer_event, 0); + + /* Dispatch queued events */ + + if (c->subscription_event_queue) { + pa_subscription_event *e; + + while ((e = pa_queue_pop(c->subscription_event_queue))) { + + for (s = c->subscriptions; s; s = s->next) { + + if (!s->dead && pa_subscription_match_flags(s->mask, e->type)) + s->callback(c, e->type, e->index, s->userdata); + } + + pa_xfree(e); + } + } + + /* Remove dead subscriptions */ + + s = c->subscriptions; + while (s) { + pa_subscription *n = s->next; + if (s->dead) + free_item(s); + s = n; + } +} + +/* Schedule an mainloop event so that a pending subscription event is dispatched */ +static void sched_event(pa_core *c) { + assert(c); + + if (!c->subscription_defer_event) { + c->subscription_defer_event = c->mainloop->defer_new(c->mainloop, defer_cb, c); + assert(c->subscription_defer_event); + } + + c->mainloop->defer_enable(c->subscription_defer_event, 1); +} + +/* Append a new subscription event to the subscription event queue and schedule a main loop event */ +void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t index) { + pa_subscription_event *e; + assert(c); + + e = pa_xmalloc(sizeof(pa_subscription_event)); + e->type = t; + e->index = index; + + if (!c->subscription_event_queue) { + c->subscription_event_queue = pa_queue_new(); + assert(c->subscription_event_queue); + } + + pa_queue_push(c->subscription_event_queue, e); + sched_event(c); +} + + diff --git a/src/pulsecore/core-subscribe.h b/src/pulsecore/core-subscribe.h new file mode 100644 index 00000000..c2467033 --- /dev/null +++ b/src/pulsecore/core-subscribe.h @@ -0,0 +1,37 @@ +#ifndef foocoresubscribehfoo +#define foocoresubscribehfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef struct pa_subscription pa_subscription; +typedef struct pa_subscription_event pa_subscription_event; + +#include +#include + +pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata); +void pa_subscription_free(pa_subscription*s); +void pa_subscription_free_all(pa_core *c); + +void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t idx); + +#endif diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c new file mode 100644 index 00000000..8e3587eb --- /dev/null +++ b/src/pulsecore/core-util.c @@ -0,0 +1,1023 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SCHED_H +#include +#endif + +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif + +#ifdef HAVE_PTHREAD +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#ifdef HAVE_PWD_H +#include +#endif + +#ifdef HAVE_GRP_H +#include +#endif + +#include + +#include +#include + +#include +#include +#include + +#include "core-util.h" + +#ifndef OS_IS_WIN32 +#define PA_RUNTIME_PATH_PREFIX "/tmp/pulseaudio-" +#define PATH_SEP '/' +#else +#define PA_RUNTIME_PATH_PREFIX "%TEMP%\\pulseaudio-" +#define PATH_SEP '\\' +#endif + +#ifdef OS_IS_WIN32 + +#define POLYP_ROOTENV "POLYP_ROOT" + +int pa_set_root(HANDLE handle) { + char library_path[MAX_PATH + sizeof(POLYP_ROOTENV) + 1], *sep; + + strcpy(library_path, POLYP_ROOTENV "="); + + if (!GetModuleFileName(handle, library_path + sizeof(POLYP_ROOTENV), MAX_PATH)) + return 0; + + sep = strrchr(library_path, '\\'); + if (sep) + *sep = '\0'; + + if (_putenv(library_path) < 0) + return 0; + + return 1; +} + +#endif + +/** Make a file descriptor nonblock. Doesn't do any error checking */ +void pa_make_nonblock_fd(int fd) { +#ifdef O_NONBLOCK + int v; + assert(fd >= 0); + + if ((v = fcntl(fd, F_GETFL)) >= 0) + if (!(v & O_NONBLOCK)) + fcntl(fd, F_SETFL, v|O_NONBLOCK); +#elif defined(OS_IS_WIN32) + u_long arg = 1; + if (ioctlsocket(fd, FIONBIO, &arg) < 0) { + if (WSAGetLastError() == WSAENOTSOCK) + pa_log_warn(__FILE__": WARNING: Only sockets can be made non-blocking!"); + } +#else + pa_log_warn(__FILE__": WARNING: Non-blocking I/O not supported.!"); +#endif +} + +/** Creates a directory securely */ +int pa_make_secure_dir(const char* dir) { + struct stat st; + assert(dir); + +#ifdef OS_IS_WIN32 + if (mkdir(dir) < 0) +#else + if (mkdir(dir, 0700) < 0) +#endif + if (errno != EEXIST) + return -1; + +#ifdef HAVE_CHOWN + chown(dir, getuid(), getgid()); +#endif +#ifdef HAVE_CHMOD + chmod(dir, 0700); +#endif + +#ifdef HAVE_LSTAT + if (lstat(dir, &st) < 0) +#else + if (stat(dir, &st) < 0) +#endif + goto fail; + +#ifndef OS_IS_WIN32 + if (!S_ISDIR(st.st_mode) || (st.st_uid != getuid()) || ((st.st_mode & 0777) != 0700)) + goto fail; +#else + fprintf(stderr, "FIXME: pa_make_secure_dir()\n"); +#endif + + return 0; + +fail: + rmdir(dir); + return -1; +} + +/* Return a newly allocated sting containing the parent directory of the specified file */ +char *pa_parent_dir(const char *fn) { + char *slash, *dir = pa_xstrdup(fn); + + slash = (char*) pa_path_get_filename(dir); + if (slash == fn) + return NULL; + + *(slash-1) = 0; + return dir; +} + +/* Creates a the parent directory of the specified path securely */ +int pa_make_secure_parent_dir(const char *fn) { + int ret = -1; + char *dir; + + if (!(dir = pa_parent_dir(fn))) + goto finish; + + if (pa_make_secure_dir(dir) < 0) + goto finish; + + ret = 0; + +finish: + pa_xfree(dir); + return ret; +} + +/** Platform independent read function. Necessary since not all systems + * treat all file descriptors equal. */ +ssize_t pa_read(int fd, void *buf, size_t count) { + ssize_t r; + +#ifdef OS_IS_WIN32 + r = recv(fd, buf, count, 0); + if (r < 0) { + if (WSAGetLastError() != WSAENOTSOCK) { + errno = WSAGetLastError(); + return r; + } + } + + if (r < 0) +#endif + r = read(fd, buf, count); + + return r; +} + +/** Similar to pa_read(), but handles writes */ +ssize_t pa_write(int fd, const void *buf, size_t count) { + ssize_t r; + +#ifdef OS_IS_WIN32 + r = send(fd, buf, count, 0); + if (r < 0) { + if (WSAGetLastError() != WSAENOTSOCK) { + errno = WSAGetLastError(); + return r; + } + } + + if (r < 0) +#endif + r = write(fd, buf, count); + + return r; +} + +/** Calls read() in a loop. Makes sure that as much as 'size' bytes, + * unless EOF is reached or an error occured */ +ssize_t pa_loop_read(int fd, void*data, size_t size) { + ssize_t ret = 0; + assert(fd >= 0 && data && size); + + while (size > 0) { + ssize_t r; + + if ((r = pa_read(fd, data, size)) < 0) + return r; + + if (r == 0) + break; + + ret += r; + data = (uint8_t*) data + r; + size -= r; + } + + return ret; +} + +/** Similar to pa_loop_read(), but wraps write() */ +ssize_t pa_loop_write(int fd, const void*data, size_t size) { + ssize_t ret = 0; + assert(fd >= 0 && data && size); + + while (size > 0) { + ssize_t r; + + if ((r = pa_write(fd, data, size)) < 0) + return r; + + if (r == 0) + break; + + ret += r; + data = (const uint8_t*) data + r; + size -= r; + } + + return ret; +} + +/* Print a warning messages in case that the given signal is not + * blocked or trapped */ +void pa_check_signal_is_blocked(int sig) { +#ifdef HAVE_SIGACTION + struct sigaction sa; + sigset_t set; + + /* If POSIX threads are supported use thread-aware + * pthread_sigmask() function, to check if the signal is + * blocked. Otherwise fall back to sigprocmask() */ + +#ifdef HAVE_PTHREAD + if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) { +#endif + if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) { + pa_log(__FILE__": sigprocmask(): %s", pa_cstrerror(errno)); + return; + } +#ifdef HAVE_PTHREAD + } +#endif + + if (sigismember(&set, sig)) + return; + + /* Check whether the signal is trapped */ + + if (sigaction(sig, NULL, &sa) < 0) { + pa_log(__FILE__": sigaction(): %s", pa_cstrerror(errno)); + return; + } + + if (sa.sa_handler != SIG_DFL) + return; + + pa_log(__FILE__": WARNING: %s is not trapped. This might cause malfunction!", pa_strsignal(sig)); +#else /* HAVE_SIGACTION */ + pa_log(__FILE__": WARNING: %s might not be trapped. This might cause malfunction!", pa_strsignal(sig)); +#endif +} + +/* The following function is based on an example from the GNU libc + * documentation. This function is similar to GNU's asprintf(). */ +char *pa_sprintf_malloc(const char *format, ...) { + int size = 100; + char *c = NULL; + + assert(format); + + for(;;) { + int r; + va_list ap; + + c = pa_xrealloc(c, size); + + va_start(ap, format); + r = vsnprintf(c, size, format, ap); + va_end(ap); + + if (r > -1 && r < size) + return c; + + if (r > -1) /* glibc 2.1 */ + size = r+1; + else /* glibc 2.0 */ + size *= 2; + } +} + +/* Same as the previous function, but use a va_list instead of an + * ellipsis */ +char *pa_vsprintf_malloc(const char *format, va_list ap) { + int size = 100; + char *c = NULL; + + assert(format); + + for(;;) { + int r; + va_list aq; + + va_copy(aq, ap); + + c = pa_xrealloc(c, size); + r = vsnprintf(c, size, format, aq); + + va_end(aq); + + if (r > -1 && r < size) + return c; + + if (r > -1) /* glibc 2.1 */ + size = r+1; + else /* glibc 2.0 */ + size *= 2; + } +} + +/* Similar to OpenBSD's strlcpy() function */ +char *pa_strlcpy(char *b, const char *s, size_t l) { + assert(b && s && l > 0); + + strncpy(b, s, l); + b[l-1] = 0; + return b; +} + +#define NICE_LEVEL (-15) + +/* Raise the priority of the current process as much as possible and +sensible: set the nice level to -15 and enable realtime scheduling if +supported.*/ +void pa_raise_priority(void) { + +#ifdef HAVE_SYS_RESOURCE_H + if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) + pa_log_warn(__FILE__": setpriority(): %s", pa_cstrerror(errno)); + else + pa_log_info(__FILE__": Successfully gained nice level %i.", NICE_LEVEL); +#endif + +#ifdef _POSIX_PRIORITY_SCHEDULING + { + struct sched_param sp; + + if (sched_getparam(0, &sp) < 0) { + pa_log(__FILE__": sched_getparam(): %s", pa_cstrerror(errno)); + return; + } + + sp.sched_priority = 1; + if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) { + pa_log_warn(__FILE__": sched_setscheduler(): %s", pa_cstrerror(errno)); + return; + } + + pa_log_info(__FILE__": Successfully enabled SCHED_FIFO scheduling."); + } +#endif + +#ifdef OS_IS_WIN32 + if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) + pa_log_warn(__FILE__": SetPriorityClass() failed: 0x%08X", GetLastError()); + else + pa_log_info(__FILE__": Successfully gained high priority class."); +#endif +} + +/* Reset the priority to normal, inverting the changes made by pa_raise_priority() */ +void pa_reset_priority(void) { +#ifdef OS_IS_WIN32 + SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); +#endif + +#ifdef _POSIX_PRIORITY_SCHEDULING + { + struct sched_param sp; + sched_getparam(0, &sp); + sp.sched_priority = 0; + sched_setscheduler(0, SCHED_OTHER, &sp); + } +#endif + +#ifdef HAVE_SYS_RESOURCE_H + setpriority(PRIO_PROCESS, 0, 0); +#endif +} + +/* Set the FD_CLOEXEC flag for a fd */ +int pa_fd_set_cloexec(int fd, int b) { + +#ifdef FD_CLOEXEC + int v; + assert(fd >= 0); + + if ((v = fcntl(fd, F_GETFD, 0)) < 0) + return -1; + + v = (v & ~FD_CLOEXEC) | (b ? FD_CLOEXEC : 0); + + if (fcntl(fd, F_SETFD, v) < 0) + return -1; +#endif + + return 0; +} + +/* Try to parse a boolean string value.*/ +int pa_parse_boolean(const char *v) { + + if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on")) + return 1; + else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off")) + return 0; + + return -1; +} + +/* Split the specified string wherever one of the strings in delimiter + * occurs. Each time it is called returns a newly allocated string + * with pa_xmalloc(). The variable state points to, should be + * initiallized to NULL before the first call. */ +char *pa_split(const char *c, const char *delimiter, const char**state) { + const char *current = *state ? *state : c; + size_t l; + + if (!*current) + return NULL; + + l = strcspn(current, delimiter); + *state = current+l; + + if (**state) + (*state)++; + + return pa_xstrndup(current, l); +} + +/* What is interpreted as whitespace? */ +#define WHITESPACE " \t\n" + +/* Split a string into words. Otherwise similar to pa_split(). */ +char *pa_split_spaces(const char *c, const char **state) { + const char *current = *state ? *state : c; + size_t l; + + if (!*current || *c == 0) + return NULL; + + current += strspn(current, WHITESPACE); + l = strcspn(current, WHITESPACE); + + *state = current+l; + + return pa_xstrndup(current, l); +} + +/* Return the name of an UNIX signal. Similar to GNU's strsignal() */ +const char *pa_strsignal(int sig) { + switch(sig) { + case SIGINT: return "SIGINT"; + case SIGTERM: return "SIGTERM"; +#ifdef SIGUSR1 + case SIGUSR1: return "SIGUSR1"; +#endif +#ifdef SIGUSR2 + case SIGUSR2: return "SIGUSR2"; +#endif +#ifdef SIGXCPU + case SIGXCPU: return "SIGXCPU"; +#endif +#ifdef SIGPIPE + case SIGPIPE: return "SIGPIPE"; +#endif +#ifdef SIGCHLD + case SIGCHLD: return "SIGCHLD"; +#endif +#ifdef SIGHUP + case SIGHUP: return "SIGHUP"; +#endif + default: return "UNKNOWN SIGNAL"; + } +} + +#ifdef HAVE_GRP_H + +/* Check whether the specified GID and the group name match */ +static int is_group(gid_t gid, const char *name) { + struct group group, *result = NULL; + long n; + void *data; + int r = -1; + +#ifdef HAVE_GETGRGID_R +#ifdef _SC_GETGR_R_SIZE_MAX + n = sysconf(_SC_GETGR_R_SIZE_MAX); +#else + n = -1; +#endif + if (n < 0) n = 512; + data = pa_xmalloc(n); + + if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) { + pa_log(__FILE__": getgrgid_r(%u): %s", (unsigned)gid, pa_cstrerror(errno)); + goto finish; + } + + r = strcmp(name, result->gr_name) == 0; + +finish: + pa_xfree(data); +#else + /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not + * support getgrgid_r. */ + if ((result = getgrgid(gid)) == NULL) { + pa_log(__FILE__": getgrgid(%u): %s", gid, pa_cstrerror(errno)); + goto finish; + } + + r = strcmp(name, result->gr_name) == 0; + +finish: +#endif + + return r; +} + +/* Check the current user is member of the specified group */ +int pa_own_uid_in_group(const char *name, gid_t *gid) { + GETGROUPS_T *gids, tgid; + int n = sysconf(_SC_NGROUPS_MAX); + int r = -1, i; + + assert(n > 0); + + gids = pa_xmalloc(sizeof(GETGROUPS_T)*n); + + if ((n = getgroups(n, gids)) < 0) { + pa_log(__FILE__": getgroups(): %s", pa_cstrerror(errno)); + goto finish; + } + + for (i = 0; i < n; i++) { + if (is_group(gids[i], name) > 0) { + *gid = gids[i]; + r = 1; + goto finish; + } + } + + if (is_group(tgid = getgid(), name) > 0) { + *gid = tgid; + r = 1; + goto finish; + } + + r = 0; + +finish: + + pa_xfree(gids); + return r; +} + +int pa_uid_in_group(uid_t uid, const char *name) { + char *g_buf, *p_buf; + long g_n, p_n; + struct group grbuf, *gr; + char **i; + int r = -1; + + g_n = sysconf(_SC_GETGR_R_SIZE_MAX); + g_buf = pa_xmalloc(g_n); + + p_n = sysconf(_SC_GETPW_R_SIZE_MAX); + p_buf = pa_xmalloc(p_n); + + if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) + goto finish; + + r = 0; + for (i = gr->gr_mem; *i; i++) { + struct passwd pwbuf, *pw; + + if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw) + continue; + + if (pw->pw_uid == uid) { + r = 1; + break; + } + } + +finish: + pa_xfree(g_buf); + pa_xfree(p_buf); + + return r; +} + +#else /* HAVE_GRP_H */ + +int pa_own_uid_in_group(const char *name, gid_t *gid) { + return -1; + +} + +int pa_uid_in_group(uid_t uid, const char *name) { + return -1; +} + +#endif + +/* Lock or unlock a file entirely. + (advisory on UNIX, mandatory on Windows) */ +int pa_lock_fd(int fd, int b) { +#ifdef F_SETLKW + struct flock flock; + + /* Try a R/W lock first */ + + flock.l_type = b ? F_WRLCK : F_UNLCK; + flock.l_whence = SEEK_SET; + flock.l_start = 0; + flock.l_len = 0; + + if (fcntl(fd, F_SETLKW, &flock) >= 0) + return 0; + + /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */ + if (b && errno == EBADF) { + flock.l_type = F_RDLCK; + if (fcntl(fd, F_SETLKW, &flock) >= 0) + return 0; + } + + pa_log(__FILE__": %slock: %s", !b? "un" : "", + pa_cstrerror(errno)); +#endif + +#ifdef OS_IS_WIN32 + HANDLE h = (HANDLE)_get_osfhandle(fd); + + if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) + return 0; + if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) + return 0; + + pa_log(__FILE__": %slock failed: 0x%08X", !b ? "un" : "", GetLastError()); +#endif + + return -1; +} + +/* Remove trailing newlines from a string */ +char* pa_strip_nl(char *s) { + assert(s); + + s[strcspn(s, "\r\n")] = 0; + return s; +} + +/* Create a temporary lock file and lock it. */ +int pa_lock_lockfile(const char *fn) { + int fd = -1; + assert(fn); + + for (;;) { + struct stat st; + + if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { + pa_log(__FILE__": failed to create lock file '%s': %s", fn, + pa_cstrerror(errno)); + goto fail; + } + + if (pa_lock_fd(fd, 1) < 0) { + pa_log(__FILE__": failed to lock file '%s'.", fn); + goto fail; + } + + if (fstat(fd, &st) < 0) { + pa_log(__FILE__": failed to fstat() file '%s'.", fn); + goto fail; + } + + /* Check wheter the file has been removed meanwhile. When yes, restart this loop, otherwise, we're done */ + if (st.st_nlink >= 1) + break; + + if (pa_lock_fd(fd, 0) < 0) { + pa_log(__FILE__": failed to unlock file '%s'.", fn); + goto fail; + } + + if (close(fd) < 0) { + pa_log(__FILE__": failed to close file '%s'.", fn); + goto fail; + } + + fd = -1; + } + + return fd; + +fail: + + if (fd >= 0) + close(fd); + + return -1; +} + +/* Unlock a temporary lcok file */ +int pa_unlock_lockfile(const char *fn, int fd) { + int r = 0; + assert(fn && fd >= 0); + + if (unlink(fn) < 0) { + pa_log_warn(__FILE__": WARNING: unable to remove lock file '%s': %s", + fn, pa_cstrerror(errno)); + r = -1; + } + + if (pa_lock_fd(fd, 0) < 0) { + pa_log_warn(__FILE__": WARNING: failed to unlock file '%s'.", fn); + r = -1; + } + + if (close(fd) < 0) { + pa_log_warn(__FILE__": WARNING: failed to close lock file '%s': %s", + fn, pa_cstrerror(errno)); + r = -1; + } + + return r; +} + +/* Try to open a configuration file. If "env" is specified, open the + * value of the specified environment variable. Otherwise look for a + * file "local" in the home directory or a file "global" in global + * file system. If "result" is non-NULL, a pointer to a newly + * allocated buffer containing the used configuration file is + * stored there.*/ +FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode) { + const char *fn; + char h[PATH_MAX]; + +#ifdef OS_IS_WIN32 + char buf[PATH_MAX]; + + if (!getenv(POLYP_ROOTENV)) + pa_set_root(NULL); +#endif + + if (env && (fn = getenv(env))) { +#ifdef OS_IS_WIN32 + if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX)) + return NULL; + fn = buf; +#endif + + if (result) + *result = pa_xstrdup(fn); + + return fopen(fn, mode); + } + + if (local && pa_get_home_dir(h, sizeof(h))) { + FILE *f; + char *lfn; + + fn = lfn = pa_sprintf_malloc("%s/%s", h, local); + +#ifdef OS_IS_WIN32 + if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) + return NULL; + fn = buf; +#endif + + f = fopen(fn, mode); + + if (f || errno != ENOENT) { + if (result) + *result = pa_xstrdup(fn); + pa_xfree(lfn); + return f; + } + + pa_xfree(lfn); + } + + if (!global) { + if (result) + *result = NULL; + errno = ENOENT; + return NULL; + } + +#ifdef OS_IS_WIN32 + if (!ExpandEnvironmentStrings(global, buf, PATH_MAX)) + return NULL; + global = buf; +#endif + + if (result) + *result = pa_xstrdup(global); + + return fopen(global, mode); +} + +/* Format the specified data as a hexademical string */ +char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) { + size_t i = 0, j = 0; + const char hex[] = "0123456789abcdef"; + assert(d && s && slength > 0); + + while (i < dlength && j+3 <= slength) { + s[j++] = hex[*d >> 4]; + s[j++] = hex[*d & 0xF]; + + d++; + i++; + } + + s[j < slength ? j : slength] = 0; + return s; +} + +/* Convert a hexadecimal digit to a number or -1 if invalid */ +static int hexc(char c) { + if (c >= '0' && c <= '9') + return c - '0'; + + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + + return -1; +} + +/* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */ +size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) { + size_t j = 0; + assert(p && d); + + while (j < dlength && *p) { + int b; + + if ((b = hexc(*(p++))) < 0) + return (size_t) -1; + + d[j] = (uint8_t) (b << 4); + + if (!*p) + return (size_t) -1; + + if ((b = hexc(*(p++))) < 0) + return (size_t) -1; + + d[j] |= (uint8_t) b; + j++; + } + + return j; +} + +/* Returns nonzero when *s starts with *pfx */ +int pa_startswith(const char *s, const char *pfx) { + size_t l; + + assert(s); + assert(pfx); + + l = strlen(pfx); + + return strlen(s) >= l && strncmp(s, pfx, l) == 0; +} + +/* Returns nonzero when *s ends with *sfx */ +int pa_endswith(const char *s, const char *sfx) { + size_t l1, l2; + + assert(s); + assert(sfx); + + l1 = strlen(s); + l2 = strlen(sfx); + + return l1 >= l2 && strcmp(s+l1-l2, sfx) == 0; +} + +/* if fn is null return the pulseaudio run time path in s (/tmp/pulseaudio) + * if fn is non-null and starts with / return fn in s + * otherwise append fn to the run time path and return it in s */ +char *pa_runtime_path(const char *fn, char *s, size_t l) { + char u[256]; + +#ifndef OS_IS_WIN32 + if (fn && *fn == '/') +#else + if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\') +#endif + return pa_strlcpy(s, fn, l); + + if (fn) + snprintf(s, l, "%s%s%c%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn); + else + snprintf(s, l, "%s%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u))); + +#ifdef OS_IS_WIN32 + { + char buf[l]; + strcpy(buf, s); + ExpandEnvironmentStrings(buf, s, l); + } +#endif + + return s; +} + +/* Convert the string s to a signed integer in *ret_i */ +int pa_atoi(const char *s, int32_t *ret_i) { + char *x = NULL; + long l; + assert(s && ret_i); + + l = strtol(s, &x, 0); + + if (!x || *x) + return -1; + + *ret_i = (int32_t) l; + + return 0; +} + +/* Convert the string s to an unsigned integer in *ret_u */ +int pa_atou(const char *s, uint32_t *ret_u) { + char *x = NULL; + unsigned long l; + assert(s && ret_u); + + l = strtoul(s, &x, 0); + + if (!x || *x) + return -1; + + *ret_u = (uint32_t) l; + + return 0; +} diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h new file mode 100644 index 00000000..0012afc6 --- /dev/null +++ b/src/pulsecore/core-util.h @@ -0,0 +1,88 @@ +#ifndef foocoreutilhfoo +#define foocoreutilhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +#include + +struct timeval; + +void pa_make_nonblock_fd(int fd); + +int pa_make_secure_dir(const char* dir); +int pa_make_secure_parent_dir(const char *fn); + +ssize_t pa_read(int fd, void *buf, size_t count); +ssize_t pa_write(int fd, const void *buf, size_t count); +ssize_t pa_loop_read(int fd, void*data, size_t size); +ssize_t pa_loop_write(int fd, const void*data, size_t size); + +void pa_check_signal_is_blocked(int sig); + +char *pa_sprintf_malloc(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +char *pa_vsprintf_malloc(const char *format, va_list ap); + +char *pa_strlcpy(char *b, const char *s, size_t l); + +char *pa_parent_dir(const char *fn); + +void pa_raise_priority(void); +void pa_reset_priority(void); + +int pa_fd_set_cloexec(int fd, int b); + +int pa_parse_boolean(const char *s); + +char *pa_split(const char *c, const char*delimiters, const char **state); +char *pa_split_spaces(const char *c, const char **state); + +char *pa_strip_nl(char *s); + +const char *pa_strsignal(int sig); + +int pa_own_uid_in_group(const char *name, gid_t *gid); +int pa_uid_in_group(uid_t uid, const char *name); + +int pa_lock_fd(int fd, int b); + +int pa_lock_lockfile(const char *fn); +int pa_unlock_lockfile(const char *fn, int fd); + +FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode); + +char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength); +size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength); + +int pa_startswith(const char *s, const char *pfx); +int pa_endswith(const char *s, const char *sfx); + +char *pa_runtime_path(const char *fn, char *s, size_t l); + +int pa_atoi(const char *s, int32_t *ret_i); +int pa_atou(const char *s, uint32_t *ret_u); + +#endif diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c new file mode 100644 index 00000000..7c780ea8 --- /dev/null +++ b/src/pulsecore/core.c @@ -0,0 +1,160 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core.h" + +pa_core* pa_core_new(pa_mainloop_api *m) { + pa_core* c; + c = pa_xmalloc(sizeof(pa_core)); + + c->mainloop = m; + c->clients = pa_idxset_new(NULL, NULL); + c->sinks = pa_idxset_new(NULL, NULL); + c->sources = pa_idxset_new(NULL, NULL); + c->source_outputs = pa_idxset_new(NULL, NULL); + c->sink_inputs = pa_idxset_new(NULL, NULL); + + c->default_source_name = c->default_sink_name = NULL; + + c->modules = NULL; + c->namereg = NULL; + c->scache = NULL; + c->autoload_idxset = NULL; + c->autoload_hashmap = NULL; + c->running_as_daemon = 0; + + c->default_sample_spec.format = PA_SAMPLE_S16NE; + c->default_sample_spec.rate = 44100; + c->default_sample_spec.channels = 2; + + c->module_auto_unload_event = NULL; + c->module_defer_unload_event = NULL; + c->scache_auto_unload_event = NULL; + + c->subscription_defer_event = NULL; + c->subscription_event_queue = NULL; + c->subscriptions = NULL; + + c->memblock_stat = pa_memblock_stat_new(); + + c->disallow_module_loading = 0; + + c->quit_event = NULL; + + c->exit_idle_time = -1; + c->module_idle_time = 20; + c->scache_idle_time = 20; + + c->resample_method = PA_RESAMPLER_SRC_SINC_FASTEST; + + pa_property_init(c); + + pa_random(&c->cookie, sizeof(c->cookie)); + +#ifdef SIGPIPE + pa_check_signal_is_blocked(SIGPIPE); +#endif + return c; +} + +void pa_core_free(pa_core *c) { + assert(c); + + pa_module_unload_all(c); + assert(!c->modules); + + assert(pa_idxset_isempty(c->clients)); + pa_idxset_free(c->clients, NULL, NULL); + + assert(pa_idxset_isempty(c->sinks)); + pa_idxset_free(c->sinks, NULL, NULL); + + assert(pa_idxset_isempty(c->sources)); + pa_idxset_free(c->sources, NULL, NULL); + + assert(pa_idxset_isempty(c->source_outputs)); + pa_idxset_free(c->source_outputs, NULL, NULL); + + assert(pa_idxset_isempty(c->sink_inputs)); + pa_idxset_free(c->sink_inputs, NULL, NULL); + + pa_scache_free(c); + pa_namereg_free(c); + pa_autoload_free(c); + pa_subscription_free_all(c); + + if (c->quit_event) + c->mainloop->time_free(c->quit_event); + + pa_xfree(c->default_source_name); + pa_xfree(c->default_sink_name); + + pa_memblock_stat_unref(c->memblock_stat); + + pa_property_cleanup(c); + + pa_xfree(c); +} + +static void quit_callback(pa_mainloop_api*m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + pa_core *c = userdata; + assert(c->quit_event = e); + + m->quit(m, 0); +} + +void pa_core_check_quit(pa_core *c) { + assert(c); + + if (!c->quit_event && c->exit_idle_time >= 0 && pa_idxset_size(c->clients) == 0) { + struct timeval tv; + pa_gettimeofday(&tv); + tv.tv_sec+= c->exit_idle_time; + c->quit_event = c->mainloop->time_new(c->mainloop, &tv, quit_callback, c); + } else if (c->quit_event && pa_idxset_size(c->clients) > 0) { + c->mainloop->time_free(c->quit_event); + c->quit_event = NULL; + } +} + diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h new file mode 100644 index 00000000..627d4239 --- /dev/null +++ b/src/pulsecore/core.h @@ -0,0 +1,82 @@ +#ifndef foocorehfoo +#define foocorehfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef struct pa_core pa_core; + +#include +#include +#include +#include +#include +#include +#include +#include + +/* The core structure of pulseaudio. Every pulseaudio daemon contains + * exactly one of these. It is used for storing kind of global + * variables for the daemon. */ + +struct pa_core { + /* A random value which may be used to identify this instance of + * pulseaudio. Not cryptographically secure in any way. */ + uint32_t cookie; + + pa_mainloop_api *mainloop; + + /* idxset of all kinds of entities */ + pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache, *autoload_idxset; + + /* Some hashmaps for all sorts of entities */ + pa_hashmap *namereg, *autoload_hashmap, *properties; + + /* The name of the default sink/source */ + char *default_source_name, *default_sink_name; + + pa_sample_spec default_sample_spec; + pa_time_event *module_auto_unload_event; + pa_defer_event *module_defer_unload_event; + + pa_defer_event *subscription_defer_event; + pa_queue *subscription_event_queue; + pa_subscription *subscriptions; + + pa_memblock_stat *memblock_stat; + + int disallow_module_loading, running_as_daemon; + int exit_idle_time, module_idle_time, scache_idle_time; + + pa_time_event *quit_event; + + pa_time_event *scache_auto_unload_event; + + pa_resample_method_t resample_method; +}; + +pa_core* pa_core_new(pa_mainloop_api *m); +void pa_core_free(pa_core*c); + +/* Check whether noone is connected to this core */ +void pa_core_check_quit(pa_core *c); + +#endif diff --git a/src/pulsecore/dllmain.c b/src/pulsecore/dllmain.c new file mode 100644 index 00000000..b86bf04f --- /dev/null +++ b/src/pulsecore/dllmain.c @@ -0,0 +1,55 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef OS_IS_WIN32 + +#include +#include +#include + +#include + +extern pa_set_root(HANDLE handle); + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { + WSADATA data; + + switch (fdwReason) { + + case DLL_PROCESS_ATTACH: + if (!pa_set_root(hinstDLL)) + return FALSE; + WSAStartup(MAKEWORD(2, 0), &data); + break; + + case DLL_PROCESS_DETACH: + WSACleanup(); + break; + + } + return TRUE; +} + +#endif /* OS_IS_WIN32 */ diff --git a/src/pulsecore/dynarray.c b/src/pulsecore/dynarray.c new file mode 100644 index 00000000..d1ab1161 --- /dev/null +++ b/src/pulsecore/dynarray.c @@ -0,0 +1,103 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include "dynarray.h" + +/* If the array becomes to small, increase its size by 100 entries */ +#define INCREASE_BY 100 + +struct pa_dynarray { + void **data; + unsigned n_allocated, n_entries; +}; + +pa_dynarray* pa_dynarray_new(void) { + pa_dynarray *a; + a = pa_xnew(pa_dynarray, 1); + a->data = NULL; + a->n_entries = 0; + a->n_allocated = 0; + return a; +} + +void pa_dynarray_free(pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata) { + unsigned i; + assert(a); + + if (func) + for (i = 0; i < a->n_entries; i++) + if (a->data[i]) + func(a->data[i], userdata); + + pa_xfree(a->data); + pa_xfree(a); +} + +void pa_dynarray_put(pa_dynarray*a, unsigned i, void *p) { + assert(a); + + if (i >= a->n_allocated) { + unsigned n; + + if (!p) + return; + + n = i+INCREASE_BY; + a->data = pa_xrealloc(a->data, sizeof(void*)*n); + memset(a->data+a->n_allocated, 0, sizeof(void*)*(n-a->n_allocated)); + a->n_allocated = n; + } + + a->data[i] = p; + + if (i >= a->n_entries) + a->n_entries = i+1; +} + +unsigned pa_dynarray_append(pa_dynarray*a, void *p) { + unsigned i = a->n_entries; + pa_dynarray_put(a, i, p); + return i; +} + +void *pa_dynarray_get(pa_dynarray*a, unsigned i) { + assert(a); + if (i >= a->n_allocated) + return NULL; + + assert(a->data); + return a->data[i]; +} + +unsigned pa_dynarray_size(pa_dynarray*a) { + assert(a); + return a->n_entries; +} diff --git a/src/pulsecore/dynarray.h b/src/pulsecore/dynarray.h new file mode 100644 index 00000000..4ddb526c --- /dev/null +++ b/src/pulsecore/dynarray.h @@ -0,0 +1,49 @@ +#ifndef foodynarrayhfoo +#define foodynarrayhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef struct pa_dynarray pa_dynarray; + +/* Implementation of a simple dynamically sized array. The array + * expands if required, but doesn't shrink if possible. Memory + * management of the array's entries is the user's job. */ + +pa_dynarray* pa_dynarray_new(void); + +/* Free the array calling the specified function for every entry in + * the array. The function may be NULL. */ +void pa_dynarray_free(pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata); + +/* Store p at position i in the array */ +void pa_dynarray_put(pa_dynarray*a, unsigned i, void *p); + +/* Store p a the first free position in the array. Returns the index + * of that entry. If entries are removed from the array their position + * are not filled any more by this function. */ +unsigned pa_dynarray_append(pa_dynarray*a, void *p); + +void *pa_dynarray_get(pa_dynarray*a, unsigned i); + +unsigned pa_dynarray_size(pa_dynarray*a); + +#endif diff --git a/src/pulsecore/endianmacros.h b/src/pulsecore/endianmacros.h new file mode 100644 index 00000000..65db3feb --- /dev/null +++ b/src/pulsecore/endianmacros.h @@ -0,0 +1,77 @@ +#ifndef fooendianmacroshfoo +#define fooendianmacroshfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define INT16_SWAP(x) ( (int16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) ) +#define UINT16_SWAP(x) ( (uint16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) ) +#define INT32_SWAP(x) ( (int32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) ) +#define UINT32_SWAP(x) ( (uint32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) ) + +#define MAYBE_INT32_SWAP(c,x) ((c) ? INT32_SWAP(x) : x) +#define MAYBE_UINT32_SWAP(c,x) ((c) ? UINT32_SWAP(x) : x) + +#ifdef WORDS_BIGENDIAN + #define INT16_FROM_LE(x) INT16_SWAP(x) + #define INT16_FROM_BE(x) ((int16_t)(x)) + + #define INT16_TO_LE(x) INT16_SWAP(x) + #define INT16_TO_BE(x) ((int16_t)(x)) + + #define UINT16_FROM_LE(x) UINT16_SWAP(x) + #define UINT16_FROM_BE(x) ((uint16_t)(x)) + + #define INT32_FROM_LE(x) INT32_SWAP(x) + #define INT32_FROM_BE(x) ((int32_t)(x)) + + #define UINT32_FROM_LE(x) UINT32_SWAP(x) + #define UINT32_FROM_BE(x) ((uint32_t)(x)) + + #define UINT32_TO_LE(x) UINT32_SWAP(x) + #define UINT32_TO_BE(x) ((uint32_t)(x)) +#else + #define INT16_FROM_LE(x) ((int16_t)(x)) + #define INT16_FROM_BE(x) INT16_SWAP(x) + + #define INT16_TO_LE(x) ((int16_t)(x)) + #define INT16_TO_BE(x) INT16_SWAP(x) + + #define UINT16_FROM_LE(x) ((uint16_t)(x)) + #define UINT16_FROM_BE(x) UINT16_SWAP(x) + + #define INT32_FROM_LE(x) ((int32_t)(x)) + #define INT32_FROM_BE(x) INT32_SWAP(x) + + #define UINT32_FROM_LE(x) ((uint32_t)(x)) + #define UINT32_FROM_BE(x) UINT32_SWAP(x) + + #define UINT32_TO_LE(x) ((uint32_t)(x)) + #define UINT32_TO_BE(x) UINT32_SWAP(x) +#endif + +#endif diff --git a/src/pulsecore/esound.h b/src/pulsecore/esound.h new file mode 100644 index 00000000..9d44f65c --- /dev/null +++ b/src/pulsecore/esound.h @@ -0,0 +1,209 @@ +#ifndef fooesoundhfoo +#define fooesoundhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* Most of the following is blatantly stolen from esound. */ + + +/* path and name of the default EsounD domain socket */ +#define ESD_UNIX_SOCKET_DIR "/tmp/.esd" +#define ESD_UNIX_SOCKET_NAME "/tmp/.esd/socket" + +/* length of the audio buffer size */ +#define ESD_BUF_SIZE (4 * 1024) +/* maximum size we can write(). Otherwise we might overflow */ +#define ESD_MAX_WRITE_SIZE (21 * 4096) + +/* length of the authorization key, octets */ +#define ESD_KEY_LEN (16) + +/* default port for the EsounD server */ +#define ESD_DEFAULT_PORT (16001) + +/* default sample rate for the EsounD server */ +#define ESD_DEFAULT_RATE (44100) + +/* maximum length of a stream/sample name */ +#define ESD_NAME_MAX (128) + +/* a magic number to identify the relative endianness of a client */ +#define ESD_ENDIAN_KEY ((uint32_t) (('E' << 24) + ('N' << 16) + ('D' << 8) + ('N'))) + +#define ESD_VOLUME_BASE (256) + + +/*************************************/ +/* what can we do to/with the EsounD */ +enum esd_proto { + ESD_PROTO_CONNECT, /* implied on inital client connection */ + + /* pseudo "security" functionality */ + ESD_PROTO_LOCK, /* disable "foreign" client connections */ + ESD_PROTO_UNLOCK, /* enable "foreign" client connections */ + + /* stream functionality: play, record, monitor */ + ESD_PROTO_STREAM_PLAY, /* play all following data as a stream */ + ESD_PROTO_STREAM_REC, /* record data from card as a stream */ + ESD_PROTO_STREAM_MON, /* send mixed buffer output as a stream */ + + /* sample functionality: cache, free, play, loop, EOL, kill */ + ESD_PROTO_SAMPLE_CACHE, /* cache a sample in the server */ + ESD_PROTO_SAMPLE_FREE, /* release a sample in the server */ + ESD_PROTO_SAMPLE_PLAY, /* play a cached sample */ + ESD_PROTO_SAMPLE_LOOP, /* loop a cached sample, til eoloop */ + ESD_PROTO_SAMPLE_STOP, /* stop a looping sample when done */ + ESD_PROTO_SAMPLE_KILL, /* stop the looping sample immed. */ + + /* free and reclaim /dev/dsp functionality */ + ESD_PROTO_STANDBY, /* release /dev/dsp and ignore all data */ + ESD_PROTO_RESUME, /* reclaim /dev/dsp and play sounds again */ + + /* TODO: move these to a more logical place. NOTE: will break the protocol */ + ESD_PROTO_SAMPLE_GETID, /* get the ID for an already-cached sample */ + ESD_PROTO_STREAM_FILT, /* filter mixed buffer output as a stream */ + + /* esd remote management */ + ESD_PROTO_SERVER_INFO, /* get server info (ver, sample rate, format) */ + ESD_PROTO_ALL_INFO, /* get all info (server info, players, samples) */ + ESD_PROTO_SUBSCRIBE, /* track new and removed players and samples */ + ESD_PROTO_UNSUBSCRIBE, /* stop tracking updates */ + + /* esd remote control */ + ESD_PROTO_STREAM_PAN, /* set stream panning */ + ESD_PROTO_SAMPLE_PAN, /* set default sample panning */ + + /* esd status */ + ESD_PROTO_STANDBY_MODE, /* see if server is in standby, autostandby, etc */ + + /* esd latency */ + ESD_PROTO_LATENCY, /* retrieve latency between write()'s and output */ + + ESD_PROTO_MAX /* for bounds checking */ +}; + +/******************/ +/* The EsounD api */ + +/* the properties of a sound buffer are logically or'd */ + +/* bits of stream/sample data */ +#define ESD_MASK_BITS ( 0x000F ) +#define ESD_BITS8 ( 0x0000 ) +#define ESD_BITS16 ( 0x0001 ) + +/* how many interleaved channels of data */ +#define ESD_MASK_CHAN ( 0x00F0 ) +#define ESD_MONO ( 0x0010 ) +#define ESD_STEREO ( 0x0020 ) + +/* whether it's a stream or a sample */ +#define ESD_MASK_MODE ( 0x0F00 ) +#define ESD_STREAM ( 0x0000 ) +#define ESD_SAMPLE ( 0x0100 ) +#define ESD_ADPCM ( 0x0200 ) /* TODO: anyone up for this? =P */ + +/* the function of the stream/sample, and common functions */ +#define ESD_MASK_FUNC ( 0xF000 ) +#define ESD_PLAY ( 0x1000 ) +/* functions for streams only */ +#define ESD_MONITOR ( 0x0000 ) +#define ESD_RECORD ( 0x2000 ) +/* functions for samples only */ +#define ESD_STOP ( 0x0000 ) +#define ESD_LOOP ( 0x2000 ) + +typedef int esd_format_t; +typedef int esd_proto_t; + +/*******************************************************************/ +/* esdmgr.c - functions to implement a "sound manager" for esd */ + +/* structures to retrieve information about streams/samples from the server */ +typedef struct esd_server_info { + + int version; /* server version encoded as an int */ + esd_format_t format; /* magic int with the format info */ + int rate; /* sample rate */ + +} esd_server_info_t; + +typedef struct esd_player_info { + + struct esd_player_info *next; /* point to next entry in list */ + esd_server_info_t *server; /* the server that contains this stream */ + + int source_id; /* either a stream fd or sample id */ + char name[ ESD_NAME_MAX ]; /* name of stream for remote control */ + int rate; /* sample rate */ + int left_vol_scale; /* volume scaling */ + int right_vol_scale; + + esd_format_t format; /* magic int with the format info */ + +} esd_player_info_t; + +typedef struct esd_sample_info { + + struct esd_sample_info *next; /* point to next entry in list */ + esd_server_info_t *server; /* the server that contains this sample */ + + int sample_id; /* either a stream fd or sample id */ + char name[ ESD_NAME_MAX ]; /* name of stream for remote control */ + int rate; /* sample rate */ + int left_vol_scale; /* volume scaling */ + int right_vol_scale; + + esd_format_t format; /* magic int with the format info */ + int length; /* total buffer length */ + +} esd_sample_info_t; + +typedef struct esd_info { + + esd_server_info_t *server; + esd_player_info_t *player_list; + esd_sample_info_t *sample_list; + +} esd_info_t; + +enum esd_standby_mode { + ESM_ERROR, ESM_ON_STANDBY, ESM_ON_AUTOSTANDBY, ESM_RUNNING +}; +typedef int esd_standby_mode_t; + +enum esd_client_state { + ESD_STREAMING_DATA, /* data from here on is streamed data */ + ESD_CACHING_SAMPLE, /* midway through caching a sample */ + ESD_NEEDS_REQDATA, /* more data needed to complere request */ + ESD_NEXT_REQUEST, /* proceed to next request */ + ESD_CLIENT_STATE_MAX /* place holder */ +}; +typedef int esd_client_state_t; + +/* the endian key is transferred in binary, if it's read into int, */ +/* and matches ESD_ENDIAN_KEY (ENDN), then the endianness of the */ +/* server and the client match; if it's SWAP_ENDIAN_KEY, swap data */ +#define ESD_SWAP_ENDIAN_KEY (UINT32_SWAP(ESD_ENDIAN_KEY)) + + +#endif diff --git a/src/pulsecore/g711.c b/src/pulsecore/g711.c new file mode 100644 index 00000000..55a82396 --- /dev/null +++ b/src/pulsecore/g711.c @@ -0,0 +1,2531 @@ +/* + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * g711.c + * + * u-law, A-law and linear PCM conversions. + */ + +/* + * December 30, 1994: + * Functions linear2alaw, linear2ulaw have been updated to correctly + * convert unquantized 16 bit values. + * Tables for direct u- to A-law and A- to u-law conversions have been + * corrected. + * Borge Lindberg, Center for PersonKommunikation, Aalborg University. + * bli@cpk.auc.dk + * + */ + +#include "g711.h" + +#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ +#define QUANT_MASK (0xf) /* Quantization field mask. */ +#define NSEGS (8) /* Number of A-law segments. */ +#define SEG_SHIFT (4) /* Left shift for segment number. */ +#define SEG_MASK (0x70) /* Segment field mask. */ + +#if !defined(FAST_ALAW_CONVERSION) || !defined(FAST_ULAW_CONVERSION) +static int16_t seg_aend[8] = {0x1F, 0x3F, 0x7F, 0xFF, + 0x1FF, 0x3FF, 0x7FF, 0xFFF}; +static int16_t seg_uend[8] = {0x3F, 0x7F, 0xFF, 0x1FF, + 0x3FF, 0x7FF, 0xFFF, 0x1FFF}; + +static int16_t search( + int16_t val, + int16_t *table, + int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (val <= *table++) + return (i); + } + return (size); +} +#endif /* !FAST_*_CONVERSION */ + +#ifndef FAST_ALAW_CONVERSION +/* + * linear2alaw() accepts an 13-bit signed integer and encodes it as A-law data + * stored in a unsigned char. This function should only be called with + * the data shifted such that it only contains information in the lower + * 13-bits. + * + * Linear Input Code Compressed Code + * ------------------------ --------------- + * 0000000wxyza 000wxyz + * 0000001wxyza 001wxyz + * 000001wxyzab 010wxyz + * 00001wxyzabc 011wxyz + * 0001wxyzabcd 100wxyz + * 001wxyzabcde 101wxyz + * 01wxyzabcdef 110wxyz + * 1wxyzabcdefg 111wxyz + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ +unsigned char st_13linear2alaw( + int16_t pcm_val) /* 2's complement (13-bit range) */ +{ + int16_t mask; + short seg; + unsigned char aval; + + /* Have calling software do it since its already doing a shift + * from 32-bits down to 16-bits. + */ + /* pcm_val = pcm_val >> 3; */ + + /* A-law using even bit inversion */ + if (pcm_val >= 0) { + mask = 0xD5; /* sign (7th) bit = 1 */ + } else { + mask = 0x55; /* sign bit = 0 */ + pcm_val = -pcm_val - 1; + } + + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_aend, 8); + + /* Combine the sign, segment, and quantization bits. */ + + if (seg >= 8) /* out of range, return maximum value. */ + return (unsigned char) (0x7F ^ mask); + else { + aval = (unsigned char) seg << SEG_SHIFT; + if (seg < 2) + aval |= (pcm_val >> 1) & QUANT_MASK; + else + aval |= (pcm_val >> seg) & QUANT_MASK; + return (aval ^ mask); + } +} + +/* + * alaw2linear() - Convert an A-law value to 16-bit signed linear PCM + * + */ +int16_t st_alaw2linear16( + unsigned char a_val) +{ + int16_t t; + int16_t seg; + + a_val ^= 0x55; + + t = (a_val & QUANT_MASK) << 4; + seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT; + switch (seg) { + case 0: + t += 8; + break; + case 1: + t += 0x108; + break; + default: + t += 0x108; + t <<= seg - 1; + } + return ((a_val & SIGN_BIT) ? t : -t); +} +#endif /* !FAST_ALAW_CONVERSION */ + +#define BIAS (0x84) /* Bias for linear code. */ +#define CLIP 8159 + +#ifndef FAST_ULAW_CONVERSION +/* + * linear2ulaw() accepts a 14-bit signed integer and encodes it as u-law data + * stored in a unsigned char. This function should only be called with + * the data shifted such that it only contains information in the lower + * 14-bits. + * + * In order to simplify the encoding process, the original linear magnitude + * is biased by adding 33 which shifts the encoding range from (0 - 8158) to + * (33 - 8191). The result can be seen in the following encoding table: + * + * Biased Linear Input Code Compressed Code + * ------------------------ --------------- + * 00000001wxyza 000wxyz + * 0000001wxyzab 001wxyz + * 000001wxyzabc 010wxyz + * 00001wxyzabcd 011wxyz + * 0001wxyzabcde 100wxyz + * 001wxyzabcdef 101wxyz + * 01wxyzabcdefg 110wxyz + * 1wxyzabcdefgh 111wxyz + * + * Each biased linear code has a leading 1 which identifies the segment + * number. The value of the segment number is equal to 7 minus the number + * of leading 0's. The quantization interval is directly available as the + * four bits wxyz. * The trailing bits (a - h) are ignored. + * + * Ordinarily the complement of the resulting code word is used for + * transmission, and so the code word is complemented before it is returned. + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ +unsigned char st_14linear2ulaw( + int16_t pcm_val) /* 2's complement (14-bit range) */ +{ + int16_t mask; + int16_t seg; + unsigned char uval; + + /* Have calling software do it since its already doing a shift + * from 32-bits down to 16-bits. + */ + /* pcm_val = pcm_val >> 2; */ + + /* u-law inverts all bits */ + /* Get the sign and the magnitude of the value. */ + if (pcm_val < 0) { + pcm_val = -pcm_val; + mask = 0x7F; + } else { + mask = 0xFF; + } + if ( pcm_val > CLIP ) pcm_val = CLIP; /* clip the magnitude */ + pcm_val += (BIAS >> 2); + + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_uend, 8); + + /* + * Combine the sign, segment, quantization bits; + * and complement the code word. + */ + if (seg >= 8) /* out of range, return maximum value. */ + return (unsigned char) (0x7F ^ mask); + else { + uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF); + return (uval ^ mask); + } + +} + +/* + * ulaw2linear() - Convert a u-law value to 16-bit linear PCM + * + * First, a biased linear code is derived from the code word. An unbiased + * output can then be obtained by subtracting 33 from the biased code. + * + * Note that this function expects to be passed the complement of the + * original code word. This is in keeping with ISDN conventions. + */ +int16_t st_ulaw2linear16( + unsigned char u_val) +{ + int16_t t; + + /* Complement to obtain normal u-law value. */ + u_val = ~u_val; + + /* + * Extract and bias the quantization bits. Then + * shift up by the segment number and subtract out the bias. + */ + t = ((u_val & QUANT_MASK) << 3) + BIAS; + t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; + + return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); +} +#endif /* !FAST_ULAW_CONVERSION */ + +#ifdef FAST_ALAW_CONVERSION + +int16_t _st_alaw2linear16[256] = { + -5504, -5248, -6016, -5760, -4480, -4224, -4992, + -4736, -7552, -7296, -8064, -7808, -6528, -6272, + -7040, -6784, -2752, -2624, -3008, -2880, -2240, + -2112, -2496, -2368, -3776, -3648, -4032, -3904, + -3264, -3136, -3520, -3392, -22016, -20992, -24064, + -23040, -17920, -16896, -19968, -18944, -30208, -29184, + -32256, -31232, -26112, -25088, -28160, -27136, -11008, + -10496, -12032, -11520, -8960, -8448, -9984, -9472, + -15104, -14592, -16128, -15616, -13056, -12544, -14080, + -13568, -344, -328, -376, -360, -280, -264, + -312, -296, -472, -456, -504, -488, -408, + -392, -440, -424, -88, -72, -120, -104, + -24, -8, -56, -40, -216, -200, -248, + -232, -152, -136, -184, -168, -1376, -1312, + -1504, -1440, -1120, -1056, -1248, -1184, -1888, + -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, + -592, -944, -912, -1008, -976, -816, -784, + -880, -848, 5504, 5248, 6016, 5760, 4480, + 4224, 4992, 4736, 7552, 7296, 8064, 7808, + 6528, 6272, 7040, 6784, 2752, 2624, 3008, + 2880, 2240, 2112, 2496, 2368, 3776, 3648, + 4032, 3904, 3264, 3136, 3520, 3392, 22016, + 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, + 27136, 11008, 10496, 12032, 11520, 8960, 8448, + 9984, 9472, 15104, 14592, 16128, 15616, 13056, + 12544, 14080, 13568, 344, 328, 376, 360, + 280, 264, 312, 296, 472, 456, 504, + 488, 408, 392, 440, 424, 88, 72, + 120, 104, 24, 8, 56, 40, 216, + 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, + 1184, 1888, 1824, 2016, 1952, 1632, 1568, + 1760, 1696, 688, 656, 752, 720, 560, + 528, 624, 592, 944, 912, 1008, 976, + 816, 784, 880, 848 +}; + +uint8_t _st_13linear2alaw[0x2000] = { + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, + 0x6b, 0x6b, 0x6b, 0x6b, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, + 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x6e, 0x6e, 0x6e, 0x6e, + 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, + 0x6d, 0x6d, 0x6d, 0x6d, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x60, 0x60, 0x60, 0x60, + 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, + 0x67, 0x67, 0x67, 0x67, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, + 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x7a, 0x7a, 0x7a, 0x7a, + 0x7b, 0x7b, 0x7b, 0x7b, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7c, 0x7c, 0x7c, 0x7c, + 0x7d, 0x7d, 0x7d, 0x7d, 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x73, + 0x70, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x71, 0x76, 0x76, 0x76, 0x76, + 0x77, 0x77, 0x77, 0x77, 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x75, + 0x4a, 0x4a, 0x4b, 0x4b, 0x48, 0x48, 0x49, 0x49, 0x4e, 0x4e, 0x4f, 0x4f, + 0x4c, 0x4c, 0x4d, 0x4d, 0x42, 0x42, 0x43, 0x43, 0x40, 0x40, 0x41, 0x41, + 0x46, 0x46, 0x47, 0x47, 0x44, 0x44, 0x45, 0x45, 0x5a, 0x5a, 0x5b, 0x5b, + 0x58, 0x58, 0x59, 0x59, 0x5e, 0x5e, 0x5f, 0x5f, 0x5c, 0x5c, 0x5d, 0x5d, + 0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51, 0x56, 0x56, 0x57, 0x57, + 0x54, 0x54, 0x55, 0x55, 0xd5, 0xd5, 0xd4, 0xd4, 0xd7, 0xd7, 0xd6, 0xd6, + 0xd1, 0xd1, 0xd0, 0xd0, 0xd3, 0xd3, 0xd2, 0xd2, 0xdd, 0xdd, 0xdc, 0xdc, + 0xdf, 0xdf, 0xde, 0xde, 0xd9, 0xd9, 0xd8, 0xd8, 0xdb, 0xdb, 0xda, 0xda, + 0xc5, 0xc5, 0xc4, 0xc4, 0xc7, 0xc7, 0xc6, 0xc6, 0xc1, 0xc1, 0xc0, 0xc0, + 0xc3, 0xc3, 0xc2, 0xc2, 0xcd, 0xcd, 0xcc, 0xcc, 0xcf, 0xcf, 0xce, 0xce, + 0xc9, 0xc9, 0xc8, 0xc8, 0xcb, 0xcb, 0xca, 0xca, 0xf5, 0xf5, 0xf5, 0xf5, + 0xf4, 0xf4, 0xf4, 0xf4, 0xf7, 0xf7, 0xf7, 0xf7, 0xf6, 0xf6, 0xf6, 0xf6, + 0xf1, 0xf1, 0xf1, 0xf1, 0xf0, 0xf0, 0xf0, 0xf0, 0xf3, 0xf3, 0xf3, 0xf3, + 0xf2, 0xf2, 0xf2, 0xf2, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xf9, 0xf9, 0xf9, 0xf9, + 0xf8, 0xf8, 0xf8, 0xf8, 0xfb, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xfa, + 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4, + 0xe4, 0xe4, 0xe4, 0xe4, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, + 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe1, 0xe1, 0xe1, 0xe1, + 0xe1, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, + 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, + 0xe2, 0xe2, 0xe2, 0xe2, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, + 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xef, 0xef, 0xef, 0xef, + 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, + 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, + 0xe8, 0xe8, 0xe8, 0xe8, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa +}; + +#endif /* FAST_ALAW_CONVERSION */ + +#ifdef FAST_ULAW_CONVERSION + +int16_t _st_ulaw2linear16[256] = { + -32124, -31100, -30076, -29052, -28028, -27004, -25980, + -24956, -23932, -22908, -21884, -20860, -19836, -18812, + -17788, -16764, -15996, -15484, -14972, -14460, -13948, + -13436, -12924, -12412, -11900, -11388, -10876, -10364, + -9852, -9340, -8828, -8316, -7932, -7676, -7420, + -7164, -6908, -6652, -6396, -6140, -5884, -5628, + -5372, -5116, -4860, -4604, -4348, -4092, -3900, + -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, + -1980, -1884, -1820, -1756, -1692, -1628, -1564, + -1500, -1436, -1372, -1308, -1244, -1180, -1116, + -1052, -988, -924, -876, -844, -812, -780, + -748, -716, -684, -652, -620, -588, -556, + -524, -492, -460, -428, -396, -372, -356, + -340, -324, -308, -292, -276, -260, -244, + -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, + -64, -56, -48, -40, -32, -24, -16, + -8, 0, 32124, 31100, 30076, 29052, 28028, + 27004, 25980, 24956, 23932, 22908, 21884, 20860, + 19836, 18812, 17788, 16764, 15996, 15484, 14972, + 14460, 13948, 13436, 12924, 12412, 11900, 11388, + 10876, 10364, 9852, 9340, 8828, 8316, 7932, + 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, + 4092, 3900, 3772, 3644, 3516, 3388, 3260, + 3132, 3004, 2876, 2748, 2620, 2492, 2364, + 2236, 2108, 1980, 1884, 1820, 1756, 1692, + 1628, 1564, 1500, 1436, 1372, 1308, 1244, + 1180, 1116, 1052, 988, 924, 876, 844, + 812, 780, 748, 716, 684, 652, 620, + 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, + 260, 244, 228, 212, 196, 180, 164, + 148, 132, 120, 112, 104, 96, 88, + 80, 72, 64, 56, 48, 40, 32, + 24, 16, 8, 0 +}; + +uint8_t _st_14linear2ulaw[0x4000] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, + 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, + 0x43, 0x43, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, + 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, + 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, + 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, + 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, + 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, + 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, + 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, + 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, + 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, + 0x52, 0x52, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, + 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x57, 0x57, + 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a, 0x5a, + 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, + 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, + 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x60, 0x60, + 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x62, 0x63, 0x63, + 0x63, 0x63, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, + 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, + 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, + 0x6f, 0x6f, 0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x74, 0x74, + 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a, + 0x7b, 0x7b, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0xff, 0xfe, 0xfe, 0xfd, + 0xfd, 0xfc, 0xfc, 0xfb, 0xfb, 0xfa, 0xfa, 0xf9, 0xf9, 0xf8, 0xf8, 0xf7, + 0xf7, 0xf6, 0xf6, 0xf5, 0xf5, 0xf4, 0xf4, 0xf3, 0xf3, 0xf2, 0xf2, 0xf1, + 0xf1, 0xf0, 0xf0, 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xed, + 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xeb, 0xeb, 0xeb, 0xeb, 0xea, + 0xea, 0xea, 0xea, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, + 0xe4, 0xe4, 0xe4, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, 0xe1, + 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, + 0xdf, 0xdf, 0xdf, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, + 0xdc, 0xdc, 0xdc, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xda, + 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, + 0xd9, 0xd9, 0xd9, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd7, + 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, + 0xd6, 0xd6, 0xd6, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd4, + 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, + 0xd3, 0xd3, 0xd3, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd1, + 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, + 0xd0, 0xd0, 0xd0, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, + 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xce, 0xce, 0xce, 0xce, 0xce, + 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, + 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xca, + 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, + 0xca, 0xca, 0xca, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, + 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, + 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc7, + 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, + 0xc7, 0xc7, 0xc7, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, + 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, + 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc1, + 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, + 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, + 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80 +}; + +#endif /* FAST_ULAW_CONVERSION */ + +/* The following code was used to generate the lookup tables */ +#if 0 +int main() +{ + int x, y, find2a = 0; + + y = 0; + printf("int16_t _st_alaw2linear16[256] = {\n "); + for (x = 0; x < 256; x++) + { + printf("%8d,", st_alaw2linear16(x)); + y++; + if (y == 7) + { + y = 0; + printf("\n "); + } + } + + printf("\n};\n\nuint8_t _st_13linear2alaw[0x2000] = {\n "); + y = 0; + for (x = 0; x < 0x2000; x++) + { + printf(" 0x%02x,", st_13linear2alaw((-0x1000)+x)); + y++; + if (y == 12) + { + y = 0; + printf("\n "); + } + } + + printf("\n};\n\nint16_t _st_ulaw2linear16[256] = {\n "); + y = 0; + for (x = 0; x < 256; x++) + { + printf("%8d,", st_ulaw2linear16(x)); + y++; + if (y == 7) + { + y = 0; + printf("\n "); + } + } + + printf("\n};\n\nuint8_t _st_14linear2ulaw[0x4000] = {\n "); + y = 0; + for (x = 0; x < 0x4000; x++) + { + printf(" 0x%02x,", st_14linear2ulaw((-0x2000)+x)); + y++; + if (y == 12) + { + y = 0; + printf("\n "); + } + } + printf("\n};\n"); + +} +#endif + +/* The following is not used by SoX but kept for reference */ +#if 0 +/* copy from CCITT G.711 specifications */ +unsigned char _u2a[128] = { /* u- to A-law conversions */ + 1, 1, 2, 2, 3, 3, 4, 4, + 5, 5, 6, 6, 7, 7, 8, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 27, 29, 31, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, + 46, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, +/* corrected: + 81, 82, 83, 84, 85, 86, 87, 88, + should be: */ + 80, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128}; + +unsigned char _a2u[128] = { /* A- to u-law conversions */ + 1, 3, 5, 7, 9, 11, 13, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 32, 33, 33, 34, 34, 35, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 48, 49, 49, + 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 64, + 65, 66, 67, 68, 69, 70, 71, 72, +/* corrected: + 73, 74, 75, 76, 77, 78, 79, 79, + should be: */ + 73, 74, 75, 76, 77, 78, 79, 80, + + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127}; + +/* A-law to u-law conversion */ +unsigned char st_alaw2ulaw( + unsigned char aval) +{ + aval &= 0xff; + return (unsigned char) ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) : + (0x7F ^ _a2u[aval ^ 0x55])); +} + +/* u-law to A-law conversion */ +unsigned char st_ulaw2alaw( + unsigned char uval) +{ + uval &= 0xff; + return (unsigned char) ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) : + (unsigned char) (0x55 ^ (_u2a[0x7F ^ uval] - 1))); +} +#endif diff --git a/src/pulsecore/g711.h b/src/pulsecore/g711.h new file mode 100644 index 00000000..97cedf81 --- /dev/null +++ b/src/pulsecore/g711.h @@ -0,0 +1,40 @@ +#ifndef foog711hfoo +#define foog711hfoo + +/* g711.h - include for G711 u-law and a-law conversion routines +** +** Copyright (C) 2001 Chris Bagwell +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +*/ + +/** Copied from sox -- Lennart Poettring*/ + +#include + +#ifdef FAST_ALAW_CONVERSION +extern uint8_t _st_13linear2alaw[0x2000]; +extern int16_t _st_alaw2linear16[256]; +#define st_13linear2alaw(sw) (_st_13linear2alaw[(sw + 0x1000)]) +#define st_alaw2linear16(uc) (_st_alaw2linear16[uc]) +#else +unsigned char st_13linear2alaw(int16_t pcm_val); +int16_t st_alaw2linear16(unsigned char); +#endif + +#ifdef FAST_ULAW_CONVERSION +extern uint8_t _st_14linear2ulaw[0x4000]; +extern int16_t _st_ulaw2linear16[256]; +#define st_14linear2ulaw(sw) (_st_14linear2ulaw[(sw + 0x2000)]) +#define st_ulaw2linear16(uc) (_st_ulaw2linear16[uc]) +#else +unsigned char st_14linear2ulaw(int16_t pcm_val); +int16_t st_ulaw2linear16(unsigned char); +#endif + +#endif diff --git a/src/pulsecore/gccmacro.h b/src/pulsecore/gccmacro.h new file mode 100644 index 00000000..2ab999d9 --- /dev/null +++ b/src/pulsecore/gccmacro.h @@ -0,0 +1,53 @@ +#ifndef foogccmacrohfoo +#define foogccmacrohfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef __GNUC__ +#define PA_GCC_PRINTF_ATTR(a,b) __attribute__ ((format (printf, a, b))) +#else +/** If we're in GNU C, use some magic for detecting invalid format strings */ +#define PA_GCC_PRINTF_ATTR(a,b) +#endif + +#if defined(__GNUC__) && (__GNUC__ >= 4) +#define PA_GCC_SENTINEL __attribute__ ((sentinel)) +#else +/** Macro for usage of GCC's sentinel compilation warnings */ +#define PA_GCC_SENTINEL +#endif + +#ifdef __GNUC__ +#define PA_GCC_NORETURN __attribute__((noreturn)) +#else +/** Macro for no-return functions */ +#define PA_GCC_NORETURN +#endif + +#ifdef __GNUC__ +#define PA_GCC_UNUSED __attribute__ ((unused)) +#else +/** Macro for not used parameter */ +#define PA_GCC_UNUSED +#endif + +#endif diff --git a/src/pulsecore/hashmap.c b/src/pulsecore/hashmap.c new file mode 100644 index 00000000..2cddba1d --- /dev/null +++ b/src/pulsecore/hashmap.c @@ -0,0 +1,196 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include +#include + +#include "hashmap.h" + +#define BUCKETS 1023 + +struct hashmap_entry { + struct hashmap_entry *next, *previous, *bucket_next, *bucket_previous; + unsigned hash; + const void *key; + void *value; +}; + +struct pa_hashmap { + unsigned size; + struct hashmap_entry **data; + struct hashmap_entry *first_entry; + + unsigned n_entries; + unsigned (*hash_func) (const void *p); + int (*compare_func) (const void*a, const void*b); +}; + +pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { + pa_hashmap *h; + h = pa_xmalloc(sizeof(pa_hashmap)); + h->data = pa_xmalloc0(sizeof(struct hashmap_entry*)*(h->size = BUCKETS)); + h->first_entry = NULL; + h->n_entries = 0; + h->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; + h->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; + return h; +} + +static void remove(pa_hashmap *h, struct hashmap_entry *e) { + assert(e); + + if (e->next) + e->next->previous = e->previous; + if (e->previous) + e->previous->next = e->next; + else + h->first_entry = e->next; + + if (e->bucket_next) + e->bucket_next->bucket_previous = e->bucket_previous; + if (e->bucket_previous) + e->bucket_previous->bucket_next = e->bucket_next; + else { + assert(e->hash < h->size); + h->data[e->hash] = e->bucket_next; + } + + pa_xfree(e); + h->n_entries--; +} + +void pa_hashmap_free(pa_hashmap*h, void (*free_func)(void *p, void *userdata), void *userdata) { + assert(h); + + while (h->first_entry) { + if (free_func) + free_func(h->first_entry->value, userdata); + remove(h, h->first_entry); + } + + pa_xfree(h->data); + pa_xfree(h); +} + +static struct hashmap_entry *get(pa_hashmap *h, unsigned hash, const void *key) { + struct hashmap_entry *e; + assert(h && hash < h->size); + + for (e = h->data[hash]; e; e = e->bucket_next) + if (h->compare_func(e->key, key) == 0) + return e; + + return NULL; +} + +int pa_hashmap_put(pa_hashmap *h, const void *key, void *value) { + struct hashmap_entry *e; + unsigned hash; + assert(h); + + hash = h->hash_func(key) % h->size; + + if ((e = get(h, hash, key))) + return -1; + + e = pa_xmalloc(sizeof(struct hashmap_entry)); + e->hash = hash; + e->key = key; + e->value = value; + + e->previous = NULL; + e->next = h->first_entry; + if (h->first_entry) + h->first_entry->previous = e; + h->first_entry = e; + + e->bucket_previous = NULL; + e->bucket_next = h->data[hash]; + if (h->data[hash]) + h->data[hash]->bucket_previous = e; + h->data[hash] = e; + + h->n_entries ++; + return 0; +} + +void* pa_hashmap_get(pa_hashmap *h, const void *key) { + unsigned hash; + struct hashmap_entry *e; + assert(h && key); + + hash = h->hash_func(key) % h->size; + + if (!(e = get(h, hash, key))) + return NULL; + + return e->value; +} + +void* pa_hashmap_remove(pa_hashmap *h, const void *key) { + struct hashmap_entry *e; + unsigned hash; + void *data; + assert(h && key); + + hash = h->hash_func(key) % h->size; + + if (!(e = get(h, hash, key))) + return NULL; + + data = e->value; + remove(h, e); + return data; +} + +unsigned pa_hashmap_size(pa_hashmap *h) { + return h->n_entries; +} + +void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void **key) { + assert(h && state); + + if (!*state) + *state = h->first_entry; + else + *state = ((struct hashmap_entry*) *state)->next; + + if (!*state) { + if (key) + *key = NULL; + return NULL; + } + + if (key) + *key = ((struct hashmap_entry*) *state)->key; + + return ((struct hashmap_entry*) *state)->value; +} diff --git a/src/pulsecore/hashmap.h b/src/pulsecore/hashmap.h new file mode 100644 index 00000000..3f62adb1 --- /dev/null +++ b/src/pulsecore/hashmap.h @@ -0,0 +1,53 @@ +#ifndef foohashmaphfoo +#define foohashmaphfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* Simple Implementation of a hash table. Memory management is the + * user's job. It's a good idea to have the key pointer point to a + * string in the value data. */ + +typedef struct pa_hashmap pa_hashmap; + +/* Create a new hashmap. Use the specified functions for hashing and comparing objects in the map */ +pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); + +/* Free the hash table. Calls the specified function for every value in the table. The function may be NULL */ +void pa_hashmap_free(pa_hashmap*, void (*free_func)(void *p, void *userdata), void *userdata); + +/* Returns non-zero when the entry already exists */ +int pa_hashmap_put(pa_hashmap *h, const void *key, void *value); +void* pa_hashmap_get(pa_hashmap *h, const void *key); + +/* Returns the data of the entry while removing */ +void* pa_hashmap_remove(pa_hashmap *h, const void *key); + +unsigned pa_hashmap_size(pa_hashmap *h); + +/* May be used to iterate through the hashmap. Initially the opaque + pointer *state has to be set to NULL. The hashmap may not be + modified during iteration. The key of the entry is returned in + *key, if key is non-NULL. After the last entry in the hashmap NULL + is returned. */ +void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void**key); + +#endif diff --git a/src/pulsecore/idxset.c b/src/pulsecore/idxset.c new file mode 100644 index 00000000..ddce623a --- /dev/null +++ b/src/pulsecore/idxset.c @@ -0,0 +1,391 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include "idxset.h" + +typedef struct idxset_entry { + void *data; + uint32_t index; + unsigned hash_value; + + struct idxset_entry *hash_prev, *hash_next; + struct idxset_entry* iterate_prev, *iterate_next; +} idxset_entry; + +struct pa_idxset { + unsigned (*hash_func) (const void *p); + int (*compare_func)(const void *a, const void *b); + + unsigned hash_table_size, n_entries; + idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail; + uint32_t index, start_index, array_size; +}; + +unsigned pa_idxset_string_hash_func(const void *p) { + unsigned hash = 0; + const char *c; + + for (c = p; *c; c++) + hash = 31 * hash + *c; + + return hash; +} + +int pa_idxset_string_compare_func(const void *a, const void *b) { + return strcmp(a, b); +} + +unsigned pa_idxset_trivial_hash_func(const void *p) { + return (unsigned) (long) p; +} + +int pa_idxset_trivial_compare_func(const void *a, const void *b) { + return a != b; +} + +pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { + pa_idxset *s; + + s = pa_xnew(pa_idxset, 1); + s->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; + s->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; + s->hash_table_size = 1023; + s->hash_table = pa_xmalloc0(sizeof(idxset_entry*)*s->hash_table_size); + s->array = NULL; + s->array_size = 0; + s->index = 0; + s->start_index = 0; + s->n_entries = 0; + + s->iterate_list_head = s->iterate_list_tail = NULL; + + return s; +} + +void pa_idxset_free(pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata) { + assert(s); + + while (s->iterate_list_head) { + idxset_entry *e = s->iterate_list_head; + s->iterate_list_head = s->iterate_list_head->iterate_next; + + if (free_func) + free_func(e->data, userdata); + pa_xfree(e); + } + + pa_xfree(s->hash_table); + pa_xfree(s->array); + pa_xfree(s); +} + +static idxset_entry* hash_scan(pa_idxset *s, idxset_entry* e, const void *p) { + assert(p); + + assert(s->compare_func); + for (; e; e = e->hash_next) + if (s->compare_func(e->data, p) == 0) + return e; + + return NULL; +} + +static void extend_array(pa_idxset *s, uint32_t idx) { + uint32_t i, j, l; + idxset_entry** n; + assert(idx >= s->start_index); + + if (idx < s->start_index + s->array_size) + return; + + for (i = 0; i < s->array_size; i++) + if (s->array[i]) + break; + + l = idx - s->start_index - i + 100; + n = pa_xnew0(idxset_entry*, l); + + for (j = 0; j < s->array_size-i; j++) + n[j] = s->array[i+j]; + + pa_xfree(s->array); + + s->array = n; + s->array_size = l; + s->start_index += i; +} + +static idxset_entry** array_index(pa_idxset*s, uint32_t idx) { + if (idx >= s->start_index + s->array_size) + return NULL; + + if (idx < s->start_index) + return NULL; + + return s->array + (idx - s->start_index); +} + +int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) { + unsigned h; + idxset_entry *e, **a; + assert(s && p); + + assert(s->hash_func); + h = s->hash_func(p) % s->hash_table_size; + + assert(s->hash_table); + if ((e = hash_scan(s, s->hash_table[h], p))) { + if (idx) + *idx = e->index; + + return -1; + } + + e = pa_xmalloc(sizeof(idxset_entry)); + e->data = p; + e->index = s->index++; + e->hash_value = h; + + /* Insert into hash table */ + e->hash_next = s->hash_table[h]; + e->hash_prev = NULL; + if (s->hash_table[h]) + s->hash_table[h]->hash_prev = e; + s->hash_table[h] = e; + + /* Insert into array */ + extend_array(s, e->index); + a = array_index(s, e->index); + assert(a && !*a); + *a = e; + + /* Insert into linked list */ + e->iterate_next = NULL; + e->iterate_prev = s->iterate_list_tail; + if (s->iterate_list_tail) { + assert(s->iterate_list_head); + s->iterate_list_tail->iterate_next = e; + } else { + assert(!s->iterate_list_head); + s->iterate_list_head = e; + } + s->iterate_list_tail = e; + + s->n_entries++; + assert(s->n_entries >= 1); + + if (idx) + *idx = e->index; + + return 0; +} + +void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx) { + idxset_entry **a; + assert(s); + + if (!(a = array_index(s, idx))) + return NULL; + + if (!*a) + return NULL; + + return (*a)->data; +} + +void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx) { + unsigned h; + idxset_entry *e; + assert(s && p); + + assert(s->hash_func); + h = s->hash_func(p) % s->hash_table_size; + + assert(s->hash_table); + if (!(e = hash_scan(s, s->hash_table[h], p))) + return NULL; + + if (idx) + *idx = e->index; + + return e->data; +} + +static void remove_entry(pa_idxset *s, idxset_entry *e) { + idxset_entry **a; + assert(s && e); + + /* Remove from array */ + a = array_index(s, e->index); + assert(a && *a && *a == e); + *a = NULL; + + /* Remove from linked list */ + if (e->iterate_next) + e->iterate_next->iterate_prev = e->iterate_prev; + else + s->iterate_list_tail = e->iterate_prev; + + if (e->iterate_prev) + e->iterate_prev->iterate_next = e->iterate_next; + else + s->iterate_list_head = e->iterate_next; + + /* Remove from hash table */ + if (e->hash_next) + e->hash_next->hash_prev = e->hash_prev; + + if (e->hash_prev) + e->hash_prev->hash_next = e->hash_next; + else + s->hash_table[e->hash_value] = e->hash_next; + + pa_xfree(e); + + assert(s->n_entries >= 1); + s->n_entries--; +} + +void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx) { + idxset_entry **a; + void *data; + + assert(s); + + if (!(a = array_index(s, idx))) + return NULL; + + data = (*a)->data; + remove_entry(s, *a); + + return data; +} + +void* pa_idxset_remove_by_data(pa_idxset*s, const void *data, uint32_t *idx) { + idxset_entry *e; + unsigned h; + void *r; + + assert(s->hash_func); + h = s->hash_func(data) % s->hash_table_size; + + assert(s->hash_table); + if (!(e = hash_scan(s, s->hash_table[h], data))) + return NULL; + + r = e->data; + if (idx) + *idx = e->index; + + remove_entry(s, e); + + return r; +} + +void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx) { + idxset_entry **a, *e = NULL; + assert(s && idx); + + if ((a = array_index(s, *idx)) && *a) + e = (*a)->iterate_next; + + if (!e) + e = s->iterate_list_head; + + if (!e) + return NULL; + + *idx = e->index; + return e->data; +} + +void* pa_idxset_first(pa_idxset *s, uint32_t *idx) { + assert(s); + + if (!s->iterate_list_head) + return NULL; + + if (idx) + *idx = s->iterate_list_head->index; + return s->iterate_list_head->data; +} + +void *pa_idxset_next(pa_idxset *s, uint32_t *idx) { + idxset_entry **a, *e = NULL; + assert(s && idx); + + if ((a = array_index(s, *idx)) && *a) + e = (*a)->iterate_next; + + if (e) { + *idx = e->index; + return e->data; + } else { + *idx = PA_IDXSET_INVALID; + return NULL; + } +} + + +int pa_idxset_foreach(pa_idxset*s, int (*func)(void *p, uint32_t idx, int *del, void*userdata), void *userdata) { + idxset_entry *e; + assert(s && func); + + e = s->iterate_list_head; + while (e) { + int del = 0, r; + idxset_entry *n = e->iterate_next; + + r = func(e->data, e->index, &del, userdata); + + if (del) + remove_entry(s, e); + + if (r < 0) + return r; + + e = n; + } + + return 0; +} + +unsigned pa_idxset_size(pa_idxset*s) { + assert(s); + return s->n_entries; +} + +int pa_idxset_isempty(pa_idxset *s) { + assert(s); + return s->n_entries == 0; +} + diff --git a/src/pulsecore/idxset.h b/src/pulsecore/idxset.h new file mode 100644 index 00000000..3d0bc75f --- /dev/null +++ b/src/pulsecore/idxset.h @@ -0,0 +1,94 @@ +#ifndef fooidxsethfoo +#define fooidxsethfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +/* A combination of a set and a dynamic array. Entries are indexable + * both through a numeric automatically generated index and the entry's + * data pointer. As usual, memory management is the user's job. */ + +/* A special index value denoting the invalid index. */ +#define PA_IDXSET_INVALID ((uint32_t) -1) + +/* Generic implementations for hash and comparison functions. Just + * compares the pointer or calculates the hash value directly from the + * pointer value. */ +unsigned pa_idxset_trivial_hash_func(const void *p); +int pa_idxset_trivial_compare_func(const void *a, const void *b); + +/* Generic implementations for hash and comparison functions for strings. */ +unsigned pa_idxset_string_hash_func(const void *p); +int pa_idxset_string_compare_func(const void *a, const void *b); + +typedef struct pa_idxset pa_idxset; + +/* Instantiate a new idxset with the specified hash and comparison functions */ +pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); + +/* Free the idxset. When the idxset is not empty the specified function is called for every entry contained */ +void pa_idxset_free(pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata); + +/* Store a new item in the idxset. The index of the item is returned in *idx */ +int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx); + +/* Get the entry by its idx */ +void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx); + +/* Get the entry by its data. The idx is returned in *index */ +void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx); + +/* Similar to pa_idxset_get_by_index(), but removes the entry from the idxset. */ +void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx); + +/* Similar to pa_idxset_get_by_data(), but removes the entry from the idxset */ +void* pa_idxset_remove_by_data(pa_idxset*s, const void *p, uint32_t *idx); + +/* This may be used to iterate through all entries. When called with + an invalid index value it returns the first entry, otherwise the + next following. The function is best called with *idx = + PA_IDXSET_VALID first. It is safe to manipulate the idxset between + the calls. It is not guaranteed that all entries have already been + returned before the an entry is returned the second time.*/ +void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx); + +/* Return the oldest entry in the idxset. Fill in its index in *idx. */ +void* pa_idxset_first(pa_idxset *s, uint32_t *idx); + +/* Return the entry following the entry indexed by *idx. After the + * call *index contains the index of the returned + * object. pa_idxset_first() and pa_idxset_next() may be used to + * iterate through the set.*/ +void *pa_idxset_next(pa_idxset *s, uint32_t *idx); + +/* Call a function for every item in the set. If the callback function + returns -1, the loop is terminated. If *del is set to non-zero that + specific item is removed. It is not safe to call any other + functions on the idxset while pa_idxset_foreach is executed. */ +int pa_idxset_foreach(pa_idxset*s, int (*func)(void *p, uint32_t idx, int *del, void*userdata), void *userdata); + +unsigned pa_idxset_size(pa_idxset*s); + +int pa_idxset_isempty(pa_idxset *s); + +#endif diff --git a/src/pulsecore/inet_ntop.c b/src/pulsecore/inet_ntop.c new file mode 100644 index 00000000..483c3e26 --- /dev/null +++ b/src/pulsecore/inet_ntop.c @@ -0,0 +1,80 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#ifndef HAVE_INET_NTOP + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#include "winsock.h" + +#include "inet_ntop.h" + +const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) { + struct in_addr *in = (struct in_addr*)src; + struct in6_addr *in6 = (struct in6_addr*)src; + + assert(src && dst); + + switch (af) { + case AF_INET: + snprintf(dst, cnt, "%d.%d.%d.%d", +#ifdef WORDS_BIGENDIAN + (int)(in->s_addr >> 24) & 0xff, + (int)(in->s_addr >> 16) & 0xff, + (int)(in->s_addr >> 8) & 0xff, + (int)(in->s_addr >> 0) & 0xff); +#else + (int)(in->s_addr >> 0) & 0xff, + (int)(in->s_addr >> 8) & 0xff, + (int)(in->s_addr >> 16) & 0xff, + (int)(in->s_addr >> 24) & 0xff); +#endif + break; + case AF_INET6: + snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x", + in6->s6_addr[ 0] << 8 | in6->s6_addr[ 1], + in6->s6_addr[ 2] << 8 | in6->s6_addr[ 3], + in6->s6_addr[ 4] << 8 | in6->s6_addr[ 5], + in6->s6_addr[ 6] << 8 | in6->s6_addr[ 7], + in6->s6_addr[ 8] << 8 | in6->s6_addr[ 9], + in6->s6_addr[10] << 8 | in6->s6_addr[11], + in6->s6_addr[12] << 8 | in6->s6_addr[13], + in6->s6_addr[14] << 8 | in6->s6_addr[15]); + break; + default: + errno = EAFNOSUPPORT; + return NULL; + } + + return dst; +} + +#endif /* INET_NTOP */ diff --git a/src/pulsecore/inet_ntop.h b/src/pulsecore/inet_ntop.h new file mode 100644 index 00000000..7fb67b44 --- /dev/null +++ b/src/pulsecore/inet_ntop.h @@ -0,0 +1,12 @@ +#ifndef fooinet_ntophfoo +#define fooinet_ntophfoo + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#include "winsock.h" + +const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt); + +#endif diff --git a/src/pulsecore/inet_pton.c b/src/pulsecore/inet_pton.c new file mode 100644 index 00000000..7b6bbc31 --- /dev/null +++ b/src/pulsecore/inet_pton.c @@ -0,0 +1,62 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#ifndef HAVE_INET_PTON + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#include "winsock.h" + +#include "inet_pton.h" + +int inet_pton(int af, const char *src, void *dst) { + struct in_addr *in = (struct in_addr*)dst; + struct in6_addr *in6 = (struct in6_addr*)dst; + + assert(src && dst); + + switch (af) { + case AF_INET: + in->s_addr = inet_addr(src); + if (in->s_addr == INADDR_NONE) + return 0; + break; + case AF_INET6: + /* FIXME */ + default: + errno = EAFNOSUPPORT; + return -1; + } + + return 1; +} + +#endif /* INET_PTON */ diff --git a/src/pulsecore/inet_pton.h b/src/pulsecore/inet_pton.h new file mode 100644 index 00000000..111b4a07 --- /dev/null +++ b/src/pulsecore/inet_pton.h @@ -0,0 +1,12 @@ +#ifndef fooinet_ptonhfoo +#define fooinet_ptonhfoo + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#include "winsock.h" + +int inet_pton(int af, const char *src, void *dst); + +#endif diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c new file mode 100644 index 00000000..8a19094a --- /dev/null +++ b/src/pulsecore/iochannel.c @@ -0,0 +1,417 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif + +#include "winsock.h" + +#include + +#include +#include +#include +#include + +#include "iochannel.h" + +struct pa_iochannel { + int ifd, ofd; + pa_mainloop_api* mainloop; + + pa_iochannel_cb_t callback; + void*userdata; + + int readable; + int writable; + int hungup; + + int no_close; + + pa_io_event* input_event, *output_event; +}; + +static void enable_mainloop_sources(pa_iochannel *io) { + assert(io); + + if (io->input_event == io->output_event && io->input_event) { + pa_io_event_flags_t f = PA_IO_EVENT_NULL; + assert(io->input_event); + + if (!io->readable) + f |= PA_IO_EVENT_INPUT; + if (!io->writable) + f |= PA_IO_EVENT_OUTPUT; + + io->mainloop->io_enable(io->input_event, f); + } else { + if (io->input_event) + io->mainloop->io_enable(io->input_event, io->readable ? PA_IO_EVENT_NULL : PA_IO_EVENT_INPUT); + if (io->output_event) + io->mainloop->io_enable(io->output_event, io->writable ? PA_IO_EVENT_NULL : PA_IO_EVENT_OUTPUT); + } +} + +static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { + pa_iochannel *io = userdata; + int changed = 0; + + assert(m); + assert(e); + assert(fd >= 0); + assert(userdata); + + if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) { + io->hungup = 1; + changed = 1; + } + + if ((f & PA_IO_EVENT_INPUT) && !io->readable) { + io->readable = 1; + changed = 1; + assert(e == io->input_event); + } + + if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) { + io->writable = 1; + changed = 1; + assert(e == io->output_event); + } + + if (changed) { + enable_mainloop_sources(io); + + if (io->callback) + io->callback(io, io->userdata); + } +} + +pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) { + pa_iochannel *io; + + assert(m); + assert(ifd >= 0 || ofd >= 0); + + io = pa_xnew(pa_iochannel, 1); + io->ifd = ifd; + io->ofd = ofd; + io->mainloop = m; + + io->userdata = NULL; + io->callback = NULL; + io->readable = 0; + io->writable = 0; + io->hungup = 0; + io->no_close = 0; + + io->input_event = io->output_event = NULL; + + if (ifd == ofd) { + assert(ifd >= 0); + pa_make_nonblock_fd(io->ifd); + io->input_event = io->output_event = m->io_new(m, ifd, PA_IO_EVENT_INPUT|PA_IO_EVENT_OUTPUT, callback, io); + } else { + + if (ifd >= 0) { + pa_make_nonblock_fd(io->ifd); + io->input_event = m->io_new(m, ifd, PA_IO_EVENT_INPUT, callback, io); + } + + if (ofd >= 0) { + pa_make_nonblock_fd(io->ofd); + io->output_event = m->io_new(m, ofd, PA_IO_EVENT_OUTPUT, callback, io); + } + } + + return io; +} + +void pa_iochannel_free(pa_iochannel*io) { + assert(io); + + if (io->input_event) + io->mainloop->io_free(io->input_event); + + if (io->output_event && (io->output_event != io->input_event)) + io->mainloop->io_free(io->output_event); + + if (!io->no_close) { + if (io->ifd >= 0) + + close(io->ifd); + if (io->ofd >= 0 && io->ofd != io->ifd) + close(io->ofd); + } + + pa_xfree(io); +} + +int pa_iochannel_is_readable(pa_iochannel*io) { + assert(io); + + return io->readable || io->hungup; +} + +int pa_iochannel_is_writable(pa_iochannel*io) { + assert(io); + + return io->writable && !io->hungup; +} + +int pa_iochannel_is_hungup(pa_iochannel*io) { + assert(io); + + return io->hungup; +} + +ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) { + ssize_t r; + + assert(io); + assert(data); + assert(l); + assert(io->ofd >= 0); + + r = pa_write(io->ofd, data, l); + if (r >= 0) { + io->writable = 0; + enable_mainloop_sources(io); + } + + return r; +} + +ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) { + ssize_t r; + + assert(io); + assert(data); + assert(io->ifd >= 0); + + r = pa_read(io->ifd, data, l); + if (r >= 0) { + io->readable = 0; + enable_mainloop_sources(io); + } + + return r; +} + +#ifdef SCM_CREDENTIALS + +int pa_iochannel_creds_supported(pa_iochannel *io) { + struct sockaddr_un sa; + socklen_t l; + + assert(io); + assert(io->ifd >= 0); + assert(io->ofd == io->ifd); + + l = sizeof(sa); + + if (getsockname(io->ifd, (struct sockaddr*) &sa, &l) < 0) + return 0; + + return sa.sun_family == AF_UNIX; +} + +int pa_iochannel_creds_enable(pa_iochannel *io) { + int t = 1; + + assert(io); + assert(io->ifd >= 0); + + if (setsockopt(io->ifd, SOL_SOCKET, SO_PASSCRED, &t, sizeof(t)) < 0) { + pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno)); + return -1; + } + + return 0; +} + +ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l) { + ssize_t r; + struct msghdr mh; + struct iovec iov; + uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))]; + struct ucred *ucred; + struct cmsghdr *cmsg; + + assert(io); + assert(data); + assert(l); + assert(io->ofd >= 0); + + memset(&iov, 0, sizeof(iov)); + iov.iov_base = (void*) data; + iov.iov_len = l; + + memset(cmsg_data, 0, sizeof(cmsg_data)); + cmsg = (struct cmsghdr*) cmsg_data; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_CREDENTIALS; + + ucred = (struct ucred*) CMSG_DATA(cmsg); + ucred->pid = getpid(); + ucred->uid = getuid(); + ucred->gid = getgid(); + + memset(&mh, 0, sizeof(mh)); + mh.msg_name = NULL; + mh.msg_namelen = 0; + mh.msg_iov = &iov; + mh.msg_iovlen = 1; + mh.msg_control = cmsg_data; + mh.msg_controllen = sizeof(cmsg_data); + mh.msg_flags = 0; + + if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) { + io->writable = 0; + enable_mainloop_sources(io); + } + + return r; +} + +ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struct ucred *ucred, int *creds_valid) { + ssize_t r; + struct msghdr mh; + struct iovec iov; + uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))]; + + assert(io); + assert(data); + assert(l); + assert(io->ifd >= 0); + assert(ucred); + assert(creds_valid); + + memset(&iov, 0, sizeof(iov)); + iov.iov_base = data; + iov.iov_len = l; + + memset(cmsg_data, 0, sizeof(cmsg_data)); + + memset(&mh, 0, sizeof(mh)); + mh.msg_name = NULL; + mh.msg_namelen = 0; + mh.msg_iov = &iov; + mh.msg_iovlen = 1; + mh.msg_control = cmsg_data; + mh.msg_controllen = sizeof(cmsg_data); + mh.msg_flags = 0; + + if ((r = recvmsg(io->ifd, &mh, MSG_NOSIGNAL)) >= 0) { + struct cmsghdr *cmsg; + + *creds_valid = 0; + + for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { + + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) { + assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))); + memcpy(ucred, CMSG_DATA(cmsg), sizeof(struct ucred)); + *creds_valid = 1; + break; + } + } + + io->readable = 0; + enable_mainloop_sources(io); + } + + return r; +} +#else /* SCM_CREDENTIALS */ + +int pa_iochannel_creds_supported(pa_iochannel *io) { + return 0; +} + +int pa_iochannel_creds_enable(pa_iochannel *io) { + return -1; +} + +ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l) { + pa_log_error("pa_iochannel_write_with_creds() not supported."); + return -1; +} + +ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struct ucred *ucred, int *creds_valid) { + pa_log_error("pa_iochannel_read_with_creds() not supported."); + return -1; +} + +#endif /* SCM_CREDENTIALS */ + +void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) { + assert(io); + + io->callback = _callback; + io->userdata = userdata; +} + +void pa_iochannel_set_noclose(pa_iochannel*io, int b) { + assert(io); + + io->no_close = b; +} + +void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) { + assert(io); + assert(s); + assert(l); + + pa_socket_peer_to_string(io->ifd, s, l); +} + +int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) { + assert(io); + + return pa_socket_set_rcvbuf(io->ifd, l); +} + +int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) { + assert(io); + + return pa_socket_set_sndbuf(io->ofd, l); +} + +pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) { + assert(io); + + return io->mainloop; +} diff --git a/src/pulsecore/iochannel.h b/src/pulsecore/iochannel.h new file mode 100644 index 00000000..64cf331e --- /dev/null +++ b/src/pulsecore/iochannel.h @@ -0,0 +1,81 @@ +#ifndef fooiochannelhfoo +#define fooiochannelhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include + +/* A wrapper around UNIX file descriptors for attaching them to the a + main event loop. Everytime new data may be read or be written to + the channel a callback function is called. It is safe to destroy + the calling iochannel object from the callback */ + +/* When pa_iochannel_is_readable() returns non-zero, the user has to + * call this function in a loop until it is no longer set or EOF + * reached. Otherwise strange things may happen when an EOF is + * reached. */ + +typedef struct pa_iochannel pa_iochannel; + +/* Create a new IO channel for the specified file descriptors for +input resp. output. It is safe to pass the same file descriptor for +both parameters (in case of full-duplex channels). For a simplex +channel specify -1 for the other direction. */ + +pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd); +void pa_iochannel_free(pa_iochannel*io); + +ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l); +ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l); + +int pa_iochannel_creds_supported(pa_iochannel *io); +int pa_iochannel_creds_enable(pa_iochannel *io); + +struct ucred; + +ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l); +ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struct ucred *ucred, int *creds_valid); + +int pa_iochannel_is_readable(pa_iochannel*io); +int pa_iochannel_is_writable(pa_iochannel*io); +int pa_iochannel_is_hungup(pa_iochannel*io); + +/* Don't close the file descirptors when the io channel is freed. By + * default the file descriptors are closed. */ +void pa_iochannel_set_noclose(pa_iochannel*io, int b); + +/* Set the callback function that is called whenever data becomes available for read or write */ +typedef void (*pa_iochannel_cb_t)(pa_iochannel*io, void *userdata); +void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t callback, void *userdata); + +/* In case the file descriptor is a socket, return a pretty-printed string in *s which describes the peer connected */ +void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l); + +/* Use setsockopt() to tune the recieve and send buffers of TCP sockets */ +int pa_iochannel_socket_set_rcvbuf(pa_iochannel*io, size_t l); +int pa_iochannel_socket_set_sndbuf(pa_iochannel*io, size_t l); + +pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io); + +#endif diff --git a/src/pulsecore/ioline.c b/src/pulsecore/ioline.c new file mode 100644 index 00000000..9c9900f8 --- /dev/null +++ b/src/pulsecore/ioline.c @@ -0,0 +1,394 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "ioline.h" + +#define BUFFER_LIMIT (64*1024) +#define READ_SIZE (1024) + +struct pa_ioline { + pa_iochannel *io; + pa_defer_event *defer_event; + pa_mainloop_api *mainloop; + int ref; + 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)(pa_ioline*io, const char *s, void *userdata); + void *userdata; + + int defer_close; +}; + +static void io_callback(pa_iochannel*io, void *userdata); +static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata); + +pa_ioline* pa_ioline_new(pa_iochannel *io) { + pa_ioline *l; + assert(io); + + l = pa_xnew(pa_ioline, 1); + 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; + l->ref = 1; + + l->mainloop = pa_iochannel_get_mainloop_api(io); + + l->defer_event = l->mainloop->defer_new(l->mainloop, defer_callback, l); + l->mainloop->defer_enable(l->defer_event, 0); + + l->defer_close = 0; + + pa_iochannel_set_callback(io, io_callback, l); + + return l; +} + +static void ioline_free(pa_ioline *l) { + assert(l); + + if (l->io) + pa_iochannel_free(l->io); + + if (l->defer_event) + l->mainloop->defer_free(l->defer_event); + + pa_xfree(l->wbuf); + pa_xfree(l->rbuf); + pa_xfree(l); +} + +void pa_ioline_unref(pa_ioline *l) { + assert(l); + assert(l->ref >= 1); + + if ((--l->ref) <= 0) + ioline_free(l); +} + +pa_ioline* pa_ioline_ref(pa_ioline *l) { + assert(l); + assert(l->ref >= 1); + + l->ref++; + return l; +} + +void pa_ioline_close(pa_ioline *l) { + assert(l); + assert(l->ref >= 1); + + l->dead = 1; + + if (l->io) { + pa_iochannel_free(l->io); + l->io = NULL; + } + + if (l->defer_event) { + l->mainloop->defer_free(l->defer_event); + l->defer_event = NULL; + } + + if (l->callback) + l->callback = NULL; +} + +void pa_ioline_puts(pa_ioline *l, const char *c) { + size_t len; + + assert(l); + assert(l->ref >= 1); + assert(c); + + if (l->dead) + return; + + len = strlen(c); + if (len > BUFFER_LIMIT - l->wbuf_valid_length) + len = BUFFER_LIMIT - l->wbuf_valid_length; + + if (len) { + assert(l->wbuf_length >= l->wbuf_valid_length); + + /* In case the allocated buffer is too small, enlarge it. */ + if (l->wbuf_valid_length + len > l->wbuf_length) { + size_t n = l->wbuf_valid_length+len; + char *new = pa_xmalloc(n); + if (l->wbuf) { + memcpy(new, l->wbuf+l->wbuf_index, l->wbuf_valid_length); + pa_xfree(l->wbuf); + } + l->wbuf = new; + l->wbuf_length = n; + l->wbuf_index = 0; + } else if (l->wbuf_index + l->wbuf_valid_length + len > l->wbuf_length) { + + /* In case the allocated buffer fits, but the current index is too far from the start, move it to the front. */ + memmove(l->wbuf, l->wbuf+l->wbuf_index, l->wbuf_valid_length); + l->wbuf_index = 0; + } + + assert(l->wbuf_index + l->wbuf_valid_length + len <= l->wbuf_length); + + /* Append the new string */ + memcpy(l->wbuf + l->wbuf_index + l->wbuf_valid_length, c, len); + l->wbuf_valid_length += len; + + l->mainloop->defer_enable(l->defer_event, 1); + } +} + +void pa_ioline_set_callback(pa_ioline*l, void (*callback)(pa_ioline*io, const char *s, void *userdata), void *userdata) { + assert(l); + assert(l->ref >= 1); + + l->callback = callback; + l->userdata = userdata; +} + +static void failure(pa_ioline *l, int process_leftover) { + assert(l); + assert(l->ref >= 1); + assert(!l->dead); + + if (process_leftover && l->rbuf_valid_length > 0) { + /* Pass the last missing bit to the client */ + + if (l->callback) { + char *p = pa_xstrndup(l->rbuf+l->rbuf_index, l->rbuf_valid_length); + l->callback(l, p, l->userdata); + pa_xfree(p); + } + } + + if (l->callback) { + l->callback(l, NULL, l->userdata); + l->callback = NULL; + } + + pa_ioline_close(l); +} + +static void scan_for_lines(pa_ioline *l, size_t skip) { + assert(l && l->ref >= 1 && skip < l->rbuf_valid_length); + + while (!l->dead && l->rbuf_valid_length > skip) { + char *e, *p; + size_t m; + + if (!(e = memchr(l->rbuf + l->rbuf_index + skip, '\n', l->rbuf_valid_length - skip))) + break; + + *e = 0; + + p = l->rbuf + l->rbuf_index; + m = strlen(p); + + l->rbuf_index += m+1; + l->rbuf_valid_length -= m+1; + + /* A shortcut for the next time */ + if (l->rbuf_valid_length == 0) + l->rbuf_index = 0; + + if (l->callback) + l->callback(l, p, l->userdata); + + skip = 0; + } + + /* If the buffer became too large and still no newline was found, drop it. */ + if (l->rbuf_valid_length >= BUFFER_LIMIT) + l->rbuf_index = l->rbuf_valid_length = 0; +} + +static int do_write(pa_ioline *l); + +static int do_read(pa_ioline *l) { + assert(l && l->ref >= 1); + + while (!l->dead && pa_iochannel_is_readable(l->io)) { + ssize_t r; + size_t len; + + len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length; + + /* Check if we have to enlarge the read buffer */ + 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) { + /* The current buffer is large enough, let's just move the data to the front */ + if (l->rbuf_valid_length) + memmove(l->rbuf, l->rbuf+l->rbuf_index, l->rbuf_valid_length); + } else { + /* Enlarge the buffer */ + char *new = pa_xmalloc(n); + if (l->rbuf_valid_length) + memcpy(new, l->rbuf+l->rbuf_index, l->rbuf_valid_length); + pa_xfree(l->rbuf); + l->rbuf = new; + l->rbuf_length = n; + } + + l->rbuf_index = 0; + } + + len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length; + + assert(len >= READ_SIZE); + + /* Read some data */ + if ((r = pa_iochannel_read(l->io, l->rbuf+l->rbuf_index+l->rbuf_valid_length, len)) <= 0) { + if (r < 0) { + pa_log(__FILE__": read(): %s", pa_cstrerror(errno)); + failure(l, 0); + } else + failure(l, 1); + + return -1; + } + + l->rbuf_valid_length += r; + + /* Look if a line has been terminated in the newly read data */ + scan_for_lines(l, l->rbuf_valid_length - r); + } + + return 0; +} + +/* Try to flush the buffer */ +static int do_write(pa_ioline *l) { + ssize_t r; + assert(l && l->ref >= 1); + + while (!l->dead && pa_iochannel_is_writable(l->io) && l->wbuf_valid_length) { + + if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0) { + pa_log(__FILE__": write(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + failure(l, 0); + return -1; + } + + l->wbuf_index += r; + l->wbuf_valid_length -= r; + + /* A shortcut for the next time */ + if (l->wbuf_valid_length == 0) + l->wbuf_index = 0; + } + + return 0; +} + +/* Try to flush read/write data */ +static void do_work(pa_ioline *l) { + assert(l); + assert(l->ref >= 1); + + pa_ioline_ref(l); + + l->mainloop->defer_enable(l->defer_event, 0); + + if (!l->dead) + do_read(l); + + if (!l->dead) + do_write(l); + + if (l->defer_close && !l->wbuf_valid_length) + failure(l, 1); + + pa_ioline_unref(l); +} + +static void io_callback(pa_iochannel*io, void *userdata) { + pa_ioline *l = userdata; + assert(io && l && l->ref >= 1); + + do_work(l); +} + +static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata) { + pa_ioline *l = userdata; + assert(l && l->ref >= 1 && l->mainloop == m && l->defer_event == e); + + do_work(l); +} + +void pa_ioline_defer_close(pa_ioline *l) { + assert(l); + assert(l->ref >= 1); + + l->defer_close = 1; + + if (!l->wbuf_valid_length) + l->mainloop->defer_enable(l->defer_event, 1); +} + +void pa_ioline_printf(pa_ioline *l, const char *format, ...) { + char *t; + va_list ap; + + assert(l); + assert(l->ref >= 1); + + va_start(ap, format); + t = pa_vsprintf_malloc(format, ap); + va_end(ap); + + pa_ioline_puts(l, t); + pa_xfree(t); +} diff --git a/src/pulsecore/ioline.h b/src/pulsecore/ioline.h new file mode 100644 index 00000000..e736e2b3 --- /dev/null +++ b/src/pulsecore/ioline.h @@ -0,0 +1,51 @@ +#ifndef fooiolinehfoo +#define fooiolinehfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/* An ioline wraps an iochannel for line based communication. A + * callback function is called whenever a new line has been recieved + * from the client */ + +typedef struct pa_ioline pa_ioline; + +pa_ioline* pa_ioline_new(pa_iochannel *io); +void pa_ioline_unref(pa_ioline *l); +pa_ioline* pa_ioline_ref(pa_ioline *l); +void pa_ioline_close(pa_ioline *l); + +/* Write a string to the channel */ +void pa_ioline_puts(pa_ioline *s, const char *c); + +/* Write a string to the channel */ +void pa_ioline_printf(pa_ioline *s, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); + +/* Set the callback function that is called for every recieved line */ +void pa_ioline_set_callback(pa_ioline*io, void (*callback)(pa_ioline*io, const char *s, void *userdata), void *userdata); + +/* Make sure to close the ioline object as soon as the send buffer is emptied */ +void pa_ioline_defer_close(pa_ioline *io); + +#endif diff --git a/src/pulsecore/llist.h b/src/pulsecore/llist.h new file mode 100644 index 00000000..bf3c150a --- /dev/null +++ b/src/pulsecore/llist.h @@ -0,0 +1,79 @@ +#ifndef foollistfoo +#define foollistfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* Some macros for maintaining doubly linked lists */ + +/* The head of the linked list. Use this in the structure that shall + * contain the head of the linked list */ +#define PA_LLIST_HEAD(t,name) t *name + +/* The pointers in the linked list's items. Use this in the item structure */ +#define PA_LLIST_FIELDS(t) t *next, *prev + +/* Initialize the list's head */ +#define PA_LLIST_HEAD_INIT(t,item) do { (item) = NULL; } while(0) + +/* Initialize a list item */ +#define PA_LLIST_INIT(t,item) do { \ + t *_item = (item); \ + assert(_item); \ + _item->prev = _item->next = NULL; \ + } while(0) + +/* Prepend an item to the list */ +#define PA_LLIST_PREPEND(t,head,item) do { \ + t **_head = &(head), *_item = (item); \ + assert(_item); \ + if ((_item->next = *_head)) \ + _item->next->prev = _item; \ + _item->prev = NULL; \ + *_head = _item; \ + } while (0) + +/* Remove an item from the list */ +#define PA_LLIST_REMOVE(t,head,item) do { \ + t **_head = &(head), *_item = (item); \ + assert(_item); \ + if (_item->next) \ + _item->next->prev = _item->prev; \ + if (_item->prev) \ + _item->prev->next = _item->next; \ + else {\ + assert(*_head == _item); \ + *_head = _item->next; \ + } \ + _item->next = _item->prev = NULL; \ + } while(0) + +#define PA_LLIST_FIND_HEAD(t,item,head) \ +do { \ + t **_head = (head), *_item = (item); \ + *_head = _item; \ + assert(_head); \ + while ((*_head)->prev) \ + *_head = (*_head)->prev; \ +} while (0) \ + + +#endif diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c new file mode 100644 index 00000000..df5b140a --- /dev/null +++ b/src/pulsecore/log.c @@ -0,0 +1,211 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#ifdef HAVE_SYSLOG_H +#include +#endif + +#include +#include + +#include + +#include "log.h" + +#define ENV_LOGLEVEL "POLYP_LOG" + +static char *log_ident = NULL, *log_ident_local = NULL; +static pa_log_target_t log_target = PA_LOG_STDERR; +static void (*user_log_func)(pa_log_level_t l, const char *s) = NULL; +static pa_log_level_t maximal_level = PA_LOG_NOTICE; + +#ifdef HAVE_SYSLOG_H +static const int level_to_syslog[] = { + [PA_LOG_ERROR] = LOG_ERR, + [PA_LOG_WARN] = LOG_WARNING, + [PA_LOG_NOTICE] = LOG_NOTICE, + [PA_LOG_INFO] = LOG_INFO, + [PA_LOG_DEBUG] = LOG_DEBUG +}; +#endif + +void pa_log_set_ident(const char *p) { + if (log_ident) + pa_xfree(log_ident); + if (log_ident_local) + pa_xfree(log_ident_local); + + log_ident = pa_xstrdup(p); + log_ident_local = pa_utf8_to_locale(log_ident); + if (!log_ident_local) + log_ident_local = pa_xstrdup(log_ident); +} + +void pa_log_set_maximal_level(pa_log_level_t l) { + assert(l < PA_LOG_LEVEL_MAX); + maximal_level = l; +} + +void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t l, const char*s)) { + assert(t == PA_LOG_USER || !func); + log_target = t; + user_log_func = func; +} + +void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { + const char *e; + char *text, *t, *n; + + assert(level < PA_LOG_LEVEL_MAX); + + if ((e = getenv(ENV_LOGLEVEL))) + maximal_level = atoi(e); + + if (level > maximal_level) + return; + + text = pa_vsprintf_malloc(format, ap); + + if (!pa_utf8_valid(text)) + pa_log_level(level, __FILE__": invalid UTF-8 string following below:"); + + for (t = text; t; t = n) { + if ((n = strchr(t, '\n'))) { + *n = 0; + n++; + } + + if (!*t) + continue; + + switch (log_target) { + case PA_LOG_STDERR: { + const char *prefix = "", *suffix = ""; + char *local_t; + +#ifndef OS_IS_WIN32 + /* Yes indeed. Useless, but fun! */ + if (isatty(STDERR_FILENO)) { + if (level <= PA_LOG_ERROR) { + prefix = "\x1B[1;31m"; + suffix = "\x1B[0m"; + } else if (level <= PA_LOG_WARN) { + prefix = "\x1B[1m"; + suffix = "\x1B[0m"; + } + } +#endif + + local_t = pa_utf8_to_locale(t); + if (!local_t) + fprintf(stderr, "%s%s%s\n", prefix, t, suffix); + else { + fprintf(stderr, "%s%s%s\n", prefix, local_t, suffix); + pa_xfree(local_t); + } + + break; + } + +#ifdef HAVE_SYSLOG_H + case PA_LOG_SYSLOG: { + char *local_t; + + openlog(log_ident_local ? log_ident_local : "???", LOG_PID, LOG_USER); + + local_t = pa_utf8_to_locale(t); + if (!local_t) + syslog(level_to_syslog[level], "%s", t); + else { + syslog(level_to_syslog[level], "%s", local_t); + pa_xfree(local_t); + } + + closelog(); + break; + } +#endif + + case PA_LOG_USER: + user_log_func(level, t); + break; + + case PA_LOG_NULL: + default: + break; + } + } + + pa_xfree(text); + +} + +void pa_log_level(pa_log_level_t level, const char *format, ...) { + va_list ap; + va_start(ap, format); + pa_log_levelv(level, format, ap); + va_end(ap); +} + +void pa_log_debug(const char *format, ...) { + va_list ap; + va_start(ap, format); + pa_log_levelv(PA_LOG_DEBUG, format, ap); + va_end(ap); +} + +void pa_log_info(const char *format, ...) { + va_list ap; + va_start(ap, format); + pa_log_levelv(PA_LOG_INFO, format, ap); + va_end(ap); +} + +void pa_log_notice(const char *format, ...) { + va_list ap; + va_start(ap, format); + pa_log_levelv(PA_LOG_INFO, format, ap); + va_end(ap); +} + +void pa_log_warn(const char *format, ...) { + va_list ap; + va_start(ap, format); + pa_log_levelv(PA_LOG_WARN, format, ap); + va_end(ap); +} + +void pa_log_error(const char *format, ...) { + va_list ap; + va_start(ap, format); + pa_log_levelv(PA_LOG_ERROR, format, ap); + va_end(ap); +} diff --git a/src/pulsecore/log.h b/src/pulsecore/log.h new file mode 100644 index 00000000..7bf4e407 --- /dev/null +++ b/src/pulsecore/log.h @@ -0,0 +1,69 @@ +#ifndef foologhfoo +#define foologhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/* A simple logging subsystem */ + +/* Where to log to */ +typedef enum pa_log_target { + PA_LOG_STDERR, /* default */ + PA_LOG_SYSLOG, + PA_LOG_USER, /* to user specified function */ + PA_LOG_NULL /* to /dev/null */ +} pa_log_target_t; + +typedef enum pa_log_level { + PA_LOG_ERROR = 0, /* Error messages */ + PA_LOG_WARN = 1, /* Warning messages */ + PA_LOG_NOTICE = 2, /* Notice messages */ + PA_LOG_INFO = 3, /* Info messages */ + PA_LOG_DEBUG = 4, /* debug message */ + PA_LOG_LEVEL_MAX +} pa_log_level_t; + +/* Set an identification for the current daemon. Used when logging to syslog. */ +void pa_log_set_ident(const char *p); + +/* Set another log target. If t is PA_LOG_USER you may specify a function that is called every log string */ +void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t t, const char*s)); + +/* Minimal log level */ +void pa_log_set_maximal_level(pa_log_level_t l); + +/* Do a log line */ +void pa_log_debug(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +void pa_log_info(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +void pa_log_notice(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +void pa_log_warn(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +void pa_log_error(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); + +void pa_log_level(pa_log_level_t level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); + +void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap); + +#define pa_log pa_log_error + +#endif diff --git a/src/pulsecore/mcalign.c b/src/pulsecore/mcalign.c new file mode 100644 index 00000000..8283a7a0 --- /dev/null +++ b/src/pulsecore/mcalign.c @@ -0,0 +1,206 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include "mcalign.h" + +struct pa_mcalign { + size_t base; + pa_memchunk leftover, current; + pa_memblock_stat *memblock_stat; +}; + +pa_mcalign *pa_mcalign_new(size_t base, pa_memblock_stat *s) { + pa_mcalign *m; + assert(base); + + m = pa_xnew(pa_mcalign, 1); + + m->base = base; + pa_memchunk_reset(&m->leftover); + pa_memchunk_reset(&m->current); + m->memblock_stat = s; + + return m; +} + +void pa_mcalign_free(pa_mcalign *m) { + assert(m); + + if (m->leftover.memblock) + pa_memblock_unref(m->leftover.memblock); + + if (m->current.memblock) + pa_memblock_unref(m->current.memblock); + + pa_xfree(m); +} + +void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { + assert(m); + assert(c); + + assert(c->memblock); + assert(c->length > 0); + + assert(!m->current.memblock); + + /* Append to the leftover memory block */ + if (m->leftover.memblock) { + + /* Try to merge */ + if (m->leftover.memblock == c->memblock && + m->leftover.index + m->leftover.length == c->index) { + + /* Merge */ + m->leftover.length += c->length; + + /* If the new chunk is larger than m->base, move it to current */ + if (m->leftover.length >= m->base) { + m->current = m->leftover; + pa_memchunk_reset(&m->leftover); + } + + } else { + size_t l; + + /* We have to copy */ + assert(m->leftover.length < m->base); + l = m->base - m->leftover.length; + + if (l > c->length) + l = c->length; + + /* Can we use the current block? */ + pa_memchunk_make_writable(&m->leftover, m->memblock_stat, m->base); + + memcpy((uint8_t*) m->leftover.memblock->data + m->leftover.index + m->leftover.length, (uint8_t*) c->memblock->data + c->index, l); + m->leftover.length += l; + + assert(m->leftover.length <= m->base && m->leftover.length <= m->leftover.memblock->length); + + if (c->length > l) { + /* Save the remainder of the memory block */ + m->current = *c; + m->current.index += l; + m->current.length -= l; + pa_memblock_ref(m->current.memblock); + } + } + } else { + /* Nothing to merge or copy, just store it */ + + if (c->length >= m->base) + m->current = *c; + else + m->leftover = *c; + + pa_memblock_ref(c->memblock); + } +} + +int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) { + assert(m); + assert(c); + + /* First test if there's a leftover memory block available */ + if (m->leftover.memblock) { + assert(m->leftover.length > 0 && m->leftover.length <= m->base); + + /* The leftover memory block is not yet complete */ + if (m->leftover.length < m->base) + return -1; + + /* Return the leftover memory block */ + *c = m->leftover; + pa_memchunk_reset(&m->leftover); + + /* If the current memblock is too small move it the leftover */ + if (m->current.memblock && m->current.length < m->base) { + m->leftover = m->current; + pa_memchunk_reset(&m->current); + } + + return 0; + } + + /* Now let's see if there is other data available */ + if (m->current.memblock) { + size_t l; + assert(m->current.length >= m->base); + + /* The length of the returned memory block */ + l = m->current.length; + l /= m->base; + l *= m->base; + assert(l > 0); + + /* Prepare the returned block */ + *c = m->current; + pa_memblock_ref(c->memblock); + c->length = l; + + /* Drop that from the current memory block */ + assert(l <= m->current.length); + m->current.index += l; + m->current.length -= l; + + /* In case the whole block was dropped ... */ + if (m->current.length == 0) + pa_memblock_unref(m->current.memblock); + else { + /* Move the raimainder to leftover */ + assert(m->current.length < m->base && !m->leftover.memblock); + + m->leftover = m->current; + } + + pa_memchunk_reset(&m->current); + + return 0; + } + + /* There's simply nothing */ + return -1; + +} + +size_t pa_mcalign_csize(pa_mcalign *m, size_t l) { + assert(m); + assert(l > 0); + + assert(!m->current.memblock); + + if (m->leftover.memblock) + l += m->leftover.length; + + return (l/m->base)*m->base; +} diff --git a/src/pulsecore/mcalign.h b/src/pulsecore/mcalign.h new file mode 100644 index 00000000..80e37499 --- /dev/null +++ b/src/pulsecore/mcalign.h @@ -0,0 +1,80 @@ +#ifndef foomcalignhfoo +#define foomcalignhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/* An alignment object, used for aligning memchunks to multiples of + * the frame size. */ + +/* Method of operation: the user creates a new mcalign object by + * calling pa_mcalign_new() with the appropriate aligning + * granularity. After that he may call pa_mcalign_push() for an input + * memchunk. After exactly one memchunk the user has to call + * pa_mcalign_pop() until it returns -1. If pa_mcalign_pop() returns + * 0, the memchunk *c is valid and aligned to the granularity. Some + * pseudocode illustrating this: + * + * pa_mcalign *a = pa_mcalign_new(4, NULL); + * + * for (;;) { + * pa_memchunk input; + * + * ... fill input ... + * + * pa_mcalign_push(m, &input); + * pa_memblock_unref(input.memblock); + * + * for (;;) { + * pa_memchunk output; + * + * if (pa_mcalign_pop(m, &output) < 0) + * break; + * + * ... consume output ... + * + * pa_memblock_unref(output.memblock); + * } + * } + * + * pa_memchunk_free(a); + * */ + +typedef struct pa_mcalign pa_mcalign; + +pa_mcalign *pa_mcalign_new(size_t base, pa_memblock_stat *s); +void pa_mcalign_free(pa_mcalign *m); + +/* Push a new memchunk into the aligner. The caller of this routine + * has to free the memchunk by himself. */ +void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c); + +/* Pop a new memchunk from the aligner. Returns 0 when sucessful, + * nonzero otherwise. */ +int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c); + +/* If we pass l bytes in now, how many bytes would we get out? */ +size_t pa_mcalign_csize(pa_mcalign *m, size_t l); + +#endif diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c new file mode 100644 index 00000000..36de17fb --- /dev/null +++ b/src/pulsecore/memblock.c @@ -0,0 +1,173 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include "memblock.h" + +static void stat_add(pa_memblock*m, pa_memblock_stat *s) { + assert(m); + + if (!s) { + m->stat = NULL; + return; + } + + m->stat = pa_memblock_stat_ref(s); + s->total++; + s->allocated++; + s->total_size += m->length; + s->allocated_size += m->length; +} + +static void stat_remove(pa_memblock *m) { + assert(m); + + if (!m->stat) + return; + + m->stat->total--; + m->stat->total_size -= m->length; + + pa_memblock_stat_unref(m->stat); + m->stat = NULL; +} + +pa_memblock *pa_memblock_new(size_t length, pa_memblock_stat*s) { + pa_memblock *b = pa_xmalloc(sizeof(pa_memblock)+length); + b->type = PA_MEMBLOCK_APPENDED; + b->ref = 1; + b->length = length; + b->data = b+1; + b->free_cb = NULL; + b->read_only = 0; + stat_add(b, s); + return b; +} + +pa_memblock *pa_memblock_new_dynamic(void *d, size_t length, pa_memblock_stat*s) { + pa_memblock *b = pa_xmalloc(sizeof(pa_memblock)); + b->type = PA_MEMBLOCK_DYNAMIC; + b->ref = 1; + b->length = length; + b->data = d; + b->free_cb = NULL; + b->read_only = 0; + stat_add(b, s); + return b; +} + +pa_memblock *pa_memblock_new_fixed(void *d, size_t length, int read_only, pa_memblock_stat*s) { + pa_memblock *b = pa_xmalloc(sizeof(pa_memblock)); + b->type = PA_MEMBLOCK_FIXED; + b->ref = 1; + b->length = length; + b->data = d; + b->free_cb = NULL; + b->read_only = read_only; + stat_add(b, s); + return b; +} + +pa_memblock *pa_memblock_new_user(void *d, size_t length, void (*free_cb)(void *p), int read_only, pa_memblock_stat*s) { + pa_memblock *b; + assert(d && length && free_cb); + b = pa_xmalloc(sizeof(pa_memblock)); + b->type = PA_MEMBLOCK_USER; + b->ref = 1; + b->length = length; + b->data = d; + b->free_cb = free_cb; + b->read_only = read_only; + stat_add(b, s); + return b; +} + +pa_memblock* pa_memblock_ref(pa_memblock*b) { + assert(b); + assert(b->ref >= 1); + + b->ref++; + return b; +} + +void pa_memblock_unref(pa_memblock*b) { + assert(b); + assert(b->ref >= 1); + + if ((--(b->ref)) == 0) { + stat_remove(b); + + if (b->type == PA_MEMBLOCK_USER) { + assert(b->free_cb); + b->free_cb(b->data); + } else if (b->type == PA_MEMBLOCK_DYNAMIC) + pa_xfree(b->data); + + pa_xfree(b); + } +} + +void pa_memblock_unref_fixed(pa_memblock *b) { + assert(b && b->ref >= 1 && b->type == PA_MEMBLOCK_FIXED); + + if (b->ref == 1) + pa_memblock_unref(b); + else { + b->data = pa_xmemdup(b->data, b->length); + b->type = PA_MEMBLOCK_DYNAMIC; + b->ref--; + } +} + +pa_memblock_stat* pa_memblock_stat_new(void) { + pa_memblock_stat *s; + + s = pa_xmalloc(sizeof(pa_memblock_stat)); + s->ref = 1; + s->total = s->total_size = s->allocated = s->allocated_size = 0; + + return s; +} + +void pa_memblock_stat_unref(pa_memblock_stat *s) { + assert(s && s->ref >= 1); + + if (!(--(s->ref))) { + assert(!s->total); + pa_xfree(s); + } +} + +pa_memblock_stat * pa_memblock_stat_ref(pa_memblock_stat *s) { + assert(s); + s->ref++; + return s; +} diff --git a/src/pulsecore/memblock.h b/src/pulsecore/memblock.h new file mode 100644 index 00000000..f8545836 --- /dev/null +++ b/src/pulsecore/memblock.h @@ -0,0 +1,86 @@ +#ifndef foomemblockhfoo +#define foomemblockhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/* A pa_memblock is a reference counted memory block. Polypaudio + * passed references to pa_memblocks around instead of copying + * data. See pa_memchunk for a structure that describes parts of + * memory blocks. */ + +/* The type of memory this block points to */ +typedef enum pa_memblock_type { + PA_MEMBLOCK_FIXED, /* data is a pointer to fixed memory that needs not to be freed */ + PA_MEMBLOCK_APPENDED, /* The most common kind: the data is appended to the memory block */ + PA_MEMBLOCK_DYNAMIC, /* data is a pointer to some memory allocated with pa_xmalloc() */ + PA_MEMBLOCK_USER /* User supplied memory, to be freed with free_cb */ +} pa_memblock_type_t; + +/* A structure of keeping memory block statistics */ +/* Maintains statistics about memory blocks */ +typedef struct pa_memblock_stat { + int ref; + unsigned total; + unsigned total_size; + unsigned allocated; + unsigned allocated_size; +} pa_memblock_stat; + +typedef struct pa_memblock { + pa_memblock_type_t type; + unsigned ref; /* the reference counter */ + int read_only; /* boolean */ + size_t length; + void *data; + void (*free_cb)(void *p); /* If type == PA_MEMBLOCK_USER this points to a function for freeing this memory block */ + pa_memblock_stat *stat; +} pa_memblock; + +/* Allocate a new memory block of type PA_MEMBLOCK_APPENDED */ +pa_memblock *pa_memblock_new(size_t length, pa_memblock_stat*s); + +/* Allocate a new memory block of type PA_MEMBLOCK_DYNAMIC. The pointer data is to be maintained be the memory block */ +pa_memblock *pa_memblock_new_dynamic(void *data, size_t length, pa_memblock_stat*s); + +/* Allocate a new memory block of type PA_MEMBLOCK_FIXED */ +pa_memblock *pa_memblock_new_fixed(void *data, size_t length, int read_only, pa_memblock_stat*s); + +/* Allocate a new memory block of type PA_MEMBLOCK_USER */ +pa_memblock *pa_memblock_new_user(void *data, size_t length, void (*free_cb)(void *p), int read_only, pa_memblock_stat*s); + +void pa_memblock_unref(pa_memblock*b); +pa_memblock* pa_memblock_ref(pa_memblock*b); + +/* This special unref function has to be called by the owner of the +memory of a static memory block when he wants to release all +references to the memory. This causes the memory to be copied and +converted into a PA_MEMBLOCK_DYNAMIC type memory block */ +void pa_memblock_unref_fixed(pa_memblock*b); + +pa_memblock_stat* pa_memblock_stat_new(void); +void pa_memblock_stat_unref(pa_memblock_stat *s); +pa_memblock_stat * pa_memblock_stat_ref(pa_memblock_stat *s); + +#endif diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c new file mode 100644 index 00000000..ff199f1b --- /dev/null +++ b/src/pulsecore/memblockq.c @@ -0,0 +1,636 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "memblockq.h" + +struct memblock_list { + struct memblock_list *next, *prev; + int64_t index; + pa_memchunk chunk; +}; + +struct pa_memblockq { + struct memblock_list *blocks, *blocks_tail; + unsigned n_blocks; + size_t maxlength, tlength, base, prebuf, minreq; + int64_t read_index, write_index; + enum { PREBUF, RUNNING } state; + pa_memblock_stat *memblock_stat; + pa_memblock *silence; + pa_mcalign *mcalign; +}; + +pa_memblockq* pa_memblockq_new( + int64_t idx, + size_t maxlength, + size_t tlength, + size_t base, + size_t prebuf, + size_t minreq, + pa_memblock *silence, + pa_memblock_stat *s) { + + pa_memblockq* bq; + + assert(base > 0); + assert(maxlength >= base); + + bq = pa_xnew(pa_memblockq, 1); + bq->blocks = bq->blocks_tail = NULL; + bq->n_blocks = 0; + + bq->base = base; + bq->read_index = bq->write_index = idx; + bq->memblock_stat = s; + + pa_log_debug(__FILE__": memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", + (unsigned long)maxlength, (unsigned long)tlength, (unsigned long)base, (unsigned long)prebuf, (unsigned long)minreq); + + bq->maxlength = ((maxlength+base-1)/base)*base; + assert(bq->maxlength >= base); + + bq->tlength = ((tlength+base-1)/base)*base; + if (!bq->tlength || bq->tlength >= bq->maxlength) + bq->tlength = bq->maxlength; + + bq->prebuf = (prebuf == (size_t) -1) ? bq->tlength/2 : prebuf; + bq->prebuf = ((bq->prebuf+base-1)/base)*base; + if (bq->prebuf > bq->maxlength) + bq->prebuf = bq->maxlength; + + bq->minreq = (minreq/base)*base; + + if (bq->minreq > bq->tlength - bq->prebuf) + bq->minreq = bq->tlength - bq->prebuf; + + if (!bq->minreq) + bq->minreq = 1; + + pa_log_debug(__FILE__": memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", + (unsigned long)bq->maxlength, (unsigned long)bq->tlength, (unsigned long)bq->base, (unsigned long)bq->prebuf, (unsigned long)bq->minreq); + + bq->state = bq->prebuf ? PREBUF : RUNNING; + bq->silence = silence ? pa_memblock_ref(silence) : NULL; + bq->mcalign = NULL; + + return bq; +} + +void pa_memblockq_free(pa_memblockq* bq) { + assert(bq); + + pa_memblockq_flush(bq); + + if (bq->silence) + pa_memblock_unref(bq->silence); + + if (bq->mcalign) + pa_mcalign_free(bq->mcalign); + + pa_xfree(bq); +} + +static void drop_block(pa_memblockq *bq, struct memblock_list *q) { + assert(bq); + assert(q); + + assert(bq->n_blocks >= 1); + + if (q->prev) + q->prev->next = q->next; + else + bq->blocks = q->next; + + if (q->next) + q->next->prev = q->prev; + else + bq->blocks_tail = q->prev; + + pa_memblock_unref(q->chunk.memblock); + pa_xfree(q); + + bq->n_blocks--; +} + +static int can_push(pa_memblockq *bq, size_t l) { + int64_t end; + + assert(bq); + + if (bq->read_index > bq->write_index) { + size_t d = bq->read_index - bq->write_index; + + if (l > d) + l -= d; + else + return 1; + } + + end = bq->blocks_tail ? bq->blocks_tail->index + bq->blocks_tail->chunk.length : 0; + + /* Make sure that the list doesn't get too long */ + if (bq->write_index + (int64_t)l > end) + if (bq->write_index + l - bq->read_index > bq->maxlength) + return 0; + + return 1; +} + +int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { + + struct memblock_list *q, *n; + pa_memchunk chunk; + + assert(bq); + assert(uchunk); + assert(uchunk->memblock); + assert(uchunk->length > 0); + assert(uchunk->index + uchunk->length <= uchunk->memblock->length); + + if (uchunk->length % bq->base) + return -1; + + if (!can_push(bq, uchunk->length)) + return -1; + + chunk = *uchunk; + + if (bq->read_index > bq->write_index) { + + /* We currently have a buffer underflow, we need to drop some + * incoming data */ + + size_t d = bq->read_index - bq->write_index; + + if (chunk.length > d) { + chunk.index += d; + chunk.length -= d; + bq->write_index = bq->read_index; + } else { + /* We drop the incoming data completely */ + bq->write_index += chunk.length; + return 0; + } + } + + /* We go from back to front to look for the right place to add + * this new entry. Drop data we will overwrite on the way */ + + q = bq->blocks_tail; + while (q) { + + if (bq->write_index >= q->index + (int64_t)q->chunk.length) + /* We found the entry where we need to place the new entry immediately after */ + break; + else if (bq->write_index + (int64_t)chunk.length <= q->index) { + /* This entry isn't touched at all, let's skip it */ + q = q->prev; + } else if (bq->write_index <= q->index && + bq->write_index + chunk.length >= q->index + q->chunk.length) { + + /* This entry is fully replaced by the new entry, so let's drop it */ + + struct memblock_list *p; + p = q; + q = q->prev; + drop_block(bq, p); + } else if (bq->write_index >= q->index) { + /* The write index points into this memblock, so let's + * truncate or split it */ + + if (bq->write_index + chunk.length < q->index + q->chunk.length) { + + /* We need to save the end of this memchunk */ + struct memblock_list *p; + size_t d; + + /* Create a new list entry for the end of thie memchunk */ + p = pa_xnew(struct memblock_list, 1); + p->chunk = q->chunk; + pa_memblock_ref(p->chunk.memblock); + + /* Calculate offset */ + d = bq->write_index + chunk.length - q->index; + assert(d > 0); + + /* Drop it from the new entry */ + p->index = q->index + d; + p->chunk.length -= d; + + /* Add it to the list */ + p->prev = q; + if ((p->next = q->next)) + q->next->prev = p; + else + bq->blocks_tail = p; + q->next = p; + + bq->n_blocks++; + } + + /* Truncate the chunk */ + if (!(q->chunk.length = bq->write_index - q->index)) { + struct memblock_list *p; + p = q; + q = q->prev; + drop_block(bq, p); + } + + /* We had to truncate this block, hence we're now at the right position */ + break; + } else { + size_t d; + + assert(bq->write_index + (int64_t)chunk.length > q->index && + bq->write_index + (int64_t)chunk.length < q->index + (int64_t)q->chunk.length && + bq->write_index < q->index); + + /* The job overwrites the current entry at the end, so let's drop the beginning of this entry */ + + d = bq->write_index + chunk.length - q->index; + q->index += d; + q->chunk.index += d; + q->chunk.length -= d; + + q = q->prev; + } + + } + + if (q) { + assert(bq->write_index >= q->index + (int64_t)q->chunk.length); + assert(!q->next || (bq->write_index + (int64_t)chunk.length <= q->next->index)); + + /* Try to merge memory blocks */ + + if (q->chunk.memblock == chunk.memblock && + q->chunk.index + (int64_t)q->chunk.length == chunk.index && + bq->write_index == q->index + (int64_t)q->chunk.length) { + + q->chunk.length += chunk.length; + bq->write_index += chunk.length; + return 0; + } + } else + assert(!bq->blocks || (bq->write_index + (int64_t)chunk.length <= bq->blocks->index)); + + + n = pa_xnew(struct memblock_list, 1); + n->chunk = chunk; + pa_memblock_ref(n->chunk.memblock); + n->index = bq->write_index; + bq->write_index += n->chunk.length; + + n->next = q ? q->next : bq->blocks; + n->prev = q; + + if (n->next) + n->next->prev = n; + else + bq->blocks_tail = n; + + if (n->prev) + n->prev->next = n; + else + bq->blocks = n; + + bq->n_blocks++; + return 0; +} + +int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { + assert(bq); + assert(chunk); + + if (bq->state == PREBUF) { + + /* We need to pre-buffer */ + if (pa_memblockq_get_length(bq) < bq->prebuf) + return -1; + + bq->state = RUNNING; + + } else if (bq->prebuf > 0 && bq->read_index >= bq->write_index) { + + /* Buffer underflow protection */ + bq->state = PREBUF; + return -1; + } + + /* Do we need to spit out silence? */ + if (!bq->blocks || bq->blocks->index > bq->read_index) { + + size_t length; + + /* How much silence shall we return? */ + length = bq->blocks ? bq->blocks->index - bq->read_index : 0; + + /* We need to return silence, since no data is yet available */ + if (bq->silence) { + chunk->memblock = pa_memblock_ref(bq->silence); + + if (!length || length > chunk->memblock->length) + length = chunk->memblock->length; + + chunk->length = length; + } else { + chunk->memblock = NULL; + chunk->length = length; + } + + chunk->index = 0; + return 0; + } + + /* Ok, let's pass real data to the caller */ + assert(bq->blocks->index == bq->read_index); + + *chunk = bq->blocks->chunk; + pa_memblock_ref(chunk->memblock); + + return 0; +} + +void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length) { + assert(bq); + assert(length % bq->base == 0); + + assert(!chunk || length <= chunk->length); + + if (chunk) { + + if (bq->blocks && bq->blocks->index == bq->read_index) { + /* The first item in queue is valid */ + + /* Does the chunk match with what the user supplied us? */ + if (memcmp(chunk, &bq->blocks->chunk, sizeof(pa_memchunk)) != 0) + return; + + } else { + size_t l; + + /* The first item in the queue is not yet relevant */ + + assert(!bq->blocks || bq->blocks->index > bq->read_index); + l = bq->blocks ? bq->blocks->index - bq->read_index : 0; + + if (bq->silence) { + + if (!l || l > bq->silence->length) + l = bq->silence->length; + + } + + /* Do the entries still match? */ + if (chunk->index != 0 || chunk->length != l || chunk->memblock != bq->silence) + return; + } + } + + while (length > 0) { + + if (bq->blocks) { + size_t d; + + assert(bq->blocks->index >= bq->read_index); + + d = (size_t) (bq->blocks->index - bq->read_index); + + if (d >= length) { + /* The first block is too far in the future */ + + bq->read_index += length; + break; + } else { + + length -= d; + bq->read_index += d; + } + + assert(bq->blocks->index == bq->read_index); + + if (bq->blocks->chunk.length <= length) { + /* We need to drop the full block */ + + length -= bq->blocks->chunk.length; + bq->read_index += bq->blocks->chunk.length; + + drop_block(bq, bq->blocks); + } else { + /* Only the start of this block needs to be dropped */ + + bq->blocks->chunk.index += length; + bq->blocks->chunk.length -= length; + bq->blocks->index += length; + bq->read_index += length; + break; + } + + } else { + + /* The list is empty, there's nothing we could drop */ + bq->read_index += length; + break; + } + } +} + +int pa_memblockq_is_readable(pa_memblockq *bq) { + assert(bq); + + if (bq->prebuf > 0) { + size_t l = pa_memblockq_get_length(bq); + + if (bq->state == PREBUF && l < bq->prebuf) + return 0; + + if (l <= 0) + return 0; + } + + return 1; +} + +int pa_memblockq_is_writable(pa_memblockq *bq, size_t length) { + assert(bq); + + if (length % bq->base) + return 0; + + return pa_memblockq_get_length(bq) + length <= bq->tlength; +} + +size_t pa_memblockq_get_length(pa_memblockq *bq) { + assert(bq); + + if (bq->write_index <= bq->read_index) + return 0; + + return (size_t) (bq->write_index - bq->read_index); +} + +size_t pa_memblockq_missing(pa_memblockq *bq) { + size_t l; + assert(bq); + + if ((l = pa_memblockq_get_length(bq)) >= bq->tlength) + return 0; + + l = bq->tlength - l; + return (l >= bq->minreq) ? l : 0; +} + +size_t pa_memblockq_get_minreq(pa_memblockq *bq) { + assert(bq); + + return bq->minreq; +} + +void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek) { + assert(bq); + + switch (seek) { + case PA_SEEK_RELATIVE: + bq->write_index += offset; + return; + case PA_SEEK_ABSOLUTE: + bq->write_index = offset; + return; + case PA_SEEK_RELATIVE_ON_READ: + bq->write_index = bq->read_index + offset; + return; + case PA_SEEK_RELATIVE_END: + bq->write_index = (bq->blocks_tail ? bq->blocks_tail->index + (int64_t)bq->blocks_tail->chunk.length : bq->read_index) + offset; + return; + } + + assert(0); +} + +void pa_memblockq_flush(pa_memblockq *bq) { + assert(bq); + + while (bq->blocks) + drop_block(bq, bq->blocks); + + assert(bq->n_blocks == 0); + + bq->write_index = bq->read_index; + + pa_memblockq_prebuf_force(bq); +} + +size_t pa_memblockq_get_tlength(pa_memblockq *bq) { + assert(bq); + + return bq->tlength; +} + +int64_t pa_memblockq_get_read_index(pa_memblockq *bq) { + assert(bq); + return bq->read_index; +} + +int64_t pa_memblockq_get_write_index(pa_memblockq *bq) { + assert(bq); + return bq->write_index; +} + +int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk) { + pa_memchunk rchunk; + + assert(bq); + assert(chunk && bq->base); + + if (bq->base == 1) + return pa_memblockq_push(bq, chunk); + + if (!bq->mcalign) + bq->mcalign = pa_mcalign_new(bq->base, bq->memblock_stat); + + if (!can_push(bq, pa_mcalign_csize(bq->mcalign, chunk->length))) + return -1; + + pa_mcalign_push(bq->mcalign, chunk); + + while (pa_mcalign_pop(bq->mcalign, &rchunk) >= 0) { + int r; + r = pa_memblockq_push(bq, &rchunk); + pa_memblock_unref(rchunk.memblock); + + if (r < 0) + return -1; + } + + return 0; +} + +void pa_memblockq_shorten(pa_memblockq *bq, size_t length) { + size_t l; + assert(bq); + + l = pa_memblockq_get_length(bq); + + if (l > length) + pa_memblockq_drop(bq, NULL, l - length); +} + +void pa_memblockq_prebuf_disable(pa_memblockq *bq) { + assert(bq); + + if (bq->state == PREBUF) + bq->state = RUNNING; +} + +void pa_memblockq_prebuf_force(pa_memblockq *bq) { + assert(bq); + + if (bq->state == RUNNING && bq->prebuf > 0) + bq->state = PREBUF; +} + +size_t pa_memblockq_get_maxlength(pa_memblockq *bq) { + assert(bq); + + return bq->maxlength; +} + +size_t pa_memblockq_get_prebuf(pa_memblockq *bq) { + assert(bq); + + return bq->prebuf; +} diff --git a/src/pulsecore/memblockq.h b/src/pulsecore/memblockq.h new file mode 100644 index 00000000..c35b62dd --- /dev/null +++ b/src/pulsecore/memblockq.h @@ -0,0 +1,140 @@ +#ifndef foomemblockqhfoo +#define foomemblockqhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include +#include +#include + +/* A memblockq is a queue of pa_memchunks (yepp, the name is not + * perfect). It is similar to the ring buffers used by most other + * audio software. In contrast to a ring buffer this memblockq data + * type doesn't need to copy any data around, it just maintains + * references to reference counted memory blocks. */ + +typedef struct pa_memblockq pa_memblockq; + + +/* Parameters: + + - idx: start value for both read and write index + + - maxlength: maximum length of queue. If more data is pushed into + the queue, the operation will fail. Must not be 0. + + - tlength: the target length of the queue. Pass 0 for the default. + + - base: a base value for all metrics. Only multiples of this value + are popped from the queue or should be pushed into + it. Must not be 0. + + - prebuf: If the queue runs empty wait until this many bytes are in + queue again before passing the first byte out. If set + to 0 pa_memblockq_pop() will return a silence memblock + if no data is in the queue and will never fail. Pass + (size_t) -1 for the default. + + - minreq: pa_memblockq_missing() will only return values greater + than this value. Pass 0 for the default. + + - silence: return this memblock whzen reading unitialized data +*/ +pa_memblockq* pa_memblockq_new( + int64_t idx, + size_t maxlength, + size_t tlength, + size_t base, + size_t prebuf, + size_t minreq, + pa_memblock *silence, + pa_memblock_stat *s); + +void pa_memblockq_free(pa_memblockq*bq); + +/* Push a new memory chunk into the queue. */ +int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *chunk); + +/* Push a new memory chunk into the queue, but filter it through a + * pa_mcalign object. Don't mix this with pa_memblockq_seek() unless + * you know what you do. */ +int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk); + +/* Return a copy of the next memory chunk in the queue. It is not removed from the queue */ +int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk); + +/* Drop the specified bytes from the queue, but only if the first + * chunk in the queue matches the one passed here. If NULL is passed, + * this check isn't done. */ +void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length); + +/* Test if the pa_memblockq is currently readable, that is, more data than base */ +int pa_memblockq_is_readable(pa_memblockq *bq); + +/* Test if the pa_memblockq is currently writable for the specified amount of bytes */ +int pa_memblockq_is_writable(pa_memblockq *bq, size_t length); + +/* Return the length of the queue in bytes */ +size_t pa_memblockq_get_length(pa_memblockq *bq); + +/* Return how many bytes are missing in queue to the specified fill amount */ +size_t pa_memblockq_missing(pa_memblockq *bq); + +/* Returns the minimal request value */ +size_t pa_memblockq_get_minreq(pa_memblockq *bq); + +/* Manipulate the write pointer */ +void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek); + +/* Set the queue to silence, set write index to read index */ +void pa_memblockq_flush(pa_memblockq *bq); + +/* Get Target length */ +size_t pa_memblockq_get_tlength(pa_memblockq *bq); + +/* Return the current read index */ +int64_t pa_memblockq_get_read_index(pa_memblockq *bq); + +/* Return the current write index */ +int64_t pa_memblockq_get_write_index(pa_memblockq *bq); + +/* Shorten the pa_memblockq to the specified length by dropping data + * at the read end of the queue. The read index is increased until the + * queue has the specified length */ +void pa_memblockq_shorten(pa_memblockq *bq, size_t length); + +/* Ignore prebuf for now */ +void pa_memblockq_prebuf_disable(pa_memblockq *bq); + +/* Force prebuf */ +void pa_memblockq_prebuf_force(pa_memblockq *bq); + +/* Return the maximum length of the queue in bytes */ +size_t pa_memblockq_get_maxlength(pa_memblockq *bq); + +/* Return the prebuffer length in bytes */ +size_t pa_memblockq_get_prebuf(pa_memblockq *bq); + +#endif diff --git a/src/pulsecore/memchunk.c b/src/pulsecore/memchunk.c new file mode 100644 index 00000000..abfc2cab --- /dev/null +++ b/src/pulsecore/memchunk.c @@ -0,0 +1,59 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include "memchunk.h" + +void pa_memchunk_make_writable(pa_memchunk *c, pa_memblock_stat *s, size_t min) { + pa_memblock *n; + size_t l; + assert(c && c->memblock && c->memblock->ref >= 1); + + if (c->memblock->ref == 1 && !c->memblock->read_only && c->memblock->length >= c->index+min) + return; + + l = c->length; + if (l < min) + l = min; + + n = pa_memblock_new(l, s); + memcpy(n->data, (uint8_t*) c->memblock->data + c->index, c->length); + pa_memblock_unref(c->memblock); + c->memblock = n; + c->index = 0; +} + +void pa_memchunk_reset(pa_memchunk *c) { + assert(c); + + c->memblock = NULL; + c->length = c->index = 0; +} diff --git a/src/pulsecore/memchunk.h b/src/pulsecore/memchunk.h new file mode 100644 index 00000000..1b26c2e6 --- /dev/null +++ b/src/pulsecore/memchunk.h @@ -0,0 +1,45 @@ +#ifndef foomemchunkhfoo +#define foomemchunkhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +/* A memchunk describes a part of a memblock. In contrast to the memblock, a + * memchunk is not allocated dynamically or reference counted, instead + * it is usually stored on the stack and copied around */ + +typedef struct pa_memchunk { + pa_memblock *memblock; + size_t index, length; +} pa_memchunk; + +/* Make a memchunk writable, i.e. make sure that the caller may have + * exclusive access to the memblock and it is not read_only. If needed + * the memblock in the structure is replaced by a copy. */ +void pa_memchunk_make_writable(pa_memchunk *c, pa_memblock_stat *s, size_t min); + +/* Invalidate a memchunk. This does not free the cotaining memblock, + * but sets all members to zero. */ +void pa_memchunk_reset(pa_memchunk *c); + +#endif diff --git a/src/pulsecore/modargs.c b/src/pulsecore/modargs.c new file mode 100644 index 00000000..13a48785 --- /dev/null +++ b/src/pulsecore/modargs.c @@ -0,0 +1,310 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "modargs.h" + +struct entry { + char *key, *value; +}; + +static int add_key_value(pa_hashmap *map, char *key, char *value, const char* const valid_keys[]) { + struct entry *e; + assert(map && key && value); + + if (valid_keys) { + const char*const* v; + for (v = valid_keys; *v; v++) + if (strcmp(*v, key) == 0) + break; + + if (!*v) { + pa_xfree(key); + pa_xfree(value); + return -1; + } + } + + e = pa_xmalloc(sizeof(struct entry)); + e->key = key; + e->value = value; + pa_hashmap_put(map, key, e); + return 0; +} + +pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) { + pa_hashmap *map = NULL; + + map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + assert(map); + + if (args) { + enum { WHITESPACE, KEY, VALUE_START, VALUE_SIMPLE, VALUE_DOUBLE_QUOTES, VALUE_TICKS } state; + const char *p, *key, *value; + size_t key_len = 0, value_len = 0; + + key = value = NULL; + state = WHITESPACE; + for (p = args; *p; p++) { + switch (state) { + case WHITESPACE: + if (*p == '=') + goto fail; + else if (!isspace(*p)) { + key = p; + state = KEY; + key_len = 1; + } + break; + case KEY: + if (*p == '=') + state = VALUE_START; + else + key_len++; + break; + case VALUE_START: + if (*p == '\'') { + state = VALUE_TICKS; + value = p+1; + value_len = 0; + } else if (*p == '"') { + state = VALUE_DOUBLE_QUOTES; + value = p+1; + value_len = 0; + } else if (isspace(*p)) { + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0) + goto fail; + state = WHITESPACE; + } else { + state = VALUE_SIMPLE; + value = p; + value_len = 1; + } + break; + case VALUE_SIMPLE: + if (isspace(*p)) { + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) + goto fail; + state = WHITESPACE; + } else + value_len++; + break; + case VALUE_DOUBLE_QUOTES: + if (*p == '"') { + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) + goto fail; + state = WHITESPACE; + } else + value_len++; + break; + case VALUE_TICKS: + if (*p == '\'') { + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) + goto fail; + state = WHITESPACE; + } else + value_len++; + break; + } + } + + if (state == VALUE_START) { + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0) + goto fail; + } else if (state == VALUE_SIMPLE) { + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(value), valid_keys) < 0) + goto fail; + } else if (state != WHITESPACE) + goto fail; + } + + return (pa_modargs*) map; + +fail: + + if (map) + pa_modargs_free((pa_modargs*) map); + + return NULL; +} + + +static void free_func(void *p, PA_GCC_UNUSED void*userdata) { + struct entry *e = p; + assert(e); + pa_xfree(e->key); + pa_xfree(e->value); + pa_xfree(e); +} + +void pa_modargs_free(pa_modargs*ma) { + pa_hashmap *map = (pa_hashmap*) ma; + pa_hashmap_free(map, free_func, NULL); +} + +const char *pa_modargs_get_value(pa_modargs *ma, const char *key, const char *def) { + pa_hashmap *map = (pa_hashmap*) ma; + struct entry*e; + + if (!(e = pa_hashmap_get(map, key))) + return def; + + return e->value; +} + +int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value) { + const char *v; + assert(ma && key && value); + + if (!(v = pa_modargs_get_value(ma, key, NULL))) + return 0; + + if (pa_atou(v, value) < 0) + return -1; + + return 0; +} + +int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value) { + const char *v; + assert(ma && key && value); + + if (!(v = pa_modargs_get_value(ma, key, NULL))) + return 0; + + if (pa_atoi(v, value) < 0) + return -1; + + return 0; +} + +int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value) { + const char *v; + int r; + assert(ma && key && value); + + if (!(v = pa_modargs_get_value(ma, key, NULL))) + return 0; + + if (!*v) + return -1; + + if ((r = pa_parse_boolean(v)) < 0) + return -1; + + *value = r; + return 0; +} + +int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) { + const char *format; + uint32_t channels; + pa_sample_spec ss; + assert(ma && rss); + +/* DEBUG_TRAP;*/ + + ss = *rss; + if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0) + return -1; + + channels = ss.channels; + if ((pa_modargs_get_value_u32(ma, "channels", &channels)) < 0) + return -1; + ss.channels = (uint8_t) channels; + + if ((format = pa_modargs_get_value(ma, "format", NULL))) + if ((ss.format = pa_parse_sample_format(format)) < 0) + return -1; + + if (!pa_sample_spec_valid(&ss)) + return -1; + + *rss = ss; + + return 0; +} + +int pa_modargs_get_channel_map(pa_modargs *ma, pa_channel_map *rmap) { + pa_channel_map map; + const char *cm; + + assert(ma); + assert(rmap); + + map = *rmap; + + if ((cm = pa_modargs_get_value(ma, "channel_map", NULL))) + if (!pa_channel_map_parse(&map, cm)) + return -1; + + if (!pa_channel_map_valid(&map)) + return -1; + + *rmap = map; + return 0; +} + +int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *rss, pa_channel_map *rmap, pa_channel_map_def_t def) { + pa_sample_spec ss; + pa_channel_map map; + + assert(ma); + assert(rss); + assert(rmap); + + ss = *rss; + + if (pa_modargs_get_sample_spec(ma, &ss) < 0) + return -1; + + if (!pa_channel_map_init_auto(&map, ss.channels, def)) + map.channels = 0; + + if (pa_modargs_get_channel_map(ma, &map) < 0) + return -1; + + if (map.channels != ss.channels) + return -1; + + *rmap = map; + *rss = ss; + + return 0; +} diff --git a/src/pulsecore/modargs.h b/src/pulsecore/modargs.h new file mode 100644 index 00000000..730cf396 --- /dev/null +++ b/src/pulsecore/modargs.h @@ -0,0 +1,60 @@ +#ifndef foomodargshfoo +#define foomodargshfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +typedef struct pa_modargs pa_modargs; + +/* A generic parser for module arguments */ + +/* Parse the string args. The NULL-terminated array keys contains all valid arguments. */ +pa_modargs *pa_modargs_new(const char *args, const char* const keys[]); +void pa_modargs_free(pa_modargs*ma); + +/* Return the module argument for the specified name as a string. If + * the argument was not specified, return def instead.*/ +const char *pa_modargs_get_value(pa_modargs *ma, const char *key, const char *def); + +/* Return a module argument as unsigned 32bit value in *value */ +int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value); +int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value); +int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value); + +/* Return sample spec data from the three arguments "rate", "format" and "channels" */ +int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *ss); + +/* Return channel map data from the argument "channel_map" */ +int pa_modargs_get_channel_map(pa_modargs *ma, pa_channel_map *map); + +/* Combination of pa_modargs_get_sample_spec() and +pa_modargs_get_channel_map(). Not always suitable, since this routine +initializes the map parameter based on the channels field of the ss +structure if no channel_map is found, using pa_channel_map_init_auto() */ + +int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *ss, pa_channel_map *map, pa_channel_map_def_t def); + +#endif diff --git a/src/pulsecore/modinfo.c b/src/pulsecore/modinfo.c new file mode 100644 index 00000000..adefdb46 --- /dev/null +++ b/src/pulsecore/modinfo.c @@ -0,0 +1,93 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include +#include + +#include "modinfo.h" + +#define PA_SYMBOL_AUTHOR "pa__get_author" +#define PA_SYMBOL_DESCRIPTION "pa__get_description" +#define PA_SYMBOL_USAGE "pa__get_usage" +#define PA_SYMBOL_VERSION "pa__get_version" + +/* lt_dlsym() violates ISO C, so confide the breakage into this function to + * avoid warnings. */ +typedef void (*fnptr)(void); +static inline fnptr lt_dlsym_fn(lt_dlhandle handle, const char *symbol) { + return (fnptr) (long) lt_dlsym(handle, symbol); +} + +pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl) { + pa_modinfo *i; + const char* (*func)(void); + assert(dl); + + i = pa_xnew0(pa_modinfo, 1); + + if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_AUTHOR))) + i->author = pa_xstrdup(func()); + + if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_DESCRIPTION))) + i->description = pa_xstrdup(func()); + + if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_USAGE))) + i->usage = pa_xstrdup(func()); + + if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_VERSION))) + i->version = pa_xstrdup(func()); + + return i; +} + +pa_modinfo *pa_modinfo_get_by_name(const char *name) { + lt_dlhandle dl; + pa_modinfo *i; + assert(name); + + if (!(dl = lt_dlopenext(name))) { + pa_log(__FILE__": Failed to open module \"%s\": %s", name, lt_dlerror()); + return NULL; + } + + i = pa_modinfo_get_by_handle(dl); + lt_dlclose(dl); + + return i; +} + +void pa_modinfo_free(pa_modinfo *i) { + assert(i); + pa_xfree(i->author); + pa_xfree(i->description); + pa_xfree(i->usage); + pa_xfree(i->version); + pa_xfree(i); +} diff --git a/src/pulsecore/modinfo.h b/src/pulsecore/modinfo.h new file mode 100644 index 00000000..f39cee3b --- /dev/null +++ b/src/pulsecore/modinfo.h @@ -0,0 +1,43 @@ +#ifndef foomodinfohfoo +#define foomodinfohfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* Some functions for reading module meta data from Polypaudio modules */ + +typedef struct pa_modinfo { + char *author; + char *description; + char *usage; + char *version; +} pa_modinfo; + +/* Read meta data from an libtool handle */ +pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl); + +/* Read meta data from a module file */ +pa_modinfo *pa_modinfo_get_by_name(const char *name); + +/* Free meta data */ +void pa_modinfo_free(pa_modinfo *i); + +#endif diff --git a/src/pulsecore/module.c b/src/pulsecore/module.c new file mode 100644 index 00000000..e7dca78d --- /dev/null +++ b/src/pulsecore/module.c @@ -0,0 +1,319 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "module.h" + +#define PA_SYMBOL_INIT "pa__init" +#define PA_SYMBOL_DONE "pa__done" + +#define UNLOAD_POLL_TIME 2 + +/* lt_dlsym() violates ISO C, so confide the breakage into this function to + * avoid warnings. */ +typedef void (*fnptr)(void); +static inline fnptr lt_dlsym_fn(lt_dlhandle handle, const char *symbol) { + return (fnptr) (long) lt_dlsym(handle, symbol); +} + +static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + pa_core *c = userdata; + struct timeval ntv; + assert(c && c->mainloop == m && c->module_auto_unload_event == e); + + pa_module_unload_unused(c); + + pa_gettimeofday(&ntv); + ntv.tv_sec += UNLOAD_POLL_TIME; + m->time_restart(e, &ntv); +} + +static inline fnptr load_sym(lt_dlhandle handle, const char *module, const char *symbol) { + char *buffer, *ch; + size_t buflen; + fnptr res; + + res = lt_dlsym_fn(handle, symbol); + if (res) + return res; + + /* As the .la files might have been cleansed from the system, we should + * try with the ltdl prefix as well. */ + + buflen = strlen(symbol) + strlen(module) + strlen("_LTX_") + 1; + buffer = pa_xmalloc(buflen); + assert(buffer); + + strcpy(buffer, module); + + for (ch = buffer;*ch != '\0';ch++) { + if (!isalnum(*ch)) + *ch = '_'; + } + + strcat(buffer, "_LTX_"); + strcat(buffer, symbol); + + res = lt_dlsym_fn(handle, buffer); + + pa_xfree(buffer); + + return res; +} + +pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { + pa_module *m = NULL; + int r; + + assert(c && name); + + if (c->disallow_module_loading) + goto fail; + + m = pa_xmalloc(sizeof(pa_module)); + + m->name = pa_xstrdup(name); + m->argument = pa_xstrdup(argument); + + if (!(m->dl = lt_dlopenext(name))) { + pa_log(__FILE__": Failed to open module \"%s\": %s", name, lt_dlerror()); + goto fail; + } + + if (!(m->init = (int (*)(pa_core *_c, pa_module*_m)) load_sym(m->dl, name, PA_SYMBOL_INIT))) { + pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.", name); + goto fail; + } + + if (!(m->done = (void (*)(pa_core *_c, pa_module*_m)) load_sym(m->dl, name, PA_SYMBOL_DONE))) { + pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_DONE"\" not found.", name); + goto fail; + } + + m->userdata = NULL; + m->core = c; + m->n_used = -1; + m->auto_unload = 0; + m->unload_requested = 0; + + assert(m->init); + if (m->init(c, m) < 0) { + pa_log_error(__FILE__": Failed to load module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : ""); + goto fail; + } + + if (!c->modules) + c->modules = pa_idxset_new(NULL, NULL); + + if (!c->module_auto_unload_event) { + struct timeval ntv; + pa_gettimeofday(&ntv); + ntv.tv_sec += UNLOAD_POLL_TIME; + c->module_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); + } + assert(c->module_auto_unload_event); + + assert(c->modules); + r = pa_idxset_put(c->modules, m, &m->index); + assert(r >= 0 && m->index != PA_IDXSET_INVALID); + + pa_log_info(__FILE__": Loaded \"%s\" (index: #%u; argument: \"%s\").", m->name, m->index, m->argument ? m->argument : ""); + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_NEW, m->index); + + return m; + +fail: + + if (m) { + pa_xfree(m->argument); + pa_xfree(m->name); + + if (m->dl) + lt_dlclose(m->dl); + + pa_xfree(m); + } + + return NULL; +} + +static void pa_module_free(pa_module *m) { + assert(m && m->done && m->core); + + if (m->core->disallow_module_loading) + return; + + pa_log_info(__FILE__": Unloading \"%s\" (index: #%u).", m->name, m->index); + + m->done(m->core, m); + + lt_dlclose(m->dl); + + pa_log_info(__FILE__": Unloaded \"%s\" (index: #%u).", m->name, m->index); + + pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_REMOVE, m->index); + + pa_xfree(m->name); + pa_xfree(m->argument); + pa_xfree(m); +} + +void pa_module_unload(pa_core *c, pa_module *m) { + assert(c && m); + + assert(c->modules); + if (!(m = pa_idxset_remove_by_data(c->modules, m, NULL))) + return; + + pa_module_free(m); +} + +void pa_module_unload_by_index(pa_core *c, uint32_t idx) { + pa_module *m; + assert(c && idx != PA_IDXSET_INVALID); + + assert(c->modules); + if (!(m = pa_idxset_remove_by_index(c->modules, idx))) + return; + + pa_module_free(m); +} + +static void free_callback(void *p, PA_GCC_UNUSED void *userdata) { + pa_module *m = p; + assert(m); + pa_module_free(m); +} + +void pa_module_unload_all(pa_core *c) { + assert(c); + + if (!c->modules) + return; + + pa_idxset_free(c->modules, free_callback, NULL); + c->modules = NULL; + + if (c->module_auto_unload_event) { + c->mainloop->time_free(c->module_auto_unload_event); + c->module_auto_unload_event = NULL; + } + + if (c->module_defer_unload_event) { + c->mainloop->defer_free(c->module_defer_unload_event); + c->module_defer_unload_event = NULL; + } +} + +static int unused_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void *userdata) { + pa_module *m = p; + time_t *now = userdata; + assert(p && del && now); + + if (m->n_used == 0 && m->auto_unload && m->last_used_time+m->core->module_idle_time <= *now) { + pa_module_free(m); + *del = 1; + } + + return 0; +} + +void pa_module_unload_unused(pa_core *c) { + time_t now; + assert(c); + + if (!c->modules) + return; + + time(&now); + pa_idxset_foreach(c->modules, unused_callback, &now); +} + +static int unload_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, PA_GCC_UNUSED void *userdata) { + pa_module *m = p; + assert(m); + + if (m->unload_requested) { + pa_module_free(m); + *del = 1; + } + + return 0; +} + +static void defer_cb(pa_mainloop_api*api, pa_defer_event *e, void *userdata) { + pa_core *core = userdata; + api->defer_enable(e, 0); + + if (!core->modules) + return; + + pa_idxset_foreach(core->modules, unload_callback, NULL); + +} + +void pa_module_unload_request(pa_module *m) { + assert(m); + + m->unload_requested = 1; + + if (!m->core->module_defer_unload_event) + m->core->module_defer_unload_event = m->core->mainloop->defer_new(m->core->mainloop, defer_cb, m->core); + + m->core->mainloop->defer_enable(m->core->module_defer_unload_event, 1); +} + +void pa_module_set_used(pa_module*m, int used) { + assert(m); + + if (m->n_used != used) + pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_CHANGE, m->index); + + if (m->n_used != used && used == 0) + time(&m->last_used_time); + + m->n_used = used; +} + +pa_modinfo *pa_module_get_info(pa_module *m) { + assert(m); + + return pa_modinfo_get_by_handle(m->dl); +} diff --git a/src/pulsecore/module.h b/src/pulsecore/module.h new file mode 100644 index 00000000..9bc5cb5d --- /dev/null +++ b/src/pulsecore/module.h @@ -0,0 +1,70 @@ +#ifndef foomodulehfoo +#define foomodulehfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include +#include + +typedef struct pa_module pa_module; + +struct pa_module { + pa_core *core; + char *name, *argument; + uint32_t index; + + lt_dlhandle dl; + + int (*init)(pa_core *c, pa_module*m); + void (*done)(pa_core *c, pa_module*m); + + void *userdata; + + int n_used; + int auto_unload; + time_t last_used_time; + + int unload_requested; +}; + +pa_module* pa_module_load(pa_core *c, const char *name, const char*argument); +void pa_module_unload(pa_core *c, pa_module *m); +void pa_module_unload_by_index(pa_core *c, uint32_t idx); + +void pa_module_unload_all(pa_core *c); +void pa_module_unload_unused(pa_core *c); + +void pa_module_unload_request(pa_module *m); + +void pa_module_set_used(pa_module*m, int used); + +#define PA_MODULE_AUTHOR(s) const char * pa__get_author(void) { return s; } +#define PA_MODULE_DESCRIPTION(s) const char * pa__get_description(void) { return s; } +#define PA_MODULE_USAGE(s) const char * pa__get_usage(void) { return s; } +#define PA_MODULE_VERSION(s) const char * pa__get_version(void) { return s; } + +pa_modinfo *pa_module_get_info(pa_module *m); + +#endif diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c new file mode 100644 index 00000000..0f35ed1c --- /dev/null +++ b/src/pulsecore/namereg.c @@ -0,0 +1,214 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "namereg.h" + +struct namereg_entry { + pa_namereg_type_t type; + char *name; + void *data; +}; + +void pa_namereg_free(pa_core *c) { + assert(c); + if (!c->namereg) + return; + assert(pa_hashmap_size(c->namereg) == 0); + pa_hashmap_free(c->namereg, NULL, NULL); +} + +const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, int fail) { + struct namereg_entry *e; + char *n = NULL; + int r; + + assert(c && name && data); + + if (!c->namereg) { + c->namereg = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + assert(c->namereg); + } + + if ((e = pa_hashmap_get(c->namereg, name)) && fail) + return NULL; + + if (!e) + n = pa_xstrdup(name); + else { + unsigned i; + size_t l = strlen(name); + n = pa_xmalloc(l+3); + + for (i = 1; i <= 99; i++) { + snprintf(n, l+2, "%s%u", name, i); + + if (!(e = pa_hashmap_get(c->namereg, n))) + break; + } + + if (e) { + pa_xfree(n); + return NULL; + } + } + + assert(n); + e = pa_xmalloc(sizeof(struct namereg_entry)); + e->type = type; + e->name = n; + e->data = data; + + r = pa_hashmap_put(c->namereg, e->name, e); + assert (r >= 0); + + return e->name; + +} + +void pa_namereg_unregister(pa_core *c, const char *name) { + struct namereg_entry *e; + assert(c && name); + + e = pa_hashmap_remove(c->namereg, name); + assert(e); + + pa_xfree(e->name); + pa_xfree(e); +} + +void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int autoload) { + struct namereg_entry *e; + uint32_t idx; + assert(c); + + if (!name) { + if (type == PA_NAMEREG_SOURCE) + name = pa_namereg_get_default_source_name(c); + else if (type == PA_NAMEREG_SINK) + name = pa_namereg_get_default_sink_name(c); + } + + if (!name) + return NULL; + + if (c->namereg && (e = pa_hashmap_get(c->namereg, name))) + if (e->type == type) + return e->data; + + if (pa_atou(name, &idx) < 0) { + + if (autoload) { + pa_autoload_request(c, name, type); + + if (c->namereg && (e = pa_hashmap_get(c->namereg, name))) + if (e->type == type) + return e->data; + } + + return NULL; + } + + if (type == PA_NAMEREG_SINK) + return pa_idxset_get_by_index(c->sinks, idx); + else if (type == PA_NAMEREG_SOURCE) + return pa_idxset_get_by_index(c->sources, idx); + else if (type == PA_NAMEREG_SAMPLE && c->scache) + return pa_idxset_get_by_index(c->scache, idx); + + return NULL; +} + +void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type) { + char **s; + assert(c && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); + + s = type == PA_NAMEREG_SINK ? &c->default_sink_name : &c->default_source_name; + assert(s); + + if (!name && !*s) + return; + + if (name && *s && !strcmp(name, *s)) + return; + + pa_xfree(*s); + *s = pa_xstrdup(name); + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); +} + +const char *pa_namereg_get_default_sink_name(pa_core *c) { + pa_sink *s; + assert(c); + + if (c->default_sink_name) + return c->default_sink_name; + + if ((s = pa_idxset_first(c->sinks, NULL))) + pa_namereg_set_default(c, s->name, PA_NAMEREG_SINK); + + if (c->default_sink_name) + return c->default_sink_name; + + return NULL; +} + +const char *pa_namereg_get_default_source_name(pa_core *c) { + pa_source *s; + uint32_t idx; + + assert(c); + + if (c->default_source_name) + return c->default_source_name; + + for (s = pa_idxset_first(c->sources, &idx); s; s = pa_idxset_next(c->sources, &idx)) + if (!s->monitor_of) { + pa_namereg_set_default(c, s->name, PA_NAMEREG_SOURCE); + break; + } + + if (!c->default_source_name) + if ((s = pa_idxset_first(c->sources, NULL))) + pa_namereg_set_default(c, s->name, PA_NAMEREG_SOURCE); + + if (c->default_source_name) + return c->default_source_name; + + return NULL; +} diff --git a/src/pulsecore/namereg.h b/src/pulsecore/namereg.h new file mode 100644 index 00000000..e1aef8bb --- /dev/null +++ b/src/pulsecore/namereg.h @@ -0,0 +1,43 @@ +#ifndef foonamereghfoo +#define foonamereghfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef enum pa_namereg_type { + PA_NAMEREG_SINK, + PA_NAMEREG_SOURCE, + PA_NAMEREG_SAMPLE +} pa_namereg_type_t; + +void pa_namereg_free(pa_core *c); + +const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, int fail); +void pa_namereg_unregister(pa_core *c, const char *name); +void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int autoload); +void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type); + +const char *pa_namereg_get_default_sink_name(pa_core *c); +const char *pa_namereg_get_default_source_name(pa_core *c); + +#endif diff --git a/src/pulsecore/native-common.h b/src/pulsecore/native-common.h new file mode 100644 index 00000000..b35931d0 --- /dev/null +++ b/src/pulsecore/native-common.h @@ -0,0 +1,127 @@ +#ifndef foonativecommonhfoo +#define foonativecommonhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +PA_C_DECL_BEGIN + +enum { + /* Generic commands */ + PA_COMMAND_ERROR, + PA_COMMAND_TIMEOUT, /* pseudo command */ + PA_COMMAND_REPLY, + + /* Commands from client to server */ + PA_COMMAND_CREATE_PLAYBACK_STREAM, + PA_COMMAND_DELETE_PLAYBACK_STREAM, + PA_COMMAND_CREATE_RECORD_STREAM, + PA_COMMAND_DELETE_RECORD_STREAM, + PA_COMMAND_EXIT, + PA_COMMAND_AUTH, + PA_COMMAND_SET_CLIENT_NAME, + PA_COMMAND_LOOKUP_SINK, + PA_COMMAND_LOOKUP_SOURCE, + PA_COMMAND_DRAIN_PLAYBACK_STREAM, + PA_COMMAND_STAT, + PA_COMMAND_GET_PLAYBACK_LATENCY, + PA_COMMAND_CREATE_UPLOAD_STREAM, + PA_COMMAND_DELETE_UPLOAD_STREAM, + PA_COMMAND_FINISH_UPLOAD_STREAM, + PA_COMMAND_PLAY_SAMPLE, + PA_COMMAND_REMOVE_SAMPLE, + + PA_COMMAND_GET_SERVER_INFO, + PA_COMMAND_GET_SINK_INFO, + PA_COMMAND_GET_SINK_INFO_LIST, + PA_COMMAND_GET_SOURCE_INFO, + PA_COMMAND_GET_SOURCE_INFO_LIST, + PA_COMMAND_GET_MODULE_INFO, + PA_COMMAND_GET_MODULE_INFO_LIST, + PA_COMMAND_GET_CLIENT_INFO, + PA_COMMAND_GET_CLIENT_INFO_LIST, + PA_COMMAND_GET_SINK_INPUT_INFO, + PA_COMMAND_GET_SINK_INPUT_INFO_LIST, + PA_COMMAND_GET_SOURCE_OUTPUT_INFO, + PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, + PA_COMMAND_GET_SAMPLE_INFO, + PA_COMMAND_GET_SAMPLE_INFO_LIST, + PA_COMMAND_SUBSCRIBE, + + PA_COMMAND_SET_SINK_VOLUME, + PA_COMMAND_SET_SINK_INPUT_VOLUME, + PA_COMMAND_SET_SOURCE_VOLUME, + + PA_COMMAND_SET_SINK_MUTE, + PA_COMMAND_SET_SOURCE_MUTE, + + PA_COMMAND_CORK_PLAYBACK_STREAM, + PA_COMMAND_FLUSH_PLAYBACK_STREAM, + PA_COMMAND_TRIGGER_PLAYBACK_STREAM, + + PA_COMMAND_SET_DEFAULT_SINK, + PA_COMMAND_SET_DEFAULT_SOURCE, + + PA_COMMAND_SET_PLAYBACK_STREAM_NAME, + PA_COMMAND_SET_RECORD_STREAM_NAME, + + PA_COMMAND_KILL_CLIENT, + PA_COMMAND_KILL_SINK_INPUT, + PA_COMMAND_KILL_SOURCE_OUTPUT, + PA_COMMAND_LOAD_MODULE, + PA_COMMAND_UNLOAD_MODULE, + PA_COMMAND_ADD_AUTOLOAD, + PA_COMMAND_REMOVE_AUTOLOAD, + PA_COMMAND_GET_AUTOLOAD_INFO, + PA_COMMAND_GET_AUTOLOAD_INFO_LIST, + PA_COMMAND_GET_RECORD_LATENCY, + PA_COMMAND_CORK_RECORD_STREAM, + PA_COMMAND_FLUSH_RECORD_STREAM, + PA_COMMAND_PREBUF_PLAYBACK_STREAM, + + /* Commands from server to client */ + PA_COMMAND_REQUEST, + PA_COMMAND_OVERFLOW, + PA_COMMAND_UNDERFLOW, + PA_COMMAND_PLAYBACK_STREAM_KILLED, + PA_COMMAND_RECORD_STREAM_KILLED, + PA_COMMAND_SUBSCRIBE_EVENT, + + PA_COMMAND_MAX +}; + +#define PA_NATIVE_COOKIE_LENGTH 256 +#define PA_NATIVE_COOKIE_FILE ".pulseaudio-cookie" + +#define PA_NATIVE_DEFAULT_PORT 4713 + +#define PA_NATIVE_COOKIE_PROPERTY_NAME "protocol-native-cookie" +#define PA_NATIVE_SERVER_PROPERTY_NAME "protocol-native-server" + +#define PA_NATIVE_DEFAULT_UNIX_SOCKET "native" + + +PA_C_DECL_END + +#endif diff --git a/src/pulsecore/packet.c b/src/pulsecore/packet.c new file mode 100644 index 00000000..8b010f01 --- /dev/null +++ b/src/pulsecore/packet.c @@ -0,0 +1,79 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include "packet.h" + +pa_packet* pa_packet_new(size_t length) { + pa_packet *p; + + assert(length); + + p = pa_xmalloc(sizeof(pa_packet)+length); + p->ref = 1; + p->length = length; + p->data = (uint8_t*) (p+1); + p->type = PA_PACKET_APPENDED; + + return p; +} + +pa_packet* pa_packet_new_dynamic(void* data, size_t length) { + pa_packet *p; + + assert(data); + assert(length); + + p = pa_xnew(pa_packet, 1); + p->ref = 1; + p->length = length; + p->data = data; + p->type = PA_PACKET_DYNAMIC; + + return p; +} + +pa_packet* pa_packet_ref(pa_packet *p) { + assert(p); + assert(p->ref >= 1); + + p->ref++; + return p; +} + +void pa_packet_unref(pa_packet *p) { + assert(p); + assert(p->ref >= 1); + + if (--p->ref == 0) { + if (p->type == PA_PACKET_DYNAMIC) + pa_xfree(p->data); + pa_xfree(p); + } +} diff --git a/src/pulsecore/packet.h b/src/pulsecore/packet.h new file mode 100644 index 00000000..7842857a --- /dev/null +++ b/src/pulsecore/packet.h @@ -0,0 +1,41 @@ +#ifndef foopackethfoo +#define foopackethfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +typedef struct pa_packet { + enum { PA_PACKET_APPENDED, PA_PACKET_DYNAMIC } type; + unsigned ref; + size_t length; + uint8_t *data; +} pa_packet; + +pa_packet* pa_packet_new(size_t length); +pa_packet* pa_packet_new_dynamic(void* data, size_t length); + +pa_packet* pa_packet_ref(pa_packet *p); +void pa_packet_unref(pa_packet *p); + +#endif diff --git a/src/pulsecore/parseaddr.c b/src/pulsecore/parseaddr.c new file mode 100644 index 00000000..da1647af --- /dev/null +++ b/src/pulsecore/parseaddr.c @@ -0,0 +1,115 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include +#include + +#include "parseaddr.h" + +/* Parse addresses in one of the following forms: + * HOSTNAME + * HOSTNAME:PORT + * [HOSTNAME] + * [HOSTNAME]:PORT + * + * Return a newly allocated string of the hostname and fill in *ret_port if specified */ + +static char *parse_host(const char *s, uint16_t *ret_port) { + assert(s && ret_port); + if (*s == '[') { + char *e; + if (!(e = strchr(s+1, ']'))) + return NULL; + + if (e[1] == ':') + *ret_port = atoi(e+2); + else if (e[1] != 0) + return NULL; + + return pa_xstrndup(s+1, e-s-1); + } else { + char *e; + + if (!(e = strrchr(s, ':'))) + return pa_xstrdup(s); + + *ret_port = atoi(e+1); + return pa_xstrndup(s, e-s); + } +} + +int pa_parse_address(const char *name, pa_parsed_address *ret_p) { + const char *p; + assert(name && ret_p); + memset(ret_p, 0, sizeof(pa_parsed_address)); + ret_p->type = PA_PARSED_ADDRESS_TCP_AUTO; + + if (*name == '{') { + char hn[256], *pfx; + /* The URL starts with a host specification for detecting local connections */ + + if (!pa_get_host_name(hn, sizeof(hn))) + return -1; + + pfx = pa_sprintf_malloc("{%s}", hn); + if (!pa_startswith(name, pfx)) { + pa_xfree(pfx); + /* Not local */ + return -1; + } + + p = name + strlen(pfx); + pa_xfree(pfx); + } else + p = name; + + if (*p == '/') + ret_p->type = PA_PARSED_ADDRESS_UNIX; + else if (pa_startswith(p, "unix:")) { + ret_p->type = PA_PARSED_ADDRESS_UNIX; + p += sizeof("unix:")-1; + } else if (pa_startswith(p, "tcp:") || pa_startswith(p, "tcp4:")) { + ret_p->type = PA_PARSED_ADDRESS_TCP4; + p += sizeof("tcp:")-1; + } else if (pa_startswith(p, "tcp6:")) { + ret_p->type = PA_PARSED_ADDRESS_TCP6; + p += sizeof("tcp6:")-1; + } + + if (ret_p->type == PA_PARSED_ADDRESS_UNIX) + ret_p->path_or_host = pa_xstrdup(p); + else + if (!(ret_p->path_or_host = parse_host(p, &ret_p->port))) + return -1; + + + return 0; +} diff --git a/src/pulsecore/parseaddr.h b/src/pulsecore/parseaddr.h new file mode 100644 index 00000000..0393f665 --- /dev/null +++ b/src/pulsecore/parseaddr.h @@ -0,0 +1,42 @@ +#ifndef fooparseaddrhfoo +#define fooparseaddrhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef enum pa_parsed_address_type { + PA_PARSED_ADDRESS_UNIX, + PA_PARSED_ADDRESS_TCP4, + PA_PARSED_ADDRESS_TCP6, + PA_PARSED_ADDRESS_TCP_AUTO +} pa_parsed_address_type_t; + +typedef struct pa_parsed_address { + pa_parsed_address_type_t type; + char *path_or_host; + uint16_t port; +} pa_parsed_address; + +int pa_parse_address(const char *a, pa_parsed_address *ret_p); + +#endif diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c new file mode 100644 index 00000000..5b76b432 --- /dev/null +++ b/src/pulsecore/pdispatch.c @@ -0,0 +1,318 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "pdispatch.h" + +/*#define DEBUG_OPCODES */ + +#ifdef DEBUG_OPCODES + +static const char *command_names[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = "ERROR", + [PA_COMMAND_TIMEOUT] = "TIMEOUT", + [PA_COMMAND_REPLY] = "REPLY", + [PA_COMMAND_CREATE_PLAYBACK_STREAM] = "CREATE_PLAYBACK_STREAM", + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = "DELETE_PLAYBACK_STREAM", + [PA_COMMAND_CREATE_RECORD_STREAM] = "CREATE_RECORD_STREAM", + [PA_COMMAND_DELETE_RECORD_STREAM] = "DELETE_RECORD_STREAM", + [PA_COMMAND_AUTH] = "AUTH", + [PA_COMMAND_REQUEST] = "REQUEST", + [PA_COMMAND_EXIT] = "EXIT", + [PA_COMMAND_SET_CLIENT_NAME] = "SET_CLIENT_NAME", + [PA_COMMAND_LOOKUP_SINK] = "LOOKUP_SINK", + [PA_COMMAND_LOOKUP_SOURCE] = "LOOKUP_SOURCE", + [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = "DRAIN_PLAYBACK_STREAM", + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = "PLAYBACK_STREAM_KILLED", + [PA_COMMAND_RECORD_STREAM_KILLED] = "RECORD_STREAM_KILLED", + [PA_COMMAND_STAT] = "STAT", + [PA_COMMAND_GET_PLAYBACK_LATENCY] = "PLAYBACK_LATENCY", + [PA_COMMAND_CREATE_UPLOAD_STREAM] = "CREATE_UPLOAD_STREAM", + [PA_COMMAND_DELETE_UPLOAD_STREAM] = "DELETE_UPLOAD_STREAM", + [PA_COMMAND_FINISH_UPLOAD_STREAM] = "FINISH_UPLOAD_STREAM", + [PA_COMMAND_PLAY_SAMPLE] = "PLAY_SAMPLE", + [PA_COMMAND_REMOVE_SAMPLE] = "REMOVE_SAMPLE", + [PA_COMMAND_GET_SERVER_INFO] = "GET_SERVER_INFO", + [PA_COMMAND_GET_SINK_INFO] = "GET_SINK_INFO", + [PA_COMMAND_GET_SINK_INFO_LIST] = "GET_SINK_INFO_LIST", + [PA_COMMAND_GET_SOURCE_INFO] = "GET_SOURCE_INFO", + [PA_COMMAND_GET_SOURCE_INFO_LIST] = "GET_SOURCE_INFO_LIST", + [PA_COMMAND_GET_MODULE_INFO] = "GET_MODULE_INFO", + [PA_COMMAND_GET_MODULE_INFO_LIST] = "GET_MODULE_INFO_LIST", + [PA_COMMAND_GET_CLIENT_INFO] = "GET_CLIENT_INFO", + [PA_COMMAND_GET_CLIENT_INFO_LIST] = "GET_CLIENT_INFO_LIST", + [PA_COMMAND_GET_SAMPLE_INFO] = "GET_SAMPLE_INFO", + [PA_COMMAND_GET_SAMPLE_INFO_LIST] = "GET_SAMPLE_INFO_LIST", + [PA_COMMAND_GET_SINK_INPUT_INFO] = "GET_SINK_INPUT_INFO", + [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = "GET_SINK_INPUT_INFO_LIST", + [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = "GET_SOURCE_OUTPUT_INFO", + [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = "GET_SOURCE_OUTPUT_INFO_LIST", + [PA_COMMAND_SUBSCRIBE] = "SUBSCRIBE", + [PA_COMMAND_SUBSCRIBE_EVENT] = "SUBSCRIBE_EVENT", + [PA_COMMAND_SET_SINK_VOLUME] = "SET_SINK_VOLUME", + [PA_COMMAND_SET_SINK_INPUT_VOLUME] = "SET_SINK_INPUT_VOLUME", + [PA_COMMAND_SET_SOURCE_VOLUME] = "SET_SOURCE_VOLME", + [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = "TRIGGER_PLAYBACK_STREAM", + [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = "FLUSH_PLAYBACK_STREAM", + [PA_COMMAND_CORK_PLAYBACK_STREAM] = "CORK_PLAYBACK_STREAM", + [PA_COMMAND_GET_AUTOLOAD_INFO] = "GET_AUTOLOAD_INFO", + [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = "GET_AUTOLOAD_INFO_LIST", +}; + +#endif + +struct reply_info { + pa_pdispatch *pdispatch; + PA_LLIST_FIELDS(struct reply_info); + pa_pdispatch_cb_t callback; + void *userdata; + pa_free_cb_t free_cb; + uint32_t tag; + pa_time_event *time_event; +}; + +struct pa_pdispatch { + int ref; + pa_mainloop_api *mainloop; + const pa_pdispatch_cb_t *callback_table; + unsigned n_commands; + PA_LLIST_HEAD(struct reply_info, replies); + pa_pdispatch_drain_callback drain_callback; + void *drain_userdata; + const void *creds; +}; + +static void reply_info_free(struct reply_info *r) { + assert(r && r->pdispatch && r->pdispatch->mainloop); + + if (r->time_event) + r->pdispatch->mainloop->time_free(r->time_event); + + PA_LLIST_REMOVE(struct reply_info, r->pdispatch->replies, r); + + pa_xfree(r); +} + +pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_cb_t*table, unsigned entries) { + pa_pdispatch *pd; + assert(mainloop); + + assert((entries && table) || (!entries && !table)); + + pd = pa_xmalloc(sizeof(pa_pdispatch)); + pd->ref = 1; + pd->mainloop = mainloop; + pd->callback_table = table; + pd->n_commands = entries; + PA_LLIST_HEAD_INIT(pa_reply_info, pd->replies); + pd->drain_callback = NULL; + pd->drain_userdata = NULL; + pd->creds = NULL; + + return pd; +} + +static void pdispatch_free(pa_pdispatch *pd) { + assert(pd); + + while (pd->replies) { + if (pd->replies->free_cb) + pd->replies->free_cb(pd->replies->userdata); + + reply_info_free(pd->replies); + } + + pa_xfree(pd); +} + +static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command, pa_tagstruct *ts) { + pa_pdispatch_cb_t callback; + void *userdata; + uint32_t tag; + assert(r); + + pa_pdispatch_ref(pd); + + callback = r->callback; + userdata = r->userdata; + tag = r->tag; + + reply_info_free(r); + + callback(pd, command, tag, ts, userdata); + + if (pd->drain_callback && !pa_pdispatch_is_pending(pd)) + pd->drain_callback(pd, pd->drain_userdata); + + pa_pdispatch_unref(pd); +} + +int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const void *creds, void *userdata) { + uint32_t tag, command; + pa_tagstruct *ts = NULL; + int ret = -1; + assert(pd && packet && packet->data); + + pa_pdispatch_ref(pd); + + if (packet->length <= 8) + goto finish; + + ts = pa_tagstruct_new(packet->data, packet->length); + assert(ts); + + if (pa_tagstruct_getu32(ts, &command) < 0 || + pa_tagstruct_getu32(ts, &tag) < 0) + goto finish; + +#ifdef DEBUG_OPCODES +{ + char t[256]; + char const *p; + if (!(p = command_names[command])) + snprintf((char*) (p = t), sizeof(t), "%u", command); + + pa_log(__FILE__": Recieved opcode <%s>", p); +} +#endif + + pd->creds = creds; + + if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) { + struct reply_info *r; + + for (r = pd->replies; r; r = r->next) + if (r->tag == tag) + break; + + if (r) + run_action(pd, r, command, ts); + + } else if (pd->callback_table && (command < pd->n_commands) && pd->callback_table[command]) { + const pa_pdispatch_cb_t *c = pd->callback_table+command; + + (*c)(pd, command, tag, ts, userdata); + } else { + pa_log(__FILE__": Recieved unsupported command %u", command); + goto finish; + } + + ret = 0; + +finish: + pd->creds = NULL; + + if (ts) + pa_tagstruct_free(ts); + + pa_pdispatch_unref(pd); + + return ret; +} + +static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + struct reply_info*r = userdata; + assert(r && r->time_event == e && r->pdispatch && r->pdispatch->mainloop == m && r->callback); + + run_action(r->pdispatch, r, PA_COMMAND_TIMEOUT, NULL); +} + +void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t cb, void *userdata, pa_free_cb_t free_cb) { + struct reply_info *r; + struct timeval tv; + assert(pd && pd->ref >= 1 && cb); + + r = pa_xmalloc(sizeof(struct reply_info)); + r->pdispatch = pd; + r->callback = cb; + r->userdata = userdata; + r->free_cb = free_cb; + r->tag = tag; + + pa_gettimeofday(&tv); + tv.tv_sec += timeout; + + r->time_event = pd->mainloop->time_new(pd->mainloop, &tv, timeout_callback, r); + assert(r->time_event); + + PA_LLIST_PREPEND(struct reply_info, pd->replies, r); +} + +int pa_pdispatch_is_pending(pa_pdispatch *pd) { + assert(pd); + + return !!pd->replies; +} + +void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, void (*cb)(pa_pdispatch *pd, void *userdata), void *userdata) { + assert(pd); + assert(!cb || pa_pdispatch_is_pending(pd)); + + pd->drain_callback = cb; + pd->drain_userdata = userdata; +} + +void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata) { + struct reply_info *r, *n; + assert(pd); + + for (r = pd->replies; r; r = n) { + n = r->next; + + if (r->userdata == userdata) + reply_info_free(r); + } +} + +void pa_pdispatch_unref(pa_pdispatch *pd) { + assert(pd && pd->ref >= 1); + + if (!(--(pd->ref))) + pdispatch_free(pd); +} + +pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd) { + assert(pd && pd->ref >= 1); + pd->ref++; + return pd; +} + +const void * pa_pdispatch_creds(pa_pdispatch *pd) { + assert(pd); + assert(pd->ref >= 1); + + return pd->creds; +} diff --git a/src/pulsecore/pdispatch.h b/src/pulsecore/pdispatch.h new file mode 100644 index 00000000..07620e5a --- /dev/null +++ b/src/pulsecore/pdispatch.h @@ -0,0 +1,53 @@ +#ifndef foopdispatchhfoo +#define foopdispatchhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include +#include + +typedef struct pa_pdispatch pa_pdispatch; + +typedef void (*pa_pdispatch_cb_t)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +typedef void (*pa_pdispatch_drain_callback)(pa_pdispatch *pd, void *userdata); + +pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *m, const pa_pdispatch_cb_t*table, unsigned entries); +void pa_pdispatch_unref(pa_pdispatch *pd); +pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd); + +int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*p, const void*creds, void *userdata); + +void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t callback, void *userdata, pa_free_cb_t free_cb); + +int pa_pdispatch_is_pending(pa_pdispatch *pd); + +void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, pa_pdispatch_drain_callback callback, void *userdata); + +/* Remove all reply slots with the give userdata parameter */ +void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata); + +const void * pa_pdispatch_creds(pa_pdispatch *pd); + +#endif diff --git a/src/pulsecore/pid.c b/src/pulsecore/pid.c new file mode 100644 index 00000000..b8972866 --- /dev/null +++ b/src/pulsecore/pid.c @@ -0,0 +1,304 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include + +#include +#include +#include + +#include "pid.h" + +/* Read the PID data from the file descriptor fd, and return it. If no + * pid could be read, return 0, on failure (pid_t) -1 */ +static pid_t read_pid(const char *fn, int fd) { + ssize_t r; + char t[20], *e; + uint32_t pid; + + assert(fn && fd >= 0); + + if ((r = pa_loop_read(fd, t, sizeof(t)-1)) < 0) { + pa_log_warn(__FILE__": WARNING: failed to read PID file '%s': %s", + fn, pa_cstrerror(errno)); + return (pid_t) -1; + } + + if (r == 0) + return (pid_t) 0; + + t[r] = 0; + if ((e = strchr(t, '\n'))) + *e = 0; + + if (pa_atou(t, &pid) < 0) { + pa_log(__FILE__": WARNING: failed to parse PID file '%s'", fn); + return (pid_t) -1; + } + + return (pid_t) pid; +} + +static int open_pid_file(const char *fn, int mode) { + int fd = -1; + int lock = -1; + + for (;;) { + struct stat st; + + pa_make_secure_parent_dir(fn); + + if ((fd = open(fn, mode, S_IRUSR|S_IWUSR)) < 0) { + if (mode != O_RDONLY || errno != ENOENT) + pa_log_warn(__FILE__": WARNING: failed to open PID file '%s': %s", + fn, pa_cstrerror(errno)); + goto fail; + } + + /* Try to lock the file. If that fails, go without */ + if (pa_lock_fd(fd, 1) < 0) + goto fail; + + if (fstat(fd, &st) < 0) { + pa_log_warn(__FILE__": WARNING: failed to fstat() PID file '%s': %s", + fn, pa_cstrerror(errno)); + goto fail; + } + + /* Does the file still exist in the file system? When ye, w're done, otherwise restart */ + if (st.st_nlink >= 1) + break; + + if (pa_lock_fd(fd, 0) < 0) + goto fail; + + if (close(fd) < 0) { + pa_log_warn(__FILE__": WARNING: failed to close file '%s': %s", + fn, pa_cstrerror(errno)); + goto fail; + } + + fd = -1; + } + + return fd; + +fail: + + if (fd < 0) { + if (lock >= 0) + pa_lock_fd(fd, 0); + + close(fd); + } + + return -1; +} + +/* Create a new PID file for the current process. */ +int pa_pid_file_create(void) { + int fd = -1; + int ret = -1; + char fn[PATH_MAX]; + char t[20]; + pid_t pid; + size_t l; + +#ifdef OS_IS_WIN32 + HANDLE process; +#endif + + pa_runtime_path("pid", fn, sizeof(fn)); + + if ((fd = open_pid_file(fn, O_CREAT|O_RDWR)) < 0) + goto fail; + + if ((pid = read_pid(fn, fd)) == (pid_t) -1) + pa_log(__FILE__": corrupt PID file, overwriting."); + else if (pid > 0) { +#ifdef OS_IS_WIN32 + if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)) != NULL) { + CloseHandle(process); +#else + if (kill(pid, 0) >= 0 || errno != ESRCH) { +#endif + pa_log(__FILE__": daemon already running."); + goto fail; + } + + pa_log(__FILE__": stale PID file, overwriting."); + } + + /* Overwrite the current PID file */ + if (lseek(fd, 0, SEEK_SET) == (off_t) -1 || ftruncate(fd, 0) < 0) { + pa_log(__FILE__": failed to truncate PID file '%s': %s", + fn, pa_cstrerror(errno)); + goto fail; + } + + snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid()); + l = strlen(t); + + if (pa_loop_write(fd, t, l) != (ssize_t) l) { + pa_log(__FILE__": failed to write PID file."); + goto fail; + } + + ret = 0; + +fail: + if (fd >= 0) { + pa_lock_fd(fd, 0); + close(fd); + } + + return ret; +} + +/* Remove the PID file, if it is ours */ +int pa_pid_file_remove(void) { + int fd = -1; + char fn[PATH_MAX]; + int ret = -1; + pid_t pid; + char *p; + + pa_runtime_path("pid", fn, sizeof(fn)); + + if ((fd = open_pid_file(fn, O_RDWR)) < 0) { + pa_log_warn(__FILE__": WARNING: failed to open PID file '%s': %s", + fn, pa_cstrerror(errno)); + goto fail; + } + + if ((pid = read_pid(fn, fd)) == (pid_t) -1) + goto fail; + + if (pid != getpid()) { + pa_log(__FILE__": WARNING: PID file '%s' not mine!", fn); + goto fail; + } + + if (ftruncate(fd, 0) < 0) { + pa_log_warn(__FILE__": WARNING: failed to truncate PID file '%s': %s", + fn, pa_cstrerror(errno)); + goto fail; + } + +#ifdef OS_IS_WIN32 + pa_lock_fd(fd, 0); + close(fd); + fd = -1; +#endif + + if (unlink(fn) < 0) { + pa_log_warn(__FILE__": WARNING: failed to remove PID file '%s': %s", + fn, pa_cstrerror(errno)); + goto fail; + } + + if ((p = pa_parent_dir(fn))) { + rmdir(p); + pa_xfree(p); + } + + ret = 0; + +fail: + + if (fd >= 0) { + pa_lock_fd(fd, 0); + close(fd); + } + + return ret; +} + +/* Check whether the daemon is currently running, i.e. if a PID file + * exists and the PID therein too. Returns 0 on succcess, -1 + * otherwise. If pid is non-NULL and a running daemon was found, + * return its PID therein */ +int pa_pid_file_check_running(pid_t *pid) { + return pa_pid_file_kill(0, pid); +} + +#ifndef OS_IS_WIN32 + +/* Kill a current running daemon. Return non-zero on success, -1 + * otherwise. If successful *pid contains the PID of the daemon + * process. */ +int pa_pid_file_kill(int sig, pid_t *pid) { + int fd = -1; + char fn[PATH_MAX]; + int ret = -1; + pid_t _pid; + + if (!pid) + pid = &_pid; + + pa_runtime_path("pid", fn, sizeof(fn)); + + if ((fd = open_pid_file(fn, O_RDONLY)) < 0) + goto fail; + + if ((*pid = read_pid(fn, fd)) == (pid_t) -1) + goto fail; + + ret = kill(*pid, sig); + +fail: + + if (fd >= 0) { + pa_lock_fd(fd, 0); + close(fd); + } + + return ret; + +} + +#else /* OS_IS_WIN32 */ + +int pa_pid_file_kill(int sig, pid_t *pid) { + return -1; +} + +#endif diff --git a/src/pulsecore/pid.h b/src/pulsecore/pid.h new file mode 100644 index 00000000..bd476b29 --- /dev/null +++ b/src/pulsecore/pid.h @@ -0,0 +1,30 @@ +#ifndef foopidhfoo +#define foopidhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +int pa_pid_file_create(void); +int pa_pid_file_remove(void); +int pa_pid_file_check_running(pid_t *pid); +int pa_pid_file_kill(int sig, pid_t *pid); + +#endif diff --git a/src/pulsecore/pipe.c b/src/pulsecore/pipe.c new file mode 100644 index 00000000..6933e180 --- /dev/null +++ b/src/pulsecore/pipe.c @@ -0,0 +1,160 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with PulseAudio; If not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#include "winsock.h" + +#include "pipe.h" + +#ifndef HAVE_PIPE + +static int set_block(int fd, int blocking) { +#ifdef O_NONBLOCK + + int v; + + assert(fd >= 0); + + if ((v = fcntl(fd, F_GETFL)) < 0) + return -1; + + if (blocking) + v &= ~O_NONBLOCK; + else + v |= O_NONBLOCK; + + if (fcntl(fd, F_SETFL, v) < 0) + return -1; + + return 0; + +#elif defined(OS_IS_WIN32) + + u_long arg; + + arg = !blocking; + + if (ioctlsocket(fd, FIONBIO, &arg) < 0) + return -1; + + return 0; + +#else + + return -1; + +#endif +} + +int pipe(int filedes[2]) { + int listener; + struct sockaddr_in addr, peer; + socklen_t len; + + listener = -1; + filedes[0] = -1; + filedes[1] = -1; + + listener = socket(PF_INET, SOCK_STREAM, 0); + if (listener < 0) + goto error; + + filedes[0] = socket(PF_INET, SOCK_STREAM, 0); + if (filedes[0] < 0) + goto error; + + filedes[1] = socket(PF_INET, SOCK_STREAM, 0); + if (filedes[1] < 0) + goto error; + + /* Make non-blocking so that connect() won't block */ + if (set_block(filedes[0], 0) < 0) + goto error; + + addr.sin_family = AF_INET; + addr.sin_port = 0; + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + if (bind(listener, (struct sockaddr*)&addr, sizeof(addr)) < 0) + goto error; + + if (listen(listener, 1) < 0) + goto error; + + len = sizeof(addr); + if (getsockname(listener, (struct sockaddr*)&addr, &len) < 0) + goto error; + + if (connect(filedes[0], (struct sockaddr*)&addr, sizeof(addr)) < 0) { +#ifdef OS_IS_WIN32 + if (WSAGetLastError() != EWOULDBLOCK) +#else + if (errno != EINPROGRESS) +#endif + goto error; + } + + len = sizeof(peer); + filedes[1] = accept(listener, (struct sockaddr*)&peer, &len); + if (filedes[1] < 0) + goto error; + + /* Restore blocking */ + if (set_block(filedes[0], 1) < 0) + goto error; + + len = sizeof(addr); + if (getsockname(filedes[0], (struct sockaddr*)&addr, &len) < 0) + goto error; + + /* Check that someone else didn't steal the connection */ + if ((addr.sin_port != peer.sin_port) || (addr.sin_addr.s_addr != peer.sin_addr.s_addr)) + goto error; + + close(listener); + + return 0; + +error: + if (listener >= 0) + close(listener); + if (filedes[0] >= 0) + close(filedes[0]); + if (filedes[1] >= 0) + close(filedes[0]); + + return -1; +} + +#endif /* HAVE_PIPE */ diff --git a/src/pulsecore/pipe.h b/src/pulsecore/pipe.h new file mode 100644 index 00000000..a2514760 --- /dev/null +++ b/src/pulsecore/pipe.h @@ -0,0 +1,31 @@ +#ifndef foopipehfoo +#define foopipehfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with PulseAudio; If not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +***/ + +#ifndef HAVE_PIPE + +int pipe(int filedes[2]); + +#endif + +#endif diff --git a/src/pulsecore/play-memchunk.c b/src/pulsecore/play-memchunk.c new file mode 100644 index 00000000..7ac579e9 --- /dev/null +++ b/src/pulsecore/play-memchunk.c @@ -0,0 +1,117 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include +#include + +#include "play-memchunk.h" + +static void sink_input_kill(pa_sink_input *i) { + pa_memchunk *c; + assert(i && i->userdata); + c = i->userdata; + + pa_sink_input_disconnect(i); + pa_sink_input_unref(i); + + pa_memblock_unref(c->memblock); + pa_xfree(c); +} + +static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { + pa_memchunk *c; + assert(i && chunk && i->userdata); + c = i->userdata; + + if (c->length <= 0) + return -1; + + assert(c->memblock && c->memblock->length); + *chunk = *c; + pa_memblock_ref(c->memblock); + + return 0; +} + +static void si_kill(PA_GCC_UNUSED pa_mainloop_api *m, void *i) { + sink_input_kill(i); +} + +static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) { + pa_memchunk *c; + assert(i && length && i->userdata); + c = i->userdata; + + assert(!memcmp(chunk, c, sizeof(chunk))); + assert(length <= c->length); + + c->length -= length; + c->index += length; + + if (c->length <= 0) + pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i); +} + +int pa_play_memchunk( + pa_sink *sink, + const char *name, + const pa_sample_spec *ss, + const pa_channel_map *map, + const pa_memchunk *chunk, + pa_cvolume *cvolume) { + + pa_sink_input *si; + pa_memchunk *nchunk; + + assert(sink); + assert(ss); + assert(chunk); + + if (cvolume && pa_cvolume_is_muted(cvolume)) + return 0; + + if (!(si = pa_sink_input_new(sink, name, __FILE__, ss, map, cvolume, 0, PA_RESAMPLER_INVALID))) + return -1; + + si->peek = sink_input_peek; + si->drop = sink_input_drop; + si->kill = sink_input_kill; + + si->userdata = nchunk = pa_xnew(pa_memchunk, 1); + *nchunk = *chunk; + + pa_memblock_ref(chunk->memblock); + + pa_sink_notify(sink); + + return 0; +} diff --git a/src/pulsecore/play-memchunk.h b/src/pulsecore/play-memchunk.h new file mode 100644 index 00000000..3d5b8cc6 --- /dev/null +++ b/src/pulsecore/play-memchunk.h @@ -0,0 +1,36 @@ +#ifndef fooplaychunkhfoo +#define fooplaychunkhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +int pa_play_memchunk( + pa_sink *sink, + const char *name, + const pa_sample_spec *ss, + const pa_channel_map *map, + const pa_memchunk *chunk, + pa_cvolume *cvolume); + +#endif diff --git a/src/pulsecore/poll.c b/src/pulsecore/poll.c new file mode 100644 index 00000000..3f9ace7c --- /dev/null +++ b/src/pulsecore/poll.c @@ -0,0 +1,191 @@ +/* $Id$ */ + +/*** + Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 2005, Cendio AB. + This file is part of PulseAudio. + Based on work for the GNU C Library. + + PulseAudio is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with PulseAudio; If not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +***/ + +/* Poll the file descriptors described by the NFDS structures starting at + FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for + an event to occur; if TIMEOUT is -1, block until an event occurs. + Returns the number of file descriptors with events, zero if timed out, + or -1 for errors. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#include "winsock.h" + +#ifndef HAVE_SYS_POLL_H + +#include + +#include "poll.h" + +int poll (struct pollfd *fds, unsigned long int nfds, int timeout) { + struct timeval tv; + fd_set rset, wset, xset; + struct pollfd *f; + int ready; + int maxfd = 0; + char data[64]; + + FD_ZERO (&rset); + FD_ZERO (&wset); + FD_ZERO (&xset); + + if (nfds == 0) { + if (timeout >= 0) { + pa_msleep(timeout); + return 0; + } + +#ifdef OS_IS_WIN32 + /* + * Windows does not support signals properly so waiting for them would + * mean a deadlock. + */ + pa_msleep(100); + return 0; +#else + return select(0, NULL, NULL, NULL, NULL); +#endif + } + + for (f = fds; f < &fds[nfds]; ++f) { + if (f->fd != -1) { + if (f->events & POLLIN) + FD_SET (f->fd, &rset); + if (f->events & POLLOUT) + FD_SET (f->fd, &wset); + if (f->events & POLLPRI) + FD_SET (f->fd, &xset); + if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI))) + maxfd = f->fd; + } + } + + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + + ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset, + SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset, + SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv)); + if ((ready == -1) && (errno == EBADF)) { + ready = 0; + + FD_ZERO (&rset); + FD_ZERO (&wset); + FD_ZERO (&xset); + + maxfd = -1; + + for (f = fds; f < &fds[nfds]; ++f) { + if (f->fd != -1) { + fd_set sngl_rset, sngl_wset, sngl_xset; + + FD_ZERO (&sngl_rset); + FD_ZERO (&sngl_wset); + FD_ZERO (&sngl_xset); + + if (f->events & POLLIN) + FD_SET (f->fd, &sngl_rset); + if (f->events & POLLOUT) + FD_SET (f->fd, &sngl_wset); + if (f->events & POLLPRI) + FD_SET (f->fd, &sngl_xset); + if (f->events & (POLLIN|POLLOUT|POLLPRI)) { + struct timeval singl_tv; + + singl_tv.tv_sec = 0; + singl_tv.tv_usec = 0; + + if (select((SELECT_TYPE_ARG1) f->fd, SELECT_TYPE_ARG234 &rset, + SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset, + SELECT_TYPE_ARG5 &singl_tv) != -1) { + if (f->events & POLLIN) + FD_SET (f->fd, &rset); + if (f->events & POLLOUT) + FD_SET (f->fd, &wset); + if (f->events & POLLPRI) + FD_SET (f->fd, &xset); + if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI))) + maxfd = f->fd; + ++ready; + } else if (errno == EBADF) + f->revents |= POLLNVAL; + } + } + } + + if (ready) { + /* Linux alters the tv struct... but it shouldn't matter here ... + * as we're going to be a little bit out anyway as we've just eaten + * more than a couple of cpu cycles above */ + ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset, + SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset, + SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv)); + } + } + +#ifdef OS_IS_WIN32 + errno = WSAGetLastError(); +#endif + + if (ready > 0) { + ready = 0; + for (f = fds; f < &fds[nfds]; ++f) { + f->revents = 0; + if (f->fd != -1) { + if (FD_ISSET (f->fd, &rset)) { + /* support for POLLHUP. An hung up descriptor does not + increase the return value! */ + if (recv (f->fd, data, 64, MSG_PEEK) == -1) { + if (errno == ESHUTDOWN || errno == ECONNRESET || + errno == ECONNABORTED || errno == ENETRESET) { + fprintf(stderr, "Hangup\n"); + f->revents |= POLLHUP; + } + } + + if (f->revents == 0) + f->revents |= POLLIN; + } + if (FD_ISSET (f->fd, &wset)) + f->revents |= POLLOUT; + if (FD_ISSET (f->fd, &xset)) + f->revents |= POLLPRI; + } + if (f->revents) + ready++; + } + } + + return ready; +} + +#endif /* HAVE_SYS_POLL_H */ diff --git a/src/pulsecore/poll.h b/src/pulsecore/poll.h new file mode 100644 index 00000000..bed772c7 --- /dev/null +++ b/src/pulsecore/poll.h @@ -0,0 +1,57 @@ +/* $Id$ */ + +/*** + Compatibility definitions for System V `poll' interface. + Copyright (C) 1994,96,97,98,99,2000,2001,2004 Free Software Foundation, Inc. + Copyright (C) 2005, Cendio AB. + This file is part of PulseAudio. + Based on work for the GNU C Library. + + PulseAudio is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with PulseAudio; If not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +***/ + +/* Event types that can be polled for. These bits may be set in `events' + to indicate the interesting event types; they will appear in `revents' + to indicate the status of the file descriptor. */ +#define POLLIN 0x001 /* There is data to read. */ +#define POLLPRI 0x002 /* There is urgent data to read. */ +#define POLLOUT 0x004 /* Writing now will not block. */ + +/* Event types always implicitly polled for. These bits need not be set in + `events', but they will appear in `revents' to indicate the status of + the file descriptor. */ +#define POLLERR 0x008 /* Error condition. */ +#define POLLHUP 0x010 /* Hung up. */ +#define POLLNVAL 0x020 /* Invalid polling request. */ + + +/* Type used for the number of file descriptors. */ +typedef unsigned long int nfds_t; + +/* Data structure describing a polling request. */ +struct pollfd + { + int fd; /* File descriptor to poll. */ + short int events; /* Types of events poller cares about. */ + short int revents; /* Types of events that actually occurred. */ + }; + +/* Poll the file descriptors described by the NFDS structures starting at + FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for + an event to occur; if TIMEOUT is -1, block until an event occurs. + Returns the number of file descriptors with events, zero if timed out, + or -1 for errors. */ +extern int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout); diff --git a/src/pulsecore/props.c b/src/pulsecore/props.c new file mode 100644 index 00000000..8879b7aa --- /dev/null +++ b/src/pulsecore/props.c @@ -0,0 +1,121 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include + +#include + +#include "props.h" + +typedef struct pa_property { + char *name; /* Points to memory allocated by the property subsystem */ + void *data; /* Points to memory maintained by the caller */ +} pa_property; + +/* Allocate a new property object */ +static pa_property* property_new(const char *name, void *data) { + pa_property* p; + assert(name && data); + + p = pa_xmalloc(sizeof(pa_property)); + p->name = pa_xstrdup(name); + p->data = data; + + return p; +} + +/* Free a property object */ +static void property_free(pa_property *p) { + assert(p); + + pa_xfree(p->name); + pa_xfree(p); +} + +void* pa_property_get(pa_core *c, const char *name) { + pa_property *p; + assert(c && name && c->properties); + + if (!(p = pa_hashmap_get(c->properties, name))) + return NULL; + + return p->data; +} + +int pa_property_set(pa_core *c, const char *name, void *data) { + pa_property *p; + assert(c && name && data && c->properties); + + if (pa_hashmap_get(c->properties, name)) + return -1; + + p = property_new(name, data); + pa_hashmap_put(c->properties, p->name, p); + return 0; +} + +int pa_property_remove(pa_core *c, const char *name) { + pa_property *p; + assert(c && name && c->properties); + + if (!(p = pa_hashmap_remove(c->properties, name))) + return -1; + + property_free(p); + return 0; +} + +void pa_property_init(pa_core *c) { + assert(c); + + c->properties = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); +} + +void pa_property_cleanup(pa_core *c) { + assert(c); + + if (!c->properties) + return; + + assert(!pa_hashmap_size(c->properties)); + + pa_hashmap_free(c->properties, NULL, NULL); + c->properties = NULL; + +} + +void pa_property_dump(pa_core *c, pa_strbuf *s) { + void *state = NULL; + pa_property *p; + assert(c && s); + + while ((p = pa_hashmap_iterate(c->properties, &state, NULL))) + pa_strbuf_printf(s, "[%s] -> [%p]\n", p->name, p->data); +} + +int pa_property_replace(pa_core *c, const char *name, void *data) { + assert(c && name); + + pa_property_remove(c, name); + return pa_property_set(c, name, data); +} diff --git a/src/pulsecore/props.h b/src/pulsecore/props.h new file mode 100644 index 00000000..39b7ca68 --- /dev/null +++ b/src/pulsecore/props.h @@ -0,0 +1,58 @@ +#ifndef foopropshfoo +#define foopropshfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/* The property subsystem is to be used to share data between + * modules. Consider them to be kind of "global" variables for a + * core. Why not use the hashmap functions directly? The hashmap + * functions copy neither the key nor value, while this property + * system copies the key. Users of this system have to think about + * reference counting themselves. */ + +/* Return a pointer to the value of the specified property. */ +void* pa_property_get(pa_core *c, const char *name); + +/* Set the property 'name' to 'data'. This function fails in case a + * property by this name already exists. The property data is not + * copied or reference counted. This is the caller's job. */ +int pa_property_set(pa_core *c, const char *name, void *data); + +/* Remove the specified property. Return non-zero on failure */ +int pa_property_remove(pa_core *c, const char *name); + +/* A combination of pa_property_remove() and pa_property_set() */ +int pa_property_replace(pa_core *c, const char *name, void *data); + +/* Free all memory used by the property system */ +void pa_property_cleanup(pa_core *c); + +/* Initialize the properties subsystem */ +void pa_property_init(pa_core *c); + +/* Dump the current set of properties */ +void pa_property_dump(pa_core *c, pa_strbuf *s); + +#endif diff --git a/src/pulsecore/protocol-cli.c b/src/pulsecore/protocol-cli.c new file mode 100644 index 00000000..c5854f1e --- /dev/null +++ b/src/pulsecore/protocol-cli.c @@ -0,0 +1,97 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include +#include + +#include "protocol-cli.h" + +/* Don't allow more than this many concurrent connections */ +#define MAX_CONNECTIONS 25 + +struct pa_protocol_cli { + pa_module *module; + pa_core *core; + pa_socket_server*server; + pa_idxset *connections; +}; + +static void cli_eof_cb(pa_cli*c, void*userdata) { + pa_protocol_cli *p = userdata; + assert(p); + pa_idxset_remove_by_data(p->connections, c, NULL); + pa_cli_free(c); +} + +static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { + pa_protocol_cli *p = userdata; + pa_cli *c; + assert(s && io && p); + + if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { + pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); + pa_iochannel_free(io); + return; + } + + c = pa_cli_new(p->core, io, p->module); + assert(c); + pa_cli_set_eof_callback(c, cli_eof_cb, p); + + pa_idxset_put(p->connections, c, NULL); +} + +pa_protocol_cli* pa_protocol_cli_new(pa_core *core, pa_socket_server *server, pa_module *m, PA_GCC_UNUSED pa_modargs *ma) { + pa_protocol_cli* p; + assert(core && server); + + p = pa_xmalloc(sizeof(pa_protocol_cli)); + p->module = m; + p->core = core; + p->server = server; + p->connections = pa_idxset_new(NULL, NULL); + + pa_socket_server_set_callback(p->server, on_connection, p); + + return p; +} + +static void free_connection(void *p, PA_GCC_UNUSED void *userdata) { + assert(p); + pa_cli_free(p); +} + +void pa_protocol_cli_free(pa_protocol_cli *p) { + assert(p); + + pa_idxset_free(p->connections, free_connection, NULL); + pa_socket_server_unref(p->server); + pa_xfree(p); +} diff --git a/src/pulsecore/protocol-cli.h b/src/pulsecore/protocol-cli.h new file mode 100644 index 00000000..84101e14 --- /dev/null +++ b/src/pulsecore/protocol-cli.h @@ -0,0 +1,35 @@ +#ifndef fooprotocolclihfoo +#define fooprotocolclihfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +typedef struct pa_protocol_cli pa_protocol_cli; + +pa_protocol_cli* pa_protocol_cli_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma); +void pa_protocol_cli_free(pa_protocol_cli *n); + +#endif diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c new file mode 100644 index 00000000..6b9112bf --- /dev/null +++ b/src/pulsecore/protocol-esound.c @@ -0,0 +1,1253 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "endianmacros.h" + +#include "protocol-esound.h" + +/* Don't accept more connection than this */ +#define MAX_CONNECTIONS 10 + +/* Kick a client if it doesn't authenticate within this time */ +#define AUTH_TIMEOUT 5 + +#define DEFAULT_COOKIE_FILE ".esd_auth" + +#define PLAYBACK_BUFFER_SECONDS (.25) +#define PLAYBACK_BUFFER_FRAGMENTS (10) +#define RECORD_BUFFER_SECONDS (5) +#define RECORD_BUFFER_FRAGMENTS (100) + +#define MAX_CACHE_SAMPLE_SIZE (1024000) + +#define SCACHE_PREFIX "esound." + +/* This is heavily based on esound's code */ + +struct connection { + uint32_t index; + int dead; + pa_protocol_esound *protocol; + pa_iochannel *io; + pa_client *client; + int authorized, swap_byte_order; + void *write_data; + size_t write_data_alloc, write_data_index, write_data_length; + void *read_data; + size_t read_data_alloc, read_data_length; + esd_proto_t request; + esd_client_state_t state; + pa_sink_input *sink_input; + pa_source_output *source_output; + pa_memblockq *input_memblockq, *output_memblockq; + pa_defer_event *defer_event; + + char *original_name; + + struct { + pa_memblock *current_memblock; + size_t memblock_index, fragment_size; + } playback; + + struct { + pa_memchunk memchunk; + char *name; + pa_sample_spec sample_spec; + } scache; + + pa_time_event *auth_timeout_event; +}; + +struct pa_protocol_esound { + int public; + pa_module *module; + pa_core *core; + pa_socket_server *server; + pa_idxset *connections; + char *sink_name, *source_name; + unsigned n_player; + uint8_t esd_key[ESD_KEY_LEN]; +}; + +typedef struct proto_handler { + size_t data_length; + int (*proc)(struct connection *c, esd_proto_t request, const void *data, size_t length); + const char *description; +} esd_proto_handler_info_t; + +static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length); +static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk); +static void sink_input_kill_cb(pa_sink_input *i); +static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i); +static pa_usec_t source_output_get_latency_cb(pa_source_output *o); + +static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk); +static void source_output_kill_cb(pa_source_output *o); + +static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_play(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_get_latency(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_server_info(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_sample_get_id(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_standby_or_resume(struct connection *c, esd_proto_t request, const void *data, size_t length); + +/* the big map of protocol handler info */ +static struct proto_handler proto_map[ESD_PROTO_MAX] = { + { ESD_KEY_LEN + sizeof(int), esd_proto_connect, "connect" }, + { ESD_KEY_LEN + sizeof(int), NULL, "lock" }, + { ESD_KEY_LEN + sizeof(int), NULL, "unlock" }, + + { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_play, "stream play" }, + { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream rec" }, + { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream mon" }, + + { ESD_NAME_MAX + 3 * sizeof(int), esd_proto_sample_cache, "sample cache" }, /* 6 */ + { sizeof(int), esd_proto_sample_free_or_play, "sample free" }, + { sizeof(int), esd_proto_sample_free_or_play, "sample play" }, /* 8 */ + { sizeof(int), NULL, "sample loop" }, + { sizeof(int), NULL, "sample stop" }, + { -1, NULL, "TODO: sample kill" }, + + { ESD_KEY_LEN + sizeof(int), esd_proto_standby_or_resume, "standby" }, /* NOOP! */ + { ESD_KEY_LEN + sizeof(int), esd_proto_standby_or_resume, "resume" }, /* NOOP! */ /* 13 */ + + { ESD_NAME_MAX, esd_proto_sample_get_id, "sample getid" }, /* 14 */ + { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" }, + + { sizeof(int), esd_proto_server_info, "server info" }, + { sizeof(int), esd_proto_all_info, "all info" }, + { -1, NULL, "TODO: subscribe" }, + { -1, NULL, "TODO: unsubscribe" }, + + { 3 * sizeof(int), esd_proto_stream_pan, "stream pan"}, + { 3 * sizeof(int), NULL, "sample pan" }, + + { sizeof(int), NULL, "standby mode" }, + { 0, esd_proto_get_latency, "get latency" } +}; + +static void connection_free(struct connection *c) { + assert(c); + pa_idxset_remove_by_data(c->protocol->connections, c, NULL); + + if (c->state == ESD_STREAMING_DATA) + c->protocol->n_player--; + + pa_client_free(c->client); + + if (c->sink_input) { + pa_sink_input_disconnect(c->sink_input); + pa_sink_input_unref(c->sink_input); + } + + if (c->source_output) { + pa_source_output_disconnect(c->source_output); + pa_source_output_unref(c->source_output); + } + + if (c->input_memblockq) + pa_memblockq_free(c->input_memblockq); + if (c->output_memblockq) + pa_memblockq_free(c->output_memblockq); + + if (c->playback.current_memblock) + pa_memblock_unref(c->playback.current_memblock); + + pa_xfree(c->read_data); + pa_xfree(c->write_data); + + if (c->io) + pa_iochannel_free(c->io); + + if (c->defer_event) + c->protocol->core->mainloop->defer_free(c->defer_event); + + if (c->scache.memchunk.memblock) + pa_memblock_unref(c->scache.memchunk.memblock); + pa_xfree(c->scache.name); + + if (c->auth_timeout_event) + c->protocol->core->mainloop->time_free(c->auth_timeout_event); + + pa_xfree(c->original_name); + pa_xfree(c); +} + +static void connection_write_prepare(struct connection *c, size_t length) { + size_t t; + assert(c); + + t = c->write_data_length+length; + + if (c->write_data_alloc < t) + c->write_data = pa_xrealloc(c->write_data, c->write_data_alloc = t); + + assert(c->write_data); +} + +static void connection_write(struct connection *c, const void *data, size_t length) { + size_t i; + assert(c); + + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + + connection_write_prepare(c, length); + + assert(c->write_data); + + i = c->write_data_length; + c->write_data_length += length; + + memcpy((char*)c->write_data + i, data, length); +} + +static void format_esd2native(int format, int swap_bytes, pa_sample_spec *ss) { + assert(ss); + + ss->channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; + if ((format & ESD_MASK_BITS) == ESD_BITS16) + ss->format = swap_bytes ? PA_SAMPLE_S16RE : PA_SAMPLE_S16NE; + else + ss->format = PA_SAMPLE_U8; +} + +static int format_native2esd(pa_sample_spec *ss) { + int format = 0; + + format = (ss->format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16; + format |= (ss->channels >= 2) ? ESD_STEREO : ESD_MONO; + + return format; +} + +#define CHECK_VALIDITY(expression, string) do { \ + if (!(expression)) { \ + pa_log_warn(__FILE__ ": " string); \ + return -1; \ + } \ +} while(0); + +/*** esound commands ***/ + +static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + uint32_t ekey; + int ok; + + assert(length == (ESD_KEY_LEN + sizeof(uint32_t))); + + if (!c->authorized) { + if (memcmp(data, c->protocol->esd_key, ESD_KEY_LEN) != 0) { + pa_log(__FILE__": kicked client with invalid authorization key."); + return -1; + } + + c->authorized = 1; + if (c->auth_timeout_event) { + c->protocol->core->mainloop->time_free(c->auth_timeout_event); + c->auth_timeout_event = NULL; + } + } + + data = (const char*)data + ESD_KEY_LEN; + + memcpy(&ekey, data, sizeof(uint32_t)); + if (ekey == ESD_ENDIAN_KEY) + c->swap_byte_order = 0; + else if (ekey == ESD_SWAP_ENDIAN_KEY) + c->swap_byte_order = 1; + else { + pa_log(__FILE__": client sent invalid endian key"); + return -1; + } + + ok = 1; + connection_write(c, &ok, sizeof(int)); + return 0; +} + +static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + char name[ESD_NAME_MAX], *utf8_name; + int32_t format, rate; + pa_sink *sink; + pa_sample_spec ss; + size_t l; + + assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); + + memcpy(&format, data, sizeof(int32_t)); + format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + data = (const char*)data + sizeof(int32_t); + + memcpy(&rate, data, sizeof(int32_t)); + rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + data = (const char*)data + sizeof(int32_t); + + ss.rate = rate; + format_esd2native(format, c->swap_byte_order, &ss); + + CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification"); + sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1); + CHECK_VALIDITY(sink, "No such sink"); + + strncpy(name, data, sizeof(name)); + name[sizeof(name)-1] = 0; + utf8_name = pa_utf8_filter(name); + + pa_client_set_name(c->client, utf8_name); + c->original_name = pa_xstrdup(name); + + assert(!c->sink_input && !c->input_memblockq); + + c->sink_input = pa_sink_input_new(sink, __FILE__, utf8_name, &ss, NULL, NULL, 0, -1); + + pa_xfree(utf8_name); + + CHECK_VALIDITY(c->sink_input, "Failed to create sink input."); + + l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); + c->input_memblockq = pa_memblockq_new( + 0, + l, + 0, + pa_frame_size(&ss), + (size_t) -1, + l/PLAYBACK_BUFFER_FRAGMENTS, + NULL, + c->protocol->core->memblock_stat); + pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2); + c->playback.fragment_size = l/10; + + c->sink_input->owner = c->protocol->module; + c->sink_input->client = c->client; + c->sink_input->peek = sink_input_peek_cb; + c->sink_input->drop = sink_input_drop_cb; + c->sink_input->kill = sink_input_kill_cb; + c->sink_input->get_latency = sink_input_get_latency_cb; + c->sink_input->userdata = c; + + c->state = ESD_STREAMING_DATA; + + c->protocol->n_player++; + + return 0; +} + +static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length) { + char name[ESD_NAME_MAX], *utf8_name; + int32_t format, rate; + pa_source *source; + pa_sample_spec ss; + size_t l; + + assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); + + memcpy(&format, data, sizeof(int32_t)); + format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + data = (const char*)data + sizeof(int32_t); + + memcpy(&rate, data, sizeof(int32_t)); + rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + data = (const char*)data + sizeof(int32_t); + + ss.rate = rate; + format_esd2native(format, c->swap_byte_order, &ss); + + CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification."); + + if (request == ESD_PROTO_STREAM_MON) { + pa_sink* sink; + + if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { + pa_log(__FILE__": no such sink."); + return -1; + } + + if (!(source = sink->monitor_source)) { + pa_log(__FILE__": no such monitor source."); + return -1; + } + } else { + assert(request == ESD_PROTO_STREAM_REC); + + if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) { + pa_log(__FILE__": no such source."); + return -1; + } + } + + strncpy(name, data, sizeof(name)); + name[sizeof(name)-1] = 0; + + utf8_name = pa_utf8_filter(name); + pa_client_set_name(c->client, utf8_name); + pa_xfree(utf8_name); + + c->original_name = pa_xstrdup(name); + + assert(!c->output_memblockq && !c->source_output); + + if (!(c->source_output = pa_source_output_new(source, __FILE__, c->client->name, &ss, NULL, -1))) { + pa_log(__FILE__": failed to create source output"); + return -1; + } + + l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); + c->output_memblockq = pa_memblockq_new( + 0, + l, + 0, + pa_frame_size(&ss), + 1, + 0, + NULL, + c->protocol->core->memblock_stat); + pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); + + c->source_output->owner = c->protocol->module; + c->source_output->client = c->client; + c->source_output->push = source_output_push_cb; + c->source_output->kill = source_output_kill_cb; + c->source_output->get_latency = source_output_get_latency_cb; + c->source_output->userdata = c; + + c->state = ESD_STREAMING_DATA; + + c->protocol->n_player++; + + return 0; +} + +static int esd_proto_get_latency(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + pa_sink *sink; + int32_t latency; + + assert(c && !data && length == 0); + + if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) + latency = 0; + else { + double usec = pa_sink_get_latency(sink); + latency = (int) ((usec*44100)/1000000); + } + + latency = MAYBE_INT32_SWAP(c->swap_byte_order, latency); + connection_write(c, &latency, sizeof(int32_t)); + return 0; +} + +static int esd_proto_server_info(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + int32_t rate = 44100, format = ESD_STEREO|ESD_BITS16; + int32_t response; + pa_sink *sink; + + assert(c && data && length == sizeof(int32_t)); + + if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { + rate = sink->sample_spec.rate; + format = format_native2esd(&sink->sample_spec); + } + + connection_write_prepare(c, sizeof(int32_t) * 3); + + response = 0; + connection_write(c, &response, sizeof(int32_t)); + rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + connection_write(c, &rate, sizeof(int32_t)); + format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + connection_write(c, &format, sizeof(int32_t)); + + return 0; +} + +static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length) { + size_t t, k, s; + struct connection *conn; + uint32_t idx = PA_IDXSET_INVALID; + unsigned nsamples; + char terminator[sizeof(int32_t)*6+ESD_NAME_MAX]; + + assert(c && data && length == sizeof(int32_t)); + + if (esd_proto_server_info(c, request, data, length) < 0) + return -1; + + k = sizeof(int32_t)*5+ESD_NAME_MAX; + s = sizeof(int32_t)*6+ESD_NAME_MAX; + nsamples = c->protocol->core->scache ? pa_idxset_size(c->protocol->core->scache) : 0; + t = s*(nsamples+1) + k*(c->protocol->n_player+1); + + connection_write_prepare(c, t); + + memset(terminator, 0, sizeof(terminator)); + + for (conn = pa_idxset_first(c->protocol->connections, &idx); conn; conn = pa_idxset_next(c->protocol->connections, &idx)) { + int32_t id, format = ESD_BITS16 | ESD_STEREO, rate = 44100, lvolume = ESD_VOLUME_BASE, rvolume = ESD_VOLUME_BASE; + char name[ESD_NAME_MAX]; + + if (conn->state != ESD_STREAMING_DATA) + continue; + + assert(t >= k*2+s); + + if (conn->sink_input) { + pa_cvolume volume = *pa_sink_input_get_volume(conn->sink_input); + rate = conn->sink_input->sample_spec.rate; + lvolume = (volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; + rvolume = (volume.values[1]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; + format = format_native2esd(&conn->sink_input->sample_spec); + } + + /* id */ + id = MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) (conn->index+1)); + connection_write(c, &id, sizeof(int32_t)); + + /* name */ + memset(name, 0, ESD_NAME_MAX); /* don't leak old data */ + if (conn->original_name) + strncpy(name, conn->original_name, ESD_NAME_MAX); + else if (conn->client && conn->client->name) + strncpy(name, conn->client->name, ESD_NAME_MAX); + connection_write(c, name, ESD_NAME_MAX); + + /* rate */ + rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + connection_write(c, &rate, sizeof(int32_t)); + + /* left */ + lvolume = MAYBE_INT32_SWAP(c->swap_byte_order, lvolume); + connection_write(c, &lvolume, sizeof(int32_t)); + + /*right*/ + rvolume = MAYBE_INT32_SWAP(c->swap_byte_order, rvolume); + connection_write(c, &rvolume, sizeof(int32_t)); + + /*format*/ + format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + connection_write(c, &format, sizeof(int32_t)); + + t -= k; + } + + assert(t == s*(nsamples+1)+k); + t -= k; + + connection_write(c, terminator, k); + + if (nsamples) { + pa_scache_entry *ce; + + idx = PA_IDXSET_INVALID; + for (ce = pa_idxset_first(c->protocol->core->scache, &idx); ce; ce = pa_idxset_next(c->protocol->core->scache, &idx)) { + int32_t id, rate, lvolume, rvolume, format, len; + char name[ESD_NAME_MAX]; + + assert(t >= s*2); + + /* id */ + id = MAYBE_INT32_SWAP(c->swap_byte_order, (int) (ce->index+1)); + connection_write(c, &id, sizeof(int32_t)); + + /* name */ + memset(name, 0, ESD_NAME_MAX); /* don't leak old data */ + if (strncmp(ce->name, SCACHE_PREFIX, sizeof(SCACHE_PREFIX)-1) == 0) + strncpy(name, ce->name+sizeof(SCACHE_PREFIX)-1, ESD_NAME_MAX); + else + snprintf(name, ESD_NAME_MAX, "native.%s", ce->name); + connection_write(c, name, ESD_NAME_MAX); + + /* rate */ + rate = MAYBE_UINT32_SWAP(c->swap_byte_order, ce->sample_spec.rate); + connection_write(c, &rate, sizeof(int32_t)); + + /* left */ + lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); + connection_write(c, &lvolume, sizeof(int32_t)); + + /*right*/ + rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); + connection_write(c, &rvolume, sizeof(int32_t)); + + /*format*/ + format = MAYBE_INT32_SWAP(c->swap_byte_order, format_native2esd(&ce->sample_spec)); + connection_write(c, &format, sizeof(int32_t)); + + /*length*/ + len = MAYBE_INT32_SWAP(c->swap_byte_order, (int) ce->memchunk.length); + connection_write(c, &len, sizeof(int32_t)); + + t -= s; + } + } + + assert(t == s); + + connection_write(c, terminator, s); + + return 0; +} + +static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + int32_t ok; + uint32_t idx, lvolume, rvolume; + struct connection *conn; + + assert(c && data && length == sizeof(int32_t)*3); + + memcpy(&idx, data, sizeof(uint32_t)); + idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; + data = (const char*)data + sizeof(uint32_t); + + memcpy(&lvolume, data, sizeof(uint32_t)); + lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, lvolume); + data = (const char*)data + sizeof(uint32_t); + + memcpy(&rvolume, data, sizeof(uint32_t)); + rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, rvolume); + data = (const char*)data + sizeof(uint32_t); + + if ((conn = pa_idxset_get_by_index(c->protocol->connections, idx)) && conn->sink_input) { + pa_cvolume volume; + volume.values[0] = (lvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; + volume.values[1] = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; + volume.channels = 2; + pa_sink_input_set_volume(conn->sink_input, &volume); + ok = 1; + } else + ok = 0; + + connection_write(c, &ok, sizeof(int32_t)); + + return 0; +} + +static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + pa_sample_spec ss; + int32_t format, rate, sc_length; + uint32_t idx; + char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; + + assert(c && data && length == (ESD_NAME_MAX+3*sizeof(int32_t))); + + memcpy(&format, data, sizeof(int32_t)); + format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + data = (const char*)data + sizeof(int32_t); + + memcpy(&rate, data, sizeof(int32_t)); + rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + data = (const char*)data + sizeof(int32_t); + + ss.rate = rate; + format_esd2native(format, c->swap_byte_order, &ss); + + CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification."); + + memcpy(&sc_length, data, sizeof(int32_t)); + sc_length = MAYBE_INT32_SWAP(c->swap_byte_order, sc_length); + data = (const char*)data + sizeof(int32_t); + + CHECK_VALIDITY(sc_length <= MAX_CACHE_SAMPLE_SIZE, "Sample too large."); + + strcpy(name, SCACHE_PREFIX); + strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX); + name[sizeof(name)-1] = 0; + + CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in sample name."); + + assert(!c->scache.memchunk.memblock); + c->scache.memchunk.memblock = pa_memblock_new(sc_length, c->protocol->core->memblock_stat); + c->scache.memchunk.index = 0; + c->scache.memchunk.length = sc_length; + c->scache.sample_spec = ss; + assert(!c->scache.name); + c->scache.name = pa_xstrdup(name); + + c->state = ESD_CACHING_SAMPLE; + + pa_scache_add_item(c->protocol->core, c->scache.name, NULL, NULL, NULL, &idx); + + idx += 1; + connection_write(c, &idx, sizeof(uint32_t)); + + return 0; +} + +static int esd_proto_sample_get_id(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + int32_t ok; + uint32_t idx; + char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; + + assert(c && data && length == ESD_NAME_MAX); + + strcpy(name, SCACHE_PREFIX); + strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX); + name[sizeof(name)-1] = 0; + + CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in sample name."); + + ok = -1; + if ((idx = pa_scache_get_id_by_name(c->protocol->core, name)) != PA_IDXSET_INVALID) + ok = idx + 1; + + connection_write(c, &ok, sizeof(int32_t)); + + return 0; +} + +static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length) { + int32_t ok; + const char *name; + uint32_t idx; + + assert(c && data && length == sizeof(int32_t)); + + memcpy(&idx, data, sizeof(uint32_t)); + idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; + + ok = 0; + + if ((name = pa_scache_get_name_by_id(c->protocol->core, idx))) { + if (request == ESD_PROTO_SAMPLE_PLAY) { + pa_sink *sink; + + if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) + if (pa_scache_play_item(c->protocol->core, name, sink, PA_VOLUME_NORM) >= 0) + ok = idx + 1; + } else { + assert(request == ESD_PROTO_SAMPLE_FREE); + + if (pa_scache_remove_item(c->protocol->core, name) >= 0) + ok = idx + 1; + } + } + + connection_write(c, &ok, sizeof(int32_t)); + + return 0; +} + +static int esd_proto_standby_or_resume(struct connection *c, PA_GCC_UNUSED esd_proto_t request, PA_GCC_UNUSED const void *data, PA_GCC_UNUSED size_t length) { + int32_t ok; + + connection_write_prepare(c, sizeof(int32_t) * 2); + + ok = 1; + connection_write(c, &ok, sizeof(int32_t)); + connection_write(c, &ok, sizeof(int32_t)); + + return 0; +} + +/*** client callbacks ***/ + +static void client_kill_cb(pa_client *c) { + assert(c && c->userdata); + connection_free(c->userdata); +} + +/*** pa_iochannel callbacks ***/ + +static int do_read(struct connection *c) { + assert(c && c->io); + +/* pa_log("READ"); */ + + if (c->state == ESD_NEXT_REQUEST) { + ssize_t r; + assert(c->read_data_length < sizeof(c->request)); + + if ((r = pa_iochannel_read(c->io, ((uint8_t*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { + pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + return -1; + } + + if ((c->read_data_length+= r) >= sizeof(c->request)) { + struct proto_handler *handler; + + c->request = MAYBE_INT32_SWAP(c->swap_byte_order, c->request); + + if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) { + pa_log(__FILE__": recieved invalid request."); + return -1; + } + + handler = proto_map+c->request; + +/* pa_log(__FILE__": executing request #%u", c->request); */ + + if (!handler->proc) { + pa_log(__FILE__": recieved unimplemented request #%u.", c->request); + return -1; + } + + if (handler->data_length == 0) { + c->read_data_length = 0; + + if (handler->proc(c, c->request, NULL, 0) < 0) + return -1; + + } else { + if (c->read_data_alloc < handler->data_length) + c->read_data = pa_xrealloc(c->read_data, c->read_data_alloc = handler->data_length); + assert(c->read_data); + + c->state = ESD_NEEDS_REQDATA; + c->read_data_length = 0; + } + } + + } else if (c->state == ESD_NEEDS_REQDATA) { + ssize_t r; + struct proto_handler *handler = proto_map+c->request; + + assert(handler->proc); + + assert(c->read_data && c->read_data_length < handler->data_length); + + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { + pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + return -1; + } + + if ((c->read_data_length += r) >= handler->data_length) { + size_t l = c->read_data_length; + assert(handler->proc); + + c->state = ESD_NEXT_REQUEST; + c->read_data_length = 0; + + if (handler->proc(c, c->request, c->read_data, l) < 0) + return -1; + } + } else if (c->state == ESD_CACHING_SAMPLE) { + ssize_t r; + + assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); + + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { + pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + return -1; + } + + c->scache.memchunk.index += r; + assert(c->scache.memchunk.index <= c->scache.memchunk.length); + + if (c->scache.memchunk.index == c->scache.memchunk.length) { + uint32_t idx; + + c->scache.memchunk.index = 0; + pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, NULL, &c->scache.memchunk, &idx); + + pa_memblock_unref(c->scache.memchunk.memblock); + c->scache.memchunk.memblock = NULL; + c->scache.memchunk.index = c->scache.memchunk.length = 0; + + pa_xfree(c->scache.name); + c->scache.name = NULL; + + c->state = ESD_NEXT_REQUEST; + + idx += 1; + connection_write(c, &idx, sizeof(uint32_t)); + } + + } else if (c->state == ESD_STREAMING_DATA && c->sink_input) { + pa_memchunk chunk; + ssize_t r; + size_t l; + + assert(c->input_memblockq); + +/* pa_log("STREAMING_DATA"); */ + + if (!(l = pa_memblockq_missing(c->input_memblockq))) + return 0; + + if (l > c->playback.fragment_size) + l = c->playback.fragment_size; + + if (c->playback.current_memblock) + if (c->playback.current_memblock->length - c->playback.memblock_index < l) { + pa_memblock_unref(c->playback.current_memblock); + c->playback.current_memblock = NULL; + c->playback.memblock_index = 0; + } + + if (!c->playback.current_memblock) { + c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2, c->protocol->core->memblock_stat); + assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); + c->playback.memblock_index = 0; + } + + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { + pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + return -1; + } + + chunk.memblock = c->playback.current_memblock; + chunk.index = c->playback.memblock_index; + chunk.length = r; + assert(chunk.memblock); + + c->playback.memblock_index += r; + + assert(c->input_memblockq); + pa_memblockq_push_align(c->input_memblockq, &chunk); + assert(c->sink_input); + pa_sink_notify(c->sink_input->sink); + } + + return 0; +} + +static int do_write(struct connection *c) { + assert(c && c->io); + +/* pa_log("WRITE"); */ + + if (c->write_data_length) { + ssize_t r; + + assert(c->write_data_index < c->write_data_length); + if ((r = pa_iochannel_write(c->io, (uint8_t*) c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { + pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); + return -1; + } + + if ((c->write_data_index +=r) >= c->write_data_length) + c->write_data_length = c->write_data_index = 0; + + } else if (c->state == ESD_STREAMING_DATA && c->source_output) { + pa_memchunk chunk; + ssize_t r; + + assert(c->output_memblockq); + if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) + return 0; + + assert(chunk.memblock && chunk.length); + + if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { + pa_memblock_unref(chunk.memblock); + pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); + return -1; + } + + pa_memblockq_drop(c->output_memblockq, &chunk, r); + pa_memblock_unref(chunk.memblock); + + pa_source_notify(c->source_output->source); + } + + return 0; +} + +static void do_work(struct connection *c) { + assert(c); + + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 0); + + if (c->dead) + return; + + if (pa_iochannel_is_readable(c->io)) { + if (do_read(c) < 0) + goto fail; + } + + if (c->state == ESD_STREAMING_DATA && c->source_output && pa_iochannel_is_hungup(c->io)) + /* In case we are in capture mode we will never call read() + * on the socket, hence we need to detect the hangup manually + * here, instead of simply waiting for read() to return 0. */ + goto fail; + + if (pa_iochannel_is_writable(c->io)) + if (do_write(c) < 0) + goto fail; + + return; + +fail: + + if (c->state == ESD_STREAMING_DATA && c->sink_input) { + c->dead = 1; + + pa_iochannel_free(c->io); + c->io = NULL; + + pa_memblockq_prebuf_disable(c->input_memblockq); + pa_sink_notify(c->sink_input->sink); + } else + connection_free(c); +} + +static void io_callback(pa_iochannel*io, void *userdata) { + struct connection *c = userdata; + assert(io && c && c->io == io); + + do_work(c); +} + +/*** defer callback ***/ + +static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { + struct connection *c = userdata; + assert(a && c && c->defer_event == e); + +/* pa_log("DEFER"); */ + + do_work(c); +} + +/*** sink_input callbacks ***/ + +static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { + struct connection*c; + assert(i && i->userdata && chunk); + c = i->userdata; + + if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) { + + if (c->dead) + connection_free(c); + + return -1; + } + + return 0; +} + +static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { + struct connection*c = i->userdata; + assert(i && c && length); + +/* pa_log("DROP"); */ + + pa_memblockq_drop(c->input_memblockq, chunk, length); + + /* do something */ + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + + if (!c->dead) + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + +/* assert(pa_memblockq_get_length(c->input_memblockq) > 2048); */ +} + +static void sink_input_kill_cb(pa_sink_input *i) { + assert(i && i->userdata); + connection_free((struct connection *) i->userdata); +} + +static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { + struct connection*c = i->userdata; + assert(i && c); + return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); +} + +/*** source_output callbacks ***/ + +static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { + struct connection *c = o->userdata; + assert(o && c && chunk); + + pa_memblockq_push(c->output_memblockq, chunk); + + /* do something */ + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + + if (!c->dead) + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); +} + +static void source_output_kill_cb(pa_source_output *o) { + assert(o && o->userdata); + connection_free((struct connection *) o->userdata); +} + +static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { + struct connection*c = o->userdata; + assert(o && c); + return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec); +} + +/*** socket server callback ***/ + +static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { + struct connection *c = userdata; + assert(m && tv && c && c->auth_timeout_event == e); + + if (!c->authorized) + connection_free(c); +} + +static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { + struct connection *c; + pa_protocol_esound *p = userdata; + char cname[256], pname[128]; + assert(s && io && p); + + if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { + pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); + pa_iochannel_free(io); + return; + } + + c = pa_xnew(struct connection, 1); + c->protocol = p; + c->io = io; + pa_iochannel_set_callback(c->io, io_callback, c); + + pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname)); + snprintf(cname, sizeof(cname), "EsounD client (%s)", pname); + assert(p->core); + c->client = pa_client_new(p->core, __FILE__, cname); + assert(c->client); + c->client->owner = p->module; + c->client->kill = client_kill_cb; + c->client->userdata = c; + + c->authorized = p->public; + c->swap_byte_order = 0; + c->dead = 0; + + c->read_data_length = 0; + c->read_data = pa_xmalloc(c->read_data_alloc = proto_map[ESD_PROTO_CONNECT].data_length); + + c->write_data_length = c->write_data_index = c->write_data_alloc = 0; + c->write_data = NULL; + + c->state = ESD_NEEDS_REQDATA; + c->request = ESD_PROTO_CONNECT; + + c->sink_input = NULL; + c->input_memblockq = NULL; + + c->source_output = NULL; + c->output_memblockq = NULL; + + c->playback.current_memblock = NULL; + c->playback.memblock_index = 0; + c->playback.fragment_size = 0; + + c->scache.memchunk.length = c->scache.memchunk.index = 0; + c->scache.memchunk.memblock = NULL; + c->scache.name = NULL; + + c->original_name = NULL; + + if (!c->authorized) { + struct timeval tv; + pa_gettimeofday(&tv); + tv.tv_sec += AUTH_TIMEOUT; + c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c); + } else + c->auth_timeout_event = NULL; + + c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c); + assert(c->defer_event); + p->core->mainloop->defer_enable(c->defer_event, 0); + + pa_idxset_put(p->connections, c, &c->index); +} + +/*** entry points ***/ + +pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { + pa_protocol_esound *p; + int public = 0; + assert(core && server && ma); + + p = pa_xnew(pa_protocol_esound, 1); + + if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) { + pa_log(__FILE__": auth-anonymous= expects a boolean argument."); + return NULL; + } + + if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", DEFAULT_COOKIE_FILE), p->esd_key, sizeof(p->esd_key)) < 0) { + pa_xfree(p); + return NULL; + } + + p->module = m; + p->public = public; + p->server = server; + pa_socket_server_set_callback(p->server, on_connection, p); + p->core = core; + p->connections = pa_idxset_new(NULL, NULL); + assert(p->connections); + + p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); + p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL)); + p->n_player = 0; + + return p; +} + +void pa_protocol_esound_free(pa_protocol_esound *p) { + struct connection *c; + assert(p); + + while ((c = pa_idxset_first(p->connections, NULL))) + connection_free(c); + + pa_idxset_free(p->connections, NULL, NULL); + pa_socket_server_unref(p->server); + pa_xfree(p); +} diff --git a/src/pulsecore/protocol-esound.h b/src/pulsecore/protocol-esound.h new file mode 100644 index 00000000..79b5acf0 --- /dev/null +++ b/src/pulsecore/protocol-esound.h @@ -0,0 +1,35 @@ +#ifndef fooprotocolesoundhfoo +#define fooprotocolesoundhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +typedef struct pa_protocol_esound pa_protocol_esound; + +pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma); +void pa_protocol_esound_free(pa_protocol_esound *p); + +#endif diff --git a/src/pulsecore/protocol-http.c b/src/pulsecore/protocol-http.c new file mode 100644 index 00000000..d0d92629 --- /dev/null +++ b/src/pulsecore/protocol-http.c @@ -0,0 +1,268 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "protocol-http.h" + +/* Don't allow more than this many concurrent connections */ +#define MAX_CONNECTIONS 10 + +#define internal_server_error(c) http_message((c), 500, "Internal Server Error", NULL) + +#define URL_ROOT "/" +#define URL_CSS "/style" +#define URL_STATUS "/status" + +struct connection { + pa_protocol_http *protocol; + pa_ioline *line; + enum { REQUEST_LINE, MIME_HEADER, DATA } state; + char *url; +}; + +struct pa_protocol_http { + pa_module *module; + pa_core *core; + pa_socket_server*server; + pa_idxset *connections; +}; + +static void http_response(struct connection *c, int code, const char *msg, const char *mime) { + char s[256]; + assert(c); + assert(msg); + assert(mime); + + snprintf(s, sizeof(s), + "HTTP/1.0 %i %s\n" + "Connection: close\n" + "Content-Type: %s\n" + "Cache-Control: no-cache\n" + "Expires: 0\n" + "Server: "PACKAGE_NAME"/"PACKAGE_VERSION"\n" + "\n", code, msg, mime); + + pa_ioline_puts(c->line, s); +} + +static void http_message(struct connection *c, int code, const char *msg, const char *text) { + char s[256]; + assert(c); + + http_response(c, code, msg, "text/html"); + + if (!text) + text = msg; + + snprintf(s, sizeof(s), + "\n" + "\n" + "%s\n" + "%s\n", + text, text); + + pa_ioline_puts(c->line, s); + pa_ioline_defer_close(c->line); +} + + +static void connection_free(struct connection *c, int del) { + assert(c); + + if (c->url) + pa_xfree(c->url); + + if (del) + pa_idxset_remove_by_data(c->protocol->connections, c, NULL); + pa_ioline_unref(c->line); + pa_xfree(c); +} + +static void line_callback(pa_ioline *line, const char *s, void *userdata) { + struct connection *c = userdata; + assert(line); + assert(c); + + if (!s) { + /* EOF */ + connection_free(c, 1); + return; + } + + switch (c->state) { + case REQUEST_LINE: { + if (memcmp(s, "GET ", 4)) + goto fail; + + s +=4; + + c->url = pa_xstrndup(s, strcspn(s, " \r\n\t?")); + c->state = MIME_HEADER; + break; + + } + + case MIME_HEADER: { + + /* Ignore MIME headers */ + if (strcspn(s, " \r\n") != 0) + break; + + /* We're done */ + c->state = DATA; + + pa_log_info(__FILE__": request for %s", c->url); + + if (!strcmp(c->url, URL_ROOT)) { + char txt[256]; + http_response(c, 200, "OK", "text/html"); + + pa_ioline_puts(c->line, + "\n" + "\n" + ""PACKAGE_NAME" "PACKAGE_VERSION"\n" + "\n"); + + pa_ioline_puts(c->line, + "

      "PACKAGE_NAME" "PACKAGE_VERSION"

      \n" + ""); + +#define PRINTF_FIELD(a,b) pa_ioline_printf(c->line, "\n",(a),(b)) + + PRINTF_FIELD("User Name:", pa_get_user_name(txt, sizeof(txt))); + PRINTF_FIELD("Fully Qualified Domain Name:", pa_get_fqdn(txt, sizeof(txt))); + PRINTF_FIELD("Default Sample Specification:", pa_sample_spec_snprint(txt, sizeof(txt), &c->protocol->core->default_sample_spec)); + PRINTF_FIELD("Default Sink:", pa_namereg_get_default_sink_name(c->protocol->core)); + PRINTF_FIELD("Default Source:", pa_namereg_get_default_source_name(c->protocol->core)); + + pa_ioline_puts(c->line, "
      %s%s
      "); + + pa_ioline_puts(c->line, "

      Click here for an extensive server status report.

      "); + + pa_ioline_puts(c->line, "\n"); + + pa_ioline_defer_close(c->line); + } else if (!strcmp(c->url, URL_CSS)) { + http_response(c, 200, "OK", "text/css"); + + pa_ioline_puts(c->line, + "body { color: black; background-color: white; margin: 0.5cm; }\n" + "a:link, a:visited { color: #900000; }\n" + "p { margin-left: 0.5cm; margin-right: 0.5cm; }\n" + "h1 { color: #00009F; }\n" + "h2 { color: #00009F; }\n" + "ul { margin-left: .5cm; }\n" + "ol { margin-left: .5cm; }\n" + "pre { margin-left: .5cm; background-color: #f0f0f0; padding: 0.4cm;}\n" + ".grey { color: #afafaf; }\n" + "table { margin-left: 1cm; border:1px solid lightgrey; padding: 0.2cm; }\n" + "td { padding-left:10px; padding-right:10px; }\n"); + + pa_ioline_defer_close(c->line); + } else if (!strcmp(c->url, URL_STATUS)) { + char *r; + + http_response(c, 200, "OK", "text/plain"); + r = pa_full_status_string(c->protocol->core); + pa_ioline_puts(c->line, r); + pa_xfree(r); + + pa_ioline_defer_close(c->line); + } else + http_message(c, 404, "Not Found", NULL); + + break; + } + + default: + ; + } + + return; + +fail: + internal_server_error(c); +} + +static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { + pa_protocol_http *p = userdata; + struct connection *c; + assert(s && io && p); + + if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { + pa_log_warn(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); + pa_iochannel_free(io); + return; + } + + c = pa_xmalloc(sizeof(struct connection)); + c->protocol = p; + c->line = pa_ioline_new(io); + c->state = REQUEST_LINE; + c->url = NULL; + + pa_ioline_set_callback(c->line, line_callback, c); + pa_idxset_put(p->connections, c, NULL); +} + +pa_protocol_http* pa_protocol_http_new(pa_core *core, pa_socket_server *server, pa_module *m, PA_GCC_UNUSED pa_modargs *ma) { + pa_protocol_http* p; + assert(core && server); + + p = pa_xmalloc(sizeof(pa_protocol_http)); + p->module = m; + p->core = core; + p->server = server; + p->connections = pa_idxset_new(NULL, NULL); + + pa_socket_server_set_callback(p->server, on_connection, p); + + return p; +} + +static void free_connection(void *p, PA_GCC_UNUSED void *userdata) { + assert(p); + connection_free(p, 0); +} + +void pa_protocol_http_free(pa_protocol_http *p) { + assert(p); + + pa_idxset_free(p->connections, free_connection, NULL); + pa_socket_server_unref(p->server); + pa_xfree(p); +} diff --git a/src/pulsecore/protocol-http.h b/src/pulsecore/protocol-http.h new file mode 100644 index 00000000..5d5dba31 --- /dev/null +++ b/src/pulsecore/protocol-http.h @@ -0,0 +1,35 @@ +#ifndef fooprotocolhttphfoo +#define fooprotocolhttphfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +typedef struct pa_protocol_http pa_protocol_http; + +pa_protocol_http* pa_protocol_http_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma); +void pa_protocol_http_free(pa_protocol_http *n); + +#endif diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c new file mode 100644 index 00000000..1f936e75 --- /dev/null +++ b/src/pulsecore/protocol-native.c @@ -0,0 +1,2398 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "protocol-native.h" + +/* Kick a client if it doesn't authenticate within this time */ +#define AUTH_TIMEOUT 60 + +/* Don't accept more connection than this */ +#define MAX_CONNECTIONS 10 + +#define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */ + +struct connection; +struct pa_protocol_native; + +struct record_stream { + struct connection *connection; + uint32_t index; + pa_source_output *source_output; + pa_memblockq *memblockq; + size_t fragment_size; +}; + +struct playback_stream { + int type; + struct connection *connection; + uint32_t index; + pa_sink_input *sink_input; + pa_memblockq *memblockq; + size_t requested_bytes; + int drain_request; + uint32_t drain_tag; + uint32_t syncid; + int underrun; + + /* Sync group members */ + PA_LLIST_FIELDS(struct playback_stream); +}; + +struct upload_stream { + int type; + struct connection *connection; + uint32_t index; + pa_memchunk memchunk; + size_t length; + char *name; + pa_sample_spec sample_spec; + pa_channel_map channel_map; +}; + +struct output_stream { + int type; +}; + +enum { + UPLOAD_STREAM, + PLAYBACK_STREAM +}; + +struct connection { + int authorized; + uint32_t version; + pa_protocol_native *protocol; + pa_client *client; + pa_pstream *pstream; + pa_pdispatch *pdispatch; + pa_idxset *record_streams, *output_streams; + uint32_t rrobin_index; + pa_subscription *subscription; + pa_time_event *auth_timeout_event; +}; + +struct pa_protocol_native { + pa_module *module; + int public; + pa_core *core; + pa_socket_server *server; + pa_idxset *connections; + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; + int auth_cookie_in_property; +#ifdef SCM_CREDENTIALS + char *auth_group; +#endif +}; + +static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk); +static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length); +static void sink_input_kill_cb(pa_sink_input *i); +static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i); + +static void request_bytes(struct playback_stream*s); + +static void source_output_kill_cb(pa_source_output *o); +static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk); +static pa_usec_t source_output_get_latency_cb(pa_source_output *o); + +static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_set_mute(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_flush_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_trigger_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_add_autoload(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_remove_autoload(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_autoload_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_get_autoload_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); + +static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = NULL, + [PA_COMMAND_TIMEOUT] = NULL, + [PA_COMMAND_REPLY] = NULL, + [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream, + [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream, + [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream, + [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream, + [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream, + [PA_COMMAND_AUTH] = command_auth, + [PA_COMMAND_REQUEST] = NULL, + [PA_COMMAND_EXIT] = command_exit, + [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name, + [PA_COMMAND_LOOKUP_SINK] = command_lookup, + [PA_COMMAND_LOOKUP_SOURCE] = command_lookup, + [PA_COMMAND_STAT] = command_stat, + [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency, + [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency, + [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream, + [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream, + [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream, + [PA_COMMAND_PLAY_SAMPLE] = command_play_sample, + [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample, + [PA_COMMAND_GET_SINK_INFO] = command_get_info, + [PA_COMMAND_GET_SOURCE_INFO] = command_get_info, + [PA_COMMAND_GET_CLIENT_INFO] = command_get_info, + [PA_COMMAND_GET_MODULE_INFO] = command_get_info, + [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info, + [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info, + [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info, + [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list, + [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info, + [PA_COMMAND_SUBSCRIBE] = command_subscribe, + + [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume, + [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume, + [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume, + + [PA_COMMAND_SET_SINK_MUTE] = command_set_mute, + [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute, + + [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream, + [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_flush_playback_stream, + [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_prebuf_playback_stream, + [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_prebuf_playback_stream, + + [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream, + [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream, + + [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source, + [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source, + [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name, + [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name, + [PA_COMMAND_KILL_CLIENT] = command_kill, + [PA_COMMAND_KILL_SINK_INPUT] = command_kill, + [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill, + [PA_COMMAND_LOAD_MODULE] = command_load_module, + [PA_COMMAND_UNLOAD_MODULE] = command_unload_module, + [PA_COMMAND_GET_AUTOLOAD_INFO] = command_get_autoload_info, + [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = command_get_autoload_info_list, + [PA_COMMAND_ADD_AUTOLOAD] = command_add_autoload, + [PA_COMMAND_REMOVE_AUTOLOAD] = command_remove_autoload +}; + +/* structure management */ + +static struct upload_stream* upload_stream_new( + struct connection *c, + const pa_sample_spec *ss, + const pa_channel_map *map, + const char *name, size_t length) { + + struct upload_stream *s; + assert(c && ss && name && length); + + s = pa_xnew(struct upload_stream, 1); + s->type = UPLOAD_STREAM; + s->connection = c; + s->sample_spec = *ss; + s->channel_map = *map; + s->name = pa_xstrdup(name); + + s->memchunk.memblock = NULL; + s->memchunk.index = 0; + s->memchunk.length = 0; + + s->length = length; + + pa_idxset_put(c->output_streams, s, &s->index); + return s; +} + +static void upload_stream_free(struct upload_stream *o) { + assert(o && o->connection); + + pa_idxset_remove_by_data(o->connection->output_streams, o, NULL); + + pa_xfree(o->name); + + if (o->memchunk.memblock) + pa_memblock_unref(o->memchunk.memblock); + + pa_xfree(o); +} + +static struct record_stream* record_stream_new( + struct connection *c, + pa_source *source, + const pa_sample_spec *ss, + const pa_channel_map *map, + const char *name, + size_t maxlength, + size_t fragment_size) { + + struct record_stream *s; + pa_source_output *source_output; + size_t base; + assert(c && source && ss && name && maxlength); + + if (!(source_output = pa_source_output_new(source, __FILE__, name, ss, map, -1))) + return NULL; + + s = pa_xnew(struct record_stream, 1); + s->connection = c; + s->source_output = source_output; + s->source_output->push = source_output_push_cb; + s->source_output->kill = source_output_kill_cb; + s->source_output->get_latency = source_output_get_latency_cb; + s->source_output->userdata = s; + s->source_output->owner = c->protocol->module; + s->source_output->client = c->client; + + s->memblockq = pa_memblockq_new( + 0, + maxlength, + 0, + base = pa_frame_size(ss), + 1, + 0, + NULL, + c->protocol->core->memblock_stat); + assert(s->memblockq); + + s->fragment_size = (fragment_size/base)*base; + if (!s->fragment_size) + s->fragment_size = base; + + pa_idxset_put(c->record_streams, s, &s->index); + return s; +} + +static void record_stream_free(struct record_stream* r) { + assert(r && r->connection); + + pa_idxset_remove_by_data(r->connection->record_streams, r, NULL); + pa_source_output_disconnect(r->source_output); + pa_source_output_unref(r->source_output); + pa_memblockq_free(r->memblockq); + pa_xfree(r); +} + +static struct playback_stream* playback_stream_new( + struct connection *c, + pa_sink *sink, + const pa_sample_spec *ss, + const pa_channel_map *map, + const char *name, + size_t maxlength, + size_t tlength, + size_t prebuf, + size_t minreq, + pa_cvolume *volume, + uint32_t syncid) { + + struct playback_stream *s, *ssync; + pa_sink_input *sink_input; + pa_memblock *silence; + uint32_t idx; + int64_t start_index; + + assert(c && sink && ss && name && maxlength); + + /* Find syncid group */ + for (ssync = pa_idxset_first(c->output_streams, &idx); ssync; ssync = pa_idxset_next(c->output_streams, &idx)) { + + if (ssync->type != PLAYBACK_STREAM) + continue; + + if (ssync->syncid == syncid) + break; + } + + /* Synced streams must connect to the same sink */ + if (ssync && ssync->sink_input->sink != sink) + return NULL; + + if (!(sink_input = pa_sink_input_new(sink, __FILE__, name, ss, map, volume, 0, -1))) + return NULL; + + s = pa_xnew(struct playback_stream, 1); + s->type = PLAYBACK_STREAM; + s->connection = c; + s->syncid = syncid; + s->sink_input = sink_input; + s->underrun = 1; + + s->sink_input->peek = sink_input_peek_cb; + s->sink_input->drop = sink_input_drop_cb; + s->sink_input->kill = sink_input_kill_cb; + s->sink_input->get_latency = sink_input_get_latency_cb; + s->sink_input->userdata = s; + s->sink_input->owner = c->protocol->module; + s->sink_input->client = c->client; + + if (ssync) { + /* Sync id found, now find head of list */ + PA_LLIST_FIND_HEAD(struct playback_stream, ssync, &ssync); + + /* Prepend ourselves */ + PA_LLIST_PREPEND(struct playback_stream, ssync, s); + + /* Set our start index to the current read index of the other grozp member(s) */ + assert(ssync->next); + start_index = pa_memblockq_get_read_index(ssync->next->memblockq); + } else { + /* This ia a new sync group */ + PA_LLIST_INIT(struct playback_stream, s); + start_index = 0; + } + + silence = pa_silence_memblock_new(ss, 0, c->protocol->core->memblock_stat); + + s->memblockq = pa_memblockq_new( + start_index, + maxlength, + tlength, + pa_frame_size(ss), + prebuf, + minreq, + silence, + c->protocol->core->memblock_stat); + + pa_memblock_unref(silence); + + s->requested_bytes = 0; + s->drain_request = 0; + + pa_idxset_put(c->output_streams, s, &s->index); + + return s; +} + +static void playback_stream_free(struct playback_stream* p) { + struct playback_stream *head; + assert(p && p->connection); + + if (p->drain_request) + pa_pstream_send_error(p->connection->pstream, p->drain_tag, PA_ERR_NOENTITY); + + PA_LLIST_FIND_HEAD(struct playback_stream, p, &head); + PA_LLIST_REMOVE(struct playback_stream, head, p); + + pa_idxset_remove_by_data(p->connection->output_streams, p, NULL); + pa_sink_input_disconnect(p->sink_input); + pa_sink_input_unref(p->sink_input); + pa_memblockq_free(p->memblockq); + pa_xfree(p); +} + +static void connection_free(struct connection *c) { + struct record_stream *r; + struct output_stream *o; + assert(c && c->protocol); + + pa_idxset_remove_by_data(c->protocol->connections, c, NULL); + while ((r = pa_idxset_first(c->record_streams, NULL))) + record_stream_free(r); + pa_idxset_free(c->record_streams, NULL, NULL); + + while ((o = pa_idxset_first(c->output_streams, NULL))) + if (o->type == PLAYBACK_STREAM) + playback_stream_free((struct playback_stream*) o); + else + upload_stream_free((struct upload_stream*) o); + pa_idxset_free(c->output_streams, NULL, NULL); + + pa_pdispatch_unref(c->pdispatch); + pa_pstream_close(c->pstream); + pa_pstream_unref(c->pstream); + pa_client_free(c->client); + + if (c->subscription) + pa_subscription_free(c->subscription); + + if (c->auth_timeout_event) + c->protocol->core->mainloop->time_free(c->auth_timeout_event); + + pa_xfree(c); +} + +static void request_bytes(struct playback_stream *s) { + pa_tagstruct *t; + size_t l; + assert(s); + + if (!(l = pa_memblockq_missing(s->memblockq))) + return; + + if (l <= s->requested_bytes) + return; + + l -= s->requested_bytes; + + if (l < pa_memblockq_get_minreq(s->memblockq)) + return; + + s->requested_bytes += l; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_REQUEST); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, s->index); + pa_tagstruct_putu32(t, l); + pa_pstream_send_tagstruct(s->connection->pstream, t); + +/* pa_log(__FILE__": Requesting %u bytes", l); */ +} + +static void send_memblock(struct connection *c) { + uint32_t start; + struct record_stream *r; + + start = PA_IDXSET_INVALID; + for (;;) { + pa_memchunk chunk; + + if (!(r = pa_idxset_rrobin(c->record_streams, &c->rrobin_index))) + return; + + if (start == PA_IDXSET_INVALID) + start = c->rrobin_index; + else if (start == c->rrobin_index) + return; + + if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) { + pa_memchunk schunk = chunk; + + if (schunk.length > r->fragment_size) + schunk.length = r->fragment_size; + + pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk); + pa_memblockq_drop(r->memblockq, &chunk, schunk.length); + pa_memblock_unref(schunk.memblock); + + return; + } + } +} + +static void send_playback_stream_killed(struct playback_stream *p) { + pa_tagstruct *t; + assert(p); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, p->index); + pa_pstream_send_tagstruct(p->connection->pstream, t); +} + +static void send_record_stream_killed(struct record_stream *r) { + pa_tagstruct *t; + assert(r); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, r->index); + pa_pstream_send_tagstruct(r->connection->pstream, t); +} + +/*** sinkinput callbacks ***/ + +static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { + struct playback_stream *s; + assert(i && i->userdata && chunk); + s = i->userdata; + + if (pa_memblockq_get_length(s->memblockq) <= 0 && !s->underrun) { + pa_tagstruct *t; + + /* Report that we're empty */ + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, s->index); + pa_pstream_send_tagstruct(s->connection->pstream, t); + + s->underrun = 1; + } + + if (pa_memblockq_peek(s->memblockq, chunk) < 0) { +/* pa_log(__FILE__": peek: failure"); */ + return -1; + } + +/* pa_log(__FILE__": peek: %u", chunk->length); */ + + return 0; +} + +static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { + struct playback_stream *s; + assert(i && i->userdata && length); + s = i->userdata; + + pa_memblockq_drop(s->memblockq, chunk, length); + + request_bytes(s); + + if (s->drain_request && !pa_memblockq_is_readable(s->memblockq)) { + pa_pstream_send_simple_ack(s->connection->pstream, s->drain_tag); + s->drain_request = 0; + } + +/* pa_log(__FILE__": after_drop: %u %u", pa_memblockq_get_length(s->memblockq), pa_memblockq_is_readable(s->memblockq)); */ +} + +static void sink_input_kill_cb(pa_sink_input *i) { + assert(i && i->userdata); + send_playback_stream_killed((struct playback_stream *) i->userdata); + playback_stream_free((struct playback_stream *) i->userdata); +} + +static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { + struct playback_stream *s; + assert(i && i->userdata); + s = i->userdata; + + /*pa_log(__FILE__": get_latency: %u", pa_memblockq_get_length(s->memblockq));*/ + + return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec); +} + +/*** source_output callbacks ***/ + +static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { + struct record_stream *s; + assert(o && o->userdata && chunk); + s = o->userdata; + + if (pa_memblockq_push_align(s->memblockq, chunk) < 0) { + pa_log_warn(__FILE__": Failed to push data into output queue."); + return; + } + + if (!pa_pstream_is_pending(s->connection->pstream)) + send_memblock(s->connection); +} + +static void source_output_kill_cb(pa_source_output *o) { + assert(o && o->userdata); + send_record_stream_killed((struct record_stream *) o->userdata); + record_stream_free((struct record_stream *) o->userdata); +} + +static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { + struct record_stream *s; + assert(o && o->userdata); + s = o->userdata; + + /*pa_log(__FILE__": get_latency: %u", pa_memblockq_get_length(s->memblockq));*/ + + return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec); +} + +/*** pdispatch callbacks ***/ + +static void protocol_error(struct connection *c) { + pa_log(__FILE__": protocol error, kicking client"); + connection_free(c); +} + +#define CHECK_VALIDITY(pstream, expression, tag, error) do { \ +if (!(expression)) { \ + pa_pstream_send_error((pstream), (tag), (error)); \ + return; \ +} \ +} while(0); + +static pa_tagstruct *reply_new(uint32_t tag) { + pa_tagstruct *reply; + + reply = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + return reply; +} + +static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + struct playback_stream *s; + uint32_t maxlength, tlength, prebuf, minreq, sink_index, syncid; + const char *name, *sink_name; + pa_sample_spec ss; + pa_channel_map map; + pa_tagstruct *reply; + pa_sink *sink; + pa_cvolume volume; + int corked; + + assert(c && t && c->protocol && c->protocol->core); + + if (pa_tagstruct_get( + t, + PA_TAG_STRING, &name, + PA_TAG_SAMPLE_SPEC, &ss, + PA_TAG_CHANNEL_MAP, &map, + PA_TAG_U32, &sink_index, + PA_TAG_STRING, &sink_name, + PA_TAG_U32, &maxlength, + PA_TAG_BOOLEAN, &corked, + PA_TAG_U32, &tlength, + PA_TAG_U32, &prebuf, + PA_TAG_U32, &minreq, + PA_TAG_U32, &syncid, + PA_TAG_CVOLUME, &volume, + PA_TAG_INVALID) < 0 || + !pa_tagstruct_eof(t) || + !name) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, sink_index != PA_INVALID_INDEX || !sink_name || (*sink_name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, maxlength > 0 && maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); + + if (sink_index != PA_INVALID_INDEX) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); + else + sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1); + + CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); + + s = playback_stream_new(c, sink, &ss, &map, name, maxlength, tlength, prebuf, minreq, &volume, syncid); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); + + pa_sink_input_cork(s->sink_input, corked); + + reply = reply_new(tag); + pa_tagstruct_putu32(reply, s->index); + assert(s->sink_input); + pa_tagstruct_putu32(reply, s->sink_input->index); + pa_tagstruct_putu32(reply, s->requested_bytes = pa_memblockq_missing(s->memblockq)); + + if (c->version >= 9) { + /* Since 0.9 we support sending the buffer metrics back to the client */ + + pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_maxlength(s->memblockq)); + pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_tlength(s->memblockq)); + pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_prebuf(s->memblockq)); + pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_minreq(s->memblockq)); + } + + pa_pstream_send_tagstruct(c->pstream, reply); + request_bytes(s); +} + +static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t channel; + assert(c && t); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + + if (command == PA_COMMAND_DELETE_PLAYBACK_STREAM) { + struct playback_stream *s; + if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != PLAYBACK_STREAM)) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); + return; + } + + playback_stream_free(s); + } else if (command == PA_COMMAND_DELETE_RECORD_STREAM) { + struct record_stream *s; + if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); + return; + } + + record_stream_free(s); + } else { + struct upload_stream *s; + assert(command == PA_COMMAND_DELETE_UPLOAD_STREAM); + if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != UPLOAD_STREAM)) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); + return; + } + + upload_stream_free(s); + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + struct record_stream *s; + uint32_t maxlength, fragment_size; + uint32_t source_index; + const char *name, *source_name; + pa_sample_spec ss; + pa_channel_map map; + pa_tagstruct *reply; + pa_source *source; + int corked; + assert(c && t && c->protocol && c->protocol->core); + + if (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_get_channel_map(t, &map) < 0 || + pa_tagstruct_getu32(t, &source_index) < 0 || + pa_tagstruct_gets(t, &source_name) < 0 || + pa_tagstruct_getu32(t, &maxlength) < 0 || + pa_tagstruct_get_boolean(t, &corked) < 0 || + pa_tagstruct_getu32(t, &fragment_size) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, source_index != PA_INVALID_INDEX || !source_name || (*source_name && pa_utf8_valid(source_name)), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); + + if (source_index != PA_INVALID_INDEX) + source = pa_idxset_get_by_index(c->protocol->core->sources, source_index); + else + source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE, 1); + + CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY); + + s = record_stream_new(c, source, &ss, &map, name, maxlength, fragment_size); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); + + pa_source_output_cork(s->source_output, corked); + + reply = reply_new(tag); + pa_tagstruct_putu32(reply, s->index); + assert(s->source_output); + pa_tagstruct_putu32(reply, s->source_output->index); + + if (c->version >= 9) { + /* Since 0.9 we support sending the buffer metrics back to the client */ + + pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_maxlength(s->memblockq)); + pa_tagstruct_putu32(reply, (uint32_t) s->fragment_size); + } + + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_exit(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + assert(c && t); + + if (!pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop); + c->protocol->core->mainloop->quit(c->protocol->core->mainloop, 0); + pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */ +} + +static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const void*cookie; + pa_tagstruct *reply; + assert(c && t); + + if (pa_tagstruct_getu32(t, &c->version) < 0 || + pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + /* Minimum supported version */ + if (c->version < 8) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION); + return; + } + + if (!c->authorized) { + int success = 0; + +#ifdef SCM_CREDENTIALS + const struct ucred *ucred = pa_pdispatch_creds(pd); + + if (ucred) { + if (ucred->uid == getuid()) + success = 1; + else if (c->protocol->auth_group) { + int r; + + if ((r = pa_uid_in_group(ucred->uid, c->protocol->auth_group)) < 0) + pa_log_warn(__FILE__": failed to check group membership."); + else if (r > 0) + success = 1; + } + + pa_log_info(__FILE__": Got credentials: pid=%lu uid=%lu gid=%lu auth=%i", + (unsigned long) ucred->pid, + (unsigned long) ucred->uid, + (unsigned long) ucred->gid, + success); + } +#endif + + if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) == 0) + success = 1; + + if (!success) { + pa_log_warn(__FILE__": Denied access to client with invalid authorization data."); + pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); + return; + } + + c->authorized = 1; + if (c->auth_timeout_event) { + c->protocol->core->mainloop->time_free(c->auth_timeout_event); + c->auth_timeout_event = NULL; + } + } + + reply = reply_new(tag); + pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_set_client_name(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const char *name; + assert(c && t); + + if (pa_tagstruct_gets(t, &name) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID); + + pa_client_set_name(c->client, name); + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const char *name; + uint32_t idx = PA_IDXSET_INVALID; + assert(c && t); + + if (pa_tagstruct_gets(t, &name) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); + + if (command == PA_COMMAND_LOOKUP_SINK) { + pa_sink *sink; + if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1))) + idx = sink->index; + } else { + pa_source *source; + assert(command == PA_COMMAND_LOOKUP_SOURCE); + if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1))) + idx = source->index; + } + + if (idx == PA_IDXSET_INVALID) + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); + else { + pa_tagstruct *reply; + reply = reply_new(tag); + pa_tagstruct_putu32(reply, idx); + pa_pstream_send_tagstruct(c->pstream, reply); + } +} + +static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + struct playback_stream *s; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + s = pa_idxset_get_by_index(c->output_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); + + s->drain_request = 0; + + pa_memblockq_prebuf_disable(s->memblockq); + + if (!pa_memblockq_is_readable(s->memblockq)) { +/* pa_log("immediate drain: %u", pa_memblockq_get_length(s->memblockq)); */ + pa_pstream_send_simple_ack(c->pstream, tag); + } else { +/* pa_log("slow drain triggered"); */ + s->drain_request = 1; + s->drain_tag = tag; + + pa_sink_notify(s->sink_input->sink); + } +} + +static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + pa_tagstruct *reply; + assert(c && t); + + if (!pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + + reply = reply_new(tag); + pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->total); + pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->total_size); + pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->allocated); + pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->allocated_size); + pa_tagstruct_putu32(reply, pa_scache_total_size(c->protocol->core)); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + pa_tagstruct *reply; + struct playback_stream *s; + struct timeval tv, now; + uint32_t idx; + pa_usec_t latency; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_get_timeval(t, &tv) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + s = pa_idxset_get_by_index(c->output_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); + + reply = reply_new(tag); + + latency = pa_sink_get_latency(s->sink_input->sink); + if (s->sink_input->resampled_chunk.memblock) + latency += pa_bytes_to_usec(s->sink_input->resampled_chunk.length, &s->sink_input->sample_spec); + pa_tagstruct_put_usec(reply, latency); + + pa_tagstruct_put_usec(reply, 0); + pa_tagstruct_put_boolean(reply, pa_memblockq_is_readable(s->memblockq)); + pa_tagstruct_put_timeval(reply, &tv); + pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now)); + pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq)); + pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq)); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + pa_tagstruct *reply; + struct record_stream *s; + struct timeval tv, now; + uint32_t idx; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_get_timeval(t, &tv) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + s = pa_idxset_get_by_index(c->record_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + + reply = reply_new(tag); + pa_tagstruct_put_usec(reply, s->source_output->source->monitor_of ? pa_sink_get_latency(s->source_output->source->monitor_of) : 0); + pa_tagstruct_put_usec(reply, pa_source_get_latency(s->source_output->source)); + pa_tagstruct_put_boolean(reply, 0); + pa_tagstruct_put_timeval(reply, &tv); + pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now)); + pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq)); + pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq)); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + struct upload_stream *s; + uint32_t length; + const char *name; + pa_sample_spec ss; + pa_channel_map map; + pa_tagstruct *reply; + assert(c && t && c->protocol && c->protocol->core); + + if (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_get_channel_map(t, &map) < 0 || + pa_tagstruct_getu32(t, &length) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE); + CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); + + s = upload_stream_new(c, &ss, &map, name, length); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); + + reply = reply_new(tag); + pa_tagstruct_putu32(reply, s->index); + pa_tagstruct_putu32(reply, length); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t channel; + struct upload_stream *s; + uint32_t idx; + assert(c && t); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + + s = pa_idxset_get_by_index(c->output_streams, channel); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, s->type == UPLOAD_STREAM, tag, PA_ERR_NOENTITY); + + if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, &idx) < 0) + pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL); + else + pa_pstream_send_simple_ack(c->pstream, tag); + + upload_stream_free(s); +} + +static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t sink_index; + pa_volume_t volume; + pa_sink *sink; + const char *name, *sink_name; + assert(c && t); + + if (pa_tagstruct_getu32(t, &sink_index) < 0 || + pa_tagstruct_gets(t, &sink_name) < 0 || + pa_tagstruct_getu32(t, &volume) < 0 || + pa_tagstruct_gets(t, &name) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, sink_index != PA_INVALID_INDEX || !sink_name || (*sink_name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); + + if (sink_index != PA_INVALID_INDEX) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); + else + sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1); + + CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); + + if (pa_scache_play_item(c->protocol->core, name, sink, volume) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); + return; + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_remove_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const char *name; + assert(c && t); + + if (pa_tagstruct_gets(t, &name) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); + + if (pa_scache_remove_item(c->protocol->core, name) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); + return; + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void sink_fill_tagstruct(pa_tagstruct *t, pa_sink *sink) { + assert(t && sink); + pa_tagstruct_put( + t, + PA_TAG_U32, sink->index, + PA_TAG_STRING, sink->name, + PA_TAG_STRING, sink->description, + PA_TAG_SAMPLE_SPEC, &sink->sample_spec, + PA_TAG_CHANNEL_MAP, &sink->channel_map, + PA_TAG_U32, sink->owner ? sink->owner->index : PA_INVALID_INDEX, + PA_TAG_CVOLUME, pa_sink_get_volume(sink, PA_MIXER_HARDWARE), + PA_TAG_BOOLEAN, pa_sink_get_mute(sink, PA_MIXER_HARDWARE), + PA_TAG_U32, sink->monitor_source->index, + PA_TAG_STRING, sink->monitor_source->name, + PA_TAG_USEC, pa_sink_get_latency(sink), + PA_TAG_STRING, sink->driver, + PA_TAG_U32, (sink->get_hw_volume ? PA_SINK_HW_VOLUME_CTRL : 0) | (sink->get_latency ? PA_SINK_LATENCY : 0), + PA_TAG_INVALID); +} + +static void source_fill_tagstruct(pa_tagstruct *t, pa_source *source) { + assert(t && source); + pa_tagstruct_put( + t, + PA_TAG_U32, source->index, + PA_TAG_STRING, source->name, + PA_TAG_STRING, source->description, + PA_TAG_SAMPLE_SPEC, &source->sample_spec, + PA_TAG_CHANNEL_MAP, &source->channel_map, + PA_TAG_U32, source->owner ? source->owner->index : PA_INVALID_INDEX, + PA_TAG_CVOLUME, pa_source_get_volume(source, PA_MIXER_HARDWARE), + PA_TAG_BOOLEAN, pa_source_get_mute(source, PA_MIXER_HARDWARE), + PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX, + PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL, + PA_TAG_USEC, pa_source_get_latency(source), + PA_TAG_STRING, source->driver, + PA_TAG_U32, (source->get_hw_volume ? PA_SOURCE_HW_VOLUME_CTRL : 0) | (source->get_latency ? PA_SOURCE_LATENCY : 0), + PA_TAG_INVALID); +} + +static void client_fill_tagstruct(pa_tagstruct *t, pa_client *client) { + assert(t && client); + pa_tagstruct_putu32(t, client->index); + pa_tagstruct_puts(t, client->name); + pa_tagstruct_putu32(t, client->owner ? client->owner->index : PA_INVALID_INDEX); + pa_tagstruct_puts(t, client->driver); +} + +static void module_fill_tagstruct(pa_tagstruct *t, pa_module *module) { + assert(t && module); + pa_tagstruct_putu32(t, module->index); + pa_tagstruct_puts(t, module->name); + pa_tagstruct_puts(t, module->argument); + pa_tagstruct_putu32(t, module->n_used); + pa_tagstruct_put_boolean(t, module->auto_unload); +} + +static void sink_input_fill_tagstruct(pa_tagstruct *t, pa_sink_input *s) { + assert(t && s); + pa_tagstruct_putu32(t, s->index); + pa_tagstruct_puts(t, s->name); + pa_tagstruct_putu32(t, s->owner ? s->owner->index : PA_INVALID_INDEX); + pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX); + pa_tagstruct_putu32(t, s->sink->index); + pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_put_channel_map(t, &s->channel_map); + pa_tagstruct_put_cvolume(t, &s->volume); + pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s)); + pa_tagstruct_put_usec(t, pa_sink_get_latency(s->sink)); + pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s))); + pa_tagstruct_puts(t, s->driver); +} + +static void source_output_fill_tagstruct(pa_tagstruct *t, pa_source_output *s) { + assert(t && s); + pa_tagstruct_putu32(t, s->index); + pa_tagstruct_puts(t, s->name); + pa_tagstruct_putu32(t, s->owner ? s->owner->index : PA_INVALID_INDEX); + pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX); + pa_tagstruct_putu32(t, s->source->index); + pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_put_channel_map(t, &s->channel_map); + pa_tagstruct_put_usec(t, pa_source_output_get_latency(s)); + pa_tagstruct_put_usec(t, pa_source_get_latency(s->source)); + pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s))); + pa_tagstruct_puts(t, s->driver); +} + +static void scache_fill_tagstruct(pa_tagstruct *t, pa_scache_entry *e) { + assert(t && e); + pa_tagstruct_putu32(t, e->index); + pa_tagstruct_puts(t, e->name); + pa_tagstruct_put_cvolume(t, &e->volume); + pa_tagstruct_put_usec(t, pa_bytes_to_usec(e->memchunk.length, &e->sample_spec)); + pa_tagstruct_put_sample_spec(t, &e->sample_spec); + pa_tagstruct_put_channel_map(t, &e->channel_map); + pa_tagstruct_putu32(t, e->memchunk.length); + pa_tagstruct_put_boolean(t, e->lazy); + pa_tagstruct_puts(t, e->filename); +} + +static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + pa_sink *sink = NULL; + pa_source *source = NULL; + pa_client *client = NULL; + pa_module *module = NULL; + pa_sink_input *si = NULL; + pa_source_output *so = NULL; + pa_scache_entry *sce = NULL; + const char *name; + pa_tagstruct *reply; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + (command != PA_COMMAND_GET_CLIENT_INFO && + command != PA_COMMAND_GET_MODULE_INFO && + command != PA_COMMAND_GET_SINK_INPUT_INFO && + command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO && + pa_tagstruct_gets(t, &name) < 0) || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); + + if (command == PA_COMMAND_GET_SINK_INFO) { + if (idx != PA_INVALID_INDEX) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); + else + sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); + } else if (command == PA_COMMAND_GET_SOURCE_INFO) { + if (idx != PA_INVALID_INDEX) + source = pa_idxset_get_by_index(c->protocol->core->sources, idx); + else + source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); + } else if (command == PA_COMMAND_GET_CLIENT_INFO) + client = pa_idxset_get_by_index(c->protocol->core->clients, idx); + else if (command == PA_COMMAND_GET_MODULE_INFO) + module = pa_idxset_get_by_index(c->protocol->core->modules, idx); + else if (command == PA_COMMAND_GET_SINK_INPUT_INFO) + si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); + else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO) + so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); + else { + assert(command == PA_COMMAND_GET_SAMPLE_INFO); + if (idx != PA_INVALID_INDEX) + sce = pa_idxset_get_by_index(c->protocol->core->scache, idx); + else + sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE, 0); + } + + if (!sink && !source && !client && !module && !si && !so && !sce) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); + return; + } + + reply = reply_new(tag); + if (sink) + sink_fill_tagstruct(reply, sink); + else if (source) + source_fill_tagstruct(reply, source); + else if (client) + client_fill_tagstruct(reply, client); + else if (module) + module_fill_tagstruct(reply, module); + else if (si) + sink_input_fill_tagstruct(reply, si); + else if (so) + source_output_fill_tagstruct(reply, so); + else + scache_fill_tagstruct(reply, sce); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + pa_idxset *i; + uint32_t idx; + void *p; + pa_tagstruct *reply; + assert(c && t); + + if (!pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + + reply = reply_new(tag); + + if (command == PA_COMMAND_GET_SINK_INFO_LIST) + i = c->protocol->core->sinks; + else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST) + i = c->protocol->core->sources; + else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST) + i = c->protocol->core->clients; + else if (command == PA_COMMAND_GET_MODULE_INFO_LIST) + i = c->protocol->core->modules; + else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) + i = c->protocol->core->sink_inputs; + else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST) + i = c->protocol->core->source_outputs; + else { + assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); + i = c->protocol->core->scache; + } + + if (i) { + for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) { + if (command == PA_COMMAND_GET_SINK_INFO_LIST) + sink_fill_tagstruct(reply, p); + else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST) + source_fill_tagstruct(reply, p); + else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST) + client_fill_tagstruct(reply, p); + else if (command == PA_COMMAND_GET_MODULE_INFO_LIST) + module_fill_tagstruct(reply, p); + else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) + sink_input_fill_tagstruct(reply, p); + else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST) + source_output_fill_tagstruct(reply, p); + else { + assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); + scache_fill_tagstruct(reply, p); + } + } + } + + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_get_server_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + pa_tagstruct *reply; + char txt[256]; + const char *n; + assert(c && t); + + if (!pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + + reply = reply_new(tag); + pa_tagstruct_puts(reply, PACKAGE_NAME); + pa_tagstruct_puts(reply, PACKAGE_VERSION); + pa_tagstruct_puts(reply, pa_get_user_name(txt, sizeof(txt))); + pa_tagstruct_puts(reply, pa_get_fqdn(txt, sizeof(txt))); + pa_tagstruct_put_sample_spec(reply, &c->protocol->core->default_sample_spec); + + n = pa_namereg_get_default_sink_name(c->protocol->core); + pa_tagstruct_puts(reply, n); + n = pa_namereg_get_default_source_name(c->protocol->core); + pa_tagstruct_puts(reply, n); + + pa_tagstruct_putu32(reply, c->protocol->core->cookie); + + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) { + pa_tagstruct *t; + struct connection *c = userdata; + assert(c && core); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_putu32(t, e); + pa_tagstruct_putu32(t, idx); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + pa_subscription_mask_t m; + assert(c && t); + + if (pa_tagstruct_getu32(t, &m) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID); + + if (c->subscription) + pa_subscription_free(c->subscription); + + if (m != 0) { + c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c); + assert(c->subscription); + } else + c->subscription = NULL; + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_set_volume( + PA_GCC_UNUSED pa_pdispatch *pd, + uint32_t command, + uint32_t tag, + pa_tagstruct *t, + void *userdata) { + + struct connection *c = userdata; + uint32_t idx; + pa_cvolume volume; + pa_sink *sink = NULL; + pa_source *source = NULL; + pa_sink_input *si = NULL; + const char *name = NULL; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) || + (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) || + pa_tagstruct_get_cvolume(t, &volume) || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID); + + if (command == PA_COMMAND_SET_SINK_VOLUME) { + if (idx != PA_INVALID_INDEX) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); + else + sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); + } else if (command == PA_COMMAND_SET_SOURCE_VOLUME) { + if (idx != (uint32_t) -1) + source = pa_idxset_get_by_index(c->protocol->core->sources, idx); + else + source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); + } else { + assert(command == PA_COMMAND_SET_SINK_INPUT_VOLUME); + si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); + } + + CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY); + + if (sink) + pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &volume); + else if (source) + pa_source_set_volume(source, PA_MIXER_HARDWARE, &volume); + else if (si) + pa_sink_input_set_volume(si, &volume); + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_set_mute( + PA_GCC_UNUSED pa_pdispatch *pd, + uint32_t command, + uint32_t tag, + pa_tagstruct *t, + void *userdata) { + + struct connection *c = userdata; + uint32_t idx; + int mute; + pa_sink *sink = NULL; + pa_source *source = NULL; + const char *name = NULL; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_get_boolean(t, &mute) || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); + + if (command == PA_COMMAND_SET_SINK_MUTE) { + if (idx != PA_INVALID_INDEX) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); + else + sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); + } else { + assert(command == PA_COMMAND_SET_SOURCE_MUTE); + if (idx != (uint32_t) -1) + source = pa_idxset_get_by_index(c->protocol->core->sources, idx); + else + source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); + } + + CHECK_VALIDITY(c->pstream, sink || source, tag, PA_ERR_NOENTITY); + + if (sink) + pa_sink_set_mute(sink, PA_MIXER_HARDWARE, mute); + else if (source) + pa_source_set_mute(source, PA_MIXER_HARDWARE, mute); + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + int b; + struct playback_stream *s, *ssync; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_get_boolean(t, &b) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); + s = pa_idxset_get_by_index(c->output_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); + + pa_sink_input_cork(s->sink_input, b); + pa_memblockq_prebuf_force(s->memblockq); + + /* Do the same for all other members in the sync group */ + for (ssync = s->prev; ssync; ssync = ssync->prev) { + pa_sink_input_cork(ssync->sink_input, b); + pa_memblockq_prebuf_force(ssync->memblockq); + } + + for (ssync = s->next; ssync; ssync = ssync->next) { + pa_sink_input_cork(ssync->sink_input, b); + pa_memblockq_prebuf_force(ssync->memblockq); + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_flush_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + struct playback_stream *s, *ssync; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); + s = pa_idxset_get_by_index(c->output_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); + + pa_memblockq_flush(s->memblockq); + s->underrun = 0; + + /* Do the same for all other members in the sync group */ + for (ssync = s->prev; ssync; ssync = ssync->prev) { + pa_memblockq_flush(ssync->memblockq); + ssync->underrun = 0; + } + + for (ssync = s->next; ssync; ssync = ssync->next) { + pa_memblockq_flush(ssync->memblockq); + ssync->underrun = 0; + } + + pa_pstream_send_simple_ack(c->pstream, tag); + pa_sink_notify(s->sink_input->sink); + request_bytes(s); + + for (ssync = s->prev; ssync; ssync = ssync->prev) + request_bytes(ssync); + + for (ssync = s->next; ssync; ssync = ssync->next) + request_bytes(ssync); +} + +static void command_trigger_or_prebuf_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + struct playback_stream *s; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); + s = pa_idxset_get_by_index(c->output_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); + + switch (command) { + case PA_COMMAND_PREBUF_PLAYBACK_STREAM: + pa_memblockq_prebuf_force(s->memblockq); + break; + + case PA_COMMAND_TRIGGER_PLAYBACK_STREAM: + pa_memblockq_prebuf_disable(s->memblockq); + break; + + default: + abort(); + } + + pa_sink_notify(s->sink_input->sink); + pa_pstream_send_simple_ack(c->pstream, tag); + request_bytes(s); +} + +static void command_cork_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + struct record_stream *s; + int b; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_get_boolean(t, &b) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + s = pa_idxset_get_by_index(c->record_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + + pa_source_output_cork(s->source_output, b); + pa_memblockq_prebuf_force(s->memblockq); + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_flush_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + struct record_stream *s; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + s = pa_idxset_get_by_index(c->record_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + + pa_memblockq_flush(s->memblockq); + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_set_default_sink_or_source(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const char *s; + assert(c && t); + + if (pa_tagstruct_gets(t, &s) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, !s || (*s && pa_utf8_valid(s)), tag, PA_ERR_INVALID); + + pa_namereg_set_default(c->protocol->core, s, command == PA_COMMAND_SET_DEFAULT_SOURCE ? PA_NAMEREG_SOURCE : PA_NAMEREG_SINK); + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + const char *name; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_gets(t, &name) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID); + + if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) { + struct playback_stream *s; + + s = pa_idxset_get_by_index(c->output_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); + + pa_sink_input_set_name(s->sink_input, name); + + } else { + struct record_stream *s; + + s = pa_idxset_get_by_index(c->record_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + + pa_source_output_set_name(s->source_output, name); + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + + if (command == PA_COMMAND_KILL_CLIENT) { + pa_client *client; + + client = pa_idxset_get_by_index(c->protocol->core->clients, idx); + CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY); + pa_client_kill(client); + + } else if (command == PA_COMMAND_KILL_SINK_INPUT) { + pa_sink_input *s; + + s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + + pa_sink_input_kill(s); + } else { + pa_source_output *s; + + assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT); + + s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + + pa_source_output_kill(s); + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_load_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + pa_module *m; + const char *name, *argument; + pa_tagstruct *reply; + assert(c && t); + + if (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_gets(t, &argument) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID); + + if (!(m = pa_module_load(c->protocol->core, name, argument))) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED); + return; + } + + reply = reply_new(tag); + pa_tagstruct_putu32(reply, m->index); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_unload_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx; + pa_module *m; + assert(c && t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + m = pa_idxset_get_by_index(c->protocol->core->modules, idx); + CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY); + + pa_module_unload_request(m); + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_add_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const char *name, *module, *argument; + uint32_t type; + uint32_t idx; + pa_tagstruct *reply; + assert(c && t); + + if (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_getu32(t, &type) < 0 || + pa_tagstruct_gets(t, &module) < 0 || + pa_tagstruct_gets(t, &argument) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, type == 0 || type == 1, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, module && *module && pa_utf8_valid(module), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID); + + if (pa_autoload_add(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, module, argument, &idx) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); + return; + } + + reply = reply_new(tag); + pa_tagstruct_putu32(reply, idx); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_remove_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const char *name = NULL; + uint32_t type, idx = PA_IDXSET_INVALID; + int r; + assert(c && t); + + if ((pa_tagstruct_getu32(t, &idx) < 0 && + (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_getu32(t, &type) < 0)) || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, name || idx != PA_IDXSET_INVALID, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || (*name && pa_utf8_valid(name) && (type == 0 || type == 1)), tag, PA_ERR_INVALID); + + if (name) + r = pa_autoload_remove_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE); + else + r = pa_autoload_remove_by_index(c->protocol->core, idx); + + CHECK_VALIDITY(c->pstream, r >= 0, tag, PA_ERR_NOENTITY); + + pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void autoload_fill_tagstruct(pa_tagstruct *t, const pa_autoload_entry *e) { + assert(t && e); + + pa_tagstruct_putu32(t, e->index); + pa_tagstruct_puts(t, e->name); + pa_tagstruct_putu32(t, e->type == PA_NAMEREG_SINK ? 0 : 1); + pa_tagstruct_puts(t, e->module); + pa_tagstruct_puts(t, e->argument); +} + +static void command_get_autoload_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + const pa_autoload_entry *a = NULL; + uint32_t type, idx; + const char *name; + pa_tagstruct *reply; + assert(c && t); + + if ((pa_tagstruct_getu32(t, &idx) < 0 && + (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_getu32(t, &type) < 0)) || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, name || idx != PA_IDXSET_INVALID, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || (*name && (type == 0 || type == 1) && pa_utf8_valid(name)), tag, PA_ERR_INVALID); + + if (name) + a = pa_autoload_get_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE); + else + a = pa_autoload_get_by_index(c->protocol->core, idx); + + CHECK_VALIDITY(c->pstream, a, tag, PA_ERR_NOENTITY); + + reply = reply_new(tag); + autoload_fill_tagstruct(reply, a); + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + pa_tagstruct *reply; + assert(c && t); + + if (!pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + + reply = reply_new(tag); + + if (c->protocol->core->autoload_hashmap) { + pa_autoload_entry *a; + void *state = NULL; + + while ((a = pa_hashmap_iterate(c->protocol->core->autoload_hashmap, &state, NULL))) + autoload_fill_tagstruct(reply, a); + } + + pa_pstream_send_tagstruct(c->pstream, reply); +} + +/*** pstream callbacks ***/ + +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const void *creds, void *userdata) { + struct connection *c = userdata; + assert(p && packet && packet->data && c); + + if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) { + pa_log(__FILE__": invalid packet."); + connection_free(c); + } +} + +static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { + struct connection *c = userdata; + struct output_stream *stream; + assert(p && chunk && userdata); + + if (!(stream = pa_idxset_get_by_index(c->output_streams, channel))) { + pa_log(__FILE__": client sent block for invalid stream."); + connection_free(c); + return; + } + + if (stream->type == PLAYBACK_STREAM) { + struct playback_stream *ps = (struct playback_stream*) stream; + if (chunk->length >= ps->requested_bytes) + ps->requested_bytes = 0; + else + ps->requested_bytes -= chunk->length; + + pa_memblockq_seek(ps->memblockq, offset, seek); + + if (pa_memblockq_push_align(ps->memblockq, chunk) < 0) { + pa_tagstruct *t; + + pa_log_warn(__FILE__": failed to push data into queue"); + + /* Pushing this block into the queue failed, so we simulate + * it by skipping ahead */ + + pa_memblockq_seek(ps->memblockq, chunk->length, PA_SEEK_RELATIVE); + + /* Notify the user */ + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, ps->index); + pa_pstream_send_tagstruct(p, t); + } + + ps->underrun = 0; + + pa_sink_notify(ps->sink_input->sink); + + } else { + struct upload_stream *u = (struct upload_stream*) stream; + size_t l; + assert(u->type == UPLOAD_STREAM); + + if (!u->memchunk.memblock) { + if (u->length == chunk->length) { + u->memchunk = *chunk; + pa_memblock_ref(u->memchunk.memblock); + u->length = 0; + } else { + u->memchunk.memblock = pa_memblock_new(u->length, c->protocol->core->memblock_stat); + u->memchunk.index = u->memchunk.length = 0; + } + } + + assert(u->memchunk.memblock); + + l = u->length; + if (l > chunk->length) + l = chunk->length; + + if (l > 0) { + memcpy((uint8_t*) u->memchunk.memblock->data + u->memchunk.index + u->memchunk.length, + (uint8_t*) chunk->memblock->data+chunk->index, l); + u->memchunk.length += l; + u->length -= l; + } + } +} + +static void pstream_die_callback(pa_pstream *p, void *userdata) { + struct connection *c = userdata; + assert(p && c); + connection_free(c); + +/* pa_log(__FILE__": connection died.");*/ +} + + +static void pstream_drain_callback(pa_pstream *p, void *userdata) { + struct connection *c = userdata; + assert(p && c); + + send_memblock(c); +} + +/*** client callbacks ***/ + +static void client_kill_cb(pa_client *c) { + assert(c && c->userdata); + connection_free(c->userdata); +} + +/*** socket server callbacks ***/ + +static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { + struct connection *c = userdata; + assert(m && tv && c && c->auth_timeout_event == e); + + if (!c->authorized) + connection_free(c); +} + +static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, void *userdata) { + pa_protocol_native *p = userdata; + struct connection *c; + char cname[256], pname[128]; + assert(io && p); + + if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { + pa_log_warn(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); + pa_iochannel_free(io); + return; + } + + c = pa_xmalloc(sizeof(struct connection)); + + c->authorized =!! p->public; + + if (!c->authorized) { + struct timeval tv; + pa_gettimeofday(&tv); + tv.tv_sec += AUTH_TIMEOUT; + c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c); + } else + c->auth_timeout_event = NULL; + + c->version = 8; + c->protocol = p; + pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname)); + snprintf(cname, sizeof(cname), "Native client (%s)", pname); + assert(p->core); + c->client = pa_client_new(p->core, __FILE__, cname); + assert(c->client); + c->client->kill = client_kill_cb; + c->client->userdata = c; + c->client->owner = p->module; + + c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->memblock_stat); + assert(c->pstream); + + pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); + pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); + pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); + pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); + + c->pdispatch = pa_pdispatch_new(p->core->mainloop, command_table, PA_COMMAND_MAX); + assert(c->pdispatch); + + c->record_streams = pa_idxset_new(NULL, NULL); + c->output_streams = pa_idxset_new(NULL, NULL); + assert(c->record_streams && c->output_streams); + + c->rrobin_index = PA_IDXSET_INVALID; + c->subscription = NULL; + + pa_idxset_put(p->connections, c, NULL); + + +#ifdef SCM_CREDENTIALS + if (pa_iochannel_creds_supported(io)) + pa_iochannel_creds_enable(io); + +#endif +} + +/*** module entry points ***/ + +static int load_key(pa_protocol_native*p, const char*fn) { + assert(p); + + p->auth_cookie_in_property = 0; + + if (!fn && pa_authkey_prop_get(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) { + pa_log_info(__FILE__": using already loaded auth cookie."); + pa_authkey_prop_ref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); + p->auth_cookie_in_property = 1; + return 0; + } + + if (!fn) + fn = PA_NATIVE_COOKIE_FILE; + + if (pa_authkey_load_auto(fn, p->auth_cookie, sizeof(p->auth_cookie)) < 0) + return -1; + + pa_log_info(__FILE__": loading cookie from disk."); + + if (pa_authkey_prop_put(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) + p->auth_cookie_in_property = 1; + + return 0; +} + +static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_modargs *ma) { + pa_protocol_native *p; + int public = 0; + assert(c && ma); + + if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) { + pa_log(__FILE__": auth-anonymous= expects a boolean argument."); + return NULL; + } + + p = pa_xnew(pa_protocol_native, 1); + p->core = c; + p->module = m; + p->public = public; + p->server = NULL; + +#ifdef SCM_CREDENTIALS + p->auth_group = pa_xstrdup(pa_modargs_get_value(ma, "auth-group", NULL)); +#endif + + if (load_key(p, pa_modargs_get_value(ma, "cookie", NULL)) < 0) { + pa_xfree(p); + return NULL; + } + + p->connections = pa_idxset_new(NULL, NULL); + assert(p->connections); + + return p; +} + +pa_protocol_native* pa_protocol_native_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { + char t[256]; + pa_protocol_native *p; + + if (!(p = protocol_new_internal(core, m, ma))) + return NULL; + + p->server = server; + pa_socket_server_set_callback(p->server, on_connection, p); + + if (pa_socket_server_get_address(p->server, t, sizeof(t))) { + pa_strlist *l; + l = pa_property_get(core, PA_NATIVE_SERVER_PROPERTY_NAME); + l = pa_strlist_prepend(l, t); + pa_property_replace(core, PA_NATIVE_SERVER_PROPERTY_NAME, l); + } + + return p; +} + +void pa_protocol_native_free(pa_protocol_native *p) { + struct connection *c; + assert(p); + + while ((c = pa_idxset_first(p->connections, NULL))) + connection_free(c); + pa_idxset_free(p->connections, NULL, NULL); + + if (p->server) { + char t[256]; + + if (pa_socket_server_get_address(p->server, t, sizeof(t))) { + pa_strlist *l; + l = pa_property_get(p->core, PA_NATIVE_SERVER_PROPERTY_NAME); + l = pa_strlist_remove(l, t); + + if (l) + pa_property_replace(p->core, PA_NATIVE_SERVER_PROPERTY_NAME, l); + else + pa_property_remove(p->core, PA_NATIVE_SERVER_PROPERTY_NAME); + } + + pa_socket_server_unref(p->server); + } + + if (p->auth_cookie_in_property) + pa_authkey_prop_unref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); + +#ifdef SCM_CREDENTIALS + pa_xfree(p->auth_group); +#endif + pa_xfree(p); +} + +pa_protocol_native* pa_protocol_native_new_iochannel(pa_core*core, pa_iochannel *io, pa_module *m, pa_modargs *ma) { + pa_protocol_native *p; + + if (!(p = protocol_new_internal(core, m, ma))) + return NULL; + + on_connection(NULL, io, p); + + return p; +} diff --git a/src/pulsecore/protocol-native.h b/src/pulsecore/protocol-native.h new file mode 100644 index 00000000..5b091014 --- /dev/null +++ b/src/pulsecore/protocol-native.h @@ -0,0 +1,37 @@ +#ifndef fooprotocolnativehfoo +#define fooprotocolnativehfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +typedef struct pa_protocol_native pa_protocol_native; + +pa_protocol_native* pa_protocol_native_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma); +void pa_protocol_native_free(pa_protocol_native *n); + +pa_protocol_native* pa_protocol_native_new_iochannel(pa_core*core, pa_iochannel *io, pa_module *m, pa_modargs *ma); + +#endif diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c new file mode 100644 index 00000000..4d73bd24 --- /dev/null +++ b/src/pulsecore/protocol-simple.c @@ -0,0 +1,494 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "protocol-simple.h" + +/* Don't allow more than this many concurrent connections */ +#define MAX_CONNECTIONS 10 + +struct connection { + pa_protocol_simple *protocol; + pa_iochannel *io; + pa_sink_input *sink_input; + pa_source_output *source_output; + pa_client *client; + pa_memblockq *input_memblockq, *output_memblockq; + pa_defer_event *defer_event; + + int dead; + + struct { + pa_memblock *current_memblock; + size_t memblock_index, fragment_size; + } playback; +}; + +struct pa_protocol_simple { + pa_module *module; + pa_core *core; + pa_socket_server*server; + pa_idxset *connections; + enum { + RECORD = 1, + PLAYBACK = 2, + DUPLEX = 3 + } mode; + pa_sample_spec sample_spec; + char *source_name, *sink_name; +}; + +#define PLAYBACK_BUFFER_SECONDS (.5) +#define PLAYBACK_BUFFER_FRAGMENTS (10) +#define RECORD_BUFFER_SECONDS (5) +#define RECORD_BUFFER_FRAGMENTS (100) + +static void connection_free(struct connection *c) { + assert(c); + + pa_idxset_remove_by_data(c->protocol->connections, c, NULL); + + if (c->playback.current_memblock) + pa_memblock_unref(c->playback.current_memblock); + if (c->sink_input) { + pa_sink_input_disconnect(c->sink_input); + pa_sink_input_unref(c->sink_input); + } + if (c->source_output) { + pa_source_output_disconnect(c->source_output); + pa_source_output_unref(c->source_output); + } + if (c->client) + pa_client_free(c->client); + if (c->io) + pa_iochannel_free(c->io); + if (c->input_memblockq) + pa_memblockq_free(c->input_memblockq); + if (c->output_memblockq) + pa_memblockq_free(c->output_memblockq); + if (c->defer_event) + c->protocol->core->mainloop->defer_free(c->defer_event); + pa_xfree(c); +} + +static int do_read(struct connection *c) { + pa_memchunk chunk; + ssize_t r; + size_t l; + + if (!c->sink_input || !(l = pa_memblockq_missing(c->input_memblockq))) + return 0; + + if (l > c->playback.fragment_size) + l = c->playback.fragment_size; + + if (c->playback.current_memblock) + if (c->playback.current_memblock->length - c->playback.memblock_index < l) { + pa_memblock_unref(c->playback.current_memblock); + c->playback.current_memblock = NULL; + c->playback.memblock_index = 0; + } + + if (!c->playback.current_memblock) { + c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2, c->protocol->core->memblock_stat); + assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); + c->playback.memblock_index = 0; + } + + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { + pa_log_debug(__FILE__": read(): %s", r == 0 ? "EOF" : pa_cstrerror(errno)); + return -1; + } + + chunk.memblock = c->playback.current_memblock; + chunk.index = c->playback.memblock_index; + chunk.length = r; + assert(chunk.memblock); + + c->playback.memblock_index += r; + + assert(c->input_memblockq); + pa_memblockq_push_align(c->input_memblockq, &chunk); + assert(c->sink_input); + pa_sink_notify(c->sink_input->sink); + + return 0; +} + +static int do_write(struct connection *c) { + pa_memchunk chunk; + ssize_t r; + + if (!c->source_output) + return 0; + + assert(c->output_memblockq); + if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) + return 0; + + assert(chunk.memblock && chunk.length); + + if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { + pa_memblock_unref(chunk.memblock); + pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); + return -1; + } + + pa_memblockq_drop(c->output_memblockq, &chunk, r); + pa_memblock_unref(chunk.memblock); + + pa_source_notify(c->source_output->source); + + return 0; +} + +static void do_work(struct connection *c) { + assert(c); + + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 0); + + if (c->dead) + return; + + if (pa_iochannel_is_readable(c->io)) { + if (do_read(c) < 0) + goto fail; + } else if (pa_iochannel_is_hungup(c->io)) + goto fail; + + if (pa_iochannel_is_writable(c->io)) { + if (do_write(c) < 0) + goto fail; + } + + return; + +fail: + + if (c->sink_input) { + c->dead = 1; + + pa_iochannel_free(c->io); + c->io = NULL; + + pa_memblockq_prebuf_disable(c->input_memblockq); + pa_sink_notify(c->sink_input->sink); + } else + connection_free(c); +} + +/*** sink_input callbacks ***/ + +static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { + struct connection*c; + assert(i && i->userdata && chunk); + c = i->userdata; + + if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) { + + if (c->dead) + connection_free(c); + + return -1; + } + + return 0; +} + +static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { + struct connection*c = i->userdata; + assert(i && c && length); + + pa_memblockq_drop(c->input_memblockq, chunk, length); + + /* do something */ + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); +} + +static void sink_input_kill_cb(pa_sink_input *i) { + assert(i && i->userdata); + connection_free((struct connection *) i->userdata); +} + + +static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { + struct connection*c = i->userdata; + assert(i && c); + return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); +} + +/*** source_output callbacks ***/ + +static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { + struct connection *c = o->userdata; + assert(o && c && chunk); + + pa_memblockq_push(c->output_memblockq, chunk); + + /* do something */ + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); +} + +static void source_output_kill_cb(pa_source_output *o) { + assert(o && o->userdata); + connection_free((struct connection *) o->userdata); +} + +static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { + struct connection*c = o->userdata; + assert(o && c); + return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec); +} + +/*** client callbacks ***/ + +static void client_kill_cb(pa_client *c) { + assert(c && c->userdata); + connection_free((struct connection *) c->userdata); +} + +/*** pa_iochannel callbacks ***/ + +static void io_callback(pa_iochannel*io, void *userdata) { + struct connection *c = userdata; + assert(io && c && c->io == io); + + do_work(c); +} + +/*** fixed callback ***/ + +static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { + struct connection *c = userdata; + assert(a && c && c->defer_event == e); + + do_work(c); +} + +/*** socket_server callbacks ***/ + +static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { + pa_protocol_simple *p = userdata; + struct connection *c = NULL; + char cname[256]; + assert(s && io && p); + + if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { + pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); + pa_iochannel_free(io); + return; + } + + c = pa_xmalloc(sizeof(struct connection)); + c->io = io; + c->sink_input = NULL; + c->source_output = NULL; + c->defer_event = NULL; + c->input_memblockq = c->output_memblockq = NULL; + c->protocol = p; + c->playback.current_memblock = NULL; + c->playback.memblock_index = 0; + c->playback.fragment_size = 0; + c->dead = 0; + + pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); + c->client = pa_client_new(p->core, __FILE__, cname); + assert(c->client); + c->client->owner = p->module; + c->client->kill = client_kill_cb; + c->client->userdata = c; + + if (p->mode & PLAYBACK) { + pa_sink *sink; + size_t l; + + if (!(sink = pa_namereg_get(p->core, p->sink_name, PA_NAMEREG_SINK, 1))) { + pa_log(__FILE__": Failed to get sink."); + goto fail; + } + + if (!(c->sink_input = pa_sink_input_new(sink, __FILE__, c->client->name, &p->sample_spec, NULL, NULL, 0, -1))) { + pa_log(__FILE__": Failed to create sink input."); + goto fail; + } + + c->sink_input->owner = p->module; + c->sink_input->client = c->client; + + c->sink_input->peek = sink_input_peek_cb; + c->sink_input->drop = sink_input_drop_cb; + c->sink_input->kill = sink_input_kill_cb; + c->sink_input->get_latency = sink_input_get_latency_cb; + c->sink_input->userdata = c; + + l = (size_t) (pa_bytes_per_second(&p->sample_spec)*PLAYBACK_BUFFER_SECONDS); + c->input_memblockq = pa_memblockq_new( + 0, + l, + 0, + pa_frame_size(&p->sample_spec), + (size_t) -1, + l/PLAYBACK_BUFFER_FRAGMENTS, + NULL, + p->core->memblock_stat); + assert(c->input_memblockq); + pa_iochannel_socket_set_rcvbuf(io, l/PLAYBACK_BUFFER_FRAGMENTS*5); + c->playback.fragment_size = l/10; + } + + if (p->mode & RECORD) { + pa_source *source; + size_t l; + + if (!(source = pa_namereg_get(p->core, p->source_name, PA_NAMEREG_SOURCE, 1))) { + pa_log(__FILE__": Failed to get source."); + goto fail; + } + + c->source_output = pa_source_output_new(source, __FILE__, c->client->name, &p->sample_spec, NULL, -1); + if (!c->source_output) { + pa_log(__FILE__": Failed to create source output."); + goto fail; + } + c->source_output->owner = p->module; + c->source_output->client = c->client; + + c->source_output->push = source_output_push_cb; + c->source_output->kill = source_output_kill_cb; + c->source_output->get_latency = source_output_get_latency_cb; + c->source_output->userdata = c; + + l = (size_t) (pa_bytes_per_second(&p->sample_spec)*RECORD_BUFFER_SECONDS); + c->output_memblockq = pa_memblockq_new( + 0, + l, + 0, + pa_frame_size(&p->sample_spec), + 1, + 0, + NULL, + p->core->memblock_stat); + pa_iochannel_socket_set_sndbuf(io, l/RECORD_BUFFER_FRAGMENTS*2); + } + + pa_iochannel_set_callback(c->io, io_callback, c); + pa_idxset_put(p->connections, c, NULL); + + c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c); + assert(c->defer_event); + p->core->mainloop->defer_enable(c->defer_event, 0); + + return; + +fail: + if (c) + connection_free(c); +} + +pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { + pa_protocol_simple* p = NULL; + int enable; + assert(core && server && ma); + + p = pa_xmalloc0(sizeof(pa_protocol_simple)); + p->module = m; + p->core = core; + p->server = server; + p->connections = pa_idxset_new(NULL, NULL); + + p->sample_spec = core->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &p->sample_spec) < 0) { + pa_log(__FILE__": Failed to parse sample type specification."); + goto fail; + } + + p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL)); + p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); + + enable = 0; + if (pa_modargs_get_value_boolean(ma, "record", &enable) < 0) { + pa_log(__FILE__": record= expects a numeric argument."); + goto fail; + } + p->mode = enable ? RECORD : 0; + + enable = 1; + if (pa_modargs_get_value_boolean(ma, "playback", &enable) < 0) { + pa_log(__FILE__": playback= expects a numeric argument."); + goto fail; + } + p->mode |= enable ? PLAYBACK : 0; + + if ((p->mode & (RECORD|PLAYBACK)) == 0) { + pa_log(__FILE__": neither playback nor recording enabled for protocol."); + goto fail; + } + + pa_socket_server_set_callback(p->server, on_connection, p); + + return p; + +fail: + if (p) + pa_protocol_simple_free(p); + return NULL; +} + + +void pa_protocol_simple_free(pa_protocol_simple *p) { + struct connection *c; + assert(p); + + if (p->connections) { + while((c = pa_idxset_first(p->connections, NULL))) + connection_free(c); + + pa_idxset_free(p->connections, NULL, NULL); + } + + if (p->server) + pa_socket_server_unref(p->server); + pa_xfree(p); +} + diff --git a/src/pulsecore/protocol-simple.h b/src/pulsecore/protocol-simple.h new file mode 100644 index 00000000..8dfaee34 --- /dev/null +++ b/src/pulsecore/protocol-simple.h @@ -0,0 +1,35 @@ +#ifndef fooprotocolsimplehfoo +#define fooprotocolsimplehfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +typedef struct pa_protocol_simple pa_protocol_simple; + +pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma); +void pa_protocol_simple_free(pa_protocol_simple *n); + +#endif diff --git a/src/pulsecore/pstream-util.c b/src/pulsecore/pstream-util.c new file mode 100644 index 00000000..3a995324 --- /dev/null +++ b/src/pulsecore/pstream-util.c @@ -0,0 +1,62 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include "pstream-util.h" + +void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, int creds) { + size_t length; + uint8_t *data; + pa_packet *packet; + assert(p); + assert(t); + + data = pa_tagstruct_free_data(t, &length); + assert(data && length); + packet = pa_packet_new_dynamic(data, length); + assert(packet); + pa_pstream_send_packet(p, packet, creds); + pa_packet_unref(packet); +} + +void pa_pstream_send_error(pa_pstream *p, uint32_t tag, uint32_t error) { + pa_tagstruct *t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_ERROR); + pa_tagstruct_putu32(t, tag); + pa_tagstruct_putu32(t, error); + pa_pstream_send_tagstruct(p, t); +} + +void pa_pstream_send_simple_ack(pa_pstream *p, uint32_t tag) { + pa_tagstruct *t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_REPLY); + pa_tagstruct_putu32(t, tag); + pa_pstream_send_tagstruct(p, t); +} diff --git a/src/pulsecore/pstream-util.h b/src/pulsecore/pstream-util.h new file mode 100644 index 00000000..fc6d18c0 --- /dev/null +++ b/src/pulsecore/pstream-util.h @@ -0,0 +1,37 @@ +#ifndef foopstreamutilhfoo +#define foopstreamutilhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include + +/* The tagstruct is freed!*/ +void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, int creds); + +#define pa_pstream_send_tagstruct(p, t) pa_pstream_send_tagstruct_with_creds((p), (t), 0) + +void pa_pstream_send_error(pa_pstream *p, uint32_t tag, uint32_t error); +void pa_pstream_send_simple_ack(pa_pstream *p, uint32_t tag); + +#endif diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c new file mode 100644 index 00000000..60c05938 --- /dev/null +++ b/src/pulsecore/pstream.c @@ -0,0 +1,589 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#include "winsock.h" + +#include + +#include +#include +#include + +#include "pstream.h" + +enum { + PA_PSTREAM_DESCRIPTOR_LENGTH, + PA_PSTREAM_DESCRIPTOR_CHANNEL, + PA_PSTREAM_DESCRIPTOR_OFFSET_HI, + PA_PSTREAM_DESCRIPTOR_OFFSET_LO, + PA_PSTREAM_DESCRIPTOR_SEEK, + PA_PSTREAM_DESCRIPTOR_MAX +}; + +typedef uint32_t pa_pstream_descriptor[PA_PSTREAM_DESCRIPTOR_MAX]; + +#define PA_PSTREAM_DESCRIPTOR_SIZE (PA_PSTREAM_DESCRIPTOR_MAX*sizeof(uint32_t)) +#define FRAME_SIZE_MAX PA_SCACHE_ENTRY_SIZE_MAX /* allow uploading a single sample in one frame at max */ + +struct item_info { + enum { PA_PSTREAM_ITEM_PACKET, PA_PSTREAM_ITEM_MEMBLOCK } type; + + /* memblock info */ + pa_memchunk chunk; + uint32_t channel; + int64_t offset; + pa_seek_mode_t seek_mode; + + /* packet info */ + pa_packet *packet; +#ifdef SCM_CREDENTIALS + int with_creds; +#endif +}; + +struct pa_pstream { + int ref; + + pa_mainloop_api *mainloop; + pa_defer_event *defer_event; + pa_iochannel *io; + pa_queue *send_queue; + + int dead; + + struct { + struct item_info* current; + pa_pstream_descriptor descriptor; + void *data; + size_t index; + } write; + + struct { + pa_memblock *memblock; + pa_packet *packet; + pa_pstream_descriptor descriptor; + void *data; + size_t index; + } read; + + pa_pstream_packet_cb_t recieve_packet_callback; + void *recieve_packet_callback_userdata; + + pa_pstream_memblock_cb_t recieve_memblock_callback; + void *recieve_memblock_callback_userdata; + + pa_pstream_notify_cb_t drain_callback; + void *drain_callback_userdata; + + pa_pstream_notify_cb_t die_callback; + void *die_callback_userdata; + + pa_memblock_stat *memblock_stat; + +#ifdef SCM_CREDENTIALS + int send_creds_now; + struct ucred ucred; + int creds_valid; +#endif +}; + +static int do_write(pa_pstream *p); +static int do_read(pa_pstream *p); + +static void do_something(pa_pstream *p) { + assert(p); + + p->mainloop->defer_enable(p->defer_event, 0); + + pa_pstream_ref(p); + + if (!p->dead && pa_iochannel_is_readable(p->io)) { + if (do_read(p) < 0) + goto fail; + } else if (!p->dead && pa_iochannel_is_hungup(p->io)) + goto fail; + + if (!p->dead && pa_iochannel_is_writable(p->io)) { + if (do_write(p) < 0) + goto fail; + } + + pa_pstream_unref(p); + return; + +fail: + + p->dead = 1; + + if (p->die_callback) + p->die_callback(p, p->die_callback_userdata); + + pa_pstream_unref(p); +} + +static void io_callback(pa_iochannel*io, void *userdata) { + pa_pstream *p = userdata; + + assert(p); + assert(p->io == io); + + do_something(p); +} + +static void defer_callback(pa_mainloop_api *m, pa_defer_event *e, void*userdata) { + pa_pstream *p = userdata; + + assert(p); + assert(p->defer_event == e); + assert(p->mainloop == m); + + do_something(p); +} + +pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_stat *s) { + pa_pstream *p; + assert(io); + + p = pa_xnew(pa_pstream, 1); + + p->ref = 1; + p->io = io; + pa_iochannel_set_callback(io, io_callback, p); + + p->dead = 0; + + p->mainloop = m; + p->defer_event = m->defer_new(m, defer_callback, p); + m->defer_enable(p->defer_event, 0); + + p->send_queue = pa_queue_new(); + assert(p->send_queue); + + p->write.current = NULL; + p->write.index = 0; + + p->read.memblock = NULL; + p->read.packet = NULL; + p->read.index = 0; + + p->recieve_packet_callback = NULL; + p->recieve_packet_callback_userdata = NULL; + + p->recieve_memblock_callback = NULL; + p->recieve_memblock_callback_userdata = NULL; + + p->drain_callback = NULL; + p->drain_callback_userdata = NULL; + + p->die_callback = NULL; + p->die_callback_userdata = NULL; + + p->memblock_stat = s; + + pa_iochannel_socket_set_rcvbuf(io, 1024*8); + pa_iochannel_socket_set_sndbuf(io, 1024*8); + +#ifdef SCM_CREDENTIALS + p->send_creds_now = 0; + p->creds_valid = 0; +#endif + return p; +} + +static void item_free(void *item, PA_GCC_UNUSED void *p) { + struct item_info *i = item; + assert(i); + + if (i->type == PA_PSTREAM_ITEM_MEMBLOCK) { + assert(i->chunk.memblock); + pa_memblock_unref(i->chunk.memblock); + } else { + assert(i->type == PA_PSTREAM_ITEM_PACKET); + assert(i->packet); + pa_packet_unref(i->packet); + } + + pa_xfree(i); +} + +static void pstream_free(pa_pstream *p) { + assert(p); + + pa_pstream_close(p); + + pa_queue_free(p->send_queue, item_free, NULL); + + if (p->write.current) + item_free(p->write.current, NULL); + + if (p->read.memblock) + pa_memblock_unref(p->read.memblock); + + if (p->read.packet) + pa_packet_unref(p->read.packet); + + pa_xfree(p); +} + +void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, int with_creds) { + struct item_info *i; + assert(p && packet && p->ref >= 1); + + if (p->dead) + return; + +/* pa_log(__FILE__": push-packet %p", packet); */ + + i = pa_xnew(struct item_info, 1); + i->type = PA_PSTREAM_ITEM_PACKET; + i->packet = pa_packet_ref(packet); +#ifdef SCM_CREDENTIALS + i->with_creds = with_creds; +#endif + + pa_queue_push(p->send_queue, i); + p->mainloop->defer_enable(p->defer_event, 1); +} + +void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek_mode, const pa_memchunk *chunk) { + struct item_info *i; + assert(p && channel != (uint32_t) -1 && chunk && p->ref >= 1); + + if (p->dead) + return; + +/* pa_log(__FILE__": push-memblock %p", chunk); */ + + i = pa_xnew(struct item_info, 1); + i->type = PA_PSTREAM_ITEM_MEMBLOCK; + i->chunk = *chunk; + i->channel = channel; + i->offset = offset; + i->seek_mode = seek_mode; + + pa_memblock_ref(i->chunk.memblock); + + pa_queue_push(p->send_queue, i); + p->mainloop->defer_enable(p->defer_event, 1); +} + +static void prepare_next_write_item(pa_pstream *p) { + assert(p); + + if (!(p->write.current = pa_queue_pop(p->send_queue))) + return; + + p->write.index = 0; + + if (p->write.current->type == PA_PSTREAM_ITEM_PACKET) { + /*pa_log(__FILE__": pop-packet %p", p->write.current->packet);*/ + + assert(p->write.current->packet); + p->write.data = p->write.current->packet->data; + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->packet->length); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl((uint32_t) -1); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = 0; + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = 0; + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK] = 0; + +#ifdef SCM_CREDENTIALS + p->send_creds_now = 1; +#endif + + } else { + assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK && p->write.current->chunk.memblock); + p->write.data = (uint8_t*) p->write.current->chunk.memblock->data + p->write.current->chunk.index; + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl(p->write.current->channel); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = htonl((uint32_t) (((uint64_t) p->write.current->offset) >> 32)); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = htonl((uint32_t) ((uint64_t) p->write.current->offset)); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK] = htonl(p->write.current->seek_mode); + +#ifdef SCM_CREDENTIALS + p->send_creds_now = 1; +#endif + } +} + +static int do_write(pa_pstream *p) { + void *d; + size_t l; + ssize_t r; + assert(p); + + if (!p->write.current) + prepare_next_write_item(p); + + if (!p->write.current) + return 0; + + assert(p->write.data); + + if (p->write.index < PA_PSTREAM_DESCRIPTOR_SIZE) { + d = (uint8_t*) p->write.descriptor + p->write.index; + l = PA_PSTREAM_DESCRIPTOR_SIZE - p->write.index; + } else { + d = (uint8_t*) p->write.data + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE; + l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE); + } + +#ifdef SCM_CREDENTIALS + if (p->send_creds_now) { + + if ((r = pa_iochannel_write_with_creds(p->io, d, l)) < 0) + return -1; + + p->send_creds_now = 0; + } else +#endif + + if ((r = pa_iochannel_write(p->io, d, l)) < 0) + return -1; + + p->write.index += r; + + if (p->write.index >= PA_PSTREAM_DESCRIPTOR_SIZE+ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])) { + assert(p->write.current); + item_free(p->write.current, (void *) 1); + p->write.current = NULL; + + if (p->drain_callback && !pa_pstream_is_pending(p)) + p->drain_callback(p, p->drain_callback_userdata); + } + + return 0; +} + +static int do_read(pa_pstream *p) { + void *d; + size_t l; + ssize_t r; + assert(p); + + if (p->read.index < PA_PSTREAM_DESCRIPTOR_SIZE) { + d = (uint8_t*) p->read.descriptor + p->read.index; + l = PA_PSTREAM_DESCRIPTOR_SIZE - p->read.index; + } else { + assert(p->read.data); + d = (uint8_t*) p->read.data + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE; + l = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE); + } + +#ifdef SCM_CREDENTIALS + { + int b; + + if ((r = pa_iochannel_read_with_creds(p->io, d, l, &p->ucred, &b)) <= 0) + return -1; + + p->creds_valid = p->creds_valid || b; + } +#else + if ((r = pa_iochannel_read(p->io, d, l)) <= 0) + return -1; +#endif + + p->read.index += r; + + if (p->read.index == PA_PSTREAM_DESCRIPTOR_SIZE) { + /* Reading of frame descriptor complete */ + + /* Frame size too large */ + if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) > FRAME_SIZE_MAX) { + pa_log_warn(__FILE__": Frame size too large: %lu > %lu", (unsigned long) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]), (unsigned long) FRAME_SIZE_MAX); + return -1; + } + + assert(!p->read.packet && !p->read.memblock); + + if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]) == (uint32_t) -1) { + /* Frame is a packet frame */ + p->read.packet = pa_packet_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])); + p->read.data = p->read.packet->data; + } else { + /* Frame is a memblock frame */ + p->read.memblock = pa_memblock_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]), p->memblock_stat); + p->read.data = p->read.memblock->data; + + if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK]) > PA_SEEK_RELATIVE_END) { + pa_log_warn(__FILE__": Invalid seek mode"); + return -1; + } + } + + } else if (p->read.index > PA_PSTREAM_DESCRIPTOR_SIZE) { + /* Frame payload available */ + + if (p->read.memblock && p->recieve_memblock_callback) { /* Is this memblock data? Than pass it to the user */ + l = (p->read.index - r) < PA_PSTREAM_DESCRIPTOR_SIZE ? p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE : (size_t) r; + + if (l > 0) { + pa_memchunk chunk; + + chunk.memblock = p->read.memblock; + chunk.index = p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE - l; + chunk.length = l; + + if (p->recieve_memblock_callback) { + int64_t offset; + + offset = (int64_t) ( + (((uint64_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])) << 32) | + (((uint64_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO])))); + + p->recieve_memblock_callback( + p, + ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]), + offset, + ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK]), + &chunk, + p->recieve_memblock_callback_userdata); + } + + /* Drop seek info for following callbacks */ + p->read.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK] = + p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = + p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = 0; + } + } + + /* Frame complete */ + if (p->read.index >= ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) + PA_PSTREAM_DESCRIPTOR_SIZE) { + if (p->read.memblock) { + assert(!p->read.packet); + + pa_memblock_unref(p->read.memblock); + p->read.memblock = NULL; + } else { + assert(p->read.packet); + + if (p->recieve_packet_callback) +#ifdef SCM_CREDENTIALS + p->recieve_packet_callback(p, p->read.packet, p->creds_valid ? &p->ucred : NULL, p->recieve_packet_callback_userdata); +#else + p->recieve_packet_callback(p, p->read.packet, NULL, p->recieve_packet_callback_userdata); +#endif + + pa_packet_unref(p->read.packet); + p->read.packet = NULL; + } + + p->read.index = 0; +#ifdef SCM_CREDENTIALS + p->creds_valid = 0; +#endif + } + } + + return 0; +} + +void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) { + assert(p); + assert(p->ref >= 1); + + p->die_callback = cb; + p->die_callback_userdata = userdata; +} + + +void pa_pstream_set_drain_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) { + assert(p); + assert(p->ref >= 1); + + p->drain_callback = cb; + p->drain_callback_userdata = userdata; +} + +void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata) { + assert(p); + assert(p->ref >= 1); + + p->recieve_packet_callback = cb; + p->recieve_packet_callback_userdata = userdata; +} + +void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, pa_pstream_memblock_cb_t cb, void *userdata) { + assert(p); + assert(p->ref >= 1); + + p->recieve_memblock_callback = cb; + p->recieve_memblock_callback_userdata = userdata; +} + +int pa_pstream_is_pending(pa_pstream *p) { + assert(p); + + if (p->dead) + return 0; + + return p->write.current || !pa_queue_is_empty(p->send_queue); +} + +void pa_pstream_unref(pa_pstream*p) { + assert(p); + assert(p->ref >= 1); + + if (--p->ref == 0) + pstream_free(p); +} + +pa_pstream* pa_pstream_ref(pa_pstream*p) { + assert(p); + assert(p->ref >= 1); + + p->ref++; + return p; +} + +void pa_pstream_close(pa_pstream *p) { + assert(p); + + p->dead = 1; + + if (p->io) { + pa_iochannel_free(p->io); + p->io = NULL; + } + + if (p->defer_event) { + p->mainloop->defer_free(p->defer_event); + p->defer_event = NULL; + } + + p->die_callback = NULL; + p->drain_callback = NULL; + p->recieve_packet_callback = NULL; + p->recieve_memblock_callback = NULL; +} diff --git a/src/pulsecore/pstream.h b/src/pulsecore/pstream.h new file mode 100644 index 00000000..1a2932d4 --- /dev/null +++ b/src/pulsecore/pstream.h @@ -0,0 +1,57 @@ +#ifndef foopstreamhfoo +#define foopstreamhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include +#include +#include +#include +#include + +typedef struct pa_pstream pa_pstream; + +typedef void (*pa_pstream_packet_cb_t)(pa_pstream *p, pa_packet *packet, const void *creds, void *userdata); +typedef void (*pa_pstream_memblock_cb_t)(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata); +typedef void (*pa_pstream_notify_cb_t)(pa_pstream *p, void *userdata); + +pa_pstream* pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_stat *s); +void pa_pstream_unref(pa_pstream*p); +pa_pstream* pa_pstream_ref(pa_pstream*p); + +void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, int with_creds); +void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk); + +void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata); +void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, pa_pstream_memblock_cb_t cb, void *userdata); +void pa_pstream_set_drain_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata); + +void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata); + +int pa_pstream_is_pending(pa_pstream *p); + +void pa_pstream_close(pa_pstream *p); + +#endif diff --git a/src/pulsecore/queue.c b/src/pulsecore/queue.c new file mode 100644 index 00000000..93b119eb --- /dev/null +++ b/src/pulsecore/queue.c @@ -0,0 +1,109 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include "queue.h" + +struct queue_entry { + struct queue_entry *next; + void *data; +}; + +struct pa_queue { + struct queue_entry *front, *back; + unsigned length; +}; + +pa_queue* pa_queue_new(void) { + pa_queue *q = pa_xnew(pa_queue, 1); + q->front = q->back = NULL; + q->length = 0; + return q; +} + +void pa_queue_free(pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata) { + struct queue_entry *e; + assert(q); + + e = q->front; + while (e) { + struct queue_entry *n = e->next; + + if (destroy) + destroy(e->data, userdata); + + pa_xfree(e); + e = n; + } + + pa_xfree(q); +} + +void pa_queue_push(pa_queue *q, void *p) { + struct queue_entry *e; + + e = pa_xnew(struct queue_entry, 1); + e->data = p; + e->next = NULL; + + if (q->back) + q->back->next = e; + else { + assert(!q->front); + q->front = e; + } + + q->back = e; + q->length++; +} + +void* pa_queue_pop(pa_queue *q) { + void *p; + struct queue_entry *e; + assert(q); + + if (!(e = q->front)) + return NULL; + + q->front = e->next; + if (q->back == e) + q->back = NULL; + + p = e->data; + pa_xfree(e); + + q->length--; + + return p; +} + +int pa_queue_is_empty(pa_queue *q) { + assert(q); + return q->length == 0; +} diff --git a/src/pulsecore/queue.h b/src/pulsecore/queue.h new file mode 100644 index 00000000..3fb9dea4 --- /dev/null +++ b/src/pulsecore/queue.h @@ -0,0 +1,40 @@ +#ifndef fooqueuehfoo +#define fooqueuehfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef struct pa_queue pa_queue; + +/* A simple implementation of the abstract data type queue. Stores + * pointers as members. The memory has to be managed by the caller. */ + +pa_queue* pa_queue_new(void); + +/* Free the queue and run the specified callback function for every remaining entry. The callback function may be NULL. */ +void pa_queue_free(pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata); + +void pa_queue_push(pa_queue *q, void *p); +void* pa_queue_pop(pa_queue *q); + +int pa_queue_is_empty(pa_queue *q); + +#endif diff --git a/src/pulsecore/random.c b/src/pulsecore/random.c new file mode 100644 index 00000000..3d3357a5 --- /dev/null +++ b/src/pulsecore/random.c @@ -0,0 +1,108 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "random.h" + +static int has_whined = 0; + +static const char *devices[] = { "/dev/urandom", "/dev/random", NULL }; + +static int random_proper(void *ret_data, size_t length) { +#ifdef OS_IS_WIN32 + assert(ret_data && length); + + return -1; + +#else /* OS_IS_WIN32 */ + + int fd, ret = -1; + ssize_t r = 0; + const char **device; + + assert(ret_data && length); + + device = devices; + + while (*device) { + ret = 0; + + if ((fd = open(*device, O_RDONLY)) >= 0) { + + if ((r = pa_loop_read(fd, ret_data, length)) < 0 || (size_t) r != length) + ret = -1; + + close(fd); + } else + ret = -1; + + if (ret == 0) + break; + } + + return ret; +#endif /* OS_IS_WIN32 */ +} + +void pa_random_seed(void) { + unsigned int seed; + + if (random_proper(&seed, sizeof(unsigned int)) < 0) { + if (!has_whined) + pa_log_warn(__FILE__": failed to get proper entropy. Falling back to seeding with current time."); + has_whined = 1; + + seed = (unsigned int) time(NULL); + } + + srand(seed); +} + +void pa_random(void *ret_data, size_t length) { + uint8_t *p; + size_t l; + + assert(ret_data && length); + + if (random_proper(ret_data, length) >= 0) + return; + + if (!has_whined) + pa_log_warn(__FILE__": failed to get proper entropy. Falling back to unsecure pseudo RNG."); + has_whined = 1; + + for (p = ret_data, l = length; l > 0; p++, l--) + *p = (uint8_t) rand(); +} diff --git a/src/pulsecore/random.h b/src/pulsecore/random.h new file mode 100644 index 00000000..f809afec --- /dev/null +++ b/src/pulsecore/random.h @@ -0,0 +1,28 @@ +#ifndef foorandomhfoo +#define foorandomhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +void pa_random_seed(void); +void pa_random(void *ret_data, size_t length); + +#endif diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c new file mode 100644 index 00000000..23cdf381 --- /dev/null +++ b/src/pulsecore/resampler.c @@ -0,0 +1,618 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include "resampler.h" + +struct pa_resampler { + pa_resample_method_t resample_method; + pa_sample_spec i_ss, o_ss; + pa_channel_map i_cm, o_cm; + size_t i_fz, o_fz; + pa_memblock_stat *memblock_stat; + + void (*impl_free)(pa_resampler *r); + void (*impl_update_input_rate)(pa_resampler *r, uint32_t rate); + void (*impl_run)(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out); + void *impl_data; +}; + +struct impl_libsamplerate { + float* buf1, *buf2, *buf3, *buf4; + unsigned buf1_samples, buf2_samples, buf3_samples, buf4_samples; + + pa_convert_to_float32ne_func_t to_float32ne_func; + pa_convert_from_float32ne_func_t from_float32ne_func; + SRC_STATE *src_state; + + int map_table[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; + int map_required; +}; + +struct impl_trivial { + unsigned o_counter; + unsigned i_counter; +}; + +static int libsamplerate_init(pa_resampler*r); +static int trivial_init(pa_resampler*r); + +pa_resampler* pa_resampler_new( + const pa_sample_spec *a, + const pa_channel_map *am, + const pa_sample_spec *b, + const pa_channel_map *bm, + pa_memblock_stat *s, + pa_resample_method_t resample_method) { + + pa_resampler *r = NULL; + + assert(a); + assert(b); + assert(pa_sample_spec_valid(a)); + assert(pa_sample_spec_valid(b)); + assert(resample_method != PA_RESAMPLER_INVALID); + + r = pa_xnew(pa_resampler, 1); + r->impl_data = NULL; + r->memblock_stat = s; + r->resample_method = resample_method; + + r->impl_free = NULL; + r->impl_update_input_rate = NULL; + r->impl_run = NULL; + + /* Fill sample specs */ + r->i_ss = *a; + r->o_ss = *b; + + if (am) + r->i_cm = *am; + else + pa_channel_map_init_auto(&r->i_cm, r->i_ss.channels, PA_CHANNEL_MAP_DEFAULT); + + if (bm) + r->o_cm = *bm; + else + pa_channel_map_init_auto(&r->o_cm, r->o_ss.channels, PA_CHANNEL_MAP_DEFAULT); + + r->i_fz = pa_frame_size(a); + r->o_fz = pa_frame_size(b); + + /* Choose implementation */ + if (a->channels != b->channels || + a->format != b->format || + !pa_channel_map_equal(&r->i_cm, &r->o_cm) || + resample_method != PA_RESAMPLER_TRIVIAL) { + + /* Use the libsamplerate based resampler for the complicated cases */ + if (resample_method == PA_RESAMPLER_TRIVIAL) + r->resample_method = PA_RESAMPLER_SRC_ZERO_ORDER_HOLD; + + if (libsamplerate_init(r) < 0) + goto fail; + + } else { + /* Use our own simple non-fp resampler for the trivial cases and when the user selects it */ + if (trivial_init(r) < 0) + goto fail; + } + + return r; + +fail: + if (r) + pa_xfree(r); + + return NULL; +} + +void pa_resampler_free(pa_resampler *r) { + assert(r); + + if (r->impl_free) + r->impl_free(r); + + pa_xfree(r); +} + +void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate) { + assert(r); + assert(rate > 0); + + if (r->i_ss.rate == rate) + return; + + r->i_ss.rate = rate; + + if (r->impl_update_input_rate) + r->impl_update_input_rate(r, rate); +} + +void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { + assert(r && in && out && r->impl_run); + + r->impl_run(r, in, out); +} + +size_t pa_resampler_request(pa_resampler *r, size_t out_length) { + assert(r); + + return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz; +} + +pa_resample_method_t pa_resampler_get_method(pa_resampler *r) { + assert(r); + return r->resample_method; +} + +static const char * const resample_methods[] = { + "src-sinc-best-quality", + "src-sinc-medium-quality", + "src-sinc-fastest", + "src-zero-order-hold", + "src-linear", + "trivial" +}; + +const char *pa_resample_method_to_string(pa_resample_method_t m) { + + if (m < 0 || m >= PA_RESAMPLER_MAX) + return NULL; + + return resample_methods[m]; +} + +pa_resample_method_t pa_parse_resample_method(const char *string) { + pa_resample_method_t m; + + assert(string); + + for (m = 0; m < PA_RESAMPLER_MAX; m++) + if (!strcmp(string, resample_methods[m])) + return m; + + return PA_RESAMPLER_INVALID; +} + + +/*** libsamplerate based implementation ***/ + +static void libsamplerate_free(pa_resampler *r) { + struct impl_libsamplerate *u; + + assert(r); + assert(r->impl_data); + + u = r->impl_data; + + if (u->src_state) + src_delete(u->src_state); + + pa_xfree(u->buf1); + pa_xfree(u->buf2); + pa_xfree(u->buf3); + pa_xfree(u->buf4); + pa_xfree(u); +} + +static void calc_map_table(pa_resampler *r) { + struct impl_libsamplerate *u; + unsigned oc; + assert(r); + assert(r->impl_data); + + u = r->impl_data; + + if (!(u->map_required = (!pa_channel_map_equal(&r->i_cm, &r->o_cm) || r->i_ss.channels != r->o_ss.channels))) + return; + + for (oc = 0; oc < r->o_ss.channels; oc++) { + unsigned ic, i = 0; + + for (ic = 0; ic < r->i_ss.channels; ic++) { + pa_channel_position_t a, b; + + a = r->i_cm.map[ic]; + b = r->o_cm.map[oc]; + + if (a == b || + (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_LEFT) || + (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_RIGHT) || + (a == PA_CHANNEL_POSITION_LEFT && b == PA_CHANNEL_POSITION_MONO) || + (a == PA_CHANNEL_POSITION_RIGHT && b == PA_CHANNEL_POSITION_MONO)) + + u->map_table[oc][i++] = ic; + } + + /* Add an end marker */ + if (i < PA_CHANNELS_MAX) + u->map_table[oc][i] = -1; + } +} + +static float * convert_to_float(pa_resampler *r, void *input, unsigned n_frames) { + struct impl_libsamplerate *u; + unsigned n_samples; + + assert(r); + assert(input); + assert(r->impl_data); + u = r->impl_data; + + /* Convert the incoming sample into floats and place them in buf1 */ + + if (!u->to_float32ne_func) + return input; + + n_samples = n_frames * r->i_ss.channels; + + if (u->buf1_samples < n_samples) + u->buf1 = pa_xrealloc(u->buf1, sizeof(float) * (u->buf1_samples = n_samples)); + + u->to_float32ne_func(n_samples, input, u->buf1); + + return u->buf1; +} + +static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) { + struct impl_libsamplerate *u; + unsigned n_samples; + int i_skip, o_skip; + unsigned oc; + + assert(r); + assert(input); + assert(r->impl_data); + u = r->impl_data; + + /* Remap channels and place the result int buf2 */ + + if (!u->map_required) + return input; + + n_samples = n_frames * r->o_ss.channels; + + if (u->buf2_samples < n_samples) + u->buf2 = pa_xrealloc(u->buf2, sizeof(float) * (u->buf2_samples = n_samples)); + + memset(u->buf2, 0, n_samples * sizeof(float)); + + o_skip = sizeof(float) * r->o_ss.channels; + i_skip = sizeof(float) * r->i_ss.channels; + + for (oc = 0; oc < r->o_ss.channels; oc++) { + unsigned i; + static const float one = 1.0; + + for (i = 0; i < PA_CHANNELS_MAX && u->map_table[oc][i] >= 0; i++) + oil_vectoradd_f32( + u->buf2 + oc, o_skip, + u->buf2 + oc, o_skip, + input + u->map_table[oc][i], i_skip, + n_frames, + &one, &one); + } + + return u->buf2; +} + +static float *resample(pa_resampler *r, float *input, unsigned *n_frames) { + struct impl_libsamplerate *u; + SRC_DATA data; + unsigned out_n_frames, out_n_samples; + int ret; + + assert(r); + assert(input); + assert(n_frames); + assert(r->impl_data); + u = r->impl_data; + + /* Resample the data and place the result in buf3 */ + + if (!u->src_state) + return input; + + out_n_frames = (*n_frames*r->o_ss.rate/r->i_ss.rate)+1024; + out_n_samples = out_n_frames * r->o_ss.channels; + + if (u->buf3_samples < out_n_samples) + u->buf3 = pa_xrealloc(u->buf3, sizeof(float) * (u->buf3_samples = out_n_samples)); + + data.data_in = input; + data.input_frames = *n_frames; + + data.data_out = u->buf3; + data.output_frames = out_n_frames; + + data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate; + data.end_of_input = 0; + + ret = src_process(u->src_state, &data); + assert(ret == 0); + assert((unsigned) data.input_frames_used == *n_frames); + + *n_frames = data.output_frames_gen; + + return u->buf3; +} + +static void *convert_from_float(pa_resampler *r, float *input, unsigned n_frames) { + struct impl_libsamplerate *u; + unsigned n_samples; + + assert(r); + assert(input); + assert(r->impl_data); + u = r->impl_data; + + /* Convert the data into the correct sample type and place the result in buf4 */ + + if (!u->from_float32ne_func) + return input; + + n_samples = n_frames * r->o_ss.channels; + + if (u->buf4_samples < n_samples) + u->buf4 = pa_xrealloc(u->buf4, sizeof(float) * (u->buf4_samples = n_samples)); + + u->from_float32ne_func(n_samples, input, u->buf4); + + return u->buf4; +} + +static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { + struct impl_libsamplerate *u; + float *buf; + void *input, *output; + unsigned n_frames; + + assert(r); + assert(in); + assert(out); + assert(in->length); + assert(in->memblock); + assert(in->length % r->i_fz == 0); + assert(r->impl_data); + + u = r->impl_data; + + input = ((uint8_t*) in->memblock->data + in->index); + n_frames = in->length / r->i_fz; + assert(n_frames > 0); + + buf = convert_to_float(r, input, n_frames); + buf = remap_channels(r, buf, n_frames); + buf = resample(r, buf, &n_frames); + + if (n_frames) { + output = convert_from_float(r, buf, n_frames); + + if (output == input) { + /* Mm, no adjustment has been necessary, so let's return the original block */ + out->memblock = pa_memblock_ref(in->memblock); + out->index = in->index; + out->length = in->length; + } else { + float **p = NULL; + + out->length = n_frames * r->o_fz; + out->index = 0; + + if (output == u->buf1) { + p = &u->buf1; + u->buf1_samples = 0; + } else if (output == u->buf2) { + p = &u->buf2; + u->buf2_samples = 0; + } else if (output == u->buf3) { + p = &u->buf3; + u->buf3_samples = 0; + } else if (output == u->buf4) { + p = &u->buf4; + u->buf4_samples = 0; + } + + assert(p); + + /* Take the existing buffer and make it a memblock */ + out->memblock = pa_memblock_new_dynamic(*p, out->length, r->memblock_stat); + *p = NULL; + } + } else { + out->memblock = NULL; + out->index = out->length = 0; + } +} + +static void libsamplerate_update_input_rate(pa_resampler *r, uint32_t rate) { + struct impl_libsamplerate *u; + + assert(r); + assert(rate > 0); + assert(r->impl_data); + u = r->impl_data; + + if (!u->src_state) { + int err; + u->src_state = src_new(r->resample_method, r->o_ss.channels, &err); + assert(u->src_state); + } else { + int ret = src_set_ratio(u->src_state, (double) r->o_ss.rate / rate); + assert(ret == 0); + } +} + +static int libsamplerate_init(pa_resampler *r) { + struct impl_libsamplerate *u = NULL; + int err; + + r->impl_data = u = pa_xnew(struct impl_libsamplerate, 1); + + u->buf1 = u->buf2 = u->buf3 = u->buf4 = NULL; + u->buf1_samples = u->buf2_samples = u->buf3_samples = u->buf4_samples = 0; + + if (r->i_ss.format == PA_SAMPLE_FLOAT32NE) + u->to_float32ne_func = NULL; + else if (!(u->to_float32ne_func = pa_get_convert_to_float32ne_function(r->i_ss.format))) + goto fail; + + if (r->o_ss.format == PA_SAMPLE_FLOAT32NE) + u->from_float32ne_func = NULL; + else if (!(u->from_float32ne_func = pa_get_convert_from_float32ne_function(r->o_ss.format))) + goto fail; + + if (r->o_ss.rate == r->i_ss.rate) + u->src_state = NULL; + else if (!(u->src_state = src_new(r->resample_method, r->o_ss.channels, &err))) + goto fail; + + r->impl_free = libsamplerate_free; + r->impl_update_input_rate = libsamplerate_update_input_rate; + r->impl_run = libsamplerate_run; + + calc_map_table(r); + + return 0; + +fail: + pa_xfree(u); + return -1; +} + +/* Trivial implementation */ + +static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { + size_t fz; + unsigned n_frames; + struct impl_trivial *u; + + assert(r); + assert(in); + assert(out); + assert(r->impl_data); + + u = r->impl_data; + + fz = r->i_fz; + assert(fz == r->o_fz); + + n_frames = in->length/fz; + + if (r->i_ss.rate == r->o_ss.rate) { + + /* In case there's no diefference in sample types, do nothing */ + *out = *in; + pa_memblock_ref(out->memblock); + + u->o_counter += n_frames; + } else { + /* Do real resampling */ + size_t l; + unsigned o_index; + + /* The length of the new memory block rounded up */ + l = ((((n_frames+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz; + + out->index = 0; + out->memblock = pa_memblock_new(l, r->memblock_stat); + + for (o_index = 0;; o_index++, u->o_counter++) { + unsigned j; + + j = (u->o_counter * r->i_ss.rate / r->o_ss.rate); + j = j > u->i_counter ? j - u->i_counter : 0; + + if (j >= n_frames) + break; + + assert(o_index*fz < out->memblock->length); + + memcpy((uint8_t*) out->memblock->data + fz*o_index, + (uint8_t*) in->memblock->data + in->index + fz*j, fz); + + } + + out->length = o_index*fz; + } + + u->i_counter += n_frames; + + /* Normalize counters */ + while (u->i_counter >= r->i_ss.rate) { + u->i_counter -= r->i_ss.rate; + assert(u->o_counter >= r->o_ss.rate); + u->o_counter -= r->o_ss.rate; + } +} + +static void trivial_free(pa_resampler *r) { + assert(r); + + pa_xfree(r->impl_data); +} + +static void trivial_update_input_rate(pa_resampler *r, uint32_t rate) { + struct impl_trivial *u; + + assert(r); + assert(rate > 0); + assert(r->impl_data); + + u = r->impl_data; + u->i_counter = 0; + u->o_counter = 0; +} + +static int trivial_init(pa_resampler*r) { + struct impl_trivial *u; + + assert(r); + assert(r->i_ss.format == r->o_ss.format); + assert(r->i_ss.channels == r->o_ss.channels); + + r->impl_data = u = pa_xnew(struct impl_trivial, 1); + u->o_counter = u->i_counter = 0; + + r->impl_run = trivial_run; + r->impl_free = trivial_free; + r->impl_update_input_rate = trivial_update_input_rate; + + return 0; +} + + diff --git a/src/pulsecore/resampler.h b/src/pulsecore/resampler.h new file mode 100644 index 00000000..c1199e5c --- /dev/null +++ b/src/pulsecore/resampler.h @@ -0,0 +1,73 @@ +#ifndef fooresamplerhfoo +#define fooresamplerhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include +#include +#include + +typedef struct pa_resampler pa_resampler; + +typedef enum pa_resample_method { + PA_RESAMPLER_INVALID = -1, + PA_RESAMPLER_SRC_SINC_BEST_QUALITY = SRC_SINC_BEST_QUALITY, + PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY = SRC_SINC_MEDIUM_QUALITY, + PA_RESAMPLER_SRC_SINC_FASTEST = SRC_SINC_FASTEST, + PA_RESAMPLER_SRC_ZERO_ORDER_HOLD = SRC_ZERO_ORDER_HOLD, + PA_RESAMPLER_SRC_LINEAR = SRC_LINEAR, + PA_RESAMPLER_TRIVIAL, + PA_RESAMPLER_MAX +} pa_resample_method_t; + +pa_resampler* pa_resampler_new( + const pa_sample_spec *a, + const pa_channel_map *am, + const pa_sample_spec *b, + const pa_channel_map *bm, + pa_memblock_stat *s, + pa_resample_method_t resample_method); + +void pa_resampler_free(pa_resampler *r); + +/* Returns the size of an input memory block which is required to return the specified amount of output data */ +size_t pa_resampler_request(pa_resampler *r, size_t out_length); + +/* Pass the specified memory chunk to the resampler and return the newly resampled data */ +void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out); + +/* Change the input rate of the resampler object */ +void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate); + +/* Return the resampling method of the resampler object */ +pa_resample_method_t pa_resampler_get_method(pa_resampler *r); + +/* Try to parse the resampler method */ +pa_resample_method_t pa_parse_resample_method(const char *string); + +/* return a human readable string for the specified resampling method. Inverse of pa_parse_resample_method() */ +const char *pa_resample_method_to_string(pa_resample_method_t m); + +#endif diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c new file mode 100644 index 00000000..638f8067 --- /dev/null +++ b/src/pulsecore/sample-util.c @@ -0,0 +1,405 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include + +#include "sample-util.h" +#include "endianmacros.h" + +pa_memblock *pa_silence_memblock_new(const pa_sample_spec *spec, size_t length, pa_memblock_stat*s) { + assert(spec); + + if (length == 0) + length = pa_bytes_per_second(spec)/10; /* 100 ms */ + + return pa_silence_memblock(pa_memblock_new(length, s), spec); +} + +pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) { + assert(b && b->data && spec); + pa_silence_memory(b->data, b->length, spec); + return b; +} + +void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) { + assert(c && c->memblock && c->memblock->data && spec && c->length); + + pa_silence_memory((uint8_t*) c->memblock->data+c->index, c->length, spec); +} + +void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { + uint8_t c = 0; + assert(p && length && spec); + + switch (spec->format) { + case PA_SAMPLE_U8: + c = 0x80; + break; + case PA_SAMPLE_S16LE: + case PA_SAMPLE_S16BE: + case PA_SAMPLE_FLOAT32: + c = 0; + break; + case PA_SAMPLE_ALAW: + case PA_SAMPLE_ULAW: + c = 80; + break; + default: + assert(0); + } + + memset(p, c, length); +} + +size_t pa_mix( + const pa_mix_info streams[], + unsigned nstreams, + void *data, + size_t length, + const pa_sample_spec *spec, + const pa_cvolume *volume, + int mute) { + + assert(streams && data && length && spec); + + switch (spec->format) { + case PA_SAMPLE_S16NE:{ + size_t d; + unsigned channel = 0; + + for (d = 0;; d += sizeof(int16_t)) { + int32_t sum = 0; + + if (d >= length) + return d; + + if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { + unsigned i; + + for (i = 0; i < nstreams; i++) { + int32_t v; + pa_volume_t cvolume = streams[i].volume.values[channel]; + + if (d >= streams[i].chunk.length) + return d; + + if (cvolume == PA_VOLUME_MUTED) + v = 0; + else { + v = *((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); + + if (cvolume != PA_VOLUME_NORM) + v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); + } + + sum += v; + } + + if (volume->values[channel] != PA_VOLUME_NORM) + sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); + + if (sum < -0x8000) sum = -0x8000; + if (sum > 0x7FFF) sum = 0x7FFF; + + } + + *((int16_t*) data) = sum; + data = (uint8_t*) data + sizeof(int16_t); + + if (++channel >= spec->channels) + channel = 0; + } + } + + case PA_SAMPLE_S16RE:{ + size_t d; + unsigned channel = 0; + + for (d = 0;; d += sizeof(int16_t)) { + int32_t sum = 0; + + if (d >= length) + return d; + + if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { + unsigned i; + + for (i = 0; i < nstreams; i++) { + int32_t v; + pa_volume_t cvolume = streams[i].volume.values[channel]; + + if (d >= streams[i].chunk.length) + return d; + + if (cvolume == PA_VOLUME_MUTED) + v = 0; + else { + v = INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d))); + + if (cvolume != PA_VOLUME_NORM) + v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); + } + + sum += v; + } + + if (volume->values[channel] != PA_VOLUME_NORM) + sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); + + if (sum < -0x8000) sum = -0x8000; + if (sum > 0x7FFF) sum = 0x7FFF; + + } + + *((int16_t*) data) = INT16_SWAP(sum); + data = (uint8_t*) data + sizeof(int16_t); + + if (++channel >= spec->channels) + channel = 0; + } + } + + case PA_SAMPLE_U8: { + size_t d; + unsigned channel = 0; + + for (d = 0;; d ++) { + int32_t sum = 0; + + if (d >= length) + return d; + + if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { + unsigned i; + + for (i = 0; i < nstreams; i++) { + int32_t v; + pa_volume_t cvolume = streams[i].volume.values[channel]; + + if (d >= streams[i].chunk.length) + return d; + + if (cvolume == PA_VOLUME_MUTED) + v = 0; + else { + v = (int32_t) *((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d) - 0x80; + + if (cvolume != PA_VOLUME_NORM) + v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); + } + + sum += v; + } + + if (volume->values[channel] != PA_VOLUME_NORM) + sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); + + if (sum < -0x80) sum = -0x80; + if (sum > 0x7F) sum = 0x7F; + + } + + *((uint8_t*) data) = (uint8_t) (sum + 0x80); + data = (uint8_t*) data + 1; + + if (++channel >= spec->channels) + channel = 0; + } + } + + case PA_SAMPLE_FLOAT32NE: { + size_t d; + unsigned channel = 0; + + for (d = 0;; d += sizeof(float)) { + float sum = 0; + + if (d >= length) + return d; + + if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { + unsigned i; + + for (i = 0; i < nstreams; i++) { + float v; + pa_volume_t cvolume = streams[i].volume.values[channel]; + + if (d >= streams[i].chunk.length) + return d; + + if (cvolume == PA_VOLUME_MUTED) + v = 0; + else { + v = *((float*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); + + if (cvolume != PA_VOLUME_NORM) + v *= pa_sw_volume_to_linear(cvolume); + } + + sum += v; + } + + if (volume->values[channel] != PA_VOLUME_NORM) + sum *= pa_sw_volume_to_linear(volume->values[channel]); + } + + *((float*) data) = sum; + data = (uint8_t*) data + sizeof(float); + + if (++channel >= spec->channels) + channel = 0; + } + } + + default: + pa_log_error(__FILE__": ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format)); + abort(); + } +} + + +void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvolume *volume) { + assert(c && spec && (c->length % pa_frame_size(spec) == 0)); + assert(volume); + + if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM)) + return; + + if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) { + pa_silence_memchunk(c, spec); + return; + } + + switch (spec->format) { + case PA_SAMPLE_S16NE: { + int16_t *d; + size_t n; + unsigned channel; + double linear[PA_CHANNELS_MAX]; + + for (channel = 0; channel < spec->channels; channel++) + linear[channel] = pa_sw_volume_to_linear(volume->values[channel]); + + for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { + int32_t t = (int32_t)(*d); + + t = (int32_t) (t * linear[channel]); + + if (t < -0x8000) t = -0x8000; + if (t > 0x7FFF) t = 0x7FFF; + + *d = (int16_t) t; + + if (++channel >= spec->channels) + channel = 0; + } + break; + } + + case PA_SAMPLE_S16RE: { + int16_t *d; + size_t n; + unsigned channel; + double linear[PA_CHANNELS_MAX]; + + for (channel = 0; channel < spec->channels; channel++) + linear[channel] = pa_sw_volume_to_linear(volume->values[channel]); + + for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { + int32_t t = (int32_t)(INT16_SWAP(*d)); + + t = (int32_t) (t * linear[channel]); + + if (t < -0x8000) t = -0x8000; + if (t > 0x7FFF) t = 0x7FFF; + + *d = INT16_SWAP((int16_t) t); + + if (++channel >= spec->channels) + channel = 0; + } + + break; + } + + case PA_SAMPLE_U8: { + uint8_t *d; + size_t n; + unsigned channel = 0; + + for (d = (uint8_t*) c->memblock->data + c->index, n = c->length; n > 0; d++, n--) { + int32_t t = (int32_t) *d - 0x80; + + t = (int32_t) (t * pa_sw_volume_to_linear(volume->values[channel])); + + if (t < -0x80) t = -0x80; + if (t > 0x7F) t = 0x7F; + + *d = (uint8_t) (t + 0x80); + + if (++channel >= spec->channels) + channel = 0; + } + break; + } + + case PA_SAMPLE_FLOAT32NE: { + float *d; + int skip; + unsigned n; + unsigned channel; + + d = (float*) ((uint8_t*) c->memblock->data + c->index); + skip = spec->channels * sizeof(float); + n = c->length/sizeof(float)/spec->channels; + + for (channel = 0; channel < spec->channels ; channel ++) { + float v, *t; + + if (volume->values[channel] == PA_VOLUME_NORM) + continue; + + v = (float) pa_sw_volume_to_linear(volume->values[channel]); + + t = d + channel; + oil_scalarmult_f32(t, skip, t, skip, &v, n); + } + break; + } + + default: + pa_log_error(__FILE__": ERROR: Unable to change volume of format %s.", + pa_sample_format_to_string(spec->format)); + abort(); + } +} + diff --git a/src/pulsecore/sample-util.h b/src/pulsecore/sample-util.h new file mode 100644 index 00000000..3ebb7e2e --- /dev/null +++ b/src/pulsecore/sample-util.h @@ -0,0 +1,55 @@ +#ifndef foosampleutilhfoo +#define foosampleutilhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec); +pa_memblock *pa_silence_memblock_new(const pa_sample_spec *spec, size_t length, pa_memblock_stat*s); +void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec); +void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec); + +typedef struct pa_mix_info { + pa_memchunk chunk; + pa_cvolume volume; + void *userdata; +} pa_mix_info; + +size_t pa_mix( + const pa_mix_info channels[], + unsigned nchannels, + void *data, + size_t length, + const pa_sample_spec *spec, + const pa_cvolume *volume, + int mute); + +void pa_volume_memchunk( + pa_memchunk*c, + const pa_sample_spec *spec, + const pa_cvolume *volume); + +#endif diff --git a/src/pulsecore/sconv-s16be.c b/src/pulsecore/sconv-s16be.c new file mode 100644 index 00000000..5ac96320 --- /dev/null +++ b/src/pulsecore/sconv-s16be.c @@ -0,0 +1,41 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "endianmacros.h" + +#define INT16_FROM INT16_FROM_BE +#define INT16_TO INT16_TO_BE + +#define pa_sconv_s16le_to_float32ne pa_sconv_s16be_to_float32ne +#define pa_sconv_s16le_from_float32ne pa_sconv_s16be_from_float32ne + +#ifdef WORDS_BIGENDIAN +#define SWAP_WORDS 0 +#else +#define SWAP_WORDS 1 +#endif + +#include "sconv-s16le.h" +#include "sconv-s16le.c" diff --git a/src/pulsecore/sconv-s16be.h b/src/pulsecore/sconv-s16be.h new file mode 100644 index 00000000..bd3fd345 --- /dev/null +++ b/src/pulsecore/sconv-s16be.h @@ -0,0 +1,28 @@ +#ifndef foosconv_s16befoo +#define foosconv_s16befoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +void pa_sconv_s16be_to_float32ne(unsigned n, const void *a, float *b); +void pa_sconv_s16be_from_float32ne(unsigned n, const float *a, void *b); + +#endif diff --git a/src/pulsecore/sconv-s16le.c b/src/pulsecore/sconv-s16le.c new file mode 100644 index 00000000..d8b93cbd --- /dev/null +++ b/src/pulsecore/sconv-s16le.c @@ -0,0 +1,103 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include +#include + +#include "endianmacros.h" + +#include "sconv-s16le.h" + +#ifndef INT16_FROM +#define INT16_FROM INT16_FROM_LE +#endif + +#ifndef INT16_TO +#define INT16_TO INT16_TO_LE +#endif + +#ifndef SWAP_WORDS +#ifdef WORDS_BIGENDIAN +#define SWAP_WORDS 1 +#else +#define SWAP_WORDS 0 +#endif +#endif + +void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b) { + const int16_t *ca = a; + + assert(a); + assert(b); + +#if SWAP_WORDS == 1 + + for (; n > 0; n--) { + int16_t s = *(ca++); + *(b++) = ((float) INT16_FROM(s))/0x7FFF; + } + +#else +{ + static const double add = 0, factor = 1.0/0x7FFF; + oil_scaleconv_f32_s16(b, ca, n, &add, &factor); +} +#endif +} + +void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b) { + int16_t *cb = b; + + assert(a); + assert(b); + +#if SWAP_WORDS == 1 + + for (; n > 0; n--) { + int16_t s; + float v = *(a++); + + if (v > 1) + v = 1; + + if (v < -1) + v = -1; + + s = (int16_t) (v * 0x7FFF); + *(cb++) = INT16_TO(s); + } + +#else +{ + static const double add = 0, factor = 0x7FFF; + oil_scaleconv_s16_f32(cb, a, n, &add, &factor); +} +#endif +} diff --git a/src/pulsecore/sconv-s16le.h b/src/pulsecore/sconv-s16le.h new file mode 100644 index 00000000..ae6e22d2 --- /dev/null +++ b/src/pulsecore/sconv-s16le.h @@ -0,0 +1,28 @@ +#ifndef foosconv_s16lefoo +#define foosconv_s16lefoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b); +void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b); + +#endif diff --git a/src/pulsecore/sconv.c b/src/pulsecore/sconv.c new file mode 100644 index 00000000..ff2a0110 --- /dev/null +++ b/src/pulsecore/sconv.c @@ -0,0 +1,169 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +#include + +#include "endianmacros.h" +#include "sconv-s16le.h" +#include "sconv-s16be.h" + +#include "sconv.h" + +static void u8_to_float32ne(unsigned n, const void *a, float *b) { + const uint8_t *ca = a; + static const double add = -128.0/127.0, factor = 1.0/127.0; + + assert(a); + assert(b); + + oil_scaleconv_f32_u8(b, ca, n, &add, &factor); +} + +static void u8_from_float32ne(unsigned n, const float *a, void *b) { + uint8_t *cb = b; + static const double add = 128.0, factor = 127.0; + + assert(a); + assert(b); + + oil_scaleconv_u8_f32(cb, a, n, &add, &factor); +} + +static void float32ne_to_float32ne(unsigned n, const void *a, float *b) { + assert(a); + assert(b); + + oil_memcpy(b, a, sizeof(float) * n); +} + +static void float32ne_from_float32ne(unsigned n, const float *a, void *b) { + assert(a); + assert(b); + + oil_memcpy(b, a, sizeof(float) * n); +} + +static void ulaw_to_float32ne(unsigned n, const void *a, float *b) { + const uint8_t *ca = a; + + assert(a); + assert(b); + + for (; n > 0; n--) + *(b++) = st_ulaw2linear16(*(ca++)) * 1.0F / 0x7FFF; +} + +static void ulaw_from_float32ne(unsigned n, const float *a, void *b) { + uint8_t *cb = b; + + assert(a); + assert(b); + + for (; n > 0; n--) { + float v = *(a++); + + if (v > 1) + v = 1; + + if (v < -1) + v = -1; + + *(cb++) = st_14linear2ulaw((int16_t) (v * 0x1FFF)); + } +} + +static void alaw_to_float32ne(unsigned n, const void *a, float *b) { + const uint8_t *ca = a; + + assert(a); + assert(b); + + for (; n > 0; n--) + *(b++) = st_alaw2linear16(*(ca++)) * 1.0F / 0x7FFF; +} + +static void alaw_from_float32ne(unsigned n, const float *a, void *b) { + uint8_t *cb = b; + + assert(a); + assert(b); + + for (; n > 0; n--) { + float v = *(a++); + + if (v > 1) + v = 1; + + if (v < -1) + v = -1; + + *(cb++) = st_13linear2alaw((int16_t) (v * 0xFFF)); + } +} + +pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f) { + switch(f) { + case PA_SAMPLE_U8: + return u8_to_float32ne; + case PA_SAMPLE_S16LE: + return pa_sconv_s16le_to_float32ne; + case PA_SAMPLE_S16BE: + return pa_sconv_s16be_to_float32ne; + case PA_SAMPLE_FLOAT32NE: + return float32ne_to_float32ne; + case PA_SAMPLE_ALAW: + return alaw_to_float32ne; + case PA_SAMPLE_ULAW: + return ulaw_to_float32ne; + default: + return NULL; + } +} + +pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f) { + switch(f) { + case PA_SAMPLE_U8: + return u8_from_float32ne; + case PA_SAMPLE_S16LE: + return pa_sconv_s16le_from_float32ne; + case PA_SAMPLE_S16BE: + return pa_sconv_s16be_from_float32ne; + case PA_SAMPLE_FLOAT32NE: + return float32ne_from_float32ne; + case PA_SAMPLE_ALAW: + return alaw_from_float32ne; + case PA_SAMPLE_ULAW: + return ulaw_from_float32ne; + default: + return NULL; + } +} diff --git a/src/pulsecore/sconv.h b/src/pulsecore/sconv.h new file mode 100644 index 00000000..4aba0694 --- /dev/null +++ b/src/pulsecore/sconv.h @@ -0,0 +1,33 @@ +#ifndef foosconvhfoo +#define foosconvhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef void (*pa_convert_to_float32ne_func_t)(unsigned n, const void *a, float *b); +typedef void (*pa_convert_from_float32ne_func_t)(unsigned n, const float *a, void *b); + +pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f); +pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f); + +#endif diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c new file mode 100644 index 00000000..8590a0b1 --- /dev/null +++ b/src/pulsecore/sink-input.c @@ -0,0 +1,386 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "sink-input.h" + +#define CONVERT_BUFFER_LENGTH 4096 + +#define CHECK_VALIDITY_RETURN_NULL(condition) \ +do {\ +if (!(condition)) \ + return NULL; \ +} while (0) + +pa_sink_input* pa_sink_input_new( + pa_sink *s, + const char *driver, + const char *name, + const pa_sample_spec *spec, + const pa_channel_map *map, + const pa_cvolume *volume, + int variable_rate, + int resample_method) { + + pa_sink_input *i; + pa_resampler *resampler = NULL; + int r; + char st[256]; + pa_channel_map tmap; + pa_cvolume tvol; + + assert(s); + assert(spec); + assert(s->state == PA_SINK_RUNNING); + + CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec)); + + if (!map) + map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT); + if (!volume) + volume = pa_cvolume_reset(&tvol, spec->channels); + + CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map)); + CHECK_VALIDITY_RETURN_NULL(volume && pa_cvolume_valid(volume)); + CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels); + CHECK_VALIDITY_RETURN_NULL(volume->channels == spec->channels); + CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver)); + CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name)); + + if (pa_idxset_size(s->inputs) >= PA_MAX_INPUTS_PER_SINK) { + pa_log_warn(__FILE__": Failed to create sink input: too many inputs per sink."); + return NULL; + } + + if (resample_method == PA_RESAMPLER_INVALID) + resample_method = s->core->resample_method; + + if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec) || !pa_channel_map_equal(map, &s->channel_map)) + if (!(resampler = pa_resampler_new(spec, map, &s->sample_spec, &s->channel_map, s->core->memblock_stat, resample_method))) + return NULL; + + i = pa_xnew(pa_sink_input, 1); + i->ref = 1; + i->state = PA_SINK_INPUT_RUNNING; + i->name = pa_xstrdup(name); + i->driver = pa_xstrdup(driver); + i->owner = NULL; + i->sink = s; + i->client = NULL; + + i->sample_spec = *spec; + i->channel_map = *map; + i->volume = *volume; + + i->peek = NULL; + i->drop = NULL; + i->kill = NULL; + i->get_latency = NULL; + i->underrun = NULL; + i->userdata = NULL; + + i->playing = 0; + + pa_memchunk_reset(&i->resampled_chunk); + i->resampler = resampler; + + assert(s->core); + r = pa_idxset_put(s->core->sink_inputs, i, &i->index); + assert(r == 0 && i->index != PA_IDXSET_INVALID); + r = pa_idxset_put(s->inputs, i, NULL); + assert(r == 0); + + pa_sample_spec_snprint(st, sizeof(st), spec); + pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"", i->index, i->name, s->index, st); + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index); + + return i; +} + +void pa_sink_input_disconnect(pa_sink_input *i) { + assert(i); + assert(i->state != PA_SINK_INPUT_DISCONNECTED); + assert(i->sink); + assert(i->sink->core); + + pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); + pa_idxset_remove_by_data(i->sink->inputs, i, NULL); + + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index); + i->sink = NULL; + + i->peek = NULL; + i->drop = NULL; + i->kill = NULL; + i->get_latency = NULL; + i->underrun = NULL; + + i->playing = 0; + i->state = PA_SINK_INPUT_DISCONNECTED; +} + +static void sink_input_free(pa_sink_input* i) { + assert(i); + + if (i->state != PA_SINK_INPUT_DISCONNECTED) + pa_sink_input_disconnect(i); + + pa_log_info(__FILE__": freed %u \"%s\"", i->index, i->name); + + if (i->resampled_chunk.memblock) + pa_memblock_unref(i->resampled_chunk.memblock); + + if (i->resampler) + pa_resampler_free(i->resampler); + + pa_xfree(i->name); + pa_xfree(i->driver); + pa_xfree(i); +} + +void pa_sink_input_unref(pa_sink_input *i) { + assert(i); + assert(i->ref >= 1); + + if (!(--i->ref)) + sink_input_free(i); +} + +pa_sink_input* pa_sink_input_ref(pa_sink_input *i) { + assert(i); + assert(i->ref >= 1); + + i->ref++; + return i; +} + +void pa_sink_input_kill(pa_sink_input*i) { + assert(i); + assert(i->ref >= 1); + + if (i->kill) + i->kill(i); +} + +pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) { + pa_usec_t r = 0; + + assert(i); + assert(i->ref >= 1); + + if (i->get_latency) + r += i->get_latency(i); + + if (i->resampled_chunk.memblock) + r += pa_bytes_to_usec(i->resampled_chunk.length, &i->sample_spec); + + return r; +} + +int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) { + int ret = -1; + int do_volume_adj_here; + + assert(i); + assert(i->ref >= 1); + assert(chunk); + assert(volume); + + pa_sink_input_ref(i); + + if (!i->peek || !i->drop || i->state == PA_SINK_INPUT_CORKED) + goto finish; + + if (!i->resampler) { + do_volume_adj_here = 0; + ret = i->peek(i, chunk); + goto finish; + } + + do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map); + + while (!i->resampled_chunk.memblock) { + pa_memchunk tchunk; + size_t l; + + if ((ret = i->peek(i, &tchunk)) < 0) + goto finish; + + assert(tchunk.length); + + l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); + + if (l > tchunk.length) + l = tchunk.length; + + i->drop(i, &tchunk, l); + tchunk.length = l; + + /* It might be necessary to adjust the volume here */ + if (do_volume_adj_here) { + pa_memchunk_make_writable(&tchunk, i->sink->core->memblock_stat, 0); + pa_volume_memchunk(&tchunk, &i->sample_spec, &i->volume); + } + + pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk); + pa_memblock_unref(tchunk.memblock); + } + + assert(i->resampled_chunk.memblock); + assert(i->resampled_chunk.length); + + *chunk = i->resampled_chunk; + pa_memblock_ref(i->resampled_chunk.memblock); + + ret = 0; + +finish: + + if (ret < 0 && i->playing && i->underrun) + i->underrun(i); + + i->playing = ret >= 0; + + if (ret >= 0) { + /* Let's see if we had to apply the volume adjustment + * ourselves, or if this can be done by the sink for us */ + + if (do_volume_adj_here) + /* We had different channel maps, so we already did the adjustment */ + pa_cvolume_reset(volume, i->sink->sample_spec.channels); + else + /* We've both the same channel map, so let's have the sink do the adjustment for us*/ + *volume = i->volume; + } + + pa_sink_input_unref(i); + + return ret; +} + +void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { + assert(i); + assert(i->ref >= 1); + assert(length > 0); + + if (!i->resampler) { + if (i->drop) + i->drop(i, chunk, length); + return; + } + + assert(i->resampled_chunk.memblock); + assert(i->resampled_chunk.length >= length); + + i->resampled_chunk.index += length; + i->resampled_chunk.length -= length; + + if (i->resampled_chunk.length <= 0) { + pa_memblock_unref(i->resampled_chunk.memblock); + i->resampled_chunk.memblock = NULL; + i->resampled_chunk.index = i->resampled_chunk.length = 0; + } +} + +void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) { + assert(i); + assert(i->ref >= 1); + assert(i->sink); + assert(i->sink->core); + + if (pa_cvolume_equal(&i->volume, volume)) + return; + + i->volume = *volume; + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); +} + +const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i) { + assert(i); + assert(i->ref >= 1); + + return &i->volume; +} + +void pa_sink_input_cork(pa_sink_input *i, int b) { + int n; + + assert(i); + assert(i->ref >= 1); + + if (i->state == PA_SINK_INPUT_DISCONNECTED) + return; + + n = i->state == PA_SINK_INPUT_CORKED && !b; + + i->state = b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING; + + if (n) + pa_sink_notify(i->sink); +} + +void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) { + assert(i); + assert(i->resampler); + assert(i->ref >= 1); + + if (i->sample_spec.rate == rate) + return; + + i->sample_spec.rate = rate; + pa_resampler_set_input_rate(i->resampler, rate); +} + +void pa_sink_input_set_name(pa_sink_input *i, const char *name) { + assert(i); + assert(i->ref >= 1); + + pa_xfree(i->name); + i->name = pa_xstrdup(name); + + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); +} + +pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) { + assert(i); + assert(i->ref >= 1); + + if (!i->resampler) + return PA_RESAMPLER_INVALID; + + return pa_resampler_get_method(i->resampler); +} diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h new file mode 100644 index 00000000..69a7e50a --- /dev/null +++ b/src/pulsecore/sink-input.h @@ -0,0 +1,107 @@ +#ifndef foosinkinputhfoo +#define foosinkinputhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef struct pa_sink_input pa_sink_input; + +#include +#include +#include +#include +#include +#include + +typedef enum pa_sink_input_state { + PA_SINK_INPUT_RUNNING, + PA_SINK_INPUT_CORKED, + PA_SINK_INPUT_DISCONNECTED +} pa_sink_input_state_t; + +struct pa_sink_input { + int ref; + uint32_t index; + pa_sink_input_state_t state; + + char *name, *driver; + pa_module *owner; + + pa_sink *sink; + pa_client *client; + + pa_sample_spec sample_spec; + pa_channel_map channel_map; + + pa_cvolume volume; + + int (*peek) (pa_sink_input *i, pa_memchunk *chunk); + void (*drop) (pa_sink_input *i, const pa_memchunk *chunk, size_t length); + void (*kill) (pa_sink_input *i); + pa_usec_t (*get_latency) (pa_sink_input *i); + void (*underrun) (pa_sink_input *i); + + void *userdata; + + int playing; + + pa_memchunk resampled_chunk; + pa_resampler *resampler; +}; + +pa_sink_input* pa_sink_input_new( + pa_sink *s, + const char *driver, + const char *name, + const pa_sample_spec *spec, + const pa_channel_map *map, + const pa_cvolume *volume, + int variable_rate, + int resample_method); + +void pa_sink_input_unref(pa_sink_input* i); +pa_sink_input* pa_sink_input_ref(pa_sink_input* i); + +/* To be called by the implementing module only */ +void pa_sink_input_disconnect(pa_sink_input* i); + +/* External code may request disconnection with this funcion */ +void pa_sink_input_kill(pa_sink_input*i); + +pa_usec_t pa_sink_input_get_latency(pa_sink_input *i); + +int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume); +void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length); + +void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume); +const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i); + +void pa_sink_input_cork(pa_sink_input *i, int b); + +void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate); + +void pa_sink_input_set_name(pa_sink_input *i, const char *name); + +pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i); + +#endif diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c new file mode 100644 index 00000000..ee6850f0 --- /dev/null +++ b/src/pulsecore/sink.c @@ -0,0 +1,513 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "sink.h" + +#define MAX_MIX_CHANNELS 32 + +#define CHECK_VALIDITY_RETURN_NULL(condition) \ +do {\ +if (!(condition)) \ + return NULL; \ +} while (0) + +pa_sink* pa_sink_new( + pa_core *core, + const char *driver, + const char *name, + int fail, + const pa_sample_spec *spec, + const pa_channel_map *map) { + + pa_sink *s; + char *n = NULL; + char st[256]; + int r; + pa_channel_map tmap; + + assert(core); + assert(name); + assert(spec); + + CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec)); + + if (!map) + map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT); + + CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map)); + CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels); + CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver)); + CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name) && *name); + + s = pa_xnew(pa_sink, 1); + + if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) { + pa_xfree(s); + return NULL; + } + + s->ref = 1; + s->core = core; + s->state = PA_SINK_RUNNING; + s->name = pa_xstrdup(name); + s->description = NULL; + s->driver = pa_xstrdup(driver); + s->owner = NULL; + + s->sample_spec = *spec; + s->channel_map = *map; + + s->inputs = pa_idxset_new(NULL, NULL); + + pa_cvolume_reset(&s->sw_volume, spec->channels); + pa_cvolume_reset(&s->hw_volume, spec->channels); + s->sw_muted = 0; + s->hw_muted = 0; + + s->get_latency = NULL; + s->notify = NULL; + s->set_hw_volume = NULL; + s->get_hw_volume = NULL; + s->set_hw_mute = NULL; + s->get_hw_mute = NULL; + s->userdata = NULL; + + r = pa_idxset_put(core->sinks, s, &s->index); + assert(s->index != PA_IDXSET_INVALID && r >= 0); + + pa_sample_spec_snprint(st, sizeof(st), spec); + pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"", s->index, s->name, st); + + n = pa_sprintf_malloc("%s_monitor", name); + s->monitor_source = pa_source_new(core, driver, n, 0, spec, map); + assert(s->monitor_source); + pa_xfree(n); + s->monitor_source->monitor_of = s; + s->monitor_source->description = pa_sprintf_malloc("Monitor source of sink '%s'", s->name); + + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index); + + return s; +} + +void pa_sink_disconnect(pa_sink* s) { + pa_sink_input *i, *j = NULL; + + assert(s); + assert(s->state == PA_SINK_RUNNING); + + pa_namereg_unregister(s->core, s->name); + + while ((i = pa_idxset_first(s->inputs, NULL))) { + assert(i != j); + pa_sink_input_kill(i); + j = i; + } + + pa_source_disconnect(s->monitor_source); + + pa_idxset_remove_by_data(s->core->sinks, s, NULL); + + s->get_latency = NULL; + s->notify = NULL; + s->get_hw_volume = NULL; + s->set_hw_volume = NULL; + s->set_hw_mute = NULL; + s->get_hw_mute = NULL; + + s->state = PA_SINK_DISCONNECTED; + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); +} + +static void sink_free(pa_sink *s) { + assert(s); + assert(!s->ref); + + if (s->state != PA_SINK_DISCONNECTED) + pa_sink_disconnect(s); + + pa_log_info(__FILE__": freed %u \"%s\"", s->index, s->name); + + pa_source_unref(s->monitor_source); + s->monitor_source = NULL; + + pa_idxset_free(s->inputs, NULL, NULL); + + pa_xfree(s->name); + pa_xfree(s->description); + pa_xfree(s->driver); + pa_xfree(s); +} + +void pa_sink_unref(pa_sink*s) { + assert(s); + assert(s->ref >= 1); + + if (!(--s->ref)) + sink_free(s); +} + +pa_sink* pa_sink_ref(pa_sink *s) { + assert(s); + assert(s->ref >= 1); + + s->ref++; + return s; +} + +void pa_sink_notify(pa_sink*s) { + assert(s); + assert(s->ref >= 1); + + if (s->notify) + s->notify(s); +} + +static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) { + uint32_t idx = PA_IDXSET_INVALID; + pa_sink_input *i; + unsigned n = 0; + + assert(s); + assert(s->ref >= 1); + assert(info); + + for (i = pa_idxset_first(s->inputs, &idx); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &idx)) { + /* Increase ref counter, to make sure that this input doesn't + * vanish while we still need it */ + pa_sink_input_ref(i); + + if (pa_sink_input_peek(i, &info->chunk, &info->volume) < 0) { + pa_sink_input_unref(i); + continue; + } + + info->userdata = i; + + assert(info->chunk.memblock); + assert(info->chunk.memblock->data); + assert(info->chunk.length); + + info++; + maxinfo--; + n++; + } + + return n; +} + +static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned maxinfo, size_t length) { + assert(s); + assert(s->ref >= 1); + assert(info); + + for (; maxinfo > 0; maxinfo--, info++) { + pa_sink_input *i = info->userdata; + + assert(i); + assert(info->chunk.memblock); + + /* Drop read data */ + pa_sink_input_drop(i, &info->chunk, length); + pa_memblock_unref(info->chunk.memblock); + + /* Decrease ref counter */ + pa_sink_input_unref(i); + info->userdata = NULL; + } +} + +int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { + pa_mix_info info[MAX_MIX_CHANNELS]; + unsigned n; + int r = -1; + + assert(s); + assert(s->ref >= 1); + assert(length); + assert(result); + + pa_sink_ref(s); + + n = fill_mix_info(s, info, MAX_MIX_CHANNELS); + + if (n <= 0) + goto finish; + + if (n == 1) { + pa_cvolume volume; + + *result = info[0].chunk; + pa_memblock_ref(result->memblock); + + if (result->length > length) + result->length = length; + + pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); + + if (s->sw_muted || !pa_cvolume_is_norm(&volume)) { + pa_memchunk_make_writable(result, s->core->memblock_stat, 0); + if (s->sw_muted) + pa_silence_memchunk(result, &s->sample_spec); + else + pa_volume_memchunk(result, &s->sample_spec, &volume); + } + } else { + result->memblock = pa_memblock_new(length, s->core->memblock_stat); + assert(result->memblock); + +/* pa_log("mixing %i", n); */ + + result->length = pa_mix(info, n, result->memblock->data, length, + &s->sample_spec, &s->sw_volume, s->sw_muted); + result->index = 0; + } + + inputs_drop(s, info, n, result->length); + pa_source_post(s->monitor_source, result); + + r = 0; + +finish: + pa_sink_unref(s); + + return r; +} + +int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { + pa_mix_info info[MAX_MIX_CHANNELS]; + unsigned n; + int r = -1; + + assert(s); + assert(s->ref >= 1); + assert(target); + assert(target->memblock); + assert(target->length); + assert(target->memblock->data); + + pa_sink_ref(s); + + n = fill_mix_info(s, info, MAX_MIX_CHANNELS); + + if (n <= 0) + goto finish; + + if (n == 1) { + pa_cvolume volume; + + if (target->length > info[0].chunk.length) + target->length = info[0].chunk.length; + + memcpy((uint8_t*) target->memblock->data + target->index, + (uint8_t*) info[0].chunk.memblock->data + info[0].chunk.index, + target->length); + + pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); + + if (s->sw_muted) + pa_silence_memchunk(target, &s->sample_spec); + else if (!pa_cvolume_is_norm(&volume)) + pa_volume_memchunk(target, &s->sample_spec, &volume); + } else + target->length = pa_mix(info, n, + (uint8_t*) target->memblock->data + target->index, + target->length, + &s->sample_spec, + &s->sw_volume, + s->sw_muted); + + inputs_drop(s, info, n, target->length); + pa_source_post(s->monitor_source, target); + + r = 0; + +finish: + pa_sink_unref(s); + + return r; +} + +void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { + pa_memchunk chunk; + size_t l, d; + + assert(s); + assert(s->ref >= 1); + assert(target); + assert(target->memblock); + assert(target->length); + assert(target->memblock->data); + + pa_sink_ref(s); + + l = target->length; + d = 0; + while (l > 0) { + chunk = *target; + chunk.index += d; + chunk.length -= d; + + if (pa_sink_render_into(s, &chunk) < 0) + break; + + d += chunk.length; + l -= chunk.length; + } + + if (l > 0) { + chunk = *target; + chunk.index += d; + chunk.length -= d; + pa_silence_memchunk(&chunk, &s->sample_spec); + } + + pa_sink_unref(s); +} + +void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { + assert(s); + assert(s->ref >= 1); + assert(length); + assert(result); + + /*** This needs optimization ***/ + + result->memblock = pa_memblock_new(result->length = length, s->core->memblock_stat); + result->index = 0; + + pa_sink_render_into_full(s, result); +} + +pa_usec_t pa_sink_get_latency(pa_sink *s) { + assert(s); + assert(s->ref >= 1); + + if (!s->get_latency) + return 0; + + return s->get_latency(s); +} + +void pa_sink_set_owner(pa_sink *s, pa_module *m) { + assert(s); + assert(s->ref >= 1); + + s->owner = m; + + if (s->monitor_source) + pa_source_set_owner(s->monitor_source, m); +} + +void pa_sink_set_volume(pa_sink *s, pa_mixer_t m, const pa_cvolume *volume) { + pa_cvolume *v; + + assert(s); + assert(s->ref >= 1); + assert(volume); + + if (m == PA_MIXER_HARDWARE && s->set_hw_volume) + v = &s->hw_volume; + else + v = &s->sw_volume; + + if (pa_cvolume_equal(v, volume)) + return; + + *v = *volume; + + if (v == &s->hw_volume) + if (s->set_hw_volume(s) < 0) + s->sw_volume = *volume; + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); +} + +const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_mixer_t m) { + assert(s); + assert(s->ref >= 1); + + if (m == PA_MIXER_HARDWARE && s->set_hw_volume) { + + if (s->get_hw_volume) + s->get_hw_volume(s); + + return &s->hw_volume; + } else + return &s->sw_volume; +} + +void pa_sink_set_mute(pa_sink *s, pa_mixer_t m, int mute) { + int *t; + + assert(s); + assert(s->ref >= 1); + + if (m == PA_MIXER_HARDWARE && s->set_hw_mute) + t = &s->hw_muted; + else + t = &s->sw_muted; + + if (!!*t == !!mute) + return; + + *t = !!mute; + + if (t == &s->hw_muted) + if (s->set_hw_mute(s) < 0) + s->sw_muted = !!mute; + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); +} + +int pa_sink_get_mute(pa_sink *s, pa_mixer_t m) { + assert(s); + assert(s->ref >= 1); + + if (m == PA_MIXER_HARDWARE && s->set_hw_mute) { + + if (s->get_hw_mute) + s->get_hw_mute(s); + + return s->hw_muted; + } else + return s->sw_muted; +} diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h new file mode 100644 index 00000000..fdff0522 --- /dev/null +++ b/src/pulsecore/sink.h @@ -0,0 +1,101 @@ +#ifndef foosinkhfoo +#define foosinkhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef struct pa_sink pa_sink; + +#include +#include +#include +#include +#include +#include +#include +#include + +#define PA_MAX_INPUTS_PER_SINK 32 + +typedef enum pa_sink_state { + PA_SINK_RUNNING, + PA_SINK_DISCONNECTED +} pa_sink_state_t; + +struct pa_sink { + int ref; + uint32_t index; + pa_core *core; + pa_sink_state_t state; + + char *name, *description, *driver; + pa_module *owner; + + pa_sample_spec sample_spec; + pa_channel_map channel_map; + + pa_idxset *inputs; + pa_source *monitor_source; + + pa_cvolume hw_volume, sw_volume; + int hw_muted, sw_muted; + + void (*notify)(pa_sink*sink); + pa_usec_t (*get_latency)(pa_sink *s); + int (*set_hw_volume)(pa_sink *s); + int (*get_hw_volume)(pa_sink *s); + int (*set_hw_mute)(pa_sink *s); + int (*get_hw_mute)(pa_sink *s); + + void *userdata; +}; + +pa_sink* pa_sink_new( + pa_core *core, + const char *driver, + const char *name, + int namereg_fail, + const pa_sample_spec *spec, + const pa_channel_map *map); + +void pa_sink_disconnect(pa_sink* s); +void pa_sink_unref(pa_sink*s); +pa_sink* pa_sink_ref(pa_sink *s); + +int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result); +void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result); +int pa_sink_render_into(pa_sink*s, pa_memchunk *target); +void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target); + +pa_usec_t pa_sink_get_latency(pa_sink *s); + +void pa_sink_notify(pa_sink*s); + +void pa_sink_set_owner(pa_sink *sink, pa_module *m); + +void pa_sink_set_volume(pa_sink *sink, pa_mixer_t m, const pa_cvolume *volume); +const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_mixer_t m); +void pa_sink_set_mute(pa_sink *sink, pa_mixer_t m, int mute); +int pa_sink_get_mute(pa_sink *sink, pa_mixer_t m); + +#endif diff --git a/src/pulsecore/sioman.c b/src/pulsecore/sioman.c new file mode 100644 index 00000000..d84010ee --- /dev/null +++ b/src/pulsecore/sioman.c @@ -0,0 +1,43 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#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/pulsecore/sioman.h b/src/pulsecore/sioman.h new file mode 100644 index 00000000..cd04d140 --- /dev/null +++ b/src/pulsecore/sioman.h @@ -0,0 +1,28 @@ +#ifndef foosiomanhfoo +#define foosiomanhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +int pa_stdio_acquire(void); +void pa_stdio_release(void); + +#endif diff --git a/src/pulsecore/socket-client.c b/src/pulsecore/socket-client.c new file mode 100644 index 00000000..8e547614 --- /dev/null +++ b/src/pulsecore/socket-client.c @@ -0,0 +1,526 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/* #undef HAVE_LIBASYNCNS */ + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_LIBASYNCNS +#include +#endif + +#include "winsock.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include "socket-client.h" + +#define CONNECT_TIMEOUT 5 + +struct pa_socket_client { + int ref; + pa_mainloop_api *mainloop; + int fd; + pa_io_event *io_event; + pa_time_event *timeout_event; + pa_defer_event *defer_event; + void (*callback)(pa_socket_client*c, pa_iochannel *io, void *userdata); + void *userdata; + int local; +#ifdef HAVE_LIBASYNCNS + asyncns_t *asyncns; + asyncns_query_t * asyncns_query; + pa_io_event *asyncns_io_event; +#endif +}; + +static pa_socket_client*pa_socket_client_new(pa_mainloop_api *m) { + pa_socket_client *c; + assert(m); + + c = pa_xmalloc(sizeof(pa_socket_client)); + c->ref = 1; + c->mainloop = m; + c->fd = -1; + c->io_event = NULL; + c->defer_event = NULL; + c->timeout_event = NULL; + c->callback = NULL; + c->userdata = NULL; + c->local = 0; + +#ifdef HAVE_LIBASYNCNS + c->asyncns = NULL; + c->asyncns_io_event = NULL; + c->asyncns_query = NULL; +#endif + + return c; +} + +static void free_events(pa_socket_client *c) { + assert(c); + + if (c->io_event) { + c->mainloop->io_free(c->io_event); + c->io_event = NULL; + } + + if (c->defer_event) { + c->mainloop->defer_free(c->defer_event); + c->defer_event = NULL; + } + + if (c->timeout_event) { + c->mainloop->time_free(c->timeout_event); + c->timeout_event = NULL; + } +} + +static void do_call(pa_socket_client *c) { + pa_iochannel *io = NULL; + int error; + socklen_t lerror; + assert(c && c->callback); + + pa_socket_client_ref(c); + + if (c->fd < 0) + goto finish; + + lerror = sizeof(error); + if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &lerror) < 0) { + pa_log(__FILE__": getsockopt(): %s", pa_cstrerror(errno)); + goto finish; + } + + if (lerror != sizeof(error)) { + pa_log(__FILE__": getsockopt() returned invalid size."); + goto finish; + } + + if (error != 0) { + pa_log_debug(__FILE__": connect(): %s", pa_cstrerror(errno)); + errno = error; + goto finish; + } + + io = pa_iochannel_new(c->mainloop, c->fd, c->fd); + assert(io); + +finish: + if (!io && c->fd >= 0) + close(c->fd); + c->fd = -1; + + free_events(c); + + assert(c->callback); + c->callback(c, io, c->userdata); + + pa_socket_client_unref(c); +} + +static void connect_fixed_cb(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { + pa_socket_client *c = userdata; + assert(m && c && c->defer_event == e); + do_call(c); +} + +static void connect_io_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { + pa_socket_client *c = userdata; + assert(m && c && c->io_event == e && fd >= 0); + do_call(c); +} + +static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t len) { + int r; + assert(c && sa && len); + + pa_make_nonblock_fd(c->fd); + + if ((r = connect(c->fd, sa, len)) < 0) { +#ifdef OS_IS_WIN32 + if (WSAGetLastError() != EWOULDBLOCK) { + pa_log_debug(__FILE__": connect(): %d", WSAGetLastError()); +#else + if (errno != EINPROGRESS) { + pa_log_debug(__FILE__": connect(): %s (%d)", pa_cstrerror(errno), errno); +#endif + return -1; + } + + c->io_event = c->mainloop->io_new(c->mainloop, c->fd, PA_IO_EVENT_OUTPUT, connect_io_cb, c); + assert(c->io_event); + } else { + c->defer_event = c->mainloop->defer_new(c->mainloop, connect_fixed_cb, c); + assert(c->defer_event); + } + + return 0; +} + +pa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port) { + struct sockaddr_in sa; + assert(m && port > 0); + + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(port); + sa.sin_addr.s_addr = htonl(address); + + return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); +} + +#ifdef HAVE_SYS_UN_H + +pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) { + struct sockaddr_un sa; + assert(m && filename); + + memset(&sa, 0, sizeof(sa)); + sa.sun_family = AF_UNIX; + strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); + sa.sun_path[sizeof(sa.sun_path) - 1] = 0; + + return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); +} + +#else /* HAVE_SYS_UN_H */ + +pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) { + return NULL; +} + +#endif /* HAVE_SYS_UN_H */ + +static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size_t salen) { + assert(c); + assert(sa); + assert(salen); + + switch (sa->sa_family) { + case AF_UNIX: + c->local = 1; + break; + + case AF_INET: + c->local = ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK; + break; + + case AF_INET6: + c->local = memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0; + break; + + default: + c->local = 0; + } + + if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) { + pa_log(__FILE__": socket(): %s", pa_cstrerror(errno)); + return -1; + } + + pa_fd_set_cloexec(c->fd, 1); + if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) + pa_socket_tcp_low_delay(c->fd); + else + pa_socket_low_delay(c->fd); + + if (do_connect(c, sa, salen) < 0) + return -1; + + return 0; +} + +pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) { + pa_socket_client *c; + assert(m && sa); + c = pa_socket_client_new(m); + assert(c); + + if (sockaddr_prepare(c, sa, salen) < 0) + goto fail; + + return c; + +fail: + pa_socket_client_unref(c); + return NULL; + +} + +static void socket_client_free(pa_socket_client *c) { + assert(c && c->mainloop); + + + free_events(c); + + if (c->fd >= 0) + close(c->fd); + +#ifdef HAVE_LIBASYNCNS + if (c->asyncns_query) + asyncns_cancel(c->asyncns, c->asyncns_query); + if (c->asyncns) + asyncns_free(c->asyncns); + if (c->asyncns_io_event) + c->mainloop->io_free(c->asyncns_io_event); +#endif + + pa_xfree(c); +} + +void pa_socket_client_unref(pa_socket_client *c) { + assert(c && c->ref >= 1); + + if (!(--(c->ref))) + socket_client_free(c); +} + +pa_socket_client* pa_socket_client_ref(pa_socket_client *c) { + assert(c && c->ref >= 1); + c->ref++; + return c; +} + +void pa_socket_client_set_callback(pa_socket_client *c, void (*on_connection)(pa_socket_client *c, pa_iochannel*io, void *userdata), void *userdata) { + assert(c); + c->callback = on_connection; + c->userdata = userdata; +} + +pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[16], uint16_t port) { + struct sockaddr_in6 sa; + + memset(&sa, 0, sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons(port); + memcpy(&sa.sin6_addr, address, sizeof(sa.sin6_addr)); + + return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); +} + +#ifdef HAVE_LIBASYNCNS + +static void asyncns_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { + pa_socket_client *c = userdata; + struct addrinfo *res = NULL; + int ret; + assert(m && c && c->asyncns_io_event == e && fd >= 0); + + if (asyncns_wait(c->asyncns, 0) < 0) + goto fail; + + if (!asyncns_isdone(c->asyncns, c->asyncns_query)) + return; + + ret = asyncns_getaddrinfo_done(c->asyncns, c->asyncns_query, &res); + c->asyncns_query = NULL; + + if (ret != 0 || !res) + goto fail; + + if (res->ai_addr) + sockaddr_prepare(c, res->ai_addr, res->ai_addrlen); + + asyncns_freeaddrinfo(res); + + m->io_free(c->asyncns_io_event); + c->asyncns_io_event = NULL; + return; + +fail: + m->io_free(c->asyncns_io_event); + c->asyncns_io_event = NULL; + + errno = EHOSTUNREACH; + do_call(c); + return; + +} + +#endif + +static void timeout_cb(pa_mainloop_api *m, pa_time_event *e, const struct timeval *tv, void *userdata) { + pa_socket_client *c = userdata; + assert(m); + assert(e); + assert(tv); + assert(c); + + if (c->fd >= 0) { + close(c->fd); + c->fd = -1; + } + + errno = ETIMEDOUT; + do_call(c); +} + +static void start_timeout(pa_socket_client *c) { + struct timeval tv; + assert(c); + assert(!c->timeout_event); + + pa_gettimeofday(&tv); + pa_timeval_add(&tv, CONNECT_TIMEOUT * 1000000); + c->timeout_event = c->mainloop->time_new(c->mainloop, &tv, timeout_cb, c); +} + +pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*name, uint16_t default_port) { + pa_socket_client *c = NULL; + pa_parsed_address a; + assert(m && name); + + if (pa_parse_address(name, &a) < 0) + return NULL; + + if (!a.port) + a.port = default_port; + + switch (a.type) { + case PA_PARSED_ADDRESS_UNIX: + if ((c = pa_socket_client_new_unix(m, a.path_or_host))) + start_timeout(c); + break; + + case PA_PARSED_ADDRESS_TCP4: /* Fallthrough */ + case PA_PARSED_ADDRESS_TCP6: /* Fallthrough */ + case PA_PARSED_ADDRESS_TCP_AUTO:{ + + struct addrinfo hints; + char port[12]; + + snprintf(port, sizeof(port), "%u", (unsigned) a.port); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = a.type == PA_PARSED_ADDRESS_TCP4 ? PF_INET : (a.type == PA_PARSED_ADDRESS_TCP6 ? PF_INET6 : PF_UNSPEC); + hints.ai_socktype = SOCK_STREAM; + +#ifdef HAVE_LIBASYNCNS + { + asyncns_t *asyncns; + + if (!(asyncns = asyncns_new(1))) + goto finish; + + c = pa_socket_client_new(m); + c->asyncns = asyncns; + c->asyncns_io_event = m->io_new(m, asyncns_fd(c->asyncns), PA_IO_EVENT_INPUT, asyncns_cb, c); + c->asyncns_query = asyncns_getaddrinfo(c->asyncns, a.path_or_host, port, &hints); + assert(c->asyncns_query); + start_timeout(c); + } +#else /* HAVE_LIBASYNCNS */ + { +#ifdef HAVE_GETADDRINFO + int ret; + struct addrinfo *res = NULL; + + ret = getaddrinfo(a.path_or_host, port, &hints, &res); + + if (ret < 0 || !res) + goto finish; + + if (res->ai_addr) { + if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen))) + start_timeout(c); + } + + freeaddrinfo(res); +#else /* HAVE_GETADDRINFO */ + struct hostent *host = NULL; + struct sockaddr_in s; + + /* FIXME: PF_INET6 support */ + if (hints.ai_family == PF_INET6) { + pa_log_error(__FILE__": IPv6 is not supported on Windows"); + goto finish; + } + + host = gethostbyname(a.path_or_host); + if (!host) { + unsigned int addr = inet_addr(a.path_or_host); + if (addr != INADDR_NONE) + host = gethostbyaddr((char*)&addr, 4, AF_INET); + } + + if (!host) + goto finish; + + s.sin_family = AF_INET; + memcpy(&s.sin_addr, host->h_addr, sizeof(struct in_addr)); + s.sin_port = htons(a.port); + + if ((c = pa_socket_client_new_sockaddr(m, (struct sockaddr*)&s, sizeof(s)))) + start_timeout(c); +#endif /* HAVE_GETADDRINFO */ + } +#endif /* HAVE_LIBASYNCNS */ + } + } + +finish: + pa_xfree(a.path_or_host); + return c; + +} + +/* Return non-zero when the target sockaddr is considered + local. "local" means UNIX socket or TCP socket on localhost. Other + local IP addresses are not considered local. */ +int pa_socket_client_is_local(pa_socket_client *c) { + assert(c); + return c->local; +} diff --git a/src/pulsecore/socket-client.h b/src/pulsecore/socket-client.h new file mode 100644 index 00000000..47e7cd5a --- /dev/null +++ b/src/pulsecore/socket-client.h @@ -0,0 +1,47 @@ +#ifndef foosocketclienthfoo +#define foosocketclienthfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include + +struct sockaddr; + +typedef struct pa_socket_client pa_socket_client; + +pa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port); +pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[16], uint16_t port); +pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename); +pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen); +pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char *a, uint16_t default_port); + +void pa_socket_client_unref(pa_socket_client *c); +pa_socket_client* pa_socket_client_ref(pa_socket_client *c); + +void pa_socket_client_set_callback(pa_socket_client *c, void (*on_connection)(pa_socket_client *c, pa_iochannel*io, void *userdata), void *userdata); + +int pa_socket_client_is_local(pa_socket_client *c); + +#endif diff --git a/src/pulsecore/socket-server.c b/src/pulsecore/socket-server.c new file mode 100644 index 00000000..77ea13e7 --- /dev/null +++ b/src/pulsecore/socket-server.c @@ -0,0 +1,505 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#ifndef SUN_LEN +#define SUN_LEN(ptr) \ + ((size_t)(((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path)) +#endif +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_LIBWRAP +#include +#endif + +#ifndef HAVE_INET_NTOP +#include "inet_ntop.h" +#endif + +#ifndef HAVE_INET_PTON +#include "inet_pton.h" +#endif + +#include "winsock.h" + +#include +#include + +#include +#include +#include +#include + +#include "socket-server.h" + +struct pa_socket_server { + int ref; + int fd; + char *filename; + char *tcpwrap_service; + + void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata); + void *userdata; + + pa_io_event *io_event; + pa_mainloop_api *mainloop; + enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX, SOCKET_SERVER_IPV6 } type; +}; + +static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { + pa_socket_server *s = userdata; + pa_iochannel *io; + int nfd; + assert(s && s->mainloop == mainloop && s->io_event == e && e && fd >= 0 && fd == s->fd); + + pa_socket_server_ref(s); + + if ((nfd = accept(fd, NULL, NULL)) < 0) { + pa_log(__FILE__": accept(): %s", pa_cstrerror(errno)); + goto finish; + } + + pa_fd_set_cloexec(nfd, 1); + + if (!s->on_connection) { + close(nfd); + goto finish; + } + +#ifdef HAVE_LIBWRAP + + if (s->tcpwrap_service) { + struct request_info req; + + request_init(&req, RQ_DAEMON, s->tcpwrap_service, RQ_FILE, nfd, NULL); + fromhost(&req); + if (!hosts_access(&req)) { + pa_log_warn(__FILE__": TCP connection refused by tcpwrap."); + close(nfd); + goto finish; + } + + pa_log_info(__FILE__": TCP connection accepted by tcpwrap."); + } +#endif + + /* There should be a check for socket type here */ + if (s->type == SOCKET_SERVER_IPV4) + pa_socket_tcp_low_delay(fd); + else + pa_socket_low_delay(fd); + + io = pa_iochannel_new(s->mainloop, nfd, nfd); + assert(io); + s->on_connection(s, io, s->userdata); + +finish: + pa_socket_server_unref(s); +} + +pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) { + pa_socket_server *s; + assert(m && fd >= 0); + + s = pa_xmalloc(sizeof(pa_socket_server)); + s->ref = 1; + s->fd = fd; + s->filename = NULL; + s->on_connection = NULL; + s->userdata = NULL; + s->tcpwrap_service = NULL; + + s->mainloop = m; + s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s); + assert(s->io_event); + + s->type = SOCKET_SERVER_GENERIC; + + return s; +} + +pa_socket_server* pa_socket_server_ref(pa_socket_server *s) { + assert(s && s->ref >= 1); + s->ref++; + return s; +} + +#ifdef HAVE_SYS_UN_H + +pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) { + int fd = -1; + struct sockaddr_un sa; + pa_socket_server *s; + + assert(m && filename); + + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + pa_log(__FILE__": socket(): %s", pa_cstrerror(errno)); + goto fail; + } + + pa_fd_set_cloexec(fd, 1); + + sa.sun_family = AF_UNIX; + strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); + sa.sun_path[sizeof(sa.sun_path) - 1] = 0; + + pa_socket_low_delay(fd); + + if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) { + pa_log(__FILE__": bind(): %s", pa_cstrerror(errno)); + goto fail; + } + + if (listen(fd, 5) < 0) { + pa_log(__FILE__": listen(): %s", pa_cstrerror(errno)); + goto fail; + } + + s = pa_socket_server_new(m, fd); + assert(s); + + s->filename = pa_xstrdup(filename); + s->type = SOCKET_SERVER_UNIX; + + return s; + +fail: + if (fd >= 0) + close(fd); + + return NULL; +} + +#else /* HAVE_SYS_UN_H */ + +pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) { + return NULL; +} + +#endif /* HAVE_SYS_UN_H */ + +pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service) { + pa_socket_server *ss; + int fd = -1; + struct sockaddr_in sa; + int on = 1; + + assert(m && port); + + if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { + pa_log(__FILE__": socket(PF_INET): %s", pa_cstrerror(errno)); + goto fail; + } + + pa_fd_set_cloexec(fd, 1); + +#ifdef SO_REUSEADDR + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) + pa_log(__FILE__": setsockopt(): %s", pa_cstrerror(errno)); +#endif + + pa_socket_tcp_low_delay(fd); + + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(port); + sa.sin_addr.s_addr = htonl(address); + + if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { + pa_log(__FILE__": bind(): %s", pa_cstrerror(errno)); + goto fail; + } + + if (listen(fd, 5) < 0) { + pa_log(__FILE__": listen(): %s", pa_cstrerror(errno)); + goto fail; + } + + if ((ss = pa_socket_server_new(m, fd))) { + ss->type = SOCKET_SERVER_IPV4; + ss->tcpwrap_service = pa_xstrdup(tcpwrap_service); + } + + return ss; + +fail: + if (fd >= 0) + close(fd); + + return NULL; +} + +pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port, const char *tcpwrap_service) { + pa_socket_server *ss; + int fd = -1; + struct sockaddr_in6 sa; + int on = 1; + + assert(m && port); + + if ((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) { + pa_log(__FILE__": socket(PF_INET6): %s", pa_cstrerror(errno)); + goto fail; + } + + pa_fd_set_cloexec(fd, 1); + +#ifdef IPV6_V6ONLY + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) + pa_log(__FILE__": setsockopt(IPPROTO_IPV6, IPV6_V6ONLY): %s", pa_cstrerror(errno)); +#endif + +#ifdef SO_REUSEADDR + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) + pa_log(__FILE__": setsockopt(SOL_SOCKET, SO_REUSEADDR, 1): %s", pa_cstrerror(errno)); +#endif + + pa_socket_tcp_low_delay(fd); + + memset(&sa, 0, sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons(port); + memcpy(sa.sin6_addr.s6_addr, address, 16); + + if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { + pa_log(__FILE__": bind(): %s", pa_cstrerror(errno)); + goto fail; + } + + if (listen(fd, 5) < 0) { + pa_log(__FILE__": listen(): %s", pa_cstrerror(errno)); + goto fail; + } + + if ((ss = pa_socket_server_new(m, fd))) { + ss->type = SOCKET_SERVER_IPV6; + ss->tcpwrap_service = pa_xstrdup(tcpwrap_service); + } + + return ss; + +fail: + if (fd >= 0) + close(fd); + + return NULL; +} + +pa_socket_server* pa_socket_server_new_ipv4_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { + assert(m); + assert(port > 0); + + return pa_socket_server_new_ipv4(m, INADDR_LOOPBACK, port, tcpwrap_service); +} + +pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { + assert(m); + assert(port > 0); + + return pa_socket_server_new_ipv6(m, in6addr_loopback.s6_addr, port, tcpwrap_service); +} + +pa_socket_server* pa_socket_server_new_ipv4_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { + assert(m); + assert(port > 0); + + return pa_socket_server_new_ipv4(m, INADDR_ANY, port, tcpwrap_service); +} + +pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { + assert(m); + assert(port > 0); + + return pa_socket_server_new_ipv6(m, in6addr_any.s6_addr, port, tcpwrap_service); +} + +pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) { + struct in_addr ipv4; + + assert(m); + assert(name); + assert(port > 0); + + if (inet_pton(AF_INET, name, &ipv4) > 0) + return pa_socket_server_new_ipv4(m, ntohl(ipv4.s_addr), port, tcpwrap_service); + + return NULL; +} + +pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) { + struct in6_addr ipv6; + + assert(m); + assert(name); + assert(port > 0); + + if (inet_pton(AF_INET6, name, &ipv6) > 0) + return pa_socket_server_new_ipv6(m, ipv6.s6_addr, port, tcpwrap_service); + + return NULL; +} + +static void socket_server_free(pa_socket_server*s) { + assert(s); + + if (s->filename) { + unlink(s->filename); + pa_xfree(s->filename); + } + + close(s->fd); + + pa_xfree(s->tcpwrap_service); + + s->mainloop->io_free(s->io_event); + pa_xfree(s); +} + +void pa_socket_server_unref(pa_socket_server *s) { + assert(s && s->ref >= 1); + + if (!(--(s->ref))) + socket_server_free(s); +} + +void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata), void *userdata) { + assert(s && s->ref >= 1); + + s->on_connection = on_connection; + s->userdata = userdata; +} + +char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { + assert(s && c && l > 0); + + switch (s->type) { + case SOCKET_SERVER_IPV6: { + struct sockaddr_in6 sa; + socklen_t sa_len = sizeof(sa); + + if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) { + pa_log(__FILE__": getsockname(): %s", pa_cstrerror(errno)); + return NULL; + } + + if (memcmp(&in6addr_any, &sa.sin6_addr, sizeof(in6addr_any)) == 0) { + char fqdn[256]; + if (!pa_get_fqdn(fqdn, sizeof(fqdn))) + return NULL; + + snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port)); + + } else if (memcmp(&in6addr_loopback, &sa.sin6_addr, sizeof(in6addr_loopback)) == 0) { + char hn[256]; + if (!pa_get_host_name(hn, sizeof(hn))) + return NULL; + + snprintf(c, l, "{%s}tcp6:localhost:%u", hn, (unsigned) ntohs(sa.sin6_port)); + } else { + char ip[INET6_ADDRSTRLEN]; + + if (!inet_ntop(AF_INET6, &sa.sin6_addr, ip, sizeof(ip))) { + pa_log(__FILE__": inet_ntop(): %s", pa_cstrerror(errno)); + return NULL; + } + + snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port)); + } + + return c; + } + + case SOCKET_SERVER_IPV4: { + struct sockaddr_in sa; + socklen_t sa_len = sizeof(sa); + + if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) { + pa_log(__FILE__": getsockname(): %s", pa_cstrerror(errno)); + return NULL; + } + + if (sa.sin_addr.s_addr == INADDR_ANY) { + char fqdn[256]; + if (!pa_get_fqdn(fqdn, sizeof(fqdn))) + return NULL; + + snprintf(c, l, "tcp:%s:%u", fqdn, (unsigned) ntohs(sa.sin_port)); + } else if (sa.sin_addr.s_addr == INADDR_LOOPBACK) { + char hn[256]; + if (!pa_get_host_name(hn, sizeof(hn))) + return NULL; + + snprintf(c, l, "{%s}tcp:localhost:%u", hn, (unsigned) ntohs(sa.sin_port)); + } else { + char ip[INET_ADDRSTRLEN]; + + if (!inet_ntop(AF_INET, &sa.sin_addr, ip, sizeof(ip))) { + pa_log(__FILE__": inet_ntop(): %s", pa_cstrerror(errno)); + return NULL; + } + + snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port)); + + } + + return c; + } + + case SOCKET_SERVER_UNIX: { + char hn[256]; + + if (!s->filename) + return NULL; + + if (!pa_get_host_name(hn, sizeof(hn))) + return NULL; + + snprintf(c, l, "{%s}unix:%s", hn, s->filename); + return c; + } + + default: + return NULL; + } +} diff --git a/src/pulsecore/socket-server.h b/src/pulsecore/socket-server.h new file mode 100644 index 00000000..d90c8194 --- /dev/null +++ b/src/pulsecore/socket-server.h @@ -0,0 +1,51 @@ +#ifndef foosocketserverhfoo +#define foosocketserverhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include + +/* It is safe to destroy the calling socket_server object from the callback */ + +typedef struct pa_socket_server pa_socket_server; + +pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd); +pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename); +pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv4_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv4_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service); +pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service); + +void pa_socket_server_unref(pa_socket_server*s); +pa_socket_server* pa_socket_server_ref(pa_socket_server *s); + +void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata), void *userdata); + +char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l); + +#endif diff --git a/src/pulsecore/socket-util.c b/src/pulsecore/socket-util.c new file mode 100644 index 00000000..8705560d --- /dev/null +++ b/src/pulsecore/socket-util.c @@ -0,0 +1,266 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_IN_SYSTM_H +#include +#endif +#ifdef HAVE_NETINET_IP_H +#include +#endif +#ifdef HAVE_NETINET_TCP_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#ifndef HAVE_INET_NTOP +#include "inet_ntop.h" +#endif + +#include "winsock.h" + +#include + +#include +#include +#include + +#include "socket-util.h" + +void pa_socket_peer_to_string(int fd, char *c, size_t l) { + struct stat st; + + assert(c && l && fd >= 0); + +#ifndef OS_IS_WIN32 + if (fstat(fd, &st) < 0) { + snprintf(c, l, "Invalid client fd"); + return; + } +#endif + +#ifndef OS_IS_WIN32 + if (S_ISSOCK(st.st_mode)) { +#endif + union { + struct sockaddr sa; + struct sockaddr_in in; + struct sockaddr_in6 in6; +#ifdef HAVE_SYS_UN_H + struct sockaddr_un un; +#endif + } sa; + socklen_t sa_len = sizeof(sa); + + if (getpeername(fd, &sa.sa, &sa_len) >= 0) { + + if (sa.sa.sa_family == AF_INET) { + uint32_t ip = ntohl(sa.in.sin_addr.s_addr); + + snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u", + ip >> 24, + (ip >> 16) & 0xFF, + (ip >> 8) & 0xFF, + ip & 0xFF, + ntohs(sa.in.sin_port)); + return; + } else if (sa.sa.sa_family == AF_INET6) { + char buf[INET6_ADDRSTRLEN]; + const char *res; + + res = inet_ntop(AF_INET6, &sa.in6.sin6_addr, buf, sizeof(buf)); + if (res) { + snprintf(c, l, "TCP/IP client from [%s]:%u", buf, ntohs(sa.in6.sin6_port)); + return; + } +#ifdef HAVE_SYS_UN_H + } else if (sa.sa.sa_family == AF_UNIX) { + snprintf(c, l, "UNIX socket client"); + return; +#endif + } + + } +#ifndef OS_IS_WIN32 + snprintf(c, l, "Unknown network client"); + return; + } else if (S_ISCHR(st.st_mode) && (fd == 0 || fd == 1)) { + snprintf(c, l, "STDIN/STDOUT client"); + return; + } +#endif /* OS_IS_WIN32 */ + + snprintf(c, l, "Unknown client"); +} + +int pa_socket_low_delay(int fd) { +#ifdef SO_PRIORITY + int priority; + assert(fd >= 0); + + priority = 7; + if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (void*)&priority, sizeof(priority)) < 0) + return -1; +#endif + + return 0; +} + +int pa_socket_tcp_low_delay(int fd) { + int ret, tos, on; + + assert(fd >= 0); + + ret = pa_socket_low_delay(fd); + + on = 1; + tos = 0; + +#if defined(SOL_TCP) || defined(IPPROTO_TCP) +#if defined(SOL_TCP) + if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0) +#else + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0) +#endif + ret = -1; +#endif + +#if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || \ + defined(IPPROTO_IP)) + tos = IPTOS_LOWDELAY; +#ifdef SOL_IP + if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) +#else + if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) +#endif + ret = -1; +#endif + + return ret; + +} + +int pa_socket_set_rcvbuf(int fd, size_t l) { + assert(fd >= 0); + +/* if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&l, sizeof(l)) < 0) { */ +/* pa_log(__FILE__": SO_RCVBUF: %s", strerror(errno)); */ +/* return -1; */ +/* } */ + + return 0; +} + +int pa_socket_set_sndbuf(int fd, size_t l) { + assert(fd >= 0); + +/* if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&l, sizeof(l)) < 0) { */ +/* pa_log(__FILE__": SO_SNDBUF: %s", strerror(errno)); */ +/* return -1; */ +/* } */ + + return 0; +} + +#ifdef HAVE_SYS_UN_H + +int pa_unix_socket_is_stale(const char *fn) { + struct sockaddr_un sa; + int fd = -1, ret = -1; + + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + pa_log(__FILE__": socket(): %s", pa_cstrerror(errno)); + goto finish; + } + + sa.sun_family = AF_UNIX; + strncpy(sa.sun_path, fn, sizeof(sa.sun_path)-1); + sa.sun_path[sizeof(sa.sun_path) - 1] = 0; + + if (connect(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) { + if (errno == ECONNREFUSED) + ret = 1; + } else + ret = 0; + +finish: + if (fd >= 0) + close(fd); + + return ret; +} + +int pa_unix_socket_remove_stale(const char *fn) { + int r; + + if ((r = pa_unix_socket_is_stale(fn)) < 0) + return errno != ENOENT ? -1 : 0; + + if (!r) + return 0; + + /* Yes, here is a race condition. But who cares? */ + if (unlink(fn) < 0) + return -1; + + return 0; +} + +#else /* HAVE_SYS_UN_H */ + +int pa_unix_socket_is_stale(const char *fn) { + return -1; +} + +int pa_unix_socket_remove_stale(const char *fn) { + return -1; +} + +#endif /* HAVE_SYS_UN_H */ diff --git a/src/pulsecore/socket-util.h b/src/pulsecore/socket-util.h new file mode 100644 index 00000000..f8248ae7 --- /dev/null +++ b/src/pulsecore/socket-util.h @@ -0,0 +1,38 @@ +#ifndef foosocketutilhfoo +#define foosocketutilhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +void pa_socket_peer_to_string(int fd, char *c, size_t l); + +int pa_socket_low_delay(int fd); +int pa_socket_tcp_low_delay(int fd); + +int pa_socket_set_sndbuf(int fd, size_t l); +int pa_socket_set_rcvbuf(int fd, size_t l); + +int pa_unix_socket_is_stale(const char *fn); +int pa_unix_socket_remove_stale(const char *fn); + +#endif diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c new file mode 100644 index 00000000..386f5bd0 --- /dev/null +++ b/src/pulsecore/sound-file-stream.c @@ -0,0 +1,192 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include "sound-file-stream.h" + +#define BUF_SIZE (1024*10) + +struct userdata { + SNDFILE *sndfile; + pa_sink_input *sink_input; + pa_memchunk memchunk; + sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames); +}; + +static void free_userdata(struct userdata *u) { + assert(u); + if (u->sink_input) { + pa_sink_input_disconnect(u->sink_input); + pa_sink_input_unref(u->sink_input); + } + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + if (u->sndfile) + sf_close(u->sndfile); + + pa_xfree(u); +} + +static void sink_input_kill(pa_sink_input *i) { + assert(i && i->userdata); + free_userdata(i->userdata); +} + +static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { + struct userdata *u; + assert(i && chunk && i->userdata); + u = i->userdata; + + if (!u->memchunk.memblock) { + uint32_t fs = pa_frame_size(&i->sample_spec); + sf_count_t n; + + u->memchunk.memblock = pa_memblock_new(BUF_SIZE, i->sink->core->memblock_stat); + u->memchunk.index = 0; + + if (u->readf_function) { + if ((n = u->readf_function(u->sndfile, u->memchunk.memblock->data, BUF_SIZE/fs)) <= 0) + n = 0; + + u->memchunk.length = n * fs; + } else { + if ((n = sf_read_raw(u->sndfile, u->memchunk.memblock->data, BUF_SIZE)) <= 0) + n = 0; + + u->memchunk.length = n; + } + + if (!u->memchunk.length) { + free_userdata(u); + return -1; + } + } + + *chunk = u->memchunk; + pa_memblock_ref(chunk->memblock); + assert(chunk->length); + return 0; +} + +static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) { + struct userdata *u; + assert(i && chunk && length && i->userdata); + u = i->userdata; + + assert(!memcmp(chunk, &u->memchunk, sizeof(chunk))); + assert(length <= u->memchunk.length); + + u->memchunk.index += length; + u->memchunk.length -= length; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + u->memchunk.index = u->memchunk.length = 0; + } +} + +int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume) { + struct userdata *u = NULL; + SF_INFO sfinfo; + pa_sample_spec ss; + assert(sink && fname); + + u = pa_xmalloc(sizeof(struct userdata)); + u->sink_input = NULL; + u->memchunk.memblock = NULL; + u->memchunk.index = u->memchunk.length = 0; + u->sndfile = NULL; + + memset(&sfinfo, 0, sizeof(sfinfo)); + + if (!(u->sndfile = sf_open(fname, SFM_READ, &sfinfo))) { + pa_log(__FILE__": Failed to open file %s", fname); + goto fail; + } + + u->readf_function = NULL; + + switch (sfinfo.format & 0xFF) { + case SF_FORMAT_PCM_16: + case SF_FORMAT_PCM_U8: + case SF_FORMAT_PCM_S8: + ss.format = PA_SAMPLE_S16NE; + u->readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_short; + break; + + case SF_FORMAT_ULAW: + ss.format = PA_SAMPLE_ULAW; + break; + + case SF_FORMAT_ALAW: + ss.format = PA_SAMPLE_ALAW; + break; + + case SF_FORMAT_FLOAT: + default: + ss.format = PA_SAMPLE_FLOAT32NE; + u->readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_float; + break; + } + + ss.rate = sfinfo.samplerate; + ss.channels = sfinfo.channels; + + if (!pa_sample_spec_valid(&ss)) { + pa_log(__FILE__": Unsupported sample format in file %s", fname); + goto fail; + } + + if (!(u->sink_input = pa_sink_input_new(sink, __FILE__, fname, &ss, NULL, volume, 0, -1))) + goto fail; + + u->sink_input->peek = sink_input_peek; + u->sink_input->drop = sink_input_drop; + u->sink_input->kill = sink_input_kill; + u->sink_input->userdata = u; + + pa_sink_notify(sink); + + return 0; + +fail: + if (u) + free_userdata(u); + + return -1; +} diff --git a/src/pulsecore/sound-file-stream.h b/src/pulsecore/sound-file-stream.h new file mode 100644 index 00000000..28e6a8ba --- /dev/null +++ b/src/pulsecore/sound-file-stream.h @@ -0,0 +1,29 @@ +#ifndef foosoundfilestreamhfoo +#define foosoundfilestreamhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume); + +#endif diff --git a/src/pulsecore/sound-file.c b/src/pulsecore/sound-file.c new file mode 100644 index 00000000..d11d4b9d --- /dev/null +++ b/src/pulsecore/sound-file.c @@ -0,0 +1,163 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include +#include + +#include "sound-file.h" +#include "core-scache.h" + +int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_channel_map *map, pa_memchunk *chunk, pa_memblock_stat *s) { + SNDFILE*sf = NULL; + SF_INFO sfinfo; + int ret = -1; + size_t l; + sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames) = NULL; + assert(fname && ss && chunk); + + chunk->memblock = NULL; + chunk->index = chunk->length = 0; + + memset(&sfinfo, 0, sizeof(sfinfo)); + + if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) { + pa_log(__FILE__": Failed to open file %s", fname); + goto finish; + } + + switch (sfinfo.format & SF_FORMAT_SUBMASK) { + case SF_FORMAT_PCM_16: + case SF_FORMAT_PCM_U8: + case SF_FORMAT_PCM_S8: + ss->format = PA_SAMPLE_S16NE; + readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_short; + break; + + case SF_FORMAT_ULAW: + ss->format = PA_SAMPLE_ULAW; + break; + + case SF_FORMAT_ALAW: + ss->format = PA_SAMPLE_ALAW; + break; + + case SF_FORMAT_FLOAT: + case SF_FORMAT_DOUBLE: + default: + ss->format = PA_SAMPLE_FLOAT32NE; + readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_float; + break; + } + + ss->rate = sfinfo.samplerate; + ss->channels = sfinfo.channels; + + if (!pa_sample_spec_valid(ss)) { + pa_log(__FILE__": Unsupported sample format in file %s", fname); + goto finish; + } + + if (map) + pa_channel_map_init_auto(map, ss->channels, PA_CHANNEL_MAP_DEFAULT); + + if ((l = pa_frame_size(ss)*sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) { + pa_log(__FILE__": File too large"); + goto finish; + } + + chunk->memblock = pa_memblock_new(l, s); + assert(chunk->memblock); + chunk->index = 0; + chunk->length = l; + + if ((readf_function && readf_function(sf, chunk->memblock->data, sfinfo.frames) != sfinfo.frames) || + (!readf_function && sf_read_raw(sf, chunk->memblock->data, l) != l)) { + pa_log(__FILE__": Premature file end"); + goto finish; + } + + ret = 0; + +finish: + + if (sf) + sf_close(sf); + + if (ret != 0 && chunk->memblock) + pa_memblock_unref(chunk->memblock); + + return ret; + +} + +int pa_sound_file_too_big_to_cache(const char *fname) { + SNDFILE*sf = NULL; + SF_INFO sfinfo; + pa_sample_spec ss; + + if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) { + pa_log(__FILE__": Failed to open file %s", fname); + return 0; + } + + sf_close(sf); + + switch (sfinfo.format & SF_FORMAT_SUBMASK) { + case SF_FORMAT_PCM_16: + case SF_FORMAT_PCM_U8: + case SF_FORMAT_PCM_S8: + ss.format = PA_SAMPLE_S16NE; + break; + + case SF_FORMAT_ULAW: + ss.format = PA_SAMPLE_ULAW; + break; + + case SF_FORMAT_ALAW: + ss.format = PA_SAMPLE_ALAW; + break; + + case SF_FORMAT_DOUBLE: + case SF_FORMAT_FLOAT: + default: + ss.format = PA_SAMPLE_FLOAT32NE; + break; + } + + ss.rate = sfinfo.samplerate; + ss.channels = sfinfo.channels; + + if ((pa_frame_size(&ss) * sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) { + pa_log(__FILE__": File too large %s", fname); + return 1; + } + + return 0; +} diff --git a/src/pulsecore/sound-file.h b/src/pulsecore/sound-file.h new file mode 100644 index 00000000..0b81d97e --- /dev/null +++ b/src/pulsecore/sound-file.h @@ -0,0 +1,33 @@ +#ifndef soundfilehfoo +#define soundfilehfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include + +int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_channel_map *map, pa_memchunk *chunk, pa_memblock_stat *s); + +int pa_sound_file_too_big_to_cache(const char *fname); + +#endif diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c new file mode 100644 index 00000000..230b416d --- /dev/null +++ b/src/pulsecore/source-output.c @@ -0,0 +1,241 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "source-output.h" + +#define CHECK_VALIDITY_RETURN_NULL(condition) \ +do {\ +if (!(condition)) \ + return NULL; \ +} while (0) + +pa_source_output* pa_source_output_new( + pa_source *s, + const char *driver, + const char *name, + const pa_sample_spec *spec, + const pa_channel_map *map, + int resample_method) { + + pa_source_output *o; + pa_resampler *resampler = NULL; + int r; + char st[256]; + pa_channel_map tmap; + + assert(s); + assert(spec); + assert(s->state == PA_SOURCE_RUNNING); + + CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec)); + + if (!map) + map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT); + + CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map)); + CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels); + CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver)); + CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name)); + + if (pa_idxset_size(s->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { + pa_log(__FILE__": Failed to create source output: too many outputs per source."); + return NULL; + } + + if (resample_method == PA_RESAMPLER_INVALID) + resample_method = s->core->resample_method; + + if (!pa_sample_spec_equal(&s->sample_spec, spec) || !pa_channel_map_equal(&s->channel_map, map)) + if (!(resampler = pa_resampler_new(&s->sample_spec, &s->channel_map, spec, map, s->core->memblock_stat, resample_method))) + return NULL; + + o = pa_xnew(pa_source_output, 1); + o->ref = 1; + o->state = PA_SOURCE_OUTPUT_RUNNING; + o->name = pa_xstrdup(name); + o->driver = pa_xstrdup(driver); + o->owner = NULL; + o->source = s; + o->client = NULL; + + o->sample_spec = *spec; + o->channel_map = *map; + + o->push = NULL; + o->kill = NULL; + o->get_latency = NULL; + o->userdata = NULL; + + o->resampler = resampler; + + assert(s->core); + r = pa_idxset_put(s->core->source_outputs, o, &o->index); + assert(r == 0 && o->index != PA_IDXSET_INVALID); + r = pa_idxset_put(s->outputs, o, NULL); + assert(r == 0); + + pa_sample_spec_snprint(st, sizeof(st), spec); + pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"", o->index, o->name, s->index, st); + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); + + return o; +} + +void pa_source_output_disconnect(pa_source_output*o) { + assert(o); + assert(o->state != PA_SOURCE_OUTPUT_DISCONNECTED); + assert(o->source); + assert(o->source->core); + + pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); + pa_idxset_remove_by_data(o->source->outputs, o, NULL); + + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); + o->source = NULL; + + o->push = NULL; + o->kill = NULL; + o->get_latency = NULL; + + o->state = PA_SOURCE_OUTPUT_DISCONNECTED; +} + +static void source_output_free(pa_source_output* o) { + assert(o); + + if (o->state != PA_SOURCE_OUTPUT_DISCONNECTED) + pa_source_output_disconnect(o); + + pa_log_info(__FILE__": freed %u \"%s\"", o->index, o->name); + + if (o->resampler) + pa_resampler_free(o->resampler); + + pa_xfree(o->name); + pa_xfree(o->driver); + pa_xfree(o); +} + +void pa_source_output_unref(pa_source_output* o) { + assert(o); + assert(o->ref >= 1); + + if (!(--o->ref)) + source_output_free(o); +} + +pa_source_output* pa_source_output_ref(pa_source_output *o) { + assert(o); + assert(o->ref >= 1); + + o->ref++; + return o; +} + + +void pa_source_output_kill(pa_source_output*o) { + assert(o); + assert(o->ref >= 1); + + if (o->kill) + o->kill(o); +} + +void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { + pa_memchunk rchunk; + + assert(o); + assert(chunk); + assert(chunk->length); + assert(o->push); + + if (o->state == PA_SOURCE_OUTPUT_CORKED) + return; + + if (!o->resampler) { + o->push(o, chunk); + return; + } + + pa_resampler_run(o->resampler, chunk, &rchunk); + if (!rchunk.length) + return; + + assert(rchunk.memblock); + o->push(o, &rchunk); + pa_memblock_unref(rchunk.memblock); +} + +void pa_source_output_set_name(pa_source_output *o, const char *name) { + assert(o); + assert(o->ref >= 1); + + pa_xfree(o->name); + o->name = pa_xstrdup(name); + + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); +} + +pa_usec_t pa_source_output_get_latency(pa_source_output *o) { + assert(o); + assert(o->ref >= 1); + + if (o->get_latency) + return o->get_latency(o); + + return 0; +} + +void pa_source_output_cork(pa_source_output *o, int b) { + assert(o); + assert(o->ref >= 1); + + if (o->state == PA_SOURCE_OUTPUT_DISCONNECTED) + return; + + o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; +} + +pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { + assert(o); + assert(o->ref >= 1); + + if (!o->resampler) + return PA_RESAMPLER_INVALID; + + return pa_resampler_get_method(o->resampler); +} diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h new file mode 100644 index 00000000..ef398dd1 --- /dev/null +++ b/src/pulsecore/source-output.h @@ -0,0 +1,92 @@ +#ifndef foosourceoutputhfoo +#define foosourceoutputhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef struct pa_source_output pa_source_output; + +#include +#include +#include +#include +#include +#include + +typedef enum { + PA_SOURCE_OUTPUT_RUNNING, + PA_SOURCE_OUTPUT_CORKED, + PA_SOURCE_OUTPUT_DISCONNECTED +} pa_source_output_state_t; + +struct pa_source_output { + int ref; + uint32_t index; + pa_source_output_state_t state; + + char *name, *driver; + pa_module *owner; + + pa_source *source; + pa_client *client; + + pa_sample_spec sample_spec; + pa_channel_map channel_map; + + void (*push)(pa_source_output *o, const pa_memchunk *chunk); + void (*kill)(pa_source_output* o); + pa_usec_t (*get_latency) (pa_source_output *o); + + pa_resampler* resampler; + + void *userdata; +}; + +pa_source_output* pa_source_output_new( + pa_source *s, + const char *driver, + const char *name, + const pa_sample_spec *spec, + const pa_channel_map *map, + int resample_method); + +void pa_source_output_unref(pa_source_output* o); +pa_source_output* pa_source_output_ref(pa_source_output *o); + +/* To be called by the implementing module only */ +void pa_source_output_disconnect(pa_source_output*o); + +/* External code may request disconnection with this funcion */ +void pa_source_output_kill(pa_source_output*o); + +void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk); + +void pa_source_output_set_name(pa_source_output *i, const char *name); + +pa_usec_t pa_source_output_get_latency(pa_source_output *i); + +void pa_source_output_cork(pa_source_output *i, int b); + +pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o); + +#endif diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c new file mode 100644 index 00000000..84151a92 --- /dev/null +++ b/src/pulsecore/source.c @@ -0,0 +1,313 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "source.h" + +#define CHECK_VALIDITY_RETURN_NULL(condition) \ +do {\ +if (!(condition)) \ + return NULL; \ +} while (0) + +pa_source* pa_source_new( + pa_core *core, + const char *driver, + const char *name, + int fail, + const pa_sample_spec *spec, + const pa_channel_map *map) { + + pa_source *s; + char st[256]; + int r; + pa_channel_map tmap; + + assert(core); + assert(name); + assert(spec); + + CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec)); + + if (!map) + map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT); + + CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map)); + CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels); + CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver)); + CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name) && *name); + + s = pa_xnew(pa_source, 1); + + if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SOURCE, s, fail))) { + pa_xfree(s); + return NULL; + } + + s->ref = 1; + s->core = core; + s->state = PA_SOURCE_RUNNING; + s->name = pa_xstrdup(name); + s->description = NULL; + s->driver = pa_xstrdup(driver); + s->owner = NULL; + + s->sample_spec = *spec; + s->channel_map = *map; + + s->outputs = pa_idxset_new(NULL, NULL); + s->monitor_of = NULL; + + pa_cvolume_reset(&s->sw_volume, spec->channels); + pa_cvolume_reset(&s->hw_volume, spec->channels); + s->sw_muted = 0; + s->hw_muted = 0; + + s->get_latency = NULL; + s->notify = NULL; + s->set_hw_volume = NULL; + s->get_hw_volume = NULL; + s->set_hw_mute = NULL; + s->get_hw_mute = NULL; + s->userdata = NULL; + + r = pa_idxset_put(core->sources, s, &s->index); + assert(s->index != PA_IDXSET_INVALID && r >= 0); + + pa_sample_spec_snprint(st, sizeof(st), spec); + pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"", s->index, s->name, st); + + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index); + + return s; +} + +void pa_source_disconnect(pa_source *s) { + pa_source_output *o, *j = NULL; + + assert(s); + assert(s->state == PA_SOURCE_RUNNING); + + pa_namereg_unregister(s->core, s->name); + + while ((o = pa_idxset_first(s->outputs, NULL))) { + assert(o != j); + pa_source_output_kill(o); + j = o; + } + + pa_idxset_remove_by_data(s->core->sources, s, NULL); + + s->get_latency = NULL; + s->notify = NULL; + s->get_hw_volume = NULL; + s->set_hw_volume = NULL; + s->set_hw_mute = NULL; + s->get_hw_mute = NULL; + + s->state = PA_SOURCE_DISCONNECTED; + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); +} + +static void source_free(pa_source *s) { + assert(s); + assert(!s->ref); + + if (s->state != PA_SOURCE_DISCONNECTED) + pa_source_disconnect(s); + + pa_log_info(__FILE__": freed %u \"%s\"", s->index, s->name); + + pa_idxset_free(s->outputs, NULL, NULL); + + pa_xfree(s->name); + pa_xfree(s->description); + pa_xfree(s->driver); + pa_xfree(s); +} + +void pa_source_unref(pa_source *s) { + assert(s); + assert(s->ref >= 1); + + if (!(--s->ref)) + source_free(s); +} + +pa_source* pa_source_ref(pa_source *s) { + assert(s); + assert(s->ref >= 1); + + s->ref++; + return s; +} + +void pa_source_notify(pa_source*s) { + assert(s); + assert(s->ref >= 1); + + if (s->notify) + s->notify(s); +} + +static int do_post(void *p, PA_GCC_UNUSED uint32_t idx, PA_GCC_UNUSED int *del, void*userdata) { + pa_source_output *o = p; + const pa_memchunk *chunk = userdata; + + assert(o); + assert(chunk); + + pa_source_output_push(o, chunk); + return 0; +} + +void pa_source_post(pa_source*s, const pa_memchunk *chunk) { + assert(s); + assert(s->ref >= 1); + assert(chunk); + + pa_source_ref(s); + + if (s->sw_muted || !pa_cvolume_is_norm(&s->sw_volume)) { + pa_memchunk vchunk = *chunk; + + pa_memblock_ref(vchunk.memblock); + pa_memchunk_make_writable(&vchunk, s->core->memblock_stat, 0); + if (s->sw_muted) + pa_silence_memchunk(&vchunk, &s->sample_spec); + else + pa_volume_memchunk(&vchunk, &s->sample_spec, &s->sw_volume); + pa_idxset_foreach(s->outputs, do_post, &vchunk); + pa_memblock_unref(vchunk.memblock); + } else + pa_idxset_foreach(s->outputs, do_post, (void*) chunk); + + pa_source_unref(s); +} + +void pa_source_set_owner(pa_source *s, pa_module *m) { + assert(s); + assert(s->ref >= 1); + + s->owner = m; +} + +pa_usec_t pa_source_get_latency(pa_source *s) { + assert(s); + assert(s->ref >= 1); + + if (!s->get_latency) + return 0; + + return s->get_latency(s); +} + +void pa_source_set_volume(pa_source *s, pa_mixer_t m, const pa_cvolume *volume) { + pa_cvolume *v; + + assert(s); + assert(s->ref >= 1); + assert(volume); + + if (m == PA_MIXER_HARDWARE && s->set_hw_volume) + v = &s->hw_volume; + else + v = &s->sw_volume; + + if (pa_cvolume_equal(v, volume)) + return; + + *v = *volume; + + if (v == &s->hw_volume) + if (s->set_hw_volume(s) < 0) + s->sw_volume = *volume; + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); +} + +const pa_cvolume *pa_source_get_volume(pa_source *s, pa_mixer_t m) { + assert(s); + assert(s->ref >= 1); + + if (m == PA_MIXER_HARDWARE && s->set_hw_volume) { + + if (s->get_hw_volume) + s->get_hw_volume(s); + + return &s->hw_volume; + } else + return &s->sw_volume; +} + +void pa_source_set_mute(pa_source *s, pa_mixer_t m, int mute) { + int *t; + + assert(s); + assert(s->ref >= 1); + + if (m == PA_MIXER_HARDWARE && s->set_hw_mute) + t = &s->hw_muted; + else + t = &s->sw_muted; + + if (!!*t == !!mute) + return; + + *t = !!mute; + + if (t == &s->hw_muted) + if (s->set_hw_mute(s) < 0) + s->sw_muted = !!mute; + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); +} + +int pa_source_get_mute(pa_source *s, pa_mixer_t m) { + assert(s); + assert(s->ref >= 1); + + if (m == PA_MIXER_HARDWARE && s->set_hw_mute) { + + if (s->get_hw_mute) + s->get_hw_mute(s); + + return s->hw_muted; + } else + return s->sw_muted; +} diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h new file mode 100644 index 00000000..6255c115 --- /dev/null +++ b/src/pulsecore/source.h @@ -0,0 +1,101 @@ +#ifndef foosourcehfoo +#define foosourcehfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef struct pa_source pa_source; + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PA_MAX_OUTPUTS_PER_SOURCE 16 + +typedef enum pa_source_state { + PA_SOURCE_RUNNING, + PA_SOURCE_DISCONNECTED +} pa_source_state_t; + +struct pa_source { + int ref; + uint32_t index; + pa_core *core; + pa_source_state_t state; + + char *name, *description, *driver; + pa_module *owner; + + pa_sample_spec sample_spec; + pa_channel_map channel_map; + + pa_idxset *outputs; + pa_sink *monitor_of; + + pa_cvolume hw_volume, sw_volume; + int hw_muted, sw_muted; + + void (*notify)(pa_source*source); + pa_usec_t (*get_latency)(pa_source *s); + int (*set_hw_volume)(pa_source *s); + int (*get_hw_volume)(pa_source *s); + int (*set_hw_mute)(pa_source *s); + int (*get_hw_mute)(pa_source *s); + + void *userdata; +}; + +pa_source* pa_source_new( + pa_core *core, + const char *driver, + const char *name, + int namereg_fail, + const pa_sample_spec *spec, + const pa_channel_map *map); + +void pa_source_disconnect(pa_source *s); +void pa_source_unref(pa_source *s); +pa_source* pa_source_ref(pa_source *c); + +/* Pass a new memory block to all output streams */ +void pa_source_post(pa_source*s, const pa_memchunk *b); + +void pa_source_notify(pa_source *s); + +void pa_source_set_owner(pa_source *s, pa_module *m); + +pa_usec_t pa_source_get_latency(pa_source *s); + +void pa_source_set_volume(pa_source *source, pa_mixer_t m, const pa_cvolume *volume); +const pa_cvolume *pa_source_get_volume(pa_source *source, pa_mixer_t m); +void pa_source_set_mute(pa_source *source, pa_mixer_t m, int mute); +int pa_source_get_mute(pa_source *source, pa_mixer_t m); + +#endif diff --git a/src/pulsecore/strbuf.c b/src/pulsecore/strbuf.c new file mode 100644 index 00000000..ef8160dc --- /dev/null +++ b/src/pulsecore/strbuf.c @@ -0,0 +1,167 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include "strbuf.h" + +/* A chunk of the linked list that makes up the string */ +struct chunk { + struct chunk *next; + size_t length; +}; + +#define CHUNK_TO_TEXT(c) ((char*) (c) + sizeof(struct chunk)) + +struct pa_strbuf { + size_t length; + struct chunk *head, *tail; +}; + +pa_strbuf *pa_strbuf_new(void) { + pa_strbuf *sb = pa_xmalloc(sizeof(pa_strbuf)); + sb->length = 0; + sb->head = sb->tail = NULL; + return sb; +} + +void pa_strbuf_free(pa_strbuf *sb) { + assert(sb); + while (sb->head) { + struct chunk *c = sb->head; + sb->head = sb->head->next; + pa_xfree(c); + } + + pa_xfree(sb); +} + +/* Make a C string from the string buffer. The caller has to free + * string with pa_xfree(). */ +char *pa_strbuf_tostring(pa_strbuf *sb) { + char *t, *e; + struct chunk *c; + assert(sb); + + e = t = pa_xmalloc(sb->length+1); + + for (c = sb->head; c; c = c->next) { + assert((size_t) (e-t) <= sb->length); + memcpy(e, CHUNK_TO_TEXT(c), c->length); + e += c->length; + } + + /* Trailing NUL */ + *e = 0; + + assert(e == t+sb->length); + + return t; +} + +/* Combination of pa_strbuf_free() and pa_strbuf_tostring() */ +char *pa_strbuf_tostring_free(pa_strbuf *sb) { + char *t; + assert(sb); + t = pa_strbuf_tostring(sb); + pa_strbuf_free(sb); + return t; +} + +/* Append a string to the string buffer */ +void pa_strbuf_puts(pa_strbuf *sb, const char *t) { + assert(sb && t); + pa_strbuf_putsn(sb, t, strlen(t)); +} + +/* Append a new chunk to the linked list */ +static void append(pa_strbuf *sb, struct chunk *c) { + assert(sb && c); + + if (sb->tail) { + assert(sb->head); + sb->tail->next = c; + } else { + assert(!sb->head); + sb->head = c; + } + + sb->tail = c; + sb->length += c->length; + c->next = NULL; +} + +/* Append up to l bytes of a string to the string buffer */ +void pa_strbuf_putsn(pa_strbuf *sb, const char *t, size_t l) { + struct chunk *c; + assert(sb && t); + + if (!l) + return; + + c = pa_xmalloc(sizeof(struct chunk)+l); + c->length = l; + memcpy(CHUNK_TO_TEXT(c), t, l); + + append(sb, c); +} + +/* Append a printf() style formatted string to the string buffer. */ +/* The following is based on an example from the GNU libc documentation */ +int pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) { + int size = 100; + struct chunk *c = NULL; + + assert(sb); + + for(;;) { + va_list ap; + int r; + + c = pa_xrealloc(c, sizeof(struct chunk)+size); + + va_start(ap, format); + r = vsnprintf(CHUNK_TO_TEXT(c), size, format, ap); + va_end(ap); + + if (r > -1 && r < size) { + c->length = r; + append(sb, c); + return r; + } + + if (r > -1) /* glibc 2.1 */ + size = r+1; + else /* glibc 2.0 */ + size *= 2; + } +} diff --git a/src/pulsecore/strbuf.h b/src/pulsecore/strbuf.h new file mode 100644 index 00000000..c45fb15f --- /dev/null +++ b/src/pulsecore/strbuf.h @@ -0,0 +1,38 @@ +#ifndef foostrbufhfoo +#define foostrbufhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef struct pa_strbuf pa_strbuf; + +pa_strbuf *pa_strbuf_new(void); +void pa_strbuf_free(pa_strbuf *sb); +char *pa_strbuf_tostring(pa_strbuf *sb); +char *pa_strbuf_tostring_free(pa_strbuf *sb); + +int pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); +void pa_strbuf_puts(pa_strbuf *sb, const char *t); +void pa_strbuf_putsn(pa_strbuf *sb, const char *t, size_t m); + +#endif diff --git a/src/pulsecore/strlist.c b/src/pulsecore/strlist.c new file mode 100644 index 00000000..df3a0275 --- /dev/null +++ b/src/pulsecore/strlist.c @@ -0,0 +1,139 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include +#include + +#include "strlist.h" + +struct pa_strlist { + pa_strlist *next; + char *str; +}; + +pa_strlist* pa_strlist_prepend(pa_strlist *l, const char *s) { + pa_strlist *n; + assert(s); + n = pa_xmalloc(sizeof(pa_strlist)); + n->str = pa_xstrdup(s); + n->next = l; + return n; +} + +char *pa_strlist_tostring(pa_strlist *l) { + int first = 1; + pa_strbuf *b; + + b = pa_strbuf_new(); + for (; l; l = l->next) { + if (!first) + pa_strbuf_puts(b, " "); + first = 0; + pa_strbuf_puts(b, l->str); + } + + return pa_strbuf_tostring_free(b); +} + +pa_strlist* pa_strlist_remove(pa_strlist *l, const char *s) { + pa_strlist *ret = l, *prev = NULL; + assert(l && s); + + while (l) { + if (!strcmp(l->str, s)) { + pa_strlist *n = l->next; + + if (!prev) { + assert(ret == l); + ret = n; + } else + prev->next = n; + + pa_xfree(l->str); + pa_xfree(l); + + l = n; + + } else { + prev = l; + l = l->next; + } + } + + return ret; +} + +void pa_strlist_free(pa_strlist *l) { + while (l) { + pa_strlist *c = l; + l = l->next; + + pa_xfree(c->str); + pa_xfree(c); + } +} + +pa_strlist* pa_strlist_pop(pa_strlist *l, char **s) { + pa_strlist *r; + assert(s); + + if (!l) { + *s = NULL; + return NULL; + } + + *s = l->str; + r = l->next; + pa_xfree(l); + return r; +} + +pa_strlist* pa_strlist_parse(const char *s) { + pa_strlist *head = NULL, *p = NULL; + const char *state = NULL; + char *r; + + while ((r = pa_split_spaces(s, &state))) { + pa_strlist *n; + + n = pa_xmalloc(sizeof(pa_strlist)); + n->str = r; + n->next = NULL; + + if (p) + p->next = n; + else + head = n; + + p = n; + } + + return head; +} diff --git a/src/pulsecore/strlist.h b/src/pulsecore/strlist.h new file mode 100644 index 00000000..87925d5e --- /dev/null +++ b/src/pulsecore/strlist.h @@ -0,0 +1,47 @@ +#ifndef foostrlisthfoo +#define foostrlisthfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef struct pa_strlist pa_strlist; + +/* Add the specified server string to the list, return the new linked list head */ +pa_strlist* pa_strlist_prepend(pa_strlist *l, const char *s); + +/* Remove the specified string from the list, return the new linked list head */ +pa_strlist* pa_strlist_remove(pa_strlist *l, const char *s); + +/* Make a whitespace separated string of all server stringes. Returned memory has to be freed with pa_xfree() */ +char *pa_strlist_tostring(pa_strlist *l); + +/* Free the entire list */ +void pa_strlist_free(pa_strlist *l); + +/* Return the next entry in the list in *string and remove it from + * the list. Returns the new list head. The memory *string points to + * has to be freed with pa_xfree() */ +pa_strlist* pa_strlist_pop(pa_strlist *l, char **s); + +/* Parse a whitespace separated server list */ +pa_strlist* pa_strlist_parse(const char *s); + +#endif diff --git a/src/pulsecore/tagstruct.c b/src/pulsecore/tagstruct.c new file mode 100644 index 00000000..60b05a3f --- /dev/null +++ b/src/pulsecore/tagstruct.c @@ -0,0 +1,630 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#include "winsock.h" + +#include + +#include "tagstruct.h" + + +struct pa_tagstruct { + uint8_t *data; + size_t length, allocated; + size_t rindex; + + int dynamic; +}; + +pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) { + pa_tagstruct*t; + + assert(!data || (data && length)); + + t = pa_xmalloc(sizeof(pa_tagstruct)); + t->data = (uint8_t*) data; + t->allocated = t->length = data ? length : 0; + t->rindex = 0; + t->dynamic = !data; + return t; +} + +void pa_tagstruct_free(pa_tagstruct*t) { + assert(t); + if (t->dynamic) + pa_xfree(t->data); + pa_xfree(t); +} + +uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l) { + uint8_t *p; + assert(t && t->dynamic && l); + p = t->data; + *l = t->length; + pa_xfree(t); + return p; +} + +static void extend(pa_tagstruct*t, size_t l) { + assert(t && t->dynamic); + + if (t->length+l <= t->allocated) + return; + + t->data = pa_xrealloc(t->data, t->allocated = t->length+l+100); +} + + +void pa_tagstruct_puts(pa_tagstruct*t, const char *s) { + size_t l; + assert(t); + if (s) { + l = strlen(s)+2; + extend(t, l); + t->data[t->length] = PA_TAG_STRING; + strcpy((char*) (t->data+t->length+1), s); + t->length += l; + } else { + extend(t, 1); + t->data[t->length] = PA_TAG_STRING_NULL; + t->length += 1; + } +} + +void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i) { + assert(t); + extend(t, 5); + t->data[t->length] = PA_TAG_U32; + i = htonl(i); + memcpy(t->data+t->length+1, &i, 4); + t->length += 5; +} + +void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c) { + assert(t); + extend(t, 2); + t->data[t->length] = PA_TAG_U8; + *(t->data+t->length+1) = c; + t->length += 2; +} + +void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss) { + uint32_t rate; + assert(t && ss); + extend(t, 7); + t->data[t->length] = PA_TAG_SAMPLE_SPEC; + t->data[t->length+1] = (uint8_t) ss->format; + t->data[t->length+2] = ss->channels; + rate = htonl(ss->rate); + memcpy(t->data+t->length+3, &rate, 4); + t->length += 7; +} + +void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) { + uint32_t tmp; + assert(t && p); + + extend(t, 5+length); + t->data[t->length] = PA_TAG_ARBITRARY; + tmp = htonl(length); + memcpy(t->data+t->length+1, &tmp, 4); + if (length) + memcpy(t->data+t->length+5, p, length); + t->length += 5+length; +} + +void pa_tagstruct_put_boolean(pa_tagstruct*t, int b) { + assert(t); + extend(t, 1); + t->data[t->length] = b ? PA_TAG_BOOLEAN_TRUE : PA_TAG_BOOLEAN_FALSE; + t->length += 1; +} + +void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv) { + uint32_t tmp; + assert(t); + extend(t, 9); + t->data[t->length] = PA_TAG_TIMEVAL; + tmp = htonl(tv->tv_sec); + memcpy(t->data+t->length+1, &tmp, 4); + tmp = htonl(tv->tv_usec); + memcpy(t->data+t->length+5, &tmp, 4); + t->length += 9; +} + +void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u) { + uint32_t tmp; + assert(t); + extend(t, 9); + t->data[t->length] = PA_TAG_USEC; + tmp = htonl((uint32_t) (u >> 32)); + memcpy(t->data+t->length+1, &tmp, 4); + tmp = htonl((uint32_t) u); + memcpy(t->data+t->length+5, &tmp, 4); + t->length += 9; +} + +void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) { + uint32_t tmp; + assert(t); + extend(t, 9); + t->data[t->length] = PA_TAG_U64; + tmp = htonl((uint32_t) (u >> 32)); + memcpy(t->data+t->length+1, &tmp, 4); + tmp = htonl((uint32_t) u); + memcpy(t->data+t->length+5, &tmp, 4); + t->length += 9; +} + +void pa_tagstruct_puts64(pa_tagstruct*t, int64_t u) { + uint32_t tmp; + assert(t); + extend(t, 9); + t->data[t->length] = PA_TAG_S64; + tmp = htonl((uint32_t) ((uint64_t) u >> 32)); + memcpy(t->data+t->length+1, &tmp, 4); + tmp = htonl((uint32_t) ((uint64_t) u)); + memcpy(t->data+t->length+5, &tmp, 4); + t->length += 9; +} + +void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) { + unsigned i; + + assert(t); + extend(t, 2 + map->channels); + + t->data[t->length++] = PA_TAG_CHANNEL_MAP; + t->data[t->length++] = map->channels; + + for (i = 0; i < map->channels; i ++) + t->data[t->length++] = (uint8_t) map->map[i]; +} + +void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) { + unsigned i; + pa_volume_t vol; + + assert(t); + extend(t, 2 + cvolume->channels * sizeof(pa_volume_t)); + + t->data[t->length++] = PA_TAG_CVOLUME; + t->data[t->length++] = cvolume->channels; + + for (i = 0; i < cvolume->channels; i ++) { + vol = htonl(cvolume->values[i]); + memcpy(t->data + t->length, &vol, sizeof(pa_volume_t)); + t->length += sizeof(pa_volume_t); + } +} + +int pa_tagstruct_gets(pa_tagstruct*t, const char **s) { + int error = 0; + size_t n; + char *c; + assert(t && s); + + if (t->rindex+1 > t->length) + return -1; + + if (t->data[t->rindex] == PA_TAG_STRING_NULL) { + t->rindex++; + *s = NULL; + return 0; + } + + if (t->rindex+2 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_STRING) + return -1; + + error = 1; + for (n = 0, c = (char*) (t->data+t->rindex+1); t->rindex+1+n < t->length; n++, c++) + if (!*c) { + error = 0; + break; + } + + if (error) + return -1; + + *s = (char*) (t->data+t->rindex+1); + + t->rindex += n+2; + return 0; +} + +int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) { + assert(t && i); + + if (t->rindex+5 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_U32) + return -1; + + memcpy(i, t->data+t->rindex+1, 4); + *i = ntohl(*i); + t->rindex += 5; + return 0; +} + +int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) { + assert(t && c); + + if (t->rindex+2 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_U8) + return -1; + + *c = t->data[t->rindex+1]; + t->rindex +=2; + return 0; +} + +int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) { + assert(t && ss); + + if (t->rindex+7 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_SAMPLE_SPEC) + return -1; + + ss->format = t->data[t->rindex+1]; + ss->channels = t->data[t->rindex+2]; + memcpy(&ss->rate, t->data+t->rindex+3, 4); + ss->rate = ntohl(ss->rate); + + t->rindex += 7; + return 0; +} + +int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) { + uint32_t len; + assert(t && p); + + if (t->rindex+5+length > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_ARBITRARY) + return -1; + + memcpy(&len, t->data+t->rindex+1, 4); + if (ntohl(len) != length) + return -1; + + *p = t->data+t->rindex+5; + t->rindex += 5+length; + return 0; +} + +int pa_tagstruct_eof(pa_tagstruct*t) { + assert(t); + return t->rindex >= t->length; +} + +const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) { + assert(t && t->dynamic && l); + *l = t->length; + return t->data; +} + +int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) { + assert(t && b); + + if (t->rindex+1 > t->length) + return -1; + + if (t->data[t->rindex] == PA_TAG_BOOLEAN_TRUE) + *b = 1; + else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE) + *b = 0; + else + return -1; + + t->rindex +=1; + return 0; +} + +int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) { + + if (t->rindex+9 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_TIMEVAL) + return -1; + + memcpy(&tv->tv_sec, t->data+t->rindex+1, 4); + tv->tv_sec = ntohl(tv->tv_sec); + memcpy(&tv->tv_usec, t->data+t->rindex+5, 4); + tv->tv_usec = ntohl(tv->tv_usec); + t->rindex += 9; + return 0; +} + +int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) { + uint32_t tmp; + assert(t && u); + + if (t->rindex+9 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_USEC) + return -1; + + memcpy(&tmp, t->data+t->rindex+1, 4); + *u = (pa_usec_t) ntohl(tmp) << 32; + memcpy(&tmp, t->data+t->rindex+5, 4); + *u |= (pa_usec_t) ntohl(tmp); + t->rindex +=9; + return 0; +} + +int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) { + uint32_t tmp; + assert(t && u); + + if (t->rindex+9 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_U64) + return -1; + + memcpy(&tmp, t->data+t->rindex+1, 4); + *u = (uint64_t) ntohl(tmp) << 32; + memcpy(&tmp, t->data+t->rindex+5, 4); + *u |= (uint64_t) ntohl(tmp); + t->rindex +=9; + return 0; +} + +int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *u) { + uint32_t tmp; + assert(t && u); + + if (t->rindex+9 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_S64) + return -1; + + memcpy(&tmp, t->data+t->rindex+1, 4); + *u = (int64_t) ((uint64_t) ntohl(tmp) << 32); + memcpy(&tmp, t->data+t->rindex+5, 4); + *u |= (int64_t) ntohl(tmp); + t->rindex +=9; + return 0; +} + +int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) { + unsigned i; + + assert(t); + assert(map); + + if (t->rindex+2 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_CHANNEL_MAP) + return -1; + + if ((map->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX) + return -1; + + if (t->rindex+2+map->channels > t->length) + return -1; + + for (i = 0; i < map->channels; i ++) + map->map[i] = (int8_t) t->data[t->rindex + 2 + i]; + + t->rindex += 2 + map->channels; + return 0; +} + +int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) { + unsigned i; + pa_volume_t vol; + + assert(t); + assert(cvolume); + + if (t->rindex+2 > t->length) + return -1; + + if (t->data[t->rindex] != PA_TAG_CVOLUME) + return -1; + + if ((cvolume->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX) + return -1; + + if (t->rindex+2+cvolume->channels*sizeof(pa_volume_t) > t->length) + return -1; + + for (i = 0; i < cvolume->channels; i ++) { + memcpy(&vol, t->data + t->rindex + 2 + i * sizeof(pa_volume_t), sizeof(pa_volume_t)); + cvolume->values[i] = (pa_volume_t) ntohl(vol); + } + + t->rindex += 2 + cvolume->channels * sizeof(pa_volume_t); + return 0; +} + +void pa_tagstruct_put(pa_tagstruct *t, ...) { + va_list va; + assert(t); + + va_start(va, t); + + for (;;) { + int tag = va_arg(va, int); + + if (tag == PA_TAG_INVALID) + break; + + switch (tag) { + case PA_TAG_STRING: + case PA_TAG_STRING_NULL: + pa_tagstruct_puts(t, va_arg(va, char*)); + break; + + case PA_TAG_U32: + pa_tagstruct_putu32(t, va_arg(va, uint32_t)); + break; + + case PA_TAG_U8: + pa_tagstruct_putu8(t, (uint8_t) va_arg(va, int)); + break; + + case PA_TAG_U64: + pa_tagstruct_putu64(t, va_arg(va, uint64_t)); + break; + + case PA_TAG_SAMPLE_SPEC: + pa_tagstruct_put_sample_spec(t, va_arg(va, pa_sample_spec*)); + break; + + case PA_TAG_ARBITRARY: { + void *p = va_arg(va, void*); + size_t size = va_arg(va, size_t); + pa_tagstruct_put_arbitrary(t, p, size); + break; + } + + case PA_TAG_BOOLEAN_TRUE: + case PA_TAG_BOOLEAN_FALSE: + pa_tagstruct_put_boolean(t, va_arg(va, int)); + break; + + case PA_TAG_TIMEVAL: + pa_tagstruct_put_timeval(t, va_arg(va, struct timeval*)); + break; + + case PA_TAG_USEC: + pa_tagstruct_put_usec(t, va_arg(va, pa_usec_t)); + break; + + case PA_TAG_CHANNEL_MAP: + pa_tagstruct_put_channel_map(t, va_arg(va, pa_channel_map *)); + break; + + case PA_TAG_CVOLUME: + pa_tagstruct_put_cvolume(t, va_arg(va, pa_cvolume *)); + break; + + default: + abort(); + } + } + + va_end(va); +} + +int pa_tagstruct_get(pa_tagstruct *t, ...) { + va_list va; + int ret = 0; + + assert(t); + + va_start(va, t); + while (ret == 0) { + int tag = va_arg(va, int); + + if (tag == PA_TAG_INVALID) + break; + + switch (tag) { + case PA_TAG_STRING: + case PA_TAG_STRING_NULL: + ret = pa_tagstruct_gets(t, va_arg(va, const char**)); + break; + + case PA_TAG_U32: + ret = pa_tagstruct_getu32(t, va_arg(va, uint32_t*)); + break; + + case PA_TAG_U8: + ret = pa_tagstruct_getu8(t, va_arg(va, uint8_t*)); + break; + + case PA_TAG_U64: + ret = pa_tagstruct_getu64(t, va_arg(va, uint64_t*)); + break; + + case PA_TAG_SAMPLE_SPEC: + ret = pa_tagstruct_get_sample_spec(t, va_arg(va, pa_sample_spec*)); + break; + + case PA_TAG_ARBITRARY: { + const void **p = va_arg(va, const void**); + size_t size = va_arg(va, size_t); + ret = pa_tagstruct_get_arbitrary(t, p, size); + break; + } + + case PA_TAG_BOOLEAN_TRUE: + case PA_TAG_BOOLEAN_FALSE: + ret = pa_tagstruct_get_boolean(t, va_arg(va, int*)); + break; + + case PA_TAG_TIMEVAL: + ret = pa_tagstruct_get_timeval(t, va_arg(va, struct timeval*)); + break; + + case PA_TAG_USEC: + ret = pa_tagstruct_get_usec(t, va_arg(va, pa_usec_t*)); + break; + + case PA_TAG_CHANNEL_MAP: + ret = pa_tagstruct_get_channel_map(t, va_arg(va, pa_channel_map *)); + break; + + case PA_TAG_CVOLUME: + ret = pa_tagstruct_get_cvolume(t, va_arg(va, pa_cvolume *)); + break; + + + default: + abort(); + } + + } + + va_end(va); + return ret; +} diff --git a/src/pulsecore/tagstruct.h b/src/pulsecore/tagstruct.h new file mode 100644 index 00000000..4c56f328 --- /dev/null +++ b/src/pulsecore/tagstruct.h @@ -0,0 +1,93 @@ +#ifndef footagstructhfoo +#define footagstructhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include + +#include +#include +#include + +typedef struct pa_tagstruct pa_tagstruct; + +enum { + PA_TAG_INVALID = 0, + PA_TAG_STRING = 't', + PA_TAG_STRING_NULL = 'N', + PA_TAG_U32 = 'L', + PA_TAG_U8 = 'B', + PA_TAG_U64 = 'R', + PA_TAG_S64 = 'r', + PA_TAG_SAMPLE_SPEC = 'a', + PA_TAG_ARBITRARY = 'x', + PA_TAG_BOOLEAN_TRUE = '1', + PA_TAG_BOOLEAN_FALSE = '0', + PA_TAG_BOOLEAN = PA_TAG_BOOLEAN_TRUE, + PA_TAG_TIMEVAL = 'T', + PA_TAG_USEC = 'U' /* 64bit unsigned */, + PA_TAG_CHANNEL_MAP = 'm', + PA_TAG_CVOLUME = 'v' +}; + +pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length); +void pa_tagstruct_free(pa_tagstruct*t); +uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l); + +int pa_tagstruct_eof(pa_tagstruct*t); +const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l); + +void pa_tagstruct_put(pa_tagstruct *t, ...); + +void pa_tagstruct_puts(pa_tagstruct*t, const char *s); +void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c); +void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i); +void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t i); +void pa_tagstruct_puts64(pa_tagstruct*t, int64_t i); +void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss); +void pa_tagstruct_put_arbitrary(pa_tagstruct*t, const void *p, size_t length); +void pa_tagstruct_put_boolean(pa_tagstruct*t, int b); +void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv); +void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u); +void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map); +void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume); + +int pa_tagstruct_get(pa_tagstruct *t, ...); + +int pa_tagstruct_gets(pa_tagstruct*t, const char **s); +int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c); +int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i); +int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *i); +int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *i); +int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss); +int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length); +int pa_tagstruct_get_boolean(pa_tagstruct *t, int *b); +int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv); +int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u); +int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map); +int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *v); + + +#endif diff --git a/src/pulsecore/tokenizer.c b/src/pulsecore/tokenizer.c new file mode 100644 index 00000000..e799c1e6 --- /dev/null +++ b/src/pulsecore/tokenizer.c @@ -0,0 +1,90 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include +#include + +#include "tokenizer.h" + +struct pa_tokenizer { + pa_dynarray *dynarray; +}; + +static void token_free(void *p, PA_GCC_UNUSED void *userdata) { + pa_xfree(p); +} + +static void parse(pa_dynarray*a, const char *s, unsigned args) { + int infty = 0; + const char delimiter[] = " \t\n\r"; + const char *p; + assert(a && s); + + if (args == 0) + infty = 1; + + p = s+strspn(s, delimiter); + while (*p && (infty || args >= 2)) { + size_t l = strcspn(p, delimiter); + char *n = pa_xstrndup(p, l); + pa_dynarray_append(a, n); + p += l; + p += strspn(p, delimiter); + args--; + } + + if (args && *p) { + char *n = pa_xstrdup(p); + pa_dynarray_append(a, n); + } +} + +pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args) { + pa_tokenizer *t; + + t = pa_xmalloc(sizeof(pa_tokenizer)); + t->dynarray = pa_dynarray_new(); + assert(t->dynarray); + + parse(t->dynarray, s, args); + return t; +} + +void pa_tokenizer_free(pa_tokenizer *t) { + assert(t); + pa_dynarray_free(t->dynarray, token_free, NULL); + pa_xfree(t); +} + +const char *pa_tokenizer_get(pa_tokenizer *t, unsigned i) { + assert(t); + return pa_dynarray_get(t->dynarray, i); +} diff --git a/src/pulsecore/tokenizer.h b/src/pulsecore/tokenizer.h new file mode 100644 index 00000000..b9a5c55b --- /dev/null +++ b/src/pulsecore/tokenizer.h @@ -0,0 +1,32 @@ +#ifndef footokenizerhfoo +#define footokenizerhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef struct pa_tokenizer pa_tokenizer; + +pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args); +void pa_tokenizer_free(pa_tokenizer *t); + +const char *pa_tokenizer_get(pa_tokenizer *t, unsigned i); + +#endif diff --git a/src/pulsecore/winsock.h b/src/pulsecore/winsock.h new file mode 100644 index 00000000..ae868b38 --- /dev/null +++ b/src/pulsecore/winsock.h @@ -0,0 +1,24 @@ +#ifndef foowinsockhfoo +#define foowinsockhfoo + +#ifdef HAVE_WINSOCK2_H +#include + +#define ESHUTDOWN WSAESHUTDOWN +#define ECONNRESET WSAECONNRESET +#define ECONNABORTED WSAECONNABORTED +#define ENETRESET WSAENETRESET +#define EINPROGRESS WSAEINPROGRESS +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define ETIMEDOUT WSAETIMEDOUT +#define ECONNREFUSED WSAECONNREFUSED +#define EHOSTUNREACH WSAEHOSTUNREACH +#define EWOULDBLOCK WSAEWOULDBLOCK + +#endif + +#ifdef HAVE_WS2TCPIP_H +#include +#endif + +#endif diff --git a/src/pulsecore/x11prop.c b/src/pulsecore/x11prop.c new file mode 100644 index 00000000..dd4ff99e --- /dev/null +++ b/src/pulsecore/x11prop.c @@ -0,0 +1,70 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include "x11prop.h" + + +void pa_x11_set_prop(Display *d, const char *name, const char *data) { + Atom a = XInternAtom(d, name, False); + XChangeProperty(d, RootWindow(d, 0), a, XA_STRING, 8, PropModeReplace, (const unsigned char*) data, strlen(data)+1); +} + +void pa_x11_del_prop(Display *d, const char *name) { + Atom a = XInternAtom(d, name, False); + XDeleteProperty(d, RootWindow(d, 0), a); +} + +char* pa_x11_get_prop(Display *d, const char *name, char *p, size_t l) { + Atom actual_type; + int actual_format; + unsigned long nitems; + unsigned long nbytes_after; + unsigned char *prop = NULL; + char *ret = NULL; + + Atom a = XInternAtom(d, name, False); + if (XGetWindowProperty(d, RootWindow(d, 0), a, 0, (l+2)/4, False, XA_STRING, &actual_type, &actual_format, &nitems, &nbytes_after, &prop) != Success) + goto finish; + + if (actual_type != XA_STRING) + goto finish; + + memcpy(p, prop, nitems); + p[nitems] = 0; + + ret = p; + +finish: + + if (prop) + XFree(prop); + + return ret; +} diff --git a/src/pulsecore/x11prop.h b/src/pulsecore/x11prop.h new file mode 100644 index 00000000..bd24951a --- /dev/null +++ b/src/pulsecore/x11prop.h @@ -0,0 +1,33 @@ +#ifndef foox11prophfoo +#define foox11prophfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include + +void pa_x11_set_prop(Display *d, const char *name, const char *data); +void pa_x11_del_prop(Display *d, const char *name); +char* pa_x11_get_prop(Display *d, const char *name, char *p, size_t l); + +#endif diff --git a/src/pulsecore/x11wrap.c b/src/pulsecore/x11wrap.c new file mode 100644 index 00000000..2ba0a87f --- /dev/null +++ b/src/pulsecore/x11wrap.c @@ -0,0 +1,247 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include + +#include +#include +#include + +#include "x11wrap.h" + +typedef struct pa_x11_internal pa_x11_internal; + +struct pa_x11_internal { + PA_LLIST_FIELDS(pa_x11_internal); + pa_x11_wrapper *wrapper; + pa_io_event* io_event; + int fd; +}; + +struct pa_x11_wrapper { + pa_core *core; + int ref; + + char *property_name; + Display *display; + + pa_defer_event* defer_event; + pa_io_event* io_event; + + PA_LLIST_HEAD(pa_x11_client, clients); + PA_LLIST_HEAD(pa_x11_internal, internals); +}; + +struct pa_x11_client { + PA_LLIST_FIELDS(pa_x11_client); + pa_x11_wrapper *wrapper; + int (*callback)(pa_x11_wrapper *w, XEvent *e, void *userdata); + void *userdata; +}; + +/* Dispatch all pending X11 events */ +static void work(pa_x11_wrapper *w) { + assert(w && w->ref >= 1); + + while (XPending(w->display)) { + pa_x11_client *c; + XEvent e; + XNextEvent(w->display, &e); + + for (c = w->clients; c; c = c->next) { + assert(c->callback); + if (c->callback(w, &e, c->userdata) != 0) + break; + } + } +} + +/* IO notification event for the X11 display connection */ +static void display_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { + pa_x11_wrapper *w = userdata; + assert(m && e && fd >= 0 && w && w->ref >= 1); + work(w); +} + +/* Deferred notification event. Called once each main loop iteration */ +static void defer_event(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { + pa_x11_wrapper *w = userdata; + assert(m && e && w && w->ref >= 1); + + m->defer_enable(e, 0); + + work(w); +} + +/* IO notification event for X11 internal connections */ +static void internal_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { + pa_x11_wrapper *w = userdata; + assert(m && e && fd >= 0 && w && w->ref >= 1); + + XProcessInternalConnection(w->display, fd); + + work(w); +} + +/* Add a new IO source for the specified X11 internal connection */ +static pa_x11_internal* x11_internal_add(pa_x11_wrapper *w, int fd) { + pa_x11_internal *i; + assert(fd >= 0); + + i = pa_xmalloc(sizeof(pa_x11_internal)); + assert(i); + i->wrapper = w; + i->io_event = w->core->mainloop->io_new(w->core->mainloop, fd, PA_IO_EVENT_INPUT, internal_io_event, w); + i->fd = fd; + + PA_LLIST_PREPEND(pa_x11_internal, w->internals, i); + return i; +} + +/* Remove an IO source for an X11 internal connection */ +static void x11_internal_remove(pa_x11_wrapper *w, pa_x11_internal *i) { + assert(i); + + PA_LLIST_REMOVE(pa_x11_internal, w->internals, i); + w->core->mainloop->io_free(i->io_event); + pa_xfree(i); +} + +/* Implementation of XConnectionWatchProc */ +static void x11_watch(Display *display, XPointer userdata, int fd, Bool opening, XPointer *watch_data) { + pa_x11_wrapper *w = (pa_x11_wrapper*) userdata; + assert(display && w && fd >= 0); + + if (opening) + *watch_data = (XPointer) x11_internal_add(w, fd); + else + x11_internal_remove(w, (pa_x11_internal*) *watch_data); +} + +static pa_x11_wrapper* x11_wrapper_new(pa_core *c, const char *name, const char *t) { + pa_x11_wrapper*w; + Display *d; + int r; + + if (!(d = XOpenDisplay(name))) { + pa_log(__FILE__": XOpenDisplay() failed"); + return NULL; + } + + w = pa_xmalloc(sizeof(pa_x11_wrapper)); + w->core = c; + w->ref = 1; + w->property_name = pa_xstrdup(t); + w->display = d; + + PA_LLIST_HEAD_INIT(pa_x11_client, w->clients); + PA_LLIST_HEAD_INIT(pa_x11_internal, w->internals); + + w->defer_event = c->mainloop->defer_new(c->mainloop, defer_event, w); + w->io_event = c->mainloop->io_new(c->mainloop, ConnectionNumber(d), PA_IO_EVENT_INPUT, display_io_event, w); + + XAddConnectionWatch(d, x11_watch, (XPointer) w); + + r = pa_property_set(c, w->property_name, w); + assert(r >= 0); + + return w; +} + +static void x11_wrapper_free(pa_x11_wrapper*w) { + int r; + assert(w); + + r = pa_property_remove(w->core, w->property_name); + assert(r >= 0); + + assert(!w->clients); + + XRemoveConnectionWatch(w->display, x11_watch, (XPointer) w); + XCloseDisplay(w->display); + + w->core->mainloop->io_free(w->io_event); + w->core->mainloop->defer_free(w->defer_event); + + while (w->internals) + x11_internal_remove(w, w->internals); + + pa_xfree(w->property_name); + pa_xfree(w); +} + +pa_x11_wrapper* pa_x11_wrapper_get(pa_core *c, const char *name) { + char t[256]; + pa_x11_wrapper *w; + assert(c); + + snprintf(t, sizeof(t), "x11-wrapper%s%s", name ? "-" : "", name ? name : ""); + if ((w = pa_property_get(c, t))) + return pa_x11_wrapper_ref(w); + + return x11_wrapper_new(c, name, t); +} + +pa_x11_wrapper* pa_x11_wrapper_ref(pa_x11_wrapper *w) { + assert(w && w->ref >= 1); + w->ref++; + return w; +} + +void pa_x11_wrapper_unref(pa_x11_wrapper* w) { + assert(w && w->ref >= 1); + + if (!(--w->ref)) + x11_wrapper_free(w); +} + +Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w) { + assert(w && w->ref >= 1); + + /* Somebody is using us, schedule a output buffer flush */ + w->core->mainloop->defer_enable(w->defer_event, 1); + + return w->display; +} + +pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata) { + pa_x11_client *c; + assert(w && w->ref >= 1); + + c = pa_xmalloc(sizeof(pa_x11_client)); + c->wrapper = w; + c->callback = cb; + c->userdata = userdata; + + PA_LLIST_PREPEND(pa_x11_client, w->clients, c); + + return c; +} + +void pa_x11_client_free(pa_x11_client *c) { + assert(c && c->wrapper && c->wrapper->ref >= 1); + + PA_LLIST_REMOVE(pa_x11_client, c->wrapper->clients, c); + pa_xfree(c); +} diff --git a/src/pulsecore/x11wrap.h b/src/pulsecore/x11wrap.h new file mode 100644 index 00000000..fcdd9f6c --- /dev/null +++ b/src/pulsecore/x11wrap.h @@ -0,0 +1,52 @@ +#ifndef foox11wraphfoo +#define foox11wraphfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include + +typedef struct pa_x11_wrapper pa_x11_wrapper; + +/* Return the X11 wrapper for this core. In case no wrapper was + existant before, allocate a new one */ +pa_x11_wrapper* pa_x11_wrapper_get(pa_core *c, const char *name); + +/* Increase the wrapper's reference count by one */ +pa_x11_wrapper* pa_x11_wrapper_ref(pa_x11_wrapper *w); + +/* Decrease the reference counter of an X11 wrapper object */ +void pa_x11_wrapper_unref(pa_x11_wrapper* w); + +/* Return the X11 display object for this connection */ +Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w); + +typedef struct pa_x11_client pa_x11_client; + +/* Register an X11 client, that is called for each X11 event */ +pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata); + +/* Free an X11 client object */ +void pa_x11_client_free(pa_x11_client *c); + +#endif diff --git a/src/tests/Makefile b/src/tests/Makefile index cd2a5c9a..c110232d 120000 --- a/src/tests/Makefile +++ b/src/tests/Makefile @@ -1 +1 @@ -../polyp/Makefile \ No newline at end of file +../pulse/Makefile \ No newline at end of file diff --git a/src/tests/channelmap-test.c b/src/tests/channelmap-test.c index c6644229..124ce576 100644 --- a/src/tests/channelmap-test.c +++ b/src/tests/channelmap-test.c @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { char cm[PA_CHANNEL_MAP_SNPRINT_MAX]; diff --git a/src/tests/cpulimit-test.c b/src/tests/cpulimit-test.c index b51014c8..2302a26d 100644 --- a/src/tests/cpulimit-test.c +++ b/src/tests/cpulimit-test.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software + License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -29,11 +29,11 @@ #include #include -#include -#include +#include +#include #ifdef TEST2 -#include +#include #endif #include "../daemon/cpulimit.h" diff --git a/src/tests/interpol-test.c b/src/tests/interpol-test.c index fa5fae7d..7cabc1c9 100644 --- a/src/tests/interpol-test.c +++ b/src/tests/interpol-test.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -34,8 +34,8 @@ #include #include -#include -#include +#include +#include static pa_context *context = NULL; static pa_stream *stream = NULL; diff --git a/src/tests/mainloop-test.c b/src/tests/mainloop-test.c index 2936420c..671adeff 100644 --- a/src/tests/mainloop-test.c +++ b/src/tests/mainloop-test.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -28,15 +28,15 @@ #include #include -#include +#include -#include -#include +#include +#include #ifdef GLIB_MAIN_LOOP #include -#include +#include static GMainLoop* glib_main_loop = NULL; @@ -48,7 +48,7 @@ static GMainLoop* glib_main_loop = NULL; #else /* GLIB_MAIN_LOOP */ -#include +#include #endif /* GLIB_MAIN_LOOP */ static pa_defer_event *de; diff --git a/src/tests/mcalign-test.c b/src/tests/mcalign-test.c index 765dcf94..ccb0613e 100644 --- a/src/tests/mcalign-test.c +++ b/src/tests/mcalign-test.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software + License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -31,9 +31,9 @@ #include #include -#include -#include -#include +#include +#include +#include /* A simple program for testing pa_mcalign */ diff --git a/src/tests/memblockq-test.c b/src/tests/memblockq-test.c index e9764627..af43d06f 100644 --- a/src/tests/memblockq-test.c +++ b/src/tests/memblockq-test.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -27,8 +27,8 @@ #include #include -#include -#include +#include +#include int main(int argc, char *argv[]) { int ret; diff --git a/src/tests/pacat-simple.c b/src/tests/pacat-simple.c index 9d8cc921..364e1ad6 100644 --- a/src/tests/pacat-simple.c +++ b/src/tests/pacat-simple.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -29,9 +29,9 @@ #include #include -#include -#include -#include +#include +#include +#include #define BUFSIZE 1024 diff --git a/src/tests/parec-simple.c b/src/tests/parec-simple.c index 4463d549..45a52288 100644 --- a/src/tests/parec-simple.c +++ b/src/tests/parec-simple.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -28,9 +28,9 @@ #include #include -#include -#include -#include +#include +#include +#include #define BUFSIZE 1024 diff --git a/src/tests/strlist-test.c b/src/tests/strlist-test.c index 415c94e6..4262a001 100644 --- a/src/tests/strlist-test.c +++ b/src/tests/strlist-test.c @@ -1,8 +1,8 @@ #include -#include -#include -#include +#include +#include +#include int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char* argv[]) { char *t, *u; diff --git a/src/tests/sync-playback.c b/src/tests/sync-playback.c index d675e01c..39c6aac4 100644 --- a/src/tests/sync-playback.c +++ b/src/tests/sync-playback.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -33,8 +33,8 @@ #include #include -#include -#include +#include +#include #define NSTREAMS 4 #define SINE_HZ 440 diff --git a/src/tests/thread-mainloop-test.c b/src/tests/thread-mainloop-test.c index aef3aff0..bf3d4cd2 100644 --- a/src/tests/thread-mainloop-test.c +++ b/src/tests/thread-mainloop-test.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -28,11 +28,11 @@ #include #include -#include -#include +#include +#include -#include -#include +#include +#include static void tcb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) { fprintf(stderr, "TIME EVENT START\n"); diff --git a/src/tests/utf8-test.c b/src/tests/utf8-test.c index 2c21613e..2e9f128a 100644 --- a/src/tests/utf8-test.c +++ b/src/tests/utf8-test.c @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include int main(int argc, char *argv[]) { char *c; diff --git a/src/tests/voltest.c b/src/tests/voltest.c index 4db8ef28..3de884af 100644 --- a/src/tests/voltest.c +++ b/src/tests/voltest.c @@ -2,8 +2,8 @@ #include -#include -#include +#include +#include int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { pa_volume_t v; diff --git a/src/utils/Makefile b/src/utils/Makefile index cd2a5c9a..c110232d 120000 --- a/src/utils/Makefile +++ b/src/utils/Makefile @@ -1 +1 @@ -../polyp/Makefile \ No newline at end of file +../pulse/Makefile \ No newline at end of file diff --git a/src/utils/pabrowse.c b/src/utils/pabrowse.c index 8063a28b..954e4e6c 100644 --- a/src/utils/pabrowse.c +++ b/src/utils/pabrowse.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -27,8 +27,8 @@ #include #include -#include -#include +#include +#include static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { fprintf(stderr, "Got signal, exiting\n"); diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 99e54e64..5e4596d1 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -33,7 +33,7 @@ #include #include -#include +#include #define TIME_EVENT_USEC 50000 @@ -479,7 +479,7 @@ int main(int argc, char *argv[]) { goto quit; case ARG_VERSION: - printf("pacat "PACKAGE_VERSION"\nCompiled with libpolyp %s\nLinked with libpolyp %s\n", pa_get_headers_version(), pa_get_library_version()); + printf("pacat "PACKAGE_VERSION"\nCompiled with libpulse %s\nLinked with libpulse %s\n", pa_get_headers_version(), pa_get_library_version()); ret = 0; goto quit; diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c index ad50c77c..e4a0970d 100644 --- a/src/utils/pacmd.c +++ b/src/utils/pacmd.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -32,12 +32,12 @@ #include #include -#include -#include +#include +#include -#include -#include -#include +#include +#include +#include int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { pid_t pid ; diff --git a/src/utils/pactl.c b/src/utils/pactl.c index cc59e459..6e40f3fe 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -35,7 +35,7 @@ #include -#include +#include #if PA_API_VERSION != 9 #error Invalid Polypaudio API version @@ -644,7 +644,7 @@ int main(int argc, char *argv[]) { goto quit; case ARG_VERSION: - printf("pactl "PACKAGE_VERSION"\nCompiled with libpolyp %s\nLinked with libpolyp %s\n", pa_get_headers_version(), pa_get_library_version()); + printf("pactl "PACKAGE_VERSION"\nCompiled with libpulse %s\nLinked with libpulse %s\n", pa_get_headers_version(), pa_get_library_version()); ret = 0; goto quit; diff --git a/src/utils/padsp b/src/utils/padsp index 27f99336..6e7e9f06 100644 --- a/src/utils/padsp +++ b/src/utils/padsp @@ -2,20 +2,20 @@ # $Id$ # -# This file is part of polypaudio. +# This file is part of PulseAudio. # -# polypaudio is free software; you can redistribute it and/or modify +# PulseAudio is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # -# polypaudio is distributed in the hope that it will be useful, but +# PulseAudio is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License -# along with polypaudio; if not, write to the Free Software +# along with PulseAudio; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. @@ -75,9 +75,9 @@ done shift $(( $OPTIND - 1 )) if [ x"$LD_PRELOAD" = x ] ; then - LD_PRELOAD="libpolypdsp.so" + LD_PRELOAD="libpulsedsp.so" else - LD_PRELOAD="$LD_PRELOAD libpolypdsp.so" + LD_PRELOAD="$LD_PRELOAD libpulsedsp.so" fi export LD_PRELOAD diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 56acbb28..13f571e1 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -46,9 +46,9 @@ #include -#include -#include -#include +#include +#include +#include typedef enum { FD_INFO_MIXER, diff --git a/src/utils/paplay.c b/src/utils/paplay.c index effc2a11..4b4a1ea6 100644 --- a/src/utils/paplay.c +++ b/src/utils/paplay.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -35,7 +35,7 @@ #include -#include +#include #if PA_API_VERSION != 9 #error Invalid Polypaudio API version @@ -253,7 +253,7 @@ int main(int argc, char *argv[]) { goto quit; case ARG_VERSION: - printf("paplay "PACKAGE_VERSION"\nCompiled with libpolyp %s\nLinked with libpolyp %s\n", pa_get_headers_version(), pa_get_library_version()); + printf("paplay "PACKAGE_VERSION"\nCompiled with libpulse %s\nLinked with libpulse %s\n", pa_get_headers_version(), pa_get_library_version()); ret = 0; goto quit; diff --git a/src/utils/pax11publish.c b/src/utils/pax11publish.c index 668361c6..770455b9 100644 --- a/src/utils/pax11publish.c +++ b/src/utils/pax11publish.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -31,15 +31,15 @@ #include #include -#include +#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include -#include "../polyp/client-conf.h" +#include "../pulse/client-conf.h" int main(int argc, char *argv[]) { const char *dname = NULL, *sink = NULL, *source = NULL, *server = NULL, *cookie_file = PA_NATIVE_COOKIE_FILE; -- cgit From 25f79693b150eb157a92d48036b904d3f7132a08 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 21:55:07 +0000 Subject: rename polypaudio.h to pulseaudio.h git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1034 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/polypaudio.h | 115 ------------------------------------------------- src/pulse/pulseaudio.h | 115 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 115 deletions(-) delete mode 100644 src/pulse/polypaudio.h create mode 100644 src/pulse/pulseaudio.h diff --git a/src/pulse/polypaudio.h b/src/pulse/polypaudio.h deleted file mode 100644 index 5bbd4cc5..00000000 --- a/src/pulse/polypaudio.h +++ /dev/null @@ -1,115 +0,0 @@ -#ifndef foopulseaudiohfoo -#define foopulseaudiohfoo - -/* $Id$ */ - -/*** - This file is part of PulseAudio. - - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with PulseAudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** \file - * Include all pulselib header files at once. The following - * files are included: \ref mainloop-api.h, \ref sample.h, \ref def.h, - * \ref context.h, \ref stream.h, \ref introspect.h, \ref subscribe.h, - * \ref scache.h, \ref version.h, \ref error.h, \ref channelmap.h, - * \ref operation.h,\ref volume.h, \ref xmalloc.h, \ref utf8.h, \ref - * thread-mainloop.h, \ref mainloop.h, \ref util.h, \ref timeval.h and - * \ref mainloop-signal.h at once */ - -/** \mainpage - * - * \section intro_sec Introduction - * - * This document describes the client API for the pulseaudio sound - * server. The API comes in two flavours to accomodate different styles - * of applications and different needs in complexity: - * - * \li The complete but somewhat complicated to use asynchronous API - * \li The simplified, easy to use, but limited synchronous API - * - * All strings in Polypaudio are in the UTF-8 encoding, regardless of current - * locale. Some functions will filter invalid sequences from the string, some - * will simply fail. To ensure reliable behaviour, make sure everything you - * pass to the API is already in UTF-8. - - * \section simple_sec Simple API - * - * Use this if you develop your program in synchronous style and just - * need a way to play or record data on the sound server. See - * \subpage simple for more details. - * - * \section async_sec Asynchronous API - * - * Use this if you develop your programs in asynchronous, event loop - * based style or if you want to use the advanced features of the - * pulseaudio API. A guide can be found in \subpage async. - * - * By using the built-in threaded main loop, it is possible to acheive a - * pseudo-synchronous API, which can be useful in synchronous applications - * where the simple API is insufficient. See the \ref async page for - * details. - * - * \section thread_sec Threads - * - * The pulseaudio client libraries are not designed to be used in a - * heavily threaded environment. They are however designed to be reentrant - * safe. - * - * To use a the libraries in a threaded environment, you must assure that - * all objects are only used in one thread at a time. Normally, this means - * that all objects belonging to a single context must be accessed from the - * same thread. - * - * The included main loop implementation is also not thread safe. Take care - * to make sure event lists are not manipulated when any other code is - * using the main loop. - * - * \section pkgconfig pkg-config - * - * The pulseaudio libraries provide pkg-config snippets for the different - * modules: - * - * \li pulselib - The asynchronous API and the internal main loop - * implementation. - * \li pulselib-glib12-mainloop - GLIB 1.2 main loop bindings. - * \li pulselib-glib-mainloop - GLIB 2.x main loop bindings. - * \li pulselib-simple - The simple pulseaudio API. - */ - -#endif diff --git a/src/pulse/pulseaudio.h b/src/pulse/pulseaudio.h new file mode 100644 index 00000000..5bbd4cc5 --- /dev/null +++ b/src/pulse/pulseaudio.h @@ -0,0 +1,115 @@ +#ifndef foopulseaudiohfoo +#define foopulseaudiohfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** \file + * Include all pulselib header files at once. The following + * files are included: \ref mainloop-api.h, \ref sample.h, \ref def.h, + * \ref context.h, \ref stream.h, \ref introspect.h, \ref subscribe.h, + * \ref scache.h, \ref version.h, \ref error.h, \ref channelmap.h, + * \ref operation.h,\ref volume.h, \ref xmalloc.h, \ref utf8.h, \ref + * thread-mainloop.h, \ref mainloop.h, \ref util.h, \ref timeval.h and + * \ref mainloop-signal.h at once */ + +/** \mainpage + * + * \section intro_sec Introduction + * + * This document describes the client API for the pulseaudio sound + * server. The API comes in two flavours to accomodate different styles + * of applications and different needs in complexity: + * + * \li The complete but somewhat complicated to use asynchronous API + * \li The simplified, easy to use, but limited synchronous API + * + * All strings in Polypaudio are in the UTF-8 encoding, regardless of current + * locale. Some functions will filter invalid sequences from the string, some + * will simply fail. To ensure reliable behaviour, make sure everything you + * pass to the API is already in UTF-8. + + * \section simple_sec Simple API + * + * Use this if you develop your program in synchronous style and just + * need a way to play or record data on the sound server. See + * \subpage simple for more details. + * + * \section async_sec Asynchronous API + * + * Use this if you develop your programs in asynchronous, event loop + * based style or if you want to use the advanced features of the + * pulseaudio API. A guide can be found in \subpage async. + * + * By using the built-in threaded main loop, it is possible to acheive a + * pseudo-synchronous API, which can be useful in synchronous applications + * where the simple API is insufficient. See the \ref async page for + * details. + * + * \section thread_sec Threads + * + * The pulseaudio client libraries are not designed to be used in a + * heavily threaded environment. They are however designed to be reentrant + * safe. + * + * To use a the libraries in a threaded environment, you must assure that + * all objects are only used in one thread at a time. Normally, this means + * that all objects belonging to a single context must be accessed from the + * same thread. + * + * The included main loop implementation is also not thread safe. Take care + * to make sure event lists are not manipulated when any other code is + * using the main loop. + * + * \section pkgconfig pkg-config + * + * The pulseaudio libraries provide pkg-config snippets for the different + * modules: + * + * \li pulselib - The asynchronous API and the internal main loop + * implementation. + * \li pulselib-glib12-mainloop - GLIB 1.2 main loop bindings. + * \li pulselib-glib-mainloop - GLIB 2.x main loop bindings. + * \li pulselib-simple - The simple pulseaudio API. + */ + +#endif -- cgit From 955e33db6076a6266d4decfbeb64d89a9b8d516c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 22:03:39 +0000 Subject: hide pulseadudio binary from SVN git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1035 fefdeb5f-60dc-0310-8127-8f9354f1896f --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index bc633bd1..612c2341 100644 --- a/LICENSE +++ b/LICENSE @@ -5,7 +5,7 @@ However, the server side links to the GPL-only library 'libsamplerate' which practically downgrades the license of the server part to GPL (see file GPL for details), exercising section 3 of the LGPL. -Hence you should treat the client library ('libpulse') of Polypaudio as being +Hence you should treat the client library ('libpulse') of PulseAudio as being LGPL licensed and the server part ('libpulsecore') as being GPL licensed. Since the PulseAudio daemon and the modules link to 'libpulsecore' they are of course also GPL licensed. -- cgit From 10b5e997d7a8a4e955ce49cc816fdcd36225ff6e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 22:11:49 +0000 Subject: replace a few remaining uppercase "Polypaudio" occurences with "PulseAudio" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1036 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/daemon-conf.h | 2 +- src/modules/module-esound-sink.c | 2 +- src/modules/module-x11-publish.c | 2 +- src/pulse/context.h | 2 +- src/pulse/introspect.h | 6 +++--- src/pulse/pulseaudio.h | 2 +- src/pulse/sample.h | 10 +++++----- src/pulse/stream.h | 16 ++++++++-------- src/pulse/thread-mainloop.h | 14 +++++++------- src/pulse/version.h.in | 4 ++-- src/pulse/volume.h | 8 ++++---- src/pulsecore/memblock.h | 2 +- src/pulsecore/modinfo.h | 2 +- src/utils/pacat.c | 2 +- src/utils/pacmd.c | 4 ++-- src/utils/pactl.c | 2 +- src/utils/padsp | 4 ++-- src/utils/padsp.c | 12 ++++++------ src/utils/paplay.c | 2 +- src/utils/pax11publish.c | 8 ++++---- 20 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h index dd5d7fb8..c325495c 100644 --- a/src/daemon/daemon-conf.h +++ b/src/daemon/daemon-conf.h @@ -35,7 +35,7 @@ typedef enum pa_daemon_conf_cmd { PA_CMD_CHECK } pa_daemon_conf_cmd_t; -/* A structure containing configuration data for the Polypaudio server . */ +/* A structure containing configuration data for the PulseAudio server . */ typedef struct pa_daemon_conf { pa_daemon_conf_cmd_t cmd; int daemonize, diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index 75a47b04..86ffaf78 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -211,7 +211,7 @@ static int handle_response(struct userdata *u) { *(p++) = ESD_PROTO_STREAM_PLAY; *(p++) = u->format; *(p++) = u->rate; - pa_strlcpy((char*) p, "Polypaudio Tunnel", ESD_NAME_MAX); + pa_strlcpy((char*) p, "PulseAudio Tunnel", ESD_NAME_MAX); u->write_index = 0; u->state = STATE_RUNNING; diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c index 99163035..05f0d86a 100644 --- a/src/modules/module-x11-publish.c +++ b/src/modules/module-x11-publish.c @@ -168,7 +168,7 @@ void pa__done(pa_core *c, pa_module*m) { /* Yes, here is a race condition */ if (!pa_x11_get_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_ID", t, sizeof(t)) || strcmp(t, u->id)) - pa_log_warn(__FILE__": Polypaudio information vanished from X11!"); + pa_log_warn(__FILE__": PulseAudio information vanished from X11!"); else { pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_ID"); pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_SERVER"); diff --git a/src/pulse/context.h b/src/pulse/context.h index 65d70e8b..ad8c9f3f 100644 --- a/src/pulse/context.h +++ b/src/pulse/context.h @@ -59,7 +59,7 @@ * * \li \subpage mainloop - A minimal but fast implementation based on poll(). * \li \subpage threaded_mainloop - A special version of the previous - * implementation where all of Polypaudio's + * implementation where all of PulseAudio's * internal handling runs in a separate * thread. * \li \subpage glib-mainloop - A wrapper around GLIB's main loop. Available diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h index 8fe218bc..23d736c6 100644 --- a/src/pulse/introspect.h +++ b/src/pulse/introspect.h @@ -35,7 +35,7 @@ * \section overv_sec Overview * * Sometimes it is necessary to query and modify global settings in the - * server. For this, Polypaudio has the introspection API. It can list sinks, + * server. For this, PulseAudio has the introspection API. It can list sinks, * sources, samples and other aspects of the server. It can also modify the * attributes of the server that will affect operations on a global level, * and not just the application's context. @@ -121,7 +121,7 @@ * * \subsection module_subsec Driver Modules * - * Polypaudio driver modules are identified by index and are retrieved using either + * PulseAudio driver modules are identified by index and are retrieved using either * pa_context_get_module_info() or pa_context_get_module_info_list(). The * information structure is called pa_module_info. * @@ -137,7 +137,7 @@ * * \subsection client_subsec Clients * - * Polypaudio clients are also identified by index and are retrieved using + * PulseAudio clients are also identified by index and are retrieved using * either pa_context_get_client_info() or pa_context_get_client_info_list(). * The information structure is called pa_client_info. * diff --git a/src/pulse/pulseaudio.h b/src/pulse/pulseaudio.h index 5bbd4cc5..5c526dc7 100644 --- a/src/pulse/pulseaudio.h +++ b/src/pulse/pulseaudio.h @@ -63,7 +63,7 @@ * \li The complete but somewhat complicated to use asynchronous API * \li The simplified, easy to use, but limited synchronous API * - * All strings in Polypaudio are in the UTF-8 encoding, regardless of current + * All strings in PulseAudio are in the UTF-8 encoding, regardless of current * locale. Some functions will filter invalid sequences from the string, some * will simply fail. To ensure reliable behaviour, make sure everything you * pass to the API is already in UTF-8. diff --git a/src/pulse/sample.h b/src/pulse/sample.h index 848fd16d..03965a99 100644 --- a/src/pulse/sample.h +++ b/src/pulse/sample.h @@ -32,12 +32,12 @@ * * \section overv_sec Overview * - * Polypaudio is capable of handling a multitude of sample formats, rates + * PulseAudio is capable of handling a multitude of sample formats, rates * and channels, transparently converting and mixing them as needed. * * \section format_sec Sample Format * - * Polypaudio supports the following sample formats: + * PulseAudio supports the following sample formats: * * \li PA_SAMPLE_U8 - Unsigned 8 bit PCM. * \li PA_SAMPLE_S16LE - Signed 16 bit PCM, little endian. @@ -54,20 +54,20 @@ * * \section rate_sec Sample Rates * - * Polypaudio supports any sample rate between 1 Hz and 4 GHz. There is no + * PulseAudio supports any sample rate between 1 Hz and 4 GHz. There is no * point trying to exceed the sample rate of the output device though as the * signal will only get downsampled, consuming CPU on the machine running the * server. * * \section chan_sec Channels * - * Polypaudio supports up to 16 individiual channels. The order of the + * PulseAudio supports up to 16 individiual channels. The order of the * channels is up to the application, but they must be continous. To map * channels to speakers, see \ref channelmap. * * \section calc_sec Calculations * - * The Polypaudio library contains a number of convenience functions to do + * The PulseAudio library contains a number of convenience functions to do * calculations on sample formats: * * \li pa_bytes_per_second() - The number of bytes one second of audio will diff --git a/src/pulse/stream.h b/src/pulse/stream.h index d117ce4a..ad15125a 100644 --- a/src/pulse/stream.h +++ b/src/pulse/stream.h @@ -107,7 +107,7 @@ * wrap. The current read/write index may be queried using * pa_stream_get_timing_info() (see below for more information). In * case of a buffer underrun the read index is equal or larger than - * the write index. Unless the prebuf value is 0, Polypaudio will + * the write index. Unless the prebuf value is 0, PulseAudio will * temporarily pause playback in such a case, and wait until the * buffer is filled up to prebuf bytes again. If prebuf is 0, the * read index may be larger than the write index, in which case @@ -169,7 +169,7 @@ * \section latency_sec Latency * * A major problem with networked audio is the increased latency caused by - * the network. To remedy this, Polypaudio supports an advanced system of + * the network. To remedy this, PulseAudio supports an advanced system of * monitoring the current latency. * * To get the raw data needed to calculate latencies, call @@ -183,14 +183,14 @@ * pa_stream_update_timing_info() operation is executed. (i.e. before * the first call to this function the timing information structure is * not available!) Since it is a lot of work to keep this structure - * up-to-date manually, Polypaudio can do that automatically for you: + * up-to-date manually, PulseAudio can do that automatically for you: * if PA_STREAM_AUTO_TIMING_UPDATE is passed when connecting the - * stream Polypaudio will automatically update the structure every + * stream PulseAudio will automatically update the structure every * 100ms and every time a function is called that might invalidate the * previously known timing data (such as pa_stream_write() or * pa_stream_flush()). Please note however, that there always is a * short time window when the data in the timing information structure - * is out-of-date. Polypaudio tries to mark these situations by + * is out-of-date. PulseAudio tries to mark these situations by * setting the write_index_corrupt and read_index_corrupt fields * accordingly. * @@ -208,7 +208,7 @@ * * Since updating the timing info structure usually requires a full * network round trip and some applications monitor the timing very - * often Polypaudio offers a timing interpolation system. If + * often PulseAudio offers a timing interpolation system. If * PA_STREAM_INTERPOLATE_TIMING is passed when connecting the stream, * pa_stream_get_time() and pa_stream_get_latency() will try to * interpolate the current playback time/latency by estimating the @@ -228,7 +228,7 @@ * * \section sync_streams Sychronizing Multiple Playback Streams * - * Polypaudio allows applications to fully synchronize multiple + * PulseAudio allows applications to fully synchronize multiple * playback streams that are connected to the same output device. That * means the streams will always be played back sample-by-sample * synchronously. If stream operations like pa_stream_cork() are @@ -441,7 +441,7 @@ const pa_channel_map* pa_stream_get_channel_map(pa_stream *s); /** Return the buffer metrics of the stream. Only valid after the * stream has been connected successfuly and if the server is at least - * Polypaudio 0.9. \since 0.9.0 */ + * PulseAudio 0.9. \since 0.9.0 */ const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s); PA_C_DECL_END diff --git a/src/pulse/thread-mainloop.h b/src/pulse/thread-mainloop.h index fb216c5a..44eff5a3 100644 --- a/src/pulse/thread-mainloop.h +++ b/src/pulse/thread-mainloop.h @@ -37,7 +37,7 @@ PA_C_DECL_BEGIN * * The added feature in the threaded main loop is that it spawns a new thread * that runs the real main loop. This allows a synchronous application to use - * the asynchronous API without risking to stall the Polypaudio library. + * the asynchronous API without risking to stall the PulseAudio library. * * \section creat_sec Creation * @@ -48,7 +48,7 @@ PA_C_DECL_BEGIN * * \section destr_sec Destruction * - * When the Polypaudio connection has been terminated, the thread must be + * When the PulseAudio connection has been terminated, the thread must be * stopped and the resources freed. Stopping the thread is done using * pa_threaded_mainloop_stop(), which must be called without the lock (see * below) held. When that function returns, the thread is stopped and the @@ -56,7 +56,7 @@ PA_C_DECL_BEGIN * * \section lock_sec Locking * - * Since the Polypaudio API doesn't allow concurrent accesses to objects, + * Since the PulseAudio API doesn't allow concurrent accesses to objects, * a locking scheme must be used to guarantee safe usage. The threaded main * loop API provides such a scheme through the functions * pa_threaded_mainloop_lock() and pa_threaded_mainloop_unlock(). @@ -65,7 +65,7 @@ PA_C_DECL_BEGIN * thread. Just make sure you call pa_threaded_mainloop_unlock() the same * number of times you called pa_threaded_mainloop_lock(). * - * The lock needs to be held whenever you call any Polypaudio function that + * The lock needs to be held whenever you call any PulseAudio function that * uses an object associated with this main loop. Make sure you do not hold * on to the lock more than necessary though, as the threaded main loop stops * while the lock is held. @@ -91,12 +91,12 @@ PA_C_DECL_BEGIN * * \section cb_sec Callbacks * - * Callbacks in Polypaudio are asynchronous, so they require extra care when + * Callbacks in PulseAudio are asynchronous, so they require extra care when * using them together with a threaded main loop. * * The easiest way to turn the callback based operations into synchronous * ones, is to simply wait for the callback to be called and continue from - * there. This is the approach chosen in Polypaudio's threaded API. + * there. This is the approach chosen in PulseAudio's threaded API. * * \subsection basic_subsec Basic callbacks * @@ -216,7 +216,7 @@ PA_C_DECL_BEGIN * * \subsection async_subsec Asynchronous callbacks * - * Polypaudio also has callbacks that are completely asynchronous, meaning + * PulseAudio also has callbacks that are completely asynchronous, meaning * that they can be called at any time. The threading main loop API provides * the locking mechanism to handle concurrent accesses, but nothing else. * Applications will have to handle communication from the callback to the diff --git a/src/pulse/version.h.in b/src/pulse/version.h.in index 6c5492e8..748541a1 100644 --- a/src/pulse/version.h.in +++ b/src/pulse/version.h.in @@ -39,12 +39,12 @@ it. */ /** Return the version of the library the current application is linked to. */ const char* pa_get_library_version(void); -/** The current API version. Version 6 relates to pulseaudio +/** The current API version. Version 6 relates to Polypaudio * 0.6. Prior versions (i.e. Polypaudio 0.5.1 and older) have * PA_API_VERSION undefined. */ #define PA_API_VERSION @PA_API_VERSION@ -/** The current protocol version. Version 8 relates to pulseaudio 0.8. +/** The current protocol version. Version 8 relates to Polypaudio 0.8/PulseAudio 0.9. * \since 0.8 */ #define PA_PROTOCOL_VERSION @PA_PROTOCOL_VERSION@ diff --git a/src/pulse/volume.h b/src/pulse/volume.h index d403a09e..6c60223a 100644 --- a/src/pulse/volume.h +++ b/src/pulse/volume.h @@ -31,10 +31,10 @@ * \section overv_sec Overview * * Sinks, sources, sink inputs and samples can all have their own volumes. - * To deal with these, The Polypaudio libray contains a number of functions + * To deal with these, The PulseAudio libray contains a number of functions * that ease handling. * - * The basic volume type in Polypaudio is the \ref pa_volume_t type. Most of + * The basic volume type in PulseAudio is the \ref pa_volume_t type. Most of * the time, applications will use the aggregated pa_cvolume structure that * can store the volume of all channels at once. * @@ -43,7 +43,7 @@ * * \section calc_sec Calculations * - * The volumes in Polypaudio are logarithmic in nature and applications + * The volumes in PulseAudio are logarithmic in nature and applications * shouldn't perform calculations with them directly. Instead, they should * be converted to and from either dB or a linear scale: * @@ -64,7 +64,7 @@ * * \section conv_sec Convenience Functions * - * To handle the pa_cvolume structure, the Polypaudio library provides a + * To handle the pa_cvolume structure, the PulseAudio library provides a * number of convenienc functions: * * \li pa_cvolume_valid() - Tests if a pa_cvolume structure is valid. diff --git a/src/pulsecore/memblock.h b/src/pulsecore/memblock.h index f8545836..04a0b55b 100644 --- a/src/pulsecore/memblock.h +++ b/src/pulsecore/memblock.h @@ -25,7 +25,7 @@ #include #include -/* A pa_memblock is a reference counted memory block. Polypaudio +/* A pa_memblock is a reference counted memory block. PulseAudio * passed references to pa_memblocks around instead of copying * data. See pa_memchunk for a structure that describes parts of * memory blocks. */ diff --git a/src/pulsecore/modinfo.h b/src/pulsecore/modinfo.h index f39cee3b..90404504 100644 --- a/src/pulsecore/modinfo.h +++ b/src/pulsecore/modinfo.h @@ -22,7 +22,7 @@ USA. ***/ -/* Some functions for reading module meta data from Polypaudio modules */ +/* Some functions for reading module meta data from PulseAudio modules */ typedef struct pa_modinfo { char *author; diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 5e4596d1..10edd71d 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -38,7 +38,7 @@ #define TIME_EVENT_USEC 50000 #if PA_API_VERSION != 9 -#error Invalid Polypaudio API version +#error Invalid PulseAudio API version #endif static enum { RECORD, PLAYBACK } mode = PLAYBACK; diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c index e4a0970d..fe8038e0 100644 --- a/src/utils/pacmd.c +++ b/src/utils/pacmd.c @@ -49,7 +49,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { fd_set ifds, ofds; if (pa_pid_file_check_running(&pid) < 0) { - pa_log(__FILE__": no Polypaudio daemon running"); + pa_log(__FILE__": no PulseAudio daemon running"); goto fail; } @@ -74,7 +74,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { break; if (pa_pid_file_kill(SIGUSR2, NULL) < 0) { - pa_log(__FILE__": failed to kill Polypaudio daemon."); + pa_log(__FILE__": failed to kill PulseAudio daemon."); goto fail; } diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 6e40f3fe..94d22f98 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -38,7 +38,7 @@ #include #if PA_API_VERSION != 9 -#error Invalid Polypaudio API version +#error Invalid PulseAudio API version #endif #define BUFSIZE 1024 diff --git a/src/utils/padsp b/src/utils/padsp index 6e7e9f06..d9ebcbc5 100644 --- a/src/utils/padsp +++ b/src/utils/padsp @@ -54,13 +54,13 @@ while getopts 'hs:n:m:MSDd' param ; do export PADSP_DEBUG ;; *) - echo "$0 - redirect OSS audio devices to Polypaudio" + echo "$0 - redirect OSS audio devices to PulseAudio" echo " " echo "$0 [options] application [arguments]" echo " " echo "options:" echo " -h show brief help" - echo " -s [:] contact a specific Polypaudio server" + echo " -s [:] contact a specific PulseAudio server" echo " -n client name to report to the server" echo " -m stream name to report to the server" echo " -M disable /dev/mixer emulation" diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 13f571e1..d9dcc764 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1262,18 +1262,18 @@ fail: static int sndstat_open(int flags, int *_errno) { static const char sndstat[] = - "Sound Driver:3.8.1a-980706 (Polypaudio Virtual OSS)\n" + "Sound Driver:3.8.1a-980706 (PulseAudio Virtual OSS)\n" "Kernel: POSIX\n" "Config options: 0\n" "\n" "Installed drivers:\n" - "Type 255: Polypaudio Virtual OSS\n" + "Type 255: PulseAudio Virtual OSS\n" "\n" "Card config:\n" - "Polypaudio Virtual OSS\n" + "PulseAudio Virtual OSS\n" "\n" "Audio devices:\n" - "0: Polypaudio Virtual OSS\n" + "0: PulseAudio Virtual OSS\n" "\n" "Synth devices: NOT ENABLED IN CONFIG\n" "\n" @@ -1282,7 +1282,7 @@ static int sndstat_open(int flags, int *_errno) { "Timers:\n" "\n" "Mixers:\n" - "0: Polypaudio Virtual OSS\n"; + "0: PulseAudio Virtual OSS\n"; char fn[] = "/tmp/padsp-sndstat-XXXXXX"; mode_t u; @@ -1501,7 +1501,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno memset(mi, 0, sizeof(mixer_info)); strncpy(mi->id, "POLYPAUDIO", sizeof(mi->id)); - strncpy(mi->name, "Polypaudio Virtual OSS", sizeof(mi->name)); + strncpy(mi->name, "PulseAudio Virtual OSS", sizeof(mi->name)); pa_threaded_mainloop_lock(i->mainloop); mi->modify_counter = i->volume_modify_count; pa_threaded_mainloop_unlock(i->mainloop); diff --git a/src/utils/paplay.c b/src/utils/paplay.c index 4b4a1ea6..7b34016c 100644 --- a/src/utils/paplay.c +++ b/src/utils/paplay.c @@ -38,7 +38,7 @@ #include #if PA_API_VERSION != 9 -#error Invalid Polypaudio API version +#error Invalid PulseAudio API version #endif static pa_context *context = NULL; diff --git a/src/utils/pax11publish.c b/src/utils/pax11publish.c index 770455b9..d2ed6c93 100644 --- a/src/utils/pax11publish.c +++ b/src/utils/pax11publish.c @@ -54,10 +54,10 @@ int main(int argc, char *argv[]) { break; case 'h': printf("%s [-D display] [-S server] [-O sink] [-I source] [-c file] [-d|-e|-i|-r]\n\n" - " -d Show current Polypaudio data attached to X11 display (default)\n" - " -e Export local Polypaudio data to X11 display\n" - " -i Import Polypaudio data from X11 display to local environment variables and cookie file.\n" - " -r Remove Polypaudio data from X11 display\n", + " -d Show current PulseAudio data attached to X11 display (default)\n" + " -e Export local PulseAudio data to X11 display\n" + " -i Import PulseAudio data from X11 display to local environment variables and cookie file.\n" + " -r Remove PulseAudio data from X11 display\n", pa_path_get_filename(argv[0])); ret = 0; goto finish; -- cgit From 0d97ac6d2b8616073a3b047bfe22416a452950a5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 23:00:21 +0000 Subject: name the pkg-config files after the library names git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1037 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 4 ++-- configure.ac | 4 ++-- libpulse-glib-mainloop.pc.in | 11 ----------- libpulse-glib12-mainloop.pc.in | 11 ----------- libpulse-mainloop-glib.pc.in | 11 +++++++++++ libpulse-mainloop-glib12.pc.in | 11 +++++++++++ src/pulse/pulseaudio.h | 19 +++++++++---------- 7 files changed, 35 insertions(+), 36 deletions(-) delete mode 100644 libpulse-glib-mainloop.pc.in delete mode 100644 libpulse-glib12-mainloop.pc.in create mode 100644 libpulse-mainloop-glib.pc.in create mode 100644 libpulse-mainloop-glib12.pc.in diff --git a/Makefile.am b/Makefile.am index 4174a39b..8a0eaf49 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,12 +33,12 @@ endif if HAVE_GLIB20 pkgconfig_DATA += \ - libpulse-glib-mainloop.pc + libpulse-mainloop-glib.pc endif if HAVE_GLIB12 pkgconfig_DATA += \ - libpulse-glib12-mainloop.pc + libpulse-mainloop-glib12.pc endif if USE_LYNX diff --git a/configure.ac b/configure.ac index 4f530347..bb72ee37 100644 --- a/configure.ac +++ b/configure.ac @@ -698,8 +698,8 @@ src/Makefile libpulse.pc libpulse-simple.pc libpulse-browse.pc -libpulse-glib-mainloop.pc -libpulse-glib12-mainloop.pc +libpulse-mainloop-glib.pc +libpulse-mainloop-glib12.pc doc/Makefile doc/README.html doc/cli.html diff --git a/libpulse-glib-mainloop.pc.in b/libpulse-glib-mainloop.pc.in deleted file mode 100644 index 169910ba..00000000 --- a/libpulse-glib-mainloop.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: libpulse-glib-mainloop -Description: GLIB 2.0 Main Loop Wrapper for PulseAudio -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpulse-mainloop-glib -Cflags: -D_REENTRANT -I${includedir} -Requires: libpulse glib-2.0 diff --git a/libpulse-glib12-mainloop.pc.in b/libpulse-glib12-mainloop.pc.in deleted file mode 100644 index f525c370..00000000 --- a/libpulse-glib12-mainloop.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: libpulse-glib12-mainloop -Description: GLIB 1.2 Main Loop Wrapper for PulseAudio -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpulse-mainloop-glib12 -Cflags: -D_REENTRANT -I${includedir} -Requires: libpulse glib diff --git a/libpulse-mainloop-glib.pc.in b/libpulse-mainloop-glib.pc.in new file mode 100644 index 00000000..a9a51cf7 --- /dev/null +++ b/libpulse-mainloop-glib.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libpulse-mainloop-glib +Description: GLIB 2.0 Main Loop Wrapper for PulseAudio +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lpulse-mainloop-glib +Cflags: -D_REENTRANT -I${includedir} +Requires: libpulse glib-2.0 diff --git a/libpulse-mainloop-glib12.pc.in b/libpulse-mainloop-glib12.pc.in new file mode 100644 index 00000000..7a038826 --- /dev/null +++ b/libpulse-mainloop-glib12.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libpulse-mainloop-glib12 +Description: GLIB 1.2 Main Loop Wrapper for PulseAudio +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lpulse-mainloop-glib12 +Cflags: -D_REENTRANT -I${includedir} +Requires: libpulse glib diff --git a/src/pulse/pulseaudio.h b/src/pulse/pulseaudio.h index 5c526dc7..71262eaa 100644 --- a/src/pulse/pulseaudio.h +++ b/src/pulse/pulseaudio.h @@ -44,7 +44,7 @@ #include /** \file - * Include all pulselib header files at once. The following + * Include all libpulse header files at once. The following * files are included: \ref mainloop-api.h, \ref sample.h, \ref def.h, * \ref context.h, \ref stream.h, \ref introspect.h, \ref subscribe.h, * \ref scache.h, \ref version.h, \ref error.h, \ref channelmap.h, @@ -56,7 +56,7 @@ * * \section intro_sec Introduction * - * This document describes the client API for the pulseaudio sound + * This document describes the client API for the PulseAudio sound * server. The API comes in two flavours to accomodate different styles * of applications and different needs in complexity: * @@ -78,7 +78,7 @@ * * Use this if you develop your programs in asynchronous, event loop * based style or if you want to use the advanced features of the - * pulseaudio API. A guide can be found in \subpage async. + * PulseAudio API. A guide can be found in \subpage async. * * By using the built-in threaded main loop, it is possible to acheive a * pseudo-synchronous API, which can be useful in synchronous applications @@ -87,7 +87,7 @@ * * \section thread_sec Threads * - * The pulseaudio client libraries are not designed to be used in a + * The PulseAudio client libraries are not designed to be used in a * heavily threaded environment. They are however designed to be reentrant * safe. * @@ -102,14 +102,13 @@ * * \section pkgconfig pkg-config * - * The pulseaudio libraries provide pkg-config snippets for the different + * The PulseAudio libraries provide pkg-config snippets for the different * modules: * - * \li pulselib - The asynchronous API and the internal main loop - * implementation. - * \li pulselib-glib12-mainloop - GLIB 1.2 main loop bindings. - * \li pulselib-glib-mainloop - GLIB 2.x main loop bindings. - * \li pulselib-simple - The simple pulseaudio API. + * \li pulselib - The asynchronous API and the internal main loop implementation. + * \li pulselib-mainloop-glib12 - GLIB 1.2 main loop bindings. + * \li pulselib-mainloop-glib - GLIB 2.x main loop bindings. + * \li pulselib-simple - The simple PulseAudio API. */ #endif -- cgit From fe1dadbadd9f694d533dc2191451d2a020d99c2f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 23:06:50 +0000 Subject: update references to the pkg-config files in the docs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1038 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/pulseaudio.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pulse/pulseaudio.h b/src/pulse/pulseaudio.h index 71262eaa..88cc326b 100644 --- a/src/pulse/pulseaudio.h +++ b/src/pulse/pulseaudio.h @@ -105,10 +105,10 @@ * The PulseAudio libraries provide pkg-config snippets for the different * modules: * - * \li pulselib - The asynchronous API and the internal main loop implementation. - * \li pulselib-mainloop-glib12 - GLIB 1.2 main loop bindings. - * \li pulselib-mainloop-glib - GLIB 2.x main loop bindings. - * \li pulselib-simple - The simple PulseAudio API. + * \li libpulse - The asynchronous API and the internal main loop implementation. + * \li libpulse-mainloop-glib12 - GLIB 1.2 main loop bindings. + * \li libpulse-mainloop-glib - GLIB 2.x main loop bindings. + * \li libpulse-simple - The simple PulseAudio API. */ #endif -- cgit From 3cf16214334b4a1c51e56b0536abd8223d6813dd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 23:51:58 +0000 Subject: * more s/pulseaudio/PulseAudio/ replacements * name the per-user dir ~/.pulse (instead of .pulseaudio), just like /etc/pulse/ git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1039 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/daemon-conf.c | 6 +++--- src/modules/module-jack-sink.c | 2 +- src/modules/module-jack-source.c | 2 +- src/modules/module-match.c | 4 ++-- src/modules/module-volume-restore.c | 2 +- src/modules/module-zeroconf-publish.c | 6 +++--- src/pulse/browser.c | 6 +++--- src/pulse/client-conf.c | 4 ++-- src/pulse/client-conf.h | 2 +- src/pulse/context.h | 12 ++++++------ src/pulse/def.h | 2 +- src/pulse/introspect.h | 2 +- src/pulse/mainloop-api.h | 8 ++++---- src/pulsecore/cli.c | 2 +- src/pulsecore/core-error.c | 2 +- src/pulsecore/core-util.c | 6 +++--- src/pulsecore/core.h | 4 ++-- src/pulsecore/native-common.h | 2 +- 18 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index fd83f28f..4d458a5c 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -41,7 +41,7 @@ #ifndef DEFAULT_CONFIG_DIR # ifndef OS_IS_WIN32 -# define DEFAULT_CONFIG_DIR "/etc/pulseaudio" +# define DEFAULT_CONFIG_DIR "/etc/pulse" # else # define DEFAULT_CONFIG_DIR "%POLYP_ROOT%" # endif @@ -54,9 +54,9 @@ #endif #define DEFAULT_SCRIPT_FILE DEFAULT_CONFIG_DIR PATH_SEP "default.pa" -#define DEFAULT_SCRIPT_FILE_USER ".pulseaudio" PATH_SEP "default.pa" +#define DEFAULT_SCRIPT_FILE_USER ".pulse" PATH_SEP "default.pa" #define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "daemon.conf" -#define DEFAULT_CONFIG_FILE_USER ".pulseaudio" PATH_SEP "daemon.conf" +#define DEFAULT_CONFIG_FILE_USER ".pulse" PATH_SEP "daemon.conf" #define ENV_SCRIPT_FILE "POLYP_SCRIPT" #define ENV_CONFIG_FILE "POLYP_CONFIG" diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index c6a161ff..74f25d53 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -261,7 +261,7 @@ int pa__init(pa_core *c, pa_module*m) { } server_name = pa_modargs_get_value(ma, "server_name", NULL); - client_name = pa_modargs_get_value(ma, "client_name", "pulseaudio"); + client_name = pa_modargs_get_value(ma, "client_name", "PulseAudio"); u = pa_xnew0(struct userdata, 1); m->userdata = u; diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index 6f31f6c3..9c7f449f 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -259,7 +259,7 @@ int pa__init(pa_core *c, pa_module*m) { } server_name = pa_modargs_get_value(ma, "server_name", NULL); - client_name = pa_modargs_get_value(ma, "client_name", "pulseaudio"); + client_name = pa_modargs_get_value(ma, "client_name", "PulseAudio"); u = pa_xnew0(struct userdata, 1); m->userdata = u; diff --git a/src/modules/module-match.c b/src/modules/module-match.c index ddeda734..28d6a08b 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -53,11 +53,11 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define WHITESPACE "\n\r \t" #ifndef DEFAULT_CONFIG_DIR -#define DEFAULT_CONFIG_DIR "/etc/pulseaudio" +#define DEFAULT_CONFIG_DIR "/etc/pulse" #endif #define DEFAULT_MATCH_TABLE_FILE DEFAULT_CONFIG_DIR"/match.table" -#define DEFAULT_MATCH_TABLE_FILE_USER ".pulseaudio/match.table" +#define DEFAULT_MATCH_TABLE_FILE_USER ".pulse/match.table" static const char* const valid_modargs[] = { "table", diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index ede2fcf2..2f45082b 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -53,7 +53,7 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define WHITESPACE "\n\r \t" -#define DEFAULT_VOLUME_TABLE_FILE ".pulseaudio/volume.table" +#define DEFAULT_VOLUME_TABLE_FILE ".pulse/volume.table" static const char* const valid_modargs[] = { "table", diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index 14cbef46..32fb1f41 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -53,9 +53,9 @@ PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Publisher") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("port=") -#define SERVICE_NAME_SINK "_pulseaudio-sink._tcp" -#define SERVICE_NAME_SOURCE "_pulseaudio-source._tcp" -#define SERVICE_NAME_SERVER "_pulseaudio-server._tcp" +#define SERVICE_NAME_SINK "_pulse-sink._tcp" +#define SERVICE_NAME_SOURCE "_pulse-source._tcp" +#define SERVICE_NAME_SERVER "_pulse-server._tcp" static const char* const valid_modargs[] = { "port", diff --git a/src/pulse/browser.c b/src/pulse/browser.c index d063465d..96625869 100644 --- a/src/pulse/browser.c +++ b/src/pulse/browser.c @@ -29,9 +29,9 @@ #include "browser.h" -#define SERVICE_NAME_SINK "_pulseaudio-sink._tcp." -#define SERVICE_NAME_SOURCE "_pulseaudio-source._tcp." -#define SERVICE_NAME_SERVER "_pulseaudio-server._tcp." +#define SERVICE_NAME_SINK "_pulse-sink._tcp." +#define SERVICE_NAME_SOURCE "_pulse-source._tcp." +#define SERVICE_NAME_SERVER "_pulse-server._tcp." struct pa_browser { int ref; diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c index 752d0134..9f5cf53d 100644 --- a/src/pulse/client-conf.c +++ b/src/pulse/client-conf.c @@ -41,7 +41,7 @@ #ifndef DEFAULT_CONFIG_DIR # ifndef OS_IS_WIN32 -# define DEFAULT_CONFIG_DIR "/etc/pulseaudio" +# define DEFAULT_CONFIG_DIR "/etc/pulse" # else # define DEFAULT_CONFIG_DIR "%POLYP_ROOT%" # endif @@ -54,7 +54,7 @@ #endif #define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "client.conf" -#define DEFAULT_CLIENT_CONFIG_FILE_USER ".pulseaudio" PATH_SEP "client.conf" +#define DEFAULT_CLIENT_CONFIG_FILE_USER ".pulse" PATH_SEP "client.conf" #define ENV_CLIENT_CONFIG_FILE "POLYP_CLIENTCONFIG" #define ENV_DEFAULT_SINK "POLYP_SINK" diff --git a/src/pulse/client-conf.h b/src/pulse/client-conf.h index 9d45af47..a532f0df 100644 --- a/src/pulse/client-conf.h +++ b/src/pulse/client-conf.h @@ -24,7 +24,7 @@ #include -/* A structure containing configuration data for pulseaudio clients. */ +/* A structure containing configuration data for PulseAudio clients. */ typedef struct pa_client_conf { char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server, *cookie_file; diff --git a/src/pulse/context.h b/src/pulse/context.h index ad8c9f3f..661ff617 100644 --- a/src/pulse/context.h +++ b/src/pulse/context.h @@ -32,7 +32,7 @@ * * \section overv_sec Overview * - * The asynchronous API is the native interface to the pulseaudio library. + * The asynchronous API is the native interface to the PulseAudio library. * It allows full access to all available functions. This also means that * it is rather complex and can take some time to fully master. * @@ -52,10 +52,10 @@ * * To actually be able to use these functions, an implementation needs to * be coupled to the abstraction. There are three of these shipped with - * pulseaudio, but any other can be used with a minimal ammount of work, + * PulseAudio, but any other can be used with a minimal ammount of work, * provided it supports the three basic events listed above. * - * The implementations shipped with pulseaudio are: + * The implementations shipped with PulseAudio are: * * \li \subpage mainloop - A minimal but fast implementation based on poll(). * \li \subpage threaded_mainloop - A special version of the previous @@ -71,7 +71,7 @@ * * \section refcnt_sec Reference Counting * - * Almost all objects in pulseaudio are reference counted. What that means + * Almost all objects in PulseAudio are reference counted. What that means * is that you rarely malloc() or free() any objects. Instead you increase * and decrease their reference counts. Whenever an object's reference * count reaches zero, that object gets destroy and any resources it uses @@ -89,7 +89,7 @@ * * \section context_sec Context * - * A context is the basic object for a connection to a pulseaudio server. + * A context is the basic object for a connection to a PulseAudio server. * It multiplexes commands, data streams and events through a single * channel. * @@ -142,7 +142,7 @@ /** \file * Connection contexts for asynchrononous communication with a - * server. A pa_context object wraps a connection to a pulseaudio + * server. A pa_context object wraps a connection to a PulseAudio * server using its native protocol. */ /** \example pacat.c diff --git a/src/pulse/def.h b/src/pulse/def.h index 3a17f43b..b98337d2 100644 --- a/src/pulse/def.h +++ b/src/pulse/def.h @@ -66,7 +66,7 @@ typedef enum pa_operation_state { /** Some special flags for contexts. \since 0.8 */ typedef enum pa_context_flags { - PA_CONTEXT_NOAUTOSPAWN = 1 /**< Disabled autospawning of the pulseaudio daemon if required */ + PA_CONTEXT_NOAUTOSPAWN = 1 /**< Disabled autospawning of the PulseAudio daemon if required */ } pa_context_flags_t; /** The direction of a pa_stream object */ diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h index 23d736c6..e9a14490 100644 --- a/src/pulse/introspect.h +++ b/src/pulse/introspect.h @@ -270,7 +270,7 @@ typedef struct pa_server_info { pa_sample_spec sample_spec; /**< Default sample specification */ const char *default_sink_name; /**< Name of default sink. \since 0.4 */ const char *default_source_name; /**< Name of default sink. \since 0.4*/ - uint32_t cookie; /**< A random cookie for identifying this instance of pulseaudio. \since 0.8 */ + uint32_t cookie; /**< A random cookie for identifying this instance of PulseAudio. \since 0.8 */ } pa_server_info; /** Callback prototype for pa_context_get_server_info() */ diff --git a/src/pulse/mainloop-api.h b/src/pulse/mainloop-api.h index a732b215..4aaeccf5 100644 --- a/src/pulse/mainloop-api.h +++ b/src/pulse/mainloop-api.h @@ -29,13 +29,13 @@ /** \file * - * Main loop abstraction layer. Both the pulseaudio core and the - * pulseaudio client library use a main loop abstraction layer. Due to - * this it is possible to embed pulseaudio into other + * Main loop abstraction layer. Both the PulseAudio core and the + * PulseAudio client library use a main loop abstraction layer. Due to + * this it is possible to embed PulseAudio into other * applications easily. Two main loop implemenations are * currently available: * \li A minimal implementation based on the C library's poll() function (See \ref mainloop.h) - * \li A wrapper around the GLIB main loop. Use this to embed pulseaudio into your GLIB/GTK+/GNOME programs (See \ref glib-mainloop.h) + * \li A wrapper around the GLIB main loop. Use this to embed PulseAudio into your GLIB/GTK+/GNOME programs (See \ref glib-mainloop.h) * * The structure pa_mainloop_api is used as vtable for the main loop abstraction. * diff --git a/src/pulsecore/cli.c b/src/pulsecore/cli.c index fbfa5009..7c284066 100644 --- a/src/pulsecore/cli.c +++ b/src/pulsecore/cli.c @@ -84,7 +84,7 @@ pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m) { c->client->owner = m; pa_ioline_set_callback(c->line, line_callback, c); - pa_ioline_puts(c->line, "Welcome to pulseaudio! Use \"help\" for usage information.\n"PROMPT); + pa_ioline_puts(c->line, "Welcome to PulseAudio! Use \"help\" for usage information.\n"PROMPT); c->fail = c->kill_requested = c->defer_kill = 0; diff --git a/src/pulsecore/core-error.c b/src/pulsecore/core-error.c index e42070d1..61878c9e 100644 --- a/src/pulsecore/core-error.c +++ b/src/pulsecore/core-error.c @@ -68,7 +68,7 @@ static void inittls(void) { HANDLE mutex; char name[64]; - sprintf(name, "pulseaudio%d", (int)GetCurrentProcessId()); + sprintf(name, "pulse%d", (int)GetCurrentProcessId()); mutex = CreateMutex(NULL, FALSE, name); if (!mutex) { diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 8e3587eb..d4b140de 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -79,10 +79,10 @@ #include "core-util.h" #ifndef OS_IS_WIN32 -#define PA_RUNTIME_PATH_PREFIX "/tmp/pulseaudio-" +#define PA_RUNTIME_PATH_PREFIX "/tmp/pulse-" #define PATH_SEP '/' #else -#define PA_RUNTIME_PATH_PREFIX "%TEMP%\\pulseaudio-" +#define PA_RUNTIME_PATH_PREFIX "%TEMP%\\pulse-" #define PATH_SEP '\\' #endif @@ -961,7 +961,7 @@ int pa_endswith(const char *s, const char *sfx) { return l1 >= l2 && strcmp(s+l1-l2, sfx) == 0; } -/* if fn is null return the pulseaudio run time path in s (/tmp/pulseaudio) +/* if fn is null return the PulseAudio run time path in s (/tmp/pulse) * if fn is non-null and starts with / return fn in s * otherwise append fn to the run time path and return it in s */ char *pa_runtime_path(const char *fn, char *s, size_t l) { diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index 627d4239..261c5f75 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -33,13 +33,13 @@ typedef struct pa_core pa_core; #include #include -/* The core structure of pulseaudio. Every pulseaudio daemon contains +/* The core structure of PulseAudio. Every PulseAudio daemon contains * exactly one of these. It is used for storing kind of global * variables for the daemon. */ struct pa_core { /* A random value which may be used to identify this instance of - * pulseaudio. Not cryptographically secure in any way. */ + * PulseAudio. Not cryptographically secure in any way. */ uint32_t cookie; pa_mainloop_api *mainloop; diff --git a/src/pulsecore/native-common.h b/src/pulsecore/native-common.h index b35931d0..5fdb6f42 100644 --- a/src/pulsecore/native-common.h +++ b/src/pulsecore/native-common.h @@ -112,7 +112,7 @@ enum { }; #define PA_NATIVE_COOKIE_LENGTH 256 -#define PA_NATIVE_COOKIE_FILE ".pulseaudio-cookie" +#define PA_NATIVE_COOKIE_FILE ".pulse-cookie" #define PA_NATIVE_DEFAULT_PORT 4713 -- cgit From 6654e987c17bc1026944248cfb01876311807bd7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 23:52:16 +0000 Subject: update docs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1040 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/FAQ.html.in | 110 +++++++++++++++++++++++++++------------------------- doc/README.html.in | 108 ++++++++++++++++++++++++++------------------------- doc/cli.html.in | 8 ++-- doc/daemon.html.in | 8 ++-- doc/modules.html.in | 26 ++++++------- 5 files changed, 133 insertions(+), 127 deletions(-) diff --git a/doc/FAQ.html.in b/doc/FAQ.html.in index d9550e95..6b83cf77 100644 --- a/doc/FAQ.html.in +++ b/doc/FAQ.html.in @@ -2,7 +2,7 @@ -pulseaudio: FAQ +PulseAudio: FAQ @@ -12,39 +12,39 @@

      Frequently Asked Questions

        -
      1. How does Polypaudio compare with ESOUND/aRts/NAS?

        +
      2. How does PulseAudio compare with ESOUND/aRts/NAS?

        -

        Polypaudio is sound daemon similar to ESOUND and NAS, but much more +

        PulseAudio is sound daemon similar to ESOUND and NAS, but much more powerful. aRts is a realtime-synthesizer-cum-sound-server, i.e. it - does much more than Polypaudio. However, I believe that Polypaudio + does much more than PulseAudio. However, I believe that PulseAudio does what it does much better than any other free sound server.

      3. What about ESOUND compatibility?

        -

        Polypaudio is a drop in replacement for ESOUND. That means: you can +

        PulseAudio is a drop in replacement for ESOUND. That means: you can load a esound compatibility module which implements an ESOUND compatible protocol which allows you to use most of the classic ESOUND compatible programs (including the command line programs like esdcat).

      4. -
      5. Is Polypaudio a GNOME program?

        -

        No, Polypaudio has no dependency on GNOME/GTK/GLIB. All it requires +

      6. Is PulseAudio a GNOME program?

        +

        No, PulseAudio has no dependency on GNOME/GTK/GLIB. All it requires is a UNIX-like operating system and very few dependency - libraries. However, the accompanying GUI tools are writen with + libraries. However, the accompanying GUI tools are written with gtkmm, i.e. require both GLIB and GTK.

      7. -
      8. Can I integrate Polypaudio in my GLIB/GTK/GNOME application?

        -

        Yes! Polypaudio comes with a GLIB main loop adapter. You can embed +

      9. Can I integrate PulseAudio in my GLIB/GTK/GNOME application?

        +

        Yes! PulseAudio comes with a GLIB main loop adapter. You can embed both the client library and the daemon (!) into your GLIB based application.

      10. -
      11. Can I integrate Polypaudio in my Qt/KDE application?

        -

        Yes! Polypaudio uses a main loop abstraction layer that allows you - to integrate Polypaudio in any program that supports main +

      12. Can I integrate PulseAudio in my Qt/KDE application?

        +

        Yes! PulseAudio uses a main loop abstraction layer that allows you + to integrate PulseAudio in any program that supports main loops. Unfortunately there is no adapter for Qt publicly available yet.

      13. -
      14. I want to write a new driver for Polypaudio, are there any docs?

        +
      15. I want to write a new driver for PulseAudio, are there any docs?

        Currently, only the client API is documented with doxygen. Read the source and base your work on a simple module like module-pipe-sink.

      16. @@ -54,67 +54,67 @@
      17. What about compatibility with aRts?

        Is not available. Since aRts is as synthesizer application you'd have to - reimplement very much code for Polypaudio. It should be easy to + reimplement very much code for PulseAudio. It should be easy to implement limited support for libartsc based applications. Noone has done this yet. It is probably a better idea to - run arts on top of Polypaudio (through a pulseaudio driver + run arts on top of PulseAudio (through a PulseAudio driver for aRts, which nobody has written yet). Another solution would be to - embed Polypaudio in the aRts process.

      18. + embed PulseAudio in the aRts process.

        -
      19. I often hear noises when playing back with Polypaudio, what can I do?

        -

        There are to possible solutions: run pulseaudio with argument +

      20. I often hear noises when playing back with PulseAudio, what can I do?

        +

        There are to possible solutions: run PulseAudio with argument --high-priority=1 and make yourself member of the group realtime, or increase the fragment sizes of the audio - drivers. The former will allow Polypaudio to activate + drivers. The former will allow PulseAudio to activate SCHED_FIFO high priority scheduling (root rights are dropped immediately after this). Keep in mind that this is a potential security hole!

      21. The pulseaudio executable is installed SUID root by default. Why this? Isn't this a potential security hole?

        -

        Polypaudio activates SCHED_FIFO scheduling if the user +

        PulseAudio activates SCHED_FIFO scheduling if the user passes --high-priority=1. This will only succeed when executed as root, therefore the binary is marked SUID root by -default. Yes, this is a potential security hole. However, pulseaudio +default. Yes, this is a potential security hole. However, PulseAudio tries its best to minimize the security threat: immediately after -startup pulseaudio drops all capabilities except +startup PulseAudio drops all capabilities except CAP_SYS_NICE (At least on systems that support it, like Linux; see man 7 capabilities for more information). If the calling user is not a member of the group realtime (which is required to have a GID < 1000), root rights are dropped immediately. This means, you can -install pulseaudio SUID root, but only a subset of your users (the +install pulseaudio SUID root, but only a subset of your users (the members of the group realtime) may make use of realtime scheduling. Keep in mind that these users might load their own binary -modules into the pulseaudio daemon which may freeze the machine. The +modules into the PulseAudio daemon which may freeze the machine. The daemon has a minimal protection against CPU hogging (the daemon is killed after hogging more than 70% CPU for 5 seconds), but this may be circumvented easily by evildoers.

      22. -
      23. I want to run pulseaudio only when it is needed, how do I do this?

        +
      24. I want to run PulseAudio only when it is needed, how do I do this?

        Set autospawn = yes in client.conf. That -configuration file may be found either in /etc/pulseaudio/ or -in ~/.pulseaudio/.

      25. +configuration file may be found either in /etc/pulse/ or +in ~/.pulse/.

        -
      26. How do I list all pulseaudio modules installed?

        +
      27. How do I list all PulseAudio modules installed?

        pulseaudio --dump-modules

        Add -v for terse usage instructions.

        -
      28. How do I use pulseaudio over the network?

        +
      29. How do I use PulseAudio over the network?

        -

        Just set $POLYP_SERVER to the host name of the pulseaudio +

        Just set $POLYP_SERVER to the host name of the PulseAudio server. For authentication you need the same auth cookies on all sides. For -that copy ~./pulseaudio-cookie to all clients that shall +that copy ~./pulse-cookie to all clients that shall be allowed to connect.

        Alternatively the authorization cookies can be stored in the X11 server.

      30. -
      31. Is pulseaudio capable of providing synchronized audio playback over the network for movie players like mplayer?

        +
      32. Is PulseAudio capable of providing synchronized audio playback over the network for movie players like mplayer?

        Yes! Unless your network is congested in some way (i.e. transfer latencies vary strongly) it works perfectly. Drop me an email for experimental patches for MPlayer.

        -
      33. What environment variables does pulseaudio care about?

        +
      34. What environment variables does PulseAudio care about?

        The client honors: POLYP_SINK (default sink to connect to), POLYP_SOURCE (default source to connect to), POLYP_SERVER (default server to connect to, like ESPEAKER), POLYP_BINARY (the binary to start when autospawning a daemon), POLYP_CLIENTCONFIG (path to the client configuration file).

        @@ -126,36 +126,36 @@ be allowed to connect.

        A brilliant guy named Lennart Poettering once wrote a nifty tool for that purpose: bidilink. To -connect to a running pulseaudio daemon try using the following commands:

        +connect to a running PulseAudio daemon try using the following commands:

        killall -USR2 pulseaudio
        -bidilink unix-client:/tmp/pulseaudio/cli
        +bidilink unix-client:/tmp/pulse-$USER/cli

      BTW: Someone should package this great tool for Debian!

      New: There's now a tool pacmd that automates sending SIGUSR2 to the daemon and running a bidilink like tool for you.

      -
    • How do the pulseaudio libraries decide where to connect to?

      +
    • How do the PulseAudio libraries decide where to connect to?

      The following rule applies:

      1. If the the application using the library specifies a server to connect to it is used. If the connection fails, the library fails too.
      2. If the environment variable POLYP_SERVER is defined the library connects to that server. If the connection fails, the library fails too.
      3. If $DISPLAY is set, the library tries to connect to that server and looks for the root window property POYLP_SERVER for the host to connect to. If POLYP_COOKIE is set it is used as authentication cookie.
      4. -
      5. If the client configuration file (~/.pulseaudio/client.conf or /etc/pulseaudio/client.conf) sets the server address, the library connects to that server. If the connection fails, the library fails too.
      6. -
      7. The library tries to connect to the default local UNIX socket for pulseaudio servers. If the connection fails, it proceeds with the next item.
      8. -
      9. The library tries to connect to the default local TCP socket for pulseaudio servers. If the connection fails, it proceeds with the next item.
      10. +
      11. If the client configuration file (~/.pulse/client.conf or /etc/pulse/client.conf) sets the server address, the library connects to that server. If the connection fails, the library fails too.
      12. +
      13. The library tries to connect to the default local UNIX socket for PulseAudio servers. If the connection fails, it proceeds with the next item.
      14. +
      15. The library tries to connect to the default local TCP socket for PulseAudio servers. If the connection fails, it proceeds with the next item.
      16. If $DISPLAY is set, the library tries to connect to the default TCP port of that host. If the connection fails, it proceeds with the next item.
      17. The connection fails.
    • Why the heck does libpulse link against libX11?

      -

      The Polypaudio client libraries look for some X11 root window -properties for the credentials of the Polypaudio server to access. You -may compile Polypaudio without X11 for disabling this feature.

    • +

      The PulseAudio client libraries look for some X11 root window +properties for the credentials of the PulseAudio server to access. You +may compile PulseAudio without X11 for disabling this feature.

      -
    • How can I use Polypaudio as an RTP based N:N multicast +

    • How can I use PulseAudio as an RTP based N:N multicast conferencing solution for the LAN?

      After loading all the necessary audio drivers for recording and playback, just load the RTP reciever and sender modules with default parameters:

      @@ -165,7 +165,7 @@ load-module module-rtp-send load-module module-rtp-recv
    • -

      As long as the Polypaudio daemon runs, the microphone data will be +

      As long as the PulseAudio daemon runs, the microphone data will be streamed to the network and the data from other hosts is played back locally. Please note that this may cause quite a lot of traffic. Hence consider passing rate=8000 format=ulaw channels=1 to the @@ -182,11 +182,11 @@ announce RTP sessions that are described with SDP. (Modern SIP based VoIP phones

      All three protocols are defined in IETF RFCs (RFC3550, RFC3551, RFC2327, RFC2327). They can be used in both multicast and unicast -fashions. Polypaudio exclusively uses multicast RTP/SDP/SAP containing audio data.

      +fashions. PulseAudio exclusively uses multicast RTP/SDP/SAP containing audio data.

      -

      For more information about using these technologies with Polypaudio have a look on the respective module's documentation. +

      For more information about using these technologies with PulseAudio have a look on the respective module's documentation. -

    • How can I use Polypaudio to stream music from my main PC to my LAN with multiple PCs with speakers?

      +
    • How can I use PulseAudio to stream music from my main PC to my LAN with multiple PCs with speakers?

      On the sender side create an RTP sink:

      @@ -208,7 +208,7 @@ load-module module-rtp-recv

      BTW: You can have more than one sender machine set up like this. The audio data will be mixed on the client side.

    • -
    • How can I use Polypaudio to share a single LINE-IN/MIC jack on the entire LAN?

      +
    • How can I use PulseAudio to share a single LINE-IN/MIC jack on the entire LAN?

      On the sender side simply load the RTP sender module:

      @@ -238,7 +238,7 @@ modules to select them. Choose your group addresses from the range 225.0.0.x to make sure the audio data never leaves the LAN.

    • -
    • Can I use Polypaudio to playback music on two sound cards simultaneously?

      +
    • Can I use PulseAudio to playback music on two sound cards simultaneously?

      Yes! Use module-combine for that.

      @@ -251,13 +251,13 @@ set-sink-default combined

      This will combine the two sinks output0 and output1 into a new sink combined. Every sample -written to the latter will be forwarded to the former two. Polypaudio +written to the latter will be forwarded to the former two. PulseAudio will make sure to adjust the sample rate of the slave device in case it deviates from the master device. You can have more than one slave sink attached to the combined sink, and hence combine even three and more sound cards.

    • -
    • Can I use Polypaudio to combine two stereo soundcards into a virtual surround sound card?

      +
    • Can I use PulseAudio to combine two stereo soundcards into a virtual surround sound card?

      Yes! You can use use module-combine for that.

      @@ -271,7 +271,7 @@ load-module module-combine sink_name=combined master=output0 slaves=output1 chan time we manually specify the channel mappings for the sinks to make sure everything is routed correctly.

      -

      Please keep in mind that Polypaudio will constantly adjust the +

      Please keep in mind that PulseAudio will constantly adjust the sample rate to compensate for the deviating quartzes of the sound devices. This is not perfect, however. Deviations in a range of 1/44100s (or 1/48000s depending on the sampling frequency) can not be @@ -281,7 +281,11 @@ you hear.

    • +
    • Why did you rename Polypaudio to PulseAudio?

      +

      Please read this blog story for an explanation.

      + +
    • diff --git a/doc/README.html.in b/doc/README.html.in index 2f6ad448..e4eea786 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -3,12 +3,12 @@ -pulseaudio @PACKAGE_VERSION@ +PulseAudio @PACKAGE_VERSION@ -

      pulseaudio @PACKAGE_VERSION@

      +

      PulseAudio @PACKAGE_VERSION@

      Copyright 2004-2006 Lennart Poettering <@PACKAGE_BUGREPORT@> and Pierre Ossman

      @@ -44,7 +44,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

      News

      Fri Jun 2 2006:

      Version 0.9.1 +href="@PACKAGE_URL@polypaudio-0.9.1.tar.gz">Version 0.9.1 released; changes include: load modules even when libtool .la files are missing; generate better ALSA device names from module-detect; if an ALSA device doesn't support the @@ -53,7 +53,7 @@ suggests instead; amd64 portability; drop .sh suffix of esdcompat.sh; build system fixes; No API or ABI changes were made

      Fri May 26 2006:

      Version 0.9.0 +href="@PACKAGE_URL@polypaudio-0.9.0.tar.gz">Version 0.9.0 released; changes include: new module module-volume-restore; new OSS API emulation tool padsp; require valid UTF8 strings everywhere; properly support ALSA channel maps for surround sound; @@ -62,7 +62,7 @@ main loop API for synchronous programs; introduce real shared object versioning; a few API additions; many, many bugfixes

      Fri Apr 28 2006:

      Version 0.8.1 +href="@PACKAGE_URL@polypaudio-0.8.1.tar.gz">Version 0.8.1 released; changes include: support for specifying the channel map on the command lines of paplay and pacat and as arguments to the driver modules; ALSA hardware mixer compatibility; @@ -70,16 +70,16 @@ fix linking; properly remove PF_UNIX sockets when unloading protocol modules; fix sample cache; many other fixes

      Thu Apr 13 2006:

      Version 0.8 released; -changes include: too many to count - consider reading this blog entry for more information; many, many minor fixes.

      +href="@PACKAGE_URL@polypaudio-0.8.tar.gz">Version 0.8 released; +changes include: too many to count - consider reading this blog entry for more information; many, many minor fixes.

      Sun Nov 21 2004:

      Version 0.7 released; +href="@PACKAGE_URL@polypaudio-0.7.tar.gz">Version 0.7 released; changes include: IPv6 support; PID file support; publish credentials in X11 root window (module-x11-publish; new tool pacmd; ESOUND backend; new command load-sample-dir-lazy; many, many minor fixes.

      Thu Oct 28 2004:

      Version 0.6 released; +href="@PACKAGE_URL@polypaudio-0.6.tar.gz">Version 0.6 released; changes include: TCP wrappers support; don't load the complete sound file into memory when playing back using pa_play_file(); autoload API change; don't load all sound files as FLOAT32; shorten @@ -91,14 +91,14 @@ generation; correctly lock daemon autospawning; print daemon layout to STDERR on SIGHUP; new options for pacat: allow sample type specification.

      Mon Sep 24 2004:

      Version 0.5.1 released; +href="@PACKAGE_URL@polypaudio-0.5.1.tar.gz">Version 0.5.1 released; changes include: improve esound protocol compatibility; fix autospawning via libesd; make use of POSIX capabilities; allow SCHED_FIFO scheduling only for users in group realtime; minor build system fix.

      Mon Sep 20 2004:

      Version 0.5 released; +href="@PACKAGE_URL@polypaudio-0.5.tar.gz">Version 0.5 released; changes include: extensive API improvements, new module module-combine for combining multiple sound cards into one, gcc 2.95 compatibility, configuration files, add "lazy" samples, @@ -106,29 +106,29 @@ support for source and network latency measurements, add module-pipe-source, many other fixes and improvements.

      Wed Sep 8 2004:

      Version 0.4 released; +href="@PACKAGE_URL@polypaudio-0.4.tar.gz">Version 0.4 released; changes include: daemon auto spawning, support for SCHED_FIFO scheduling, three new modules, proper logging, CPU load watchdog, many fixes.

      Fri Aug 27 2004:

      Version 0.3 released; +href="@PACKAGE_URL@polypaudio-0.3.tar.gz">Version 0.3 released; changes include: support for both glib 2.0 and glib 1.2, future cancellation, API updates, many fixes, relicense client library to LGPL.

      Fri Aug 20 2004:

      Version 0.2 released; +href="@PACKAGE_URL@polypaudio-0.2.tar.gz">Version 0.2 released; changes include: added sample cache, introspection API, client API documentation, module autoloading, glib support, a module for intercepting X11 bell events, and much more.

      Sat Jul 17 2004:

      Version 0.1 released

      +href="@PACKAGE_URL@polypaudio-0.1.tar.gz">Version 0.1 released

      Overview

      -

      pulseaudio is a networked sound server for Linux and other +

      PulseAudio is a networked sound server for Linux and other Unix like operating systems and Microsoft Windows. It is intended to be an improved drop-in replacement for the Enlightened Sound Daemon (ESOUND). In addition to the features ESOUND provides -pulseaudio has:

      +PulseAudio has:

      • Extensible plugin architecture (by loading dynamic loadable modules with dlopen())
      • @@ -150,8 +150,8 @@ Daemon (ESOUND). In addition to the features ESOUND provides use of a simple main loop abstraction layer. This allows easy integration with asynchronous applications using the glib/gtk mainloop. Since the asynchronous API -available through pulselib is quite difficult to use there is -a simplified synchronous API wrapper pulselib-simple +available through libpulse is quite difficult to use there is +a simplified synchronous API wrapper libpulse-simple available. A simple main loop implementation is available as well.

        The following modules are currently available:

        @@ -167,12 +167,12 @@ Sound Architecture (ALSA) sinks and sources
      • module-combine: combine multiple sinks into one, adjusting the sample rate if the their clocks deviate.
      • module-sine: a sine generate sink input.
      • module-x11-bell: play a sample from the sample cache on every X11 bell event.
      • -
      • module-x11-publish: store Polypaudio credentials in the X11 root window.
      • +
      • module-x11-publish: store PulseAudio credentials in the X11 root window.
      • module-esound-protocol-tcp, module-esound-protocol-unix: ESOUND compatibility modules (for TCP/IP resp. UNIX domain sockets)
      • -
      • module-native-protocol-tcp, module-native-protocol-unix: Native pulseaudio protocol (for TCP/IP resp. UNIX domain sockets)
      • +
      • module-native-protocol-tcp, module-native-protocol-unix: Native PulseAudio protocol (for TCP/IP resp. UNIX domain sockets)
      • module-simple-protocol-tcp, module-simple-protocol-unix: Simplistic protocol for playback/capture for usage with tools like netcat (for TCP/IP resp. UNIX domain sockets)
      • -
      • module-cli-protocol-tcp, module-cli-protocol-unix, module-cli: Expose pulseaudio's internals whith a simple command line interface. (for TCP/IP resp. UNIX domain sockets resp. STDIN/STDOUT)
      • -
      • module-http-protocol-tcp: Spawns a small HTTP server which can be used to introspect the Polypaudio server with a web browser.
      • +
      • module-cli-protocol-tcp, module-cli-protocol-unix, module-cli: Expose PulseAudio's internals whith a simple command line interface. (for TCP/IP resp. UNIX domain sockets resp. STDIN/STDOUT)
      • +
      • module-http-protocol-tcp: Spawns a small HTTP server which can be used to introspect the PulseAudio server with a web browser.
      • module-tunnel-sink, module-tunnel-source: make sinks/sources from other hosts available locally.
      • module-match: adjust volume automatically for newly created playback streams based on a regular expression matching table.
      • module-volume-restore: much like module-match, but create rules fully automatically based on the client name.
      • @@ -186,12 +186,12 @@ Sound Architecture (ALSA) sinks and sources
      • module-jack-sink, module-jack-source: connect to a JACK Audio Connection Kit server. (A sound server for professional audio production)
      -

      A GTK GUI manager application for pulseaudio is the Polypaudio -Manager. Other GTK GUI tool for Polypaudio are the Polypaudio Volume +

      A GTK GUI manager application for PulseAudio is the PulseAudio +Manager. Other GTK GUI tool for PulseAudio are the PulseAudio Volume Meter and the Polypaudio Volume +href="http://0pointer.de/lennart/projects/pavucontrol">PulseAudio Volume Control .

      There are output plugins for Xine (merged in Xine CVS). Drivers for PortAudio will be released shortly.

      +

      PulseAudio was formerly known as Polypaudio.

      +

      Current Status

      Version @PACKAGE_VERSION@ is quite usable. It matches and supersedes ESOUND's feature set in nearly all areas.

      @@ -216,68 +218,68 @@ href="modules.html">modules.html, cli.html, daemon.html and FAQ.html.

      -

      There is a Trac based Wiki for Polypaudio available.

      +

      There is a Trac based Wiki for PulseAudio available.

      First Steps

      -

      Simply start the pulseaudio daemon with the argument -nC

      +

      Simply start the PulseAudio daemon with the argument -nC

      pulseaudio -nC

      This will present you a screen like this:

      -
      Welcome to pulseaudio! Use "help" for usage information.
      +
      Welcome to PulseAudio! Use "help" for usage information.
       >>> 

      Now you can issue CLI commands as described in cli.html. Another way to start -pulseaudio is by specifying a configuration script like that one included in the distribution on the +PulseAudio is by specifying a configuration script like that one included in the distribution on the command line :

      pulseaudio -nF pulseaudio.pa

      This will load some drivers and protocols automatically.

      -

      The best idea is to configure your daemon in /etc/pulseaudio/daemon.conf and /etc/pulseaudio/default.pa and to run pulseaudio without any arguments.

      +

      The best idea is to configure your daemon in /etc/pulse/daemon.conf and /etc/pulse/default.pa and to run PulseAudio without any arguments.

      Beware! Unless you pass the option --sysconfdir=/etc to -configure, the directory /etc/pulseaudio/ is really -/usr/local/etc/pulseaudio/.

      +configure, the directory /etc/pulse/ is really +/usr/local/etc/pulse/.

      -

      Developing pulseaudio Clients

      +

      Developing PulseAudio Clients

      You may browse the Doxygen generated programing documentation for the client API. (Run make doxygen to generate this documentation from the source tree)

      -

      Developing pulseaudio Modules

      +

      Developing PulseAudio Modules

      -

      There are several reasons for writing loadable modules for pulseaudio:

      +

      There are several reasons for writing loadable modules for PulseAudio:

      • Extended device driver support
      • Protocol support beyond ESOUND's protocol and the native protocol. (such as NAS or a subset of aRts)
      • New programming interfaces such as XMLRPC or DBUS for controlling the daemon.
      • -
      • Hooking audio event sources directly into pulseaudio (similar to module-x11-bell)
      • -
      • For low latency applications such as VOIP: load the VOIP core directly into pulseaudio and have a slim GUI frontend to control it.
      • +
      • Hooking audio event sources directly into PulseAudio (similar to module-x11-bell)
      • +
      • For low latency applications such as VOIP: load the VOIP core directly into PulseAudio and have a slim GUI frontend to control it.

      There is currently no documentation how to write loadable modules -for pulseaudio. Read the source, Luke! If you are interested in +for PulseAudio. Read the source, Luke! If you are interested in writing new modules feel free to contact the author in case you have any questions.

      Requirements

      -

      Currently, pulseaudio is tested on Linux, FreeBSD, Solaris and Microsoft Windows. It requires an OSS, ALSA, Win32 or Solaris compatible soundcard.

      +

      Currently, PulseAudio> is tested on Linux, FreeBSD, Solaris and Microsoft Windows. It requires an OSS, ALSA, Win32 or Solaris compatible soundcard.

      -

      pulseaudio was developed and tested on Debian GNU/Linux +

      PulseAudio was developed and tested on Debian GNU/Linux "testing" from November 2004, it should work on most other Linux distributions (and maybe Unix versions) since it uses GNU autoconf and GNU libtool for source code configuration and shared library management.

      -

      pulseaudio needs Pulseaudio needs Secret Rabbit Code (aka libsamplerate), libsndfile, ./configure inside the distribution directory for configuring the source tree. After that you should run make for compilation and make install (as root) for installation of -pulseaudio.

      +PulseAudio.

      Acknowledgements

      @@ -304,11 +306,11 @@ compilation and make install (as root) for installation of

      Jeff Waugh for creating Ubuntu packages (and hopefully soon Debian)

      -

      Miguel Freitas for writing a Polypaudio driver for Xine

      +

      Miguel Freitas for writing a PulseAudio driver for Xine

      -

      Joe Marcus Clarke for porting Polypaudio to FreeBSD

      +

      Joe Marcus Clarke for porting PulseAudio to FreeBSD

      -

      Cendio AB for paying for Pierre's work on Polypaudio

      +

      Cendio AB for paying for Pierre's work on PulseAudio

      Sebastien ESTIENNE for testing

      @@ -320,7 +322,7 @@ compilation and make install (as root) for installation of

      The current release is @PACKAGE_VERSION@

      -

      Get pulseaudio's development sources from the Subversion repository (viewcvs):

      +

      Get PulseAudio's development sources from the Subversion repository (viewcvs):

      svn checkout svn://0pointer.de/pulseaudio/trunk pulseaudio
      @@ -328,13 +330,13 @@ compilation and make install (as root) for installation of

      If you want to be notified whenever I release a new version of this software use the subscription feature of Freshmeat.

      -

      There is a general discussion mailing list for pulseaudio available. In addition, you can subscribe to SVN changes and Trac Tickets.

      +

      There is a general discussion mailing list for PulseAudio available. In addition, you can subscribe to SVN changes and Trac Tickets.

      -

      Polypaudio is being tracked at CIA.

      +

      PulseAudio is being tracked at CIA.

      -

      There's a chance to meet the Polypaudio developers on our IRC channel #pulseaudio on irc.freenode.org.

      +

      There's a chance to meet the PulseAudio developers on our IRC channel #pulseaudio on irc.freenode.org.

      -

      There is a Trac based Wiki for Polypaudio available.

      +

      There is a Trac based Wiki for PulseAudio available.

      Please report bugs to our Trac ticket system.

      diff --git a/doc/cli.html.in b/doc/cli.html.in index 511f5964..3a256732 100644 --- a/doc/cli.html.in +++ b/doc/cli.html.in @@ -2,14 +2,14 @@ -pulseaudio: Simple Command Line Language +PulseAudio: Simple Command Line Language

      Simple Command Line Language

      -

      pulseaudio provides a simple command line language used by +

      PulseAudio provides a simple command line language used by configuration scripts as well as the modules module-cli and module-cli-protocol-{unix,tcp}. Empty lines and lines beginning with a hashmark (#) are silently ignored. Several @@ -181,7 +181,7 @@ on the interactive command line.

      Example Configuration Script

      -

      Mark the following script as executable (chmod +x) and run it for a sensible pulseaudio configuration.

      +

      Mark the following script as executable (chmod +x) and run it for a sensible PulseAudio configuration.

       #!/usr/bin/polaudio -nF
      @@ -215,6 +215,6 @@ play-file /usr/share/sounds/startup3.wav combined
       

      -
      Lennart Poettering <@PACKAGE_BUGREPORT@>, April 2006
      +
      Lennart Poettering <@PACKAGE_BUGREPORT@>, June 2006
      $Id$
      diff --git a/doc/daemon.html.in b/doc/daemon.html.in index 0d91e534..d90caa2a 100644 --- a/doc/daemon.html.in +++ b/doc/daemon.html.in @@ -2,7 +2,7 @@ -pulseaudio: Daemon +PulseAudio: Daemon @@ -11,7 +11,7 @@

      Command Line Arguments

      -The pulseaudio daemon accepts several command line arguments: +The PulseAudio daemon accepts several command line arguments:
       COMMANDS:
      @@ -60,7 +60,7 @@ STARTUP SCRIPT:
       
       
      pulseaudio -D
      -

      This will run /etc/pulseaudio/default.pa after startup. This should be a script written in the CLI language described in cli.html.

      +

      This will run /etc/pulse/default.pa after startup. This should be a script written in the CLI language described in cli.html.

      Signals

      @@ -83,6 +83,6 @@ STARTUP SCRIPT:

      The daemon logs the current server layout.


      -
      Lennart Poettering <@PACKAGE_BUGREPORT@>, November 2004
      +
      Lennart Poettering <@PACKAGE_BUGREPORT@>, June 2006
      $Id$
      diff --git a/doc/modules.html.in b/doc/modules.html.in index f004f084..dbad8d63 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -2,7 +2,7 @@ -pulseaudio: Loadable Modules +PulseAudio: Loadable Modules @@ -10,7 +10,7 @@

      Loadable Modules

      -

      The following loadable modules are provided with the pulseaudio distribution:

      +

      The following loadable modules are provided with the PulseAudio distribution:

      Device Drivers

      @@ -157,7 +157,7 @@ will decrease output quality however. (defaults to

      module-tunnel-{sink,source}

      Tunnel a remote sink/source to a local "ghost" -sink/source. Requires a running pulseaudio daemon on the remote server +sink/source. Requires a running PulseAudio daemon on the remote server with module-native-protocol-tcp loaded. It's probably a better idea to connect to the remote sink/source directly since some buffer control is lost through this tunneling.

      @@ -204,7 +204,7 @@ module see cli.html.

      module-cli-protocol-{unix,tcp}

      An implemenation of a simple command line based protocol for -controlling the pulseaudio daemon. If loaded, the user may +controlling the PulseAudio daemon. If loaded, the user may connect with tools like netcat, telnet or bidilink to the listening sockets and execute commands the same way as with module-cli.

      @@ -225,7 +225,7 @@ transparent TCP/IP socket. (Both IPv6 and IPv4 - if available)

      a numerical binary value. If 1 the socket is bound to the loopback device, i.e. not publicly accessible. (defaults to 1) listen=(only for -tcp) The IP address to listen on. If specified, supersedes the value specified in loopback= - socket=(only for -unix) The UNIX socket name (defaults to /tmp/pulseaudio/cli) + socket=(only for -unix) The UNIX socket name (defaults to /tmp/pulse/cli)

      module-simple-protocol-{unix,tcp}

      @@ -254,7 +254,7 @@ about the two possible suffixes of this module.

      An implemenation of a protocol compatible with the Enlightened Sound Daemon (ESOUND, esd). When you load this module you may -access the pulseaudio daemon with tools like esdcat, +access the PulseAudio daemon with tools like esdcat, esdrec or even esdctl. Many applications, such as XMMS, include support for this protocol.

      @@ -273,7 +273,7 @@ about the two possible suffixes of this module.

      module-native-protocol-{unix,tcp}

      -

      The native protocol of pulseaudio.

      +

      The native protocol of PulseAudio.

      See module-cli-protocol-{unix,tcp} for more information about the two possible suffixes of this module.

      @@ -293,7 +293,7 @@ about the two possible suffixes of this module.

      module-http-protocol-tcp

      A proof-of-concept HTTP module, which can be used to introspect -the current status of the pulseaudio daemon using HTTP. Just load this +the current status of the PulseAudio daemon using HTTP. Just load this module and point your browser to http://localhost:4714/. This module takes the same arguments as module-cli-protocol-tcp.

      @@ -430,7 +430,7 @@ created in the JACK server.

      - +
      sink_name=The name for the Polypaudio sink. If ommited defaults to jack_out.
      server_name=The JACK server to connect to. If ommited defaults to the default server.
      client_name=The client name to tell the JACK server. If ommited defaults to pulseaudio.
      client_name=The client name to tell the JACK server. If ommited defaults to PulseAudio.
      channels=Number of channels to register. If ommited defaults to the number of physical playback ports of the JACK server.
      connect=Takes a boolean value. If enabled (the default) Polypaudio will try to connect its ports to the physicial playback ports of the JACK server
      @@ -455,18 +455,18 @@ which is replaced by source_name (with a default of jack_in) f

      module-esound-compat-spawnfd

      -

      This is a compatibility module for libesd based autospawning of pulseaudio. Don't use it directly.

      +

      This is a compatibility module for libesd based autospawning of PulseAudio. Don't use it directly.

      module-esound-compat-spawnpid

      -

      This is a compatibility module for libesd based autospawning of pulseaudio. Don't use it directly.

      +

      This is a compatibility module for libesd based autospawning of PulseAudio. Don't use it directly.

      module-match

      Adjust the volume of a playback stream automatically based on its name.

      - +
      table=The regular expression matching table file to use (defaults to ~/.pulseaudio/match.table)
      table=The regular expression matching table file to use (defaults to ~/.pulse/match.table)

      The table file should contain a regexp and volume on each line, seperated by spaces. An example:

      @@ -482,7 +482,7 @@ which is replaced by source_name (with a default of jack_in) f

      Adjust the volume of a playback stream automatically based on its name.

      - +
      table=The table file to use (defaults to ~/.pulseaudio/volume.table)
      table=The table file to use (defaults to ~/.pulse/volume.table)

      In contrast to module-match this module needs no explicit -- cgit From 230f97a4a4dc22510a19add8b2df0533a359846c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 23:56:54 +0000 Subject: s/POLYP/PULSE/g git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1041 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 10 +++---- doc/FAQ.html.in | 10 +++---- doc/modules.html.in | 4 +-- src/Makefile.am | 24 ++++++++-------- src/daemon/daemon-conf.c | 8 +++--- src/modules/module-x11-publish.c | 22 +++++++-------- src/pulse/client-conf-x11.c | 8 +++--- src/pulse/client-conf.c | 16 +++++------ src/pulsecore/core-util.c | 10 +++---- src/pulsecore/log.c | 2 +- src/utils/padsp.c | 2 +- src/utils/pax11publish.c | 60 ++++++++++++++++++++-------------------- 12 files changed, 88 insertions(+), 88 deletions(-) diff --git a/configure.ac b/configure.ac index bb72ee37..e2c8ed6c 100644 --- a/configure.ac +++ b/configure.ac @@ -36,11 +36,11 @@ AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/pulseaudio/]) AC_SUBST(PA_API_VERSION, 9) AC_SUBST(PA_PROTOCOL_VERSION, 9) -AC_SUBST(LIBPOLYP_VERSION_INFO, [0:0:0]) -AC_SUBST(LIBPOLYPCORE_VERSION_INFO, [0:1:0]) -AC_SUBST(LIBPOLYP_SIMPLE_VERSION_INFO, [0:0:0]) -AC_SUBST(LIBPOLYP_BROWSE_VERSION_INFO, [0:0:0]) -AC_SUBST(LIBPOLYP_MAINLOOP_GLIB_VERSION_INFO, [0:0:0]) +AC_SUBST(LIBPULSE_VERSION_INFO, [0:0:0]) +AC_SUBST(LIBPULSECORE_VERSION_INFO, [0:1:0]) +AC_SUBST(LIBPULSE_SIMPLE_VERSION_INFO, [0:0:0]) +AC_SUBST(LIBPULSE_BROWSE_VERSION_INFO, [0:0:0]) +AC_SUBST(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO, [0:0:0]) if type -p stow > /dev/null && test -d /usr/local/stow ; then AC_MSG_NOTICE([*** Found /usr/local/stow: default install prefix set to /usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION} ***]) diff --git a/doc/FAQ.html.in b/doc/FAQ.html.in index 6b83cf77..39b7390a 100644 --- a/doc/FAQ.html.in +++ b/doc/FAQ.html.in @@ -103,7 +103,7 @@ in ~/.pulse/.

    • How do I use PulseAudio over the network?

      -

      Just set $POLYP_SERVER to the host name of the PulseAudio +

      Just set $PULSE_SERVER to the host name of the PulseAudio server. For authentication you need the same auth cookies on all sides. For that copy ~./pulse-cookie to all clients that shall be allowed to connect.

      @@ -116,9 +116,9 @@ be allowed to connect.

    • What environment variables does PulseAudio care about?

      -

      The client honors: POLYP_SINK (default sink to connect to), POLYP_SOURCE (default source to connect to), POLYP_SERVER (default server to connect to, like ESPEAKER), POLYP_BINARY (the binary to start when autospawning a daemon), POLYP_CLIENTCONFIG (path to the client configuration file).

      +

      The client honors: PULSE_SINK (default sink to connect to), PULSE_SOURCE (default source to connect to), PULSE_SERVER (default server to connect to, like ESPEAKER), PULSE_BINARY (the binary to start when autospawning a daemon), PULSE_CLIENTCONFIG (path to the client configuration file).

      -

      The daemon honors: POLYP_SCRIPT (default CLI script file run after startup), POLYP_CONFIG (default daemon configuration file), POLYP_DLPATH (colon separated list of paths where to look for modules)

    • +

      The daemon honors: PULSE_SCRIPT (default CLI script file run after startup), PULSE_CONFIG (default daemon configuration file), PULSE_DLPATH (colon separated list of paths where to look for modules)

    • I saw that SIGUSR2 provokes loading of the module module-cli-protocol-unix. But how do I make use of that?

      @@ -140,8 +140,8 @@ bidilink unix-client:/tmp/pulse-$USER/cli
    • The following rule applies:

      1. If the the application using the library specifies a server to connect to it is used. If the connection fails, the library fails too.
      2. -
      3. If the environment variable POLYP_SERVER is defined the library connects to that server. If the connection fails, the library fails too.
      4. -
      5. If $DISPLAY is set, the library tries to connect to that server and looks for the root window property POYLP_SERVER for the host to connect to. If POLYP_COOKIE is set it is used as authentication cookie.
      6. +
      7. If the environment variable PULSE_SERVER is defined the library connects to that server. If the connection fails, the library fails too.
      8. +
      9. If $DISPLAY is set, the library tries to connect to that server and looks for the root window property POYLP_SERVER for the host to connect to. If PULSE_COOKIE is set it is used as authentication cookie.
      10. If the client configuration file (~/.pulse/client.conf or /etc/pulse/client.conf) sets the server address, the library connects to that server. If the connection fails, the library fails too.
      11. The library tries to connect to the default local UNIX socket for PulseAudio servers. If the connection fails, it proceeds with the next item.
      12. The library tries to connect to the default local TCP socket for PulseAudio servers. If the connection fails, it proceeds with the next item.
      13. diff --git a/doc/modules.html.in b/doc/modules.html.in index dbad8d63..23ece954 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -314,8 +314,8 @@ as module-cli-protocol-tcp.

        Publishes the access credentials to the Polypaudio server in the X11 root window. The following properties are used: -POLYP_SERVER, POYLP_SINK, POLYP_SOURCE, -POLYP_COOKIE. This is very useful when using SSH or any other +PULSE_SERVER, POYLP_SINK, PULSE_SOURCE, +PULSE_COOKIE. This is very useful when using SSH or any other remote login tool for logging into other machines and getting audio playback to your local speakers. The Polypaudio client libraries make use of this data automatically. Instead of using this module you may diff --git a/src/Makefile.am b/src/Makefile.am index 746f85ec..12621d6a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,9 +30,9 @@ pulseconfdir=$(sysconfdir)/pulse # Defines # ################################### -POLYPAUDIO_BINARY=$(bindir)/pulseaudio$(EXEEXT) +PULSEAUDIO_BINARY=$(bindir)/pulseaudio$(EXEEXT) if OS_IS_WIN32 -DEFAULT_CONFIG_DIR=%POLYP_ROOT% +DEFAULT_CONFIG_DIR=%PULSE_ROOT% else DEFAULT_CONFIG_DIR=$(pulseconfdir) endif @@ -48,7 +48,7 @@ AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibexecdir)\" #AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\" AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\" -AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(POLYPAUDIO_BINARY)\" +AM_CFLAGS += -DPULSEAUDIO_BINARY=\"$(PULSEAUDIO_BINARY)\" # This cool debug trap works on i386/gcc only AM_CFLAGS += '-DDEBUG_TRAP=__asm__("int $$3")' @@ -426,7 +426,7 @@ libpulse_la_SOURCES += \ endif libpulse_la_CFLAGS = $(AM_CFLAGS) -libpulse_la_LDFLAGS = -version-info $(LIBPOLYP_VERSION_INFO) +libpulse_la_LDFLAGS = -version-info $(LIBPULSE_VERSION_INFO) libpulse_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) $(LIBICONV) if HAVE_X11 @@ -442,22 +442,22 @@ endif libpulse_simple_la_SOURCES = pulse/simple.c pulse/simple.h libpulse_simple_la_CFLAGS = $(AM_CFLAGS) libpulse_simple_la_LIBADD = $(AM_LIBADD) libpulse.la -libpulse_simple_la_LDFLAGS = -version-info $(LIBPOLYP_SIMPLE_VERSION_INFO) +libpulse_simple_la_LDFLAGS = -version-info $(LIBPULSE_SIMPLE_VERSION_INFO) libpulse_browse_la_SOURCES = pulse/browser.c pulse/browser.h libpulse_browse_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) libpulse_browse_la_LIBADD = $(AM_LIBADD) libpulse.la $(HOWL_LIBS) -libpulse_browse_la_LDFLAGS = -version-info $(LIBPOLYP_BROWSE_VERSION_INFO) +libpulse_browse_la_LDFLAGS = -version-info $(LIBPULSE_BROWSE_VERSION_INFO) libpulse_mainloop_glib_la_SOURCES = pulse/glib-mainloop.h pulse/glib-mainloop.c libpulse_mainloop_glib_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) libpulse_mainloop_glib_la_LIBADD = $(AM_LIBADD) libpulse.la $(GLIB20_LIBS) -libpulse_mainloop_glib_la_LDFLAGS = -version-info $(LIBPOLYP_MAINLOOP_GLIB_VERSION_INFO) +libpulse_mainloop_glib_la_LDFLAGS = -version-info $(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO) libpulse_mainloop_glib12_la_SOURCES = pulse/glib-mainloop.h pulse/glib12-mainloop.c libpulse_mainloop_glib12_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS) libpulse_mainloop_glib12_la_LIBADD = $(AM_LIBADD) libpulse.la $(GLIB12_LIBS) -libpulse_mainloop_glib12_la_LDFLAGS = -version-info $(LIBPOLYP_MAINLOOP_GLIB_VERSION_INFO) +libpulse_mainloop_glib12_la_LDFLAGS = -version-info $(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO) ################################### # OSS emulation # @@ -593,7 +593,7 @@ libpulsecore_la_SOURCES += \ endif libpulsecore_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBOIL_CFLAGS) -libpulsecore_la_LDFLAGS = -version-info $(LIBPOLYPCORE_VERSION_INFO) +libpulsecore_la_LDFLAGS = -version-info $(LIBPULSECORE_VERSION_INFO) libpulsecore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) $(LIBOIL_LIBS) $(LIBICONV) ################################### @@ -1177,17 +1177,17 @@ CLEANFILES = esdcompat client.conf default.pa daemon.conf esdcompat: daemon/esdcompat.in Makefile sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ - -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ + -e 's,@PULSEAUDIO_BINARY\@,$(PULSEAUDIO_BINARY),g' < $< > $@ client.conf: pulse/client.conf.in Makefile - sed -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ + sed -e 's,@PULSEAUDIO_BINARY\@,$(PULSEAUDIO_BINARY),g' < $< > $@ if OS_IS_WIN32 default.pa: daemon/default.pa.win32 cp $< $@ else default.pa: daemon/default.pa.in Makefile - sed -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ + sed -e 's,@PULSEAUDIO_BINARY\@,$(PULSEAUDIO_BINARY),g' < $< > $@ endif daemon.conf: daemon/daemon.conf.in Makefile diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 4d458a5c..64e8d235 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -43,7 +43,7 @@ # ifndef OS_IS_WIN32 # define DEFAULT_CONFIG_DIR "/etc/pulse" # else -# define DEFAULT_CONFIG_DIR "%POLYP_ROOT%" +# define DEFAULT_CONFIG_DIR "%PULSE_ROOT%" # endif #endif @@ -58,9 +58,9 @@ #define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "daemon.conf" #define DEFAULT_CONFIG_FILE_USER ".pulse" PATH_SEP "daemon.conf" -#define ENV_SCRIPT_FILE "POLYP_SCRIPT" -#define ENV_CONFIG_FILE "POLYP_CONFIG" -#define ENV_DL_SEARCH_PATH "POLYP_DLPATH" +#define ENV_SCRIPT_FILE "PULSE_SCRIPT" +#define ENV_CONFIG_FILE "PULSE_CONFIG" +#define ENV_DL_SEARCH_PATH "PULSE_DLPATH" static const pa_daemon_conf default_conf = { .cmd = PA_CMD_DAEMON, diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c index 05f0d86a..0ee453cc 100644 --- a/src/modules/module-x11-publish.c +++ b/src/modules/module-x11-publish.c @@ -128,22 +128,22 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; s = pa_strlist_tostring(l); - pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_SERVER", s); + pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SERVER", s); pa_xfree(s); if (!pa_get_fqdn(hn, sizeof(hn)) || !pa_get_user_name(un, sizeof(un))) goto fail; u->id = pa_sprintf_malloc("%s@%s/%u", un, hn, (unsigned) getpid()); - pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_ID", u->id); + pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_ID", u->id); if ((t = pa_modargs_get_value(ma, "source", NULL))) - pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_SOURCE", t); + pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SOURCE", t); if ((t = pa_modargs_get_value(ma, "sink", NULL))) - pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_SINK", t); + pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SINK", t); - pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_COOKIE", pa_hexstr(u->auth_cookie, sizeof(u->auth_cookie), hx, sizeof(hx))); + pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_COOKIE", pa_hexstr(u->auth_cookie, sizeof(u->auth_cookie), hx, sizeof(hx))); pa_modargs_free(ma); return 0; @@ -167,14 +167,14 @@ void pa__done(pa_core *c, pa_module*m) { char t[256]; /* Yes, here is a race condition */ - if (!pa_x11_get_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_ID", t, sizeof(t)) || strcmp(t, u->id)) + if (!pa_x11_get_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_ID", t, sizeof(t)) || strcmp(t, u->id)) pa_log_warn(__FILE__": PulseAudio information vanished from X11!"); else { - pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_ID"); - pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_SERVER"); - pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_SINK"); - pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_SOURCE"); - pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "POLYP_COOKIE"); + pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_ID"); + pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SERVER"); + pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SINK"); + pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SOURCE"); + pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_COOKIE"); XSync(pa_x11_wrapper_get_display(u->x11_wrapper), False); } } diff --git a/src/pulse/client-conf-x11.c b/src/pulse/client-conf-x11.c index 7eea5ae3..e4a90017 100644 --- a/src/pulse/client-conf-x11.c +++ b/src/pulse/client-conf-x11.c @@ -50,22 +50,22 @@ int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) { goto finish; } - if (pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) { + if (pa_x11_get_prop(d, "PULSE_SERVER", t, sizeof(t))) { pa_xfree(c->default_server); c->default_server = pa_xstrdup(t); } - if (pa_x11_get_prop(d, "POLYP_SINK", t, sizeof(t))) { + if (pa_x11_get_prop(d, "PULSE_SINK", t, sizeof(t))) { pa_xfree(c->default_sink); c->default_sink = pa_xstrdup(t); } - if (pa_x11_get_prop(d, "POLYP_SOURCE", t, sizeof(t))) { + if (pa_x11_get_prop(d, "PULSE_SOURCE", t, sizeof(t))) { pa_xfree(c->default_source); c->default_source = pa_xstrdup(t); } - if (pa_x11_get_prop(d, "POLYP_COOKIE", t, sizeof(t))) { + if (pa_x11_get_prop(d, "PULSE_COOKIE", t, sizeof(t))) { uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; if (pa_parsehex(t, cookie, sizeof(cookie)) != sizeof(cookie)) { diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c index 9f5cf53d..e150a9cc 100644 --- a/src/pulse/client-conf.c +++ b/src/pulse/client-conf.c @@ -43,7 +43,7 @@ # ifndef OS_IS_WIN32 # define DEFAULT_CONFIG_DIR "/etc/pulse" # else -# define DEFAULT_CONFIG_DIR "%POLYP_ROOT%" +# define DEFAULT_CONFIG_DIR "%PULSE_ROOT%" # endif #endif @@ -56,12 +56,12 @@ #define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "client.conf" #define DEFAULT_CLIENT_CONFIG_FILE_USER ".pulse" PATH_SEP "client.conf" -#define ENV_CLIENT_CONFIG_FILE "POLYP_CLIENTCONFIG" -#define ENV_DEFAULT_SINK "POLYP_SINK" -#define ENV_DEFAULT_SOURCE "POLYP_SOURCE" -#define ENV_DEFAULT_SERVER "POLYP_SERVER" -#define ENV_DAEMON_BINARY "POLYP_BINARY" -#define ENV_COOKIE_FILE "POLYP_COOKIE" +#define ENV_CLIENT_CONFIG_FILE "PULSE_CLIENTCONFIG" +#define ENV_DEFAULT_SINK "PULSE_SINK" +#define ENV_DEFAULT_SOURCE "PULSE_SOURCE" +#define ENV_DEFAULT_SERVER "PULSE_SERVER" +#define ENV_DAEMON_BINARY "PULSE_BINARY" +#define ENV_COOKIE_FILE "PULSE_COOKIE" static const pa_client_conf default_conf = { .daemon_binary = NULL, @@ -77,7 +77,7 @@ static const pa_client_conf default_conf = { pa_client_conf *pa_client_conf_new(void) { pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); - c->daemon_binary = pa_xstrdup(POLYPAUDIO_BINARY); + c->daemon_binary = pa_xstrdup(PULSEAUDIO_BINARY); c->extra_arguments = pa_xstrdup("--log-target=syslog --exit-idle-time=5"); c->cookie_file = pa_xstrdup(PA_NATIVE_COOKIE_FILE); diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index d4b140de..9d694da5 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -88,14 +88,14 @@ #ifdef OS_IS_WIN32 -#define POLYP_ROOTENV "POLYP_ROOT" +#define PULSE_ROOTENV "PULSE_ROOT" int pa_set_root(HANDLE handle) { - char library_path[MAX_PATH + sizeof(POLYP_ROOTENV) + 1], *sep; + char library_path[MAX_PATH + sizeof(PULSE_ROOTENV) + 1], *sep; - strcpy(library_path, POLYP_ROOTENV "="); + strcpy(library_path, PULSE_ROOTENV "="); - if (!GetModuleFileName(handle, library_path + sizeof(POLYP_ROOTENV), MAX_PATH)) + if (!GetModuleFileName(handle, library_path + sizeof(PULSE_ROOTENV), MAX_PATH)) return 0; sep = strrchr(library_path, '\\'); @@ -818,7 +818,7 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env #ifdef OS_IS_WIN32 char buf[PATH_MAX]; - if (!getenv(POLYP_ROOTENV)) + if (!getenv(PULSE_ROOTENV)) pa_set_root(NULL); #endif diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c index df5b140a..06e95b28 100644 --- a/src/pulsecore/log.c +++ b/src/pulsecore/log.c @@ -40,7 +40,7 @@ #include "log.h" -#define ENV_LOGLEVEL "POLYP_LOG" +#define ENV_LOGLEVEL "PULSE_LOG" static char *log_ident = NULL, *log_ident_local = NULL; static pa_log_target_t log_target = PA_LOG_STDERR; diff --git a/src/utils/padsp.c b/src/utils/padsp.c index d9dcc764..af89f8fb 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1500,7 +1500,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_INFO\n"); memset(mi, 0, sizeof(mixer_info)); - strncpy(mi->id, "POLYPAUDIO", sizeof(mi->id)); + strncpy(mi->id, "PULSEAUDIO", sizeof(mi->id)); strncpy(mi->name, "PulseAudio Virtual OSS", sizeof(mi->name)); pa_threaded_mainloop_lock(i->mainloop); mi->modify_counter = i->volume_modify_count; diff --git a/src/utils/pax11publish.c b/src/utils/pax11publish.c index d2ed6c93..2a0d21d6 100644 --- a/src/utils/pax11publish.c +++ b/src/utils/pax11publish.c @@ -99,13 +99,13 @@ int main(int argc, char *argv[]) { switch (mode) { case DUMP: { char t[1024]; - if (pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) + if (pa_x11_get_prop(d, "PULSE_SERVER", t, sizeof(t))) printf("Server: %s\n", t); - if (pa_x11_get_prop(d, "POLYP_SOURCE", t, sizeof(t))) + if (pa_x11_get_prop(d, "PULSE_SOURCE", t, sizeof(t))) printf("Source: %s\n", t); - if (pa_x11_get_prop(d, "POLYP_SINK", t, sizeof(t))) + if (pa_x11_get_prop(d, "PULSE_SINK", t, sizeof(t))) printf("Sink: %s\n", t); - if (pa_x11_get_prop(d, "POLYP_COOKIE", t, sizeof(t))) + if (pa_x11_get_prop(d, "PULSE_COOKIE", t, sizeof(t))) printf("Cookie: %s\n", t); break; @@ -113,14 +113,14 @@ int main(int argc, char *argv[]) { case IMPORT: { char t[1024]; - if (pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) - printf("POLYP_SERVER='%s'\nexport POLYP_SERVER\n", t); - if (pa_x11_get_prop(d, "POLYP_SOURCE", t, sizeof(t))) - printf("POLYP_SOURCE='%s'\nexport POLYP_SOURCE\n", t); - if (pa_x11_get_prop(d, "POLYP_SINK", t, sizeof(t))) - printf("POLYP_SINK='%s'\nexport POLYP_SINK\n", t); - - if (pa_x11_get_prop(d, "POLYP_COOKIE", t, sizeof(t))) { + if (pa_x11_get_prop(d, "PULSE_SERVER", t, sizeof(t))) + printf("PULSE_SERVER='%s'\nexport PULSE_SERVER\n", t); + if (pa_x11_get_prop(d, "PULSE_SOURCE", t, sizeof(t))) + printf("PULSE_SOURCE='%s'\nexport PULSE_SOURCE\n", t); + if (pa_x11_get_prop(d, "PULSE_SINK", t, sizeof(t))) + printf("PULSE_SINK='%s'\nexport PULSE_SINK\n", t); + + if (pa_x11_get_prop(d, "PULSE_COOKIE", t, sizeof(t))) { uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; size_t l; if ((l = pa_parsehex(t, cookie, sizeof(cookie))) != sizeof(cookie)) { @@ -153,16 +153,16 @@ int main(int argc, char *argv[]) { goto finish; } - pa_x11_del_prop(d, "POLYP_SERVER"); - pa_x11_del_prop(d, "POLYP_SINK"); - pa_x11_del_prop(d, "POLYP_SOURCE"); - pa_x11_del_prop(d, "POLYP_ID"); - pa_x11_del_prop(d, "POLYP_COOKIE"); + pa_x11_del_prop(d, "PULSE_SERVER"); + pa_x11_del_prop(d, "PULSE_SINK"); + pa_x11_del_prop(d, "PULSE_SOURCE"); + pa_x11_del_prop(d, "PULSE_ID"); + pa_x11_del_prop(d, "PULSE_COOKIE"); if (server) - pa_x11_set_prop(d, "POLYP_SERVER", server); + pa_x11_set_prop(d, "PULSE_SERVER", server); else if (conf->default_server) - pa_x11_set_prop(d, "POLYP_SERVER", conf->default_server); + pa_x11_set_prop(d, "PULSE_SERVER", conf->default_server); else { char hn[256]; if (!pa_get_fqdn(hn, sizeof(hn))) { @@ -170,18 +170,18 @@ int main(int argc, char *argv[]) { goto finish; } - pa_x11_set_prop(d, "POLYP_SERVER", hn); + pa_x11_set_prop(d, "PULSE_SERVER", hn); } if (sink) - pa_x11_set_prop(d, "POLYP_SINK", sink); + pa_x11_set_prop(d, "PULSE_SINK", sink); else if (conf->default_sink) - pa_x11_set_prop(d, "POLYP_SINK", conf->default_sink); + pa_x11_set_prop(d, "PULSE_SINK", conf->default_sink); if (source) - pa_x11_set_prop(d, "POLYP_SOURCE", source); + pa_x11_set_prop(d, "PULSE_SOURCE", source); if (conf->default_source) - pa_x11_set_prop(d, "POLYP_SOURCE", conf->default_source); + pa_x11_set_prop(d, "PULSE_SOURCE", conf->default_source); pa_client_conf_free(conf); @@ -190,16 +190,16 @@ int main(int argc, char *argv[]) { goto finish; } - pa_x11_set_prop(d, "POLYP_COOKIE", pa_hexstr(cookie, sizeof(cookie), hx, sizeof(hx))); + pa_x11_set_prop(d, "PULSE_COOKIE", pa_hexstr(cookie, sizeof(cookie), hx, sizeof(hx))); break; } case REMOVE: - pa_x11_del_prop(d, "POLYP_SERVER"); - pa_x11_del_prop(d, "POLYP_SINK"); - pa_x11_del_prop(d, "POLYP_SOURCE"); - pa_x11_del_prop(d, "POLYP_ID"); - pa_x11_del_prop(d, "POLYP_COOKIE"); + pa_x11_del_prop(d, "PULSE_SERVER"); + pa_x11_del_prop(d, "PULSE_SINK"); + pa_x11_del_prop(d, "PULSE_SOURCE"); + pa_x11_del_prop(d, "PULSE_ID"); + pa_x11_del_prop(d, "PULSE_COOKIE"); break; default: -- cgit From 3ff68bd7a57186c6c6def975be3fc7e826c8bbcd Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 20 Jun 2006 13:02:34 +0000 Subject: Fix the final few occurences of polyp. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1042 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/modules.html.in | 20 ++++++++++---------- src/daemon/default.pa.in | 2 +- src/daemon/esdcompat.in | 2 +- src/modules/rtp/module-rtp-send.c | 2 +- src/pulse/client.conf.in | 2 +- src/utils/padsp | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/doc/modules.html.in b/doc/modules.html.in index 23ece954..7f12d9a9 100644 --- a/doc/modules.html.in +++ b/doc/modules.html.in @@ -312,12 +312,12 @@ as module-cli-protocol-tcp.

        module-x11-publish

        -

        Publishes the access credentials to the Polypaudio server in the +

        Publishes the access credentials to the PulseAudio server in the X11 root window. The following properties are used: PULSE_SERVER, POYLP_SINK, PULSE_SOURCE, PULSE_COOKIE. This is very useful when using SSH or any other remote login tool for logging into other machines and getting audio -playback to your local speakers. The Polypaudio client libraries make +playback to your local speakers. The PulseAudio client libraries make use of this data automatically. Instead of using this module you may use the tool pax11publish which may be used to access, modify and import credential data from/to the X11 display.

        @@ -354,7 +354,7 @@ already loaded protocol module is used.

        RTP/SDP/SAP Transport

        -

        Polypaudio can stream audio data to an IP multicast group via the +

        PulseAudio can stream audio data to an IP multicast group via the standard protocols RTP, -

        Polypaudio implements both a sender and a reciever for RTP +

        PulseAudio implements both a sender and a reciever for RTP traffic. The sender announces itself via SAP/SDP on the same multicast group as it sends the RTP data to. The reciever picks up the SAP/SDP announcements and creates a playback stream for each @@ -418,26 +418,26 @@ module to create an RTP source.

        JACK Connectivity

        -

        Polypaudio can be hooked up to a PulseAudio can be hooked up to a JACK Audio Connection Kit server which is a specialized sound server used for professional audio production on Unix/Linux. Both a -Polypaudio sink and a source are available. For each channel a port is +PulseAudio sink and a source are available. For each channel a port is created in the JACK server.

        module-jack-sink

        -

        This module implements a Polypaudio sink that connects to JACK and registers as many output ports as requested.

        +

        This module implements a PulseAudio sink that connects to JACK and registers as many output ports as requested.

        - + - +
        sink_name=The name for the Polypaudio sink. If ommited defaults to jack_out.
        sink_name=The name for the PulseAudio sink. If ommited defaults to jack_out.
        server_name=The JACK server to connect to. If ommited defaults to the default server.
        client_name=The client name to tell the JACK server. If ommited defaults to PulseAudio.
        channels=Number of channels to register. If ommited defaults to the number of physical playback ports of the JACK server.
        connect=Takes a boolean value. If enabled (the default) Polypaudio will try to connect its ports to the physicial playback ports of the JACK server
        connect=Takes a boolean value. If enabled (the default) PulseAudio will try to connect its ports to the physicial playback ports of the JACK server

        module-jack-source

        -

        This module implements a Polypaudio source that connects to JACK +

        This module implements a PulseAudio source that connects to JACK and registers as many input ports as requested. Takes the same arguments as module-jack-sink, except for sink_name which is replaced by source_name (with a default of jack_in) for obvious reasons.

        diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in index 623cd114..6beeb90f 100755 --- a/src/daemon/default.pa.in +++ b/src/daemon/default.pa.in @@ -1,4 +1,4 @@ -#!@POLYPAUDIO_BINARY@ -nF +#!@PULSEAUDIO_BINARY@ -nF # # This file is part of PulseAudio. diff --git a/src/daemon/esdcompat.in b/src/daemon/esdcompat.in index 673f8c8a..edae8615 100755 --- a/src/daemon/esdcompat.in +++ b/src/daemon/esdcompat.in @@ -95,4 +95,4 @@ EOF shift done -eval "exec '@POLYPAUDIO_BINARY@'$ARGS" +eval "exec '@PULSEAUDIO_BINARY@'$ARGS" diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 00da64d5..5c47047f 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -298,7 +298,7 @@ int pa__init(pa_core *c, pa_module*m) { r = getsockname(fd, (struct sockaddr*) &sa_dst, &k); assert(r >= 0); - n = pa_sprintf_malloc("Polypaudio RTP Stream on %s", pa_get_fqdn(hn, sizeof(hn))); + n = pa_sprintf_malloc("PulseAudio RTP Stream on %s", pa_get_fqdn(hn, sizeof(hn))); p = pa_sdp_build(af, af == AF_INET ? (void*) &((struct sockaddr_in*) &sa_dst)->sin_addr : (void*) &((struct sockaddr_in6*) &sa_dst)->sin6_addr, diff --git a/src/pulse/client.conf.in b/src/pulse/client.conf.in index d881c44e..21786ebf 100644 --- a/src/pulse/client.conf.in +++ b/src/pulse/client.conf.in @@ -21,7 +21,7 @@ ## commented out. Use either ; or # for commenting ## Path to the pulseaudio daemon to run when autospawning. -; daemon-binary = @POLYPAUDIO_BINARY@ +; daemon-binary = @PULSEAUDIO_BINARY@ ## Extra arguments to pass to the pulseaudio daemon ; extra-arguments = --log-target=syslog --exit-idle-time=5 diff --git a/src/utils/padsp b/src/utils/padsp index d9ebcbc5..bae5a728 100644 --- a/src/utils/padsp +++ b/src/utils/padsp @@ -22,8 +22,8 @@ while getopts 'hs:n:m:MSDd' param ; do case $param in s) - POLYP_SERVER="$OPTARG" - export POLYP_SERVER + PULSE_SERVER="$OPTARG" + export PULSE_SERVER ;; n) PADSP_CLIENT_NAME="$OPTARG" -- cgit From 6ca46f4d7a9fa57b949e2286d3af1b6e78dce8f5 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 20 Jun 2006 13:49:30 +0000 Subject: Make interpol-test build on Win32 and non-pthread systems. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1043 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/tests/interpol-test.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/tests/interpol-test.c b/src/tests/interpol-test.c index 7cabc1c9..bf7f582c 100644 --- a/src/tests/interpol-test.c +++ b/src/tests/interpol-test.c @@ -32,7 +32,10 @@ #include #include #include + +#ifdef HAVE_PTHREAD #include +#endif #include #include @@ -145,7 +148,13 @@ int main(int argc, char *argv[]) { tv = now; while (pa_timeval_diff(pa_gettimeofday(&now), &tv) < 1000) +#ifdef HAVE_PTHREAD pthread_yield(); +#elif defined(OS_IS_WIN32) + Sleep(0); +#else + ; +#endif } if (m) -- cgit From 3b2835843e61e41cdcef1bf0e5cd3687d20767b9 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 20 Jun 2006 14:22:34 +0000 Subject: Check for pthread_yield() as not all platforms have that. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1044 fefdeb5f-60dc-0310-8127-8f9354f1896f --- acinclude.m4 | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/acinclude.m4 b/acinclude.m4 index edd80344..f3a4ac52 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -174,6 +174,17 @@ if test "x$acx_pthread_ok" = xyes; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi + AC_MSG_CHECKING([if pthread_yield is available]) + flag=no + AC_TRY_LINK([#include ], + [pthread_yield();], + [flag=yes]) + AC_MSG_RESULT(${flag}) + if test "x$flag" != xno; then + AC_DEFINE(HAVE_PTHREAD_YIELD, 1, + [Define to 1 if you have the 'pthread_yield' function.]) + fi + LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" -- cgit From 1342999b5197adeb76ee9feb41f38dba26a20dbe Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 20 Jun 2006 14:26:52 +0000 Subject: Make sure we do not use pthread_yield() on platforms that do not have them. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1045 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/tests/interpol-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/interpol-test.c b/src/tests/interpol-test.c index bf7f582c..2df65a45 100644 --- a/src/tests/interpol-test.c +++ b/src/tests/interpol-test.c @@ -148,7 +148,7 @@ int main(int argc, char *argv[]) { tv = now; while (pa_timeval_diff(pa_gettimeofday(&now), &tv) < 1000) -#ifdef HAVE_PTHREAD +#ifdef HAVE_PTHREAD_YIELD pthread_yield(); #elif defined(OS_IS_WIN32) Sleep(0); -- cgit From 07edf591771e719a5616ca11319f644fbf66f576 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 20 Jun 2006 15:36:28 +0000 Subject: Make fix_metrics() exit early so that it doesn't spam the output needlessly. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1046 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index af89f8fb..3b8ecbf1 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -673,6 +673,13 @@ static void fix_metrics(fd_info *i) { char t[PA_SAMPLE_SPEC_SNPRINT_MAX]; fs = pa_frame_size(&i->sample_spec); + + /* Don't fix things more than necessary */ + if ((i->fragment_size % fs) == 0 && + i->n_fragments >= 2 && + i->fragment_size > 0) + return; + i->fragment_size = (i->fragment_size/fs)*fs; /* Number of fragments set? */ -- cgit From 1040b69cf2fc6175a1069226a93ec66f1a092ad0 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 20 Jun 2006 15:45:10 +0000 Subject: Warn when applications use SNDCTL_DSP_GET[IO]PTR even when they shouldn't. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1047 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 3b8ecbf1..3b2294f7 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1992,10 +1992,19 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) break; } - + + case SNDCTL_DSP_GETIPTR: + debug(DEBUG_LEVEL_NORMAL, __FILE__": invalid ioctl SNDCTL_DSP_GETIPTR\n"); + goto inval; + + case SNDCTL_DSP_GETOPTR: + debug(DEBUG_LEVEL_NORMAL, __FILE__": invalid ioctl SNDCTL_DSP_GETOPTR\n"); + goto inval; + default: debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request); +inval: *_errno = EINVAL; goto fail; } -- cgit From 320bedb58032d33a2bd31978c95b8f17d07c9872 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 20 Jun 2006 16:43:46 +0000 Subject: Fix handling of the io flags in duplex mode. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1048 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 3b2294f7..f493f7e5 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -75,6 +75,7 @@ struct fd_info { pa_stream *rec_stream; pa_io_event *io_event; + pa_io_event_flags_t io_flags; void *buf; size_t rec_offset; @@ -557,6 +558,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { i->play_stream = NULL; i->rec_stream = NULL; i->io_event = NULL; + i->io_flags = 0; pthread_mutex_init(&i->mutex, NULL); i->ref = 1; i->buf = NULL; @@ -709,13 +711,10 @@ static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { if (i->io_event) { pa_mainloop_api *api; - pa_io_event_flags_t flags; size_t n; api = pa_threaded_mainloop_get_api(i->mainloop); - flags = 0; - if (s == i->play_stream) { n = pa_stream_writable_size(i->play_stream); if (n == (size_t)-1) { @@ -724,7 +723,9 @@ static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { } if (n >= i->fragment_size) - flags |= PA_IO_EVENT_INPUT; + i->io_flags |= PA_IO_EVENT_INPUT; + else + i->io_flags &= ~PA_IO_EVENT_INPUT; } if (s == i->rec_stream) { @@ -735,10 +736,12 @@ static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { } if (n >= i->fragment_size) - flags |= PA_IO_EVENT_OUTPUT; + i->io_flags |= PA_IO_EVENT_OUTPUT; + else + i->io_flags &= ~PA_IO_EVENT_OUTPUT; } - api->io_enable(i->io_event, flags); + api->io_enable(i->io_event, i->io_flags); } } @@ -757,6 +760,7 @@ static void fd_info_shutdown(fd_info *i) { api = pa_threaded_mainloop_get_api(i->mainloop); api->io_free(i->io_event); i->io_event = NULL; + i->io_flags = 0; } if (i->thread_fd >= 0) { @@ -767,13 +771,10 @@ static void fd_info_shutdown(fd_info *i) { static int fd_info_copy_data(fd_info *i, int force) { size_t n; - pa_io_event_flags_t flags; if (!i->play_stream && !i->rec_stream) return -1; - flags = 0; - if ((i->play_stream) && (pa_stream_get_state(i->play_stream) == PA_STREAM_READY)) { n = pa_stream_writable_size(i->play_stream); @@ -814,7 +815,9 @@ static int fd_info_copy_data(fd_info *i, int force) { } if (n >= i->fragment_size) - flags |= PA_IO_EVENT_INPUT; + i->io_flags |= PA_IO_EVENT_INPUT; + else + i->io_flags &= ~PA_IO_EVENT_INPUT; } if ((i->rec_stream) && (pa_stream_get_state(i->rec_stream) == PA_STREAM_READY)) { @@ -867,14 +870,16 @@ static int fd_info_copy_data(fd_info *i, int force) { } if (n >= i->fragment_size) - flags |= PA_IO_EVENT_OUTPUT; + i->io_flags |= PA_IO_EVENT_OUTPUT; + else + i->io_flags &= ~PA_IO_EVENT_OUTPUT; } if (i->io_event) { pa_mainloop_api *api; api = pa_threaded_mainloop_get_api(i->mainloop); - api->io_enable(i->io_event, flags); + api->io_enable(i->io_event, i->io_flags); } return 0; @@ -1034,7 +1039,6 @@ static int dsp_open(int flags, int *_errno) { pa_mainloop_api *api; int ret; int f; - pa_io_event_flags_t ioflags; debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open()\n"); @@ -1056,23 +1060,23 @@ static int dsp_open(int flags, int *_errno) { switch (flags & O_ACCMODE) { case O_RDONLY: - ioflags = PA_IO_EVENT_OUTPUT; + i->io_flags = PA_IO_EVENT_OUTPUT; shutdown(i->thread_fd, SHUT_RD); shutdown(i->app_fd, SHUT_WR); break; case O_WRONLY: - ioflags = PA_IO_EVENT_INPUT; + i->io_flags = PA_IO_EVENT_INPUT; shutdown(i->thread_fd, SHUT_WR); shutdown(i->app_fd, SHUT_RD); break; case O_RDWR: - ioflags = PA_IO_EVENT_INPUT | PA_IO_EVENT_OUTPUT; + i->io_flags = PA_IO_EVENT_INPUT | PA_IO_EVENT_OUTPUT; break; default: return -1; } - if (!(i->io_event = api->io_new(api, i->thread_fd, ioflags, io_event_cb, i))) + if (!(i->io_event = api->io_new(api, i->thread_fd, i->io_flags, io_event_cb, i))) goto fail; pa_threaded_mainloop_unlock(i->mainloop); -- cgit From 84907e6716b83a340c0d5717148d6262fc0f7121 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 20 Jun 2006 21:23:10 +0000 Subject: fix segfault when module-alsa-source fails to load git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1049 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-sink.c | 2 +- src/modules/module-alsa-source.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index d49b3407..9238072b 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -342,7 +342,7 @@ int pa__init(pa_core *c, pa_module*m) { } period_size = fragsize/frame_size; - u = pa_xmalloc0(sizeof(struct userdata)); + u = pa_xnew0(struct userdata, 1); m->userdata = u; u->module = m; diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index c4e8689c..68c61be9 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -335,7 +335,7 @@ int pa__init(pa_core *c, pa_module*m) { } period_size = fragsize/frame_size; - u = pa_xnew(struct userdata, 1); + u = pa_xnew0(struct userdata, 1); m->userdata = u; u->module = m; -- cgit From 74e958c008c743ec157edf4f08edf5cb94413194 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 20 Jun 2006 22:27:35 +0000 Subject: bump version number git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1050 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- doc/README.html.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index e2c8ed6c..3b02df5a 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ AC_PREREQ(2.57) m4_define(PA_MAJOR, [0]) m4_define(PA_MINOR, [9]) -m4_define(PA_MICRO, [1]) +m4_define(PA_MICRO, [2]) AC_INIT([pulseaudio], PA_MAJOR.PA_MINOR.PA_MICRO,[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([src/daemon/main.c]) diff --git a/doc/README.html.in b/doc/README.html.in index e4eea786..31cd929d 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -328,7 +328,7 @@ PulseAudio.

        Community

        -

        If you want to be notified whenever I release a new version of this software use the subscription feature of Freshmeat.

        +

        If you want to be notified whenever I release a new version of this software use the subscription feature of Freshmeat.

        There is a general discussion mailing list for PulseAudio available. In addition, you can subscribe to SVN changes and Trac Tickets.

        -- cgit From 1710041eaffc917d45eaeb6143db24a9773842b3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Jun 2006 00:18:43 +0000 Subject: only interpolate when the last timing info told us the stream is indeed playing git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1051 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulse/stream.c b/src/pulse/stream.c index c8fc09d2..677df009 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -1254,7 +1254,7 @@ int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) { /* We just add the time that passed since the latency info was * current */ - if (!s->corked) { + if (!s->corked && s->timing_info.playing) { struct timeval now; usec += pa_timeval_diff(pa_gettimeofday(&now), &s->timing_info.timestamp); } -- cgit From 045b05cd91aa313d9a3cb496f8a0e664d8bceea3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Jun 2006 14:05:15 +0000 Subject: include config.h in browser.c (closes #20) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1052 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/browser.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pulse/browser.c b/src/pulse/browser.c index 96625869..60c71090 100644 --- a/src/pulse/browser.c +++ b/src/pulse/browser.c @@ -19,6 +19,10 @@ USA. ***/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include -- cgit From 18b8b84b7e3885165ef14cd7c25fa34f1ce36b61 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Jun 2006 16:36:58 +0000 Subject: increase the maxium number of concurrent esd and native connections git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1053 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 2 +- src/pulsecore/protocol-native.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 6b9112bf..5daa32fe 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -55,7 +55,7 @@ #include "protocol-esound.h" /* Don't accept more connection than this */ -#define MAX_CONNECTIONS 10 +#define MAX_CONNECTIONS 64 /* Kick a client if it doesn't authenticate within this time */ #define AUTH_TIMEOUT 5 diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 1f936e75..f77c9c24 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -62,7 +62,7 @@ #define AUTH_TIMEOUT 60 /* Don't accept more connection than this */ -#define MAX_CONNECTIONS 10 +#define MAX_CONNECTIONS 64 #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */ -- cgit From 8b0d1346022d0eb3f3b4bf3eb956f9757ff57156 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 30 Jun 2006 08:16:14 +0000 Subject: Make sure we print the file name we actually use. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1054 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/daemon-conf.c | 2 +- src/pulse/client-conf.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 64e8d235..d1afed7b 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -238,7 +238,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { pa_open_config_file(DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file, "r"); if (!f && errno != ENOENT) { - pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", filename, pa_cstrerror(errno)); + pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", c->config_file, pa_cstrerror(errno)); goto finish; } diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c index e150a9cc..5cebcf46 100644 --- a/src/pulse/client-conf.c +++ b/src/pulse/client-conf.c @@ -124,7 +124,7 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) { pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn, "r"); if (!f && errno != EINTR) { - pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", filename, pa_cstrerror(errno)); + pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } -- cgit From 9e45991b112680c9ae64454811577c7c0d790501 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Jul 2006 12:45:24 +0000 Subject: update readme for 0.9.2 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1055 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/doc/README.html.in b/doc/README.html.in index 31cd929d..0a49e1ed 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -43,6 +43,15 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

        News

        +
        Fri Jul 7 2006:

        Version 0.9.2 +released; changes include: rename project to PulseAudio (see this blog +article for an explanation); increase maximum number of concurrent +connections; fix latency interpolation; add support for reverse endian +sound cards; add support for recording in padsp; reenable CPU +load limiter; other bugfixes

        +
        Fri Jun 2 2006:

        Version 0.9.1 released; changes include: load modules even when libtool .la @@ -123,7 +132,7 @@ href="@PACKAGE_URL@polypaudio-0.1.tar.gz">Version 0.1 released

        Overview

        -

        PulseAudio is a networked sound server for Linux and other +

        PulseAudio is a networked sound server for Linux and other Unix like operating systems and Microsoft Windows. It is intended to be an improved drop-in replacement for the Enlightened Sound @@ -190,7 +199,8 @@ Sound Architecture (ALSA) sinks and sources href="http://0pointer.de/lennart/projects/paman/">PulseAudio Manager. Other GTK GUI tool for PulseAudio are the PulseAudio Volume -Meter and the , PulseAudio Device Chooser and the PulseAudio Volume Control .

        @@ -199,11 +209,7 @@ href="http://0pointer.de/lennart/projects/xmms-pulse/">XMMS, libao (merged in libao SVN) and gstreamer -(merged in gstreamer-plugins CVS), MPlayer (merged in MPlayer CVS) and Xine (merged in Xine CVS). Drivers for -PortAudio will be released -shortly.

        +(merged in gstreamer-plugins CVS).

        PulseAudio was formerly known as Polypaudio.

        @@ -316,19 +322,21 @@ PulseAudio.

        Igor Zubkov for some portability patches

        +

        Jan Schmidt for some latency interpolation love

        +

        Download

        The newest release is always available from @PACKAGE_URL@

        The current release is @PACKAGE_VERSION@

        -

        Get PulseAudio's development sources from the Subversion repository (viewcvs):

        +

        Get PulseAudio's development sources from the Subversion repository (ViewCVS, Trac):

        svn checkout svn://0pointer.de/pulseaudio/trunk pulseaudio

        Community

        -

        If you want to be notified whenever I release a new version of this software use the subscription feature of Freshmeat.

        +

        If you want to be notified whenever I release a new version of this software use the subscription feature of Freshmeat.

        There is a general discussion mailing list for PulseAudio available. In addition, you can subscribe to SVN changes and Trac Tickets.

        @@ -336,12 +344,12 @@ PulseAudio.

        There's a chance to meet the PulseAudio developers on our IRC channel #pulseaudio on irc.freenode.org.

        -

        There is a Trac based Wiki for PulseAudio available.

        +

        The main project homepage is http://avahi.org/.

        -

        Please report bugs to our Trac ticket system.

        +

        Please report bugs to our Trac ticket system.


        -
        Lennart Poettering <@PACKAGE_BUGREPORT@>, June 2006
        +
        Lennart Poettering <@PACKAGE_BUGREPORT@>, July 2006
        $Id$
        -- cgit From 81eb4a2d76e145406bbe1f78f7765b6c63521031 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Jul 2006 12:53:19 +0000 Subject: fix mailman URL git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1056 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/README.html.in b/doc/README.html.in index 0a49e1ed..84d69466 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -338,7 +338,7 @@ PulseAudio.

        If you want to be notified whenever I release a new version of this software use the subscription feature of Freshmeat.

        -

        There is a general discussion mailing list for PulseAudio available. In addition, you can subscribe to SVN changes and Trac Tickets.

        +

        There is a general discussion mailing list for PulseAudio available. In addition, you can subscribe to SVN changes and Trac Tickets.

        PulseAudio is being tracked at CIA.

        -- cgit From 7fe5e5f0204626d8fcfaf62b21cab895b340cce4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Jul 2006 12:59:13 +0000 Subject: replace remaining ML refs to polyp git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1057 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/README.html.in b/doc/README.html.in index 84d69466..9076758e 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -338,7 +338,7 @@ PulseAudio.

        If you want to be notified whenever I release a new version of this software use the subscription feature of Freshmeat.

        -

        There is a general discussion mailing list for PulseAudio available. In addition, you can subscribe to SVN changes and Trac Tickets.

        +

        There is a general discussion mailing list for PulseAudio available. In addition, you can subscribe to SVN changes and Trac Tickets.

        PulseAudio is being tracked at CIA.

        -- cgit From 9a778bddfe3bb8e5124805456d23bafdf7b8dbec Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Jul 2006 14:36:39 +0000 Subject: s/avahi/pulseuaiod/ git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1058 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/README.html.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/README.html.in b/doc/README.html.in index 9076758e..4937deb3 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -344,9 +344,9 @@ PulseAudio.

        There's a chance to meet the PulseAudio developers on our IRC channel #pulseaudio on irc.freenode.org.

        -

        The main project homepage is http://avahi.org/.

        +

        The main project homepage is http://pulseaudio.org/.

        -

        Please report bugs to our Trac ticket system.

        +

        Please report bugs to our Trac ticket system.


        Lennart Poettering <@PACKAGE_BUGREPORT@>, July 2006
        -- cgit From e16cdb50bd1a38403cd7aac7922461bc23fe918c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Jul 2006 16:05:20 +0000 Subject: remove all docs from tarball since they are now available on pulseaudio.org git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1059 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 18 +- README | 1 + configure.ac | 28 --- doc/FAQ.html.in | 295 ------------------------------ doc/Makefile.am | 23 +-- doc/README.html.in | 356 ------------------------------------ doc/cli.html.in | 220 ----------------------- doc/daemon.html.in | 88 --------- doc/modules.html.in | 510 ---------------------------------------------------- doc/style.css | 27 --- 10 files changed, 3 insertions(+), 1563 deletions(-) create mode 100644 README delete mode 100644 doc/FAQ.html.in delete mode 100644 doc/README.html.in delete mode 100644 doc/cli.html.in delete mode 100644 doc/daemon.html.in delete mode 100644 doc/modules.html.in delete mode 100644 doc/style.css diff --git a/Makefile.am b/Makefile.am index 8a0eaf49..0884476d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,7 +17,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -EXTRA_DIST = bootstrap.sh LICENSE GPL LGPL doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in libtool.m4 ltdl.m4 +EXTRA_DIST = bootstrap.sh LICENSE GPL LGPL doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in libtool.m4 ltdl.m4 README SUBDIRS=libltdl src doc doxygen MAINTAINERCLEANFILES = @@ -41,27 +41,11 @@ pkgconfig_DATA += \ libpulse-mainloop-glib12.pc endif -if USE_LYNX -EXTRA_DIST += README -MAINTAINERCLEANFILES += README -noinst_DATA += README - -README: - rm -f README - $(MAKE) -C doc README - cd $(srcdir) && ln -s doc/README README -endif - homepage: all dist doxygen test -d $$HOME/homepage/private mkdir -p $$HOME/homepage/private/projects/pulseaudio $$HOME/homepage/private/projects/pulseaudio/doxygen cp pulseaudio-@PACKAGE_VERSION@.tar.gz $$HOME/homepage/private/projects/pulseaudio - cp doc/README.html doc/FAQ.html doc/cli.html doc/daemon.html doc/modules.html doc/style.css $$HOME/homepage/private/projects/pulseaudio cp -a doxygen/html/* $$HOME/homepage/private/projects/pulseaudio/doxygen - ln -sf $$HOME/homepage/private/projects/pulseaudio/README.html $$HOME/homepage/private/projects/pulseaudio/index.html - -#distcleancheck: -# @: doxygen: $(MAKE) -C doxygen doxygen diff --git a/README b/README new file mode 100644 index 00000000..005ddf4a --- /dev/null +++ b/README @@ -0,0 +1 @@ +For more information see http://pulseaudio.org/ diff --git a/configure.ac b/configure.ac index 3b02df5a..6b82effd 100644 --- a/configure.ac +++ b/configure.ac @@ -100,29 +100,6 @@ if test "x$GCC" = "xyes" ; then done fi -# LYNX documentation generation -AC_ARG_ENABLE(lynx, - AC_HELP_STRING(--disable-lynx,Turn off lynx usage for documentation generation), -[case "${enableval}" in - yes) lynx=yes ;; - no) lynx=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --disable-lynx) ;; -esac],[lynx=auto]) - -if test x$lynx != xno ; then - AC_CHECK_PROG(have_lynx, lynx, yes, no) - - if test x$have_lynx = xno ; then - if test x$lynx = xyes ; then - AC_MSG_ERROR([*** lynx not found]) - else - AC_MSG_WARN([*** lynx not found, plain text README will not be built ***]) - fi - fi -fi - -AM_CONDITIONAL([USE_LYNX], [test "x$have_lynx" = xyes]) - #### libtool stuff #### AC_LTDL_ENABLE_INSTALL @@ -701,13 +678,8 @@ libpulse-browse.pc libpulse-mainloop-glib.pc libpulse-mainloop-glib12.pc doc/Makefile -doc/README.html -doc/cli.html -doc/daemon.html -doc/modules.html doxygen/Makefile doxygen/doxygen.conf src/pulse/version.h -doc/FAQ.html ]) AC_OUTPUT diff --git a/doc/FAQ.html.in b/doc/FAQ.html.in deleted file mode 100644 index 39b7390a..00000000 --- a/doc/FAQ.html.in +++ /dev/null @@ -1,295 +0,0 @@ - - - - -PulseAudio: FAQ - - - - - - -

        Frequently Asked Questions

        - -
          -
        1. How does PulseAudio compare with ESOUND/aRts/NAS?

          - -

          PulseAudio is sound daemon similar to ESOUND and NAS, but much more - powerful. aRts is a realtime-synthesizer-cum-sound-server, i.e. it - does much more than PulseAudio. However, I believe that PulseAudio - does what it does much better than any other free sound server.

          -
        2. - -
        3. What about ESOUND compatibility?

          -

          PulseAudio is a drop in replacement for ESOUND. That means: you can - load a esound compatibility module which implements an ESOUND - compatible protocol which allows you to use most of the classic ESOUND - compatible programs (including the command line programs like - esdcat).

          -
        4. - -
        5. Is PulseAudio a GNOME program?

          -

          No, PulseAudio has no dependency on GNOME/GTK/GLIB. All it requires - is a UNIX-like operating system and very few dependency - libraries. However, the accompanying GUI tools are written with - gtkmm, i.e. require both GLIB and GTK.

        6. - -
        7. Can I integrate PulseAudio in my GLIB/GTK/GNOME application?

          -

          Yes! PulseAudio comes with a GLIB main loop adapter. You can embed - both the client library and the daemon (!) into your GLIB based - application.

        8. - -
        9. Can I integrate PulseAudio in my Qt/KDE application?

          -

          Yes! PulseAudio uses a main loop abstraction layer that allows you - to integrate PulseAudio in any program that supports main - loops. Unfortunately there is no adapter for Qt publicly available yet.

        10. - -
        11. I want to write a new driver for PulseAudio, are there any docs?

          -

          Currently, only the client API is documented with doxygen. Read - the source and base your work on a simple module like - module-pipe-sink.

        12. - -
        13. What about compatibility with NAS?

          -

          Is not available (yet?). It is doable, but noone has implemented it yet.

        14. - -
        15. What about compatibility with aRts?

          -

          Is not available. Since aRts is as synthesizer application you'd have to - reimplement very much code for PulseAudio. It should be easy to - implement limited support for libartsc based - applications. Noone has done this yet. It is probably a better idea to - run arts on top of PulseAudio (through a PulseAudio driver - for aRts, which nobody has written yet). Another solution would be to - embed PulseAudio in the aRts process.

        16. - -
        17. I often hear noises when playing back with PulseAudio, what can I do?

          -

          There are to possible solutions: run PulseAudio with argument ---high-priority=1 and make yourself member of the group -realtime, or increase the fragment sizes of the audio - drivers. The former will allow PulseAudio to activate - SCHED_FIFO high priority scheduling (root rights are dropped - immediately after this). Keep in mind that this is a potential security hole!

        18. - -
        19. The pulseaudio executable is installed SUID root by default. Why this? Isn't this a potential security hole?

          - -

          PulseAudio activates SCHED_FIFO scheduling if the user -passes --high-priority=1. This will only succeed when -executed as root, therefore the binary is marked SUID root by -default. Yes, this is a potential security hole. However, PulseAudio -tries its best to minimize the security threat: immediately after -startup PulseAudio drops all capabilities except -CAP_SYS_NICE (At least on systems that support it, like Linux; see man 7 -capabilities for more information). If the calling user is not a -member of the group realtime (which is required to have a GID -< 1000), root rights are dropped immediately. This means, you can -install pulseaudio SUID root, but only a subset of your users (the -members of the group realtime) may make use of realtime -scheduling. Keep in mind that these users might load their own binary -modules into the PulseAudio daemon which may freeze the machine. The -daemon has a minimal protection against CPU hogging (the daemon is -killed after hogging more than 70% CPU for 5 seconds), but this may -be circumvented easily by evildoers.

        20. - -
        21. I want to run PulseAudio only when it is needed, how do I do this?

          - -

          Set autospawn = yes in client.conf. That -configuration file may be found either in /etc/pulse/ or -in ~/.pulse/.

        22. - -
        23. How do I list all PulseAudio modules installed?

          - -

          pulseaudio --dump-modules

          - -

          Add -v for terse usage instructions.

          - -
        24. How do I use PulseAudio over the network?

          - -

          Just set $PULSE_SERVER to the host name of the PulseAudio -server. For authentication you need the same auth cookies on all sides. For -that copy ~./pulse-cookie to all clients that shall -be allowed to connect.

          - -

          Alternatively the authorization cookies can be stored in the X11 server.

        25. - -
        26. Is PulseAudio capable of providing synchronized audio playback over the network for movie players like mplayer?

          - -

          Yes! Unless your network is congested in some way (i.e. transfer latencies vary strongly) it works perfectly. Drop me an email for experimental patches for MPlayer.

          - -
        27. What environment variables does PulseAudio care about?

          - -

          The client honors: PULSE_SINK (default sink to connect to), PULSE_SOURCE (default source to connect to), PULSE_SERVER (default server to connect to, like ESPEAKER), PULSE_BINARY (the binary to start when autospawning a daemon), PULSE_CLIENTCONFIG (path to the client configuration file).

          - -

          The daemon honors: PULSE_SCRIPT (default CLI script file run after startup), PULSE_CONFIG (default daemon configuration file), PULSE_DLPATH (colon separated list of paths where to look for modules)

        28. - - -
        29. I saw that SIGUSR2 provokes loading of the module module-cli-protocol-unix. But how do I make use of that?

          - -

          A brilliant guy named Lennart Poettering once wrote a nifty tool -for that purpose: bidilink. To -connect to a running PulseAudio daemon try using the following commands:

          - -
          killall -USR2 pulseaudio
          -bidilink unix-client:/tmp/pulse-$USER/cli
          - -

          BTW: Someone should package this great tool for Debian!

          - -

          New: There's now a tool pacmd that automates sending SIGUSR2 to the daemon and running a bidilink like tool for you.

          -
        30. - -
        31. How do the PulseAudio libraries decide where to connect to?

          -

          The following rule applies:

          -
            -
          1. If the the application using the library specifies a server to connect to it is used. If the connection fails, the library fails too.
          2. -
          3. If the environment variable PULSE_SERVER is defined the library connects to that server. If the connection fails, the library fails too.
          4. -
          5. If $DISPLAY is set, the library tries to connect to that server and looks for the root window property POYLP_SERVER for the host to connect to. If PULSE_COOKIE is set it is used as authentication cookie.
          6. -
          7. If the client configuration file (~/.pulse/client.conf or /etc/pulse/client.conf) sets the server address, the library connects to that server. If the connection fails, the library fails too.
          8. -
          9. The library tries to connect to the default local UNIX socket for PulseAudio servers. If the connection fails, it proceeds with the next item.
          10. -
          11. The library tries to connect to the default local TCP socket for PulseAudio servers. If the connection fails, it proceeds with the next item.
          12. -
          13. If $DISPLAY is set, the library tries to connect to the default TCP port of that host. If the connection fails, it proceeds with the next item.
          14. -
          15. The connection fails.
          16. -
          -
        32. - -
        33. Why the heck does libpulse link against libX11?

          -

          The PulseAudio client libraries look for some X11 root window -properties for the credentials of the PulseAudio server to access. You -may compile PulseAudio without X11 for disabling this feature.

        34. - -
        35. How can I use PulseAudio as an RTP based N:N multicast -conferencing solution for the LAN?

          After loading all the -necessary audio drivers for recording and playback, just load the RTP -reciever and sender modules with default parameters:

          - -
          -load-module module-rtp-send
          -load-module module-rtp-recv
          -
          - -

          As long as the PulseAudio daemon runs, the microphone data will be -streamed to the network and the data from other hosts is played back -locally. Please note that this may cause quite a lot of traffic. Hence -consider passing rate=8000 format=ulaw channels=1 to the -sender module to save bandwith while still maintaining good quality -for speech transmission.

        36. - -
        37. What is this RTP/SDP/SAP thing all about?

          - -

          RTP is the Realtime Transfer Protocol. It is a well-known -protocol for transferring audio and video data over IP. SDP is the Session -Description Protocol and can be used to describe RTP sessions. SAP -is the Session Announcement Protocol and can be used to -announce RTP sessions that are described with SDP. (Modern SIP based VoIP phones use RTP/SDP for their sessions, too)

          - -

          All three protocols are defined in IETF RFCs (RFC3550, RFC3551, -RFC2327, RFC2327). They can be used in both multicast and unicast -fashions. PulseAudio exclusively uses multicast RTP/SDP/SAP containing audio data.

          - -

          For more information about using these technologies with PulseAudio have a look on the respective module's documentation. - -

        38. How can I use PulseAudio to stream music from my main PC to my LAN with multiple PCs with speakers?

          - -

          On the sender side create an RTP sink:

          - -
          -load-module module-null-sink sink_name=rtp
          -load-module module-rtp-send source=rtp_monitor
          -set-default-sink rtp
          -
          - -

          This will make rtp the default sink, i.e. all applications will write to this virtual RTP device by default.

          - -

          On the client sides just load the reciever module:

          -
          -load-module module-rtp-recv
          -
          - -

          Now you can play your favourite music on the sender side and all clients will output it simultaneously.

          - - -

          BTW: You can have more than one sender machine set up like this. The audio data will be mixed on the client side.

        39. - -
        40. How can I use PulseAudio to share a single LINE-IN/MIC jack on the entire LAN?

          - -

          On the sender side simply load the RTP sender module:

          - -
          -load-module module-rtp-send
          -
          - -

          On the reciever sides, create an RTP source:

          - -
          -load-module module-null-sink sink_name=rtp
          -load-module module-rtp-recv sink=rtp
          -set-default-source rtp_monitor
          -
          - -

          Now the audio data will be available from the default source rtp_monitor.

        41. - -
        42. When sending multicast RTP traffic it is recieved on the entire LAN but not by the sender machine itself!

          - -

          Pass loop=1 to the sender module!

        43. - -
        44. Can I have more than one multicast RTP group?

          - -

          Yes! Simply use a new multicast group address. Use -the destination/sap_address arguments of the RTP -modules to select them. Choose your group addresses from the range -225.0.0.x to make sure the audio data never leaves the LAN.

        45. - - -
        46. Can I use PulseAudio to playback music on two sound cards simultaneously?

          - -

          Yes! Use module-combine for that.

          - -
          -load-module module-oss-mmap device="/dev/dsp" sink_name=output0
          -load-module module-oss-mmap device="/dev/dsp1" sink_name=output1
          -load-module module-combine sink_name=combined master=output0 slaves=output1
          -set-sink-default combined
          -
          - -

          This will combine the two sinks output0 and -output1 into a new sink combined. Every sample -written to the latter will be forwarded to the former two. PulseAudio -will make sure to adjust the sample rate of the slave device in case -it deviates from the master device. You can have more than one slave -sink attached to the combined sink, and hence combine even three and -more sound cards.

        47. - -
        48. Can I use PulseAudio to combine two stereo soundcards into a virtual surround sound card?

          - -

          Yes! You can use use module-combine for that.

          - -
          -load-module module-oss-mmap device="/dev/dsp" sink_name=output0 channel_map=left,right channels=2
          -load-module module-oss-mmap device="/dev/dsp1" sink_name=output1 channel_map=rear-left,rear-right channels=2
          -load-module module-combine sink_name=combined master=output0 slaves=output1 channel_map=left,right,rear-left,rear-right channels=4
          -
          - -

          This is mostly identical to the previous example. However, this -time we manually specify the channel mappings for the sinks to make -sure everything is routed correctly.

          - -

          Please keep in mind that PulseAudio will constantly adjust the -sample rate to compensate for the deviating quartzes of the sound -devices. This is not perfect, however. Deviations in a range of -1/44100s (or 1/48000s depending on the sampling frequency) can not be -compensated. The human ear will decode these deviations as minor -movements (less than 1cm) of the positions of the sound sources -you hear.

          - -
        49. - -
        50. Why did you rename Polypaudio to PulseAudio?

          - -

          Please read this blog story for an explanation.

          - -
        51. - -
        - -
        -
        Lennart Poettering <@PACKAGE_BUGREPORT@>, April 2006
        -
        $Id$
        - diff --git a/doc/Makefile.am b/doc/Makefile.am index a58911ad..1e9fe244 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -16,26 +16,5 @@ # along with PulseAudio; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -noinst_DATA = README.html cli.html modules.html daemon.html FAQ.html -EXTRA_DIST = $(noinst_DATA) style.css README.html.in cli.html.in modules.html.in daemon.html.in todo FAQ.html.in - -MAINTAINERCLEANFILES = README.html cli.html modules.html daemon.html FAQ.html -CLEANFILES = - -if USE_LYNX -README: README.html - lynx --dump $^ | sed 's,file://localhost/.*/doc/README.html,README,' > $@ - -noinst_DATA += README -CLEANFILES += README -endif - -tidy: README.html cli.html modules.html daemon.html - tidy -qe < README.html ; true - tidy -qe < cli.html ; true - tidy -qe < daemon.html ; true - tidy -qe < modules.html ; true - tidy -qe < FAQ.html ; true - -.PHONY: tidy +EXTRA_DIST = todo diff --git a/doc/README.html.in b/doc/README.html.in deleted file mode 100644 index 4937deb3..00000000 --- a/doc/README.html.in +++ /dev/null @@ -1,356 +0,0 @@ - - - - - -PulseAudio @PACKAGE_VERSION@ - - - - -

        PulseAudio @PACKAGE_VERSION@

        - -

        Copyright 2004-2006 Lennart Poettering <@PACKAGE_BUGREPORT@> and Pierre Ossman

        - - - -

        License

        - -

        This program is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version.

        - -

        This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details.

        - -

        You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

        - -

        News

        - -
        Fri Jul 7 2006:

        Version 0.9.2 -released; changes include: rename project to PulseAudio (see this blog -article for an explanation); increase maximum number of concurrent -connections; fix latency interpolation; add support for reverse endian -sound cards; add support for recording in padsp; reenable CPU -load limiter; other bugfixes

        - -
        Fri Jun 2 2006:

        Version 0.9.1 -released; changes include: load modules even when libtool .la -files are missing; generate better ALSA device names from -module-detect; if an ALSA device doesn't support the -requested number of channels or the frequency, accept what ALSA -suggests instead; amd64 portability; drop .sh suffix of -esdcompat.sh; build system fixes; No API or ABI changes were made

        - -
        Fri May 26 2006:

        Version 0.9.0 -released; changes include: new module module-volume-restore; -new OSS API emulation tool padsp; require valid UTF8 strings -everywhere; properly support ALSA channel maps for surround sound; -increase maximum number of channels per stream to 32; add new threaded -main loop API for synchronous programs; introduce real shared object -versioning; a few API additions; many, many bugfixes

        - -
        Fri Apr 28 2006:

        Version 0.8.1 -released; changes include: support for specifying the channel map on -the command lines of paplay and pacat and as -arguments to the driver modules; ALSA hardware mixer compatibility; -fix linking; properly remove PF_UNIX sockets when unloading -protocol modules; fix sample cache; many other fixes

        - -
        Thu Apr 13 2006:

        Version 0.8 released; -changes include: too many to count - consider reading this blog entry for more information; many, many minor fixes.

        - -
        Sun Nov 21 2004:

        Version 0.7 released; -changes include: IPv6 support; PID file support; publish credentials -in X11 root window (module-x11-publish; new tool pacmd; ESOUND backend; new command load-sample-dir-lazy; many, many minor fixes.

        - -
        Thu Oct 28 2004:

        Version 0.6 released; -changes include: TCP wrappers support; don't load the complete sound -file into memory when playing back using pa_play_file(); -autoload API change; don't load all sound files as FLOAT32; shorten -default buffers; client-side latency interpolation; add new user -volume metrics; add module-tunnel, module-null-sink, -module-match and new tool paplay; new API version -macros; many client API improvements; correctly lock cookie file -generation; correctly lock daemon autospawning; print daemon layout to -STDERR on SIGHUP; new options for pacat: allow sample type specification.

        - -
        Mon Sep 24 2004:

        Version 0.5.1 released; -changes include: improve esound protocol compatibility; fix -autospawning via libesd; make use of POSIX capabilities; -allow SCHED_FIFO scheduling only for users in group -realtime; minor build system fix.

        - -
        Mon Sep 20 2004:

        Version 0.5 released; -changes include: extensive API improvements, new module -module-combine for combining multiple sound cards into one, -gcc 2.95 compatibility, configuration files, add "lazy" samples, -support for source and network latency measurements, add -module-pipe-source, many other fixes and improvements.

        - -
        Wed Sep 8 2004:

        Version 0.4 released; -changes include: daemon auto spawning, support for SCHED_FIFO scheduling, three new modules, proper logging, CPU load watchdog, many fixes.

        - -
        Fri Aug 27 2004:

        Version 0.3 released; -changes include: support for both glib 2.0 and glib 1.2, future cancellation, API updates, many fixes, relicense client library to LGPL.

        - -
        Fri Aug 20 2004:

        Version 0.2 released; -changes include: added sample cache, introspection API, client API -documentation, module autoloading, glib support, a module for intercepting X11 bell events, and much more.

        - -
        Sat Jul 17 2004:

        Version 0.1 released

        - -

        Overview

        - -

        PulseAudio is a networked sound server for Linux and other -Unix like operating systems and Microsoft Windows. It is intended to be an improved drop-in -replacement for the Enlightened Sound -Daemon (ESOUND). In addition to the features ESOUND provides -PulseAudio has:

        - -
          -
        • Extensible plugin architecture (by loading dynamic loadable modules with dlopen())
        • -
        • Support for more than one sink/source
        • -
        • Better low latency behaviour
        • -
        • Embedabble into other software (the core is available as C library)
        • -
        • Completely asynchronous C API
        • -
        • Simple command line interface for reconfiguring the daemon while running
        • -
        • Flexible, implicit sample type conversion and resampling
        • -
        • "Zero-Copy" architecture
        • -
        • Module autoloading
        • -
        • Very accurate latency measurement for playback and recording.
        • -
        • May be used to combine multiple sound cards to one (with sample rate adjustment)
        • -
        • Client side latency interpolation
        • -
        • Ability to fully synchronize multiple playback streams
        • -
        - -

        Both the core and the client API are completely asynchronous making -use of a simple main loop abstraction layer. This allows easy -integration with asynchronous applications using the -glib/gtk mainloop. Since the asynchronous API -available through libpulse is quite difficult to use there is -a simplified synchronous API wrapper libpulse-simple -available. A simple main loop implementation is available as well.

        - -

        The following modules are currently available:

        - -
          -
        • module-oss: driver for Open Sound System (OSS) audio sinks and sources.
        • -
        • module-oss-mmap: same as above, but uses mmap() access to the audio buffer. Not as compatible bot more accurate in latency calculations
        • -
        • module-alsa-sink, module-alsa-source: drivers for Advanced Linux -Sound Architecture (ALSA) sinks and sources
        • -
        • module-solaris: drivers for Solaris audio sinks and sources
        • -
        • module-waveout: drivers for Microsoft Windows audio sinks and sources
        • -
        • module-pipe-sink, module-pipe-source: demonstration module providing UNIX FIFOs backed sinks/sources
        • -
        • module-combine: combine multiple sinks into one, adjusting the sample rate if the their clocks deviate.
        • -
        • module-sine: a sine generate sink input.
        • -
        • module-x11-bell: play a sample from the sample cache on every X11 bell event.
        • -
        • module-x11-publish: store PulseAudio credentials in the X11 root window.
        • -
        • module-esound-protocol-tcp, module-esound-protocol-unix: ESOUND compatibility modules (for TCP/IP resp. UNIX domain sockets)
        • -
        • module-native-protocol-tcp, module-native-protocol-unix: Native PulseAudio protocol (for TCP/IP resp. UNIX domain sockets)
        • -
        • module-simple-protocol-tcp, module-simple-protocol-unix: Simplistic protocol for playback/capture for usage with tools like netcat (for TCP/IP resp. UNIX domain sockets)
        • -
        • module-cli-protocol-tcp, module-cli-protocol-unix, module-cli: Expose PulseAudio's internals whith a simple command line interface. (for TCP/IP resp. UNIX domain sockets resp. STDIN/STDOUT)
        • -
        • module-http-protocol-tcp: Spawns a small HTTP server which can be used to introspect the PulseAudio server with a web browser.
        • -
        • module-tunnel-sink, module-tunnel-source: make sinks/sources from other hosts available locally.
        • -
        • module-match: adjust volume automatically for newly created playback streams based on a regular expression matching table.
        • -
        • module-volume-restore: much like module-match, but create rules fully automatically based on the client name.
        • -
        • module-null-sink: a clocked sink similar to /dev/null.
        • -
        • module-esound-sink: a sink for forwarding audio data to an ESOUND server.
        • -
        • module-detect: a module which automatically detects what sound hardware is available locally and which loads the required driver modules.
        • -
        • module-lirc: a module to control the volume of a sink with infrared remote controls supported by LIRC.
        • -
        • module-mmkbd-evdev: a module to control the volume of a sink with the special volume keys of a multimeda keyboard.
        • -
        • module-zeroconf-publish: a module to publish local sources/sinks using mDNS zeroconf.
        • -
        • module-rtp-send, module-rtp-recv: modules to implement RTP/SAP/SDP based audio streaming.
        • -
        • module-jack-sink, module-jack-source: connect to a JACK Audio Connection Kit server. (A sound server for professional audio production)
        • -
        - -

        A GTK GUI manager application for PulseAudio is the PulseAudio -Manager. Other GTK GUI tool for PulseAudio are the PulseAudio Volume -Meter, PulseAudio Device Chooser and the PulseAudio Volume -Control .

        - -

        There are output plugins for XMMS, libao -(merged in libao SVN) and gstreamer -(merged in gstreamer-plugins CVS).

        - -

        PulseAudio was formerly known as Polypaudio.

        - -

        Current Status

        - -

        Version @PACKAGE_VERSION@ is quite usable. It matches and supersedes ESOUND's feature set in nearly all areas.

        - -

        Documentation

        - -

        There is some preliminary documentation available: modules.html, cli.html, daemon.html and FAQ.html.

        - -

        There is a Trac based Wiki for PulseAudio available.

        - -

        First Steps

        - -

        Simply start the PulseAudio daemon with the argument -nC

        - -
        pulseaudio -nC
        - -

        This will present you a screen like this:

        - -
        Welcome to PulseAudio! Use "help" for usage information.
        ->>> 
        - -

        Now you can issue CLI commands as described in cli.html. Another way to start -PulseAudio is by specifying a configuration script like that one included in the distribution on the -command line :

        - -
        pulseaudio -nF pulseaudio.pa
        - -

        This will load some drivers and protocols automatically.

        - -

        The best idea is to configure your daemon in /etc/pulse/daemon.conf and /etc/pulse/default.pa and to run PulseAudio without any arguments.

        - -

        Beware! Unless you pass the option --sysconfdir=/etc to -configure, the directory /etc/pulse/ is really -/usr/local/etc/pulse/.

        - -

        Developing PulseAudio Clients

        - -

        You may browse the Doxygen generated programing -documentation for the client API. (Run make doxygen to generate this documentation from the source tree)

        - -

        Developing PulseAudio Modules

        - -

        There are several reasons for writing loadable modules for PulseAudio:

        - -
          -
        • Extended device driver support
        • -
        • Protocol support beyond ESOUND's protocol and the native protocol. (such as NAS or a subset of aRts)
        • -
        • New programming interfaces such as XMLRPC or DBUS for controlling the daemon.
        • -
        • Hooking audio event sources directly into PulseAudio (similar to module-x11-bell)
        • -
        • For low latency applications such as VOIP: load the VOIP core directly into PulseAudio and have a slim GUI frontend to control it.
        • -
        - -

        There is currently no documentation how to write loadable modules -for PulseAudio. Read the source, Luke! If you are interested in -writing new modules feel free to contact the author in case you have any -questions.

        - -

        Requirements

        - -

        Currently, PulseAudio> is tested on Linux, FreeBSD, Solaris and Microsoft Windows. It requires an OSS, ALSA, Win32 or Solaris compatible soundcard.

        - -

        PulseAudio was developed and tested on Debian GNU/Linux -"testing" from November 2004, it should work on most other Linux -distributions (and maybe Unix versions) since it uses GNU autoconf and -GNU libtool for source code configuration and shared library -management.

        - -

        Pulseaudio needs Secret Rabbit Code (aka -libsamplerate), libsndfile, liboil.

        - -

        Optionally it can make use of libwrap, alsa-lib, libasyncns, -lirc, HOWL (or preferably the compatibility layer included in its superior replacement Avahi) and GLIB. (The latter is required for -building the GLIB main loop integration module only.)

        - -

        Installation

        - -

        As this package is made with the GNU autotools you should run -./configure inside the distribution directory for configuring -the source tree. After that you should run make for -compilation and make install (as root) for installation of -PulseAudio.

        - -

        Acknowledgements

        - -

        Eric B. Mitchell for writing ESOUND

        - -

        Jeff Waugh for creating Ubuntu packages (and hopefully soon Debian)

        - -

        Miguel Freitas for writing a PulseAudio driver for Xine

        - -

        Joe Marcus Clarke for porting PulseAudio to FreeBSD

        - -

        Cendio AB for paying for Pierre's work on PulseAudio

        - -

        Sebastien ESTIENNE for testing

        - -

        Igor Zubkov for some portability patches

        - -

        Jan Schmidt for some latency interpolation love

        - -

        Download

        - -

        The newest release is always available from @PACKAGE_URL@

        - -

        The current release is @PACKAGE_VERSION@

        - -

        Get PulseAudio's development sources from the Subversion repository (ViewCVS, Trac):

        - -
        svn checkout svn://0pointer.de/pulseaudio/trunk pulseaudio
        - -

        Community

        - -

        If you want to be notified whenever I release a new version of this software use the subscription feature of Freshmeat.

        - -

        There is a general discussion mailing list for PulseAudio available. In addition, you can subscribe to SVN changes and Trac Tickets.

        - -

        PulseAudio is being tracked at CIA.

        - -

        There's a chance to meet the PulseAudio developers on our IRC channel #pulseaudio on irc.freenode.org.

        - -

        The main project homepage is http://pulseaudio.org/.

        - -

        Please report bugs to our Trac ticket system.

        - -
        -
        Lennart Poettering <@PACKAGE_BUGREPORT@>, July 2006
        -
        $Id$
        - - - diff --git a/doc/cli.html.in b/doc/cli.html.in deleted file mode 100644 index 3a256732..00000000 --- a/doc/cli.html.in +++ /dev/null @@ -1,220 +0,0 @@ - - - - -PulseAudio: Simple Command Line Language - - - - -

        Simple Command Line Language

        - -

        PulseAudio provides a simple command line language used by -configuration scripts as well as the modules module-cli -and module-cli-protocol-{unix,tcp}. Empty lines and lines -beginning with a hashmark (#) are silently ignored. Several -commands are supported:

        - -

        Miscellaneous Commands

        - -

        help

        - -

        Show a quick help on the commands available.

        - -

        exit

        - -

        Terminate the daemon. If you want to terminate a CLI connection -("log out") you might want to use C-d.

        - -

        Status Commands

        - -

        list-modules

        - -

        Show all currently loaded modules with their arguments.

        - -

        list-sinks/list-sources

        - -

        Show all currently registered sinks (resp. sources).

        - -

        list-clients

        - -

        Show all currently active clients.

        - -

        list-sink-inputs/list-sink-outputs

        - -

        Show all currently active inputs to sinks (resp. outputs of sources).

        - -

        stat

        - -

        Show some simple statistics about the allocated memory blocks and -the space used by them.

        - -

        info

        - -

        A combination of all status commands described above. ls -and list are synonyms for info.

        - -

        Module Management

        - -

        load-module

        - -

        Load a module specified by its name and arguments. For most modules -it is OK to be loaded more than once.

        - -

        unload-module

        - -

        Unload a module specified by its index in the module list as -returned by modules.

        - -

        Configuration Commands

        - -

        set-sink-volume/set-source-volume

        - -

        Set the volume of the specified sink or source. You may specify the sink/source either -by its index in the sink/source list or by its name. The volume should be an -integer value greater or equal than 0 (= muted). Volume 65536 -(0x10000) is normal volume, values greater than this amplify -the audio signal (with clipping).

        - -

        set-sink-mute/set-source-mute

        - -

        Mute or unmute the specified sink our source. You may specify the -sink/source either by its index or by its name. The mute value is -either 0 or 1.

        - -

        set-sink-input-volume

        - -

        Set the volume of a sink input specified by its index the the sink -input list. The same volume rules apply as with sink_volume.

        - -

        set-default-sink/set-default-source

        - -

        Make a sink (resp. source) the default. You may specify the sink -(resp. ssource) by its index in the sink (resp. source) list or by its -name.

        - -

        Sample Cache

        - -

        list-samples

        - -

        Lists the contents of the sample cache.

        - -

        play-sample

        - -

        Play a sample cache entry to a sink. Expects the sample name and the sink name as arguments.

        - -

        remove-sample

        - -

        Remove an entry from the sample cache. Expects the sample name as argument.

        - -

        load-sample

        - -

        Load an audio file to the sample cache. Expects the file name to load and the desired sample name as arguments.

        - -

        load-sample-lazy

        - -

        Create a new entry in the sample cache, but don't load the sample -immediately. The sample is loaded only when it is first used. After a -certain idle time it is freed again. Expects the the desired sample -name and file name to load as arguments.

        - -

        load-sample-dir-lazy

        - -

        Load all entries in the specified directory into the sample cache -as lazy entries. A shell globbing expression (e.g. *.wav) may -be appended to the path of the directory to add.

        - -

        Module Autoloading

        - -

        list-autoload

        - -

        Lists all currently defined autoloading entries.

        - -

        add-autoload-sink/add-autoload-source

        - -

        Adds an autoloading entry for a sink (resp. source). Expects the sink name (resp. source name), the module name and the module arguments as arguments.

        - -

        remove-autoload-sink/remove-autoload-source

        - -

        Remove an autoloading entry. Expects the sink name (resp. source name) as argument.

        - -

        Miscellaneous Commands

        - -

        play-file

        - -

        Play an audio file to a sink. Expects the file name and the sink name as argumens.

        - -

        dump

        - -

        Dump the daemon's current configuration in CLI commands.

        - -

        Killing Clients/Streams

        - -

        kill-client

        - -

        Remove a client forcibly from the server. There is no protection that -the client reconnects immediately.

        - -

        kill-sink-input/kill-source-output

        - -

        Remove a sink input (resp. source output) forcibly from the -server. This will not remove the owning client or any other streams -opened by the client from the server.

        - -

        Meta Commands

        - -

        In addition the the commands described above there a few meta -directives supported by the command line interpreter:

        - -

        .include

        - -

        Executes the commands from the specified script file.

        - -

        .fail/.nofail

        - -

        Enable (resp. disable) that following failing commands will cancel -the execution of the current script file. This is a ignored when used -on the interactive command line.

        - -

        .verbose/.noverbose

        -

        Enable (resp. disable) extra verbosity.

        - -

        Example Configuration Script

        - -

        Mark the following script as executable (chmod +x) and run it for a sensible PulseAudio configuration.

        - -
        -#!/usr/bin/polaudio -nF
        -
        -# Create autoload entries for the device drivers
        -add-autoload-sink output module-alsa-sink device=plughw:0,0 rate=48000 sink_name=output
        -add-autoload-sink output2 module-oss device=/dev/dsp1 record=0 sink_name=output2
        -add-autoload-sink combined module-combine master=output slaves=output2 sink_name=combined
        -
        -add-autoload-source input module-alsa-source device=hw:1,0 source_name=input
        -
        -# Load several protocols
        -load-module module-esound-protocol-unix
        -load-module module-simple-protocol-tcp
        -load-module module-native-protocol-unix
        -load-module module-cli-protocol-unix
        -
        -# Make some devices default
        -set-default-sink combined
        -set-default-source input
        -
        -# Don't fail if the audio files referred to below don't exist
        -.nofail
        -
        -# Load an audio to the sample cache for usage with module-x11-bell
        -load-sample-lazy  /usr/share/sounds/KDE_Notify.wav x11-bell
        -load-module module-x11-bell sample=x11-bell
        -
        -# Play a welcome sound
        -play-file /usr/share/sounds/startup3.wav combined
        -
        - -
        -
        Lennart Poettering <@PACKAGE_BUGREPORT@>, June 2006
        -
        $Id$
        - diff --git a/doc/daemon.html.in b/doc/daemon.html.in deleted file mode 100644 index d90caa2a..00000000 --- a/doc/daemon.html.in +++ /dev/null @@ -1,88 +0,0 @@ - - - - -PulseAudio: Daemon - - - - -

        Daemon

        - -

        Command Line Arguments

        - -The PulseAudio daemon accepts several command line arguments: - -
        -COMMANDS:
        -  -h, --help                            Show this help
        -      --version                         Show version
        -      --dump-conf                       Dump default configuration
        -      --dump-modules                    Dump list of available modules
        -  -k  --kill                            Kill a running daemon
        -      --check                           Check for a running daemon
        -
        -OPTIONS:
        -  -D, --daemonize[=BOOL]                Daemonize after startup
        -      --fail[=BOOL]                     Quit when startup fails
        -      --verbose[=BOOL]                  Be slightly more verbose
        -      --high-priority[=BOOL]            Try to set high process priority
        -                                        (only available as root)
        -      --disallow-module-loading[=BOOL]  Disallow module loading after startup
        -      --exit-idle-time=SECS             Terminate the daemon when idle and this
        -                                        time passed
        -      --module-idle-time=SECS           Unload autoloaded modules when idle and
        -                                        this time passed
        -      --scache-idle-time=SECS           Unload autoloaded samples when idle and
        -                                        this time passed
        -      --log-target={auto,syslog,stderr} Specify the log target
        -  -p, --dl-search-path=PATH             Set the search path for dynamic shared
        -                                        objects (plugins)
        -      --resample-method=[METHOD]        Use the specified resampling method
        -                                        (one of src-sinc-medium-quality,
        -                                        src-sinc-best-quality,src-sinc-fastest
        -                                        src-zero-order-hold,src-linear,trivial)
        -      --use-pid-file[=BOOL]             Create a PID file
        -
        -STARTUP SCRIPT:
        -  -L, --load="MODULE ARGUMENTS"         Load the specified plugin module with
        -                                        the specified argument
        -  -F, --file=FILENAME                   Run the specified script
        -  -C                                    Open a command line on the running TTY
        -                                        after startup
        -
        -  -n                                    Don't load default script file
        -
        - -

        Example

        - -

        It is a good idea to run the daemon like this:

        - -
        pulseaudio -D
        - -

        This will run /etc/pulse/default.pa after startup. This should be a script written in the CLI language described in cli.html.

        - -

        Signals

        - -

        The following signals are trapped specially:

        - -

        SIGINT

        - -

        The daemon is shut down cleanly.

        - -

        SIGUSR1

        - -

        The daemon tries to load the module module-cli, effectively providing a command line interface on the calling TTY.

        - -

        SIGUSR2

        - -

        The daemon tries to load the module module-cli-protocol-unix, effectively providing a command line interface on a special UNIX domain socket.

        - -

        SIGHUP

        - -

        The daemon logs the current server layout.

        - -
        -
        Lennart Poettering <@PACKAGE_BUGREPORT@>, June 2006
        -
        $Id$
        - diff --git a/doc/modules.html.in b/doc/modules.html.in deleted file mode 100644 index 7f12d9a9..00000000 --- a/doc/modules.html.in +++ /dev/null @@ -1,510 +0,0 @@ - - - - -PulseAudio: Loadable Modules - - - - - -

        Loadable Modules

        - -

        The following loadable modules are provided with the PulseAudio distribution:

        - -

        Device Drivers

        - -

        All device driver modules support the following parameters:

        - - - - - -
        format=The sample format (one of u8, s16, s16le, s16le, float32, float32be, float32le, alaw, ulaw) (defaults to s16)
        rate=The sample rate (defaults to 44100)
        channels=Audio channels (defaults to 2)
        sink_name=, source_name=Name for the sink (resp. source)
        channel_map=Channel map. A list of -comma-seperated channel names. The currently defined channel names -are: left, right, mono, center, -front-left, front-right, front-center, -rear-center, rear-left, rear-right, -lfe, subwoofer, front-left-of-center, -front-right-of-center, side-left, -side-right, aux0, aux1 to aux15, -top-center, top-front-left, -top-front-right, top-front-center, -top-rear-left, top-rear-right, -top-rear-center, (Default depends on the number of channels -and the driver)
        - -

        module-pipe-sink

        - -

        Provides a simple test sink that writes the audio data to a FIFO -special file in the file system. The sink name defaults to pipe_output.

        - -

        The following option is supported:

        - - - -
        file=The name of the FIFO special file to use. (defaults to: /tmp/music.output)
        - -

        module-pipe-source

        - -

        Provides a simple test source that reads the audio data from a FIFO -special file in the file system. The source name defaults to pipe_input.

        - -

        The following option is supported:

        - - - -
        file=The name of the FIFO special file to use. (defaults to: /tmp/music.input)
        - - -

        module-null-sink

        - -

        Provides a simple null sink. All data written to this sink is silently dropped. This sink is clocked using the system time.

        - -

        This module doesn't support any special parameters

        - - - -

        module-alsa-sink

        - -

        Provides a playback sink for devices supported by the Advanced Linux -Sound Architecture (ALSA). The sink name defaults to alsa_output.

        - -

        In addition to the general device driver options described above this module supports:

        - - - - - -
        device=The ALSA device to use. (defaults to "plughw:0,0")
        fragments=The desired fragments when opening the device. (defaults to 12)
        fragment_size=The desired fragment size in bytes when opening the device (defaults to 1024)
        - -

        module-alsa-source

        - -

        Provides a recording source for devices supported by the Advanced -Linux Sound Architecture (ALSA). The source name defaults to alsa_input.

        - -

        This module supports device=, fragments= and fragment_size= arguments the same way as module-alsa-sink.

        - - - -

        module-oss

        - -

        Provides both a sink and a source for playback, resp. recording on -Open Sound System (OSS) compatible devices.

        - -

        This module supports device= (which defaults to /dev/dsp), fragments= and fragment_size= arguments the same way as module-alsa-sink.

        - -

        In addition this module supports the following options:

        - - - - -
        record=Accepts a binary numerical value for enabling (resp. disabling) the recording on this device. (defaults: to 1)
        playback=Accepts a binary numerical value for enabling (resp. disabling) the playback on this device. (defaults: to 1)
        - -

        The sink name (resp. source name) defaults to oss_output (resp. oss_input).

        - -

        module-oss-mmap

        - -

        Similar to module-oss but uses memory mapped -(mmap()) access to the input/output buffers of the audio -device. This provides better latency behaviour but is not as -compatible as module-oss.

        - -

        This module accepts exactly the same arguments as module-oss.

        - -

        module-solaris

        - -

        Provides a sink and source for the Solaris audio device.

        - -

        In addition to the general device driver options described above this module supports:

        - - - - - -
        record=Accepts a binary numerical value for enabling (resp. disabling) the recording on this device. (defaults: to 1)
        playback=Accepts a binary numerical value for enabling (resp. disabling) the playback on this device. (defaults: to 1)
        buffer_size=Record buffer size
        - -

        module-waveout

        - -

        Provides a sink and source for the Win32 audio device.

        - -

        This module supports all arguments thet module-oss supports except device=.

        - - -

        module-combine

        - -

        This combines two or more sinks into one. A new virtual sink is -allocated. All data written to it is forwarded to all connected -sinks. In aequidistant intervals the sample rates of the output sinks -is recalculated: i.e. even when the sinks' crystals deviate (which is -normally the case) output appears synchronously to the human ear. The -resampling required for this may be very CPU intensive.

        - - - - - - -
        sink_name=The name for the combined sink. (defaults to combined)
        master=The name of the first sink to link into the combined think. The sample rate/type is taken from this sink.
        slaves=Name of additional sinks to link into the combined think, seperated by commas.
        adjust_time=Time in seconds when to readjust the sample rate of all sinks. (defaults to 20)
        resample_method=Resampling algorithm to -use. See libsamplerate's documentation for more -information. Use one of sinc-best-quality, -sinc-medium-quality, sinc-fastest, -zero-order-hold, linear. If the default happens to -be to slow on your machine try using zero-order-hold. This -will decrease output quality however. (defaults to -sinc-fastest)
        - -

        module-tunnel-{sink,source}

        - -

        Tunnel a remote sink/source to a local "ghost" -sink/source. Requires a running PulseAudio daemon on the remote server -with module-native-protocol-tcp loaded. It's probably a -better idea to connect to the remote sink/source directly since some -buffer control is lost through this tunneling.

        - - - - - - -
        server=The server to connect to
        source=The source on the remote server. Only available for module-tunnel-source.
        sink=The sink on the remote server. Only available for module-tunnel-sink.
        cookie=The authentication cookie file to use.
        - -

        module-esound-sink

        - -

        Create a playback sink using an ESOUND server as backend. Whenever you can, try to omit this -module since it has many disadvantages including bad latency -and even worse latency measurement.

        - - - - -
        server=The server to connect to
        cookie=The authentication cookie file to use.
        - -

        Protocols

        - - - -

        module-cli

        - -

        Provides the user with a simple command line interface on the -controlling TTY of the daemon. This module may not be loaded more than -once.

        - -

        For an explanation of the simple command line language used by this -module see cli.html. - - - -
        exit_on_eof=Accepts a binary numerical argument specifying whether the daemon shuld exit after an EOF was recieved from STDIN (default: 0)
        - - - - - -

        module-cli-protocol-{unix,tcp}

        - -

        An implemenation of a simple command line based protocol for -controlling the PulseAudio daemon. If loaded, the user may -connect with tools like netcat, telnet or -bidilink to the listening sockets and execute commands the -same way as with module-cli.

        - -

        Beware! Users are not authenticated when connecting to this -service.

        - -

        This module exists in two versions: with the suffix -unix -the service will listen on an UNIX domain socket in the local file -system. With the suffix -tcp it will listen on a network -transparent TCP/IP socket. (Both IPv6 and IPv4 - if available)

        - -

        This module supports the following options:

        - - - - - - -
        port=(only for -tcp) The port number to listen on (defaults to 4712)
        loopback=(only for -tcp) Accepts -a numerical binary value. If 1 the socket is bound to the loopback -device, i.e. not publicly accessible. (defaults to 1)
        listen=(only for -tcp) The IP address to listen on. If specified, supersedes the value specified in loopback=
        socket=(only for -unix) The UNIX socket name (defaults to /tmp/pulse/cli)
        - -

        module-simple-protocol-{unix,tcp}

        - -

        An implementation of a simple protocol which allows playback by using -simple tools like netcat. Just connect to the listening -socket of this module and write the audio data to it, or read it from -it for playback, resp. recording.

        - -

        Beware! Users are not authenticated when connecting to this -service.

        - -

        See module-cli-protocol-{unix,tcp} for more information -about the two possible suffixes of this module.

        - -

        In addition to the options supported by module-cli-protocol-*, this module supports:

        - - - - - -
        rate=, format=, channels=Sample format for streams connecting to this service.
        playback=, record=Enable/disable playback/recording
        sink=, source=Specify the sink/source this service connects to
        - -

        module-esound-protocol-{unix,tcp}

        - -

        An implemenation of a protocol compatible with the Enlightened Sound -Daemon (ESOUND, esd). When you load this module you may -access the PulseAudio daemon with tools like esdcat, -esdrec or even esdctl. Many applications, such as -XMMS, include support for this protocol.

        - -

        See module-cli-protocol-{unix,tcp} for more information -about the two possible suffixes of this module.

        - -

        In addition to the options supported by module-cli-protocol-*, this module supports:

        - - - - - -
        sink=, source=Specify the sink/source this service connects to
        auth-anonymous=If set to 1 no authentication is required to connect to the service
        cookie=Name of the cookie file for authentication purposes
        - -

        This implementation misses some features the original ESOUND has: e.g. there is no sample cache yet. However: XMMS works fine.

        - -

        module-native-protocol-{unix,tcp}

        - -

        The native protocol of PulseAudio.

        - -

        See module-cli-protocol-{unix,tcp} for more information -about the two possible suffixes of this module.

        - -

        In addition to the options supported by module-cli-protocol-*, this module supports:

        - - - - - -
        auth-anonymous=If set to 1 no authentication is required to connect to the service
        auth-group=(only for -unix): members of the specified unix group may access the server without further auhentication.
        cookie=Name of the cookie file for authentication purposes
        - -

        module-native-protocol-fd

        - -

        This is used internally when auto spawning a new daemon. Don't use it directly.

        - -

        module-http-protocol-tcp

        - -

        A proof-of-concept HTTP module, which can be used to introspect -the current status of the PulseAudio daemon using HTTP. Just load this -module and point your browser to http://localhost:4714/. This module takes the same arguments -as module-cli-protocol-tcp.

        - -

        X Window System

        - -

        module-x11-bell

        - -

        Intercepts X11 bell events and plays a sample from the sample cache on each occurence.

        - - - - - -
        display=X11 display to connect to. If ommited defaults to the value of $DISPLAY
        sample=The sample to play. If ommited defaults to x11-bell.
        sink=Name of the sink to play the sample on. If ommited defaults to the default sink.
        - -

        module-x11-publish

        - -

        Publishes the access credentials to the PulseAudio server in the -X11 root window. The following properties are used: -PULSE_SERVER, POYLP_SINK, PULSE_SOURCE, -PULSE_COOKIE. This is very useful when using SSH or any other -remote login tool for logging into other machines and getting audio -playback to your local speakers. The PulseAudio client libraries make -use of this data automatically. Instead of using this module you may -use the tool pax11publish which may be used to access, modify -and import credential data from/to the X11 display.

        - - - - - -
        display=X11 display to connect to. If ommited defaults to the value of $DISPLAY
        sink=Name of the default sink. If ommited this property isn't stored in the X11 display.
        source=Name of the default source. If ommited this property isn't stored in the X11 display.
        cookie=Name of the cookie file of the -cookie to store in the X11 display. If ommited the cookie of an -already loaded protocol module is used.
        - -

        Volume Control

        - -

        module-mmkbd-evdev

        - -

        Adjust the volume of a sink when the special multimedia buttons of modern keyboards are pressed.

        - - - - -
        device=Linux input device ("evdev", defaults to /dev/input/event0)
        sink=The sink to control
        - -

        module-lirc

        - -

        Adjust the volume of a sink when the volume buttons of an infrared remote control are pressed (through LIRC).

        - - - - - -
        config=The LIRC configuration file
        appname=The application name to pass to LIRC (defaults to pulseaudio)
        sink=The sink to control
        - - -

        RTP/SDP/SAP Transport

        - -

        PulseAudio can stream audio data to an IP multicast group via the -standard protocols RTP, -SAP -and SDP -(RFC3550, RFC3551, RFC2327, RFC2327). This can be used for multiple -different purposes: for sharing a single microphone on multiple -computers on the local LAN, for streaming music from a single -controlling PC to multiple PCs with speakers or to implement a simple -"always-on" teleconferencing solution.

        - -

        The current implementation is designed to be used exlusively in -local area networks, though Internet multicasting is theoretically -supported. Only uncompressed audio is supported, hence you won't be -able to multicast more than a few streams at the same time over a -standard LAN.

        - -

        PulseAudio implements both a sender and a reciever for RTP -traffic. The sender announces itself via SAP/SDP on the same multicast -group as it sends the RTP data to. The reciever picks up the SAP/SDP -announcements and creates a playback stream for each -session. Alternatively you can use any RTP capable client to -recieve and play back the RTP data (such as mplayer).

        - -

        module-rtp-send

        - -

        This is the sender side of the RTP/SDP/SAP implementation. It reads -audio data from an existing source and forwards it to the network -encapsulated in RTP. In addition it sends SAP packets with an SDP -session description.

        - -

        In combination with the monitor source of module-null-sink -you can use this module to create an RTP sink.

        - - - - - - - - -
        source=The source to read the audio data from. If ommited defaults to the default source.
        format=, rate=, channels=Sample format to use, defaults to the source's.
        destination=Destination multicast group for both RTP and SAP packets, defaults to 224.0.0.56
        port=Destination port number of the RTP -traffic. If ommited defaults to a randomly chosen even port -number. Please keep in mind that the RFC suggests to use only even -port numbers for RTP traffic.
        mtu=Maximum payload size for RTP packets. If ommited defaults to 1280
        loop=Takes a boolean value, specifying whether locally generated RTP traffic should be looped back to the local host. Disabled by default.
        - -

        module-rtp-recv

        - -

        This is the reciever side of the RTP/SDP/SAP implementation. It -picks up SAP session announcements and creates an RTP playback stream -for each.

        - -

        In combination with module-null-sink you can use this -module to create an RTP source.

        - - - - -
        sink=The sink to connect to. If ommited defaults to the default sink.
        sap_address=The multicast group to join for SAP announcements, defaults to 224.0.0.56.
        - -

        JACK Connectivity

        - -

        PulseAudio can be hooked up to a JACK Audio Connection Kit server which is a specialized sound server used for professional audio production on Unix/Linux. Both a -PulseAudio sink and a source are available. For each channel a port is -created in the JACK server.

        - -

        module-jack-sink

        - -

        This module implements a PulseAudio sink that connects to JACK and registers as many output ports as requested.

        - - - - - - - -
        sink_name=The name for the PulseAudio sink. If ommited defaults to jack_out.
        server_name=The JACK server to connect to. If ommited defaults to the default server.
        client_name=The client name to tell the JACK server. If ommited defaults to PulseAudio.
        channels=Number of channels to register. If ommited defaults to the number of physical playback ports of the JACK server.
        connect=Takes a boolean value. If enabled (the default) PulseAudio will try to connect its ports to the physicial playback ports of the JACK server
        - -

        module-jack-source

        - -

        This module implements a PulseAudio source that connects to JACK -and registers as many input ports as requested. Takes the same -arguments as module-jack-sink, except for sink_name -which is replaced by source_name (with a default of jack_in) for obvious reasons.

        - -

        Miscellaneous

        - -

        module-sine

        - -

        Creates a sink input and generates a sine waveform stream.

        - - - - -
        sink=The sink to connect to. If ommited defaults to the default sink.
        frequency=The frequency to generate in Hertz. Defaults to 440.
        - -

        module-esound-compat-spawnfd

        - -

        This is a compatibility module for libesd based autospawning of PulseAudio. Don't use it directly.

        - -

        module-esound-compat-spawnpid

        - -

        This is a compatibility module for libesd based autospawning of PulseAudio. Don't use it directly.

        - -

        module-match

        - -

        Adjust the volume of a playback stream automatically based on its name.

        - - - -
        table=The regular expression matching table file to use (defaults to ~/.pulse/match.table)
        - -

        The table file should contain a regexp and volume on each line, seperated by spaces. An example:

        - -
        -^sample: 32000
        -
        - -

        The volumes of all streams with titles starting with sample: are automatically set to 32000. (FYI: All sample cache streams start with sample:)

        - -

        module-volume-restore

        - -

        Adjust the volume of a playback stream automatically based on its name.

        - - - -
        table=The table file to use (defaults to ~/.pulse/volume.table)
        - -

        In contrast to module-match this module needs no explicit -configuration. Instead the volumes are saved and restored in a fully -automatical fashion depending on the client name to identify -streams. The volume for a stream is automatically saved every time it is -changed and than restored when a new stream is created.

        - -

        module-detect

        - -

        Automatically detect the available sound hardware and load modules for it. Supports OSS, ALSA, Solaris and Win32 output drivers. - - - -
        just-one=If set to 1 the module will only try to load a single sink/source and than stop.
        - -

        module-zeroconf-publish

        - -

        Publish all local sinks/sources using mDNS Zeroconf.

        - - -
        -
        Lennart Poettering <@PACKAGE_BUGREPORT@>, April 2006
        -
        $Id$
        - diff --git a/doc/style.css b/doc/style.css deleted file mode 100644 index c5af0055..00000000 --- a/doc/style.css +++ /dev/null @@ -1,27 +0,0 @@ -/* $Id$ */ - -/*** - * This file is part of PulseAudio. - * - * PulseAudio is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * PulseAudio is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with PulseAudio; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - ***/ - -body { color: black; background-color: white; } -a:link, a:visited { color: #900000; } -div.news-date { font-size: 80%; font-style: italic; } -pre { background-color: #f0f0f0; padding: 0.4cm; } -.grey { color: #8f8f8f; font-size: 80%; } -table { margin-left: 1cm; border:1px solid lightgrey; padding: 0.2cm; } -td { padding-left:10px; padding-right:10px; } -- cgit -- cgit From eb4abb2cceb2f178cdabcea31c99c6d75dae7d1c Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sat, 8 Jul 2006 10:51:46 +0000 Subject: Fix typo. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1061 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index 12621d6a..2bd3b871 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -749,7 +749,7 @@ libauthkey_prop_la_LDFLAGS = -avoid-version libauthkey_prop_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket_util_la_SOURCES = \ - pulsecore/inet_ntop.c pulsecor/inet_ntop.h \ + pulsecore/inet_ntop.c pulsecore/inet_ntop.h \ pulsecore/socket-util.c pulsecore/socket-util.h libsocket_util_la_LDFLAGS = -avoid-version libsocket_util_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) libpulsecore.la -- cgit From e12ead7c5948c8ff7265fda5dc433de031ebbcda Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sat, 8 Jul 2006 11:29:14 +0000 Subject: Remove some unused m4 files. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1062 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- libtool.m4 | 5951 ----------------------------------------------------------- ltdl.m4 | 431 ----- 3 files changed, 1 insertion(+), 6383 deletions(-) delete mode 100644 libtool.m4 delete mode 100644 ltdl.m4 diff --git a/Makefile.am b/Makefile.am index 0884476d..d5d9b52f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,7 +17,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -EXTRA_DIST = bootstrap.sh LICENSE GPL LGPL doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in libtool.m4 ltdl.m4 README +EXTRA_DIST = bootstrap.sh LICENSE GPL LGPL doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in README SUBDIRS=libltdl src doc doxygen MAINTAINERCLEANFILES = diff --git a/libtool.m4 b/libtool.m4 deleted file mode 100644 index 4f5ac795..00000000 --- a/libtool.m4 +++ /dev/null @@ -1,5951 +0,0 @@ -# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- -## Copyright 1996, 1997, 1998, 1999, 2000, 2001 -## Free Software Foundation, Inc. -## Originally by Gordon Matzigkeit , 1996 -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -## -## As a special exception to the GNU General Public License, if you -## distribute this file as part of a program that contains a -## configuration script generated by Autoconf, you may include it under -## the same distribution terms that you use for the rest of that program. - -# serial 47 AC_PROG_LIBTOOL -# Debian $Rev: 214 $ - - -# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED) -# ----------------------------------------------------------- -# If this macro is not defined by Autoconf, define it here. -m4_ifdef([AC_PROVIDE_IFELSE], - [], - [m4_define([AC_PROVIDE_IFELSE], - [m4_ifdef([AC_PROVIDE_$1], - [$2], [$3])])]) - - -# AC_PROG_LIBTOOL -# --------------- -AC_DEFUN([AC_PROG_LIBTOOL], -[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl -dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX -dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. - AC_PROVIDE_IFELSE([AC_PROG_CXX], - [AC_LIBTOOL_CXX], - [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX - ])]) -dnl And a similar setup for Fortran 77 support - AC_PROVIDE_IFELSE([AC_PROG_F77], - [AC_LIBTOOL_F77], - [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77 -])]) - -dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. -dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run -dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. - AC_PROVIDE_IFELSE([AC_PROG_GCJ], - [AC_LIBTOOL_GCJ], - [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], - [AC_LIBTOOL_GCJ], - [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], - [AC_LIBTOOL_GCJ], - [ifdef([AC_PROG_GCJ], - [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])]) - ifdef([A][M_PROG_GCJ], - [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])]) - ifdef([LT_AC_PROG_GCJ], - [define([LT_AC_PROG_GCJ], - defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])]) -])])# AC_PROG_LIBTOOL - - -# _AC_PROG_LIBTOOL -# ---------------- -AC_DEFUN([_AC_PROG_LIBTOOL], -[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl -AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl -AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl -AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl - -# This can be used to rebuild libtool when needed -LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" - -# Always use our own libtool. -LIBTOOL='$(SHELL) $(top_builddir)/libtool' -AC_SUBST(LIBTOOL)dnl - -# Prevent multiple expansion -define([AC_PROG_LIBTOOL], []) -])# _AC_PROG_LIBTOOL - - -# AC_LIBTOOL_SETUP -# ---------------- -AC_DEFUN([AC_LIBTOOL_SETUP], -[AC_PREREQ(2.50)dnl -AC_REQUIRE([AC_ENABLE_SHARED])dnl -AC_REQUIRE([AC_ENABLE_STATIC])dnl -AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl -AC_REQUIRE([AC_CANONICAL_HOST])dnl -AC_REQUIRE([AC_CANONICAL_BUILD])dnl -AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([AC_PROG_LD])dnl -AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl -AC_REQUIRE([AC_PROG_NM])dnl - -AC_REQUIRE([AC_PROG_LN_S])dnl -AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl -# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! -AC_REQUIRE([AC_OBJEXT])dnl -AC_REQUIRE([AC_EXEEXT])dnl -dnl - -AC_LIBTOOL_SYS_MAX_CMD_LEN -AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE -AC_LIBTOOL_OBJDIR - -AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl -_LT_AC_PROG_ECHO_BACKSLASH - -case $host_os in -aix3*) - # AIX sometimes has problems with the GCC collect2 program. For some - # reason, if we set the COLLECT_NAMES environment variable, the problems - # vanish in a puff of smoke. - if test "X${COLLECT_NAMES+set}" != Xset; then - COLLECT_NAMES= - export COLLECT_NAMES - fi - ;; -esac - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -Xsed='sed -e s/^X//' -[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] - -# Same as above, but do not quote variable references. -[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] - -# Sed substitution to delay expansion of an escaped shell variable in a -# double_quote_subst'ed string. -delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' - -# Sed substitution to avoid accidental globbing in evaled expressions -no_glob_subst='s/\*/\\\*/g' - -# Constants: -rm="rm -f" - -# Global variables: -default_ofile=libtool -can_build_shared=yes - -# All known linkers require a `.a' archive for static linking (except M$VC, -# which needs '.lib'). -libext=a -ltmain="$ac_aux_dir/ltmain.sh" -ofile="$default_ofile" -with_gnu_ld="$lt_cv_prog_gnu_ld" - -AC_CHECK_TOOL(AR, ar, false) -AC_CHECK_TOOL(RANLIB, ranlib, :) -AC_CHECK_TOOL(STRIP, strip, :) - -old_CC="$CC" -old_CFLAGS="$CFLAGS" - -# Set sane defaults for various variables -test -z "$AR" && AR=ar -test -z "$AR_FLAGS" && AR_FLAGS=cru -test -z "$AS" && AS=as -test -z "$CC" && CC=cc -test -z "$LTCC" && LTCC=$CC -test -z "$DLLTOOL" && DLLTOOL=dlltool -test -z "$LD" && LD=ld -test -z "$LN_S" && LN_S="ln -s" -test -z "$MAGIC_CMD" && MAGIC_CMD=file -test -z "$NM" && NM=nm -test -z "$SED" && SED=sed -test -z "$OBJDUMP" && OBJDUMP=objdump -test -z "$RANLIB" && RANLIB=: -test -z "$STRIP" && STRIP=: -test -z "$ac_objext" && ac_objext=o - -# Determine commands to create old-style static archives. -old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' -old_postinstall_cmds='chmod 644 $oldlib' -old_postuninstall_cmds= - -if test -n "$RANLIB"; then - case $host_os in - openbsd*) - old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds" - ;; - *) - old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" - ;; - esac - old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" -fi - -# Only perform the check for file, if the check method requires it -case $deplibs_check_method in -file_magic*) - if test "$file_magic_cmd" = '$MAGIC_CMD'; then - AC_PATH_MAGIC - fi - ;; -esac - -AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) -AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], -enable_win32_dll=yes, enable_win32_dll=no) - -AC_ARG_ENABLE([libtool-lock], - [AC_HELP_STRING([--disable-libtool-lock], - [avoid locking (might break parallel builds)])]) -test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes - -AC_ARG_WITH([pic], - [AC_HELP_STRING([--with-pic], - [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], - [pic_mode="$withval"], - [pic_mode=default]) -test -z "$pic_mode" && pic_mode=default - -# Use C for the default configuration in the libtool script -tagname= -AC_LIBTOOL_LANG_C_CONFIG -_LT_AC_TAGCONFIG -])# AC_LIBTOOL_SETUP - - -# _LT_AC_SYS_COMPILER -# ------------------- -AC_DEFUN([_LT_AC_SYS_COMPILER], -[AC_REQUIRE([AC_PROG_CC])dnl - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# Allow CC to be a program name with arguments. -compiler=$CC -])# _LT_AC_SYS_COMPILER - - -# _LT_AC_SYS_LIBPATH_AIX -# ---------------------- -# Links a minimal program and checks the executable -# for the system default hardcoded library path. In most cases, -# this is /usr/lib:/lib, but when the MPI compilers are used -# the location of the communication and MPI libs are included too. -# If we don't find anything, use the default library path according -# to the aix ld manual. -AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX], -[AC_LINK_IFELSE(AC_LANG_PROGRAM,[ -aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } -}'` -# Check for a 64-bit object if we didn't find anything. -if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } -}'`; fi],[]) -if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi -])# _LT_AC_SYS_LIBPATH_AIX - - -# _LT_AC_SHELL_INIT(ARG) -# ---------------------- -AC_DEFUN([_LT_AC_SHELL_INIT], -[ifdef([AC_DIVERSION_NOTICE], - [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], - [AC_DIVERT_PUSH(NOTICE)]) -$1 -AC_DIVERT_POP -])# _LT_AC_SHELL_INIT - - -# _LT_AC_PROG_ECHO_BACKSLASH -# -------------------------- -# Add some code to the start of the generated configure script which -# will find an echo command which doesn't interpret backslashes. -AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], -[_LT_AC_SHELL_INIT([ -# Check that we are running under the correct shell. -SHELL=${CONFIG_SHELL-/bin/sh} - -case X$ECHO in -X*--fallback-echo) - # Remove one level of quotation (which was required for Make). - ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` - ;; -esac - -echo=${ECHO-echo} -if test "X[$]1" = X--no-reexec; then - # Discard the --no-reexec flag, and continue. - shift -elif test "X[$]1" = X--fallback-echo; then - # Avoid inline document here, it may be left over - : -elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then - # Yippee, $echo works! - : -else - # Restart under the correct shell. - exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} -fi - -if test "X[$]1" = X--fallback-echo; then - # used as fallback echo - shift - cat </dev/null && - echo_test_string="`eval $cmd`" && - (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null - then - break - fi - done -fi - -if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - : -else - # The Solaris, AIX, and Digital Unix default echo programs unquote - # backslashes. This makes it impossible to quote backslashes using - # echo "$something" | sed 's/\\/\\\\/g' - # - # So, first we look for a working echo in the user's PATH. - - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for dir in $PATH /usr/ucb; do - IFS="$lt_save_ifs" - if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && - test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - echo="$dir/echo" - break - fi - done - IFS="$lt_save_ifs" - - if test "X$echo" = Xecho; then - # We didn't find a better echo, so look for alternatives. - if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - # This shell has a builtin print -r that does the trick. - echo='print -r' - elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && - test "X$CONFIG_SHELL" != X/bin/ksh; then - # If we have ksh, try running configure again with it. - ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} - export ORIGINAL_CONFIG_SHELL - CONFIG_SHELL=/bin/ksh - export CONFIG_SHELL - exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} - else - # Try using printf. - echo='printf %s\n' - if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - # Cool, printf works - : - elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && - test "X$echo_testing_string" = 'X\t' && - echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL - export CONFIG_SHELL - SHELL="$CONFIG_SHELL" - export SHELL - echo="$CONFIG_SHELL [$]0 --fallback-echo" - elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && - test "X$echo_testing_string" = 'X\t' && - echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - echo="$CONFIG_SHELL [$]0 --fallback-echo" - else - # maybe with a smaller string... - prev=: - - for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do - if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null - then - break - fi - prev="$cmd" - done - - if test "$prev" != 'sed 50q "[$]0"'; then - echo_test_string=`eval $prev` - export echo_test_string - exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} - else - # Oops. We lost completely, so just stick with echo. - echo=echo - fi - fi - fi - fi -fi -fi - -# Copy echo and quote the copy suitably for passing to libtool from -# the Makefile, instead of quoting the original, which is used later. -ECHO=$echo -if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then - ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" -fi - -AC_SUBST(ECHO) -])])# _LT_AC_PROG_ECHO_BACKSLASH - - -# _LT_AC_LOCK -# ----------- -AC_DEFUN([_LT_AC_LOCK], -[AC_ARG_ENABLE([libtool-lock], - [AC_HELP_STRING([--disable-libtool-lock], - [avoid locking (might break parallel builds)])]) -test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes - -# Some flags need to be propagated to the compiler or linker for good -# libtool support. -case $host in -ia64-*-hpux*) - # Find out which ABI we are using. - echo 'int i;' > conftest.$ac_ext - if AC_TRY_EVAL(ac_compile); then - case `/usr/bin/file conftest.$ac_objext` in - *ELF-32*) - HPUX_IA64_MODE="32" - ;; - *ELF-64*) - HPUX_IA64_MODE="64" - ;; - esac - fi - rm -rf conftest* - ;; -*-*-irix6*) - # Find out which ABI we are using. - echo '[#]line __oline__ "configure"' > conftest.$ac_ext - if AC_TRY_EVAL(ac_compile); then - if test "$lt_cv_prog_gnu_ld" = yes; then - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -melf32bsmip" - ;; - *N32*) - LD="${LD-ld} -melf32bmipn32" - ;; - *64-bit*) - LD="${LD-ld} -melf64bmip" - ;; - esac - else - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -32" - ;; - *N32*) - LD="${LD-ld} -n32" - ;; - *64-bit*) - LD="${LD-ld} -64" - ;; - esac - fi - fi - rm -rf conftest* - ;; - -x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) - # Find out which ABI we are using. - echo 'int i;' > conftest.$ac_ext - if AC_TRY_EVAL(ac_compile); then - case "`/usr/bin/file conftest.o`" in - *32-bit*) - case $host in - x86_64-*linux*) - LD="${LD-ld} -m elf_i386" - ;; - ppc64-*linux*|powerpc64-*linux*) - LD="${LD-ld} -m elf32ppclinux" - ;; - s390x-*linux*) - LD="${LD-ld} -m elf_s390" - ;; - sparc64-*linux*) - LD="${LD-ld} -m elf32_sparc" - ;; - esac - ;; - *64-bit*) - case $host in - x86_64-*linux*) - LD="${LD-ld} -m elf_x86_64" - ;; - ppc*-*linux*|powerpc*-*linux*) - LD="${LD-ld} -m elf64ppc" - ;; - s390*-*linux*) - LD="${LD-ld} -m elf64_s390" - ;; - sparc*-*linux*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; - -*-*-sco3.2v5*) - # On SCO OpenServer 5, we need -belf to get full-featured binaries. - SAVE_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -belf" - AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, - [AC_LANG_PUSH(C) - AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) - AC_LANG_POP]) - if test x"$lt_cv_cc_needs_belf" != x"yes"; then - # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf - CFLAGS="$SAVE_CFLAGS" - fi - ;; -AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], -[*-*-cygwin* | *-*-mingw* | *-*-pw32*) - AC_CHECK_TOOL(DLLTOOL, dlltool, false) - AC_CHECK_TOOL(AS, as, false) - AC_CHECK_TOOL(OBJDUMP, objdump, false) - ;; - ]) -esac - -need_locks="$enable_libtool_lock" - -])# _LT_AC_LOCK - - -# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, -# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) -# ---------------------------------------------------------------- -# Check whether the given compiler option works -AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], -[AC_REQUIRE([LT_AC_PROG_SED]) -AC_CACHE_CHECK([$1], [$2], - [$2=no - ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) - printf "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$3" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ - -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&AS_MESSAGE_LOG_FD - echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - if test ! -s conftest.err; then - $2=yes - fi - fi - $rm conftest* -]) - -if test x"[$]$2" = xyes; then - ifelse([$5], , :, [$5]) -else - ifelse([$6], , :, [$6]) -fi -])# AC_LIBTOOL_COMPILER_OPTION - - -# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, -# [ACTION-SUCCESS], [ACTION-FAILURE]) -# ------------------------------------------------------------ -# Check whether the given compiler option works -AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], -[AC_CACHE_CHECK([$1], [$2], - [$2=no - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS $3" - printf "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&AS_MESSAGE_LOG_FD - else - $2=yes - fi - fi - $rm conftest* - LDFLAGS="$save_LDFLAGS" -]) - -if test x"[$]$2" = xyes; then - ifelse([$4], , :, [$4]) -else - ifelse([$5], , :, [$5]) -fi -])# AC_LIBTOOL_LINKER_OPTION - - -# AC_LIBTOOL_SYS_MAX_CMD_LEN -# -------------------------- -AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], -[# find the maximum length of command line arguments -AC_MSG_CHECKING([the maximum length of command line arguments]) -AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl - i=0 - teststring="ABCD" - - case $build_os in - msdosdjgpp*) - # On DJGPP, this test can blow up pretty badly due to problems in libc - # (any single argument exceeding 2000 bytes causes a buffer overrun - # during glob expansion). Even if it were fixed, the result of this - # check would be larger than it should be. - lt_cv_sys_max_cmd_len=12288; # 12K is about right - ;; - - gnu*) - # Under GNU Hurd, this test is not required because there is - # no limit to the length of command line arguments. - # Libtool will interpret -1 as no limit whatsoever - lt_cv_sys_max_cmd_len=-1; - ;; - - cygwin* | mingw*) - # On Win9x/ME, this test blows up -- it succeeds, but takes - # about 5 minutes as the teststring grows exponentially. - # Worse, since 9x/ME are not pre-emptively multitasking, - # you end up with a "frozen" computer, even though with patience - # the test eventually succeeds (with a max line length of 256k). - # Instead, let's just punt: use the minimum linelength reported by - # all of the supported platforms: 8192 (on NT/2K/XP). - lt_cv_sys_max_cmd_len=8192; - ;; - - amigaos*) - # On AmigaOS with pdksh, this test takes hours, literally. - # So we just punt and use a minimum line length of 8192. - lt_cv_sys_max_cmd_len=8192; - ;; - - *) - # If test is not a shell built-in, we'll probably end up computing a - # maximum length that is only half of the actual maximum length, but - # we can't tell. - while (test "X"`$CONFIG_SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \ - = "XX$teststring") >/dev/null 2>&1 && - new_result=`expr "X$teststring" : ".*" 2>&1` && - lt_cv_sys_max_cmd_len=$new_result && - test $i != 17 # 1/2 MB should be enough - do - i=`expr $i + 1` - teststring=$teststring$teststring - done - teststring= - # Add a significant safety factor because C++ compilers can tack on massive - # amounts of additional arguments before passing them to the linker. - # It appears as though 1/2 is a usable value. - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` - ;; - esac -]) -if test -n $lt_cv_sys_max_cmd_len ; then - AC_MSG_RESULT($lt_cv_sys_max_cmd_len) -else - AC_MSG_RESULT(none) -fi -])# AC_LIBTOOL_SYS_MAX_CMD_LEN - - -# _LT_AC_CHECK_DLFCN -# -------------------- -AC_DEFUN([_LT_AC_CHECK_DLFCN], -[AC_CHECK_HEADERS(dlfcn.h)dnl -])# _LT_AC_CHECK_DLFCN - - -# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, -# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) -# ------------------------------------------------------------------ -AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], -[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl -if test "$cross_compiling" = yes; then : - [$4] -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext < -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -#ifdef __cplusplus -extern "C" void exit (int); -#endif - -void fnord() { int i=42;} -int main () -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - /* dlclose (self); */ - } - - exit (status); -}] -EOF - if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then - (./conftest; exit; ) 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) $1 ;; - x$lt_dlneed_uscore) $2 ;; - x$lt_unknown|x*) $3 ;; - esac - else : - # compilation failed - $3 - fi -fi -rm -fr conftest* -])# _LT_AC_TRY_DLOPEN_SELF - - -# AC_LIBTOOL_DLOPEN_SELF -# ------------------- -AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], -[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl -if test "x$enable_dlopen" != xyes; then - enable_dlopen=unknown - enable_dlopen_self=unknown - enable_dlopen_self_static=unknown -else - lt_cv_dlopen=no - lt_cv_dlopen_libs= - - case $host_os in - beos*) - lt_cv_dlopen="load_add_on" - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; - - mingw* | pw32*) - lt_cv_dlopen="LoadLibrary" - lt_cv_dlopen_libs= - ;; - - cygwin*) - lt_cv_dlopen="dlopen" - lt_cv_dlopen_libs= - ;; - - darwin*) - # if libdl is installed we need to link against it - AC_CHECK_LIB([dl], [dlopen], - [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ - lt_cv_dlopen="dyld" - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ]) - ;; - - *) - AC_CHECK_FUNC([shl_load], - [lt_cv_dlopen="shl_load"], - [AC_CHECK_LIB([dld], [shl_load], - [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], - [AC_CHECK_FUNC([dlopen], - [lt_cv_dlopen="dlopen"], - [AC_CHECK_LIB([dl], [dlopen], - [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], - [AC_CHECK_LIB([svld], [dlopen], - [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], - [AC_CHECK_LIB([dld], [dld_link], - [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) - ]) - ]) - ]) - ]) - ]) - ;; - esac - - if test "x$lt_cv_dlopen" != xno; then - enable_dlopen=yes - else - enable_dlopen=no - fi - - case $lt_cv_dlopen in - dlopen) - save_CPPFLAGS="$CPPFLAGS" - test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" - - save_LDFLAGS="$LDFLAGS" - eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" - - save_LIBS="$LIBS" - LIBS="$lt_cv_dlopen_libs $LIBS" - - AC_CACHE_CHECK([whether a program can dlopen itself], - lt_cv_dlopen_self, [dnl - _LT_AC_TRY_DLOPEN_SELF( - lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, - lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) - ]) - - if test "x$lt_cv_dlopen_self" = xyes; then - LDFLAGS="$LDFLAGS $link_static_flag" - AC_CACHE_CHECK([whether a statically linked program can dlopen itself], - lt_cv_dlopen_self_static, [dnl - _LT_AC_TRY_DLOPEN_SELF( - lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, - lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) - ]) - fi - - CPPFLAGS="$save_CPPFLAGS" - LDFLAGS="$save_LDFLAGS" - LIBS="$save_LIBS" - ;; - esac - - case $lt_cv_dlopen_self in - yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; - *) enable_dlopen_self=unknown ;; - esac - - case $lt_cv_dlopen_self_static in - yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; - *) enable_dlopen_self_static=unknown ;; - esac -fi -])# AC_LIBTOOL_DLOPEN_SELF - - -# AC_LIBTOOL_PROG_CC_C_O([TAGNAME]) -# --------------------------------- -# Check to see if options -c and -o are simultaneously supported by compiler -AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O], -[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl -AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], - [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)], - [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no - $rm -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - printf "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ - -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&AS_MESSAGE_LOG_FD - echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - if test ! -s out/conftest.err; then - _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes - fi - fi - chmod u+w . - $rm conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files - $rm out/* && rmdir out - cd .. - rmdir conftest - $rm conftest* -]) -])# AC_LIBTOOL_PROG_CC_C_O - - -# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME]) -# ----------------------------------------- -# Check to see if we can do hard links to lock some files if needed -AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], -[AC_REQUIRE([_LT_AC_LOCK])dnl - -hard_links="nottested" -if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then - # do not overwrite the value of need_locks provided by the user - AC_MSG_CHECKING([if we can lock with hard links]) - hard_links=yes - $rm conftest* - ln conftest.a conftest.b 2>/dev/null && hard_links=no - touch conftest.a - ln conftest.a conftest.b 2>&5 || hard_links=no - ln conftest.a conftest.b 2>/dev/null && hard_links=no - AC_MSG_RESULT([$hard_links]) - if test "$hard_links" = no; then - AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) - need_locks=warn - fi -else - need_locks=no -fi -])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS - - -# AC_LIBTOOL_OBJDIR -# ----------------- -AC_DEFUN([AC_LIBTOOL_OBJDIR], -[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], -[rm -f .libs 2>/dev/null -mkdir .libs 2>/dev/null -if test -d .libs; then - lt_cv_objdir=.libs -else - # MS-DOS does not allow filenames that begin with a dot. - lt_cv_objdir=_libs -fi -rmdir .libs 2>/dev/null]) -objdir=$lt_cv_objdir -])# AC_LIBTOOL_OBJDIR - - -# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME]) -# ---------------------------------------------- -# Check hardcoding attributes. -AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], -[AC_MSG_CHECKING([how to hardcode library paths into programs]) -_LT_AC_TAGVAR(hardcode_action, $1)= -if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \ - test -n "$_LT_AC_TAGVAR(runpath_var $1)" || \ - test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)"="Xyes" ; then - - # We can hardcode non-existant directories. - if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no && - # If the only mechanism to avoid hardcoding is shlibpath_var, we - # have to relink, otherwise we might link with an installed library - # when we should be linking with a yet-to-be-installed one - ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no && - test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then - # Linking always hardcodes the temporary library directory. - _LT_AC_TAGVAR(hardcode_action, $1)=relink - else - # We can link without hardcoding, and we can hardcode nonexisting dirs. - _LT_AC_TAGVAR(hardcode_action, $1)=immediate - fi -else - # We cannot hardcode anything, or else we can only hardcode existing - # directories. - _LT_AC_TAGVAR(hardcode_action, $1)=unsupported -fi -AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)]) - -if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then - # Fast installation is not supported - enable_fast_install=no -elif test "$shlibpath_overrides_runpath" = yes || - test "$enable_shared" = no; then - # Fast installation is not necessary - enable_fast_install=needless -fi -])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH - - -# AC_LIBTOOL_SYS_LIB_STRIP -# ------------------------ -AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP], -[striplib= -old_striplib= -AC_MSG_CHECKING([whether stripping libraries is possible]) -if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then - test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" - test -z "$striplib" && striplib="$STRIP --strip-unneeded" - AC_MSG_RESULT([yes]) -else -# FIXME - insert some real tests, host_os isn't really good enough - case $host_os in - darwin*) - if test -n "$STRIP" ; then - striplib="$STRIP -x" - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) -fi - ;; - *) - AC_MSG_RESULT([no]) - ;; - esac -fi -])# AC_LIBTOOL_SYS_LIB_STRIP - - -# AC_LIBTOOL_SYS_DYNAMIC_LINKER -# ----------------------------- -# PORTME Fill in your ld.so characteristics -AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER], -[AC_MSG_CHECKING([dynamic linker characteristics]) -library_names_spec= -libname_spec='lib$name' -soname_spec= -shrext_cmds=".so" -postinstall_cmds= -postuninstall_cmds= -finish_cmds= -finish_eval= -shlibpath_var= -shlibpath_overrides_runpath=unknown -version_type=none -dynamic_linker="$host_os ld.so" -sys_lib_dlsearch_path_spec="/lib /usr/lib" -if test "$GCC" = yes; then - sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` - if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then - # if the path contains ";" then we assume it to be the separator - # otherwise default to the standard path separator (i.e. ":") - it is - # assumed that no part of a normal pathname contains ";" but that should - # okay in the real world where ";" in dirpaths is itself problematic. - sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi -else - sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" -fi -need_lib_prefix=unknown -hardcode_into_libs=no - -# when you set need_version to no, make sure it does not cause -set_version -# flags to be left without arguments -need_version=unknown - -case $host_os in -aix3*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' - shlibpath_var=LIBPATH - - # AIX 3 has no versioning support, so we append a major version to the name. - soname_spec='${libname}${release}${shared_ext}$major' - ;; - -aix4* | aix5*) - version_type=linux - need_lib_prefix=no - need_version=no - hardcode_into_libs=yes - if test "$host_cpu" = ia64; then - # AIX 5 supports IA64 - library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - else - # With GCC up to 2.95.x, collect2 would create an import file - # for dependence libraries. The import file would start with - # the line `#! .'. This would cause the generated library to - # depend on `.', always an invalid library. This was fixed in - # development snapshots of GCC prior to 3.0. - case $host_os in - aix4 | aix4.[[01]] | aix4.[[01]].*) - if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' - echo ' yes ' - echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then - : - else - can_build_shared=no - fi - ;; - esac - # AIX (on Power*) has no versioning support, so currently we can not hardcode correct - # soname into executable. Probably we can add versioning support to - # collect2, so additional links can be useful in future. - if test "$aix_use_runtimelinking" = yes; then - # If using run time linking (on AIX 4.2 or later) use lib.so - # instead of lib.a to let people know that these are not - # typical AIX shared libraries. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - else - # We preserve .a as extension for shared libraries through AIX4.2 - # and later when we are not doing run time linking. - library_names_spec='${libname}${release}.a $libname.a' - soname_spec='${libname}${release}${shared_ext}$major' - fi - shlibpath_var=LIBPATH - fi - ;; - -amigaos*) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' - ;; - -beos*) - library_names_spec='${libname}${shared_ext}' - dynamic_linker="$host_os ld.so" - shlibpath_var=LIBRARY_PATH - ;; - -bsdi4*) - version_type=linux - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" - sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" - # the default ld.so.conf also contains /usr/contrib/lib and - # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow - # libtool to hard-code these into programs - ;; - -cygwin* | mingw* | pw32*) - version_type=windows - shrext_cmds=".dll" - need_version=no - need_lib_prefix=no - - case $GCC,$host_os in - yes,cygwin* | yes,mingw* | yes,pw32*) - library_names_spec='$libname.dll.a' - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \${file}`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $rm \$dlpath' - shlibpath_overrides_runpath=yes - - case $host_os in - cygwin*) - # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' - sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" - ;; - mingw*) - # MinGW DLLs use traditional 'lib' prefix - soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' - sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` - if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then - # It is most probably a Windows format PATH printed by - # mingw gcc, but we are running on Cygwin. Gcc prints its search - # path with ; separators, and with drive letters. We can handle the - # drive letters (cygwin fileutils understands them), so leave them, - # especially as we might pass files found there to a mingw objdump, - # which wouldn't understand a cygwinified path. Ahh. - sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi - ;; - pw32*) - # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - ;; - esac - ;; - - *) - library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' - ;; - esac - dynamic_linker='Win32 ld.exe' - # FIXME: first we should search . and the directory the executable is in - shlibpath_var=PATH - ;; - -darwin* | rhapsody*) - dynamic_linker="$host_os dyld" - version_type=darwin - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' - soname_spec='${libname}${release}${major}$shared_ext' - shlibpath_overrides_runpath=yes - shlibpath_var=DYLD_LIBRARY_PATH - shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)' - # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. - if test "$GCC" = yes; then - sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` - else - sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' - fi - sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' - ;; - -dgux*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -freebsd1*) - dynamic_linker=no - ;; - -kfreebsd*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='GNU ld.so' - ;; - -freebsd*) - objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` - version_type=freebsd-$objformat - case $version_type in - freebsd-elf*) - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - need_version=no - need_lib_prefix=no - ;; - freebsd-*) - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' - need_version=yes - ;; - esac - shlibpath_var=LD_LIBRARY_PATH - case $host_os in - freebsd2*) - shlibpath_overrides_runpath=yes - ;; - freebsd3.[01]* | freebsdelf3.[01]*) - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - *) # from 3.2 on - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - esac - ;; - -gnu*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - hardcode_into_libs=yes - ;; - -hpux9* | hpux10* | hpux11*) - # Give a soname corresponding to the major version so that dld.sl refuses to - # link against other versions. - version_type=sunos - need_lib_prefix=no - need_version=no - case "$host_cpu" in - ia64*) - shrext_cmds='.so' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.so" - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - if test "X$HPUX_IA64_MODE" = X32; then - sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" - else - sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" - fi - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - hppa*64*) - shrext_cmds='.sl' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.sl" - shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - *) - shrext_cmds='.sl' - dynamic_linker="$host_os dld.sl" - shlibpath_var=SHLIB_PATH - shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - ;; - esac - # HP-UX runs *really* slowly unless shared libraries are mode 555. - postinstall_cmds='chmod 555 $lib' - ;; - -irix5* | irix6* | nonstopux*) - case $host_os in - nonstopux*) version_type=nonstopux ;; - *) - if test "$lt_cv_prog_gnu_ld" = yes; then - version_type=linux - else - version_type=irix - fi ;; - esac - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' - case $host_os in - irix5* | nonstopux*) - libsuff= shlibsuff= - ;; - *) - case $LD in # libtool.m4 will add one of these switches to LD - *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") - libsuff= shlibsuff= libmagic=32-bit;; - *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") - libsuff=32 shlibsuff=N32 libmagic=N32;; - *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") - libsuff=64 shlibsuff=64 libmagic=64-bit;; - *) libsuff= shlibsuff= libmagic=never-match;; - esac - ;; - esac - shlibpath_var=LD_LIBRARY${shlibsuff}_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" - sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" - hardcode_into_libs=yes - ;; - -# No shared lib support for Linux oldld, aout, or coff. -linux*oldld* | linux*aout* | linux*coff*) - dynamic_linker=no - ;; - -# This must be Linux ELF. -linux*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - # Append ld.so.conf contents to the search path - if test -f /etc/ld.so.conf; then - lt_ld_extra=`$SED -e 's/[:,\t]/ /g;s/=[^=]*$//;s/=[^= ]* / /g' /etc/ld.so.conf | tr '\n' ' '` - sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" - fi - - # We used to test for /lib/ld.so.1 and disable shared libraries on - # powerpc, because MkLinux only supported shared libraries with the - # GNU dynamic linker. Since this was broken with cross compilers, - # most powerpc-linux boxes support dynamic linking these days and - # people can always --disable-shared, the test was removed, and we - # assume the GNU/Linux dynamic linker is in use. - dynamic_linker='GNU/Linux ld.so' - ;; - -netbsdelf*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='NetBSD ld.elf_so' - ;; - -knetbsd*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='GNU ld.so' - ;; - -netbsd*) - version_type=sunos - need_lib_prefix=no - need_version=no - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - dynamic_linker='NetBSD (a.out) ld.so' - else - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='NetBSD ld.elf_so' - fi - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - -newsos6) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -nto-qnx*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -openbsd*) - version_type=sunos - need_lib_prefix=no - need_version=yes - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - case $host_os in - openbsd2.[[89]] | openbsd2.[[89]].*) - shlibpath_overrides_runpath=no - ;; - *) - shlibpath_overrides_runpath=yes - ;; - esac - else - shlibpath_overrides_runpath=yes - fi - ;; - -os2*) - libname_spec='$name' - shrext_cmds=".dll" - need_lib_prefix=no - library_names_spec='$libname${shared_ext} $libname.a' - dynamic_linker='OS/2 ld.exe' - shlibpath_var=LIBPATH - ;; - -osf3* | osf4* | osf5*) - version_type=osf - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" - ;; - -sco3.2v5*) - version_type=osf - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - ;; - -solaris*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - # ldd complains unless libraries are executable - postinstall_cmds='chmod +x $lib' - ;; - -sunos4*) - version_type=sunos - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - if test "$with_gnu_ld" = yes; then - need_lib_prefix=no - fi - need_version=yes - ;; - -sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - case $host_vendor in - sni) - shlibpath_overrides_runpath=no - need_lib_prefix=no - export_dynamic_flag_spec='${wl}-Blargedynsym' - runpath_var=LD_RUN_PATH - ;; - siemens) - need_lib_prefix=no - ;; - motorola) - need_lib_prefix=no - need_version=no - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' - ;; - esac - ;; - -sysv4*MP*) - if test -d /usr/nec ;then - version_type=linux - library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' - soname_spec='$libname${shared_ext}.$major' - shlibpath_var=LD_LIBRARY_PATH - fi - ;; - -uts4*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -*) - dynamic_linker=no - ;; -esac -AC_MSG_RESULT([$dynamic_linker]) -test "$dynamic_linker" = no && can_build_shared=no -])# AC_LIBTOOL_SYS_DYNAMIC_LINKER - - -# _LT_AC_TAGCONFIG -# ---------------- -AC_DEFUN([_LT_AC_TAGCONFIG], -[AC_ARG_WITH([tags], - [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@], - [include additional configurations @<:@automatic@:>@])], - [tagnames="$withval"]) - -if test -f "$ltmain" && test -n "$tagnames"; then - if test ! -f "${ofile}"; then - AC_MSG_WARN([output file `$ofile' does not exist]) - fi - - if test -z "$LTCC"; then - eval "`$SHELL ${ofile} --config | grep '^LTCC='`" - if test -z "$LTCC"; then - AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) - else - AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) - fi - fi - - # Extract list of available tagged configurations in $ofile. - # Note that this assumes the entire list is on one line. - available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` - - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for tagname in $tagnames; do - IFS="$lt_save_ifs" - # Check whether tagname contains only valid characters - case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in - "") ;; - *) AC_MSG_ERROR([invalid tag name: $tagname]) - ;; - esac - - if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null - then - AC_MSG_ERROR([tag name \"$tagname\" already exists]) - fi - - # Update the list of available tags. - if test -n "$tagname"; then - echo appending configuration tag \"$tagname\" to $ofile - - case $tagname in - CXX) - if test -n "$CXX" && test "X$CXX" != "Xno"; then - AC_LIBTOOL_LANG_CXX_CONFIG - else - tagname="" - fi - ;; - - F77) - if test -n "$F77" && test "X$F77" != "Xno"; then - AC_LIBTOOL_LANG_F77_CONFIG - else - tagname="" - fi - ;; - - GCJ) - if test -n "$GCJ" && test "X$GCJ" != "Xno"; then - AC_LIBTOOL_LANG_GCJ_CONFIG - else - tagname="" - fi - ;; - - RC) - AC_LIBTOOL_LANG_RC_CONFIG - ;; - - *) - AC_MSG_ERROR([Unsupported tag name: $tagname]) - ;; - esac - - # Append the new tag name to the list of available tags. - if test -n "$tagname" ; then - available_tags="$available_tags $tagname" - fi - fi - done - IFS="$lt_save_ifs" - - # Now substitute the updated list of available tags. - if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then - mv "${ofile}T" "$ofile" - chmod +x "$ofile" - else - rm -f "${ofile}T" - AC_MSG_ERROR([unable to update list of available tagged configurations.]) - fi -fi -])# _LT_AC_TAGCONFIG - - -# AC_LIBTOOL_DLOPEN -# ----------------- -# enable checks for dlopen support -AC_DEFUN([AC_LIBTOOL_DLOPEN], - [AC_BEFORE([$0],[AC_LIBTOOL_SETUP]) -])# AC_LIBTOOL_DLOPEN - - -# AC_LIBTOOL_WIN32_DLL -# -------------------- -# declare package support for building win32 dll's -AC_DEFUN([AC_LIBTOOL_WIN32_DLL], -[AC_BEFORE([$0], [AC_LIBTOOL_SETUP]) -])# AC_LIBTOOL_WIN32_DLL - - -# AC_ENABLE_SHARED([DEFAULT]) -# --------------------------- -# implement the --enable-shared flag -# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. -AC_DEFUN([AC_ENABLE_SHARED], -[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl -AC_ARG_ENABLE([shared], - [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@], - [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])], - [p=${PACKAGE-default} - case $enableval in - yes) enable_shared=yes ;; - no) enable_shared=no ;; - *) - enable_shared=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for pkg in $enableval; do - IFS="$lt_save_ifs" - if test "X$pkg" = "X$p"; then - enable_shared=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac], - [enable_shared=]AC_ENABLE_SHARED_DEFAULT) -])# AC_ENABLE_SHARED - - -# AC_DISABLE_SHARED -# ----------------- -#- set the default shared flag to --disable-shared -AC_DEFUN([AC_DISABLE_SHARED], -[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl -AC_ENABLE_SHARED(no) -])# AC_DISABLE_SHARED - - -# AC_ENABLE_STATIC([DEFAULT]) -# --------------------------- -# implement the --enable-static flag -# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. -AC_DEFUN([AC_ENABLE_STATIC], -[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl -AC_ARG_ENABLE([static], - [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@], - [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])], - [p=${PACKAGE-default} - case $enableval in - yes) enable_static=yes ;; - no) enable_static=no ;; - *) - enable_static=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for pkg in $enableval; do - IFS="$lt_save_ifs" - if test "X$pkg" = "X$p"; then - enable_static=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac], - [enable_static=]AC_ENABLE_STATIC_DEFAULT) -])# AC_ENABLE_STATIC - - -# AC_DISABLE_STATIC -# ----------------- -# set the default static flag to --disable-static -AC_DEFUN([AC_DISABLE_STATIC], -[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl -AC_ENABLE_STATIC(no) -])# AC_DISABLE_STATIC - - -# AC_ENABLE_FAST_INSTALL([DEFAULT]) -# --------------------------------- -# implement the --enable-fast-install flag -# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. -AC_DEFUN([AC_ENABLE_FAST_INSTALL], -[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl -AC_ARG_ENABLE([fast-install], - [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], - [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], - [p=${PACKAGE-default} - case $enableval in - yes) enable_fast_install=yes ;; - no) enable_fast_install=no ;; - *) - enable_fast_install=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for pkg in $enableval; do - IFS="$lt_save_ifs" - if test "X$pkg" = "X$p"; then - enable_fast_install=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac], - [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT) -])# AC_ENABLE_FAST_INSTALL - - -# AC_DISABLE_FAST_INSTALL -# ----------------------- -# set the default to --disable-fast-install -AC_DEFUN([AC_DISABLE_FAST_INSTALL], -[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl -AC_ENABLE_FAST_INSTALL(no) -])# AC_DISABLE_FAST_INSTALL - - -# AC_LIBTOOL_PICMODE([MODE]) -# -------------------------- -# implement the --with-pic flag -# MODE is either `yes' or `no'. If omitted, it defaults to `both'. -AC_DEFUN([AC_LIBTOOL_PICMODE], -[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl -pic_mode=ifelse($#,1,$1,default) -])# AC_LIBTOOL_PICMODE - - -# AC_PROG_EGREP -# ------------- -# This is predefined starting with Autoconf 2.54, so this conditional -# definition can be removed once we require Autoconf 2.54 or later. -m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP], -[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], - [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 - then ac_cv_prog_egrep='grep -E' - else ac_cv_prog_egrep='egrep' - fi]) - EGREP=$ac_cv_prog_egrep - AC_SUBST([EGREP]) -])]) - - -# AC_PATH_TOOL_PREFIX -# ------------------- -# find a file program which can recognise shared library -AC_DEFUN([AC_PATH_TOOL_PREFIX], -[AC_REQUIRE([AC_PROG_EGREP])dnl -AC_MSG_CHECKING([for $1]) -AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, -[case $MAGIC_CMD in -[[\\/*] | ?:[\\/]*]) - lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD="$MAGIC_CMD" - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR -dnl $ac_dummy forces splitting on constant user-supplied paths. -dnl POSIX.2 word splitting is done only on the output of word expansions, -dnl not every word. This closes a longstanding sh security hole. - ac_dummy="ifelse([$2], , $PATH, [$2])" - for ac_dir in $ac_dummy; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$1; then - lt_cv_path_MAGIC_CMD="$ac_dir/$1" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" - MAGIC_CMD="$lt_cv_path_MAGIC_CMD" - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -EOF - fi ;; - esac - fi - break - fi - done - IFS="$lt_save_ifs" - MAGIC_CMD="$lt_save_MAGIC_CMD" - ;; -esac]) -MAGIC_CMD="$lt_cv_path_MAGIC_CMD" -if test -n "$MAGIC_CMD"; then - AC_MSG_RESULT($MAGIC_CMD) -else - AC_MSG_RESULT(no) -fi -])# AC_PATH_TOOL_PREFIX - - -# AC_PATH_MAGIC -# ------------- -# find a file program which can recognise a shared library -AC_DEFUN([AC_PATH_MAGIC], -[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) -if test -z "$lt_cv_path_MAGIC_CMD"; then - if test -n "$ac_tool_prefix"; then - AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) - else - MAGIC_CMD=: - fi -fi -])# AC_PATH_MAGIC - - -# AC_PROG_LD -# ---------- -# find the pathname to the GNU or non-GNU linker -AC_DEFUN([AC_PROG_LD], -[AC_ARG_WITH([gnu-ld], - [AC_HELP_STRING([--with-gnu-ld], - [assume the C compiler uses GNU ld @<:@default=no@:>@])], - [test "$withval" = no || with_gnu_ld=yes], - [with_gnu_ld=no]) -AC_REQUIRE([LT_AC_PROG_SED])dnl -AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([AC_CANONICAL_HOST])dnl -AC_REQUIRE([AC_CANONICAL_BUILD])dnl -ac_prog=ld -if test "$GCC" = yes; then - # Check if gcc -print-prog-name=ld gives a path. - AC_MSG_CHECKING([for ld used by $CC]) - case $host in - *-*-mingw*) - # gcc leaves a trailing carriage return which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [[\\/]]* | ?:[[\\/]]*) - re_direlt='/[[^/]][[^/]]*/\.\./' - # Canonicalize the pathname of ld - ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` - while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do - ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` - done - test -z "$LD" && LD="$ac_prog" - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test "$with_gnu_ld" = yes; then - AC_MSG_CHECKING([for GNU ld]) -else - AC_MSG_CHECKING([for non-GNU ld]) -fi -AC_CACHE_VAL(lt_cv_path_LD, -[if test -z "$LD"; then - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - lt_cv_path_LD="$ac_dir/$ac_prog" - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some GNU ld's only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null; then - case $host_cpu in - i*86 ) - # Not sure whether the presence of OpenBSD here was a mistake. - # Let's accept both of them until this is cleared up. - lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[[3-9]]86 (compact )?demand paged shared library' - lt_cv_file_magic_cmd=/usr/bin/file - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` - ;; - esac - else - lt_cv_deplibs_check_method=pass_all - fi - ;; - -gnu*) - lt_cv_deplibs_check_method=pass_all - ;; - -hpux10.20* | hpux11*) - lt_cv_file_magic_cmd=/usr/bin/file - case "$host_cpu" in - ia64*) - lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' - lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so - ;; - hppa*64*) - [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] - lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl - ;; - *) - lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' - lt_cv_file_magic_test_file=/usr/lib/libc.sl - ;; - esac - ;; - -irix5* | irix6* | nonstopux*) - case $LD in - *-32|*"-32 ") libmagic=32-bit;; - *-n32|*"-n32 ") libmagic=N32;; - *-64|*"-64 ") libmagic=64-bit;; - *) libmagic=never-match;; - esac - lt_cv_deplibs_check_method=pass_all - ;; - -# This must be Linux ELF. -linux*) - lt_cv_deplibs_check_method=pass_all - ;; - -netbsd* | netbsdelf*-gnu | knetbsd*-gnu) - if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then - lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' - fi - ;; - -newos6*) - lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' - lt_cv_file_magic_cmd=/usr/bin/file - lt_cv_file_magic_test_file=/usr/lib/libnls.so - ;; - -nto-qnx*) - lt_cv_deplibs_check_method=unknown - ;; - -openbsd*) - lt_cv_file_magic_cmd=/usr/bin/file - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB shared object' - else - lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library' - fi - ;; - -osf3* | osf4* | osf5*) - lt_cv_deplibs_check_method=pass_all - ;; - -sco3.2v5*) - lt_cv_deplibs_check_method=pass_all - ;; - -solaris*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) - case $host_vendor in - motorola) - lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` - ;; - ncr) - lt_cv_deplibs_check_method=pass_all - ;; - sequent) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' - ;; - sni) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" - lt_cv_file_magic_test_file=/lib/libc.so - ;; - siemens) - lt_cv_deplibs_check_method=pass_all - ;; - esac - ;; - -sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7* | sysv4*uw2*) - lt_cv_deplibs_check_method=pass_all - ;; -esac -]) -file_magic_cmd=$lt_cv_file_magic_cmd -deplibs_check_method=$lt_cv_deplibs_check_method -test -z "$deplibs_check_method" && deplibs_check_method=unknown -])# AC_DEPLIBS_CHECK_METHOD - - -# AC_PROG_NM -# ---------- -# find the pathname to a BSD-compatible name lister -AC_DEFUN([AC_PROG_NM], -[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM, -[if test -n "$NM"; then - # Let the user override the test. - lt_cv_path_NM="$NM" -else - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - tmp_nm="$ac_dir/${ac_tool_prefix}nm" - if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then - # Check to see if the nm accepts a BSD-compat flag. - # Adding the `sed 1q' prevents false positives on HP-UX, which says: - # nm: unknown option "B" ignored - # Tru64's nm complains that /dev/null is an invalid object file - case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in - */dev/null* | *'Invalid file or object type'*) - lt_cv_path_NM="$tmp_nm -B" - break - ;; - *) - case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in - */dev/null*) - lt_cv_path_NM="$tmp_nm -p" - break - ;; - *) - lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but - continue # so that we can try to find one that supports BSD flags - ;; - esac - esac - fi - done - IFS="$lt_save_ifs" - test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm -fi]) -NM="$lt_cv_path_NM" -])# AC_PROG_NM - - -# AC_CHECK_LIBM -# ------------- -# check for math library -AC_DEFUN([AC_CHECK_LIBM], -[AC_REQUIRE([AC_CANONICAL_HOST])dnl -LIBM= -case $host in -*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) - # These system don't have libm, or don't need it - ;; -*-ncr-sysv4.3*) - AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") - AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") - ;; -*) - AC_CHECK_LIB(m, cos, LIBM="-lm") - ;; -esac -])# AC_CHECK_LIBM - - -# AC_LIBLTDL_CONVENIENCE([DIRECTORY]) -# ----------------------------------- -# sets LIBLTDL to the link flags for the libltdl convenience library and -# LTDLINCL to the include flags for the libltdl header and adds -# --enable-ltdl-convenience to the configure arguments. Note that LIBLTDL -# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If -# DIRECTORY is not provided, it is assumed to be `libltdl'. LIBLTDL will -# be prefixed with '${top_builddir}/' and LTDLINCL will be prefixed with -# '${top_srcdir}/' (note the single quotes!). If your package is not -# flat and you're not using automake, define top_builddir and -# top_srcdir appropriately in the Makefiles. -AC_DEFUN([AC_LIBLTDL_CONVENIENCE], -[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl - case $enable_ltdl_convenience in - no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; - "") enable_ltdl_convenience=yes - ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; - esac - LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la - LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) - # For backwards non-gettext consistent compatibility... - INCLTDL="$LTDLINCL" -])# AC_LIBLTDL_CONVENIENCE - - -# AC_LIBLTDL_INSTALLABLE([DIRECTORY]) -# ----------------------------------- -# sets LIBLTDL to the link flags for the libltdl installable library and -# LTDLINCL to the include flags for the libltdl header and adds -# --enable-ltdl-install to the configure arguments. Note that LIBLTDL -# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If -# DIRECTORY is not provided and an installed libltdl is not found, it is -# assumed to be `libltdl'. LIBLTDL will be prefixed with '${top_builddir}/' -# and LTDLINCL will be prefixed with '${top_srcdir}/' (note the single -# quotes!). If your package is not flat and you're not using automake, -# define top_builddir and top_srcdir appropriately in the Makefiles. -# In the future, this macro may have to be called after AC_PROG_LIBTOOL. -AC_DEFUN([AC_LIBLTDL_INSTALLABLE], -[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl - AC_CHECK_LIB(ltdl, lt_dlinit, - [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], - [if test x"$enable_ltdl_install" = xno; then - AC_MSG_WARN([libltdl not installed, but installation disabled]) - else - enable_ltdl_install=yes - fi - ]) - if test x"$enable_ltdl_install" = x"yes"; then - ac_configure_args="$ac_configure_args --enable-ltdl-install" - LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la - LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) - else - ac_configure_args="$ac_configure_args --enable-ltdl-install=no" - LIBLTDL="-lltdl" - LTDLINCL= - fi - # For backwards non-gettext consistent compatibility... - INCLTDL="$LTDLINCL" -])# AC_LIBLTDL_INSTALLABLE - - -# AC_LIBTOOL_CXX -# -------------- -# enable support for C++ libraries -AC_DEFUN([AC_LIBTOOL_CXX], -[AC_REQUIRE([_LT_AC_LANG_CXX]) -])# AC_LIBTOOL_CXX - - -# _LT_AC_LANG_CXX -# --------------- -AC_DEFUN([_LT_AC_LANG_CXX], -[AC_REQUIRE([AC_PROG_CXX]) -AC_REQUIRE([AC_PROG_CXXCPP]) -_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX]) -])# _LT_AC_LANG_CXX - - -# AC_LIBTOOL_F77 -# -------------- -# enable support for Fortran 77 libraries -AC_DEFUN([AC_LIBTOOL_F77], -[AC_REQUIRE([_LT_AC_LANG_F77]) -])# AC_LIBTOOL_F77 - - -# _LT_AC_LANG_F77 -# --------------- -AC_DEFUN([_LT_AC_LANG_F77], -[AC_REQUIRE([AC_PROG_F77]) -_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77]) -])# _LT_AC_LANG_F77 - - -# AC_LIBTOOL_GCJ -# -------------- -# enable support for GCJ libraries -AC_DEFUN([AC_LIBTOOL_GCJ], -[AC_REQUIRE([_LT_AC_LANG_GCJ]) -])# AC_LIBTOOL_GCJ - - -# _LT_AC_LANG_GCJ -# --------------- -AC_DEFUN([_LT_AC_LANG_GCJ], -[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], - [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], - [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], - [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], - [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], - [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) -_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ]) -])# _LT_AC_LANG_GCJ - - -# AC_LIBTOOL_RC -# -------------- -# enable support for Windows resource files -AC_DEFUN([AC_LIBTOOL_RC], -[AC_REQUIRE([LT_AC_PROG_RC]) -_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC]) -])# AC_LIBTOOL_RC - - -# AC_LIBTOOL_LANG_C_CONFIG -# ------------------------ -# Ensure that the configuration vars for the C compiler are -# suitably defined. Those variables are subsequently used by -# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. -AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG]) -AC_DEFUN([_LT_AC_LANG_C_CONFIG], -[lt_save_CC="$CC" -AC_LANG_PUSH(C) - -# Source file extension for C test sources. -ac_ext=c - -# Object file extension for compiled C test sources. -objext=o -_LT_AC_TAGVAR(objext, $1)=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="int some_variable = 0;\n" - -# Code to be used in simple link tests -lt_simple_link_test_code='int main(){return(0);}\n' - -_LT_AC_SYS_COMPILER - -# -# Check for any special shared library compilation flags. -# -_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)= -if test "$GCC" = no; then - case $host_os in - sco3.2v5*) - _LT_AC_TAGVAR(lt_prog_cc_shlib, $1)='-belf' - ;; - esac -fi -if test -n "$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)"; then - AC_MSG_WARN([`$CC' requires `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to build shared libraries]) - if echo "$old_CC $old_CFLAGS " | grep "[[ ]]$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)[[ ]]" >/dev/null; then : - else - AC_MSG_WARN([add `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to the CC or CFLAGS env variable and reconfigure]) - _LT_AC_TAGVAR(lt_cv_prog_cc_can_build_shared, $1)=no - fi -fi - - -# -# Check to make sure the static flag actually works. -# -AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $_LT_AC_TAGVAR(lt_prog_compiler_static, $1) works], - _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1), - $_LT_AC_TAGVAR(lt_prog_compiler_static, $1), - [], - [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=]) - - -## CAVEAT EMPTOR: -## There is no encapsulation within the following macros, do not change -## the running order or otherwise move them around unless you know exactly -## what you are doing... -AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) -AC_LIBTOOL_PROG_COMPILER_PIC($1) -AC_LIBTOOL_PROG_CC_C_O($1) -AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) -AC_LIBTOOL_PROG_LD_SHLIBS($1) -AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) -AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) -AC_LIBTOOL_SYS_LIB_STRIP -AC_LIBTOOL_DLOPEN_SELF($1) - -# Report which librarie types wil actually be built -AC_MSG_CHECKING([if libtool supports shared libraries]) -AC_MSG_RESULT([$can_build_shared]) - -AC_MSG_CHECKING([whether to build shared libraries]) -test "$can_build_shared" = "no" && enable_shared=no - -# On AIX, shared libraries and static libraries use the same namespace, and -# are all built from PIC. -case "$host_os" in -aix3*) - test "$enable_shared" = yes && enable_static=no - if test -n "$RANLIB"; then - archive_cmds="$archive_cmds~\$RANLIB \$lib" - postinstall_cmds='$RANLIB $lib' - fi - ;; - -aix4* | aix5*) - if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then - test "$enable_shared" = yes && enable_static=no - fi - ;; - darwin* | rhapsody*) - if test "$GCC" = yes; then - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no - case "$host_os" in - rhapsody* | darwin1.[[012]]) - _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress' - ;; - *) # Darwin 1.3 on - if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then - _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' - else - case ${MACOSX_DEPLOYMENT_TARGET} in - 10.[[012]]) - _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' - ;; - 10.*) - _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup' - ;; - esac - fi - ;; - esac - output_verbose_link_cmd='echo' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring' - _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' - # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - _LT_AC_TAGVAR(hardcode_direct, $1)=no - _LT_AC_TAGVAR(hardcode_automatic, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' - _LT_AC_TAGVAR(link_all_deplibs, $1)=yes - else - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; -esac -AC_MSG_RESULT([$enable_shared]) - -AC_MSG_CHECKING([whether to build static libraries]) -# Make sure either enable_shared or enable_static is yes. -test "$enable_shared" = yes || enable_static=yes -AC_MSG_RESULT([$enable_static]) - -AC_LIBTOOL_CONFIG($1) - -AC_LANG_POP -CC="$lt_save_CC" -])# AC_LIBTOOL_LANG_C_CONFIG - - -# AC_LIBTOOL_LANG_CXX_CONFIG -# -------------------------- -# Ensure that the configuration vars for the C compiler are -# suitably defined. Those variables are subsequently used by -# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. -AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)]) -AC_DEFUN([_LT_AC_LANG_CXX_CONFIG], -[AC_LANG_PUSH(C++) -AC_REQUIRE([AC_PROG_CXX]) -AC_REQUIRE([AC_PROG_CXXCPP]) - -_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no -_LT_AC_TAGVAR(allow_undefined_flag, $1)= -_LT_AC_TAGVAR(always_export_symbols, $1)=no -_LT_AC_TAGVAR(archive_expsym_cmds, $1)= -_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= -_LT_AC_TAGVAR(hardcode_direct, $1)=no -_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= -_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= -_LT_AC_TAGVAR(hardcode_libdir_separator, $1)= -_LT_AC_TAGVAR(hardcode_minus_L, $1)=no -_LT_AC_TAGVAR(hardcode_automatic, $1)=no -_LT_AC_TAGVAR(module_cmds, $1)= -_LT_AC_TAGVAR(module_expsym_cmds, $1)= -_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown -_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds -_LT_AC_TAGVAR(no_undefined_flag, $1)= -_LT_AC_TAGVAR(whole_archive_flag_spec, $1)= -_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no - -# Dependencies to place before and after the object being linked: -_LT_AC_TAGVAR(predep_objects, $1)= -_LT_AC_TAGVAR(postdep_objects, $1)= -_LT_AC_TAGVAR(predeps, $1)= -_LT_AC_TAGVAR(postdeps, $1)= -_LT_AC_TAGVAR(compiler_lib_search_path, $1)= - -# Source file extension for C++ test sources. -ac_ext=cc - -# Object file extension for compiled C++ test sources. -objext=o -_LT_AC_TAGVAR(objext, $1)=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="int some_variable = 0;\n" - -# Code to be used in simple link tests -lt_simple_link_test_code='int main(int, char *[]) { return(0); }\n' - -# ltmain only uses $CC for tagged configurations so make sure $CC is set. -_LT_AC_SYS_COMPILER - -# Allow CC to be a program name with arguments. -lt_save_CC=$CC -lt_save_LD=$LD -lt_save_GCC=$GCC -GCC=$GXX -lt_save_with_gnu_ld=$with_gnu_ld -lt_save_path_LD=$lt_cv_path_LD -if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then - lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx -else - unset lt_cv_prog_gnu_ld -fi -if test -n "${lt_cv_path_LDCXX+set}"; then - lt_cv_path_LD=$lt_cv_path_LDCXX -else - unset lt_cv_path_LD -fi -test -z "${LDCXX+set}" || LD=$LDCXX -CC=${CXX-"c++"} -compiler=$CC -_LT_AC_TAGVAR(compiler, $1)=$CC -cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'` - -# We don't want -fno-exception wen compiling C++ code, so set the -# no_builtin_flag separately -if test "$GXX" = yes; then - _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' -else - _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= -fi - -if test "$GXX" = yes; then - # Set up default GNU C++ configuration - - AC_PROG_LD - - # Check if GNU C++ uses GNU ld as the underlying linker, since the - # archiving commands below assume that GNU ld is being used. - if test "$with_gnu_ld" = yes; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' - - # If archive_cmds runs LD, not CC, wlarc should be empty - # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to - # investigate it a little bit more. (MM) - wlarc='${wl}' - - # ancient GNU ld didn't support --whole-archive et. al. - if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ - grep 'no-whole-archive' > /dev/null; then - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - else - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= - fi - else - with_gnu_ld=no - wlarc= - - # A generic and very simple default shared library creation - # command for GNU C++ for the case where it uses the native - # linker, instead of GNU ld. If possible, this setting should - # overridden to take advantage of the native linker features on - # the platform it is being used on. - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' - fi - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' - -else - GXX=no - with_gnu_ld=no - wlarc= -fi - -# PORTME: fill in a description of your system's C++ link characteristics -AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) -_LT_AC_TAGVAR(ld_shlibs, $1)=yes -case $host_os in - aix3*) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - aix4* | aix5*) - if test "$host_cpu" = ia64; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag="" - else - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # need to do runtime linking. - case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) - for ld_flag in $LDFLAGS; do - case $ld_flag in - *-brtl*) - aix_use_runtimelinking=yes - break - ;; - esac - done - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - _LT_AC_TAGVAR(archive_cmds, $1)='' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' - _LT_AC_TAGVAR(link_all_deplibs, $1)=yes - - if test "$GXX" = yes; then - case $host_os in aix4.[012]|aix4.[012].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`${CC} -print-prog-name=collect2` - if test -f "$collect2name" && \ - strings "$collect2name" | grep resolve_lib_name >/dev/null - then - # We have reworked collect2 - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - else - # We have old collect2 - _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= - fi - esac - shared_flag='-shared' - else - # not using gcc - if test "$host_cpu" = ia64; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test "$aix_use_runtimelinking" = yes; then - shared_flag='${wl}-G' - else - shared_flag='${wl}-bM:SRE' - fi - fi - fi - - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to export. - _LT_AC_TAGVAR(always_export_symbols, $1)=yes - if test "$aix_use_runtimelinking" = yes; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' - # Determine the default libpath from the value encoded in an empty executable. - _LT_AC_SYS_LIBPATH_AIX - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" - - _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" - else - if test "$host_cpu" = ia64; then - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' - _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" - _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an empty executable. - _LT_AC_SYS_LIBPATH_AIX - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' - # -bexpall does not export symbols beginning with underscore (_) - _LT_AC_TAGVAR(always_export_symbols, $1)=yes - # Exported symbols can be pulled into shared objects from archives - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes - # This is similar to how AIX traditionally builds it's shared libraries. - _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' - fi - fi - ;; - chorus*) - case $cc_basename in - *) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - esac - ;; - - cygwin* | mingw* | pw32*) - # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, - # as there is no search path for DLLs. - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported - _LT_AC_TAGVAR(always_export_symbols, $1)=no - _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes - - if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' - # If the export-symbols file already is a .def file (1st line - # is EXPORTS), use it as is; otherwise, prepend... - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' - else - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - - darwin* | rhapsody*) - if test "$GXX" = yes; then - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no - case "$host_os" in - rhapsody* | darwin1.[[012]]) - _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress' - ;; - *) # Darwin 1.3 on - if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then - _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' - else - case ${MACOSX_DEPLOYMENT_TARGET} in - 10.[[012]]) - _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' - ;; - 10.*) - _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup' - ;; - esac - fi - ;; - esac - lt_int_apple_cc_single_mod=no - output_verbose_link_cmd='echo' - if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then - lt_int_apple_cc_single_mod=yes - fi - if test "X$lt_int_apple_cc_single_mod" = Xyes ; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' - else - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' - fi - _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' - - # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's - if test "X$lt_int_apple_cc_single_mod" = Xyes ; then - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - else - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - fi - _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - _LT_AC_TAGVAR(hardcode_direct, $1)=no - _LT_AC_TAGVAR(hardcode_automatic, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' - _LT_AC_TAGVAR(link_all_deplibs, $1)=yes - else - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - - dgux*) - case $cc_basename in - ec++) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - ghcx) - # Green Hills C++ Compiler - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - *) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - esac - ;; - freebsd[12]*) - # C++ shared libraries reported to be fairly broken before switch to ELF - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - freebsd-elf*) - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no - ;; - freebsd* | kfreebsd*-gnu) - # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF - # conventions - _LT_AC_TAGVAR(ld_shlibs, $1)=yes - ;; - gnu*) - ;; - hpux9*) - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, - # but as the default - # location of the library. - - case $cc_basename in - CC) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - aCC) - _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[-]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' - ;; - *) - if test "$GXX" = yes; then - _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - else - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - esac - ;; - hpux10*|hpux11*) - if test $with_gnu_ld = no; then - case "$host_cpu" in - hppa*64*) - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - ;; - ia64*) - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - ;; - *) - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' - ;; - esac - fi - case "$host_cpu" in - hppa*64*) - _LT_AC_TAGVAR(hardcode_direct, $1)=no - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - ia64*) - _LT_AC_TAGVAR(hardcode_direct, $1)=no - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, - # but as the default - # location of the library. - ;; - *) - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, - # but as the default - # location of the library. - ;; - esac - - case $cc_basename in - CC) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - aCC) - case "$host_cpu" in - hppa*64*|ia64*) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' - ;; - *) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - esac - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' - ;; - *) - if test "$GXX" = yes; then - if test $with_gnu_ld = no; then - case "$host_cpu" in - ia64*|hppa*64*) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' - ;; - *) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - esac - fi - else - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - esac - ;; - irix5* | irix6*) - case $cc_basename in - CC) - # SGI C++ - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' - - # Archives containing C++ object files must be created using - # "CC -ar", where "CC" is the IRIX C++ compiler. This is - # necessary to make sure instantiated templates are included - # in the archive. - _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' - ;; - *) - if test "$GXX" = yes; then - if test "$with_gnu_ld" = no; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' - else - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' - fi - fi - _LT_AC_TAGVAR(link_all_deplibs, $1)=yes - ;; - esac - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - ;; - linux*) - case $cc_basename in - KCC) - # Kuck and Associates, Inc. (KAI) C++ Compiler - - # KCC will only create a shared library if the output file - # ends with ".so" (or ".sl" for HP-UX), so rename the library - # to its proper name (with version) after linking. - _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir' - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' - - # Archives containing C++ object files must be created using - # "CC -Bstatic", where "CC" is the KAI C++ compiler. - _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' - ;; - icpc) - # Intel C++ - with_gnu_ld=yes - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' - ;; - cxx) - # Compaq C++ - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' - - runpath_var=LD_RUN_PATH - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' - ;; - esac - ;; - lynxos*) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - m88k*) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - mvs*) - case $cc_basename in - cxx) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - *) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - esac - ;; - netbsd* | netbsdelf*-gnu | knetbsd*-gnu) - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' - wlarc= - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - fi - # Workaround some broken pre-1.5 toolchains - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' - ;; - osf3*) - case $cc_basename in - KCC) - # Kuck and Associates, Inc. (KAI) C++ Compiler - - # KCC will only create a shared library if the output file - # ends with ".so" (or ".sl" for HP-UX), so rename the library - # to its proper name (with version) after linking. - _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - - # Archives containing C++ object files must be created using - # "CC -Bstatic", where "CC" is the KAI C++ compiler. - _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' - - ;; - RCC) - # Rational C++ 2.4.1 - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - cxx) - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' - ;; - *) - if test "$GXX" = yes && test "$with_gnu_ld" = no; then - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' - - else - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - esac - ;; - osf4* | osf5*) - case $cc_basename in - KCC) - # Kuck and Associates, Inc. (KAI) C++ Compiler - - # KCC will only create a shared library if the output file - # ends with ".so" (or ".sl" for HP-UX), so rename the library - # to its proper name (with version) after linking. - _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - - # Archives containing C++ object files must be created using - # the KAI C++ compiler. - _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' - ;; - RCC) - # Rational C++ 2.4.1 - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - cxx) - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ - echo "-hidden">> $lib.exp~ - $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry $objdir/so_locations -o $lib~ - $rm $lib.exp' - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' - ;; - *) - if test "$GXX" = yes && test "$with_gnu_ld" = no; then - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' - - else - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - esac - ;; - psos*) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - sco*) - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no - case $cc_basename in - CC) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - *) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - esac - ;; - sunos4*) - case $cc_basename in - CC) - # Sun C++ 4.x - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - lcc) - # Lucid - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - *) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - esac - ;; - solaris*) - case $cc_basename in - CC) - # Sun C++ 4.2, 5.x and Centerline C++ - _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - case $host_os in - solaris2.[0-5] | solaris2.[0-5].*) ;; - *) - # The C++ compiler is used as linker so we must use $wl - # flag to pass the commands to the underlying system - # linker. - # Supported since Solaris 2.6 (maybe 2.5.1?) - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' - ;; - esac - _LT_AC_TAGVAR(link_all_deplibs, $1)=yes - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[[LR]]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' - - # Archives containing C++ object files must be created using - # "CC -xar", where "CC" is the Sun C++ compiler. This is - # necessary to make sure instantiated templates are included - # in the archive. - _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' - ;; - gcx) - # Green Hills C++ Compiler - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' - - # The C++ compiler must be used to create the archive. - _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' - ;; - *) - # GNU C++ compiler with Solaris linker - if test "$GXX" = yes && test "$with_gnu_ld" = no; then - _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' - if $CC --version | grep -v '^2\.7' > /dev/null; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" - else - # g++ 2.7 appears to require `-G' NOT `-shared' on this - # platform. - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" - fi - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' - fi - ;; - esac - ;; - sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no - ;; - tandem*) - case $cc_basename in - NCC) - # NonStop-UX NCC 3.20 - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - *) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - esac - ;; - vxworks*) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - *) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; -esac -AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) -test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no - -_LT_AC_TAGVAR(GCC, $1)="$GXX" -_LT_AC_TAGVAR(LD, $1)="$LD" - -## CAVEAT EMPTOR: -## There is no encapsulation within the following macros, do not change -## the running order or otherwise move them around unless you know exactly -## what you are doing... -AC_LIBTOOL_POSTDEP_PREDEP($1) -AC_LIBTOOL_PROG_COMPILER_PIC($1) -AC_LIBTOOL_PROG_CC_C_O($1) -AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) -AC_LIBTOOL_PROG_LD_SHLIBS($1) -AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) -AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) -AC_LIBTOOL_SYS_LIB_STRIP -AC_LIBTOOL_DLOPEN_SELF($1) - -AC_LIBTOOL_CONFIG($1) - -AC_LANG_POP -CC=$lt_save_CC -LDCXX=$LD -LD=$lt_save_LD -GCC=$lt_save_GCC -with_gnu_ldcxx=$with_gnu_ld -with_gnu_ld=$lt_save_with_gnu_ld -lt_cv_path_LDCXX=$lt_cv_path_LD -lt_cv_path_LD=$lt_save_path_LD -lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld -lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld -])# AC_LIBTOOL_LANG_CXX_CONFIG - -# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME]) -# ------------------------ -# Figure out "hidden" library dependencies from verbose -# compiler output when linking a shared library. -# Parse the compiler output and extract the necessary -# objects, libraries and library flags. -AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[ -dnl we can't use the lt_simple_compile_test_code here, -dnl because it contains code intended for an executable, -dnl not a library. It's possible we should let each -dnl tag define a new lt_????_link_test_code variable, -dnl but it's only used here... -ifelse([$1],[],[cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext <> "$cfgfile" -ifelse([$1], [], -[#! $SHELL - -# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. -# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) -# NOTE: Changes made to this file will be lost: look at ltmain.sh. -# -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 -# Free Software Foundation, Inc. -# -# This file is part of GNU Libtool: -# Originally by Gordon Matzigkeit , 1996 -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# A sed program that does not truncate output. -SED=$lt_SED - -# Sed that helps us avoid accidentally triggering echo(1) options like -n. -Xsed="$SED -e s/^X//" - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi - -# The names of the tagged configurations supported by this script. -available_tags= - -# ### BEGIN LIBTOOL CONFIG], -[# ### BEGIN LIBTOOL TAG CONFIG: $tagname]) - -# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: - -# Shell to use when invoking shell scripts. -SHELL=$lt_SHELL - -# Whether or not to build shared libraries. -build_libtool_libs=$enable_shared - -# Whether or not to build static libraries. -build_old_libs=$enable_static - -# Whether or not to add -lc for building shared libraries. -build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1) - -# Whether or not to disallow shared libs when runtime libs are static -allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) - -# Whether or not to optimize for fast installation. -fast_install=$enable_fast_install - -# The host system. -host_alias=$host_alias -host=$host - -# An echo program that does not interpret backslashes. -echo=$lt_echo - -# The archiver. -AR=$lt_AR -AR_FLAGS=$lt_AR_FLAGS - -# A C compiler. -LTCC=$lt_LTCC - -# A language-specific compiler. -CC=$lt_[]_LT_AC_TAGVAR(compiler, $1) - -# Is the compiler the GNU C compiler? -with_gcc=$_LT_AC_TAGVAR(GCC, $1) - -# An ERE matcher. -EGREP=$lt_EGREP - -# The linker used to build libraries. -LD=$lt_[]_LT_AC_TAGVAR(LD, $1) - -# Whether we need hard or soft links. -LN_S=$lt_LN_S - -# A BSD-compatible nm program. -NM=$lt_NM - -# A symbol stripping program -STRIP=$lt_STRIP - -# Used to examine libraries when file_magic_cmd begins "file" -MAGIC_CMD=$MAGIC_CMD - -# Used on cygwin: DLL creation program. -DLLTOOL="$DLLTOOL" - -# Used on cygwin: object dumper. -OBJDUMP="$OBJDUMP" - -# Used on cygwin: assembler. -AS="$AS" - -# The name of the directory that contains temporary libtool files. -objdir=$objdir - -# How to create reloadable object files. -reload_flag=$lt_reload_flag -reload_cmds=$lt_reload_cmds - -# How to pass a linker flag through the compiler. -wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) - -# Object file suffix (normally "o"). -objext="$ac_objext" - -# Old archive suffix (normally "a"). -libext="$libext" - -# Shared library suffix (normally ".so"). -shrext_cmds='$shrext_cmds' - -# Executable file suffix (normally ""). -exeext="$exeext" - -# Additional compiler flags for building library objects. -pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) -pic_mode=$pic_mode - -# What is the maximum length of a command? -max_cmd_len=$lt_cv_sys_max_cmd_len - -# Does compiler simultaneously support -c and -o options? -compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) - -# Must we lock files when doing compilation ? -need_locks=$lt_need_locks - -# Do we need the lib prefix for modules? -need_lib_prefix=$need_lib_prefix - -# Do we need a version for libraries? -need_version=$need_version - -# Whether dlopen is supported. -dlopen_support=$enable_dlopen - -# Whether dlopen of programs is supported. -dlopen_self=$enable_dlopen_self - -# Whether dlopen of statically linked programs is supported. -dlopen_self_static=$enable_dlopen_self_static - -# Compiler flag to prevent dynamic linking. -link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1) - -# Compiler flag to turn off builtin functions. -no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1) - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1) - -# Compiler flag to generate thread-safe objects. -thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1) - -# Library versioning type. -version_type=$version_type - -# Format of library name prefix. -libname_spec=$lt_libname_spec - -# List of archive names. First name is the real one, the rest are links. -# The last name is the one that the linker finds with -lNAME. -library_names_spec=$lt_library_names_spec - -# The coded name of the library, if different from the real name. -soname_spec=$lt_soname_spec - -# Commands used to build and install an old-style archive. -RANLIB=$lt_RANLIB -old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1) -old_postinstall_cmds=$lt_old_postinstall_cmds -old_postuninstall_cmds=$lt_old_postuninstall_cmds - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1) - -# Create a temporary old-style archive to link instead of a shared archive. -old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) - -# Commands used to build and install a shared archive. -archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1) -archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1) -postinstall_cmds=$lt_postinstall_cmds -postuninstall_cmds=$lt_postuninstall_cmds - -# Commands used to build a loadable module (assumed same as above if empty) -module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1) -module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1) - -# Commands to strip libraries. -old_striplib=$lt_old_striplib -striplib=$lt_striplib - -# Dependencies to place before the objects being linked to create a -# shared library. -predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1) - -# Dependencies to place after the objects being linked to create a -# shared library. -postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1) - -# Dependencies to place before the objects being linked to create a -# shared library. -predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1) - -# Dependencies to place after the objects being linked to create a -# shared library. -postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1) - -# The library search path used internally by the compiler when linking -# a shared library. -compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1) - -# Method to check whether dependent libraries are shared objects. -deplibs_check_method=$lt_deplibs_check_method - -# Command to use when deplibs_check_method == file_magic. -file_magic_cmd=$lt_file_magic_cmd - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1) - -# Flag that forces no undefined symbols. -no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1) - -# Commands used to finish a libtool library installation in a directory. -finish_cmds=$lt_finish_cmds - -# Same as above, but a single script fragment to be evaled but not shown. -finish_eval=$lt_finish_eval - -# Take the output of nm and produce a listing of raw symbols and C names. -global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe - -# Transform the output of nm in a proper C declaration -global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl - -# Transform the output of nm in a C name address pair -global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address - -# This is the shared library runtime path variable. -runpath_var=$runpath_var - -# This is the shared library path variable. -shlibpath_var=$shlibpath_var - -# Is shlibpath searched before the hard-coded library search path? -shlibpath_overrides_runpath=$shlibpath_overrides_runpath - -# How to hardcode a shared library path into an executable. -hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1) - -# Whether we should hardcode library paths into libraries. -hardcode_into_libs=$hardcode_into_libs - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist. -hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) - -# If ld is used when linking, flag to hardcode \$libdir into -# a binary during linking. This must work even if \$libdir does -# not exist. -hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) - -# Whether we need a single -rpath flag with a separated argument. -hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1) - -# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the -# resulting binary. -hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1) - -# Set to yes if using the -LDIR flag during linking hardcodes DIR into the -# resulting binary. -hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1) - -# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into -# the resulting binary. -hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1) - -# Set to yes if building a shared library automatically hardcodes DIR into the library -# and all subsequent libraries and executables linked against it. -hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1) - -# Variables whose values should be saved in libtool wrapper scripts and -# restored at relink time. -variables_saved_for_relink="$variables_saved_for_relink" - -# Whether libtool must link a program against all its dependency libraries. -link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1) - -# Compile-time system search path for libraries -sys_lib_search_path_spec=$lt_sys_lib_search_path_spec - -# Run-time system search path for libraries -sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec - -# Fix the shell variable \$srcfile for the compiler. -fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)" - -# Set to yes if exported symbols are required. -always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1) - -# The commands to list exported symbols. -export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1) - -# The commands to extract the exported symbol list from a shared archive. -extract_expsyms_cmds=$lt_extract_expsyms_cmds - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1) - -# Symbols that must always be exported. -include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1) - -ifelse([$1],[], -[# ### END LIBTOOL CONFIG], -[# ### END LIBTOOL TAG CONFIG: $tagname]) - -__EOF__ - -ifelse([$1],[], [ - case $host_os in - aix3*) - cat <<\EOF >> "$cfgfile" - -# AIX sometimes has problems with the GCC collect2 program. For some -# reason, if we set the COLLECT_NAMES environment variable, the problems -# vanish in a puff of smoke. -if test "X${COLLECT_NAMES+set}" != Xset; then - COLLECT_NAMES= - export COLLECT_NAMES -fi -EOF - ;; - esac - - # We use sed instead of cat because bash on DJGPP gets confused if - # if finds mixed CR/LF and LF-only lines. Since sed operates in - # text mode, it properly converts lines to CR/LF. This bash problem - # is reportedly fixed, but why not run on old versions too? - sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) - - mv -f "$cfgfile" "$ofile" || \ - (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") - chmod +x "$ofile" -]) -else - # If there is no Makefile yet, we rely on a make rule to execute - # `config.status --recheck' to rerun these tests and create the - # libtool script then. - ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` - if test -f "$ltmain_in"; then - test -f Makefile && make "$ltmain" - fi -fi -])# AC_LIBTOOL_CONFIG - - -# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME]) -# ------------------------------------------- -AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], -[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl - -_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= - -if test "$GCC" = yes; then - _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' - - AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], - lt_cv_prog_compiler_rtti_exceptions, - [-fno-rtti -fno-exceptions], [], - [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) -fi -])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI - - -# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE -# --------------------------------- -AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], -[AC_REQUIRE([AC_CANONICAL_HOST]) -AC_REQUIRE([AC_PROG_NM]) -AC_REQUIRE([AC_OBJEXT]) -# Check for command to grab the raw symbol name followed by C symbol from nm. -AC_MSG_CHECKING([command to parse $NM output from $compiler object]) -AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], -[ -# These are sane defaults that work on at least a few old systems. -# [They come from Ultrix. What could be older than Ultrix?!! ;)] - -# Character class describing NM global symbol codes. -symcode='[[BCDEGRST]]' - -# Regexp to match symbols that can be accessed directly from C. -sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' - -# Transform the above into a raw symbol and a C symbol. -symxfrm='\1 \2\3 \3' - -# Transform an extracted symbol line into a proper C declaration -lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" - -# Transform an extracted symbol line into symbol name and symbol address -lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" - -# Define system-specific variables. -case $host_os in -aix*) - symcode='[[BCDT]]' - ;; -cygwin* | mingw* | pw32*) - symcode='[[ABCDGISTW]]' - ;; -hpux*) # Its linker distinguishes data from code symbols - if test "$host_cpu" = ia64; then - symcode='[[ABCDEGRST]]' - fi - lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" - lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" - ;; -irix* | nonstopux*) - symcode='[[BCDEGRST]]' - ;; -osf*) - symcode='[[BCDEGQRST]]' - ;; -solaris* | sysv5*) - symcode='[[BDRT]]' - ;; -sysv4) - symcode='[[DFNSTU]]' - ;; -esac - -# Handle CRLF in mingw tool chain -opt_cr= -case $build_os in -mingw*) - opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp - ;; -esac - -# If we're using GNU nm, then use its standard symbol codes. -case `$NM -V 2>&1` in -*GNU* | *'with BFD'*) - symcode='[[ABCDGIRSTW]]' ;; -esac - -# Try without a prefix undercore, then with it. -for ac_symprfx in "" "_"; do - - # Write the raw and C identifiers. - lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'" - - # Check to see that the pipe works correctly. - pipe_works=no - - rm -f conftest* - cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then - # Try sorting and uniquifying the output. - if sort "$nlist" | uniq > "$nlist"T; then - mv -f "$nlist"T "$nlist" - else - rm -f "$nlist"T - fi - - # Make sure that we snagged all the symbols we need. - if grep ' nm_test_var$' "$nlist" >/dev/null; then - if grep ' nm_test_func$' "$nlist" >/dev/null; then - cat < conftest.$ac_ext -#ifdef __cplusplus -extern "C" { -#endif - -EOF - # Now generate the symbol file. - eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' - - cat <> conftest.$ac_ext -#if defined (__STDC__) && __STDC__ -# define lt_ptr_t void * -#else -# define lt_ptr_t char * -# define const -#endif - -/* The mapping between symbol names and symbols. */ -const struct { - const char *name; - lt_ptr_t address; -} -lt_preloaded_symbols[[]] = -{ -EOF - $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext - cat <<\EOF >> conftest.$ac_ext - {0, (lt_ptr_t) 0} -}; - -#ifdef __cplusplus -} -#endif -EOF - # Now try linking the two files. - mv conftest.$ac_objext conftstm.$ac_objext - lt_save_LIBS="$LIBS" - lt_save_CFLAGS="$CFLAGS" - LIBS="conftstm.$ac_objext" - CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" - if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then - pipe_works=yes - fi - LIBS="$lt_save_LIBS" - CFLAGS="$lt_save_CFLAGS" - else - echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD - fi - else - echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD - fi - else - echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD - fi - else - echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD - cat conftest.$ac_ext >&5 - fi - rm -f conftest* conftst* - - # Do not use the global_symbol_pipe unless it works. - if test "$pipe_works" = yes; then - break - else - lt_cv_sys_global_symbol_pipe= - fi -done -]) -if test -z "$lt_cv_sys_global_symbol_pipe"; then - lt_cv_sys_global_symbol_to_cdecl= -fi -if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then - AC_MSG_RESULT(failed) -else - AC_MSG_RESULT(ok) -fi -]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE - - -# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME]) -# --------------------------------------- -AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC], -[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)= -_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= -_LT_AC_TAGVAR(lt_prog_compiler_static, $1)= - -AC_MSG_CHECKING([for $compiler option to produce PIC]) - ifelse([$1],[CXX],[ - # C++ specific cases for pic, static, wl, etc. - if test "$GXX" = yes; then - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - fi - ;; - amigaos*) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the `-m68020' flag to GCC prevents building anything better, - # like `-m68040'. - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' - ;; - beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - mingw* | os2* | pw32*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' - ;; - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' - ;; - *djgpp*) - # DJGPP does not support shared libraries at all - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= - ;; - sysv4*MP*) - if test -d /usr/nec; then - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic - fi - ;; - hpux*) - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case "$host_cpu" in - hppa*64*|ia64*) - ;; - *) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - esac - ;; - *) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - esac - else - case $host_os in - aix4* | aix5*) - # All AIX code is PIC. - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - else - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' - fi - ;; - chorus*) - case $cc_basename in - cxch68) - # Green Hills C++ Compiler - # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" - ;; - esac - ;; - dgux*) - case $cc_basename in - ec++) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - ;; - ghcx) - # Green Hills C++ Compiler - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' - ;; - *) - ;; - esac - ;; - freebsd* | kfreebsd*-gnu) - # FreeBSD uses GNU C++ - ;; - hpux9* | hpux10* | hpux11*) - case $cc_basename in - CC) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" - if test "$host_cpu" != ia64; then - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' - fi - ;; - aCC) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" - case "$host_cpu" in - hppa*64*|ia64*) - # +Z the default - ;; - *) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' - ;; - esac - ;; - *) - ;; - esac - ;; - irix5* | irix6* | nonstopux*) - case $cc_basename in - CC) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - # CC pic flag -KPIC is the default. - ;; - *) - ;; - esac - ;; - linux*) - case $cc_basename in - KCC) - # KAI C++ Compiler - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - icpc) - # Intel C++ - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' - ;; - cxx) - # Compaq C++ - # Make sure the PIC flag is empty. It appears that all Alpha - # Linux and Compaq Tru64 Unix objects are PIC. - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - ;; - *) - ;; - esac - ;; - lynxos*) - ;; - m88k*) - ;; - mvs*) - case $cc_basename in - cxx) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' - ;; - *) - ;; - esac - ;; - netbsd* | netbsdelf*-gnu | knetbsd*-gnu) - ;; - osf3* | osf4* | osf5*) - case $cc_basename in - KCC) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' - ;; - RCC) - # Rational C++ 2.4.1 - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' - ;; - cxx) - # Digital/Compaq C++ - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - # Make sure the PIC flag is empty. It appears that all Alpha - # Linux and Compaq Tru64 Unix objects are PIC. - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - ;; - *) - ;; - esac - ;; - psos*) - ;; - sco*) - case $cc_basename in - CC) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - *) - ;; - esac - ;; - solaris*) - case $cc_basename in - CC) - # Sun C++ 4.2, 5.x and Centerline C++ - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' - ;; - gcx) - # Green Hills C++ Compiler - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' - ;; - *) - ;; - esac - ;; - sunos4*) - case $cc_basename in - CC) - # Sun C++ 4.x - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - lcc) - # Lucid - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' - ;; - *) - ;; - esac - ;; - tandem*) - case $cc_basename in - NCC) - # NonStop-UX NCC 3.20 - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - ;; - *) - ;; - esac - ;; - unixware*) - ;; - vxworks*) - ;; - *) - _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no - ;; - esac - fi -], -[ - if test "$GCC" = yes; then - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - fi - ;; - - amigaos*) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the `-m68020' flag to GCC prevents building anything better, - # like `-m68040'. - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' - ;; - - beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - - mingw* | pw32* | os2*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' - ;; - - msdosdjgpp*) - # Just because we use GCC doesn't mean we suddenly get shared libraries - # on systems that don't support them. - _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no - enable_shared=no - ;; - - sysv4*MP*) - if test -d /usr/nec; then - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic - fi - ;; - - hpux*) - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case "$host_cpu" in - hppa*64*|ia64*) - # +Z the default - ;; - *) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - esac - ;; - - *) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - esac - else - # PORTME Check for flag to pass linker flags through the system compiler. - case $host_os in - aix*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - else - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' - fi - ;; - - mingw* | pw32* | os2*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' - ;; - - hpux9* | hpux10* | hpux11*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case "$host_cpu" in - hppa*64*|ia64*) - # +Z the default - ;; - *) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' - ;; - esac - # Is there a better lt_prog_compiler_static that works with the bundled CC? - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' - ;; - - irix5* | irix6* | nonstopux*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - # PIC (with -KPIC) is the default. - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - ;; - - newsos6) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - - linux*) - case $CC in - icc* | ecc*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' - ;; - ccc*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - # All Alpha code is PIC. - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - ;; - esac - ;; - - osf3* | osf4* | osf5*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - # All OSF/1 code is PIC. - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - ;; - - sco3.2v5*) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kpic' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-dn' - ;; - - solaris*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - - sunos4*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - - sysv4*MP*) - if test -d /usr/nec ;then - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - fi - ;; - - uts4*) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - - *) - _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no - ;; - esac - fi -]) -AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)]) - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then - AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works], - _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1), - [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [], - [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in - "" | " "*) ;; - *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;; - esac], - [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= - _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) -fi -case "$host_os" in - # For platforms which do not support PIC, -DPIC is meaningless: - *djgpp*) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= - ;; - *) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])" - ;; -esac -]) - - -# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME]) -# ------------------------------------ -# See if the linker supports building shared libraries. -AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS], -[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) -ifelse([$1],[CXX],[ - _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - case $host_os in - aix4* | aix5*) - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to AIX nm, but means don't demangle with GNU nm - if $NM -V 2>&1 | grep 'GNU' > /dev/null; then - _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' - else - _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' - fi - ;; - pw32*) - _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" - ;; - cygwin* | mingw*) - _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' - ;; - linux*) - _LT_AC_TAGVAR(link_all_deplibs, $1)=no - ;; - *) - _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - ;; - esac -],[ - runpath_var= - _LT_AC_TAGVAR(allow_undefined_flag, $1)= - _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no - _LT_AC_TAGVAR(archive_cmds, $1)= - _LT_AC_TAGVAR(archive_expsym_cmds, $1)= - _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)= - _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)= - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= - _LT_AC_TAGVAR(thread_safe_flag_spec, $1)= - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= - _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= - _LT_AC_TAGVAR(hardcode_direct, $1)=no - _LT_AC_TAGVAR(hardcode_minus_L, $1)=no - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported - _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown - _LT_AC_TAGVAR(hardcode_automatic, $1)=no - _LT_AC_TAGVAR(module_cmds, $1)= - _LT_AC_TAGVAR(module_expsym_cmds, $1)= - _LT_AC_TAGVAR(always_export_symbols, $1)=no - _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - # include_expsyms should be a list of space-separated symbols to be *always* - # included in the symbol list - _LT_AC_TAGVAR(include_expsyms, $1)= - # exclude_expsyms can be an extended regexp of symbols to exclude - # it will be wrapped by ` (' and `)$', so one must not match beginning or - # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', - # as well as any symbol that contains `d'. - _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_" - # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out - # platforms (ab)use it in PIC code, but their linkers get confused if - # the symbol is explicitly referenced. Since portable code cannot - # rely on this symbol name, it's probably fine to never include it in - # preloaded symbol tables. - extract_expsyms_cmds= - - case $host_os in - cygwin* | mingw* | pw32*) - # FIXME: the MSVC++ port hasn't been tested in a loooong time - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - if test "$GCC" != yes; then - with_gnu_ld=no - fi - ;; - openbsd*) - with_gnu_ld=no - ;; - esac - - _LT_AC_TAGVAR(ld_shlibs, $1)=yes - if test "$with_gnu_ld" = yes; then - # If archive_cmds runs LD, not CC, wlarc should be empty - wlarc='${wl}' - - # See if GNU ld supports shared libraries. - case $host_os in - aix3* | aix4* | aix5*) - # On AIX/PPC, the GNU linker is very broken - if test "$host_cpu" != ia64; then - _LT_AC_TAGVAR(ld_shlibs, $1)=no - cat <&2 - -*** Warning: the GNU linker, at least up to release 2.9.1, is reported -*** to be unable to reliably create shared libraries on AIX. -*** Therefore, libtool is disabling shared libraries support. If you -*** really care for shared libraries, you may want to modify your PATH -*** so that a non-GNU linker is found, and then restart. - -EOF - fi - ;; - - amigaos*) - _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - - # Samuel A. Falvo II reports - # that the semantics of dynamic libraries on AmigaOS, at least up - # to version 4, is to share data among multiple programs linked - # with the same dynamic library. Since this doesn't match the - # behavior of shared libraries on other platforms, we can't use - # them. - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - - beos*) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported - # Joseph Beckenbach says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - else - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - - cygwin* | mingw* | pw32*) - # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, - # as there is no search path for DLLs. - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported - _LT_AC_TAGVAR(always_export_symbols, $1)=no - _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes - _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' - - if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' - # If the export-symbols file already is a .def file (1st line - # is EXPORTS), use it as is; otherwise, prepend... - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' - else - ld_shlibs=no - fi - ;; - - netbsd* | netbsdelf*-gnu | knetbsd*-gnu) - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' - wlarc= - else - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - fi - ;; - - solaris* | sysv5*) - if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then - _LT_AC_TAGVAR(ld_shlibs, $1)=no - cat <&2 - -*** Warning: The releases 2.8.* of the GNU linker cannot reliably -*** create shared libraries on Solaris systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.9.1 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -EOF - elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - - sunos4*) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' - wlarc= - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - linux*) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - _LT_AC_TAGVAR(archive_cmds, $1)="$tmp_archive_cmds" - supports_anon_versioning=no - case `$LD -v 2>/dev/null` in - *\ [01].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 - *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... - *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... - *\ 2.11.*) ;; # other 2.11 versions - *) supports_anon_versioning=yes ;; - esac - if test $supports_anon_versioning = yes; then - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~ -cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ -$echo "local: *; };" >> $output_objdir/$libname.ver~ - $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' - else - _LT_AC_TAGVAR(archive_expsym_cmds, $1)="$tmp_archive_cmds" - fi - _LT_AC_TAGVAR(link_all_deplibs, $1)=no - else - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - - *) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - esac - - if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = yes; then - runpath_var=LD_RUN_PATH - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' - # ancient GNU ld didn't support --whole-archive et. al. - if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - else - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= - fi - fi - else - # PORTME fill in a description of your system's linker (not GNU ld) - case $host_os in - aix3*) - _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported - _LT_AC_TAGVAR(always_export_symbols, $1)=yes - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' - # Note: this linker hardcodes the directories in LIBPATH if there - # are no directories specified by -L. - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - if test "$GCC" = yes && test -z "$link_static_flag"; then - # Neither direct hardcoding nor static linking is supported with a - # broken collect2. - _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported - fi - ;; - - aix4* | aix5*) - if test "$host_cpu" = ia64; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag="" - else - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to AIX nm, but means don't demangle with GNU nm - if $NM -V 2>&1 | grep 'GNU' > /dev/null; then - _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' - else - _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' - fi - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # need to do runtime linking. - case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) - for ld_flag in $LDFLAGS; do - if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then - aix_use_runtimelinking=yes - break - fi - done - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - _LT_AC_TAGVAR(archive_cmds, $1)='' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' - _LT_AC_TAGVAR(link_all_deplibs, $1)=yes - - if test "$GCC" = yes; then - case $host_os in aix4.[012]|aix4.[012].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`${CC} -print-prog-name=collect2` - if test -f "$collect2name" && \ - strings "$collect2name" | grep resolve_lib_name >/dev/null - then - # We have reworked collect2 - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - else - # We have old collect2 - _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= - fi - esac - shared_flag='-shared' - else - # not using gcc - if test "$host_cpu" = ia64; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test "$aix_use_runtimelinking" = yes; then - shared_flag='${wl}-G' - else - shared_flag='${wl}-bM:SRE' - fi - fi - fi - - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to export. - _LT_AC_TAGVAR(always_export_symbols, $1)=yes - if test "$aix_use_runtimelinking" = yes; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' - # Determine the default libpath from the value encoded in an empty executable. - _LT_AC_SYS_LIBPATH_AIX - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" - _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" - else - if test "$host_cpu" = ia64; then - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' - _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" - _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an empty executable. - _LT_AC_SYS_LIBPATH_AIX - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' - # -bexpall does not export symbols beginning with underscore (_) - _LT_AC_TAGVAR(always_export_symbols, $1)=yes - # Exported symbols can be pulled into shared objects from archives - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes - # This is similar to how AIX traditionally builds it's shared libraries. - _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' - fi - fi - ;; - - amigaos*) - _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - # see comment about different semantics on the GNU ld section - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - - bsdi4*) - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic - ;; - - cygwin* | mingw* | pw32*) - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' - _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=".dll" - # FIXME: Setting linknames here is a bad hack. - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' - # The linker will automatically build a .lib file if we build a DLL. - _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true' - # FIXME: Should let the user specify the lib program. - _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs' - fix_srcfile_path='`cygpath -w "$srcfile"`' - _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes - ;; - - darwin* | rhapsody*) - if test "$GXX" = yes ; then - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no - case "$host_os" in - rhapsody* | darwin1.[[012]]) - _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress' - ;; - *) # Darwin 1.3 on - if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then - _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' - else - case ${MACOSX_DEPLOYMENT_TARGET} in - 10.[[012]]) - _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' - ;; - 10.*) - _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup' - ;; - esac - fi - ;; - esac - lt_int_apple_cc_single_mod=no - output_verbose_link_cmd='echo' - if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then - lt_int_apple_cc_single_mod=yes - fi - if test "X$lt_int_apple_cc_single_mod" = Xyes ; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' - else - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' - fi - _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' - # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's - if test "X$lt_int_apple_cc_single_mod" = Xyes ; then - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - else - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - fi - _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - _LT_AC_TAGVAR(hardcode_direct, $1)=no - _LT_AC_TAGVAR(hardcode_automatic, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' - _LT_AC_TAGVAR(link_all_deplibs, $1)=yes - else - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - - dgux*) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - freebsd1*) - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - - # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor - # support. Future versions do this automatically, but an explicit c++rt0.o - # does not break anything, and helps significantly (at the cost of a little - # extra space). - freebsd2.2*) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - # Unfortunately, older versions of FreeBSD 2 do not have this feature. - freebsd2*) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - # FreeBSD 3 and greater uses gcc -shared to do shared libraries. - freebsd* | kfreebsd*-gnu) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - hpux9*) - if test "$GCC" = yes; then - _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - else - _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - fi - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' - ;; - - hpux10* | hpux11*) - if test "$GCC" = yes -a "$with_gnu_ld" = no; then - case "$host_cpu" in - hppa*64*|ia64*) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - else - case "$host_cpu" in - hppa*64*|ia64*) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags' - ;; - *) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' - ;; - esac - fi - if test "$with_gnu_ld" = no; then - case "$host_cpu" in - hppa*64*) - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - _LT_AC_TAGVAR(hardcode_direct, $1)=no - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - ia64*) - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(hardcode_direct, $1)=no - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - ;; - *) - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - ;; - esac - fi - ;; - - irix5* | irix6* | nonstopux*) - if test "$GCC" = yes; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - else - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' - fi - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - _LT_AC_TAGVAR(link_all_deplibs, $1)=yes - ;; - - netbsd* | netbsdelf*-gnu | knetbsd*-gnu) - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out - else - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF - fi - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - newsos6) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - openbsd*) - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' - else - case $host_os in - openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - ;; - *) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' - ;; - esac - fi - ;; - - os2*) - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported - _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' - _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' - ;; - - osf3*) - if test "$GCC" = yes; then - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - else - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - fi - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - ;; - - osf4* | osf5*) # as osf3* with the addition of -msym flag - if test "$GCC" = yes; then - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' - else - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ - $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' - - # Both c and cxx compiler support -rpath directly - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' - fi - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - ;; - - sco3.2v5*) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' - runpath_var=LD_RUN_PATH - hardcode_runpath_var=yes - ;; - - solaris*) - _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' - if test "$GCC" = yes; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' - else - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' - fi - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - case $host_os in - solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; - *) # Supported since Solaris 2.6 (maybe 2.5.1?) - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; - esac - _LT_AC_TAGVAR(link_all_deplibs, $1)=yes - ;; - - sunos4*) - if test "x$host_vendor" = xsequent; then - # Use $CC to link under sequent, because it throws in some extra .o - # files that make .init and .fini sections work. - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' - else - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' - fi - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - sysv4) - case $host_vendor in - sni) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true??? - ;; - siemens) - ## LD is ld it makes a PLAMLIB - ## CC just makes a GrossModule. - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' - _LT_AC_TAGVAR(hardcode_direct, $1)=no - ;; - motorola) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie - ;; - esac - runpath_var='LD_RUN_PATH' - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - sysv4.3*) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - runpath_var=LD_RUN_PATH - hardcode_runpath_var=yes - _LT_AC_TAGVAR(ld_shlibs, $1)=yes - fi - ;; - - sysv4.2uw2*) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_minus_L, $1)=no - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - hardcode_runpath_var=yes - runpath_var=LD_RUN_PATH - ;; - - sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) - _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z ${wl}text' - if test "$GCC" = yes; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - else - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - runpath_var='LD_RUN_PATH' - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - sysv5*) - _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' - # $CC -shared without GNU ld will not create a library from C++ - # object files and a static libstdc++, better avoid it by now - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - runpath_var='LD_RUN_PATH' - ;; - - uts4*) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - *) - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - esac - fi -]) -AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) -test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no - -variables_saved_for_relink="PATH $shlibpath_var $runpath_var" -if test "$GCC" = yes; then - variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" -fi - -# -# Do we need to explicitly link libc? -# -case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in -x|xyes) - # Assume -lc should be added - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes - - if test "$enable_shared" = yes && test "$GCC" = yes; then - case $_LT_AC_TAGVAR(archive_cmds, $1) in - *'~'*) - # FIXME: we may have to deal with multi-command sequences. - ;; - '$CC '*) - # Test whether the compiler implicitly links with -lc since on some - # systems, -lgcc has to come before -lc. If gcc already passes -lc - # to ld, don't add -lc before -lgcc. - AC_MSG_CHECKING([whether -lc should be explicitly linked in]) - $rm conftest* - printf "$lt_simple_compile_test_code" > conftest.$ac_ext - - if AC_TRY_EVAL(ac_compile) 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1) - _LT_AC_TAGVAR(allow_undefined_flag, $1)= - if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) - then - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no - else - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes - fi - _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $rm conftest* - AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)]) - ;; - esac - fi - ;; -esac -])# AC_LIBTOOL_PROG_LD_SHLIBS - - -# _LT_AC_FILE_LTDLL_C -# ------------------- -# Be careful that the start marker always follows a newline. -AC_DEFUN([_LT_AC_FILE_LTDLL_C], [ -# /* ltdll.c starts here */ -# #define WIN32_LEAN_AND_MEAN -# #include -# #undef WIN32_LEAN_AND_MEAN -# #include -# -# #ifndef __CYGWIN__ -# # ifdef __CYGWIN32__ -# # define __CYGWIN__ __CYGWIN32__ -# # endif -# #endif -# -# #ifdef __cplusplus -# extern "C" { -# #endif -# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); -# #ifdef __cplusplus -# } -# #endif -# -# #ifdef __CYGWIN__ -# #include -# DECLARE_CYGWIN_DLL( DllMain ); -# #endif -# HINSTANCE __hDllInstance_base; -# -# BOOL APIENTRY -# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) -# { -# __hDllInstance_base = hInst; -# return TRUE; -# } -# /* ltdll.c ends here */ -])# _LT_AC_FILE_LTDLL_C - - -# _LT_AC_TAGVAR(VARNAME, [TAGNAME]) -# --------------------------------- -AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])]) - - -# old names -AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) -AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) -AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) -AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) -AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) -AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) -AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) - -# This is just to silence aclocal about the macro not being used -ifelse([AC_DISABLE_FAST_INSTALL]) - -AC_DEFUN([LT_AC_PROG_GCJ], -[AC_CHECK_TOOL(GCJ, gcj, no) - test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" - AC_SUBST(GCJFLAGS) -]) - -AC_DEFUN([LT_AC_PROG_RC], -[AC_CHECK_TOOL(RC, windres, no) -]) - -############################################################ -# NOTE: This macro has been submitted for inclusion into # -# GNU Autoconf as AC_PROG_SED. When it is available in # -# a released version of Autoconf we should remove this # -# macro and use it instead. # -############################################################ -# LT_AC_PROG_SED -# -------------- -# Check for a fully-functional sed program, that truncates -# as few characters as possible. Prefer GNU sed if found. -AC_DEFUN([LT_AC_PROG_SED], -[AC_MSG_CHECKING([for a sed that does not truncate output]) -AC_CACHE_VAL(lt_cv_path_SED, -[# Loop through the user's path and test for sed and gsed. -# Then use that list of sed's as ones to test for truncation. -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for lt_ac_prog in sed gsed; do - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then - lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" - fi - done - done -done -lt_ac_max=0 -lt_ac_count=0 -# Add /usr/xpg4/bin/sed as it is typically found on Solaris -# along with /bin/sed that truncates output. -for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do - test ! -f $lt_ac_sed && break - cat /dev/null > conftest.in - lt_ac_count=0 - echo $ECHO_N "0123456789$ECHO_C" >conftest.in - # Check for GNU sed and select it if it is found. - if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then - lt_cv_path_SED=$lt_ac_sed - break - fi - while true; do - cat conftest.in conftest.in >conftest.tmp - mv conftest.tmp conftest.in - cp conftest.in conftest.nl - echo >>conftest.nl - $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break - cmp -s conftest.out conftest.nl || break - # 10000 chars as input seems more than enough - test $lt_ac_count -gt 10 && break - lt_ac_count=`expr $lt_ac_count + 1` - if test $lt_ac_count -gt $lt_ac_max; then - lt_ac_max=$lt_ac_count - lt_cv_path_SED=$lt_ac_sed - fi - done -done -SED=$lt_cv_path_SED -]) -AC_MSG_RESULT([$SED]) -]) diff --git a/ltdl.m4 b/ltdl.m4 deleted file mode 100644 index aa6a0d13..00000000 --- a/ltdl.m4 +++ /dev/null @@ -1,431 +0,0 @@ -## ltdl.m4 - Configure ltdl for the target system. -*-Autoconf-*- -## Copyright (C) 1999-2000 Free Software Foundation, Inc. -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -## -## As a special exception to the GNU General Public License, if you -## distribute this file as part of a program that contains a -## configuration script generated by Autoconf, you may include it under -## the same distribution terms that you use for the rest of that program. - -# serial 6 AC_LIB_LTDL -# Debian $Rev: 214 $ - -# AC_WITH_LTDL -# ------------ -# Clients of libltdl can use this macro to allow the installer to -# choose between a shipped copy of the ltdl sources or a preinstalled -# version of the library. -AC_DEFUN([AC_WITH_LTDL], -[AC_REQUIRE([AC_LIB_LTDL]) -AC_SUBST([LIBLTDL]) -AC_SUBST([INCLTDL]) - -# Unless the user asks us to check, assume no installed ltdl exists. -use_installed_libltdl=no - -AC_ARG_WITH([included_ltdl], - [ --with-included-ltdl use the GNU ltdl sources included here]) - -if test "x$with_included_ltdl" != xyes; then - # We are not being forced to use the included libltdl sources, so - # decide whether there is a useful installed version we can use. - AC_CHECK_HEADER([ltdl.h], - [AC_CHECK_LIB([ltdl], [lt_dlcaller_register], - [with_included_ltdl=no], - [with_included_ltdl=yes]) - ]) -fi - -if test "x$enable_ltdl_install" != xyes; then - # If the user did not specify an installable libltdl, then default - # to a convenience lib. - AC_LIBLTDL_CONVENIENCE -fi - -if test "x$with_included_ltdl" = xno; then - # If the included ltdl is not to be used. then Use the - # preinstalled libltdl we found. - AC_DEFINE([HAVE_LTDL], 1, - [Define this if a modern libltdl is already installed]) - LIBLTDL=-lltdl -fi - -# Report our decision... -AC_MSG_CHECKING([whether to use included libltdl]) -AC_MSG_RESULT([$with_included_ltdl]) - -AC_CONFIG_SUBDIRS([libltdl]) -])# AC_WITH_LTDL - - -# AC_LIB_LTDL -# ----------- -# Perform all the checks necessary for compilation of the ltdl objects -# -- including compiler checks and header checks. -AC_DEFUN([AC_LIB_LTDL], -[AC_PREREQ(2.50) -AC_REQUIRE([AC_PROG_CC]) -AC_REQUIRE([AC_C_CONST]) -AC_REQUIRE([AC_HEADER_STDC]) -AC_REQUIRE([AC_HEADER_DIRENT]) -AC_REQUIRE([_LT_AC_CHECK_DLFCN]) -AC_REQUIRE([AC_LTDL_ENABLE_INSTALL]) -AC_REQUIRE([AC_LTDL_SHLIBEXT]) -AC_REQUIRE([AC_LTDL_SHLIBPATH]) -AC_REQUIRE([AC_LTDL_SYSSEARCHPATH]) -AC_REQUIRE([AC_LTDL_OBJDIR]) -AC_REQUIRE([AC_LTDL_DLPREOPEN]) -AC_REQUIRE([AC_LTDL_DLLIB]) -AC_REQUIRE([AC_LTDL_SYMBOL_USCORE]) -AC_REQUIRE([AC_LTDL_DLSYM_USCORE]) -AC_REQUIRE([AC_LTDL_SYS_DLOPEN_DEPLIBS]) -AC_REQUIRE([AC_LTDL_FUNC_ARGZ]) - -AC_CHECK_HEADERS([assert.h ctype.h errno.h malloc.h memory.h stdlib.h \ - stdio.h unistd.h]) -AC_CHECK_HEADERS([dl.h sys/dl.h dld.h mach-o/dyld.h]) -AC_CHECK_HEADERS([string.h strings.h], [break]) - -AC_CHECK_FUNCS([strchr index], [break]) -AC_CHECK_FUNCS([strrchr rindex], [break]) -AC_CHECK_FUNCS([memcpy bcopy], [break]) -AC_CHECK_FUNCS([memmove strcmp]) -AC_CHECK_FUNCS([closedir opendir readdir]) -])# AC_LIB_LTDL - - -# AC_LTDL_ENABLE_INSTALL -# ---------------------- -AC_DEFUN([AC_LTDL_ENABLE_INSTALL], -[AC_ARG_ENABLE([ltdl-install], - [AC_HELP_STRING([--enable-ltdl-install], [install libltdl])]) - -AM_CONDITIONAL(INSTALL_LTDL, test x"${enable_ltdl_install-no}" != xno) -AM_CONDITIONAL(CONVENIENCE_LTDL, test x"${enable_ltdl_convenience-no}" != xno) -])])# AC_LTDL_ENABLE_INSTALL - - -# AC_LTDL_SYS_DLOPEN_DEPLIBS -# -------------------------- -AC_DEFUN([AC_LTDL_SYS_DLOPEN_DEPLIBS], -[AC_REQUIRE([AC_CANONICAL_HOST]) -AC_CACHE_CHECK([whether deplibs are loaded by dlopen], - [libltdl_cv_sys_dlopen_deplibs], - [# PORTME does your system automatically load deplibs for dlopen? - # or its logical equivalent (e.g. shl_load for HP-UX < 11) - # For now, we just catch OSes we know something about -- in the - # future, we'll try test this programmatically. - libltdl_cv_sys_dlopen_deplibs=unknown - case "$host_os" in - aix3*|aix4.1.*|aix4.2.*) - # Unknown whether this is true for these versions of AIX, but - # we want this `case' here to explicitly catch those versions. - libltdl_cv_sys_dlopen_deplibs=unknown - ;; - aix[[45]]*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - darwin*) - # Assuming the user has installed a libdl from somewhere, this is true - # If you are looking for one http://www.opendarwin.org/projects/dlcompat - libltdl_cv_sys_dlopen_deplibs=yes - ;; - gnu* | linux* | kfreebsd*-gnu | knetbsd*-gnu) - # GNU and its variants, using gnu ld.so (Glibc) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - hpux10*|hpux11*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - irix[[12345]]*|irix6.[[01]]*) - # Catch all versions of IRIX before 6.2, and indicate that we don't - # know how it worked for any of those versions. - libltdl_cv_sys_dlopen_deplibs=unknown - ;; - irix*) - # The case above catches anything before 6.2, and it's known that - # at 6.2 and later dlopen does load deplibs. - libltdl_cv_sys_dlopen_deplibs=yes - ;; - netbsd* | netbsdelf*-gnu) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - openbsd*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - osf[[1234]]*) - # dlopen did load deplibs (at least at 4.x), but until the 5.x series, - # it did *not* use an RPATH in a shared library to find objects the - # library depends on, so we explictly say `no'. - libltdl_cv_sys_dlopen_deplibs=no - ;; - osf5.0|osf5.0a|osf5.1) - # dlopen *does* load deplibs and with the right loader patch applied - # it even uses RPATH in a shared library to search for shared objects - # that the library depends on, but there's no easy way to know if that - # patch is installed. Since this is the case, all we can really - # say is unknown -- it depends on the patch being installed. If - # it is, this changes to `yes'. Without it, it would be `no'. - libltdl_cv_sys_dlopen_deplibs=unknown - ;; - osf*) - # the two cases above should catch all versions of osf <= 5.1. Read - # the comments above for what we know about them. - # At > 5.1, deplibs are loaded *and* any RPATH in a shared library - # is used to find them so we can finally say `yes'. - libltdl_cv_sys_dlopen_deplibs=yes - ;; - solaris*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - esac - ]) -if test "$libltdl_cv_sys_dlopen_deplibs" != yes; then - AC_DEFINE([LTDL_DLOPEN_DEPLIBS], [1], - [Define if the OS needs help to load dependent libraries for dlopen().]) -fi -])# AC_LTDL_SYS_DLOPEN_DEPLIBS - - -# AC_LTDL_SHLIBEXT -# ---------------- -AC_DEFUN([AC_LTDL_SHLIBEXT], -[AC_REQUIRE([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) -AC_CACHE_CHECK([which extension is used for loadable modules], - [libltdl_cv_shlibext], -[ -module=yes -eval libltdl_cv_shlibext=$shrext_cmds - ]) -if test -n "$libltdl_cv_shlibext"; then - AC_DEFINE_UNQUOTED(LTDL_SHLIB_EXT, "$libltdl_cv_shlibext", - [Define to the extension used for shared libraries, say, ".so".]) -fi -])# AC_LTDL_SHLIBEXT - - -# AC_LTDL_SHLIBPATH -# ----------------- -AC_DEFUN([AC_LTDL_SHLIBPATH], -[AC_REQUIRE([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) -AC_CACHE_CHECK([which variable specifies run-time library path], - [libltdl_cv_shlibpath_var], [libltdl_cv_shlibpath_var="$shlibpath_var"]) -if test -n "$libltdl_cv_shlibpath_var"; then - AC_DEFINE_UNQUOTED(LTDL_SHLIBPATH_VAR, "$libltdl_cv_shlibpath_var", - [Define to the name of the environment variable that determines the dynamic library search path.]) -fi -])# AC_LTDL_SHLIBPATH - - -# AC_LTDL_SYSSEARCHPATH -# --------------------- -AC_DEFUN([AC_LTDL_SYSSEARCHPATH], -[AC_REQUIRE([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) -AC_CACHE_CHECK([for the default library search path], - [libltdl_cv_sys_search_path], - [libltdl_cv_sys_search_path="$sys_lib_dlsearch_path_spec"]) -if test -n "$libltdl_cv_sys_search_path"; then - sys_search_path= - for dir in $libltdl_cv_sys_search_path; do - if test -z "$sys_search_path"; then - sys_search_path="$dir" - else - sys_search_path="$sys_search_path$PATH_SEPARATOR$dir" - fi - done - AC_DEFINE_UNQUOTED(LTDL_SYSSEARCHPATH, "$sys_search_path", - [Define to the system default library search path.]) -fi -])# AC_LTDL_SYSSEARCHPATH - - -# AC_LTDL_OBJDIR -# -------------- -AC_DEFUN([AC_LTDL_OBJDIR], -[AC_CACHE_CHECK([for objdir], - [libltdl_cv_objdir], - [libltdl_cv_objdir="$objdir" - if test -n "$objdir"; then - : - else - rm -f .libs 2>/dev/null - mkdir .libs 2>/dev/null - if test -d .libs; then - libltdl_cv_objdir=.libs - else - # MS-DOS does not allow filenames that begin with a dot. - libltdl_cv_objdir=_libs - fi - rmdir .libs 2>/dev/null - fi - ]) -AC_DEFINE_UNQUOTED(LTDL_OBJDIR, "$libltdl_cv_objdir/", - [Define to the sub-directory in which libtool stores uninstalled libraries.]) -])# AC_LTDL_OBJDIR - - -# AC_LTDL_DLPREOPEN -# ----------------- -AC_DEFUN([AC_LTDL_DLPREOPEN], -[AC_REQUIRE([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE]) -AC_CACHE_CHECK([whether libtool supports -dlopen/-dlpreopen], - [libltdl_cv_preloaded_symbols], - [if test -n "$lt_cv_sys_global_symbol_pipe"; then - libltdl_cv_preloaded_symbols=yes - else - libltdl_cv_preloaded_symbols=no - fi - ]) -if test x"$libltdl_cv_preloaded_symbols" = xyes; then - AC_DEFINE(HAVE_PRELOADED_SYMBOLS, 1, - [Define if libtool can extract symbol lists from object files.]) -fi -])# AC_LTDL_DLPREOPEN - - -# AC_LTDL_DLLIB -# ------------- -AC_DEFUN([AC_LTDL_DLLIB], -[LIBADD_DL= -AC_SUBST(LIBADD_DL) -AC_LANG_PUSH([C]) - -AC_CHECK_FUNC([shl_load], - [AC_DEFINE([HAVE_SHL_LOAD], [1], - [Define if you have the shl_load function.])], - [AC_CHECK_LIB([dld], [shl_load], - [AC_DEFINE([HAVE_SHL_LOAD], [1], - [Define if you have the shl_load function.]) - LIBADD_DL="$LIBADD_DL -ldld"], - [AC_CHECK_LIB([dl], [dlopen], - [AC_DEFINE([HAVE_LIBDL], [1], - [Define if you have the libdl library or equivalent.]) - LIBADD_DL="-ldl" libltdl_cv_lib_dl_dlopen="yes"], - [AC_TRY_LINK([#if HAVE_DLFCN_H -# include -#endif - ], - [dlopen(0, 0);], - [AC_DEFINE([HAVE_LIBDL], [1], - [Define if you have the libdl library or equivalent.]) libltdl_cv_func_dlopen="yes"], - [AC_CHECK_LIB([svld], [dlopen], - [AC_DEFINE([HAVE_LIBDL], [1], - [Define if you have the libdl library or equivalent.]) - LIBADD_DL="-lsvld" libltdl_cv_func_dlopen="yes"], - [AC_CHECK_LIB([dld], [dld_link], - [AC_DEFINE([HAVE_DLD], [1], - [Define if you have the GNU dld library.]) - LIBADD_DL="$LIBADD_DL -ldld"], - [AC_CHECK_FUNC([_dyld_func_lookup], - [AC_DEFINE([HAVE_DYLD], [1], - [Define if you have the _dyld_func_lookup function.])]) - ]) - ]) - ]) - ]) - ]) -]) - -if test x"$libltdl_cv_func_dlopen" = xyes || test x"$libltdl_cv_lib_dl_dlopen" = xyes -then - lt_save_LIBS="$LIBS" - LIBS="$LIBS $LIBADD_DL" - AC_CHECK_FUNCS([dlerror]) - LIBS="$lt_save_LIBS" -fi -AC_LANG_POP -])# AC_LTDL_DLLIB - - -# AC_LTDL_SYMBOL_USCORE -# --------------------- -# does the compiler prefix global symbols with an underscore? -AC_DEFUN([AC_LTDL_SYMBOL_USCORE], -[AC_REQUIRE([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE]) -AC_CACHE_CHECK([for _ prefix in compiled symbols], - [ac_cv_sys_symbol_underscore], - [ac_cv_sys_symbol_underscore=no - cat > conftest.$ac_ext < $ac_nlist) && test -s "$ac_nlist"; then - # See whether the symbols have a leading underscore. - if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then - ac_cv_sys_symbol_underscore=yes - else - if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then - : - else - echo "configure: cannot find nm_test_func in $ac_nlist" >&AC_FD_CC - fi - fi - else - echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&AC_FD_CC - fi - else - echo "configure: failed program was:" >&AC_FD_CC - cat conftest.c >&AC_FD_CC - fi - rm -rf conftest* - ]) -])# AC_LTDL_SYMBOL_USCORE - - -# AC_LTDL_DLSYM_USCORE -# -------------------- -AC_DEFUN([AC_LTDL_DLSYM_USCORE], -[AC_REQUIRE([AC_LTDL_SYMBOL_USCORE]) -if test x"$ac_cv_sys_symbol_underscore" = xyes; then - if test x"$libltdl_cv_func_dlopen" = xyes || - test x"$libltdl_cv_lib_dl_dlopen" = xyes ; then - AC_CACHE_CHECK([whether we have to add an underscore for dlsym], - [libltdl_cv_need_uscore], - [libltdl_cv_need_uscore=unknown - save_LIBS="$LIBS" - LIBS="$LIBS $LIBADD_DL" - _LT_AC_TRY_DLOPEN_SELF( - [libltdl_cv_need_uscore=no], [libltdl_cv_need_uscore=yes], - [], [libltdl_cv_need_uscore=cross]) - LIBS="$save_LIBS" - ]) - fi -fi - -if test x"$libltdl_cv_need_uscore" = xyes; then - AC_DEFINE(NEED_USCORE, 1, - [Define if dlsym() requires a leading underscore in symbol names.]) -fi -])# AC_LTDL_DLSYM_USCORE - -# AC_LTDL_FUNC_ARGZ -# ----------------- -AC_DEFUN([AC_LTDL_FUNC_ARGZ], -[AC_CHECK_HEADERS([argz.h]) - -AC_CHECK_TYPES([error_t], - [], - [AC_DEFINE([error_t], [int], - [Define to a type to use for `error_t' if it is not otherwise available.])], - [#if HAVE_ARGZ_H -# include -#endif]) - -AC_CHECK_FUNCS([argz_append argz_create_sep argz_insert argz_next argz_stringify]) -])# AC_LTDL_FUNC_ARGZ -- cgit From 9c96bdcf01798b9146d232019825ca5cc927648a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 8 Jul 2006 13:25:35 +0000 Subject: * remove doc/ directory * move doc/todo to root dir git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1063 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 4 ++-- configure.ac | 1 - doc/Makefile.am | 20 -------------------- doc/todo | 46 ---------------------------------------------- todo | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 48 insertions(+), 69 deletions(-) delete mode 100644 doc/Makefile.am delete mode 100644 doc/todo create mode 100644 todo diff --git a/Makefile.am b/Makefile.am index d5d9b52f..566cec68 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,8 +17,8 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -EXTRA_DIST = bootstrap.sh LICENSE GPL LGPL doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in README -SUBDIRS=libltdl src doc doxygen +EXTRA_DIST = bootstrap.sh LICENSE GPL LGPL doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in README todo +SUBDIRS=libltdl src doxygen MAINTAINERCLEANFILES = noinst_DATA = diff --git a/configure.ac b/configure.ac index 6b82effd..300201f7 100644 --- a/configure.ac +++ b/configure.ac @@ -677,7 +677,6 @@ libpulse-simple.pc libpulse-browse.pc libpulse-mainloop-glib.pc libpulse-mainloop-glib12.pc -doc/Makefile doxygen/Makefile doxygen/doxygen.conf src/pulse/version.h diff --git a/doc/Makefile.am b/doc/Makefile.am deleted file mode 100644 index 1e9fe244..00000000 --- a/doc/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -# $Id$ - -# This file is part of PulseAudio. -# -# PulseAudio is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# PulseAudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with PulseAudio; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - -EXTRA_DIST = todo - diff --git a/doc/todo b/doc/todo deleted file mode 100644 index 1ea40d3e..00000000 --- a/doc/todo +++ /dev/null @@ -1,46 +0,0 @@ -*** $Id$ *** - -Post 0.9.0: -- alsa mmap driver -- dbus/hal -- polish for starting polypaudio as root/system-wide instance -- chroot() -- module-tunnel: improve latency calculation -- port from howl to avahi -- multiline configuration statements -- use scatter/gather io for sockets -- rtp module ported to Win32 (sendmsg/recvmsg emulation) -- CODECs to reduce bandwidth usage (plug-in based) -- Remove symdef files and use macros (like most other projects) -- Use own name mangling scheme instead of ltdl's, which will eliminate the - need for .la files or extra trickery. -- use software volume when hardware doesn't support all channels (alsa done) -- paplay needs to set a channel map. our default is only correct for AIFF. - (we need help from libsndfile for this) -- silence generation should be moved into the core to avoid races and code - duplication in the backends -- examine if it is possible to mimic esd's handling of half duplex cards - (switch to capture when a recording client connects and drop playback during - that time) -- Fix a way for the threading API to handle state and subscription callbacks - in a nice way. -- iconv stuff sent from utils to server (UTF-8) -- iconv sample loading in server -- Document utf8.h, timeval.h and util.h -- fix clock of the NULL sink -- gettextify polypaudio -- use send() with MSG_NOSIGNAL instead of write() wherever possible, and than drop that SIGPIPE warning -- drop dependency of libpolyp on libX11, instead use an external mini binary -- "hot" moving of streams between sinks -- check if using prctl(PR_GET_NAME) makes sense in pa_get_binary_name() -- gconf module + frontend -- hooks for creating sink inputs - -Long term: -- pass meta info for hearing impaired -- X11: support for the X11 synchronization extension - -Backends for: -- portaudio (semi-done) -- sdl -- xine (needs update) diff --git a/todo b/todo new file mode 100644 index 00000000..1ea40d3e --- /dev/null +++ b/todo @@ -0,0 +1,46 @@ +*** $Id$ *** + +Post 0.9.0: +- alsa mmap driver +- dbus/hal +- polish for starting polypaudio as root/system-wide instance +- chroot() +- module-tunnel: improve latency calculation +- port from howl to avahi +- multiline configuration statements +- use scatter/gather io for sockets +- rtp module ported to Win32 (sendmsg/recvmsg emulation) +- CODECs to reduce bandwidth usage (plug-in based) +- Remove symdef files and use macros (like most other projects) +- Use own name mangling scheme instead of ltdl's, which will eliminate the + need for .la files or extra trickery. +- use software volume when hardware doesn't support all channels (alsa done) +- paplay needs to set a channel map. our default is only correct for AIFF. + (we need help from libsndfile for this) +- silence generation should be moved into the core to avoid races and code + duplication in the backends +- examine if it is possible to mimic esd's handling of half duplex cards + (switch to capture when a recording client connects and drop playback during + that time) +- Fix a way for the threading API to handle state and subscription callbacks + in a nice way. +- iconv stuff sent from utils to server (UTF-8) +- iconv sample loading in server +- Document utf8.h, timeval.h and util.h +- fix clock of the NULL sink +- gettextify polypaudio +- use send() with MSG_NOSIGNAL instead of write() wherever possible, and than drop that SIGPIPE warning +- drop dependency of libpolyp on libX11, instead use an external mini binary +- "hot" moving of streams between sinks +- check if using prctl(PR_GET_NAME) makes sense in pa_get_binary_name() +- gconf module + frontend +- hooks for creating sink inputs + +Long term: +- pass meta info for hearing impaired +- X11: support for the X11 synchronization extension + +Backends for: +- portaudio (semi-done) +- sdl +- xine (needs update) -- cgit From 3428f0384def9f1b39889d6a06c3780820d8ec5c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 10 Jul 2006 17:56:05 +0000 Subject: mark HAL for shams king git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1065 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/todo b/todo index 1ea40d3e..978331f4 100644 --- a/todo +++ b/todo @@ -2,7 +2,7 @@ Post 0.9.0: - alsa mmap driver -- dbus/hal +- dbus/hal (Shams King is working on this one) - polish for starting polypaudio as root/system-wide instance - chroot() - module-tunnel: improve latency calculation -- cgit From 81621641b77cfa897cb136e670b9defaa4642fff Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Jul 2006 15:51:49 +0000 Subject: check for avahi in configure.ac git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1066 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/configure.ac b/configure.ac index 300201f7..eb6fa2d3 100644 --- a/configure.ac +++ b/configure.ac @@ -510,6 +510,37 @@ AC_SUBST(HOWL_LIBS) AC_SUBST(HAVE_HOWL) AM_CONDITIONAL([HAVE_HOWL], [test "x$HAVE_HOWL" = x1]) +#### Avahi support (optional) #### + +AC_ARG_ENABLE([avahi], + AC_HELP_STRING([--disable-avahi], [Disable optional Avahi support]), + [ + case "${enableval}" in + yes) avahi=yes ;; + no) avahi=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-avahi) ;; + esac + ], + [avahi=auto]) + +if test "x${avahi}" != xno ; then + PKG_CHECK_MODULES(AVAHI, [ avahi-client >= 0.6.0 ], + HAVE_AVAHI=1, + [ + HAVE_AVAHI=0 + if test "x$avahi" = xyes ; then + AC_MSG_ERROR([*** Avahi support not found]) + fi + ]) +else + HAVE_AVAHI=0 +fi + +AC_SUBST(AVAHI_CFLAGS) +AC_SUBST(AVAHI_LIBS) +AC_SUBST(HAVE_AVAHI) +AM_CONDITIONAL([HAVE_AVAHI], [test "x$HAVE_AVAHI" = x1]) + ### LIBOIL #### PKG_CHECK_MODULES(LIBOIL, [ liboil-0.3 >= 0.3.0 ]) -- cgit From 10f7a6457545320595574ad249a3e9e1dd56c481 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Jul 2006 15:52:34 +0000 Subject: make sure gccmacro.h and cdecl.h may be included at the same time as those headers from the avahi project git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1067 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/cdecl.h | 4 ++-- src/pulsecore/gccmacro.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pulse/cdecl.h b/src/pulse/cdecl.h index 6ac96687..a3ec231c 100644 --- a/src/pulse/cdecl.h +++ b/src/pulse/cdecl.h @@ -1,5 +1,5 @@ -#ifndef foocdeclhfoo -#define foocdeclhfoo +#ifndef foopulsecdeclhfoo +#define foopulsecdeclhfoo /* $Id$ */ diff --git a/src/pulsecore/gccmacro.h b/src/pulsecore/gccmacro.h index 2ab999d9..8825700a 100644 --- a/src/pulsecore/gccmacro.h +++ b/src/pulsecore/gccmacro.h @@ -1,5 +1,5 @@ -#ifndef foogccmacrohfoo -#define foogccmacrohfoo +#ifndef foopulsegccmacrohfoo +#define foopulsegccmacrohfoo /* $Id$ */ -- cgit From 3a816205ffde85bcf06c9ff55febc1ba69ce8de9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Jul 2006 15:54:13 +0000 Subject: update module-zeroconf-publish to make use of the native AVAHI API, instead of HOWL git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1068 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 19 +- src/modules/module-zeroconf-publish.c | 426 ++++++++++++++++++++++++---------- src/pulsecore/avahi-wrap.c | 188 +++++++++++++++ src/pulsecore/avahi-wrap.h | 33 +++ 4 files changed, 537 insertions(+), 129 deletions(-) create mode 100644 src/pulsecore/avahi-wrap.c create mode 100644 src/pulsecore/avahi-wrap.h diff --git a/src/Makefile.am b/src/Makefile.am index 2bd3b871..8c8168d5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -667,6 +667,14 @@ modlibexec_LTLIBRARIES += \ libx11prop.la endif +if HAVE_AVAHI +pulsecoreinclude_HEADERS += \ + pulsecore/avahi-wrap.h + +modlibexec_LTLIBRARIES += \ + libavahi-wrap.la +endif + libprotocol_simple_la_SOURCES = pulsecore/protocol-simple.c pulsecore/protocol-simple.h libprotocol_simple_la_LDFLAGS = -avoid-version libprotocol_simple_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-server.la libiochannel.la @@ -770,6 +778,13 @@ libx11prop_la_LDFLAGS = -avoid-version libx11prop_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) libx11prop_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) +# Avahi + +libavahi_wrap_la_SOURCES = pulsecore/avahi-wrap.c pulsecore/avahi-wrap.h +libavahi_wrap_la_LDFLAGS = -avoid-version +libavahi_wrap_la_CFLAGS = $(AM_CFLAGS) $(AVAHI_CFLAGS) +libavahi_wrap_la_LIBADD = $(AM_LIBADD) $(AVAHI_CFLAGS) libpulsecore.la + ################################### # Plug-in libraries # ################################### @@ -1105,8 +1120,8 @@ libhowl_wrap_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) module_zeroconf_publish_la_SOURCES = modules/module-zeroconf-publish.c module_zeroconf_publish_la_LDFLAGS = -module -avoid-version -module_zeroconf_publish_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) libhowl-wrap.la libpulsecore.la -module_zeroconf_publish_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) +module_zeroconf_publish_la_LIBADD = $(AM_LIBADD) $(AVAHI_LIBS) libavahi-wrap.la libpulsecore.la +module_zeroconf_publish_la_CFLAGS = $(AM_CFLAGS) $(AVAHI_CFLAGS) # LIRC diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index 32fb1f41..23a188b3 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -29,6 +29,11 @@ #include #include +#include +#include +#include +#include + #include #include @@ -41,10 +46,8 @@ #include #include #include - -#include "../pulsecore/endianmacros.h" - -#include "howl-wrap.h" +#include +#include #include "module-zeroconf-publish-symdef.h" @@ -53,9 +56,9 @@ PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Publisher") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("port=") -#define SERVICE_NAME_SINK "_pulse-sink._tcp" -#define SERVICE_NAME_SOURCE "_pulse-source._tcp" -#define SERVICE_NAME_SERVER "_pulse-server._tcp" +#define SERVICE_TYPE_SINK "_pulse-sink._tcp" +#define SERVICE_TYPE_SOURCE "_pulse-source._tcp" +#define SERVICE_TYPE_SERVER "_pulse-server._tcp" static const char* const valid_modargs[] = { "port", @@ -63,9 +66,11 @@ static const char* const valid_modargs[] = { }; struct service { - sw_discovery_oid oid; + struct userdata *userdata; + AvahiEntryGroup *entry_group; + char *service_name; char *name; - int published; /* 0 -> not yet registered, 1 -> registered with data from real device, 2 -> registered with data from autoload device */ + enum { UNPUBLISHED, PUBLISHED_REAL, PUBLISHED_AUTOLOAD } published ; struct { int valid; @@ -82,19 +87,18 @@ struct service { struct userdata { pa_core *core; - pa_howl_wrapper *howl_wrapper; + AvahiPoll *avahi_poll; + AvahiClient *client; pa_hashmap *services; pa_dynarray *sink_dynarray, *source_dynarray, *autoload_dynarray; pa_subscription *subscription; + char *service_name; + + AvahiEntryGroup *main_entry_group; uint16_t port; - sw_discovery_oid server_oid; }; -static sw_result publish_reply(sw_discovery discovery, sw_discovery_publish_status status, sw_discovery_oid oid, sw_opaque extra) { - return SW_OKAY; -} - static void get_service_data(struct userdata *u, struct service *s, pa_sample_spec *ret_ss, char **ret_description) { assert(u && s && s->loaded.valid && ret_ss && ret_description); @@ -112,109 +116,144 @@ static void get_service_data(struct userdata *u, struct service *s, pa_sample_sp assert(0); } -static void txt_record_server_data(pa_core *c, sw_text_record t) { - char s[256]; +static AvahiStringList* txt_record_server_data(pa_core *c, AvahiStringList *l) { + char s[128]; assert(c); - sw_text_record_add_key_and_string_value(t, "server-version", PACKAGE_NAME" "PACKAGE_VERSION); - sw_text_record_add_key_and_string_value(t, "user-name", pa_get_user_name(s, sizeof(s))); - sw_text_record_add_key_and_string_value(t, "fqdn", pa_get_fqdn(s, sizeof(s))); - snprintf(s, sizeof(s), "0x%08x", c->cookie); - sw_text_record_add_key_and_string_value(t, "cookie", s); + l = avahi_string_list_add_pair(l, "server-version", PACKAGE_NAME" "PACKAGE_VERSION); + l = avahi_string_list_add_pair(l, "user-name", pa_get_user_name(s, sizeof(s))); + l = avahi_string_list_add_pair(l, "fqdn", pa_get_fqdn(s, sizeof(s))); + l = avahi_string_list_add_printf(l, "cookie=0x%08x", c->cookie); + + return l; } -static int publish_service(struct userdata *u, struct service *s) { - char t[256]; - char hn[256]; - int r = -1; - sw_text_record txt; - int free_txt = 0; - assert(u && s); - - if ((s->published == 1 && s->loaded.valid) || - (s->published == 2 && s->autoload.valid && !s->loaded.valid)) - return 0; +static int publish_service(struct userdata *u, struct service *s); - if (s->published) { - sw_discovery_cancel(pa_howl_wrapper_get_discovery(u->howl_wrapper), s->oid); - s->published = 0; - } +static void service_entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) { + struct service *s = userdata; - snprintf(t, sizeof(t), "%s on %s", s->name, pa_get_host_name(hn, sizeof(hn))); + if (state == AVAHI_ENTRY_GROUP_COLLISION) { + char *t; - if (sw_text_record_init(&txt) != SW_OKAY) { - pa_log(__FILE__": sw_text_record_init() failed"); - goto finish; + t = avahi_alternative_service_name(s->service_name); + pa_xfree(s->service_name); + s->service_name = t; + + publish_service(s->userdata, s); } - free_txt = 1; +} + +static int publish_service(struct userdata *u, struct service *s) { + int r = -1; + AvahiStringList *txt = NULL; + + assert(u); + assert(s); - sw_text_record_add_key_and_string_value(txt, "device", s->name); + if (!u->client || avahi_client_get_state(u->client) != AVAHI_CLIENT_S_RUNNING) + return 0; + + if ((s->published == PUBLISHED_REAL && s->loaded.valid) || + (s->published == PUBLISHED_AUTOLOAD && s->autoload.valid && !s->loaded.valid)) + return 0; - txt_record_server_data(u->core, txt); + if (s->published != UNPUBLISHED) { + avahi_entry_group_reset(s->entry_group); + s->published = UNPUBLISHED; + } - if (s->loaded.valid) { - char z[64], *description; - pa_sample_spec ss; + if (s->loaded.valid || s->autoload.valid) { + pa_namereg_type_t type; - get_service_data(u, s, &ss, &description); + if (!s->entry_group) { + if (!(s->entry_group = avahi_entry_group_new(u->client, service_entry_group_callback, s))) { + pa_log("avahi_entry_group_new(): %s", avahi_strerror(avahi_client_errno(u->client))); + goto finish; + } + } + + txt = avahi_string_list_add_pair(txt, "device", s->name); + txt = txt_record_server_data(u->core, txt); + + if (s->loaded.valid) { + char *description; + pa_sample_spec ss; + + get_service_data(u, s, &ss, &description); + + txt = avahi_string_list_add_printf(txt, "rate=%u", ss.rate); + txt = avahi_string_list_add_printf(txt, "channels=%u", ss.channels); + txt = avahi_string_list_add_pair(txt, "format", pa_sample_format_to_string(ss.format)); + txt = avahi_string_list_add_pair(txt, "description", description); - snprintf(z, sizeof(z), "%u", ss.rate); - sw_text_record_add_key_and_string_value(txt, "rate", z); - snprintf(z, sizeof(z), "%u", ss.channels); - sw_text_record_add_key_and_string_value(txt, "channels", z); - sw_text_record_add_key_and_string_value(txt, "format", pa_sample_format_to_string(ss.format)); - - sw_text_record_add_key_and_string_value(txt, "description", description); - - if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t, - s->loaded.type == PA_NAMEREG_SINK ? SERVICE_NAME_SINK : SERVICE_NAME_SOURCE, - NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt), - publish_reply, s, &s->oid) != SW_OKAY) { - pa_log(__FILE__": failed to register sink on zeroconf."); + type = s->loaded.type; + } else if (s->autoload.valid) + type = s->autoload.type; + + if (avahi_entry_group_add_service_strlst( + s->entry_group, + AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, + 0, + s->service_name, + type == PA_NAMEREG_SINK ? SERVICE_TYPE_SINK : SERVICE_TYPE_SOURCE, + NULL, + NULL, + u->port, + txt) < 0) { + + pa_log(__FILE__": avahi_entry_group_add_service_strlst(): %s", avahi_strerror(avahi_client_errno(u->client))); goto finish; } - - s->published = 1; - } else if (s->autoload.valid) { - - if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t, - s->autoload.type == PA_NAMEREG_SINK ? SERVICE_NAME_SINK : SERVICE_NAME_SOURCE, - NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt), - publish_reply, s, &s->oid) != SW_OKAY) { - pa_log(__FILE__": failed to register sink on zeroconf."); + + if (avahi_entry_group_commit(s->entry_group) < 0) { + pa_log(__FILE__": avahi_entry_group_commit(): %s", avahi_strerror(avahi_client_errno(u->client))); goto finish; } - - s->published = 2; + + if (s->loaded.valid) + s->published = PUBLISHED_REAL; + else if (s->autoload.valid) + s->published = PUBLISHED_AUTOLOAD; } - + r = 0; finish: - if (!s->published) { + if (s->published == UNPUBLISHED) { /* Remove this service */ + + if (s->entry_group) { + avahi_entry_group_free(s->entry_group); + } + pa_hashmap_remove(u->services, s->name); pa_xfree(s->name); + pa_xfree(s->service_name); pa_xfree(s); } - if (free_txt) - sw_text_record_fina(txt); + if (txt) + avahi_string_list_free(txt); return r; } static struct service *get_service(struct userdata *u, const char *name) { struct service *s; + char hn[64]; if ((s = pa_hashmap_get(u->services, name))) return s; - s = pa_xmalloc(sizeof(struct service)); - s->published = 0; + s = pa_xnew(struct service, 1); + s->userdata = u; + s->entry_group = NULL; + s->published = UNPUBLISHED; s->name = pa_xstrdup(name); s->loaded.valid = s->autoload.valid = 0; + s->service_name = pa_sprintf_malloc("%s on %s", s->name, pa_get_host_name(hn, sizeof(hn))); pa_hashmap_put(u->services, s->name, s); @@ -227,7 +266,7 @@ static int publish_sink(struct userdata *u, pa_sink *s) { svc = get_service(u, s->name); if (svc->loaded.valid) - return 0; + return publish_service(u, svc); svc->loaded.valid = 1; svc->loaded.type = PA_NAMEREG_SINK; @@ -244,7 +283,7 @@ static int publish_source(struct userdata *u, pa_source *s) { svc = get_service(u, s->name); if (svc->loaded.valid) - return 0; + return publish_service(u, svc); svc->loaded.valid = 1; svc->loaded.type = PA_NAMEREG_SOURCE; @@ -261,7 +300,7 @@ static int publish_autoload(struct userdata *u, pa_autoload_entry *s) { svc = get_service(u, s->name); if (svc->autoload.valid) - return 0; + return publish_service(u, svc); svc->autoload.valid = 1; svc->autoload.type = s->type; @@ -381,16 +420,164 @@ fail: } } -int pa__init(pa_core *c, pa_module*m) { - struct userdata *u; - uint32_t idx, port = PA_NATIVE_DEFAULT_PORT; +static int publish_main_service(struct userdata *u); + +static void main_entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) { + struct userdata *u = userdata; + assert(u); + + if (state == AVAHI_ENTRY_GROUP_COLLISION) { + char *t; + + t = avahi_alternative_service_name(u->service_name); + pa_xfree(u->service_name); + u->service_name = t; + + publish_main_service(u); + } +} + +static int publish_main_service(struct userdata *u) { + AvahiStringList *txt = NULL; + int r = -1; + + if (!u->main_entry_group) { + if (!(u->main_entry_group = avahi_entry_group_new(u->client, main_entry_group_callback, u))) { + pa_log(__FILE__": avahi_entry_group_new() failed: %s", avahi_strerror(avahi_client_errno(u->client))); + goto fail; + } + } else + avahi_entry_group_reset(u->main_entry_group); + + txt = txt_record_server_data(u->core, NULL); + + if (avahi_entry_group_add_service_strlst( + u->main_entry_group, + AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, + 0, + u->service_name, + SERVICE_TYPE_SERVER, + NULL, + NULL, + u->port, + txt) < 0) { + + pa_log(__FILE__": avahi_entry_group_add_service_strlst() failed: %s", avahi_strerror(avahi_client_errno(u->client))); + goto fail; + } + + if (avahi_entry_group_commit(u->main_entry_group) < 0) { + pa_log(__FILE__": avahi_entry_group_commit() failed: %s", avahi_strerror(avahi_client_errno(u->client))); + goto fail; + } + + r = 0; + +fail: + avahi_string_list_free(txt); + + return r; +} + +static int publish_all_services(struct userdata *u) { pa_sink *sink; pa_source *source; pa_autoload_entry *autoload; + int r = -1; + uint32_t idx; + + assert(u); + + pa_log_debug(__FILE__": Publishing services in Zeroconf"); + + for (sink = pa_idxset_first(u->core->sinks, &idx); sink; sink = pa_idxset_next(u->core->sinks, &idx)) + if (publish_sink(u, sink) < 0) + goto fail; + + for (source = pa_idxset_first(u->core->sources, &idx); source; source = pa_idxset_next(u->core->sources, &idx)) + if (publish_source(u, source) < 0) + goto fail; + + if (u->core->autoload_idxset) + for (autoload = pa_idxset_first(u->core->autoload_idxset, &idx); autoload; autoload = pa_idxset_next(u->core->autoload_idxset, &idx)) + if (publish_autoload(u, autoload) < 0) + goto fail; + + if (publish_main_service(u) < 0) + goto fail; + + r = 0; + +fail: + return r; +} + +static void unpublish_all_services(struct userdata *u, int rem) { + void *state = NULL; + struct service *s; + + assert(u); + + pa_log_debug(__FILE__": Unpublishing services in Zeroconf"); + + while ((s = pa_hashmap_iterate(u->services, &state, NULL))) { + if (s->entry_group) { + if (rem) { + avahi_entry_group_free(s->entry_group); + s->entry_group = NULL; + } else + avahi_entry_group_reset(s->entry_group); + } + + s->published = UNPUBLISHED; + } + + if (u->main_entry_group) { + if (rem) { + avahi_entry_group_free(u->main_entry_group); + u->main_entry_group = NULL; + } else + avahi_entry_group_reset(u->main_entry_group); + } +} + +static void client_callback(AvahiClient *c, AvahiClientState state, void *userdata) { + struct userdata *u = userdata; + assert(c); + + u->client = c; + + switch (state) { + case AVAHI_CLIENT_S_RUNNING: + publish_all_services(u); + break; + + case AVAHI_CLIENT_S_COLLISION: + unpublish_all_services(u, 0); + break; + + case AVAHI_CLIENT_FAILURE: + if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) { + int error; + unpublish_all_services(u, 1); + avahi_client_free(u->client); + + if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error))) + pa_log(__FILE__": pa_avahi_client_new() failed: %s", avahi_strerror(error)); + } + + break; + + default: ; + } +} + +int pa__init(pa_core *c, pa_module*m) { + struct userdata *u; + uint32_t port = PA_NATIVE_DEFAULT_PORT; pa_modargs *ma = NULL; - char t[256], hn[256]; - int free_txt = 0; - sw_text_record txt; + char hn[256]; + int error; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": failed to parse module arguments."); @@ -402,55 +589,31 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - m->userdata = u = pa_xmalloc(sizeof(struct userdata)); + m->userdata = u = pa_xnew(struct userdata, 1); u->core = c; u->port = (uint16_t) port; - if (!(u->howl_wrapper = pa_howl_wrapper_get(c))) - goto fail; - + u->avahi_poll = pa_avahi_poll_new(c->mainloop); + u->services = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); u->sink_dynarray = pa_dynarray_new(); u->source_dynarray = pa_dynarray_new(); u->autoload_dynarray = pa_dynarray_new(); - + u->subscription = pa_subscription_new(c, PA_SUBSCRIPTION_MASK_SINK| PA_SUBSCRIPTION_MASK_SOURCE| PA_SUBSCRIPTION_MASK_AUTOLOAD, subscribe_callback, u); - for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) - if (publish_sink(u, sink) < 0) - goto fail; + u->main_entry_group = NULL; - for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) - if (publish_source(u, source) < 0) - goto fail; + u->service_name = pa_xstrdup(pa_get_host_name(hn, sizeof(hn))); - if (c->autoload_idxset) - for (autoload = pa_idxset_first(c->autoload_idxset, &idx); autoload; autoload = pa_idxset_next(c->autoload_idxset, &idx)) - if (publish_autoload(u, autoload) < 0) - goto fail; - - snprintf(t, sizeof(t), "%s", pa_get_host_name(hn, sizeof(hn))); - - if (sw_text_record_init(&txt) != SW_OKAY) { - pa_log(__FILE__": sw_text_record_init() failed"); + if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error))) { + pa_log(__FILE__": pa_avahi_client_new() failed: %s", avahi_strerror(error)); goto fail; } - free_txt = 1; - txt_record_server_data(u->core, txt); - - if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t, - SERVICE_NAME_SERVER, - NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt), - publish_reply, u, &u->server_oid) != SW_OKAY) { - pa_log(__FILE__": failed to register server on zeroconf."); - goto fail; - } - - sw_text_record_fina(txt); pa_modargs_free(ma); return 0; @@ -460,9 +623,6 @@ fail: if (ma) pa_modargs_free(ma); - - if (free_txt) - sw_text_record_fina(txt); return -1; } @@ -470,8 +630,14 @@ fail: static void service_free(void *p, void *userdata) { struct service *s = p; struct userdata *u = userdata; - assert(s && u); - sw_discovery_cancel(pa_howl_wrapper_get_discovery(u->howl_wrapper), s->oid); + + assert(s); + assert(u); + + if (s->entry_group) + avahi_entry_group_free(s->entry_group); + + pa_xfree(s->service_name); pa_xfree(s->name); pa_xfree(s); } @@ -495,11 +661,17 @@ void pa__done(pa_core *c, pa_module*m) { if (u->subscription) pa_subscription_free(u->subscription); - - if (u->howl_wrapper) - pa_howl_wrapper_unref(u->howl_wrapper); + if (u->main_entry_group) + avahi_entry_group_free(u->main_entry_group); + if (u->client) + avahi_client_free(u->client); + + if (u->avahi_poll) + pa_avahi_poll_free(u->avahi_poll); + + pa_xfree(u->service_name); pa_xfree(u); } diff --git a/src/pulsecore/avahi-wrap.c b/src/pulsecore/avahi-wrap.c new file mode 100644 index 00000000..9da76558 --- /dev/null +++ b/src/pulsecore/avahi-wrap.c @@ -0,0 +1,188 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include + +#include + +#include "avahi-wrap.h" + +typedef struct { + AvahiPoll api; + pa_mainloop_api *mainloop; +} pa_avahi_poll; + +struct AvahiWatch { + pa_io_event *io_event; + pa_avahi_poll *avahi_poll; + AvahiWatchEvent current_event; + AvahiWatchCallback callback; + void *userdata; +}; + +static AvahiWatchEvent translate_io_flags_back(pa_io_event_flags_t e) { + return + (e & PA_IO_EVENT_INPUT ? AVAHI_WATCH_IN : 0) | + (e & PA_IO_EVENT_OUTPUT ? AVAHI_WATCH_OUT : 0) | + (e & PA_IO_EVENT_ERROR ? AVAHI_WATCH_ERR : 0) | + (e & PA_IO_EVENT_HANGUP ? AVAHI_WATCH_HUP : 0); +} + +static pa_io_event_flags_t translate_io_flags(AvahiWatchEvent e) { + return + (e & AVAHI_WATCH_IN ? PA_IO_EVENT_INPUT : 0) | + (e & AVAHI_WATCH_OUT ? PA_IO_EVENT_OUTPUT : 0) | + (e & AVAHI_WATCH_ERR ? PA_IO_EVENT_ERROR : 0) | + (e & AVAHI_WATCH_HUP ? PA_IO_EVENT_HANGUP : 0); +} + +static void watch_callback(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) { + AvahiWatch *w = userdata; + + assert(a); + assert(e); + assert(w); + + w->current_event = translate_io_flags_back(events); + w->callback(w, fd, w->current_event, w->userdata); + w->current_event = 0; +} + +static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void *userdata) { + pa_avahi_poll *p; + AvahiWatch *w; + + assert(api); + assert(fd >= 0); + assert(callback); + + p = api->userdata; + assert(p); + + w = pa_xnew(AvahiWatch, 1); + w->avahi_poll = p; + w->current_event = 0; + w->callback = callback; + w->userdata = userdata; + w->io_event = p->mainloop->io_new(p->mainloop, fd, translate_io_flags(event), watch_callback, w); + + return w; +} + +static void watch_update(AvahiWatch *w, AvahiWatchEvent event) { + assert(w); + + w->avahi_poll->mainloop->io_enable(w->io_event, translate_io_flags(event)); +} + +static AvahiWatchEvent watch_get_events(AvahiWatch *w) { + assert(w); + + return w->current_event; +} + +static void watch_free(AvahiWatch *w) { + assert(w); + + w->avahi_poll->mainloop->io_free(w->io_event); + pa_xfree(w); +} + +struct AvahiTimeout { + pa_time_event *time_event; + pa_avahi_poll *avahi_poll; + AvahiTimeoutCallback callback; + void *userdata; +}; + +static void timeout_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata) { + AvahiTimeout *t = userdata; + + assert(a); + assert(e); + assert(t); + + t->callback(t, t->userdata); +} + +static AvahiTimeout* timeout_new(const AvahiPoll *api, const struct timeval *tv, AvahiTimeoutCallback callback, void *userdata) { + pa_avahi_poll *p; + AvahiTimeout *t; + + assert(api); + assert(callback); + + p = api->userdata; + assert(p); + + t = pa_xnew(AvahiTimeout, 1); + t->avahi_poll = p; + t->callback = callback; + t->userdata = userdata; + t->time_event = p->mainloop->time_new(p->mainloop, tv, timeout_callback, t); + + return t; +} + +static void timeout_update(AvahiTimeout *t, const struct timeval *tv) { + assert(t); + + t->avahi_poll->mainloop->time_restart(t->time_event, tv); +} + +static void timeout_free(AvahiTimeout *t) { + assert(t); + + t->avahi_poll->mainloop->time_free(t->time_event); + pa_xfree(t); +} + +AvahiPoll* pa_avahi_poll_new(pa_mainloop_api *m) { + pa_avahi_poll *p; + + assert(m); + + p = pa_xnew(pa_avahi_poll, 1); + + p->api.userdata = p; + p->api.watch_new = watch_new; + p->api.watch_update = watch_update; + p->api.watch_get_events = watch_get_events; + p->api.watch_free = watch_free; + p->api.timeout_new = timeout_new; + p->api.timeout_update = timeout_update; + p->api.timeout_free = timeout_free; + p->mainloop = m; + + return &p->api; +} + +void pa_avahi_poll_free(AvahiPoll *api) { + pa_avahi_poll *p; + assert(api); + p = api->userdata; + assert(p); + + pa_xfree(p); +} + diff --git a/src/pulsecore/avahi-wrap.h b/src/pulsecore/avahi-wrap.h new file mode 100644 index 00000000..97da11eb --- /dev/null +++ b/src/pulsecore/avahi-wrap.h @@ -0,0 +1,33 @@ +#ifndef fooavahiwrapperhfoo +#define fooavahiwrapperhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include + +AvahiPoll* pa_avahi_poll_new(pa_mainloop_api *api); +void pa_avahi_poll_free(AvahiPoll *p); + + +#endif -- cgit From 76f93a07f9d683c3484ff3a71857fe30bedcfd46 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Jul 2006 17:33:44 +0000 Subject: * port libpulse-browse to use the native avahi API instead of the HOWL cruft * add new function pa_browser_set_error_callback() * add doxygen docs to browser.h git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1069 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 22 +-- src/pulse/browser.c | 443 +++++++++++++++++++++++++++------------------ src/pulse/browser.h | 66 +++++-- src/pulsecore/avahi-wrap.h | 1 - 4 files changed, 327 insertions(+), 205 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 8c8168d5..fad01e08 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -140,7 +140,7 @@ if HAVE_X11 bin_PROGRAMS += pax11publish endif -if HAVE_HOWL +if HAVE_AVAHI bin_PROGRAMS += pabrowse endif @@ -319,7 +319,7 @@ pulseinclude_HEADERS = \ pulse/volume.h \ pulse/xmalloc.h -if HAVE_HOWL +if HAVE_AVAHI pulseinclude_HEADERS += \ pulse/browser.h endif @@ -338,7 +338,7 @@ lib_LTLIBRARIES = \ libpulse.la \ libpulse-simple.la -if HAVE_HOWL +if HAVE_AVAHI lib_LTLIBRARIES += \ libpulse-browse.la endif @@ -444,9 +444,9 @@ libpulse_simple_la_CFLAGS = $(AM_CFLAGS) libpulse_simple_la_LIBADD = $(AM_LIBADD) libpulse.la libpulse_simple_la_LDFLAGS = -version-info $(LIBPULSE_SIMPLE_VERSION_INFO) -libpulse_browse_la_SOURCES = pulse/browser.c pulse/browser.h -libpulse_browse_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) -libpulse_browse_la_LIBADD = $(AM_LIBADD) libpulse.la $(HOWL_LIBS) +libpulse_browse_la_SOURCES = pulse/browser.c pulse/browser.h pulsecore/avahi-wrap.c pulsecore/avahi-wrap.h +libpulse_browse_la_CFLAGS = $(AM_CFLAGS) $(AVAHI_CFLAGS) +libpulse_browse_la_LIBADD = $(AM_LIBADD) libpulse.la $(AVAHI_LIBS) libpulse_browse_la_LDFLAGS = -version-info $(LIBPULSE_BROWSE_VERSION_INFO) libpulse_mainloop_glib_la_SOURCES = pulse/glib-mainloop.h pulse/glib-mainloop.c @@ -864,9 +864,8 @@ modlibexec_LTLIBRARIES += \ module-solaris.la endif -if HAVE_HOWL +if HAVE_AVAHI modlibexec_LTLIBRARIES += \ - libhowl-wrap.la \ module-zeroconf-publish.la endif @@ -1111,12 +1110,7 @@ module_solaris_la_SOURCES = modules/module-solaris.c module_solaris_la_LDFLAGS = -module -avoid-version module_solaris_la_LIBADD = $(AM_LIBADD) libiochannel.la -# HOWL - -libhowl_wrap_la_SOURCES = modules/howl-wrap.c modules/howl-wrap.h -libhowl_wrap_la_LDFLAGS = -avoid-version -libhowl_wrap_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) libpulsecore.la -libhowl_wrap_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) +# Avahi module_zeroconf_publish_la_SOURCES = modules/module-zeroconf-publish.c module_zeroconf_publish_la_LDFLAGS = -module -avoid-version diff --git a/src/pulse/browser.c b/src/pulse/browser.c index 60c71090..dae8e3d5 100644 --- a/src/pulse/browser.c +++ b/src/pulse/browser.c @@ -24,85 +24,68 @@ #endif #include -#include +#include + +#include +#include +#include #include #include #include +#include + #include "browser.h" -#define SERVICE_NAME_SINK "_pulse-sink._tcp." -#define SERVICE_NAME_SOURCE "_pulse-source._tcp." -#define SERVICE_NAME_SERVER "_pulse-server._tcp." +#define SERVICE_TYPE_SINK "_pulse-sink._tcp." +#define SERVICE_TYPE_SOURCE "_pulse-source._tcp." +#define SERVICE_TYPE_SERVER "_pulse-server._tcp." struct pa_browser { int ref; pa_mainloop_api *mainloop; + AvahiPoll* avahi_poll; pa_browse_cb_t callback; void *userdata; - - sw_discovery discovery; - pa_io_event *io_event; -}; - -static void io_callback(pa_mainloop_api*a, PA_GCC_UNUSED pa_io_event*e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void *userdata) { - pa_browser *b = userdata; - assert(a && b && b->mainloop == a); - if (events != PA_IO_EVENT_INPUT || sw_discovery_read_socket(b->discovery) != SW_OKAY) { - pa_log(__FILE__": connection to HOWL daemon failed."); - b->mainloop->io_free(b->io_event); - b->io_event = NULL; - return; - } -} - -static int type_equal(const char *a, const char *b) { - size_t la, lb; + pa_browser_error_cb_t error_callback; + void *error_userdata; - if (strcasecmp(a, b) == 0) - return 1; - - la = strlen(a); - lb = strlen(b); - - if (la > 0 && a[la-1] == '.' && la == lb+1 && strncasecmp(a, b, la-1) == 0) - return 1; - - if (lb > 0 && b[lb-1] == '.' && lb == la+1 && strncasecmp(a, b, lb-1) == 0) - return 1; - - return 0; -} + AvahiClient *client; + AvahiServiceBrowser *server_browser, *sink_browser, *source_browser; + +}; static int map_to_opcode(const char *type, int new) { - if (type_equal(type, SERVICE_NAME_SINK)) + if (avahi_domain_equal(type, SERVICE_TYPE_SINK)) return new ? PA_BROWSE_NEW_SINK : PA_BROWSE_REMOVE_SINK; - else if (type_equal(type, SERVICE_NAME_SOURCE)) + else if (avahi_domain_equal(type, SERVICE_TYPE_SOURCE)) return new ? PA_BROWSE_NEW_SOURCE : PA_BROWSE_REMOVE_SOURCE; - else if (type_equal(type, SERVICE_NAME_SERVER)) + else if (avahi_domain_equal(type, SERVICE_TYPE_SERVER)) return new ? PA_BROWSE_NEW_SERVER : PA_BROWSE_REMOVE_SERVER; return -1; } -static sw_result resolve_reply( - sw_discovery discovery, - sw_discovery_oid oid, - sw_uint32 interface_index, - sw_const_string name, - sw_const_string type, - sw_const_string domain, - sw_ipv4_address address, - sw_port port, - sw_octets text_record, - sw_ulong text_record_len, - sw_opaque extra) { +static void resolve_callback( + AvahiServiceResolver *r, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiResolverEvent event, + const char *name, + const char *type, + const char *domain, + const char *host_name, + const AvahiAddress *aa, + uint16_t port, + AvahiStringList *txt, + AvahiLookupResultFlags flags, + void *userdata) { - pa_browser *b = extra; + pa_browser *b = userdata; pa_browse_info i; char ip[256], a[256]; int opcode; @@ -110,100 +93,96 @@ static sw_result resolve_reply( uint32_t cookie; pa_sample_spec ss; int ss_valid = 0; - sw_text_record_iterator iterator; - int free_iterator = 0; - char *c = NULL; + char *key = NULL, *value = NULL; assert(b); - sw_discovery_cancel(discovery, oid); - memset(&i, 0, sizeof(i)); i.name = name; - + + if (event != AVAHI_RESOLVER_FOUND) + goto fail; + if (!b->callback) goto fail; opcode = map_to_opcode(type, 1); assert(opcode >= 0); - - snprintf(a, sizeof(a), "tcp:%s:%u", sw_ipv4_address_name(address, ip, sizeof(ip)), port); + + if (aa->proto == AVAHI_PROTO_INET) + snprintf(a, sizeof(a), "tcp:%s:%u", avahi_address_snprint(ip, sizeof(ip), aa), port); + else { + assert(aa->proto == AVAHI_PROTO_INET6); + snprintf(a, sizeof(a), "tcp6:%s:%u", avahi_address_snprint(ip, sizeof(ip), aa), port); + } i.server = a; - - if (text_record && text_record_len) { - char key[SW_TEXT_RECORD_MAX_LEN]; - uint8_t val[SW_TEXT_RECORD_MAX_LEN]; - uint32_t val_len; - - if (sw_text_record_iterator_init(&iterator, text_record, text_record_len) != SW_OKAY) { - pa_log_error(__FILE__": sw_text_record_string_iterator_init() failed."); - goto fail; - } - free_iterator = 1; + + while (txt) { - while (sw_text_record_iterator_next(iterator, key, val, &val_len) == SW_OKAY) { - c = pa_xstrndup((char*) val, val_len); + if (avahi_string_list_get_pair(txt, &key, &value, NULL) < 0) + break; + + if (!strcmp(key, "device")) { + device_found = 1; + pa_xfree((char*) i.device); + i.device = value; + value = NULL; + } else if (!strcmp(key, "server-version")) { + pa_xfree((char*) i.server_version); + i.server_version = value; + value = NULL; + } else if (!strcmp(key, "user-name")) { + pa_xfree((char*) i.user_name); + i.user_name = value; + value = NULL; + } else if (!strcmp(key, "fqdn")) { + size_t l; - if (!strcmp(key, "device")) { - device_found = 1; - pa_xfree((char*) i.device); - i.device = c; - c = NULL; - } else if (!strcmp(key, "server-version")) { - pa_xfree((char*) i.server_version); - i.server_version = c; - c = NULL; - } else if (!strcmp(key, "user-name")) { - pa_xfree((char*) i.user_name); - i.user_name = c; - c = NULL; - } else if (!strcmp(key, "fqdn")) { - size_t l; + pa_xfree((char*) i.fqdn); + i.fqdn = value; + value = NULL; - pa_xfree((char*) i.fqdn); - i.fqdn = c; - c = NULL; - - l = strlen(a); - assert(l+1 <= sizeof(a)); - strncat(a, " ", sizeof(a)-l-1); - strncat(a, i.fqdn, sizeof(a)-l-2); - } else if (!strcmp(key, "cookie")) { - - if (pa_atou(c, &cookie) < 0) - goto fail; - - i.cookie = &cookie; - } else if (!strcmp(key, "description")) { - pa_xfree((char*) i.description); - i.description = c; - c = NULL; - } else if (!strcmp(key, "channels")) { - uint32_t ch; - - if (pa_atou(c, &ch) < 0 || ch <= 0 || ch > 255) - goto fail; - - ss.channels = (uint8_t) ch; - ss_valid |= 1; - - } else if (!strcmp(key, "rate")) { - if (pa_atou(c, &ss.rate) < 0) - goto fail; - ss_valid |= 2; - } else if (!strcmp(key, "format")) { + l = strlen(a); + assert(l+1 <= sizeof(a)); + strncat(a, " ", sizeof(a)-l-1); + strncat(a, i.fqdn, sizeof(a)-l-2); + } else if (!strcmp(key, "cookie")) { + + if (pa_atou(value, &cookie) < 0) + goto fail; + + i.cookie = &cookie; + } else if (!strcmp(key, "description")) { + pa_xfree((char*) i.description); + i.description = value; + value = NULL; + } else if (!strcmp(key, "channels")) { + uint32_t ch; + + if (pa_atou(value, &ch) < 0 || ch <= 0 || ch > 255) + goto fail; + + ss.channels = (uint8_t) ch; + ss_valid |= 1; + + } else if (!strcmp(key, "rate")) { + if (pa_atou(value, &ss.rate) < 0) + goto fail; + ss_valid |= 2; + } else if (!strcmp(key, "format")) { + + if ((ss.format = pa_parse_sample_format(value)) == PA_SAMPLE_INVALID) + goto fail; + + ss_valid |= 4; + } - if ((ss.format = pa_parse_sample_format(c)) == PA_SAMPLE_INVALID) - goto fail; - - ss_valid |= 4; - } + pa_xfree(key); + pa_xfree(value); + key = value = NULL; - pa_xfree(c); - c = NULL; - } - + txt = avahi_string_list_get_next(txt); } /* No device txt record was sent for a sink or source service */ @@ -212,7 +191,6 @@ static sw_result resolve_reply( if (ss_valid == 7) i.sample_spec = &ss; - b->callback(b, opcode, &i, b->userdata); @@ -222,39 +200,72 @@ fail: pa_xfree((void*) i.server_version); pa_xfree((void*) i.user_name); pa_xfree((void*) i.description); - pa_xfree(c); - - if (free_iterator) - sw_text_record_iterator_fina(iterator); + pa_xfree(key); + pa_xfree(value); - return SW_OKAY; + avahi_service_resolver_free(r); } -static sw_result browse_reply( - sw_discovery discovery, - sw_discovery_oid id, - sw_discovery_browse_status status, - sw_uint32 interface_index, - sw_const_string name, - sw_const_string type, - sw_const_string domain, - sw_opaque extra) { - - pa_browser *b = extra; +static void handle_failure(pa_browser *b) { + const char *e = NULL; assert(b); - switch (status) { - case SW_DISCOVERY_BROWSE_ADD_SERVICE: { - sw_discovery_oid oid; + if (b->sink_browser) + avahi_service_browser_free(b->sink_browser); + if (b->source_browser) + avahi_service_browser_free(b->source_browser); + if (b->server_browser) + avahi_service_browser_free(b->server_browser); - if (sw_discovery_resolve(b->discovery, 0, name, type, domain, resolve_reply, b, &oid) != SW_OKAY) - pa_log_error(__FILE__": sw_discovery_resolve() failed"); + b->sink_browser = b->source_browser = b->server_browser = NULL; + + if (b->client) { + e = avahi_strerror(avahi_client_errno(b->client)); + avahi_client_free(b->client); + } + + b->client = NULL; + + if (b->error_callback) + b->error_callback(b, e, b->error_userdata); +} + +static void browse_callback( + AvahiServiceBrowser *sb, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiBrowserEvent event, + const char *name, + const char *type, + const char *domain, + AvahiLookupResultFlags flags, + void *userdata) { + + pa_browser *b = userdata; + assert(b); + + switch (event) { + case AVAHI_BROWSER_NEW: { + + if (!avahi_service_resolver_new( + b->client, + interface, + protocol, + name, + type, + domain, + AVAHI_PROTO_UNSPEC, + 0, + resolve_callback, + b)) + handle_failure(b); break; } - case SW_DISCOVERY_BROWSE_REMOVE_SERVICE: + case AVAHI_BROWSER_REMOVE: { + if (b->callback) { pa_browse_info i; int opcode; @@ -268,63 +279,144 @@ static sw_result browse_reply( b->callback(b, opcode, &i, b->userdata); } break; + } + case AVAHI_BROWSER_FAILURE: { + handle_failure(b); + break; + } + default: ; } +} + +static void client_callback(AvahiClient *s, AvahiClientState state, void *userdata) { + pa_browser *b = userdata; + assert(s); - return SW_OKAY; + if (state == AVAHI_CLIENT_FAILURE) + handle_failure(b); } +static void browser_free(pa_browser *b); + pa_browser *pa_browser_new(pa_mainloop_api *mainloop) { + return pa_browser_new_full(mainloop, PA_BROWSE_FOR_SERVERS|PA_BROWSE_FOR_SINKS|PA_BROWSE_FOR_SOURCES, NULL); +} + +pa_browser *pa_browser_new_full(pa_mainloop_api *mainloop, pa_browse_flags_t flags, const char **error_string) { pa_browser *b; - sw_discovery_oid oid; + int error; + assert(mainloop); + + if (flags & ~(PA_BROWSE_FOR_SERVERS|PA_BROWSE_FOR_SINKS|PA_BROWSE_FOR_SOURCES) || flags == 0) + return NULL; + b = pa_xnew(pa_browser, 1); b->mainloop = mainloop; b->ref = 1; b->callback = NULL; b->userdata = NULL; + b->error_callback = NULL; + b->error_userdata = NULL; + b->sink_browser = b->source_browser = b->server_browser = NULL; - if (sw_discovery_init(&b->discovery) != SW_OKAY) { - pa_log_error(__FILE__": sw_discovery_init() failed."); - pa_xfree(b); - return NULL; + b->avahi_poll = pa_avahi_poll_new(mainloop); + + if (!(b->client = avahi_client_new(b->avahi_poll, 0, client_callback, b, &error))) { + if (error_string) + *error_string = avahi_strerror(error); + goto fail; + } + + if ((flags & PA_BROWSE_FOR_SERVERS) && + !(b->server_browser = avahi_service_browser_new( + b->client, + AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + SERVICE_TYPE_SERVER, + NULL, + 0, + browse_callback, + b))) { + + if (error_string) + *error_string = avahi_strerror(avahi_client_errno(b->client)); + goto fail; } - if (sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SERVER, NULL, browse_reply, b, &oid) != SW_OKAY || - sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SINK, NULL, browse_reply, b, &oid) != SW_OKAY || - sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SOURCE, NULL, browse_reply, b, &oid) != SW_OKAY) { + if ((flags & PA_BROWSE_FOR_SINKS) && + !(b->sink_browser = avahi_service_browser_new( + b->client, + AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + SERVICE_TYPE_SINK, + NULL, + 0, + browse_callback, + b))) { + + if (error_string) + *error_string = avahi_strerror(avahi_client_errno(b->client)); + goto fail; + } - pa_log_error(__FILE__": sw_discovery_browse() failed."); - - sw_discovery_fina(b->discovery); - pa_xfree(b); - return NULL; + if ((flags & PA_BROWSE_FOR_SOURCES) && + !(b->source_browser = avahi_service_browser_new( + b->client, + AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + SERVICE_TYPE_SOURCE, + NULL, + 0, + browse_callback, + b))) { + + if (error_string) + *error_string = avahi_strerror(avahi_client_errno(b->client)); + goto fail; } - b->io_event = mainloop->io_new(mainloop, sw_discovery_socket(b->discovery), PA_IO_EVENT_INPUT, io_callback, b); return b; + +fail: + if (b) + browser_free(b); + + return NULL; } static void browser_free(pa_browser *b) { assert(b && b->mainloop); - if (b->io_event) - b->mainloop->io_free(b->io_event); + if (b->sink_browser) + avahi_service_browser_free(b->sink_browser); + if (b->source_browser) + avahi_service_browser_free(b->source_browser); + if (b->server_browser) + avahi_service_browser_free(b->server_browser); + + if (b->client) + avahi_client_free(b->client); + + if (b->avahi_poll) + pa_avahi_poll_free(b->avahi_poll); - sw_discovery_fina(b->discovery); pa_xfree(b); } pa_browser *pa_browser_ref(pa_browser *b) { - assert(b && b->ref >= 1); + assert(b); + assert(b->ref >= 1); b->ref++; return b; } void pa_browser_unref(pa_browser *b) { - assert(b && b->ref >= 1); + assert(b); + assert(b->ref >= 1); if ((-- (b->ref)) <= 0) browser_free(b); @@ -336,3 +428,10 @@ void pa_browser_set_callback(pa_browser *b, pa_browse_cb_t cb, void *userdata) { b->callback = cb; b->userdata = userdata; } + +void pa_browser_set_error_callback(pa_browser *b, pa_browser_error_cb_t cb, void *userdata) { + assert(b); + + b->error_callback = cb; + b->error_userdata = userdata; +} diff --git a/src/pulse/browser.h b/src/pulse/browser.h index 2d20c6c0..fc57a4d5 100644 --- a/src/pulse/browser.h +++ b/src/pulse/browser.h @@ -27,42 +27,72 @@ #include #include +/** \file + * An abstract interface for Zeroconf browsing of PulseAudio servers */ + PA_C_DECL_BEGIN +/** An opaque Zeroconf service browser object */ typedef struct pa_browser pa_browser; +/** Opcodes for pa_browser_cb_t callbacks */ typedef enum pa_browse_opcode { - PA_BROWSE_NEW_SERVER = 0, - PA_BROWSE_NEW_SINK, - PA_BROWSE_NEW_SOURCE, - PA_BROWSE_REMOVE_SERVER, - PA_BROWSE_REMOVE_SINK, - PA_BROWSE_REMOVE_SOURCE + PA_BROWSE_NEW_SERVER = 0, /**< New server found */ + PA_BROWSE_NEW_SINK, /**< New sink found */ + PA_BROWSE_NEW_SOURCE, /**< New source found */ + PA_BROWSE_REMOVE_SERVER, /**< Server disappeared */ + PA_BROWSE_REMOVE_SINK, /**< Sink disappeared */ + PA_BROWSE_REMOVE_SOURCE /**< Source disappeared */ } pa_browse_opcode_t; +typedef enum pa_browse_flags { + PA_BROWSE_FOR_SERVERS = 1, /**< Browse for servers */ + PA_BROWSE_FOR_SINKS = 2, /**< Browse for sinks */ + PA_BROWSE_FOR_SOURCES = 4 /** Browse for sources */ +} pa_browse_flags_t; + +/** Create a new browser object on the specified main loop */ pa_browser *pa_browser_new(pa_mainloop_api *mainloop); + +/** Same pa_browser_new, but pass additional flags parameter. */ +pa_browser *pa_browser_new_full(pa_mainloop_api *mainloop, pa_browse_flags_t flags, const char **error_string); + +/** Increase reference counter of the specified browser object */ pa_browser *pa_browser_ref(pa_browser *z); + +/** Decrease reference counter of the specified browser object */ void pa_browser_unref(pa_browser *z); +/** Information about a sink/source/server found with Zeroconf */ typedef struct pa_browse_info { - /* Unique service name */ - const char *name; /* always available */ - - /* Server info */ - const char *server; /* always available */ - const char *server_version, *user_name, *fqdn; /* optional */ - const uint32_t *cookie; /* optional */ - - /* Device info */ - const char *device; /* always available when this information is of a sink/source */ - const char *description; /* optional */ - const pa_sample_spec *sample_spec; /* optional */ + const char *name; /**< Unique service name; always available */ + + const char *server; /**< Server name; always available */ + const char *server_version; /**< Server version string; optional */ + const char *user_name; /**< User name of the server process; optional */ + const char *fqdn; /* Server version; optional */ + const uint32_t *cookie; /* Server cookie; optional */ + + const char *device; /* Device name; always available when this information is of a sink/source */ + const char *description; /* Device description; optional */ + const pa_sample_spec *sample_spec; /* Sample specification of the device; optional */ } pa_browse_info; +/** Callback prototype */ typedef void (*pa_browse_cb_t)(pa_browser *z, pa_browse_opcode_t c, const pa_browse_info *i, void *userdata); +/** Set the callback pointer for the browser object */ void pa_browser_set_callback(pa_browser *z, pa_browse_cb_t cb, void *userdata); +/** Callback prototype for errors */ +typedef void (*pa_browser_error_cb_t)(pa_browser *z, const char *error_string, void *userdata); + +/** Set a callback function that is called whenever the browser object + * becomes invalid due to an error. After this function has been + * called the browser object has become invalid and should be + * freed. */ +void pa_browser_set_error_callback(pa_browser *z, pa_browser_error_cb_t, void *userdata); + PA_C_DECL_END #endif diff --git a/src/pulsecore/avahi-wrap.h b/src/pulsecore/avahi-wrap.h index 97da11eb..d868fed4 100644 --- a/src/pulsecore/avahi-wrap.h +++ b/src/pulsecore/avahi-wrap.h @@ -29,5 +29,4 @@ AvahiPoll* pa_avahi_poll_new(pa_mainloop_api *api); void pa_avahi_poll_free(AvahiPoll *p); - #endif -- cgit From d989c692ac2178f0724bd34d5ac0bc2c12176efb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Jul 2006 17:34:08 +0000 Subject: add browser.h to doxygen docs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1070 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doxygen/doxygen.conf.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doxygen/doxygen.conf.in b/doxygen/doxygen.conf.in index 8ccf667a..81923a9f 100644 --- a/doxygen/doxygen.conf.in +++ b/doxygen/doxygen.conf.in @@ -417,7 +417,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = ../src/pulse/context.h ../src/pulse/stream.h ../src/pulse/pulseaudio.h ../src/pulse/sample.h ../src/pulse/def.h ../src/pulse/subscribe.h ../src/pulse/introspect.h ../src/pulse/scache.h ../src/pulse/mainloop-api.h ../src/pulse/glib-mainloop.h ../src/pulse/mainloop.h ../src/pulse/mainloop-signal.h ../src/pulse/error.h ../src/pulse/operation.h ../src/pulse/simple.h ../src/pulse/version.h ../src/pulse/volume.h ../src/pulse/channelmap.h ../src/pulse/thread-mainloop.h ../src/pulse/xmalloc.h ../src/pulse/utf8.h ../src/pulse/util.h ../src/pulse/timeval.h +INPUT = ../src/pulse/context.h ../src/pulse/stream.h ../src/pulse/pulseaudio.h ../src/pulse/sample.h ../src/pulse/def.h ../src/pulse/subscribe.h ../src/pulse/introspect.h ../src/pulse/scache.h ../src/pulse/mainloop-api.h ../src/pulse/glib-mainloop.h ../src/pulse/mainloop.h ../src/pulse/mainloop-signal.h ../src/pulse/error.h ../src/pulse/operation.h ../src/pulse/simple.h ../src/pulse/version.h ../src/pulse/volume.h ../src/pulse/channelmap.h ../src/pulse/thread-mainloop.h ../src/pulse/xmalloc.h ../src/pulse/utf8.h ../src/pulse/util.h ../src/pulse/timeval.h ../src/pulse/browser.h # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -- cgit From 1fd18d6b5fce487faea673d093019395ec783fbc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Jul 2006 17:35:10 +0000 Subject: * add proper error handling to pabrowse.c * properly destroy pa_browser object on exit git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1071 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pabrowse.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/utils/pabrowse.c b/src/utils/pabrowse.c index 954e4e6c..450182f5 100644 --- a/src/utils/pabrowse.c +++ b/src/utils/pabrowse.c @@ -107,10 +107,18 @@ static void browser_callback(pa_browser *b, pa_browse_opcode_t c, const pa_brows } } +static void error_callback(pa_browser *b, const char *s, void *userdata) { + pa_mainloop_api*m = userdata; + + fprintf(stderr, "Failure: %s\n", s); + m->quit(m, 1); +} + int main(int argc, char *argv[]) { pa_mainloop *mainloop = NULL; pa_browser *browser = NULL; int ret = 1, r; + const char *s; if (!(mainloop = pa_mainloop_new())) goto finish; @@ -121,15 +129,22 @@ int main(int argc, char *argv[]) { pa_signal_new(SIGTERM, exit_signal_callback, NULL); signal(SIGPIPE, SIG_IGN); - if (!(browser = pa_browser_new(pa_mainloop_get_api(mainloop)))) + if (!(browser = pa_browser_new_full(pa_mainloop_get_api(mainloop), PA_BROWSE_FOR_SERVERS|PA_BROWSE_FOR_SINKS|PA_BROWSE_FOR_SOURCES, &s))) { + fprintf(stderr, "pa_browse_new_full(): %s\n", s); goto finish; + } pa_browser_set_callback(browser, browser_callback, NULL); + pa_browser_set_error_callback(browser, error_callback, pa_mainloop_get_api(mainloop)); ret = 0; pa_mainloop_run(mainloop, &ret); finish: + + if (browser) + pa_browser_unref(browser); + if (mainloop) { pa_signal_done(); pa_mainloop_free(mainloop); -- cgit From 6f24a9d32c8132fdd842035f473750bbd313305d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Jul 2006 17:44:18 +0000 Subject: remove HOWL snippet from configure script git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1072 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- configure.ac | 35 ----------------------------------- 2 files changed, 1 insertion(+), 36 deletions(-) diff --git a/Makefile.am b/Makefile.am index 566cec68..8aa609f6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -26,7 +26,7 @@ noinst_DATA = pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libpulse.pc libpulse-simple.pc -if HAVE_HOWL +if HAVE_AVAHI pkgconfig_DATA += \ libpulse-browse.pc endif diff --git a/configure.ac b/configure.ac index eb6fa2d3..83cb2e1a 100644 --- a/configure.ac +++ b/configure.ac @@ -475,41 +475,6 @@ AC_SUBST(GLIB12_LIBS) AC_SUBST(HAVE_GLIB12) AM_CONDITIONAL([HAVE_GLIB12], [test "x$HAVE_GLIB12" = x1]) -#### Howl support (optional) #### - -AC_ARG_ENABLE([howl], - AC_HELP_STRING([--disable-howl], [Disable optional Howl support]), - [ - case "${enableval}" in - yes) howl=yes ;; - no) howl=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --disable-howl) ;; - esac - ], - [howl=auto]) - -if test "x${howl}" != xno ; then - PKG_CHECK_MODULES(HOWL, [ howl >= 0.9.8 ], - HAVE_HOWL=1, - [ - PKG_CHECK_MODULES(HOWL, [ avahi-compat-howl >= 0.9.8 ], - HAVE_HOWL=1, - [ - HAVE_HOWL=0 - if test "x$howl" = xyes ; then - AC_MSG_ERROR([*** Howl support not found]) - fi - ]) - ]) -else - HAVE_HOWL=0 -fi - -AC_SUBST(HOWL_CFLAGS) -AC_SUBST(HOWL_LIBS) -AC_SUBST(HAVE_HOWL) -AM_CONDITIONAL([HAVE_HOWL], [test "x$HAVE_HOWL" = x1]) - #### Avahi support (optional) #### AC_ARG_ENABLE([avahi], -- cgit From 3f0f4f57d29e868c03f2e164c44faa715f2572d7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Jul 2006 17:44:54 +0000 Subject: remove howl-wrap.[ch] git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1073 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/howl-wrap.c | 117 ------------------------------------------------ src/modules/howl-wrap.h | 37 --------------- 2 files changed, 154 deletions(-) delete mode 100644 src/modules/howl-wrap.c delete mode 100644 src/modules/howl-wrap.h diff --git a/src/modules/howl-wrap.c b/src/modules/howl-wrap.c deleted file mode 100644 index e56fca3e..00000000 --- a/src/modules/howl-wrap.c +++ /dev/null @@ -1,117 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of PulseAudio. - - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with PulseAudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include - -#include -#include - -#include "howl-wrap.h" - -#define HOWL_PROPERTY "howl" - -struct pa_howl_wrapper { - pa_core *core; - int ref; - - pa_io_event *io_event; - sw_discovery discovery; -}; - -static void howl_io_event(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { - pa_howl_wrapper *w = userdata; - assert(m && e && fd >= 0 && w && w->ref >= 1); - - if (f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) - goto fail; - - if (sw_discovery_read_socket(w->discovery) != SW_OKAY) - goto fail; - - return; - -fail: - pa_log_error(__FILE__": howl connection died."); - w->core->mainloop->io_free(w->io_event); - w->io_event = NULL; -} - -static pa_howl_wrapper* howl_wrapper_new(pa_core *c) { - pa_howl_wrapper *h; - sw_discovery session; - assert(c); - - if (sw_discovery_init(&session) != SW_OKAY) { - pa_log_error(__FILE__": sw_discovery_init() failed."); - return NULL; - } - - h = pa_xmalloc(sizeof(pa_howl_wrapper)); - h->core = c; - h->ref = 1; - h->discovery = session; - - h->io_event = c->mainloop->io_new(c->mainloop, sw_discovery_socket(session), PA_IO_EVENT_INPUT, howl_io_event, h); - - return h; -} - -static void howl_wrapper_free(pa_howl_wrapper *h) { - assert(h); - - sw_discovery_fina(h->discovery); - - if (h->io_event) - h->core->mainloop->io_free(h->io_event); - - pa_xfree(h); -} - -pa_howl_wrapper* pa_howl_wrapper_get(pa_core *c) { - pa_howl_wrapper *h; - assert(c); - - if ((h = pa_property_get(c, HOWL_PROPERTY))) - return pa_howl_wrapper_ref(h); - - return howl_wrapper_new(c); -} - -pa_howl_wrapper* pa_howl_wrapper_ref(pa_howl_wrapper *h) { - assert(h && h->ref >= 1); - h->ref++; - return h; -} - -void pa_howl_wrapper_unref(pa_howl_wrapper *h) { - assert(h && h->ref >= 1); - if (!(--h->ref)) - howl_wrapper_free(h); -} - -sw_discovery pa_howl_wrapper_get_discovery(pa_howl_wrapper *h) { - assert(h && h->ref >= 1); - - return h->discovery; -} - diff --git a/src/modules/howl-wrap.h b/src/modules/howl-wrap.h deleted file mode 100644 index 506c0b68..00000000 --- a/src/modules/howl-wrap.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef foohowlwrapperhfoo -#define foohowlwrapperhfoo - -/* $Id$ */ - -/*** - This file is part of PulseAudio. - - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with PulseAudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include - -#include - -typedef struct pa_howl_wrapper pa_howl_wrapper; - -pa_howl_wrapper* pa_howl_wrapper_get(pa_core *c); -pa_howl_wrapper* pa_howl_wrapper_ref(pa_howl_wrapper *h); -void pa_howl_wrapper_unref(pa_howl_wrapper *h); - -sw_discovery pa_howl_wrapper_get_discovery(pa_howl_wrapper *h); - -#endif -- cgit From ceb1b6f3d18f1485849f96009aadf53520faede2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Jul 2006 18:23:57 +0000 Subject: remove avahi/howl item from todo list git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1074 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 - 1 file changed, 1 deletion(-) diff --git a/todo b/todo index 978331f4..e2333557 100644 --- a/todo +++ b/todo @@ -6,7 +6,6 @@ Post 0.9.0: - polish for starting polypaudio as root/system-wide instance - chroot() - module-tunnel: improve latency calculation -- port from howl to avahi - multiline configuration statements - use scatter/gather io for sockets - rtp module ported to Win32 (sendmsg/recvmsg emulation) -- cgit From 7484b62e1e00e551cd4b1a19507b98da698d4f7e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Jul 2006 23:10:48 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1075 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 2 ++ 1 file changed, 2 insertions(+) diff --git a/todo b/todo index e2333557..cae27b2a 100644 --- a/todo +++ b/todo @@ -34,6 +34,8 @@ Post 0.9.0: - check if using prctl(PR_GET_NAME) makes sense in pa_get_binary_name() - gconf module + frontend - hooks for creating sink inputs +- insert the low-level device name in the default sink/source name, to make them recognizable:q! + Long term: - pass meta info for hearing impaired -- cgit From 55296041473306ca4aa346197b60545814dfebe8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Jul 2006 23:12:50 +0000 Subject: support time events with NULL timevals which are OK in avahi, but not in PA. This makes padevchooser actually work on top of the new avahi browsing stuff git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1076 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/avahi-wrap.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/pulsecore/avahi-wrap.c b/src/pulsecore/avahi-wrap.c index 9da76558..80256a12 100644 --- a/src/pulsecore/avahi-wrap.c +++ b/src/pulsecore/avahi-wrap.c @@ -139,7 +139,8 @@ static AvahiTimeout* timeout_new(const AvahiPoll *api, const struct timeval *tv, t->avahi_poll = p; t->callback = callback; t->userdata = userdata; - t->time_event = p->mainloop->time_new(p->mainloop, tv, timeout_callback, t); + + t->time_event = tv ? p->mainloop->time_new(p->mainloop, tv, timeout_callback, t) : NULL; return t; } @@ -147,13 +148,21 @@ static AvahiTimeout* timeout_new(const AvahiPoll *api, const struct timeval *tv, static void timeout_update(AvahiTimeout *t, const struct timeval *tv) { assert(t); - t->avahi_poll->mainloop->time_restart(t->time_event, tv); + if (t->time_event && tv) + t->avahi_poll->mainloop->time_restart(t->time_event, tv); + else if (!t->time_event && tv) + t->time_event = t->avahi_poll->mainloop->time_new(t->avahi_poll->mainloop, tv, timeout_callback, t); + else if (t->time_event && !tv) { + t->avahi_poll->mainloop->time_free(t->time_event); + t->time_event = NULL; + } } static void timeout_free(AvahiTimeout *t) { assert(t); - t->avahi_poll->mainloop->time_free(t->time_event); + if (t->time_event) + t->avahi_poll->mainloop->time_free(t->time_event); pa_xfree(t); } -- cgit From 881d4ddd397a829930b6800f1ecc438439cdc766 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Jul 2006 00:17:31 +0000 Subject: * fall back to prctl(PR_GET_NAME) in pa_get_binary_name() if readlink() fails * call pa_path_get_filename() in all cases before returning in pa_get_binary_name(). We already did so on Win32, but didn't on Linux. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1077 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 ++ src/pulse/util.c | 63 ++++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/configure.ac b/configure.ac index 83cb2e1a..a36ee5a0 100644 --- a/configure.ac +++ b/configure.ac @@ -160,6 +160,8 @@ AC_CHECK_HEADERS([linux/input.h], [HAVE_EVDEV=1], [HAVE_EVDEV=0]) AM_CONDITIONAL([HAVE_EVDEV], [test "x$HAVE_EVDEV" = "x1"]) +AC_CHECK_HEADERS([sys/prctl.h]) + # Solaris AC_CHECK_HEADERS([sys/filio.h]) diff --git a/src/pulse/util.c b/src/pulse/util.c index 338607c4..b041fec8 100644 --- a/src/pulse/util.c +++ b/src/pulse/util.c @@ -49,6 +49,10 @@ #include #endif +#ifdef HAVE_SYS_PRCTL_H +#include +#endif + #include "../pulsecore/winsock.h" #include @@ -152,28 +156,51 @@ char *pa_get_home_dir(char *s, size_t l) { char *pa_get_binary_name(char *s, size_t l) { -#ifdef HAVE_READLINK - char path[PATH_MAX]; - int i; - assert(s && l); + assert(s); + assert(l); - /* This works on Linux only */ +#if defined(OS_IS_WIN32) + { + char path[PATH_MAX]; + + if (GetModuleFileName(NULL, path, PATH_MAX)) + return pa_strlcpy(s, pa_path_get_filename(path), l); + } +#endif - snprintf(path, sizeof(path), "/proc/%u/exe", (unsigned) getpid()); - if ((i = readlink(path, s, l-1)) < 0) - return NULL; +#ifdef HAVE_READLINK + { + int i; + char path[PATH_MAX]; + /* This works on Linux only */ + + if ((i = readlink("/proc/self/exe", path, sizeof(path)-1)) >= 0) { + path[i] = 0; + return pa_strlcpy(s, pa_path_get_filename(path), l); + } + } + +#endif + +#if defined(HAVE_SYS_PRCTL_H) && defined(PR_GET_NAME) + { - s[i] = 0; - return s; -#elif defined(OS_IS_WIN32) - char path[PATH_MAX]; - if (!GetModuleFileName(NULL, path, PATH_MAX)) - return NULL; - pa_strlcpy(s, pa_path_get_filename(path), l); - return s; -#else - return NULL; + #ifndef TASK_COMM_LEN + /* Actually defined in linux/sched.h */ + #define TASK_COMM_LEN 16 + #endif + + char tcomm[TASK_COMM_LEN+1]; + memset(tcomm, 0, sizeof(tcomm)); + + /* This works on Linux only */ + if (prctl(PR_GET_NAME, (unsigned long) tcomm, 0, 0, 0) == 0) + return pa_strlcpy(s, tcomm, l); + + } #endif + + return NULL; } const char *pa_path_get_filename(const char *p) { -- cgit From a87c43d61e950b60b44e7e786116dd1e2fad4dc6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Jul 2006 00:18:21 +0000 Subject: Don't call pa_path_get_filename() anymore since it is implicitly called by pa_get_binary_name() anyway git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1078 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index f493f7e5..b1636754 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -408,7 +408,7 @@ static const char *client_name(char *buf, size_t n) { return e; if (pa_get_binary_name(p, sizeof(p))) - snprintf(buf, n, "OSS Emulation[%s]", pa_path_get_filename(p)); + snprintf(buf, n, "OSS Emulation[%s]", p); else snprintf(buf, n, "OSS"); -- cgit From 883ce83f92c408c77bf1a50952893ee5af3f0acc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Jul 2006 00:19:09 +0000 Subject: add new test get-binary-name-test for testing pa_get_binary_name() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1079 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 8 +++++++- src/tests/get-binary-name-test.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/tests/get-binary-name-test.c diff --git a/src/Makefile.am b/src/Makefile.am index fad01e08..0db8a8f2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -192,7 +192,8 @@ noinst_PROGRAMS = \ interpol-test \ channelmap-test \ thread-mainloop-test \ - utf8-test + utf8-test \ + get-binary-name-test if HAVE_SIGXCPU noinst_PROGRAMS += \ @@ -225,6 +226,11 @@ utf8_test_CFLAGS = $(AM_CFLAGS) utf8_test_LDADD = $(AM_LDADD) libpulsecore.la utf8_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +get_binary_name_test_SOURCES = tests/get-binary-name-test.c +get_binary_name_test_CFLAGS = $(AM_CFLAGS) +get_binary_name_test_LDADD = $(AM_LDADD) libpulse.la +get_binary_name_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + mcalign_test_SOURCES = tests/mcalign-test.c mcalign_test_CFLAGS = $(AM_CFLAGS) mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpulsecore.la diff --git a/src/tests/get-binary-name-test.c b/src/tests/get-binary-name-test.c new file mode 100644 index 00000000..0cea2b6d --- /dev/null +++ b/src/tests/get-binary-name-test.c @@ -0,0 +1,36 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +int main(int argc, char *argv[]) { + char exename[PATH_MAX]; + + printf("%s\n", pa_get_binary_name(exename, sizeof(exename))); + return 0; +} -- cgit From 82e680c31ca9df51c599ce9634343b28233a27fa Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 14 Jul 2006 10:08:53 +0000 Subject: Make sure the win32 default conf gets shipped. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1080 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Makefile.am b/src/Makefile.am index 0db8a8f2..8da51aac 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -76,6 +76,7 @@ EXTRA_DIST = \ pulse/client.conf.in \ daemon/daemon.conf.in \ daemon/default.pa.in \ + daemon/default.pa.win32 \ depmod.py \ daemon/esdcompat.in \ utils/padsp \ -- cgit From dfd864a00e45c3fef8a5be51718b022843de7a30 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Jul 2006 10:19:46 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1081 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 2 -- 1 file changed, 2 deletions(-) diff --git a/todo b/todo index cae27b2a..6a805813 100644 --- a/todo +++ b/todo @@ -31,12 +31,10 @@ Post 0.9.0: - use send() with MSG_NOSIGNAL instead of write() wherever possible, and than drop that SIGPIPE warning - drop dependency of libpolyp on libX11, instead use an external mini binary - "hot" moving of streams between sinks -- check if using prctl(PR_GET_NAME) makes sense in pa_get_binary_name() - gconf module + frontend - hooks for creating sink inputs - insert the low-level device name in the default sink/source name, to make them recognizable:q! - Long term: - pass meta info for hearing impaired - X11: support for the X11 synchronization extension -- cgit From 350a253dc559956b63ced4e602b1040ccba66f98 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Jul 2006 10:20:57 +0000 Subject: remove vi'ism git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1082 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/todo b/todo index 6a805813..f3012281 100644 --- a/todo +++ b/todo @@ -33,7 +33,7 @@ Post 0.9.0: - "hot" moving of streams between sinks - gconf module + frontend - hooks for creating sink inputs -- insert the low-level device name in the default sink/source name, to make them recognizable:q! +- insert the low-level device name in the default sink/source name, to make them recognizable Long term: - pass meta info for hearing impaired -- cgit From 860be2e70b33ff5eeb9130f80c4b1c096a2a8f27 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Jul 2006 22:42:01 +0000 Subject: try to use send(,,MSG_NOSIGNAL) instead of write() wherever possible (which will allow us to drop the SIGPIPE check). Cache the results of the last write()/send() to make sure that we do not issue more than necessary system calls. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1083 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/cpulimit.c | 4 +- src/daemon/main.c | 10 ++-- src/modules/module-esound-compat-spawnfd.c | 2 +- src/modules/module-jack-sink.c | 6 ++- src/modules/module-jack-source.c | 6 ++- src/modules/module-mmkbd-evdev.c | 5 +- src/modules/module-oss.c | 2 +- src/pulse/mainloop-signal.c | 4 +- src/pulse/mainloop.c | 6 ++- src/pulse/xmalloc.c | 2 +- src/pulsecore/authkey.c | 6 +-- src/pulsecore/core-util.c | 83 +++++++++++++++++++++--------- src/pulsecore/core-util.h | 8 +-- src/pulsecore/iochannel.c | 6 ++- src/pulsecore/pid.c | 4 +- src/pulsecore/random.c | 2 +- src/tests/mcalign-test.c | 2 +- 17 files changed, 100 insertions(+), 58 deletions(-) diff --git a/src/daemon/cpulimit.c b/src/daemon/cpulimit.c index a8c9d3f5..b8740ea0 100644 --- a/src/daemon/cpulimit.c +++ b/src/daemon/cpulimit.c @@ -111,7 +111,7 @@ static void reset_cpu_time(int t) { /* A simple, thread-safe puts() work-alike */ static void write_err(const char *p) { - pa_loop_write(2, p, strlen(p)); + pa_loop_write(2, p, strlen(p), NULL); } /* The signal handler, called on every SIGXCPU */ @@ -159,7 +159,7 @@ static void signal_handler(int sig) { static void callback(pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata) { char c; assert(m && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == the_pipe[0]); - read(the_pipe[0], &c, sizeof(c)); + pa_read(the_pipe[0], &c, sizeof(c), NULL); m->quit(m, 1); /* Quit the main loop */ } diff --git a/src/daemon/main.c b/src/daemon/main.c index 5e7330a5..c41c69df 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -304,7 +304,7 @@ int main(int argc, char *argv[]) { close(daemon_pipe[1]); daemon_pipe[1] = -1; - if (pa_loop_read(daemon_pipe[0], &retval, sizeof(retval)) != sizeof(retval)) { + if (pa_loop_read(daemon_pipe[0], &retval, sizeof(retval), NULL) != sizeof(retval)) { pa_log(__FILE__": read() failed: %s", pa_cstrerror(errno)); retval = 1; } @@ -368,7 +368,7 @@ int main(int argc, char *argv[]) { pa_log(__FILE__": pa_pid_file_create() failed."); #ifdef HAVE_FORK if (conf->daemonize) - pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); + pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL); #endif goto finish; } @@ -428,20 +428,20 @@ int main(int argc, char *argv[]) { pa_log(__FILE__": failed to initialize daemon."); #ifdef HAVE_FORK if (conf->daemonize) - pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); + pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL); #endif } else if (!c->modules || pa_idxset_size(c->modules) == 0) { pa_log(__FILE__": daemon startup without any loaded modules, refusing to work."); #ifdef HAVE_FORK if (conf->daemonize) - pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); + pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL); #endif } else { retval = 0; #ifdef HAVE_FORK if (conf->daemonize) - pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); + pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL); #endif c->disallow_module_loading = conf->disallow_module_loading; diff --git a/src/modules/module-esound-compat-spawnfd.c b/src/modules/module-esound-compat-spawnfd.c index c4bc342a..54e090e4 100644 --- a/src/modules/module-esound-compat-spawnfd.c +++ b/src/modules/module-esound-compat-spawnfd.c @@ -59,7 +59,7 @@ int pa__init(pa_core *c, pa_module*m) { goto finish; } - if (pa_loop_write(fd, &x, sizeof(x)) != sizeof(x)) + if (pa_loop_write(fd, &x, sizeof(x), NULL) != sizeof(x)) pa_log(__FILE__": WARNING: write(%u, 1, 1) failed: %s", fd, pa_cstrerror(errno)); close(fd); diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index 74f25d53..d761c1f7 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -80,6 +80,7 @@ struct userdata { jack_nframes_t frames_requested; int quit_requested; + int pipe_fd_type; int pipe_fds[2]; pa_io_event *io_event; @@ -120,7 +121,7 @@ static void io_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_ assert(u); assert(u->pipe_fds[0] == fd); - read(fd, &x, 1); + pa_read(fd, &x, 1, &u->pipe_fd_type); if (u->quit_requested) { stop_sink(u); @@ -165,7 +166,7 @@ static void request_render(struct userdata *u) { assert(u); assert(u->pipe_fds[1] >= 0); - write(u->pipe_fds[1], &c, 1); + pa_write(u->pipe_fds[1], &c, 1, &u->pipe_fd_type); } static void jack_shutdown(void *arg) { @@ -268,6 +269,7 @@ int pa__init(pa_core *c, pa_module*m) { u->core = c; u->module = m; u->pipe_fds[0] = u->pipe_fds[1] = -1; + u->pipe_fd_type = 0; pthread_mutex_init(&u->mutex, NULL); pthread_cond_init(&u->cond, NULL); diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index 9c7f449f..649a8f98 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -81,6 +81,7 @@ struct userdata { int quit_requested; int pipe_fds[2]; + int pipe_fd_type; pa_io_event *io_event; jack_nframes_t frames_in_buffer; @@ -119,7 +120,7 @@ static void io_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_ assert(u); assert(u->pipe_fds[0] == fd); - read(fd, &x, 1); + pa_read(fd, &x, 1, &u->pipe_fd_type); if (u->quit_requested) { stop_source(u); @@ -166,7 +167,7 @@ static void request_post(struct userdata *u) { assert(u); assert(u->pipe_fds[1] >= 0); - write(u->pipe_fds[1], &c, 1); + pa_write(u->pipe_fds[1], &c, 1, &u->pipe_fd_type); } static void jack_shutdown(void *arg) { @@ -266,6 +267,7 @@ int pa__init(pa_core *c, pa_module*m) { u->core = c; u->module = m; u->pipe_fds[0] = u->pipe_fds[1] = -1; + u->pipe_fd_type = 0; pthread_mutex_init(&u->mutex, NULL); pthread_cond_init(&u->cond, NULL); diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c index ddbf16d2..c3d07396 100644 --- a/src/modules/module-mmkbd-evdev.c +++ b/src/modules/module-mmkbd-evdev.c @@ -70,7 +70,7 @@ static const char* const valid_modargs[] = { }; struct userdata { - int fd; + int fd, fd_type; pa_io_event *io; char *sink_name; pa_module *module; @@ -89,7 +89,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC if (events & PA_IO_EVENT_INPUT) { struct input_event ev; - if (pa_loop_read(u->fd, &ev, sizeof(ev)) <= 0) { + if (pa_loop_read(u->fd, &ev, sizeof(ev), &u->fd_type) <= 0) { pa_log(__FILE__": failed to read from event device: %s", pa_cstrerror(errno)); goto fail; } @@ -182,6 +182,7 @@ int pa__init(pa_core *c, pa_module*m) { u->io = NULL; u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); u->fd = -1; + u->fd_type = 0; if ((u->fd = open(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), O_RDONLY)) < 0) { pa_log(__FILE__": failed to open evdev device: %s", pa_cstrerror(errno)); diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 5a80661e..a3ea2c1f 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -467,7 +467,7 @@ int pa__init(pa_core *c, pa_module*m) { */ if (u->source) { char *buf = pa_xnew(char, u->sample_size); - read(u->fd, buf, u->sample_size); + pa_read(u->fd, buf, u->sample_size, NULL); pa_xfree(buf); } diff --git a/src/pulse/mainloop-signal.c b/src/pulse/mainloop-signal.c index c3cf362d..11a27cd5 100644 --- a/src/pulse/mainloop-signal.c +++ b/src/pulse/mainloop-signal.c @@ -67,7 +67,7 @@ static void signal_handler(int sig) { #ifndef HAVE_SIGACTION signal(sig, signal_handler); #endif - pa_write(signal_pipe[1], &sig, sizeof(sig)); + pa_write(signal_pipe[1], &sig, sizeof(sig), NULL); } static void dispatch(pa_mainloop_api*a, int sig) { @@ -86,7 +86,7 @@ static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags int sig; assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]); - if ((r = pa_read(signal_pipe[0], &sig, sizeof(sig))) < 0) { + if ((r = pa_read(signal_pipe[0], &sig, sizeof(sig), NULL)) < 0) { if (errno == EAGAIN) return; diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c index 32f1a845..dfbc337b 100644 --- a/src/pulse/mainloop.c +++ b/src/pulse/mainloop.c @@ -100,6 +100,7 @@ struct pa_mainloop { int deferred_pending; int wakeup_pipe[2]; + int wakeup_pipe_type; enum { STATE_PASSIVE, @@ -337,6 +338,7 @@ pa_mainloop *pa_mainloop_new(void) { m = pa_xmalloc(sizeof(pa_mainloop)); + m->wakeup_pipe_type = 0; if (pipe(m->wakeup_pipe) < 0) { pa_log_error(__FILE__": ERROR: cannot create wakeup pipe"); pa_xfree(m); @@ -625,7 +627,7 @@ void pa_mainloop_wakeup(pa_mainloop *m) { assert(m); if (m->wakeup_pipe[1] >= 0) - pa_write(m->wakeup_pipe[1], &c, sizeof(c)); + pa_write(m->wakeup_pipe[1], &c, sizeof(c), &m->wakeup_pipe_type); } static void clear_wakeup(pa_mainloop *m) { @@ -636,7 +638,7 @@ static void clear_wakeup(pa_mainloop *m) { if (m->wakeup_pipe[0] < 0) return; - while (pa_read(m->wakeup_pipe[0], &c, sizeof(c)) == sizeof(c)); + while (pa_read(m->wakeup_pipe[0], &c, sizeof(c), &m->wakeup_pipe_type) == sizeof(c)); } int pa_mainloop_prepare(pa_mainloop *m, int timeout) { diff --git a/src/pulse/xmalloc.c b/src/pulse/xmalloc.c index 46871aeb..36755166 100644 --- a/src/pulse/xmalloc.c +++ b/src/pulse/xmalloc.c @@ -49,7 +49,7 @@ static void oom(void) PA_GCC_NORETURN; * exits */ static void oom(void) { static const char e[] = "Not enough memory\n"; - pa_loop_write(STDERR_FILENO, e, sizeof(e)-1); + pa_loop_write(STDERR_FILENO, e, sizeof(e)-1, NULL); #ifdef SIGQUIT raise(SIGQUIT); #endif diff --git a/src/pulsecore/authkey.c b/src/pulsecore/authkey.c index 064209d9..a5df3ed1 100644 --- a/src/pulsecore/authkey.c +++ b/src/pulsecore/authkey.c @@ -53,7 +53,7 @@ static int generate(int fd, void *ret_data, size_t length) { lseek(fd, 0, SEEK_SET); ftruncate(fd, 0); - if ((r = pa_loop_write(fd, ret_data, length)) < 0 || (size_t) r != length) { + if ((r = pa_loop_write(fd, ret_data, length, NULL)) < 0 || (size_t) r != length) { pa_log(__FILE__": failed to write cookie file: %s", pa_cstrerror(errno)); return -1; } @@ -84,7 +84,7 @@ static int load(const char *fn, void *data, size_t length) { unlock = pa_lock_fd(fd, 1) >= 0; - if ((r = pa_loop_read(fd, data, length)) < 0) { + if ((r = pa_loop_read(fd, data, length, NULL)) < 0) { pa_log(__FILE__": failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } @@ -188,7 +188,7 @@ int pa_authkey_save(const char *fn, const void *data, size_t length) { unlock = pa_lock_fd(fd, 1) >= 0; - if ((r = pa_loop_write(fd, data, length)) < 0 || (size_t) r != length) { + if ((r = pa_loop_write(fd, data, length, NULL)) < 0 || (size_t) r != length) { pa_log(__FILE__": failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 9d694da5..16c3631f 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -201,57 +201,81 @@ finish: return ret; } -/** Platform independent read function. Necessary since not all systems - * treat all file descriptors equal. */ -ssize_t pa_read(int fd, void *buf, size_t count) { - ssize_t r; +/** Platform independent read function. Necessary since not all + * systems treat all file descriptors equal. If type is + * non-NULL it is used to cache the type of the fd. This is + * useful for making sure that only a single syscall is executed per + * function call. The variable pointed to should be initialized to 0 + * by the caller. */ +ssize_t pa_read(int fd, void *buf, size_t count, int *type) { #ifdef OS_IS_WIN32 - r = recv(fd, buf, count, 0); - if (r < 0) { + + if (!type || *type == 0) { + ssize_t r; + + if ((r = recv(fd, buf, count, 0)) >= 0) + return r; + if (WSAGetLastError() != WSAENOTSOCK) { errno = WSAGetLastError(); return r; } + + if (type) + *type = 1; } - if (r < 0) #endif - r = read(fd, buf, count); - - return r; + + return read(fd, buf, count); } /** Similar to pa_read(), but handles writes */ -ssize_t pa_write(int fd, const void *buf, size_t count) { - ssize_t r; +ssize_t pa_write(int fd, const void *buf, size_t count, int *type) { + + if (!type || *type == 0) { + ssize_t r; + if ((r = send(fd, buf, count, MSG_NOSIGNAL)) >= 0) + return r; + #ifdef OS_IS_WIN32 - r = send(fd, buf, count, 0); - if (r < 0) { if (WSAGetLastError() != WSAENOTSOCK) { errno = WSAGetLastError(); return r; } - } - - if (r < 0) +#else + if (errno != ENOTSOCK) + return r; #endif - r = write(fd, buf, count); - return r; + if (type) + *type = 1; + } + + return write(fd, buf, count); } /** Calls read() in a loop. Makes sure that as much as 'size' bytes, * unless EOF is reached or an error occured */ -ssize_t pa_loop_read(int fd, void*data, size_t size) { +ssize_t pa_loop_read(int fd, void*data, size_t size, int *type) { ssize_t ret = 0; - assert(fd >= 0 && data && size); + int _type; + + assert(fd >= 0); + assert(data); + assert(size); + + if (!type) { + _type = 0; + type = &_type; + } while (size > 0) { ssize_t r; - if ((r = pa_read(fd, data, size)) < 0) + if ((r = pa_read(fd, data, size, type)) < 0) return r; if (r == 0) @@ -266,14 +290,23 @@ ssize_t pa_loop_read(int fd, void*data, size_t size) { } /** Similar to pa_loop_read(), but wraps write() */ -ssize_t pa_loop_write(int fd, const void*data, size_t size) { +ssize_t pa_loop_write(int fd, const void*data, size_t size, int *type) { ssize_t ret = 0; - assert(fd >= 0 && data && size); + int _type; + + assert(fd >= 0); + assert(data); + assert(size); + + if (!type) { + _type = 0; + type = &_type; + } while (size > 0) { ssize_t r; - if ((r = pa_write(fd, data, size)) < 0) + if ((r = pa_write(fd, data, size, type)) < 0) return r; if (r == 0) diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index 0012afc6..864a96ec 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -36,10 +36,10 @@ void pa_make_nonblock_fd(int fd); int pa_make_secure_dir(const char* dir); int pa_make_secure_parent_dir(const char *fn); -ssize_t pa_read(int fd, void *buf, size_t count); -ssize_t pa_write(int fd, const void *buf, size_t count); -ssize_t pa_loop_read(int fd, void*data, size_t size); -ssize_t pa_loop_write(int fd, const void*data, size_t size); +ssize_t pa_read(int fd, void *buf, size_t count, int *type); +ssize_t pa_write(int fd, const void *buf, size_t count, int *type); +ssize_t pa_loop_read(int fd, void*data, size_t size, int *type); +ssize_t pa_loop_write(int fd, const void*data, size_t size, int *type); void pa_check_signal_is_blocked(int sig); diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c index 8a19094a..842c0e6a 100644 --- a/src/pulsecore/iochannel.c +++ b/src/pulsecore/iochannel.c @@ -49,6 +49,7 @@ struct pa_iochannel { int ifd, ofd; + int ifd_type, ofd_type; pa_mainloop_api* mainloop; pa_iochannel_cb_t callback; @@ -127,6 +128,7 @@ pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) { io = pa_xnew(pa_iochannel, 1); io->ifd = ifd; io->ofd = ofd; + io->ifd_type = io->ofd_type = 0; io->mainloop = m; io->userdata = NULL; @@ -204,7 +206,7 @@ ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) { assert(l); assert(io->ofd >= 0); - r = pa_write(io->ofd, data, l); + r = pa_write(io->ofd, data, l, &io->ofd_type); if (r >= 0) { io->writable = 0; enable_mainloop_sources(io); @@ -220,7 +222,7 @@ ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) { assert(data); assert(io->ifd >= 0); - r = pa_read(io->ifd, data, l); + r = pa_read(io->ifd, data, l, &io->ifd_type); if (r >= 0) { io->readable = 0; enable_mainloop_sources(io); diff --git a/src/pulsecore/pid.c b/src/pulsecore/pid.c index b8972866..0ad76a6e 100644 --- a/src/pulsecore/pid.c +++ b/src/pulsecore/pid.c @@ -56,7 +56,7 @@ static pid_t read_pid(const char *fn, int fd) { assert(fn && fd >= 0); - if ((r = pa_loop_read(fd, t, sizeof(t)-1)) < 0) { + if ((r = pa_loop_read(fd, t, sizeof(t)-1, NULL)) < 0) { pa_log_warn(__FILE__": WARNING: failed to read PID file '%s': %s", fn, pa_cstrerror(errno)); return (pid_t) -1; @@ -177,7 +177,7 @@ int pa_pid_file_create(void) { snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid()); l = strlen(t); - if (pa_loop_write(fd, t, l) != (ssize_t) l) { + if (pa_loop_write(fd, t, l, NULL) != (ssize_t) l) { pa_log(__FILE__": failed to write PID file."); goto fail; } diff --git a/src/pulsecore/random.c b/src/pulsecore/random.c index 3d3357a5..684ead71 100644 --- a/src/pulsecore/random.c +++ b/src/pulsecore/random.c @@ -61,7 +61,7 @@ static int random_proper(void *ret_data, size_t length) { if ((fd = open(*device, O_RDONLY)) >= 0) { - if ((r = pa_loop_read(fd, ret_data, length)) < 0 || (size_t) r != length) + if ((r = pa_loop_read(fd, ret_data, length, NULL)) < 0 || (size_t) r != length) ret = -1; close(fd); diff --git a/src/tests/mcalign-test.c b/src/tests/mcalign-test.c index ccb0613e..7a68e6de 100644 --- a/src/tests/mcalign-test.c +++ b/src/tests/mcalign-test.c @@ -82,7 +82,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { if (pa_mcalign_pop(a, &t) < 0) break; - pa_loop_write(STDOUT_FILENO, (uint8_t*) t.memblock->data + t.index, t.length); + pa_loop_write(STDOUT_FILENO, (uint8_t*) t.memblock->data + t.index, t.length, NULL); fprintf(stderr, "Wrote %lu bytes.\n", (unsigned long) t.length); pa_memblock_unref(t.memblock); -- cgit From 3eeecdc79095748eb8ac046edee6bf4fe7268060 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Jul 2006 23:00:20 +0000 Subject: don't set MSG_NOSIGNAL for recvmsg(), since it doesn't make sense there git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1084 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/iochannel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c index 842c0e6a..15aa8e35 100644 --- a/src/pulsecore/iochannel.c +++ b/src/pulsecore/iochannel.c @@ -336,7 +336,7 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struc mh.msg_controllen = sizeof(cmsg_data); mh.msg_flags = 0; - if ((r = recvmsg(io->ifd, &mh, MSG_NOSIGNAL)) >= 0) { + if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) { struct cmsghdr *cmsg; *creds_valid = 0; -- cgit From fc544a63de7496ab6ea23cce65599c086d730256 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Jul 2006 23:00:57 +0000 Subject: don't send SCM_CREDENTIALS on every sendmsg(), instead do it only on handshake git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1085 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/pstream.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index 60c05938..e9b6f4c8 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -291,6 +291,7 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa i->channel = channel; i->offset = offset; i->seek_mode = seek_mode; + i->with_creds = 0; pa_memblock_ref(i->chunk.memblock); @@ -317,9 +318,6 @@ static void prepare_next_write_item(pa_pstream *p) { p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = 0; p->write.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK] = 0; -#ifdef SCM_CREDENTIALS - p->send_creds_now = 1; -#endif } else { assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK && p->write.current->chunk.memblock); @@ -329,11 +327,12 @@ static void prepare_next_write_item(pa_pstream *p) { p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = htonl((uint32_t) (((uint64_t) p->write.current->offset) >> 32)); p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = htonl((uint32_t) ((uint64_t) p->write.current->offset)); p->write.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK] = htonl(p->write.current->seek_mode); + } #ifdef SCM_CREDENTIALS - p->send_creds_now = 1; + p->send_creds_now = p->write.current->with_creds; #endif - } + } static int do_write(pa_pstream *p) { -- cgit From b8f9ae00f341c936eb27dd51d307f99682a09685 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Jul 2006 23:06:44 +0000 Subject: remove checking for SIGPIPE blocking from client code. Because we use send(,,MSG_NOSIGNAL) for most socket writes now the reason for SIGPIPE blocking is no longer give. We keep this check for the server side however, because pipes create SIGPIPE too but cannot be used with MSG_NOSIGNAL. Some modules use pipes for internal and external communication. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1086 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/context.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/pulse/context.c b/src/pulse/context.c index 648024c3..5724765b 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -132,10 +132,6 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { memset(&c->spawn_api, 0, sizeof(c->spawn_api)); c->do_autospawn = 0; -#ifdef SIGPIPE - pa_check_signal_is_blocked(SIGPIPE); -#endif - c->conf = pa_client_conf_new(); pa_client_conf_load(c->conf, NULL); #ifdef HAVE_X11 -- cgit From d43bcb31bb355f1cddc037b017e1c65ef7725633 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Jul 2006 23:08:14 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1087 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 - 1 file changed, 1 deletion(-) diff --git a/todo b/todo index f3012281..9b28ce1d 100644 --- a/todo +++ b/todo @@ -28,7 +28,6 @@ Post 0.9.0: - Document utf8.h, timeval.h and util.h - fix clock of the NULL sink - gettextify polypaudio -- use send() with MSG_NOSIGNAL instead of write() wherever possible, and than drop that SIGPIPE warning - drop dependency of libpolyp on libX11, instead use an external mini binary - "hot" moving of streams between sinks - gconf module + frontend -- cgit From 55a8db8efe50a85abe690224c13c8501dd56be47 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Jul 2006 23:59:42 +0000 Subject: improve latency calculation of NULL sink git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1088 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-null-sink.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index 8cfce8fe..470be6bc 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -63,6 +63,9 @@ struct userdata { pa_sink *sink; pa_time_event *time_event; size_t block_size; + + uint64_t n_bytes; + struct timeval start_time; }; static const char* const valid_modargs[] = { @@ -90,6 +93,19 @@ static void time_callback(pa_mainloop_api *m, pa_time_event*e, const struct time pa_timeval_add(&ntv, pa_bytes_to_usec(l, &u->sink->sample_spec)); m->time_restart(e, &ntv); + + u->n_bytes += l; +} + +static pa_usec_t get_latency(pa_sink *s) { + struct userdata *u = s->userdata; + pa_usec_t a, b; + struct timeval now; + + a = pa_timeval_diff(pa_gettimeofday(&now), &u->start_time); + b = pa_bytes_to_usec(u->n_bytes, &s->sample_spec); + + return b > a ? b - a : 0; } int pa__init(pa_core *c, pa_module*m) { @@ -97,8 +113,9 @@ int pa__init(pa_core *c, pa_module*m) { pa_sample_spec ss; pa_channel_map map; pa_modargs *ma = NULL; - struct timeval tv; - assert(c && m); + + assert(c); + assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": failed to parse module arguments."); @@ -111,7 +128,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - u = pa_xmalloc0(sizeof(struct userdata)); + u = pa_xnew0(struct userdata, 1); u->core = c; u->module = m; m->userdata = u; @@ -120,13 +137,16 @@ int pa__init(pa_core *c, pa_module*m) { pa_log(__FILE__": failed to create sink."); goto fail; } - + + u->sink->get_latency = get_latency; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("NULL sink"); + u->sink->description = pa_xstrdup("NULL sink"); - pa_gettimeofday(&tv); - u->time_event = c->mainloop->time_new(c->mainloop, &tv, time_callback, u); + u->n_bytes = 0; + pa_gettimeofday(&u->start_time); + + u->time_event = c->mainloop->time_new(c->mainloop, &u->start_time, time_callback, u); u->block_size = pa_bytes_per_second(&ss) / 10; -- cgit From a537b01cba05ff3d5b8bb3035413d2aebf4e00f0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Jul 2006 12:40:27 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1089 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/todo b/todo index 9b28ce1d..2c98c4ed 100644 --- a/todo +++ b/todo @@ -26,13 +26,13 @@ Post 0.9.0: - iconv stuff sent from utils to server (UTF-8) - iconv sample loading in server - Document utf8.h, timeval.h and util.h -- fix clock of the NULL sink - gettextify polypaudio - drop dependency of libpolyp on libX11, instead use an external mini binary - "hot" moving of streams between sinks - gconf module + frontend - hooks for creating sink inputs - insert the low-level device name in the default sink/source name, to make them recognizable +- add new flag for distuinguishing hw sinks/sources from virtual sink/sources Long term: - pass meta info for hearing impaired -- cgit From 6e38949039cca052ee0d167b92f895e4d95ee30d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Jul 2006 17:26:55 +0000 Subject: add a new boolean variable is_hardware to pa_sink/pa_source to denote wether the specific device is a hardware device or virtual/software git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1090 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/sink.c | 2 ++ src/pulsecore/sink.h | 2 ++ src/pulsecore/source.c | 2 ++ src/pulsecore/source.h | 2 ++ 4 files changed, 8 insertions(+) diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index ee6850f0..8acb7715 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -102,6 +102,8 @@ pa_sink* pa_sink_new( s->sw_muted = 0; s->hw_muted = 0; + s->is_hardware = 0; + s->get_latency = NULL; s->notify = NULL; s->set_hw_volume = NULL; diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index fdff0522..1a6bc988 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -60,6 +60,8 @@ struct pa_sink { pa_cvolume hw_volume, sw_volume; int hw_muted, sw_muted; + int is_hardware; + void (*notify)(pa_sink*sink); pa_usec_t (*get_latency)(pa_sink *s); int (*set_hw_volume)(pa_sink *s); diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 84151a92..48b6daea 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -98,6 +98,8 @@ pa_source* pa_source_new( s->sw_muted = 0; s->hw_muted = 0; + s->is_hardware = 0; + s->get_latency = NULL; s->notify = NULL; s->set_hw_volume = NULL; diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index 6255c115..878ae34d 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -61,6 +61,8 @@ struct pa_source { pa_cvolume hw_volume, sw_volume; int hw_muted, sw_muted; + + int is_hardware; void (*notify)(pa_source*source); pa_usec_t (*get_latency)(pa_source *s); -- cgit From 494fa68327fb52276d68437e8467886ce81de297 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Jul 2006 17:28:10 +0000 Subject: add new PA_SOURCE_HARDWARE/PA_SINK_HARDWARE flag git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1091 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/def.h | 6 ++++-- src/pulsecore/protocol-native.c | 10 ++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/pulse/def.h b/src/pulse/def.h index b98337d2..06d4c7c2 100644 --- a/src/pulse/def.h +++ b/src/pulse/def.h @@ -295,13 +295,15 @@ typedef enum pa_seek_mode { /** Special sink flags. \since 0.8 */ typedef enum pa_sink_flags { PA_SINK_HW_VOLUME_CTRL = 1, /**< Supports hardware volume control */ - PA_SINK_LATENCY = 2 /**< Supports latency querying */ + PA_SINK_LATENCY = 2, /**< Supports latency querying */ + PA_SINK_HARDWARE = 4 /**< Is a hardware sink of some kind, in contrast to "virtual"/software sinks */ } pa_sink_flags_t; /** Special source flags. \since 0.8 */ typedef enum pa_source_flags { PA_SOURCE_HW_VOLUME_CTRL = 1, /**< Supports hardware volume control */ - PA_SOURCE_LATENCY = 2 /**< Supports latency querying */ + PA_SOURCE_LATENCY = 2, /**< Supports latency querying */ + PA_SOURCE_HARDWARE = 4 /**< Is a hardware source of some kind, in contrast to "virtual"/software source */ } pa_source_flags_t; /** A generic free() like callback prototype */ diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index f77c9c24..784610bd 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -1265,7 +1265,10 @@ static void sink_fill_tagstruct(pa_tagstruct *t, pa_sink *sink) { PA_TAG_STRING, sink->monitor_source->name, PA_TAG_USEC, pa_sink_get_latency(sink), PA_TAG_STRING, sink->driver, - PA_TAG_U32, (sink->get_hw_volume ? PA_SINK_HW_VOLUME_CTRL : 0) | (sink->get_latency ? PA_SINK_LATENCY : 0), + PA_TAG_U32, + (sink->get_hw_volume ? PA_SINK_HW_VOLUME_CTRL : 0) | + (sink->get_latency ? PA_SINK_LATENCY : 0) | + (sink->is_hardware ? PA_SINK_HARDWARE : 0), PA_TAG_INVALID); } @@ -1285,7 +1288,10 @@ static void source_fill_tagstruct(pa_tagstruct *t, pa_source *source) { PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL, PA_TAG_USEC, pa_source_get_latency(source), PA_TAG_STRING, source->driver, - PA_TAG_U32, (source->get_hw_volume ? PA_SOURCE_HW_VOLUME_CTRL : 0) | (source->get_latency ? PA_SOURCE_LATENCY : 0), + PA_TAG_U32, + (source->get_hw_volume ? PA_SOURCE_HW_VOLUME_CTRL : 0) | + (source->get_latency ? PA_SOURCE_LATENCY : 0) | + (source->is_hardware ? PA_SOURCE_HARDWARE : 0), PA_TAG_INVALID); } -- cgit From b91dd2381bffeb0a4b5450ef4ce1f0031909f79a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Jul 2006 17:28:41 +0000 Subject: set is_hardware flag for a few hw plugins git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1092 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-sink.c | 1 + src/modules/module-alsa-source.c | 1 + src/modules/module-oss-mmap.c | 2 ++ src/modules/module-oss.c | 2 ++ src/modules/module-solaris.c | 2 ++ src/modules/module-waveout.c | 2 ++ 6 files changed, 10 insertions(+) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 9238072b..d5abdc28 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -383,6 +383,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } + u->sink->is_hardware = 1; u->sink->get_latency = sink_get_latency_cb; if (u->mixer_handle) { assert(u->mixer_elem); diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 68c61be9..ca4ac9d0 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -376,6 +376,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } + u->source->is_hardware = 1; u->source->userdata = u; u->source->get_latency = source_get_latency_cb; if (u->mixer_handle) { diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index fcc89c84..d6f37633 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -444,6 +444,7 @@ int pa__init(pa_core *c, pa_module*m) { hwdesc[0] ? " (" : "", hwdesc[0] ? hwdesc : "", hwdesc[0] ? ")" : ""); + u->source->is_hardware = 1; u->in_memblocks = pa_xnew0(pa_memblock*, u->in_fragments); @@ -485,6 +486,7 @@ int pa__init(pa_core *c, pa_module*m) { hwdesc[0] ? hwdesc : "", hwdesc[0] ? ")" : ""); + u->sink->is_hardware = 1; u->out_memblocks = pa_xmalloc0(sizeof(struct memblock *)*u->out_fragments); enable_bits |= PCM_ENABLE_OUTPUT; diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index a3ea2c1f..cde7f311 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -418,6 +418,7 @@ int pa__init(pa_core *c, pa_module*m) { hwdesc[0] ? " (" : "", hwdesc[0] ? hwdesc : "", hwdesc[0] ? ")" : ""); + u->source->is_hardware = 1; } else u->source = NULL; @@ -435,6 +436,7 @@ int pa__init(pa_core *c, pa_module*m) { hwdesc[0] ? " (" : "", hwdesc[0] ? hwdesc : "", hwdesc[0] ? ")" : ""); + u->sink->is_hardware = 1; } else u->sink = NULL; diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 12c4a3ff..02ef4bc4 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -555,6 +555,7 @@ int pa__init(pa_core *c, pa_module*m) { u->source->set_hw_volume = source_set_hw_volume_cb; pa_source_set_owner(u->source, m); u->source->description = pa_sprintf_malloc("Solaris PCM on '%s'", p); + u->source->is_hardware = 1; } else u->source = NULL; @@ -569,6 +570,7 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->userdata = u; pa_sink_set_owner(u->sink, m); u->sink->description = pa_sprintf_malloc("Solaris PCM on '%s'", p); + u->sink->is_hardware = 1; } else u->sink = NULL; diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index 2bd4905a..8fd60b6a 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -504,6 +504,7 @@ int pa__init(pa_core *c, pa_module*m) { u->source->get_latency = source_get_latency_cb; pa_source_set_owner(u->source, m); u->source->description = pa_sprintf_malloc("Windows waveIn PCM"); + u->source->is_hardware = 1; } else u->source = NULL; @@ -517,6 +518,7 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->userdata = u; pa_sink_set_owner(u->sink, m); u->sink->description = pa_sprintf_malloc("Windows waveOut PCM"); + u->sink->is_hardware = 1; } else u->sink = NULL; -- cgit From 3b2843d5a8d50d6f9c3f5bedd63e3cc429c7ea13 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Jul 2006 17:29:09 +0000 Subject: show value of PA_SINK_HARDWARE/PA_SOURCE_HARDWARE in pactl git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1093 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pactl.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 94d22f98..25ef324d 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -174,7 +174,7 @@ static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_ "Volume: %s\n" "Monitor Source: %u\n" "Latency: %0.0f usec\n" - "Flags: %s%s\n", + "Flags: %s%s%s\n", i->index, i->name, i->driver, @@ -186,7 +186,8 @@ static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_ i->monitor_source, (double) i->latency, i->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", - i->flags & PA_SINK_LATENCY ? "LATENCY" : ""); + i->flags & PA_SINK_LATENCY ? "LATENCY " : "", + i->flags & PA_SINK_HARDWARE ? "HARDWARE" : ""); } @@ -222,7 +223,7 @@ static void get_source_info_callback(pa_context *c, const pa_source_info *i, int "Volume: %s\n" "Monitor of Sink: %s\n" "Latency: %0.0f usec\n" - "Flags: %s%s\n", + "Flags: %s%s%s\n", i->index, i->driver, i->name, @@ -234,7 +235,8 @@ static void get_source_info_callback(pa_context *c, const pa_source_info *i, int i->monitor_of_sink != PA_INVALID_INDEX ? t : "no", (double) i->latency, i->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", - i->flags & PA_SOURCE_LATENCY ? "LATENCY" : ""); + i->flags & PA_SOURCE_LATENCY ? "LATENCY " : "", + i->flags & PA_SOURCE_HARDWARE ? "HARDWARE" : ""); } -- cgit From 9ced7f62a7a453242eee9b56a0c5158753712ef4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Jul 2006 17:38:45 +0000 Subject: show summary after "configure" has run (closes: #22) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1094 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/configure.ac b/configure.ac index a36ee5a0..10f511c6 100644 --- a/configure.ac +++ b/configure.ac @@ -680,3 +680,80 @@ doxygen/doxygen.conf src/pulse/version.h ]) AC_OUTPUT + +# ========================================================================== +ENABLE_X11=no +if test "x$HAVE_X11" = "x1" ; then + ENABLE_X11=yes +fi + +ENABLE_OSS=no +if test "x$HAVE_OSS" = "x1" ; then + ENABLE_OSS=yes +fi + +ENABLE_ALSA=no +if test "x$HAVE_ALSA" = "x1" ; then + ENABLE_ALSA=yes +fi + +ENABLE_SOLARIS=no +if test "x$HAVE_SOLARIS" = "x1" ; then + ENABLE_SOLARIS=yes +fi + +ENABLE_GLIB20=no +if test "x$HAVE_GLIB20" = "x1" ; then + ENABLE_GLIB20=yes +fi + +ENABLE_GLIB12=no +if test "x$HAVE_GLIB12" = "x1" ; then + ENABLE_GLIB12=yes +fi + +ENABLE_AVAHI=no +if test "x$HAVE_AVAHI" = "x1" ; then + ENABLE_AVAHI=yes +fi + +ENABLE_JACK=no +if test "x$HAVE_JACK" = "x1" ; then + ENABLE_JACK=yes +fi + +ENABLE_LIBASYNCNS=no +if test "x$HAVE_LIBASYNCNS" = "x1" ; then + ENABLE_LIBASYNCNS=yes +fi + +ENABLE_LIRC=no +if test "x$HAVE_LIRC" = "x1" ; then + ENABLE_LIRC=yes +fi + +ENABLE_TCPWRAP=no +if test "x${LIBWRAP_LIBS}" != x ; then + ENABLE_TCPWRAP=yes +fi + +echo " + ---{ $PACKAGE_NAME $VERSION }--- + + prefix: ${prefix} + sysconfdir: ${sysconfdir} + localstatedir: ${localstatedir} + compiler: ${CC} + cflags: ${CFLAGS} + Have X11: ${ENABLE_X11} + Enable OSS: ${ENABLE_OSS} + Enable Alsa: ${ENABLE_ALSA} + Enable Solaris: ${ENABLE_SOLARIS} + Enable Glib 2.0: ${ENABLE_GLIB20} + Enable Glib 1.2: ${ENABLE_GLIB12} + Enable Avahi: ${ENABLE_AVAHI} + Enable Jack: ${ENABLE_JACK} + Enable Async DNS: ${ENABLE_LIBASYNCNS} + Enable LIRC: ${ENABLE_LIRC} + Enable TCP Wrappers: ${ENABLE_TCPWRAP} +" -- cgit From e45b1dceaf290b9a49893b5237127717773518d3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Jul 2006 17:42:29 +0000 Subject: todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1095 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 - 1 file changed, 1 deletion(-) diff --git a/todo b/todo index 2c98c4ed..07d022b7 100644 --- a/todo +++ b/todo @@ -32,7 +32,6 @@ Post 0.9.0: - gconf module + frontend - hooks for creating sink inputs - insert the low-level device name in the default sink/source name, to make them recognizable -- add new flag for distuinguishing hw sinks/sources from virtual sink/sources Long term: - pass meta info for hearing impaired -- cgit From ba31adcf3ebb542931fb6d66f2e1fc7689dfc712 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Jul 2006 23:20:27 +0000 Subject: make pulseaudio compile again on FreeBSD (patch from Diego "Flameeyes" Petteno) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1096 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 3 ++ src/modules/rtp/module-rtp-recv.c | 2 +- src/modules/rtp/sap.c | 1 + src/modules/rtp/sdp.c | 1 + src/utils/padsp.c | 58 +++++++++++++++++++++++++++++++++++---- 5 files changed, 58 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 10f511c6..80473415 100644 --- a/configure.ac +++ b/configure.ac @@ -249,6 +249,9 @@ ACX_PTHREAD AC_SYS_LARGEFILE +# Check for open64 to know if the current system does have open64() and similar functions +AC_CHECK_FUNCS([open64]) + #### [lib]iconv #### AM_ICONV diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index 932da849..0359a43b 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -236,7 +236,7 @@ static int mcast_socket(const struct sockaddr* sa, socklen_t salen) { struct ipv6_mreq mr6; memset(&mr6, 0, sizeof(mr6)); mr6.ipv6mr_multiaddr = ((const struct sockaddr_in6*) sa)->sin6_addr; - r = setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mr6, sizeof(mr6)); + r = setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mr6, sizeof(mr6)); } if (r < 0) { diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c index 3814a1c3..615b8e4e 100644 --- a/src/modules/rtp/sap.c +++ b/src/modules/rtp/sap.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/src/modules/rtp/sdp.c b/src/modules/rtp/sdp.c index cada636a..e707e4bb 100644 --- a/src/modules/rtp/sdp.c +++ b/src/modules/rtp/sdp.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include diff --git a/src/utils/padsp.c b/src/utils/padsp.c index b1636754..32cb5f9a 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,9 @@ #include #include +#ifdef __linux__ #include +#endif #include #include @@ -101,8 +104,10 @@ static int (*_ioctl)(int, int, void*) = NULL; static int (*_close)(int) = NULL; static int (*_open)(const char *, int, mode_t) = NULL; static FILE* (*_fopen)(const char *path, const char *mode) = NULL; +#ifdef HAVE_OPEN64 static int (*_open64)(const char *, int, mode_t) = NULL; static FILE* (*_fopen64)(const char *path, const char *mode) = NULL; +#endif static int (*_fclose)(FILE *f) = NULL; static int (*_access)(const char *, int) = NULL; @@ -1302,7 +1307,11 @@ static int sndstat_open(int flags, int *_errno) { debug(DEBUG_LEVEL_NORMAL, __FILE__": sndstat_open()\n"); - if (flags != O_RDONLY && flags != (O_RDONLY|O_LARGEFILE)) { + if (flags != O_RDONLY +#ifdef O_LARGEFILE + && flags != (O_RDONLY|O_LARGEFILE) +#endif + ) { *_errno = EACCES; debug(DEBUG_LEVEL_NORMAL, __FILE__": bad access!\n"); goto fail; @@ -1349,8 +1358,12 @@ int open(const char *filename, int flags, ...) { debug(DEBUG_LEVEL_VERBOSE, __FILE__": open(%s)\n", filename); va_start(args, flags); - if (flags & O_CREAT) + if (flags & O_CREAT) { + if (sizeof(mode_t) < sizeof(int)) + mode = va_arg(args, int); + else mode = va_arg(args, mode_t); + } va_end(args); if (!function_enter()) { @@ -1587,6 +1600,7 @@ static int map_format_back(pa_sample_format_t format) { } static int dsp_flush_fd(int fd) { +#ifdef SIOCINQ int l; if (ioctl(fd, SIOCINQ, &l) < 0) { @@ -1605,6 +1619,10 @@ static int dsp_flush_fd(int fd) { } return 0; +#else +# warning "Your platform does not support SIOCINQ, something might not work as intended." + return 0; +#endif } static int dsp_flush_socket(fd_info *i) { @@ -1629,6 +1647,7 @@ static int dsp_flush_socket(fd_info *i) { } static int dsp_empty_socket(fd_info *i) { +#ifdef SIOCINQ int ret = -1; /* Empty the socket */ @@ -1652,6 +1671,10 @@ static int dsp_empty_socket(fd_info *i) { } return ret; +#else +# warning "Your platform does not support SIOCINQ, something might not work as intended." + return 0; +#endif } static int dsp_drain(fd_info *i) { @@ -1864,7 +1887,11 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_GETCAPS: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CAPS\n"); - *(int*) argp = DSP_CAP_DUPLEX | DSP_CAP_MULTI; + *(int*) argp = DSP_CAP_DUPLEX +#ifdef DSP_CAP_MULTI + | DSP_CAP_MULTI +#endif + ; break; case SNDCTL_DSP_GETODELAY: { @@ -1895,11 +1922,15 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) } exit_loop: - + +#ifdef SIOCINQ if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno)); else *(int*) argp += l; +#else +# warning "Your platform does not support SIOCINQ, something might not work as intended." +#endif pa_threaded_mainloop_unlock(i->mainloop); @@ -1946,7 +1977,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_GETOSPACE: case SNDCTL_DSP_GETISPACE: { audio_buf_info *bi = (audio_buf_info*) argp; - int l; + int l = 0; size_t k = 0; if (request == SNDCTL_DSP_GETOSPACE) @@ -1965,10 +1996,14 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) } else k = i->fragment_size * i->n_fragments; +#ifdef SIOCINQ if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno)); l = 0; } +#else +# warning "Your platform does not dsp_flush_fd, something might not work as intended." +#endif bi->bytes = k > (size_t) l ? k - l : 0; } else { @@ -1978,11 +2013,14 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) } else k = 0; +#ifdef SIOCINQ if (ioctl(i->app_fd, SIOCINQ, &l) < 0) { debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno)); l = 0; } - +#else +# warning "Your platform does not dsp_flush_fd, something might not work as intended." +#endif bi->bytes = k + l; } @@ -2104,6 +2142,8 @@ int access(const char *pathname, int mode) { return 0; } +#ifdef HAVE_OPEN64 + int open64(const char *filename, int flags, ...) { va_list args; mode_t mode = 0; @@ -2126,6 +2166,8 @@ int open64(const char *filename, int flags, ...) { return open(filename, flags, mode); } +#endif + FILE* fopen(const char *filename, const char *mode) { FILE *f = NULL; int fd; @@ -2168,6 +2210,8 @@ FILE* fopen(const char *filename, const char *mode) { return f; } +#ifdef HAVE_OPEN64 + FILE *fopen64(const char *filename, const char *mode) { debug(DEBUG_LEVEL_VERBOSE, __FILE__": fopen64(%s)\n", filename); @@ -2183,6 +2227,8 @@ FILE *fopen64(const char *filename, const char *mode) { return fopen(filename, mode); } +#endif + int fclose(FILE *f) { fd_info *i; -- cgit From 4b352e5fac5ff546315139f7b791074261544f66 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 17 Jul 2006 11:26:29 +0000 Subject: Restore SIGPIPE warning when the platform doesn't have MSG_NOSIGNAL. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1097 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/context.c | 6 ++++++ src/pulsecore/core-util.c | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/src/pulse/context.c b/src/pulse/context.c index 5724765b..228053bc 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -132,6 +132,12 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { memset(&c->spawn_api, 0, sizeof(c->spawn_api)); c->do_autospawn = 0; +#ifndef MSG_NOSIGNAL +#ifdef SIGPIPE + pa_check_signal_is_blocked(SIGPIPE); +#endif +#endif + c->conf = pa_client_conf_new(); pa_client_conf_load(c->conf, NULL); #ifdef HAVE_X11 diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 16c3631f..7cb85209 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -78,6 +78,11 @@ #include "core-util.h" +/* Not all platforms have this */ +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif + #ifndef OS_IS_WIN32 #define PA_RUNTIME_PATH_PREFIX "/tmp/pulse-" #define PATH_SEP '/' -- cgit From f5afb7b6d06d78e63e714cbf3617b1bd372b2e7d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 17 Jul 2006 11:42:25 +0000 Subject: Forgot to protect one access to with_creds with an ifdef. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1098 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/pstream.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index e9b6f4c8..7992ccb6 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -291,7 +291,9 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa i->channel = channel; i->offset = offset; i->seek_mode = seek_mode; +#ifdef SCM_CREDENTIALS i->with_creds = 0; +#endif pa_memblock_ref(i->chunk.memblock); -- cgit From 64d87ac36329d76d220c437bf56c665f1f839ea5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 17 Jul 2006 21:20:31 +0000 Subject: change licensing blurb form "Library GPL" to "Lesser GPL" on request of Loic Minier. Effectively this means using the same license blurb like in all other source files. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1099 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/pipe.c | 32 ++++++++++++++++---------------- src/pulsecore/pipe.h | 32 ++++++++++++++++---------------- src/pulsecore/poll.c | 32 ++++++++++++++++++-------------- src/pulsecore/poll.h | 32 ++++++++++++++++++-------------- 4 files changed, 68 insertions(+), 60 deletions(-) diff --git a/src/pulsecore/pipe.c b/src/pulsecore/pipe.c index 6933e180..41ffb693 100644 --- a/src/pulsecore/pipe.c +++ b/src/pulsecore/pipe.c @@ -1,22 +1,22 @@ /* $Id$ */ /*** - This file is part of PulseAudio. - - PulseAudio is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with PulseAudio; If not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. ***/ #ifdef HAVE_CONFIG_H diff --git a/src/pulsecore/pipe.h b/src/pulsecore/pipe.h index a2514760..21049e17 100644 --- a/src/pulsecore/pipe.h +++ b/src/pulsecore/pipe.h @@ -4,22 +4,22 @@ /* $Id$ */ /*** - This file is part of PulseAudio. - - PulseAudio is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with PulseAudio; If not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. ***/ #ifndef HAVE_PIPE diff --git a/src/pulsecore/poll.c b/src/pulsecore/poll.c index 3f9ace7c..289e0cdf 100644 --- a/src/pulsecore/poll.c +++ b/src/pulsecore/poll.c @@ -5,21 +5,25 @@ Copyright (C) 2005, Cendio AB. This file is part of PulseAudio. Based on work for the GNU C Library. +***/ - PulseAudio is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with PulseAudio; If not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. ***/ /* Poll the file descriptors described by the NFDS structures starting at diff --git a/src/pulsecore/poll.h b/src/pulsecore/poll.h index bed772c7..c3d486e1 100644 --- a/src/pulsecore/poll.h +++ b/src/pulsecore/poll.h @@ -6,21 +6,25 @@ Copyright (C) 2005, Cendio AB. This file is part of PulseAudio. Based on work for the GNU C Library. +***/ - PulseAudio is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with PulseAudio; If not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. ***/ /* Event types that can be polled for. These bits may be set in `events' -- cgit From ddd5acf5535b3a97af56987bb26ce152bdd772a3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Jul 2006 18:51:35 +0000 Subject: define proper typdefs for callback prototypes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1100 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/mainloop-api.h | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/pulse/mainloop-api.h b/src/pulse/mainloop-api.h index 4aaeccf5..7b7075ae 100644 --- a/src/pulse/mainloop-api.h +++ b/src/pulse/mainloop-api.h @@ -44,6 +44,9 @@ PA_C_DECL_BEGIN +/** An abstract mainloop API vtable */ +typedef struct pa_mainloop_api pa_mainloop_api; + /** A bitmask for IO events */ typedef enum pa_io_event_flags { PA_IO_EVENT_NULL = 0, /**< No event */ @@ -55,15 +58,24 @@ typedef enum pa_io_event_flags { /** An opaque IO event source object */ typedef struct pa_io_event pa_io_event; - -/** An opaque deferred event source object. Events of this type are triggered once in every main loop iteration */ -typedef struct pa_defer_event pa_defer_event; +/** An IO event callback protoype \since 0.9.3 */ +typedef void (*pa_io_event_cb_t)(pa_mainloop_api*ea, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata); +/** A IO event destroy callback prototype \ since 0.9.3 */ +typedef void (*pa_io_event_destroy_cb_t)(pa_mainloop_api*a, pa_io_event *e, void *userdata); /** An opaque timer event source object */ typedef struct pa_time_event pa_time_event; +/** A time event callback prototype \since 0.9.3 */ +typedef void (*pa_time_event_cb_t)(pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata); +/** A time event destroy callback prototype \ since 0.9.3 */ +typedef void (*pa_time_event_destroy_cb_t)(pa_mainloop_api*a, pa_time_event *e, void *userdata); -/** An abstract mainloop API vtable */ -typedef struct pa_mainloop_api pa_mainloop_api; +/** An opaque deferred event source object. Events of this type are triggered once in every main loop iteration */ +typedef struct pa_defer_event pa_defer_event; +/** A defer event callback protoype \since 0.9.3 */ +typedef void (*pa_defer_event_cb_t)(pa_mainloop_api*a, pa_defer_event* e, void *userdata); +/** A defer event destroy callback prototype \ since 0.9.3 */ +typedef void (*pa_defer_event_destroy_cb_t)(pa_mainloop_api*a, pa_defer_event *e, void *userdata); /** An abstract mainloop API vtable */ struct pa_mainloop_api { @@ -71,40 +83,31 @@ struct pa_mainloop_api { void *userdata; /** Create a new IO event source object */ - pa_io_event* (*io_new)(pa_mainloop_api*a, int fd, pa_io_event_flags_t events, void (*callback) (pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata); - + pa_io_event* (*io_new)(pa_mainloop_api*a, int fd, pa_io_event_flags_t events, pa_io_event_cb_t cb, void *userdata); /** Enable or disable IO events on this object */ void (*io_enable)(pa_io_event* e, pa_io_event_flags_t events); - /** Free a IO event source object */ void (*io_free)(pa_io_event* e); - /** Set a function that is called when the IO event source is destroyed. Use this to free the userdata argument if required */ - void (*io_set_destroy)(pa_io_event *e, void (*callback) (pa_mainloop_api*a, pa_io_event *e, void *userdata)); + void (*io_set_destroy)(pa_io_event *e, pa_io_event_destroy_cb_t cb); /** Create a new timer event source object for the specified Unix time */ - pa_time_event* (*time_new)(pa_mainloop_api*a, const struct timeval *tv, void (*callback) (pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata), void *userdata); - + pa_time_event* (*time_new)(pa_mainloop_api*a, const struct timeval *tv, pa_time_event_cb_t cb, void *userdata); /** Restart a running or expired timer event source with a new Unix time */ void (*time_restart)(pa_time_event* e, const struct timeval *tv); - /** Free a deferred timer event source object */ void (*time_free)(pa_time_event* e); - /** Set a function that is called when the timer event source is destroyed. Use this to free the userdata argument if required */ - void (*time_set_destroy)(pa_time_event *e, void (*callback) (pa_mainloop_api*a, pa_time_event *e, void *userdata)); + void (*time_set_destroy)(pa_time_event *e, pa_time_event_destroy_cb_t cb); /** Create a new deferred event source object */ - pa_defer_event* (*defer_new)(pa_mainloop_api*a, void (*callback) (pa_mainloop_api*a, pa_defer_event* e, void *userdata), void *userdata); - + pa_defer_event* (*defer_new)(pa_mainloop_api*a, pa_defer_event_cb_t cb, void *userdata); /** Enable or disable a deferred event source temporarily */ void (*defer_enable)(pa_defer_event* e, int b); - /** Free a deferred event source object */ void (*defer_free)(pa_defer_event* e); - /** Set a function that is called when the deferred event source is destroyed. Use this to free the userdata argument if required */ - void (*defer_set_destroy)(pa_defer_event *e, void (*callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata)); + void (*defer_set_destroy)(pa_defer_event *e, pa_defer_event_destroy_cb_t cb); /** Exit the main loop and return the specfied retval*/ void (*quit)(pa_mainloop_api*a, int retval); -- cgit From 2c2abbb1698c6fa0607d4db2a20efce141a0f8c5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Jul 2006 18:52:13 +0000 Subject: turn the glib adapter into a single GSource instead of creating a bunch of seperate GSources for each event git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1101 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/glib-mainloop.c | 788 ++++++++++++++++++++++++++-------------------- 1 file changed, 444 insertions(+), 344 deletions(-) diff --git a/src/pulse/glib-mainloop.c b/src/pulse/glib-mainloop.c index 25848ece..cdaecdf8 100644 --- a/src/pulse/glib-mainloop.c +++ b/src/pulse/glib-mainloop.c @@ -30,363 +30,544 @@ #include #include +#include +#include -#include "glib.h" +#include #include "glib-mainloop.h" struct pa_io_event { pa_glib_mainloop *mainloop; int dead; - GIOChannel *io_channel; - GSource *source; - GIOCondition io_condition; - int fd; - void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); + + GPollFD poll_fd; + int poll_fd_added; + + pa_io_event_cb_t callback; void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_io_event *e, void *userdata); - pa_io_event *next, *prev; + pa_io_event_destroy_cb_t destroy_callback; + + PA_LLIST_FIELDS(pa_io_event); }; struct pa_time_event { pa_glib_mainloop *mainloop; int dead; - GSource *source; + + int enabled; struct timeval timeval; - void (*callback) (pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata); + + pa_time_event_cb_t callback; void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_time_event*e, void *userdata); - pa_time_event *next, *prev; + pa_time_event_destroy_cb_t destroy_callback; + + PA_LLIST_FIELDS(pa_time_event); }; struct pa_defer_event { pa_glib_mainloop *mainloop; int dead; - GSource *source; - void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata); + + int enabled; + + pa_defer_event_cb_t callback; void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_defer_event*e, void *userdata); - pa_defer_event *next, *prev; + pa_defer_event_destroy_cb_t destroy_callback; + + PA_LLIST_FIELDS(pa_defer_event); }; struct pa_glib_mainloop { - GMainContext *glib_main_context; + GSource source; + pa_mainloop_api api; - GSource *cleanup_source; - pa_io_event *io_events, *dead_io_events; - pa_time_event *time_events, *dead_time_events; - pa_defer_event *defer_events, *dead_defer_events; -}; + GMainContext *context; -static void schedule_free_dead_events(pa_glib_mainloop *g); + PA_LLIST_HEAD(pa_io_event, io_events); + PA_LLIST_HEAD(pa_time_event, time_events); + PA_LLIST_HEAD(pa_defer_event, defer_events); -static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f); + int n_enabled_defer_events, n_enabled_time_events; + int io_events_please_scan, time_events_please_scan, defer_events_please_scan; -static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags_t f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata), void *userdata) { - pa_io_event *e; - pa_glib_mainloop *g; + pa_time_event *cached_next_time_event; +}; - assert(m && m->userdata && fd >= 0 && callback); - g = m->userdata; +static void cleanup_io_events(pa_glib_mainloop *g, int force) { + pa_io_event *e; - e = pa_xmalloc(sizeof(pa_io_event)); - e->mainloop = m->userdata; - e->dead = 0; - e->fd = fd; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; + e = g->io_events; + while (e) { + pa_io_event *n = e->next; - e->io_channel = g_io_channel_unix_new(e->fd); - assert(e->io_channel); - e->source = NULL; - e->io_condition = 0; + if (!force && g->io_events_please_scan <= 0) + break; + + if (force || e->dead) { + PA_LLIST_REMOVE(pa_io_event, g->io_events, e); + + if (e->dead) + g->io_events_please_scan--; + + if (e->poll_fd_added) + g_source_remove_poll(&g->source, &e->poll_fd); + + if (e->destroy_callback) + e->destroy_callback(&g->api, e, e->userdata); + + pa_xfree(e); + } - glib_io_enable(e, f); + e = n; + } - e->next = g->io_events; - if (e->next) e->next->prev = e; - g->io_events = e; - e->prev = NULL; - - return e; + assert(g->io_events_please_scan == 0); } -/* The callback GLIB calls whenever an IO condition is met */ -static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { - pa_io_event *e = data; - pa_io_event_flags_t f; - assert(source && e && e->io_channel == source); +static void cleanup_time_events(pa_glib_mainloop *g, int force) { + pa_time_event *e; - f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | - (condition & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) | - (condition & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) | - (condition & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0); - - e->callback(&e->mainloop->api, e, e->fd, f, e->userdata); - return TRUE; -} + e = g->time_events; + while (e) { + pa_time_event *n = e->next; -static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { - GIOCondition c; - assert(e && !e->dead); + if (!force && g->time_events_please_scan <= 0) + break; + + if (force || e->dead) { + PA_LLIST_REMOVE(pa_time_event, g->time_events, e); + + if (e->dead) + g->time_events_please_scan--; + + if (!e->dead && e->enabled) + g->n_enabled_time_events--; + + if (e->destroy_callback) + e->destroy_callback(&g->api, e, e->userdata); + + pa_xfree(e); + } - c = (f & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | (f & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0); - - if (c == e->io_condition) - return; - - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); + e = n; } - - e->source = g_io_create_watch(e->io_channel, c | G_IO_ERR | G_IO_HUP); - assert(e->source); - - g_source_set_callback(e->source, (GSourceFunc) io_cb, e, NULL); - g_source_attach(e->source, e->mainloop->glib_main_context); - g_source_set_priority(e->source, G_PRIORITY_DEFAULT); - - e->io_condition = c; -} -static void glib_io_free(pa_io_event*e) { - assert(e && !e->dead); + assert(g->time_events_please_scan == 0); +} - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); - e->source = NULL; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->io_events = e->next; +static void cleanup_defer_events(pa_glib_mainloop *g, int force) { + pa_defer_event *e; - if (e->next) - e->next->prev = e->prev; + e = g->defer_events; + while (e) { + pa_defer_event *n = e->next; - if ((e->next = e->mainloop->dead_io_events)) - e->next->prev = e; + if (!force && g->defer_events_please_scan <= 0) + break; + + if (force || e->dead) { + PA_LLIST_REMOVE(pa_defer_event, g->defer_events, e); + + if (e->dead) + g->defer_events_please_scan--; + + if (!e->dead && e->enabled) + g->n_enabled_defer_events--; + + if (e->destroy_callback) + e->destroy_callback(&g->api, e, e->userdata); + + pa_xfree(e); + } - e->mainloop->dead_io_events = e; - e->prev = NULL; + e = n; + } - e->dead = 1; - schedule_free_dead_events(e->mainloop); + assert(g->defer_events_please_scan == 0); } -static void glib_io_set_destroy(pa_io_event*e, void (*callback)(pa_mainloop_api*m, pa_io_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; +static gushort map_flags_to_glib(pa_io_event_flags_t flags) { + return + (flags & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | + (flags & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0) | + (flags & PA_IO_EVENT_ERROR ? G_IO_ERR : 0) | + (flags & PA_IO_EVENT_HANGUP ? G_IO_HUP : 0); } -/* Time sources */ - -static void glib_time_restart(pa_time_event*e, const struct timeval *tv); +static pa_io_event_flags_t map_flags_from_glib(gushort flags) { + return + (flags & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | + (flags & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) | + (flags & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) | + (flags & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0); +} -static pa_time_event* glib_time_new(pa_mainloop_api*m, const struct timeval *tv, void (*callback) (pa_mainloop_api*m, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { +static pa_io_event* glib_io_new( + pa_mainloop_api*m, + int fd, + pa_io_event_flags_t f, + pa_io_event_cb_t cb, + void *userdata) { + + pa_io_event *e; pa_glib_mainloop *g; - pa_time_event *e; + + assert(m); + assert(m->userdata); + assert(fd >= 0); + assert(cb); - assert(m && m->userdata && tv && callback); g = m->userdata; - e = pa_xmalloc(sizeof(pa_time_event)); + e = pa_xnew(pa_io_event, 1); e->mainloop = g; e->dead = 0; - e->callback = callback; + + e->poll_fd.fd = fd; + e->poll_fd.events = map_flags_to_glib(f); + e->poll_fd.revents = 0; + + e->callback = cb; e->userdata = userdata; e->destroy_callback = NULL; - e->source = NULL; - glib_time_restart(e, tv); + PA_LLIST_PREPEND(pa_io_event, g->io_events, e); - e->next = g->time_events; - if (e->next) e->next->prev = e; - g->time_events = e; - e->prev = NULL; + g_source_add_poll(&g->source, &e->poll_fd); + e->poll_fd_added = 1; return e; } -static guint msec_diff(const struct timeval *a, const struct timeval *b) { - guint r; - assert(a && b); - - if (a->tv_sec < b->tv_sec) - return 0; +static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { + assert(e); + assert(!e->dead); - if (a->tv_sec == b->tv_sec && a->tv_sec <= b->tv_sec) - return 0; + e->poll_fd.events = map_flags_to_glib(f); +} - r = (a->tv_sec-b->tv_sec)*1000; +static void glib_io_free(pa_io_event*e) { + assert(e); + assert(!e->dead); - if (a->tv_usec >= b->tv_usec) - r += (a->tv_usec - b->tv_usec) / 1000; - else - r -= (b->tv_usec - a->tv_usec) / 1000; + e->dead = 1; + e->mainloop->io_events_please_scan++; + + if (e->poll_fd_added) { + g_source_remove_poll(&e->mainloop->source, &e->poll_fd); + e->poll_fd_added = 0; + } +} + +static void glib_io_set_destroy(pa_io_event*e, pa_io_event_destroy_cb_t cb) { + assert(e); + assert(!e->dead); - return r; + e->destroy_callback = cb; } -static gboolean time_cb(gpointer data) { - pa_time_event* e = data; - assert(e && e->mainloop && e->source); +/* Time sources */ - g_source_unref(e->source); - e->source = NULL; +static pa_time_event* glib_time_new( + pa_mainloop_api*m, + const struct timeval *tv, + pa_time_event_cb_t cb, + void *userdata) { + + pa_glib_mainloop *g; + pa_time_event *e; + + assert(m); + assert(m->userdata); + assert(cb); + + g = m->userdata; - e->callback(&e->mainloop->api, e, &e->timeval, e->userdata); - return FALSE; -} + e = pa_xnew(pa_time_event, 1); + e->mainloop = g; + e->dead = 0; -static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { - struct timeval now; - assert(e && e->mainloop && !e->dead); + if ((e->enabled = !!tv)) { + e->timeval = *tv; + g->n_enabled_time_events++; - pa_gettimeofday(&now); - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); + if (g->cached_next_time_event) { + g_assert(g->cached_next_time_event->enabled); + + if (pa_timeval_cmp(tv, &g->cached_next_time_event->timeval) < 0) + g->cached_next_time_event = e; + } } + + e->callback = cb; + e->userdata = userdata; + e->destroy_callback = NULL; - if (tv) { - e->timeval = *tv; - e->source = g_timeout_source_new(msec_diff(tv, &now)); - assert(e->source); - g_source_set_callback(e->source, time_cb, e, NULL); - g_source_set_priority(e->source, G_PRIORITY_DEFAULT); - g_source_attach(e->source, e->mainloop->glib_main_context); - } else - e->source = NULL; - } + PA_LLIST_PREPEND(pa_time_event, g->time_events, e); + + return e; +} -static void glib_time_free(pa_time_event *e) { - assert(e && e->mainloop && !e->dead); +static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { + assert(e); + assert(!e->dead); - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); - e->source = NULL; - } + if (e->enabled && !!tv) + e->mainloop->n_enabled_time_events--; + else if (!e->enabled && tv) + e->mainloop->n_enabled_time_events++; - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->time_events = e->next; + if ((e->enabled = !!tv)) + e->timeval = *tv; - if (e->next) - e->next->prev = e->prev; + if (e->mainloop->cached_next_time_event && e->enabled) { + g_assert(e->mainloop->cached_next_time_event->enabled); - if ((e->next = e->mainloop->dead_time_events)) - e->next->prev = e; + if (pa_timeval_cmp(tv, &e->mainloop->cached_next_time_event->timeval) < 0) + e->mainloop->cached_next_time_event = e; + } else if (e->mainloop->cached_next_time_event == e) + e->mainloop->cached_next_time_event = NULL; + } - e->mainloop->dead_time_events = e; - e->prev = NULL; +static void glib_time_free(pa_time_event *e) { + assert(e); + assert(!e->dead); e->dead = 1; - schedule_free_dead_events(e->mainloop); + e->mainloop->time_events_please_scan++; + + if (e->enabled) + e->mainloop->n_enabled_time_events--; + + if (e->mainloop->cached_next_time_event == e) + e->mainloop->cached_next_time_event = NULL; } -static void glib_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*m, pa_time_event*e, void *userdata)) { +static void glib_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t cb) { assert(e); - e->destroy_callback = callback; + assert(!e->dead); + + e->destroy_callback = cb; } /* Deferred sources */ -static void glib_defer_enable(pa_defer_event *e, int b); - -static pa_defer_event* glib_defer_new(pa_mainloop_api*m, void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata), void *userdata) { +static pa_defer_event* glib_defer_new( + pa_mainloop_api*m, + pa_defer_event_cb_t cb, + void *userdata) { + pa_defer_event *e; pa_glib_mainloop *g; - assert(m && m->userdata && callback); + assert(m); + assert(m->userdata); + assert(cb); + g = m->userdata; - e = pa_xmalloc(sizeof(pa_defer_event)); + e = pa_xnew(pa_defer_event, 1); e->mainloop = g; e->dead = 0; - e->callback = callback; + + e->enabled = 1; + g->n_enabled_defer_events++; + + e->callback = cb; e->userdata = userdata; e->destroy_callback = NULL; - e->source = NULL; + + PA_LLIST_PREPEND(pa_defer_event, g->defer_events, e); + return e; +} + +static void glib_defer_enable(pa_defer_event *e, int b) { + assert(e); + assert(!e->dead); - glib_defer_enable(e, 1); + if (e->enabled && !b) + e->mainloop->n_enabled_defer_events--; + else if (!e->enabled && b) + e->mainloop->n_enabled_defer_events++; - e->next = g->defer_events; - if (e->next) e->next->prev = e; - g->defer_events = e; - e->prev = NULL; - return e; + e->enabled = b; } -static gboolean idle_cb(gpointer data) { - pa_defer_event* e = data; - assert(e && e->mainloop && e->source); +static void glib_defer_free(pa_defer_event *e) { + assert(e); + assert(!e->dead); + + e->dead = 1; + e->mainloop->defer_events_please_scan++; - e->callback(&e->mainloop->api, e, e->userdata); - return TRUE; + if (e->enabled) + e->mainloop->n_enabled_defer_events--; } -static void glib_defer_enable(pa_defer_event *e, int b) { - assert(e && e->mainloop); - - if (e->source && !b) { - g_source_destroy(e->source); - g_source_unref(e->source); - e->source = NULL; - } else if (!e->source && b) { - e->source = g_idle_source_new(); - assert(e->source); - g_source_set_callback(e->source, idle_cb, e, NULL); - g_source_attach(e->source, e->mainloop->glib_main_context); - g_source_set_priority(e->source, G_PRIORITY_HIGH); - } +static void glib_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t cb) { + assert(e); + assert(!e->dead); + + e->destroy_callback = cb; } -static void glib_defer_free(pa_defer_event *e) { - assert(e && e->mainloop && !e->dead); +/* quit() */ + +static void glib_quit(pa_mainloop_api*a, PA_GCC_UNUSED int retval) { - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); - e->source = NULL; + g_warning("quit() ignored"); + + /* NOOP */ +} + +static pa_time_event* find_next_time_event(pa_glib_mainloop *g) { + pa_time_event *t, *n = NULL; + assert(g); + + if (g->cached_next_time_event) + return g->cached_next_time_event; + + for (t = g->time_events; t; t = t->next) { + + if (t->dead || !t->enabled) + continue; + + if (!n || pa_timeval_cmp(&t->timeval, &n->timeval) < 0) { + n = t; + + /* Shortcut for tv = { 0, 0 } */ + if (n->timeval.tv_sec <= 0) + break; + } } - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->defer_events = e->next; + g->cached_next_time_event = n; + return n; +} - if (e->next) - e->next->prev = e->prev; +static gboolean prepare_func(GSource *source, gint *timeout) { + pa_glib_mainloop *g = (pa_glib_mainloop*) source; - if ((e->next = e->mainloop->dead_defer_events)) - e->next->prev = e; + g_assert(g); + g_assert(timeout); - e->mainloop->dead_defer_events = e; - e->prev = NULL; + if (g->io_events_please_scan) + cleanup_io_events(g, 0); - e->dead = 1; - schedule_free_dead_events(e->mainloop); + if (g->time_events_please_scan) + cleanup_time_events(g, 0); + + if (g->defer_events_please_scan) + cleanup_defer_events(g, 0); + + if (g->n_enabled_defer_events) { + *timeout = 0; + return TRUE; + } else if (g->n_enabled_time_events) { + pa_time_event *t; + GTimeVal now; + struct timeval tvnow; + pa_usec_t usec; + + t = find_next_time_event(g); + g_assert(t); + + g_source_get_current_time(source, &now); + tvnow.tv_sec = now.tv_sec; + tvnow.tv_usec = now.tv_usec; + + usec = pa_timeval_diff(&t->timeval, &tvnow); + + if (usec <= 0) { + *timeout = 0; + return TRUE; + } + + *timeout = (gint) (usec / 1000); + } else + *timeout = -1; + + return FALSE; } +static gboolean check_func(GSource *source) { + pa_glib_mainloop *g = (pa_glib_mainloop*) source; + pa_io_event *e; -static void glib_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api *m, pa_defer_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; + g_assert(g); + + if (g->n_enabled_defer_events) + return TRUE; + else if (g->n_enabled_time_events) { + pa_time_event *t; + GTimeVal now; + struct timeval tvnow; + + t = find_next_time_event(g); + g_assert(t); + + g_source_get_current_time(source, &now); + tvnow.tv_sec = now.tv_sec; + tvnow.tv_usec = now.tv_usec; + + if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) + return TRUE; + } + + for (e = g->io_events; e; e = e->next) + if (!e->dead && e->poll_fd.revents != 0) + return TRUE; + + return FALSE; } -/* quit() */ +static gboolean dispatch_func(GSource *source, PA_GCC_UNUSED GSourceFunc callback, PA_GCC_UNUSED gpointer userdata) { + pa_glib_mainloop *g = (pa_glib_mainloop*) source; + pa_io_event *e; -static void glib_quit(pa_mainloop_api*a, PA_GCC_UNUSED int retval) { - pa_glib_mainloop *g; - assert(a && a->userdata); - g = a->userdata; + g_assert(g); - /* NOOP */ + if (g->n_enabled_defer_events) { + pa_defer_event *d; + + for (d = g->defer_events; d; d = d->next) { + if (d->dead || !d->enabled) + continue; + + break; + } + + assert(d); + + d->callback(&g->api, d, d->userdata); + return TRUE; + } + + if (g->n_enabled_time_events) { + GTimeVal now; + struct timeval tvnow; + pa_time_event *t; + + t = find_next_time_event(g); + g_assert(t); + + g_source_get_current_time(source, &now); + tvnow.tv_sec = now.tv_sec; + tvnow.tv_usec = now.tv_usec; + + if (pa_timeval_cmp(&t->timeval, &tvnow) < 0) { + t->callback(&g->api, t, &t->timeval, t->userdata); + return TRUE; + } + } + + for (e = g->io_events; e; e = e->next) + if (!e->dead && e->poll_fd.revents != 0) { + e->callback(&g->api, e, e->poll_fd.fd, map_flags_from_glib(e->poll_fd.revents), e->userdata); + e->poll_fd.revents = 0; + return TRUE; + } + + return FALSE; } static const pa_mainloop_api vtable = { @@ -412,130 +593,49 @@ static const pa_mainloop_api vtable = { pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) { pa_glib_mainloop *g; + + static GSourceFuncs source_funcs = { + prepare_func, + check_func, + dispatch_func, + NULL, + NULL, + NULL + }; - g = pa_xmalloc(sizeof(pa_glib_mainloop)); - if (c) { - g->glib_main_context = c; - g_main_context_ref(c); - } else - g->glib_main_context = g_main_context_default(); + g = (pa_glib_mainloop*) g_source_new(&source_funcs, sizeof(pa_glib_mainloop)); + g_main_context_ref(g->context = c ? c : g_main_context_default()); g->api = vtable; g->api.userdata = g; - g->io_events = g->dead_io_events = NULL; - g->time_events = g->dead_time_events = NULL; - g->defer_events = g->dead_defer_events = NULL; + PA_LLIST_HEAD_INIT(pa_io_event, g->io_events); + PA_LLIST_HEAD_INIT(pa_time_event, g->time_events); + PA_LLIST_HEAD_INIT(pa_defer_event, g->defer_events); - g->cleanup_source = NULL; + g->n_enabled_defer_events = g->n_enabled_time_events = 0; + g->io_events_please_scan = g->time_events_please_scan = g->defer_events_please_scan = 0; + + g_source_attach(&g->source, g->context); + g_source_set_can_recurse(&g->source, FALSE); + return g; } -static void free_io_events(pa_io_event *e) { - while (e) { - pa_io_event *r = e; - e = r->next; - - if (r->source) { - g_source_destroy(r->source); - g_source_unref(r->source); - } - - if (r->io_channel) - g_io_channel_unref(r->io_channel); - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -static void free_time_events(pa_time_event *e) { - while (e) { - pa_time_event *r = e; - e = r->next; - - if (r->source) { - g_source_destroy(r->source); - g_source_unref(r->source); - } - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -static void free_defer_events(pa_defer_event *e) { - while (e) { - pa_defer_event *r = e; - e = r->next; - - if (r->source) { - g_source_destroy(r->source); - g_source_unref(r->source); - } - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - void pa_glib_mainloop_free(pa_glib_mainloop* g) { assert(g); - free_io_events(g->io_events); - free_io_events(g->dead_io_events); - free_defer_events(g->defer_events); - free_defer_events(g->dead_defer_events); - free_time_events(g->time_events); - free_time_events(g->dead_time_events); - - if (g->cleanup_source) { - g_source_destroy(g->cleanup_source); - g_source_unref(g->cleanup_source); - } + cleanup_io_events(g, 1); + cleanup_defer_events(g, 1); + cleanup_time_events(g, 1); - g_main_context_unref(g->glib_main_context); - pa_xfree(g); + g_main_context_unref(g->context); + g_source_destroy(&g->source); + g_source_unref(&g->source); } pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) { assert(g); - return &g->api; -} - -static gboolean free_dead_events(gpointer p) { - pa_glib_mainloop *g = p; - assert(g); - - free_io_events(g->dead_io_events); - free_defer_events(g->dead_defer_events); - free_time_events(g->dead_time_events); - - g->dead_io_events = NULL; - g->dead_defer_events = NULL; - g->dead_time_events = NULL; - - g_source_destroy(g->cleanup_source); - g_source_unref(g->cleanup_source); - g->cleanup_source = NULL; - - return FALSE; -} - -static void schedule_free_dead_events(pa_glib_mainloop *g) { - assert(g && g->glib_main_context); - - if (g->cleanup_source) - return; - g->cleanup_source = g_idle_source_new(); - assert(g->cleanup_source); - g_source_set_callback(g->cleanup_source, free_dead_events, g, NULL); - g_source_attach(g->cleanup_source, g->glib_main_context); + return &g->api; } -- cgit From f4ec7d47fd15465b86056266983f8d15ce5b8d68 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Jul 2006 19:19:52 +0000 Subject: fix module-detect on FreeBSD (patch from Diego "Flameeyes" Pettenó) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1102 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-detect.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index 3e4d2bf6..ebafa10d 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -135,23 +135,29 @@ static int detect_oss(pa_core *c, int just_one) { line[strcspn(line, "\r\n")] = 0; if (!b) { - b = strcmp(line, "Audio devices:") == 0; + b = strcmp(line, "Audio devices:") == 0 || strcmp(line, "Installed devices:") == 0; continue; } if (line[0] == 0) break; - if (sscanf(line, "%u: ", &device) != 1) - continue; - - if (device == 0) - snprintf(args, sizeof(args), "device=/dev/dsp"); - else - snprintf(args, sizeof(args), "device=/dev/dsp%u", device); - - if (!pa_module_load(c, "module-oss", args)) - continue; + if (sscanf(line, "%u: ", &device) == 1) { + if (device == 0) + snprintf(args, sizeof(args), "device=/dev/dsp"); + else + snprintf(args, sizeof(args), "device=/dev/dsp%u", device); + + if (!pa_module_load(c, "module-oss", args)) + continue; + + } else if (sscanf(line, "pcm%u: ", &device) == 1) { + /* FreeBSD support, the devices are named /dev/dsp0.0, dsp0.1 and so on */ + snprintf(args, sizeof(args), "device=/dev/dsp%u.0", device); + + if (!pa_module_load(c, "module-oss", args)) + continue; + } n++; -- cgit From d7cdaf22a199e4b6710e6912b0378f0c919ff4d1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Jul 2006 19:50:09 +0000 Subject: add two more \since git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1103 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/def.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pulse/def.h b/src/pulse/def.h index 06d4c7c2..01ed0f6d 100644 --- a/src/pulse/def.h +++ b/src/pulse/def.h @@ -296,14 +296,14 @@ typedef enum pa_seek_mode { typedef enum pa_sink_flags { PA_SINK_HW_VOLUME_CTRL = 1, /**< Supports hardware volume control */ PA_SINK_LATENCY = 2, /**< Supports latency querying */ - PA_SINK_HARDWARE = 4 /**< Is a hardware sink of some kind, in contrast to "virtual"/software sinks */ + PA_SINK_HARDWARE = 4 /**< Is a hardware sink of some kind, in contrast to "virtual"/software sinks \since 0.9.3 */ } pa_sink_flags_t; /** Special source flags. \since 0.8 */ typedef enum pa_source_flags { PA_SOURCE_HW_VOLUME_CTRL = 1, /**< Supports hardware volume control */ PA_SOURCE_LATENCY = 2, /**< Supports latency querying */ - PA_SOURCE_HARDWARE = 4 /**< Is a hardware source of some kind, in contrast to "virtual"/software source */ + PA_SOURCE_HARDWARE = 4 /**< Is a hardware source of some kind, in contrast to "virtual"/software source \since 0.9.3 */ } pa_source_flags_t; /** A generic free() like callback prototype */ -- cgit From 9db70682d68cc4fef9314677b6427582e5d5c8f2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Jul 2006 19:53:29 +0000 Subject: remove glib 1.2 adapter. It started to bitrot and wasn't used by anything anyway. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1104 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 5 - configure.ac | 56 +---- libpulse-mainloop-glib12.pc.in | 11 - src/Makefile.am | 25 -- src/pulse/glib-mainloop.h | 6 +- src/pulse/glib12-mainloop.c | 503 ----------------------------------------- src/tests/mainloop-test.c | 26 +-- 7 files changed, 12 insertions(+), 620 deletions(-) delete mode 100644 libpulse-mainloop-glib12.pc.in delete mode 100644 src/pulse/glib12-mainloop.c diff --git a/Makefile.am b/Makefile.am index 8aa609f6..1b77187d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -36,11 +36,6 @@ pkgconfig_DATA += \ libpulse-mainloop-glib.pc endif -if HAVE_GLIB12 -pkgconfig_DATA += \ - libpulse-mainloop-glib12.pc -endif - homepage: all dist doxygen test -d $$HOME/homepage/private mkdir -p $$HOME/homepage/private/projects/pulseaudio $$HOME/homepage/private/projects/pulseaudio/doxygen diff --git a/configure.ac b/configure.ac index 80473415..cf7b5534 100644 --- a/configure.ac +++ b/configure.ac @@ -449,37 +449,6 @@ AC_SUBST(GLIB20_LIBS) AC_SUBST(HAVE_GLIB20) AM_CONDITIONAL([HAVE_GLIB20], [test "x$HAVE_GLIB20" = x1]) -#### GLib 1 support (optional) #### - -AC_ARG_ENABLE([glib1], - AC_HELP_STRING([--disable-glib1], [Disable optional GLib 1 support]), - [ - case "${enableval}" in - yes) glib1=yes ;; - no) glib1=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --disable-glib1) ;; - esac - ], - [glib1=auto]) - -if test "x${glib1}" != xno ; then - PKG_CHECK_MODULES(GLIB12, [ glib >= 1.2.0 ], - HAVE_GLIB12=1, - [ - HAVE_GLIB12=0 - if test "x$glib1" = xyes ; then - AC_MSG_ERROR([*** GLib 1 support not found]) - fi - ]) -else - HAVE_GLIB12=0 -fi - -AC_SUBST(GLIB12_CFLAGS) -AC_SUBST(GLIB12_LIBS) -AC_SUBST(HAVE_GLIB12) -AM_CONDITIONAL([HAVE_GLIB12], [test "x$HAVE_GLIB12" = x1]) - #### Avahi support (optional) #### AC_ARG_ENABLE([avahi], @@ -677,7 +646,6 @@ libpulse.pc libpulse-simple.pc libpulse-browse.pc libpulse-mainloop-glib.pc -libpulse-mainloop-glib12.pc doxygen/Makefile doxygen/doxygen.conf src/pulse/version.h @@ -710,11 +678,6 @@ if test "x$HAVE_GLIB20" = "x1" ; then ENABLE_GLIB20=yes fi -ENABLE_GLIB12=no -if test "x$HAVE_GLIB12" = "x1" ; then - ENABLE_GLIB12=yes -fi - ENABLE_AVAHI=no if test "x$HAVE_AVAHI" = "x1" ; then ENABLE_AVAHI=yes @@ -748,15 +711,14 @@ echo " localstatedir: ${localstatedir} compiler: ${CC} cflags: ${CFLAGS} - Have X11: ${ENABLE_X11} - Enable OSS: ${ENABLE_OSS} - Enable Alsa: ${ENABLE_ALSA} - Enable Solaris: ${ENABLE_SOLARIS} - Enable Glib 2.0: ${ENABLE_GLIB20} - Enable Glib 1.2: ${ENABLE_GLIB12} - Enable Avahi: ${ENABLE_AVAHI} - Enable Jack: ${ENABLE_JACK} - Enable Async DNS: ${ENABLE_LIBASYNCNS} - Enable LIRC: ${ENABLE_LIRC} + Have X11: ${ENABLE_X11} + Enable OSS: ${ENABLE_OSS} + Enable Alsa: ${ENABLE_ALSA} + Enable Solaris: ${ENABLE_SOLARIS} + Enable Glib 2.0: ${ENABLE_GLIB20} + Enable Avahi: ${ENABLE_AVAHI} + Enable Jack: ${ENABLE_JACK} + Enable Async DNS: ${ENABLE_LIBASYNCNS} + Enable LIRC: ${ENABLE_LIRC} Enable TCP Wrappers: ${ENABLE_TCPWRAP} " diff --git a/libpulse-mainloop-glib12.pc.in b/libpulse-mainloop-glib12.pc.in deleted file mode 100644 index 7a038826..00000000 --- a/libpulse-mainloop-glib12.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: libpulse-mainloop-glib12 -Description: GLIB 1.2 Main Loop Wrapper for PulseAudio -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpulse-mainloop-glib12 -Cflags: -D_REENTRANT -I${includedir} -Requires: libpulse glib diff --git a/src/Makefile.am b/src/Makefile.am index 8da51aac..0235741b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -207,11 +207,6 @@ noinst_PROGRAMS += \ mainloop-test-glib endif -if HAVE_GLIB12 -noinst_PROGRAMS += \ - mainloop-test-glib12 -endif - mainloop_test_SOURCES = tests/mainloop-test.c mainloop_test_CFLAGS = $(AM_CFLAGS) mainloop_test_LDADD = $(AM_LDADD) libpulse.la @@ -277,11 +272,6 @@ mainloop_test_glib_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB20_CFLAGS) -DGLIB_MAIN mainloop_test_glib_LDADD = $(mainloop_test_LDADD) $(GLIB20_LIBS) libpulse-mainloop-glib.la mainloop_test_glib_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -mainloop_test_glib12_SOURCES = $(mainloop_test_SOURCES) -mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MAIN_LOOP -mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpulse-mainloop-glib12.la -mainloop_test_glib12_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) - memblockq_test_SOURCES = tests/memblockq-test.c memblockq_test_CFLAGS = $(AM_CFLAGS) memblockq_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpulsecore.la @@ -334,11 +324,6 @@ endif if HAVE_GLIB20 pulseinclude_HEADERS += \ pulse/glib-mainloop.h -else -if HAVE_GLIB12 -pulseinclude_HEADERS += \ - pulse/glib-mainloop.h -endif endif lib_LTLIBRARIES = \ @@ -355,11 +340,6 @@ lib_LTLIBRARIES += \ libpulse-mainloop-glib.la endif -if HAVE_GLIB12 -lib_LTLIBRARIES += \ - libpulse-mainloop-glib12.la -endif - # Public interface libpulse_la_SOURCES = \ pulse/cdecl.h \ @@ -461,11 +441,6 @@ libpulse_mainloop_glib_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) libpulse_mainloop_glib_la_LIBADD = $(AM_LIBADD) libpulse.la $(GLIB20_LIBS) libpulse_mainloop_glib_la_LDFLAGS = -version-info $(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO) -libpulse_mainloop_glib12_la_SOURCES = pulse/glib-mainloop.h pulse/glib12-mainloop.c -libpulse_mainloop_glib12_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS) -libpulse_mainloop_glib12_la_LIBADD = $(AM_LIBADD) libpulse.la $(GLIB12_LIBS) -libpulse_mainloop_glib12_la_LDFLAGS = -version-info $(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO) - ################################### # OSS emulation # ################################### diff --git a/src/pulse/glib-mainloop.h b/src/pulse/glib-mainloop.h index 75de1cc7..af7cc0e9 100644 --- a/src/pulse/glib-mainloop.h +++ b/src/pulse/glib-mainloop.h @@ -47,13 +47,9 @@ PA_C_DECL_BEGIN typedef struct pa_glib_mainloop pa_glib_mainloop; /** Create a new GLIB main loop object for the specified GLIB main - * loop context. The GLIB 2.0 version takes an argument c for the + * loop context. Takes an argument c for the * GMainContext to use. If c is NULL the default context is used. */ -#if GLIB_MAJOR_VERSION >= 2 pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c); -#else -pa_glib_mainloop *pa_glib_mainloop_new(void); -#endif /** Free the GLIB main loop object */ void pa_glib_mainloop_free(pa_glib_mainloop* g); diff --git a/src/pulse/glib12-mainloop.c b/src/pulse/glib12-mainloop.c deleted file mode 100644 index ebaf87fc..00000000 --- a/src/pulse/glib12-mainloop.c +++ /dev/null @@ -1,503 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of PulseAudio. - - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PulseAudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include -#include - -#include -#include - -#include "glib-mainloop.h" - -/* A mainloop implementation based on GLIB 1.2 */ - -struct pa_io_event { - pa_glib_mainloop *mainloop; - int dead; - GIOChannel *io_channel; - guint source; - GIOCondition io_condition; - int fd; - void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_io_event*e, void *userdata); - pa_io_event *next, *prev; -}; - -struct pa_time_event { - pa_glib_mainloop *mainloop; - int dead; - guint source; - struct timeval timeval; - void (*callback) (pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_time_event*e, void *userdata); - pa_time_event *next, *prev; -}; - -struct pa_defer_event { - pa_glib_mainloop *mainloop; - int dead; - guint source; - void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_defer_event*e, void *userdata); - pa_defer_event *next, *prev; -}; - -struct pa_glib_mainloop { - pa_mainloop_api api; - guint cleanup_source; - pa_io_event *io_events, *dead_io_events; - pa_time_event *time_events, *dead_time_events; - pa_defer_event *defer_events, *dead_defer_events; -}; - -static void schedule_free_dead_events(pa_glib_mainloop *g); - -static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f); - -static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags_t f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata), void *userdata) { - pa_io_event *e; - pa_glib_mainloop *g; - - assert(m && m->userdata && fd >= 0 && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_io_event)); - e->mainloop = m->userdata; - e->dead = 0; - e->fd = fd; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - - e->io_channel = g_io_channel_unix_new(e->fd); - assert(e->io_channel); - e->source = (guint) -1; - e->io_condition = 0; - - glib_io_enable(e, f); - - e->next = g->io_events; - if (e->next) e->next->prev = e; - g->io_events = e; - e->prev = NULL; - - return e; -} - -static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { - pa_io_event *e = data; - pa_io_event_flags_t f; - assert(source && e && e->io_channel == source); - - f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | - (condition & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) | - (condition & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) | - (condition & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0); - - e->callback(&e->mainloop->api, e, e->fd, f, e->userdata); - return TRUE; -} - -static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { - GIOCondition c; - assert(e && !e->dead); - - c = (f & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | (f & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0); - - if (c == e->io_condition) - return; - - if (e->source != (guint) -1) - g_source_remove(e->source); - - e->source = g_io_add_watch_full(e->io_channel, G_PRIORITY_DEFAULT, c | G_IO_ERR | G_IO_HUP, io_cb, e, NULL); - assert(e->source != (guint) -1); - e->io_condition = c; -} - -static void glib_io_free(pa_io_event*e) { - assert(e && !e->dead); - - if (e->source != (guint) -1) { - g_source_remove(e->source); - e->source = (guint) -1; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->io_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_io_events)) - e->next->prev = e; - - e->mainloop->dead_io_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_io_set_destroy(pa_io_event*e, void (*callback)(pa_mainloop_api*m, pa_io_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Time sources */ - -static void glib_time_restart(pa_time_event*e, const struct timeval *tv); - -static pa_time_event* glib_time_new(pa_mainloop_api*m, const struct timeval *tv, void (*callback) (pa_mainloop_api*m, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { - pa_glib_mainloop *g; - pa_time_event *e; - - assert(m && m->userdata && tv && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_time_event)); - e->mainloop = g; - e->dead = 0; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - e->source = (guint) -1; - - glib_time_restart(e, tv); - - e->next = g->time_events; - if (e->next) e->next->prev = e; - g->time_events = e; - e->prev = NULL; - - return e; -} - -static guint msec_diff(const struct timeval *a, const struct timeval *b) { - guint r; - assert(a && b); - - if (a->tv_sec < b->tv_sec) - return 0; - - if (a->tv_sec == b->tv_sec && a->tv_sec <= b->tv_sec) - return 0; - - r = (a->tv_sec-b->tv_sec)*1000; - - if (a->tv_usec >= b->tv_usec) - r += (a->tv_usec - b->tv_usec) / 1000; - else - r -= (b->tv_usec - a->tv_usec) / 1000; - - return r; -} - -static gboolean time_cb(gpointer data) { - pa_time_event* e = data; - assert(e && e->mainloop && e->source != (guint) -1); - - g_source_remove(e->source); - e->source = (guint) -1; - - e->callback(&e->mainloop->api, e, &e->timeval, e->userdata); - return FALSE; -} - -static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { - struct timeval now; - assert(e && e->mainloop && !e->dead); - - pa_gettimeofday(&now); - if (e->source != (guint) -1) - g_source_remove(e->source); - - if (tv) { - e->timeval = *tv; - e->source = g_timeout_add_full(G_PRIORITY_DEFAULT, msec_diff(tv, &now), time_cb, e, NULL); - assert(e->source != (guint) -1); - } else - e->source = (guint) -1; - } - -static void glib_time_free(pa_time_event *e) { - assert(e && e->mainloop && !e->dead); - - if (e->source != (guint) -1) { - g_source_remove(e->source); - e->source = (guint) -1; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->time_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_time_events)) - e->next->prev = e; - - e->mainloop->dead_time_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*m, pa_time_event*e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Deferred sources */ - -static void glib_defer_enable(pa_defer_event *e, int b); - -static pa_defer_event* glib_defer_new(pa_mainloop_api*m, void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata), void *userdata) { - pa_defer_event *e; - pa_glib_mainloop *g; - - assert(m && m->userdata && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_defer_event)); - e->mainloop = g; - e->dead = 0; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - e->source = (guint) -1; - - glib_defer_enable(e, 1); - - e->next = g->defer_events; - if (e->next) e->next->prev = e; - g->defer_events = e; - e->prev = NULL; - return e; -} - -static gboolean idle_cb(gpointer data) { - pa_defer_event* e = data; - assert(e && e->mainloop && e->source != (guint) -1); - - e->callback(&e->mainloop->api, e, e->userdata); - return TRUE; -} - -static void glib_defer_enable(pa_defer_event *e, int b) { - assert(e && e->mainloop); - - if (e->source != (guint) -1 && !b) { - g_source_remove(e->source); - e->source = (guint) -1; - } else if (e->source == (guint) -1 && b) { - e->source = g_idle_add_full(G_PRIORITY_HIGH, idle_cb, e, NULL); - assert(e->source != (guint) -1); - } -} - -static void glib_defer_free(pa_defer_event *e) { - assert(e && e->mainloop && !e->dead); - - if (e->source != (guint) -1) { - g_source_remove(e->source); - e->source = (guint) -1; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->defer_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_defer_events)) - e->next->prev = e; - - e->mainloop->dead_defer_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api *m, pa_defer_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* quit() */ - -static void glib_quit(pa_mainloop_api*a, PA_GCC_UNUSED int retval) { - pa_glib_mainloop *g; - assert(a && a->userdata); - g = a->userdata; - - /* NOOP */ -} - -static const pa_mainloop_api vtable = { - .userdata = NULL, - - .io_new = glib_io_new, - .io_enable = glib_io_enable, - .io_free = glib_io_free, - .io_set_destroy= glib_io_set_destroy, - - .time_new = glib_time_new, - .time_restart = glib_time_restart, - .time_free = glib_time_free, - .time_set_destroy = glib_time_set_destroy, - - .defer_new = glib_defer_new, - .defer_enable = glib_defer_enable, - .defer_free = glib_defer_free, - .defer_set_destroy = glib_defer_set_destroy, - - .quit = glib_quit, -}; - -pa_glib_mainloop *pa_glib_mainloop_new(void) { - pa_glib_mainloop *g; - - g = pa_xmalloc(sizeof(pa_glib_mainloop)); - - g->api = vtable; - g->api.userdata = g; - - g->io_events = g->dead_io_events = NULL; - g->time_events = g->dead_time_events = NULL; - g->defer_events = g->dead_defer_events = NULL; - - g->cleanup_source = (guint) -1; - return g; -} - -static void free_io_events(pa_io_event *e) { - while (e) { - pa_io_event *r = e; - e = r->next; - - if (r->source != (guint) -1) - g_source_remove(r->source); - - if (r->io_channel) - g_io_channel_unref(r->io_channel); - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -static void free_time_events(pa_time_event *e) { - while (e) { - pa_time_event *r = e; - e = r->next; - - if (r->source != (guint) -1) - g_source_remove(r->source); - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -static void free_defer_events(pa_defer_event *e) { - while (e) { - pa_defer_event *r = e; - e = r->next; - - if (r->source != (guint) -1) - g_source_remove(r->source); - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -void pa_glib_mainloop_free(pa_glib_mainloop* g) { - assert(g); - - free_io_events(g->io_events); - free_io_events(g->dead_io_events); - free_defer_events(g->defer_events); - free_defer_events(g->dead_defer_events); - free_time_events(g->time_events); - free_time_events(g->dead_time_events); - - if (g->cleanup_source != (guint) -1) - g_source_remove(g->cleanup_source); - - pa_xfree(g); -} - -pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) { - assert(g); - return &g->api; -} - -static gboolean free_dead_events(gpointer p) { - pa_glib_mainloop *g = p; - assert(g); - - free_io_events(g->dead_io_events); - free_defer_events(g->dead_defer_events); - free_time_events(g->dead_time_events); - - g->dead_io_events = NULL; - g->dead_defer_events = NULL; - g->dead_time_events = NULL; - - g_source_remove(g->cleanup_source); - g->cleanup_source = (guint) -1; - - return FALSE; -} - -static void schedule_free_dead_events(pa_glib_mainloop *g) { - assert(g); - - if (g->cleanup_source != (guint) -1) - return; - - g->cleanup_source = g_idle_add_full(G_PRIORITY_HIGH, free_dead_events, g, NULL); -} diff --git a/src/tests/mainloop-test.c b/src/tests/mainloop-test.c index 671adeff..b06d0ed1 100644 --- a/src/tests/mainloop-test.c +++ b/src/tests/mainloop-test.c @@ -40,13 +40,6 @@ static GMainLoop* glib_main_loop = NULL; -#if GLIB_MAJOR_VERSION >= 2 -#define GLIB20 -#else -#undef GLIB20 -#endif - - #else /* GLIB_MAIN_LOOP */ #include #endif /* GLIB_MAIN_LOOP */ @@ -68,10 +61,8 @@ static void dcb(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { static void tcb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) { fprintf(stderr, "TIME EVENT\n"); -#if defined(GLIB_MAIN_LOOP) && defined(GLIB20) +#if defined(GLIB_MAIN_LOOP) g_main_loop_quit(glib_main_loop); -#elif defined(GLIB_MAIN_LOOP) - g_main_quit(glib_main_loop); #else a->quit(a, 0); #endif @@ -86,17 +77,10 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { #ifdef GLIB_MAIN_LOOP pa_glib_mainloop *g; -#ifdef GLIB20 glib_main_loop = g_main_loop_new(NULL, FALSE); assert(glib_main_loop); g = pa_glib_mainloop_new(NULL); -#else /* GLIB20 */ - glib_main_loop = g_main_new(FALSE); - assert(glib_main_loop); - - g = pa_glib_mainloop_new(); -#endif /* GLIB20 */ assert(g); a = pa_glib_mainloop_get_api(g); @@ -121,10 +105,8 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { tv.tv_sec += 10; te = a->time_new(a, &tv, tcb, NULL); -#if defined(GLIB_MAIN_LOOP) && defined(GLIB20) +#if defined(GLIB_MAIN_LOOP) g_main_loop_run(glib_main_loop); -#elif defined(GLIB_MAIN_LOOP) - g_main_run(glib_main_loop); #else pa_mainloop_run(m, NULL); #endif @@ -135,11 +117,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { #ifdef GLIB_MAIN_LOOP pa_glib_mainloop_free(g); -#ifdef GLIB20 g_main_loop_unref(glib_main_loop); -#else - g_main_destroy(glib_main_loop); -#endif #else pa_mainloop_free(m); #endif -- cgit From 9c87a65ce91c38b60c19ae108a51a2e8ce46a85c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Jul 2006 17:44:19 +0000 Subject: * add new --system command line parameter to the daemon for running PulseAudio as system-wide instance * add PA_ prefixes to all global #defines * modify auth-by-creds: define a new group "pulse-access" which is used for authentication * add proper privilige dropping when running in --system mode * create runtime directory once on startup and not by each module seperately git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1105 fefdeb5f-60dc-0310-8127-8f9354f1896f --- bootstrap.sh | 2 +- configure.ac | 55 +++++++++++++++- src/Makefile.am | 14 ++-- src/daemon/cmdline.c | 12 +++- src/daemon/daemon-conf.c | 22 +++---- src/daemon/daemon-conf.h | 3 +- src/daemon/daemon.conf.in | 6 ++ src/daemon/main.c | 129 +++++++++++++++++++++++++++++++++++-- src/modules/module-match.c | 6 +- src/modules/module-protocol-stub.c | 55 ++++++++++------ src/modules/module-tunnel.c | 2 +- src/pulse/client-conf.c | 19 +++--- src/pulse/client-conf.h | 2 +- src/pulse/context.c | 24 ++++++- src/pulsecore/core-util.c | 86 +++++++++++++++++++------ src/pulsecore/core-util.h | 5 +- src/pulsecore/core.c | 5 +- src/pulsecore/core.h | 2 + src/pulsecore/iochannel.c | 17 +++-- src/pulsecore/iochannel.h | 2 +- src/pulsecore/pdispatch.c | 4 +- src/pulsecore/pdispatch.h | 6 +- src/pulsecore/pid.c | 15 +---- src/pulsecore/protocol-native.c | 2 +- src/pulsecore/pstream-util.c | 2 +- src/pulsecore/pstream-util.h | 4 +- src/pulsecore/pstream.c | 31 +++++---- src/pulsecore/pstream.h | 6 +- 28 files changed, 403 insertions(+), 135 deletions(-) diff --git a/bootstrap.sh b/bootstrap.sh index 1f8b29d0..b85f025e 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -57,7 +57,7 @@ else run_versioned automake "$VERSION" -a -c --foreign if test "x$NOCONFIGURE" = "x"; then - CFLAGS="-g -O0" ./configure --sysconfdir=/etc --enable-force-preopen "$@" + CFLAGS="-g -O0" ./configure --sysconfdir=/etc --localstatedir=/var --enable-force-preopen "$@" make clean fi fi diff --git a/configure.ac b/configure.ac index cf7b5534..a7f85ea0 100644 --- a/configure.ac +++ b/configure.ac @@ -239,7 +239,11 @@ AC_CHECK_FUNCS([lstat]) # Non-standard AC_CHECK_FUNCS(setresuid) +AC_CHECK_FUNCS(setresgid) AC_CHECK_FUNCS(setreuid) +AC_CHECK_FUNCS(setregid) +AC_CHECK_FUNCS(seteuid) +AC_CHECK_FUNCS(setegid) #### POSIX threads #### @@ -602,6 +606,48 @@ AC_SUBST(LIRC_CFLAGS) AC_SUBST(LIRC_LIBS) AM_CONDITIONAL([HAVE_LIRC], [test "x$HAVE_LIRC" = x1]) +#### PulseAudio system group & user ##### + +AC_ARG_WITH(system_user, AS_HELP_STRING([--with-system-user=],[User for running the PulseAudio daemon as a system-wide instance (pulse)])) +if test -z "$with_system_user" ; then + PA_SYSTEM_USER=pulse +else + PA_SYSTEM_USER=$with_system_user +fi +AC_SUBST(PA_SYSTEM_USER) +AC_DEFINE_UNQUOTED(PA_SYSTEM_USER,"$PA_SYSTEM_USER", [User for running the PulseAudio system daemon]) + +AC_ARG_WITH(system_group,AS_HELP_STRING([--with-system-group=],[Group for running the PulseAudio daemon as a system-wide instance (pulse)])) +if test -z "$with_system_group" ; then + PA_SYSTEM_GROUP=pulse +else + PA_SYSTEM_GROUP=$with_system_group +fi +AC_SUBST(PA_SYSTEM_GROUP) +AC_DEFINE_UNQUOTED(PA_SYSTEM_GROUP,"$PA_SYSTEM_GROUP", [Group for the PulseAudio system daemon]) + +AC_ARG_WITH(realtime_group,AS_HELP_STRING([--with-realtime-group=],[Group for users that are allowed to start the PulseAudio daemon with realtime scheduling (realtime)])) +if test -z "$with_realtime_group" ; then + PA_REALTIME_GROUP=realtime +else + PA_REALTIME_GROUP=$with_realtime_group +fi +AC_SUBST(PA_REALTIME_GROUP) +AC_DEFINE_UNQUOTED(PA_REALTIME_GROUP,"$PA_REALTIME_GROUP", [Realtime group]) + +AC_ARG_WITH(access_group,AS_HELP_STRING([--with-access-group=],[Group which is allowed access to a system-wide PulseAudio daemon (pulse-access)])) +if test -z "$with_access_group" ; then + PA_ACCESS_GROUP=pulse-access +else + PA_ACCESS_GROUP=$with_access_group +fi +AC_SUBST(PA_ACCESS_GROUP) +AC_DEFINE_UNQUOTED(PA_ACCESS_GROUP,"$PA_ACCESS_GROUP", [Access group]) + +#### PulseAudio system runtime dir #### +PA_SYSTEM_RUNTIME_PATH="${localstatedir}/run/pulse" +AC_SUBST(PA_SYSTEM_RUNTIME_PATH) + ################################### # Output # ################################### @@ -709,8 +755,9 @@ echo " prefix: ${prefix} sysconfdir: ${sysconfdir} localstatedir: ${localstatedir} - compiler: ${CC} - cflags: ${CFLAGS} + System Runtime Path: ${PA_SYSTEM_RUNTIME_PATH} + Compiler: ${CC} + CFLAGS: ${CFLAGS} Have X11: ${ENABLE_X11} Enable OSS: ${ENABLE_OSS} Enable Alsa: ${ENABLE_ALSA} @@ -721,4 +768,8 @@ echo " Enable Async DNS: ${ENABLE_LIBASYNCNS} Enable LIRC: ${ENABLE_LIRC} Enable TCP Wrappers: ${ENABLE_TCPWRAP} + System User: ${PA_SYSTEM_USER} + System Group: ${PA_SYSTEM_GROUP} + Realtime Group: ${PA_REALTIME_GROUP} + Access Group: ${PA_ACCESS_GROUP} " diff --git a/src/Makefile.am b/src/Makefile.am index 0235741b..1a4bcb04 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,11 +30,11 @@ pulseconfdir=$(sysconfdir)/pulse # Defines # ################################### -PULSEAUDIO_BINARY=$(bindir)/pulseaudio$(EXEEXT) +PA_BINARY=$(bindir)/pulseaudio$(EXEEXT) if OS_IS_WIN32 -DEFAULT_CONFIG_DIR=%PULSE_ROOT% +PA_DEFAULT_CONFIG_DIR=%PULSE_ROOT% else -DEFAULT_CONFIG_DIR=$(pulseconfdir) +PA_DEFAULT_CONFIG_DIR=$(pulseconfdir) endif ################################### @@ -45,10 +45,10 @@ AM_CFLAGS = -I$(top_srcdir)/src AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS AM_CFLAGS += $(LTDLINCL) AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) -AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibexecdir)\" -#AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\" -AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\" -AM_CFLAGS += -DPULSEAUDIO_BINARY=\"$(PULSEAUDIO_BINARY)\" +AM_CFLAGS += -DPA_DLSEARCHPATH=\"$(modlibexecdir)\" +AM_CFLAGS += -DPA_DEFAULT_CONFIG_DIR=\"$(PA_DEFAULT_CONFIG_DIR)\" +AM_CFLAGS += -DPA_BINARY=\"$(PA_BINARY)\" +AM_CFLAGS += -DPA_SYSTEM_RUNTIME_PATH=\"$(PA_SYSTEM_RUNTIME_PATH)\" # This cool debug trap works on i386/gcc only AM_CFLAGS += '-DDEBUG_TRAP=__asm__("int $$3")' diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c index a106dc09..ab876edf 100644 --- a/src/daemon/cmdline.c +++ b/src/daemon/cmdline.c @@ -58,7 +58,8 @@ enum { ARG_RESAMPLE_METHOD, ARG_KILL, ARG_USE_PID_FILE, - ARG_CHECK + ARG_CHECK, + ARG_SYSTEM }; /* Tabel for getopt_long() */ @@ -84,6 +85,7 @@ static struct option long_options[] = { {"kill", 0, 0, ARG_KILL}, {"use-pid-file", 2, 0, ARG_USE_PID_FILE}, {"check", 0, 0, ARG_CHECK}, + {"system", 2, 0, ARG_SYSTEM}, {NULL, 0, 0, 0} }; @@ -105,6 +107,7 @@ void pa_cmdline_help(const char *argv0) { " --check Check for a running daemon\n\n" "OPTIONS:\n" + " --system[=BOOL] Run as system-wide instance\n" " -D, --daemonize[=BOOL] Daemonize after startup\n" " --fail[=BOOL] Quit when startup fails\n" " --high-priority[=BOOL] Try to set high process priority\n" @@ -276,6 +279,13 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d goto fail; } break; + + case ARG_SYSTEM: + if ((conf->system_instance = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + pa_log(__FILE__": --system expects boolean argument"); + goto fail; + } + break; default: goto fail; diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index d1afed7b..a5a62567 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -39,23 +39,15 @@ #include "daemon-conf.h" -#ifndef DEFAULT_CONFIG_DIR -# ifndef OS_IS_WIN32 -# define DEFAULT_CONFIG_DIR "/etc/pulse" -# else -# define DEFAULT_CONFIG_DIR "%PULSE_ROOT%" -# endif -#endif - #ifndef OS_IS_WIN32 # define PATH_SEP "/" #else # define PATH_SEP "\\" #endif -#define DEFAULT_SCRIPT_FILE DEFAULT_CONFIG_DIR PATH_SEP "default.pa" +#define DEFAULT_SCRIPT_FILE PA_DEFAULT_CONFIG_DIR PATH_SEP "default.pa" #define DEFAULT_SCRIPT_FILE_USER ".pulse" PATH_SEP "default.pa" -#define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "daemon.conf" +#define DEFAULT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PATH_SEP "daemon.conf" #define DEFAULT_CONFIG_FILE_USER ".pulse" PATH_SEP "daemon.conf" #define ENV_SCRIPT_FILE "PULSE_SCRIPT" @@ -79,7 +71,8 @@ static const pa_daemon_conf default_conf = { .log_level = PA_LOG_NOTICE, .resample_method = PA_RESAMPLER_SRC_SINC_FASTEST, .config_file = NULL, - .use_pid_file = 1 + .use_pid_file = 1, + .system_instance = 0 }; pa_daemon_conf* pa_daemon_conf_new(void) { @@ -89,9 +82,7 @@ pa_daemon_conf* pa_daemon_conf_new(void) { if ((f = pa_open_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE, &c->default_script_file, "r"))) fclose(f); -#ifdef DLSEARCHPATH - c->dl_search_path = pa_xstrdup(DLSEARCHPATH); -#endif + c->dl_search_path = pa_xstrdup(PA_DLSEARCHPATH); return c; } @@ -212,6 +203,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { { "verbose", parse_log_level, NULL }, { "resample-method", parse_resample_method, NULL }, { "use-pid-file", pa_config_parse_bool, NULL }, + { "system-instance", pa_config_parse_bool, NULL }, { NULL, NULL, NULL }, }; @@ -229,6 +221,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { table[11].data = c; table[12].data = c; table[13].data = &c->use_pid_file; + table[14].data = &c->system_instance; pa_xfree(c->config_file); c->config_file = NULL; @@ -295,6 +288,7 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { pa_strbuf_printf(s, "log-level = %s\n", log_level_to_string[c->log_level]); pa_strbuf_printf(s, "resample-method = %s\n", pa_resample_method_to_string(c->resample_method)); pa_strbuf_printf(s, "use-pid-file = %i\n", c->use_pid_file); + pa_strbuf_printf(s, "system-instance = %i\n", !!c->system_instance); return pa_strbuf_tostring_free(s); } diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h index c325495c..bfea7358 100644 --- a/src/daemon/daemon-conf.h +++ b/src/daemon/daemon-conf.h @@ -46,7 +46,8 @@ typedef struct pa_daemon_conf { module_idle_time, scache_idle_time, auto_log_target, - use_pid_file; + use_pid_file, + system_instance; char *script_commands, *dl_search_path, *default_script_file; pa_log_target_t log_target; pa_log_level_t log_level; diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in index 30bf3ca1..6e55c0ee 100644 --- a/src/daemon/daemon.conf.in +++ b/src/daemon/daemon.conf.in @@ -46,6 +46,9 @@ ## Unload autoloaded modules after being idle for this time ; module-idle-time = 20 +## Unload autoloaded sample cache entries after being idle for this time +; scache-idle-time = 20 + ## The path were to look for dynamic shared objects (DSOs aka ## plugins). You may specify more than one path seperated by ## colons. @@ -75,3 +78,6 @@ ## process per user, you better disable this option since it ## effectively disables multiple instances. ; use-pid-file = 1 + +## Run the daemon as system-wide instance, requires root priviliges +; system-instance = 0 diff --git a/src/daemon/main.c b/src/daemon/main.c index c41c69df..4961f0ca 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -37,6 +37,9 @@ #include #include #include +#include +#include + #include #ifdef HAVE_SYS_IOCTL_H @@ -149,6 +152,104 @@ static void close_pipe(int p[2]) { p[0] = p[1] = -1; } +#define set_env(key, value) putenv(pa_sprintf_malloc("%s=%s", (key), (value))) + +static int change_user(void) { + struct passwd *pw; + struct group * gr; + int r; + + if (!(pw = getpwnam(PA_SYSTEM_USER))) { + pa_log(__FILE__": Failed to find user '%s'.", PA_SYSTEM_USER); + return -1; + } + + if (!(gr = getgrnam(PA_SYSTEM_GROUP))) { + pa_log(__FILE__": Failed to find group '%s'.", PA_SYSTEM_GROUP); + return -1; + } + + pa_log_info(__FILE__": Found user '%s' (UID %lu) and group '%s' (GID %lu).", + PA_SYSTEM_USER, (unsigned long) pw->pw_uid, + PA_SYSTEM_GROUP, (unsigned long) gr->gr_gid); + + if (pw->pw_gid != gr->gr_gid) { + pa_log(__FILE__": GID of user '%s' and of group '%s' don't match.", PA_SYSTEM_USER, PA_SYSTEM_GROUP); + return -1; + } + + if (strcmp(pw->pw_dir, PA_SYSTEM_RUNTIME_PATH) != 0) + pa_log_warn(__FILE__": Warning: home directory of user '%s' is not '%s', ignoring.", PA_SYSTEM_USER, PA_SYSTEM_RUNTIME_PATH); + + if (pa_make_secure_dir(PA_SYSTEM_RUNTIME_PATH, 0755, pw->pw_uid, gr->gr_gid) < 0) { + pa_log(__FILE__": Failed to create '%s': %s", PA_SYSTEM_RUNTIME_PATH, pa_cstrerror(errno)); + return -1; + } + + if (initgroups(PA_SYSTEM_USER, gr->gr_gid) != 0) { + pa_log(__FILE__": Failed to change group list: %s", pa_cstrerror(errno)); + return -1; + } + +#if defined(HAVE_SETRESGID) + r = setresgid(gr->gr_gid, gr->gr_gid, gr->gr_gid); +#elif defined(HAVE_SETEGID) + if ((r = setgid(gr->gr_gid)) >= 0) + r = setegid(gr->gr_gid); +#elif defined(HAVE_SETREGID) + r = setregid(gr->gr_gid, gr->gr_gid); +#else +#error "No API to drop priviliges" +#endif + + if (r < 0) { + pa_log(__FILE__": Failed to change GID: %s", pa_cstrerror(errno)); + return -1; + } + +#if defined(HAVE_SETRESUID) + r = setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid); +#elif defined(HAVE_SETEUID) + if ((r = setuid(pw->pw_uid)) >= 0) + r = seteuid(pw->pw_uid); +#elif defined(HAVE_SETREUID) + r = setreuid(pw->pw_uid, pw->pw_uid); +#else +#error "No API to drop priviliges" +#endif + + if (r < 0) { + pa_log(__FILE__": Failed to change UID: %s", pa_cstrerror(errno)); + return -1; + } + + set_env("USER", PA_SYSTEM_USER); + set_env("LOGNAME", PA_SYSTEM_GROUP); + set_env("HOME", PA_SYSTEM_RUNTIME_PATH); + + /* Relevant for pa_runtime_path() */ + set_env("PULSE_RUNTIME_PATH", PA_SYSTEM_RUNTIME_PATH); + + pa_log_info(__FILE__": Successfully dropped root privileges."); + + return 0; +} + +static int create_runtime_dir(void) { + char fn[PATH_MAX]; + + pa_runtime_path(NULL, fn, sizeof(fn)); + + if (pa_make_secure_dir(fn, 0700, getuid(), getgid()) < 0) { + pa_log(__FILE__": Failed to create '%s': %s", fn, pa_cstrerror(errno)); + return -1; + } + + /* Relevant for pa_runtime_path() later on */ + set_env("PULSE_RUNTIME_PATH", fn); + return 0; +} + int main(int argc, char *argv[]) { pa_core *c; pa_strbuf *buf = NULL; @@ -172,13 +273,14 @@ int main(int argc, char *argv[]) { setlocale(LC_ALL, ""); - pa_limit_caps(); + if (getuid() != 0) + pa_limit_caps(); #ifdef HAVE_GETUID suid_root = getuid() != 0 && geteuid() == 0; - if (suid_root && (pa_own_uid_in_group("realtime", &gid) <= 0 || gid >= 1000)) { - pa_log_warn(__FILE__": WARNING: called SUID root, but not in group 'realtime'."); + if (suid_root && (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) <= 0 || gid >= 1000)) { + pa_log_warn(__FILE__": WARNING: called SUID root, but not in group '"PA_REALTIME_GROUP"'."); pa_drop_root(); } #else @@ -220,7 +322,8 @@ int main(int argc, char *argv[]) { if (conf->high_priority && conf->cmd == PA_CMD_DAEMON) pa_raise_priority(); - pa_drop_caps(); + if (getuid() != 0) + pa_drop_caps(); if (suid_root) pa_drop_root(); @@ -278,6 +381,14 @@ int main(int argc, char *argv[]) { assert(conf->cmd == PA_CMD_DAEMON); } + if (getuid() == 0 && !conf->system_instance) { + pa_log(__FILE__": This program is not intended to be run as root (unless --system is specified)."); + goto finish; + } else if (getuid() != 0 && conf->system_instance) { + pa_log(__FILE__": Root priviliges required."); + goto finish; + } + if (conf->daemonize) { pid_t child; int tty_fd; @@ -362,6 +473,13 @@ int main(int argc, char *argv[]) { } chdir("/"); + umask(0022); + + if (conf->system_instance) { + if (change_user() < 0) + goto finish; + } else if (create_runtime_dir() < 0) + goto finish; if (conf->use_pid_file) { if (pa_pid_file_create() < 0) { @@ -379,12 +497,13 @@ int main(int argc, char *argv[]) { #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif - + mainloop = pa_mainloop_new(); assert(mainloop); c = pa_core_new(pa_mainloop_get_api(mainloop)); assert(c); + c->is_system_instance = !!conf->system_instance; r = pa_signal_init(pa_mainloop_get_api(mainloop)); assert(r == 0); diff --git a/src/modules/module-match.c b/src/modules/module-match.c index 28d6a08b..cd58a838 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -52,11 +52,7 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define WHITESPACE "\n\r \t" -#ifndef DEFAULT_CONFIG_DIR -#define DEFAULT_CONFIG_DIR "/etc/pulse" -#endif - -#define DEFAULT_MATCH_TABLE_FILE DEFAULT_CONFIG_DIR"/match.table" +#define DEFAULT_MATCH_TABLE_FILE PA_DEFAULT_CONFIG_DIR"/match.table" #define DEFAULT_MATCH_TABLE_FILE_USER ".pulse/match.table" static const char* const valid_modargs[] = { diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index 20728766..fa21b737 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -75,7 +75,14 @@ #include "module-simple-protocol-unix-symdef.h" #endif PA_MODULE_DESCRIPTION("Simple protocol "SOCKET_DESCRIPTION) - PA_MODULE_USAGE("rate= format= channels= sink= source= playback= record= "SOCKET_USAGE) + PA_MODULE_USAGE("rate= " + "format= " + "channels= " + "sink= " + "source= " + "playback= " + "record= " + SOCKET_USAGE) #elif defined(USE_PROTOCOL_CLI) #include #define protocol_new pa_protocol_cli_new @@ -129,7 +136,10 @@ #endif PA_MODULE_DESCRIPTION("Native protocol "SOCKET_DESCRIPTION) - PA_MODULE_USAGE("auth-anonymous= cookie= "AUTH_USAGE SOCKET_USAGE) + PA_MODULE_USAGE("auth-anonymous= " + "cookie= " + AUTH_USAGE + SOCKET_USAGE) #elif defined(USE_PROTOCOL_ESOUND) #include #include @@ -145,7 +155,11 @@ #include "module-esound-protocol-unix-symdef.h" #endif PA_MODULE_DESCRIPTION("ESOUND protocol "SOCKET_DESCRIPTION) - PA_MODULE_USAGE("sink= source= auth-anonymous= cookie= "SOCKET_USAGE) + PA_MODULE_USAGE("sink= " + "source= " + "auth-anonymous= " + "cookie= " + SOCKET_USAGE) #else #error "Broken build system" #endif @@ -189,7 +203,6 @@ int pa__init(pa_core *c, pa_module*m) { #else pa_socket_server *s; int r; - const char *v; char tmp[PATH_MAX]; #endif @@ -241,15 +254,21 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; #else - v = pa_modargs_get_value(ma, "socket", UNIX_SOCKET); - pa_runtime_path(v, tmp, sizeof(tmp)); + + pa_runtime_path(pa_modargs_get_value(ma, "socket", UNIX_SOCKET), tmp, sizeof(tmp)); u->socket_path = pa_xstrdup(tmp); - if (pa_make_secure_parent_dir(tmp) < 0) { - pa_log(__FILE__": Failed to create secure socket directory."); +#if defined(USE_PROTOCOL_ESOUND) + + /* This socket doesn't reside in our own runtime dir but in + * /tmp/.esd/, hence we have to create the dir first */ + + if (pa_make_secure_parent_dir(u->socket_path, c->is_system_instance ? 0755 : 0700, getuid(), getgid()) < 0) { + pa_log(__FILE__": Failed to create socket directory: %s\n", pa_cstrerror(errno)); goto fail; } - +#endif + if ((r = pa_unix_socket_remove_stale(tmp)) < 0) { pa_log(__FILE__": Failed to remove stale UNIX socket '%s': %s", tmp, pa_cstrerror(errno)); goto fail; @@ -324,19 +343,17 @@ void pa__done(pa_core *c, pa_module*m) { if (u->protocol_unix) protocol_free(u->protocol_unix); +#if defined(USE_PROTOCOL_ESOUND) if (u->socket_path) { - char *p; - - if ((p = pa_parent_dir(u->socket_path))) { - if (rmdir(p) < 0 && errno != ENOENT && errno != ENOTEMPTY) - pa_log(__FILE__": Failed to remove %s: %s.", u->socket_path, pa_cstrerror(errno)); - - pa_xfree(p); - } - - pa_xfree(u->socket_path); + char *p = pa_parent_dir(u->socket_path); + rmdir(p); + pa_xfree(p); } #endif + + + pa_xfree(u->socket_path); +#endif pa_xfree(u); } diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index bf2627a7..c018c520 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -611,7 +611,7 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { } -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const void*creds, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const struct ucred *creds, void *userdata) { struct userdata *u = userdata; assert(p && packet && u); diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c index 5cebcf46..28b4f2d1 100644 --- a/src/pulse/client-conf.c +++ b/src/pulse/client-conf.c @@ -39,21 +39,13 @@ #include "client-conf.h" -#ifndef DEFAULT_CONFIG_DIR -# ifndef OS_IS_WIN32 -# define DEFAULT_CONFIG_DIR "/etc/pulse" -# else -# define DEFAULT_CONFIG_DIR "%PULSE_ROOT%" -# endif -#endif - #ifndef OS_IS_WIN32 # define PATH_SEP "/" #else # define PATH_SEP "\\" #endif -#define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "client.conf" +#define DEFAULT_CLIENT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PATH_SEP "client.conf" #define DEFAULT_CLIENT_CONFIG_FILE_USER ".pulse" PATH_SEP "client.conf" #define ENV_CLIENT_CONFIG_FILE "PULSE_CLIENTCONFIG" @@ -71,15 +63,17 @@ static const pa_client_conf default_conf = { .default_server = NULL, .autospawn = 0, .cookie_file = NULL, - .cookie_valid = 0 + .cookie_valid = 0, + .access_group = NULL }; pa_client_conf *pa_client_conf_new(void) { pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); - c->daemon_binary = pa_xstrdup(PULSEAUDIO_BINARY); + c->daemon_binary = pa_xstrdup(PA_BINARY); c->extra_arguments = pa_xstrdup("--log-target=syslog --exit-idle-time=5"); c->cookie_file = pa_xstrdup(PA_NATIVE_COOKIE_FILE); + c->access_group = pa_xstrdup(PA_ACCESS_GROUP); return c; } @@ -92,6 +86,7 @@ void pa_client_conf_free(pa_client_conf *c) { pa_xfree(c->default_source); pa_xfree(c->default_server); pa_xfree(c->cookie_file); + pa_xfree(c->access_group); pa_xfree(c); } int pa_client_conf_load(pa_client_conf *c, const char *filename) { @@ -108,6 +103,7 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) { { "default-server", pa_config_parse_string, NULL }, { "autospawn", pa_config_parse_bool, NULL }, { "cookie-file", pa_config_parse_string, NULL }, + { "access-group", pa_config_parse_string, NULL }, { NULL, NULL, NULL }, }; @@ -118,6 +114,7 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) { table[4].data = &c->default_server; table[5].data = &c->autospawn; table[6].data = &c->cookie_file; + table[7].data = &c->access_group; f = filename ? fopen((fn = pa_xstrdup(filename)), "r") : diff --git a/src/pulse/client-conf.h b/src/pulse/client-conf.h index a532f0df..dfb1148d 100644 --- a/src/pulse/client-conf.h +++ b/src/pulse/client-conf.h @@ -27,7 +27,7 @@ /* A structure containing configuration data for PulseAudio clients. */ typedef struct pa_client_conf { - char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server, *cookie_file; + char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server, *cookie_file, *access_group; int autospawn; uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; int cookie_valid; /* non-zero, when cookie is valid */ diff --git a/src/pulse/context.c b/src/pulse/context.c index 228053bc..a25e2f78 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include #ifdef HAVE_SYS_WAIT_H #include @@ -270,7 +272,7 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED); } -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const void *creds, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const struct ucred *creds, void *userdata) { pa_context *c = userdata; assert(p); @@ -420,7 +422,23 @@ static void setup_context(pa_context *c, pa_iochannel *io) { t = pa_tagstruct_command(c, PA_COMMAND_AUTH, &tag); pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION); pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie)); - pa_pstream_send_tagstruct_with_creds(c->pstream, t, 1); + +#ifdef SCM_CREDENTIALS +{ + struct ucred ucred; + + ucred.pid = getpid(); + ucred.uid = getuid(); + + if ((ucred.gid = pa_get_gid_of_group(PA_ACCESS_GROUP)) == (gid_t) -1) + ucred.gid = getgid(); + + pa_pstream_send_tagstruct_with_creds(c->pstream, t, &ucred); +} +#else + pa_pstream_send_tagstruct_with_creds(c->pstream, t, NULL); +#endif + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL); pa_context_set_state(c, PA_CONTEXT_AUTHORIZING); @@ -680,7 +698,7 @@ int pa_context_connect( char lf[PATH_MAX]; pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); - pa_make_secure_parent_dir(lf); + pa_make_secure_parent_dir(lf, 0700, getuid(), getgid()); assert(c->autospawn_lock_fd <= 0); c->autospawn_lock_fd = pa_lock_lockfile(lf); diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 7cb85209..6375e5ef 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -84,10 +84,10 @@ #endif #ifndef OS_IS_WIN32 -#define PA_RUNTIME_PATH_PREFIX "/tmp/pulse-" +#define PA_USER_RUNTIME_PATH_PREFIX "/tmp/pulse-" #define PATH_SEP '/' #else -#define PA_RUNTIME_PATH_PREFIX "%TEMP%\\pulse-" +#define PA_USER_RUNTIME_PATH_PREFIX "%TEMP%\\pulse-" #define PATH_SEP '\\' #endif @@ -136,23 +136,32 @@ void pa_make_nonblock_fd(int fd) { } /** Creates a directory securely */ -int pa_make_secure_dir(const char* dir) { +int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) { struct stat st; + int r; + assert(dir); #ifdef OS_IS_WIN32 - if (mkdir(dir) < 0) + r = mkdir(dir); #else - if (mkdir(dir, 0700) < 0) + { + mode_t u; + u = umask(~m); + r = mkdir(dir, m); + umask(u); + } #endif - if (errno != EEXIST) - return -1; + + if (r < 0 && errno != EEXIST) + return -1; #ifdef HAVE_CHOWN - chown(dir, getuid(), getgid()); + chown(dir, uid, gid); #endif + #ifdef HAVE_CHMOD - chmod(dir, 0700); + chmod(dir, m); #endif #ifdef HAVE_LSTAT @@ -163,8 +172,13 @@ int pa_make_secure_dir(const char* dir) { goto fail; #ifndef OS_IS_WIN32 - if (!S_ISDIR(st.st_mode) || (st.st_uid != getuid()) || ((st.st_mode & 0777) != 0700)) + if (!S_ISDIR(st.st_mode) || + (st.st_uid != uid) || + (st.st_gid != gid) || + ((st.st_mode & 0777) != m)) { + errno = EACCES; goto fail; + } #else fprintf(stderr, "FIXME: pa_make_secure_dir()\n"); #endif @@ -180,23 +194,24 @@ fail: char *pa_parent_dir(const char *fn) { char *slash, *dir = pa_xstrdup(fn); - slash = (char*) pa_path_get_filename(dir); - if (slash == fn) + if ((slash = (char*) pa_path_get_filename(dir)) == dir) { + pa_xfree(dir); return NULL; + } *(slash-1) = 0; return dir; } /* Creates a the parent directory of the specified path securely */ -int pa_make_secure_parent_dir(const char *fn) { +int pa_make_secure_parent_dir(const char *fn, mode_t m, uid_t uid, gid_t gid) { int ret = -1; char *dir; if (!(dir = pa_parent_dir(fn))) goto finish; - if (pa_make_secure_dir(dir) < 0) + if (pa_make_secure_dir(dir, m, uid, gid) < 0) goto finish; ret = 0; @@ -669,6 +684,7 @@ finish: return r; } +/* Check whether the specifc user id is a member of the specified group */ int pa_uid_in_group(uid_t uid, const char *name) { char *g_buf, *p_buf; long g_n, p_n; @@ -705,6 +721,26 @@ finish: return r; } +/* Get the GID of a gfiven group, return (gid_t) -1 on failure. */ +gid_t pa_get_gid_of_group(const char *name) { + gid_t ret = (gid_t) -1; + char *g_buf; + long g_n; + struct group grbuf, *gr; + + g_n = sysconf(_SC_GETGR_R_SIZE_MAX); + g_buf = pa_xmalloc(g_n); + + if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) + goto finish; + + ret = gr->gr_gid; + +finish: + pa_xfree(g_buf); + return ret; +} + #else /* HAVE_GRP_H */ int pa_own_uid_in_group(const char *name, gid_t *gid) { @@ -1003,7 +1039,7 @@ int pa_endswith(const char *s, const char *sfx) { * if fn is non-null and starts with / return fn in s * otherwise append fn to the run time path and return it in s */ char *pa_runtime_path(const char *fn, char *s, size_t l) { - char u[256]; + const char *e; #ifndef OS_IS_WIN32 if (fn && *fn == '/') @@ -1012,10 +1048,22 @@ char *pa_runtime_path(const char *fn, char *s, size_t l) { #endif return pa_strlcpy(s, fn, l); - if (fn) - snprintf(s, l, "%s%s%c%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn); - else - snprintf(s, l, "%s%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u))); + if ((e = getenv("PULSE_RUNTIME_PATH"))) { + + if (fn) + snprintf(s, l, "%s%c%s", e, PATH_SEP, fn); + else + snprintf(s, l, "%s", e); + + } else { + char u[256]; + + if (fn) + snprintf(s, l, "%s%s%c%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn); + else + snprintf(s, l, "%s%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u))); + } + #ifdef OS_IS_WIN32 { diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index 864a96ec..db764de1 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -33,8 +33,8 @@ struct timeval; void pa_make_nonblock_fd(int fd); -int pa_make_secure_dir(const char* dir); -int pa_make_secure_parent_dir(const char *fn); +int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid); +int pa_make_secure_parent_dir(const char *fn, mode_t, uid_t uid, gid_t gid); ssize_t pa_read(int fd, void *buf, size_t count, int *type); ssize_t pa_write(int fd, const void *buf, size_t count, int *type); @@ -66,6 +66,7 @@ const char *pa_strsignal(int sig); int pa_own_uid_in_group(const char *name, gid_t *gid); int pa_uid_in_group(uid_t uid, const char *name); +gid_t pa_get_gid_of_group(const char *name); int pa_lock_fd(int fd, int b); diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index 7c780ea8..d6af3ca9 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -46,7 +46,8 @@ pa_core* pa_core_new(pa_mainloop_api *m) { pa_core* c; - c = pa_xmalloc(sizeof(pa_core)); + + c = pa_xnew(pa_core, 1); c->mainloop = m; c->clients = pa_idxset_new(NULL, NULL); @@ -88,6 +89,8 @@ pa_core* pa_core_new(pa_mainloop_api *m) { c->resample_method = PA_RESAMPLER_SRC_SINC_FASTEST; + c->is_system_instance = 0; + pa_property_init(c); pa_random(&c->cookie, sizeof(c->cookie)); diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index 261c5f75..61f17432 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -71,6 +71,8 @@ struct pa_core { pa_time_event *scache_auto_unload_event; pa_resample_method_t resample_method; + + int is_system_instance; }; pa_core* pa_core_new(pa_mainloop_api *m); diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c index 15aa8e35..852e960e 100644 --- a/src/pulsecore/iochannel.c +++ b/src/pulsecore/iochannel.c @@ -263,12 +263,12 @@ int pa_iochannel_creds_enable(pa_iochannel *io) { return 0; } -ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l) { +ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const struct ucred *ucred) { ssize_t r; struct msghdr mh; struct iovec iov; uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))]; - struct ucred *ucred; + struct ucred *u; struct cmsghdr *cmsg; assert(io); @@ -286,10 +286,15 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_CREDENTIALS; - ucred = (struct ucred*) CMSG_DATA(cmsg); - ucred->pid = getpid(); - ucred->uid = getuid(); - ucred->gid = getgid(); + u = (struct ucred*) CMSG_DATA(cmsg); + + if (ucred) + *u = *ucred; + else { + u->pid = getpid(); + u->uid = getuid(); + u->gid = getgid(); + } memset(&mh, 0, sizeof(mh)); mh.msg_name = NULL; diff --git a/src/pulsecore/iochannel.h b/src/pulsecore/iochannel.h index 64cf331e..3b5cba1c 100644 --- a/src/pulsecore/iochannel.h +++ b/src/pulsecore/iochannel.h @@ -54,7 +54,7 @@ int pa_iochannel_creds_enable(pa_iochannel *io); struct ucred; -ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l); +ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const struct ucred *ucred); ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struct ucred *ucred, int *creds_valid); int pa_iochannel_is_readable(pa_iochannel*io); diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c index 5b76b432..9bc20da4 100644 --- a/src/pulsecore/pdispatch.c +++ b/src/pulsecore/pdispatch.c @@ -180,7 +180,7 @@ static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command, pa_pdispatch_unref(pd); } -int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const void *creds, void *userdata) { +int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const struct ucred *creds, void *userdata) { uint32_t tag, command; pa_tagstruct *ts = NULL; int ret = -1; @@ -310,7 +310,7 @@ pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd) { return pd; } -const void * pa_pdispatch_creds(pa_pdispatch *pd) { +const struct ucred * pa_pdispatch_creds(pa_pdispatch *pd) { assert(pd); assert(pd->ref >= 1); diff --git a/src/pulsecore/pdispatch.h b/src/pulsecore/pdispatch.h index 07620e5a..18073502 100644 --- a/src/pulsecore/pdispatch.h +++ b/src/pulsecore/pdispatch.h @@ -28,6 +28,8 @@ #include #include +struct ucred; + typedef struct pa_pdispatch pa_pdispatch; typedef void (*pa_pdispatch_cb_t)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); @@ -37,7 +39,7 @@ pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *m, const pa_pdispatch_cb_t*table void pa_pdispatch_unref(pa_pdispatch *pd); pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd); -int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*p, const void*creds, void *userdata); +int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*p, const struct ucred*creds, void *userdata); void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t callback, void *userdata, pa_free_cb_t free_cb); @@ -48,6 +50,6 @@ void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, pa_pdispatch_drain_callba /* Remove all reply slots with the give userdata parameter */ void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata); -const void * pa_pdispatch_creds(pa_pdispatch *pd); +const struct ucred * pa_pdispatch_creds(pa_pdispatch *pd); #endif diff --git a/src/pulsecore/pid.c b/src/pulsecore/pid.c index 0ad76a6e..044d223d 100644 --- a/src/pulsecore/pid.c +++ b/src/pulsecore/pid.c @@ -79,13 +79,10 @@ static pid_t read_pid(const char *fn, int fd) { static int open_pid_file(const char *fn, int mode) { int fd = -1; - int lock = -1; for (;;) { struct stat st; - pa_make_secure_parent_dir(fn); - if ((fd = open(fn, mode, S_IRUSR|S_IWUSR)) < 0) { if (mode != O_RDONLY || errno != ENOENT) pa_log_warn(__FILE__": WARNING: failed to open PID file '%s': %s", @@ -123,10 +120,8 @@ static int open_pid_file(const char *fn, int mode) { fail: - if (fd < 0) { - if (lock >= 0) - pa_lock_fd(fd, 0); - + if (fd >= 0) { + pa_lock_fd(fd, 0); close(fd); } @@ -199,7 +194,6 @@ int pa_pid_file_remove(void) { char fn[PATH_MAX]; int ret = -1; pid_t pid; - char *p; pa_runtime_path("pid", fn, sizeof(fn)); @@ -235,11 +229,6 @@ int pa_pid_file_remove(void) { goto fail; } - if ((p = pa_parent_dir(fn))) { - rmdir(p); - pa_xfree(p); - } - ret = 0; fail: diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 784610bd..14f880d7 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -2100,7 +2100,7 @@ static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC /*** pstream callbacks ***/ -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const void *creds, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const struct ucred *creds, void *userdata) { struct connection *c = userdata; assert(p && packet && packet->data && c); diff --git a/src/pulsecore/pstream-util.c b/src/pulsecore/pstream-util.c index 3a995324..09d6f2fa 100644 --- a/src/pulsecore/pstream-util.c +++ b/src/pulsecore/pstream-util.c @@ -29,7 +29,7 @@ #include "pstream-util.h" -void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, int creds) { +void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, const struct ucred *creds) { size_t length; uint8_t *data; pa_packet *packet; diff --git a/src/pulsecore/pstream-util.h b/src/pulsecore/pstream-util.h index fc6d18c0..c60000a8 100644 --- a/src/pulsecore/pstream-util.h +++ b/src/pulsecore/pstream-util.h @@ -26,8 +26,10 @@ #include #include +struct ucred; + /* The tagstruct is freed!*/ -void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, int creds); +void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, const struct ucred *creds); #define pa_pstream_send_tagstruct(p, t) pa_pstream_send_tagstruct_with_creds((p), (t), 0) diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index 7992ccb6..7ef49305 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #ifdef HAVE_NETINET_IN_H #include @@ -69,6 +71,7 @@ struct item_info { pa_packet *packet; #ifdef SCM_CREDENTIALS int with_creds; + struct ucred creds; #endif }; @@ -112,9 +115,8 @@ struct pa_pstream { pa_memblock_stat *memblock_stat; #ifdef SCM_CREDENTIALS - int send_creds_now; - struct ucred ucred; - int creds_valid; + struct ucred read_creds, write_creds; + int read_creds_valid, send_creds_now; #endif }; @@ -216,7 +218,7 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_sta #ifdef SCM_CREDENTIALS p->send_creds_now = 0; - p->creds_valid = 0; + p->read_creds_valid = 0; #endif return p; } @@ -256,7 +258,7 @@ static void pstream_free(pa_pstream *p) { pa_xfree(p); } -void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, int with_creds) { +void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const struct ucred *creds) { struct item_info *i; assert(p && packet && p->ref >= 1); @@ -269,7 +271,8 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, int with_creds) { i->type = PA_PSTREAM_ITEM_PACKET; i->packet = pa_packet_ref(packet); #ifdef SCM_CREDENTIALS - i->with_creds = with_creds; + if ((i->with_creds = !!creds)) + i->creds = *creds; #endif pa_queue_push(p->send_queue, i); @@ -332,7 +335,9 @@ static void prepare_next_write_item(pa_pstream *p) { } #ifdef SCM_CREDENTIALS - p->send_creds_now = p->write.current->with_creds; + if ((p->send_creds_now = p->write.current->with_creds)) + p->write_creds = p->write.current->creds; + #endif } @@ -362,7 +367,7 @@ static int do_write(pa_pstream *p) { #ifdef SCM_CREDENTIALS if (p->send_creds_now) { - if ((r = pa_iochannel_write_with_creds(p->io, d, l)) < 0) + if ((r = pa_iochannel_write_with_creds(p->io, d, l, &p->write_creds)) < 0) return -1; p->send_creds_now = 0; @@ -403,12 +408,12 @@ static int do_read(pa_pstream *p) { #ifdef SCM_CREDENTIALS { - int b; + int b = 0; - if ((r = pa_iochannel_read_with_creds(p->io, d, l, &p->ucred, &b)) <= 0) + if ((r = pa_iochannel_read_with_creds(p->io, d, l, &p->read_creds, &b)) <= 0) return -1; - p->creds_valid = p->creds_valid || b; + p->read_creds_valid = p->read_creds_valid || b; } #else if ((r = pa_iochannel_read(p->io, d, l)) <= 0) @@ -491,7 +496,7 @@ static int do_read(pa_pstream *p) { if (p->recieve_packet_callback) #ifdef SCM_CREDENTIALS - p->recieve_packet_callback(p, p->read.packet, p->creds_valid ? &p->ucred : NULL, p->recieve_packet_callback_userdata); + p->recieve_packet_callback(p, p->read.packet, p->read_creds_valid ? &p->read_creds : NULL, p->recieve_packet_callback_userdata); #else p->recieve_packet_callback(p, p->read.packet, NULL, p->recieve_packet_callback_userdata); #endif @@ -502,7 +507,7 @@ static int do_read(pa_pstream *p) { p->read.index = 0; #ifdef SCM_CREDENTIALS - p->creds_valid = 0; + p->read_creds_valid = 0; #endif } } diff --git a/src/pulsecore/pstream.h b/src/pulsecore/pstream.h index 1a2932d4..39cb7591 100644 --- a/src/pulsecore/pstream.h +++ b/src/pulsecore/pstream.h @@ -31,9 +31,11 @@ #include #include +struct ucred; + typedef struct pa_pstream pa_pstream; -typedef void (*pa_pstream_packet_cb_t)(pa_pstream *p, pa_packet *packet, const void *creds, void *userdata); +typedef void (*pa_pstream_packet_cb_t)(pa_pstream *p, pa_packet *packet, const struct ucred *creds, void *userdata); typedef void (*pa_pstream_memblock_cb_t)(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata); typedef void (*pa_pstream_notify_cb_t)(pa_pstream *p, void *userdata); @@ -41,7 +43,7 @@ pa_pstream* pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_sta void pa_pstream_unref(pa_pstream*p); pa_pstream* pa_pstream_ref(pa_pstream*p); -void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, int with_creds); +void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const struct ucred *creds); void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk); void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata); -- cgit From 45a9a8bcb5572188ca9121e4f11bfeb5c932411f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Jul 2006 18:08:29 +0000 Subject: fix sed scripts according to #define renames git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1106 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 1a4bcb04..d4fbe528 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1168,22 +1168,22 @@ CLEANFILES = esdcompat client.conf default.pa daemon.conf esdcompat: daemon/esdcompat.in Makefile sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ - -e 's,@PULSEAUDIO_BINARY\@,$(PULSEAUDIO_BINARY),g' < $< > $@ + -e 's,@PA_BINARY\@,$(PULSEAUDIO_BINARY),g' < $< > $@ client.conf: pulse/client.conf.in Makefile - sed -e 's,@PULSEAUDIO_BINARY\@,$(PULSEAUDIO_BINARY),g' < $< > $@ + sed -e 's,@PA_BINARY\@,$(PULSEAUDIO_BINARY),g' < $< > $@ if OS_IS_WIN32 default.pa: daemon/default.pa.win32 cp $< $@ else default.pa: daemon/default.pa.in Makefile - sed -e 's,@PULSEAUDIO_BINARY\@,$(PULSEAUDIO_BINARY),g' < $< > $@ + sed -e 's,@PA_BINARY\@,$(PULSEAUDIO_BINARY),g' < $< > $@ endif daemon.conf: daemon/daemon.conf.in Makefile - sed -e 's,@DLSEARCHPATH\@,$(modlibexecdir),g' \ - -e 's,@DEFAULT_CONFIG_FILE\@,$(DEFAULT_CONFIG_DIR),g' < $< > $@ + sed -e 's,@PA_DLSEARCHPATH\@,$(modlibexecdir),g' \ + -e 's,@PA_DEFAULT_CONFIG_FILE\@,$(DEFAULT_CONFIG_DIR),g' < $< > $@ install-exec-hook: chown root $(DESTDIR)$(bindir)/pulseaudio ; true -- cgit From 2b31a900d67506592aecd9c0d59ad997d7977deb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Jul 2006 18:11:12 +0000 Subject: update @@ tokens according to recent Makefile.am change git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1107 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/daemon.conf.in | 4 ++-- src/daemon/esdcompat.in | 2 +- src/pulse/client.conf.in | 8 +++++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in index 6e55c0ee..30628969 100644 --- a/src/daemon/daemon.conf.in +++ b/src/daemon/daemon.conf.in @@ -52,11 +52,11 @@ ## The path were to look for dynamic shared objects (DSOs aka ## plugins). You may specify more than one path seperated by ## colons. -; dl-search-path = @DLSEARCHPATH@ +; dl-search-path = @PA_DLSEARCHPATH@ ## The default script file to load. Specify an empty string for not ## loading a default script file. The -; default-script-file = @DEFAULT_CONFIG_FILE@ +; default-script-file = @PA_DEFAULT_CONFIG_FILE@ ## The default log target. Use either "stderr", "syslog" or ## "auto". The latter is equivalent to "sylog" in case daemonize is diff --git a/src/daemon/esdcompat.in b/src/daemon/esdcompat.in index edae8615..ece1f4f9 100755 --- a/src/daemon/esdcompat.in +++ b/src/daemon/esdcompat.in @@ -95,4 +95,4 @@ EOF shift done -eval "exec '@PULSEAUDIO_BINARY@'$ARGS" +eval "exec '@PA_BINARY@'$ARGS" diff --git a/src/pulse/client.conf.in b/src/pulse/client.conf.in index 21786ebf..3e008766 100644 --- a/src/pulse/client.conf.in +++ b/src/pulse/client.conf.in @@ -21,7 +21,7 @@ ## commented out. Use either ; or # for commenting ## Path to the pulseaudio daemon to run when autospawning. -; daemon-binary = @PULSEAUDIO_BINARY@ +; daemon-binary = @PA_BINARY@ ## Extra arguments to pass to the pulseaudio daemon ; extra-arguments = --log-target=syslog --exit-idle-time=5 @@ -37,3 +37,9 @@ ## Autospawn daemons? ; autospawn = 0 + +### Cookie file +; cookie-file = + +### Access group +; access-group = -- cgit From 340803b30c154ead29795454416592ff9d0e0df2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Jul 2006 18:14:14 +0000 Subject: use access group dedclared in ~/.pulse/client.conf instead of PA_ACCESS_GROUP git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1108 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/default.pa.in | 2 +- src/pulse/context.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in index 6beeb90f..ac10c0ca 100755 --- a/src/daemon/default.pa.in +++ b/src/daemon/default.pa.in @@ -1,4 +1,4 @@ -#!@PULSEAUDIO_BINARY@ -nF +#!@PA_BINARY@ -nF # # This file is part of PulseAudio. diff --git a/src/pulse/context.c b/src/pulse/context.c index a25e2f78..f6452d4e 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -430,7 +430,7 @@ static void setup_context(pa_context *c, pa_iochannel *io) { ucred.pid = getpid(); ucred.uid = getuid(); - if ((ucred.gid = pa_get_gid_of_group(PA_ACCESS_GROUP)) == (gid_t) -1) + if ((ucred.gid = pa_get_gid_of_group(c->conf->access_group)) == (gid_t) -1) ucred.gid = getgid(); pa_pstream_send_tagstruct_with_creds(c->pstream, t, &ucred); -- cgit From a382492204ad3588c0c837e120e5bc31578df72a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Jul 2006 21:48:35 +0000 Subject: * add new function pa_check_in_group() * abstract credential APis a little bit by introducing HAVE_CREDS and a structure pa_creds * rework credential authentication * fix module-volume-restore and friends for usage in system-wide instance * remove loopback= argument from moulde-*-protocol-tcp since it is a superset of listen= and usually a bad idea anyway since the user shouldn't load the TCP module at all if he doesn't want remote access * rename a few variables in the jack modules to make sure they don't conflict with symbols defined in the system headers * add server address for system-wide daemons to the default server list for the the client libs * update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1109 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/daemon-conf.c | 4 +-- src/daemon/main.c | 3 +- src/modules/module-jack-sink.c | 6 ++-- src/modules/module-jack-source.c | 6 ++-- src/modules/module-match.c | 2 +- src/modules/module-protocol-stub.c | 19 +++--------- src/modules/module-tunnel.c | 2 +- src/modules/module-volume-restore.c | 2 +- src/pulse/client-conf.c | 2 +- src/pulse/context.c | 22 ++++++++----- src/pulsecore/core-util.c | 61 ++++++++++++++++++++++++++----------- src/pulsecore/core-util.h | 1 + src/pulsecore/creds.h | 44 ++++++++++++++++++++++++++ src/pulsecore/iochannel.c | 44 +++++++++----------------- src/pulsecore/iochannel.h | 9 +++--- src/pulsecore/pdispatch.c | 6 ++-- src/pulsecore/pdispatch.h | 9 +++--- src/pulsecore/protocol-native.c | 55 ++++++++++++++++++++++----------- src/pulsecore/pstream-util.c | 2 +- src/pulsecore/pstream-util.h | 5 ++- src/pulsecore/pstream.c | 27 ++++++++-------- src/pulsecore/pstream.h | 8 ++--- src/pulsecore/socket-server.c | 9 +++++- todo | 6 +++- 24 files changed, 221 insertions(+), 133 deletions(-) create mode 100644 src/pulsecore/creds.h diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index a5a62567..2577578c 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -46,9 +46,9 @@ #endif #define DEFAULT_SCRIPT_FILE PA_DEFAULT_CONFIG_DIR PATH_SEP "default.pa" -#define DEFAULT_SCRIPT_FILE_USER ".pulse" PATH_SEP "default.pa" +#define DEFAULT_SCRIPT_FILE_USER PATH_SEP "default.pa" #define DEFAULT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PATH_SEP "daemon.conf" -#define DEFAULT_CONFIG_FILE_USER ".pulse" PATH_SEP "daemon.conf" +#define DEFAULT_CONFIG_FILE_USER PATH_SEP "daemon.conf" #define ENV_SCRIPT_FILE "PULSE_SCRIPT" #define ENV_CONFIG_FILE "PULSE_CONFIG" diff --git a/src/daemon/main.c b/src/daemon/main.c index 4961f0ca..0449cb94 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -229,6 +229,7 @@ static int change_user(void) { /* Relevant for pa_runtime_path() */ set_env("PULSE_RUNTIME_PATH", PA_SYSTEM_RUNTIME_PATH); + set_env("PULSE_CONFIG_PATH", PA_SYSTEM_RUNTIME_PATH); pa_log_info(__FILE__": Successfully dropped root privileges."); @@ -245,8 +246,6 @@ static int create_runtime_dir(void) { return -1; } - /* Relevant for pa_runtime_path() later on */ - set_env("PULSE_RUNTIME_PATH", fn); return 0; } diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index d761c1f7..c645caa9 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -242,7 +242,7 @@ int pa__init(pa_core *c, pa_module*m) { jack_status_t status; const char *server_name, *client_name; uint32_t channels = 0; - int connect = 1; + int do_connect = 1; unsigned i; const char **ports = NULL, **p; @@ -256,7 +256,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - if (pa_modargs_get_value_boolean(ma, "connect", &connect) < 0) { + if (pa_modargs_get_value_boolean(ma, "connect", &do_connect) < 0) { pa_log(__FILE__": failed to parse connect= argument."); goto fail; } @@ -339,7 +339,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - if (connect) { + if (do_connect) { for (i = 0, p = ports; i < ss.channels; i++, p++) { if (!*p) { diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index 649a8f98..2a492929 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -240,7 +240,7 @@ int pa__init(pa_core *c, pa_module*m) { jack_status_t status; const char *server_name, *client_name; uint32_t channels = 0; - int connect = 1; + int do_connect = 1; unsigned i; const char **ports = NULL, **p; @@ -254,7 +254,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - if (pa_modargs_get_value_boolean(ma, "connect", &connect) < 0) { + if (pa_modargs_get_value_boolean(ma, "connect", &do_connect) < 0) { pa_log(__FILE__": failed to parse connect= argument."); goto fail; } @@ -337,7 +337,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - if (connect) { + if (do_connect) { for (i = 0, p = ports; i < ss.channels; i++, p++) { if (!*p) { diff --git a/src/modules/module-match.c b/src/modules/module-match.c index cd58a838..ab94b02d 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -53,7 +53,7 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define WHITESPACE "\n\r \t" #define DEFAULT_MATCH_TABLE_FILE PA_DEFAULT_CONFIG_DIR"/match.table" -#define DEFAULT_MATCH_TABLE_FILE_USER ".pulse/match.table" +#define DEFAULT_MATCH_TABLE_FILE_USER "match.table" static const char* const valid_modargs[] = { "table", diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index fa21b737..ecbc5676 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -52,10 +52,11 @@ #include #include #include +#include #ifdef USE_TCP_SOCKETS #define SOCKET_DESCRIPTION "(TCP sockets)" -#define SOCKET_USAGE "port= loopback= listen=
        " +#define SOCKET_USAGE "port= listen=
        " #else #define SOCKET_DESCRIPTION "(UNIX sockets)" #define SOCKET_USAGE "socket=" @@ -127,9 +128,9 @@ #include "module-native-protocol-unix-symdef.h" #endif - #if defined(SCM_CREDENTIALS) && !defined(USE_TCP_SOCKETS) - #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-group", - #define AUTH_USAGE "auth-group=" + #if defined(HAVE_CREDS) && !defined(USE_TCP_SOCKETS) + #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-group", "auth-group-enable=" + #define AUTH_USAGE "auth-group= auth-group-enable= " #else #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON #define AUTH_USAGE @@ -171,7 +172,6 @@ static const char* const valid_modargs[] = { MODULE_ARGUMENTS #if defined(USE_TCP_SOCKETS) "port", - "loopback", "listen", #else "socket", @@ -197,7 +197,6 @@ int pa__init(pa_core *c, pa_module*m) { #if defined(USE_TCP_SOCKETS) pa_socket_server *s_ipv4 = NULL, *s_ipv6 = NULL; - int loopback = 1; uint32_t port = IPV4_PORT; const char *listen_on; #else @@ -216,11 +215,6 @@ int pa__init(pa_core *c, pa_module*m) { u = pa_xnew0(struct userdata, 1); #if defined(USE_TCP_SOCKETS) - if (pa_modargs_get_value_boolean(ma, "loopback", &loopback) < 0) { - pa_log(__FILE__": loopback= expects a boolean argument."); - goto fail; - } - if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) { pa_log(__FILE__": port= expects a numerical argument between 1 and 65535."); goto fail; @@ -231,9 +225,6 @@ int pa__init(pa_core *c, pa_module*m) { if (listen_on) { s_ipv6 = pa_socket_server_new_ipv6_string(c->mainloop, listen_on, port, TCPWRAP_SERVICE); s_ipv4 = pa_socket_server_new_ipv4_string(c->mainloop, listen_on, port, TCPWRAP_SERVICE); - } else if (loopback) { - s_ipv6 = pa_socket_server_new_ipv6_loopback(c->mainloop, port, TCPWRAP_SERVICE); - s_ipv4 = pa_socket_server_new_ipv4_loopback(c->mainloop, port, TCPWRAP_SERVICE); } else { s_ipv6 = pa_socket_server_new_ipv6_any(c->mainloop, port, TCPWRAP_SERVICE); s_ipv4 = pa_socket_server_new_ipv4_any(c->mainloop, port, TCPWRAP_SERVICE); diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index c018c520..2fb34d12 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -611,7 +611,7 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { } -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const struct ucred *creds, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) { struct userdata *u = userdata; assert(p && packet && u); diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index 2f45082b..d0956509 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -53,7 +53,7 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define WHITESPACE "\n\r \t" -#define DEFAULT_VOLUME_TABLE_FILE ".pulse/volume.table" +#define DEFAULT_VOLUME_TABLE_FILE "volume.table" static const char* const valid_modargs[] = { "table", diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c index 28b4f2d1..21917597 100644 --- a/src/pulse/client-conf.c +++ b/src/pulse/client-conf.c @@ -46,7 +46,7 @@ #endif #define DEFAULT_CLIENT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PATH_SEP "client.conf" -#define DEFAULT_CLIENT_CONFIG_FILE_USER ".pulse" PATH_SEP "client.conf" +#define DEFAULT_CLIENT_CONFIG_FILE_USER "client.conf" #define ENV_CLIENT_CONFIG_FILE "PULSE_CLIENTCONFIG" #define ENV_DEFAULT_SINK "PULSE_SINK" diff --git a/src/pulse/context.c b/src/pulse/context.c index f6452d4e..0150204c 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -62,6 +62,7 @@ #include #include #include +#include #include "internal.h" @@ -272,7 +273,7 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED); } -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const struct ucred *creds, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) { pa_context *c = userdata; assert(p); @@ -423,15 +424,17 @@ static void setup_context(pa_context *c, pa_iochannel *io) { pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION); pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie)); -#ifdef SCM_CREDENTIALS +#ifdef HAVE_CREDS { - struct ucred ucred; + pa_creds ucred; + gid_t g; - ucred.pid = getpid(); ucred.uid = getuid(); + ucred.gid = getgid(); - if ((ucred.gid = pa_get_gid_of_group(c->conf->access_group)) == (gid_t) -1) - ucred.gid = getgid(); + if ((g = pa_get_gid_of_group(c->conf->access_group)) != (gid_t) -1) + if (pa_check_in_group(g) > 0) + ucred.gid = g; pa_pstream_send_tagstruct_with_creds(c->pstream, t, &ucred); } @@ -690,7 +693,12 @@ int pa_context_connect( } c->server_list = pa_strlist_prepend(c->server_list, "tcp6:localhost"); - c->server_list = pa_strlist_prepend(c->server_list, "localhost"); + c->server_list = pa_strlist_prepend(c->server_list, "tcp4:localhost"); + + /* The system wide instance */ + c->server_list = pa_strlist_prepend(c->server_list, PA_SYSTEM_RUNTIME_PATH "/" PA_NATIVE_DEFAULT_UNIX_SOCKET); + + /* The per-user instance */ c->server_list = pa_strlist_prepend(c->server_list, pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET, ufn, sizeof(ufn))); /* Wrap the connection attempts in a single transaction for sane autospawn locking */ diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 6375e5ef..0e6501b8 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -741,6 +741,20 @@ finish: return ret; } +int pa_check_in_group(gid_t g) { + gid_t gids[NGROUPS_MAX]; + int r; + + if ((r = getgroups(NGROUPS_MAX, gids)) < 0) + return -1; + + for (; r > 0; r--) + if (gids[r-1] == g) + return 1; + + return 0; +} + #else /* HAVE_GRP_H */ int pa_own_uid_in_group(const char *name, gid_t *gid) { @@ -752,6 +766,14 @@ int pa_uid_in_group(uid_t uid, const char *name) { return -1; } +gid_t pa_get_gid_of_group(const char *name) { + return (gid_t) -1; +} + +int pa_check_in_group(gid_t g) { + return -1; +} + #endif /* Lock or unlock a file entirely. @@ -909,28 +931,33 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env return fopen(fn, mode); } - if (local && pa_get_home_dir(h, sizeof(h))) { - FILE *f; - char *lfn; - - fn = lfn = pa_sprintf_malloc("%s/%s", h, local); + if (local) { + const char *e; + char *lfn = NULL; + if ((e = getenv("PULSE_CONFIG_PATH"))) + fn = lfn = pa_sprintf_malloc("%s/%s", e, local); + else if (pa_get_home_dir(h, sizeof(h))) + fn = lfn = pa_sprintf_malloc("%s/.pulse/%s", h, local); + + if (lfn) { + FILE *f; + #ifdef OS_IS_WIN32 - if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) - return NULL; - fn = buf; + if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) + return NULL; + fn = buf; #endif - - f = fopen(fn, mode); - - if (f || errno != ENOENT) { - if (result) - *result = pa_xstrdup(fn); + + if ((f = fopen(fn, mode)) || errno != ENOENT) { + if (result) + *result = pa_xstrdup(fn); + pa_xfree(lfn); + return f; + } + pa_xfree(lfn); - return f; } - - pa_xfree(lfn); } if (!global) { diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index db764de1..ba325968 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -67,6 +67,7 @@ const char *pa_strsignal(int sig); int pa_own_uid_in_group(const char *name, gid_t *gid); int pa_uid_in_group(uid_t uid, const char *name); gid_t pa_get_gid_of_group(const char *name); +int pa_check_in_group(gid_t g); int pa_lock_fd(int fd, int b); diff --git a/src/pulsecore/creds.h b/src/pulsecore/creds.h new file mode 100644 index 00000000..a95f4480 --- /dev/null +++ b/src/pulsecore/creds.h @@ -0,0 +1,44 @@ +#ifndef foocredshfoo +#define foocredshfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include + +typedef struct pa_creds pa_creds; + +#if defined(SCM_CREDENTIALS) + +#define HAVE_CREDS 1 + +struct pa_creds { + gid_t gid; + uid_t uid; +}; + +#else +#undef HAVE_CREDS +#endif + +#endif diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c index 852e960e..b50293bf 100644 --- a/src/pulsecore/iochannel.c +++ b/src/pulsecore/iochannel.c @@ -231,7 +231,7 @@ ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) { return r; } -#ifdef SCM_CREDENTIALS +#ifdef HAVE_CREDS int pa_iochannel_creds_supported(pa_iochannel *io) { struct sockaddr_un sa; @@ -263,7 +263,7 @@ int pa_iochannel_creds_enable(pa_iochannel *io) { return 0; } -ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const struct ucred *ucred) { +ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const pa_creds *ucred) { ssize_t r; struct msghdr mh; struct iovec iov; @@ -288,10 +288,11 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l u = (struct ucred*) CMSG_DATA(cmsg); - if (ucred) - *u = *ucred; - else { - u->pid = getpid(); + u->pid = getpid(); + if (ucred) { + u->uid = ucred->uid; + u->gid = ucred->gid; + } else { u->uid = getuid(); u->gid = getgid(); } @@ -313,7 +314,7 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l return r; } -ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struct ucred *ucred, int *creds_valid) { +ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *creds, int *creds_valid) { ssize_t r; struct msghdr mh; struct iovec iov; @@ -323,7 +324,7 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struc assert(data); assert(l); assert(io->ifd >= 0); - assert(ucred); + assert(creds); assert(creds_valid); memset(&iov, 0, sizeof(iov)); @@ -349,8 +350,12 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struc for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) { + struct ucred u; assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))); - memcpy(ucred, CMSG_DATA(cmsg), sizeof(struct ucred)); + memcpy(&u, CMSG_DATA(cmsg), sizeof(struct ucred)); + + creds->gid = u.gid; + creds->uid = u.uid; *creds_valid = 1; break; } @@ -362,27 +367,8 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struc return r; } -#else /* SCM_CREDENTIALS */ - -int pa_iochannel_creds_supported(pa_iochannel *io) { - return 0; -} - -int pa_iochannel_creds_enable(pa_iochannel *io) { - return -1; -} - -ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l) { - pa_log_error("pa_iochannel_write_with_creds() not supported."); - return -1; -} - -ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struct ucred *ucred, int *creds_valid) { - pa_log_error("pa_iochannel_read_with_creds() not supported."); - return -1; -} -#endif /* SCM_CREDENTIALS */ +#endif /* HAVE_CREDS */ void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) { assert(io); diff --git a/src/pulsecore/iochannel.h b/src/pulsecore/iochannel.h index 3b5cba1c..1f9ab0d4 100644 --- a/src/pulsecore/iochannel.h +++ b/src/pulsecore/iochannel.h @@ -25,6 +25,7 @@ #include #include +#include /* A wrapper around UNIX file descriptors for attaching them to the a main event loop. Everytime new data may be read or be written to @@ -49,13 +50,13 @@ void pa_iochannel_free(pa_iochannel*io); ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l); ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l); +#ifdef HAVE_CREDS int pa_iochannel_creds_supported(pa_iochannel *io); int pa_iochannel_creds_enable(pa_iochannel *io); -struct ucred; - -ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const struct ucred *ucred); -ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, struct ucred *ucred, int *creds_valid); +ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const pa_creds *ucred); +ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *ucred, int *creds_valid); +#endif int pa_iochannel_is_readable(pa_iochannel*io); int pa_iochannel_is_writable(pa_iochannel*io); diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c index 9bc20da4..db54b2a3 100644 --- a/src/pulsecore/pdispatch.c +++ b/src/pulsecore/pdispatch.c @@ -112,7 +112,7 @@ struct pa_pdispatch { PA_LLIST_HEAD(struct reply_info, replies); pa_pdispatch_drain_callback drain_callback; void *drain_userdata; - const void *creds; + const pa_creds *creds; }; static void reply_info_free(struct reply_info *r) { @@ -180,7 +180,7 @@ static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command, pa_pdispatch_unref(pd); } -int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const struct ucred *creds, void *userdata) { +int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds, void *userdata) { uint32_t tag, command; pa_tagstruct *ts = NULL; int ret = -1; @@ -310,7 +310,7 @@ pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd) { return pd; } -const struct ucred * pa_pdispatch_creds(pa_pdispatch *pd) { +const pa_creds * pa_pdispatch_creds(pa_pdispatch *pd) { assert(pd); assert(pd->ref >= 1); diff --git a/src/pulsecore/pdispatch.h b/src/pulsecore/pdispatch.h index 18073502..479eb6b4 100644 --- a/src/pulsecore/pdispatch.h +++ b/src/pulsecore/pdispatch.h @@ -23,12 +23,13 @@ ***/ #include + #include #include + #include #include - -struct ucred; +#include typedef struct pa_pdispatch pa_pdispatch; @@ -39,7 +40,7 @@ pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *m, const pa_pdispatch_cb_t*table void pa_pdispatch_unref(pa_pdispatch *pd); pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd); -int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*p, const struct ucred*creds, void *userdata); +int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*p, const pa_creds *creds, void *userdata); void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t callback, void *userdata, pa_free_cb_t free_cb); @@ -50,6 +51,6 @@ void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, pa_pdispatch_drain_callba /* Remove all reply slots with the give userdata parameter */ void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata); -const struct ucred * pa_pdispatch_creds(pa_pdispatch *pd); +const pa_creds * pa_pdispatch_creds(pa_pdispatch *pd); #endif diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 14f880d7..2775d774 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -55,6 +55,8 @@ #include #include #include +#include +#include #include "protocol-native.h" @@ -134,7 +136,7 @@ struct pa_protocol_native { pa_idxset *connections; uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; int auth_cookie_in_property; -#ifdef SCM_CREDENTIALS +#ifdef HAVE_CREDS char *auth_group; #endif }; @@ -910,25 +912,32 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t if (!c->authorized) { int success = 0; -#ifdef SCM_CREDENTIALS - const struct ucred *ucred = pa_pdispatch_creds(pd); +#ifdef HAVE_CREDS + const pa_creds *creds; - if (ucred) { - if (ucred->uid == getuid()) + if ((creds = pa_pdispatch_creds(pd))) { + if (creds->uid == getuid()) success = 1; else if (c->protocol->auth_group) { int r; - - if ((r = pa_uid_in_group(ucred->uid, c->protocol->auth_group)) < 0) - pa_log_warn(__FILE__": failed to check group membership."); - else if (r > 0) + gid_t gid; + + if ((gid = pa_get_gid_of_group(c->protocol->auth_group)) == (gid_t) -1) + pa_log_warn(__FILE__": failed to get GID of group '%s'", c->protocol->auth_group); + else if (gid == creds->gid) success = 1; + + if (!success) { + if ((r = pa_uid_in_group(creds->uid, c->protocol->auth_group)) < 0) + pa_log_warn(__FILE__": failed to check group membership."); + else if (r > 0) + success = 1; + } } - pa_log_info(__FILE__": Got credentials: pid=%lu uid=%lu gid=%lu auth=%i", - (unsigned long) ucred->pid, - (unsigned long) ucred->uid, - (unsigned long) ucred->gid, + pa_log_info(__FILE__": Got credentials: uid=%lu gid=%lu success=%i", + (unsigned long) creds->uid, + (unsigned long) creds->gid, success); } #endif @@ -2100,7 +2109,7 @@ static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC /*** pstream callbacks ***/ -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const struct ucred *creds, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) { struct connection *c = userdata; assert(p && packet && packet->data && c); @@ -2272,7 +2281,7 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo pa_idxset_put(p->connections, c, NULL); -#ifdef SCM_CREDENTIALS +#ifdef HAVE_CREDS if (pa_iochannel_creds_supported(io)) pa_iochannel_creds_enable(io); @@ -2323,8 +2332,18 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo p->public = public; p->server = NULL; -#ifdef SCM_CREDENTIALS - p->auth_group = pa_xstrdup(pa_modargs_get_value(ma, "auth-group", NULL)); +#ifdef HAVE_CREDS + { + int a = 1; + if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &a) < 0) { + pa_log(__FILE__": auth-group-enabled= expects a boolean argument."); + return NULL; + } + p->auth_group = a ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", c->is_system_instance ? PA_ACCESS_GROUP : NULL)) : NULL; + + if (p->auth_group) + pa_log_info(__FILE__": Allowing access to group '%s'.", p->auth_group); + } #endif if (load_key(p, pa_modargs_get_value(ma, "cookie", NULL)) < 0) { @@ -2386,7 +2405,7 @@ void pa_protocol_native_free(pa_protocol_native *p) { if (p->auth_cookie_in_property) pa_authkey_prop_unref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); -#ifdef SCM_CREDENTIALS +#ifdef HAVE_CREDS pa_xfree(p->auth_group); #endif pa_xfree(p); diff --git a/src/pulsecore/pstream-util.c b/src/pulsecore/pstream-util.c index 09d6f2fa..d7c1b31b 100644 --- a/src/pulsecore/pstream-util.c +++ b/src/pulsecore/pstream-util.c @@ -29,7 +29,7 @@ #include "pstream-util.h" -void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, const struct ucred *creds) { +void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, const pa_creds *creds) { size_t length; uint8_t *data; pa_packet *packet; diff --git a/src/pulsecore/pstream-util.h b/src/pulsecore/pstream-util.h index c60000a8..f384d889 100644 --- a/src/pulsecore/pstream-util.h +++ b/src/pulsecore/pstream-util.h @@ -25,11 +25,10 @@ #include #include #include - -struct ucred; +#include /* The tagstruct is freed!*/ -void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, const struct ucred *creds); +void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, const pa_creds *creds); #define pa_pstream_send_tagstruct(p, t) pa_pstream_send_tagstruct_with_creds((p), (t), 0) diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index 7ef49305..de5fa43e 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "pstream.h" @@ -69,9 +70,9 @@ struct item_info { /* packet info */ pa_packet *packet; -#ifdef SCM_CREDENTIALS +#ifdef HAVE_CREDS int with_creds; - struct ucred creds; + pa_creds creds; #endif }; @@ -114,8 +115,8 @@ struct pa_pstream { pa_memblock_stat *memblock_stat; -#ifdef SCM_CREDENTIALS - struct ucred read_creds, write_creds; +#ifdef HAVE_CREDS + pa_creds read_creds, write_creds; int read_creds_valid, send_creds_now; #endif }; @@ -216,7 +217,7 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_sta pa_iochannel_socket_set_rcvbuf(io, 1024*8); pa_iochannel_socket_set_sndbuf(io, 1024*8); -#ifdef SCM_CREDENTIALS +#ifdef HAVE_CREDS p->send_creds_now = 0; p->read_creds_valid = 0; #endif @@ -258,7 +259,7 @@ static void pstream_free(pa_pstream *p) { pa_xfree(p); } -void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const struct ucred *creds) { +void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *creds) { struct item_info *i; assert(p && packet && p->ref >= 1); @@ -270,7 +271,7 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const struct ucred i = pa_xnew(struct item_info, 1); i->type = PA_PSTREAM_ITEM_PACKET; i->packet = pa_packet_ref(packet); -#ifdef SCM_CREDENTIALS +#ifdef HAVE_CREDS if ((i->with_creds = !!creds)) i->creds = *creds; #endif @@ -294,7 +295,7 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa i->channel = channel; i->offset = offset; i->seek_mode = seek_mode; -#ifdef SCM_CREDENTIALS +#ifdef HAVE_CREDS i->with_creds = 0; #endif @@ -334,7 +335,7 @@ static void prepare_next_write_item(pa_pstream *p) { p->write.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK] = htonl(p->write.current->seek_mode); } -#ifdef SCM_CREDENTIALS +#ifdef HAVE_CREDS if ((p->send_creds_now = p->write.current->with_creds)) p->write_creds = p->write.current->creds; @@ -364,7 +365,7 @@ static int do_write(pa_pstream *p) { l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE); } -#ifdef SCM_CREDENTIALS +#ifdef HAVE_CREDS if (p->send_creds_now) { if ((r = pa_iochannel_write_with_creds(p->io, d, l, &p->write_creds)) < 0) @@ -406,7 +407,7 @@ static int do_read(pa_pstream *p) { l = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE); } -#ifdef SCM_CREDENTIALS +#ifdef HAVE_CREDS { int b = 0; @@ -495,7 +496,7 @@ static int do_read(pa_pstream *p) { assert(p->read.packet); if (p->recieve_packet_callback) -#ifdef SCM_CREDENTIALS +#ifdef HAVE_CREDS p->recieve_packet_callback(p, p->read.packet, p->read_creds_valid ? &p->read_creds : NULL, p->recieve_packet_callback_userdata); #else p->recieve_packet_callback(p, p->read.packet, NULL, p->recieve_packet_callback_userdata); @@ -506,7 +507,7 @@ static int do_read(pa_pstream *p) { } p->read.index = 0; -#ifdef SCM_CREDENTIALS +#ifdef HAVE_CREDS p->read_creds_valid = 0; #endif } diff --git a/src/pulsecore/pstream.h b/src/pulsecore/pstream.h index 39cb7591..789e40bc 100644 --- a/src/pulsecore/pstream.h +++ b/src/pulsecore/pstream.h @@ -26,16 +26,16 @@ #include #include + #include #include #include #include - -struct ucred; +#include typedef struct pa_pstream pa_pstream; -typedef void (*pa_pstream_packet_cb_t)(pa_pstream *p, pa_packet *packet, const struct ucred *creds, void *userdata); +typedef void (*pa_pstream_packet_cb_t)(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata); typedef void (*pa_pstream_memblock_cb_t)(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata); typedef void (*pa_pstream_notify_cb_t)(pa_pstream *p, void *userdata); @@ -43,7 +43,7 @@ pa_pstream* pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_sta void pa_pstream_unref(pa_pstream*p); pa_pstream* pa_pstream_ref(pa_pstream*p); -void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const struct ucred *creds); +void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *creds); void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk); void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata); diff --git a/src/pulsecore/socket-server.c b/src/pulsecore/socket-server.c index 77ea13e7..25483592 100644 --- a/src/pulsecore/socket-server.c +++ b/src/pulsecore/socket-server.c @@ -30,6 +30,7 @@ #include #include #include +#include #ifdef HAVE_SYS_SOCKET_H #include @@ -185,12 +186,18 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file sa.sun_path[sizeof(sa.sun_path) - 1] = 0; pa_socket_low_delay(fd); - + if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) { pa_log(__FILE__": bind(): %s", pa_cstrerror(errno)); goto fail; } + /* Allow access from all clients. Sockets like this one should + * always be put inside a directory with proper access rights, + * because not all OS check the access rights on the socket + * inodes. */ + chmod(filename, 0777); + if (listen(fd, 5) < 0) { pa_log(__FILE__": listen(): %s", pa_cstrerror(errno)); goto fail; diff --git a/todo b/todo index 07d022b7..0173ccd9 100644 --- a/todo +++ b/todo @@ -3,7 +3,6 @@ Post 0.9.0: - alsa mmap driver - dbus/hal (Shams King is working on this one) -- polish for starting polypaudio as root/system-wide instance - chroot() - module-tunnel: improve latency calculation - multiline configuration statements @@ -32,6 +31,11 @@ Post 0.9.0: - gconf module + frontend - hooks for creating sink inputs - insert the low-level device name in the default sink/source name, to make them recognizable +- ssl +- key rings for auth +- challenge response auth +- sasl auth +- setrlimit Long term: - pass meta info for hearing impaired -- cgit From 703bb49c91a53d03ec55a704d895f59bfbafd8b0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Jul 2006 23:16:02 +0000 Subject: add a few comments git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1110 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/main.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/daemon/main.c b/src/daemon/main.c index 0449cb94..cf655ee0 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -158,6 +158,10 @@ static int change_user(void) { struct passwd *pw; struct group * gr; int r; + + /* This function is called only in system-wide mode. It creates a + * runtime dir in /var/run/ with proper UID/GID and drops privs + * afterwards. */ if (!(pw = getpwnam(PA_SYSTEM_USER))) { pa_log(__FILE__": Failed to find user '%s'.", PA_SYSTEM_USER); @@ -238,8 +242,12 @@ static int change_user(void) { static int create_runtime_dir(void) { char fn[PATH_MAX]; - + pa_runtime_path(NULL, fn, sizeof(fn)); + + /* This function is called only when the daemon is started in + * per-user mode. We create the runtime directory somewhere in + * /tmp/ with the current UID/GID */ if (pa_make_secure_dir(fn, 0700, getuid(), getgid()) < 0) { pa_log(__FILE__": Failed to create '%s': %s", fn, pa_cstrerror(errno)); -- cgit From 2ad69389d4a584a1058474341ee959c6cfc070a2 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 20 Jul 2006 00:12:52 +0000 Subject: Remove unneeded headers. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1111 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/creds.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pulsecore/creds.h b/src/pulsecore/creds.h index a95f4480..a2acae04 100644 --- a/src/pulsecore/creds.h +++ b/src/pulsecore/creds.h @@ -23,8 +23,6 @@ ***/ #include -#include -#include typedef struct pa_creds pa_creds; -- cgit From 7ba93ebae21742522bfe430e229a859370a888d1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 20 Jul 2006 00:13:12 +0000 Subject: Protect platform dependent headers with ifdefs. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1112 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/context.c | 5 +++-- src/pulsecore/pstream.c | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/pulse/context.c b/src/pulse/context.c index 0150204c..efc1685b 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -33,8 +33,6 @@ #include #include #include -#include -#include #ifdef HAVE_SYS_WAIT_H #include @@ -43,6 +41,9 @@ #ifdef HAVE_SYS_SOCKET_H #include #endif +#ifdef HAVE_SYS_UN_H +#include +#endif #ifdef HAVE_NETDB_H #include #endif diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index de5fa43e..7096d65a 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -27,9 +27,13 @@ #include #include #include + +#ifdef HAVE_SYS_SOCKET_H #include +#endif +#ifdef HAVE_SYS_UN_H #include - +#endif #ifdef HAVE_NETINET_IN_H #include #endif -- cgit From a3e7595ac179ca32bc5c876b25a4e80171c3d917 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 20 Jul 2006 00:21:50 +0000 Subject: Make -1 mean "current group/user" so that some platform dependent calls can be centralised. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1113 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/main.c | 2 +- src/modules/module-protocol-stub.c | 2 +- src/pulse/context.c | 2 +- src/pulsecore/core-util.c | 4 ++++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/daemon/main.c b/src/daemon/main.c index cf655ee0..948b2055 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -249,7 +249,7 @@ static int create_runtime_dir(void) { * per-user mode. We create the runtime directory somewhere in * /tmp/ with the current UID/GID */ - if (pa_make_secure_dir(fn, 0700, getuid(), getgid()) < 0) { + if (pa_make_secure_dir(fn, 0700, (uid_t)-1, (gid_t)-1) < 0) { pa_log(__FILE__": Failed to create '%s': %s", fn, pa_cstrerror(errno)); return -1; } diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index ecbc5676..36d7db89 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -254,7 +254,7 @@ int pa__init(pa_core *c, pa_module*m) { /* This socket doesn't reside in our own runtime dir but in * /tmp/.esd/, hence we have to create the dir first */ - if (pa_make_secure_parent_dir(u->socket_path, c->is_system_instance ? 0755 : 0700, getuid(), getgid()) < 0) { + if (pa_make_secure_parent_dir(u->socket_path, c->is_system_instance ? 0755 : 0700, (uid_t)-1, (gid_t)-1) < 0) { pa_log(__FILE__": Failed to create socket directory: %s\n", pa_cstrerror(errno)); goto fail; } diff --git a/src/pulse/context.c b/src/pulse/context.c index efc1685b..30a257fe 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -707,7 +707,7 @@ int pa_context_connect( char lf[PATH_MAX]; pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); - pa_make_secure_parent_dir(lf, 0700, getuid(), getgid()); + pa_make_secure_parent_dir(lf, 0700, (uid_t)-1, (gid_t)-1); assert(c->autospawn_lock_fd <= 0); c->autospawn_lock_fd = pa_lock_lockfile(lf); diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 0e6501b8..595ef939 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -157,6 +157,10 @@ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) { return -1; #ifdef HAVE_CHOWN + if (uid == (uid_t)-1) + uid = getuid(); + if (gid == (gid_t)-1) + gid = getgid(); chown(dir, uid, gid); #endif -- cgit From 246e30aec74c76fd7db53f4c537a4c90b87d5ea4 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 20 Jul 2006 00:28:18 +0000 Subject: Add missing header. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1114 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/daemon/main.c b/src/daemon/main.c index 948b2055..63452f6f 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -55,6 +55,7 @@ #include #include +#include #include #include -- cgit From 0ff247db7303d7c452d62bcfc1291075f297dcbd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Jul 2006 00:52:44 +0000 Subject: undo r1111 in some way: include sys/socket.h and sys/un.h but wrap it in #ifdef HAVE_xxx_H. This should be safe because config.h should be the first included header in all .c files and creds.h is never included by any external tools git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1115 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/creds.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/pulsecore/creds.h b/src/pulsecore/creds.h index a2acae04..d92ce598 100644 --- a/src/pulsecore/creds.h +++ b/src/pulsecore/creds.h @@ -24,6 +24,16 @@ #include +/* config.h must be included before this file */ + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef HAVE_SYS_UN_H +#include +#endif + typedef struct pa_creds pa_creds; #if defined(SCM_CREDENTIALS) -- cgit From 2409f1a80b708ead6c48ebbb568bd2b7d6d3af31 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Jul 2006 01:25:37 +0000 Subject: add support to set resource limits for the daemon and set some of them to some sane values git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1116 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/daemon-conf.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++ src/daemon/daemon-conf.h | 22 +++++++++++++ src/daemon/daemon.conf.in | 10 ++++++ src/daemon/main.c | 37 ++++++++++++++++++++- todo | 2 +- 5 files changed, 153 insertions(+), 2 deletions(-) diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 2577578c..12ee0800 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -73,6 +73,20 @@ static const pa_daemon_conf default_conf = { .config_file = NULL, .use_pid_file = 1, .system_instance = 0 +#ifdef HAVE_SYS_RESOURCE_H + , .rlimit_as = { .value = 0, .is_set = 0 }, + .rlimit_core = { .value = 0, .is_set = 0 }, + .rlimit_data = { .value = 0, .is_set = 0 }, + .rlimit_fsize = { .value = 0, .is_set = 0 }, + .rlimit_nofile = { .value = 25, .is_set = 1 }, + .rlimit_stack = { .value = 0, .is_set = 0 } +#ifdef RLIMIT_NPROC + , .rlimit_nproc = { .value = 0, .is_set = 0 } +#endif +#ifdef RLIMIT_MEMLOCK + , .rlimit_memlock = { .value = 0, .is_set = 1 } +#endif +#endif }; pa_daemon_conf* pa_daemon_conf_new(void) { @@ -184,6 +198,30 @@ static int parse_resample_method(const char *filename, unsigned line, const char return 0; } +static int parse_rlimit(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + pa_rlimit *r = data; + assert(filename); + assert(lvalue); + assert(rvalue); + assert(r); + + if (rvalue[strspn(rvalue, "\t ")] == 0) { + /* Empty string */ + r->is_set = 0; + r->value = 0; + } else { + int32_t k; + if (pa_atoi(rvalue, &k) < 0) { + pa_log(__FILE__": [%s:%u] Inavalid rlimit '%s'.", filename, line, rvalue); + return -1; + } + r->is_set = k >= 0; + r->value = k >= 0 ? (rlim_t) k : 0; + } + + return 0; +} + int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { int r = -1; FILE *f = NULL; @@ -204,6 +242,20 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { { "resample-method", parse_resample_method, NULL }, { "use-pid-file", pa_config_parse_bool, NULL }, { "system-instance", pa_config_parse_bool, NULL }, +#ifdef HAVE_SYS_RESOURCE_H + { "rlimit-as", parse_rlimit, NULL }, + { "rlimit-core", parse_rlimit, NULL }, + { "rlimit-data", parse_rlimit, NULL }, + { "rlimit-fsize", parse_rlimit, NULL }, + { "rlimit-nofile", parse_rlimit, NULL }, + { "rlimit-stack", parse_rlimit, NULL }, +#ifdef RLIMIT_NPROC + { "rlimit-nproc", parse_rlimit, NULL }, +#endif +#ifdef RLIMIT_MEMLOCK + { "rlimit-memlock", parse_rlimit, NULL }, +#endif +#endif { NULL, NULL, NULL }, }; @@ -222,6 +274,24 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { table[12].data = c; table[13].data = &c->use_pid_file; table[14].data = &c->system_instance; +#ifdef HAVE_SYS_RESOURCE_H + table[15].data = &c->rlimit_as; + table[16].data = &c->rlimit_core; + table[17].data = &c->rlimit_data; + table[18].data = &c->rlimit_fsize; + table[19].data = &c->rlimit_nofile; + table[20].data = &c->rlimit_stack; +#ifdef RLIMIT_NPROC + table[21].data = &c->rlimit_nproc; +#endif +#ifdef RLIMIT_MEMLOCK +#ifndef RLIMIT_NPROC +#error "Houston, we have a numbering problem!" +#endif + table[22].data = &c->rlimit_memlock; +#endif +#endif + pa_xfree(c->config_file); c->config_file = NULL; @@ -289,6 +359,20 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { pa_strbuf_printf(s, "resample-method = %s\n", pa_resample_method_to_string(c->resample_method)); pa_strbuf_printf(s, "use-pid-file = %i\n", c->use_pid_file); pa_strbuf_printf(s, "system-instance = %i\n", !!c->system_instance); +#ifdef HAVE_SYS_RESOURCE_H + pa_strbuf_printf(s, "rlimit-as = %li\n", c->rlimit_as.is_set ? (long int) c->rlimit_as.value : -1); + pa_strbuf_printf(s, "rlimit-core = %li\n", c->rlimit_core.is_set ? (long int) c->rlimit_core.value : -1); + pa_strbuf_printf(s, "rlimit-data = %li\n", c->rlimit_data.is_set ? (long int) c->rlimit_data.value : -1); + pa_strbuf_printf(s, "rlimit-fsize = %li\n", c->rlimit_fsize.is_set ? (long int) c->rlimit_fsize.value : -1); + pa_strbuf_printf(s, "rlimit-nofile = %li\n", c->rlimit_nofile.is_set ? (long int) c->rlimit_nofile.value : -1); + pa_strbuf_printf(s, "rlimit-stack = %li\n", c->rlimit_stack.is_set ? (long int) c->rlimit_stack.value : -1); +#ifdef RLIMIT_NPROC + pa_strbuf_printf(s, "rlimit-nproc = %li\n", c->rlimit_nproc.is_set ? (long int) c->rlimit_nproc.value : -1); +#endif +#ifdef RLIMIT_MEMLOCK + pa_strbuf_printf(s, "rlimit-memlock = %li\n", c->rlimit_memlock.is_set ? (long int) c->rlimit_memlock.value : -1); +#endif +#endif return pa_strbuf_tostring_free(s); } diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h index bfea7358..a09773f1 100644 --- a/src/daemon/daemon-conf.h +++ b/src/daemon/daemon-conf.h @@ -24,6 +24,10 @@ #include +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif + /* The actual command to execute */ typedef enum pa_daemon_conf_cmd { PA_CMD_DAEMON, /* the default */ @@ -35,6 +39,13 @@ typedef enum pa_daemon_conf_cmd { PA_CMD_CHECK } pa_daemon_conf_cmd_t; +#ifdef HAVE_SYS_RESOURCE_H +typedef struct pa_rlimit { + rlim_t value; + int is_set; +} pa_rlimit; +#endif + /* A structure containing configuration data for the PulseAudio server . */ typedef struct pa_daemon_conf { pa_daemon_conf_cmd_t cmd; @@ -53,6 +64,17 @@ typedef struct pa_daemon_conf { pa_log_level_t log_level; int resample_method; char *config_file; + +#ifdef HAVE_SYS_RESOURCE_H + pa_rlimit rlimit_as, rlimit_core, rlimit_data, rlimit_fsize, rlimit_nofile, rlimit_stack; +#ifdef RLIMIT_NPROC + pa_rlimit rlimit_nproc; +#endif +#ifdef RLIMIT_MEMLOCK + pa_rlimit rlimit_memlock; +#endif +#endif + } pa_daemon_conf; /* Allocate a new structure and fill it with sane defaults */ diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in index 30628969..787405f8 100644 --- a/src/daemon/daemon.conf.in +++ b/src/daemon/daemon.conf.in @@ -81,3 +81,13 @@ ## Run the daemon as system-wide instance, requires root priviliges ; system-instance = 0 + +## Resource limits, see getrlimit(2) for more information +; rlimit-as = -1 +; rlimit-core = -1 +; rlimit-data = -1 +; rlimit-fsize = -1 +; rlimit-nofile = 25 +; rlimit-stack = -1 +; rlimit-nproc = -1 +; rlimit-memlock = 25 diff --git a/src/daemon/main.c b/src/daemon/main.c index 63452f6f..517d9984 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -258,6 +258,37 @@ static int create_runtime_dir(void) { return 0; } +#ifdef HAVE_SYS_RESOURCE_H + +static void set_one_rlimit(const pa_rlimit *r, int resource, const char *name) { + struct rlimit rl; + assert(r); + + if (!r->is_set) + return; + + rl.rlim_cur = rl.rlim_max = r->value; + + if (setrlimit(resource, &rl) < 0) + pa_log_warn(__FILE__": setrlimit(%s, (%u, %u)) failed: %s", name, (unsigned) r->value, (unsigned) r->value, pa_cstrerror(errno)); +} + +static void set_all_rlimits(const pa_daemon_conf *conf) { + set_one_rlimit(&conf->rlimit_as, RLIMIT_AS, "RLIMIT_AS"); + set_one_rlimit(&conf->rlimit_core, RLIMIT_CORE, "RLIMIT_CORE"); + set_one_rlimit(&conf->rlimit_data, RLIMIT_DATA, "RLIMIT_DATA"); + set_one_rlimit(&conf->rlimit_fsize, RLIMIT_FSIZE, "RLIMIT_FSIZE"); + set_one_rlimit(&conf->rlimit_nofile, RLIMIT_NOFILE, "RLIMIT_NOFILE"); + set_one_rlimit(&conf->rlimit_stack, RLIMIT_STACK, "RLIMIT_STACK"); +#ifdef RLIMIT_NPROC + set_one_rlimit(&conf->rlimit_nproc, RLIMIT_NPROC, "RLIMIT_NPROC"); +#endif +#ifdef RLIMIT_MEMLOCK + set_one_rlimit(&conf->rlimit_memlock, RLIMIT_MEMLOCK, "RLIMIT_MEMLOCK"); +#endif +} +#endif + int main(int argc, char *argv[]) { pa_core *c; pa_strbuf *buf = NULL; @@ -335,7 +366,7 @@ int main(int argc, char *argv[]) { if (suid_root) pa_drop_root(); - + if (conf->dl_search_path) lt_dlsetsearchpath(conf->dl_search_path); @@ -502,6 +533,10 @@ int main(int argc, char *argv[]) { valid_pid_file = 1; } +#ifdef HAVE_SYS_RESOURCE_H + set_all_rlimits(conf); +#endif + #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif diff --git a/todo b/todo index 0173ccd9..cdc97373 100644 --- a/todo +++ b/todo @@ -35,7 +35,7 @@ Post 0.9.0: - key rings for auth - challenge response auth - sasl auth -- setrlimit +- IP ACLs Long term: - pass meta info for hearing impaired -- cgit From b12f29d04ba9fcaa6930d52b13880086693c0faa Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 20 Jul 2006 13:07:01 +0000 Subject: Make sure parse_rlimit is only used when rlimits are supported. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1117 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/daemon-conf.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 12ee0800..7184b2e6 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -199,7 +199,8 @@ static int parse_resample_method(const char *filename, unsigned line, const char } static int parse_rlimit(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { - pa_rlimit *r = data; +#ifdef HAVE_SYS_RESOURCE_H + struct pa_rlimit *r = data; assert(filename); assert(lvalue); assert(rvalue); @@ -218,6 +219,9 @@ static int parse_rlimit(const char *filename, unsigned line, const char *lvalue, r->is_set = k >= 0; r->value = k >= 0 ? (rlim_t) k : 0; } +#else + pa_log_warning(__FILE__": [%s:%u] rlimit not supported on this platform.", filename, line); +#endif return 0; } -- cgit From 8d2dc9c4d14fd879aac3e4137b1dfc2c32a338cb Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 20 Jul 2006 13:16:23 +0000 Subject: Handle user switch in a more platform independent manner. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1118 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/main.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/daemon/main.c b/src/daemon/main.c index 517d9984..8b905b31 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -37,8 +37,6 @@ #include #include #include -#include -#include #include @@ -46,6 +44,13 @@ #include #endif +#ifdef HAVE_PWD_H +#include +#endif +#ifdef HAVE_GRP_H +#include +#endif + #ifdef HAVE_LIBWRAP #include #include @@ -155,6 +160,8 @@ static void close_pipe(int p[2]) { #define set_env(key, value) putenv(pa_sprintf_malloc("%s=%s", (key), (value))) +#if defined(HAVE_PWD_H) && defined(HAVE_GRP_H) + static int change_user(void) { struct passwd *pw; struct group * gr; @@ -241,6 +248,15 @@ static int change_user(void) { return 0; } +#else /* HAVE_PWD_H && HAVE_GRP_H */ + +static int change_user(void) { + pa_log(__FILE__": System wide mode unsupported on this platform."); + return -1; +} + +#endif /* HAVE_PWD_H && HAVE_GRP_H */ + static int create_runtime_dir(void) { char fn[PATH_MAX]; -- cgit From 57d8a315ea3c3e4e19e19fe1d293ca941d6229d5 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 20 Jul 2006 13:19:16 +0000 Subject: Move check for SUID into the caps functions. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1119 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/caps.c | 9 +++++++++ src/daemon/main.c | 6 ++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/daemon/caps.c b/src/daemon/caps.c index dc74bc7d..957824d9 100644 --- a/src/daemon/caps.c +++ b/src/daemon/caps.c @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef HAVE_SYS_CAPABILITY_H #include @@ -80,6 +81,10 @@ int pa_limit_caps(void) { cap_t caps; cap_value_t nice_cap = CAP_SYS_NICE; + /* Only drop caps when called SUID */ + if (getuid() != 0) + return 0; + caps = cap_init(); assert(caps); @@ -106,6 +111,10 @@ int pa_drop_caps(void) { cap_t caps; int r = -1; + /* Only drop caps when called SUID */ + if (getuid() != 0) + return 0; + caps = cap_init(); assert(caps); diff --git a/src/daemon/main.c b/src/daemon/main.c index 8b905b31..3f489981 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -328,8 +328,7 @@ int main(int argc, char *argv[]) { setlocale(LC_ALL, ""); - if (getuid() != 0) - pa_limit_caps(); + pa_limit_caps(); #ifdef HAVE_GETUID suid_root = getuid() != 0 && geteuid() == 0; @@ -377,8 +376,7 @@ int main(int argc, char *argv[]) { if (conf->high_priority && conf->cmd == PA_CMD_DAEMON) pa_raise_priority(); - if (getuid() != 0) - pa_drop_caps(); + pa_drop_caps(); if (suid_root) pa_drop_root(); -- cgit From f3d49244731498c009b5c1991cb7242a8e9914ae Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 20 Jul 2006 13:24:04 +0000 Subject: Centralise check if we're running as root. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1120 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/main.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/daemon/main.c b/src/daemon/main.c index 3f489981..14c16ab2 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -314,7 +314,7 @@ int main(int argc, char *argv[]) { char *s; int r, retval = 1, d = 0; int daemon_pipe[2] = { -1, -1 }; - int suid_root; + int suid_root, real_root; int valid_pid_file = 0; #ifdef HAVE_GETUID @@ -331,13 +331,15 @@ int main(int argc, char *argv[]) { pa_limit_caps(); #ifdef HAVE_GETUID - suid_root = getuid() != 0 && geteuid() == 0; + real_root = getuid() == 0; + suid_root = !real_root && geteuid() == 0; if (suid_root && (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) <= 0 || gid >= 1000)) { pa_log_warn(__FILE__": WARNING: called SUID root, but not in group '"PA_REALTIME_GROUP"'."); pa_drop_root(); } #else + real_root = 0; suid_root = 0; #endif @@ -434,10 +436,10 @@ int main(int argc, char *argv[]) { assert(conf->cmd == PA_CMD_DAEMON); } - if (getuid() == 0 && !conf->system_instance) { + if (real_root && !conf->system_instance) { pa_log(__FILE__": This program is not intended to be run as root (unless --system is specified)."); goto finish; - } else if (getuid() != 0 && conf->system_instance) { + } else if (!real_root && conf->system_instance) { pa_log(__FILE__": Root priviliges required."); goto finish; } -- cgit From 0762af2aeed6f590bf5833128185adf902eac0cf Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 20 Jul 2006 13:24:57 +0000 Subject: Only warn when running as root and not --system. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1121 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/daemon/main.c b/src/daemon/main.c index 14c16ab2..d578f508 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -437,8 +437,7 @@ int main(int argc, char *argv[]) { } if (real_root && !conf->system_instance) { - pa_log(__FILE__": This program is not intended to be run as root (unless --system is specified)."); - goto finish; + pa_log_warning(__FILE__": This program is not intended to be run as root (unless --system is specified)."); } else if (!real_root && conf->system_instance) { pa_log(__FILE__": Root priviliges required."); goto finish; -- cgit From 4a59581a4c95c94d97abc7844a097a356c937f0e Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 20 Jul 2006 13:28:50 +0000 Subject: Fix incorrect call to nonexistant pa_log_warning(). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1122 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/daemon-conf.c | 2 +- src/daemon/main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 7184b2e6..894c0434 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -220,7 +220,7 @@ static int parse_rlimit(const char *filename, unsigned line, const char *lvalue, r->value = k >= 0 ? (rlim_t) k : 0; } #else - pa_log_warning(__FILE__": [%s:%u] rlimit not supported on this platform.", filename, line); + pa_log_warn(__FILE__": [%s:%u] rlimit not supported on this platform.", filename, line); #endif return 0; diff --git a/src/daemon/main.c b/src/daemon/main.c index d578f508..3ced3bf6 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -437,7 +437,7 @@ int main(int argc, char *argv[]) { } if (real_root && !conf->system_instance) { - pa_log_warning(__FILE__": This program is not intended to be run as root (unless --system is specified)."); + pa_log_warn(__FILE__": This program is not intended to be run as root (unless --system is specified)."); } else if (!real_root && conf->system_instance) { pa_log(__FILE__": Root priviliges required."); goto finish; -- cgit From 30ada90fd2bce05097a85da86a10ffb52c2ffd35 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Jul 2006 16:48:26 +0000 Subject: add IP address ACL subsystem git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1123 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 14 +++- src/pulsecore/ipacl.c | 216 +++++++++++++++++++++++++++++++++++++++++++++++++ src/pulsecore/ipacl.h | 31 +++++++ src/tests/ipacl-test.c | 117 +++++++++++++++++++++++++++ 4 files changed, 377 insertions(+), 1 deletion(-) create mode 100644 src/pulsecore/ipacl.c create mode 100644 src/pulsecore/ipacl.h create mode 100644 src/tests/ipacl-test.c diff --git a/src/Makefile.am b/src/Makefile.am index d4fbe528..431bedbd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -194,7 +194,8 @@ noinst_PROGRAMS = \ channelmap-test \ thread-mainloop-test \ utf8-test \ - get-binary-name-test + get-binary-name-test \ + ipacl-test if HAVE_SIGXCPU noinst_PROGRAMS += \ @@ -227,6 +228,11 @@ get_binary_name_test_CFLAGS = $(AM_CFLAGS) get_binary_name_test_LDADD = $(AM_LDADD) libpulse.la get_binary_name_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +ipacl_test_SOURCES = tests/ipacl-test.c pulsecore/ipacl.c pulsecore/ipacl.h +ipacl_test_CFLAGS = $(AM_CFLAGS) +ipacl_test_LDADD = $(AM_LDADD) libpulsecore.la +ipacl_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + mcalign_test_SOURCES = tests/mcalign-test.c mcalign_test_CFLAGS = $(AM_CFLAGS) mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpulsecore.la @@ -586,6 +592,7 @@ pulsecoreinclude_HEADERS += \ pulsecore/socket-util.h \ pulsecore/iochannel.h \ pulsecore/socket-server.h \ + pulsecore/ipacl.h \ pulsecore/socket-client.h \ pulsecore/parseaddr.h \ pulsecore/packet.h \ @@ -615,6 +622,7 @@ modlibexec_LTLIBRARIES = \ libsocket-util.la \ libiochannel.la \ libsocket-server.la \ + libipacl.la \ libparseaddr.la \ libsocket-client.la \ libpacket.la \ @@ -668,6 +676,10 @@ libsocket_server_la_SOURCES = \ libsocket_server_la_LDFLAGS = -avoid-version libsocket_server_la_LIBADD = $(AM_LIBADD) libpulsecore.la libiochannel.la libsocket-util.la $(LIBWRAP_LIBS) $(WINSOCK_LIBS) +libipacl_la_SOURCES = pulsecore/ipacl.h pulsecore/ipacl.c +libipacl_la_LDFLAGS = -avoid-version +libipacl_la_LIBADD = $(AM_LIBADD) libpulsecore.la $(WINSOCK_LIBS) + libsocket_client_la_SOURCES = pulsecore/socket-client.c pulsecore/socket-client.h libsocket_client_la_LDFLAGS = -avoid-version libsocket_client_la_LIBADD = $(AM_LIBADD) libpulsecore.la libiochannel.la libsocket-util.la libparseaddr.la $(LIBASYNCNS_LIBS) $(WINSOCK_LIBS) diff --git a/src/pulsecore/ipacl.c b/src/pulsecore/ipacl.c new file mode 100644 index 00000000..06be0a28 --- /dev/null +++ b/src/pulsecore/ipacl.c @@ -0,0 +1,216 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ipacl.h" + +struct acl_entry { + PA_LLIST_FIELDS(struct acl_entry); + int family; + struct in_addr address_ipv4; + struct in6_addr address_ipv6; + int bits; +}; + +struct pa_ip_acl { + PA_LLIST_HEAD(struct acl_entry, entries); +}; + +pa_ip_acl* pa_ip_acl_new(const char *s) { + const char *state = NULL; + char *a; + pa_ip_acl *acl; + + assert(s); + + acl = pa_xnew(pa_ip_acl, 1); + PA_LLIST_HEAD_INIT(struct acl_entry, acl->entries); + + while ((a = pa_split(s, ";", &state))) { + char *slash; + struct acl_entry e, *n; + uint32_t bits; + + if ((slash = strchr(a, '/'))) { + *slash = 0; + slash++; + if (pa_atou(slash, &bits) < 0) { + pa_log(__FILE__": failed to parse number of bits: %s", slash); + goto fail; + } + } else + bits = (uint32_t) -1; + + if (inet_pton(AF_INET, a, &e.address_ipv4) > 0) { + + e.bits = bits == (uint32_t) -1 ? 32 : (int) bits; + + if (e.bits > 32) { + pa_log(__FILE__": number of bits out of range: %i", e.bits); + goto fail; + } + + e.family = AF_INET; + + if (e.bits < 32 && (uint32_t) (ntohl(e.address_ipv4.s_addr) << e.bits) != 0) + pa_log_warn(__FILE__": WARNING: Host part of ACL entry '%s/%u' is not zero!", a, e.bits); + + } else if (inet_pton(AF_INET6, a, &e.address_ipv6) > 0) { + + e.bits = bits == (uint32_t) -1 ? 128 : (int) bits; + + if (e.bits > 128) { + pa_log(__FILE__": number of bits out of range: %i", e.bits); + goto fail; + } + e.family = AF_INET6; + + if (e.bits < 128) { + int t = 0, i; + + for (i = 0, bits = e.bits; i < 16; i++) { + + if (bits >= 8) + bits -= 8; + else { + if ((uint8_t) ((e.address_ipv6.s6_addr[i]) << bits) != 0) { + t = 1; + break; + } + bits = 0; + } + } + + if (t) + pa_log_warn(__FILE__": WARNING: Host part of ACL entry '%s/%u' is not zero!", a, e.bits); + } + + } else { + pa_log(__FILE__": failed to parse address: %s", a); + goto fail; + } + + n = pa_xmemdup(&e, sizeof(struct acl_entry)); + PA_LLIST_PREPEND(struct acl_entry, acl->entries, n); + + pa_xfree(a); + } + + return acl; + +fail: + pa_xfree(a); + pa_ip_acl_free(acl); + + return NULL; +} + +void pa_ip_acl_free(pa_ip_acl *acl) { + assert(acl); + + while (acl->entries) { + struct acl_entry *e = acl->entries; + PA_LLIST_REMOVE(struct acl_entry, acl->entries, e); + pa_xfree(e); + } + + pa_xfree(acl); +} + +int pa_ip_acl_check(pa_ip_acl *acl, int fd) { + struct sockaddr_storage sa; + struct acl_entry *e; + socklen_t salen; + + assert(acl); + assert(fd >= 0); + + salen = sizeof(sa); + if (getpeername(fd, (struct sockaddr*) &sa, &salen) < 0) + return -1; + + if (sa.ss_family != AF_INET && sa.ss_family != AF_INET6) + return -1; + + if (sa.ss_family == AF_INET && salen != sizeof(struct sockaddr_in)) + return -1; + + if (sa.ss_family == AF_INET6 && salen != sizeof(struct sockaddr_in6)) + return -1; + + for (e = acl->entries; e; e = e->next) { + + if (e->family != sa.ss_family) + continue; + + if (e->family == AF_INET) { + struct sockaddr_in *sai = (struct sockaddr_in*) &sa; + + if (e->bits == 0 || /* this needs special handling because >> takes the right-hand side modulo 32 */ + (ntohl(sai->sin_addr.s_addr ^ e->address_ipv4.s_addr) >> (32 - e->bits)) == 0) + return 1; + } else if (e->family == AF_INET6) { + int i, bits ; + struct sockaddr_in6 *sai = (struct sockaddr_in6*) &sa; + + if (e->bits == 128) + return memcmp(&sai->sin6_addr, &e->address_ipv6, 16) == 0; + + if (e->bits == 0) + return 1; + + for (i = 0, bits = e->bits; i < 16; i++) { + + if (bits >= 8) { + if (sai->sin6_addr.s6_addr[i] != e->address_ipv6.s6_addr[i]) + break; + + bits -= 8; + } else { + if ((sai->sin6_addr.s6_addr[i] ^ e->address_ipv6.s6_addr[i]) >> (8 - bits) != 0) + break; + + bits = 0; + } + + if (bits == 0) + return 1; + } + } + } + + return 0; +} diff --git a/src/pulsecore/ipacl.h b/src/pulsecore/ipacl.h new file mode 100644 index 00000000..7a4540ce --- /dev/null +++ b/src/pulsecore/ipacl.h @@ -0,0 +1,31 @@ +#ifndef fooparseaddrhfoo +#define fooparseaddrhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef struct pa_ip_acl pa_ip_acl; + +pa_ip_acl* pa_ip_acl_new(const char *s); +void pa_ip_acl_free(pa_ip_acl *acl); +int pa_ip_acl_check(pa_ip_acl *acl, int fd); + +#endif diff --git a/src/tests/ipacl-test.c b/src/tests/ipacl-test.c new file mode 100644 index 00000000..b98151ee --- /dev/null +++ b/src/tests/ipacl-test.c @@ -0,0 +1,117 @@ +/* $Id$ */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int main(int argc, char *argv[]) { + struct sockaddr_in sa; + struct sockaddr_in6 sa6; + int fd; + int r; + pa_ip_acl *acl; + + fd = socket(PF_INET, SOCK_STREAM, 0); + assert(fd >= 0); + + sa.sin_family = AF_INET; + sa.sin_port = htons(22); + sa.sin_addr.s_addr = inet_addr("127.0.0.1"); + + r = connect(fd, (struct sockaddr*) &sa, sizeof(sa)); + assert(r >= 0); + + acl = pa_ip_acl_new("127.0.0.1"); + assert(acl); + printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd)); + pa_ip_acl_free(acl); + + acl = pa_ip_acl_new("127.0.0.2/0"); + assert(acl); + printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd)); + pa_ip_acl_free(acl); + + acl = pa_ip_acl_new("127.0.0.1/32"); + assert(acl); + printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd)); + pa_ip_acl_free(acl); + + acl = pa_ip_acl_new("127.0.0.1/7"); + assert(acl); + printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd)); + pa_ip_acl_free(acl); + + acl = pa_ip_acl_new("127.0.0.2"); + assert(acl); + printf("result=%u (should be 0)\n", pa_ip_acl_check(acl, fd)); + pa_ip_acl_free(acl); + + acl = pa_ip_acl_new("127.0.0.0/8;0.0.0.0/32"); + assert(acl); + printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd)); + pa_ip_acl_free(acl); + + acl = pa_ip_acl_new("128.0.0.2/9"); + assert(acl); + printf("result=%u (should be 0)\n", pa_ip_acl_check(acl, fd)); + pa_ip_acl_free(acl); + + acl = pa_ip_acl_new("::1/9"); + assert(acl); + printf("result=%u (should be 0)\n", pa_ip_acl_check(acl, fd)); + pa_ip_acl_free(acl); + + close(fd); + + fd = socket(PF_INET6, SOCK_STREAM, 0); + assert(fd >= 0); + + memset(&sa6, 0, sizeof(sa6)); + sa6.sin6_family = AF_INET6; + sa6.sin6_port = htons(22); + inet_pton(AF_INET6, "::1", &sa6.sin6_addr); + + r = connect(fd, (struct sockaddr*) &sa6, sizeof(sa6)); + assert(r >= 0); + + acl = pa_ip_acl_new("::1"); + assert(acl); + printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd)); + pa_ip_acl_free(acl); + + acl = pa_ip_acl_new("::1/9"); + assert(acl); + printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd)); + pa_ip_acl_free(acl); + + acl = pa_ip_acl_new("::/0"); + assert(acl); + printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd)); + pa_ip_acl_free(acl); + + acl = pa_ip_acl_new("::2/128"); + assert(acl); + printf("result=%u (should be 0)\n", pa_ip_acl_check(acl, fd)); + pa_ip_acl_free(acl); + + acl = pa_ip_acl_new("::2/127"); + assert(acl); + printf("result=%u (should be 0)\n", pa_ip_acl_check(acl, fd)); + pa_ip_acl_free(acl); + + acl = pa_ip_acl_new("::2/126"); + assert(acl); + printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd)); + pa_ip_acl_free(acl); + + close(fd); + + return 0; +} -- cgit From db75f68854b03a4fb8884616d085f48b9fc4d001 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Jul 2006 16:56:06 +0000 Subject: actually ship src/pulsecore/creds.h in the tarballs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1124 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 431bedbd..ec1678c7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -405,7 +405,7 @@ libpulse_la_SOURCES += \ pulsecore/strlist.c pulsecore/strlist.h \ pulsecore/tagstruct.c pulsecore/tagstruct.h \ pulsecore/core-error.c pulsecore/core-error.h \ - pulsecore/winsock.h + pulsecore/winsock.h pulsecore/creds.h if OS_IS_WIN32 libpulse_la_SOURCES += \ @@ -508,7 +508,8 @@ pulsecoreinclude_HEADERS = \ pulsecore/source.h \ pulsecore/source-output.h \ pulsecore/strbuf.h \ - pulsecore/tokenizer.h + pulsecore/tokenizer.h \ + pulsecore/creds.h lib_LTLIBRARIES += libpulsecore.la -- cgit From 44beeaa648a1d434692721dd65a04ecb3f75dace Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Jul 2006 18:43:20 +0000 Subject: implement "auth-ip-acl=" in the native and esound protocols git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1125 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 6 +++--- src/modules/module-protocol-stub.c | 17 +++++++++++++-- src/pulsecore/iochannel.c | 6 ++++++ src/pulsecore/iochannel.h | 2 ++ src/pulsecore/protocol-esound.c | 41 +++++++++++++++++++++++++++++------ src/pulsecore/protocol-native.c | 44 +++++++++++++++++++++++++++++++------- 6 files changed, 96 insertions(+), 20 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index ec1678c7..428e4521 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -513,7 +513,7 @@ pulsecoreinclude_HEADERS = \ lib_LTLIBRARIES += libpulsecore.la -# Some public stuff is used even in the core. +# Some public stuff is used even in the core libpulsecore_la_SOURCES = \ pulse/channelmap.c pulse/channelmap.h \ pulse/error.c pulse/error.h \ @@ -733,7 +733,7 @@ libprotocol_http_la_LIBADD = $(AM_LIBADD) libsocket-server.la libioline.la libpu libprotocol_native_la_SOURCES = pulsecore/protocol-native.c pulsecore/protocol-native.h pulsecore/native-common.h libprotocol_native_la_LDFLAGS = -avoid-version -libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libstrlist.la libpulsecore.la libiochannel.la +libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libstrlist.la libpulsecore.la libiochannel.la libipacl.la libtagstruct_la_SOURCES = pulsecore/tagstruct.c pulsecore/tagstruct.h libtagstruct_la_LDFLAGS = -avoid-version @@ -741,7 +741,7 @@ libtagstruct_la_LIBADD = $(AM_LIBADD) libpulsecore.la $(WINSOCK_LIBS) libprotocol_esound_la_SOURCES = pulsecore/protocol-esound.c pulsecore/protocol-esound.h pulsecore/esound.h libprotocol_esound_la_LDFLAGS = -avoid-version -libprotocol_esound_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libauthkey.la libpulsecore.la +libprotocol_esound_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libauthkey.la libpulsecore.la libipacl.la libauthkey_la_SOURCES = pulsecore/authkey.c pulsecore/authkey.h libauthkey_la_LDFLAGS = -avoid-version diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index 36d7db89..d1f5fa15 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -129,8 +129,11 @@ #endif #if defined(HAVE_CREDS) && !defined(USE_TCP_SOCKETS) - #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-group", "auth-group-enable=" + #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-group", "auth-group-enable", #define AUTH_USAGE "auth-group= auth-group-enable= " + #elif defined(USE_TCP_SOCKETS) + #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-ip-acl", + #define AUTH_USAGE "auth-ip-acl= " #else #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON #define AUTH_USAGE @@ -149,17 +152,27 @@ #define TCPWRAP_SERVICE "esound" #define IPV4_PORT ESD_DEFAULT_PORT #define UNIX_SOCKET ESD_UNIX_SOCKET_NAME - #define MODULE_ARGUMENTS "sink", "source", "auth-anonymous", "cookie", + #define MODULE_ARGUMENTS_COMMON "sink", "source", "auth-anonymous", "cookie", #ifdef USE_TCP_SOCKETS #include "module-esound-protocol-tcp-symdef.h" #else #include "module-esound-protocol-unix-symdef.h" #endif + + #if defined(USE_TCP_SOCKETS) + #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-ip-acl", + #define AUTH_USAGE "auth-ip-acl= " + #else + #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON + #define AUTH_USAGE + #endif + PA_MODULE_DESCRIPTION("ESOUND protocol "SOCKET_DESCRIPTION) PA_MODULE_USAGE("sink= " "source= " "auth-anonymous= " "cookie= " + AUTH_USAGE SOCKET_USAGE) #else #error "Broken build system" diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c index b50293bf..af732c26 100644 --- a/src/pulsecore/iochannel.c +++ b/src/pulsecore/iochannel.c @@ -408,3 +408,9 @@ pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) { return io->mainloop; } + +int pa_iochannel_get_recv_fd(pa_iochannel *io) { + assert(io); + + return io->ifd; +} diff --git a/src/pulsecore/iochannel.h b/src/pulsecore/iochannel.h index 1f9ab0d4..0e6d6d3a 100644 --- a/src/pulsecore/iochannel.h +++ b/src/pulsecore/iochannel.h @@ -79,4 +79,6 @@ int pa_iochannel_socket_set_sndbuf(pa_iochannel*io, size_t l); pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io); +int pa_iochannel_get_recv_fd(pa_iochannel *io); + #endif diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 5daa32fe..0fa2c7f1 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -49,6 +49,7 @@ #include #include #include +#include #include "endianmacros.h" @@ -116,6 +117,7 @@ struct pa_protocol_esound { char *sink_name, *source_name; unsigned n_player; uint8_t esd_key[ESD_KEY_LEN]; + pa_ip_acl *auth_ip_acl; }; typedef struct proto_handler { @@ -1162,7 +1164,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->client->kill = client_kill_cb; c->client->userdata = c; - c->authorized = p->public; + c->authorized = !!p->public; c->swap_byte_order = 0; c->dead = 0; @@ -1191,6 +1193,11 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->original_name = NULL; + if (!c->authorized && p->auth_ip_acl && pa_ip_acl_check(p->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) { + pa_log_info(__FILE__": Client authenticated by IP ACL."); + c->authorized = 1; + } + if (!c->authorized) { struct timeval tv; pa_gettimeofday(&tv); @@ -1211,20 +1218,32 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { pa_protocol_esound *p; int public = 0; - assert(core && server && ma); + const char *acl; + + assert(core); + assert(server); + assert(m); + assert(ma); p = pa_xnew(pa_protocol_esound, 1); if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) { pa_log(__FILE__": auth-anonymous= expects a boolean argument."); - return NULL; + goto fail; } - if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", DEFAULT_COOKIE_FILE), p->esd_key, sizeof(p->esd_key)) < 0) { - pa_xfree(p); - return NULL; - } + if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", DEFAULT_COOKIE_FILE), p->esd_key, sizeof(p->esd_key)) < 0) + goto fail; + if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) { + + if (!(p->auth_ip_acl = pa_ip_acl_new(acl))) { + pa_log(__FILE__": Failed to parse IP ACL '%s'", acl); + goto fail; + } + } else + p->auth_ip_acl = NULL; + p->module = m; p->public = public; p->server = server; @@ -1238,6 +1257,10 @@ pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *serve p->n_player = 0; return p; + +fail: + pa_xfree(p); + return NULL; } void pa_protocol_esound_free(pa_protocol_esound *p) { @@ -1249,5 +1272,9 @@ void pa_protocol_esound_free(pa_protocol_esound *p) { pa_idxset_free(p->connections, NULL, NULL); pa_socket_server_unref(p->server); + + if (p->auth_ip_acl) + pa_ip_acl_free(p->auth_ip_acl); + pa_xfree(p); } diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 2775d774..f1959dd7 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -57,6 +57,7 @@ #include #include #include +#include #include "protocol-native.h" @@ -139,6 +140,7 @@ struct pa_protocol_native { #ifdef HAVE_CREDS char *auth_group; #endif + pa_ip_acl *auth_ip_acl; }; static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk); @@ -942,7 +944,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t } #endif - if (memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) == 0) + if (!success && memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) == 0) success = 1; if (!success) { @@ -2239,8 +2241,13 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo c = pa_xmalloc(sizeof(struct connection)); - c->authorized =!! p->public; + c->authorized = !!p->public; + if (!c->authorized && p->auth_ip_acl && pa_ip_acl_check(p->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) { + pa_log_info(__FILE__": Client authenticated by IP ACL."); + c->authorized = 1; + } + if (!c->authorized) { struct timeval tv; pa_gettimeofday(&tv); @@ -2319,7 +2326,10 @@ static int load_key(pa_protocol_native*p, const char*fn) { static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_modargs *ma) { pa_protocol_native *p; int public = 0; - assert(c && ma); + const char *acl; + + assert(c); + assert(ma); if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) { pa_log(__FILE__": auth-anonymous= expects a boolean argument."); @@ -2331,7 +2341,8 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo p->module = m; p->public = public; p->server = NULL; - + p->auth_ip_acl = NULL; + #ifdef HAVE_CREDS { int a = 1; @@ -2345,16 +2356,30 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo pa_log_info(__FILE__": Allowing access to group '%s'.", p->auth_group); } #endif - - if (load_key(p, pa_modargs_get_value(ma, "cookie", NULL)) < 0) { - pa_xfree(p); - return NULL; + + + if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) { + + if (!(p->auth_ip_acl = pa_ip_acl_new(acl))) { + pa_log(__FILE__": Failed to parse IP ACL '%s'", acl); + goto fail; + } } + if (load_key(p, pa_modargs_get_value(ma, "cookie", NULL)) < 0) + goto fail; + p->connections = pa_idxset_new(NULL, NULL); assert(p->connections); return p; + +fail: + pa_xfree(p->auth_group); + if (p->auth_ip_acl) + pa_ip_acl_free(p->auth_ip_acl); + pa_xfree(p); + return NULL; } pa_protocol_native* pa_protocol_native_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { @@ -2405,6 +2430,9 @@ void pa_protocol_native_free(pa_protocol_native *p) { if (p->auth_cookie_in_property) pa_authkey_prop_unref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); + if (p->auth_ip_acl) + pa_ip_acl_free(p->auth_ip_acl); + #ifdef HAVE_CREDS pa_xfree(p->auth_group); #endif -- cgit From dd5fd8d7036074480fd6ea28eb39644adc8531a2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Jul 2006 18:43:38 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1126 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 - 1 file changed, 1 deletion(-) diff --git a/todo b/todo index cdc97373..9ea67dda 100644 --- a/todo +++ b/todo @@ -35,7 +35,6 @@ Post 0.9.0: - key rings for auth - challenge response auth - sasl auth -- IP ACLs Long term: - pass meta info for hearing impaired -- cgit From da1ec271bbc1907c32811cd61f41390a7d3ac1e8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Jul 2006 21:28:44 +0000 Subject: remove configurable client access group, since can never work on Linux anway, since SCM_CREDENTAILS doesn't allow sending supplementary GIDs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1127 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/client-conf.c | 5 ----- src/pulse/client-conf.h | 2 +- src/pulse/context.c | 5 ----- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c index 21917597..c3f58ec2 100644 --- a/src/pulse/client-conf.c +++ b/src/pulse/client-conf.c @@ -64,7 +64,6 @@ static const pa_client_conf default_conf = { .autospawn = 0, .cookie_file = NULL, .cookie_valid = 0, - .access_group = NULL }; pa_client_conf *pa_client_conf_new(void) { @@ -73,7 +72,6 @@ pa_client_conf *pa_client_conf_new(void) { c->daemon_binary = pa_xstrdup(PA_BINARY); c->extra_arguments = pa_xstrdup("--log-target=syslog --exit-idle-time=5"); c->cookie_file = pa_xstrdup(PA_NATIVE_COOKIE_FILE); - c->access_group = pa_xstrdup(PA_ACCESS_GROUP); return c; } @@ -86,7 +84,6 @@ void pa_client_conf_free(pa_client_conf *c) { pa_xfree(c->default_source); pa_xfree(c->default_server); pa_xfree(c->cookie_file); - pa_xfree(c->access_group); pa_xfree(c); } int pa_client_conf_load(pa_client_conf *c, const char *filename) { @@ -103,7 +100,6 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) { { "default-server", pa_config_parse_string, NULL }, { "autospawn", pa_config_parse_bool, NULL }, { "cookie-file", pa_config_parse_string, NULL }, - { "access-group", pa_config_parse_string, NULL }, { NULL, NULL, NULL }, }; @@ -114,7 +110,6 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) { table[4].data = &c->default_server; table[5].data = &c->autospawn; table[6].data = &c->cookie_file; - table[7].data = &c->access_group; f = filename ? fopen((fn = pa_xstrdup(filename)), "r") : diff --git a/src/pulse/client-conf.h b/src/pulse/client-conf.h index dfb1148d..a532f0df 100644 --- a/src/pulse/client-conf.h +++ b/src/pulse/client-conf.h @@ -27,7 +27,7 @@ /* A structure containing configuration data for PulseAudio clients. */ typedef struct pa_client_conf { - char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server, *cookie_file, *access_group; + char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server, *cookie_file; int autospawn; uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; int cookie_valid; /* non-zero, when cookie is valid */ diff --git a/src/pulse/context.c b/src/pulse/context.c index 30a257fe..34f517f0 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -428,14 +428,9 @@ static void setup_context(pa_context *c, pa_iochannel *io) { #ifdef HAVE_CREDS { pa_creds ucred; - gid_t g; ucred.uid = getuid(); ucred.gid = getgid(); - - if ((g = pa_get_gid_of_group(c->conf->access_group)) != (gid_t) -1) - if (pa_check_in_group(g) > 0) - ucred.gid = g; pa_pstream_send_tagstruct_with_creds(c->pstream, t, &ucred); } -- cgit From b3d3d16bbeeee1067a27593908004f30b2e1b20e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Jul 2006 21:48:49 +0000 Subject: bump release and sonames git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1128 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index a7f85ea0..746da479 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ AC_PREREQ(2.57) m4_define(PA_MAJOR, [0]) m4_define(PA_MINOR, [9]) -m4_define(PA_MICRO, [2]) +m4_define(PA_MICRO, [3]) AC_INIT([pulseaudio], PA_MAJOR.PA_MINOR.PA_MICRO,[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([src/daemon/main.c]) @@ -36,11 +36,11 @@ AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/pulseaudio/]) AC_SUBST(PA_API_VERSION, 9) AC_SUBST(PA_PROTOCOL_VERSION, 9) -AC_SUBST(LIBPULSE_VERSION_INFO, [0:0:0]) -AC_SUBST(LIBPULSECORE_VERSION_INFO, [0:1:0]) +AC_SUBST(LIBPULSE_VERSION_INFO, [0:1:0]) +AC_SUBST(LIBPULSECORE_VERSION_INFO, [1:0:0]) AC_SUBST(LIBPULSE_SIMPLE_VERSION_INFO, [0:0:0]) -AC_SUBST(LIBPULSE_BROWSE_VERSION_INFO, [0:0:0]) -AC_SUBST(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO, [0:0:0]) +AC_SUBST(LIBPULSE_BROWSE_VERSION_INFO, [1:0:1]) +AC_SUBST(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO, [0:1:0]) if type -p stow > /dev/null && test -d /usr/local/stow ; then AC_MSG_NOTICE([*** Found /usr/local/stow: default install prefix set to /usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION} ***]) -- cgit From 2683f25b97420ceba7be99b9de03bc8f2eb4d3a9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Jul 2006 22:44:38 +0000 Subject: some more FreeBSD compat from Flameeyes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1129 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/ipacl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pulsecore/ipacl.c b/src/pulsecore/ipacl.c index 06be0a28..ed5044ef 100644 --- a/src/pulsecore/ipacl.c +++ b/src/pulsecore/ipacl.c @@ -23,8 +23,10 @@ #include #endif +#include #include #include +#include #include #include #include -- cgit From 90b521d73e2a51f7b5df0bce1ee19d30bd0b087e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Jul 2006 22:46:41 +0000 Subject: add missing #ifdef HAVE_CREDS (thanks, Flameeyes) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1130 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-native.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index f1959dd7..9023adde 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -2375,7 +2375,9 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo return p; fail: +#ifdef HAVE_CREDS pa_xfree(p->auth_group); +#endif if (p->auth_ip_acl) pa_ip_acl_free(p->auth_ip_acl); pa_xfree(p); -- cgit From 6ad1f33c3fdad0c9cbf78f722223b29fe3160ec6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Jul 2006 22:58:37 +0000 Subject: even more FreeBSD portability (thanks Flameeyes, again!) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1131 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/tests/ipacl-test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tests/ipacl-test.c b/src/tests/ipacl-test.c index b98151ee..8819a6a0 100644 --- a/src/tests/ipacl-test.c +++ b/src/tests/ipacl-test.c @@ -1,7 +1,9 @@ /* $Id$ */ +#include #include #include +#include #include #include #include -- cgit From 55e97b84c40f32506b1fcd0a96bac84b0ee134a6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Jul 2006 23:04:59 +0000 Subject: fix a few @@ replacments git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1132 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 428e4521..4669fbbe 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1181,17 +1181,17 @@ CLEANFILES = esdcompat client.conf default.pa daemon.conf esdcompat: daemon/esdcompat.in Makefile sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ - -e 's,@PA_BINARY\@,$(PULSEAUDIO_BINARY),g' < $< > $@ + -e 's,@PA_BINARY\@,$(PA_BINARY),g' < $< > $@ client.conf: pulse/client.conf.in Makefile - sed -e 's,@PA_BINARY\@,$(PULSEAUDIO_BINARY),g' < $< > $@ + sed -e 's,@PA_BINARY\@,$(PA_BINARY),g' < $< > $@ if OS_IS_WIN32 default.pa: daemon/default.pa.win32 cp $< $@ else default.pa: daemon/default.pa.in Makefile - sed -e 's,@PA_BINARY\@,$(PULSEAUDIO_BINARY),g' < $< > $@ + sed -e 's,@PA_BINARY\@,$(PA_BINARY),g' < $< > $@ endif daemon.conf: daemon/daemon.conf.in Makefile -- cgit From 40b408990ae4d52df33a88508b02954a67b6841b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Jul 2006 23:12:18 +0000 Subject: remove access group setting from default client.conf git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1133 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/client.conf.in | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/pulse/client.conf.in b/src/pulse/client.conf.in index 3e008766..c970be56 100644 --- a/src/pulse/client.conf.in +++ b/src/pulse/client.conf.in @@ -40,6 +40,3 @@ ### Cookie file ; cookie-file = - -### Access group -; access-group = -- cgit From 09e01afa1fa27b5148fa8eb7dc35bfd04cc3de68 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 20 Jul 2006 23:21:57 +0000 Subject: Get ACL:s to work on Win32. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1134 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 7 +++++-- src/pulsecore/ipacl.c | 24 +++++++++++++++++++++--- src/tests/ipacl-test.c | 25 +++++++++++++++++++++---- 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 4669fbbe..9eb957d5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -228,7 +228,9 @@ get_binary_name_test_CFLAGS = $(AM_CFLAGS) get_binary_name_test_LDADD = $(AM_LDADD) libpulse.la get_binary_name_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -ipacl_test_SOURCES = tests/ipacl-test.c pulsecore/ipacl.c pulsecore/ipacl.h +ipacl_test_SOURCES = tests/ipacl-test.c \ + pulsecore/ipacl.c pulsecore/ipacl.h \ + pulsecore/inet_pton.c pulsecore/inet_pton.h ipacl_test_CFLAGS = $(AM_CFLAGS) ipacl_test_LDADD = $(AM_LDADD) libpulsecore.la ipacl_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -677,7 +679,8 @@ libsocket_server_la_SOURCES = \ libsocket_server_la_LDFLAGS = -avoid-version libsocket_server_la_LIBADD = $(AM_LIBADD) libpulsecore.la libiochannel.la libsocket-util.la $(LIBWRAP_LIBS) $(WINSOCK_LIBS) -libipacl_la_SOURCES = pulsecore/ipacl.h pulsecore/ipacl.c +libipacl_la_SOURCES = pulsecore/ipacl.h pulsecore/ipacl.c \ + pulsecore/inet_pton.c pulsecore/inet_pton.h libipacl_la_LDFLAGS = -avoid-version libipacl_la_LIBADD = $(AM_LIBADD) libpulsecore.la $(WINSOCK_LIBS) diff --git a/src/pulsecore/ipacl.c b/src/pulsecore/ipacl.c index ed5044ef..15b6b3f9 100644 --- a/src/pulsecore/ipacl.c +++ b/src/pulsecore/ipacl.c @@ -24,18 +24,36 @@ #endif #include +#include +#include + +#ifdef HAVE_SYS_SOCKET_H #include +#endif +#ifdef HAVE_NETINET_IN_H #include +#endif +#ifdef HAVE_NETINET_IN_SYSTM_H #include +#endif +#ifdef HAVE_NETINET_IP_H #include -#include +#endif +#ifdef HAVE_ARPA_INET_H #include -#include +#endif + +#include "winsock.h" + +#include #include #include #include -#include + +#ifndef HAVE_INET_PTON +#include "inet_pton.h" +#endif #include "ipacl.h" diff --git a/src/tests/ipacl-test.c b/src/tests/ipacl-test.c index 8819a6a0..2566b038 100644 --- a/src/tests/ipacl-test.c +++ b/src/tests/ipacl-test.c @@ -1,15 +1,32 @@ /* $Id$ */ +#ifdef HAVE_CONFIG_H +#include +#endif + #include +#include +#include +#include +#include + +#ifdef HAVE_SYS_SOCKET_H #include +#endif +#ifdef HAVE_NETINET_IN_H #include +#endif +#ifdef HAVE_NETINET_IN_SYSTM_H #include +#endif +#ifdef HAVE_NETINET_IP_H #include -#include -#include +#endif +#ifdef HAVE_ARPA_INET_H #include -#include -#include +#endif + +#include "../pulsecore/winsock.h" #include -- cgit From a84a2f91384060720dc1e1a97963faadc526c299 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 21 Jul 2006 19:59:52 +0000 Subject: raise the default value for RLIMIT_NOFILE to 200 since 25 is apparently too small if every single GNOME apps thinks it needs to create its own server connection! git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1136 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/daemon-conf.c | 2 +- src/daemon/daemon.conf.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 894c0434..0426989c 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -78,7 +78,7 @@ static const pa_daemon_conf default_conf = { .rlimit_core = { .value = 0, .is_set = 0 }, .rlimit_data = { .value = 0, .is_set = 0 }, .rlimit_fsize = { .value = 0, .is_set = 0 }, - .rlimit_nofile = { .value = 25, .is_set = 1 }, + .rlimit_nofile = { .value = 200, .is_set = 1 }, .rlimit_stack = { .value = 0, .is_set = 0 } #ifdef RLIMIT_NPROC , .rlimit_nproc = { .value = 0, .is_set = 0 } diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in index 787405f8..696b25a9 100644 --- a/src/daemon/daemon.conf.in +++ b/src/daemon/daemon.conf.in @@ -87,7 +87,7 @@ ; rlimit-core = -1 ; rlimit-data = -1 ; rlimit-fsize = -1 -; rlimit-nofile = 25 +; rlimit-nofile = 200 ; rlimit-stack = -1 ; rlimit-nproc = -1 ; rlimit-memlock = 25 -- cgit From b345af2273cdeee77785514974e5c5b28ebb5fe3 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 21 Jul 2006 21:19:11 +0000 Subject: Use proper @libdir@ in pc.in files to handle x86_64 machines. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1137 fefdeb5f-60dc-0310-8127-8f9354f1896f --- libpulse-browse.pc.in | 4 ++-- libpulse-mainloop-glib.pc.in | 2 +- libpulse-simple.pc.in | 2 +- libpulse.pc.in | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libpulse-browse.pc.in b/libpulse-browse.pc.in index 7bdedf2e..7b9a59f4 100644 --- a/libpulse-browse.pc.in +++ b/libpulse-browse.pc.in @@ -1,9 +1,9 @@ prefix=@prefix@ exec_prefix=${prefix} -libdir=${exec_prefix}/lib +libdir=@libdir@ includedir=${prefix}/include -Name: libpuls-browse +Name: libpulse-browse Description: PulseAudio Network Browsing API Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lpulse-browse diff --git a/libpulse-mainloop-glib.pc.in b/libpulse-mainloop-glib.pc.in index a9a51cf7..0977f185 100644 --- a/libpulse-mainloop-glib.pc.in +++ b/libpulse-mainloop-glib.pc.in @@ -1,6 +1,6 @@ prefix=@prefix@ exec_prefix=${prefix} -libdir=${exec_prefix}/lib +libdir=@libdir@ includedir=${prefix}/include Name: libpulse-mainloop-glib diff --git a/libpulse-simple.pc.in b/libpulse-simple.pc.in index c35e83fa..4ccc3d58 100644 --- a/libpulse-simple.pc.in +++ b/libpulse-simple.pc.in @@ -1,6 +1,6 @@ prefix=@prefix@ exec_prefix=${prefix} -libdir=${exec_prefix}/lib +libdir=@libdir@ includedir=${prefix}/include Name: libpulse-simple diff --git a/libpulse.pc.in b/libpulse.pc.in index 8d0ffb85..45fec220 100644 --- a/libpulse.pc.in +++ b/libpulse.pc.in @@ -1,6 +1,6 @@ prefix=@prefix@ exec_prefix=${prefix} -libdir=${exec_prefix}/lib +libdir=@libdir@ includedir=${prefix}/include Name: libpulse -- cgit From 07a1c45cc1bd647d9a9c579a0c2bffd4c3d5fc1b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Jul 2006 00:54:23 +0000 Subject: fix horribly broken glib timeout event handling git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1138 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/glib-mainloop.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/pulse/glib-mainloop.c b/src/pulse/glib-mainloop.c index cdaecdf8..77f93450 100644 --- a/src/pulse/glib-mainloop.c +++ b/src/pulse/glib-mainloop.c @@ -312,7 +312,7 @@ static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { assert(e); assert(!e->dead); - if (e->enabled && !!tv) + if (e->enabled && !tv) e->mainloop->n_enabled_time_events--; else if (!e->enabled && tv) e->mainloop->n_enabled_time_events++; @@ -476,13 +476,11 @@ static gboolean prepare_func(GSource *source, gint *timeout) { tvnow.tv_sec = now.tv_sec; tvnow.tv_usec = now.tv_usec; - usec = pa_timeval_diff(&t->timeval, &tvnow); - - if (usec <= 0) { + if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) { *timeout = 0; return TRUE; - } - + } + usec = pa_timeval_diff(&t->timeval, &tvnow); *timeout = (gint) (usec / 1000); } else *timeout = -1; @@ -554,7 +552,7 @@ static gboolean dispatch_func(GSource *source, PA_GCC_UNUSED GSourceFunc callbac tvnow.tv_sec = now.tv_sec; tvnow.tv_usec = now.tv_usec; - if (pa_timeval_cmp(&t->timeval, &tvnow) < 0) { + if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) { t->callback(&g->api, t, &t->timeval, t->userdata); return TRUE; } -- cgit From 95eee87380dfbb648243da456dfb204cd5009441 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 23 Jul 2006 19:23:12 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1139 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 + 1 file changed, 1 insertion(+) diff --git a/todo b/todo index 9ea67dda..d453b4d8 100644 --- a/todo +++ b/todo @@ -2,6 +2,7 @@ Post 0.9.0: - alsa mmap driver +- alsa driver with hw mixing - dbus/hal (Shams King is working on this one) - chroot() - module-tunnel: improve latency calculation -- cgit From c85351ba054045fd4fad1d8825c3d8c6e036c93b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 23 Jul 2006 22:35:30 +0000 Subject: as a result of memory profiling with valgrind/massif: decrease default hash table size from 1024 to 127. the hashtables are sparsely filled most of the time, so there is no point in allocating to much memory by default. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1140 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/hashmap.c | 2 +- src/pulsecore/idxset.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pulsecore/hashmap.c b/src/pulsecore/hashmap.c index 2cddba1d..6e0e6b02 100644 --- a/src/pulsecore/hashmap.c +++ b/src/pulsecore/hashmap.c @@ -34,7 +34,7 @@ #include "hashmap.h" -#define BUCKETS 1023 +#define BUCKETS 127 struct hashmap_entry { struct hashmap_entry *next, *previous, *bucket_next, *bucket_previous; diff --git a/src/pulsecore/idxset.c b/src/pulsecore/idxset.c index ddce623a..d3aec2de 100644 --- a/src/pulsecore/idxset.c +++ b/src/pulsecore/idxset.c @@ -78,7 +78,7 @@ pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_fu s = pa_xnew(pa_idxset, 1); s->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; s->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; - s->hash_table_size = 1023; + s->hash_table_size = 127; s->hash_table = pa_xmalloc0(sizeof(idxset_entry*)*s->hash_table_size); s->array = NULL; s->array_size = 0; -- cgit From 3aac89331bfaf7858fcb8672da4c9a0ced1de911 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 23 Jul 2006 22:36:08 +0000 Subject: add massif target to Makefile git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1141 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Makefile.am b/src/Makefile.am index 9eb957d5..e0add703 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1209,4 +1209,7 @@ install-exec-hook: rm -f $(DESTDIR)$(libdir)/libpulsedsp.a rm -f $(DESTDIR)$(libdir)/libpulsedsp.la +massif: pulseaudio + libtool --mode=execute valgrind --tool=massif --depth=6 --alloc-fn=pa_xmalloc --alloc-fn=pa_xmalloc0 --alloc-fn=pa_xrealloc --alloc-fn=dbus_realloc --alloc-fn=pa_xnew0_internal --alloc-fn=pa_xnew_internal ./pulseaudio + .PHONY: utils/padsp -- cgit From 0f8f5bce6c3b94e2638bcbcbad4310b49e4010cd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 24 Jul 2006 17:48:33 +0000 Subject: bump version and sonames git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1142 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 746da479..6cfbcf18 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ AC_PREREQ(2.57) m4_define(PA_MAJOR, [0]) m4_define(PA_MINOR, [9]) -m4_define(PA_MICRO, [3]) +m4_define(PA_MICRO, [4]) AC_INIT([pulseaudio], PA_MAJOR.PA_MINOR.PA_MICRO,[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([src/daemon/main.c]) @@ -36,8 +36,8 @@ AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/pulseaudio/]) AC_SUBST(PA_API_VERSION, 9) AC_SUBST(PA_PROTOCOL_VERSION, 9) -AC_SUBST(LIBPULSE_VERSION_INFO, [0:1:0]) -AC_SUBST(LIBPULSECORE_VERSION_INFO, [1:0:0]) +AC_SUBST(LIBPULSE_VERSION_INFO, [0:2:0]) +AC_SUBST(LIBPULSECORE_VERSION_INFO, [1:1:0]) AC_SUBST(LIBPULSE_SIMPLE_VERSION_INFO, [0:0:0]) AC_SUBST(LIBPULSE_BROWSE_VERSION_INFO, [1:0:1]) AC_SUBST(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO, [0:1:0]) -- cgit From 675bf2f51a0e37e8f0d4fd4d733255ca92efc923 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 24 Jul 2006 20:03:27 +0000 Subject: add autogen.sh for jhbuild (for you, elmarco!) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1144 fefdeb5f-60dc-0310-8127-8f9354f1896f --- autogen.sh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100755 autogen.sh diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 00000000..16c57386 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,24 @@ +#!/bin/sh +# $Id$ + +# This file is part of PulseAudio. +# +# PulseAudio is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# PulseAudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with PulseAudio; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + +# Only there to make jhbuild happy + +NOCONFIGURE=1 ./bootstrap.sh + +exec ./configure "$@" -- cgit From c41d7498d3edc66c05297874cd106adb3961e8a4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 25 Jul 2006 20:09:22 +0000 Subject: add a few more g_assert()s and change all assert()s to g_assert()s git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1145 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/glib-mainloop.c | 125 +++++++++++++++++++++++++++------------------- 1 file changed, 73 insertions(+), 52 deletions(-) diff --git a/src/pulse/glib-mainloop.c b/src/pulse/glib-mainloop.c index 77f93450..76767552 100644 --- a/src/pulse/glib-mainloop.c +++ b/src/pulse/glib-mainloop.c @@ -106,8 +106,10 @@ static void cleanup_io_events(pa_glib_mainloop *g, int force) { if (force || e->dead) { PA_LLIST_REMOVE(pa_io_event, g->io_events, e); - if (e->dead) + if (e->dead) { + g_assert(g->io_events_please_scan > 0); g->io_events_please_scan--; + } if (e->poll_fd_added) g_source_remove_poll(&g->source, &e->poll_fd); @@ -121,7 +123,7 @@ static void cleanup_io_events(pa_glib_mainloop *g, int force) { e = n; } - assert(g->io_events_please_scan == 0); + g_assert(g->io_events_please_scan == 0); } static void cleanup_time_events(pa_glib_mainloop *g, int force) { @@ -137,11 +139,15 @@ static void cleanup_time_events(pa_glib_mainloop *g, int force) { if (force || e->dead) { PA_LLIST_REMOVE(pa_time_event, g->time_events, e); - if (e->dead) + if (e->dead) { + g_assert(g->time_events_please_scan > 0); g->time_events_please_scan--; + } - if (!e->dead && e->enabled) + if (!e->dead && e->enabled) { + g_assert(g->n_enabled_time_events > 0); g->n_enabled_time_events--; + } if (e->destroy_callback) e->destroy_callback(&g->api, e, e->userdata); @@ -152,7 +158,7 @@ static void cleanup_time_events(pa_glib_mainloop *g, int force) { e = n; } - assert(g->time_events_please_scan == 0); + g_assert(g->time_events_please_scan == 0); } static void cleanup_defer_events(pa_glib_mainloop *g, int force) { @@ -168,11 +174,15 @@ static void cleanup_defer_events(pa_glib_mainloop *g, int force) { if (force || e->dead) { PA_LLIST_REMOVE(pa_defer_event, g->defer_events, e); - if (e->dead) + if (e->dead) { + g_assert(g->defer_events_please_scan > 0); g->defer_events_please_scan--; + } - if (!e->dead && e->enabled) + if (!e->dead && e->enabled) { + g_assert(g->n_enabled_defer_events > 0); g->n_enabled_defer_events--; + } if (e->destroy_callback) e->destroy_callback(&g->api, e, e->userdata); @@ -183,7 +193,7 @@ static void cleanup_defer_events(pa_glib_mainloop *g, int force) { e = n; } - assert(g->defer_events_please_scan == 0); + g_assert(g->defer_events_please_scan == 0); } static gushort map_flags_to_glib(pa_io_event_flags_t flags) { @@ -212,10 +222,10 @@ static pa_io_event* glib_io_new( pa_io_event *e; pa_glib_mainloop *g; - assert(m); - assert(m->userdata); - assert(fd >= 0); - assert(cb); + g_assert(m); + g_assert(m->userdata); + g_assert(fd >= 0); + g_assert(cb); g = m->userdata; @@ -240,15 +250,15 @@ static pa_io_event* glib_io_new( } static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { - assert(e); - assert(!e->dead); + g_assert(e); + g_assert(!e->dead); e->poll_fd.events = map_flags_to_glib(f); } static void glib_io_free(pa_io_event*e) { - assert(e); - assert(!e->dead); + g_assert(e); + g_assert(!e->dead); e->dead = 1; e->mainloop->io_events_please_scan++; @@ -260,8 +270,8 @@ static void glib_io_free(pa_io_event*e) { } static void glib_io_set_destroy(pa_io_event*e, pa_io_event_destroy_cb_t cb) { - assert(e); - assert(!e->dead); + g_assert(e); + g_assert(!e->dead); e->destroy_callback = cb; } @@ -277,9 +287,9 @@ static pa_time_event* glib_time_new( pa_glib_mainloop *g; pa_time_event *e; - assert(m); - assert(m->userdata); - assert(cb); + g_assert(m); + g_assert(m->userdata); + g_assert(cb); g = m->userdata; @@ -309,20 +319,21 @@ static pa_time_event* glib_time_new( } static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { - assert(e); - assert(!e->dead); + g_assert(e); + g_assert(!e->dead); - if (e->enabled && !tv) + if (e->enabled && !tv) { + g_assert(e->mainloop->n_enabled_time_events > 0); e->mainloop->n_enabled_time_events--; - else if (!e->enabled && tv) + } else if (!e->enabled && tv) e->mainloop->n_enabled_time_events++; - if ((e->enabled = !!tv)) + if ((e->enabled = !!tv)) e->timeval = *tv; if (e->mainloop->cached_next_time_event && e->enabled) { g_assert(e->mainloop->cached_next_time_event->enabled); - + if (pa_timeval_cmp(tv, &e->mainloop->cached_next_time_event->timeval) < 0) e->mainloop->cached_next_time_event = e; } else if (e->mainloop->cached_next_time_event == e) @@ -330,8 +341,8 @@ static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { } static void glib_time_free(pa_time_event *e) { - assert(e); - assert(!e->dead); + g_assert(e); + g_assert(!e->dead); e->dead = 1; e->mainloop->time_events_please_scan++; @@ -344,8 +355,8 @@ static void glib_time_free(pa_time_event *e) { } static void glib_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t cb) { - assert(e); - assert(!e->dead); + g_assert(e); + g_assert(!e->dead); e->destroy_callback = cb; } @@ -360,9 +371,9 @@ static pa_defer_event* glib_defer_new( pa_defer_event *e; pa_glib_mainloop *g; - assert(m); - assert(m->userdata); - assert(cb); + g_assert(m); + g_assert(m->userdata); + g_assert(cb); g = m->userdata; @@ -382,31 +393,34 @@ static pa_defer_event* glib_defer_new( } static void glib_defer_enable(pa_defer_event *e, int b) { - assert(e); - assert(!e->dead); + g_assert(e); + g_assert(!e->dead); - if (e->enabled && !b) + if (e->enabled && !b) { + g_assert(e->mainloop->n_enabled_defer_events > 0); e->mainloop->n_enabled_defer_events--; - else if (!e->enabled && b) + } else if (!e->enabled && b) e->mainloop->n_enabled_defer_events++; e->enabled = b; } static void glib_defer_free(pa_defer_event *e) { - assert(e); - assert(!e->dead); + g_assert(e); + g_assert(!e->dead); e->dead = 1; e->mainloop->defer_events_please_scan++; - if (e->enabled) + if (e->enabled) { + g_assert(e->mainloop->n_enabled_defer_events > 0); e->mainloop->n_enabled_defer_events--; + } } static void glib_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t cb) { - assert(e); - assert(!e->dead); + g_assert(e); + g_assert(!e->dead); e->destroy_callback = cb; } @@ -422,7 +436,7 @@ static void glib_quit(pa_mainloop_api*a, PA_GCC_UNUSED int retval) { static pa_time_event* find_next_time_event(pa_glib_mainloop *g) { pa_time_event *t, *n = NULL; - assert(g); + g_assert(g); if (g->cached_next_time_event) return g->cached_next_time_event; @@ -445,12 +459,9 @@ static pa_time_event* find_next_time_event(pa_glib_mainloop *g) { return n; } -static gboolean prepare_func(GSource *source, gint *timeout) { - pa_glib_mainloop *g = (pa_glib_mainloop*) source; - +static void scan_dead(pa_glib_mainloop *g) { g_assert(g); - g_assert(timeout); - + if (g->io_events_please_scan) cleanup_io_events(g, 0); @@ -459,6 +470,15 @@ static gboolean prepare_func(GSource *source, gint *timeout) { if (g->defer_events_please_scan) cleanup_defer_events(g, 0); +} + +static gboolean prepare_func(GSource *source, gint *timeout) { + pa_glib_mainloop *g = (pa_glib_mainloop*) source; + + g_assert(g); + g_assert(timeout); + + scan_dead(g); if (g->n_enabled_defer_events) { *timeout = 0; @@ -534,7 +554,7 @@ static gboolean dispatch_func(GSource *source, PA_GCC_UNUSED GSourceFunc callbac break; } - assert(d); + g_assert(d); d->callback(&g->api, d, d->userdata); return TRUE; @@ -553,6 +573,7 @@ static gboolean dispatch_func(GSource *source, PA_GCC_UNUSED GSourceFunc callbac tvnow.tv_usec = now.tv_usec; if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) { + t->enabled = 0; t->callback(&g->api, t, &t->timeval, t->userdata); return TRUE; } @@ -621,7 +642,7 @@ pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) { } void pa_glib_mainloop_free(pa_glib_mainloop* g) { - assert(g); + g_assert(g); cleanup_io_events(g, 1); cleanup_defer_events(g, 1); @@ -633,7 +654,7 @@ void pa_glib_mainloop_free(pa_glib_mainloop* g) { } pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) { - assert(g); + g_assert(g); return &g->api; } -- cgit From 32444f0df3c5a28a812b37a6665f8f39201d80d7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 25 Jul 2006 20:10:30 +0000 Subject: split a few assert()s git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1146 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/idxset.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/pulsecore/idxset.c b/src/pulsecore/idxset.c index d3aec2de..5c79767d 100644 --- a/src/pulsecore/idxset.c +++ b/src/pulsecore/idxset.c @@ -151,13 +151,15 @@ static idxset_entry** array_index(pa_idxset*s, uint32_t idx) { if (idx < s->start_index) return NULL; - return s->array + (idx - s->start_index); + return s->array + idx - s->start_index; } int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) { unsigned h; idxset_entry *e, **a; - assert(s && p); + + assert(s); + assert(p); assert(s->hash_func); h = s->hash_func(p) % s->hash_table_size; @@ -341,7 +343,8 @@ void* pa_idxset_first(pa_idxset *s, uint32_t *idx) { void *pa_idxset_next(pa_idxset *s, uint32_t *idx) { idxset_entry **a, *e = NULL; - assert(s && idx); + assert(s); + assert(idx); if ((a = array_index(s, *idx)) && *a) e = (*a)->iterate_next; @@ -355,7 +358,6 @@ void *pa_idxset_next(pa_idxset *s, uint32_t *idx) { } } - int pa_idxset_foreach(pa_idxset*s, int (*func)(void *p, uint32_t idx, int *del, void*userdata), void *userdata) { idxset_entry *e; assert(s && func); -- cgit From 216bdd48594f6b6be7c09f8b4c7094ec070cdaf1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 25 Jul 2006 20:10:47 +0000 Subject: split a few asserts git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1147 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/tagstruct.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pulsecore/tagstruct.c b/src/pulsecore/tagstruct.c index 60b05a3f..11e85c19 100644 --- a/src/pulsecore/tagstruct.c +++ b/src/pulsecore/tagstruct.c @@ -79,7 +79,8 @@ uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l) { } static void extend(pa_tagstruct*t, size_t l) { - assert(t && t->dynamic); + assert(t); + assert(t->dynamic); if (t->length+l <= t->allocated) return; @@ -87,7 +88,6 @@ static void extend(pa_tagstruct*t, size_t l) { t->data = pa_xrealloc(t->data, t->allocated = t->length+l+100); } - void pa_tagstruct_puts(pa_tagstruct*t, const char *s) { size_t l; assert(t); -- cgit From 563fab983f065fdad14696ce3f13d3df6a2b0370 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 25 Jul 2006 20:39:34 +0000 Subject: Results of profiling PulseAudio with valgrind's callgrind module: rework the default event loop implementation to use PA_LLIST_xxx instead of pa_idxset; don't generate weakeup events if we aren't in STATE_POLLING; minimize dispatching of io events; cache next time event instead of traversing the list of time events on every event loop iteration; other optimizations git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1148 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/mainloop.c | 547 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 353 insertions(+), 194 deletions(-) diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c index dfbc337b..682b2ccd 100644 --- a/src/pulse/mainloop.c +++ b/src/pulse/mainloop.c @@ -49,7 +49,7 @@ #include #include -#include +#include #include #include "mainloop.h" @@ -57,50 +57,66 @@ struct pa_io_event { pa_mainloop *mainloop; int dead; + int fd; pa_io_event_flags_t events; - void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); struct pollfd *pollfd; + + pa_io_event_cb_t callback; void *userdata; - void (*destroy_callback) (pa_mainloop_api*a, pa_io_event *e, void *userdata); + pa_io_event_destroy_cb_t destroy_callback; + + PA_LLIST_FIELDS(pa_io_event); }; struct pa_time_event { pa_mainloop *mainloop; int dead; + int enabled; struct timeval timeval; - void (*callback)(pa_mainloop_api*a, pa_time_event *e, const struct timeval*tv, void *userdata); + + pa_time_event_cb_t callback; void *userdata; - void (*destroy_callback) (pa_mainloop_api*a, pa_time_event *e, void *userdata); + pa_time_event_destroy_cb_t destroy_callback; + + PA_LLIST_FIELDS(pa_time_event); }; struct pa_defer_event { pa_mainloop *mainloop; int dead; + int enabled; - void (*callback)(pa_mainloop_api*a, pa_defer_event*e, void *userdata); + + pa_defer_event_cb_t callback; void *userdata; - void (*destroy_callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata); + pa_defer_event_destroy_cb_t destroy_callback; + + PA_LLIST_FIELDS(pa_defer_event); }; struct pa_mainloop { - pa_idxset *io_events, *time_events, *defer_events; - int io_events_scan_dead, defer_events_scan_dead, time_events_scan_dead; + PA_LLIST_HEAD(pa_io_event, io_events); + PA_LLIST_HEAD(pa_time_event, time_events); + PA_LLIST_HEAD(pa_defer_event, defer_events); + + int n_enabled_defer_events, n_enabled_time_events, n_io_events; + int io_events_please_scan, time_events_please_scan, defer_events_please_scan; struct pollfd *pollfds; unsigned max_pollfds, n_pollfds; int rebuild_pollfds; int prepared_timeout; + pa_time_event *cached_next_time_event; int quit, retval; pa_mainloop_api api; - int deferred_pending; - int wakeup_pipe[2]; int wakeup_pipe_type; + int wakeup_requested; enum { STATE_PASSIVE, @@ -112,33 +128,55 @@ struct pa_mainloop { pa_poll_func poll_func; void *poll_func_userdata; + int poll_func_ret; }; +static short map_flags_to_libc(pa_io_event_flags_t flags) { + return + (flags & PA_IO_EVENT_INPUT ? POLLIN : 0) | + (flags & PA_IO_EVENT_OUTPUT ? POLLOUT : 0) | + (flags & PA_IO_EVENT_ERROR ? POLLERR : 0) | + (flags & PA_IO_EVENT_HANGUP ? POLLHUP : 0); +} + +static pa_io_event_flags_t map_flags_from_libc(short flags) { + return + (flags & POLLIN ? PA_IO_EVENT_INPUT : 0) | + (flags & POLLOUT ? PA_IO_EVENT_OUTPUT : 0) | + (flags & POLLERR ? PA_IO_EVENT_ERROR : 0) | + (flags & POLLHUP ? PA_IO_EVENT_HANGUP : 0); +} + /* IO events */ static pa_io_event* mainloop_io_new( - pa_mainloop_api*a, - int fd, - pa_io_event_flags_t events, - void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), - void *userdata) { + pa_mainloop_api*a, + int fd, + pa_io_event_flags_t events, + pa_io_event_cb_t callback, + void *userdata) { pa_mainloop *m; pa_io_event *e; - assert(a && a->userdata && fd >= 0 && callback); + assert(a); + assert(a->userdata); + assert(fd >= 0); + assert(callback); + m = a->userdata; assert(a == &m->api); - e = pa_xmalloc(sizeof(pa_io_event)); + e = pa_xnew(pa_io_event, 1); e->mainloop = m; e->dead = 0; e->fd = fd; e->events = events; + e->pollfd = NULL; + e->callback = callback; e->userdata = userdata; e->destroy_callback = NULL; - e->pollfd = NULL; #ifdef OS_IS_WIN32 { @@ -160,8 +198,9 @@ static pa_io_event* mainloop_io_new( } #endif - pa_idxset_put(m->io_events, e, NULL); + PA_LLIST_PREPEND(pa_io_event, m->io_events, e); m->rebuild_pollfds = 1; + m->n_io_events ++; pa_mainloop_wakeup(m); @@ -169,48 +208,69 @@ static pa_io_event* mainloop_io_new( } static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags_t events) { - assert(e && e->mainloop); + assert(e); + assert(!e->dead); + if (e->events == events) + return; + e->events = events; - e->mainloop->rebuild_pollfds = 1; + + if (e->pollfd) + e->pollfd->events = map_flags_to_libc(events); + else + e->mainloop->rebuild_pollfds = 1; pa_mainloop_wakeup(e->mainloop); } static void mainloop_io_free(pa_io_event *e) { - assert(e && e->mainloop); + assert(e); + assert(!e->dead); - e->dead = e->mainloop->io_events_scan_dead = e->mainloop->rebuild_pollfds = 1; + e->dead = 1; + e->mainloop->io_events_please_scan ++; + + e->mainloop->n_io_events --; + e->mainloop->rebuild_pollfds = 1; pa_mainloop_wakeup(e->mainloop); } -static void mainloop_io_set_destroy(pa_io_event *e, void (*callback)(pa_mainloop_api*a, pa_io_event *e, void *userdata)) { +static void mainloop_io_set_destroy(pa_io_event *e, pa_io_event_destroy_cb_t callback) { assert(e); + e->destroy_callback = callback; } /* Defer events */ -static pa_defer_event* mainloop_defer_new(pa_mainloop_api*a, void (*callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata), void *userdata) { +static pa_defer_event* mainloop_defer_new( + pa_mainloop_api*a, + pa_defer_event_cb_t callback, + void *userdata) { + pa_mainloop *m; pa_defer_event *e; - assert(a && a->userdata && callback); + assert(a); + assert(a->userdata); + assert(callback); + m = a->userdata; assert(a == &m->api); - e = pa_xmalloc(sizeof(pa_defer_event)); + e = pa_xnew(pa_defer_event, 1); e->mainloop = m; e->dead = 0; e->enabled = 1; + m->n_enabled_defer_events++; + e->callback = callback; e->userdata = userdata; e->destroy_callback = NULL; - pa_idxset_put(m->defer_events, e, NULL); - - m->deferred_pending++; + PA_LLIST_PREPEND(pa_defer_event, m->defer_events, e); pa_mainloop_wakeup(e->mainloop); @@ -219,12 +279,13 @@ static pa_defer_event* mainloop_defer_new(pa_mainloop_api*a, void (*callback) (p static void mainloop_defer_enable(pa_defer_event *e, int b) { assert(e); + assert(!e->dead); if (e->enabled && !b) { - assert(e->mainloop->deferred_pending > 0); - e->mainloop->deferred_pending--; + assert(e->mainloop->n_enabled_defer_events > 0); + e->mainloop->n_enabled_defer_events--; } else if (!e->enabled && b) { - e->mainloop->deferred_pending++; + e->mainloop->n_enabled_defer_events++; pa_mainloop_wakeup(e->mainloop); } @@ -233,42 +294,63 @@ static void mainloop_defer_enable(pa_defer_event *e, int b) { static void mainloop_defer_free(pa_defer_event *e) { assert(e); - e->dead = e->mainloop->defer_events_scan_dead = 1; + assert(!e->dead); + + e->dead = 1; + e->mainloop->defer_events_please_scan ++; if (e->enabled) { - e->enabled = 0; - assert(e->mainloop->deferred_pending > 0); - e->mainloop->deferred_pending--; + assert(e->mainloop->n_enabled_defer_events > 0); + e->mainloop->n_enabled_defer_events--; } } -static void mainloop_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api*a, pa_defer_event *e, void *userdata)) { +static void mainloop_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t callback) { assert(e); + assert(!e->dead); + e->destroy_callback = callback; } /* Time events */ -static pa_time_event* mainloop_time_new(pa_mainloop_api*a, const struct timeval *tv, void (*callback) (pa_mainloop_api*a, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { +static pa_time_event* mainloop_time_new( + pa_mainloop_api*a, + const struct timeval *tv, + pa_time_event_cb_t callback, + void *userdata) { + pa_mainloop *m; pa_time_event *e; - assert(a && a->userdata && callback); + assert(a); + assert(a->userdata); + assert(callback); + m = a->userdata; assert(a == &m->api); - e = pa_xmalloc(sizeof(pa_time_event)); + e = pa_xnew(pa_time_event, 1); e->mainloop = m; e->dead = 0; - e->enabled = !!tv; - if (tv) + if ((e->enabled = !!tv)) { e->timeval = *tv; + m->n_enabled_time_events++; + + if (m->cached_next_time_event) { + assert(m->cached_next_time_event->enabled); + + if (pa_timeval_cmp(tv, &m->cached_next_time_event->timeval) < 0) + m->cached_next_time_event = e; + } + } + e->callback = callback; e->userdata = userdata; e->destroy_callback = NULL; - pa_idxset_put(m->time_events, e, NULL); + PA_LLIST_PREPEND(pa_time_event, m->time_events, e); if (e->enabled) pa_mainloop_wakeup(m); @@ -278,26 +360,50 @@ static pa_time_event* mainloop_time_new(pa_mainloop_api*a, const struct timeval static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) { assert(e); + assert(!e->dead); - if (tv) { - e->enabled = 1; - e->timeval = *tv; + if (e->enabled && !tv) { + assert(e->mainloop->n_enabled_time_events > 0); + e->mainloop->n_enabled_time_events--; + } else if (!e->enabled && tv) + e->mainloop->n_enabled_time_events++; + if ((e->enabled = !!tv)) { + e->timeval = *tv; pa_mainloop_wakeup(e->mainloop); - } else - e->enabled = 0; + } + + if (e->mainloop->cached_next_time_event && e->enabled) { + assert(e->mainloop->cached_next_time_event->enabled); + + if (pa_timeval_cmp(tv, &e->mainloop->cached_next_time_event->timeval) < 0) + e->mainloop->cached_next_time_event = e; + } else if (e->mainloop->cached_next_time_event == e) + e->mainloop->cached_next_time_event = NULL; } static void mainloop_time_free(pa_time_event *e) { assert(e); + assert(!e->dead); - e->dead = e->mainloop->time_events_scan_dead = 1; + e->dead = 1; + e->mainloop->time_events_please_scan ++; + if (e->enabled) { + assert(e->mainloop->n_enabled_time_events > 0); + e->mainloop->n_enabled_time_events--; + } + + if (e->mainloop->cached_next_time_event == e) + e->mainloop->cached_next_time_event = NULL; + /* no wakeup needed here. Think about it! */ } -static void mainloop_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*a, pa_time_event *e, void *userdata)) { +static void mainloop_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t callback) { assert(e); + assert(!e->dead); + e->destroy_callback = callback; } @@ -305,7 +411,9 @@ static void mainloop_time_set_destroy(pa_time_event *e, void (*callback)(pa_main static void mainloop_quit(pa_mainloop_api*a, int retval) { pa_mainloop *m; - assert(a && a->userdata); + + assert(a); + assert(a->userdata); m = a->userdata; assert(a == &m->api); @@ -336,7 +444,7 @@ static const pa_mainloop_api vtable = { pa_mainloop *pa_mainloop_new(void) { pa_mainloop *m; - m = pa_xmalloc(sizeof(pa_mainloop)); + m = pa_xnew(pa_mainloop, 1); m->wakeup_pipe_type = 0; if (pipe(m->wakeup_pipe) < 0) { @@ -347,14 +455,17 @@ pa_mainloop *pa_mainloop_new(void) { pa_make_nonblock_fd(m->wakeup_pipe[0]); pa_make_nonblock_fd(m->wakeup_pipe[1]); + m->wakeup_requested = 0; - m->io_events = pa_idxset_new(NULL, NULL); - m->defer_events = pa_idxset_new(NULL, NULL); - m->time_events = pa_idxset_new(NULL, NULL); + PA_LLIST_HEAD_INIT(pa_io_event, m->io_events); + PA_LLIST_HEAD_INIT(pa_time_event, m->time_events); + PA_LLIST_HEAD_INIT(pa_defer_event, m->defer_events); - assert(m->io_events && m->defer_events && m->time_events); + m->n_enabled_defer_events = m->n_enabled_time_events = m->n_io_events = 0; + m->io_events_please_scan = m->time_events_please_scan = m->defer_events_please_scan = 0; - m->io_events_scan_dead = m->defer_events_scan_dead = m->time_events_scan_dead = 0; + m->cached_next_time_event = NULL; + m->prepared_timeout = 0; m->pollfds = NULL; m->max_pollfds = m->n_pollfds = 0; @@ -365,74 +476,124 @@ pa_mainloop *pa_mainloop_new(void) { m->api = vtable; m->api.userdata = m; - m->deferred_pending = 0; - m->state = STATE_PASSIVE; m->poll_func = NULL; m->poll_func_userdata = NULL; - - m->retval = -1; + m->poll_func_ret = -1; return m; } -static int io_foreach(void *p, uint32_t PA_GCC_UNUSED idx, int *del, void*userdata) { - pa_io_event *e = p; - int *all = userdata; - assert(e && del && all); +static void cleanup_io_events(pa_mainloop *m, int force) { + pa_io_event *e; - if (!*all && !e->dead) - return 0; - - if (e->destroy_callback) - e->destroy_callback(&e->mainloop->api, e, e->userdata); - pa_xfree(e); - *del = 1; - return 0; + e = m->io_events; + while (e) { + pa_io_event *n = e->next; + + if (!force && m->io_events_please_scan <= 0) + break; + + if (force || e->dead) { + PA_LLIST_REMOVE(pa_io_event, m->io_events, e); + + if (e->dead) { + assert(m->io_events_please_scan > 0); + m->io_events_please_scan--; + } + + if (e->destroy_callback) + e->destroy_callback(&m->api, e, e->userdata); + + pa_xfree(e); + + m->rebuild_pollfds = 1; + } + + e = n; + } + + assert(m->io_events_please_scan == 0); } -static int time_foreach(void *p, uint32_t PA_GCC_UNUSED idx, int *del, void*userdata) { - pa_time_event *e = p; - int *all = userdata; - assert(e && del && all); +static void cleanup_time_events(pa_mainloop *m, int force) { + pa_time_event *e; - if (!*all && !e->dead) - return 0; - - if (e->destroy_callback) - e->destroy_callback(&e->mainloop->api, e, e->userdata); - pa_xfree(e); - *del = 1; - return 0; + e = m->time_events; + while (e) { + pa_time_event *n = e->next; + + if (!force && m->time_events_please_scan <= 0) + break; + + if (force || e->dead) { + PA_LLIST_REMOVE(pa_time_event, m->time_events, e); + + if (e->dead) { + assert(m->time_events_please_scan > 0); + m->time_events_please_scan--; + } + + if (!e->dead && e->enabled) { + assert(m->n_enabled_time_events > 0); + m->n_enabled_time_events--; + } + + if (e->destroy_callback) + e->destroy_callback(&m->api, e, e->userdata); + + pa_xfree(e); + } + + e = n; + } + + assert(m->time_events_please_scan == 0); } -static int defer_foreach(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void*userdata) { - pa_defer_event *e = p; - int *all = userdata; - assert(e && del && all); +static void cleanup_defer_events(pa_mainloop *m, int force) { + pa_defer_event *e; - if (!*all && !e->dead) - return 0; - - if (e->destroy_callback) - e->destroy_callback(&e->mainloop->api, e, e->userdata); - pa_xfree(e); - *del = 1; - return 0; + e = m->defer_events; + while (e) { + pa_defer_event *n = e->next; + + if (!force && m->defer_events_please_scan <= 0) + break; + + if (force || e->dead) { + PA_LLIST_REMOVE(pa_defer_event, m->defer_events, e); + + if (e->dead) { + assert(m->defer_events_please_scan > 0); + m->defer_events_please_scan--; + } + + if (!e->dead && e->enabled) { + assert(m->n_enabled_defer_events > 0); + m->n_enabled_defer_events--; + } + + if (e->destroy_callback) + e->destroy_callback(&m->api, e, e->userdata); + + pa_xfree(e); + } + + e = n; + } + + assert(m->defer_events_please_scan == 0); } + void pa_mainloop_free(pa_mainloop* m) { - int all = 1; assert(m); - pa_idxset_foreach(m->io_events, io_foreach, &all); - pa_idxset_foreach(m->time_events, time_foreach, &all); - pa_idxset_foreach(m->defer_events, defer_foreach, &all); - - pa_idxset_free(m->io_events, NULL, NULL); - pa_idxset_free(m->time_events, NULL, NULL); - pa_idxset_free(m->defer_events, NULL, NULL); + cleanup_io_events(m, 1); + cleanup_defer_events(m, 1); + cleanup_time_events(m, 1); pa_xfree(m->pollfds); @@ -445,27 +606,26 @@ void pa_mainloop_free(pa_mainloop* m) { } static void scan_dead(pa_mainloop *m) { - int all = 0; assert(m); - if (m->io_events_scan_dead) - pa_idxset_foreach(m->io_events, io_foreach, &all); - if (m->time_events_scan_dead) - pa_idxset_foreach(m->time_events, time_foreach, &all); - if (m->defer_events_scan_dead) - pa_idxset_foreach(m->defer_events, defer_foreach, &all); + if (m->io_events_please_scan) + cleanup_io_events(m, 0); - m->io_events_scan_dead = m->time_events_scan_dead = m->defer_events_scan_dead = 0; + if (m->time_events_please_scan) + cleanup_time_events(m, 0); + + if (m->defer_events_please_scan) + cleanup_defer_events(m, 0); } static void rebuild_pollfds(pa_mainloop *m) { pa_io_event*e; struct pollfd *p; - uint32_t idx = PA_IDXSET_INVALID; unsigned l; - l = pa_idxset_size(m->io_events) + 1; + l = m->n_io_events + 1; if (m->max_pollfds < l) { + l *= 2; m->pollfds = pa_xrealloc(m->pollfds, sizeof(struct pollfd)*l); m->max_pollfds = l; } @@ -481,7 +641,7 @@ static void rebuild_pollfds(pa_mainloop *m) { m->n_pollfds++; } - for (e = pa_idxset_first(m->io_events, &idx); e; e = pa_idxset_next(m->io_events, &idx)) { + for (e = m->io_events; e; e = e->next) { if (e->dead) { e->pollfd = NULL; continue; @@ -489,11 +649,7 @@ static void rebuild_pollfds(pa_mainloop *m) { e->pollfd = p; p->fd = e->fd; - p->events = - ((e->events & PA_IO_EVENT_INPUT) ? POLLIN : 0) | - ((e->events & PA_IO_EVENT_OUTPUT) ? POLLOUT : 0) | - POLLHUP | - POLLERR; + p->events = map_flags_to_libc(e->events); p->revents = 0; p++; @@ -504,37 +660,34 @@ static void rebuild_pollfds(pa_mainloop *m) { } static int dispatch_pollfds(pa_mainloop *m) { - uint32_t idx = PA_IDXSET_INVALID; pa_io_event *e; - int r = 0; + int r = 0, k; - for (e = pa_idxset_first(m->io_events, &idx); e && !m->quit; e = pa_idxset_next(m->io_events, &idx)) { + assert(m->poll_func_ret > 0); + + for (e = m->io_events, k = m->poll_func_ret; e && !m->quit && k > 0; e = e->next) { if (e->dead || !e->pollfd || !e->pollfd->revents) continue; assert(e->pollfd->fd == e->fd && e->callback); - e->callback(&m->api, e, e->fd, - (e->pollfd->revents & POLLHUP ? PA_IO_EVENT_HANGUP : 0) | - (e->pollfd->revents & POLLIN ? PA_IO_EVENT_INPUT : 0) | - (e->pollfd->revents & POLLOUT ? PA_IO_EVENT_OUTPUT : 0) | - (e->pollfd->revents & POLLERR ? PA_IO_EVENT_ERROR : 0), - e->userdata); + e->callback(&m->api, e, e->fd, map_flags_from_libc(e->pollfd->revents), e->userdata); e->pollfd->revents = 0; r++; + + k--; } return r; } static int dispatch_defer(pa_mainloop *m) { - uint32_t idx; pa_defer_event *e; int r = 0; - if (!m->deferred_pending) + if (m->n_enabled_defer_events <= 0) return 0; - for (e = pa_idxset_first(m->defer_events, &idx); e && !m->quit; e = pa_idxset_next(m->defer_events, &idx)) { + for (e = m->defer_events; e && !m->quit; e = e->next) { if (e->dead || !e->enabled) continue; @@ -546,70 +699,71 @@ static int dispatch_defer(pa_mainloop *m) { return r; } -static int calc_next_timeout(pa_mainloop *m) { - uint32_t idx; - pa_time_event *e; - struct timeval now; - int t = -1; - int got_time = 0; +static pa_time_event* find_next_time_event(pa_mainloop *m) { + pa_time_event *t, *n = NULL; + assert(m); - if (pa_idxset_isempty(m->time_events)) - return -1; + if (m->cached_next_time_event) + return m->cached_next_time_event; + + for (t = m->time_events; t; t = t->next) { - for (e = pa_idxset_first(m->time_events, &idx); e; e = pa_idxset_next(m->time_events, &idx)) { - int tmp; - - if (e->dead || !e->enabled) + if (t->dead || !t->enabled) continue; - /* Let's save a system call */ - if (!got_time) { - pa_gettimeofday(&now); - got_time = 1; + if (!n || pa_timeval_cmp(&t->timeval, &n->timeval) < 0) { + n = t; + + /* Shortcut for tv = { 0, 0 } */ + if (n->timeval.tv_sec <= 0) + break; } + } - if (e->timeval.tv_sec < now.tv_sec || (e->timeval.tv_sec == now.tv_sec && e->timeval.tv_usec <= now.tv_usec)) - return 0; + m->cached_next_time_event = n; + return n; +} - tmp = (e->timeval.tv_sec - now.tv_sec)*1000; - - if (e->timeval.tv_usec > now.tv_usec) - tmp += (e->timeval.tv_usec - now.tv_usec)/1000; - else - tmp -= (now.tv_usec - e->timeval.tv_usec)/1000; +static int calc_next_timeout(pa_mainloop *m) { + pa_time_event *t; + struct timeval now; + pa_usec_t usec; - if (tmp == 0) - return 0; - else if (t == -1 || tmp < t) - t = tmp; - } + if (!m->n_enabled_time_events) + return -1; - return t; + t = find_next_time_event(m); + assert(t); + + if (t->timeval.tv_sec <= 0) + return 0; + + pa_gettimeofday(&now); + + if (pa_timeval_cmp(&t->timeval, &now) <= 0) + return 0; + + usec = pa_timeval_diff(&t->timeval, &now); + return (int) (usec / 1000); } static int dispatch_timeout(pa_mainloop *m) { - uint32_t idx; pa_time_event *e; struct timeval now; - int got_time = 0; int r = 0; assert(m); - if (pa_idxset_isempty(m->time_events)) + if (m->n_enabled_time_events <= 0) return 0; - for (e = pa_idxset_first(m->time_events, &idx); e && !m->quit; e = pa_idxset_next(m->time_events, &idx)) { + pa_gettimeofday(&now); + + for (e = m->time_events; e && !m->quit; e = e->next) { if (e->dead || !e->enabled) continue; - /* Let's save a system call */ - if (!got_time) { - pa_gettimeofday(&now); - got_time = 1; - } - - if (e->timeval.tv_sec < now.tv_sec || (e->timeval.tv_sec == now.tv_sec && e->timeval.tv_usec <= now.tv_usec)) { + if (pa_timeval_cmp(&e->timeval, &now) <= 0) { assert(e->callback); e->enabled = 0; @@ -626,8 +780,10 @@ void pa_mainloop_wakeup(pa_mainloop *m) { char c = 'W'; assert(m); - if (m->wakeup_pipe[1] >= 0) + if (m->wakeup_pipe[1] >= 0 && m->state == STATE_POLLING) { pa_write(m->wakeup_pipe[1], &c, sizeof(c), &m->wakeup_pipe_type); + m->wakeup_requested++; + } } static void clear_wakeup(pa_mainloop *m) { @@ -638,7 +794,10 @@ static void clear_wakeup(pa_mainloop *m) { if (m->wakeup_pipe[0] < 0) return; - while (pa_read(m->wakeup_pipe[0], &c, sizeof(c), &m->wakeup_pipe_type) == sizeof(c)); + if (m->wakeup_requested) { + while (pa_read(m->wakeup_pipe[0], &c, sizeof(c), &m->wakeup_pipe_type) == sizeof(c)); + m->wakeup_requested = 0; + } } int pa_mainloop_prepare(pa_mainloop *m, int timeout) { @@ -651,8 +810,7 @@ int pa_mainloop_prepare(pa_mainloop *m, int timeout) { if (m->quit) goto quit; - if (!m->deferred_pending) { - + if (m->n_enabled_defer_events <= 0) { if (m->rebuild_pollfds) rebuild_pollfds(m); @@ -670,8 +828,6 @@ quit: } int pa_mainloop_poll(pa_mainloop *m) { - int r; - assert(m); assert(m->state == STATE_PREPARED); @@ -680,24 +836,26 @@ int pa_mainloop_poll(pa_mainloop *m) { m->state = STATE_POLLING; - if (m->deferred_pending) - r = 0; + if (m->n_enabled_defer_events ) + m->poll_func_ret = 0; else { + assert(!m->rebuild_pollfds); + if (m->poll_func) - r = m->poll_func(m->pollfds, m->n_pollfds, m->prepared_timeout, m->poll_func_userdata); + m->poll_func_ret = m->poll_func(m->pollfds, m->n_pollfds, m->prepared_timeout, m->poll_func_userdata); else - r = poll(m->pollfds, m->n_pollfds, m->prepared_timeout); + m->poll_func_ret = poll(m->pollfds, m->n_pollfds, m->prepared_timeout); - if (r < 0) { + if (m->poll_func_ret < 0) { if (errno == EINTR) - r = 0; + m->poll_func_ret = 0; else pa_log(__FILE__": poll(): %s", pa_cstrerror(errno)); } } - m->state = r < 0 ? STATE_PASSIVE : STATE_POLLED; - return r; + m->state = m->poll_func_ret < 0 ? STATE_PASSIVE : STATE_POLLED; + return m->poll_func_ret; quit: m->state = STATE_QUIT; @@ -713,16 +871,17 @@ int pa_mainloop_dispatch(pa_mainloop *m) { if (m->quit) goto quit; - if (m->deferred_pending) + if (m->n_enabled_defer_events) dispatched += dispatch_defer(m); else { - dispatched += dispatch_timeout(m); + if (m->n_enabled_time_events) + dispatched += dispatch_timeout(m); if (m->quit) goto quit; - - dispatched += dispatch_pollfds(m); + if (m->poll_func_ret > 0) + dispatched += dispatch_pollfds(m); } if (m->quit) -- cgit From 61ce8bb0024764fa059aa5f5f1f5c2a0189c40bc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 25 Jul 2006 20:51:15 +0000 Subject: add new command line option --no-cpu-limit. This is useful when running PulseAudio in valgrind's massif or callgrind tools git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1149 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/cmdline.c | 14 +++++++++++++- src/daemon/daemon-conf.c | 22 +++++++++++++--------- src/daemon/daemon-conf.h | 3 ++- src/daemon/daemon.conf.in | 5 +++++ src/daemon/main.c | 14 +++++++++----- 5 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c index ab876edf..e00f290e 100644 --- a/src/daemon/cmdline.c +++ b/src/daemon/cmdline.c @@ -59,6 +59,7 @@ enum { ARG_KILL, ARG_USE_PID_FILE, ARG_CHECK, + ARG_NO_CPU_LIMIT, ARG_SYSTEM }; @@ -86,6 +87,7 @@ static struct option long_options[] = { {"use-pid-file", 2, 0, ARG_USE_PID_FILE}, {"check", 0, 0, ARG_CHECK}, {"system", 2, 0, ARG_SYSTEM}, + {"no-cpu-limit", 2, 0, ARG_NO_CPU_LIMIT}, {NULL, 0, 0, 0} }; @@ -128,7 +130,9 @@ void pa_cmdline_help(const char *argv0) { " (one of src-sinc-medium-quality,\n" " src-sinc-best-quality,src-sinc-fastest\n" " src-zero-order-hold,src-linear,trivial)\n" - " --use-pid-file[=BOOL] Create a PID file\n\n" + " --use-pid-file[=BOOL] Create a PID file\n" + " --no-cpu-limit[=BOOL] Do not install CPU load limiter on\n" + " platforms that support it.\n\n" "STARTUP SCRIPT:\n" " -L, --load=\"MODULE ARGUMENTS\" Load the specified plugin module with\n" @@ -286,6 +290,14 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d goto fail; } break; + + case ARG_NO_CPU_LIMIT: + if ((conf->no_cpu_limit = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + pa_log(__FILE__": --no-cpu-limit expects boolean argument"); + goto fail; + } + break; + default: goto fail; diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 0426989c..3e585d90 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -72,7 +72,8 @@ static const pa_daemon_conf default_conf = { .resample_method = PA_RESAMPLER_SRC_SINC_FASTEST, .config_file = NULL, .use_pid_file = 1, - .system_instance = 0 + .system_instance = 0, + .no_cpu_limit = 0 #ifdef HAVE_SYS_RESOURCE_H , .rlimit_as = { .value = 0, .is_set = 0 }, .rlimit_core = { .value = 0, .is_set = 0 }, @@ -246,6 +247,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { { "resample-method", parse_resample_method, NULL }, { "use-pid-file", pa_config_parse_bool, NULL }, { "system-instance", pa_config_parse_bool, NULL }, + { "no-cpu-limit", pa_config_parse_bool, NULL }, #ifdef HAVE_SYS_RESOURCE_H { "rlimit-as", parse_rlimit, NULL }, { "rlimit-core", parse_rlimit, NULL }, @@ -278,21 +280,22 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { table[12].data = c; table[13].data = &c->use_pid_file; table[14].data = &c->system_instance; + table[15].data = &c->no_cpu_limit; #ifdef HAVE_SYS_RESOURCE_H - table[15].data = &c->rlimit_as; - table[16].data = &c->rlimit_core; - table[17].data = &c->rlimit_data; - table[18].data = &c->rlimit_fsize; - table[19].data = &c->rlimit_nofile; - table[20].data = &c->rlimit_stack; + table[16].data = &c->rlimit_as; + table[17].data = &c->rlimit_core; + table[18].data = &c->rlimit_data; + table[19].data = &c->rlimit_fsize; + table[20].data = &c->rlimit_nofile; + table[21].data = &c->rlimit_stack; #ifdef RLIMIT_NPROC - table[21].data = &c->rlimit_nproc; + table[22].data = &c->rlimit_nproc; #endif #ifdef RLIMIT_MEMLOCK #ifndef RLIMIT_NPROC #error "Houston, we have a numbering problem!" #endif - table[22].data = &c->rlimit_memlock; + table[23].data = &c->rlimit_memlock; #endif #endif @@ -363,6 +366,7 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { pa_strbuf_printf(s, "resample-method = %s\n", pa_resample_method_to_string(c->resample_method)); pa_strbuf_printf(s, "use-pid-file = %i\n", c->use_pid_file); pa_strbuf_printf(s, "system-instance = %i\n", !!c->system_instance); + pa_strbuf_printf(s, "no-cpu-limit = %i\n", !!c->no_cpu_limit); #ifdef HAVE_SYS_RESOURCE_H pa_strbuf_printf(s, "rlimit-as = %li\n", c->rlimit_as.is_set ? (long int) c->rlimit_as.value : -1); pa_strbuf_printf(s, "rlimit-core = %li\n", c->rlimit_core.is_set ? (long int) c->rlimit_core.value : -1); diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h index a09773f1..84208336 100644 --- a/src/daemon/daemon-conf.h +++ b/src/daemon/daemon-conf.h @@ -58,7 +58,8 @@ typedef struct pa_daemon_conf { scache_idle_time, auto_log_target, use_pid_file, - system_instance; + system_instance, + no_cpu_limit; char *script_commands, *dl_search_path, *default_script_file; pa_log_target_t log_target; pa_log_level_t log_level; diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in index 696b25a9..0204b9e3 100644 --- a/src/daemon/daemon.conf.in +++ b/src/daemon/daemon.conf.in @@ -79,6 +79,11 @@ ## effectively disables multiple instances. ; use-pid-file = 1 +## Do not install the CPU load limit, even on platforms where it is +## supported. This option is useful when debugging/profiling +## PulseAudio to disable disturbing SIGXCPU signals. +; no-cpu-limit = 0 + ## Run the daemon as system-wide instance, requires root priviliges ; system-instance = 0 diff --git a/src/daemon/main.c b/src/daemon/main.c index 3ced3bf6..38d465f8 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -588,10 +588,12 @@ int main(int argc, char *argv[]) { c->running_as_daemon = 1; oil_init(); - - r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop)); - assert(r == 0); - + + if (!conf->no_cpu_limit) { + r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop)); + assert(r == 0); + } + buf = pa_strbuf_new(); if (conf->default_script_file) r = pa_cli_command_execute_file(c, conf->default_script_file, buf, &conf->fail); @@ -645,7 +647,9 @@ int main(int argc, char *argv[]) { pa_core_free(c); - pa_cpu_limit_done(); + if (!conf->no_cpu_limit) + pa_cpu_limit_done(); + pa_signal_done(); pa_mainloop_free(mainloop); -- cgit From cc1d8213d6a58b0022017f8d231a346387aab507 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Jul 2006 17:36:14 +0000 Subject: add new module "module-gconf" which reads configuration information from gconf. this will be used in my upcoming paconf module git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1150 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 24 ++- src/modules/gconf/Makefile | 13 ++ src/modules/gconf/gconf-helper.c | 123 +++++++++++++ src/modules/gconf/module-gconf.c | 386 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 544 insertions(+), 2 deletions(-) create mode 100644 src/modules/gconf/Makefile create mode 100644 src/modules/gconf/gconf-helper.c create mode 100644 src/modules/gconf/module-gconf.c diff --git a/src/Makefile.am b/src/Makefile.am index e0add703..bb08ed78 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,6 +25,7 @@ pulseincludedir=$(includedir)/pulse pulsecoreincludedir=$(includedir)/pulsecore pulseconfdir=$(sysconfdir)/pulse +pulselibexecdir=$(libexecdir)/pulse ################################### # Defines # @@ -883,6 +884,14 @@ modlibexec_LTLIBRARIES += \ module-jack-source.la endif +if HAVE_GCONF +modlibexec_LTLIBRARIES += \ + module-gconf.la + +pulselibexec_PROGRAMS = \ + gconf-helper +endif + if OS_IS_WIN32 modlibexec_LTLIBRARIES += \ module-waveout.la @@ -930,8 +939,8 @@ SYMDEF_FILES = \ modules/rtp/module-rtp-recv-symdef.h \ modules/module-jack-sink-symdef.h \ modules/module-jack-source-symdef.h \ - modules/module-volume-restore-symdef.h - + modules/module-volume-restore-symdef.h \ + modules/gconf/module-gconf-symdef.h EXTRA_DIST += $(SYMDEF_FILES) BUILT_SOURCES += $(SYMDEF_FILES) @@ -1171,6 +1180,17 @@ module_jack_source_la_LDFLAGS = -module -avoid-version module_jack_source_la_LIBADD = $(AM_LIBADD) libpulsecore.la $(JACK_LIBS) module_jack_source_la_CFLAGS = $(AM_LIBADD) $(JACK_CFLAGS) +# GConf support +module_gconf_la_SOURCES = modules/gconf/module-gconf.c +module_gconf_la_LDFLAGS = -module -avoid-version +module_gconf_la_LIBADD = $(AM_LIBADD) libpulsecore.la +module_gconf_la_CFLAGS = $(AM_CFLAGS) -DPA_GCONF_HELPER=\"$(pulselibexecdir)/gconf-helper\" + +gconf_helper_SOURCES = modules/gconf/gconf-helper.c +gconf_helper_LDADD = $(AM_LDADD) $(GCONF_LIBS) +gconf_helper_CFLAGS = $(AM_CFLAGS) $(GCONF_CFLAGS) +gconf_helper_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + ################################### # Some minor stuff # ################################### diff --git a/src/modules/gconf/Makefile b/src/modules/gconf/Makefile new file mode 100644 index 00000000..316beb72 --- /dev/null +++ b/src/modules/gconf/Makefile @@ -0,0 +1,13 @@ +# This is a dirty trick just to ease compilation with emacs +# +# This file is not intended to be distributed or anything +# +# So: don't touch it, even better ignore it! + +all: + $(MAKE) -C ../.. + +clean: + $(MAKE) -C ../.. clean + +.PHONY: all clean diff --git a/src/modules/gconf/gconf-helper.c b/src/modules/gconf/gconf-helper.c new file mode 100644 index 00000000..c8b9b144 --- /dev/null +++ b/src/modules/gconf/gconf-helper.c @@ -0,0 +1,123 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +#define PA_GCONF_ROOT "/system/pulseaudio" +#define PA_GCONF_PATH_MODULES PA_GCONF_ROOT"/modules" + +static void handle_module(GConfClient *client, const char *name) { + gchar p[1024]; + gboolean enabled; + int i; + + snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/enabled", name); + enabled = gconf_client_get_bool(client, p, FALSE); + + printf("%c%s%c", enabled ? '+' : '-', name, 0); + + if (enabled) { + + for (i = 0; i < 10; i++) { + gchar *n, *a; + + snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/name%i", name, i); + if (!(n = gconf_client_get_string(client, p, NULL)) || !*n) + break; + + snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/args%i", name, i); + a = gconf_client_get_string(client, p, NULL); + + printf("%s%c%s%c", n, 0, a ? a : "", 0); + + g_free(n); + g_free(a); + } + + printf("%c", 0); + } + + fflush(stdout); +} + +static void modules_callback( + GConfClient* client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data) { + + const char *n; + char buf[128]; + + g_assert(strncmp(entry->key, PA_GCONF_PATH_MODULES"/", sizeof(PA_GCONF_PATH_MODULES)) == 0); + + n = entry->key + sizeof(PA_GCONF_PATH_MODULES); + + g_strlcpy(buf, n, sizeof(buf)); + buf[strcspn(buf, "/")] = 0; + + handle_module(client, buf); +} + +int main(int argc, char *argv[]) { + GMainLoop *g; + GConfClient *client; + GSList *modules, *m; + + if (!(client = gconf_client_get_default())) + goto fail; + + gconf_client_add_dir(client, PA_GCONF_ROOT, GCONF_CLIENT_PRELOAD_RECURSIVE, NULL); + gconf_client_notify_add(client, PA_GCONF_PATH_MODULES, modules_callback, NULL, NULL, NULL); + + modules = gconf_client_all_dirs(client, PA_GCONF_PATH_MODULES, NULL); + + for (m = modules; m; m = m->next) { + char *e = strrchr(m->data, '/'); + handle_module(client, e ? e+1 : m->data); + } + + g_slist_free(modules); + + /* Signal the parent that we are now initialized */ + printf("!"); + fflush(stdout); + + g = g_main_loop_new(NULL, FALSE); + g_main_loop_run(g); + g_main_loop_unref(g); + + g_object_unref(G_OBJECT(client)); + + return 0; + +fail: + return 1; +} diff --git a/src/modules/gconf/module-gconf.c b/src/modules/gconf/module-gconf.c new file mode 100644 index 00000000..30e6292e --- /dev/null +++ b/src/modules/gconf/module-gconf.c @@ -0,0 +1,386 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-gconf-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("GConf Adapter") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("") + +#define MAX_MODULES 10 +#define BUF_MAX 2048 + +#undef PA_GCONF_HELPER +#define PA_GCONF_HELPER "/home/lennart/projects/pulseaudio/src/gconf-helper" + +struct module_info { + char *name; + + unsigned n_indexes; + uint32_t indexes[MAX_MODULES]; +}; + +struct userdata { + pa_core *core; + pa_module *module; + + pa_hashmap *module_infos; + + pid_t pid; + + int fd; + int fd_type; + pa_io_event *io_event; + + char buf[BUF_MAX]; + size_t buf_fill; +}; + +static int fill_buf(struct userdata *u) { + ssize_t r; + assert(u); + + if (u->buf_fill >= BUF_MAX) { + pa_log(__FILE__": read buffer overflow"); + return -1; + } + + if ((r = pa_read(u->fd, u->buf + u->buf_fill, BUF_MAX - u->buf_fill, &u->fd_type)) <= 0) + return -1; + + u->buf_fill += r; + return 0; +} + +static int read_byte(struct userdata *u) { + int ret; + assert(u); + + if (u->buf_fill < 1) + if (fill_buf(u) < 0) + return -1; + + ret = u->buf[0]; + assert(u->buf_fill > 0); + u->buf_fill--; + memmove(u->buf, u->buf+1, u->buf_fill); + return ret; +} + +static char *read_string(struct userdata *u) { + assert(u); + + for (;;) { + char *e; + + if ((e = memchr(u->buf, 0, u->buf_fill))) { + char *ret = pa_xstrdup(u->buf); + u->buf_fill -= e - u->buf +1; + memmove(u->buf, e+1, u->buf_fill); + return ret; + } + + if (fill_buf(u) < 0) + return NULL; + } +} + +static void unload_modules(struct userdata *u, struct module_info*m) { + unsigned i; + + assert(u); + assert(m); + + for (i = 0; i < m->n_indexes; i++) { + pa_log_debug(__FILE__": Unloading module #%i", m->indexes[i]); + pa_module_unload_by_index(u->core, m->indexes[i]); + } + + m->n_indexes = 0; +} + +static void load_module( + struct userdata *u, + struct module_info *m, + const char *module, + const char *args) { + + pa_module *mod; + + assert(u); + assert(m); + assert(module); + + assert(m->n_indexes < MAX_MODULES); + + pa_log_debug(__FILE__": Loading module '%s' with args '%s' due to GConf configuration.", module, args); + + if (!(mod = pa_module_load(u->core, module, args))) { + pa_log(__FILE__": pa_module_load() failed"); + return; + } + + m->indexes[m->n_indexes++] = mod->index; +} + +static void module_info_free(void *p, void *userdata) { + struct module_info *m = p; + struct userdata *u = userdata; + + assert(m); + assert(u); + + unload_modules(u, m); + pa_xfree(m->name); + pa_xfree(m); +} + +static int handle_event(struct userdata *u) { + int opcode; + int ret = 0; + + do { + if ((opcode = read_byte(u)) < 0) + goto fail; + + switch (opcode) { + case '!': + /* The helper tool is now initialized */ + ret = 1; + break; + + case '+': { + char *name; + struct module_info *m; + + if (!(name = read_string(u))) + goto fail; + + if ((m = pa_hashmap_get(u->module_infos, name))) { + unload_modules(u, m); + } else { + m = pa_xnew(struct module_info, 1); + m->name = pa_xstrdup(name); + m->n_indexes = 0; + pa_hashmap_put(u->module_infos, m->name, m); + } + + while (m->n_indexes < MAX_MODULES) { + char *module, *args; + + if (!(module = read_string(u))) { + pa_xfree(name); + goto fail; + } + + if (!*module) { + pa_xfree(module); + break; + } + + if (!(args = read_string(u))) { + pa_xfree(name); + pa_xfree(module); + goto fail; + } + + load_module(u, m, module, args); + + pa_xfree(module); + pa_xfree(args); + } + + pa_xfree(name); + + break; + } + + case '-': { + char *name; + struct module_info *m; + + if (!(name = read_string(u))) + goto fail; + + if ((m = pa_hashmap_get(u->module_infos, name))) { + pa_hashmap_remove(u->module_infos, name); + module_info_free(m, u); + } + + pa_xfree(name); + + break; + } + } + } while (u->buf_fill > 0 && ret == 0); + + return ret; + +fail: + pa_log(__FILE__": Unable to read or parse data from client."); + return -1; +} + +static void io_event_cb( + pa_mainloop_api*a, + pa_io_event* e, + int fd, + pa_io_event_flags_t events, + void *userdata) { + + struct userdata *u = userdata; + + handle_event(u); +} + +static int start_client(const char *n, pid_t *pid) { + pid_t child; + int pipe_fds[2] = { -1, -1 }; + + if (pipe(pipe_fds) < 0) { + pa_log(__FILE__": pipe() failed: %s", pa_cstrerror(errno)); + goto fail; + } + + if ((child = fork()) == (pid_t) -1) { + pa_log(__FILE__": fork() failed: %s", pa_cstrerror(errno)); + goto fail; + } else if (child != 0) { + + /* Parent */ + close(pipe_fds[1]); + + if (pid) + *pid = child; + + return pipe_fds[0]; + } else { + + /* child */ + + close(pipe_fds[0]); + dup2(pipe_fds[1], 1); + + if (pipe_fds[1] != 1) + close(pipe_fds[1]); + + execl(n, n, NULL); + _exit(1); + } + +fail: + if (pipe_fds[0] >= 0) + close(pipe_fds[0]); + + if (pipe_fds[1] >= 0) + close(pipe_fds[1]); + + return -1; +} + +int pa__init(pa_core *c, pa_module*m) { + struct userdata *u; + int r; + + u = pa_xnew(struct userdata, 1); + u->core = c; + u->module = m; + u->module_infos = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + u->pid = (pid_t) -1; + u->fd = -1; + u->fd_type = 0; + u->io_event = NULL; + u->buf_fill = 0; + + if ((u->fd = start_client(PA_GCONF_HELPER, &u->pid)) < 0) + goto fail; + + u->io_event = c->mainloop->io_new( + c->mainloop, + u->fd, + PA_IO_EVENT_INPUT, + io_event_cb, + u); + + do { + if ((r = handle_event(u)) < 0) + goto fail; + + /* Read until the client signalled us that it is ready with + * initialization */ + } while (r != 1); + + return 0; + +fail: + pa__done(c, m); + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + + assert(c); + assert(m); + + if (!(u = m->userdata)) + return; + + if (u->io_event) + c->mainloop->io_free(u->io_event); + + if (u->fd >= 0) + close(u->fd); + + if (u->pid != (pid_t) -1) { + kill(u->pid, SIGTERM); + waitpid(u->pid, NULL, 0); + } + + if (u->module_infos) + pa_hashmap_free(u->module_infos, module_info_free, u); + + pa_xfree(u); +} + -- cgit From f5d29acdeb1e6412af3d2c9f761f329be36366d8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Jul 2006 17:46:51 +0000 Subject: add missing configure.ac checks for module-gconf git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1151 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 6cfbcf18..e6b09c53 100644 --- a/configure.ac +++ b/configure.ac @@ -453,6 +453,37 @@ AC_SUBST(GLIB20_LIBS) AC_SUBST(HAVE_GLIB20) AM_CONDITIONAL([HAVE_GLIB20], [test "x$HAVE_GLIB20" = x1]) +#### GConf support (optional) #### + +AC_ARG_ENABLE([gconf], + AC_HELP_STRING([--disable-gconf], [Disable optional GConf support]), + [ + case "${enableval}" in + yes) gconf=yes ;; + no) gconf=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-gconf) ;; + esac + ], + [glib=auto]) + +if test "x${gconf}" != xno ; then + PKG_CHECK_MODULES(GCONF, [ gconf-2.0 >= 2.4.0 ], + HAVE_GCONF=1, + [ + HAVE_GCONF=0 + if test "x$gconf" = xyes ; then + AC_MSG_ERROR([*** GConf support not found]) + fi + ]) +else + HAVE_GCONF=0 +fi + +AC_SUBST(GCONF_CFLAGS) +AC_SUBST(GCONF_LIBS) +AC_SUBST(HAVE_GCONF) +AM_CONDITIONAL([HAVE_GCONF], [test "x$HAVE_GCONF" = x1]) + #### Avahi support (optional) #### AC_ARG_ENABLE([avahi], @@ -724,6 +755,11 @@ if test "x$HAVE_GLIB20" = "x1" ; then ENABLE_GLIB20=yes fi +ENABLE_GCONF=no +if test "x$HAVE_GCONF" = "x1" ; then + ENABLE_GCONF=yes +fi + ENABLE_AVAHI=no if test "x$HAVE_AVAHI" = "x1" ; then ENABLE_AVAHI=yes @@ -762,7 +798,8 @@ echo " Enable OSS: ${ENABLE_OSS} Enable Alsa: ${ENABLE_ALSA} Enable Solaris: ${ENABLE_SOLARIS} - Enable Glib 2.0: ${ENABLE_GLIB20} + Enable GLib 2.0: ${ENABLE_GLIB20} + Enable GConf: ${ENABLE_GCONF} Enable Avahi: ${ENABLE_AVAHI} Enable Jack: ${ENABLE_JACK} Enable Async DNS: ${ENABLE_LIBASYNCNS} -- cgit From b2ad9a9753d9d5e69192a620b714f7e32a31e574 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Jul 2006 18:28:31 +0000 Subject: add some protection that the gconf helper process will be killed when the daemon process dies. make sure the gconf helper process doesn't keep open file descriptors belonging to the daemon; if gconf helper path git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1152 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/gconf/module-gconf.c | 58 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/src/modules/gconf/module-gconf.c b/src/modules/gconf/module-gconf.c index 30e6292e..c6f83f6d 100644 --- a/src/modules/gconf/module-gconf.c +++ b/src/modules/gconf/module-gconf.c @@ -31,6 +31,14 @@ #include #include #include +#include + +#ifdef HAVE_SYS_PRCTL_H +#include +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif #include #include @@ -51,8 +59,8 @@ PA_MODULE_USAGE("") #define MAX_MODULES 10 #define BUF_MAX 2048 -#undef PA_GCONF_HELPER -#define PA_GCONF_HELPER "/home/lennart/projects/pulseaudio/src/gconf-helper" +/* #undef PA_GCONF_HELPER */ +/* #define PA_GCONF_HELPER "/home/lennart/projects/pulseaudio/src/gconf-helper" */ struct module_info { char *name; @@ -271,7 +279,15 @@ static void io_event_cb( struct userdata *u = userdata; - handle_event(u); + if (handle_event(u) < 0) { + + if (u->io_event) { + u->core->mainloop->io_free(u->io_event); + u->io_event = NULL; + } + + pa_module_unload_request(u->module); + } } static int start_client(const char *n, pid_t *pid) { @@ -296,7 +312,8 @@ static int start_client(const char *n, pid_t *pid) { return pipe_fds[0]; } else { - + int max_fd, i; + /* child */ close(pipe_fds[0]); @@ -305,6 +322,39 @@ static int start_client(const char *n, pid_t *pid) { if (pipe_fds[1] != 1) close(pipe_fds[1]); + close(0); + open("/dev/null", O_RDONLY); + + close(2); + open("/dev/null", O_WRONLY); + + max_fd = 1024; + +#ifdef HAVE_SYS_RESOURCE_H + { + struct rlimit r; + if (getrlimit(RLIMIT_NOFILE, &r) == 0) + max_fd = r.rlim_max; + } +#endif + + for (i = 3; i < max_fd; i++) + close(i); + +#ifdef PR_SET_PDEATHSIG + /* On Linux we can use PR_SET_PDEATHSIG to have the helper + process killed when the daemon dies abnormally. On non-Linux + machines the client will die as soon as it writes data to + stdout again (SIGPIPE) */ + + prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); +#endif + +#ifdef SIGPIPE + /* Make sure that SIGPIPE kills the child process */ + signal(SIGPIPE, SIG_DFL); +#endif + execl(n, n, NULL); _exit(1); } -- cgit From 0d7be3148e872d0d2a68ecd740a596a3bcf4db5a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Jul 2006 22:39:06 +0000 Subject: mainloop fixes: when disabling time events when dispatching them, make sure to adjust the cache time event and enabled time event counters git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1153 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/glib-mainloop.c | 7 ++++++- src/pulse/mainloop.c | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/pulse/glib-mainloop.c b/src/pulse/glib-mainloop.c index 76767552..201b6e23 100644 --- a/src/pulse/glib-mainloop.c +++ b/src/pulse/glib-mainloop.c @@ -573,7 +573,10 @@ static gboolean dispatch_func(GSource *source, PA_GCC_UNUSED GSourceFunc callbac tvnow.tv_usec = now.tv_usec; if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) { - t->enabled = 0; + + /* Disable time event */ + glib_time_restart(t, NULL); + t->callback(&g->api, t, &t->timeval, t->userdata); return TRUE; } @@ -634,6 +637,8 @@ pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) { g->n_enabled_defer_events = g->n_enabled_time_events = 0; g->io_events_please_scan = g->time_events_please_scan = g->defer_events_please_scan = 0; + + g->cached_next_time_event = NULL; g_source_attach(&g->source, g->context); g_source_set_can_recurse(&g->source, FALSE); diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c index 682b2ccd..699c0ee7 100644 --- a/src/pulse/mainloop.c +++ b/src/pulse/mainloop.c @@ -766,7 +766,12 @@ static int dispatch_timeout(pa_mainloop *m) { if (pa_timeval_cmp(&e->timeval, &now) <= 0) { assert(e->callback); - e->enabled = 0; + /* Disable time event */ + mainloop_time_restart(e, NULL); + + if (m->cached_next_time_event == e) + m->cached_next_time_event = NULL; + e->callback(&m->api, e, &e->timeval, e->userdata); r++; -- cgit From 358e577403f081efa1e838df58617a86c1eaacb7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Jul 2006 22:39:56 +0000 Subject: remove two superfluous lines git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1154 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/mainloop.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c index 699c0ee7..5aa72706 100644 --- a/src/pulse/mainloop.c +++ b/src/pulse/mainloop.c @@ -769,9 +769,6 @@ static int dispatch_timeout(pa_mainloop *m) { /* Disable time event */ mainloop_time_restart(e, NULL); - if (m->cached_next_time_event == e) - m->cached_next_time_event = NULL; - e->callback(&m->api, e, &e->timeval, e->userdata); r++; -- cgit From 6afb61efdc53be232b345b293ac0cd8943966beb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 27 Jul 2006 16:49:44 +0000 Subject: remove superfluous code git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1155 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/mainloop.c | 43 ------------------------------------------- 1 file changed, 43 deletions(-) diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c index 5aa72706..5ebb9bc8 100644 --- a/src/pulse/mainloop.c +++ b/src/pulse/mainloop.c @@ -957,46 +957,3 @@ void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *use m->poll_func = poll_func; m->poll_func_userdata = userdata; } - - -#if 0 -void pa_mainloop_dump(pa_mainloop *m) { - assert(m); - - pa_log(__FILE__": Dumping mainloop sources START"); - - { - uint32_t idx = PA_IDXSET_INVALID; - pa_io_event *e; - for (e = pa_idxset_first(m->io_events, &idx); e; e = pa_idxset_next(m->io_events, &idx)) { - if (e->dead) - continue; - - pa_log(__FILE__": kind=io fd=%i events=%i callback=%p userdata=%p", e->fd, (int) e->events, (void*) e->callback, (void*) e->userdata); - } - } - { - uint32_t idx = PA_IDXSET_INVALID; - pa_defer_event *e; - for (e = pa_idxset_first(m->defer_events, &idx); e; e = pa_idxset_next(m->defer_events, &idx)) { - if (e->dead) - continue; - - pa_log(__FILE__": kind=defer enabled=%i callback=%p userdata=%p", e->enabled, (void*) e->callback, (void*) e->userdata); - } - } - { - uint32_t idx = PA_IDXSET_INVALID; - pa_time_event *e; - for (e = pa_idxset_first(m->time_events, &idx); e; e = pa_idxset_next(m->time_events, &idx)) { - if (e->dead) - continue; - - pa_log(__FILE__": kind=time enabled=%i time=%lu.%lu callback=%p userdata=%p", e->enabled, (unsigned long) e->timeval.tv_sec, (unsigned long) e->timeval.tv_usec, (void*) e->callback, (void*) e->userdata); - } - } - - pa_log(__FILE__": Dumping mainloop sources STOP"); - -} -#endif -- cgit From 87d4f0bd93f7c1c9d31409b526505c3c21aa5a19 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 27 Jul 2006 16:50:26 +0000 Subject: because gconf doesn't provide real transactions we emulate our own with a "locked" gconf key git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1156 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/gconf/gconf-helper.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/modules/gconf/gconf-helper.c b/src/modules/gconf/gconf-helper.c index c8b9b144..72454817 100644 --- a/src/modules/gconf/gconf-helper.c +++ b/src/modules/gconf/gconf-helper.c @@ -35,12 +35,18 @@ static void handle_module(GConfClient *client, const char *name) { gchar p[1024]; - gboolean enabled; + gboolean enabled, locked; int i; + snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/locked", name); + locked = gconf_client_get_bool(client, p, FALSE); + + if (locked) + return; + snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/enabled", name); enabled = gconf_client_get_bool(client, p, FALSE); - + printf("%c%s%c", enabled ? '+' : '-', name, 0); if (enabled) { -- cgit From fec7e9bec70364996a857b5f4e2cee01299ea59c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 27 Jul 2006 16:51:20 +0000 Subject: if possible do not unload already loaded modules when the gconf settings change. instead try to reuse already loaded modules as much as possible git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1157 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/gconf/module-gconf.c | 100 +++++++++++++++++++++++++++------------ 1 file changed, 71 insertions(+), 29 deletions(-) diff --git a/src/modules/gconf/module-gconf.c b/src/modules/gconf/module-gconf.c index c6f83f6d..d524346c 100644 --- a/src/modules/gconf/module-gconf.c +++ b/src/modules/gconf/module-gconf.c @@ -62,11 +62,17 @@ PA_MODULE_USAGE("") /* #undef PA_GCONF_HELPER */ /* #define PA_GCONF_HELPER "/home/lennart/projects/pulseaudio/src/gconf-helper" */ +struct module_item { + char *name; + char *args; + uint32_t index; +}; + struct module_info { char *name; - - unsigned n_indexes; - uint32_t indexes[MAX_MODULES]; + + struct module_item items[MAX_MODULES]; + unsigned n_items; }; struct userdata { @@ -134,42 +140,70 @@ static char *read_string(struct userdata *u) { } } -static void unload_modules(struct userdata *u, struct module_info*m) { +static void unload_one_module(struct userdata *u, struct module_info*m, unsigned i) { + assert(u); + assert(m); + assert(i < m->n_items); + + if (m->items[i].index == PA_INVALID_INDEX) + return; + + pa_log_debug(__FILE__": Unloading module #%i", m->items[i].index); + pa_module_unload_by_index(u->core, m->items[i].index); + m->items[i].index = PA_INVALID_INDEX; + pa_xfree(m->items[i].name); + pa_xfree(m->items[i].args); + m->items[i].name = m->items[i].args = NULL; +} + +static void unload_all_modules(struct userdata *u, struct module_info*m) { unsigned i; assert(u); assert(m); - for (i = 0; i < m->n_indexes; i++) { - pa_log_debug(__FILE__": Unloading module #%i", m->indexes[i]); - pa_module_unload_by_index(u->core, m->indexes[i]); - } + for (i = 0; i < m->n_items; i++) + unload_one_module(u, m, i); - m->n_indexes = 0; + m->n_items = 0; } static void load_module( struct userdata *u, struct module_info *m, - const char *module, - const char *args) { + int i, + const char *name, + const char *args, + int is_new) { pa_module *mod; assert(u); assert(m); - assert(module); + assert(name); + assert(args); + + if (!is_new) { + if (m->items[i].index != PA_INVALID_INDEX && + strcmp(m->items[i].name, name) == 0 && + strcmp(m->items[i].args, args) == 0) + return; - assert(m->n_indexes < MAX_MODULES); + unload_one_module(u, m, i); + } + + pa_log_debug(__FILE__": Loading module '%s' with args '%s' due to GConf configuration.", name, args); - pa_log_debug(__FILE__": Loading module '%s' with args '%s' due to GConf configuration.", module, args); + m->items[i].name = pa_xstrdup(name); + m->items[i].args = pa_xstrdup(args); + m->items[i].index = PA_INVALID_INDEX; - if (!(mod = pa_module_load(u->core, module, args))) { + if (!(mod = pa_module_load(u->core, name, args))) { pa_log(__FILE__": pa_module_load() failed"); return; } - m->indexes[m->n_indexes++] = mod->index; + m->items[i].index = mod->index; } static void module_info_free(void *p, void *userdata) { @@ -179,7 +213,7 @@ static void module_info_free(void *p, void *userdata) { assert(m); assert(u); - unload_modules(u, m); + unload_all_modules(u, m); pa_xfree(m->name); pa_xfree(m); } @@ -201,24 +235,25 @@ static int handle_event(struct userdata *u) { case '+': { char *name; struct module_info *m; + unsigned i, j; if (!(name = read_string(u))) goto fail; - if ((m = pa_hashmap_get(u->module_infos, name))) { - unload_modules(u, m); - } else { + if (!(m = pa_hashmap_get(u->module_infos, name))) { m = pa_xnew(struct module_info, 1); - m->name = pa_xstrdup(name); - m->n_indexes = 0; + m->name = name; + m->n_items = 0; pa_hashmap_put(u->module_infos, m->name, m); - } - - while (m->n_indexes < MAX_MODULES) { + } else + pa_xfree(name); + + i = 0; + while (i < MAX_MODULES) { char *module, *args; if (!(module = read_string(u))) { - pa_xfree(name); + if (i > m->n_items) m->n_items = i; goto fail; } @@ -228,18 +263,25 @@ static int handle_event(struct userdata *u) { } if (!(args = read_string(u))) { - pa_xfree(name); pa_xfree(module); + + if (i > m->n_items) m->n_items = i; goto fail; } - load_module(u, m, module, args); + load_module(u, m, i, module, args, i >= m->n_items); + + i++; pa_xfree(module); pa_xfree(args); } - pa_xfree(name); + /* Unload all removed modules */ + for (j = i; j < m->n_items; j++) + unload_one_module(u, m, j); + + m->n_items = i; break; } -- cgit From 0dea2237ed0a75d5696de228e66cc492a4db2fe4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 27 Jul 2006 18:02:59 +0000 Subject: introduce three virtual sink/source names: @DEFAULT_SINK@, @DEFAULT_SOURCE@, @DEFAULT_MONITOR@. Especially the latter is useful for connecting to the monitor source of the default sink. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1158 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/namereg.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c index 0f35ed1c..11c36c3a 100644 --- a/src/pulsecore/namereg.c +++ b/src/pulsecore/namereg.c @@ -58,7 +58,13 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t char *n = NULL; int r; - assert(c && name && data); + assert(c); + assert(name); + assert(data); + + /* Don't allow registration of special names */ + if (*name == '@') + return NULL; if (!c->namereg) { c->namereg = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); @@ -118,11 +124,29 @@ void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int a assert(c); if (!name) { + if (type == PA_NAMEREG_SOURCE) name = pa_namereg_get_default_source_name(c); else if (type == PA_NAMEREG_SINK) name = pa_namereg_get_default_sink_name(c); - } + + } else if (strcmp(name, "@DEFAULT_SINK@") == 0) { + if (type == PA_NAMEREG_SINK) + name = pa_namereg_get_default_sink_name(c); + + } else if (strcmp(name, "@DEFAULT_SOURCE@") == 0) { + if (type == PA_NAMEREG_SOURCE) + name = pa_namereg_get_default_source_name(c); + + } else if (strcmp(name, "@DEFAULT_MONITOR@") == 0) { + if (type == PA_NAMEREG_SOURCE) { + pa_sink *k; + + if ((k = pa_namereg_get(c, NULL, PA_NAMEREG_SINK, autoload))) + return k->monitor_source; + } + } else if (*name == '@') + name = NULL; if (!name) return NULL; -- cgit From c21f88cb9020caca5a45a6c899d9d0a66b0d3200 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 27 Jul 2006 18:35:17 +0000 Subject: load module-gconf in default install git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1159 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/default.pa.in | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in index ac10c0ca..ef6048d6 100755 --- a/src/daemon/default.pa.in +++ b/src/daemon/default.pa.in @@ -39,9 +39,11 @@ load-module module-detect ### Load several protocols load-module module-esound-protocol-unix -#load-module module-esound-protocol-tcp load-module module-native-protocol-unix + +#load-module module-esound-protocol-tcp #load-module module-native-protocol-tcp +#load-module module-zeroconf-publish ### Load the RTP reciever module #load-module module-rtp-recv @@ -69,3 +71,7 @@ load-module module-x11-bell sample=x11-bell ### Publish connection data in the X11 root window load-module module-x11-publish +### Load additional modules from GConf settings. This can be configured with the paprefs tool. +### Please keep in mind that the modules configured by paprefs might conflict with manually +### loaded modules. +load-module module-gconf -- cgit From ecd4655b873c6f103b151c3b53e94dfc9237b714 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 27 Jul 2006 18:40:01 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1160 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 - 1 file changed, 1 deletion(-) diff --git a/todo b/todo index d453b4d8..8d0105f5 100644 --- a/todo +++ b/todo @@ -29,7 +29,6 @@ Post 0.9.0: - gettextify polypaudio - drop dependency of libpolyp on libX11, instead use an external mini binary - "hot" moving of streams between sinks -- gconf module + frontend - hooks for creating sink inputs - insert the low-level device name in the default sink/source name, to make them recognizable - ssl -- cgit From 12aa8421747fa3448fb4dce6adafa198181cb4ac Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 28 Jul 2006 22:52:28 +0000 Subject: introduce pa_play_memblockq() which creates a playback stream and passes the data from the memblockq to it. after that is done, frees the memblockq git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1161 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 2 + src/pulsecore/play-memblockq.c | 113 +++++++++++++++++++++++++++++++++++++++++ src/pulsecore/play-memblockq.h | 36 +++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 src/pulsecore/play-memblockq.c create mode 100644 src/pulsecore/play-memblockq.h diff --git a/src/Makefile.am b/src/Makefile.am index bb08ed78..48211e1f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -497,6 +497,7 @@ pulsecoreinclude_HEADERS = \ pulsecore/namereg.h \ pulsecore/pid.h \ pulsecore/play-memchunk.h \ + pulsecore/play-memblockq.h \ pulsecore/props.h \ pulsecore/queue.h \ pulsecore/random.h \ @@ -558,6 +559,7 @@ libpulsecore_la_SOURCES += \ pulsecore/pid.c pulsecore/pid.h \ pulsecore/pipe.c pulsecore/pipe.h \ pulsecore/play-memchunk.c pulsecore/play-memchunk.h \ + pulsecore/play-memblockq.c pulsecore/play-memblockq.h \ pulsecore/poll.c pulsecore/poll.h \ pulsecore/props.c pulsecore/props.h \ pulsecore/queue.c pulsecore/queue.h \ diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c new file mode 100644 index 00000000..2df3b952 --- /dev/null +++ b/src/pulsecore/play-memblockq.c @@ -0,0 +1,113 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include +#include + +#include "play-memblockq.h" + +static void sink_input_kill(pa_sink_input *i) { + pa_memblockq *q; + assert(i); + assert(i->userdata); + + q = i->userdata; + + pa_sink_input_disconnect(i); + pa_sink_input_unref(i); + + pa_memblockq_free(q); +} + +static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { + pa_memblockq *q; + assert(i); + assert(chunk); + assert(i->userdata); + + q = i->userdata; + + return pa_memblockq_peek(q, chunk); +} + +static void si_kill(PA_GCC_UNUSED pa_mainloop_api *m, void *i) { + sink_input_kill(i); +} + +static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) { + pa_memblockq *q; + + assert(i); + assert(length > 0); + assert( i->userdata); + + q = i->userdata; + + pa_memblockq_drop(q, chunk, length); + + if (pa_memblockq_get_length(q) <= 0) + pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i); +} + +int pa_play_memblockq( + pa_sink *sink, + const char *name, + const pa_sample_spec *ss, + const pa_channel_map *map, + pa_memblockq *q, + pa_cvolume *cvolume) { + + pa_sink_input *si; + + assert(sink); + assert(ss); + assert(q); + + if (pa_memblockq_get_length(q) <= 0) + return 0; + + if (cvolume && pa_cvolume_is_muted(cvolume)) + return 0; + + if (!(si = pa_sink_input_new(sink, name, __FILE__, ss, map, cvolume, 0, PA_RESAMPLER_INVALID))) + return -1; + + si->peek = sink_input_peek; + si->drop = sink_input_drop; + si->kill = sink_input_kill; + + si->userdata = q; + + pa_sink_notify(sink); + + return 0; +} diff --git a/src/pulsecore/play-memblockq.h b/src/pulsecore/play-memblockq.h new file mode 100644 index 00000000..9b96efe3 --- /dev/null +++ b/src/pulsecore/play-memblockq.h @@ -0,0 +1,36 @@ +#ifndef fooplaymemblockqhfoo +#define fooplaymemblockqhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +int pa_play_memblockq( + pa_sink *sink, + const char *name, + const pa_sample_spec *ss, + const pa_channel_map *map, + pa_memblockq *q, + pa_cvolume *cvolume); + +#endif -- cgit From f1c46113ae4b0eedd291907d187f5ed39f29104d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 28 Jul 2006 23:27:16 +0000 Subject: fold the seperate variable pa_sink_input::playing into pa_sink_input::state as state PA_SINK_INPUT_DRAINED. The following mappings hold: old PA_SINK_RUNNING + playing set = new PA_SINK_RUNNING old PA_SINK_RUNNING + playing not set = new PA_SINK_DRAINED git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1162 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/sink-input.c | 24 ++++++++++++++---------- src/pulsecore/sink-input.h | 9 ++++----- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 8590a0b1..5613b15e 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -94,7 +94,7 @@ pa_sink_input* pa_sink_input_new( i = pa_xnew(pa_sink_input, 1); i->ref = 1; - i->state = PA_SINK_INPUT_RUNNING; + i->state = PA_SINK_INPUT_DRAINED; i->name = pa_xstrdup(name); i->driver = pa_xstrdup(driver); i->owner = NULL; @@ -112,8 +112,6 @@ pa_sink_input* pa_sink_input_new( i->underrun = NULL; i->userdata = NULL; - i->playing = 0; - pa_memchunk_reset(&i->resampled_chunk); i->resampler = resampler; @@ -149,7 +147,6 @@ void pa_sink_input_disconnect(pa_sink_input *i) { i->get_latency = NULL; i->underrun = NULL; - i->playing = 0; i->state = PA_SINK_INPUT_DISCONNECTED; } @@ -225,6 +222,8 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) if (!i->peek || !i->drop || i->state == PA_SINK_INPUT_CORKED) goto finish; + assert(i->state == PA_SINK_INPUT_RUNNING || i->state == PA_SINK_INPUT_DRAINED); + if (!i->resampler) { do_volume_adj_here = 0; ret = i->peek(i, chunk); @@ -270,10 +269,13 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) finish: - if (ret < 0 && i->playing && i->underrun) + if (ret < 0 && i->state == PA_SINK_INPUT_RUNNING && i->underrun) i->underrun(i); - i->playing = ret >= 0; + if (ret >= 0) + i->state = PA_SINK_INPUT_RUNNING; + else if (ret < 0 && i->state == PA_SINK_INPUT_RUNNING) + i->state = PA_SINK_INPUT_DRAINED; if (ret >= 0) { /* Let's see if we had to apply the volume adjustment @@ -342,12 +344,14 @@ void pa_sink_input_cork(pa_sink_input *i, int b) { assert(i); assert(i->ref >= 1); - if (i->state == PA_SINK_INPUT_DISCONNECTED) - return; + assert(i->state != PA_SINK_INPUT_DISCONNECTED); n = i->state == PA_SINK_INPUT_CORKED && !b; - - i->state = b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING; + + if (b) + i->state = PA_SINK_INPUT_CORKED; + else if (i->state == PA_SINK_INPUT_CORKED) + i->state = PA_SINK_INPUT_DRAINED; if (n) pa_sink_notify(i->sink); diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 69a7e50a..60105d31 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -34,9 +34,10 @@ typedef struct pa_sink_input pa_sink_input; #include typedef enum pa_sink_input_state { - PA_SINK_INPUT_RUNNING, - PA_SINK_INPUT_CORKED, - PA_SINK_INPUT_DISCONNECTED + PA_SINK_INPUT_RUNNING, /*< The stream is alive and kicking */ + PA_SINK_INPUT_DRAINED, /*< The stream stopped playing because there was no data to play */ + PA_SINK_INPUT_CORKED, /*< The stream was corked on user request */ + PA_SINK_INPUT_DISCONNECTED /*< The stream is dead */ } pa_sink_input_state_t; struct pa_sink_input { @@ -63,8 +64,6 @@ struct pa_sink_input { void *userdata; - int playing; - pa_memchunk resampled_chunk; pa_resampler *resampler; }; -- cgit From d1db0375771636a2f43e5c016afe181da5cb8008 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 28 Jul 2006 23:29:37 +0000 Subject: for the playing field of pa_timing_info use pa_sink_input::state == PA_SINK_INPUT_RUNNING. This means that this variable will now refer to the current state and not to the expected future state, which is probably more what clients expect. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1163 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 9023adde..d2268a5a 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -1101,7 +1101,7 @@ static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_tagstruct_put_usec(reply, latency); pa_tagstruct_put_usec(reply, 0); - pa_tagstruct_put_boolean(reply, pa_memblockq_is_readable(s->memblockq)); + pa_tagstruct_put_boolean(reply, s->sink_input->state == PA_SINK_INPUT_RUNNING); pa_tagstruct_put_timeval(reply, &tv); pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now)); pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq)); -- cgit From b325e07c7337a533792aac2d19ac6ff364c92fb6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 29 Jul 2006 15:02:24 +0000 Subject: handle EOF correctly if it is read before the stream was created git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1164 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pacat.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 10edd71d..dda5c192 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -291,18 +291,22 @@ static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_even if ((r = read(fd, buffer, l)) <= 0) { if (r == 0) { - pa_operation *o; - if (verbose) fprintf(stderr, "Got EOF.\n"); - - if (!(o = pa_stream_drain(stream, stream_drain_complete, NULL))) { - fprintf(stderr, "pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(context))); - quit(1); - return; - } - pa_operation_unref(o); + if (stream) { + pa_operation *o; + + if (!(o = pa_stream_drain(stream, stream_drain_complete, NULL))) { + fprintf(stderr, "pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(context))); + quit(1); + return; + } + + pa_operation_unref(o); + } else + quit(0); + } else { fprintf(stderr, "read() failed: %s\n", strerror(errno)); quit(1); -- cgit From 9310a2e3b88286fdb60f52c4b8a8c51848ffca53 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 29 Jul 2006 15:02:53 +0000 Subject: fix calculation of pa_usec_to_bytes, to make sure that it never returns fractions of a frame size git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1165 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/sample.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulse/sample.c b/src/pulse/sample.c index 2e055bf1..87b2d7a0 100644 --- a/src/pulse/sample.c +++ b/src/pulse/sample.c @@ -70,7 +70,7 @@ pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) { size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec) { assert(spec); - return ((double) t * spec->rate / 1000000)*pa_frame_size(spec); + return (size_t) (((double) t * spec->rate / 1000000))*pa_frame_size(spec); } int pa_sample_spec_valid(const pa_sample_spec *spec) { -- cgit From f15b4c7c704292ee88ae05919adc88a2765684cf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 29 Jul 2006 15:03:26 +0000 Subject: if the memblockq is empty, return -1 in all cases git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1166 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/memblockq.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index ff199f1b..822bd66c 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -368,6 +368,12 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { chunk->length = length; } else { + + /* If the memblockq is empty, return -1, otherwise return + * the time to sleep */ + if (!bq->blocks) + return -1; + chunk->memblock = NULL; chunk->length = length; } -- cgit From 4dd3b31825aa3feeea4d1cf6cfeee2b48a945f7c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 29 Jul 2006 15:04:17 +0000 Subject: free the memblockq if we decide not to play it git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1167 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/play-memblockq.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c index 2df3b952..7b796a8d 100644 --- a/src/pulsecore/play-memblockq.c +++ b/src/pulsecore/play-memblockq.c @@ -92,11 +92,15 @@ int pa_play_memblockq( assert(ss); assert(q); - if (pa_memblockq_get_length(q) <= 0) + if (pa_memblockq_get_length(q) <= 0) { + pa_memblockq_free(q); return 0; + } - if (cvolume && pa_cvolume_is_muted(cvolume)) + if (cvolume && pa_cvolume_is_muted(cvolume)) { + pa_memblockq_free(q); return 0; + } if (!(si = pa_sink_input_new(sink, name, __FILE__, ss, map, cvolume, 0, PA_RESAMPLER_INVALID))) return -1; -- cgit From 5e9295037f073fc768c1011253685ef35dba6331 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 29 Jul 2006 15:06:49 +0000 Subject: * implement "hot" moving of playback streams between sinks (pa_sink_input_move_to()). * optimize the adjusting of the volume in pa_sink_input_peek() a little git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1168 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/sink-input.c | 231 ++++++++++++++++++++++++++++++++++++++++++++- src/pulsecore/sink-input.h | 14 ++- 2 files changed, 239 insertions(+), 6 deletions(-) diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 5613b15e..8280d0bf 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -34,10 +34,13 @@ #include #include #include +#include #include "sink-input.h" #define CONVERT_BUFFER_LENGTH 4096 +#define MOVE_BUFFER_LENGTH (1024*1024) +#define SILENCE_BUFFER_LENGTH (64*1024) #define CHECK_VALIDITY_RETURN_NULL(condition) \ do {\ @@ -89,9 +92,11 @@ pa_sink_input* pa_sink_input_new( resample_method = s->core->resample_method; if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec) || !pa_channel_map_equal(map, &s->channel_map)) - if (!(resampler = pa_resampler_new(spec, map, &s->sample_spec, &s->channel_map, s->core->memblock_stat, resample_method))) + if (!(resampler = pa_resampler_new(spec, map, &s->sample_spec, &s->channel_map, s->core->memblock_stat, resample_method))) { + pa_log_warn(__FILE__": Unsupported resampling operation."); return NULL; - + } + i = pa_xnew(pa_sink_input, 1); i->ref = 1; i->state = PA_SINK_INPUT_DRAINED; @@ -111,9 +116,14 @@ pa_sink_input* pa_sink_input_new( i->get_latency = NULL; i->underrun = NULL; i->userdata = NULL; + i->move_silence = 0; pa_memchunk_reset(&i->resampled_chunk); i->resampler = resampler; + i->resample_method = resample_method; + i->variable_rate = variable_rate; + + i->silence_memblock = NULL; assert(s->core); r = pa_idxset_put(s->core->sink_inputs, i, &i->index); @@ -125,7 +135,8 @@ pa_sink_input* pa_sink_input_new( pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"", i->index, i->name, s->index, st); pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index); - + pa_sink_notify(i->sink); + return i; } @@ -164,6 +175,9 @@ static void sink_input_free(pa_sink_input* i) { if (i->resampler) pa_resampler_free(i->resampler); + if (i->silence_memblock) + pa_memblock_unref(i->silence_memblock); + pa_xfree(i->name); pa_xfree(i->driver); pa_xfree(i); @@ -203,7 +217,10 @@ pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) { r += i->get_latency(i); if (i->resampled_chunk.memblock) - r += pa_bytes_to_usec(i->resampled_chunk.length, &i->sample_spec); + r += pa_bytes_to_usec(i->resampled_chunk.length, &i->sink->sample_spec); + + if (i->move_silence) + r += pa_bytes_to_usec(i->move_silence, &i->sink->sample_spec); return r; } @@ -211,6 +228,7 @@ pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) { int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) { int ret = -1; int do_volume_adj_here; + int volume_is_norm; assert(i); assert(i->ref >= 1); @@ -223,6 +241,23 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) goto finish; assert(i->state == PA_SINK_INPUT_RUNNING || i->state == PA_SINK_INPUT_DRAINED); + + if (i->move_silence > 0) { + + /* We have just been moved and shall play some silence for a + * while until the old sink has drained its playback buffer */ + + if (!i->silence_memblock) + i->silence_memblock = pa_silence_memblock_new(&i->sink->sample_spec, SILENCE_BUFFER_LENGTH, i->sink->core->memblock_stat); + + chunk->memblock = pa_memblock_ref(i->silence_memblock); + chunk->index = 0; + chunk->length = i->move_silence < chunk->memblock->length ? i->move_silence : chunk->memblock->length; + + ret = 0; + do_volume_adj_here = 1; + goto finish; + } if (!i->resampler) { do_volume_adj_here = 0; @@ -231,6 +266,7 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) } do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map); + volume_is_norm = pa_cvolume_is_norm(&i->volume); while (!i->resampled_chunk.memblock) { pa_memchunk tchunk; @@ -250,7 +286,7 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) tchunk.length = l; /* It might be necessary to adjust the volume here */ - if (do_volume_adj_here) { + if (do_volume_adj_here && !volume_is_norm) { pa_memchunk_make_writable(&tchunk, i->sink->core->memblock_stat, 0); pa_volume_memchunk(&tchunk, &i->sample_spec, &i->volume); } @@ -299,6 +335,30 @@ void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t lengt assert(i->ref >= 1); assert(length > 0); + if (i->move_silence > 0) { + + if (chunk) { + + if (chunk->memblock != i->silence_memblock || + chunk->index != 0 || + (chunk->memblock && (chunk->length != (i->silence_memblock->length < i->move_silence ? i->silence_memblock->length : i->move_silence)))) + return; + + } + + assert(i->move_silence >= length); + + i->move_silence -= length; + + if (i->move_silence <= 0) { + assert(i->silence_memblock); + pa_memblock_unref(i->silence_memblock); + i->silence_memblock = NULL; + } + + return; + } + if (!i->resampler) { if (i->drop) i->drop(i, chunk, length); @@ -367,6 +427,8 @@ void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) { i->sample_spec.rate = rate; pa_resampler_set_input_rate(i->resampler, rate); + + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); } void pa_sink_input_set_name(pa_sink_input *i, const char *name) { @@ -388,3 +450,162 @@ pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) { return pa_resampler_get_method(i->resampler); } + +int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { + pa_resampler *new_resampler = NULL; + pa_memblockq *buffer = NULL; + pa_sink *origin; + + assert(i); + assert(dest); + + origin = i->sink; + + if (dest == origin) + return 0; + + if (pa_idxset_size(dest->inputs) >= PA_MAX_INPUTS_PER_SINK) { + pa_log_warn(__FILE__": Failed to move sink input: too many inputs per sink."); + return -1; + } + + if (i->resampler && + pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) && + pa_channel_map_equal(&origin->channel_map, &dest->channel_map)) + + /* Try to reuse the old resampler if possible */ + new_resampler = i->resampler; + + else if (i->variable_rate || + !pa_sample_spec_equal(&i->sample_spec, &dest->sample_spec) || + !pa_channel_map_equal(&i->channel_map, &dest->channel_map)) { + + /* Okey, we need a new resampler for the new sink */ + + if (!(new_resampler = pa_resampler_new( + &i->sample_spec, &i->channel_map, + &dest->sample_spec, &dest->channel_map, + dest->core->memblock_stat, + i->resample_method))) { + pa_log_warn(__FILE__": Unsupported resampling operation."); + return -1; + } + } + + if (!immediately) { + pa_usec_t old_latency, new_latency; + pa_usec_t silence_usec = 0; + + buffer = pa_memblockq_new(0, MOVE_BUFFER_LENGTH, 0, pa_frame_size(&origin->sample_spec), 0, 0, NULL, NULL); + + /* Let's do a little bit of Voodoo for compensating latency + * differences */ + + old_latency = pa_sink_get_latency(origin); + new_latency = pa_sink_get_latency(dest); + + /* The already resampled data should go to the old sink */ + + if (old_latency >= new_latency) { + + /* The latency of the old sink is larger than the latency + * of the new sink. Therefore to compensate for the + * difference we to play silence on the new one for a + * while */ + + silence_usec = old_latency - new_latency; + + } else { + size_t l; + int volume_is_norm; + + /* The latency of new sink is larger than the latency of + * the old sink. Therefore we have to precompute a little + * and make sure that this is still played on the old + * sink, until we can play the first sample on the new + * sink.*/ + + l = pa_usec_to_bytes(new_latency - old_latency, &origin->sample_spec); + + volume_is_norm = pa_cvolume_is_norm(&i->volume); + + while (l > 0) { + pa_memchunk chunk; + pa_cvolume volume; + size_t n; + + if (pa_sink_input_peek(i, &chunk, &volume) < 0) + break; + + n = chunk.length > l ? l : chunk.length; + pa_sink_input_drop(i, &chunk, n); + chunk.length = n; + + if (!volume_is_norm) { + pa_memchunk_make_writable(&chunk, origin->core->memblock_stat, 0); + pa_volume_memchunk(&chunk, &origin->sample_spec, &volume); + } + + if (pa_memblockq_push(buffer, &chunk) < 0) { + pa_memblock_unref(chunk.memblock); + break; + } + + pa_memblock_unref(chunk.memblock); + l -= n; + } + } + + if (i->resampled_chunk.memblock) { + + /* There is still some data left in the already resampled + * memory block. Hence, let's output it on the old sink + * and sleep so long on the new sink */ + + pa_memblockq_push(buffer, &i->resampled_chunk); + silence_usec += pa_bytes_to_usec(i->resampled_chunk.length, &origin->sample_spec); + } + + /* Calculate the new sleeping time */ + i->move_silence = pa_usec_to_bytes( + pa_bytes_to_usec(i->move_silence, &i->sample_spec) + + silence_usec, + &i->sample_spec); + } + + /* Okey, let's move it */ + pa_idxset_remove_by_data(i->sink->inputs, i, NULL); + i->sink = dest; + pa_idxset_put(i->sink->inputs, i, NULL); + + /* Replace resampler */ + if (new_resampler != i->resampler) { + if (i->resampler) + pa_resampler_free(i->resampler); + i->resampler = new_resampler; + + /* if the resampler changed, the silence memblock is + * probably invalid now, too */ + if (i->silence_memblock) { + pa_memblock_unref(i->silence_memblock); + i->silence_memblock = NULL; + } + } + + /* Dump already resampled data */ + if (i->resampled_chunk.memblock) { + pa_memblock_unref(i->resampled_chunk.memblock); + i->resampled_chunk.memblock = NULL; + i->resampled_chunk.index = i->resampled_chunk.length = 0; + } + + /* Notify everyone */ + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); + pa_sink_notify(i->sink); + + /* Ok, no let's feed the precomputed buffer to the old sink */ + if (buffer) + pa_play_memblockq(origin, "Ghost Stream", &origin->sample_spec, &origin->channel_map, buffer, NULL); + + return 0; +} diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 60105d31..b1971d0a 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -55,6 +55,11 @@ struct pa_sink_input { pa_channel_map channel_map; pa_cvolume volume; + + /* Some silence to play before the actual data. This is used to + * compensate for latency differences when moving a sink input + * "hot" between sinks. */ + size_t move_silence; int (*peek) (pa_sink_input *i, pa_memchunk *chunk); void (*drop) (pa_sink_input *i, const pa_memchunk *chunk, size_t length); @@ -66,6 +71,11 @@ struct pa_sink_input { pa_memchunk resampled_chunk; pa_resampler *resampler; + + int variable_rate; + pa_resample_method_t resample_method; + + pa_memblock *silence_memblock; }; pa_sink_input* pa_sink_input_new( @@ -76,7 +86,7 @@ pa_sink_input* pa_sink_input_new( const pa_channel_map *map, const pa_cvolume *volume, int variable_rate, - int resample_method); + pa_resample_method_t resample_method); void pa_sink_input_unref(pa_sink_input* i); pa_sink_input* pa_sink_input_ref(pa_sink_input* i); @@ -103,4 +113,6 @@ void pa_sink_input_set_name(pa_sink_input *i, const char *name); pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i); +int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately); + #endif -- cgit From a1e8b0968b9637e9813c320e0d1ca63e5fedf8ba Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 29 Jul 2006 15:07:15 +0000 Subject: add new CLI function "move-sink-input" as wrapper around pa_sink_input_move_to() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1169 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/cli-command.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index 4ba3e0af..f04c710b 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -98,7 +98,7 @@ static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *b static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); - +static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); /* A method table for all available commands */ @@ -141,6 +141,7 @@ static const struct command commands[] = { { "remove-autoload-source", pa_cli_command_autoload_remove, "Remove autoload entry for a source (args: name)", 2}, { "dump", pa_cli_command_dump, "Dump daemon configuration", 1}, { "list-props", pa_cli_command_list_props, NULL, 1}, + { "move-sink-input", pa_cli_command_move_sink_input, "Move Sink input to another sink (args: index, sink)", 3}, { NULL, NULL, NULL, 0 } }; @@ -728,6 +729,44 @@ static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf return 0; } +static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *n, *k; + pa_sink_input *si; + pa_sink *sink; + uint32_t idx; + + 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 ((idx = parse_index(n)) == PA_IDXSET_INVALID) { + pa_strbuf_puts(buf, "Failed to parse index.\n"); + return -1; + } + + if (!(k = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a sink.\n"); + return -1; + } + + if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) { + pa_strbuf_puts(buf, "No sink input found with this index.\n"); + return -1; + } + + if (!(sink = pa_namereg_get(c, k, PA_NAMEREG_SINK, 1))) { + pa_strbuf_puts(buf, "No sink found by this name or index.\n"); + return -1; + } + + if (pa_sink_input_move_to(si, sink, 0) < 0) { + pa_strbuf_puts(buf, "Moved failed.\n"); + return -1; + } + return 0; +} + static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { pa_module *m; pa_sink *sink; @@ -835,7 +874,6 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G return 0; } - int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { const char *cs; -- cgit From a7cf5e0f2de5474b4a1131a4254a56229436b7f7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 29 Jul 2006 15:34:36 +0000 Subject: fix two typos (pierre, have you been sleeping? next time please the comments wrong but the code right, not the other way round! ;-)) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1170 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/caps.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/daemon/caps.c b/src/daemon/caps.c index 957824d9..8ae43fb2 100644 --- a/src/daemon/caps.c +++ b/src/daemon/caps.c @@ -82,7 +82,7 @@ int pa_limit_caps(void) { cap_value_t nice_cap = CAP_SYS_NICE; /* Only drop caps when called SUID */ - if (getuid() != 0) + if (getuid() == 0) return 0; caps = cap_init(); @@ -112,7 +112,7 @@ int pa_drop_caps(void) { int r = -1; /* Only drop caps when called SUID */ - if (getuid() != 0) + if (getuid() == 0) return 0; caps = cap_init(); -- cgit From 646deeaee69b2a3e5b3dedbf6bf4cccdd9255957 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 29 Jul 2006 17:20:08 +0000 Subject: don't hit an assetr if there are operations outstanding when the pa_context is destroyed git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1171 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/operation.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pulse/operation.c b/src/pulse/operation.c index 24ddf69f..8d896d7d 100644 --- a/src/pulse/operation.c +++ b/src/pulse/operation.c @@ -76,6 +76,8 @@ static void operation_set_state(pa_operation *o, pa_operation_state_t st) { if (st == o->state) return; + pa_operation_ref(o); + o->state = st; if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) { @@ -92,6 +94,8 @@ static void operation_set_state(pa_operation *o, pa_operation_state_t st) { o->callback = NULL; o->userdata = NULL; } + + pa_operation_unref(o); } void pa_operation_cancel(pa_operation *o) { -- cgit From d7ee1bcf758241d744002e3aea982295ce9e9247 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 29 Jul 2006 17:42:25 +0000 Subject: fix module-gconf initialization git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1172 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/gconf/module-gconf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/gconf/module-gconf.c b/src/modules/gconf/module-gconf.c index d524346c..a61295e0 100644 --- a/src/modules/gconf/module-gconf.c +++ b/src/modules/gconf/module-gconf.c @@ -418,6 +418,7 @@ int pa__init(pa_core *c, pa_module*m) { u = pa_xnew(struct userdata, 1); u->core = c; u->module = m; + m->userdata = u; u->module_infos = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); u->pid = (pid_t) -1; u->fd = -1; -- cgit From e2e94ca47c5fc8b52ec28d9811a6da199a2c7262 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 31 Jul 2006 21:53:21 +0000 Subject: fix bad memory access if a non-existing entry shall be removed from a pa_idxset by index git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1173 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/idxset.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pulsecore/idxset.c b/src/pulsecore/idxset.c index 5c79767d..23fe0b5a 100644 --- a/src/pulsecore/idxset.c +++ b/src/pulsecore/idxset.c @@ -286,6 +286,9 @@ void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx) { if (!(a = array_index(s, idx))) return NULL; + if (!*a) + return NULL; + data = (*a)->data; remove_entry(s, *a); -- cgit From ccf67d2988521a8caf14ef1d650dcab4764462e4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 31 Jul 2006 21:53:48 +0000 Subject: deal properly with recursive module unloading git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1174 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/module.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pulsecore/module.c b/src/pulsecore/module.c index e7dca78d..3568059e 100644 --- a/src/pulsecore/module.c +++ b/src/pulsecore/module.c @@ -224,10 +224,14 @@ static void free_callback(void *p, PA_GCC_UNUSED void *userdata) { void pa_module_unload_all(pa_core *c) { assert(c); + pa_module *m; if (!c->modules) return; + while ((m = pa_idxset_first(c->modules, NULL))) + pa_module_unload(c, m); + pa_idxset_free(c->modules, free_callback, NULL); c->modules = NULL; -- cgit From 304fcbb8435949fa6e94280040cbbea2c4fc43c0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 31 Jul 2006 21:54:20 +0000 Subject: add new commands opcode for moving sink inputs and source outputs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1175 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/native-common.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pulsecore/native-common.h b/src/pulsecore/native-common.h index 5fdb6f42..785289eb 100644 --- a/src/pulsecore/native-common.h +++ b/src/pulsecore/native-common.h @@ -108,6 +108,10 @@ enum { PA_COMMAND_RECORD_STREAM_KILLED, PA_COMMAND_SUBSCRIBE_EVENT, + /* A few more client->server commands */ + PA_COMMAND_MOVE_SINK_INPUT, + PA_COMMAND_MOVE_SOURCE_OUTPUT, + PA_COMMAND_MAX }; -- cgit From 785477ba937e6850dff35d65e46e2b8a56bcc592 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 31 Jul 2006 21:54:46 +0000 Subject: add new native protocol function for moving sink inputs between sinks git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1176 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-native.c | 45 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index d2268a5a..f14aa873 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -189,6 +189,7 @@ static void command_get_autoload_info(pa_pdispatch *pd, uint32_t command, uint32 static void command_get_autoload_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = NULL, @@ -257,7 +258,10 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_GET_AUTOLOAD_INFO] = command_get_autoload_info, [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = command_get_autoload_info_list, [PA_COMMAND_ADD_AUTOLOAD] = command_add_autoload, - [PA_COMMAND_REMOVE_AUTOLOAD] = command_remove_autoload + [PA_COMMAND_REMOVE_AUTOLOAD] = command_remove_autoload, + + [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream, + [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream }; /* structure management */ @@ -2109,6 +2113,45 @@ static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC pa_pstream_send_tagstruct(c->pstream, reply); } +static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX; + pa_sink_input *si = NULL; + pa_sink *sink = NULL; + const char *name = NULL; + + assert(c); + assert(t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_getu32(t, &idx_device) < 0 || + pa_tagstruct_gets(t, &name) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); + + si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); + + if (idx_device != PA_INVALID_INDEX) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device); + else + sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); + + CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY); + + if (pa_sink_input_move_to(si, sink, 0) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); + return; + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + /*** pstream callbacks ***/ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) { -- cgit From bb9b08758e0eb1447f9891adccabda5334923b7b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 31 Jul 2006 21:55:09 +0000 Subject: wrap PA_COMMAND_MOVE_SINK_INPUT for libpulse git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1177 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/introspect.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ src/pulse/introspect.h | 5 +++++ 2 files changed, 53 insertions(+) diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c index ed40c53d..8aaf8b3f 100644 --- a/src/pulse/introspect.c +++ b/src/pulse/introspect.c @@ -1238,3 +1238,51 @@ pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, p return o; } + +pa_operation* pa_context_move_sink_input_by_name(pa_context *c, uint32_t idx, char *sink_name, pa_context_success_cb_t cb, void* userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, sink_name && *sink_name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_MOVE_SINK_INPUT, &tag); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, sink_name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_move_sink_input_by_index(pa_context *c, uint32_t idx, uint32_t sink_idx, pa_context_success_cb_t cb, void* userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, sink_idx != PA_INVALID_INDEX, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_MOVE_SINK_INPUT, &tag); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_putu32(t, sink_idx); + pa_tagstruct_puts(t, NULL); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h index e9a14490..529945fd 100644 --- a/src/pulse/introspect.h +++ b/src/pulse/introspect.h @@ -484,6 +484,11 @@ pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name /** Remove an autoload entry. \since 0.6 */ pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void* userdata); +/** Move the specified sink input to a different sink. \since 0.9.5 */ +pa_operation* pa_context_move_sink_input_by_name(pa_context *c, uint32_t idx, char *sink_name, pa_context_success_cb_t cb, void* userdata); + +/** Move the specified sink input to a different sink. \since 0.9.5 */ +pa_operation* pa_context_move_sink_input_by_index(pa_context *c, uint32_t idx, uint32_t sink_idx, pa_context_success_cb_t cb, void* userdata); PA_C_DECL_END -- cgit From bc30e2d9346edad2c8a755656e9aec803227bde1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 31 Jul 2006 21:55:42 +0000 Subject: add new "move-sink-input" command to pactl git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1178 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pactl.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 25ef324d..3674f950 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -46,7 +46,8 @@ static pa_context *context = NULL; static pa_mainloop_api *mainloop_api = NULL; -static char *device = NULL, *sample_name = NULL; +static char *device = NULL, *sample_name = NULL, *sink_name = NULL; +static uint32_t sink_input_idx = PA_INVALID_INDEX; static SNDFILE *sndfile = NULL; static pa_stream *sample_stream = NULL; @@ -64,7 +65,8 @@ static enum { UPLOAD_SAMPLE, PLAY_SAMPLE, REMOVE_SAMPLE, - LIST + LIST, + MOVE_SINK_INPUT } action = NONE; static void quit(int ret) { @@ -581,6 +583,10 @@ static void context_state_callback(pa_context *c, void *userdata) { pa_operation_unref(pa_context_get_autoload_info_list(c, get_autoload_info_callback, NULL)); break; + case MOVE_SINK_INPUT: + pa_operation_unref(pa_context_move_sink_input_by_name(c, sink_input_idx, sink_name, simple_callback, NULL)); + break; + default: assert(0); } @@ -609,12 +615,13 @@ static void help(const char *argv0) { "%s [options] exit\n" "%s [options] upload-sample FILENAME [NAME]\n" "%s [options] play-sample NAME [SINK]\n" + "%s [options] move-sink-input NAME [SINK]\n" "%s [options] remove-sample NAME\n\n" " -h, --help Show this help\n" " --version Show version\n\n" " -s, --server=SERVER The name of the server to connect to\n" " -n, --client-name=NAME How to call this client on the server\n", - argv0, argv0, argv0, argv0, argv0, argv0); + argv0, argv0, argv0, argv0, argv0, argv0, argv0); } enum { ARG_VERSION = 256 }; @@ -731,6 +738,15 @@ int main(int argc, char *argv[]) { } sample_name = pa_xstrdup(argv[optind+1]); + } else if (!strcmp(argv[optind], "move-sink-input")) { + action = MOVE_SINK_INPUT; + if (optind+2 >= argc) { + fprintf(stderr, "You have to specify a sink input index and a sink\n"); + goto quit; + } + + sink_input_idx = atoi(argv[optind+1]); + sink_name = pa_xstrdup(argv[optind+2]); } } @@ -784,6 +800,7 @@ quit: pa_xfree(server); pa_xfree(device); pa_xfree(sample_name); + pa_xfree(sink_name); return ret; } -- cgit From 7f93d08d4014cc68965611068c47834c1e5547ef Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 1 Aug 2006 21:04:43 +0000 Subject: bump API and protocol version. Return PA_ERR_NOTSUPPORTED if pa_context_move_sink_input_by_*()is called for servers that don't support it git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1179 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 4 ++-- src/pulse/def.h | 1 + src/pulse/introspect.c | 2 ++ src/utils/pacat.c | 2 +- src/utils/pactl.c | 2 +- src/utils/paplay.c | 2 +- todo | 2 +- 7 files changed, 9 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index e6b09c53..26fd860c 100644 --- a/configure.ac +++ b/configure.ac @@ -33,8 +33,8 @@ AM_INIT_AUTOMAKE([foreign -Wall]) AC_SUBST(PA_MAJORMINOR, "PA_MAJOR.PA_MINOR") AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/pulseaudio/]) -AC_SUBST(PA_API_VERSION, 9) -AC_SUBST(PA_PROTOCOL_VERSION, 9) +AC_SUBST(PA_API_VERSION, 10) +AC_SUBST(PA_PROTOCOL_VERSION, 10) AC_SUBST(LIBPULSE_VERSION_INFO, [0:2:0]) AC_SUBST(LIBPULSECORE_VERSION_INFO, [1:1:0]) diff --git a/src/pulse/def.h b/src/pulse/def.h index 01ed0f6d..a22e3c19 100644 --- a/src/pulse/def.h +++ b/src/pulse/def.h @@ -161,6 +161,7 @@ enum { PA_ERR_NODATA, /**< No data */ PA_ERR_VERSION, /**< Incompatible protocol version \since 0.8 */ PA_ERR_TOOLARGE, /**< Data too large \since 0.8.1 */ + PA_ERR_NOTSUPPORTED, /**< Operation not supported \since 0.9.5 */ PA_ERR_MAX /**< Not really an error but the first invalid error code */ }; diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c index 8aaf8b3f..d750bbde 100644 --- a/src/pulse/introspect.c +++ b/src/pulse/introspect.c @@ -1248,6 +1248,7 @@ pa_operation* pa_context_move_sink_input_by_name(pa_context *c, uint32_t idx, ch assert(c->ref >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 10, PA_ERR_NOTSUPPORTED); PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); PA_CHECK_VALIDITY_RETURN_NULL(c, sink_name && *sink_name, PA_ERR_INVALID); @@ -1272,6 +1273,7 @@ pa_operation* pa_context_move_sink_input_by_index(pa_context *c, uint32_t idx, u assert(c->ref >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 10, PA_ERR_NOTSUPPORTED); PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); PA_CHECK_VALIDITY_RETURN_NULL(c, sink_idx != PA_INVALID_INDEX, PA_ERR_INVALID); diff --git a/src/utils/pacat.c b/src/utils/pacat.c index dda5c192..1c581f4d 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -37,7 +37,7 @@ #define TIME_EVENT_USEC 50000 -#if PA_API_VERSION != 9 +#if PA_API_VERSION < 9 #error Invalid PulseAudio API version #endif diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 3674f950..0fde33eb 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -37,7 +37,7 @@ #include -#if PA_API_VERSION != 9 +#if PA_API_VERSION < 10 #error Invalid PulseAudio API version #endif diff --git a/src/utils/paplay.c b/src/utils/paplay.c index 7b34016c..0386c9df 100644 --- a/src/utils/paplay.c +++ b/src/utils/paplay.c @@ -37,7 +37,7 @@ #include -#if PA_API_VERSION != 9 +#if PA_API_VERSION < 9 #error Invalid PulseAudio API version #endif diff --git a/todo b/todo index 8d0105f5..cdd8b872 100644 --- a/todo +++ b/todo @@ -28,7 +28,7 @@ Post 0.9.0: - Document utf8.h, timeval.h and util.h - gettextify polypaudio - drop dependency of libpolyp on libX11, instead use an external mini binary -- "hot" moving of streams between sinks +- "hot" moving of recording streams between sources - hooks for creating sink inputs - insert the low-level device name in the default sink/source name, to make them recognizable - ssl -- cgit From ddc69fccb5eec6ed546b1d2fe1771c383eeb5413 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 3 Aug 2006 22:29:55 +0000 Subject: - don't call pa_sink_notify in pa_sink_input_new() because the virtual methods are not yet initialized at this time - some minor cleanups git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1180 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/sink-input.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 8280d0bf..b89210f4 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -135,8 +135,10 @@ pa_sink_input* pa_sink_input_new( pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"", i->index, i->name, s->index, st); pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index); - pa_sink_notify(i->sink); + /* We do not call pa_sink_notify() here, because the virtual + * functions have not yet been initialized */ + return i; } @@ -446,7 +448,7 @@ pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) { assert(i->ref >= 1); if (!i->resampler) - return PA_RESAMPLER_INVALID; + return i->resample_method; return pa_resampler_get_method(i->resampler); } @@ -574,9 +576,9 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { } /* Okey, let's move it */ - pa_idxset_remove_by_data(i->sink->inputs, i, NULL); + pa_idxset_remove_by_data(origin->inputs, i, NULL); + pa_idxset_put(dest->inputs, i, NULL); i->sink = dest; - pa_idxset_put(i->sink->inputs, i, NULL); /* Replace resampler */ if (new_resampler != i->resampler) { -- cgit From 2d00de58513fa069d4a8aabca0aa0be33eb37ce9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 3 Aug 2006 22:30:45 +0000 Subject: Implement pa_source_input_move_to() for moving record streams between sources git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1181 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/source-output.c | 77 +++++++++++++++++++++++++++++++++++++++++-- src/pulsecore/source-output.h | 3 ++ 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 230b416d..1ffaedae 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -79,8 +79,10 @@ pa_source_output* pa_source_output_new( resample_method = s->core->resample_method; if (!pa_sample_spec_equal(&s->sample_spec, spec) || !pa_channel_map_equal(&s->channel_map, map)) - if (!(resampler = pa_resampler_new(&s->sample_spec, &s->channel_map, spec, map, s->core->memblock_stat, resample_method))) + if (!(resampler = pa_resampler_new(&s->sample_spec, &s->channel_map, spec, map, s->core->memblock_stat, resample_method))) { + pa_log_warn(__FILE__": Unsupported resampling operation."); return NULL; + } o = pa_xnew(pa_source_output, 1); o->ref = 1; @@ -100,6 +102,7 @@ pa_source_output* pa_source_output_new( o->userdata = NULL; o->resampler = resampler; + o->resample_method = resample_method; assert(s->core); r = pa_idxset_put(s->core->source_outputs, o, &o->index); @@ -111,6 +114,9 @@ pa_source_output* pa_source_output_new( pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"", o->index, o->name, s->index, st); pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); + + /* We do not call pa_source_notify() here, because the virtual + * functions have not yet been initialized */ return o; } @@ -166,7 +172,6 @@ pa_source_output* pa_source_output_ref(pa_source_output *o) { return o; } - void pa_source_output_kill(pa_source_output*o) { assert(o); assert(o->ref >= 1); @@ -221,13 +226,20 @@ pa_usec_t pa_source_output_get_latency(pa_source_output *o) { } void pa_source_output_cork(pa_source_output *o, int b) { + int n; + assert(o); assert(o->ref >= 1); if (o->state == PA_SOURCE_OUTPUT_DISCONNECTED) return; + + n = o->state == PA_SOURCE_OUTPUT_CORKED && !b; o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; + + if (n) + pa_source_notify(o->source); } pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { @@ -235,7 +247,66 @@ pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { assert(o->ref >= 1); if (!o->resampler) - return PA_RESAMPLER_INVALID; + return o->resample_method; return pa_resampler_get_method(o->resampler); } + +int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { + pa_source *origin; + pa_resampler *new_resampler; + + assert(o); + assert(o->ref >= 1); + assert(dest); + + origin = o->source; + + if (dest == origin) + return 0; + + if (pa_idxset_size(dest->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { + pa_log_warn(__FILE__": Failed to move source output: too many outputs per source."); + return -1; + } + + if (o->resampler && + pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) && + pa_channel_map_equal(&origin->channel_map, &dest->channel_map)) + + /* Try to reuse the old resampler if possible */ + new_resampler = o->resampler; + + else if (!pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec) || + !pa_channel_map_equal(&o->channel_map, &dest->channel_map)) { + + /* Okey, we need a new resampler for the new sink */ + + if (!(new_resampler = pa_resampler_new( + &dest->sample_spec, &dest->channel_map, + &o->sample_spec, &o->channel_map, + dest->core->memblock_stat, + o->resample_method))) { + pa_log_warn(__FILE__": Unsupported resampling operation."); + return -1; + } + } + + /* Okey, let's move it */ + pa_idxset_remove_by_data(origin->outputs, o, NULL); + pa_idxset_put(dest->outputs, o, NULL); + o->source = dest; + + /* Replace resampler */ + if (new_resampler != o->resampler) { + if (o->resampler) + pa_resampler_free(o->resampler); + o->resampler = new_resampler; + } + + /* Notify everyone */ + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); + pa_source_notify(o->source); + + return 0; +} diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index ef398dd1..9a8ea92b 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -58,6 +58,7 @@ struct pa_source_output { pa_usec_t (*get_latency) (pa_source_output *o); pa_resampler* resampler; + pa_resample_method_t resample_method; void *userdata; }; @@ -89,4 +90,6 @@ void pa_source_output_cork(pa_source_output *i, int b); pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o); +int pa_source_output_move_to(pa_source_output *o, pa_source *dest); + #endif -- cgit From 1c45061fe1291e65620967d47cf7fc5258669d21 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 3 Aug 2006 22:31:35 +0000 Subject: add new CLI command move-source-output as wrapper around pa_source_output_move_to() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1182 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/cli-command.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index f04c710b..f74258d3 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -99,6 +99,7 @@ static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); /* A method table for all available commands */ @@ -141,7 +142,8 @@ static const struct command commands[] = { { "remove-autoload-source", pa_cli_command_autoload_remove, "Remove autoload entry for a source (args: name)", 2}, { "dump", pa_cli_command_dump, "Dump daemon configuration", 1}, { "list-props", pa_cli_command_list_props, NULL, 1}, - { "move-sink-input", pa_cli_command_move_sink_input, "Move Sink input to another sink (args: index, sink)", 3}, + { "move-sink-input", pa_cli_command_move_sink_input, "Move sink input to another sink (args: index, sink)", 3}, + { "move-source-output", pa_cli_command_move_source_output, "Move source output to another source (args: index, source)", 3}, { NULL, NULL, NULL, 0 } }; @@ -767,6 +769,44 @@ static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf return 0; } +static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *n, *k; + pa_source_output *so; + pa_source *source; + uint32_t idx; + + 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 ((idx = parse_index(n)) == PA_IDXSET_INVALID) { + pa_strbuf_puts(buf, "Failed to parse index.\n"); + return -1; + } + + if (!(k = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a source.\n"); + return -1; + } + + if (!(so = pa_idxset_get_by_index(c->source_outputs, (uint32_t) idx))) { + pa_strbuf_puts(buf, "No source output found with this index.\n"); + return -1; + } + + if (!(source = pa_namereg_get(c, k, PA_NAMEREG_SOURCE, 1))) { + pa_strbuf_puts(buf, "No source found by this name or index.\n"); + return -1; + } + + if (pa_source_output_move_to(so, source) < 0) { + pa_strbuf_puts(buf, "Moved failed.\n"); + return -1; + } + return 0; +} + static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { pa_module *m; pa_sink *sink; -- cgit From 5fdc39dc26c2691a8315de271d3f00fa257beff1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 3 Aug 2006 22:32:23 +0000 Subject: wrap pa_source_output_move_to() in the native protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1183 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-native.c | 49 +++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index f14aa873..d5a4cf45 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -2116,8 +2116,6 @@ static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX; - pa_sink_input *si = NULL; - pa_sink *sink = NULL; const char *name = NULL; assert(c); @@ -2135,21 +2133,44 @@ static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); - si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); - - if (idx_device != PA_INVALID_INDEX) - sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device); - else - sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); - - CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY); + if (command == PA_COMMAND_MOVE_SINK_INPUT) { + pa_sink_input *si = NULL; + pa_sink *sink = NULL; - if (pa_sink_input_move_to(si, sink, 0) < 0) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); - return; - } + si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); + + if (idx_device != PA_INVALID_INDEX) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device); + else + sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); + + CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY); + + if (pa_sink_input_move_to(si, sink, 0) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); + return; + } + } else { + pa_source_output *so = NULL; + pa_source *source; + + so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); + + if (idx_device != PA_INVALID_INDEX) + source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device); + else + source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); + + CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY); + if (pa_source_output_move_to(so, source) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); + return; + } + } + pa_pstream_send_simple_ack(c->pstream, tag); + } /*** pstream callbacks ***/ -- cgit From e52436b6c4ff50906b4fbf2e9e5cdb8fb2eb683b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 3 Aug 2006 22:33:11 +0000 Subject: implement pa_context_move_source_output_by_{name,index}() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1184 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/introspect.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/pulse/introspect.h | 6 ++++++ 2 files changed, 56 insertions(+) diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c index d750bbde..b926e4e4 100644 --- a/src/pulse/introspect.c +++ b/src/pulse/introspect.c @@ -1288,3 +1288,53 @@ pa_operation* pa_context_move_sink_input_by_index(pa_context *c, uint32_t idx, u return o; } + +pa_operation* pa_context_move_source_output_by_name(pa_context *c, uint32_t idx, char *source_name, pa_context_success_cb_t cb, void* userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 10, PA_ERR_NOTSUPPORTED); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, source_name && *source_name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_MOVE_SOURCE_OUTPUT, &tag); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, source_name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_move_source_output_by_index(pa_context *c, uint32_t idx, uint32_t source_idx, pa_context_success_cb_t cb, void* userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + assert(c); + assert(c->ref >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 10, PA_ERR_NOTSUPPORTED); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, source_idx != PA_INVALID_INDEX, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_MOVE_SOURCE_OUTPUT, &tag); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_putu32(t, source_idx); + pa_tagstruct_puts(t, NULL); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h index 529945fd..28d22cd7 100644 --- a/src/pulse/introspect.h +++ b/src/pulse/introspect.h @@ -490,6 +490,12 @@ pa_operation* pa_context_move_sink_input_by_name(pa_context *c, uint32_t idx, ch /** Move the specified sink input to a different sink. \since 0.9.5 */ pa_operation* pa_context_move_sink_input_by_index(pa_context *c, uint32_t idx, uint32_t sink_idx, pa_context_success_cb_t cb, void* userdata); +/** Move the specified source output to a different source. \since 0.9.5 */ +pa_operation* pa_context_move_source_output_by_name(pa_context *c, uint32_t idx, char *source_name, pa_context_success_cb_t cb, void* userdata); + +/** Move the specified source output to a different source. \since 0.9.5 */ +pa_operation* pa_context_move_source_output_by_index(pa_context *c, uint32_t idx, uint32_t source_idx, pa_context_success_cb_t cb, void* userdata); + PA_C_DECL_END #endif -- cgit From ad95c96a7278ac2e7d213e9575c2db1503d422fd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 3 Aug 2006 22:33:54 +0000 Subject: implement "pactl move-source-output" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1185 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pactl.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 0fde33eb..f6f75498 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -46,8 +46,8 @@ static pa_context *context = NULL; static pa_mainloop_api *mainloop_api = NULL; -static char *device = NULL, *sample_name = NULL, *sink_name = NULL; -static uint32_t sink_input_idx = PA_INVALID_INDEX; +static char *device = NULL, *sample_name = NULL, *sink_name = NULL, *source_name = NULL; +static uint32_t sink_input_idx = PA_INVALID_INDEX, source_output_idx = PA_INVALID_INDEX; static SNDFILE *sndfile = NULL; static pa_stream *sample_stream = NULL; @@ -66,7 +66,8 @@ static enum { PLAY_SAMPLE, REMOVE_SAMPLE, LIST, - MOVE_SINK_INPUT + MOVE_SINK_INPUT, + MOVE_SOURCE_OUTPUT } action = NONE; static void quit(int ret) { @@ -587,6 +588,10 @@ static void context_state_callback(pa_context *c, void *userdata) { pa_operation_unref(pa_context_move_sink_input_by_name(c, sink_input_idx, sink_name, simple_callback, NULL)); break; + case MOVE_SOURCE_OUTPUT: + pa_operation_unref(pa_context_move_source_output_by_name(c, source_output_idx, source_name, simple_callback, NULL)); + break; + default: assert(0); } @@ -615,7 +620,8 @@ static void help(const char *argv0) { "%s [options] exit\n" "%s [options] upload-sample FILENAME [NAME]\n" "%s [options] play-sample NAME [SINK]\n" - "%s [options] move-sink-input NAME [SINK]\n" + "%s [options] move-sink-input ID SINK\n" + "%s [options] move-source-output ID SOURCE\n" "%s [options] remove-sample NAME\n\n" " -h, --help Show this help\n" " --version Show version\n\n" @@ -747,6 +753,15 @@ int main(int argc, char *argv[]) { sink_input_idx = atoi(argv[optind+1]); sink_name = pa_xstrdup(argv[optind+2]); + } else if (!strcmp(argv[optind], "move-source-output")) { + action = MOVE_SOURCE_OUTPUT; + if (optind+2 >= argc) { + fprintf(stderr, "You have to specify a source output index and a source\n"); + goto quit; + } + + source_output_idx = atoi(argv[optind+1]); + source_name = pa_xstrdup(argv[optind+2]); } } @@ -801,6 +816,7 @@ quit: pa_xfree(device); pa_xfree(sample_name); pa_xfree(sink_name); + pa_xfree(source_name); return ret; } -- cgit From f74e5ef8845b7b7e5ee39b1e0dae8ca7f6113eb8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 3 Aug 2006 22:34:22 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1186 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 - 1 file changed, 1 deletion(-) diff --git a/todo b/todo index cdd8b872..5c2edf75 100644 --- a/todo +++ b/todo @@ -28,7 +28,6 @@ Post 0.9.0: - Document utf8.h, timeval.h and util.h - gettextify polypaudio - drop dependency of libpolyp on libX11, instead use an external mini binary -- "hot" moving of recording streams between sources - hooks for creating sink inputs - insert the low-level device name in the default sink/source name, to make them recognizable - ssl -- cgit From 050b73912ca0e81a5740b65745d4ba1d450a66ab Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 6 Aug 2006 16:16:50 +0000 Subject: merge HAL support from Shams E. King git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1187 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 37 +++ src/Makefile.am | 18 ++ src/modules/dbus-util.c | 354 ++++++++++++++++++++++++++++ src/modules/dbus-util.h | 36 +++ src/modules/module-hal-detect.c | 495 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 940 insertions(+) create mode 100644 src/modules/dbus-util.c create mode 100644 src/modules/dbus-util.h create mode 100644 src/modules/module-hal-detect.c diff --git a/configure.ac b/configure.ac index 26fd860c..bf7425c0 100644 --- a/configure.ac +++ b/configure.ac @@ -637,6 +637,37 @@ AC_SUBST(LIRC_CFLAGS) AC_SUBST(LIRC_LIBS) AM_CONDITIONAL([HAVE_LIRC], [test "x$HAVE_LIRC" = x1]) +#### HAL support (optional) #### + +AC_ARG_ENABLE([hal], + AC_HELP_STRING([--disable-hal], [Disable optional HAL support]), + [ + case "${enableval}" in + yes) hal=yes ;; + no) hal=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-hal) ;; + esac + ], + [hal=auto]) + +if test "x${hal}" != xno ; then + PKG_CHECK_MODULES(HAL, [ hal >= 0.5.7 ], + HAVE_HAL=1, + [ + HAVE_HAL=0 + if test "x$hal" = xyes ; then + AC_MSG_ERROR([*** HAL support not found]) + fi + ]) +else + HAVE_HAL=0 +fi + +AC_SUBST(HAL_CFLAGS) +AC_SUBST(HAL_LIBS) +AC_SUBST(HAVE_HAL) +AM_CONDITIONAL([HAVE_HAL], [test "x$HAVE_HAL" = x1]) + #### PulseAudio system group & user ##### AC_ARG_WITH(system_user, AS_HELP_STRING([--with-system-user=],[User for running the PulseAudio daemon as a system-wide instance (pulse)])) @@ -780,6 +811,11 @@ if test "x$HAVE_LIRC" = "x1" ; then ENABLE_LIRC=yes fi +ENABLE_HAL=no +if test "x$HAVE_HAL" = "x1" ; then + ENABLE_HAL=yes +fi + ENABLE_TCPWRAP=no if test "x${LIBWRAP_LIBS}" != x ; then ENABLE_TCPWRAP=yes @@ -804,6 +840,7 @@ echo " Enable Jack: ${ENABLE_JACK} Enable Async DNS: ${ENABLE_LIBASYNCNS} Enable LIRC: ${ENABLE_LIRC} + Enable HAL: ${ENABLE_HAL} Enable TCP Wrappers: ${ENABLE_TCPWRAP} System User: ${PA_SYSTEM_USER} System Group: ${PA_SYSTEM_GROUP} diff --git a/src/Makefile.am b/src/Makefile.am index 48211e1f..e0fae996 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -899,6 +899,12 @@ modlibexec_LTLIBRARIES += \ module-waveout.la endif +if HAVE_HAL +modlibexec_LTLIBRARIES += \ + libdbus-util.la \ + module-hal-detect.la +endif + # These are generated by a M4 script SYMDEF_FILES = \ @@ -942,6 +948,7 @@ SYMDEF_FILES = \ modules/module-jack-sink-symdef.h \ modules/module-jack-source-symdef.h \ modules/module-volume-restore-symdef.h \ + modules/module-hal-detect-symdef.h \ modules/gconf/module-gconf-symdef.h EXTRA_DIST += $(SYMDEF_FILES) @@ -1182,6 +1189,17 @@ module_jack_source_la_LDFLAGS = -module -avoid-version module_jack_source_la_LIBADD = $(AM_LIBADD) libpulsecore.la $(JACK_LIBS) module_jack_source_la_CFLAGS = $(AM_LIBADD) $(JACK_CFLAGS) +# HAL +libdbus_util_la_SOURCES = modules/dbus-util.c modules/dbus-util.h +libdbus_util_la_LDFLAGS = -avoid-version +libdbus_util_la_LIBADD = $(AM_LIBADD) $(HAL_LIBS) libpulsecore.la +libdbus_util_la_CFLAGS = $(AM_CFLAGS) $(HAL_CFLAGS) + +module_hal_detect_la_SOURCES = modules/module-hal-detect.c +module_hal_detect_la_LDFLAGS = -module -avoid-version +module_hal_detect_la_LIBADD = $(AM_LIBADD) $(HAL_LIBS) libpulsecore.la libdbus-util.la +module_hal_detect_la_CFLAGS = $(AM_CFLAGS) $(HAL_CFLAGS) + # GConf support module_gconf_la_SOURCES = modules/gconf/module-gconf.c module_gconf_la_LDFLAGS = -module -avoid-version diff --git a/src/modules/dbus-util.c b/src/modules/dbus-util.c new file mode 100644 index 00000000..0c9978e7 --- /dev/null +++ b/src/modules/dbus-util.c @@ -0,0 +1,354 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "dbus-util.h" + +struct pa_dbus_connection { + int refcount; + pa_core *core; + DBusConnection *connection; + const char *property_name; + pa_defer_event* dispatch_event; +}; + +static void dispatch_cb(pa_mainloop_api *ea, pa_defer_event *ev, void *userdata) +{ + DBusConnection *conn = (DBusConnection *) userdata; + if (dbus_connection_dispatch(conn) == DBUS_DISPATCH_COMPLETE) { + /* no more data to process, disable the deferred */ + ea->defer_enable(ev, 0); + } +} + +/* DBusDispatchStatusFunction callback for the pa mainloop */ +static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, + void *userdata) +{ + pa_dbus_connection *c = (pa_dbus_connection*) userdata; + switch(status) { + case DBUS_DISPATCH_COMPLETE: + c->core->mainloop->defer_enable(c->dispatch_event, 0); + break; + case DBUS_DISPATCH_DATA_REMAINS: + case DBUS_DISPATCH_NEED_MEMORY: + default: + c->core->mainloop->defer_enable(c->dispatch_event, 1); + break; + } +} + +static pa_io_event_flags_t +get_watch_flags(DBusWatch *watch) +{ + unsigned int flags = dbus_watch_get_flags(watch); + pa_io_event_flags_t events = PA_IO_EVENT_HANGUP | PA_IO_EVENT_ERROR; + + /* no watch flags for disabled watches */ + if (!dbus_watch_get_enabled(watch)) + return PA_IO_EVENT_NULL; + + if (flags & DBUS_WATCH_READABLE) + events |= PA_IO_EVENT_INPUT; + if (flags & DBUS_WATCH_WRITABLE) + events |= PA_IO_EVENT_OUTPUT; + + return events; +} + +static void timeval_next(struct timeval *tv, int millint) +{ + /* number of seconds in the milli-second interval */ + tv->tv_sec += (millint / 1000); + /* milliseconds minus the seconds portion, converted to microseconds */ + tv->tv_usec += (millint - tv->tv_sec * 1000) * 1000; +} + +/* pa_io_event_cb_t IO event handler */ +static void handle_io_event(PA_GCC_UNUSED pa_mainloop_api *ea, pa_io_event *e, + int fd, pa_io_event_flags_t events, void *userdata) +{ + unsigned int flags = 0; + DBusWatch *watch = (DBusWatch*) userdata; + + assert(fd == dbus_watch_get_fd(watch)); + + if (!dbus_watch_get_enabled(watch)) { + pa_log_warn(__FILE__": Asked to handle disabled watch: %p %i", + (void *) watch, fd); + return; + } + + if (events & PA_IO_EVENT_INPUT) + flags |= DBUS_WATCH_READABLE; + if (events & PA_IO_EVENT_OUTPUT) + flags |= DBUS_WATCH_WRITABLE; + if (events & PA_IO_EVENT_HANGUP) + flags |= DBUS_WATCH_HANGUP; + if (events & PA_IO_EVENT_ERROR) + flags |= DBUS_WATCH_ERROR; + + dbus_watch_handle(watch, flags); +} + +/* pa_time_event_cb_t timer event handler */ +static void handle_time_event(pa_mainloop_api *ea, pa_time_event* e, + const struct timeval *tv, void *userdata) +{ + DBusTimeout *timeout = (DBusTimeout*) userdata; + + if (dbus_timeout_get_enabled(timeout)) { + struct timeval next = *tv; + dbus_timeout_handle(timeout); + + /* restart it for the next scheduled time */ + timeval_next(&next, dbus_timeout_get_interval(timeout)); + ea->time_restart(e, &next); + } +} + +/* DBusAddWatchFunction callback for pa mainloop */ +static dbus_bool_t add_watch(DBusWatch *watch, void *data) +{ + pa_io_event *ev; + pa_core *c = (pa_core*) data; + + ev = c->mainloop->io_new(c->mainloop, dbus_watch_get_fd(watch), + get_watch_flags(watch), + handle_io_event, (void*) watch); + if (NULL == ev) + return FALSE; + + /* dbus_watch_set_data(watch, (void*) ev, c->mainloop->io_free); */ + dbus_watch_set_data(watch, (void*) ev, NULL); + + return TRUE; +} + +/* DBusRemoveWatchFunction callback for pa mainloop */ +static void remove_watch(DBusWatch *watch, void *data) +{ + pa_core *c = (pa_core*) data; + pa_io_event *ev = (pa_io_event*) dbus_watch_get_data(watch); + + /* free the event */ + if (NULL != ev) + c->mainloop->io_free(ev); +} + +/* DBusWatchToggledFunction callback for pa mainloop */ +static void toggle_watch(DBusWatch *watch, void *data) +{ + pa_core *c = (pa_core*) data; + pa_io_event *ev = (pa_io_event*) dbus_watch_get_data(watch); + + /* get_watch_flags() checks if the watch is enabled */ + c->mainloop->io_enable(ev, get_watch_flags(watch)); +} + +/* DBusAddTimeoutFunction callback for pa mainloop */ +static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) +{ + struct timeval tv; + pa_time_event *ev; + pa_core *c = (pa_core*) data; + + if (!dbus_timeout_get_enabled(timeout)) + return FALSE; + + if (gettimeofday(&tv, NULL) < 0) + return -1; + + timeval_next(&tv, dbus_timeout_get_interval(timeout)); + + ev = c->mainloop->time_new(c->mainloop, &tv, handle_time_event, + (void*) timeout); + if (NULL == ev) + return FALSE; + + /* dbus_timeout_set_data(timeout, (void*) ev, c->mainloop->time_free); */ + dbus_timeout_set_data(timeout, (void*) ev, NULL); + + return TRUE; +} + +/* DBusRemoveTimeoutFunction callback for pa mainloop */ +static void remove_timeout(DBusTimeout *timeout, void *data) +{ + pa_core *c = (pa_core*) data; + pa_time_event *ev = (pa_time_event*) dbus_timeout_get_data(timeout); + + /* free the event */ + if (NULL != ev) + c->mainloop->time_free(ev); +} + +/* DBusTimeoutToggledFunction callback for pa mainloop */ +static void toggle_timeout(DBusTimeout *timeout, void *data) +{ + struct timeval tv; + pa_core *c = (pa_core*) data; + pa_time_event *ev = (pa_time_event*) dbus_timeout_get_data(timeout); + + gettimeofday(&tv, NULL); + if (dbus_timeout_get_enabled(timeout)) { + timeval_next(&tv, dbus_timeout_get_interval(timeout)); + c->mainloop->time_restart(ev, &tv); + } else { + /* set it to expire one second ago */ + tv.tv_sec -= 1; + c->mainloop->time_restart(ev, &tv); + } +} + +static void +pa_dbus_connection_free(pa_dbus_connection *c) +{ + assert(c); + assert(!dbus_connection_get_is_connected(c->connection)); + + /* already disconnected, just free */ + pa_property_remove(c->core, c->property_name); + c->core->mainloop->defer_free(c->dispatch_event); + dbus_connection_unref(c->connection); + pa_xfree(c); +} + +static void +wakeup_main(void *userdata) +{ + pa_dbus_connection *c = (pa_dbus_connection*) userdata; + /* this will wakeup the mainloop and dispatch events, although + * it may not be the cleanest way of accomplishing it */ + c->core->mainloop->defer_enable(c->dispatch_event, 1); +} + +static pa_dbus_connection* pa_dbus_connection_new(pa_core* c, DBusConnection *conn, const char* name) +{ + pa_dbus_connection *pconn = pa_xmalloc(sizeof(pa_dbus_connection)); + + pconn->refcount = 1; + pconn->core = c; + pconn->property_name = name; + pconn->connection = conn; + pconn->dispatch_event = c->mainloop->defer_new(c->mainloop, dispatch_cb, + (void*) conn); + + pa_property_set(c, name, pconn); + + return pconn; +} + +DBusConnection* pa_dbus_connection_get(pa_dbus_connection *c) +{ + assert(c && c->connection); + return c->connection; +} + +void pa_dbus_connection_unref(pa_dbus_connection *c) +{ + assert(c); + + /* non-zero refcount, still outstanding refs */ + if (--(c->refcount)) + return; + + /* refcount is zero */ + if (dbus_connection_get_is_connected(c->connection)) { + /* disconnect as we have no more internal references */ + dbus_connection_close(c->connection); + /* must process remaining messages, bit of a kludge to + * handle both unload and shutdown */ + while(dbus_connection_read_write_dispatch(c->connection, -1)); + } + pa_dbus_connection_free(c); +} + +pa_dbus_connection* pa_dbus_connection_ref(pa_dbus_connection *c) +{ + assert(c); + + ++(c->refcount); + + return c; +} + +pa_dbus_connection* pa_dbus_bus_get(pa_core *c, DBusBusType type, + DBusError *error) +{ + const char* name; + DBusConnection *conn; + pa_dbus_connection *pconn; + static const char sysname[] = "dbus-connection-system"; + static const char sessname[] = "dbus-connection-session"; + static const char startname[] = "dbus-connection-starter"; + + switch (type) { + case DBUS_BUS_SYSTEM: + name = sysname; + break; + case DBUS_BUS_SESSION: + name = sessname; + break; + case DBUS_BUS_STARTER: + name = startname; + break; + default: + assert(0); /* never reached */ + break; + } + + if ((pconn = pa_property_get(c, name))) + return pa_dbus_connection_ref(pconn); + + /* else */ + conn = dbus_bus_get_private(type, error); + if (conn == NULL || dbus_error_is_set(error)) { + return NULL; + } + + pconn = pa_dbus_connection_new(c, conn, name); + + /* don't exit on disconnect */ + dbus_connection_set_exit_on_disconnect(conn, FALSE); + /* set up the DBUS call backs */ + dbus_connection_set_dispatch_status_function(conn, dispatch_status, + (void*) pconn, NULL); + dbus_connection_set_watch_functions(conn, + add_watch, + remove_watch, + toggle_watch, + (void*) c, NULL); + dbus_connection_set_timeout_functions(conn, + add_timeout, + remove_timeout, + toggle_timeout, + (void*) c, NULL); + dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL); + + return pconn; +} diff --git a/src/modules/dbus-util.h b/src/modules/dbus-util.h new file mode 100644 index 00000000..d5d5b36a --- /dev/null +++ b/src/modules/dbus-util.h @@ -0,0 +1,36 @@ +#ifndef foodbusutilhfoo +#define foodbusutilhfoo + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef struct pa_dbus_connection pa_dbus_connection; + +/* return the DBusConnection of the specified type for the given core, + * like dbus_bus_get(), but integrates the connection with the pa_core */ +pa_dbus_connection* pa_dbus_bus_get(pa_core *c, DBusBusType type, DBusError *error); + +DBusConnection* pa_dbus_connection_get(pa_dbus_connection *conn); + +pa_dbus_connection* pa_dbus_connection_ref(pa_dbus_connection *conn); +void pa_dbus_connection_unref(pa_dbus_connection *conn); + +#endif diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c new file mode 100644 index 00000000..1c15a2d1 --- /dev/null +++ b/src/modules/module-hal-detect.c @@ -0,0 +1,495 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "dbus-util.h" +#include "module-hal-detect-symdef.h" + +PA_MODULE_AUTHOR("Shahms King") +PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers") +PA_MODULE_VERSION(PACKAGE_VERSION) + +static const char* capabilities[] = { "alsa", "oss" }; + +typedef enum { + CAP_ALSA, + CAP_OSS, + CAP_MAX +} capability_t; + +typedef enum { + ALSA_TYPE_SINK, + ALSA_TYPE_SOURCE, + ALSA_TYPE_OTHER, + ALSA_TYPE_MAX +} alsa_type_t; + +struct device { + char *udi; + pa_module *module; +}; + +struct userdata { + pa_core *core; + pa_subscription *sub; + LibHalContext *ctx; + capability_t capability; + pa_dbus_connection *conn; + pa_hashmap *by_udi; + pa_hashmap *by_module; +}; + +struct timerdata { + struct userdata *u; + char *udi; +}; + +static alsa_type_t hal_device_get_alsa_type(LibHalContext *ctx, const char *udi, + DBusError *error) +{ + char *type; + alsa_type_t t; + + type = libhal_device_get_property_string(ctx, udi, "alsa.type", error); + if (!type || dbus_error_is_set(error)) + return FALSE; + + if (!strcmp(type, "playback")) { + t = ALSA_TYPE_SINK; + } else if (!strcmp(type, "capture")) { + t = ALSA_TYPE_SOURCE; + } else { + t = ALSA_TYPE_OTHER; + } + libhal_free_string(type); + + return t; +} + +static int hal_device_get_alsa_card(LibHalContext *ctx, const char *udi, + DBusError *error) +{ + return libhal_device_get_property_int(ctx, udi, "alsa.card", error); +} + +static int hal_device_get_alsa_device(LibHalContext *ctx, const char *udi, + DBusError *error) +{ + return libhal_device_get_property_int(ctx, udi, "alsa.device", error); +} + +static void hal_device_free(struct device* d) { + pa_xfree(d->udi); + pa_xfree(d); +} + +static void hal_device_free_cb(void *d, PA_GCC_UNUSED void *data) { + hal_device_free((struct device*) d); +} + +static dbus_bool_t hal_device_add_alsa(struct userdata *u, const char *udi, + DBusError *error) +{ + char args[64]; + alsa_type_t type; + int device, card; + pa_module *m; + struct device *d; + const char *module_name; + + type = hal_device_get_alsa_type(u->ctx, udi, error); + if (dbus_error_is_set(error) || type == ALSA_TYPE_OTHER) { + return FALSE; + } + + device = hal_device_get_alsa_device(u->ctx, udi, error); + if (dbus_error_is_set(error) || device != 0) + return FALSE; + + card = hal_device_get_alsa_card(u->ctx, udi, error); + if (dbus_error_is_set(error)) + return FALSE; + + module_name = (type == ALSA_TYPE_SINK) ? "module-alsa-sink" + : "module-alsa-source"; + snprintf(args, sizeof(args), "device=hw:%u", card); + if (!(m = pa_module_load(u->core, module_name, args))) + return FALSE; + + d = pa_xmalloc(sizeof(struct device)); + d->udi = pa_xstrdup(udi); + d->module = m; + + pa_hashmap_put(u->by_module, m, d); + pa_hashmap_put(u->by_udi, udi, d); + + return TRUE; +} + +static int hal_device_add_all(struct userdata *u, capability_t capability) +{ + DBusError error; + int i,n,count; + dbus_bool_t r; + char** udis; + const char* cap = capabilities[capability]; + + assert(capability < CAP_MAX); + + pa_log_info(__FILE__": Trying capability %u (%s)", capability, cap); + dbus_error_init(&error); + udis = libhal_find_device_by_capability(u->ctx, cap, &n, &error); + if (dbus_error_is_set(&error)) { + pa_log_error(__FILE__": Error finding devices: %s: %s", error.name, + error.message); + dbus_error_free(&error); + return -1; + } + count = 0; + for (i = 0; i < n; ++i) { + switch(capability) { + case CAP_ALSA: + r = hal_device_add_alsa(u, udis[i], &error); + break; + case CAP_OSS: + /* r = hal_device_add_oss(u, udis[i], &error) + * break; */ + case CAP_MAX: + default: + assert(FALSE); + break; + } + + if (dbus_error_is_set(&error)) { + pa_log_error(__FILE__": Error adding device: %s: %s", error.name, + error.message); + dbus_error_free(&error); + count = -1; + break; + } + if (r) + ++count; + } + + libhal_free_string_array(udis); + u->capability = capability; + return count; +} + +static dbus_bool_t device_has_capability(LibHalContext *ctx, const char *udi, + const char* cap, DBusError *error) +{ + dbus_bool_t has_prop; + has_prop = libhal_device_property_exists(ctx, udi, "info.capabilities", + error); + if (!has_prop || dbus_error_is_set(error)) + return FALSE; + + return libhal_device_query_capability(ctx, udi, cap, error); +} + +static void device_added_time_cb(pa_mainloop_api *ea, pa_time_event *ev, + const struct timeval *tv, void *userdata) +{ + DBusError error; + struct timerdata *td = (struct timerdata*) userdata; + + dbus_error_init(&error); + if (!libhal_device_exists(td->u->ctx, td->udi, &error)) + goto exit; + + switch(td->u->capability) { + case CAP_ALSA: + hal_device_add_alsa(td->u, td->udi, &error); + break; + case CAP_OSS: + /* hal_device_add_oss(td->u, td->udi, &error); + * break; */ + case CAP_MAX: + default: + /* not reached */ + assert(FALSE); + break; + } + +exit: + if (dbus_error_is_set(&error)) { + pa_log_error(__FILE__": Error adding device: %s: %s", error.name, + error.message); + dbus_error_free(&error); + } + + pa_xfree(td->udi); + pa_xfree(td); + ea->time_free(ev); +} + +static void device_added_cb(LibHalContext *ctx, const char *udi) +{ + DBusError error; + struct timeval tv; + dbus_bool_t has_cap; + struct timerdata *t; + struct userdata *u = (struct userdata*) libhal_ctx_get_user_data(ctx); + const char* cap = capabilities[u->capability]; + + pa_log_debug(__FILE__": HAL Device added: %s", udi); + + dbus_error_init(&error); + has_cap = device_has_capability(ctx, udi, cap, &error); + if (dbus_error_is_set(&error)) { + pa_log_error(__FILE__": Error getting capability: %s: %s", error.name, + error.message); + dbus_error_free(&error); + return; + } + + /* skip it */ + if (!has_cap) + return; + + /* actually add the device one second later */ + t = pa_xmalloc(sizeof(struct timerdata)); + t->u = u; + t->udi = pa_xstrdup(udi); + + gettimeofday(&tv, NULL); + tv.tv_sec += 1; + u->core->mainloop->time_new(u->core->mainloop, &tv, + device_added_time_cb, t); +} + +static void device_removed_cb(LibHalContext* ctx, const char *udi) +{ + struct device *d; + struct userdata *u = (struct userdata*) libhal_ctx_get_user_data(ctx); + + pa_log_debug(__FILE__": Device removed: %s", udi); + if ((d = pa_hashmap_remove(u->by_udi, udi))) { + d = pa_hashmap_remove(u->by_module, d->module); + pa_log_debug(__FILE__": Unloading: %s <%s>", d->module->name, d->module->argument); + pa_module_unload_request(d->module); + hal_device_free(d); + } +} + +#if 0 +static void new_capability_cb(LibHalContext *ctx, const char *udi, + const char* capability) +{ +} + +static void lost_capability_cb(LibHalContext *ctx, const char *udi, + const char* capability) +{ +} + +static void property_modified_cb(LibHalContext *ctx, const char *udi, + const char* key, + dbus_bool_t is_removed, + dbus_bool_t is_added) +{ +} +#endif + +static void subscribe_notify_cb(pa_core *c, pa_subscription_event_type_t type, + uint32_t idx, void *userdata) +{ + pa_module *m; + struct device *d; + struct userdata *u = (struct userdata*) userdata; + + /* only listen for module remove events */ + if (type != (PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_REMOVE)) + return; + + if (!(m = pa_idxset_get_by_index(c->modules, idx))) + return; + + /* we found the module, see if it's one we care about */ + if ((d = pa_hashmap_remove(u->by_module, m))) { + pa_log_debug(__FILE__": Removing module #%u %s: %s", + m->index, m->name, d->udi); + d = pa_hashmap_remove(u->by_udi, d->udi); + hal_device_free(d); + } +} + + +static void pa_hal_context_free(LibHalContext* hal_ctx) +{ + DBusError error; + + dbus_error_init(&error); + libhal_ctx_shutdown(hal_ctx, &error); + libhal_ctx_free(hal_ctx); + + if (dbus_error_is_set(&error)) { + dbus_error_free(&error); + } +} + +static void userdata_free(struct userdata *u) { + pa_hal_context_free(u->ctx); + pa_subscription_free(u->sub); + /* free the hashmap */ + pa_hashmap_free(u->by_module, NULL, NULL); + /* free the devices with the hashmap */ + pa_hashmap_free(u->by_udi, hal_device_free_cb, NULL); + pa_dbus_connection_unref(u->conn); + pa_xfree(u); +} + +static LibHalContext* pa_hal_context_new(pa_core* c, DBusConnection *conn) +{ + DBusError error; + LibHalContext *hal_ctx = NULL; + + dbus_error_init(&error); + if (!(hal_ctx = libhal_ctx_new())) { + pa_log_error(__FILE__": libhal_ctx_new() failed"); + goto fail; + } + + if (!libhal_ctx_set_dbus_connection(hal_ctx, conn)) { + pa_log_error(__FILE__": Error establishing DBUS connection: %s: %s", + error.name, error.message); + goto fail; + } + + if (!libhal_ctx_init(hal_ctx, &error)) { + pa_log_error(__FILE__": Couldn't connect to hald: %s: %s", + error.name, error.message); + goto fail; + } + + return hal_ctx; + +fail: + if (hal_ctx) + pa_hal_context_free(hal_ctx); + + if (dbus_error_is_set(&error)) + dbus_error_free(&error); + + return NULL; +} + +int pa__init(pa_core *c, pa_module*m) { + int n; + DBusError error; + pa_dbus_connection *conn; + struct userdata *u = NULL; + LibHalContext *hal_ctx = NULL; + + assert(c); + assert(m); + + dbus_error_init(&error); + if (!(conn = pa_dbus_bus_get(c, DBUS_BUS_SYSTEM, &error))) { + pa_log_error(__FILE__": Unable to contact DBUS system bus: %s: %s", + error.name, error.message); + dbus_error_free(&error); + return -1; + } + + if (!(hal_ctx = pa_hal_context_new(c, pa_dbus_connection_get(conn)))) { + /* pa_hal_context_new() logs appropriate errors */ + return -1; + } + + u = pa_xmalloc(sizeof(struct userdata)); + u->core = c; + u->ctx = hal_ctx; + u->conn = conn; + u->by_module = pa_hashmap_new(NULL, NULL); + u->by_udi = pa_hashmap_new(pa_idxset_string_hash_func, + pa_idxset_string_compare_func); + u->sub = pa_subscription_new(c, PA_SUBSCRIPTION_MASK_MODULE, + subscribe_notify_cb, (void*) u); + m->userdata = (void*) u; + +#if HAVE_ALSA + if ((n = hal_device_add_all(u, CAP_ALSA)) <= 0) +#endif +#if HAVE_OSS + if ((n = hal_device_add_all(u, CAP_OSS)) <= 0) +#endif + { + pa_log_warn(__FILE__": failed to detect any sound hardware."); + userdata_free(u); + return -1; + } + + libhal_ctx_set_user_data(hal_ctx, (void*) u); + libhal_ctx_set_device_added(hal_ctx, device_added_cb); + libhal_ctx_set_device_removed(hal_ctx, device_removed_cb); + + dbus_error_init(&error); + if (!libhal_device_property_watch_all(hal_ctx, &error)) { + pa_log_error(__FILE__": error monitoring device list: %s: %s", + error.name, error.message); + dbus_error_free(&error); + userdata_free(u); + return -1; + } + + /* + libhal_ctx_set_device_new_capability(hal_ctx, new_capability_cb); + libhal_ctx_set_device_lost_capability(hal_ctx, lost_capability_cb); + libhal_ctx_set_device_property_modified(hal_ctx, property_modified_cb); + */ + + pa_log_info(__FILE__": loaded %i modules.", n); + + return 0; +} + + +void pa__done(PA_GCC_UNUSED pa_core *c, pa_module *m) { + assert (c && m); + + /* free the user data */ + userdata_free(m->userdata); +} -- cgit From d953870564c13bc4742634a17300c58abbf1eadf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 6 Aug 2006 19:14:07 +0000 Subject: * add SVN $Id$ tags * add a const git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1188 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/dbus-util.c | 2 ++ src/modules/dbus-util.h | 2 ++ src/modules/module-hal-detect.c | 4 +++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/modules/dbus-util.c b/src/modules/dbus-util.c index 0c9978e7..b5c61337 100644 --- a/src/modules/dbus-util.c +++ b/src/modules/dbus-util.c @@ -1,3 +1,5 @@ +/* $Id$ */ + /*** This file is part of PulseAudio. diff --git a/src/modules/dbus-util.h b/src/modules/dbus-util.h index d5d5b36a..7a9871a4 100644 --- a/src/modules/dbus-util.h +++ b/src/modules/dbus-util.h @@ -1,6 +1,8 @@ #ifndef foodbusutilhfoo #define foodbusutilhfoo +/* $Id$ */ + /*** This file is part of PulseAudio. diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index 1c15a2d1..adcb866c 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -1,3 +1,5 @@ +/* $Id$ */ + /*** This file is part of PulseAudio. @@ -50,7 +52,7 @@ PA_MODULE_AUTHOR("Shahms King") PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers") PA_MODULE_VERSION(PACKAGE_VERSION) -static const char* capabilities[] = { "alsa", "oss" }; +static const char*const capabilities[] = { "alsa", "oss" }; typedef enum { CAP_ALSA, -- cgit From 5d8ccfd83984c6b0559857e6a0bf13037818ca95 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Aug 2006 16:50:15 +0000 Subject: try to reduce volume updates in the ALSA sinks/sources: only touch the shadowed hw volme if necessary git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1189 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-sink.c | 32 +++++++++++++++++++------------- src/modules/module-alsa-source.c | 22 +++++++++++++--------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index d5abdc28..0a0717df 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -212,20 +212,25 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { static int sink_get_hw_volume_cb(pa_sink *s) { struct userdata *u = s->userdata; - long vol; int err; int i; - assert(u && u->mixer_elem); + assert(u); + assert(u->mixer_elem); + + for (i = 0; i < s->hw_volume.channels; i++) { + long set_vol, vol; - for (i = 0;i < s->hw_volume.channels;i++) { assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, i)); - err = snd_mixer_selem_get_playback_volume(u->mixer_elem, i, &vol); - if (err < 0) + if ((err = snd_mixer_selem_get_playback_volume(u->mixer_elem, i, &vol)) < 0) goto fail; - s->hw_volume.values[i] = - (vol - u->hw_volume_min) * PA_VOLUME_NORM / (u->hw_volume_max - u->hw_volume_min); + + set_vol = (long) roundf(((float) s->hw_volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; + + /* Try to avoid superfluous volume changes */ + if (set_vol != vol) + s->hw_volume.values[i] = (pa_volume_t) roundf(((float) (vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min)); } return 0; @@ -243,9 +248,12 @@ static int sink_set_hw_volume_cb(pa_sink *s) { int i; pa_volume_t vol; - assert(u && u->mixer_elem); + assert(u); + assert(u->mixer_elem); - for (i = 0;i < s->hw_volume.channels;i++) { + for (i = 0; i < s->hw_volume.channels; i++) { + long alsa_vol; + assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, i)); vol = s->hw_volume.values[i]; @@ -253,11 +261,9 @@ static int sink_set_hw_volume_cb(pa_sink *s) { if (vol > PA_VOLUME_NORM) vol = PA_VOLUME_NORM; - vol = (vol * (u->hw_volume_max - u->hw_volume_min)) / - PA_VOLUME_NORM + u->hw_volume_min; + alsa_vol = (long) roundf(((float) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; - err = snd_mixer_selem_set_playback_volume(u->mixer_elem, i, vol); - if (err < 0) + if ((err = snd_mixer_selem_set_playback_volume(u->mixer_elem, i, alsa_vol)) < 0) goto fail; } diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index ca4ac9d0..3952a385 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -213,13 +213,18 @@ static int source_get_hw_volume_cb(pa_source *s) { assert(u && u->mixer_elem); for (i = 0;i < s->hw_volume.channels;i++) { + long set_vol; + assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); - - err = snd_mixer_selem_get_capture_volume(u->mixer_elem, i, &vol); - if (err < 0) + + if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, i, &vol)) < 0) goto fail; - s->hw_volume.values[i] = - (vol - u->hw_volume_min) * PA_VOLUME_NORM / (u->hw_volume_max - u->hw_volume_min); + + set_vol = (long) roundf(((float) s->hw_volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; + + /* Try to avoid superfluous volume changes */ + if (set_vol != vol) + s->hw_volume.values[i] = (pa_volume_t) roundf(((float) (vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min)); } return 0; @@ -247,10 +252,9 @@ static int source_set_hw_volume_cb(pa_source *s) { if (vol > PA_VOLUME_NORM) vol = PA_VOLUME_NORM; - vol = vol * (u->hw_volume_max - u->hw_volume_min) / - PA_VOLUME_NORM + u->hw_volume_min; - err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, vol); - if (err < 0) + vol = (long) roundf(((float) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; + + if ((err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, vol)) < 0) goto fail; } -- cgit From b382df5868db14628bed2d7445706dab5a4bdf58 Mon Sep 17 00:00:00 2001 From: "Shahms E. King" Date: Mon, 7 Aug 2006 20:29:31 +0000 Subject: clean up hal patch to use pa_xnew and timeval compatibility wrappers git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1190 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/dbus-util.c | 35 ++++++++------------- src/modules/module-hal-detect.c | 67 ++++++++++------------------------------- 2 files changed, 28 insertions(+), 74 deletions(-) diff --git a/src/modules/dbus-util.c b/src/modules/dbus-util.c index b5c61337..c9cdf114 100644 --- a/src/modules/dbus-util.c +++ b/src/modules/dbus-util.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "dbus-util.h" @@ -82,14 +83,6 @@ get_watch_flags(DBusWatch *watch) return events; } -static void timeval_next(struct timeval *tv, int millint) -{ - /* number of seconds in the milli-second interval */ - tv->tv_sec += (millint / 1000); - /* milliseconds minus the seconds portion, converted to microseconds */ - tv->tv_usec += (millint - tv->tv_sec * 1000) * 1000; -} - /* pa_io_event_cb_t IO event handler */ static void handle_io_event(PA_GCC_UNUSED pa_mainloop_api *ea, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) @@ -128,7 +121,7 @@ static void handle_time_event(pa_mainloop_api *ea, pa_time_event* e, dbus_timeout_handle(timeout); /* restart it for the next scheduled time */ - timeval_next(&next, dbus_timeout_get_interval(timeout)); + pa_timeval_add(&next, dbus_timeout_get_interval(timeout) * 1000); ea->time_restart(e, &next); } } @@ -182,10 +175,10 @@ static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) if (!dbus_timeout_get_enabled(timeout)) return FALSE; - if (gettimeofday(&tv, NULL) < 0) + if (pa_gettimeofday(&tv) < 0) return -1; - timeval_next(&tv, dbus_timeout_get_interval(timeout)); + pa_timeval_add(&tv, dbus_timeout_get_interval(timeout) * 1000); ev = c->mainloop->time_new(c->mainloop, &tv, handle_time_event, (void*) timeout); @@ -216,14 +209,13 @@ static void toggle_timeout(DBusTimeout *timeout, void *data) pa_core *c = (pa_core*) data; pa_time_event *ev = (pa_time_event*) dbus_timeout_get_data(timeout); - gettimeofday(&tv, NULL); if (dbus_timeout_get_enabled(timeout)) { - timeval_next(&tv, dbus_timeout_get_interval(timeout)); + pa_gettimeofday(&tv); + pa_timeval_add(&tv, dbus_timeout_get_interval(timeout) * 1000); c->mainloop->time_restart(ev, &tv); } else { - /* set it to expire one second ago */ - tv.tv_sec -= 1; - c->mainloop->time_restart(ev, &tv); + /* disable the timeout */ + c->mainloop->time_restart(ev, NULL); } } @@ -251,7 +243,7 @@ wakeup_main(void *userdata) static pa_dbus_connection* pa_dbus_connection_new(pa_core* c, DBusConnection *conn, const char* name) { - pa_dbus_connection *pconn = pa_xmalloc(sizeof(pa_dbus_connection)); + pa_dbus_connection *pconn = pa_xnew(pa_dbus_connection, 1); pconn->refcount = 1; pconn->core = c; @@ -305,19 +297,16 @@ pa_dbus_connection* pa_dbus_bus_get(pa_core *c, DBusBusType type, const char* name; DBusConnection *conn; pa_dbus_connection *pconn; - static const char sysname[] = "dbus-connection-system"; - static const char sessname[] = "dbus-connection-session"; - static const char startname[] = "dbus-connection-starter"; switch (type) { case DBUS_BUS_SYSTEM: - name = sysname; + name = "dbus-connection-system"; break; case DBUS_BUS_SESSION: - name = sessname; + name = "dbus-connection-session"; break; case DBUS_BUS_STARTER: - name = startname; + name = "dbus-connection-starter"; break; default: assert(0); /* never reached */ diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index adcb866c..a35144b0 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -34,11 +34,11 @@ #include #include +#include #include #include #include -#include #include #include #include @@ -68,18 +68,16 @@ typedef enum { } alsa_type_t; struct device { + uint32_t index; char *udi; - pa_module *module; }; struct userdata { pa_core *core; - pa_subscription *sub; LibHalContext *ctx; capability_t capability; pa_dbus_connection *conn; - pa_hashmap *by_udi; - pa_hashmap *by_module; + pa_hashmap *devices; }; struct timerdata { @@ -159,12 +157,11 @@ static dbus_bool_t hal_device_add_alsa(struct userdata *u, const char *udi, if (!(m = pa_module_load(u->core, module_name, args))) return FALSE; - d = pa_xmalloc(sizeof(struct device)); + d = pa_xnew(struct device, 1); d->udi = pa_xstrdup(udi); - d->module = m; + d->index = m->index; - pa_hashmap_put(u->by_module, m, d); - pa_hashmap_put(u->by_udi, udi, d); + pa_hashmap_put(u->devices, udi, d); return TRUE; } @@ -291,13 +288,13 @@ static void device_added_cb(LibHalContext *ctx, const char *udi) if (!has_cap) return; - /* actually add the device one second later */ - t = pa_xmalloc(sizeof(struct timerdata)); + /* actually add the device 1/2 second later */ + t = pa_xnew(struct timerdata, 1); t->u = u; t->udi = pa_xstrdup(udi); - gettimeofday(&tv, NULL); - tv.tv_sec += 1; + pa_gettimeofday(&tv); + pa_timeval_add(&tv, 500000); u->core->mainloop->time_new(u->core->mainloop, &tv, device_added_time_cb, t); } @@ -308,10 +305,8 @@ static void device_removed_cb(LibHalContext* ctx, const char *udi) struct userdata *u = (struct userdata*) libhal_ctx_get_user_data(ctx); pa_log_debug(__FILE__": Device removed: %s", udi); - if ((d = pa_hashmap_remove(u->by_udi, udi))) { - d = pa_hashmap_remove(u->by_module, d->module); - pa_log_debug(__FILE__": Unloading: %s <%s>", d->module->name, d->module->argument); - pa_module_unload_request(d->module); + if ((d = pa_hashmap_remove(u->devices, udi))) { + pa_module_unload_by_index(u->core, d->index); hal_device_free(d); } } @@ -335,30 +330,6 @@ static void property_modified_cb(LibHalContext *ctx, const char *udi, } #endif -static void subscribe_notify_cb(pa_core *c, pa_subscription_event_type_t type, - uint32_t idx, void *userdata) -{ - pa_module *m; - struct device *d; - struct userdata *u = (struct userdata*) userdata; - - /* only listen for module remove events */ - if (type != (PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_REMOVE)) - return; - - if (!(m = pa_idxset_get_by_index(c->modules, idx))) - return; - - /* we found the module, see if it's one we care about */ - if ((d = pa_hashmap_remove(u->by_module, m))) { - pa_log_debug(__FILE__": Removing module #%u %s: %s", - m->index, m->name, d->udi); - d = pa_hashmap_remove(u->by_udi, d->udi); - hal_device_free(d); - } -} - - static void pa_hal_context_free(LibHalContext* hal_ctx) { DBusError error; @@ -374,11 +345,8 @@ static void pa_hal_context_free(LibHalContext* hal_ctx) static void userdata_free(struct userdata *u) { pa_hal_context_free(u->ctx); - pa_subscription_free(u->sub); - /* free the hashmap */ - pa_hashmap_free(u->by_module, NULL, NULL); /* free the devices with the hashmap */ - pa_hashmap_free(u->by_udi, hal_device_free_cb, NULL); + pa_hashmap_free(u->devices, hal_device_free_cb, NULL); pa_dbus_connection_unref(u->conn); pa_xfree(u); } @@ -441,15 +409,12 @@ int pa__init(pa_core *c, pa_module*m) { return -1; } - u = pa_xmalloc(sizeof(struct userdata)); + u = pa_xnew(struct userdata, 1); u->core = c; u->ctx = hal_ctx; u->conn = conn; - u->by_module = pa_hashmap_new(NULL, NULL); - u->by_udi = pa_hashmap_new(pa_idxset_string_hash_func, - pa_idxset_string_compare_func); - u->sub = pa_subscription_new(c, PA_SUBSCRIPTION_MASK_MODULE, - subscribe_notify_cb, (void*) u); + u->devices = pa_hashmap_new(pa_idxset_string_hash_func, + pa_idxset_string_compare_func); m->userdata = (void*) u; #if HAVE_ALSA -- cgit From 7ee7a23408a1dae0ce1655067b26ed49e8e2e11f Mon Sep 17 00:00:00 2001 From: "Shahms E. King" Date: Tue, 8 Aug 2006 19:26:06 +0000 Subject: add HAL support for OSS devices and capability changes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1191 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-hal-detect.c | 175 ++++++++++++++++++++++++++-------------- 1 file changed, 115 insertions(+), 60 deletions(-) diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index a35144b0..27c39221 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -85,6 +85,21 @@ struct timerdata { char *udi; }; +static const char* get_capability_name(capability_t cap) { + if (cap >= CAP_MAX) + return NULL; + return capabilities[cap]; +} + +static void hal_device_free(struct device* d) { + pa_xfree(d->udi); + pa_xfree(d); +} + +static void hal_device_free_cb(void *d, PA_GCC_UNUSED void *data) { + hal_device_free((struct device*) d); +} + static alsa_type_t hal_device_get_alsa_type(LibHalContext *ctx, const char *udi, DBusError *error) { @@ -119,42 +134,98 @@ static int hal_device_get_alsa_device(LibHalContext *ctx, const char *udi, return libhal_device_get_property_int(ctx, udi, "alsa.device", error); } -static void hal_device_free(struct device* d) { - pa_xfree(d->udi); - pa_xfree(d); -} - -static void hal_device_free_cb(void *d, PA_GCC_UNUSED void *data) { - hal_device_free((struct device*) d); -} - -static dbus_bool_t hal_device_add_alsa(struct userdata *u, const char *udi, +static pa_module* hal_device_load_alsa(struct userdata *u, const char *udi, DBusError *error) { char args[64]; alsa_type_t type; int device, card; - pa_module *m; - struct device *d; const char *module_name; type = hal_device_get_alsa_type(u->ctx, udi, error); - if (dbus_error_is_set(error) || type == ALSA_TYPE_OTHER) { - return FALSE; - } + if (dbus_error_is_set(error) || type == ALSA_TYPE_OTHER) + return NULL; device = hal_device_get_alsa_device(u->ctx, udi, error); if (dbus_error_is_set(error) || device != 0) - return FALSE; + return NULL; card = hal_device_get_alsa_card(u->ctx, udi, error); if (dbus_error_is_set(error)) - return FALSE; + return NULL; module_name = (type == ALSA_TYPE_SINK) ? "module-alsa-sink" : "module-alsa-source"; snprintf(args, sizeof(args), "device=hw:%u", card); - if (!(m = pa_module_load(u->core, module_name, args))) + return pa_module_load(u->core, module_name, args); +} + +static dbus_bool_t hal_device_is_oss_pcm(LibHalContext *ctx, const char *udi, + DBusError *error) +{ + dbus_bool_t rv = FALSE; + char* device; + char* type; + + type = libhal_device_get_property_string(ctx, udi, "oss.type", error); + if (!type || dbus_error_is_set(error)) + return FALSE; + + if (!strcmp(type, "pcm")) { + device = libhal_device_get_property_string(ctx, udi, "oss.device_file", + error); + if (!device || dbus_error_is_set(error)) + goto exit; + + /* hack to ignore /dev/audio style devices */ + if ((device = strrchr(device, '/'))) + rv = (pa_startswith(device + 1, "audio")) ? FALSE : TRUE; + } + +exit: + libhal_free_string(type); + return rv; +} + +static pa_module* hal_device_load_oss(struct userdata *u, const char *udi, + DBusError *error) +{ + char args[128]; + char* device; + + if (!hal_device_is_oss_pcm(u->ctx, udi, error) || dbus_error_is_set(error)) + return NULL; + + device = libhal_device_get_property_string(u->ctx, udi, "oss.device_file", + error); + if (!device || dbus_error_is_set(error)) + return NULL; + + snprintf(args, sizeof(args), "device=%s", device); + libhal_free_string(device); + + return pa_module_load(u->core, "module-oss", args); +} + +static dbus_bool_t hal_device_add(struct userdata *u, const char *udi, + DBusError *error) +{ + pa_module* m; + struct device *d; + + switch(u->capability) { + case CAP_ALSA: + m = hal_device_load_alsa(u, udi, error); + break; + case CAP_OSS: + m = hal_device_load_oss(u, udi, error); + break; + default: + assert(FALSE); /* never reached */ + break; + } + + if (!m || dbus_error_is_set(error)) return FALSE; d = pa_xnew(struct device, 1); @@ -172,7 +243,7 @@ static int hal_device_add_all(struct userdata *u, capability_t capability) int i,n,count; dbus_bool_t r; char** udis; - const char* cap = capabilities[capability]; + const char* cap = get_capability_name(capability); assert(capability < CAP_MAX); @@ -186,20 +257,9 @@ static int hal_device_add_all(struct userdata *u, capability_t capability) return -1; } count = 0; + u->capability = capability; for (i = 0; i < n; ++i) { - switch(capability) { - case CAP_ALSA: - r = hal_device_add_alsa(u, udis[i], &error); - break; - case CAP_OSS: - /* r = hal_device_add_oss(u, udis[i], &error) - * break; */ - case CAP_MAX: - default: - assert(FALSE); - break; - } - + r = hal_device_add(u, udis[i], &error); if (dbus_error_is_set(&error)) { pa_log_error(__FILE__": Error adding device: %s: %s", error.name, error.message); @@ -212,7 +272,6 @@ static int hal_device_add_all(struct userdata *u, capability_t capability) } libhal_free_string_array(udis); - u->capability = capability; return count; } @@ -221,7 +280,7 @@ static dbus_bool_t device_has_capability(LibHalContext *ctx, const char *udi, { dbus_bool_t has_prop; has_prop = libhal_device_property_exists(ctx, udi, "info.capabilities", - error); + error); if (!has_prop || dbus_error_is_set(error)) return FALSE; @@ -235,24 +294,9 @@ static void device_added_time_cb(pa_mainloop_api *ea, pa_time_event *ev, struct timerdata *td = (struct timerdata*) userdata; dbus_error_init(&error); - if (!libhal_device_exists(td->u->ctx, td->udi, &error)) - goto exit; + if (libhal_device_exists(td->u->ctx, td->udi, &error)) + hal_device_add(td->u, td->udi, &error); - switch(td->u->capability) { - case CAP_ALSA: - hal_device_add_alsa(td->u, td->udi, &error); - break; - case CAP_OSS: - /* hal_device_add_oss(td->u, td->udi, &error); - * break; */ - case CAP_MAX: - default: - /* not reached */ - assert(FALSE); - break; - } - -exit: if (dbus_error_is_set(&error)) { pa_log_error(__FILE__": Error adding device: %s: %s", error.name, error.message); @@ -271,7 +315,7 @@ static void device_added_cb(LibHalContext *ctx, const char *udi) dbus_bool_t has_cap; struct timerdata *t; struct userdata *u = (struct userdata*) libhal_ctx_get_user_data(ctx); - const char* cap = capabilities[u->capability]; + const char* cap = get_capability_name(u->capability); pa_log_debug(__FILE__": HAL Device added: %s", udi); @@ -311,17 +355,31 @@ static void device_removed_cb(LibHalContext* ctx, const char *udi) } } -#if 0 static void new_capability_cb(LibHalContext *ctx, const char *udi, - const char* capability) + const char* capability) { + struct userdata *u = (struct userdata*) libhal_ctx_get_user_data(ctx); + const char* capname = get_capability_name(u->capability); + + if (capname && !strcmp(capname, capability)) { + /* capability we care about, pretend it's a new device */ + device_added_cb(ctx, udi); + } } static void lost_capability_cb(LibHalContext *ctx, const char *udi, const char* capability) { + struct userdata *u = (struct userdata*) libhal_ctx_get_user_data(ctx); + const char* capname = get_capability_name(u->capability); + + if (capname && !strcmp(capname, capability)) { + /* capability we care about, pretend it was removed */ + device_removed_cb(ctx, udi); + } } +#if 0 static void property_modified_cb(LibHalContext *ctx, const char *udi, const char* key, dbus_bool_t is_removed, @@ -432,6 +490,9 @@ int pa__init(pa_core *c, pa_module*m) { libhal_ctx_set_user_data(hal_ctx, (void*) u); libhal_ctx_set_device_added(hal_ctx, device_added_cb); libhal_ctx_set_device_removed(hal_ctx, device_removed_cb); + libhal_ctx_set_device_new_capability(hal_ctx, new_capability_cb); + libhal_ctx_set_device_lost_capability(hal_ctx, lost_capability_cb); + /*libhal_ctx_set_device_property_modified(hal_ctx, property_modified_cb);*/ dbus_error_init(&error); if (!libhal_device_property_watch_all(hal_ctx, &error)) { @@ -442,12 +503,6 @@ int pa__init(pa_core *c, pa_module*m) { return -1; } - /* - libhal_ctx_set_device_new_capability(hal_ctx, new_capability_cb); - libhal_ctx_set_device_lost_capability(hal_ctx, lost_capability_cb); - libhal_ctx_set_device_property_modified(hal_ctx, property_modified_cb); - */ - pa_log_info(__FILE__": loaded %i modules.", n); return 0; -- cgit From 59f1a67cb5f55f57b743667a3a15547fb1fb7cbc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 15:05:02 +0000 Subject: use the copied udi string as hash key for the device table, because the temporary one is freed when the function exits git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1192 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-hal-detect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index 27c39221..dd30045e 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -232,7 +232,7 @@ static dbus_bool_t hal_device_add(struct userdata *u, const char *udi, d->udi = pa_xstrdup(udi); d->index = m->index; - pa_hashmap_put(u->devices, udi, d); + pa_hashmap_put(u->devices, d->udi, d); return TRUE; } -- cgit From b0b968df0048a66c9beb76a0c0f42e3264753d4d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 15:06:03 +0000 Subject: change order of the ALSA event dispatch code to make sure that the code survives if the event dispatcher frees the ALSA client git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1193 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 04a2d849..969a3da1 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -93,14 +93,14 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, PA_GCC_UNUSED int fd, pa_io return; } + a->defer_enable(fdl->defer, 1); + if (revents) { if (fdl->pcm) fdl->cb(fdl->userdata); else snd_mixer_handle_events(fdl->mixer); } - - a->defer_enable(fdl->defer, 1); } static void defer_cb(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event* e, void *userdata) { -- cgit From 7a4e1c9a0ea6143553d6f63ad4b2f96f3c7bb9be Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 15:08:09 +0000 Subject: ALSA: handle write()/read() errors properly by unloading the driver module. This should fix problems when removing USB audio device while pulseaudio is running. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1194 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-sink.c | 78 ++++++++++++++++++++++++++-------------- src/modules/module-alsa-source.c | 76 ++++++++++++++++++++++++++------------- 2 files changed, 104 insertions(+), 50 deletions(-) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 0a0717df..d47e8c3b 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -96,13 +96,49 @@ static void update_usage(struct userdata *u) { (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0)); } -static void xrun_recovery(struct userdata *u) { +static void clear_up(struct userdata *u) { assert(u); + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + u->sink = NULL; + } + + if (u->pcm_fdl) + pa_alsa_fdlist_free(u->pcm_fdl); + if (u->mixer_fdl) + pa_alsa_fdlist_free(u->mixer_fdl); - pa_log(__FILE__": *** ALSA-XRUN (playback) ***"); + u->pcm_fdl = u->mixer_fdl = NULL; + + if (u->mixer_handle) { + snd_mixer_close(u->mixer_handle); + u->mixer_handle = NULL; + } - if (snd_pcm_prepare(u->pcm_handle) < 0) - pa_log(__FILE__": snd_pcm_prepare() failed"); + if (u->pcm_handle) { + snd_pcm_drop(u->pcm_handle); + snd_pcm_close(u->pcm_handle); + u->pcm_handle = NULL; + } +} + +static int xrun_recovery(struct userdata *u) { + int ret; + assert(u); + + pa_log_info(__FILE__": *** ALSA-XRUN (playback) ***"); + + if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) { + pa_log(__FILE__": snd_pcm_prepare() failed: %s", snd_strerror(-ret)); + + clear_up(u); + pa_module_unload_request(u->module); + return -1; + } + + return ret; } static void do_write(struct userdata *u) { @@ -130,11 +166,16 @@ static void do_write(struct userdata *u) { return; if (frames == -EPIPE) { - xrun_recovery(u); + if (xrun_recovery(u) < 0) + return; + continue; } - pa_log(__FILE__": snd_pcm_writei() failed: %s", snd_strerror(frames)); + pa_log(__FILE__": snd_pcm_writei() failed: %s", snd_strerror(-frames)); + + clear_up(u); + pa_module_unload_request(u->module); return; } @@ -159,7 +200,8 @@ static void fdl_callback(void *userdata) { assert(u); if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) - xrun_recovery(u); + if (xrun_recovery(u) < 0) + return; do_write(u); } @@ -480,25 +522,9 @@ void pa__done(pa_core *c, pa_module*m) { if (!(u = m->userdata)) return; - - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - } - - if (u->pcm_fdl) - pa_alsa_fdlist_free(u->pcm_fdl); - if (u->mixer_fdl) - pa_alsa_fdlist_free(u->mixer_fdl); - - if (u->mixer_handle) - snd_mixer_close(u->mixer_handle); - - if (u->pcm_handle) { - snd_pcm_drop(u->pcm_handle); - snd_pcm_close(u->pcm_handle); - } - + + clear_up(u); + if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); if (u->silence.memblock) diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 3952a385..b5cf9c70 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -96,13 +96,50 @@ static void update_usage(struct userdata *u) { (u->source ? pa_idxset_size(u->source->outputs) : 0)); } -static void xrun_recovery(struct userdata *u) { +static void clear_up(struct userdata *u) { assert(u); + + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + u->source = NULL; + } + + if (u->pcm_fdl) + pa_alsa_fdlist_free(u->pcm_fdl); + if (u->mixer_fdl) + pa_alsa_fdlist_free(u->mixer_fdl); - pa_log(__FILE__": *** ALSA-XRUN (capture) ***"); + u->pcm_fdl = u->mixer_fdl = NULL; + + if (u->mixer_handle) { + snd_mixer_close(u->mixer_handle); + u->mixer_handle = NULL; + } - if (snd_pcm_prepare(u->pcm_handle) < 0) - pa_log(__FILE__": snd_pcm_prepare() failed"); + if (u->pcm_handle) { + snd_pcm_drop(u->pcm_handle); + snd_pcm_close(u->pcm_handle); + u->pcm_handle = NULL; + } +} + +static int xrun_recovery(struct userdata *u) { + int ret; + assert(u); + + pa_log_info(__FILE__": *** ALSA-XRUN (capture) ***"); + + if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) { + pa_log(__FILE__": snd_pcm_prepare() failed: %s", snd_strerror(-ret)); + + clear_up(u); + pa_module_unload_request(u->module); + + return -1; + } + + return 0; } static void do_read(struct userdata *u) { @@ -131,11 +168,16 @@ static void do_read(struct userdata *u) { return; if (frames == -EPIPE) { - xrun_recovery(u); + if (xrun_recovery(u) < 0) + return; + continue; } - pa_log(__FILE__": snd_pcm_readi() failed: %s", pa_cstrerror(-frames)); + pa_log(__FILE__": snd_pcm_readi() failed: %s", snd_strerror(-frames)); + + clear_up(u); + pa_module_unload_request(u->module); return; } @@ -164,7 +206,8 @@ static void fdl_callback(void *userdata) { assert(u); if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) - xrun_recovery(u); + if (xrun_recovery(u) < 0) + return; do_read(u); } @@ -182,6 +225,7 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { u->source->get_hw_volume(u->source); if (u->source->get_hw_mute) u->source->get_hw_mute(u->source); + pa_subscription_post(u->source->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, u->source->index); @@ -468,24 +512,8 @@ void pa__done(pa_core *c, pa_module*m) { if (!(u = m->userdata)) return; - - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - } - - if (u->pcm_fdl) - pa_alsa_fdlist_free(u->pcm_fdl); - if (u->mixer_fdl) - pa_alsa_fdlist_free(u->mixer_fdl); - if (u->mixer_handle) - snd_mixer_close(u->mixer_handle); - - if (u->pcm_handle) { - snd_pcm_drop(u->pcm_handle); - snd_pcm_close(u->pcm_handle); - } + clear_up(u); if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); -- cgit From dcd3acc0b887dcf3f94569a1984e0217a1ddf581 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 16:29:46 +0000 Subject: remove OSS specific code from module-hal-detect if HAVE_OSS is not set. Same for ALSA git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1195 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-hal-detect.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index dd30045e..6a430a83 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -52,20 +52,24 @@ PA_MODULE_AUTHOR("Shahms King") PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers") PA_MODULE_VERSION(PACKAGE_VERSION) -static const char*const capabilities[] = { "alsa", "oss" }; - typedef enum { +#ifdef HAVE_ALSA CAP_ALSA, +#endif +#ifdef HAVE_OSS CAP_OSS, +#endif CAP_MAX } capability_t; -typedef enum { - ALSA_TYPE_SINK, - ALSA_TYPE_SOURCE, - ALSA_TYPE_OTHER, - ALSA_TYPE_MAX -} alsa_type_t; +static const char* const capabilities[CAP_MAX] = { +#ifdef HAVE_ALSA + [CAP_ALSA] = "alsa", +#endif +#ifdef HAVE_OSS + [CAP_OSS] = "oss", +#endif +}; struct device { uint32_t index; @@ -100,6 +104,14 @@ static void hal_device_free_cb(void *d, PA_GCC_UNUSED void *data) { hal_device_free((struct device*) d); } +#ifdef HAVE_ALSA +typedef enum { + ALSA_TYPE_SINK, + ALSA_TYPE_SOURCE, + ALSA_TYPE_OTHER, + ALSA_TYPE_MAX +} alsa_type_t; + static alsa_type_t hal_device_get_alsa_type(LibHalContext *ctx, const char *udi, DBusError *error) { @@ -160,6 +172,9 @@ static pa_module* hal_device_load_alsa(struct userdata *u, const char *udi, return pa_module_load(u->core, module_name, args); } +#endif + +#ifdef HAVE_OSS static dbus_bool_t hal_device_is_oss_pcm(LibHalContext *ctx, const char *udi, DBusError *error) { @@ -206,6 +221,7 @@ static pa_module* hal_device_load_oss(struct userdata *u, const char *udi, return pa_module_load(u->core, "module-oss", args); } +#endif static dbus_bool_t hal_device_add(struct userdata *u, const char *udi, DBusError *error) @@ -214,12 +230,16 @@ static dbus_bool_t hal_device_add(struct userdata *u, const char *udi, struct device *d; switch(u->capability) { +#ifdef HAVE_ALSA case CAP_ALSA: m = hal_device_load_alsa(u, udi, error); break; +#endif +#ifdef HAVE_OSS case CAP_OSS: m = hal_device_load_oss(u, udi, error); break; +#endif default: assert(FALSE); /* never reached */ break; @@ -475,10 +495,10 @@ int pa__init(pa_core *c, pa_module*m) { pa_idxset_string_compare_func); m->userdata = (void*) u; -#if HAVE_ALSA +#ifdef HAVE_ALSA if ((n = hal_device_add_all(u, CAP_ALSA)) <= 0) #endif -#if HAVE_OSS +#ifdef HAVE_OSS if ((n = hal_device_add_all(u, CAP_OSS)) <= 0) #endif { -- cgit From bf854c445ab83a298b8a364c08b0aca9938471f0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 16:38:05 +0000 Subject: Build HAL support only when either OSS or ALSA is available git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1196 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index bf7425c0..68d9d5d5 100644 --- a/configure.ac +++ b/configure.ac @@ -650,7 +650,7 @@ AC_ARG_ENABLE([hal], ], [hal=auto]) -if test "x${hal}" != xno ; then +if test "x${hal}" != xno -a \( "x$HAVE_OSS" = "x1" -o "x$HAVE_ALSA" = "x1" \) ; then PKG_CHECK_MODULES(HAL, [ hal >= 0.5.7 ], HAVE_HAL=1, [ -- cgit From 576c4dd96a3780716e603363c0dfa83f20e85937 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 16:38:51 +0000 Subject: rework name register a litle to only allow "valid" names. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1197 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/namereg.c | 126 ++++++++++++++++++++++++++++++++++++------------ src/pulsecore/namereg.h | 8 ++- 2 files changed, 101 insertions(+), 33 deletions(-) diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c index 11c36c3a..bb5eb7be 100644 --- a/src/pulsecore/namereg.c +++ b/src/pulsecore/namereg.c @@ -45,10 +45,54 @@ struct namereg_entry { void *data; }; +static int is_valid_char(char c) { + return + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '.' || + c == '_'; +} + +int pa_namereg_is_valid_name(const char *name) { + const char *c; + + if (*name == 0) + return 0; + + for (c = name; *c && (c-name < PA_NAME_MAX); c++) + if (!is_valid_char(*c)) + return 0; + + if (*c) + return 0; + + return 1; +} + +char* pa_namereg_cleanup_name(const char *name) { + const char *a; + char *b, *n; + + if (*name == 0) + return NULL; + + n = pa_xnew(char, strlen(name)+1); + + for (a = name, b = n; *a && (a-name < PA_NAME_MAX); a++, b++) + *b = is_valid_char(*a) ? *a : '_'; + + *b = 0; + + return n; +} + void pa_namereg_free(pa_core *c) { assert(c); + if (!c->namereg) return; + assert(pa_hashmap_size(c->namereg) == 0); pa_hashmap_free(c->namereg, NULL, NULL); } @@ -62,54 +106,71 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t assert(name); assert(data); - /* Don't allow registration of special names */ - if (*name == '@') + if (!*name) return NULL; + + if (!pa_namereg_is_valid_name(name)) { + + if (fail) + return NULL; - if (!c->namereg) { - c->namereg = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - assert(c->namereg); + if (!(name = n = pa_namereg_cleanup_name(name))) + return NULL; } - if ((e = pa_hashmap_get(c->namereg, name)) && fail) + if (!c->namereg) + c->namereg = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + + if ((e = pa_hashmap_get(c->namereg, name)) && fail) { + pa_xfree(n); return NULL; + } - if (!e) - n = pa_xstrdup(name); - else { + if (e) { unsigned i; size_t l = strlen(name); - n = pa_xmalloc(l+3); + char *k; + + if (l+4 > PA_NAME_MAX) { + pa_xfree(n); + return NULL; + } - for (i = 1; i <= 99; i++) { - snprintf(n, l+2, "%s%u", name, i); + k = pa_xnew(char, l+4); + + for (i = 2; i <= 99; i++) { + snprintf(k, l+4, "%s.%u", name, i); - if (!(e = pa_hashmap_get(c->namereg, n))) + if (!(e = pa_hashmap_get(c->namereg, k))) break; } if (e) { pa_xfree(n); + pa_xfree(k); return NULL; } + + pa_xfree(n); + n = k; } - assert(n); - e = pa_xmalloc(sizeof(struct namereg_entry)); + e = pa_xnew(struct namereg_entry, 1); e->type = type; - e->name = n; + e->name = n ? n : pa_xstrdup(name); e->data = data; r = pa_hashmap_put(c->namereg, e->name, e); assert (r >= 0); return e->name; - } void pa_namereg_unregister(pa_core *c, const char *name) { struct namereg_entry *e; - assert(c && name); + + assert(c); + assert(name); e = pa_hashmap_remove(c->namereg, name); assert(e); @@ -178,26 +239,33 @@ void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int a return NULL; } -void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type) { +int pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type) { char **s; - assert(c && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); + + assert(c); + assert(type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE); s = type == PA_NAMEREG_SINK ? &c->default_sink_name : &c->default_source_name; - assert(s); if (!name && !*s) - return; - + return 0; + if (name && *s && !strcmp(name, *s)) - return; + return 0; + + if (!pa_namereg_is_valid_name(name)) + return -1; pa_xfree(*s); *s = pa_xstrdup(name); pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); + + return 0; } const char *pa_namereg_get_default_sink_name(pa_core *c) { pa_sink *s; + assert(c); if (c->default_sink_name) @@ -206,10 +274,7 @@ const char *pa_namereg_get_default_sink_name(pa_core *c) { if ((s = pa_idxset_first(c->sinks, NULL))) pa_namereg_set_default(c, s->name, PA_NAMEREG_SINK); - if (c->default_sink_name) - return c->default_sink_name; - - return NULL; + return c->default_sink_name; } const char *pa_namereg_get_default_source_name(pa_core *c) { @@ -231,8 +296,5 @@ const char *pa_namereg_get_default_source_name(pa_core *c) { if ((s = pa_idxset_first(c->sources, NULL))) pa_namereg_set_default(c, s->name, PA_NAMEREG_SOURCE); - if (c->default_source_name) - return c->default_source_name; - - return NULL; + return c->default_source_name; } diff --git a/src/pulsecore/namereg.h b/src/pulsecore/namereg.h index e1aef8bb..0f8466ad 100644 --- a/src/pulsecore/namereg.h +++ b/src/pulsecore/namereg.h @@ -24,6 +24,8 @@ #include +#define PA_NAME_MAX 64 + typedef enum pa_namereg_type { PA_NAMEREG_SINK, PA_NAMEREG_SOURCE, @@ -32,10 +34,14 @@ typedef enum pa_namereg_type { void pa_namereg_free(pa_core *c); +int pa_namereg_is_valid_name(const char *name); + +char* pa_namereg_cleanup_name(const char *name); + const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, int fail); void pa_namereg_unregister(pa_core *c, const char *name); void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int autoload); -void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type); +int pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type); const char *pa_namereg_get_default_sink_name(pa_core *c); const char *pa_namereg_get_default_source_name(pa_core *c); -- cgit From e1316f572828257ea788c87aabf4e298101fbaa1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 16:56:47 +0000 Subject: fix bad memory access and a leak when detructing ALSA fd lists git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1198 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 969a3da1..39ddbfe9 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -178,7 +178,6 @@ struct pa_alsa_fdlist *pa_alsa_fdlist_new(void) { struct pa_alsa_fdlist *fdl; fdl = pa_xmalloc(sizeof(struct pa_alsa_fdlist)); - assert(fdl); fdl->num_fds = 0; fdl->fds = NULL; @@ -208,7 +207,7 @@ void pa_alsa_fdlist_free(struct pa_alsa_fdlist *fdl) { int i; assert(fdl->m); for (i = 0;i < fdl->num_fds;i++) - fdl->m->io_free(fdl->ios[0]); + fdl->m->io_free(fdl->ios[i]); pa_xfree(fdl->ios); } -- cgit From 539612a5c27a9b786ba76fb632110d9fa9178a39 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 16:58:21 +0000 Subject: do not export name validity checking routes and apply them only to sink/source names, not sample names git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1199 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/namereg.c | 11 ++++++----- src/pulsecore/namereg.h | 4 ---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c index bb5eb7be..fcd271bf 100644 --- a/src/pulsecore/namereg.c +++ b/src/pulsecore/namereg.c @@ -54,7 +54,7 @@ static int is_valid_char(char c) { c == '_'; } -int pa_namereg_is_valid_name(const char *name) { +static int is_valid_name(const char *name) { const char *c; if (*name == 0) @@ -70,7 +70,7 @@ int pa_namereg_is_valid_name(const char *name) { return 1; } -char* pa_namereg_cleanup_name(const char *name) { +static char* cleanup_name(const char *name) { const char *a; char *b, *n; @@ -109,12 +109,13 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t if (!*name) return NULL; - if (!pa_namereg_is_valid_name(name)) { + if ((type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE) && + !is_valid_name(name) ) { if (fail) return NULL; - if (!(name = n = pa_namereg_cleanup_name(name))) + if (!(name = n = cleanup_name(name))) return NULL; } @@ -253,7 +254,7 @@ int pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type) if (name && *s && !strcmp(name, *s)) return 0; - if (!pa_namereg_is_valid_name(name)) + if (!is_valid_name(name)) return -1; pa_xfree(*s); diff --git a/src/pulsecore/namereg.h b/src/pulsecore/namereg.h index 0f8466ad..53295b84 100644 --- a/src/pulsecore/namereg.h +++ b/src/pulsecore/namereg.h @@ -34,10 +34,6 @@ typedef enum pa_namereg_type { void pa_namereg_free(pa_core *c); -int pa_namereg_is_valid_name(const char *name); - -char* pa_namereg_cleanup_name(const char *name); - const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, int fail); void pa_namereg_unregister(pa_core *c, const char *name); void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int autoload); -- cgit From 1d7b8e1ba761314a85908dd172b75a02526ff649 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 17:12:54 +0000 Subject: use the HAL UDI for naming input/output devices git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1200 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-hal-detect.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index 6a430a83..0063fdbd 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -104,6 +104,14 @@ static void hal_device_free_cb(void *d, PA_GCC_UNUSED void *data) { hal_device_free((struct device*) d); } +static const char *strip_udi(const char *udi) { + const char *slash; + if ((slash = strrchr(udi, '/'))) + return slash+1; + + return udi; +} + #ifdef HAVE_ALSA typedef enum { ALSA_TYPE_SINK, @@ -166,9 +174,14 @@ static pa_module* hal_device_load_alsa(struct userdata *u, const char *udi, if (dbus_error_is_set(error)) return NULL; - module_name = (type == ALSA_TYPE_SINK) ? "module-alsa-sink" - : "module-alsa-source"; - snprintf(args, sizeof(args), "device=hw:%u", card); + if (type == ALSA_TYPE_SINK) { + module_name = "module-alsa-sink"; + snprintf(args, sizeof(args), "device=hw:%u sink_name=alsa_output.%s", card, strip_udi(udi)); + } else { + module_name = "module-alsa-source"; + snprintf(args, sizeof(args), "device=hw:%u source_name=alsa_input.%s", card, strip_udi(udi)); + } + return pa_module_load(u->core, module_name, args); } @@ -216,7 +229,7 @@ static pa_module* hal_device_load_oss(struct userdata *u, const char *udi, if (!device || dbus_error_is_set(error)) return NULL; - snprintf(args, sizeof(args), "device=%s", device); + snprintf(args, sizeof(args), "device=%s sink_name=oss_output.%s source_name=oss_input.%s", device, strip_udi(udi), strip_udi(udi)); libhal_free_string(device); return pa_module_load(u->core, "module-oss", args); -- cgit From bfff23db10db9fe6370f8bfbc8498d2057030a0d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 17:14:35 +0000 Subject: shorten sink/source device descriptions a little git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1201 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-sink.c | 2 +- src/modules/module-alsa-source.c | 2 +- src/modules/module-oss-mmap.c | 4 ++-- src/modules/module-oss.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index d47e8c3b..649fe99c 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -457,7 +457,7 @@ int pa__init(pa_core *c, pa_module*m) { } u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s' (%s)", dev, snd_pcm_info_get_name(pcm_info)); + u->sink->description = pa_sprintf_malloc("ALSA PCM on %s (%s)", dev, snd_pcm_info_get_name(pcm_info)); u->pcm_fdl = pa_alsa_fdlist_new(); assert(u->pcm_fdl); diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index b5cf9c70..63369e47 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -450,7 +450,7 @@ int pa__init(pa_core *c, pa_module*m) { } } pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s' (%s)", dev, snd_pcm_info_get_name(pcm_info)); + u->source->description = pa_sprintf_malloc("ALSA PCM on %s (%s)", dev, snd_pcm_info_get_name(pcm_info)); u->pcm_fdl = pa_alsa_fdlist_new(); assert(u->pcm_fdl); diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index d6f37633..4212febe 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -439,7 +439,7 @@ int pa__init(pa_core *c, pa_module*m) { u->source->get_hw_volume = source_get_hw_volume; u->source->set_hw_volume = source_set_hw_volume; pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'%s%s%s", + u->source->description = pa_sprintf_malloc("OSS PCM/mmap() on %s%s%s%s", p, hwdesc[0] ? " (" : "", hwdesc[0] ? hwdesc : "", @@ -480,7 +480,7 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->set_hw_volume = sink_set_hw_volume; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Open Sound System PCM/mmap() on '%s'%s%s%s", + u->sink->description = pa_sprintf_malloc("OSS PCM/mmap() on %s%s%s%s", p, hwdesc[0] ? " (" : "", hwdesc[0] ? hwdesc : "", diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index cde7f311..c9fce7a7 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -413,7 +413,7 @@ int pa__init(pa_core *c, pa_module*m) { u->source->get_hw_volume = source_get_hw_volume; u->source->set_hw_volume = source_set_hw_volume; pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Open Sound System PCM on '%s'%s%s%s", + u->source->description = pa_sprintf_malloc("OSS PCM on %s%s%s%s", p, hwdesc[0] ? " (" : "", hwdesc[0] ? hwdesc : "", @@ -431,7 +431,7 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->set_hw_volume = sink_set_hw_volume; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Open Sound System PCM on '%s'%s%s%s", + u->sink->description = pa_sprintf_malloc("OSS PCM on %s%s%s%s", p, hwdesc[0] ? " (" : "", hwdesc[0] ? hwdesc : "", -- cgit From 0aebc03d1ad0820dac76057a0474a4bd7c025c76 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 17:15:41 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1202 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/todo b/todo index 5c2edf75..89239db0 100644 --- a/todo +++ b/todo @@ -3,7 +3,7 @@ Post 0.9.0: - alsa mmap driver - alsa driver with hw mixing -- dbus/hal (Shams King is working on this one) +- merge module-oss-mmap into module-oss - chroot() - module-tunnel: improve latency calculation - multiline configuration statements @@ -34,6 +34,8 @@ Post 0.9.0: - key rings for auth - challenge response auth - sasl auth +- fix OSS hot-remove +- use better sink/source names, generated from the device file names Long term: - pass meta info for hearing impaired -- cgit From c90dd53268bec8516be3b37e8af1989290f022a2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 17:53:34 +0000 Subject: * introduce new functions pa_sink_set_description() and pa_source_set_description() for changing the description of a sink/source * allow sinks without monitor sources attached git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1203 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/sink.c | 58 +++++++++++++++++++++++++++++++++++++++++--------- src/pulsecore/sink.h | 2 ++ src/pulsecore/source.c | 16 ++++++++++++++ src/pulsecore/source.h | 3 +++ 4 files changed, 69 insertions(+), 10 deletions(-) diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 8acb7715..eecf89cc 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -118,12 +118,19 @@ pa_sink* pa_sink_new( pa_sample_spec_snprint(st, sizeof(st), spec); pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"", s->index, s->name, st); - n = pa_sprintf_malloc("%s_monitor", name); - s->monitor_source = pa_source_new(core, driver, n, 0, spec, map); - assert(s->monitor_source); + n = pa_sprintf_malloc("%s.monitor", name); + + if (!(s->monitor_source = pa_source_new(core, driver, n, 0, spec, map))) + pa_log_warn(__FILE__": failed to create monitor source."); + else { + char *d; + s->monitor_source->monitor_of = s; + d = pa_sprintf_malloc("Monitor Source of %s", s->name); + pa_source_set_description(s->monitor_source, d); + pa_xfree(d); + } + pa_xfree(n); - s->monitor_source->monitor_of = s; - s->monitor_source->description = pa_sprintf_malloc("Monitor source of sink '%s'", s->name); pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index); @@ -144,7 +151,8 @@ void pa_sink_disconnect(pa_sink* s) { j = i; } - pa_source_disconnect(s->monitor_source); + if (s->monitor_source) + pa_source_disconnect(s->monitor_source); pa_idxset_remove_by_data(s->core->sinks, s, NULL); @@ -168,8 +176,10 @@ static void sink_free(pa_sink *s) { pa_log_info(__FILE__": freed %u \"%s\"", s->index, s->name); - pa_source_unref(s->monitor_source); - s->monitor_source = NULL; + if (s->monitor_source) { + pa_source_unref(s->monitor_source); + s->monitor_source = NULL; + } pa_idxset_free(s->inputs, NULL, NULL); @@ -304,7 +314,9 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { } inputs_drop(s, info, n, result->length); - pa_source_post(s->monitor_source, result); + + if (s->monitor_source) + pa_source_post(s->monitor_source, result); r = 0; @@ -358,7 +370,9 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { s->sw_muted); inputs_drop(s, info, n, target->length); - pa_source_post(s->monitor_source, target); + + if (s->monitor_source) + pa_source_post(s->monitor_source, target); r = 0; @@ -513,3 +527,27 @@ int pa_sink_get_mute(pa_sink *s, pa_mixer_t m) { } else return s->sw_muted; } + +void pa_sink_set_description(pa_sink *s, const char *description) { + assert(s); + assert(s->ref >= 1); + + if (!description && !s->description) + return; + + if (description && s->description && !strcmp(description, s->description)) + return; + + pa_xfree(s->description); + s->description = pa_xstrdup(description); + + if (s->monitor_source) { + char *n; + + n = pa_sprintf_malloc("Monitor Source of %s", s->description? s->description : s->name); + pa_source_set_description(s->monitor_source, n); + pa_xfree(n); + } + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); +} diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 1a6bc988..5a80a013 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -100,4 +100,6 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_mixer_t m); void pa_sink_set_mute(pa_sink *sink, pa_mixer_t m, int mute); int pa_sink_get_mute(pa_sink *sink, pa_mixer_t m); +void pa_sink_set_description(pa_sink *s, const char *description); + #endif diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 48b6daea..f9c0703d 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -313,3 +313,19 @@ int pa_source_get_mute(pa_source *s, pa_mixer_t m) { } else return s->sw_muted; } + +void pa_source_set_description(pa_source *s, const char *description) { + assert(s); + assert(s->ref >= 1); + + if (!description && !s->description) + return; + + if (description && s->description && !strcmp(description, s->description)) + return; + + pa_xfree(s->description); + s->description = pa_xstrdup(description); + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); +} diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index 878ae34d..0643a108 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -100,4 +100,7 @@ const pa_cvolume *pa_source_get_volume(pa_source *source, pa_mixer_t m); void pa_source_set_mute(pa_source *source, pa_mixer_t m, int mute); int pa_source_get_mute(pa_source *source, pa_mixer_t m); +void pa_source_set_description(pa_source *s, const char *description); + + #endif -- cgit From af1b0317f653a3da092b45de3b27643359b9a85e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 23:31:59 +0000 Subject: comment which values in pa_{sink,source,sink_input,source_output} structures may be NULL git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1204 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/sink-input.h | 16 ++++++++-------- src/pulsecore/sink.h | 23 ++++++++++++----------- src/pulsecore/source-output.h | 12 ++++++------ src/pulsecore/source.h | 20 +++++++++++--------- 4 files changed, 37 insertions(+), 34 deletions(-) diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index b1971d0a..d33f382b 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -45,11 +45,11 @@ struct pa_sink_input { uint32_t index; pa_sink_input_state_t state; - char *name, *driver; - pa_module *owner; + char *name, *driver; /* may be NULL */ + pa_module *owner; /* may be NULL */ pa_sink *sink; - pa_client *client; + pa_client *client; /* may be NULL */ pa_sample_spec sample_spec; pa_channel_map channel_map; @@ -63,19 +63,19 @@ struct pa_sink_input { int (*peek) (pa_sink_input *i, pa_memchunk *chunk); void (*drop) (pa_sink_input *i, const pa_memchunk *chunk, size_t length); - void (*kill) (pa_sink_input *i); - pa_usec_t (*get_latency) (pa_sink_input *i); - void (*underrun) (pa_sink_input *i); + void (*kill) (pa_sink_input *i); /* may be NULL */ + pa_usec_t (*get_latency) (pa_sink_input *i); /* may be NULL */ + void (*underrun) (pa_sink_input *i); /* may be NULL */ void *userdata; pa_memchunk resampled_chunk; - pa_resampler *resampler; + pa_resampler *resampler; /* may be NULL */ int variable_rate; pa_resample_method_t resample_method; - pa_memblock *silence_memblock; + pa_memblock *silence_memblock; /* may be NULL */ }; pa_sink_input* pa_sink_input_new( diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 5a80a013..fb0912ca 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -48,26 +48,27 @@ struct pa_sink { pa_core *core; pa_sink_state_t state; - char *name, *description, *driver; - pa_module *owner; + char *name; + char *description, *driver; /* may be NULL */ + int is_hardware; + + pa_module *owner; /* may be NULL */ pa_sample_spec sample_spec; pa_channel_map channel_map; pa_idxset *inputs; - pa_source *monitor_source; + pa_source *monitor_source; /* may be NULL */ pa_cvolume hw_volume, sw_volume; int hw_muted, sw_muted; - int is_hardware; - - void (*notify)(pa_sink*sink); - pa_usec_t (*get_latency)(pa_sink *s); - int (*set_hw_volume)(pa_sink *s); - int (*get_hw_volume)(pa_sink *s); - int (*set_hw_mute)(pa_sink *s); - int (*get_hw_mute)(pa_sink *s); + void (*notify)(pa_sink*sink); /* may be NULL */ + pa_usec_t (*get_latency)(pa_sink *s); /* dito */ + int (*set_hw_volume)(pa_sink *s); /* dito */ + int (*get_hw_volume)(pa_sink *s); /* dito */ + int (*set_hw_mute)(pa_sink *s); /* dito */ + int (*get_hw_mute)(pa_sink *s); /* dito */ void *userdata; }; diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index 9a8ea92b..acf53bd1 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -44,20 +44,20 @@ struct pa_source_output { uint32_t index; pa_source_output_state_t state; - char *name, *driver; - pa_module *owner; + char *name, *driver; /* may be NULL */ + pa_module *owner; /* may be NULL */ pa_source *source; - pa_client *client; + pa_client *client; /* may be NULL */ pa_sample_spec sample_spec; pa_channel_map channel_map; void (*push)(pa_source_output *o, const pa_memchunk *chunk); - void (*kill)(pa_source_output* o); - pa_usec_t (*get_latency) (pa_source_output *o); + void (*kill)(pa_source_output* o); /* may be NULL */ + pa_usec_t (*get_latency) (pa_source_output *o); /* may be NULL */ - pa_resampler* resampler; + pa_resampler* resampler; /* may be NULL */ pa_resample_method_t resample_method; void *userdata; diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index 0643a108..be0c969d 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -50,26 +50,28 @@ struct pa_source { pa_core *core; pa_source_state_t state; - char *name, *description, *driver; - pa_module *owner; + char *name; + char *description, *driver; /* may be NULL */ + + pa_module *owner; /* may be NULL */ pa_sample_spec sample_spec; pa_channel_map channel_map; pa_idxset *outputs; - pa_sink *monitor_of; + pa_sink *monitor_of; /* may be NULL */ pa_cvolume hw_volume, sw_volume; int hw_muted, sw_muted; int is_hardware; - void (*notify)(pa_source*source); - pa_usec_t (*get_latency)(pa_source *s); - int (*set_hw_volume)(pa_source *s); - int (*get_hw_volume)(pa_source *s); - int (*set_hw_mute)(pa_source *s); - int (*get_hw_mute)(pa_source *s); + void (*notify)(pa_source*source); /* may be NULL */ + pa_usec_t (*get_latency)(pa_source *s); /* dito */ + int (*set_hw_volume)(pa_source *s); /* dito */ + int (*get_hw_volume)(pa_source *s); /* dito */ + int (*set_hw_mute)(pa_source *s); /* dito */ + int (*get_hw_mute)(pa_source *s); /* dito */ void *userdata; }; -- cgit From bfa6604b1ddc5e2c0f1aaa15330363724856359b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 23:58:55 +0000 Subject: don't set the sink/source descriptions manually, use the new functions pa_{sink,source}_set_description() instead git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1205 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-sink.c | 6 ++++-- src/modules/module-alsa-source.c | 4 +++- src/modules/module-combine.c | 2 +- src/modules/module-esound-sink.c | 5 ++++- src/modules/module-jack-sink.c | 4 +++- src/modules/module-jack-source.c | 4 +++- src/modules/module-null-sink.c | 2 +- src/modules/module-oss-mmap.c | 24 +++++++++++++----------- src/modules/module-oss.c | 24 +++++++++++++----------- src/modules/module-pipe-sink.c | 6 ++++-- src/modules/module-pipe-source.c | 6 ++++-- src/modules/module-solaris.c | 7 +++++-- src/modules/module-tunnel.c | 9 +++++++-- src/modules/module-waveout.c | 4 ++-- src/modules/module-zeroconf-publish.c | 3 ++- 15 files changed, 69 insertions(+), 41 deletions(-) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 649fe99c..efecfc21 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -366,7 +366,8 @@ int pa__init(pa_core *c, pa_module*m) { size_t frame_size; snd_pcm_info_t *pcm_info = NULL; int err; - + char *t; + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": failed to parse module arguments"); goto fail; @@ -457,7 +458,8 @@ int pa__init(pa_core *c, pa_module*m) { } u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("ALSA PCM on %s (%s)", dev, snd_pcm_info_get_name(pcm_info)); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("ALSA PCM on %s (%s)", dev, snd_pcm_info_get_name(pcm_info))); + pa_xfree(t); u->pcm_fdl = pa_alsa_fdlist_new(); assert(u->pcm_fdl); diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 63369e47..6149224a 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -359,6 +359,7 @@ int pa__init(pa_core *c, pa_module*m) { size_t frame_size; snd_pcm_info_t *pcm_info = NULL; int err; + char *t; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": failed to parse module arguments"); @@ -450,7 +451,8 @@ int pa__init(pa_core *c, pa_module*m) { } } pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("ALSA PCM on %s (%s)", dev, snd_pcm_info_get_name(pcm_info)); + pa_source_set_description(u->source, t = pa_sprintf_malloc("ALSA PCM on %s (%s)", dev, snd_pcm_info_get_name(pcm_info))); + pa_xfree(t); u->pcm_fdl = pa_alsa_fdlist_new(); assert(u->pcm_fdl); diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 4e3dd555..0a5bd472 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -381,7 +381,7 @@ int pa__init(pa_core *c, pa_module*m) { } pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Combined sink"); + pa_sink_set_description(u->sink, "Combined sink"); u->sink->get_latency = sink_get_latency_cb; u->sink->userdata = u; diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index 86ffaf78..9f0c2c5b 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -320,6 +320,8 @@ int pa__init(pa_core *c, pa_module*m) { const char *p; pa_sample_spec ss; pa_modargs *ma = NULL; + char *t; + assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -381,7 +383,8 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->get_latency = get_latency_cb; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Esound sink '%s'", p); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Esound sink '%s'", p)); + pa_xfree(t); u->memchunk.memblock = NULL; u->memchunk.length = 0; diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index c645caa9..286f6f57 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -245,6 +245,7 @@ int pa__init(pa_core *c, pa_module*m) { int do_connect = 1; unsigned i; const char **ports = NULL, **p; + char *t; assert(c); assert(m); @@ -328,7 +329,8 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Jack sink (%s)", jack_get_client_name(u->client)); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Jack sink (%s)", jack_get_client_name(u->client))); + pa_xfree(t); u->sink->get_latency = sink_get_latency_cb; jack_set_process_callback(u->client, jack_process, u); diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index 2a492929..583f3b8e 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -243,6 +243,7 @@ int pa__init(pa_core *c, pa_module*m) { int do_connect = 1; unsigned i; const char **ports = NULL, **p; + char *t; assert(c); assert(m); @@ -326,7 +327,8 @@ int pa__init(pa_core *c, pa_module*m) { u->source->userdata = u; pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Jack source (%s)", jack_get_client_name(u->client)); + pa_source_set_description(u->source, t = pa_sprintf_malloc("Jack source (%s)", jack_get_client_name(u->client))); + pa_xfree(t); u->source->get_latency = source_get_latency_cb; jack_set_process_callback(u->client, jack_process, u); diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index 470be6bc..73cacc72 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -141,7 +141,7 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->get_latency = get_latency; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - u->sink->description = pa_xstrdup("NULL sink"); + pa_sink_set_description(u->sink, "NULL sink"); u->n_bytes = 0; pa_gettimeofday(&u->start_time); diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index 4212febe..cc408f90 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -349,7 +349,7 @@ int pa__init(pa_core *c, pa_module*m) { int enable_bits = 0, zero = 0; int playback = 1, record = 1; pa_modargs *ma = NULL; - char hwdesc[64]; + char hwdesc[64], *t; pa_channel_map map; assert(c); @@ -439,11 +439,12 @@ int pa__init(pa_core *c, pa_module*m) { u->source->get_hw_volume = source_get_hw_volume; u->source->set_hw_volume = source_set_hw_volume; pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("OSS PCM/mmap() on %s%s%s%s", - p, - hwdesc[0] ? " (" : "", - hwdesc[0] ? hwdesc : "", - hwdesc[0] ? ")" : ""); + pa_source_set_description(u->source, t = pa_sprintf_malloc("OSS PCM/mmap() on %s%s%s%s", + p, + hwdesc[0] ? " (" : "", + hwdesc[0] ? hwdesc : "", + hwdesc[0] ? ")" : "")); + pa_xfree(t); u->source->is_hardware = 1; u->in_memblocks = pa_xnew0(pa_memblock*, u->in_fragments); @@ -480,11 +481,12 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->set_hw_volume = sink_set_hw_volume; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("OSS PCM/mmap() on %s%s%s%s", - p, - hwdesc[0] ? " (" : "", - hwdesc[0] ? hwdesc : "", - hwdesc[0] ? ")" : ""); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("OSS PCM/mmap() on %s%s%s%s", + p, + hwdesc[0] ? " (" : "", + hwdesc[0] ? hwdesc : "", + hwdesc[0] ? ")" : "")); + pa_xfree(t); u->sink->is_hardware = 1; u->out_memblocks = pa_xmalloc0(sizeof(struct memblock *)*u->out_fragments); diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index c9fce7a7..085ae5da 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -326,7 +326,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_sample_spec ss; pa_channel_map map; pa_modargs *ma = NULL; - char hwdesc[64]; + char hwdesc[64], *t; assert(c); assert(m); @@ -413,11 +413,12 @@ int pa__init(pa_core *c, pa_module*m) { u->source->get_hw_volume = source_get_hw_volume; u->source->set_hw_volume = source_set_hw_volume; pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("OSS PCM on %s%s%s%s", - p, - hwdesc[0] ? " (" : "", - hwdesc[0] ? hwdesc : "", - hwdesc[0] ? ")" : ""); + pa_source_set_description(u->source, t = pa_sprintf_malloc("OSS PCM on %s%s%s%s", + p, + hwdesc[0] ? " (" : "", + hwdesc[0] ? hwdesc : "", + hwdesc[0] ? ")" : "")); + pa_xfree(t); u->source->is_hardware = 1; } else u->source = NULL; @@ -431,11 +432,12 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->set_hw_volume = sink_set_hw_volume; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("OSS PCM on %s%s%s%s", - p, - hwdesc[0] ? " (" : "", - hwdesc[0] ? hwdesc : "", - hwdesc[0] ? ")" : ""); + pa_sink_set_description(u->sink, pa_sprintf_malloc("OSS PCM on %s%s%s%s", + p, + hwdesc[0] ? " (" : "", + hwdesc[0] ? hwdesc : "", + hwdesc[0] ? ")" : "")); + pa_xfree(t); u->sink->is_hardware = 1; } else u->sink = NULL; diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index 4878a1a1..cc5276d4 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -148,6 +148,8 @@ int pa__init(pa_core *c, pa_module*m) { pa_sample_spec ss; pa_channel_map map; pa_modargs *ma = NULL; + char *t; + assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -194,8 +196,8 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->get_latency = get_latency_cb; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Unix FIFO sink '%s'", p); - assert(u->sink->description); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Unix FIFO sink '%s'", p)); + pa_xfree(t); u->io = pa_iochannel_new(c->mainloop, -1, fd); assert(u->io); diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index f2f214c7..5caa60a3 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -126,6 +126,8 @@ int pa__init(pa_core *c, pa_module*m) { pa_sample_spec ss; pa_channel_map map; pa_modargs *ma = NULL; + char *t; + assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -169,8 +171,8 @@ int pa__init(pa_core *c, pa_module*m) { } u->source->userdata = u; pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Unix FIFO source '%s'", p); - assert(u->source->description); + pa_source_set_description(u->source, t = pa_sprintf_malloc("Unix FIFO source '%s'", p)); + pa_xfree(t); u->io = pa_iochannel_new(c->mainloop, fd, -1); assert(u->io); diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 02ef4bc4..21a72b38 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -500,6 +500,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_channel_map map; pa_modargs *ma = NULL; struct timeval tv; + char *t; assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -554,7 +555,8 @@ int pa__init(pa_core *c, pa_module*m) { u->source->get_hw_volume = source_get_hw_volume_cb; u->source->set_hw_volume = source_set_hw_volume_cb; pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Solaris PCM on '%s'", p); + pa_source_set_description(u->source, t = pa_sprintf_malloc("Solaris PCM on '%s'", p)); + pa_xfree(t); u->source->is_hardware = 1; } else u->source = NULL; @@ -569,7 +571,8 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->set_hw_mute = sink_set_hw_mute_cb; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Solaris PCM on '%s'", p); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Solaris PCM on '%s'", p)); + pa_xfree(t); u->sink->is_hardware = 1; } else u->sink = NULL; diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 2fb34d12..9bb11c09 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -859,6 +859,8 @@ int pa__init(pa_core *c, pa_module*m) { pa_sample_spec ss; pa_channel_map map; struct timeval ntv; + char *t; + assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -925,7 +927,8 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->get_hw_mute = sink_get_hw_mute; u->sink->set_hw_mute = sink_set_hw_mute; u->sink->userdata = u; - u->sink->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->sink_name ? u->sink_name : "", u->sink_name ? "@" : "", u->server_name); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->sink_name ? u->sink_name : "", u->sink_name ? "@" : "", u->server_name)); + pa_xfree(t); pa_sink_set_owner(u->sink, m); #else @@ -940,7 +943,9 @@ int pa__init(pa_core *c, pa_module*m) { u->source->get_hw_mute = source_get_hw_mute; u->source->set_hw_mute = source_set_hw_mute; u->source->userdata = u; - u->source->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->source_name ? u->source_name : "", u->source_name ? "@" : "", u->server_name); + + pa_source_set_description(u->source, t = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->source_name ? u->source_name : "", u->source_name ? "@" : "", u->server_name)); + pa_xfree(t); pa_source_set_owner(u->source, m); #endif diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index 8fd60b6a..27e8de58 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -503,7 +503,7 @@ int pa__init(pa_core *c, pa_module*m) { u->source->notify = notify_source_cb; u->source->get_latency = source_get_latency_cb; pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Windows waveIn PCM"); + pa_source_set_description(u->source, "Windows waveIn PCM"); u->source->is_hardware = 1; } else u->source = NULL; @@ -517,7 +517,7 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->set_hw_volume = sink_set_hw_volume_cb; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Windows waveOut PCM"); + pa_sink_set_description(u->sink, "Windows waveOut PCM"); u->sink->is_hardware = 1; } else u->sink = NULL; diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index 23a188b3..16315d35 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -185,7 +185,8 @@ static int publish_service(struct userdata *u, struct service *s) { txt = avahi_string_list_add_printf(txt, "rate=%u", ss.rate); txt = avahi_string_list_add_printf(txt, "channels=%u", ss.channels); txt = avahi_string_list_add_pair(txt, "format", pa_sample_format_to_string(ss.format)); - txt = avahi_string_list_add_pair(txt, "description", description); + if (description) + txt = avahi_string_list_add_pair(txt, "description", description); type = s->loaded.type; } else if (s->autoload.valid) -- cgit From 8da9b94af667b066b6ab2bb86553bedae330e27b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 00:25:52 +0000 Subject: allow setting the null sink description by a module parameter git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1206 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-null-sink.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index 73cacc72..4d5ebb08 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -53,7 +53,8 @@ PA_MODULE_USAGE( "channels= " "rate= " "sink_name=" - "channel_map=") + "channel_map=" + "description=") #define DEFAULT_SINK_NAME "null" @@ -73,7 +74,8 @@ static const char* const valid_modargs[] = { "format", "channels", "sink_name", - "channel_map", + "channel_map", + "description", NULL }; @@ -141,7 +143,7 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->get_latency = get_latency; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - pa_sink_set_description(u->sink, "NULL sink"); + pa_sink_set_description(u->sink, pa_modargs_get_value(ma, "description", "NULL sink")); u->n_bytes = 0; pa_gettimeofday(&u->start_time); -- cgit From 1e12c75ba1a236bd5a8304c4c6c4aae28e9e6179 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 00:26:17 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1207 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 2 ++ 1 file changed, 2 insertions(+) diff --git a/todo b/todo index 89239db0..c9c9a86e 100644 --- a/todo +++ b/todo @@ -36,6 +36,8 @@ Post 0.9.0: - sasl auth - fix OSS hot-remove - use better sink/source names, generated from the device file names +- subscription: filter out superfluous events +- make sure that everyone knows how to deal with sinks without a monitor source Long term: - pass meta info for hearing impaired -- cgit From bb961569eb562b4c92617098627f8092098955d0 Mon Sep 17 00:00:00 2001 From: "Shahms E. King" Date: Sat, 12 Aug 2006 01:17:19 +0000 Subject: increase module argument buffer size to prevent truncating names git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1208 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-hal-detect.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index 0063fdbd..54d139ec 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -157,7 +157,7 @@ static int hal_device_get_alsa_device(LibHalContext *ctx, const char *udi, static pa_module* hal_device_load_alsa(struct userdata *u, const char *udi, DBusError *error) { - char args[64]; + char args[128]; alsa_type_t type; int device, card; const char *module_name; @@ -218,7 +218,7 @@ exit: static pa_module* hal_device_load_oss(struct userdata *u, const char *udi, DBusError *error) { - char args[128]; + char args[256]; char* device; if (!hal_device_is_oss_pcm(u->ctx, udi, error) || dbus_error_is_set(error)) -- cgit From e9d9356d110945bf9bc8c3ca0e1cb0b1d42a67a1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 02:16:12 +0000 Subject: add new macro PA_LLIST_INSERT_AFTER git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1209 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/llist.h | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/llist.h b/src/pulsecore/llist.h index bf3c150a..9ce24e74 100644 --- a/src/pulsecore/llist.h +++ b/src/pulsecore/llist.h @@ -73,7 +73,24 @@ do { \ assert(_head); \ while ((*_head)->prev) \ *_head = (*_head)->prev; \ -} while (0) \ +} while (0) +#define PA_LLIST_INSERT_AFTER(t,head,a,b) \ +do { \ + t **_head = &(head), *_a = (a), *_b = (b); \ + assert(_b); \ + if (!_a) { \ + if ((_b->next = *_head)) \ + _b->next->prev = _b; \ + _b->prev = NULL; \ + *_head = _b; \ + } else { \ + if ((_b->next = _a->next)) \ + _b->next->prev = _b; \ + _b->prev = _a; \ + _a->next = _b; \ + } \ +} while (0) + #endif -- cgit From f8e5f47e233fc401eec5e2c7fdeab46c7314a6b2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 02:16:47 +0000 Subject: fix a compiler warning git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1210 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/module.c b/src/pulsecore/module.c index 3568059e..cdf95ada 100644 --- a/src/pulsecore/module.c +++ b/src/pulsecore/module.c @@ -223,8 +223,8 @@ static void free_callback(void *p, PA_GCC_UNUSED void *userdata) { } void pa_module_unload_all(pa_core *c) { - assert(c); pa_module *m; + assert(c); if (!c->modules) return; -- cgit From 47d009afd69612aa97fd368fd481734f1c52909a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 02:18:24 +0000 Subject: rework subscription code: try to drop redundant queued events git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1211 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/core-subscribe.c | 207 +++++++++++++++++++++++------------------ src/pulsecore/core-subscribe.h | 4 +- src/pulsecore/core.c | 5 +- src/pulsecore/core.h | 10 +- 4 files changed, 129 insertions(+), 97 deletions(-) diff --git a/src/pulsecore/core-subscribe.c b/src/pulsecore/core-subscribe.c index e865256a..2c625632 100644 --- a/src/pulsecore/core-subscribe.c +++ b/src/pulsecore/core-subscribe.c @@ -43,75 +43,81 @@ struct pa_subscription { pa_core *core; int dead; - void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata); + + pa_subscription_cb_t callback; void *userdata; pa_subscription_mask_t mask; - pa_subscription *prev, *next; + PA_LLIST_FIELDS(pa_subscription); }; struct pa_subscription_event { + pa_core *core; + pa_subscription_event_type_t type; uint32_t index; + + PA_LLIST_FIELDS(pa_subscription_event); }; static void sched_event(pa_core *c); /* Allocate a new subscription object for the given subscription mask. Use the specified callback function and user data */ -pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata) { +pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, pa_subscription_cb_t callback, void *userdata) { pa_subscription *s; + assert(c); + assert(m); + assert(callback); - s = pa_xmalloc(sizeof(pa_subscription)); + s = pa_xnew(pa_subscription, 1); s->core = c; s->dead = 0; s->callback = callback; s->userdata = userdata; s->mask = m; - if ((s->next = c->subscriptions)) - s->next->prev = s; - s->prev = NULL; - c->subscriptions = s; + PA_LLIST_PREPEND(pa_subscription, c->subscriptions, s); return s; } /* Free a subscription object, effectively marking it for deletion */ void pa_subscription_free(pa_subscription*s) { - assert(s && !s->dead); + assert(s); + assert(!s->dead); + s->dead = 1; sched_event(s->core); } -static void free_item(pa_subscription *s) { - assert(s && s->core); +static void free_subscription(pa_subscription *s) { + assert(s); + assert(s->core); - if (s->prev) - s->prev->next = s->next; - else - s->core->subscriptions = s->next; - - if (s->next) - s->next->prev = s->prev; + PA_LLIST_REMOVE(pa_subscription, s->core->subscriptions, s); + pa_xfree(s); +} + +static void free_event(pa_subscription_event *s) { + assert(s); + assert(s->core); + + if (!s->next) + s->core->subscription_event_last = s->prev; + PA_LLIST_REMOVE(pa_subscription_event, s->core->subscription_event_queue, s); pa_xfree(s); } /* Free all subscription objects */ void pa_subscription_free_all(pa_core *c) { - pa_subscription_event *e; assert(c); while (c->subscriptions) - free_item(c->subscriptions); + free_subscription(c->subscriptions); - if (c->subscription_event_queue) { - while ((e = pa_queue_pop(c->subscription_event_queue))) - pa_xfree(e); - - pa_queue_free(c->subscription_event_queue, NULL, NULL); - c->subscription_event_queue = NULL; - } + while (c->subscription_event_queue) + free_event(c->subscription_event_queue); if (c->subscription_defer_event) { c->mainloop->defer_free(c->subscription_defer_event); @@ -119,48 +125,31 @@ void pa_subscription_free_all(pa_core *c) { } } -#if 0 -static void dump_event(pa_subscription_event*e) { - switch (e->type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { - case PA_SUBSCRIPTION_EVENT_SINK: - pa_log(__FILE__": SINK_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_SOURCE: - pa_log(__FILE__": SOURCE_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_SINK_INPUT: - pa_log(__FILE__": SINK_INPUT_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: - pa_log(__FILE__": SOURCE_OUTPUT_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_MODULE: - pa_log(__FILE__": MODULE_EVENT"); - break; - case PA_SUBSCRIPTION_EVENT_CLIENT: - pa_log(__FILE__": CLIENT_EVENT"); - break; - default: - pa_log(__FILE__": OTHER"); - break; - } - - switch (e->type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) { - case PA_SUBSCRIPTION_EVENT_NEW: - pa_log(__FILE__": NEW"); - break; - case PA_SUBSCRIPTION_EVENT_CHANGE: - pa_log(__FILE__": CHANGE"); - break; - case PA_SUBSCRIPTION_EVENT_REMOVE: - pa_log(__FILE__": REMOVE"); - break; - default: - pa_log(__FILE__": OTHER"); - break; - } - - pa_log(__FILE__": %u", e->index); +#ifdef DEBUG +static void dump_event(const char * prefix, pa_subscription_event*e) { + const char * const fac_table[] = { + [PA_SUBSCRIPTION_EVENT_SINK] = "SINK", + [PA_SUBSCRIPTION_EVENT_SOURCE] = "SOURCE", + [PA_SUBSCRIPTION_EVENT_SINK_INPUT] = "SINK_INPUT", + [PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT] = "SOURCE_OUTPUT", + [PA_SUBSCRIPTION_EVENT_MODULE] = "MODULE", + [PA_SUBSCRIPTION_EVENT_CLIENT] = "CLIENT", + [PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE] = "SAMPLE_CACHE", + [PA_SUBSCRIPTION_EVENT_SERVER] = "SERVER", + [PA_SUBSCRIPTION_EVENT_AUTOLOAD] = "AUTOLOAD" + }; + + const char * const type_table[] = { + [PA_SUBSCRIPTION_EVENT_NEW] = "NEW", + [PA_SUBSCRIPTION_EVENT_CHANGE] = "CHANGE", + [PA_SUBSCRIPTION_EVENT_REMOVE] = "REMOVE" + }; + + pa_log(__FILE__": %s event (%s|%s|%u)", + prefix, + fac_table[e->type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK], + type_table[e->type & PA_SUBSCRIPTION_EVENT_TYPE_MASK], + e->index); } #endif @@ -168,25 +157,28 @@ static void dump_event(pa_subscription_event*e) { static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) { pa_core *c = userdata; pa_subscription *s; - assert(c && c->subscription_defer_event == de && c->mainloop == m); + + assert(c->mainloop == m); + assert(c); + assert(c->subscription_defer_event == de); c->mainloop->defer_enable(c->subscription_defer_event, 0); /* Dispatch queued events */ - - if (c->subscription_event_queue) { - pa_subscription_event *e; - - while ((e = pa_queue_pop(c->subscription_event_queue))) { - for (s = c->subscriptions; s; s = s->next) { + while (c->subscription_event_queue) { + pa_subscription_event *e = c->subscription_event_queue; - if (!s->dead && pa_subscription_match_flags(s->mask, e->type)) - s->callback(c, e->type, e->index, s->userdata); - } + for (s = c->subscriptions; s; s = s->next) { - pa_xfree(e); + if (!s->dead && pa_subscription_match_flags(s->mask, e->type)) + s->callback(c, e->type, e->index, s->userdata); } + +#ifdef DEBUG + dump_event("Dispatched", e); +#endif + free_event(e); } /* Remove dead subscriptions */ @@ -195,7 +187,7 @@ static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) { while (s) { pa_subscription *n = s->next; if (s->dead) - free_item(s); + free_subscription(s); s = n; } } @@ -217,17 +209,52 @@ void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t i pa_subscription_event *e; assert(c); - e = pa_xmalloc(sizeof(pa_subscription_event)); + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_NEW) { + pa_subscription_event *i, *n; + + /* Check for duplicates */ + for (i = c->subscription_event_last; i; i = n) { + n = i->prev; + + /* not the same object type */ + if (((t ^ i->type) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)) + continue; + + /* not the same object */ + if (i->index != index) + continue; + + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { + /* This object is being removed, hence there is no + * point in keeping the old events regarding this + * entry in the queue. */ + + free_event(i); + pa_log_debug(__FILE__": dropped redundant event."); + continue; + } + + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_CHANGE) { + /* This object has changed. If a "new" or "change" event for + * this object is still in the queue we can exit. */ + + pa_log_debug(__FILE__": dropped redundant event."); + return; + } + } + } + + e = pa_xnew(pa_subscription_event, 1); + e->core = c; e->type = t; e->index = index; - if (!c->subscription_event_queue) { - c->subscription_event_queue = pa_queue_new(); - assert(c->subscription_event_queue); - } - - pa_queue_push(c->subscription_event_queue, e); - sched_event(c); -} + PA_LLIST_INSERT_AFTER(pa_subscription_event, c->subscription_event_queue, c->subscription_event_last, e); + c->subscription_event_last = e; +#ifdef DEBUG + dump_event("Queued", e); +#endif + sched_event(c); +} diff --git a/src/pulsecore/core-subscribe.h b/src/pulsecore/core-subscribe.h index c2467033..6e3b646e 100644 --- a/src/pulsecore/core-subscribe.h +++ b/src/pulsecore/core-subscribe.h @@ -28,7 +28,9 @@ typedef struct pa_subscription_event pa_subscription_event; #include #include -pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata); +typedef void (*pa_subscription_cb_t)(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata); + +pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, pa_subscription_cb_t cb, void *userdata); void pa_subscription_free(pa_subscription*s); void pa_subscription_free_all(pa_core *c); diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index d6af3ca9..710e00ad 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -74,8 +74,9 @@ pa_core* pa_core_new(pa_mainloop_api *m) { c->scache_auto_unload_event = NULL; c->subscription_defer_event = NULL; - c->subscription_event_queue = NULL; - c->subscriptions = NULL; + PA_LLIST_HEAD_INIT(pa_subscription, c->subscriptions); + PA_LLIST_HEAD_INIT(pa_subscription_event, c->subscription_event_queue); + c->subscription_event_last = NULL; c->memblock_stat = pa_memblock_stat_new(); diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index 61f17432..391ba9b8 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -24,14 +24,15 @@ typedef struct pa_core pa_core; -#include -#include #include #include +#include +#include #include #include #include #include +#include /* The core structure of PulseAudio. Every PulseAudio daemon contains * exactly one of these. It is used for storing kind of global @@ -58,8 +59,9 @@ struct pa_core { pa_defer_event *module_defer_unload_event; pa_defer_event *subscription_defer_event; - pa_queue *subscription_event_queue; - pa_subscription *subscriptions; + PA_LLIST_HEAD(pa_subscription, subscriptions); + PA_LLIST_HEAD(pa_subscription_event, subscription_event_queue); + pa_subscription_event *subscription_event_last; pa_memblock_stat *memblock_stat; -- cgit From 3aba099fc3e515db5c4b1f2990c48fdb4160ff52 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 02:19:36 +0000 Subject: clean up event generation a little: suppress unnecessary events and generate new ones on owner change git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1212 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/sink-input.c | 6 ++++++ src/pulsecore/sink.c | 7 ++++++- src/pulsecore/source-output.c | 6 ++++++ src/pulsecore/source.c | 4 ++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index b89210f4..701d7f6c 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -437,6 +437,12 @@ void pa_sink_input_set_name(pa_sink_input *i, const char *name) { assert(i); assert(i->ref >= 1); + if (!i->name && !name) + return; + + if (i->name && name && !strcmp(i->name, name)) + return; + pa_xfree(i->name); i->name = pa_xstrdup(name); diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index eecf89cc..d1d9785a 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -446,11 +446,16 @@ pa_usec_t pa_sink_get_latency(pa_sink *s) { void pa_sink_set_owner(pa_sink *s, pa_module *m) { assert(s); assert(s->ref >= 1); - + + if (s->owner == m) + return; + s->owner = m; if (s->monitor_source) pa_source_set_owner(s->monitor_source, m); + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } void pa_sink_set_volume(pa_sink *s, pa_mixer_t m, const pa_cvolume *volume) { diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 1ffaedae..36ea420c 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -208,6 +208,12 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { void pa_source_output_set_name(pa_source_output *o, const char *name) { assert(o); assert(o->ref >= 1); + + if (!o->name && !name) + return; + + if (o->name && name && !strcmp(o->name, name)) + return; pa_xfree(o->name); o->name = pa_xstrdup(name); diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index f9c0703d..903de88b 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -225,8 +225,12 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) { void pa_source_set_owner(pa_source *s, pa_module *m) { assert(s); assert(s->ref >= 1); + + if (m == s->owner) + return; s->owner = m; + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } pa_usec_t pa_source_get_latency(pa_source *s) { -- cgit From 365ceec6d61524b157b95e5b0cca11080f63ab49 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 02:20:05 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1213 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 - 1 file changed, 1 deletion(-) diff --git a/todo b/todo index c9c9a86e..c5ad29f8 100644 --- a/todo +++ b/todo @@ -36,7 +36,6 @@ Post 0.9.0: - sasl auth - fix OSS hot-remove - use better sink/source names, generated from the device file names -- subscription: filter out superfluous events - make sure that everyone knows how to deal with sinks without a monitor source Long term: -- cgit From adfa76c43388c6b6895ea7cdd3c307c90933cd91 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 12:03:30 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1214 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/todo b/todo index c5ad29f8..2029ce6b 100644 --- a/todo +++ b/todo @@ -35,8 +35,8 @@ Post 0.9.0: - challenge response auth - sasl auth - fix OSS hot-remove -- use better sink/source names, generated from the device file names - make sure that everyone knows how to deal with sinks without a monitor source +- allow passing data with shared memory between local clients and the server Long term: - pass meta info for hearing impaired -- cgit From 2d702715f7f1b2158a50d5c838b0bad0487b42fd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 12:07:22 +0000 Subject: fix pa_gettimeofday() return value testing git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1215 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/dbus-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/dbus-util.c b/src/modules/dbus-util.c index c9cdf114..e4bd2c3e 100644 --- a/src/modules/dbus-util.c +++ b/src/modules/dbus-util.c @@ -175,7 +175,7 @@ static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) if (!dbus_timeout_get_enabled(timeout)) return FALSE; - if (pa_gettimeofday(&tv) < 0) + if (!pa_gettimeofday(&tv)) return -1; pa_timeval_add(&tv, dbus_timeout_get_interval(timeout) * 1000); -- cgit From 7fa074480687dff06723b7078c8146aae5eec61a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 13:17:33 +0000 Subject: fix a segfault in module-oss git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1216 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 085ae5da..5ce74151 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -432,7 +432,7 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->set_hw_volume = sink_set_hw_volume; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - pa_sink_set_description(u->sink, pa_sprintf_malloc("OSS PCM on %s%s%s%s", + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("OSS PCM on %s%s%s%s", p, hwdesc[0] ? " (" : "", hwdesc[0] ? hwdesc : "", -- cgit From c86890d5e794aa5b4b3e39796c705b5922877dfe Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 13:18:34 +0000 Subject: * only load an OSS driver for the first device of a sound card, similar to what is done for ALSA. * fix a mem leak git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1217 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-hal-detect.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index 54d139ec..825fa96c 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -192,26 +192,33 @@ static dbus_bool_t hal_device_is_oss_pcm(LibHalContext *ctx, const char *udi, DBusError *error) { dbus_bool_t rv = FALSE; - char* device; - char* type; + char* type, *device_file = NULL; + int device; type = libhal_device_get_property_string(ctx, udi, "oss.type", error); if (!type || dbus_error_is_set(error)) return FALSE; - + if (!strcmp(type, "pcm")) { - device = libhal_device_get_property_string(ctx, udi, "oss.device_file", + char *e; + + device = libhal_device_get_property_int(ctx, udi, "oss.device", error); + if (dbus_error_is_set(error) || device != 0) + goto exit; + + device_file = libhal_device_get_property_string(ctx, udi, "oss.device_file", error); - if (!device || dbus_error_is_set(error)) + if (!device_file || dbus_error_is_set(error)) goto exit; /* hack to ignore /dev/audio style devices */ - if ((device = strrchr(device, '/'))) - rv = (pa_startswith(device + 1, "audio")) ? FALSE : TRUE; + if ((e = strrchr(device_file, '/'))) + rv = !pa_startswith(e + 1, "audio"); } exit: libhal_free_string(type); + libhal_free_string(device_file); return rv; } -- cgit From 0547b0fd4a9a8df1f7c6836a6e1e04697769d4b8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 15:08:53 +0000 Subject: there's no need to queue subscription events if noone is listening, hence don't do it! git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1218 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/core-subscribe.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pulsecore/core-subscribe.c b/src/pulsecore/core-subscribe.c index 2c625632..37673da5 100644 --- a/src/pulsecore/core-subscribe.c +++ b/src/pulsecore/core-subscribe.c @@ -209,6 +209,10 @@ void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t i pa_subscription_event *e; assert(c); + /* No need for queuing subscriptions of noone is listening */ + if (!c->subscriptions) + return; + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_NEW) { pa_subscription_event *i, *n; -- cgit From fbeeb8b70d754cf16af87330f3a5fe748a27078f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 15:09:49 +0000 Subject: when the requested sample format is not available for OSS devices, print a nice warning and take what we can get instead git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1219 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/oss-util.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index f4cc45de..feb1aadf 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -98,6 +98,8 @@ fail: int pa_oss_auto_format(int fd, pa_sample_spec *ss) { int format, channels, speed, reqformat; + pa_sample_format_t orig_format; + static const int format_trans[PA_SAMPLE_MAX] = { [PA_SAMPLE_U8] = AFMT_U8, [PA_SAMPLE_ALAW] = AFMT_A_LAW, @@ -110,6 +112,8 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss) { assert(fd >= 0 && ss); + orig_format = ss->format; + reqformat = format = format_trans[ss->format]; if (reqformat == AFMT_QUERY || ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != reqformat) { format = AFMT_S16_NE; @@ -128,22 +132,38 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss) { } else ss->format = PA_SAMPLE_S16NE; } - + + if (orig_format != ss->format) + pa_log_warn(__FILE__": device doesn't support sample format %s, changed to %s.", + pa_sample_format_to_string(orig_format), + pa_sample_format_to_string(ss->format)); + channels = ss->channels; if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) { pa_log(__FILE__": SNDCTL_DSP_CHANNELS: %s", pa_cstrerror(errno)); return -1; } - assert(channels); - ss->channels = channels; + assert(channels > 0); + + if (ss->channels != channels) { + pa_log_warn(__FILE__": device doesn't support %i channels, using %i channels.", ss->channels, channels); + ss->channels = channels; + } speed = ss->rate; if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) { pa_log(__FILE__": SNDCTL_DSP_SPEED: %s", pa_cstrerror(errno)); return -1; } - assert(speed); - ss->rate = speed; + assert(speed > 0); + + if (ss->rate != (unsigned) speed) { + pa_log_warn(__FILE__": device doesn't support %i Hz, changed to %i Hz.", ss->rate, speed); + + /* If the sample rate deviates too much, we need to resample */ + if (speed < ss->rate*.95 || speed > ss->rate*1.05) + ss->rate = speed; + } return 0; } -- cgit From 3cfed301d91ebf773ace89a02fea6db817426221 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 16:01:40 +0000 Subject: print the device capabilities after opening the device git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1220 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/oss-util.c | 55 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index feb1aadf..177322be 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -42,8 +42,13 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { int fd = -1; + int caps; + assert(device && mode && (*mode == O_RDWR || *mode == O_RDONLY || *mode == O_WRONLY)); + if(!pcaps) + pcaps = ∩︀ + if (*mode == O_RDWR) { if ((fd = open(device, O_RDWR|O_NDELAY)) >= 0) { int dcaps, *tcaps; @@ -79,12 +84,52 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { success: - if (pcaps) { - if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s", pa_cstrerror(errno)); - goto fail; - } + *pcaps = 0; + + if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { + pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s", pa_cstrerror(errno)); + goto fail; } + + pa_log_debug(__FILE__": capabilities:%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + *pcaps & DSP_CAP_BATCH ? " BATCH" : "", + *pcaps & DSP_CAP_BIND ? " BIND" : "", + *pcaps & DSP_CAP_COPROC ? " COPROC" : "", + *pcaps & DSP_CAP_DUPLEX ? " DUPLEX" : "", +#ifdef DSP_CAP_FREERATE + *pcaps & DSP_CAP_FREERATE ? " FREERATE" : "", +#else + "", +#endif +#ifdef DSP_CAP_INPUT + *pcaps & DSP_CAP_INPUT ? " INPUT" : "", +#else + "", +#endif + *pcaps & DSP_CAP_MMAP ? " MMAP" : "", +#ifdef DSP_CAP_MODEM + *pcaps & DSP_CAP_MODEM ? " MODEM" : "", +#else + "", +#endif + *pcaps & DSP_CAP_MULTI ? " MULTI" : "", +#ifdef DSP_CAP_OUTPUT + *pcaps & DSP_CAP_OUTPUT ? " OUTPUT" : "", +#else + "", +#endif + *pcaps & DSP_CAP_REALTIME ? " REALTIME" : "", +#ifdef DSP_CAP_SHADOW + *pcaps & DSP_CAP_SHADOW ? " SHADOW" : "", +#else + "", +#endif +#ifdef DSP_CAP_VIRTUAL + *pcaps & DSP_CAP_VIRTUAL ? " VIRTUAL" : "", +#else + "", +#endif + *pcaps & DSP_CAP_TRIGGER ? " TRIGGER" : ""); pa_fd_set_cloexec(fd, 1); -- cgit From 4c9c4269bb70aad6c7a62ed7f73867087f4af217 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 16:02:26 +0000 Subject: handle hot-remeving of OSS devices properly git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1221 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss-mmap.c | 74 +++++++++++++++++++++++++++++-------------- src/modules/module-oss.c | 42 +++++++++++++++++------- 2 files changed, 81 insertions(+), 35 deletions(-) diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index cc408f90..08cf1a8d 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -117,6 +117,42 @@ static void update_usage(struct userdata *u) { (u->source ? pa_idxset_size(u->source->outputs) : 0)); } +static void clear_up(struct userdata *u) { + assert(u); + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + u->sink = NULL; + } + + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + u->source = NULL; + } + + if (u->in_mmap && u->in_mmap != MAP_FAILED) { + munmap(u->in_mmap, u->in_mmap_length); + u->in_mmap = NULL; + } + + if (u->out_mmap && u->out_mmap != MAP_FAILED) { + munmap(u->out_mmap, u->out_mmap_length); + u->out_mmap = NULL; + } + + if (u->io_event) { + u->core->mainloop->io_free(u->io_event); + u->io_event = NULL; + } + + if (u->fd >= 0) { + close(u->fd); + u->fd = -1; + } +} + static void out_fill_memblocks(struct userdata *u, unsigned n) { assert(u && u->out_memblocks); @@ -154,6 +190,9 @@ static void do_write(struct userdata *u) { if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { pa_log(__FILE__": SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno)); + + clear_up(u); + pa_module_unload_request(u->module); return; } @@ -217,6 +256,9 @@ static void do_read(struct userdata *u) { if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { pa_log(__FILE__": SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno)); + + clear_up(u); + pa_module_unload_request(u->module); return; } @@ -234,6 +276,12 @@ static void io_callback(pa_mainloop_api *m, pa_io_event *e, PA_GCC_UNUSED int fd struct userdata *u = userdata; assert (u && u->core->mainloop == m && u->io_event == e); + if (f & PA_IO_EVENT_ERROR) { + clear_up(u); + pa_module_unload_request(u->module); + return; + } + if (f & PA_IO_EVENT_INPUT) do_read(u); if (f & PA_IO_EVENT_OUTPUT) @@ -393,7 +441,7 @@ int pa__init(pa_core *c, pa_module*m) { if ((u->fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0) goto fail; - if (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_REALTIME) || !(caps & DSP_CAP_TRIGGER)) { + if (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_TRIGGER)) { pa_log(__FILE__": OSS device not mmap capable."); goto fail; } @@ -539,6 +587,8 @@ void pa__done(pa_core *c, pa_module*m) { if (!(u = m->userdata)) return; + clear_up(u); + if (u->out_memblocks) { unsigned i; for (i = 0; i < u->out_fragments; i++) @@ -555,27 +605,5 @@ void pa__done(pa_core *c, pa_module*m) { pa_xfree(u->in_memblocks); } - if (u->in_mmap && u->in_mmap != MAP_FAILED) - munmap(u->in_mmap, u->in_mmap_length); - - if (u->out_mmap && u->out_mmap != MAP_FAILED) - munmap(u->out_mmap, u->out_mmap_length); - - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - } - - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - } - - if (u->io_event) - u->core->mainloop->io_free(u->io_event); - - if (u->fd >= 0) - close(u->fd); - pa_xfree(u); } diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 5ce74151..c3972680 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -107,6 +107,27 @@ static void update_usage(struct userdata *u) { (u->source ? pa_idxset_size(u->source->outputs) : 0)); } +static void clear_up(struct userdata *u) { + assert(u); + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + u->sink = NULL; + } + + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + u->source = NULL; + } + + if (u->io) { + pa_iochannel_free(u->io); + u->io = NULL; + } +} + static void do_write(struct userdata *u) { pa_memchunk *memchunk; ssize_t r; @@ -148,6 +169,9 @@ static void do_write(struct userdata *u) { if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { pa_log(__FILE__": write() failed: %s", pa_cstrerror(errno)); + + clear_up(u); + pa_module_unload_request(u->module); break; } @@ -199,8 +223,11 @@ static void do_read(struct userdata *u) { assert(memchunk.memblock); if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); - if (errno != EAGAIN) + if (errno != EAGAIN) { pa_log(__FILE__": read() failed: %s", pa_cstrerror(errno)); + clear_up(u); + pa_module_unload_request(u->module); + } break; } @@ -501,22 +528,13 @@ void pa__done(pa_core *c, pa_module*m) { if (!(u = m->userdata)) return; + + clear_up(u); if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); if (u->silence.memblock) pa_memblock_unref(u->silence.memblock); - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - } - - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - } - - pa_iochannel_free(u->io); pa_xfree(u); } -- cgit From 005017647b4d883fd4d3fe376f3373f71b5f7b53 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 16:02:52 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1222 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 - 1 file changed, 1 deletion(-) diff --git a/todo b/todo index 2029ce6b..568ff30a 100644 --- a/todo +++ b/todo @@ -34,7 +34,6 @@ Post 0.9.0: - key rings for auth - challenge response auth - sasl auth -- fix OSS hot-remove - make sure that everyone knows how to deal with sinks without a monitor source - allow passing data with shared memory between local clients and the server -- cgit From bf79e9759112abfa7be5d01de807b24a68038d26 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 16:26:59 +0000 Subject: generate default sink/source names from the device files they belong to git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1223 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-sink.c | 16 ++++++++++++++-- src/modules/module-alsa-source.c | 17 ++++++++++++++--- src/modules/module-oss.c | 32 ++++++++++++++++++++++++++++---- 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index efecfc21..e14cc5c8 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -87,7 +87,6 @@ static const char* const valid_modargs[] = { NULL }; -#define DEFAULT_SINK_NAME "alsa_output" #define DEFAULT_DEVICE "default" static void update_usage(struct userdata *u) { @@ -367,6 +366,9 @@ int pa__init(pa_core *c, pa_module*m) { snd_pcm_info_t *pcm_info = NULL; int err; char *t; + const char *name; + char *name_buf = NULL; + int namereg_fail; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": failed to parse module arguments"); @@ -427,7 +429,14 @@ int pa__init(pa_core *c, pa_module*m) { u->mixer_handle = NULL; } - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { + if ((name = pa_modargs_get_value(ma, "sink_name", NULL))) + namereg_fail = 1; + else { + name = name_buf = pa_sprintf_malloc("alsa_output.%s", dev); + namereg_fail = 0; + } + + if (!(u->sink = pa_sink_new(c, __FILE__, name, namereg_fail, &ss, &map))) { pa_log(__FILE__": Failed to create sink object"); goto fail; } @@ -502,6 +511,9 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->get_hw_mute(u->sink); finish: + + pa_xfree(name_buf); + if (ma) pa_modargs_free(ma); diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 6149224a..b4ef09d9 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -88,7 +88,6 @@ static const char* const valid_modargs[] = { NULL }; -#define DEFAULT_SOURCE_NAME "alsa_input" #define DEFAULT_DEVICE "default" static void update_usage(struct userdata *u) { @@ -360,6 +359,9 @@ int pa__init(pa_core *c, pa_module*m) { snd_pcm_info_t *pcm_info = NULL; int err; char *t; + const char *name; + char *name_buf = NULL; + int namereg_fail; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": failed to parse module arguments"); @@ -420,7 +422,14 @@ int pa__init(pa_core *c, pa_module*m) { u->mixer_handle = NULL; } - if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) { + if ((name = pa_modargs_get_value(ma, "source_name", NULL))) + namereg_fail = 1; + else { + name = name_buf = pa_sprintf_malloc("alsa_input.%s", dev); + namereg_fail = 0; + } + + if (!(u->source = pa_source_new(c, __FILE__, name, namereg_fail, &ss, &map))) { pa_log(__FILE__": Failed to create source object"); goto fail; } @@ -492,7 +501,9 @@ int pa__init(pa_core *c, pa_module*m) { u->source->get_hw_mute(u->source); finish: - if (ma) + pa_xfree(name_buf); + + if (ma) pa_modargs_free(ma); if (pcm_info) diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index c3972680..89a8152b 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -36,6 +36,7 @@ #include #include +#include #include #include @@ -96,8 +97,6 @@ static const char* const valid_modargs[] = { NULL }; -#define DEFAULT_SINK_NAME "oss_output" -#define DEFAULT_SOURCE_NAME "oss_input" #define DEFAULT_DEVICE "/dev/dsp" static void update_usage(struct userdata *u) { @@ -354,6 +353,9 @@ int pa__init(pa_core *c, pa_module*m) { pa_channel_map map; pa_modargs *ma = NULL; char hwdesc[64], *t; + const char *name; + char *name_buf = NULL; + int namereg_fail; assert(c); assert(m); @@ -431,7 +433,14 @@ int pa__init(pa_core *c, pa_module*m) { } if (mode != O_WRONLY) { - if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) + if ((name = pa_modargs_get_value(ma, "source_name", NULL))) + namereg_fail = 1; + else { + name = name_buf = pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(p)); + namereg_fail = 0; + } + + if (!(u->source = pa_source_new(c, __FILE__, name, namereg_fail, &ss, &map))) goto fail; u->source->userdata = u; @@ -450,8 +459,18 @@ int pa__init(pa_core *c, pa_module*m) { } else u->source = NULL; + pa_xfree(name_buf); + name_buf = NULL; + if (mode != O_RDONLY) { - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) + if ((name = pa_modargs_get_value(ma, "sink_name", NULL))) + namereg_fail = 1; + else { + name = name_buf = pa_sprintf_malloc("oss_output.%s", pa_path_get_filename(p)); + namereg_fail = 0; + } + + if (!(u->sink = pa_sink_new(c, __FILE__, name, namereg_fail, &ss, &map))) goto fail; u->sink->get_latency = sink_get_latency_cb; @@ -469,6 +488,9 @@ int pa__init(pa_core *c, pa_module*m) { } else u->sink = NULL; + pa_xfree(name_buf); + name_buf = NULL; + assert(u->source || u->sink); u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : -1); @@ -516,6 +538,8 @@ fail: if (ma) pa_modargs_free(ma); + + pa_xfree(name_buf); return -1; } -- cgit From 28f86ea698c12218383e302236cd687a20987bec Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 16:33:31 +0000 Subject: name the sink/source after the device file, just like we already do for the non-mmaped driver git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1224 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss-mmap.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index 08cf1a8d..21a23d75 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -104,8 +105,6 @@ static const char* const valid_modargs[] = { NULL }; -#define DEFAULT_SINK_NAME "oss_output" -#define DEFAULT_SOURCE_NAME "oss_input" #define DEFAULT_DEVICE "/dev/dsp" #define DEFAULT_NFRAGS 12 #define DEFAULT_FRAGSIZE 1024 @@ -399,6 +398,9 @@ int pa__init(pa_core *c, pa_module*m) { pa_modargs *ma = NULL; char hwdesc[64], *t; pa_channel_map map; + const char *name; + char *name_buf = NULL; + int namereg_fail; assert(c); assert(m); @@ -478,8 +480,14 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } } else { - - if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec, &map))) + if ((name = pa_modargs_get_value(ma, "source_name", NULL))) + namereg_fail = 1; + else { + name = name_buf = pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(p)); + namereg_fail = 0; + } + + if (!(u->source = pa_source_new(c, __FILE__, name, namereg_fail, &u->sample_spec, &map))) goto fail; u->source->userdata = u; @@ -501,6 +509,9 @@ int pa__init(pa_core *c, pa_module*m) { } } + pa_xfree(name_buf); + name_buf = NULL; + if (mode != O_RDONLY) { if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { pa_log(__FILE__": SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno)); @@ -520,8 +531,15 @@ int pa__init(pa_core *c, pa_module*m) { } } else { pa_silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec); + + if ((name = pa_modargs_get_value(ma, "sink_name", NULL))) + namereg_fail = 1; + else { + name = name_buf = pa_sprintf_malloc("oss_output.%s", pa_path_get_filename(p)); + namereg_fail = 0; + } - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec, &map))) + if (!(u->sink = pa_sink_new(c, __FILE__, name, namereg_fail, &u->sample_spec, &map))) goto fail; u->sink->get_latency = sink_get_latency_cb; @@ -543,6 +561,9 @@ int pa__init(pa_core *c, pa_module*m) { } } + pa_xfree(name_buf); + name_buf = NULL; + zero = 0; if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero) < 0) { pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno)); @@ -574,6 +595,8 @@ fail: if (ma) pa_modargs_free(ma); + + pa_xfree(name_buf); return -1; } -- cgit From b45c39269fe3f59694056b2ae6bae2ac9eada9dc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 16:40:59 +0000 Subject: categorize todo file git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1225 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 55 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/todo b/todo index 568ff30a..f386e94a 100644 --- a/todo +++ b/todo @@ -1,41 +1,50 @@ *** $Id$ *** -Post 0.9.0: -- alsa mmap driver -- alsa driver with hw mixing -- merge module-oss-mmap into module-oss -- chroot() -- module-tunnel: improve latency calculation -- multiline configuration statements -- use scatter/gather io for sockets -- rtp module ported to Win32 (sendmsg/recvmsg emulation) -- CODECs to reduce bandwidth usage (plug-in based) +Build System: - Remove symdef files and use macros (like most other projects) - Use own name mangling scheme instead of ltdl's, which will eliminate the need for .la files or extra trickery. -- use software volume when hardware doesn't support all channels (alsa done) -- paplay needs to set a channel map. our default is only correct for AIFF. - (we need help from libsndfile for this) -- silence generation should be moved into the core to avoid races and code - duplication in the backends -- examine if it is possible to mimic esd's handling of half duplex cards - (switch to capture when a recording client connects and drop playback during - that time) -- Fix a way for the threading API to handle state and subscription callbacks - in a nice way. + +Porting: +- rtp module ported to Win32 (sendmsg/recvmsg emulation) + +I18N: - iconv stuff sent from utils to server (UTF-8) - iconv sample loading in server - Document utf8.h, timeval.h and util.h - gettextify polypaudio + +Cleanups: - drop dependency of libpolyp on libX11, instead use an external mini binary -- hooks for creating sink inputs -- insert the low-level device name in the default sink/source name, to make them recognizable +- merge module-oss-mmap into module-oss +- module-tunnel: improve latency calculation +- use software volume when hardware doesn't support all channels (alsa done) +- silence generation should be moved into the core to avoid races and code + duplication in the backends +- make sure that everyone knows how to deal with sinks without a monitor source + +Auth/Crypto: - ssl - key rings for auth - challenge response auth - sasl auth -- make sure that everyone knows how to deal with sinks without a monitor source + +Features: +- alsa mmap driver +- alsa driver with hw mixing - allow passing data with shared memory between local clients and the server +- hooks for creating sink inputs/window manager for sound +- chroot() +- use scatter/gather io for sockets +- CODECs to reduce bandwidth usage (plug-in based) +- multiline configuration statements +- paplay needs to set a channel map. our default is only correct for AIFF. + (we need help from libsndfile for this) +- Fix a way for the threading API to handle state and subscription callbacks + in a nice way. +- examine if it is possible to mimic esd's handling of half duplex cards + (switch to capture when a recording client connects and drop playback during + that time) Long term: - pass meta info for hearing impaired -- cgit From b5207fc9cac954d49132ff4e6760a60e4e6f2b51 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 16:50:58 +0000 Subject: add pa_sink_used_by()/pa_source_used_by() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1226 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/sink.c | 14 ++++++++++++++ src/pulsecore/sink.h | 2 ++ src/pulsecore/source.c | 7 +++++++ src/pulsecore/source.h | 2 +- 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index d1d9785a..e770950c 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -556,3 +556,17 @@ void pa_sink_set_description(pa_sink *s, const char *description) { pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } + +unsigned pa_sink_used_by(pa_sink *s) { + unsigned ret; + + assert(s); + assert(s->ref >= 1); + + ret = pa_idxset_size(s->inputs); + + if (s->monitor_source) + ret += pa_source_used_by(s->monitor_source); + + return ret; +} diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index fb0912ca..1d870620 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -103,4 +103,6 @@ int pa_sink_get_mute(pa_sink *sink, pa_mixer_t m); void pa_sink_set_description(pa_sink *s, const char *description); +unsigned pa_sink_used_by(pa_sink *s); + #endif diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 903de88b..ae72f040 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -333,3 +333,10 @@ void pa_source_set_description(pa_source *s, const char *description) { pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } + +unsigned pa_source_used_by(pa_source *s) { + assert(s); + assert(s->ref >= 1); + + return pa_idxset_size(s->outputs); +} diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index be0c969d..4dbe4e01 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -104,5 +104,5 @@ int pa_source_get_mute(pa_source *source, pa_mixer_t m); void pa_source_set_description(pa_source *s, const char *description); - +unsigned pa_source_used_by(pa_source *s); #endif -- cgit From dbe6bdd2bcd035b0b07d70811593be719c5cc7c0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 17:06:05 +0000 Subject: make use of pa_sink_used_by()/pa_source_used_by() wherever applicable git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1227 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-sink.c | 4 +--- src/modules/module-alsa-source.c | 3 +-- src/modules/module-combine.c | 5 +---- src/modules/module-esound-sink.c | 2 +- src/modules/module-oss-mmap.c | 7 +++---- src/modules/module-oss.c | 7 +++---- src/modules/module-pipe-sink.c | 2 +- src/modules/module-solaris.c | 5 ++--- src/modules/module-waveout.c | 5 ++--- 9 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index e14cc5c8..8da3d236 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -90,9 +90,7 @@ static const char* const valid_modargs[] = { #define DEFAULT_DEVICE "default" static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, - (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + - (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0)); + pa_module_set_used(u->module, u->sink ? pa_sink_used_by(u->sink) : 0); } static void clear_up(struct userdata *u) { diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index b4ef09d9..4a8678c9 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -91,8 +91,7 @@ static const char* const valid_modargs[] = { #define DEFAULT_DEVICE "default" static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, - (u->source ? pa_idxset_size(u->source->outputs) : 0)); + pa_module_set_used(u->module, u->source ? pa_source_used_by(u->source) : 0); } static void clear_up(struct userdata *u) { diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 0a5bd472..9368aed8 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -99,12 +99,9 @@ static void output_free(struct output *o); static void clear_up(struct userdata *u); static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, - (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + - (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0)); + pa_module_set_used(u->module, u->sink ? pa_sink_used_by(u->sink) : 0); } - static void adjust_rates(struct userdata *u) { struct output *o; pa_usec_t max_sink_latency = 0, min_total_latency = (pa_usec_t) -1, target_latency; diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index 9f0c2c5b..c774d8c1 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -142,7 +142,7 @@ static int do_write(struct userdata *u) { u->write_index = u->write_length = 0; } } else if (u->state == STATE_RUNNING) { - pa_module_set_used(u->module, pa_idxset_size(u->sink->inputs) + pa_idxset_size(u->sink->monitor_source->outputs)); + pa_module_set_used(u->module, pa_sink_used_by(u->sink)); if (!u->memchunk.length) if (pa_sink_render(u->sink, 8192, &u->memchunk) < 0) diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index 21a23d75..c783a2f1 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -110,10 +110,9 @@ static const char* const valid_modargs[] = { #define DEFAULT_FRAGSIZE 1024 static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, - (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + - (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0) + - (u->source ? pa_idxset_size(u->source->outputs) : 0)); + pa_module_set_used(u->module, + (u->sink ? pa_sink_used_by(u->sink) : 0) + + (u->source ? pa_source_used_by(u->source) : 0)); } static void clear_up(struct userdata *u) { diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 89a8152b..ce11ee02 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -100,10 +100,9 @@ static const char* const valid_modargs[] = { #define DEFAULT_DEVICE "/dev/dsp" static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, - (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + - (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0) + - (u->source ? pa_idxset_size(u->source->outputs) : 0)); + pa_module_set_used(u->module, + (u->sink ? pa_sink_used_by(u->sink) : 0) + + (u->source ? pa_source_used_by(u->source) : 0)); } static void clear_up(struct userdata *u) { diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index cc5276d4..c90039fd 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -91,7 +91,7 @@ static void do_write(struct userdata *u) { if (!pa_iochannel_is_writable(u->io)) return; - pa_module_set_used(u->module, pa_idxset_size(u->sink->inputs) + pa_idxset_size(u->sink->monitor_source->outputs)); + pa_module_set_used(u->module, pa_sink_used_by(u->sink)); if (!u->memchunk.length) if (pa_sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0) diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 21a72b38..53c73af7 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -110,9 +110,8 @@ static const char* const valid_modargs[] = { static void update_usage(struct userdata *u) { pa_module_set_used(u->module, - (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + - (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0) + - (u->source ? pa_idxset_size(u->source->outputs) : 0)); + (u->sink ? pa_sink_used_by(u->sink) : 0) + + (u->source ? pa_source_used_by(u->source) : 0)); } static void do_write(struct userdata *u) { diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index 27e8de58..5f55c202 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -103,9 +103,8 @@ static const char* const valid_modargs[] = { static void update_usage(struct userdata *u) { pa_module_set_used(u->module, - (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + - (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0) + - (u->source ? pa_idxset_size(u->source->outputs) : 0)); + (u->sink ? pa_sink_used_by(u->sink) : 0) + + (u->source ? pa_source_used_by(u->source) : 0)); } static void do_write(struct userdata *u) -- cgit From 02e083cbc4956e6c8990ea0e2a888efb912d90c3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 17:06:39 +0000 Subject: test if sink->monitor_source is set before making use of it git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1228 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/cli-text.c | 2 +- src/pulsecore/protocol-native.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index eecf68ff..a1a2e564 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -109,7 +109,7 @@ char *pa_sink_list_to_string(pa_core *c) { sink->driver, pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, PA_MIXER_HARDWARE)), (double) pa_sink_get_latency(sink), - sink->monitor_source->index, + sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX, pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map)); diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index d5a4cf45..98212922 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -1276,8 +1276,8 @@ static void sink_fill_tagstruct(pa_tagstruct *t, pa_sink *sink) { PA_TAG_U32, sink->owner ? sink->owner->index : PA_INVALID_INDEX, PA_TAG_CVOLUME, pa_sink_get_volume(sink, PA_MIXER_HARDWARE), PA_TAG_BOOLEAN, pa_sink_get_mute(sink, PA_MIXER_HARDWARE), - PA_TAG_U32, sink->monitor_source->index, - PA_TAG_STRING, sink->monitor_source->name, + PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX, + PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL, PA_TAG_USEC, pa_sink_get_latency(sink), PA_TAG_STRING, sink->driver, PA_TAG_U32, -- cgit From 17964dda374210579b887ea849ba35dbb438ef0a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 17:07:49 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1229 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 - 1 file changed, 1 deletion(-) diff --git a/todo b/todo index f386e94a..7fbf01a8 100644 --- a/todo +++ b/todo @@ -21,7 +21,6 @@ Cleanups: - use software volume when hardware doesn't support all channels (alsa done) - silence generation should be moved into the core to avoid races and code duplication in the backends -- make sure that everyone knows how to deal with sinks without a monitor source Auth/Crypto: - ssl -- cgit From 7f70ca31a148edd2bbe82d1424d02fa50892d9bc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 17:59:10 +0000 Subject: extend maximum sink/source name length, because HAL UDIs can get ridiculously long git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1230 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/namereg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/namereg.h b/src/pulsecore/namereg.h index 53295b84..53fb6618 100644 --- a/src/pulsecore/namereg.h +++ b/src/pulsecore/namereg.h @@ -24,7 +24,7 @@ #include -#define PA_NAME_MAX 64 +#define PA_NAME_MAX 128 typedef enum pa_namereg_type { PA_NAMEREG_SINK, -- cgit From 80d73dd21b0af1970ec3cedfe1490acc39f7c221 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 23:35:44 +0000 Subject: implement typeafe hook chain git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1231 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 8 +++++++- src/pulsecore/llist.h | 2 ++ src/tests/hook-list-test.c | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/tests/hook-list-test.c diff --git a/src/Makefile.am b/src/Makefile.am index e0fae996..82175e42 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -196,7 +196,8 @@ noinst_PROGRAMS = \ thread-mainloop-test \ utf8-test \ get-binary-name-test \ - ipacl-test + ipacl-test \ + hook-list-test if HAVE_SIGXCPU noinst_PROGRAMS += \ @@ -236,6 +237,11 @@ ipacl_test_CFLAGS = $(AM_CFLAGS) ipacl_test_LDADD = $(AM_LDADD) libpulsecore.la ipacl_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +hook_list_test_SOURCES = tests/hook-list-test.c +hook_list_test_CFLAGS = $(AM_CFLAGS) +hook_list_test_LDADD = $(AM_LDADD) libpulsecore.la +hook_list_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + mcalign_test_SOURCES = tests/mcalign-test.c mcalign_test_CFLAGS = $(AM_CFLAGS) mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpulsecore.la diff --git a/src/pulsecore/llist.h b/src/pulsecore/llist.h index 9ce24e74..c50b8a78 100644 --- a/src/pulsecore/llist.h +++ b/src/pulsecore/llist.h @@ -22,6 +22,8 @@ USA. ***/ +#include + /* Some macros for maintaining doubly linked lists */ /* The head of the linked list. Use this in the structure that shall diff --git a/src/tests/hook-list-test.c b/src/tests/hook-list-test.c new file mode 100644 index 00000000..ee0b54f9 --- /dev/null +++ b/src/tests/hook-list-test.c @@ -0,0 +1,38 @@ +/* $Id$ */ + +#include +#include + +PA_HOOK_DECLARE(test, const char *, const char*); +PA_HOOK_IMPLEMENT(test, const char *, const char *); + +static pa_hook_result_t func1(const char*a, const char*b, void *userdata) { + pa_log("#1 a=%s b=%s userdata=%s", a, b, (char*) userdata); + return PA_HOOK_OK; +} + +static pa_hook_result_t func2(const char*a, const char*b, void *userdata) { + pa_log("#2 a=%s b=%s userdata=%s", a, b, (char*) userdata); + return PA_HOOK_OK; +} + +int main(int argc, char *argv[]) { + void *u; + + PA_HOOK_HEAD(test, test); + + PA_HOOK_HEAD_INIT(test, test); + + PA_HOOK_APPEND(test, test, func1, (void*) "1-1"); + PA_HOOK_APPEND(test, test, func2, u = (void*) "2"); + PA_HOOK_APPEND(test, test, func1, (void*) "1-2"); + + + PA_HOOK_EXECUTE(test, test, "arg1", "arg2"); + + PA_HOOK_REMOVE(test, test, func2, u); + + PA_HOOK_FREE(test, test); + + return 0; +} -- cgit From 82a913d73e6a319b040510a172e3c6fb46602624 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 23:55:22 +0000 Subject: reall add type safe hook list git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1232 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/hook-list.h | 117 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/pulsecore/hook-list.h diff --git a/src/pulsecore/hook-list.h b/src/pulsecore/hook-list.h new file mode 100644 index 00000000..6bfe9cb5 --- /dev/null +++ b/src/pulsecore/hook-list.h @@ -0,0 +1,117 @@ +#ifndef foohooklistfoo +#define foohooklistfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* Some macro voodoo to implement a type safe hook list */ + +#include +#include +#include + +typedef enum pa_hook_result { + PA_HOOK_OK = 0, + PA_HOOK_STOP = 1, + PA_HOOK_CANCEL = -1 +} pa_hook_result_t; + +#define PA_HOOK_DECLARE(name, arg1, arg2) \ +typedef pa_hook_result_t (*pa_hook__##name##__func_t)(arg1 a, arg2 b, void *userdata); \ +\ +typedef struct pa_hook__##name##__func_info pa_hook__##name##__func_info; \ +struct pa_hook__##name##__func_info { \ + int dead; \ + pa_hook__##name##__func_t func; \ + void *userdata; \ + PA_LLIST_FIELDS(pa_hook__##name##__func_info); \ +}; \ +PA_GCC_UNUSED static void pa_hook__##name##__free_one( \ + pa_hook__##name##__func_info **head, \ + pa_hook__##name##__func_info *i) { \ + PA_LLIST_REMOVE(pa_hook__##name##__func_info, *head, i); \ + pa_xfree(i); \ +} \ +PA_GCC_UNUSED static void pa_hook__##name##__free_all( \ + pa_hook__##name##__func_info **head) { \ + while (*head) \ + pa_hook__##name##__free_one(head, *head); \ +} \ +PA_GCC_UNUSED static void pa_hook__##name##__mark_dead( \ + pa_hook__##name##__func_info *i, \ + pa_hook__##name##__func_t func, \ + void *userdata) { \ + for (; i; i = i->next) { \ + if (i->func != func || i->userdata != userdata) \ + continue; \ + i->dead = 1; \ + break; \ + } \ +} \ +PA_GCC_UNUSED static void pa_hook__##name##__append( \ + pa_hook__##name##__func_info **head, \ + pa_hook__##name##__func_t func, \ + void *userdata) { \ + pa_hook__##name##__func_info *i = pa_xnew(pa_hook__##name##__func_info, 1); \ + i->dead = 0; \ + i->func = func; \ + i->userdata = userdata; \ + PA_LLIST_PREPEND(pa_hook__##name##__func_info, *head, i); \ +} \ +PA_GCC_UNUSED static pa_hook_result_t pa_hook__##name##__execute ( \ + pa_hook__##name##__func_info **head, \ + arg1 a, \ + arg2 b) { \ + pa_hook__##name##__func_info *i, *n; \ + pa_hook_result_t ret = PA_HOOK_OK; \ + for (i = *head; i; i = i->next) { \ + if ((ret = i->func(a, b, i->userdata)) != PA_HOOK_OK) \ + break; \ + } \ + for (i = *head; i; i = n) { \ + n = i->next; \ + if (i->dead) \ + pa_hook__##name##__free_one(head, i); \ + } \ + return ret; \ +}\ +void pa_hook__##name##__nowarn(void) + + +#define PA_HOOK_HEAD(name, head) \ +pa_hook__##name##__func_info *head; + +#define PA_HOOK_HEAD_INIT(name, head) \ +(head) = NULL + +#define PA_HOOK_EXECUTE(name, head, arg1, arg2) \ +pa_hook__##name##__execute(&(head), arg1, arg2) + +#define PA_HOOK_APPEND(name, head, func, userdata) \ +pa_hook__##name##__append(&(head), func, userdata) + +#define PA_HOOK_REMOVE(name, head, func, userdata) \ +pa_hook__##name##__mark_dead(head, func, userdata) + +#define PA_HOOK_FREE(name, head) \ +pa_hook__##name##__free_all(&(head)) + +#endif -- cgit From 2622b0ca9eae2ffb18caed2b54b4e25325bed702 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 23:55:48 +0000 Subject: update hook list test git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1233 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/tests/hook-list-test.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tests/hook-list-test.c b/src/tests/hook-list-test.c index ee0b54f9..b0ea5997 100644 --- a/src/tests/hook-list-test.c +++ b/src/tests/hook-list-test.c @@ -4,7 +4,6 @@ #include PA_HOOK_DECLARE(test, const char *, const char*); -PA_HOOK_IMPLEMENT(test, const char *, const char *); static pa_hook_result_t func1(const char*a, const char*b, void *userdata) { pa_log("#1 a=%s b=%s userdata=%s", a, b, (char*) userdata); @@ -27,7 +26,6 @@ int main(int argc, char *argv[]) { PA_HOOK_APPEND(test, test, func2, u = (void*) "2"); PA_HOOK_APPEND(test, test, func1, (void*) "1-2"); - PA_HOOK_EXECUTE(test, test, "arg1", "arg2"); PA_HOOK_REMOVE(test, test, func2, u); -- cgit From 281125c72767713d6294ac7094f3bf7bde47a1e3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 01:43:34 +0000 Subject: rework hook list stuff again, and replace macros with real functins. We loose type safety but things are much cleaner now git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1234 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 3 +- src/pulsecore/hook-list.c | 111 +++++++++++++++++++++++++++++++++++++++++++++ src/pulsecore/hook-list.h | 99 +++++++++------------------------------- src/tests/hook-list-test.c | 32 ++++++------- 4 files changed, 149 insertions(+), 96 deletions(-) create mode 100644 src/pulsecore/hook-list.c diff --git a/src/Makefile.am b/src/Makefile.am index 82175e42..3cf3168c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -585,7 +585,8 @@ libpulsecore_la_SOURCES += \ pulsecore/strbuf.c pulsecore/strbuf.h \ pulsecore/tokenizer.c pulsecore/tokenizer.h \ pulsecore/winsock.h \ - pulsecore/core-error.c pulsecore/core-error.h + pulsecore/core-error.c pulsecore/core-error.h \ + pulsecore/hook-list.c pulsecore/hook-list.h if OS_IS_WIN32 libpulsecore_la_SOURCES += \ diff --git a/src/pulsecore/hook-list.c b/src/pulsecore/hook-list.c new file mode 100644 index 00000000..14ab8e89 --- /dev/null +++ b/src/pulsecore/hook-list.c @@ -0,0 +1,111 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +void pa_hook_init(pa_hook *hook) { + assert(hook); + + PA_LLIST_HEAD_INIT(pa_hook_slots, hook->slots); + hook->last = NULL; + hook->n_dead = hook->firing = 0; +} + +static void slot_free(pa_hook *hook, pa_hook_slot *slot) { + assert(hook); + assert(slot); + + if (hook->last == slot) + hook->last = slot->prev; + + PA_LLIST_REMOVE(pa_hook_slot, hook->slots, slot); + + pa_xfree(slot); +} + +void pa_hook_free(pa_hook *hook) { + assert(hook); + assert(!hook->firing); + + while (hook->slots) + slot_free(hook, hook->slots); + + pa_hook_init(hook); +} + +pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t cb, void *userdata) { + pa_hook_slot *slot; + + assert(cb); + + slot = pa_xnew(pa_hook_slot, 1); + slot->hook = hook; + slot->dead = 0; + slot->callback = cb; + slot->userdata = userdata; + + PA_LLIST_INSERT_AFTER(pa_hook_slot, hook->slots, hook->last, slot); + hook->last = slot; + + return slot; +} + +void pa_hook_slot_free(pa_hook_slot *slot) { + assert(slot); + assert(!slot->dead); + + if (slot->hook->firing > 0) { + slot->dead = 1; + slot->hook->n_dead++; + } else + slot_free(slot->hook, slot); +} + +pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data) { + pa_hook_slot *slot, *next; + pa_hook_result_t result = PA_HOOK_OK; + + assert(hook); + + hook->firing ++; + + for (slot = hook->slots; slot; slot = slot->next) { + if (slot->dead) + continue; + + if ((result = slot->callback(data, slot->userdata)) != PA_HOOK_OK) + break; + } + + hook->firing --; + + for (slot = hook->slots; hook->n_dead > 0 && slot; slot = next) { + next = slot->next; + + if (slot->dead) { + slot_free(hook, slot); + hook->n_dead--; + } + } + + return result; +} + diff --git a/src/pulsecore/hook-list.h b/src/pulsecore/hook-list.h index 6bfe9cb5..e016ff0c 100644 --- a/src/pulsecore/hook-list.h +++ b/src/pulsecore/hook-list.h @@ -22,11 +22,12 @@ USA. ***/ -/* Some macro voodoo to implement a type safe hook list */ - #include #include -#include +#include + +typedef struct pa_hook_slot pa_hook_slot; +typedef struct pa_hook pa_hook; typedef enum pa_hook_result { PA_HOOK_OK = 0, @@ -34,84 +35,28 @@ typedef enum pa_hook_result { PA_HOOK_CANCEL = -1 } pa_hook_result_t; -#define PA_HOOK_DECLARE(name, arg1, arg2) \ -typedef pa_hook_result_t (*pa_hook__##name##__func_t)(arg1 a, arg2 b, void *userdata); \ -\ -typedef struct pa_hook__##name##__func_info pa_hook__##name##__func_info; \ -struct pa_hook__##name##__func_info { \ - int dead; \ - pa_hook__##name##__func_t func; \ - void *userdata; \ - PA_LLIST_FIELDS(pa_hook__##name##__func_info); \ -}; \ -PA_GCC_UNUSED static void pa_hook__##name##__free_one( \ - pa_hook__##name##__func_info **head, \ - pa_hook__##name##__func_info *i) { \ - PA_LLIST_REMOVE(pa_hook__##name##__func_info, *head, i); \ - pa_xfree(i); \ -} \ -PA_GCC_UNUSED static void pa_hook__##name##__free_all( \ - pa_hook__##name##__func_info **head) { \ - while (*head) \ - pa_hook__##name##__free_one(head, *head); \ -} \ -PA_GCC_UNUSED static void pa_hook__##name##__mark_dead( \ - pa_hook__##name##__func_info *i, \ - pa_hook__##name##__func_t func, \ - void *userdata) { \ - for (; i; i = i->next) { \ - if (i->func != func || i->userdata != userdata) \ - continue; \ - i->dead = 1; \ - break; \ - } \ -} \ -PA_GCC_UNUSED static void pa_hook__##name##__append( \ - pa_hook__##name##__func_info **head, \ - pa_hook__##name##__func_t func, \ - void *userdata) { \ - pa_hook__##name##__func_info *i = pa_xnew(pa_hook__##name##__func_info, 1); \ - i->dead = 0; \ - i->func = func; \ - i->userdata = userdata; \ - PA_LLIST_PREPEND(pa_hook__##name##__func_info, *head, i); \ -} \ -PA_GCC_UNUSED static pa_hook_result_t pa_hook__##name##__execute ( \ - pa_hook__##name##__func_info **head, \ - arg1 a, \ - arg2 b) { \ - pa_hook__##name##__func_info *i, *n; \ - pa_hook_result_t ret = PA_HOOK_OK; \ - for (i = *head; i; i = i->next) { \ - if ((ret = i->func(a, b, i->userdata)) != PA_HOOK_OK) \ - break; \ - } \ - for (i = *head; i; i = n) { \ - n = i->next; \ - if (i->dead) \ - pa_hook__##name##__free_one(head, i); \ - } \ - return ret; \ -}\ -void pa_hook__##name##__nowarn(void) - - -#define PA_HOOK_HEAD(name, head) \ -pa_hook__##name##__func_info *head; +typedef pa_hook_result_t (*pa_hook_cb_t)(void *data, void *userdata); -#define PA_HOOK_HEAD_INIT(name, head) \ -(head) = NULL +struct pa_hook_slot { + int dead; + pa_hook *hook; + pa_hook_cb_t callback; + void *userdata; + PA_LLIST_FIELDS(pa_hook_slot); +}; -#define PA_HOOK_EXECUTE(name, head, arg1, arg2) \ -pa_hook__##name##__execute(&(head), arg1, arg2) +struct pa_hook { + PA_LLIST_HEAD(pa_hook_slot, slots); + pa_hook_slot *last; + int firing, n_dead; +}; -#define PA_HOOK_APPEND(name, head, func, userdata) \ -pa_hook__##name##__append(&(head), func, userdata) +void pa_hook_init(pa_hook *hook); +void pa_hook_free(pa_hook *hook); -#define PA_HOOK_REMOVE(name, head, func, userdata) \ -pa_hook__##name##__mark_dead(head, func, userdata) +pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t, void *userdata); +void pa_hook_slot_free(pa_hook_slot *slot); -#define PA_HOOK_FREE(name, head) \ -pa_hook__##name##__free_all(&(head)) +pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data); #endif diff --git a/src/tests/hook-list-test.c b/src/tests/hook-list-test.c index b0ea5997..0d811a1e 100644 --- a/src/tests/hook-list-test.c +++ b/src/tests/hook-list-test.c @@ -3,34 +3,30 @@ #include #include -PA_HOOK_DECLARE(test, const char *, const char*); - -static pa_hook_result_t func1(const char*a, const char*b, void *userdata) { - pa_log("#1 a=%s b=%s userdata=%s", a, b, (char*) userdata); +static pa_hook_result_t func1(const char*a, void *userdata) { + pa_log("#1 arg=%s userdata=%s", a, (char*) userdata); return PA_HOOK_OK; } -static pa_hook_result_t func2(const char*a, const char*b, void *userdata) { - pa_log("#2 a=%s b=%s userdata=%s", a, b, (char*) userdata); +static pa_hook_result_t func2(const char*a, void *userdata) { + pa_log("#2 arg=%s userdata=%s", a, (char*) userdata); return PA_HOOK_OK; } int main(int argc, char *argv[]) { - void *u; - - PA_HOOK_HEAD(test, test); - - PA_HOOK_HEAD_INIT(test, test); + pa_hook hook; + pa_hook_slot *slot; - PA_HOOK_APPEND(test, test, func1, (void*) "1-1"); - PA_HOOK_APPEND(test, test, func2, u = (void*) "2"); - PA_HOOK_APPEND(test, test, func1, (void*) "1-2"); + pa_hook_init(&hook); - PA_HOOK_EXECUTE(test, test, "arg1", "arg2"); - - PA_HOOK_REMOVE(test, test, func2, u); + pa_hook_connect(&hook, (pa_hook_cb_t) func1, (void*) "1-1"); + slot = pa_hook_connect(&hook, (pa_hook_cb_t) func2, (void*) "2-1"); + pa_hook_connect(&hook, (pa_hook_cb_t) func1, (void*) "1-2"); + + pa_hook_fire(&hook, (void*) "arg2"); - PA_HOOK_FREE(test, test); + pa_hook_slot_free(slot); + pa_hook_free(&hook); return 0; } -- cgit From db3f561ec4d6fe7b6deedff45802a5efd3ba4013 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 16:13:36 +0000 Subject: rework hook list stuff once again: change the callback prototype to recieve three data pointers: one to the data for the hook, once for the slot and once for the call git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1235 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/hook-list.c | 11 ++++++----- src/pulsecore/hook-list.h | 13 +++++++++---- src/tests/hook-list-test.c | 21 ++++++++++++--------- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/pulsecore/hook-list.c b/src/pulsecore/hook-list.c index 14ab8e89..72b206b2 100644 --- a/src/pulsecore/hook-list.c +++ b/src/pulsecore/hook-list.c @@ -21,12 +21,13 @@ #include -void pa_hook_init(pa_hook *hook) { +void pa_hook_init(pa_hook *hook, void *data) { assert(hook); PA_LLIST_HEAD_INIT(pa_hook_slots, hook->slots); hook->last = NULL; hook->n_dead = hook->firing = 0; + hook->data = data; } static void slot_free(pa_hook *hook, pa_hook_slot *slot) { @@ -48,10 +49,10 @@ void pa_hook_free(pa_hook *hook) { while (hook->slots) slot_free(hook, hook->slots); - pa_hook_init(hook); + pa_hook_init(hook, NULL); } -pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t cb, void *userdata) { +pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t cb, void *data) { pa_hook_slot *slot; assert(cb); @@ -60,7 +61,7 @@ pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t cb, void *userdata) { slot->hook = hook; slot->dead = 0; slot->callback = cb; - slot->userdata = userdata; + slot->data = data; PA_LLIST_INSERT_AFTER(pa_hook_slot, hook->slots, hook->last, slot); hook->last = slot; @@ -91,7 +92,7 @@ pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data) { if (slot->dead) continue; - if ((result = slot->callback(data, slot->userdata)) != PA_HOOK_OK) + if ((result = slot->callback(hook->data, data, slot->data)) != PA_HOOK_OK) break; } diff --git a/src/pulsecore/hook-list.h b/src/pulsecore/hook-list.h index e016ff0c..67e5d1ae 100644 --- a/src/pulsecore/hook-list.h +++ b/src/pulsecore/hook-list.h @@ -35,13 +35,16 @@ typedef enum pa_hook_result { PA_HOOK_CANCEL = -1 } pa_hook_result_t; -typedef pa_hook_result_t (*pa_hook_cb_t)(void *data, void *userdata); +typedef pa_hook_result_t (*pa_hook_cb_t)( + void *hook_data, + void *call_data, + void *slot_data); struct pa_hook_slot { int dead; pa_hook *hook; pa_hook_cb_t callback; - void *userdata; + void *data; PA_LLIST_FIELDS(pa_hook_slot); }; @@ -49,12 +52,14 @@ struct pa_hook { PA_LLIST_HEAD(pa_hook_slot, slots); pa_hook_slot *last; int firing, n_dead; + + void *data; }; -void pa_hook_init(pa_hook *hook); +void pa_hook_init(pa_hook *hook, void *data); void pa_hook_free(pa_hook *hook); -pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t, void *userdata); +pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t, void *data); void pa_hook_slot_free(pa_hook_slot *slot); pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data); diff --git a/src/tests/hook-list-test.c b/src/tests/hook-list-test.c index 0d811a1e..d68d1b7d 100644 --- a/src/tests/hook-list-test.c +++ b/src/tests/hook-list-test.c @@ -3,13 +3,13 @@ #include #include -static pa_hook_result_t func1(const char*a, void *userdata) { - pa_log("#1 arg=%s userdata=%s", a, (char*) userdata); +static pa_hook_result_t func1(const char*hook_data, const char*call_data, const char*slot_data) { + pa_log("(func1) hook=%s call=%s slot=%s", hook_data, call_data, slot_data); return PA_HOOK_OK; } -static pa_hook_result_t func2(const char*a, void *userdata) { - pa_log("#2 arg=%s userdata=%s", a, (char*) userdata); +static pa_hook_result_t func2(const char*hook_data, const char*call_data, const char*slot_data) { + pa_log("(func2) hook=%s call=%s slot=%s", hook_data, call_data, slot_data); return PA_HOOK_OK; } @@ -17,15 +17,18 @@ int main(int argc, char *argv[]) { pa_hook hook; pa_hook_slot *slot; - pa_hook_init(&hook); + pa_hook_init(&hook, (void*) "hook"); - pa_hook_connect(&hook, (pa_hook_cb_t) func1, (void*) "1-1"); - slot = pa_hook_connect(&hook, (pa_hook_cb_t) func2, (void*) "2-1"); - pa_hook_connect(&hook, (pa_hook_cb_t) func1, (void*) "1-2"); + pa_hook_connect(&hook, (pa_hook_cb_t) func1, (void*) "slot1"); + slot = pa_hook_connect(&hook, (pa_hook_cb_t) func2, (void*) "slot2"); + pa_hook_connect(&hook, (pa_hook_cb_t) func1, (void*) "slot3"); - pa_hook_fire(&hook, (void*) "arg2"); + pa_hook_fire(&hook, (void*) "call1"); pa_hook_slot_free(slot); + + pa_hook_fire(&hook, (void*) "call2"); + pa_hook_free(&hook); return 0; -- cgit From b5cbea940ea70b8ed92fa3be6b742e8a14897337 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 16:14:06 +0000 Subject: fix bad printf() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1236 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pactl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/pactl.c b/src/utils/pactl.c index f6f75498..028f71c8 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -627,7 +627,7 @@ static void help(const char *argv0) { " --version Show version\n\n" " -s, --server=SERVER The name of the server to connect to\n" " -n, --client-name=NAME How to call this client on the server\n", - argv0, argv0, argv0, argv0, argv0, argv0, argv0); + argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0); } enum { ARG_VERSION = 256 }; -- cgit From a621d9028548723d13df64df06a4f4538504e7a3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 16:19:56 +0000 Subject: allow hooking into the process of creating playback streams. To implement this I modified the pa_sink_input_new() signature to take a pa_sink_input_new_data structure instead of direct arguments. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1237 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-combine.c | 14 +++- src/modules/module-sine.c | 12 ++- src/modules/rtp/module-rtp-recv.c | 11 ++- src/pulsecore/cli-text.c | 4 +- src/pulsecore/client.h | 10 ++- src/pulsecore/core.c | 6 ++ src/pulsecore/core.h | 13 +++- src/pulsecore/module.h | 4 +- src/pulsecore/play-memblockq.c | 27 ++++--- src/pulsecore/play-memchunk.c | 27 ++++--- src/pulsecore/protocol-esound.c | 15 +++- src/pulsecore/protocol-native.c | 41 ++++++---- src/pulsecore/protocol-simple.c | 19 ++--- src/pulsecore/sink-input.c | 160 +++++++++++++++++++++++++------------- src/pulsecore/sink-input.h | 47 +++++++---- src/pulsecore/sound-file-stream.c | 24 ++++-- 16 files changed, 296 insertions(+), 138 deletions(-) diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 9368aed8..008fe6e7 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -220,6 +220,8 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { static struct output *output_new(struct userdata *u, pa_sink *sink, int resample_method) { struct output *o = NULL; char t[256]; + pa_sink_input_new_data data; + assert(u && sink && u->sink); o = pa_xmalloc(sizeof(struct output)); @@ -237,7 +239,16 @@ static struct output *output_new(struct userdata *u, pa_sink *sink, int resample sink->core->memblock_stat); snprintf(t, sizeof(t), "%s: output #%u", u->sink->name, u->n_outputs+1); - if (!(o->sink_input = pa_sink_input_new(sink, __FILE__, t, &u->sink->sample_spec, &u->sink->channel_map, NULL, 1, resample_method))) + + pa_sink_input_new_data_init(&data); + data.sink = sink; + data.driver = __FILE__; + data.name = t; + pa_sink_input_new_data_set_sample_spec(&data, &u->sink->sample_spec); + pa_sink_input_new_data_set_channel_map(&data, &u->sink->channel_map); + data.module = u->module; + + if (!(o->sink_input = pa_sink_input_new(u->core, &data, PA_SINK_INPUT_VARIABLE_RATE))) goto fail; o->sink_input->get_latency = sink_input_get_latency_cb; @@ -245,7 +256,6 @@ static struct output *output_new(struct userdata *u, pa_sink *sink, int resample o->sink_input->drop = sink_input_drop_cb; o->sink_input->kill = sink_input_kill_cb; o->sink_input->userdata = o; - o->sink_input->owner = u->module; PA_LLIST_PREPEND(struct output, u->outputs, o); u->n_outputs++; diff --git a/src/modules/module-sine.c b/src/modules/module-sine.c index f4392b9a..5ceddce0 100644 --- a/src/modules/module-sine.c +++ b/src/modules/module-sine.c @@ -109,6 +109,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_sample_spec ss; uint32_t frequency; char t[256]; + pa_sink_input_new_data data; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": Failed to parse module arguments"); @@ -142,14 +143,21 @@ int pa__init(pa_core *c, pa_module*m) { calc_sine(u->memblock->data, u->memblock->length, frequency); snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency); - if (!(u->sink_input = pa_sink_input_new(sink, __FILE__, t, &ss, NULL, NULL, 0, -1))) + + pa_sink_input_new_data_init(&data); + data.sink = sink; + data.driver = __FILE__; + data.name = t; + pa_sink_input_new_data_set_sample_spec(&data, &ss); + data.module = m; + + if (!(u->sink_input = pa_sink_input_new(c, &data, 0))) goto fail; u->sink_input->peek = sink_input_peek; u->sink_input->drop = sink_input_drop; u->sink_input->kill = sink_input_kill; u->sink_input->userdata = u; - u->sink_input->owner = m; u->peek_index = 0; diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index 0359a43b..df6f8c11 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -265,6 +265,7 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in pa_sink *sink; int fd = -1; pa_memblock *silence; + pa_sink_input_new_data data; if (u->n_sessions >= MAX_SESSIONS) { pa_log(__FILE__": session limit reached."); @@ -289,7 +290,14 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in sdp_info->session_name ? sdp_info->session_name : "", sdp_info->session_name ? ")" : ""); - s->sink_input = pa_sink_input_new(sink, __FILE__, c, &sdp_info->sample_spec, NULL, NULL, 0, PA_RESAMPLER_INVALID); + pa_sink_input_new_data_init(&data); + data.sink = sink; + data.driver = __FILE__; + data.name = c; + data.module = u->module; + pa_sink_input_new_data_set_sample_spec(&data, &sdp_info->sample_spec); + + s->sink_input = pa_sink_input_new(u->core, &data, 0); pa_xfree(c); if (!s->sink_input) { @@ -298,7 +306,6 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in } s->sink_input->userdata = s; - s->sink_input->owner = u->module; s->sink_input->peek = sink_input_peek; s->sink_input->drop = sink_input_drop; diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index a1a2e564..ff083dc3 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -257,8 +257,8 @@ char *pa_sink_input_list_to_string(pa_core *c) { pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), pa_resample_method_to_string(pa_sink_input_get_resample_method(i))); - if (i->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", i->owner->index); + if (i->module) + pa_strbuf_printf(s, "\towner module: <%u>\n", i->module->index); if (i->client) pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", i->client->index, i->client->name); } diff --git a/src/pulsecore/client.h b/src/pulsecore/client.h index 1e72baf7..b28065e5 100644 --- a/src/pulsecore/client.h +++ b/src/pulsecore/client.h @@ -1,5 +1,5 @@ -#ifndef fooclienthfoo -#define fooclienthfoo +#ifndef foopulseclienthfoo +#define foopulseclienthfoo /* $Id$ */ @@ -22,6 +22,10 @@ USA. ***/ +#include + +typedef struct pa_client pa_client; + #include #include @@ -29,8 +33,6 @@ * attached. That way the user may generate a listing of all connected * clients easily and kill them if he wants.*/ -typedef struct pa_client pa_client; - struct pa_client { uint32_t index; diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index 710e00ad..24f835f7 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -92,6 +92,9 @@ pa_core* pa_core_new(pa_mainloop_api *m) { c->is_system_instance = 0; + pa_hook_init(&c->hook_sink_input_new, c); + pa_hook_init(&c->hook_sink_input_disconnect, c); + pa_property_init(c); pa_random(&c->cookie, sizeof(c->cookie)); @@ -137,6 +140,9 @@ void pa_core_free(pa_core *c) { pa_memblock_stat_unref(c->memblock_stat); pa_property_cleanup(c); + + pa_hook_free(&c->hook_sink_input_new); + pa_hook_free(&c->hook_sink_input_disconnect); pa_xfree(c); } diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index 391ba9b8..fd92de61 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -22,17 +22,21 @@ USA. ***/ -typedef struct pa_core pa_core; - #include #include + #include #include #include #include #include -#include #include +#include + +typedef struct pa_core pa_core; + +#include +#include /* The core structure of PulseAudio. Every PulseAudio daemon contains * exactly one of these. It is used for storing kind of global @@ -75,6 +79,9 @@ struct pa_core { pa_resample_method_t resample_method; int is_system_instance; + + /* hooks */ + pa_hook hook_sink_input_new, hook_sink_input_disconnect; }; pa_core* pa_core_new(pa_mainloop_api *m); diff --git a/src/pulsecore/module.h b/src/pulsecore/module.h index 9bc5cb5d..8c320be8 100644 --- a/src/pulsecore/module.h +++ b/src/pulsecore/module.h @@ -25,11 +25,11 @@ #include #include +typedef struct pa_module pa_module; + #include #include -typedef struct pa_module pa_module; - struct pa_module { pa_core *core; char *name, *argument; diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c index 7b796a8d..f459142a 100644 --- a/src/pulsecore/play-memblockq.c +++ b/src/pulsecore/play-memblockq.c @@ -79,14 +79,15 @@ static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t le } int pa_play_memblockq( - pa_sink *sink, - const char *name, - const pa_sample_spec *ss, - const pa_channel_map *map, - pa_memblockq *q, - pa_cvolume *cvolume) { + pa_sink *sink, + const char *name, + const pa_sample_spec *ss, + const pa_channel_map *map, + pa_memblockq *q, + pa_cvolume *volume) { pa_sink_input *si; + pa_sink_input_new_data data; assert(sink); assert(ss); @@ -97,12 +98,20 @@ int pa_play_memblockq( return 0; } - if (cvolume && pa_cvolume_is_muted(cvolume)) { + if (volume && pa_cvolume_is_muted(volume)) { pa_memblockq_free(q); return 0; } - if (!(si = pa_sink_input_new(sink, name, __FILE__, ss, map, cvolume, 0, PA_RESAMPLER_INVALID))) + pa_sink_input_new_data_init(&data); + data.sink = sink; + data.name = name; + data.driver = __FILE__; + pa_sink_input_new_data_set_channel_map(&data, map); + pa_sink_input_new_data_set_sample_spec(&data, ss); + pa_sink_input_new_data_set_volume(&data, volume); + + if (!(si = pa_sink_input_new(sink->core, &data, 0))) return -1; si->peek = sink_input_peek; @@ -111,7 +120,7 @@ int pa_play_memblockq( si->userdata = q; - pa_sink_notify(sink); + pa_sink_notify(si->sink); return 0; } diff --git a/src/pulsecore/play-memchunk.c b/src/pulsecore/play-memchunk.c index 7ac579e9..cde6a9ee 100644 --- a/src/pulsecore/play-memchunk.c +++ b/src/pulsecore/play-memchunk.c @@ -82,24 +82,33 @@ static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t le } int pa_play_memchunk( - pa_sink *sink, - const char *name, - const pa_sample_spec *ss, - const pa_channel_map *map, - const pa_memchunk *chunk, - pa_cvolume *cvolume) { + pa_sink *sink, + const char *name, + const pa_sample_spec *ss, + const pa_channel_map *map, + const pa_memchunk *chunk, + pa_cvolume *volume) { pa_sink_input *si; pa_memchunk *nchunk; + pa_sink_input_new_data data; assert(sink); assert(ss); assert(chunk); - if (cvolume && pa_cvolume_is_muted(cvolume)) + if (volume && pa_cvolume_is_muted(volume)) return 0; - if (!(si = pa_sink_input_new(sink, name, __FILE__, ss, map, cvolume, 0, PA_RESAMPLER_INVALID))) + pa_sink_input_new_data_init(&data); + data.sink = sink; + data.name = name; + data.driver = __FILE__; + pa_sink_input_new_data_set_sample_spec(&data, ss); + pa_sink_input_new_data_set_channel_map(&data, map); + pa_sink_input_new_data_set_volume(&data, volume); + + if (!(si = pa_sink_input_new(sink->core, &data, 0))) return -1; si->peek = sink_input_peek; @@ -111,7 +120,7 @@ int pa_play_memchunk( pa_memblock_ref(chunk->memblock); - pa_sink_notify(sink); + pa_sink_notify(si->sink); return 0; } diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 0fa2c7f1..724dccbc 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -325,9 +325,10 @@ static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t req static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { char name[ESD_NAME_MAX], *utf8_name; int32_t format, rate; - pa_sink *sink; pa_sample_spec ss; size_t l; + pa_sink *sink; + pa_sink_input_new_data sdata; assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); @@ -355,7 +356,15 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t assert(!c->sink_input && !c->input_memblockq); - c->sink_input = pa_sink_input_new(sink, __FILE__, utf8_name, &ss, NULL, NULL, 0, -1); + pa_sink_input_new_data_init(&sdata); + sdata.sink = sink; + sdata.driver = __FILE__; + sdata.name = utf8_name; + pa_sink_input_new_data_set_sample_spec(&sdata, &ss); + sdata.module = c->protocol->module; + sdata.client = c->client; + + c->sink_input = pa_sink_input_new(c->protocol->core, &sdata, 0); pa_xfree(utf8_name); @@ -374,8 +383,6 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2); c->playback.fragment_size = l/10; - c->sink_input->owner = c->protocol->module; - c->sink_input->client = c->client; c->sink_input->peek = sink_input_peek_cb; c->sink_input->drop = sink_input_drop_cb; c->sink_input->kill = sink_input_kill_cb; diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 98212922..f922fb55 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -362,23 +362,24 @@ static void record_stream_free(struct record_stream* r) { } static struct playback_stream* playback_stream_new( - struct connection *c, - pa_sink *sink, - const pa_sample_spec *ss, - const pa_channel_map *map, - const char *name, - size_t maxlength, - size_t tlength, - size_t prebuf, - size_t minreq, - pa_cvolume *volume, - uint32_t syncid) { + struct connection *c, + pa_sink *sink, + const pa_sample_spec *ss, + const pa_channel_map *map, + const char *name, + size_t maxlength, + size_t tlength, + size_t prebuf, + size_t minreq, + pa_cvolume *volume, + uint32_t syncid) { struct playback_stream *s, *ssync; pa_sink_input *sink_input; pa_memblock *silence; uint32_t idx; int64_t start_index; + pa_sink_input_new_data data; assert(c && sink && ss && name && maxlength); @@ -395,8 +396,18 @@ static struct playback_stream* playback_stream_new( /* Synced streams must connect to the same sink */ if (ssync && ssync->sink_input->sink != sink) return NULL; - - if (!(sink_input = pa_sink_input_new(sink, __FILE__, name, ss, map, volume, 0, -1))) + + pa_sink_input_new_data_init(&data); + data.sink = sink; + data.driver = __FILE__; + data.name = name; + pa_sink_input_new_data_set_sample_spec(&data, ss); + pa_sink_input_new_data_set_channel_map(&data, map); + pa_sink_input_new_data_set_volume(&data, volume); + data.module = c->protocol->module; + data.client = c->client; + + if (!(sink_input = pa_sink_input_new(sink->core, &data, 0))) return NULL; s = pa_xnew(struct playback_stream, 1); @@ -411,8 +422,6 @@ static struct playback_stream* playback_stream_new( s->sink_input->kill = sink_input_kill_cb; s->sink_input->get_latency = sink_input_get_latency_cb; s->sink_input->userdata = s; - s->sink_input->owner = c->protocol->module; - s->sink_input->client = c->client; if (ssync) { /* Sync id found, now find head of list */ @@ -1331,7 +1340,7 @@ static void sink_input_fill_tagstruct(pa_tagstruct *t, pa_sink_input *s) { assert(t && s); pa_tagstruct_putu32(t, s->index); pa_tagstruct_puts(t, s->name); - pa_tagstruct_putu32(t, s->owner ? s->owner->index : PA_INVALID_INDEX); + pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX); pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX); pa_tagstruct_putu32(t, s->sink->index); pa_tagstruct_put_sample_spec(t, &s->sample_spec); diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c index 4d73bd24..5071191a 100644 --- a/src/pulsecore/protocol-simple.c +++ b/src/pulsecore/protocol-simple.c @@ -340,22 +340,21 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->client->userdata = c; if (p->mode & PLAYBACK) { - pa_sink *sink; + pa_sink_input_new_data data; size_t l; - if (!(sink = pa_namereg_get(p->core, p->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": Failed to get sink."); - goto fail; - } + pa_sink_input_new_data_init(&data); + data.driver = __FILE__; + data.name = c->client->name; + pa_sink_input_new_data_set_sample_spec(&data, &p->sample_spec); + data.module = p->module; + data.client = c->client; - if (!(c->sink_input = pa_sink_input_new(sink, __FILE__, c->client->name, &p->sample_spec, NULL, NULL, 0, -1))) { + if (!(c->sink_input = pa_sink_input_new(p->core, &data, 0))) { pa_log(__FILE__": Failed to create sink input."); goto fail; } - c->sink_input->owner = p->module; - c->sink_input->client = c->client; - c->sink_input->peek = sink_input_peek_cb; c->sink_input->drop = sink_input_drop_cb; c->sink_input->kill = sink_input_kill_cb; @@ -375,6 +374,8 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) assert(c->input_memblockq); pa_iochannel_socket_set_rcvbuf(io, l/PLAYBACK_BUFFER_FRAGMENTS*5); c->playback.fragment_size = l/10; + + pa_sink_notify(c->sink_input->sink); } if (p->mode & RECORD) { diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 701d7f6c..ff5213e1 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "sink-input.h" @@ -48,51 +49,96 @@ if (!(condition)) \ return NULL; \ } while (0) +pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data) { + assert(data); + + memset(data, 0, sizeof(*data)); + data->resample_method = PA_RESAMPLER_INVALID; + return data; +} + +void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const pa_channel_map *map) { + assert(data); + + if ((data->channel_map_is_set = !!map)) + data->channel_map = *map; +} + +void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume) { + assert(data); + + if ((data->volume_is_set = !!volume)) + data->volume = *volume; +} + +void pa_sink_input_new_data_set_sample_spec(pa_sink_input_new_data *data, const pa_sample_spec *spec) { + assert(data); + + if ((data->sample_spec_is_set = !!spec)) + data->sample_spec = *spec; +} + pa_sink_input* pa_sink_input_new( - pa_sink *s, - const char *driver, - const char *name, - const pa_sample_spec *spec, - const pa_channel_map *map, - const pa_cvolume *volume, - int variable_rate, - int resample_method) { + pa_core *core, + pa_sink_input_new_data *data, + pa_sink_input_flags_t flags) { pa_sink_input *i; pa_resampler *resampler = NULL; int r; - char st[256]; - pa_channel_map tmap; - pa_cvolume tvol; - - assert(s); - assert(spec); - assert(s->state == PA_SINK_RUNNING); - - CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec)); - - if (!map) - map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT); - if (!volume) - volume = pa_cvolume_reset(&tvol, spec->channels); - - CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map)); - CHECK_VALIDITY_RETURN_NULL(volume && pa_cvolume_valid(volume)); - CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels); - CHECK_VALIDITY_RETURN_NULL(volume->channels == spec->channels); - CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver)); - CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name)); - - if (pa_idxset_size(s->inputs) >= PA_MAX_INPUTS_PER_SINK) { + char st[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + assert(core); + assert(data); + + if (!(flags & PA_SINK_INPUT_NO_HOOKS)) + if (pa_hook_fire(&core->hook_sink_input_new, data) < 0) + return NULL; + + CHECK_VALIDITY_RETURN_NULL(!data->driver || pa_utf8_valid(data->driver)); + CHECK_VALIDITY_RETURN_NULL(!data->name || pa_utf8_valid(data->name)); + + if (!data->sink) + data->sink = pa_namereg_get(core, NULL, PA_NAMEREG_SINK, 1); + + CHECK_VALIDITY_RETURN_NULL(data->sink && data->sink->state == PA_SINK_RUNNING); + + if (!data->sample_spec_is_set) + data->sample_spec = data->sink->sample_spec; + + CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(&data->sample_spec)); + + if (!data->channel_map_is_set) + pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); + + CHECK_VALIDITY_RETURN_NULL(pa_channel_map_valid(&data->channel_map)); + CHECK_VALIDITY_RETURN_NULL(data->channel_map.channels == data->sample_spec.channels); + + if (!data->volume_is_set) + pa_cvolume_reset(&data->volume, data->sample_spec.channels); + + CHECK_VALIDITY_RETURN_NULL(pa_cvolume_valid(&data->volume)); + CHECK_VALIDITY_RETURN_NULL(data->volume.channels == data->sample_spec.channels); + + if (data->resample_method == PA_RESAMPLER_INVALID) + data->resample_method = core->resample_method; + + CHECK_VALIDITY_RETURN_NULL(data->resample_method < PA_RESAMPLER_MAX); + + if (pa_idxset_size(data->sink->inputs) >= PA_MAX_INPUTS_PER_SINK) { pa_log_warn(__FILE__": Failed to create sink input: too many inputs per sink."); return NULL; } - if (resample_method == PA_RESAMPLER_INVALID) - resample_method = s->core->resample_method; - - if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec) || !pa_channel_map_equal(map, &s->channel_map)) - if (!(resampler = pa_resampler_new(spec, map, &s->sample_spec, &s->channel_map, s->core->memblock_stat, resample_method))) { + if ((flags & PA_SINK_INPUT_VARIABLE_RATE) || + !pa_sample_spec_equal(&data->sample_spec, &data->sink->sample_spec) || + !pa_channel_map_equal(&data->channel_map, &data->sink->channel_map)) + + if (!(resampler = pa_resampler_new( + &data->sample_spec, &data->channel_map, + &data->sink->sample_spec, &data->sink->channel_map, + core->memblock_stat, + data->resample_method))) { pa_log_warn(__FILE__": Unsupported resampling operation."); return NULL; } @@ -100,15 +146,16 @@ pa_sink_input* pa_sink_input_new( i = pa_xnew(pa_sink_input, 1); i->ref = 1; i->state = PA_SINK_INPUT_DRAINED; - i->name = pa_xstrdup(name); - i->driver = pa_xstrdup(driver); - i->owner = NULL; - i->sink = s; - i->client = NULL; - - i->sample_spec = *spec; - i->channel_map = *map; - i->volume = *volume; + i->flags = flags; + i->name = pa_xstrdup(data->name); + i->driver = pa_xstrdup(data->driver); + i->module = data->module; + i->sink = data->sink; + i->client = data->client; + + i->sample_spec = data->sample_spec; + i->channel_map = data->channel_map; + i->volume = data->volume; i->peek = NULL; i->drop = NULL; @@ -116,25 +163,26 @@ pa_sink_input* pa_sink_input_new( i->get_latency = NULL; i->underrun = NULL; i->userdata = NULL; + i->move_silence = 0; pa_memchunk_reset(&i->resampled_chunk); i->resampler = resampler; - i->resample_method = resample_method; - i->variable_rate = variable_rate; - + i->resample_method = data->resample_method; i->silence_memblock = NULL; - assert(s->core); - r = pa_idxset_put(s->core->sink_inputs, i, &i->index); - assert(r == 0 && i->index != PA_IDXSET_INVALID); - r = pa_idxset_put(s->inputs, i, NULL); + r = pa_idxset_put(core->sink_inputs, i, &i->index); + assert(r == 0); + r = pa_idxset_put(i->sink->inputs, i, NULL); assert(r == 0); - pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"", i->index, i->name, s->index, st); - - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index); + pa_log_info(__FILE__": created %u \"%s\" on %s with sample spec %s", + i->index, + i->name, + i->sink->name, + pa_sample_spec_snprint(st, sizeof(st), &i->sample_spec)); + + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index); /* We do not call pa_sink_notify() here, because the virtual * functions have not yet been initialized */ diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index d33f382b..243978fe 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -27,11 +27,13 @@ typedef struct pa_sink_input pa_sink_input; #include -#include +#include #include #include #include #include +#include +#include typedef enum pa_sink_input_state { PA_SINK_INPUT_RUNNING, /*< The stream is alive and kicking */ @@ -40,20 +42,25 @@ typedef enum pa_sink_input_state { PA_SINK_INPUT_DISCONNECTED /*< The stream is dead */ } pa_sink_input_state_t; +typedef enum pa_sink_input_flags { + PA_SINK_INPUT_VARIABLE_RATE = 1, + PA_SINK_INPUT_NO_HOOKS = 2 +} pa_sink_input_flags_t; + struct pa_sink_input { int ref; uint32_t index; pa_sink_input_state_t state; + pa_sink_input_flags_t flags; char *name, *driver; /* may be NULL */ - pa_module *owner; /* may be NULL */ + pa_module *module; /* may be NULL */ + pa_client *client; /* may be NULL */ pa_sink *sink; - pa_client *client; /* may be NULL */ pa_sample_spec sample_spec; pa_channel_map channel_map; - pa_cvolume volume; /* Some silence to play before the actual data. This is used to @@ -78,15 +85,29 @@ struct pa_sink_input { pa_memblock *silence_memblock; /* may be NULL */ }; -pa_sink_input* pa_sink_input_new( - pa_sink *s, - const char *driver, - const char *name, - const pa_sample_spec *spec, - const pa_channel_map *map, - const pa_cvolume *volume, - int variable_rate, - pa_resample_method_t resample_method); +typedef struct pa_sink_input_new_data { + const char *name, *driver; + pa_module *module; + pa_client *client; + + pa_sink *sink; + + pa_sample_spec sample_spec; + int sample_spec_is_set; + pa_channel_map channel_map; + int channel_map_is_set; + pa_cvolume volume; + int volume_is_set; + + pa_resample_method_t resample_method; +} pa_sink_input_new_data; + +pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data); +void pa_sink_input_new_data_set_sample_spec(pa_sink_input_new_data *data, const pa_sample_spec *spec); +void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const pa_channel_map *map); +void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume); + +pa_sink_input* pa_sink_input_new(pa_core *core, pa_sink_input_new_data *data, pa_sink_input_flags_t flags); void pa_sink_input_unref(pa_sink_input* i); pa_sink_input* pa_sink_input_ref(pa_sink_input* i); diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c index 386f5bd0..6063b93e 100644 --- a/src/pulsecore/sound-file-stream.c +++ b/src/pulsecore/sound-file-stream.c @@ -120,13 +120,20 @@ static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t le } } -int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume) { +int pa_play_file( + pa_sink *sink, + const char *fname, + const pa_cvolume *volume) { + struct userdata *u = NULL; SF_INFO sfinfo; pa_sample_spec ss; - assert(sink && fname); + pa_sink_input_new_data data; + + assert(sink); + assert(fname); - u = pa_xmalloc(sizeof(struct userdata)); + u = pa_xnew(struct userdata, 1); u->sink_input = NULL; u->memchunk.memblock = NULL; u->memchunk.index = u->memchunk.length = 0; @@ -171,8 +178,15 @@ int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume) { pa_log(__FILE__": Unsupported sample format in file %s", fname); goto fail; } + + pa_sink_input_new_data_init(&data); + data.sink = sink; + data.driver = __FILE__; + data.name = fname; + pa_sink_input_new_data_set_sample_spec(&data, &ss); + pa_sink_input_new_data_set_volume(&data, volume); - if (!(u->sink_input = pa_sink_input_new(sink, __FILE__, fname, &ss, NULL, volume, 0, -1))) + if (!(u->sink_input = pa_sink_input_new(sink->core, &data, 0))) goto fail; u->sink_input->peek = sink_input_peek; @@ -180,7 +194,7 @@ int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume) { u->sink_input->kill = sink_input_kill; u->sink_input->userdata = u; - pa_sink_notify(sink); + pa_sink_notify(u->sink_input->sink); return 0; -- cgit From b37ad1ffd37b2e590191c3dced2b92bb72071dd2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 16:21:20 +0000 Subject: modify module-volume-restore to change the initial volume of a sink input from a hook instead of an asyncronous subscription event. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1238 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-volume-restore.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index d0956509..d49cceb0 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -68,6 +68,7 @@ struct rule { struct userdata { pa_hashmap *hashmap; pa_subscription *subscription; + pa_hook_slot *hook_slot; int modified; char *table_file; }; @@ -255,7 +256,7 @@ static char* client_name(pa_client *c) { return t; } -static void callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { +static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { struct userdata *u = userdata; pa_sink_input *si; struct rule *r; @@ -277,15 +278,11 @@ static void callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, v if ((r = pa_hashmap_get(u->hashmap, name))) { pa_xfree(name); - if (((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) && si->sample_spec.channels == r->volume.channels) { - pa_log_info(__FILE__": Restoring volume for <%s>", r->name); - pa_sink_input_set_volume(si, &r->volume); - } else if (!pa_cvolume_equal(pa_sink_input_get_volume(si), &r->volume)) { + if (!pa_cvolume_equal(pa_sink_input_get_volume(si), &r->volume)) { pa_log_info(__FILE__": Saving volume for <%s>", r->name); r->volume = *pa_sink_input_get_volume(si); u->modified = 1; } - } else { pa_log_info(__FILE__": Creating new entry for <%s>", name); @@ -298,6 +295,26 @@ static void callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, v } } +static pa_hook_result_t hook_callback(pa_core *c, pa_sink_input_new_data *data, struct userdata *u) { + struct rule *r; + char *name; + + assert(data); + + if (!data->client || !(name = client_name(data->client))) + return PA_HOOK_OK; + + if ((r = pa_hashmap_get(u->hashmap, name))) { + + if (data->sample_spec_is_set && data->sample_spec.channels == r->volume.channels) { + pa_log_info(__FILE__": Restoring volume for <%s>", r->name); + pa_sink_input_new_data_set_volume(data, &r->volume); + } + } + + return PA_HOOK_OK; +} + int pa__init(pa_core *c, pa_module*m) { pa_modargs *ma = NULL; struct userdata *u; @@ -321,7 +338,8 @@ int pa__init(pa_core *c, pa_module*m) { if (load_rules(u) < 0) goto fail; - u->subscription = pa_subscription_new(c, PA_SUBSCRIPTION_MASK_SINK_INPUT, callback, u); + u->subscription = pa_subscription_new(c, PA_SUBSCRIPTION_MASK_SINK_INPUT, subscribe_callback, u); + u->hook_slot = pa_hook_connect(&c->hook_sink_input_new, (pa_hook_cb_t) hook_callback, u); pa_modargs_free(ma); return 0; @@ -355,6 +373,9 @@ void pa__done(pa_core *c, pa_module*m) { if (u->subscription) pa_subscription_free(u->subscription); + if (u->hook_slot) + pa_hook_slot_free(u->hook_slot); + if (u->hashmap) { if (u->modified) -- cgit -- cgit From 72cf2118df6a3cb0515bcb426e2dc57c781fa2b1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 17:30:51 +0000 Subject: remove pa_sink_input::variable_rate field since it has been folded into pa_sink_input::flags git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1240 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/sink-input.c | 2 +- src/pulsecore/sink-input.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index ff5213e1..21050d22 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -532,7 +532,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { /* Try to reuse the old resampler if possible */ new_resampler = i->resampler; - else if (i->variable_rate || + else if ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) || !pa_sample_spec_equal(&i->sample_spec, &dest->sample_spec) || !pa_channel_map_equal(&i->channel_map, &dest->channel_map)) { diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 243978fe..da0c2662 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -79,7 +79,6 @@ struct pa_sink_input { pa_memchunk resampled_chunk; pa_resampler *resampler; /* may be NULL */ - int variable_rate; pa_resample_method_t resample_method; pa_memblock *silence_memblock; /* may be NULL */ -- cgit From abbabd848a3ece49d58f59c88edc379d73bbd77e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 17:31:58 +0000 Subject: ignore if we recieved a memory block for an invalid stream, since this might happen unwillingly due to the asychnronous nature of the protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1241 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index f922fb55..e5344448 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -2201,7 +2201,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o if (!(stream = pa_idxset_get_by_index(c->output_streams, channel))) { pa_log(__FILE__": client sent block for invalid stream."); - connection_free(c); + /* Ignoring */ return; } -- cgit From 87e64d58454f73bfa1e979b0fedfea7e0827d845 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 17:32:35 +0000 Subject: Clean up module description a little git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1242 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-volume-restore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index d49cceb0..bdead0f6 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -47,7 +47,7 @@ #include "module-volume-restore-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Playback stream automatic volume restore module") +PA_MODULE_DESCRIPTION("Automatically restore volume of playback streams") PA_MODULE_USAGE("table=") PA_MODULE_VERSION(PACKAGE_VERSION) -- cgit From 818083289882e8739bbfaefd1edb252ed5629771 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 17:33:32 +0000 Subject: properly implement a pa_sink_disconnect() hook git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1243 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/core.c | 4 ++-- src/pulsecore/core.h | 3 ++- src/pulsecore/sink.c | 4 +++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index 24f835f7..50d79fbf 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -93,7 +93,7 @@ pa_core* pa_core_new(pa_mainloop_api *m) { c->is_system_instance = 0; pa_hook_init(&c->hook_sink_input_new, c); - pa_hook_init(&c->hook_sink_input_disconnect, c); + pa_hook_init(&c->hook_sink_disconnect, c); pa_property_init(c); @@ -142,7 +142,7 @@ void pa_core_free(pa_core *c) { pa_property_cleanup(c); pa_hook_free(&c->hook_sink_input_new); - pa_hook_free(&c->hook_sink_input_disconnect); + pa_hook_free(&c->hook_sink_disconnect); pa_xfree(c); } diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index fd92de61..22dec50c 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -81,7 +81,8 @@ struct pa_core { int is_system_instance; /* hooks */ - pa_hook hook_sink_input_new, hook_sink_input_disconnect; + pa_hook hook_sink_input_new, + hook_sink_disconnect; }; pa_core* pa_core_new(pa_mainloop_api *m); diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index e770950c..557d5efc 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -143,7 +143,10 @@ void pa_sink_disconnect(pa_sink* s) { assert(s); assert(s->state == PA_SINK_RUNNING); + s->state = PA_SINK_DISCONNECTED; pa_namereg_unregister(s->core, s->name); + + pa_hook_fire(&s->core->hook_sink_disconnect, s); while ((i = pa_idxset_first(s->inputs, NULL))) { assert(i != j); @@ -163,7 +166,6 @@ void pa_sink_disconnect(pa_sink* s) { s->set_hw_mute = NULL; s->get_hw_mute = NULL; - s->state = PA_SINK_DISCONNECTED; pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); } -- cgit From dd8706115378193c8f8889526c108a2b49653619 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 17:34:36 +0000 Subject: implement new module "module-rescue-streams" which moves sink inputs away when their sink is removed. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1244 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 10 +++- src/modules/module-rescue-streams.c | 98 +++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/modules/module-rescue-streams.c diff --git a/src/Makefile.am b/src/Makefile.am index 3cf3168c..0ab0436b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -812,7 +812,8 @@ modlibexec_LTLIBRARIES += \ module-esound-sink.la \ module-http-protocol-tcp.la \ module-detect.la \ - module-volume-restore.la + module-volume-restore.la \ + module-rescue-streams.la # See comment at librtp.la above if !OS_IS_WIN32 @@ -955,6 +956,7 @@ SYMDEF_FILES = \ modules/module-jack-sink-symdef.h \ modules/module-jack-source-symdef.h \ modules/module-volume-restore-symdef.h \ + modules/module-rescue-streams-symdef.h \ modules/module-hal-detect-symdef.h \ modules/gconf/module-gconf-symdef.h @@ -1173,6 +1175,12 @@ module_volume_restore_la_LDFLAGS = -module -avoid-version module_volume_restore_la_LIBADD = $(AM_LIBADD) libpulsecore.la module_volume_restore_la_CFLAGS = $(AM_CFLAGS) +# Rescue streams module +module_rescue_streams_la_SOURCES = modules/module-rescue-streams.c +module_rescue_streams_la_LDFLAGS = -module -avoid-version +module_rescue_streams_la_LIBADD = $(AM_LIBADD) libpulsecore.la +module_rescue_streams_la_CFLAGS = $(AM_CFLAGS) + # RTP modules module_rtp_send_la_SOURCES = modules/rtp/module-rtp-send.c module_rtp_send_la_LDFLAGS = -module -avoid-version diff --git a/src/modules/module-rescue-streams.c b/src/modules/module-rescue-streams.c new file mode 100644 index 00000000..0e3946b1 --- /dev/null +++ b/src/modules/module-rescue-streams.c @@ -0,0 +1,98 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include + +#include "module-rescue-streams-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("When a sink/source is removed, try to move their streams to the default sink/source") +PA_MODULE_VERSION(PACKAGE_VERSION) + +static const char* const valid_modargs[] = { + NULL, +}; + +static pa_hook_result_t hook_callback(pa_core *c, pa_sink *sink, void* userdata) { + pa_sink_input *i; + pa_sink *target; + + assert(c); + assert(sink); + + if (!pa_idxset_size(sink->inputs)) { + pa_log_debug(__FILE__": No sink inputs to move away."); + return PA_HOOK_OK; + } + + if (!(target = pa_namereg_get(c, NULL, PA_NAMEREG_SINK, 0))) { + pa_log_info(__FILE__": No evacuation sink found."); + return PA_HOOK_OK; + } + + assert(target != sink); + + while ((i = pa_idxset_first(sink->inputs, NULL))) { + if (pa_sink_input_move_to(i, target, 1) < 0) { + pa_log_warn(__FILE__": Failed to move sink input %u \"%s\" to %s.", i->index, i->name, target->name); + return PA_HOOK_OK; + } + + pa_log_info(__FILE__": Sucessfully moved sink input %u \"%s\" to %s.", i->index, i->name, target->name); + } + + + return PA_HOOK_OK; +} + +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; + + assert(c); + assert(m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": Failed to parse module arguments"); + return -1; + } + + m->userdata = pa_hook_connect(&c->hook_sink_disconnect, (pa_hook_cb_t) hook_callback, NULL); + + pa_modargs_free(ma); + return 0; +} + +void pa__done(pa_core *c, pa_module*m) { + assert(c); + assert(m); + + if (m->userdata) + pa_hook_slot_free((pa_hook_slot*) m->userdata); +} -- cgit From a7b9a7d599d461b36d225849bdbf2d5c6ad73008 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 17:35:46 +0000 Subject: Load module-rescue-streams by default git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1245 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/default.pa.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in index ef6048d6..74148cd1 100755 --- a/src/daemon/default.pa.in +++ b/src/daemon/default.pa.in @@ -55,6 +55,9 @@ load-module module-native-protocol-unix ### Automatically restore the volume of playback streams load-module module-volume-restore +### Automatically move streams to the default sink if the sink they are connected to dies +load-module module-rescue-streams + ### Make some devices default #set-default-sink output #set-default-source input -- cgit From a09a49e41b086721ed644a0c9573e701e945287d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 17:39:19 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1246 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/todo b/todo index 7fbf01a8..573fc2a1 100644 --- a/todo +++ b/todo @@ -4,6 +4,7 @@ Build System: - Remove symdef files and use macros (like most other projects) - Use own name mangling scheme instead of ltdl's, which will eliminate the need for .la files or extra trickery. +- build pulsecore only statically by default, it's not a public API yet Porting: - rtp module ported to Win32 (sendmsg/recvmsg emulation) @@ -32,7 +33,8 @@ Features: - alsa mmap driver - alsa driver with hw mixing - allow passing data with shared memory between local clients and the server -- hooks for creating sink inputs/window manager for sound +- "window manager for sound" +- hooks for pa_source_output_new, pa_source_disconnect() - chroot() - use scatter/gather io for sockets - CODECs to reduce bandwidth usage (plug-in based) -- cgit From 8f91b1f4c4b47997ce4bfd70dc4e0f7fffe58a35 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 19:52:43 +0000 Subject: define new hooks: hook_source_output_new, hook_source_disconnect git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1247 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/core.c | 4 ++++ src/pulsecore/core.h | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index 50d79fbf..7f2f0f60 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -94,6 +94,8 @@ pa_core* pa_core_new(pa_mainloop_api *m) { pa_hook_init(&c->hook_sink_input_new, c); pa_hook_init(&c->hook_sink_disconnect, c); + pa_hook_init(&c->hook_source_output_new, c); + pa_hook_init(&c->hook_source_disconnect, c); pa_property_init(c); @@ -143,6 +145,8 @@ void pa_core_free(pa_core *c) { pa_hook_free(&c->hook_sink_input_new); pa_hook_free(&c->hook_sink_disconnect); + pa_hook_free(&c->hook_source_output_new); + pa_hook_free(&c->hook_source_disconnect); pa_xfree(c); } diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index 22dec50c..f9fa386e 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -81,8 +81,11 @@ struct pa_core { int is_system_instance; /* hooks */ - pa_hook hook_sink_input_new, - hook_sink_disconnect; + pa_hook + hook_sink_input_new, + hook_sink_disconnect, + hook_source_output_new, + hook_source_disconnect; }; pa_core* pa_core_new(pa_mainloop_api *m); -- cgit From 79cb80c5740dd00fae89464e7d03f1a7ade6ccdd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 19:53:18 +0000 Subject: implement hook_source_disconnect git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1248 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/source.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index ae72f040..0d55da44 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -125,7 +125,10 @@ void pa_source_disconnect(pa_source *s) { assert(s); assert(s->state == PA_SOURCE_RUNNING); + s->state = PA_SOURCE_DISCONNECTED; pa_namereg_unregister(s->core, s->name); + + pa_hook_fire(&s->core->hook_source_disconnect, s); while ((o = pa_idxset_first(s->outputs, NULL))) { assert(o != j); @@ -142,7 +145,6 @@ void pa_source_disconnect(pa_source *s) { s->set_hw_mute = NULL; s->get_hw_mute = NULL; - s->state = PA_SOURCE_DISCONNECTED; pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); } -- cgit From e0f7e8614ce06f2b0a4bd5a38189cf97b07c0d30 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 19:53:35 +0000 Subject: split a validity check into two git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1249 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/sink-input.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 21050d22..b3fabad3 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -101,7 +101,8 @@ pa_sink_input* pa_sink_input_new( if (!data->sink) data->sink = pa_namereg_get(core, NULL, PA_NAMEREG_SINK, 1); - CHECK_VALIDITY_RETURN_NULL(data->sink && data->sink->state == PA_SINK_RUNNING); + CHECK_VALIDITY_RETURN_NULL(data->sink); + CHECK_VALIDITY_RETURN_NULL(data->sink->state == PA_SINK_RUNNING); if (!data->sample_spec_is_set) data->sample_spec = data->sink->sample_spec; -- cgit From a75e1ed9ef483c4c08f0fc963c0ea1a980f0c0e9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 19:55:17 +0000 Subject: implement hook_source_ouput_new. For this I modified the pa_source_output_new constructor to take a struct similar to what I already did for pa_sink_input_new() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1250 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/rtp/module-rtp-send.c | 11 +++- src/pulsecore/cli-text.c | 4 +- src/pulsecore/protocol-esound.c | 26 +++++---- src/pulsecore/protocol-native.c | 17 ++++-- src/pulsecore/protocol-simple.c | 19 +++--- src/pulsecore/sink-input.h | 5 +- src/pulsecore/source-output.c | 119 +++++++++++++++++++++++++------------- src/pulsecore/source-output.h | 35 ++++++++--- 8 files changed, 160 insertions(+), 76 deletions(-) diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 5c47047f..52cd4052 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -168,6 +168,7 @@ int pa__init(pa_core *c, pa_module*m) { struct timeval tv; char hn[128], *n; int loop = 0; + pa_source_output_new_data data; assert(c); assert(m); @@ -263,8 +264,15 @@ int pa__init(pa_core *c, pa_module*m) { pa_log(__FILE__": IP_MULTICAST_LOOP failed: %s", pa_cstrerror(errno)); goto fail; } + + pa_source_output_new_data_init(&data); + data.name = "RTP Monitor Stream"; + data.driver = __FILE__; + data.module = m; + pa_source_output_new_data_set_sample_spec(&data, &ss); + pa_source_output_new_data_set_channel_map(&data, &cm); - if (!(o = pa_source_output_new(s, __FILE__, "RTP Monitor Stream", &ss, &cm, PA_RESAMPLER_INVALID))) { + if (!(o = pa_source_output_new(c, &data, 0))) { pa_log(__FILE__": failed to create source output."); goto fail; } @@ -272,7 +280,6 @@ int pa__init(pa_core *c, pa_module*m) { o->push = source_output_push; o->kill = source_output_kill; o->get_latency = source_output_get_latency; - o->owner = m; u = pa_xnew(struct userdata, 1); m->userdata = u; diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index ff083dc3..49934c07 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -204,8 +204,8 @@ char *pa_source_output_list_to_string(pa_core *c) { pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map), pa_resample_method_to_string(pa_source_output_get_resample_method(o))); - if (o->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", o->owner->index); + if (o->module) + pa_strbuf_printf(s, "\towner module: <%u>\n", o->module->index); if (o->client) pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", o->client->index, o->client->name); } diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 724dccbc..f1a827bc 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -349,9 +349,11 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t strncpy(name, data, sizeof(name)); name[sizeof(name)-1] = 0; + utf8_name = pa_utf8_filter(name); - pa_client_set_name(c->client, utf8_name); + pa_xfree(utf8_name); + c->original_name = pa_xstrdup(name); assert(!c->sink_input && !c->input_memblockq); @@ -359,15 +361,12 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t pa_sink_input_new_data_init(&sdata); sdata.sink = sink; sdata.driver = __FILE__; - sdata.name = utf8_name; + sdata.name = c->client->name; pa_sink_input_new_data_set_sample_spec(&sdata, &ss); sdata.module = c->protocol->module; sdata.client = c->client; c->sink_input = pa_sink_input_new(c->protocol->core, &sdata, 0); - - pa_xfree(utf8_name); - CHECK_VALIDITY(c->sink_input, "Failed to create sink input."); l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); @@ -402,6 +401,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co pa_source *source; pa_sample_spec ss; size_t l; + pa_source_output_new_data sdata; assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); @@ -450,10 +450,16 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co assert(!c->output_memblockq && !c->source_output); - if (!(c->source_output = pa_source_output_new(source, __FILE__, c->client->name, &ss, NULL, -1))) { - pa_log(__FILE__": failed to create source output"); - return -1; - } + pa_source_output_new_data_init(&sdata); + sdata.source = source; + sdata.driver = __FILE__; + sdata.name = c->client->name; + pa_source_output_new_data_set_sample_spec(&sdata, &ss); + sdata.module = c->protocol->module; + sdata.client = c->client; + + c->source_output = pa_source_output_new(c->protocol->core, &sdata, 9); + CHECK_VALIDITY(c->sink_input, "Failed to create source_output."); l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); c->output_memblockq = pa_memblockq_new( @@ -467,8 +473,6 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co c->protocol->core->memblock_stat); pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); - c->source_output->owner = c->protocol->module; - c->source_output->client = c->client; c->source_output->push = source_output_push_cb; c->source_output->kill = source_output_kill_cb; c->source_output->get_latency = source_output_get_latency_cb; diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index e5344448..0b79892c 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -317,9 +317,20 @@ static struct record_stream* record_stream_new( struct record_stream *s; pa_source_output *source_output; size_t base; + pa_source_output_new_data data; + assert(c && source && ss && name && maxlength); - if (!(source_output = pa_source_output_new(source, __FILE__, name, ss, map, -1))) + pa_source_output_new_data_init(&data); + data.source = source; + data.driver = __FILE__; + data.name = name; + pa_source_output_new_data_set_sample_spec(&data, ss); + pa_source_output_new_data_set_channel_map(&data, map); + data.module = c->protocol->module; + data.client = c->client; + + if (!(source_output = pa_source_output_new(source->core, &data, 0))) return NULL; s = pa_xnew(struct record_stream, 1); @@ -329,8 +340,6 @@ static struct record_stream* record_stream_new( s->source_output->kill = source_output_kill_cb; s->source_output->get_latency = source_output_get_latency_cb; s->source_output->userdata = s; - s->source_output->owner = c->protocol->module; - s->source_output->client = c->client; s->memblockq = pa_memblockq_new( 0, @@ -1356,7 +1365,7 @@ static void source_output_fill_tagstruct(pa_tagstruct *t, pa_source_output *s) { assert(t && s); pa_tagstruct_putu32(t, s->index); pa_tagstruct_puts(t, s->name); - pa_tagstruct_putu32(t, s->owner ? s->owner->index : PA_INVALID_INDEX); + pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX); pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX); pa_tagstruct_putu32(t, s->source->index); pa_tagstruct_put_sample_spec(t, &s->sample_spec); diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c index 5071191a..3705986d 100644 --- a/src/pulsecore/protocol-simple.c +++ b/src/pulsecore/protocol-simple.c @@ -379,22 +379,20 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) } if (p->mode & RECORD) { - pa_source *source; + pa_source_output_new_data data; size_t l; - if (!(source = pa_namereg_get(p->core, p->source_name, PA_NAMEREG_SOURCE, 1))) { - pa_log(__FILE__": Failed to get source."); - goto fail; - } + pa_source_output_new_data_init(&data); + data.driver = __FILE__; + data.name = c->client->name; + pa_source_output_new_data_set_sample_spec(&data, &p->sample_spec); + data.module = p->module; + data.client = c->client; - c->source_output = pa_source_output_new(source, __FILE__, c->client->name, &p->sample_spec, NULL, -1); - if (!c->source_output) { + if (!(c->source_output = pa_source_output_new(p->core, &data, 0))) { pa_log(__FILE__": Failed to create source output."); goto fail; } - c->source_output->owner = p->module; - c->source_output->client = c->client; - c->source_output->push = source_output_push_cb; c->source_output->kill = source_output_kill_cb; c->source_output->get_latency = source_output_get_latency_cb; @@ -411,6 +409,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) NULL, p->core->memblock_stat); pa_iochannel_socket_set_sndbuf(io, l/RECORD_BUFFER_FRAGMENTS*2); + pa_source_notify(c->source_output->source); } pa_iochannel_set_callback(c->io, io_callback, c); diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index da0c2662..2943dfae 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -106,7 +106,10 @@ void pa_sink_input_new_data_set_sample_spec(pa_sink_input_new_data *data, const void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const pa_channel_map *map); void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume); -pa_sink_input* pa_sink_input_new(pa_core *core, pa_sink_input_new_data *data, pa_sink_input_flags_t flags); +pa_sink_input* pa_sink_input_new( + pa_core *core, + pa_sink_input_new_data *data, + pa_sink_input_flags_t flags); void pa_sink_input_unref(pa_sink_input* i); pa_sink_input* pa_sink_input_ref(pa_sink_input* i); diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 36ea420c..7371474f 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -33,6 +33,7 @@ #include #include +#include #include "source-output.h" @@ -42,44 +43,82 @@ if (!(condition)) \ return NULL; \ } while (0) +pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_data *data) { + assert(data); + + memset(data, 0, sizeof(*data)); + data->resample_method = PA_RESAMPLER_INVALID; + return data; +} + +void pa_source_output_new_data_set_channel_map(pa_source_output_new_data *data, const pa_channel_map *map) { + assert(data); + + if ((data->channel_map_is_set = !!map)) + data->channel_map = *map; +} + +void pa_source_output_new_data_set_sample_spec(pa_source_output_new_data *data, const pa_sample_spec *spec) { + assert(data); + + if ((data->sample_spec_is_set = !!spec)) + data->sample_spec = *spec; +} + pa_source_output* pa_source_output_new( - pa_source *s, - const char *driver, - const char *name, - const pa_sample_spec *spec, - const pa_channel_map *map, - int resample_method) { + pa_core *core, + pa_source_output_new_data *data, + pa_source_output_flags_t flags) { pa_source_output *o; pa_resampler *resampler = NULL; int r; - char st[256]; - pa_channel_map tmap; + char st[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + assert(core); + assert(data); - assert(s); - assert(spec); - assert(s->state == PA_SOURCE_RUNNING); + if (!(flags & PA_SOURCE_OUTPUT_NO_HOOKS)) + if (pa_hook_fire(&core->hook_source_output_new, data) < 0) + return NULL; + + CHECK_VALIDITY_RETURN_NULL(!data->driver || pa_utf8_valid(data->driver)); + CHECK_VALIDITY_RETURN_NULL(!data->name || pa_utf8_valid(data->name)); + + if (!data->source) + data->source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE, 1); - CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec)); + CHECK_VALIDITY_RETURN_NULL(data->source); + CHECK_VALIDITY_RETURN_NULL(data->source->state == PA_SOURCE_RUNNING); + + if (!data->sample_spec_is_set) + data->sample_spec = data->source->sample_spec; + + CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(&data->sample_spec)); - if (!map) - map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT); + if (!data->channel_map_is_set) + pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); - CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map)); - CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels); - CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver)); - CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name)); + CHECK_VALIDITY_RETURN_NULL(pa_channel_map_valid(&data->channel_map)); + CHECK_VALIDITY_RETURN_NULL(data->channel_map.channels == data->sample_spec.channels); - if (pa_idxset_size(s->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { + if (data->resample_method == PA_RESAMPLER_INVALID) + data->resample_method = core->resample_method; + + CHECK_VALIDITY_RETURN_NULL(data->resample_method < PA_RESAMPLER_MAX); + + if (pa_idxset_size(data->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { pa_log(__FILE__": Failed to create source output: too many outputs per source."); return NULL; } - if (resample_method == PA_RESAMPLER_INVALID) - resample_method = s->core->resample_method; - - if (!pa_sample_spec_equal(&s->sample_spec, spec) || !pa_channel_map_equal(&s->channel_map, map)) - if (!(resampler = pa_resampler_new(&s->sample_spec, &s->channel_map, spec, map, s->core->memblock_stat, resample_method))) { + if (!pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec) || + !pa_channel_map_equal(&data->channel_map, &data->source->channel_map)) + if (!(resampler = pa_resampler_new( + &data->source->sample_spec, &data->source->channel_map, + &data->sample_spec, &data->channel_map, + core->memblock_stat, + data->resample_method))) { pa_log_warn(__FILE__": Unsupported resampling operation."); return NULL; } @@ -87,14 +126,14 @@ pa_source_output* pa_source_output_new( o = pa_xnew(pa_source_output, 1); o->ref = 1; o->state = PA_SOURCE_OUTPUT_RUNNING; - o->name = pa_xstrdup(name); - o->driver = pa_xstrdup(driver); - o->owner = NULL; - o->source = s; - o->client = NULL; + o->name = pa_xstrdup(data->name); + o->driver = pa_xstrdup(data->driver); + o->module = data->module; + o->source = data->source; + o->client = data->client; - o->sample_spec = *spec; - o->channel_map = *map; + o->sample_spec = data->sample_spec; + o->channel_map = data->channel_map; o->push = NULL; o->kill = NULL; @@ -102,18 +141,20 @@ pa_source_output* pa_source_output_new( o->userdata = NULL; o->resampler = resampler; - o->resample_method = resample_method; + o->resample_method = data->resample_method; - assert(s->core); - r = pa_idxset_put(s->core->source_outputs, o, &o->index); - assert(r == 0 && o->index != PA_IDXSET_INVALID); - r = pa_idxset_put(s->outputs, o, NULL); + r = pa_idxset_put(core->source_outputs, o, &o->index); + assert(r == 0); + r = pa_idxset_put(o->source->outputs, o, NULL); assert(r == 0); - pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"", o->index, o->name, s->index, st); + pa_log_info(__FILE__": created %u \"%s\" on %s with sample spec %s", + o->index, + o->name, + o->source->name, + pa_sample_spec_snprint(st, sizeof(st), &o->sample_spec)); - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); /* We do not call pa_source_notify() here, because the virtual * functions have not yet been initialized */ diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index acf53bd1..f7396a19 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -39,13 +39,17 @@ typedef enum { PA_SOURCE_OUTPUT_DISCONNECTED } pa_source_output_state_t; +typedef enum pa_source_output_flags { + PA_SOURCE_OUTPUT_NO_HOOKS = 1 +} pa_source_output_flags_t; + struct pa_source_output { int ref; uint32_t index; pa_source_output_state_t state; char *name, *driver; /* may be NULL */ - pa_module *owner; /* may be NULL */ + pa_module *module; /* may be NULL */ pa_source *source; pa_client *client; /* may be NULL */ @@ -63,13 +67,30 @@ struct pa_source_output { void *userdata; }; +typedef struct pa_source_output_new_data { + const char *name, *driver; + pa_module *module; + pa_client *client; + + pa_source *source; + + pa_sample_spec sample_spec; + int sample_spec_is_set; + pa_channel_map channel_map; + int channel_map_is_set; + + pa_resample_method_t resample_method; +} pa_source_output_new_data; + +pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_data *data); +void pa_source_output_new_data_set_sample_spec(pa_source_output_new_data *data, const pa_sample_spec *spec); +void pa_source_output_new_data_set_channel_map(pa_source_output_new_data *data, const pa_channel_map *map); +void pa_source_output_new_data_set_volume(pa_source_output_new_data *data, const pa_cvolume *volume); + pa_source_output* pa_source_output_new( - pa_source *s, - const char *driver, - const char *name, - const pa_sample_spec *spec, - const pa_channel_map *map, - int resample_method); + pa_core *core, + pa_source_output_new_data *data, + pa_source_output_flags_t flags); void pa_source_output_unref(pa_source_output* o); pa_source_output* pa_source_output_ref(pa_source_output *o); -- cgit From d182a0b1cb2eede12a7e3f902d9f2d374a2a6838 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 20:43:22 +0000 Subject: minor optimization git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1251 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/dynarray.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/dynarray.c b/src/pulsecore/dynarray.c index d1ab1161..cd1fcb0f 100644 --- a/src/pulsecore/dynarray.c +++ b/src/pulsecore/dynarray.c @@ -90,7 +90,7 @@ unsigned pa_dynarray_append(pa_dynarray*a, void *p) { void *pa_dynarray_get(pa_dynarray*a, unsigned i) { assert(a); - if (i >= a->n_allocated) + if (i >= a->n_entries) return NULL; assert(a->data); -- cgit From cdb173f6aba3e514d5d5c0abbd07e2722dd4d205 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 20:44:00 +0000 Subject: create rtp source output on correct source git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1252 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/rtp/module-rtp-send.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 52cd4052..759aa819 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -269,6 +269,7 @@ int pa__init(pa_core *c, pa_module*m) { data.name = "RTP Monitor Stream"; data.driver = __FILE__; data.module = m; + data.source = s; pa_source_output_new_data_set_sample_spec(&data, &ss); pa_source_output_new_data_set_channel_map(&data, &cm); -- cgit From 3334814ebb3c955b696c413ac5246ddb09efefe2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 20:44:32 +0000 Subject: fix a segfault when registering a service with avahi fails git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1253 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-zeroconf-publish.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index 16315d35..24e324f8 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -225,9 +225,8 @@ finish: if (s->published == UNPUBLISHED) { /* Remove this service */ - if (s->entry_group) { + if (s->entry_group) avahi_entry_group_free(s->entry_group); - } pa_hashmap_remove(u->services, s->name); pa_xfree(s->name); @@ -263,6 +262,7 @@ static struct service *get_service(struct userdata *u, const char *name) { static int publish_sink(struct userdata *u, pa_sink *s) { struct service *svc; + int ret; assert(u && s); svc = get_service(u, s->name); @@ -273,13 +273,17 @@ static int publish_sink(struct userdata *u, pa_sink *s) { svc->loaded.type = PA_NAMEREG_SINK; svc->loaded.index = s->index; - pa_dynarray_put(u->sink_dynarray, s->index, svc); + if ((ret = publish_service(u, svc)) < 0) + return ret; - return publish_service(u, svc); + pa_dynarray_put(u->sink_dynarray, s->index, svc); + return ret; } static int publish_source(struct userdata *u, pa_source *s) { struct service *svc; + int ret; + assert(u && s); svc = get_service(u, s->name); @@ -292,11 +296,17 @@ static int publish_source(struct userdata *u, pa_source *s) { pa_dynarray_put(u->source_dynarray, s->index, svc); - return publish_service(u, svc); + if ((ret = publish_service(u, svc)) < 0) + return ret; + + pa_dynarray_put(u->sink_dynarray, s->index, svc); + return ret; } static int publish_autoload(struct userdata *u, pa_autoload_entry *s) { struct service *svc; + int ret; + assert(u && s); svc = get_service(u, s->name); @@ -307,9 +317,11 @@ static int publish_autoload(struct userdata *u, pa_autoload_entry *s) { svc->autoload.type = s->type; svc->autoload.index = s->index; - pa_dynarray_put(u->autoload_dynarray, s->index, svc); + if ((ret = publish_service(u, svc)) < 0) + return ret; - return publish_service(u, svc); + pa_dynarray_put(u->autoload_dynarray, s->index, svc); + return ret; } static int remove_sink(struct userdata *u, uint32_t idx) { @@ -653,6 +665,9 @@ void pa__done(pa_core *c, pa_module*m) { if (u->services) pa_hashmap_free(u->services, service_free, u); + if (u->subscription) + pa_subscription_free(u->subscription); + if (u->sink_dynarray) pa_dynarray_free(u->sink_dynarray, NULL, NULL); if (u->source_dynarray) @@ -660,8 +675,6 @@ void pa__done(pa_core *c, pa_module*m) { if (u->autoload_dynarray) pa_dynarray_free(u->autoload_dynarray, NULL, NULL); - if (u->subscription) - pa_subscription_free(u->subscription); if (u->main_entry_group) avahi_entry_group_free(u->main_entry_group); -- cgit From 2bf46537136a73220771c899e86a52b1ee9b22d8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 20:45:19 +0000 Subject: extend module-rescue-streams to move also source outputs when a source dies git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1254 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-rescue-streams.c | 59 ++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/src/modules/module-rescue-streams.c b/src/modules/module-rescue-streams.c index 0e3946b1..5700ef43 100644 --- a/src/modules/module-rescue-streams.c +++ b/src/modules/module-rescue-streams.c @@ -26,6 +26,8 @@ #include #include +#include +#include #include #include #include @@ -40,7 +42,11 @@ static const char* const valid_modargs[] = { NULL, }; -static pa_hook_result_t hook_callback(pa_core *c, pa_sink *sink, void* userdata) { +struct userdata { + pa_hook_slot *sink_slot, *source_slot; +}; + +static pa_hook_result_t sink_hook_callback(pa_core *c, pa_sink *sink, void* userdata) { pa_sink_input *i; pa_sink *target; @@ -72,8 +78,41 @@ static pa_hook_result_t hook_callback(pa_core *c, pa_sink *sink, void* userdata) return PA_HOOK_OK; } +static pa_hook_result_t source_hook_callback(pa_core *c, pa_source *source, void* userdata) { + pa_source_output *o; + pa_source *target; + + assert(c); + assert(source); + + if (!pa_idxset_size(source->outputs)) { + pa_log_debug(__FILE__": No source outputs to move away."); + return PA_HOOK_OK; + } + + if (!(target = pa_namereg_get(c, NULL, PA_NAMEREG_SOURCE, 0))) { + pa_log_info(__FILE__": No evacuation source found."); + return PA_HOOK_OK; + } + + assert(target != source); + + while ((o = pa_idxset_first(source->outputs, NULL))) { + if (pa_source_output_move_to(o, target) < 0) { + pa_log_warn(__FILE__": Failed to move source output %u \"%s\" to %s.", o->index, o->name, target->name); + return PA_HOOK_OK; + } + + pa_log_info(__FILE__": Sucessfully moved source output %u \"%s\" to %s.", o->index, o->name, target->name); + } + + + return PA_HOOK_OK; +} + int pa__init(pa_core *c, pa_module*m) { pa_modargs *ma = NULL; + struct userdata *u; assert(c); assert(m); @@ -83,16 +122,28 @@ int pa__init(pa_core *c, pa_module*m) { return -1; } - m->userdata = pa_hook_connect(&c->hook_sink_disconnect, (pa_hook_cb_t) hook_callback, NULL); + m->userdata = u = pa_xnew(struct userdata, 1); + u->sink_slot = pa_hook_connect(&c->hook_sink_disconnect, (pa_hook_cb_t) sink_hook_callback, NULL); + u->source_slot = pa_hook_connect(&c->hook_source_disconnect, (pa_hook_cb_t) source_hook_callback, NULL); pa_modargs_free(ma); return 0; } void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c); assert(m); - if (m->userdata) - pa_hook_slot_free((pa_hook_slot*) m->userdata); + if (!m->userdata) + return; + + u = m->userdata; + if (u->sink_slot) + pa_hook_slot_free(u->sink_slot); + if (u->source_slot) + pa_hook_slot_free(u->source_slot); + + pa_xfree(u); } -- cgit From 5d8d9164747c0cded726e86b4fc84505305e87dd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 20:45:54 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1255 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 - 1 file changed, 1 deletion(-) diff --git a/todo b/todo index 573fc2a1..d4165481 100644 --- a/todo +++ b/todo @@ -34,7 +34,6 @@ Features: - alsa driver with hw mixing - allow passing data with shared memory between local clients and the server - "window manager for sound" -- hooks for pa_source_output_new, pa_source_disconnect() - chroot() - use scatter/gather io for sockets - CODECs to reduce bandwidth usage (plug-in based) -- cgit From 6c39af7ad368743463540e85982c63b9d351e7a2 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 14 Aug 2006 08:38:07 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1256 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 + 1 file changed, 1 insertion(+) diff --git a/todo b/todo index d4165481..2c67f6d5 100644 --- a/todo +++ b/todo @@ -45,6 +45,7 @@ Features: - examine if it is possible to mimic esd's handling of half duplex cards (switch to capture when a recording client connects and drop playback during that time) +- Support for device selection in waveout driver Long term: - pass meta info for hearing impaired -- cgit From 1c3bfc44dcbd760687ea841d893c35db510804af Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 15 Aug 2006 18:15:00 +0000 Subject: use the description field of sinks/sources to name the zeroconf services, instead of the logical name git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1257 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-zeroconf-publish.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index 24e324f8..651a95b7 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -240,7 +240,7 @@ finish: return r; } -static struct service *get_service(struct userdata *u, const char *name) { +static struct service *get_service(struct userdata *u, const char *name, const char *description) { struct service *s; char hn[64]; @@ -253,7 +253,7 @@ static struct service *get_service(struct userdata *u, const char *name) { s->published = UNPUBLISHED; s->name = pa_xstrdup(name); s->loaded.valid = s->autoload.valid = 0; - s->service_name = pa_sprintf_malloc("%s on %s", s->name, pa_get_host_name(hn, sizeof(hn))); + s->service_name = pa_sprintf_malloc("%s on %s", description ? description : s->name, pa_get_host_name(hn, sizeof(hn))); pa_hashmap_put(u->services, s->name, s); @@ -265,7 +265,7 @@ static int publish_sink(struct userdata *u, pa_sink *s) { int ret; assert(u && s); - svc = get_service(u, s->name); + svc = get_service(u, s->name, s->description); if (svc->loaded.valid) return publish_service(u, svc); @@ -286,7 +286,7 @@ static int publish_source(struct userdata *u, pa_source *s) { assert(u && s); - svc = get_service(u, s->name); + svc = get_service(u, s->name, s->description); if (svc->loaded.valid) return publish_service(u, svc); @@ -309,7 +309,7 @@ static int publish_autoload(struct userdata *u, pa_autoload_entry *s) { assert(u && s); - svc = get_service(u, s->name); + svc = get_service(u, s->name, NULL); if (svc->autoload.valid) return publish_service(u, svc); -- cgit From 99db0672c7866f6d622a3e342ad8a7b308e1f4dd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 17 Aug 2006 20:01:04 +0000 Subject: make PA_LLIST_HEAD_INIT thread safe git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1258 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/llist.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/llist.h b/src/pulsecore/llist.h index c50b8a78..31279431 100644 --- a/src/pulsecore/llist.h +++ b/src/pulsecore/llist.h @@ -34,7 +34,7 @@ #define PA_LLIST_FIELDS(t) t *next, *prev /* Initialize the list's head */ -#define PA_LLIST_HEAD_INIT(t,item) do { (item) = NULL; } while(0) +#define PA_LLIST_HEAD_INIT(t,item) do { (item) = (t*) NULL; } while(0) /* Initialize a list item */ #define PA_LLIST_INIT(t,item) do { \ -- cgit From d89066036ba2b6d62a728540baff3c1269515c22 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 17 Aug 2006 20:02:46 +0000 Subject: modify pa_bytes_snprint() to return the string we just wrote to. This should be binary compat with older versions which returned void git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1259 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/sample.c | 4 +++- src/pulse/sample.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pulse/sample.c b/src/pulse/sample.c index 87b2d7a0..7ca418e1 100644 --- a/src/pulse/sample.c +++ b/src/pulse/sample.c @@ -120,7 +120,7 @@ char *pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec) { return s; } -void pa_bytes_snprint(char *s, size_t l, unsigned v) { +char* pa_bytes_snprint(char *s, size_t l, unsigned v) { if (v >= ((unsigned) 1024)*1024*1024) snprintf(s, l, "%0.1f GiB", ((double) v)/1024/1024/1024); else if (v >= ((unsigned) 1024)*1024) @@ -129,6 +129,8 @@ void pa_bytes_snprint(char *s, size_t l, unsigned v) { snprintf(s, l, "%0.1f KiB", ((double) v)/1024); else snprintf(s, l, "%u B", (unsigned) v); + + return s; } pa_sample_format_t pa_parse_sample_format(const char *format) { diff --git a/src/pulse/sample.h b/src/pulse/sample.h index 03965a99..da32fdf0 100644 --- a/src/pulse/sample.h +++ b/src/pulse/sample.h @@ -182,7 +182,7 @@ pa_sample_format_t pa_parse_sample_format(const char *format); char* pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec); /** Pretty print a byte size value. (i.e. "2.5 MiB") */ -void pa_bytes_snprint(char *s, size_t l, unsigned v); +char* pa_bytes_snprint(char *s, size_t l, unsigned v); PA_C_DECL_END -- cgit From a847f74ed0fcc268a4dd23ac5b310db6026982a5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 17 Aug 2006 20:03:09 +0000 Subject: add missing #include git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1260 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/random.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pulsecore/random.h b/src/pulsecore/random.h index f809afec..b2bb3934 100644 --- a/src/pulsecore/random.h +++ b/src/pulsecore/random.h @@ -22,6 +22,8 @@ USA. ***/ +#include + void pa_random_seed(void); void pa_random(void *ret_data, size_t length); -- cgit From c3df1ceb3827e3ffaef6c6182270ce0c7d325518 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 17 Aug 2006 20:03:38 +0000 Subject: fix a PA_LLIST_HEAD_INIT invocation git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1261 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/hook-list.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/hook-list.c b/src/pulsecore/hook-list.c index 72b206b2..91c2598b 100644 --- a/src/pulsecore/hook-list.c +++ b/src/pulsecore/hook-list.c @@ -24,7 +24,7 @@ void pa_hook_init(pa_hook *hook, void *data) { assert(hook); - PA_LLIST_HEAD_INIT(pa_hook_slots, hook->slots); + PA_LLIST_HEAD_INIT(pa_hook_slot, hook->slots); hook->last = NULL; hook->n_dead = hook->firing = 0; hook->data = data; -- cgit From 8be0cf60079da8f75933fa128f91efefbd73d5c5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 19:42:14 +0000 Subject: cleanup idxset.[ch] a little: define proper types for the hash/compare funcs, do ptr->int/int->ptr conversions with clean macros git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1262 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/idxset.c | 10 +++++----- src/pulsecore/idxset.h | 10 +++++++++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/pulsecore/idxset.c b/src/pulsecore/idxset.c index 23fe0b5a..ee0137a3 100644 --- a/src/pulsecore/idxset.c +++ b/src/pulsecore/idxset.c @@ -42,8 +42,8 @@ typedef struct idxset_entry { } idxset_entry; struct pa_idxset { - unsigned (*hash_func) (const void *p); - int (*compare_func)(const void *a, const void *b); + pa_hash_func_t hash_func; + pa_compare_func_t compare_func; unsigned hash_table_size, n_entries; idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail; @@ -65,21 +65,21 @@ int pa_idxset_string_compare_func(const void *a, const void *b) { } unsigned pa_idxset_trivial_hash_func(const void *p) { - return (unsigned) (long) p; + return PA_PTR_TO_UINT(p); } int pa_idxset_trivial_compare_func(const void *a, const void *b) { return a != b; } -pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { +pa_idxset* pa_idxset_new(pa_hash_func_t hash_func, pa_compare_func_t compare_func) { pa_idxset *s; s = pa_xnew(pa_idxset, 1); s->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; s->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; s->hash_table_size = 127; - s->hash_table = pa_xmalloc0(sizeof(idxset_entry*)*s->hash_table_size); + s->hash_table = pa_xnew0(idxset_entry*, s->hash_table_size); s->array = NULL; s->array_size = 0; s->index = 0; diff --git a/src/pulsecore/idxset.h b/src/pulsecore/idxset.h index 3d0bc75f..1765e843 100644 --- a/src/pulsecore/idxset.h +++ b/src/pulsecore/idxset.h @@ -41,10 +41,18 @@ int pa_idxset_trivial_compare_func(const void *a, const void *b); unsigned pa_idxset_string_hash_func(const void *p); int pa_idxset_string_compare_func(const void *a, const void *b); +#define PA_PTR_TO_UINT(p) ((unsigned int) (unsigned long) (p)) +#define PA_UINT_TO_PTR(u) ((void*) (unsigned long) (u)) +#define PA_PTR_TO_UINT32(p) ((uint32_t) PA_PTR_TO_UINT(p)) +#define PA_UINT32_TO_PTR(u) PA_UINT_TO_PTR(u) + +typedef unsigned (*pa_hash_func_t)(const void *p); +typedef int (*pa_compare_func_t)(const void *a, const void *b); + typedef struct pa_idxset pa_idxset; /* Instantiate a new idxset with the specified hash and comparison functions */ -pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); +pa_idxset* pa_idxset_new(pa_hash_func_t hash_func, pa_compare_func_t compare_func); /* Free the idxset. When the idxset is not empty the specified function is called for every entry contained */ void pa_idxset_free(pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata); -- cgit From dfa17b9f36f5741be05e144c15a8e89fceae9415 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 19:43:46 +0000 Subject: cleanup hashmap.[ch] a little: use hash/compare func prototypes defined in idxset.h, add pa_hashmpa_{get,steal}_first git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1263 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/hashmap.c | 49 +++++++++++++++++++++++++++++++++++++++---------- src/pulsecore/hashmap.h | 8 +++++++- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/src/pulsecore/hashmap.c b/src/pulsecore/hashmap.c index 6e0e6b02..81a160a6 100644 --- a/src/pulsecore/hashmap.c +++ b/src/pulsecore/hashmap.c @@ -49,22 +49,25 @@ struct pa_hashmap { struct hashmap_entry *first_entry; unsigned n_entries; - unsigned (*hash_func) (const void *p); - int (*compare_func) (const void*a, const void*b); + pa_hash_func_t hash_func; + pa_compare_func_t compare_func; }; -pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)) { +pa_hashmap *pa_hashmap_new(pa_hash_func_t hash_func, pa_compare_func_t compare_func) { pa_hashmap *h; - h = pa_xmalloc(sizeof(pa_hashmap)); - h->data = pa_xmalloc0(sizeof(struct hashmap_entry*)*(h->size = BUCKETS)); + + h = pa_xnew(pa_hashmap, 1); + h->data = pa_xnew0(struct hashmap_entry*, h->size = BUCKETS); h->first_entry = NULL; h->n_entries = 0; h->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; h->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; + return h; } static void remove(pa_hashmap *h, struct hashmap_entry *e) { + assert(h); assert(e); if (e->next) @@ -102,7 +105,8 @@ void pa_hashmap_free(pa_hashmap*h, void (*free_func)(void *p, void *userdata), v static struct hashmap_entry *get(pa_hashmap *h, unsigned hash, const void *key) { struct hashmap_entry *e; - assert(h && hash < h->size); + assert(h); + assert(hash < h->size); for (e = h->data[hash]; e; e = e->bucket_next) if (h->compare_func(e->key, key) == 0) @@ -121,7 +125,7 @@ int pa_hashmap_put(pa_hashmap *h, const void *key, void *value) { if ((e = get(h, hash, key))) return -1; - e = pa_xmalloc(sizeof(struct hashmap_entry)); + e = pa_xnew(struct hashmap_entry, 1); e->hash = hash; e->key = key; e->value = value; @@ -145,7 +149,8 @@ int pa_hashmap_put(pa_hashmap *h, const void *key, void *value) { void* pa_hashmap_get(pa_hashmap *h, const void *key) { unsigned hash; struct hashmap_entry *e; - assert(h && key); + + assert(h); hash = h->hash_func(key) % h->size; @@ -159,7 +164,8 @@ void* pa_hashmap_remove(pa_hashmap *h, const void *key) { struct hashmap_entry *e; unsigned hash; void *data; - assert(h && key); + + assert(h); hash = h->hash_func(key) % h->size; @@ -176,7 +182,8 @@ unsigned pa_hashmap_size(pa_hashmap *h) { } void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void **key) { - assert(h && state); + assert(h); + assert(state); if (!*state) *state = h->first_entry; @@ -194,3 +201,25 @@ void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void **key) { return ((struct hashmap_entry*) *state)->value; } + +void* pa_hashmap_steal_first(pa_hashmap *h) { + void *data; + + assert(h); + + if (!h->first_entry) + return NULL; + + data = h->first_entry->value; + remove(h, h->first_entry); + return data; +} + +void *pa_hashmap_get_first(pa_hashmap *h) { + assert(h); + + if (!h->first_entry) + return NULL; + + return h->first_entry->value; +} diff --git a/src/pulsecore/hashmap.h b/src/pulsecore/hashmap.h index 3f62adb1..b8a358ec 100644 --- a/src/pulsecore/hashmap.h +++ b/src/pulsecore/hashmap.h @@ -22,6 +22,8 @@ USA. ***/ +#include + /* Simple Implementation of a hash table. Memory management is the * user's job. It's a good idea to have the key pointer point to a * string in the value data. */ @@ -29,7 +31,7 @@ typedef struct pa_hashmap pa_hashmap; /* Create a new hashmap. Use the specified functions for hashing and comparing objects in the map */ -pa_hashmap *pa_hashmap_new(unsigned (*hash_func) (const void *p), int (*compare_func) (const void*a, const void*b)); +pa_hashmap *pa_hashmap_new(pa_hash_func_t hash_func, pa_compare_func_t compare_func); /* Free the hash table. Calls the specified function for every value in the table. The function may be NULL */ void pa_hashmap_free(pa_hashmap*, void (*free_func)(void *p, void *userdata), void *userdata); @@ -50,4 +52,8 @@ unsigned pa_hashmap_size(pa_hashmap *h); is returned. */ void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void**key); +void *pa_hashmap_steal_first(pa_hashmap *h); + +void *pa_hashmap_get_first(pa_hashmap *h); + #endif -- cgit From 20d0823e35e62165cc4bf277020814521117a632 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 19:45:19 +0000 Subject: fix a bad type cast git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1264 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/pdispatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c index db54b2a3..e1653d64 100644 --- a/src/pulsecore/pdispatch.c +++ b/src/pulsecore/pdispatch.c @@ -137,7 +137,7 @@ pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_cb_ pd->mainloop = mainloop; pd->callback_table = table; pd->n_commands = entries; - PA_LLIST_HEAD_INIT(pa_reply_info, pd->replies); + PA_LLIST_HEAD_INIT(struct reply_info, pd->replies); pd->drain_callback = NULL; pd->drain_userdata = NULL; pd->creds = NULL; -- cgit From ff48681aaef919cd2c85e4572928e936397a615c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 19:46:20 +0000 Subject: add abstracted shared memory API git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1265 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/shm.c | 224 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/pulsecore/shm.h | 42 ++++++++++ 2 files changed, 266 insertions(+) create mode 100644 src/pulsecore/shm.c create mode 100644 src/pulsecore/shm.h diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c new file mode 100644 index 00000000..ad9dc46a --- /dev/null +++ b/src/pulsecore/shm.c @@ -0,0 +1,224 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "shm.h" + +#if defined(__linux__) && !defined(MADV_REMOVE) +#define MADV_REMOVE 9 +#endif + +#define MAX_SHM_SIZE (1024*1024*20) + +static char *segment_name(char *fn, size_t l, unsigned id) { + snprintf(fn, l, "/pulse-shm-%u", id); + return fn; +} + +int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { + char fn[32]; + int fd = -1; + + assert(m); + assert(size > 0); + assert(size < MAX_SHM_SIZE); + assert(mode >= 0600); + + if (!shared) { + m->id = 0; + m->size = size; + +#ifdef MAP_ANONYMOUS + if ((m->ptr = mmap(NULL, m->size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS, fd, 0)) == MAP_FAILED) { + pa_log(__FILE__": mmap() failed: %s", pa_cstrerror(errno)); + goto fail; + } +#else + m->ptr = pa_xmalloc(m->size); +#endif + + m->do_unlink = 0; + + } else { + pa_random(&m->id, sizeof(m->id)); + segment_name(fn, sizeof(fn), m->id); + + if ((fd = shm_open(fn, O_RDWR|O_CREAT|O_EXCL, mode & 0444)) < 0) { + pa_log(__FILE__": shm_open() failed: %s", pa_cstrerror(errno)); + goto fail; + } + + if (ftruncate(fd, m->size = size) < 0) { + pa_log(__FILE__": ftruncate() failed: %s", pa_cstrerror(errno)); + goto fail; + } + + if ((m->ptr = mmap(NULL, m->size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { + pa_log(__FILE__": mmap() failed: %s", pa_cstrerror(errno)); + goto fail; + } + + close(fd); + m->do_unlink = 1; + } + + m->shared = shared; + + return 0; + +fail: + + if (fd >= 0) { + shm_unlink(fn); + close(fd); + } + + return -1; +} + +void pa_shm_free(pa_shm *m) { + char fn[32]; + + assert(m); + assert(m->ptr && m->ptr != MAP_FAILED); + assert(m->size > 0); + +#ifndef MAP_ANONYMOUS + if (!m->shared) + pa_xfree(m->ptr); + else +#endif + + if (munmap(m->ptr, m->size) < 0) + pa_log(__FILE__": munmap() failed: %s", pa_cstrerror(errno)); + + if (m->do_unlink) { + segment_name(fn, sizeof(fn), m->id); + + if (shm_unlink(fn) < 0) + pa_log(__FILE__":shm_unlink(%s) failed: %s", fn, pa_cstrerror(errno)); + } + + memset(m, 0, sizeof(*m)); +} + +void pa_shm_punch(pa_shm *m, size_t offset, size_t size) { + void *ptr; + + assert(m); + assert(m->ptr && m->ptr != MAP_FAILED); + assert(m->size > 0); + assert(m->do_unlink); + assert(offset < m->size); + assert(offset+size < m->size); + + /* You're welcome to implement this as NOOP on systems that don't + * support it */ + + ptr = (uint8_t*) m->ptr + offset; + +#ifdef __linux__ +{ + /* On Linux ptr must be page aligned */ + long psz = sysconf(_SC_PAGESIZE); + unsigned o; + + o = ((unsigned long) ptr) - ((((unsigned long) ptr)/psz) * psz); + + if (o > 0) { + ptr = (uint8_t*) ptr + (psz - o); + size -= psz - o; + } +} +#endif + +#ifdef MADV_REMOVE + if (madvise(ptr, size, MADV_REMOVE) >= 0) + return; +#endif + +#ifdef MADV_FREE + if (madvise(ptr, size, MADV_FREE) >= 0) + return; +#endif + +#ifdef MADV_DONTNEED + madvise(ptr, size, MADV_DONTNEED); +#endif +} + +int pa_shm_attach_ro(pa_shm *m, unsigned id) { + char fn[32]; + int fd = -1; + struct stat st; + + assert(m); + + segment_name(fn, sizeof(fn), m->id = id); + + if ((fd = shm_open(fn, O_RDONLY, 0)) < 0) { + pa_log(__FILE__": shm_open() failed: %s", pa_cstrerror(errno)); + goto fail; + } + + if (fstat(fd, &st) < 0) { + pa_log(__FILE__": fstat() failed: %s", pa_cstrerror(errno)); + goto fail; + } + + if (st.st_size <= 0 || st.st_size > MAX_SHM_SIZE) { + pa_log(__FILE__": Invalid shared memory segment size"); + goto fail; + } + + m->size = st.st_size; + + if ((m->ptr = mmap(NULL, m->size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { + pa_log(__FILE__": mmap() failed: %s", pa_cstrerror(errno)); + goto fail; + } + + m->do_unlink = 0; + m->shared = 1; + + close(fd); + + return 0; + +fail: + if (fd >= 0) + close(fd); + + return -1; +} diff --git a/src/pulsecore/shm.h b/src/pulsecore/shm.h new file mode 100644 index 00000000..ea72403a --- /dev/null +++ b/src/pulsecore/shm.h @@ -0,0 +1,42 @@ +#ifndef foopulseshmhfoo +#define foopulseshmhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef struct pa_shm { + unsigned id; + void *ptr; + size_t size; + int do_unlink; + int shared; +} pa_shm; + +int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode); +int pa_shm_attach_ro(pa_shm *m, unsigned id); + +void pa_shm_punch(pa_shm *m, size_t offset, size_t size); + +void pa_shm_free(pa_shm *m); + +#endif -- cgit From 0e436a6926af56f37a74a03bb5e143e078ca0d55 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 19:55:18 +0000 Subject: Rework memory management to allow shared memory data transfer. The central idea is to allocate all audio memory blocks from a per-process memory pool which is available as read-only SHM segment to other local processes. Then, instead of writing the actual audio data to the socket just write references to this shared memory pool. To work optimally all memory blocks should now be of type PA_MEMBLOCK_POOL or PA_MEMBLOCK_POOL_EXTERNAL. The function pa_memblock_new() now generates memory blocks of this type by default. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1266 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/main.c | 2 +- src/modules/module-alsa-sink.c | 2 +- src/modules/module-alsa-source.c | 2 +- src/modules/module-combine.c | 3 +- src/modules/module-jack-source.c | 2 +- src/modules/module-oss-mmap.c | 6 +- src/modules/module-oss.c | 4 +- src/modules/module-pipe-source.c | 2 +- src/modules/module-sine.c | 2 +- src/modules/module-tunnel.c | 2 +- src/modules/rtp/module-rtp-recv.c | 11 +- src/modules/rtp/module-rtp-send.c | 3 +- src/modules/rtp/rtp.c | 4 +- src/modules/rtp/rtp.h | 2 +- src/pulse/context.c | 8 +- src/pulse/internal.h | 2 +- src/pulse/stream.c | 7 +- src/pulsecore/cli-command.c | 40 ++- src/pulsecore/core-scache.c | 4 +- src/pulsecore/core.c | 6 +- src/pulsecore/core.h | 4 +- src/pulsecore/mcalign.c | 6 +- src/pulsecore/mcalign.h | 2 +- src/pulsecore/memblock.c | 737 ++++++++++++++++++++++++++++++++++---- src/pulsecore/memblock.h | 108 ++++-- src/pulsecore/memblockq.c | 7 +- src/pulsecore/memblockq.h | 3 +- src/pulsecore/memchunk.c | 9 +- src/pulsecore/memchunk.h | 2 +- src/pulsecore/protocol-esound.c | 10 +- src/pulsecore/protocol-native.c | 25 +- src/pulsecore/protocol-simple.c | 8 +- src/pulsecore/pstream.c | 396 ++++++++++++++++---- src/pulsecore/pstream.h | 4 +- src/pulsecore/resampler.c | 21 +- src/pulsecore/resampler.h | 12 +- src/pulsecore/sample-util.c | 7 +- src/pulsecore/sample-util.h | 2 +- src/pulsecore/sink-input.c | 12 +- src/pulsecore/sink.c | 6 +- src/pulsecore/sound-file-stream.c | 2 +- src/pulsecore/sound-file.c | 4 +- src/pulsecore/sound-file.h | 2 +- src/pulsecore/source-output.c | 4 +- src/pulsecore/source.c | 2 +- 45 files changed, 1216 insertions(+), 293 deletions(-) diff --git a/src/daemon/main.c b/src/daemon/main.c index 38d465f8..aada0ad7 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -559,7 +559,7 @@ int main(int argc, char *argv[]) { mainloop = pa_mainloop_new(); assert(mainloop); - c = pa_core_new(pa_mainloop_get_api(mainloop)); + c = pa_core_new(pa_mainloop_get_api(mainloop), 1); assert(c); c->is_system_instance = !!conf->system_instance; diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 8da3d236..0cebd50f 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -492,7 +492,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log_info(__FILE__": using %u fragments of size %lu bytes.", periods, (long unsigned)u->fragment_size); - u->silence.memblock = pa_memblock_new(u->silence.length = u->fragment_size, c->memblock_stat); + u->silence.memblock = pa_memblock_new(c->mempool, u->silence.length = u->fragment_size); assert(u->silence.memblock); pa_silence_memblock(u->silence.memblock, &ss); u->silence.index = 0; diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 4a8678c9..c3979df1 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -151,7 +151,7 @@ static void do_read(struct userdata *u) { size_t l; if (!u->memchunk.memblock) { - u->memchunk.memblock = pa_memblock_new(u->memchunk.length = u->fragment_size, u->source->core->memblock_stat); + u->memchunk.memblock = pa_memblock_new(u->source->core->mempool, u->memchunk.length = u->fragment_size); u->memchunk.index = 0; } diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 008fe6e7..5243975b 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -235,8 +235,7 @@ static struct output *output_new(struct userdata *u, pa_sink *sink, int resample pa_frame_size(&u->sink->sample_spec), 1, 0, - NULL, - sink->core->memblock_stat); + NULL); snprintf(t, sizeof(t), "%s: output #%u", u->sink->name, u->n_outputs+1); diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index 583f3b8e..8e659198 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -137,7 +137,7 @@ static void io_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_ fs = pa_frame_size(&u->source->sample_spec); - chunk.memblock = pa_memblock_new(chunk.length = u->frames_posted * fs, u->core->memblock_stat); + chunk.memblock = pa_memblock_new(u->core->mempool, chunk.length = u->frames_posted * fs); chunk.index = 0; for (frame_idx = 0; frame_idx < u->frames_posted; frame_idx ++) { diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index c783a2f1..75ab9a9e 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -162,10 +162,10 @@ static void out_fill_memblocks(struct userdata *u, unsigned n) { chunk.memblock = u->out_memblocks[u->out_current] = pa_memblock_new_fixed( + u->core->mempool, (uint8_t*) u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size, - 1, - u->core->memblock_stat); + 1); assert(chunk.memblock); chunk.length = chunk.memblock->length; chunk.index = 0; @@ -210,7 +210,7 @@ static void in_post_memblocks(struct userdata *u, unsigned n) { pa_memchunk chunk; if (!u->in_memblocks[u->in_current]) { - chunk.memblock = u->in_memblocks[u->in_current] = pa_memblock_new_fixed((uint8_t*) u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size, 1, u->core->memblock_stat); + chunk.memblock = u->in_memblocks[u->in_current] = pa_memblock_new_fixed(u->core->mempool, (uint8_t*) u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size, 1); chunk.length = chunk.memblock->length; chunk.index = 0; diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index ce11ee02..b9b80e72 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -217,7 +217,7 @@ static void do_read(struct userdata *u) { } do { - memchunk.memblock = pa_memblock_new(l, u->core->memblock_stat); + memchunk.memblock = pa_memblock_new(u->core->mempool, l); assert(memchunk.memblock); if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); @@ -503,7 +503,7 @@ int pa__init(pa_core *c, pa_module*m) { u->out_fragment_size = out_frag_size; u->in_fragment_size = in_frag_size; - u->silence.memblock = pa_memblock_new(u->silence.length = u->out_fragment_size, u->core->memblock_stat); + u->silence.memblock = pa_memblock_new(u->core->mempool, u->silence.length = u->out_fragment_size); assert(u->silence.memblock); pa_silence_memblock(u->silence.memblock, &ss); u->silence.index = 0; diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index 5caa60a3..43a8dab5 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -91,7 +91,7 @@ static void do_read(struct userdata *u) { pa_module_set_used(u->module, pa_idxset_size(u->source->outputs)); if (!u->chunk.memblock) { - u->chunk.memblock = pa_memblock_new(1024, u->core->memblock_stat); + u->chunk.memblock = pa_memblock_new(u->core->mempool, PIPE_BUF); u->chunk.index = chunk.length = 0; } diff --git a/src/modules/module-sine.c b/src/modules/module-sine.c index 5ceddce0..89c3c609 100644 --- a/src/modules/module-sine.c +++ b/src/modules/module-sine.c @@ -139,7 +139,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - u->memblock = pa_memblock_new(pa_bytes_per_second(&ss), c->memblock_stat); + u->memblock = pa_memblock_new(c->mempool, pa_bytes_per_second(&ss)); calc_sine(u->memblock->data, u->memblock->length, frequency); snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency); diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 9bb11c09..53bffd3b 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -651,7 +651,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata return; } - u->pstream = pa_pstream_new(u->core->mainloop, io, u->core->memblock_stat); + u->pstream = pa_pstream_new(u->core->mainloop, io, u->core->mempool); u->pdispatch = pa_pdispatch_new(u->core->mainloop, command_table, PA_COMMAND_MAX); pa_pstream_set_die_callback(u->pstream, pstream_die_callback, u); diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index df6f8c11..5d3f3e27 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -150,7 +150,7 @@ static void rtp_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event assert(fd == s->rtp_context.fd); assert(flags == PA_IO_EVENT_INPUT); - if (pa_rtp_recv(&s->rtp_context, &chunk, s->userdata->core->memblock_stat) < 0) + if (pa_rtp_recv(&s->rtp_context, &chunk, s->userdata->core->mempool) < 0) return; if (s->sdp_info.payload != s->rtp_context.payload) { @@ -312,10 +312,10 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in s->sink_input->kill = sink_input_kill; s->sink_input->get_latency = sink_input_get_latency; - silence = pa_silence_memblock_new(&s->sink_input->sample_spec, + silence = pa_silence_memblock_new(s->userdata->core->mempool, + &s->sink_input->sample_spec, (pa_bytes_per_second(&s->sink_input->sample_spec)/128/pa_frame_size(&s->sink_input->sample_spec))* - pa_frame_size(&s->sink_input->sample_spec), - s->userdata->core->memblock_stat); + pa_frame_size(&s->sink_input->sample_spec)); s->memblockq = pa_memblockq_new( 0, @@ -324,8 +324,7 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in pa_frame_size(&s->sink_input->sample_spec), pa_bytes_per_second(&s->sink_input->sample_spec)/10+1, 0, - silence, - u->core->memblock_stat); + silence); pa_memblock_unref(silence); diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 759aa819..1b85c840 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -297,8 +297,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_frame_size(&ss), 1, 0, - NULL, - c->memblock_stat); + NULL); u->mtu = mtu; diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c index ee037d42..8e77c60a 100644 --- a/src/modules/rtp/rtp.c +++ b/src/modules/rtp/rtp.c @@ -149,7 +149,7 @@ pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd, size_t frame return c; } -int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_memblock_stat *st) { +int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { int size; struct msghdr m; struct iovec iov; @@ -170,7 +170,7 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_memblock_stat *st) { if (!size) return 0; - chunk->memblock = pa_memblock_new(size, st); + chunk->memblock = pa_memblock_new(pool, size); iov.iov_base = chunk->memblock->data; iov.iov_len = size; diff --git a/src/modules/rtp/rtp.h b/src/modules/rtp/rtp.h index 35fbbd35..123602b2 100644 --- a/src/modules/rtp/rtp.h +++ b/src/modules/rtp/rtp.h @@ -41,7 +41,7 @@ pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssr int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q); pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd, size_t frame_size); -int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_memblock_stat *st); +int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool); void pa_rtp_context_destroy(pa_rtp_context *c); diff --git a/src/pulse/context.c b/src/pulse/context.c index 34f517f0..b3530542 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -128,7 +128,7 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { c->subscribe_callback = NULL; c->subscribe_userdata = NULL; - c->memblock_stat = pa_memblock_stat_new(); + c->mempool = pa_mempool_new(1); c->local = -1; c->server_list = NULL; c->server = NULL; @@ -177,7 +177,7 @@ static void context_free(pa_context *c) { if (c->playback_streams) pa_dynarray_free(c->playback_streams, NULL, NULL); - pa_memblock_stat_unref(c->memblock_stat); + pa_mempool_free(c->mempool); if (c->conf) pa_client_conf_free(c->conf); @@ -407,7 +407,9 @@ static void setup_context(pa_context *c, pa_iochannel *io) { pa_context_ref(c); assert(!c->pstream); - c->pstream = pa_pstream_new(c->mainloop, io, c->memblock_stat); + c->pstream = pa_pstream_new(c->mainloop, io, c->mempool); + + pa_pstream_use_shm(c->pstream, 1); pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); diff --git a/src/pulse/internal.h b/src/pulse/internal.h index 96028d83..afcfaeff 100644 --- a/src/pulse/internal.h +++ b/src/pulse/internal.h @@ -69,7 +69,7 @@ struct pa_context { pa_context_subscribe_cb_t subscribe_callback; void *subscribe_userdata; - pa_memblock_stat *memblock_stat; + pa_mempool *mempool; int local; int do_autospawn; diff --git a/src/pulse/stream.c b/src/pulse/stream.c index 677df009..180cd096 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -437,8 +437,7 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED pa_frame_size(&s->sample_spec), 1, 0, - NULL, - s->context->memblock_stat); + NULL); } s->channel_valid = 1; @@ -604,9 +603,9 @@ int pa_stream_write( return 0; if (free_cb) - chunk.memblock = pa_memblock_new_user((void*) data, length, free_cb, 1, s->context->memblock_stat); + chunk.memblock = pa_memblock_new_user(s->context->mempool, (void*) data, length, free_cb, 1); else { - chunk.memblock = pa_memblock_new(length, s->context->memblock_stat); + chunk.memblock = pa_memblock_new(s->context->mempool, length); memcpy(chunk.memblock->data, data, length); } diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index f74258d3..811b96d2 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -100,6 +100,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); /* A method table for all available commands */ @@ -144,6 +145,7 @@ static const struct command commands[] = { { "list-props", pa_cli_command_list_props, NULL, 1}, { "move-sink-input", pa_cli_command_move_sink_input, "Move sink input to another sink (args: index, sink)", 3}, { "move-source-output", pa_cli_command_move_source_output, "Move source output to another source (args: index, source)", 3}, + { "vacuum", pa_cli_command_vacuum, NULL, 1}, { NULL, NULL, NULL, 0 } }; @@ -239,23 +241,32 @@ static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { char s[256]; + const pa_mempool_stat *stat; assert(c && t); - pa_bytes_snprint(s, sizeof(s), c->memblock_stat->total_size); + stat = pa_mempool_get_stat(c->mempool); + pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n", - c->memblock_stat->total, - s); + stat->n_allocated, + pa_bytes_snprint(s, sizeof(s), stat->allocated_size)); - pa_bytes_snprint(s, sizeof(s), c->memblock_stat->allocated_size); pa_strbuf_printf(buf, "Memory blocks allocated during the whole lifetime: %u, size: %s.\n", - c->memblock_stat->allocated, - s); + stat->n_accumulated, + pa_bytes_snprint(s, sizeof(s), stat->accumulated_size)); + + pa_strbuf_printf(buf, "Memory blocks imported from other processes: %u, size: %s.\n", + stat->n_imported, + pa_bytes_snprint(s, sizeof(s), stat->imported_size)); - pa_bytes_snprint(s, sizeof(s), pa_scache_total_size(c)); - pa_strbuf_printf(buf, "Total sample cache size: %s.\n", s); + pa_strbuf_printf(buf, "Memory blocks exported to other processes: %u, size: %s.\n", + stat->n_exported, + pa_bytes_snprint(s, sizeof(s), stat->exported_size)); - pa_sample_spec_snprint(s, sizeof(s), &c->default_sample_spec); - pa_strbuf_printf(buf, "Default sample spec: %s\n", s); + pa_strbuf_printf(buf, "Total sample cache size: %s.\n", + pa_bytes_snprint(s, sizeof(s), pa_scache_total_size(c))); + + pa_strbuf_printf(buf, "Default sample spec: %s\n", + pa_sample_spec_snprint(s, sizeof(s), &c->default_sample_spec)); pa_strbuf_printf(buf, "Default sink name: %s\n" "Default source name: %s\n", @@ -731,6 +742,15 @@ static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf return 0; } +static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + assert(c); + assert(t); + + pa_mempool_vacuum(c->mempool); + + return 0; +} + static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *n, *k; pa_sink_input *si; diff --git a/src/pulsecore/core-scache.c b/src/pulsecore/core-scache.c index 377dd569..ca2408fe 100644 --- a/src/pulsecore/core-scache.c +++ b/src/pulsecore/core-scache.c @@ -176,7 +176,7 @@ int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint3 filename = buf; #endif - if (pa_sound_file_load(filename, &ss, &map, &chunk, c->memblock_stat) < 0) + if (pa_sound_file_load(c->mempool, filename, &ss, &map, &chunk) < 0) return -1; r = pa_scache_add_item(c, name, &ss, &map, &chunk, idx); @@ -261,7 +261,7 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t return -1; if (e->lazy && !e->memchunk.memblock) { - if (pa_sound_file_load(e->filename, &e->sample_spec, &e->channel_map, &e->memchunk, c->memblock_stat) < 0) + if (pa_sound_file_load(c->mempool, e->filename, &e->sample_spec, &e->channel_map, &e->memchunk) < 0) return -1; pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index 7f2f0f60..5fdeab56 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -44,7 +44,7 @@ #include "core.h" -pa_core* pa_core_new(pa_mainloop_api *m) { +pa_core* pa_core_new(pa_mainloop_api *m, int shared) { pa_core* c; c = pa_xnew(pa_core, 1); @@ -78,7 +78,7 @@ pa_core* pa_core_new(pa_mainloop_api *m) { PA_LLIST_HEAD_INIT(pa_subscription_event, c->subscription_event_queue); c->subscription_event_last = NULL; - c->memblock_stat = pa_memblock_stat_new(); + c->mempool = pa_mempool_new(shared); c->disallow_module_loading = 0; @@ -139,7 +139,7 @@ void pa_core_free(pa_core *c) { pa_xfree(c->default_source_name); pa_xfree(c->default_sink_name); - pa_memblock_stat_unref(c->memblock_stat); + pa_mempool_free(c->mempool); pa_property_cleanup(c); diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index f9fa386e..3a34d297 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -67,7 +67,7 @@ struct pa_core { PA_LLIST_HEAD(pa_subscription_event, subscription_event_queue); pa_subscription_event *subscription_event_last; - pa_memblock_stat *memblock_stat; + pa_mempool *mempool; int disallow_module_loading, running_as_daemon; int exit_idle_time, module_idle_time, scache_idle_time; @@ -88,7 +88,7 @@ struct pa_core { hook_source_disconnect; }; -pa_core* pa_core_new(pa_mainloop_api *m); +pa_core* pa_core_new(pa_mainloop_api *m, int shared); void pa_core_free(pa_core*c); /* Check whether noone is connected to this core */ diff --git a/src/pulsecore/mcalign.c b/src/pulsecore/mcalign.c index 8283a7a0..9ede610d 100644 --- a/src/pulsecore/mcalign.c +++ b/src/pulsecore/mcalign.c @@ -35,10 +35,9 @@ struct pa_mcalign { size_t base; pa_memchunk leftover, current; - pa_memblock_stat *memblock_stat; }; -pa_mcalign *pa_mcalign_new(size_t base, pa_memblock_stat *s) { +pa_mcalign *pa_mcalign_new(size_t base) { pa_mcalign *m; assert(base); @@ -47,7 +46,6 @@ pa_mcalign *pa_mcalign_new(size_t base, pa_memblock_stat *s) { m->base = base; pa_memchunk_reset(&m->leftover); pa_memchunk_reset(&m->current); - m->memblock_stat = s; return m; } @@ -100,7 +98,7 @@ void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { l = c->length; /* Can we use the current block? */ - pa_memchunk_make_writable(&m->leftover, m->memblock_stat, m->base); + pa_memchunk_make_writable(&m->leftover, m->base); memcpy((uint8_t*) m->leftover.memblock->data + m->leftover.index + m->leftover.length, (uint8_t*) c->memblock->data + c->index, l); m->leftover.length += l; diff --git a/src/pulsecore/mcalign.h b/src/pulsecore/mcalign.h index 80e37499..94e99e21 100644 --- a/src/pulsecore/mcalign.h +++ b/src/pulsecore/mcalign.h @@ -63,7 +63,7 @@ typedef struct pa_mcalign pa_mcalign; -pa_mcalign *pa_mcalign_new(size_t base, pa_memblock_stat *s); +pa_mcalign *pa_mcalign_new(size_t base); void pa_mcalign_free(pa_mcalign *m); /* Push a new memchunk into the aligner. The caller of this routine diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 36de17fb..4ce1b7c1 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -27,86 +27,271 @@ #include #include #include +#include #include +#include +#include +#include + #include "memblock.h" -static void stat_add(pa_memblock*m, pa_memblock_stat *s) { - assert(m); +#define PA_MEMPOOL_SLOTS_MAX 128 +#define PA_MEMPOOL_SLOT_SIZE (16*1024) - if (!s) { - m->stat = NULL; - return; - } +#define PA_MEMEXPORT_SLOTS_MAX 128 + +#define PA_MEMIMPORT_SLOTS_MAX 128 +#define PA_MEMIMPORT_SEGMENTS_MAX 16 + +struct pa_memimport_segment { + pa_memimport *import; + pa_shm memory; + unsigned n_blocks; +}; + +struct pa_memimport { + pa_mempool *pool; + pa_hashmap *segments; + pa_hashmap *blocks; + + /* Called whenever an imported memory block is no longer + * needed. */ + pa_memimport_release_cb_t release_cb; + void *userdata; + + PA_LLIST_FIELDS(pa_memimport); +}; + +struct memexport_slot { + PA_LLIST_FIELDS(struct memexport_slot); + pa_memblock *block; +}; + +struct pa_memexport { + pa_mempool *pool; + + struct memexport_slot slots[PA_MEMEXPORT_SLOTS_MAX]; + PA_LLIST_HEAD(struct memexport_slot, free_slots); + PA_LLIST_HEAD(struct memexport_slot, used_slots); + unsigned n_init; + + /* Called whenever a client from which we imported a memory block + which we in turn exported to another client dies and we need to + revoke the memory block accordingly */ + pa_memexport_revoke_cb_t revoke_cb; + void *userdata; + + PA_LLIST_FIELDS(pa_memexport); +}; + +struct mempool_slot { + PA_LLIST_FIELDS(struct mempool_slot); + /* the actual data follows immediately hereafter */ +}; - m->stat = pa_memblock_stat_ref(s); - s->total++; - s->allocated++; - s->total_size += m->length; - s->allocated_size += m->length; +struct pa_mempool { + pa_shm memory; + size_t block_size; + unsigned n_blocks, n_init; + + PA_LLIST_HEAD(pa_memimport, imports); + PA_LLIST_HEAD(pa_memexport, exports); + + /* A list of free slots that may be reused */ + PA_LLIST_HEAD(struct mempool_slot, free_slots); + PA_LLIST_HEAD(struct mempool_slot, used_slots); + + pa_mempool_stat stat; +}; + +static void segment_detach(pa_memimport_segment *seg); + +static void stat_add(pa_memblock*b) { + assert(b); + assert(b->pool); + + b->pool->stat.n_allocated ++; + b->pool->stat.n_accumulated ++; + b->pool->stat.allocated_size += b->length; + b->pool->stat.accumulated_size += b->length; + + if (b->type == PA_MEMBLOCK_IMPORTED) { + b->pool->stat.n_imported++; + b->pool->stat.imported_size += b->length; + } } -static void stat_remove(pa_memblock *m) { - assert(m); +static void stat_remove(pa_memblock *b) { + assert(b); + assert(b->pool); - if (!m->stat) - return; + assert(b->pool->stat.n_allocated > 0); + assert(b->pool->stat.allocated_size >= b->length); + + b->pool->stat.n_allocated --; + b->pool->stat.allocated_size -= b->length; + + if (b->type == PA_MEMBLOCK_IMPORTED) { + assert(b->pool->stat.n_imported > 0); + assert(b->pool->stat.imported_size >= b->length); + + b->pool->stat.n_imported --; + b->pool->stat.imported_size -= b->length; + } +} - m->stat->total--; - m->stat->total_size -= m->length; +static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length); + +pa_memblock *pa_memblock_new(pa_mempool *p, size_t length) { + pa_memblock *b; - pa_memblock_stat_unref(m->stat); - m->stat = NULL; + assert(p); + assert(length > 0); + + if (!(b = pa_memblock_new_pool(p, length))) + b = memblock_new_appended(p, length); + + return b; } -pa_memblock *pa_memblock_new(size_t length, pa_memblock_stat*s) { - pa_memblock *b = pa_xmalloc(sizeof(pa_memblock)+length); +static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length) { + pa_memblock *b; + + assert(p); + assert(length > 0); + + b = pa_xmalloc(sizeof(pa_memblock) + length); b->type = PA_MEMBLOCK_APPENDED; + b->read_only = 0; b->ref = 1; b->length = length; - b->data = b+1; - b->free_cb = NULL; - b->read_only = 0; - stat_add(b, s); + b->data = (uint8_t*) b + sizeof(pa_memblock); + b->pool = p; + + stat_add(b); return b; } -pa_memblock *pa_memblock_new_dynamic(void *d, size_t length, pa_memblock_stat*s) { - pa_memblock *b = pa_xmalloc(sizeof(pa_memblock)); - b->type = PA_MEMBLOCK_DYNAMIC; - b->ref = 1; +static struct mempool_slot* mempool_allocate_slot(pa_mempool *p) { + struct mempool_slot *slot; + assert(p); + + if (p->free_slots) { + slot = p->free_slots; + PA_LLIST_REMOVE(struct mempool_slot, p->free_slots, slot); + } else if (p->n_init < p->n_blocks) + slot = (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->block_size * p->n_init++)); + else { + pa_log_debug(__FILE__": Pool full"); + p->stat.n_pool_full++; + return NULL; + } + + PA_LLIST_PREPEND(struct mempool_slot, p->used_slots, slot); + return slot; +} + +static void* mempool_slot_data(struct mempool_slot *slot) { + assert(slot); + + return (uint8_t*) slot + sizeof(struct mempool_slot); +} + +static unsigned mempool_slot_idx(pa_mempool *p, void *ptr) { + assert(p); + assert((uint8_t*) ptr >= (uint8_t*) p->memory.ptr); + assert((uint8_t*) ptr < (uint8_t*) p->memory.ptr + p->memory.size); + + return ((uint8_t*) ptr - (uint8_t*) p->memory.ptr) / p->block_size; +} + +static struct mempool_slot* mempool_slot_by_ptr(pa_mempool *p, void *ptr) { + unsigned idx; + + if ((idx = mempool_slot_idx(p, ptr)) == (unsigned) -1) + return NULL; + + return (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (idx * p->block_size)); +} + +pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) { + pa_memblock *b = NULL; + struct mempool_slot *slot; + + assert(p); + assert(length > 0); + + if (p->block_size - sizeof(struct mempool_slot) >= sizeof(pa_memblock) + length) { + + if (!(slot = mempool_allocate_slot(p))) + return NULL; + + b = mempool_slot_data(slot); + b->type = PA_MEMBLOCK_POOL; + b->data = (uint8_t*) b + sizeof(pa_memblock); + + } else if (p->block_size - sizeof(struct mempool_slot) >= length) { + + if (!(slot = mempool_allocate_slot(p))) + return NULL; + + b = pa_xnew(pa_memblock, 1); + b->type = PA_MEMBLOCK_POOL_EXTERNAL; + b->data = mempool_slot_data(slot); + } else { + pa_log_debug(__FILE__": Memory block to large for pool: %u > %u", length, p->block_size - sizeof(struct mempool_slot)); + p->stat.n_too_large_for_pool++; + return NULL; + } + b->length = length; - b->data = d; - b->free_cb = NULL; b->read_only = 0; - stat_add(b, s); + b->ref = 1; + b->pool = p; + + stat_add(b); return b; } -pa_memblock *pa_memblock_new_fixed(void *d, size_t length, int read_only, pa_memblock_stat*s) { - pa_memblock *b = pa_xmalloc(sizeof(pa_memblock)); +pa_memblock *pa_memblock_new_fixed(pa_mempool *p, void *d, size_t length, int read_only) { + pa_memblock *b; + + assert(p); + assert(d); + assert(length > 0); + + b = pa_xnew(pa_memblock, 1); b->type = PA_MEMBLOCK_FIXED; + b->read_only = read_only; b->ref = 1; b->length = length; b->data = d; - b->free_cb = NULL; - b->read_only = read_only; - stat_add(b, s); + b->pool = p; + + stat_add(b); return b; } -pa_memblock *pa_memblock_new_user(void *d, size_t length, void (*free_cb)(void *p), int read_only, pa_memblock_stat*s) { +pa_memblock *pa_memblock_new_user(pa_mempool *p, void *d, size_t length, void (*free_cb)(void *p), int read_only) { pa_memblock *b; - assert(d && length && free_cb); - b = pa_xmalloc(sizeof(pa_memblock)); + + assert(p); + assert(d); + assert(length > 0); + assert(free_cb); + + b = pa_xnew(pa_memblock, 1); b->type = PA_MEMBLOCK_USER; + b->read_only = read_only; b->ref = 1; b->length = length; b->data = d; - b->free_cb = free_cb; - b->read_only = read_only; - stat_add(b, s); + b->per_type.user.free_cb = free_cb; + b->pool = p; + + stat_add(b); return b; } @@ -122,52 +307,458 @@ void pa_memblock_unref(pa_memblock*b) { assert(b); assert(b->ref >= 1); - if ((--(b->ref)) == 0) { - stat_remove(b); + if ((--(b->ref)) > 0) + return; + + stat_remove(b); + + switch (b->type) { + case PA_MEMBLOCK_USER : + assert(b->per_type.user.free_cb); + b->per_type.user.free_cb(b->data); + + /* Fall through */ + + case PA_MEMBLOCK_FIXED: + case PA_MEMBLOCK_APPENDED : + pa_xfree(b); + break; + + case PA_MEMBLOCK_IMPORTED : { + pa_memimport_segment *segment; + + segment = b->per_type.imported.segment; + assert(segment); + assert(segment->import); + + pa_hashmap_remove(segment->import->blocks, PA_UINT32_TO_PTR(b->per_type.imported.id)); + segment->import->release_cb(segment->import, b->per_type.imported.id, segment->import->userdata); + + if (-- segment->n_blocks <= 0) + segment_detach(segment); + + pa_xfree(b); + break; + } - if (b->type == PA_MEMBLOCK_USER) { - assert(b->free_cb); - b->free_cb(b->data); - } else if (b->type == PA_MEMBLOCK_DYNAMIC) - pa_xfree(b->data); + case PA_MEMBLOCK_POOL_EXTERNAL: + case PA_MEMBLOCK_POOL: { + struct mempool_slot *slot; - pa_xfree(b); + slot = mempool_slot_by_ptr(b->pool, b->data); + assert(slot); + + PA_LLIST_REMOVE(struct mempool_slot, b->pool->used_slots, slot); + PA_LLIST_PREPEND(struct mempool_slot, b->pool->free_slots, slot); + + if (b->type == PA_MEMBLOCK_POOL_EXTERNAL) + pa_xfree(b); + } } } +static void memblock_make_local(pa_memblock *b) { + assert(b); + + if (b->length <= b->pool->block_size - sizeof(struct mempool_slot)) { + struct mempool_slot *slot; + + if ((slot = mempool_allocate_slot(b->pool))) { + void *new_data; + /* We can move it into a local pool, perfect! */ + + b->type = PA_MEMBLOCK_POOL_EXTERNAL; + b->read_only = 0; + + new_data = mempool_slot_data(slot); + memcpy(new_data, b->data, b->length); + b->data = new_data; + return; + } + } + + /* Humm, not enough space in the pool, so lets allocate the memory with malloc() */ + b->type = PA_MEMBLOCK_USER; + b->per_type.user.free_cb = pa_xfree; + b->read_only = 0; + b->data = pa_xmemdup(b->data, b->length); +} + void pa_memblock_unref_fixed(pa_memblock *b) { - assert(b && b->ref >= 1 && b->type == PA_MEMBLOCK_FIXED); + assert(b); + assert(b->ref >= 1); + assert(b->type == PA_MEMBLOCK_FIXED); - if (b->ref == 1) - pa_memblock_unref(b); - else { - b->data = pa_xmemdup(b->data, b->length); - b->type = PA_MEMBLOCK_DYNAMIC; - b->ref--; + if (b->ref > 1) + memblock_make_local(b); + + pa_memblock_unref(b); +} + +static void memblock_replace_import(pa_memblock *b) { + pa_memimport_segment *seg; + + assert(b); + assert(b->type == PA_MEMBLOCK_IMPORTED); + + assert(b->pool->stat.n_imported > 0); + assert(b->pool->stat.imported_size >= b->length); + b->pool->stat.n_imported --; + b->pool->stat.imported_size -= b->length; + + seg = b->per_type.imported.segment; + assert(seg); + assert(seg->import); + + pa_hashmap_remove( + seg->import->blocks, + PA_UINT32_TO_PTR(b->per_type.imported.id)); + + memblock_make_local(b); + + if (-- seg->n_blocks <= 0) + segment_detach(seg); +} + +pa_mempool* pa_mempool_new(int shared) { + size_t ps; + pa_mempool *p; + + p = pa_xnew(pa_mempool, 1); + + ps = (size_t) sysconf(_SC_PAGESIZE); + + p->block_size = (PA_MEMPOOL_SLOT_SIZE/ps)*ps; + + if (p->block_size < ps) + p->block_size = ps; + + p->n_blocks = PA_MEMPOOL_SLOTS_MAX; + + assert(p->block_size > sizeof(struct mempool_slot)); + + if (pa_shm_create_rw(&p->memory, p->n_blocks * p->block_size, shared, 0700) < 0) { + pa_xfree(p); + return NULL; + } + + p->n_init = 0; + + PA_LLIST_HEAD_INIT(pa_memimport, p->imports); + PA_LLIST_HEAD_INIT(pa_memexport, p->exports); + PA_LLIST_HEAD_INIT(struct mempool_slot, p->free_slots); + PA_LLIST_HEAD_INIT(struct mempool_slot, p->used_slots); + + memset(&p->stat, 0, sizeof(p->stat)); + + return p; +} + +void pa_mempool_free(pa_mempool *p) { + assert(p); + + while (p->imports) + pa_memimport_free(p->imports); + + while (p->exports) + pa_memexport_free(p->exports); + + if (p->stat.n_allocated > 0) + pa_log_warn(__FILE__": WARNING! Memory pool destroyed but not all memory blocks freed!"); + + pa_shm_free(&p->memory); + pa_xfree(p); +} + +const pa_mempool_stat* pa_mempool_get_stat(pa_mempool *p) { + assert(p); + + return &p->stat; +} + +void pa_mempool_vacuum(pa_mempool *p) { + struct mempool_slot *slot; + + assert(p); + + for (slot = p->free_slots; slot; slot = slot->next) { + pa_shm_punch(&p->memory, (uint8_t*) slot + sizeof(struct mempool_slot) - (uint8_t*) p->memory.ptr, p->block_size - sizeof(struct mempool_slot)); } } -pa_memblock_stat* pa_memblock_stat_new(void) { - pa_memblock_stat *s; +int pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id) { + assert(p); - s = pa_xmalloc(sizeof(pa_memblock_stat)); - s->ref = 1; - s->total = s->total_size = s->allocated = s->allocated_size = 0; + if (!p->memory.shared) + return -1; - return s; + *id = p->memory.id; + + return 0; +} + +/* For recieving blocks from other nodes */ +pa_memimport* pa_memimport_new(pa_mempool *p, pa_memimport_release_cb_t cb, void *userdata) { + pa_memimport *i; + + assert(p); + assert(cb); + + i = pa_xnew(pa_memimport, 1); + i->pool = p; + i->segments = pa_hashmap_new(NULL, NULL); + i->blocks = pa_hashmap_new(NULL, NULL); + i->release_cb = cb; + i->userdata = userdata; + + PA_LLIST_PREPEND(pa_memimport, p->imports, i); + return i; } -void pa_memblock_stat_unref(pa_memblock_stat *s) { - assert(s && s->ref >= 1); +static void memexport_revoke_blocks(pa_memexport *e, pa_memimport *i); + +static pa_memimport_segment* segment_attach(pa_memimport *i, uint32_t shm_id) { + pa_memimport_segment* seg; - if (!(--(s->ref))) { - assert(!s->total); - pa_xfree(s); + if (pa_hashmap_size(i->segments) >= PA_MEMIMPORT_SEGMENTS_MAX) + return NULL; + + seg = pa_xnew(pa_memimport_segment, 1); + + if (pa_shm_attach_ro(&seg->memory, shm_id) < 0) { + pa_xfree(seg); + return NULL; } + + seg->import = i; + seg->n_blocks = 0; + + pa_hashmap_put(i->segments, PA_UINT32_TO_PTR(shm_id), seg); + return seg; +} + +static void segment_detach(pa_memimport_segment *seg) { + assert(seg); + + pa_hashmap_remove(seg->import->segments, PA_UINT32_TO_PTR(seg->memory.id)); + pa_shm_free(&seg->memory); + pa_xfree(seg); +} + +void pa_memimport_free(pa_memimport *i) { + pa_memexport *e; + pa_memblock *b; + + assert(i); + + /* If we've exported this block further we need to revoke that export */ + for (e = i->pool->exports; e; e = e->next) + memexport_revoke_blocks(e, i); + + while ((b = pa_hashmap_get_first(i->blocks))) + memblock_replace_import(b); + + assert(pa_hashmap_size(i->segments) == 0); + + pa_hashmap_free(i->blocks, NULL, NULL); + pa_hashmap_free(i->segments, NULL, NULL); + + PA_LLIST_REMOVE(pa_memimport, i->pool->imports, i); + pa_xfree(i); } -pa_memblock_stat * pa_memblock_stat_ref(pa_memblock_stat *s) { - assert(s); - s->ref++; - return s; +pa_memblock* pa_memimport_get(pa_memimport *i, uint32_t block_id, uint32_t shm_id, size_t offset, size_t size) { + pa_memblock *b; + pa_memimport_segment *seg; + + assert(i); + + if (pa_hashmap_size(i->blocks) >= PA_MEMIMPORT_SLOTS_MAX) + return NULL; + + if (!(seg = pa_hashmap_get(i->segments, PA_UINT32_TO_PTR(shm_id)))) + if (!(seg = segment_attach(i, shm_id))) + return NULL; + + if (offset+size > seg->memory.size) + return NULL; + + b = pa_xnew(pa_memblock, 1); + b->type = PA_MEMBLOCK_IMPORTED; + b->read_only = 1; + b->ref = 1; + b->length = size; + b->data = (uint8_t*) seg->memory.ptr + offset; + b->pool = i->pool; + b->per_type.imported.id = block_id; + b->per_type.imported.segment = seg; + + pa_hashmap_put(i->blocks, PA_UINT32_TO_PTR(block_id), b); + + seg->n_blocks++; + + stat_add(b); + + return b; +} + +int pa_memimport_process_revoke(pa_memimport *i, uint32_t id) { + pa_memblock *b; + assert(i); + + if (!(b = pa_hashmap_get(i->blocks, PA_UINT32_TO_PTR(id)))) + return -1; + + memblock_replace_import(b); + return 0; +} + +/* For sending blocks to other nodes */ +pa_memexport* pa_memexport_new(pa_mempool *p, pa_memexport_revoke_cb_t cb, void *userdata) { + pa_memexport *e; + + assert(p); + assert(cb); + + if (!p->memory.shared) + return NULL; + + e = pa_xnew(pa_memexport, 1); + e->pool = p; + PA_LLIST_HEAD_INIT(struct memexport_slot, e->free_slots); + PA_LLIST_HEAD_INIT(struct memexport_slot, e->used_slots); + e->n_init = 0; + e->revoke_cb = cb; + e->userdata = userdata; + + PA_LLIST_PREPEND(pa_memexport, p->exports, e); + return e; +} + +void pa_memexport_free(pa_memexport *e) { + assert(e); + + while (e->used_slots) + pa_memexport_process_release(e, e->used_slots - e->slots); + + PA_LLIST_REMOVE(pa_memexport, e->pool->exports, e); + pa_xfree(e); +} + +int pa_memexport_process_release(pa_memexport *e, uint32_t id) { + assert(e); + + if (id >= e->n_init) + return -1; + + if (!e->slots[id].block) + return -1; + +/* pa_log("Processing release for %u", id); */ + + assert(e->pool->stat.n_exported > 0); + assert(e->pool->stat.exported_size >= e->slots[id].block->length); + + e->pool->stat.n_exported --; + e->pool->stat.exported_size -= e->slots[id].block->length; + + pa_memblock_unref(e->slots[id].block); + e->slots[id].block = NULL; + + PA_LLIST_REMOVE(struct memexport_slot, e->used_slots, &e->slots[id]); + PA_LLIST_PREPEND(struct memexport_slot, e->free_slots, &e->slots[id]); + + return 0; +} + +static void memexport_revoke_blocks(pa_memexport *e, pa_memimport *i) { + struct memexport_slot *slot, *next; + assert(e); + assert(i); + + for (slot = e->used_slots; slot; slot = next) { + uint32_t idx; + next = slot->next; + + if (slot->block->type != PA_MEMBLOCK_IMPORTED || + slot->block->per_type.imported.segment->import != i) + continue; + + idx = slot - e->slots; + e->revoke_cb(e, idx, e->userdata); + pa_memexport_process_release(e, idx); + } +} + +static pa_memblock *memblock_shared_copy(pa_mempool *p, pa_memblock *b) { + pa_memblock *n; + + assert(p); + assert(b); + + if (b->type == PA_MEMBLOCK_IMPORTED || + b->type == PA_MEMBLOCK_POOL || + b->type == PA_MEMBLOCK_POOL_EXTERNAL) { + assert(b->pool == p); + return pa_memblock_ref(b); + } + + if (!(n = pa_memblock_new_pool(p, b->length))) + return NULL; + + memcpy(n->data, b->data, b->length); + return n; +} + +int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32_t *shm_id, size_t *offset, size_t * size) { + pa_shm *memory; + struct memexport_slot *slot; + + assert(e); + assert(b); + assert(block_id); + assert(shm_id); + assert(offset); + assert(size); + assert(b->pool == e->pool); + + if (!(b = memblock_shared_copy(e->pool, b))) + return -1; + + if (e->free_slots) { + slot = e->free_slots; + PA_LLIST_REMOVE(struct memexport_slot, e->free_slots, slot); + } else if (e->n_init < PA_MEMEXPORT_SLOTS_MAX) { + slot = &e->slots[e->n_init++]; + } else { + pa_memblock_unref(b); + return -1; + } + + PA_LLIST_PREPEND(struct memexport_slot, e->used_slots, slot); + slot->block = b; + *block_id = slot - e->slots; + +/* pa_log("Got block id %u", *block_id); */ + + if (b->type == PA_MEMBLOCK_IMPORTED) { + assert(b->per_type.imported.segment); + memory = &b->per_type.imported.segment->memory; + } else { + assert(b->type == PA_MEMBLOCK_POOL || b->type == PA_MEMBLOCK_POOL_EXTERNAL); + assert(b->pool); + memory = &b->pool->memory; + } + + assert(b->data >= memory->ptr); + assert((uint8_t*) b->data + b->length <= (uint8_t*) memory->ptr + memory->size); + + *shm_id = memory->id; + *offset = (uint8_t*) b->data - (uint8_t*) memory->ptr; + *size = b->length; + + e->pool->stat.n_exported ++; + e->pool->stat.exported_size += b->length; + + return 0; } diff --git a/src/pulsecore/memblock.h b/src/pulsecore/memblock.h index 04a0b55b..e63e1e0f 100644 --- a/src/pulsecore/memblock.h +++ b/src/pulsecore/memblock.h @@ -1,5 +1,5 @@ -#ifndef foomemblockhfoo -#define foomemblockhfoo +#ifndef foopulsememblockhfoo +#define foopulsememblockhfoo /* $Id$ */ @@ -25,6 +25,8 @@ #include #include +#include + /* A pa_memblock is a reference counted memory block. PulseAudio * passed references to pa_memblocks around instead of copying * data. See pa_memchunk for a structure that describes parts of @@ -32,43 +34,72 @@ /* The type of memory this block points to */ typedef enum pa_memblock_type { - PA_MEMBLOCK_FIXED, /* data is a pointer to fixed memory that needs not to be freed */ - PA_MEMBLOCK_APPENDED, /* The most common kind: the data is appended to the memory block */ - PA_MEMBLOCK_DYNAMIC, /* data is a pointer to some memory allocated with pa_xmalloc() */ - PA_MEMBLOCK_USER /* User supplied memory, to be freed with free_cb */ + PA_MEMBLOCK_POOL, /* Memory is part of the memory pool */ + PA_MEMBLOCK_POOL_EXTERNAL, /* Data memory is part of the memory pool but the pa_memblock structure itself not */ + PA_MEMBLOCK_APPENDED, /* the data is appended to the memory block */ + PA_MEMBLOCK_USER, /* User supplied memory, to be freed with free_cb */ + PA_MEMBLOCK_FIXED, /* data is a pointer to fixed memory that needs not to be freed */ + PA_MEMBLOCK_IMPORTED, /* Memory is imported from another process via shm */ } pa_memblock_type_t; -/* A structure of keeping memory block statistics */ -/* Maintains statistics about memory blocks */ -typedef struct pa_memblock_stat { - int ref; - unsigned total; - unsigned total_size; - unsigned allocated; - unsigned allocated_size; -} pa_memblock_stat; - -typedef struct pa_memblock { +typedef struct pa_memblock pa_memblock; +typedef struct pa_mempool pa_mempool; +typedef struct pa_mempool_stat pa_mempool_stat; +typedef struct pa_memimport_segment pa_memimport_segment; +typedef struct pa_memimport pa_memimport; +typedef struct pa_memexport pa_memexport; + +typedef void (*pa_memimport_release_cb_t)(pa_memimport *i, uint32_t block_id, void *userdata); +typedef void (*pa_memexport_revoke_cb_t)(pa_memexport *e, uint32_t block_id, void *userdata); + +struct pa_memblock { pa_memblock_type_t type; - unsigned ref; /* the reference counter */ int read_only; /* boolean */ + unsigned ref; /* the reference counter */ size_t length; void *data; - void (*free_cb)(void *p); /* If type == PA_MEMBLOCK_USER this points to a function for freeing this memory block */ - pa_memblock_stat *stat; -} pa_memblock; + pa_mempool *pool; -/* Allocate a new memory block of type PA_MEMBLOCK_APPENDED */ -pa_memblock *pa_memblock_new(size_t length, pa_memblock_stat*s); + union { + struct { + void (*free_cb)(void *p); /* If type == PA_MEMBLOCK_USER this points to a function for freeing this memory block */ + } user; + + struct { + uint32_t id; + pa_memimport_segment *segment; + } imported; + } per_type; +}; -/* Allocate a new memory block of type PA_MEMBLOCK_DYNAMIC. The pointer data is to be maintained be the memory block */ -pa_memblock *pa_memblock_new_dynamic(void *data, size_t length, pa_memblock_stat*s); +struct pa_mempool_stat { + unsigned n_allocated; + unsigned n_accumulated; + unsigned n_imported; + unsigned n_exported; + size_t allocated_size; + size_t accumulated_size; + size_t imported_size; + size_t exported_size; -/* Allocate a new memory block of type PA_MEMBLOCK_FIXED */ -pa_memblock *pa_memblock_new_fixed(void *data, size_t length, int read_only, pa_memblock_stat*s); + unsigned n_too_large_for_pool; + unsigned n_pool_full; +}; + +/* Allocate a new memory block of type PA_MEMBLOCK_MEMPOOL or PA_MEMBLOCK_APPENDED, depending on the size */ +pa_memblock *pa_memblock_new(pa_mempool *, size_t length); + +/* Allocate a new memory block of type PA_MEMBLOCK_MEMPOOL. If the requested size is too large, return NULL */ +pa_memblock *pa_memblock_new_pool(pa_mempool *, size_t length); /* Allocate a new memory block of type PA_MEMBLOCK_USER */ -pa_memblock *pa_memblock_new_user(void *data, size_t length, void (*free_cb)(void *p), int read_only, pa_memblock_stat*s); +pa_memblock *pa_memblock_new_user(pa_mempool *, void *data, size_t length, void (*free_cb)(void *p), int read_only); + +/* A special case of pa_memblock_new_user: take a memory buffer previously allocated with pa_xmalloc() */ +#define pa_memblock_new_malloced(p,data,length) pa_memblock_new_user(p, data, length, pa_xfree, 0) + +/* Allocate a new memory block of type PA_MEMBLOCK_FIXED */ +pa_memblock *pa_memblock_new_fixed(pa_mempool *, void *data, size_t length, int read_only); void pa_memblock_unref(pa_memblock*b); pa_memblock* pa_memblock_ref(pa_memblock*b); @@ -79,8 +110,23 @@ references to the memory. This causes the memory to be copied and converted into a PA_MEMBLOCK_DYNAMIC type memory block */ void pa_memblock_unref_fixed(pa_memblock*b); -pa_memblock_stat* pa_memblock_stat_new(void); -void pa_memblock_stat_unref(pa_memblock_stat *s); -pa_memblock_stat * pa_memblock_stat_ref(pa_memblock_stat *s); +/* The memory block manager */ +pa_mempool* pa_mempool_new(int shared); +void pa_mempool_free(pa_mempool *p); +const pa_mempool_stat* pa_mempool_get_stat(pa_mempool *p); +void pa_mempool_vacuum(pa_mempool *p); +int pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id); + +/* For recieving blocks from other nodes */ +pa_memimport* pa_memimport_new(pa_mempool *p, pa_memimport_release_cb_t cb, void *userdata); +void pa_memimport_free(pa_memimport *i); +pa_memblock* pa_memimport_get(pa_memimport *i, uint32_t block_id, uint32_t shm_id, size_t offset, size_t size); +int pa_memimport_process_revoke(pa_memimport *i, uint32_t block_id); + +/* For sending blocks to other nodes */ +pa_memexport* pa_memexport_new(pa_mempool *p, pa_memexport_revoke_cb_t cb, void *userdata); +void pa_memexport_free(pa_memexport *e); +int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32_t *shm_id, size_t *offset, size_t *size); +int pa_memexport_process_release(pa_memexport *e, uint32_t id); #endif diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index 822bd66c..2fd38850 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -49,7 +49,6 @@ struct pa_memblockq { size_t maxlength, tlength, base, prebuf, minreq; int64_t read_index, write_index; enum { PREBUF, RUNNING } state; - pa_memblock_stat *memblock_stat; pa_memblock *silence; pa_mcalign *mcalign; }; @@ -61,8 +60,7 @@ pa_memblockq* pa_memblockq_new( size_t base, size_t prebuf, size_t minreq, - pa_memblock *silence, - pa_memblock_stat *s) { + pa_memblock *silence) { pa_memblockq* bq; @@ -75,7 +73,6 @@ pa_memblockq* pa_memblockq_new( bq->base = base; bq->read_index = bq->write_index = idx; - bq->memblock_stat = s; pa_log_debug(__FILE__": memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", (unsigned long)maxlength, (unsigned long)tlength, (unsigned long)base, (unsigned long)prebuf, (unsigned long)minreq); @@ -586,7 +583,7 @@ int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk) { return pa_memblockq_push(bq, chunk); if (!bq->mcalign) - bq->mcalign = pa_mcalign_new(bq->base, bq->memblock_stat); + bq->mcalign = pa_mcalign_new(bq->base); if (!can_push(bq, pa_mcalign_csize(bq->mcalign, chunk->length))) return -1; diff --git a/src/pulsecore/memblockq.h b/src/pulsecore/memblockq.h index c35b62dd..4d701a80 100644 --- a/src/pulsecore/memblockq.h +++ b/src/pulsecore/memblockq.h @@ -69,8 +69,7 @@ pa_memblockq* pa_memblockq_new( size_t base, size_t prebuf, size_t minreq, - pa_memblock *silence, - pa_memblock_stat *s); + pa_memblock *silence); void pa_memblockq_free(pa_memblockq*bq); diff --git a/src/pulsecore/memchunk.c b/src/pulsecore/memchunk.c index abfc2cab..bcf0ce04 100644 --- a/src/pulsecore/memchunk.c +++ b/src/pulsecore/memchunk.c @@ -32,10 +32,13 @@ #include "memchunk.h" -void pa_memchunk_make_writable(pa_memchunk *c, pa_memblock_stat *s, size_t min) { +void pa_memchunk_make_writable(pa_memchunk *c, size_t min) { pa_memblock *n; size_t l; - assert(c && c->memblock && c->memblock->ref >= 1); + + assert(c); + assert(c->memblock); + assert(c->memblock->ref >= 1); if (c->memblock->ref == 1 && !c->memblock->read_only && c->memblock->length >= c->index+min) return; @@ -44,7 +47,7 @@ void pa_memchunk_make_writable(pa_memchunk *c, pa_memblock_stat *s, size_t min) if (l < min) l = min; - n = pa_memblock_new(l, s); + n = pa_memblock_new(c->memblock->pool, l); memcpy(n->data, (uint8_t*) c->memblock->data + c->index, c->length); pa_memblock_unref(c->memblock); c->memblock = n; diff --git a/src/pulsecore/memchunk.h b/src/pulsecore/memchunk.h index 1b26c2e6..b8ce6249 100644 --- a/src/pulsecore/memchunk.h +++ b/src/pulsecore/memchunk.h @@ -36,7 +36,7 @@ typedef struct pa_memchunk { /* Make a memchunk writable, i.e. make sure that the caller may have * exclusive access to the memblock and it is not read_only. If needed * the memblock in the structure is replaced by a copy. */ -void pa_memchunk_make_writable(pa_memchunk *c, pa_memblock_stat *s, size_t min); +void pa_memchunk_make_writable(pa_memchunk *c, size_t min); /* Invalidate a memchunk. This does not free the cotaining memblock, * but sets all members to zero. */ diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index f1a827bc..2fadeca3 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -377,8 +377,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t pa_frame_size(&ss), (size_t) -1, l/PLAYBACK_BUFFER_FRAGMENTS, - NULL, - c->protocol->core->memblock_stat); + NULL); pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2); c->playback.fragment_size = l/10; @@ -469,8 +468,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co pa_frame_size(&ss), 1, 0, - NULL, - c->protocol->core->memblock_stat); + NULL); pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); c->source_output->push = source_output_push_cb; @@ -722,7 +720,7 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in sample name."); assert(!c->scache.memchunk.memblock); - c->scache.memchunk.memblock = pa_memblock_new(sc_length, c->protocol->core->memblock_stat); + c->scache.memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, sc_length); c->scache.memchunk.index = 0; c->scache.memchunk.length = sc_length; c->scache.sample_spec = ss; @@ -941,7 +939,7 @@ static int do_read(struct connection *c) { } if (!c->playback.current_memblock) { - c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2, c->protocol->core->memblock_stat); + c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, c->playback.fragment_size*2); assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); c->playback.memblock_index = 0; } diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 0b79892c..2c9b3566 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -348,8 +348,7 @@ static struct record_stream* record_stream_new( base = pa_frame_size(ss), 1, 0, - NULL, - c->protocol->core->memblock_stat); + NULL); assert(s->memblockq); s->fragment_size = (fragment_size/base)*base; @@ -448,7 +447,7 @@ static struct playback_stream* playback_stream_new( start_index = 0; } - silence = pa_silence_memblock_new(ss, 0, c->protocol->core->memblock_stat); + silence = pa_silence_memblock_new(c->protocol->core->mempool, ss, 0); s->memblockq = pa_memblockq_new( start_index, @@ -457,8 +456,7 @@ static struct playback_stream* playback_stream_new( pa_frame_size(ss), prebuf, minreq, - silence, - c->protocol->core->memblock_stat); + silence); pa_memblock_unref(silence); @@ -1076,6 +1074,7 @@ static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; pa_tagstruct *reply; + const pa_mempool_stat *stat; assert(c && t); if (!pa_tagstruct_eof(t)) { @@ -1085,11 +1084,13 @@ static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + stat = pa_mempool_get_stat(c->protocol->core->mempool); + reply = reply_new(tag); - pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->total); - pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->total_size); - pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->allocated); - pa_tagstruct_putu32(reply, c->protocol->core->memblock_stat->allocated_size); + pa_tagstruct_putu32(reply, stat->n_allocated); + pa_tagstruct_putu32(reply, stat->allocated_size); + pa_tagstruct_putu32(reply, stat->n_accumulated); + pa_tagstruct_putu32(reply, stat->accumulated_size); pa_tagstruct_putu32(reply, pa_scache_total_size(c->protocol->core)); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -2256,7 +2257,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o pa_memblock_ref(u->memchunk.memblock); u->length = 0; } else { - u->memchunk.memblock = pa_memblock_new(u->length, c->protocol->core->memblock_stat); + u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length); u->memchunk.index = u->memchunk.length = 0; } } @@ -2349,9 +2350,11 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo c->client->userdata = c; c->client->owner = p->module; - c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->memblock_stat); + c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool); assert(c->pstream); + pa_pstream_use_shm(c->pstream, 1); + pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c index 3705986d..924ee29e 100644 --- a/src/pulsecore/protocol-simple.c +++ b/src/pulsecore/protocol-simple.c @@ -128,7 +128,7 @@ static int do_read(struct connection *c) { } if (!c->playback.current_memblock) { - c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2, c->protocol->core->memblock_stat); + c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, c->playback.fragment_size*2); assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); c->playback.memblock_index = 0; } @@ -369,8 +369,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) pa_frame_size(&p->sample_spec), (size_t) -1, l/PLAYBACK_BUFFER_FRAGMENTS, - NULL, - p->core->memblock_stat); + NULL); assert(c->input_memblockq); pa_iochannel_socket_set_rcvbuf(io, l/PLAYBACK_BUFFER_FRAGMENTS*5); c->playback.fragment_size = l/10; @@ -406,8 +405,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) pa_frame_size(&p->sample_spec), 1, 0, - NULL, - p->core->memblock_stat); + NULL); pa_iochannel_socket_set_sndbuf(io, l/RECORD_BUFFER_FRAGMENTS*2); pa_source_notify(c->source_output->source); } diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index 7096d65a..421f5de9 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -49,28 +49,45 @@ #include "pstream.h" +/* We piggyback information if audio data blocks are stored in SHM on the seek mode */ +#define PA_FLAG_SHMDATA 0x80000000LU +#define PA_FLAG_SHMRELEASE 0x40000000LU +#define PA_FLAG_SHMREVOKE 0xC0000000LU +#define PA_FLAG_SHMMASK 0xFF000000LU +#define PA_FLAG_SEEKMASK 0x000000FFLU + +/* The sequence descriptor header consists of 5 32bit integers: */ enum { PA_PSTREAM_DESCRIPTOR_LENGTH, PA_PSTREAM_DESCRIPTOR_CHANNEL, PA_PSTREAM_DESCRIPTOR_OFFSET_HI, PA_PSTREAM_DESCRIPTOR_OFFSET_LO, - PA_PSTREAM_DESCRIPTOR_SEEK, + PA_PSTREAM_DESCRIPTOR_FLAGS, PA_PSTREAM_DESCRIPTOR_MAX }; +/* If we have an SHM block, this info follows the descriptor */ +enum { + PA_PSTREAM_SHM_BLOCKID, + PA_PSTREAM_SHM_SHMID, + PA_PSTREAM_SHM_INDEX, + PA_PSTREAM_SHM_LENGTH, + PA_PSTREAM_SHM_MAX +}; + typedef uint32_t pa_pstream_descriptor[PA_PSTREAM_DESCRIPTOR_MAX]; #define PA_PSTREAM_DESCRIPTOR_SIZE (PA_PSTREAM_DESCRIPTOR_MAX*sizeof(uint32_t)) #define FRAME_SIZE_MAX PA_SCACHE_ENTRY_SIZE_MAX /* allow uploading a single sample in one frame at max */ struct item_info { - enum { PA_PSTREAM_ITEM_PACKET, PA_PSTREAM_ITEM_MEMBLOCK } type; + enum { + PA_PSTREAM_ITEM_PACKET, + PA_PSTREAM_ITEM_MEMBLOCK, + PA_PSTREAM_ITEM_SHMRELEASE, + PA_PSTREAM_ITEM_SHMREVOKE + } type; - /* memblock info */ - pa_memchunk chunk; - uint32_t channel; - int64_t offset; - pa_seek_mode_t seek_mode; /* packet info */ pa_packet *packet; @@ -78,6 +95,15 @@ struct item_info { int with_creds; pa_creds creds; #endif + + /* memblock info */ + pa_memchunk chunk; + uint32_t channel; + int64_t offset; + pa_seek_mode_t seek_mode; + + /* release/revoke info */ + uint32_t block_id; }; struct pa_pstream { @@ -91,20 +117,26 @@ struct pa_pstream { int dead; struct { - struct item_info* current; pa_pstream_descriptor descriptor; + struct item_info* current; + uint32_t shm_info[PA_PSTREAM_SHM_MAX]; void *data; size_t index; } write; struct { + pa_pstream_descriptor descriptor; pa_memblock *memblock; pa_packet *packet; - pa_pstream_descriptor descriptor; + uint32_t shm_info[PA_PSTREAM_SHM_MAX]; void *data; size_t index; } read; + int use_shm; + pa_memimport *import; + pa_memexport *export; + pa_pstream_packet_cb_t recieve_packet_callback; void *recieve_packet_callback_userdata; @@ -117,7 +149,7 @@ struct pa_pstream { pa_pstream_notify_cb_t die_callback; void *die_callback_userdata; - pa_memblock_stat *memblock_stat; + pa_mempool *mempool; #ifdef HAVE_CREDS pa_creds read_creds, write_creds; @@ -178,16 +210,19 @@ static void defer_callback(pa_mainloop_api *m, pa_defer_event *e, void*userdata) do_something(p); } -pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_stat *s) { +static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userdata); + +pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *pool) { pa_pstream *p; + + assert(m); assert(io); + assert(pool); p = pa_xnew(pa_pstream, 1); - p->ref = 1; p->io = io; pa_iochannel_set_callback(io, io_callback, p); - p->dead = 0; p->mainloop = m; @@ -199,24 +234,24 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_sta p->write.current = NULL; p->write.index = 0; - p->read.memblock = NULL; p->read.packet = NULL; p->read.index = 0; p->recieve_packet_callback = NULL; p->recieve_packet_callback_userdata = NULL; - p->recieve_memblock_callback = NULL; p->recieve_memblock_callback_userdata = NULL; - p->drain_callback = NULL; p->drain_callback_userdata = NULL; - p->die_callback = NULL; p->die_callback_userdata = NULL; - p->memblock_stat = s; + p->mempool = pool; + + p->use_shm = 0; + p->export = NULL; + p->import = NULL; pa_iochannel_socket_set_rcvbuf(io, 1024*8); pa_iochannel_socket_set_sndbuf(io, 1024*8); @@ -235,8 +270,7 @@ static void item_free(void *item, PA_GCC_UNUSED void *p) { if (i->type == PA_PSTREAM_ITEM_MEMBLOCK) { assert(i->chunk.memblock); pa_memblock_unref(i->chunk.memblock); - } else { - assert(i->type == PA_PSTREAM_ITEM_PACKET); + } else if (i->type == PA_PSTREAM_ITEM_PACKET) { assert(i->packet); pa_packet_unref(i->packet); } @@ -265,16 +299,18 @@ static void pstream_free(pa_pstream *p) { void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *creds) { struct item_info *i; - assert(p && packet && p->ref >= 1); + + assert(p); + assert(p->ref >= 1); + assert(packet); if (p->dead) return; -/* pa_log(__FILE__": push-packet %p", packet); */ - i = pa_xnew(struct item_info, 1); i->type = PA_PSTREAM_ITEM_PACKET; i->packet = pa_packet_ref(packet); + #ifdef HAVE_CREDS if ((i->with_creds = !!creds)) i->creds = *creds; @@ -286,13 +322,15 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *cre void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek_mode, const pa_memchunk *chunk) { struct item_info *i; - assert(p && channel != (uint32_t) -1 && chunk && p->ref >= 1); + + assert(p); + assert(p->ref >= 1); + assert(channel != (uint32_t) -1); + assert(chunk); if (p->dead) return; - -/* pa_log(__FILE__": push-memblock %p", chunk); */ - + i = pa_xnew(struct item_info, 1); i->type = PA_PSTREAM_ITEM_MEMBLOCK; i->chunk = *chunk; @@ -309,6 +347,52 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa p->mainloop->defer_enable(p->defer_event, 1); } +static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userdata) { + struct item_info *item; + pa_pstream *p = userdata; + + assert(p); + assert(p->ref >= 1); + + if (p->dead) + return; + +/* pa_log(__FILE__": Releasing block %u", block_id); */ + + item = pa_xnew(struct item_info, 1); + item->type = PA_PSTREAM_ITEM_SHMRELEASE; + item->block_id = block_id; +#ifdef HAVE_CREDS + item->with_creds = 0; +#endif + + pa_queue_push(p->send_queue, item); + p->mainloop->defer_enable(p->defer_event, 1); +} + +static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userdata) { + struct item_info *item; + pa_pstream *p = userdata; + + assert(p); + assert(p->ref >= 1); + + if (p->dead) + return; + +/* pa_log(__FILE__": Revoking block %u", block_id); */ + + item = pa_xnew(struct item_info, 1); + item->type = PA_PSTREAM_ITEM_SHMREVOKE; + item->block_id = block_id; +#ifdef HAVE_CREDS + item->with_creds = 0; +#endif + + pa_queue_push(p->send_queue, item); + p->mainloop->defer_enable(p->defer_event, 1); +} + static void prepare_next_write_item(pa_pstream *p) { assert(p); @@ -316,27 +400,77 @@ static void prepare_next_write_item(pa_pstream *p) { return; p->write.index = 0; + p->write.data = NULL; + + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = 0; + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl((uint32_t) -1); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = 0; + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = 0; + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS] = 0; if (p->write.current->type == PA_PSTREAM_ITEM_PACKET) { - /*pa_log(__FILE__": pop-packet %p", p->write.current->packet);*/ assert(p->write.current->packet); p->write.data = p->write.current->packet->data; p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->packet->length); - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl((uint32_t) -1); - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = 0; - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = 0; - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK] = 0; + } else if (p->write.current->type == PA_PSTREAM_ITEM_SHMRELEASE) { + + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS] = htonl(PA_FLAG_SHMRELEASE); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = htonl(p->write.current->block_id); + + } else if (p->write.current->type == PA_PSTREAM_ITEM_SHMREVOKE) { + + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS] = htonl(PA_FLAG_SHMREVOKE); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = htonl(p->write.current->block_id); } else { - assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK && p->write.current->chunk.memblock); - p->write.data = (uint8_t*) p->write.current->chunk.memblock->data + p->write.current->chunk.index; - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length); + uint32_t flags; + int send_payload = 1; + + assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK); + assert(p->write.current->chunk.memblock); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl(p->write.current->channel); p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = htonl((uint32_t) (((uint64_t) p->write.current->offset) >> 32)); p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = htonl((uint32_t) ((uint64_t) p->write.current->offset)); - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK] = htonl(p->write.current->seek_mode); + + flags = p->write.current->seek_mode & PA_FLAG_SEEKMASK; + + if (p->use_shm) { + uint32_t block_id, shm_id; + size_t offset, length; + + assert(p->export); + + if (pa_memexport_put(p->export, + p->write.current->chunk.memblock, + &block_id, + &shm_id, + &offset, + &length) >= 0) { + + flags |= PA_FLAG_SHMDATA; + send_payload = 0; + + p->write.shm_info[PA_PSTREAM_SHM_BLOCKID] = htonl(block_id); + p->write.shm_info[PA_PSTREAM_SHM_SHMID] = htonl(shm_id); + p->write.shm_info[PA_PSTREAM_SHM_INDEX] = htonl((uint32_t) (offset + p->write.current->chunk.index)); + p->write.shm_info[PA_PSTREAM_SHM_LENGTH] = htonl((uint32_t) p->write.current->chunk.length); + + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(sizeof(p->write.shm_info)); + p->write.data = p->write.shm_info; + } +/* else */ +/* pa_log_warn(__FILE__": Failed to export memory block."); */ + } + + if (send_payload) { + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length); + p->write.data = (uint8_t*) p->write.current->chunk.memblock->data + p->write.current->chunk.index; + } + + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS] = htonl(flags); } #ifdef HAVE_CREDS @@ -344,7 +478,6 @@ static void prepare_next_write_item(pa_pstream *p) { p->write_creds = p->write.current->creds; #endif - } static int do_write(pa_pstream *p) { @@ -359,16 +492,18 @@ static int do_write(pa_pstream *p) { if (!p->write.current) return 0; - assert(p->write.data); - if (p->write.index < PA_PSTREAM_DESCRIPTOR_SIZE) { d = (uint8_t*) p->write.descriptor + p->write.index; l = PA_PSTREAM_DESCRIPTOR_SIZE - p->write.index; } else { + assert(p->write.data); + d = (uint8_t*) p->write.data + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE; l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE); } + assert(l > 0); + #ifdef HAVE_CREDS if (p->send_creds_now) { @@ -384,7 +519,7 @@ static int do_write(pa_pstream *p) { p->write.index += r; - if (p->write.index >= PA_PSTREAM_DESCRIPTOR_SIZE+ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])) { + if (p->write.index >= PA_PSTREAM_DESCRIPTOR_SIZE + ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])) { assert(p->write.current); item_free(p->write.current, (void *) 1); p->write.current = NULL; @@ -428,27 +563,87 @@ static int do_read(pa_pstream *p) { p->read.index += r; if (p->read.index == PA_PSTREAM_DESCRIPTOR_SIZE) { + uint32_t flags, length, channel; /* Reading of frame descriptor complete */ - /* Frame size too large */ - if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) > FRAME_SIZE_MAX) { - pa_log_warn(__FILE__": Frame size too large: %lu > %lu", (unsigned long) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]), (unsigned long) FRAME_SIZE_MAX); + flags = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]); + + if (!p->use_shm && (flags & PA_FLAG_SHMMASK) != 0) { + pa_log_warn(__FILE__": Recieved SHM frame on a socket where SHM is disabled."); + return -1; + } + + if (flags == PA_FLAG_SHMRELEASE) { + + /* This is a SHM memblock release frame with no payload */ + +/* pa_log(__FILE__": Got release frame for %u", ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); */ + + assert(p->export); + pa_memexport_process_release(p->export, ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); + + goto frame_done; + + } else if (flags == PA_FLAG_SHMREVOKE) { + + /* This is a SHM memblock revoke frame with no payload */ + +/* pa_log(__FILE__": Got revoke frame for %u", ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); */ + + assert(p->import); + pa_memimport_process_revoke(p->import, ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); + + goto frame_done; + } + + length = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]); + + if (length > FRAME_SIZE_MAX) { + pa_log_warn(__FILE__": Recieved invalid frame size : %lu", (unsigned long) length); return -1; } assert(!p->read.packet && !p->read.memblock); - if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]) == (uint32_t) -1) { + channel = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]); + + if (channel == (uint32_t) -1) { + + if (flags != 0) { + pa_log_warn(__FILE__": Received packet frame with invalid flags value."); + return -1; + } + /* Frame is a packet frame */ - p->read.packet = pa_packet_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])); + p->read.packet = pa_packet_new(length); p->read.data = p->read.packet->data; + } else { - /* Frame is a memblock frame */ - p->read.memblock = pa_memblock_new(ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]), p->memblock_stat); - p->read.data = p->read.memblock->data; - if (ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK]) > PA_SEEK_RELATIVE_END) { - pa_log_warn(__FILE__": Invalid seek mode"); + if ((flags & PA_FLAG_SEEKMASK) > PA_SEEK_RELATIVE_END) { + pa_log_warn(__FILE__": Received memblock frame with invalid seek mode."); + return -1; + } + + if ((flags & PA_FLAG_SHMMASK) == PA_FLAG_SHMDATA) { + + if (length != sizeof(p->read.shm_info)) { + pa_log_warn(__FILE__": Recieved SHM memblock frame with Invalid frame length."); + return -1; + } + + /* Frame is a memblock frame referencing an SHM memblock */ + p->read.data = p->read.shm_info; + + } else if ((flags & PA_FLAG_SHMMASK) == 0) { + + /* Frame is a memblock frame */ + + p->read.memblock = pa_memblock_new(p->mempool, length); + p->read.data = p->read.memblock->data; + } else { + + pa_log_warn(__FILE__": Recieved memblock frame with invalid flags value."); return -1; } } @@ -456,7 +651,9 @@ static int do_read(pa_pstream *p) { } else if (p->read.index > PA_PSTREAM_DESCRIPTOR_SIZE) { /* Frame payload available */ - if (p->read.memblock && p->recieve_memblock_callback) { /* Is this memblock data? Than pass it to the user */ + if (p->read.memblock && p->recieve_memblock_callback) { + + /* Is this memblock data? Than pass it to the user */ l = (p->read.index - r) < PA_PSTREAM_DESCRIPTOR_SIZE ? p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE : (size_t) r; if (l > 0) { @@ -477,13 +674,13 @@ static int do_read(pa_pstream *p) { p, ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]), offset, - ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK]), + ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]) & PA_FLAG_SEEKMASK, &chunk, p->recieve_memblock_callback_userdata); } /* Drop seek info for following callbacks */ - p->read.descriptor[PA_PSTREAM_DESCRIPTOR_SEEK] = + p->read.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS] = p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = 0; } @@ -491,13 +688,13 @@ static int do_read(pa_pstream *p) { /* Frame complete */ if (p->read.index >= ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) + PA_PSTREAM_DESCRIPTOR_SIZE) { + if (p->read.memblock) { - assert(!p->read.packet); - + + /* This was a memblock frame. We can unref the memblock now */ pa_memblock_unref(p->read.memblock); - p->read.memblock = NULL; - } else { - assert(p->read.packet); + + } else if (p->read.packet) { if (p->recieve_packet_callback) #ifdef HAVE_CREDS @@ -507,17 +704,63 @@ static int do_read(pa_pstream *p) { #endif pa_packet_unref(p->read.packet); - p->read.packet = NULL; + } else { + pa_memblock *b; + + assert((ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]) & PA_FLAG_SHMMASK) == PA_FLAG_SHMDATA); + + assert(p->import); + + if (!(b = pa_memimport_get(p->import, + ntohl(p->read.shm_info[PA_PSTREAM_SHM_BLOCKID]), + ntohl(p->read.shm_info[PA_PSTREAM_SHM_SHMID]), + ntohl(p->read.shm_info[PA_PSTREAM_SHM_INDEX]), + ntohl(p->read.shm_info[PA_PSTREAM_SHM_LENGTH])))) { + + pa_log_warn(__FILE__": Failed to import memory block."); + return -1; + } + + if (p->recieve_memblock_callback) { + int64_t offset; + pa_memchunk chunk; + + chunk.memblock = b; + chunk.index = 0; + chunk.length = b->length; + + offset = (int64_t) ( + (((uint64_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])) << 32) | + (((uint64_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO])))); + + p->recieve_memblock_callback( + p, + ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]), + offset, + ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]) & PA_FLAG_SEEKMASK, + &chunk, + p->recieve_memblock_callback_userdata); + } + + pa_memblock_unref(b); } - p->read.index = 0; -#ifdef HAVE_CREDS - p->read_creds_valid = 0; -#endif + goto frame_done; } } - return 0; + return 0; + +frame_done: + p->read.memblock = NULL; + p->read.packet = NULL; + p->read.index = 0; + +#ifdef HAVE_CREDS + p->read_creds_valid = 0; +#endif + + return 0; } void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) { @@ -583,6 +826,16 @@ void pa_pstream_close(pa_pstream *p) { p->dead = 1; + if (p->import) { + pa_memimport_free(p->import); + p->import = NULL; + } + + if (p->export) { + pa_memexport_free(p->export); + p->export = NULL; + } + if (p->io) { pa_iochannel_free(p->io); p->io = NULL; @@ -597,4 +850,19 @@ void pa_pstream_close(pa_pstream *p) { p->drain_callback = NULL; p->recieve_packet_callback = NULL; p->recieve_memblock_callback = NULL; + + +} + +void pa_pstream_use_shm(pa_pstream *p, int enable) { + assert(p); + assert(p->ref >= 1); + + p->use_shm = enable; + + if (!p->import) + p->import = pa_memimport_new(p->mempool, memimport_release_cb, p); + + if (!p->export) + p->export = pa_memexport_new(p->mempool, memexport_revoke_cb, p); } diff --git a/src/pulsecore/pstream.h b/src/pulsecore/pstream.h index 789e40bc..26bb7699 100644 --- a/src/pulsecore/pstream.h +++ b/src/pulsecore/pstream.h @@ -39,7 +39,7 @@ typedef void (*pa_pstream_packet_cb_t)(pa_pstream *p, pa_packet *packet, const p typedef void (*pa_pstream_memblock_cb_t)(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata); typedef void (*pa_pstream_notify_cb_t)(pa_pstream *p, void *userdata); -pa_pstream* pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_memblock_stat *s); +pa_pstream* pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *p); void pa_pstream_unref(pa_pstream*p); pa_pstream* pa_pstream_ref(pa_pstream*p); @@ -54,6 +54,8 @@ void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void int pa_pstream_is_pending(pa_pstream *p); +void pa_pstream_use_shm(pa_pstream *p, int enable); + void pa_pstream_close(pa_pstream *p); #endif diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index 23cdf381..74226714 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -42,7 +42,7 @@ struct pa_resampler { pa_sample_spec i_ss, o_ss; pa_channel_map i_cm, o_cm; size_t i_fz, o_fz; - pa_memblock_stat *memblock_stat; + pa_mempool *mempool; void (*impl_free)(pa_resampler *r); void (*impl_update_input_rate)(pa_resampler *r, uint32_t rate); @@ -71,15 +71,16 @@ static int libsamplerate_init(pa_resampler*r); static int trivial_init(pa_resampler*r); pa_resampler* pa_resampler_new( - const pa_sample_spec *a, - const pa_channel_map *am, - const pa_sample_spec *b, - const pa_channel_map *bm, - pa_memblock_stat *s, - pa_resample_method_t resample_method) { + pa_mempool *pool, + const pa_sample_spec *a, + const pa_channel_map *am, + const pa_sample_spec *b, + const pa_channel_map *bm, + pa_resample_method_t resample_method) { pa_resampler *r = NULL; + assert(pool); assert(a); assert(b); assert(pa_sample_spec_valid(a)); @@ -88,7 +89,7 @@ pa_resampler* pa_resampler_new( r = pa_xnew(pa_resampler, 1); r->impl_data = NULL; - r->memblock_stat = s; + r->mempool = pool; r->resample_method = resample_method; r->impl_free = NULL; @@ -450,7 +451,7 @@ static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchun assert(p); /* Take the existing buffer and make it a memblock */ - out->memblock = pa_memblock_new_dynamic(*p, out->length, r->memblock_stat); + out->memblock = pa_memblock_new_malloced(r->mempool, *p, out->length); *p = NULL; } } else { @@ -549,7 +550,7 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out l = ((((n_frames+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz; out->index = 0; - out->memblock = pa_memblock_new(l, r->memblock_stat); + out->memblock = pa_memblock_new(r->mempool, l); for (o_index = 0;; o_index++, u->o_counter++) { unsigned j; diff --git a/src/pulsecore/resampler.h b/src/pulsecore/resampler.h index c1199e5c..327e24a2 100644 --- a/src/pulsecore/resampler.h +++ b/src/pulsecore/resampler.h @@ -43,12 +43,12 @@ typedef enum pa_resample_method { } pa_resample_method_t; pa_resampler* pa_resampler_new( - const pa_sample_spec *a, - const pa_channel_map *am, - const pa_sample_spec *b, - const pa_channel_map *bm, - pa_memblock_stat *s, - pa_resample_method_t resample_method); + pa_mempool *pool, + const pa_sample_spec *a, + const pa_channel_map *am, + const pa_sample_spec *b, + const pa_channel_map *bm, + pa_resample_method_t resample_method); void pa_resampler_free(pa_resampler *r); diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index 638f8067..7f5d8a02 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -35,13 +35,14 @@ #include "sample-util.h" #include "endianmacros.h" -pa_memblock *pa_silence_memblock_new(const pa_sample_spec *spec, size_t length, pa_memblock_stat*s) { +pa_memblock *pa_silence_memblock_new(pa_mempool *pool, const pa_sample_spec *spec, size_t length) { + assert(pool); assert(spec); if (length == 0) - length = pa_bytes_per_second(spec)/10; /* 100 ms */ + length = pa_bytes_per_second(spec)/20; /* 50 ms */ - return pa_silence_memblock(pa_memblock_new(length, s), spec); + return pa_silence_memblock(pa_memblock_new(pool, length), spec); } pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) { diff --git a/src/pulsecore/sample-util.h b/src/pulsecore/sample-util.h index 3ebb7e2e..6b770792 100644 --- a/src/pulsecore/sample-util.h +++ b/src/pulsecore/sample-util.h @@ -28,7 +28,7 @@ #include pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec); -pa_memblock *pa_silence_memblock_new(const pa_sample_spec *spec, size_t length, pa_memblock_stat*s); +pa_memblock *pa_silence_memblock_new(pa_mempool *pool, const pa_sample_spec *spec, size_t length); void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec); void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec); diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index b3fabad3..b5ba9df1 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -136,9 +136,9 @@ pa_sink_input* pa_sink_input_new( !pa_channel_map_equal(&data->channel_map, &data->sink->channel_map)) if (!(resampler = pa_resampler_new( + core->mempool, &data->sample_spec, &data->channel_map, &data->sink->sample_spec, &data->sink->channel_map, - core->memblock_stat, data->resample_method))) { pa_log_warn(__FILE__": Unsupported resampling operation."); return NULL; @@ -299,7 +299,7 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) * while until the old sink has drained its playback buffer */ if (!i->silence_memblock) - i->silence_memblock = pa_silence_memblock_new(&i->sink->sample_spec, SILENCE_BUFFER_LENGTH, i->sink->core->memblock_stat); + i->silence_memblock = pa_silence_memblock_new(i->sink->core->mempool, &i->sink->sample_spec, SILENCE_BUFFER_LENGTH); chunk->memblock = pa_memblock_ref(i->silence_memblock); chunk->index = 0; @@ -338,7 +338,7 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) /* It might be necessary to adjust the volume here */ if (do_volume_adj_here && !volume_is_norm) { - pa_memchunk_make_writable(&tchunk, i->sink->core->memblock_stat, 0); + pa_memchunk_make_writable(&tchunk, 0); pa_volume_memchunk(&tchunk, &i->sample_spec, &i->volume); } @@ -540,9 +540,9 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { /* Okey, we need a new resampler for the new sink */ if (!(new_resampler = pa_resampler_new( + dest->core->mempool, &i->sample_spec, &i->channel_map, &dest->sample_spec, &dest->channel_map, - dest->core->memblock_stat, i->resample_method))) { pa_log_warn(__FILE__": Unsupported resampling operation."); return -1; @@ -553,7 +553,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { pa_usec_t old_latency, new_latency; pa_usec_t silence_usec = 0; - buffer = pa_memblockq_new(0, MOVE_BUFFER_LENGTH, 0, pa_frame_size(&origin->sample_spec), 0, 0, NULL, NULL); + buffer = pa_memblockq_new(0, MOVE_BUFFER_LENGTH, 0, pa_frame_size(&origin->sample_spec), 0, 0, NULL); /* Let's do a little bit of Voodoo for compensating latency * differences */ @@ -599,7 +599,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { chunk.length = n; if (!volume_is_norm) { - pa_memchunk_make_writable(&chunk, origin->core->memblock_stat, 0); + pa_memchunk_make_writable(&chunk, 0); pa_volume_memchunk(&chunk, &origin->sample_spec, &volume); } diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 557d5efc..aacb89fd 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -298,14 +298,14 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); if (s->sw_muted || !pa_cvolume_is_norm(&volume)) { - pa_memchunk_make_writable(result, s->core->memblock_stat, 0); + pa_memchunk_make_writable(result, 0); if (s->sw_muted) pa_silence_memchunk(result, &s->sample_spec); else pa_volume_memchunk(result, &s->sample_spec, &volume); } } else { - result->memblock = pa_memblock_new(length, s->core->memblock_stat); + result->memblock = pa_memblock_new(s->core->mempool, length); assert(result->memblock); /* pa_log("mixing %i", n); */ @@ -429,7 +429,7 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { /*** This needs optimization ***/ - result->memblock = pa_memblock_new(result->length = length, s->core->memblock_stat); + result->memblock = pa_memblock_new(s->core->mempool, result->length = length); result->index = 0; pa_sink_render_into_full(s, result); diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c index 6063b93e..6782f50e 100644 --- a/src/pulsecore/sound-file-stream.c +++ b/src/pulsecore/sound-file-stream.c @@ -75,7 +75,7 @@ static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { uint32_t fs = pa_frame_size(&i->sample_spec); sf_count_t n; - u->memchunk.memblock = pa_memblock_new(BUF_SIZE, i->sink->core->memblock_stat); + u->memchunk.memblock = pa_memblock_new(i->sink->core->mempool, BUF_SIZE); u->memchunk.index = 0; if (u->readf_function) { diff --git a/src/pulsecore/sound-file.c b/src/pulsecore/sound-file.c index d11d4b9d..256cce43 100644 --- a/src/pulsecore/sound-file.c +++ b/src/pulsecore/sound-file.c @@ -34,7 +34,7 @@ #include "sound-file.h" #include "core-scache.h" -int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_channel_map *map, pa_memchunk *chunk, pa_memblock_stat *s) { +int pa_sound_file_load(pa_mempool *pool, const char *fname, pa_sample_spec *ss, pa_channel_map *map, pa_memchunk *chunk) { SNDFILE*sf = NULL; SF_INFO sfinfo; int ret = -1; @@ -92,7 +92,7 @@ int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_channel_map *ma goto finish; } - chunk->memblock = pa_memblock_new(l, s); + chunk->memblock = pa_memblock_new(pool, l); assert(chunk->memblock); chunk->index = 0; chunk->length = l; diff --git a/src/pulsecore/sound-file.h b/src/pulsecore/sound-file.h index 0b81d97e..7e3c82ea 100644 --- a/src/pulsecore/sound-file.h +++ b/src/pulsecore/sound-file.h @@ -26,7 +26,7 @@ #include #include -int pa_sound_file_load(const char *fname, pa_sample_spec *ss, pa_channel_map *map, pa_memchunk *chunk, pa_memblock_stat *s); +int pa_sound_file_load(pa_mempool *pool, const char *fname, pa_sample_spec *ss, pa_channel_map *map, pa_memchunk *chunk); int pa_sound_file_too_big_to_cache(const char *fname); diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 7371474f..f9d66f6d 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -115,9 +115,9 @@ pa_source_output* pa_source_output_new( if (!pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec) || !pa_channel_map_equal(&data->channel_map, &data->source->channel_map)) if (!(resampler = pa_resampler_new( + core->mempool, &data->source->sample_spec, &data->source->channel_map, &data->sample_spec, &data->channel_map, - core->memblock_stat, data->resample_method))) { pa_log_warn(__FILE__": Unsupported resampling operation."); return NULL; @@ -330,9 +330,9 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { /* Okey, we need a new resampler for the new sink */ if (!(new_resampler = pa_resampler_new( + dest->core->mempool, &dest->sample_spec, &dest->channel_map, &o->sample_spec, &o->channel_map, - dest->core->memblock_stat, o->resample_method))) { pa_log_warn(__FILE__": Unsupported resampling operation."); return -1; diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 0d55da44..cb5b1030 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -211,7 +211,7 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) { pa_memchunk vchunk = *chunk; pa_memblock_ref(vchunk.memblock); - pa_memchunk_make_writable(&vchunk, s->core->memblock_stat, 0); + pa_memchunk_make_writable(&vchunk, 0); if (s->sw_muted) pa_silence_memchunk(&vchunk, &s->sample_spec); else -- cgit From c3fc2eaa7e44c1d71f53e4f61c874f551a65de3e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 19:56:11 +0000 Subject: update tests for new memory manager git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1267 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/tests/mcalign-test.c | 11 +++++++++-- src/tests/memblockq-test.c | 16 ++++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/tests/mcalign-test.c b/src/tests/mcalign-test.c index 7a68e6de..35691698 100644 --- a/src/tests/mcalign-test.c +++ b/src/tests/mcalign-test.c @@ -38,9 +38,14 @@ /* A simple program for testing pa_mcalign */ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { - pa_mcalign *a = pa_mcalign_new(11, NULL); + pa_mempool *p; + pa_mcalign *a; pa_memchunk c; + p = pa_mempool_new(0); + + a = pa_mcalign_new(11); + pa_memchunk_reset(&c); srand(time(NULL)); @@ -50,7 +55,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { size_t l; if (!c.memblock) { - c.memblock = pa_memblock_new(2048, NULL); + c.memblock = pa_memblock_new(p, 2048); c.index = c.length = 0; } @@ -94,5 +99,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { if (c.memblock) pa_memblock_unref(c.memblock); + pa_mempool_free(p); + return 0; } diff --git a/src/tests/memblockq-test.c b/src/tests/memblockq-test.c index af43d06f..1ac4577b 100644 --- a/src/tests/memblockq-test.c +++ b/src/tests/memblockq-test.c @@ -32,34 +32,38 @@ int main(int argc, char *argv[]) { int ret; + + pa_mempool *p; pa_memblockq *bq; pa_memchunk chunk1, chunk2, chunk3, chunk4; pa_memblock *silence; pa_log_set_maximal_level(PA_LOG_DEBUG); + + p = pa_mempool_new(0); - silence = pa_memblock_new_fixed((char*) "__", 2, 1, NULL); + silence = pa_memblock_new_fixed(p, (char*) "__", 2, 1); assert(silence); - bq = pa_memblockq_new(0, 40, 10, 2, 4, 4, silence, NULL); + bq = pa_memblockq_new(0, 40, 10, 2, 4, 4, silence); assert(bq); - chunk1.memblock = pa_memblock_new_fixed((char*) "AA", 2, 1, NULL); + chunk1.memblock = pa_memblock_new_fixed(p, (char*) "AA", 2, 1); chunk1.index = 0; chunk1.length = 2; assert(chunk1.memblock); - chunk2.memblock = pa_memblock_new_fixed((char*) "TTBB", 4, 1, NULL); + chunk2.memblock = pa_memblock_new_fixed(p, (char*) "TTBB", 4, 1); chunk2.index = 2; chunk2.length = 2; assert(chunk2.memblock); - chunk3.memblock = pa_memblock_new_fixed((char*) "ZZZZ", 4, 1, NULL); + chunk3.memblock = pa_memblock_new_fixed(p, (char*) "ZZZZ", 4, 1); chunk3.index = 0; chunk3.length = 4; assert(chunk3.memblock); - chunk4.memblock = pa_memblock_new_fixed((char*) "KKKKKKKK", 8, 1, NULL); + chunk4.memblock = pa_memblock_new_fixed(p, (char*) "KKKKKKKK", 8, 1); chunk4.index = 0; chunk4.length = 8; assert(chunk4.memblock); -- cgit From 35caf0c4eaedbf8553c1fe59e7d3e3438e59a7d9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 19:56:51 +0000 Subject: add new test memblock-test for testing SHM import/export git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1268 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 17 +++-- src/tests/memblock-test.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 src/tests/memblock-test.c diff --git a/src/Makefile.am b/src/Makefile.am index 0ab0436b..c4988d8e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -197,7 +197,8 @@ noinst_PROGRAMS = \ utf8-test \ get-binary-name-test \ ipacl-test \ - hook-list-test + hook-list-test \ + memblock-test if HAVE_SIGXCPU noinst_PROGRAMS += \ @@ -242,6 +243,11 @@ hook_list_test_CFLAGS = $(AM_CFLAGS) hook_list_test_LDADD = $(AM_LDADD) libpulsecore.la hook_list_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +memblock_test_SOURCES = tests/memblock-test.c +memblock_test_CFLAGS = $(AM_CFLAGS) +memblock_test_LDADD = $(AM_LDADD) libpulsecore.la +memblock_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + mcalign_test_SOURCES = tests/mcalign-test.c mcalign_test_CFLAGS = $(AM_CFLAGS) mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpulsecore.la @@ -414,7 +420,8 @@ libpulse_la_SOURCES += \ pulsecore/strlist.c pulsecore/strlist.h \ pulsecore/tagstruct.c pulsecore/tagstruct.h \ pulsecore/core-error.c pulsecore/core-error.h \ - pulsecore/winsock.h pulsecore/creds.h + pulsecore/winsock.h pulsecore/creds.h \ + pulsecore/shm.c pulsecore/shm.h if OS_IS_WIN32 libpulse_la_SOURCES += \ @@ -519,7 +526,8 @@ pulsecoreinclude_HEADERS = \ pulsecore/source-output.h \ pulsecore/strbuf.h \ pulsecore/tokenizer.h \ - pulsecore/creds.h + pulsecore/creds.h \ + pulsecore/shm.h lib_LTLIBRARIES += libpulsecore.la @@ -586,7 +594,8 @@ libpulsecore_la_SOURCES += \ pulsecore/tokenizer.c pulsecore/tokenizer.h \ pulsecore/winsock.h \ pulsecore/core-error.c pulsecore/core-error.h \ - pulsecore/hook-list.c pulsecore/hook-list.h + pulsecore/hook-list.c pulsecore/hook-list.h \ + pulsecore/shm.c pulsecore/shm.h if OS_IS_WIN32 libpulsecore_la_SOURCES += \ diff --git a/src/tests/memblock-test.c b/src/tests/memblock-test.c new file mode 100644 index 00000000..11198ae6 --- /dev/null +++ b/src/tests/memblock-test.c @@ -0,0 +1,164 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +static void release_cb(pa_memimport *i, uint32_t block_id, void *userdata) { + printf("%s: Imported block %u is released.\n", (char*) userdata, block_id); +} + +static void revoke_cb(pa_memexport *e, uint32_t block_id, void *userdata) { + printf("%s: Exported block %u is revoked.\n", (char*) userdata, block_id); +} + +static void print_stats(pa_mempool *p, const char *text) { + const pa_mempool_stat*s = pa_mempool_get_stat(p); + + printf("%s = {\n" + "n_allocated = %u\n" + "n_accumulated = %u\n" + "n_imported = %u\n" + "n_exported = %u\n" + "allocated_size = %lu\n" + "accumulated_size = %lu\n" + "imported_size = %lu\n" + "exported_size = %lu\n" + "n_too_large_for_pool = %u\n" + "n_pool_full = %u\n" + "}\n", + text, + s->n_allocated, + s->n_accumulated, + s->n_imported, + s->n_exported, + (unsigned long) s->allocated_size, + (unsigned long) s->accumulated_size, + (unsigned long) s->imported_size, + (unsigned long) s->exported_size, + s->n_too_large_for_pool, + s->n_pool_full); +} + +int main(int argc, char *argv[]) { + pa_mempool *pool_a, *pool_b, *pool_c; + unsigned id_a, id_b, id_c; + pa_memexport *export_a, *export_b; + pa_memimport *import_b, *import_c; + pa_memblock *mb_a, *mb_b, *mb_c; + int r, i; + pa_memblock* blocks[5]; + uint32_t id, shm_id; + size_t offset, size; + + const char txt[] = "This is a test!"; + + pool_a = pa_mempool_new(1); + pool_b = pa_mempool_new(1); + pool_c = pa_mempool_new(1); + + pa_mempool_get_shm_id(pool_a, &id_a); + pa_mempool_get_shm_id(pool_b, &id_b); + pa_mempool_get_shm_id(pool_c, &id_c); + + assert(pool_a && pool_b && pool_c); + + blocks[0] = pa_memblock_new_fixed(pool_a, (void*) txt, sizeof(txt), 1); + blocks[1] = pa_memblock_new(pool_a, sizeof(txt)); + snprintf(blocks[1]->data, blocks[1]->length, "%s", txt); + blocks[2] = pa_memblock_new_pool(pool_a, sizeof(txt)); + snprintf(blocks[2]->data, blocks[2]->length, "%s", txt); + blocks[3] = pa_memblock_new_malloced(pool_a, pa_xstrdup(txt), sizeof(txt)); + blocks[4] = NULL; + + for (i = 0; blocks[i]; i++) { + printf("Memory block %u\n", i); + + mb_a = blocks[i]; + assert(mb_a); + + export_a = pa_memexport_new(pool_a, revoke_cb, (void*) "A"); + export_b = pa_memexport_new(pool_b, revoke_cb, (void*) "B"); + + assert(export_a && export_b); + + import_b = pa_memimport_new(pool_b, release_cb, (void*) "B"); + import_c = pa_memimport_new(pool_c, release_cb, (void*) "C"); + + assert(import_b && import_c); + + r = pa_memexport_put(export_a, mb_a, &id, &shm_id, &offset, &size); + assert(r >= 0); + assert(shm_id == id_a); + + printf("A: Memory block exported as %u\n", id); + + mb_b = pa_memimport_get(import_b, id, shm_id, offset, size); + assert(mb_b); + r = pa_memexport_put(export_b, mb_b, &id, &shm_id, &offset, &size); + assert(r >= 0); + assert(shm_id == id_a || shm_id == id_b); + pa_memblock_unref(mb_b); + + printf("B: Memory block exported as %u\n", id); + + mb_c = pa_memimport_get(import_c, id, shm_id, offset, size); + assert(mb_c); + printf("1 data=%s\n", (char*) mb_c->data); + + print_stats(pool_a, "A"); + print_stats(pool_b, "B"); + print_stats(pool_c, "C"); + + pa_memexport_free(export_b); + printf("2 data=%s\n", (char*) mb_c->data); + pa_memblock_unref(mb_c); + + pa_memimport_free(import_b); + + pa_memblock_unref(mb_a); + + pa_memimport_free(import_c); + pa_memexport_free(export_a); + } + + printf("vaccuuming...\n"); + + pa_mempool_vacuum(pool_a); + pa_mempool_vacuum(pool_b); + pa_mempool_vacuum(pool_c); + + printf("vaccuuming done...\n"); + + pa_mempool_free(pool_a); + pa_mempool_free(pool_b); + pa_mempool_free(pool_c); + + return 0; +} -- cgit From 8ebef4d00f1868fd968218d594c7993c1c4254b1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 19:57:19 +0000 Subject: look for shm_open in -lrt git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1269 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure.ac b/configure.ac index 68d9d5d5..07b2cfa1 100644 --- a/configure.ac +++ b/configure.ac @@ -206,6 +206,8 @@ AC_SEARCH_LIBS([dlopen], [dl]) # BSD AC_SEARCH_LIBS([connect], [socket]) +AC_SEARCH_LIBS([shm_open], [rt]) + # Non-standard # This magic is needed so we do not needlessly add static libs to the win32 -- cgit From 666eca38b9db862629c22c858767a14962cbd262 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 19:57:53 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1270 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 2 ++ 1 file changed, 2 insertions(+) diff --git a/todo b/todo index 2c67f6d5..c4bb9b0d 100644 --- a/todo +++ b/todo @@ -22,6 +22,8 @@ Cleanups: - use software volume when hardware doesn't support all channels (alsa done) - silence generation should be moved into the core to avoid races and code duplication in the backends +- rework resampler to not use pa_xrealloc. Use pa_memblock_new instead. +- allow disabling shm in both client and server Auth/Crypto: - ssl -- cgit From 1bc62d5ec671bf3edab5263fdc8015c0a701ce81 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 21:26:01 +0000 Subject: rework logging subsystem, to implicitly include __FILE__ in pa_log() calls. In addition we now record the line numbers and function names of pa_log calls. However, those are only shown If $PULSE_LOG_META is set. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1271 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/log.c | 81 +++++++++++++++++++++++++++-------------------------- src/pulsecore/log.h | 49 +++++++++++++++++++++++++++----- 2 files changed, 84 insertions(+), 46 deletions(-) diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c index 06e95b28..8bc673e5 100644 --- a/src/pulsecore/log.c +++ b/src/pulsecore/log.c @@ -35,12 +35,14 @@ #include #include +#include #include #include "log.h" #define ENV_LOGLEVEL "PULSE_LOG" +#define ENV_LOGMETA "PULSE_LOG_META" static char *log_ident = NULL, *log_ident_local = NULL; static pa_log_target_t log_target = PA_LOG_STDERR; @@ -80,11 +82,19 @@ void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t l, const c user_log_func = func; } -void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { +void pa_log_levelv_meta( + pa_log_level_t level, + const char*file, + int line, + const char *func, + const char *format, + va_list ap) { + const char *e; - char *text, *t, *n; + char *text, *t, *n, *location = pa_xstrdup(""); assert(level < PA_LOG_LEVEL_MAX); + assert(format); if ((e = getenv(ENV_LOGLEVEL))) maximal_level = atoi(e); @@ -94,6 +104,11 @@ void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { text = pa_vsprintf_malloc(format, ap); + if (getenv(ENV_LOGMETA) && file && line > 0 && func) + location = pa_sprintf_malloc("[%s:%i %s()] ", file, line, func); + else if (file) + location = pa_sprintf_malloc("%s: ", pa_path_get_filename(file)); + if (!pa_utf8_valid(text)) pa_log_level(level, __FILE__": invalid UTF-8 string following below:"); @@ -126,9 +141,9 @@ void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { local_t = pa_utf8_to_locale(t); if (!local_t) - fprintf(stderr, "%s%s%s\n", prefix, t, suffix); + fprintf(stderr, "%s%s%s%s\n", location, prefix, t, suffix); else { - fprintf(stderr, "%s%s%s\n", prefix, local_t, suffix); + fprintf(stderr, "%s%s%s%s\n", location, prefix, local_t, suffix); pa_xfree(local_t); } @@ -143,9 +158,9 @@ void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { local_t = pa_utf8_to_locale(t); if (!local_t) - syslog(level_to_syslog[level], "%s", t); + syslog(level_to_syslog[level], "%s%s", location, t); else { - syslog(level_to_syslog[level], "%s", local_t); + syslog(level_to_syslog[level], "%s%s", location, local_t); pa_xfree(local_t); } @@ -154,9 +169,15 @@ void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { } #endif - case PA_LOG_USER: - user_log_func(level, t); + case PA_LOG_USER: { + char *x; + + x = pa_sprintf_malloc("%s%s", location, t); + user_log_func(level, x); + pa_xfree(x); + break; + } case PA_LOG_NULL: default: @@ -165,47 +186,29 @@ void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { } pa_xfree(text); - + pa_xfree(location); } -void pa_log_level(pa_log_level_t level, const char *format, ...) { - va_list ap; - va_start(ap, format); - pa_log_levelv(level, format, ap); - va_end(ap); -} - -void pa_log_debug(const char *format, ...) { - va_list ap; - va_start(ap, format); - pa_log_levelv(PA_LOG_DEBUG, format, ap); - va_end(ap); -} - -void pa_log_info(const char *format, ...) { - va_list ap; - va_start(ap, format); - pa_log_levelv(PA_LOG_INFO, format, ap); - va_end(ap); -} - -void pa_log_notice(const char *format, ...) { +void pa_log_level_meta( + pa_log_level_t level, + const char*file, + int line, + const char *func, + const char *format, ...) { + va_list ap; va_start(ap, format); - pa_log_levelv(PA_LOG_INFO, format, ap); + pa_log_levelv_meta(level, file, line, func, format, ap); va_end(ap); } -void pa_log_warn(const char *format, ...) { - va_list ap; - va_start(ap, format); - pa_log_levelv(PA_LOG_WARN, format, ap); - va_end(ap); +void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { + pa_log_levelv_meta(level, NULL, 0, NULL, format, ap); } -void pa_log_error(const char *format, ...) { +void pa_log_level(pa_log_level_t level, const char *format, ...) { va_list ap; va_start(ap, format); - pa_log_levelv(PA_LOG_ERROR, format, ap); + pa_log_levelv_meta(level, NULL, 0, NULL, format, ap); va_end(ap); } diff --git a/src/pulsecore/log.h b/src/pulsecore/log.h index 7bf4e407..bf0e75f5 100644 --- a/src/pulsecore/log.h +++ b/src/pulsecore/log.h @@ -23,6 +23,7 @@ ***/ #include +#include #include /* A simple logging subsystem */ @@ -53,17 +54,51 @@ void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t t, const c /* Minimal log level */ void pa_log_set_maximal_level(pa_log_level_t l); -/* Do a log line */ -void pa_log_debug(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); -void pa_log_info(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); -void pa_log_notice(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); -void pa_log_warn(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); -void pa_log_error(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); +void pa_log_level_meta( + pa_log_level_t level, + const char*file, + int line, + const char *func, + const char *format, ...) PA_GCC_PRINTF_ATTR(5,6); +void pa_log_levelv_meta( + pa_log_level_t level, + const char*file, + int line, + const char *func, + const char *format, + va_list ap); void pa_log_level(pa_log_level_t level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); - void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap); +#if __STDC_VERSION__ >= 199901L + +/* ISO varargs available */ + +#define pa_log_debug(...) pa_log_level_meta(PA_LOG_DEBUG, __FILE__, __LINE__, __func__, __VA_ARGS__) +#define pa_log_info(...) pa_log_level_meta(PA_LOG_INFO, __FILE__, __LINE__, __func__, __VA_ARGS__) +#define pa_log_notice(...) pa_log_level_meta(PA_LOG_NOTICE, __FILE__, __LINE__, __func__, __VA_ARGS__) +#define pa_log_warn(...) pa_log_level_meta(PA_LOG_WARN, __FILE__, __LINE__, __func__, __VA_ARGS__) +#define pa_log_error(...) pa_log_level_meta(PA_LOG_ERROR, __FILE__, __LINE__, __func__, __VA_ARGS__) + +#else + +#define LOG_FUNC(suffix, level) \ +PA_GCC_UNUSED static void pa_log_##suffix(const char *format, ...) { \ + va_list ap; \ + va_start(ap, format); \ + pa_log_levelv_meta(level, NULL, 0, NULL, format, ap); \ + va_end(ap); \ +} + +LOG_FUNC(debug, PA_LOG_DEBUG) +LOG_FUNC(info, PA_LOG_INFO) +LOG_FUNC(notice, PA_LOG_NOTICE) +LOG_FUNC(warn, PA_LOG_WARN) +LOG_FUNC(error, PA_LOG_ERROR) + +#endif + #define pa_log pa_log_error #endif -- cgit From e385d93e5aad6a6fce754c00c804ff1d6a6746d4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 21:38:40 +0000 Subject: remove all occurences of pa_logXXX(__FILE__": and replace them by pa_logXXX(" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1272 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/caps.c | 6 +-- src/daemon/cmdline.c | 20 ++++----- src/daemon/cpulimit.c | 2 +- src/daemon/daemon-conf.c | 12 ++--- src/daemon/main.c | 68 ++++++++++++++--------------- src/modules/alsa-util.c | 22 +++++----- src/modules/dbus-util.c | 2 +- src/modules/gconf/module-gconf.c | 14 +++--- src/modules/module-alsa-sink.c | 38 ++++++++-------- src/modules/module-alsa-source.c | 38 ++++++++-------- src/modules/module-cli.c | 8 ++-- src/modules/module-combine.c | 32 +++++++------- src/modules/module-detect.c | 14 +++--- src/modules/module-esound-compat-spawnfd.c | 4 +- src/modules/module-esound-compat-spawnpid.c | 4 +- src/modules/module-esound-sink.c | 24 +++++----- src/modules/module-hal-detect.c | 28 ++++++------ src/modules/module-jack-sink.c | 28 ++++++------ src/modules/module-jack-source.c | 28 ++++++------ src/modules/module-lirc.c | 20 ++++----- src/modules/module-match.c | 10 ++--- src/modules/module-mmkbd-evdev.c | 28 ++++++------ src/modules/module-native-protocol-fd.c | 4 +- src/modules/module-null-sink.c | 6 +-- src/modules/module-oss-mmap.c | 52 +++++++++++----------- src/modules/module-oss.c | 34 +++++++-------- src/modules/module-pipe-sink.c | 14 +++--- src/modules/module-pipe-source.c | 14 +++--- src/modules/module-protocol-stub.c | 10 ++--- src/modules/module-rescue-streams.c | 18 ++++---- src/modules/module-sine.c | 6 +-- src/modules/module-solaris.c | 36 +++++++-------- src/modules/module-tunnel.c | 58 ++++++++++++------------ src/modules/module-volume-restore.c | 20 ++++----- src/modules/module-waveout.c | 24 +++++----- src/modules/module-x11-bell.c | 10 ++--- src/modules/module-x11-publish.c | 8 ++-- src/modules/module-zeroconf-publish.c | 22 +++++----- src/modules/oss-util.c | 32 +++++++------- src/modules/rtp/module-rtp-recv.c | 24 +++++----- src/modules/rtp/module-rtp-send.c | 36 +++++++-------- src/modules/rtp/rtp.c | 18 ++++---- src/modules/rtp/sap.c | 16 +++---- src/modules/rtp/sdp.c | 16 +++---- src/pulse/client-conf-x11.c | 4 +- src/pulse/client-conf.c | 2 +- src/pulse/context.c | 8 ++-- src/pulse/mainloop-signal.c | 6 +-- src/pulse/mainloop.c | 6 +-- src/pulse/thread-mainloop.c | 2 +- src/pulse/util.c | 6 +-- src/pulsecore/authkey.c | 16 +++---- src/pulsecore/cli.c | 4 +- src/pulsecore/client.c | 8 ++-- src/pulsecore/conf-parser.c | 12 ++--- src/pulsecore/core-scache.c | 4 +- src/pulsecore/core-subscribe.c | 6 +-- src/pulsecore/core-util.c | 52 +++++++++++----------- src/pulsecore/ioline.c | 4 +- src/pulsecore/ipacl.c | 12 ++--- src/pulsecore/memblock.c | 6 +-- src/pulsecore/memblockq.c | 4 +- src/pulsecore/modinfo.c | 2 +- src/pulsecore/module.c | 14 +++--- src/pulsecore/pdispatch.c | 4 +- src/pulsecore/pid.c | 28 ++++++------ src/pulsecore/protocol-cli.c | 2 +- src/pulsecore/protocol-esound.c | 36 +++++++-------- src/pulsecore/protocol-http.c | 4 +- src/pulsecore/protocol-native.c | 48 ++++++++++---------- src/pulsecore/protocol-simple.c | 18 ++++---- src/pulsecore/pstream.c | 24 +++++----- src/pulsecore/random.c | 4 +- src/pulsecore/sample-util.c | 4 +- src/pulsecore/shm.c | 18 ++++---- src/pulsecore/sink-input.c | 12 ++--- src/pulsecore/sink.c | 6 +-- src/pulsecore/socket-client.c | 14 +++--- src/pulsecore/socket-server.c | 38 ++++++++-------- src/pulsecore/socket-util.c | 6 +-- src/pulsecore/sound-file-stream.c | 4 +- src/pulsecore/sound-file.c | 12 ++--- src/pulsecore/source-output.c | 12 ++--- src/pulsecore/source.c | 4 +- src/pulsecore/x11wrap.c | 2 +- src/utils/pacmd.c | 20 ++++----- src/utils/pax11publish.c | 2 +- 87 files changed, 714 insertions(+), 714 deletions(-) diff --git a/src/daemon/caps.c b/src/daemon/caps.c index 8ae43fb2..cebdaebc 100644 --- a/src/daemon/caps.c +++ b/src/daemon/caps.c @@ -54,7 +54,7 @@ void pa_drop_root(void) { if (uid == 0 || geteuid() != 0) return; - pa_log_info(__FILE__": dropping root rights."); + pa_log_info("dropping root rights."); #if defined(HAVE_SETRESUID) setresuid(uid, uid, uid); @@ -96,7 +96,7 @@ int pa_limit_caps(void) { if (cap_set_proc(caps) < 0) goto fail; - pa_log_info(__FILE__": dropped capabilities successfully."); + pa_log_info("dropped capabilities successfully."); r = 0; @@ -121,7 +121,7 @@ int pa_drop_caps(void) { cap_clear(caps); if (cap_set_proc(caps) < 0) { - pa_log(__FILE__": failed to drop capabilities: %s", pa_cstrerror(errno)); + pa_log("failed to drop capabilities: %s", pa_cstrerror(errno)); goto fail; } diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c index e00f290e..d3fe8e65 100644 --- a/src/daemon/cmdline.c +++ b/src/daemon/cmdline.c @@ -199,14 +199,14 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d case ARG_DAEMONIZE: case 'D': if ((conf->daemonize = optarg ? pa_parse_boolean(optarg) : 1) < 0) { - pa_log(__FILE__": --daemonize expects boolean argument"); + pa_log("--daemonize expects boolean argument"); goto fail; } break; case ARG_FAIL: if ((conf->fail = optarg ? pa_parse_boolean(optarg) : 1) < 0) { - pa_log(__FILE__": --fail expects boolean argument"); + pa_log("--fail expects boolean argument"); goto fail; } break; @@ -216,7 +216,7 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d if (optarg) { if (pa_daemon_conf_set_log_level(conf, optarg) < 0) { - pa_log(__FILE__": --log-level expects log level argument (either numeric in range 0..4 or one of debug, info, notice, warn, error)."); + pa_log("--log-level expects log level argument (either numeric in range 0..4 or one of debug, info, notice, warn, error)."); goto fail; } } else { @@ -228,21 +228,21 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d case ARG_HIGH_PRIORITY: if ((conf->high_priority = optarg ? pa_parse_boolean(optarg) : 1) < 0) { - pa_log(__FILE__": --high-priority expects boolean argument"); + pa_log("--high-priority expects boolean argument"); goto fail; } break; case ARG_DISALLOW_MODULE_LOADING: if ((conf->disallow_module_loading = optarg ? pa_parse_boolean(optarg) : 1) < 0) { - pa_log(__FILE__": --disallow-module-loading expects boolean argument"); + pa_log("--disallow-module-loading expects boolean argument"); goto fail; } break; case ARG_USE_PID_FILE: if ((conf->use_pid_file = optarg ? pa_parse_boolean(optarg) : 1) < 0) { - pa_log(__FILE__": --use-pid-file expects boolean argument"); + pa_log("--use-pid-file expects boolean argument"); goto fail; } break; @@ -260,7 +260,7 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d case ARG_LOG_TARGET: if (pa_daemon_conf_set_log_target(conf, optarg) < 0) { - pa_log(__FILE__": Invalid log target: use either 'syslog', 'stderr' or 'auto'."); + pa_log("Invalid log target: use either 'syslog', 'stderr' or 'auto'."); goto fail; } break; @@ -279,21 +279,21 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d case ARG_RESAMPLE_METHOD: if (pa_daemon_conf_set_resample_method(conf, optarg) < 0) { - pa_log(__FILE__": Invalid resample method '%s'.", optarg); + pa_log("Invalid resample method '%s'.", optarg); goto fail; } break; case ARG_SYSTEM: if ((conf->system_instance = optarg ? pa_parse_boolean(optarg) : 1) < 0) { - pa_log(__FILE__": --system expects boolean argument"); + pa_log("--system expects boolean argument"); goto fail; } break; case ARG_NO_CPU_LIMIT: if ((conf->no_cpu_limit = optarg ? pa_parse_boolean(optarg) : 1) < 0) { - pa_log(__FILE__": --no-cpu-limit expects boolean argument"); + pa_log("--no-cpu-limit expects boolean argument"); goto fail; } break; diff --git a/src/daemon/cpulimit.c b/src/daemon/cpulimit.c index b8740ea0..d7466b06 100644 --- a/src/daemon/cpulimit.c +++ b/src/daemon/cpulimit.c @@ -172,7 +172,7 @@ int pa_cpu_limit_init(pa_mainloop_api *m) { /* Prepare the main loop pipe */ if (pipe(the_pipe) < 0) { - pa_log(__FILE__": pipe() failed: %s", pa_cstrerror(errno)); + pa_log("pipe() failed: %s", pa_cstrerror(errno)); return -1; } diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 3e585d90..2cb06697 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -168,7 +168,7 @@ static int parse_log_target(const char *filename, unsigned line, const char *lva assert(filename && lvalue && rvalue && data); if (pa_daemon_conf_set_log_target(c, rvalue) < 0) { - pa_log(__FILE__": [%s:%u] Invalid log target '%s'.", filename, line, rvalue); + pa_log("[%s:%u] Invalid log target '%s'.", filename, line, rvalue); return -1; } @@ -180,7 +180,7 @@ static int parse_log_level(const char *filename, unsigned line, const char *lval assert(filename && lvalue && rvalue && data); if (pa_daemon_conf_set_log_level(c, rvalue) < 0) { - pa_log(__FILE__": [%s:%u] Invalid log level '%s'.", filename, line, rvalue); + pa_log("[%s:%u] Invalid log level '%s'.", filename, line, rvalue); return -1; } @@ -192,7 +192,7 @@ static int parse_resample_method(const char *filename, unsigned line, const char assert(filename && lvalue && rvalue && data); if (pa_daemon_conf_set_resample_method(c, rvalue) < 0) { - pa_log(__FILE__": [%s:%u] Inavalid resample method '%s'.", filename, line, rvalue); + pa_log("[%s:%u] Inavalid resample method '%s'.", filename, line, rvalue); return -1; } @@ -214,14 +214,14 @@ static int parse_rlimit(const char *filename, unsigned line, const char *lvalue, } else { int32_t k; if (pa_atoi(rvalue, &k) < 0) { - pa_log(__FILE__": [%s:%u] Inavalid rlimit '%s'.", filename, line, rvalue); + pa_log("[%s:%u] Inavalid rlimit '%s'.", filename, line, rvalue); return -1; } r->is_set = k >= 0; r->value = k >= 0 ? (rlim_t) k : 0; } #else - pa_log_warn(__FILE__": [%s:%u] rlimit not supported on this platform.", filename, line); + pa_log_warn("[%s:%u] rlimit not supported on this platform.", filename, line); #endif return 0; @@ -308,7 +308,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { pa_open_config_file(DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file, "r"); if (!f && errno != ENOENT) { - pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", c->config_file, pa_cstrerror(errno)); + pa_log("WARNING: failed to open configuration file '%s': %s", c->config_file, pa_cstrerror(errno)); goto finish; } diff --git a/src/daemon/main.c b/src/daemon/main.c index aada0ad7..95ba6dd5 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -117,7 +117,7 @@ static void message_cb(pa_mainloop_api*a, pa_time_event*e, PA_GCC_UNUSED const s #endif static void signal_callback(pa_mainloop_api*m, PA_GCC_UNUSED pa_signal_event *e, int sig, void *userdata) { - pa_log_info(__FILE__": Got signal %s.", pa_strsignal(sig)); + pa_log_info("Got signal %s.", pa_strsignal(sig)); switch (sig) { #ifdef SIGUSR1 @@ -144,7 +144,7 @@ static void signal_callback(pa_mainloop_api*m, PA_GCC_UNUSED pa_signal_event *e, case SIGINT: case SIGTERM: default: - pa_log_info(__FILE__": Exiting."); + pa_log_info("Exiting."); m->quit(m, 1); break; } @@ -172,34 +172,34 @@ static int change_user(void) { * afterwards. */ if (!(pw = getpwnam(PA_SYSTEM_USER))) { - pa_log(__FILE__": Failed to find user '%s'.", PA_SYSTEM_USER); + pa_log("Failed to find user '%s'.", PA_SYSTEM_USER); return -1; } if (!(gr = getgrnam(PA_SYSTEM_GROUP))) { - pa_log(__FILE__": Failed to find group '%s'.", PA_SYSTEM_GROUP); + pa_log("Failed to find group '%s'.", PA_SYSTEM_GROUP); return -1; } - pa_log_info(__FILE__": Found user '%s' (UID %lu) and group '%s' (GID %lu).", + pa_log_info("Found user '%s' (UID %lu) and group '%s' (GID %lu).", PA_SYSTEM_USER, (unsigned long) pw->pw_uid, PA_SYSTEM_GROUP, (unsigned long) gr->gr_gid); if (pw->pw_gid != gr->gr_gid) { - pa_log(__FILE__": GID of user '%s' and of group '%s' don't match.", PA_SYSTEM_USER, PA_SYSTEM_GROUP); + pa_log("GID of user '%s' and of group '%s' don't match.", PA_SYSTEM_USER, PA_SYSTEM_GROUP); return -1; } if (strcmp(pw->pw_dir, PA_SYSTEM_RUNTIME_PATH) != 0) - pa_log_warn(__FILE__": Warning: home directory of user '%s' is not '%s', ignoring.", PA_SYSTEM_USER, PA_SYSTEM_RUNTIME_PATH); + pa_log_warn("Warning: home directory of user '%s' is not '%s', ignoring.", PA_SYSTEM_USER, PA_SYSTEM_RUNTIME_PATH); if (pa_make_secure_dir(PA_SYSTEM_RUNTIME_PATH, 0755, pw->pw_uid, gr->gr_gid) < 0) { - pa_log(__FILE__": Failed to create '%s': %s", PA_SYSTEM_RUNTIME_PATH, pa_cstrerror(errno)); + pa_log("Failed to create '%s': %s", PA_SYSTEM_RUNTIME_PATH, pa_cstrerror(errno)); return -1; } if (initgroups(PA_SYSTEM_USER, gr->gr_gid) != 0) { - pa_log(__FILE__": Failed to change group list: %s", pa_cstrerror(errno)); + pa_log("Failed to change group list: %s", pa_cstrerror(errno)); return -1; } @@ -215,7 +215,7 @@ static int change_user(void) { #endif if (r < 0) { - pa_log(__FILE__": Failed to change GID: %s", pa_cstrerror(errno)); + pa_log("Failed to change GID: %s", pa_cstrerror(errno)); return -1; } @@ -231,7 +231,7 @@ static int change_user(void) { #endif if (r < 0) { - pa_log(__FILE__": Failed to change UID: %s", pa_cstrerror(errno)); + pa_log("Failed to change UID: %s", pa_cstrerror(errno)); return -1; } @@ -243,7 +243,7 @@ static int change_user(void) { set_env("PULSE_RUNTIME_PATH", PA_SYSTEM_RUNTIME_PATH); set_env("PULSE_CONFIG_PATH", PA_SYSTEM_RUNTIME_PATH); - pa_log_info(__FILE__": Successfully dropped root privileges."); + pa_log_info("Successfully dropped root privileges."); return 0; } @@ -251,7 +251,7 @@ static int change_user(void) { #else /* HAVE_PWD_H && HAVE_GRP_H */ static int change_user(void) { - pa_log(__FILE__": System wide mode unsupported on this platform."); + pa_log("System wide mode unsupported on this platform."); return -1; } @@ -267,7 +267,7 @@ static int create_runtime_dir(void) { * /tmp/ with the current UID/GID */ if (pa_make_secure_dir(fn, 0700, (uid_t)-1, (gid_t)-1) < 0) { - pa_log(__FILE__": Failed to create '%s': %s", fn, pa_cstrerror(errno)); + pa_log("Failed to create '%s': %s", fn, pa_cstrerror(errno)); return -1; } @@ -286,7 +286,7 @@ static void set_one_rlimit(const pa_rlimit *r, int resource, const char *name) { rl.rlim_cur = rl.rlim_max = r->value; if (setrlimit(resource, &rl) < 0) - pa_log_warn(__FILE__": setrlimit(%s, (%u, %u)) failed: %s", name, (unsigned) r->value, (unsigned) r->value, pa_cstrerror(errno)); + pa_log_warn("setrlimit(%s, (%u, %u)) failed: %s", name, (unsigned) r->value, (unsigned) r->value, pa_cstrerror(errno)); } static void set_all_rlimits(const pa_daemon_conf *conf) { @@ -335,7 +335,7 @@ int main(int argc, char *argv[]) { suid_root = !real_root && geteuid() == 0; if (suid_root && (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) <= 0 || gid >= 1000)) { - pa_log_warn(__FILE__": WARNING: called SUID root, but not in group '"PA_REALTIME_GROUP"'."); + pa_log_warn("WARNING: called SUID root, but not in group '"PA_REALTIME_GROUP"'."); pa_drop_root(); } #else @@ -368,7 +368,7 @@ int main(int argc, char *argv[]) { goto finish; if (pa_cmdline_parse(conf, argc, argv, &d) < 0) { - pa_log(__FILE__": failed to parse command line."); + pa_log("failed to parse command line."); goto finish; } @@ -414,9 +414,9 @@ int main(int argc, char *argv[]) { pid_t pid; if (pa_pid_file_check_running(&pid) < 0) { - pa_log_info(__FILE__": daemon not running"); + pa_log_info("daemon not running"); } else { - pa_log_info(__FILE__": daemon running as PID %u", pid); + pa_log_info("daemon running as PID %u", pid); retval = 0; } @@ -426,7 +426,7 @@ int main(int argc, char *argv[]) { case PA_CMD_KILL: if (pa_pid_file_kill(SIGINT, NULL) < 0) - pa_log(__FILE__": failed to kill daemon."); + pa_log("failed to kill daemon."); else retval = 0; @@ -437,9 +437,9 @@ int main(int argc, char *argv[]) { } if (real_root && !conf->system_instance) { - pa_log_warn(__FILE__": This program is not intended to be run as root (unless --system is specified)."); + pa_log_warn("This program is not intended to be run as root (unless --system is specified)."); } else if (!real_root && conf->system_instance) { - pa_log(__FILE__": Root priviliges required."); + pa_log("Root priviliges required."); goto finish; } @@ -448,18 +448,18 @@ int main(int argc, char *argv[]) { int tty_fd; if (pa_stdio_acquire() < 0) { - pa_log(__FILE__": failed to acquire stdio."); + pa_log("failed to acquire stdio."); goto finish; } #ifdef HAVE_FORK if (pipe(daemon_pipe) < 0) { - pa_log(__FILE__": failed to create pipe."); + pa_log("failed to create pipe."); goto finish; } if ((child = fork()) < 0) { - pa_log(__FILE__": fork() failed: %s", pa_cstrerror(errno)); + pa_log("fork() failed: %s", pa_cstrerror(errno)); goto finish; } @@ -470,14 +470,14 @@ int main(int argc, char *argv[]) { daemon_pipe[1] = -1; if (pa_loop_read(daemon_pipe[0], &retval, sizeof(retval), NULL) != sizeof(retval)) { - pa_log(__FILE__": read() failed: %s", pa_cstrerror(errno)); + pa_log("read() failed: %s", pa_cstrerror(errno)); retval = 1; } if (retval) - pa_log(__FILE__": daemon startup failed."); + pa_log("daemon startup failed."); else - pa_log_info(__FILE__": daemon startup successful."); + pa_log_info("daemon startup successful."); goto finish; } @@ -537,7 +537,7 @@ int main(int argc, char *argv[]) { if (conf->use_pid_file) { if (pa_pid_file_create() < 0) { - pa_log(__FILE__": pa_pid_file_create() failed."); + pa_log("pa_pid_file_create() failed."); #ifdef HAVE_FORK if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL); @@ -604,13 +604,13 @@ int main(int argc, char *argv[]) { pa_xfree(s); if (r < 0 && conf->fail) { - pa_log(__FILE__": failed to initialize daemon."); + pa_log("failed to initialize daemon."); #ifdef HAVE_FORK if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL); #endif } else if (!c->modules || pa_idxset_size(c->modules) == 0) { - pa_log(__FILE__": daemon startup without any loaded modules, refusing to work."); + pa_log("daemon startup without any loaded modules, refusing to work."); #ifdef HAVE_FORK if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL); @@ -634,10 +634,10 @@ int main(int argc, char *argv[]) { pa_log_error("%s : Fatal error. Default sink name (%s) does not exist in name register.", __FILE__, c->default_sink_name); retval = 1; } else { - pa_log_info(__FILE__": Daemon startup complete."); + pa_log_info("Daemon startup complete."); if (pa_mainloop_run(mainloop, &retval) < 0) retval = 1; - pa_log_info(__FILE__": Daemon shutdown initiated."); + pa_log_info("Daemon shutdown initiated."); } } @@ -653,7 +653,7 @@ int main(int argc, char *argv[]) { pa_signal_done(); pa_mainloop_free(mainloop); - pa_log_info(__FILE__": Daemon terminated."); + pa_log_info("Daemon terminated."); finish: diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 39ddbfe9..d8b6c5cc 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -88,7 +88,7 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, PA_GCC_UNUSED int fd, pa_io err = snd_mixer_poll_descriptors_revents(fdl->mixer, fdl->work_fds, fdl->num_fds, &revents); if (err < 0) { - pa_log_error(__FILE__": Unable to get poll revent: %s", + pa_log_error("Unable to get poll revent: %s", snd_strerror(err)); return; } @@ -135,7 +135,7 @@ static void defer_cb(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event* e, void *u err = snd_mixer_poll_descriptors(fdl->mixer, fdl->work_fds, num_fds); if (err < 0) { - pa_log_error(__FILE__": Unable to get poll descriptors: %s", + pa_log_error("Unable to get poll descriptors: %s", snd_strerror(err)); return; } @@ -343,7 +343,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p goto finish; if (ss->rate != r) { - pa_log_warn(__FILE__": device doesn't support %u Hz, changed to %u Hz.", ss->rate, r); + pa_log_warn("device doesn't support %u Hz, changed to %u Hz.", ss->rate, r); /* If the sample rate deviates too much, we need to resample */ if (r < ss->rate*.95 || r > ss->rate*1.05) @@ -351,12 +351,12 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p } if (ss->channels != c) { - pa_log_warn(__FILE__": device doesn't support %u channels, changed to %u.", ss->channels, c); + pa_log_warn("device doesn't support %u channels, changed to %u.", ss->channels, c); ss->channels = c; } if (ss->format != f) { - pa_log_warn(__FILE__": device doesn't support sample format %s, changed to %s.", pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f)); + pa_log_warn("device doesn't support sample format %s, changed to %s.", pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f)); ss->format = f; } @@ -387,17 +387,17 @@ int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { assert(mixer && dev); if ((err = snd_mixer_attach(mixer, dev)) < 0) { - pa_log_warn(__FILE__": Unable to attach to mixer %s: %s", dev, snd_strerror(err)); + pa_log_warn("Unable to attach to mixer %s: %s", dev, snd_strerror(err)); return -1; } if ((err = snd_mixer_selem_register(mixer, NULL, NULL)) < 0) { - pa_log_warn(__FILE__": Unable to register mixer: %s", snd_strerror(err)); + pa_log_warn("Unable to register mixer: %s", snd_strerror(err)); return -1; } if ((err = snd_mixer_load(mixer)) < 0) { - pa_log_warn(__FILE__": Unable to load mixer: %s", snd_strerror(err)); + pa_log_warn("Unable to load mixer: %s", snd_strerror(err)); return -1; } @@ -415,18 +415,18 @@ snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const snd_mixer_selem_id_set_name(sid, name); if (!(elem = snd_mixer_find_selem(mixer, sid))) { - pa_log_warn(__FILE__": Cannot find mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); + pa_log_warn("Cannot find mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); if (fallback) { snd_mixer_selem_id_set_name(sid, fallback); if (!(elem = snd_mixer_find_selem(mixer, sid))) - pa_log_warn(__FILE__": Cannot find fallback mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); + pa_log_warn("Cannot find fallback mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); } } if (elem) - pa_log_info(__FILE__": Using mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); + pa_log_info("Using mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); return elem; } diff --git a/src/modules/dbus-util.c b/src/modules/dbus-util.c index e4bd2c3e..165ccff6 100644 --- a/src/modules/dbus-util.c +++ b/src/modules/dbus-util.c @@ -93,7 +93,7 @@ static void handle_io_event(PA_GCC_UNUSED pa_mainloop_api *ea, pa_io_event *e, assert(fd == dbus_watch_get_fd(watch)); if (!dbus_watch_get_enabled(watch)) { - pa_log_warn(__FILE__": Asked to handle disabled watch: %p %i", + pa_log_warn("Asked to handle disabled watch: %p %i", (void *) watch, fd); return; } diff --git a/src/modules/gconf/module-gconf.c b/src/modules/gconf/module-gconf.c index a61295e0..d9f649fd 100644 --- a/src/modules/gconf/module-gconf.c +++ b/src/modules/gconf/module-gconf.c @@ -96,7 +96,7 @@ static int fill_buf(struct userdata *u) { assert(u); if (u->buf_fill >= BUF_MAX) { - pa_log(__FILE__": read buffer overflow"); + pa_log("read buffer overflow"); return -1; } @@ -148,7 +148,7 @@ static void unload_one_module(struct userdata *u, struct module_info*m, unsigned if (m->items[i].index == PA_INVALID_INDEX) return; - pa_log_debug(__FILE__": Unloading module #%i", m->items[i].index); + pa_log_debug("Unloading module #%i", m->items[i].index); pa_module_unload_by_index(u->core, m->items[i].index); m->items[i].index = PA_INVALID_INDEX; pa_xfree(m->items[i].name); @@ -192,14 +192,14 @@ static void load_module( unload_one_module(u, m, i); } - pa_log_debug(__FILE__": Loading module '%s' with args '%s' due to GConf configuration.", name, args); + pa_log_debug("Loading module '%s' with args '%s' due to GConf configuration.", name, args); m->items[i].name = pa_xstrdup(name); m->items[i].args = pa_xstrdup(args); m->items[i].index = PA_INVALID_INDEX; if (!(mod = pa_module_load(u->core, name, args))) { - pa_log(__FILE__": pa_module_load() failed"); + pa_log("pa_module_load() failed"); return; } @@ -308,7 +308,7 @@ static int handle_event(struct userdata *u) { return ret; fail: - pa_log(__FILE__": Unable to read or parse data from client."); + pa_log("Unable to read or parse data from client."); return -1; } @@ -337,12 +337,12 @@ static int start_client(const char *n, pid_t *pid) { int pipe_fds[2] = { -1, -1 }; if (pipe(pipe_fds) < 0) { - pa_log(__FILE__": pipe() failed: %s", pa_cstrerror(errno)); + pa_log("pipe() failed: %s", pa_cstrerror(errno)); goto fail; } if ((child = fork()) == (pid_t) -1) { - pa_log(__FILE__": fork() failed: %s", pa_cstrerror(errno)); + pa_log("fork() failed: %s", pa_cstrerror(errno)); goto fail; } else if (child != 0) { diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 0cebd50f..6ff9a6e4 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -125,10 +125,10 @@ static int xrun_recovery(struct userdata *u) { int ret; assert(u); - pa_log_info(__FILE__": *** ALSA-XRUN (playback) ***"); + pa_log_info("*** ALSA-XRUN (playback) ***"); if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) { - pa_log(__FILE__": snd_pcm_prepare() failed: %s", snd_strerror(-ret)); + pa_log("snd_pcm_prepare() failed: %s", snd_strerror(-ret)); clear_up(u); pa_module_unload_request(u->module); @@ -169,7 +169,7 @@ static void do_write(struct userdata *u) { continue; } - pa_log(__FILE__": snd_pcm_writei() failed: %s", snd_strerror(-frames)); + pa_log("snd_pcm_writei() failed: %s", snd_strerror(-frames)); clear_up(u); pa_module_unload_request(u->module); @@ -233,7 +233,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { assert(s && u && u->sink); if ((err = snd_pcm_delay(u->pcm_handle, &frames)) < 0) { - pa_log(__FILE__": failed to get delay: %s", snd_strerror(err)); + pa_log("failed to get delay: %s", snd_strerror(err)); s->get_latency = NULL; return 0; } @@ -275,7 +275,7 @@ static int sink_get_hw_volume_cb(pa_sink *s) { return 0; fail: - pa_log_error(__FILE__": Unable to read volume: %s", snd_strerror(err)); + pa_log_error("Unable to read volume: %s", snd_strerror(err)); s->get_hw_volume = NULL; s->set_hw_volume = NULL; return -1; @@ -309,7 +309,7 @@ static int sink_set_hw_volume_cb(pa_sink *s) { return 0; fail: - pa_log_error(__FILE__": Unable to set volume: %s", snd_strerror(err)); + pa_log_error("Unable to set volume: %s", snd_strerror(err)); s->get_hw_volume = NULL; s->set_hw_volume = NULL; return -1; @@ -323,7 +323,7 @@ static int sink_get_hw_mute_cb(pa_sink *s) { err = snd_mixer_selem_get_playback_switch(u->mixer_elem, 0, &sw); if (err) { - pa_log_error(__FILE__": Unable to get switch: %s", snd_strerror(err)); + pa_log_error("Unable to get switch: %s", snd_strerror(err)); s->get_hw_mute = NULL; s->set_hw_mute = NULL; return -1; @@ -342,7 +342,7 @@ static int sink_set_hw_mute_cb(pa_sink *s) { err = snd_mixer_selem_set_playback_switch_all(u->mixer_elem, !s->hw_muted); if (err) { - pa_log_error(__FILE__": Unable to set switch: %s", snd_strerror(err)); + pa_log_error("Unable to set switch: %s", snd_strerror(err)); s->get_hw_mute = NULL; s->set_hw_mute = NULL; return -1; @@ -369,13 +369,13 @@ int pa__init(pa_core *c, pa_module*m) { int namereg_fail; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments"); + pa_log("failed to parse module arguments"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) { - pa_log(__FILE__": failed to parse sample specification and channel map"); + pa_log("failed to parse sample specification and channel map"); goto fail; } @@ -386,7 +386,7 @@ int pa__init(pa_core *c, pa_module*m) { fragsize = pa_bytes_per_second(&ss)/128; if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { - pa_log(__FILE__": failed to parse buffer metrics"); + pa_log("failed to parse buffer metrics"); goto fail; } period_size = fragsize/frame_size; @@ -397,18 +397,18 @@ int pa__init(pa_core *c, pa_module*m) { snd_config_update_free_global(); if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { - pa_log(__FILE__": Error opening PCM device %s: %s", dev, snd_strerror(err)); + pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err)); goto fail; } if ((err = snd_pcm_info_malloc(&pcm_info)) < 0 || (err = snd_pcm_info(u->pcm_handle, pcm_info)) < 0) { - pa_log(__FILE__": Error fetching PCM info: %s", snd_strerror(err)); + pa_log("Error fetching PCM info: %s", snd_strerror(err)); goto fail; } if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) { - pa_log(__FILE__": Failed to set hardware parameters: %s", snd_strerror(err)); + pa_log("Failed to set hardware parameters: %s", snd_strerror(err)); goto fail; } @@ -417,7 +417,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) { - pa_log(__FILE__": Error opening mixer: %s", snd_strerror(err)); + pa_log("Error opening mixer: %s", snd_strerror(err)); goto fail; } @@ -435,7 +435,7 @@ int pa__init(pa_core *c, pa_module*m) { } if (!(u->sink = pa_sink_new(c, __FILE__, name, namereg_fail, &ss, &map))) { - pa_log(__FILE__": Failed to create sink object"); + pa_log("Failed to create sink object"); goto fail; } @@ -471,7 +471,7 @@ int pa__init(pa_core *c, pa_module*m) { u->pcm_fdl = pa_alsa_fdlist_new(); assert(u->pcm_fdl); if (pa_alsa_fdlist_init_pcm(u->pcm_fdl, u->pcm_handle, c->mainloop, fdl_callback, u) < 0) { - pa_log(__FILE__": failed to initialise file descriptor monitoring"); + pa_log("failed to initialise file descriptor monitoring"); goto fail; } @@ -479,7 +479,7 @@ int pa__init(pa_core *c, pa_module*m) { u->mixer_fdl = pa_alsa_fdlist_new(); assert(u->mixer_fdl); if (pa_alsa_fdlist_init_mixer(u->mixer_fdl, u->mixer_handle, c->mainloop) < 0) { - pa_log(__FILE__": failed to initialise file descriptor monitoring"); + pa_log("failed to initialise file descriptor monitoring"); goto fail; } snd_mixer_elem_set_callback(u->mixer_elem, mixer_callback); @@ -490,7 +490,7 @@ int pa__init(pa_core *c, pa_module*m) { u->frame_size = frame_size; u->fragment_size = period_size * frame_size; - pa_log_info(__FILE__": using %u fragments of size %lu bytes.", periods, (long unsigned)u->fragment_size); + pa_log_info("using %u fragments of size %lu bytes.", periods, (long unsigned)u->fragment_size); u->silence.memblock = pa_memblock_new(c->mempool, u->silence.length = u->fragment_size); assert(u->silence.memblock); diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index c3979df1..aa0666f1 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -126,10 +126,10 @@ static int xrun_recovery(struct userdata *u) { int ret; assert(u); - pa_log_info(__FILE__": *** ALSA-XRUN (capture) ***"); + pa_log_info("*** ALSA-XRUN (capture) ***"); if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) { - pa_log(__FILE__": snd_pcm_prepare() failed: %s", snd_strerror(-ret)); + pa_log("snd_pcm_prepare() failed: %s", snd_strerror(-ret)); clear_up(u); pa_module_unload_request(u->module); @@ -172,7 +172,7 @@ static void do_read(struct userdata *u) { continue; } - pa_log(__FILE__": snd_pcm_readi() failed: %s", snd_strerror(-frames)); + pa_log("snd_pcm_readi() failed: %s", snd_strerror(-frames)); clear_up(u); pa_module_unload_request(u->module); @@ -238,7 +238,7 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { assert(s && u && u->source); if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { - pa_log(__FILE__": failed to get delay"); + pa_log("failed to get delay"); s->get_latency = NULL; return 0; } @@ -272,7 +272,7 @@ static int source_get_hw_volume_cb(pa_source *s) { return 0; fail: - pa_log_error(__FILE__": Unable to read volume: %s", snd_strerror(err)); + pa_log_error("Unable to read volume: %s", snd_strerror(err)); s->get_hw_volume = NULL; s->set_hw_volume = NULL; return -1; @@ -303,7 +303,7 @@ static int source_set_hw_volume_cb(pa_source *s) { return 0; fail: - pa_log_error(__FILE__": Unable to set volume: %s", snd_strerror(err)); + pa_log_error("Unable to set volume: %s", snd_strerror(err)); s->get_hw_volume = NULL; s->set_hw_volume = NULL; return -1; @@ -317,7 +317,7 @@ static int source_get_hw_mute_cb(pa_source *s) { err = snd_mixer_selem_get_capture_switch(u->mixer_elem, 0, &sw); if (err) { - pa_log_error(__FILE__": Unable to get switch: %s", snd_strerror(err)); + pa_log_error("Unable to get switch: %s", snd_strerror(err)); s->get_hw_mute = NULL; s->set_hw_mute = NULL; return -1; @@ -336,7 +336,7 @@ static int source_set_hw_mute_cb(pa_source *s) { err = snd_mixer_selem_set_capture_switch_all(u->mixer_elem, !s->hw_muted); if (err) { - pa_log_error(__FILE__": Unable to set switch: %s", snd_strerror(err)); + pa_log_error("Unable to set switch: %s", snd_strerror(err)); s->get_hw_mute = NULL; s->set_hw_mute = NULL; return -1; @@ -363,13 +363,13 @@ int pa__init(pa_core *c, pa_module*m) { int namereg_fail; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments"); + pa_log("failed to parse module arguments"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) { - pa_log(__FILE__": failed to parse sample specification"); + pa_log("failed to parse sample specification"); goto fail; } @@ -380,7 +380,7 @@ int pa__init(pa_core *c, pa_module*m) { fragsize = pa_bytes_per_second(&ss)/128; if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { - pa_log(__FILE__": failed to parse buffer metrics"); + pa_log("failed to parse buffer metrics"); goto fail; } period_size = fragsize/frame_size; @@ -391,18 +391,18 @@ int pa__init(pa_core *c, pa_module*m) { snd_config_update_free_global(); if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { - pa_log(__FILE__": Error opening PCM device %s: %s", dev, snd_strerror(err)); + pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err)); goto fail; } if ((err = snd_pcm_info_malloc(&pcm_info)) < 0 || (err = snd_pcm_info(u->pcm_handle, pcm_info)) < 0) { - pa_log(__FILE__": Error fetching PCM info: %s", snd_strerror(err)); + pa_log("Error fetching PCM info: %s", snd_strerror(err)); goto fail; } if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) { - pa_log(__FILE__": Failed to set hardware parameters: %s", snd_strerror(err)); + pa_log("Failed to set hardware parameters: %s", snd_strerror(err)); goto fail; } @@ -411,7 +411,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) { - pa_log(__FILE__": Error opening mixer: %s", snd_strerror(err)); + pa_log("Error opening mixer: %s", snd_strerror(err)); goto fail; } @@ -429,7 +429,7 @@ int pa__init(pa_core *c, pa_module*m) { } if (!(u->source = pa_source_new(c, __FILE__, name, namereg_fail, &ss, &map))) { - pa_log(__FILE__": Failed to create source object"); + pa_log("Failed to create source object"); goto fail; } @@ -465,7 +465,7 @@ int pa__init(pa_core *c, pa_module*m) { u->pcm_fdl = pa_alsa_fdlist_new(); assert(u->pcm_fdl); if (pa_alsa_fdlist_init_pcm(u->pcm_fdl, u->pcm_handle, c->mainloop, fdl_callback, u) < 0) { - pa_log(__FILE__": failed to initialise file descriptor monitoring"); + pa_log("failed to initialise file descriptor monitoring"); goto fail; } @@ -473,7 +473,7 @@ int pa__init(pa_core *c, pa_module*m) { u->mixer_fdl = pa_alsa_fdlist_new(); assert(u->mixer_fdl); if (pa_alsa_fdlist_init_mixer(u->mixer_fdl, u->mixer_handle, c->mainloop) < 0) { - pa_log(__FILE__": failed to initialise file descriptor monitoring"); + pa_log("failed to initialise file descriptor monitoring"); goto fail; } snd_mixer_elem_set_callback(u->mixer_elem, mixer_callback); @@ -484,7 +484,7 @@ int pa__init(pa_core *c, pa_module*m) { u->frame_size = frame_size; u->fragment_size = period_size * frame_size; - pa_log_info(__FILE__": using %u fragments of size %lu bytes.", periods, (long unsigned) u->fragment_size); + pa_log_info("using %u fragments of size %lu bytes.", periods, (long unsigned) u->fragment_size); u->memchunk.memblock = NULL; u->memchunk.index = u->memchunk.length = 0; diff --git a/src/modules/module-cli.c b/src/modules/module-cli.c index 2eef5c46..d5374838 100644 --- a/src/modules/module-cli.c +++ b/src/modules/module-cli.c @@ -73,22 +73,22 @@ int pa__init(pa_core *c, pa_module*m) { assert(m); if (c->running_as_daemon) { - pa_log_info(__FILE__": Running as daemon, refusing to load this module."); + pa_log_info("Running as daemon, refusing to load this module."); return 0; } if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments."); + pa_log("failed to parse module arguments."); goto fail; } if (pa_modargs_get_value_boolean(ma, "exit_on_eof", &exit_on_eof) < 0) { - pa_log(__FILE__": exit_on_eof= expects boolean argument."); + pa_log("exit_on_eof= expects boolean argument."); goto fail; } if (pa_stdio_acquire() < 0) { - pa_log(__FILE__": STDIN/STDUSE already in use."); + pa_log("STDIN/STDUSE already in use."); goto fail; } diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 5243975b..217fdae6 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -124,7 +124,7 @@ static void adjust_rates(struct userdata *u) { target_latency = max_sink_latency > min_total_latency ? max_sink_latency : min_total_latency; - pa_log_info(__FILE__": [%s] target latency is %0.0f usec.", u->sink->name, (float) target_latency); + pa_log_info("[%s] target latency is %0.0f usec.", u->sink->name, (float) target_latency); base_rate = u->sink->sample_spec.rate; @@ -137,9 +137,9 @@ static void adjust_rates(struct userdata *u) { r += (uint32_t) (((((double) o->total_latency - target_latency))/u->adjust_time)*r/ 1000000); if (r < (uint32_t) (base_rate*0.9) || r > (uint32_t) (base_rate*1.1)) - pa_log_warn(__FILE__": [%s] sample rates too different, not adjusting (%u vs. %u).", o->sink_input->name, base_rate, r); + pa_log_warn("[%s] sample rates too different, not adjusting (%u vs. %u).", o->sink_input->name, base_rate, r); else { - pa_log_info(__FILE__": [%s] new rate is %u Hz; ratio is %0.3f; latency is %0.0f usec.", o->sink_input->name, r, (double) r / base_rate, (float) o->total_latency); + pa_log_info("[%s] new rate is %u Hz; ratio is %0.3f; latency is %0.0f usec.", o->sink_input->name, r, (double) r / base_rate, (float) o->total_latency); pa_sink_input_set_rate(o->sink_input, r); } } @@ -323,13 +323,13 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments"); + pa_log("failed to parse module arguments"); goto fail; } if ((rm = pa_modargs_get_value(ma, "resample_method", NULL))) { if ((resample_method = pa_parse_resample_method(rm)) < 0) { - pa_log(__FILE__": invalid resample method '%s'", rm); + pa_log("invalid resample method '%s'", rm); goto fail; } } @@ -346,23 +346,23 @@ int pa__init(pa_core *c, pa_module*m) { PA_LLIST_HEAD_INIT(struct output, u->outputs); if (pa_modargs_get_value_u32(ma, "adjust_time", &u->adjust_time) < 0) { - pa_log(__FILE__": failed to parse adjust_time value"); + pa_log("failed to parse adjust_time value"); goto fail; } if (!(master_name = pa_modargs_get_value(ma, "master", NULL)) || !(slaves = pa_modargs_get_value(ma, "slaves", NULL))) { - pa_log(__FILE__": no master or slave sinks specified"); + pa_log("no master or slave sinks specified"); goto fail; } if (!(master_sink = pa_namereg_get(c, master_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": invalid master sink '%s'", master_name); + pa_log("invalid master sink '%s'", master_name); goto fail; } ss = master_sink->sample_spec; if ((pa_modargs_get_sample_spec(ma, &ss) < 0)) { - pa_log(__FILE__": invalid sample specification."); + pa_log("invalid sample specification."); goto fail; } @@ -372,17 +372,17 @@ int pa__init(pa_core *c, pa_module*m) { pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_DEFAULT); if ((pa_modargs_get_channel_map(ma, &map) < 0)) { - pa_log(__FILE__": invalid channel map."); + pa_log("invalid channel map."); goto fail; } if (ss.channels != map.channels) { - pa_log(__FILE__": channel map and sample specification don't match."); + pa_log("channel map and sample specification don't match."); goto fail; } if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { - pa_log(__FILE__": failed to create sink"); + pa_log("failed to create sink"); goto fail; } @@ -392,7 +392,7 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->userdata = u; if (!(u->master = output_new(u, master_sink, resample_method))) { - pa_log(__FILE__": failed to create master sink input on sink '%s'.", u->sink->name); + pa_log("failed to create master sink input on sink '%s'.", u->sink->name); goto fail; } @@ -401,20 +401,20 @@ int pa__init(pa_core *c, pa_module*m) { pa_sink *slave_sink; if (!(slave_sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": invalid slave sink '%s'", n); + pa_log("invalid slave sink '%s'", n); goto fail; } pa_xfree(n); if (!output_new(u, slave_sink, resample_method)) { - pa_log(__FILE__": failed to create slave sink input on sink '%s'.", slave_sink->name); + pa_log("failed to create slave sink input on sink '%s'.", slave_sink->name); goto fail; } } if (u->n_outputs <= 1) - pa_log_warn(__FILE__": WARNING: no slave sinks specified."); + pa_log_warn("WARNING: no slave sinks specified."); if (u->adjust_time > 0) { pa_gettimeofday(&tv); diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index ebafa10d..84ccd14c 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -57,7 +57,7 @@ static int detect_alsa(pa_core *c, int just_one) { if (!(f = fopen("/proc/asound/devices", "r"))) { if (errno != ENOENT) - pa_log_error(__FILE__": open(\"/proc/asound/devices\") failed: %s", pa_cstrerror(errno)); + pa_log_error("open(\"/proc/asound/devices\") failed: %s", pa_cstrerror(errno)); return -1; } @@ -120,7 +120,7 @@ static int detect_oss(pa_core *c, int just_one) { !(f = fopen("/proc/asound/oss/sndstat", "r"))) { if (errno != ENOENT) - pa_log_error(__FILE__": failed to open OSS sndstat device: %s", pa_cstrerror(errno)); + pa_log_error("failed to open OSS sndstat device: %s", pa_cstrerror(errno)); return -1; } @@ -182,7 +182,7 @@ static int detect_solaris(pa_core *c, int just_one) { if (stat(dev, &s) < 0) { if (errno != ENOENT) - pa_log_error(__FILE__": failed to open device %s: %s", dev, pa_cstrerror(errno)); + pa_log_error("failed to open device %s: %s", dev, pa_cstrerror(errno)); return -1; } @@ -224,12 +224,12 @@ int pa__init(pa_core *c, pa_module*m) { assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments"); + pa_log("Failed to parse module arguments"); goto fail; } if (pa_modargs_get_value_boolean(ma, "just-one", &just_one) < 0) { - pa_log(__FILE__": just_one= expects a boolean argument."); + pa_log("just_one= expects a boolean argument."); goto fail; } @@ -246,11 +246,11 @@ int pa__init(pa_core *c, pa_module*m) { if ((n = detect_waveout(c, just_one)) <= 0) #endif { - pa_log_warn(__FILE__": failed to detect any sound hardware."); + pa_log_warn("failed to detect any sound hardware."); goto fail; } - pa_log_info(__FILE__": loaded %i modules.", n); + pa_log_info("loaded %i modules.", n); /* We were successful and can unload ourselves now. */ pa_module_unload_request(m); diff --git a/src/modules/module-esound-compat-spawnfd.c b/src/modules/module-esound-compat-spawnfd.c index 54e090e4..263e81f9 100644 --- a/src/modules/module-esound-compat-spawnfd.c +++ b/src/modules/module-esound-compat-spawnfd.c @@ -55,12 +55,12 @@ int pa__init(pa_core *c, pa_module*m) { if (!(ma = pa_modargs_new(m->argument, valid_modargs)) || pa_modargs_get_value_s32(ma, "fd", &fd) < 0 || fd < 0) { - pa_log(__FILE__": Failed to parse module arguments"); + pa_log("Failed to parse module arguments"); goto finish; } if (pa_loop_write(fd, &x, sizeof(x), NULL) != sizeof(x)) - pa_log(__FILE__": WARNING: write(%u, 1, 1) failed: %s", fd, pa_cstrerror(errno)); + pa_log("WARNING: write(%u, 1, 1) failed: %s", fd, pa_cstrerror(errno)); close(fd); diff --git a/src/modules/module-esound-compat-spawnpid.c b/src/modules/module-esound-compat-spawnpid.c index 3108baf7..7a662c2d 100644 --- a/src/modules/module-esound-compat-spawnpid.c +++ b/src/modules/module-esound-compat-spawnpid.c @@ -55,12 +55,12 @@ int pa__init(pa_core *c, pa_module*m) { if (!(ma = pa_modargs_new(m->argument, valid_modargs)) || pa_modargs_get_value_u32(ma, "pid", &pid) < 0 || !pid) { - pa_log(__FILE__": Failed to parse module arguments"); + pa_log("Failed to parse module arguments"); goto finish; } if (kill(pid, SIGUSR1) < 0) - pa_log(__FILE__": WARNING: kill(%u) failed: %s", pid, pa_cstrerror(errno)); + pa_log("WARNING: kill(%u) failed: %s", pid, pa_cstrerror(errno)); pa_module_unload_request(m); diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index c774d8c1..6d4a8489 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -129,7 +129,7 @@ static int do_write(struct userdata *u) { assert(u->write_index < u->write_length); if ((r = pa_iochannel_write(u->io, (uint8_t*) u->write_data + u->write_index, u->write_length - u->write_index)) <= 0) { - pa_log(__FILE__": write() failed: %s", pa_cstrerror(errno)); + pa_log("write() failed: %s", pa_cstrerror(errno)); return -1; } @@ -151,7 +151,7 @@ static int do_write(struct userdata *u) { assert(u->memchunk.memblock && u->memchunk.length); if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { - pa_log(__FILE__": write() failed: %s", pa_cstrerror(errno)); + pa_log("write() failed: %s", pa_cstrerror(errno)); return -1; } @@ -176,7 +176,7 @@ static int handle_response(struct userdata *u) { /* Process auth data */ if (!*(int32_t*) u->read_data) { - pa_log(__FILE__": Authentication failed: %s", pa_cstrerror(errno)); + pa_log("Authentication failed: %s", pa_cstrerror(errno)); return -1; } @@ -201,7 +201,7 @@ static int handle_response(struct userdata *u) { /* Process latency info */ u->latency = (pa_usec_t) ((double) (*(int32_t*) u->read_data) * 1000000 / 44100); if (u->latency > 10000000) { - pa_log(__FILE__": WARNING! Invalid latency information received from server"); + pa_log("WARNING! Invalid latency information received from server"); u->latency = 0; } @@ -246,7 +246,7 @@ static int do_read(struct userdata *u) { assert(u->read_index < u->read_length); if ((r = pa_iochannel_read(u->io, (uint8_t*) u->read_data + u->read_index, u->read_length - u->read_index)) <= 0) { - pa_log(__FILE__": read() failed: %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + pa_log("read() failed: %s", r < 0 ? pa_cstrerror(errno) : "EOF"); cancel(u); return -1; } @@ -306,7 +306,7 @@ static void on_connection(PA_GCC_UNUSED pa_socket_client *c, pa_iochannel*io, vo u->client = NULL; if (!io) { - pa_log(__FILE__": connection failed: %s", pa_cstrerror(errno)); + pa_log("connection failed: %s", pa_cstrerror(errno)); cancel(u); return; } @@ -325,19 +325,19 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments"); + pa_log("failed to parse module arguments"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": invalid sample format specification"); + pa_log("invalid sample format specification"); goto fail; } if ((ss.format != PA_SAMPLE_U8 && ss.format != PA_SAMPLE_S16NE) || (ss.channels > 2)) { - pa_log(__FILE__": esound sample type support is limited to mono/stereo and U8 or S16NE sample data"); + pa_log("esound sample type support is limited to mono/stereo and U8 or S16NE sample data"); goto fail; } @@ -358,12 +358,12 @@ int pa__init(pa_core *c, pa_module*m) { u->latency = 0; if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { - pa_log(__FILE__": failed to create sink."); + pa_log("failed to create sink."); goto fail; } if (!(u->client = pa_socket_client_new_string(u->core->mainloop, p = pa_modargs_get_value(ma, "server", ESD_UNIX_SOCKET_NAME), ESD_DEFAULT_PORT))) { - pa_log(__FILE__": failed to connect to server."); + pa_log("failed to connect to server."); goto fail; } pa_socket_client_set_callback(u->client, on_connection, u); @@ -371,7 +371,7 @@ int pa__init(pa_core *c, pa_module*m) { /* Prepare the initial request */ u->write_data = pa_xmalloc(u->write_length = ESD_KEY_LEN + sizeof(int32_t)); if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", ".esd_auth"), u->write_data, ESD_KEY_LEN) < 0) { - pa_log(__FILE__": failed to load cookie"); + pa_log("failed to load cookie"); goto fail; } *(int32_t*) ((uint8_t*) u->write_data + ESD_KEY_LEN) = ESD_ENDIAN_KEY; diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index 825fa96c..8232cd38 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -287,11 +287,11 @@ static int hal_device_add_all(struct userdata *u, capability_t capability) assert(capability < CAP_MAX); - pa_log_info(__FILE__": Trying capability %u (%s)", capability, cap); + pa_log_info("Trying capability %u (%s)", capability, cap); dbus_error_init(&error); udis = libhal_find_device_by_capability(u->ctx, cap, &n, &error); if (dbus_error_is_set(&error)) { - pa_log_error(__FILE__": Error finding devices: %s: %s", error.name, + pa_log_error("Error finding devices: %s: %s", error.name, error.message); dbus_error_free(&error); return -1; @@ -301,7 +301,7 @@ static int hal_device_add_all(struct userdata *u, capability_t capability) for (i = 0; i < n; ++i) { r = hal_device_add(u, udis[i], &error); if (dbus_error_is_set(&error)) { - pa_log_error(__FILE__": Error adding device: %s: %s", error.name, + pa_log_error("Error adding device: %s: %s", error.name, error.message); dbus_error_free(&error); count = -1; @@ -338,7 +338,7 @@ static void device_added_time_cb(pa_mainloop_api *ea, pa_time_event *ev, hal_device_add(td->u, td->udi, &error); if (dbus_error_is_set(&error)) { - pa_log_error(__FILE__": Error adding device: %s: %s", error.name, + pa_log_error("Error adding device: %s: %s", error.name, error.message); dbus_error_free(&error); } @@ -357,12 +357,12 @@ static void device_added_cb(LibHalContext *ctx, const char *udi) struct userdata *u = (struct userdata*) libhal_ctx_get_user_data(ctx); const char* cap = get_capability_name(u->capability); - pa_log_debug(__FILE__": HAL Device added: %s", udi); + pa_log_debug("HAL Device added: %s", udi); dbus_error_init(&error); has_cap = device_has_capability(ctx, udi, cap, &error); if (dbus_error_is_set(&error)) { - pa_log_error(__FILE__": Error getting capability: %s: %s", error.name, + pa_log_error("Error getting capability: %s: %s", error.name, error.message); dbus_error_free(&error); return; @@ -388,7 +388,7 @@ static void device_removed_cb(LibHalContext* ctx, const char *udi) struct device *d; struct userdata *u = (struct userdata*) libhal_ctx_get_user_data(ctx); - pa_log_debug(__FILE__": Device removed: %s", udi); + pa_log_debug("Device removed: %s", udi); if ((d = pa_hashmap_remove(u->devices, udi))) { pa_module_unload_by_index(u->core, d->index); hal_device_free(d); @@ -456,18 +456,18 @@ static LibHalContext* pa_hal_context_new(pa_core* c, DBusConnection *conn) dbus_error_init(&error); if (!(hal_ctx = libhal_ctx_new())) { - pa_log_error(__FILE__": libhal_ctx_new() failed"); + pa_log_error("libhal_ctx_new() failed"); goto fail; } if (!libhal_ctx_set_dbus_connection(hal_ctx, conn)) { - pa_log_error(__FILE__": Error establishing DBUS connection: %s: %s", + pa_log_error("Error establishing DBUS connection: %s: %s", error.name, error.message); goto fail; } if (!libhal_ctx_init(hal_ctx, &error)) { - pa_log_error(__FILE__": Couldn't connect to hald: %s: %s", + pa_log_error("Couldn't connect to hald: %s: %s", error.name, error.message); goto fail; } @@ -496,7 +496,7 @@ int pa__init(pa_core *c, pa_module*m) { dbus_error_init(&error); if (!(conn = pa_dbus_bus_get(c, DBUS_BUS_SYSTEM, &error))) { - pa_log_error(__FILE__": Unable to contact DBUS system bus: %s: %s", + pa_log_error("Unable to contact DBUS system bus: %s: %s", error.name, error.message); dbus_error_free(&error); return -1; @@ -522,7 +522,7 @@ int pa__init(pa_core *c, pa_module*m) { if ((n = hal_device_add_all(u, CAP_OSS)) <= 0) #endif { - pa_log_warn(__FILE__": failed to detect any sound hardware."); + pa_log_warn("failed to detect any sound hardware."); userdata_free(u); return -1; } @@ -536,14 +536,14 @@ int pa__init(pa_core *c, pa_module*m) { dbus_error_init(&error); if (!libhal_device_property_watch_all(hal_ctx, &error)) { - pa_log_error(__FILE__": error monitoring device list: %s: %s", + pa_log_error("error monitoring device list: %s: %s", error.name, error.message); dbus_error_free(&error); userdata_free(u); return -1; } - pa_log_info(__FILE__": loaded %i modules.", n); + pa_log_info("loaded %i modules.", n); return 0; } diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index 286f6f57..47f77bab 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -231,7 +231,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { } static void jack_error_func(const char*t) { - pa_log_warn(__FILE__": JACK error >%s<", t); + pa_log_warn("JACK error >%s<", t); } int pa__init(pa_core *c, pa_module*m) { @@ -253,12 +253,12 @@ int pa__init(pa_core *c, pa_module*m) { jack_set_error_function(jack_error_func); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments."); + pa_log("failed to parse module arguments."); goto fail; } if (pa_modargs_get_value_boolean(ma, "connect", &do_connect) < 0) { - pa_log(__FILE__": failed to parse connect= argument."); + pa_log("failed to parse connect= argument."); goto fail; } @@ -276,14 +276,14 @@ int pa__init(pa_core *c, pa_module*m) { pthread_cond_init(&u->cond, NULL); if (pipe(u->pipe_fds) < 0) { - pa_log(__FILE__": pipe() failed: %s", pa_cstrerror(errno)); + pa_log("pipe() failed: %s", pa_cstrerror(errno)); goto fail; } pa_make_nonblock_fd(u->pipe_fds[1]); if (!(u->client = jack_client_open(client_name, server_name ? JackServerName : JackNullOption, &status, server_name))) { - pa_log(__FILE__": jack_client_open() failed."); + pa_log("jack_client_open() failed."); goto fail; } @@ -297,17 +297,17 @@ int pa__init(pa_core *c, pa_module*m) { channels = c->default_sample_spec.channels; if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0 || channels <= 0 || channels >= PA_CHANNELS_MAX) { - pa_log(__FILE__": failed to parse channels= argument."); + pa_log("failed to parse channels= argument."); goto fail; } pa_channel_map_init_auto(&map, channels, PA_CHANNEL_MAP_ALSA); if (pa_modargs_get_channel_map(ma, &map) < 0 || map.channels != channels) { - pa_log(__FILE__": failed to parse channel_map= argument."); + pa_log("failed to parse channel_map= argument."); goto fail; } - pa_log_info(__FILE__": Successfully connected as '%s'", jack_get_client_name(u->client)); + pa_log_info("Successfully connected as '%s'", jack_get_client_name(u->client)); ss.channels = u->channels = channels; ss.rate = jack_get_sample_rate(u->client); @@ -317,13 +317,13 @@ int pa__init(pa_core *c, pa_module*m) { for (i = 0; i < ss.channels; i++) { if (!(u->port[i] = jack_port_register(u->client, pa_channel_position_to_string(map.map[i]), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput|JackPortIsTerminal, 0))) { - pa_log(__FILE__": jack_port_register() failed."); + pa_log("jack_port_register() failed."); goto fail; } } if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { - pa_log(__FILE__": failed to create sink."); + pa_log("failed to create sink."); goto fail; } @@ -337,7 +337,7 @@ int pa__init(pa_core *c, pa_module*m) { jack_on_shutdown(u->client, jack_shutdown, u); if (jack_activate(u->client)) { - pa_log(__FILE__": jack_activate() failed"); + pa_log("jack_activate() failed"); goto fail; } @@ -345,14 +345,14 @@ int pa__init(pa_core *c, pa_module*m) { for (i = 0, p = ports; i < ss.channels; i++, p++) { if (!*p) { - pa_log(__FILE__": not enough physical output ports, leaving unconnected."); + pa_log("not enough physical output ports, leaving unconnected."); break; } - pa_log_info(__FILE__": connecting %s to %s", jack_port_name(u->port[i]), *p); + pa_log_info("connecting %s to %s", jack_port_name(u->port[i]), *p); if (jack_connect(u->client, jack_port_name(u->port[i]), *p)) { - pa_log(__FILE__": failed to connect %s to %s, leaving unconnected.", jack_port_name(u->port[i]), *p); + pa_log("failed to connect %s to %s, leaving unconnected.", jack_port_name(u->port[i]), *p); break; } } diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index 8e659198..62a99108 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -229,7 +229,7 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { } static void jack_error_func(const char*t) { - pa_log_warn(__FILE__": JACK error >%s<", t); + pa_log_warn("JACK error >%s<", t); } int pa__init(pa_core *c, pa_module*m) { @@ -251,12 +251,12 @@ int pa__init(pa_core *c, pa_module*m) { jack_set_error_function(jack_error_func); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments."); + pa_log("failed to parse module arguments."); goto fail; } if (pa_modargs_get_value_boolean(ma, "connect", &do_connect) < 0) { - pa_log(__FILE__": failed to parse connect= argument."); + pa_log("failed to parse connect= argument."); goto fail; } @@ -274,14 +274,14 @@ int pa__init(pa_core *c, pa_module*m) { pthread_cond_init(&u->cond, NULL); if (pipe(u->pipe_fds) < 0) { - pa_log(__FILE__": pipe() failed: %s", pa_cstrerror(errno)); + pa_log("pipe() failed: %s", pa_cstrerror(errno)); goto fail; } pa_make_nonblock_fd(u->pipe_fds[1]); if (!(u->client = jack_client_open(client_name, server_name ? JackServerName : JackNullOption, &status, server_name))) { - pa_log(__FILE__": jack_client_open() failed."); + pa_log("jack_client_open() failed."); goto fail; } @@ -295,17 +295,17 @@ int pa__init(pa_core *c, pa_module*m) { channels = c->default_sample_spec.channels; if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0 || channels <= 0 || channels >= PA_CHANNELS_MAX) { - pa_log(__FILE__": failed to parse channels= argument."); + pa_log("failed to parse channels= argument."); goto fail; } pa_channel_map_init_auto(&map, channels, PA_CHANNEL_MAP_ALSA); if (pa_modargs_get_channel_map(ma, &map) < 0 || map.channels != channels) { - pa_log(__FILE__": failed to parse channel_map= argument."); + pa_log("failed to parse channel_map= argument."); goto fail; } - pa_log_info(__FILE__": Successfully connected as '%s'", jack_get_client_name(u->client)); + pa_log_info("Successfully connected as '%s'", jack_get_client_name(u->client)); ss.channels = u->channels = channels; ss.rate = jack_get_sample_rate(u->client); @@ -315,13 +315,13 @@ int pa__init(pa_core *c, pa_module*m) { for (i = 0; i < ss.channels; i++) { if (!(u->port[i] = jack_port_register(u->client, pa_channel_position_to_string(map.map[i]), JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput|JackPortIsTerminal, 0))) { - pa_log(__FILE__": jack_port_register() failed."); + pa_log("jack_port_register() failed."); goto fail; } } if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) { - pa_log(__FILE__": failed to create source."); + pa_log("failed to create source."); goto fail; } @@ -335,7 +335,7 @@ int pa__init(pa_core *c, pa_module*m) { jack_on_shutdown(u->client, jack_shutdown, u); if (jack_activate(u->client)) { - pa_log(__FILE__": jack_activate() failed"); + pa_log("jack_activate() failed"); goto fail; } @@ -343,14 +343,14 @@ int pa__init(pa_core *c, pa_module*m) { for (i = 0, p = ports; i < ss.channels; i++, p++) { if (!*p) { - pa_log(__FILE__": not enough physical output ports, leaving unconnected."); + pa_log("not enough physical output ports, leaving unconnected."); break; } - pa_log_info(__FILE__": connecting %s to %s", jack_port_name(u->port[i]), *p); + pa_log_info("connecting %s to %s", jack_port_name(u->port[i]), *p); if (jack_connect(u->client, *p, jack_port_name(u->port[i]))) { - pa_log(__FILE__": failed to connect %s to %s, leaving unconnected.", jack_port_name(u->port[i]), *p); + pa_log("failed to connect %s to %s, leaving unconnected.", jack_port_name(u->port[i]), *p); break; } } diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c index a93a3b92..18b2ddf1 100644 --- a/src/modules/module-lirc.c +++ b/src/modules/module-lirc.c @@ -70,7 +70,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC assert(u); if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { - pa_log(__FILE__": lost connection to LIRC daemon."); + pa_log("lost connection to LIRC daemon."); goto fail; } @@ -78,13 +78,13 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC char *c; if (lirc_nextcode(&code) != 0 || !code) { - pa_log(__FILE__": lirc_nextcode() failed."); + pa_log("lirc_nextcode() failed."); goto fail; } c = pa_xstrdup(code); c[strcspn(c, "\n\r")] = 0; - pa_log_debug(__FILE__": raw IR code '%s'", c); + pa_log_debug("raw IR code '%s'", c); pa_xfree(c); while (lirc_code2char(u->config, code, &name) == 0 && name) { @@ -97,7 +97,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC MUTE_TOGGLE } volchange = INVALID; - pa_log_info(__FILE__": translated IR code '%s'", name); + pa_log_info("translated IR code '%s'", name); if (strcasecmp(name, "volume-up") == 0) volchange = UP; @@ -111,12 +111,12 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC volchange = RESET; if (volchange == INVALID) - pa_log_warn(__FILE__": recieved unknown IR code '%s'", name); + pa_log_warn("recieved unknown IR code '%s'", name); else { pa_sink *s; if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) - pa_log(__FILE__": failed to get sink '%s'", u->sink_name); + pa_log("failed to get sink '%s'", u->sink_name); else { int i; pa_cvolume cv = *pa_sink_get_volume(s, PA_MIXER_HARDWARE); @@ -186,12 +186,12 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (lirc_in_use) { - pa_log(__FILE__": module-lirc may no be loaded twice."); + pa_log("module-lirc may no be loaded twice."); return -1; } if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments"); + pa_log("Failed to parse module arguments"); goto fail; } @@ -204,12 +204,12 @@ int pa__init(pa_core *c, pa_module*m) { u->mute_toggle_save = 0; if ((u->lirc_fd = lirc_init((char*) pa_modargs_get_value(ma, "appname", "pulseaudio"), 1)) < 0) { - pa_log(__FILE__": lirc_init() failed."); + pa_log("lirc_init() failed."); goto fail; } if (lirc_readconfig((char*) pa_modargs_get_value(ma, "config", NULL), &u->config, NULL) < 0) { - pa_log(__FILE__": lirc_readconfig() failed."); + pa_log("lirc_readconfig() failed."); goto fail; } diff --git a/src/modules/module-match.c b/src/modules/module-match.c index ab94b02d..eb5de64e 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -83,7 +83,7 @@ static int load_rules(struct userdata *u, const char *filename) { pa_open_config_file(DEFAULT_MATCH_TABLE_FILE, DEFAULT_MATCH_TABLE_FILE_USER, NULL, &fn, "r"); if (!f) { - pa_log(__FILE__": failed to open file '%s': %s", fn, pa_cstrerror(errno)); + pa_log("failed to open file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } @@ -118,7 +118,7 @@ static int load_rules(struct userdata *u, const char *filename) { *d = 0; if (pa_atou(v, &k) < 0) { - pa_log(__FILE__": [%s:%u] failed to parse volume", filename, n); + pa_log("[%s:%u] failed to parse volume", filename, n); goto finish; } @@ -126,7 +126,7 @@ static int load_rules(struct userdata *u, const char *filename) { if (regcomp(®ex, ln, REG_EXTENDED|REG_NOSUB) != 0) { - pa_log(__FILE__": [%s:%u] invalid regular expression", filename, n); + pa_log("[%s:%u] invalid regular expression", filename, n); goto finish; } @@ -176,7 +176,7 @@ static void callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, v for (r = u->rules; r; r = r->next) { if (!regexec(&r->regex, si->name, 0, NULL, 0)) { pa_cvolume cv; - pa_log_debug(__FILE__": changing volume of sink input '%s' to 0x%03x", si->name, r->volume); + pa_log_debug("changing volume of sink input '%s' to 0x%03x", si->name, r->volume); pa_cvolume_set(&cv, r->volume, si->sample_spec.channels); pa_sink_input_set_volume(si, &cv); } @@ -189,7 +189,7 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments"); + pa_log("Failed to parse module arguments"); goto fail; } diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c index c3d07396..37234d92 100644 --- a/src/modules/module-mmkbd-evdev.c +++ b/src/modules/module-mmkbd-evdev.c @@ -82,7 +82,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC assert(u); if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { - pa_log(__FILE__": lost connection to evdev device."); + pa_log("lost connection to evdev device."); goto fail; } @@ -90,14 +90,14 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC struct input_event ev; if (pa_loop_read(u->fd, &ev, sizeof(ev), &u->fd_type) <= 0) { - pa_log(__FILE__": failed to read from event device: %s", pa_cstrerror(errno)); + pa_log("failed to read from event device: %s", pa_cstrerror(errno)); goto fail; } if (ev.type == EV_KEY && (ev.value == 1 || ev.value == 2)) { enum { INVALID, UP, DOWN, MUTE_TOGGLE } volchange = INVALID; - pa_log_debug(__FILE__": key code=%u, value=%u", ev.code, ev.value); + pa_log_debug("key code=%u, value=%u", ev.code, ev.value); switch (ev.code) { case KEY_VOLUMEDOWN: volchange = DOWN; break; @@ -109,7 +109,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC pa_sink *s; if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) - pa_log(__FILE__": failed to get sink '%s'", u->sink_name); + pa_log("failed to get sink '%s'", u->sink_name); else { int i; pa_cvolume cv = *pa_sink_get_volume(s, PA_MIXER_HARDWARE); @@ -173,7 +173,7 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments"); + pa_log("Failed to parse module arguments"); goto fail; } @@ -185,41 +185,41 @@ int pa__init(pa_core *c, pa_module*m) { u->fd_type = 0; if ((u->fd = open(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), O_RDONLY)) < 0) { - pa_log(__FILE__": failed to open evdev device: %s", pa_cstrerror(errno)); + pa_log("failed to open evdev device: %s", pa_cstrerror(errno)); goto fail; } if (ioctl(u->fd, EVIOCGVERSION, &version) < 0) { - pa_log(__FILE__": EVIOCGVERSION failed: %s", pa_cstrerror(errno)); + pa_log("EVIOCGVERSION failed: %s", pa_cstrerror(errno)); goto fail; } - pa_log_info(__FILE__": evdev driver version %i.%i.%i", version >> 16, (version >> 8) & 0xff, version & 0xff); + pa_log_info("evdev driver version %i.%i.%i", version >> 16, (version >> 8) & 0xff, version & 0xff); if(ioctl(u->fd, EVIOCGID, &input_id)) { - pa_log(__FILE__": EVIOCGID failed: %s", pa_cstrerror(errno)); + pa_log("EVIOCGID failed: %s", pa_cstrerror(errno)); goto fail; } - pa_log_info(__FILE__": evdev vendor 0x%04hx product 0x%04hx version 0x%04hx bustype %u", + pa_log_info("evdev vendor 0x%04hx product 0x%04hx version 0x%04hx bustype %u", input_id.vendor, input_id.product, input_id.version, input_id.bustype); memset(name, 0, sizeof(name)); if(ioctl(u->fd, EVIOCGNAME(sizeof(name)), name) < 0) { - pa_log(__FILE__": EVIOCGNAME failed: %s", pa_cstrerror(errno)); + pa_log("EVIOCGNAME failed: %s", pa_cstrerror(errno)); goto fail; } - pa_log_info(__FILE__": evdev device name: %s", name); + pa_log_info("evdev device name: %s", name); memset(evtype_bitmask, 0, sizeof(evtype_bitmask)); if (ioctl(u->fd, EVIOCGBIT(0, EV_MAX), evtype_bitmask) < 0) { - pa_log(__FILE__": EVIOCGBIT failed: %s", pa_cstrerror(errno)); + pa_log("EVIOCGBIT failed: %s", pa_cstrerror(errno)); goto fail; } if (!test_bit(EV_KEY, evtype_bitmask)) { - pa_log(__FILE__": device has no keys."); + pa_log("device has no keys."); goto fail; } diff --git a/src/modules/module-native-protocol-fd.c b/src/modules/module-native-protocol-fd.c index 9e1cac09..dd3b4abe 100644 --- a/src/modules/module-native-protocol-fd.c +++ b/src/modules/module-native-protocol-fd.c @@ -53,12 +53,12 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments."); + pa_log("failed to parse module arguments."); goto finish; } if (pa_modargs_get_value_s32(ma, "fd", &fd) < 0) { - pa_log(__FILE__": invalid file descriptor."); + pa_log("invalid file descriptor."); goto finish; } diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index 4d5ebb08..50e58853 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -120,13 +120,13 @@ int pa__init(pa_core *c, pa_module*m) { assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments."); + pa_log("failed to parse module arguments."); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { - pa_log(__FILE__": invalid sample format specification or channel map."); + pa_log("invalid sample format specification or channel map."); goto fail; } @@ -136,7 +136,7 @@ int pa__init(pa_core *c, pa_module*m) { m->userdata = u; if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { - pa_log(__FILE__": failed to create sink."); + pa_log("failed to create sink."); goto fail; } diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index 75ab9a9e..0be6bbe2 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -187,7 +187,7 @@ static void do_write(struct userdata *u) { update_usage(u); if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno)); + pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno)); clear_up(u); pa_module_unload_request(u->module); @@ -253,7 +253,7 @@ static void do_read(struct userdata *u) { update_usage(u); if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno)); + pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno)); clear_up(u); pa_module_unload_request(u->module); @@ -293,7 +293,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { assert(s && u); if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno)); + pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno)); return 0; } @@ -319,7 +319,7 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { assert(s && u); if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno)); + pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno)); return 0; } @@ -342,7 +342,7 @@ static int sink_get_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; if (pa_oss_get_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); + pa_log_info("device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); s->get_hw_volume = NULL; return -1; } @@ -354,7 +354,7 @@ static int sink_set_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; if (pa_oss_set_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); + pa_log_info("device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); s->set_hw_volume = NULL; return -1; } @@ -366,7 +366,7 @@ static int source_get_hw_volume(pa_source *s) { struct userdata *u = s->userdata; if (pa_oss_get_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); + pa_log_info("device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); s->get_hw_volume = NULL; return -1; } @@ -378,7 +378,7 @@ static int source_set_hw_volume(pa_source *s) { struct userdata *u = s->userdata; if (pa_oss_set_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); + pa_log_info("device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); s->set_hw_volume = NULL; return -1; } @@ -410,17 +410,17 @@ int pa__init(pa_core *c, pa_module*m) { u->core = c; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments."); + pa_log("failed to parse module arguments."); goto fail; } if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { - pa_log(__FILE__": record= and playback= expect numeric arguments."); + pa_log("record= and playback= expect numeric arguments."); goto fail; } if (!playback && !record) { - pa_log(__FILE__": neither playback nor record enabled for device."); + pa_log("neither playback nor record enabled for device."); goto fail; } @@ -429,13 +429,13 @@ int pa__init(pa_core *c, pa_module*m) { nfrags = DEFAULT_NFRAGS; frag_size = DEFAULT_FRAGSIZE; if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { - pa_log(__FILE__": failed to parse fragments arguments"); + pa_log("failed to parse fragments arguments"); goto fail; } u->sample_spec = c->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &u->sample_spec, &map, PA_CHANNEL_MAP_OSS) < 0) { - pa_log(__FILE__": failed to parse sample specification or channel map"); + pa_log("failed to parse sample specification or channel map"); goto fail; } @@ -443,14 +443,14 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; if (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_TRIGGER)) { - pa_log(__FILE__": OSS device not mmap capable."); + pa_log("OSS device not mmap capable."); goto fail; } - pa_log_info(__FILE__": device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + pa_log_info("device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); if (pa_oss_get_hw_description(p, hwdesc, sizeof(hwdesc)) >= 0) - pa_log_info(__FILE__": hardware name is '%s'.", hwdesc); + pa_log_info("hardware name is '%s'.", hwdesc); else hwdesc[0] = 0; @@ -463,19 +463,19 @@ int pa__init(pa_core *c, pa_module*m) { if (mode != O_WRONLY) { if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno)); + pa_log("SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno)); goto fail; } - pa_log_info(__FILE__": input -- %u fragments of size %u.", info.fragstotal, info.fragsize); + pa_log_info("input -- %u fragments of size %u.", info.fragstotal, info.fragsize); u->in_mmap_length = (u->in_fragment_size = info.fragsize) * (u->in_fragments = info.fragstotal); if ((u->in_mmap = mmap(NULL, u->in_mmap_length, PROT_READ, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { if (mode == O_RDWR) { - pa_log(__FILE__": mmap failed for input. Changing to O_WRONLY mode."); + pa_log("mmap failed for input. Changing to O_WRONLY mode."); mode = O_WRONLY; } else { - pa_log(__FILE__": mmap(): %s", pa_cstrerror(errno)); + pa_log("mmap(): %s", pa_cstrerror(errno)); goto fail; } } else { @@ -513,19 +513,19 @@ int pa__init(pa_core *c, pa_module*m) { if (mode != O_RDONLY) { if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno)); + pa_log("SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno)); goto fail; } - pa_log_info(__FILE__": output -- %u fragments of size %u.", info.fragstotal, info.fragsize); + pa_log_info("output -- %u fragments of size %u.", info.fragstotal, info.fragsize); u->out_mmap_length = (u->out_fragment_size = info.fragsize) * (u->out_fragments = info.fragstotal); if ((u->out_mmap = mmap(NULL, u->out_mmap_length, PROT_WRITE, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { if (mode == O_RDWR) { - pa_log(__FILE__": mmap filed for output. Changing to O_RDONLY mode."); + pa_log("mmap filed for output. Changing to O_RDONLY mode."); mode = O_RDONLY; } else { - pa_log(__FILE__": mmap(): %s", pa_cstrerror(errno)); + pa_log("mmap(): %s", pa_cstrerror(errno)); goto fail; } } else { @@ -565,12 +565,12 @@ int pa__init(pa_core *c, pa_module*m) { zero = 0; if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero) < 0) { - pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno)); + pa_log("SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno)); goto fail; } if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0) { - pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno)); + pa_log("SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno)); goto fail; } diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index b9b80e72..b71581d9 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -166,7 +166,7 @@ static void do_write(struct userdata *u) { assert(memchunk->length); if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { - pa_log(__FILE__": write() failed: %s", pa_cstrerror(errno)); + pa_log("write() failed: %s", pa_cstrerror(errno)); clear_up(u); pa_module_unload_request(u->module); @@ -222,7 +222,7 @@ static void do_read(struct userdata *u) { if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); if (errno != EAGAIN) { - pa_log(__FILE__": read() failed: %s", pa_cstrerror(errno)); + pa_log("read() failed: %s", pa_cstrerror(errno)); clear_up(u); pa_module_unload_request(u->module); } @@ -260,7 +260,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { assert(s && u && u->sink); if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { - pa_log_info(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY: %s", pa_cstrerror(errno)); + pa_log_info("device doesn't support SNDCTL_DSP_GETODELAY: %s", pa_cstrerror(errno)); s->get_latency = NULL; return 0; } @@ -296,7 +296,7 @@ static int sink_get_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; if (pa_oss_get_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); + pa_log_info("device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); s->get_hw_volume = NULL; return -1; } @@ -308,7 +308,7 @@ static int sink_set_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; if (pa_oss_set_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); + pa_log_info("device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); s->set_hw_volume = NULL; return -1; } @@ -320,7 +320,7 @@ static int source_get_hw_volume(pa_source *s) { struct userdata *u = s->userdata; if (pa_oss_get_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); + pa_log_info("device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); s->get_hw_volume = NULL; return -1; } @@ -332,7 +332,7 @@ static int source_set_hw_volume(pa_source *s) { struct userdata *u = s->userdata; if (pa_oss_set_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); + pa_log_info("device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); s->set_hw_volume = NULL; return -1; } @@ -360,17 +360,17 @@ int pa__init(pa_core *c, pa_module*m) { assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments."); + pa_log("failed to parse module arguments."); goto fail; } if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { - pa_log(__FILE__": record= and playback= expect numeric argument."); + pa_log("record= and playback= expect numeric argument."); goto fail; } if (!playback && !record) { - pa_log(__FILE__": neither playback nor record enabled for device."); + pa_log("neither playback nor record enabled for device."); goto fail; } @@ -378,7 +378,7 @@ int pa__init(pa_core *c, pa_module*m) { ss = c->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_OSS) < 0) { - pa_log(__FILE__": failed to parse sample specification or channel map"); + pa_log("failed to parse sample specification or channel map"); goto fail; } @@ -387,7 +387,7 @@ int pa__init(pa_core *c, pa_module*m) { frag_size = pa_bytes_per_second(&ss)/128; if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { - pa_log(__FILE__": failed to parse fragments arguments"); + pa_log("failed to parse fragments arguments"); goto fail; } @@ -395,11 +395,11 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; if (pa_oss_get_hw_description(p, hwdesc, sizeof(hwdesc)) >= 0) - pa_log_info(__FILE__": hardware name is '%s'.", hwdesc); + pa_log_info("hardware name is '%s'.", hwdesc); else hwdesc[0] = 0; - pa_log_info(__FILE__": device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + pa_log_info("device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); if (nfrags >= 2 && frag_size >= 1) if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) @@ -409,7 +409,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno)); + pa_log("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno)); goto fail; } assert(frag_size); @@ -420,13 +420,13 @@ int pa__init(pa_core *c, pa_module*m) { u->use_getospace = u->use_getispace = 0; if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { - pa_log_info(__FILE__": input -- %u fragments of size %u.", info.fragstotal, info.fragsize); + pa_log_info("input -- %u fragments of size %u.", info.fragstotal, info.fragsize); in_frag_size = info.fragsize; u->use_getispace = 1; } if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) { - pa_log_info(__FILE__": output -- %u fragments of size %u.", info.fragstotal, info.fragsize); + pa_log_info("output -- %u fragments of size %u.", info.fragstotal, info.fragsize); out_frag_size = info.fragsize; u->use_getospace = 1; } diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index c90039fd..4aee849b 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -100,7 +100,7 @@ static void do_write(struct userdata *u) { assert(u->memchunk.memblock && u->memchunk.length); if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { - pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); + pa_log("write(): %s", pa_cstrerror(errno)); return; } @@ -153,32 +153,32 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments"); + pa_log("failed to parse module arguments"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { - pa_log(__FILE__": invalid sample format specification"); + pa_log("invalid sample format specification"); goto fail; } mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777); if ((fd = open(p, O_RDWR)) < 0) { - pa_log(__FILE__": open('%s'): %s", p, pa_cstrerror(errno)); + pa_log("open('%s'): %s", p, pa_cstrerror(errno)); goto fail; } pa_fd_set_cloexec(fd, 1); if (fstat(fd, &st) < 0) { - pa_log(__FILE__": fstat('%s'): %s", p, pa_cstrerror(errno)); + pa_log("fstat('%s'): %s", p, pa_cstrerror(errno)); goto fail; } if (!S_ISFIFO(st.st_mode)) { - pa_log(__FILE__": '%s' is not a FIFO.", p); + pa_log("'%s' is not a FIFO.", p); goto fail; } @@ -189,7 +189,7 @@ int pa__init(pa_core *c, pa_module*m) { m->userdata = u; if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { - pa_log(__FILE__": failed to create sink."); + pa_log("failed to create sink."); goto fail; } u->sink->notify = notify_cb; diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index 43a8dab5..c251f7ac 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -97,7 +97,7 @@ static void do_read(struct userdata *u) { assert(u->chunk.memblock && u->chunk.memblock->length > u->chunk.index); if ((r = pa_iochannel_read(u->io, (uint8_t*) u->chunk.memblock->data + u->chunk.index, u->chunk.memblock->length - u->chunk.index)) <= 0) { - pa_log(__FILE__": read(): %s", pa_cstrerror(errno)); + pa_log("read(): %s", pa_cstrerror(errno)); return; } @@ -131,32 +131,32 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments"); + pa_log("failed to parse module arguments"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { - pa_log(__FILE__": invalid sample format specification or channel map"); + pa_log("invalid sample format specification or channel map"); goto fail; } mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777); if ((fd = open(p, O_RDWR)) < 0) { - pa_log(__FILE__": open('%s'): %s", p, pa_cstrerror(errno)); + pa_log("open('%s'): %s", p, pa_cstrerror(errno)); goto fail; } pa_fd_set_cloexec(fd, 1); if (fstat(fd, &st) < 0) { - pa_log(__FILE__": fstat('%s'): %s", p, pa_cstrerror(errno)); + pa_log("fstat('%s'): %s", p, pa_cstrerror(errno)); goto fail; } if (!S_ISFIFO(st.st_mode)) { - pa_log(__FILE__": '%s' is not a FIFO.", p); + pa_log("'%s' is not a FIFO.", p); goto fail; } @@ -166,7 +166,7 @@ int pa__init(pa_core *c, pa_module*m) { u->core = c; if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) { - pa_log(__FILE__": failed to create source."); + pa_log("failed to create source."); goto fail; } u->source->userdata = u; diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index d1f5fa15..df58958a 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -221,7 +221,7 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments"); + pa_log("Failed to parse module arguments"); goto finish; } @@ -229,7 +229,7 @@ int pa__init(pa_core *c, pa_module*m) { #if defined(USE_TCP_SOCKETS) if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) { - pa_log(__FILE__": port= expects a numerical argument between 1 and 65535."); + pa_log("port= expects a numerical argument between 1 and 65535."); goto fail; } @@ -268,18 +268,18 @@ int pa__init(pa_core *c, pa_module*m) { * /tmp/.esd/, hence we have to create the dir first */ if (pa_make_secure_parent_dir(u->socket_path, c->is_system_instance ? 0755 : 0700, (uid_t)-1, (gid_t)-1) < 0) { - pa_log(__FILE__": Failed to create socket directory: %s\n", pa_cstrerror(errno)); + pa_log("Failed to create socket directory: %s\n", pa_cstrerror(errno)); goto fail; } #endif if ((r = pa_unix_socket_remove_stale(tmp)) < 0) { - pa_log(__FILE__": Failed to remove stale UNIX socket '%s': %s", tmp, pa_cstrerror(errno)); + pa_log("Failed to remove stale UNIX socket '%s': %s", tmp, pa_cstrerror(errno)); goto fail; } if (r) - pa_log(__FILE__": Removed stale UNIX socket '%s'.", tmp); + pa_log("Removed stale UNIX socket '%s'.", tmp); if (!(s = pa_socket_server_new_unix(c->mainloop, tmp))) goto fail; diff --git a/src/modules/module-rescue-streams.c b/src/modules/module-rescue-streams.c index 5700ef43..7aa205bd 100644 --- a/src/modules/module-rescue-streams.c +++ b/src/modules/module-rescue-streams.c @@ -54,12 +54,12 @@ static pa_hook_result_t sink_hook_callback(pa_core *c, pa_sink *sink, void* user assert(sink); if (!pa_idxset_size(sink->inputs)) { - pa_log_debug(__FILE__": No sink inputs to move away."); + pa_log_debug("No sink inputs to move away."); return PA_HOOK_OK; } if (!(target = pa_namereg_get(c, NULL, PA_NAMEREG_SINK, 0))) { - pa_log_info(__FILE__": No evacuation sink found."); + pa_log_info("No evacuation sink found."); return PA_HOOK_OK; } @@ -67,11 +67,11 @@ static pa_hook_result_t sink_hook_callback(pa_core *c, pa_sink *sink, void* user while ((i = pa_idxset_first(sink->inputs, NULL))) { if (pa_sink_input_move_to(i, target, 1) < 0) { - pa_log_warn(__FILE__": Failed to move sink input %u \"%s\" to %s.", i->index, i->name, target->name); + pa_log_warn("Failed to move sink input %u \"%s\" to %s.", i->index, i->name, target->name); return PA_HOOK_OK; } - pa_log_info(__FILE__": Sucessfully moved sink input %u \"%s\" to %s.", i->index, i->name, target->name); + pa_log_info("Sucessfully moved sink input %u \"%s\" to %s.", i->index, i->name, target->name); } @@ -86,12 +86,12 @@ static pa_hook_result_t source_hook_callback(pa_core *c, pa_source *source, void assert(source); if (!pa_idxset_size(source->outputs)) { - pa_log_debug(__FILE__": No source outputs to move away."); + pa_log_debug("No source outputs to move away."); return PA_HOOK_OK; } if (!(target = pa_namereg_get(c, NULL, PA_NAMEREG_SOURCE, 0))) { - pa_log_info(__FILE__": No evacuation source found."); + pa_log_info("No evacuation source found."); return PA_HOOK_OK; } @@ -99,11 +99,11 @@ static pa_hook_result_t source_hook_callback(pa_core *c, pa_source *source, void while ((o = pa_idxset_first(source->outputs, NULL))) { if (pa_source_output_move_to(o, target) < 0) { - pa_log_warn(__FILE__": Failed to move source output %u \"%s\" to %s.", o->index, o->name, target->name); + pa_log_warn("Failed to move source output %u \"%s\" to %s.", o->index, o->name, target->name); return PA_HOOK_OK; } - pa_log_info(__FILE__": Sucessfully moved source output %u \"%s\" to %s.", o->index, o->name, target->name); + pa_log_info("Sucessfully moved source output %u \"%s\" to %s.", o->index, o->name, target->name); } @@ -118,7 +118,7 @@ int pa__init(pa_core *c, pa_module*m) { assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments"); + pa_log("Failed to parse module arguments"); return -1; } diff --git a/src/modules/module-sine.c b/src/modules/module-sine.c index 89c3c609..fa29ba16 100644 --- a/src/modules/module-sine.c +++ b/src/modules/module-sine.c @@ -112,7 +112,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_sink_input_new_data data; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments"); + pa_log("Failed to parse module arguments"); goto fail; } @@ -125,7 +125,7 @@ int pa__init(pa_core *c, pa_module*m) { sink_name = pa_modargs_get_value(ma, "sink", NULL); if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": No such sink."); + pa_log("No such sink."); goto fail; } @@ -135,7 +135,7 @@ int pa__init(pa_core *c, pa_module*m) { frequency = 440; if (pa_modargs_get_value_u32(ma, "frequency", &frequency) < 0 || frequency < 1 || frequency > ss.rate/2) { - pa_log(__FILE__": Invalid frequency specification"); + pa_log("Invalid frequency specification"); goto fail; } diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 53c73af7..e13254e9 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -144,7 +144,7 @@ static void do_write(struct userdata *u) { len = 0; if (len == u->buffer_size) - pa_log_debug(__FILE__": Solaris buffer underflow!"); + pa_log_debug("Solaris buffer underflow!"); len -= len % u->frame_size; @@ -168,7 +168,7 @@ static void do_write(struct userdata *u) { } if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, len)) < 0) { - pa_log(__FILE__": write() failed: %s", pa_cstrerror(errno)); + pa_log("write() failed: %s", pa_cstrerror(errno)); return; } @@ -206,7 +206,7 @@ static void do_read(struct userdata *u) { if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); if (errno != EAGAIN) - pa_log(__FILE__": read() failed: %s", pa_cstrerror(errno)); + pa_log("read() failed: %s", pa_cstrerror(errno)); return; } @@ -332,9 +332,9 @@ static int sink_set_hw_volume_cb(pa_sink *s) { if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { if (errno == EINVAL) - pa_log(__FILE__": AUDIO_SETINFO: Unsupported volume."); + pa_log("AUDIO_SETINFO: Unsupported volume."); else - pa_log(__FILE__": AUDIO_SETINFO: %s", pa_cstrerror(errno)); + pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); return -1; } @@ -363,7 +363,7 @@ static int sink_set_hw_mute_cb(pa_sink *s) { info.output_muted = !!s->hw_muted; if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { - pa_log(__FILE__": AUDIO_SETINFO: %s", pa_cstrerror(errno)); + pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); return -1; } @@ -395,9 +395,9 @@ static int source_set_hw_volume_cb(pa_source *s) { if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { if (errno == EINVAL) - pa_log(__FILE__": AUDIO_SETINFO: Unsupported volume."); + pa_log("AUDIO_SETINFO: Unsupported volume."); else - pa_log(__FILE__": AUDIO_SETINFO: %s", pa_cstrerror(errno)); + pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); return -1; } @@ -461,9 +461,9 @@ static int pa_solaris_auto_format(int fd, int mode, pa_sample_spec *ss) { if (ioctl(fd, AUDIO_SETINFO, &info) < 0) { if (errno == EINVAL) - pa_log(__FILE__": AUDIO_SETINFO: Unsupported sample format."); + pa_log("AUDIO_SETINFO: Unsupported sample format."); else - pa_log(__FILE__": AUDIO_SETINFO: %s", pa_cstrerror(errno)); + pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); return -1; } @@ -479,9 +479,9 @@ static int pa_solaris_set_buffer(int fd, int buffer_size) { if (ioctl(fd, AUDIO_SETINFO, &info) < 0) { if (errno == EINVAL) - pa_log(__FILE__": AUDIO_SETINFO: Unsupported buffer size."); + pa_log("AUDIO_SETINFO: Unsupported buffer size."); else - pa_log(__FILE__": AUDIO_SETINFO: %s", pa_cstrerror(errno)); + pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); return -1; } @@ -503,17 +503,17 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments."); + pa_log("failed to parse module arguments."); goto fail; } if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { - pa_log(__FILE__": record= and playback= expect numeric argument."); + pa_log("record= and playback= expect numeric argument."); goto fail; } if (!playback && !record) { - pa_log(__FILE__": neither playback nor record enabled for device."); + pa_log("neither playback nor record enabled for device."); goto fail; } @@ -521,20 +521,20 @@ int pa__init(pa_core *c, pa_module*m) { buffer_size = 16384; if (pa_modargs_get_value_s32(ma, "buffer_size", &buffer_size) < 0) { - pa_log(__FILE__": failed to parse buffer size argument"); + pa_log("failed to parse buffer size argument"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { - pa_log(__FILE__": failed to parse sample specification"); + pa_log("failed to parse sample specification"); goto fail; } if ((fd = open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), mode | O_NONBLOCK)) < 0) goto fail; - pa_log_info(__FILE__": device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + pa_log_info("device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); if (pa_solaris_auto_format(fd, mode, &ss) < 0) goto fail; diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 53bffd3b..de1a12c9 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -206,7 +206,7 @@ static void command_stream_killed(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t comma struct userdata *u = userdata; assert(pd && t && u && u->pdispatch == pd); - pa_log(__FILE__": stream killed"); + pa_log("stream killed"); die(u); } @@ -223,7 +223,7 @@ static void command_subscribe_event(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t com if (pa_tagstruct_getu32(t, &e) < 0 || pa_tagstruct_getu32(t, &idx) < 0 || !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid protocol reply"); + pa_log("invalid protocol reply"); die(u); return; } @@ -284,13 +284,13 @@ static void command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED ui if (pa_tagstruct_getu32(t, &channel) < 0 || pa_tagstruct_getu32(t, &bytes) < 0 || !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid protocol reply"); + pa_log("invalid protocol reply"); die(u); return; } if (channel != u->channel) { - pa_log(__FILE__": recieved data for invalid channel"); + pa_log("recieved data for invalid channel"); die(u); return; } @@ -311,9 +311,9 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G if (command != PA_COMMAND_REPLY) { if (command == PA_COMMAND_ERROR) - pa_log(__FILE__": failed to get latency."); + pa_log("failed to get latency."); else - pa_log(__FILE__": protocol error."); + pa_log("protocol error."); die(u); return; } @@ -326,7 +326,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G pa_tagstruct_gets64(t, &write_index) < 0 || pa_tagstruct_gets64(t, &read_index) < 0 || !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid reply. (latency)"); + pa_log("invalid reply. (latency)"); die(u); return; } @@ -353,7 +353,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G u->host_latency = 0; #endif -/* pa_log(__FILE__": estimated host latency: %0.0f usec", (double) u->host_latency); */ +/* pa_log("estimated host latency: %0.0f usec", (double) u->host_latency); */ } static void request_latency(struct userdata *u) { @@ -392,9 +392,9 @@ static void stream_get_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_ if (command != PA_COMMAND_REPLY) { if (command == PA_COMMAND_ERROR) - pa_log(__FILE__": failed to get info."); + pa_log("failed to get info."); else - pa_log(__FILE__": protocol error."); + pa_log("protocol error."); die(u); return; } @@ -413,7 +413,7 @@ static void stream_get_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_ pa_tagstruct_gets(t, &driver) < 0 || pa_tagstruct_getu32(t, &flags) < 0 || !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid reply. (get_info)"); + pa_log("invalid reply. (get_info)"); die(u); return; } @@ -495,9 +495,9 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN if (command != PA_COMMAND_REPLY) { if (command == PA_COMMAND_ERROR) - pa_log(__FILE__": failed to create stream."); + pa_log("failed to create stream."); else - pa_log(__FILE__": protocol error."); + pa_log("protocol error."); die(u); return; } @@ -508,7 +508,7 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN pa_tagstruct_getu32(t, &u->requested_bytes) < 0 || #endif !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid reply. (create stream)"); + pa_log("invalid reply. (create stream)"); die(u); return; } @@ -535,16 +535,16 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_tagstruct_getu32(t, &u->version) < 0 || !pa_tagstruct_eof(t)) { if (command == PA_COMMAND_ERROR) - pa_log(__FILE__": failed to authenticate"); + pa_log("failed to authenticate"); else - pa_log(__FILE__": protocol error."); + pa_log("protocol error."); die(u); return; } /* Minimum supported protocol version */ if (u->version < 8) { - pa_log(__FILE__": incompatible protocol version"); + pa_log("incompatible protocol version"); die(u); return; } @@ -606,7 +606,7 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { struct userdata *u = userdata; assert(p && u); - pa_log(__FILE__": stream died."); + pa_log("stream died."); die(u); } @@ -616,7 +616,7 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_c assert(p && packet && u); if (pa_pdispatch_run(u->pdispatch, packet, creds, u) < 0) { - pa_log(__FILE__": invalid packet"); + pa_log("invalid packet"); die(u); } } @@ -627,7 +627,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, PA_GCC_UN assert(p && chunk && u); if (channel != u->channel) { - pa_log(__FILE__": recieved memory block on bad channel."); + pa_log("recieved memory block on bad channel."); die(u); return; } @@ -646,7 +646,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata u->client = NULL; if (!io) { - pa_log(__FILE__": connection failed."); + pa_log("connection failed."); pa_module_unload_request(u->module); return; } @@ -833,7 +833,7 @@ static int load_key(struct userdata *u, const char*fn) { u->auth_cookie_in_property = 0; if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { - pa_log_debug(__FILE__": using already loaded auth cookie."); + pa_log_debug("using already loaded auth cookie."); pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); u->auth_cookie_in_property = 1; return 0; @@ -845,7 +845,7 @@ static int load_key(struct userdata *u, const char*fn) { if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) return -1; - pa_log_debug(__FILE__": loading cookie from disk."); + pa_log_debug("loading cookie from disk."); if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) u->auth_cookie_in_property = 1; @@ -864,7 +864,7 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments"); + pa_log("failed to parse module arguments"); goto fail; } @@ -894,18 +894,18 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; if (!(u->server_name = pa_xstrdup(pa_modargs_get_value(ma, "server", NULL)))) { - pa_log(__FILE__": no server specified."); + pa_log("no server specified."); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { - pa_log(__FILE__": invalid sample format specification"); + pa_log("invalid sample format specification"); goto fail; } if (!(u->client = pa_socket_client_new_string(c->mainloop, u->server_name, PA_NATIVE_DEFAULT_PORT))) { - pa_log(__FILE__": failed to connect to server '%s'", u->server_name); + pa_log("failed to connect to server '%s'", u->server_name); goto fail; } @@ -916,7 +916,7 @@ int pa__init(pa_core *c, pa_module*m) { #ifdef TUNNEL_SINK if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { - pa_log(__FILE__": failed to create sink."); + pa_log("failed to create sink."); goto fail; } @@ -933,7 +933,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_sink_set_owner(u->sink, m); #else if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) { - pa_log(__FILE__": failed to create source."); + pa_log("failed to create source."); goto fail; } diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index bdead0f6..0e4f278c 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -123,10 +123,10 @@ static int load_rules(struct userdata *u) { if (!f) { if (errno == ENOENT) { - pa_log_info(__FILE__": starting with empty ruleset."); + pa_log_info("starting with empty ruleset."); ret = 0; } else - pa_log(__FILE__": failed to open file '%s': %s", u->table_file, pa_cstrerror(errno)); + pa_log("failed to open file '%s': %s", u->table_file, pa_cstrerror(errno)); goto finish; } @@ -155,14 +155,14 @@ static int load_rules(struct userdata *u) { assert(ln == buf_volume); if (!parse_volume(buf_volume, &v)) { - pa_log(__FILE__": parse failure in %s:%u, stopping parsing", u->table_file, n); + pa_log("parse failure in %s:%u, stopping parsing", u->table_file, n); goto finish; } ln = buf_name; if (pa_hashmap_get(u->hashmap, buf_name)) { - pa_log(__FILE__": double entry in %s:%u, ignoring", u->table_file, n); + pa_log("double entry in %s:%u, ignoring", u->table_file, n); goto finish; } @@ -174,7 +174,7 @@ static int load_rules(struct userdata *u) { } if (ln == buf_volume) { - pa_log(__FILE__": invalid number of lines in %s.", u->table_file); + pa_log("invalid number of lines in %s.", u->table_file); goto finish; } @@ -200,7 +200,7 @@ static int save_rules(struct userdata *u) { pa_open_config_file(NULL, DEFAULT_VOLUME_TABLE_FILE, NULL, &u->table_file, "w"); if (!f) { - pa_log(__FILE__": failed to open file '%s': %s", u->table_file, pa_cstrerror(errno)); + pa_log("failed to open file '%s': %s", u->table_file, pa_cstrerror(errno)); goto finish; } @@ -279,12 +279,12 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 pa_xfree(name); if (!pa_cvolume_equal(pa_sink_input_get_volume(si), &r->volume)) { - pa_log_info(__FILE__": Saving volume for <%s>", r->name); + pa_log_info("Saving volume for <%s>", r->name); r->volume = *pa_sink_input_get_volume(si); u->modified = 1; } } else { - pa_log_info(__FILE__": Creating new entry for <%s>", name); + pa_log_info("Creating new entry for <%s>", name); r = pa_xnew(struct rule, 1); r->name = name; @@ -307,7 +307,7 @@ static pa_hook_result_t hook_callback(pa_core *c, pa_sink_input_new_data *data, if ((r = pa_hashmap_get(u->hashmap, name))) { if (data->sample_spec_is_set && data->sample_spec.channels == r->volume.channels) { - pa_log_info(__FILE__": Restoring volume for <%s>", r->name); + pa_log_info("Restoring volume for <%s>", r->name); pa_sink_input_new_data_set_volume(data, &r->volume); } } @@ -323,7 +323,7 @@ int pa__init(pa_core *c, pa_module*m) { assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": Failed to parse module arguments"); + pa_log("Failed to parse module arguments"); goto fail; } diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index 5f55c202..2cc665b4 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -125,7 +125,7 @@ static void do_write(struct userdata *u) LeaveCriticalSection(&u->crit); if (free_frags == u->fragments) - pa_log_debug(__FILE__": WaveOut underflow!"); + pa_log_debug("WaveOut underflow!"); while (free_frags) { hdr = &u->ohdrs[u->cur_ohdr]; @@ -209,7 +209,7 @@ static void do_read(struct userdata *u) LeaveCriticalSection(&u->crit); if (free_frags == u->fragments) - pa_log_debug(__FILE__": WaveIn overflow!"); + pa_log_debug("WaveIn overflow!"); while (free_frags) { hdr = &u->ihdrs[u->cur_ihdr]; @@ -395,7 +395,7 @@ static int ss_to_waveformat(pa_sample_spec *ss, LPWAVEFORMATEX wf) { wf->wFormatTag = WAVE_FORMAT_PCM; if (ss->channels > 2) { - pa_log_error(__FILE__": ERROR: More than two channels not supported."); + pa_log_error("ERROR: More than two channels not supported."); return -1; } @@ -408,7 +408,7 @@ static int ss_to_waveformat(pa_sample_spec *ss, LPWAVEFORMATEX wf) { case 44100: break; default: - pa_log_error(__FILE__": ERROR: Unsupported sample rate."); + pa_log_error("ERROR: Unsupported sample rate."); return -1; } @@ -419,7 +419,7 @@ static int ss_to_waveformat(pa_sample_spec *ss, LPWAVEFORMATEX wf) { else if (ss->format == PA_SAMPLE_S16NE) wf->wBitsPerSample = 16; else { - pa_log_error(__FILE__": ERROR: Unsupported sample format."); + pa_log_error("ERROR: Unsupported sample format."); return -1; } @@ -447,30 +447,30 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments."); + pa_log("failed to parse module arguments."); goto fail; } if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { - pa_log(__FILE__": record= and playback= expect boolean argument."); + pa_log("record= and playback= expect boolean argument."); goto fail; } if (!playback && !record) { - pa_log(__FILE__": neither playback nor record enabled for device."); + pa_log("neither playback nor record enabled for device."); goto fail; } nfrags = 5; frag_size = 8192; if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { - pa_log(__FILE__": failed to parse fragments arguments"); + pa_log("failed to parse fragments arguments"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_WAVEEX) < 0) { - pa_log(__FILE__": failed to parse sample specification"); + pa_log("failed to parse sample specification"); goto fail; } @@ -484,13 +484,13 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; if (waveInStart(hwi) != MMSYSERR_NOERROR) goto fail; - pa_log_debug(__FILE__": Opened waveIn subsystem."); + pa_log_debug("Opened waveIn subsystem."); } if (playback) { if (waveOutOpen(&hwo, WAVE_MAPPER, &wf, (DWORD_PTR)chunk_done_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) goto fail; - pa_log_debug(__FILE__": Opened waveOut subsystem."); + pa_log_debug("Opened waveOut subsystem."); } InitializeCriticalSection(&u->crit); diff --git a/src/modules/module-x11-bell.c b/src/modules/module-x11-bell.c index 7ac5f558..48e95c8c 100644 --- a/src/modules/module-x11-bell.c +++ b/src/modules/module-x11-bell.c @@ -70,7 +70,7 @@ static int ring_bell(struct userdata *u, int percent) { assert(u); if (!(s = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": Invalid sink: %s", u->sink_name); + pa_log("Invalid sink: %s", u->sink_name); return -1; } @@ -89,7 +89,7 @@ static int x11_event_callback(pa_x11_wrapper *w, XEvent *e, void *userdata) { bne = (XkbBellNotifyEvent*) e; if (ring_bell(u, bne->percent) < 0) { - pa_log_info(__FILE__": Ringing bell failed, reverting to X11 device bell."); + pa_log_info("Ringing bell failed, reverting to X11 device bell."); XkbForceDeviceBell(pa_x11_wrapper_get_display(w), bne->device, bne->bell_class, bne->bell_id, bne->percent); } @@ -104,7 +104,7 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments"); + pa_log("failed to parse module arguments"); goto fail; } @@ -121,7 +121,7 @@ int pa__init(pa_core *c, pa_module*m) { minor = XkbMinorVersion; if (!XkbLibraryVersion(&major, &minor)) { - pa_log(__FILE__": XkbLibraryVersion() failed"); + pa_log("XkbLibraryVersion() failed"); goto fail; } @@ -130,7 +130,7 @@ int pa__init(pa_core *c, pa_module*m) { if (!XkbQueryExtension(pa_x11_wrapper_get_display(u->x11_wrapper), NULL, &u->xkb_event_base, NULL, &major, &minor)) { - pa_log(__FILE__": XkbQueryExtension() failed"); + pa_log("XkbQueryExtension() failed"); goto fail; } diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c index 0ee453cc..f2cace14 100644 --- a/src/modules/module-x11-publish.c +++ b/src/modules/module-x11-publish.c @@ -79,7 +79,7 @@ static int load_key(struct userdata *u, const char*fn) { u->auth_cookie_in_property = 0; if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { - pa_log_debug(__FILE__": using already loaded auth cookie."); + pa_log_debug("using already loaded auth cookie."); pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); u->auth_cookie_in_property = 1; return 0; @@ -91,7 +91,7 @@ static int load_key(struct userdata *u, const char*fn) { if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) return -1; - pa_log_debug(__FILE__": loading cookie from disk."); + pa_log_debug("loading cookie from disk."); if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) u->auth_cookie_in_property = 1; @@ -109,7 +109,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_strlist *l; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments"); + pa_log("failed to parse module arguments"); goto fail; } @@ -168,7 +168,7 @@ void pa__done(pa_core *c, pa_module*m) { /* Yes, here is a race condition */ if (!pa_x11_get_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_ID", t, sizeof(t)) || strcmp(t, u->id)) - pa_log_warn(__FILE__": PulseAudio information vanished from X11!"); + pa_log_warn("PulseAudio information vanished from X11!"); else { pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_ID"); pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SERVER"); diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index 651a95b7..696d8afe 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -203,12 +203,12 @@ static int publish_service(struct userdata *u, struct service *s) { u->port, txt) < 0) { - pa_log(__FILE__": avahi_entry_group_add_service_strlst(): %s", avahi_strerror(avahi_client_errno(u->client))); + pa_log("avahi_entry_group_add_service_strlst(): %s", avahi_strerror(avahi_client_errno(u->client))); goto finish; } if (avahi_entry_group_commit(s->entry_group) < 0) { - pa_log(__FILE__": avahi_entry_group_commit(): %s", avahi_strerror(avahi_client_errno(u->client))); + pa_log("avahi_entry_group_commit(): %s", avahi_strerror(avahi_client_errno(u->client))); goto finish; } @@ -456,7 +456,7 @@ static int publish_main_service(struct userdata *u) { if (!u->main_entry_group) { if (!(u->main_entry_group = avahi_entry_group_new(u->client, main_entry_group_callback, u))) { - pa_log(__FILE__": avahi_entry_group_new() failed: %s", avahi_strerror(avahi_client_errno(u->client))); + pa_log("avahi_entry_group_new() failed: %s", avahi_strerror(avahi_client_errno(u->client))); goto fail; } } else @@ -475,12 +475,12 @@ static int publish_main_service(struct userdata *u) { u->port, txt) < 0) { - pa_log(__FILE__": avahi_entry_group_add_service_strlst() failed: %s", avahi_strerror(avahi_client_errno(u->client))); + pa_log("avahi_entry_group_add_service_strlst() failed: %s", avahi_strerror(avahi_client_errno(u->client))); goto fail; } if (avahi_entry_group_commit(u->main_entry_group) < 0) { - pa_log(__FILE__": avahi_entry_group_commit() failed: %s", avahi_strerror(avahi_client_errno(u->client))); + pa_log("avahi_entry_group_commit() failed: %s", avahi_strerror(avahi_client_errno(u->client))); goto fail; } @@ -501,7 +501,7 @@ static int publish_all_services(struct userdata *u) { assert(u); - pa_log_debug(__FILE__": Publishing services in Zeroconf"); + pa_log_debug("Publishing services in Zeroconf"); for (sink = pa_idxset_first(u->core->sinks, &idx); sink; sink = pa_idxset_next(u->core->sinks, &idx)) if (publish_sink(u, sink) < 0) @@ -531,7 +531,7 @@ static void unpublish_all_services(struct userdata *u, int rem) { assert(u); - pa_log_debug(__FILE__": Unpublishing services in Zeroconf"); + pa_log_debug("Unpublishing services in Zeroconf"); while ((s = pa_hashmap_iterate(u->services, &state, NULL))) { if (s->entry_group) { @@ -576,7 +576,7 @@ static void client_callback(AvahiClient *c, AvahiClientState state, void *userda avahi_client_free(u->client); if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error))) - pa_log(__FILE__": pa_avahi_client_new() failed: %s", avahi_strerror(error)); + pa_log("pa_avahi_client_new() failed: %s", avahi_strerror(error)); } break; @@ -593,12 +593,12 @@ int pa__init(pa_core *c, pa_module*m) { int error; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments."); + pa_log("failed to parse module arguments."); goto fail; } if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port == 0 || port >= 0xFFFF) { - pa_log(__FILE__": invalid port specified."); + pa_log("invalid port specified."); goto fail; } @@ -623,7 +623,7 @@ int pa__init(pa_core *c, pa_module*m) { u->service_name = pa_xstrdup(pa_get_host_name(hn, sizeof(hn))); if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error))) { - pa_log(__FILE__": pa_avahi_client_new() failed: %s", avahi_strerror(error)); + pa_log("pa_avahi_client_new() failed: %s", avahi_strerror(error)); goto fail; } diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index 177322be..d1c623b4 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -57,27 +57,27 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { tcaps = pcaps ? pcaps : &dcaps; if (ioctl(fd, SNDCTL_DSP_GETCAPS, tcaps) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s", pa_cstrerror(errno)); + pa_log("SNDCTL_DSP_GETCAPS: %s", pa_cstrerror(errno)); goto fail; } if (*tcaps & DSP_CAP_DUPLEX) goto success; - pa_log_warn(__FILE__": '%s' doesn't support full duplex", device); + pa_log_warn("'%s' doesn't support full duplex", device); close(fd); } if ((fd = open(device, (*mode = O_WRONLY)|O_NDELAY)) < 0) { if ((fd = open(device, (*mode = O_RDONLY)|O_NDELAY)) < 0) { - pa_log(__FILE__": open('%s'): %s", device, pa_cstrerror(errno)); + pa_log("open('%s'): %s", device, pa_cstrerror(errno)); goto fail; } } } else { if ((fd = open(device, *mode|O_NDELAY)) < 0) { - pa_log(__FILE__": open('%s'): %s", device, pa_cstrerror(errno)); + pa_log("open('%s'): %s", device, pa_cstrerror(errno)); goto fail; } } @@ -87,11 +87,11 @@ success: *pcaps = 0; if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETCAPS: %s", pa_cstrerror(errno)); + pa_log("SNDCTL_DSP_GETCAPS: %s", pa_cstrerror(errno)); goto fail; } - pa_log_debug(__FILE__": capabilities:%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + pa_log_debug("capabilities:%s%s%s%s%s%s%s%s%s%s%s%s%s%s", *pcaps & DSP_CAP_BATCH ? " BATCH" : "", *pcaps & DSP_CAP_BIND ? " BIND" : "", *pcaps & DSP_CAP_COPROC ? " COPROC" : "", @@ -168,7 +168,7 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss) { if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != f) { format = AFMT_U8; if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != AFMT_U8) { - pa_log(__FILE__": SNDCTL_DSP_SETFMT: %s", format != AFMT_U8 ? "No supported sample format" : pa_cstrerror(errno)); + pa_log("SNDCTL_DSP_SETFMT: %s", format != AFMT_U8 ? "No supported sample format" : pa_cstrerror(errno)); return -1; } else ss->format = PA_SAMPLE_U8; @@ -179,31 +179,31 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss) { } if (orig_format != ss->format) - pa_log_warn(__FILE__": device doesn't support sample format %s, changed to %s.", + pa_log_warn("device doesn't support sample format %s, changed to %s.", pa_sample_format_to_string(orig_format), pa_sample_format_to_string(ss->format)); channels = ss->channels; if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) { - pa_log(__FILE__": SNDCTL_DSP_CHANNELS: %s", pa_cstrerror(errno)); + pa_log("SNDCTL_DSP_CHANNELS: %s", pa_cstrerror(errno)); return -1; } assert(channels > 0); if (ss->channels != channels) { - pa_log_warn(__FILE__": device doesn't support %i channels, using %i channels.", ss->channels, channels); + pa_log_warn("device doesn't support %i channels, using %i channels.", ss->channels, channels); ss->channels = channels; } speed = ss->rate; if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) { - pa_log(__FILE__": SNDCTL_DSP_SPEED: %s", pa_cstrerror(errno)); + pa_log("SNDCTL_DSP_SPEED: %s", pa_cstrerror(errno)); return -1; } assert(speed > 0); if (ss->rate != (unsigned) speed) { - pa_log_warn(__FILE__": device doesn't support %i Hz, changed to %i Hz.", ss->rate, speed); + pa_log_warn("device doesn't support %i Hz, changed to %i Hz.", ss->rate, speed); /* If the sample rate deviates too much, we need to resample */ if (speed < ss->rate*.95 || speed > ss->rate*1.05) @@ -230,7 +230,7 @@ int pa_oss_set_fragments(int fd, int nfrags, int frag_size) { arg = ((int) nfrags << 16) | simple_log2(frag_size); if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &arg) < 0) { - pa_log(__FILE__": SNDCTL_DSP_SETFRAGMENT: %s", pa_cstrerror(errno)); + pa_log("SNDCTL_DSP_SETFRAGMENT: %s", pa_cstrerror(errno)); return -1; } @@ -253,7 +253,7 @@ static int pa_oss_get_volume(int fd, int mixer, const pa_sample_spec *ss, pa_cvo if ((volume->channels = ss->channels) >= 2) volume->values[1] = (((vol >> 8) & 0xFF) * PA_VOLUME_NORM) / 100; - pa_log_debug(__FILE__": Read mixer settings: %s", pa_cvolume_snprint(cv, sizeof(cv), volume)); + pa_log_debug("Read mixer settings: %s", pa_cvolume_snprint(cv, sizeof(cv), volume)); return 0; } @@ -274,7 +274,7 @@ static int pa_oss_set_volume(int fd, int mixer, const pa_sample_spec *ss, const if (ioctl(fd, mixer, &vol) < 0) return -1; - pa_log_debug(__FILE__": Wrote mixer settings: %s", pa_cvolume_snprint(cv, sizeof(cv), volume)); + pa_log_debug("Wrote mixer settings: %s", pa_cvolume_snprint(cv, sizeof(cv), volume)); return 0; } @@ -319,7 +319,7 @@ int pa_oss_get_hw_description(const char *dev, char *name, size_t l) { !(f = fopen("/proc/asound/oss/sndstat", "r"))) { if (errno != ENOENT) - pa_log_warn(__FILE__": failed to open OSS sndstat device: %s", pa_cstrerror(errno)); + pa_log_warn("failed to open OSS sndstat device: %s", pa_cstrerror(errno)); return -1; } diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index 5d3f3e27..338d57cf 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -165,7 +165,7 @@ static void rtp_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event s->offset = s->rtp_context.timestamp; if (s->ssrc == s->userdata->core->cookie) - pa_log_warn(__FILE__": WARNING! Detected RTP packet loop!"); + pa_log_warn("WARNING! Detected RTP packet loop!"); } else { if (s->ssrc != s->rtp_context.ssrc) { pa_memblock_unref(chunk.memblock); @@ -217,13 +217,13 @@ static int mcast_socket(const struct sockaddr* sa, socklen_t salen) { af = sa->sa_family; if ((fd = socket(af, SOCK_DGRAM, 0)) < 0) { - pa_log(__FILE__": Failed to create socket: %s", pa_cstrerror(errno)); + pa_log("Failed to create socket: %s", pa_cstrerror(errno)); goto fail; } one = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) { - pa_log(__FILE__": SO_REUSEADDR failed: %s", pa_cstrerror(errno)); + pa_log("SO_REUSEADDR failed: %s", pa_cstrerror(errno)); goto fail; } @@ -240,12 +240,12 @@ static int mcast_socket(const struct sockaddr* sa, socklen_t salen) { } if (r < 0) { - pa_log_info(__FILE__": Joining mcast group failed: %s", pa_cstrerror(errno)); + pa_log_info("Joining mcast group failed: %s", pa_cstrerror(errno)); goto fail; } if (bind(fd, sa, salen) < 0) { - pa_log(__FILE__": bind() failed: %s", pa_cstrerror(errno)); + pa_log("bind() failed: %s", pa_cstrerror(errno)); goto fail; } @@ -268,12 +268,12 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in pa_sink_input_new_data data; if (u->n_sessions >= MAX_SESSIONS) { - pa_log(__FILE__": session limit reached."); + pa_log("session limit reached."); goto fail; } if (!(sink = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": sink does not exist."); + pa_log("sink does not exist."); goto fail; } @@ -301,7 +301,7 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in pa_xfree(c); if (!s->sink_input) { - pa_log(__FILE__": failed to create sink input."); + pa_log("failed to create sink input."); goto fail; } @@ -338,7 +338,7 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in pa_rtp_context_init_recv(&s->rtp_context, fd, pa_frame_size(&s->sdp_info.sample_spec)); - pa_log_info(__FILE__": Found new session '%s'", s->sdp_info.session_name); + pa_log_info("Found new session '%s'", s->sdp_info.session_name); u->n_sessions++; @@ -358,7 +358,7 @@ fail: static void session_free(struct session *s, int from_hash) { assert(s); - pa_log_info(__FILE__": Freeing session '%s'", s->sdp_info.session_name); + pa_log_info("Freeing session '%s'", s->sdp_info.session_name); s->userdata->core->mainloop->time_free(s->death_event); s->userdata->core->mainloop->io_free(s->rtp_event); @@ -435,7 +435,7 @@ int pa__init(pa_core *c, pa_module*m) { assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments"); + pa_log("failed to parse module arguments"); goto fail; } @@ -452,7 +452,7 @@ int pa__init(pa_core *c, pa_module*m) { sa = (struct sockaddr*) &sa4; salen = sizeof(sa4); } else { - pa_log(__FILE__": invalid SAP address '%s'", sap_address); + pa_log("invalid SAP address '%s'", sap_address); goto fail; } diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 1b85c840..61dd0047 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -105,7 +105,7 @@ static void source_output_push(pa_source_output *o, const pa_memchunk *chunk) { u = o->userdata; if (pa_memblockq_push(u->memblockq, chunk) < 0) { - pa_log(__FILE__": Failed to push chunk into memblockq."); + pa_log("Failed to push chunk into memblockq."); return; } @@ -174,17 +174,17 @@ int pa__init(pa_core *c, pa_module*m) { assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments"); + pa_log("failed to parse module arguments"); goto fail; } if (!(s = pa_namereg_get(m->core, pa_modargs_get_value(ma, "source", NULL), PA_NAMEREG_SOURCE, 1))) { - pa_log(__FILE__": source does not exist."); + pa_log("source does not exist."); goto fail; } if (pa_modargs_get_value_boolean(ma, "loop", &loop) < 0) { - pa_log(__FILE__": failed to parse \"loop\" parameter."); + pa_log("failed to parse \"loop\" parameter."); goto fail; } @@ -192,12 +192,12 @@ int pa__init(pa_core *c, pa_module*m) { pa_rtp_sample_spec_fixup(&ss); cm = s->channel_map; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": failed to parse sample specification"); + pa_log("failed to parse sample specification"); goto fail; } if (!pa_rtp_sample_spec_valid(&ss)) { - pa_log(__FILE__": specified sample type not compatible with RTP"); + pa_log("specified sample type not compatible with RTP"); goto fail; } @@ -209,18 +209,18 @@ int pa__init(pa_core *c, pa_module*m) { mtu = (DEFAULT_MTU/pa_frame_size(&ss))*pa_frame_size(&ss); if (pa_modargs_get_value_u32(ma, "mtu", &mtu) < 0 || mtu < 1 || mtu % pa_frame_size(&ss) != 0) { - pa_log(__FILE__": invalid mtu."); + pa_log("invalid mtu."); goto fail; } port = DEFAULT_PORT + ((rand() % 512) << 1); if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) { - pa_log(__FILE__": port= expects a numerical argument between 1 and 65535."); + pa_log("port= expects a numerical argument between 1 and 65535."); goto fail; } if (port & 1) - pa_log_warn(__FILE__": WARNING: port number not even as suggested in RFC3550!"); + pa_log_warn("WARNING: port number not even as suggested in RFC3550!"); dest = pa_modargs_get_value(ma, "destination", DEFAULT_DESTINATION); @@ -235,33 +235,33 @@ int pa__init(pa_core *c, pa_module*m) { sap_sa4 = sa4; sap_sa4.sin_port = htons(SAP_PORT); } else { - pa_log(__FILE__": invalid destination '%s'", dest); + pa_log("invalid destination '%s'", dest); goto fail; } if ((fd = socket(af, SOCK_DGRAM, 0)) < 0) { - pa_log(__FILE__": socket() failed: %s", pa_cstrerror(errno)); + pa_log("socket() failed: %s", pa_cstrerror(errno)); goto fail; } if (connect(fd, af == AF_INET ? (struct sockaddr*) &sa4 : (struct sockaddr*) &sa6, af == AF_INET ? sizeof(sa4) : sizeof(sa6)) < 0) { - pa_log(__FILE__": connect() failed: %s", pa_cstrerror(errno)); + pa_log("connect() failed: %s", pa_cstrerror(errno)); goto fail; } if ((sap_fd = socket(af, SOCK_DGRAM, 0)) < 0) { - pa_log(__FILE__": socket() failed: %s", pa_cstrerror(errno)); + pa_log("socket() failed: %s", pa_cstrerror(errno)); goto fail; } if (connect(sap_fd, af == AF_INET ? (struct sockaddr*) &sap_sa4 : (struct sockaddr*) &sap_sa6, af == AF_INET ? sizeof(sap_sa4) : sizeof(sap_sa6)) < 0) { - pa_log(__FILE__": connect() failed: %s", pa_cstrerror(errno)); + pa_log("connect() failed: %s", pa_cstrerror(errno)); goto fail; } if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0 || setsockopt(sap_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) { - pa_log(__FILE__": IP_MULTICAST_LOOP failed: %s", pa_cstrerror(errno)); + pa_log("IP_MULTICAST_LOOP failed: %s", pa_cstrerror(errno)); goto fail; } @@ -274,7 +274,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_source_output_new_data_set_channel_map(&data, &cm); if (!(o = pa_source_output_new(c, &data, 0))) { - pa_log(__FILE__": failed to create source output."); + pa_log("failed to create source output."); goto fail; } @@ -317,8 +317,8 @@ int pa__init(pa_core *c, pa_module*m) { pa_rtp_context_init_send(&u->rtp_context, fd, c->cookie, payload, pa_frame_size(&ss)); pa_sap_context_init_send(&u->sap_context, sap_fd, p); - pa_log_info(__FILE__": RTP stream initialized with mtu %u on %s:%u, SSRC=0x%08x, payload=%u, initial sequence #%u", mtu, dest, port, u->rtp_context.ssrc, payload, u->rtp_context.sequence); - pa_log_info(__FILE__": SDP-Data:\n%s\n"__FILE__": EOF", p); + pa_log_info("RTP stream initialized with mtu %u on %s:%u, SSRC=0x%08x, payload=%u, initial sequence #%u", mtu, dest, port, u->rtp_context.ssrc, payload, u->rtp_context.sequence); + pa_log_info("SDP-Data:\n%s\n"__FILE__": EOF", p); pa_sap_send(&u->sap_context, 0); diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c index 8e77c60a..3bb0ea47 100644 --- a/src/modules/rtp/rtp.c +++ b/src/modules/rtp/rtp.c @@ -125,7 +125,7 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { if (k < 0) { if (errno != EAGAIN) /* If the queue is full, just ignore it */ - pa_log(__FILE__": sendmsg() failed: %s", pa_cstrerror(errno)); + pa_log("sendmsg() failed: %s", pa_cstrerror(errno)); return -1; } @@ -163,7 +163,7 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { chunk->memblock = NULL; if (ioctl(c->fd, FIONREAD, &size) < 0) { - pa_log(__FILE__": FIONREAD failed: %s", pa_cstrerror(errno)); + pa_log("FIONREAD failed: %s", pa_cstrerror(errno)); goto fail; } @@ -184,12 +184,12 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { m.msg_flags = 0; if ((r = recvmsg(c->fd, &m, 0)) != size) { - pa_log(__FILE__": recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch"); + pa_log("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch"); goto fail; } if (size < 12) { - pa_log(__FILE__": RTP packet too short."); + pa_log("RTP packet too short."); goto fail; } @@ -202,17 +202,17 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { c->ssrc = ntohl(c->ssrc); if ((header >> 30) != 2) { - pa_log(__FILE__": Unsupported RTP version."); + pa_log("Unsupported RTP version."); goto fail; } if ((header >> 29) & 1) { - pa_log(__FILE__": RTP padding not supported."); + pa_log("RTP padding not supported."); goto fail; } if ((header >> 28) & 1) { - pa_log(__FILE__": RTP header extensions not supported."); + pa_log("RTP header extensions not supported."); goto fail; } @@ -221,7 +221,7 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { c->sequence = header & 0xFFFF; if (12 + cc*4 > size) { - pa_log(__FILE__": RTP packet too short. (CSRC)"); + pa_log("RTP packet too short. (CSRC)"); goto fail; } @@ -229,7 +229,7 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { chunk->length = size - chunk->index; if (chunk->length % c->frame_size != 0) { - pa_log(__FILE__": Vad RTP packet size."); + pa_log("Vad RTP packet size."); goto fail; } diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c index 615b8e4e..022c7fa3 100644 --- a/src/modules/rtp/sap.c +++ b/src/modules/rtp/sap.c @@ -138,7 +138,7 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) { assert(goodbye); if (ioctl(c->fd, FIONREAD, &size) < 0) { - pa_log(__FILE__": FIONREAD failed: %s", pa_cstrerror(errno)); + pa_log("FIONREAD failed: %s", pa_cstrerror(errno)); goto fail; } @@ -160,12 +160,12 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) { m.msg_flags = 0; if ((r = recvmsg(c->fd, &m, 0)) != size) { - pa_log(__FILE__": recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch"); + pa_log("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch"); goto fail; } if (size < 4) { - pa_log(__FILE__": SAP packet too short."); + pa_log("SAP packet too short."); goto fail; } @@ -173,17 +173,17 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) { header = ntohl(header); if (header >> 29 != 1) { - pa_log(__FILE__": Unsupported SAP version."); + pa_log("Unsupported SAP version."); goto fail; } if ((header >> 25) & 1) { - pa_log(__FILE__": Encrypted SAP not supported."); + pa_log("Encrypted SAP not supported."); goto fail; } if ((header >> 24) & 1) { - pa_log(__FILE__": Compressed SAP not supported."); + pa_log("Compressed SAP not supported."); goto fail; } @@ -192,7 +192,7 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) { k = 4 + (six ? 16 : 4) + ac*4; if (size < k) { - pa_log(__FILE__": SAP packet too short (AD)."); + pa_log("SAP packet too short (AD)."); goto fail; } @@ -203,7 +203,7 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) { e += sizeof(MIME_TYPE); size -= sizeof(MIME_TYPE); } else if ((unsigned) size < sizeof(PA_SDP_HEADER)-1 || strncmp(e, PA_SDP_HEADER, sizeof(PA_SDP_HEADER)-1)) { - pa_log(__FILE__": Invalid SDP header."); + pa_log("Invalid SDP header."); goto fail; } diff --git a/src/modules/rtp/sdp.c b/src/modules/rtp/sdp.c index e707e4bb..1b71a9a0 100644 --- a/src/modules/rtp/sdp.c +++ b/src/modules/rtp/sdp.c @@ -129,7 +129,7 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { i->payload = 255; if (!pa_startswith(t, PA_SDP_HEADER)) { - pa_log(__FILE__": Failed to parse SDP data: invalid header."); + pa_log("Failed to parse SDP data: invalid header."); goto fail; } @@ -141,7 +141,7 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { l = strcspn(t, "\n"); if (l <= 2) { - pa_log(__FILE__": Failed to parse SDP data: line too short: >%s<.", t); + pa_log("Failed to parse SDP data: line too short: >%s<.", t); goto fail; } @@ -159,7 +159,7 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { a[strcspn(a, "/")] = 0; if (inet_pton(AF_INET, a, &((struct sockaddr_in*) &i->sa)->sin_addr) <= 0) { - pa_log(__FILE__": Failed to parse SDP data: bad address: >%s<.", a); + pa_log("Failed to parse SDP data: bad address: >%s<.", a); goto fail; } @@ -176,7 +176,7 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { a[strcspn(a, "/")] = 0; if (inet_pton(AF_INET6, a, &((struct sockaddr_in6*) &i->sa)->sin6_addr) <= 0) { - pa_log(__FILE__": Failed to parse SDP data: bad address: >%s<.", a); + pa_log("Failed to parse SDP data: bad address: >%s<.", a); goto fail; } @@ -191,12 +191,12 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { if (sscanf(t+8, "%i RTP/AVP %i", &_port, &_payload) == 2) { if (_port <= 0 || _port > 0xFFFF) { - pa_log(__FILE__": Failed to parse SDP data: invalid port %i.", _port); + pa_log("Failed to parse SDP data: invalid port %i.", _port); goto fail; } if (_payload < 0 || _payload > 127) { - pa_log(__FILE__": Failed to parse SDP data: invalid payload %i.", _payload); + pa_log("Failed to parse SDP data: invalid payload %i.", _payload); goto fail; } @@ -216,7 +216,7 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { if (sscanf(t+9, "%i %64c", &_payload, c) == 2) { if (_payload < 0 || _payload > 127) { - pa_log(__FILE__": Failed to parse SDP data: invalid payload %i.", _payload); + pa_log("Failed to parse SDP data: invalid payload %i.", _payload); goto fail; } if (_payload == i->payload) { @@ -237,7 +237,7 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { } if (!i->origin || (!is_goodbye && (!i->salen || i->payload > 127 || !ss_valid || port == 0))) { - pa_log(__FILE__": Failed to parse SDP data: missing data."); + pa_log("Failed to parse SDP data: missing data."); goto fail; } diff --git a/src/pulse/client-conf-x11.c b/src/pulse/client-conf-x11.c index e4a90017..8cedc48b 100644 --- a/src/pulse/client-conf-x11.c +++ b/src/pulse/client-conf-x11.c @@ -46,7 +46,7 @@ int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) { goto finish; if (!(d = XOpenDisplay(dname))) { - pa_log(__FILE__": XOpenDisplay() failed"); + pa_log("XOpenDisplay() failed"); goto finish; } @@ -69,7 +69,7 @@ int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) { uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; if (pa_parsehex(t, cookie, sizeof(cookie)) != sizeof(cookie)) { - pa_log(__FILE__": failed to parse cookie data"); + pa_log("failed to parse cookie data"); goto finish; } diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c index c3f58ec2..619b11c3 100644 --- a/src/pulse/client-conf.c +++ b/src/pulse/client-conf.c @@ -116,7 +116,7 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) { pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn, "r"); if (!f && errno != EINTR) { - pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", fn, pa_cstrerror(errno)); + pa_log("WARNING: failed to open configuration file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } diff --git a/src/pulse/context.c b/src/pulse/context.c index b3530542..df627ee6 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -462,7 +462,7 @@ static int context_connect_spawn(pa_context *c) { pa_context_ref(c); if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { - pa_log(__FILE__": socketpair(): %s", pa_cstrerror(errno)); + pa_log("socketpair(): %s", pa_cstrerror(errno)); pa_context_fail(c, PA_ERR_INTERNAL); goto fail; } @@ -476,7 +476,7 @@ static int context_connect_spawn(pa_context *c) { c->spawn_api.prefork(); if ((pid = fork()) < 0) { - pa_log(__FILE__": fork(): %s", pa_cstrerror(errno)); + pa_log("fork(): %s", pa_cstrerror(errno)); pa_context_fail(c, PA_ERR_INTERNAL); if (c->spawn_api.postfork) @@ -532,7 +532,7 @@ static int context_connect_spawn(pa_context *c) { c->spawn_api.postfork(); if (r < 0) { - pa_log(__FILE__": waitpid(): %s", pa_cstrerror(errno)); + pa_log("waitpid(): %s", pa_cstrerror(errno)); pa_context_fail(c, PA_ERR_INTERNAL); goto fail; } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { @@ -594,7 +594,7 @@ static int try_next_connection(pa_context *c) { goto finish; } - pa_log_debug(__FILE__": Trying to connect to %s...", u); + pa_log_debug("Trying to connect to %s...", u); pa_xfree(c->server); c->server = pa_xstrdup(u); diff --git a/src/pulse/mainloop-signal.c b/src/pulse/mainloop-signal.c index 11a27cd5..d651462b 100644 --- a/src/pulse/mainloop-signal.c +++ b/src/pulse/mainloop-signal.c @@ -90,12 +90,12 @@ static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags if (errno == EAGAIN) return; - pa_log(__FILE__": read(): %s", pa_cstrerror(errno)); + pa_log("read(): %s", pa_cstrerror(errno)); return; } if (r != sizeof(sig)) { - pa_log(__FILE__": short read()"); + pa_log("short read()"); return; } @@ -107,7 +107,7 @@ int pa_signal_init(pa_mainloop_api *a) { assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event); if (pipe(signal_pipe) < 0) { - pa_log(__FILE__": pipe(): %s", pa_cstrerror(errno)); + pa_log("pipe(): %s", pa_cstrerror(errno)); return -1; } diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c index 5ebb9bc8..f7b15537 100644 --- a/src/pulse/mainloop.c +++ b/src/pulse/mainloop.c @@ -192,7 +192,7 @@ static pa_io_event* mainloop_io_new( if ((select((SELECT_TYPE_ARG1) fd, NULL, NULL, SELECT_TYPE_ARG234 &xset, SELECT_TYPE_ARG5 &tv) == -1) && (WSAGetLastError() == WSAENOTSOCK)) { - pa_log_warn(__FILE__": WARNING: cannot monitor non-socket file descriptors."); + pa_log_warn("WARNING: cannot monitor non-socket file descriptors."); e->dead = 1; } } @@ -448,7 +448,7 @@ pa_mainloop *pa_mainloop_new(void) { m->wakeup_pipe_type = 0; if (pipe(m->wakeup_pipe) < 0) { - pa_log_error(__FILE__": ERROR: cannot create wakeup pipe"); + pa_log_error("ERROR: cannot create wakeup pipe"); pa_xfree(m); return NULL; } @@ -852,7 +852,7 @@ int pa_mainloop_poll(pa_mainloop *m) { if (errno == EINTR) m->poll_func_ret = 0; else - pa_log(__FILE__": poll(): %s", pa_cstrerror(errno)); + pa_log("poll(): %s", pa_cstrerror(errno)); } } diff --git a/src/pulse/thread-mainloop.c b/src/pulse/thread-mainloop.c index 34f0f250..b1b180a0 100644 --- a/src/pulse/thread-mainloop.c +++ b/src/pulse/thread-mainloop.c @@ -421,7 +421,7 @@ pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) { #else /* defined(OS_IS_WIN32) || defined(HAVE_PTHREAD) */ pa_threaded_mainloop *pa_threaded_mainloop_new(void) { - pa_log_error(__FILE__": Threaded main loop not supported on this platform"); + pa_log_error("Threaded main loop not supported on this platform"); return NULL; } diff --git a/src/pulse/util.c b/src/pulse/util.c index b041fec8..c13951da 100644 --- a/src/pulse/util.c +++ b/src/pulse/util.c @@ -112,7 +112,7 @@ char *pa_get_user_name(char *s, size_t l) { char *pa_get_host_name(char *s, size_t l) { assert(s && l > 0); if (gethostname(s, l) < 0) { - pa_log(__FILE__": gethostname(): %s", pa_cstrerror(errno)); + pa_log("gethostname(): %s", pa_cstrerror(errno)); return NULL; } s[l-1] = 0; @@ -138,12 +138,12 @@ char *pa_get_home_dir(char *s, size_t l) { #ifdef HAVE_PWD_H #ifdef HAVE_GETPWUID_R if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { - pa_log(__FILE__": getpwuid_r() failed"); + pa_log("getpwuid_r() failed"); #else /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) * that do not support getpwuid_r. */ if ((r = getpwuid(getuid())) == NULL) { - pa_log(__FILE__": getpwuid_r() failed"); + pa_log("getpwuid_r() failed"); #endif return NULL; } diff --git a/src/pulsecore/authkey.c b/src/pulsecore/authkey.c index a5df3ed1..87631ca5 100644 --- a/src/pulsecore/authkey.c +++ b/src/pulsecore/authkey.c @@ -54,7 +54,7 @@ static int generate(int fd, void *ret_data, size_t length) { ftruncate(fd, 0); if ((r = pa_loop_write(fd, ret_data, length, NULL)) < 0 || (size_t) r != length) { - pa_log(__FILE__": failed to write cookie file: %s", pa_cstrerror(errno)); + pa_log("failed to write cookie file: %s", pa_cstrerror(errno)); return -1; } @@ -76,7 +76,7 @@ static int load(const char *fn, void *data, size_t length) { if ((fd = open(fn, O_RDWR|O_CREAT|O_BINARY, S_IRUSR|S_IWUSR)) < 0) { if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY)) < 0) { - pa_log(__FILE__": failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); + pa_log("failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } else writable = 0; @@ -85,15 +85,15 @@ static int load(const char *fn, void *data, size_t length) { unlock = pa_lock_fd(fd, 1) >= 0; if ((r = pa_loop_read(fd, data, length, NULL)) < 0) { - pa_log(__FILE__": failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); + pa_log("failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } if ((size_t) r != length) { - pa_log_debug(__FILE__": got %d bytes from cookie file '%s', expected %d", (int)r, fn, (int)length); + pa_log_debug("got %d bytes from cookie file '%s', expected %d", (int)r, fn, (int)length); if (!writable) { - pa_log(__FILE__": unable to write cookie to read only file"); + pa_log("unable to write cookie to read only file"); goto finish; } @@ -125,7 +125,7 @@ int pa_authkey_load(const char *path, void *data, size_t length) { ret = load(path, data, length); if (ret < 0) - pa_log(__FILE__": Failed to load authorization key '%s': %s", path, + pa_log("Failed to load authorization key '%s': %s", path, (ret == -1) ? pa_cstrerror(errno) : "file corrupt"); return ret; @@ -182,14 +182,14 @@ int pa_authkey_save(const char *fn, const void *data, size_t length) { return -2; if ((fd = open(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { - pa_log(__FILE__": failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); + pa_log("failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } unlock = pa_lock_fd(fd, 1) >= 0; if ((r = pa_loop_write(fd, data, length, NULL)) < 0 || (size_t) r != length) { - pa_log(__FILE__": failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); + pa_log("failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } diff --git a/src/pulsecore/cli.c b/src/pulsecore/cli.c index 7c284066..e3fc2e4c 100644 --- a/src/pulsecore/cli.c +++ b/src/pulsecore/cli.c @@ -104,7 +104,7 @@ static void client_kill(pa_client *client) { assert(client && client->userdata); c = client->userdata; - pa_log_debug(__FILE__": CLI client killed."); + pa_log_debug("CLI client killed."); if (c->defer_kill) c->kill_requested = 1; else { @@ -120,7 +120,7 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) { assert(line && c); if (!s) { - pa_log_debug(__FILE__": CLI got EOF from user."); + pa_log_debug("CLI got EOF from user."); if (c->eof_callback) c->eof_callback(c, c->userdata); diff --git a/src/pulsecore/client.c b/src/pulsecore/client.c index bf2b13df..c34bf149 100644 --- a/src/pulsecore/client.c +++ b/src/pulsecore/client.c @@ -52,7 +52,7 @@ pa_client *pa_client_new(pa_core *core, const char *driver, const char *name) { r = pa_idxset_put(core->clients, c, &c->index); assert(c->index != PA_IDXSET_INVALID && r >= 0); - pa_log_info(__FILE__": created %u \"%s\"", c->index, c->name); + pa_log_info("created %u \"%s\"", c->index, c->name); pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index); pa_core_check_quit(core); @@ -67,7 +67,7 @@ void pa_client_free(pa_client *c) { pa_core_check_quit(c->core); - pa_log_info(__FILE__": freed %u \"%s\"", c->index, c->name); + pa_log_info("freed %u \"%s\"", c->index, c->name); pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index); pa_xfree(c->name); pa_xfree(c->driver); @@ -77,7 +77,7 @@ void pa_client_free(pa_client *c) { void pa_client_kill(pa_client *c) { assert(c); if (!c->kill) { - pa_log_warn(__FILE__": kill() operation not implemented for client %u", c->index); + pa_log_warn("kill() operation not implemented for client %u", c->index); return; } @@ -87,7 +87,7 @@ void pa_client_kill(pa_client *c) { void pa_client_set_name(pa_client *c, const char *name) { assert(c); - pa_log_info(__FILE__": client %u changed name from \"%s\" to \"%s\"", c->index, c->name, name); + pa_log_info("client %u changed name from \"%s\" to \"%s\"", c->index, c->name, name); pa_xfree(c->name); c->name = pa_xstrdup(name); diff --git a/src/pulsecore/conf-parser.c b/src/pulsecore/conf-parser.c index cc471ff9..db1e3719 100644 --- a/src/pulsecore/conf-parser.c +++ b/src/pulsecore/conf-parser.c @@ -47,7 +47,7 @@ static int next_assignment(const char *filename, unsigned line, const pa_config_ if (!strcmp(lvalue, t->lvalue)) return t->parse(filename, line, lvalue, rvalue, t->data, userdata); - pa_log(__FILE__": [%s:%u] Unknown lvalue '%s'.", filename, line, lvalue); + pa_log("[%s:%u] Unknown lvalue '%s'.", filename, line, lvalue); return -1; } @@ -90,7 +90,7 @@ static int parse_line(const char *filename, unsigned line, const pa_config_item return 0; if (!(e = strchr(b, '='))) { - pa_log(__FILE__": [%s:%u] Missing '='.", filename, line); + pa_log("[%s:%u] Missing '='.", filename, line); return -1; } @@ -113,7 +113,7 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void goto finish; } - pa_log_warn(__FILE__": WARNING: failed to open configuration file '%s': %s", + pa_log_warn("WARNING: failed to open configuration file '%s': %s", filename, pa_cstrerror(errno)); goto finish; } @@ -124,7 +124,7 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void if (feof(f)) break; - pa_log_warn(__FILE__": WARNING: failed to read configuration file '%s': %s", + pa_log_warn("WARNING: failed to read configuration file '%s': %s", filename, pa_cstrerror(errno)); goto finish; } @@ -149,7 +149,7 @@ int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, assert(filename && lvalue && rvalue && data); if (pa_atoi(rvalue, &k) < 0) { - pa_log(__FILE__": [%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); + pa_log("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); return -1; } @@ -162,7 +162,7 @@ int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue assert(filename && lvalue && rvalue && data); if ((k = pa_parse_boolean(rvalue)) < 0) { - pa_log(__FILE__": [%s:%u] Failed to parse boolean value: %s", filename, line, rvalue); + pa_log("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue); return -1; } diff --git a/src/pulsecore/core-scache.c b/src/pulsecore/core-scache.c index ca2408fe..e3bf3ca2 100644 --- a/src/pulsecore/core-scache.c +++ b/src/pulsecore/core-scache.c @@ -360,7 +360,7 @@ static void add_file(pa_core *c, const char *pathname) { e = pa_path_get_filename(pathname); if (stat(pathname, &st) < 0) { - pa_log(__FILE__": stat('%s'): %s", pathname, pa_cstrerror(errno)); + pa_log("stat('%s'): %s", pathname, pa_cstrerror(errno)); return; } @@ -382,7 +382,7 @@ int pa_scache_add_directory_lazy(pa_core *c, const char *pathname) { /* If that fails, try to open it as shell glob */ if (glob(pathname, GLOB_ERR|GLOB_NOSORT, NULL, &p) < 0) { - pa_log(__FILE__": failed to open directory '%s': %s", pathname, pa_cstrerror(errno)); + pa_log("failed to open directory '%s': %s", pathname, pa_cstrerror(errno)); return -1; } diff --git a/src/pulsecore/core-subscribe.c b/src/pulsecore/core-subscribe.c index 37673da5..4df1d511 100644 --- a/src/pulsecore/core-subscribe.c +++ b/src/pulsecore/core-subscribe.c @@ -145,7 +145,7 @@ static void dump_event(const char * prefix, pa_subscription_event*e) { [PA_SUBSCRIPTION_EVENT_REMOVE] = "REMOVE" }; - pa_log(__FILE__": %s event (%s|%s|%u)", + pa_log("%s event (%s|%s|%u)", prefix, fac_table[e->type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK], type_table[e->type & PA_SUBSCRIPTION_EVENT_TYPE_MASK], @@ -234,7 +234,7 @@ void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t i * entry in the queue. */ free_event(i); - pa_log_debug(__FILE__": dropped redundant event."); + pa_log_debug("dropped redundant event."); continue; } @@ -242,7 +242,7 @@ void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t i /* This object has changed. If a "new" or "change" event for * this object is still in the queue we can exit. */ - pa_log_debug(__FILE__": dropped redundant event."); + pa_log_debug("dropped redundant event."); return; } } diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 595ef939..b504b6d3 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -128,10 +128,10 @@ void pa_make_nonblock_fd(int fd) { u_long arg = 1; if (ioctlsocket(fd, FIONBIO, &arg) < 0) { if (WSAGetLastError() == WSAENOTSOCK) - pa_log_warn(__FILE__": WARNING: Only sockets can be made non-blocking!"); + pa_log_warn("WARNING: Only sockets can be made non-blocking!"); } #else - pa_log_warn(__FILE__": WARNING: Non-blocking I/O not supported.!"); + pa_log_warn("WARNING: Non-blocking I/O not supported.!"); #endif } @@ -359,7 +359,7 @@ void pa_check_signal_is_blocked(int sig) { if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) { #endif if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) { - pa_log(__FILE__": sigprocmask(): %s", pa_cstrerror(errno)); + pa_log("sigprocmask(): %s", pa_cstrerror(errno)); return; } #ifdef HAVE_PTHREAD @@ -372,16 +372,16 @@ void pa_check_signal_is_blocked(int sig) { /* Check whether the signal is trapped */ if (sigaction(sig, NULL, &sa) < 0) { - pa_log(__FILE__": sigaction(): %s", pa_cstrerror(errno)); + pa_log("sigaction(): %s", pa_cstrerror(errno)); return; } if (sa.sa_handler != SIG_DFL) return; - pa_log(__FILE__": WARNING: %s is not trapped. This might cause malfunction!", pa_strsignal(sig)); + pa_log("WARNING: %s is not trapped. This might cause malfunction!", pa_strsignal(sig)); #else /* HAVE_SIGACTION */ - pa_log(__FILE__": WARNING: %s might not be trapped. This might cause malfunction!", pa_strsignal(sig)); + pa_log("WARNING: %s might not be trapped. This might cause malfunction!", pa_strsignal(sig)); #endif } @@ -460,9 +460,9 @@ void pa_raise_priority(void) { #ifdef HAVE_SYS_RESOURCE_H if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) - pa_log_warn(__FILE__": setpriority(): %s", pa_cstrerror(errno)); + pa_log_warn("setpriority(): %s", pa_cstrerror(errno)); else - pa_log_info(__FILE__": Successfully gained nice level %i.", NICE_LEVEL); + pa_log_info("Successfully gained nice level %i.", NICE_LEVEL); #endif #ifdef _POSIX_PRIORITY_SCHEDULING @@ -470,25 +470,25 @@ void pa_raise_priority(void) { struct sched_param sp; if (sched_getparam(0, &sp) < 0) { - pa_log(__FILE__": sched_getparam(): %s", pa_cstrerror(errno)); + pa_log("sched_getparam(): %s", pa_cstrerror(errno)); return; } sp.sched_priority = 1; if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) { - pa_log_warn(__FILE__": sched_setscheduler(): %s", pa_cstrerror(errno)); + pa_log_warn("sched_setscheduler(): %s", pa_cstrerror(errno)); return; } - pa_log_info(__FILE__": Successfully enabled SCHED_FIFO scheduling."); + pa_log_info("Successfully enabled SCHED_FIFO scheduling."); } #endif #ifdef OS_IS_WIN32 if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) - pa_log_warn(__FILE__": SetPriorityClass() failed: 0x%08X", GetLastError()); + pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError()); else - pa_log_info(__FILE__": Successfully gained high priority class."); + pa_log_info("Successfully gained high priority class."); #endif } @@ -627,7 +627,7 @@ static int is_group(gid_t gid, const char *name) { data = pa_xmalloc(n); if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) { - pa_log(__FILE__": getgrgid_r(%u): %s", (unsigned)gid, pa_cstrerror(errno)); + pa_log("getgrgid_r(%u): %s", (unsigned)gid, pa_cstrerror(errno)); goto finish; } @@ -639,7 +639,7 @@ finish: /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not * support getgrgid_r. */ if ((result = getgrgid(gid)) == NULL) { - pa_log(__FILE__": getgrgid(%u): %s", gid, pa_cstrerror(errno)); + pa_log("getgrgid(%u): %s", gid, pa_cstrerror(errno)); goto finish; } @@ -662,7 +662,7 @@ int pa_own_uid_in_group(const char *name, gid_t *gid) { gids = pa_xmalloc(sizeof(GETGROUPS_T)*n); if ((n = getgroups(n, gids)) < 0) { - pa_log(__FILE__": getgroups(): %s", pa_cstrerror(errno)); + pa_log("getgroups(): %s", pa_cstrerror(errno)); goto finish; } @@ -803,7 +803,7 @@ int pa_lock_fd(int fd, int b) { return 0; } - pa_log(__FILE__": %slock: %s", !b? "un" : "", + pa_log("%slock: %s", !b? "un" : "", pa_cstrerror(errno)); #endif @@ -815,7 +815,7 @@ int pa_lock_fd(int fd, int b) { if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) return 0; - pa_log(__FILE__": %slock failed: 0x%08X", !b ? "un" : "", GetLastError()); + pa_log("%slock failed: 0x%08X", !b ? "un" : "", GetLastError()); #endif return -1; @@ -838,18 +838,18 @@ int pa_lock_lockfile(const char *fn) { struct stat st; if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { - pa_log(__FILE__": failed to create lock file '%s': %s", fn, + pa_log("failed to create lock file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } if (pa_lock_fd(fd, 1) < 0) { - pa_log(__FILE__": failed to lock file '%s'.", fn); + pa_log("failed to lock file '%s'.", fn); goto fail; } if (fstat(fd, &st) < 0) { - pa_log(__FILE__": failed to fstat() file '%s'.", fn); + pa_log("failed to fstat() file '%s'.", fn); goto fail; } @@ -858,12 +858,12 @@ int pa_lock_lockfile(const char *fn) { break; if (pa_lock_fd(fd, 0) < 0) { - pa_log(__FILE__": failed to unlock file '%s'.", fn); + pa_log("failed to unlock file '%s'.", fn); goto fail; } if (close(fd) < 0) { - pa_log(__FILE__": failed to close file '%s'.", fn); + pa_log("failed to close file '%s'.", fn); goto fail; } @@ -886,18 +886,18 @@ int pa_unlock_lockfile(const char *fn, int fd) { assert(fn && fd >= 0); if (unlink(fn) < 0) { - pa_log_warn(__FILE__": WARNING: unable to remove lock file '%s': %s", + pa_log_warn("WARNING: unable to remove lock file '%s': %s", fn, pa_cstrerror(errno)); r = -1; } if (pa_lock_fd(fd, 0) < 0) { - pa_log_warn(__FILE__": WARNING: failed to unlock file '%s'.", fn); + pa_log_warn("WARNING: failed to unlock file '%s'.", fn); r = -1; } if (close(fd) < 0) { - pa_log_warn(__FILE__": WARNING: failed to close lock file '%s': %s", + pa_log_warn("WARNING: failed to close lock file '%s': %s", fn, pa_cstrerror(errno)); r = -1; } diff --git a/src/pulsecore/ioline.c b/src/pulsecore/ioline.c index 9c9900f8..a3bca22f 100644 --- a/src/pulsecore/ioline.c +++ b/src/pulsecore/ioline.c @@ -292,7 +292,7 @@ static int do_read(pa_ioline *l) { /* Read some data */ if ((r = pa_iochannel_read(l->io, l->rbuf+l->rbuf_index+l->rbuf_valid_length, len)) <= 0) { if (r < 0) { - pa_log(__FILE__": read(): %s", pa_cstrerror(errno)); + pa_log("read(): %s", pa_cstrerror(errno)); failure(l, 0); } else failure(l, 1); @@ -317,7 +317,7 @@ static int do_write(pa_ioline *l) { while (!l->dead && pa_iochannel_is_writable(l->io) && l->wbuf_valid_length) { if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0) { - pa_log(__FILE__": write(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + pa_log("write(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); failure(l, 0); return -1; } diff --git a/src/pulsecore/ipacl.c b/src/pulsecore/ipacl.c index 15b6b3f9..36159fab 100644 --- a/src/pulsecore/ipacl.c +++ b/src/pulsecore/ipacl.c @@ -88,7 +88,7 @@ pa_ip_acl* pa_ip_acl_new(const char *s) { *slash = 0; slash++; if (pa_atou(slash, &bits) < 0) { - pa_log(__FILE__": failed to parse number of bits: %s", slash); + pa_log("failed to parse number of bits: %s", slash); goto fail; } } else @@ -99,21 +99,21 @@ pa_ip_acl* pa_ip_acl_new(const char *s) { e.bits = bits == (uint32_t) -1 ? 32 : (int) bits; if (e.bits > 32) { - pa_log(__FILE__": number of bits out of range: %i", e.bits); + pa_log("number of bits out of range: %i", e.bits); goto fail; } e.family = AF_INET; if (e.bits < 32 && (uint32_t) (ntohl(e.address_ipv4.s_addr) << e.bits) != 0) - pa_log_warn(__FILE__": WARNING: Host part of ACL entry '%s/%u' is not zero!", a, e.bits); + pa_log_warn("WARNING: Host part of ACL entry '%s/%u' is not zero!", a, e.bits); } else if (inet_pton(AF_INET6, a, &e.address_ipv6) > 0) { e.bits = bits == (uint32_t) -1 ? 128 : (int) bits; if (e.bits > 128) { - pa_log(__FILE__": number of bits out of range: %i", e.bits); + pa_log("number of bits out of range: %i", e.bits); goto fail; } e.family = AF_INET6; @@ -135,11 +135,11 @@ pa_ip_acl* pa_ip_acl_new(const char *s) { } if (t) - pa_log_warn(__FILE__": WARNING: Host part of ACL entry '%s/%u' is not zero!", a, e.bits); + pa_log_warn("WARNING: Host part of ACL entry '%s/%u' is not zero!", a, e.bits); } } else { - pa_log(__FILE__": failed to parse address: %s", a); + pa_log("failed to parse address: %s", a); goto fail; } diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 4ce1b7c1..2109d83c 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -184,7 +184,7 @@ static struct mempool_slot* mempool_allocate_slot(pa_mempool *p) { } else if (p->n_init < p->n_blocks) slot = (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->block_size * p->n_init++)); else { - pa_log_debug(__FILE__": Pool full"); + pa_log_debug("Pool full"); p->stat.n_pool_full++; return NULL; } @@ -241,7 +241,7 @@ pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) { b->type = PA_MEMBLOCK_POOL_EXTERNAL; b->data = mempool_slot_data(slot); } else { - pa_log_debug(__FILE__": Memory block to large for pool: %u > %u", length, p->block_size - sizeof(struct mempool_slot)); + pa_log_debug("Memory block to large for pool: %u > %u", length, p->block_size - sizeof(struct mempool_slot)); p->stat.n_too_large_for_pool++; return NULL; } @@ -464,7 +464,7 @@ void pa_mempool_free(pa_mempool *p) { pa_memexport_free(p->exports); if (p->stat.n_allocated > 0) - pa_log_warn(__FILE__": WARNING! Memory pool destroyed but not all memory blocks freed!"); + pa_log_warn("WARNING! Memory pool destroyed but not all memory blocks freed!"); pa_shm_free(&p->memory); pa_xfree(p); diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index 2fd38850..e6b73fc5 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -74,7 +74,7 @@ pa_memblockq* pa_memblockq_new( bq->base = base; bq->read_index = bq->write_index = idx; - pa_log_debug(__FILE__": memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", + pa_log_debug("memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", (unsigned long)maxlength, (unsigned long)tlength, (unsigned long)base, (unsigned long)prebuf, (unsigned long)minreq); bq->maxlength = ((maxlength+base-1)/base)*base; @@ -97,7 +97,7 @@ pa_memblockq* pa_memblockq_new( if (!bq->minreq) bq->minreq = 1; - pa_log_debug(__FILE__": memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", + pa_log_debug("memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", (unsigned long)bq->maxlength, (unsigned long)bq->tlength, (unsigned long)bq->base, (unsigned long)bq->prebuf, (unsigned long)bq->minreq); bq->state = bq->prebuf ? PREBUF : RUNNING; diff --git a/src/pulsecore/modinfo.c b/src/pulsecore/modinfo.c index adefdb46..00720113 100644 --- a/src/pulsecore/modinfo.c +++ b/src/pulsecore/modinfo.c @@ -73,7 +73,7 @@ pa_modinfo *pa_modinfo_get_by_name(const char *name) { assert(name); if (!(dl = lt_dlopenext(name))) { - pa_log(__FILE__": Failed to open module \"%s\": %s", name, lt_dlerror()); + pa_log("Failed to open module \"%s\": %s", name, lt_dlerror()); return NULL; } diff --git a/src/pulsecore/module.c b/src/pulsecore/module.c index cdf95ada..ea3d726e 100644 --- a/src/pulsecore/module.c +++ b/src/pulsecore/module.c @@ -112,17 +112,17 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { m->argument = pa_xstrdup(argument); if (!(m->dl = lt_dlopenext(name))) { - pa_log(__FILE__": Failed to open module \"%s\": %s", name, lt_dlerror()); + pa_log("Failed to open module \"%s\": %s", name, lt_dlerror()); goto fail; } if (!(m->init = (int (*)(pa_core *_c, pa_module*_m)) load_sym(m->dl, name, PA_SYMBOL_INIT))) { - pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.", name); + pa_log("Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.", name); goto fail; } if (!(m->done = (void (*)(pa_core *_c, pa_module*_m)) load_sym(m->dl, name, PA_SYMBOL_DONE))) { - pa_log(__FILE__": Failed to load module \"%s\": symbol \""PA_SYMBOL_DONE"\" not found.", name); + pa_log("Failed to load module \"%s\": symbol \""PA_SYMBOL_DONE"\" not found.", name); goto fail; } @@ -134,7 +134,7 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { assert(m->init); if (m->init(c, m) < 0) { - pa_log_error(__FILE__": Failed to load module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : ""); + pa_log_error("Failed to load module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : ""); goto fail; } @@ -153,7 +153,7 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { r = pa_idxset_put(c->modules, m, &m->index); assert(r >= 0 && m->index != PA_IDXSET_INVALID); - pa_log_info(__FILE__": Loaded \"%s\" (index: #%u; argument: \"%s\").", m->name, m->index, m->argument ? m->argument : ""); + pa_log_info("Loaded \"%s\" (index: #%u; argument: \"%s\").", m->name, m->index, m->argument ? m->argument : ""); pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_NEW, m->index); @@ -180,13 +180,13 @@ static void pa_module_free(pa_module *m) { if (m->core->disallow_module_loading) return; - pa_log_info(__FILE__": Unloading \"%s\" (index: #%u).", m->name, m->index); + pa_log_info("Unloading \"%s\" (index: #%u).", m->name, m->index); m->done(m->core, m); lt_dlclose(m->dl); - pa_log_info(__FILE__": Unloaded \"%s\" (index: #%u).", m->name, m->index); + pa_log_info("Unloaded \"%s\" (index: #%u).", m->name, m->index); pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_REMOVE, m->index); diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c index e1653d64..6ecf710a 100644 --- a/src/pulsecore/pdispatch.c +++ b/src/pulsecore/pdispatch.c @@ -205,7 +205,7 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds, if (!(p = command_names[command])) snprintf((char*) (p = t), sizeof(t), "%u", command); - pa_log(__FILE__": Recieved opcode <%s>", p); + pa_log("Recieved opcode <%s>", p); } #endif @@ -226,7 +226,7 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds, (*c)(pd, command, tag, ts, userdata); } else { - pa_log(__FILE__": Recieved unsupported command %u", command); + pa_log("Recieved unsupported command %u", command); goto finish; } diff --git a/src/pulsecore/pid.c b/src/pulsecore/pid.c index 044d223d..6e0c085e 100644 --- a/src/pulsecore/pid.c +++ b/src/pulsecore/pid.c @@ -57,7 +57,7 @@ static pid_t read_pid(const char *fn, int fd) { assert(fn && fd >= 0); if ((r = pa_loop_read(fd, t, sizeof(t)-1, NULL)) < 0) { - pa_log_warn(__FILE__": WARNING: failed to read PID file '%s': %s", + pa_log_warn("WARNING: failed to read PID file '%s': %s", fn, pa_cstrerror(errno)); return (pid_t) -1; } @@ -70,7 +70,7 @@ static pid_t read_pid(const char *fn, int fd) { *e = 0; if (pa_atou(t, &pid) < 0) { - pa_log(__FILE__": WARNING: failed to parse PID file '%s'", fn); + pa_log("WARNING: failed to parse PID file '%s'", fn); return (pid_t) -1; } @@ -85,7 +85,7 @@ static int open_pid_file(const char *fn, int mode) { if ((fd = open(fn, mode, S_IRUSR|S_IWUSR)) < 0) { if (mode != O_RDONLY || errno != ENOENT) - pa_log_warn(__FILE__": WARNING: failed to open PID file '%s': %s", + pa_log_warn("WARNING: failed to open PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } @@ -95,7 +95,7 @@ static int open_pid_file(const char *fn, int mode) { goto fail; if (fstat(fd, &st) < 0) { - pa_log_warn(__FILE__": WARNING: failed to fstat() PID file '%s': %s", + pa_log_warn("WARNING: failed to fstat() PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } @@ -108,7 +108,7 @@ static int open_pid_file(const char *fn, int mode) { goto fail; if (close(fd) < 0) { - pa_log_warn(__FILE__": WARNING: failed to close file '%s': %s", + pa_log_warn("WARNING: failed to close file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } @@ -147,7 +147,7 @@ int pa_pid_file_create(void) { goto fail; if ((pid = read_pid(fn, fd)) == (pid_t) -1) - pa_log(__FILE__": corrupt PID file, overwriting."); + pa_log("corrupt PID file, overwriting."); else if (pid > 0) { #ifdef OS_IS_WIN32 if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)) != NULL) { @@ -155,16 +155,16 @@ int pa_pid_file_create(void) { #else if (kill(pid, 0) >= 0 || errno != ESRCH) { #endif - pa_log(__FILE__": daemon already running."); + pa_log("daemon already running."); goto fail; } - pa_log(__FILE__": stale PID file, overwriting."); + pa_log("stale PID file, overwriting."); } /* Overwrite the current PID file */ if (lseek(fd, 0, SEEK_SET) == (off_t) -1 || ftruncate(fd, 0) < 0) { - pa_log(__FILE__": failed to truncate PID file '%s': %s", + pa_log("failed to truncate PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } @@ -173,7 +173,7 @@ int pa_pid_file_create(void) { l = strlen(t); if (pa_loop_write(fd, t, l, NULL) != (ssize_t) l) { - pa_log(__FILE__": failed to write PID file."); + pa_log("failed to write PID file."); goto fail; } @@ -198,7 +198,7 @@ int pa_pid_file_remove(void) { pa_runtime_path("pid", fn, sizeof(fn)); if ((fd = open_pid_file(fn, O_RDWR)) < 0) { - pa_log_warn(__FILE__": WARNING: failed to open PID file '%s': %s", + pa_log_warn("WARNING: failed to open PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } @@ -207,12 +207,12 @@ int pa_pid_file_remove(void) { goto fail; if (pid != getpid()) { - pa_log(__FILE__": WARNING: PID file '%s' not mine!", fn); + pa_log("WARNING: PID file '%s' not mine!", fn); goto fail; } if (ftruncate(fd, 0) < 0) { - pa_log_warn(__FILE__": WARNING: failed to truncate PID file '%s': %s", + pa_log_warn("WARNING: failed to truncate PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } @@ -224,7 +224,7 @@ int pa_pid_file_remove(void) { #endif if (unlink(fn) < 0) { - pa_log_warn(__FILE__": WARNING: failed to remove PID file '%s': %s", + pa_log_warn("WARNING: failed to remove PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } diff --git a/src/pulsecore/protocol-cli.c b/src/pulsecore/protocol-cli.c index c5854f1e..81ce5e8f 100644 --- a/src/pulsecore/protocol-cli.c +++ b/src/pulsecore/protocol-cli.c @@ -56,7 +56,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) assert(s && io && p); if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); + pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); pa_iochannel_free(io); return; } diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 2fadeca3..c96a98b9 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -294,7 +294,7 @@ static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t req if (!c->authorized) { if (memcmp(data, c->protocol->esd_key, ESD_KEY_LEN) != 0) { - pa_log(__FILE__": kicked client with invalid authorization key."); + pa_log("kicked client with invalid authorization key."); return -1; } @@ -313,7 +313,7 @@ static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t req else if (ekey == ESD_SWAP_ENDIAN_KEY) c->swap_byte_order = 1; else { - pa_log(__FILE__": client sent invalid endian key"); + pa_log("client sent invalid endian key"); return -1; } @@ -421,19 +421,19 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co pa_sink* sink; if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": no such sink."); + pa_log("no such sink."); return -1; } if (!(source = sink->monitor_source)) { - pa_log(__FILE__": no such monitor source."); + pa_log("no such monitor source."); return -1; } } else { assert(request == ESD_PROTO_STREAM_REC); if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) { - pa_log(__FILE__": no such source."); + pa_log("no such source."); return -1; } } @@ -822,7 +822,7 @@ static int do_read(struct connection *c) { assert(c->read_data_length < sizeof(c->request)); if ((r = pa_iochannel_read(c->io, ((uint8_t*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { - pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } @@ -832,16 +832,16 @@ static int do_read(struct connection *c) { c->request = MAYBE_INT32_SWAP(c->swap_byte_order, c->request); if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) { - pa_log(__FILE__": recieved invalid request."); + pa_log("recieved invalid request."); return -1; } handler = proto_map+c->request; -/* pa_log(__FILE__": executing request #%u", c->request); */ +/* pa_log("executing request #%u", c->request); */ if (!handler->proc) { - pa_log(__FILE__": recieved unimplemented request #%u.", c->request); + pa_log("recieved unimplemented request #%u.", c->request); return -1; } @@ -870,7 +870,7 @@ static int do_read(struct connection *c) { assert(c->read_data && c->read_data_length < handler->data_length); if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { - pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } @@ -890,7 +890,7 @@ static int do_read(struct connection *c) { assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { - pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } @@ -945,7 +945,7 @@ static int do_read(struct connection *c) { } if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { - pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } @@ -975,7 +975,7 @@ static int do_write(struct connection *c) { assert(c->write_data_index < c->write_data_length); if ((r = pa_iochannel_write(c->io, (uint8_t*) c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { - pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); + pa_log("write(): %s", pa_cstrerror(errno)); return -1; } @@ -994,7 +994,7 @@ static int do_write(struct connection *c) { if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { pa_memblock_unref(chunk.memblock); - pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); + pa_log("write(): %s", pa_cstrerror(errno)); return -1; } @@ -1154,7 +1154,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) assert(s && io && p); if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); + pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); pa_iochannel_free(io); return; } @@ -1203,7 +1203,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->original_name = NULL; if (!c->authorized && p->auth_ip_acl && pa_ip_acl_check(p->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) { - pa_log_info(__FILE__": Client authenticated by IP ACL."); + pa_log_info("Client authenticated by IP ACL."); c->authorized = 1; } @@ -1237,7 +1237,7 @@ pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *serve p = pa_xnew(pa_protocol_esound, 1); if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) { - pa_log(__FILE__": auth-anonymous= expects a boolean argument."); + pa_log("auth-anonymous= expects a boolean argument."); goto fail; } @@ -1247,7 +1247,7 @@ pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *serve if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) { if (!(p->auth_ip_acl = pa_ip_acl_new(acl))) { - pa_log(__FILE__": Failed to parse IP ACL '%s'", acl); + pa_log("Failed to parse IP ACL '%s'", acl); goto fail; } } else diff --git a/src/pulsecore/protocol-http.c b/src/pulsecore/protocol-http.c index d0d92629..3b1207f6 100644 --- a/src/pulsecore/protocol-http.c +++ b/src/pulsecore/protocol-http.c @@ -145,7 +145,7 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) { /* We're done */ c->state = DATA; - pa_log_info(__FILE__": request for %s", c->url); + pa_log_info("request for %s", c->url); if (!strcmp(c->url, URL_ROOT)) { char txt[256]; @@ -224,7 +224,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) assert(s && io && p); if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log_warn(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); + pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); pa_iochannel_free(io); return; } diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 2c9b3566..506442f5 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -542,7 +542,7 @@ static void request_bytes(struct playback_stream *s) { pa_tagstruct_putu32(t, l); pa_pstream_send_tagstruct(s->connection->pstream, t); -/* pa_log(__FILE__": Requesting %u bytes", l); */ +/* pa_log("Requesting %u bytes", l); */ } static void send_memblock(struct connection *c) { @@ -620,11 +620,11 @@ static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { } if (pa_memblockq_peek(s->memblockq, chunk) < 0) { -/* pa_log(__FILE__": peek: failure"); */ +/* pa_log("peek: failure"); */ return -1; } -/* pa_log(__FILE__": peek: %u", chunk->length); */ +/* pa_log("peek: %u", chunk->length); */ return 0; } @@ -643,7 +643,7 @@ static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_ s->drain_request = 0; } -/* pa_log(__FILE__": after_drop: %u %u", pa_memblockq_get_length(s->memblockq), pa_memblockq_is_readable(s->memblockq)); */ +/* pa_log("after_drop: %u %u", pa_memblockq_get_length(s->memblockq), pa_memblockq_is_readable(s->memblockq)); */ } static void sink_input_kill_cb(pa_sink_input *i) { @@ -657,7 +657,7 @@ static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { assert(i && i->userdata); s = i->userdata; - /*pa_log(__FILE__": get_latency: %u", pa_memblockq_get_length(s->memblockq));*/ + /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/ return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec); } @@ -670,7 +670,7 @@ static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) s = o->userdata; if (pa_memblockq_push_align(s->memblockq, chunk) < 0) { - pa_log_warn(__FILE__": Failed to push data into output queue."); + pa_log_warn("Failed to push data into output queue."); return; } @@ -689,7 +689,7 @@ static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { assert(o && o->userdata); s = o->userdata; - /*pa_log(__FILE__": get_latency: %u", pa_memblockq_get_length(s->memblockq));*/ + /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/ return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec); } @@ -697,7 +697,7 @@ static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { /*** pdispatch callbacks ***/ static void protocol_error(struct connection *c) { - pa_log(__FILE__": protocol error, kicking client"); + pa_log("protocol error, kicking client"); connection_free(c); } @@ -945,19 +945,19 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t gid_t gid; if ((gid = pa_get_gid_of_group(c->protocol->auth_group)) == (gid_t) -1) - pa_log_warn(__FILE__": failed to get GID of group '%s'", c->protocol->auth_group); + pa_log_warn("failed to get GID of group '%s'", c->protocol->auth_group); else if (gid == creds->gid) success = 1; if (!success) { if ((r = pa_uid_in_group(creds->uid, c->protocol->auth_group)) < 0) - pa_log_warn(__FILE__": failed to check group membership."); + pa_log_warn("failed to check group membership."); else if (r > 0) success = 1; } } - pa_log_info(__FILE__": Got credentials: uid=%lu gid=%lu success=%i", + pa_log_info("Got credentials: uid=%lu gid=%lu success=%i", (unsigned long) creds->uid, (unsigned long) creds->gid, success); @@ -968,7 +968,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t success = 1; if (!success) { - pa_log_warn(__FILE__": Denied access to client with invalid authorization data."); + pa_log_warn("Denied access to client with invalid authorization data."); pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } @@ -2199,7 +2199,7 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_c assert(p && packet && packet->data && c); if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) { - pa_log(__FILE__": invalid packet."); + pa_log("invalid packet."); connection_free(c); } } @@ -2210,7 +2210,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o assert(p && chunk && userdata); if (!(stream = pa_idxset_get_by_index(c->output_streams, channel))) { - pa_log(__FILE__": client sent block for invalid stream."); + pa_log("client sent block for invalid stream."); /* Ignoring */ return; } @@ -2227,7 +2227,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o if (pa_memblockq_push_align(ps->memblockq, chunk) < 0) { pa_tagstruct *t; - pa_log_warn(__FILE__": failed to push data into queue"); + pa_log_warn("failed to push data into queue"); /* Pushing this block into the queue failed, so we simulate * it by skipping ahead */ @@ -2282,7 +2282,7 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { assert(p && c); connection_free(c); -/* pa_log(__FILE__": connection died.");*/ +/* pa_log("connection died.");*/ } @@ -2317,7 +2317,7 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo assert(io && p); if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log_warn(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); + pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); pa_iochannel_free(io); return; } @@ -2327,7 +2327,7 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo c->authorized = !!p->public; if (!c->authorized && p->auth_ip_acl && pa_ip_acl_check(p->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) { - pa_log_info(__FILE__": Client authenticated by IP ACL."); + pa_log_info("Client authenticated by IP ACL."); c->authorized = 1; } @@ -2388,7 +2388,7 @@ static int load_key(pa_protocol_native*p, const char*fn) { p->auth_cookie_in_property = 0; if (!fn && pa_authkey_prop_get(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) { - pa_log_info(__FILE__": using already loaded auth cookie."); + pa_log_info("using already loaded auth cookie."); pa_authkey_prop_ref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); p->auth_cookie_in_property = 1; return 0; @@ -2400,7 +2400,7 @@ static int load_key(pa_protocol_native*p, const char*fn) { if (pa_authkey_load_auto(fn, p->auth_cookie, sizeof(p->auth_cookie)) < 0) return -1; - pa_log_info(__FILE__": loading cookie from disk."); + pa_log_info("loading cookie from disk."); if (pa_authkey_prop_put(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) p->auth_cookie_in_property = 1; @@ -2417,7 +2417,7 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo assert(ma); if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) { - pa_log(__FILE__": auth-anonymous= expects a boolean argument."); + pa_log("auth-anonymous= expects a boolean argument."); return NULL; } @@ -2432,13 +2432,13 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo { int a = 1; if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &a) < 0) { - pa_log(__FILE__": auth-group-enabled= expects a boolean argument."); + pa_log("auth-group-enabled= expects a boolean argument."); return NULL; } p->auth_group = a ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", c->is_system_instance ? PA_ACCESS_GROUP : NULL)) : NULL; if (p->auth_group) - pa_log_info(__FILE__": Allowing access to group '%s'.", p->auth_group); + pa_log_info("Allowing access to group '%s'.", p->auth_group); } #endif @@ -2446,7 +2446,7 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) { if (!(p->auth_ip_acl = pa_ip_acl_new(acl))) { - pa_log(__FILE__": Failed to parse IP ACL '%s'", acl); + pa_log("Failed to parse IP ACL '%s'", acl); goto fail; } } diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c index 924ee29e..6bfba875 100644 --- a/src/pulsecore/protocol-simple.c +++ b/src/pulsecore/protocol-simple.c @@ -134,7 +134,7 @@ static int do_read(struct connection *c) { } if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { - pa_log_debug(__FILE__": read(): %s", r == 0 ? "EOF" : pa_cstrerror(errno)); + pa_log_debug("read(): %s", r == 0 ? "EOF" : pa_cstrerror(errno)); return -1; } @@ -168,7 +168,7 @@ static int do_write(struct connection *c) { if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { pa_memblock_unref(chunk.memblock); - pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); + pa_log("write(): %s", pa_cstrerror(errno)); return -1; } @@ -315,7 +315,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) assert(s && io && p); if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); + pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); pa_iochannel_free(io); return; } @@ -351,7 +351,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) data.client = c->client; if (!(c->sink_input = pa_sink_input_new(p->core, &data, 0))) { - pa_log(__FILE__": Failed to create sink input."); + pa_log("Failed to create sink input."); goto fail; } @@ -389,7 +389,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) data.client = c->client; if (!(c->source_output = pa_source_output_new(p->core, &data, 0))) { - pa_log(__FILE__": Failed to create source output."); + pa_log("Failed to create source output."); goto fail; } c->source_output->push = source_output_push_cb; @@ -437,7 +437,7 @@ pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *serv p->sample_spec = core->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &p->sample_spec) < 0) { - pa_log(__FILE__": Failed to parse sample type specification."); + pa_log("Failed to parse sample type specification."); goto fail; } @@ -446,20 +446,20 @@ pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *serv enable = 0; if (pa_modargs_get_value_boolean(ma, "record", &enable) < 0) { - pa_log(__FILE__": record= expects a numeric argument."); + pa_log("record= expects a numeric argument."); goto fail; } p->mode = enable ? RECORD : 0; enable = 1; if (pa_modargs_get_value_boolean(ma, "playback", &enable) < 0) { - pa_log(__FILE__": playback= expects a numeric argument."); + pa_log("playback= expects a numeric argument."); goto fail; } p->mode |= enable ? PLAYBACK : 0; if ((p->mode & (RECORD|PLAYBACK)) == 0) { - pa_log(__FILE__": neither playback nor recording enabled for protocol."); + pa_log("neither playback nor recording enabled for protocol."); goto fail; } diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index 421f5de9..ca8137a4 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -357,7 +357,7 @@ static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userd if (p->dead) return; -/* pa_log(__FILE__": Releasing block %u", block_id); */ +/* pa_log("Releasing block %u", block_id); */ item = pa_xnew(struct item_info, 1); item->type = PA_PSTREAM_ITEM_SHMRELEASE; @@ -380,7 +380,7 @@ static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userda if (p->dead) return; -/* pa_log(__FILE__": Revoking block %u", block_id); */ +/* pa_log("Revoking block %u", block_id); */ item = pa_xnew(struct item_info, 1); item->type = PA_PSTREAM_ITEM_SHMREVOKE; @@ -462,7 +462,7 @@ static void prepare_next_write_item(pa_pstream *p) { p->write.data = p->write.shm_info; } /* else */ -/* pa_log_warn(__FILE__": Failed to export memory block."); */ +/* pa_log_warn("Failed to export memory block."); */ } if (send_payload) { @@ -569,7 +569,7 @@ static int do_read(pa_pstream *p) { flags = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]); if (!p->use_shm && (flags & PA_FLAG_SHMMASK) != 0) { - pa_log_warn(__FILE__": Recieved SHM frame on a socket where SHM is disabled."); + pa_log_warn("Recieved SHM frame on a socket where SHM is disabled."); return -1; } @@ -577,7 +577,7 @@ static int do_read(pa_pstream *p) { /* This is a SHM memblock release frame with no payload */ -/* pa_log(__FILE__": Got release frame for %u", ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); */ +/* pa_log("Got release frame for %u", ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); */ assert(p->export); pa_memexport_process_release(p->export, ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); @@ -588,7 +588,7 @@ static int do_read(pa_pstream *p) { /* This is a SHM memblock revoke frame with no payload */ -/* pa_log(__FILE__": Got revoke frame for %u", ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); */ +/* pa_log("Got revoke frame for %u", ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); */ assert(p->import); pa_memimport_process_revoke(p->import, ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); @@ -599,7 +599,7 @@ static int do_read(pa_pstream *p) { length = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]); if (length > FRAME_SIZE_MAX) { - pa_log_warn(__FILE__": Recieved invalid frame size : %lu", (unsigned long) length); + pa_log_warn("Recieved invalid frame size : %lu", (unsigned long) length); return -1; } @@ -610,7 +610,7 @@ static int do_read(pa_pstream *p) { if (channel == (uint32_t) -1) { if (flags != 0) { - pa_log_warn(__FILE__": Received packet frame with invalid flags value."); + pa_log_warn("Received packet frame with invalid flags value."); return -1; } @@ -621,14 +621,14 @@ static int do_read(pa_pstream *p) { } else { if ((flags & PA_FLAG_SEEKMASK) > PA_SEEK_RELATIVE_END) { - pa_log_warn(__FILE__": Received memblock frame with invalid seek mode."); + pa_log_warn("Received memblock frame with invalid seek mode."); return -1; } if ((flags & PA_FLAG_SHMMASK) == PA_FLAG_SHMDATA) { if (length != sizeof(p->read.shm_info)) { - pa_log_warn(__FILE__": Recieved SHM memblock frame with Invalid frame length."); + pa_log_warn("Recieved SHM memblock frame with Invalid frame length."); return -1; } @@ -643,7 +643,7 @@ static int do_read(pa_pstream *p) { p->read.data = p->read.memblock->data; } else { - pa_log_warn(__FILE__": Recieved memblock frame with invalid flags value."); + pa_log_warn("Recieved memblock frame with invalid flags value."); return -1; } } @@ -717,7 +717,7 @@ static int do_read(pa_pstream *p) { ntohl(p->read.shm_info[PA_PSTREAM_SHM_INDEX]), ntohl(p->read.shm_info[PA_PSTREAM_SHM_LENGTH])))) { - pa_log_warn(__FILE__": Failed to import memory block."); + pa_log_warn("Failed to import memory block."); return -1; } diff --git a/src/pulsecore/random.c b/src/pulsecore/random.c index 684ead71..7908e87d 100644 --- a/src/pulsecore/random.c +++ b/src/pulsecore/random.c @@ -81,7 +81,7 @@ void pa_random_seed(void) { if (random_proper(&seed, sizeof(unsigned int)) < 0) { if (!has_whined) - pa_log_warn(__FILE__": failed to get proper entropy. Falling back to seeding with current time."); + pa_log_warn("failed to get proper entropy. Falling back to seeding with current time."); has_whined = 1; seed = (unsigned int) time(NULL); @@ -100,7 +100,7 @@ void pa_random(void *ret_data, size_t length) { return; if (!has_whined) - pa_log_warn(__FILE__": failed to get proper entropy. Falling back to unsecure pseudo RNG."); + pa_log_warn("failed to get proper entropy. Falling back to unsecure pseudo RNG."); has_whined = 1; for (p = ret_data, l = length; l > 0; p++, l--) diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index 7f5d8a02..d902b4b5 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -282,7 +282,7 @@ size_t pa_mix( } default: - pa_log_error(__FILE__": ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format)); + pa_log_error("ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format)); abort(); } } @@ -398,7 +398,7 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol } default: - pa_log_error(__FILE__": ERROR: Unable to change volume of format %s.", + pa_log_error("ERROR: Unable to change volume of format %s.", pa_sample_format_to_string(spec->format)); abort(); } diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c index ad9dc46a..bf0071d6 100644 --- a/src/pulsecore/shm.c +++ b/src/pulsecore/shm.c @@ -61,7 +61,7 @@ int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { #ifdef MAP_ANONYMOUS if ((m->ptr = mmap(NULL, m->size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS, fd, 0)) == MAP_FAILED) { - pa_log(__FILE__": mmap() failed: %s", pa_cstrerror(errno)); + pa_log("mmap() failed: %s", pa_cstrerror(errno)); goto fail; } #else @@ -75,17 +75,17 @@ int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { segment_name(fn, sizeof(fn), m->id); if ((fd = shm_open(fn, O_RDWR|O_CREAT|O_EXCL, mode & 0444)) < 0) { - pa_log(__FILE__": shm_open() failed: %s", pa_cstrerror(errno)); + pa_log("shm_open() failed: %s", pa_cstrerror(errno)); goto fail; } if (ftruncate(fd, m->size = size) < 0) { - pa_log(__FILE__": ftruncate() failed: %s", pa_cstrerror(errno)); + pa_log("ftruncate() failed: %s", pa_cstrerror(errno)); goto fail; } if ((m->ptr = mmap(NULL, m->size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { - pa_log(__FILE__": mmap() failed: %s", pa_cstrerror(errno)); + pa_log("mmap() failed: %s", pa_cstrerror(errno)); goto fail; } @@ -121,7 +121,7 @@ void pa_shm_free(pa_shm *m) { #endif if (munmap(m->ptr, m->size) < 0) - pa_log(__FILE__": munmap() failed: %s", pa_cstrerror(errno)); + pa_log("munmap() failed: %s", pa_cstrerror(errno)); if (m->do_unlink) { segment_name(fn, sizeof(fn), m->id); @@ -188,24 +188,24 @@ int pa_shm_attach_ro(pa_shm *m, unsigned id) { segment_name(fn, sizeof(fn), m->id = id); if ((fd = shm_open(fn, O_RDONLY, 0)) < 0) { - pa_log(__FILE__": shm_open() failed: %s", pa_cstrerror(errno)); + pa_log("shm_open() failed: %s", pa_cstrerror(errno)); goto fail; } if (fstat(fd, &st) < 0) { - pa_log(__FILE__": fstat() failed: %s", pa_cstrerror(errno)); + pa_log("fstat() failed: %s", pa_cstrerror(errno)); goto fail; } if (st.st_size <= 0 || st.st_size > MAX_SHM_SIZE) { - pa_log(__FILE__": Invalid shared memory segment size"); + pa_log("Invalid shared memory segment size"); goto fail; } m->size = st.st_size; if ((m->ptr = mmap(NULL, m->size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { - pa_log(__FILE__": mmap() failed: %s", pa_cstrerror(errno)); + pa_log("mmap() failed: %s", pa_cstrerror(errno)); goto fail; } diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index b5ba9df1..d948f0a4 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -127,7 +127,7 @@ pa_sink_input* pa_sink_input_new( CHECK_VALIDITY_RETURN_NULL(data->resample_method < PA_RESAMPLER_MAX); if (pa_idxset_size(data->sink->inputs) >= PA_MAX_INPUTS_PER_SINK) { - pa_log_warn(__FILE__": Failed to create sink input: too many inputs per sink."); + pa_log_warn("Failed to create sink input: too many inputs per sink."); return NULL; } @@ -140,7 +140,7 @@ pa_sink_input* pa_sink_input_new( &data->sample_spec, &data->channel_map, &data->sink->sample_spec, &data->sink->channel_map, data->resample_method))) { - pa_log_warn(__FILE__": Unsupported resampling operation."); + pa_log_warn("Unsupported resampling operation."); return NULL; } @@ -177,7 +177,7 @@ pa_sink_input* pa_sink_input_new( r = pa_idxset_put(i->sink->inputs, i, NULL); assert(r == 0); - pa_log_info(__FILE__": created %u \"%s\" on %s with sample spec %s", + pa_log_info("created %u \"%s\" on %s with sample spec %s", i->index, i->name, i->sink->name, @@ -218,7 +218,7 @@ static void sink_input_free(pa_sink_input* i) { if (i->state != PA_SINK_INPUT_DISCONNECTED) pa_sink_input_disconnect(i); - pa_log_info(__FILE__": freed %u \"%s\"", i->index, i->name); + pa_log_info("freed %u \"%s\"", i->index, i->name); if (i->resampled_chunk.memblock) pa_memblock_unref(i->resampled_chunk.memblock); @@ -522,7 +522,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { return 0; if (pa_idxset_size(dest->inputs) >= PA_MAX_INPUTS_PER_SINK) { - pa_log_warn(__FILE__": Failed to move sink input: too many inputs per sink."); + pa_log_warn("Failed to move sink input: too many inputs per sink."); return -1; } @@ -544,7 +544,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { &i->sample_spec, &i->channel_map, &dest->sample_spec, &dest->channel_map, i->resample_method))) { - pa_log_warn(__FILE__": Unsupported resampling operation."); + pa_log_warn("Unsupported resampling operation."); return -1; } } diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index aacb89fd..05695254 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -116,12 +116,12 @@ pa_sink* pa_sink_new( assert(s->index != PA_IDXSET_INVALID && r >= 0); pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"", s->index, s->name, st); + pa_log_info("created %u \"%s\" with sample spec \"%s\"", s->index, s->name, st); n = pa_sprintf_malloc("%s.monitor", name); if (!(s->monitor_source = pa_source_new(core, driver, n, 0, spec, map))) - pa_log_warn(__FILE__": failed to create monitor source."); + pa_log_warn("failed to create monitor source."); else { char *d; s->monitor_source->monitor_of = s; @@ -176,7 +176,7 @@ static void sink_free(pa_sink *s) { if (s->state != PA_SINK_DISCONNECTED) pa_sink_disconnect(s); - pa_log_info(__FILE__": freed %u \"%s\"", s->index, s->name); + pa_log_info("freed %u \"%s\"", s->index, s->name); if (s->monitor_source) { pa_source_unref(s->monitor_source); diff --git a/src/pulsecore/socket-client.c b/src/pulsecore/socket-client.c index 8e547614..2ceaf5c3 100644 --- a/src/pulsecore/socket-client.c +++ b/src/pulsecore/socket-client.c @@ -140,17 +140,17 @@ static void do_call(pa_socket_client *c) { lerror = sizeof(error); if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &lerror) < 0) { - pa_log(__FILE__": getsockopt(): %s", pa_cstrerror(errno)); + pa_log("getsockopt(): %s", pa_cstrerror(errno)); goto finish; } if (lerror != sizeof(error)) { - pa_log(__FILE__": getsockopt() returned invalid size."); + pa_log("getsockopt() returned invalid size."); goto finish; } if (error != 0) { - pa_log_debug(__FILE__": connect(): %s", pa_cstrerror(errno)); + pa_log_debug("connect(): %s", pa_cstrerror(errno)); errno = error; goto finish; } @@ -192,10 +192,10 @@ static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t if ((r = connect(c->fd, sa, len)) < 0) { #ifdef OS_IS_WIN32 if (WSAGetLastError() != EWOULDBLOCK) { - pa_log_debug(__FILE__": connect(): %d", WSAGetLastError()); + pa_log_debug("connect(): %d", WSAGetLastError()); #else if (errno != EINPROGRESS) { - pa_log_debug(__FILE__": connect(): %s (%d)", pa_cstrerror(errno), errno); + pa_log_debug("connect(): %s (%d)", pa_cstrerror(errno), errno); #endif return -1; } @@ -267,7 +267,7 @@ static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size } if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s", pa_cstrerror(errno)); + pa_log("socket(): %s", pa_cstrerror(errno)); return -1; } @@ -485,7 +485,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam /* FIXME: PF_INET6 support */ if (hints.ai_family == PF_INET6) { - pa_log_error(__FILE__": IPv6 is not supported on Windows"); + pa_log_error("IPv6 is not supported on Windows"); goto finish; } diff --git a/src/pulsecore/socket-server.c b/src/pulsecore/socket-server.c index 25483592..4d69b8a4 100644 --- a/src/pulsecore/socket-server.c +++ b/src/pulsecore/socket-server.c @@ -96,7 +96,7 @@ static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_U pa_socket_server_ref(s); if ((nfd = accept(fd, NULL, NULL)) < 0) { - pa_log(__FILE__": accept(): %s", pa_cstrerror(errno)); + pa_log("accept(): %s", pa_cstrerror(errno)); goto finish; } @@ -115,12 +115,12 @@ static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_U request_init(&req, RQ_DAEMON, s->tcpwrap_service, RQ_FILE, nfd, NULL); fromhost(&req); if (!hosts_access(&req)) { - pa_log_warn(__FILE__": TCP connection refused by tcpwrap."); + pa_log_warn("TCP connection refused by tcpwrap."); close(nfd); goto finish; } - pa_log_info(__FILE__": TCP connection accepted by tcpwrap."); + pa_log_info("TCP connection accepted by tcpwrap."); } #endif @@ -175,7 +175,7 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file assert(m && filename); if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s", pa_cstrerror(errno)); + pa_log("socket(): %s", pa_cstrerror(errno)); goto fail; } @@ -188,7 +188,7 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file pa_socket_low_delay(fd); if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) { - pa_log(__FILE__": bind(): %s", pa_cstrerror(errno)); + pa_log("bind(): %s", pa_cstrerror(errno)); goto fail; } @@ -199,7 +199,7 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file chmod(filename, 0777); if (listen(fd, 5) < 0) { - pa_log(__FILE__": listen(): %s", pa_cstrerror(errno)); + pa_log("listen(): %s", pa_cstrerror(errno)); goto fail; } @@ -235,7 +235,7 @@ pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address assert(m && port); if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(PF_INET): %s", pa_cstrerror(errno)); + pa_log("socket(PF_INET): %s", pa_cstrerror(errno)); goto fail; } @@ -243,7 +243,7 @@ pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address #ifdef SO_REUSEADDR if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) - pa_log(__FILE__": setsockopt(): %s", pa_cstrerror(errno)); + pa_log("setsockopt(): %s", pa_cstrerror(errno)); #endif pa_socket_tcp_low_delay(fd); @@ -254,12 +254,12 @@ pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address sa.sin_addr.s_addr = htonl(address); if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { - pa_log(__FILE__": bind(): %s", pa_cstrerror(errno)); + pa_log("bind(): %s", pa_cstrerror(errno)); goto fail; } if (listen(fd, 5) < 0) { - pa_log(__FILE__": listen(): %s", pa_cstrerror(errno)); + pa_log("listen(): %s", pa_cstrerror(errno)); goto fail; } @@ -286,7 +286,7 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad assert(m && port); if ((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(PF_INET6): %s", pa_cstrerror(errno)); + pa_log("socket(PF_INET6): %s", pa_cstrerror(errno)); goto fail; } @@ -294,12 +294,12 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad #ifdef IPV6_V6ONLY if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) - pa_log(__FILE__": setsockopt(IPPROTO_IPV6, IPV6_V6ONLY): %s", pa_cstrerror(errno)); + pa_log("setsockopt(IPPROTO_IPV6, IPV6_V6ONLY): %s", pa_cstrerror(errno)); #endif #ifdef SO_REUSEADDR if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) - pa_log(__FILE__": setsockopt(SOL_SOCKET, SO_REUSEADDR, 1): %s", pa_cstrerror(errno)); + pa_log("setsockopt(SOL_SOCKET, SO_REUSEADDR, 1): %s", pa_cstrerror(errno)); #endif pa_socket_tcp_low_delay(fd); @@ -310,12 +310,12 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad memcpy(sa.sin6_addr.s6_addr, address, 16); if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { - pa_log(__FILE__": bind(): %s", pa_cstrerror(errno)); + pa_log("bind(): %s", pa_cstrerror(errno)); goto fail; } if (listen(fd, 5) < 0) { - pa_log(__FILE__": listen(): %s", pa_cstrerror(errno)); + pa_log("listen(): %s", pa_cstrerror(errno)); goto fail; } @@ -426,7 +426,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { socklen_t sa_len = sizeof(sa); if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) { - pa_log(__FILE__": getsockname(): %s", pa_cstrerror(errno)); + pa_log("getsockname(): %s", pa_cstrerror(errno)); return NULL; } @@ -447,7 +447,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { char ip[INET6_ADDRSTRLEN]; if (!inet_ntop(AF_INET6, &sa.sin6_addr, ip, sizeof(ip))) { - pa_log(__FILE__": inet_ntop(): %s", pa_cstrerror(errno)); + pa_log("inet_ntop(): %s", pa_cstrerror(errno)); return NULL; } @@ -462,7 +462,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { socklen_t sa_len = sizeof(sa); if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) { - pa_log(__FILE__": getsockname(): %s", pa_cstrerror(errno)); + pa_log("getsockname(): %s", pa_cstrerror(errno)); return NULL; } @@ -482,7 +482,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { char ip[INET_ADDRSTRLEN]; if (!inet_ntop(AF_INET, &sa.sin_addr, ip, sizeof(ip))) { - pa_log(__FILE__": inet_ntop(): %s", pa_cstrerror(errno)); + pa_log("inet_ntop(): %s", pa_cstrerror(errno)); return NULL; } diff --git a/src/pulsecore/socket-util.c b/src/pulsecore/socket-util.c index 8705560d..856c28e8 100644 --- a/src/pulsecore/socket-util.c +++ b/src/pulsecore/socket-util.c @@ -191,7 +191,7 @@ int pa_socket_set_rcvbuf(int fd, size_t l) { assert(fd >= 0); /* if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&l, sizeof(l)) < 0) { */ -/* pa_log(__FILE__": SO_RCVBUF: %s", strerror(errno)); */ +/* pa_log("SO_RCVBUF: %s", strerror(errno)); */ /* return -1; */ /* } */ @@ -202,7 +202,7 @@ int pa_socket_set_sndbuf(int fd, size_t l) { assert(fd >= 0); /* if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&l, sizeof(l)) < 0) { */ -/* pa_log(__FILE__": SO_SNDBUF: %s", strerror(errno)); */ +/* pa_log("SO_SNDBUF: %s", strerror(errno)); */ /* return -1; */ /* } */ @@ -216,7 +216,7 @@ int pa_unix_socket_is_stale(const char *fn) { int fd = -1, ret = -1; if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(): %s", pa_cstrerror(errno)); + pa_log("socket(): %s", pa_cstrerror(errno)); goto finish; } diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c index 6782f50e..e6f24a79 100644 --- a/src/pulsecore/sound-file-stream.c +++ b/src/pulsecore/sound-file-stream.c @@ -142,7 +142,7 @@ int pa_play_file( memset(&sfinfo, 0, sizeof(sfinfo)); if (!(u->sndfile = sf_open(fname, SFM_READ, &sfinfo))) { - pa_log(__FILE__": Failed to open file %s", fname); + pa_log("Failed to open file %s", fname); goto fail; } @@ -175,7 +175,7 @@ int pa_play_file( ss.channels = sfinfo.channels; if (!pa_sample_spec_valid(&ss)) { - pa_log(__FILE__": Unsupported sample format in file %s", fname); + pa_log("Unsupported sample format in file %s", fname); goto fail; } diff --git a/src/pulsecore/sound-file.c b/src/pulsecore/sound-file.c index 256cce43..1bf650e2 100644 --- a/src/pulsecore/sound-file.c +++ b/src/pulsecore/sound-file.c @@ -48,7 +48,7 @@ int pa_sound_file_load(pa_mempool *pool, const char *fname, pa_sample_spec *ss, memset(&sfinfo, 0, sizeof(sfinfo)); if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) { - pa_log(__FILE__": Failed to open file %s", fname); + pa_log("Failed to open file %s", fname); goto finish; } @@ -80,7 +80,7 @@ int pa_sound_file_load(pa_mempool *pool, const char *fname, pa_sample_spec *ss, ss->channels = sfinfo.channels; if (!pa_sample_spec_valid(ss)) { - pa_log(__FILE__": Unsupported sample format in file %s", fname); + pa_log("Unsupported sample format in file %s", fname); goto finish; } @@ -88,7 +88,7 @@ int pa_sound_file_load(pa_mempool *pool, const char *fname, pa_sample_spec *ss, pa_channel_map_init_auto(map, ss->channels, PA_CHANNEL_MAP_DEFAULT); if ((l = pa_frame_size(ss)*sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) { - pa_log(__FILE__": File too large"); + pa_log("File too large"); goto finish; } @@ -99,7 +99,7 @@ int pa_sound_file_load(pa_mempool *pool, const char *fname, pa_sample_spec *ss, if ((readf_function && readf_function(sf, chunk->memblock->data, sfinfo.frames) != sfinfo.frames) || (!readf_function && sf_read_raw(sf, chunk->memblock->data, l) != l)) { - pa_log(__FILE__": Premature file end"); + pa_log("Premature file end"); goto finish; } @@ -123,7 +123,7 @@ int pa_sound_file_too_big_to_cache(const char *fname) { pa_sample_spec ss; if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) { - pa_log(__FILE__": Failed to open file %s", fname); + pa_log("Failed to open file %s", fname); return 0; } @@ -155,7 +155,7 @@ int pa_sound_file_too_big_to_cache(const char *fname) { ss.channels = sfinfo.channels; if ((pa_frame_size(&ss) * sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) { - pa_log(__FILE__": File too large %s", fname); + pa_log("File too large %s", fname); return 1; } diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index f9d66f6d..a2fc8519 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -108,7 +108,7 @@ pa_source_output* pa_source_output_new( CHECK_VALIDITY_RETURN_NULL(data->resample_method < PA_RESAMPLER_MAX); if (pa_idxset_size(data->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { - pa_log(__FILE__": Failed to create source output: too many outputs per source."); + pa_log("Failed to create source output: too many outputs per source."); return NULL; } @@ -119,7 +119,7 @@ pa_source_output* pa_source_output_new( &data->source->sample_spec, &data->source->channel_map, &data->sample_spec, &data->channel_map, data->resample_method))) { - pa_log_warn(__FILE__": Unsupported resampling operation."); + pa_log_warn("Unsupported resampling operation."); return NULL; } @@ -148,7 +148,7 @@ pa_source_output* pa_source_output_new( r = pa_idxset_put(o->source->outputs, o, NULL); assert(r == 0); - pa_log_info(__FILE__": created %u \"%s\" on %s with sample spec %s", + pa_log_info("created %u \"%s\" on %s with sample spec %s", o->index, o->name, o->source->name, @@ -187,7 +187,7 @@ static void source_output_free(pa_source_output* o) { if (o->state != PA_SOURCE_OUTPUT_DISCONNECTED) pa_source_output_disconnect(o); - pa_log_info(__FILE__": freed %u \"%s\"", o->index, o->name); + pa_log_info("freed %u \"%s\"", o->index, o->name); if (o->resampler) pa_resampler_free(o->resampler); @@ -313,7 +313,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { return 0; if (pa_idxset_size(dest->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { - pa_log_warn(__FILE__": Failed to move source output: too many outputs per source."); + pa_log_warn("Failed to move source output: too many outputs per source."); return -1; } @@ -334,7 +334,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { &dest->sample_spec, &dest->channel_map, &o->sample_spec, &o->channel_map, o->resample_method))) { - pa_log_warn(__FILE__": Unsupported resampling operation."); + pa_log_warn("Unsupported resampling operation."); return -1; } } diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index cb5b1030..c48d6aaa 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -112,7 +112,7 @@ pa_source* pa_source_new( assert(s->index != PA_IDXSET_INVALID && r >= 0); pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"", s->index, s->name, st); + pa_log_info("created %u \"%s\" with sample spec \"%s\"", s->index, s->name, st); pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index); @@ -155,7 +155,7 @@ static void source_free(pa_source *s) { if (s->state != PA_SOURCE_DISCONNECTED) pa_source_disconnect(s); - pa_log_info(__FILE__": freed %u \"%s\"", s->index, s->name); + pa_log_info("freed %u \"%s\"", s->index, s->name); pa_idxset_free(s->outputs, NULL, NULL); diff --git a/src/pulsecore/x11wrap.c b/src/pulsecore/x11wrap.c index 2ba0a87f..cc993e78 100644 --- a/src/pulsecore/x11wrap.c +++ b/src/pulsecore/x11wrap.c @@ -145,7 +145,7 @@ static pa_x11_wrapper* x11_wrapper_new(pa_core *c, const char *name, const char int r; if (!(d = XOpenDisplay(name))) { - pa_log(__FILE__": XOpenDisplay() failed"); + pa_log("XOpenDisplay() failed"); return NULL; } diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c index fe8038e0..b9912701 100644 --- a/src/utils/pacmd.c +++ b/src/utils/pacmd.c @@ -49,12 +49,12 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { fd_set ifds, ofds; if (pa_pid_file_check_running(&pid) < 0) { - pa_log(__FILE__": no PulseAudio daemon running"); + pa_log("no PulseAudio daemon running"); goto fail; } if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - pa_log(__FILE__": socket(PF_UNIX, SOCK_STREAM, 0): %s", strerror(errno)); + pa_log("socket(PF_UNIX, SOCK_STREAM, 0): %s", strerror(errno)); goto fail; } @@ -66,7 +66,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { int r; if ((r = connect(fd, (struct sockaddr*) &sa, sizeof(sa))) < 0 && (errno != ECONNREFUSED && errno != ENOENT)) { - pa_log(__FILE__": connect(): %s", strerror(errno)); + pa_log("connect(): %s", strerror(errno)); goto fail; } @@ -74,7 +74,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { break; if (pa_pid_file_kill(SIGUSR2, NULL) < 0) { - pa_log(__FILE__": failed to kill PulseAudio daemon."); + pa_log("failed to kill PulseAudio daemon."); goto fail; } @@ -82,7 +82,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { } if (i >= 5) { - pa_log(__FILE__": daemon not responding."); + pa_log("daemon not responding."); goto fail; } @@ -97,7 +97,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { for (;;) { if (select(FD_SETSIZE, &ifds, &ofds, NULL, NULL) < 0) { - pa_log(__FILE__": select(): %s", strerror(errno)); + pa_log("select(): %s", strerror(errno)); goto fail; } @@ -109,7 +109,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { if (r == 0) break; - pa_log(__FILE__": read(): %s", strerror(errno)); + pa_log("read(): %s", strerror(errno)); goto fail; } @@ -125,7 +125,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { if (r == 0) break; - pa_log(__FILE__": read(): %s", strerror(errno)); + pa_log("read(): %s", strerror(errno)); goto fail; } @@ -138,7 +138,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { assert(obuf_length); if ((r = write(1, obuf + obuf_index, obuf_length)) < 0) { - pa_log(__FILE__": write(): %s", strerror(errno)); + pa_log("write(): %s", strerror(errno)); goto fail; } @@ -152,7 +152,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { assert(ibuf_length); if ((r = write(fd, ibuf + ibuf_index, ibuf_length)) < 0) { - pa_log(__FILE__": write(): %s", strerror(errno)); + pa_log("write(): %s", strerror(errno)); goto fail; } diff --git a/src/utils/pax11publish.c b/src/utils/pax11publish.c index 2a0d21d6..6a3c6dbc 100644 --- a/src/utils/pax11publish.c +++ b/src/utils/pax11publish.c @@ -92,7 +92,7 @@ int main(int argc, char *argv[]) { } if (!(d = XOpenDisplay(dname))) { - pa_log(__FILE__": XOpenDisplay() failed"); + pa_log("XOpenDisplay() failed"); goto finish; } -- cgit -- cgit From fd3fe96ce52a1737bb253939f36264908b353b26 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 23:40:48 +0000 Subject: add new function pa_mempool_is_shared() to test whether a memory pool is suitable for SHM data transfers git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1274 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/memblock.c | 6 ++++++ src/pulsecore/memblock.h | 1 + 2 files changed, 7 insertions(+) diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 2109d83c..90494fb6 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -497,6 +497,12 @@ int pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id) { return 0; } +int pa_mempool_is_shared(pa_mempool *p) { + assert(p); + + return !!p->memory.shared; +} + /* For recieving blocks from other nodes */ pa_memimport* pa_memimport_new(pa_mempool *p, pa_memimport_release_cb_t cb, void *userdata) { pa_memimport *i; diff --git a/src/pulsecore/memblock.h b/src/pulsecore/memblock.h index e63e1e0f..70cd1b9e 100644 --- a/src/pulsecore/memblock.h +++ b/src/pulsecore/memblock.h @@ -116,6 +116,7 @@ void pa_mempool_free(pa_mempool *p); const pa_mempool_stat* pa_mempool_get_stat(pa_mempool *p); void pa_mempool_vacuum(pa_mempool *p); int pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id); +int pa_mempool_is_shared(pa_mempool *p); /* For recieving blocks from other nodes */ pa_memimport* pa_memimport_new(pa_mempool *p, pa_memimport_release_cb_t cb, void *userdata); -- cgit From 7ac79098a623e33ffc9d7ca4bbce215ba5f10700 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 23:42:14 +0000 Subject: remove export/import objects when SHM is disable for a pa_pstream object git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1275 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/pstream.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index ca8137a4..e2cfcb63 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -476,7 +476,6 @@ static void prepare_next_write_item(pa_pstream *p) { #ifdef HAVE_CREDS if ((p->send_creds_now = p->write.current->with_creds)) p->write_creds = p->write.current->creds; - #endif } @@ -860,9 +859,25 @@ void pa_pstream_use_shm(pa_pstream *p, int enable) { p->use_shm = enable; - if (!p->import) - p->import = pa_memimport_new(p->mempool, memimport_release_cb, p); + if (enable) { + + if (!p->import) + p->import = pa_memimport_new(p->mempool, memimport_release_cb, p); + + if (!p->export) + p->export = pa_memexport_new(p->mempool, memexport_revoke_cb, p); + + } else { - if (!p->export) - p->export = pa_memexport_new(p->mempool, memexport_revoke_cb, p); + if (p->import) { + pa_memimport_free(p->import); + p->import = NULL; + } + + if (p->export) { + pa_memexport_free(p->export); + p->export = NULL; + } + + } } -- cgit From c313b23d5f5a8ee1a5510d1cc79b8ba54c217df6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 23:43:27 +0000 Subject: one s/0/NULL/ git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1276 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/pstream-util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/pstream-util.h b/src/pulsecore/pstream-util.h index f384d889..c6d76a7c 100644 --- a/src/pulsecore/pstream-util.h +++ b/src/pulsecore/pstream-util.h @@ -30,7 +30,7 @@ /* The tagstruct is freed!*/ void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, const pa_creds *creds); -#define pa_pstream_send_tagstruct(p, t) pa_pstream_send_tagstruct_with_creds((p), (t), 0) +#define pa_pstream_send_tagstruct(p, t) pa_pstream_send_tagstruct_with_creds((p), (t), NULL) void pa_pstream_send_error(pa_pstream *p, uint32_t tag, uint32_t error); void pa_pstream_send_simple_ack(pa_pstream *p, uint32_t tag); -- cgit From e33abc30894dab740ca2fb2f864161266792ea08 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 23:44:35 +0000 Subject: activate SHM support on the server side only when new client supports it and when client and server have the same UID. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1277 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-native.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 506442f5..40a83973 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -961,6 +961,15 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t (unsigned long) creds->uid, (unsigned long) creds->gid, success); + + if (c->version >= 10 && + pa_mempool_is_shared(c->protocol->core->mempool) && + creds->uid == getuid()) { + + pa_pstream_use_shm(c->pstream, 1); + pa_log_info("Enabled SHM for new connection"); + } + } #endif @@ -982,7 +991,21 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t reply = reply_new(tag); pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION); + +#ifdef HAVE_CREDS +{ + /* SHM support is only enabled after both sides made sure they are the same user. */ + + pa_creds ucred; + + ucred.uid = getuid(); + ucred.gid = getgid(); + + pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred); +} +#else pa_pstream_send_tagstruct(c->pstream, reply); +#endif } static void command_set_client_name(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -2353,8 +2376,6 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool); assert(c->pstream); - pa_pstream_use_shm(c->pstream, 1); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); -- cgit From 40875d6d05d00eb54265907be36b76ed7fc590ea Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 23:45:23 +0000 Subject: enable SHM support on the client side only if both the client and the server run as the same user and the server supports it git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1278 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/context.c | 30 +++++++++++++++++++++++------- src/pulse/internal.h | 2 +- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/pulse/context.c b/src/pulse/context.c index df627ee6..55b49a79 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -129,7 +129,7 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { c->subscribe_userdata = NULL; c->mempool = pa_mempool_new(1); - c->local = -1; + c->is_local = -1; c->server_list = NULL; c->server = NULL; c->autospawn_lock_fd = -1; @@ -376,6 +376,21 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t goto finish; } + /* Enable shared memory support if possible */ + if (c->version >= 10 && + pa_mempool_is_shared(c->mempool) && + c->is_local) { + + /* Only enable SHM if both sides are owned by the same + * user. This is a security measure because otherwise + * data private to the user might leak. */ + + const pa_creds *creds; + if ((creds = pa_pdispatch_creds(pd))) + if (getuid() == creds->uid) + pa_pstream_use_shm(c->pstream, 1); + } + reply = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag); pa_tagstruct_puts(reply, c->name); pa_pstream_send_tagstruct(c->pstream, reply); @@ -409,8 +424,6 @@ static void setup_context(pa_context *c, pa_iochannel *io) { assert(!c->pstream); c->pstream = pa_pstream_new(c->mainloop, io, c->mempool); - pa_pstream_use_shm(c->pstream, 1); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); @@ -431,13 +444,16 @@ static void setup_context(pa_context *c, pa_iochannel *io) { { pa_creds ucred; + if (pa_iochannel_creds_supported(io)) + pa_iochannel_creds_enable(io); + ucred.uid = getuid(); ucred.gid = getgid(); pa_pstream_send_tagstruct_with_creds(c->pstream, t, &ucred); } #else - pa_pstream_send_tagstruct_with_creds(c->pstream, t, NULL); + pa_pstream_send_tagstruct(c->pstream, t, NULL); #endif pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL); @@ -542,7 +558,7 @@ static int context_connect_spawn(pa_context *c) { close(fds[1]); - c->local = 1; + c->is_local = 1; io = pa_iochannel_new(c->mainloop, fds[0], fds[0]); @@ -602,7 +618,7 @@ static int try_next_connection(pa_context *c) { if (!(c->client = pa_socket_client_new_string(c->mainloop, u, PA_NATIVE_DEFAULT_PORT))) continue; - c->local = pa_socket_client_is_local(c->client); + c->is_local = pa_socket_client_is_local(c->client); pa_socket_client_set_callback(c->client, on_connection, c); break; } @@ -938,7 +954,7 @@ pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_ int pa_context_is_local(pa_context *c) { assert(c); - return c->local; + return c->is_local; } pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { diff --git a/src/pulse/internal.h b/src/pulse/internal.h index afcfaeff..fa7d5bbd 100644 --- a/src/pulse/internal.h +++ b/src/pulse/internal.h @@ -71,7 +71,7 @@ struct pa_context { pa_mempool *mempool; - int local; + int is_local; int do_autospawn; int autospawn_lock_fd; pa_spawn_api spawn_api; -- cgit From c979b87feab8fc444c2402fe6614a18f18c8b1b6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 23:45:57 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1279 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 - 1 file changed, 1 deletion(-) diff --git a/todo b/todo index c4bb9b0d..35d8fffa 100644 --- a/todo +++ b/todo @@ -34,7 +34,6 @@ Auth/Crypto: Features: - alsa mmap driver - alsa driver with hw mixing -- allow passing data with shared memory between local clients and the server - "window manager for sound" - chroot() - use scatter/gather io for sockets -- cgit From c2db5f88646b2899400479b36ce7eeea44fa00f4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 01:14:59 +0000 Subject: fix a memory leak git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1280 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/log.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c index 8bc673e5..ce093221 100644 --- a/src/pulsecore/log.c +++ b/src/pulsecore/log.c @@ -91,7 +91,7 @@ void pa_log_levelv_meta( va_list ap) { const char *e; - char *text, *t, *n, *location = pa_xstrdup(""); + char *text, *t, *n, *location; assert(level < PA_LOG_LEVEL_MAX); assert(format); @@ -108,6 +108,8 @@ void pa_log_levelv_meta( location = pa_sprintf_malloc("[%s:%i %s()] ", file, line, func); else if (file) location = pa_sprintf_malloc("%s: ", pa_path_get_filename(file)); + else + location = pa_xstrdup(""); if (!pa_utf8_valid(text)) pa_log_level(level, __FILE__": invalid UTF-8 string following below:"); -- cgit From 8c9bdb838c35c12505a63cab6f0da6912a6bbf49 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 01:15:22 +0000 Subject: fix allocation of anonymous memory git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1281 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/shm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c index bf0071d6..52867d2a 100644 --- a/src/pulsecore/shm.c +++ b/src/pulsecore/shm.c @@ -60,7 +60,7 @@ int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { m->size = size; #ifdef MAP_ANONYMOUS - if ((m->ptr = mmap(NULL, m->size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS, fd, 0)) == MAP_FAILED) { + if ((m->ptr = mmap(NULL, m->size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)) == MAP_FAILED) { pa_log("mmap() failed: %s", pa_cstrerror(errno)); goto fail; } -- cgit From 046bdd9b30d10a18d21890f7975a8ca268cdfeeb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 01:15:48 +0000 Subject: deal properly with pa_mempool_new() failing git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1282 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index 5fdeab56..c36a35bd 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -46,7 +46,11 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) { pa_core* c; - + pa_mempool *pool; + + if (!(pool = pa_mempool_new(shared))) + return NULL; + c = pa_xnew(pa_core, 1); c->mainloop = m; @@ -78,7 +82,7 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) { PA_LLIST_HEAD_INIT(pa_subscription_event, c->subscription_event_queue); c->subscription_event_last = NULL; - c->mempool = pa_mempool_new(shared); + c->mempool = pool; c->disallow_module_loading = 0; -- cgit From 206ac6f3ee4e849a80d3449b9e0f7e3d794cac27 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 01:16:38 +0000 Subject: allow importing of external shm data blocks unconditionally, even when local SHM support is disabled git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1283 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/pstream.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index e2cfcb63..fa5b2788 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -251,7 +251,9 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *poo p->use_shm = 0; p->export = NULL; - p->import = NULL; + + /* We do importing unconditionally */ + p->import = pa_memimport_new(p->mempool, memimport_release_cb, p); pa_iochannel_socket_set_rcvbuf(io, 1024*8); pa_iochannel_socket_set_sndbuf(io, 1024*8); @@ -567,7 +569,7 @@ static int do_read(pa_pstream *p) { flags = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]); - if (!p->use_shm && (flags & PA_FLAG_SHMMASK) != 0) { + if (!p->import && (flags & PA_FLAG_SHMMASK) != 0) { pa_log_warn("Recieved SHM frame on a socket where SHM is disabled."); return -1; } @@ -861,19 +863,11 @@ void pa_pstream_use_shm(pa_pstream *p, int enable) { if (enable) { - if (!p->import) - p->import = pa_memimport_new(p->mempool, memimport_release_cb, p); - if (!p->export) p->export = pa_memexport_new(p->mempool, memexport_revoke_cb, p); } else { - if (p->import) { - pa_memimport_free(p->import); - p->import = NULL; - } - if (p->export) { pa_memexport_free(p->export); p->export = NULL; -- cgit From d785b8fa877b829d9d38082968b35117f7c9d9ec Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 01:18:30 +0000 Subject: add new "disable-shm" option to client.conf git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1284 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/client-conf.c | 3 +++ src/pulse/client-conf.h | 2 +- src/pulse/context.c | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c index 619b11c3..5cd7e3ed 100644 --- a/src/pulse/client-conf.c +++ b/src/pulse/client-conf.c @@ -62,6 +62,7 @@ static const pa_client_conf default_conf = { .default_source = NULL, .default_server = NULL, .autospawn = 0, + .disable_shm = 0, .cookie_file = NULL, .cookie_valid = 0, }; @@ -100,6 +101,7 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) { { "default-server", pa_config_parse_string, NULL }, { "autospawn", pa_config_parse_bool, NULL }, { "cookie-file", pa_config_parse_string, NULL }, + { "disable-shm", pa_config_parse_bool, NULL }, { NULL, NULL, NULL }, }; @@ -110,6 +112,7 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) { table[4].data = &c->default_server; table[5].data = &c->autospawn; table[6].data = &c->cookie_file; + table[7].data = &c->disable_shm; f = filename ? fopen((fn = pa_xstrdup(filename)), "r") : diff --git a/src/pulse/client-conf.h b/src/pulse/client-conf.h index a532f0df..35728aeb 100644 --- a/src/pulse/client-conf.h +++ b/src/pulse/client-conf.h @@ -28,7 +28,7 @@ typedef struct pa_client_conf { char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server, *cookie_file; - int autospawn; + int autospawn, disable_shm; uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; int cookie_valid; /* non-zero, when cookie is valid */ } pa_client_conf; diff --git a/src/pulse/context.c b/src/pulse/context.c index 55b49a79..b4641590 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -128,7 +128,6 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { c->subscribe_callback = NULL; c->subscribe_userdata = NULL; - c->mempool = pa_mempool_new(1); c->is_local = -1; c->server_list = NULL; c->server = NULL; @@ -149,6 +148,8 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { #endif pa_client_conf_env(c->conf); + c->mempool = pa_mempool_new(!c->conf->disable_shm); + return c; } -- cgit From c9b6d55090a22256443b0a0f4b24acfa94bf4422 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 01:18:57 +0000 Subject: add default "disable-shm" option to client.conf git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1285 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/client.conf.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pulse/client.conf.in b/src/pulse/client.conf.in index c970be56..3cfd9760 100644 --- a/src/pulse/client.conf.in +++ b/src/pulse/client.conf.in @@ -40,3 +40,6 @@ ### Cookie file ; cookie-file = + +### Disable shared memory data transfer +; disable-shm = 0 -- cgit From dbc658df4129eec260619f3fd31680ad7977f46c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 01:20:13 +0000 Subject: add new "disable-shm" server config option git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1286 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/daemon-conf.c | 22 +++++++++++++--------- src/daemon/daemon-conf.h | 3 ++- src/daemon/main.c | 15 +++++++++------ 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 2cb06697..dd478126 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -73,7 +73,8 @@ static const pa_daemon_conf default_conf = { .config_file = NULL, .use_pid_file = 1, .system_instance = 0, - .no_cpu_limit = 0 + .no_cpu_limit = 0, + .disable_shm = 0 #ifdef HAVE_SYS_RESOURCE_H , .rlimit_as = { .value = 0, .is_set = 0 }, .rlimit_core = { .value = 0, .is_set = 0 }, @@ -248,6 +249,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { { "use-pid-file", pa_config_parse_bool, NULL }, { "system-instance", pa_config_parse_bool, NULL }, { "no-cpu-limit", pa_config_parse_bool, NULL }, + { "disable-shm", pa_config_parse_bool, NULL }, #ifdef HAVE_SYS_RESOURCE_H { "rlimit-as", parse_rlimit, NULL }, { "rlimit-core", parse_rlimit, NULL }, @@ -281,21 +283,22 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { table[13].data = &c->use_pid_file; table[14].data = &c->system_instance; table[15].data = &c->no_cpu_limit; + table[16].data = &c->disable_shm; #ifdef HAVE_SYS_RESOURCE_H - table[16].data = &c->rlimit_as; - table[17].data = &c->rlimit_core; - table[18].data = &c->rlimit_data; - table[19].data = &c->rlimit_fsize; - table[20].data = &c->rlimit_nofile; - table[21].data = &c->rlimit_stack; + table[17].data = &c->rlimit_as; + table[18].data = &c->rlimit_core; + table[19].data = &c->rlimit_data; + table[20].data = &c->rlimit_fsize; + table[21].data = &c->rlimit_nofile; + table[22].data = &c->rlimit_stack; #ifdef RLIMIT_NPROC - table[22].data = &c->rlimit_nproc; + table[23].data = &c->rlimit_nproc; #endif #ifdef RLIMIT_MEMLOCK #ifndef RLIMIT_NPROC #error "Houston, we have a numbering problem!" #endif - table[23].data = &c->rlimit_memlock; + table[24].data = &c->rlimit_memlock; #endif #endif @@ -367,6 +370,7 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { pa_strbuf_printf(s, "use-pid-file = %i\n", c->use_pid_file); pa_strbuf_printf(s, "system-instance = %i\n", !!c->system_instance); pa_strbuf_printf(s, "no-cpu-limit = %i\n", !!c->no_cpu_limit); + pa_strbuf_printf(s, "disable_shm = %i\n", !!c->disable_shm); #ifdef HAVE_SYS_RESOURCE_H pa_strbuf_printf(s, "rlimit-as = %li\n", c->rlimit_as.is_set ? (long int) c->rlimit_as.value : -1); pa_strbuf_printf(s, "rlimit-core = %li\n", c->rlimit_core.is_set ? (long int) c->rlimit_core.value : -1); diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h index 84208336..b4b833ad 100644 --- a/src/daemon/daemon-conf.h +++ b/src/daemon/daemon-conf.h @@ -59,7 +59,8 @@ typedef struct pa_daemon_conf { auto_log_target, use_pid_file, system_instance, - no_cpu_limit; + no_cpu_limit, + disable_shm; char *script_commands, *dl_search_path, *default_script_file; pa_log_target_t log_target; pa_log_level_t log_level; diff --git a/src/daemon/main.c b/src/daemon/main.c index 95ba6dd5..8b816b9a 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -306,10 +306,10 @@ static void set_all_rlimits(const pa_daemon_conf *conf) { #endif int main(int argc, char *argv[]) { - pa_core *c; + pa_core *c = NULL; pa_strbuf *buf = NULL; - pa_daemon_conf *conf; - pa_mainloop *mainloop; + pa_daemon_conf *conf = NULL; + pa_mainloop *mainloop = NULL; char *s; int r, retval = 1, d = 0; @@ -559,8 +559,9 @@ int main(int argc, char *argv[]) { mainloop = pa_mainloop_new(); assert(mainloop); - c = pa_core_new(pa_mainloop_get_api(mainloop), 1); - assert(c); + if (!(c = pa_core_new(pa_mainloop_get_api(mainloop), !conf->disable_shm))) + goto finish; + c->is_system_instance = !!conf->system_instance; r = pa_signal_init(pa_mainloop_get_api(mainloop)); @@ -651,12 +652,14 @@ int main(int argc, char *argv[]) { pa_cpu_limit_done(); pa_signal_done(); - pa_mainloop_free(mainloop); pa_log_info("Daemon terminated."); finish: + if (mainloop) + pa_mainloop_free(mainloop); + if (conf) pa_daemon_conf_free(conf); -- cgit From a8519d56677f79e9ef6ee65439531a8d6b955d43 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 01:20:40 +0000 Subject: add "disable-shm=" to default daemon configuration file git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1287 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/daemon.conf.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in index 0204b9e3..29b22a42 100644 --- a/src/daemon/daemon.conf.in +++ b/src/daemon/daemon.conf.in @@ -96,3 +96,6 @@ ; rlimit-stack = -1 ; rlimit-nproc = -1 ; rlimit-memlock = 25 + +## Disable shared memory data transfer +; disable-shm = 0 -- cgit From 47c7a14b828a35ade80b49ec6bed75b2801af7bb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 01:21:22 +0000 Subject: add --disable-shm command line option to the daemon git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1288 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/cmdline.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c index d3fe8e65..d368b644 100644 --- a/src/daemon/cmdline.c +++ b/src/daemon/cmdline.c @@ -60,6 +60,7 @@ enum { ARG_USE_PID_FILE, ARG_CHECK, ARG_NO_CPU_LIMIT, + ARG_DISABLE_SHM, ARG_SYSTEM }; @@ -88,6 +89,7 @@ static struct option long_options[] = { {"check", 0, 0, ARG_CHECK}, {"system", 2, 0, ARG_SYSTEM}, {"no-cpu-limit", 2, 0, ARG_NO_CPU_LIMIT}, + {"disable-shm", 2, 0, ARG_DISABLE_SHM}, {NULL, 0, 0, 0} }; @@ -132,7 +134,8 @@ void pa_cmdline_help(const char *argv0) { " src-zero-order-hold,src-linear,trivial)\n" " --use-pid-file[=BOOL] Create a PID file\n" " --no-cpu-limit[=BOOL] Do not install CPU load limiter on\n" - " platforms that support it.\n\n" + " platforms that support it.\n" + " --disable-shm[=BOOL] Disable shared memory support.\n\n" "STARTUP SCRIPT:\n" " -L, --load=\"MODULE ARGUMENTS\" Load the specified plugin module with\n" @@ -297,7 +300,13 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d goto fail; } break; - + + case ARG_DISABLE_SHM: + if ((conf->disable_shm = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + pa_log("--disable-shm expects boolean argument"); + goto fail; + } + break; default: goto fail; -- cgit From 1b7fff323853cee6944a47316dd882785f365f77 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 01:23:09 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1289 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 - 1 file changed, 1 deletion(-) diff --git a/todo b/todo index 35d8fffa..7597cb31 100644 --- a/todo +++ b/todo @@ -23,7 +23,6 @@ Cleanups: - silence generation should be moved into the core to avoid races and code duplication in the backends - rework resampler to not use pa_xrealloc. Use pa_memblock_new instead. -- allow disabling shm in both client and server Auth/Crypto: - ssl -- cgit From 521d15babb5be8f3ce47d2e73b1b3470c71159ba Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 02:23:11 +0000 Subject: fix a memory leak git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1290 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-volume-restore.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index 0e4f278c..59c47743 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -237,8 +237,10 @@ static char* client_name(pa_client *c) { t = pa_sprintf_malloc("%s$%s", c->driver, c->name); t[strcspn(t, "\n\r#")] = 0; - if (!*t) + if (!*t) { + pa_xfree(t); return NULL; + } if ((e = strrchr(t, '('))) { char *k = e + 1 + strspn(e + 1, "0123456789-"); -- cgit From af87c7d21bad55d91daa7a60028df5d0ee66cd8d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 02:23:52 +0000 Subject: rework the resample to allocate temporary memory with pa_memblock_new() instead of pa_xrealloc() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1291 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/resampler.c | 83 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 58 insertions(+), 25 deletions(-) diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index 74226714..b0142049 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -51,6 +51,7 @@ struct pa_resampler { }; struct impl_libsamplerate { + pa_memblock *buf1_block, *buf2_block, *buf3_block, *buf4_block; float* buf1, *buf2, *buf3, *buf4; unsigned buf1_samples, buf2_samples, buf3_samples, buf4_samples; @@ -223,10 +224,14 @@ static void libsamplerate_free(pa_resampler *r) { if (u->src_state) src_delete(u->src_state); - pa_xfree(u->buf1); - pa_xfree(u->buf2); - pa_xfree(u->buf3); - pa_xfree(u->buf4); + if (u->buf1_block) + pa_memblock_unref(u->buf1_block); + if (u->buf2_block) + pa_memblock_unref(u->buf2_block); + if (u->buf3_block) + pa_memblock_unref(u->buf3_block); + if (u->buf4_block) + pa_memblock_unref(u->buf4_block); pa_xfree(u); } @@ -281,8 +286,14 @@ static float * convert_to_float(pa_resampler *r, void *input, unsigned n_frames) n_samples = n_frames * r->i_ss.channels; - if (u->buf1_samples < n_samples) - u->buf1 = pa_xrealloc(u->buf1, sizeof(float) * (u->buf1_samples = n_samples)); + if (u->buf1_samples < n_samples) { + if (u->buf1_block) + pa_memblock_unref(u->buf1_block); + + u->buf1_samples = n_samples; + u->buf1_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples); + u->buf1 = u->buf1_block->data; + } u->to_float32ne_func(n_samples, input, u->buf1); @@ -307,8 +318,14 @@ static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) { n_samples = n_frames * r->o_ss.channels; - if (u->buf2_samples < n_samples) - u->buf2 = pa_xrealloc(u->buf2, sizeof(float) * (u->buf2_samples = n_samples)); + if (u->buf2_samples < n_samples) { + if (u->buf2_block) + pa_memblock_unref(u->buf2_block); + + u->buf2_samples = n_samples; + u->buf2_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples); + u->buf2 = u->buf2_block->data; + } memset(u->buf2, 0, n_samples * sizeof(float)); @@ -351,8 +368,14 @@ static float *resample(pa_resampler *r, float *input, unsigned *n_frames) { out_n_frames = (*n_frames*r->o_ss.rate/r->i_ss.rate)+1024; out_n_samples = out_n_frames * r->o_ss.channels; - if (u->buf3_samples < out_n_samples) - u->buf3 = pa_xrealloc(u->buf3, sizeof(float) * (u->buf3_samples = out_n_samples)); + if (u->buf3_samples < out_n_samples) { + if (u->buf3_block) + pa_memblock_unref(u->buf3_block); + + u->buf3_samples = out_n_samples; + u->buf3_block = pa_memblock_new(r->mempool, sizeof(float) * out_n_samples); + u->buf3 = u->buf3_block->data; + } data.data_in = input; data.input_frames = *n_frames; @@ -388,9 +411,15 @@ static void *convert_from_float(pa_resampler *r, float *input, unsigned n_frames n_samples = n_frames * r->o_ss.channels; - if (u->buf4_samples < n_samples) - u->buf4 = pa_xrealloc(u->buf4, sizeof(float) * (u->buf4_samples = n_samples)); - + if (u->buf4_samples < n_samples) { + if (u->buf4_block) + pa_memblock_unref(u->buf4_block); + + u->buf4_samples = n_samples; + u->buf4_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples); + u->buf4 = u->buf4_block->data; + } + u->from_float32ne_func(n_samples, input, u->buf4); return u->buf4; @@ -429,30 +458,33 @@ static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchun out->index = in->index; out->length = in->length; } else { - float **p = NULL; - out->length = n_frames * r->o_fz; out->index = 0; - + out->memblock = NULL; + if (output == u->buf1) { - p = &u->buf1; + u->buf1 = NULL; u->buf1_samples = 0; + out->memblock = u->buf1_block; + u->buf1_block = NULL; } else if (output == u->buf2) { - p = &u->buf2; + u->buf2 = NULL; u->buf2_samples = 0; + out->memblock = u->buf2_block; + u->buf2_block = NULL; } else if (output == u->buf3) { - p = &u->buf3; + u->buf3 = NULL; u->buf3_samples = 0; + out->memblock = u->buf3_block; + u->buf3_block = NULL; } else if (output == u->buf4) { - p = &u->buf4; + u->buf4 = NULL; u->buf4_samples = 0; + out->memblock = u->buf4_block; + u->buf4_block = NULL; } - assert(p); - - /* Take the existing buffer and make it a memblock */ - out->memblock = pa_memblock_new_malloced(r->mempool, *p, out->length); - *p = NULL; + assert(out->memblock); } } else { out->memblock = NULL; @@ -485,6 +517,7 @@ static int libsamplerate_init(pa_resampler *r) { r->impl_data = u = pa_xnew(struct impl_libsamplerate, 1); u->buf1 = u->buf2 = u->buf3 = u->buf4 = NULL; + u->buf1_block = u->buf2_block = u->buf3_block = u->buf4_block = NULL; u->buf1_samples = u->buf2_samples = u->buf3_samples = u->buf4_samples = 0; if (r->i_ss.format == PA_SAMPLE_FLOAT32NE) -- cgit From 16ff83f5c0acbd606f23090ebd4cba9ecaf502a7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 02:24:59 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1292 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/todo b/todo index 7597cb31..a47caa7c 100644 --- a/todo +++ b/todo @@ -22,7 +22,9 @@ Cleanups: - use software volume when hardware doesn't support all channels (alsa done) - silence generation should be moved into the core to avoid races and code duplication in the backends -- rework resampler to not use pa_xrealloc. Use pa_memblock_new instead. +- pdispatch: split large memory blocks when sending +- sysv shm +- posix_memalign Auth/Crypto: - ssl -- cgit From 57f0b08cc1c6be0afc4f563d41cacae7c5d820a9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 16:25:15 +0000 Subject: generate per-type memory block statistics git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1293 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/memblock.c | 19 ++++++++++++++++++- src/pulsecore/memblock.h | 4 ++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 90494fb6..c34ddee5 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -121,6 +121,9 @@ static void stat_add(pa_memblock*b) { b->pool->stat.n_imported++; b->pool->stat.imported_size += b->length; } + + b->pool->stat.n_allocated_by_type[b->type]++; + b->pool->stat.n_accumulated_by_type[b->type]++; } static void stat_remove(pa_memblock *b) { @@ -140,6 +143,8 @@ static void stat_remove(pa_memblock *b) { b->pool->stat.n_imported --; b->pool->stat.imported_size -= b->length; } + + b->pool->stat.n_allocated_by_type[b->type]--; } static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length); @@ -353,13 +358,21 @@ void pa_memblock_unref(pa_memblock*b) { if (b->type == PA_MEMBLOCK_POOL_EXTERNAL) pa_xfree(b); + + break; } + + case PA_MEMBLOCK_TYPE_MAX: + default: + abort(); } } static void memblock_make_local(pa_memblock *b) { assert(b); + b->pool->stat.n_allocated_by_type[b->type]--; + if (b->length <= b->pool->block_size - sizeof(struct mempool_slot)) { struct mempool_slot *slot; @@ -373,7 +386,7 @@ static void memblock_make_local(pa_memblock *b) { new_data = mempool_slot_data(slot); memcpy(new_data, b->data, b->length); b->data = new_data; - return; + goto finish; } } @@ -382,6 +395,10 @@ static void memblock_make_local(pa_memblock *b) { b->per_type.user.free_cb = pa_xfree; b->read_only = 0; b->data = pa_xmemdup(b->data, b->length); + +finish: + b->pool->stat.n_allocated_by_type[b->type]++; + b->pool->stat.n_accumulated_by_type[b->type]++; } void pa_memblock_unref_fixed(pa_memblock *b) { diff --git a/src/pulsecore/memblock.h b/src/pulsecore/memblock.h index 70cd1b9e..620bf726 100644 --- a/src/pulsecore/memblock.h +++ b/src/pulsecore/memblock.h @@ -40,6 +40,7 @@ typedef enum pa_memblock_type { PA_MEMBLOCK_USER, /* User supplied memory, to be freed with free_cb */ PA_MEMBLOCK_FIXED, /* data is a pointer to fixed memory that needs not to be freed */ PA_MEMBLOCK_IMPORTED, /* Memory is imported from another process via shm */ + PA_MEMBLOCK_TYPE_MAX } pa_memblock_type_t; typedef struct pa_memblock pa_memblock; @@ -84,6 +85,9 @@ struct pa_mempool_stat { unsigned n_too_large_for_pool; unsigned n_pool_full; + + unsigned n_allocated_by_type[PA_MEMBLOCK_TYPE_MAX]; + unsigned n_accumulated_by_type[PA_MEMBLOCK_TYPE_MAX]; }; /* Allocate a new memory block of type PA_MEMBLOCK_MEMPOOL or PA_MEMBLOCK_APPENDED, depending on the size */ -- cgit From c6ca9a85c375a0ecc3b205b05b7867b251676162 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 16:25:41 +0000 Subject: print per-type memory block statistics on "stat" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1294 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/cli-command.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index 811b96d2..8ea9262b 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -242,7 +242,19 @@ static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { char s[256]; const pa_mempool_stat *stat; - assert(c && t); + unsigned k; + + static const char* const type_table[PA_MEMBLOCK_TYPE_MAX] = { + [PA_MEMBLOCK_POOL] = "POOL", + [PA_MEMBLOCK_POOL_EXTERNAL] = "POOL_EXTERNAL", + [PA_MEMBLOCK_APPENDED] = "APPENDED", + [PA_MEMBLOCK_USER] = "USER", + [PA_MEMBLOCK_FIXED] = "FIXED", + [PA_MEMBLOCK_IMPORTED] = "IMPORTED", + }; + + assert(c); + assert(t); stat = pa_mempool_get_stat(c->mempool); @@ -273,6 +285,13 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G pa_namereg_get_default_sink_name(c), pa_namereg_get_default_source_name(c)); + for (k = 0; k < PA_MEMBLOCK_TYPE_MAX; k++) + pa_strbuf_printf(buf, + "Memory blocks of type %s: %u allocated/%u accumulated.\n", + type_table[k], + stat->n_allocated_by_type[k], + stat->n_accumulated_by_type[k]); + return 0; } -- cgit From d50c56a8f31515e1678b5d56b34a00b58b735539 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 16:26:08 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1295 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 + 1 file changed, 1 insertion(+) diff --git a/todo b/todo index a47caa7c..4100ee2d 100644 --- a/todo +++ b/todo @@ -25,6 +25,7 @@ Cleanups: - pdispatch: split large memory blocks when sending - sysv shm - posix_memalign +- test sample upload Auth/Crypto: - ssl -- cgit From 3e0f00f93deed28e68b60f29fc42838575241b0e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 17:27:27 +0000 Subject: if MAP_ANONYMOUS is not supported use posix_memalign if possible to allocate the memory pool git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1296 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/shm.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c index 52867d2a..02528126 100644 --- a/src/pulsecore/shm.c +++ b/src/pulsecore/shm.c @@ -19,6 +19,10 @@ USA. ***/ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include @@ -32,6 +36,7 @@ #include #include #include +#include #include "shm.h" @@ -64,6 +69,15 @@ int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { pa_log("mmap() failed: %s", pa_cstrerror(errno)); goto fail; } +#elif defined(HAVE_POSIX_MEMALIGN) + { + int r; + + if ((r = posix_memalign(&m->ptr, sysconf(_SC_PAGESIZE), size)) < 0) { + pa_log("posix_memalign() failed: %s", pa_cstrerror(r)); + goto fail; + } + } #else m->ptr = pa_xmalloc(m->size); #endif @@ -114,7 +128,11 @@ void pa_shm_free(pa_shm *m) { assert(m->ptr && m->ptr != MAP_FAILED); assert(m->size > 0); -#ifndef MAP_ANONYMOUS +#if !defined(MAP_ANONYMOUS) && defined(HAVE_POSIX_MEMALIGN) + if (!m->shared) + free(m->ptr); + else +#elif !defined(MAP_ANONYMOUS) if (!m->shared) pa_xfree(m->ptr); else @@ -139,7 +157,6 @@ void pa_shm_punch(pa_shm *m, size_t offset, size_t size) { assert(m); assert(m->ptr && m->ptr != MAP_FAILED); assert(m->size > 0); - assert(m->do_unlink); assert(offset < m->size); assert(offset+size < m->size); -- cgit From b642325d1090b699e14bf8f218b61227a9d1b2ab Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 17:30:30 +0000 Subject: check for posix_memalign and friends git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1297 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 07b2cfa1..b6b5f495 100644 --- a/configure.ac +++ b/configure.ac @@ -240,12 +240,11 @@ AC_CHECK_FUNCS([lstat]) # Non-standard -AC_CHECK_FUNCS(setresuid) -AC_CHECK_FUNCS(setresgid) -AC_CHECK_FUNCS(setreuid) -AC_CHECK_FUNCS(setregid) -AC_CHECK_FUNCS(seteuid) -AC_CHECK_FUNCS(setegid) +AC_CHECK_FUNCS([setresuid setresgid setreuid setregid seteuid setegid]) + +# Memory mangement + +AC_CHECK_FUNCS([mmap posix_memalign madvise]) #### POSIX threads #### -- cgit From 84d1d3eff293e9d30b65d2656a7e5abdad893075 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 17:34:08 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1298 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/todo b/todo index 4100ee2d..7719190c 100644 --- a/todo +++ b/todo @@ -23,9 +23,12 @@ Cleanups: - silence generation should be moved into the core to avoid races and code duplication in the backends - pdispatch: split large memory blocks when sending -- sysv shm -- posix_memalign -- test sample upload +- don't read/write audio data from/to ALSA devices if noone is listening + +Test: +- autoload +- sample upload + SHM +- SHM revoke stuff Auth/Crypto: - ssl -- cgit From 79b26280cc11cbb0d12185ba8226eeb5e7652467 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 18:28:04 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1299 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/todo b/todo index 7719190c..4b52e7f0 100644 --- a/todo +++ b/todo @@ -27,8 +27,6 @@ Cleanups: Test: - autoload -- sample upload + SHM -- SHM revoke stuff Auth/Crypto: - ssl @@ -52,6 +50,8 @@ Features: (switch to capture when a recording client connects and drop playback during that time) - Support for device selection in waveout driver +- beefup module-volume-restore to restore the device a stream was connected to, too +- add an API to libpulse for allocating memory from the pa_context memory pool Long term: - pass meta info for hearing impaired -- cgit From c0b3e8b34605e902f2aed311b0ed393aadd9592d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 18:57:33 +0000 Subject: when transferring large memory chunks of a pa_pstream, split them up git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1300 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/pstream.c | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index fa5b2788..511972d9 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -78,7 +78,8 @@ enum { typedef uint32_t pa_pstream_descriptor[PA_PSTREAM_DESCRIPTOR_MAX]; #define PA_PSTREAM_DESCRIPTOR_SIZE (PA_PSTREAM_DESCRIPTOR_MAX*sizeof(uint32_t)) -#define FRAME_SIZE_MAX PA_SCACHE_ENTRY_SIZE_MAX /* allow uploading a single sample in one frame at max */ +#define FRAME_SIZE_MAX_ALLOW PA_SCACHE_ENTRY_SIZE_MAX /* allow uploading a single sample in one frame at max */ +#define FRAME_SIZE_MAX_USE (1024*64) struct item_info { enum { @@ -323,7 +324,7 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *cre } void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek_mode, const pa_memchunk *chunk) { - struct item_info *i; + size_t length, idx; assert(p); assert(p->ref >= 1); @@ -333,19 +334,34 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa if (p->dead) return; - i = pa_xnew(struct item_info, 1); - i->type = PA_PSTREAM_ITEM_MEMBLOCK; - i->chunk = *chunk; - i->channel = channel; - i->offset = offset; - i->seek_mode = seek_mode; + length = chunk->length; + idx = 0; + + while (length > 0) { + struct item_info *i; + size_t n; + + i = pa_xnew(struct item_info, 1); + i->type = PA_PSTREAM_ITEM_MEMBLOCK; + + n = length < FRAME_SIZE_MAX_USE ? length : FRAME_SIZE_MAX_USE; + i->chunk.index = chunk->index + idx; + i->chunk.length = n; + i->chunk.memblock = pa_memblock_ref(chunk->memblock); + + i->channel = channel; + i->offset = offset; + i->seek_mode = seek_mode; #ifdef HAVE_CREDS - i->with_creds = 0; + i->with_creds = 0; #endif + + pa_queue_push(p->send_queue, i); - pa_memblock_ref(i->chunk.memblock); - - pa_queue_push(p->send_queue, i); + idx += n; + length -= n; + } + p->mainloop->defer_enable(p->defer_event, 1); } @@ -599,7 +615,7 @@ static int do_read(pa_pstream *p) { length = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]); - if (length > FRAME_SIZE_MAX) { + if (length > FRAME_SIZE_MAX_ALLOW) { pa_log_warn("Recieved invalid frame size : %lu", (unsigned long) length); return -1; } -- cgit From ce11b1f23098e07742f71c878b7a174791ccee22 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 18:58:17 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1301 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 - 1 file changed, 1 deletion(-) diff --git a/todo b/todo index 4b52e7f0..4f2a8f3a 100644 --- a/todo +++ b/todo @@ -22,7 +22,6 @@ Cleanups: - use software volume when hardware doesn't support all channels (alsa done) - silence generation should be moved into the core to avoid races and code duplication in the backends -- pdispatch: split large memory blocks when sending - don't read/write audio data from/to ALSA devices if noone is listening Test: -- cgit From bf62e77f71733cd458df6fc02c6d9eda82a8e0c4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 23:04:04 +0000 Subject: fix a bad memory access git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1302 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/source-output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index a2fc8519..352fce14 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -301,7 +301,7 @@ pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { pa_source *origin; - pa_resampler *new_resampler; + pa_resampler *new_resampler = NULL; assert(o); assert(o->ref >= 1); -- cgit From bffde5da05806ed1801b29b0440e9f542b3a6017 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 23:06:45 +0000 Subject: If a client leaves the sink/source for a stream unspecified by passing NULL as sink/source name sink/source we should pass NULL to pa_sink_input_new()/pa_source_output_new() as too. This allows hooks to change the sink/source device only if it is left unspecified by the client git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1303 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 21 +++++++++++++-------- src/pulsecore/protocol-native.c | 34 ++++++++++++++++++---------------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index c96a98b9..80aeb27b 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -327,7 +327,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t int32_t format, rate; pa_sample_spec ss; size_t l; - pa_sink *sink; + pa_sink *sink = NULL; pa_sink_input_new_data sdata; assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); @@ -344,8 +344,11 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t format_esd2native(format, c->swap_byte_order, &ss); CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification"); - sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1); - CHECK_VALIDITY(sink, "No such sink"); + + if (c->protocol->sink_name) { + sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1); + CHECK_VALIDITY(sink, "No such sink"); + } strncpy(name, data, sizeof(name)); name[sizeof(name)-1] = 0; @@ -397,7 +400,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length) { char name[ESD_NAME_MAX], *utf8_name; int32_t format, rate; - pa_source *source; + pa_source *source = NULL; pa_sample_spec ss; size_t l; pa_source_output_new_data sdata; @@ -431,10 +434,12 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co } } else { assert(request == ESD_PROTO_STREAM_REC); - - if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) { - pa_log("no such source."); - return -1; + + if (c->protocol->source_name) { + if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) { + pa_log("no such source."); + return -1; + } } } diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 40a83973..0f015071 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -319,7 +319,7 @@ static struct record_stream* record_stream_new( size_t base; pa_source_output_new_data data; - assert(c && source && ss && name && maxlength); + assert(c && ss && name && maxlength); pa_source_output_new_data_init(&data); data.source = source; @@ -330,7 +330,7 @@ static struct record_stream* record_stream_new( data.module = c->protocol->module; data.client = c->client; - if (!(source_output = pa_source_output_new(source->core, &data, 0))) + if (!(source_output = pa_source_output_new(c->protocol->core, &data, 0))) return NULL; s = pa_xnew(struct record_stream, 1); @@ -389,7 +389,7 @@ static struct playback_stream* playback_stream_new( int64_t start_index; pa_sink_input_new_data data; - assert(c && sink && ss && name && maxlength); + assert(c && ss && name && maxlength); /* Find syncid group */ for (ssync = pa_idxset_first(c->output_streams, &idx); ssync; ssync = pa_idxset_next(c->output_streams, &idx)) { @@ -402,8 +402,8 @@ static struct playback_stream* playback_stream_new( } /* Synced streams must connect to the same sink */ - if (ssync && ssync->sink_input->sink != sink) - return NULL; + if (ssync) + sink = ssync->sink_input->sink; pa_sink_input_new_data_init(&data); data.sink = sink; @@ -415,7 +415,7 @@ static struct playback_stream* playback_stream_new( data.module = c->protocol->module; data.client = c->client; - if (!(sink_input = pa_sink_input_new(sink->core, &data, 0))) + if (!(sink_input = pa_sink_input_new(c->protocol->core, &data, 0))) return NULL; s = pa_xnew(struct playback_stream, 1); @@ -725,7 +725,7 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC pa_sample_spec ss; pa_channel_map map; pa_tagstruct *reply; - pa_sink *sink; + pa_sink *sink = NULL; pa_cvolume volume; int corked; @@ -761,12 +761,13 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, maxlength > 0 && maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); - if (sink_index != PA_INVALID_INDEX) + if (sink_index != PA_INVALID_INDEX) { sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); - else + CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); + } else if (sink_name) { sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1); - - CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); + } s = playback_stream_new(c, sink, &ss, &map, name, maxlength, tlength, prebuf, minreq, &volume, syncid); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); @@ -844,7 +845,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_sample_spec ss; pa_channel_map map; pa_tagstruct *reply; - pa_source *source; + pa_source *source = NULL; int corked; assert(c && t && c->protocol && c->protocol->core); @@ -869,12 +870,13 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); - if (source_index != PA_INVALID_INDEX) + if (source_index != PA_INVALID_INDEX) { source = pa_idxset_get_by_index(c->protocol->core->sources, source_index); - else + CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY); + } else if (source_name) { source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE, 1); - - CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY); + } s = record_stream_new(c, source, &ss, &map, name, maxlength, fragment_size); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); -- cgit From 3dbc4ae973070760bcc2d525fdb9dcbaecfd1835 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 23:08:50 +0000 Subject: restore the sink/source for a client in addition to the playback volume. This changes the file format of the table file. To avoid parse errors ~/.pulse/volume.table has been renamed to ~/.pulse/volume-restore.table git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1304 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-volume-restore.c | 176 ++++++++++++++++++++++++++++-------- 1 file changed, 140 insertions(+), 36 deletions(-) diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index 59c47743..efa59f40 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -41,19 +41,21 @@ #include #include #include +#include #include +#include #include #include "module-volume-restore-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Automatically restore volume of playback streams") +PA_MODULE_DESCRIPTION("Automatically restore the volume and the devices of streams") PA_MODULE_USAGE("table=") PA_MODULE_VERSION(PACKAGE_VERSION) #define WHITESPACE "\n\r \t" -#define DEFAULT_VOLUME_TABLE_FILE "volume.table" +#define DEFAULT_VOLUME_TABLE_FILE "volume-restore.table" static const char* const valid_modargs[] = { "table", @@ -62,13 +64,16 @@ static const char* const valid_modargs[] = { struct rule { char* name; + int volume_is_set; pa_cvolume volume; + char *sink; + char *source; }; struct userdata { pa_hashmap *hashmap; pa_subscription *subscription; - pa_hook_slot *hook_slot; + pa_hook_slot *sink_input_hook_slot, *source_output_hook_slot; int modified; char *table_file; }; @@ -114,7 +119,7 @@ static int load_rules(struct userdata *u) { FILE *f; int n = 0; int ret = -1; - char buf_name[256], buf_volume[256]; + char buf_name[256], buf_volume[256], buf_sink[256], buf_source[256]; char *ln = buf_name; f = u->table_file ? @@ -136,6 +141,7 @@ static int load_rules(struct userdata *u) { while (!feof(f)) { struct rule *rule; pa_cvolume v; + int v_is_set; if (!fgets(ln, sizeof(buf_name), f)) break; @@ -144,7 +150,7 @@ static int load_rules(struct userdata *u) { pa_strip_nl(ln); - if (ln[0] == '#' || !*ln ) + if (ln[0] == '#') continue; if (ln == buf_name) { @@ -152,28 +158,46 @@ static int load_rules(struct userdata *u) { continue; } - assert(ln == buf_volume); + if (ln == buf_volume) { + ln = buf_sink; + continue; + } - if (!parse_volume(buf_volume, &v)) { - pa_log("parse failure in %s:%u, stopping parsing", u->table_file, n); - goto finish; + if (ln == buf_sink) { + ln = buf_source; + continue; } + assert(ln == buf_source); + + if (buf_volume[0]) { + if (!parse_volume(buf_volume, &v)) { + pa_log("parse failure in %s:%u, stopping parsing", u->table_file, n); + goto finish; + } + + v_is_set = 1; + } else + v_is_set = 0; + ln = buf_name; if (pa_hashmap_get(u->hashmap, buf_name)) { pa_log("double entry in %s:%u, ignoring", u->table_file, n); - goto finish; + continue; } rule = pa_xnew(struct rule, 1); rule->name = pa_xstrdup(buf_name); - rule->volume = v; + if ((rule->volume_is_set = v_is_set)) + rule->volume = v; + rule->sink = buf_sink[0] ? pa_xstrdup(buf_sink) : NULL; + rule->source = buf_source[0] ? pa_xstrdup(buf_source) : NULL; pa_hashmap_put(u->hashmap, rule->name, rule); } - if (ln == buf_volume) { + if (ln != buf_name) { pa_log("invalid number of lines in %s.", u->table_file); goto finish; } @@ -209,12 +233,18 @@ static int save_rules(struct userdata *u) { while ((rule = pa_hashmap_iterate(u->hashmap, &state, NULL))) { unsigned i; - fprintf(f, "%s\n%u", rule->name, rule->volume.channels); - - for (i = 0; i < rule->volume.channels; i++) - fprintf(f, " %u", rule->volume.values[i]); + fprintf(f, "%s\n", rule->name); - fprintf(f, "\n"); + if (rule->volume_is_set) { + fprintf(f, "%u", rule->volume.channels); + + for (i = 0; i < rule->volume.channels; i++) + fprintf(f, " %u", rule->volume.values[i]); + } + + fprintf(f, "\n%s\n%s\n", + rule->sink ? rule->sink : "", + rule->source ? rule->source : ""); } ret = 0; @@ -260,7 +290,8 @@ static char* client_name(pa_client *c) { static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { struct userdata *u = userdata; - pa_sink_input *si; + pa_sink_input *si = NULL; + pa_source_output *so = NULL; struct rule *r; char *name; @@ -268,36 +299,80 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 assert(u); if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW) && - t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE)) + t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) && + t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW) && + t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE)) return; + + if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT) { + if (!(si = pa_idxset_get_by_index(c->sink_inputs, idx))) + return; - if (!(si = pa_idxset_get_by_index(c->sink_inputs, idx))) - return; - - if (!si->client || !(name = client_name(si->client))) - return; + if (!si->client || !(name = client_name(si->client))) + return; + } else { + assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT); + + if (!(so = pa_idxset_get_by_index(c->source_outputs, idx))) + return; + + if (!so->client || !(name = client_name(so->client))) + return; + } if ((r = pa_hashmap_get(u->hashmap, name))) { pa_xfree(name); - if (!pa_cvolume_equal(pa_sink_input_get_volume(si), &r->volume)) { - pa_log_info("Saving volume for <%s>", r->name); - r->volume = *pa_sink_input_get_volume(si); - u->modified = 1; + if (si) { + + if (!r->volume_is_set || !pa_cvolume_equal(pa_sink_input_get_volume(si), &r->volume)) { + pa_log_info("Saving volume for <%s>", r->name); + r->volume = *pa_sink_input_get_volume(si); + r->volume_is_set = 1; + u->modified = 1; + } + + if (!r->sink || strcmp(si->sink->name, r->sink) != 0) { + pa_log_info("Saving sink for <%s>", r->name); + pa_xfree(r->sink); + r->sink = pa_xstrdup(si->sink->name); + u->modified = 1; + } + } else { + assert(so); + + if (!r->source || strcmp(so->source->name, r->source) != 0) { + pa_log_info("Saving source for <%s>", r->name); + pa_xfree(r->source); + r->source = pa_xstrdup(so->source->name); + u->modified = 1; + } } + } else { pa_log_info("Creating new entry for <%s>", name); r = pa_xnew(struct rule, 1); r->name = name; - r->volume = *pa_sink_input_get_volume(si); - pa_hashmap_put(u->hashmap, r->name, r); + if (si) { + r->volume = *pa_sink_input_get_volume(si); + r->volume_is_set = 1; + r->sink = pa_xstrdup(si->sink->name); + r->source = NULL; + } else { + assert(so); + r->volume_is_set = 0; + r->sink = NULL; + r->source = pa_xstrdup(so->source->name); + } + + pa_hashmap_put(u->hashmap, r->name, r); u->modified = 1; } } -static pa_hook_result_t hook_callback(pa_core *c, pa_sink_input_new_data *data, struct userdata *u) { +static pa_hook_result_t sink_input_hook_callback(pa_core *c, pa_sink_input_new_data *data, struct userdata *u) { struct rule *r; char *name; @@ -308,10 +383,34 @@ static pa_hook_result_t hook_callback(pa_core *c, pa_sink_input_new_data *data, if ((r = pa_hashmap_get(u->hashmap, name))) { - if (data->sample_spec_is_set && data->sample_spec.channels == r->volume.channels) { + if (r->volume_is_set && data->sample_spec.channels == r->volume.channels) { pa_log_info("Restoring volume for <%s>", r->name); pa_sink_input_new_data_set_volume(data, &r->volume); } + + if (!data->sink && r->sink) { + if ((data->sink = pa_namereg_get(c, r->sink, PA_NAMEREG_SINK, 1))) + pa_log_info("Restoring sink for <%s>", r->name); + } + } + + return PA_HOOK_OK; +} + +static pa_hook_result_t source_output_hook_callback(pa_core *c, pa_source_output_new_data *data, struct userdata *u) { + struct rule *r; + char *name; + + assert(data); + + if (!data->client || !(name = client_name(data->client))) + return PA_HOOK_OK; + + if ((r = pa_hashmap_get(u->hashmap, name))) { + if (!data->source && r->source) { + if ((data->source = pa_namereg_get(c, r->source, PA_NAMEREG_SOURCE, 1))) + pa_log_info("Restoring source for <%s>", r->name); + } } return PA_HOOK_OK; @@ -340,8 +439,9 @@ int pa__init(pa_core *c, pa_module*m) { if (load_rules(u) < 0) goto fail; - u->subscription = pa_subscription_new(c, PA_SUBSCRIPTION_MASK_SINK_INPUT, subscribe_callback, u); - u->hook_slot = pa_hook_connect(&c->hook_sink_input_new, (pa_hook_cb_t) hook_callback, u); + u->subscription = pa_subscription_new(c, PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscribe_callback, u); + u->sink_input_hook_slot = pa_hook_connect(&c->hook_sink_input_new, (pa_hook_cb_t) sink_input_hook_callback, u); + u->source_output_hook_slot = pa_hook_connect(&c->hook_source_output_new, (pa_hook_cb_t) source_output_hook_callback, u); pa_modargs_free(ma); return 0; @@ -360,6 +460,8 @@ static void free_func(void *p, void *userdata) { assert(r); pa_xfree(r->name); + pa_xfree(r->sink); + pa_xfree(r->source); pa_xfree(r); } @@ -375,8 +477,10 @@ void pa__done(pa_core *c, pa_module*m) { if (u->subscription) pa_subscription_free(u->subscription); - if (u->hook_slot) - pa_hook_slot_free(u->hook_slot); + if (u->sink_input_hook_slot) + pa_hook_slot_free(u->sink_input_hook_slot); + if (u->source_output_hook_slot) + pa_hook_slot_free(u->source_output_hook_slot); if (u->hashmap) { -- cgit From 3d32b96771ece395eb25988f2a644d97903ce513 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 23:09:23 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1305 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 - 1 file changed, 1 deletion(-) diff --git a/todo b/todo index 4f2a8f3a..befa5ee9 100644 --- a/todo +++ b/todo @@ -49,7 +49,6 @@ Features: (switch to capture when a recording client connects and drop playback during that time) - Support for device selection in waveout driver -- beefup module-volume-restore to restore the device a stream was connected to, too - add an API to libpulse for allocating memory from the pa_context memory pool Long term: -- cgit From 26201b27ec3233bb0f28539d63e49bb00d285d2a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 21 Aug 2006 22:37:09 +0000 Subject: fix pactl output (sink drivers and names where switched) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1306 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pactl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 028f71c8..110585f7 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -228,8 +228,8 @@ static void get_source_info_callback(pa_context *c, const pa_source_info *i, int "Latency: %0.0f usec\n" "Flags: %s%s%s\n", i->index, - i->driver, i->name, + i->driver, i->description, pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), -- cgit From 25c0640ac2206872f76df70368180c74153581e3 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 Aug 2006 07:12:50 +0000 Subject: Add an ifdef for when we do not have creds. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1307 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/context.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pulse/context.c b/src/pulse/context.c index b4641590..f2af4727 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -385,11 +385,13 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t /* Only enable SHM if both sides are owned by the same * user. This is a security measure because otherwise * data private to the user might leak. */ - + +#ifdef HAVE_CREDS const pa_creds *creds; if ((creds = pa_pdispatch_creds(pd))) if (getuid() == creds->uid) pa_pstream_use_shm(c->pstream, 1); +#endif } reply = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag); -- cgit From 8a16c731514a7d25e37ea70080e4c3d42fb5e5d4 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 Aug 2006 07:18:07 +0000 Subject: Fix call to pa_pstream_send_tagstruct(). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1308 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulse/context.c b/src/pulse/context.c index f2af4727..2f9106a5 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -456,7 +456,7 @@ static void setup_context(pa_context *c, pa_iochannel *io) { pa_pstream_send_tagstruct_with_creds(c->pstream, t, &ucred); } #else - pa_pstream_send_tagstruct(c->pstream, t, NULL); + pa_pstream_send_tagstruct(c->pstream, t); #endif pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL); -- cgit From 6e3d8af52078db439f9cacece690dfe96d353c42 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 Aug 2006 07:21:41 +0000 Subject: Add header for pa_cstrerror(). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1309 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-solaris.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index e13254e9..06de7d36 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -52,6 +52,7 @@ #include #include #include +#include #include "module-solaris-symdef.h" -- cgit From 1c320fe0b76995c50cfc4b54bfe90e859accdfc4 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 Aug 2006 07:23:47 +0000 Subject: Fix calls to pa_memblock_new(). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1310 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-solaris.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 06de7d36..d198ee61 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -202,7 +202,7 @@ static void do_read(struct userdata *u) { err = ioctl(u->fd, I_NREAD, &l); assert(err >= 0); - memchunk.memblock = pa_memblock_new(l, u->core->memblock_stat); + memchunk.memblock = pa_memblock_new(u->core->mempool, l); assert(memchunk.memblock); if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); @@ -589,7 +589,7 @@ int pa__init(pa_core *c, pa_module*m) { u->frame_size = pa_frame_size(&ss); u->buffer_size = buffer_size; - u->silence.memblock = pa_memblock_new(u->silence.length = CHUNK_SIZE, u->core->memblock_stat); + u->silence.memblock = pa_memblock_new(u->core->mempool, u->silence.length = CHUNK_SIZE); assert(u->silence.memblock); pa_silence_memblock(u->silence.memblock, &ss); u->silence.index = 0; -- cgit From 7bc71103fb51609edfb0d7893344871a00f1221d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 Aug 2006 07:25:45 +0000 Subject: Fix missing header for timeval helpers. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1311 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-solaris.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index d198ee61..8eaf6758 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include -- cgit From d964459a649ff8c8d73388bc810a2ea629abe5c9 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 Aug 2006 07:41:23 +0000 Subject: Fix detection of page size for non-POSIX systems. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1312 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 3 ++- src/pulsecore/memblock.c | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index b6b5f495..4aba536d 100644 --- a/configure.ac +++ b/configure.ac @@ -221,7 +221,8 @@ AC_FUNC_FORK AC_FUNC_GETGROUPS AC_FUNC_SELECT_ARGTYPES AC_CHECK_FUNCS([chmod chown getaddrinfo getgrgid_r getpwuid_r gettimeofday \ - getuid inet_ntop inet_pton nanosleep pipe setpgid setsid sigaction sleep]) + getuid inet_ntop inet_pton nanosleep pipe setpgid setsid sigaction sleep \ + sysconf]) AC_CHECK_FUNCS([mkfifo], [HAVE_MKFIFO=1], [HAVE_MKFIFO=0]) AM_CONDITIONAL(HAVE_MKFIFO, test "x$HAVE_MKFIFO" = "x1") diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index c34ddee5..9e5c5b81 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -443,8 +443,14 @@ pa_mempool* pa_mempool_new(int shared) { p = pa_xnew(pa_mempool, 1); +#ifdef HAVE_SYSCONF ps = (size_t) sysconf(_SC_PAGESIZE); - +#elif defined(PAGE_SIZE) + ps = (size_t) PAGE_SIZE; +#else + ps = 4096; /* Let's hope it's like x86. */ +#endif + p->block_size = (PA_MEMPOOL_SLOT_SIZE/ps)*ps; if (p->block_size < ps) -- cgit From b5ef414ec89f827b741e2656f3236db7b4195dbf Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 Aug 2006 11:37:53 +0000 Subject: Fix call to pa_memblock_new(). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1313 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-waveout.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index 2cc665b4..7965d015 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -217,7 +217,7 @@ static void do_read(struct userdata *u) waveInUnprepareHeader(u->hwi, hdr, sizeof(WAVEHDR)); if (hdr->dwBytesRecorded) { - memchunk.memblock = pa_memblock_new(hdr->dwBytesRecorded, u->core->memblock_stat); + memchunk.memblock = pa_memblock_new(u->core->mempool, hdr->dwBytesRecorded); assert(memchunk.memblock); memcpy((char*)memchunk.memblock->data, hdr->lpData, hdr->dwBytesRecorded); @@ -564,7 +564,7 @@ int pa__init(pa_core *c, pa_module*m) { } u->silence.length = u->fragment_size; - u->silence.memblock = pa_memblock_new(u->silence.length, u->core->memblock_stat); + u->silence.memblock = pa_memblock_new(u->core->mem, u->silence.length); assert(u->silence.memblock); pa_silence_memblock(u->silence.memblock, &ss); u->silence.index = 0; -- cgit From eeabf636732f784969bded89a215b3a0b263852f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 Aug 2006 11:38:46 +0000 Subject: Add missing header. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1314 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-waveout.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index 7965d015..d4fa121b 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -30,6 +30,7 @@ #include #include +#include #include #include -- cgit From 568c8ea7158d3f94793f27768afbd639558a932f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 Aug 2006 11:39:19 +0000 Subject: Fix typo. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1315 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-waveout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index d4fa121b..1222d4af 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -565,7 +565,7 @@ int pa__init(pa_core *c, pa_module*m) { } u->silence.length = u->fragment_size; - u->silence.memblock = pa_memblock_new(u->core->mem, u->silence.length); + u->silence.memblock = pa_memblock_new(u->core->mempool, u->silence.length); assert(u->silence.memblock); pa_silence_memblock(u->silence.memblock, &ss); u->silence.index = 0; -- cgit From 10bbc4b7c9e6aed6e0b281eaf23b8192e53233d7 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 Aug 2006 11:41:14 +0000 Subject: Fix detection of shared memory support and proper fallback. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1316 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 13 ++++--------- src/modules/module-oss-mmap.c | 3 +++ src/pulsecore/shm.c | 25 ++++++++++++++++++++++++- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/configure.ac b/configure.ac index 4aba536d..cb9ca2ef 100644 --- a/configure.ac +++ b/configure.ac @@ -144,7 +144,7 @@ AC_HEADER_STDC # POSIX AC_CHECK_HEADERS([arpa/inet.h glob.h grp.h netdb.h netinet/in.h \ netinet/in_systm.h netinet/ip.h netinet/tcp.h pwd.h sched.h \ - sys/resource.h sys/select.h sys/socket.h sys/wait.h \ + sys/mman.h sys/resource.h sys/select.h sys/socket.h sys/wait.h \ syslog.h]) AC_CHECK_HEADERS([regex.h], [HAVE_REGEX=1], [HAVE_REGEX=0]) AC_CHECK_HEADERS([sys/un.h], [HAVE_AF_UNIX=1], [HAVE_AF_UNIX=0]) @@ -202,12 +202,11 @@ AC_SEARCH_LIBS([pow], [m]) # POSIX AC_SEARCH_LIBS([sched_setscheduler], [rt]) AC_SEARCH_LIBS([dlopen], [dl]) +AC_SEARCH_LIBS([shm_open], [rt]) # BSD AC_SEARCH_LIBS([connect], [socket]) -AC_SEARCH_LIBS([shm_open], [rt]) - # Non-standard # This magic is needed so we do not needlessly add static libs to the win32 @@ -221,8 +220,8 @@ AC_FUNC_FORK AC_FUNC_GETGROUPS AC_FUNC_SELECT_ARGTYPES AC_CHECK_FUNCS([chmod chown getaddrinfo getgrgid_r getpwuid_r gettimeofday \ - getuid inet_ntop inet_pton nanosleep pipe setpgid setsid sigaction sleep \ - sysconf]) + getuid inet_ntop inet_pton nanosleep pipe posix_memalignsetpgid setsid \ + shm_open sigaction sleep sysconf]) AC_CHECK_FUNCS([mkfifo], [HAVE_MKFIFO=1], [HAVE_MKFIFO=0]) AM_CONDITIONAL(HAVE_MKFIFO, test "x$HAVE_MKFIFO" = "x1") @@ -243,10 +242,6 @@ AC_CHECK_FUNCS([lstat]) AC_CHECK_FUNCS([setresuid setresgid setreuid setregid seteuid setegid]) -# Memory mangement - -AC_CHECK_FUNCS([mmap posix_memalign madvise]) - #### POSIX threads #### ACX_PTHREAD diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index 0be6bbe2..5ab08287 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -34,7 +34,10 @@ #include #include #include + +#ifdef HAVE_SYS_MMAN_H #include +#endif #include #include diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c index 02528126..7c10bd0a 100644 --- a/src/pulsecore/shm.c +++ b/src/pulsecore/shm.c @@ -27,12 +27,15 @@ #include #include #include -#include #include #include #include #include +#ifdef HAVE_SYS_MMAN_H +#include +#endif + #include #include #include @@ -51,6 +54,8 @@ static char *segment_name(char *fn, size_t l, unsigned id) { return fn; } +#ifdef HAVE_SHM_OPEN + int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { char fn[32]; int fd = -1; @@ -239,3 +244,21 @@ fail: return -1; } + +#else /* HAVE_SHM_OPEN */ + +int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { + return -1; +} + +void pa_shm_free(pa_shm *m) { +} + +void pa_shm_punch(pa_shm *m, size_t offset, size_t size) { +} + +int pa_shm_attach_ro(pa_shm *m, unsigned id) { + return -1; +} + +#endif /* HAVE_SHM_OPEN */ -- cgit From 22d8e0e75e05f8c414df17e4dedfb310397483ea Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 22 Aug 2006 12:04:55 +0000 Subject: fix typo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1317 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index cb9ca2ef..c337930b 100644 --- a/configure.ac +++ b/configure.ac @@ -220,7 +220,7 @@ AC_FUNC_FORK AC_FUNC_GETGROUPS AC_FUNC_SELECT_ARGTYPES AC_CHECK_FUNCS([chmod chown getaddrinfo getgrgid_r getpwuid_r gettimeofday \ - getuid inet_ntop inet_pton nanosleep pipe posix_memalignsetpgid setsid \ + getuid inet_ntop inet_pton nanosleep pipe posix_memalign setpgid setsid \ shm_open sigaction sleep sysconf]) AC_CHECK_FUNCS([mkfifo], [HAVE_MKFIFO=1], [HAVE_MKFIFO=0]) -- cgit From fef4a2059915dc30711be1f6d514ef3cce61bcc4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 22 Aug 2006 12:29:41 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1318 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 + 1 file changed, 1 insertion(+) diff --git a/todo b/todo index befa5ee9..6d263c2b 100644 --- a/todo +++ b/todo @@ -50,6 +50,7 @@ Features: that time) - Support for device selection in waveout driver - add an API to libpulse for allocating memory from the pa_context memory pool +- allow buffer metric changes during runtime Long term: - pass meta info for hearing impaired -- cgit From cf7b401ac61f7dd3b30adba2660a3ea4059f4677 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 Aug 2006 12:45:43 +0000 Subject: Fix up portability of memory pool handling a bit. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1319 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/shm.c | 76 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c index 7c10bd0a..806a0320 100644 --- a/src/pulsecore/shm.c +++ b/src/pulsecore/shm.c @@ -54,8 +54,6 @@ static char *segment_name(char *fn, size_t l, unsigned id) { return fn; } -#ifdef HAVE_SHM_OPEN - int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { char fn[32]; int fd = -1; @@ -90,9 +88,10 @@ int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { m->do_unlink = 0; } else { +#ifdef HAVE_SHM_OPEN pa_random(&m->id, sizeof(m->id)); segment_name(fn, sizeof(fn), m->id); - + if ((fd = shm_open(fn, O_RDWR|O_CREAT|O_EXCL, mode & 0444)) < 0) { pa_log("shm_open() failed: %s", pa_cstrerror(errno)); goto fail; @@ -110,6 +109,9 @@ int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { close(fd); m->do_unlink = 1; +#else + return -1; +#endif } m->shared = shared; @@ -118,40 +120,52 @@ int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { fail: +#ifdef HAVE_SHM_OPEN if (fd >= 0) { shm_unlink(fn); close(fd); } +#endif return -1; } void pa_shm_free(pa_shm *m) { - char fn[32]; - assert(m); - assert(m->ptr && m->ptr != MAP_FAILED); + assert(m->ptr); assert(m->size > 0); -#if !defined(MAP_ANONYMOUS) && defined(HAVE_POSIX_MEMALIGN) - if (!m->shared) +#ifdef MAP_FAILED + assert(m->ptr != MAP_FAILED); +#endif + + if (!m->shared) { +#ifdef MAP_ANONYMOUS + if (munmap(m->ptr, m->size) < 0) + pa_log("munmap() failed: %s", pa_cstrerror(errno)); +#elif defined(HAVE_POSIX_MEMALIGN) free(m->ptr); - else -#elif !defined(MAP_ANONYMOUS) - if (!m->shared) +#else pa_xfree(m->ptr); - else -#endif - - if (munmap(m->ptr, m->size) < 0) - pa_log("munmap() failed: %s", pa_cstrerror(errno)); +#endif + } else { +#ifdef HAVE_SHM_OPEN + if (munmap(m->ptr, m->size) < 0) + pa_log("munmap() failed: %s", pa_cstrerror(errno)); - if (m->do_unlink) { - segment_name(fn, sizeof(fn), m->id); - - if (shm_unlink(fn) < 0) - pa_log(__FILE__":shm_unlink(%s) failed: %s", fn, pa_cstrerror(errno)); - } + if (m->do_unlink) { + char fn[32]; + + segment_name(fn, sizeof(fn), m->id); + + if (shm_unlink(fn) < 0) + pa_log(__FILE__":shm_unlink(%s) failed: %s", fn, pa_cstrerror(errno)); + } +#else + /* We shouldn't be here without shm support */ + assert(0); +#endif + } memset(m, 0, sizeof(*m)); } @@ -160,11 +174,15 @@ void pa_shm_punch(pa_shm *m, size_t offset, size_t size) { void *ptr; assert(m); - assert(m->ptr && m->ptr != MAP_FAILED); + assert(m->ptr); assert(m->size > 0); assert(offset < m->size); assert(offset+size < m->size); +#ifdef MAP_FAILED + assert(m->ptr != MAP_FAILED); +#endif + /* You're welcome to implement this as NOOP on systems that don't * support it */ @@ -200,6 +218,8 @@ void pa_shm_punch(pa_shm *m, size_t offset, size_t size) { #endif } +#ifdef HAVE_SHM_OPEN + int pa_shm_attach_ro(pa_shm *m, unsigned id) { char fn[32]; int fd = -1; @@ -247,16 +267,6 @@ fail: #else /* HAVE_SHM_OPEN */ -int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { - return -1; -} - -void pa_shm_free(pa_shm *m) { -} - -void pa_shm_punch(pa_shm *m, size_t offset, size_t size) { -} - int pa_shm_attach_ro(pa_shm *m, unsigned id) { return -1; } -- cgit From 26bfce6281f475d04f122dee6a711c7c00496614 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 Aug 2006 12:46:05 +0000 Subject: Improve error messages a bit. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1320 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/main.c | 4 +++- src/pulsecore/core-util.c | 2 +- src/pulsecore/core.c | 5 ++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/daemon/main.c b/src/daemon/main.c index 8b816b9a..5d77282c 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -559,8 +559,10 @@ int main(int argc, char *argv[]) { mainloop = pa_mainloop_new(); assert(mainloop); - if (!(c = pa_core_new(pa_mainloop_get_api(mainloop), !conf->disable_shm))) + if (!(c = pa_core_new(pa_mainloop_get_api(mainloop), !conf->disable_shm))) { + pa_log("pa_core_new() failed."); goto finish; + } c->is_system_instance = !!conf->system_instance; diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index b504b6d3..5f72b342 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -184,7 +184,7 @@ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) { goto fail; } #else - fprintf(stderr, "FIXME: pa_make_secure_dir()\n"); + pa_log_warn("secure directory creation not supported on Win32."); #endif return 0; diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index c36a35bd..1a7382e5 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "core.h" @@ -48,8 +49,10 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) { pa_core* c; pa_mempool *pool; - if (!(pool = pa_mempool_new(shared))) + if (!(pool = pa_mempool_new(shared))) { + pa_log("pa_mempool_new() failed."); return NULL; + } c = pa_xnew(pa_core, 1); -- cgit From 7bf25407789a99eec9d77ec8b9f9ece8abe49589 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 Aug 2006 12:51:29 +0000 Subject: Fall back to creating a "normal" memory pool if unable to get a shared one. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1321 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/core.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index 1a7382e5..3b6434d7 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -49,11 +49,20 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) { pa_core* c; pa_mempool *pool; - if (!(pool = pa_mempool_new(shared))) { - pa_log("pa_mempool_new() failed."); - return NULL; + if (shared) { + if (!(pool = pa_mempool_new(shared))) { + pa_log_warn("failed to allocate shared memory pool. Falling back to a normal memory pool."); + shared = 0; + } + } + + if (!shared) { + if (!(pool = pa_mempool_new(shared))) { + pa_log("pa_mempool_new() failed."); + return NULL; + } } - + c = pa_xnew(pa_core, 1); c->mainloop = m; -- cgit From 0249651c8e46f2133f159baae1eac52e8b5a5e2f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 Aug 2006 15:20:57 +0000 Subject: Log when there is a problem opening the waveOut/waveIn device. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1322 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-waveout.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index 1222d4af..9c867fdb 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -481,16 +481,22 @@ int pa__init(pa_core *c, pa_module*m) { u = pa_xmalloc(sizeof(struct userdata)); if (record) { - if (waveInOpen(&hwi, WAVE_MAPPER, &wf, (DWORD_PTR)chunk_ready_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) + if (waveInOpen(&hwi, WAVE_MAPPER, &wf, (DWORD_PTR)chunk_ready_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { + pa_log("failed to open waveIn"); goto fail; - if (waveInStart(hwi) != MMSYSERR_NOERROR) + } + if (waveInStart(hwi) != MMSYSERR_NOERROR) { + pa_log("failed to start waveIn"); goto fail; + } pa_log_debug("Opened waveIn subsystem."); } if (playback) { - if (waveOutOpen(&hwo, WAVE_MAPPER, &wf, (DWORD_PTR)chunk_done_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) + if (waveOutOpen(&hwo, WAVE_MAPPER, &wf, (DWORD_PTR)chunk_done_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { + pa_log("failed to open waveOut"); goto fail; + } pa_log_debug("Opened waveOut subsystem."); } -- cgit From 306aea78d35486596627bcbbcb566d5f19bb9e21 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 Aug 2006 15:24:11 +0000 Subject: Fix memory leak in waveout module. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1323 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-waveout.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index 9c867fdb..f1861466 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -611,6 +611,9 @@ void pa__done(pa_core *c, pa_module*m) { if (!(u = m->userdata)) return; + + if (u->silence.memblock) + pa_memblock_unref(u->silence.memblock); if (u->event) c->mainloop->time_free(u->event); -- cgit From 095f35725d644e0284c4b2d99b6fab71290eaeaa Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 Aug 2006 15:36:37 +0000 Subject: Proceed with connect even when no cookie is loaded. Allows you to connect to server which do not require a cookie under all circumstances. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1324 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/context.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/pulse/context.c b/src/pulse/context.c index 2f9106a5..b700657b 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -434,10 +434,8 @@ static void setup_context(pa_context *c, pa_iochannel *io) { assert(!c->pdispatch); c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - if (!c->conf->cookie_valid) { - pa_context_fail(c, PA_ERR_AUTHKEY); - goto finish; - } + if (!c->conf->cookie_valid) + pa_log_warn("No cookie loaded. Attempting to connect without."); t = pa_tagstruct_command(c, PA_COMMAND_AUTH, &tag); pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION); @@ -463,8 +461,6 @@ static void setup_context(pa_context *c, pa_iochannel *io) { pa_context_set_state(c, PA_CONTEXT_AUTHORIZING); -finish: - pa_context_unref(c); } -- cgit From d194604402648fbab61bde3d1106fecb1b82dc83 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 Aug 2006 16:15:47 +0000 Subject: Remove silence generation in waveout module. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1325 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-waveout.c | 83 ++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 50 deletions(-) diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index f1861466..4043c136 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -75,11 +75,10 @@ struct userdata { uint32_t free_ofrags, free_ifrags; DWORD written_bytes; + int sink_underflow; int cur_ohdr, cur_ihdr; - unsigned int oremain; WAVEHDR *ohdrs, *ihdrs; - pa_memchunk silence; HWAVEOUT hwo; HWAVEIN hwi; @@ -110,8 +109,8 @@ static void update_usage(struct userdata *u) { static void do_write(struct userdata *u) { - uint32_t free_frags, remain; - pa_memchunk memchunk, *cur_chunk; + uint32_t free_frags; + pa_memchunk memchunk; WAVEHDR *hdr; MMRESULT res; @@ -119,13 +118,10 @@ static void do_write(struct userdata *u) return; EnterCriticalSection(&u->crit); - free_frags = u->free_ofrags; - u->free_ofrags = 0; - LeaveCriticalSection(&u->crit); - if (free_frags == u->fragments) + if (!u->sink_underflow && (free_frags == u->fragments)) pa_log_debug("WaveOut underflow!"); while (free_frags) { @@ -133,45 +129,39 @@ static void do_write(struct userdata *u) if (hdr->dwFlags & WHDR_PREPARED) waveOutUnprepareHeader(u->hwo, hdr, sizeof(WAVEHDR)); - remain = u->oremain; - while (remain) { - cur_chunk = &memchunk; + hdr->dwBufferLength = 0; + while (hdr->dwBufferLength < u->fragment_size) { + size_t len; - if (pa_sink_render(u->sink, remain, cur_chunk) < 0) { - /* - * Don't fill with silence unless we're getting close to - * underflowing. - */ - if (free_frags > u->fragments/2) - cur_chunk = &u->silence; - else { - EnterCriticalSection(&u->crit); + len = u->fragment_size - hdr->dwBufferLength; - u->free_ofrags += free_frags; + if (pa_sink_render(u->sink, len, &memchunk) < 0) + break; - LeaveCriticalSection(&u->crit); + assert(memchunk.memblock); + assert(memchunk.memblock->data); + assert(memchunk.length); - u->oremain = remain; - return; - } - } + if (memchunk.length < len) + len = memchunk.length; - assert(cur_chunk->memblock); - assert(cur_chunk->memblock->data); - assert(cur_chunk->length); + memcpy(hdr->lpData + hdr->dwBufferLength, + (char*)memchunk.memblock->data + memchunk.index, len); - memcpy(hdr->lpData + u->fragment_size - remain, - (char*)cur_chunk->memblock->data + cur_chunk->index, - (cur_chunk->length < remain)?cur_chunk->length:remain); + hdr->dwBufferLength += len; - remain -= (cur_chunk->length < remain)?cur_chunk->length:remain; + pa_memblock_unref(memchunk.memblock); + memchunk.memblock = NULL; + } - if (cur_chunk != &u->silence) { - pa_memblock_unref(cur_chunk->memblock); - cur_chunk->memblock = NULL; - } + /* Insufficient data in sink buffer? */ + if (hdr->dwBufferLength == 0) { + u->sink_underflow = 1; + break; } + u->sink_underflow = 0; + res = waveOutPrepareHeader(u->hwo, hdr, sizeof(WAVEHDR)); if (res != MMSYSERR_NOERROR) { pa_log_error(__FILE__ ": ERROR: Unable to prepare waveOut block: %d", @@ -183,12 +173,15 @@ static void do_write(struct userdata *u) res); } - u->written_bytes += u->fragment_size; + u->written_bytes += hdr->dwBufferLength; + + EnterCriticalSection(&u->crit); + u->free_ofrags--; + LeaveCriticalSection(&u->crit); free_frags--; u->cur_ohdr++; u->cur_ohdr %= u->fragments; - u->oremain = u->fragment_size; } } @@ -540,8 +533,7 @@ int pa__init(pa_core *c, pa_module*m) { u->fragment_size = frag_size - (frag_size % pa_frame_size(&ss)); u->written_bytes = 0; - - u->oremain = u->fragment_size; + u->sink_underflow = 1; u->poll_timeout = pa_bytes_to_usec(u->fragments * u->fragment_size / 10, &ss); @@ -570,12 +562,6 @@ int pa__init(pa_core *c, pa_module*m) { assert(u->ohdrs); } - u->silence.length = u->fragment_size; - u->silence.memblock = pa_memblock_new(u->core->mempool, u->silence.length); - assert(u->silence.memblock); - pa_silence_memblock(u->silence.memblock, &ss); - u->silence.index = 0; - u->module = m; m->userdata = u; @@ -611,9 +597,6 @@ void pa__done(pa_core *c, pa_module*m) { if (!(u = m->userdata)) return; - - if (u->silence.memblock) - pa_memblock_unref(u->silence.memblock); if (u->event) c->mainloop->time_free(u->event); -- cgit From b27ffbec8c815d0efa936063482b9bf0bc312103 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 Aug 2006 16:25:47 +0000 Subject: Remove silence generation in solaris module. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1326 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-solaris.c | 55 +++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 8eaf6758..90cf010b 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -80,11 +80,12 @@ struct userdata { pa_usec_t poll_timeout; pa_signal_event *sig; - pa_memchunk memchunk, silence; + pa_memchunk memchunk; uint32_t frame_size; uint32_t buffer_size; unsigned int written_bytes, read_bytes; + int sink_underflow; int fd; pa_module *module; @@ -119,7 +120,6 @@ static void update_usage(struct userdata *u) { static void do_write(struct userdata *u) { audio_info_t info; int err; - pa_memchunk *memchunk; size_t len; ssize_t r; @@ -145,7 +145,7 @@ static void do_write(struct userdata *u) { if (len > u->buffer_size) len = 0; - if (len == u->buffer_size) + if (!u->sink_underflow && (len == u->buffer_size)) pa_log_debug("Solaris buffer underflow!"); len -= len % u->frame_size; @@ -153,37 +153,39 @@ static void do_write(struct userdata *u) { if (len == 0) return; - memchunk = &u->memchunk; - - if (!memchunk->length) - if (pa_sink_render(u->sink, len, memchunk) < 0) - memchunk = &u->silence; + if (!u->memchunk.length) { + if (pa_sink_render(u->sink, len, &u->memchunk) < 0) { + u->sink_underflow = 1; + return; + } + } + + u->sink_underflow = 0; - assert(memchunk->memblock); - assert(memchunk->memblock->data); - assert(memchunk->length); + assert(u->memchunk.memblock); + assert(u->memchunk.memblock->data); + assert(u->memchunk.length); - if (memchunk->length < len) { - len = memchunk->length; + if (u->memchunk.length < len) { + len = u->memchunk.length; len -= len % u->frame_size; assert(len); } - if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, len)) < 0) { + if ((r = pa_iochannel_write(u->io, + (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, len)) < 0) { pa_log("write() failed: %s", pa_cstrerror(errno)); return; } assert(r % u->frame_size == 0); - if (memchunk != &u->silence) { - u->memchunk.index += r; - u->memchunk.length -= r; - - if (u->memchunk.length <= 0) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - } + u->memchunk.index += r; + u->memchunk.length -= r; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; } u->written_bytes += r; @@ -590,14 +592,11 @@ int pa__init(pa_core *c, pa_module*m) { u->frame_size = pa_frame_size(&ss); u->buffer_size = buffer_size; - u->silence.memblock = pa_memblock_new(u->core->mempool, u->silence.length = CHUNK_SIZE); - assert(u->silence.memblock); - pa_silence_memblock(u->silence.memblock, &ss); - u->silence.index = 0; - u->written_bytes = 0; u->read_bytes = 0; + u->sink_underflow = 1; + u->module = m; m->userdata = u; @@ -649,8 +648,6 @@ void pa__done(pa_core *c, pa_module*m) { if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); - if (u->silence.memblock) - pa_memblock_unref(u->silence.memblock); if (u->sink) { pa_sink_disconnect(u->sink); -- cgit From 79c4a6842c7e67a9e39d951d8ac2beab98100ae4 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 23 Aug 2006 07:57:43 +0000 Subject: Make the recording a bit more chunky so that we can fit in the pool and have efficient blocks. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1327 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-solaris.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 90cf010b..66968cb1 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -82,6 +82,8 @@ struct userdata { pa_memchunk memchunk; + unsigned int page_size; + uint32_t frame_size; uint32_t buffer_size; unsigned int written_bytes, read_bytes; @@ -193,7 +195,8 @@ static void do_write(struct userdata *u) { static void do_read(struct userdata *u) { pa_memchunk memchunk; - int err, l; + int err; + size_t l; ssize_t r; assert(u); @@ -205,6 +208,11 @@ static void do_read(struct userdata *u) { err = ioctl(u->fd, I_NREAD, &l); assert(err >= 0); + /* This is to make sure it fits in the memory pool. Also, a page + should be the most efficient transfer size. */ + if (l > u->page_size) + l = u->page_size; + memchunk.memblock = pa_memblock_new(u->core->mempool, l); assert(memchunk.memblock); if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { @@ -589,6 +597,10 @@ int pa__init(pa_core *c, pa_module*m) { u->memchunk.memblock = NULL; u->memchunk.length = 0; + + /* We use this to get a reasonable chunk size */ + u->page_size = sysconf(_SC_PAGESIZE); + u->frame_size = pa_frame_size(&ss); u->buffer_size = buffer_size; -- cgit From 2575b446372b249fddb2cc792c089985901de7f2 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 23 Aug 2006 07:58:07 +0000 Subject: fix typo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1328 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/memblock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 9e5c5b81..286f7b5a 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -246,7 +246,7 @@ pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) { b->type = PA_MEMBLOCK_POOL_EXTERNAL; b->data = mempool_slot_data(slot); } else { - pa_log_debug("Memory block to large for pool: %u > %u", length, p->block_size - sizeof(struct mempool_slot)); + pa_log_debug("Memory block too large for pool: %u > %u", length, p->block_size - sizeof(struct mempool_slot)); p->stat.n_too_large_for_pool++; return NULL; } -- cgit From 8f5b86b77d75b9e4287942c30d3b5d4c42b8afb2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 Aug 2006 22:28:53 +0000 Subject: fix handling of "mtu" module argument (patch by "theBear") git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1329 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/rtp/module-rtp-send.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 61dd0047..7bbfabee 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -81,6 +81,7 @@ static const char* const valid_modargs[] = { "rate", "destination", "port", + "mtu" , "loop", NULL }; -- cgit From aec3888ef2deb1dba51922fcf149115acea6476b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 24 Aug 2006 08:57:35 +0000 Subject: Add missing header. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1330 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/tests/interpol-test.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tests/interpol-test.c b/src/tests/interpol-test.c index 2df65a45..3ec8a18f 100644 --- a/src/tests/interpol-test.c +++ b/src/tests/interpol-test.c @@ -37,6 +37,10 @@ #include #endif +#ifdef HAVE_WINDOWS_H +#include +#endif + #include #include -- cgit From 8ead68fcb3fb7da981a42f4b502bdeabf96a62fb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 25 Aug 2006 12:12:13 +0000 Subject: activate HAL in the default config git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1331 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/default.pa.in | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in index 74148cd1..03122669 100755 --- a/src/daemon/default.pa.in +++ b/src/daemon/default.pa.in @@ -27,7 +27,11 @@ #load-module module-pipe-sink ### Automatically load driver modules depending on the hardware available -load-module module-detect +load-module module-hal-detect + +### Alternatively use the static hardware detection module (for systems that +### lack HAL support +#load-module module-detect ### Load audio drivers automatically on access #add-autoload-sink output module-oss device="/dev/dsp" sink_name=output source_name=input @@ -41,21 +45,24 @@ load-module module-detect load-module module-esound-protocol-unix load-module module-native-protocol-unix +### Network access (may be configured with paprefs, so leave this commented +### here if you plan to use paprefs) #load-module module-esound-protocol-tcp #load-module module-native-protocol-tcp #load-module module-zeroconf-publish -### Load the RTP reciever module +### Load the RTP reciever module (also configured via paprefs, see above) #load-module module-rtp-recv -### Load the RTP sender module -#load-module module-null-sink sink_name=rtp -#load-module module-rtp-send source=rtp_monitor +### Load the RTP sender module (also configured via paprefs, see above) +#load-module module-null-sink sink_name=rtp format=s16be channels=2 rate=44100 description="RTP Multicast Sink" +#load-module module-rtp-send source=rtp.monitor ### Automatically restore the volume of playback streams load-module module-volume-restore -### Automatically move streams to the default sink if the sink they are connected to dies +### Automatically move streams to the default sink if the sink they are +### connected to dies, similar for sources load-module module-rescue-streams ### Make some devices default -- cgit From 93e005ad3767eb08cb9542b4bc50f8fab81f5c07 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 25 Aug 2006 22:52:59 +0000 Subject: update module-tunnel to latest protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1332 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 67 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index de1a12c9..18c289a8 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -79,9 +79,6 @@ PA_MODULE_USAGE( PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_VERSION(PACKAGE_VERSION) -#define DEFAULT_SINK_NAME "tunnel" -#define DEFAULT_SOURCE_NAME "tunnel" - #define DEFAULT_TLENGTH (44100*2*2/10) //(10240*8) #define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2) #define DEFAULT_MINREQ 512 @@ -503,15 +500,33 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN } if (pa_tagstruct_getu32(t, &u->channel) < 0 || - pa_tagstruct_getu32(t, &u->device_index) < 0 || + pa_tagstruct_getu32(t, &u->device_index) < 0 #ifdef TUNNEL_SINK - pa_tagstruct_getu32(t, &u->requested_bytes) < 0 || + || pa_tagstruct_getu32(t, &u->requested_bytes) < 0 #endif - !pa_tagstruct_eof(t)) { - pa_log("invalid reply. (create stream)"); - die(u); - return; + ) + goto parse_error; + + if (u->version >= 9) { +#ifdef TUNNEL_SINK + uint32_t maxlength, tlength, prebuf, minreq; + + if (pa_tagstruct_getu32(t, &maxlength) < 0 || + pa_tagstruct_getu32(t, &tlength) < 0 || + pa_tagstruct_getu32(t, &prebuf) < 0 || + pa_tagstruct_getu32(t, &minreq) < 0) + goto parse_error; +#else + uint32_t maxlength, fragsize; + + if (pa_tagstruct_getu32(t, &maxlength) < 0 || + pa_tagstruct_getu32(t, &fragsize) < 0) + goto parse_error; +#endif } + + if (!pa_tagstruct_eof(t)) + goto parse_error; start_subscribe(u); request_info(u); @@ -520,6 +535,12 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN #ifdef TUNNEL_SINK send_bytes(u); #endif + + return; + +parse_error: + pa_log("invalid reply. (create stream)"); + die(u); } static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -550,12 +571,12 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t } #ifdef TUNNEL_SINK - snprintf(name, sizeof(name), "Tunnel from host '%s', user '%s', sink '%s'", + snprintf(name, sizeof(name), "Tunnel from host %s, user %s, sink %s", pa_get_host_name(hn, sizeof(hn)), pa_get_user_name(un, sizeof(un)), u->sink->name); #else - snprintf(name, sizeof(name), "Tunnel from host '%s', user '%s', source '%s'", + snprintf(name, sizeof(name), "Tunnel from host %s, user %s, source %s", pa_get_host_name(hn, sizeof(hn)), pa_get_user_name(un, sizeof(un)), u->source->name); @@ -859,7 +880,8 @@ int pa__init(pa_core *c, pa_module*m) { pa_sample_spec ss; pa_channel_map map; struct timeval ntv; - char *t; + char *t, *dn = NULL; + assert(c && m); @@ -915,7 +937,11 @@ int pa__init(pa_core *c, pa_module*m) { pa_socket_client_set_callback(u->client, on_connection, u); #ifdef TUNNEL_SINK - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { + + if (!(dn = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", NULL)))) + dn = pa_sprintf_malloc("tunnel.%s", u->server_name); + + if (!(u->sink = pa_sink_new(c, __FILE__, dn, 0, &ss, &map))) { pa_log("failed to create sink."); goto fail; } @@ -927,12 +953,16 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->get_hw_mute = sink_get_hw_mute; u->sink->set_hw_mute = sink_set_hw_mute; u->sink->userdata = u; - pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->sink_name ? u->sink_name : "", u->sink_name ? "@" : "", u->server_name)); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Tunnel to %s%s%s", u->sink_name ? u->sink_name : "", u->sink_name ? " on " : "", u->server_name)); pa_xfree(t); pa_sink_set_owner(u->sink, m); #else - if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) { + + if (!(dn = pa_xstrdup(pa_modargs_get_value(ma, "source_name", NULL)))) + dn = pa_sprintf_malloc("tunnel.%s", u->server_name); + + if (!(u->source = pa_source_new(c, __FILE__, dn, 0, &ss, &map))) { pa_log("failed to create source."); goto fail; } @@ -944,12 +974,14 @@ int pa__init(pa_core *c, pa_module*m) { u->source->set_hw_mute = source_set_hw_mute; u->source->userdata = u; - pa_source_set_description(u->source, t = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->source_name ? u->source_name : "", u->source_name ? "@" : "", u->server_name)); + pa_source_set_description(u->source, t = pa_sprintf_malloc("Tunnel to %s%s%s", u->source_name ? u->source_name : "", u->source_name ? " on " : "", u->server_name)); pa_xfree(t); pa_source_set_owner(u->source, m); #endif + pa_xfree(dn); + pa_gettimeofday(&ntv); ntv.tv_sec += LATENCY_INTERVAL; u->time_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, u); @@ -963,6 +995,9 @@ fail: if (ma) pa_modargs_free(ma); + + pa_xfree(dn); + return -1; } -- cgit From b8ea488b7654f447fff49811129001334b2db3fa Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 26 Aug 2006 19:00:22 +0000 Subject: fix module-combine when used on top of a tunnel sink git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1333 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-combine.c | 17 +++++++++++++++-- src/modules/module-tunnel.c | 10 +++++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 217fdae6..f3bb3fd3 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -217,6 +217,18 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { pa_sink_get_latency(u->master->sink_input->sink); } +static void sink_notify(pa_sink *s) { + struct userdata *u; + struct output *o; + + assert(s); + u = s->userdata; + assert(u); + + for (o = u->outputs; o; o = o->next) + pa_sink_notify(o->sink_input->sink); +} + static struct output *output_new(struct userdata *u, pa_sink *sink, int resample_method) { struct output *o = NULL; char t[256]; @@ -237,7 +249,7 @@ static struct output *output_new(struct userdata *u, pa_sink *sink, int resample 0, NULL); - snprintf(t, sizeof(t), "%s: output #%u", u->sink->name, u->n_outputs+1); + snprintf(t, sizeof(t), "Output stream #%u of sink %s", u->n_outputs+1, u->sink->name); pa_sink_input_new_data_init(&data); data.sink = sink; @@ -387,8 +399,9 @@ int pa__init(pa_core *c, pa_module*m) { } pa_sink_set_owner(u->sink, m); - pa_sink_set_description(u->sink, "Combined sink"); + pa_sink_set_description(u->sink, "Combined Sink"); u->sink->get_latency = sink_get_latency_cb; + u->sink->notify = sink_notify; u->sink->userdata = u; if (!(u->master = output_new(u, master_sink, resample_method))) { diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 18c289a8..18e1d97d 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -266,6 +266,8 @@ static void send_bytes(struct userdata *u) { pa_pstream_send_memblock(u->pstream, u->channel, 0, PA_SEEK_RELATIVE, &chunk); pa_memblock_unref(chunk.memblock); +/* pa_log("sent %lu", (unsigned long) chunk.length); */ + if (chunk.length > u->requested_bytes) u->requested_bytes = 0; else @@ -330,6 +332,8 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G pa_gettimeofday(&now); + /* FIXME! This could use some serious love. */ + if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) { /* local and remote seem to have synchronized clocks */ #ifdef TUNNEL_SINK @@ -350,7 +354,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G u->host_latency = 0; #endif -/* pa_log("estimated host latency: %0.0f usec", (double) u->host_latency); */ +/* pa_log("estimated host latency: %0.0f usec", (double) u->host_latency); */ } static void request_latency(struct userdata *u) { @@ -631,7 +635,6 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { die(u); } - static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) { struct userdata *u = userdata; assert(p && packet && u); @@ -772,6 +775,7 @@ static int sink_set_hw_mute(pa_sink *sink) { return 0; } + #else static pa_usec_t source_get_latency(pa_source *source) { struct userdata *u; @@ -946,12 +950,12 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - u->sink->notify = sink_notify; u->sink->get_latency = sink_get_latency; u->sink->get_hw_volume = sink_get_hw_volume; u->sink->set_hw_volume = sink_set_hw_volume; u->sink->get_hw_mute = sink_get_hw_mute; u->sink->set_hw_mute = sink_set_hw_mute; + u->sink->notify = sink_notify; u->sink->userdata = u; pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Tunnel to %s%s%s", u->sink_name ? u->sink_name : "", u->sink_name ? " on " : "", u->server_name)); pa_xfree(t); -- cgit From bc87a5869dc80ea2faed9c0ebc9f97a2e40ce2dd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 26 Aug 2006 19:22:14 +0000 Subject: bump version and sonames git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1334 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index c337930b..33b305e7 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ AC_PREREQ(2.57) m4_define(PA_MAJOR, [0]) m4_define(PA_MINOR, [9]) -m4_define(PA_MICRO, [4]) +m4_define(PA_MICRO, [5]) AC_INIT([pulseaudio], PA_MAJOR.PA_MINOR.PA_MICRO,[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([src/daemon/main.c]) @@ -36,11 +36,11 @@ AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/pulseaudio/]) AC_SUBST(PA_API_VERSION, 10) AC_SUBST(PA_PROTOCOL_VERSION, 10) -AC_SUBST(LIBPULSE_VERSION_INFO, [0:2:0]) -AC_SUBST(LIBPULSECORE_VERSION_INFO, [1:1:0]) +AC_SUBST(LIBPULSE_VERSION_INFO, [1:0:1]) +AC_SUBST(LIBPULSECORE_VERSION_INFO, [2:0:0]) AC_SUBST(LIBPULSE_SIMPLE_VERSION_INFO, [0:0:0]) AC_SUBST(LIBPULSE_BROWSE_VERSION_INFO, [1:0:1]) -AC_SUBST(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO, [0:1:0]) +AC_SUBST(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO, [0:2:0]) if type -p stow > /dev/null && test -d /usr/local/stow ; then AC_MSG_NOTICE([*** Found /usr/local/stow: default install prefix set to /usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION} ***]) -- cgit From 1ed33478e531eba112dd421cbcaa42202d314135 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 27 Aug 2006 13:04:56 +0000 Subject: increase operation timeout git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1336 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulse/internal.h b/src/pulse/internal.h index fa7d5bbd..4eef4b4a 100644 --- a/src/pulse/internal.h +++ b/src/pulse/internal.h @@ -41,7 +41,7 @@ #include "client-conf.h" -#define DEFAULT_TIMEOUT (10) +#define DEFAULT_TIMEOUT (30) struct pa_context { int ref; -- cgit From cd4767305cc73a019564754430af470da3882553 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 28 Aug 2006 05:15:46 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1337 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 + 1 file changed, 1 insertion(+) diff --git a/todo b/todo index 6d263c2b..34935c6f 100644 --- a/todo +++ b/todo @@ -51,6 +51,7 @@ Features: - Support for device selection in waveout driver - add an API to libpulse for allocating memory from the pa_context memory pool - allow buffer metric changes during runtime +- "include" command in configuration files. should have glob support. Long term: - pass meta info for hearing impaired -- cgit From 5ecbd9edeead63b7ac694b728bb8dda5811438f8 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 28 Aug 2006 06:25:41 +0000 Subject: Add PulseAudio logo to tree. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1338 fefdeb5f-60dc-0310-8127-8f9354f1896f --- pulseaudio.svg | 287 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 287 insertions(+) create mode 100644 pulseaudio.svg diff --git a/pulseaudio.svg b/pulseaudio.svg new file mode 100644 index 00000000..a79e03da --- /dev/null +++ b/pulseaudio.svg @@ -0,0 +1,287 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + PulseAudio logotype + 2006-08-28 + + + Pierre Ossman <ossman@cendio.se> for Cendio AB + + + + + + + + + + Rafael Jannone (basic idea) + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit From a6339448202d01a922934dd85d0efa851f81dd3d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 28 Aug 2006 19:16:00 +0000 Subject: fix an misdesigned assert() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1339 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/shm.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c index 806a0320..19731b5f 100644 --- a/src/pulsecore/shm.c +++ b/src/pulsecore/shm.c @@ -156,10 +156,10 @@ void pa_shm_free(pa_shm *m) { if (m->do_unlink) { char fn[32]; - segment_name(fn, sizeof(fn), m->id); - - if (shm_unlink(fn) < 0) - pa_log(__FILE__":shm_unlink(%s) failed: %s", fn, pa_cstrerror(errno)); + segment_name(fn, sizeof(fn), m->id); + + if (shm_unlink(fn) < 0) + pa_log(" shm_unlink(%s) failed: %s", fn, pa_cstrerror(errno)); } #else /* We shouldn't be here without shm support */ @@ -176,8 +176,7 @@ void pa_shm_punch(pa_shm *m, size_t offset, size_t size) { assert(m); assert(m->ptr); assert(m->size > 0); - assert(offset < m->size); - assert(offset+size < m->size); + assert(offset+size <= m->size); #ifdef MAP_FAILED assert(m->ptr != MAP_FAILED); -- cgit From 91d802582362e0d81f291cd4955b278a85528e51 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 29 Aug 2006 01:15:09 +0000 Subject: add libatomic-ops to hard dependencies git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1340 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/configure.ac b/configure.ac index 33b305e7..42bee9a8 100644 --- a/configure.ac +++ b/configure.ac @@ -320,6 +320,18 @@ PKG_CHECK_MODULES(LIBSNDFILE, [ sndfile >= 1.0.10 ]) AC_SUBST(LIBSNDFILE_CFLAGS) AC_SUBST(LIBSNDFILE_LIBS) +#### atomic-ops ### + +AC_CHECK_HEADERS([atomic_ops.h], [], [ +AC_MSG_ERROR([*** libatomic-ops headers not found]) +]) + +AC_SEARCH_LIBS([AO_spin], [atomic_ops], [], [ +AC_MSG_ERROR([*** libatomic-ops library file not found]) +]) + + + #### OSS support (optional) #### AC_ARG_ENABLE([oss], -- cgit From 9948cb09a3e1b976ad1705df06ef24216a61bf85 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 29 Aug 2006 01:15:51 +0000 Subject: add lock-free reference counting macros, based on libatomic-ops git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1341 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 4 +++- src/pulsecore/refcnt.h | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/pulsecore/refcnt.h diff --git a/src/Makefile.am b/src/Makefile.am index c4988d8e..c9942cff 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -527,7 +527,9 @@ pulsecoreinclude_HEADERS = \ pulsecore/strbuf.h \ pulsecore/tokenizer.h \ pulsecore/creds.h \ - pulsecore/shm.h + pulsecore/shm.h \ + pulsecore/llist.h \ + pulsecore/refcnt.h lib_LTLIBRARIES += libpulsecore.la diff --git a/src/pulsecore/refcnt.h b/src/pulsecore/refcnt.h new file mode 100644 index 00000000..fade9aa4 --- /dev/null +++ b/src/pulsecore/refcnt.h @@ -0,0 +1,41 @@ +#ifndef foopulserefcntfoo +#define foopulserefcntfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#define PA_REFCNT_DECLARE volatile AO_t _ref + +#define PA_REFCNT_INIT(p) \ + AO_store_release_write(&(p)->_ref, 1) + +#define PA_REFCNT_INC(p) \ + AO_fetch_and_add1_release_write(&(p)->_ref) + +#define PA_REFCNT_DEC(p) \ + (AO_fetch_and_sub1_release_write(&(p)->_ref)-1) + +#define PA_REFCNT_VALUE(p) \ + AO_load_acquire_read(&(p)->_ref) + +#endif -- cgit From 327e0cd8e1e81999dd855e38d3cb3b414aeadc7a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 29 Aug 2006 01:16:47 +0000 Subject: modify memory block reference counting to use the new reference counting API git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1342 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/memblock.c | 24 ++++++++++++------------ src/pulsecore/memblock.h | 3 ++- src/pulsecore/memchunk.c | 6 ++++-- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 286f7b5a..516ade13 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -170,7 +170,7 @@ static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length) { b = pa_xmalloc(sizeof(pa_memblock) + length); b->type = PA_MEMBLOCK_APPENDED; b->read_only = 0; - b->ref = 1; + PA_REFCNT_INIT(b); b->length = length; b->data = (uint8_t*) b + sizeof(pa_memblock); b->pool = p; @@ -253,7 +253,7 @@ pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) { b->length = length; b->read_only = 0; - b->ref = 1; + PA_REFCNT_INIT(b); b->pool = p; stat_add(b); @@ -270,7 +270,7 @@ pa_memblock *pa_memblock_new_fixed(pa_mempool *p, void *d, size_t length, int re b = pa_xnew(pa_memblock, 1); b->type = PA_MEMBLOCK_FIXED; b->read_only = read_only; - b->ref = 1; + PA_REFCNT_INIT(b); b->length = length; b->data = d; b->pool = p; @@ -290,7 +290,7 @@ pa_memblock *pa_memblock_new_user(pa_mempool *p, void *d, size_t length, void (* b = pa_xnew(pa_memblock, 1); b->type = PA_MEMBLOCK_USER; b->read_only = read_only; - b->ref = 1; + PA_REFCNT_INIT(b); b->length = length; b->data = d; b->per_type.user.free_cb = free_cb; @@ -302,17 +302,17 @@ pa_memblock *pa_memblock_new_user(pa_mempool *p, void *d, size_t length, void (* pa_memblock* pa_memblock_ref(pa_memblock*b) { assert(b); - assert(b->ref >= 1); - - b->ref++; + assert(PA_REFCNT_VALUE(b) > 0); + + PA_REFCNT_INC(b); return b; } void pa_memblock_unref(pa_memblock*b) { assert(b); - assert(b->ref >= 1); + assert(PA_REFCNT_VALUE(b) > 0); - if ((--(b->ref)) > 0) + if (PA_REFCNT_DEC(b) > 0) return; stat_remove(b); @@ -403,10 +403,10 @@ finish: void pa_memblock_unref_fixed(pa_memblock *b) { assert(b); - assert(b->ref >= 1); + assert(PA_REFCNT_VALUE(b) > 0); assert(b->type == PA_MEMBLOCK_FIXED); - if (b->ref > 1) + if (PA_REFCNT_VALUE(b) > 1) memblock_make_local(b); pa_memblock_unref(b); @@ -615,7 +615,7 @@ pa_memblock* pa_memimport_get(pa_memimport *i, uint32_t block_id, uint32_t shm_i b = pa_xnew(pa_memblock, 1); b->type = PA_MEMBLOCK_IMPORTED; b->read_only = 1; - b->ref = 1; + PA_REFCNT_INIT(b); b->length = size; b->data = (uint8_t*) seg->memory.ptr + offset; b->pool = i->pool; diff --git a/src/pulsecore/memblock.h b/src/pulsecore/memblock.h index 620bf726..60a0c900 100644 --- a/src/pulsecore/memblock.h +++ b/src/pulsecore/memblock.h @@ -26,6 +26,7 @@ #include #include +#include /* A pa_memblock is a reference counted memory block. PulseAudio * passed references to pa_memblocks around instead of copying @@ -56,7 +57,7 @@ typedef void (*pa_memexport_revoke_cb_t)(pa_memexport *e, uint32_t block_id, voi struct pa_memblock { pa_memblock_type_t type; int read_only; /* boolean */ - unsigned ref; /* the reference counter */ + PA_REFCNT_DECLARE; /* the reference counter */ size_t length; void *data; pa_mempool *pool; diff --git a/src/pulsecore/memchunk.c b/src/pulsecore/memchunk.c index bcf0ce04..1dbad2b9 100644 --- a/src/pulsecore/memchunk.c +++ b/src/pulsecore/memchunk.c @@ -38,9 +38,11 @@ void pa_memchunk_make_writable(pa_memchunk *c, size_t min) { assert(c); assert(c->memblock); - assert(c->memblock->ref >= 1); + assert(PA_REFCNT_VALUE(c->memblock) > 0); - if (c->memblock->ref == 1 && !c->memblock->read_only && c->memblock->length >= c->index+min) + if (PA_REFCNT_VALUE(c->memblock) == 1 && + !c->memblock->read_only && + c->memblock->length >= c->index+min) return; l = c->length; -- cgit From 5264d235d25f04d3cd5796e751a66cb92453be73 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 29 Aug 2006 02:01:39 +0000 Subject: make pa_mempool_stat thread-safe/lock-free git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1343 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/cli-command.c | 20 ++++++------ src/pulsecore/memblock.c | 67 +++++++++++++++++++++-------------------- src/pulsecore/memblock.h | 32 +++++++++++--------- src/pulsecore/protocol-native.c | 8 ++--- src/tests/memblock-test.c | 20 ++++++------ 5 files changed, 76 insertions(+), 71 deletions(-) diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index 8ea9262b..ae475c3a 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -259,20 +259,20 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G stat = pa_mempool_get_stat(c->mempool); pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n", - stat->n_allocated, - pa_bytes_snprint(s, sizeof(s), stat->allocated_size)); + (unsigned) AO_load_acquire_read((AO_t*) &stat->n_allocated), + pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->allocated_size))); pa_strbuf_printf(buf, "Memory blocks allocated during the whole lifetime: %u, size: %s.\n", - stat->n_accumulated, - pa_bytes_snprint(s, sizeof(s), stat->accumulated_size)); + (unsigned) AO_load_acquire_read((AO_t*) &stat->n_accumulated), + pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->accumulated_size))); pa_strbuf_printf(buf, "Memory blocks imported from other processes: %u, size: %s.\n", - stat->n_imported, - pa_bytes_snprint(s, sizeof(s), stat->imported_size)); + (unsigned) AO_load_acquire_read((AO_t*) &stat->n_imported), + pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->imported_size))); pa_strbuf_printf(buf, "Memory blocks exported to other processes: %u, size: %s.\n", - stat->n_exported, - pa_bytes_snprint(s, sizeof(s), stat->exported_size)); + (unsigned) AO_load_acquire_read((AO_t*) &stat->n_exported), + pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->exported_size))); pa_strbuf_printf(buf, "Total sample cache size: %s.\n", pa_bytes_snprint(s, sizeof(s), pa_scache_total_size(c))); @@ -289,8 +289,8 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G pa_strbuf_printf(buf, "Memory blocks of type %s: %u allocated/%u accumulated.\n", type_table[k], - stat->n_allocated_by_type[k], - stat->n_accumulated_by_type[k]); + (unsigned) AO_load_acquire_read(&stat->n_allocated_by_type[k]), + (unsigned) AO_load_acquire_read(&stat->n_accumulated_by_type[k])); return 0; } diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 516ade13..70bcf677 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -112,39 +112,40 @@ static void stat_add(pa_memblock*b) { assert(b); assert(b->pool); - b->pool->stat.n_allocated ++; - b->pool->stat.n_accumulated ++; - b->pool->stat.allocated_size += b->length; - b->pool->stat.accumulated_size += b->length; + AO_fetch_and_add1_release_write(&b->pool->stat.n_allocated); + AO_fetch_and_add_release_write(&b->pool->stat.allocated_size, (AO_t) b->length); + + AO_fetch_and_add1_release_write(&b->pool->stat.n_accumulated); + AO_fetch_and_add_release_write(&b->pool->stat.accumulated_size, (AO_t) b->length); if (b->type == PA_MEMBLOCK_IMPORTED) { - b->pool->stat.n_imported++; - b->pool->stat.imported_size += b->length; + AO_fetch_and_add1_release_write(&b->pool->stat.n_imported); + AO_fetch_and_add_release_write(&b->pool->stat.imported_size, (AO_t) b->length); } - b->pool->stat.n_allocated_by_type[b->type]++; - b->pool->stat.n_accumulated_by_type[b->type]++; + AO_fetch_and_add1_release_write(&b->pool->stat.n_allocated_by_type[b->type]); + AO_fetch_and_add1_release_write(&b->pool->stat.n_accumulated_by_type[b->type]); } static void stat_remove(pa_memblock *b) { assert(b); assert(b->pool); - assert(b->pool->stat.n_allocated > 0); - assert(b->pool->stat.allocated_size >= b->length); + assert(AO_load_acquire_read(&b->pool->stat.n_allocated) > 0); + assert(AO_load_acquire_read(&b->pool->stat.allocated_size) >= (AO_t) b->length); - b->pool->stat.n_allocated --; - b->pool->stat.allocated_size -= b->length; + AO_fetch_and_sub1_release_write(&b->pool->stat.n_allocated); + AO_fetch_and_add_release_write(&b->pool->stat.allocated_size, (AO_t) (-b->length)); if (b->type == PA_MEMBLOCK_IMPORTED) { - assert(b->pool->stat.n_imported > 0); - assert(b->pool->stat.imported_size >= b->length); + assert(AO_load_acquire_read(&b->pool->stat.n_imported) > 0); + assert(AO_load_acquire_read(&b->pool->stat.imported_size) >= (AO_t) b->length); - b->pool->stat.n_imported --; - b->pool->stat.imported_size -= b->length; + AO_fetch_and_sub1_release_write(&b->pool->stat.n_imported); + AO_fetch_and_add_release_write(&b->pool->stat.imported_size, (AO_t) (-b->length)); } - b->pool->stat.n_allocated_by_type[b->type]--; + AO_fetch_and_sub1_release_write(&b->pool->stat.n_allocated_by_type[b->type]); } static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length); @@ -190,7 +191,7 @@ static struct mempool_slot* mempool_allocate_slot(pa_mempool *p) { slot = (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->block_size * p->n_init++)); else { pa_log_debug("Pool full"); - p->stat.n_pool_full++; + AO_fetch_and_add1_release_write(&p->stat.n_pool_full); return NULL; } @@ -247,7 +248,7 @@ pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) { b->data = mempool_slot_data(slot); } else { pa_log_debug("Memory block too large for pool: %u > %u", length, p->block_size - sizeof(struct mempool_slot)); - p->stat.n_too_large_for_pool++; + AO_fetch_and_add1_release_write(&p->stat.n_too_large_for_pool); return NULL; } @@ -371,7 +372,7 @@ void pa_memblock_unref(pa_memblock*b) { static void memblock_make_local(pa_memblock *b) { assert(b); - b->pool->stat.n_allocated_by_type[b->type]--; + AO_fetch_and_sub1_release_write(&b->pool->stat.n_allocated_by_type[b->type]); if (b->length <= b->pool->block_size - sizeof(struct mempool_slot)) { struct mempool_slot *slot; @@ -397,8 +398,8 @@ static void memblock_make_local(pa_memblock *b) { b->data = pa_xmemdup(b->data, b->length); finish: - b->pool->stat.n_allocated_by_type[b->type]++; - b->pool->stat.n_accumulated_by_type[b->type]++; + AO_fetch_and_add1_release_write(&b->pool->stat.n_allocated_by_type[b->type]); + AO_fetch_and_add1_release_write(&b->pool->stat.n_accumulated_by_type[b->type]); } void pa_memblock_unref_fixed(pa_memblock *b) { @@ -418,10 +419,10 @@ static void memblock_replace_import(pa_memblock *b) { assert(b); assert(b->type == PA_MEMBLOCK_IMPORTED); - assert(b->pool->stat.n_imported > 0); - assert(b->pool->stat.imported_size >= b->length); - b->pool->stat.n_imported --; - b->pool->stat.imported_size -= b->length; + assert(AO_load_acquire_read(&b->pool->stat.n_imported) > 0); + assert(AO_load_acquire_read(&b->pool->stat.imported_size) >= (AO_t) b->length); + AO_fetch_and_sub1_release_write(&b->pool->stat.n_imported); + AO_fetch_and_add_release_write(&b->pool->stat.imported_size, (AO_t) - b->length); seg = b->per_type.imported.segment; assert(seg); @@ -486,7 +487,7 @@ void pa_mempool_free(pa_mempool *p) { while (p->exports) pa_memexport_free(p->exports); - if (p->stat.n_allocated > 0) + if (AO_load_acquire_read(&p->stat.n_allocated) > 0) pa_log_warn("WARNING! Memory pool destroyed but not all memory blocks freed!"); pa_shm_free(&p->memory); @@ -685,11 +686,11 @@ int pa_memexport_process_release(pa_memexport *e, uint32_t id) { /* pa_log("Processing release for %u", id); */ - assert(e->pool->stat.n_exported > 0); - assert(e->pool->stat.exported_size >= e->slots[id].block->length); + assert(AO_load_acquire_read(&e->pool->stat.n_exported) > 0); + assert(AO_load_acquire_read(&e->pool->stat.exported_size) >= (AO_t) e->slots[id].block->length); - e->pool->stat.n_exported --; - e->pool->stat.exported_size -= e->slots[id].block->length; + AO_fetch_and_sub1_release_write(&e->pool->stat.n_exported); + AO_fetch_and_add_release_write(&e->pool->stat.exported_size, (AO_t) -e->slots[id].block->length); pa_memblock_unref(e->slots[id].block); e->slots[id].block = NULL; @@ -786,8 +787,8 @@ int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32 *offset = (uint8_t*) b->data - (uint8_t*) memory->ptr; *size = b->length; - e->pool->stat.n_exported ++; - e->pool->stat.exported_size += b->length; + AO_fetch_and_add1_release_write(&e->pool->stat.n_exported); + AO_fetch_and_add_release_write(&e->pool->stat.exported_size, (AO_t) b->length); return 0; } diff --git a/src/pulsecore/memblock.h b/src/pulsecore/memblock.h index 60a0c900..d4f2b7aa 100644 --- a/src/pulsecore/memblock.h +++ b/src/pulsecore/memblock.h @@ -74,21 +74,25 @@ struct pa_memblock { } per_type; }; +/* Please note that updates to this structure are not locked, + * i.e. n_allocated might be updated at a point in time where + * n_accumulated is not yet. Take these values with a grain of salt, + * threy are here for purely statistical reasons.*/ struct pa_mempool_stat { - unsigned n_allocated; - unsigned n_accumulated; - unsigned n_imported; - unsigned n_exported; - size_t allocated_size; - size_t accumulated_size; - size_t imported_size; - size_t exported_size; - - unsigned n_too_large_for_pool; - unsigned n_pool_full; - - unsigned n_allocated_by_type[PA_MEMBLOCK_TYPE_MAX]; - unsigned n_accumulated_by_type[PA_MEMBLOCK_TYPE_MAX]; + AO_t n_allocated; + AO_t n_accumulated; + AO_t n_imported; + AO_t n_exported; + AO_t allocated_size; + AO_t accumulated_size; + AO_t imported_size; + AO_t exported_size; + + AO_t n_too_large_for_pool; + AO_t n_pool_full; + + AO_t n_allocated_by_type[PA_MEMBLOCK_TYPE_MAX]; + AO_t n_accumulated_by_type[PA_MEMBLOCK_TYPE_MAX]; }; /* Allocate a new memory block of type PA_MEMBLOCK_MEMPOOL or PA_MEMBLOCK_APPENDED, depending on the size */ diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 0f015071..38c024b7 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -1112,10 +1112,10 @@ static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t stat = pa_mempool_get_stat(c->protocol->core->mempool); reply = reply_new(tag); - pa_tagstruct_putu32(reply, stat->n_allocated); - pa_tagstruct_putu32(reply, stat->allocated_size); - pa_tagstruct_putu32(reply, stat->n_accumulated); - pa_tagstruct_putu32(reply, stat->accumulated_size); + pa_tagstruct_putu32(reply, (uint32_t) AO_load_acquire_read((AO_t*) &stat->n_allocated)); + pa_tagstruct_putu32(reply, (uint32_t) AO_load_acquire_read((AO_t*) &stat->allocated_size)); + pa_tagstruct_putu32(reply, (uint32_t) AO_load_acquire_read((AO_t*) &stat->n_accumulated)); + pa_tagstruct_putu32(reply, (uint32_t) AO_load_acquire_read((AO_t*) &stat->accumulated_size)); pa_tagstruct_putu32(reply, pa_scache_total_size(c->protocol->core)); pa_pstream_send_tagstruct(c->pstream, reply); } diff --git a/src/tests/memblock-test.c b/src/tests/memblock-test.c index 11198ae6..ef2e0ad7 100644 --- a/src/tests/memblock-test.c +++ b/src/tests/memblock-test.c @@ -54,16 +54,16 @@ static void print_stats(pa_mempool *p, const char *text) { "n_pool_full = %u\n" "}\n", text, - s->n_allocated, - s->n_accumulated, - s->n_imported, - s->n_exported, - (unsigned long) s->allocated_size, - (unsigned long) s->accumulated_size, - (unsigned long) s->imported_size, - (unsigned long) s->exported_size, - s->n_too_large_for_pool, - s->n_pool_full); + (unsigned) AO_load_acquire_read((AO_t*) &s->n_allocated), + (unsigned) AO_load_acquire_read((AO_t*) &s->n_accumulated), + (unsigned) AO_load_acquire_read((AO_t*) &s->n_imported), + (unsigned) AO_load_acquire_read((AO_t*) &s->n_exported), + (unsigned long) AO_load_acquire_read((AO_t*) &s->allocated_size), + (unsigned long) AO_load_acquire_read((AO_t*) &s->accumulated_size), + (unsigned long) AO_load_acquire_read((AO_t*) &s->imported_size), + (unsigned long) AO_load_acquire_read((AO_t*) &s->exported_size), + (unsigned) AO_load_acquire_read((AO_t*) &s->n_too_large_for_pool), + (unsigned) AO_load_acquire_read((AO_t*) &s->n_pool_full)); } int main(int argc, char *argv[]) { -- cgit From b2c341f935bd54eb1b7f80a297e72bf0e6c6dc83 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 29 Aug 2006 19:51:14 +0000 Subject: add a threading primitive API git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1344 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 16 ++++- src/pulsecore/mutex-posix.c | 121 +++++++++++++++++++++++++++++++++++ src/pulsecore/mutex.h | 39 ++++++++++++ src/pulsecore/thread-posix.c | 146 +++++++++++++++++++++++++++++++++++++++++++ src/pulsecore/thread.h | 44 +++++++++++++ src/tests/thread-test.c | 135 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 498 insertions(+), 3 deletions(-) create mode 100644 src/pulsecore/mutex-posix.c create mode 100644 src/pulsecore/mutex.h create mode 100644 src/pulsecore/thread-posix.c create mode 100644 src/pulsecore/thread.h create mode 100644 src/tests/thread-test.c diff --git a/src/Makefile.am b/src/Makefile.am index c9942cff..bbdc4612 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -198,7 +198,8 @@ noinst_PROGRAMS = \ get-binary-name-test \ ipacl-test \ hook-list-test \ - memblock-test + memblock-test \ + thread-test if HAVE_SIGXCPU noinst_PROGRAMS += \ @@ -248,6 +249,11 @@ memblock_test_CFLAGS = $(AM_CFLAGS) memblock_test_LDADD = $(AM_LDADD) libpulsecore.la memblock_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +thread_test_SOURCES = tests/thread-test.c +thread_test_CFLAGS = $(AM_CFLAGS) +thread_test_LDADD = $(AM_LDADD) libpulsecore.la +thread_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + mcalign_test_SOURCES = tests/mcalign-test.c mcalign_test_CFLAGS = $(AM_CFLAGS) mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpulsecore.la @@ -529,7 +535,9 @@ pulsecoreinclude_HEADERS = \ pulsecore/creds.h \ pulsecore/shm.h \ pulsecore/llist.h \ - pulsecore/refcnt.h + pulsecore/refcnt.h \ + pulsecore/mutex.h \ + pulsecore/thread.h lib_LTLIBRARIES += libpulsecore.la @@ -597,7 +605,9 @@ libpulsecore_la_SOURCES += \ pulsecore/winsock.h \ pulsecore/core-error.c pulsecore/core-error.h \ pulsecore/hook-list.c pulsecore/hook-list.h \ - pulsecore/shm.c pulsecore/shm.h + pulsecore/shm.c pulsecore/shm.h \ + pulsecore/mutex-posix.c pulsecore/mutex.h \ + pulsecore/thread-posix.c pulsecore/thread.h if OS_IS_WIN32 libpulsecore_la_SOURCES += \ diff --git a/src/pulsecore/mutex-posix.c b/src/pulsecore/mutex-posix.c new file mode 100644 index 00000000..d0156dbf --- /dev/null +++ b/src/pulsecore/mutex-posix.c @@ -0,0 +1,121 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include "mutex.h" + +#define ASSERT_SUCCESS(x) do { \ + int _r = (x); \ + assert(_r == 0); \ +} while(0) + +struct pa_mutex { + pthread_mutex_t mutex; +}; + +struct pa_cond { + pthread_cond_t cond; +}; + +pa_mutex* pa_mutex_new(int recursive) { + pa_mutex *m; + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + + if (recursive) + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) < 0) + return NULL; + + m = pa_xnew(pa_mutex, 1); + + if (pthread_mutex_init(&m->mutex, &attr) < 0) { + pa_xfree(m); + return NULL; + } + + return m; +} + +void pa_mutex_free(pa_mutex *m) { + assert(m); + + ASSERT_SUCCESS(pthread_mutex_destroy(&m->mutex)); + pa_xfree(m); +} + +void pa_mutex_lock(pa_mutex *m) { + assert(m); + + ASSERT_SUCCESS(pthread_mutex_lock(&m->mutex)); +} + +void pa_mutex_unlock(pa_mutex *m) { + assert(m); + + ASSERT_SUCCESS(pthread_mutex_unlock(&m->mutex)); +} + + +pa_cond *pa_cond_new(void) { + pa_cond *c; + + c = pa_xnew(pa_cond, 1); + + if (pthread_cond_init(&c->cond, NULL) < 0) { + pa_xfree(c); + return NULL; + } + + return c; +} + +void pa_cond_free(pa_cond *c) { + assert(c); + + ASSERT_SUCCESS(pthread_cond_destroy(&c->cond)); + pa_xfree(c); +} + +void pa_cond_signal(pa_cond *c, int broadcast) { + assert(c); + + if (broadcast) + ASSERT_SUCCESS(pthread_cond_broadcast(&c->cond)); + else + ASSERT_SUCCESS(pthread_cond_signal(&c->cond)); +} + +int pa_cond_wait(pa_cond *c, pa_mutex *m) { + assert(c); + assert(m); + + return pthread_cond_wait(&c->cond, &m->mutex); +} diff --git a/src/pulsecore/mutex.h b/src/pulsecore/mutex.h new file mode 100644 index 00000000..b3b9c5c6 --- /dev/null +++ b/src/pulsecore/mutex.h @@ -0,0 +1,39 @@ +#ifndef foopulsemutexhfoo +#define foopulsemutexhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef struct pa_mutex pa_mutex; + +pa_mutex* pa_mutex_new(int recursive); +void pa_mutex_free(pa_mutex *m); +void pa_mutex_lock(pa_mutex *m); +void pa_mutex_unlock(pa_mutex *m); + +typedef struct pa_cond pa_cond; + +pa_cond *pa_cond_new(void); +void pa_cond_free(pa_cond *c); +void pa_cond_signal(pa_cond *c, int broadcast); +int pa_cond_wait(pa_cond *c, pa_mutex *m); + +#endif diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c new file mode 100644 index 00000000..15ade290 --- /dev/null +++ b/src/pulsecore/thread-posix.c @@ -0,0 +1,146 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include "thread.h" + +#define ASSERT_SUCCESS(x) do { \ + int _r = (x); \ + assert(_r == 0); \ +} while(0) + +struct pa_thread { + pthread_t id; + pa_thread_func_t thread_func; + void *userdata; + AO_t running; +}; + +struct pa_tls { + pthread_key_t key; +}; + +static pa_tls *thread_tls; +static pthread_once_t thread_tls_once = PTHREAD_ONCE_INIT; + +static void thread_tls_once_func(void) { + thread_tls = pa_tls_new(NULL); + assert(thread_tls); +} + +static void* internal_thread_func(void *userdata) { + pa_thread *t = userdata; + assert(t); + + t->id = pthread_self(); + + ASSERT_SUCCESS(pthread_once(&thread_tls_once, thread_tls_once_func)); + pa_tls_set(thread_tls, t); + + AO_store_release_write(&t->running, 1); + t->thread_func(t->userdata); + AO_store_release_write(&t->running, 0); + + return NULL; +} + +pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) { + pa_thread *t; + + t = pa_xnew(pa_thread, 1); + t->thread_func = thread_func; + t->userdata = userdata; + + if (pthread_create(&t->id, NULL, internal_thread_func, t) < 0) { + pa_xfree(t); + return NULL; + } + + return t; +} + +int pa_thread_is_running(pa_thread *t) { + assert(t); + + return !!AO_load_acquire_read(&t->running); +} + +void pa_thread_free(pa_thread *t) { + assert(t); + + pa_thread_join(t); + pa_xfree(t); +} + +int pa_thread_join(pa_thread *t) { + assert(t); + + return pthread_join(t->id, NULL); +} + +pa_thread* pa_thread_self(void) { + ASSERT_SUCCESS(pthread_once(&thread_tls_once, thread_tls_once_func)); + return pa_tls_get(thread_tls); +} + +pa_tls* pa_tls_new(pa_free_cb_t free_cb) { + pa_tls *t; + + t = pa_xnew(pa_tls, 1); + + if (pthread_key_create(&t->key, free_cb) < 0) { + pa_xfree(t); + return NULL; + } + + return t; +} + +void pa_tls_free(pa_tls *t) { + assert(t); + + ASSERT_SUCCESS(pthread_key_delete(t->key)); + pa_xfree(t); +} + +void *pa_tls_get(pa_tls *t) { + assert(t); + + return pthread_getspecific(t->key); +} + +void *pa_tls_set(pa_tls *t, void *userdata) { + void *r; + + r = pthread_getspecific(t->key); + ASSERT_SUCCESS(pthread_setspecific(t->key, userdata)); + return r; +} + diff --git a/src/pulsecore/thread.h b/src/pulsecore/thread.h new file mode 100644 index 00000000..978e9927 --- /dev/null +++ b/src/pulsecore/thread.h @@ -0,0 +1,44 @@ +#ifndef foopulsethreadhfoo +#define foopulsethreadhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef struct pa_thread pa_thread; + +typedef void (*pa_thread_func_t) (void *userdata); + +pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata); +void pa_thread_free(pa_thread *t); +int pa_thread_join(pa_thread *t); +int pa_thread_is_running(pa_thread *t); +pa_thread *pa_thread_self(void); + +typedef struct pa_tls pa_tls; + +pa_tls* pa_tls_new(pa_free_cb_t free_cb); +void pa_tls_free(pa_tls *t); +void * pa_tls_get(pa_tls *t); +void *pa_tls_set(pa_tls *t, void *userdata); + +#endif diff --git a/src/tests/thread-test.c b/src/tests/thread-test.c new file mode 100644 index 00000000..a93ac1e4 --- /dev/null +++ b/src/tests/thread-test.c @@ -0,0 +1,135 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include +#include + +static pa_mutex *mutex = NULL; +static pa_cond *cond1 = NULL, *cond2 = NULL; +static pa_tls *tls = NULL; + +static int magic_number = 0; + +#define THREADS_MAX 20 + +static void thread_func(void *data) { + pa_tls_set(tls, data); + + pa_log("thread_func() for %s starting...", (char*) pa_tls_get(tls)); + + pa_mutex_lock(mutex); + + for (;;) { + int k, n; + + pa_log("%s waiting ...", (char*) pa_tls_get(tls)); + + for (;;) { + + if (magic_number < 0) + goto quit; + + if (magic_number != 0) + break; + + pa_cond_wait(cond1, mutex); + } + + k = magic_number; + magic_number = 0; + + pa_mutex_unlock(mutex); + + pa_cond_signal(cond2, 0); + + pa_log("%s got number %i", (char*) pa_tls_get(tls), k); + + /* Spin! */ + for (n = 0; n < k; n++) + sched_yield(); + + pa_mutex_lock(mutex); + } + +quit: + + pa_mutex_unlock(mutex); + + pa_log("thread_func() for %s done...", (char*) pa_tls_get(tls)); +} + +int main(int argc, char *argv[]) { + int i, k; + pa_thread* t[THREADS_MAX]; + + mutex = pa_mutex_new(0); + cond1 = pa_cond_new(); + cond2 = pa_cond_new(); + tls = pa_tls_new(pa_xfree); + + for (i = 0; i < THREADS_MAX; i++) { + t[i] = pa_thread_new(thread_func, pa_sprintf_malloc("Thread #%i", i+1)); + assert(t[i]); + } + + pa_mutex_lock(mutex); + + pa_log("loop-init"); + + for (k = 0; k < 100; k++) { + assert(magic_number == 0); + + + magic_number = (int) rand() % 0x10000; + + pa_log("iteration %i (%i)", k, magic_number); + + pa_cond_signal(cond1, 0); + + pa_cond_wait(cond2, mutex); + } + + pa_log("loop-exit"); + + magic_number = -1; + pa_cond_signal(cond1, 1); + + pa_mutex_unlock(mutex); + + for (i = 0; i < THREADS_MAX; i++) + pa_thread_free(t[i]); + + pa_mutex_free(mutex); + pa_cond_free(cond1); + pa_cond_free(cond2); + pa_tls_free(tls); + + return 0; +} -- cgit From 078420a9d2b2532062f30263d067e76735a30349 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 30 Aug 2006 13:02:29 +0000 Subject: We need to have a callback when changing volume or we might deadlock. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1345 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 32cb5f9a..c765b693 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1487,9 +1487,9 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno pa_operation *o; if (request == SOUND_MIXER_READ_PCM) - o = pa_context_set_sink_volume_by_index(i->context, i->sink_index, pv, NULL, NULL); + o = pa_context_set_sink_volume_by_index(i->context, i->sink_index, pv, context_success_cb, i); else - o = pa_context_set_source_volume_by_index(i->context, i->source_index, pv, NULL, NULL); + o = pa_context_set_source_volume_by_index(i->context, i->source_index, pv, context_success_cb, i); if (!o) debug(DEBUG_LEVEL_NORMAL, __FILE__":Failed set volume: %s", pa_strerror(pa_context_errno(i->context))); -- cgit From c4e47c63b7dbba208cb8c78bb5d15a0d1310854e Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 30 Aug 2006 14:44:15 +0000 Subject: Remove check for libatomic_ops library as some systems have no (zero, nada) symbols in it. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1346 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 6 ------ 1 file changed, 6 deletions(-) diff --git a/configure.ac b/configure.ac index 42bee9a8..2bb20809 100644 --- a/configure.ac +++ b/configure.ac @@ -326,12 +326,6 @@ AC_CHECK_HEADERS([atomic_ops.h], [], [ AC_MSG_ERROR([*** libatomic-ops headers not found]) ]) -AC_SEARCH_LIBS([AO_spin], [atomic_ops], [], [ -AC_MSG_ERROR([*** libatomic-ops library file not found]) -]) - - - #### OSS support (optional) #### AC_ARG_ENABLE([oss], -- cgit From a6b99d5196cf66aa276d9e7c9483f1b9e2fba491 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 30 Aug 2006 16:55:37 +0000 Subject: Make sure the libatomic_ops lib is included. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1347 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure.ac b/configure.ac index 2bb20809..c08c1d02 100644 --- a/configure.ac +++ b/configure.ac @@ -326,6 +326,8 @@ AC_CHECK_HEADERS([atomic_ops.h], [], [ AC_MSG_ERROR([*** libatomic-ops headers not found]) ]) +LIBS="$LIBS -latomic_ops" + #### OSS support (optional) #### AC_ARG_ENABLE([oss], -- cgit From ad0535beef4cd0d4e96fa194d54796a0945ed3c6 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 30 Aug 2006 17:01:10 +0000 Subject: Add AO_REQUIRE_CAS as we do. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1348 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/mutex-posix.c | 2 ++ src/pulsecore/refcnt.h | 1 + src/pulsecore/thread-posix.c | 2 ++ 3 files changed, 5 insertions(+) diff --git a/src/pulsecore/mutex-posix.c b/src/pulsecore/mutex-posix.c index d0156dbf..08baa386 100644 --- a/src/pulsecore/mutex-posix.c +++ b/src/pulsecore/mutex-posix.c @@ -25,6 +25,8 @@ #include #include + +#define AO_REQUIRE_CAS #include #include diff --git a/src/pulsecore/refcnt.h b/src/pulsecore/refcnt.h index fade9aa4..ff0a9923 100644 --- a/src/pulsecore/refcnt.h +++ b/src/pulsecore/refcnt.h @@ -22,6 +22,7 @@ USA. ***/ +#define AO_REQUIRE_CAS #include #define PA_REFCNT_DECLARE volatile AO_t _ref diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c index 15ade290..54f21b75 100644 --- a/src/pulsecore/thread-posix.c +++ b/src/pulsecore/thread-posix.c @@ -25,6 +25,8 @@ #include #include + +#define AO_REQUIRE_CAS #include #include -- cgit From 2f6cc4f8fa8d806ef6120887cd3aed62b1b072c0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 30 Aug 2006 17:12:35 +0000 Subject: fix handling of "running" variable git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1349 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/thread-posix.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c index 54f21b75..b634a6f6 100644 --- a/src/pulsecore/thread-posix.c +++ b/src/pulsecore/thread-posix.c @@ -66,9 +66,9 @@ static void* internal_thread_func(void *userdata) { ASSERT_SUCCESS(pthread_once(&thread_tls_once, thread_tls_once_func)); pa_tls_set(thread_tls, t); - AO_store_release_write(&t->running, 1); + AO_fetch_and_add1_full(&t->running); t->thread_func(t->userdata); - AO_store_release_write(&t->running, 0); + AO_fetch_and_add_full(&t->running, (AO_t) -2); return NULL; } @@ -79,19 +79,24 @@ pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) { t = pa_xnew(pa_thread, 1); t->thread_func = thread_func; t->userdata = userdata; + AO_store_full(&t->running, 0); if (pthread_create(&t->id, NULL, internal_thread_func, t) < 0) { pa_xfree(t); return NULL; } + AO_fetch_and_add1_full(&t->running); + return t; } int pa_thread_is_running(pa_thread *t) { + AO_t r; assert(t); - return !!AO_load_acquire_read(&t->running); + r = AO_load_full(&t->running); + return r == 1 || r == 2; } void pa_thread_free(pa_thread *t) { -- cgit From 7ce39d35c680d2a51e14c0776f3b3a17bdc598f0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 31 Aug 2006 15:17:40 +0000 Subject: update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1350 fefdeb5f-60dc-0310-8127-8f9354f1896f --- todo | 1 + 1 file changed, 1 insertion(+) diff --git a/todo b/todo index 34935c6f..7b4ce786 100644 --- a/todo +++ b/todo @@ -23,6 +23,7 @@ Cleanups: - silence generation should be moved into the core to avoid races and code duplication in the backends - don't read/write audio data from/to ALSA devices if noone is listening +- using POSIX monotonous clocks wherever possible instead of gettimeofday() Test: - autoload -- cgit From aee4a3738eaa5026a5ade1e865f67860c9bc004f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 31 Aug 2006 15:20:43 +0000 Subject: define AO_REQUIRE_CAS in the Makefile instead of each source file, effectively reversing r1348 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1351 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 1 + src/pulsecore/mutex-posix.c | 1 - src/pulsecore/refcnt.h | 1 - src/pulsecore/thread-posix.c | 1 - 4 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index bbdc4612..3b79acad 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -50,6 +50,7 @@ AM_CFLAGS += -DPA_DLSEARCHPATH=\"$(modlibexecdir)\" AM_CFLAGS += -DPA_DEFAULT_CONFIG_DIR=\"$(PA_DEFAULT_CONFIG_DIR)\" AM_CFLAGS += -DPA_BINARY=\"$(PA_BINARY)\" AM_CFLAGS += -DPA_SYSTEM_RUNTIME_PATH=\"$(PA_SYSTEM_RUNTIME_PATH)\" +AM_CFLAGS += -DAO_REQUIRE_CAS # This cool debug trap works on i386/gcc only AM_CFLAGS += '-DDEBUG_TRAP=__asm__("int $$3")' diff --git a/src/pulsecore/mutex-posix.c b/src/pulsecore/mutex-posix.c index 08baa386..6f0e7336 100644 --- a/src/pulsecore/mutex-posix.c +++ b/src/pulsecore/mutex-posix.c @@ -26,7 +26,6 @@ #include #include -#define AO_REQUIRE_CAS #include #include diff --git a/src/pulsecore/refcnt.h b/src/pulsecore/refcnt.h index ff0a9923..fade9aa4 100644 --- a/src/pulsecore/refcnt.h +++ b/src/pulsecore/refcnt.h @@ -22,7 +22,6 @@ USA. ***/ -#define AO_REQUIRE_CAS #include #define PA_REFCNT_DECLARE volatile AO_t _ref diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c index b634a6f6..6ca46d70 100644 --- a/src/pulsecore/thread-posix.c +++ b/src/pulsecore/thread-posix.c @@ -26,7 +26,6 @@ #include #include -#define AO_REQUIRE_CAS #include #include -- cgit From 0f6098bf6428b17bbff2b2d6f4e8ead0d43d7f3a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 31 Aug 2006 15:31:33 +0000 Subject: work around bug in firefox which apparently misuses access() as NULL pointer test. Original patch by "alon". (Closes #27) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1352 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index c765b693..ddb732f0 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -2121,6 +2121,13 @@ int close(int fd) { } int access(const char *pathname, int mode) { + + if (!pathname) { + /* Firefox needs this. See #27 */ + errno = EFAULT; + return -1; + } + debug(DEBUG_LEVEL_VERBOSE, __FILE__": access(%s)\n", pathname); if (strcmp(pathname, "/dev/dsp") != 0 && -- cgit From 6e9706bcbcc0c5743d21ed48bd6e6485e4ee5203 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 31 Aug 2006 16:13:07 +0000 Subject: Also wrap yield functionality so that it can be platform independent. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1353 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/thread-posix.c | 9 +++++++++ src/pulsecore/thread.h | 1 + src/tests/thread-test.c | 4 +--- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c index 6ca46d70..4c12ec93 100644 --- a/src/pulsecore/thread-posix.c +++ b/src/pulsecore/thread-posix.c @@ -25,6 +25,7 @@ #include #include +#include #include @@ -116,6 +117,14 @@ pa_thread* pa_thread_self(void) { return pa_tls_get(thread_tls); } +void pa_thread_yield(void) { +#ifdef HAVE_PTHREAD_YIELD + pthread_yield(); +#else + sched_yield(); +#endif +} + pa_tls* pa_tls_new(pa_free_cb_t free_cb) { pa_tls *t; diff --git a/src/pulsecore/thread.h b/src/pulsecore/thread.h index 978e9927..9b99c8c2 100644 --- a/src/pulsecore/thread.h +++ b/src/pulsecore/thread.h @@ -33,6 +33,7 @@ void pa_thread_free(pa_thread *t); int pa_thread_join(pa_thread *t); int pa_thread_is_running(pa_thread *t); pa_thread *pa_thread_self(void); +void pa_thread_yield(void); typedef struct pa_tls pa_tls; diff --git a/src/tests/thread-test.c b/src/tests/thread-test.c index a93ac1e4..120d2554 100644 --- a/src/tests/thread-test.c +++ b/src/tests/thread-test.c @@ -23,8 +23,6 @@ #include #endif -#include - #include #include #include @@ -73,7 +71,7 @@ static void thread_func(void *data) { /* Spin! */ for (n = 0; n < k; n++) - sched_yield(); + pa_thread_yield(); pa_mutex_lock(mutex); } -- cgit From 6e3de3dbe5e70839c70c1180a08fa720946ee247 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 31 Aug 2006 16:39:53 +0000 Subject: Make sure libatomic_ops.a isn't included in win32 builds as libtool doesn't like static libs in dlls. Everything is in the headers anyway, so we do not need it. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1354 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index c08c1d02..7d85b32a 100644 --- a/configure.ac +++ b/configure.ac @@ -326,7 +326,10 @@ AC_CHECK_HEADERS([atomic_ops.h], [], [ AC_MSG_ERROR([*** libatomic-ops headers not found]) ]) -LIBS="$LIBS -latomic_ops" +# Win32 does not need the lib and breaks horribly if we try to include it +if test "x$os_is_win32" != "x1" ; then + LIBS="$LIBS -latomic_ops" +fi #### OSS support (optional) #### -- cgit From 97202d1b2d1638df147a369f4476060f608b568f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 1 Sep 2006 00:24:32 +0000 Subject: fix a race condition with stream connection vs. latency measuremtn (found by theBear) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1355 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 18e1d97d..a110c57e 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -490,8 +490,21 @@ static void start_subscribe(struct userdata *u) { pa_pstream_send_tagstruct(u->pstream, t); } +static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + struct userdata *u = userdata; + struct timeval ntv; + assert(m && e && u); + + request_latency(u); + + pa_gettimeofday(&ntv); + ntv.tv_sec += LATENCY_INTERVAL; + m->time_restart(e, &ntv); +} + static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; + struct timeval ntv; assert(pd && u && u->pdispatch == pd); if (command != PA_COMMAND_REPLY) { @@ -535,6 +548,11 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN start_subscribe(u); request_info(u); + assert(!u->time_event); + pa_gettimeofday(&ntv); + ntv.tv_sec += LATENCY_INTERVAL; + u->time_event = u->core->mainloop->time_new(u->core->mainloop, &ntv, timeout_callback, u); + request_latency(u); #ifdef TUNNEL_SINK send_bytes(u); @@ -840,18 +858,6 @@ static int source_set_hw_mute(pa_source *source) { } #endif -static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - struct userdata *u = userdata; - struct timeval ntv; - assert(m && e && u); - - request_latency(u); - - pa_gettimeofday(&ntv); - ntv.tv_sec += LATENCY_INTERVAL; - m->time_restart(e, &ntv); -} - static int load_key(struct userdata *u, const char*fn) { assert(u); @@ -883,10 +889,8 @@ int pa__init(pa_core *c, pa_module*m) { struct userdata *u = NULL; pa_sample_spec ss; pa_channel_map map; - struct timeval ntv; char *t, *dn = NULL; - assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -986,9 +990,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_xfree(dn); - pa_gettimeofday(&ntv); - ntv.tv_sec += LATENCY_INTERVAL; - u->time_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, u); + u->time_event = NULL; pa_modargs_free(ma); -- cgit From 3571bf1699d1fa42b5d24fcf62eea867f0fe9903 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 1 Sep 2006 18:16:55 +0000 Subject: Thread implementation for Win32. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1356 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 16 ++- src/pulsecore/mutex-win32.c | 133 +++++++++++++++++++++++ src/pulsecore/thread-win32.c | 246 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 392 insertions(+), 3 deletions(-) create mode 100644 src/pulsecore/mutex-win32.c create mode 100644 src/pulsecore/thread-win32.c diff --git a/src/Makefile.am b/src/Makefile.am index 3b79acad..5043197c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -580,6 +580,7 @@ libpulsecore_la_SOURCES += \ pulsecore/modargs.c pulsecore/modargs.h \ pulsecore/modinfo.c pulsecore/modinfo.h \ pulsecore/module.c pulsecore/module.h \ + pulsecore/mutex.h \ pulsecore/namereg.c pulsecore/namereg.h \ pulsecore/pid.c pulsecore/pid.h \ pulsecore/pipe.c pulsecore/pipe.h \ @@ -602,19 +603,28 @@ libpulsecore_la_SOURCES += \ pulsecore/source.c pulsecore/source.h \ pulsecore/source-output.c pulsecore/source-output.h \ pulsecore/strbuf.c pulsecore/strbuf.h \ + pulsecore/thread.h \ pulsecore/tokenizer.c pulsecore/tokenizer.h \ pulsecore/winsock.h \ pulsecore/core-error.c pulsecore/core-error.h \ pulsecore/hook-list.c pulsecore/hook-list.h \ - pulsecore/shm.c pulsecore/shm.h \ - pulsecore/mutex-posix.c pulsecore/mutex.h \ - pulsecore/thread-posix.c pulsecore/thread.h + pulsecore/shm.c pulsecore/shm.h if OS_IS_WIN32 libpulsecore_la_SOURCES += \ pulsecore/dllmain.c endif +if OS_IS_WIN32 +libpulsecore_la_SOURCES += \ + pulsecore/mutex-win32.c \ + pulsecore/thread-win32.c +else +libpulsecore_la_SOURCES += \ + pulsecore/mutex-posix.c \ + pulsecore/thread-posix.c +endif + libpulsecore_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBOIL_CFLAGS) libpulsecore_la_LDFLAGS = -version-info $(LIBPULSECORE_VERSION_INFO) libpulsecore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) $(LIBOIL_LIBS) $(LIBICONV) diff --git a/src/pulsecore/mutex-win32.c b/src/pulsecore/mutex-win32.c new file mode 100644 index 00000000..3710d914 --- /dev/null +++ b/src/pulsecore/mutex-win32.c @@ -0,0 +1,133 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include "mutex.h" + +struct pa_mutex { + CRITICAL_SECTION mutex; +}; + +struct pa_cond { + pa_hashmap *wait_events; +}; + +pa_mutex* pa_mutex_new(int recursive) { + pa_mutex *m; + + m = pa_xnew(pa_mutex, 1); + + InitializeCriticalSection(&m->mutex); + + return m; +} + +void pa_mutex_free(pa_mutex *m) { + assert(m); + + DeleteCriticalSection(&m->mutex); + pa_xfree(m); +} + +void pa_mutex_lock(pa_mutex *m) { + assert(m); + + EnterCriticalSection(&m->mutex); +} + +void pa_mutex_unlock(pa_mutex *m) { + assert(m); + + LeaveCriticalSection(&m->mutex); +} + +pa_cond *pa_cond_new(void) { + pa_cond *c; + + c = pa_xnew(pa_cond, 1); + c->wait_events = pa_hashmap_new(NULL, NULL); + assert(c->wait_events); + + return c; +} + +void pa_cond_free(pa_cond *c) { + assert(c); + + pa_hashmap_free(c->wait_events, NULL, NULL); + pa_xfree(c); +} + +void pa_cond_signal(pa_cond *c, int broadcast) { + assert(c); + + if (pa_hashmap_size(c->wait_events) == 0) + return; + + if (broadcast) + SetEvent(pa_hashmap_get_first(c->wait_events)); + else { + void *iter; + const void *key; + HANDLE event; + + iter = NULL; + while (1) { + pa_hashmap_iterate(c->wait_events, &iter, &key); + if (key == NULL) + break; + event = (HANDLE)pa_hashmap_get(c->wait_events, key); + SetEvent(event); + } + } +} + +int pa_cond_wait(pa_cond *c, pa_mutex *m) { + HANDLE event; + + assert(c); + assert(m); + + event = CreateEvent(NULL, FALSE, FALSE, NULL); + assert(event); + + pa_hashmap_put(c->wait_events, event, event); + + pa_mutex_unlock(m); + + WaitForSingleObject(event, INFINITE); + + pa_mutex_lock(m); + + pa_hashmap_remove(c->wait_events, event); + + CloseHandle(event); + + return 0; +} diff --git a/src/pulsecore/thread-win32.c b/src/pulsecore/thread-win32.c new file mode 100644 index 00000000..bdcc5b2c --- /dev/null +++ b/src/pulsecore/thread-win32.c @@ -0,0 +1,246 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include +#include + +#include "thread.h" + +struct pa_thread { + HANDLE thread; + pa_thread_func_t thread_func; + void *userdata; +}; + +struct pa_tls { + DWORD index; + pa_free_cb_t free_func; +}; + +struct pa_tls_monitor { + HANDLE thread; + pa_free_cb_t free_func; + void *data; +}; + +static pa_tls *thread_tls = NULL; +static pa_tls *monitor_tls = NULL; + +static void thread_tls_once_func(void) { + HANDLE mutex; + char name[64]; + + sprintf(name, "pulse%d", (int)GetCurrentProcessId()); + + mutex = CreateMutex(NULL, FALSE, name); + assert(mutex); + + WaitForSingleObject(mutex, INFINITE); + + if (thread_tls == NULL) { + thread_tls = pa_tls_new(NULL); + assert(thread_tls); + } + + ReleaseMutex(mutex); + + CloseHandle(mutex); +} + +static DWORD WINAPI internal_thread_func(LPVOID param) { + pa_thread *t = param; + assert(t); + + thread_tls_once_func(); + pa_tls_set(thread_tls, t); + + t->thread_func(t->userdata); + + return 0; +} + +pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) { + pa_thread *t; + + assert(thread_func); + + t = pa_xnew(pa_thread, 1); + t->thread_func = thread_func; + t->userdata = userdata; + + t->thread = CreateThread(NULL, 0, internal_thread_func, t, 0, NULL); + + if (!t->thread) { + pa_xfree(t); + return NULL; + } + + return t; +} + +int pa_thread_is_running(pa_thread *t) { + DWORD code; + + assert(t); + + if (!GetExitCodeThread(t->thread, &code)) + return 0; + + return code == STILL_ACTIVE; +} + +void pa_thread_free(pa_thread *t) { + assert(t); + + pa_thread_join(t); + CloseHandle(t->thread); + pa_xfree(t); +} + +int pa_thread_join(pa_thread *t) { + assert(t); + + if (WaitForSingleObject(t->thread, INFINITE) == WAIT_FAILED) + return -1; + + return 0; +} + +pa_thread* pa_thread_self(void) { + thread_tls_once_func(); + return pa_tls_get(thread_tls); +} + +void pa_thread_yield(void) { + Sleep(0); +} + +static void monitor_tls_once_func(void) { + HANDLE mutex; + char name[64]; + + sprintf(name, "pulse%d", (int)GetCurrentProcessId()); + + mutex = CreateMutex(NULL, FALSE, name); + assert(mutex); + + WaitForSingleObject(mutex, INFINITE); + + if (monitor_tls == NULL) { + monitor_tls = pa_tls_new(NULL); + assert(monitor_tls); + pa_tls_set(monitor_tls, NULL); + } + + ReleaseMutex(mutex); + + CloseHandle(mutex); +} + +static DWORD WINAPI monitor_thread_func(LPVOID param) { + struct pa_tls_monitor *m = param; + assert(m); + + WaitForSingleObject(m->thread, INFINITE); + + CloseHandle(m->thread); + + m->free_func(m->data); + + pa_xfree(m); + + return 0; +} + +pa_tls* pa_tls_new(pa_free_cb_t free_cb) { + pa_tls *t; + + t = pa_xnew(pa_tls, 1); + t->index = TlsAlloc(); + t->free_func = free_cb; + + if (t->index == TLS_OUT_OF_INDEXES) { + pa_xfree(t); + return NULL; + } + + return t; +} + +void pa_tls_free(pa_tls *t) { + assert(t); + + TlsFree(t->index); + pa_xfree(t); +} + +void *pa_tls_get(pa_tls *t) { + assert(t); + + return TlsGetValue(t->index); +} + +void *pa_tls_set(pa_tls *t, void *userdata) { + void *r; + + assert(t); + + r = TlsGetValue(t->index); + + TlsSetValue(t->index, userdata); + + if (t->free_func) { + struct pa_tls_monitor *m; + + monitor_tls_once_func(); + + m = pa_tls_get(monitor_tls); + if (!m) { + HANDLE thread; + + m = pa_xnew(struct pa_tls_monitor, 1); + + DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), + GetCurrentProcess(), &m->thread, 0, FALSE, + DUPLICATE_SAME_ACCESS); + + m->free_func = t->free_func; + + pa_tls_set(monitor_tls, m); + + thread = CreateThread(NULL, 0, monitor_thread_func, m, 0, NULL); + assert(thread); + CloseHandle(thread); + } + + m->data = userdata; + } + + return r; +} -- cgit From f84c65ed86ae59aae6e9a48e62aca31eaa30e2e3 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 1 Sep 2006 18:39:55 +0000 Subject: Add pthread_once() equivalent support. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1357 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/thread-posix.c | 25 ++++++++++++++++++++ src/pulsecore/thread-win32.c | 56 ++++++++++++++++++++------------------------ src/pulsecore/thread.h | 5 ++++ 3 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c index 4c12ec93..bc71ea47 100644 --- a/src/pulsecore/thread-posix.c +++ b/src/pulsecore/thread-posix.c @@ -30,6 +30,7 @@ #include #include +#include #include "thread.h" @@ -52,6 +53,9 @@ struct pa_tls { static pa_tls *thread_tls; static pthread_once_t thread_tls_once = PTHREAD_ONCE_INIT; +static pa_mutex *once_mutex; +static pthread_once_t thread_once_once = PTHREAD_ONCE_INIT; + static void thread_tls_once_func(void) { thread_tls = pa_tls_new(NULL); assert(thread_tls); @@ -125,6 +129,27 @@ void pa_thread_yield(void) { #endif } +static void thread_once_once_func(void) { + once_mutex = pa_mutex_new(); + assert(once_mutex); +} + +void pa_thread_once(pa_thread_once_t *control, pa_thread_once_func_t once_func) { + assert(control); + assert(once_func); + + ASSERT_SUCCESS(pthread_once(&thread_once_once, thread_once_once_func)); + + pa_mutex_lock(once_mutex); + + if (*control == PA_THREAD_ONCE_INIT) { + *control = ~PA_THREAD_ONCE_INIT; + pa_mutex_unlock(once_mutex); + once_func(); + } else + pa_mutex_unlock(once_mutex); +} + pa_tls* pa_tls_new(pa_free_cb_t free_cb) { pa_tls *t; diff --git a/src/pulsecore/thread-win32.c b/src/pulsecore/thread-win32.c index bdcc5b2c..ee61d85a 100644 --- a/src/pulsecore/thread-win32.c +++ b/src/pulsecore/thread-win32.c @@ -49,35 +49,21 @@ struct pa_tls_monitor { void *data; }; -static pa_tls *thread_tls = NULL; -static pa_tls *monitor_tls = NULL; +static pa_tls *thread_tls; +static pa_thread_once_t thread_tls_once = PA_THREAD_ONCE_INIT; +static pa_tls *monitor_tls; +static pa_thread_once_t monitor_tls_once = PA_THREAD_ONCE_INIT; static void thread_tls_once_func(void) { - HANDLE mutex; - char name[64]; - - sprintf(name, "pulse%d", (int)GetCurrentProcessId()); - - mutex = CreateMutex(NULL, FALSE, name); - assert(mutex); - - WaitForSingleObject(mutex, INFINITE); - - if (thread_tls == NULL) { - thread_tls = pa_tls_new(NULL); - assert(thread_tls); - } - - ReleaseMutex(mutex); - - CloseHandle(mutex); + thread_tls = pa_tls_new(NULL); + assert(thread_tls); } static DWORD WINAPI internal_thread_func(LPVOID param) { pa_thread *t = param; assert(t); - thread_tls_once_func(); + pa_thread_once(&thread_tls_once, thread_tls_once_func); pa_tls_set(thread_tls, t); t->thread_func(t->userdata); @@ -133,7 +119,7 @@ int pa_thread_join(pa_thread *t) { } pa_thread* pa_thread_self(void) { - thread_tls_once_func(); + pa_thread_once(&thread_tls_once, thread_tls_once_func); return pa_tls_get(thread_tls); } @@ -141,10 +127,13 @@ void pa_thread_yield(void) { Sleep(0); } -static void monitor_tls_once_func(void) { +void pa_thread_once(pa_thread_once_t *control, pa_thread_once_func_t once_func) { HANDLE mutex; char name[64]; + assert(control); + assert(once_func); + sprintf(name, "pulse%d", (int)GetCurrentProcessId()); mutex = CreateMutex(NULL, FALSE, name); @@ -152,17 +141,22 @@ static void monitor_tls_once_func(void) { WaitForSingleObject(mutex, INFINITE); - if (monitor_tls == NULL) { - monitor_tls = pa_tls_new(NULL); - assert(monitor_tls); - pa_tls_set(monitor_tls, NULL); - } - - ReleaseMutex(mutex); + if (*control == PA_THREAD_ONCE_INIT) { + *control = ~PA_THREAD_ONCE_INIT; + ReleaseMutex(mutex); + once_func(); + } else + ReleaseMutex(mutex); CloseHandle(mutex); } +static void monitor_tls_once_func(void) { + monitor_tls = pa_tls_new(NULL); + assert(monitor_tls); + pa_tls_set(monitor_tls, NULL); +} + static DWORD WINAPI monitor_thread_func(LPVOID param) { struct pa_tls_monitor *m = param; assert(m); @@ -218,7 +212,7 @@ void *pa_tls_set(pa_tls *t, void *userdata) { if (t->free_func) { struct pa_tls_monitor *m; - monitor_tls_once_func(); + pa_thread_once(&monitor_tls_once, monitor_tls_once_func); m = pa_tls_get(monitor_tls); if (!m) { diff --git a/src/pulsecore/thread.h b/src/pulsecore/thread.h index 9b99c8c2..8aabecfa 100644 --- a/src/pulsecore/thread.h +++ b/src/pulsecore/thread.h @@ -24,9 +24,13 @@ #include +#define PA_THREAD_ONCE_INIT 0 + typedef struct pa_thread pa_thread; typedef void (*pa_thread_func_t) (void *userdata); +typedef void (*pa_thread_once_func_t) (void); +typedef unsigned int pa_thread_once_t; pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata); void pa_thread_free(pa_thread *t); @@ -34,6 +38,7 @@ int pa_thread_join(pa_thread *t); int pa_thread_is_running(pa_thread *t); pa_thread *pa_thread_self(void); void pa_thread_yield(void); +void pa_thread_once(pa_thread_once_t *control, pa_thread_once_func_t once_func); typedef struct pa_tls pa_tls; -- cgit From 647ef180c3dac933963fdfeca53772bd3be894ae Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 1 Sep 2006 19:06:44 +0000 Subject: Fix call to pa_mutex_new(). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1358 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/thread-posix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c index bc71ea47..2e8d6b68 100644 --- a/src/pulsecore/thread-posix.c +++ b/src/pulsecore/thread-posix.c @@ -130,7 +130,7 @@ void pa_thread_yield(void) { } static void thread_once_once_func(void) { - once_mutex = pa_mutex_new(); + once_mutex = pa_mutex_new(0); assert(once_mutex); } -- cgit From 5fa9cdb6b4be9f5998af462a858124a528914bf3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 2 Sep 2006 12:03:18 +0000 Subject: Merge FreeBSD compatibility patch (from Flameeyes) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1359 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/oss-util.c | 8 ++++++++ src/utils/padsp.c | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index d1c623b4..0aaf6971 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -93,7 +93,11 @@ success: pa_log_debug("capabilities:%s%s%s%s%s%s%s%s%s%s%s%s%s%s", *pcaps & DSP_CAP_BATCH ? " BATCH" : "", +#ifdef DSP_CAP_BIND *pcaps & DSP_CAP_BIND ? " BIND" : "", +#else + "", +#endif *pcaps & DSP_CAP_COPROC ? " COPROC" : "", *pcaps & DSP_CAP_DUPLEX ? " DUPLEX" : "", #ifdef DSP_CAP_FREERATE @@ -112,7 +116,11 @@ success: #else "", #endif +#ifdef DSP_CAP_MULTI *pcaps & DSP_CAP_MULTI ? " MULTI" : "", +#else + "", +#endif #ifdef DSP_CAP_OUTPUT *pcaps & DSP_CAP_OUTPUT ? " OUTPUT" : "", #else diff --git a/src/utils/padsp.c b/src/utils/padsp.c index ddb732f0..dfef3f3a 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -53,6 +53,11 @@ #include #include +/* On some systems SIOCINQ isn't defined, but FIONREAD is just an alias */ +#if !defined(SIOCINQ) && defined(FIONREAD) +# define SIOCINQ FIONREAD +#endif + typedef enum { FD_INFO_MIXER, FD_INFO_STREAM, -- cgit From 161c2c0c45bb10e8be1d58771297d4df672bfaa2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 2 Sep 2006 12:28:17 +0000 Subject: make esdcompat executable git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1360 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Makefile.am b/src/Makefile.am index 5043197c..487b7ff7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1272,6 +1272,7 @@ esdcompat: daemon/esdcompat.in Makefile sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ -e 's,@PA_BINARY\@,$(PA_BINARY),g' < $< > $@ + chmod +x esdcompat client.conf: pulse/client.conf.in Makefile sed -e 's,@PA_BINARY\@,$(PA_BINARY),g' < $< > $@ -- cgit From 11b6c451b88099d2094183de5f4237ec578f4cfe Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 2 Sep 2006 12:28:40 +0000 Subject: fix esdcompat for non-gnu systems git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1361 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/esdcompat.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/daemon/esdcompat.in b/src/daemon/esdcompat.in index ece1f4f9..942389d2 100755 --- a/src/daemon/esdcompat.in +++ b/src/daemon/esdcompat.in @@ -28,7 +28,7 @@ fail() { ARGS=" --log-target=syslog" -for N in $(seq $#) ; do +while [ "$#" -gt "0" ]; do case "$1" in "") -- cgit From a00c3cb9afc3848fc3369b16a3187354176d3b99 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 2 Sep 2006 12:45:53 +0000 Subject: fix a few autoconf warnings (patch by Flameeyes) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1362 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 7d85b32a..48b86cd3 100644 --- a/configure.ac +++ b/configure.ac @@ -143,9 +143,18 @@ AC_HEADER_STDC # POSIX AC_CHECK_HEADERS([arpa/inet.h glob.h grp.h netdb.h netinet/in.h \ - netinet/in_systm.h netinet/ip.h netinet/tcp.h pwd.h sched.h \ + netinet/in_systm.h netinet/tcp.h pwd.h sched.h \ sys/mman.h sys/resource.h sys/select.h sys/socket.h sys/wait.h \ syslog.h]) +AC_CHECK_HEADERS([netinet/ip.h], [], [], + [#include + #if HAVE_NETINET_IN_H + # include + #endif + #if HAVE_NETINET_IN_SYSTM_H + # include + #endif + ]) AC_CHECK_HEADERS([regex.h], [HAVE_REGEX=1], [HAVE_REGEX=0]) AC_CHECK_HEADERS([sys/un.h], [HAVE_AF_UNIX=1], [HAVE_AF_UNIX=0]) -- cgit From 6528b6b19efeacc72bcb93b1eb78547eac8bd98c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 2 Sep 2006 12:51:44 +0000 Subject: allow building when srcdir != builddir (patch from Flameeyes) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1363 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index 487b7ff7..22e0a5c9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -995,7 +995,12 @@ SYMDEF_FILES = \ EXTRA_DIST += $(SYMDEF_FILES) BUILT_SOURCES += $(SYMDEF_FILES) -$(SYMDEF_FILES): modules/module-defs.h.m4 +modulesdirs: + $(mkdir_p) modules + $(mkdir_p) modules/gconf + $(mkdir_p) modules/rtp + +$(SYMDEF_FILES): modules/module-defs.h.m4 modulesdirs $(M4) -Dfname="$@" $< > $@ # Simple protocol -- cgit From b01fabff657656ad29c3dcce80048cdac959f0fc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 2 Sep 2006 14:56:41 +0000 Subject: update acx_pthread.m4 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1364 fefdeb5f-60dc-0310-8127-8f9354f1896f --- acinclude.m4 | 217 ++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 177 insertions(+), 40 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index f3a4ac52..723eb87e 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -1,6 +1,55 @@ -dnl Available from the GNU Autoconf Macro Archive at: -dnl http://www.gnu.org/software/ac-archive/htmldoc/acx_pthread.html +dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) dnl +dnl @summary figure out how to build C programs using POSIX threads +dnl +dnl This macro figures out how to build C programs using POSIX threads. +dnl It sets the PTHREAD_LIBS output variable to the threads library and +dnl linker flags, and the PTHREAD_CFLAGS output variable to any special +dnl C compiler flags that are needed. (The user can also force certain +dnl compiler flags/libs to be tested by setting these environment +dnl variables.) +dnl +dnl Also sets PTHREAD_CC to any special C compiler that is needed for +dnl multi-threaded programs (defaults to the value of CC otherwise). +dnl (This is necessary on AIX to use the special cc_r compiler alias.) +dnl +dnl NOTE: You are assumed to not only compile your program with these +dnl flags, but also link it with them as well. e.g. you should link +dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS +dnl $LIBS +dnl +dnl If you are only building threads programs, you may wish to use +dnl these variables in your default LIBS, CFLAGS, and CC: +dnl +dnl LIBS="$PTHREAD_LIBS $LIBS" +dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +dnl CC="$PTHREAD_CC" +dnl +dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute +dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to +dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +dnl +dnl ACTION-IF-FOUND is a list of shell commands to run if a threads +dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to +dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the +dnl default action will define HAVE_PTHREAD. +dnl +dnl Please let the authors know if this macro fails on any platform, or +dnl if you have any other suggestions or comments. This macro was based +dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with +dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros +dnl posted by Alejandro Forero Cuervo to the autoconf macro repository. +dnl We are also grateful for the helpful feedback of numerous users. +dnl +dnl @category InstalledPackages +dnl @author Steven G. Johnson +dnl @version 2006-05-29 +dnl @license GPLWithACException +dnl +dnl Checks for GCC shared/pthread inconsistency based on work by +dnl Marcin Owsiany + + AC_DEFUN([ACX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_SAVE @@ -57,6 +106,7 @@ acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -m # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) +# ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) @@ -66,13 +116,13 @@ case "${host_cpu}-${host_os}" in # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (We need to link with -pthread or + # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: - acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags" + acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" ;; esac @@ -142,54 +192,142 @@ if test "x$acx_pthread_ok" = xyes; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - # Detect AIX lossage: threads are created detached by default - # and the JOINABLE attribute has a nonstandard name (UNDETACHED). - AC_MSG_CHECKING([for joinable pthread attribute]) - AC_TRY_LINK([#include ], - [int attr=PTHREAD_CREATE_JOINABLE;], - ok=PTHREAD_CREATE_JOINABLE, ok=unknown) - if test x"$ok" = xunknown; then - AC_TRY_LINK([#include ], - [int attr=PTHREAD_CREATE_UNDETACHED;], - ok=PTHREAD_CREATE_UNDETACHED, ok=unknown) - fi - if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then - AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok, - [Define to the necessary symbol if this constant - uses a non-standard name on your system.]) - fi - AC_MSG_RESULT(${ok}) - if test x"$ok" = xunknown; then - AC_MSG_WARN([we do not know how to create joinable pthreads]) + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + AC_MSG_CHECKING([for joinable pthread attribute]) + attr_name=unknown + for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_TRY_LINK([#include ], [int attr=$attr; return attr;], + [attr_name=$attr; break]) + done + AC_MSG_RESULT($attr_name) + if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then + AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case "${host_cpu}-${host_os}" in - *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; - *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; + *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; + *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; esac AC_MSG_RESULT(${flag}) if test "x$flag" != xno; then - PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" - fi - - AC_MSG_CHECKING([if pthread_yield is available]) - flag=no - AC_TRY_LINK([#include ], - [pthread_yield();], - [flag=yes]) - AC_MSG_RESULT(${flag}) - if test "x$flag" != xno; then - AC_DEFINE(HAVE_PTHREAD_YIELD, 1, - [Define to 1 if you have the 'pthread_yield' function.]) + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" + # More AIX lossage: must compile with xlc_r or cc_r + if test x"$GCC" != xyes; then + AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) + else + PTHREAD_CC=$CC + fi - # More AIX lossage: must compile with cc_r - AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC}) + # The next part tries to detect GCC inconsistency with -shared on some + # architectures and systems. The problem is that in certain + # configurations, when -shared is specified, GCC "forgets" to + # internally use various flags which are still necessary. + + AC_MSG_CHECKING([whether to check for GCC pthread/shared inconsistencies]) + check_inconsistencies=yes + case "${host_cpu}-${host_os}" in + *-darwin*) check_inconsistencies=no ;; + esac + if test x"$GCC" != xyes -o "x$check_inconsistencies" != xyes ; then + AC_MSG_RESULT([no]) + else + AC_MSG_RESULT([yes]) + + # In order not to create several levels of indentation, we test + # the value of "$ok" until we find out the cure or run out of + # ideas. + ok="no" + + # + # Prepare the flags + # + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + save_CC="$CC" + # Try with the flags determined by the earlier checks. + # + # -Wl,-z,defs forces link-time symbol resolution, so that the + # linking checks with -shared actually have any value + # + # FIXME: -fPIC is required for -shared on many architectures, + # so we specify it here, but the right way would probably be to + # properly detect whether it is actually required. + CFLAGS="-shared -fPIC -Wl,-z,defs $CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CC="$PTHREAD_CC" + + AC_MSG_CHECKING([whether -pthread is sufficient with -shared]) + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [ok=yes]) + + if test "x$ok" = xyes; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + + # + # Linux gcc on some architectures such as mips/mipsel forgets + # about -lpthread + # + if test x"$ok" = xno; then + AC_MSG_CHECKING([whether -lpthread fixes that]) + LIBS="-lpthread $PTHREAD_LIBS $save_LIBS" + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [ok=yes]) + + if test "x$ok" = xyes; then + AC_MSG_RESULT([yes]) + PTHREAD_LIBS="-lpthread $PTHREAD_LIBS" + else + AC_MSG_RESULT([no]) + fi + fi + # + # FreeBSD 4.10 gcc forgets to use -lc_r instead of -lc + # + if test x"$ok" = xno; then + AC_MSG_CHECKING([whether -lc_r fixes that]) + LIBS="-lc_r $PTHREAD_LIBS $save_LIBS" + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [ok=yes]) + + if test "x$ok" = xyes; then + AC_MSG_RESULT([yes]) + PTHREAD_LIBS="-lc_r $PTHREAD_LIBS" + else + AC_MSG_RESULT([no]) + fi + fi + if test x"$ok" = xno; then + # OK, we have run out of ideas + AC_MSG_WARN([Impossible to determine how to use pthreads with shared libraries]) + + # so it's not safe to assume that we may use pthreads + acx_pthread_ok=no + fi + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + CC="$save_CC" + fi else PTHREAD_CC="$CC" fi @@ -208,7 +346,6 @@ else fi AC_LANG_RESTORE ])dnl ACX_PTHREAD - AC_DEFUN([AC_CHECK_DEFINE],[ AS_VAR_PUSHDEF([ac_var],[ac_cv_defined_$1_$2])dnl AC_CACHE_CHECK([for $1 in $2], ac_var, -- cgit From e504e807ce43df0a7bc0bad1158e06aca31368c3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 2 Sep 2006 14:57:50 +0000 Subject: include PTRHEAD_LIBS in pkg-config file (patch from Flameeyes) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1365 fefdeb5f-60dc-0310-8127-8f9354f1896f --- libpulse.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libpulse.pc.in b/libpulse.pc.in index 45fec220..0f01799b 100644 --- a/libpulse.pc.in +++ b/libpulse.pc.in @@ -6,6 +6,6 @@ includedir=${prefix}/include Name: libpulse Description: Client Interface to PulseAudio Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpulse +Libs: -L${libdir} -lpulse @PTHREAD_LIBS@ Cflags: -D_REENTRANT -I${includedir} Requires: -- cgit From 2536ba9279f681eb97ba51bdc3b5cadad7c5c5fc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 2 Sep 2006 14:59:12 +0000 Subject: rework handling of srcdir != builddir (patch from Flameeyes) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1366 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 22e0a5c9..3dec5c1c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -42,7 +42,7 @@ endif # Compiler/linker flags # ################################### -AM_CFLAGS = -I$(top_srcdir)/src +AM_CFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src/modules -I$(top_builddir)/src/modules/rtp -I$(top_builddir)/src/modules/gconf AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS AM_CFLAGS += $(LTDLINCL) AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) @@ -995,12 +995,8 @@ SYMDEF_FILES = \ EXTRA_DIST += $(SYMDEF_FILES) BUILT_SOURCES += $(SYMDEF_FILES) -modulesdirs: - $(mkdir_p) modules - $(mkdir_p) modules/gconf - $(mkdir_p) modules/rtp - -$(SYMDEF_FILES): modules/module-defs.h.m4 modulesdirs +$(SYMDEF_FILES): modules/module-defs.h.m4 + $(mkdir_p) modules/gconf modules/rtp $(M4) -Dfname="$@" $< > $@ # Simple protocol -- cgit From 6db6c835ec450e4e70197f01e2fcf1b9c9d3e222 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 2 Sep 2006 15:18:56 +0000 Subject: add missing g_type_init() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1367 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/gconf/gconf-helper.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/gconf/gconf-helper.c b/src/modules/gconf/gconf-helper.c index 72454817..40724f4e 100644 --- a/src/modules/gconf/gconf-helper.c +++ b/src/modules/gconf/gconf-helper.c @@ -97,6 +97,8 @@ int main(int argc, char *argv[]) { GConfClient *client; GSList *modules, *m; + g_type_init(); + if (!(client = gconf_client_get_default())) goto fail; -- cgit From 8e7c2a3b0c2fd67802222b3f216bc67bb2c1fe70 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 4 Sep 2006 21:28:34 +0000 Subject: make pa_thread_self() return a sensible pointer on foreign threads git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1368 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/thread-posix.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c index 2e8d6b68..43ad2d52 100644 --- a/src/pulsecore/thread-posix.c +++ b/src/pulsecore/thread-posix.c @@ -117,15 +117,32 @@ int pa_thread_join(pa_thread *t) { } pa_thread* pa_thread_self(void) { + pa_thread *t; + ASSERT_SUCCESS(pthread_once(&thread_tls_once, thread_tls_once_func)); - return pa_tls_get(thread_tls); + + if ((t = pa_tls_get(thread_tls))) + return t; + + /* This is a foreign thread, let's create a pthread structure to + * make sure that we can always return a sensible pointer */ + + t = pa_xnew(pa_thread, 1); + t->id = pthread_self(); + t->thread_func = NULL; + t->userdata = NULL; + AO_store_full(&t->running, 1); + + pa_tls_set(thread_tls, t); + + return t; } void pa_thread_yield(void) { #ifdef HAVE_PTHREAD_YIELD pthread_yield(); #else - sched_yield(); + ASSERT_SUCCESS(sched_yield()); #endif } -- cgit From 813e95f3b88a8345f82a205126d94bbffeda57b9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 4 Sep 2006 21:29:17 +0000 Subject: port the threaded mainloop to our new abstract mutex/thread API git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1369 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 6 + src/pulse/thread-mainloop.c | 331 ++++++-------------------------------------- 2 files changed, 49 insertions(+), 288 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 3dec5c1c..69c6ac34 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -619,10 +619,16 @@ if OS_IS_WIN32 libpulsecore_la_SOURCES += \ pulsecore/mutex-win32.c \ pulsecore/thread-win32.c +libpulse_la_SOURCES += \ + pulsecore/mutex-win32.c \ + pulsecore/thread-win32.c else libpulsecore_la_SOURCES += \ pulsecore/mutex-posix.c \ pulsecore/thread-posix.c +libpulse_la_SOURCES += \ + pulsecore/mutex-posix.c \ + pulsecore/thread-posix.c endif libpulsecore_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBOIL_CFLAGS) diff --git a/src/pulse/thread-mainloop.c b/src/pulse/thread-mainloop.c index b1b180a0..060782b5 100644 --- a/src/pulse/thread-mainloop.c +++ b/src/pulse/thread-mainloop.c @@ -33,57 +33,31 @@ #include "../pulsecore/poll.h" #endif -#ifdef HAVE_PTHREAD -#include -#endif - -#ifdef HAVE_WINDOWS_H -#include -#endif - #include #include #include +#include +#include #include "mainloop.h" #include "thread-mainloop.h" -#if defined(HAVE_PTHREAD) || defined(OS_IS_WIN32) - struct pa_threaded_mainloop { pa_mainloop *real_mainloop; int n_waiting; - int thread_running; - -#ifdef OS_IS_WIN32 - DWORD thread_id; - HANDLE thread; - CRITICAL_SECTION mutex; - pa_hashmap *cond_events; - HANDLE accept_cond; -#else - pthread_t thread_id; - pthread_mutex_t mutex; - pthread_cond_t cond, accept_cond; -#endif + + pa_thread* thread; + pa_mutex* mutex; + pa_cond* cond, *accept_cond; }; static inline int in_worker(pa_threaded_mainloop *m) { -#ifdef OS_IS_WIN32 - return GetCurrentThreadId() == m->thread_id; -#else - return pthread_equal(pthread_self(), m->thread_id); -#endif + return pa_thread_self() == m->thread; } static int poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) { -#ifdef OS_IS_WIN32 - CRITICAL_SECTION *mutex = userdata; -#else - pthread_mutex_t *mutex = userdata; -#endif - + pa_mutex *mutex = userdata; int r; assert(mutex); @@ -91,28 +65,14 @@ static int poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void /* Before entering poll() we unlock the mutex, so that * avahi_simple_poll_quit() can succeed from another thread. */ -#ifdef OS_IS_WIN32 - LeaveCriticalSection(mutex); -#else - pthread_mutex_unlock(mutex); -#endif - + pa_mutex_unlock(mutex); r = poll(ufds, nfds, timeout); - -#ifdef OS_IS_WIN32 - EnterCriticalSection(mutex); -#else - pthread_mutex_lock(mutex); -#endif + pa_mutex_lock(mutex); return r; } -#ifdef OS_IS_WIN32 -static DWORD WINAPI thread(void *userdata) { -#else -static void* thread(void *userdata) { -#endif +static void thread(void *userdata) { pa_threaded_mainloop *m = userdata; #ifndef OS_IS_WIN32 @@ -123,32 +83,15 @@ static void* thread(void *userdata) { pthread_sigmask(SIG_BLOCK, &mask, NULL); #endif -#ifdef OS_IS_WIN32 - EnterCriticalSection(&m->mutex); -#else - pthread_mutex_lock(&m->mutex); -#endif + pa_mutex_lock(m->mutex); pa_mainloop_run(m->real_mainloop, NULL); -#ifdef OS_IS_WIN32 - LeaveCriticalSection(&m->mutex); -#else - pthread_mutex_unlock(&m->mutex); -#endif - -#ifdef OS_IS_WIN32 - return 0; -#else - return NULL; -#endif + pa_mutex_unlock(m->mutex); } pa_threaded_mainloop *pa_threaded_mainloop_new(void) { pa_threaded_mainloop *m; -#ifndef OS_IS_WIN32 - pthread_mutexattr_t a; -#endif m = pa_xnew(pa_threaded_mainloop, 1); @@ -157,26 +100,13 @@ pa_threaded_mainloop *pa_threaded_mainloop_new(void) { return NULL; } - pa_mainloop_set_poll_func(m->real_mainloop, poll_func, &m->mutex); + m->mutex = pa_mutex_new(1); + m->cond = pa_cond_new(); + m->accept_cond = pa_cond_new(); + m->thread = NULL; -#ifdef OS_IS_WIN32 - InitializeCriticalSection(&m->mutex); - - m->cond_events = pa_hashmap_new(NULL, NULL); - assert(m->cond_events); - m->accept_cond = CreateEvent(NULL, FALSE, FALSE, NULL); - assert(m->accept_cond); -#else - pthread_mutexattr_init(&a); - pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&m->mutex, &a); - pthread_mutexattr_destroy(&a); - - pthread_cond_init(&m->cond, NULL); - pthread_cond_init(&m->accept_cond, NULL); -#endif + pa_mainloop_set_poll_func(m->real_mainloop, poll_func, m->mutex); - m->thread_running = 0; m->n_waiting = 0; return m; @@ -186,22 +116,17 @@ void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { assert(m); /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); + assert((m->thread && !pa_thread_is_running(m->thread)) || !in_worker(m)); - if (m->thread_running) - pa_threaded_mainloop_stop(m); + pa_threaded_mainloop_stop(m); - if (m->real_mainloop) - pa_mainloop_free(m->real_mainloop); + pa_thread_free(m->thread); -#ifdef OS_IS_WIN32 - pa_hashmap_free(m->cond_events, NULL, NULL); - CloseHandle(m->accept_cond); -#else - pthread_mutex_destroy(&m->mutex); - pthread_cond_destroy(&m->cond); - pthread_cond_destroy(&m->accept_cond); -#endif + pa_mainloop_free(m->real_mainloop); + + pa_mutex_free(m->mutex); + pa_cond_free(m->cond); + pa_cond_free(m->accept_cond); pa_xfree(m); } @@ -209,36 +134,10 @@ void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { int pa_threaded_mainloop_start(pa_threaded_mainloop *m) { assert(m); - assert(!m->thread_running); - -#ifdef OS_IS_WIN32 - - EnterCriticalSection(&m->mutex); + assert(!m->thread || !pa_thread_is_running(m->thread)); - m->thread = CreateThread(NULL, 0, thread, m, 0, &m->thread_id); - if (!m->thread) { - LeaveCriticalSection(&m->mutex); + if (!(m->thread = pa_thread_new(thread, m))) return -1; - } - -#else - - pthread_mutex_lock(&m->mutex); - - if (pthread_create(&m->thread_id, NULL, thread, m) < 0) { - pthread_mutex_unlock(&m->mutex); - return -1; - } - -#endif - - m->thread_running = 1; - -#ifdef OS_IS_WIN32 - LeaveCriticalSection(&m->mutex); -#else - pthread_mutex_unlock(&m->mutex); -#endif return 0; } @@ -246,148 +145,55 @@ int pa_threaded_mainloop_start(pa_threaded_mainloop *m) { void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) { assert(m); - if (!m->thread_running) + if (!m->thread || !pa_thread_is_running(m->thread)) return; /* Make sure that this function is not called from the helper thread */ assert(!in_worker(m)); -#ifdef OS_IS_WIN32 - EnterCriticalSection(&m->mutex); -#else - pthread_mutex_lock(&m->mutex); -#endif - + pa_mutex_lock(m->mutex); pa_mainloop_quit(m->real_mainloop, 0); + pa_mutex_unlock(m->mutex); -#ifdef OS_IS_WIN32 - LeaveCriticalSection(&m->mutex); -#else - pthread_mutex_unlock(&m->mutex); -#endif - -#ifdef OS_IS_WIN32 - WaitForSingleObject(m->thread, INFINITE); - CloseHandle(m->thread); -#else - pthread_join(m->thread_id, NULL); -#endif - - m->thread_running = 0; - - return; + pa_thread_join(m->thread); } void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) { assert(m); /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); + assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); -#ifdef OS_IS_WIN32 - EnterCriticalSection(&m->mutex); -#else - pthread_mutex_lock(&m->mutex); -#endif + pa_mutex_lock(m->mutex); } void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { assert(m); /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); + assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); -#ifdef OS_IS_WIN32 - LeaveCriticalSection(&m->mutex); -#else - pthread_mutex_unlock(&m->mutex); -#endif + pa_mutex_unlock(m->mutex); } void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept) { -#ifdef OS_IS_WIN32 - void *iter; - const void *key; - HANDLE event; -#endif - assert(m); -#ifdef OS_IS_WIN32 - - iter = NULL; - while (1) { - pa_hashmap_iterate(m->cond_events, &iter, &key); - if (key == NULL) - break; - event = (HANDLE)pa_hashmap_get(m->cond_events, key); - SetEvent(event); - } - -#else - - pthread_cond_broadcast(&m->cond); - -#endif - - if (wait_for_accept && m->n_waiting > 0) { - -#ifdef OS_IS_WIN32 - - /* This is just to make sure it's unsignaled */ - WaitForSingleObject(m->accept_cond, 0); - - LeaveCriticalSection(&m->mutex); - - WaitForSingleObject(m->accept_cond, INFINITE); - - EnterCriticalSection(&m->mutex); - -#else - - pthread_cond_wait(&m->accept_cond, &m->mutex); + pa_cond_signal(m->cond, 1); -#endif - - } + if (wait_for_accept && m->n_waiting > 0) + pa_cond_wait(m->accept_cond, m->mutex); } void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { -#ifdef OS_IS_WIN32 - HANDLE event; - DWORD result; -#endif - assert(m); /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); + assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); m->n_waiting ++; -#ifdef OS_IS_WIN32 - - event = CreateEvent(NULL, FALSE, FALSE, NULL); - assert(event); - - pa_hashmap_put(m->cond_events, event, event); - - LeaveCriticalSection(&m->mutex); - - result = WaitForSingleObject(event, INFINITE); - assert(result == WAIT_OBJECT_0); - - EnterCriticalSection(&m->mutex); - - pa_hashmap_remove(m->cond_events, event); - - CloseHandle(event); - -#else - - pthread_cond_wait(&m->cond, &m->mutex); - -#endif + pa_cond_wait(m->cond, m->mutex); assert(m->n_waiting > 0); m->n_waiting --; @@ -397,13 +203,9 @@ void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) { assert(m); /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); + assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); -#ifdef OS_IS_WIN32 - SetEvent(m->accept_cond); -#else - pthread_cond_signal(&m->accept_cond); -#endif + pa_cond_signal(m->accept_cond, 0); } int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) { @@ -417,50 +219,3 @@ pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) { return pa_mainloop_get_api(m->real_mainloop); } - -#else /* defined(OS_IS_WIN32) || defined(HAVE_PTHREAD) */ - -pa_threaded_mainloop *pa_threaded_mainloop_new(void) { - pa_log_error("Threaded main loop not supported on this platform"); - return NULL; -} - -void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { - assert(0); -} - -int pa_threaded_mainloop_start(pa_threaded_mainloop *m) { - assert(0); - return -1; -} - -void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) { - assert(0); -} - -void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) { - assert(0); -} - -void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { - assert(0); -} - -void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { - assert(0); -} - -void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_release) { - assert(0); -} - -int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) { - assert(0); -} - -pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) { - assert(0); - return NULL; -} - -#endif /* defined(OS_IS_WIN32) || defined(HAVE_PTHREAD) */ -- cgit From 3be920d9aec656e7e34672558e85ba025a4059d0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 4 Sep 2006 22:04:33 +0000 Subject: fix pa_thread_is_running() for foreign threads; fix a memory leak for foreign threads git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1370 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/thread-posix.c | 26 +++++++++++++++++++++++++- src/tests/thread-test.c | 2 ++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c index 43ad2d52..1b9a94a3 100644 --- a/src/pulsecore/thread-posix.c +++ b/src/pulsecore/thread-posix.c @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -56,8 +57,18 @@ static pthread_once_t thread_tls_once = PTHREAD_ONCE_INIT; static pa_mutex *once_mutex; static pthread_once_t thread_once_once = PTHREAD_ONCE_INIT; +static void tls_free_cb(void *p) { + pa_thread *t = p; + + assert(t); + + if (!t->thread_func) + /* This is a foreign thread, we need to free the struct */ + pa_xfree(t); +} + static void thread_tls_once_func(void) { - thread_tls = pa_tls_new(NULL); + thread_tls = pa_tls_new(tls_free_cb); assert(thread_tls); } @@ -80,6 +91,8 @@ static void* internal_thread_func(void *userdata) { pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) { pa_thread *t; + assert(thread_func); + t = pa_xnew(pa_thread, 1); t->thread_func = thread_func; t->userdata = userdata; @@ -99,6 +112,17 @@ int pa_thread_is_running(pa_thread *t) { AO_t r; assert(t); + if (!t->thread_func) { + /* Mhmm, this is a foreign thread, t->running is not + * necessarily valid. We misuse pthread_getschedparam() to + * check if the thread is valid. This might not be portable. */ + + int policy; + struct sched_param param; + + return pthread_getschedparam(t->id, &policy, ¶m) >= 0 || errno != ESRCH; + } + r = AO_load_full(&t->running); return r == 1 || r == 2; } diff --git a/src/tests/thread-test.c b/src/tests/thread-test.c index 120d2554..9e8afd9b 100644 --- a/src/tests/thread-test.c +++ b/src/tests/thread-test.c @@ -87,6 +87,8 @@ int main(int argc, char *argv[]) { int i, k; pa_thread* t[THREADS_MAX]; + assert(pa_thread_is_running(pa_thread_self())); + mutex = pa_mutex_new(0); cond1 = pa_cond_new(); cond2 = pa_cond_new(); -- cgit From 6bbfb43f2ac597c2d1ba95b0c4b7c9619dcb9a35 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 4 Sep 2006 22:15:15 +0000 Subject: add accessor functions for the userdata attached to a pa_thread object git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1371 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/thread-posix.c | 12 ++++++++++++ src/pulsecore/thread.h | 3 +++ 2 files changed, 15 insertions(+) diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c index 1b9a94a3..a2cb9b56 100644 --- a/src/pulsecore/thread-posix.c +++ b/src/pulsecore/thread-posix.c @@ -162,6 +162,18 @@ pa_thread* pa_thread_self(void) { return t; } +void* pa_thread_get_data(pa_thread *t) { + assert(t); + + return t->userdata; +} + +void pa_thread_set_data(pa_thread *t, void *userdata) { + assert(t); + + t->userdata = userdata; +} + void pa_thread_yield(void) { #ifdef HAVE_PTHREAD_YIELD pthread_yield(); diff --git a/src/pulsecore/thread.h b/src/pulsecore/thread.h index 8aabecfa..e50a707f 100644 --- a/src/pulsecore/thread.h +++ b/src/pulsecore/thread.h @@ -40,6 +40,9 @@ pa_thread *pa_thread_self(void); void pa_thread_yield(void); void pa_thread_once(pa_thread_once_t *control, pa_thread_once_func_t once_func); +void* pa_thread_get_data(pa_thread *t); +void pa_thread_set_data(pa_thread *t, void *userdata); + typedef struct pa_tls pa_tls; pa_tls* pa_tls_new(pa_free_cb_t free_cb); -- cgit From e00ba020cb712aee50c591fc66c6bc2ab3659deb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 4 Sep 2006 22:38:41 +0000 Subject: remove yet another occurence of pthread_yield() by pa_thread_yield() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1372 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/tests/interpol-test.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/tests/interpol-test.c b/src/tests/interpol-test.c index 3ec8a18f..54bdd775 100644 --- a/src/tests/interpol-test.c +++ b/src/tests/interpol-test.c @@ -33,17 +33,11 @@ #include #include -#ifdef HAVE_PTHREAD -#include -#endif - -#ifdef HAVE_WINDOWS_H -#include -#endif - #include #include +#include + static pa_context *context = NULL; static pa_stream *stream = NULL; static pa_mainloop_api *mainloop_api = NULL; @@ -152,13 +146,7 @@ int main(int argc, char *argv[]) { tv = now; while (pa_timeval_diff(pa_gettimeofday(&now), &tv) < 1000) -#ifdef HAVE_PTHREAD_YIELD - pthread_yield(); -#elif defined(OS_IS_WIN32) - Sleep(0); -#else - ; -#endif + pa_thread_yield(); } if (m) -- cgit From 65691997782da950f1e2f38700321e635cc5f37c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 6 Sep 2006 19:47:53 +0000 Subject: implement a few more ioctl()s, including a subset of SNDCTL_DSP_GETOPTR. Just enough to make JavaSound work. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1373 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp | 0 src/utils/padsp.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 72 insertions(+), 5 deletions(-) mode change 100644 => 100755 src/utils/padsp diff --git a/src/utils/padsp b/src/utils/padsp old mode 100644 new mode 100755 diff --git a/src/utils/padsp.c b/src/utils/padsp.c index dfef3f3a..b20f0d06 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -93,6 +93,8 @@ struct fd_info { pa_cvolume sink_volume, source_volume; uint32_t sink_index, source_index; int volume_modify_count; + + int optr_n_blocks; PA_LLIST_FIELDS(fd_info); }; @@ -579,6 +581,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { i->volume_modify_count = 0; i->sink_index = (uint32_t) -1; i->source_index = (uint32_t) -1; + i->optr_n_blocks = 0; PA_LLIST_INIT(fd_info, i); reset_params(i); @@ -1952,6 +1955,8 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) free_streams(i); dsp_flush_socket(i); reset_params(i); + + i->optr_n_blocks = 0; pa_threaded_mainloop_unlock(i->mainloop); break; @@ -2040,14 +2045,76 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) break; } + case SOUND_PCM_READ_RATE: + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_PCM_READ_RATE\n"); + + pa_threaded_mainloop_lock(i->mainloop); + *(int*) argp = i->sample_spec.rate; + pa_threaded_mainloop_unlock(i->mainloop); + break; + + case SOUND_PCM_READ_CHANNELS: + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_PCM_READ_CHANNELS\n"); + + pa_threaded_mainloop_lock(i->mainloop); + *(int*) argp = i->sample_spec.channels; + pa_threaded_mainloop_unlock(i->mainloop); + break; + + case SOUND_PCM_READ_BITS: + debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_PCM_READ_BITS\n"); + + pa_threaded_mainloop_lock(i->mainloop); + *(int*) argp = pa_sample_size(&i->sample_spec)*8; + pa_threaded_mainloop_unlock(i->mainloop); + break; + + case SNDCTL_DSP_GETOPTR: { + count_info *info; + + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETODELAY\n"); + + info = (count_info*) argp; + memset(info, 0, sizeof(*info)); + + pa_threaded_mainloop_lock(i->mainloop); + + for (;;) { + pa_usec_t usec; + + PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, exit_loop); + + if (pa_stream_get_time(i->play_stream, &usec) >= 0) { + size_t k = pa_usec_to_bytes(usec, &i->sample_spec); + int m; + + info->bytes = (int) k; + m = k / i->fragment_size; + info->blocks = m - i->optr_n_blocks; + i->optr_n_blocks = m; + + break; + } + + if (pa_context_errno(i->context) != PA_ERR_NODATA) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i->context))); + break; + } + + pa_threaded_mainloop_wait(i->mainloop); + } + + pa_threaded_mainloop_unlock(i->mainloop); + + debug(DEBUG_LEVEL_NORMAL, __FILE__": GETOPTR bytes=%i, blocks=%i, ptr=%i\n", info->bytes, info->blocks, info->ptr); + + break; + } + case SNDCTL_DSP_GETIPTR: debug(DEBUG_LEVEL_NORMAL, __FILE__": invalid ioctl SNDCTL_DSP_GETIPTR\n"); goto inval; - - case SNDCTL_DSP_GETOPTR: - debug(DEBUG_LEVEL_NORMAL, __FILE__": invalid ioctl SNDCTL_DSP_GETOPTR\n"); - goto inval; - + default: debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request); -- cgit From 66ec460845d2e3df08a447b3ba93ee1006b04846 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 6 Sep 2006 21:37:09 +0000 Subject: fix a bogus debug line git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1374 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index b20f0d06..883ffbd9 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -2072,7 +2072,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_GETOPTR: { count_info *info; - debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETODELAY\n"); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETOPTR\n"); info = (count_info*) argp; memset(info, 0, sizeof(*info)); -- cgit From ead67cda48f58ad8d1f53ce2c32e3b500dfc5a19 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 6 Sep 2006 22:19:11 +0000 Subject: fix indentation git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1375 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index 3b6434d7..63ee60ca 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -58,10 +58,10 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) { if (!shared) { if (!(pool = pa_mempool_new(shared))) { - pa_log("pa_mempool_new() failed."); + pa_log("pa_mempool_new() failed."); return NULL; } - } + } c = pa_xnew(pa_core, 1); -- cgit From 40ecf869d0f77a3af2ce59bc060c4bccd2baec25 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 6 Sep 2006 22:19:54 +0000 Subject: don't hit an assert in the client if posix shm is not available git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1376 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/context.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/pulse/context.c b/src/pulse/context.c index b700657b..a458c6b1 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -98,6 +98,8 @@ static void unlock_autospawn_lock_file(pa_context *c) { } } +static void context_free(pa_context *c); + pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { pa_context *c; @@ -148,7 +150,16 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { #endif pa_client_conf_env(c->conf); - c->mempool = pa_mempool_new(!c->conf->disable_shm); + if (!(c->mempool = pa_mempool_new(!c->conf->disable_shm))) { + + if (!c->conf->disable_shm) + c->mempool = pa_mempool_new(0); + + if (!c->mempool) { + context_free(c); + return NULL; + } + } return c; } @@ -178,7 +189,8 @@ static void context_free(pa_context *c) { if (c->playback_streams) pa_dynarray_free(c->playback_streams, NULL, NULL); - pa_mempool_free(c->mempool); + if (c->mempool) + pa_mempool_free(c->mempool); if (c->conf) pa_client_conf_free(c->conf); -- cgit From 40f18d97f6e84e56e8792212f6078519609dec47 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 7 Sep 2006 13:29:59 +0000 Subject: fix alsa-sink example git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1377 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/default.pa.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in index 03122669..a495f890 100755 --- a/src/daemon/default.pa.in +++ b/src/daemon/default.pa.in @@ -20,7 +20,7 @@ ### Load audio drivers statically #load-module module-alsa-sink -#load-module module-alsa-source device=plughw:1,0 +#load-module module-alsa-source device=hw:1,0 #load-module module-oss device="/dev/dsp" sink_name=output source_name=input #load-module module-oss-mmap device="/dev/dsp" sink_name=output source_name=input #load-module module-null-sink -- cgit From 0669c99fb6fedcd43af43466b7967b30b5af4f1d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 7 Sep 2006 13:31:53 +0000 Subject: add missing channel names (fixes a segfault when parsing invalid channel maps) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1378 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/channelmap.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/pulse/channelmap.c b/src/pulse/channelmap.c index a4f13372..69b09089 100644 --- a/src/pulse/channelmap.c +++ b/src/pulse/channelmap.c @@ -68,6 +68,22 @@ const char *const table[] = { [PA_CHANNEL_POSITION_AUX13] = "aux13", [PA_CHANNEL_POSITION_AUX14] = "aux14", [PA_CHANNEL_POSITION_AUX15] = "aux15", + [PA_CHANNEL_POSITION_AUX16] = "aux16", + [PA_CHANNEL_POSITION_AUX17] = "aux17", + [PA_CHANNEL_POSITION_AUX18] = "aux18", + [PA_CHANNEL_POSITION_AUX19] = "aux19", + [PA_CHANNEL_POSITION_AUX20] = "aux20", + [PA_CHANNEL_POSITION_AUX21] = "aux21", + [PA_CHANNEL_POSITION_AUX22] = "aux22", + [PA_CHANNEL_POSITION_AUX23] = "aux23", + [PA_CHANNEL_POSITION_AUX24] = "aux24", + [PA_CHANNEL_POSITION_AUX25] = "aux25", + [PA_CHANNEL_POSITION_AUX26] = "aux26", + [PA_CHANNEL_POSITION_AUX27] = "aux27", + [PA_CHANNEL_POSITION_AUX28] = "aux28", + [PA_CHANNEL_POSITION_AUX29] = "aux29", + [PA_CHANNEL_POSITION_AUX30] = "aux30", + [PA_CHANNEL_POSITION_AUX31] = "aux31", [PA_CHANNEL_POSITION_TOP_CENTER] = "top-center", -- cgit From 1728e3ac982146c0ff2d5e46571aadda6937e4fc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 7 Sep 2006 19:08:19 +0000 Subject: make pa_stream thread-safe: use new refcounting system, protect access using mutexes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1379 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/pstream.c | 121 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 93 insertions(+), 28 deletions(-) diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index 511972d9..566fb060 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -46,6 +46,8 @@ #include #include #include +#include +#include #include "pstream.h" @@ -108,12 +110,13 @@ struct item_info { }; struct pa_pstream { - int ref; + PA_REFCNT_DECLARE; pa_mainloop_api *mainloop; pa_defer_event *defer_event; pa_iochannel *io; pa_queue *send_queue; + pa_mutex *mutex; int dead; @@ -163,11 +166,14 @@ static int do_read(pa_pstream *p); static void do_something(pa_pstream *p) { assert(p); - - p->mainloop->defer_enable(p->defer_event, 0); + assert(PA_REFCNT_VALUE(p) > 0); pa_pstream_ref(p); + pa_mutex_lock(p->mutex); + + p->mainloop->defer_enable(p->defer_event, 0); + if (!p->dead && pa_iochannel_is_readable(p->io)) { if (do_read(p) < 0) goto fail; @@ -179,6 +185,8 @@ static void do_something(pa_pstream *p) { goto fail; } + pa_mutex_unlock(p->mutex); + pa_pstream_unref(p); return; @@ -189,6 +197,8 @@ fail: if (p->die_callback) p->die_callback(p, p->die_callback_userdata); + pa_mutex_unlock(p->mutex); + pa_pstream_unref(p); } @@ -221,11 +231,13 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *poo assert(pool); p = pa_xnew(pa_pstream, 1); - p->ref = 1; + PA_REFCNT_INIT(p); p->io = io; pa_iochannel_set_callback(io, io_callback, p); p->dead = 0; + p->mutex = pa_mutex_new(1); + p->mainloop = m; p->defer_event = m->defer_new(m, defer_callback, p); m->defer_enable(p->defer_event, 0); @@ -297,6 +309,9 @@ static void pstream_free(pa_pstream *p) { if (p->read.packet) pa_packet_unref(p->read.packet); + if (p->mutex) + pa_mutex_free(p->mutex); + pa_xfree(p); } @@ -304,11 +319,13 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *cre struct item_info *i; assert(p); - assert(p->ref >= 1); + assert(PA_REFCNT_VALUE(p) > 0); assert(packet); + pa_mutex_lock(p->mutex); + if (p->dead) - return; + goto finish; i = pa_xnew(struct item_info, 1); i->type = PA_PSTREAM_ITEM_PACKET; @@ -321,18 +338,24 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *cre pa_queue_push(p->send_queue, i); p->mainloop->defer_enable(p->defer_event, 1); + +finish: + + pa_mutex_unlock(p->mutex); } void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek_mode, const pa_memchunk *chunk) { size_t length, idx; assert(p); - assert(p->ref >= 1); + assert(PA_REFCNT_VALUE(p) > 0); assert(channel != (uint32_t) -1); assert(chunk); + pa_mutex_lock(p->mutex); + if (p->dead) - return; + goto finish; length = chunk->length; idx = 0; @@ -363,6 +386,10 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa } p->mainloop->defer_enable(p->defer_event, 1); + +finish: + + pa_mutex_unlock(p->mutex); } static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userdata) { @@ -370,10 +397,12 @@ static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userd pa_pstream *p = userdata; assert(p); - assert(p->ref >= 1); + assert(PA_REFCNT_VALUE(p) > 0); + + pa_mutex_lock(p->mutex); if (p->dead) - return; + goto finish; /* pa_log("Releasing block %u", block_id); */ @@ -386,6 +415,10 @@ static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userd pa_queue_push(p->send_queue, item); p->mainloop->defer_enable(p->defer_event, 1); + +finish: + + pa_mutex_unlock(p->mutex); } static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userdata) { @@ -393,10 +426,12 @@ static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userda pa_pstream *p = userdata; assert(p); - assert(p->ref >= 1); + assert(PA_REFCNT_VALUE(p) > 0); + + pa_mutex_lock(p->mutex); if (p->dead) - return; + goto finish; /* pa_log("Revoking block %u", block_id); */ @@ -409,10 +444,15 @@ static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userda pa_queue_push(p->send_queue, item); p->mainloop->defer_enable(p->defer_event, 1); + +finish: + + pa_mutex_unlock(p->mutex); } static void prepare_next_write_item(pa_pstream *p) { assert(p); + assert(PA_REFCNT_VALUE(p) > 0); if (!(p->write.current = pa_queue_pop(p->send_queue))) return; @@ -501,7 +541,9 @@ static int do_write(pa_pstream *p) { void *d; size_t l; ssize_t r; + assert(p); + assert(PA_REFCNT_VALUE(p) > 0); if (!p->write.current) prepare_next_write_item(p); @@ -552,8 +594,10 @@ static int do_read(pa_pstream *p) { void *d; size_t l; ssize_t r; + assert(p); - + assert(PA_REFCNT_VALUE(p) > 0); + if (p->read.index < PA_PSTREAM_DESCRIPTOR_SIZE) { d = (uint8_t*) p->read.descriptor + p->read.index; l = PA_PSTREAM_DESCRIPTOR_SIZE - p->read.index; @@ -782,65 +826,83 @@ frame_done: void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) { assert(p); - assert(p->ref >= 1); - + assert(PA_REFCNT_VALUE(p) > 0); + + pa_mutex_lock(p->mutex); p->die_callback = cb; p->die_callback_userdata = userdata; + pa_mutex_unlock(p->mutex); } - void pa_pstream_set_drain_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) { assert(p); - assert(p->ref >= 1); + assert(PA_REFCNT_VALUE(p) > 0); + pa_mutex_lock(p->mutex); p->drain_callback = cb; p->drain_callback_userdata = userdata; + pa_mutex_unlock(p->mutex); } void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata) { assert(p); - assert(p->ref >= 1); + assert(PA_REFCNT_VALUE(p) > 0); + pa_mutex_lock(p->mutex); p->recieve_packet_callback = cb; p->recieve_packet_callback_userdata = userdata; + pa_mutex_unlock(p->mutex); } void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, pa_pstream_memblock_cb_t cb, void *userdata) { assert(p); - assert(p->ref >= 1); + assert(PA_REFCNT_VALUE(p) > 0); + pa_mutex_lock(p->mutex); p->recieve_memblock_callback = cb; p->recieve_memblock_callback_userdata = userdata; + pa_mutex_unlock(p->mutex); } int pa_pstream_is_pending(pa_pstream *p) { + int b; + assert(p); + assert(PA_REFCNT_VALUE(p) > 0); + + pa_mutex_lock(p->mutex); if (p->dead) - return 0; + b = 0; + else + b = p->write.current || !pa_queue_is_empty(p->send_queue); + + pa_mutex_unlock(p->mutex); - return p->write.current || !pa_queue_is_empty(p->send_queue); + return b; } void pa_pstream_unref(pa_pstream*p) { assert(p); - assert(p->ref >= 1); + assert(PA_REFCNT_VALUE(p) > 0); - if (--p->ref == 0) + if (PA_REFCNT_DEC(p) <= 0) pstream_free(p); } pa_pstream* pa_pstream_ref(pa_pstream*p) { assert(p); - assert(p->ref >= 1); + assert(PA_REFCNT_VALUE(p) > 0); - p->ref++; + PA_REFCNT_INC(p); return p; } void pa_pstream_close(pa_pstream *p) { assert(p); + pa_mutex_lock(p->mutex); + p->dead = 1; if (p->import) { @@ -868,12 +930,14 @@ void pa_pstream_close(pa_pstream *p) { p->recieve_packet_callback = NULL; p->recieve_memblock_callback = NULL; - + pa_mutex_unlock(p->mutex); } void pa_pstream_use_shm(pa_pstream *p, int enable) { assert(p); - assert(p->ref >= 1); + assert(PA_REFCNT_VALUE(p) > 0); + + pa_mutex_lock(p->mutex); p->use_shm = enable; @@ -888,6 +952,7 @@ void pa_pstream_use_shm(pa_pstream *p, int enable) { pa_memexport_free(p->export); p->export = NULL; } - } + + pa_mutex_unlock(p->mutex); } -- cgit From 791bbd8e0e8b0a2350ee20321578f34ca026cd0e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 7 Sep 2006 20:17:25 +0000 Subject: don't maintain a list of allocated mempool slots, we don't use it anyway git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1380 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/memblock.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 70bcf677..9cfd79b5 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -101,7 +101,6 @@ struct pa_mempool { /* A list of free slots that may be reused */ PA_LLIST_HEAD(struct mempool_slot, free_slots); - PA_LLIST_HEAD(struct mempool_slot, used_slots); pa_mempool_stat stat; }; @@ -195,7 +194,6 @@ static struct mempool_slot* mempool_allocate_slot(pa_mempool *p) { return NULL; } - PA_LLIST_PREPEND(struct mempool_slot, p->used_slots, slot); return slot; } @@ -354,7 +352,6 @@ void pa_memblock_unref(pa_memblock*b) { slot = mempool_slot_by_ptr(b->pool, b->data); assert(slot); - PA_LLIST_REMOVE(struct mempool_slot, b->pool->used_slots, slot); PA_LLIST_PREPEND(struct mempool_slot, b->pool->free_slots, slot); if (b->type == PA_MEMBLOCK_POOL_EXTERNAL) @@ -471,7 +468,6 @@ pa_mempool* pa_mempool_new(int shared) { PA_LLIST_HEAD_INIT(pa_memimport, p->imports); PA_LLIST_HEAD_INIT(pa_memexport, p->exports); PA_LLIST_HEAD_INIT(struct mempool_slot, p->free_slots); - PA_LLIST_HEAD_INIT(struct mempool_slot, p->used_slots); memset(&p->stat, 0, sizeof(p->stat)); @@ -505,9 +501,8 @@ void pa_mempool_vacuum(pa_mempool *p) { assert(p); - for (slot = p->free_slots; slot; slot = slot->next) { + for (slot = p->free_slots; slot; slot = slot->next) pa_shm_punch(&p->memory, (uint8_t*) slot + sizeof(struct mempool_slot) - (uint8_t*) p->memory.ptr, p->block_size - sizeof(struct mempool_slot)); - } } int pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id) { -- cgit From bfaa3584581c0d9f3acc7208a0d7ab13845124ab Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 8 Sep 2006 15:43:44 +0000 Subject: add a tiny wrapper around libatomic_ops: pa_atomic_int_t and pa_atomit_ptr_t. Reasoning: This wrapper fixes a few API issues I found with atomic_ops: * AO_t is an int, which can be written to with "=". pa_tomic_int_t however is a struct which due to type-safety enforces proper access with pa_atomic_xx(). (Inspired by the way the Linux kernel handles this) * AO_load()'s parameter is lacking a "const" * Explicitly choosing the proper memory barrier for each call is very difficult and especially hard to debug because most CPUs support only two different barrier types which the eight types defined by atomic_ops are mapped to. Most other software (i.e. glib, Linux kernel) which provides atomic variable access usually do a full barrier in all cases and so should we. Eventually we might choose to add additional memory barrier calls, in which case we can add special versions of the current function with special suffixes. * The function names are unnecesarily long * Atomic pointer accesses are only supported with manual casts. The new pa_atomic_xxx interface borrows heavily from the GLib and Linux kernel atomicity API, though it is different from both of them. In addition this abstract API makes it easy to port PA to different atomicty APIs, if libatomic_ops should ever become out-of-fashion or if the system OS supports atomic primitives anyway. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1381 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/atomic.h | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/pulsecore/atomic.h diff --git a/src/pulsecore/atomic.h b/src/pulsecore/atomic.h new file mode 100644 index 00000000..f789142d --- /dev/null +++ b/src/pulsecore/atomic.h @@ -0,0 +1,80 @@ +#ifndef foopulseatomichfoo +#define foopulseatomichfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +/* atomic_ops guarantees us that sizeof(AO_t) == sizeof(void*). + * + * It is not guaranteed however, that sizeof(AO_t) == sizeof(size_t). + * however very likely. */ + +typedef struct pa_atomic_int { + volatile AO_t value; +} pa_atomic_int_t; + +/* For now we do only full memory barriers. Eventually we might want + * to support more elaborate memory barriers, in which case we will add + * suffixes to the function names */ + +static inline int pa_atomic_load(const pa_atomic_int_t *a) { + return (int) AO_load_full((AO_t*) &a->value); +} + +static inline void pa_atomic_store(pa_atomic_int_t *a, int i) { + AO_store_full(&a->value, (AO_t) i); +} + +static inline int pa_atomic_add(pa_atomic_int_t *a, int i) { + return AO_fetch_and_add_full(&a->value, (AO_t) i); +} + +static inline int pa_atomic_inc(pa_atomic_int_t *a) { + return AO_fetch_and_add1_full(&a->value); +} + +static inline int pa_atomic_dec(pa_atomic_int_t *a) { + return AO_fetch_and_sub1_full(&a->value); +} + +static inline int pa_atomic_cmpxchg(pa_atomic_int_t *a, int old_i, int new_i) { + return AO_compare_and_swap_full(&a->value, old_i, new_i); +} + +typedef struct pa_atomic_ptr { + volatile AO_t value; +} pa_atomic_ptr_t; + +static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) { + return (void*) AO_load_full((AO_t*) &a->value); +} + +static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) { + AO_store_full(&a->value, (AO_t) p); +} + +static inline int pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) { + return AO_compare_and_swap_full(&a->value, (AO_t) old_p, (AO_t) new_p); +} + +#endif -- cgit From ee40a3439f33186f2c14237cbd1dab4a88bd1b10 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 9 Sep 2006 21:05:31 +0000 Subject: implement a simple lock-free free list git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1382 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/flist.c | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/pulsecore/flist.h | 39 +++++++++ 2 files changed, 265 insertions(+) create mode 100644 src/pulsecore/flist.c create mode 100644 src/pulsecore/flist.h diff --git a/src/pulsecore/flist.c b/src/pulsecore/flist.c new file mode 100644 index 00000000..cfeeac22 --- /dev/null +++ b/src/pulsecore/flist.c @@ -0,0 +1,226 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include + +#include "flist.h" + +/* Algorithm is not perfect, in a few corner cases it will fail to pop + * from the flist although it isn't empty, and fail to push into the + * flist, although it isn't full. + * + * We keep a fixed size array of entries, each item is either marked + * UNUSED, USED or BUSY and contains a user data pointer. When pushing + * into the queue we look for an UNUSED cell and mark it BUSY with a + * CAS operation. If successful we use it and mark it USED, otherwise + * we go on and look for the next UNUSED cell. The algorithm for + * popping an item from the queue is practically inverse: look for a + * USED cell and and mark it BUSY with a CAS operation, after reading + * from it mark it UNUSED again. + * + * To accelerate finding of used/unused cells we maintain a read and a + * write index which is used like a ring buffer. After each push we + * increase the write index and after each pop we increase the read + * index. + * + * The indexes are incremented atomically and are never truncated to + * the buffer size. Instead we assume that the buffer size is a power + * of two and that the truncation can thus be done by applying a + * simple AND on read. + * + * To make sure that we do not look for empty cells indefinitely we + * maintain a length value which stores the number of used cells. From + * this value the number of unused cells is easily calculated. Please + * note that the length value is not updated atomically with the read + * and write index and might thus be a few cells off the real + * value. To deal with this we always look for N_EXTRA_SCAN extra + * cells when pushing/popping entries. + * + * It might make sense to replace this implementation with a link list + * stack or queue, which however requires DCAS to be simple. Patches + * welcome. + * + * Please note that this algorithm is home grown.*/ + +#define FLIST_SIZE 128 +#define N_EXTRA_SCAN 2 + +/* For debugging purposes we can define _Y to put and extra thread + * yield between each operation. */ + +#ifdef PROFILE +#define _Y pa_thread_yield() +#else +#define _Y do { } while(0) +#endif + +enum { + STATE_UNUSED, + STATE_USED, + STATE_BUSY +}; + +struct cell { + pa_atomic_int_t state; + void *data; +}; + +struct pa_flist { + struct cell *cells; + unsigned size; + pa_atomic_int_t length; + pa_atomic_int_t read_idx; + pa_atomic_int_t write_idx; +}; + +static int is_power_of_two(unsigned size) { + return !(size & (size - 1)); +} + +pa_flist *pa_flist_new(unsigned size) { + pa_flist *l; + + if (!size) + size = FLIST_SIZE; + + assert(is_power_of_two(size)); + + l = pa_xnew(pa_flist, 1); + + l->size = size; + l->cells = pa_xnew0(struct cell, size); + + pa_atomic_store(&l->read_idx, 0); + pa_atomic_store(&l->write_idx, 0); + pa_atomic_store(&l->length, 0); + + return l; +} + +static int reduce(pa_flist *l, int value) { + return value & (unsigned) (l->size - 1); +} + +void pa_flist_free(pa_flist *l, pa_free_cb_t free_cb) { + assert(l); + + if (free_cb) { + int len, idx; + + idx = reduce(l, pa_atomic_load(&l->read_idx)); + len = pa_atomic_load(&l->length); + + for (; len > 0; len--) { + + if (pa_atomic_load(&l->cells[idx].state) == STATE_USED) + free_cb(l->cells[idx].data); + + idx = reduce(l, idx + 1); + } + } + + pa_xfree(l->cells); + pa_xfree(l); +} + +int pa_flist_push(pa_flist*l, void *p) { + int idx, len, n; + + assert(l); + assert(p); + + n = len = (int) l->size - pa_atomic_load(&l->length) + N_EXTRA_SCAN; + _Y; + idx = reduce(l, pa_atomic_load(&l->write_idx)); + + for (; n > 0 ; n--) { + _Y; + + if (pa_atomic_cmpxchg(&l->cells[idx].state, STATE_UNUSED, STATE_BUSY)) { + _Y; + pa_atomic_inc(&l->write_idx); + _Y; + l->cells[idx].data = p; + _Y; + pa_atomic_store(&l->cells[idx].state, STATE_USED); + _Y; + pa_atomic_inc(&l->length); + return 0; + } + + _Y; + idx = reduce(l, idx + 1); + } + +#ifdef PROFILE + if (len > N_EXTRA_SCAN) + pa_log("WARNING: Didn't find free cell after %u iterations.", len); +#endif + + return -1; +} + +void* pa_flist_pop(pa_flist*l) { + int idx, len, n; + + assert(l); + + n = len = pa_atomic_load(&l->length) + N_EXTRA_SCAN; + _Y; + idx = reduce(l, pa_atomic_load(&l->read_idx)); + + for (; n > 0 ; n--) { + _Y; + + if (pa_atomic_cmpxchg(&l->cells[idx].state, STATE_USED, STATE_BUSY)) { + void *p; + _Y; + pa_atomic_inc(&l->read_idx); + _Y; + p = l->cells[idx].data; + _Y; + pa_atomic_store(&l->cells[idx].state, STATE_UNUSED); + _Y; + + pa_atomic_dec(&l->length); + return p; + } + + _Y; + idx = reduce(l, idx+1); + } + +#ifdef PROFILE + if (len > N_EXTRA_SCAN) + pa_log("WARNING: Didn't find used cell after %u iterations.", len); +#endif + + return NULL; +} diff --git a/src/pulsecore/flist.h b/src/pulsecore/flist.h new file mode 100644 index 00000000..57c9598b --- /dev/null +++ b/src/pulsecore/flist.h @@ -0,0 +1,39 @@ +#ifndef foopulseflisthfoo +#define foopulseflisthfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +/* A multiple-reader multipler-write lock-free free list implementation */ + +typedef struct pa_flist pa_flist; + +/* Size is required to be a power of two, or 0 for the default size */ +pa_flist * pa_flist_new(unsigned size); +void pa_flist_free(pa_flist *l, pa_free_cb_t free_cb); + +/* Please note that this routine might fail! */ +int pa_flist_push(pa_flist*l, void *p); +void* pa_flist_pop(pa_flist*l); + +#endif -- cgit From b93fedd49c95675ed8ce089b94b2b3bcfd903565 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 9 Sep 2006 21:09:55 +0000 Subject: add a test program for the free list git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1383 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/tests/flist-test.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 src/tests/flist-test.c diff --git a/src/tests/flist-test.c b/src/tests/flist-test.c new file mode 100644 index 00000000..b0404449 --- /dev/null +++ b/src/tests/flist-test.c @@ -0,0 +1,104 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include + +#define THREADS_MAX 20 + +static pa_flist *flist; +static int quit = 0; + +static void spin(void) { + int k; + + /* Spin a little */ + k = rand() % 10000; + for (; k > 0; k--) + pa_thread_yield(); +} + +static void thread_func(void *data) { + char *s = data; + int n = 0; + int b = 1; + + while (!quit) { + char *text, *t; + + /* Allocate some memory, if possible take it from the flist */ + if (b && (text = pa_flist_pop(flist))) + pa_log("%s: popped '%s'", s, text); + else { + text = pa_sprintf_malloc("Block %i, allocated by %s", n++, s); + pa_log("%s: allocated '%s'", s, text); + } + + b = !b; + + spin(); + + /* Give it back to the flist if possible */ + if (pa_flist_push(flist, text) < 0) { + pa_log("%s: failed to push back '%s'", s, text); + pa_xfree(text); + } else + pa_log("%s: pushed", s); + + spin(); + } + + if (pa_flist_push(flist, s) < 0) + pa_xfree(s); +} + +int main(int argc, char* argv[]) { + pa_thread *threads[THREADS_MAX]; + int i; + + flist = pa_flist_new(0); + + for (i = 0; i < THREADS_MAX; i++) { + threads[i] = pa_thread_new(thread_func, pa_sprintf_malloc("Thread #%i", i+1)); + assert(threads[i]); + } + + sleep(60); + quit = 1; + + for (i = 0; i < THREADS_MAX; i++) + pa_thread_free(threads[i]); + + pa_flist_free(flist, pa_xfree); + + return 0; +} -- cgit From c89cb6a00f6ab862a047db1124486492e5e59f83 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 9 Sep 2006 22:54:11 +0000 Subject: add static initializer PA_ATOMIC_INIT() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1384 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/atomic.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pulsecore/atomic.h b/src/pulsecore/atomic.h index f789142d..8d608b5b 100644 --- a/src/pulsecore/atomic.h +++ b/src/pulsecore/atomic.h @@ -33,6 +33,8 @@ typedef struct pa_atomic_int { volatile AO_t value; } pa_atomic_int_t; +#define PA_ATOMIC_INIT(v) { .value = (v) } + /* For now we do only full memory barriers. Eventually we might want * to support more elaborate memory barriers, in which case we will add * suffixes to the function names */ -- cgit From 3426a399ccbaa60c03bf38f9fb788a6f12b888b0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 9 Sep 2006 22:55:51 +0000 Subject: implement trival pa_once API based on atomic operations git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1385 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/once.h | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/pulsecore/once.h diff --git a/src/pulsecore/once.h b/src/pulsecore/once.h new file mode 100644 index 00000000..a82a3c86 --- /dev/null +++ b/src/pulsecore/once.h @@ -0,0 +1,42 @@ +#ifndef foopulseoncehfoo +#define foopulseoncehfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef struct pa_once { + pa_atomic_int_t atomic; +} pa_once_t; + +#define PA_ONCE_INIT { PA_ATOMIC_INIT(0) } + +#define pa_once_test(o) (pa_atomic_cmpxchg(&(o)->atomic, 0, 1)) + +typedef void (*pa_once_func_t) (void); + +static inline void pa_once(pa_once_t *o, pa_once_func_t f) { + if (pa_once_test(o)) + f(); +} + +#endif -- cgit From 6d532029eaac08a3b60a28752f23f0586f895168 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 9 Sep 2006 22:59:17 +0000 Subject: update for newer APIs: replace direct usage of libatomic_ops by usage of our own atomic.h; remove pa_once implementation; always use our pa_once implementation instead of the POSIX version git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1386 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/thread-posix.c | 51 +++++++++++--------------------------------- src/pulsecore/thread.h | 5 ----- 2 files changed, 13 insertions(+), 43 deletions(-) diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c index a2cb9b56..d69790a5 100644 --- a/src/pulsecore/thread-posix.c +++ b/src/pulsecore/thread-posix.c @@ -28,10 +28,10 @@ #include #include -#include - #include #include +#include +#include #include "thread.h" @@ -44,7 +44,7 @@ struct pa_thread { pthread_t id; pa_thread_func_t thread_func; void *userdata; - AO_t running; + pa_atomic_int_t running; }; struct pa_tls { @@ -52,10 +52,7 @@ struct pa_tls { }; static pa_tls *thread_tls; -static pthread_once_t thread_tls_once = PTHREAD_ONCE_INIT; - -static pa_mutex *once_mutex; -static pthread_once_t thread_once_once = PTHREAD_ONCE_INIT; +static pa_once_t thread_tls_once = PA_ONCE_INIT; static void tls_free_cb(void *p) { pa_thread *t = p; @@ -78,12 +75,13 @@ static void* internal_thread_func(void *userdata) { t->id = pthread_self(); - ASSERT_SUCCESS(pthread_once(&thread_tls_once, thread_tls_once_func)); + pa_once(&thread_tls_once, thread_tls_once_func); + pa_tls_set(thread_tls, t); - AO_fetch_and_add1_full(&t->running); + pa_atomic_inc(&t->running); t->thread_func(t->userdata); - AO_fetch_and_add_full(&t->running, (AO_t) -2); + pa_atomic_add(&t->running, -2); return NULL; } @@ -96,20 +94,19 @@ pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) { t = pa_xnew(pa_thread, 1); t->thread_func = thread_func; t->userdata = userdata; - AO_store_full(&t->running, 0); + pa_atomic_store(&t->running, 0); if (pthread_create(&t->id, NULL, internal_thread_func, t) < 0) { pa_xfree(t); return NULL; } - AO_fetch_and_add1_full(&t->running); + pa_atomic_inc(&t->running); return t; } int pa_thread_is_running(pa_thread *t) { - AO_t r; assert(t); if (!t->thread_func) { @@ -123,8 +120,7 @@ int pa_thread_is_running(pa_thread *t) { return pthread_getschedparam(t->id, &policy, ¶m) >= 0 || errno != ESRCH; } - r = AO_load_full(&t->running); - return r == 1 || r == 2; + return pa_atomic_load(&t->running) > 0; } void pa_thread_free(pa_thread *t) { @@ -143,7 +139,7 @@ int pa_thread_join(pa_thread *t) { pa_thread* pa_thread_self(void) { pa_thread *t; - ASSERT_SUCCESS(pthread_once(&thread_tls_once, thread_tls_once_func)); + pa_once(&thread_tls_once, thread_tls_once_func); if ((t = pa_tls_get(thread_tls))) return t; @@ -155,7 +151,7 @@ pa_thread* pa_thread_self(void) { t->id = pthread_self(); t->thread_func = NULL; t->userdata = NULL; - AO_store_full(&t->running, 1); + pa_atomic_store(&t->running, 2); pa_tls_set(thread_tls, t); @@ -182,27 +178,6 @@ void pa_thread_yield(void) { #endif } -static void thread_once_once_func(void) { - once_mutex = pa_mutex_new(0); - assert(once_mutex); -} - -void pa_thread_once(pa_thread_once_t *control, pa_thread_once_func_t once_func) { - assert(control); - assert(once_func); - - ASSERT_SUCCESS(pthread_once(&thread_once_once, thread_once_once_func)); - - pa_mutex_lock(once_mutex); - - if (*control == PA_THREAD_ONCE_INIT) { - *control = ~PA_THREAD_ONCE_INIT; - pa_mutex_unlock(once_mutex); - once_func(); - } else - pa_mutex_unlock(once_mutex); -} - pa_tls* pa_tls_new(pa_free_cb_t free_cb) { pa_tls *t; diff --git a/src/pulsecore/thread.h b/src/pulsecore/thread.h index e50a707f..d08990a2 100644 --- a/src/pulsecore/thread.h +++ b/src/pulsecore/thread.h @@ -24,13 +24,9 @@ #include -#define PA_THREAD_ONCE_INIT 0 - typedef struct pa_thread pa_thread; typedef void (*pa_thread_func_t) (void *userdata); -typedef void (*pa_thread_once_func_t) (void); -typedef unsigned int pa_thread_once_t; pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata); void pa_thread_free(pa_thread *t); @@ -38,7 +34,6 @@ int pa_thread_join(pa_thread *t); int pa_thread_is_running(pa_thread *t); pa_thread *pa_thread_self(void); void pa_thread_yield(void); -void pa_thread_once(pa_thread_once_t *control, pa_thread_once_func_t once_func); void* pa_thread_get_data(pa_thread *t); void pa_thread_set_data(pa_thread *t, void *userdata); -- cgit From d0dcde060bb3e5fd04512d16afdd1ed71e780e08 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 9 Sep 2006 23:54:19 +0000 Subject: rework pa_once once again, because the once function needs to have terminated before pa_once returns, regardless whether the local call executes it or another thread does. With the previous code it might happen that an long-running initializing in a once function is not terminated yet when another thread thinks it already is. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1387 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/once-posix.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++ src/pulsecore/once.h | 14 ++++------ 2 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 src/pulsecore/once-posix.c diff --git a/src/pulsecore/once-posix.c b/src/pulsecore/once-posix.c new file mode 100644 index 00000000..865997df --- /dev/null +++ b/src/pulsecore/once-posix.c @@ -0,0 +1,69 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include "once.h" + +#define ASSERT_SUCCESS(x) do { \ + int _r = (x); \ + assert(_r == 0); \ +} while(0) + +static pa_mutex *global_mutex; +static pthread_once_t global_mutex_once = PTHREAD_ONCE_INIT; + +static void global_mutex_once_func(void) { + global_mutex = pa_mutex_new(0); +} + +void pa_once(pa_once_t *control, pa_once_func_t func) { + assert(control); + assert(func); + + /* Create the global mutex */ + ASSERT_SUCCESS(pthread_once(&global_mutex_once, global_mutex_once_func)); + + /* Create the local mutex */ + pa_mutex_lock(global_mutex); + if (!control->mutex) + control->mutex = pa_mutex_new(1); + pa_mutex_unlock(global_mutex); + + /* Execute function */ + pa_mutex_lock(control->mutex); + if (!control->once_value) { + control->once_value = 1; + func(); + } + pa_mutex_unlock(control->mutex); + + /* Caveat: We have to make sure that the once func has completed + * before returning, even if the once func is not actually + * executed by us. Hence the awkward locking. */ +} diff --git a/src/pulsecore/once.h b/src/pulsecore/once.h index a82a3c86..0aabb3f2 100644 --- a/src/pulsecore/once.h +++ b/src/pulsecore/once.h @@ -22,21 +22,17 @@ USA. ***/ -#include +#include typedef struct pa_once { - pa_atomic_int_t atomic; + unsigned int once_value; + pa_mutex *mutex; } pa_once_t; -#define PA_ONCE_INIT { PA_ATOMIC_INIT(0) } - -#define pa_once_test(o) (pa_atomic_cmpxchg(&(o)->atomic, 0, 1)) +#define PA_ONCE_INIT { .once_value = 0, .mutex = NULL } typedef void (*pa_once_func_t) (void); -static inline void pa_once(pa_once_t *o, pa_once_func_t f) { - if (pa_once_test(o)) - f(); -} +void pa_once(pa_once_t *o, pa_once_func_t f); #endif -- cgit From 3ae98db1aa01cfe68ed55f303fecf9c9bbcb4438 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 9 Sep 2006 23:54:56 +0000 Subject: add pa_once testing code git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1388 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/tests/thread-test.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/tests/thread-test.c b/src/tests/thread-test.c index 9e8afd9b..9559cdbb 100644 --- a/src/tests/thread-test.c +++ b/src/tests/thread-test.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -37,6 +38,12 @@ static int magic_number = 0; #define THREADS_MAX 20 +static void once_func(void) { + pa_log("once!"); +} + +static pa_once_t once = PA_ONCE_INIT; + static void thread_func(void *data) { pa_tls_set(tls, data); @@ -65,6 +72,8 @@ static void thread_func(void *data) { pa_mutex_unlock(mutex); + pa_once(&once, once_func); + pa_cond_signal(cond2, 0); pa_log("%s got number %i", (char*) pa_tls_get(tls), k); -- cgit From 0e96d8b7bc8be2621867fbd38a455ca1a3724abc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 9 Sep 2006 23:55:58 +0000 Subject: make pa_mutex_new() and pa_cond_new() succeed in all cases. Similar behaviour to pa_xmalloc(). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1389 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/mutex-posix.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/pulsecore/mutex-posix.c b/src/pulsecore/mutex-posix.c index 6f0e7336..094d637d 100644 --- a/src/pulsecore/mutex-posix.c +++ b/src/pulsecore/mutex-posix.c @@ -52,16 +52,11 @@ pa_mutex* pa_mutex_new(int recursive) { pthread_mutexattr_init(&attr); if (recursive) - if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) < 0) - return NULL; + ASSERT_SUCCESS(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)); m = pa_xnew(pa_mutex, 1); - if (pthread_mutex_init(&m->mutex, &attr) < 0) { - pa_xfree(m); - return NULL; - } - + ASSERT_SUCCESS(pthread_mutex_init(&m->mutex, &attr)); return m; } @@ -84,17 +79,12 @@ void pa_mutex_unlock(pa_mutex *m) { ASSERT_SUCCESS(pthread_mutex_unlock(&m->mutex)); } - pa_cond *pa_cond_new(void) { pa_cond *c; c = pa_xnew(pa_cond, 1); - if (pthread_cond_init(&c->cond, NULL) < 0) { - pa_xfree(c); - return NULL; - } - + ASSERT_SUCCESS(pthread_cond_init(&c->cond, NULL)); return c; } -- cgit From 9358d28c21c5ea9bf8c288bd10d61eae4e3cc278 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 9 Sep 2006 23:56:58 +0000 Subject: update Makefile git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1390 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 69c6ac34..aad6e26d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -200,7 +200,8 @@ noinst_PROGRAMS = \ ipacl-test \ hook-list-test \ memblock-test \ - thread-test + thread-test \ + flist-test if HAVE_SIGXCPU noinst_PROGRAMS += \ @@ -250,11 +251,16 @@ memblock_test_CFLAGS = $(AM_CFLAGS) memblock_test_LDADD = $(AM_LDADD) libpulsecore.la memblock_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -thread_test_SOURCES = tests/thread-test.c +thread_test_SOURCES = tests/thread-test.c pulse/xmalloc.c pulsecore/flist.c pulsecore/thread-posix.c pulsecore/mutex-posix.c pulsecore/log.c pulsecore/core-util.c pulse/util.c pulse/utf8.c pulsecore/core-error.c pulsecore/once-posix.c thread_test_CFLAGS = $(AM_CFLAGS) -thread_test_LDADD = $(AM_LDADD) libpulsecore.la +thread_test_LDADD = $(AM_LDADD) thread_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +flist_test_SOURCES = tests/flist-test.c pulse/xmalloc.c pulsecore/flist.c pulsecore/thread-posix.c pulsecore/mutex-posix.c pulsecore/log.c pulsecore/core-util.c pulse/util.c pulse/utf8.c pulsecore/core-error.c pulsecore/once-posix.c +flist_test_CFLAGS = $(AM_CFLAGS) +flist_test_LDADD = $(AM_LDADD) +flist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + mcalign_test_SOURCES = tests/mcalign-test.c mcalign_test_CFLAGS = $(AM_CFLAGS) mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpulsecore.la @@ -625,10 +631,12 @@ libpulse_la_SOURCES += \ else libpulsecore_la_SOURCES += \ pulsecore/mutex-posix.c \ - pulsecore/thread-posix.c + pulsecore/thread-posix.c \ + pulsecore/once-posix.c libpulse_la_SOURCES += \ pulsecore/mutex-posix.c \ - pulsecore/thread-posix.c + pulsecore/thread-posix.c \ + pulecore/once-posix.c endif libpulsecore_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBOIL_CFLAGS) -- cgit -- cgit -- cgit From 7c6088d98a6399171c9abf108084c46de133f132 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 11 Sep 2006 07:14:39 +0000 Subject: Fix typo. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1393 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index aad6e26d..7db0f8c7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -636,7 +636,7 @@ libpulsecore_la_SOURCES += \ libpulse_la_SOURCES += \ pulsecore/mutex-posix.c \ pulsecore/thread-posix.c \ - pulecore/once-posix.c + pulsecore/once-posix.c endif libpulsecore_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBOIL_CFLAGS) -- cgit From a85b3e2dd49adc5addab25e5ceeb8eb56e283e48 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 11 Sep 2006 07:54:41 +0000 Subject: Use platform independent sleep. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1394 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/tests/flist-test.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tests/flist-test.c b/src/tests/flist-test.c index b0404449..abc0659d 100644 --- a/src/tests/flist-test.c +++ b/src/tests/flist-test.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -92,7 +93,7 @@ int main(int argc, char* argv[]) { assert(threads[i]); } - sleep(60); + pa_msleep(60000); quit = 1; for (i = 0; i < THREADS_MAX; i++) -- cgit From 772645922a450f5d366bd6e077a44582e7a7b79f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 11 Sep 2006 07:56:03 +0000 Subject: Fix up build structure for platform dependent modules. Also add implementation on Win32 for pa_once(). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1395 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 50 +++++++++++++++------------------ src/pulsecore/once-win32.c | 67 ++++++++++++++++++++++++++++++++++++++++++++ src/pulsecore/thread-win32.c | 35 ++++------------------- 3 files changed, 96 insertions(+), 56 deletions(-) create mode 100644 src/pulsecore/once-win32.c diff --git a/src/Makefile.am b/src/Makefile.am index 7db0f8c7..c04507dc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -70,6 +70,18 @@ AM_LDFLAGS+=-Wl,--export-all-symbols WINSOCK_LIBS=-lwsock32 -lws2_32 -lwininet endif +if OS_IS_WIN32 +PA_THREAD_OBJS = \ + pulsecore/once-win32.c pulsecore/once.h \ + pulsecore/mutex-win32.c pulsecore/mutex.h \ + pulsecore/thread-win32.c pulsecore/thread.h +else +PA_THREAD_OBJS = \ + pulsecore/once-posix.c pulsecore/once.h \ + pulsecore/mutex-posix.c pulsecore/mutex.h \ + pulsecore/thread-posix.c pulsecore/thread.h +endif + ################################### # Extra files # ################################### @@ -251,14 +263,15 @@ memblock_test_CFLAGS = $(AM_CFLAGS) memblock_test_LDADD = $(AM_LDADD) libpulsecore.la memblock_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -thread_test_SOURCES = tests/thread-test.c pulse/xmalloc.c pulsecore/flist.c pulsecore/thread-posix.c pulsecore/mutex-posix.c pulsecore/log.c pulsecore/core-util.c pulse/util.c pulse/utf8.c pulsecore/core-error.c pulsecore/once-posix.c +thread_test_SOURCES = tests/thread-test.c thread_test_CFLAGS = $(AM_CFLAGS) -thread_test_LDADD = $(AM_LDADD) +thread_test_LDADD = $(AM_LDADD) libpulsecore.la thread_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -flist_test_SOURCES = tests/flist-test.c pulse/xmalloc.c pulsecore/flist.c pulsecore/thread-posix.c pulsecore/mutex-posix.c pulsecore/log.c pulsecore/core-util.c pulse/util.c pulse/utf8.c pulsecore/core-error.c pulsecore/once-posix.c +flist_test_SOURCES = tests/flist-test.c \ + pulsecore/flist.c pulsecore/flist.h flist_test_CFLAGS = $(AM_CFLAGS) -flist_test_LDADD = $(AM_LDADD) +flist_test_LDADD = $(AM_LDADD) libpulsecore.la flist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) mcalign_test_SOURCES = tests/mcalign-test.c @@ -434,7 +447,8 @@ libpulse_la_SOURCES += \ pulsecore/tagstruct.c pulsecore/tagstruct.h \ pulsecore/core-error.c pulsecore/core-error.h \ pulsecore/winsock.h pulsecore/creds.h \ - pulsecore/shm.c pulsecore/shm.h + pulsecore/shm.c pulsecore/shm.h \ + $(PA_THREAD_OBJS) if OS_IS_WIN32 libpulse_la_SOURCES += \ @@ -544,7 +558,8 @@ pulsecoreinclude_HEADERS = \ pulsecore/llist.h \ pulsecore/refcnt.h \ pulsecore/mutex.h \ - pulsecore/thread.h + pulsecore/thread.h \ + pulsecore/once.h lib_LTLIBRARIES += libpulsecore.la @@ -586,7 +601,6 @@ libpulsecore_la_SOURCES += \ pulsecore/modargs.c pulsecore/modargs.h \ pulsecore/modinfo.c pulsecore/modinfo.h \ pulsecore/module.c pulsecore/module.h \ - pulsecore/mutex.h \ pulsecore/namereg.c pulsecore/namereg.h \ pulsecore/pid.c pulsecore/pid.h \ pulsecore/pipe.c pulsecore/pipe.h \ @@ -609,36 +623,18 @@ libpulsecore_la_SOURCES += \ pulsecore/source.c pulsecore/source.h \ pulsecore/source-output.c pulsecore/source-output.h \ pulsecore/strbuf.c pulsecore/strbuf.h \ - pulsecore/thread.h \ pulsecore/tokenizer.c pulsecore/tokenizer.h \ pulsecore/winsock.h \ pulsecore/core-error.c pulsecore/core-error.h \ pulsecore/hook-list.c pulsecore/hook-list.h \ - pulsecore/shm.c pulsecore/shm.h + pulsecore/shm.c pulsecore/shm.h \ + $(PA_THREAD_OBJS) if OS_IS_WIN32 libpulsecore_la_SOURCES += \ pulsecore/dllmain.c endif -if OS_IS_WIN32 -libpulsecore_la_SOURCES += \ - pulsecore/mutex-win32.c \ - pulsecore/thread-win32.c -libpulse_la_SOURCES += \ - pulsecore/mutex-win32.c \ - pulsecore/thread-win32.c -else -libpulsecore_la_SOURCES += \ - pulsecore/mutex-posix.c \ - pulsecore/thread-posix.c \ - pulsecore/once-posix.c -libpulse_la_SOURCES += \ - pulsecore/mutex-posix.c \ - pulsecore/thread-posix.c \ - pulsecore/once-posix.c -endif - libpulsecore_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBOIL_CFLAGS) libpulsecore_la_LDFLAGS = -version-info $(LIBPULSECORE_VERSION_INFO) libpulsecore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) $(LIBOIL_LIBS) $(LIBICONV) diff --git a/src/pulsecore/once-win32.c b/src/pulsecore/once-win32.c new file mode 100644 index 00000000..8b9282f4 --- /dev/null +++ b/src/pulsecore/once-win32.c @@ -0,0 +1,67 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include + +#include "once.h" + +void pa_once(pa_once_t *control, pa_once_func_t func) { + HANDLE mutex; + char name[64]; + + assert(control); + assert(func); + + /* Create the global mutex */ + sprintf(name, "pulse%d", (int)GetCurrentProcessId()); + + mutex = CreateMutex(NULL, FALSE, name); + assert(mutex); + + /* Create the local mutex */ + WaitForSingleObject(mutex, INFINITE); + if (!control->mutex) + control->mutex = pa_mutex_new(1); + ReleaseMutex(mutex); + + CloseHandle(mutex); + + /* Execute function */ + pa_mutex_lock(control->mutex); + if (!control->once_value) { + control->once_value = 1; + func(); + } + pa_mutex_unlock(control->mutex); + + /* Caveat: We have to make sure that the once func has completed + * before returning, even if the once func is not actually + * executed by us. Hence the awkward locking. */ +} diff --git a/src/pulsecore/thread-win32.c b/src/pulsecore/thread-win32.c index ee61d85a..98ea0691 100644 --- a/src/pulsecore/thread-win32.c +++ b/src/pulsecore/thread-win32.c @@ -29,6 +29,7 @@ #include #include +#include #include "thread.h" @@ -50,9 +51,9 @@ struct pa_tls_monitor { }; static pa_tls *thread_tls; -static pa_thread_once_t thread_tls_once = PA_THREAD_ONCE_INIT; +static pa_once_t thread_tls_once = PA_ONCE_INIT; static pa_tls *monitor_tls; -static pa_thread_once_t monitor_tls_once = PA_THREAD_ONCE_INIT; +static pa_once_t monitor_tls_once = PA_ONCE_INIT; static void thread_tls_once_func(void) { thread_tls = pa_tls_new(NULL); @@ -63,7 +64,7 @@ static DWORD WINAPI internal_thread_func(LPVOID param) { pa_thread *t = param; assert(t); - pa_thread_once(&thread_tls_once, thread_tls_once_func); + pa_once(&thread_tls_once, thread_tls_once_func); pa_tls_set(thread_tls, t); t->thread_func(t->userdata); @@ -119,7 +120,7 @@ int pa_thread_join(pa_thread *t) { } pa_thread* pa_thread_self(void) { - pa_thread_once(&thread_tls_once, thread_tls_once_func); + pa_once(&thread_tls_once, thread_tls_once_func); return pa_tls_get(thread_tls); } @@ -127,30 +128,6 @@ void pa_thread_yield(void) { Sleep(0); } -void pa_thread_once(pa_thread_once_t *control, pa_thread_once_func_t once_func) { - HANDLE mutex; - char name[64]; - - assert(control); - assert(once_func); - - sprintf(name, "pulse%d", (int)GetCurrentProcessId()); - - mutex = CreateMutex(NULL, FALSE, name); - assert(mutex); - - WaitForSingleObject(mutex, INFINITE); - - if (*control == PA_THREAD_ONCE_INIT) { - *control = ~PA_THREAD_ONCE_INIT; - ReleaseMutex(mutex); - once_func(); - } else - ReleaseMutex(mutex); - - CloseHandle(mutex); -} - static void monitor_tls_once_func(void) { monitor_tls = pa_tls_new(NULL); assert(monitor_tls); @@ -212,7 +189,7 @@ void *pa_tls_set(pa_tls *t, void *userdata) { if (t->free_func) { struct pa_tls_monitor *m; - pa_thread_once(&monitor_tls_once, monitor_tls_once_func); + pa_once(&monitor_tls_once, monitor_tls_once_func); m = pa_tls_get(monitor_tls); if (!m) { -- cgit From 5f828c2c3df6a788b5f8be3422bd355b91104791 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 14 Sep 2006 14:56:31 +0000 Subject: Fix debug output for SNDCTL_DSP_SETFRAGMENT. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1396 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 883ffbd9..d947f697 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1875,7 +1875,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) break; case SNDCTL_DSP_SETFRAGMENT: - debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFRAGMENT: 0x%8x\n", *(int*) argp); + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFRAGMENT: 0x%08x\n", *(int*) argp); pa_threaded_mainloop_lock(i->mainloop); -- cgit From 29ab939570ee739570a6bfaa6569bd6f6135df56 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 14 Sep 2006 16:00:57 +0000 Subject: Stop using x86-isms and use ISO C (oversized shifts are undefined). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1397 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index d947f697..c7bfe5ab 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1879,7 +1879,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_threaded_mainloop_lock(i->mainloop); - i->fragment_size = 1 << (*(int*) argp); + i->fragment_size = 1 << ((*(int*) argp) & 31); i->n_fragments = (*(int*) argp) >> 16; /* 0x7FFF means that we can set whatever we like */ -- cgit From 534eeb181e264945968c841ba08f918efb473930 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 19 Sep 2006 07:49:39 +0000 Subject: No need to create these dirs as they're part of the source tree. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1398 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index c04507dc..f7026c5f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1006,7 +1006,6 @@ EXTRA_DIST += $(SYMDEF_FILES) BUILT_SOURCES += $(SYMDEF_FILES) $(SYMDEF_FILES): modules/module-defs.h.m4 - $(mkdir_p) modules/gconf modules/rtp $(M4) -Dfname="$@" $< > $@ # Simple protocol -- cgit From 71a6ceb29bb7714389576d274216e1a275fa08aa Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 19 Sep 2006 07:54:53 +0000 Subject: Revert r1398 as it broke the srcdir != builddir patch. New fix that doesn't use the $(mkdir_p) define as it isn't present on many systems. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1399 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Makefile.am b/src/Makefile.am index f7026c5f..dfe35851 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1006,6 +1006,9 @@ EXTRA_DIST += $(SYMDEF_FILES) BUILT_SOURCES += $(SYMDEF_FILES) $(SYMDEF_FILES): modules/module-defs.h.m4 + mkdir modules + mkdir modules/gconf + mkdir modules/rtp $(M4) -Dfname="$@" $< > $@ # Simple protocol -- cgit From bf83a961d5b246b6aed1d52d27f37e4b745bf264 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Sep 2006 19:01:59 +0000 Subject: rename default realtime group from "realtime" to "pulse-rt", since it is pulseaudio specific. you may still pass --with-realtime-group=realtime to configure to get the old behaviour git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1400 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 48b86cd3..2f09279c 100644 --- a/configure.ac +++ b/configure.ac @@ -707,7 +707,7 @@ AC_DEFINE_UNQUOTED(PA_SYSTEM_GROUP,"$PA_SYSTEM_GROUP", [Group for the PulseAudio AC_ARG_WITH(realtime_group,AS_HELP_STRING([--with-realtime-group=],[Group for users that are allowed to start the PulseAudio daemon with realtime scheduling (realtime)])) if test -z "$with_realtime_group" ; then - PA_REALTIME_GROUP=realtime + PA_REALTIME_GROUP=pulse-rt else PA_REALTIME_GROUP=$with_realtime_group fi -- cgit From f1021b9e0ba9727ff08009295dea28cc247b9d4f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Sep 2006 19:02:45 +0000 Subject: enable module-hal-detect in the default configuration file only if HAL support is enabled (closes #30) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1401 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 4 +++- src/daemon/default.pa.in | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index dfe35851..64df8614 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1295,7 +1295,9 @@ default.pa: daemon/default.pa.win32 cp $< $@ else default.pa: daemon/default.pa.in Makefile - sed -e 's,@PA_BINARY\@,$(PA_BINARY),g' < $< > $@ + sed -e 's,@PA_BINARY\@,$(PA_BINARY),g' \ + -e 's,@HAVE_HAL_TRUE\@,@HAVE_HAL_TRUE@,g' \ + -e 's,@HAVE_HAL_FALSE\@,@HAVE_HAL_FALSE@,g' < $< > $@ endif daemon.conf: daemon/daemon.conf.in Makefile diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in index a495f890..af2a6789 100755 --- a/src/daemon/default.pa.in +++ b/src/daemon/default.pa.in @@ -27,11 +27,11 @@ #load-module module-pipe-sink ### Automatically load driver modules depending on the hardware available -load-module module-hal-detect +@HAVE_HAL_TRUE@load-module module-hal-detect ### Alternatively use the static hardware detection module (for systems that ### lack HAL support -#load-module module-detect +@HAVE_HAL_FALSE@load-module module-detect ### Load audio drivers automatically on access #add-autoload-sink output module-oss device="/dev/dsp" sink_name=output source_name=input -- cgit From 736de36f6822d7ff85bb604ab749af88f8e19e12 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Sep 2006 23:41:20 +0000 Subject: add asynchronous inter-thread notification API git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1402 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/anotify.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++ src/pulsecore/anotify.h | 38 +++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 src/pulsecore/anotify.c create mode 100644 src/pulsecore/anotify.h diff --git a/src/pulsecore/anotify.c b/src/pulsecore/anotify.c new file mode 100644 index 00000000..a61f8442 --- /dev/null +++ b/src/pulsecore/anotify.c @@ -0,0 +1,143 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include "anotify.h" + +#define EVENTS_MAX 16 + +struct pa_anotify { + pa_mainloop_api *api; + pa_anotify_cb_t callback; + void *userdata; + int fds[2]; + pa_io_event *io_event; + pa_defer_event *defer_event; + + uint8_t queued_events[EVENTS_MAX]; + unsigned n_queued_events, queue_index; +}; + +static void dispatch_event(pa_anotify *a) { + assert(a); + assert(a->queue_index < a->n_queued_events); + + a->callback(a->queued_events[a->queue_index++], a->userdata); + + if (a->queue_index >= a->n_queued_events) { + a->n_queued_events = 0; + a->queue_index = 0; + + a->api->io_enable(a->io_event, PA_IO_EVENT_INPUT); + a->api->defer_enable(a->defer_event, 0); + } else { + a->api->io_enable(a->io_event, 0); + a->api->defer_enable(a->defer_event, 1); + } +} + +static void io_callback( + pa_mainloop_api *api, + pa_io_event *e, + int fd, + pa_io_event_flags_t events, + void *userdata) { + + pa_anotify *a = userdata; + ssize_t r; + + assert(a); + assert(events == PA_IO_EVENT_INPUT); + assert(a->n_queued_events == 0); + + r = read(fd, a->queued_events, sizeof(a->queued_events)); + assert(r > 0); + + a->n_queued_events = (unsigned) r; + a->queue_index = 0; + + /* Only dispatch a single event */ + dispatch_event(a); +} + +static void defer_callback(pa_mainloop_api *api, pa_defer_event *e, void *userdata) { + pa_anotify *a = userdata; + assert(a); + + dispatch_event(a); +} + +pa_anotify *pa_anotify_new(pa_mainloop_api*api, pa_anotify_cb_t cb, void *userdata) { + pa_anotify *a; + + assert(api); + assert(cb); + + a = pa_xnew(pa_anotify, 1); + + if (pipe(a->fds) < 0) { + pa_xfree(a); + return NULL; + } + + a->api = api; + a->callback = cb; + a->userdata = userdata; + + a->io_event = api->io_new(api, a->fds[0], PA_IO_EVENT_INPUT, io_callback, a); + a->defer_event = api->defer_new(api, defer_callback, a); + a->api->defer_enable(a->defer_event, 0); + + a->n_queued_events = 0; + + return a; +} + +void pa_anotify_free(pa_anotify *a) { + assert(a); + + a->api->io_free(a->io_event); + a->api->defer_free(a->defer_event); + + if (a->fds[0] >= 0) + close(a->fds[0]); + if (a->fds[1] >= 0) + close(a->fds[1]); + + pa_xfree(a); +} + +int pa_anotify_signal(pa_anotify *a, uint8_t event) { + ssize_t r; + assert(a); + + r = write(a->fds[1], &event, 1); + return r != 1 ? -1 : 0; +} diff --git a/src/pulsecore/anotify.h b/src/pulsecore/anotify.h new file mode 100644 index 00000000..44e942f7 --- /dev/null +++ b/src/pulsecore/anotify.h @@ -0,0 +1,38 @@ +#ifndef foopulseanotifyhfoo +#define foopulseanotifyhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* Asynchronous thread-safe notification of mainloops */ + + +#include +#include + +typedef struct pa_anotify pa_anotify; +typedef void (*pa_anotify_cb_t)(uint8_t event, void *userdata); + +pa_anotify *pa_anotify_new(pa_mainloop_api*api, pa_anotify_cb_t cb, void *userdata); +void pa_anotify_free(pa_anotify *a); +int pa_anotify_signal(pa_anotify *a, uint8_t event); + +#endif -- cgit From 5ad143b3aba3e5bd0d528feb3143dd9cd2f1e845 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Sep 2006 23:42:08 +0000 Subject: upgrade refcnt.h to make use of our new pa_atomic_xxx() API git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1403 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/refcnt.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/pulsecore/refcnt.h b/src/pulsecore/refcnt.h index fade9aa4..6eb5ee3f 100644 --- a/src/pulsecore/refcnt.h +++ b/src/pulsecore/refcnt.h @@ -1,5 +1,5 @@ -#ifndef foopulserefcntfoo -#define foopulserefcntfoo +#ifndef foopulserefcnthfoo +#define foopulserefcnthfoo /* $Id$ */ @@ -22,20 +22,21 @@ USA. ***/ -#include +#include -#define PA_REFCNT_DECLARE volatile AO_t _ref +#define PA_REFCNT_DECLARE \ + pa_atomic_int_t _ref #define PA_REFCNT_INIT(p) \ - AO_store_release_write(&(p)->_ref, 1) + pa_atomic_store(&p->_ref, 1) #define PA_REFCNT_INC(p) \ - AO_fetch_and_add1_release_write(&(p)->_ref) + pa_atomic_inc(&p->_ref) #define PA_REFCNT_DEC(p) \ - (AO_fetch_and_sub1_release_write(&(p)->_ref)-1) + (pa_atomic_dec(&p->_ref)-1) #define PA_REFCNT_VALUE(p) \ - AO_load_acquire_read(&(p)->_ref) + pa_atomic_load(&p->_ref) #endif -- cgit From d210ebbb09daddb2c8c8e8e77243e088b0b19c4d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Sep 2006 23:50:56 +0000 Subject: rework memory block management to be thread-safe and mostly lock-free. pa_memblock is now an opaque structure. Access to its fields is now done through various accessor functions in a thread-safe manner. pa_memblock_acquire() and pa_memblock_release() are now used to access the attached audio data. Why? To allow safe manipulation of the memory pointer maintained by the memory block. Internally _acquire() and _release() maintain a reference counter. Please do not confuse this reference counter whith the one maintained by pa_memblock_ref()/_unref()! As a side effect this patch removes all direct usages of AO_t and replaces it with pa_atomic_xxx based code. This stuff needs some serious testing love. Especially if threads are actively used. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1404 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 7 +- src/modules/module-alsa-sink.c | 14 +- src/modules/module-alsa-source.c | 10 +- src/modules/module-esound-sink.c | 11 +- src/modules/module-jack-sink.c | 5 +- src/modules/module-jack-source.c | 7 +- src/modules/module-oss-mmap.c | 4 +- src/modules/module-oss.c | 22 +- src/modules/module-pipe-sink.c | 11 +- src/modules/module-pipe-source.c | 13 +- src/modules/module-sine.c | 14 +- src/modules/rtp/rtp.c | 18 +- src/pulse/internal.h | 1 + src/pulse/stream.c | 20 +- src/pulsecore/cli-command.c | 20 +- src/pulsecore/mcalign.c | 10 +- src/pulsecore/memblock.c | 507 +++++++++++++++++++++++++++++--------- src/pulsecore/memblock.h | 61 ++--- src/pulsecore/memblockq.c | 10 +- src/pulsecore/memchunk.c | 15 +- src/pulsecore/play-memchunk.c | 2 +- src/pulsecore/protocol-esound.c | 38 ++- src/pulsecore/protocol-native.c | 14 +- src/pulsecore/protocol-simple.c | 22 +- src/pulsecore/pstream.c | 169 ++++++------- src/pulsecore/resampler.c | 247 ++++++++++--------- src/pulsecore/sample-util.c | 116 ++++++--- src/pulsecore/sample-util.h | 3 +- src/pulsecore/sink-input.c | 9 +- src/pulsecore/sink.c | 26 +- src/pulsecore/sound-file-stream.c | 9 +- src/pulsecore/sound-file.c | 15 +- src/tests/flist-test.c | 2 +- src/tests/mcalign-test.c | 19 +- src/tests/memblock-test.c | 20 +- src/tests/memblockq-test.c | 4 +- 36 files changed, 993 insertions(+), 502 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 64df8614..0ce805ec 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -268,8 +268,7 @@ thread_test_CFLAGS = $(AM_CFLAGS) thread_test_LDADD = $(AM_LDADD) libpulsecore.la thread_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -flist_test_SOURCES = tests/flist-test.c \ - pulsecore/flist.c pulsecore/flist.h +flist_test_SOURCES = tests/flist-test.c flist_test_CFLAGS = $(AM_CFLAGS) flist_test_LDADD = $(AM_LDADD) libpulsecore.la flist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -448,6 +447,8 @@ libpulse_la_SOURCES += \ pulsecore/core-error.c pulsecore/core-error.h \ pulsecore/winsock.h pulsecore/creds.h \ pulsecore/shm.c pulsecore/shm.h \ + pulsecore/flist.c pulsecore/flist.h \ + pulsecore/anotify.c pulsecore/anotify.h \ $(PA_THREAD_OBJS) if OS_IS_WIN32 @@ -628,6 +629,8 @@ libpulsecore_la_SOURCES += \ pulsecore/core-error.c pulsecore/core-error.h \ pulsecore/hook-list.c pulsecore/hook-list.h \ pulsecore/shm.c pulsecore/shm.h \ + pulsecore/flist.c pulsecore/flist.h \ + pulsecore/anotify.c pulsecore/anotify.h \ $(PA_THREAD_OBJS) if OS_IS_WIN32 diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 6ff9a6e4..7bbd7de2 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -144,6 +144,7 @@ static void do_write(struct userdata *u) { update_usage(u); for (;;) { + void *p; pa_memchunk *memchunk = NULL; snd_pcm_sframes_t frames; @@ -156,9 +157,15 @@ static void do_write(struct userdata *u) { memchunk = &u->memchunk; } - assert(memchunk->memblock && memchunk->memblock->data && memchunk->length && memchunk->memblock->length && (memchunk->length % u->frame_size) == 0); + assert(memchunk->memblock); + assert(memchunk->length); + assert((memchunk->length % u->frame_size) == 0); - if ((frames = snd_pcm_writei(u->pcm_handle, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length / u->frame_size)) < 0) { + p = pa_memblock_acquire(memchunk->memblock); + + if ((frames = snd_pcm_writei(u->pcm_handle, (uint8_t*) p + memchunk->index, memchunk->length / u->frame_size)) < 0) { + pa_memblock_release(memchunk->memblock); + if (frames == -EAGAIN) return; @@ -176,6 +183,9 @@ static void do_write(struct userdata *u) { return; } + pa_memblock_release(memchunk->memblock); + + if (memchunk == &u->memchunk) { size_t l = frames * u->frame_size; memchunk->index += l; diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index aa0666f1..9bde46da 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -149,6 +149,7 @@ static void do_read(struct userdata *u) { pa_memchunk post_memchunk; snd_pcm_sframes_t frames; size_t l; + void *p; if (!u->memchunk.memblock) { u->memchunk.memblock = pa_memblock_new(u->source->core->mempool, u->memchunk.length = u->fragment_size); @@ -157,11 +158,13 @@ static void do_read(struct userdata *u) { assert(u->memchunk.memblock); assert(u->memchunk.length); - assert(u->memchunk.memblock->data); - assert(u->memchunk.memblock->length); assert(u->memchunk.length % u->frame_size == 0); - if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { + p = pa_memblock_acquire(u->memchunk.memblock); + + if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) p + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { + pa_memblock_release(u->memchunk.memblock); + if (frames == -EAGAIN) return; @@ -178,6 +181,7 @@ static void do_read(struct userdata *u) { pa_module_unload_request(u->module); return; } + pa_memblock_release(u->memchunk.memblock); l = frames * u->frame_size; diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index 6d4a8489..ca1f16ce 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -142,18 +142,25 @@ static int do_write(struct userdata *u) { u->write_index = u->write_length = 0; } } else if (u->state == STATE_RUNNING) { + void *p; + pa_module_set_used(u->module, pa_sink_used_by(u->sink)); if (!u->memchunk.length) if (pa_sink_render(u->sink, 8192, &u->memchunk) < 0) return 0; - assert(u->memchunk.memblock && u->memchunk.length); + assert(u->memchunk.memblock); + assert(u->memchunk.length); + + p = pa_memblock_acquire(u->memchunk.memblock); - if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { + if ((r = pa_iochannel_write(u->io, (uint8_t*) p + u->memchunk.index, u->memchunk.length)) < 0) { + pa_memblock_release(u->memchunk.memblock); pa_log("write() failed: %s", pa_cstrerror(errno)); return -1; } + pa_memblock_release(u->memchunk.memblock); u->memchunk.index += r; u->memchunk.length -= r; diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index 47f77bab..66ded27f 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -135,22 +135,25 @@ static void io_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_ unsigned fs; jack_nframes_t frame_idx; pa_memchunk chunk; + void *p; fs = pa_frame_size(&u->sink->sample_spec); pa_sink_render_full(u->sink, u->frames_requested * fs, &chunk); + p = pa_memblock_acquire(chunk.memblock); for (frame_idx = 0; frame_idx < u->frames_requested; frame_idx ++) { unsigned c; for (c = 0; c < u->channels; c++) { - float *s = ((float*) ((uint8_t*) chunk.memblock->data + chunk.index)) + (frame_idx * u->channels) + c; + float *s = ((float*) ((uint8_t*) p + chunk.index)) + (frame_idx * u->channels) + c; float *d = ((float*) u->buffer[c]) + frame_idx; *d = *s; } } + pa_memblock_release(chunk.memblock); pa_memblock_unref(chunk.memblock); u->frames_requested = 0; diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index 62a99108..5270b241 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -134,23 +134,28 @@ static void io_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_ unsigned fs; jack_nframes_t frame_idx; pa_memchunk chunk; + void *p; fs = pa_frame_size(&u->source->sample_spec); chunk.memblock = pa_memblock_new(u->core->mempool, chunk.length = u->frames_posted * fs); chunk.index = 0; + + p = pa_memblock_acquire(chunk.memblock); for (frame_idx = 0; frame_idx < u->frames_posted; frame_idx ++) { unsigned c; for (c = 0; c < u->channels; c++) { float *s = ((float*) u->buffer[c]) + frame_idx; - float *d = ((float*) ((uint8_t*) chunk.memblock->data + chunk.index)) + (frame_idx * u->channels) + c; + float *d = ((float*) ((uint8_t*) p + chunk.index)) + (frame_idx * u->channels) + c; *d = *s; } } + pa_memblock_release(chunk.memblock); + pa_source_post(u->source, &chunk); pa_memblock_unref(chunk.memblock); diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index 5ab08287..39a8511f 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -170,7 +170,7 @@ static void out_fill_memblocks(struct userdata *u, unsigned n) { u->out_fragment_size, 1); assert(chunk.memblock); - chunk.length = chunk.memblock->length; + chunk.length = pa_memblock_get_length(chunk.memblock); chunk.index = 0; pa_sink_render_into_full(u->sink, &chunk); @@ -214,7 +214,7 @@ static void in_post_memblocks(struct userdata *u, unsigned n) { if (!u->in_memblocks[u->in_current]) { chunk.memblock = u->in_memblocks[u->in_current] = pa_memblock_new_fixed(u->core->mempool, (uint8_t*) u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size, 1); - chunk.length = chunk.memblock->length; + chunk.length = pa_memblock_get_length(chunk.memblock); chunk.index = 0; pa_source_post(u->source, &chunk); diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index b71581d9..73f0d57e 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -155,6 +155,7 @@ static void do_write(struct userdata *u) { } do { + void *p; memchunk = &u->memchunk; if (!memchunk->length) @@ -162,16 +163,18 @@ static void do_write(struct userdata *u) { memchunk = &u->silence; assert(memchunk->memblock); - assert(memchunk->memblock->data); assert(memchunk->length); - - if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { + + p = pa_memblock_acquire(memchunk->memblock); + if ((r = pa_iochannel_write(u->io, (uint8_t*) p + memchunk->index, memchunk->length)) < 0) { + pa_memblock_release(memchunk->memblock); pa_log("write() failed: %s", pa_cstrerror(errno)); clear_up(u); pa_module_unload_request(u->module); break; } + pa_memblock_release(memchunk->memblock); if (memchunk == &u->silence) assert(r % u->sample_size == 0); @@ -217,9 +220,13 @@ static void do_read(struct userdata *u) { } do { + void *p; memchunk.memblock = pa_memblock_new(u->core->mempool, l); - assert(memchunk.memblock); - if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { + + p = pa_memblock_acquire(memchunk.memblock); + + if ((r = pa_iochannel_read(u->io, p, pa_memblock_get_length(memchunk.memblock))) < 0) { + pa_memblock_release(memchunk.memblock); pa_memblock_unref(memchunk.memblock); if (errno != EAGAIN) { pa_log("read() failed: %s", pa_cstrerror(errno)); @@ -228,9 +235,10 @@ static void do_read(struct userdata *u) { } break; } + pa_memblock_release(memchunk.memblock); - assert(r <= (ssize_t) memchunk.memblock->length); - memchunk.length = memchunk.memblock->length = r; + assert(r <= (ssize_t) pa_memblock_get_length(memchunk.memblock)); + memchunk.length = r; memchunk.index = 0; pa_source_post(u->source, &memchunk); diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index 4aee849b..59d91aa4 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -84,6 +84,8 @@ static const char* const valid_modargs[] = { static void do_write(struct userdata *u) { ssize_t r; + void *p; + assert(u); u->core->mainloop->defer_enable(u->defer_event, 0); @@ -97,12 +99,17 @@ static void do_write(struct userdata *u) { if (pa_sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0) return; - assert(u->memchunk.memblock && u->memchunk.length); + assert(u->memchunk.memblock); + assert(u->memchunk.length); + + p = pa_memblock_acquire(u->memchunk.memblock); - if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { + if ((r = pa_iochannel_write(u->io, (uint8_t*) p + u->memchunk.index, u->memchunk.length)) < 0) { + pa_memblock_release(u->memchunk.memblock); pa_log("write(): %s", pa_cstrerror(errno)); return; } + pa_memblock_release(u->memchunk.memblock); u->memchunk.index += r; u->memchunk.length -= r; diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index c251f7ac..99f4f3b9 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -82,7 +82,9 @@ static const char* const valid_modargs[] = { static void do_read(struct userdata *u) { ssize_t r; + void *p; pa_memchunk chunk; + assert(u); if (!pa_iochannel_is_readable(u->io)) @@ -95,17 +97,22 @@ static void do_read(struct userdata *u) { u->chunk.index = chunk.length = 0; } - assert(u->chunk.memblock && u->chunk.memblock->length > u->chunk.index); - if ((r = pa_iochannel_read(u->io, (uint8_t*) u->chunk.memblock->data + u->chunk.index, u->chunk.memblock->length - u->chunk.index)) <= 0) { + assert(u->chunk.memblock); + assert(pa_memblock_get_length(u->chunk.memblock) > u->chunk.index); + + p = pa_memblock_acquire(u->chunk.memblock); + if ((r = pa_iochannel_read(u->io, (uint8_t*) p + u->chunk.index, pa_memblock_get_length(u->chunk.memblock) - u->chunk.index)) <= 0) { + pa_memblock_release(u->chunk.memblock); pa_log("read(): %s", pa_cstrerror(errno)); return; } + pa_memblock_release(u->chunk.memblock); u->chunk.length = r; pa_source_post(u->source, &u->chunk); u->chunk.index += r; - if (u->chunk.index >= u->chunk.memblock->length) { + if (u->chunk.index >= pa_memblock_get_length(u->chunk.memblock)) { u->chunk.index = u->chunk.length = 0; pa_memblock_unref(u->chunk.memblock); u->chunk.memblock = NULL; diff --git a/src/modules/module-sine.c b/src/modules/module-sine.c index fa29ba16..f65b1f3a 100644 --- a/src/modules/module-sine.c +++ b/src/modules/module-sine.c @@ -63,7 +63,7 @@ static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { chunk->memblock = pa_memblock_ref(u->memblock); chunk->index = u->peek_index; - chunk->length = u->memblock->length - u->peek_index; + chunk->length = pa_memblock_get_length(u->memblock) - u->peek_index; return 0; } @@ -72,11 +72,12 @@ static void sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t l assert(i && chunk && length && i->userdata); u = i->userdata; - assert(chunk->memblock == u->memblock && length <= u->memblock->length-u->peek_index); + assert(chunk->memblock == u->memblock); + assert(length <= pa_memblock_get_length(u->memblock)-u->peek_index); u->peek_index += length; - if (u->peek_index >= u->memblock->length) + if (u->peek_index >= pa_memblock_get_length(u->memblock)) u->peek_index = 0; } @@ -109,6 +110,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_sample_spec ss; uint32_t frequency; char t[256]; + void *p; pa_sink_input_new_data data; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -140,8 +142,10 @@ int pa__init(pa_core *c, pa_module*m) { } u->memblock = pa_memblock_new(c->mempool, pa_bytes_per_second(&ss)); - calc_sine(u->memblock->data, u->memblock->length, frequency); - + p = pa_memblock_acquire(u->memblock); + calc_sine(p, pa_memblock_get_length(u->memblock), frequency); + pa_memblock_release(u->memblock); + snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency); pa_sink_input_new_data_init(&data); diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c index 3bb0ea47..a4362f84 100644 --- a/src/modules/rtp/rtp.c +++ b/src/modules/rtp/rtp.c @@ -79,7 +79,7 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { size_t k = n + chunk.length > size ? size - n : chunk.length; if (chunk.memblock) { - iov[iov_idx].iov_base = (void*)((uint8_t*) chunk.memblock->data + chunk.index); + iov[iov_idx].iov_base = (void*)((uint8_t*) pa_memblock_acquire(chunk.memblock) + chunk.index); iov[iov_idx].iov_len = k; mb[iov_idx] = chunk.memblock; iov_idx ++; @@ -114,8 +114,10 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { k = sendmsg(c->fd, &m, MSG_DONTWAIT); - for (i = 1; i < iov_idx; i++) + for (i = 1; i < iov_idx; i++) { + pa_memblock_release(mb[i]); pa_memblock_unref(mb[i]); + } c->sequence++; } else @@ -172,7 +174,7 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { chunk->memblock = pa_memblock_new(pool, size); - iov.iov_base = chunk->memblock->data; + iov.iov_base = pa_memblock_acquire(chunk->memblock); iov.iov_len = size; m.msg_name = NULL; @@ -193,9 +195,9 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { goto fail; } - memcpy(&header, chunk->memblock->data, sizeof(uint32_t)); - memcpy(&c->timestamp, (uint8_t*) chunk->memblock->data + 4, sizeof(uint32_t)); - memcpy(&c->ssrc, (uint8_t*) chunk->memblock->data + 8, sizeof(uint32_t)); + memcpy(&header, iov.iov_base, sizeof(uint32_t)); + memcpy(&c->timestamp, (uint8_t*) iov.iov_base + 4, sizeof(uint32_t)); + memcpy(&c->ssrc, (uint8_t*) iov.iov_base + 8, sizeof(uint32_t)); header = ntohl(header); c->timestamp = ntohl(c->timestamp); @@ -236,8 +238,10 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { return 0; fail: - if (chunk->memblock) + if (chunk->memblock) { + pa_memblock_release(chunk->memblock); pa_memblock_unref(chunk->memblock); + } return -1; } diff --git a/src/pulse/internal.h b/src/pulse/internal.h index 4eef4b4a..76d80d83 100644 --- a/src/pulse/internal.h +++ b/src/pulse/internal.h @@ -113,6 +113,7 @@ struct pa_stream { uint32_t requested_bytes; pa_memchunk peek_memchunk; + void *peek_data; pa_memblockq *record_memblockq; int corked; diff --git a/src/pulse/stream.c b/src/pulse/stream.c index 180cd096..d31127d8 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -88,6 +88,7 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->peek_memchunk.index = 0; s->peek_memchunk.length = 0; s->peek_memchunk.memblock = NULL; + s->peek_data = NULL; s->record_memblockq = NULL; @@ -122,8 +123,11 @@ static void stream_free(pa_stream *s) { s->mainloop->time_free(s->auto_timing_update_event); } - if (s->peek_memchunk.memblock) + if (s->peek_memchunk.memblock) { + if (s->peek_data) + pa_memblock_release(s->peek_memchunk.memblock); pa_memblock_unref(s->peek_memchunk.memblock); + } if (s->record_memblockq) pa_memblockq_free(s->record_memblockq); @@ -605,8 +609,11 @@ int pa_stream_write( if (free_cb) chunk.memblock = pa_memblock_new_user(s->context->mempool, (void*) data, length, free_cb, 1); else { + void *tdata; chunk.memblock = pa_memblock_new(s->context->mempool, length); - memcpy(chunk.memblock->data, data, length); + tdata = pa_memblock_acquire(chunk.memblock); + memcpy(tdata, data, length); + pa_memblock_release(chunk.memblock); } chunk.index = 0; @@ -672,9 +679,12 @@ int pa_stream_peek(pa_stream *s, const void **data, size_t *length) { *length = 0; return 0; } + + s->peek_data = pa_memblock_acquire(s->peek_memchunk.memblock); } - *data = (const char*) s->peek_memchunk.memblock->data + s->peek_memchunk.index; + assert(s->peek_data); + *data = (uint8_t*) s->peek_data + s->peek_memchunk.index; *length = s->peek_memchunk.length; return 0; } @@ -692,7 +702,9 @@ int pa_stream_drop(pa_stream *s) { /* Fix the simulated local read index */ if (s->timing_info_valid && !s->timing_info.read_index_corrupt) s->timing_info.read_index += s->peek_memchunk.length; - + + assert(s->peek_data); + pa_memblock_release(s->peek_memchunk.memblock); pa_memblock_unref(s->peek_memchunk.memblock); s->peek_memchunk.length = 0; s->peek_memchunk.index = 0; diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index ae475c3a..d7e4a75c 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -259,20 +259,20 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G stat = pa_mempool_get_stat(c->mempool); pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n", - (unsigned) AO_load_acquire_read((AO_t*) &stat->n_allocated), - pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->allocated_size))); + (unsigned) pa_atomic_load(&stat->n_allocated), + pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->allocated_size))); pa_strbuf_printf(buf, "Memory blocks allocated during the whole lifetime: %u, size: %s.\n", - (unsigned) AO_load_acquire_read((AO_t*) &stat->n_accumulated), - pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->accumulated_size))); + (unsigned) pa_atomic_load(&stat->n_accumulated), + pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->accumulated_size))); pa_strbuf_printf(buf, "Memory blocks imported from other processes: %u, size: %s.\n", - (unsigned) AO_load_acquire_read((AO_t*) &stat->n_imported), - pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->imported_size))); + (unsigned) pa_atomic_load(&stat->n_imported), + pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->imported_size))); pa_strbuf_printf(buf, "Memory blocks exported to other processes: %u, size: %s.\n", - (unsigned) AO_load_acquire_read((AO_t*) &stat->n_exported), - pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->exported_size))); + (unsigned) pa_atomic_load(&stat->n_exported), + pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->exported_size))); pa_strbuf_printf(buf, "Total sample cache size: %s.\n", pa_bytes_snprint(s, sizeof(s), pa_scache_total_size(c))); @@ -289,8 +289,8 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G pa_strbuf_printf(buf, "Memory blocks of type %s: %u allocated/%u accumulated.\n", type_table[k], - (unsigned) AO_load_acquire_read(&stat->n_allocated_by_type[k]), - (unsigned) AO_load_acquire_read(&stat->n_accumulated_by_type[k])); + (unsigned) pa_atomic_load(&stat->n_allocated_by_type[k]), + (unsigned) pa_atomic_load(&stat->n_accumulated_by_type[k])); return 0; } diff --git a/src/pulsecore/mcalign.c b/src/pulsecore/mcalign.c index 9ede610d..aa2eae46 100644 --- a/src/pulsecore/mcalign.c +++ b/src/pulsecore/mcalign.c @@ -89,6 +89,7 @@ void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { } else { size_t l; + void *lo_data, *m_data; /* We have to copy */ assert(m->leftover.length < m->base); @@ -100,10 +101,15 @@ void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { /* Can we use the current block? */ pa_memchunk_make_writable(&m->leftover, m->base); - memcpy((uint8_t*) m->leftover.memblock->data + m->leftover.index + m->leftover.length, (uint8_t*) c->memblock->data + c->index, l); + lo_data = pa_memblock_acquire(m->leftover.memblock); + m_data = pa_memblock_acquire(c->memblock); + memcpy((uint8_t*) lo_data + m->leftover.index + m->leftover.length, (uint8_t*) m_data + c->index, l); + pa_memblock_release(m->leftover.memblock); + pa_memblock_release(c->memblock); m->leftover.length += l; - assert(m->leftover.length <= m->base && m->leftover.length <= m->leftover.memblock->length); + assert(m->leftover.length <= m->base); + assert(m->leftover.length <= pa_memblock_get_length(m->leftover.memblock)); if (c->length > l) { /* Save the remainder of the memory block */ diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 9cfd79b5..f11a7174 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -30,10 +30,13 @@ #include #include +#include #include #include #include +#include +#include #include "memblock.h" @@ -45,6 +48,32 @@ #define PA_MEMIMPORT_SLOTS_MAX 128 #define PA_MEMIMPORT_SEGMENTS_MAX 16 +struct pa_memblock { + PA_REFCNT_DECLARE; /* the reference counter */ + pa_mempool *pool; + + pa_memblock_type_t type; + int read_only; /* boolean */ + + pa_atomic_ptr_t data; + size_t length; + + pa_atomic_int_t n_acquired; + pa_atomic_int_t please_signal; + + union { + struct { + /* If type == PA_MEMBLOCK_USER this points to a function for freeing this memory block */ + pa_free_cb_t free_cb; + } user; + + struct { + uint32_t id; + pa_memimport_segment *segment; + } imported; + } per_type; +}; + struct pa_memimport_segment { pa_memimport *import; pa_shm memory; @@ -52,6 +81,8 @@ struct pa_memimport_segment { }; struct pa_memimport { + pa_mutex *mutex; + pa_mempool *pool; pa_hashmap *segments; pa_hashmap *blocks; @@ -70,9 +101,11 @@ struct memexport_slot { }; struct pa_memexport { + pa_mutex *mutex; pa_mempool *pool; struct memexport_slot slots[PA_MEMEXPORT_SLOTS_MAX]; + PA_LLIST_HEAD(struct memexport_slot, free_slots); PA_LLIST_HEAD(struct memexport_slot, used_slots); unsigned n_init; @@ -92,63 +125,71 @@ struct mempool_slot { }; struct pa_mempool { + pa_mutex *mutex; + pa_cond *cond; + pa_shm memory; size_t block_size; - unsigned n_blocks, n_init; + unsigned n_blocks; + + pa_atomic_int_t n_init; PA_LLIST_HEAD(pa_memimport, imports); PA_LLIST_HEAD(pa_memexport, exports); /* A list of free slots that may be reused */ - PA_LLIST_HEAD(struct mempool_slot, free_slots); + pa_flist *free_slots; pa_mempool_stat stat; }; static void segment_detach(pa_memimport_segment *seg); +/* No lock necessary */ static void stat_add(pa_memblock*b) { assert(b); assert(b->pool); - AO_fetch_and_add1_release_write(&b->pool->stat.n_allocated); - AO_fetch_and_add_release_write(&b->pool->stat.allocated_size, (AO_t) b->length); + pa_atomic_inc(&b->pool->stat.n_allocated); + pa_atomic_add(&b->pool->stat.allocated_size, (int) b->length); - AO_fetch_and_add1_release_write(&b->pool->stat.n_accumulated); - AO_fetch_and_add_release_write(&b->pool->stat.accumulated_size, (AO_t) b->length); + pa_atomic_inc(&b->pool->stat.n_accumulated); + pa_atomic_add(&b->pool->stat.accumulated_size, (int) b->length); if (b->type == PA_MEMBLOCK_IMPORTED) { - AO_fetch_and_add1_release_write(&b->pool->stat.n_imported); - AO_fetch_and_add_release_write(&b->pool->stat.imported_size, (AO_t) b->length); + pa_atomic_inc(&b->pool->stat.n_imported); + pa_atomic_add(&b->pool->stat.imported_size, (int) b->length); } - AO_fetch_and_add1_release_write(&b->pool->stat.n_allocated_by_type[b->type]); - AO_fetch_and_add1_release_write(&b->pool->stat.n_accumulated_by_type[b->type]); + pa_atomic_inc(&b->pool->stat.n_allocated_by_type[b->type]); + pa_atomic_inc(&b->pool->stat.n_accumulated_by_type[b->type]); } +/* No lock necessary */ static void stat_remove(pa_memblock *b) { assert(b); assert(b->pool); - assert(AO_load_acquire_read(&b->pool->stat.n_allocated) > 0); - assert(AO_load_acquire_read(&b->pool->stat.allocated_size) >= (AO_t) b->length); + assert(pa_atomic_load(&b->pool->stat.n_allocated) > 0); + assert(pa_atomic_load(&b->pool->stat.allocated_size) >= (int) b->length); - AO_fetch_and_sub1_release_write(&b->pool->stat.n_allocated); - AO_fetch_and_add_release_write(&b->pool->stat.allocated_size, (AO_t) (-b->length)); + pa_atomic_dec(&b->pool->stat.n_allocated); + pa_atomic_add(&b->pool->stat.allocated_size, - (int) b->length); if (b->type == PA_MEMBLOCK_IMPORTED) { - assert(AO_load_acquire_read(&b->pool->stat.n_imported) > 0); - assert(AO_load_acquire_read(&b->pool->stat.imported_size) >= (AO_t) b->length); + assert(pa_atomic_load(&b->pool->stat.n_imported) > 0); + assert(pa_atomic_load(&b->pool->stat.imported_size) >= (int) b->length); - AO_fetch_and_sub1_release_write(&b->pool->stat.n_imported); - AO_fetch_and_add_release_write(&b->pool->stat.imported_size, (AO_t) (-b->length)); + pa_atomic_dec(&b->pool->stat.n_imported); + pa_atomic_add(&b->pool->stat.imported_size, - (int) b->length); } - AO_fetch_and_sub1_release_write(&b->pool->stat.n_allocated_by_type[b->type]); + pa_atomic_dec(&b->pool->stat.n_allocated_by_type[b->type]); } static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length); +/* No lock necessary */ pa_memblock *pa_memblock_new(pa_mempool *p, size_t length) { pa_memblock *b; @@ -161,6 +202,7 @@ pa_memblock *pa_memblock_new(pa_mempool *p, size_t length) { return b; } +/* No lock necessary */ static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length) { pa_memblock *b; @@ -168,49 +210,61 @@ static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length) { assert(length > 0); b = pa_xmalloc(sizeof(pa_memblock) + length); + PA_REFCNT_INIT(b); + b->pool = p; b->type = PA_MEMBLOCK_APPENDED; b->read_only = 0; - PA_REFCNT_INIT(b); + pa_atomic_ptr_store(&b->data, (uint8_t*)b + sizeof(pa_memblock)); b->length = length; - b->data = (uint8_t*) b + sizeof(pa_memblock); - b->pool = p; - + pa_atomic_store(&b->n_acquired, 0); + pa_atomic_store(&b->please_signal, 0); + stat_add(b); return b; } +/* No lock necessary */ static struct mempool_slot* mempool_allocate_slot(pa_mempool *p) { struct mempool_slot *slot; assert(p); - if (p->free_slots) { - slot = p->free_slots; - PA_LLIST_REMOVE(struct mempool_slot, p->free_slots, slot); - } else if (p->n_init < p->n_blocks) - slot = (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->block_size * p->n_init++)); - else { - pa_log_debug("Pool full"); - AO_fetch_and_add1_release_write(&p->stat.n_pool_full); - return NULL; + if (!(slot = pa_flist_pop(p->free_slots))) { + int idx; + + /* The free list was empty, we have to allocate a new entry */ + + if ((unsigned) (idx = pa_atomic_inc(&p->n_init)) >= p->n_blocks) + pa_atomic_dec(&p->n_init); + else + slot = (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->block_size * idx)); + + if (!slot) { + pa_log_debug("Pool full"); + pa_atomic_inc(&p->stat.n_pool_full); + } } return slot; } +/* No lock necessary */ static void* mempool_slot_data(struct mempool_slot *slot) { assert(slot); return (uint8_t*) slot + sizeof(struct mempool_slot); } +/* No lock necessary */ static unsigned mempool_slot_idx(pa_mempool *p, void *ptr) { assert(p); + assert((uint8_t*) ptr >= (uint8_t*) p->memory.ptr); assert((uint8_t*) ptr < (uint8_t*) p->memory.ptr + p->memory.size); return ((uint8_t*) ptr - (uint8_t*) p->memory.ptr) / p->block_size; } +/* No lock necessary */ static struct mempool_slot* mempool_slot_by_ptr(pa_mempool *p, void *ptr) { unsigned idx; @@ -220,6 +274,7 @@ static struct mempool_slot* mempool_slot_by_ptr(pa_mempool *p, void *ptr) { return (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (idx * p->block_size)); } +/* No lock necessary */ pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) { pa_memblock *b = NULL; struct mempool_slot *slot; @@ -234,7 +289,7 @@ pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) { b = mempool_slot_data(slot); b->type = PA_MEMBLOCK_POOL; - b->data = (uint8_t*) b + sizeof(pa_memblock); + pa_atomic_ptr_store(&b->data, (uint8_t*) b + sizeof(pa_memblock)); } else if (p->block_size - sizeof(struct mempool_slot) >= length) { @@ -243,22 +298,26 @@ pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) { b = pa_xnew(pa_memblock, 1); b->type = PA_MEMBLOCK_POOL_EXTERNAL; - b->data = mempool_slot_data(slot); + pa_atomic_ptr_store(&b->data, mempool_slot_data(slot)); + } else { pa_log_debug("Memory block too large for pool: %u > %u", length, p->block_size - sizeof(struct mempool_slot)); - AO_fetch_and_add1_release_write(&p->stat.n_too_large_for_pool); + pa_atomic_inc(&p->stat.n_too_large_for_pool); return NULL; } - b->length = length; - b->read_only = 0; PA_REFCNT_INIT(b); b->pool = p; + b->read_only = 0; + b->length = length; + pa_atomic_store(&b->n_acquired, 0); + pa_atomic_store(&b->please_signal, 0); stat_add(b); return b; } +/* No lock necessary */ pa_memblock *pa_memblock_new_fixed(pa_mempool *p, void *d, size_t length, int read_only) { pa_memblock *b; @@ -267,17 +326,20 @@ pa_memblock *pa_memblock_new_fixed(pa_mempool *p, void *d, size_t length, int re assert(length > 0); b = pa_xnew(pa_memblock, 1); + PA_REFCNT_INIT(b); + b->pool = p; b->type = PA_MEMBLOCK_FIXED; b->read_only = read_only; - PA_REFCNT_INIT(b); + pa_atomic_ptr_store(&b->data, d); b->length = length; - b->data = d; - b->pool = p; + pa_atomic_store(&b->n_acquired, 0); + pa_atomic_store(&b->please_signal, 0); stat_add(b); return b; } +/* No lock necessary */ pa_memblock *pa_memblock_new_user(pa_mempool *p, void *d, size_t length, void (*free_cb)(void *p), int read_only) { pa_memblock *b; @@ -287,18 +349,72 @@ pa_memblock *pa_memblock_new_user(pa_mempool *p, void *d, size_t length, void (* assert(free_cb); b = pa_xnew(pa_memblock, 1); + PA_REFCNT_INIT(b); + b->pool = p; b->type = PA_MEMBLOCK_USER; b->read_only = read_only; - PA_REFCNT_INIT(b); + pa_atomic_ptr_store(&b->data, d); b->length = length; - b->data = d; + pa_atomic_store(&b->n_acquired, 0); + pa_atomic_store(&b->please_signal, 0); + b->per_type.user.free_cb = free_cb; - b->pool = p; stat_add(b); return b; } +/* No lock necessary */ +int pa_memblock_is_read_only(pa_memblock *b) { + assert(b); + assert(PA_REFCNT_VALUE(b) > 0); + + return b->read_only && PA_REFCNT_VALUE(b) == 1; +} + +/* No lock necessary */ +void* pa_memblock_acquire(pa_memblock *b) { + assert(b); + assert(PA_REFCNT_VALUE(b) > 0); + + pa_atomic_inc(&b->n_acquired); + + return pa_atomic_ptr_load(&b->data); +} + +/* No lock necessary, in corner cases locks by its own */ +void pa_memblock_release(pa_memblock *b) { + int r; + assert(b); + assert(PA_REFCNT_VALUE(b) > 0); + + r = pa_atomic_dec(&b->n_acquired); + assert(r >= 1); + + if (r == 1 && pa_atomic_load(&b->please_signal)) { + pa_mempool *p = b->pool; + /* Signal a waiting thread that this memblock is no longer used */ + pa_mutex_lock(p->mutex); + pa_cond_signal(p->cond, 1); + pa_mutex_unlock(p->mutex); + } +} + +size_t pa_memblock_get_length(pa_memblock *b) { + assert(b); + assert(PA_REFCNT_VALUE(b) > 0); + + return b->length; +} + +pa_mempool* pa_memblock_get_pool(pa_memblock *b) { + assert(b); + assert(PA_REFCNT_VALUE(b) > 0); + + return b->pool; +} + +/* No lock necessary */ pa_memblock* pa_memblock_ref(pa_memblock*b) { assert(b); assert(PA_REFCNT_VALUE(b) > 0); @@ -307,19 +423,17 @@ pa_memblock* pa_memblock_ref(pa_memblock*b) { return b; } -void pa_memblock_unref(pa_memblock*b) { +static void memblock_free(pa_memblock *b) { assert(b); - assert(PA_REFCNT_VALUE(b) > 0); - - if (PA_REFCNT_DEC(b) > 0) - return; + assert(pa_atomic_load(&b->n_acquired) == 0); + stat_remove(b); switch (b->type) { case PA_MEMBLOCK_USER : assert(b->per_type.user.free_cb); - b->per_type.user.free_cb(b->data); + b->per_type.user.free_cb(pa_atomic_ptr_load(&b->data)); /* Fall through */ @@ -330,17 +444,23 @@ void pa_memblock_unref(pa_memblock*b) { case PA_MEMBLOCK_IMPORTED : { pa_memimport_segment *segment; - + pa_memimport *import; + + /* FIXME! This should be implemented lock-free */ + segment = b->per_type.imported.segment; assert(segment); - assert(segment->import); + import = segment->import; + assert(import); - pa_hashmap_remove(segment->import->blocks, PA_UINT32_TO_PTR(b->per_type.imported.id)); - segment->import->release_cb(segment->import, b->per_type.imported.id, segment->import->userdata); - + pa_mutex_lock(import->mutex); + pa_hashmap_remove(import->blocks, PA_UINT32_TO_PTR(b->per_type.imported.id)); if (-- segment->n_blocks <= 0) segment_detach(segment); - + pa_mutex_unlock(import->mutex); + + import->release_cb(import, b->per_type.imported.id, import->userdata); + pa_xfree(b); break; } @@ -348,13 +468,20 @@ void pa_memblock_unref(pa_memblock*b) { case PA_MEMBLOCK_POOL_EXTERNAL: case PA_MEMBLOCK_POOL: { struct mempool_slot *slot; + int call_free; - slot = mempool_slot_by_ptr(b->pool, b->data); + slot = mempool_slot_by_ptr(b->pool, pa_atomic_ptr_load(&b->data)); assert(slot); + + call_free = b->type == PA_MEMBLOCK_POOL_EXTERNAL; + + /* The free list dimensions should easily allow all slots + * to fit in, hence try harder if pushing this slot into + * the free list fails */ + while (pa_flist_push(b->pool->free_slots, slot) < 0) + ; - PA_LLIST_PREPEND(struct mempool_slot, b->pool->free_slots, slot); - - if (b->type == PA_MEMBLOCK_POOL_EXTERNAL) + if (call_free) pa_xfree(b); break; @@ -366,10 +493,42 @@ void pa_memblock_unref(pa_memblock*b) { } } +/* No lock necessary */ +void pa_memblock_unref(pa_memblock*b) { + assert(b); + assert(PA_REFCNT_VALUE(b) > 0); + + if (PA_REFCNT_DEC(b) > 0) + return; + + memblock_free(b); +} + +/* Self locked */ +static void memblock_wait(pa_memblock *b) { + assert(b); + + if (pa_atomic_load(&b->n_acquired) > 0) { + /* We need to wait until all threads gave up access to the + * memory block before we can go on. Unfortunately this means + * that we have to lock and wait here. Sniff! */ + + pa_atomic_inc(&b->please_signal); + + pa_mutex_lock(b->pool->mutex); + while (pa_atomic_load(&b->n_acquired) > 0) + pa_cond_wait(b->pool->cond, b->pool->mutex); + pa_mutex_unlock(b->pool->mutex); + + pa_atomic_dec(&b->please_signal); + } +} + +/* No lock necessary. This function is not multiple caller safe! */ static void memblock_make_local(pa_memblock *b) { assert(b); - AO_fetch_and_sub1_release_write(&b->pool->stat.n_allocated_by_type[b->type]); + pa_atomic_dec(&b->pool->stat.n_allocated_by_type[b->type]); if (b->length <= b->pool->block_size - sizeof(struct mempool_slot)) { struct mempool_slot *slot; @@ -378,53 +537,61 @@ static void memblock_make_local(pa_memblock *b) { void *new_data; /* We can move it into a local pool, perfect! */ + new_data = mempool_slot_data(slot); + memcpy(new_data, pa_atomic_ptr_load(&b->data), b->length); + pa_atomic_ptr_store(&b->data, new_data); + b->type = PA_MEMBLOCK_POOL_EXTERNAL; b->read_only = 0; - new_data = mempool_slot_data(slot); - memcpy(new_data, b->data, b->length); - b->data = new_data; goto finish; } } /* Humm, not enough space in the pool, so lets allocate the memory with malloc() */ - b->type = PA_MEMBLOCK_USER; b->per_type.user.free_cb = pa_xfree; + pa_atomic_ptr_store(&b->data, pa_xmemdup(pa_atomic_ptr_load(&b->data), b->length)); + + b->type = PA_MEMBLOCK_USER; b->read_only = 0; - b->data = pa_xmemdup(b->data, b->length); finish: - AO_fetch_and_add1_release_write(&b->pool->stat.n_allocated_by_type[b->type]); - AO_fetch_and_add1_release_write(&b->pool->stat.n_accumulated_by_type[b->type]); + pa_atomic_inc(&b->pool->stat.n_allocated_by_type[b->type]); + pa_atomic_inc(&b->pool->stat.n_accumulated_by_type[b->type]); + + memblock_wait(b); } +/* No lock necessary. This function is not multiple caller safe*/ void pa_memblock_unref_fixed(pa_memblock *b) { assert(b); assert(PA_REFCNT_VALUE(b) > 0); assert(b->type == PA_MEMBLOCK_FIXED); - if (PA_REFCNT_VALUE(b) > 1) + if (PA_REFCNT_DEC(b) > 0) memblock_make_local(b); - - pa_memblock_unref(b); + else + memblock_free(b); } +/* Self-locked. This function is not multiple-caller safe */ static void memblock_replace_import(pa_memblock *b) { pa_memimport_segment *seg; assert(b); assert(b->type == PA_MEMBLOCK_IMPORTED); - assert(AO_load_acquire_read(&b->pool->stat.n_imported) > 0); - assert(AO_load_acquire_read(&b->pool->stat.imported_size) >= (AO_t) b->length); - AO_fetch_and_sub1_release_write(&b->pool->stat.n_imported); - AO_fetch_and_add_release_write(&b->pool->stat.imported_size, (AO_t) - b->length); + assert(pa_atomic_load(&b->pool->stat.n_imported) > 0); + assert(pa_atomic_load(&b->pool->stat.imported_size) >= (int) b->length); + pa_atomic_dec(&b->pool->stat.n_imported); + pa_atomic_add(&b->pool->stat.imported_size, (int) - b->length); seg = b->per_type.imported.segment; assert(seg); assert(seg->import); + pa_mutex_lock(seg->import->mutex); + pa_hashmap_remove( seg->import->blocks, PA_UINT32_TO_PTR(b->per_type.imported.id)); @@ -433,6 +600,8 @@ static void memblock_replace_import(pa_memblock *b) { if (-- seg->n_blocks <= 0) segment_detach(seg); + + pa_mutex_unlock(seg->import->mutex); } pa_mempool* pa_mempool_new(int shared) { @@ -441,12 +610,15 @@ pa_mempool* pa_mempool_new(int shared) { p = pa_xnew(pa_mempool, 1); + p->mutex = pa_mutex_new(1); + p->cond = pa_cond_new(); + #ifdef HAVE_SYSCONF ps = (size_t) sysconf(_SC_PAGESIZE); #elif defined(PAGE_SIZE) - ps = (size_t) PAGE_SIZE; + ps = (size_t) PAGE_SIZE; #else - ps = 4096; /* Let's hope it's like x86. */ + ps = 4096; /* Let's hope it's like x86. */ #endif p->block_size = (PA_MEMPOOL_SLOT_SIZE/ps)*ps; @@ -463,13 +635,13 @@ pa_mempool* pa_mempool_new(int shared) { return NULL; } - p->n_init = 0; + memset(&p->stat, 0, sizeof(p->stat)); + pa_atomic_store(&p->n_init, 0); PA_LLIST_HEAD_INIT(pa_memimport, p->imports); PA_LLIST_HEAD_INIT(pa_memexport, p->exports); - PA_LLIST_HEAD_INIT(struct mempool_slot, p->free_slots); - memset(&p->stat, 0, sizeof(p->stat)); + p->free_slots = pa_flist_new(p->n_blocks*2); return p; } @@ -477,34 +649,62 @@ pa_mempool* pa_mempool_new(int shared) { void pa_mempool_free(pa_mempool *p) { assert(p); + pa_mutex_lock(p->mutex); + while (p->imports) pa_memimport_free(p->imports); while (p->exports) pa_memexport_free(p->exports); - if (AO_load_acquire_read(&p->stat.n_allocated) > 0) + pa_mutex_unlock(p->mutex); + + if (pa_atomic_load(&p->stat.n_allocated) > 0) pa_log_warn("WARNING! Memory pool destroyed but not all memory blocks freed!"); + + pa_flist_free(p->free_slots, NULL); pa_shm_free(&p->memory); + + pa_mutex_free(p->mutex); + pa_cond_free(p->cond); + pa_xfree(p); } +/* No lock necessary */ const pa_mempool_stat* pa_mempool_get_stat(pa_mempool *p) { assert(p); return &p->stat; } +/* No lock necessary */ void pa_mempool_vacuum(pa_mempool *p) { struct mempool_slot *slot; + pa_flist *list; assert(p); - for (slot = p->free_slots; slot; slot = slot->next) - pa_shm_punch(&p->memory, (uint8_t*) slot + sizeof(struct mempool_slot) - (uint8_t*) p->memory.ptr, p->block_size - sizeof(struct mempool_slot)); + list = pa_flist_new(p->n_blocks*2); + + while ((slot = pa_flist_pop(p->free_slots))) + while (pa_flist_push(list, slot) < 0) + ; + + while ((slot = pa_flist_pop(list))) { + pa_shm_punch(&p->memory, + (uint8_t*) slot - (uint8_t*) p->memory.ptr + sizeof(struct mempool_slot), + p->block_size - sizeof(struct mempool_slot)); + + while (pa_flist_push(p->free_slots, slot)) + ; + } + + pa_flist_free(list, NULL); } +/* No lock necessary */ int pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id) { assert(p); @@ -516,6 +716,7 @@ int pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id) { return 0; } +/* No lock necessary */ int pa_mempool_is_shared(pa_mempool *p) { assert(p); @@ -530,18 +731,23 @@ pa_memimport* pa_memimport_new(pa_mempool *p, pa_memimport_release_cb_t cb, void assert(cb); i = pa_xnew(pa_memimport, 1); + i->mutex = pa_mutex_new(0); i->pool = p; i->segments = pa_hashmap_new(NULL, NULL); i->blocks = pa_hashmap_new(NULL, NULL); i->release_cb = cb; i->userdata = userdata; - + + pa_mutex_lock(p->mutex); PA_LLIST_PREPEND(pa_memimport, p->imports, i); + pa_mutex_unlock(p->mutex); + return i; } static void memexport_revoke_blocks(pa_memexport *e, pa_memimport *i); +/* Should be called locked */ static pa_memimport_segment* segment_attach(pa_memimport *i, uint32_t shm_id) { pa_memimport_segment* seg; @@ -562,6 +768,7 @@ static pa_memimport_segment* segment_attach(pa_memimport *i, uint32_t shm_id) { return seg; } +/* Should be called locked */ static void segment_detach(pa_memimport_segment *seg) { assert(seg); @@ -570,51 +777,68 @@ static void segment_detach(pa_memimport_segment *seg) { pa_xfree(seg); } +/* Self-locked. Not multiple-caller safe */ void pa_memimport_free(pa_memimport *i) { pa_memexport *e; pa_memblock *b; assert(i); - /* If we've exported this block further we need to revoke that export */ - for (e = i->pool->exports; e; e = e->next) - memexport_revoke_blocks(e, i); + pa_mutex_lock(i->mutex); while ((b = pa_hashmap_get_first(i->blocks))) memblock_replace_import(b); assert(pa_hashmap_size(i->segments) == 0); + + pa_mutex_unlock(i->mutex); + + pa_mutex_lock(i->pool->mutex); + + /* If we've exported this block further we need to revoke that export */ + for (e = i->pool->exports; e; e = e->next) + memexport_revoke_blocks(e, i); + PA_LLIST_REMOVE(pa_memimport, i->pool->imports, i); + + pa_mutex_unlock(i->pool->mutex); + pa_hashmap_free(i->blocks, NULL, NULL); pa_hashmap_free(i->segments, NULL, NULL); + + pa_mutex_free(i->mutex); - PA_LLIST_REMOVE(pa_memimport, i->pool->imports, i); pa_xfree(i); } +/* Self-locked */ pa_memblock* pa_memimport_get(pa_memimport *i, uint32_t block_id, uint32_t shm_id, size_t offset, size_t size) { - pa_memblock *b; + pa_memblock *b = NULL; pa_memimport_segment *seg; assert(i); + pa_mutex_lock(i->mutex); + if (pa_hashmap_size(i->blocks) >= PA_MEMIMPORT_SLOTS_MAX) - return NULL; + goto finish; if (!(seg = pa_hashmap_get(i->segments, PA_UINT32_TO_PTR(shm_id)))) if (!(seg = segment_attach(i, shm_id))) - return NULL; + goto finish; if (offset+size > seg->memory.size) - return NULL; - + goto finish; + b = pa_xnew(pa_memblock, 1); + PA_REFCNT_INIT(b); + b->pool = i->pool; b->type = PA_MEMBLOCK_IMPORTED; b->read_only = 1; - PA_REFCNT_INIT(b); + pa_atomic_ptr_store(&b->data, (uint8_t*) seg->memory.ptr + offset); b->length = size; - b->data = (uint8_t*) seg->memory.ptr + offset; - b->pool = i->pool; + pa_atomic_store(&b->n_acquired, 0); + pa_atomic_store(&b->please_signal, 0); b->per_type.imported.id = block_id; b->per_type.imported.segment = seg; @@ -622,7 +846,11 @@ pa_memblock* pa_memimport_get(pa_memimport *i, uint32_t block_id, uint32_t shm_i seg->n_blocks++; - stat_add(b); +finish: + pa_mutex_unlock(i->mutex); + + if (b) + stat_add(b); return b; } @@ -631,10 +859,15 @@ int pa_memimport_process_revoke(pa_memimport *i, uint32_t id) { pa_memblock *b; assert(i); + pa_mutex_lock(i->mutex); + if (!(b = pa_hashmap_get(i->blocks, PA_UINT32_TO_PTR(id)))) return -1; memblock_replace_import(b); + + pa_mutex_unlock(i->mutex); + return 0; } @@ -649,58 +882,84 @@ pa_memexport* pa_memexport_new(pa_mempool *p, pa_memexport_revoke_cb_t cb, void return NULL; e = pa_xnew(pa_memexport, 1); + e->mutex = pa_mutex_new(1); e->pool = p; PA_LLIST_HEAD_INIT(struct memexport_slot, e->free_slots); PA_LLIST_HEAD_INIT(struct memexport_slot, e->used_slots); e->n_init = 0; e->revoke_cb = cb; e->userdata = userdata; - + + pa_mutex_lock(p->mutex); PA_LLIST_PREPEND(pa_memexport, p->exports, e); + pa_mutex_unlock(p->mutex); + return e; } void pa_memexport_free(pa_memexport *e) { assert(e); + pa_mutex_lock(e->mutex); while (e->used_slots) pa_memexport_process_release(e, e->used_slots - e->slots); + pa_mutex_unlock(e->mutex); + pa_mutex_lock(e->pool->mutex); PA_LLIST_REMOVE(pa_memexport, e->pool->exports, e); + pa_mutex_unlock(e->pool->mutex); + pa_xfree(e); } +/* Self-locked */ int pa_memexport_process_release(pa_memexport *e, uint32_t id) { + pa_memblock *b; + assert(e); + pa_mutex_lock(e->mutex); + if (id >= e->n_init) - return -1; + goto fail; if (!e->slots[id].block) - return -1; + goto fail; -/* pa_log("Processing release for %u", id); */ - - assert(AO_load_acquire_read(&e->pool->stat.n_exported) > 0); - assert(AO_load_acquire_read(&e->pool->stat.exported_size) >= (AO_t) e->slots[id].block->length); - - AO_fetch_and_sub1_release_write(&e->pool->stat.n_exported); - AO_fetch_and_add_release_write(&e->pool->stat.exported_size, (AO_t) -e->slots[id].block->length); - - pa_memblock_unref(e->slots[id].block); + b = e->slots[id].block; e->slots[id].block = NULL; PA_LLIST_REMOVE(struct memexport_slot, e->used_slots, &e->slots[id]); PA_LLIST_PREPEND(struct memexport_slot, e->free_slots, &e->slots[id]); + pa_mutex_unlock(e->mutex); + +/* pa_log("Processing release for %u", id); */ + + assert(pa_atomic_load(&e->pool->stat.n_exported) > 0); + assert(pa_atomic_load(&e->pool->stat.exported_size) >= (int) b->length); + + pa_atomic_dec(&e->pool->stat.n_exported); + pa_atomic_add(&e->pool->stat.exported_size, (int) -b->length); + + pa_memblock_unref(b); + return 0; + +fail: + pa_mutex_unlock(e->mutex); + + return -1; } +/* Self-locked */ static void memexport_revoke_blocks(pa_memexport *e, pa_memimport *i) { struct memexport_slot *slot, *next; assert(e); assert(i); + pa_mutex_lock(e->mutex); + for (slot = e->used_slots; slot; slot = next) { uint32_t idx; next = slot->next; @@ -713,8 +972,11 @@ static void memexport_revoke_blocks(pa_memexport *e, pa_memimport *i) { e->revoke_cb(e, idx, e->userdata); pa_memexport_process_release(e, idx); } + + pa_mutex_unlock(e->mutex); } +/* No lock necessary */ static pa_memblock *memblock_shared_copy(pa_mempool *p, pa_memblock *b) { pa_memblock *n; @@ -731,13 +993,16 @@ static pa_memblock *memblock_shared_copy(pa_mempool *p, pa_memblock *b) { if (!(n = pa_memblock_new_pool(p, b->length))) return NULL; - memcpy(n->data, b->data, b->length); + memcpy(pa_atomic_ptr_load(&n->data), pa_atomic_ptr_load(&b->data), b->length); return n; } +/* Self-locked */ int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32_t *shm_id, size_t *offset, size_t * size) { pa_shm *memory; struct memexport_slot *slot; + void *data; + size_t length; assert(e); assert(b); @@ -750,12 +1015,15 @@ int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32 if (!(b = memblock_shared_copy(e->pool, b))) return -1; + pa_mutex_lock(e->mutex); + if (e->free_slots) { slot = e->free_slots; PA_LLIST_REMOVE(struct memexport_slot, e->free_slots, slot); - } else if (e->n_init < PA_MEMEXPORT_SLOTS_MAX) { + } else if (e->n_init < PA_MEMEXPORT_SLOTS_MAX) slot = &e->slots[e->n_init++]; - } else { + else { + pa_mutex_unlock(e->mutex); pa_memblock_unref(b); return -1; } @@ -764,8 +1032,11 @@ int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32 slot->block = b; *block_id = slot - e->slots; + pa_mutex_unlock(e->mutex); /* pa_log("Got block id %u", *block_id); */ + data = pa_memblock_acquire(b); + if (b->type == PA_MEMBLOCK_IMPORTED) { assert(b->per_type.imported.segment); memory = &b->per_type.imported.segment->memory; @@ -775,15 +1046,17 @@ int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32 memory = &b->pool->memory; } - assert(b->data >= memory->ptr); - assert((uint8_t*) b->data + b->length <= (uint8_t*) memory->ptr + memory->size); + assert(data >= memory->ptr); + assert((uint8_t*) data + length <= (uint8_t*) memory->ptr + memory->size); *shm_id = memory->id; - *offset = (uint8_t*) b->data - (uint8_t*) memory->ptr; - *size = b->length; + *offset = (uint8_t*) data - (uint8_t*) memory->ptr; + *size = length; - AO_fetch_and_add1_release_write(&e->pool->stat.n_exported); - AO_fetch_and_add_release_write(&e->pool->stat.exported_size, (AO_t) b->length); + pa_memblock_release(b); + + pa_atomic_inc(&e->pool->stat.n_exported); + pa_atomic_add(&e->pool->stat.exported_size, (int) length); return 0; } diff --git a/src/pulsecore/memblock.h b/src/pulsecore/memblock.h index d4f2b7aa..9937818f 100644 --- a/src/pulsecore/memblock.h +++ b/src/pulsecore/memblock.h @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -54,45 +55,25 @@ typedef struct pa_memexport pa_memexport; typedef void (*pa_memimport_release_cb_t)(pa_memimport *i, uint32_t block_id, void *userdata); typedef void (*pa_memexport_revoke_cb_t)(pa_memexport *e, uint32_t block_id, void *userdata); -struct pa_memblock { - pa_memblock_type_t type; - int read_only; /* boolean */ - PA_REFCNT_DECLARE; /* the reference counter */ - size_t length; - void *data; - pa_mempool *pool; - - union { - struct { - void (*free_cb)(void *p); /* If type == PA_MEMBLOCK_USER this points to a function for freeing this memory block */ - } user; - - struct { - uint32_t id; - pa_memimport_segment *segment; - } imported; - } per_type; -}; - /* Please note that updates to this structure are not locked, * i.e. n_allocated might be updated at a point in time where * n_accumulated is not yet. Take these values with a grain of salt, - * threy are here for purely statistical reasons.*/ + * they are here for purely statistical reasons.*/ struct pa_mempool_stat { - AO_t n_allocated; - AO_t n_accumulated; - AO_t n_imported; - AO_t n_exported; - AO_t allocated_size; - AO_t accumulated_size; - AO_t imported_size; - AO_t exported_size; - - AO_t n_too_large_for_pool; - AO_t n_pool_full; - - AO_t n_allocated_by_type[PA_MEMBLOCK_TYPE_MAX]; - AO_t n_accumulated_by_type[PA_MEMBLOCK_TYPE_MAX]; + pa_atomic_int_t n_allocated; + pa_atomic_int_t n_accumulated; + pa_atomic_int_t n_imported; + pa_atomic_int_t n_exported; + pa_atomic_int_t allocated_size; + pa_atomic_int_t accumulated_size; + pa_atomic_int_t imported_size; + pa_atomic_int_t exported_size; + + pa_atomic_int_t n_too_large_for_pool; + pa_atomic_int_t n_pool_full; + + pa_atomic_int_t n_allocated_by_type[PA_MEMBLOCK_TYPE_MAX]; + pa_atomic_int_t n_accumulated_by_type[PA_MEMBLOCK_TYPE_MAX]; }; /* Allocate a new memory block of type PA_MEMBLOCK_MEMPOOL or PA_MEMBLOCK_APPENDED, depending on the size */ @@ -116,9 +97,17 @@ pa_memblock* pa_memblock_ref(pa_memblock*b); /* This special unref function has to be called by the owner of the memory of a static memory block when he wants to release all references to the memory. This causes the memory to be copied and -converted into a PA_MEMBLOCK_DYNAMIC type memory block */ +converted into a pool or malloc'ed memory block. Please note that this +function is not multiple caller safe, i.e. needs to be locked +manually if called from more than one thread at the same time. */ void pa_memblock_unref_fixed(pa_memblock*b); +int pa_memblock_is_read_only(pa_memblock *b); +void* pa_memblock_acquire(pa_memblock *b); +void pa_memblock_release(pa_memblock *b); +size_t pa_memblock_get_length(pa_memblock *b); +pa_mempool * pa_memblock_get_pool(pa_memblock *b); + /* The memory block manager */ pa_mempool* pa_mempool_new(int shared); void pa_mempool_free(pa_mempool *p); diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index e6b73fc5..dab44dc3 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -176,7 +176,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { assert(uchunk); assert(uchunk->memblock); assert(uchunk->length > 0); - assert(uchunk->index + uchunk->length <= uchunk->memblock->length); + assert(uchunk->index + uchunk->length <= pa_memblock_get_length(uchunk->memblock)); if (uchunk->length % bq->base) return -1; @@ -360,8 +360,8 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { if (bq->silence) { chunk->memblock = pa_memblock_ref(bq->silence); - if (!length || length > chunk->memblock->length) - length = chunk->memblock->length; + if (!length || length > pa_memblock_get_length(chunk->memblock)) + length = pa_memblock_get_length(chunk->memblock); chunk->length = length; } else { @@ -413,8 +413,8 @@ void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length if (bq->silence) { - if (!l || l > bq->silence->length) - l = bq->silence->length; + if (!l || l > pa_memblock_get_length(bq->silence)) + l = pa_memblock_get_length(bq->silence); } diff --git a/src/pulsecore/memchunk.c b/src/pulsecore/memchunk.c index 1dbad2b9..55c4bfa7 100644 --- a/src/pulsecore/memchunk.c +++ b/src/pulsecore/memchunk.c @@ -35,22 +35,25 @@ void pa_memchunk_make_writable(pa_memchunk *c, size_t min) { pa_memblock *n; size_t l; + void *tdata, *sdata; assert(c); assert(c->memblock); - assert(PA_REFCNT_VALUE(c->memblock) > 0); - if (PA_REFCNT_VALUE(c->memblock) == 1 && - !c->memblock->read_only && - c->memblock->length >= c->index+min) + if (pa_memblock_is_read_only(c->memblock) && + pa_memblock_get_length(c->memblock) >= c->index+min) return; l = c->length; if (l < min) l = min; - n = pa_memblock_new(c->memblock->pool, l); - memcpy(n->data, (uint8_t*) c->memblock->data + c->index, c->length); + n = pa_memblock_new(pa_memblock_get_pool(c->memblock), l); + tdata = pa_memblock_acquire(n); + sdata = pa_memblock_acquire(c->memblock); + memcpy(tdata, (uint8_t*) sdata + c->index, c->length); + pa_memblock_release(n); + pa_memblock_release(c->memblock); pa_memblock_unref(c->memblock); c->memblock = n; c->index = 0; diff --git a/src/pulsecore/play-memchunk.c b/src/pulsecore/play-memchunk.c index cde6a9ee..b711c98c 100644 --- a/src/pulsecore/play-memchunk.c +++ b/src/pulsecore/play-memchunk.c @@ -55,7 +55,7 @@ static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { if (c->length <= 0) return -1; - assert(c->memblock && c->memblock->length); + assert(c->memblock); *chunk = *c; pa_memblock_ref(c->memblock); diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 80aeb27b..65b93eb4 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -891,14 +891,22 @@ static int do_read(struct connection *c) { } } else if (c->state == ESD_CACHING_SAMPLE) { ssize_t r; + void *p; - assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); + assert(c->scache.memchunk.memblock); + assert(c->scache.name); + assert(c->scache.memchunk.index < c->scache.memchunk.length); + + p = pa_memblock_acquire(c->scache.memchunk.memblock); - if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { + if ((r = pa_iochannel_read(c->io, (uint8_t*) p+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { + pa_memblock_release(c->scache.memchunk.memblock); pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } + pa_memblock_release(c->scache.memchunk.memblock); + c->scache.memchunk.index += r; assert(c->scache.memchunk.index <= c->scache.memchunk.length); @@ -925,6 +933,7 @@ static int do_read(struct connection *c) { pa_memchunk chunk; ssize_t r; size_t l; + void *p; assert(c->input_memblockq); @@ -937,7 +946,7 @@ static int do_read(struct connection *c) { l = c->playback.fragment_size; if (c->playback.current_memblock) - if (c->playback.current_memblock->length - c->playback.memblock_index < l) { + if (pa_memblock_get_length(c->playback.current_memblock) - c->playback.memblock_index < l) { pa_memblock_unref(c->playback.current_memblock); c->playback.current_memblock = NULL; c->playback.memblock_index = 0; @@ -945,15 +954,21 @@ static int do_read(struct connection *c) { if (!c->playback.current_memblock) { c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, c->playback.fragment_size*2); - assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); + assert(c->playback.current_memblock); + assert(pa_memblock_get_length(c->playback.current_memblock) >= l); c->playback.memblock_index = 0; } - if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { + p = pa_memblock_acquire(c->playback.current_memblock); + + if ((r = pa_iochannel_read(c->io, (uint8_t*) p+c->playback.memblock_index, l)) <= 0) { + pa_memblock_release(c->playback.current_memblock); pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } - + + pa_memblock_release(c->playback.current_memblock); + chunk.memblock = c->playback.current_memblock; chunk.index = c->playback.memblock_index; chunk.length = r; @@ -990,19 +1005,26 @@ static int do_write(struct connection *c) { } else if (c->state == ESD_STREAMING_DATA && c->source_output) { pa_memchunk chunk; ssize_t r; + void *p; assert(c->output_memblockq); if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) return 0; - assert(chunk.memblock && chunk.length); + assert(chunk.memblock); + assert(chunk.length); + + p = pa_memblock_acquire(chunk.memblock); - if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { + if ((r = pa_iochannel_write(c->io, (uint8_t*) p+chunk.index, chunk.length)) < 0) { + pa_memblock_release(chunk.memblock); pa_memblock_unref(chunk.memblock); pa_log("write(): %s", pa_cstrerror(errno)); return -1; } + pa_memblock_release(chunk.memblock); + pa_memblockq_drop(c->output_memblockq, &chunk, r); pa_memblock_unref(chunk.memblock); diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 38c024b7..fba611d7 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -2274,6 +2274,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o } else { struct upload_stream *u = (struct upload_stream*) stream; size_t l; + assert(u->type == UPLOAD_STREAM); if (!u->memchunk.memblock) { @@ -2293,9 +2294,18 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o if (l > chunk->length) l = chunk->length; + if (l > 0) { - memcpy((uint8_t*) u->memchunk.memblock->data + u->memchunk.index + u->memchunk.length, - (uint8_t*) chunk->memblock->data+chunk->index, l); + void *src, *dst; + dst = pa_memblock_acquire(u->memchunk.memblock); + src = pa_memblock_acquire(chunk->memblock); + + memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length, + (uint8_t*) src+chunk->index, l); + + pa_memblock_release(u->memchunk.memblock); + pa_memblock_release(chunk->memblock); + u->memchunk.length += l; u->length -= l; } diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c index 6bfba875..bf203e42 100644 --- a/src/pulsecore/protocol-simple.c +++ b/src/pulsecore/protocol-simple.c @@ -113,6 +113,7 @@ static int do_read(struct connection *c) { pa_memchunk chunk; ssize_t r; size_t l; + void *p; if (!c->sink_input || !(l = pa_memblockq_missing(c->input_memblockq))) return 0; @@ -121,7 +122,7 @@ static int do_read(struct connection *c) { l = c->playback.fragment_size; if (c->playback.current_memblock) - if (c->playback.current_memblock->length - c->playback.memblock_index < l) { + if (pa_memblock_get_length(c->playback.current_memblock) - c->playback.memblock_index < l) { pa_memblock_unref(c->playback.current_memblock); c->playback.current_memblock = NULL; c->playback.memblock_index = 0; @@ -129,15 +130,20 @@ static int do_read(struct connection *c) { if (!c->playback.current_memblock) { c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, c->playback.fragment_size*2); - assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); + assert(c->playback.current_memblock); + assert(pa_memblock_get_length(c->playback.current_memblock) >= l); c->playback.memblock_index = 0; } + + p = pa_memblock_acquire(c->playback.current_memblock); - if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { + if ((r = pa_iochannel_read(c->io, (uint8_t*) p + c->playback.memblock_index, l)) <= 0) { + pa_memblock_release(c->playback.current_memblock); pa_log_debug("read(): %s", r == 0 ? "EOF" : pa_cstrerror(errno)); return -1; } + pa_memblock_release(c->playback.current_memblock); chunk.memblock = c->playback.current_memblock; chunk.index = c->playback.memblock_index; chunk.length = r; @@ -156,7 +162,8 @@ static int do_read(struct connection *c) { static int do_write(struct connection *c) { pa_memchunk chunk; ssize_t r; - + void *p; + if (!c->source_output) return 0; @@ -165,12 +172,17 @@ static int do_write(struct connection *c) { return 0; assert(chunk.memblock && chunk.length); + + p = pa_memblock_acquire(chunk.memblock); - if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { + if ((r = pa_iochannel_write(c->io, (uint8_t*) p+chunk.index, chunk.length)) < 0) { + pa_memblock_release(chunk.memblock); pa_memblock_unref(chunk.memblock); pa_log("write(): %s", pa_cstrerror(errno)); return -1; } + + pa_memblock_release(chunk.memblock); pa_memblockq_drop(c->output_memblockq, &chunk, r); pa_memblock_unref(chunk.memblock); diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index 566fb060..33963796 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -48,6 +48,7 @@ #include #include #include +#include #include "pstream.h" @@ -113,10 +114,11 @@ struct pa_pstream { PA_REFCNT_DECLARE; pa_mainloop_api *mainloop; - pa_defer_event *defer_event; pa_iochannel *io; + pa_queue *send_queue; - pa_mutex *mutex; + pa_mutex *mutex; /* only for access to the queue */ + pa_anotify *anotify; int dead; @@ -126,6 +128,7 @@ struct pa_pstream { uint32_t shm_info[PA_PSTREAM_SHM_MAX]; void *data; size_t index; + pa_memchunk memchunk; } write; struct { @@ -170,10 +173,6 @@ static void do_something(pa_pstream *p) { pa_pstream_ref(p); - pa_mutex_lock(p->mutex); - - p->mainloop->defer_enable(p->defer_event, 0); - if (!p->dead && pa_iochannel_is_readable(p->io)) { if (do_read(p) < 0) goto fail; @@ -185,8 +184,6 @@ static void do_something(pa_pstream *p) { goto fail; } - pa_mutex_unlock(p->mutex); - pa_pstream_unref(p); return; @@ -197,8 +194,6 @@ fail: if (p->die_callback) p->die_callback(p, p->die_callback_userdata); - pa_mutex_unlock(p->mutex); - pa_pstream_unref(p); } @@ -211,13 +206,10 @@ static void io_callback(pa_iochannel*io, void *userdata) { do_something(p); } -static void defer_callback(pa_mainloop_api *m, pa_defer_event *e, void*userdata) { +static void anotify_callback(uint8_t event, void *userdata) { pa_pstream *p = userdata; assert(p); - assert(p->defer_event == e); - assert(p->mainloop == m); - do_something(p); } @@ -237,16 +229,16 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *poo p->dead = 0; p->mutex = pa_mutex_new(1); + p->anotify = pa_anotify_new(m, anotify_callback, p); p->mainloop = m; - p->defer_event = m->defer_new(m, defer_callback, p); - m->defer_enable(p->defer_event, 0); p->send_queue = pa_queue_new(); assert(p->send_queue); p->write.current = NULL; p->write.index = 0; + pa_memchunk_reset(&p->write.memchunk); p->read.memblock = NULL; p->read.packet = NULL; p->read.index = 0; @@ -309,9 +301,15 @@ static void pstream_free(pa_pstream *p) { if (p->read.packet) pa_packet_unref(p->read.packet); + if (p->write.memchunk.memblock) + pa_memblock_unref(p->write.memchunk.memblock); + if (p->mutex) pa_mutex_free(p->mutex); + if (p->anotify) + pa_anotify_free(p->anotify); + pa_xfree(p); } @@ -322,11 +320,6 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *cre assert(PA_REFCNT_VALUE(p) > 0); assert(packet); - pa_mutex_lock(p->mutex); - - if (p->dead) - goto finish; - i = pa_xnew(struct item_info, 1); i->type = PA_PSTREAM_ITEM_PACKET; i->packet = pa_packet_ref(packet); @@ -336,12 +329,11 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *cre i->creds = *creds; #endif + pa_mutex_lock(p->mutex); pa_queue_push(p->send_queue, i); - p->mainloop->defer_enable(p->defer_event, 1); - -finish: - pa_mutex_unlock(p->mutex); + + pa_anotify_signal(p->anotify, 0); } void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek_mode, const pa_memchunk *chunk) { @@ -352,12 +344,6 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa assert(channel != (uint32_t) -1); assert(chunk); - pa_mutex_lock(p->mutex); - - if (p->dead) - goto finish; - - length = chunk->length; idx = 0; while (length > 0) { @@ -379,17 +365,15 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa i->with_creds = 0; #endif + pa_mutex_lock(p->mutex); pa_queue_push(p->send_queue, i); + pa_mutex_unlock(p->mutex); idx += n; length -= n; } - - p->mainloop->defer_enable(p->defer_event, 1); -finish: - - pa_mutex_unlock(p->mutex); + pa_anotify_signal(p->anotify, 0); } static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userdata) { @@ -399,11 +383,6 @@ static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userd assert(p); assert(PA_REFCNT_VALUE(p) > 0); - pa_mutex_lock(p->mutex); - - if (p->dead) - goto finish; - /* pa_log("Releasing block %u", block_id); */ item = pa_xnew(struct item_info, 1); @@ -413,12 +392,11 @@ static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userd item->with_creds = 0; #endif + pa_mutex_lock(p->mutex); pa_queue_push(p->send_queue, item); - p->mainloop->defer_enable(p->defer_event, 1); - -finish: - pa_mutex_unlock(p->mutex); + + pa_anotify_signal(p->anotify, 0); } static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userdata) { @@ -428,11 +406,6 @@ static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userda assert(p); assert(PA_REFCNT_VALUE(p) > 0); - pa_mutex_lock(p->mutex); - - if (p->dead) - goto finish; - /* pa_log("Revoking block %u", block_id); */ item = pa_xnew(struct item_info, 1); @@ -442,23 +415,27 @@ static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userda item->with_creds = 0; #endif + pa_mutex_lock(p->mutex); pa_queue_push(p->send_queue, item); - p->mainloop->defer_enable(p->defer_event, 1); - -finish: - pa_mutex_unlock(p->mutex); + + pa_anotify_signal(p->anotify, 0); } static void prepare_next_write_item(pa_pstream *p) { assert(p); assert(PA_REFCNT_VALUE(p) > 0); - if (!(p->write.current = pa_queue_pop(p->send_queue))) + pa_mutex_lock(p->mutex); + p->write.current = pa_queue_pop(p->send_queue); + pa_mutex_unlock(p->mutex); + + if (!p->write.current) return; p->write.index = 0; p->write.data = NULL; + pa_memchunk_reset(&p->write.memchunk); p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = 0; p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl((uint32_t) -1); @@ -525,7 +502,9 @@ static void prepare_next_write_item(pa_pstream *p) { if (send_payload) { p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length); - p->write.data = (uint8_t*) p->write.current->chunk.memblock->data + p->write.current->chunk.index; + p->write.memchunk = p->write.current->chunk; + pa_memblock_ref(p->write.memchunk.memblock); + p->write.data = NULL; } p->write.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS] = htonl(flags); @@ -541,6 +520,7 @@ static int do_write(pa_pstream *p) { void *d; size_t l; ssize_t r; + pa_memblock *release_memblock = NULL; assert(p); assert(PA_REFCNT_VALUE(p) > 0); @@ -555,9 +535,16 @@ static int do_write(pa_pstream *p) { d = (uint8_t*) p->write.descriptor + p->write.index; l = PA_PSTREAM_DESCRIPTOR_SIZE - p->write.index; } else { - assert(p->write.data); + assert(p->write.data || p->write.memchunk.memblock); + + if (p->write.data) + d = p->write.data; + else { + d = (uint8_t*) pa_memblock_acquire(p->write.memchunk.memblock) + p->write.memchunk.index; + release_memblock = p->write.memchunk.memblock; + } - d = (uint8_t*) p->write.data + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE; + d = (uint8_t*) d + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE; l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE); } @@ -567,14 +554,17 @@ static int do_write(pa_pstream *p) { if (p->send_creds_now) { if ((r = pa_iochannel_write_with_creds(p->io, d, l, &p->write_creds)) < 0) - return -1; + goto fail; p->send_creds_now = 0; } else #endif if ((r = pa_iochannel_write(p->io, d, l)) < 0) - return -1; + goto fail; + + if (release_memblock) + pa_memblock_release(release_memblock); p->write.index += r; @@ -588,12 +578,20 @@ static int do_write(pa_pstream *p) { } return 0; + +fail: + + if (release_memblock) + pa_memblock_release(release_memblock); + + return -1; } static int do_read(pa_pstream *p) { void *d; size_t l; ssize_t r; + pa_memblock *release_memblock = NULL; assert(p); assert(PA_REFCNT_VALUE(p) > 0); @@ -602,8 +600,16 @@ static int do_read(pa_pstream *p) { d = (uint8_t*) p->read.descriptor + p->read.index; l = PA_PSTREAM_DESCRIPTOR_SIZE - p->read.index; } else { - assert(p->read.data); - d = (uint8_t*) p->read.data + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE; + assert(p->read.data || p->read.memblock); + + if (p->read.data) + d = p->read.data; + else { + d = pa_memblock_acquire(p->read.memblock); + release_memblock = p->read.memblock; + } + + d = (uint8_t*) d + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE; l = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE); } @@ -612,14 +618,17 @@ static int do_read(pa_pstream *p) { int b = 0; if ((r = pa_iochannel_read_with_creds(p->io, d, l, &p->read_creds, &b)) <= 0) - return -1; + goto fail; p->read_creds_valid = p->read_creds_valid || b; } #else if ((r = pa_iochannel_read(p->io, d, l)) <= 0) - return -1; + goto fail; #endif + + if (release_memblock) + pa_memblock_release(release_memblock); p->read.index += r; @@ -701,7 +710,7 @@ static int do_read(pa_pstream *p) { /* Frame is a memblock frame */ p->read.memblock = pa_memblock_new(p->mempool, length); - p->read.data = p->read.memblock->data; + p->read.data = NULL; } else { pa_log_warn("Recieved memblock frame with invalid flags value."); @@ -788,7 +797,7 @@ static int do_read(pa_pstream *p) { chunk.memblock = b; chunk.index = 0; - chunk.length = b->length; + chunk.length = pa_memblock_get_length(b); offset = (int64_t) ( (((uint64_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])) << 32) | @@ -816,52 +825,51 @@ frame_done: p->read.memblock = NULL; p->read.packet = NULL; p->read.index = 0; + p->read.data = NULL; #ifdef HAVE_CREDS p->read_creds_valid = 0; #endif return 0; + +fail: + if (release_memblock) + pa_memblock_release(release_memblock); + + return -1; } void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) { assert(p); assert(PA_REFCNT_VALUE(p) > 0); - pa_mutex_lock(p->mutex); p->die_callback = cb; p->die_callback_userdata = userdata; - pa_mutex_unlock(p->mutex); } void pa_pstream_set_drain_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) { assert(p); assert(PA_REFCNT_VALUE(p) > 0); - pa_mutex_lock(p->mutex); p->drain_callback = cb; p->drain_callback_userdata = userdata; - pa_mutex_unlock(p->mutex); } void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata) { assert(p); assert(PA_REFCNT_VALUE(p) > 0); - pa_mutex_lock(p->mutex); p->recieve_packet_callback = cb; p->recieve_packet_callback_userdata = userdata; - pa_mutex_unlock(p->mutex); } void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, pa_pstream_memblock_cb_t cb, void *userdata) { assert(p); assert(PA_REFCNT_VALUE(p) > 0); - pa_mutex_lock(p->mutex); p->recieve_memblock_callback = cb; p->recieve_memblock_callback_userdata = userdata; - pa_mutex_unlock(p->mutex); } int pa_pstream_is_pending(pa_pstream *p) { @@ -901,8 +909,6 @@ pa_pstream* pa_pstream_ref(pa_pstream*p) { void pa_pstream_close(pa_pstream *p) { assert(p); - pa_mutex_lock(p->mutex); - p->dead = 1; if (p->import) { @@ -920,25 +926,16 @@ void pa_pstream_close(pa_pstream *p) { p->io = NULL; } - if (p->defer_event) { - p->mainloop->defer_free(p->defer_event); - p->defer_event = NULL; - } - p->die_callback = NULL; p->drain_callback = NULL; p->recieve_packet_callback = NULL; p->recieve_memblock_callback = NULL; - - pa_mutex_unlock(p->mutex); } void pa_pstream_use_shm(pa_pstream *p, int enable) { assert(p); assert(PA_REFCNT_VALUE(p) > 0); - pa_mutex_lock(p->mutex); - p->use_shm = enable; if (enable) { @@ -953,6 +950,4 @@ void pa_pstream_use_shm(pa_pstream *p, int enable) { p->export = NULL; } } - - pa_mutex_unlock(p->mutex); } diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index b0142049..c28c2fb3 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -51,8 +51,7 @@ struct pa_resampler { }; struct impl_libsamplerate { - pa_memblock *buf1_block, *buf2_block, *buf3_block, *buf4_block; - float* buf1, *buf2, *buf3, *buf4; + pa_memchunk buf1, buf2, buf3, buf4; unsigned buf1_samples, buf2_samples, buf3_samples, buf4_samples; pa_convert_to_float32ne_func_t to_float32ne_func; @@ -224,14 +223,14 @@ static void libsamplerate_free(pa_resampler *r) { if (u->src_state) src_delete(u->src_state); - if (u->buf1_block) - pa_memblock_unref(u->buf1_block); - if (u->buf2_block) - pa_memblock_unref(u->buf2_block); - if (u->buf3_block) - pa_memblock_unref(u->buf3_block); - if (u->buf4_block) - pa_memblock_unref(u->buf4_block); + if (u->buf1.memblock) + pa_memblock_unref(u->buf1.memblock); + if (u->buf2.memblock) + pa_memblock_unref(u->buf2.memblock); + if (u->buf3.memblock) + pa_memblock_unref(u->buf3.memblock); + if (u->buf4.memblock) + pa_memblock_unref(u->buf4.memblock); pa_xfree(u); } @@ -270,64 +269,80 @@ static void calc_map_table(pa_resampler *r) { } } -static float * convert_to_float(pa_resampler *r, void *input, unsigned n_frames) { +static pa_memchunk* convert_to_float(pa_resampler *r, pa_memchunk *input) { struct impl_libsamplerate *u; unsigned n_samples; + void *src, *dst; assert(r); assert(input); + assert(input->memblock); + assert(r->impl_data); u = r->impl_data; /* Convert the incoming sample into floats and place them in buf1 */ - if (!u->to_float32ne_func) + if (!u->to_float32ne_func || !input->length) return input; - n_samples = n_frames * r->i_ss.channels; + n_samples = (input->length / r->i_fz) * r->i_ss.channels; - if (u->buf1_samples < n_samples) { - if (u->buf1_block) - pa_memblock_unref(u->buf1_block); + if (!u->buf1.memblock || u->buf1_samples < n_samples) { + if (u->buf1.memblock) + pa_memblock_unref(u->buf1.memblock); u->buf1_samples = n_samples; - u->buf1_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples); - u->buf1 = u->buf1_block->data; + u->buf1.memblock = pa_memblock_new(r->mempool, u->buf1.length = sizeof(float) * n_samples); + u->buf1.index = 0; } - - u->to_float32ne_func(n_samples, input, u->buf1); - return u->buf1; + src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index; + dst = (uint8_t*) pa_memblock_acquire(u->buf1.memblock); + u->to_float32ne_func(n_samples, src, dst); + pa_memblock_release(input->memblock); + pa_memblock_release(u->buf1.memblock); + + u->buf1.length = sizeof(float) * n_samples; + + return &u->buf1; } -static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) { +static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { struct impl_libsamplerate *u; - unsigned n_samples; + unsigned n_samples, n_frames; int i_skip, o_skip; unsigned oc; + float *src, *dst; assert(r); assert(input); + assert(input->memblock); + assert(r->impl_data); u = r->impl_data; /* Remap channels and place the result int buf2 */ - if (!u->map_required) + if (!u->map_required || !input->length) return input; - n_samples = n_frames * r->o_ss.channels; + n_samples = input->length / sizeof(float); + n_frames = n_samples / r->o_ss.channels; - if (u->buf2_samples < n_samples) { - if (u->buf2_block) - pa_memblock_unref(u->buf2_block); + if (!u->buf2.memblock || u->buf2_samples < n_samples) { + if (u->buf2.memblock) + pa_memblock_unref(u->buf2.memblock); u->buf2_samples = n_samples; - u->buf2_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples); - u->buf2 = u->buf2_block->data; + u->buf2.memblock = pa_memblock_new(r->mempool, u->buf2.length = sizeof(float) * n_samples); + u->buf2.index = 0; } - memset(u->buf2, 0, n_samples * sizeof(float)); + src = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index); + dst = (float*) pa_memblock_acquire(u->buf2.memblock); + + memset(dst, 0, n_samples * sizeof(float)); o_skip = sizeof(float) * r->o_ss.channels; i_skip = sizeof(float) * r->i_ss.channels; @@ -338,49 +353,57 @@ static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) { for (i = 0; i < PA_CHANNELS_MAX && u->map_table[oc][i] >= 0; i++) oil_vectoradd_f32( - u->buf2 + oc, o_skip, - u->buf2 + oc, o_skip, - input + u->map_table[oc][i], i_skip, + dst + oc, o_skip, + dst + oc, o_skip, + src + u->map_table[oc][i], i_skip, n_frames, &one, &one); } - return u->buf2; + pa_memblock_release(input->memblock); + pa_memblock_release(u->buf2.memblock); + + u->buf2.length = n_frames * sizeof(float) * r->o_ss.channels; + + return &u->buf2; } -static float *resample(pa_resampler *r, float *input, unsigned *n_frames) { +static pa_memchunk *resample(pa_resampler *r, pa_memchunk *input) { struct impl_libsamplerate *u; SRC_DATA data; + unsigned in_n_frames, in_n_samples; unsigned out_n_frames, out_n_samples; int ret; assert(r); assert(input); - assert(n_frames); assert(r->impl_data); u = r->impl_data; /* Resample the data and place the result in buf3 */ - if (!u->src_state) + if (!u->src_state || !input->length) return input; - out_n_frames = (*n_frames*r->o_ss.rate/r->i_ss.rate)+1024; + in_n_samples = input->length / sizeof(float); + in_n_frames = in_n_samples * r->o_ss.channels; + + out_n_frames = (in_n_frames*r->o_ss.rate/r->i_ss.rate)+1024; out_n_samples = out_n_frames * r->o_ss.channels; - if (u->buf3_samples < out_n_samples) { - if (u->buf3_block) - pa_memblock_unref(u->buf3_block); + if (!u->buf3.memblock || u->buf3_samples < out_n_samples) { + if (u->buf3.memblock) + pa_memblock_unref(u->buf3.memblock); u->buf3_samples = out_n_samples; - u->buf3_block = pa_memblock_new(r->mempool, sizeof(float) * out_n_samples); - u->buf3 = u->buf3_block->data; + u->buf3.memblock = pa_memblock_new(r->mempool, u->buf3.length = sizeof(float) * out_n_samples); + u->buf3.index = 0; } - data.data_in = input; - data.input_frames = *n_frames; + data.data_in = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index); + data.input_frames = in_n_frames; - data.data_out = u->buf3; + data.data_out = (float*) pa_memblock_acquire(u->buf3.memblock); data.output_frames = out_n_frames; data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate; @@ -388,16 +411,20 @@ static float *resample(pa_resampler *r, float *input, unsigned *n_frames) { ret = src_process(u->src_state, &data); assert(ret == 0); - assert((unsigned) data.input_frames_used == *n_frames); + assert((unsigned) data.input_frames_used == in_n_frames); - *n_frames = data.output_frames_gen; + pa_memblock_release(input->memblock); + pa_memblock_release(u->buf3.memblock); + + u->buf3.length = data.output_frames_gen * sizeof(float) * r->o_ss.channels; - return u->buf3; + return &u->buf3; } -static void *convert_from_float(pa_resampler *r, float *input, unsigned n_frames) { +static pa_memchunk *convert_from_float(pa_resampler *r, pa_memchunk *input) { struct impl_libsamplerate *u; - unsigned n_samples; + unsigned n_samples, n_frames; + void *src, *dst; assert(r); assert(input); @@ -406,30 +433,35 @@ static void *convert_from_float(pa_resampler *r, float *input, unsigned n_frames /* Convert the data into the correct sample type and place the result in buf4 */ - if (!u->from_float32ne_func) + if (!u->from_float32ne_func || !input->length) return input; - + + n_frames = input->length / sizeof(float) / r->o_ss.channels; n_samples = n_frames * r->o_ss.channels; if (u->buf4_samples < n_samples) { - if (u->buf4_block) - pa_memblock_unref(u->buf4_block); + if (u->buf4.memblock) + pa_memblock_unref(u->buf4.memblock); u->buf4_samples = n_samples; - u->buf4_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples); - u->buf4 = u->buf4_block->data; + u->buf4.memblock = pa_memblock_new(r->mempool, u->buf4.length = r->o_fz * n_frames); + u->buf4.index = 0; } - - u->from_float32ne_func(n_samples, input, u->buf4); - return u->buf4; + src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->length; + dst = pa_memblock_acquire(u->buf4.memblock); + u->from_float32ne_func(n_samples, src, dst); + pa_memblock_release(input->memblock); + pa_memblock_release(u->buf4.memblock); + + u->buf4.length = r->o_fz * n_frames; + + return &u->buf4; } static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { struct impl_libsamplerate *u; - float *buf; - void *input, *output; - unsigned n_frames; + pa_memchunk *buf; assert(r); assert(in); @@ -441,55 +473,23 @@ static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchun u = r->impl_data; - input = ((uint8_t*) in->memblock->data + in->index); - n_frames = in->length / r->i_fz; - assert(n_frames > 0); - - buf = convert_to_float(r, input, n_frames); - buf = remap_channels(r, buf, n_frames); - buf = resample(r, buf, &n_frames); - - if (n_frames) { - output = convert_from_float(r, buf, n_frames); - - if (output == input) { - /* Mm, no adjustment has been necessary, so let's return the original block */ - out->memblock = pa_memblock_ref(in->memblock); - out->index = in->index; - out->length = in->length; - } else { - out->length = n_frames * r->o_fz; - out->index = 0; - out->memblock = NULL; - - if (output == u->buf1) { - u->buf1 = NULL; - u->buf1_samples = 0; - out->memblock = u->buf1_block; - u->buf1_block = NULL; - } else if (output == u->buf2) { - u->buf2 = NULL; - u->buf2_samples = 0; - out->memblock = u->buf2_block; - u->buf2_block = NULL; - } else if (output == u->buf3) { - u->buf3 = NULL; - u->buf3_samples = 0; - out->memblock = u->buf3_block; - u->buf3_block = NULL; - } else if (output == u->buf4) { - u->buf4 = NULL; - u->buf4_samples = 0; - out->memblock = u->buf4_block; - u->buf4_block = NULL; - } - - assert(out->memblock); - } - } else { - out->memblock = NULL; - out->index = out->length = 0; - } + buf = convert_to_float(r, (pa_memchunk*) in); + buf = remap_channels(r, buf); + buf = resample(r, buf); + + if (buf->length) { + buf = convert_from_float(r, buf); + *out = *buf; + + if (buf == in) + pa_memblock_ref(buf->memblock); + else + pa_memchunk_reset(buf); + } else + pa_memchunk_reset(out); + + pa_memblock_release(in->memblock); + } static void libsamplerate_update_input_rate(pa_resampler *r, uint32_t rate) { @@ -516,8 +516,10 @@ static int libsamplerate_init(pa_resampler *r) { r->impl_data = u = pa_xnew(struct impl_libsamplerate, 1); - u->buf1 = u->buf2 = u->buf3 = u->buf4 = NULL; - u->buf1_block = u->buf2_block = u->buf3_block = u->buf4_block = NULL; + pa_memchunk_reset(&u->buf1); + pa_memchunk_reset(&u->buf2); + pa_memchunk_reset(&u->buf3); + pa_memchunk_reset(&u->buf4); u->buf1_samples = u->buf2_samples = u->buf3_samples = u->buf4_samples = 0; if (r->i_ss.format == PA_SAMPLE_FLOAT32NE) @@ -578,12 +580,16 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out /* Do real resampling */ size_t l; unsigned o_index; + void *src, *dst; /* The length of the new memory block rounded up */ l = ((((n_frames+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz; out->index = 0; out->memblock = pa_memblock_new(r->mempool, l); + + src = (uint8_t*) pa_memblock_acquire(in->memblock) + in->index; + dst = pa_memblock_acquire(out->memblock); for (o_index = 0;; o_index++, u->o_counter++) { unsigned j; @@ -594,13 +600,16 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out if (j >= n_frames) break; - assert(o_index*fz < out->memblock->length); + assert(o_index*fz < pa_memblock_get_length(out->memblock)); - memcpy((uint8_t*) out->memblock->data + fz*o_index, - (uint8_t*) in->memblock->data + in->index + fz*j, fz); + memcpy((uint8_t*) dst + fz*o_index, + (uint8_t*) src + fz*j, fz); } - + + pa_memblock_release(in->memblock); + pa_memblock_release(out->memblock); + out->length = o_index*fz; } diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index d902b4b5..52023d31 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -46,15 +46,27 @@ pa_memblock *pa_silence_memblock_new(pa_mempool *pool, const pa_sample_spec *spe } pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) { - assert(b && b->data && spec); - pa_silence_memory(b->data, b->length, spec); + void *data; + + assert(b); + assert(spec); + + data = pa_memblock_acquire(b); + pa_silence_memory(data, pa_memblock_get_length(b), spec); + pa_memblock_release(b); return b; } void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) { - assert(c && c->memblock && c->memblock->data && spec && c->length); + void *data; + + assert(c); + assert(c->memblock); + assert(spec); - pa_silence_memory((uint8_t*) c->memblock->data+c->index, c->length, spec); + data = pa_memblock_acquire(c->memblock); + pa_silence_memory((uint8_t*) data+c->index, c->length, spec); + pa_memblock_release(c->memblock); } void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { @@ -82,26 +94,38 @@ void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { } size_t pa_mix( - const pa_mix_info streams[], - unsigned nstreams, - void *data, - size_t length, - const pa_sample_spec *spec, - const pa_cvolume *volume, - int mute) { + pa_mix_info streams[], + unsigned nstreams, + void *data, + size_t length, + const pa_sample_spec *spec, + const pa_cvolume *volume, + int mute) { + + pa_cvolume full_volume; + size_t d = 0; + unsigned k; - assert(streams && data && length && spec); + assert(streams); + assert(data); + assert(length); + assert(spec); + if (!volume) + volume = pa_cvolume_reset(&full_volume, spec->channels); + + for (k = 0; k < nstreams; k++) + streams[k].internal = pa_memblock_acquire(streams[k].chunk.memblock); + switch (spec->format) { case PA_SAMPLE_S16NE:{ - size_t d; unsigned channel = 0; for (d = 0;; d += sizeof(int16_t)) { int32_t sum = 0; if (d >= length) - return d; + goto finish; if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { unsigned i; @@ -111,12 +135,12 @@ size_t pa_mix( pa_volume_t cvolume = streams[i].volume.values[channel]; if (d >= streams[i].chunk.length) - return d; + goto finish; if (cvolume == PA_VOLUME_MUTED) v = 0; else { - v = *((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); + v = *((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d)); if (cvolume != PA_VOLUME_NORM) v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); @@ -139,17 +163,18 @@ size_t pa_mix( if (++channel >= spec->channels) channel = 0; } + + break; } case PA_SAMPLE_S16RE:{ - size_t d; unsigned channel = 0; for (d = 0;; d += sizeof(int16_t)) { int32_t sum = 0; if (d >= length) - return d; + goto finish; if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { unsigned i; @@ -159,12 +184,12 @@ size_t pa_mix( pa_volume_t cvolume = streams[i].volume.values[channel]; if (d >= streams[i].chunk.length) - return d; + goto finish; if (cvolume == PA_VOLUME_MUTED) v = 0; else { - v = INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d))); + v = INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d))); if (cvolume != PA_VOLUME_NORM) v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); @@ -187,17 +212,18 @@ size_t pa_mix( if (++channel >= spec->channels) channel = 0; } + + break; } case PA_SAMPLE_U8: { - size_t d; unsigned channel = 0; for (d = 0;; d ++) { int32_t sum = 0; if (d >= length) - return d; + goto finish; if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { unsigned i; @@ -207,12 +233,12 @@ size_t pa_mix( pa_volume_t cvolume = streams[i].volume.values[channel]; if (d >= streams[i].chunk.length) - return d; + goto finish; if (cvolume == PA_VOLUME_MUTED) v = 0; else { - v = (int32_t) *((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d) - 0x80; + v = (int32_t) *((uint8_t*) streams[i].internal + streams[i].chunk.index + d) - 0x80; if (cvolume != PA_VOLUME_NORM) v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); @@ -235,17 +261,18 @@ size_t pa_mix( if (++channel >= spec->channels) channel = 0; } + + break; } case PA_SAMPLE_FLOAT32NE: { - size_t d; unsigned channel = 0; for (d = 0;; d += sizeof(float)) { float sum = 0; if (d >= length) - return d; + goto finish; if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { unsigned i; @@ -255,12 +282,12 @@ size_t pa_mix( pa_volume_t cvolume = streams[i].volume.values[channel]; if (d >= streams[i].chunk.length) - return d; + goto finish; if (cvolume == PA_VOLUME_MUTED) v = 0; else { - v = *((float*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); + v = *((float*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d)); if (cvolume != PA_VOLUME_NORM) v *= pa_sw_volume_to_linear(cvolume); @@ -279,17 +306,34 @@ size_t pa_mix( if (++channel >= spec->channels) channel = 0; } + + break; } default: pa_log_error("ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format)); abort(); } + +finish: + + for (k = 0; k < nstreams; k++) + pa_memblock_release(streams[k].chunk.memblock); + + return d; } -void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvolume *volume) { - assert(c && spec && (c->length % pa_frame_size(spec) == 0)); +void pa_volume_memchunk( + pa_memchunk*c, + const pa_sample_spec *spec, + const pa_cvolume *volume) { + + void *ptr; + + assert(c); + assert(spec); + assert(c->length % pa_frame_size(spec) == 0); assert(volume); if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM)) @@ -300,6 +344,8 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol return; } + ptr = pa_memblock_acquire(c->memblock); + switch (spec->format) { case PA_SAMPLE_S16NE: { int16_t *d; @@ -310,7 +356,7 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol for (channel = 0; channel < spec->channels; channel++) linear[channel] = pa_sw_volume_to_linear(volume->values[channel]); - for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { + for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { int32_t t = (int32_t)(*d); t = (int32_t) (t * linear[channel]); @@ -335,7 +381,7 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol for (channel = 0; channel < spec->channels; channel++) linear[channel] = pa_sw_volume_to_linear(volume->values[channel]); - for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { + for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { int32_t t = (int32_t)(INT16_SWAP(*d)); t = (int32_t) (t * linear[channel]); @@ -357,7 +403,7 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol size_t n; unsigned channel = 0; - for (d = (uint8_t*) c->memblock->data + c->index, n = c->length; n > 0; d++, n--) { + for (d = (uint8_t*) ptr + c->index, n = c->length; n > 0; d++, n--) { int32_t t = (int32_t) *d - 0x80; t = (int32_t) (t * pa_sw_volume_to_linear(volume->values[channel])); @@ -379,7 +425,7 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol unsigned n; unsigned channel; - d = (float*) ((uint8_t*) c->memblock->data + c->index); + d = (float*) ((uint8_t*) ptr + c->index); skip = spec->channels * sizeof(float); n = c->length/sizeof(float)/spec->channels; @@ -402,5 +448,7 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol pa_sample_format_to_string(spec->format)); abort(); } + + pa_memblock_release(c->memblock); } diff --git a/src/pulsecore/sample-util.h b/src/pulsecore/sample-util.h index 6b770792..04c2f6b1 100644 --- a/src/pulsecore/sample-util.h +++ b/src/pulsecore/sample-util.h @@ -36,10 +36,11 @@ typedef struct pa_mix_info { pa_memchunk chunk; pa_cvolume volume; void *userdata; + void *internal; /* Used internally by pa_mix(), should not be initialised when calling pa_mix() */ } pa_mix_info; size_t pa_mix( - const pa_mix_info channels[], + pa_mix_info channels[], unsigned nchannels, void *data, size_t length, diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index d948f0a4..c3cd4952 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -294,6 +294,7 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) assert(i->state == PA_SINK_INPUT_RUNNING || i->state == PA_SINK_INPUT_DRAINED); if (i->move_silence > 0) { + size_t l; /* We have just been moved and shall play some silence for a * while until the old sink has drained its playback buffer */ @@ -303,7 +304,8 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) chunk->memblock = pa_memblock_ref(i->silence_memblock); chunk->index = 0; - chunk->length = i->move_silence < chunk->memblock->length ? i->move_silence : chunk->memblock->length; + l = pa_memblock_get_length(chunk->memblock); + chunk->length = i->move_silence < l ? i->move_silence : l; ret = 0; do_volume_adj_here = 1; @@ -389,10 +391,13 @@ void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t lengt if (i->move_silence > 0) { if (chunk) { + size_t l; + l = pa_memblock_get_length(i->silence_memblock); + if (chunk->memblock != i->silence_memblock || chunk->index != 0 || - (chunk->memblock && (chunk->length != (i->silence_memblock->length < i->move_silence ? i->silence_memblock->length : i->move_silence)))) + (chunk->memblock && (chunk->length != (l < i->move_silence ? l : i->move_silence)))) return; } diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 05695254..04795e39 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -237,7 +237,6 @@ static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) { info->userdata = i; assert(info->chunk.memblock); - assert(info->chunk.memblock->data); assert(info->chunk.length); info++; @@ -305,13 +304,16 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { pa_volume_memchunk(result, &s->sample_spec, &volume); } } else { + void *ptr; result->memblock = pa_memblock_new(s->core->mempool, length); assert(result->memblock); /* pa_log("mixing %i", n); */ - result->length = pa_mix(info, n, result->memblock->data, length, - &s->sample_spec, &s->sw_volume, s->sw_muted); + ptr = pa_memblock_acquire(result->memblock); + result->length = pa_mix(info, n, ptr, length, &s->sample_spec, &s->sw_volume, s->sw_muted); + pa_memblock_release(result->memblock); + result->index = 0; } @@ -332,13 +334,13 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; int r = -1; + void *ptr; assert(s); assert(s->ref >= 1); assert(target); assert(target->memblock); assert(target->length); - assert(target->memblock->data); pa_sink_ref(s); @@ -347,16 +349,23 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { if (n <= 0) goto finish; + ptr = pa_memblock_acquire(target->memblock); + if (n == 1) { + void *src; pa_cvolume volume; if (target->length > info[0].chunk.length) target->length = info[0].chunk.length; + + src = pa_memblock_acquire(info[0].chunk.memblock); - memcpy((uint8_t*) target->memblock->data + target->index, - (uint8_t*) info[0].chunk.memblock->data + info[0].chunk.index, + memcpy((uint8_t*) ptr + target->index, + (uint8_t*) src + info[0].chunk.index, target->length); + pa_memblock_release(info[0].chunk.memblock); + pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); if (s->sw_muted) @@ -365,11 +374,13 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { pa_volume_memchunk(target, &s->sample_spec, &volume); } else target->length = pa_mix(info, n, - (uint8_t*) target->memblock->data + target->index, + (uint8_t*) ptr + target->index, target->length, &s->sample_spec, &s->sw_volume, s->sw_muted); + + pa_memblock_release(target->memblock); inputs_drop(s, info, n, target->length); @@ -393,7 +404,6 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { assert(target); assert(target->memblock); assert(target->length); - assert(target->memblock->data); pa_sink_ref(s); diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c index e6f24a79..d2ffeeed 100644 --- a/src/pulsecore/sound-file-stream.c +++ b/src/pulsecore/sound-file-stream.c @@ -74,21 +74,26 @@ static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { if (!u->memchunk.memblock) { uint32_t fs = pa_frame_size(&i->sample_spec); sf_count_t n; + void *p; u->memchunk.memblock = pa_memblock_new(i->sink->core->mempool, BUF_SIZE); u->memchunk.index = 0; + p = pa_memblock_acquire(u->memchunk.memblock); + if (u->readf_function) { - if ((n = u->readf_function(u->sndfile, u->memchunk.memblock->data, BUF_SIZE/fs)) <= 0) + if ((n = u->readf_function(u->sndfile, p, BUF_SIZE/fs)) <= 0) n = 0; u->memchunk.length = n * fs; } else { - if ((n = sf_read_raw(u->sndfile, u->memchunk.memblock->data, BUF_SIZE)) <= 0) + if ((n = sf_read_raw(u->sndfile, p, BUF_SIZE)) <= 0) n = 0; u->memchunk.length = n; } + + pa_memblock_release(u->memchunk.memblock); if (!u->memchunk.length) { free_userdata(u); diff --git a/src/pulsecore/sound-file.c b/src/pulsecore/sound-file.c index 1bf650e2..c74a1586 100644 --- a/src/pulsecore/sound-file.c +++ b/src/pulsecore/sound-file.c @@ -40,7 +40,11 @@ int pa_sound_file_load(pa_mempool *pool, const char *fname, pa_sample_spec *ss, int ret = -1; size_t l; sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames) = NULL; - assert(fname && ss && chunk); + void *ptr = NULL; + + assert(fname); + assert(ss); + assert(chunk); chunk->memblock = NULL; chunk->index = chunk->length = 0; @@ -97,8 +101,10 @@ int pa_sound_file_load(pa_mempool *pool, const char *fname, pa_sample_spec *ss, chunk->index = 0; chunk->length = l; - if ((readf_function && readf_function(sf, chunk->memblock->data, sfinfo.frames) != sfinfo.frames) || - (!readf_function && sf_read_raw(sf, chunk->memblock->data, l) != l)) { + ptr = pa_memblock_acquire(chunk->memblock); + + if ((readf_function && readf_function(sf, ptr, sfinfo.frames) != sfinfo.frames) || + (!readf_function && sf_read_raw(sf, ptr, l) != l)) { pa_log("Premature file end"); goto finish; } @@ -110,6 +116,9 @@ finish: if (sf) sf_close(sf); + if (ptr) + pa_memblock_release(chunk->memblock); + if (ret != 0 && chunk->memblock) pa_memblock_unref(chunk->memblock); diff --git a/src/tests/flist-test.c b/src/tests/flist-test.c index abc0659d..06d68311 100644 --- a/src/tests/flist-test.c +++ b/src/tests/flist-test.c @@ -54,7 +54,7 @@ static void thread_func(void *data) { int b = 1; while (!quit) { - char *text, *t; + char *text; /* Allocate some memory, if possible take it from the flist */ if (b && (text = pa_flist_pop(flist))) diff --git a/src/tests/mcalign-test.c b/src/tests/mcalign-test.c index 35691698..1584256c 100644 --- a/src/tests/mcalign-test.c +++ b/src/tests/mcalign-test.c @@ -59,24 +59,27 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { c.index = c.length = 0; } - assert(c.index < c.memblock->length); + assert(c.index < pa_memblock_get_length(c.memblock)); - l = c.memblock->length - c.index; + l = pa_memblock_get_length(c.memblock) - c.index; l = l <= 1 ? l : rand() % (l-1) +1 ; - - if ((r = read(STDIN_FILENO, (uint8_t*) c.memblock->data + c.index, l)) <= 0) { + + p = pa_memblock_acquire(c.memblock); + if ((r = read(STDIN_FILENO, (uint8_t*) p + c.index, l)) <= 0) { + pa_memblock_release(c.memblock); fprintf(stderr, "read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); break; } - + pa_memblock_release(c.memblock); + c.length = r; pa_mcalign_push(a, &c); fprintf(stderr, "Read %ld bytes\n", (long)r); c.index += r; - if (c.index >= c.memblock->length) { + if (c.index >= pa_memblock_get_length(c.memblock)) { pa_memblock_unref(c.memblock); pa_memchunk_reset(&c); } @@ -87,7 +90,9 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { if (pa_mcalign_pop(a, &t) < 0) break; - pa_loop_write(STDOUT_FILENO, (uint8_t*) t.memblock->data + t.index, t.length, NULL); + p = pa_memblock_acquire(t.memblock); + pa_loop_write(STDOUT_FILENO, (uint8_t*) p + t.index, t.length, NULL); + pa_memblock_release(t.memblock); fprintf(stderr, "Wrote %lu bytes.\n", (unsigned long) t.length); pa_memblock_unref(t.memblock); diff --git a/src/tests/memblock-test.c b/src/tests/memblock-test.c index ef2e0ad7..c2dd2efa 100644 --- a/src/tests/memblock-test.c +++ b/src/tests/memblock-test.c @@ -76,6 +76,7 @@ int main(int argc, char *argv[]) { pa_memblock* blocks[5]; uint32_t id, shm_id; size_t offset, size; + char *x; const char txt[] = "This is a test!"; @@ -90,10 +91,17 @@ int main(int argc, char *argv[]) { assert(pool_a && pool_b && pool_c); blocks[0] = pa_memblock_new_fixed(pool_a, (void*) txt, sizeof(txt), 1); + blocks[1] = pa_memblock_new(pool_a, sizeof(txt)); - snprintf(blocks[1]->data, blocks[1]->length, "%s", txt); + x = pa_memblock_acquire(blocks[1]); + snprintf(x, pa_memblock_get_length(blocks[1]), "%s", txt); + pa_memblock_release(blocks[1]); + blocks[2] = pa_memblock_new_pool(pool_a, sizeof(txt)); - snprintf(blocks[2]->data, blocks[2]->length, "%s", txt); + x = pa_memblock_acquire(blocks[2]); + snprintf(x, pa_memblock_get_length(blocks[2]), "%s", txt); + pa_memblock_release(blocks[1]); + blocks[3] = pa_memblock_new_malloced(pool_a, pa_xstrdup(txt), sizeof(txt)); blocks[4] = NULL; @@ -130,14 +138,18 @@ int main(int argc, char *argv[]) { mb_c = pa_memimport_get(import_c, id, shm_id, offset, size); assert(mb_c); - printf("1 data=%s\n", (char*) mb_c->data); + x = pa_memblock_acquire(mb_c); + printf("1 data=%s\n", x); + pa_memblock_release(mb_c); print_stats(pool_a, "A"); print_stats(pool_b, "B"); print_stats(pool_c, "C"); pa_memexport_free(export_b); - printf("2 data=%s\n", (char*) mb_c->data); + x = pa_memblock_acquire(mb_c); + printf("2 data=%s\n", x); + pa_memblock_release(mb_c); pa_memblock_unref(mb_c); pa_memimport_free(import_b); diff --git a/src/tests/memblockq-test.c b/src/tests/memblockq-test.c index 1ac4577b..02848eb2 100644 --- a/src/tests/memblockq-test.c +++ b/src/tests/memblockq-test.c @@ -131,8 +131,10 @@ int main(int argc, char *argv[]) { if (pa_memblockq_peek(bq, &out) < 0) break; - for (e = (char*) out.memblock->data + out.index, n = 0; n < out.length; n++) + p = pa_memblock_acquire(out.memblock); + for (e = (char*) p + out.index, n = 0; n < out.length; n++) printf("%c", *e); + pa_memblock_release(out.memblock); pa_memblock_unref(out.memblock); pa_memblockq_drop(bq, &out, out.length); -- cgit From 977659684855d30d48958910f92593e94dbb8da8 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 6 Nov 2006 10:14:16 +0000 Subject: Handle when threaded mainloop is freed before it is started. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1405 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/thread-mainloop.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pulse/thread-mainloop.c b/src/pulse/thread-mainloop.c index 060782b5..7e1ccfaa 100644 --- a/src/pulse/thread-mainloop.c +++ b/src/pulse/thread-mainloop.c @@ -120,7 +120,8 @@ void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { pa_threaded_mainloop_stop(m); - pa_thread_free(m->thread); + if (m->thread) + pa_thread_free(m->thread); pa_mainloop_free(m->real_mainloop); -- cgit From 6ca819354cabdaeda0b122535a50fa49924d8d2d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 6 Nov 2006 10:17:39 +0000 Subject: The OSS spec is unclear what should happen when a reset is requested. Let's have a nicer attitude and keep as much settings as possible. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1406 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index c7bfe5ab..5d96a984 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1003,12 +1003,21 @@ static void free_streams(fd_info *i) { pa_stream_disconnect(i->play_stream); pa_stream_unref(i->play_stream); i->play_stream = NULL; + i->io_flags |= PA_IO_EVENT_INPUT; } if (i->rec_stream) { pa_stream_disconnect(i->rec_stream); pa_stream_unref(i->rec_stream); i->rec_stream = NULL; + i->io_flags |= PA_IO_EVENT_OUTPUT; + } + + if (i->io_event) { + pa_mainloop_api *api; + + api = pa_threaded_mainloop_get_api(i->mainloop); + api->io_enable(i->io_event, i->io_flags); } } @@ -1954,7 +1963,6 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) free_streams(i); dsp_flush_socket(i); - reset_params(i); i->optr_n_blocks = 0; -- cgit From 8dc62142765249addf131b058c27f931ede1776b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 6 Nov 2006 13:06:01 +0000 Subject: Revert r1404 and keep it on a development branch until it is fully tested. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1409 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 7 +- src/modules/module-alsa-sink.c | 14 +- src/modules/module-alsa-source.c | 10 +- src/modules/module-esound-sink.c | 11 +- src/modules/module-jack-sink.c | 5 +- src/modules/module-jack-source.c | 7 +- src/modules/module-oss-mmap.c | 4 +- src/modules/module-oss.c | 22 +- src/modules/module-pipe-sink.c | 11 +- src/modules/module-pipe-source.c | 13 +- src/modules/module-sine.c | 14 +- src/modules/rtp/rtp.c | 18 +- src/pulse/internal.h | 1 - src/pulse/stream.c | 20 +- src/pulsecore/cli-command.c | 20 +- src/pulsecore/mcalign.c | 10 +- src/pulsecore/memblock.c | 507 +++++++++----------------------------- src/pulsecore/memblock.h | 61 +++-- src/pulsecore/memblockq.c | 10 +- src/pulsecore/memchunk.c | 15 +- src/pulsecore/play-memchunk.c | 2 +- src/pulsecore/protocol-esound.c | 38 +-- src/pulsecore/protocol-native.c | 14 +- src/pulsecore/protocol-simple.c | 22 +- src/pulsecore/pstream.c | 169 +++++++------ src/pulsecore/resampler.c | 247 +++++++++---------- src/pulsecore/sample-util.c | 116 +++------ src/pulsecore/sample-util.h | 3 +- src/pulsecore/sink-input.c | 9 +- src/pulsecore/sink.c | 26 +- src/pulsecore/sound-file-stream.c | 9 +- src/pulsecore/sound-file.c | 15 +- src/tests/flist-test.c | 2 +- src/tests/mcalign-test.c | 19 +- src/tests/memblock-test.c | 20 +- src/tests/memblockq-test.c | 4 +- 36 files changed, 502 insertions(+), 993 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 0ce805ec..64df8614 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -268,7 +268,8 @@ thread_test_CFLAGS = $(AM_CFLAGS) thread_test_LDADD = $(AM_LDADD) libpulsecore.la thread_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -flist_test_SOURCES = tests/flist-test.c +flist_test_SOURCES = tests/flist-test.c \ + pulsecore/flist.c pulsecore/flist.h flist_test_CFLAGS = $(AM_CFLAGS) flist_test_LDADD = $(AM_LDADD) libpulsecore.la flist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -447,8 +448,6 @@ libpulse_la_SOURCES += \ pulsecore/core-error.c pulsecore/core-error.h \ pulsecore/winsock.h pulsecore/creds.h \ pulsecore/shm.c pulsecore/shm.h \ - pulsecore/flist.c pulsecore/flist.h \ - pulsecore/anotify.c pulsecore/anotify.h \ $(PA_THREAD_OBJS) if OS_IS_WIN32 @@ -629,8 +628,6 @@ libpulsecore_la_SOURCES += \ pulsecore/core-error.c pulsecore/core-error.h \ pulsecore/hook-list.c pulsecore/hook-list.h \ pulsecore/shm.c pulsecore/shm.h \ - pulsecore/flist.c pulsecore/flist.h \ - pulsecore/anotify.c pulsecore/anotify.h \ $(PA_THREAD_OBJS) if OS_IS_WIN32 diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 7bbd7de2..6ff9a6e4 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -144,7 +144,6 @@ static void do_write(struct userdata *u) { update_usage(u); for (;;) { - void *p; pa_memchunk *memchunk = NULL; snd_pcm_sframes_t frames; @@ -157,15 +156,9 @@ static void do_write(struct userdata *u) { memchunk = &u->memchunk; } - assert(memchunk->memblock); - assert(memchunk->length); - assert((memchunk->length % u->frame_size) == 0); + assert(memchunk->memblock && memchunk->memblock->data && memchunk->length && memchunk->memblock->length && (memchunk->length % u->frame_size) == 0); - p = pa_memblock_acquire(memchunk->memblock); - - if ((frames = snd_pcm_writei(u->pcm_handle, (uint8_t*) p + memchunk->index, memchunk->length / u->frame_size)) < 0) { - pa_memblock_release(memchunk->memblock); - + if ((frames = snd_pcm_writei(u->pcm_handle, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length / u->frame_size)) < 0) { if (frames == -EAGAIN) return; @@ -183,9 +176,6 @@ static void do_write(struct userdata *u) { return; } - pa_memblock_release(memchunk->memblock); - - if (memchunk == &u->memchunk) { size_t l = frames * u->frame_size; memchunk->index += l; diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 9bde46da..aa0666f1 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -149,7 +149,6 @@ static void do_read(struct userdata *u) { pa_memchunk post_memchunk; snd_pcm_sframes_t frames; size_t l; - void *p; if (!u->memchunk.memblock) { u->memchunk.memblock = pa_memblock_new(u->source->core->mempool, u->memchunk.length = u->fragment_size); @@ -158,13 +157,11 @@ static void do_read(struct userdata *u) { assert(u->memchunk.memblock); assert(u->memchunk.length); + assert(u->memchunk.memblock->data); + assert(u->memchunk.memblock->length); assert(u->memchunk.length % u->frame_size == 0); - p = pa_memblock_acquire(u->memchunk.memblock); - - if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) p + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { - pa_memblock_release(u->memchunk.memblock); - + if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { if (frames == -EAGAIN) return; @@ -181,7 +178,6 @@ static void do_read(struct userdata *u) { pa_module_unload_request(u->module); return; } - pa_memblock_release(u->memchunk.memblock); l = frames * u->frame_size; diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index ca1f16ce..6d4a8489 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -142,25 +142,18 @@ static int do_write(struct userdata *u) { u->write_index = u->write_length = 0; } } else if (u->state == STATE_RUNNING) { - void *p; - pa_module_set_used(u->module, pa_sink_used_by(u->sink)); if (!u->memchunk.length) if (pa_sink_render(u->sink, 8192, &u->memchunk) < 0) return 0; - assert(u->memchunk.memblock); - assert(u->memchunk.length); - - p = pa_memblock_acquire(u->memchunk.memblock); + assert(u->memchunk.memblock && u->memchunk.length); - if ((r = pa_iochannel_write(u->io, (uint8_t*) p + u->memchunk.index, u->memchunk.length)) < 0) { - pa_memblock_release(u->memchunk.memblock); + if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { pa_log("write() failed: %s", pa_cstrerror(errno)); return -1; } - pa_memblock_release(u->memchunk.memblock); u->memchunk.index += r; u->memchunk.length -= r; diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index 66ded27f..47f77bab 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -135,25 +135,22 @@ static void io_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_ unsigned fs; jack_nframes_t frame_idx; pa_memchunk chunk; - void *p; fs = pa_frame_size(&u->sink->sample_spec); pa_sink_render_full(u->sink, u->frames_requested * fs, &chunk); - p = pa_memblock_acquire(chunk.memblock); for (frame_idx = 0; frame_idx < u->frames_requested; frame_idx ++) { unsigned c; for (c = 0; c < u->channels; c++) { - float *s = ((float*) ((uint8_t*) p + chunk.index)) + (frame_idx * u->channels) + c; + float *s = ((float*) ((uint8_t*) chunk.memblock->data + chunk.index)) + (frame_idx * u->channels) + c; float *d = ((float*) u->buffer[c]) + frame_idx; *d = *s; } } - pa_memblock_release(chunk.memblock); pa_memblock_unref(chunk.memblock); u->frames_requested = 0; diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index 5270b241..62a99108 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -134,28 +134,23 @@ static void io_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_ unsigned fs; jack_nframes_t frame_idx; pa_memchunk chunk; - void *p; fs = pa_frame_size(&u->source->sample_spec); chunk.memblock = pa_memblock_new(u->core->mempool, chunk.length = u->frames_posted * fs); chunk.index = 0; - - p = pa_memblock_acquire(chunk.memblock); for (frame_idx = 0; frame_idx < u->frames_posted; frame_idx ++) { unsigned c; for (c = 0; c < u->channels; c++) { float *s = ((float*) u->buffer[c]) + frame_idx; - float *d = ((float*) ((uint8_t*) p + chunk.index)) + (frame_idx * u->channels) + c; + float *d = ((float*) ((uint8_t*) chunk.memblock->data + chunk.index)) + (frame_idx * u->channels) + c; *d = *s; } } - pa_memblock_release(chunk.memblock); - pa_source_post(u->source, &chunk); pa_memblock_unref(chunk.memblock); diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index 39a8511f..5ab08287 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -170,7 +170,7 @@ static void out_fill_memblocks(struct userdata *u, unsigned n) { u->out_fragment_size, 1); assert(chunk.memblock); - chunk.length = pa_memblock_get_length(chunk.memblock); + chunk.length = chunk.memblock->length; chunk.index = 0; pa_sink_render_into_full(u->sink, &chunk); @@ -214,7 +214,7 @@ static void in_post_memblocks(struct userdata *u, unsigned n) { if (!u->in_memblocks[u->in_current]) { chunk.memblock = u->in_memblocks[u->in_current] = pa_memblock_new_fixed(u->core->mempool, (uint8_t*) u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size, 1); - chunk.length = pa_memblock_get_length(chunk.memblock); + chunk.length = chunk.memblock->length; chunk.index = 0; pa_source_post(u->source, &chunk); diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 73f0d57e..b71581d9 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -155,7 +155,6 @@ static void do_write(struct userdata *u) { } do { - void *p; memchunk = &u->memchunk; if (!memchunk->length) @@ -163,18 +162,16 @@ static void do_write(struct userdata *u) { memchunk = &u->silence; assert(memchunk->memblock); + assert(memchunk->memblock->data); assert(memchunk->length); - - p = pa_memblock_acquire(memchunk->memblock); - if ((r = pa_iochannel_write(u->io, (uint8_t*) p + memchunk->index, memchunk->length)) < 0) { - pa_memblock_release(memchunk->memblock); + + if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { pa_log("write() failed: %s", pa_cstrerror(errno)); clear_up(u); pa_module_unload_request(u->module); break; } - pa_memblock_release(memchunk->memblock); if (memchunk == &u->silence) assert(r % u->sample_size == 0); @@ -220,13 +217,9 @@ static void do_read(struct userdata *u) { } do { - void *p; memchunk.memblock = pa_memblock_new(u->core->mempool, l); - - p = pa_memblock_acquire(memchunk.memblock); - - if ((r = pa_iochannel_read(u->io, p, pa_memblock_get_length(memchunk.memblock))) < 0) { - pa_memblock_release(memchunk.memblock); + assert(memchunk.memblock); + if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); if (errno != EAGAIN) { pa_log("read() failed: %s", pa_cstrerror(errno)); @@ -235,10 +228,9 @@ static void do_read(struct userdata *u) { } break; } - pa_memblock_release(memchunk.memblock); - assert(r <= (ssize_t) pa_memblock_get_length(memchunk.memblock)); - memchunk.length = r; + assert(r <= (ssize_t) memchunk.memblock->length); + memchunk.length = memchunk.memblock->length = r; memchunk.index = 0; pa_source_post(u->source, &memchunk); diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index 59d91aa4..4aee849b 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -84,8 +84,6 @@ static const char* const valid_modargs[] = { static void do_write(struct userdata *u) { ssize_t r; - void *p; - assert(u); u->core->mainloop->defer_enable(u->defer_event, 0); @@ -99,17 +97,12 @@ static void do_write(struct userdata *u) { if (pa_sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0) return; - assert(u->memchunk.memblock); - assert(u->memchunk.length); - - p = pa_memblock_acquire(u->memchunk.memblock); + assert(u->memchunk.memblock && u->memchunk.length); - if ((r = pa_iochannel_write(u->io, (uint8_t*) p + u->memchunk.index, u->memchunk.length)) < 0) { - pa_memblock_release(u->memchunk.memblock); + if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { pa_log("write(): %s", pa_cstrerror(errno)); return; } - pa_memblock_release(u->memchunk.memblock); u->memchunk.index += r; u->memchunk.length -= r; diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index 99f4f3b9..c251f7ac 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -82,9 +82,7 @@ static const char* const valid_modargs[] = { static void do_read(struct userdata *u) { ssize_t r; - void *p; pa_memchunk chunk; - assert(u); if (!pa_iochannel_is_readable(u->io)) @@ -97,22 +95,17 @@ static void do_read(struct userdata *u) { u->chunk.index = chunk.length = 0; } - assert(u->chunk.memblock); - assert(pa_memblock_get_length(u->chunk.memblock) > u->chunk.index); - - p = pa_memblock_acquire(u->chunk.memblock); - if ((r = pa_iochannel_read(u->io, (uint8_t*) p + u->chunk.index, pa_memblock_get_length(u->chunk.memblock) - u->chunk.index)) <= 0) { - pa_memblock_release(u->chunk.memblock); + assert(u->chunk.memblock && u->chunk.memblock->length > u->chunk.index); + if ((r = pa_iochannel_read(u->io, (uint8_t*) u->chunk.memblock->data + u->chunk.index, u->chunk.memblock->length - u->chunk.index)) <= 0) { pa_log("read(): %s", pa_cstrerror(errno)); return; } - pa_memblock_release(u->chunk.memblock); u->chunk.length = r; pa_source_post(u->source, &u->chunk); u->chunk.index += r; - if (u->chunk.index >= pa_memblock_get_length(u->chunk.memblock)) { + if (u->chunk.index >= u->chunk.memblock->length) { u->chunk.index = u->chunk.length = 0; pa_memblock_unref(u->chunk.memblock); u->chunk.memblock = NULL; diff --git a/src/modules/module-sine.c b/src/modules/module-sine.c index f65b1f3a..fa29ba16 100644 --- a/src/modules/module-sine.c +++ b/src/modules/module-sine.c @@ -63,7 +63,7 @@ static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { chunk->memblock = pa_memblock_ref(u->memblock); chunk->index = u->peek_index; - chunk->length = pa_memblock_get_length(u->memblock) - u->peek_index; + chunk->length = u->memblock->length - u->peek_index; return 0; } @@ -72,12 +72,11 @@ static void sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t l assert(i && chunk && length && i->userdata); u = i->userdata; - assert(chunk->memblock == u->memblock); - assert(length <= pa_memblock_get_length(u->memblock)-u->peek_index); + assert(chunk->memblock == u->memblock && length <= u->memblock->length-u->peek_index); u->peek_index += length; - if (u->peek_index >= pa_memblock_get_length(u->memblock)) + if (u->peek_index >= u->memblock->length) u->peek_index = 0; } @@ -110,7 +109,6 @@ int pa__init(pa_core *c, pa_module*m) { pa_sample_spec ss; uint32_t frequency; char t[256]; - void *p; pa_sink_input_new_data data; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -142,10 +140,8 @@ int pa__init(pa_core *c, pa_module*m) { } u->memblock = pa_memblock_new(c->mempool, pa_bytes_per_second(&ss)); - p = pa_memblock_acquire(u->memblock); - calc_sine(p, pa_memblock_get_length(u->memblock), frequency); - pa_memblock_release(u->memblock); - + calc_sine(u->memblock->data, u->memblock->length, frequency); + snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency); pa_sink_input_new_data_init(&data); diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c index a4362f84..3bb0ea47 100644 --- a/src/modules/rtp/rtp.c +++ b/src/modules/rtp/rtp.c @@ -79,7 +79,7 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { size_t k = n + chunk.length > size ? size - n : chunk.length; if (chunk.memblock) { - iov[iov_idx].iov_base = (void*)((uint8_t*) pa_memblock_acquire(chunk.memblock) + chunk.index); + iov[iov_idx].iov_base = (void*)((uint8_t*) chunk.memblock->data + chunk.index); iov[iov_idx].iov_len = k; mb[iov_idx] = chunk.memblock; iov_idx ++; @@ -114,10 +114,8 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { k = sendmsg(c->fd, &m, MSG_DONTWAIT); - for (i = 1; i < iov_idx; i++) { - pa_memblock_release(mb[i]); + for (i = 1; i < iov_idx; i++) pa_memblock_unref(mb[i]); - } c->sequence++; } else @@ -174,7 +172,7 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { chunk->memblock = pa_memblock_new(pool, size); - iov.iov_base = pa_memblock_acquire(chunk->memblock); + iov.iov_base = chunk->memblock->data; iov.iov_len = size; m.msg_name = NULL; @@ -195,9 +193,9 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { goto fail; } - memcpy(&header, iov.iov_base, sizeof(uint32_t)); - memcpy(&c->timestamp, (uint8_t*) iov.iov_base + 4, sizeof(uint32_t)); - memcpy(&c->ssrc, (uint8_t*) iov.iov_base + 8, sizeof(uint32_t)); + memcpy(&header, chunk->memblock->data, sizeof(uint32_t)); + memcpy(&c->timestamp, (uint8_t*) chunk->memblock->data + 4, sizeof(uint32_t)); + memcpy(&c->ssrc, (uint8_t*) chunk->memblock->data + 8, sizeof(uint32_t)); header = ntohl(header); c->timestamp = ntohl(c->timestamp); @@ -238,10 +236,8 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { return 0; fail: - if (chunk->memblock) { - pa_memblock_release(chunk->memblock); + if (chunk->memblock) pa_memblock_unref(chunk->memblock); - } return -1; } diff --git a/src/pulse/internal.h b/src/pulse/internal.h index 76d80d83..4eef4b4a 100644 --- a/src/pulse/internal.h +++ b/src/pulse/internal.h @@ -113,7 +113,6 @@ struct pa_stream { uint32_t requested_bytes; pa_memchunk peek_memchunk; - void *peek_data; pa_memblockq *record_memblockq; int corked; diff --git a/src/pulse/stream.c b/src/pulse/stream.c index d31127d8..180cd096 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -88,7 +88,6 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->peek_memchunk.index = 0; s->peek_memchunk.length = 0; s->peek_memchunk.memblock = NULL; - s->peek_data = NULL; s->record_memblockq = NULL; @@ -123,11 +122,8 @@ static void stream_free(pa_stream *s) { s->mainloop->time_free(s->auto_timing_update_event); } - if (s->peek_memchunk.memblock) { - if (s->peek_data) - pa_memblock_release(s->peek_memchunk.memblock); + if (s->peek_memchunk.memblock) pa_memblock_unref(s->peek_memchunk.memblock); - } if (s->record_memblockq) pa_memblockq_free(s->record_memblockq); @@ -609,11 +605,8 @@ int pa_stream_write( if (free_cb) chunk.memblock = pa_memblock_new_user(s->context->mempool, (void*) data, length, free_cb, 1); else { - void *tdata; chunk.memblock = pa_memblock_new(s->context->mempool, length); - tdata = pa_memblock_acquire(chunk.memblock); - memcpy(tdata, data, length); - pa_memblock_release(chunk.memblock); + memcpy(chunk.memblock->data, data, length); } chunk.index = 0; @@ -679,12 +672,9 @@ int pa_stream_peek(pa_stream *s, const void **data, size_t *length) { *length = 0; return 0; } - - s->peek_data = pa_memblock_acquire(s->peek_memchunk.memblock); } - assert(s->peek_data); - *data = (uint8_t*) s->peek_data + s->peek_memchunk.index; + *data = (const char*) s->peek_memchunk.memblock->data + s->peek_memchunk.index; *length = s->peek_memchunk.length; return 0; } @@ -702,9 +692,7 @@ int pa_stream_drop(pa_stream *s) { /* Fix the simulated local read index */ if (s->timing_info_valid && !s->timing_info.read_index_corrupt) s->timing_info.read_index += s->peek_memchunk.length; - - assert(s->peek_data); - pa_memblock_release(s->peek_memchunk.memblock); + pa_memblock_unref(s->peek_memchunk.memblock); s->peek_memchunk.length = 0; s->peek_memchunk.index = 0; diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index d7e4a75c..ae475c3a 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -259,20 +259,20 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G stat = pa_mempool_get_stat(c->mempool); pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n", - (unsigned) pa_atomic_load(&stat->n_allocated), - pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->allocated_size))); + (unsigned) AO_load_acquire_read((AO_t*) &stat->n_allocated), + pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->allocated_size))); pa_strbuf_printf(buf, "Memory blocks allocated during the whole lifetime: %u, size: %s.\n", - (unsigned) pa_atomic_load(&stat->n_accumulated), - pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->accumulated_size))); + (unsigned) AO_load_acquire_read((AO_t*) &stat->n_accumulated), + pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->accumulated_size))); pa_strbuf_printf(buf, "Memory blocks imported from other processes: %u, size: %s.\n", - (unsigned) pa_atomic_load(&stat->n_imported), - pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->imported_size))); + (unsigned) AO_load_acquire_read((AO_t*) &stat->n_imported), + pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->imported_size))); pa_strbuf_printf(buf, "Memory blocks exported to other processes: %u, size: %s.\n", - (unsigned) pa_atomic_load(&stat->n_exported), - pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->exported_size))); + (unsigned) AO_load_acquire_read((AO_t*) &stat->n_exported), + pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->exported_size))); pa_strbuf_printf(buf, "Total sample cache size: %s.\n", pa_bytes_snprint(s, sizeof(s), pa_scache_total_size(c))); @@ -289,8 +289,8 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G pa_strbuf_printf(buf, "Memory blocks of type %s: %u allocated/%u accumulated.\n", type_table[k], - (unsigned) pa_atomic_load(&stat->n_allocated_by_type[k]), - (unsigned) pa_atomic_load(&stat->n_accumulated_by_type[k])); + (unsigned) AO_load_acquire_read(&stat->n_allocated_by_type[k]), + (unsigned) AO_load_acquire_read(&stat->n_accumulated_by_type[k])); return 0; } diff --git a/src/pulsecore/mcalign.c b/src/pulsecore/mcalign.c index aa2eae46..9ede610d 100644 --- a/src/pulsecore/mcalign.c +++ b/src/pulsecore/mcalign.c @@ -89,7 +89,6 @@ void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { } else { size_t l; - void *lo_data, *m_data; /* We have to copy */ assert(m->leftover.length < m->base); @@ -101,15 +100,10 @@ void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { /* Can we use the current block? */ pa_memchunk_make_writable(&m->leftover, m->base); - lo_data = pa_memblock_acquire(m->leftover.memblock); - m_data = pa_memblock_acquire(c->memblock); - memcpy((uint8_t*) lo_data + m->leftover.index + m->leftover.length, (uint8_t*) m_data + c->index, l); - pa_memblock_release(m->leftover.memblock); - pa_memblock_release(c->memblock); + memcpy((uint8_t*) m->leftover.memblock->data + m->leftover.index + m->leftover.length, (uint8_t*) c->memblock->data + c->index, l); m->leftover.length += l; - assert(m->leftover.length <= m->base); - assert(m->leftover.length <= pa_memblock_get_length(m->leftover.memblock)); + assert(m->leftover.length <= m->base && m->leftover.length <= m->leftover.memblock->length); if (c->length > l) { /* Save the remainder of the memory block */ diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index f11a7174..9cfd79b5 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -30,13 +30,10 @@ #include #include -#include #include #include #include -#include -#include #include "memblock.h" @@ -48,32 +45,6 @@ #define PA_MEMIMPORT_SLOTS_MAX 128 #define PA_MEMIMPORT_SEGMENTS_MAX 16 -struct pa_memblock { - PA_REFCNT_DECLARE; /* the reference counter */ - pa_mempool *pool; - - pa_memblock_type_t type; - int read_only; /* boolean */ - - pa_atomic_ptr_t data; - size_t length; - - pa_atomic_int_t n_acquired; - pa_atomic_int_t please_signal; - - union { - struct { - /* If type == PA_MEMBLOCK_USER this points to a function for freeing this memory block */ - pa_free_cb_t free_cb; - } user; - - struct { - uint32_t id; - pa_memimport_segment *segment; - } imported; - } per_type; -}; - struct pa_memimport_segment { pa_memimport *import; pa_shm memory; @@ -81,8 +52,6 @@ struct pa_memimport_segment { }; struct pa_memimport { - pa_mutex *mutex; - pa_mempool *pool; pa_hashmap *segments; pa_hashmap *blocks; @@ -101,11 +70,9 @@ struct memexport_slot { }; struct pa_memexport { - pa_mutex *mutex; pa_mempool *pool; struct memexport_slot slots[PA_MEMEXPORT_SLOTS_MAX]; - PA_LLIST_HEAD(struct memexport_slot, free_slots); PA_LLIST_HEAD(struct memexport_slot, used_slots); unsigned n_init; @@ -125,71 +92,63 @@ struct mempool_slot { }; struct pa_mempool { - pa_mutex *mutex; - pa_cond *cond; - pa_shm memory; size_t block_size; - unsigned n_blocks; - - pa_atomic_int_t n_init; + unsigned n_blocks, n_init; PA_LLIST_HEAD(pa_memimport, imports); PA_LLIST_HEAD(pa_memexport, exports); /* A list of free slots that may be reused */ - pa_flist *free_slots; + PA_LLIST_HEAD(struct mempool_slot, free_slots); pa_mempool_stat stat; }; static void segment_detach(pa_memimport_segment *seg); -/* No lock necessary */ static void stat_add(pa_memblock*b) { assert(b); assert(b->pool); - pa_atomic_inc(&b->pool->stat.n_allocated); - pa_atomic_add(&b->pool->stat.allocated_size, (int) b->length); + AO_fetch_and_add1_release_write(&b->pool->stat.n_allocated); + AO_fetch_and_add_release_write(&b->pool->stat.allocated_size, (AO_t) b->length); - pa_atomic_inc(&b->pool->stat.n_accumulated); - pa_atomic_add(&b->pool->stat.accumulated_size, (int) b->length); + AO_fetch_and_add1_release_write(&b->pool->stat.n_accumulated); + AO_fetch_and_add_release_write(&b->pool->stat.accumulated_size, (AO_t) b->length); if (b->type == PA_MEMBLOCK_IMPORTED) { - pa_atomic_inc(&b->pool->stat.n_imported); - pa_atomic_add(&b->pool->stat.imported_size, (int) b->length); + AO_fetch_and_add1_release_write(&b->pool->stat.n_imported); + AO_fetch_and_add_release_write(&b->pool->stat.imported_size, (AO_t) b->length); } - pa_atomic_inc(&b->pool->stat.n_allocated_by_type[b->type]); - pa_atomic_inc(&b->pool->stat.n_accumulated_by_type[b->type]); + AO_fetch_and_add1_release_write(&b->pool->stat.n_allocated_by_type[b->type]); + AO_fetch_and_add1_release_write(&b->pool->stat.n_accumulated_by_type[b->type]); } -/* No lock necessary */ static void stat_remove(pa_memblock *b) { assert(b); assert(b->pool); - assert(pa_atomic_load(&b->pool->stat.n_allocated) > 0); - assert(pa_atomic_load(&b->pool->stat.allocated_size) >= (int) b->length); + assert(AO_load_acquire_read(&b->pool->stat.n_allocated) > 0); + assert(AO_load_acquire_read(&b->pool->stat.allocated_size) >= (AO_t) b->length); - pa_atomic_dec(&b->pool->stat.n_allocated); - pa_atomic_add(&b->pool->stat.allocated_size, - (int) b->length); + AO_fetch_and_sub1_release_write(&b->pool->stat.n_allocated); + AO_fetch_and_add_release_write(&b->pool->stat.allocated_size, (AO_t) (-b->length)); if (b->type == PA_MEMBLOCK_IMPORTED) { - assert(pa_atomic_load(&b->pool->stat.n_imported) > 0); - assert(pa_atomic_load(&b->pool->stat.imported_size) >= (int) b->length); + assert(AO_load_acquire_read(&b->pool->stat.n_imported) > 0); + assert(AO_load_acquire_read(&b->pool->stat.imported_size) >= (AO_t) b->length); - pa_atomic_dec(&b->pool->stat.n_imported); - pa_atomic_add(&b->pool->stat.imported_size, - (int) b->length); + AO_fetch_and_sub1_release_write(&b->pool->stat.n_imported); + AO_fetch_and_add_release_write(&b->pool->stat.imported_size, (AO_t) (-b->length)); } - pa_atomic_dec(&b->pool->stat.n_allocated_by_type[b->type]); + AO_fetch_and_sub1_release_write(&b->pool->stat.n_allocated_by_type[b->type]); } static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length); -/* No lock necessary */ pa_memblock *pa_memblock_new(pa_mempool *p, size_t length) { pa_memblock *b; @@ -202,7 +161,6 @@ pa_memblock *pa_memblock_new(pa_mempool *p, size_t length) { return b; } -/* No lock necessary */ static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length) { pa_memblock *b; @@ -210,61 +168,49 @@ static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length) { assert(length > 0); b = pa_xmalloc(sizeof(pa_memblock) + length); - PA_REFCNT_INIT(b); - b->pool = p; b->type = PA_MEMBLOCK_APPENDED; b->read_only = 0; - pa_atomic_ptr_store(&b->data, (uint8_t*)b + sizeof(pa_memblock)); + PA_REFCNT_INIT(b); b->length = length; - pa_atomic_store(&b->n_acquired, 0); - pa_atomic_store(&b->please_signal, 0); - + b->data = (uint8_t*) b + sizeof(pa_memblock); + b->pool = p; + stat_add(b); return b; } -/* No lock necessary */ static struct mempool_slot* mempool_allocate_slot(pa_mempool *p) { struct mempool_slot *slot; assert(p); - if (!(slot = pa_flist_pop(p->free_slots))) { - int idx; - - /* The free list was empty, we have to allocate a new entry */ - - if ((unsigned) (idx = pa_atomic_inc(&p->n_init)) >= p->n_blocks) - pa_atomic_dec(&p->n_init); - else - slot = (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->block_size * idx)); - - if (!slot) { - pa_log_debug("Pool full"); - pa_atomic_inc(&p->stat.n_pool_full); - } + if (p->free_slots) { + slot = p->free_slots; + PA_LLIST_REMOVE(struct mempool_slot, p->free_slots, slot); + } else if (p->n_init < p->n_blocks) + slot = (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->block_size * p->n_init++)); + else { + pa_log_debug("Pool full"); + AO_fetch_and_add1_release_write(&p->stat.n_pool_full); + return NULL; } return slot; } -/* No lock necessary */ static void* mempool_slot_data(struct mempool_slot *slot) { assert(slot); return (uint8_t*) slot + sizeof(struct mempool_slot); } -/* No lock necessary */ static unsigned mempool_slot_idx(pa_mempool *p, void *ptr) { assert(p); - assert((uint8_t*) ptr >= (uint8_t*) p->memory.ptr); assert((uint8_t*) ptr < (uint8_t*) p->memory.ptr + p->memory.size); return ((uint8_t*) ptr - (uint8_t*) p->memory.ptr) / p->block_size; } -/* No lock necessary */ static struct mempool_slot* mempool_slot_by_ptr(pa_mempool *p, void *ptr) { unsigned idx; @@ -274,7 +220,6 @@ static struct mempool_slot* mempool_slot_by_ptr(pa_mempool *p, void *ptr) { return (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (idx * p->block_size)); } -/* No lock necessary */ pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) { pa_memblock *b = NULL; struct mempool_slot *slot; @@ -289,7 +234,7 @@ pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) { b = mempool_slot_data(slot); b->type = PA_MEMBLOCK_POOL; - pa_atomic_ptr_store(&b->data, (uint8_t*) b + sizeof(pa_memblock)); + b->data = (uint8_t*) b + sizeof(pa_memblock); } else if (p->block_size - sizeof(struct mempool_slot) >= length) { @@ -298,26 +243,22 @@ pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) { b = pa_xnew(pa_memblock, 1); b->type = PA_MEMBLOCK_POOL_EXTERNAL; - pa_atomic_ptr_store(&b->data, mempool_slot_data(slot)); - + b->data = mempool_slot_data(slot); } else { pa_log_debug("Memory block too large for pool: %u > %u", length, p->block_size - sizeof(struct mempool_slot)); - pa_atomic_inc(&p->stat.n_too_large_for_pool); + AO_fetch_and_add1_release_write(&p->stat.n_too_large_for_pool); return NULL; } + b->length = length; + b->read_only = 0; PA_REFCNT_INIT(b); b->pool = p; - b->read_only = 0; - b->length = length; - pa_atomic_store(&b->n_acquired, 0); - pa_atomic_store(&b->please_signal, 0); stat_add(b); return b; } -/* No lock necessary */ pa_memblock *pa_memblock_new_fixed(pa_mempool *p, void *d, size_t length, int read_only) { pa_memblock *b; @@ -326,20 +267,17 @@ pa_memblock *pa_memblock_new_fixed(pa_mempool *p, void *d, size_t length, int re assert(length > 0); b = pa_xnew(pa_memblock, 1); - PA_REFCNT_INIT(b); - b->pool = p; b->type = PA_MEMBLOCK_FIXED; b->read_only = read_only; - pa_atomic_ptr_store(&b->data, d); + PA_REFCNT_INIT(b); b->length = length; - pa_atomic_store(&b->n_acquired, 0); - pa_atomic_store(&b->please_signal, 0); + b->data = d; + b->pool = p; stat_add(b); return b; } -/* No lock necessary */ pa_memblock *pa_memblock_new_user(pa_mempool *p, void *d, size_t length, void (*free_cb)(void *p), int read_only) { pa_memblock *b; @@ -349,72 +287,18 @@ pa_memblock *pa_memblock_new_user(pa_mempool *p, void *d, size_t length, void (* assert(free_cb); b = pa_xnew(pa_memblock, 1); - PA_REFCNT_INIT(b); - b->pool = p; b->type = PA_MEMBLOCK_USER; b->read_only = read_only; - pa_atomic_ptr_store(&b->data, d); + PA_REFCNT_INIT(b); b->length = length; - pa_atomic_store(&b->n_acquired, 0); - pa_atomic_store(&b->please_signal, 0); - + b->data = d; b->per_type.user.free_cb = free_cb; + b->pool = p; stat_add(b); return b; } -/* No lock necessary */ -int pa_memblock_is_read_only(pa_memblock *b) { - assert(b); - assert(PA_REFCNT_VALUE(b) > 0); - - return b->read_only && PA_REFCNT_VALUE(b) == 1; -} - -/* No lock necessary */ -void* pa_memblock_acquire(pa_memblock *b) { - assert(b); - assert(PA_REFCNT_VALUE(b) > 0); - - pa_atomic_inc(&b->n_acquired); - - return pa_atomic_ptr_load(&b->data); -} - -/* No lock necessary, in corner cases locks by its own */ -void pa_memblock_release(pa_memblock *b) { - int r; - assert(b); - assert(PA_REFCNT_VALUE(b) > 0); - - r = pa_atomic_dec(&b->n_acquired); - assert(r >= 1); - - if (r == 1 && pa_atomic_load(&b->please_signal)) { - pa_mempool *p = b->pool; - /* Signal a waiting thread that this memblock is no longer used */ - pa_mutex_lock(p->mutex); - pa_cond_signal(p->cond, 1); - pa_mutex_unlock(p->mutex); - } -} - -size_t pa_memblock_get_length(pa_memblock *b) { - assert(b); - assert(PA_REFCNT_VALUE(b) > 0); - - return b->length; -} - -pa_mempool* pa_memblock_get_pool(pa_memblock *b) { - assert(b); - assert(PA_REFCNT_VALUE(b) > 0); - - return b->pool; -} - -/* No lock necessary */ pa_memblock* pa_memblock_ref(pa_memblock*b) { assert(b); assert(PA_REFCNT_VALUE(b) > 0); @@ -423,17 +307,19 @@ pa_memblock* pa_memblock_ref(pa_memblock*b) { return b; } -static void memblock_free(pa_memblock *b) { +void pa_memblock_unref(pa_memblock*b) { assert(b); - - assert(pa_atomic_load(&b->n_acquired) == 0); + assert(PA_REFCNT_VALUE(b) > 0); + if (PA_REFCNT_DEC(b) > 0) + return; + stat_remove(b); switch (b->type) { case PA_MEMBLOCK_USER : assert(b->per_type.user.free_cb); - b->per_type.user.free_cb(pa_atomic_ptr_load(&b->data)); + b->per_type.user.free_cb(b->data); /* Fall through */ @@ -444,23 +330,17 @@ static void memblock_free(pa_memblock *b) { case PA_MEMBLOCK_IMPORTED : { pa_memimport_segment *segment; - pa_memimport *import; - - /* FIXME! This should be implemented lock-free */ - + segment = b->per_type.imported.segment; assert(segment); - import = segment->import; - assert(import); + assert(segment->import); - pa_mutex_lock(import->mutex); - pa_hashmap_remove(import->blocks, PA_UINT32_TO_PTR(b->per_type.imported.id)); + pa_hashmap_remove(segment->import->blocks, PA_UINT32_TO_PTR(b->per_type.imported.id)); + segment->import->release_cb(segment->import, b->per_type.imported.id, segment->import->userdata); + if (-- segment->n_blocks <= 0) segment_detach(segment); - pa_mutex_unlock(import->mutex); - - import->release_cb(import, b->per_type.imported.id, import->userdata); - + pa_xfree(b); break; } @@ -468,20 +348,13 @@ static void memblock_free(pa_memblock *b) { case PA_MEMBLOCK_POOL_EXTERNAL: case PA_MEMBLOCK_POOL: { struct mempool_slot *slot; - int call_free; - slot = mempool_slot_by_ptr(b->pool, pa_atomic_ptr_load(&b->data)); + slot = mempool_slot_by_ptr(b->pool, b->data); assert(slot); - - call_free = b->type == PA_MEMBLOCK_POOL_EXTERNAL; - - /* The free list dimensions should easily allow all slots - * to fit in, hence try harder if pushing this slot into - * the free list fails */ - while (pa_flist_push(b->pool->free_slots, slot) < 0) - ; - if (call_free) + PA_LLIST_PREPEND(struct mempool_slot, b->pool->free_slots, slot); + + if (b->type == PA_MEMBLOCK_POOL_EXTERNAL) pa_xfree(b); break; @@ -493,42 +366,10 @@ static void memblock_free(pa_memblock *b) { } } -/* No lock necessary */ -void pa_memblock_unref(pa_memblock*b) { - assert(b); - assert(PA_REFCNT_VALUE(b) > 0); - - if (PA_REFCNT_DEC(b) > 0) - return; - - memblock_free(b); -} - -/* Self locked */ -static void memblock_wait(pa_memblock *b) { - assert(b); - - if (pa_atomic_load(&b->n_acquired) > 0) { - /* We need to wait until all threads gave up access to the - * memory block before we can go on. Unfortunately this means - * that we have to lock and wait here. Sniff! */ - - pa_atomic_inc(&b->please_signal); - - pa_mutex_lock(b->pool->mutex); - while (pa_atomic_load(&b->n_acquired) > 0) - pa_cond_wait(b->pool->cond, b->pool->mutex); - pa_mutex_unlock(b->pool->mutex); - - pa_atomic_dec(&b->please_signal); - } -} - -/* No lock necessary. This function is not multiple caller safe! */ static void memblock_make_local(pa_memblock *b) { assert(b); - pa_atomic_dec(&b->pool->stat.n_allocated_by_type[b->type]); + AO_fetch_and_sub1_release_write(&b->pool->stat.n_allocated_by_type[b->type]); if (b->length <= b->pool->block_size - sizeof(struct mempool_slot)) { struct mempool_slot *slot; @@ -537,61 +378,53 @@ static void memblock_make_local(pa_memblock *b) { void *new_data; /* We can move it into a local pool, perfect! */ - new_data = mempool_slot_data(slot); - memcpy(new_data, pa_atomic_ptr_load(&b->data), b->length); - pa_atomic_ptr_store(&b->data, new_data); - b->type = PA_MEMBLOCK_POOL_EXTERNAL; b->read_only = 0; + new_data = mempool_slot_data(slot); + memcpy(new_data, b->data, b->length); + b->data = new_data; goto finish; } } /* Humm, not enough space in the pool, so lets allocate the memory with malloc() */ - b->per_type.user.free_cb = pa_xfree; - pa_atomic_ptr_store(&b->data, pa_xmemdup(pa_atomic_ptr_load(&b->data), b->length)); - b->type = PA_MEMBLOCK_USER; + b->per_type.user.free_cb = pa_xfree; b->read_only = 0; + b->data = pa_xmemdup(b->data, b->length); finish: - pa_atomic_inc(&b->pool->stat.n_allocated_by_type[b->type]); - pa_atomic_inc(&b->pool->stat.n_accumulated_by_type[b->type]); - - memblock_wait(b); + AO_fetch_and_add1_release_write(&b->pool->stat.n_allocated_by_type[b->type]); + AO_fetch_and_add1_release_write(&b->pool->stat.n_accumulated_by_type[b->type]); } -/* No lock necessary. This function is not multiple caller safe*/ void pa_memblock_unref_fixed(pa_memblock *b) { assert(b); assert(PA_REFCNT_VALUE(b) > 0); assert(b->type == PA_MEMBLOCK_FIXED); - if (PA_REFCNT_DEC(b) > 0) + if (PA_REFCNT_VALUE(b) > 1) memblock_make_local(b); - else - memblock_free(b); + + pa_memblock_unref(b); } -/* Self-locked. This function is not multiple-caller safe */ static void memblock_replace_import(pa_memblock *b) { pa_memimport_segment *seg; assert(b); assert(b->type == PA_MEMBLOCK_IMPORTED); - assert(pa_atomic_load(&b->pool->stat.n_imported) > 0); - assert(pa_atomic_load(&b->pool->stat.imported_size) >= (int) b->length); - pa_atomic_dec(&b->pool->stat.n_imported); - pa_atomic_add(&b->pool->stat.imported_size, (int) - b->length); + assert(AO_load_acquire_read(&b->pool->stat.n_imported) > 0); + assert(AO_load_acquire_read(&b->pool->stat.imported_size) >= (AO_t) b->length); + AO_fetch_and_sub1_release_write(&b->pool->stat.n_imported); + AO_fetch_and_add_release_write(&b->pool->stat.imported_size, (AO_t) - b->length); seg = b->per_type.imported.segment; assert(seg); assert(seg->import); - pa_mutex_lock(seg->import->mutex); - pa_hashmap_remove( seg->import->blocks, PA_UINT32_TO_PTR(b->per_type.imported.id)); @@ -600,8 +433,6 @@ static void memblock_replace_import(pa_memblock *b) { if (-- seg->n_blocks <= 0) segment_detach(seg); - - pa_mutex_unlock(seg->import->mutex); } pa_mempool* pa_mempool_new(int shared) { @@ -610,15 +441,12 @@ pa_mempool* pa_mempool_new(int shared) { p = pa_xnew(pa_mempool, 1); - p->mutex = pa_mutex_new(1); - p->cond = pa_cond_new(); - #ifdef HAVE_SYSCONF ps = (size_t) sysconf(_SC_PAGESIZE); #elif defined(PAGE_SIZE) - ps = (size_t) PAGE_SIZE; + ps = (size_t) PAGE_SIZE; #else - ps = 4096; /* Let's hope it's like x86. */ + ps = 4096; /* Let's hope it's like x86. */ #endif p->block_size = (PA_MEMPOOL_SLOT_SIZE/ps)*ps; @@ -635,13 +463,13 @@ pa_mempool* pa_mempool_new(int shared) { return NULL; } - memset(&p->stat, 0, sizeof(p->stat)); - pa_atomic_store(&p->n_init, 0); + p->n_init = 0; PA_LLIST_HEAD_INIT(pa_memimport, p->imports); PA_LLIST_HEAD_INIT(pa_memexport, p->exports); + PA_LLIST_HEAD_INIT(struct mempool_slot, p->free_slots); - p->free_slots = pa_flist_new(p->n_blocks*2); + memset(&p->stat, 0, sizeof(p->stat)); return p; } @@ -649,62 +477,34 @@ pa_mempool* pa_mempool_new(int shared) { void pa_mempool_free(pa_mempool *p) { assert(p); - pa_mutex_lock(p->mutex); - while (p->imports) pa_memimport_free(p->imports); while (p->exports) pa_memexport_free(p->exports); - pa_mutex_unlock(p->mutex); - - if (pa_atomic_load(&p->stat.n_allocated) > 0) + if (AO_load_acquire_read(&p->stat.n_allocated) > 0) pa_log_warn("WARNING! Memory pool destroyed but not all memory blocks freed!"); - - pa_flist_free(p->free_slots, NULL); pa_shm_free(&p->memory); - - pa_mutex_free(p->mutex); - pa_cond_free(p->cond); - pa_xfree(p); } -/* No lock necessary */ const pa_mempool_stat* pa_mempool_get_stat(pa_mempool *p) { assert(p); return &p->stat; } -/* No lock necessary */ void pa_mempool_vacuum(pa_mempool *p) { struct mempool_slot *slot; - pa_flist *list; assert(p); - list = pa_flist_new(p->n_blocks*2); - - while ((slot = pa_flist_pop(p->free_slots))) - while (pa_flist_push(list, slot) < 0) - ; - - while ((slot = pa_flist_pop(list))) { - pa_shm_punch(&p->memory, - (uint8_t*) slot - (uint8_t*) p->memory.ptr + sizeof(struct mempool_slot), - p->block_size - sizeof(struct mempool_slot)); - - while (pa_flist_push(p->free_slots, slot)) - ; - } - - pa_flist_free(list, NULL); + for (slot = p->free_slots; slot; slot = slot->next) + pa_shm_punch(&p->memory, (uint8_t*) slot + sizeof(struct mempool_slot) - (uint8_t*) p->memory.ptr, p->block_size - sizeof(struct mempool_slot)); } -/* No lock necessary */ int pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id) { assert(p); @@ -716,7 +516,6 @@ int pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id) { return 0; } -/* No lock necessary */ int pa_mempool_is_shared(pa_mempool *p) { assert(p); @@ -731,23 +530,18 @@ pa_memimport* pa_memimport_new(pa_mempool *p, pa_memimport_release_cb_t cb, void assert(cb); i = pa_xnew(pa_memimport, 1); - i->mutex = pa_mutex_new(0); i->pool = p; i->segments = pa_hashmap_new(NULL, NULL); i->blocks = pa_hashmap_new(NULL, NULL); i->release_cb = cb; i->userdata = userdata; - - pa_mutex_lock(p->mutex); + PA_LLIST_PREPEND(pa_memimport, p->imports, i); - pa_mutex_unlock(p->mutex); - return i; } static void memexport_revoke_blocks(pa_memexport *e, pa_memimport *i); -/* Should be called locked */ static pa_memimport_segment* segment_attach(pa_memimport *i, uint32_t shm_id) { pa_memimport_segment* seg; @@ -768,7 +562,6 @@ static pa_memimport_segment* segment_attach(pa_memimport *i, uint32_t shm_id) { return seg; } -/* Should be called locked */ static void segment_detach(pa_memimport_segment *seg) { assert(seg); @@ -777,68 +570,51 @@ static void segment_detach(pa_memimport_segment *seg) { pa_xfree(seg); } -/* Self-locked. Not multiple-caller safe */ void pa_memimport_free(pa_memimport *i) { pa_memexport *e; pa_memblock *b; assert(i); - pa_mutex_lock(i->mutex); + /* If we've exported this block further we need to revoke that export */ + for (e = i->pool->exports; e; e = e->next) + memexport_revoke_blocks(e, i); while ((b = pa_hashmap_get_first(i->blocks))) memblock_replace_import(b); assert(pa_hashmap_size(i->segments) == 0); - - pa_mutex_unlock(i->mutex); - - pa_mutex_lock(i->pool->mutex); - - /* If we've exported this block further we need to revoke that export */ - for (e = i->pool->exports; e; e = e->next) - memexport_revoke_blocks(e, i); - PA_LLIST_REMOVE(pa_memimport, i->pool->imports, i); - - pa_mutex_unlock(i->pool->mutex); - pa_hashmap_free(i->blocks, NULL, NULL); pa_hashmap_free(i->segments, NULL, NULL); - - pa_mutex_free(i->mutex); + PA_LLIST_REMOVE(pa_memimport, i->pool->imports, i); pa_xfree(i); } -/* Self-locked */ pa_memblock* pa_memimport_get(pa_memimport *i, uint32_t block_id, uint32_t shm_id, size_t offset, size_t size) { - pa_memblock *b = NULL; + pa_memblock *b; pa_memimport_segment *seg; assert(i); - pa_mutex_lock(i->mutex); - if (pa_hashmap_size(i->blocks) >= PA_MEMIMPORT_SLOTS_MAX) - goto finish; + return NULL; if (!(seg = pa_hashmap_get(i->segments, PA_UINT32_TO_PTR(shm_id)))) if (!(seg = segment_attach(i, shm_id))) - goto finish; + return NULL; if (offset+size > seg->memory.size) - goto finish; - + return NULL; + b = pa_xnew(pa_memblock, 1); - PA_REFCNT_INIT(b); - b->pool = i->pool; b->type = PA_MEMBLOCK_IMPORTED; b->read_only = 1; - pa_atomic_ptr_store(&b->data, (uint8_t*) seg->memory.ptr + offset); + PA_REFCNT_INIT(b); b->length = size; - pa_atomic_store(&b->n_acquired, 0); - pa_atomic_store(&b->please_signal, 0); + b->data = (uint8_t*) seg->memory.ptr + offset; + b->pool = i->pool; b->per_type.imported.id = block_id; b->per_type.imported.segment = seg; @@ -846,11 +622,7 @@ pa_memblock* pa_memimport_get(pa_memimport *i, uint32_t block_id, uint32_t shm_i seg->n_blocks++; -finish: - pa_mutex_unlock(i->mutex); - - if (b) - stat_add(b); + stat_add(b); return b; } @@ -859,15 +631,10 @@ int pa_memimport_process_revoke(pa_memimport *i, uint32_t id) { pa_memblock *b; assert(i); - pa_mutex_lock(i->mutex); - if (!(b = pa_hashmap_get(i->blocks, PA_UINT32_TO_PTR(id)))) return -1; memblock_replace_import(b); - - pa_mutex_unlock(i->mutex); - return 0; } @@ -882,84 +649,58 @@ pa_memexport* pa_memexport_new(pa_mempool *p, pa_memexport_revoke_cb_t cb, void return NULL; e = pa_xnew(pa_memexport, 1); - e->mutex = pa_mutex_new(1); e->pool = p; PA_LLIST_HEAD_INIT(struct memexport_slot, e->free_slots); PA_LLIST_HEAD_INIT(struct memexport_slot, e->used_slots); e->n_init = 0; e->revoke_cb = cb; e->userdata = userdata; - - pa_mutex_lock(p->mutex); - PA_LLIST_PREPEND(pa_memexport, p->exports, e); - pa_mutex_unlock(p->mutex); + PA_LLIST_PREPEND(pa_memexport, p->exports, e); return e; } void pa_memexport_free(pa_memexport *e) { assert(e); - pa_mutex_lock(e->mutex); while (e->used_slots) pa_memexport_process_release(e, e->used_slots - e->slots); - pa_mutex_unlock(e->mutex); - pa_mutex_lock(e->pool->mutex); PA_LLIST_REMOVE(pa_memexport, e->pool->exports, e); - pa_mutex_unlock(e->pool->mutex); - pa_xfree(e); } -/* Self-locked */ int pa_memexport_process_release(pa_memexport *e, uint32_t id) { - pa_memblock *b; - assert(e); - pa_mutex_lock(e->mutex); - if (id >= e->n_init) - goto fail; + return -1; if (!e->slots[id].block) - goto fail; - - b = e->slots[id].block; - e->slots[id].block = NULL; - - PA_LLIST_REMOVE(struct memexport_slot, e->used_slots, &e->slots[id]); - PA_LLIST_PREPEND(struct memexport_slot, e->free_slots, &e->slots[id]); + return -1; - pa_mutex_unlock(e->mutex); - /* pa_log("Processing release for %u", id); */ - assert(pa_atomic_load(&e->pool->stat.n_exported) > 0); - assert(pa_atomic_load(&e->pool->stat.exported_size) >= (int) b->length); + assert(AO_load_acquire_read(&e->pool->stat.n_exported) > 0); + assert(AO_load_acquire_read(&e->pool->stat.exported_size) >= (AO_t) e->slots[id].block->length); - pa_atomic_dec(&e->pool->stat.n_exported); - pa_atomic_add(&e->pool->stat.exported_size, (int) -b->length); + AO_fetch_and_sub1_release_write(&e->pool->stat.n_exported); + AO_fetch_and_add_release_write(&e->pool->stat.exported_size, (AO_t) -e->slots[id].block->length); - pa_memblock_unref(b); + pa_memblock_unref(e->slots[id].block); + e->slots[id].block = NULL; - return 0; + PA_LLIST_REMOVE(struct memexport_slot, e->used_slots, &e->slots[id]); + PA_LLIST_PREPEND(struct memexport_slot, e->free_slots, &e->slots[id]); -fail: - pa_mutex_unlock(e->mutex); - - return -1; + return 0; } -/* Self-locked */ static void memexport_revoke_blocks(pa_memexport *e, pa_memimport *i) { struct memexport_slot *slot, *next; assert(e); assert(i); - pa_mutex_lock(e->mutex); - for (slot = e->used_slots; slot; slot = next) { uint32_t idx; next = slot->next; @@ -972,11 +713,8 @@ static void memexport_revoke_blocks(pa_memexport *e, pa_memimport *i) { e->revoke_cb(e, idx, e->userdata); pa_memexport_process_release(e, idx); } - - pa_mutex_unlock(e->mutex); } -/* No lock necessary */ static pa_memblock *memblock_shared_copy(pa_mempool *p, pa_memblock *b) { pa_memblock *n; @@ -993,16 +731,13 @@ static pa_memblock *memblock_shared_copy(pa_mempool *p, pa_memblock *b) { if (!(n = pa_memblock_new_pool(p, b->length))) return NULL; - memcpy(pa_atomic_ptr_load(&n->data), pa_atomic_ptr_load(&b->data), b->length); + memcpy(n->data, b->data, b->length); return n; } -/* Self-locked */ int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32_t *shm_id, size_t *offset, size_t * size) { pa_shm *memory; struct memexport_slot *slot; - void *data; - size_t length; assert(e); assert(b); @@ -1015,15 +750,12 @@ int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32 if (!(b = memblock_shared_copy(e->pool, b))) return -1; - pa_mutex_lock(e->mutex); - if (e->free_slots) { slot = e->free_slots; PA_LLIST_REMOVE(struct memexport_slot, e->free_slots, slot); - } else if (e->n_init < PA_MEMEXPORT_SLOTS_MAX) + } else if (e->n_init < PA_MEMEXPORT_SLOTS_MAX) { slot = &e->slots[e->n_init++]; - else { - pa_mutex_unlock(e->mutex); + } else { pa_memblock_unref(b); return -1; } @@ -1032,11 +764,8 @@ int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32 slot->block = b; *block_id = slot - e->slots; - pa_mutex_unlock(e->mutex); /* pa_log("Got block id %u", *block_id); */ - data = pa_memblock_acquire(b); - if (b->type == PA_MEMBLOCK_IMPORTED) { assert(b->per_type.imported.segment); memory = &b->per_type.imported.segment->memory; @@ -1046,17 +775,15 @@ int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32 memory = &b->pool->memory; } - assert(data >= memory->ptr); - assert((uint8_t*) data + length <= (uint8_t*) memory->ptr + memory->size); + assert(b->data >= memory->ptr); + assert((uint8_t*) b->data + b->length <= (uint8_t*) memory->ptr + memory->size); *shm_id = memory->id; - *offset = (uint8_t*) data - (uint8_t*) memory->ptr; - *size = length; + *offset = (uint8_t*) b->data - (uint8_t*) memory->ptr; + *size = b->length; - pa_memblock_release(b); - - pa_atomic_inc(&e->pool->stat.n_exported); - pa_atomic_add(&e->pool->stat.exported_size, (int) length); + AO_fetch_and_add1_release_write(&e->pool->stat.n_exported); + AO_fetch_and_add_release_write(&e->pool->stat.exported_size, (AO_t) b->length); return 0; } diff --git a/src/pulsecore/memblock.h b/src/pulsecore/memblock.h index 9937818f..d4f2b7aa 100644 --- a/src/pulsecore/memblock.h +++ b/src/pulsecore/memblock.h @@ -25,7 +25,6 @@ #include #include -#include #include #include @@ -55,25 +54,45 @@ typedef struct pa_memexport pa_memexport; typedef void (*pa_memimport_release_cb_t)(pa_memimport *i, uint32_t block_id, void *userdata); typedef void (*pa_memexport_revoke_cb_t)(pa_memexport *e, uint32_t block_id, void *userdata); +struct pa_memblock { + pa_memblock_type_t type; + int read_only; /* boolean */ + PA_REFCNT_DECLARE; /* the reference counter */ + size_t length; + void *data; + pa_mempool *pool; + + union { + struct { + void (*free_cb)(void *p); /* If type == PA_MEMBLOCK_USER this points to a function for freeing this memory block */ + } user; + + struct { + uint32_t id; + pa_memimport_segment *segment; + } imported; + } per_type; +}; + /* Please note that updates to this structure are not locked, * i.e. n_allocated might be updated at a point in time where * n_accumulated is not yet. Take these values with a grain of salt, - * they are here for purely statistical reasons.*/ + * threy are here for purely statistical reasons.*/ struct pa_mempool_stat { - pa_atomic_int_t n_allocated; - pa_atomic_int_t n_accumulated; - pa_atomic_int_t n_imported; - pa_atomic_int_t n_exported; - pa_atomic_int_t allocated_size; - pa_atomic_int_t accumulated_size; - pa_atomic_int_t imported_size; - pa_atomic_int_t exported_size; - - pa_atomic_int_t n_too_large_for_pool; - pa_atomic_int_t n_pool_full; - - pa_atomic_int_t n_allocated_by_type[PA_MEMBLOCK_TYPE_MAX]; - pa_atomic_int_t n_accumulated_by_type[PA_MEMBLOCK_TYPE_MAX]; + AO_t n_allocated; + AO_t n_accumulated; + AO_t n_imported; + AO_t n_exported; + AO_t allocated_size; + AO_t accumulated_size; + AO_t imported_size; + AO_t exported_size; + + AO_t n_too_large_for_pool; + AO_t n_pool_full; + + AO_t n_allocated_by_type[PA_MEMBLOCK_TYPE_MAX]; + AO_t n_accumulated_by_type[PA_MEMBLOCK_TYPE_MAX]; }; /* Allocate a new memory block of type PA_MEMBLOCK_MEMPOOL or PA_MEMBLOCK_APPENDED, depending on the size */ @@ -97,17 +116,9 @@ pa_memblock* pa_memblock_ref(pa_memblock*b); /* This special unref function has to be called by the owner of the memory of a static memory block when he wants to release all references to the memory. This causes the memory to be copied and -converted into a pool or malloc'ed memory block. Please note that this -function is not multiple caller safe, i.e. needs to be locked -manually if called from more than one thread at the same time. */ +converted into a PA_MEMBLOCK_DYNAMIC type memory block */ void pa_memblock_unref_fixed(pa_memblock*b); -int pa_memblock_is_read_only(pa_memblock *b); -void* pa_memblock_acquire(pa_memblock *b); -void pa_memblock_release(pa_memblock *b); -size_t pa_memblock_get_length(pa_memblock *b); -pa_mempool * pa_memblock_get_pool(pa_memblock *b); - /* The memory block manager */ pa_mempool* pa_mempool_new(int shared); void pa_mempool_free(pa_mempool *p); diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index dab44dc3..e6b73fc5 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -176,7 +176,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { assert(uchunk); assert(uchunk->memblock); assert(uchunk->length > 0); - assert(uchunk->index + uchunk->length <= pa_memblock_get_length(uchunk->memblock)); + assert(uchunk->index + uchunk->length <= uchunk->memblock->length); if (uchunk->length % bq->base) return -1; @@ -360,8 +360,8 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { if (bq->silence) { chunk->memblock = pa_memblock_ref(bq->silence); - if (!length || length > pa_memblock_get_length(chunk->memblock)) - length = pa_memblock_get_length(chunk->memblock); + if (!length || length > chunk->memblock->length) + length = chunk->memblock->length; chunk->length = length; } else { @@ -413,8 +413,8 @@ void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length if (bq->silence) { - if (!l || l > pa_memblock_get_length(bq->silence)) - l = pa_memblock_get_length(bq->silence); + if (!l || l > bq->silence->length) + l = bq->silence->length; } diff --git a/src/pulsecore/memchunk.c b/src/pulsecore/memchunk.c index 55c4bfa7..1dbad2b9 100644 --- a/src/pulsecore/memchunk.c +++ b/src/pulsecore/memchunk.c @@ -35,25 +35,22 @@ void pa_memchunk_make_writable(pa_memchunk *c, size_t min) { pa_memblock *n; size_t l; - void *tdata, *sdata; assert(c); assert(c->memblock); + assert(PA_REFCNT_VALUE(c->memblock) > 0); - if (pa_memblock_is_read_only(c->memblock) && - pa_memblock_get_length(c->memblock) >= c->index+min) + if (PA_REFCNT_VALUE(c->memblock) == 1 && + !c->memblock->read_only && + c->memblock->length >= c->index+min) return; l = c->length; if (l < min) l = min; - n = pa_memblock_new(pa_memblock_get_pool(c->memblock), l); - tdata = pa_memblock_acquire(n); - sdata = pa_memblock_acquire(c->memblock); - memcpy(tdata, (uint8_t*) sdata + c->index, c->length); - pa_memblock_release(n); - pa_memblock_release(c->memblock); + n = pa_memblock_new(c->memblock->pool, l); + memcpy(n->data, (uint8_t*) c->memblock->data + c->index, c->length); pa_memblock_unref(c->memblock); c->memblock = n; c->index = 0; diff --git a/src/pulsecore/play-memchunk.c b/src/pulsecore/play-memchunk.c index b711c98c..cde6a9ee 100644 --- a/src/pulsecore/play-memchunk.c +++ b/src/pulsecore/play-memchunk.c @@ -55,7 +55,7 @@ static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { if (c->length <= 0) return -1; - assert(c->memblock); + assert(c->memblock && c->memblock->length); *chunk = *c; pa_memblock_ref(c->memblock); diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 65b93eb4..80aeb27b 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -891,22 +891,14 @@ static int do_read(struct connection *c) { } } else if (c->state == ESD_CACHING_SAMPLE) { ssize_t r; - void *p; - assert(c->scache.memchunk.memblock); - assert(c->scache.name); - assert(c->scache.memchunk.index < c->scache.memchunk.length); - - p = pa_memblock_acquire(c->scache.memchunk.memblock); + assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); - if ((r = pa_iochannel_read(c->io, (uint8_t*) p+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { - pa_memblock_release(c->scache.memchunk.memblock); + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } - pa_memblock_release(c->scache.memchunk.memblock); - c->scache.memchunk.index += r; assert(c->scache.memchunk.index <= c->scache.memchunk.length); @@ -933,7 +925,6 @@ static int do_read(struct connection *c) { pa_memchunk chunk; ssize_t r; size_t l; - void *p; assert(c->input_memblockq); @@ -946,7 +937,7 @@ static int do_read(struct connection *c) { l = c->playback.fragment_size; if (c->playback.current_memblock) - if (pa_memblock_get_length(c->playback.current_memblock) - c->playback.memblock_index < l) { + if (c->playback.current_memblock->length - c->playback.memblock_index < l) { pa_memblock_unref(c->playback.current_memblock); c->playback.current_memblock = NULL; c->playback.memblock_index = 0; @@ -954,21 +945,15 @@ static int do_read(struct connection *c) { if (!c->playback.current_memblock) { c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, c->playback.fragment_size*2); - assert(c->playback.current_memblock); - assert(pa_memblock_get_length(c->playback.current_memblock) >= l); + assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); c->playback.memblock_index = 0; } - p = pa_memblock_acquire(c->playback.current_memblock); - - if ((r = pa_iochannel_read(c->io, (uint8_t*) p+c->playback.memblock_index, l)) <= 0) { - pa_memblock_release(c->playback.current_memblock); + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } - - pa_memblock_release(c->playback.current_memblock); - + chunk.memblock = c->playback.current_memblock; chunk.index = c->playback.memblock_index; chunk.length = r; @@ -1005,26 +990,19 @@ static int do_write(struct connection *c) { } else if (c->state == ESD_STREAMING_DATA && c->source_output) { pa_memchunk chunk; ssize_t r; - void *p; assert(c->output_memblockq); if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) return 0; - assert(chunk.memblock); - assert(chunk.length); - - p = pa_memblock_acquire(chunk.memblock); + assert(chunk.memblock && chunk.length); - if ((r = pa_iochannel_write(c->io, (uint8_t*) p+chunk.index, chunk.length)) < 0) { - pa_memblock_release(chunk.memblock); + if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { pa_memblock_unref(chunk.memblock); pa_log("write(): %s", pa_cstrerror(errno)); return -1; } - pa_memblock_release(chunk.memblock); - pa_memblockq_drop(c->output_memblockq, &chunk, r); pa_memblock_unref(chunk.memblock); diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index fba611d7..38c024b7 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -2274,7 +2274,6 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o } else { struct upload_stream *u = (struct upload_stream*) stream; size_t l; - assert(u->type == UPLOAD_STREAM); if (!u->memchunk.memblock) { @@ -2294,18 +2293,9 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o if (l > chunk->length) l = chunk->length; - if (l > 0) { - void *src, *dst; - dst = pa_memblock_acquire(u->memchunk.memblock); - src = pa_memblock_acquire(chunk->memblock); - - memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length, - (uint8_t*) src+chunk->index, l); - - pa_memblock_release(u->memchunk.memblock); - pa_memblock_release(chunk->memblock); - + memcpy((uint8_t*) u->memchunk.memblock->data + u->memchunk.index + u->memchunk.length, + (uint8_t*) chunk->memblock->data+chunk->index, l); u->memchunk.length += l; u->length -= l; } diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c index bf203e42..6bfba875 100644 --- a/src/pulsecore/protocol-simple.c +++ b/src/pulsecore/protocol-simple.c @@ -113,7 +113,6 @@ static int do_read(struct connection *c) { pa_memchunk chunk; ssize_t r; size_t l; - void *p; if (!c->sink_input || !(l = pa_memblockq_missing(c->input_memblockq))) return 0; @@ -122,7 +121,7 @@ static int do_read(struct connection *c) { l = c->playback.fragment_size; if (c->playback.current_memblock) - if (pa_memblock_get_length(c->playback.current_memblock) - c->playback.memblock_index < l) { + if (c->playback.current_memblock->length - c->playback.memblock_index < l) { pa_memblock_unref(c->playback.current_memblock); c->playback.current_memblock = NULL; c->playback.memblock_index = 0; @@ -130,20 +129,15 @@ static int do_read(struct connection *c) { if (!c->playback.current_memblock) { c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, c->playback.fragment_size*2); - assert(c->playback.current_memblock); - assert(pa_memblock_get_length(c->playback.current_memblock) >= l); + assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); c->playback.memblock_index = 0; } - - p = pa_memblock_acquire(c->playback.current_memblock); - if ((r = pa_iochannel_read(c->io, (uint8_t*) p + c->playback.memblock_index, l)) <= 0) { - pa_memblock_release(c->playback.current_memblock); + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { pa_log_debug("read(): %s", r == 0 ? "EOF" : pa_cstrerror(errno)); return -1; } - pa_memblock_release(c->playback.current_memblock); chunk.memblock = c->playback.current_memblock; chunk.index = c->playback.memblock_index; chunk.length = r; @@ -162,8 +156,7 @@ static int do_read(struct connection *c) { static int do_write(struct connection *c) { pa_memchunk chunk; ssize_t r; - void *p; - + if (!c->source_output) return 0; @@ -172,17 +165,12 @@ static int do_write(struct connection *c) { return 0; assert(chunk.memblock && chunk.length); - - p = pa_memblock_acquire(chunk.memblock); - if ((r = pa_iochannel_write(c->io, (uint8_t*) p+chunk.index, chunk.length)) < 0) { - pa_memblock_release(chunk.memblock); + if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { pa_memblock_unref(chunk.memblock); pa_log("write(): %s", pa_cstrerror(errno)); return -1; } - - pa_memblock_release(chunk.memblock); pa_memblockq_drop(c->output_memblockq, &chunk, r); pa_memblock_unref(chunk.memblock); diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index 33963796..566fb060 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -48,7 +48,6 @@ #include #include #include -#include #include "pstream.h" @@ -114,11 +113,10 @@ struct pa_pstream { PA_REFCNT_DECLARE; pa_mainloop_api *mainloop; + pa_defer_event *defer_event; pa_iochannel *io; - pa_queue *send_queue; - pa_mutex *mutex; /* only for access to the queue */ - pa_anotify *anotify; + pa_mutex *mutex; int dead; @@ -128,7 +126,6 @@ struct pa_pstream { uint32_t shm_info[PA_PSTREAM_SHM_MAX]; void *data; size_t index; - pa_memchunk memchunk; } write; struct { @@ -173,6 +170,10 @@ static void do_something(pa_pstream *p) { pa_pstream_ref(p); + pa_mutex_lock(p->mutex); + + p->mainloop->defer_enable(p->defer_event, 0); + if (!p->dead && pa_iochannel_is_readable(p->io)) { if (do_read(p) < 0) goto fail; @@ -184,6 +185,8 @@ static void do_something(pa_pstream *p) { goto fail; } + pa_mutex_unlock(p->mutex); + pa_pstream_unref(p); return; @@ -194,6 +197,8 @@ fail: if (p->die_callback) p->die_callback(p, p->die_callback_userdata); + pa_mutex_unlock(p->mutex); + pa_pstream_unref(p); } @@ -206,10 +211,13 @@ static void io_callback(pa_iochannel*io, void *userdata) { do_something(p); } -static void anotify_callback(uint8_t event, void *userdata) { +static void defer_callback(pa_mainloop_api *m, pa_defer_event *e, void*userdata) { pa_pstream *p = userdata; assert(p); + assert(p->defer_event == e); + assert(p->mainloop == m); + do_something(p); } @@ -229,16 +237,16 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *poo p->dead = 0; p->mutex = pa_mutex_new(1); - p->anotify = pa_anotify_new(m, anotify_callback, p); p->mainloop = m; + p->defer_event = m->defer_new(m, defer_callback, p); + m->defer_enable(p->defer_event, 0); p->send_queue = pa_queue_new(); assert(p->send_queue); p->write.current = NULL; p->write.index = 0; - pa_memchunk_reset(&p->write.memchunk); p->read.memblock = NULL; p->read.packet = NULL; p->read.index = 0; @@ -301,15 +309,9 @@ static void pstream_free(pa_pstream *p) { if (p->read.packet) pa_packet_unref(p->read.packet); - if (p->write.memchunk.memblock) - pa_memblock_unref(p->write.memchunk.memblock); - if (p->mutex) pa_mutex_free(p->mutex); - if (p->anotify) - pa_anotify_free(p->anotify); - pa_xfree(p); } @@ -320,6 +322,11 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *cre assert(PA_REFCNT_VALUE(p) > 0); assert(packet); + pa_mutex_lock(p->mutex); + + if (p->dead) + goto finish; + i = pa_xnew(struct item_info, 1); i->type = PA_PSTREAM_ITEM_PACKET; i->packet = pa_packet_ref(packet); @@ -329,11 +336,12 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *cre i->creds = *creds; #endif - pa_mutex_lock(p->mutex); pa_queue_push(p->send_queue, i); + p->mainloop->defer_enable(p->defer_event, 1); + +finish: + pa_mutex_unlock(p->mutex); - - pa_anotify_signal(p->anotify, 0); } void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek_mode, const pa_memchunk *chunk) { @@ -344,6 +352,12 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa assert(channel != (uint32_t) -1); assert(chunk); + pa_mutex_lock(p->mutex); + + if (p->dead) + goto finish; + + length = chunk->length; idx = 0; while (length > 0) { @@ -365,15 +379,17 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa i->with_creds = 0; #endif - pa_mutex_lock(p->mutex); pa_queue_push(p->send_queue, i); - pa_mutex_unlock(p->mutex); idx += n; length -= n; } + + p->mainloop->defer_enable(p->defer_event, 1); - pa_anotify_signal(p->anotify, 0); +finish: + + pa_mutex_unlock(p->mutex); } static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userdata) { @@ -383,6 +399,11 @@ static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userd assert(p); assert(PA_REFCNT_VALUE(p) > 0); + pa_mutex_lock(p->mutex); + + if (p->dead) + goto finish; + /* pa_log("Releasing block %u", block_id); */ item = pa_xnew(struct item_info, 1); @@ -392,11 +413,12 @@ static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userd item->with_creds = 0; #endif - pa_mutex_lock(p->mutex); pa_queue_push(p->send_queue, item); - pa_mutex_unlock(p->mutex); + p->mainloop->defer_enable(p->defer_event, 1); - pa_anotify_signal(p->anotify, 0); +finish: + + pa_mutex_unlock(p->mutex); } static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userdata) { @@ -406,6 +428,11 @@ static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userda assert(p); assert(PA_REFCNT_VALUE(p) > 0); + pa_mutex_lock(p->mutex); + + if (p->dead) + goto finish; + /* pa_log("Revoking block %u", block_id); */ item = pa_xnew(struct item_info, 1); @@ -415,27 +442,23 @@ static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userda item->with_creds = 0; #endif - pa_mutex_lock(p->mutex); pa_queue_push(p->send_queue, item); - pa_mutex_unlock(p->mutex); + p->mainloop->defer_enable(p->defer_event, 1); - pa_anotify_signal(p->anotify, 0); +finish: + + pa_mutex_unlock(p->mutex); } static void prepare_next_write_item(pa_pstream *p) { assert(p); assert(PA_REFCNT_VALUE(p) > 0); - pa_mutex_lock(p->mutex); - p->write.current = pa_queue_pop(p->send_queue); - pa_mutex_unlock(p->mutex); - - if (!p->write.current) + if (!(p->write.current = pa_queue_pop(p->send_queue))) return; p->write.index = 0; p->write.data = NULL; - pa_memchunk_reset(&p->write.memchunk); p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = 0; p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl((uint32_t) -1); @@ -502,9 +525,7 @@ static void prepare_next_write_item(pa_pstream *p) { if (send_payload) { p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length); - p->write.memchunk = p->write.current->chunk; - pa_memblock_ref(p->write.memchunk.memblock); - p->write.data = NULL; + p->write.data = (uint8_t*) p->write.current->chunk.memblock->data + p->write.current->chunk.index; } p->write.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS] = htonl(flags); @@ -520,7 +541,6 @@ static int do_write(pa_pstream *p) { void *d; size_t l; ssize_t r; - pa_memblock *release_memblock = NULL; assert(p); assert(PA_REFCNT_VALUE(p) > 0); @@ -535,16 +555,9 @@ static int do_write(pa_pstream *p) { d = (uint8_t*) p->write.descriptor + p->write.index; l = PA_PSTREAM_DESCRIPTOR_SIZE - p->write.index; } else { - assert(p->write.data || p->write.memchunk.memblock); - - if (p->write.data) - d = p->write.data; - else { - d = (uint8_t*) pa_memblock_acquire(p->write.memchunk.memblock) + p->write.memchunk.index; - release_memblock = p->write.memchunk.memblock; - } + assert(p->write.data); - d = (uint8_t*) d + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE; + d = (uint8_t*) p->write.data + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE; l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE); } @@ -554,17 +567,14 @@ static int do_write(pa_pstream *p) { if (p->send_creds_now) { if ((r = pa_iochannel_write_with_creds(p->io, d, l, &p->write_creds)) < 0) - goto fail; + return -1; p->send_creds_now = 0; } else #endif if ((r = pa_iochannel_write(p->io, d, l)) < 0) - goto fail; - - if (release_memblock) - pa_memblock_release(release_memblock); + return -1; p->write.index += r; @@ -578,20 +588,12 @@ static int do_write(pa_pstream *p) { } return 0; - -fail: - - if (release_memblock) - pa_memblock_release(release_memblock); - - return -1; } static int do_read(pa_pstream *p) { void *d; size_t l; ssize_t r; - pa_memblock *release_memblock = NULL; assert(p); assert(PA_REFCNT_VALUE(p) > 0); @@ -600,16 +602,8 @@ static int do_read(pa_pstream *p) { d = (uint8_t*) p->read.descriptor + p->read.index; l = PA_PSTREAM_DESCRIPTOR_SIZE - p->read.index; } else { - assert(p->read.data || p->read.memblock); - - if (p->read.data) - d = p->read.data; - else { - d = pa_memblock_acquire(p->read.memblock); - release_memblock = p->read.memblock; - } - - d = (uint8_t*) d + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE; + assert(p->read.data); + d = (uint8_t*) p->read.data + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE; l = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE); } @@ -618,17 +612,14 @@ static int do_read(pa_pstream *p) { int b = 0; if ((r = pa_iochannel_read_with_creds(p->io, d, l, &p->read_creds, &b)) <= 0) - goto fail; + return -1; p->read_creds_valid = p->read_creds_valid || b; } #else if ((r = pa_iochannel_read(p->io, d, l)) <= 0) - goto fail; + return -1; #endif - - if (release_memblock) - pa_memblock_release(release_memblock); p->read.index += r; @@ -710,7 +701,7 @@ static int do_read(pa_pstream *p) { /* Frame is a memblock frame */ p->read.memblock = pa_memblock_new(p->mempool, length); - p->read.data = NULL; + p->read.data = p->read.memblock->data; } else { pa_log_warn("Recieved memblock frame with invalid flags value."); @@ -797,7 +788,7 @@ static int do_read(pa_pstream *p) { chunk.memblock = b; chunk.index = 0; - chunk.length = pa_memblock_get_length(b); + chunk.length = b->length; offset = (int64_t) ( (((uint64_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])) << 32) | @@ -825,51 +816,52 @@ frame_done: p->read.memblock = NULL; p->read.packet = NULL; p->read.index = 0; - p->read.data = NULL; #ifdef HAVE_CREDS p->read_creds_valid = 0; #endif return 0; - -fail: - if (release_memblock) - pa_memblock_release(release_memblock); - - return -1; } void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) { assert(p); assert(PA_REFCNT_VALUE(p) > 0); + pa_mutex_lock(p->mutex); p->die_callback = cb; p->die_callback_userdata = userdata; + pa_mutex_unlock(p->mutex); } void pa_pstream_set_drain_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) { assert(p); assert(PA_REFCNT_VALUE(p) > 0); + pa_mutex_lock(p->mutex); p->drain_callback = cb; p->drain_callback_userdata = userdata; + pa_mutex_unlock(p->mutex); } void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata) { assert(p); assert(PA_REFCNT_VALUE(p) > 0); + pa_mutex_lock(p->mutex); p->recieve_packet_callback = cb; p->recieve_packet_callback_userdata = userdata; + pa_mutex_unlock(p->mutex); } void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, pa_pstream_memblock_cb_t cb, void *userdata) { assert(p); assert(PA_REFCNT_VALUE(p) > 0); + pa_mutex_lock(p->mutex); p->recieve_memblock_callback = cb; p->recieve_memblock_callback_userdata = userdata; + pa_mutex_unlock(p->mutex); } int pa_pstream_is_pending(pa_pstream *p) { @@ -909,6 +901,8 @@ pa_pstream* pa_pstream_ref(pa_pstream*p) { void pa_pstream_close(pa_pstream *p) { assert(p); + pa_mutex_lock(p->mutex); + p->dead = 1; if (p->import) { @@ -926,16 +920,25 @@ void pa_pstream_close(pa_pstream *p) { p->io = NULL; } + if (p->defer_event) { + p->mainloop->defer_free(p->defer_event); + p->defer_event = NULL; + } + p->die_callback = NULL; p->drain_callback = NULL; p->recieve_packet_callback = NULL; p->recieve_memblock_callback = NULL; + + pa_mutex_unlock(p->mutex); } void pa_pstream_use_shm(pa_pstream *p, int enable) { assert(p); assert(PA_REFCNT_VALUE(p) > 0); + pa_mutex_lock(p->mutex); + p->use_shm = enable; if (enable) { @@ -950,4 +953,6 @@ void pa_pstream_use_shm(pa_pstream *p, int enable) { p->export = NULL; } } + + pa_mutex_unlock(p->mutex); } diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index c28c2fb3..b0142049 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -51,7 +51,8 @@ struct pa_resampler { }; struct impl_libsamplerate { - pa_memchunk buf1, buf2, buf3, buf4; + pa_memblock *buf1_block, *buf2_block, *buf3_block, *buf4_block; + float* buf1, *buf2, *buf3, *buf4; unsigned buf1_samples, buf2_samples, buf3_samples, buf4_samples; pa_convert_to_float32ne_func_t to_float32ne_func; @@ -223,14 +224,14 @@ static void libsamplerate_free(pa_resampler *r) { if (u->src_state) src_delete(u->src_state); - if (u->buf1.memblock) - pa_memblock_unref(u->buf1.memblock); - if (u->buf2.memblock) - pa_memblock_unref(u->buf2.memblock); - if (u->buf3.memblock) - pa_memblock_unref(u->buf3.memblock); - if (u->buf4.memblock) - pa_memblock_unref(u->buf4.memblock); + if (u->buf1_block) + pa_memblock_unref(u->buf1_block); + if (u->buf2_block) + pa_memblock_unref(u->buf2_block); + if (u->buf3_block) + pa_memblock_unref(u->buf3_block); + if (u->buf4_block) + pa_memblock_unref(u->buf4_block); pa_xfree(u); } @@ -269,80 +270,64 @@ static void calc_map_table(pa_resampler *r) { } } -static pa_memchunk* convert_to_float(pa_resampler *r, pa_memchunk *input) { +static float * convert_to_float(pa_resampler *r, void *input, unsigned n_frames) { struct impl_libsamplerate *u; unsigned n_samples; - void *src, *dst; assert(r); assert(input); - assert(input->memblock); - assert(r->impl_data); u = r->impl_data; /* Convert the incoming sample into floats and place them in buf1 */ - if (!u->to_float32ne_func || !input->length) + if (!u->to_float32ne_func) return input; - n_samples = (input->length / r->i_fz) * r->i_ss.channels; + n_samples = n_frames * r->i_ss.channels; - if (!u->buf1.memblock || u->buf1_samples < n_samples) { - if (u->buf1.memblock) - pa_memblock_unref(u->buf1.memblock); + if (u->buf1_samples < n_samples) { + if (u->buf1_block) + pa_memblock_unref(u->buf1_block); u->buf1_samples = n_samples; - u->buf1.memblock = pa_memblock_new(r->mempool, u->buf1.length = sizeof(float) * n_samples); - u->buf1.index = 0; + u->buf1_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples); + u->buf1 = u->buf1_block->data; } + + u->to_float32ne_func(n_samples, input, u->buf1); - src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index; - dst = (uint8_t*) pa_memblock_acquire(u->buf1.memblock); - u->to_float32ne_func(n_samples, src, dst); - pa_memblock_release(input->memblock); - pa_memblock_release(u->buf1.memblock); - - u->buf1.length = sizeof(float) * n_samples; - - return &u->buf1; + return u->buf1; } -static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { +static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) { struct impl_libsamplerate *u; - unsigned n_samples, n_frames; + unsigned n_samples; int i_skip, o_skip; unsigned oc; - float *src, *dst; assert(r); assert(input); - assert(input->memblock); - assert(r->impl_data); u = r->impl_data; /* Remap channels and place the result int buf2 */ - if (!u->map_required || !input->length) + if (!u->map_required) return input; - n_samples = input->length / sizeof(float); - n_frames = n_samples / r->o_ss.channels; + n_samples = n_frames * r->o_ss.channels; - if (!u->buf2.memblock || u->buf2_samples < n_samples) { - if (u->buf2.memblock) - pa_memblock_unref(u->buf2.memblock); + if (u->buf2_samples < n_samples) { + if (u->buf2_block) + pa_memblock_unref(u->buf2_block); u->buf2_samples = n_samples; - u->buf2.memblock = pa_memblock_new(r->mempool, u->buf2.length = sizeof(float) * n_samples); - u->buf2.index = 0; + u->buf2_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples); + u->buf2 = u->buf2_block->data; } - src = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index); - dst = (float*) pa_memblock_acquire(u->buf2.memblock); - - memset(dst, 0, n_samples * sizeof(float)); + memset(u->buf2, 0, n_samples * sizeof(float)); o_skip = sizeof(float) * r->o_ss.channels; i_skip = sizeof(float) * r->i_ss.channels; @@ -353,57 +338,49 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { for (i = 0; i < PA_CHANNELS_MAX && u->map_table[oc][i] >= 0; i++) oil_vectoradd_f32( - dst + oc, o_skip, - dst + oc, o_skip, - src + u->map_table[oc][i], i_skip, + u->buf2 + oc, o_skip, + u->buf2 + oc, o_skip, + input + u->map_table[oc][i], i_skip, n_frames, &one, &one); } - pa_memblock_release(input->memblock); - pa_memblock_release(u->buf2.memblock); - - u->buf2.length = n_frames * sizeof(float) * r->o_ss.channels; - - return &u->buf2; + return u->buf2; } -static pa_memchunk *resample(pa_resampler *r, pa_memchunk *input) { +static float *resample(pa_resampler *r, float *input, unsigned *n_frames) { struct impl_libsamplerate *u; SRC_DATA data; - unsigned in_n_frames, in_n_samples; unsigned out_n_frames, out_n_samples; int ret; assert(r); assert(input); + assert(n_frames); assert(r->impl_data); u = r->impl_data; /* Resample the data and place the result in buf3 */ - if (!u->src_state || !input->length) + if (!u->src_state) return input; - in_n_samples = input->length / sizeof(float); - in_n_frames = in_n_samples * r->o_ss.channels; - - out_n_frames = (in_n_frames*r->o_ss.rate/r->i_ss.rate)+1024; + out_n_frames = (*n_frames*r->o_ss.rate/r->i_ss.rate)+1024; out_n_samples = out_n_frames * r->o_ss.channels; - if (!u->buf3.memblock || u->buf3_samples < out_n_samples) { - if (u->buf3.memblock) - pa_memblock_unref(u->buf3.memblock); + if (u->buf3_samples < out_n_samples) { + if (u->buf3_block) + pa_memblock_unref(u->buf3_block); u->buf3_samples = out_n_samples; - u->buf3.memblock = pa_memblock_new(r->mempool, u->buf3.length = sizeof(float) * out_n_samples); - u->buf3.index = 0; + u->buf3_block = pa_memblock_new(r->mempool, sizeof(float) * out_n_samples); + u->buf3 = u->buf3_block->data; } - data.data_in = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index); - data.input_frames = in_n_frames; + data.data_in = input; + data.input_frames = *n_frames; - data.data_out = (float*) pa_memblock_acquire(u->buf3.memblock); + data.data_out = u->buf3; data.output_frames = out_n_frames; data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate; @@ -411,20 +388,16 @@ static pa_memchunk *resample(pa_resampler *r, pa_memchunk *input) { ret = src_process(u->src_state, &data); assert(ret == 0); - assert((unsigned) data.input_frames_used == in_n_frames); + assert((unsigned) data.input_frames_used == *n_frames); - pa_memblock_release(input->memblock); - pa_memblock_release(u->buf3.memblock); - - u->buf3.length = data.output_frames_gen * sizeof(float) * r->o_ss.channels; + *n_frames = data.output_frames_gen; - return &u->buf3; + return u->buf3; } -static pa_memchunk *convert_from_float(pa_resampler *r, pa_memchunk *input) { +static void *convert_from_float(pa_resampler *r, float *input, unsigned n_frames) { struct impl_libsamplerate *u; - unsigned n_samples, n_frames; - void *src, *dst; + unsigned n_samples; assert(r); assert(input); @@ -433,35 +406,30 @@ static pa_memchunk *convert_from_float(pa_resampler *r, pa_memchunk *input) { /* Convert the data into the correct sample type and place the result in buf4 */ - if (!u->from_float32ne_func || !input->length) + if (!u->from_float32ne_func) return input; - - n_frames = input->length / sizeof(float) / r->o_ss.channels; + n_samples = n_frames * r->o_ss.channels; if (u->buf4_samples < n_samples) { - if (u->buf4.memblock) - pa_memblock_unref(u->buf4.memblock); + if (u->buf4_block) + pa_memblock_unref(u->buf4_block); u->buf4_samples = n_samples; - u->buf4.memblock = pa_memblock_new(r->mempool, u->buf4.length = r->o_fz * n_frames); - u->buf4.index = 0; + u->buf4_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples); + u->buf4 = u->buf4_block->data; } + + u->from_float32ne_func(n_samples, input, u->buf4); - src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->length; - dst = pa_memblock_acquire(u->buf4.memblock); - u->from_float32ne_func(n_samples, src, dst); - pa_memblock_release(input->memblock); - pa_memblock_release(u->buf4.memblock); - - u->buf4.length = r->o_fz * n_frames; - - return &u->buf4; + return u->buf4; } static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { struct impl_libsamplerate *u; - pa_memchunk *buf; + float *buf; + void *input, *output; + unsigned n_frames; assert(r); assert(in); @@ -473,23 +441,55 @@ static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchun u = r->impl_data; - buf = convert_to_float(r, (pa_memchunk*) in); - buf = remap_channels(r, buf); - buf = resample(r, buf); - - if (buf->length) { - buf = convert_from_float(r, buf); - *out = *buf; - - if (buf == in) - pa_memblock_ref(buf->memblock); - else - pa_memchunk_reset(buf); - } else - pa_memchunk_reset(out); - - pa_memblock_release(in->memblock); - + input = ((uint8_t*) in->memblock->data + in->index); + n_frames = in->length / r->i_fz; + assert(n_frames > 0); + + buf = convert_to_float(r, input, n_frames); + buf = remap_channels(r, buf, n_frames); + buf = resample(r, buf, &n_frames); + + if (n_frames) { + output = convert_from_float(r, buf, n_frames); + + if (output == input) { + /* Mm, no adjustment has been necessary, so let's return the original block */ + out->memblock = pa_memblock_ref(in->memblock); + out->index = in->index; + out->length = in->length; + } else { + out->length = n_frames * r->o_fz; + out->index = 0; + out->memblock = NULL; + + if (output == u->buf1) { + u->buf1 = NULL; + u->buf1_samples = 0; + out->memblock = u->buf1_block; + u->buf1_block = NULL; + } else if (output == u->buf2) { + u->buf2 = NULL; + u->buf2_samples = 0; + out->memblock = u->buf2_block; + u->buf2_block = NULL; + } else if (output == u->buf3) { + u->buf3 = NULL; + u->buf3_samples = 0; + out->memblock = u->buf3_block; + u->buf3_block = NULL; + } else if (output == u->buf4) { + u->buf4 = NULL; + u->buf4_samples = 0; + out->memblock = u->buf4_block; + u->buf4_block = NULL; + } + + assert(out->memblock); + } + } else { + out->memblock = NULL; + out->index = out->length = 0; + } } static void libsamplerate_update_input_rate(pa_resampler *r, uint32_t rate) { @@ -516,10 +516,8 @@ static int libsamplerate_init(pa_resampler *r) { r->impl_data = u = pa_xnew(struct impl_libsamplerate, 1); - pa_memchunk_reset(&u->buf1); - pa_memchunk_reset(&u->buf2); - pa_memchunk_reset(&u->buf3); - pa_memchunk_reset(&u->buf4); + u->buf1 = u->buf2 = u->buf3 = u->buf4 = NULL; + u->buf1_block = u->buf2_block = u->buf3_block = u->buf4_block = NULL; u->buf1_samples = u->buf2_samples = u->buf3_samples = u->buf4_samples = 0; if (r->i_ss.format == PA_SAMPLE_FLOAT32NE) @@ -580,16 +578,12 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out /* Do real resampling */ size_t l; unsigned o_index; - void *src, *dst; /* The length of the new memory block rounded up */ l = ((((n_frames+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz; out->index = 0; out->memblock = pa_memblock_new(r->mempool, l); - - src = (uint8_t*) pa_memblock_acquire(in->memblock) + in->index; - dst = pa_memblock_acquire(out->memblock); for (o_index = 0;; o_index++, u->o_counter++) { unsigned j; @@ -600,16 +594,13 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out if (j >= n_frames) break; - assert(o_index*fz < pa_memblock_get_length(out->memblock)); + assert(o_index*fz < out->memblock->length); - memcpy((uint8_t*) dst + fz*o_index, - (uint8_t*) src + fz*j, fz); + memcpy((uint8_t*) out->memblock->data + fz*o_index, + (uint8_t*) in->memblock->data + in->index + fz*j, fz); } - - pa_memblock_release(in->memblock); - pa_memblock_release(out->memblock); - + out->length = o_index*fz; } diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index 52023d31..d902b4b5 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -46,27 +46,15 @@ pa_memblock *pa_silence_memblock_new(pa_mempool *pool, const pa_sample_spec *spe } pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) { - void *data; - - assert(b); - assert(spec); - - data = pa_memblock_acquire(b); - pa_silence_memory(data, pa_memblock_get_length(b), spec); - pa_memblock_release(b); + assert(b && b->data && spec); + pa_silence_memory(b->data, b->length, spec); return b; } void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) { - void *data; - - assert(c); - assert(c->memblock); - assert(spec); + assert(c && c->memblock && c->memblock->data && spec && c->length); - data = pa_memblock_acquire(c->memblock); - pa_silence_memory((uint8_t*) data+c->index, c->length, spec); - pa_memblock_release(c->memblock); + pa_silence_memory((uint8_t*) c->memblock->data+c->index, c->length, spec); } void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { @@ -94,38 +82,26 @@ void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { } size_t pa_mix( - pa_mix_info streams[], - unsigned nstreams, - void *data, - size_t length, - const pa_sample_spec *spec, - const pa_cvolume *volume, - int mute) { - - pa_cvolume full_volume; - size_t d = 0; - unsigned k; + const pa_mix_info streams[], + unsigned nstreams, + void *data, + size_t length, + const pa_sample_spec *spec, + const pa_cvolume *volume, + int mute) { - assert(streams); - assert(data); - assert(length); - assert(spec); + assert(streams && data && length && spec); - if (!volume) - volume = pa_cvolume_reset(&full_volume, spec->channels); - - for (k = 0; k < nstreams; k++) - streams[k].internal = pa_memblock_acquire(streams[k].chunk.memblock); - switch (spec->format) { case PA_SAMPLE_S16NE:{ + size_t d; unsigned channel = 0; for (d = 0;; d += sizeof(int16_t)) { int32_t sum = 0; if (d >= length) - goto finish; + return d; if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { unsigned i; @@ -135,12 +111,12 @@ size_t pa_mix( pa_volume_t cvolume = streams[i].volume.values[channel]; if (d >= streams[i].chunk.length) - goto finish; + return d; if (cvolume == PA_VOLUME_MUTED) v = 0; else { - v = *((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d)); + v = *((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); if (cvolume != PA_VOLUME_NORM) v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); @@ -163,18 +139,17 @@ size_t pa_mix( if (++channel >= spec->channels) channel = 0; } - - break; } case PA_SAMPLE_S16RE:{ + size_t d; unsigned channel = 0; for (d = 0;; d += sizeof(int16_t)) { int32_t sum = 0; if (d >= length) - goto finish; + return d; if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { unsigned i; @@ -184,12 +159,12 @@ size_t pa_mix( pa_volume_t cvolume = streams[i].volume.values[channel]; if (d >= streams[i].chunk.length) - goto finish; + return d; if (cvolume == PA_VOLUME_MUTED) v = 0; else { - v = INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d))); + v = INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d))); if (cvolume != PA_VOLUME_NORM) v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); @@ -212,18 +187,17 @@ size_t pa_mix( if (++channel >= spec->channels) channel = 0; } - - break; } case PA_SAMPLE_U8: { + size_t d; unsigned channel = 0; for (d = 0;; d ++) { int32_t sum = 0; if (d >= length) - goto finish; + return d; if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { unsigned i; @@ -233,12 +207,12 @@ size_t pa_mix( pa_volume_t cvolume = streams[i].volume.values[channel]; if (d >= streams[i].chunk.length) - goto finish; + return d; if (cvolume == PA_VOLUME_MUTED) v = 0; else { - v = (int32_t) *((uint8_t*) streams[i].internal + streams[i].chunk.index + d) - 0x80; + v = (int32_t) *((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d) - 0x80; if (cvolume != PA_VOLUME_NORM) v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); @@ -261,18 +235,17 @@ size_t pa_mix( if (++channel >= spec->channels) channel = 0; } - - break; } case PA_SAMPLE_FLOAT32NE: { + size_t d; unsigned channel = 0; for (d = 0;; d += sizeof(float)) { float sum = 0; if (d >= length) - goto finish; + return d; if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { unsigned i; @@ -282,12 +255,12 @@ size_t pa_mix( pa_volume_t cvolume = streams[i].volume.values[channel]; if (d >= streams[i].chunk.length) - goto finish; + return d; if (cvolume == PA_VOLUME_MUTED) v = 0; else { - v = *((float*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d)); + v = *((float*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); if (cvolume != PA_VOLUME_NORM) v *= pa_sw_volume_to_linear(cvolume); @@ -306,34 +279,17 @@ size_t pa_mix( if (++channel >= spec->channels) channel = 0; } - - break; } default: pa_log_error("ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format)); abort(); } - -finish: - - for (k = 0; k < nstreams; k++) - pa_memblock_release(streams[k].chunk.memblock); - - return d; } -void pa_volume_memchunk( - pa_memchunk*c, - const pa_sample_spec *spec, - const pa_cvolume *volume) { - - void *ptr; - - assert(c); - assert(spec); - assert(c->length % pa_frame_size(spec) == 0); +void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvolume *volume) { + assert(c && spec && (c->length % pa_frame_size(spec) == 0)); assert(volume); if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM)) @@ -344,8 +300,6 @@ void pa_volume_memchunk( return; } - ptr = pa_memblock_acquire(c->memblock); - switch (spec->format) { case PA_SAMPLE_S16NE: { int16_t *d; @@ -356,7 +310,7 @@ void pa_volume_memchunk( for (channel = 0; channel < spec->channels; channel++) linear[channel] = pa_sw_volume_to_linear(volume->values[channel]); - for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { + for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { int32_t t = (int32_t)(*d); t = (int32_t) (t * linear[channel]); @@ -381,7 +335,7 @@ void pa_volume_memchunk( for (channel = 0; channel < spec->channels; channel++) linear[channel] = pa_sw_volume_to_linear(volume->values[channel]); - for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { + for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { int32_t t = (int32_t)(INT16_SWAP(*d)); t = (int32_t) (t * linear[channel]); @@ -403,7 +357,7 @@ void pa_volume_memchunk( size_t n; unsigned channel = 0; - for (d = (uint8_t*) ptr + c->index, n = c->length; n > 0; d++, n--) { + for (d = (uint8_t*) c->memblock->data + c->index, n = c->length; n > 0; d++, n--) { int32_t t = (int32_t) *d - 0x80; t = (int32_t) (t * pa_sw_volume_to_linear(volume->values[channel])); @@ -425,7 +379,7 @@ void pa_volume_memchunk( unsigned n; unsigned channel; - d = (float*) ((uint8_t*) ptr + c->index); + d = (float*) ((uint8_t*) c->memblock->data + c->index); skip = spec->channels * sizeof(float); n = c->length/sizeof(float)/spec->channels; @@ -448,7 +402,5 @@ void pa_volume_memchunk( pa_sample_format_to_string(spec->format)); abort(); } - - pa_memblock_release(c->memblock); } diff --git a/src/pulsecore/sample-util.h b/src/pulsecore/sample-util.h index 04c2f6b1..6b770792 100644 --- a/src/pulsecore/sample-util.h +++ b/src/pulsecore/sample-util.h @@ -36,11 +36,10 @@ typedef struct pa_mix_info { pa_memchunk chunk; pa_cvolume volume; void *userdata; - void *internal; /* Used internally by pa_mix(), should not be initialised when calling pa_mix() */ } pa_mix_info; size_t pa_mix( - pa_mix_info channels[], + const pa_mix_info channels[], unsigned nchannels, void *data, size_t length, diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index c3cd4952..d948f0a4 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -294,7 +294,6 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) assert(i->state == PA_SINK_INPUT_RUNNING || i->state == PA_SINK_INPUT_DRAINED); if (i->move_silence > 0) { - size_t l; /* We have just been moved and shall play some silence for a * while until the old sink has drained its playback buffer */ @@ -304,8 +303,7 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) chunk->memblock = pa_memblock_ref(i->silence_memblock); chunk->index = 0; - l = pa_memblock_get_length(chunk->memblock); - chunk->length = i->move_silence < l ? i->move_silence : l; + chunk->length = i->move_silence < chunk->memblock->length ? i->move_silence : chunk->memblock->length; ret = 0; do_volume_adj_here = 1; @@ -391,13 +389,10 @@ void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t lengt if (i->move_silence > 0) { if (chunk) { - size_t l; - l = pa_memblock_get_length(i->silence_memblock); - if (chunk->memblock != i->silence_memblock || chunk->index != 0 || - (chunk->memblock && (chunk->length != (l < i->move_silence ? l : i->move_silence)))) + (chunk->memblock && (chunk->length != (i->silence_memblock->length < i->move_silence ? i->silence_memblock->length : i->move_silence)))) return; } diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 04795e39..05695254 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -237,6 +237,7 @@ static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) { info->userdata = i; assert(info->chunk.memblock); + assert(info->chunk.memblock->data); assert(info->chunk.length); info++; @@ -304,16 +305,13 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { pa_volume_memchunk(result, &s->sample_spec, &volume); } } else { - void *ptr; result->memblock = pa_memblock_new(s->core->mempool, length); assert(result->memblock); /* pa_log("mixing %i", n); */ - ptr = pa_memblock_acquire(result->memblock); - result->length = pa_mix(info, n, ptr, length, &s->sample_spec, &s->sw_volume, s->sw_muted); - pa_memblock_release(result->memblock); - + result->length = pa_mix(info, n, result->memblock->data, length, + &s->sample_spec, &s->sw_volume, s->sw_muted); result->index = 0; } @@ -334,13 +332,13 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; int r = -1; - void *ptr; assert(s); assert(s->ref >= 1); assert(target); assert(target->memblock); assert(target->length); + assert(target->memblock->data); pa_sink_ref(s); @@ -349,23 +347,16 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { if (n <= 0) goto finish; - ptr = pa_memblock_acquire(target->memblock); - if (n == 1) { - void *src; pa_cvolume volume; if (target->length > info[0].chunk.length) target->length = info[0].chunk.length; - - src = pa_memblock_acquire(info[0].chunk.memblock); - memcpy((uint8_t*) ptr + target->index, - (uint8_t*) src + info[0].chunk.index, + memcpy((uint8_t*) target->memblock->data + target->index, + (uint8_t*) info[0].chunk.memblock->data + info[0].chunk.index, target->length); - pa_memblock_release(info[0].chunk.memblock); - pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); if (s->sw_muted) @@ -374,13 +365,11 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { pa_volume_memchunk(target, &s->sample_spec, &volume); } else target->length = pa_mix(info, n, - (uint8_t*) ptr + target->index, + (uint8_t*) target->memblock->data + target->index, target->length, &s->sample_spec, &s->sw_volume, s->sw_muted); - - pa_memblock_release(target->memblock); inputs_drop(s, info, n, target->length); @@ -404,6 +393,7 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { assert(target); assert(target->memblock); assert(target->length); + assert(target->memblock->data); pa_sink_ref(s); diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c index d2ffeeed..e6f24a79 100644 --- a/src/pulsecore/sound-file-stream.c +++ b/src/pulsecore/sound-file-stream.c @@ -74,26 +74,21 @@ static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { if (!u->memchunk.memblock) { uint32_t fs = pa_frame_size(&i->sample_spec); sf_count_t n; - void *p; u->memchunk.memblock = pa_memblock_new(i->sink->core->mempool, BUF_SIZE); u->memchunk.index = 0; - p = pa_memblock_acquire(u->memchunk.memblock); - if (u->readf_function) { - if ((n = u->readf_function(u->sndfile, p, BUF_SIZE/fs)) <= 0) + if ((n = u->readf_function(u->sndfile, u->memchunk.memblock->data, BUF_SIZE/fs)) <= 0) n = 0; u->memchunk.length = n * fs; } else { - if ((n = sf_read_raw(u->sndfile, p, BUF_SIZE)) <= 0) + if ((n = sf_read_raw(u->sndfile, u->memchunk.memblock->data, BUF_SIZE)) <= 0) n = 0; u->memchunk.length = n; } - - pa_memblock_release(u->memchunk.memblock); if (!u->memchunk.length) { free_userdata(u); diff --git a/src/pulsecore/sound-file.c b/src/pulsecore/sound-file.c index c74a1586..1bf650e2 100644 --- a/src/pulsecore/sound-file.c +++ b/src/pulsecore/sound-file.c @@ -40,11 +40,7 @@ int pa_sound_file_load(pa_mempool *pool, const char *fname, pa_sample_spec *ss, int ret = -1; size_t l; sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames) = NULL; - void *ptr = NULL; - - assert(fname); - assert(ss); - assert(chunk); + assert(fname && ss && chunk); chunk->memblock = NULL; chunk->index = chunk->length = 0; @@ -101,10 +97,8 @@ int pa_sound_file_load(pa_mempool *pool, const char *fname, pa_sample_spec *ss, chunk->index = 0; chunk->length = l; - ptr = pa_memblock_acquire(chunk->memblock); - - if ((readf_function && readf_function(sf, ptr, sfinfo.frames) != sfinfo.frames) || - (!readf_function && sf_read_raw(sf, ptr, l) != l)) { + if ((readf_function && readf_function(sf, chunk->memblock->data, sfinfo.frames) != sfinfo.frames) || + (!readf_function && sf_read_raw(sf, chunk->memblock->data, l) != l)) { pa_log("Premature file end"); goto finish; } @@ -116,9 +110,6 @@ finish: if (sf) sf_close(sf); - if (ptr) - pa_memblock_release(chunk->memblock); - if (ret != 0 && chunk->memblock) pa_memblock_unref(chunk->memblock); diff --git a/src/tests/flist-test.c b/src/tests/flist-test.c index 06d68311..abc0659d 100644 --- a/src/tests/flist-test.c +++ b/src/tests/flist-test.c @@ -54,7 +54,7 @@ static void thread_func(void *data) { int b = 1; while (!quit) { - char *text; + char *text, *t; /* Allocate some memory, if possible take it from the flist */ if (b && (text = pa_flist_pop(flist))) diff --git a/src/tests/mcalign-test.c b/src/tests/mcalign-test.c index 1584256c..35691698 100644 --- a/src/tests/mcalign-test.c +++ b/src/tests/mcalign-test.c @@ -59,27 +59,24 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { c.index = c.length = 0; } - assert(c.index < pa_memblock_get_length(c.memblock)); + assert(c.index < c.memblock->length); - l = pa_memblock_get_length(c.memblock) - c.index; + l = c.memblock->length - c.index; l = l <= 1 ? l : rand() % (l-1) +1 ; - - p = pa_memblock_acquire(c.memblock); - if ((r = read(STDIN_FILENO, (uint8_t*) p + c.index, l)) <= 0) { - pa_memblock_release(c.memblock); + + if ((r = read(STDIN_FILENO, (uint8_t*) c.memblock->data + c.index, l)) <= 0) { fprintf(stderr, "read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); break; } - pa_memblock_release(c.memblock); - + c.length = r; pa_mcalign_push(a, &c); fprintf(stderr, "Read %ld bytes\n", (long)r); c.index += r; - if (c.index >= pa_memblock_get_length(c.memblock)) { + if (c.index >= c.memblock->length) { pa_memblock_unref(c.memblock); pa_memchunk_reset(&c); } @@ -90,9 +87,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { if (pa_mcalign_pop(a, &t) < 0) break; - p = pa_memblock_acquire(t.memblock); - pa_loop_write(STDOUT_FILENO, (uint8_t*) p + t.index, t.length, NULL); - pa_memblock_release(t.memblock); + pa_loop_write(STDOUT_FILENO, (uint8_t*) t.memblock->data + t.index, t.length, NULL); fprintf(stderr, "Wrote %lu bytes.\n", (unsigned long) t.length); pa_memblock_unref(t.memblock); diff --git a/src/tests/memblock-test.c b/src/tests/memblock-test.c index c2dd2efa..ef2e0ad7 100644 --- a/src/tests/memblock-test.c +++ b/src/tests/memblock-test.c @@ -76,7 +76,6 @@ int main(int argc, char *argv[]) { pa_memblock* blocks[5]; uint32_t id, shm_id; size_t offset, size; - char *x; const char txt[] = "This is a test!"; @@ -91,17 +90,10 @@ int main(int argc, char *argv[]) { assert(pool_a && pool_b && pool_c); blocks[0] = pa_memblock_new_fixed(pool_a, (void*) txt, sizeof(txt), 1); - blocks[1] = pa_memblock_new(pool_a, sizeof(txt)); - x = pa_memblock_acquire(blocks[1]); - snprintf(x, pa_memblock_get_length(blocks[1]), "%s", txt); - pa_memblock_release(blocks[1]); - + snprintf(blocks[1]->data, blocks[1]->length, "%s", txt); blocks[2] = pa_memblock_new_pool(pool_a, sizeof(txt)); - x = pa_memblock_acquire(blocks[2]); - snprintf(x, pa_memblock_get_length(blocks[2]), "%s", txt); - pa_memblock_release(blocks[1]); - + snprintf(blocks[2]->data, blocks[2]->length, "%s", txt); blocks[3] = pa_memblock_new_malloced(pool_a, pa_xstrdup(txt), sizeof(txt)); blocks[4] = NULL; @@ -138,18 +130,14 @@ int main(int argc, char *argv[]) { mb_c = pa_memimport_get(import_c, id, shm_id, offset, size); assert(mb_c); - x = pa_memblock_acquire(mb_c); - printf("1 data=%s\n", x); - pa_memblock_release(mb_c); + printf("1 data=%s\n", (char*) mb_c->data); print_stats(pool_a, "A"); print_stats(pool_b, "B"); print_stats(pool_c, "C"); pa_memexport_free(export_b); - x = pa_memblock_acquire(mb_c); - printf("2 data=%s\n", x); - pa_memblock_release(mb_c); + printf("2 data=%s\n", (char*) mb_c->data); pa_memblock_unref(mb_c); pa_memimport_free(import_b); diff --git a/src/tests/memblockq-test.c b/src/tests/memblockq-test.c index 02848eb2..1ac4577b 100644 --- a/src/tests/memblockq-test.c +++ b/src/tests/memblockq-test.c @@ -131,10 +131,8 @@ int main(int argc, char *argv[]) { if (pa_memblockq_peek(bq, &out) < 0) break; - p = pa_memblock_acquire(out.memblock); - for (e = (char*) p + out.index, n = 0; n < out.length; n++) + for (e = (char*) out.memblock->data + out.index, n = 0; n < out.length; n++) printf("%c", *e); - pa_memblock_release(out.memblock); pa_memblock_unref(out.memblock); pa_memblockq_drop(bq, &out, out.length); -- cgit From d4ca81fc2e8f480ec3f244b5f23e9303b5816452 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 6 Nov 2006 13:16:15 +0000 Subject: Fix some missing line breaks. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1410 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 5d96a984..a8ac8667 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -191,7 +191,7 @@ do { \ #define CONTEXT_CHECK_DEAD_GOTO(i, label) do { \ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY) { \ - debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ + debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ goto label; \ } \ } while(0); @@ -199,7 +199,7 @@ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY) { \ #define PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, label) do { \ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ !(i)->play_stream || pa_stream_get_state((i)->play_stream) != PA_STREAM_READY) { \ - debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ + debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ goto label; \ } \ } while(0); @@ -207,7 +207,7 @@ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ #define RECORD_STREAM_CHECK_DEAD_GOTO(i, label) do { \ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ !(i)->rec_stream || pa_stream_get_state((i)->rec_stream) != PA_STREAM_READY) { \ - debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ + debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ goto label; \ } \ } while(0); -- cgit From 55c25c657e907178de36e5b06b44cae66174d922 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 8 Nov 2006 12:56:26 +0000 Subject: Check correct variable for return value. Closes #37. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1411 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 80aeb27b..c36f8201 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -463,7 +463,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co sdata.client = c->client; c->source_output = pa_source_output_new(c->protocol->core, &sdata, 9); - CHECK_VALIDITY(c->sink_input, "Failed to create source_output."); + CHECK_VALIDITY(c->source_output, "Failed to create source_output."); l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); c->output_memblockq = pa_memblockq_new( -- cgit From 0ef2d7eb778e25d252c78594fa6490a6cb654cb9 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 8 Nov 2006 13:03:35 +0000 Subject: Support reversed endian floats. (closes #28) (closes #35) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1412 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/sample-util.c | 1 + src/pulsecore/sconv.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index d902b4b5..a7a5ed8f 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -68,6 +68,7 @@ void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { case PA_SAMPLE_S16LE: case PA_SAMPLE_S16BE: case PA_SAMPLE_FLOAT32: + case PA_SAMPLE_FLOAT32RE: c = 0; break; case PA_SAMPLE_ALAW: diff --git a/src/pulsecore/sconv.c b/src/pulsecore/sconv.c index ff2a0110..2e5e2dbe 100644 --- a/src/pulsecore/sconv.c +++ b/src/pulsecore/sconv.c @@ -72,6 +72,22 @@ static void float32ne_from_float32ne(unsigned n, const float *a, void *b) { oil_memcpy(b, a, sizeof(float) * n); } +static void float32re_to_float32ne(unsigned n, const void *a, float *b) { + assert(a); + assert(b); + + while (n-- > 0) + ((uint32_t *)b)[n] = UINT32_SWAP (((uint32_t *)a)[n]); +} + +static void float32re_from_float32ne(unsigned n, const float *a, void *b) { + assert(a); + assert(b); + + while (n-- > 0) + ((uint32_t *)b)[n] = UINT32_SWAP (((uint32_t *)a)[n]); +} + static void ulaw_to_float32ne(unsigned n, const void *a, float *b) { const uint8_t *ca = a; @@ -140,6 +156,8 @@ pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_fo return pa_sconv_s16be_to_float32ne; case PA_SAMPLE_FLOAT32NE: return float32ne_to_float32ne; + case PA_SAMPLE_FLOAT32RE: + return float32re_to_float32ne; case PA_SAMPLE_ALAW: return alaw_to_float32ne; case PA_SAMPLE_ULAW: @@ -159,6 +177,8 @@ pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sampl return pa_sconv_s16be_from_float32ne; case PA_SAMPLE_FLOAT32NE: return float32ne_from_float32ne; + case PA_SAMPLE_FLOAT32RE: + return float32re_from_float32ne; case PA_SAMPLE_ALAW: return alaw_from_float32ne; case PA_SAMPLE_ULAW: -- cgit From 0a37ec28ff9e3b20a1c41170968de010cc0cb99f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 9 Nov 2006 15:23:30 +0000 Subject: Yet again try to fix the creation of necessary directories when srcdir != builddir. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1413 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 64df8614..1a071ec4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1006,9 +1006,9 @@ EXTRA_DIST += $(SYMDEF_FILES) BUILT_SOURCES += $(SYMDEF_FILES) $(SYMDEF_FILES): modules/module-defs.h.m4 - mkdir modules - mkdir modules/gconf - mkdir modules/rtp + -mkdir modules + -mkdir modules/gconf + -mkdir modules/rtp $(M4) -Dfname="$@" $< > $@ # Simple protocol -- cgit From 86f4c2108f1bac17c32c68b9a4e8880a4577d533 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 10 Nov 2006 12:20:16 +0000 Subject: Make sure we package version.h.in. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1414 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Makefile.am b/src/Makefile.am index 1a071ec4..6adc0688 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -88,6 +88,7 @@ endif EXTRA_DIST = \ pulse/client.conf.in \ + pulse/version.h.in \ daemon/daemon.conf.in \ daemon/default.pa.in \ daemon/default.pa.win32 \ -- cgit From 7933cbaf29c85e072ee3176dbb7a8baebb9263ca Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 10 Nov 2006 14:58:22 +0000 Subject: Add atomic.h as a dependency at relevant places. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1415 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Makefile.am b/src/Makefile.am index 6adc0688..2f3bd8ab 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -77,6 +77,7 @@ PA_THREAD_OBJS = \ pulsecore/thread-win32.c pulsecore/thread.h else PA_THREAD_OBJS = \ + pulsecore/atomic.h \ pulsecore/once-posix.c pulsecore/once.h \ pulsecore/mutex-posix.c pulsecore/mutex.h \ pulsecore/thread-posix.c pulsecore/thread.h @@ -270,6 +271,7 @@ thread_test_LDADD = $(AM_LDADD) libpulsecore.la thread_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) flist_test_SOURCES = tests/flist-test.c \ + pulsecore/atomic.h \ pulsecore/flist.c pulsecore/flist.h flist_test_CFLAGS = $(AM_CFLAGS) flist_test_LDADD = $(AM_LDADD) libpulsecore.la @@ -514,6 +516,7 @@ libpulsedsp_la_LDFLAGS = -avoid-version pulsecoreinclude_HEADERS = \ pulsecore/autoload.h \ + pulsecore/atomic.h \ pulsecore/cli-command.h \ pulsecore/cli-text.h \ pulsecore/client.h \ -- cgit From 68bcbd29139df99174e0e7757c540a91b577883f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 24 Nov 2006 09:29:10 +0000 Subject: Fix incorrect assert. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1416 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/autoload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/autoload.c b/src/pulsecore/autoload.c index f6869097..8e57d343 100644 --- a/src/pulsecore/autoload.c +++ b/src/pulsecore/autoload.c @@ -102,7 +102,7 @@ int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const c int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type_t type) { pa_autoload_entry *e; - assert(c && name && type); + assert(c && name && module && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type) return -1; -- cgit From 1a460ee40ab19e354402f6c9346591b554471f03 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 4 Dec 2006 08:15:06 +0000 Subject: Fix silly copy-and-paste error. (closes #45) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1417 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/autoload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/autoload.c b/src/pulsecore/autoload.c index 8e57d343..60304201 100644 --- a/src/pulsecore/autoload.c +++ b/src/pulsecore/autoload.c @@ -102,7 +102,7 @@ int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const c int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type_t type) { pa_autoload_entry *e; - assert(c && name && module && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); + assert(c && name && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type) return -1; -- cgit From 521daf6f0ac4fa6a2fbfb5d523c0c743342dca2b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 4 Jan 2007 13:43:45 +0000 Subject: Huge trailing whitespace cleanup. Let's keep the tree pure from here on, mmmkay? git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1418 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/caps.c | 18 +- src/daemon/caps.h | 6 +- src/daemon/cmdline.c | 36 ++-- src/daemon/cmdline.h | 6 +- src/daemon/cpulimit.c | 22 +-- src/daemon/cpulimit.h | 6 +- src/daemon/daemon-conf.c | 16 +- src/daemon/daemon-conf.h | 4 +- src/daemon/dumpmodules.c | 22 +-- src/daemon/main.c | 60 +++--- src/modules/alsa-util.c | 28 +-- src/modules/alsa-util.h | 6 +- src/modules/dbus-util.c | 6 +- src/modules/dbus-util.h | 6 +- src/modules/module-alsa-sink.c | 54 +++--- src/modules/module-alsa-source.c | 58 +++--- src/modules/module-cli.c | 14 +- src/modules/module-combine.c | 70 +++---- src/modules/module-detect.c | 36 ++-- src/modules/module-esound-compat-spawnfd.c | 6 +- src/modules/module-esound-compat-spawnpid.c | 6 +- src/modules/module-esound-sink.c | 58 +++--- src/modules/module-hal-detect.c | 12 +- src/modules/module-jack-sink.c | 70 +++---- src/modules/module-jack-source.c | 70 +++---- src/modules/module-lirc.c | 42 ++--- src/modules/module-match.c | 26 +-- src/modules/module-mmkbd-evdev.c | 26 +-- src/modules/module-native-protocol-fd.c | 10 +- src/modules/module-null-sink.c | 24 +-- src/modules/module-oss-mmap.c | 86 ++++----- src/modules/module-oss.c | 70 +++---- src/modules/module-pipe-sink.c | 36 ++-- src/modules/module-pipe-source.c | 30 +-- src/modules/module-protocol-stub.c | 36 ++-- src/modules/module-rescue-streams.c | 22 +-- src/modules/module-sine.c | 18 +- src/modules/module-solaris.c | 36 ++-- src/modules/module-tunnel.c | 86 ++++----- src/modules/module-volume-restore.c | 64 +++---- src/modules/module-waveout.c | 22 +-- src/modules/module-x11-bell.c | 18 +- src/modules/module-x11-publish.c | 26 +-- src/modules/module-zeroconf-publish.c | 108 +++++------ src/modules/oss-util.c | 44 ++--- src/modules/oss-util.h | 6 +- src/pulse/browser.c | 62 +++---- src/pulse/browser.h | 8 +- src/pulse/cdecl.h | 6 +- src/pulse/channelmap.c | 110 +++++------ src/pulse/channelmap.h | 20 +- src/pulse/client-conf-x11.c | 4 +- src/pulse/client-conf.c | 16 +- src/pulse/context.c | 156 ++++++++-------- src/pulse/context.h | 10 +- src/pulse/def.h | 16 +- src/pulse/error.c | 6 +- src/pulse/error.h | 6 +- src/pulse/glib-mainloop.c | 98 +++++----- src/pulse/glib-mainloop.h | 6 +- src/pulse/internal.h | 20 +- src/pulse/introspect.c | 118 ++++++------ src/pulse/introspect.h | 24 +-- src/pulse/mainloop-api.c | 6 +- src/pulse/mainloop-api.h | 8 +- src/pulse/mainloop-signal.c | 20 +- src/pulse/mainloop-signal.h | 6 +- src/pulse/mainloop.c | 96 +++++----- src/pulse/mainloop.h | 8 +- src/pulse/operation.c | 20 +- src/pulse/operation.h | 6 +- src/pulse/pulseaudio.h | 12 +- src/pulse/sample.c | 12 +- src/pulse/sample.h | 6 +- src/pulse/scache.c | 24 +-- src/pulse/scache.h | 6 +- src/pulse/simple.c | 68 +++---- src/pulse/simple.h | 6 +- src/pulse/stream.c | 238 ++++++++++++------------ src/pulse/stream.h | 20 +- src/pulse/subscribe.c | 10 +- src/pulse/subscribe.h | 6 +- src/pulse/thread-mainloop.c | 16 +- src/pulse/thread-mainloop.h | 10 +- src/pulse/timeval.c | 12 +- src/pulse/timeval.h | 6 +- src/pulse/utf8.c | 2 +- src/pulse/utf8.h | 6 +- src/pulse/util.c | 30 +-- src/pulse/util.h | 6 +- src/pulse/volume.c | 14 +- src/pulse/volume.h | 6 +- src/pulse/xmalloc.c | 20 +- src/pulse/xmalloc.h | 6 +- src/pulsecore/anotify.c | 18 +- src/pulsecore/anotify.h | 6 +- src/pulsecore/atomic.h | 6 +- src/pulsecore/authkey-prop.c | 10 +- src/pulsecore/authkey-prop.h | 6 +- src/pulsecore/authkey.c | 26 +-- src/pulsecore/authkey.h | 6 +- src/pulsecore/autoload.c | 30 +-- src/pulsecore/autoload.h | 8 +- src/pulsecore/avahi-wrap.c | 34 ++-- src/pulsecore/avahi-wrap.h | 6 +- src/pulsecore/cli-command.c | 48 ++--- src/pulsecore/cli-command.h | 6 +- src/pulsecore/cli-text.c | 46 ++--- src/pulsecore/cli-text.h | 6 +- src/pulsecore/cli.c | 14 +- src/pulsecore/cli.h | 6 +- src/pulsecore/client.c | 8 +- src/pulsecore/client.h | 6 +- src/pulsecore/conf-parser.c | 34 ++-- src/pulsecore/core-def.h | 6 +- src/pulsecore/core-error.c | 6 +- src/pulsecore/core-error.h | 6 +- src/pulsecore/core-scache.c | 28 +-- src/pulsecore/core-scache.h | 10 +- src/pulsecore/core-subscribe.c | 32 ++-- src/pulsecore/core-subscribe.h | 6 +- src/pulsecore/core-util.c | 154 +++++++-------- src/pulsecore/core-util.h | 6 +- src/pulsecore/core.c | 18 +- src/pulsecore/core.h | 8 +- src/pulsecore/creds.h | 6 +- src/pulsecore/dynarray.c | 6 +- src/pulsecore/dynarray.h | 6 +- src/pulsecore/endianmacros.h | 6 +- src/pulsecore/esound.h | 6 +- src/pulsecore/flist.c | 22 +-- src/pulsecore/flist.h | 6 +- src/pulsecore/g711.h | 2 +- src/pulsecore/gccmacro.h | 6 +- src/pulsecore/hashmap.c | 30 +-- src/pulsecore/hashmap.h | 6 +- src/pulsecore/hook-list.c | 30 +-- src/pulsecore/hook-list.h | 6 +- src/pulsecore/idxset.c | 50 ++--- src/pulsecore/idxset.h | 6 +- src/pulsecore/inet_ntop.c | 6 +- src/pulsecore/inet_pton.c | 6 +- src/pulsecore/iochannel.c | 66 +++---- src/pulsecore/iochannel.h | 6 +- src/pulsecore/ioline.c | 70 +++---- src/pulsecore/ioline.h | 6 +- src/pulsecore/ipacl.c | 36 ++-- src/pulsecore/ipacl.h | 6 +- src/pulsecore/llist.h | 12 +- src/pulsecore/log.c | 30 +-- src/pulsecore/log.h | 6 +- src/pulsecore/mcalign.c | 34 ++-- src/pulsecore/mcalign.h | 10 +- src/pulsecore/memblock.c | 94 +++++----- src/pulsecore/memblock.h | 10 +- src/pulsecore/memblockq.c | 80 ++++---- src/pulsecore/memblockq.h | 20 +- src/pulsecore/memchunk.c | 10 +- src/pulsecore/memchunk.h | 6 +- src/pulsecore/modargs.c | 22 +-- src/pulsecore/modargs.h | 6 +- src/pulsecore/modinfo.c | 6 +- src/pulsecore/modinfo.h | 6 +- src/pulsecore/module.c | 38 ++-- src/pulsecore/module.h | 8 +- src/pulsecore/mutex-posix.c | 6 +- src/pulsecore/mutex-win32.c | 6 +- src/pulsecore/mutex.h | 6 +- src/pulsecore/namereg.c | 60 +++--- src/pulsecore/namereg.h | 6 +- src/pulsecore/native-common.h | 18 +- src/pulsecore/once-posix.c | 30 +-- src/pulsecore/once-win32.c | 8 +- src/pulsecore/once.h | 6 +- src/pulsecore/packet.c | 14 +- src/pulsecore/packet.h | 6 +- src/pulsecore/parseaddr.c | 22 +-- src/pulsecore/parseaddr.h | 6 +- src/pulsecore/pdispatch.c | 40 ++-- src/pulsecore/pdispatch.h | 6 +- src/pulsecore/pid.c | 36 ++-- src/pulsecore/pid.h | 6 +- src/pulsecore/pipe.c | 6 +- src/pulsecore/pipe.h | 6 +- src/pulsecore/play-memblockq.c | 18 +- src/pulsecore/play-memblockq.h | 6 +- src/pulsecore/play-memchunk.c | 18 +- src/pulsecore/play-memchunk.h | 6 +- src/pulsecore/poll.c | 6 +- src/pulsecore/poll.h | 6 +- src/pulsecore/props.c | 12 +- src/pulsecore/props.h | 6 +- src/pulsecore/protocol-cli.c | 10 +- src/pulsecore/protocol-cli.h | 6 +- src/pulsecore/protocol-esound.c | 152 +++++++-------- src/pulsecore/protocol-esound.h | 6 +- src/pulsecore/protocol-http.c | 28 +-- src/pulsecore/protocol-http.h | 6 +- src/pulsecore/protocol-native.c | 274 +++++++++++++-------------- src/pulsecore/protocol-native.h | 6 +- src/pulsecore/protocol-simple.c | 54 +++--- src/pulsecore/protocol-simple.h | 6 +- src/pulsecore/pstream-util.c | 6 +- src/pulsecore/pstream-util.h | 6 +- src/pulsecore/pstream.c | 146 +++++++-------- src/pulsecore/pstream.h | 6 +- src/pulsecore/queue.c | 8 +- src/pulsecore/queue.h | 6 +- src/pulsecore/random.c | 6 +- src/pulsecore/random.h | 8 +- src/pulsecore/refcnt.h | 6 +- src/pulsecore/resampler.c | 104 +++++------ src/pulsecore/resampler.h | 6 +- src/pulsecore/sample-util.c | 138 +++++++------- src/pulsecore/sample-util.h | 6 +- src/pulsecore/sconv-s16be.c | 6 +- src/pulsecore/sconv-s16be.h | 6 +- src/pulsecore/sconv-s16le.c | 14 +- src/pulsecore/sconv-s16le.h | 6 +- src/pulsecore/sconv.c | 16 +- src/pulsecore/sconv.h | 6 +- src/pulsecore/shm.c | 46 ++--- src/pulsecore/shm.h | 6 +- src/pulsecore/sink-input.c | 100 +++++----- src/pulsecore/sink-input.h | 22 +-- src/pulsecore/sink.c | 98 +++++----- src/pulsecore/sink.h | 12 +- src/pulsecore/sioman.c | 8 +- src/pulsecore/sioman.h | 6 +- src/pulsecore/socket-client.c | 68 +++---- src/pulsecore/socket-client.h | 6 +- src/pulsecore/socket-server.c | 66 +++---- src/pulsecore/socket-server.h | 6 +- src/pulsecore/socket-util.c | 20 +- src/pulsecore/socket-util.h | 6 +- src/pulsecore/sound-file-stream.c | 28 +-- src/pulsecore/sound-file-stream.h | 6 +- src/pulsecore/sound-file.c | 18 +- src/pulsecore/sound-file.h | 6 +- src/pulsecore/source-output.c | 64 +++---- src/pulsecore/source-output.h | 12 +- src/pulsecore/source.c | 54 +++--- src/pulsecore/source.h | 16 +- src/pulsecore/strbuf.c | 18 +- src/pulsecore/strbuf.h | 6 +- src/pulsecore/strlist.c | 14 +- src/pulsecore/strlist.h | 6 +- src/pulsecore/tagstruct.c | 48 ++--- src/pulsecore/tagstruct.h | 6 +- src/pulsecore/thread-posix.c | 36 ++-- src/pulsecore/thread-win32.c | 6 +- src/pulsecore/thread.h | 6 +- src/pulsecore/tokenizer.c | 8 +- src/pulsecore/tokenizer.h | 6 +- src/pulsecore/x11prop.c | 4 +- src/pulsecore/x11wrap.c | 26 +-- src/pulsecore/x11wrap.h | 6 +- src/tests/channelmap-test.c | 10 +- src/tests/cpulimit-test.c | 14 +- src/tests/flist-test.c | 10 +- src/tests/get-binary-name-test.c | 6 +- src/tests/hook-list-test.c | 4 +- src/tests/interpol-test.c | 30 +-- src/tests/ipacl-test.c | 14 +- src/tests/mainloop-test.c | 8 +- src/tests/mcalign-test.c | 10 +- src/tests/memblock-test.c | 36 ++-- src/tests/memblockq-test.c | 30 +-- src/tests/pacat-simple.c | 16 +- src/tests/parec-simple.c | 10 +- src/tests/strlist-test.c | 6 +- src/tests/sync-playback.c | 28 +-- src/tests/thread-mainloop-test.c | 14 +- src/tests/thread-test.c | 32 ++-- src/tests/utf8-test.c | 4 +- src/tests/voltest.c | 2 +- src/utils/pabrowse.c | 18 +- src/utils/pacat.c | 86 ++++----- src/utils/pacmd.c | 40 ++-- src/utils/pactl.c | 76 ++++---- src/utils/padsp.c | 278 ++++++++++++++-------------- src/utils/paplay.c | 48 ++--- src/utils/pax11publish.c | 24 +-- 283 files changed, 3742 insertions(+), 3742 deletions(-) diff --git a/src/daemon/caps.c b/src/daemon/caps.c index cebdaebc..db4bd919 100644 --- a/src/daemon/caps.c +++ b/src/daemon/caps.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -50,7 +50,7 @@ int setresuid(uid_t r, uid_t e, uid_t s); /* Drop root rights when called SUID root */ void pa_drop_root(void) { uid_t uid = getuid(); - + if (uid == 0 || geteuid() != 0) return; @@ -96,13 +96,13 @@ int pa_limit_caps(void) { if (cap_set_proc(caps) < 0) goto fail; - pa_log_info("dropped capabilities successfully."); - + pa_log_info("dropped capabilities successfully."); + r = 0; fail: cap_free (caps); - + return r; } @@ -124,12 +124,12 @@ int pa_drop_caps(void) { pa_log("failed to drop capabilities: %s", pa_cstrerror(errno)); goto fail; } - + r = 0; fail: cap_free (caps); - + return r; } diff --git a/src/daemon/caps.h b/src/daemon/caps.h index 8a618286..34da1af6 100644 --- a/src/daemon/caps.h +++ b/src/daemon/caps.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c index d368b644..c3cb9209 100644 --- a/src/daemon/cmdline.c +++ b/src/daemon/cmdline.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -100,7 +100,7 @@ void pa_cmdline_help(const char *argv0) { e++; else e = argv0; - + printf("%s [options]\n\n" "COMMANDS:\n" " -h, --help Show this help\n" @@ -124,7 +124,7 @@ void pa_cmdline_help(const char *argv0) { " --scache-idle-time=SECS Unload autoloaded samples when idle and\n" " this time passed\n" " --log-level[=LEVEL] Increase or set verbosity level\n" - " -v Increase the verbosity level\n" + " -v Increase the verbosity level\n" " --log-target={auto,syslog,stderr} Specify the log target\n" " -p, --dl-search-path=PATH Set the search path for dynamic shared\n" " objects (plugins)\n" @@ -143,7 +143,7 @@ void pa_cmdline_help(const char *argv0) { " -F, --file=FILENAME Run the specified script\n" " -C Open a command line on the running TTY\n" " after startup\n\n" - + " -n Don't load default script file\n", e); } @@ -156,7 +156,7 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d if (conf->script_commands) pa_strbuf_puts(buf, conf->script_commands); - + while ((c = getopt_long(argc, argv, "L:F:ChDnp:kv", long_options, NULL)) != -1) { switch (c) { case ARG_HELP: @@ -184,21 +184,21 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d case ARG_CHECK: conf->cmd = PA_CMD_CHECK; break; - + case ARG_LOAD: case 'L': pa_strbuf_printf(buf, "load-module %s\n", optarg); break; - + case ARG_FILE: case 'F': pa_strbuf_printf(buf, ".include %s\n", optarg); break; - + case 'C': pa_strbuf_puts(buf, "load-module module-cli exit_on_eof=1\n"); break; - + case ARG_DAEMONIZE: case 'D': if ((conf->daemonize = optarg ? pa_parse_boolean(optarg) : 1) < 0) { @@ -226,7 +226,7 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d if (conf->log_level < PA_LOG_LEVEL_MAX-1) conf->log_level++; } - + break; case ARG_HIGH_PRIORITY: @@ -249,13 +249,13 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d goto fail; } break; - + case 'p': case ARG_DL_SEARCH_PATH: pa_xfree(conf->dl_search_path); conf->dl_search_path = *optarg ? pa_xstrdup(optarg) : NULL; break; - + case 'n': pa_xfree(conf->default_script_file); conf->default_script_file = NULL; @@ -307,7 +307,7 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d goto fail; } break; - + default: goto fail; } @@ -322,12 +322,12 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d } *d = optind; - + return 0; - + fail: if (buf) pa_strbuf_free(buf); - + return -1; } diff --git a/src/daemon/cmdline.h b/src/daemon/cmdline.h index 25453e55..fdfbc0b6 100644 --- a/src/daemon/cmdline.h +++ b/src/daemon/cmdline.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/daemon/cpulimit.c b/src/daemon/cpulimit.c index d7466b06..808cb4d4 100644 --- a/src/daemon/cpulimit.c +++ b/src/daemon/cpulimit.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -80,7 +80,7 @@ static pa_io_event *io_event = NULL; static struct sigaction sigaction_prev; /* Nonzero after pa_cpu_limit_init() */ -static int installed = 0; +static int installed = 0; /* The current state of operation */ static enum { @@ -131,24 +131,24 @@ static void signal_handler(int sig) { snprintf(t, sizeof(t), "Using %0.1f%% CPU\n", (double)CPUTIME_INTERVAL_SOFT/(now-last_time)*100); write_err(t); #endif - + if (CPUTIME_INTERVAL_SOFT >= ((now-last_time)*(double)CPUTIME_PERCENT/100)) { static const char c = 'X'; write_err("Soft CPU time limit exhausted, terminating.\n"); - + /* Try a soft cleanup */ write(the_pipe[1], &c, sizeof(c)); phase = PHASE_SOFT; reset_cpu_time(CPUTIME_INTERVAL_HARD); - + } else { /* Everything's fine */ reset_cpu_time(CPUTIME_INTERVAL_SOFT); last_time = now; } - + } else if (phase == PHASE_SOFT) { write_err("Hard CPU time limit exhausted, terminating forcibly.\n"); _exit(1); /* Forced exit */ @@ -167,7 +167,7 @@ static void callback(pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags int pa_cpu_limit_init(pa_mainloop_api *m) { struct sigaction sa; assert(m && !api && !io_event && the_pipe[0] == -1 && the_pipe[1] == -1 && !installed); - + time(&last_time); /* Prepare the main loop pipe */ @@ -191,7 +191,7 @@ int pa_cpu_limit_init(pa_mainloop_api *m) { sa.sa_handler = signal_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; - + if (sigaction(SIGXCPU, &sa, &sigaction_prev) < 0) { pa_cpu_limit_done(); return -1; @@ -200,7 +200,7 @@ int pa_cpu_limit_init(pa_mainloop_api *m) { installed = 1; reset_cpu_time(CPUTIME_INTERVAL_SOFT); - + return 0; } diff --git a/src/daemon/cpulimit.h b/src/daemon/cpulimit.h index 21bdd17b..bb11f794 100644 --- a/src/daemon/cpulimit.h +++ b/src/daemon/cpulimit.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index dd478126..319cf0c7 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -231,7 +231,7 @@ static int parse_rlimit(const char *filename, unsigned line, const char *lvalue, int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { int r = -1; FILE *f = NULL; - + pa_config_item table[] = { { "daemonize", pa_config_parse_bool, NULL }, { "fail", pa_config_parse_bool, NULL }, @@ -266,7 +266,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { #endif { NULL, NULL, NULL }, }; - + table[0].data = &c->daemonize; table[1].data = &c->fail; table[2].data = &c->high_priority; @@ -301,8 +301,8 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { table[24].data = &c->rlimit_memlock; #endif #endif - - + + pa_xfree(c->config_file); c->config_file = NULL; @@ -316,11 +316,11 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { } r = f ? pa_config_parse(c->config_file, f, table, NULL) : 0; - + finish: if (f) fclose(f); - + return r; } @@ -354,7 +354,7 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { pa_strbuf_printf(s, "### Read from configuration file: %s ###\n", c->config_file); assert(c->log_level <= PA_LOG_LEVEL_MAX); - + pa_strbuf_printf(s, "daemonize = %i\n", !!c->daemonize); pa_strbuf_printf(s, "fail = %i\n", !!c->fail); pa_strbuf_printf(s, "high-priority = %i\n", !!c->high_priority); @@ -385,6 +385,6 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { pa_strbuf_printf(s, "rlimit-memlock = %li\n", c->rlimit_memlock.is_set ? (long int) c->rlimit_memlock.value : -1); #endif #endif - + return pa_strbuf_tostring_free(s); } diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h index b4b833ad..b7fcf23b 100644 --- a/src/daemon/daemon-conf.h +++ b/src/daemon/daemon-conf.h @@ -66,7 +66,7 @@ typedef struct pa_daemon_conf { pa_log_level_t log_level; int resample_method; char *config_file; - + #ifdef HAVE_SYS_RESOURCE_H pa_rlimit rlimit_as, rlimit_core, rlimit_data, rlimit_fsize, rlimit_nofile, rlimit_stack; #ifdef RLIMIT_NPROC @@ -76,7 +76,7 @@ typedef struct pa_daemon_conf { pa_rlimit rlimit_memlock; #endif #endif - + } pa_daemon_conf; /* Allocate a new structure and fill it with sane defaults */ diff --git a/src/daemon/dumpmodules.c b/src/daemon/dumpmodules.c index 06734ea6..8509924a 100644 --- a/src/daemon/dumpmodules.c +++ b/src/daemon/dumpmodules.c @@ -45,14 +45,14 @@ static void short_info(const char *name, PA_GCC_UNUSED const char *path, pa_modi static void long_info(const char *name, const char *path, pa_modinfo *i) { static int nl = 0; assert(name && i); - + if (nl) printf("\n"); nl = 1; printf("Name: %s\n", name); - + if (!i->description && !i->version && !i->author && !i->usage) printf("No module information available\n"); else { @@ -65,14 +65,14 @@ static void long_info(const char *name, const char *path, pa_modinfo *i) { if (i->usage) printf("Usage: %s\n", i->usage); } - + if (path) printf("Path: %s\n", path); } static void show_info(const char *name, const char *path, void (*info)(const char *name, const char *path, pa_modinfo*i)) { pa_modinfo *i; - + if ((i = pa_modinfo_get_by_name(path ? path : name))) { info(name, path, i); pa_modinfo_free(i); @@ -86,10 +86,10 @@ static int is_preloaded(const char *name) { for (l = lt_preloaded_symbols; l->name; l++) { char buf[64], *e; - + if (l->address) continue; - + snprintf(buf, sizeof(buf), "%s", l->name); if ((e = strrchr(buf, '.'))) *e = 0; @@ -112,7 +112,7 @@ static int callback(const char *path, lt_ptr data) { if (is_preloaded(e)) return 0; - + show_info(e, path, c->log_level >= PA_LOG_INFO ? long_info : short_info); return 0; } @@ -127,20 +127,20 @@ void pa_dump_modules(pa_daemon_conf *c, int argc, char * const argv[]) { for (l = lt_preloaded_symbols; l->name; l++) { char buf[64], *e; - + if (l->address) continue; if (strlen(l->name) <= sizeof(PREFIX)-1 || strncmp(l->name, PREFIX, sizeof(PREFIX)-1)) continue; - + snprintf(buf, sizeof(buf), "%s", l->name); if ((e = strrchr(buf, '.'))) *e = 0; - + show_info(buf, NULL, c->log_level >= PA_LOG_INFO ? long_info : short_info); } - + lt_dlforeachfile(NULL, callback, c); } } diff --git a/src/daemon/main.c b/src/daemon/main.c index 5d77282c..b7266b7e 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -125,7 +125,7 @@ static void signal_callback(pa_mainloop_api*m, PA_GCC_UNUSED pa_signal_event *e, pa_module_load(userdata, "module-cli", NULL); break; #endif - + #ifdef SIGUSR2 case SIGUSR2: pa_module_load(userdata, "module-cli-protocol-unix", NULL); @@ -170,7 +170,7 @@ static int change_user(void) { /* This function is called only in system-wide mode. It creates a * runtime dir in /var/run/ with proper UID/GID and drops privs * afterwards. */ - + if (!(pw = getpwnam(PA_SYSTEM_USER))) { pa_log("Failed to find user '%s'.", PA_SYSTEM_USER); return -1; @@ -197,7 +197,7 @@ static int change_user(void) { pa_log("Failed to create '%s': %s", PA_SYSTEM_RUNTIME_PATH, pa_cstrerror(errno)); return -1; } - + if (initgroups(PA_SYSTEM_USER, gr->gr_gid) != 0) { pa_log("Failed to change group list: %s", pa_cstrerror(errno)); return -1; @@ -265,7 +265,7 @@ static int create_runtime_dir(void) { /* This function is called only when the daemon is started in * per-user mode. We create the runtime directory somewhere in * /tmp/ with the current UID/GID */ - + if (pa_make_secure_dir(fn, 0700, (uid_t)-1, (gid_t)-1) < 0) { pa_log("Failed to create '%s': %s", fn, pa_cstrerror(errno)); return -1; @@ -311,7 +311,7 @@ int main(int argc, char *argv[]) { pa_daemon_conf *conf = NULL; pa_mainloop *mainloop = NULL; - char *s; + char *s; int r, retval = 1, d = 0; int daemon_pipe[2] = { -1, -1 }; int suid_root, real_root; @@ -333,7 +333,7 @@ int main(int argc, char *argv[]) { #ifdef HAVE_GETUID real_root = getuid() == 0; suid_root = !real_root && geteuid() == 0; - + if (suid_root && (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) <= 0 || gid >= 1000)) { pa_log_warn("WARNING: called SUID root, but not in group '"PA_REALTIME_GROUP"'."); pa_drop_root(); @@ -342,9 +342,9 @@ int main(int argc, char *argv[]) { real_root = 0; suid_root = 0; #endif - + LTDL_SET_PRELOADED_SYMBOLS(); - + r = lt_dlinit(); assert(r == 0); @@ -356,11 +356,11 @@ int main(int argc, char *argv[]) { #endif pa_random_seed(); - + pa_log_set_ident("pulseaudio"); - + conf = pa_daemon_conf_new(); - + if (pa_daemon_conf_load(conf, NULL) < 0) goto finish; @@ -429,9 +429,9 @@ int main(int argc, char *argv[]) { pa_log("failed to kill daemon."); else retval = 0; - + goto finish; - + default: assert(conf->cmd == PA_CMD_DAEMON); } @@ -457,7 +457,7 @@ int main(int argc, char *argv[]) { pa_log("failed to create pipe."); goto finish; } - + if ((child = fork()) < 0) { pa_log("fork() failed: %s", pa_cstrerror(errno)); goto finish; @@ -478,7 +478,7 @@ int main(int argc, char *argv[]) { pa_log("daemon startup failed."); else pa_log_info("daemon startup successful."); - + goto finish; } @@ -517,7 +517,7 @@ int main(int argc, char *argv[]) { #ifdef SIGTSTP signal(SIGTSTP, SIG_IGN); #endif - + #ifdef TIOCNOTTY if ((tty_fd = open("/dev/tty", O_RDWR)) >= 0) { ioctl(tty_fd, TIOCNOTTY, (char*) 0); @@ -528,13 +528,13 @@ int main(int argc, char *argv[]) { chdir("/"); umask(0022); - + if (conf->system_instance) { if (change_user() < 0) goto finish; } else if (create_runtime_dir() < 0) goto finish; - + if (conf->use_pid_file) { if (pa_pid_file_create() < 0) { pa_log("pa_pid_file_create() failed."); @@ -551,7 +551,7 @@ int main(int argc, char *argv[]) { #ifdef HAVE_SYS_RESOURCE_H set_all_rlimits(conf); #endif - + #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif @@ -580,7 +580,7 @@ int main(int argc, char *argv[]) { #ifdef SIGHUP pa_signal_new(SIGHUP, signal_callback, c); #endif - + #ifdef OS_IS_WIN32 timer = pa_mainloop_get_api(mainloop)->time_new( pa_mainloop_get_api(mainloop), pa_gettimeofday(&tv), message_cb, NULL); @@ -596,7 +596,7 @@ int main(int argc, char *argv[]) { r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop)); assert(r == 0); } - + buf = pa_strbuf_new(); if (conf->default_script_file) r = pa_cli_command_execute_file(c, conf->default_script_file, buf, &conf->fail); @@ -605,7 +605,7 @@ int main(int argc, char *argv[]) { r = pa_cli_command_execute(c, conf->script_commands, buf, &conf->fail); pa_log_error("%s", s = pa_strbuf_tostring_free(buf)); pa_xfree(s); - + if (r < 0 && conf->fail) { pa_log("failed to initialize daemon."); #ifdef HAVE_FORK @@ -652,11 +652,11 @@ int main(int argc, char *argv[]) { if (!conf->no_cpu_limit) pa_cpu_limit_done(); - + pa_signal_done(); - + pa_log_info("Daemon terminated."); - + finish: if (mainloop) @@ -667,7 +667,7 @@ finish: if (valid_pid_file) pa_pid_file_remove(); - + close_pipe(daemon_pipe); #ifdef OS_IS_WIN32 @@ -675,6 +675,6 @@ finish: #endif lt_dlexit(); - + return retval; } diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index d8b6c5cc..8023d3ad 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -270,7 +270,7 @@ static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_s }; int i, ret; - + assert(pcm_handle); assert(f); @@ -290,12 +290,12 @@ static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_s if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0) return ret; - + try_auto: for (i = 0; try_order[i] != PA_SAMPLE_INVALID; i++) { *f = try_order[i]; - + if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0) return ret; } @@ -312,14 +312,14 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p unsigned int c = ss->channels; pa_sample_format_t f = ss->format; snd_pcm_hw_params_t *hwparams; - + assert(pcm_handle); assert(ss); assert(periods); assert(period_size); buffer_size = *periods * *period_size; - + if ((ret = snd_pcm_hw_params_malloc(&hwparams)) < 0 || (ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 || (ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0 || @@ -359,25 +359,25 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p pa_log_warn("device doesn't support sample format %s, changed to %s.", pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f)); ss->format = f; } - + if ((ret = snd_pcm_prepare(pcm_handle)) < 0) goto finish; if ((ret = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size)) < 0 || (ret = snd_pcm_hw_params_get_period_size(hwparams, period_size, NULL)) < 0) goto finish; - + assert(buffer_size > 0); assert(*period_size > 0); *periods = buffer_size / *period_size; assert(*periods > 0); - + ret = 0; - + finish: if (hwparams) snd_pcm_hw_params_free(hwparams); - + return ret; } @@ -419,7 +419,7 @@ snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const if (fallback) { snd_mixer_selem_id_set_name(sid, fallback); - + if (!(elem = snd_mixer_find_selem(mixer, sid))) pa_log_warn("Cannot find fallback mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); } diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h index 215844b4..675856c6 100644 --- a/src/modules/alsa-util.h +++ b/src/modules/alsa-util.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/modules/dbus-util.c b/src/modules/dbus-util.c index 165ccff6..ee9062d1 100644 --- a/src/modules/dbus-util.c +++ b/src/modules/dbus-util.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/modules/dbus-util.h b/src/modules/dbus-util.h index 7a9871a4..73501c29 100644 --- a/src/modules/dbus-util.h +++ b/src/modules/dbus-util.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 6ff9a6e4..2fea5891 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -95,13 +95,13 @@ static void update_usage(struct userdata *u) { static void clear_up(struct userdata *u) { assert(u); - + if (u->sink) { pa_sink_disconnect(u->sink); pa_sink_unref(u->sink); u->sink = NULL; } - + if (u->pcm_fdl) pa_alsa_fdlist_free(u->pcm_fdl); if (u->mixer_fdl) @@ -113,7 +113,7 @@ static void clear_up(struct userdata *u) { snd_mixer_close(u->mixer_handle); u->mixer_handle = NULL; } - + if (u->pcm_handle) { snd_pcm_drop(u->pcm_handle); snd_pcm_close(u->pcm_handle); @@ -126,7 +126,7 @@ static int xrun_recovery(struct userdata *u) { assert(u); pa_log_info("*** ALSA-XRUN (playback) ***"); - + if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) { pa_log("snd_pcm_prepare() failed: %s", snd_strerror(-ret)); @@ -142,11 +142,11 @@ static void do_write(struct userdata *u) { assert(u); update_usage(u); - + for (;;) { pa_memchunk *memchunk = NULL; snd_pcm_sframes_t frames; - + if (u->memchunk.memblock) memchunk = &u->memchunk; else { @@ -155,7 +155,7 @@ static void do_write(struct userdata *u) { else memchunk = &u->memchunk; } - + assert(memchunk->memblock && memchunk->memblock->data && memchunk->length && memchunk->memblock->length && (memchunk->length % u->frame_size) == 0); if ((frames = snd_pcm_writei(u->pcm_handle, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length / u->frame_size)) < 0) { @@ -165,7 +165,7 @@ static void do_write(struct userdata *u) { if (frames == -EPIPE) { if (xrun_recovery(u) < 0) return; - + continue; } @@ -187,7 +187,7 @@ static void do_write(struct userdata *u) { memchunk->index = memchunk->length = 0; } } - + break; } } @@ -229,7 +229,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { struct userdata *u = s->userdata; snd_pcm_sframes_t frames; int err; - + assert(s && u && u->sink); if ((err = snd_pcm_delay(u->pcm_handle, &frames)) < 0) { @@ -292,14 +292,14 @@ static int sink_set_hw_volume_cb(pa_sink *s) { for (i = 0; i < s->hw_volume.channels; i++) { long alsa_vol; - + assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, i)); vol = s->hw_volume.values[i]; if (vol > PA_VOLUME_NORM) vol = PA_VOLUME_NORM; - + alsa_vol = (long) roundf(((float) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; if ((err = snd_mixer_selem_set_playback_volume(u->mixer_elem, i, alsa_vol)) < 0) @@ -367,7 +367,7 @@ int pa__init(pa_core *c, pa_module*m) { const char *name; char *name_buf = NULL; int namereg_fail; - + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("failed to parse module arguments"); goto fail; @@ -380,7 +380,7 @@ int pa__init(pa_core *c, pa_module*m) { } frame_size = pa_frame_size(&ss); - + /* Fix latency to 100ms */ periods = 8; fragsize = pa_bytes_per_second(&ss)/128; @@ -390,11 +390,11 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } period_size = fragsize/frame_size; - + u = pa_xnew0(struct userdata, 1); m->userdata = u; u->module = m; - + snd_config_update_free_global(); if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err)); @@ -415,7 +415,7 @@ int pa__init(pa_core *c, pa_module*m) { if (ss.channels != map.channels) /* Seems ALSA didn't like the channel number, so let's fix the channel map */ pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); - + if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) { pa_log("Error opening mixer: %s", snd_strerror(err)); goto fail; @@ -486,7 +486,7 @@ int pa__init(pa_core *c, pa_module*m) { snd_mixer_elem_set_callback_private(u->mixer_elem, u); } else u->mixer_fdl = NULL; - + u->frame_size = frame_size; u->fragment_size = period_size * frame_size; @@ -499,7 +499,7 @@ int pa__init(pa_core *c, pa_module*m) { u->memchunk.memblock = NULL; u->memchunk.index = u->memchunk.length = 0; - + ret = 0; /* Get initial mixer settings */ @@ -507,21 +507,21 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->get_hw_volume(u->sink); if (u->sink->get_hw_mute) u->sink->get_hw_mute(u->sink); - + finish: pa_xfree(name_buf); - + if (ma) pa_modargs_free(ma); if (pcm_info) snd_pcm_info_free(pcm_info); - + return ret; fail: - + if (u) pa__done(c, m); @@ -541,7 +541,7 @@ void pa__done(pa_core *c, pa_module*m) { pa_memblock_unref(u->memchunk.memblock); if (u->silence.memblock) pa_memblock_unref(u->silence.memblock); - + pa_xfree(u); } diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index aa0666f1..596998d1 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -96,13 +96,13 @@ static void update_usage(struct userdata *u) { static void clear_up(struct userdata *u) { assert(u); - + if (u->source) { pa_source_disconnect(u->source); pa_source_unref(u->source); u->source = NULL; } - + if (u->pcm_fdl) pa_alsa_fdlist_free(u->pcm_fdl); if (u->mixer_fdl) @@ -114,7 +114,7 @@ static void clear_up(struct userdata *u) { snd_mixer_close(u->mixer_handle); u->mixer_handle = NULL; } - + if (u->pcm_handle) { snd_pcm_drop(u->pcm_handle); snd_pcm_close(u->pcm_handle); @@ -127,7 +127,7 @@ static int xrun_recovery(struct userdata *u) { assert(u); pa_log_info("*** ALSA-XRUN (capture) ***"); - + if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) { pa_log("snd_pcm_prepare() failed: %s", snd_strerror(-ret)); @@ -144,17 +144,17 @@ static void do_read(struct userdata *u) { assert(u); update_usage(u); - + for (;;) { pa_memchunk post_memchunk; snd_pcm_sframes_t frames; size_t l; - + if (!u->memchunk.memblock) { u->memchunk.memblock = pa_memblock_new(u->source->core->mempool, u->memchunk.length = u->fragment_size); u->memchunk.index = 0; } - + assert(u->memchunk.memblock); assert(u->memchunk.length); assert(u->memchunk.memblock->data); @@ -164,11 +164,11 @@ static void do_read(struct userdata *u) { if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { if (frames == -EAGAIN) return; - + if (frames == -EPIPE) { if (xrun_recovery(u) < 0) return; - + continue; } @@ -180,7 +180,7 @@ static void do_read(struct userdata *u) { } l = frames * u->frame_size; - + post_memchunk = u->memchunk; post_memchunk.length = l; @@ -188,13 +188,13 @@ static void do_read(struct userdata *u) { u->memchunk.index += l; u->memchunk.length -= l; - + if (u->memchunk.length == 0) { pa_memblock_unref(u->memchunk.memblock); u->memchunk.memblock = NULL; u->memchunk.index = u->memchunk.length = 0; } - + break; } } @@ -223,7 +223,7 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { u->source->get_hw_volume(u->source); if (u->source->get_hw_mute) u->source->get_hw_mute(u->source); - + pa_subscription_post(u->source->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, u->source->index); @@ -256,14 +256,14 @@ static int source_get_hw_volume_cb(pa_source *s) { for (i = 0;i < s->hw_volume.channels;i++) { long set_vol; - + assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); - + if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, i, &vol)) < 0) goto fail; set_vol = (long) roundf(((float) s->hw_volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; - + /* Try to avoid superfluous volume changes */ if (set_vol != vol) s->hw_volume.values[i] = (pa_volume_t) roundf(((float) (vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min)); @@ -361,7 +361,7 @@ int pa__init(pa_core *c, pa_module*m) { const char *name; char *name_buf = NULL; int namereg_fail; - + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("failed to parse module arguments"); goto fail; @@ -378,17 +378,17 @@ int pa__init(pa_core *c, pa_module*m) { /* Fix latency to 100ms */ periods = 12; fragsize = pa_bytes_per_second(&ss)/128; - + if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { pa_log("failed to parse buffer metrics"); goto fail; } period_size = fragsize/frame_size; - + u = pa_xnew0(struct userdata, 1); m->userdata = u; u->module = m; - + snd_config_update_free_global(); if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err)); @@ -427,7 +427,7 @@ int pa__init(pa_core *c, pa_module*m) { name = name_buf = pa_sprintf_malloc("alsa_input.%s", dev); namereg_fail = 0; } - + if (!(u->source = pa_source_new(c, __FILE__, name, namereg_fail, &ss, &map))) { pa_log("Failed to create source object"); goto fail; @@ -490,7 +490,7 @@ int pa__init(pa_core *c, pa_module*m) { u->memchunk.index = u->memchunk.length = 0; snd_pcm_start(u->pcm_handle); - + ret = 0; /* Get initial mixer settings */ @@ -507,11 +507,11 @@ finish: if (pcm_info) snd_pcm_info_free(pcm_info); - + return ret; fail: - + if (u) pa__done(c, m); @@ -526,10 +526,10 @@ void pa__done(pa_core *c, pa_module*m) { return; clear_up(u); - + if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); - + pa_xfree(u); } diff --git a/src/modules/module-cli.c b/src/modules/module-cli.c index d5374838..b5c27299 100644 --- a/src/modules/module-cli.c +++ b/src/modules/module-cli.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -48,7 +48,7 @@ static const char* const valid_modargs[] = { static void eof_and_unload_cb(pa_cli*c, void *userdata) { pa_module *m = userdata; - + assert(c); assert(m); @@ -68,7 +68,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_iochannel *io; pa_modargs *ma; int exit_on_eof = 0; - + assert(c); assert(m); @@ -81,7 +81,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("failed to parse module arguments."); goto fail; } - + if (pa_modargs_get_value_boolean(ma, "exit_on_eof", &exit_on_eof) < 0) { pa_log("exit_on_eof= expects boolean argument."); goto fail; @@ -102,7 +102,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_cli_set_eof_callback(m->userdata, exit_on_eof ? eof_and_exit_cb : eof_and_unload_cb, m); pa_modargs_free(ma); - + return 0; fail: diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index f3bb3fd3..6bc958aa 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -91,7 +91,7 @@ struct userdata { struct output *master; pa_time_event *time_event; uint32_t adjust_time; - + PA_LLIST_HEAD(struct output, outputs); }; @@ -110,9 +110,9 @@ static void adjust_rates(struct userdata *u) { for (o = u->outputs; o; o = o->next) { uint32_t sink_latency = o->sink_input->sink ? pa_sink_get_latency(o->sink_input->sink) : 0; - + o->total_latency = sink_latency + pa_sink_input_get_latency(o->sink_input); - + if (sink_latency > max_sink_latency) max_sink_latency = sink_latency; @@ -123,14 +123,14 @@ static void adjust_rates(struct userdata *u) { assert(min_total_latency != (pa_usec_t) -1); target_latency = max_sink_latency > min_total_latency ? max_sink_latency : min_total_latency; - + pa_log_info("[%s] target latency is %0.0f usec.", u->sink->name, (float) target_latency); base_rate = u->sink->sample_spec.rate; for (o = u->outputs; o; o = o->next) { - uint32_t r = base_rate; - + uint32_t r = base_rate; + if (o->total_latency < target_latency) r -= (uint32_t) (((((double) target_latency - o->total_latency))/u->adjust_time)*r/ 1000000); else if (o->total_latency > target_latency) @@ -151,7 +151,7 @@ static void request_memblock(struct userdata *u) { assert(u && u->sink); update_usage(u); - + if (pa_sink_render(u->sink, RENDER_SIZE, &chunk) < 0) return; @@ -179,10 +179,10 @@ static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { if (pa_memblockq_peek(o->memblockq, chunk) >= 0) return 0; - + /* Try harder */ request_memblock(o->userdata); - + return pa_memblockq_peek(o->memblockq, chunk); } @@ -204,7 +204,7 @@ static void sink_input_kill_cb(pa_sink_input *i) { static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { struct output *o = i->userdata; assert(i && o && o->sink_input); - + return pa_bytes_to_usec(pa_memblockq_get_length(o->memblockq), &i->sample_spec); } @@ -220,11 +220,11 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { static void sink_notify(pa_sink *s) { struct userdata *u; struct output *o; - + assert(s); u = s->userdata; assert(u); - + for (o = u->outputs; o; o = o->next) pa_sink_notify(o->sink_input->sink); } @@ -233,12 +233,12 @@ static struct output *output_new(struct userdata *u, pa_sink *sink, int resample struct output *o = NULL; char t[256]; pa_sink_input_new_data data; - + assert(u && sink && u->sink); - + o = pa_xmalloc(sizeof(struct output)); o->userdata = u; - + o->counter = 0; o->memblockq = pa_memblockq_new( 0, @@ -258,7 +258,7 @@ static struct output *output_new(struct userdata *u, pa_sink *sink, int resample pa_sink_input_new_data_set_sample_spec(&data, &u->sink->sample_spec); pa_sink_input_new_data_set_channel_map(&data, &u->sink->channel_map); data.module = u->module; - + if (!(o->sink_input = pa_sink_input_new(u->core, &data, PA_SINK_INPUT_VARIABLE_RATE))) goto fail; @@ -267,7 +267,7 @@ static struct output *output_new(struct userdata *u, pa_sink *sink, int resample o->sink_input->drop = sink_input_drop_cb; o->sink_input->kill = sink_input_kill_cb; o->sink_input->userdata = o; - + PA_LLIST_PREPEND(struct output, u->outputs, o); u->n_outputs++; return o; @@ -282,7 +282,7 @@ fail: if (o->memblockq) pa_memblockq_free(o->memblockq); - + pa_xfree(o); } @@ -302,17 +302,17 @@ static void output_free(struct output *o) { static void clear_up(struct userdata *u) { struct output *o; assert(u); - + if (u->time_event) { u->core->mainloop->time_free(u->time_event); u->time_event = NULL; } - + while ((o = u->outputs)) output_free(o); u->master = NULL; - + if (u->sink) { pa_sink_disconnect(u->sink); pa_sink_unref(u->sink); @@ -331,7 +331,7 @@ int pa__init(pa_core *c, pa_module*m) { int resample_method = -1; pa_sample_spec ss; pa_channel_map map; - + assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -345,7 +345,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } } - + u = pa_xnew(struct userdata, 1); m->userdata = u; u->sink = NULL; @@ -361,7 +361,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("failed to parse adjust_time value"); goto fail; } - + if (!(master_name = pa_modargs_get_value(ma, "master", NULL)) || !(slaves = pa_modargs_get_value(ma, "slaves", NULL))) { pa_log("no master or slave sinks specified"); goto fail; @@ -392,7 +392,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("channel map and sample specification don't match."); goto fail; } - + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { pa_log("failed to create sink"); goto fail; @@ -403,16 +403,16 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->get_latency = sink_get_latency_cb; u->sink->notify = sink_notify; u->sink->userdata = u; - + if (!(u->master = output_new(u, master_sink, resample_method))) { pa_log("failed to create master sink input on sink '%s'.", u->sink->name); goto fail; } - + split_state = NULL; while ((n = pa_split(slaves, ",", &split_state))) { pa_sink *slave_sink; - + if (!(slave_sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) { pa_log("invalid slave sink '%s'", n); goto fail; @@ -425,7 +425,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } } - + if (u->n_outputs <= 1) pa_log_warn("WARNING: no slave sinks specified."); @@ -434,13 +434,13 @@ int pa__init(pa_core *c, pa_module*m) { tv.tv_sec += u->adjust_time; u->time_event = c->mainloop->time_new(c->mainloop, &tv, time_callback, u); } - + pa_modargs_free(ma); - return 0; + return 0; fail: pa_xfree(n); - + if (ma) pa_modargs_free(ma); diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index 84ccd14c..3057f70d 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -58,7 +58,7 @@ static int detect_alsa(pa_core *c, int just_one) { if (errno != ENOENT) pa_log_error("open(\"/proc/asound/devices\") failed: %s", pa_cstrerror(errno)); - + return -1; } @@ -66,7 +66,7 @@ static int detect_alsa(pa_core *c, int just_one) { char line[64], args[64]; unsigned device, subdevice; int is_sink; - + if (!fgets(line, sizeof(line), f)) break; @@ -81,7 +81,7 @@ static int detect_alsa(pa_core *c, int just_one) { if (just_one && is_sink && n_sink >= 1) continue; - + if (just_one && !is_sink && n_source >= 1) continue; @@ -105,7 +105,7 @@ static int detect_alsa(pa_core *c, int just_one) { } fclose(f); - + return n; } #endif @@ -114,7 +114,7 @@ static int detect_alsa(pa_core *c, int just_one) { static int detect_oss(pa_core *c, int just_one) { FILE *f; int n = 0, b = 0; - + if (!(f = fopen("/dev/sndstat", "r")) && !(f = fopen("/proc/sndstat", "r")) && !(f = fopen("/proc/asound/oss/sndstat", "r"))) { @@ -128,7 +128,7 @@ static int detect_oss(pa_core *c, int just_one) { while (!feof(f)) { char line[64], args[64]; unsigned device; - + if (!fgets(line, sizeof(line), f)) break; @@ -141,20 +141,20 @@ static int detect_oss(pa_core *c, int just_one) { if (line[0] == 0) break; - + if (sscanf(line, "%u: ", &device) == 1) { if (device == 0) snprintf(args, sizeof(args), "device=/dev/dsp"); else snprintf(args, sizeof(args), "device=/dev/dsp%u", device); - + if (!pa_module_load(c, "module-oss", args)) continue; - + } else if (sscanf(line, "pcm%u: ", &device) == 1) { /* FreeBSD support, the devices are named /dev/dsp0.0, dsp0.1 and so on */ snprintf(args, sizeof(args), "device=/dev/dsp%u.0", device); - + if (!pa_module_load(c, "module-oss", args)) continue; } @@ -219,7 +219,7 @@ int pa__init(pa_core *c, pa_module*m) { "just-one", NULL }; - + assert(c); assert(m); @@ -227,14 +227,14 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("Failed to parse module arguments"); goto fail; } - + if (pa_modargs_get_value_boolean(ma, "just-one", &just_one) < 0) { pa_log("just_one= expects a boolean argument."); goto fail; } #if HAVE_ALSA - if ((n = detect_alsa(c, just_one)) <= 0) + if ((n = detect_alsa(c, just_one)) <= 0) #endif #if HAVE_OSS if ((n = detect_oss(c, just_one)) <= 0) @@ -251,7 +251,7 @@ int pa__init(pa_core *c, pa_module*m) { } pa_log_info("loaded %i modules.", n); - + /* We were successful and can unload ourselves now. */ pa_module_unload_request(m); @@ -262,7 +262,7 @@ int pa__init(pa_core *c, pa_module*m) { fail: if (ma) pa_modargs_free(ma); - + return -1; } diff --git a/src/modules/module-esound-compat-spawnfd.c b/src/modules/module-esound-compat-spawnfd.c index 263e81f9..fbb6bd6d 100644 --- a/src/modules/module-esound-compat-spawnfd.c +++ b/src/modules/module-esound-compat-spawnfd.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/modules/module-esound-compat-spawnpid.c b/src/modules/module-esound-compat-spawnpid.c index 7a662c2d..a7196313 100644 --- a/src/modules/module-esound-compat-spawnpid.c +++ b/src/modules/module-esound-compat-spawnpid.c @@ -1,17 +1,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index 6d4a8489..62600682 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -69,7 +69,7 @@ struct userdata { void *write_data; size_t write_length, write_index; - + void *read_data; size_t read_length, read_index; @@ -135,7 +135,7 @@ static int do_write(struct userdata *u) { u->write_index += r; assert(u->write_index <= u->write_length); - + if (u->write_index == u->write_length) { free(u->write_data); u->write_data = NULL; @@ -143,13 +143,13 @@ static int do_write(struct userdata *u) { } } else if (u->state == STATE_RUNNING) { pa_module_set_used(u->module, pa_sink_used_by(u->sink)); - + if (!u->memchunk.length) if (pa_sink_render(u->sink, 8192, &u->memchunk) < 0) return 0; assert(u->memchunk.memblock && u->memchunk.length); - + if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { pa_log("write() failed: %s", pa_cstrerror(errno)); return -1; @@ -157,13 +157,13 @@ static int do_write(struct userdata *u) { u->memchunk.index += r; u->memchunk.length -= r; - + if (u->memchunk.length <= 0) { pa_memblock_unref(u->memchunk.memblock); u->memchunk.memblock = NULL; } } - + return 0; } @@ -191,7 +191,7 @@ static int handle_response(struct userdata *u) { assert(u->read_length >= sizeof(int32_t)); u->read_index = 0; u->read_length = sizeof(int32_t); - + break; case STATE_LATENCY: { @@ -220,10 +220,10 @@ static int handle_response(struct userdata *u) { pa_xfree(u->read_data); u->read_data = NULL; u->read_index = u->read_length = 0; - + break; } - + default: abort(); } @@ -233,18 +233,18 @@ static int handle_response(struct userdata *u) { static int do_read(struct userdata *u) { assert(u); - + if (!pa_iochannel_is_readable(u->io)) return 0; - + if (u->state == STATE_AUTH || u->state == STATE_LATENCY) { ssize_t r; - + if (!u->read_data) return 0; - + assert(u->read_index < u->read_length); - + if ((r = pa_iochannel_read(u->io, (uint8_t*) u->read_data + u->read_index, u->read_length - u->read_index)) <= 0) { pa_log("read() failed: %s", r < 0 ? pa_cstrerror(errno) : "EOF"); cancel(u); @@ -265,7 +265,7 @@ static void do_work(struct userdata *u) { assert(u); u->core->mainloop->defer_enable(u->defer_event, 0); - + if (do_read(u) < 0 || do_write(u) < 0) cancel(u); } @@ -304,13 +304,13 @@ static void on_connection(PA_GCC_UNUSED pa_socket_client *c, pa_iochannel*io, vo pa_socket_client_unref(u->client); u->client = NULL; - + if (!io) { pa_log("connection failed: %s", pa_cstrerror(errno)); cancel(u); return; } - + u->io = io; pa_iochannel_set_callback(u->io, io_callback, u); } @@ -321,9 +321,9 @@ int pa__init(pa_core *c, pa_module*m) { pa_sample_spec ss; pa_modargs *ma = NULL; char *t; - + assert(c && m); - + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("failed to parse module arguments"); goto fail; @@ -340,7 +340,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("esound sample type support is limited to mono/stereo and U8 or S16NE sample data"); goto fail; } - + u = pa_xmalloc0(sizeof(struct userdata)); u->core = c; u->module = m; @@ -378,7 +378,7 @@ int pa__init(pa_core *c, pa_module*m) { /* Reserve space for the response */ u->read_data = pa_xmalloc(u->read_length = sizeof(int32_t)); - + u->sink->notify = notify_cb; u->sink->get_latency = get_latency_cb; u->sink->userdata = u; @@ -392,15 +392,15 @@ int pa__init(pa_core *c, pa_module*m) { u->defer_event = c->mainloop->defer_new(c->mainloop, defer_callback, u); c->mainloop->defer_enable(u->defer_event, 0); - + pa_modargs_free(ma); - + return 0; fail: if (ma) pa_modargs_free(ma); - + pa__done(c, m); return -1; @@ -415,13 +415,13 @@ void pa__done(pa_core *c, pa_module*m) { u->module = NULL; cancel(u); - + if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); if (u->client) pa_socket_client_unref(u->client); - + pa_xfree(u->read_data); pa_xfree(u->write_data); diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index 8232cd38..eb275ff0 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -58,7 +58,7 @@ typedef enum { #endif #ifdef HAVE_OSS CAP_OSS, -#endif +#endif CAP_MAX } capability_t; @@ -181,7 +181,7 @@ static pa_module* hal_device_load_alsa(struct userdata *u, const char *udi, module_name = "module-alsa-source"; snprintf(args, sizeof(args), "device=hw:%u source_name=alsa_input.%s", card, strip_udi(udi)); } - + return pa_module_load(u->core, module_name, args); } @@ -198,7 +198,7 @@ static dbus_bool_t hal_device_is_oss_pcm(LibHalContext *ctx, const char *udi, type = libhal_device_get_property_string(ctx, udi, "oss.type", error); if (!type || dbus_error_is_set(error)) return FALSE; - + if (!strcmp(type, "pcm")) { char *e; diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index 47f77bab..6175536c 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -75,7 +75,7 @@ struct userdata { pthread_mutex_t mutex; pthread_cond_t cond; - + void * buffer[PA_CHANNELS_MAX]; jack_nframes_t frames_requested; int quit_requested; @@ -100,7 +100,7 @@ static const char* const valid_modargs[] = { static void stop_sink(struct userdata *u) { assert (u); - + jack_client_close(u->client); u->client = NULL; u->core->mainloop->io_free(u->io_event); @@ -114,7 +114,7 @@ static void stop_sink(struct userdata *u) { static void io_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) { struct userdata *u = userdata; char x; - + assert(m); assert(e); assert(flags == PA_IO_EVENT_INPUT); @@ -122,39 +122,39 @@ static void io_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_ assert(u->pipe_fds[0] == fd); pa_read(fd, &x, 1, &u->pipe_fd_type); - + if (u->quit_requested) { stop_sink(u); u->quit_requested = 0; return; } - + pthread_mutex_lock(&u->mutex); if (u->frames_requested > 0) { unsigned fs; jack_nframes_t frame_idx; pa_memchunk chunk; - + fs = pa_frame_size(&u->sink->sample_spec); pa_sink_render_full(u->sink, u->frames_requested * fs, &chunk); for (frame_idx = 0; frame_idx < u->frames_requested; frame_idx ++) { unsigned c; - + for (c = 0; c < u->channels; c++) { float *s = ((float*) ((uint8_t*) chunk.memblock->data + chunk.index)) + (frame_idx * u->channels) + c; float *d = ((float*) u->buffer[c]) + frame_idx; - + *d = *s; } } - + pa_memblock_unref(chunk.memblock); u->frames_requested = 0; - + pthread_cond_signal(&u->cond); } @@ -183,36 +183,36 @@ static int jack_process(jack_nframes_t nframes, void *arg) { if (jack_transport_query(u->client, NULL) == JackTransportRolling) { unsigned c; - + pthread_mutex_lock(&u->mutex); - + u->frames_requested = nframes; - + for (c = 0; c < u->channels; c++) { u->buffer[c] = jack_port_get_buffer(u->port[c], nframes); assert(u->buffer[c]); } - + request_render(u); - + pthread_cond_wait(&u->cond, &u->mutex); u->frames_in_buffer = nframes; u->timestamp = jack_get_current_transport_frame(u->client); - + pthread_mutex_unlock(&u->mutex); } - + return 0; } static pa_usec_t sink_get_latency_cb(pa_sink *s) { struct userdata *u; jack_nframes_t n, l, d; - + assert(s); u = s->userdata; - + if (jack_transport_query(u->client, NULL) != JackTransportRolling) return 0; @@ -226,7 +226,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { if (d >= l) return 0; - + return pa_bytes_to_usec((l - d) * pa_frame_size(&s->sample_spec), &s->sample_spec); } @@ -246,12 +246,12 @@ int pa__init(pa_core *c, pa_module*m) { unsigned i; const char **ports = NULL, **p; char *t; - + assert(c); assert(m); jack_set_error_function(jack_error_func); - + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("failed to parse module arguments."); goto fail; @@ -261,7 +261,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("failed to parse connect= argument."); goto fail; } - + server_name = pa_modargs_get_value(ma, "server_name", NULL); client_name = pa_modargs_get_value(ma, "client_name", "PulseAudio"); @@ -274,28 +274,28 @@ int pa__init(pa_core *c, pa_module*m) { pthread_mutex_init(&u->mutex, NULL); pthread_cond_init(&u->cond, NULL); - + if (pipe(u->pipe_fds) < 0) { pa_log("pipe() failed: %s", pa_cstrerror(errno)); goto fail; } pa_make_nonblock_fd(u->pipe_fds[1]); - + if (!(u->client = jack_client_open(client_name, server_name ? JackServerName : JackNullOption, &status, server_name))) { pa_log("jack_client_open() failed."); goto fail; } ports = jack_get_ports(u->client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); - + channels = 0; for (p = ports; *p; p++) channels++; if (!channels) channels = c->default_sample_spec.channels; - + if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0 || channels <= 0 || channels >= PA_CHANNELS_MAX) { pa_log("failed to parse channels= argument."); goto fail; @@ -306,7 +306,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("failed to parse channel_map= argument."); goto fail; } - + pa_log_info("Successfully connected as '%s'", jack_get_client_name(u->client)); ss.channels = u->channels = channels; @@ -350,7 +350,7 @@ int pa__init(pa_core *c, pa_module*m) { } pa_log_info("connecting %s to %s", jack_port_name(u->port[i]), *p); - + if (jack_connect(u->client, jack_port_name(u->port[i]), *p)) { pa_log("failed to connect %s to %s, leaving unconnected.", jack_port_name(u->port[i]), *p); break; @@ -360,10 +360,10 @@ int pa__init(pa_core *c, pa_module*m) { } u->io_event = c->mainloop->io_new(c->mainloop, u->pipe_fds[0], PA_IO_EVENT_INPUT, io_event_cb, u); - + free(ports); pa_modargs_free(ma); - + return 0; fail: @@ -371,7 +371,7 @@ fail: pa_modargs_free(ma); free(ports); - + pa__done(c, m); return -1; diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index 62a99108..8d891ce6 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -75,7 +75,7 @@ struct userdata { pthread_mutex_t mutex; pthread_cond_t cond; - + void * buffer[PA_CHANNELS_MAX]; jack_nframes_t frames_posted; int quit_requested; @@ -100,7 +100,7 @@ static const char* const valid_modargs[] = { static void stop_source(struct userdata *u) { assert (u); - + jack_client_close(u->client); u->client = NULL; u->core->mainloop->io_free(u->io_event); @@ -114,39 +114,39 @@ static void stop_source(struct userdata *u) { static void io_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) { struct userdata *u = userdata; char x; - + assert(m); assert(flags == PA_IO_EVENT_INPUT); assert(u); assert(u->pipe_fds[0] == fd); pa_read(fd, &x, 1, &u->pipe_fd_type); - + if (u->quit_requested) { stop_source(u); u->quit_requested = 0; return; } - + pthread_mutex_lock(&u->mutex); if (u->frames_posted > 0) { unsigned fs; jack_nframes_t frame_idx; pa_memchunk chunk; - + fs = pa_frame_size(&u->source->sample_spec); chunk.memblock = pa_memblock_new(u->core->mempool, chunk.length = u->frames_posted * fs); chunk.index = 0; - + for (frame_idx = 0; frame_idx < u->frames_posted; frame_idx ++) { unsigned c; - + for (c = 0; c < u->channels; c++) { float *s = ((float*) u->buffer[c]) + frame_idx; float *d = ((float*) ((uint8_t*) chunk.memblock->data + chunk.index)) + (frame_idx * u->channels) + c; - + *d = *s; } } @@ -155,7 +155,7 @@ static void io_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_ pa_memblock_unref(chunk.memblock); u->frames_posted = 0; - + pthread_cond_signal(&u->cond); } @@ -184,36 +184,36 @@ static int jack_process(jack_nframes_t nframes, void *arg) { if (jack_transport_query(u->client, NULL) == JackTransportRolling) { unsigned c; - + pthread_mutex_lock(&u->mutex); - + u->frames_posted = nframes; - + for (c = 0; c < u->channels; c++) { u->buffer[c] = jack_port_get_buffer(u->port[c], nframes); assert(u->buffer[c]); } - + request_post(u); - + pthread_cond_wait(&u->cond, &u->mutex); u->frames_in_buffer = nframes; u->timestamp = jack_get_current_transport_frame(u->client); - + pthread_mutex_unlock(&u->mutex); } - + return 0; } static pa_usec_t source_get_latency_cb(pa_source *s) { struct userdata *u; jack_nframes_t n, l, d; - + assert(s); u = s->userdata; - + if (jack_transport_query(u->client, NULL) != JackTransportRolling) return 0; @@ -224,7 +224,7 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { d = n - u->timestamp; l = jack_port_get_total_latency(u->client, u->port[0]); - + return pa_bytes_to_usec((l + d) * pa_frame_size(&s->sample_spec), &s->sample_spec); } @@ -244,12 +244,12 @@ int pa__init(pa_core *c, pa_module*m) { unsigned i; const char **ports = NULL, **p; char *t; - + assert(c); assert(m); jack_set_error_function(jack_error_func); - + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("failed to parse module arguments."); goto fail; @@ -259,7 +259,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("failed to parse connect= argument."); goto fail; } - + server_name = pa_modargs_get_value(ma, "server_name", NULL); client_name = pa_modargs_get_value(ma, "client_name", "PulseAudio"); @@ -272,28 +272,28 @@ int pa__init(pa_core *c, pa_module*m) { pthread_mutex_init(&u->mutex, NULL); pthread_cond_init(&u->cond, NULL); - + if (pipe(u->pipe_fds) < 0) { pa_log("pipe() failed: %s", pa_cstrerror(errno)); goto fail; } pa_make_nonblock_fd(u->pipe_fds[1]); - + if (!(u->client = jack_client_open(client_name, server_name ? JackServerName : JackNullOption, &status, server_name))) { pa_log("jack_client_open() failed."); goto fail; } ports = jack_get_ports(u->client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput); - + channels = 0; for (p = ports; *p; p++) channels++; if (!channels) channels = c->default_sample_spec.channels; - + if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0 || channels <= 0 || channels >= PA_CHANNELS_MAX) { pa_log("failed to parse channels= argument."); goto fail; @@ -304,7 +304,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("failed to parse channel_map= argument."); goto fail; } - + pa_log_info("Successfully connected as '%s'", jack_get_client_name(u->client)); ss.channels = u->channels = channels; @@ -348,7 +348,7 @@ int pa__init(pa_core *c, pa_module*m) { } pa_log_info("connecting %s to %s", jack_port_name(u->port[i]), *p); - + if (jack_connect(u->client, *p, jack_port_name(u->port[i]))) { pa_log("failed to connect %s to %s, leaving unconnected.", jack_port_name(u->port[i]), *p); break; @@ -358,10 +358,10 @@ int pa__init(pa_core *c, pa_module*m) { } u->io_event = c->mainloop->io_new(c->mainloop, u->pipe_fds[0], PA_IO_EVENT_INPUT, io_event_cb, u); - + free(ports); pa_modargs_free(ma); - + return 0; fail: @@ -369,7 +369,7 @@ fail: pa_modargs_free(ma); free(ports); - + pa__done(c, m); return -1; diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c index 18b2ddf1..f32667ee 100644 --- a/src/modules/module-lirc.c +++ b/src/modules/module-lirc.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -73,20 +73,20 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC pa_log("lost connection to LIRC daemon."); goto fail; } - + if (events & PA_IO_EVENT_INPUT) { char *c; - + if (lirc_nextcode(&code) != 0 || !code) { pa_log("lirc_nextcode() failed."); goto fail; } - + c = pa_xstrdup(code); c[strcspn(c, "\n\r")] = 0; pa_log_debug("raw IR code '%s'", c); pa_xfree(c); - + while (lirc_code2char(u->config, code, &name) == 0 && name) { enum { INVALID, @@ -96,9 +96,9 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC RESET, MUTE_TOGGLE } volchange = INVALID; - + pa_log_info("translated IR code '%s'", name); - + if (strcasecmp(name, "volume-up") == 0) volchange = UP; else if (strcasecmp(name, "volume-down") == 0) @@ -109,12 +109,12 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC volchange = MUTE_TOGGLE; else if (strcasecmp(name, "reset") == 0) volchange = RESET; - + if (volchange == INVALID) pa_log_warn("recieved unknown IR code '%s'", name); else { pa_sink *s; - + if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) pa_log("failed to get sink '%s'", u->sink_name); else { @@ -134,7 +134,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); break; - + case DOWN: for (i = 0; i < cv.channels; i++) { if (cv.values[i] >= DELTA) @@ -142,18 +142,18 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC else cv.values[i] = PA_VOLUME_MUTED; } - + pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); break; - + case MUTE: pa_sink_set_mute(s, PA_MIXER_HARDWARE, 0); break; - + case RESET: pa_sink_set_mute(s, PA_MIXER_HARDWARE, 1); break; - + case MUTE_TOGGLE: pa_sink_set_mute(s, PA_MIXER_HARDWARE, !pa_sink_get_mute(s, PA_MIXER_HARDWARE)); @@ -170,7 +170,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC pa_xfree(code); return; - + fail: u->module->core->mainloop->io_free(u->io); u->io = NULL; @@ -179,7 +179,7 @@ fail: free(code); } - + int pa__init(pa_core *c, pa_module*m) { pa_modargs *ma = NULL; struct userdata *u; @@ -189,7 +189,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("module-lirc may no be loaded twice."); return -1; } - + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments"); goto fail; @@ -212,13 +212,13 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("lirc_readconfig() failed."); goto fail; } - + u->io = c->mainloop->io_new(c->mainloop, u->lirc_fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u); lirc_in_use = 1; pa_modargs_free(ma); - + return 0; fail: diff --git a/src/modules/module-match.c b/src/modules/module-match.c index eb5de64e..d0e82ba3 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -88,7 +88,7 @@ static int load_rules(struct userdata *u, const char *filename) { } pa_lock_fd(fileno(f), 1); - + while (!feof(f)) { char *d, *v; pa_volume_t volume; @@ -96,12 +96,12 @@ static int load_rules(struct userdata *u, const char *filename) { regex_t regex; char ln[256]; struct rule *rule; - + if (!fgets(ln, sizeof(ln), f)) break; n++; - + pa_strip_nl(ln); if (ln[0] == '#' || !*ln ) @@ -110,7 +110,7 @@ static int load_rules(struct userdata *u, const char *filename) { d = ln+strcspn(ln, WHITESPACE); v = d+strspn(d, WHITESPACE); - + if (!*v) { pa_log(__FILE__ ": [%s:%u] failed to parse line - too few words", filename, n); goto finish; @@ -124,7 +124,7 @@ static int load_rules(struct userdata *u, const char *filename) { volume = (pa_volume_t) k; - + if (regcomp(®ex, ln, REG_EXTENDED|REG_NOSUB) != 0) { pa_log("[%s:%u] invalid regular expression", filename, n); goto finish; @@ -140,12 +140,12 @@ static int load_rules(struct userdata *u, const char *filename) { else u->rules = rule; end = rule; - + *d = 0; } ret = 0; - + finish: if (f) { pa_lock_fd(fileno(f), 0); @@ -172,7 +172,7 @@ static void callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, v if (!si->name) return; - + for (r = u->rules; r; r = r->next) { if (!regexec(&r->regex, si->name, 0, NULL, 0)) { pa_cvolume cv; @@ -197,7 +197,7 @@ int pa__init(pa_core *c, pa_module*m) { u->rules = NULL; u->subscription = NULL; m->userdata = u; - + if (load_rules(u, pa_modargs_get_value(ma, "table", NULL)) < 0) goto fail; @@ -224,7 +224,7 @@ void pa__done(pa_core *c, pa_module*m) { if (u->subscription) pa_subscription_free(u->subscription); - + for (r = u->rules; r; r = n) { n = r->next; diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c index 37234d92..baf688f1 100644 --- a/src/modules/module-mmkbd-evdev.c +++ b/src/modules/module-mmkbd-evdev.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -85,7 +85,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC pa_log("lost connection to evdev device."); goto fail; } - + if (events & PA_IO_EVENT_INPUT) { struct input_event ev; @@ -107,15 +107,15 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC if (volchange != INVALID) { pa_sink *s; - + if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) pa_log("failed to get sink '%s'", u->sink_name); else { int i; pa_cvolume cv = *pa_sink_get_volume(s, PA_MIXER_HARDWARE); - + #define DELTA (PA_VOLUME_NORM/20) - + switch (volchange) { case UP: for (i = 0; i < cv.channels; i++) { @@ -127,7 +127,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); break; - + case DOWN: for (i = 0; i < cv.channels; i++) { if (cv.values[i] >= DELTA) @@ -135,10 +135,10 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC else cv.values[i] = PA_VOLUME_MUTED; } - + pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); break; - + case MUTE_TOGGLE: pa_sink_set_mute(s, PA_MIXER_HARDWARE, !pa_sink_get_mute(s, PA_MIXER_HARDWARE)); @@ -153,7 +153,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC } return; - + fail: u->module->core->mainloop->io_free(u->io); u->io = NULL; @@ -162,7 +162,7 @@ fail: } #define test_bit(bit, array) (array[bit/8] & (1<<(bit%8))) - + int pa__init(pa_core *c, pa_module*m) { pa_modargs *ma = NULL; struct userdata *u; @@ -226,7 +226,7 @@ int pa__init(pa_core *c, pa_module*m) { u->io = c->mainloop->io_new(c->mainloop, u->fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u); pa_modargs_free(ma); - + return 0; fail: diff --git a/src/modules/module-native-protocol-fd.c b/src/modules/module-native-protocol-fd.c index dd3b4abe..907aab27 100644 --- a/src/modules/module-native-protocol-fd.c +++ b/src/modules/module-native-protocol-fd.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -61,7 +61,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("invalid file descriptor."); goto finish; } - + io = pa_iochannel_new(c->mainloop, fd, fd); if (!(m->userdata = pa_protocol_native_new_iochannel(c, io, m, ma))) { @@ -74,7 +74,7 @@ int pa__init(pa_core *c, pa_module*m) { finish: if (ma) pa_modargs_free(ma); - + return r; } diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index 50e58853..fc9107a3 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -115,10 +115,10 @@ int pa__init(pa_core *c, pa_module*m) { pa_sample_spec ss; pa_channel_map map; pa_modargs *ma = NULL; - + assert(c); assert(m); - + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("failed to parse module arguments."); goto fail; @@ -129,12 +129,12 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("invalid sample format specification or channel map."); goto fail; } - + u = pa_xnew0(struct userdata, 1); u->core = c; u->module = m; m->userdata = u; - + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { pa_log("failed to create sink."); goto fail; @@ -147,19 +147,19 @@ int pa__init(pa_core *c, pa_module*m) { u->n_bytes = 0; pa_gettimeofday(&u->start_time); - + u->time_event = c->mainloop->time_new(c->mainloop, &u->start_time, time_callback, u); u->block_size = pa_bytes_per_second(&ss) / 10; - + pa_modargs_free(ma); - + return 0; fail: if (ma) pa_modargs_free(ma); - + pa__done(c, m); return -1; @@ -171,7 +171,7 @@ void pa__done(pa_core *c, pa_module*m) { if (!(u = m->userdata)) return; - + pa_sink_disconnect(u->sink); pa_sink_unref(u->sink); diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index 5ab08287..7bf6cbbd 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -113,7 +113,7 @@ static const char* const valid_modargs[] = { #define DEFAULT_FRAGSIZE 1024 static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, + pa_module_set_used(u->module, (u->sink ? pa_sink_used_by(u->sink) : 0) + (u->source ? pa_source_used_by(u->source) : 0)); } @@ -126,7 +126,7 @@ static void clear_up(struct userdata *u) { pa_sink_unref(u->sink); u->sink = NULL; } - + if (u->source) { pa_source_disconnect(u->source); pa_source_unref(u->source); @@ -137,12 +137,12 @@ static void clear_up(struct userdata *u) { munmap(u->in_mmap, u->in_mmap_length); u->in_mmap = NULL; } - + if (u->out_mmap && u->out_mmap != MAP_FAILED) { munmap(u->out_mmap, u->out_mmap_length); u->out_mmap = NULL; } - + if (u->io_event) { u->core->mainloop->io_free(u->io_event); u->io_event = NULL; @@ -156,13 +156,13 @@ static void clear_up(struct userdata *u) { static void out_fill_memblocks(struct userdata *u, unsigned n) { assert(u && u->out_memblocks); - + while (n > 0) { pa_memchunk chunk; - + if (u->out_memblocks[u->out_current]) pa_memblock_unref_fixed(u->out_memblocks[u->out_current]); - + chunk.memblock = u->out_memblocks[u->out_current] = pa_memblock_new_fixed( u->core->mempool, @@ -172,13 +172,13 @@ static void out_fill_memblocks(struct userdata *u, unsigned n) { assert(chunk.memblock); chunk.length = chunk.memblock->length; chunk.index = 0; - + pa_sink_render_into_full(u->sink, &chunk); - + u->out_current++; while (u->out_current >= u->out_fragments) u->out_current -= u->out_fragments; - + n--; } } @@ -188,7 +188,7 @@ static void do_write(struct userdata *u) { assert(u && u->sink); update_usage(u); - + if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno)); @@ -199,31 +199,31 @@ static void do_write(struct userdata *u) { info.blocks += u->out_blocks_saved; u->out_blocks_saved = 0; - + if (!info.blocks) return; - + out_fill_memblocks(u, info.blocks); } static void in_post_memblocks(struct userdata *u, unsigned n) { assert(u && u->in_memblocks); - + while (n > 0) { pa_memchunk chunk; - + if (!u->in_memblocks[u->in_current]) { chunk.memblock = u->in_memblocks[u->in_current] = pa_memblock_new_fixed(u->core->mempool, (uint8_t*) u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size, 1); chunk.length = chunk.memblock->length; chunk.index = 0; - + pa_source_post(u->source, &chunk); } u->in_current++; while (u->in_current >= u->in_fragments) u->in_current -= u->in_fragments; - + n--; } } @@ -234,7 +234,7 @@ static void in_clear_memblocks(struct userdata*u, unsigned n) { if (n > u->in_fragments) n = u->in_fragments; - + while (n > 0) { if (u->in_memblocks[i]) { pa_memblock_unref_fixed(u->in_memblocks[i]); @@ -254,7 +254,7 @@ static void do_read(struct userdata *u) { assert(u && u->source); update_usage(u); - + if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno)); @@ -265,10 +265,10 @@ static void do_read(struct userdata *u) { info.blocks += u->in_blocks_saved; u->in_blocks_saved = 0; - + if (!info.blocks) return; - + in_post_memblocks(u, info.blocks); in_clear_memblocks(u, u->in_fragments/2); } @@ -311,7 +311,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { n = bpos - info.ptr; /* pa_log("n = %u, bpos = %u, ptr = %u, total=%u, fragsize = %u, n_frags = %u\n", n, bpos, (unsigned) info.ptr, total, u->out_fragment_size, u->out_fragments); */ - + return pa_bytes_to_usec(n, &s->sample_spec); } @@ -337,7 +337,7 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { n = (u->in_fragments * u->in_fragment_size) - bpos + info.ptr; /* pa_log("n = %u, bpos = %u, ptr = %u, total=%u, fragsize = %u, n_frags = %u\n", n, bpos, (unsigned) info.ptr, total, u->in_fragment_size, u->in_fragments); */ - + return pa_bytes_to_usec(n, &s->sample_spec); } @@ -416,7 +416,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("failed to parse module arguments."); goto fail; } - + if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { pa_log("record= and playback= expect numeric arguments."); goto fail; @@ -460,7 +460,7 @@ int pa__init(pa_core *c, pa_module*m) { if (nfrags >= 2 && frag_size >= 1) if (pa_oss_set_fragments(u->fd, nfrags, frag_size) < 0) goto fail; - + if (pa_oss_auto_format(u->fd, &u->sample_spec) < 0) goto fail; @@ -491,7 +491,7 @@ int pa__init(pa_core *c, pa_module*m) { if (!(u->source = pa_source_new(c, __FILE__, name, namereg_fail, &u->sample_spec, &map))) goto fail; - + u->source->userdata = u; u->source->get_latency = source_get_latency_cb; u->source->get_hw_volume = source_get_hw_volume; @@ -504,22 +504,22 @@ int pa__init(pa_core *c, pa_module*m) { hwdesc[0] ? ")" : "")); pa_xfree(t); u->source->is_hardware = 1; - + u->in_memblocks = pa_xnew0(pa_memblock*, u->in_fragments); - + enable_bits |= PCM_ENABLE_INPUT; } } pa_xfree(name_buf); name_buf = NULL; - + if (mode != O_RDONLY) { if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { pa_log("SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno)); goto fail; } - + pa_log_info("output -- %u fragments of size %u.", info.fragstotal, info.fragsize); u->out_mmap_length = (u->out_fragment_size = info.fragsize) * (u->out_fragments = info.fragstotal); @@ -540,7 +540,7 @@ int pa__init(pa_core *c, pa_module*m) { name = name_buf = pa_sprintf_malloc("oss_output.%s", pa_path_get_filename(p)); namereg_fail = 0; } - + if (!(u->sink = pa_sink_new(c, __FILE__, name, namereg_fail, &u->sample_spec, &map))) goto fail; @@ -555,28 +555,28 @@ int pa__init(pa_core *c, pa_module*m) { hwdesc[0] ? hwdesc : "", hwdesc[0] ? ")" : "")); pa_xfree(t); - + u->sink->is_hardware = 1; u->out_memblocks = pa_xmalloc0(sizeof(struct memblock *)*u->out_fragments); - + enable_bits |= PCM_ENABLE_OUTPUT; } } pa_xfree(name_buf); name_buf = NULL; - + zero = 0; if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero) < 0) { pa_log("SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno)); goto fail; } - + if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0) { pa_log("SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno)); goto fail; } - + assert(u->source || u->sink); u->io_event = c->mainloop->io_new(c->mainloop, u->fd, (u->source ? PA_IO_EVENT_INPUT : 0) | (u->sink ? PA_IO_EVENT_OUTPUT : 0), io_callback, u); @@ -589,7 +589,7 @@ int pa__init(pa_core *c, pa_module*m) { source_get_hw_volume(u->source); if (u->sink) sink_get_hw_volume(u->sink); - + return 0; fail: @@ -599,13 +599,13 @@ fail: pa_modargs_free(ma); pa_xfree(name_buf); - + return -1; } void pa__done(pa_core *c, pa_module*m) { struct userdata *u; - + assert(c); assert(m); @@ -629,6 +629,6 @@ void pa__done(pa_core *c, pa_module*m) { pa_memblock_unref_fixed(u->in_memblocks[i]); pa_xfree(u->in_memblocks); } - + pa_xfree(u); } diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index b71581d9..b8ced86f 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -100,20 +100,20 @@ static const char* const valid_modargs[] = { #define DEFAULT_DEVICE "/dev/dsp" static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, + pa_module_set_used(u->module, (u->sink ? pa_sink_used_by(u->sink) : 0) + (u->source ? pa_source_used_by(u->source) : 0)); } static void clear_up(struct userdata *u) { assert(u); - + if (u->sink) { pa_sink_disconnect(u->sink); pa_sink_unref(u->sink); u->sink = NULL; } - + if (u->source) { pa_source_disconnect(u->source); pa_source_unref(u->source); @@ -131,7 +131,7 @@ static void do_write(struct userdata *u) { ssize_t r; size_t l; int loop = 0; - + assert(u); if (!u->sink || !pa_iochannel_is_writable(u->io)) @@ -140,10 +140,10 @@ static void do_write(struct userdata *u) { update_usage(u); l = u->out_fragment_size; - + if (u->use_getospace) { audio_buf_info info; - + if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) u->use_getospace = 0; else { @@ -156,15 +156,15 @@ static void do_write(struct userdata *u) { do { memchunk = &u->memchunk; - + if (!memchunk->length) if (pa_sink_render(u->sink, l, memchunk) < 0) memchunk = &u->silence; - + assert(memchunk->memblock); assert(memchunk->memblock->data); assert(memchunk->length); - + if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { pa_log("write() failed: %s", pa_cstrerror(errno)); @@ -172,13 +172,13 @@ static void do_write(struct userdata *u) { pa_module_unload_request(u->module); break; } - + if (memchunk == &u->silence) assert(r % u->sample_size == 0); else { u->memchunk.index += r; u->memchunk.length -= r; - + if (u->memchunk.length <= 0) { pa_memblock_unref(u->memchunk.memblock); u->memchunk.memblock = NULL; @@ -195,7 +195,7 @@ static void do_read(struct userdata *u) { size_t l; int loop = 0; assert(u); - + if (!u->source || !pa_iochannel_is_readable(u->io) || !pa_idxset_size(u->source->outputs)) return; @@ -205,7 +205,7 @@ static void do_read(struct userdata *u) { if (u->use_getispace) { audio_buf_info info; - + if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) u->use_getispace = 0; else { @@ -215,7 +215,7 @@ static void do_read(struct userdata *u) { } } } - + do { memchunk.memblock = pa_memblock_new(u->core->mempool, l); assert(memchunk.memblock); @@ -228,11 +228,11 @@ static void do_read(struct userdata *u) { } break; } - + assert(r <= (ssize_t) memchunk.memblock->length); memchunk.length = memchunk.memblock->length = r; memchunk.index = 0; - + pa_source_post(u->source, &memchunk); pa_memblock_unref(memchunk.memblock); @@ -280,12 +280,12 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { if (!u->use_getispace) return 0; - + if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { u->use_getispace = 0; return 0; } - + if (info.bytes <= 0) return 0; @@ -355,7 +355,7 @@ int pa__init(pa_core *c, pa_module*m) { const char *name; char *name_buf = NULL; int namereg_fail; - + assert(c); assert(m); @@ -363,7 +363,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("failed to parse module arguments."); goto fail; } - + if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { pa_log("record= and playback= expect numeric argument."); goto fail; @@ -381,11 +381,11 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("failed to parse sample specification or channel map"); goto fail; } - + /* Fix latency to 100ms */ nfrags = 12; frag_size = pa_bytes_per_second(&ss)/128; - + if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { pa_log("failed to parse fragments arguments"); goto fail; @@ -398,12 +398,12 @@ int pa__init(pa_core *c, pa_module*m) { pa_log_info("hardware name is '%s'.", hwdesc); else hwdesc[0] = 0; - + pa_log_info("device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); if (nfrags >= 2 && frag_size >= 1) - if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) - goto fail; + if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) + goto fail; if (pa_oss_auto_format(fd, &ss) < 0) goto fail; @@ -418,7 +418,7 @@ int pa__init(pa_core *c, pa_module*m) { u = pa_xmalloc(sizeof(struct userdata)); u->core = c; u->use_getospace = u->use_getispace = 0; - + if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { pa_log_info("input -- %u fragments of size %u.", info.fragstotal, info.fragsize); in_frag_size = info.fragsize; @@ -438,7 +438,7 @@ int pa__init(pa_core *c, pa_module*m) { name = name_buf = pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(p)); namereg_fail = 0; } - + if (!(u->source = pa_source_new(c, __FILE__, name, namereg_fail, &ss, &map))) goto fail; @@ -468,7 +468,7 @@ int pa__init(pa_core *c, pa_module*m) { name = name_buf = pa_sprintf_malloc("oss_output.%s", pa_path_get_filename(p)); namereg_fail = 0; } - + if (!(u->sink = pa_sink_new(c, __FILE__, name, namereg_fail, &ss, &map))) goto fail; @@ -489,7 +489,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_xfree(name_buf); name_buf = NULL; - + assert(u->source || u->sink); u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : -1); @@ -539,13 +539,13 @@ fail: pa_modargs_free(ma); pa_xfree(name_buf); - + return -1; } void pa__done(pa_core *c, pa_module*m) { struct userdata *u; - + assert(c); assert(m); @@ -553,7 +553,7 @@ void pa__done(pa_core *c, pa_module*m) { return; clear_up(u); - + if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); if (u->silence.memblock) diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index 4aee849b..72400313 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -63,7 +63,7 @@ struct userdata { pa_core *core; char *filename; - + pa_sink *sink; pa_iochannel *io; pa_defer_event *defer_event; @@ -87,18 +87,18 @@ static void do_write(struct userdata *u) { assert(u); u->core->mainloop->defer_enable(u->defer_event, 0); - + if (!pa_iochannel_is_writable(u->io)) return; pa_module_set_used(u->module, pa_sink_used_by(u->sink)); - + if (!u->memchunk.length) if (pa_sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0) return; assert(u->memchunk.memblock && u->memchunk.length); - + if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { pa_log("write(): %s", pa_cstrerror(errno)); return; @@ -106,7 +106,7 @@ static void do_write(struct userdata *u) { u->memchunk.index += r; u->memchunk.length -= r; - + if (u->memchunk.length <= 0) { pa_memblock_unref(u->memchunk.memblock); u->memchunk.memblock = NULL; @@ -149,9 +149,9 @@ int pa__init(pa_core *c, pa_module*m) { pa_channel_map map; pa_modargs *ma = NULL; char *t; - + assert(c && m); - + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("failed to parse module arguments"); goto fail; @@ -162,7 +162,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("invalid sample format specification"); goto fail; } - + mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777); if ((fd = open(p, O_RDWR)) < 0) { @@ -171,7 +171,7 @@ int pa__init(pa_core *c, pa_module*m) { } pa_fd_set_cloexec(fd, 1); - + if (fstat(fd, &st) < 0) { pa_log("fstat('%s'): %s", p, pa_cstrerror(errno)); goto fail; @@ -187,7 +187,7 @@ int pa__init(pa_core *c, pa_module*m) { u->core = c; u->module = m; m->userdata = u; - + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { pa_log("failed to create sink."); goto fail; @@ -211,13 +211,13 @@ int pa__init(pa_core *c, pa_module*m) { c->mainloop->defer_enable(u->defer_event, 0); pa_modargs_free(ma); - + return 0; fail: if (ma) pa_modargs_free(ma); - + if (fd >= 0) close(fd); @@ -232,10 +232,10 @@ void pa__done(pa_core *c, pa_module*m) { if (!(u = m->userdata)) return; - + if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); - + pa_sink_disconnect(u->sink); pa_sink_unref(u->sink); pa_iochannel_free(u->io); @@ -244,6 +244,6 @@ void pa__done(pa_core *c, pa_module*m) { assert(u->filename); unlink(u->filename); pa_xfree(u->filename); - + pa_xfree(u); } diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index c251f7ac..f53f6a63 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -63,7 +63,7 @@ struct userdata { pa_core *core; char *filename; - + pa_source *source; pa_iochannel *io; pa_module *module; @@ -127,9 +127,9 @@ int pa__init(pa_core *c, pa_module*m) { pa_channel_map map; pa_modargs *ma = NULL; char *t; - + assert(c && m); - + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("failed to parse module arguments"); goto fail; @@ -140,7 +140,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("invalid sample format specification or channel map"); goto fail; } - + mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777); if ((fd = open(p, O_RDWR)) < 0) { @@ -149,7 +149,7 @@ int pa__init(pa_core *c, pa_module*m) { } pa_fd_set_cloexec(fd, 1); - + if (fstat(fd, &st) < 0) { pa_log("fstat('%s'): %s", p, pa_cstrerror(errno)); goto fail; @@ -164,7 +164,7 @@ int pa__init(pa_core *c, pa_module*m) { u->filename = pa_xstrdup(p); u->core = c; - + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) { pa_log("failed to create source."); goto fail; @@ -180,18 +180,18 @@ int pa__init(pa_core *c, pa_module*m) { u->chunk.memblock = NULL; u->chunk.index = u->chunk.length = 0; - + u->module = m; m->userdata = u; pa_modargs_free(ma); - + return 0; fail: if (ma) pa_modargs_free(ma); - + if (fd >= 0) close(fd); @@ -206,10 +206,10 @@ void pa__done(pa_core *c, pa_module*m) { if (!(u = m->userdata)) return; - + if (u->chunk.memblock) pa_memblock_unref(u->chunk.memblock); - + pa_source_disconnect(u->source); pa_source_unref(u->source); pa_iochannel_free(u->io); @@ -217,6 +217,6 @@ void pa__done(pa_core *c, pa_module*m) { assert(u->filename); unlink(u->filename); pa_xfree(u->filename); - + pa_xfree(u); } diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index df58958a..93fb2a36 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -85,13 +85,13 @@ "record= " SOCKET_USAGE) #elif defined(USE_PROTOCOL_CLI) - #include + #include #define protocol_new pa_protocol_cli_new #define protocol_free pa_protocol_cli_free #define TCPWRAP_SERVICE "pulseaudio-cli" #define IPV4_PORT 4712 #define UNIX_SOCKET "cli" - #define MODULE_ARGUMENTS + #define MODULE_ARGUMENTS #ifdef USE_TCP_SOCKETS #include "module-cli-protocol-tcp-symdef.h" #else @@ -106,7 +106,7 @@ #define TCPWRAP_SERVICE "pulseaudio-http" #define IPV4_PORT 4714 #define UNIX_SOCKET "http" - #define MODULE_ARGUMENTS + #define MODULE_ARGUMENTS #ifdef USE_TCP_SOCKETS #include "module-http-protocol-tcp-symdef.h" #else @@ -129,16 +129,16 @@ #endif #if defined(HAVE_CREDS) && !defined(USE_TCP_SOCKETS) - #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-group", "auth-group-enable", + #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-group", "auth-group-enable", #define AUTH_USAGE "auth-group= auth-group-enable= " #elif defined(USE_TCP_SOCKETS) - #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-ip-acl", + #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-ip-acl", #define AUTH_USAGE "auth-ip-acl= " #else #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON #define AUTH_USAGE #endif - + PA_MODULE_DESCRIPTION("Native protocol "SOCKET_DESCRIPTION) PA_MODULE_USAGE("auth-anonymous= " "cookie= " @@ -160,7 +160,7 @@ #endif #if defined(USE_TCP_SOCKETS) - #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-ip-acl", + #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-ip-acl", #define AUTH_USAGE "auth-ip-acl= " #else #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON @@ -175,7 +175,7 @@ AUTH_USAGE SOCKET_USAGE) #else - #error "Broken build system" + #error "Broken build system" #endif PA_MODULE_AUTHOR("Lennart Poettering") @@ -266,21 +266,21 @@ int pa__init(pa_core *c, pa_module*m) { /* This socket doesn't reside in our own runtime dir but in * /tmp/.esd/, hence we have to create the dir first */ - + if (pa_make_secure_parent_dir(u->socket_path, c->is_system_instance ? 0755 : 0700, (uid_t)-1, (gid_t)-1) < 0) { pa_log("Failed to create socket directory: %s\n", pa_cstrerror(errno)); goto fail; } #endif - + if ((r = pa_unix_socket_remove_stale(tmp)) < 0) { pa_log("Failed to remove stale UNIX socket '%s': %s", tmp, pa_cstrerror(errno)); goto fail; } - + if (r) pa_log("Removed stale UNIX socket '%s'.", tmp); - + if (!(s = pa_socket_server_new_unix(c->mainloop, tmp))) goto fail; @@ -332,7 +332,7 @@ fail: void pa__done(pa_core *c, pa_module*m) { struct userdata *u; - + assert(c); assert(m); @@ -354,8 +354,8 @@ void pa__done(pa_core *c, pa_module*m) { pa_xfree(p); } #endif - - + + pa_xfree(u->socket_path); #endif diff --git a/src/modules/module-rescue-streams.c b/src/modules/module-rescue-streams.c index 7aa205bd..2eea4f61 100644 --- a/src/modules/module-rescue-streams.c +++ b/src/modules/module-rescue-streams.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -49,7 +49,7 @@ struct userdata { static pa_hook_result_t sink_hook_callback(pa_core *c, pa_sink *sink, void* userdata) { pa_sink_input *i; pa_sink *target; - + assert(c); assert(sink); @@ -57,7 +57,7 @@ static pa_hook_result_t sink_hook_callback(pa_core *c, pa_sink *sink, void* user pa_log_debug("No sink inputs to move away."); return PA_HOOK_OK; } - + if (!(target = pa_namereg_get(c, NULL, PA_NAMEREG_SINK, 0))) { pa_log_info("No evacuation sink found."); return PA_HOOK_OK; @@ -74,14 +74,14 @@ static pa_hook_result_t sink_hook_callback(pa_core *c, pa_sink *sink, void* user pa_log_info("Sucessfully moved sink input %u \"%s\" to %s.", i->index, i->name, target->name); } - + return PA_HOOK_OK; } static pa_hook_result_t source_hook_callback(pa_core *c, pa_source *source, void* userdata) { pa_source_output *o; pa_source *target; - + assert(c); assert(source); @@ -89,7 +89,7 @@ static pa_hook_result_t source_hook_callback(pa_core *c, pa_source *source, void pa_log_debug("No source outputs to move away."); return PA_HOOK_OK; } - + if (!(target = pa_namereg_get(c, NULL, PA_NAMEREG_SOURCE, 0))) { pa_log_info("No evacuation source found."); return PA_HOOK_OK; @@ -106,14 +106,14 @@ static pa_hook_result_t source_hook_callback(pa_core *c, pa_source *source, void pa_log_info("Sucessfully moved source output %u \"%s\" to %s.", o->index, o->name, target->name); } - + return PA_HOOK_OK; } int pa__init(pa_core *c, pa_module*m) { pa_modargs *ma = NULL; struct userdata *u; - + assert(c); assert(m); @@ -132,7 +132,7 @@ int pa__init(pa_core *c, pa_module*m) { void pa__done(pa_core *c, pa_module*m) { struct userdata *u; - + assert(c); assert(m); diff --git a/src/modules/module-sine.c b/src/modules/module-sine.c index fa29ba16..871b702d 100644 --- a/src/modules/module-sine.c +++ b/src/modules/module-sine.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -96,7 +96,7 @@ static void calc_sine(float *f, size_t l, float freq) { size_t i; l /= sizeof(float); - + for (i = 0; i < l; i++) f[i] = (float) sin((double) i/l*M_PI*2*freq)/2; } @@ -115,7 +115,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("Failed to parse module arguments"); goto fail; } - + m->userdata = u = pa_xmalloc(sizeof(struct userdata)); u->core = c; u->module = m; @@ -138,7 +138,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("Invalid frequency specification"); goto fail; } - + u->memblock = pa_memblock_new(c->mempool, pa_bytes_per_second(&ss)); calc_sine(u->memblock->data, u->memblock->length, frequency); @@ -160,10 +160,10 @@ int pa__init(pa_core *c, pa_module*m) { u->sink_input->userdata = u; u->peek_index = 0; - + pa_modargs_free(ma); return 0; - + fail: if (ma) pa_modargs_free(ma); @@ -183,7 +183,7 @@ void pa__done(pa_core *c, pa_module*m) { pa_sink_input_disconnect(u->sink_input); pa_sink_input_unref(u->sink_input); } - + if (u->memblock) pa_memblock_unref(u->memblock); pa_xfree(u); diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 66968cb1..1454d639 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -124,7 +124,7 @@ static void do_write(struct userdata *u) { int err; size_t len; ssize_t r; - + assert(u); /* We cannot check pa_iochannel_is_writable() because of our buffer hack */ @@ -163,7 +163,7 @@ static void do_write(struct userdata *u) { } u->sink_underflow = 0; - + assert(u->memchunk.memblock); assert(u->memchunk.memblock->data); assert(u->memchunk.length); @@ -181,10 +181,10 @@ static void do_write(struct userdata *u) { } assert(r % u->frame_size == 0); - + u->memchunk.index += r; u->memchunk.length -= r; - + if (u->memchunk.length <= 0) { pa_memblock_unref(u->memchunk.memblock); u->memchunk.memblock = NULL; @@ -199,7 +199,7 @@ static void do_read(struct userdata *u) { size_t l; ssize_t r; assert(u); - + if (!u->source || !pa_iochannel_is_readable(u->io)) return; @@ -221,11 +221,11 @@ static void do_read(struct userdata *u) { pa_log("read() failed: %s", pa_cstrerror(errno)); return; } - + assert(r <= (ssize_t) memchunk.memblock->length); memchunk.length = memchunk.memblock->length = r; memchunk.index = 0; - + pa_source_post(u->source, &memchunk); pa_memblock_unref(memchunk.memblock); @@ -256,7 +256,7 @@ static void timer_cb(pa_mainloop_api*a, pa_time_event *e, const struct timeval * static void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata) { struct userdata *u = userdata; pa_cvolume old_vol; - + assert(u); if (u->sink) { @@ -518,7 +518,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("failed to parse module arguments."); goto fail; } - + if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { pa_log("record= and playback= expect numeric argument."); goto fail; @@ -531,7 +531,7 @@ int pa__init(pa_core *c, pa_module*m) { mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); - buffer_size = 16384; + buffer_size = 16384; if (pa_modargs_get_value_s32(ma, "buffer_size", &buffer_size) < 0) { pa_log("failed to parse buffer size argument"); goto fail; @@ -542,7 +542,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("failed to parse sample specification"); goto fail; } - + if ((fd = open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), mode | O_NONBLOCK)) < 0) goto fail; @@ -642,7 +642,7 @@ fail: if (ma) pa_modargs_free(ma); - + return -1; } @@ -657,7 +657,7 @@ void pa__done(pa_core *c, pa_module*m) { c->mainloop->time_free(u->timer); ioctl(u->fd, I_SETSIG, 0); pa_signal_free(u->sig); - + if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); @@ -665,12 +665,12 @@ void pa__done(pa_core *c, pa_module*m) { pa_sink_disconnect(u->sink); pa_sink_unref(u->sink); } - + if (u->source) { pa_source_disconnect(u->source); pa_source_unref(u->source); } - + pa_iochannel_free(u->io); pa_xfree(u); } diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index a110c57e..f7420a67 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -116,10 +116,10 @@ static void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { #ifdef TUNNEL_SINK [PA_COMMAND_REQUEST] = command_request, -#endif +#endif [PA_COMMAND_PLAYBACK_STREAM_KILLED] = command_stream_killed, [PA_COMMAND_RECORD_STREAM_KILLED] = command_stream_killed, - [PA_COMMAND_SUBSCRIBE_EVENT] = command_subscribe_event, + [PA_COMMAND_SUBSCRIBE_EVENT] = command_subscribe_event, }; struct userdata { @@ -136,7 +136,7 @@ struct userdata { char *source_name; pa_source *source; #endif - + pa_module *module; pa_core *core; @@ -146,7 +146,7 @@ struct userdata { uint32_t ctag; uint32_t device_index; uint32_t channel; - + pa_usec_t host_latency; pa_time_event *time_event; @@ -156,7 +156,7 @@ struct userdata { static void close_stuff(struct userdata *u) { assert(u); - + if (u->pstream) { pa_pstream_close(u->pstream); pa_pstream_unref(u->pstream); @@ -256,10 +256,10 @@ static void send_bytes(struct userdata *u) { while (u->requested_bytes > 0) { pa_memchunk chunk; if (pa_sink_render(u->sink, u->requested_bytes, &chunk) < 0) { - - if (u->requested_bytes >= DEFAULT_TLENGTH-DEFAULT_PREBUF) + + if (u->requested_bytes >= DEFAULT_TLENGTH-DEFAULT_PREBUF) send_prebuf_request(u); - + return; } @@ -293,7 +293,7 @@ static void command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED ui die(u); return; } - + u->requested_bytes += bytes; send_bytes(u); } @@ -316,7 +316,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G die(u); return; } - + if (pa_tagstruct_get_usec(t, &sink_usec) < 0 || pa_tagstruct_get_usec(t, &source_usec) < 0 || pa_tagstruct_get_boolean(t, &playing) < 0 || @@ -333,14 +333,14 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G pa_gettimeofday(&now); /* FIXME! This could use some serious love. */ - + if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) { /* local and remote seem to have synchronized clocks */ #ifdef TUNNEL_SINK transport_usec = pa_timeval_diff(&remote, &local); #else transport_usec = pa_timeval_diff(&now, &remote); -#endif +#endif } else transport_usec = pa_timeval_diff(&now, &local)/2; @@ -364,7 +364,7 @@ static void request_latency(struct userdata *u) { assert(u); t = pa_tagstruct_new(NULL, 0); -#ifdef TUNNEL_SINK +#ifdef TUNNEL_SINK pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); #else pa_tagstruct_putu32(t, PA_COMMAND_GET_RECORD_LATENCY); @@ -374,7 +374,7 @@ static void request_latency(struct userdata *u) { pa_gettimeofday(&now); pa_tagstruct_put_timeval(t, &now); - + pa_pstream_send_tagstruct(u->pstream, t); pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u, NULL); } @@ -496,7 +496,7 @@ static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED assert(m && e && u); request_latency(u); - + pa_gettimeofday(&ntv); ntv.tv_sec += LATENCY_INTERVAL; m->time_restart(e, &ntv); @@ -518,16 +518,16 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN if (pa_tagstruct_getu32(t, &u->channel) < 0 || pa_tagstruct_getu32(t, &u->device_index) < 0 -#ifdef TUNNEL_SINK +#ifdef TUNNEL_SINK || pa_tagstruct_getu32(t, &u->requested_bytes) < 0 -#endif +#endif ) goto parse_error; if (u->version >= 9) { #ifdef TUNNEL_SINK uint32_t maxlength, tlength, prebuf, minreq; - + if (pa_tagstruct_getu32(t, &maxlength) < 0 || pa_tagstruct_getu32(t, &tlength) < 0 || pa_tagstruct_getu32(t, &prebuf) < 0 || @@ -535,13 +535,13 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN goto parse_error; #else uint32_t maxlength, fragsize; - + if (pa_tagstruct_getu32(t, &maxlength) < 0 || - pa_tagstruct_getu32(t, &fragsize) < 0) + pa_tagstruct_getu32(t, &fragsize) < 0) goto parse_error; #endif } - + if (!pa_tagstruct_eof(t)) goto parse_error; @@ -559,7 +559,7 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN #endif return; - + parse_error: pa_log("invalid reply. (create stream)"); die(u); @@ -603,7 +603,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_get_user_name(un, sizeof(un)), u->source->name); #endif - + reply = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME); pa_tagstruct_putu32(reply, tag = u->ctag++); @@ -612,7 +612,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t /* We ignore the server's reply here */ reply = pa_tagstruct_new(NULL, 0); -#ifdef TUNNEL_SINK +#ifdef TUNNEL_SINK pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_PLAYBACK_STREAM); pa_tagstruct_putu32(reply, tag = u->ctag++); pa_tagstruct_puts(reply, name); @@ -640,7 +640,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_tagstruct_put_boolean(reply, 0); pa_tagstruct_putu32(reply, DEFAULT_FRAGSIZE); #endif - + pa_pstream_send_tagstruct(u->pstream, reply); pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, u, NULL); } @@ -673,7 +673,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, PA_GCC_UN die(u); return; } - + pa_source_post(u->source, chunk); } #endif @@ -686,7 +686,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata pa_socket_client_unref(u->client); u->client = NULL; - + if (!io) { pa_log("connection failed."); pa_module_unload_request(u->module); @@ -701,7 +701,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata #ifndef TUNNEL_SINK pa_pstream_set_recieve_memblock_callback(u->pstream, pstream_memblock_callback, u); #endif - + t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_AUTH); pa_tagstruct_putu32(t, tag = u->ctag++); @@ -709,7 +709,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata pa_tagstruct_put_arbitrary(t, u->auth_cookie, sizeof(u->auth_cookie)); pa_pstream_send_tagstruct(u->pstream, t); pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, u, NULL); - + } #ifdef TUNNEL_SINK @@ -862,14 +862,14 @@ static int load_key(struct userdata *u, const char*fn) { assert(u); u->auth_cookie_in_property = 0; - + if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { pa_log_debug("using already loaded auth cookie."); pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); u->auth_cookie_in_property = 1; return 0; } - + if (!fn) fn = PA_NATIVE_COOKIE_FILE; @@ -877,7 +877,7 @@ static int load_key(struct userdata *u, const char*fn) { return -1; pa_log_debug("loading cookie from disk."); - + if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) u->auth_cookie_in_property = 1; @@ -890,7 +890,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_sample_spec ss; pa_channel_map map; char *t, *dn = NULL; - + assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -919,10 +919,10 @@ int pa__init(pa_core *c, pa_module*m) { u->host_latency = 0; u->auth_cookie_in_property = 0; u->time_event = NULL; - + if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0) goto fail; - + if (!(u->server_name = pa_xstrdup(pa_modargs_get_value(ma, "server", NULL)))) { pa_log("no server specified."); goto fail; @@ -938,7 +938,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("failed to connect to server '%s'", u->server_name); goto fail; } - + if (!u->client) goto fail; @@ -987,7 +987,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_source_set_owner(u->source, m); #endif - + pa_xfree(dn); u->time_event = NULL; @@ -995,7 +995,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_modargs_free(ma); return 0; - + fail: pa__done(c, m); @@ -1003,7 +1003,7 @@ fail: pa_modargs_free(ma); pa_xfree(dn); - + return -1; } @@ -1018,7 +1018,7 @@ void pa__done(pa_core *c, pa_module*m) { if (u->auth_cookie_in_property) pa_authkey_prop_unref(c, PA_NATIVE_COOKIE_PROPERTY_NAME); - + #ifdef TUNNEL_SINK pa_xfree(u->sink_name); #else diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index efa59f40..877d17c7 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -82,7 +82,7 @@ static pa_cvolume* parse_volume(const char *s, pa_cvolume *v) { char *p; long k; unsigned i; - + assert(s); assert(v); @@ -92,7 +92,7 @@ static pa_cvolume* parse_volume(const char *s, pa_cvolume *v) { k = strtol(s, &p, 0); if (k <= 0 || k > PA_CHANNELS_MAX) return NULL; - + v->channels = (unsigned) k; for (i = 0; i < v->channels; i++) { @@ -105,7 +105,7 @@ static pa_cvolume* parse_volume(const char *s, pa_cvolume *v) { if (k < PA_VOLUME_MUTED) return NULL; - + v->values[i] = (pa_volume_t) k; } @@ -132,22 +132,22 @@ static int load_rules(struct userdata *u) { ret = 0; } else pa_log("failed to open file '%s': %s", u->table_file, pa_cstrerror(errno)); - + goto finish; } pa_lock_fd(fileno(f), 1); - + while (!feof(f)) { struct rule *rule; pa_cvolume v; int v_is_set; - + if (!fgets(ln, sizeof(buf_name), f)) break; n++; - + pa_strip_nl(ln); if (ln[0] == '#') @@ -181,12 +181,12 @@ static int load_rules(struct userdata *u) { v_is_set = 0; ln = buf_name; - + if (pa_hashmap_get(u->hashmap, buf_name)) { pa_log("double entry in %s:%u, ignoring", u->table_file, n); continue; } - + rule = pa_xnew(struct rule, 1); rule->name = pa_xstrdup(buf_name); if ((rule->volume_is_set = v_is_set)) @@ -203,7 +203,7 @@ static int load_rules(struct userdata *u) { } ret = 0; - + finish: if (f) { pa_lock_fd(fileno(f), 0); @@ -218,7 +218,7 @@ static int save_rules(struct userdata *u) { int ret = -1; void *state = NULL; struct rule *rule; - + f = u->table_file ? fopen(u->table_file, "w") : pa_open_config_file(NULL, DEFAULT_VOLUME_TABLE_FILE, NULL, &u->table_file, "w"); @@ -232,7 +232,7 @@ static int save_rules(struct userdata *u) { while ((rule = pa_hashmap_iterate(u->hashmap, &state, NULL))) { unsigned i; - + fprintf(f, "%s\n", rule->name); if (rule->volume_is_set) { @@ -241,14 +241,14 @@ static int save_rules(struct userdata *u) { for (i = 0; i < rule->volume.channels; i++) fprintf(f, " %u", rule->volume.values[i]); } - + fprintf(f, "\n%s\n%s\n", rule->sink ? rule->sink : "", rule->source ? rule->source : ""); } - + ret = 0; - + finish: if (f) { pa_lock_fd(fileno(f), 0); @@ -260,7 +260,7 @@ finish: static char* client_name(pa_client *c) { char *t, *e; - + if (!c->name || !c->driver) return NULL; @@ -280,11 +280,11 @@ static char* client_name(pa_client *c) { * sessions of the same application, which is something we * explicitly don't want. Besides other stuff this makes xmms * with esound work properly for us. */ - + if (*k == ')' && *(k+1) == 0) *e = 0; } - + return t; } @@ -294,7 +294,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 pa_source_output *so = NULL; struct rule *r; char *name; - + assert(c); assert(u); @@ -307,7 +307,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT) { if (!(si = pa_idxset_get_by_index(c->sink_inputs, idx))) return; - + if (!si->client || !(name = client_name(si->client))) return; } else { @@ -315,7 +315,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 if (!(so = pa_idxset_get_by_index(c->source_outputs, idx))) return; - + if (!so->client || !(name = client_name(so->client))) return; } @@ -348,7 +348,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 u->modified = 1; } } - + } else { pa_log_info("Creating new entry for <%s>", name); @@ -366,7 +366,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 r->sink = NULL; r->source = pa_xstrdup(so->source->name); } - + pa_hashmap_put(u->hashmap, r->name, r); u->modified = 1; } @@ -419,7 +419,7 @@ static pa_hook_result_t source_output_hook_callback(pa_core *c, pa_source_output int pa__init(pa_core *c, pa_module*m) { pa_modargs *ma = NULL; struct userdata *u; - + assert(c); assert(m); @@ -433,9 +433,9 @@ int pa__init(pa_core *c, pa_module*m) { u->subscription = NULL; u->table_file = pa_xstrdup(pa_modargs_get_value(ma, "table", NULL)); u->modified = 0; - + m->userdata = u; - + if (load_rules(u) < 0) goto fail; @@ -451,7 +451,7 @@ fail: if (ma) pa_modargs_free(ma); - + return -1; } @@ -467,7 +467,7 @@ static void free_func(void *p, void *userdata) { void pa__done(pa_core *c, pa_module*m) { struct userdata* u; - + assert(c); assert(m); @@ -486,7 +486,7 @@ void pa__done(pa_core *c, pa_module*m) { if (u->modified) save_rules(u); - + pa_hashmap_free(u->hashmap, free_func, NULL); } diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index 4043c136..e245e138 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -172,7 +172,7 @@ static void do_write(struct userdata *u) pa_log_error(__FILE__ ": ERROR: Unable to write waveOut block: %d", res); } - + u->written_bytes += hdr->dwBufferLength; EnterCriticalSection(&u->crit); @@ -233,7 +233,7 @@ static void do_read(struct userdata *u) pa_log_error(__FILE__ ": ERROR: Unable to add waveIn block: %d", res); } - + free_frags--; u->cur_ihdr++; u->cur_ihdr %= u->fragments; @@ -561,7 +561,7 @@ int pa__init(pa_core *c, pa_module*m) { u->ohdrs[i].lpData = pa_xmalloc(u->fragment_size); assert(u->ohdrs); } - + u->module = m; m->userdata = u; @@ -585,7 +585,7 @@ fail: if (ma) pa_modargs_free(ma); - + return -1; } @@ -597,7 +597,7 @@ void pa__done(pa_core *c, pa_module*m) { if (!(u = m->userdata)) return; - + if (u->event) c->mainloop->time_free(u->event); @@ -608,12 +608,12 @@ void pa__done(pa_core *c, pa_module*m) { pa_sink_disconnect(u->sink); pa_sink_unref(u->sink); } - + if (u->source) { pa_source_disconnect(u->source); pa_source_unref(u->source); } - + if (u->hwi != INVALID_HANDLE_VALUE) { waveInReset(u->hwi); waveInClose(u->hwi); @@ -633,6 +633,6 @@ void pa__done(pa_core *c, pa_module*m) { pa_xfree(u->ohdrs); DeleteCriticalSection(&u->crit); - + pa_xfree(u); } diff --git a/src/modules/module-x11-bell.c b/src/modules/module-x11-bell.c index 48e95c8c..5322a71f 100644 --- a/src/modules/module-x11-bell.c +++ b/src/modules/module-x11-bell.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -107,19 +107,19 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("failed to parse module arguments"); goto fail; } - + m->userdata = u = pa_xmalloc(sizeof(struct userdata)); u->core = c; u->scache_item = pa_xstrdup(pa_modargs_get_value(ma, "sample", "x11-bell")); u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); u->x11_client = NULL; - if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL)))) + if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL)))) goto fail; major = XkbMajorVersion; minor = XkbMinorVersion; - + if (!XkbLibraryVersion(&major, &minor)) { pa_log("XkbLibraryVersion() failed"); goto fail; @@ -140,11 +140,11 @@ int pa__init(pa_core *c, pa_module*m) { XkbChangeEnabledControls(pa_x11_wrapper_get_display(u->x11_wrapper), XkbUseCoreKbd, XkbAudibleBellMask, 0); u->x11_client = pa_x11_client_new(u->x11_wrapper, x11_event_callback, u); - + pa_modargs_free(ma); - + return 0; - + fail: if (ma) pa_modargs_free(ma); diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c index f2cace14..b1c17a7c 100644 --- a/src/modules/module-x11-publish.c +++ b/src/modules/module-x11-publish.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -77,14 +77,14 @@ static int load_key(struct userdata *u, const char*fn) { assert(u); u->auth_cookie_in_property = 0; - + if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { pa_log_debug("using already loaded auth cookie."); pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); u->auth_cookie_in_property = 1; return 0; } - + if (!fn) fn = PA_NATIVE_COOKIE_FILE; @@ -92,7 +92,7 @@ static int load_key(struct userdata *u, const char*fn) { return -1; pa_log_debug("loading cookie from disk."); - + if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) u->auth_cookie_in_property = 1; @@ -121,7 +121,7 @@ int pa__init(pa_core *c, pa_module*m) { if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0) goto fail; - if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL)))) + if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL)))) goto fail; if (!(l = pa_property_get(c, PA_NATIVE_SERVER_PROPERTY_NAME))) @@ -130,10 +130,10 @@ int pa__init(pa_core *c, pa_module*m) { s = pa_strlist_tostring(l); pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SERVER", s); pa_xfree(s); - + if (!pa_get_fqdn(hn, sizeof(hn)) || !pa_get_user_name(un, sizeof(un))) goto fail; - + u->id = pa_sprintf_malloc("%s@%s/%u", un, hn, (unsigned) getpid()); pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_ID", u->id); @@ -144,10 +144,10 @@ int pa__init(pa_core *c, pa_module*m) { pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SINK", t); pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_COOKIE", pa_hexstr(u->auth_cookie, sizeof(u->auth_cookie), hx, sizeof(hx))); - + pa_modargs_free(ma); return 0; - + fail: if (ma) pa_modargs_free(ma); @@ -162,7 +162,7 @@ void pa__done(pa_core *c, pa_module*m) { if (!(u = m->userdata)) return; - + if (u->x11_wrapper) { char t[256]; @@ -178,7 +178,7 @@ void pa__done(pa_core *c, pa_module*m) { XSync(pa_x11_wrapper_get_display(u->x11_wrapper), False); } } - + if (u->x11_wrapper) pa_x11_wrapper_unref(u->x11_wrapper); diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index 696d8afe..10643808 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -153,7 +153,7 @@ static int publish_service(struct userdata *u, struct service *s) { if (!u->client || avahi_client_get_state(u->client) != AVAHI_CLIENT_S_RUNNING) return 0; - + if ((s->published == PUBLISHED_REAL && s->loaded.valid) || (s->published == PUBLISHED_AUTOLOAD && s->autoload.valid && !s->loaded.valid)) return 0; @@ -161,8 +161,8 @@ static int publish_service(struct userdata *u, struct service *s) { if (s->published != UNPUBLISHED) { avahi_entry_group_reset(s->entry_group); s->published = UNPUBLISHED; - } - + } + if (s->loaded.valid || s->autoload.valid) { pa_namereg_type_t type; @@ -172,26 +172,26 @@ static int publish_service(struct userdata *u, struct service *s) { goto finish; } } - + txt = avahi_string_list_add_pair(txt, "device", s->name); txt = txt_record_server_data(u->core, txt); - + if (s->loaded.valid) { char *description; pa_sample_spec ss; - + get_service_data(u, s, &ss, &description); - + txt = avahi_string_list_add_printf(txt, "rate=%u", ss.rate); txt = avahi_string_list_add_printf(txt, "channels=%u", ss.channels); txt = avahi_string_list_add_pair(txt, "format", pa_sample_format_to_string(ss.format)); if (description) txt = avahi_string_list_add_pair(txt, "description", description); - + type = s->loaded.type; } else if (s->autoload.valid) type = s->autoload.type; - + if (avahi_entry_group_add_service_strlst( s->entry_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, @@ -202,24 +202,24 @@ static int publish_service(struct userdata *u, struct service *s) { NULL, u->port, txt) < 0) { - + pa_log("avahi_entry_group_add_service_strlst(): %s", avahi_strerror(avahi_client_errno(u->client))); goto finish; } - + if (avahi_entry_group_commit(s->entry_group) < 0) { pa_log("avahi_entry_group_commit(): %s", avahi_strerror(avahi_client_errno(u->client))); goto finish; } - + if (s->loaded.valid) s->published = PUBLISHED_REAL; else if (s->autoload.valid) s->published = PUBLISHED_AUTOLOAD; } - + r = 0; - + finish: if (s->published == UNPUBLISHED) { @@ -227,7 +227,7 @@ finish: if (s->entry_group) avahi_entry_group_free(s->entry_group); - + pa_hashmap_remove(u->services, s->name); pa_xfree(s->name); pa_xfree(s->service_name); @@ -236,17 +236,17 @@ finish: if (txt) avahi_string_list_free(txt); - + return r; } static struct service *get_service(struct userdata *u, const char *name, const char *description) { struct service *s; char hn[64]; - + if ((s = pa_hashmap_get(u->services, name))) return s; - + s = pa_xnew(struct service, 1); s->userdata = u; s->entry_group = NULL; @@ -283,7 +283,7 @@ static int publish_sink(struct userdata *u, pa_sink *s) { static int publish_source(struct userdata *u, pa_source *s) { struct service *svc; int ret; - + assert(u && s); svc = get_service(u, s->name, s->description); @@ -295,7 +295,7 @@ static int publish_source(struct userdata *u, pa_source *s) { svc->loaded.index = s->index; pa_dynarray_put(u->source_dynarray, s->index, svc); - + if ((ret = publish_service(u, svc)) < 0) return ret; @@ -306,7 +306,7 @@ static int publish_source(struct userdata *u, pa_source *s) { static int publish_autoload(struct userdata *u, pa_autoload_entry *s) { struct service *svc; int ret; - + assert(u && s); svc = get_service(u, s->name, NULL); @@ -319,7 +319,7 @@ static int publish_autoload(struct userdata *u, pa_autoload_entry *s) { if ((ret = publish_service(u, svc)) < 0) return ret; - + pa_dynarray_put(u->autoload_dynarray, s->index, svc); return ret; } @@ -336,14 +336,14 @@ static int remove_sink(struct userdata *u, uint32_t idx) { svc->loaded.valid = 0; pa_dynarray_put(u->sink_dynarray, idx, NULL); - + return publish_service(u, svc); } static int remove_source(struct userdata *u, uint32_t idx) { struct service *svc; assert(u && idx != PA_INVALID_INDEX); - + if (!(svc = pa_dynarray_get(u->source_dynarray, idx))) return 0; @@ -359,7 +359,7 @@ static int remove_source(struct userdata *u, uint32_t idx) { static int remove_autoload(struct userdata *u, uint32_t idx) { struct service *svc; assert(u && idx != PA_INVALID_INDEX); - + if (!(svc = pa_dynarray_get(u->autoload_dynarray, idx))) return 0; @@ -389,14 +389,14 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 if (remove_sink(u, idx) < 0) goto fail; } - + break; case PA_SUBSCRIPTION_EVENT_SOURCE: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { pa_source *source; - + if ((source = pa_idxset_get_by_index(c->sources, idx))) { if (publish_source(u, source) < 0) goto fail; @@ -405,13 +405,13 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 if (remove_source(u, idx) < 0) goto fail; } - + break; case PA_SUBSCRIPTION_EVENT_AUTOLOAD: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { pa_autoload_entry *autoload; - + if ((autoload = pa_idxset_get_by_index(c->autoload_idxset, idx))) { if (publish_autoload(u, autoload) < 0) goto fail; @@ -420,7 +420,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 if (remove_autoload(u, idx) < 0) goto fail; } - + break; } @@ -453,7 +453,7 @@ static void main_entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState s static int publish_main_service(struct userdata *u) { AvahiStringList *txt = NULL; int r = -1; - + if (!u->main_entry_group) { if (!(u->main_entry_group = avahi_entry_group_new(u->client, main_entry_group_callback, u))) { pa_log("avahi_entry_group_new() failed: %s", avahi_strerror(avahi_client_errno(u->client))); @@ -461,7 +461,7 @@ static int publish_main_service(struct userdata *u) { } } else avahi_entry_group_reset(u->main_entry_group); - + txt = txt_record_server_data(u->core, NULL); if (avahi_entry_group_add_service_strlst( @@ -474,18 +474,18 @@ static int publish_main_service(struct userdata *u) { NULL, u->port, txt) < 0) { - + pa_log("avahi_entry_group_add_service_strlst() failed: %s", avahi_strerror(avahi_client_errno(u->client))); goto fail; } - + if (avahi_entry_group_commit(u->main_entry_group) < 0) { pa_log("avahi_entry_group_commit() failed: %s", avahi_strerror(avahi_client_errno(u->client))); goto fail; } r = 0; - + fail: avahi_string_list_free(txt); @@ -498,7 +498,7 @@ static int publish_all_services(struct userdata *u) { pa_autoload_entry *autoload; int r = -1; uint32_t idx; - + assert(u); pa_log_debug("Publishing services in Zeroconf"); @@ -518,9 +518,9 @@ static int publish_all_services(struct userdata *u) { if (publish_main_service(u) < 0) goto fail; - + r = 0; - + fail: return r; } @@ -528,7 +528,7 @@ fail: static void unpublish_all_services(struct userdata *u, int rem) { void *state = NULL; struct service *s; - + assert(u); pa_log_debug("Unpublishing services in Zeroconf"); @@ -538,7 +538,7 @@ static void unpublish_all_services(struct userdata *u, int rem) { if (rem) { avahi_entry_group_free(s->entry_group); s->entry_group = NULL; - } else + } else avahi_entry_group_reset(s->entry_group); } @@ -559,12 +559,12 @@ static void client_callback(AvahiClient *c, AvahiClientState state, void *userda assert(c); u->client = c; - + switch (state) { case AVAHI_CLIENT_S_RUNNING: publish_all_services(u); break; - + case AVAHI_CLIENT_S_COLLISION: unpublish_all_services(u, 0); break; @@ -578,7 +578,7 @@ static void client_callback(AvahiClient *c, AvahiClientState state, void *userda if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error))) pa_log("pa_avahi_client_new() failed: %s", avahi_strerror(error)); } - + break; default: ; @@ -607,7 +607,7 @@ int pa__init(pa_core *c, pa_module*m) { u->port = (uint16_t) port; u->avahi_poll = pa_avahi_poll_new(c->mainloop); - + u->services = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); u->sink_dynarray = pa_dynarray_new(); u->source_dynarray = pa_dynarray_new(); @@ -628,15 +628,15 @@ int pa__init(pa_core *c, pa_module*m) { } pa_modargs_free(ma); - + return 0; - + fail: pa__done(c, m); if (ma) pa_modargs_free(ma); - + return -1; } @@ -649,7 +649,7 @@ static void service_free(void *p, void *userdata) { if (s->entry_group) avahi_entry_group_free(s->entry_group); - + pa_xfree(s->service_name); pa_xfree(s->name); pa_xfree(s); @@ -674,14 +674,14 @@ void pa__done(pa_core *c, pa_module*m) { pa_dynarray_free(u->source_dynarray, NULL, NULL); if (u->autoload_dynarray) pa_dynarray_free(u->autoload_dynarray, NULL, NULL); - + if (u->main_entry_group) avahi_entry_group_free(u->main_entry_group); - + if (u->client) avahi_client_free(u->client); - + if (u->avahi_poll) pa_avahi_poll_free(u->avahi_poll); diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index 0aaf6971..d26a0e81 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -48,14 +48,14 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { if(!pcaps) pcaps = ∩︀ - + if (*mode == O_RDWR) { if ((fd = open(device, O_RDWR|O_NDELAY)) >= 0) { int dcaps, *tcaps; ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0); tcaps = pcaps ? pcaps : &dcaps; - + if (ioctl(fd, SNDCTL_DSP_GETCAPS, tcaps) < 0) { pa_log("SNDCTL_DSP_GETCAPS: %s", pa_cstrerror(errno)); goto fail; @@ -68,7 +68,7 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { close(fd); } - + if ((fd = open(device, (*mode = O_WRONLY)|O_NDELAY)) < 0) { if ((fd = open(device, (*mode = O_RDONLY)|O_NDELAY)) < 0) { pa_log("open('%s'): %s", device, pa_cstrerror(errno)); @@ -80,17 +80,17 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { pa_log("open('%s'): %s", device, pa_cstrerror(errno)); goto fail; } - } + } success: *pcaps = 0; - + if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { pa_log("SNDCTL_DSP_GETCAPS: %s", pa_cstrerror(errno)); goto fail; } - + pa_log_debug("capabilities:%s%s%s%s%s%s%s%s%s%s%s%s%s%s", *pcaps & DSP_CAP_BATCH ? " BATCH" : "", #ifdef DSP_CAP_BIND @@ -100,7 +100,7 @@ success: #endif *pcaps & DSP_CAP_COPROC ? " COPROC" : "", *pcaps & DSP_CAP_DUPLEX ? " DUPLEX" : "", -#ifdef DSP_CAP_FREERATE +#ifdef DSP_CAP_FREERATE *pcaps & DSP_CAP_FREERATE ? " FREERATE" : "", #else "", @@ -140,7 +140,7 @@ success: *pcaps & DSP_CAP_TRIGGER ? " TRIGGER" : ""); pa_fd_set_cloexec(fd, 1); - + return fd; fail: @@ -152,7 +152,7 @@ fail: int pa_oss_auto_format(int fd, pa_sample_spec *ss) { int format, channels, speed, reqformat; pa_sample_format_t orig_format; - + static const int format_trans[PA_SAMPLE_MAX] = { [PA_SAMPLE_U8] = AFMT_U8, [PA_SAMPLE_ALAW] = AFMT_A_LAW, @@ -166,7 +166,7 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss) { assert(fd >= 0 && ss); orig_format = ss->format; - + reqformat = format = format_trans[ss->format]; if (reqformat == AFMT_QUERY || ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0 || format != reqformat) { format = AFMT_S16_NE; @@ -190,7 +190,7 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss) { pa_log_warn("device doesn't support sample format %s, changed to %s.", pa_sample_format_to_string(orig_format), pa_sample_format_to_string(ss->format)); - + channels = ss->channels; if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) < 0) { pa_log("SNDCTL_DSP_CHANNELS: %s", pa_cstrerror(errno)); @@ -229,14 +229,14 @@ static int simple_log2(int v) { if (!v) break; k++; } - + return k; } int pa_oss_set_fragments(int fd, int nfrags, int frag_size) { int arg; arg = ((int) nfrags << 16) | simple_log2(frag_size); - + if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &arg) < 0) { pa_log("SNDCTL_DSP_SETFRAGMENT: %s", pa_cstrerror(errno)); return -1; @@ -252,7 +252,7 @@ static int pa_oss_get_volume(int fd, int mixer, const pa_sample_spec *ss, pa_cvo assert(fd >= 0); assert(ss); assert(volume); - + if (ioctl(fd, mixer, &vol) < 0) return -1; @@ -278,7 +278,7 @@ static int pa_oss_set_volume(int fd, int mixer, const pa_sample_spec *ss, const r = volume->values[1] > PA_VOLUME_NORM ? PA_VOLUME_NORM : volume->values[1]; vol |= ((r*100)/PA_VOLUME_NORM) << 8; } - + if (ioctl(fd, mixer, &vol) < 0) return -1; @@ -321,7 +321,7 @@ int pa_oss_get_hw_description(const char *dev, char *name, size_t l) { n = *e - '0'; else return -1; - + if (!(f = fopen("/dev/sndstat", "r")) && !(f = fopen("/proc/sndstat", "r")) && !(f = fopen("/proc/asound/oss/sndstat", "r"))) { @@ -335,7 +335,7 @@ int pa_oss_get_hw_description(const char *dev, char *name, size_t l) { while (!feof(f)) { char line[64]; int device; - + if (!fgets(line, sizeof(line), f)) break; @@ -348,7 +348,7 @@ int pa_oss_get_hw_description(const char *dev, char *name, size_t l) { if (line[0] == 0) break; - + if (sscanf(line, "%i: ", &device) != 1) continue; @@ -360,7 +360,7 @@ int pa_oss_get_hw_description(const char *dev, char *name, size_t l) { if (pa_endswith(k, " (DUPLEX)")) k[strlen(k)-9] = 0; - + pa_strlcpy(name, k, l); r = 0; break; diff --git a/src/modules/oss-util.h b/src/modules/oss-util.h index 12855f4e..6a8bf3d2 100644 --- a/src/modules/oss-util.h +++ b/src/modules/oss-util.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulse/browser.c b/src/pulse/browser.c index dae8e3d5..4b0de029 100644 --- a/src/pulse/browser.c +++ b/src/pulse/browser.c @@ -2,26 +2,26 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include #include @@ -53,10 +53,10 @@ struct pa_browser { pa_browser_error_cb_t error_callback; void *error_userdata; - + AvahiClient *client; AvahiServiceBrowser *server_browser, *sink_browser, *source_browser; - + }; static int map_to_opcode(const char *type, int new) { @@ -84,7 +84,7 @@ static void resolve_callback( AvahiStringList *txt, AvahiLookupResultFlags flags, void *userdata) { - + pa_browser *b = userdata; pa_browse_info i; char ip[256], a[256]; @@ -94,7 +94,7 @@ static void resolve_callback( pa_sample_spec ss; int ss_valid = 0; char *key = NULL, *value = NULL; - + assert(b); memset(&i, 0, sizeof(i)); @@ -102,7 +102,7 @@ static void resolve_callback( if (event != AVAHI_RESOLVER_FOUND) goto fail; - + if (!b->callback) goto fail; @@ -119,10 +119,10 @@ static void resolve_callback( while (txt) { - + if (avahi_string_list_get_pair(txt, &key, &value, NULL) < 0) break; - + if (!strcmp(key, "device")) { device_found = 1; pa_xfree((char*) i.device); @@ -138,11 +138,11 @@ static void resolve_callback( value = NULL; } else if (!strcmp(key, "fqdn")) { size_t l; - + pa_xfree((char*) i.fqdn); i.fqdn = value; value = NULL; - + l = strlen(a); assert(l+1 <= sizeof(a)); strncat(a, " ", sizeof(a)-l-1); @@ -151,7 +151,7 @@ static void resolve_callback( if (pa_atou(value, &cookie) < 0) goto fail; - + i.cookie = &cookie; } else if (!strcmp(key, "description")) { pa_xfree((char*) i.description); @@ -159,13 +159,13 @@ static void resolve_callback( value = NULL; } else if (!strcmp(key, "channels")) { uint32_t ch; - + if (pa_atou(value, &ch) < 0 || ch <= 0 || ch > 255) goto fail; - + ss.channels = (uint8_t) ch; ss_valid |= 1; - + } else if (!strcmp(key, "rate")) { if (pa_atou(value, &ss.rate) < 0) goto fail; @@ -174,7 +174,7 @@ static void resolve_callback( if ((ss.format = pa_parse_sample_format(value)) == PA_SAMPLE_INVALID) goto fail; - + ss_valid |= 4; } @@ -186,7 +186,7 @@ static void resolve_callback( } /* No device txt record was sent for a sink or source service */ - if (opcode != PA_BROWSE_NEW_SERVER && !device_found) + if (opcode != PA_BROWSE_NEW_SERVER && !device_found) goto fail; if (ss_valid == 7) @@ -203,7 +203,7 @@ fail: pa_xfree(key); pa_xfree(value); - + avahi_service_resolver_free(r); } @@ -263,19 +263,19 @@ static void browse_callback( break; } - + case AVAHI_BROWSER_REMOVE: { if (b->callback) { pa_browse_info i; int opcode; - + memset(&i, 0, sizeof(i)); i.name = name; opcode = map_to_opcode(type, 0); assert(opcode >= 0); - + b->callback(b, opcode, &i, b->userdata); } break; @@ -285,7 +285,7 @@ static void browse_callback( handle_failure(b); break; } - + default: ; } @@ -313,7 +313,7 @@ pa_browser *pa_browser_new_full(pa_mainloop_api *mainloop, pa_browse_flags_t fla if (flags & ~(PA_BROWSE_FOR_SERVERS|PA_BROWSE_FOR_SINKS|PA_BROWSE_FOR_SOURCES) || flags == 0) return NULL; - + b = pa_xnew(pa_browser, 1); b->mainloop = mainloop; b->ref = 1; @@ -346,7 +346,7 @@ pa_browser *pa_browser_new_full(pa_mainloop_api *mainloop, pa_browse_flags_t fla *error_string = avahi_strerror(avahi_client_errno(b->client)); goto fail; } - + if ((flags & PA_BROWSE_FOR_SINKS) && !(b->sink_browser = avahi_service_browser_new( b->client, @@ -378,13 +378,13 @@ pa_browser *pa_browser_new_full(pa_mainloop_api *mainloop, pa_browse_flags_t fla *error_string = avahi_strerror(avahi_client_errno(b->client)); goto fail; } - + return b; fail: if (b) browser_free(b); - + return NULL; } @@ -403,7 +403,7 @@ static void browser_free(pa_browser *b) { if (b->avahi_poll) pa_avahi_poll_free(b->avahi_poll); - + pa_xfree(b); } diff --git a/src/pulse/browser.h b/src/pulse/browser.h index fc57a4d5..7b9aae8d 100644 --- a/src/pulse/browser.h +++ b/src/pulse/browser.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -41,7 +41,7 @@ typedef enum pa_browse_opcode { PA_BROWSE_NEW_SINK, /**< New sink found */ PA_BROWSE_NEW_SOURCE, /**< New source found */ PA_BROWSE_REMOVE_SERVER, /**< Server disappeared */ - PA_BROWSE_REMOVE_SINK, /**< Sink disappeared */ + PA_BROWSE_REMOVE_SINK, /**< Sink disappeared */ PA_BROWSE_REMOVE_SOURCE /**< Source disappeared */ } pa_browse_opcode_t; diff --git a/src/pulse/cdecl.h b/src/pulse/cdecl.h index a3ec231c..09b9b84a 100644 --- a/src/pulse/cdecl.h +++ b/src/pulse/cdecl.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulse/channelmap.c b/src/pulse/channelmap.c index 69b09089..40655cf5 100644 --- a/src/pulse/channelmap.c +++ b/src/pulse/channelmap.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -35,23 +35,23 @@ const char *const table[] = { [PA_CHANNEL_POSITION_MONO] = "mono", - + [PA_CHANNEL_POSITION_FRONT_CENTER] = "front-center", [PA_CHANNEL_POSITION_FRONT_LEFT] = "front-left", [PA_CHANNEL_POSITION_FRONT_RIGHT] = "front-right", - + [PA_CHANNEL_POSITION_REAR_CENTER] = "rear-center", [PA_CHANNEL_POSITION_REAR_LEFT] = "rear-left", [PA_CHANNEL_POSITION_REAR_RIGHT] = "rear-right", - + [PA_CHANNEL_POSITION_LFE] = "lfe", - + [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = "front-left-of-center", [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = "front-right-of-center", - + [PA_CHANNEL_POSITION_SIDE_LEFT] = "side-left", [PA_CHANNEL_POSITION_SIDE_RIGHT] = "side-right", - + [PA_CHANNEL_POSITION_AUX0] = "aux0", [PA_CHANNEL_POSITION_AUX1] = "aux1", [PA_CHANNEL_POSITION_AUX2] = "aux2", @@ -86,7 +86,7 @@ const char *const table[] = { [PA_CHANNEL_POSITION_AUX31] = "aux31", [PA_CHANNEL_POSITION_TOP_CENTER] = "top-center", - + [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = "top-front-left", [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = "top-front-right", [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = "top-front-center", @@ -140,14 +140,14 @@ pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, p switch (def) { case PA_CHANNEL_MAP_AIFF: - + /* This is somewhat compatible with RFC3551 */ - + switch (channels) { case 1: m->map[0] = PA_CHANNEL_POSITION_MONO; return m; - + case 6: m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m->map[1] = PA_CHANNEL_POSITION_SIDE_LEFT; @@ -156,31 +156,31 @@ pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, p m->map[4] = PA_CHANNEL_POSITION_SIDE_RIGHT; m->map[5] = PA_CHANNEL_POSITION_LFE; return m; - + case 5: m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; m->map[3] = PA_CHANNEL_POSITION_REAR_LEFT; m->map[4] = PA_CHANNEL_POSITION_REAR_RIGHT; /* Fall through */ - + case 2: m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; return m; - + case 3: m->map[0] = PA_CHANNEL_POSITION_LEFT; m->map[1] = PA_CHANNEL_POSITION_RIGHT; m->map[2] = PA_CHANNEL_POSITION_CENTER; return m; - + case 4: m->map[0] = PA_CHANNEL_POSITION_LEFT; m->map[1] = PA_CHANNEL_POSITION_CENTER; m->map[2] = PA_CHANNEL_POSITION_RIGHT; m->map[3] = PA_CHANNEL_POSITION_LFE; return m; - + default: return NULL; } @@ -191,43 +191,43 @@ pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, p case 1: m->map[0] = PA_CHANNEL_POSITION_MONO; return m; - + case 8: m->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; m->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; /* Fall through */ - + case 6: m->map[5] = PA_CHANNEL_POSITION_LFE; /* Fall through */ - + case 5: m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; /* Fall through */ - + case 4: m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT; m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; /* Fall through */ - + case 2: m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; return m; - + default: return NULL; } case PA_CHANNEL_MAP_AUX: { unsigned i; - + if (channels >= PA_CHANNELS_MAX) return NULL; for (i = 0; i < channels; i++) m->map[i] = PA_CHANNEL_POSITION_AUX0 + i; - + return m; } @@ -237,55 +237,55 @@ pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, p case 1: m->map[0] = PA_CHANNEL_POSITION_MONO; return m; - + case 18: m->map[15] = PA_CHANNEL_POSITION_TOP_REAR_LEFT; m->map[16] = PA_CHANNEL_POSITION_TOP_REAR_CENTER; m->map[17] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT; /* Fall through */ - + case 15: m->map[12] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT; m->map[13] = PA_CHANNEL_POSITION_TOP_FRONT_CENTER; m->map[14] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT; /* Fall through */ - + case 12: m->map[11] = PA_CHANNEL_POSITION_TOP_CENTER; /* Fall through */ - + case 11: m->map[9] = PA_CHANNEL_POSITION_SIDE_LEFT; m->map[10] = PA_CHANNEL_POSITION_SIDE_RIGHT; /* Fall through */ - + case 9: m->map[8] = PA_CHANNEL_POSITION_REAR_CENTER; /* Fall through */ - + case 8: m->map[6] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER; m->map[7] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER; /* Fall through */ - + case 6: m->map[4] = PA_CHANNEL_POSITION_REAR_LEFT; m->map[5] = PA_CHANNEL_POSITION_REAR_RIGHT; /* Fall through */ - + case 4: m->map[3] = PA_CHANNEL_POSITION_LFE; /* Fall through */ - + case 3: m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; /* Fall through */ - + case 2: m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; return m; - + default: return NULL; } @@ -296,12 +296,12 @@ pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, p case 1: m->map[0] = PA_CHANNEL_POSITION_MONO; return m; - + case 8: m->map[6] = PA_CHANNEL_POSITION_REAR_LEFT; m->map[7] = PA_CHANNEL_POSITION_REAR_RIGHT; /* Fall through */ - + case 6: m->map[4] = PA_CHANNEL_POSITION_SIDE_LEFT; m->map[5] = PA_CHANNEL_POSITION_SIDE_RIGHT; @@ -310,20 +310,20 @@ pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, p case 4: m->map[3] = PA_CHANNEL_POSITION_LFE; /* Fall through */ - + case 3: m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; /* Fall through */ - + case 2: m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; return m; - + default: return NULL; } - + default: return NULL; @@ -341,13 +341,13 @@ const char* pa_channel_position_to_string(pa_channel_position_t pos) { int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) { unsigned c; - + assert(a); assert(b); if (a->channels != b->channels) return 0; - + for (c = 0; c < a->channels; c++) if (a->map[c] != b->map[c]) return 0; @@ -359,7 +359,7 @@ char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) { unsigned channel; int first = 1; char *e; - + assert(s); assert(l > 0); assert(map); @@ -382,7 +382,7 @@ pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) { const char *state; pa_channel_map map; char *p; - + assert(rmap); assert(s); @@ -397,14 +397,14 @@ pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) { state = NULL; map.channels = 0; - + while ((p = pa_split(s, ",", &state))) { if (map.channels >= PA_CHANNELS_MAX) { pa_xfree(p); return NULL; } - + /* Some special aliases */ if (strcmp(p, "left") == 0) map.map[map.channels++] = PA_CHANNEL_POSITION_LEFT; @@ -416,13 +416,13 @@ pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) { map.map[map.channels++] = PA_CHANNEL_POSITION_SUBWOOFER; else { pa_channel_position_t i; - + for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++) if (strcmp(p, table[i]) == 0) { map.map[map.channels++] = i; break; } - + if (i >= PA_CHANNEL_POSITION_MAX) { pa_xfree(p); return NULL; @@ -433,24 +433,24 @@ pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) { } finish: - + if (!pa_channel_map_valid(&map)) return NULL; - + *rmap = map; return rmap; } int pa_channel_map_valid(const pa_channel_map *map) { unsigned c; - + assert(map); if (map->channels <= 0 || map->channels > PA_CHANNELS_MAX) return 0; for (c = 0; c < map->channels; c++) { - + if (map->map[c] < 0 ||map->map[c] >= PA_CHANNEL_POSITION_MAX) return 0; diff --git a/src/pulse/channelmap.h b/src/pulse/channelmap.h index 8a39ade8..20380251 100644 --- a/src/pulse/channelmap.h +++ b/src/pulse/channelmap.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -72,7 +72,7 @@ typedef enum pa_channel_position { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_CENTER, - + PA_CHANNEL_POSITION_FRONT_LEFT = PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT = PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_FRONT_CENTER = PA_CHANNEL_POSITION_CENTER, @@ -80,13 +80,13 @@ typedef enum pa_channel_position { PA_CHANNEL_POSITION_REAR_CENTER, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, - + PA_CHANNEL_POSITION_LFE, PA_CHANNEL_POSITION_SUBWOOFER = PA_CHANNEL_POSITION_LFE, - + PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, - + PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, @@ -124,7 +124,7 @@ typedef enum pa_channel_position { PA_CHANNEL_POSITION_AUX31, PA_CHANNEL_POSITION_TOP_CENTER, - + PA_CHANNEL_POSITION_TOP_FRONT_LEFT, PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, PA_CHANNEL_POSITION_TOP_FRONT_CENTER, @@ -132,7 +132,7 @@ typedef enum pa_channel_position { PA_CHANNEL_POSITION_TOP_REAR_LEFT, PA_CHANNEL_POSITION_TOP_REAR_RIGHT, PA_CHANNEL_POSITION_TOP_REAR_CENTER, - + PA_CHANNEL_POSITION_MAX } pa_channel_position_t; @@ -143,7 +143,7 @@ typedef enum pa_channel_map_def { PA_CHANNEL_MAP_AUX, /**< Only aux channels */ PA_CHANNEL_MAP_WAVEEX, /**< Microsoft's WAVEFORMATEXTENSIBLE mapping */ PA_CHANNEL_MAP_OSS, /**< The default channel mapping used by OSS as defined in the OSS 4.0 API specs */ - + PA_CHANNEL_MAP_DEFAULT = PA_CHANNEL_MAP_AIFF /**< The default channel map */ } pa_channel_map_def_t; diff --git a/src/pulse/client-conf-x11.c b/src/pulse/client-conf-x11.c index 8cedc48b..78e190e5 100644 --- a/src/pulse/client-conf-x11.c +++ b/src/pulse/client-conf-x11.c @@ -44,7 +44,7 @@ int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) { if (!dname && !getenv("DISPLAY")) goto finish; - + if (!(d = XOpenDisplay(dname))) { pa_log("XOpenDisplay() failed"); goto finish; @@ -89,5 +89,5 @@ finish: XCloseDisplay(d); return ret; - + } diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c index 5cd7e3ed..b652a25b 100644 --- a/src/pulse/client-conf.c +++ b/src/pulse/client-conf.c @@ -69,11 +69,11 @@ static const pa_client_conf default_conf = { pa_client_conf *pa_client_conf_new(void) { pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); - + c->daemon_binary = pa_xstrdup(PA_BINARY); c->extra_arguments = pa_xstrdup("--log-target=syslog --exit-idle-time=5"); c->cookie_file = pa_xstrdup(PA_NATIVE_COOKIE_FILE); - + return c; } @@ -122,25 +122,25 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) { pa_log("WARNING: failed to open configuration file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } - + r = f ? pa_config_parse(fn, f, table, NULL) : 0; if (!r) r = pa_client_conf_load_cookie(c); - + finish: pa_xfree(fn); if (f) fclose(f); - + return r; } int pa_client_conf_env(pa_client_conf *c) { char *e; - + if ((e = getenv(ENV_DEFAULT_SINK))) { pa_xfree(c->default_sink); c->default_sink = pa_xstrdup(e); @@ -155,7 +155,7 @@ int pa_client_conf_env(pa_client_conf *c) { pa_xfree(c->default_server); c->default_server = pa_xstrdup(e); } - + if ((e = getenv(ENV_DAEMON_BINARY))) { pa_xfree(c->daemon_binary); c->daemon_binary = pa_xstrdup(e); @@ -167,7 +167,7 @@ int pa_client_conf_env(pa_client_conf *c) { return pa_client_conf_load_cookie(c); } - + return 0; } diff --git a/src/pulse/context.c b/src/pulse/context.c index a458c6b1..7ef43b30 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -88,11 +88,11 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { static void unlock_autospawn_lock_file(pa_context *c) { assert(c); - + if (c->autospawn_lock_fd >= 0) { char lf[PATH_MAX]; pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); - + pa_unlock_lockfile(lf, c->autospawn_lock_fd); c->autospawn_lock_fd = -1; } @@ -102,10 +102,10 @@ static void context_free(pa_context *c); pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { pa_context *c; - + assert(mainloop); assert(name); - + c = pa_xnew(pa_context, 1); c->ref = 1; c->name = pa_xstrdup(name); @@ -118,7 +118,7 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { PA_LLIST_HEAD_INIT(pa_stream, c->streams); PA_LLIST_HEAD_INIT(pa_operation, c->operations); - + c->error = PA_OK; c->state = PA_CONTEXT_UNCONNECTED; c->ctag = 0; @@ -138,7 +138,7 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { c->do_autospawn = 0; #ifndef MSG_NOSIGNAL -#ifdef SIGPIPE +#ifdef SIGPIPE pa_check_signal_is_blocked(SIGPIPE); #endif #endif @@ -183,7 +183,7 @@ static void context_free(pa_context *c) { pa_pstream_close(c->pstream); pa_pstream_unref(c->pstream); } - + if (c->record_streams) pa_dynarray_free(c->record_streams, NULL, NULL); if (c->playback_streams) @@ -196,7 +196,7 @@ static void context_free(pa_context *c) { pa_client_conf_free(c->conf); pa_strlist_free(c->server_list); - + pa_xfree(c->name); pa_xfree(c->server); pa_xfree(c); @@ -205,7 +205,7 @@ static void context_free(pa_context *c) { pa_context* pa_context_ref(pa_context *c) { assert(c); assert(c->ref >= 1); - + c->ref++; return c; } @@ -221,7 +221,7 @@ void pa_context_unref(pa_context *c) { void pa_context_set_state(pa_context *c, pa_context_state_t st) { assert(c); assert(c->ref >= 1); - + if (c->state == st) return; @@ -233,7 +233,7 @@ void pa_context_set_state(pa_context *c, pa_context_state_t st) { if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) { pa_stream *s; - + s = c->streams ? pa_stream_ref(c->streams) : NULL; while (s) { pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL; @@ -245,13 +245,13 @@ void pa_context_set_state(pa_context *c, pa_context_state_t st) { if (c->pdispatch) pa_pdispatch_unref(c->pdispatch); c->pdispatch = NULL; - + if (c->pstream) { pa_pstream_close(c->pstream); pa_pstream_unref(c->pstream); } c->pstream = NULL; - + if (c->client) pa_socket_client_unref(c->client); c->client = NULL; @@ -263,7 +263,7 @@ void pa_context_set_state(pa_context *c, pa_context_state_t st) { void pa_context_fail(pa_context *c, int error) { assert(c); assert(c->ref >= 1); - + pa_context_set_error(c, error); pa_context_set_state(c, PA_CONTEXT_FAILED); } @@ -283,19 +283,19 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { assert(p); assert(c); - + pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED); } static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) { pa_context *c = userdata; - + assert(p); assert(packet); assert(c); pa_context_ref(c); - + if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) pa_context_fail(c, PA_ERR_PROTOCOL); @@ -305,7 +305,7 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_c static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { pa_context *c = userdata; pa_stream *s; - + assert(p); assert(chunk); assert(chunk->memblock); @@ -321,7 +321,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o pa_memblockq_seek(s->record_memblockq, offset, seek); pa_memblockq_push_align(s->record_memblockq, chunk); - + if (s->read_callback) { size_t l; @@ -339,11 +339,11 @@ int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t) { if (command == PA_COMMAND_ERROR) { assert(t); - + if (pa_tagstruct_getu32(t, &c->error) < 0) { pa_context_fail(c, PA_ERR_PROTOCOL); return -1; - + } } else if (command == PA_COMMAND_TIMEOUT) c->error = PA_ERR_TIMEOUT; @@ -357,15 +357,15 @@ int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t) { static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_context *c = userdata; - + assert(pd); assert(c); assert(c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME); pa_context_ref(c); - + if (command != PA_COMMAND_REPLY) { - + if (pa_context_handle_error(c, command, t) < 0) pa_context_fail(c, PA_ERR_PROTOCOL); @@ -398,7 +398,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t * user. This is a security measure because otherwise * data private to the user might leak. */ -#ifdef HAVE_CREDS +#ifdef HAVE_CREDS const pa_creds *creds; if ((creds = pa_pdispatch_creds(pd))) if (getuid() == creds->uid) @@ -418,7 +418,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t case PA_CONTEXT_SETTING_NAME : pa_context_set_state(c, PA_CONTEXT_READY); break; - + default: assert(0); } @@ -430,12 +430,12 @@ finish: static void setup_context(pa_context *c, pa_iochannel *io) { pa_tagstruct *t; uint32_t tag; - + assert(c); assert(io); pa_context_ref(c); - + assert(!c->pstream); c->pstream = pa_pstream_new(c->mainloop, io, c->mempool); @@ -462,13 +462,13 @@ static void setup_context(pa_context *c, pa_iochannel *io) { ucred.uid = getuid(); ucred.gid = getgid(); - + pa_pstream_send_tagstruct_with_creds(c->pstream, t, &ucred); } #else pa_pstream_send_tagstruct(c->pstream, t); #endif - + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL); pa_context_set_state(c, PA_CONTEXT_AUTHORIZING); @@ -487,7 +487,7 @@ static int context_connect_spawn(pa_context *c) { pa_iochannel *io; pa_context_ref(c); - + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { pa_log("socketpair(): %s", pa_cstrerror(errno)); pa_context_fail(c, PA_ERR_INTERNAL); @@ -495,7 +495,7 @@ static int context_connect_spawn(pa_context *c) { } pa_fd_set_cloexec(fds[0], 1); - + pa_socket_low_delay(fds[0]); pa_socket_low_delay(fds[1]); @@ -508,7 +508,7 @@ static int context_connect_spawn(pa_context *c) { if (c->spawn_api.postfork) c->spawn_api.postfork(); - + goto fail; } else if (!pid) { /* Child */ @@ -521,17 +521,17 @@ static int context_connect_spawn(pa_context *c) { /* Not required, since fds[0] has CLOEXEC enabled anyway */ close(fds[0]); - + if (c->spawn_api.atfork) c->spawn_api.atfork(); /* Setup argv */ n = 0; - + argv[n++] = c->conf->daemon_binary; argv[n++] = "--daemonize=yes"; - + snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]); argv[n++] = strdup(t); @@ -540,7 +540,7 @@ static int context_connect_spawn(pa_context *c) { if (!(a = pa_split_spaces(c->conf->extra_arguments, &state))) break; - + argv[n++] = a; } @@ -549,7 +549,7 @@ static int context_connect_spawn(pa_context *c) { execv(argv[0], (char * const *) argv); _exit(1); #undef MAX_ARGS - } + } /* Parent */ @@ -557,7 +557,7 @@ static int context_connect_spawn(pa_context *c) { if (c->spawn_api.postfork) c->spawn_api.postfork(); - + if (r < 0) { pa_log("waitpid(): %s", pa_cstrerror(errno)); pa_context_fail(c, PA_ERR_INTERNAL); @@ -570,7 +570,7 @@ static int context_connect_spawn(pa_context *c) { close(fds[1]); c->is_local = 1; - + io = pa_iochannel_new(c->mainloop, fds[0], fds[0]); setup_context(c, io); @@ -598,16 +598,16 @@ fail: static int try_next_connection(pa_context *c) { char *u = NULL; int r = -1; - + assert(c); assert(!c->client); for (;;) { pa_xfree(u); u = NULL; - + c->server_list = pa_strlist_pop(c->server_list, &u); - + if (!u) { #ifndef OS_IS_WIN32 @@ -616,19 +616,19 @@ static int try_next_connection(pa_context *c) { goto finish; } #endif - + pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); goto finish; } - - pa_log_debug("Trying to connect to %s...", u); + + pa_log_debug("Trying to connect to %s...", u); pa_xfree(c->server); c->server = pa_xstrdup(u); if (!(c->client = pa_socket_client_new_string(c->mainloop, u, PA_NATIVE_DEFAULT_PORT))) continue; - + c->is_local = pa_socket_client_is_local(c->client); pa_socket_client_set_callback(c->client, on_connection, c); break; @@ -638,13 +638,13 @@ static int try_next_connection(pa_context *c) { finish: pa_xfree(u); - + return r; } static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata) { pa_context *c = userdata; - + assert(client); assert(c); assert(c->state == PA_CONTEXT_CONNECTING); @@ -677,9 +677,9 @@ int pa_context_connect( const char *server, pa_context_flags_t flags, const pa_spawn_api *api) { - + int r = -1; - + assert(c); assert(c->ref >= 1); @@ -693,7 +693,7 @@ int pa_context_connect( pa_context_ref(c); assert(!c->server_list); - + if (server) { if (!(c->server_list = pa_strlist_parse(server))) { pa_context_fail(c, PA_ERR_INVALIDSERVER); @@ -704,7 +704,7 @@ int pa_context_connect( char ufn[PATH_MAX]; /* Prepend in reverse order */ - + if ((d = getenv("DISPLAY"))) { char *e; d = pa_xstrdup(d); @@ -716,7 +716,7 @@ int pa_context_connect( pa_xfree(d); } - + c->server_list = pa_strlist_prepend(c->server_list, "tcp6:localhost"); c->server_list = pa_strlist_prepend(c->server_list, "tcp4:localhost"); @@ -744,38 +744,38 @@ int pa_context_connect( pa_context_set_state(c, PA_CONTEXT_CONNECTING); r = try_next_connection(c); - + finish: pa_context_unref(c); - + return r; } void pa_context_disconnect(pa_context *c) { assert(c); assert(c->ref >= 1); - + pa_context_set_state(c, PA_CONTEXT_TERMINATED); } pa_context_state_t pa_context_get_state(pa_context *c) { assert(c); assert(c->ref >= 1); - + return c->state; } int pa_context_errno(pa_context *c) { assert(c); assert(c->ref >= 1); - + return c->error; } void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) { assert(c); assert(c->ref >= 1); - + c->state_callback = cb; c->state_userdata = userdata; } @@ -807,7 +807,7 @@ static void pstream_drain_callback(PA_GCC_UNUSED pa_pstream *s, void *userdata) static void set_dispatch_callbacks(pa_operation *o) { int done = 1; - + assert(o); assert(o->ref >= 1); assert(o->context); @@ -816,7 +816,7 @@ static void set_dispatch_callbacks(pa_operation *o) { pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL); pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL); - + if (pa_pdispatch_is_pending(o->context->pdispatch)) { pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o); done = 0; @@ -832,7 +832,7 @@ static void set_dispatch_callbacks(pa_operation *o) { pa_context_notify_cb_t cb = (pa_context_notify_cb_t) o->callback; cb(o->context, o->userdata); } - + pa_operation_done(o); pa_operation_unref(o); } @@ -840,13 +840,13 @@ static void set_dispatch_callbacks(pa_operation *o) { pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) { pa_operation *o; - + assert(c); assert(c->ref >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, pa_context_is_pending(c), PA_ERR_BADSTATE); - + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); set_dispatch_callbacks(pa_operation_ref(o)); @@ -856,7 +856,7 @@ pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *u void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; int success = 1; - + assert(pd); assert(o); assert(o->ref >= 1); @@ -907,12 +907,12 @@ pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, pa pa_tagstruct *t; pa_operation *o; uint32_t tag; - + assert(c); assert(c->ref >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - + o = pa_operation_new(c, NULL, cb, userdata); t = pa_tagstruct_command(c, command, &tag); @@ -926,7 +926,7 @@ pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_co pa_tagstruct *t; pa_operation *o; uint32_t tag; - + assert(c); assert(c->ref >= 1); @@ -951,7 +951,7 @@ pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_ assert(c->ref >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SOURCE, &tag); @@ -964,7 +964,7 @@ pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_ int pa_context_is_local(pa_context *c) { assert(c); - + return c->is_local; } @@ -978,7 +978,7 @@ pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_su assert(name); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag); @@ -999,12 +999,12 @@ const char* pa_context_get_server(pa_context *c) { if (!c->server) return NULL; - + if (*c->server == '{') { char *e = strchr(c->server+1, '}'); return e ? e+1 : c->server; } - + return c->server; } @@ -1024,7 +1024,7 @@ pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *ta assert(c); assert(tag); - + t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, command); pa_tagstruct_putu32(t, *tag = c->ctag++); diff --git a/src/pulse/context.h b/src/pulse/context.h index 661ff617..048ed17f 100644 --- a/src/pulse/context.h +++ b/src/pulse/context.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -50,7 +50,7 @@ * The abstraction is represented as a number of function pointers in the * pa_mainloop_api structure. * - * To actually be able to use these functions, an implementation needs to + * To actually be able to use these functions, an implementation needs to * be coupled to the abstraction. There are three of these shipped with * PulseAudio, but any other can be used with a minimal ammount of work, * provided it supports the three basic events listed above. @@ -76,7 +76,7 @@ * and decrease their reference counts. Whenever an object's reference * count reaches zero, that object gets destroy and any resources it uses * get freed. - * + * * The benefit of this design is that an application need not worry about * whether or not it needs to keep an object around in case the library is * using it internally. If it is, then it has made sure it has its own diff --git a/src/pulse/def.h b/src/pulse/def.h index a22e3c19..fb04de50 100644 --- a/src/pulse/def.h +++ b/src/pulse/def.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -69,7 +69,7 @@ typedef enum pa_context_flags { PA_CONTEXT_NOAUTOSPAWN = 1 /**< Disabled autospawning of the PulseAudio daemon if required */ } pa_context_flags_t; -/** The direction of a pa_stream object */ +/** The direction of a pa_stream object */ typedef enum pa_stream_direction { PA_STREAM_NODIRECTION, /**< Invalid direction */ PA_STREAM_PLAYBACK, /**< Playback stream */ @@ -149,7 +149,7 @@ enum { PA_ERR_EXIST, /**< Entity exists */ PA_ERR_NOENTITY, /**< No such entity */ PA_ERR_CONNECTIONREFUSED, /**< Connection refused */ - PA_ERR_PROTOCOL, /**< Protocol error */ + PA_ERR_PROTOCOL, /**< Protocol error */ PA_ERR_TIMEOUT, /**< Timeout */ PA_ERR_AUTHKEY, /**< No authorization key */ PA_ERR_INTERNAL, /**< Internal error */ @@ -207,7 +207,7 @@ typedef enum pa_subscription_event_type { * total output latency a sample that is written with * pa_stream_write() takes to be played may be estimated by * sink_usec+buffer_usec+transport_usec. (where buffer_usec is defined - * as pa_bytes_to_usec(write_index-read_index)) The output buffer + * as pa_bytes_to_usec(write_index-read_index)) The output buffer * which buffer_usec relates to may be manipulated freely (with * pa_stream_write()'s seek argument, pa_stream_flush() and friends), * the buffers sink_usec and source_usec relate to are first-in @@ -256,7 +256,7 @@ typedef struct pa_timing_info { * flush request that corrupted it has * been issued in the time since this * latency info was current. \since 0.8 */ - + int64_t read_index; /**< Current read index into the * playback buffer in bytes. Think twice before * using this for seeking purposes: it @@ -288,7 +288,7 @@ typedef struct pa_spawn_api { /** Seek type for pa_stream_write(). \since 0.8*/ typedef enum pa_seek_mode { PA_SEEK_RELATIVE = 0, /**< Seek relatively to the write index */ - PA_SEEK_ABSOLUTE = 1, /**< Seek relatively to the start of the buffer queue */ + PA_SEEK_ABSOLUTE = 1, /**< Seek relatively to the start of the buffer queue */ PA_SEEK_RELATIVE_ON_READ = 2, /**< Seek relatively to the read index. */ PA_SEEK_RELATIVE_END = 3 /**< Seek relatively to the current end of the buffer queue. */ } pa_seek_mode_t; diff --git a/src/pulse/error.c b/src/pulse/error.c index 7bd31ead..3b9a60a4 100644 --- a/src/pulse/error.c +++ b/src/pulse/error.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulse/error.h b/src/pulse/error.h index bfce023c..c96349a6 100644 --- a/src/pulse/error.h +++ b/src/pulse/error.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulse/glib-mainloop.c b/src/pulse/glib-mainloop.c index 201b6e23..1669acdd 100644 --- a/src/pulse/glib-mainloop.c +++ b/src/pulse/glib-mainloop.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -69,7 +69,7 @@ struct pa_defer_event { int dead; int enabled; - + pa_defer_event_cb_t callback; void *userdata; pa_defer_event_destroy_cb_t destroy_callback; @@ -79,7 +79,7 @@ struct pa_defer_event { struct pa_glib_mainloop { GSource source; - + pa_mainloop_api api; GMainContext *context; @@ -102,7 +102,7 @@ static void cleanup_io_events(pa_glib_mainloop *g, int force) { if (!force && g->io_events_please_scan <= 0) break; - + if (force || e->dead) { PA_LLIST_REMOVE(pa_io_event, g->io_events, e); @@ -110,13 +110,13 @@ static void cleanup_io_events(pa_glib_mainloop *g, int force) { g_assert(g->io_events_please_scan > 0); g->io_events_please_scan--; } - + if (e->poll_fd_added) g_source_remove_poll(&g->source, &e->poll_fd); - + if (e->destroy_callback) e->destroy_callback(&g->api, e, e->userdata); - + pa_xfree(e); } @@ -135,7 +135,7 @@ static void cleanup_time_events(pa_glib_mainloop *g, int force) { if (!force && g->time_events_please_scan <= 0) break; - + if (force || e->dead) { PA_LLIST_REMOVE(pa_time_event, g->time_events, e); @@ -148,10 +148,10 @@ static void cleanup_time_events(pa_glib_mainloop *g, int force) { g_assert(g->n_enabled_time_events > 0); g->n_enabled_time_events--; } - + if (e->destroy_callback) e->destroy_callback(&g->api, e, e->userdata); - + pa_xfree(e); } @@ -170,7 +170,7 @@ static void cleanup_defer_events(pa_glib_mainloop *g, int force) { if (!force && g->defer_events_please_scan <= 0) break; - + if (force || e->dead) { PA_LLIST_REMOVE(pa_defer_event, g->defer_events, e); @@ -183,10 +183,10 @@ static void cleanup_defer_events(pa_glib_mainloop *g, int force) { g_assert(g->n_enabled_defer_events > 0); g->n_enabled_defer_events--; } - + if (e->destroy_callback) e->destroy_callback(&g->api, e, e->userdata); - + pa_xfree(e); } @@ -218,7 +218,7 @@ static pa_io_event* glib_io_new( pa_io_event_flags_t f, pa_io_event_cb_t cb, void *userdata) { - + pa_io_event *e; pa_glib_mainloop *g; @@ -226,7 +226,7 @@ static pa_io_event* glib_io_new( g_assert(m->userdata); g_assert(fd >= 0); g_assert(cb); - + g = m->userdata; e = pa_xnew(pa_io_event, 1); @@ -236,7 +236,7 @@ static pa_io_event* glib_io_new( e->poll_fd.fd = fd; e->poll_fd.events = map_flags_to_glib(f); e->poll_fd.revents = 0; - + e->callback = cb; e->userdata = userdata; e->destroy_callback = NULL; @@ -245,7 +245,7 @@ static pa_io_event* glib_io_new( g_source_add_poll(&g->source, &e->poll_fd); e->poll_fd_added = 1; - + return e; } @@ -272,7 +272,7 @@ static void glib_io_free(pa_io_event*e) { static void glib_io_set_destroy(pa_io_event*e, pa_io_event_destroy_cb_t cb) { g_assert(e); g_assert(!e->dead); - + e->destroy_callback = cb; } @@ -283,14 +283,14 @@ static pa_time_event* glib_time_new( const struct timeval *tv, pa_time_event_cb_t cb, void *userdata) { - + pa_glib_mainloop *g; pa_time_event *e; - + g_assert(m); g_assert(m->userdata); g_assert(cb); - + g = m->userdata; e = pa_xnew(pa_time_event, 1); @@ -308,13 +308,13 @@ static pa_time_event* glib_time_new( g->cached_next_time_event = e; } } - + e->callback = cb; e->userdata = userdata; e->destroy_callback = NULL; PA_LLIST_PREPEND(pa_time_event, g->time_events, e); - + return e; } @@ -328,12 +328,12 @@ static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { } else if (!e->enabled && tv) e->mainloop->n_enabled_time_events++; - if ((e->enabled = !!tv)) + if ((e->enabled = !!tv)) e->timeval = *tv; if (e->mainloop->cached_next_time_event && e->enabled) { g_assert(e->mainloop->cached_next_time_event->enabled); - + if (pa_timeval_cmp(tv, &e->mainloop->cached_next_time_event->timeval) < 0) e->mainloop->cached_next_time_event = e; } else if (e->mainloop->cached_next_time_event == e) @@ -357,7 +357,7 @@ static void glib_time_free(pa_time_event *e) { static void glib_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t cb) { g_assert(e); g_assert(!e->dead); - + e->destroy_callback = cb; } @@ -367,27 +367,27 @@ static pa_defer_event* glib_defer_new( pa_mainloop_api*m, pa_defer_event_cb_t cb, void *userdata) { - + pa_defer_event *e; pa_glib_mainloop *g; g_assert(m); g_assert(m->userdata); g_assert(cb); - + g = m->userdata; - + e = pa_xnew(pa_defer_event, 1); e->mainloop = g; e->dead = 0; e->enabled = 1; g->n_enabled_defer_events++; - + e->callback = cb; e->userdata = userdata; e->destroy_callback = NULL; - + PA_LLIST_PREPEND(pa_defer_event, g->defer_events, e); return e; } @@ -430,7 +430,7 @@ static void glib_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_ static void glib_quit(pa_mainloop_api*a, PA_GCC_UNUSED int retval) { g_warning("quit() ignored"); - + /* NOOP */ } @@ -440,7 +440,7 @@ static pa_time_event* find_next_time_event(pa_glib_mainloop *g) { if (g->cached_next_time_event) return g->cached_next_time_event; - + for (t = g->time_events; t; t = t->next) { if (t->dead || !t->enabled) @@ -461,7 +461,7 @@ static pa_time_event* find_next_time_event(pa_glib_mainloop *g) { static void scan_dead(pa_glib_mainloop *g) { g_assert(g); - + if (g->io_events_please_scan) cleanup_io_events(g, 0); @@ -499,7 +499,7 @@ static gboolean prepare_func(GSource *source, gint *timeout) { if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) { *timeout = 0; return TRUE; - } + } usec = pa_timeval_diff(&t->timeval, &tvnow); *timeout = (gint) (usec / 1000); } else @@ -519,10 +519,10 @@ static gboolean check_func(GSource *source) { pa_time_event *t; GTimeVal now; struct timeval tvnow; - + t = find_next_time_event(g); g_assert(t); - + g_source_get_current_time(source, &now); tvnow.tv_sec = now.tv_sec; tvnow.tv_usec = now.tv_usec; @@ -555,7 +555,7 @@ static gboolean dispatch_func(GSource *source, PA_GCC_UNUSED GSourceFunc callbac } g_assert(d); - + d->callback(&g->api, d, d->userdata); return TRUE; } @@ -567,7 +567,7 @@ static gboolean dispatch_func(GSource *source, PA_GCC_UNUSED GSourceFunc callbac t = find_next_time_event(g); g_assert(t); - + g_source_get_current_time(source, &now); tvnow.tv_sec = now.tv_sec; tvnow.tv_usec = now.tv_usec; @@ -576,7 +576,7 @@ static gboolean dispatch_func(GSource *source, PA_GCC_UNUSED GSourceFunc callbac /* Disable time event */ glib_time_restart(t, NULL); - + t->callback(&g->api, t, &t->timeval, t->userdata); return TRUE; } @@ -604,12 +604,12 @@ static const pa_mainloop_api vtable = { .time_restart = glib_time_restart, .time_free = glib_time_free, .time_set_destroy = glib_time_set_destroy, - + .defer_new = glib_defer_new, .defer_enable = glib_defer_enable, .defer_free = glib_defer_free, .defer_set_destroy = glib_defer_set_destroy, - + .quit = glib_quit, }; @@ -624,10 +624,10 @@ pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) { NULL, NULL }; - + g = (pa_glib_mainloop*) g_source_new(&source_funcs, sizeof(pa_glib_mainloop)); g_main_context_ref(g->context = c ? c : g_main_context_default()); - + g->api = vtable; g->api.userdata = g; @@ -639,10 +639,10 @@ pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) { g->io_events_please_scan = g->time_events_please_scan = g->defer_events_please_scan = 0; g->cached_next_time_event = NULL; - + g_source_attach(&g->source, g->context); g_source_set_can_recurse(&g->source, FALSE); - + return g; } @@ -660,6 +660,6 @@ void pa_glib_mainloop_free(pa_glib_mainloop* g) { pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) { g_assert(g); - + return &g->api; } diff --git a/src/pulse/glib-mainloop.h b/src/pulse/glib-mainloop.h index af7cc0e9..5f8093a1 100644 --- a/src/pulse/glib-mainloop.h +++ b/src/pulse/glib-mainloop.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulse/internal.h b/src/pulse/internal.h index 4eef4b4a..8cdbf84a 100644 --- a/src/pulse/internal.h +++ b/src/pulse/internal.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -45,7 +45,7 @@ struct pa_context { int ref; - + char *name; pa_mainloop_api* mainloop; @@ -75,7 +75,7 @@ struct pa_context { int do_autospawn; int autospawn_lock_fd; pa_spawn_api spawn_api; - + pa_strlist *server_list; char *server; @@ -109,7 +109,7 @@ struct pa_stream { uint32_t device_index; pa_stream_direction_t direction; pa_stream_state_t state; - + uint32_t requested_bytes; pa_memchunk peek_memchunk; @@ -120,10 +120,10 @@ struct pa_stream { /* Store latest latency info */ pa_timing_info timing_info; int timing_info_valid; - + /* Use to make sure that time advances monotonically */ pa_usec_t previous_time; - + /* time updates with tags older than these are invalid */ uint32_t write_index_not_before; uint32_t read_index_not_before; @@ -135,7 +135,7 @@ struct pa_stream { /* Latency interpolation stuff */ pa_time_event *auto_timing_update_event; int auto_timing_update_requested; - + pa_usec_t cached_time; int cached_time_valid; @@ -160,7 +160,7 @@ struct pa_operation { int ref; pa_context *context; pa_stream *stream; - + PA_LLIST_FIELDS(pa_operation); pa_operation_state_t state; diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c index b926e4e4..5a2c8fb6 100644 --- a/src/pulse/introspect.c +++ b/src/pulse/introspect.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -39,7 +39,7 @@ static void context_stat_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; pa_stat_info i, *p = &i; - + assert(pd); assert(o); assert(o->ref >= 1); @@ -81,11 +81,11 @@ pa_operation* pa_context_stat(pa_context *c, pa_stat_info_cb_t cb, void *userdat static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; pa_server_info i, *p = &i; - + assert(pd); assert(o); assert(o->ref >= 1); - + if (!o->context) goto finish; @@ -107,7 +107,7 @@ static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command, pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } - + if (o->callback) { pa_server_info_cb_t cb = (pa_server_info_cb_t) o->callback; cb(o->context, p, o->userdata); @@ -127,14 +127,14 @@ pa_operation* pa_context_get_server_info(pa_context *c, pa_server_info_cb_t cb, static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; int eol = 1; - + assert(pd); assert(o); assert(o->ref >= 1); if (!o->context) goto finish; - + if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; @@ -142,10 +142,10 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P eol = -1; } else { uint32_t flags; - + while (!pa_tagstruct_eof(t)) { pa_sink_info i; - + if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_gets(t, &i.description) < 0 || @@ -159,7 +159,7 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P pa_tagstruct_get_usec(t, &i.latency) < 0 || pa_tagstruct_gets(t, &i.driver) < 0 || pa_tagstruct_getu32(t, &flags) < 0) { - + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } @@ -172,7 +172,7 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P } } } - + if (o->callback) { pa_sink_info_cb_t cb = (pa_sink_info_cb_t) o->callback; cb(o->context, NULL, eol, o->userdata); @@ -191,7 +191,7 @@ pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, pa_ pa_tagstruct *t; pa_operation *o; uint32_t tag; - + assert(c); assert(c->ref >= 1); assert(cb); @@ -213,7 +213,7 @@ pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, pa_tagstruct *t; pa_operation *o; uint32_t tag; - + assert(c); assert(c->ref >= 1); assert(cb); @@ -251,11 +251,11 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, eol = -1; } else { - + while (!pa_tagstruct_eof(t)) { pa_source_info i; uint32_t flags; - + if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_gets(t, &i.description) < 0 || @@ -269,7 +269,7 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, pa_tagstruct_get_usec(t, &i.latency) < 0 || pa_tagstruct_gets(t, &i.driver) < 0 || pa_tagstruct_getu32(t, &flags) < 0) { - + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } @@ -282,7 +282,7 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, } } } - + if (o->callback) { pa_source_info_cb_t cb = (pa_source_info_cb_t) o->callback; cb(o->context, NULL, eol, o->userdata); @@ -309,7 +309,7 @@ pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, p PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - + t = pa_tagstruct_command(c, PA_COMMAND_GET_SOURCE_INFO, &tag); pa_tagstruct_putu32(t, idx); pa_tagstruct_puts(t, NULL); @@ -361,10 +361,10 @@ static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, eol = -1; } else { - + while (!pa_tagstruct_eof(t)) { pa_client_info i; - + if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_getu32(t, &i.owner_module) < 0 || @@ -379,7 +379,7 @@ static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, } } } - + if (o->callback) { pa_client_info_cb_t cb = (pa_client_info_cb_t) o->callback; cb(o->context, NULL, eol, o->userdata); @@ -428,17 +428,17 @@ static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command, if (!o->context) goto finish; - + if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; eol = -1; } else { - + while (!pa_tagstruct_eof(t)) { pa_module_info i; - + if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_gets(t, &i.argument) < 0 || @@ -454,7 +454,7 @@ static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command, } } } - + if (o->callback) { pa_module_info_cb_t cb = (pa_module_info_cb_t) o->callback; cb(o->context, NULL, eol, o->userdata); @@ -476,7 +476,7 @@ pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_ PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_command(c, PA_COMMAND_GET_MODULE_INFO, &tag); @@ -503,17 +503,17 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm if (!o->context) goto finish; - + if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; eol = -1; } else { - + while (!pa_tagstruct_eof(t)) { pa_sink_input_info i; - + if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_getu32(t, &i.owner_module) < 0 || @@ -526,7 +526,7 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || pa_tagstruct_gets(t, &i.resample_method) < 0 || pa_tagstruct_gets(t, &i.driver) < 0) { - + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } @@ -537,7 +537,7 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm } } } - + if (o->callback) { pa_sink_input_info_cb_t cb = (pa_sink_input_info_cb_t) o->callback; cb(o->context, NULL, eol, o->userdata); @@ -559,7 +559,7 @@ pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sin PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_command(c, PA_COMMAND_GET_SINK_INPUT_INFO, &tag); @@ -593,10 +593,10 @@ static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t c eol = -1; } else { - + while (!pa_tagstruct_eof(t)) { pa_source_output_info i; - + if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_getu32(t, &i.owner_module) < 0 || @@ -608,7 +608,7 @@ static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t c pa_tagstruct_get_usec(t, &i.source_usec) < 0 || pa_tagstruct_gets(t, &i.resample_method) < 0 || pa_tagstruct_gets(t, &i.driver) < 0) { - + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } @@ -619,7 +619,7 @@ static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t c } } } - + if (o->callback) { pa_source_output_info_cb_t cb = (pa_source_output_info_cb_t) o->callback; cb(o->context, NULL, eol, o->userdata); @@ -641,7 +641,7 @@ pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, pa_ PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO, &tag); @@ -695,7 +695,7 @@ pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_VOLUME, &tag); @@ -741,7 +741,7 @@ pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name, PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_MUTE, &tag); @@ -766,7 +766,7 @@ pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, cons PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); - + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_INPUT_VOLUME, &tag); @@ -815,7 +815,7 @@ pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *na PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_VOLUME, &tag); @@ -861,7 +861,7 @@ pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_MUTE, &tag); @@ -886,17 +886,17 @@ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, if (!o->context) goto finish; - + if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; eol = -1; } else { - + while (!pa_tagstruct_eof(t)) { pa_sample_info i; - + if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_get_cvolume(t, &i.volume) < 0 || @@ -906,7 +906,7 @@ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, pa_tagstruct_getu32(t, &i.bytes) < 0 || pa_tagstruct_get_boolean(t, &i.lazy) < 0 || pa_tagstruct_gets(t, &i.filename) < 0) { - + pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } @@ -917,7 +917,7 @@ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, } } } - + if (o->callback) { pa_sample_info_cb_t cb = (pa_sample_info_cb_t) o->callback; cb(o->context, NULL, eol, o->userdata); @@ -932,7 +932,7 @@ pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name pa_tagstruct *t; pa_operation *o; uint32_t tag; - + assert(c); assert(c->ref >= 1); assert(cb); @@ -1002,7 +1002,7 @@ static pa_operation* command_kill(pa_context *c, uint32_t command, uint32_t idx, pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { return command_kill(c, PA_COMMAND_KILL_CLIENT, idx, cb, userdata); } - + pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { return command_kill(c, PA_COMMAND_KILL_SINK_INPUT, idx, cb, userdata); } @@ -1021,7 +1021,7 @@ static void context_index_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN if (!o->context) goto finish; - + if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; @@ -1048,7 +1048,7 @@ pa_operation* pa_context_load_module(pa_context *c, const char*name, const char pa_operation *o; pa_tagstruct *t; uint32_t tag; - + assert(c); assert(c->ref >= 1); @@ -1089,10 +1089,10 @@ static void context_get_autoload_info_callback(pa_pdispatch *pd, uint32_t comman eol = -1; } else { - + while (!pa_tagstruct_eof(t)) { pa_autoload_info i; - + if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_getu32(t, &i.type) < 0 || @@ -1108,7 +1108,7 @@ static void context_get_autoload_info_callback(pa_pdispatch *pd, uint32_t comman } } } - + if (o->callback) { pa_autoload_info_cb_t cb = (pa_autoload_info_cb_t) o->callback; cb(o->context, NULL, eol, o->userdata); @@ -1147,7 +1147,7 @@ pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, pa_tagstruct *t; pa_operation *o; uint32_t tag; - + assert(c); assert(c->ref >= 1); assert(cb); @@ -1176,7 +1176,7 @@ pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autolo assert(c); assert(c->ref >= 1); - + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); PA_CHECK_VALIDITY_RETURN_NULL(c, type == PA_AUTOLOAD_SINK || type == PA_AUTOLOAD_SOURCE, PA_ERR_INVALID); @@ -1202,7 +1202,7 @@ pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name assert(c); assert(c->ref >= 1); - + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); PA_CHECK_VALIDITY_RETURN_NULL(c, type == PA_AUTOLOAD_SINK || type == PA_AUTOLOAD_SOURCE, PA_ERR_INVALID); diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h index 28d22cd7..6de7bc71 100644 --- a/src/pulse/introspect.h +++ b/src/pulse/introspect.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -206,7 +206,7 @@ PA_C_DECL_BEGIN /** Stores information about sinks */ typedef struct pa_sink_info { const char *name; /**< Name of the sink */ - uint32_t index; /**< Index of the sink */ + uint32_t index; /**< Index of the sink */ const char *description; /**< Description of this sink */ pa_sample_spec sample_spec; /**< Sample spec of this sink */ pa_channel_map channel_map; /**< Channel map \since 0.8 */ @@ -233,7 +233,7 @@ pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t id, pa_s pa_operation* pa_context_get_sink_info_list(pa_context *c, pa_sink_info_cb_t cb, void *userdata); /** Stores information about sources */ -typedef struct pa_source_info { +typedef struct pa_source_info { const char *name ; /**< Name of the source */ uint32_t index; /**< Index of the source */ const char *description; /**< Description of this source */ @@ -316,7 +316,7 @@ pa_operation* pa_context_get_client_info_list(pa_context *c, pa_client_info_cb_t /** Stores information about sink inputs */ typedef struct pa_sink_input_info { - uint32_t index; /**< Index of the sink input */ + uint32_t index; /**< Index of the sink input */ const char *name; /**< Name of the sink input */ uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ @@ -341,11 +341,11 @@ pa_operation* pa_context_get_sink_input_info_list(pa_context *c, pa_sink_input_i /** Stores information about source outputs */ typedef struct pa_source_output_info { - uint32_t index; /**< Index of the sink input */ + uint32_t index; /**< Index of the sink input */ const char *name; /**< Name of the sink input */ - uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ - uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ - uint32_t source; /**< Index of the connected source */ + uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ + uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ + uint32_t source; /**< Index of the connected source */ pa_sample_spec sample_spec; /**< The sample specification of the source output */ pa_channel_map channel_map; /**< Channel map */ pa_usec_t buffer_usec; /**< Latency due to buffering in the source output, see pa_latency_info for details. \since 0.5 */ @@ -396,7 +396,7 @@ typedef struct pa_stat_info { uint32_t memblock_total_size; /**< Currentl total size of allocated memory blocks */ uint32_t memblock_allocated; /**< Allocated memory blocks during the whole lifetime of the daemon */ uint32_t memblock_allocated_size; /**< Total size of all memory blocks allocated during the whole lifetime of the daemon */ - uint32_t scache_size; /**< Total size of all sample cache entries. \since 0.4 */ + uint32_t scache_size; /**< Total size of all sample cache entries. \since 0.4 */ } pa_stat_info; /** Callback prototype for pa_context_stat() */ @@ -432,7 +432,7 @@ pa_operation* pa_context_get_sample_info_list(pa_context *c, pa_sample_info_cb_t /** Kill a client. \since 0.5 */ pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); - + /** Kill a sink input. \since 0.5 */ pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); diff --git a/src/pulse/mainloop-api.c b/src/pulse/mainloop-api.c index 2e20b446..bf3ef37e 100644 --- a/src/pulse/mainloop-api.c +++ b/src/pulse/mainloop-api.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulse/mainloop-api.h b/src/pulse/mainloop-api.h index 7b7075ae..b88bf125 100644 --- a/src/pulse/mainloop-api.h +++ b/src/pulse/mainloop-api.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -28,7 +28,7 @@ #include /** \file - * + * * Main loop abstraction layer. Both the PulseAudio core and the * PulseAudio client library use a main loop abstraction layer. Due to * this it is possible to embed PulseAudio into other diff --git a/src/pulse/mainloop-signal.c b/src/pulse/mainloop-signal.c index d651462b..4dd42796 100644 --- a/src/pulse/mainloop-signal.c +++ b/src/pulse/mainloop-signal.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -73,7 +73,7 @@ static void signal_handler(int sig) { static void dispatch(pa_mainloop_api*a, int sig) { pa_signal_event*s; - for (s = signals; s; s = s->next) + for (s = signals; s; s = s->next) if (s->sig == sig) { assert(s->callback); s->callback(a, s, sig, s->userdata); @@ -93,7 +93,7 @@ static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags pa_log("read(): %s", pa_cstrerror(errno)); return; } - + if (r != sizeof(sig)) { pa_log("short read()"); return; @@ -129,7 +129,7 @@ void pa_signal_done(void) { while (signals) pa_signal_free(signals); - + api->io_free(io_event); io_event = NULL; @@ -148,11 +148,11 @@ pa_signal_event* pa_signal_new(int sig, void (*_callback) (pa_mainloop_api *api, #endif assert(sig > 0 && _callback); - + for (e = signals; e; e = e->next) if (e->sig == sig) goto fail; - + e = pa_xmalloc(sizeof(pa_signal_event)); e->sig = sig; e->callback = _callback; @@ -164,7 +164,7 @@ pa_signal_event* pa_signal_new(int sig, void (*_callback) (pa_mainloop_api *api, sa.sa_handler = signal_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; - + if (sigaction(sig, &sa, &e->saved_sigaction) < 0) #else if ((e->saved_handler = signal(sig, signal_handler)) == SIG_ERR) @@ -200,7 +200,7 @@ void pa_signal_free(pa_signal_event *e) { if (e->destroy_callback) e->destroy_callback(api, e, e->userdata); - + pa_xfree(e); } diff --git a/src/pulse/mainloop-signal.h b/src/pulse/mainloop-signal.h index 0721c1f5..e991cf1c 100644 --- a/src/pulse/mainloop-signal.h +++ b/src/pulse/mainloop-signal.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c index f7b15537..04461b30 100644 --- a/src/pulse/mainloop.c +++ b/src/pulse/mainloop.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -57,11 +57,11 @@ struct pa_io_event { pa_mainloop *mainloop; int dead; - + int fd; pa_io_event_flags_t events; struct pollfd *pollfd; - + pa_io_event_cb_t callback; void *userdata; pa_io_event_destroy_cb_t destroy_callback; @@ -154,7 +154,7 @@ static pa_io_event* mainloop_io_new( pa_io_event_flags_t events, pa_io_event_cb_t callback, void *userdata) { - + pa_mainloop *m; pa_io_event *e; @@ -162,7 +162,7 @@ static pa_io_event* mainloop_io_new( assert(a->userdata); assert(fd >= 0); assert(callback); - + m = a->userdata; assert(a == &m->api); @@ -173,7 +173,7 @@ static pa_io_event* mainloop_io_new( e->fd = fd; e->events = events; e->pollfd = NULL; - + e->callback = callback; e->userdata = userdata; e->destroy_callback = NULL; @@ -213,7 +213,7 @@ static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags_t events) { if (e->events == events) return; - + e->events = events; if (e->pollfd) @@ -239,7 +239,7 @@ static void mainloop_io_free(pa_io_event *e) { static void mainloop_io_set_destroy(pa_io_event *e, pa_io_event_destroy_cb_t callback) { assert(e); - + e->destroy_callback = callback; } @@ -255,7 +255,7 @@ static pa_defer_event* mainloop_defer_new( assert(a); assert(a->userdata); assert(callback); - + m = a->userdata; assert(a == &m->api); @@ -265,7 +265,7 @@ static pa_defer_event* mainloop_defer_new( e->enabled = 1; m->n_enabled_defer_events++; - + e->callback = callback; e->userdata = userdata; e->destroy_callback = NULL; @@ -288,7 +288,7 @@ static void mainloop_defer_enable(pa_defer_event *e, int b) { e->mainloop->n_enabled_defer_events++; pa_mainloop_wakeup(e->mainloop); } - + e->enabled = b; } @@ -318,14 +318,14 @@ static pa_time_event* mainloop_time_new( const struct timeval *tv, pa_time_event_cb_t callback, void *userdata) { - + pa_mainloop *m; pa_time_event *e; assert(a); assert(a->userdata); assert(callback); - + m = a->userdata; assert(a == &m->api); @@ -354,7 +354,7 @@ static pa_time_event* mainloop_time_new( if (e->enabled) pa_mainloop_wakeup(m); - + return e; } @@ -375,7 +375,7 @@ static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) { if (e->mainloop->cached_next_time_event && e->enabled) { assert(e->mainloop->cached_next_time_event->enabled); - + if (pa_timeval_cmp(tv, &e->mainloop->cached_next_time_event->timeval) < 0) e->mainloop->cached_next_time_event = e; } else if (e->mainloop->cached_next_time_event == e) @@ -396,7 +396,7 @@ static void mainloop_time_free(pa_time_event *e) { if (e->mainloop->cached_next_time_event == e) e->mainloop->cached_next_time_event = NULL; - + /* no wakeup needed here. Think about it! */ } @@ -411,7 +411,7 @@ static void mainloop_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb static void mainloop_quit(pa_mainloop_api*a, int retval) { pa_mainloop *m; - + assert(a); assert(a->userdata); m = a->userdata; @@ -419,7 +419,7 @@ static void mainloop_quit(pa_mainloop_api*a, int retval) { pa_mainloop_quit(m, retval); } - + static const pa_mainloop_api vtable = { .userdata = NULL, @@ -432,12 +432,12 @@ static const pa_mainloop_api vtable = { .time_restart = mainloop_time_restart, .time_free = mainloop_time_free, .time_set_destroy = mainloop_time_set_destroy, - + .defer_new = mainloop_defer_new, .defer_enable = mainloop_defer_enable, .defer_free = mainloop_defer_free, .defer_set_destroy = mainloop_defer_set_destroy, - + .quit = mainloop_quit, }; @@ -466,7 +466,7 @@ pa_mainloop *pa_mainloop_new(void) { m->cached_next_time_event = NULL; m->prepared_timeout = 0; - + m->pollfds = NULL; m->max_pollfds = m->n_pollfds = 0; m->rebuild_pollfds = 1; @@ -481,7 +481,7 @@ pa_mainloop *pa_mainloop_new(void) { m->poll_func = NULL; m->poll_func_userdata = NULL; m->poll_func_ret = -1; - + return m; } @@ -494,7 +494,7 @@ static void cleanup_io_events(pa_mainloop *m, int force) { if (!force && m->io_events_please_scan <= 0) break; - + if (force || e->dead) { PA_LLIST_REMOVE(pa_io_event, m->io_events, e); @@ -502,10 +502,10 @@ static void cleanup_io_events(pa_mainloop *m, int force) { assert(m->io_events_please_scan > 0); m->io_events_please_scan--; } - + if (e->destroy_callback) e->destroy_callback(&m->api, e, e->userdata); - + pa_xfree(e); m->rebuild_pollfds = 1; @@ -526,7 +526,7 @@ static void cleanup_time_events(pa_mainloop *m, int force) { if (!force && m->time_events_please_scan <= 0) break; - + if (force || e->dead) { PA_LLIST_REMOVE(pa_time_event, m->time_events, e); @@ -539,10 +539,10 @@ static void cleanup_time_events(pa_mainloop *m, int force) { assert(m->n_enabled_time_events > 0); m->n_enabled_time_events--; } - + if (e->destroy_callback) e->destroy_callback(&m->api, e, e->userdata); - + pa_xfree(e); } @@ -561,7 +561,7 @@ static void cleanup_defer_events(pa_mainloop *m, int force) { if (!force && m->defer_events_please_scan <= 0) break; - + if (force || e->dead) { PA_LLIST_REMOVE(pa_defer_event, m->defer_events, e); @@ -574,10 +574,10 @@ static void cleanup_defer_events(pa_mainloop *m, int force) { assert(m->n_enabled_defer_events > 0); m->n_enabled_defer_events--; } - + if (e->destroy_callback) e->destroy_callback(&m->api, e, e->userdata); - + pa_xfree(e); } @@ -664,11 +664,11 @@ static int dispatch_pollfds(pa_mainloop *m) { int r = 0, k; assert(m->poll_func_ret > 0); - + for (e = m->io_events, k = m->poll_func_ret; e && !m->quit && k > 0; e = e->next) { if (e->dead || !e->pollfd || !e->pollfd->revents) continue; - + assert(e->pollfd->fd == e->fd && e->callback); e->callback(&m->api, e, e->fd, map_flags_from_libc(e->pollfd->revents), e->userdata); e->pollfd->revents = 0; @@ -690,7 +690,7 @@ static int dispatch_defer(pa_mainloop *m) { for (e = m->defer_events; e && !m->quit; e = e->next) { if (e->dead || !e->enabled) continue; - + assert(e->callback); e->callback(&m->api, e, e->userdata); r++; @@ -705,7 +705,7 @@ static pa_time_event* find_next_time_event(pa_mainloop *m) { if (m->cached_next_time_event) return m->cached_next_time_event; - + for (t = m->time_events; t; t = t->next) { if (t->dead || !t->enabled) @@ -737,7 +737,7 @@ static int calc_next_timeout(pa_mainloop *m) { if (t->timeval.tv_sec <= 0) return 0; - + pa_gettimeofday(&now); if (pa_timeval_cmp(&t->timeval, &now) <= 0) @@ -759,7 +759,7 @@ static int dispatch_timeout(pa_mainloop *m) { pa_gettimeofday(&now); for (e = m->time_events; e && !m->quit; e = e->next) { - + if (e->dead || !e->enabled) continue; @@ -815,7 +815,7 @@ int pa_mainloop_prepare(pa_mainloop *m, int timeout) { if (m->n_enabled_defer_events <= 0) { if (m->rebuild_pollfds) rebuild_pollfds(m); - + m->prepared_timeout = calc_next_timeout(m); if (timeout >= 0 && (timeout < m->prepared_timeout || m->prepared_timeout < 0)) m->prepared_timeout = timeout; @@ -842,7 +842,7 @@ int pa_mainloop_poll(pa_mainloop *m) { m->poll_func_ret = 0; else { assert(!m->rebuild_pollfds); - + if (m->poll_func) m->poll_func_ret = m->poll_func(m->pollfds, m->n_pollfds, m->prepared_timeout, m->poll_func_userdata); else @@ -872,23 +872,23 @@ int pa_mainloop_dispatch(pa_mainloop *m) { if (m->quit) goto quit; - + if (m->n_enabled_defer_events) dispatched += dispatch_defer(m); else { - if (m->n_enabled_time_events) + if (m->n_enabled_time_events) dispatched += dispatch_timeout(m); - + if (m->quit) goto quit; if (m->poll_func_ret > 0) dispatched += dispatch_pollfds(m); } - + if (m->quit) goto quit; - + m->state = STATE_PASSIVE; return dispatched; @@ -919,7 +919,7 @@ int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) { return r; quit: - + if ((r == -2) && retval) *retval = pa_mainloop_get_retval(m); return r; @@ -927,7 +927,7 @@ quit: int pa_mainloop_run(pa_mainloop *m, int *retval) { int r; - + while ((r = pa_mainloop_iterate(m, 1, retval)) >= 0); if (r == -2) diff --git a/src/pulse/mainloop.h b/src/pulse/mainloop.h index 8abd8fe4..18be1f2b 100644 --- a/src/pulse/mainloop.h +++ b/src/pulse/mainloop.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -65,7 +65,7 @@ struct pollfd; */ /** \file - * + * * A minimal main loop implementation based on the C library's poll() * function. Using the routines defined herein you may create a simple * main loop supporting the generic main loop abstraction layer as diff --git a/src/pulse/operation.c b/src/pulse/operation.c index 8d896d7d..e039e8c9 100644 --- a/src/pulse/operation.c +++ b/src/pulse/operation.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -46,14 +46,14 @@ pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t cb /* Refcounting is strictly one-way: from the "bigger" to the "smaller" object. */ PA_LLIST_PREPEND(pa_operation, c->operations, o); pa_operation_ref(o); - + return o; } pa_operation *pa_operation_ref(pa_operation *o) { assert(o); assert(o->ref >= 1); - + o->ref++; return o; } @@ -81,14 +81,14 @@ static void operation_set_state(pa_operation *o, pa_operation_state_t st) { o->state = st; if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) { - + if (o->context) { assert(o->ref >= 2); - + PA_LLIST_REMOVE(pa_operation, o->context->operations, o); pa_operation_unref(o); } - + o->context = NULL; o->stream = NULL; o->callback = NULL; @@ -101,14 +101,14 @@ static void operation_set_state(pa_operation *o, pa_operation_state_t st) { void pa_operation_cancel(pa_operation *o) { assert(o); assert(o->ref >= 1); - + operation_set_state(o, PA_OPERATION_CANCELED); } void pa_operation_done(pa_operation *o) { assert(o); assert(o->ref >= 1); - + operation_set_state(o, PA_OPERATION_DONE); } diff --git a/src/pulse/operation.h b/src/pulse/operation.h index b544e08e..adfd5f2d 100644 --- a/src/pulse/operation.h +++ b/src/pulse/operation.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulse/pulseaudio.h b/src/pulse/pulseaudio.h index 88cc326b..5543d7cd 100644 --- a/src/pulse/pulseaudio.h +++ b/src/pulse/pulseaudio.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -55,11 +55,11 @@ /** \mainpage * * \section intro_sec Introduction - * + * * This document describes the client API for the PulseAudio sound * server. The API comes in two flavours to accomodate different styles * of applications and different needs in complexity: - * + * * \li The complete but somewhat complicated to use asynchronous API * \li The simplified, easy to use, but limited synchronous API * @@ -67,7 +67,7 @@ * locale. Some functions will filter invalid sequences from the string, some * will simply fail. To ensure reliable behaviour, make sure everything you * pass to the API is already in UTF-8. - + * \section simple_sec Simple API * * Use this if you develop your program in synchronous style and just diff --git a/src/pulse/sample.c b/src/pulse/sample.c index 7ca418e1..dd68ac17 100644 --- a/src/pulse/sample.c +++ b/src/pulse/sample.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -70,7 +70,7 @@ pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) { size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec) { assert(spec); - return (size_t) (((double) t * spec->rate / 1000000))*pa_frame_size(spec); + return (size_t) (((double) t * spec->rate / 1000000))*pa_frame_size(spec); } int pa_sample_spec_valid(const pa_sample_spec *spec) { @@ -111,7 +111,7 @@ const char *pa_sample_format_to_string(pa_sample_format_t f) { char *pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec) { assert(s && l && spec); - + if (!pa_sample_spec_valid(spec)) snprintf(s, l, "Invalid"); else @@ -134,7 +134,7 @@ char* pa_bytes_snprint(char *s, size_t l, unsigned v) { } pa_sample_format_t pa_parse_sample_format(const char *format) { - + if (strcasecmp(format, "s16le") == 0) return PA_SAMPLE_S16LE; else if (strcasecmp(format, "s16be") == 0) diff --git a/src/pulse/sample.h b/src/pulse/sample.h index da32fdf0..b7c537e4 100644 --- a/src/pulse/sample.h +++ b/src/pulse/sample.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulse/scache.c b/src/pulse/scache.c index 5d29c5b3..5abaf845 100644 --- a/src/pulse/scache.c +++ b/src/pulse/scache.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -37,14 +37,14 @@ int pa_stream_connect_upload(pa_stream *s, size_t length) { pa_tagstruct *t; uint32_t tag; - + assert(s); PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, length > 0, PA_ERR_INVALID); - + pa_stream_ref(s); - + s->direction = PA_STREAM_UPLOAD; t = pa_tagstruct_command(s->context, PA_COMMAND_CREATE_UPLOAD_STREAM, &tag); @@ -56,7 +56,7 @@ int pa_stream_connect_upload(pa_stream *s, size_t length) { pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL); pa_stream_set_state(s, PA_STREAM_CREATING); - + pa_stream_unref(s); return 0; } @@ -87,16 +87,16 @@ pa_operation *pa_context_play_sample(pa_context *c, const char *name, const char assert(c); assert(c->ref >= 1); - + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); PA_CHECK_VALIDITY_RETURN_NULL(c, !dev || *dev, PA_ERR_INVALID); - + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); if (!dev) dev = c->conf->default_sink; - + t = pa_tagstruct_command(c, PA_COMMAND_PLAY_SAMPLE, &tag); pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, dev); @@ -118,9 +118,9 @@ pa_operation* pa_context_remove_sample(pa_context *c, const char *name, pa_conte PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); - + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - + t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_SAMPLE, &tag); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); diff --git a/src/pulse/scache.h b/src/pulse/scache.h index e32703d4..2293dec4 100644 --- a/src/pulse/scache.h +++ b/src/pulse/scache.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulse/simple.c b/src/pulse/simple.c index a41881bb..1c632fa7 100644 --- a/src/pulse/simple.c +++ b/src/pulse/simple.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -64,7 +64,7 @@ if (!(expression)) { \ goto label; \ } \ } while(0); - + #define CHECK_DEAD_GOTO(p, rerror, label) do { \ if (!(p)->context || pa_context_get_state((p)->context) != PA_CONTEXT_READY || \ !(p)->stream || pa_stream_get_state((p)->stream) != PA_STREAM_READY) { \ @@ -143,7 +143,7 @@ pa_simple* pa_simple_new( const pa_channel_map *map, const pa_buffer_attr *attr, int *rerror) { - + pa_simple *p; int error = PA_ERR_INTERNAL, r; @@ -162,12 +162,12 @@ pa_simple* pa_simple_new( if (!(p->mainloop = pa_threaded_mainloop_new())) goto fail; - + if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), name))) goto fail; pa_context_set_state_callback(p->context, context_state_cb, p); - + if (pa_context_connect(p->context, server, 0, NULL) < 0) { error = pa_context_errno(p->context); goto fail; @@ -180,7 +180,7 @@ pa_simple* pa_simple_new( /* Wait until the context is ready */ pa_threaded_mainloop_wait(p->mainloop); - + if (pa_context_get_state(p->context) != PA_CONTEXT_READY) { error = pa_context_errno(p->context); goto unlock_and_fail; @@ -216,12 +216,12 @@ pa_simple* pa_simple_new( } pa_threaded_mainloop_unlock(p->mainloop); - + return p; unlock_and_fail: pa_threaded_mainloop_unlock(p->mainloop); - + fail: if (rerror) *rerror = error; @@ -234,10 +234,10 @@ void pa_simple_free(pa_simple *s) { if (s->mainloop) pa_threaded_mainloop_stop(s->mainloop); - + if (s->stream) pa_stream_unref(s->stream); - + if (s->context) pa_context_unref(s->context); @@ -249,38 +249,38 @@ void pa_simple_free(pa_simple *s) { int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { assert(p); - + CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1); pa_threaded_mainloop_lock(p->mainloop); - + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); while (length > 0) { size_t l; int r; - + while (!(l = pa_stream_writable_size(p->stream))) { pa_threaded_mainloop_wait(p->mainloop); CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); } CHECK_SUCCESS_GOTO(p, rerror, l != (size_t) -1, unlock_and_fail); - + if (l > length) l = length; r = pa_stream_write(p->stream, data, l, NULL, 0, PA_SEEK_RELATIVE); CHECK_SUCCESS_GOTO(p, rerror, r >= 0, unlock_and_fail); - + data = (const uint8_t*) data + l; length -= l; } pa_threaded_mainloop_unlock(p->mainloop); return 0; - + unlock_and_fail: pa_threaded_mainloop_unlock(p->mainloop); return -1; @@ -293,15 +293,15 @@ int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1); pa_threaded_mainloop_lock(p->mainloop); - + CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); while (length > 0) { size_t l; - + while (!p->read_data) { int r; - + r = pa_stream_peek(p->stream, &p->read_data, &p->read_length); CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail); @@ -311,31 +311,31 @@ int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { } else p->read_index = 0; } - + l = p->read_length < length ? p->read_length : length; memcpy(data, (const uint8_t*) p->read_data+p->read_index, l); data = (uint8_t*) data + l; length -= l; - + p->read_index += l; p->read_length -= l; if (!p->read_length) { int r; - + r = pa_stream_drop(p->stream); p->read_data = NULL; p->read_length = 0; p->read_index = 0; - + CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail); } } pa_threaded_mainloop_unlock(p->mainloop); return 0; - + unlock_and_fail: pa_threaded_mainloop_unlock(p->mainloop); return -1; @@ -353,7 +353,7 @@ static void success_cb(pa_stream *s, int success, void *userdata) { int pa_simple_drain(pa_simple *p, int *rerror) { pa_operation *o = NULL; - + assert(p); CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); @@ -370,7 +370,7 @@ int pa_simple_drain(pa_simple *p, int *rerror) { CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); } CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail); - + pa_operation_unref(o); pa_threaded_mainloop_unlock(p->mainloop); @@ -389,7 +389,7 @@ unlock_and_fail: int pa_simple_flush(pa_simple *p, int *rerror) { pa_operation *o = NULL; - + assert(p); CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); @@ -399,7 +399,7 @@ int pa_simple_flush(pa_simple *p, int *rerror) { o = pa_stream_flush(p->stream, success_cb, p); CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); - + p->operation_success = 0; while (pa_operation_get_state(o) != PA_OPERATION_DONE) { pa_threaded_mainloop_wait(p->mainloop); @@ -426,14 +426,14 @@ unlock_and_fail: pa_usec_t pa_simple_get_latency(pa_simple *p, int *rerror) { pa_usec_t t; int negative; - + assert(p); - + pa_threaded_mainloop_lock(p->mainloop); for (;;) { CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - + if (pa_stream_get_latency(p->stream, &t, &negative) >= 0) break; @@ -442,7 +442,7 @@ pa_usec_t pa_simple_get_latency(pa_simple *p, int *rerror) { /* Wait until latency data is available again */ pa_threaded_mainloop_wait(p->mainloop); } - + pa_threaded_mainloop_unlock(p->mainloop); return negative ? 0 : t; diff --git a/src/pulse/simple.h b/src/pulse/simple.h index 0438d319..a97875f9 100644 --- a/src/pulse/simple.h +++ b/src/pulse/simple.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulse/stream.c b/src/pulse/stream.c index 180cd096..009eb3cf 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -43,7 +43,7 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map) { pa_stream *s; int i; - + assert(c); PA_CHECK_VALIDITY_RETURN_NULL(c, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID); @@ -76,7 +76,7 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->channel_map = *map; else pa_channel_map_init_auto(&s->channel_map, ss->channels, PA_CHANNEL_MAP_DEFAULT); - + s->channel = 0; s->channel_valid = 0; s->syncid = c->csyncid++; @@ -99,11 +99,11 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * for (i = 0; i < PA_MAX_WRITE_INDEX_CORRECTIONS; i++) s->write_index_corrections[i].valid = 0; s->current_write_index_correction = 0; - + s->corked = 0; s->cached_time_valid = 0; - + s->auto_timing_update_event = NULL; s->auto_timing_update_requested = 0; @@ -143,7 +143,7 @@ void pa_stream_unref(pa_stream *s) { pa_stream* pa_stream_ref(pa_stream *s) { assert(s); assert(s->ref >= 1); - + s->ref++; return s; } @@ -151,14 +151,14 @@ pa_stream* pa_stream_ref(pa_stream *s) { pa_stream_state_t pa_stream_get_state(pa_stream *s) { assert(s); assert(s->ref >= 1); - + return s->state; } pa_context* pa_stream_get_context(pa_stream *s) { assert(s); assert(s->ref >= 1); - + return s->context; } @@ -167,17 +167,17 @@ uint32_t pa_stream_get_index(pa_stream *s) { assert(s->ref >= 1); PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX); - + return s->device_index; } - + void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { assert(s); assert(s->ref >= 1); if (s->state == st) return; - + pa_stream_ref(s); s->state = st; @@ -192,24 +192,24 @@ void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { /* Unref all operatio object that point to us */ for (o = s->context->operations; o; o = n) { n = o->next; - + if (o->stream == s) pa_operation_cancel(o); } - + /* Drop all outstanding replies for this stream */ if (s->context->pdispatch) pa_pdispatch_unregister_reply(s->context->pdispatch, s); if (s->channel_valid) pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - + PA_LLIST_REMOVE(pa_stream, s->context->streams, s); pa_stream_unref(s); s->channel = 0; s->channel_valid = 0; - + s->context = NULL; } @@ -220,20 +220,20 @@ void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED pa_context *c = userdata; pa_stream *s; uint32_t channel; - + assert(pd); assert(command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED); assert(t); assert(c); pa_context_ref(c); - + if (pa_tagstruct_getu32(t, &channel) < 0 || !pa_tagstruct_eof(t)) { pa_context_fail(c, PA_ERR_PROTOCOL); goto finish; } - + if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) goto finish; @@ -248,27 +248,27 @@ void pa_command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32 pa_stream *s; pa_context *c = userdata; uint32_t bytes, channel; - + assert(pd); assert(command == PA_COMMAND_REQUEST); assert(t); assert(c); pa_context_ref(c); - + if (pa_tagstruct_getu32(t, &channel) < 0 || pa_tagstruct_getu32(t, &bytes) < 0 || !pa_tagstruct_eof(t)) { pa_context_fail(c, PA_ERR_PROTOCOL); goto finish; } - + if (!(s = pa_dynarray_get(c->playback_streams, channel))) goto finish; if (s->state == PA_STREAM_READY) { s->requested_bytes += bytes; - + if (s->requested_bytes > 0 && s->write_callback) s->write_callback(s, s->requested_bytes, s->write_userdata); } @@ -288,13 +288,13 @@ void pa_command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, PA_GCC assert(c); pa_context_ref(c); - + if (pa_tagstruct_getu32(t, &channel) < 0 || !pa_tagstruct_eof(t)) { pa_context_fail(c, PA_ERR_PROTOCOL); goto finish; } - + if (!(s = pa_dynarray_get(c->playback_streams, channel))) goto finish; @@ -319,11 +319,11 @@ static void request_auto_timing_update(pa_stream *s, int force) { if (!(s->flags & PA_STREAM_AUTO_TIMING_UPDATE)) return; - + if (s->state == PA_STREAM_READY && (force || !s->auto_timing_update_requested)) { pa_operation *o; - + /* pa_log("automatically requesting new timing data"); */ if ((o = pa_stream_update_timing_info(s, NULL, NULL))) { @@ -341,32 +341,32 @@ static void invalidate_indexes(pa_stream *s, int r, int w) { assert(s); /* pa_log("invalidate r:%u w:%u tag:%u", r, w, s->context->ctag); */ - + if (s->state != PA_STREAM_READY) return; if (w) { s->write_index_not_before = s->context->ctag; - + if (s->timing_info_valid) s->timing_info.write_index_corrupt = 1; - + /* pa_log("write_index invalidated"); */ } - + if (r) { s->read_index_not_before = s->context->ctag; - + if (s->timing_info_valid) s->timing_info.read_index_corrupt = 1; - + /* pa_log("read_index invalidated"); */ } - + if ((s->direction == PA_STREAM_PLAYBACK && r) || (s->direction == PA_STREAM_RECORD && w)) s->cached_time_valid = 0; - + request_auto_timing_update(s, 1); } @@ -382,17 +382,17 @@ static void auto_timing_update_callback(PA_GCC_UNUSED pa_mainloop_api *m, PA_GCC void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_stream *s = userdata; - + assert(pd); assert(s); assert(s->state == PA_STREAM_CREATING); - + pa_stream_ref(s); - + if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(s->context, command, t) < 0) goto finish; - + pa_stream_set_state(s, PA_STREAM_FAILED); goto finish; } @@ -429,9 +429,9 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED if (s->direction == PA_STREAM_RECORD) { assert(!s->record_memblockq); - + s->record_memblockq = pa_memblockq_new( - 0, + 0, s->buffer_attr.maxlength, 0, pa_frame_size(&s->sample_spec), @@ -444,7 +444,7 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); pa_stream_set_state(s, PA_STREAM_READY); - + if (s->direction != PA_STREAM_UPLOAD && s->flags & PA_STREAM_AUTO_TIMING_UPDATE) { struct timeval tv; @@ -473,13 +473,13 @@ static int create_stream( pa_stream_flags_t flags, const pa_cvolume *volume, pa_stream *sync_stream) { - + pa_tagstruct *t; uint32_t tag; - + assert(s); assert(s->ref >= 1); - + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, !(flags & ~((direction != PA_STREAM_UPLOAD ? PA_STREAM_START_CORKED| @@ -493,10 +493,10 @@ static int create_stream( s->direction = direction; s->flags = flags; - + if (sync_stream) s->syncid = sync_stream->syncid; - + if (attr) s->buffer_attr = *attr; else { @@ -515,7 +515,7 @@ static int create_stream( s->context, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM, &tag); - + pa_tagstruct_put( t, PA_TAG_STRING, s->name, @@ -526,7 +526,7 @@ static int create_stream( PA_TAG_U32, s->buffer_attr.maxlength, PA_TAG_BOOLEAN, !!(flags & PA_STREAM_START_CORKED), PA_TAG_INVALID); - + if (s->direction == PA_STREAM_PLAYBACK) { pa_cvolume cv; @@ -540,7 +540,7 @@ static int create_stream( if (!volume) volume = pa_cvolume_reset(&cv, s->sample_spec.channels); - + pa_tagstruct_put_cvolume(t, volume); } else pa_tagstruct_putu32(t, s->buffer_attr.fragsize); @@ -549,7 +549,7 @@ static int create_stream( pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL); pa_stream_set_state(s, PA_STREAM_CREATING); - + pa_stream_unref(s); return 0; } @@ -561,10 +561,10 @@ int pa_stream_connect_playback( pa_stream_flags_t flags, pa_cvolume *volume, pa_stream *sync_stream) { - + assert(s); assert(s->ref >= 1); - + return create_stream(PA_STREAM_PLAYBACK, s, dev, attr, flags, volume, sync_stream); } @@ -573,7 +573,7 @@ int pa_stream_connect_record( const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags) { - + assert(s); assert(s->ref >= 1); @@ -587,9 +587,9 @@ int pa_stream_write( void (*free_cb)(void *p), int64_t offset, pa_seek_mode_t seek) { - + pa_memchunk chunk; - + assert(s); assert(s->ref >= 1); assert(data); @@ -602,29 +602,29 @@ int pa_stream_write( if (length <= 0) return 0; - if (free_cb) + if (free_cb) chunk.memblock = pa_memblock_new_user(s->context->mempool, (void*) data, length, free_cb, 1); else { chunk.memblock = pa_memblock_new(s->context->mempool, length); memcpy(chunk.memblock->data, data, length); } - + chunk.index = 0; chunk.length = length; pa_pstream_send_memblock(s->context->pstream, s->channel, offset, seek, &chunk); pa_memblock_unref(chunk.memblock); - + if (length < s->requested_bytes) s->requested_bytes -= length; else s->requested_bytes = 0; if (s->direction == PA_STREAM_PLAYBACK) { - + /* Update latency request correction */ if (s->write_index_corrections[s->current_write_index_correction].valid) { - + if (seek == PA_SEEK_ABSOLUTE) { s->write_index_corrections[s->current_write_index_correction].corrupt = 0; s->write_index_corrections[s->current_write_index_correction].absolute = 1; @@ -635,10 +635,10 @@ int pa_stream_write( } else s->write_index_corrections[s->current_write_index_correction].corrupt = 1; } - + /* Update the write index in the already available latency data */ if (s->timing_info_valid) { - + if (seek == PA_SEEK_ABSOLUTE) { s->timing_info.write_index_corrupt = 0; s->timing_info.write_index = offset + length; @@ -652,7 +652,7 @@ int pa_stream_write( if (!s->timing_info_valid || s->timing_info.write_index_corrupt) request_auto_timing_update(s, 1); } - + return 0; } @@ -664,7 +664,7 @@ int pa_stream_peek(pa_stream *s, const void **data, size_t *length) { PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE); - + if (!s->peek_memchunk.memblock) { if (pa_memblockq_peek(s->record_memblockq, &s->peek_memchunk) < 0) { @@ -686,13 +686,13 @@ int pa_stream_drop(pa_stream *s) { PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, s->peek_memchunk.memblock, PA_ERR_BADSTATE); - + pa_memblockq_drop(s->record_memblockq, &s->peek_memchunk, s->peek_memchunk.length); /* Fix the simulated local read index */ if (s->timing_info_valid && !s->timing_info.read_index_corrupt) s->timing_info.read_index += s->peek_memchunk.length; - + pa_memblock_unref(s->peek_memchunk.memblock); s->peek_memchunk.length = 0; s->peek_memchunk.index = 0; @@ -707,7 +707,7 @@ size_t pa_stream_writable_size(pa_stream *s) { PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (size_t) -1); PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_RECORD, PA_ERR_BADSTATE, (size_t) -1); - + return s->requested_bytes; } @@ -725,7 +725,7 @@ pa_operation * pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *us pa_operation *o; pa_tagstruct *t; uint32_t tag; - + assert(s); assert(s->ref >= 1); @@ -746,7 +746,7 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, pa_operation *o = userdata; struct timeval local, remote, now; pa_timing_info *i; - + assert(pd); assert(o); @@ -756,7 +756,7 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, i = &o->stream->timing_info; /* pa_log("pre corrupt w:%u r:%u\n", !o->stream->timing_info_valid || i->write_index_corrupt,!o->stream->timing_info_valid || i->read_index_corrupt); */ - + o->stream->timing_info_valid = 0; i->write_index_corrupt = 0; i->read_index_corrupt = 0; @@ -777,21 +777,21 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, !pa_tagstruct_eof(t)) { pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; - + } else { o->stream->timing_info_valid = 1; pa_gettimeofday(&now); - + /* Calculcate timestamps */ if (pa_timeval_cmp(&local, &remote) <= 0 && pa_timeval_cmp(&remote, &now) <= 0) { /* local and remote seem to have synchronized clocks */ - + if (o->stream->direction == PA_STREAM_PLAYBACK) i->transport_usec = pa_timeval_diff(&remote, &local); else i->transport_usec = pa_timeval_diff(&now, &remote); - + i->synchronized_clocks = 1; i->timestamp = remote; } else { @@ -816,7 +816,7 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, uint32_t ctag = tag; /* Go through the saved correction values and add up the total correction.*/ - + for (n = 0, j = o->stream->current_write_index_correction+1; n < PA_MAX_WRITE_INDEX_CORRECTIONS; n++, j = (j + 1) % PA_MAX_WRITE_INDEX_CORRECTIONS) { @@ -851,21 +851,21 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, if (!i->read_index_corrupt) i->read_index -= pa_memblockq_get_length(o->stream->record_memblockq); } - + o->stream->cached_time_valid = 0; } o->stream->auto_timing_update_requested = 0; /* pa_log("post corrupt w:%u r:%u\n", i->write_index_corrupt || !o->stream->timing_info_valid, i->read_index_corrupt || !o->stream->timing_info_valid); */ - + /* Clear old correction entries */ if (o->stream->direction == PA_STREAM_PLAYBACK) { int n; - + for (n = 0; n < PA_MAX_WRITE_INDEX_CORRECTIONS; n++) { if (!o->stream->write_index_corrections[n].valid) continue; - + if (o->stream->write_index_corrections[n].tag <= tag) o->stream->write_index_corrections[n].valid = 0; } @@ -873,12 +873,12 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, if (o->stream->latency_update_callback) o->stream->latency_update_callback(o->stream, o->stream->latency_update_userdata); - + if (o->callback && o->stream && o->stream->state == PA_STREAM_READY) { pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback; cb(o->stream, o->stream->timing_info_valid, o->userdata); } - + finish: pa_operation_done(o); @@ -891,29 +891,29 @@ pa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t pa_tagstruct *t; struct timeval now; int cidx = 0; - + assert(s); assert(s->ref >= 1); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - + if (s->direction == PA_STREAM_PLAYBACK) { /* Find a place to store the write_index correction data for this entry */ cidx = (s->current_write_index_correction + 1) % PA_MAX_WRITE_INDEX_CORRECTIONS; - + /* Check if we could allocate a correction slot. If not, there are too many outstanding queries */ PA_CHECK_VALIDITY_RETURN_NULL(s->context, !s->write_index_corrections[cidx].valid, PA_ERR_INTERNAL); } o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); - + t = pa_tagstruct_command( s->context, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_GET_PLAYBACK_LATENCY : PA_COMMAND_GET_RECORD_LATENCY, &tag); pa_tagstruct_putu32(t, s->channel); pa_tagstruct_put_timeval(t, pa_gettimeofday(&now)); - + pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_timing_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); @@ -926,15 +926,15 @@ pa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t o->stream->write_index_corrections[cidx].value = 0; o->stream->write_index_corrections[cidx].corrupt = 0; } - + /* pa_log("requesting update %u\n", tag); */ - + return o; } void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_stream *s = userdata; - + assert(pd); assert(s); assert(s->ref >= 1); @@ -961,7 +961,7 @@ finish: int pa_stream_disconnect(pa_stream *s) { pa_tagstruct *t; uint32_t tag; - + assert(s); assert(s->ref >= 1); @@ -1010,7 +1010,7 @@ void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void * void pa_stream_set_overflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { assert(s); assert(s->ref >= 1); - + s->overflow_callback = cb; s->overflow_userdata = userdata; } @@ -1018,7 +1018,7 @@ void pa_stream_set_overflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, voi void pa_stream_set_underflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { assert(s); assert(s->ref >= 1); - + s->underflow_callback = cb; s->underflow_userdata = userdata; } @@ -1026,7 +1026,7 @@ void pa_stream_set_underflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, vo void pa_stream_set_latency_update_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { assert(s); assert(s->ref >= 1); - + s->latency_update_callback = cb; s->latency_update_userdata = userdata; } @@ -1034,14 +1034,14 @@ void pa_stream_set_latency_update_callback(pa_stream *s, pa_stream_notify_cb_t c void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; int success = 1; - + assert(pd); assert(o); assert(o->ref >= 1); if (!o->context) goto finish; - + if (command != PA_COMMAND_REPLY) { if (pa_context_handle_error(o->context, command, t) < 0) goto finish; @@ -1066,15 +1066,15 @@ pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, voi pa_operation *o; pa_tagstruct *t; uint32_t tag; - + assert(s); assert(s->ref >= 1); - + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); s->corked = b; - + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_command( @@ -1096,12 +1096,12 @@ static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, pa_tagstruct *t; pa_operation *o; uint32_t tag; - + assert(s); assert(s->ref >= 1); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_command(s->context, command, &tag); @@ -1114,26 +1114,26 @@ static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { pa_operation *o; - + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - + if ((o = stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata))) { if (s->direction == PA_STREAM_PLAYBACK) { if (s->write_index_corrections[s->current_write_index_correction].valid) s->write_index_corrections[s->current_write_index_correction].corrupt = 1; - + if (s->timing_info_valid) s->timing_info.write_index_corrupt = 1; - if (s->buffer_attr.prebuf > 0) + if (s->buffer_attr.prebuf > 0) invalidate_indexes(s, 1, 0); else request_auto_timing_update(s, 1); } else invalidate_indexes(s, 0, 1); } - + return o; } @@ -1151,13 +1151,13 @@ pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *us pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { pa_operation *o; - + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE); if ((o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata))) invalidate_indexes(s, 1, 0); - + return o; } @@ -1165,7 +1165,7 @@ pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_succe pa_operation *o; pa_tagstruct *t; uint32_t tag; - + assert(s); assert(s->ref >= 1); assert(name); @@ -1213,7 +1213,7 @@ int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) { * to us, we assume that the real output time is actually * a little ahead */ usec += s->timing_info.transport_usec; - + /* However, the output device usually maintains a buffer too, hence the real sample currently played is a little back */ @@ -1222,7 +1222,7 @@ int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) { else usec -= s->timing_info.sink_usec; } - + } else if (s->direction == PA_STREAM_RECORD) { /* The last byte written into the server side queue had * this time value associated */ @@ -1231,10 +1231,10 @@ int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) { if (!s->corked) { /* Add transport latency */ usec += s->timing_info.transport_usec; - + /* Add latency of data in device buffer */ usec += s->timing_info.source_usec; - + /* If this is a monitor source, we need to correct the * time by the playback device buffer */ if (s->timing_info.sink_usec >= usec) @@ -1269,18 +1269,18 @@ int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) { if (r_usec) *r_usec = usec; - + return 0; } static pa_usec_t time_counter_diff(pa_stream *s, pa_usec_t a, pa_usec_t b, int *negative) { assert(s); assert(s->ref >= 1); - + if (negative) *negative = 0; - if (a >= b) + if (a >= b) return a-b; else { if (negative && s->direction == PA_STREAM_RECORD) { @@ -1305,7 +1305,7 @@ int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative) { PA_CHECK_VALIDITY(s->context, s->timing_info_valid, PA_ERR_NODATA); PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_PLAYBACK || !s->timing_info.write_index_corrupt, PA_ERR_NODATA); PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_RECORD || !s->timing_info.read_index_corrupt, PA_ERR_NODATA); - + if ((r = pa_stream_get_time(s, &t)) < 0) return r; @@ -1316,7 +1316,7 @@ int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative) { if (cindex < 0) cindex = 0; - + c = pa_bytes_to_usec(cindex, &s->sample_spec); if (s->direction == PA_STREAM_PLAYBACK) diff --git a/src/pulse/stream.h b/src/pulse/stream.h index ad15125a..2ce53458 100644 --- a/src/pulse/stream.h +++ b/src/pulse/stream.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -113,7 +113,7 @@ * read index may be larger than the write index, in which case * silence is played. If the application writes data to indexes lower * than the read index, the data is immediately lost. - * + * * \section transfer_sec Transferring Data * * Once the stream is up, data can start flowing between the client and the @@ -159,13 +159,13 @@ * \li PA_SEEK_ABSOLUTE - seek relative to the beginning of the playback buffer, (i.e. the first that was ever played in the stream) * \li PA_SEEK_RELATIVE_ON_READ - seek relative to the current read index. Use this to write data to the output buffer that should be played as soon as possible * \li PA_SEEK_RELATIVE_END - seek relative to the last byte ever written. - * + * * If an application just wants to append some data to the output * buffer, PA_SEEK_RELATIVE and an offset of 0 should be used. * * After a call to pa_stream_write() the write index will be left at * the position right after the last byte of the written data. - * + * * \section latency_sec Latency * * A major problem with networked audio is the increased latency caused by @@ -217,7 +217,7 @@ * this option with PA_STREAM_AUTO_TIMING_UPDATE, which will enable * you to monitor the current playback time/latency very precisely and * very frequently without requiring a network round trip every time. - * + * * \section flow_sec Overflow and underflow * * Even with the best precautions, buffers will sometime over - or @@ -275,7 +275,7 @@ typedef void (*pa_stream_notify_cb_t)(pa_stream *p, void *userdata); /** Create a new, unconnected stream with the specified name and sample type */ pa_stream* pa_stream_new( - pa_context *c /**< The context to create this stream in */, + pa_context *c /**< The context to create this stream in */, const char *name /**< A name for this stream */, const pa_sample_spec *ss /**< The desired sample format */, const pa_channel_map *map /**< The desired channel map, or NULL for default */); @@ -320,7 +320,7 @@ int pa_stream_disconnect(pa_stream *s); * is not copied. If NULL, the data is copied into an internal * buffer. The client my freely seek around in the output buffer. For * most applications passing 0 and PA_SEEK_RELATIVE as arguments for - * offset and seek should be useful.*/ + * offset and seek should be useful.*/ int pa_stream_write( pa_stream *p /**< The stream to use */, const void *data /**< The data to write */, @@ -333,7 +333,7 @@ int pa_stream_write( * data will point to the actual data and length will contain the size * of the data in bytes (which can be less than a complete framgnet). * Use pa_stream_drop() to actually remove the data from the - * buffer. If no data is available will return a NULL pointer \since 0.8 */ + * buffer. If no data is available will return a NULL pointer \since 0.8 */ int pa_stream_peek( pa_stream *p /**< The stream to use */, const void **data /**< Pointer to pointer that will point to data */, diff --git a/src/pulse/subscribe.c b/src/pulse/subscribe.c index c1d88912..d9abf6f8 100644 --- a/src/pulse/subscribe.c +++ b/src/pulse/subscribe.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -69,7 +69,7 @@ pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_c assert(c->ref >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_command(c, PA_COMMAND_SUBSCRIBE, &tag); @@ -83,7 +83,7 @@ pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_c void pa_context_set_subscribe_callback(pa_context *c, pa_context_subscribe_cb_t cb, void *userdata) { assert(c); assert(c->ref >= 1); - + c->subscribe_callback = cb; c->subscribe_userdata = userdata; } diff --git a/src/pulse/subscribe.h b/src/pulse/subscribe.h index adbea680..35d5a31c 100644 --- a/src/pulse/subscribe.h +++ b/src/pulse/subscribe.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulse/thread-mainloop.c b/src/pulse/thread-mainloop.c index 7e1ccfaa..ad29f5ba 100644 --- a/src/pulse/thread-mainloop.c +++ b/src/pulse/thread-mainloop.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -128,7 +128,7 @@ void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { pa_mutex_free(m->mutex); pa_cond_free(m->cond); pa_cond_free(m->accept_cond); - + pa_xfree(m); } @@ -161,7 +161,7 @@ void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) { void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) { assert(m); - + /* Make sure that this function is not called from the helper thread */ assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); @@ -170,7 +170,7 @@ void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) { void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { assert(m); - + /* Make sure that this function is not called from the helper thread */ assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); @@ -188,7 +188,7 @@ void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept) { void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { assert(m); - + /* Make sure that this function is not called from the helper thread */ assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); @@ -202,7 +202,7 @@ void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) { assert(m); - + /* Make sure that this function is not called from the helper thread */ assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); diff --git a/src/pulse/thread-mainloop.h b/src/pulse/thread-mainloop.h index 44eff5a3..48048b35 100644 --- a/src/pulse/thread-mainloop.h +++ b/src/pulse/thread-mainloop.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -149,7 +149,7 @@ PA_C_DECL_BEGIN * deal with that. * * The functions will not dead lock because the wait function will release - * the lock before waiting and then regrab it once it has been signaled. + * the lock before waiting and then regrab it once it has been signaled. * For those of you familiar with threads, the behaviour is that of a * condition variable. * @@ -229,7 +229,7 @@ PA_C_DECL_BEGIN */ /** \file - * + * * A thread based event loop implementation based on pa_mainloop. The * event loop is run in a helper thread in the background. A few * synchronization primitives are available to access the objects diff --git a/src/pulse/timeval.c b/src/pulse/timeval.c index 11285230..e5a86a63 100644 --- a/src/pulse/timeval.c +++ b/src/pulse/timeval.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -38,7 +38,7 @@ struct timeval *pa_gettimeofday(struct timeval *tv) { #ifdef HAVE_GETTIMEOFDAY assert(tv); - + return gettimeofday(tv, NULL) < 0 ? NULL : tv; #elif defined(OS_IS_WIN32) /* @@ -118,14 +118,14 @@ int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { pa_usec_t pa_timeval_age(const struct timeval *tv) { struct timeval now; assert(tv); - + return pa_timeval_diff(pa_gettimeofday(&now), tv); } struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v) { unsigned long secs; assert(tv); - + secs = (v/1000000); tv->tv_sec += (unsigned long) secs; v -= secs*1000000; diff --git a/src/pulse/timeval.h b/src/pulse/timeval.h index e2dbbadb..c10ec9f6 100644 --- a/src/pulse/timeval.h +++ b/src/pulse/timeval.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulse/utf8.c b/src/pulse/utf8.c index 33fa7214..2708c518 100644 --- a/src/pulse/utf8.c +++ b/src/pulse/utf8.c @@ -130,7 +130,7 @@ ONE_REMAINING: if (o) o++; - + continue; error: diff --git a/src/pulse/utf8.h b/src/pulse/utf8.h index 2eac724d..7225471f 100644 --- a/src/pulse/utf8.h +++ b/src/pulse/utf8.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulse/util.c b/src/pulse/util.c index c13951da..63f54e3b 100644 --- a/src/pulse/util.c +++ b/src/pulse/util.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -79,7 +79,7 @@ char *pa_get_user_name(char *s, size_t l) { if (!(p = getenv("USER")) && !(p = getenv("LOGNAME")) && !(p = getenv("USERNAME"))) { #ifdef HAVE_PWD_H - + #ifdef HAVE_GETPWUID_R if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { #else @@ -90,7 +90,7 @@ char *pa_get_user_name(char *s, size_t l) { snprintf(s, l, "%lu", (unsigned long) getuid()); return s; } - + p = r->pw_name; #elif defined(OS_IS_WIN32) /* HAVE_PWD_H */ @@ -162,26 +162,26 @@ char *pa_get_binary_name(char *s, size_t l) { #if defined(OS_IS_WIN32) { char path[PATH_MAX]; - + if (GetModuleFileName(NULL, path, PATH_MAX)) return pa_strlcpy(s, pa_path_get_filename(path), l); } #endif - + #ifdef HAVE_READLINK { int i; char path[PATH_MAX]; /* This works on Linux only */ - + if ((i = readlink("/proc/self/exe", path, sizeof(path)-1)) >= 0) { path[i] = 0; return pa_strlcpy(s, pa_path_get_filename(path), l); } } - + #endif - + #if defined(HAVE_SYS_PRCTL_H) && defined(PR_GET_NAME) { @@ -192,14 +192,14 @@ char *pa_get_binary_name(char *s, size_t l) { char tcomm[TASK_COMM_LEN+1]; memset(tcomm, 0, sizeof(tcomm)); - + /* This works on Linux only */ if (prctl(PR_GET_NAME, (unsigned long) tcomm, 0, 0, 0) == 0) return pa_strlcpy(s, tcomm, l); - + } #endif - + return NULL; } @@ -214,7 +214,7 @@ const char *pa_path_get_filename(const char *p) { char *pa_get_fqdn(char *s, size_t l) { char hn[256]; -#ifdef HAVE_GETADDRINFO +#ifdef HAVE_GETADDRINFO struct addrinfo *a, hints; #endif @@ -225,7 +225,7 @@ char *pa_get_fqdn(char *s, size_t l) { memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_flags = AI_CANONNAME; - + if (getaddrinfo(hn, NULL, &hints, &a) < 0 || !a || !a->ai_canonname || !*a->ai_canonname) return pa_strlcpy(s, hn, l); diff --git a/src/pulse/util.h b/src/pulse/util.h index 5c03b0a9..0be169fb 100644 --- a/src/pulse/util.h +++ b/src/pulse/util.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulse/volume.c b/src/pulse/volume.c index 530814e0..aa7ddba2 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -36,7 +36,7 @@ int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) { if (a->channels != b->channels) return 0; - + for (i = 0; i < a->channels; i++) if (a->values[i] != b->values[i]) return 0; @@ -46,7 +46,7 @@ int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) { pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) { int i; - + assert(a); assert(channels > 0); assert(channels <= PA_CHANNELS_MAX); @@ -115,7 +115,7 @@ char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) { unsigned channel; int first = 1; char *e; - + assert(s); assert(l > 0); assert(c); @@ -149,7 +149,7 @@ int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) { pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { unsigned i; - + assert(dest); assert(a); assert(b); diff --git a/src/pulse/volume.h b/src/pulse/volume.h index 6c60223a..62d2867a 100644 --- a/src/pulse/volume.h +++ b/src/pulse/volume.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulse/xmalloc.c b/src/pulse/xmalloc.c index 36755166..dda42bdc 100644 --- a/src/pulse/xmalloc.c +++ b/src/pulse/xmalloc.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -60,10 +60,10 @@ void* pa_xmalloc(size_t size) { void *p; assert(size > 0); assert(size < MAX_ALLOC_SIZE); - + if (!(p = malloc(size))) oom(); - + return p; } @@ -71,18 +71,18 @@ void* pa_xmalloc0(size_t size) { void *p; assert(size > 0); assert(size < MAX_ALLOC_SIZE); - + if (!(p = calloc(1, size))) oom(); - + return p; } - + void *pa_xrealloc(void *ptr, size_t size) { void *p; assert(size > 0); assert(size < MAX_ALLOC_SIZE); - + if (!(p = realloc(ptr, size))) oom(); return p; @@ -107,7 +107,7 @@ char *pa_xstrdup(const char *s) { char *pa_xstrndup(const char *s, size_t l) { char *e, *r; - + if (!s) return NULL; diff --git a/src/pulse/xmalloc.h b/src/pulse/xmalloc.h index 126c495c..2fb1c5f0 100644 --- a/src/pulse/xmalloc.h +++ b/src/pulse/xmalloc.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/anotify.c b/src/pulsecore/anotify.c index a61f8442..c89d4a15 100644 --- a/src/pulsecore/anotify.c +++ b/src/pulsecore/anotify.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -48,7 +48,7 @@ struct pa_anotify { static void dispatch_event(pa_anotify *a) { assert(a); assert(a->queue_index < a->n_queued_events); - + a->callback(a->queued_events[a->queue_index++], a->userdata); if (a->queue_index >= a->n_queued_events) { @@ -69,14 +69,14 @@ static void io_callback( int fd, pa_io_event_flags_t events, void *userdata) { - + pa_anotify *a = userdata; ssize_t r; assert(a); assert(events == PA_IO_EVENT_INPUT); assert(a->n_queued_events == 0); - + r = read(fd, a->queued_events, sizeof(a->queued_events)); assert(r > 0); @@ -96,7 +96,7 @@ static void defer_callback(pa_mainloop_api *api, pa_defer_event *e, void *userda pa_anotify *pa_anotify_new(pa_mainloop_api*api, pa_anotify_cb_t cb, void *userdata) { pa_anotify *a; - + assert(api); assert(cb); @@ -106,7 +106,7 @@ pa_anotify *pa_anotify_new(pa_mainloop_api*api, pa_anotify_cb_t cb, void *userda pa_xfree(a); return NULL; } - + a->api = api; a->callback = cb; a->userdata = userdata; @@ -130,7 +130,7 @@ void pa_anotify_free(pa_anotify *a) { close(a->fds[0]); if (a->fds[1] >= 0) close(a->fds[1]); - + pa_xfree(a); } diff --git a/src/pulsecore/anotify.h b/src/pulsecore/anotify.h index 44e942f7..b91e6875 100644 --- a/src/pulsecore/anotify.h +++ b/src/pulsecore/anotify.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/atomic.h b/src/pulsecore/atomic.h index 8d608b5b..e713e7a8 100644 --- a/src/pulsecore/atomic.h +++ b/src/pulsecore/atomic.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/authkey-prop.c b/src/pulsecore/authkey-prop.c index 7eda1e49..f3a81179 100644 --- a/src/pulsecore/authkey-prop.c +++ b/src/pulsecore/authkey-prop.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -37,7 +37,7 @@ struct authkey_data { int pa_authkey_prop_get(pa_core *c, const char *name, void *data, size_t len) { struct authkey_data *a; assert(c && name && data && len > 0); - + if (!(a = pa_property_get(c, name))) return -1; @@ -59,7 +59,7 @@ int pa_authkey_prop_put(pa_core *c, const char *name, const void *data, size_t l memcpy(a+1, data, len); pa_property_set(c, name, a); - + return 0; } diff --git a/src/pulsecore/authkey-prop.h b/src/pulsecore/authkey-prop.h index b1da28be..fb777f85 100644 --- a/src/pulsecore/authkey-prop.h +++ b/src/pulsecore/authkey-prop.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/authkey.c b/src/pulsecore/authkey.c index 87631ca5..8ef53bd8 100644 --- a/src/pulsecore/authkey.c +++ b/src/pulsecore/authkey.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -91,25 +91,25 @@ static int load(const char *fn, void *data, size_t length) { if ((size_t) r != length) { pa_log_debug("got %d bytes from cookie file '%s', expected %d", (int)r, fn, (int)length); - + if (!writable) { pa_log("unable to write cookie to read only file"); goto finish; } - + if (generate(fd, data, length) < 0) goto finish; } ret = 0; - + finish: if (fd >= 0) { - + if (unlock) pa_lock_fd(fd, 0); - + close(fd); } @@ -144,7 +144,7 @@ static const char *normalize_path(const char *fn, char *s, size_t l) { char homedir[PATH_MAX]; if (!pa_get_home_dir(homedir, sizeof(homedir))) return NULL; - + #ifndef OS_IS_WIN32 snprintf(s, l, "%s/%s", homedir, fn); #else @@ -165,7 +165,7 @@ int pa_authkey_load_auto(const char *fn, void *data, size_t length) { if (!(p = normalize_path(fn, path, sizeof(path)))) return -2; - + return pa_authkey_load(p, data, length); } @@ -194,14 +194,14 @@ int pa_authkey_save(const char *fn, const void *data, size_t length) { } ret = 0; - + finish: if (fd >= 0) { - + if (unlock) pa_lock_fd(fd, 0); - + close(fd); } diff --git a/src/pulsecore/authkey.h b/src/pulsecore/authkey.h index cc8a565c..bba0bc73 100644 --- a/src/pulsecore/authkey.h +++ b/src/pulsecore/authkey.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/autoload.c b/src/pulsecore/autoload.c index 60304201..b68eaac7 100644 --- a/src/pulsecore/autoload.c +++ b/src/pulsecore/autoload.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -58,20 +58,20 @@ static void entry_remove_and_free(pa_autoload_entry *e) { static pa_autoload_entry* entry_new(pa_core *c, const char *name) { pa_autoload_entry *e = NULL; assert(c && name); - + if (c->autoload_hashmap && (e = pa_hashmap_get(c->autoload_hashmap, name))) return NULL; - + e = pa_xmalloc(sizeof(pa_autoload_entry)); e->core = c; e->name = pa_xstrdup(name); e->module = e->argument = NULL; e->in_action = 0; - + if (!c->autoload_hashmap) c->autoload_hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); assert(c->autoload_hashmap); - + pa_hashmap_put(c->autoload_hashmap, e->name, e); if (!c->autoload_idxset) @@ -79,24 +79,24 @@ static pa_autoload_entry* entry_new(pa_core *c, const char *name) { pa_idxset_put(c->autoload_idxset, e, &e->index); pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_AUTOLOAD|PA_SUBSCRIPTION_EVENT_NEW, e->index); - + return e; } int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const char*module, const char *argument, uint32_t *idx) { pa_autoload_entry *e = NULL; assert(c && name && module && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); - + if (!(e = entry_new(c, name))) return -1; - + e->module = pa_xstrdup(module); e->argument = pa_xstrdup(argument); e->type = type; if (idx) *idx = e->index; - + return 0; } @@ -139,7 +139,7 @@ void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type_t type) { if ((m = pa_module_load(c, e->module, e->argument))) m->auto_unload = 1; } - + e->in_action = 0; } @@ -154,7 +154,7 @@ void pa_autoload_free(pa_core *c) { pa_hashmap_free(c->autoload_hashmap, free_func, NULL); c->autoload_hashmap = NULL; } - + if (c->autoload_idxset) { pa_idxset_free(c->autoload_idxset, NULL, NULL); c->autoload_idxset = NULL; @@ -164,7 +164,7 @@ void pa_autoload_free(pa_core *c) { const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type_t type) { pa_autoload_entry *e; assert(c && name); - + if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type) return NULL; @@ -174,7 +174,7 @@ const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa const pa_autoload_entry* pa_autoload_get_by_index(pa_core *c, uint32_t idx) { pa_autoload_entry *e; assert(c && idx != PA_IDXSET_INVALID); - + if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, idx))) return NULL; diff --git a/src/pulsecore/autoload.h b/src/pulsecore/autoload.h index 65bdd6da..f410e49c 100644 --- a/src/pulsecore/autoload.h +++ b/src/pulsecore/autoload.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -36,7 +36,7 @@ typedef struct pa_autoload_entry { char *name; pa_namereg_type_t type; /* Type of the autoload entry */ int in_action; /* Currently loaded */ - char *module, *argument; + char *module, *argument; } pa_autoload_entry; /* Add a new autoload entry of the given time, with the speicified diff --git a/src/pulsecore/avahi-wrap.c b/src/pulsecore/avahi-wrap.c index 80256a12..bcda9954 100644 --- a/src/pulsecore/avahi-wrap.c +++ b/src/pulsecore/avahi-wrap.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -58,7 +58,7 @@ static pa_io_event_flags_t translate_io_flags(AvahiWatchEvent e) { static void watch_callback(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) { AvahiWatch *w = userdata; - + assert(a); assert(e); assert(w); @@ -75,7 +75,7 @@ static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event assert(api); assert(fd >= 0); assert(callback); - + p = api->userdata; assert(p); @@ -88,19 +88,19 @@ static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event return w; } - + static void watch_update(AvahiWatch *w, AvahiWatchEvent event) { assert(w); w->avahi_poll->mainloop->io_enable(w->io_event, translate_io_flags(event)); } - + static AvahiWatchEvent watch_get_events(AvahiWatch *w) { assert(w); return w->current_event; } - + static void watch_free(AvahiWatch *w) { assert(w); @@ -117,7 +117,7 @@ struct AvahiTimeout { static void timeout_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata) { AvahiTimeout *t = userdata; - + assert(a); assert(e); assert(t); @@ -131,7 +131,7 @@ static AvahiTimeout* timeout_new(const AvahiPoll *api, const struct timeval *tv, assert(api); assert(callback); - + p = api->userdata; assert(p); @@ -139,12 +139,12 @@ static AvahiTimeout* timeout_new(const AvahiPoll *api, const struct timeval *tv, t->avahi_poll = p; t->callback = callback; t->userdata = userdata; - + t->time_event = tv ? p->mainloop->time_new(p->mainloop, tv, timeout_callback, t) : NULL; return t; } - + static void timeout_update(AvahiTimeout *t, const struct timeval *tv) { assert(t); @@ -157,7 +157,7 @@ static void timeout_update(AvahiTimeout *t, const struct timeval *tv) { t->time_event = NULL; } } - + static void timeout_free(AvahiTimeout *t) { assert(t); @@ -170,9 +170,9 @@ AvahiPoll* pa_avahi_poll_new(pa_mainloop_api *m) { pa_avahi_poll *p; assert(m); - + p = pa_xnew(pa_avahi_poll, 1); - + p->api.userdata = p; p->api.watch_new = watch_new; p->api.watch_update = watch_update; @@ -182,7 +182,7 @@ AvahiPoll* pa_avahi_poll_new(pa_mainloop_api *m) { p->api.timeout_update = timeout_update; p->api.timeout_free = timeout_free; p->mainloop = m; - + return &p->api; } @@ -191,7 +191,7 @@ void pa_avahi_poll_free(AvahiPoll *api) { assert(api); p = api->userdata; assert(p); - + pa_xfree(p); } diff --git a/src/pulsecore/avahi-wrap.h b/src/pulsecore/avahi-wrap.h index d868fed4..bb8f5716 100644 --- a/src/pulsecore/avahi-wrap.h +++ b/src/pulsecore/avahi-wrap.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index ae475c3a..cb438a22 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -172,7 +172,7 @@ static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G assert(c && t && buf); pa_strbuf_puts(buf, "Available commands:\n"); - + for (command = commands; command->name; command++) if (command->help) pa_strbuf_printf(buf, " %-25s %s\n", command->name, command->help); @@ -252,12 +252,12 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G [PA_MEMBLOCK_FIXED] = "FIXED", [PA_MEMBLOCK_IMPORTED] = "IMPORTED", }; - + assert(c); assert(t); stat = pa_mempool_get_stat(c->mempool); - + pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n", (unsigned) AO_load_acquire_read((AO_t*) &stat->n_allocated), pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->allocated_size))); @@ -291,7 +291,7 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G type_table[k], (unsigned) AO_load_acquire_read(&stat->n_allocated_by_type[k]), (unsigned) AO_load_acquire_read(&stat->n_accumulated_by_type[k])); - + return 0; } @@ -318,7 +318,7 @@ static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G 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; @@ -724,14 +724,14 @@ static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *b } pa_autoload_add(c, a, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, b, pa_tokenizer_get(t, 3), NULL); - + return 0; } static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *name; assert(c && t && buf && fail); - + if (!(name = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify a device name\n"); return -1; @@ -742,7 +742,7 @@ static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf return -1; } - return 0; + return 0; } static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { @@ -766,7 +766,7 @@ static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, in assert(t); pa_mempool_vacuum(c->mempool); - + return 0; } @@ -857,7 +857,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G time_t now; void *i; pa_autoload_entry *a; - + assert(c && t); time(&now); @@ -868,7 +868,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now)); #endif - + for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) { if (m->auto_unload) continue; @@ -912,7 +912,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G if (c->autoload_hashmap) { nl = 0; - + i = NULL; while ((a = pa_hashmap_iterate(c->autoload_hashmap, &i, NULL))) { @@ -920,18 +920,18 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G pa_strbuf_puts(buf, "\n"); nl = 1; } - + pa_strbuf_printf(buf, "add-autoload-%s %s %s", a->type == PA_NAMEREG_SINK ? "sink" : "source", a->name, a->module); - + if (a->argument) pa_strbuf_printf(buf, " %s", a->argument); - + pa_strbuf_puts(buf, "\n"); } } nl = 0; - + if ((p = pa_namereg_get_default_sink_name(c))) { if (!nl) { pa_strbuf_puts(buf, "\n"); @@ -955,7 +955,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { const char *cs; - + cs = s+strspn(s, whitespace); if (*cs == '#' || !*cs) @@ -983,10 +983,10 @@ int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int * const struct command*command; int unknown = 1; size_t l; - + l = strcspn(cs, whitespace); - for (command = commands; command->name; command++) + for (command = commands; command->name; command++) if (strlen(command->name) == l && !strncmp(cs, command->name, l)) { int ret; pa_tokenizer *t = pa_tokenizer_new(cs, command->args); @@ -997,7 +997,7 @@ int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int * if (ret < 0 && *fail) return -1; - + break; } @@ -1049,7 +1049,7 @@ int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail) while (*p) { size_t l = strcspn(p, linebreak); char *line = pa_xstrndup(p, l); - + if (pa_cli_command_execute_line(c, line, buf, fail) < 0&& *fail) { pa_xfree(line); return -1; diff --git a/src/pulsecore/cli-command.h b/src/pulsecore/cli-command.h index c56c3ca0..1594f4db 100644 --- a/src/pulsecore/cli-command.h +++ b/src/pulsecore/cli-command.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index 49934c07..ac74a287 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -52,10 +52,10 @@ char *pa_module_list_to_string(pa_core *c) { assert(s); pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_size(c->modules)); - + for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\targument: <%s>\n\tused: %i\n\tauto unload: %s\n", m->index, m->name, m->argument, m->n_used, m->auto_unload ? "yes" : "no"); - + return pa_strbuf_tostring_free(s); } @@ -69,14 +69,14 @@ char *pa_client_list_to_string(pa_core *c) { assert(s); pa_strbuf_printf(s, "%u client(s) logged in.\n", pa_idxset_size(c->clients)); - + for (client = pa_idxset_first(c->clients, &idx); client; client = pa_idxset_next(c->clients, &idx)) { pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\tdriver: <%s>\n", client->index, client->name, client->driver); if (client->owner) pa_strbuf_printf(s, "\towner module: <%u>\n", client->owner->index); } - + return pa_strbuf_tostring_free(s); } @@ -93,7 +93,7 @@ char *pa_sink_list_to_string(pa_core *c) { for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - + pa_strbuf_printf( s, " %c index: %u\n" @@ -118,7 +118,7 @@ char *pa_sink_list_to_string(pa_core *c) { if (sink->description) pa_strbuf_printf(s, "\tdescription: <%s>\n", sink->description); } - + return pa_strbuf_tostring_free(s); } @@ -135,8 +135,8 @@ char *pa_source_list_to_string(pa_core *c) { for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - - + + pa_strbuf_printf( s, " %c index: %u\n" @@ -153,14 +153,14 @@ char *pa_source_list_to_string(pa_core *c) { pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map)); - if (source->monitor_of) + if (source->monitor_of) pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index); if (source->owner) pa_strbuf_printf(s, "\towner module: <%u>\n", source->owner->index); if (source->description) pa_strbuf_printf(s, "\tdescription: <%s>\n", source->description); } - + return pa_strbuf_tostring_free(s); } @@ -183,9 +183,9 @@ char *pa_source_output_list_to_string(pa_core *c) { for (o = pa_idxset_first(c->source_outputs, &idx); o; o = pa_idxset_next(c->source_outputs, &idx)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - + assert(o->source); - + pa_strbuf_printf( s, " index: %u\n" @@ -209,7 +209,7 @@ char *pa_source_output_list_to_string(pa_core *c) { if (o->client) pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", o->client->index, o->client->name); } - + return pa_strbuf_tostring_free(s); } @@ -233,7 +233,7 @@ char *pa_sink_input_list_to_string(pa_core *c) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; assert(i->sink); - + pa_strbuf_printf( s, " index: %u\n" @@ -262,7 +262,7 @@ char *pa_sink_input_list_to_string(pa_core *c) { if (i->client) pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", i->client->index, i->client->name); } - + return pa_strbuf_tostring_free(s); } @@ -282,13 +282,13 @@ char *pa_scache_list_to_string(pa_core *c) { for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) { double l = 0; char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = "n/a", cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX] = "n/a"; - + if (e->memchunk.memblock) { pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec); pa_channel_map_snprint(cm, sizeof(cm), &e->channel_map); l = (double) e->memchunk.length / pa_bytes_per_second(&e->sample_spec); } - + pa_strbuf_printf( s, " name: <%s>\n" @@ -351,9 +351,9 @@ char *pa_full_status_string(pa_core *c) { for (i = 0; i < 8; i++) { char *t = NULL; - + switch (i) { - case 0: + case 0: t = pa_sink_list_to_string(c); break; case 1: @@ -365,7 +365,7 @@ char *pa_full_status_string(pa_core *c) { case 3: t = pa_source_output_list_to_string(c); break; - case 4: + case 4: t = pa_client_list_to_string(c); break; case 5: diff --git a/src/pulsecore/cli-text.h b/src/pulsecore/cli-text.h index cd3acdee..b092fc8b 100644 --- a/src/pulsecore/cli-text.h +++ b/src/pulsecore/cli-text.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/cli.c b/src/pulsecore/cli.c index e3fc2e4c..0820fc8e 100644 --- a/src/pulsecore/cli.c +++ b/src/pulsecore/cli.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -82,12 +82,12 @@ pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m) { c->client->kill = client_kill; c->client->userdata = c; c->client->owner = m; - + pa_ioline_set_callback(c->line, line_callback, c); pa_ioline_puts(c->line, "Welcome to PulseAudio! Use \"help\" for usage information.\n"PROMPT); c->fail = c->kill_requested = c->defer_kill = 0; - + return c; } @@ -103,7 +103,7 @@ static void client_kill(pa_client *client) { pa_cli *c; assert(client && client->userdata); c = client->userdata; - + pa_log_debug("CLI client killed."); if (c->defer_kill) c->kill_requested = 1; @@ -138,7 +138,7 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) { if (c->kill_requested) { if (c->eof_callback) c->eof_callback(c, c->userdata); - } else + } else pa_ioline_puts(line, PROMPT); } diff --git a/src/pulsecore/cli.h b/src/pulsecore/cli.h index 639fa952..5cf0ebd2 100644 --- a/src/pulsecore/cli.h +++ b/src/pulsecore/cli.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/client.c b/src/pulsecore/client.c index c34bf149..55697d2e 100644 --- a/src/pulsecore/client.c +++ b/src/pulsecore/client.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -56,7 +56,7 @@ pa_client *pa_client_new(pa_core *core, const char *driver, const char *name) { pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index); pa_core_check_quit(core); - + return c; } diff --git a/src/pulsecore/client.h b/src/pulsecore/client.h index b28065e5..e632da12 100644 --- a/src/pulsecore/client.h +++ b/src/pulsecore/client.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/conf-parser.c b/src/pulsecore/conf-parser.c index db1e3719..6f55e2de 100644 --- a/src/pulsecore/conf-parser.c +++ b/src/pulsecore/conf-parser.c @@ -42,24 +42,24 @@ /* Run the user supplied parser for an assignment */ static int next_assignment(const char *filename, unsigned line, const pa_config_item *t, const char *lvalue, const char *rvalue, void *userdata) { assert(filename && t && lvalue && rvalue); - + for (; t->parse; t++) if (!strcmp(lvalue, t->lvalue)) return t->parse(filename, line, lvalue, rvalue, t->data, userdata); pa_log("[%s:%u] Unknown lvalue '%s'.", filename, line, lvalue); - + return -1; } /* Returns non-zero when c is contained in s */ static int in_string(char c, const char *s) { assert(s); - + for (; *s; s++) if (*s == c) return 1; - + return 0; } @@ -85,7 +85,7 @@ static int parse_line(const char *filename, unsigned line, const pa_config_item if ((c = strpbrk(b, COMMENTS))) *c = 0; - + if (!*b) return 0; @@ -106,13 +106,13 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void unsigned line = 0; int do_close = !f; assert(filename && t); - + if (!f && !(f = fopen(filename, "r"))) { if (errno == ENOENT) { r = 0; goto finish; } - + pa_log_warn("WARNING: failed to open configuration file '%s': %s", filename, pa_cstrerror(errno)); goto finish; @@ -123,23 +123,23 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void if (!fgets(l, sizeof(l), f)) { if (feof(f)) break; - + pa_log_warn("WARNING: failed to read configuration file '%s': %s", filename, pa_cstrerror(errno)); goto finish; } - + if (parse_line(filename, ++line, t, l, userdata) < 0) goto finish; } - + r = 0; - + finish: if (do_close && f) fclose(f); - + return r; } @@ -152,22 +152,22 @@ int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, pa_log("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); return -1; } - + *i = (int) k; - return 0; + return 0; } int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { int *b = data, k; assert(filename && lvalue && rvalue && data); - + if ((k = pa_parse_boolean(rvalue)) < 0) { pa_log("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue); return -1; } - + *b = k; - + return 0; } diff --git a/src/pulsecore/core-def.h b/src/pulsecore/core-def.h index 718499d1..f849a6f6 100644 --- a/src/pulsecore/core-def.h +++ b/src/pulsecore/core-def.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/core-error.c b/src/pulsecore/core-error.c index 61878c9e..2362068f 100644 --- a/src/pulsecore/core-error.c +++ b/src/pulsecore/core-error.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/core-error.h b/src/pulsecore/core-error.h index 32da8bf2..e4390833 100644 --- a/src/pulsecore/core-error.h +++ b/src/pulsecore/core-error.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/core-scache.c b/src/pulsecore/core-scache.c index e3bf3ca2..26c493ca 100644 --- a/src/pulsecore/core-scache.c +++ b/src/pulsecore/core-scache.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -94,7 +94,7 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { pa_memblock_unref(e->memchunk.memblock); pa_xfree(e->filename); - + assert(e->core == c); pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); @@ -178,7 +178,7 @@ int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint3 if (pa_sound_file_load(c->mempool, filename, &ss, &map, &chunk) < 0) return -1; - + r = pa_scache_add_item(c, name, &ss, &map, &chunk, idx); pa_memblock_unref(chunk.memblock); @@ -202,7 +202,7 @@ int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, e->lazy = 1; e->filename = pa_xstrdup(filename); - + if (!c->scache_auto_unload_event) { struct timeval ntv; pa_gettimeofday(&ntv); @@ -252,7 +252,7 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t pa_scache_entry *e; char *t; pa_cvolume r; - + assert(c); assert(name); assert(sink); @@ -269,7 +269,7 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t if (e->volume.channels > e->sample_spec.channels) e->volume.channels = e->sample_spec.channels; } - + if (!e->memchunk.memblock) return -1; @@ -287,7 +287,7 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t if (e->lazy) time(&e->last_used_time); - + return 0; } @@ -318,7 +318,7 @@ uint32_t pa_scache_total_size(pa_core *c) { if (!c->scache || !pa_idxset_size(c->scache)) return 0; - + for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) if (e->memchunk.memblock) sum += e->memchunk.length; @@ -334,7 +334,7 @@ void pa_scache_unload_unused(pa_core *c) { if (!c->scache || !pa_idxset_size(c->scache)) return; - + time(&now); for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) { @@ -344,7 +344,7 @@ void pa_scache_unload_unused(pa_core *c) { if (e->last_used_time + c->scache_idle_time > now) continue; - + pa_memblock_unref(e->memchunk.memblock); e->memchunk.memblock = NULL; e->memchunk.index = e->memchunk.length = 0; @@ -358,7 +358,7 @@ static void add_file(pa_core *c, const char *pathname) { const char *e; e = pa_path_get_filename(pathname); - + if (stat(pathname, &st) < 0) { pa_log("stat('%s'): %s", pathname, pa_cstrerror(errno)); return; @@ -388,7 +388,7 @@ int pa_scache_add_directory_lazy(pa_core *c, const char *pathname) { for (i = 0; i < p.gl_pathc; i++) add_file(c, p.gl_pathv[i]); - + globfree(&p); #else return -1; diff --git a/src/pulsecore/core-scache.h b/src/pulsecore/core-scache.h index d01aae9b..69baabbc 100644 --- a/src/pulsecore/core-scache.h +++ b/src/pulsecore/core-scache.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -32,14 +32,14 @@ typedef struct pa_scache_entry { pa_core *core; uint32_t index; char *name; - + pa_cvolume volume; pa_sample_spec sample_spec; pa_channel_map channel_map; pa_memchunk memchunk; char *filename; - + int lazy; time_t last_used_time; } pa_scache_entry; diff --git a/src/pulsecore/core-subscribe.c b/src/pulsecore/core-subscribe.c index 4df1d511..5a958b83 100644 --- a/src/pulsecore/core-subscribe.c +++ b/src/pulsecore/core-subscribe.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -65,7 +65,7 @@ static void sched_event(pa_core *c); /* Allocate a new subscription object for the given subscription mask. Use the specified callback function and user data */ pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, pa_subscription_cb_t callback, void *userdata) { pa_subscription *s; - + assert(c); assert(m); assert(callback); @@ -85,7 +85,7 @@ pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, pa_su void pa_subscription_free(pa_subscription*s) { assert(s); assert(!s->dead); - + s->dead = 1; sched_event(s->core); } @@ -104,7 +104,7 @@ static void free_event(pa_subscription_event *s) { if (!s->next) s->core->subscription_event_last = s->prev; - + PA_LLIST_REMOVE(pa_subscription_event, s->core->subscription_event_queue, s); pa_xfree(s); } @@ -112,7 +112,7 @@ static void free_event(pa_subscription_event *s) { /* Free all subscription objects */ void pa_subscription_free_all(pa_core *c) { assert(c); - + while (c->subscriptions) free_subscription(c->subscriptions); @@ -157,7 +157,7 @@ static void dump_event(const char * prefix, pa_subscription_event*e) { static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) { pa_core *c = userdata; pa_subscription *s; - + assert(c->mainloop == m); assert(c); assert(c->subscription_defer_event == de); @@ -170,7 +170,7 @@ static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) { pa_subscription_event *e = c->subscription_event_queue; for (s = c->subscriptions; s; s = s->next) { - + if (!s->dead && pa_subscription_match_flags(s->mask, e->type)) s->callback(c, e->type, e->index, s->userdata); } @@ -182,7 +182,7 @@ static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) { } /* Remove dead subscriptions */ - + s = c->subscriptions; while (s) { pa_subscription *n = s->next; @@ -200,7 +200,7 @@ static void sched_event(pa_core *c) { c->subscription_defer_event = c->mainloop->defer_new(c->mainloop, defer_cb, c); assert(c->subscription_defer_event); } - + c->mainloop->defer_enable(c->subscription_defer_event, 1); } @@ -212,18 +212,18 @@ void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t i /* No need for queuing subscriptions of noone is listening */ if (!c->subscriptions) return; - + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_NEW) { pa_subscription_event *i, *n; - + /* Check for duplicates */ for (i = c->subscription_event_last; i; i = n) { n = i->prev; - + /* not the same object type */ if (((t ^ i->type) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)) continue; - + /* not the same object */ if (i->index != index) continue; @@ -253,7 +253,7 @@ void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t i e->type = t; e->index = index; - PA_LLIST_INSERT_AFTER(pa_subscription_event, c->subscription_event_queue, c->subscription_event_last, e); + PA_LLIST_INSERT_AFTER(pa_subscription_event, c->subscription_event_queue, c->subscription_event_last, e); c->subscription_event_last = e; #ifdef DEBUG diff --git a/src/pulsecore/core-subscribe.h b/src/pulsecore/core-subscribe.h index 6e3b646e..875cf331 100644 --- a/src/pulsecore/core-subscribe.h +++ b/src/pulsecore/core-subscribe.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 5f72b342..b42dc0ca 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -139,7 +139,7 @@ void pa_make_nonblock_fd(int fd) { int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) { struct stat st; int r; - + assert(dir); #ifdef OS_IS_WIN32 @@ -152,7 +152,7 @@ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) { umask(u); } #endif - + if (r < 0 && errno != EEXIST) return -1; @@ -163,18 +163,18 @@ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) { gid = getgid(); chown(dir, uid, gid); #endif - + #ifdef HAVE_CHMOD chmod(dir, m); #endif - + #ifdef HAVE_LSTAT if (lstat(dir, &st) < 0) #else if (stat(dir, &st) < 0) #endif goto fail; - + #ifndef OS_IS_WIN32 if (!S_ISDIR(st.st_mode) || (st.st_uid != uid) || @@ -186,9 +186,9 @@ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) { #else pa_log_warn("secure directory creation not supported on Win32."); #endif - + return 0; - + fail: rmdir(dir); return -1; @@ -214,12 +214,12 @@ int pa_make_secure_parent_dir(const char *fn, mode_t m, uid_t uid, gid_t gid) { if (!(dir = pa_parent_dir(fn))) goto finish; - + if (pa_make_secure_dir(dir, m, uid, gid) < 0) goto finish; ret = 0; - + finish: pa_xfree(dir); return ret; @@ -237,7 +237,7 @@ ssize_t pa_read(int fd, void *buf, size_t count, int *type) { if (!type || *type == 0) { ssize_t r; - + if ((r = recv(fd, buf, count, 0)) >= 0) return r; @@ -251,7 +251,7 @@ ssize_t pa_read(int fd, void *buf, size_t count, int *type) { } #endif - + return read(fd, buf, count); } @@ -263,7 +263,7 @@ ssize_t pa_write(int fd, const void *buf, size_t count, int *type) { if ((r = send(fd, buf, count, MSG_NOSIGNAL)) >= 0) return r; - + #ifdef OS_IS_WIN32 if (WSAGetLastError() != WSAENOTSOCK) { errno = WSAGetLastError(); @@ -286,7 +286,7 @@ ssize_t pa_write(int fd, const void *buf, size_t count, int *type) { ssize_t pa_loop_read(int fd, void*data, size_t size, int *type) { ssize_t ret = 0; int _type; - + assert(fd >= 0); assert(data); assert(size); @@ -304,7 +304,7 @@ ssize_t pa_loop_read(int fd, void*data, size_t size, int *type) { if (r == 0) break; - + ret += r; data = (uint8_t*) data + r; size -= r; @@ -335,7 +335,7 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size, int *type) { if (r == 0) break; - + ret += r; data = (const uint8_t*) data + r; size -= r; @@ -354,8 +354,8 @@ void pa_check_signal_is_blocked(int sig) { /* If POSIX threads are supported use thread-aware * pthread_sigmask() function, to check if the signal is * blocked. Otherwise fall back to sigprocmask() */ - -#ifdef HAVE_PTHREAD + +#ifdef HAVE_PTHREAD if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) { #endif if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) { @@ -370,15 +370,15 @@ void pa_check_signal_is_blocked(int sig) { return; /* Check whether the signal is trapped */ - + if (sigaction(sig, NULL, &sa) < 0) { pa_log("sigaction(): %s", pa_cstrerror(errno)); return; } - + if (sa.sa_handler != SIG_DFL) return; - + pa_log("WARNING: %s is not trapped. This might cause malfunction!", pa_strsignal(sig)); #else /* HAVE_SIGACTION */ pa_log("WARNING: %s might not be trapped. This might cause malfunction!", pa_strsignal(sig)); @@ -390,9 +390,9 @@ void pa_check_signal_is_blocked(int sig) { char *pa_sprintf_malloc(const char *format, ...) { int size = 100; char *c = NULL; - + assert(format); - + for(;;) { int r; va_list ap; @@ -402,12 +402,12 @@ char *pa_sprintf_malloc(const char *format, ...) { va_start(ap, format); r = vsnprintf(c, size, format, ap); va_end(ap); - + if (r > -1 && r < size) return c; if (r > -1) /* glibc 2.1 */ - size = r+1; + size = r+1; else /* glibc 2.0 */ size *= 2; } @@ -418,9 +418,9 @@ char *pa_sprintf_malloc(const char *format, ...) { char *pa_vsprintf_malloc(const char *format, va_list ap) { int size = 100; char *c = NULL; - + assert(format); - + for(;;) { int r; va_list aq; @@ -431,12 +431,12 @@ char *pa_vsprintf_malloc(const char *format, va_list ap) { r = vsnprintf(c, size, format, aq); va_end(aq); - + if (r > -1 && r < size) return c; if (r > -1) /* glibc 2.1 */ - size = r+1; + size = r+1; else /* glibc 2.0 */ size *= 2; } @@ -461,10 +461,10 @@ void pa_raise_priority(void) { #ifdef HAVE_SYS_RESOURCE_H if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) pa_log_warn("setpriority(): %s", pa_cstrerror(errno)); - else - pa_log_info("Successfully gained nice level %i.", NICE_LEVEL); + else + pa_log_info("Successfully gained nice level %i.", NICE_LEVEL); #endif - + #ifdef _POSIX_PRIORITY_SCHEDULING { struct sched_param sp; @@ -473,14 +473,14 @@ void pa_raise_priority(void) { pa_log("sched_getparam(): %s", pa_cstrerror(errno)); return; } - + sp.sched_priority = 1; if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) { pa_log_warn("sched_setscheduler(): %s", pa_cstrerror(errno)); return; } - pa_log_info("Successfully enabled SCHED_FIFO scheduling."); + pa_log_info("Successfully enabled SCHED_FIFO scheduling."); } #endif @@ -488,7 +488,7 @@ void pa_raise_priority(void) { if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError()); else - pa_log_info("Successfully gained high priority class."); + pa_log_info("Successfully gained high priority class."); #endif } @@ -521,19 +521,19 @@ int pa_fd_set_cloexec(int fd, int b) { if ((v = fcntl(fd, F_GETFD, 0)) < 0) return -1; - + v = (v & ~FD_CLOEXEC) | (b ? FD_CLOEXEC : 0); - + if (fcntl(fd, F_SETFD, v) < 0) return -1; -#endif +#endif return 0; } /* Try to parse a boolean string value.*/ int pa_parse_boolean(const char *v) { - + if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on")) return 1; else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off")) @@ -552,7 +552,7 @@ char *pa_split(const char *c, const char *delimiter, const char**state) { if (!*current) return NULL; - + l = strcspn(current, delimiter); *state = current+l; @@ -632,7 +632,7 @@ static int is_group(gid_t gid, const char *name) { } r = strcmp(name, result->gr_name) == 0; - + finish: pa_xfree(data); #else @@ -647,7 +647,7 @@ finish: finish: #endif - + return r; } @@ -658,9 +658,9 @@ int pa_own_uid_in_group(const char *name, gid_t *gid) { int r = -1, i; assert(n > 0); - + gids = pa_xmalloc(sizeof(GETGROUPS_T)*n); - + if ((n = getgroups(n, gids)) < 0) { pa_log("getgroups(): %s", pa_cstrerror(errno)); goto finish; @@ -681,7 +681,7 @@ int pa_own_uid_in_group(const char *name, gid_t *gid) { } r = 0; - + finish: pa_xfree(gids); @@ -695,20 +695,20 @@ int pa_uid_in_group(uid_t uid, const char *name) { struct group grbuf, *gr; char **i; int r = -1; - + g_n = sysconf(_SC_GETGR_R_SIZE_MAX); g_buf = pa_xmalloc(g_n); p_n = sysconf(_SC_GETPW_R_SIZE_MAX); p_buf = pa_xmalloc(p_n); - + if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) goto finish; r = 0; for (i = gr->gr_mem; *i; i++) { struct passwd pwbuf, *pw; - + if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw) continue; @@ -763,7 +763,7 @@ int pa_check_in_group(gid_t g) { int pa_own_uid_in_group(const char *name, gid_t *gid) { return -1; - + } int pa_uid_in_group(uid_t uid, const char *name) { @@ -787,7 +787,7 @@ int pa_lock_fd(int fd, int b) { struct flock flock; /* Try a R/W lock first */ - + flock.l_type = b ? F_WRLCK : F_UNLCK; flock.l_whence = SEEK_SET; flock.l_start = 0; @@ -802,7 +802,7 @@ int pa_lock_fd(int fd, int b) { if (fcntl(fd, F_SETLKW, &flock) >= 0) return 0; } - + pa_log("%slock: %s", !b? "un" : "", pa_cstrerror(errno)); #endif @@ -836,18 +836,18 @@ int pa_lock_lockfile(const char *fn) { for (;;) { struct stat st; - + if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { pa_log("failed to create lock file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } - + if (pa_lock_fd(fd, 1) < 0) { pa_log("failed to lock file '%s'.", fn); goto fail; } - + if (fstat(fd, &st) < 0) { pa_log("failed to fstat() file '%s'.", fn); goto fail; @@ -856,12 +856,12 @@ int pa_lock_lockfile(const char *fn) { /* Check wheter the file has been removed meanwhile. When yes, restart this loop, otherwise, we're done */ if (st.st_nlink >= 1) break; - + if (pa_lock_fd(fd, 0) < 0) { pa_log("failed to unlock file '%s'.", fn); goto fail; } - + if (close(fd) < 0) { pa_log("failed to close file '%s'.", fn); goto fail; @@ -869,7 +869,7 @@ int pa_lock_lockfile(const char *fn) { fd = -1; } - + return fd; fail: @@ -890,7 +890,7 @@ int pa_unlock_lockfile(const char *fn, int fd) { fn, pa_cstrerror(errno)); r = -1; } - + if (pa_lock_fd(fd, 0) < 0) { pa_log_warn("WARNING: failed to unlock file '%s'.", fn); r = -1; @@ -946,20 +946,20 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env if (lfn) { FILE *f; - + #ifdef OS_IS_WIN32 if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) return NULL; fn = buf; #endif - + if ((f = fopen(fn, mode)) || errno != ENOENT) { if (result) *result = pa_xstrdup(fn); pa_xfree(lfn); return f; } - + pa_xfree(lfn); } } @@ -979,10 +979,10 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env if (result) *result = pa_xstrdup(global); - + return fopen(global, mode); } - + /* Format the specified data as a hexademical string */ char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) { size_t i = 0, j = 0; @@ -1025,7 +1025,7 @@ size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) { if ((b = hexc(*(p++))) < 0) return (size_t) -1; - + d[j] = (uint8_t) (b << 4); if (!*p) @@ -1044,10 +1044,10 @@ size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) { /* Returns nonzero when *s starts with *pfx */ int pa_startswith(const char *s, const char *pfx) { size_t l; - + assert(s); assert(pfx); - + l = strlen(pfx); return strlen(s) >= l && strncmp(s, pfx, l) == 0; @@ -1056,10 +1056,10 @@ int pa_startswith(const char *s, const char *pfx) { /* Returns nonzero when *s ends with *sfx */ int pa_endswith(const char *s, const char *sfx) { size_t l1, l2; - + assert(s); assert(sfx); - + l1 = strlen(s); l2 = strlen(sfx); @@ -1081,20 +1081,20 @@ char *pa_runtime_path(const char *fn, char *s, size_t l) { if ((e = getenv("PULSE_RUNTIME_PATH"))) { - if (fn) + if (fn) snprintf(s, l, "%s%c%s", e, PATH_SEP, fn); else snprintf(s, l, "%s", e); - + } else { char u[256]; - - if (fn) + + if (fn) snprintf(s, l, "%s%s%c%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn); else snprintf(s, l, "%s%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u))); } - + #ifdef OS_IS_WIN32 { @@ -1119,7 +1119,7 @@ int pa_atoi(const char *s, int32_t *ret_i) { return -1; *ret_i = (int32_t) l; - + return 0; } @@ -1135,6 +1135,6 @@ int pa_atou(const char *s, uint32_t *ret_u) { return -1; *ret_u = (uint32_t) l; - + return 0; } diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index ba325968..b2608edd 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index 63ee60ca..b19b1974 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -116,7 +116,7 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) { pa_property_init(c); pa_random(&c->cookie, sizeof(c->cookie)); - + #ifdef SIGPIPE pa_check_signal_is_blocked(SIGPIPE); #endif @@ -131,16 +131,16 @@ void pa_core_free(pa_core *c) { assert(pa_idxset_isempty(c->clients)); pa_idxset_free(c->clients, NULL, NULL); - + assert(pa_idxset_isempty(c->sinks)); pa_idxset_free(c->sinks, NULL, NULL); assert(pa_idxset_isempty(c->sources)); pa_idxset_free(c->sources, NULL, NULL); - + assert(pa_idxset_isempty(c->source_outputs)); pa_idxset_free(c->source_outputs, NULL, NULL); - + assert(pa_idxset_isempty(c->sink_inputs)); pa_idxset_free(c->sink_inputs, NULL, NULL); @@ -163,8 +163,8 @@ void pa_core_free(pa_core *c) { pa_hook_free(&c->hook_sink_disconnect); pa_hook_free(&c->hook_source_output_new); pa_hook_free(&c->hook_source_disconnect); - - pa_xfree(c); + + pa_xfree(c); } static void quit_callback(pa_mainloop_api*m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index 3a34d297..c1c6a19c 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -46,7 +46,7 @@ struct pa_core { /* A random value which may be used to identify this instance of * PulseAudio. Not cryptographically secure in any way. */ uint32_t cookie; - + pa_mainloop_api *mainloop; /* idxset of all kinds of entities */ diff --git a/src/pulsecore/creds.h b/src/pulsecore/creds.h index d92ce598..5ad880a0 100644 --- a/src/pulsecore/creds.h +++ b/src/pulsecore/creds.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/dynarray.c b/src/pulsecore/dynarray.c index cd1fcb0f..91a9d5e1 100644 --- a/src/pulsecore/dynarray.c +++ b/src/pulsecore/dynarray.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/dynarray.h b/src/pulsecore/dynarray.h index 4ddb526c..216d8766 100644 --- a/src/pulsecore/dynarray.h +++ b/src/pulsecore/dynarray.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/endianmacros.h b/src/pulsecore/endianmacros.h index 65db3feb..c0193014 100644 --- a/src/pulsecore/endianmacros.h +++ b/src/pulsecore/endianmacros.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/esound.h b/src/pulsecore/esound.h index 9d44f65c..0ea201b6 100644 --- a/src/pulsecore/esound.h +++ b/src/pulsecore/esound.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/flist.c b/src/pulsecore/flist.c index cfeeac22..5091bfd1 100644 --- a/src/pulsecore/flist.c +++ b/src/pulsecore/flist.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -111,12 +111,12 @@ pa_flist *pa_flist_new(unsigned size) { size = FLIST_SIZE; assert(is_power_of_two(size)); - + l = pa_xnew(pa_flist, 1); l->size = size; l->cells = pa_xnew0(struct cell, size); - + pa_atomic_store(&l->read_idx, 0); pa_atomic_store(&l->write_idx, 0); pa_atomic_store(&l->length, 0); @@ -133,10 +133,10 @@ void pa_flist_free(pa_flist *l, pa_free_cb_t free_cb) { if (free_cb) { int len, idx; - + idx = reduce(l, pa_atomic_load(&l->read_idx)); len = pa_atomic_load(&l->length); - + for (; len > 0; len--) { if (pa_atomic_load(&l->cells[idx].state) == STATE_USED) @@ -152,7 +152,7 @@ void pa_flist_free(pa_flist *l, pa_free_cb_t free_cb) { int pa_flist_push(pa_flist*l, void *p) { int idx, len, n; - + assert(l); assert(p); @@ -183,13 +183,13 @@ int pa_flist_push(pa_flist*l, void *p) { if (len > N_EXTRA_SCAN) pa_log("WARNING: Didn't find free cell after %u iterations.", len); #endif - + return -1; } void* pa_flist_pop(pa_flist*l) { int idx, len, n; - + assert(l); n = len = pa_atomic_load(&l->length) + N_EXTRA_SCAN; @@ -221,6 +221,6 @@ void* pa_flist_pop(pa_flist*l) { if (len > N_EXTRA_SCAN) pa_log("WARNING: Didn't find used cell after %u iterations.", len); #endif - + return NULL; } diff --git a/src/pulsecore/flist.h b/src/pulsecore/flist.h index 57c9598b..9871f32d 100644 --- a/src/pulsecore/flist.h +++ b/src/pulsecore/flist.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/g711.h b/src/pulsecore/g711.h index 97cedf81..b5c9e6a2 100644 --- a/src/pulsecore/g711.h +++ b/src/pulsecore/g711.h @@ -33,7 +33,7 @@ extern int16_t _st_ulaw2linear16[256]; #define st_14linear2ulaw(sw) (_st_14linear2ulaw[(sw + 0x2000)]) #define st_ulaw2linear16(uc) (_st_ulaw2linear16[uc]) #else -unsigned char st_14linear2ulaw(int16_t pcm_val); +unsigned char st_14linear2ulaw(int16_t pcm_val); int16_t st_ulaw2linear16(unsigned char); #endif diff --git a/src/pulsecore/gccmacro.h b/src/pulsecore/gccmacro.h index 8825700a..87f7eece 100644 --- a/src/pulsecore/gccmacro.h +++ b/src/pulsecore/gccmacro.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/hashmap.c b/src/pulsecore/hashmap.c index 81a160a6..809eaeec 100644 --- a/src/pulsecore/hashmap.c +++ b/src/pulsecore/hashmap.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -47,7 +47,7 @@ struct pa_hashmap { unsigned size; struct hashmap_entry **data; struct hashmap_entry *first_entry; - + unsigned n_entries; pa_hash_func_t hash_func; pa_compare_func_t compare_func; @@ -55,14 +55,14 @@ struct pa_hashmap { pa_hashmap *pa_hashmap_new(pa_hash_func_t hash_func, pa_compare_func_t compare_func) { pa_hashmap *h; - + h = pa_xnew(pa_hashmap, 1); h->data = pa_xnew0(struct hashmap_entry*, h->size = BUCKETS); h->first_entry = NULL; h->n_entries = 0; h->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; h->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; - + return h; } @@ -98,7 +98,7 @@ void pa_hashmap_free(pa_hashmap*h, void (*free_func)(void *p, void *userdata), v free_func(h->first_entry->value, userdata); remove(h, h->first_entry); } - + pa_xfree(h->data); pa_xfree(h); } @@ -124,24 +124,24 @@ int pa_hashmap_put(pa_hashmap *h, const void *key, void *value) { if ((e = get(h, hash, key))) return -1; - + e = pa_xnew(struct hashmap_entry, 1); e->hash = hash; e->key = key; e->value = value; - + e->previous = NULL; e->next = h->first_entry; if (h->first_entry) h->first_entry->previous = e; h->first_entry = e; - + e->bucket_previous = NULL; e->bucket_next = h->data[hash]; if (h->data[hash]) h->data[hash]->bucket_previous = e; h->data[hash] = e; - + h->n_entries ++; return 0; } @@ -164,7 +164,7 @@ void* pa_hashmap_remove(pa_hashmap *h, const void *key) { struct hashmap_entry *e; unsigned hash; void *data; - + assert(h); hash = h->hash_func(key) % h->size; @@ -185,7 +185,7 @@ void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void **key) { assert(h); assert(state); - if (!*state) + if (!*state) *state = h->first_entry; else *state = ((struct hashmap_entry*) *state)->next; @@ -198,13 +198,13 @@ void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void **key) { if (key) *key = ((struct hashmap_entry*) *state)->key; - + return ((struct hashmap_entry*) *state)->value; } void* pa_hashmap_steal_first(pa_hashmap *h) { void *data; - + assert(h); if (!h->first_entry) diff --git a/src/pulsecore/hashmap.h b/src/pulsecore/hashmap.h index b8a358ec..18e41cf3 100644 --- a/src/pulsecore/hashmap.h +++ b/src/pulsecore/hashmap.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/hook-list.c b/src/pulsecore/hook-list.c index 91c2598b..40f6b435 100644 --- a/src/pulsecore/hook-list.c +++ b/src/pulsecore/hook-list.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -36,9 +36,9 @@ static void slot_free(pa_hook *hook, pa_hook_slot *slot) { if (hook->last == slot) hook->last = slot->prev; - + PA_LLIST_REMOVE(pa_hook_slot, hook->slots, slot); - + pa_xfree(slot); } @@ -48,13 +48,13 @@ void pa_hook_free(pa_hook *hook) { while (hook->slots) slot_free(hook, hook->slots); - + pa_hook_init(hook, NULL); } pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t cb, void *data) { pa_hook_slot *slot; - + assert(cb); slot = pa_xnew(pa_hook_slot, 1); @@ -62,17 +62,17 @@ pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t cb, void *data) { slot->dead = 0; slot->callback = cb; slot->data = data; - + PA_LLIST_INSERT_AFTER(pa_hook_slot, hook->slots, hook->last, slot); hook->last = slot; - + return slot; } void pa_hook_slot_free(pa_hook_slot *slot) { assert(slot); assert(!slot->dead); - + if (slot->hook->firing > 0) { slot->dead = 1; slot->hook->n_dead++; @@ -83,7 +83,7 @@ void pa_hook_slot_free(pa_hook_slot *slot) { pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data) { pa_hook_slot *slot, *next; pa_hook_result_t result = PA_HOOK_OK; - + assert(hook); hook->firing ++; @@ -91,16 +91,16 @@ pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data) { for (slot = hook->slots; slot; slot = slot->next) { if (slot->dead) continue; - + if ((result = slot->callback(hook->data, data, slot->data)) != PA_HOOK_OK) break; } - + hook->firing --; - + for (slot = hook->slots; hook->n_dead > 0 && slot; slot = next) { next = slot->next; - + if (slot->dead) { slot_free(hook, slot); hook->n_dead--; diff --git a/src/pulsecore/hook-list.h b/src/pulsecore/hook-list.h index 67e5d1ae..9a219a90 100644 --- a/src/pulsecore/hook-list.h +++ b/src/pulsecore/hook-list.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/idxset.c b/src/pulsecore/idxset.c index ee0137a3..dce51e21 100644 --- a/src/pulsecore/idxset.c +++ b/src/pulsecore/idxset.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -44,7 +44,7 @@ typedef struct idxset_entry { struct pa_idxset { pa_hash_func_t hash_func; pa_compare_func_t compare_func; - + unsigned hash_table_size, n_entries; idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail; uint32_t index, start_index, array_size; @@ -53,7 +53,7 @@ struct pa_idxset { unsigned pa_idxset_string_hash_func(const void *p) { unsigned hash = 0; const char *c; - + for (c = p; *c; c++) hash = 31 * hash + *c; @@ -97,7 +97,7 @@ void pa_idxset_free(pa_idxset *s, void (*free_func) (void *p, void *userdata), v while (s->iterate_list_head) { idxset_entry *e = s->iterate_list_head; s->iterate_list_head = s->iterate_list_head->iterate_next; - + if (free_func) free_func(e->data, userdata); pa_xfree(e); @@ -133,12 +133,12 @@ static void extend_array(pa_idxset *s, uint32_t idx) { l = idx - s->start_index - i + 100; n = pa_xnew0(idxset_entry*, l); - + for (j = 0; j < s->array_size-i; j++) n[j] = s->array[i+j]; pa_xfree(s->array); - + s->array = n; s->array_size = l; s->start_index += i; @@ -147,17 +147,17 @@ static void extend_array(pa_idxset *s, uint32_t idx) { static idxset_entry** array_index(pa_idxset*s, uint32_t idx) { if (idx >= s->start_index + s->array_size) return NULL; - + if (idx < s->start_index) return NULL; - + return s->array + idx - s->start_index; } int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) { unsigned h; idxset_entry *e, **a; - + assert(s); assert(p); @@ -168,7 +168,7 @@ int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) { if ((e = hash_scan(s, s->hash_table[h], p))) { if (idx) *idx = e->index; - + return -1; } @@ -201,10 +201,10 @@ int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) { s->iterate_list_head = e; } s->iterate_list_tail = e; - + s->n_entries++; assert(s->n_entries >= 1); - + if (idx) *idx = e->index; @@ -214,7 +214,7 @@ int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) { void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx) { idxset_entry **a; assert(s); - + if (!(a = array_index(s, idx))) return NULL; @@ -228,7 +228,7 @@ void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx) { unsigned h; idxset_entry *e; assert(s && p); - + assert(s->hash_func); h = s->hash_func(p) % s->hash_table_size; @@ -250,13 +250,13 @@ static void remove_entry(pa_idxset *s, idxset_entry *e) { a = array_index(s, e->index); assert(a && *a && *a == e); *a = NULL; - + /* Remove from linked list */ if (e->iterate_next) e->iterate_next->iterate_prev = e->iterate_prev; else s->iterate_list_tail = e->iterate_prev; - + if (e->iterate_prev) e->iterate_prev->iterate_next = e->iterate_next; else @@ -280,7 +280,7 @@ static void remove_entry(pa_idxset *s, idxset_entry *e) { void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx) { idxset_entry **a; void *data; - + assert(s); if (!(a = array_index(s, idx))) @@ -291,15 +291,15 @@ void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx) { data = (*a)->data; remove_entry(s, *a); - - return data; + + return data; } void* pa_idxset_remove_by_data(pa_idxset*s, const void *data, uint32_t *idx) { idxset_entry *e; unsigned h; void *r; - + assert(s->hash_func); h = s->hash_func(data) % s->hash_table_size; @@ -328,7 +328,7 @@ void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx) { if (!e) return NULL; - + *idx = e->index; return e->data; } @@ -351,7 +351,7 @@ void *pa_idxset_next(pa_idxset *s, uint32_t *idx) { if ((a = array_index(s, *idx)) && *a) e = (*a)->iterate_next; - + if (e) { *idx = e->index; return e->data; @@ -380,7 +380,7 @@ int pa_idxset_foreach(pa_idxset*s, int (*func)(void *p, uint32_t idx, int *del, e = n; } - + return 0; } diff --git a/src/pulsecore/idxset.h b/src/pulsecore/idxset.h index 1765e843..0d751e07 100644 --- a/src/pulsecore/idxset.h +++ b/src/pulsecore/idxset.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/inet_ntop.c b/src/pulsecore/inet_ntop.c index 483c3e26..5d7a543e 100644 --- a/src/pulsecore/inet_ntop.c +++ b/src/pulsecore/inet_ntop.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/inet_pton.c b/src/pulsecore/inet_pton.c index 7b6bbc31..42bb5387 100644 --- a/src/pulsecore/inet_pton.c +++ b/src/pulsecore/inet_pton.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c index af732c26..b40f0aa1 100644 --- a/src/pulsecore/iochannel.c +++ b/src/pulsecore/iochannel.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -54,11 +54,11 @@ struct pa_iochannel { pa_iochannel_cb_t callback; void*userdata; - + int readable; int writable; int hungup; - + int no_close; pa_io_event* input_event, *output_event; @@ -70,7 +70,7 @@ static void enable_mainloop_sources(pa_iochannel *io) { if (io->input_event == io->output_event && io->input_event) { pa_io_event_flags_t f = PA_IO_EVENT_NULL; assert(io->input_event); - + if (!io->readable) f |= PA_IO_EVENT_INPUT; if (!io->writable) @@ -88,7 +88,7 @@ static void enable_mainloop_sources(pa_iochannel *io) { static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { pa_iochannel *io = userdata; int changed = 0; - + assert(m); assert(e); assert(fd >= 0); @@ -104,7 +104,7 @@ static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_fla changed = 1; assert(e == io->input_event); } - + if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) { io->writable = 1; changed = 1; @@ -113,7 +113,7 @@ static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_fla if (changed) { enable_mainloop_sources(io); - + if (io->callback) io->callback(io, io->userdata); } @@ -121,7 +121,7 @@ static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_fla pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) { pa_iochannel *io; - + assert(m); assert(ifd >= 0 || ofd >= 0); @@ -165,42 +165,42 @@ void pa_iochannel_free(pa_iochannel*io) { if (io->input_event) io->mainloop->io_free(io->input_event); - + if (io->output_event && (io->output_event != io->input_event)) io->mainloop->io_free(io->output_event); if (!io->no_close) { if (io->ifd >= 0) - + close(io->ifd); if (io->ofd >= 0 && io->ofd != io->ifd) close(io->ofd); } - + pa_xfree(io); } int pa_iochannel_is_readable(pa_iochannel*io) { assert(io); - + return io->readable || io->hungup; } int pa_iochannel_is_writable(pa_iochannel*io) { assert(io); - + return io->writable && !io->hungup; } int pa_iochannel_is_hungup(pa_iochannel*io) { assert(io); - + return io->hungup; } ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) { ssize_t r; - + assert(io); assert(data); assert(l); @@ -217,7 +217,7 @@ ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) { ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) { ssize_t r; - + assert(io); assert(data); assert(io->ifd >= 0); @@ -236,13 +236,13 @@ ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) { int pa_iochannel_creds_supported(pa_iochannel *io) { struct sockaddr_un sa; socklen_t l; - + assert(io); assert(io->ifd >= 0); assert(io->ofd == io->ifd); l = sizeof(sa); - + if (getsockname(io->ifd, (struct sockaddr*) &sa, &l) < 0) return 0; @@ -254,7 +254,7 @@ int pa_iochannel_creds_enable(pa_iochannel *io) { assert(io); assert(io->ifd >= 0); - + if (setsockopt(io->ifd, SOL_SOCKET, SO_PASSCRED, &t, sizeof(t)) < 0) { pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno)); return -1; @@ -270,7 +270,7 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))]; struct ucred *u; struct cmsghdr *cmsg; - + assert(io); assert(data); assert(l); @@ -296,7 +296,7 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l u->uid = getuid(); u->gid = getgid(); } - + memset(&mh, 0, sizeof(mh)); mh.msg_name = NULL; mh.msg_namelen = 0; @@ -319,7 +319,7 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_cr struct msghdr mh; struct iovec iov; uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))]; - + assert(io); assert(data); assert(l); @@ -346,9 +346,9 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_cr struct cmsghdr *cmsg; *creds_valid = 0; - + for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { - + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) { struct ucred u; assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))); @@ -364,7 +364,7 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_cr io->readable = 0; enable_mainloop_sources(io); } - + return r; } @@ -372,14 +372,14 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_cr void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) { assert(io); - + io->callback = _callback; io->userdata = userdata; } void pa_iochannel_set_noclose(pa_iochannel*io, int b) { assert(io); - + io->no_close = b; } @@ -387,25 +387,25 @@ void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) { assert(io); assert(s); assert(l); - + pa_socket_peer_to_string(io->ifd, s, l); } int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) { assert(io); - + return pa_socket_set_rcvbuf(io->ifd, l); } int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) { assert(io); - + return pa_socket_set_sndbuf(io->ofd, l); } pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) { assert(io); - + return io->mainloop; } diff --git a/src/pulsecore/iochannel.h b/src/pulsecore/iochannel.h index 0e6d6d3a..147e7276 100644 --- a/src/pulsecore/iochannel.h +++ b/src/pulsecore/iochannel.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/ioline.c b/src/pulsecore/ioline.c index a3bca22f..2fe5c88d 100644 --- a/src/pulsecore/ioline.c +++ b/src/pulsecore/ioline.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -64,7 +64,7 @@ static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata); pa_ioline* pa_ioline_new(pa_iochannel *io) { pa_ioline *l; assert(io); - + l = pa_xnew(pa_ioline, 1); l->io = io; l->dead = 0; @@ -85,9 +85,9 @@ pa_ioline* pa_ioline_new(pa_iochannel *io) { l->mainloop->defer_enable(l->defer_event, 0); l->defer_close = 0; - + pa_iochannel_set_callback(io, io_callback, l); - + return l; } @@ -126,7 +126,7 @@ void pa_ioline_close(pa_ioline *l) { assert(l->ref >= 1); l->dead = 1; - + if (l->io) { pa_iochannel_free(l->io); l->io = NULL; @@ -143,21 +143,21 @@ void pa_ioline_close(pa_ioline *l) { void pa_ioline_puts(pa_ioline *l, const char *c) { size_t len; - + assert(l); assert(l->ref >= 1); assert(c); if (l->dead) return; - + len = strlen(c); if (len > BUFFER_LIMIT - l->wbuf_valid_length) len = BUFFER_LIMIT - l->wbuf_valid_length; if (len) { assert(l->wbuf_length >= l->wbuf_valid_length); - + /* In case the allocated buffer is too small, enlarge it. */ if (l->wbuf_valid_length + len > l->wbuf_length) { size_t n = l->wbuf_valid_length+len; @@ -170,14 +170,14 @@ void pa_ioline_puts(pa_ioline *l, const char *c) { l->wbuf_length = n; l->wbuf_index = 0; } else if (l->wbuf_index + l->wbuf_valid_length + len > l->wbuf_length) { - + /* In case the allocated buffer fits, but the current index is too far from the start, move it to the front. */ memmove(l->wbuf, l->wbuf+l->wbuf_index, l->wbuf_valid_length); l->wbuf_index = 0; } - + assert(l->wbuf_index + l->wbuf_valid_length + len <= l->wbuf_length); - + /* Append the new string */ memcpy(l->wbuf + l->wbuf_index + l->wbuf_valid_length, c, len); l->wbuf_valid_length += len; @@ -189,7 +189,7 @@ void pa_ioline_puts(pa_ioline *l, const char *c) { void pa_ioline_set_callback(pa_ioline*l, void (*callback)(pa_ioline*io, const char *s, void *userdata), void *userdata) { assert(l); assert(l->ref >= 1); - + l->callback = callback; l->userdata = userdata; } @@ -213,7 +213,7 @@ static void failure(pa_ioline *l, int process_leftover) { l->callback(l, NULL, l->userdata); l->callback = NULL; } - + pa_ioline_close(l); } @@ -223,12 +223,12 @@ static void scan_for_lines(pa_ioline *l, size_t skip) { while (!l->dead && l->rbuf_valid_length > skip) { char *e, *p; size_t m; - + if (!(e = memchr(l->rbuf + l->rbuf_index + skip, '\n', l->rbuf_valid_length - skip))) break; *e = 0; - + p = l->rbuf + l->rbuf_index; m = strlen(p); @@ -260,14 +260,14 @@ static int do_read(pa_ioline *l) { size_t len; len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length; - + /* Check if we have to enlarge the read buffer */ 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) { /* The current buffer is large enough, let's just move the data to the front */ if (l->rbuf_valid_length) @@ -281,14 +281,14 @@ static int do_read(pa_ioline *l) { l->rbuf = new; l->rbuf_length = n; } - + l->rbuf_index = 0; } - + len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length; - + assert(len >= READ_SIZE); - + /* Read some data */ if ((r = pa_iochannel_read(l->io, l->rbuf+l->rbuf_index+l->rbuf_valid_length, len)) <= 0) { if (r < 0) { @@ -296,16 +296,16 @@ static int do_read(pa_ioline *l) { failure(l, 0); } else failure(l, 1); - + return -1; } - + l->rbuf_valid_length += r; - + /* Look if a line has been terminated in the newly read data */ scan_for_lines(l, l->rbuf_valid_length - r); } - + return 0; } @@ -315,21 +315,21 @@ static int do_write(pa_ioline *l) { assert(l && l->ref >= 1); while (!l->dead && pa_iochannel_is_writable(l->io) && l->wbuf_valid_length) { - + if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0) { pa_log("write(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); failure(l, 0); return -1; } - + l->wbuf_index += r; l->wbuf_valid_length -= r; - + /* A shortcut for the next time */ if (l->wbuf_valid_length == 0) l->wbuf_index = 0; } - + return 0; } @@ -341,7 +341,7 @@ static void do_work(pa_ioline *l) { pa_ioline_ref(l); l->mainloop->defer_enable(l->defer_event, 0); - + if (!l->dead) do_read(l); @@ -371,7 +371,7 @@ static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata) void pa_ioline_defer_close(pa_ioline *l) { assert(l); assert(l->ref >= 1); - + l->defer_close = 1; if (!l->wbuf_valid_length) @@ -381,7 +381,7 @@ void pa_ioline_defer_close(pa_ioline *l) { void pa_ioline_printf(pa_ioline *l, const char *format, ...) { char *t; va_list ap; - + assert(l); assert(l->ref >= 1); diff --git a/src/pulsecore/ioline.h b/src/pulsecore/ioline.h index e736e2b3..8d3fb5f8 100644 --- a/src/pulsecore/ioline.h +++ b/src/pulsecore/ioline.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/ipacl.c b/src/pulsecore/ipacl.c index 36159fab..2848b169 100644 --- a/src/pulsecore/ipacl.c +++ b/src/pulsecore/ipacl.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -59,7 +59,7 @@ struct acl_entry { PA_LLIST_FIELDS(struct acl_entry); - int family; + int family; struct in_addr address_ipv4; struct in6_addr address_ipv6; int bits; @@ -75,10 +75,10 @@ pa_ip_acl* pa_ip_acl_new(const char *s) { pa_ip_acl *acl; assert(s); - + acl = pa_xnew(pa_ip_acl, 1); PA_LLIST_HEAD_INIT(struct acl_entry, acl->entries); - + while ((a = pa_split(s, ";", &state))) { char *slash; struct acl_entry e, *n; @@ -97,7 +97,7 @@ pa_ip_acl* pa_ip_acl_new(const char *s) { if (inet_pton(AF_INET, a, &e.address_ipv4) > 0) { e.bits = bits == (uint32_t) -1 ? 32 : (int) bits; - + if (e.bits > 32) { pa_log("number of bits out of range: %i", e.bits); goto fail; @@ -107,7 +107,7 @@ pa_ip_acl* pa_ip_acl_new(const char *s) { if (e.bits < 32 && (uint32_t) (ntohl(e.address_ipv4.s_addr) << e.bits) != 0) pa_log_warn("WARNING: Host part of ACL entry '%s/%u' is not zero!", a, e.bits); - + } else if (inet_pton(AF_INET6, a, &e.address_ipv6) > 0) { e.bits = bits == (uint32_t) -1 ? 128 : (int) bits; @@ -123,7 +123,7 @@ pa_ip_acl* pa_ip_acl_new(const char *s) { for (i = 0, bits = e.bits; i < 16; i++) { - if (bits >= 8) + if (bits >= 8) bits -= 8; else { if ((uint8_t) ((e.address_ipv6.s6_addr[i]) << bits) != 0) { @@ -137,7 +137,7 @@ pa_ip_acl* pa_ip_acl_new(const char *s) { if (t) pa_log_warn("WARNING: Host part of ACL entry '%s/%u' is not zero!", a, e.bits); } - + } else { pa_log("failed to parse address: %s", a); goto fail; @@ -145,16 +145,16 @@ pa_ip_acl* pa_ip_acl_new(const char *s) { n = pa_xmemdup(&e, sizeof(struct acl_entry)); PA_LLIST_PREPEND(struct acl_entry, acl->entries, n); - + pa_xfree(a); } return acl; - + fail: pa_xfree(a); pa_ip_acl_free(acl); - + return NULL; } @@ -166,7 +166,7 @@ void pa_ip_acl_free(pa_ip_acl *acl) { PA_LLIST_REMOVE(struct acl_entry, acl->entries, e); pa_xfree(e); } - + pa_xfree(acl); } @@ -174,7 +174,7 @@ int pa_ip_acl_check(pa_ip_acl *acl, int fd) { struct sockaddr_storage sa; struct acl_entry *e; socklen_t salen; - + assert(acl); assert(fd >= 0); @@ -190,7 +190,7 @@ int pa_ip_acl_check(pa_ip_acl *acl, int fd) { if (sa.ss_family == AF_INET6 && salen != sizeof(struct sockaddr_in6)) return -1; - + for (e = acl->entries; e; e = e->next) { if (e->family != sa.ss_family) @@ -198,7 +198,7 @@ int pa_ip_acl_check(pa_ip_acl *acl, int fd) { if (e->family == AF_INET) { struct sockaddr_in *sai = (struct sockaddr_in*) &sa; - + if (e->bits == 0 || /* this needs special handling because >> takes the right-hand side modulo 32 */ (ntohl(sai->sin_addr.s_addr ^ e->address_ipv4.s_addr) >> (32 - e->bits)) == 0) return 1; @@ -211,7 +211,7 @@ int pa_ip_acl_check(pa_ip_acl *acl, int fd) { if (e->bits == 0) return 1; - + for (i = 0, bits = e->bits; i < 16; i++) { if (bits >= 8) { diff --git a/src/pulsecore/ipacl.h b/src/pulsecore/ipacl.h index 7a4540ce..61bf99b0 100644 --- a/src/pulsecore/ipacl.h +++ b/src/pulsecore/ipacl.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/llist.h b/src/pulsecore/llist.h index 31279431..49d26166 100644 --- a/src/pulsecore/llist.h +++ b/src/pulsecore/llist.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -75,7 +75,7 @@ do { \ assert(_head); \ while ((*_head)->prev) \ *_head = (*_head)->prev; \ -} while (0) +} while (0) #define PA_LLIST_INSERT_AFTER(t,head,a,b) \ do { \ @@ -92,7 +92,7 @@ do { \ _b->prev = _a; \ _a->next = _b; \ } \ -} while (0) - +} while (0) + #endif diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c index ce093221..7ad90383 100644 --- a/src/pulsecore/log.c +++ b/src/pulsecore/log.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -89,16 +89,16 @@ void pa_log_levelv_meta( const char *func, const char *format, va_list ap) { - + const char *e; char *text, *t, *n, *location; - + assert(level < PA_LOG_LEVEL_MAX); assert(format); if ((e = getenv(ENV_LOGLEVEL))) maximal_level = atoi(e); - + if (level > maximal_level) return; @@ -122,13 +122,13 @@ void pa_log_levelv_meta( if (!*t) continue; - + switch (log_target) { case PA_LOG_STDERR: { const char *prefix = "", *suffix = ""; char *local_t; -#ifndef OS_IS_WIN32 +#ifndef OS_IS_WIN32 /* Yes indeed. Useless, but fun! */ if (isatty(STDERR_FILENO)) { if (level <= PA_LOG_ERROR) { @@ -151,8 +151,8 @@ void pa_log_levelv_meta( break; } - -#ifdef HAVE_SYSLOG_H + +#ifdef HAVE_SYSLOG_H case PA_LOG_SYSLOG: { char *local_t; @@ -167,20 +167,20 @@ void pa_log_levelv_meta( } closelog(); - break; + break; } #endif - + case PA_LOG_USER: { char *x; x = pa_sprintf_malloc("%s%s", location, t); user_log_func(level, x); pa_xfree(x); - + break; } - + case PA_LOG_NULL: default: break; @@ -197,7 +197,7 @@ void pa_log_level_meta( int line, const char *func, const char *format, ...) { - + va_list ap; va_start(ap, format); pa_log_levelv_meta(level, file, line, func, format, ap); diff --git a/src/pulsecore/log.h b/src/pulsecore/log.h index bf0e75f5..728c2501 100644 --- a/src/pulsecore/log.h +++ b/src/pulsecore/log.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/mcalign.c b/src/pulsecore/mcalign.c index 9ede610d..baf36784 100644 --- a/src/pulsecore/mcalign.c +++ b/src/pulsecore/mcalign.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -42,11 +42,11 @@ pa_mcalign *pa_mcalign_new(size_t base) { assert(base); m = pa_xnew(pa_mcalign, 1); - + m->base = base; pa_memchunk_reset(&m->leftover); pa_memchunk_reset(&m->current); - + return m; } @@ -58,22 +58,22 @@ void pa_mcalign_free(pa_mcalign *m) { if (m->current.memblock) pa_memblock_unref(m->current.memblock); - + pa_xfree(m); } void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { assert(m); assert(c); - + assert(c->memblock); assert(c->length > 0); assert(!m->current.memblock); - + /* Append to the leftover memory block */ if (m->leftover.memblock) { - + /* Try to merge */ if (m->leftover.memblock == c->memblock && m->leftover.index + m->leftover.length == c->index) { @@ -85,7 +85,7 @@ void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { if (m->leftover.length >= m->base) { m->current = m->leftover; pa_memchunk_reset(&m->leftover); - } + } } else { size_t l; @@ -93,7 +93,7 @@ void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { /* We have to copy */ assert(m->leftover.length < m->base); l = m->base - m->leftover.length; - + if (l > c->length) l = c->length; @@ -115,7 +115,7 @@ void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { } } else { /* Nothing to merge or copy, just store it */ - + if (c->length >= m->base) m->current = *c; else @@ -146,7 +146,7 @@ int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) { m->leftover = m->current; pa_memchunk_reset(&m->current); } - + return 0; } @@ -182,13 +182,13 @@ int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) { } pa_memchunk_reset(&m->current); - + return 0; } /* There's simply nothing */ return -1; - + } size_t pa_mcalign_csize(pa_mcalign *m, size_t l) { @@ -196,9 +196,9 @@ size_t pa_mcalign_csize(pa_mcalign *m, size_t l) { assert(l > 0); assert(!m->current.memblock); - + if (m->leftover.memblock) l += m->leftover.length; - + return (l/m->base)*m->base; } diff --git a/src/pulsecore/mcalign.h b/src/pulsecore/mcalign.h index 94e99e21..751eacd3 100644 --- a/src/pulsecore/mcalign.h +++ b/src/pulsecore/mcalign.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -41,11 +41,11 @@ * for (;;) { * pa_memchunk input; * - * ... fill input ... + * ... fill input ... * * pa_mcalign_push(m, &input); * pa_memblock_unref(input.memblock); - * + * * for (;;) { * pa_memchunk output; * diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 9cfd79b5..73874cf1 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -71,7 +71,7 @@ struct memexport_slot { struct pa_memexport { pa_mempool *pool; - + struct memexport_slot slots[PA_MEMEXPORT_SLOTS_MAX]; PA_LLIST_HEAD(struct memexport_slot, free_slots); PA_LLIST_HEAD(struct memexport_slot, used_slots); @@ -101,7 +101,7 @@ struct pa_mempool { /* A list of free slots that may be reused */ PA_LLIST_HEAD(struct mempool_slot, free_slots); - + pa_mempool_stat stat; }; @@ -132,14 +132,14 @@ static void stat_remove(pa_memblock *b) { assert(AO_load_acquire_read(&b->pool->stat.n_allocated) > 0); assert(AO_load_acquire_read(&b->pool->stat.allocated_size) >= (AO_t) b->length); - + AO_fetch_and_sub1_release_write(&b->pool->stat.n_allocated); AO_fetch_and_add_release_write(&b->pool->stat.allocated_size, (AO_t) (-b->length)); if (b->type == PA_MEMBLOCK_IMPORTED) { assert(AO_load_acquire_read(&b->pool->stat.n_imported) > 0); assert(AO_load_acquire_read(&b->pool->stat.imported_size) >= (AO_t) b->length); - + AO_fetch_and_sub1_release_write(&b->pool->stat.n_imported); AO_fetch_and_add_release_write(&b->pool->stat.imported_size, (AO_t) (-b->length)); } @@ -151,10 +151,10 @@ static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length); pa_memblock *pa_memblock_new(pa_mempool *p, size_t length) { pa_memblock *b; - + assert(p); assert(length > 0); - + if (!(b = pa_memblock_new_pool(p, length))) b = memblock_new_appended(p, length); @@ -231,16 +231,16 @@ pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) { if (!(slot = mempool_allocate_slot(p))) return NULL; - + b = mempool_slot_data(slot); b->type = PA_MEMBLOCK_POOL; b->data = (uint8_t*) b + sizeof(pa_memblock); - + } else if (p->block_size - sizeof(struct mempool_slot) >= length) { if (!(slot = mempool_allocate_slot(p))) return NULL; - + b = pa_xnew(pa_memblock, 1); b->type = PA_MEMBLOCK_POOL_EXTERNAL; b->data = mempool_slot_data(slot); @@ -285,7 +285,7 @@ pa_memblock *pa_memblock_new_user(pa_mempool *p, void *d, size_t length, void (* assert(d); assert(length > 0); assert(free_cb); - + b = pa_xnew(pa_memblock, 1); b->type = PA_MEMBLOCK_USER; b->read_only = read_only; @@ -313,7 +313,7 @@ void pa_memblock_unref(pa_memblock*b) { if (PA_REFCNT_DEC(b) > 0) return; - + stat_remove(b); switch (b->type) { @@ -334,13 +334,13 @@ void pa_memblock_unref(pa_memblock*b) { segment = b->per_type.imported.segment; assert(segment); assert(segment->import); - + pa_hashmap_remove(segment->import->blocks, PA_UINT32_TO_PTR(b->per_type.imported.id)); segment->import->release_cb(segment->import, b->per_type.imported.id, segment->import->userdata); if (-- segment->n_blocks <= 0) segment_detach(segment); - + pa_xfree(b); break; } @@ -351,9 +351,9 @@ void pa_memblock_unref(pa_memblock*b) { slot = mempool_slot_by_ptr(b->pool, b->data); assert(slot); - + PA_LLIST_PREPEND(struct mempool_slot, b->pool->free_slots, slot); - + if (b->type == PA_MEMBLOCK_POOL_EXTERNAL) pa_xfree(b); @@ -377,7 +377,7 @@ static void memblock_make_local(pa_memblock *b) { if ((slot = mempool_allocate_slot(b->pool))) { void *new_data; /* We can move it into a local pool, perfect! */ - + b->type = PA_MEMBLOCK_POOL_EXTERNAL; b->read_only = 0; @@ -412,7 +412,7 @@ void pa_memblock_unref_fixed(pa_memblock *b) { static void memblock_replace_import(pa_memblock *b) { pa_memimport_segment *seg; - + assert(b); assert(b->type == PA_MEMBLOCK_IMPORTED); @@ -453,7 +453,7 @@ pa_mempool* pa_mempool_new(int shared) { if (p->block_size < ps) p->block_size = ps; - + p->n_blocks = PA_MEMPOOL_SLOTS_MAX; assert(p->block_size > sizeof(struct mempool_slot)); @@ -464,7 +464,7 @@ pa_mempool* pa_mempool_new(int shared) { } p->n_init = 0; - + PA_LLIST_HEAD_INIT(pa_memimport, p->imports); PA_LLIST_HEAD_INIT(pa_memexport, p->exports); PA_LLIST_HEAD_INIT(struct mempool_slot, p->free_slots); @@ -485,7 +485,7 @@ void pa_mempool_free(pa_mempool *p) { if (AO_load_acquire_read(&p->stat.n_allocated) > 0) pa_log_warn("WARNING! Memory pool destroyed but not all memory blocks freed!"); - + pa_shm_free(&p->memory); pa_xfree(p); } @@ -498,7 +498,7 @@ const pa_mempool_stat* pa_mempool_get_stat(pa_mempool *p) { void pa_mempool_vacuum(pa_mempool *p) { struct mempool_slot *slot; - + assert(p); for (slot = p->free_slots; slot; slot = slot->next) @@ -512,7 +512,7 @@ int pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id) { return -1; *id = p->memory.id; - + return 0; } @@ -528,14 +528,14 @@ pa_memimport* pa_memimport_new(pa_mempool *p, pa_memimport_release_cb_t cb, void assert(p); assert(cb); - + i = pa_xnew(pa_memimport, 1); i->pool = p; i->segments = pa_hashmap_new(NULL, NULL); i->blocks = pa_hashmap_new(NULL, NULL); i->release_cb = cb; i->userdata = userdata; - + PA_LLIST_PREPEND(pa_memimport, p->imports, i); return i; } @@ -549,7 +549,7 @@ static pa_memimport_segment* segment_attach(pa_memimport *i, uint32_t shm_id) { return NULL; seg = pa_xnew(pa_memimport_segment, 1); - + if (pa_shm_attach_ro(&seg->memory, shm_id) < 0) { pa_xfree(seg); return NULL; @@ -557,7 +557,7 @@ static pa_memimport_segment* segment_attach(pa_memimport *i, uint32_t shm_id) { seg->import = i; seg->n_blocks = 0; - + pa_hashmap_put(i->segments, PA_UINT32_TO_PTR(shm_id), seg); return seg; } @@ -573,7 +573,7 @@ static void segment_detach(pa_memimport_segment *seg) { void pa_memimport_free(pa_memimport *i) { pa_memexport *e; pa_memblock *b; - + assert(i); /* If we've exported this block further we need to revoke that export */ @@ -587,7 +587,7 @@ void pa_memimport_free(pa_memimport *i) { pa_hashmap_free(i->blocks, NULL, NULL); pa_hashmap_free(i->segments, NULL, NULL); - + PA_LLIST_REMOVE(pa_memimport, i->pool->imports, i); pa_xfree(i); } @@ -595,19 +595,19 @@ void pa_memimport_free(pa_memimport *i) { pa_memblock* pa_memimport_get(pa_memimport *i, uint32_t block_id, uint32_t shm_id, size_t offset, size_t size) { pa_memblock *b; pa_memimport_segment *seg; - + assert(i); if (pa_hashmap_size(i->blocks) >= PA_MEMIMPORT_SLOTS_MAX) return NULL; - if (!(seg = pa_hashmap_get(i->segments, PA_UINT32_TO_PTR(shm_id)))) + if (!(seg = pa_hashmap_get(i->segments, PA_UINT32_TO_PTR(shm_id)))) if (!(seg = segment_attach(i, shm_id))) return NULL; if (offset+size > seg->memory.size) return NULL; - + b = pa_xnew(pa_memblock, 1); b->type = PA_MEMBLOCK_IMPORTED; b->read_only = 1; @@ -621,9 +621,9 @@ pa_memblock* pa_memimport_get(pa_memimport *i, uint32_t block_id, uint32_t shm_i pa_hashmap_put(i->blocks, PA_UINT32_TO_PTR(block_id), b); seg->n_blocks++; - + stat_add(b); - + return b; } @@ -633,7 +633,7 @@ int pa_memimport_process_revoke(pa_memimport *i, uint32_t id) { if (!(b = pa_hashmap_get(i->blocks, PA_UINT32_TO_PTR(id)))) return -1; - + memblock_replace_import(b); return 0; } @@ -641,13 +641,13 @@ int pa_memimport_process_revoke(pa_memimport *i, uint32_t id) { /* For sending blocks to other nodes */ pa_memexport* pa_memexport_new(pa_mempool *p, pa_memexport_revoke_cb_t cb, void *userdata) { pa_memexport *e; - + assert(p); assert(cb); if (!p->memory.shared) return NULL; - + e = pa_xnew(pa_memexport, 1); e->pool = p; PA_LLIST_HEAD_INIT(struct memexport_slot, e->free_slots); @@ -655,7 +655,7 @@ pa_memexport* pa_memexport_new(pa_mempool *p, pa_memexport_revoke_cb_t cb, void e->n_init = 0; e->revoke_cb = cb; e->userdata = userdata; - + PA_LLIST_PREPEND(pa_memexport, p->exports, e); return e; } @@ -683,10 +683,10 @@ int pa_memexport_process_release(pa_memexport *e, uint32_t id) { assert(AO_load_acquire_read(&e->pool->stat.n_exported) > 0); assert(AO_load_acquire_read(&e->pool->stat.exported_size) >= (AO_t) e->slots[id].block->length); - + AO_fetch_and_sub1_release_write(&e->pool->stat.n_exported); AO_fetch_and_add_release_write(&e->pool->stat.exported_size, (AO_t) -e->slots[id].block->length); - + pa_memblock_unref(e->slots[id].block); e->slots[id].block = NULL; @@ -704,7 +704,7 @@ static void memexport_revoke_blocks(pa_memexport *e, pa_memimport *i) { for (slot = e->used_slots; slot; slot = next) { uint32_t idx; next = slot->next; - + if (slot->block->type != PA_MEMBLOCK_IMPORTED || slot->block->per_type.imported.segment->import != i) continue; @@ -720,7 +720,7 @@ static pa_memblock *memblock_shared_copy(pa_mempool *p, pa_memblock *b) { assert(p); assert(b); - + if (b->type == PA_MEMBLOCK_IMPORTED || b->type == PA_MEMBLOCK_POOL || b->type == PA_MEMBLOCK_POOL_EXTERNAL) { @@ -738,7 +738,7 @@ static pa_memblock *memblock_shared_copy(pa_mempool *p, pa_memblock *b) { int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32_t *shm_id, size_t *offset, size_t * size) { pa_shm *memory; struct memexport_slot *slot; - + assert(e); assert(b); assert(block_id); @@ -774,10 +774,10 @@ int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32 assert(b->pool); memory = &b->pool->memory; } - + assert(b->data >= memory->ptr); assert((uint8_t*) b->data + b->length <= (uint8_t*) memory->ptr + memory->size); - + *shm_id = memory->id; *offset = (uint8_t*) b->data - (uint8_t*) memory->ptr; *size = b->length; diff --git a/src/pulsecore/memblock.h b/src/pulsecore/memblock.h index d4f2b7aa..eeecf756 100644 --- a/src/pulsecore/memblock.h +++ b/src/pulsecore/memblock.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -37,7 +37,7 @@ typedef enum pa_memblock_type { PA_MEMBLOCK_POOL, /* Memory is part of the memory pool */ PA_MEMBLOCK_POOL_EXTERNAL, /* Data memory is part of the memory pool but the pa_memblock structure itself not */ - PA_MEMBLOCK_APPENDED, /* the data is appended to the memory block */ + PA_MEMBLOCK_APPENDED, /* the data is appended to the memory block */ PA_MEMBLOCK_USER, /* User supplied memory, to be freed with free_cb */ PA_MEMBLOCK_FIXED, /* data is a pointer to fixed memory that needs not to be freed */ PA_MEMBLOCK_IMPORTED, /* Memory is imported from another process via shm */ @@ -66,7 +66,7 @@ struct pa_memblock { struct { void (*free_cb)(void *p); /* If type == PA_MEMBLOCK_USER this points to a function for freeing this memory block */ } user; - + struct { uint32_t id; pa_memimport_segment *segment; diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index e6b73fc5..4a845a53 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -61,12 +61,12 @@ pa_memblockq* pa_memblockq_new( size_t prebuf, size_t minreq, pa_memblock *silence) { - + pa_memblockq* bq; - + assert(base > 0); assert(maxlength >= base); - + bq = pa_xnew(pa_memblockq, 1); bq->blocks = bq->blocks_tail = NULL; bq->n_blocks = 0; @@ -90,20 +90,20 @@ pa_memblockq* pa_memblockq_new( bq->prebuf = bq->maxlength; bq->minreq = (minreq/base)*base; - + if (bq->minreq > bq->tlength - bq->prebuf) bq->minreq = bq->tlength - bq->prebuf; if (!bq->minreq) bq->minreq = 1; - + pa_log_debug("memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", (unsigned long)bq->maxlength, (unsigned long)bq->tlength, (unsigned long)bq->base, (unsigned long)bq->prebuf, (unsigned long)bq->minreq); bq->state = bq->prebuf ? PREBUF : RUNNING; bq->silence = silence ? pa_memblock_ref(silence) : NULL; bq->mcalign = NULL; - + return bq; } @@ -117,7 +117,7 @@ void pa_memblockq_free(pa_memblockq* bq) { if (bq->mcalign) pa_mcalign_free(bq->mcalign); - + pa_xfree(bq); } @@ -126,12 +126,12 @@ static void drop_block(pa_memblockq *bq, struct memblock_list *q) { assert(q); assert(bq->n_blocks >= 1); - + if (q->prev) q->prev->next = q->next; else bq->blocks = q->next; - + if (q->next) q->next->prev = q->prev; else @@ -168,10 +168,10 @@ static int can_push(pa_memblockq *bq, size_t l) { } int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { - + struct memblock_list *q, *n; pa_memchunk chunk; - + assert(bq); assert(uchunk); assert(uchunk->memblock); @@ -185,7 +185,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { return -1; chunk = *uchunk; - + if (bq->read_index > bq->write_index) { /* We currently have a buffer underflow, we need to drop some @@ -203,7 +203,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { return 0; } } - + /* We go from back to front to look for the right place to add * this new entry. Drop data we will overwrite on the way */ @@ -275,29 +275,29 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { assert(bq->write_index + (int64_t)chunk.length > q->index && bq->write_index + (int64_t)chunk.length < q->index + (int64_t)q->chunk.length && bq->write_index < q->index); - + /* The job overwrites the current entry at the end, so let's drop the beginning of this entry */ d = bq->write_index + chunk.length - q->index; q->index += d; q->chunk.index += d; q->chunk.length -= d; - + q = q->prev; } - + } if (q) { assert(bq->write_index >= q->index + (int64_t)q->chunk.length); assert(!q->next || (bq->write_index + (int64_t)chunk.length <= q->next->index)); - + /* Try to merge memory blocks */ - + if (q->chunk.memblock == chunk.memblock && q->chunk.index + (int64_t)q->chunk.length == chunk.index && bq->write_index == q->index + (int64_t)q->chunk.length) { - + q->chunk.length += chunk.length; bq->write_index += chunk.length; return 0; @@ -324,7 +324,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { n->prev->next = n; else bq->blocks = n; - + bq->n_blocks++; return 0; } @@ -347,7 +347,7 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { bq->state = PREBUF; return -1; } - + /* Do we need to spit out silence? */ if (!bq->blocks || bq->blocks->index > bq->read_index) { @@ -362,7 +362,7 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { if (!length || length > chunk->memblock->length) length = chunk->memblock->length; - + chunk->length = length; } else { @@ -370,7 +370,7 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { * the time to sleep */ if (!bq->blocks) return -1; - + chunk->memblock = NULL; chunk->length = length; } @@ -381,7 +381,7 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { /* Ok, let's pass real data to the caller */ assert(bq->blocks->index == bq->read_index); - + *chunk = bq->blocks->chunk; pa_memblock_ref(chunk->memblock); @@ -432,14 +432,14 @@ void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length assert(bq->blocks->index >= bq->read_index); d = (size_t) (bq->blocks->index - bq->read_index); - + if (d >= length) { /* The first block is too far in the future */ - + bq->read_index += length; break; } else { - + length -= d; bq->read_index += d; } @@ -462,7 +462,7 @@ void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length bq->read_index += length; break; } - + } else { /* The list is empty, there's nothing we could drop */ @@ -477,7 +477,7 @@ int pa_memblockq_is_readable(pa_memblockq *bq) { if (bq->prebuf > 0) { size_t l = pa_memblockq_get_length(bq); - + if (bq->state == PREBUF && l < bq->prebuf) return 0; @@ -493,7 +493,7 @@ int pa_memblockq_is_writable(pa_memblockq *bq, size_t length) { if (length % bq->base) return 0; - + return pa_memblockq_get_length(bq) + length <= bq->tlength; } @@ -502,7 +502,7 @@ size_t pa_memblockq_get_length(pa_memblockq *bq) { if (bq->write_index <= bq->read_index) return 0; - + return (size_t) (bq->write_index - bq->read_index); } @@ -546,7 +546,7 @@ void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek) { void pa_memblockq_flush(pa_memblockq *bq) { assert(bq); - + while (bq->blocks) drop_block(bq, bq->blocks); @@ -559,7 +559,7 @@ void pa_memblockq_flush(pa_memblockq *bq) { size_t pa_memblockq_get_tlength(pa_memblockq *bq) { assert(bq); - + return bq->tlength; } @@ -578,18 +578,18 @@ int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk) { assert(bq); assert(chunk && bq->base); - + if (bq->base == 1) return pa_memblockq_push(bq, chunk); - + if (!bq->mcalign) bq->mcalign = pa_mcalign_new(bq->base); if (!can_push(bq, pa_mcalign_csize(bq->mcalign, chunk->length))) return -1; - + pa_mcalign_push(bq->mcalign, chunk); - + while (pa_mcalign_pop(bq->mcalign, &rchunk) >= 0) { int r; r = pa_memblockq_push(bq, &rchunk); diff --git a/src/pulsecore/memblockq.h b/src/pulsecore/memblockq.h index 4d701a80..3485a669 100644 --- a/src/pulsecore/memblockq.h +++ b/src/pulsecore/memblockq.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -39,27 +39,27 @@ typedef struct pa_memblockq pa_memblockq; /* Parameters: - + - idx: start value for both read and write index - maxlength: maximum length of queue. If more data is pushed into the queue, the operation will fail. Must not be 0. - + - tlength: the target length of the queue. Pass 0 for the default. - + - base: a base value for all metrics. Only multiples of this value are popped from the queue or should be pushed into it. Must not be 0. - + - prebuf: If the queue runs empty wait until this many bytes are in queue again before passing the first byte out. If set to 0 pa_memblockq_pop() will return a silence memblock if no data is in the queue and will never fail. Pass (size_t) -1 for the default. - + - minreq: pa_memblockq_missing() will only return values greater than this value. Pass 0 for the default. - + - silence: return this memblock whzen reading unitialized data */ pa_memblockq* pa_memblockq_new( @@ -67,7 +67,7 @@ pa_memblockq* pa_memblockq_new( size_t maxlength, size_t tlength, size_t base, - size_t prebuf, + size_t prebuf, size_t minreq, pa_memblock *silence); diff --git a/src/pulsecore/memchunk.c b/src/pulsecore/memchunk.c index 1dbad2b9..2ab6d358 100644 --- a/src/pulsecore/memchunk.c +++ b/src/pulsecore/memchunk.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -35,7 +35,7 @@ void pa_memchunk_make_writable(pa_memchunk *c, size_t min) { pa_memblock *n; size_t l; - + assert(c); assert(c->memblock); assert(PA_REFCNT_VALUE(c->memblock) > 0); @@ -48,7 +48,7 @@ void pa_memchunk_make_writable(pa_memchunk *c, size_t min) { l = c->length; if (l < min) l = min; - + n = pa_memblock_new(c->memblock->pool, l); memcpy(n->data, (uint8_t*) c->memblock->data + c->index, c->length); pa_memblock_unref(c->memblock); diff --git a/src/pulsecore/memchunk.h b/src/pulsecore/memchunk.h index b8ce6249..2e2f936b 100644 --- a/src/pulsecore/memchunk.h +++ b/src/pulsecore/memchunk.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/modargs.c b/src/pulsecore/modargs.c index 13a48785..243ea019 100644 --- a/src/pulsecore/modargs.c +++ b/src/pulsecore/modargs.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -60,7 +60,7 @@ static int add_key_value(pa_hashmap *map, char *key, char *value, const char* co return -1; } } - + e = pa_xmalloc(sizeof(struct entry)); e->key = key; e->value = value; @@ -78,7 +78,7 @@ pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) { enum { WHITESPACE, KEY, VALUE_START, VALUE_SIMPLE, VALUE_DOUBLE_QUOTES, VALUE_TICKS } state; const char *p, *key, *value; size_t key_len = 0, value_len = 0; - + key = value = NULL; state = WHITESPACE; for (p = args; *p; p++) { @@ -160,7 +160,7 @@ fail: if (map) pa_modargs_free((pa_modargs*) map); - + return NULL; } @@ -210,7 +210,7 @@ int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value) { if (pa_atoi(v, value) < 0) return -1; - + return 0; } @@ -239,7 +239,7 @@ int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) { assert(ma && rss); /* DEBUG_TRAP;*/ - + ss = *rss; if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0) return -1; @@ -257,14 +257,14 @@ int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) { return -1; *rss = ss; - + return 0; } int pa_modargs_get_channel_map(pa_modargs *ma, pa_channel_map *rmap) { pa_channel_map map; const char *cm; - + assert(ma); assert(rmap); @@ -284,7 +284,7 @@ int pa_modargs_get_channel_map(pa_modargs *ma, pa_channel_map *rmap) { int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *rss, pa_channel_map *rmap, pa_channel_map_def_t def) { pa_sample_spec ss; pa_channel_map map; - + assert(ma); assert(rss); assert(rmap); diff --git a/src/pulsecore/modargs.h b/src/pulsecore/modargs.h index 730cf396..5cccee90 100644 --- a/src/pulsecore/modargs.h +++ b/src/pulsecore/modargs.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/modinfo.c b/src/pulsecore/modinfo.c index 00720113..46e66c50 100644 --- a/src/pulsecore/modinfo.c +++ b/src/pulsecore/modinfo.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/modinfo.h b/src/pulsecore/modinfo.h index 90404504..e8d3103f 100644 --- a/src/pulsecore/modinfo.h +++ b/src/pulsecore/modinfo.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/module.c b/src/pulsecore/module.c index ea3d726e..94410b39 100644 --- a/src/pulsecore/module.c +++ b/src/pulsecore/module.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -100,17 +100,17 @@ static inline fnptr load_sym(lt_dlhandle handle, const char *module, const char pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { pa_module *m = NULL; int r; - + assert(c && name); if (c->disallow_module_loading) goto fail; - + m = pa_xmalloc(sizeof(pa_module)); m->name = pa_xstrdup(name); m->argument = pa_xstrdup(argument); - + if (!(m->dl = lt_dlopenext(name))) { pa_log("Failed to open module \"%s\": %s", name, lt_dlerror()); goto fail; @@ -125,7 +125,7 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { pa_log("Failed to load module \"%s\": symbol \""PA_SYMBOL_DONE"\" not found.", name); goto fail; } - + m->userdata = NULL; m->core = c; m->n_used = -1; @@ -148,23 +148,23 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { c->module_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); } assert(c->module_auto_unload_event); - + assert(c->modules); r = pa_idxset_put(c->modules, m, &m->index); assert(r >= 0 && m->index != PA_IDXSET_INVALID); - pa_log_info("Loaded \"%s\" (index: #%u; argument: \"%s\").", m->name, m->index, m->argument ? m->argument : ""); + pa_log_info("Loaded \"%s\" (index: #%u; argument: \"%s\").", m->name, m->index, m->argument ? m->argument : ""); pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_NEW, m->index); - + return m; - + fail: if (m) { pa_xfree(m->argument); pa_xfree(m->name); - + if (m->dl) lt_dlclose(m->dl); @@ -180,16 +180,16 @@ static void pa_module_free(pa_module *m) { if (m->core->disallow_module_loading) return; - pa_log_info("Unloading \"%s\" (index: #%u).", m->name, m->index); + pa_log_info("Unloading \"%s\" (index: #%u).", m->name, m->index); m->done(m->core, m); lt_dlclose(m->dl); - - pa_log_info("Unloaded \"%s\" (index: #%u).", m->name, m->index); + + pa_log_info("Unloaded \"%s\" (index: #%u).", m->name, m->index); pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_REMOVE, m->index); - + pa_xfree(m->name); pa_xfree(m->argument); pa_xfree(m); @@ -250,7 +250,7 @@ static int unused_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void * pa_module *m = p; time_t *now = userdata; assert(p && del && now); - + if (m->n_used == 0 && m->auto_unload && m->last_used_time+m->core->module_idle_time <= *now) { pa_module_free(m); *del = 1; @@ -265,7 +265,7 @@ void pa_module_unload_unused(pa_core *c) { if (!c->modules) return; - + time(&now); pa_idxset_foreach(c->modules, unused_callback, &now); } @@ -309,7 +309,7 @@ void pa_module_set_used(pa_module*m, int used) { if (m->n_used != used) pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_CHANGE, m->index); - + if (m->n_used != used && used == 0) time(&m->last_used_time); diff --git a/src/pulsecore/module.h b/src/pulsecore/module.h index 8c320be8..5f107507 100644 --- a/src/pulsecore/module.h +++ b/src/pulsecore/module.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -36,7 +36,7 @@ struct pa_module { uint32_t index; lt_dlhandle dl; - + int (*init)(pa_core *c, pa_module*m); void (*done)(pa_core *c, pa_module*m); diff --git a/src/pulsecore/mutex-posix.c b/src/pulsecore/mutex-posix.c index 094d637d..896913ce 100644 --- a/src/pulsecore/mutex-posix.c +++ b/src/pulsecore/mutex-posix.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/mutex-win32.c b/src/pulsecore/mutex-win32.c index 3710d914..124b17c6 100644 --- a/src/pulsecore/mutex-win32.c +++ b/src/pulsecore/mutex-win32.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/mutex.h b/src/pulsecore/mutex.h index b3b9c5c6..11a20733 100644 --- a/src/pulsecore/mutex.h +++ b/src/pulsecore/mutex.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c index fcd271bf..faf7f144 100644 --- a/src/pulsecore/namereg.c +++ b/src/pulsecore/namereg.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -59,14 +59,14 @@ static int is_valid_name(const char *name) { if (*name == 0) return 0; - + for (c = name; *c && (c-name < PA_NAME_MAX); c++) if (!is_valid_char(*c)) return 0; if (*c) return 0; - + return 1; } @@ -78,7 +78,7 @@ static char* cleanup_name(const char *name) { return NULL; n = pa_xnew(char, strlen(name)+1); - + for (a = name, b = n; *a && (a-name < PA_NAME_MAX); a++, b++) *b = is_valid_char(*a) ? *a : '_'; @@ -89,10 +89,10 @@ static char* cleanup_name(const char *name) { void pa_namereg_free(pa_core *c) { assert(c); - + if (!c->namereg) return; - + assert(pa_hashmap_size(c->namereg) == 0); pa_hashmap_free(c->namereg, NULL, NULL); } @@ -101,17 +101,17 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t struct namereg_entry *e; char *n = NULL; int r; - + assert(c); assert(name); assert(data); if (!*name) return NULL; - + if ((type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE) && !is_valid_name(name) ) { - + if (fail) return NULL; @@ -136,9 +136,9 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t pa_xfree(n); return NULL; } - + k = pa_xnew(char, l+4); - + for (i = 2; i <= 99; i++) { snprintf(k, l+4, "%s.%u", name, i); @@ -151,11 +151,11 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t pa_xfree(k); return NULL; } - + pa_xfree(n); n = k; } - + e = pa_xnew(struct namereg_entry, 1); e->type = type; e->name = n ? n : pa_xstrdup(name); @@ -169,7 +169,7 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t void pa_namereg_unregister(pa_core *c, const char *name) { struct namereg_entry *e; - + assert(c); assert(name); @@ -184,26 +184,26 @@ void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int a struct namereg_entry *e; uint32_t idx; assert(c); - + if (!name) { - + if (type == PA_NAMEREG_SOURCE) name = pa_namereg_get_default_source_name(c); else if (type == PA_NAMEREG_SINK) name = pa_namereg_get_default_sink_name(c); - + } else if (strcmp(name, "@DEFAULT_SINK@") == 0) { if (type == PA_NAMEREG_SINK) name = pa_namereg_get_default_sink_name(c); - + } else if (strcmp(name, "@DEFAULT_SOURCE@") == 0) { if (type == PA_NAMEREG_SOURCE) name = pa_namereg_get_default_source_name(c); - + } else if (strcmp(name, "@DEFAULT_MONITOR@") == 0) { if (type == PA_NAMEREG_SOURCE) { pa_sink *k; - + if ((k = pa_namereg_get(c, NULL, PA_NAMEREG_SINK, autoload))) return k->monitor_source; } @@ -212,7 +212,7 @@ void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int a if (!name) return NULL; - + if (c->namereg && (e = pa_hashmap_get(c->namereg, name))) if (e->type == type) return e->data; @@ -221,12 +221,12 @@ void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int a if (autoload) { pa_autoload_request(c, name, type); - + if (c->namereg && (e = pa_hashmap_get(c->namereg, name))) if (e->type == type) return e->data; } - + return NULL; } @@ -242,7 +242,7 @@ void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int a int pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type) { char **s; - + assert(c); assert(type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE); @@ -256,7 +256,7 @@ int pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type) if (!is_valid_name(name)) return -1; - + pa_xfree(*s); *s = pa_xstrdup(name); pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); @@ -266,12 +266,12 @@ int pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type) const char *pa_namereg_get_default_sink_name(pa_core *c) { pa_sink *s; - + assert(c); if (c->default_sink_name) return c->default_sink_name; - + if ((s = pa_idxset_first(c->sinks, NULL))) pa_namereg_set_default(c, s->name, PA_NAMEREG_SINK); @@ -281,7 +281,7 @@ const char *pa_namereg_get_default_sink_name(pa_core *c) { const char *pa_namereg_get_default_source_name(pa_core *c) { pa_source *s; uint32_t idx; - + assert(c); if (c->default_source_name) diff --git a/src/pulsecore/namereg.h b/src/pulsecore/namereg.h index 53fb6618..efadb06e 100644 --- a/src/pulsecore/namereg.h +++ b/src/pulsecore/namereg.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/native-common.h b/src/pulsecore/native-common.h index 785289eb..df7654ff 100644 --- a/src/pulsecore/native-common.h +++ b/src/pulsecore/native-common.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -51,7 +51,7 @@ enum { PA_COMMAND_FINISH_UPLOAD_STREAM, PA_COMMAND_PLAY_SAMPLE, PA_COMMAND_REMOVE_SAMPLE, - + PA_COMMAND_GET_SERVER_INFO, PA_COMMAND_GET_SINK_INFO, PA_COMMAND_GET_SINK_INFO_LIST, @@ -68,24 +68,24 @@ enum { PA_COMMAND_GET_SAMPLE_INFO, PA_COMMAND_GET_SAMPLE_INFO_LIST, PA_COMMAND_SUBSCRIBE, - + PA_COMMAND_SET_SINK_VOLUME, PA_COMMAND_SET_SINK_INPUT_VOLUME, PA_COMMAND_SET_SOURCE_VOLUME, PA_COMMAND_SET_SINK_MUTE, PA_COMMAND_SET_SOURCE_MUTE, - + PA_COMMAND_CORK_PLAYBACK_STREAM, PA_COMMAND_FLUSH_PLAYBACK_STREAM, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, - + PA_COMMAND_SET_DEFAULT_SINK, PA_COMMAND_SET_DEFAULT_SOURCE, - + PA_COMMAND_SET_PLAYBACK_STREAM_NAME, PA_COMMAND_SET_RECORD_STREAM_NAME, - + PA_COMMAND_KILL_CLIENT, PA_COMMAND_KILL_SINK_INPUT, PA_COMMAND_KILL_SOURCE_OUTPUT, diff --git a/src/pulsecore/once-posix.c b/src/pulsecore/once-posix.c index 865997df..bb2ca793 100644 --- a/src/pulsecore/once-posix.c +++ b/src/pulsecore/once-posix.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -35,22 +35,22 @@ assert(_r == 0); \ } while(0) -static pa_mutex *global_mutex; +static pa_mutex *global_mutex; static pthread_once_t global_mutex_once = PTHREAD_ONCE_INIT; -static void global_mutex_once_func(void) { - global_mutex = pa_mutex_new(0); -} +static void global_mutex_once_func(void) { + global_mutex = pa_mutex_new(0); +} + +void pa_once(pa_once_t *control, pa_once_func_t func) { + assert(control); + assert(func); -void pa_once(pa_once_t *control, pa_once_func_t func) { - assert(control); - assert(func); - /* Create the global mutex */ - ASSERT_SUCCESS(pthread_once(&global_mutex_once, global_mutex_once_func)); + ASSERT_SUCCESS(pthread_once(&global_mutex_once, global_mutex_once_func)); /* Create the local mutex */ - pa_mutex_lock(global_mutex); + pa_mutex_lock(global_mutex); if (!control->mutex) control->mutex = pa_mutex_new(1); pa_mutex_unlock(global_mutex); @@ -61,9 +61,9 @@ void pa_once(pa_once_t *control, pa_once_func_t func) { control->once_value = 1; func(); } - pa_mutex_unlock(control->mutex); + pa_mutex_unlock(control->mutex); /* Caveat: We have to make sure that the once func has completed * before returning, even if the once func is not actually * executed by us. Hence the awkward locking. */ -} +} diff --git a/src/pulsecore/once-win32.c b/src/pulsecore/once-win32.c index 8b9282f4..07f68f38 100644 --- a/src/pulsecore/once-win32.c +++ b/src/pulsecore/once-win32.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -59,7 +59,7 @@ void pa_once(pa_once_t *control, pa_once_func_t func) { control->once_value = 1; func(); } - pa_mutex_unlock(control->mutex); + pa_mutex_unlock(control->mutex); /* Caveat: We have to make sure that the once func has completed * before returning, even if the once func is not actually diff --git a/src/pulsecore/once.h b/src/pulsecore/once.h index 0aabb3f2..3c475a1d 100644 --- a/src/pulsecore/once.h +++ b/src/pulsecore/once.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/packet.c b/src/pulsecore/packet.c index 8b010f01..b3a4b6f4 100644 --- a/src/pulsecore/packet.c +++ b/src/pulsecore/packet.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -40,7 +40,7 @@ pa_packet* pa_packet_new(size_t length) { p->length = length; p->data = (uint8_t*) (p+1); p->type = PA_PACKET_APPENDED; - + return p; } @@ -55,14 +55,14 @@ pa_packet* pa_packet_new_dynamic(void* data, size_t length) { p->length = length; p->data = data; p->type = PA_PACKET_DYNAMIC; - + return p; } pa_packet* pa_packet_ref(pa_packet *p) { assert(p); assert(p->ref >= 1); - + p->ref++; return p; } @@ -70,7 +70,7 @@ pa_packet* pa_packet_ref(pa_packet *p) { void pa_packet_unref(pa_packet *p) { assert(p); assert(p->ref >= 1); - + if (--p->ref == 0) { if (p->type == PA_PACKET_DYNAMIC) pa_xfree(p->data); diff --git a/src/pulsecore/packet.h b/src/pulsecore/packet.h index 7842857a..89759c5a 100644 --- a/src/pulsecore/packet.h +++ b/src/pulsecore/packet.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/parseaddr.c b/src/pulsecore/parseaddr.c index da1647af..3a5bc2e8 100644 --- a/src/pulsecore/parseaddr.c +++ b/src/pulsecore/parseaddr.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -53,11 +53,11 @@ static char *parse_host(const char *s, uint16_t *ret_port) { *ret_port = atoi(e+2); else if (e[1] != 0) return NULL; - + return pa_xstrndup(s+1, e-s-1); } else { char *e; - + if (!(e = strrchr(s, ':'))) return pa_xstrdup(s); @@ -75,22 +75,22 @@ int pa_parse_address(const char *name, pa_parsed_address *ret_p) { if (*name == '{') { char hn[256], *pfx; /* The URL starts with a host specification for detecting local connections */ - + if (!pa_get_host_name(hn, sizeof(hn))) return -1; - + pfx = pa_sprintf_malloc("{%s}", hn); if (!pa_startswith(name, pfx)) { pa_xfree(pfx); /* Not local */ return -1; } - + p = name + strlen(pfx); pa_xfree(pfx); } else p = name; - + if (*p == '/') ret_p->type = PA_PARSED_ADDRESS_UNIX; else if (pa_startswith(p, "unix:")) { @@ -109,7 +109,7 @@ int pa_parse_address(const char *name, pa_parsed_address *ret_p) { else if (!(ret_p->path_or_host = parse_host(p, &ret_p->port))) return -1; - - + + return 0; } diff --git a/src/pulsecore/parseaddr.h b/src/pulsecore/parseaddr.h index 0393f665..bbbb8989 100644 --- a/src/pulsecore/parseaddr.h +++ b/src/pulsecore/parseaddr.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c index 6ecf710a..c474ccd1 100644 --- a/src/pulsecore/pdispatch.c +++ b/src/pulsecore/pdispatch.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -120,9 +120,9 @@ static void reply_info_free(struct reply_info *r) { if (r->time_event) r->pdispatch->mainloop->time_free(r->time_event); - + PA_LLIST_REMOVE(struct reply_info, r->pdispatch->replies, r); - + pa_xfree(r); } @@ -131,7 +131,7 @@ pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_cb_ assert(mainloop); assert((entries && table) || (!entries && !table)); - + pd = pa_xmalloc(sizeof(pa_pdispatch)); pd->ref = 1; pd->mainloop = mainloop; @@ -141,7 +141,7 @@ pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_cb_ pd->drain_callback = NULL; pd->drain_userdata = NULL; pd->creds = NULL; - + return pd; } @@ -154,7 +154,7 @@ static void pdispatch_free(pa_pdispatch *pd) { reply_info_free(pd->replies); } - + pa_xfree(pd); } @@ -165,13 +165,13 @@ static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command, assert(r); pa_pdispatch_ref(pd); - + callback = r->callback; userdata = r->userdata; tag = r->tag; - + reply_info_free(r); - + callback(pd, command, tag, ts, userdata); if (pd->drain_callback && !pa_pdispatch_is_pending(pd)) @@ -187,24 +187,24 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds, assert(pd && packet && packet->data); pa_pdispatch_ref(pd); - + if (packet->length <= 8) goto finish; ts = pa_tagstruct_new(packet->data, packet->length); assert(ts); - + if (pa_tagstruct_getu32(ts, &command) < 0 || pa_tagstruct_getu32(ts, &tag) < 0) goto finish; - + #ifdef DEBUG_OPCODES { char t[256]; char const *p; if (!(p = command_names[command])) snprintf((char*) (p = t), sizeof(t), "%u", command); - + pa_log("Recieved opcode <%s>", p); } #endif @@ -231,10 +231,10 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds, } ret = 0; - + finish: pd->creds = NULL; - + if (ts) pa_tagstruct_free(ts); @@ -261,7 +261,7 @@ void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa r->userdata = userdata; r->free_cb = free_cb; r->tag = tag; - + pa_gettimeofday(&tv); tv.tv_sec += timeout; @@ -292,7 +292,7 @@ void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata) { for (r = pd->replies; r; r = n) { n = r->next; - if (r->userdata == userdata) + if (r->userdata == userdata) reply_info_free(r); } } @@ -313,6 +313,6 @@ pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd) { const pa_creds * pa_pdispatch_creds(pa_pdispatch *pd) { assert(pd); assert(pd->ref >= 1); - + return pd->creds; } diff --git a/src/pulsecore/pdispatch.h b/src/pulsecore/pdispatch.h index 479eb6b4..28bc29d9 100644 --- a/src/pulsecore/pdispatch.h +++ b/src/pulsecore/pdispatch.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/pid.c b/src/pulsecore/pid.c index 6e0c085e..40cc8248 100644 --- a/src/pulsecore/pid.c +++ b/src/pulsecore/pid.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -64,7 +64,7 @@ static pid_t read_pid(const char *fn, int fd) { if (r == 0) return (pid_t) 0; - + t[r] = 0; if ((e = strchr(t, '\n'))) *e = 0; @@ -79,10 +79,10 @@ static pid_t read_pid(const char *fn, int fd) { static int open_pid_file(const char *fn, int mode) { int fd = -1; - + for (;;) { struct stat st; - + if ((fd = open(fn, mode, S_IRUSR|S_IWUSR)) < 0) { if (mode != O_RDONLY || errno != ENOENT) pa_log_warn("WARNING: failed to open PID file '%s': %s", @@ -93,7 +93,7 @@ static int open_pid_file(const char *fn, int mode) { /* Try to lock the file. If that fails, go without */ if (pa_lock_fd(fd, 1) < 0) goto fail; - + if (fstat(fd, &st) < 0) { pa_log_warn("WARNING: failed to fstat() PID file '%s': %s", fn, pa_cstrerror(errno)); @@ -168,23 +168,23 @@ int pa_pid_file_create(void) { fn, pa_cstrerror(errno)); goto fail; } - + snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid()); l = strlen(t); - + if (pa_loop_write(fd, t, l, NULL) != (ssize_t) l) { pa_log("failed to write PID file."); goto fail; } ret = 0; - + fail: if (fd >= 0) { pa_lock_fd(fd, 0); close(fd); } - + return ret; } @@ -230,7 +230,7 @@ int pa_pid_file_remove(void) { } ret = 0; - + fail: if (fd >= 0) { @@ -262,26 +262,26 @@ int pa_pid_file_kill(int sig, pid_t *pid) { if (!pid) pid = &_pid; - + pa_runtime_path("pid", fn, sizeof(fn)); - + if ((fd = open_pid_file(fn, O_RDONLY)) < 0) goto fail; - + if ((*pid = read_pid(fn, fd)) == (pid_t) -1) goto fail; ret = kill(*pid, sig); - + fail: - + if (fd >= 0) { pa_lock_fd(fd, 0); close(fd); } return ret; - + } #else /* OS_IS_WIN32 */ diff --git a/src/pulsecore/pid.h b/src/pulsecore/pid.h index bd476b29..31d6f0bb 100644 --- a/src/pulsecore/pid.h +++ b/src/pulsecore/pid.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/pipe.c b/src/pulsecore/pipe.c index 41ffb693..a0c46fa3 100644 --- a/src/pulsecore/pipe.c +++ b/src/pulsecore/pipe.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/pipe.h b/src/pulsecore/pipe.h index 21049e17..86a198d3 100644 --- a/src/pulsecore/pipe.h +++ b/src/pulsecore/pipe.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c index f459142a..ae7cd616 100644 --- a/src/pulsecore/play-memblockq.c +++ b/src/pulsecore/play-memblockq.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -65,11 +65,11 @@ static void si_kill(PA_GCC_UNUSED pa_mainloop_api *m, void *i) { static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) { pa_memblockq *q; - + assert(i); assert(length > 0); assert( i->userdata); - + q = i->userdata; pa_memblockq_drop(q, chunk, length); @@ -85,7 +85,7 @@ int pa_play_memblockq( const pa_channel_map *map, pa_memblockq *q, pa_cvolume *volume) { - + pa_sink_input *si; pa_sink_input_new_data data; @@ -110,17 +110,17 @@ int pa_play_memblockq( pa_sink_input_new_data_set_channel_map(&data, map); pa_sink_input_new_data_set_sample_spec(&data, ss); pa_sink_input_new_data_set_volume(&data, volume); - + if (!(si = pa_sink_input_new(sink->core, &data, 0))) return -1; si->peek = sink_input_peek; si->drop = sink_input_drop; si->kill = sink_input_kill; - + si->userdata = q; pa_sink_notify(si->sink); - + return 0; } diff --git a/src/pulsecore/play-memblockq.h b/src/pulsecore/play-memblockq.h index 9b96efe3..68d0f8e3 100644 --- a/src/pulsecore/play-memblockq.h +++ b/src/pulsecore/play-memblockq.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/play-memchunk.c b/src/pulsecore/play-memchunk.c index cde6a9ee..c5dcc8ce 100644 --- a/src/pulsecore/play-memchunk.c +++ b/src/pulsecore/play-memchunk.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -54,7 +54,7 @@ static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { if (c->length <= 0) return -1; - + assert(c->memblock && c->memblock->length); *chunk = *c; pa_memblock_ref(c->memblock); @@ -88,7 +88,7 @@ int pa_play_memchunk( const pa_channel_map *map, const pa_memchunk *chunk, pa_cvolume *volume) { - + pa_sink_input *si; pa_memchunk *nchunk; pa_sink_input_new_data data; @@ -107,20 +107,20 @@ int pa_play_memchunk( pa_sink_input_new_data_set_sample_spec(&data, ss); pa_sink_input_new_data_set_channel_map(&data, map); pa_sink_input_new_data_set_volume(&data, volume); - + if (!(si = pa_sink_input_new(sink->core, &data, 0))) return -1; si->peek = sink_input_peek; si->drop = sink_input_drop; si->kill = sink_input_kill; - + si->userdata = nchunk = pa_xnew(pa_memchunk, 1); *nchunk = *chunk; - + pa_memblock_ref(chunk->memblock); pa_sink_notify(si->sink); - + return 0; } diff --git a/src/pulsecore/play-memchunk.h b/src/pulsecore/play-memchunk.h index 3d5b8cc6..3e087baa 100644 --- a/src/pulsecore/play-memchunk.h +++ b/src/pulsecore/play-memchunk.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/poll.c b/src/pulsecore/poll.c index 289e0cdf..82af4c05 100644 --- a/src/pulsecore/poll.c +++ b/src/pulsecore/poll.c @@ -9,17 +9,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/poll.h b/src/pulsecore/poll.h index c3d486e1..9c29789d 100644 --- a/src/pulsecore/poll.h +++ b/src/pulsecore/poll.h @@ -10,17 +10,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/props.c b/src/pulsecore/props.c index 8879b7aa..b8f92090 100644 --- a/src/pulsecore/props.c +++ b/src/pulsecore/props.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -36,7 +36,7 @@ typedef struct pa_property { static pa_property* property_new(const char *name, void *data) { pa_property* p; assert(name && data); - + p = pa_xmalloc(sizeof(pa_property)); p->name = pa_xstrdup(name); p->data = data; @@ -80,7 +80,7 @@ int pa_property_remove(pa_core *c, const char *name) { if (!(p = pa_hashmap_remove(c->properties, name))) return -1; - + property_free(p); return 0; } @@ -101,7 +101,7 @@ void pa_property_cleanup(pa_core *c) { pa_hashmap_free(c->properties, NULL, NULL); c->properties = NULL; - + } void pa_property_dump(pa_core *c, pa_strbuf *s) { diff --git a/src/pulsecore/props.h b/src/pulsecore/props.h index 39b7ca68..2b881b67 100644 --- a/src/pulsecore/props.h +++ b/src/pulsecore/props.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/protocol-cli.c b/src/pulsecore/protocol-cli.c index 81ce5e8f..9cca39eb 100644 --- a/src/pulsecore/protocol-cli.c +++ b/src/pulsecore/protocol-cli.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -60,7 +60,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) pa_iochannel_free(io); return; } - + c = pa_cli_new(p->core, io, p->module); assert(c); pa_cli_set_eof_callback(c, cli_eof_cb, p); @@ -79,7 +79,7 @@ pa_protocol_cli* pa_protocol_cli_new(pa_core *core, pa_socket_server *server, pa p->connections = pa_idxset_new(NULL, NULL); pa_socket_server_set_callback(p->server, on_connection, p); - + return p; } diff --git a/src/pulsecore/protocol-cli.h b/src/pulsecore/protocol-cli.h index 84101e14..6acd62cf 100644 --- a/src/pulsecore/protocol-cli.h +++ b/src/pulsecore/protocol-cli.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index c36f8201..2984676d 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -93,7 +93,7 @@ struct connection { pa_defer_event *defer_event; char *original_name; - + struct { pa_memblock *current_memblock; size_t memblock_index, fragment_size; @@ -177,7 +177,7 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = { { 3 * sizeof(int), esd_proto_stream_pan, "stream pan"}, { 3 * sizeof(int), NULL, "sample pan" }, - + { sizeof(int), NULL, "standby mode" }, { 0, esd_proto_get_latency, "get latency" } }; @@ -188,19 +188,19 @@ static void connection_free(struct connection *c) { if (c->state == ESD_STREAMING_DATA) c->protocol->n_player--; - + pa_client_free(c->client); if (c->sink_input) { pa_sink_input_disconnect(c->sink_input); pa_sink_input_unref(c->sink_input); } - + if (c->source_output) { pa_source_output_disconnect(c->source_output); pa_source_output_unref(c->source_output); } - + if (c->input_memblockq) pa_memblockq_free(c->input_memblockq); if (c->output_memblockq) @@ -208,13 +208,13 @@ static void connection_free(struct connection *c) { if (c->playback.current_memblock) pa_memblock_unref(c->playback.current_memblock); - + pa_xfree(c->read_data); pa_xfree(c->write_data); if (c->io) pa_iochannel_free(c->io); - + if (c->defer_event) c->protocol->core->mainloop->defer_free(c->defer_event); @@ -254,7 +254,7 @@ static void connection_write(struct connection *c, const void *data, size_t leng i = c->write_data_length; c->write_data_length += length; - + memcpy((char*)c->write_data + i, data, length); } @@ -270,7 +270,7 @@ static void format_esd2native(int format, int swap_bytes, pa_sample_spec *ss) { static int format_native2esd(pa_sample_spec *ss) { int format = 0; - + format = (ss->format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16; format |= (ss->channels >= 2) ? ESD_STEREO : ESD_MONO; @@ -331,7 +331,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t pa_sink_input_new_data sdata; assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); - + memcpy(&format, data, sizeof(int32_t)); format = MAYBE_INT32_SWAP(c->swap_byte_order, format); data = (const char*)data + sizeof(int32_t); @@ -356,7 +356,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t utf8_name = pa_utf8_filter(name); pa_client_set_name(c->client, utf8_name); pa_xfree(utf8_name); - + c->original_name = pa_xstrdup(name); assert(!c->sink_input && !c->input_memblockq); @@ -368,11 +368,11 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t pa_sink_input_new_data_set_sample_spec(&sdata, &ss); sdata.module = c->protocol->module; sdata.client = c->client; - + c->sink_input = pa_sink_input_new(c->protocol->core, &sdata, 0); CHECK_VALIDITY(c->sink_input, "Failed to create sink input."); - l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); + l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); c->input_memblockq = pa_memblockq_new( 0, l, @@ -393,7 +393,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t c->state = ESD_STREAMING_DATA; c->protocol->n_player++; - + return 0; } @@ -406,7 +406,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co pa_source_output_new_data sdata; assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); - + memcpy(&format, data, sizeof(int32_t)); format = MAYBE_INT32_SWAP(c->swap_byte_order, format); data = (const char*)data + sizeof(int32_t); @@ -442,14 +442,14 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co } } } - + strncpy(name, data, sizeof(name)); name[sizeof(name)-1] = 0; utf8_name = pa_utf8_filter(name); pa_client_set_name(c->client, utf8_name); pa_xfree(utf8_name); - + c->original_name = pa_xstrdup(name); assert(!c->output_memblockq && !c->source_output); @@ -461,11 +461,11 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co pa_source_output_new_data_set_sample_spec(&sdata, &ss); sdata.module = c->protocol->module; sdata.client = c->client; - + c->source_output = pa_source_output_new(c->protocol->core, &sdata, 9); CHECK_VALIDITY(c->source_output, "Failed to create source_output."); - l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); + l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); c->output_memblockq = pa_memblockq_new( 0, l, @@ -475,7 +475,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co 0, NULL); pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); - + c->source_output->push = source_output_push_cb; c->source_output->kill = source_output_kill_cb; c->source_output->get_latency = source_output_get_latency_cb; @@ -484,7 +484,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co c->state = ESD_STREAMING_DATA; c->protocol->n_player++; - + return 0; } @@ -500,7 +500,7 @@ static int esd_proto_get_latency(struct connection *c, PA_GCC_UNUSED esd_proto_t double usec = pa_sink_get_latency(sink); latency = (int) ((usec*44100)/1000000); } - + latency = MAYBE_INT32_SWAP(c->swap_byte_order, latency); connection_write(c, &latency, sizeof(int32_t)); return 0; @@ -538,7 +538,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v char terminator[sizeof(int32_t)*6+ESD_NAME_MAX]; assert(c && data && length == sizeof(int32_t)); - + if (esd_proto_server_info(c, request, data, length) < 0) return -1; @@ -559,7 +559,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v continue; assert(t >= k*2+s); - + if (conn->sink_input) { pa_cvolume volume = *pa_sink_input_get_volume(conn->sink_input); rate = conn->sink_input->sample_spec.rate; @@ -567,7 +567,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v rvolume = (volume.values[1]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; format = format_native2esd(&conn->sink_input->sample_spec); } - + /* id */ id = MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) (conn->index+1)); connection_write(c, &id, sizeof(int32_t)); @@ -606,7 +606,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v if (nsamples) { pa_scache_entry *ce; - + idx = PA_IDXSET_INVALID; for (ce = pa_idxset_first(c->protocol->core->scache, &idx); ce; ce = pa_idxset_next(c->protocol->core->scache, &idx)) { int32_t id, rate, lvolume, rvolume, format, len; @@ -617,7 +617,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v /* id */ id = MAYBE_INT32_SWAP(c->swap_byte_order, (int) (ce->index+1)); connection_write(c, &id, sizeof(int32_t)); - + /* name */ memset(name, 0, ESD_NAME_MAX); /* don't leak old data */ if (strncmp(ce->name, SCACHE_PREFIX, sizeof(SCACHE_PREFIX)-1) == 0) @@ -625,19 +625,19 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v else snprintf(name, ESD_NAME_MAX, "native.%s", ce->name); connection_write(c, name, ESD_NAME_MAX); - + /* rate */ rate = MAYBE_UINT32_SWAP(c->swap_byte_order, ce->sample_spec.rate); connection_write(c, &rate, sizeof(int32_t)); - + /* left */ lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); connection_write(c, &lvolume, sizeof(int32_t)); - + /*right*/ rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); connection_write(c, &rvolume, sizeof(int32_t)); - + /*format*/ format = MAYBE_INT32_SWAP(c->swap_byte_order, format_native2esd(&ce->sample_spec)); connection_write(c, &format, sizeof(int32_t)); @@ -663,7 +663,7 @@ static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t struct connection *conn; assert(c && data && length == sizeof(int32_t)*3); - + memcpy(&idx, data, sizeof(uint32_t)); idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; data = (const char*)data + sizeof(uint32_t); @@ -687,7 +687,7 @@ static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t ok = 0; connection_write(c, &ok, sizeof(int32_t)); - + return 0; } @@ -706,7 +706,7 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ memcpy(&rate, data, sizeof(int32_t)); rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); data = (const char*)data + sizeof(int32_t); - + ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); @@ -723,7 +723,7 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ name[sizeof(name)-1] = 0; CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in sample name."); - + assert(!c->scache.memchunk.memblock); c->scache.memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, sc_length); c->scache.memchunk.index = 0; @@ -731,14 +731,14 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ c->scache.sample_spec = ss; assert(!c->scache.name); c->scache.name = pa_xstrdup(name); - + c->state = ESD_CACHING_SAMPLE; pa_scache_add_item(c->protocol->core, c->scache.name, NULL, NULL, NULL, &idx); idx += 1; connection_write(c, &idx, sizeof(uint32_t)); - + return 0; } @@ -775,11 +775,11 @@ static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t reque idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; ok = 0; - + if ((name = pa_scache_get_name_by_id(c->protocol->core, idx))) { if (request == ESD_PROTO_SAMPLE_PLAY) { pa_sink *sink; - + if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) if (pa_scache_play_item(c->protocol->core, name, sink, PA_VOLUME_NORM) >= 0) ok = idx + 1; @@ -790,7 +790,7 @@ static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t reque ok = idx + 1; } } - + connection_write(c, &ok, sizeof(int32_t)); return 0; @@ -821,7 +821,7 @@ static int do_read(struct connection *c) { assert(c && c->io); /* pa_log("READ"); */ - + if (c->state == ESD_NEXT_REQUEST) { ssize_t r; assert(c->read_data_length < sizeof(c->request)); @@ -833,7 +833,7 @@ static int do_read(struct connection *c) { if ((c->read_data_length+= r) >= sizeof(c->request)) { struct proto_handler *handler; - + c->request = MAYBE_INT32_SWAP(c->swap_byte_order, c->request); if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) { @@ -849,18 +849,18 @@ static int do_read(struct connection *c) { pa_log("recieved unimplemented request #%u.", c->request); return -1; } - + if (handler->data_length == 0) { c->read_data_length = 0; if (handler->proc(c, c->request, NULL, 0) < 0) return -1; - + } else { if (c->read_data_alloc < handler->data_length) c->read_data = pa_xrealloc(c->read_data, c->read_data_alloc = handler->data_length); assert(c->read_data); - + c->state = ESD_NEEDS_REQDATA; c->read_data_length = 0; } @@ -871,7 +871,7 @@ static int do_read(struct connection *c) { struct proto_handler *handler = proto_map+c->request; assert(handler->proc); - + assert(c->read_data && c->read_data_length < handler->data_length); if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { @@ -885,7 +885,7 @@ static int do_read(struct connection *c) { c->state = ESD_NEXT_REQUEST; c->read_data_length = 0; - + if (handler->proc(c, c->request, c->read_data, l) < 0) return -1; } @@ -893,7 +893,7 @@ static int do_read(struct connection *c) { ssize_t r; assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); - + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; @@ -901,10 +901,10 @@ static int do_read(struct connection *c) { c->scache.memchunk.index += r; assert(c->scache.memchunk.index <= c->scache.memchunk.length); - + if (c->scache.memchunk.index == c->scache.memchunk.length) { uint32_t idx; - + c->scache.memchunk.index = 0; pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, NULL, &c->scache.memchunk, &idx); @@ -920,7 +920,7 @@ static int do_read(struct connection *c) { idx += 1; connection_write(c, &idx, sizeof(uint32_t)); } - + } else if (c->state == ESD_STREAMING_DATA && c->sink_input) { pa_memchunk chunk; ssize_t r; @@ -936,13 +936,13 @@ static int do_read(struct connection *c) { if (l > c->playback.fragment_size) l = c->playback.fragment_size; - if (c->playback.current_memblock) + if (c->playback.current_memblock) if (c->playback.current_memblock->length - c->playback.memblock_index < l) { pa_memblock_unref(c->playback.current_memblock); c->playback.current_memblock = NULL; c->playback.memblock_index = 0; } - + if (!c->playback.current_memblock) { c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, c->playback.fragment_size*2); assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); @@ -953,20 +953,20 @@ static int do_read(struct connection *c) { pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } - + chunk.memblock = c->playback.current_memblock; chunk.index = c->playback.memblock_index; chunk.length = r; assert(chunk.memblock); c->playback.memblock_index += r; - + assert(c->input_memblockq); pa_memblockq_push_align(c->input_memblockq, &chunk); assert(c->sink_input); pa_sink_notify(c->sink_input->sink); } - + return 0; } @@ -974,19 +974,19 @@ static int do_write(struct connection *c) { assert(c && c->io); /* pa_log("WRITE"); */ - + if (c->write_data_length) { ssize_t r; - + assert(c->write_data_index < c->write_data_length); if ((r = pa_iochannel_write(c->io, (uint8_t*) c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { pa_log("write(): %s", pa_cstrerror(errno)); return -1; } - + if ((c->write_data_index +=r) >= c->write_data_length) c->write_data_length = c->write_data_index = 0; - + } else if (c->state == ESD_STREAMING_DATA && c->source_output) { pa_memchunk chunk; ssize_t r; @@ -994,9 +994,9 @@ static int do_write(struct connection *c) { assert(c->output_memblockq); if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) return 0; - + assert(chunk.memblock && chunk.length); - + if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { pa_memblock_unref(chunk.memblock); pa_log("write(): %s", pa_cstrerror(errno)); @@ -1008,7 +1008,7 @@ static int do_write(struct connection *c) { pa_source_notify(c->source_output->source); } - + return 0; } @@ -1035,7 +1035,7 @@ static void do_work(struct connection *c) { if (pa_iochannel_is_writable(c->io)) if (do_write(c) < 0) goto fail; - + return; fail: @@ -1066,7 +1066,7 @@ static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) assert(a && c && c->defer_event == e); /* pa_log("DEFER"); */ - + do_work(c); } @@ -1076,12 +1076,12 @@ static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { struct connection*c; assert(i && i->userdata && chunk); c = i->userdata; - + if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) { if (c->dead) connection_free(c); - + return -1; } @@ -1093,7 +1093,7 @@ static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_ assert(i && c && length); /* pa_log("DROP"); */ - + pa_memblockq_drop(c->input_memblockq, chunk, length); /* do something */ @@ -1163,7 +1163,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) pa_iochannel_free(io); return; } - + c = pa_xnew(struct connection, 1); c->protocol = p; c->io = io; @@ -1177,7 +1177,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->client->owner = p->module; c->client->kill = client_kill_cb; c->client->userdata = c; - + c->authorized = !!p->public; c->swap_byte_order = 0; c->dead = 0; @@ -1219,7 +1219,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c); } else c->auth_timeout_event = NULL; - + c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c); assert(c->defer_event); p->core->mainloop->defer_enable(c->defer_event, 0); @@ -1233,7 +1233,7 @@ pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *serve pa_protocol_esound *p; int public = 0; const char *acl; - + assert(core); assert(server); assert(m); @@ -1257,7 +1257,7 @@ pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *serve } } else p->auth_ip_acl = NULL; - + p->module = m; p->public = public; p->server = server; diff --git a/src/pulsecore/protocol-esound.h b/src/pulsecore/protocol-esound.h index 79b5acf0..265f9e2c 100644 --- a/src/pulsecore/protocol-esound.h +++ b/src/pulsecore/protocol-esound.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/protocol-http.c b/src/pulsecore/protocol-http.c index 3b1207f6..22ecba82 100644 --- a/src/pulsecore/protocol-http.c +++ b/src/pulsecore/protocol-http.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -67,7 +67,7 @@ static void http_response(struct connection *c, int code, const char *msg, const assert(msg); assert(mime); - snprintf(s, sizeof(s), + snprintf(s, sizeof(s), "HTTP/1.0 %i %s\n" "Connection: close\n" "Content-Type: %s\n" @@ -137,16 +137,16 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) { } case MIME_HEADER: { - + /* Ignore MIME headers */ if (strcspn(s, " \r\n") != 0) break; - + /* We're done */ c->state = DATA; pa_log_info("request for %s", c->url); - + if (!strcmp(c->url, URL_ROOT)) { char txt[256]; http_response(c, 200, "OK", "text/html"); @@ -168,18 +168,18 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) { PRINTF_FIELD("Default Sample Specification:", pa_sample_spec_snprint(txt, sizeof(txt), &c->protocol->core->default_sample_spec)); PRINTF_FIELD("Default Sink:", pa_namereg_get_default_sink_name(c->protocol->core)); PRINTF_FIELD("Default Source:", pa_namereg_get_default_source_name(c->protocol->core)); - + pa_ioline_puts(c->line, ""); pa_ioline_puts(c->line, "

        Click here for an extensive server status report.

        "); - + pa_ioline_puts(c->line, "\n"); - - pa_ioline_defer_close(c->line); + + pa_ioline_defer_close(c->line); } else if (!strcmp(c->url, URL_CSS)) { http_response(c, 200, "OK", "text/css"); - pa_ioline_puts(c->line, + pa_ioline_puts(c->line, "body { color: black; background-color: white; margin: 0.5cm; }\n" "a:link, a:visited { color: #900000; }\n" "p { margin-left: 0.5cm; margin-right: 0.5cm; }\n" @@ -207,13 +207,13 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) { break; } - + default: ; } return; - + fail: internal_server_error(c); } diff --git a/src/pulsecore/protocol-http.h b/src/pulsecore/protocol-http.h index 5d5dba31..bf1562e6 100644 --- a/src/pulsecore/protocol-http.h +++ b/src/pulsecore/protocol-http.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 38c024b7..a882d701 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -234,7 +234,7 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume, [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume, [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume, - + [PA_COMMAND_SET_SINK_MUTE] = command_set_mute, [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute, @@ -242,13 +242,13 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_flush_playback_stream, [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_prebuf_playback_stream, [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_prebuf_playback_stream, - + [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream, [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream, - + [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source, [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source, - [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name, + [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name, [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name, [PA_COMMAND_KILL_CLIENT] = command_kill, [PA_COMMAND_KILL_SINK_INPUT] = command_kill, @@ -271,10 +271,10 @@ static struct upload_stream* upload_stream_new( const pa_sample_spec *ss, const pa_channel_map *map, const char *name, size_t length) { - + struct upload_stream *s; assert(c && ss && name && length); - + s = pa_xnew(struct upload_stream, 1); s->type = UPLOAD_STREAM; s->connection = c; @@ -287,7 +287,7 @@ static struct upload_stream* upload_stream_new( s->memchunk.length = 0; s->length = length; - + pa_idxset_put(c->output_streams, s, &s->index); return s; } @@ -298,10 +298,10 @@ static void upload_stream_free(struct upload_stream *o) { pa_idxset_remove_by_data(o->connection->output_streams, o, NULL); pa_xfree(o->name); - + if (o->memchunk.memblock) pa_memblock_unref(o->memchunk.memblock); - + pa_xfree(o); } @@ -313,12 +313,12 @@ static struct record_stream* record_stream_new( const char *name, size_t maxlength, size_t fragment_size) { - + struct record_stream *s; pa_source_output *source_output; size_t base; pa_source_output_new_data data; - + assert(c && ss && name && maxlength); pa_source_output_new_data_init(&data); @@ -329,7 +329,7 @@ static struct record_stream* record_stream_new( pa_source_output_new_data_set_channel_map(&data, map); data.module = c->protocol->module; data.client = c->client; - + if (!(source_output = pa_source_output_new(c->protocol->core, &data, 0))) return NULL; @@ -381,19 +381,19 @@ static struct playback_stream* playback_stream_new( size_t minreq, pa_cvolume *volume, uint32_t syncid) { - + struct playback_stream *s, *ssync; pa_sink_input *sink_input; pa_memblock *silence; uint32_t idx; int64_t start_index; pa_sink_input_new_data data; - + assert(c && ss && name && maxlength); /* Find syncid group */ for (ssync = pa_idxset_first(c->output_streams, &idx); ssync; ssync = pa_idxset_next(c->output_streams, &idx)) { - + if (ssync->type != PLAYBACK_STREAM) continue; @@ -417,14 +417,14 @@ static struct playback_stream* playback_stream_new( if (!(sink_input = pa_sink_input_new(c->protocol->core, &data, 0))) return NULL; - + s = pa_xnew(struct playback_stream, 1); s->type = PLAYBACK_STREAM; s->connection = c; s->syncid = syncid; s->sink_input = sink_input; s->underrun = 1; - + s->sink_input->peek = sink_input_peek_cb; s->sink_input->drop = sink_input_drop_cb; s->sink_input->kill = sink_input_kill_cb; @@ -446,9 +446,9 @@ static struct playback_stream* playback_stream_new( PA_LLIST_INIT(struct playback_stream, s); start_index = 0; } - + silence = pa_silence_memblock_new(c->protocol->core->mempool, ss, 0); - + s->memblockq = pa_memblockq_new( start_index, maxlength, @@ -459,10 +459,10 @@ static struct playback_stream* playback_stream_new( silence); pa_memblock_unref(silence); - + s->requested_bytes = 0; s->drain_request = 0; - + pa_idxset_put(c->output_streams, s, &s->index); return s; @@ -512,7 +512,7 @@ static void connection_free(struct connection *c) { if (c->auth_timeout_event) c->protocol->core->mainloop->time_free(c->auth_timeout_event); - + pa_xfree(c); } @@ -523,7 +523,7 @@ static void request_bytes(struct playback_stream *s) { if (!(l = pa_memblockq_missing(s->memblockq))) return; - + if (l <= s->requested_bytes) return; @@ -531,7 +531,7 @@ static void request_bytes(struct playback_stream *s) { if (l < pa_memblockq_get_minreq(s->memblockq)) return; - + s->requested_bytes += l; t = pa_tagstruct_new(NULL, 0); @@ -552,7 +552,7 @@ static void send_memblock(struct connection *c) { start = PA_IDXSET_INVALID; for (;;) { pa_memchunk chunk; - + if (!(r = pa_idxset_rrobin(c->record_streams, &c->rrobin_index))) return; @@ -563,14 +563,14 @@ static void send_memblock(struct connection *c) { if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) { pa_memchunk schunk = chunk; - + if (schunk.length > r->fragment_size) schunk.length = r->fragment_size; pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk); pa_memblockq_drop(r->memblockq, &chunk, schunk.length); pa_memblock_unref(schunk.memblock); - + return; } } @@ -618,14 +618,14 @@ static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { s->underrun = 1; } - + if (pa_memblockq_peek(s->memblockq, chunk) < 0) { /* pa_log("peek: failure"); */ return -1; } /* pa_log("peek: %u", chunk->length); */ - + return 0; } @@ -658,7 +658,7 @@ static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { s = i->userdata; /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/ - + return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec); } @@ -668,12 +668,12 @@ static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) struct record_stream *s; assert(o && o->userdata && chunk); s = o->userdata; - + if (pa_memblockq_push_align(s->memblockq, chunk) < 0) { pa_log_warn("Failed to push data into output queue."); return; - } - + } + if (!pa_pstream_is_pending(s->connection->pstream)) send_memblock(s->connection); } @@ -690,7 +690,7 @@ static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { s = o->userdata; /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/ - + return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec); } @@ -710,7 +710,7 @@ if (!(expression)) { \ static pa_tagstruct *reply_new(uint32_t tag) { pa_tagstruct *reply; - + reply = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); pa_tagstruct_putu32(reply, tag); @@ -728,9 +728,9 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC pa_sink *sink = NULL; pa_cvolume volume; int corked; - + assert(c && t && c->protocol && c->protocol->core); - + if (pa_tagstruct_get( t, PA_TAG_STRING, &name, @@ -773,7 +773,7 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); pa_sink_input_cork(s->sink_input, corked); - + reply = reply_new(tag); pa_tagstruct_putu32(reply, s->index); assert(s->sink_input); @@ -788,7 +788,7 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_prebuf(s->memblockq)); pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_minreq(s->memblockq)); } - + pa_pstream_send_tagstruct(c->pstream, reply); request_bytes(s); } @@ -797,7 +797,7 @@ static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma struct connection *c = userdata; uint32_t channel; assert(c && t); - + if (pa_tagstruct_getu32(t, &channel) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -832,7 +832,7 @@ static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma upload_stream_free(s); } - + pa_pstream_send_simple_ack(c->pstream, tag); } @@ -848,7 +848,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_source *source = NULL; int corked; assert(c && t && c->protocol && c->protocol->core); - + if (pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_get_sample_spec(t, &ss) < 0 || pa_tagstruct_get_channel_map(t, &map) < 0 || @@ -876,13 +876,13 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ } else if (source_name) { source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE, 1); CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY); - } - + } + s = record_stream_new(c, source, &ss, &map, name, maxlength, fragment_size); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); - + pa_source_output_cork(s->source_output, corked); - + reply = reply_new(tag); pa_tagstruct_putu32(reply, s->index); assert(s->source_output); @@ -894,21 +894,21 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_maxlength(s->memblockq)); pa_tagstruct_putu32(reply, (uint32_t) s->fragment_size); } - + pa_pstream_send_tagstruct(c->pstream, reply); } static void command_exit(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; assert(c && t); - + if (!pa_tagstruct_eof(t)) { protocol_error(c); return; } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop); c->protocol->core->mainloop->quit(c->protocol->core->mainloop, 0); pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */ @@ -935,7 +935,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t if (!c->authorized) { int success = 0; - + #ifdef HAVE_CREDS const pa_creds *creds; @@ -950,7 +950,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t pa_log_warn("failed to get GID of group '%s'", c->protocol->auth_group); else if (gid == creds->gid) success = 1; - + if (!success) { if ((r = pa_uid_in_group(creds->uid, c->protocol->auth_group)) < 0) pa_log_warn("failed to check group membership."); @@ -958,7 +958,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t success = 1; } } - + pa_log_info("Got credentials: uid=%lu gid=%lu success=%i", (unsigned long) creds->uid, (unsigned long) creds->gid, @@ -971,7 +971,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t pa_pstream_use_shm(c->pstream, 1); pa_log_info("Enabled SHM for new connection"); } - + } #endif @@ -983,7 +983,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return; } - + c->authorized = 1; if (c->auth_timeout_event) { c->protocol->core->mainloop->time_free(c->auth_timeout_event); @@ -997,12 +997,12 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t #ifdef HAVE_CREDS { /* SHM support is only enabled after both sides made sure they are the same user. */ - + pa_creds ucred; ucred.uid = getuid(); ucred.gid = getgid(); - + pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred); } #else @@ -1022,7 +1022,7 @@ static void command_set_client_name(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE } CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID); - + pa_client_set_name(c->client, name); pa_pstream_send_simple_ack(c->pstream, tag); } @@ -1079,11 +1079,11 @@ static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC s = pa_idxset_get_by_index(c->output_streams, idx); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); - + s->drain_request = 0; pa_memblockq_prebuf_disable(s->memblockq); - + if (!pa_memblockq_is_readable(s->memblockq)) { /* pa_log("immediate drain: %u", pa_memblockq_get_length(s->memblockq)); */ pa_pstream_send_simple_ack(c->pstream, tag); @@ -1094,7 +1094,7 @@ static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC pa_sink_notify(s->sink_input->sink); } -} +} static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; @@ -1110,7 +1110,7 @@ static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); stat = pa_mempool_get_stat(c->protocol->core->mempool); - + reply = reply_new(tag); pa_tagstruct_putu32(reply, (uint32_t) AO_load_acquire_read((AO_t*) &stat->n_allocated)); pa_tagstruct_putu32(reply, (uint32_t) AO_load_acquire_read((AO_t*) &stat->allocated_size)); @@ -1128,7 +1128,7 @@ static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ uint32_t idx; pa_usec_t latency; assert(c && t); - + if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_get_timeval(t, &tv) < 0 || !pa_tagstruct_eof(t)) { @@ -1147,7 +1147,7 @@ static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ if (s->sink_input->resampled_chunk.memblock) latency += pa_bytes_to_usec(s->sink_input->resampled_chunk.length, &s->sink_input->sample_spec); pa_tagstruct_put_usec(reply, latency); - + pa_tagstruct_put_usec(reply, 0); pa_tagstruct_put_boolean(reply, s->sink_input->state == PA_SINK_INPUT_RUNNING); pa_tagstruct_put_timeval(reply, &tv); @@ -1196,8 +1196,8 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_channel_map map; pa_tagstruct *reply; assert(c && t && c->protocol && c->protocol->core); - - if (pa_tagstruct_gets(t, &name) < 0 || + + if (pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_get_sample_spec(t, &ss) < 0 || pa_tagstruct_get_channel_map(t, &map) < 0 || pa_tagstruct_getu32(t, &length) < 0 || @@ -1213,10 +1213,10 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE); CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); - + s = upload_stream_new(c, &ss, &map, name, length); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); - + reply = reply_new(tag); pa_tagstruct_putu32(reply, s->index); pa_tagstruct_putu32(reply, length); @@ -1229,7 +1229,7 @@ static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ struct upload_stream *s; uint32_t idx; assert(c && t); - + if (pa_tagstruct_getu32(t, &channel) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1246,7 +1246,7 @@ static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL); else pa_pstream_send_simple_ack(c->pstream, tag); - + upload_stream_free(s); } @@ -1266,7 +1266,7 @@ static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui protocol_error(c); return; } - + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, sink_index != PA_INVALID_INDEX || !sink_name || (*sink_name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); @@ -1455,7 +1455,7 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); } else if (command == PA_COMMAND_GET_CLIENT_INFO) client = pa_idxset_get_by_index(c->protocol->core->clients, idx); - else if (command == PA_COMMAND_GET_MODULE_INFO) + else if (command == PA_COMMAND_GET_MODULE_INFO) module = pa_idxset_get_by_index(c->protocol->core->modules, idx); else if (command == PA_COMMAND_GET_SINK_INPUT_INFO) si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); @@ -1468,7 +1468,7 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u else sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE, 0); } - + if (!sink && !source && !client && !module && !si && !so && !sce) { pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); return; @@ -1538,7 +1538,7 @@ static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma module_fill_tagstruct(reply, p); else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) sink_input_fill_tagstruct(reply, p); - else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST) + else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST) source_output_fill_tagstruct(reply, p); else { assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); @@ -1546,7 +1546,7 @@ static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma } } } - + pa_pstream_send_tagstruct(c->pstream, reply); } @@ -1561,7 +1561,7 @@ static void command_get_server_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE protocol_error(c); return; } - + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); reply = reply_new(tag); @@ -1577,7 +1577,7 @@ static void command_get_server_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE pa_tagstruct_puts(reply, n); pa_tagstruct_putu32(reply, c->protocol->core->cookie); - + pa_pstream_send_tagstruct(c->pstream, reply); } @@ -1607,7 +1607,7 @@ static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID); - + if (c->subscription) pa_subscription_free(c->subscription); @@ -1626,7 +1626,7 @@ static void command_set_volume( uint32_t tag, pa_tagstruct *t, void *userdata) { - + struct connection *c = userdata; uint32_t idx; pa_cvolume volume; @@ -1644,7 +1644,7 @@ static void command_set_volume( protocol_error(c); return; } - + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID); @@ -1682,7 +1682,7 @@ static void command_set_mute( uint32_t tag, pa_tagstruct *t, void *userdata) { - + struct connection *c = userdata; uint32_t idx; int mute; @@ -1698,7 +1698,7 @@ static void command_set_mute( protocol_error(c); return; } - + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); @@ -1758,9 +1758,9 @@ static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_sink_input_cork(ssync->sink_input, b); pa_memblockq_prebuf_force(ssync->memblockq); } - + pa_pstream_send_simple_ack(c->pstream, tag); -} +} static void command_flush_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; @@ -1782,7 +1782,7 @@ static void command_flush_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC pa_memblockq_flush(s->memblockq); s->underrun = 0; - + /* Do the same for all other members in the sync group */ for (ssync = s->prev; ssync; ssync = ssync->prev) { pa_memblockq_flush(ssync->memblockq); @@ -1793,11 +1793,11 @@ static void command_flush_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC pa_memblockq_flush(ssync->memblockq); ssync->underrun = 0; } - + pa_pstream_send_simple_ack(c->pstream, tag); pa_sink_notify(s->sink_input->sink); request_bytes(s); - + for (ssync = s->prev; ssync; ssync = ssync->prev) request_bytes(ssync); @@ -1827,11 +1827,11 @@ static void command_trigger_or_prebuf_playback_stream(PA_GCC_UNUSED pa_pdispatch case PA_COMMAND_PREBUF_PLAYBACK_STREAM: pa_memblockq_prebuf_force(s->memblockq); break; - + case PA_COMMAND_TRIGGER_PLAYBACK_STREAM: pa_memblockq_prebuf_disable(s->memblockq); break; - + default: abort(); } @@ -1914,22 +1914,22 @@ static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t com protocol_error(c); return; } - + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID); if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) { struct playback_stream *s; - + s = pa_idxset_get_by_index(c->output_streams, idx); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); pa_sink_input_set_name(s->sink_input, name); - + } else { struct record_stream *s; - + s = pa_idxset_get_by_index(c->record_streams, idx); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); @@ -1954,14 +1954,14 @@ static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint3 if (command == PA_COMMAND_KILL_CLIENT) { pa_client *client; - + client = pa_idxset_get_by_index(c->protocol->core->clients, idx); CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY); pa_client_kill(client); - + } else if (command == PA_COMMAND_KILL_SINK_INPUT) { pa_sink_input *s; - + s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); @@ -1970,7 +1970,7 @@ static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint3 pa_source_output *s; assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT); - + s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); @@ -1997,7 +1997,7 @@ static void command_load_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID); - + if (!(m = pa_module_load(c->protocol->core, name, argument))) { pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED); return; @@ -2019,7 +2019,7 @@ static void command_unload_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED protocol_error(c); return; } - + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); m = pa_idxset_get_by_index(c->protocol->core->modules, idx); CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY); @@ -2036,15 +2036,15 @@ static void command_add_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED u pa_tagstruct *reply; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || - pa_tagstruct_getu32(t, &type) < 0 || - pa_tagstruct_gets(t, &module) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_getu32(t, &type) < 0 || + pa_tagstruct_gets(t, &module) < 0 || pa_tagstruct_gets(t, &argument) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; } - + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, type == 0 || type == 1, tag, PA_ERR_INVALID); @@ -2075,12 +2075,12 @@ static void command_remove_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE protocol_error(c); return; } - + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, name || idx != PA_IDXSET_INVALID, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, !name || (*name && pa_utf8_valid(name) && (type == 0 || type == 1)), tag, PA_ERR_INVALID); - if (name) + if (name) r = pa_autoload_remove_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE); else r = pa_autoload_remove_by_index(c->protocol->core, idx); @@ -2141,7 +2141,7 @@ static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC protocol_error(c); return; } - + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); reply = reply_new(tag); @@ -2153,7 +2153,7 @@ static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC while ((a = pa_hashmap_iterate(c->protocol->core->autoload_hashmap, &state, NULL))) autoload_fill_tagstruct(reply, a); } - + pa_pstream_send_tagstruct(c->pstream, reply); } @@ -2161,7 +2161,7 @@ static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag struct connection *c = userdata; uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX; const char *name = NULL; - + assert(c); assert(t); @@ -2172,7 +2172,7 @@ static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag protocol_error(c); return; } - + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); @@ -2182,7 +2182,7 @@ static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag pa_sink *sink = NULL; si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); - + if (idx_device != PA_INVALID_INDEX) sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device); else @@ -2199,7 +2199,7 @@ static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag pa_source *source; so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); - + if (idx_device != PA_INVALID_INDEX) source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device); else @@ -2212,9 +2212,9 @@ static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag return; } } - + pa_pstream_send_simple_ack(c->pstream, tag); - + } /*** pstream callbacks ***/ @@ -2233,7 +2233,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o struct connection *c = userdata; struct output_stream *stream; assert(p && chunk && userdata); - + if (!(stream = pa_idxset_get_by_index(c->output_streams, channel))) { pa_log("client sent block for invalid stream."); /* Ignoring */ @@ -2251,12 +2251,12 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o if (pa_memblockq_push_align(ps->memblockq, chunk) < 0) { pa_tagstruct *t; - + pa_log_warn("failed to push data into queue"); /* Pushing this block into the queue failed, so we simulate * it by skipping ahead */ - + pa_memblockq_seek(ps->memblockq, chunk->length, PA_SEEK_RELATIVE); /* Notify the user */ @@ -2268,7 +2268,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o } ps->underrun = 0; - + pa_sink_notify(ps->sink_input->sink); } else { @@ -2286,10 +2286,10 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o u->memchunk.index = u->memchunk.length = 0; } } - + assert(u->memchunk.memblock); - - l = u->length; + + l = u->length; if (l > chunk->length) l = chunk->length; @@ -2355,7 +2355,7 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo pa_log_info("Client authenticated by IP ACL."); c->authorized = 1; } - + if (!c->authorized) { struct timeval tv; pa_gettimeofday(&tv); @@ -2374,7 +2374,7 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo c->client->kill = client_kill_cb; c->client->userdata = c; c->client->owner = p->module; - + c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool); assert(c->pstream); @@ -2399,7 +2399,7 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo #ifdef HAVE_CREDS if (pa_iochannel_creds_supported(io)) pa_iochannel_creds_enable(io); - + #endif } @@ -2409,14 +2409,14 @@ static int load_key(pa_protocol_native*p, const char*fn) { assert(p); p->auth_cookie_in_property = 0; - + if (!fn && pa_authkey_prop_get(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) { pa_log_info("using already loaded auth cookie."); pa_authkey_prop_ref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); p->auth_cookie_in_property = 1; return 0; } - + if (!fn) fn = PA_NATIVE_COOKIE_FILE; @@ -2427,7 +2427,7 @@ static int load_key(pa_protocol_native*p, const char*fn) { if (pa_authkey_prop_put(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) p->auth_cookie_in_property = 1; - + return 0; } @@ -2435,7 +2435,7 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo pa_protocol_native *p; int public = 0; const char *acl; - + assert(c); assert(ma); @@ -2443,14 +2443,14 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo pa_log("auth-anonymous= expects a boolean argument."); return NULL; } - + p = pa_xnew(pa_protocol_native, 1); p->core = c; p->module = m; p->public = public; p->server = NULL; p->auth_ip_acl = NULL; - + #ifdef HAVE_CREDS { int a = 1; @@ -2498,7 +2498,7 @@ pa_protocol_native* pa_protocol_native_new(pa_core *core, pa_socket_server *serv if (!(p = protocol_new_internal(core, m, ma))) return NULL; - + p->server = server; pa_socket_server_set_callback(p->server, on_connection, p); @@ -2508,7 +2508,7 @@ pa_protocol_native* pa_protocol_native_new(pa_core *core, pa_socket_server *serv l = pa_strlist_prepend(l, t); pa_property_replace(core, PA_NATIVE_SERVER_PROPERTY_NAME, l); } - + return p; } @@ -2522,7 +2522,7 @@ void pa_protocol_native_free(pa_protocol_native *p) { if (p->server) { char t[256]; - + if (pa_socket_server_get_address(p->server, t, sizeof(t))) { pa_strlist *l; l = pa_property_get(p->core, PA_NATIVE_SERVER_PROPERTY_NAME); @@ -2533,7 +2533,7 @@ void pa_protocol_native_free(pa_protocol_native *p) { else pa_property_remove(p->core, PA_NATIVE_SERVER_PROPERTY_NAME); } - + pa_socket_server_unref(p->server); } @@ -2542,7 +2542,7 @@ void pa_protocol_native_free(pa_protocol_native *p) { if (p->auth_ip_acl) pa_ip_acl_free(p->auth_ip_acl); - + #ifdef HAVE_CREDS pa_xfree(p->auth_group); #endif @@ -2556,6 +2556,6 @@ pa_protocol_native* pa_protocol_native_new_iochannel(pa_core*core, pa_iochannel return NULL; on_connection(NULL, io, p); - + return p; } diff --git a/src/pulsecore/protocol-native.h b/src/pulsecore/protocol-native.h index 5b091014..fcd4cb37 100644 --- a/src/pulsecore/protocol-native.h +++ b/src/pulsecore/protocol-native.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c index 6bfba875..0a7a7acb 100644 --- a/src/pulsecore/protocol-simple.c +++ b/src/pulsecore/protocol-simple.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -55,7 +55,7 @@ struct connection { pa_defer_event *defer_event; int dead; - + struct { pa_memblock *current_memblock; size_t memblock_index, fragment_size; @@ -120,7 +120,7 @@ static int do_read(struct connection *c) { if (l > c->playback.fragment_size) l = c->playback.fragment_size; - if (c->playback.current_memblock) + if (c->playback.current_memblock) if (c->playback.current_memblock->length - c->playback.memblock_index < l) { pa_memblock_unref(c->playback.current_memblock); c->playback.current_memblock = NULL; @@ -132,7 +132,7 @@ static int do_read(struct connection *c) { assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); c->playback.memblock_index = 0; } - + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { pa_log_debug("read(): %s", r == 0 ? "EOF" : pa_cstrerror(errno)); return -1; @@ -144,12 +144,12 @@ static int do_read(struct connection *c) { assert(chunk.memblock); c->playback.memblock_index += r; - + assert(c->input_memblockq); pa_memblockq_push_align(c->input_memblockq, &chunk); assert(c->sink_input); pa_sink_notify(c->sink_input->sink); - + return 0; } @@ -158,25 +158,25 @@ static int do_write(struct connection *c) { ssize_t r; if (!c->source_output) - return 0; + return 0; assert(c->output_memblockq); if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) return 0; - + assert(chunk.memblock && chunk.length); - + if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { pa_memblock_unref(chunk.memblock); pa_log("write(): %s", pa_cstrerror(errno)); return -1; } - + pa_memblockq_drop(c->output_memblockq, &chunk, r); pa_memblock_unref(chunk.memblock); pa_source_notify(c->source_output->source); - + return 0; } @@ -188,7 +188,7 @@ static void do_work(struct connection *c) { if (c->dead) return; - + if (pa_iochannel_is_readable(c->io)) { if (do_read(c) < 0) goto fail; @@ -198,7 +198,7 @@ static void do_work(struct connection *c) { if (pa_iochannel_is_writable(c->io)) { if (do_write(c) < 0) goto fail; - } + } return; @@ -206,7 +206,7 @@ fail: if (c->sink_input) { c->dead = 1; - + pa_iochannel_free(c->io); c->io = NULL; @@ -222,12 +222,12 @@ static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { struct connection*c; assert(i && i->userdata && chunk); c = i->userdata; - + if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) { - + if (c->dead) connection_free(c); - + return -1; } @@ -331,7 +331,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->playback.memblock_index = 0; c->playback.fragment_size = 0; c->dead = 0; - + pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); c->client = pa_client_new(p->core, __FILE__, cname); assert(c->client); @@ -354,7 +354,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) pa_log("Failed to create sink input."); goto fail; } - + c->sink_input->peek = sink_input_peek_cb; c->sink_input->drop = sink_input_drop_cb; c->sink_input->kill = sink_input_kill_cb; @@ -416,9 +416,9 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c); assert(c->defer_event); p->core->mainloop->defer_enable(c->defer_event, 0); - + return; - + fail: if (c) connection_free(c); @@ -443,7 +443,7 @@ pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *serv p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL)); p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); - + enable = 0; if (pa_modargs_get_value_boolean(ma, "record", &enable) < 0) { pa_log("record= expects a numeric argument."); @@ -462,9 +462,9 @@ pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *serv pa_log("neither playback nor recording enabled for protocol."); goto fail; } - + pa_socket_server_set_callback(p->server, on_connection, p); - + return p; fail: @@ -481,7 +481,7 @@ void pa_protocol_simple_free(pa_protocol_simple *p) { if (p->connections) { while((c = pa_idxset_first(p->connections, NULL))) connection_free(c); - + pa_idxset_free(p->connections, NULL, NULL); } diff --git a/src/pulsecore/protocol-simple.h b/src/pulsecore/protocol-simple.h index 8dfaee34..183f3acc 100644 --- a/src/pulsecore/protocol-simple.h +++ b/src/pulsecore/protocol-simple.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/pstream-util.c b/src/pulsecore/pstream-util.c index d7c1b31b..6ebb2863 100644 --- a/src/pulsecore/pstream-util.c +++ b/src/pulsecore/pstream-util.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/pstream-util.h b/src/pulsecore/pstream-util.h index c6d76a7c..5f1bbd60 100644 --- a/src/pulsecore/pstream-util.h +++ b/src/pulsecore/pstream-util.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index 566fb060..7e1e5f57 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -111,7 +111,7 @@ struct item_info { struct pa_pstream { PA_REFCNT_DECLARE; - + pa_mainloop_api *mainloop; pa_defer_event *defer_event; pa_iochannel *io; @@ -171,7 +171,7 @@ static void do_something(pa_pstream *p) { pa_pstream_ref(p); pa_mutex_lock(p->mutex); - + p->mainloop->defer_enable(p->defer_event, 0); if (!p->dead && pa_iochannel_is_readable(p->io)) { @@ -193,21 +193,21 @@ static void do_something(pa_pstream *p) { fail: p->dead = 1; - + if (p->die_callback) p->die_callback(p, p->die_callback_userdata); - + pa_mutex_unlock(p->mutex); - + pa_pstream_unref(p); } static void io_callback(pa_iochannel*io, void *userdata) { pa_pstream *p = userdata; - + assert(p); assert(p->io == io); - + do_something(p); } @@ -217,7 +217,7 @@ static void defer_callback(pa_mainloop_api *m, pa_defer_event *e, void*userdata) assert(p); assert(p->defer_event == e); assert(p->mainloop == m); - + do_something(p); } @@ -225,7 +225,7 @@ static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userd pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *pool) { pa_pstream *p; - + assert(m); assert(io); assert(pool); @@ -241,7 +241,7 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *poo p->mainloop = m; p->defer_event = m->defer_new(m, defer_callback, p); m->defer_enable(p->defer_event, 0); - + p->send_queue = pa_queue_new(); assert(p->send_queue); @@ -268,7 +268,7 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *poo /* We do importing unconditionally */ p->import = pa_memimport_new(p->mempool, memimport_release_cb, p); - pa_iochannel_socket_set_rcvbuf(io, 1024*8); + pa_iochannel_socket_set_rcvbuf(io, 1024*8); pa_iochannel_socket_set_sndbuf(io, 1024*8); #ifdef HAVE_CREDS @@ -297,7 +297,7 @@ static void pstream_free(pa_pstream *p) { assert(p); pa_pstream_close(p); - + pa_queue_free(p->send_queue, item_free, NULL); if (p->write.current) @@ -305,7 +305,7 @@ static void pstream_free(pa_pstream *p) { if (p->read.memblock) pa_memblock_unref(p->read.memblock); - + if (p->read.packet) pa_packet_unref(p->read.packet); @@ -323,14 +323,14 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *cre assert(packet); pa_mutex_lock(p->mutex); - + if (p->dead) goto finish; - + i = pa_xnew(struct item_info, 1); i->type = PA_PSTREAM_ITEM_PACKET; i->packet = pa_packet_ref(packet); - + #ifdef HAVE_CREDS if ((i->with_creds = !!creds)) i->creds = *creds; @@ -346,14 +346,14 @@ finish: void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek_mode, const pa_memchunk *chunk) { size_t length, idx; - + assert(p); assert(PA_REFCNT_VALUE(p) > 0); assert(channel != (uint32_t) -1); assert(chunk); pa_mutex_lock(p->mutex); - + if (p->dead) goto finish; @@ -363,7 +363,7 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa while (length > 0) { struct item_info *i; size_t n; - + i = pa_xnew(struct item_info, 1); i->type = PA_PSTREAM_ITEM_MEMBLOCK; @@ -371,24 +371,24 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa i->chunk.index = chunk->index + idx; i->chunk.length = n; i->chunk.memblock = pa_memblock_ref(chunk->memblock); - + i->channel = channel; i->offset = offset; i->seek_mode = seek_mode; #ifdef HAVE_CREDS i->with_creds = 0; #endif - + pa_queue_push(p->send_queue, i); idx += n; length -= n; } - + p->mainloop->defer_enable(p->defer_event, 1); finish: - + pa_mutex_unlock(p->mutex); } @@ -400,7 +400,7 @@ static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userd assert(PA_REFCNT_VALUE(p) > 0); pa_mutex_lock(p->mutex); - + if (p->dead) goto finish; @@ -429,12 +429,12 @@ static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userda assert(PA_REFCNT_VALUE(p) > 0); pa_mutex_lock(p->mutex); - + if (p->dead) goto finish; /* pa_log("Revoking block %u", block_id); */ - + item = pa_xnew(struct item_info, 1); item->type = PA_PSTREAM_ITEM_SHMREVOKE; item->block_id = block_id; @@ -456,7 +456,7 @@ static void prepare_next_write_item(pa_pstream *p) { if (!(p->write.current = pa_queue_pop(p->send_queue))) return; - + p->write.index = 0; p->write.data = NULL; @@ -465,9 +465,9 @@ static void prepare_next_write_item(pa_pstream *p) { p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = 0; p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = 0; p->write.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS] = 0; - + if (p->write.current->type == PA_PSTREAM_ITEM_PACKET) { - + assert(p->write.current->packet); p->write.data = p->write.current->packet->data; p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->packet->length); @@ -481,14 +481,14 @@ static void prepare_next_write_item(pa_pstream *p) { p->write.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS] = htonl(PA_FLAG_SHMREVOKE); p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = htonl(p->write.current->block_id); - + } else { uint32_t flags; int send_payload = 1; - + assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK); assert(p->write.current->chunk.memblock); - + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl(p->write.current->channel); p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = htonl((uint32_t) (((uint64_t) p->write.current->offset) >> 32)); p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = htonl((uint32_t) ((uint64_t) p->write.current->offset)); @@ -507,15 +507,15 @@ static void prepare_next_write_item(pa_pstream *p) { &shm_id, &offset, &length) >= 0) { - + flags |= PA_FLAG_SHMDATA; send_payload = 0; - + p->write.shm_info[PA_PSTREAM_SHM_BLOCKID] = htonl(block_id); p->write.shm_info[PA_PSTREAM_SHM_SHMID] = htonl(shm_id); p->write.shm_info[PA_PSTREAM_SHM_INDEX] = htonl((uint32_t) (offset + p->write.current->chunk.index)); p->write.shm_info[PA_PSTREAM_SHM_LENGTH] = htonl((uint32_t) p->write.current->chunk.length); - + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(sizeof(p->write.shm_info)); p->write.data = p->write.shm_info; } @@ -527,7 +527,7 @@ static void prepare_next_write_item(pa_pstream *p) { p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length); p->write.data = (uint8_t*) p->write.current->chunk.memblock->data + p->write.current->chunk.index; } - + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS] = htonl(flags); } @@ -541,7 +541,7 @@ static int do_write(pa_pstream *p) { void *d; size_t l; ssize_t r; - + assert(p); assert(PA_REFCNT_VALUE(p) > 0); @@ -556,13 +556,13 @@ static int do_write(pa_pstream *p) { l = PA_PSTREAM_DESCRIPTOR_SIZE - p->write.index; } else { assert(p->write.data); - + d = (uint8_t*) p->write.data + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE; l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE); } assert(l > 0); - + #ifdef HAVE_CREDS if (p->send_creds_now) { @@ -592,12 +592,12 @@ static int do_write(pa_pstream *p) { static int do_read(pa_pstream *p) { void *d; - size_t l; + size_t l; ssize_t r; - + assert(p); assert(PA_REFCNT_VALUE(p) > 0); - + if (p->read.index < PA_PSTREAM_DESCRIPTOR_SIZE) { d = (uint8_t*) p->read.descriptor + p->read.index; l = PA_PSTREAM_DESCRIPTOR_SIZE - p->read.index; @@ -610,7 +610,7 @@ static int do_read(pa_pstream *p) { #ifdef HAVE_CREDS { int b = 0; - + if ((r = pa_iochannel_read_with_creds(p->io, d, l, &p->read_creds, &b)) <= 0) return -1; @@ -620,7 +620,7 @@ static int do_read(pa_pstream *p) { if ((r = pa_iochannel_read(p->io, d, l)) <= 0) return -1; #endif - + p->read.index += r; if (p->read.index == PA_PSTREAM_DESCRIPTOR_SIZE) { @@ -633,18 +633,18 @@ static int do_read(pa_pstream *p) { pa_log_warn("Recieved SHM frame on a socket where SHM is disabled."); return -1; } - + if (flags == PA_FLAG_SHMRELEASE) { /* This is a SHM memblock release frame with no payload */ /* pa_log("Got release frame for %u", ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); */ - + assert(p->export); pa_memexport_process_release(p->export, ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); goto frame_done; - + } else if (flags == PA_FLAG_SHMREVOKE) { /* This is a SHM memblock revoke frame with no payload */ @@ -658,68 +658,68 @@ static int do_read(pa_pstream *p) { } length = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]); - + if (length > FRAME_SIZE_MAX_ALLOW) { pa_log_warn("Recieved invalid frame size : %lu", (unsigned long) length); return -1; } - + assert(!p->read.packet && !p->read.memblock); channel = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]); - + if (channel == (uint32_t) -1) { if (flags != 0) { pa_log_warn("Received packet frame with invalid flags value."); return -1; } - + /* Frame is a packet frame */ p->read.packet = pa_packet_new(length); p->read.data = p->read.packet->data; - + } else { if ((flags & PA_FLAG_SEEKMASK) > PA_SEEK_RELATIVE_END) { pa_log_warn("Received memblock frame with invalid seek mode."); return -1; } - + if ((flags & PA_FLAG_SHMMASK) == PA_FLAG_SHMDATA) { if (length != sizeof(p->read.shm_info)) { pa_log_warn("Recieved SHM memblock frame with Invalid frame length."); return -1; } - + /* Frame is a memblock frame referencing an SHM memblock */ p->read.data = p->read.shm_info; } else if ((flags & PA_FLAG_SHMMASK) == 0) { /* Frame is a memblock frame */ - + p->read.memblock = pa_memblock_new(p->mempool, length); p->read.data = p->read.memblock->data; } else { - + pa_log_warn("Recieved memblock frame with invalid flags value."); return -1; } } - + } else if (p->read.index > PA_PSTREAM_DESCRIPTOR_SIZE) { /* Frame payload available */ - + if (p->read.memblock && p->recieve_memblock_callback) { /* Is this memblock data? Than pass it to the user */ l = (p->read.index - r) < PA_PSTREAM_DESCRIPTOR_SIZE ? p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE : (size_t) r; - + if (l > 0) { pa_memchunk chunk; - + chunk.memblock = p->read.memblock; chunk.index = p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE - l; chunk.length = l; @@ -730,7 +730,7 @@ static int do_read(pa_pstream *p) { offset = (int64_t) ( (((uint64_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])) << 32) | (((uint64_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO])))); - + p->recieve_memblock_callback( p, ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]), @@ -749,14 +749,14 @@ static int do_read(pa_pstream *p) { /* Frame complete */ if (p->read.index >= ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) + PA_PSTREAM_DESCRIPTOR_SIZE) { - + if (p->read.memblock) { /* This was a memblock frame. We can unref the memblock now */ pa_memblock_unref(p->read.memblock); } else if (p->read.packet) { - + if (p->recieve_packet_callback) #ifdef HAVE_CREDS p->recieve_packet_callback(p, p->read.packet, p->read_creds_valid ? &p->read_creds : NULL, p->recieve_packet_callback_userdata); @@ -767,7 +767,7 @@ static int do_read(pa_pstream *p) { pa_packet_unref(p->read.packet); } else { pa_memblock *b; - + assert((ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]) & PA_FLAG_SHMMASK) == PA_FLAG_SHMDATA); assert(p->import); @@ -785,7 +785,7 @@ static int do_read(pa_pstream *p) { if (p->recieve_memblock_callback) { int64_t offset; pa_memchunk chunk; - + chunk.memblock = b; chunk.index = 0; chunk.length = b->length; @@ -793,7 +793,7 @@ static int do_read(pa_pstream *p) { offset = (int64_t) ( (((uint64_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])) << 32) | (((uint64_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO])))); - + p->recieve_memblock_callback( p, ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]), @@ -827,7 +827,7 @@ frame_done: void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) { assert(p); assert(PA_REFCNT_VALUE(p) > 0); - + pa_mutex_lock(p->mutex); p->die_callback = cb; p->die_callback_userdata = userdata; @@ -893,7 +893,7 @@ void pa_pstream_unref(pa_pstream*p) { pa_pstream* pa_pstream_ref(pa_pstream*p) { assert(p); assert(PA_REFCNT_VALUE(p) > 0); - + PA_REFCNT_INC(p); return p; } @@ -902,7 +902,7 @@ void pa_pstream_close(pa_pstream *p) { assert(p); pa_mutex_lock(p->mutex); - + p->dead = 1; if (p->import) { @@ -942,7 +942,7 @@ void pa_pstream_use_shm(pa_pstream *p, int enable) { p->use_shm = enable; if (enable) { - + if (!p->export) p->export = pa_memexport_new(p->mempool, memexport_revoke_cb, p); diff --git a/src/pulsecore/pstream.h b/src/pulsecore/pstream.h index 26bb7699..0ab16720 100644 --- a/src/pulsecore/pstream.h +++ b/src/pulsecore/pstream.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/queue.c b/src/pulsecore/queue.c index 93b119eb..3132c5c5 100644 --- a/src/pulsecore/queue.c +++ b/src/pulsecore/queue.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -99,7 +99,7 @@ void* pa_queue_pop(pa_queue *q) { pa_xfree(e); q->length--; - + return p; } diff --git a/src/pulsecore/queue.h b/src/pulsecore/queue.h index 3fb9dea4..cebe4cdf 100644 --- a/src/pulsecore/queue.h +++ b/src/pulsecore/queue.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/random.c b/src/pulsecore/random.c index 7908e87d..c3184c78 100644 --- a/src/pulsecore/random.c +++ b/src/pulsecore/random.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/random.h b/src/pulsecore/random.h index b2bb3934..cdac9ac6 100644 --- a/src/pulsecore/random.h +++ b/src/pulsecore/random.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -26,5 +26,5 @@ void pa_random_seed(void); void pa_random(void *ret_data, size_t length); - + #endif diff --git a/src/pulsecore/refcnt.h b/src/pulsecore/refcnt.h index 6eb5ee3f..f3918213 100644 --- a/src/pulsecore/refcnt.h +++ b/src/pulsecore/refcnt.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index b0142049..e61864dd 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -54,7 +54,7 @@ struct impl_libsamplerate { pa_memblock *buf1_block, *buf2_block, *buf3_block, *buf4_block; float* buf1, *buf2, *buf3, *buf4; unsigned buf1_samples, buf2_samples, buf3_samples, buf4_samples; - + pa_convert_to_float32ne_func_t to_float32ne_func; pa_convert_from_float32ne_func_t from_float32ne_func; SRC_STATE *src_state; @@ -78,7 +78,7 @@ pa_resampler* pa_resampler_new( const pa_sample_spec *b, const pa_channel_map *bm, pa_resample_method_t resample_method) { - + pa_resampler *r = NULL; assert(pool); @@ -110,7 +110,7 @@ pa_resampler* pa_resampler_new( r->o_cm = *bm; else pa_channel_map_init_auto(&r->o_cm, r->o_ss.channels, PA_CHANNEL_MAP_DEFAULT); - + r->i_fz = pa_frame_size(a); r->o_fz = pa_frame_size(b); @@ -126,19 +126,19 @@ pa_resampler* pa_resampler_new( if (libsamplerate_init(r) < 0) goto fail; - + } else { /* Use our own simple non-fp resampler for the trivial cases and when the user selects it */ if (trivial_init(r) < 0) goto fail; } - + return r; - + fail: if (r) pa_xfree(r); - + return NULL; } @@ -147,7 +147,7 @@ void pa_resampler_free(pa_resampler *r) { if (r->impl_free) r->impl_free(r); - + pa_xfree(r); } @@ -157,9 +157,9 @@ void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate) { if (r->i_ss.rate == rate) return; - + r->i_ss.rate = rate; - + if (r->impl_update_input_rate) r->impl_update_input_rate(r, rate); } @@ -172,7 +172,7 @@ void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) size_t pa_resampler_request(pa_resampler *r, size_t out_length) { assert(r); - + return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz; } @@ -200,7 +200,7 @@ const char *pa_resample_method_to_string(pa_resample_method_t m) { pa_resample_method_t pa_parse_resample_method(const char *string) { pa_resample_method_t m; - + assert(string); for (m = 0; m < PA_RESAMPLER_MAX; m++) @@ -218,9 +218,9 @@ static void libsamplerate_free(pa_resampler *r) { assert(r); assert(r->impl_data); - + u = r->impl_data; - + if (u->src_state) src_delete(u->src_state); @@ -251,16 +251,16 @@ static void calc_map_table(pa_resampler *r) { for (ic = 0; ic < r->i_ss.channels; ic++) { pa_channel_position_t a, b; - + a = r->i_cm.map[ic]; b = r->o_cm.map[oc]; - + if (a == b || (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_LEFT) || (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_RIGHT) || (a == PA_CHANNEL_POSITION_LEFT && b == PA_CHANNEL_POSITION_MONO) || (a == PA_CHANNEL_POSITION_RIGHT && b == PA_CHANNEL_POSITION_MONO)) - + u->map_table[oc][i++] = ic; } @@ -278,12 +278,12 @@ static float * convert_to_float(pa_resampler *r, void *input, unsigned n_frames) assert(input); assert(r->impl_data); u = r->impl_data; - + /* Convert the incoming sample into floats and place them in buf1 */ if (!u->to_float32ne_func) return input; - + n_samples = n_frames * r->i_ss.channels; if (u->buf1_samples < n_samples) { @@ -294,7 +294,7 @@ static float * convert_to_float(pa_resampler *r, void *input, unsigned n_frames) u->buf1_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples); u->buf1 = u->buf1_block->data; } - + u->to_float32ne_func(n_samples, input, u->buf1); return u->buf1; @@ -305,14 +305,14 @@ static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) { unsigned n_samples; int i_skip, o_skip; unsigned oc; - + assert(r); assert(input); assert(r->impl_data); u = r->impl_data; /* Remap channels and place the result int buf2 */ - + if (!u->map_required) return input; @@ -331,7 +331,7 @@ static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) { o_skip = sizeof(float) * r->o_ss.channels; i_skip = sizeof(float) * r->i_ss.channels; - + for (oc = 0; oc < r->o_ss.channels; oc++) { unsigned i; static const float one = 1.0; @@ -361,7 +361,7 @@ static float *resample(pa_resampler *r, float *input, unsigned *n_frames) { u = r->impl_data; /* Resample the data and place the result in buf3 */ - + if (!u->src_state) return input; @@ -376,16 +376,16 @@ static float *resample(pa_resampler *r, float *input, unsigned *n_frames) { u->buf3_block = pa_memblock_new(r->mempool, sizeof(float) * out_n_samples); u->buf3 = u->buf3_block->data; } - + data.data_in = input; data.input_frames = *n_frames; data.data_out = u->buf3; data.output_frames = out_n_frames; - + data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate; data.end_of_input = 0; - + ret = src_process(u->src_state, &data); assert(ret == 0); assert((unsigned) data.input_frames_used == *n_frames); @@ -398,17 +398,17 @@ static float *resample(pa_resampler *r, float *input, unsigned *n_frames) { static void *convert_from_float(pa_resampler *r, float *input, unsigned n_frames) { struct impl_libsamplerate *u; unsigned n_samples; - + assert(r); assert(input); assert(r->impl_data); u = r->impl_data; - + /* Convert the data into the correct sample type and place the result in buf4 */ if (!u->from_float32ne_func) return input; - + n_samples = n_frames * r->o_ss.channels; if (u->buf4_samples < n_samples) { @@ -419,7 +419,7 @@ static void *convert_from_float(pa_resampler *r, float *input, unsigned n_frames u->buf4_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples); u->buf4 = u->buf4_block->data; } - + u->from_float32ne_func(n_samples, input, u->buf4); return u->buf4; @@ -438,13 +438,13 @@ static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchun assert(in->memblock); assert(in->length % r->i_fz == 0); assert(r->impl_data); - + u = r->impl_data; input = ((uint8_t*) in->memblock->data + in->index); n_frames = in->length / r->i_fz; assert(n_frames > 0); - + buf = convert_to_float(r, input, n_frames); buf = remap_channels(r, buf, n_frames); buf = resample(r, buf, &n_frames); @@ -461,7 +461,7 @@ static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchun out->length = n_frames * r->o_fz; out->index = 0; out->memblock = NULL; - + if (output == u->buf1) { u->buf1 = NULL; u->buf1_samples = 0; @@ -494,7 +494,7 @@ static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchun static void libsamplerate_update_input_rate(pa_resampler *r, uint32_t rate) { struct impl_libsamplerate *u; - + assert(r); assert(rate > 0); assert(r->impl_data); @@ -540,7 +540,7 @@ static int libsamplerate_init(pa_resampler *r) { r->impl_run = libsamplerate_run; calc_map_table(r); - + return 0; fail: @@ -559,7 +559,7 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out assert(in); assert(out); assert(r->impl_data); - + u = r->impl_data; fz = r->i_fz; @@ -578,34 +578,34 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out /* Do real resampling */ size_t l; unsigned o_index; - + /* The length of the new memory block rounded up */ l = ((((n_frames+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz; - + out->index = 0; out->memblock = pa_memblock_new(r->mempool, l); - + for (o_index = 0;; o_index++, u->o_counter++) { unsigned j; - + j = (u->o_counter * r->i_ss.rate / r->o_ss.rate); j = j > u->i_counter ? j - u->i_counter : 0; - + if (j >= n_frames) break; assert(o_index*fz < out->memblock->length); - + memcpy((uint8_t*) out->memblock->data + fz*o_index, (uint8_t*) in->memblock->data + in->index + fz*j, fz); - + } - + out->length = o_index*fz; } u->i_counter += n_frames; - + /* Normalize counters */ while (u->i_counter >= r->i_ss.rate) { u->i_counter -= r->i_ss.rate; @@ -616,7 +616,7 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out static void trivial_free(pa_resampler *r) { assert(r); - + pa_xfree(r->impl_data); } @@ -634,7 +634,7 @@ static void trivial_update_input_rate(pa_resampler *r, uint32_t rate) { static int trivial_init(pa_resampler*r) { struct impl_trivial *u; - + assert(r); assert(r->i_ss.format == r->o_ss.format); assert(r->i_ss.channels == r->o_ss.channels); @@ -645,7 +645,7 @@ static int trivial_init(pa_resampler*r) { r->impl_run = trivial_run; r->impl_free = trivial_free; r->impl_update_input_rate = trivial_update_input_rate; - + return 0; } diff --git a/src/pulsecore/resampler.h b/src/pulsecore/resampler.h index 327e24a2..7a781364 100644 --- a/src/pulsecore/resampler.h +++ b/src/pulsecore/resampler.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index a7a5ed8f..ddf72920 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -78,7 +78,7 @@ void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { default: assert(0); } - + memset(p, c, length); } @@ -90,42 +90,42 @@ size_t pa_mix( const pa_sample_spec *spec, const pa_cvolume *volume, int mute) { - + assert(streams && data && length && spec); switch (spec->format) { case PA_SAMPLE_S16NE:{ size_t d; unsigned channel = 0; - + for (d = 0;; d += sizeof(int16_t)) { int32_t sum = 0; - + if (d >= length) return d; if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { unsigned i; - + for (i = 0; i < nstreams; i++) { int32_t v; pa_volume_t cvolume = streams[i].volume.values[channel]; - + if (d >= streams[i].chunk.length) return d; - + if (cvolume == PA_VOLUME_MUTED) v = 0; else { v = *((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); - + if (cvolume != PA_VOLUME_NORM) v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); } - + sum += v; } - + if (volume->values[channel] != PA_VOLUME_NORM) sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); @@ -133,10 +133,10 @@ size_t pa_mix( if (sum > 0x7FFF) sum = 0x7FFF; } - + *((int16_t*) data) = sum; data = (uint8_t*) data + sizeof(int16_t); - + if (++channel >= spec->channels) channel = 0; } @@ -145,35 +145,35 @@ size_t pa_mix( case PA_SAMPLE_S16RE:{ size_t d; unsigned channel = 0; - + for (d = 0;; d += sizeof(int16_t)) { int32_t sum = 0; - + if (d >= length) return d; if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { unsigned i; - + for (i = 0; i < nstreams; i++) { int32_t v; pa_volume_t cvolume = streams[i].volume.values[channel]; - + if (d >= streams[i].chunk.length) return d; - + if (cvolume == PA_VOLUME_MUTED) v = 0; else { v = INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d))); - + if (cvolume != PA_VOLUME_NORM) v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); } - + sum += v; } - + if (volume->values[channel] != PA_VOLUME_NORM) sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); @@ -181,40 +181,40 @@ size_t pa_mix( if (sum > 0x7FFF) sum = 0x7FFF; } - + *((int16_t*) data) = INT16_SWAP(sum); data = (uint8_t*) data + sizeof(int16_t); - + if (++channel >= spec->channels) channel = 0; } } - + case PA_SAMPLE_U8: { size_t d; unsigned channel = 0; - + for (d = 0;; d ++) { int32_t sum = 0; - + if (d >= length) return d; if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { unsigned i; - + for (i = 0; i < nstreams; i++) { int32_t v; pa_volume_t cvolume = streams[i].volume.values[channel]; - + if (d >= streams[i].chunk.length) return d; - + if (cvolume == PA_VOLUME_MUTED) v = 0; else { v = (int32_t) *((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d) - 0x80; - + if (cvolume != PA_VOLUME_NORM) v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); } @@ -229,51 +229,51 @@ size_t pa_mix( if (sum > 0x7F) sum = 0x7F; } - + *((uint8_t*) data) = (uint8_t) (sum + 0x80); data = (uint8_t*) data + 1; - + if (++channel >= spec->channels) channel = 0; } } - + case PA_SAMPLE_FLOAT32NE: { size_t d; unsigned channel = 0; - + for (d = 0;; d += sizeof(float)) { float sum = 0; - + if (d >= length) return d; - + if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { unsigned i; - + for (i = 0; i < nstreams; i++) { float v; pa_volume_t cvolume = streams[i].volume.values[channel]; - + if (d >= streams[i].chunk.length) return d; - + if (cvolume == PA_VOLUME_MUTED) v = 0; else { v = *((float*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); - + if (cvolume != PA_VOLUME_NORM) v *= pa_sw_volume_to_linear(cvolume); } - + sum += v; } - + if (volume->values[channel] != PA_VOLUME_NORM) sum *= pa_sw_volume_to_linear(volume->values[channel]); } - + *((float*) data) = sum; data = (uint8_t*) data + sizeof(float); @@ -281,7 +281,7 @@ size_t pa_mix( channel = 0; } } - + default: pa_log_error("ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format)); abort(); @@ -310,17 +310,17 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol for (channel = 0; channel < spec->channels; channel++) linear[channel] = pa_sw_volume_to_linear(volume->values[channel]); - + for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { int32_t t = (int32_t)(*d); - + t = (int32_t) (t * linear[channel]); - + if (t < -0x8000) t = -0x8000; if (t > 0x7FFF) t = 0x7FFF; - + *d = (int16_t) t; - + if (++channel >= spec->channels) channel = 0; } @@ -332,66 +332,66 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol size_t n; unsigned channel; double linear[PA_CHANNELS_MAX]; - + for (channel = 0; channel < spec->channels; channel++) linear[channel] = pa_sw_volume_to_linear(volume->values[channel]); - + for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { int32_t t = (int32_t)(INT16_SWAP(*d)); - + t = (int32_t) (t * linear[channel]); - + if (t < -0x8000) t = -0x8000; if (t > 0x7FFF) t = 0x7FFF; - + *d = INT16_SWAP((int16_t) t); - + if (++channel >= spec->channels) channel = 0; } break; } - + case PA_SAMPLE_U8: { uint8_t *d; size_t n; unsigned channel = 0; - + for (d = (uint8_t*) c->memblock->data + c->index, n = c->length; n > 0; d++, n--) { int32_t t = (int32_t) *d - 0x80; - + t = (int32_t) (t * pa_sw_volume_to_linear(volume->values[channel])); - + if (t < -0x80) t = -0x80; if (t > 0x7F) t = 0x7F; - + *d = (uint8_t) (t + 0x80); - + if (++channel >= spec->channels) channel = 0; } break; } - + case PA_SAMPLE_FLOAT32NE: { float *d; int skip; unsigned n; unsigned channel; - + d = (float*) ((uint8_t*) c->memblock->data + c->index); skip = spec->channels * sizeof(float); n = c->length/sizeof(float)/spec->channels; - + for (channel = 0; channel < spec->channels ; channel ++) { float v, *t; - + if (volume->values[channel] == PA_VOLUME_NORM) continue; - + v = (float) pa_sw_volume_to_linear(volume->values[channel]); - + t = d + channel; oil_scalarmult_f32(t, skip, t, skip, &v, n); } diff --git a/src/pulsecore/sample-util.h b/src/pulsecore/sample-util.h index 6b770792..1883b2cc 100644 --- a/src/pulsecore/sample-util.h +++ b/src/pulsecore/sample-util.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/sconv-s16be.c b/src/pulsecore/sconv-s16be.c index 5ac96320..3af167df 100644 --- a/src/pulsecore/sconv-s16be.c +++ b/src/pulsecore/sconv-s16be.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/sconv-s16be.h b/src/pulsecore/sconv-s16be.h index bd3fd345..b96f59ab 100644 --- a/src/pulsecore/sconv-s16be.h +++ b/src/pulsecore/sconv-s16be.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/sconv-s16le.c b/src/pulsecore/sconv-s16le.c index d8b93cbd..1743d61f 100644 --- a/src/pulsecore/sconv-s16le.c +++ b/src/pulsecore/sconv-s16le.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -58,7 +58,7 @@ void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b) { assert(b); #if SWAP_WORDS == 1 - + for (; n > 0; n--) { int16_t s = *(ca++); *(b++) = ((float) INT16_FROM(s))/0x7FFF; @@ -74,19 +74,19 @@ void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b) { void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b) { int16_t *cb = b; - + assert(a); assert(b); #if SWAP_WORDS == 1 - + for (; n > 0; n--) { int16_t s; float v = *(a++); if (v > 1) v = 1; - + if (v < -1) v = -1; diff --git a/src/pulsecore/sconv-s16le.h b/src/pulsecore/sconv-s16le.h index ae6e22d2..37e85e2f 100644 --- a/src/pulsecore/sconv-s16le.h +++ b/src/pulsecore/sconv-s16le.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/sconv.c b/src/pulsecore/sconv.c index 2e5e2dbe..6bea0608 100644 --- a/src/pulsecore/sconv.c +++ b/src/pulsecore/sconv.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -41,12 +41,12 @@ static void u8_to_float32ne(unsigned n, const void *a, float *b) { const uint8_t *ca = a; static const double add = -128.0/127.0, factor = 1.0/127.0; - + assert(a); assert(b); oil_scaleconv_f32_u8(b, ca, n, &add, &factor); -} +} static void u8_from_float32ne(unsigned n, const float *a, void *b) { uint8_t *cb = b; @@ -93,7 +93,7 @@ static void ulaw_to_float32ne(unsigned n, const void *a, float *b) { assert(a); assert(b); - + for (; n > 0; n--) *(b++) = st_ulaw2linear16(*(ca++)) * 1.0F / 0x7FFF; } @@ -103,7 +103,7 @@ static void ulaw_from_float32ne(unsigned n, const float *a, void *b) { assert(a); assert(b); - + for (; n > 0; n--) { float v = *(a++); @@ -132,7 +132,7 @@ static void alaw_from_float32ne(unsigned n, const float *a, void *b) { assert(a); assert(b); - + for (; n > 0; n--) { float v = *(a++); diff --git a/src/pulsecore/sconv.h b/src/pulsecore/sconv.h index 4aba0694..52240fd3 100644 --- a/src/pulsecore/sconv.h +++ b/src/pulsecore/sconv.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c index 19731b5f..6188b16c 100644 --- a/src/pulsecore/shm.c +++ b/src/pulsecore/shm.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -45,7 +45,7 @@ #if defined(__linux__) && !defined(MADV_REMOVE) #define MADV_REMOVE 9 -#endif +#endif #define MAX_SHM_SIZE (1024*1024*20) @@ -57,7 +57,7 @@ static char *segment_name(char *fn, size_t l, unsigned id) { int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { char fn[32]; int fd = -1; - + assert(m); assert(size > 0); assert(size < MAX_SHM_SIZE); @@ -75,7 +75,7 @@ int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { #elif defined(HAVE_POSIX_MEMALIGN) { int r; - + if ((r = posix_memalign(&m->ptr, sysconf(_SC_PAGESIZE), size)) < 0) { pa_log("posix_memalign() failed: %s", pa_cstrerror(r)); goto fail; @@ -84,9 +84,9 @@ int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { #else m->ptr = pa_xmalloc(m->size); #endif - + m->do_unlink = 0; - + } else { #ifdef HAVE_SHM_OPEN pa_random(&m->id, sizeof(m->id)); @@ -96,12 +96,12 @@ int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { pa_log("shm_open() failed: %s", pa_cstrerror(errno)); goto fail; } - + if (ftruncate(fd, m->size = size) < 0) { pa_log("ftruncate() failed: %s", pa_cstrerror(errno)); goto fail; } - + if ((m->ptr = mmap(NULL, m->size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { pa_log("mmap() failed: %s", pa_cstrerror(errno)); goto fail; @@ -115,9 +115,9 @@ int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { } m->shared = shared; - + return 0; - + fail: #ifdef HAVE_SHM_OPEN @@ -157,7 +157,7 @@ void pa_shm_free(pa_shm *m) { char fn[32]; segment_name(fn, sizeof(fn), m->id); - + if (shm_unlink(fn) < 0) pa_log(" shm_unlink(%s) failed: %s", fn, pa_cstrerror(errno)); } @@ -172,7 +172,7 @@ void pa_shm_free(pa_shm *m) { void pa_shm_punch(pa_shm *m, size_t offset, size_t size) { void *ptr; - + assert(m); assert(m->ptr); assert(m->size > 0); @@ -186,7 +186,7 @@ void pa_shm_punch(pa_shm *m, size_t offset, size_t size) { * support it */ ptr = (uint8_t*) m->ptr + offset; - + #ifdef __linux__ { /* On Linux ptr must be page aligned */ @@ -194,14 +194,14 @@ void pa_shm_punch(pa_shm *m, size_t offset, size_t size) { unsigned o; o = ((unsigned long) ptr) - ((((unsigned long) ptr)/psz) * psz); - + if (o > 0) { ptr = (uint8_t*) ptr + (psz - o); size -= psz - o; } } #endif - + #ifdef MADV_REMOVE if (madvise(ptr, size, MADV_REMOVE) >= 0) return; @@ -210,8 +210,8 @@ void pa_shm_punch(pa_shm *m, size_t offset, size_t size) { #ifdef MADV_FREE if (madvise(ptr, size, MADV_FREE) >= 0) return; -#endif - +#endif + #ifdef MADV_DONTNEED madvise(ptr, size, MADV_DONTNEED); #endif @@ -244,7 +244,7 @@ int pa_shm_attach_ro(pa_shm *m, unsigned id) { } m->size = st.st_size; - + if ((m->ptr = mmap(NULL, m->size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { pa_log("mmap() failed: %s", pa_cstrerror(errno)); goto fail; @@ -252,11 +252,11 @@ int pa_shm_attach_ro(pa_shm *m, unsigned id) { m->do_unlink = 0; m->shared = 1; - + close(fd); - + return 0; - + fail: if (fd >= 0) close(fd); diff --git a/src/pulsecore/shm.h b/src/pulsecore/shm.h index ea72403a..f621474c 100644 --- a/src/pulsecore/shm.h +++ b/src/pulsecore/shm.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index d948f0a4..58fe37d5 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -51,7 +51,7 @@ if (!(condition)) \ pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data) { assert(data); - + memset(data, 0, sizeof(*data)); data->resample_method = PA_RESAMPLER_INVALID; return data; @@ -82,7 +82,7 @@ pa_sink_input* pa_sink_input_new( pa_core *core, pa_sink_input_new_data *data, pa_sink_input_flags_t flags) { - + pa_sink_input *i; pa_resampler *resampler = NULL; int r; @@ -100,21 +100,21 @@ pa_sink_input* pa_sink_input_new( if (!data->sink) data->sink = pa_namereg_get(core, NULL, PA_NAMEREG_SINK, 1); - + CHECK_VALIDITY_RETURN_NULL(data->sink); CHECK_VALIDITY_RETURN_NULL(data->sink->state == PA_SINK_RUNNING); if (!data->sample_spec_is_set) data->sample_spec = data->sink->sample_spec; - + CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(&data->sample_spec)); - + if (!data->channel_map_is_set) pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); - + CHECK_VALIDITY_RETURN_NULL(pa_channel_map_valid(&data->channel_map)); CHECK_VALIDITY_RETURN_NULL(data->channel_map.channels == data->sample_spec.channels); - + if (!data->volume_is_set) pa_cvolume_reset(&data->volume, data->sample_spec.channels); @@ -134,9 +134,9 @@ pa_sink_input* pa_sink_input_new( if ((flags & PA_SINK_INPUT_VARIABLE_RATE) || !pa_sample_spec_equal(&data->sample_spec, &data->sink->sample_spec) || !pa_channel_map_equal(&data->channel_map, &data->sink->channel_map)) - + if (!(resampler = pa_resampler_new( - core->mempool, + core->mempool, &data->sample_spec, &data->channel_map, &data->sink->sample_spec, &data->sink->channel_map, data->resample_method))) { @@ -157,21 +157,21 @@ pa_sink_input* pa_sink_input_new( i->sample_spec = data->sample_spec; i->channel_map = data->channel_map; i->volume = data->volume; - + i->peek = NULL; i->drop = NULL; i->kill = NULL; i->get_latency = NULL; i->underrun = NULL; i->userdata = NULL; - + i->move_silence = 0; pa_memchunk_reset(&i->resampled_chunk); i->resampler = resampler; i->resample_method = data->resample_method; i->silence_memblock = NULL; - + r = pa_idxset_put(core->sink_inputs, i, &i->index); assert(r == 0); r = pa_idxset_put(i->sink->inputs, i, NULL); @@ -182,13 +182,13 @@ pa_sink_input* pa_sink_input_new( i->name, i->sink->name, pa_sample_spec_snprint(st, sizeof(st), &i->sample_spec)); - + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index); /* We do not call pa_sink_notify() here, because the virtual * functions have not yet been initialized */ - - return i; + + return i; } void pa_sink_input_disconnect(pa_sink_input *i) { @@ -218,17 +218,17 @@ static void sink_input_free(pa_sink_input* i) { if (i->state != PA_SINK_INPUT_DISCONNECTED) pa_sink_input_disconnect(i); - pa_log_info("freed %u \"%s\"", i->index, i->name); - + pa_log_info("freed %u \"%s\"", i->index, i->name); + if (i->resampled_chunk.memblock) pa_memblock_unref(i->resampled_chunk.memblock); - + if (i->resampler) pa_resampler_free(i->resampler); if (i->silence_memblock) pa_memblock_unref(i->silence_memblock); - + pa_xfree(i->name); pa_xfree(i->driver); pa_xfree(i); @@ -245,7 +245,7 @@ void pa_sink_input_unref(pa_sink_input *i) { pa_sink_input* pa_sink_input_ref(pa_sink_input *i) { assert(i); assert(i->ref >= 1); - + i->ref++; return i; } @@ -260,10 +260,10 @@ void pa_sink_input_kill(pa_sink_input*i) { pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) { pa_usec_t r = 0; - + assert(i); assert(i->ref >= 1); - + if (i->get_latency) r += i->get_latency(i); @@ -280,7 +280,7 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) int ret = -1; int do_volume_adj_here; int volume_is_norm; - + assert(i); assert(i->ref >= 1); assert(chunk); @@ -297,7 +297,7 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) /* We have just been moved and shall play some silence for a * while until the old sink has drained its playback buffer */ - + if (!i->silence_memblock) i->silence_memblock = pa_silence_memblock_new(i->sink->core->mempool, &i->sink->sample_spec, SILENCE_BUFFER_LENGTH); @@ -309,7 +309,7 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) do_volume_adj_here = 1; goto finish; } - + if (!i->resampler) { do_volume_adj_here = 0; ret = i->peek(i, chunk); @@ -318,16 +318,16 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map); volume_is_norm = pa_cvolume_is_norm(&i->volume); - + while (!i->resampled_chunk.memblock) { pa_memchunk tchunk; size_t l; - + if ((ret = i->peek(i, &tchunk)) < 0) goto finish; assert(tchunk.length); - + l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); if (l > tchunk.length) @@ -348,7 +348,7 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) assert(i->resampled_chunk.memblock); assert(i->resampled_chunk.length); - + *chunk = i->resampled_chunk; pa_memblock_ref(i->resampled_chunk.memblock); @@ -375,9 +375,9 @@ finish: /* We've both the same channel map, so let's have the sink do the adjustment for us*/ *volume = i->volume; } - + pa_sink_input_unref(i); - + return ret; } @@ -392,13 +392,13 @@ void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t lengt if (chunk->memblock != i->silence_memblock || chunk->index != 0 || - (chunk->memblock && (chunk->length != (i->silence_memblock->length < i->move_silence ? i->silence_memblock->length : i->move_silence)))) + (chunk->memblock && (chunk->length != (i->silence_memblock->length < i->move_silence ? i->silence_memblock->length : i->move_silence)))) return; - + } assert(i->move_silence >= length); - + i->move_silence -= length; if (i->move_silence <= 0) { @@ -415,7 +415,7 @@ void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t lengt i->drop(i, chunk, length); return; } - + assert(i->resampled_chunk.memblock); assert(i->resampled_chunk.length >= length); @@ -437,7 +437,7 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) { if (pa_cvolume_equal(&i->volume, volume)) return; - + i->volume = *volume; pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); } @@ -451,7 +451,7 @@ const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i) { void pa_sink_input_cork(pa_sink_input *i, int b) { int n; - + assert(i); assert(i->ref >= 1); @@ -491,7 +491,7 @@ void pa_sink_input_set_name(pa_sink_input *i, const char *name) { if (i->name && name && !strcmp(i->name, name)) return; - + pa_xfree(i->name); i->name = pa_xstrdup(name); @@ -512,7 +512,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { pa_resampler *new_resampler = NULL; pa_memblockq *buffer = NULL; pa_sink *origin; - + assert(i); assert(dest); @@ -532,13 +532,13 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { /* Try to reuse the old resampler if possible */ new_resampler = i->resampler; - + else if ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) || !pa_sample_spec_equal(&i->sample_spec, &dest->sample_spec) || !pa_channel_map_equal(&i->channel_map, &dest->channel_map)) { /* Okey, we need a new resampler for the new sink */ - + if (!(new_resampler = pa_resampler_new( dest->core->mempool, &i->sample_spec, &i->channel_map, @@ -554,13 +554,13 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { pa_usec_t silence_usec = 0; buffer = pa_memblockq_new(0, MOVE_BUFFER_LENGTH, 0, pa_frame_size(&origin->sample_spec), 0, 0, NULL); - + /* Let's do a little bit of Voodoo for compensating latency * differences */ old_latency = pa_sink_get_latency(origin); new_latency = pa_sink_get_latency(dest); - + /* The already resampled data should go to the old sink */ if (old_latency >= new_latency) { @@ -571,17 +571,17 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { * while */ silence_usec = old_latency - new_latency; - + } else { size_t l; int volume_is_norm; - + /* The latency of new sink is larger than the latency of * the old sink. Therefore we have to precompute a little * and make sure that this is still played on the old * sink, until we can play the first sample on the new * sink.*/ - + l = pa_usec_to_bytes(new_latency - old_latency, &origin->sample_spec); volume_is_norm = pa_cvolume_is_norm(&i->volume); @@ -655,7 +655,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { i->resampled_chunk.memblock = NULL; i->resampled_chunk.index = i->resampled_chunk.length = 0; } - + /* Notify everyone */ pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); pa_sink_notify(i->sink); diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 2943dfae..9d7487f7 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -52,13 +52,13 @@ struct pa_sink_input { uint32_t index; pa_sink_input_state_t state; pa_sink_input_flags_t flags; - + char *name, *driver; /* may be NULL */ - pa_module *module; /* may be NULL */ - pa_client *client; /* may be NULL */ + pa_module *module; /* may be NULL */ + pa_client *client; /* may be NULL */ pa_sink *sink; - + pa_sample_spec sample_spec; pa_channel_map channel_map; pa_cvolume volume; @@ -67,7 +67,7 @@ struct pa_sink_input { * compensate for latency differences when moving a sink input * "hot" between sinks. */ size_t move_silence; - + int (*peek) (pa_sink_input *i, pa_memchunk *chunk); void (*drop) (pa_sink_input *i, const pa_memchunk *chunk, size_t length); void (*kill) (pa_sink_input *i); /* may be NULL */ @@ -88,16 +88,16 @@ typedef struct pa_sink_input_new_data { const char *name, *driver; pa_module *module; pa_client *client; - + pa_sink *sink; - + pa_sample_spec sample_spec; int sample_spec_is_set; pa_channel_map channel_map; int channel_map_is_set; pa_cvolume volume; int volume_is_set; - + pa_resample_method_t resample_method; } pa_sink_input_new_data; diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 05695254..cb0e54c1 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -56,7 +56,7 @@ pa_sink* pa_sink_new( int fail, const pa_sample_spec *spec, const pa_channel_map *map) { - + pa_sink *s; char *n = NULL; char st[256]; @@ -68,7 +68,7 @@ pa_sink* pa_sink_new( assert(spec); CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec)); - + if (!map) map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT); @@ -76,7 +76,7 @@ pa_sink* pa_sink_new( CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels); CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver)); CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name) && *name); - + s = pa_xnew(pa_sink, 1); if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) { @@ -94,7 +94,7 @@ pa_sink* pa_sink_new( s->sample_spec = *spec; s->channel_map = *map; - + s->inputs = pa_idxset_new(NULL, NULL); pa_cvolume_reset(&s->sw_volume, spec->channels); @@ -103,7 +103,7 @@ pa_sink* pa_sink_new( s->hw_muted = 0; s->is_hardware = 0; - + s->get_latency = NULL; s->notify = NULL; s->set_hw_volume = NULL; @@ -114,12 +114,12 @@ pa_sink* pa_sink_new( r = pa_idxset_put(core->sinks, s, &s->index); assert(s->index != PA_IDXSET_INVALID && r >= 0); - + pa_sample_spec_snprint(st, sizeof(st), spec); pa_log_info("created %u \"%s\" with sample spec \"%s\"", s->index, s->name, st); n = pa_sprintf_malloc("%s.monitor", name); - + if (!(s->monitor_source = pa_source_new(core, driver, n, 0, spec, map))) pa_log_warn("failed to create monitor source."); else { @@ -131,15 +131,15 @@ pa_sink* pa_sink_new( } pa_xfree(n); - + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index); - + return s; } void pa_sink_disconnect(pa_sink* s) { pa_sink_input *i, *j = NULL; - + assert(s); assert(s->state == PA_SINK_RUNNING); @@ -147,7 +147,7 @@ void pa_sink_disconnect(pa_sink* s) { pa_namereg_unregister(s->core, s->name); pa_hook_fire(&s->core->hook_sink_disconnect, s); - + while ((i = pa_idxset_first(s->inputs, NULL))) { assert(i != j); pa_sink_input_kill(i); @@ -165,24 +165,24 @@ void pa_sink_disconnect(pa_sink* s) { s->set_hw_volume = NULL; s->set_hw_mute = NULL; s->get_hw_mute = NULL; - + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); } static void sink_free(pa_sink *s) { assert(s); assert(!s->ref); - + if (s->state != PA_SINK_DISCONNECTED) pa_sink_disconnect(s); - pa_log_info("freed %u \"%s\"", s->index, s->name); + pa_log_info("freed %u \"%s\"", s->index, s->name); if (s->monitor_source) { pa_source_unref(s->monitor_source); s->monitor_source = NULL; } - + pa_idxset_free(s->inputs, NULL, NULL); pa_xfree(s->name); @@ -202,7 +202,7 @@ void pa_sink_unref(pa_sink*s) { pa_sink* pa_sink_ref(pa_sink *s) { assert(s); assert(s->ref >= 1); - + s->ref++; return s; } @@ -219,7 +219,7 @@ static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) { uint32_t idx = PA_IDXSET_INVALID; pa_sink_input *i; unsigned n = 0; - + assert(s); assert(s->ref >= 1); assert(info); @@ -235,11 +235,11 @@ static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) { } info->userdata = i; - + assert(info->chunk.memblock); assert(info->chunk.memblock->data); assert(info->chunk.length); - + info++; maxinfo--; n++; @@ -255,7 +255,7 @@ static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned maxinfo, size_t for (; maxinfo > 0; maxinfo--, info++) { pa_sink_input *i = info->userdata; - + assert(i); assert(info->chunk.memblock); @@ -268,19 +268,19 @@ static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned maxinfo, size_t info->userdata = NULL; } } - + int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; int r = -1; - + assert(s); assert(s->ref >= 1); assert(length); assert(result); pa_sink_ref(s); - + n = fill_mix_info(s, info, MAX_MIX_CHANNELS); if (n <= 0) @@ -296,7 +296,7 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { result->length = length; pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); - + if (s->sw_muted || !pa_cvolume_is_norm(&volume)) { pa_memchunk_make_writable(result, 0); if (s->sw_muted) @@ -332,7 +332,7 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; int r = -1; - + assert(s); assert(s->ref >= 1); assert(target); @@ -341,7 +341,7 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { assert(target->memblock->data); pa_sink_ref(s); - + n = fill_mix_info(s, info, MAX_MIX_CHANNELS); if (n <= 0) @@ -352,7 +352,7 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { if (target->length > info[0].chunk.length) target->length = info[0].chunk.length; - + memcpy((uint8_t*) target->memblock->data + target->index, (uint8_t*) info[0].chunk.memblock->data + info[0].chunk.index, target->length); @@ -360,7 +360,7 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); if (s->sw_muted) - pa_silence_memchunk(target, &s->sample_spec); + pa_silence_memchunk(target, &s->sample_spec); else if (!pa_cvolume_is_norm(&volume)) pa_volume_memchunk(target, &s->sample_spec, &volume); } else @@ -370,7 +370,7 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { &s->sample_spec, &s->sw_volume, s->sw_muted); - + inputs_drop(s, info, n, target->length); if (s->monitor_source) @@ -380,14 +380,14 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { finish: pa_sink_unref(s); - + return r; } void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { pa_memchunk chunk; size_t l, d; - + assert(s); assert(s->ref >= 1); assert(target); @@ -396,14 +396,14 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { assert(target->memblock->data); pa_sink_ref(s); - + l = target->length; d = 0; while (l > 0) { chunk = *target; chunk.index += d; chunk.length -= d; - + if (pa_sink_render_into(s, &chunk) < 0) break; @@ -428,7 +428,7 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { assert(result); /*** This needs optimization ***/ - + result->memblock = pa_memblock_new(s->core->mempool, result->length = length); result->index = 0; @@ -451,7 +451,7 @@ void pa_sink_set_owner(pa_sink *s, pa_module *m) { if (s->owner == m) return; - + s->owner = m; if (s->monitor_source) @@ -462,19 +462,19 @@ void pa_sink_set_owner(pa_sink *s, pa_module *m) { void pa_sink_set_volume(pa_sink *s, pa_mixer_t m, const pa_cvolume *volume) { pa_cvolume *v; - + assert(s); assert(s->ref >= 1); assert(volume); - if (m == PA_MIXER_HARDWARE && s->set_hw_volume) + if (m == PA_MIXER_HARDWARE && s->set_hw_volume) v = &s->hw_volume; else v = &s->sw_volume; if (pa_cvolume_equal(v, volume)) return; - + *v = *volume; if (v == &s->hw_volume) @@ -492,7 +492,7 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_mixer_t m) { if (s->get_hw_volume) s->get_hw_volume(s); - + return &s->hw_volume; } else return &s->sw_volume; @@ -500,18 +500,18 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_mixer_t m) { void pa_sink_set_mute(pa_sink *s, pa_mixer_t m, int mute) { int *t; - + assert(s); assert(s->ref >= 1); - if (m == PA_MIXER_HARDWARE && s->set_hw_mute) + if (m == PA_MIXER_HARDWARE && s->set_hw_mute) t = &s->hw_muted; else t = &s->sw_muted; if (!!*t == !!mute) return; - + *t = !!mute; if (t == &s->hw_muted) @@ -529,7 +529,7 @@ int pa_sink_get_mute(pa_sink *s, pa_mixer_t m) { if (s->get_hw_mute) s->get_hw_mute(s); - + return s->hw_muted; } else return s->sw_muted; @@ -544,18 +544,18 @@ void pa_sink_set_description(pa_sink *s, const char *description) { if (description && s->description && !strcmp(description, s->description)) return; - + pa_xfree(s->description); s->description = pa_xstrdup(description); if (s->monitor_source) { char *n; - + n = pa_sprintf_malloc("Monitor Source of %s", s->description? s->description : s->name); pa_source_set_description(s->monitor_source, n); pa_xfree(n); } - + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 1d870620..7cfc9e26 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -59,7 +59,7 @@ struct pa_sink { pa_idxset *inputs; pa_source *monitor_source; /* may be NULL */ - + pa_cvolume hw_volume, sw_volume; int hw_muted, sw_muted; @@ -69,7 +69,7 @@ struct pa_sink { int (*get_hw_volume)(pa_sink *s); /* dito */ int (*set_hw_mute)(pa_sink *s); /* dito */ int (*get_hw_mute)(pa_sink *s); /* dito */ - + void *userdata; }; @@ -89,7 +89,7 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result); void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result); int pa_sink_render_into(pa_sink*s, pa_memchunk *target); void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target); - + pa_usec_t pa_sink_get_latency(pa_sink *s); void pa_sink_notify(pa_sink*s); diff --git a/src/pulsecore/sioman.c b/src/pulsecore/sioman.c index d84010ee..4d5d5562 100644 --- a/src/pulsecore/sioman.c +++ b/src/pulsecore/sioman.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -40,4 +40,4 @@ int pa_stdio_acquire(void) { void pa_stdio_release(void) { assert(stdio_inuse); stdio_inuse = 0; -} +} diff --git a/src/pulsecore/sioman.h b/src/pulsecore/sioman.h index cd04d140..bbd52110 100644 --- a/src/pulsecore/sioman.h +++ b/src/pulsecore/sioman.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/socket-client.c b/src/pulsecore/socket-client.c index 2ceaf5c3..b08ba010 100644 --- a/src/pulsecore/socket-client.c +++ b/src/pulsecore/socket-client.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -110,17 +110,17 @@ static pa_socket_client*pa_socket_client_new(pa_mainloop_api *m) { static void free_events(pa_socket_client *c) { assert(c); - + if (c->io_event) { c->mainloop->io_free(c->io_event); c->io_event = NULL; } - + if (c->defer_event) { c->mainloop->defer_free(c->defer_event); c->defer_event = NULL; } - + if (c->timeout_event) { c->mainloop->time_free(c->timeout_event); c->timeout_event = NULL; @@ -137,7 +137,7 @@ static void do_call(pa_socket_client *c) { if (c->fd < 0) goto finish; - + lerror = sizeof(error); if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &lerror) < 0) { pa_log("getsockopt(): %s", pa_cstrerror(errno)); @@ -157,17 +157,17 @@ static void do_call(pa_socket_client *c) { io = pa_iochannel_new(c->mainloop, c->fd, c->fd); assert(io); - + finish: if (!io && c->fd >= 0) close(c->fd); c->fd = -1; free_events(c); - + assert(c->callback); c->callback(c, io, c->userdata); - + pa_socket_client_unref(c); } @@ -186,9 +186,9 @@ static void connect_io_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUS static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t len) { int r; assert(c && sa && len); - + pa_make_nonblock_fd(c->fd); - + if ((r = connect(c->fd, sa, len)) < 0) { #ifdef OS_IS_WIN32 if (WSAGetLastError() != EWOULDBLOCK) { @@ -227,7 +227,7 @@ pa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) { struct sockaddr_un sa; assert(m && filename); - + memset(&sa, 0, sizeof(sa)); sa.sun_family = AF_UNIX; strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); @@ -248,24 +248,24 @@ static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size assert(c); assert(sa); assert(salen); - + switch (sa->sa_family) { case AF_UNIX: c->local = 1; break; - + case AF_INET: c->local = ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK; break; - + case AF_INET6: c->local = memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0; break; - + default: c->local = 0; } - + if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) { pa_log("socket(): %s", pa_cstrerror(errno)); return -1; @@ -291,13 +291,13 @@ pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct if (sockaddr_prepare(c, sa, salen) < 0) goto fail; - + return c; fail: pa_socket_client_unref(c); return NULL; - + } static void socket_client_free(pa_socket_client *c) { @@ -305,7 +305,7 @@ static void socket_client_free(pa_socket_client *c) { free_events(c); - + if (c->fd >= 0) close(c->fd); @@ -317,7 +317,7 @@ static void socket_client_free(pa_socket_client *c) { if (c->asyncns_io_event) c->mainloop->io_free(c->asyncns_io_event); #endif - + pa_xfree(c); } @@ -342,7 +342,7 @@ void pa_socket_client_set_callback(pa_socket_client *c, void (*on_connection)(pa pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[16], uint16_t port) { struct sockaddr_in6 sa; - + memset(&sa, 0, sizeof(sa)); sa.sin6_family = AF_INET6; sa.sin6_port = htons(port); @@ -370,24 +370,24 @@ static void asyncns_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED if (ret != 0 || !res) goto fail; - + if (res->ai_addr) sockaddr_prepare(c, res->ai_addr, res->ai_addrlen); - + asyncns_freeaddrinfo(res); m->io_free(c->asyncns_io_event); c->asyncns_io_event = NULL; return; - + fail: m->io_free(c->asyncns_io_event); c->asyncns_io_event = NULL; - + errno = EHOSTUNREACH; do_call(c); return; - + } #endif @@ -428,7 +428,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam if (!a.port) a.port = default_port; - + switch (a.type) { case PA_PARSED_ADDRESS_UNIX: if ((c = pa_socket_client_new_unix(m, a.path_or_host))) @@ -447,11 +447,11 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam memset(&hints, 0, sizeof(hints)); hints.ai_family = a.type == PA_PARSED_ADDRESS_TCP4 ? PF_INET : (a.type == PA_PARSED_ADDRESS_TCP6 ? PF_INET6 : PF_UNSPEC); hints.ai_socktype = SOCK_STREAM; - + #ifdef HAVE_LIBASYNCNS { asyncns_t *asyncns; - + if (!(asyncns = asyncns_new(1))) goto finish; @@ -469,7 +469,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam struct addrinfo *res = NULL; ret = getaddrinfo(a.path_or_host, port, &hints, &res); - + if (ret < 0 || !res) goto finish; @@ -477,7 +477,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen))) start_timeout(c); } - + freeaddrinfo(res); #else /* HAVE_GETADDRINFO */ struct hostent *host = NULL; @@ -514,7 +514,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam finish: pa_xfree(a.path_or_host); return c; - + } /* Return non-zero when the target sockaddr is considered diff --git a/src/pulsecore/socket-client.h b/src/pulsecore/socket-client.h index 47e7cd5a..146ebda8 100644 --- a/src/pulsecore/socket-client.h +++ b/src/pulsecore/socket-client.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/socket-server.c b/src/pulsecore/socket-server.c index 4d69b8a4..c878ab1a 100644 --- a/src/pulsecore/socket-server.c +++ b/src/pulsecore/socket-server.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -94,14 +94,14 @@ static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_U assert(s && s->mainloop == mainloop && s->io_event == e && e && fd >= 0 && fd == s->fd); pa_socket_server_ref(s); - + if ((nfd = accept(fd, NULL, NULL)) < 0) { pa_log("accept(): %s", pa_cstrerror(errno)); goto finish; } pa_fd_set_cloexec(nfd, 1); - + if (!s->on_connection) { close(nfd); goto finish; @@ -123,13 +123,13 @@ static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_U pa_log_info("TCP connection accepted by tcpwrap."); } #endif - + /* There should be a check for socket type here */ - if (s->type == SOCKET_SERVER_IPV4) + if (s->type == SOCKET_SERVER_IPV4) pa_socket_tcp_low_delay(fd); else pa_socket_low_delay(fd); - + io = pa_iochannel_new(s->mainloop, nfd, nfd); assert(io); s->on_connection(s, io, s->userdata); @@ -141,7 +141,7 @@ finish: pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) { pa_socket_server *s; assert(m && fd >= 0); - + s = pa_xmalloc(sizeof(pa_socket_server)); s->ref = 1; s->fd = fd; @@ -155,7 +155,7 @@ pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) { assert(s->io_event); s->type = SOCKET_SERVER_GENERIC; - + return s; } @@ -171,7 +171,7 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file int fd = -1; struct sockaddr_un sa; pa_socket_server *s; - + assert(m && filename); if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { @@ -197,7 +197,7 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file * because not all OS check the access rights on the socket * inodes. */ chmod(filename, 0777); - + if (listen(fd, 5) < 0) { pa_log("listen(): %s", pa_cstrerror(errno)); goto fail; @@ -208,9 +208,9 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file s->filename = pa_xstrdup(filename); s->type = SOCKET_SERVER_UNIX; - + return s; - + fail: if (fd >= 0) close(fd); @@ -247,7 +247,7 @@ pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address #endif pa_socket_tcp_low_delay(fd); - + memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_port = htons(port); @@ -269,7 +269,7 @@ pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address } return ss; - + fail: if (fd >= 0) close(fd); @@ -323,9 +323,9 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad ss->type = SOCKET_SERVER_IPV6; ss->tcpwrap_service = pa_xstrdup(tcpwrap_service); } - + return ss; - + fail: if (fd >= 0) close(fd); @@ -350,20 +350,20 @@ pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_ pa_socket_server* pa_socket_server_new_ipv4_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { assert(m); assert(port > 0); - + return pa_socket_server_new_ipv4(m, INADDR_ANY, port, tcpwrap_service); } pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { assert(m); assert(port > 0); - + return pa_socket_server_new_ipv6(m, in6addr_any.s6_addr, port, tcpwrap_service); } pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) { struct in_addr ipv4; - + assert(m); assert(name); assert(port > 0); @@ -376,7 +376,7 @@ pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const cha pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) { struct in6_addr ipv6; - + assert(m); assert(name); assert(port > 0); @@ -419,7 +419,7 @@ void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { assert(s && c && l > 0); - + switch (s->type) { case SOCKET_SERVER_IPV6: { struct sockaddr_in6 sa; @@ -434,23 +434,23 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { char fqdn[256]; if (!pa_get_fqdn(fqdn, sizeof(fqdn))) return NULL; - + snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port)); - + } else if (memcmp(&in6addr_loopback, &sa.sin6_addr, sizeof(in6addr_loopback)) == 0) { char hn[256]; if (!pa_get_host_name(hn, sizeof(hn))) return NULL; - + snprintf(c, l, "{%s}tcp6:localhost:%u", hn, (unsigned) ntohs(sa.sin6_port)); } else { char ip[INET6_ADDRSTRLEN]; - + if (!inet_ntop(AF_INET6, &sa.sin6_addr, ip, sizeof(ip))) { pa_log("inet_ntop(): %s", pa_cstrerror(errno)); return NULL; } - + snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port)); } @@ -470,13 +470,13 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { char fqdn[256]; if (!pa_get_fqdn(fqdn, sizeof(fqdn))) return NULL; - + snprintf(c, l, "tcp:%s:%u", fqdn, (unsigned) ntohs(sa.sin_port)); } else if (sa.sin_addr.s_addr == INADDR_LOOPBACK) { char hn[256]; if (!pa_get_host_name(hn, sizeof(hn))) return NULL; - + snprintf(c, l, "{%s}tcp:localhost:%u", hn, (unsigned) ntohs(sa.sin_port)); } else { char ip[INET_ADDRSTRLEN]; @@ -485,11 +485,11 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { pa_log("inet_ntop(): %s", pa_cstrerror(errno)); return NULL; } - + snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port)); } - + return c; } @@ -498,7 +498,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { if (!s->filename) return NULL; - + if (!pa_get_host_name(hn, sizeof(hn))) return NULL; diff --git a/src/pulsecore/socket-server.h b/src/pulsecore/socket-server.h index d90c8194..489878cb 100644 --- a/src/pulsecore/socket-server.h +++ b/src/pulsecore/socket-server.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/socket-util.c b/src/pulsecore/socket-util.c index 856c28e8..e16f8979 100644 --- a/src/pulsecore/socket-util.c +++ b/src/pulsecore/socket-util.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -78,7 +78,7 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) { struct stat st; assert(c && l && fd >= 0); - + #ifndef OS_IS_WIN32 if (fstat(fd, &st) < 0) { snprintf(c, l, "Invalid client fd"); @@ -88,7 +88,7 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) { #ifndef OS_IS_WIN32 if (S_ISSOCK(st.st_mode)) { -#endif +#endif union { struct sockaddr sa; struct sockaddr_in in; @@ -98,12 +98,12 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) { #endif } sa; socklen_t sa_len = sizeof(sa); - + if (getpeername(fd, &sa.sa, &sa_len) >= 0) { if (sa.sa.sa_family == AF_INET) { uint32_t ip = ntohl(sa.in.sin_addr.s_addr); - + snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u", ip >> 24, (ip >> 16) & 0xFF, @@ -159,7 +159,7 @@ int pa_socket_tcp_low_delay(int fd) { assert(fd >= 0); ret = pa_socket_low_delay(fd); - + on = 1; tos = 0; @@ -239,13 +239,13 @@ finish: int pa_unix_socket_remove_stale(const char *fn) { int r; - + if ((r = pa_unix_socket_is_stale(fn)) < 0) return errno != ENOENT ? -1 : 0; if (!r) return 0; - + /* Yes, here is a race condition. But who cares? */ if (unlink(fn) < 0) return -1; diff --git a/src/pulsecore/socket-util.h b/src/pulsecore/socket-util.h index f8248ae7..59b4980d 100644 --- a/src/pulsecore/socket-util.h +++ b/src/pulsecore/socket-util.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c index e6f24a79..a277f1f0 100644 --- a/src/pulsecore/sound-file-stream.c +++ b/src/pulsecore/sound-file-stream.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -52,7 +52,7 @@ static void free_userdata(struct userdata *u) { pa_sink_input_disconnect(u->sink_input); pa_sink_input_unref(u->sink_input); } - + if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); if (u->sndfile) @@ -86,10 +86,10 @@ static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { } else { if ((n = sf_read_raw(u->sndfile, u->memchunk.memblock->data, BUF_SIZE)) <= 0) n = 0; - + u->memchunk.length = n; } - + if (!u->memchunk.length) { free_userdata(u); return -1; @@ -124,12 +124,12 @@ int pa_play_file( pa_sink *sink, const char *fname, const pa_cvolume *volume) { - + struct userdata *u = NULL; SF_INFO sfinfo; pa_sample_spec ss; pa_sink_input_new_data data; - + assert(sink); assert(fname); @@ -147,7 +147,7 @@ int pa_play_file( } u->readf_function = NULL; - + switch (sfinfo.format & 0xFF) { case SF_FORMAT_PCM_16: case SF_FORMAT_PCM_U8: @@ -159,7 +159,7 @@ int pa_play_file( case SF_FORMAT_ULAW: ss.format = PA_SAMPLE_ULAW; break; - + case SF_FORMAT_ALAW: ss.format = PA_SAMPLE_ALAW; break; @@ -170,7 +170,7 @@ int pa_play_file( u->readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_float; break; } - + ss.rate = sfinfo.samplerate; ss.channels = sfinfo.channels; @@ -185,7 +185,7 @@ int pa_play_file( data.name = fname; pa_sink_input_new_data_set_sample_spec(&data, &ss); pa_sink_input_new_data_set_volume(&data, volume); - + if (!(u->sink_input = pa_sink_input_new(sink->core, &data, 0))) goto fail; @@ -193,7 +193,7 @@ int pa_play_file( u->sink_input->drop = sink_input_drop; u->sink_input->kill = sink_input_kill; u->sink_input->userdata = u; - + pa_sink_notify(u->sink_input->sink); return 0; @@ -201,6 +201,6 @@ int pa_play_file( fail: if (u) free_userdata(u); - + return -1; } diff --git a/src/pulsecore/sound-file-stream.h b/src/pulsecore/sound-file-stream.h index 28e6a8ba..0798b423 100644 --- a/src/pulsecore/sound-file-stream.h +++ b/src/pulsecore/sound-file-stream.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/sound-file.c b/src/pulsecore/sound-file.c index 1bf650e2..284bbdda 100644 --- a/src/pulsecore/sound-file.c +++ b/src/pulsecore/sound-file.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -63,7 +63,7 @@ int pa_sound_file_load(pa_mempool *pool, const char *fname, pa_sample_spec *ss, case SF_FORMAT_ULAW: ss->format = PA_SAMPLE_ULAW; break; - + case SF_FORMAT_ALAW: ss->format = PA_SAMPLE_ALAW; break; @@ -86,7 +86,7 @@ int pa_sound_file_load(pa_mempool *pool, const char *fname, pa_sample_spec *ss, if (map) pa_channel_map_init_auto(map, ss->channels, PA_CHANNEL_MAP_DEFAULT); - + if ((l = pa_frame_size(ss)*sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) { pa_log("File too large"); goto finish; @@ -102,7 +102,7 @@ int pa_sound_file_load(pa_mempool *pool, const char *fname, pa_sample_spec *ss, pa_log("Premature file end"); goto finish; } - + ret = 0; finish: @@ -112,9 +112,9 @@ finish: if (ret != 0 && chunk->memblock) pa_memblock_unref(chunk->memblock); - + return ret; - + } int pa_sound_file_too_big_to_cache(const char *fname) { @@ -139,7 +139,7 @@ int pa_sound_file_too_big_to_cache(const char *fname) { case SF_FORMAT_ULAW: ss.format = PA_SAMPLE_ULAW; break; - + case SF_FORMAT_ALAW: ss.format = PA_SAMPLE_ALAW; break; diff --git a/src/pulsecore/sound-file.h b/src/pulsecore/sound-file.h index 7e3c82ea..cf8168d0 100644 --- a/src/pulsecore/sound-file.h +++ b/src/pulsecore/sound-file.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 352fce14..5783b44a 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -45,7 +45,7 @@ if (!(condition)) \ pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_data *data) { assert(data); - + memset(data, 0, sizeof(*data)); data->resample_method = PA_RESAMPLER_INVALID; return data; @@ -69,7 +69,7 @@ pa_source_output* pa_source_output_new( pa_core *core, pa_source_output_new_data *data, pa_source_output_flags_t flags) { - + pa_source_output *o; pa_resampler *resampler = NULL; int r; @@ -90,15 +90,15 @@ pa_source_output* pa_source_output_new( CHECK_VALIDITY_RETURN_NULL(data->source); CHECK_VALIDITY_RETURN_NULL(data->source->state == PA_SOURCE_RUNNING); - + if (!data->sample_spec_is_set) data->sample_spec = data->source->sample_spec; - + CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(&data->sample_spec)); if (!data->channel_map_is_set) pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); - + CHECK_VALIDITY_RETURN_NULL(pa_channel_map_valid(&data->channel_map)); CHECK_VALIDITY_RETURN_NULL(data->channel_map.channels == data->sample_spec.channels); @@ -106,7 +106,7 @@ pa_source_output* pa_source_output_new( data->resample_method = core->resample_method; CHECK_VALIDITY_RETURN_NULL(data->resample_method < PA_RESAMPLER_MAX); - + if (pa_idxset_size(data->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { pa_log("Failed to create source output: too many outputs per source."); return NULL; @@ -122,7 +122,7 @@ pa_source_output* pa_source_output_new( pa_log_warn("Unsupported resampling operation."); return NULL; } - + o = pa_xnew(pa_source_output, 1); o->ref = 1; o->state = PA_SOURCE_OUTPUT_RUNNING; @@ -131,7 +131,7 @@ pa_source_output* pa_source_output_new( o->module = data->module; o->source = data->source; o->client = data->client; - + o->sample_spec = data->sample_spec; o->channel_map = data->channel_map; @@ -139,10 +139,10 @@ pa_source_output* pa_source_output_new( o->kill = NULL; o->get_latency = NULL; o->userdata = NULL; - + o->resampler = resampler; o->resample_method = data->resample_method; - + r = pa_idxset_put(core->source_outputs, o, &o->index); assert(r == 0); r = pa_idxset_put(o->source->outputs, o, NULL); @@ -153,13 +153,13 @@ pa_source_output* pa_source_output_new( o->name, o->source->name, pa_sample_spec_snprint(st, sizeof(st), &o->sample_spec)); - + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); /* We do not call pa_source_notify() here, because the virtual * functions have not yet been initialized */ - - return o; + + return o; } void pa_source_output_disconnect(pa_source_output*o) { @@ -167,7 +167,7 @@ void pa_source_output_disconnect(pa_source_output*o) { assert(o->state != PA_SOURCE_OUTPUT_DISCONNECTED); assert(o->source); assert(o->source->core); - + pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); pa_idxset_remove_by_data(o->source->outputs, o, NULL); @@ -177,7 +177,7 @@ void pa_source_output_disconnect(pa_source_output*o) { o->push = NULL; o->kill = NULL; o->get_latency = NULL; - + o->state = PA_SOURCE_OUTPUT_DISCONNECTED; } @@ -187,8 +187,8 @@ static void source_output_free(pa_source_output* o) { if (o->state != PA_SOURCE_OUTPUT_DISCONNECTED) pa_source_output_disconnect(o); - pa_log_info("freed %u \"%s\"", o->index, o->name); - + pa_log_info("freed %u \"%s\"", o->index, o->name); + if (o->resampler) pa_resampler_free(o->resampler); @@ -208,7 +208,7 @@ void pa_source_output_unref(pa_source_output* o) { pa_source_output* pa_source_output_ref(pa_source_output *o) { assert(o); assert(o->ref >= 1); - + o->ref++; return o; } @@ -223,7 +223,7 @@ void pa_source_output_kill(pa_source_output*o) { void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { pa_memchunk rchunk; - + assert(o); assert(chunk); assert(chunk->length); @@ -231,7 +231,7 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { if (o->state == PA_SOURCE_OUTPUT_CORKED) return; - + if (!o->resampler) { o->push(o, chunk); return; @@ -240,7 +240,7 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { pa_resampler_run(o->resampler, chunk, &rchunk); if (!rchunk.length) return; - + assert(rchunk.memblock); o->push(o, &rchunk); pa_memblock_unref(rchunk.memblock); @@ -255,7 +255,7 @@ void pa_source_output_set_name(pa_source_output *o, const char *name) { if (o->name && name && !strcmp(o->name, name)) return; - + pa_xfree(o->name); o->name = pa_xstrdup(name); @@ -265,7 +265,7 @@ void pa_source_output_set_name(pa_source_output *o, const char *name) { pa_usec_t pa_source_output_get_latency(pa_source_output *o) { assert(o); assert(o->ref >= 1); - + if (o->get_latency) return o->get_latency(o); @@ -274,7 +274,7 @@ pa_usec_t pa_source_output_get_latency(pa_source_output *o) { void pa_source_output_cork(pa_source_output *o, int b) { int n; - + assert(o); assert(o->ref >= 1); @@ -282,9 +282,9 @@ void pa_source_output_cork(pa_source_output *o, int b) { return; n = o->state == PA_SOURCE_OUTPUT_CORKED && !b; - + o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; - + if (n) pa_source_notify(o->source); } @@ -292,7 +292,7 @@ void pa_source_output_cork(pa_source_output *o, int b) { pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { assert(o); assert(o->ref >= 1); - + if (!o->resampler) return o->resample_method; @@ -323,12 +323,12 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { /* Try to reuse the old resampler if possible */ new_resampler = o->resampler; - + else if (!pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec) || !pa_channel_map_equal(&o->channel_map, &dest->channel_map)) { /* Okey, we need a new resampler for the new sink */ - + if (!(new_resampler = pa_resampler_new( dest->core->mempool, &dest->sample_spec, &dest->channel_map, diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index f7396a19..827b68ee 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -47,7 +47,7 @@ struct pa_source_output { int ref; uint32_t index; pa_source_output_state_t state; - + char *name, *driver; /* may be NULL */ pa_module *module; /* may be NULL */ @@ -56,14 +56,14 @@ struct pa_source_output { pa_sample_spec sample_spec; pa_channel_map channel_map; - + void (*push)(pa_source_output *o, const pa_memchunk *chunk); void (*kill)(pa_source_output* o); /* may be NULL */ pa_usec_t (*get_latency) (pa_source_output *o); /* may be NULL */ pa_resampler* resampler; /* may be NULL */ pa_resample_method_t resample_method; - + void *userdata; }; diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index c48d6aaa..702dbeff 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -52,12 +52,12 @@ pa_source* pa_source_new( int fail, const pa_sample_spec *spec, const pa_channel_map *map) { - + pa_source *s; char st[256]; int r; pa_channel_map tmap; - + assert(core); assert(name); assert(spec); @@ -86,7 +86,7 @@ pa_source* pa_source_new( s->description = NULL; s->driver = pa_xstrdup(driver); s->owner = NULL; - + s->sample_spec = *spec; s->channel_map = *map; @@ -112,16 +112,16 @@ pa_source* pa_source_new( assert(s->index != PA_IDXSET_INVALID && r >= 0); pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info("created %u \"%s\" with sample spec \"%s\"", s->index, s->name, st); + pa_log_info("created %u \"%s\" with sample spec \"%s\"", s->index, s->name, st); pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index); - + return s; } void pa_source_disconnect(pa_source *s) { pa_source_output *o, *j = NULL; - + assert(s); assert(s->state == PA_SOURCE_RUNNING); @@ -129,7 +129,7 @@ void pa_source_disconnect(pa_source *s) { pa_namereg_unregister(s->core, s->name); pa_hook_fire(&s->core->hook_source_disconnect, s); - + while ((o = pa_idxset_first(s->outputs, NULL))) { assert(o != j); pa_source_output_kill(o); @@ -144,18 +144,18 @@ void pa_source_disconnect(pa_source *s) { s->set_hw_volume = NULL; s->set_hw_mute = NULL; s->get_hw_mute = NULL; - + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); } static void source_free(pa_source *s) { assert(s); assert(!s->ref); - + if (s->state != PA_SOURCE_DISCONNECTED) pa_source_disconnect(s); - - pa_log_info("freed %u \"%s\"", s->index, s->name); + + pa_log_info("freed %u \"%s\"", s->index, s->name); pa_idxset_free(s->outputs, NULL, NULL); @@ -176,7 +176,7 @@ void pa_source_unref(pa_source *s) { pa_source* pa_source_ref(pa_source *s) { assert(s); assert(s->ref >= 1); - + s->ref++; return s; } @@ -192,7 +192,7 @@ void pa_source_notify(pa_source*s) { static int do_post(void *p, PA_GCC_UNUSED uint32_t idx, PA_GCC_UNUSED int *del, void*userdata) { pa_source_output *o = p; const pa_memchunk *chunk = userdata; - + assert(o); assert(chunk); @@ -209,7 +209,7 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) { if (s->sw_muted || !pa_cvolume_is_norm(&s->sw_volume)) { pa_memchunk vchunk = *chunk; - + pa_memblock_ref(vchunk.memblock); pa_memchunk_make_writable(&vchunk, 0); if (s->sw_muted) @@ -230,7 +230,7 @@ void pa_source_set_owner(pa_source *s, pa_module *m) { if (m == s->owner) return; - + s->owner = m; pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } @@ -247,19 +247,19 @@ pa_usec_t pa_source_get_latency(pa_source *s) { void pa_source_set_volume(pa_source *s, pa_mixer_t m, const pa_cvolume *volume) { pa_cvolume *v; - + assert(s); assert(s->ref >= 1); assert(volume); - if (m == PA_MIXER_HARDWARE && s->set_hw_volume) + if (m == PA_MIXER_HARDWARE && s->set_hw_volume) v = &s->hw_volume; else v = &s->sw_volume; if (pa_cvolume_equal(v, volume)) return; - + *v = *volume; if (v == &s->hw_volume) @@ -277,7 +277,7 @@ const pa_cvolume *pa_source_get_volume(pa_source *s, pa_mixer_t m) { if (s->get_hw_volume) s->get_hw_volume(s); - + return &s->hw_volume; } else return &s->sw_volume; @@ -285,18 +285,18 @@ const pa_cvolume *pa_source_get_volume(pa_source *s, pa_mixer_t m) { void pa_source_set_mute(pa_source *s, pa_mixer_t m, int mute) { int *t; - + assert(s); assert(s->ref >= 1); - if (m == PA_MIXER_HARDWARE && s->set_hw_mute) + if (m == PA_MIXER_HARDWARE && s->set_hw_mute) t = &s->hw_muted; else t = &s->sw_muted; if (!!*t == !!mute) return; - + *t = !!mute; if (t == &s->hw_muted) @@ -314,7 +314,7 @@ int pa_source_get_mute(pa_source *s, pa_mixer_t m) { if (s->get_hw_mute) s->get_hw_mute(s); - + return s->hw_muted; } else return s->sw_muted; @@ -329,7 +329,7 @@ void pa_source_set_description(pa_source *s, const char *description) { if (description && s->description && !strcmp(description, s->description)) return; - + pa_xfree(s->description); s->description = pa_xstrdup(description); diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index 4dbe4e01..462bc6ff 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -49,10 +49,10 @@ struct pa_source { uint32_t index; pa_core *core; pa_source_state_t state; - + char *name; char *description, *driver; /* may be NULL */ - + pa_module *owner; /* may be NULL */ pa_sample_spec sample_spec; @@ -65,14 +65,14 @@ struct pa_source { int hw_muted, sw_muted; int is_hardware; - + void (*notify)(pa_source*source); /* may be NULL */ pa_usec_t (*get_latency)(pa_source *s); /* dito */ int (*set_hw_volume)(pa_source *s); /* dito */ - int (*get_hw_volume)(pa_source *s); /* dito */ + int (*get_hw_volume)(pa_source *s); /* dito */ int (*set_hw_mute)(pa_source *s); /* dito */ int (*get_hw_mute)(pa_source *s); /* dito */ - + void *userdata; }; diff --git a/src/pulsecore/strbuf.c b/src/pulsecore/strbuf.c index ef8160dc..59d57260 100644 --- a/src/pulsecore/strbuf.c +++ b/src/pulsecore/strbuf.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -84,7 +84,7 @@ char *pa_strbuf_tostring(pa_strbuf *sb) { *e = 0; assert(e == t+sb->length); - + return t; } @@ -124,10 +124,10 @@ static void append(pa_strbuf *sb, struct chunk *c) { void pa_strbuf_putsn(pa_strbuf *sb, const char *t, size_t l) { struct chunk *c; assert(sb && t); - + if (!l) return; - + c = pa_xmalloc(sizeof(struct chunk)+l); c->length = l; memcpy(CHUNK_TO_TEXT(c), t, l); @@ -142,7 +142,7 @@ int pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) { struct chunk *c = NULL; assert(sb); - + for(;;) { va_list ap; int r; @@ -152,7 +152,7 @@ int pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) { va_start(ap, format); r = vsnprintf(CHUNK_TO_TEXT(c), size, format, ap); va_end(ap); - + if (r > -1 && r < size) { c->length = r; append(sb, c); @@ -160,7 +160,7 @@ int pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) { } if (r > -1) /* glibc 2.1 */ - size = r+1; + size = r+1; else /* glibc 2.0 */ size *= 2; } diff --git a/src/pulsecore/strbuf.h b/src/pulsecore/strbuf.h index c45fb15f..04109197 100644 --- a/src/pulsecore/strbuf.h +++ b/src/pulsecore/strbuf.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/strlist.c b/src/pulsecore/strlist.c index df3a0275..23547bba 100644 --- a/src/pulsecore/strlist.c +++ b/src/pulsecore/strlist.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -69,7 +69,7 @@ pa_strlist* pa_strlist_remove(pa_strlist *l, const char *s) { while (l) { if (!strcmp(l->str, s)) { pa_strlist *n = l->next; - + if (!prev) { assert(ret == l); ret = n; @@ -80,7 +80,7 @@ pa_strlist* pa_strlist_remove(pa_strlist *l, const char *s) { pa_xfree(l); l = n; - + } else { prev = l; l = l->next; @@ -103,12 +103,12 @@ void pa_strlist_free(pa_strlist *l) { pa_strlist* pa_strlist_pop(pa_strlist *l, char **s) { pa_strlist *r; assert(s); - + if (!l) { *s = NULL; return NULL; } - + *s = l->str; r = l->next; pa_xfree(l); diff --git a/src/pulsecore/strlist.h b/src/pulsecore/strlist.h index 87925d5e..07d04677 100644 --- a/src/pulsecore/strlist.h +++ b/src/pulsecore/strlist.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/tagstruct.c b/src/pulsecore/tagstruct.c index 11e85c19..3a0915cf 100644 --- a/src/pulsecore/tagstruct.c +++ b/src/pulsecore/tagstruct.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -53,7 +53,7 @@ pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) { pa_tagstruct*t; assert(!data || (data && length)); - + t = pa_xmalloc(sizeof(pa_tagstruct)); t->data = (uint8_t*) data; t->allocated = t->length = data ? length : 0; @@ -61,7 +61,7 @@ pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) { t->dynamic = !data; return t; } - + void pa_tagstruct_free(pa_tagstruct*t) { assert(t); if (t->dynamic) @@ -203,13 +203,13 @@ void pa_tagstruct_puts64(pa_tagstruct*t, int64_t u) { void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) { unsigned i; - + assert(t); extend(t, 2 + map->channels); t->data[t->length++] = PA_TAG_CHANNEL_MAP; t->data[t->length++] = map->channels; - + for (i = 0; i < map->channels; i ++) t->data[t->length++] = (uint8_t) map->map[i]; } @@ -217,13 +217,13 @@ void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) { void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) { unsigned i; pa_volume_t vol; - + assert(t); extend(t, 2 + cvolume->channels * sizeof(pa_volume_t)); t->data[t->length++] = PA_TAG_CVOLUME; t->data[t->length++] = cvolume->channels; - + for (i = 0; i < cvolume->channels; i ++) { vol = htonl(cvolume->values[i]); memcpy(t->data + t->length, &vol, sizeof(pa_volume_t)); @@ -245,10 +245,10 @@ int pa_tagstruct_gets(pa_tagstruct*t, const char **s) { *s = NULL; return 0; } - + if (t->rindex+2 > t->length) return -1; - + if (t->data[t->rindex] != PA_TAG_STRING) return -1; @@ -305,7 +305,7 @@ int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) { if (t->data[t->rindex] != PA_TAG_SAMPLE_SPEC) return -1; - + ss->format = t->data[t->rindex+1]; ss->channels = t->data[t->rindex+2]; memcpy(&ss->rate, t->data+t->rindex+3, 4); @@ -318,7 +318,7 @@ int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) { int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) { uint32_t len; assert(t && p); - + if (t->rindex+5+length > t->length) return -1; @@ -357,7 +357,7 @@ int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) { *b = 0; else return -1; - + t->rindex +=1; return 0; } @@ -434,7 +434,7 @@ int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *u) { int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) { unsigned i; - + assert(t); assert(map); @@ -449,7 +449,7 @@ int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) { if (t->rindex+2+map->channels > t->length) return -1; - + for (i = 0; i < map->channels; i ++) map->map[i] = (int8_t) t->data[t->rindex + 2 + i]; @@ -460,7 +460,7 @@ int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) { int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) { unsigned i; pa_volume_t vol; - + assert(t); assert(cvolume); @@ -475,7 +475,7 @@ int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) { if (t->rindex+2+cvolume->channels*sizeof(pa_volume_t) > t->length) return -1; - + for (i = 0; i < cvolume->channels; i ++) { memcpy(&vol, t->data + t->rindex + 2 + i * sizeof(pa_volume_t), sizeof(pa_volume_t)); cvolume->values[i] = (pa_volume_t) ntohl(vol); @@ -488,7 +488,7 @@ int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) { void pa_tagstruct_put(pa_tagstruct *t, ...) { va_list va; assert(t); - + va_start(va, t); for (;;) { @@ -551,16 +551,16 @@ void pa_tagstruct_put(pa_tagstruct *t, ...) { abort(); } } - + va_end(va); } int pa_tagstruct_get(pa_tagstruct *t, ...) { va_list va; int ret = 0; - + assert(t); - + va_start(va, t); while (ret == 0) { int tag = va_arg(va, int); @@ -618,11 +618,11 @@ int pa_tagstruct_get(pa_tagstruct *t, ...) { ret = pa_tagstruct_get_cvolume(t, va_arg(va, pa_cvolume *)); break; - + default: abort(); } - + } va_end(va); diff --git a/src/pulsecore/tagstruct.h b/src/pulsecore/tagstruct.h index 4c56f328..0177ff9d 100644 --- a/src/pulsecore/tagstruct.h +++ b/src/pulsecore/tagstruct.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c index d69790a5..dcd45ea7 100644 --- a/src/pulsecore/thread-posix.c +++ b/src/pulsecore/thread-posix.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -58,8 +58,8 @@ static void tls_free_cb(void *p) { pa_thread *t = p; assert(t); - - if (!t->thread_func) + + if (!t->thread_func) /* This is a foreign thread, we need to free the struct */ pa_xfree(t); } @@ -76,13 +76,13 @@ static void* internal_thread_func(void *userdata) { t->id = pthread_self(); pa_once(&thread_tls_once, thread_tls_once_func); - + pa_tls_set(thread_tls, t); - + pa_atomic_inc(&t->running); t->thread_func(t->userdata); pa_atomic_add(&t->running, -2); - + return NULL; } @@ -90,7 +90,7 @@ pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) { pa_thread *t; assert(thread_func); - + t = pa_xnew(pa_thread, 1); t->thread_func = thread_func; t->userdata = userdata; @@ -116,7 +116,7 @@ int pa_thread_is_running(pa_thread *t) { int policy; struct sched_param param; - + return pthread_getschedparam(t->id, &policy, ¶m) >= 0 || errno != ESRCH; } @@ -125,20 +125,20 @@ int pa_thread_is_running(pa_thread *t) { void pa_thread_free(pa_thread *t) { assert(t); - + pa_thread_join(t); pa_xfree(t); } int pa_thread_join(pa_thread *t) { assert(t); - + return pthread_join(t->id, NULL); } pa_thread* pa_thread_self(void) { pa_thread *t; - + pa_once(&thread_tls_once, thread_tls_once_func); if ((t = pa_tls_get(thread_tls))) @@ -146,7 +146,7 @@ pa_thread* pa_thread_self(void) { /* This is a foreign thread, let's create a pthread structure to * make sure that we can always return a sensible pointer */ - + t = pa_xnew(pa_thread, 1); t->id = pthread_self(); t->thread_func = NULL; @@ -154,7 +154,7 @@ pa_thread* pa_thread_self(void) { pa_atomic_store(&t->running, 2); pa_tls_set(thread_tls, t); - + return t; } @@ -187,7 +187,7 @@ pa_tls* pa_tls_new(pa_free_cb_t free_cb) { pa_xfree(t); return NULL; } - + return t; } @@ -200,13 +200,13 @@ void pa_tls_free(pa_tls *t) { void *pa_tls_get(pa_tls *t) { assert(t); - + return pthread_getspecific(t->key); } void *pa_tls_set(pa_tls *t, void *userdata) { void *r; - + r = pthread_getspecific(t->key); ASSERT_SUCCESS(pthread_setspecific(t->key, userdata)); return r; diff --git a/src/pulsecore/thread-win32.c b/src/pulsecore/thread-win32.c index 98ea0691..38dd4dd6 100644 --- a/src/pulsecore/thread-win32.c +++ b/src/pulsecore/thread-win32.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/thread.h b/src/pulsecore/thread.h index d08990a2..b383bb49 100644 --- a/src/pulsecore/thread.h +++ b/src/pulsecore/thread.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/tokenizer.c b/src/pulsecore/tokenizer.c index e799c1e6..0bc1c095 100644 --- a/src/pulsecore/tokenizer.c +++ b/src/pulsecore/tokenizer.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -69,7 +69,7 @@ static void parse(pa_dynarray*a, const char *s, unsigned args) { pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args) { pa_tokenizer *t; - + t = pa_xmalloc(sizeof(pa_tokenizer)); t->dynarray = pa_dynarray_new(); assert(t->dynarray); diff --git a/src/pulsecore/tokenizer.h b/src/pulsecore/tokenizer.h index b9a5c55b..82cd6db1 100644 --- a/src/pulsecore/tokenizer.h +++ b/src/pulsecore/tokenizer.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/x11prop.c b/src/pulsecore/x11prop.c index dd4ff99e..03d7990e 100644 --- a/src/pulsecore/x11prop.c +++ b/src/pulsecore/x11prop.c @@ -48,7 +48,7 @@ char* pa_x11_get_prop(Display *d, const char *name, char *p, size_t l) { unsigned long nbytes_after; unsigned char *prop = NULL; char *ret = NULL; - + Atom a = XInternAtom(d, name, False); if (XGetWindowProperty(d, RootWindow(d, 0), a, 0, (l+2)/4, False, XA_STRING, &actual_type, &actual_format, &nitems, &nbytes_after, &prop) != Success) goto finish; @@ -65,6 +65,6 @@ finish: if (prop) XFree(prop); - + return ret; } diff --git a/src/pulsecore/x11wrap.c b/src/pulsecore/x11wrap.c index cc993e78..e4b048ba 100644 --- a/src/pulsecore/x11wrap.c +++ b/src/pulsecore/x11wrap.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -42,7 +42,7 @@ struct pa_x11_internal { struct pa_x11_wrapper { pa_core *core; int ref; - + char *property_name; Display *display; @@ -63,7 +63,7 @@ struct pa_x11_client { /* Dispatch all pending X11 events */ static void work(pa_x11_wrapper *w) { assert(w && w->ref >= 1); - + while (XPending(w->display)) { pa_x11_client *c; XEvent e; @@ -90,7 +90,7 @@ static void defer_event(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { assert(m && e && w && w->ref >= 1); m->defer_enable(e, 0); - + work(w); } @@ -154,7 +154,7 @@ static pa_x11_wrapper* x11_wrapper_new(pa_core *c, const char *name, const char w->ref = 1; w->property_name = pa_xstrdup(t); w->display = d; - + PA_LLIST_HEAD_INIT(pa_x11_client, w->clients); PA_LLIST_HEAD_INIT(pa_x11_internal, w->internals); @@ -162,10 +162,10 @@ static pa_x11_wrapper* x11_wrapper_new(pa_core *c, const char *name, const char w->io_event = c->mainloop->io_new(c->mainloop, ConnectionNumber(d), PA_IO_EVENT_INPUT, display_io_event, w); XAddConnectionWatch(d, x11_watch, (XPointer) w); - + r = pa_property_set(c, w->property_name, w); assert(r >= 0); - + return w; } @@ -180,13 +180,13 @@ static void x11_wrapper_free(pa_x11_wrapper*w) { XRemoveConnectionWatch(w->display, x11_watch, (XPointer) w); XCloseDisplay(w->display); - + w->core->mainloop->io_free(w->io_event); w->core->mainloop->defer_free(w->defer_event); while (w->internals) x11_internal_remove(w, w->internals); - + pa_xfree(w->property_name); pa_xfree(w); } @@ -195,7 +195,7 @@ pa_x11_wrapper* pa_x11_wrapper_get(pa_core *c, const char *name) { char t[256]; pa_x11_wrapper *w; assert(c); - + snprintf(t, sizeof(t), "x11-wrapper%s%s", name ? "-" : "", name ? name : ""); if ((w = pa_property_get(c, t))) return pa_x11_wrapper_ref(w); @@ -221,7 +221,7 @@ Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w) { /* Somebody is using us, schedule a output buffer flush */ w->core->mainloop->defer_enable(w->defer_event, 1); - + return w->display; } diff --git a/src/pulsecore/x11wrap.h b/src/pulsecore/x11wrap.h index fcdd9f6c..b2e8e534 100644 --- a/src/pulsecore/x11wrap.h +++ b/src/pulsecore/x11wrap.h @@ -5,17 +5,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/tests/channelmap-test.c b/src/tests/channelmap-test.c index 124ce576..98f36b61 100644 --- a/src/tests/channelmap-test.c +++ b/src/tests/channelmap-test.c @@ -11,23 +11,23 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { pa_channel_map map, map2; pa_channel_map_init_auto(&map, 6, PA_CHANNEL_MAP_AIFF); - + fprintf(stderr, "map: <%s>\n", pa_channel_map_snprint(cm, sizeof(cm), &map)); pa_channel_map_init_auto(&map, 6, PA_CHANNEL_MAP_AUX); - + fprintf(stderr, "map: <%s>\n", pa_channel_map_snprint(cm, sizeof(cm), &map)); pa_channel_map_init_auto(&map, 6, PA_CHANNEL_MAP_ALSA); - + fprintf(stderr, "map: <%s>\n", pa_channel_map_snprint(cm, sizeof(cm), &map)); - + pa_channel_map_parse(&map2, cm); assert(pa_channel_map_equal(&map, &map2)); pa_channel_map_parse(&map2, "left,test"); - + return 0; } diff --git a/src/tests/cpulimit-test.c b/src/tests/cpulimit-test.c index 2302a26d..d582e9c5 100644 --- a/src/tests/cpulimit-test.c +++ b/src/tests/cpulimit-test.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -47,7 +47,7 @@ static time_t start; static void func(pa_mainloop_api *m, PA_GCC_UNUSED pa_signal_event *e, PA_GCC_UNUSED int sig, PA_GCC_UNUSED void *userdata) { time_t now; time(&now); - + if ((now - start) >= 30) { m->quit(m, 1); fprintf(stderr, "Test failed\n"); @@ -59,7 +59,7 @@ static void func(pa_mainloop_api *m, PA_GCC_UNUSED pa_signal_event *e, PA_GCC_UN int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { pa_mainloop *m; - + m = pa_mainloop_new(); assert(m); @@ -77,7 +77,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { for (;;) { time_t now; time(&now); - + if ((now - start) >= 30) { fprintf(stderr, "Test failed\n"); break; @@ -86,7 +86,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { #endif pa_cpu_limit_done(); - + pa_mainloop_free(m); return 0; diff --git a/src/tests/flist-test.c b/src/tests/flist-test.c index abc0659d..17ba55c1 100644 --- a/src/tests/flist-test.c +++ b/src/tests/flist-test.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -41,7 +41,7 @@ static int quit = 0; static void spin(void) { int k; - + /* Spin a little */ k = rand() % 10000; for (; k > 0; k--) @@ -100,6 +100,6 @@ int main(int argc, char* argv[]) { pa_thread_free(threads[i]); pa_flist_free(flist, pa_xfree); - + return 0; } diff --git a/src/tests/get-binary-name-test.c b/src/tests/get-binary-name-test.c index 0cea2b6d..29ebbe22 100644 --- a/src/tests/get-binary-name-test.c +++ b/src/tests/get-binary-name-test.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/tests/hook-list-test.c b/src/tests/hook-list-test.c index d68d1b7d..6879eae5 100644 --- a/src/tests/hook-list-test.c +++ b/src/tests/hook-list-test.c @@ -22,7 +22,7 @@ int main(int argc, char *argv[]) { pa_hook_connect(&hook, (pa_hook_cb_t) func1, (void*) "slot1"); slot = pa_hook_connect(&hook, (pa_hook_cb_t) func2, (void*) "slot2"); pa_hook_connect(&hook, (pa_hook_cb_t) func1, (void*) "slot3"); - + pa_hook_fire(&hook, (void*) "call1"); pa_hook_slot_free(slot); @@ -30,6 +30,6 @@ int main(int argc, char *argv[]) { pa_hook_fire(&hook, (void*) "call2"); pa_hook_free(&hook); - + return 0; } diff --git a/src/tests/interpol-test.c b/src/tests/interpol-test.c index 54bdd775..3953043f 100644 --- a/src/tests/interpol-test.c +++ b/src/tests/interpol-test.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -57,7 +57,7 @@ static void context_state_callback(pa_context *c, void *userdata) { case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_SETTING_NAME: break; - + case PA_CONTEXT_READY: { static const pa_sample_spec ss = { @@ -65,18 +65,18 @@ static void context_state_callback(pa_context *c, void *userdata) { .rate = 44100, .channels = 1 }; - + fprintf(stderr, "Connection established.\n"); stream = pa_stream_new(c, "interpol-test", &ss, NULL); assert(stream); - + pa_stream_connect_playback(stream, NULL, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); pa_stream_set_write_callback(stream, stream_write_cb, NULL); - + break; } - + case PA_CONTEXT_TERMINATED: break; @@ -108,19 +108,19 @@ int main(int argc, char *argv[]) { assert(r >= 0); pa_gettimeofday(&start); - + pa_threaded_mainloop_start(m); for (k = 0; k < 5000; k++) { int success = 0, changed = 0; pa_usec_t t, rtc; struct timeval now, tv; - + pa_threaded_mainloop_lock(m); if (stream) { const pa_timing_info *info; - + if (pa_stream_get_time(stream, &t) >= 0) success = 1; @@ -130,9 +130,9 @@ int main(int argc, char *argv[]) { last_info = info->timestamp; } } - + pa_threaded_mainloop_unlock(m); - + if (success) { pa_gettimeofday(&now); @@ -156,7 +156,7 @@ int main(int argc, char *argv[]) { pa_stream_disconnect(stream); pa_stream_unref(stream); } - + if (context) { pa_context_disconnect(context); pa_context_unref(context); @@ -164,6 +164,6 @@ int main(int argc, char *argv[]) { if (m) pa_threaded_mainloop_free(m); - + return 0; } diff --git a/src/tests/ipacl-test.c b/src/tests/ipacl-test.c index 2566b038..d1bcb3e3 100644 --- a/src/tests/ipacl-test.c +++ b/src/tests/ipacl-test.c @@ -37,13 +37,13 @@ int main(int argc, char *argv[]) { int r; pa_ip_acl *acl; - fd = socket(PF_INET, SOCK_STREAM, 0); + fd = socket(PF_INET, SOCK_STREAM, 0); assert(fd >= 0); - + sa.sin_family = AF_INET; sa.sin_port = htons(22); sa.sin_addr.s_addr = inet_addr("127.0.0.1"); - + r = connect(fd, (struct sockaddr*) &sa, sizeof(sa)); assert(r >= 0); @@ -66,7 +66,7 @@ int main(int argc, char *argv[]) { assert(acl); printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd)); pa_ip_acl_free(acl); - + acl = pa_ip_acl_new("127.0.0.2"); assert(acl); printf("result=%u (should be 0)\n", pa_ip_acl_check(acl, fd)); @@ -86,7 +86,7 @@ int main(int argc, char *argv[]) { assert(acl); printf("result=%u (should be 0)\n", pa_ip_acl_check(acl, fd)); pa_ip_acl_free(acl); - + close(fd); fd = socket(PF_INET6, SOCK_STREAM, 0); @@ -96,7 +96,7 @@ int main(int argc, char *argv[]) { sa6.sin6_family = AF_INET6; sa6.sin6_port = htons(22); inet_pton(AF_INET6, "::1", &sa6.sin6_addr); - + r = connect(fd, (struct sockaddr*) &sa6, sizeof(sa6)); assert(r >= 0); @@ -131,6 +131,6 @@ int main(int argc, char *argv[]) { pa_ip_acl_free(acl); close(fd); - + return 0; } diff --git a/src/tests/mainloop-test.c b/src/tests/mainloop-test.c index b06d0ed1..c386251c 100644 --- a/src/tests/mainloop-test.c +++ b/src/tests/mainloop-test.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -121,6 +121,6 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { #else pa_mainloop_free(m); #endif - + return 0; } diff --git a/src/tests/mcalign-test.c b/src/tests/mcalign-test.c index 35691698..db76712b 100644 --- a/src/tests/mcalign-test.c +++ b/src/tests/mcalign-test.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -45,7 +45,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { p = pa_mempool_new(0); a = pa_mcalign_new(11); - + pa_memchunk_reset(&c); srand(time(NULL)); @@ -64,7 +64,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { l = c.memblock->length - c.index; l = l <= 1 ? l : rand() % (l-1) +1 ; - + if ((r = read(STDIN_FILENO, (uint8_t*) c.memblock->data + c.index, l)) <= 0) { fprintf(stderr, "read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); break; diff --git a/src/tests/memblock-test.c b/src/tests/memblock-test.c index ef2e0ad7..13bfdf0d 100644 --- a/src/tests/memblock-test.c +++ b/src/tests/memblock-test.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -78,7 +78,7 @@ int main(int argc, char *argv[]) { size_t offset, size; const char txt[] = "This is a test!"; - + pool_a = pa_mempool_new(1); pool_b = pa_mempool_new(1); pool_c = pa_mempool_new(1); @@ -86,9 +86,9 @@ int main(int argc, char *argv[]) { pa_mempool_get_shm_id(pool_a, &id_a); pa_mempool_get_shm_id(pool_b, &id_b); pa_mempool_get_shm_id(pool_c, &id_c); - + assert(pool_a && pool_b && pool_c); - + blocks[0] = pa_memblock_new_fixed(pool_a, (void*) txt, sizeof(txt), 1); blocks[1] = pa_memblock_new(pool_a, sizeof(txt)); snprintf(blocks[1]->data, blocks[1]->length, "%s", txt); @@ -102,23 +102,23 @@ int main(int argc, char *argv[]) { mb_a = blocks[i]; assert(mb_a); - + export_a = pa_memexport_new(pool_a, revoke_cb, (void*) "A"); export_b = pa_memexport_new(pool_b, revoke_cb, (void*) "B"); - + assert(export_a && export_b); - + import_b = pa_memimport_new(pool_b, release_cb, (void*) "B"); import_c = pa_memimport_new(pool_c, release_cb, (void*) "C"); - + assert(import_b && import_c); - + r = pa_memexport_put(export_a, mb_a, &id, &shm_id, &offset, &size); assert(r >= 0); assert(shm_id == id_a); printf("A: Memory block exported as %u\n", id); - + mb_b = pa_memimport_get(import_b, id, shm_id, offset, size); assert(mb_b); r = pa_memexport_put(export_b, mb_b, &id, &shm_id, &offset, &size); @@ -127,7 +127,7 @@ int main(int argc, char *argv[]) { pa_memblock_unref(mb_b); printf("B: Memory block exported as %u\n", id); - + mb_c = pa_memimport_get(import_c, id, shm_id, offset, size); assert(mb_c); printf("1 data=%s\n", (char*) mb_c->data); @@ -135,21 +135,21 @@ int main(int argc, char *argv[]) { print_stats(pool_a, "A"); print_stats(pool_b, "B"); print_stats(pool_c, "C"); - + pa_memexport_free(export_b); printf("2 data=%s\n", (char*) mb_c->data); pa_memblock_unref(mb_c); - + pa_memimport_free(import_b); - + pa_memblock_unref(mb_a); - + pa_memimport_free(import_c); pa_memexport_free(export_a); } printf("vaccuuming...\n"); - + pa_mempool_vacuum(pool_a); pa_mempool_vacuum(pool_b); pa_mempool_vacuum(pool_c); diff --git a/src/tests/memblockq-test.c b/src/tests/memblockq-test.c index 1ac4577b..1c0b7fed 100644 --- a/src/tests/memblockq-test.c +++ b/src/tests/memblockq-test.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -41,7 +41,7 @@ int main(int argc, char *argv[]) { pa_log_set_maximal_level(PA_LOG_DEBUG); p = pa_mempool_new(0); - + silence = pa_memblock_new_fixed(p, (char*) "__", 2, 1); assert(silence); @@ -52,7 +52,7 @@ int main(int argc, char *argv[]) { chunk1.index = 0; chunk1.length = 2; assert(chunk1.memblock); - + chunk2.memblock = pa_memblock_new_fixed(p, (char*) "TTBB", 4, 1); chunk2.index = 2; chunk2.length = 2; @@ -70,13 +70,13 @@ int main(int argc, char *argv[]) { ret = pa_memblockq_push(bq, &chunk1); assert(ret == 0); - + ret = pa_memblockq_push(bq, &chunk1); assert(ret == 0); - + ret = pa_memblockq_push(bq, &chunk2); assert(ret == 0); - + ret = pa_memblockq_push(bq, &chunk2); assert(ret == 0); @@ -115,19 +115,19 @@ int main(int argc, char *argv[]) { chunk3.index += 2; chunk3.length -= 2; - + ret = pa_memblockq_push(bq, &chunk3); assert(ret == 0); - + printf(">"); pa_memblockq_shorten(bq, 6); - + for (;;) { pa_memchunk out; char *e; size_t n; - + if (pa_memblockq_peek(bq, &out) < 0) break; @@ -137,15 +137,15 @@ int main(int argc, char *argv[]) { pa_memblock_unref(out.memblock); pa_memblockq_drop(bq, &out, out.length); } - + printf("<\n"); - + pa_memblockq_free(bq); pa_memblock_unref(silence); pa_memblock_unref(chunk1.memblock); pa_memblock_unref(chunk2.memblock); pa_memblock_unref(chunk3.memblock); pa_memblock_unref(chunk4.memblock); - + return 0; } diff --git a/src/tests/pacat-simple.c b/src/tests/pacat-simple.c index 364e1ad6..2da67c1a 100644 --- a/src/tests/pacat-simple.c +++ b/src/tests/pacat-simple.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -43,7 +43,7 @@ int main(PA_GCC_UNUSED int argc, char*argv[]) { .rate = 44100, .channels = 2 }; - + pa_simple *s = NULL; int ret = 1; int error; @@ -61,10 +61,10 @@ int main(PA_GCC_UNUSED int argc, char*argv[]) { fprintf(stderr, __FILE__": dup2() failed: %s\n", strerror(errno)); goto finish; } - + close(fd); } - + /* Create a new playback stream */ if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL, &error))) { fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); @@ -90,7 +90,7 @@ int main(PA_GCC_UNUSED int argc, char*argv[]) { if ((r = read(STDIN_FILENO, buf, sizeof(buf))) <= 0) { if (r == 0) /* EOF */ break; - + fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno)); goto finish; } @@ -114,6 +114,6 @@ finish: if (s) pa_simple_free(s); - + return ret; } diff --git a/src/tests/parec-simple.c b/src/tests/parec-simple.c index 45a52288..d7d88360 100644 --- a/src/tests/parec-simple.c +++ b/src/tests/parec-simple.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -46,7 +46,7 @@ static ssize_t loop_write(int fd, const void*data, size_t size) { if (r == 0) break; - + ret += r; data = (const uint8_t*) data + r; size -= r; @@ -95,6 +95,6 @@ finish: if (s) pa_simple_free(s); - + return ret; } diff --git a/src/tests/strlist-test.c b/src/tests/strlist-test.c index 4262a001..47770b5d 100644 --- a/src/tests/strlist-test.c +++ b/src/tests/strlist-test.c @@ -16,7 +16,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char* argv[]) { t = pa_strlist_tostring(l); pa_strlist_free(l); - + fprintf(stderr, "1: %s\n", t); l = pa_strlist_parse(t); @@ -29,9 +29,9 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char* argv[]) { l = pa_strlist_pop(l, &u); fprintf(stderr, "3: %s\n", u); pa_xfree(u); - + l = pa_strlist_remove(l, "c"); - + t = pa_strlist_tostring(l); fprintf(stderr, "4: %s\n", t); pa_xfree(t); diff --git a/src/tests/sync-playback.c b/src/tests/sync-playback.c index 39c6aac4..63510eb6 100644 --- a/src/tests/sync-playback.c +++ b/src/tests/sync-playback.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -67,7 +67,7 @@ static void underflow_cb(struct pa_stream *s, void *userdata) { int i = (int) (long) userdata; fprintf(stderr, "Stream %i finished\n", i); - + if (++n_streams_ready >= 2*NSTREAMS) { fprintf(stderr, "We're done\n"); mainloop_api->quit(mainloop_api, 0); @@ -89,19 +89,19 @@ static void stream_state_callback(pa_stream *s, void *userdata) { int r, i = (int) (long) userdata; fprintf(stderr, "Writing data to stream %i.\n", i); - + r = pa_stream_write(s, data, sizeof(data), nop_free_cb, sizeof(data) * i, PA_SEEK_ABSOLUTE); assert(r == 0); /* Be notified when this stream is drained */ pa_stream_set_underflow_callback(s, underflow_cb, userdata); - + /* All streams have been set up, let's go! */ if (++n_streams_ready >= NSTREAMS) { fprintf(stderr, "Uncorking\n"); pa_operation_unref(pa_stream_cork(s, 0, NULL, NULL)); } - + break; } @@ -121,7 +121,7 @@ static void context_state_callback(pa_context *c, void *userdata) { case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_SETTING_NAME: break; - + case PA_CONTEXT_READY: { int i; @@ -131,18 +131,18 @@ static void context_state_callback(pa_context *c, void *userdata) { char name[64]; fprintf(stderr, "Creating stream %i\n", i); - + snprintf(name, sizeof(name), "stream #%i", i); - + streams[i] = pa_stream_new(c, name, &sample_spec, NULL); assert(streams[i]); pa_stream_set_state_callback(streams[i], stream_state_callback, (void*) (long) i); pa_stream_connect_playback(streams[i], NULL, &buffer_attr, PA_STREAM_START_CORKED, NULL, i == 0 ? NULL : streams[0]); } - + break; } - + case PA_CONTEXT_TERMINATED: mainloop_api->quit(mainloop_api, 0); break; @@ -163,7 +163,7 @@ int main(int argc, char *argv[]) { for (i = 0; i < NSTREAMS; i++) streams[i] = NULL; - + /* Set up a new main loop */ m = pa_mainloop_new(); assert(m); @@ -187,6 +187,6 @@ int main(int argc, char *argv[]) { pa_stream_unref(streams[i]); pa_mainloop_free(m); - + return ret; } diff --git a/src/tests/thread-mainloop-test.c b/src/tests/thread-mainloop-test.c index bf3d4cd2..9d0e5de1 100644 --- a/src/tests/thread-mainloop-test.c +++ b/src/tests/thread-mainloop-test.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -53,19 +53,19 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { pa_threaded_mainloop_start(m); pa_threaded_mainloop_lock(m); - + pa_gettimeofday(&tv); tv.tv_sec += 5; a->time_new(a, &tv, tcb, m); - + fprintf(stderr, "waiting 5s (signal)\n"); pa_threaded_mainloop_wait(m); fprintf(stderr, "wait completed\n"); pa_threaded_mainloop_accept(m); fprintf(stderr, "signal accepted\n"); - + pa_threaded_mainloop_unlock(m); - + fprintf(stderr, "waiting 5s (sleep)\n"); pa_msleep(5000); diff --git a/src/tests/thread-test.c b/src/tests/thread-test.c index 9559cdbb..2153c985 100644 --- a/src/tests/thread-test.c +++ b/src/tests/thread-test.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -48,7 +48,7 @@ static void thread_func(void *data) { pa_tls_set(tls, data); pa_log("thread_func() for %s starting...", (char*) pa_tls_get(tls)); - + pa_mutex_lock(mutex); for (;;) { @@ -57,13 +57,13 @@ static void thread_func(void *data) { pa_log("%s waiting ...", (char*) pa_tls_get(tls)); for (;;) { - + if (magic_number < 0) goto quit; if (magic_number != 0) break; - + pa_cond_wait(cond1, mutex); } @@ -75,18 +75,18 @@ static void thread_func(void *data) { pa_once(&once, once_func); pa_cond_signal(cond2, 0); - + pa_log("%s got number %i", (char*) pa_tls_get(tls), k); - + /* Spin! */ for (n = 0; n < k; n++) pa_thread_yield(); - + pa_mutex_lock(mutex); } quit: - + pa_mutex_unlock(mutex); pa_log("thread_func() for %s done...", (char*) pa_tls_get(tls)); @@ -97,25 +97,25 @@ int main(int argc, char *argv[]) { pa_thread* t[THREADS_MAX]; assert(pa_thread_is_running(pa_thread_self())); - + mutex = pa_mutex_new(0); cond1 = pa_cond_new(); cond2 = pa_cond_new(); tls = pa_tls_new(pa_xfree); - + for (i = 0; i < THREADS_MAX; i++) { t[i] = pa_thread_new(thread_func, pa_sprintf_malloc("Thread #%i", i+1)); assert(t[i]); } pa_mutex_lock(mutex); - + pa_log("loop-init"); for (k = 0; k < 100; k++) { assert(magic_number == 0); - + magic_number = (int) rand() % 0x10000; pa_log("iteration %i (%i)", k, magic_number); @@ -126,10 +126,10 @@ int main(int argc, char *argv[]) { } pa_log("loop-exit"); - + magic_number = -1; pa_cond_signal(cond1, 1); - + pa_mutex_unlock(mutex); for (i = 0; i < THREADS_MAX; i++) diff --git a/src/tests/utf8-test.c b/src/tests/utf8-test.c index 2e9f128a..b9594dcc 100644 --- a/src/tests/utf8-test.c +++ b/src/tests/utf8-test.c @@ -8,13 +8,13 @@ int main(int argc, char *argv[]) { char *c; - + assert(pa_utf8_valid("hallo")); assert(pa_utf8_valid("hallo\n")); assert(!pa_utf8_valid("hüpfburg\n")); assert(pa_utf8_valid("hallo\n")); assert(pa_utf8_valid("hüpfburg\n")); - + printf("LATIN1: %s\n", c = pa_utf8_filter("hüpfburg")); pa_xfree(c); printf("UTF8: %sx\n", c = pa_utf8_filter("hüpfburg")); diff --git a/src/tests/voltest.c b/src/tests/voltest.c index 3de884af..dcc1ec51 100644 --- a/src/tests/voltest.c +++ b/src/tests/voltest.c @@ -12,7 +12,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { double dB = pa_sw_volume_to_dB(v); double f = pa_sw_volume_to_linear(v); - + printf("Volume: %3i; percent: %i%%; decibel %0.2f; linear = %0.2f; volume(decibel): %3i; volume(linear): %3i\n", v, (v*100)/PA_VOLUME_NORM, dB, f, pa_sw_volume_from_dB(dB), pa_sw_volume_from_linear(f)); diff --git a/src/utils/pabrowse.c b/src/utils/pabrowse.c index 450182f5..f756ac01 100644 --- a/src/utils/pabrowse.c +++ b/src/utils/pabrowse.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -40,7 +40,7 @@ static void dump_server(const pa_browse_info *i) { if (i->cookie) snprintf(t, sizeof(t), "0x%08x", *i->cookie); - + printf("server: %s\n" "server-version: %s\n" "user-name: %s\n" @@ -65,7 +65,7 @@ static void dump_device(const pa_browse_info *i) { i->device, i->description ? i->description : "n/a", i->sample_spec ? ss : "n/a"); - + } static void browser_callback(pa_browser *b, pa_browse_opcode_t c, const pa_browse_info *i, void *userdata) { @@ -89,7 +89,7 @@ static void browser_callback(pa_browser *b, pa_browse_opcode_t c, const pa_brows dump_server(i); dump_device(i); break; - + case PA_BROWSE_REMOVE_SERVER: printf("\n=> removed server <%s>\n", i->name); break; @@ -109,7 +109,7 @@ static void browser_callback(pa_browser *b, pa_browse_opcode_t c, const pa_brows static void error_callback(pa_browser *b, const char *s, void *userdata) { pa_mainloop_api*m = userdata; - + fprintf(stderr, "Failure: %s\n", s); m->quit(m, 1); } @@ -128,7 +128,7 @@ int main(int argc, char *argv[]) { pa_signal_new(SIGINT, exit_signal_callback, NULL); pa_signal_new(SIGTERM, exit_signal_callback, NULL); signal(SIGPIPE, SIG_IGN); - + if (!(browser = pa_browser_new_full(pa_mainloop_get_api(mainloop), PA_BROWSE_FOR_SERVERS|PA_BROWSE_FOR_SINKS|PA_BROWSE_FOR_SOURCES, &s))) { fprintf(stderr, "pa_browse_new_full(): %s\n", s); goto finish; @@ -136,7 +136,7 @@ int main(int argc, char *argv[]) { pa_browser_set_callback(browser, browser_callback, NULL); pa_browser_set_error_callback(browser, error_callback, pa_mainloop_get_api(mainloop)); - + ret = 0; pa_mainloop_run(mainloop, &ret); diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 1c581f4d..cb103c99 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -79,20 +79,20 @@ static void do_stream_write(size_t length) { if (!buffer || !buffer_length) return; - + l = length; if (l > buffer_length) l = buffer_length; - + if (pa_stream_write(stream, (uint8_t*) buffer + buffer_index, l, NULL, 0, PA_SEEK_RELATIVE) < 0) { fprintf(stderr, "pa_stream_write() failed: %s\n", pa_strerror(pa_context_errno(context))); quit(1); return; } - + buffer_length -= l; buffer_index += l; - + if (!buffer_length) { pa_xfree(buffer); buffer = NULL; @@ -126,7 +126,7 @@ static void stream_read_callback(pa_stream *s, size_t length, void *userdata) { quit(1); return; } - + assert(data && length); if (buffer) { @@ -156,7 +156,7 @@ static void stream_state_callback(pa_stream *s, void *userdata) { case PA_STREAM_READY: if (verbose) { const pa_buffer_attr *a; - + fprintf(stderr, "Stream successfully created.\n"); if (!(a = pa_stream_get_buffer_attr(s))) @@ -169,13 +169,13 @@ static void stream_state_callback(pa_stream *s, void *userdata) { assert(mode == RECORD); fprintf(stderr, "Buffer metrics: maxlength=%u, fragsize=%u\n", a->maxlength, a->fragsize); } - + } } - + break; - + case PA_STREAM_FAILED: default: fprintf(stderr, "Stream error: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); @@ -192,10 +192,10 @@ static void context_state_callback(pa_context *c, void *userdata) { case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_SETTING_NAME: break; - + case PA_CONTEXT_READY: { int r; - + assert(c && !stream); if (verbose) @@ -216,17 +216,17 @@ static void context_state_callback(pa_context *c, void *userdata) { fprintf(stderr, "pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(c))); goto fail; } - + } else { if ((r = pa_stream_connect_record(stream, device, NULL, 0)) < 0) { fprintf(stderr, "pa_stream_connect_record() failed: %s\n", pa_strerror(pa_context_errno(c))); goto fail; } } - + break; } - + case PA_CONTEXT_TERMINATED: quit(0); break; @@ -238,10 +238,10 @@ static void context_state_callback(pa_context *c, void *userdata) { } return; - + fail: quit(1); - + } /* Connection draining complete */ @@ -257,14 +257,14 @@ static void stream_drain_complete(pa_stream*s, int success, void *userdata) { fprintf(stderr, "Failed to drain stream: %s\n", pa_strerror(pa_context_errno(context))); quit(1); } - - if (verbose) + + if (verbose) fprintf(stderr, "Playback stream drained.\n"); pa_stream_disconnect(stream); pa_stream_unref(stream); stream = NULL; - + if (!(o = pa_context_drain(context, context_drain_complete, NULL))) pa_context_disconnect(context); else { @@ -286,7 +286,7 @@ static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_even if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY || !(l = w = pa_stream_writable_size(stream))) l = 4096; - + buffer = pa_xmalloc(l); if ((r = read(fd, buffer, l)) <= 0) { @@ -296,17 +296,17 @@ static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_even if (stream) { pa_operation *o; - + if (!(o = pa_stream_drain(stream, stream_drain_complete, NULL))) { fprintf(stderr, "pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(context))); quit(1); return; } - + pa_operation_unref(o); } else quit(0); - + } else { fprintf(stderr, "read() failed: %s\n", strerror(errno)); quit(1); @@ -335,7 +335,7 @@ static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_eve } assert(buffer_length); - + if ((r = write(fd, (uint8_t*) buffer+buffer_index, buffer_length)) <= 0) { fprintf(stderr, "write() failed: %s\n", strerror(errno)); quit(1); @@ -366,7 +366,7 @@ static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, static void stream_update_timing_callback(pa_stream *s, int success, void *userdata) { pa_usec_t latency, usec; int negative = 0; - + assert(s); if (!success || @@ -387,13 +387,13 @@ static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int s if (!stream) return; - + pa_operation_unref(pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL)); } static void time_event_callback(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { struct timeval next; - + if (stream && pa_stream_get_state(stream) == PA_STREAM_READY) { pa_operation *o; if (!(o = pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL))) @@ -481,7 +481,7 @@ int main(int argc, char *argv[]) { help(bn); ret = 0; goto quit; - + case ARG_VERSION: printf("pacat "PACKAGE_VERSION"\nCompiled with libpulse %s\nLinked with libpulse %s\n", pa_get_headers_version(), pa_get_library_version()); ret = 0; @@ -525,7 +525,7 @@ int main(int argc, char *argv[]) { break; } - case ARG_CHANNELS: + case ARG_CHANNELS: sample_spec.channels = atoi(optarg); break; @@ -545,7 +545,7 @@ int main(int argc, char *argv[]) { channel_map_set = 1; break; - + default: goto quit; } @@ -560,7 +560,7 @@ int main(int argc, char *argv[]) { fprintf(stderr, "Channel map doesn't match sample specification\n"); goto quit; } - + if (verbose) { char t[PA_SAMPLE_SPEC_SNPRINT_MAX]; pa_sample_spec_snprint(t, sizeof(t), &sample_spec); @@ -570,22 +570,22 @@ int main(int argc, char *argv[]) { if (!(optind >= argc)) { if (optind+1 == argc) { int fd; - + if ((fd = open(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) { fprintf(stderr, "open(): %s\n", strerror(errno)); goto quit; } - + if (dup2(fd, mode == PLAYBACK ? 0 : 1) < 0) { fprintf(stderr, "dup2(): %s\n", strerror(errno)); goto quit; } - + close(fd); if (!stream_name) stream_name = pa_xstrdup(argv[optind]); - + } else { fprintf(stderr, "Too many arguments.\n"); goto quit; @@ -616,7 +616,7 @@ int main(int argc, char *argv[]) { #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif - + if (!(stdio_event = mainloop_api->io_new(mainloop_api, mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO, mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT, @@ -641,7 +641,7 @@ int main(int argc, char *argv[]) { pa_gettimeofday(&tv); pa_timeval_add(&tv, TIME_EVENT_USEC); - + if (!(time_event = mainloop_api->time_new(mainloop_api, &tv, time_event_callback, NULL))) { fprintf(stderr, "time_new() failed.\n"); goto quit; @@ -653,7 +653,7 @@ int main(int argc, char *argv[]) { fprintf(stderr, "pa_mainloop_run() failed.\n"); goto quit; } - + quit: if (stream) pa_stream_unref(stream); @@ -670,7 +670,7 @@ quit: assert(mainloop_api); mainloop_api->time_free(time_event); } - + if (m) { pa_signal_done(); pa_mainloop_free(m); @@ -682,6 +682,6 @@ quit: pa_xfree(device); pa_xfree(client_name); pa_xfree(stream_name); - + return ret; } diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c index b9912701..d25b26c3 100644 --- a/src/utils/pacmd.c +++ b/src/utils/pacmd.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -64,12 +64,12 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { for (i = 0; i < 5; i++) { int r; - + if ((r = connect(fd, (struct sockaddr*) &sa, sizeof(sa))) < 0 && (errno != ECONNREFUSED && errno != ENOENT)) { pa_log("connect(): %s", strerror(errno)); goto fail; } - + if (r >= 0) break; @@ -94,7 +94,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { FD_SET(fd, &ifds); FD_ZERO(&ofds); - + for (;;) { if (select(FD_SETSIZE, &ifds, &ofds, NULL, NULL) < 0) { pa_log("select(): %s", strerror(errno)); @@ -104,19 +104,19 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { if (FD_ISSET(0, &ifds)) { ssize_t r; assert(!ibuf_length); - + if ((r = read(0, ibuf, sizeof(ibuf))) <= 0) { if (r == 0) break; - + pa_log("read(): %s", strerror(errno)); goto fail; } - + ibuf_length = (size_t) r; ibuf_index = 0; } - + if (FD_ISSET(fd, &ifds)) { ssize_t r; assert(!obuf_length); @@ -124,7 +124,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { if ((r = read(fd, obuf, sizeof(obuf))) <= 0) { if (r == 0) break; - + pa_log("read(): %s", strerror(errno)); goto fail; } @@ -136,12 +136,12 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { if (FD_ISSET(1, &ofds)) { ssize_t r; assert(obuf_length); - + if ((r = write(1, obuf + obuf_index, obuf_length)) < 0) { pa_log("write(): %s", strerror(errno)); goto fail; } - + obuf_length -= (size_t) r; obuf_index += obuf_index; @@ -150,12 +150,12 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { if (FD_ISSET(fd, &ofds)) { ssize_t r; assert(ibuf_length); - + if ((r = write(fd, ibuf + ibuf_index, ibuf_length)) < 0) { pa_log("write(): %s", strerror(errno)); goto fail; } - + ibuf_length -= (size_t) r; ibuf_index += obuf_index; @@ -163,24 +163,24 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { FD_ZERO(&ifds); FD_ZERO(&ofds); - + if (obuf_length <= 0) FD_SET(fd, &ifds); else FD_SET(1, &ofds); - + if (ibuf_length <= 0) FD_SET(0, &ifds); else FD_SET(fd, &ofds); } - + ret = 0; - + fail: if (fd >= 0) close(fd); - + return ret; } diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 110585f7..0c418c4f 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -112,13 +112,13 @@ static void stat_callback(pa_context *c, const pa_stat_info *i, void *userdata) pa_bytes_snprint(s, sizeof(s), i->scache_size); printf("Sample cache size: %s\n", s); - + complete_action(); } static void get_server_info_callback(pa_context *c, const pa_server_info *i, void *useerdata) { char s[PA_SAMPLE_SPEC_SNPRINT_MAX]; - + if (!i) { fprintf(stderr, "Failed to get server information: %s\n", pa_strerror(pa_context_errno(c))); quit(1); @@ -149,7 +149,7 @@ static void get_server_info_callback(pa_context *c, const pa_server_info *i, voi static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) { char s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - + if (is_last < 0) { fprintf(stderr, "Failed to get sink information: %s\n", pa_strerror(pa_context_errno(c))); quit(1); @@ -160,7 +160,7 @@ static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_ complete_action(); return; } - + assert(i); if (nl) @@ -207,7 +207,7 @@ static void get_source_info_callback(pa_context *c, const pa_source_info *i, int complete_action(); return; } - + assert(i); if (nl) @@ -215,7 +215,7 @@ static void get_source_info_callback(pa_context *c, const pa_source_info *i, int nl = 1; snprintf(t, sizeof(t), "%u", i->monitor_of_sink); - + printf("*** Source #%u ***\n" "Name: %s\n" "Driver: %s\n" @@ -256,7 +256,7 @@ static void get_module_info_callback(pa_context *c, const pa_module_info *i, int complete_action(); return; } - + assert(i); if (nl) @@ -264,7 +264,7 @@ static void get_module_info_callback(pa_context *c, const pa_module_info *i, int nl = 1; snprintf(t, sizeof(t), "%u", i->n_used); - + printf("*** Module #%u ***\n" "Name: %s\n" "Argument: %s\n" @@ -290,7 +290,7 @@ static void get_client_info_callback(pa_context *c, const pa_client_info *i, int complete_action(); return; } - + assert(i); if (nl) @@ -298,7 +298,7 @@ static void get_client_info_callback(pa_context *c, const pa_client_info *i, int nl = 1; snprintf(t, sizeof(t), "%u", i->owner_module); - + printf("*** Client #%u ***\n" "Name: %s\n" "Driver: %s\n" @@ -322,7 +322,7 @@ static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info complete_action(); return; } - + assert(i); if (nl) @@ -331,7 +331,7 @@ static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info snprintf(t, sizeof(t), "%u", i->owner_module); snprintf(k, sizeof(k), "%u", i->client); - + printf("*** Sink Input #%u ***\n" "Name: %s\n" "Driver: %s\n" @@ -372,17 +372,17 @@ static void get_source_output_info_callback(pa_context *c, const pa_source_outpu complete_action(); return; } - + assert(i); if (nl) printf("\n"); nl = 1; - + snprintf(t, sizeof(t), "%u", i->owner_module); snprintf(k, sizeof(k), "%u", i->client); - + printf("*** Source Output #%u ***\n" "Name: %s\n" "Driver: %s\n" @@ -420,16 +420,16 @@ static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int complete_action(); return; } - + assert(i); if (nl) printf("\n"); nl = 1; - + pa_bytes_snprint(t, sizeof(t), i->bytes); - + printf("*** Sample #%u ***\n" "Name: %s\n" "Volume: %s\n" @@ -461,7 +461,7 @@ static void get_autoload_info_callback(pa_context *c, const pa_autoload_info *i, complete_action(); return; } - + assert(i); if (nl) @@ -497,11 +497,11 @@ static void stream_state_callback(pa_stream *s, void *userdata) { case PA_STREAM_CREATING: case PA_STREAM_READY: break; - + case PA_STREAM_TERMINATED: drain(); break; - + case PA_STREAM_FAILED: default: fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); @@ -524,7 +524,7 @@ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { fprintf(stderr, "Premature end of file\n"); quit(1); } - + pa_stream_write(s, d, length, pa_xfree, 0, PA_SEEK_RELATIVE); sample_length -= length; @@ -551,7 +551,7 @@ static void context_state_callback(pa_context *c, void *userdata) { pa_operation_unref(pa_context_get_server_info(c, get_server_info_callback, NULL)); break; - case PLAY_SAMPLE: + case PLAY_SAMPLE: pa_operation_unref(pa_context_play_sample(c, sample_name, device, PA_VOLUME_NORM, simple_callback, NULL)); break; @@ -562,12 +562,12 @@ static void context_state_callback(pa_context *c, void *userdata) { case UPLOAD_SAMPLE: sample_stream = pa_stream_new(c, sample_name, &sample_spec, NULL); assert(sample_stream); - + pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL); pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL); pa_stream_connect_upload(sample_stream, sample_length); break; - + case EXIT: pa_operation_unref(pa_context_exit_daemon(c, NULL, NULL)); drain(); @@ -578,7 +578,7 @@ static void context_state_callback(pa_context *c, void *userdata) { pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL)); pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL)); pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL)); - pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL)); + pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL)); pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL)); pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL)); pa_operation_unref(pa_context_get_autoload_info_list(c, get_autoload_info_callback, NULL)); @@ -591,7 +591,7 @@ static void context_state_callback(pa_context *c, void *userdata) { case MOVE_SOURCE_OUTPUT: pa_operation_unref(pa_context_move_source_output_by_name(c, source_output_idx, source_name, simple_callback, NULL)); break; - + default: assert(0); } @@ -650,14 +650,14 @@ int main(int argc, char *argv[]) { bn = argv[0]; else bn++; - + while ((c = getopt_long(argc, argv, "s:n:h", long_options, NULL)) != -1) { switch (c) { case 'h' : help(bn); ret = 0; goto quit; - + case ARG_VERSION: printf("pactl "PACKAGE_VERSION"\nCompiled with libpulse %s\nLinked with libpulse %s\n", pa_get_headers_version(), pa_get_library_version()); ret = 0; @@ -680,7 +680,7 @@ int main(int argc, char *argv[]) { if (!client_name) client_name = pa_xstrdup(bn); - + if (optind < argc) { if (!strcmp(argv[optind], "stat")) action = STAT; @@ -712,13 +712,13 @@ int main(int argc, char *argv[]) { tmp[n] = 0; sample_name = pa_xstrdup(tmp); } - + memset(&sfinfo, 0, sizeof(sfinfo)); if (!(sndfile = sf_open(argv[optind+1], SFM_READ, &sfinfo))) { fprintf(stderr, "Failed to open sound file.\n"); goto quit; } - + sample_spec.format = PA_SAMPLE_FLOAT32; sample_spec.rate = sfinfo.samplerate; sample_spec.channels = sfinfo.channels; @@ -735,7 +735,7 @@ int main(int argc, char *argv[]) { if (optind+2 < argc) device = pa_xstrdup(argv[optind+2]); - + } else if (!strcmp(argv[optind], "remove-sample")) { action = REMOVE_SAMPLE; if (optind+1 >= argc) { @@ -783,7 +783,7 @@ int main(int argc, char *argv[]) { #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif - + if (!(context = pa_context_new(mainloop_api, client_name))) { fprintf(stderr, "pa_context_new() failed.\n"); goto quit; @@ -808,7 +808,7 @@ quit: pa_signal_done(); pa_mainloop_free(m); } - + if (sndfile) sf_close(sndfile); diff --git a/src/utils/padsp.c b/src/utils/padsp.c index a8ac8667..679a5d01 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -69,7 +69,7 @@ struct fd_info { pthread_mutex_t mutex; int ref; int unusable; - + fd_info_type_t type; int app_fd, thread_fd; @@ -95,7 +95,7 @@ struct fd_info { int volume_modify_count; int optr_n_blocks; - + PA_LLIST_FIELDS(fd_info); }; @@ -248,7 +248,7 @@ static int padsp_disabled(void) { * -> disable /dev/dsp emulation, bit 2 -> disable /dev/sndstat * emulation, bit 3 -> disable /dev/mixer emulation. Hence a value * of 7 disables padsp entirely. */ - + pthread_mutex_lock(&func_mutex); if (!sym_resolved) { sym = (int*) dlsym(RTLD_DEFAULT, "__padsp_disabled__"); @@ -259,14 +259,14 @@ static int padsp_disabled(void) { if (!sym) return 0; - + return *sym; } static int dsp_cloak_enable(void) { if (padsp_disabled() & 1) return 0; - + if (getenv("PADSP_NO_DSP")) return 0; @@ -302,7 +302,7 @@ static int function_enter(void) { /* Avoid recursive calls */ static pthread_once_t recursion_key_once = PTHREAD_ONCE_INIT; pthread_once(&recursion_key_once, recursion_key_alloc); - + if (pthread_getspecific(recursion_key)) return 0; @@ -320,10 +320,10 @@ static void fd_info_free(fd_info *i) { debug(DEBUG_LEVEL_NORMAL, __FILE__": freeing fd info (fd=%i)\n", i->app_fd); dsp_drain(i); - + if (i->mainloop) pa_threaded_mainloop_stop(i->mainloop); - + if (i->play_stream) { pa_stream_disconnect(i->play_stream); pa_stream_unref(i->play_stream); @@ -338,7 +338,7 @@ static void fd_info_free(fd_info *i) { pa_context_disconnect(i->context); pa_context_unref(i->context); } - + if (i->mainloop) pa_threaded_mainloop_free(i->mainloop); @@ -360,7 +360,7 @@ static void fd_info_free(fd_info *i) { static fd_info *fd_info_ref(fd_info *i) { assert(i); - + pthread_mutex_lock(&i->mutex); assert(i->ref >= 1); i->ref++; @@ -404,7 +404,7 @@ static void context_state_cb(pa_context *c, void *userdata) { static void reset_params(fd_info *i) { assert(i); - + i->sample_spec.format = PA_SAMPLE_U8; i->sample_spec.channels = 1; i->sample_spec.rate = 8000; @@ -418,7 +418,7 @@ static const char *client_name(char *buf, size_t n) { if ((e = getenv("PADSP_CLIENT_NAME"))) return e; - + if (pa_get_binary_name(p, sizeof(p))) snprintf(buf, n, "OSS Emulation[%s]", p); else @@ -440,7 +440,7 @@ static void atfork_prepare(void) { fd_info *i; debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_prepare() enter\n"); - + function_enter(); pthread_mutex_lock(&fd_infos_mutex); @@ -452,13 +452,13 @@ static void atfork_prepare(void) { pthread_mutex_lock(&func_mutex); - + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_prepare() exit\n"); } static void atfork_parent(void) { fd_info *i; - + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_parent() enter\n"); pthread_mutex_unlock(&func_mutex); @@ -471,19 +471,19 @@ static void atfork_parent(void) { pthread_mutex_unlock(&fd_infos_mutex); function_exit(); - + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_parent() exit\n"); } static void atfork_child(void) { fd_info *i; - + debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_child() enter\n"); /* We do only the bare minimum to get all fds closed */ pthread_mutex_init(&func_mutex, NULL); pthread_mutex_init(&fd_infos_mutex, NULL); - + for (i = fd_infos; i; i = i->next) { pthread_mutex_init(&i->mutex, NULL); @@ -556,7 +556,7 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { signal(SIGPIPE, SIG_IGN); /* Yes, ugly as hell */ pthread_once(&install_atfork_once, install_atfork); - + if (!(i = malloc(sizeof(fd_info)))) { *_errno = ENOMEM; goto fail; @@ -638,12 +638,12 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { unlock_and_fail: pa_threaded_mainloop_unlock(i->mainloop); - + fail: if (i) fd_info_unref(i); - + return NULL; } @@ -671,7 +671,7 @@ static fd_info* fd_info_find(int fd) { fd_info *i; pthread_mutex_lock(&fd_infos_mutex); - + for (i = fd_infos; i; i = i->next) if (i->app_fd == fd && !i->unusable) { fd_info_ref(i); @@ -679,7 +679,7 @@ static fd_info* fd_info_find(int fd) { } pthread_mutex_unlock(&fd_infos_mutex); - + return i; } @@ -907,7 +907,7 @@ static void stream_state_cb(pa_stream *s, void * userdata) { case PA_STREAM_READY: debug(DEBUG_LEVEL_NORMAL, __FILE__": stream established.\n"); break; - + case PA_STREAM_FAILED: debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); fd_info_shutdown(i); @@ -923,7 +923,7 @@ static void stream_state_cb(pa_stream *s, void * userdata) { static int create_playback_stream(fd_info *i) { pa_buffer_attr attr; int n; - + assert(i); fix_metrics(i); @@ -942,7 +942,7 @@ static int create_playback_stream(fd_info *i) { attr.tlength = i->fragment_size * i->n_fragments; attr.prebuf = i->fragment_size; attr.minreq = i->fragment_size; - + if (pa_stream_connect_playback(i->play_stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; @@ -952,7 +952,7 @@ static int create_playback_stream(fd_info *i) { setsockopt(i->app_fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)); n = i->fragment_size; setsockopt(i->thread_fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)); - + return 0; fail: @@ -962,7 +962,7 @@ fail: static int create_record_stream(fd_info *i) { pa_buffer_attr attr; int n; - + assert(i); fix_metrics(i); @@ -979,7 +979,7 @@ static int create_record_stream(fd_info *i) { memset(&attr, 0, sizeof(attr)); attr.maxlength = i->fragment_size * (i->n_fragments+1); attr.fragsize = i->fragment_size; - + if (pa_stream_connect_record(i->rec_stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE) < 0) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; @@ -989,7 +989,7 @@ static int create_record_stream(fd_info *i) { setsockopt(i->app_fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)); n = i->fragment_size; setsockopt(i->thread_fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)); - + return 0; fail: @@ -1025,7 +1025,7 @@ static void io_event_cb(pa_mainloop_api *api, pa_io_event *e, int fd, pa_io_even fd_info *i = userdata; pa_threaded_mainloop_signal(i->mainloop, 0); - + if (flags & PA_IO_EVENT_INPUT) { if (!i->play_stream) { @@ -1035,7 +1035,7 @@ static void io_event_cb(pa_mainloop_api *api, pa_io_event *e, int fd, pa_io_even if (fd_info_copy_data(i, 0) < 0) goto fail; } - + } else if (flags & PA_IO_EVENT_OUTPUT) { if (!i->rec_stream) { @@ -1050,7 +1050,7 @@ static void io_event_cb(pa_mainloop_api *api, pa_io_event *e, int fd, pa_io_even goto fail; return; - + fail: /* We can't do anything better than removing the event source */ fd_info_shutdown(i); @@ -1100,7 +1100,7 @@ static int dsp_open(int flags, int *_errno) { if (!(i->io_event = api->io_new(api, i->thread_fd, i->io_flags, io_event_cb, i))) goto fail; - + pa_threaded_mainloop_unlock(i->mainloop); debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open() succeeded, fd=%i\n", i->app_fd); @@ -1108,7 +1108,7 @@ static int dsp_open(int flags, int *_errno) { fd_info_add_to_list(i); ret = i->app_fd; fd_info_unref(i); - + return ret; fail: @@ -1116,7 +1116,7 @@ fail: if (i) fd_info_unref(i); - + *_errno = EIO; debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open() failed\n"); @@ -1138,7 +1138,7 @@ static void sink_info_cb(pa_context *context, const pa_sink_info *si, int eol, v if (!pa_cvolume_equal(&i->sink_volume, &si->volume)) i->volume_modify_count++; - + i->sink_volume = si->volume; i->sink_index = si->index; @@ -1160,7 +1160,7 @@ static void source_info_cb(pa_context *context, const pa_source_info *si, int eo if (!pa_cvolume_equal(&i->source_volume, &si->volume)) i->volume_modify_count++; - + i->source_volume = si->volume; i->source_index = si->index; @@ -1193,13 +1193,13 @@ static int mixer_open(int flags, int *_errno) { debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open()\n"); - if (!(i = fd_info_new(FD_INFO_MIXER, _errno))) + if (!(i = fd_info_new(FD_INFO_MIXER, _errno))) return -1; - + pa_threaded_mainloop_lock(i->mainloop); pa_context_set_subscribe_callback(i->context, subscribe_cb, i); - + if (!(o = pa_context_subscribe(i->context, PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE, context_success_cb, i))) { debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context))); *_errno = EIO; @@ -1274,7 +1274,7 @@ static int mixer_open(int flags, int *_errno) { fd_info_add_to_list(i); ret = i->app_fd; fd_info_unref(i); - + return ret; fail: @@ -1285,7 +1285,7 @@ fail: if (i) fd_info_unref(i); - + *_errno = EIO; debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open() failed\n"); @@ -1323,7 +1323,7 @@ static int sndstat_open(int flags, int *_errno) { int e; debug(DEBUG_LEVEL_NORMAL, __FILE__": sndstat_open()\n"); - + if (flags != O_RDONLY #ifdef O_LARGEFILE && flags != (O_RDONLY|O_LARGEFILE) @@ -1401,16 +1401,16 @@ int open(const char *filename, int flags, ...) { } function_exit(); - + if (_errno) errno = _errno; - + return r; } static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) { int ret = -1; - + switch (request) { case SOUND_MIXER_READ_DEVMASK : debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_DEVMASK\n"); @@ -1423,7 +1423,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno *(int*) argp = SOUND_MASK_IGAIN; break; - + case SOUND_MIXER_READ_STEREODEVS: debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_STEREODEVS\n"); @@ -1434,7 +1434,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno if (i->source_volume.channels > 1) *(int*) argp |= SOUND_MASK_IGAIN; pa_threaded_mainloop_unlock(i->mainloop); - + break; case SOUND_MIXER_READ_RECSRC: @@ -1452,7 +1452,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno *(int*) argp = 0; break; - + case SOUND_MIXER_READ_PCM: case SOUND_MIXER_READ_IGAIN: { pa_cvolume *v; @@ -1515,23 +1515,23 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno i->operation_success = 0; while (pa_operation_get_state(o) != PA_OPERATION_DONE) { CONTEXT_CHECK_DEAD_GOTO(i, exit_loop); - + pa_threaded_mainloop_wait(i->mainloop); } exit_loop: - + if (!i->operation_success) debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to set volume: %s\n", pa_strerror(pa_context_errno(i->context))); pa_operation_unref(o); } - + /* We don't wait for completion here */ i->volume_modify_count++; } - + pa_threaded_mainloop_unlock(i->mainloop); - + break; } @@ -1548,7 +1548,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno pa_threaded_mainloop_unlock(i->mainloop); break; } - + default: debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request); @@ -1557,44 +1557,44 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno } ret = 0; - + fail: - + return ret; } static int map_format(int *fmt, pa_sample_spec *ss) { - + switch (*fmt) { case AFMT_MU_LAW: ss->format = PA_SAMPLE_ULAW; break; - + case AFMT_A_LAW: ss->format = PA_SAMPLE_ALAW; break; - + case AFMT_S8: *fmt = AFMT_U8; /* fall through */ case AFMT_U8: ss->format = PA_SAMPLE_U8; break; - + case AFMT_U16_BE: *fmt = AFMT_S16_BE; /* fall through */ case AFMT_S16_BE: ss->format = PA_SAMPLE_S16BE; break; - + case AFMT_U16_LE: *fmt = AFMT_S16_LE; /* fall through */ case AFMT_S16_LE: ss->format = PA_SAMPLE_S16LE; break; - + default: ss->format = PA_SAMPLE_S16NE; *fmt = AFMT_S16_NE; @@ -1666,14 +1666,14 @@ static int dsp_flush_socket(fd_info *i) { static int dsp_empty_socket(fd_info *i) { #ifdef SIOCINQ int ret = -1; - + /* Empty the socket */ for (;;) { int l; - + if (i->thread_fd < 0) break; - + if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) { debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ: %s\n", strerror(errno)); break; @@ -1683,7 +1683,7 @@ static int dsp_empty_socket(fd_info *i) { ret = 0; break; } - + pa_threaded_mainloop_wait(i->mainloop); } @@ -1700,19 +1700,19 @@ static int dsp_drain(fd_info *i) { if (!i->mainloop) return 0; - + debug(DEBUG_LEVEL_NORMAL, __FILE__": Draining.\n"); pa_threaded_mainloop_lock(i->mainloop); if (dsp_empty_socket(i) < 0) goto fail; - + if (!i->play_stream) goto fail; debug(DEBUG_LEVEL_NORMAL, __FILE__": Really draining.\n"); - + if (!(o = pa_stream_drain(i->play_stream, stream_success_cb, i))) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; @@ -1721,7 +1721,7 @@ static int dsp_drain(fd_info *i) { i->operation_success = 0; while (pa_operation_get_state(o) != PA_OPERATION_DONE) { PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, fail); - + pa_threaded_mainloop_wait(i->mainloop); } @@ -1731,9 +1731,9 @@ static int dsp_drain(fd_info *i) { } r = 0; - + fail: - + if (o) pa_operation_unref(o); @@ -1755,7 +1755,7 @@ static int dsp_trigger(fd_info *i) { goto fail; debug(DEBUG_LEVEL_NORMAL, __FILE__": Triggering.\n"); - + if (!(o = pa_stream_trigger(i->play_stream, stream_success_cb, i))) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; @@ -1764,7 +1764,7 @@ static int dsp_trigger(fd_info *i) { i->operation_success = 0; while (!pa_operation_get_state(o) != PA_OPERATION_DONE) { PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, fail); - + pa_threaded_mainloop_wait(i->mainloop); } @@ -1774,9 +1774,9 @@ static int dsp_trigger(fd_info *i) { } r = 0; - + fail: - + if (o) pa_operation_unref(o); @@ -1787,11 +1787,11 @@ fail: static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) { int ret = -1; - + switch (request) { case SNDCTL_DSP_SETFMT: { debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp); - + pa_threaded_mainloop_lock(i->mainloop); if (*(int*) argp == AFMT_QUERY) @@ -1804,12 +1804,12 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_threaded_mainloop_unlock(i->mainloop); break; } - + case SNDCTL_DSP_SPEED: { pa_sample_spec ss; int valid; char t[256]; - + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SPEED: %i\n", *(int*) argp); pa_threaded_mainloop_lock(i->mainloop); @@ -1821,7 +1821,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) i->sample_spec = ss; free_streams(i); } - + debug(DEBUG_LEVEL_NORMAL, __FILE__": ss: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec)); pa_threaded_mainloop_unlock(i->mainloop); @@ -1833,24 +1833,24 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) break; } - + case SNDCTL_DSP_STEREO: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_STEREO: %i\n", *(int*) argp); - + pa_threaded_mainloop_lock(i->mainloop); - + i->sample_spec.channels = *(int*) argp ? 2 : 1; free_streams(i); - + pa_threaded_mainloop_unlock(i->mainloop); return 0; case SNDCTL_DSP_CHANNELS: { pa_sample_spec ss; int valid; - + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CHANNELS: %i\n", *(int*) argp); - + pa_threaded_mainloop_lock(i->mainloop); ss = i->sample_spec; @@ -1860,7 +1860,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) i->sample_spec = ss; free_streams(i); } - + pa_threaded_mainloop_unlock(i->mainloop); if (!valid) { @@ -1878,16 +1878,16 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) fix_metrics(i); *(int*) argp = i->fragment_size; - + pa_threaded_mainloop_unlock(i->mainloop); - + break; case SNDCTL_DSP_SETFRAGMENT: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFRAGMENT: 0x%08x\n", *(int*) argp); - + pa_threaded_mainloop_lock(i->mainloop); - + i->fragment_size = 1 << ((*(int*) argp) & 31); i->n_fragments = (*(int*) argp) >> 16; @@ -1896,14 +1896,14 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) i->n_fragments = 12; free_streams(i); - + pa_threaded_mainloop_unlock(i->mainloop); - + break; - + case SNDCTL_DSP_GETCAPS: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CAPS\n"); - + *(int*) argp = DSP_CAP_DUPLEX #ifdef DSP_CAP_MULTI | DSP_CAP_MULTI @@ -1913,13 +1913,13 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_GETODELAY: { int l; - + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETODELAY\n"); - + pa_threaded_mainloop_lock(i->mainloop); *(int*) argp = 0; - + for (;;) { pa_usec_t usec; @@ -1937,10 +1937,10 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_threaded_mainloop_wait(i->mainloop); } - + exit_loop: -#ifdef SIOCINQ +#ifdef SIOCINQ if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno)); else @@ -1955,39 +1955,39 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) break; } - + case SNDCTL_DSP_RESET: { debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_RESET\n"); - + pa_threaded_mainloop_lock(i->mainloop); free_streams(i); dsp_flush_socket(i); i->optr_n_blocks = 0; - + pa_threaded_mainloop_unlock(i->mainloop); break; } - + case SNDCTL_DSP_GETFMTS: { debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETFMTS\n"); - + *(int*) argp = AFMT_MU_LAW|AFMT_A_LAW|AFMT_U8|AFMT_S16_LE|AFMT_S16_BE; break; } case SNDCTL_DSP_POST: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_POST\n"); - - if (dsp_trigger(i) < 0) + + if (dsp_trigger(i) < 0) *_errno = EIO; break; - case SNDCTL_DSP_SYNC: + case SNDCTL_DSP_SYNC: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SYNC\n"); - - if (dsp_drain(i) < 0) + + if (dsp_drain(i) < 0) *_errno = EIO; break; @@ -2055,36 +2055,36 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SOUND_PCM_READ_RATE: debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_PCM_READ_RATE\n"); - + pa_threaded_mainloop_lock(i->mainloop); *(int*) argp = i->sample_spec.rate; pa_threaded_mainloop_unlock(i->mainloop); - break; + break; case SOUND_PCM_READ_CHANNELS: debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_PCM_READ_CHANNELS\n"); - + pa_threaded_mainloop_lock(i->mainloop); *(int*) argp = i->sample_spec.channels; pa_threaded_mainloop_unlock(i->mainloop); - break; + break; case SOUND_PCM_READ_BITS: debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_PCM_READ_BITS\n"); - + pa_threaded_mainloop_lock(i->mainloop); *(int*) argp = pa_sample_size(&i->sample_spec)*8; pa_threaded_mainloop_unlock(i->mainloop); - break; - + break; + case SNDCTL_DSP_GETOPTR: { count_info *info; - + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETOPTR\n"); info = (count_info*) argp; memset(info, 0, sizeof(*info)); - + pa_threaded_mainloop_lock(i->mainloop); for (;;) { @@ -2095,7 +2095,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) if (pa_stream_get_time(i->play_stream, &usec) >= 0) { size_t k = pa_usec_to_bytes(usec, &i->sample_spec); int m; - + info->bytes = (int) k; m = k / i->fragment_size; info->blocks = m - i->optr_n_blocks; @@ -2111,7 +2111,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) pa_threaded_mainloop_wait(i->mainloop); } - + pa_threaded_mainloop_unlock(i->mainloop); debug(DEBUG_LEVEL_NORMAL, __FILE__": GETOPTR bytes=%i, blocks=%i, ptr=%i\n", info->bytes, info->blocks, info->ptr); @@ -2122,7 +2122,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_GETIPTR: debug(DEBUG_LEVEL_NORMAL, __FILE__": invalid ioctl SNDCTL_DSP_GETIPTR\n"); goto inval; - + default: debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request); @@ -2132,9 +2132,9 @@ inval: } ret = 0; - + fail: - + return ret; } @@ -2165,14 +2165,14 @@ int ioctl(int fd, unsigned long request, ...) { r = mixer_ioctl(i, request, argp, &_errno); else r = dsp_ioctl(i, request, argp, &_errno); - + fd_info_unref(i); if (_errno) errno = _errno; function_exit(); - + return r; } @@ -2194,7 +2194,7 @@ int close(int fd) { fd_info_remove_from_list(i); fd_info_unref(i); - + function_exit(); return 0; @@ -2207,7 +2207,7 @@ int access(const char *pathname, int mode) { errno = EFAULT; return -1; } - + debug(DEBUG_LEVEL_VERBOSE, __FILE__": access(%s)\n", pathname); if (strcmp(pathname, "/dev/dsp") != 0 && @@ -2236,7 +2236,7 @@ int open64(const char *filename, int flags, ...) { mode_t mode = 0; debug(DEBUG_LEVEL_VERBOSE, __FILE__": open64(%s)\n", filename); - + va_start(args, flags); if (flags & O_CREAT) mode = va_arg(args, mode_t); @@ -2259,7 +2259,7 @@ FILE* fopen(const char *filename, const char *mode) { FILE *f = NULL; int fd; mode_t m; - + debug(DEBUG_LEVEL_VERBOSE, __FILE__": fopen(%s)\n", filename); if (strcmp(filename, "/dev/dsp") != 0 && @@ -2293,7 +2293,7 @@ FILE* fopen(const char *filename, const char *mode) { close(fd); return NULL; } - + return f; } @@ -2337,9 +2337,9 @@ int fclose(FILE *f) { /* Dirty trick to avoid that the fd is not freed twice, once by us * and once by the real fclose() */ i->app_fd = -1; - + fd_info_unref(i); - + function_exit(); LOAD_FCLOSE_FUNC(); diff --git a/src/utils/paplay.c b/src/utils/paplay.c index 0386c9df..1617b27d 100644 --- a/src/utils/paplay.c +++ b/src/utils/paplay.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -77,14 +77,14 @@ static void stream_drain_complete(pa_stream*s, int success, void *userdata) { fprintf(stderr, "Failed to drain stream: %s\n", pa_strerror(pa_context_errno(context))); quit(1); } - - if (verbose) + + if (verbose) fprintf(stderr, "Playback stream drained.\n"); pa_stream_disconnect(stream); pa_stream_unref(stream); stream = NULL; - + if (!(o = pa_context_drain(context, context_drain_complete, NULL))) pa_context_disconnect(context); else { @@ -111,7 +111,7 @@ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { if ((bytes = readf_function(sndfile, data, length/k)) > 0) bytes *= k; - + } else bytes = sf_read_raw(sndfile, data, length); @@ -140,7 +140,7 @@ static void stream_state_callback(pa_stream *s, void *userdata) { if (verbose) fprintf(stderr, "Stream successfully created\n"); break; - + case PA_STREAM_FAILED: default: fprintf(stderr, "Stream errror: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); @@ -157,10 +157,10 @@ static void context_state_callback(pa_context *c, void *userdata) { case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_SETTING_NAME: break; - + case PA_CONTEXT_READY: { pa_cvolume cv; - + assert(c && !stream); if (verbose) @@ -172,10 +172,10 @@ static void context_state_callback(pa_context *c, void *userdata) { pa_stream_set_state_callback(stream, stream_state_callback, NULL); pa_stream_set_write_callback(stream, stream_write_callback, NULL); pa_stream_connect_playback(stream, device, NULL, 0, pa_cvolume_set(&cv, sample_spec.channels, volume), NULL); - + break; } - + case PA_CONTEXT_TERMINATED: quit(0); break; @@ -192,7 +192,7 @@ static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, if (verbose) fprintf(stderr, "Got SIGINT, exiting.\n"); quit(0); - + } static void help(const char *argv0) { @@ -251,7 +251,7 @@ int main(int argc, char *argv[]) { help(bn); ret = 0; goto quit; - + case ARG_VERSION: printf("paplay "PACKAGE_VERSION"\nCompiled with libpulse %s\nLinked with libpulse %s\n", pa_get_headers_version(), pa_get_library_version()); ret = 0; @@ -302,7 +302,7 @@ int main(int argc, char *argv[]) { } filename = optind < argc ? argv[optind] : "STDIN"; - + memset(&sfinfo, 0, sizeof(sfinfo)); if (optind < argc) @@ -317,9 +317,9 @@ int main(int argc, char *argv[]) { sample_spec.rate = sfinfo.samplerate; sample_spec.channels = sfinfo.channels; - + readf_function = NULL; - + switch (sfinfo.format & 0xFF) { case SF_FORMAT_PCM_16: case SF_FORMAT_PCM_U8: @@ -327,11 +327,11 @@ int main(int argc, char *argv[]) { sample_spec.format = PA_SAMPLE_S16NE; readf_function = (sf_count_t (*)(SNDFILE *_sndfile, void *ptr, sf_count_t frames)) sf_readf_short; break; - + case SF_FORMAT_ULAW: sample_spec.format = PA_SAMPLE_ULAW; break; - + case SF_FORMAT_ALAW: sample_spec.format = PA_SAMPLE_ALAW; break; @@ -369,13 +369,13 @@ int main(int argc, char *argv[]) { if (!stream_name) stream_name = pa_utf8_filter(n); } - + if (verbose) { char t[PA_SAMPLE_SPEC_SNPRINT_MAX]; pa_sample_spec_snprint(t, sizeof(t), &sample_spec); fprintf(stderr, "Using sample spec '%s'\n", t); } - + /* Set up a new main loop */ if (!(m = pa_mainloop_new())) { fprintf(stderr, "pa_mainloop_new() failed.\n"); @@ -390,7 +390,7 @@ int main(int argc, char *argv[]) { #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif - + /* Create a new connection context */ if (!(context = pa_context_new(mainloop_api, client_name))) { fprintf(stderr, "pa_context_new() failed.\n"); @@ -407,7 +407,7 @@ int main(int argc, char *argv[]) { fprintf(stderr, "pa_mainloop_run() failed.\n"); goto quit; } - + quit: if (stream) pa_stream_unref(stream); @@ -427,6 +427,6 @@ quit: if (sndfile) sf_close(sndfile); - + return ret; } diff --git a/src/utils/pax11publish.c b/src/utils/pax11publish.c index 6a3c6dbc..00332f65 100644 --- a/src/utils/pax11publish.c +++ b/src/utils/pax11publish.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -99,7 +99,7 @@ int main(int argc, char *argv[]) { switch (mode) { case DUMP: { char t[1024]; - if (pa_x11_get_prop(d, "PULSE_SERVER", t, sizeof(t))) + if (pa_x11_get_prop(d, "PULSE_SERVER", t, sizeof(t))) printf("Server: %s\n", t); if (pa_x11_get_prop(d, "PULSE_SOURCE", t, sizeof(t))) printf("Source: %s\n", t); @@ -110,10 +110,10 @@ int main(int argc, char *argv[]) { break; } - + case IMPORT: { char t[1024]; - if (pa_x11_get_prop(d, "PULSE_SERVER", t, sizeof(t))) + if (pa_x11_get_prop(d, "PULSE_SERVER", t, sizeof(t))) printf("PULSE_SERVER='%s'\nexport PULSE_SERVER\n", t); if (pa_x11_get_prop(d, "PULSE_SOURCE", t, sizeof(t))) printf("PULSE_SOURCE='%s'\nexport PULSE_SOURCE\n", t); @@ -158,7 +158,7 @@ int main(int argc, char *argv[]) { pa_x11_del_prop(d, "PULSE_SOURCE"); pa_x11_del_prop(d, "PULSE_ID"); pa_x11_del_prop(d, "PULSE_COOKIE"); - + if (server) pa_x11_set_prop(d, "PULSE_SERVER", server); else if (conf->default_server) @@ -169,7 +169,7 @@ int main(int argc, char *argv[]) { fprintf(stderr, "Failed to get FQDN.\n"); goto finish; } - + pa_x11_set_prop(d, "PULSE_SERVER", hn); } @@ -184,7 +184,7 @@ int main(int argc, char *argv[]) { pa_x11_set_prop(d, "PULSE_SOURCE", conf->default_source); pa_client_conf_free(conf); - + if (pa_authkey_load_auto(cookie_file, cookie, sizeof(cookie)) < 0) { fprintf(stderr, "Failed to load cookie data\n"); goto finish; @@ -201,20 +201,20 @@ int main(int argc, char *argv[]) { pa_x11_del_prop(d, "PULSE_ID"); pa_x11_del_prop(d, "PULSE_COOKIE"); break; - + default: fprintf(stderr, "No yet implemented.\n"); goto finish; } ret = 0; - + finish: if (d) { XSync(d, False); XCloseDisplay(d); } - + return ret; } -- cgit From 19bd9148c5d16a8363065ca128e06037780337ab Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 4 Jan 2007 14:06:24 +0000 Subject: Fix error messages for failure connecting streams. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1419 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 679a5d01..c6025417 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -909,7 +909,15 @@ static void stream_state_cb(pa_stream *s, void * userdata) { break; case PA_STREAM_FAILED: - debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + if (s == i->play_stream) { + debug(DEBUG_LEVEL_NORMAL, + __FILE__": pa_stream_connect_playback() failed: %s\n", + pa_strerror(pa_context_errno(i->context))); + } else if (s == i->rec_stream) { + debug(DEBUG_LEVEL_NORMAL, + __FILE__": pa_stream_connect_record() failed: %s\n", + pa_strerror(pa_context_errno(i->context))); + } fd_info_shutdown(i); break; @@ -981,7 +989,7 @@ static int create_record_stream(fd_info *i) { attr.fragsize = i->fragment_size; if (pa_stream_connect_record(i->rec_stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE) < 0) { - debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_record() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } -- cgit From c992ed9c47854338106b38a1d093c4c1bf65e96d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 4 Jan 2007 14:17:57 +0000 Subject: Free stream objects when they've been invalidated. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1420 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index c6025417..aa0ec9dd 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -913,10 +913,14 @@ static void stream_state_cb(pa_stream *s, void * userdata) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + pa_stream_unref(i->play_stream); + i->play_stream = NULL; } else if (s == i->rec_stream) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_record() failed: %s\n", pa_strerror(pa_context_errno(i->context))); + pa_stream_unref(i->rec_stream); + i->rec_stream = NULL; } fd_info_shutdown(i); break; -- cgit From 4c0a481f79715c0e783000c75e800d2401c11019 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 4 Jan 2007 14:20:53 +0000 Subject: Report IO error on ioctl() when we're in a fatal error state. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1421 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index aa0ec9dd..b4c5bb0b 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1800,6 +1800,16 @@ fail: static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) { int ret = -1; + if (i->thread_fd == -1) { + /* + * We've encountered some fatal error and are just waiting + * for a close. + */ + debug(DEBUG_LEVEL_NORMAL, __FILE__": got ioctl 0x%08lx in fatal error state\n", request); + *_errno = EIO; + return -1; + } + switch (request) { case SNDCTL_DSP_SETFMT: { debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp); -- cgit From 4171f2504a4e0de5c46c3237da009f5355cf57ec Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 19 Jan 2007 08:00:31 +0000 Subject: Make sure we report success for SNDCTL_DSP_SETDUPLEX. (Patch by ZlatkO) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1422 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index b4c5bb0b..2b314a9c 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -2145,6 +2145,11 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) debug(DEBUG_LEVEL_NORMAL, __FILE__": invalid ioctl SNDCTL_DSP_GETIPTR\n"); goto inval; + case SNDCTL_DSP_SETDUPLEX: + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETDUPLEX\n"); + /* this is a no-op */ + break; + default: debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request); -- cgit From f65ab1b3eb2cd91f0bb98f18517e48156177e679 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 5 Feb 2007 10:26:14 +0000 Subject: Don't abort config loading when the user specific cannot be loaded. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1423 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/core-util.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index b42dc0ca..1e8fd23b 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -184,7 +184,7 @@ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) { goto fail; } #else - pa_log_warn("secure directory creation not supported on Win32."); + pa_log_warn("secure directory creation not supported on Win32."); #endif return 0; @@ -953,13 +953,19 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env fn = buf; #endif - if ((f = fopen(fn, mode)) || errno != ENOENT) { + f = fopen(fn, mode); + if (f != NULL) { if (result) *result = pa_xstrdup(fn); pa_xfree(lfn); return f; } + if (errno != ENOENT) { + pa_log_warn("WARNING: failed to open configuration file '%s': %s", + lfn, pa_cstrerror(errno)); + } + pa_xfree(lfn); } } -- cgit From de7a883245937a8db63991d5fa568bf35bef5bb1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 12 Feb 2007 09:37:34 +0000 Subject: Allow specification of device number. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1424 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-waveout.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index e245e138..79de077d 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -47,7 +47,8 @@ PA_MODULE_DESCRIPTION("Windows waveOut Sink/Source") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE( "sink_name= " - "source_name=" + "source_name= " + "device= " "record= " "playback= " "format= " @@ -90,6 +91,7 @@ struct userdata { static const char* const valid_modargs[] = { "sink_name", "source_name", + "device", "record", "playback", "fragments", @@ -432,6 +434,7 @@ int pa__init(pa_core *c, pa_module*m) { WAVEFORMATEX wf; int nfrags, frag_size; int record = 1, playback = 1; + unsigned int device; pa_sample_spec ss; pa_channel_map map; pa_modargs *ma = NULL; @@ -455,6 +458,12 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } + device = WAVE_MAPPER; + if (pa_modargs_get_value_u32(ma, "device", &device) < 0) { + pa_log("failed to parse device argument"); + goto fail; + } + nfrags = 5; frag_size = 8192; if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { @@ -474,7 +483,7 @@ int pa__init(pa_core *c, pa_module*m) { u = pa_xmalloc(sizeof(struct userdata)); if (record) { - if (waveInOpen(&hwi, WAVE_MAPPER, &wf, (DWORD_PTR)chunk_ready_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { + if (waveInOpen(&hwi, device, &wf, (DWORD_PTR)chunk_ready_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { pa_log("failed to open waveIn"); goto fail; } @@ -486,7 +495,7 @@ int pa__init(pa_core *c, pa_module*m) { } if (playback) { - if (waveOutOpen(&hwo, WAVE_MAPPER, &wf, (DWORD_PTR)chunk_done_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { + if (waveOutOpen(&hwo, device, &wf, (DWORD_PTR)chunk_done_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { pa_log("failed to open waveOut"); goto fail; } -- cgit From 1d0e8e4f14e6d8589732a8e347ec7cd5dfdfb66b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 12 Feb 2007 09:39:12 +0000 Subject: Make sure we get proper host identifiers. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1425 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure.ac b/configure.ac index 2f09279c..e35502ca 100644 --- a/configure.ac +++ b/configure.ac @@ -42,6 +42,8 @@ AC_SUBST(LIBPULSE_SIMPLE_VERSION_INFO, [0:0:0]) AC_SUBST(LIBPULSE_BROWSE_VERSION_INFO, [1:0:1]) AC_SUBST(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO, [0:2:0]) +AC_CANONICAL_HOST + if type -p stow > /dev/null && test -d /usr/local/stow ; then AC_MSG_NOTICE([*** Found /usr/local/stow: default install prefix set to /usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION} ***]) ac_default_prefix="/usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION}" -- cgit From 06211b7c8fd329137ae9003818543912a87d9898 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 13 Feb 2007 15:35:19 +0000 Subject: Add copyright notices to all relevant files. (based on svn log) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1426 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 3 +++ src/Makefile.am | 4 ++++ src/daemon/caps.c | 3 +++ src/daemon/caps.h | 2 ++ src/daemon/cmdline.c | 2 ++ src/daemon/cmdline.h | 2 ++ src/daemon/cpulimit.c | 2 ++ src/daemon/cpulimit.h | 2 ++ src/daemon/daemon-conf.c | 3 +++ src/daemon/daemon-conf.h | 3 +++ src/daemon/dumpmodules.c | 3 +++ src/daemon/dumpmodules.h | 2 ++ src/daemon/main.c | 3 +++ src/modules/alsa-util.c | 3 +++ src/modules/alsa-util.h | 3 +++ src/modules/dbus-util.c | 3 +++ src/modules/dbus-util.h | 2 ++ src/modules/gconf/gconf-helper.c | 2 ++ src/modules/gconf/module-gconf.c | 2 ++ src/modules/module-alsa-sink.c | 3 +++ src/modules/module-alsa-source.c | 3 +++ src/modules/module-cli.c | 2 ++ src/modules/module-combine.c | 2 ++ src/modules/module-detect.c | 4 ++++ src/modules/module-esound-compat-spawnfd.c | 2 ++ src/modules/module-esound-compat-spawnpid.c | 2 ++ src/modules/module-esound-sink.c | 2 ++ src/modules/module-hal-detect.c | 3 +++ src/modules/module-jack-sink.c | 2 ++ src/modules/module-jack-source.c | 2 ++ src/modules/module-lirc.c | 2 ++ src/modules/module-match.c | 2 ++ src/modules/module-mmkbd-evdev.c | 2 ++ src/modules/module-native-protocol-fd.c | 2 ++ src/modules/module-null-sink.c | 2 ++ src/modules/module-oss-mmap.c | 3 +++ src/modules/module-oss.c | 3 +++ src/modules/module-pipe-sink.c | 2 ++ src/modules/module-pipe-source.c | 2 ++ src/modules/module-protocol-stub.c | 3 +++ src/modules/module-rescue-streams.c | 2 ++ src/modules/module-sine.c | 2 ++ src/modules/module-solaris.c | 3 +++ src/modules/module-tunnel.c | 3 +++ src/modules/module-volume-restore.c | 2 ++ src/modules/module-waveout.c | 3 +++ src/modules/module-x11-bell.c | 2 ++ src/modules/module-x11-publish.c | 2 ++ src/modules/module-zeroconf-publish.c | 2 ++ src/modules/oss-util.c | 3 +++ src/modules/oss-util.h | 3 +++ src/modules/rtp/module-rtp-recv.c | 2 ++ src/modules/rtp/module-rtp-send.c | 2 ++ src/modules/rtp/rtp.c | 2 ++ src/modules/rtp/rtp.h | 2 ++ src/modules/rtp/sap.c | 2 ++ src/modules/rtp/sap.h | 2 ++ src/modules/rtp/sdp.c | 2 ++ src/modules/rtp/sdp.h | 2 ++ src/pulse/browser.c | 2 ++ src/pulse/browser.h | 2 ++ src/pulse/cdecl.h | 2 ++ src/pulse/channelmap.c | 3 +++ src/pulse/channelmap.h | 3 +++ src/pulse/client-conf-x11.c | 2 ++ src/pulse/client-conf-x11.h | 2 ++ src/pulse/client-conf.c | 3 +++ src/pulse/client-conf.h | 2 ++ src/pulse/context.c | 3 +++ src/pulse/context.h | 3 +++ src/pulse/def.h | 3 +++ src/pulse/error.c | 3 +++ src/pulse/error.h | 3 +++ src/pulse/glib-mainloop.c | 2 ++ src/pulse/glib-mainloop.h | 3 +++ src/pulse/internal.h | 3 +++ src/pulse/introspect.c | 3 +++ src/pulse/introspect.h | 3 +++ src/pulse/mainloop-api.c | 2 ++ src/pulse/mainloop-api.h | 3 +++ src/pulse/mainloop-signal.c | 3 +++ src/pulse/mainloop-signal.h | 3 +++ src/pulse/mainloop.c | 3 +++ src/pulse/mainloop.h | 3 +++ src/pulse/operation.c | 2 ++ src/pulse/operation.h | 2 ++ src/pulse/pulseaudio.h | 3 +++ src/pulse/sample.c | 3 +++ src/pulse/sample.h | 3 +++ src/pulse/scache.c | 2 ++ src/pulse/scache.h | 3 +++ src/pulse/simple.c | 2 ++ src/pulse/simple.h | 3 +++ src/pulse/stream.c | 3 +++ src/pulse/stream.h | 3 +++ src/pulse/subscribe.c | 2 ++ src/pulse/subscribe.h | 3 +++ src/pulse/thread-mainloop.c | 3 +++ src/pulse/thread-mainloop.h | 3 +++ src/pulse/timeval.c | 3 +++ src/pulse/timeval.h | 3 +++ src/pulse/utf8.c | 22 ++++++++++++++++++++++ src/pulse/utf8.h | 3 +++ src/pulse/util.c | 3 +++ src/pulse/util.h | 3 +++ src/pulse/version.h.in | 3 +++ src/pulse/volume.c | 2 ++ src/pulse/volume.h | 3 +++ src/pulse/xmalloc.c | 2 ++ src/pulse/xmalloc.h | 2 ++ src/pulsecore/anotify.c | 2 ++ src/pulsecore/anotify.h | 2 ++ src/pulsecore/atomic.h | 2 ++ src/pulsecore/authkey-prop.c | 2 ++ src/pulsecore/authkey-prop.h | 2 ++ src/pulsecore/authkey.c | 3 +++ src/pulsecore/authkey.h | 2 ++ src/pulsecore/autoload.c | 3 +++ src/pulsecore/autoload.h | 2 ++ src/pulsecore/avahi-wrap.c | 2 ++ src/pulsecore/avahi-wrap.h | 2 ++ src/pulsecore/cli-command.c | 3 +++ src/pulsecore/cli-command.h | 2 ++ src/pulsecore/cli-text.c | 2 ++ src/pulsecore/cli-text.h | 2 ++ src/pulsecore/cli.c | 2 ++ src/pulsecore/cli.h | 2 ++ src/pulsecore/client.c | 3 +++ src/pulsecore/client.h | 2 ++ src/pulsecore/conf-parser.c | 2 ++ src/pulsecore/conf-parser.h | 2 ++ src/pulsecore/core-def.h | 2 ++ src/pulsecore/core-error.c | 3 +++ src/pulsecore/core-error.h | 3 +++ src/pulsecore/core-scache.c | 3 +++ src/pulsecore/core-scache.h | 3 +++ src/pulsecore/core-subscribe.c | 2 ++ src/pulsecore/core-subscribe.h | 2 ++ src/pulsecore/core-util.c | 4 ++++ src/pulsecore/core-util.h | 3 +++ src/pulsecore/core.c | 3 +++ src/pulsecore/core.h | 2 ++ src/pulsecore/creds.h | 2 ++ src/pulsecore/dllmain.c | 2 ++ src/pulsecore/dynarray.c | 2 ++ src/pulsecore/dynarray.h | 2 ++ src/pulsecore/endianmacros.h | 3 +++ src/pulsecore/esound.h | 2 ++ src/pulsecore/flist.c | 2 ++ src/pulsecore/flist.h | 2 ++ src/pulsecore/gccmacro.h | 2 ++ src/pulsecore/hashmap.c | 2 ++ src/pulsecore/hashmap.h | 2 ++ src/pulsecore/hook-list.c | 2 ++ src/pulsecore/hook-list.h | 2 ++ src/pulsecore/idxset.c | 3 +++ src/pulsecore/idxset.h | 3 +++ src/pulsecore/inet_ntop.c | 2 ++ src/pulsecore/inet_pton.c | 2 ++ src/pulsecore/iochannel.c | 3 +++ src/pulsecore/iochannel.h | 3 +++ src/pulsecore/ioline.c | 2 ++ src/pulsecore/ioline.h | 2 ++ src/pulsecore/ipacl.c | 3 +++ src/pulsecore/ipacl.h | 3 +++ src/pulsecore/llist.h | 2 ++ src/pulsecore/log.c | 3 +++ src/pulsecore/log.h | 3 +++ src/pulsecore/mcalign.c | 2 ++ src/pulsecore/mcalign.h | 2 ++ src/pulsecore/memblock.c | 3 +++ src/pulsecore/memblock.h | 3 +++ src/pulsecore/memblockq.c | 2 ++ src/pulsecore/memblockq.h | 2 ++ src/pulsecore/memchunk.c | 2 ++ src/pulsecore/memchunk.h | 2 ++ src/pulsecore/modargs.c | 2 ++ src/pulsecore/modargs.h | 2 ++ src/pulsecore/modinfo.c | 2 ++ src/pulsecore/modinfo.h | 2 ++ src/pulsecore/module.c | 3 +++ src/pulsecore/module.h | 2 ++ src/pulsecore/mutex-posix.c | 2 ++ src/pulsecore/mutex-win32.c | 2 ++ src/pulsecore/mutex.h | 2 ++ src/pulsecore/namereg.c | 2 ++ src/pulsecore/namereg.h | 2 ++ src/pulsecore/native-common.h | 3 +++ src/pulsecore/once-posix.c | 2 ++ src/pulsecore/once-win32.c | 2 ++ src/pulsecore/once.h | 2 ++ src/pulsecore/packet.c | 2 ++ src/pulsecore/packet.h | 2 ++ src/pulsecore/parseaddr.c | 2 ++ src/pulsecore/parseaddr.h | 2 ++ src/pulsecore/pdispatch.c | 3 +++ src/pulsecore/pdispatch.h | 3 +++ src/pulsecore/pid.c | 3 +++ src/pulsecore/pid.h | 2 ++ src/pulsecore/pipe.c | 2 ++ src/pulsecore/pipe.h | 2 ++ src/pulsecore/play-memblockq.c | 2 ++ src/pulsecore/play-memblockq.h | 2 ++ src/pulsecore/play-memchunk.c | 2 ++ src/pulsecore/play-memchunk.h | 2 ++ src/pulsecore/poll.c | 13 +++++++------ src/pulsecore/poll.h | 15 +++++++-------- src/pulsecore/props.c | 2 ++ src/pulsecore/props.h | 2 ++ src/pulsecore/protocol-cli.c | 2 ++ src/pulsecore/protocol-cli.h | 2 ++ src/pulsecore/protocol-esound.c | 3 +++ src/pulsecore/protocol-esound.h | 3 +++ src/pulsecore/protocol-http.c | 2 ++ src/pulsecore/protocol-http.h | 2 ++ src/pulsecore/protocol-native.c | 3 +++ src/pulsecore/protocol-native.h | 3 +++ src/pulsecore/protocol-simple.c | 2 ++ src/pulsecore/protocol-simple.h | 2 ++ src/pulsecore/pstream-util.c | 2 ++ src/pulsecore/pstream-util.h | 2 ++ src/pulsecore/pstream.c | 3 +++ src/pulsecore/pstream.h | 3 +++ src/pulsecore/queue.c | 2 ++ src/pulsecore/queue.h | 2 ++ src/pulsecore/random.c | 3 +++ src/pulsecore/random.h | 3 +++ src/pulsecore/refcnt.h | 2 ++ src/pulsecore/resampler.c | 2 ++ src/pulsecore/resampler.h | 2 ++ src/pulsecore/sample-util.c | 3 +++ src/pulsecore/sample-util.h | 3 +++ src/pulsecore/sconv-s16be.c | 2 ++ src/pulsecore/sconv-s16be.h | 2 ++ src/pulsecore/sconv-s16le.c | 2 ++ src/pulsecore/sconv-s16le.h | 2 ++ src/pulsecore/sconv.c | 3 +++ src/pulsecore/sconv.h | 3 +++ src/pulsecore/shm.c | 3 +++ src/pulsecore/shm.h | 2 ++ src/pulsecore/sink-input.c | 3 +++ src/pulsecore/sink-input.h | 3 +++ src/pulsecore/sink.c | 3 +++ src/pulsecore/sink.h | 3 +++ src/pulsecore/sioman.c | 2 ++ src/pulsecore/sioman.h | 2 ++ src/pulsecore/socket-client.c | 3 +++ src/pulsecore/socket-client.h | 3 +++ src/pulsecore/socket-server.c | 3 +++ src/pulsecore/socket-server.h | 3 +++ src/pulsecore/socket-util.c | 4 ++++ src/pulsecore/socket-util.h | 3 +++ src/pulsecore/sound-file-stream.c | 2 ++ src/pulsecore/sound-file-stream.h | 2 ++ src/pulsecore/sound-file.c | 2 ++ src/pulsecore/sound-file.h | 2 ++ src/pulsecore/source-output.c | 2 ++ src/pulsecore/source-output.h | 2 ++ src/pulsecore/source.c | 3 +++ src/pulsecore/source.h | 3 +++ src/pulsecore/strbuf.c | 2 ++ src/pulsecore/strbuf.h | 2 ++ src/pulsecore/strlist.c | 2 ++ src/pulsecore/strlist.h | 2 ++ src/pulsecore/tagstruct.c | 2 ++ src/pulsecore/tagstruct.h | 2 ++ src/pulsecore/thread-posix.c | 3 +++ src/pulsecore/thread-win32.c | 2 ++ src/pulsecore/thread.h | 3 +++ src/pulsecore/tokenizer.c | 2 ++ src/pulsecore/tokenizer.h | 2 ++ src/pulsecore/x11prop.c | 2 ++ src/pulsecore/x11prop.h | 2 ++ src/pulsecore/x11wrap.c | 2 ++ src/pulsecore/x11wrap.h | 2 ++ src/utils/pabrowse.c | 2 ++ src/utils/pacat.c | 3 +++ src/utils/pacmd.c | 2 ++ src/utils/pactl.c | 2 ++ src/utils/padsp | 3 +++ src/utils/padsp.c | 3 +++ src/utils/paplay.c | 3 +++ src/utils/pax11publish.c | 2 ++ 283 files changed, 714 insertions(+), 14 deletions(-) diff --git a/configure.ac b/configure.ac index e35502ca..65a99a00 100644 --- a/configure.ac +++ b/configure.ac @@ -5,6 +5,9 @@ # This file is part of PulseAudio. # +# Copyright 2004-2006 Lennart Poettering +# Copyright 2006-2007 Pierre Ossman for Cendio AB +# # PulseAudio is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or diff --git a/src/Makefile.am b/src/Makefile.am index 2f3bd8ab..0b509ac9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,6 +2,10 @@ # # This file is part of PulseAudio. # +# Copyright 2004-2006 Lennart Poettering +# Copyright 2006 Pierre Ossman for Cendio AB +# Copyright 2006 Diego Pettenò +# # PulseAudio is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or diff --git a/src/daemon/caps.c b/src/daemon/caps.c index db4bd919..2ea51c9f 100644 --- a/src/daemon/caps.c +++ b/src/daemon/caps.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/daemon/caps.h b/src/daemon/caps.h index 34da1af6..4cd09578 100644 --- a/src/daemon/caps.h +++ b/src/daemon/caps.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c index c3cb9209..dc757c9c 100644 --- a/src/daemon/cmdline.c +++ b/src/daemon/cmdline.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/daemon/cmdline.h b/src/daemon/cmdline.h index fdfbc0b6..18418894 100644 --- a/src/daemon/cmdline.h +++ b/src/daemon/cmdline.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/daemon/cpulimit.c b/src/daemon/cpulimit.c index 808cb4d4..d4ac1d86 100644 --- a/src/daemon/cpulimit.c +++ b/src/daemon/cpulimit.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/daemon/cpulimit.h b/src/daemon/cpulimit.h index bb11f794..271109b4 100644 --- a/src/daemon/cpulimit.h +++ b/src/daemon/cpulimit.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 319cf0c7..8cab327f 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h index b7fcf23b..4843a610 100644 --- a/src/daemon/daemon-conf.h +++ b/src/daemon/daemon-conf.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/daemon/dumpmodules.c b/src/daemon/dumpmodules.c index 8509924a..6743622a 100644 --- a/src/daemon/dumpmodules.c +++ b/src/daemon/dumpmodules.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/daemon/dumpmodules.h b/src/daemon/dumpmodules.h index 05cd86e0..ab2ddb64 100644 --- a/src/daemon/dumpmodules.h +++ b/src/daemon/dumpmodules.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/daemon/main.c b/src/daemon/main.c index b7266b7e..211dd30c 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 8023d3ad..40be5311 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h index 675856c6..ea6c7e1d 100644 --- a/src/modules/alsa-util.h +++ b/src/modules/alsa-util.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/dbus-util.c b/src/modules/dbus-util.c index ee9062d1..48a45174 100644 --- a/src/modules/dbus-util.c +++ b/src/modules/dbus-util.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + Copyright 2006 Shams E. King + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/dbus-util.h b/src/modules/dbus-util.h index 73501c29..8dca54fe 100644 --- a/src/modules/dbus-util.h +++ b/src/modules/dbus-util.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Shams E. King + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/gconf/gconf-helper.c b/src/modules/gconf/gconf-helper.c index 40724f4e..5f6def4d 100644 --- a/src/modules/gconf/gconf-helper.c +++ b/src/modules/gconf/gconf-helper.c @@ -2,6 +2,8 @@ /*** This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published diff --git a/src/modules/gconf/module-gconf.c b/src/modules/gconf/module-gconf.c index d9f649fd..df7b1643 100644 --- a/src/modules/gconf/module-gconf.c +++ b/src/modules/gconf/module-gconf.c @@ -2,6 +2,8 @@ /*** This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 2fea5891..74a57f37 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 596998d1..2ea551cb 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-cli.c b/src/modules/module-cli.c index b5c27299..19ac0c26 100644 --- a/src/modules/module-cli.c +++ b/src/modules/module-cli.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 6bc958aa..716c20b2 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index 3057f70d..41b68ac3 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -3,6 +3,10 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + Copyright 2006 Diego Pettenò + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-esound-compat-spawnfd.c b/src/modules/module-esound-compat-spawnfd.c index fbb6bd6d..1aecade5 100644 --- a/src/modules/module-esound-compat-spawnfd.c +++ b/src/modules/module-esound-compat-spawnfd.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-esound-compat-spawnpid.c b/src/modules/module-esound-compat-spawnpid.c index a7196313..a9fd166d 100644 --- a/src/modules/module-esound-compat-spawnpid.c +++ b/src/modules/module-esound-compat-spawnpid.c @@ -2,6 +2,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index 62600682..26638d9d 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index eb275ff0..56a3efc1 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + Copyright 2006 Shams E. King + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index 6175536c..c6a7e33f 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index 8d891ce6..8ca24035 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c index f32667ee..c8adbc8b 100644 --- a/src/modules/module-lirc.c +++ b/src/modules/module-lirc.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2005-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-match.c b/src/modules/module-match.c index d0e82ba3..0b051fac 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c index baf688f1..b7433ac8 100644 --- a/src/modules/module-mmkbd-evdev.c +++ b/src/modules/module-mmkbd-evdev.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2005-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-native-protocol-fd.c b/src/modules/module-native-protocol-fd.c index 907aab27..3c1c2bca 100644 --- a/src/modules/module-native-protocol-fd.c +++ b/src/modules/module-native-protocol-fd.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index fc9107a3..54a8e890 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index 7bf6cbbd..16c9b311 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index b8ced86f..965944a7 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index 72400313..170b046e 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index f53f6a63..56c721b0 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index 93fb2a36..4728f750 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-rescue-streams.c b/src/modules/module-rescue-streams.c index 2eea4f61..25005f25 100644 --- a/src/modules/module-rescue-streams.c +++ b/src/modules/module-rescue-streams.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-sine.c b/src/modules/module-sine.c index 871b702d..661455b3 100644 --- a/src/modules/module-sine.c +++ b/src/modules/module-sine.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 1454d639..a50f1ecf 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index f7420a67..288e049e 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index 877d17c7..0df270df 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index 79de077d..ad3645fc 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + Copyright 2006-2007 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-x11-bell.c b/src/modules/module-x11-bell.c index 5322a71f..b9c4ad49 100644 --- a/src/modules/module-x11-bell.c +++ b/src/modules/module-x11-bell.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c index b1c17a7c..fd1d532f 100644 --- a/src/modules/module-x11-publish.c +++ b/src/modules/module-x11-publish.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index 10643808..69508ad0 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index d26a0e81..fb531468 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/oss-util.h b/src/modules/oss-util.h index 6a8bf3d2..087e0d22 100644 --- a/src/modules/oss-util.h +++ b/src/modules/oss-util.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index 338d57cf..db83756a 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -1,6 +1,8 @@ /*** This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 7bbfabee..18e5e055 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -2,6 +2,8 @@ /*** This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c index 3bb0ea47..bc5260a8 100644 --- a/src/modules/rtp/rtp.c +++ b/src/modules/rtp/rtp.c @@ -2,6 +2,8 @@ /*** This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published diff --git a/src/modules/rtp/rtp.h b/src/modules/rtp/rtp.h index 123602b2..db7acd98 100644 --- a/src/modules/rtp/rtp.h +++ b/src/modules/rtp/rtp.h @@ -5,6 +5,8 @@ /*** This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c index 022c7fa3..f61c0efe 100644 --- a/src/modules/rtp/sap.c +++ b/src/modules/rtp/sap.c @@ -2,6 +2,8 @@ /*** This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published diff --git a/src/modules/rtp/sap.h b/src/modules/rtp/sap.h index 987403e3..cac697e6 100644 --- a/src/modules/rtp/sap.h +++ b/src/modules/rtp/sap.h @@ -5,6 +5,8 @@ /*** This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published diff --git a/src/modules/rtp/sdp.c b/src/modules/rtp/sdp.c index 1b71a9a0..7f0e7027 100644 --- a/src/modules/rtp/sdp.c +++ b/src/modules/rtp/sdp.c @@ -2,6 +2,8 @@ /*** This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published diff --git a/src/modules/rtp/sdp.h b/src/modules/rtp/sdp.h index b95ca633..4c68ac5a 100644 --- a/src/modules/rtp/sdp.h +++ b/src/modules/rtp/sdp.h @@ -5,6 +5,8 @@ /*** This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published diff --git a/src/pulse/browser.c b/src/pulse/browser.c index 4b0de029..27c5a2ea 100644 --- a/src/pulse/browser.c +++ b/src/pulse/browser.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/pulse/browser.h b/src/pulse/browser.h index 7b9aae8d..b039ca33 100644 --- a/src/pulse/browser.h +++ b/src/pulse/browser.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/pulse/cdecl.h b/src/pulse/cdecl.h index 09b9b84a..922ad276 100644 --- a/src/pulse/cdecl.h +++ b/src/pulse/cdecl.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/channelmap.c b/src/pulse/channelmap.c index 40655cf5..d5b8f743 100644 --- a/src/pulse/channelmap.c +++ b/src/pulse/channelmap.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2005-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/channelmap.h b/src/pulse/channelmap.h index 20380251..f0c8f475 100644 --- a/src/pulse/channelmap.h +++ b/src/pulse/channelmap.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2005-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/client-conf-x11.c b/src/pulse/client-conf-x11.c index 78e190e5..b5ac8d9f 100644 --- a/src/pulse/client-conf-x11.c +++ b/src/pulse/client-conf-x11.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/client-conf-x11.h b/src/pulse/client-conf-x11.h index 02e808be..56cd406d 100644 --- a/src/pulse/client-conf-x11.h +++ b/src/pulse/client-conf-x11.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c index b652a25b..bb912335 100644 --- a/src/pulse/client-conf.c +++ b/src/pulse/client-conf.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/client-conf.h b/src/pulse/client-conf.h index 35728aeb..6de64582 100644 --- a/src/pulse/client-conf.h +++ b/src/pulse/client-conf.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/context.c b/src/pulse/context.c index 7ef43b30..58a5a879 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/context.h b/src/pulse/context.h index 048ed17f..1de3abad 100644 --- a/src/pulse/context.h +++ b/src/pulse/context.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/def.h b/src/pulse/def.h index fb04de50..c2816234 100644 --- a/src/pulse/def.h +++ b/src/pulse/def.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulse/error.c b/src/pulse/error.c index 3b9a60a4..78f0da95 100644 --- a/src/pulse/error.c +++ b/src/pulse/error.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/error.h b/src/pulse/error.h index c96349a6..44a2e5ec 100644 --- a/src/pulse/error.h +++ b/src/pulse/error.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/glib-mainloop.c b/src/pulse/glib-mainloop.c index 1669acdd..5b399aa2 100644 --- a/src/pulse/glib-mainloop.c +++ b/src/pulse/glib-mainloop.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/glib-mainloop.h b/src/pulse/glib-mainloop.h index 5f8093a1..a4e06ea0 100644 --- a/src/pulse/glib-mainloop.h +++ b/src/pulse/glib-mainloop.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/internal.h b/src/pulse/internal.h index 8cdbf84a..52354fdc 100644 --- a/src/pulse/internal.h +++ b/src/pulse/internal.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c index 5a2c8fb6..7f6406cf 100644 --- a/src/pulse/introspect.c +++ b/src/pulse/introspect.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h index 6de7bc71..43e430b2 100644 --- a/src/pulse/introspect.h +++ b/src/pulse/introspect.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/mainloop-api.c b/src/pulse/mainloop-api.c index bf3ef37e..001ff314 100644 --- a/src/pulse/mainloop-api.c +++ b/src/pulse/mainloop-api.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulse/mainloop-api.h b/src/pulse/mainloop-api.h index b88bf125..985806e6 100644 --- a/src/pulse/mainloop-api.h +++ b/src/pulse/mainloop-api.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulse/mainloop-signal.c b/src/pulse/mainloop-signal.c index 4dd42796..28ddec49 100644 --- a/src/pulse/mainloop-signal.c +++ b/src/pulse/mainloop-signal.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/mainloop-signal.h b/src/pulse/mainloop-signal.h index e991cf1c..50aa99ce 100644 --- a/src/pulse/mainloop-signal.h +++ b/src/pulse/mainloop-signal.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c index 04461b30..43cbb19f 100644 --- a/src/pulse/mainloop.c +++ b/src/pulse/mainloop.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/mainloop.h b/src/pulse/mainloop.h index 18be1f2b..db2797fb 100644 --- a/src/pulse/mainloop.h +++ b/src/pulse/mainloop.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/operation.c b/src/pulse/operation.c index e039e8c9..f23def50 100644 --- a/src/pulse/operation.c +++ b/src/pulse/operation.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/operation.h b/src/pulse/operation.h index adfd5f2d..97d1c6b8 100644 --- a/src/pulse/operation.h +++ b/src/pulse/operation.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/pulseaudio.h b/src/pulse/pulseaudio.h index 5543d7cd..88d1275b 100644 --- a/src/pulse/pulseaudio.h +++ b/src/pulse/pulseaudio.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulse/sample.c b/src/pulse/sample.c index dd68ac17..aafafc83 100644 --- a/src/pulse/sample.c +++ b/src/pulse/sample.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/sample.h b/src/pulse/sample.h index b7c537e4..5e603685 100644 --- a/src/pulse/sample.h +++ b/src/pulse/sample.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/scache.c b/src/pulse/scache.c index 5abaf845..09bc1078 100644 --- a/src/pulse/scache.c +++ b/src/pulse/scache.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/scache.h b/src/pulse/scache.h index 2293dec4..31fd8956 100644 --- a/src/pulse/scache.h +++ b/src/pulse/scache.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/simple.c b/src/pulse/simple.c index 1c632fa7..3cf862d2 100644 --- a/src/pulse/simple.c +++ b/src/pulse/simple.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/simple.h b/src/pulse/simple.h index a97875f9..128d2716 100644 --- a/src/pulse/simple.h +++ b/src/pulse/simple.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/stream.c b/src/pulse/stream.c index 009eb3cf..f20c17ae 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/stream.h b/src/pulse/stream.h index 2ce53458..65603262 100644 --- a/src/pulse/stream.h +++ b/src/pulse/stream.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/subscribe.c b/src/pulse/subscribe.c index d9abf6f8..5d8f1252 100644 --- a/src/pulse/subscribe.c +++ b/src/pulse/subscribe.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/subscribe.h b/src/pulse/subscribe.h index 35d5a31c..c37ead57 100644 --- a/src/pulse/subscribe.h +++ b/src/pulse/subscribe.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/thread-mainloop.c b/src/pulse/thread-mainloop.c index ad29f5ba..4f3cacc9 100644 --- a/src/pulse/thread-mainloop.c +++ b/src/pulse/thread-mainloop.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/thread-mainloop.h b/src/pulse/thread-mainloop.h index 48048b35..b78c1583 100644 --- a/src/pulse/thread-mainloop.h +++ b/src/pulse/thread-mainloop.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/timeval.c b/src/pulse/timeval.c index e5a86a63..78ece061 100644 --- a/src/pulse/timeval.c +++ b/src/pulse/timeval.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulse/timeval.h b/src/pulse/timeval.h index c10ec9f6..1e5627e3 100644 --- a/src/pulse/timeval.h +++ b/src/pulse/timeval.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulse/utf8.c b/src/pulse/utf8.c index 2708c518..2ac2d106 100644 --- a/src/pulse/utf8.c +++ b/src/pulse/utf8.c @@ -1,5 +1,27 @@ /* $Id$ */ +/*** + This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + /* This file is based on the GLIB utf8 validation functions. The * original license text follows. */ diff --git a/src/pulse/utf8.h b/src/pulse/utf8.h index 7225471f..ff8dc215 100644 --- a/src/pulse/utf8.h +++ b/src/pulse/utf8.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulse/util.c b/src/pulse/util.c index 63f54e3b..d561329c 100644 --- a/src/pulse/util.c +++ b/src/pulse/util.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulse/util.h b/src/pulse/util.h index 0be169fb..95bd86f3 100644 --- a/src/pulse/util.h +++ b/src/pulse/util.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulse/version.h.in b/src/pulse/version.h.in index 748541a1..20c7a9c0 100644 --- a/src/pulse/version.h.in +++ b/src/pulse/version.h.in @@ -5,6 +5,9 @@ /*** This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published diff --git a/src/pulse/volume.c b/src/pulse/volume.c index aa7ddba2..feb33f07 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/volume.h b/src/pulse/volume.h index 62d2867a..a928ff71 100644 --- a/src/pulse/volume.h +++ b/src/pulse/volume.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/xmalloc.c b/src/pulse/xmalloc.c index dda42bdc..1f0734c2 100644 --- a/src/pulse/xmalloc.c +++ b/src/pulse/xmalloc.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulse/xmalloc.h b/src/pulse/xmalloc.h index 2fb1c5f0..2f6399c5 100644 --- a/src/pulse/xmalloc.h +++ b/src/pulse/xmalloc.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/anotify.c b/src/pulsecore/anotify.c index c89d4a15..25c5fe7d 100644 --- a/src/pulsecore/anotify.c +++ b/src/pulsecore/anotify.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/anotify.h b/src/pulsecore/anotify.h index b91e6875..b3f75b7e 100644 --- a/src/pulsecore/anotify.h +++ b/src/pulsecore/anotify.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/pulsecore/atomic.h b/src/pulsecore/atomic.h index e713e7a8..8867f884 100644 --- a/src/pulsecore/atomic.h +++ b/src/pulsecore/atomic.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/pulsecore/authkey-prop.c b/src/pulsecore/authkey-prop.c index f3a81179..3b8304b2 100644 --- a/src/pulsecore/authkey-prop.c +++ b/src/pulsecore/authkey-prop.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/authkey-prop.h b/src/pulsecore/authkey-prop.h index fb777f85..247202f3 100644 --- a/src/pulsecore/authkey-prop.h +++ b/src/pulsecore/authkey-prop.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/authkey.c b/src/pulsecore/authkey.c index 8ef53bd8..a6150d0e 100644 --- a/src/pulsecore/authkey.c +++ b/src/pulsecore/authkey.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/authkey.h b/src/pulsecore/authkey.h index bba0bc73..18e5157d 100644 --- a/src/pulsecore/authkey.h +++ b/src/pulsecore/authkey.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/autoload.c b/src/pulsecore/autoload.c index b68eaac7..6f888526 100644 --- a/src/pulsecore/autoload.c +++ b/src/pulsecore/autoload.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/autoload.h b/src/pulsecore/autoload.h index f410e49c..2899586c 100644 --- a/src/pulsecore/autoload.h +++ b/src/pulsecore/autoload.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/avahi-wrap.c b/src/pulsecore/avahi-wrap.c index bcda9954..855ed567 100644 --- a/src/pulsecore/avahi-wrap.c +++ b/src/pulsecore/avahi-wrap.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/pulsecore/avahi-wrap.h b/src/pulsecore/avahi-wrap.h index bb8f5716..1e20ec38 100644 --- a/src/pulsecore/avahi-wrap.h +++ b/src/pulsecore/avahi-wrap.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index cb438a22..aa2beba2 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/cli-command.h b/src/pulsecore/cli-command.h index 1594f4db..10d50f37 100644 --- a/src/pulsecore/cli-command.h +++ b/src/pulsecore/cli-command.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index ac74a287..e97f0574 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/cli-text.h b/src/pulsecore/cli-text.h index b092fc8b..9e5bf081 100644 --- a/src/pulsecore/cli-text.h +++ b/src/pulsecore/cli-text.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/cli.c b/src/pulsecore/cli.c index 0820fc8e..ee05d7f9 100644 --- a/src/pulsecore/cli.c +++ b/src/pulsecore/cli.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/cli.h b/src/pulsecore/cli.h index 5cf0ebd2..2b58d458 100644 --- a/src/pulsecore/cli.h +++ b/src/pulsecore/cli.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/client.c b/src/pulsecore/client.c index 55697d2e..0d792bb4 100644 --- a/src/pulsecore/client.c +++ b/src/pulsecore/client.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/client.h b/src/pulsecore/client.h index e632da12..6d09b999 100644 --- a/src/pulsecore/client.h +++ b/src/pulsecore/client.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/conf-parser.c b/src/pulsecore/conf-parser.c index 6f55e2de..12efbd2c 100644 --- a/src/pulsecore/conf-parser.c +++ b/src/pulsecore/conf-parser.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/conf-parser.h b/src/pulsecore/conf-parser.h index 9c1a697a..b56d979e 100644 --- a/src/pulsecore/conf-parser.h +++ b/src/pulsecore/conf-parser.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/core-def.h b/src/pulsecore/core-def.h index f849a6f6..10a3be42 100644 --- a/src/pulsecore/core-def.h +++ b/src/pulsecore/core-def.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/core-error.c b/src/pulsecore/core-error.c index 2362068f..044bea12 100644 --- a/src/pulsecore/core-error.c +++ b/src/pulsecore/core-error.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/core-error.h b/src/pulsecore/core-error.h index e4390833..443c4883 100644 --- a/src/pulsecore/core-error.h +++ b/src/pulsecore/core-error.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/core-scache.c b/src/pulsecore/core-scache.c index 26c493ca..75fb47f0 100644 --- a/src/pulsecore/core-scache.c +++ b/src/pulsecore/core-scache.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/core-scache.h b/src/pulsecore/core-scache.h index 69baabbc..bbf13f15 100644 --- a/src/pulsecore/core-scache.h +++ b/src/pulsecore/core-scache.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/core-subscribe.c b/src/pulsecore/core-subscribe.c index 5a958b83..6608d57a 100644 --- a/src/pulsecore/core-subscribe.c +++ b/src/pulsecore/core-subscribe.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/core-subscribe.h b/src/pulsecore/core-subscribe.h index 875cf331..2b6863f9 100644 --- a/src/pulsecore/core-subscribe.h +++ b/src/pulsecore/core-subscribe.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 1e8fd23b..ac1023a0 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -3,6 +3,10 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2004 Joe Marcus Clarke + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index b2608edd..a1da3e28 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index b19b1974..31b6c188 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index c1c6a19c..51a18b62 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/creds.h b/src/pulsecore/creds.h index 5ad880a0..e0a025bd 100644 --- a/src/pulsecore/creds.h +++ b/src/pulsecore/creds.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/dllmain.c b/src/pulsecore/dllmain.c index b86bf04f..52cbf9e2 100644 --- a/src/pulsecore/dllmain.c +++ b/src/pulsecore/dllmain.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/dynarray.c b/src/pulsecore/dynarray.c index 91a9d5e1..944e3570 100644 --- a/src/pulsecore/dynarray.c +++ b/src/pulsecore/dynarray.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/dynarray.h b/src/pulsecore/dynarray.h index 216d8766..0f222e10 100644 --- a/src/pulsecore/dynarray.h +++ b/src/pulsecore/dynarray.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/endianmacros.h b/src/pulsecore/endianmacros.h index c0193014..c0c3a6d8 100644 --- a/src/pulsecore/endianmacros.h +++ b/src/pulsecore/endianmacros.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/esound.h b/src/pulsecore/esound.h index 0ea201b6..3778a535 100644 --- a/src/pulsecore/esound.h +++ b/src/pulsecore/esound.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/flist.c b/src/pulsecore/flist.c index 5091bfd1..00567ab3 100644 --- a/src/pulsecore/flist.c +++ b/src/pulsecore/flist.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/flist.h b/src/pulsecore/flist.h index 9871f32d..bf702bf3 100644 --- a/src/pulsecore/flist.h +++ b/src/pulsecore/flist.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/pulsecore/gccmacro.h b/src/pulsecore/gccmacro.h index 87f7eece..57d28006 100644 --- a/src/pulsecore/gccmacro.h +++ b/src/pulsecore/gccmacro.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/hashmap.c b/src/pulsecore/hashmap.c index 809eaeec..818e12bf 100644 --- a/src/pulsecore/hashmap.c +++ b/src/pulsecore/hashmap.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/hashmap.h b/src/pulsecore/hashmap.h index 18e41cf3..3ca2a479 100644 --- a/src/pulsecore/hashmap.h +++ b/src/pulsecore/hashmap.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/hook-list.c b/src/pulsecore/hook-list.c index 40f6b435..4f884187 100644 --- a/src/pulsecore/hook-list.c +++ b/src/pulsecore/hook-list.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/pulsecore/hook-list.h b/src/pulsecore/hook-list.h index 9a219a90..b3bd600a 100644 --- a/src/pulsecore/hook-list.h +++ b/src/pulsecore/hook-list.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/pulsecore/idxset.c b/src/pulsecore/idxset.c index dce51e21..70ef7ba7 100644 --- a/src/pulsecore/idxset.c +++ b/src/pulsecore/idxset.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/idxset.h b/src/pulsecore/idxset.h index 0d751e07..17a70f4f 100644 --- a/src/pulsecore/idxset.h +++ b/src/pulsecore/idxset.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/inet_ntop.c b/src/pulsecore/inet_ntop.c index 5d7a543e..302369f7 100644 --- a/src/pulsecore/inet_ntop.c +++ b/src/pulsecore/inet_ntop.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/inet_pton.c b/src/pulsecore/inet_pton.c index 42bb5387..7272e459 100644 --- a/src/pulsecore/inet_pton.c +++ b/src/pulsecore/inet_pton.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c index b40f0aa1..2f6fdd39 100644 --- a/src/pulsecore/iochannel.c +++ b/src/pulsecore/iochannel.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/iochannel.h b/src/pulsecore/iochannel.h index 147e7276..c22fefd3 100644 --- a/src/pulsecore/iochannel.h +++ b/src/pulsecore/iochannel.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/ioline.c b/src/pulsecore/ioline.c index 2fe5c88d..07b60bee 100644 --- a/src/pulsecore/ioline.c +++ b/src/pulsecore/ioline.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/ioline.h b/src/pulsecore/ioline.h index 8d3fb5f8..8475b798 100644 --- a/src/pulsecore/ioline.h +++ b/src/pulsecore/ioline.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/ipacl.c b/src/pulsecore/ipacl.c index 2848b169..a240d2a0 100644 --- a/src/pulsecore/ipacl.c +++ b/src/pulsecore/ipacl.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/ipacl.h b/src/pulsecore/ipacl.h index 61bf99b0..175f54e0 100644 --- a/src/pulsecore/ipacl.h +++ b/src/pulsecore/ipacl.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/llist.h b/src/pulsecore/llist.h index 49d26166..8fc8e22b 100644 --- a/src/pulsecore/llist.h +++ b/src/pulsecore/llist.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c index 7ad90383..7eb83de7 100644 --- a/src/pulsecore/log.c +++ b/src/pulsecore/log.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/pulsecore/log.h b/src/pulsecore/log.h index 728c2501..b0711dca 100644 --- a/src/pulsecore/log.h +++ b/src/pulsecore/log.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/mcalign.c b/src/pulsecore/mcalign.c index baf36784..dd1d71f3 100644 --- a/src/pulsecore/mcalign.c +++ b/src/pulsecore/mcalign.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/mcalign.h b/src/pulsecore/mcalign.h index 751eacd3..6ff8f94e 100644 --- a/src/pulsecore/mcalign.h +++ b/src/pulsecore/mcalign.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 73874cf1..5e7d6e48 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/memblock.h b/src/pulsecore/memblock.h index eeecf756..3eace92c 100644 --- a/src/pulsecore/memblock.h +++ b/src/pulsecore/memblock.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index 4a845a53..e31fb6df 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/memblockq.h b/src/pulsecore/memblockq.h index 3485a669..437c5a41 100644 --- a/src/pulsecore/memblockq.h +++ b/src/pulsecore/memblockq.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/pulsecore/memchunk.c b/src/pulsecore/memchunk.c index 2ab6d358..7111e1ec 100644 --- a/src/pulsecore/memchunk.c +++ b/src/pulsecore/memchunk.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/memchunk.h b/src/pulsecore/memchunk.h index 2e2f936b..0b982b6d 100644 --- a/src/pulsecore/memchunk.h +++ b/src/pulsecore/memchunk.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/modargs.c b/src/pulsecore/modargs.c index 243ea019..3733f655 100644 --- a/src/pulsecore/modargs.c +++ b/src/pulsecore/modargs.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/modargs.h b/src/pulsecore/modargs.h index 5cccee90..77262e1e 100644 --- a/src/pulsecore/modargs.h +++ b/src/pulsecore/modargs.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/modinfo.c b/src/pulsecore/modinfo.c index 46e66c50..58394e59 100644 --- a/src/pulsecore/modinfo.c +++ b/src/pulsecore/modinfo.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/pulsecore/modinfo.h b/src/pulsecore/modinfo.h index e8d3103f..3ee33ede 100644 --- a/src/pulsecore/modinfo.h +++ b/src/pulsecore/modinfo.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/module.c b/src/pulsecore/module.c index 94410b39..09b15b8b 100644 --- a/src/pulsecore/module.c +++ b/src/pulsecore/module.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/module.h b/src/pulsecore/module.h index 5f107507..750dfaa8 100644 --- a/src/pulsecore/module.h +++ b/src/pulsecore/module.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/mutex-posix.c b/src/pulsecore/mutex-posix.c index 896913ce..52e731b3 100644 --- a/src/pulsecore/mutex-posix.c +++ b/src/pulsecore/mutex-posix.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/mutex-win32.c b/src/pulsecore/mutex-win32.c index 124b17c6..1f16e24c 100644 --- a/src/pulsecore/mutex-win32.c +++ b/src/pulsecore/mutex-win32.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/mutex.h b/src/pulsecore/mutex.h index 11a20733..b2e34c07 100644 --- a/src/pulsecore/mutex.h +++ b/src/pulsecore/mutex.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c index faf7f144..7f66af05 100644 --- a/src/pulsecore/namereg.c +++ b/src/pulsecore/namereg.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/namereg.h b/src/pulsecore/namereg.h index efadb06e..350ba0f6 100644 --- a/src/pulsecore/namereg.h +++ b/src/pulsecore/namereg.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/native-common.h b/src/pulsecore/native-common.h index df7654ff..f7a7da1d 100644 --- a/src/pulsecore/native-common.h +++ b/src/pulsecore/native-common.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/once-posix.c b/src/pulsecore/once-posix.c index bb2ca793..4af7b36e 100644 --- a/src/pulsecore/once-posix.c +++ b/src/pulsecore/once-posix.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/once-win32.c b/src/pulsecore/once-win32.c index 07f68f38..b30097c8 100644 --- a/src/pulsecore/once-win32.c +++ b/src/pulsecore/once-win32.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/once.h b/src/pulsecore/once.h index 3c475a1d..c20fc0b4 100644 --- a/src/pulsecore/once.h +++ b/src/pulsecore/once.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/pulsecore/packet.c b/src/pulsecore/packet.c index b3a4b6f4..ce57cb3e 100644 --- a/src/pulsecore/packet.c +++ b/src/pulsecore/packet.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/packet.h b/src/pulsecore/packet.h index 89759c5a..842582c8 100644 --- a/src/pulsecore/packet.h +++ b/src/pulsecore/packet.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/parseaddr.c b/src/pulsecore/parseaddr.c index 3a5bc2e8..a49a09ed 100644 --- a/src/pulsecore/parseaddr.c +++ b/src/pulsecore/parseaddr.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/parseaddr.h b/src/pulsecore/parseaddr.h index bbbb8989..fd7cad3b 100644 --- a/src/pulsecore/parseaddr.h +++ b/src/pulsecore/parseaddr.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c index c474ccd1..758beaff 100644 --- a/src/pulsecore/pdispatch.c +++ b/src/pulsecore/pdispatch.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/pdispatch.h b/src/pulsecore/pdispatch.h index 28bc29d9..de0aa3ec 100644 --- a/src/pulsecore/pdispatch.h +++ b/src/pulsecore/pdispatch.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/pid.c b/src/pulsecore/pid.c index 40cc8248..5e670e17 100644 --- a/src/pulsecore/pid.c +++ b/src/pulsecore/pid.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/pulsecore/pid.h b/src/pulsecore/pid.h index 31d6f0bb..0f25d1c8 100644 --- a/src/pulsecore/pid.h +++ b/src/pulsecore/pid.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/pulsecore/pipe.c b/src/pulsecore/pipe.c index a0c46fa3..a659915e 100644 --- a/src/pulsecore/pipe.c +++ b/src/pulsecore/pipe.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/pipe.h b/src/pulsecore/pipe.h index 86a198d3..e013a2e7 100644 --- a/src/pulsecore/pipe.h +++ b/src/pulsecore/pipe.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c index ae7cd616..76edd27a 100644 --- a/src/pulsecore/play-memblockq.c +++ b/src/pulsecore/play-memblockq.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/play-memblockq.h b/src/pulsecore/play-memblockq.h index 68d0f8e3..8248e859 100644 --- a/src/pulsecore/play-memblockq.h +++ b/src/pulsecore/play-memblockq.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/play-memchunk.c b/src/pulsecore/play-memchunk.c index c5dcc8ce..9132e294 100644 --- a/src/pulsecore/play-memchunk.c +++ b/src/pulsecore/play-memchunk.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/play-memchunk.h b/src/pulsecore/play-memchunk.h index 3e087baa..5afb094c 100644 --- a/src/pulsecore/play-memchunk.h +++ b/src/pulsecore/play-memchunk.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/poll.c b/src/pulsecore/poll.c index 82af4c05..2f8eae89 100644 --- a/src/pulsecore/poll.c +++ b/src/pulsecore/poll.c @@ -1,15 +1,11 @@ /* $Id$ */ -/*** - Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc. - Copyright (C) 2005, Cendio AB. - This file is part of PulseAudio. - Based on work for the GNU C Library. -***/ /*** This file is part of PulseAudio. + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, @@ -26,6 +22,11 @@ USA. ***/ +/*** + Based on work for the GNU C Library. + Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc. +***/ + /* Poll the file descriptors described by the NFDS structures starting at FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for an event to occur; if TIMEOUT is -1, block until an event occurs. diff --git a/src/pulsecore/poll.h b/src/pulsecore/poll.h index 9c29789d..6be6069b 100644 --- a/src/pulsecore/poll.h +++ b/src/pulsecore/poll.h @@ -1,16 +1,10 @@ /* $Id$ */ -/*** - Compatibility definitions for System V `poll' interface. - Copyright (C) 1994,96,97,98,99,2000,2001,2004 Free Software Foundation, Inc. - Copyright (C) 2005, Cendio AB. - This file is part of PulseAudio. - Based on work for the GNU C Library. -***/ - /*** This file is part of PulseAudio. + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, @@ -27,6 +21,11 @@ USA. ***/ +/*** + Based on work for the GNU C Library. + Copyright (C) 1994,96,97,98,99,2000,2001,2004 Free Software Foundation, Inc. +***/ + /* Event types that can be polled for. These bits may be set in `events' to indicate the interesting event types; they will appear in `revents' to indicate the status of the file descriptor. */ diff --git a/src/pulsecore/props.c b/src/pulsecore/props.c index b8f92090..4a39f0fb 100644 --- a/src/pulsecore/props.c +++ b/src/pulsecore/props.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/props.h b/src/pulsecore/props.h index 2b881b67..880325f6 100644 --- a/src/pulsecore/props.h +++ b/src/pulsecore/props.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/protocol-cli.c b/src/pulsecore/protocol-cli.c index 9cca39eb..1d543ae5 100644 --- a/src/pulsecore/protocol-cli.c +++ b/src/pulsecore/protocol-cli.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/protocol-cli.h b/src/pulsecore/protocol-cli.h index 6acd62cf..3870def3 100644 --- a/src/pulsecore/protocol-cli.h +++ b/src/pulsecore/protocol-cli.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 2984676d..ae6612ae 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/protocol-esound.h b/src/pulsecore/protocol-esound.h index 265f9e2c..868ef5d2 100644 --- a/src/pulsecore/protocol-esound.h +++ b/src/pulsecore/protocol-esound.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/protocol-http.c b/src/pulsecore/protocol-http.c index 22ecba82..3541721a 100644 --- a/src/pulsecore/protocol-http.c +++ b/src/pulsecore/protocol-http.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2005-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/protocol-http.h b/src/pulsecore/protocol-http.h index bf1562e6..cf952476 100644 --- a/src/pulsecore/protocol-http.h +++ b/src/pulsecore/protocol-http.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2005-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index a882d701..4e861f85 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/protocol-native.h b/src/pulsecore/protocol-native.h index fcd4cb37..bf05f937 100644 --- a/src/pulsecore/protocol-native.h +++ b/src/pulsecore/protocol-native.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c index 0a7a7acb..31ad6ddd 100644 --- a/src/pulsecore/protocol-simple.c +++ b/src/pulsecore/protocol-simple.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/protocol-simple.h b/src/pulsecore/protocol-simple.h index 183f3acc..3b02c88e 100644 --- a/src/pulsecore/protocol-simple.h +++ b/src/pulsecore/protocol-simple.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/pstream-util.c b/src/pulsecore/pstream-util.c index 6ebb2863..fae1e49b 100644 --- a/src/pulsecore/pstream-util.c +++ b/src/pulsecore/pstream-util.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/pstream-util.h b/src/pulsecore/pstream-util.h index 5f1bbd60..67759f2a 100644 --- a/src/pulsecore/pstream-util.h +++ b/src/pulsecore/pstream-util.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index 7e1e5f57..3398df0d 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/pstream.h b/src/pulsecore/pstream.h index 0ab16720..5900ecea 100644 --- a/src/pulsecore/pstream.h +++ b/src/pulsecore/pstream.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/queue.c b/src/pulsecore/queue.c index 3132c5c5..1dd0f606 100644 --- a/src/pulsecore/queue.c +++ b/src/pulsecore/queue.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/queue.h b/src/pulsecore/queue.h index cebe4cdf..cd767364 100644 --- a/src/pulsecore/queue.h +++ b/src/pulsecore/queue.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/random.c b/src/pulsecore/random.c index c3184c78..3f591917 100644 --- a/src/pulsecore/random.c +++ b/src/pulsecore/random.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/random.h b/src/pulsecore/random.h index cdac9ac6..01b7d746 100644 --- a/src/pulsecore/random.h +++ b/src/pulsecore/random.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/refcnt.h b/src/pulsecore/refcnt.h index f3918213..43433ff8 100644 --- a/src/pulsecore/refcnt.h +++ b/src/pulsecore/refcnt.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index e61864dd..3827ff94 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/resampler.h b/src/pulsecore/resampler.h index 7a781364..c283593d 100644 --- a/src/pulsecore/resampler.h +++ b/src/pulsecore/resampler.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index ddf72920..411787af 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/sample-util.h b/src/pulsecore/sample-util.h index 1883b2cc..3ff065ab 100644 --- a/src/pulsecore/sample-util.h +++ b/src/pulsecore/sample-util.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/sconv-s16be.c b/src/pulsecore/sconv-s16be.c index 3af167df..c530e79b 100644 --- a/src/pulsecore/sconv-s16be.c +++ b/src/pulsecore/sconv-s16be.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/sconv-s16be.h b/src/pulsecore/sconv-s16be.h index b96f59ab..6b736f69 100644 --- a/src/pulsecore/sconv-s16be.h +++ b/src/pulsecore/sconv-s16be.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/sconv-s16le.c b/src/pulsecore/sconv-s16le.c index 1743d61f..5f45ef66 100644 --- a/src/pulsecore/sconv-s16le.c +++ b/src/pulsecore/sconv-s16le.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/sconv-s16le.h b/src/pulsecore/sconv-s16le.h index 37e85e2f..c4e4911a 100644 --- a/src/pulsecore/sconv-s16le.h +++ b/src/pulsecore/sconv-s16le.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/sconv.c b/src/pulsecore/sconv.c index 6bea0608..d15cec84 100644 --- a/src/pulsecore/sconv.c +++ b/src/pulsecore/sconv.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/sconv.h b/src/pulsecore/sconv.h index 52240fd3..1e97aad9 100644 --- a/src/pulsecore/sconv.h +++ b/src/pulsecore/sconv.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c index 6188b16c..444d4010 100644 --- a/src/pulsecore/shm.c +++ b/src/pulsecore/shm.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/shm.h b/src/pulsecore/shm.h index f621474c..e695a2a1 100644 --- a/src/pulsecore/shm.h +++ b/src/pulsecore/shm.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 58fe37d5..3ddd7435 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 9d7487f7..51d9ec78 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index cb0e54c1..9588c2c3 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 7cfc9e26..ef73f67d 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/sioman.c b/src/pulsecore/sioman.c index 4d5d5562..d3d7538e 100644 --- a/src/pulsecore/sioman.c +++ b/src/pulsecore/sioman.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/sioman.h b/src/pulsecore/sioman.h index bbd52110..49fffb34 100644 --- a/src/pulsecore/sioman.h +++ b/src/pulsecore/sioman.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/socket-client.c b/src/pulsecore/socket-client.c index b08ba010..4ea81113 100644 --- a/src/pulsecore/socket-client.c +++ b/src/pulsecore/socket-client.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/socket-client.h b/src/pulsecore/socket-client.h index 146ebda8..b1d58eff 100644 --- a/src/pulsecore/socket-client.h +++ b/src/pulsecore/socket-client.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/socket-server.c b/src/pulsecore/socket-server.c index c878ab1a..eaa8eb91 100644 --- a/src/pulsecore/socket-server.c +++ b/src/pulsecore/socket-server.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/socket-server.h b/src/pulsecore/socket-server.h index 489878cb..777599e5 100644 --- a/src/pulsecore/socket-server.h +++ b/src/pulsecore/socket-server.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/socket-util.c b/src/pulsecore/socket-util.c index e16f8979..5e2cfe03 100644 --- a/src/pulsecore/socket-util.c +++ b/src/pulsecore/socket-util.c @@ -3,6 +3,10 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2004 Joe Marcus Clarke + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/socket-util.h b/src/pulsecore/socket-util.h index 59b4980d..616c40ac 100644 --- a/src/pulsecore/socket-util.h +++ b/src/pulsecore/socket-util.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c index a277f1f0..7a43c743 100644 --- a/src/pulsecore/sound-file-stream.c +++ b/src/pulsecore/sound-file-stream.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/sound-file-stream.h b/src/pulsecore/sound-file-stream.h index 0798b423..189e242d 100644 --- a/src/pulsecore/sound-file-stream.h +++ b/src/pulsecore/sound-file-stream.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/sound-file.c b/src/pulsecore/sound-file.c index 284bbdda..69b543ab 100644 --- a/src/pulsecore/sound-file.c +++ b/src/pulsecore/sound-file.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/sound-file.h b/src/pulsecore/sound-file.h index cf8168d0..46763bd8 100644 --- a/src/pulsecore/sound-file.h +++ b/src/pulsecore/sound-file.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 5783b44a..c7a9858c 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index 827b68ee..3da6caac 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 702dbeff..9bb2d342 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index 462bc6ff..5a28cf4b 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/strbuf.c b/src/pulsecore/strbuf.c index 59d57260..a3ddc114 100644 --- a/src/pulsecore/strbuf.c +++ b/src/pulsecore/strbuf.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/strbuf.h b/src/pulsecore/strbuf.h index 04109197..1c0850b1 100644 --- a/src/pulsecore/strbuf.h +++ b/src/pulsecore/strbuf.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/strlist.c b/src/pulsecore/strlist.c index 23547bba..955b78e4 100644 --- a/src/pulsecore/strlist.c +++ b/src/pulsecore/strlist.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/strlist.h b/src/pulsecore/strlist.h index 07d04677..96ad47e2 100644 --- a/src/pulsecore/strlist.h +++ b/src/pulsecore/strlist.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/tagstruct.c b/src/pulsecore/tagstruct.c index 3a0915cf..ac7ae1ab 100644 --- a/src/pulsecore/tagstruct.c +++ b/src/pulsecore/tagstruct.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/tagstruct.h b/src/pulsecore/tagstruct.h index 0177ff9d..e9bb9ac8 100644 --- a/src/pulsecore/tagstruct.h +++ b/src/pulsecore/tagstruct.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c index dcd45ea7..7ff5e7c3 100644 --- a/src/pulsecore/thread-posix.c +++ b/src/pulsecore/thread-posix.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/thread-win32.c b/src/pulsecore/thread-win32.c index 38dd4dd6..46d273b4 100644 --- a/src/pulsecore/thread-win32.c +++ b/src/pulsecore/thread-win32.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/thread.h b/src/pulsecore/thread.h index b383bb49..ca1fe4da 100644 --- a/src/pulsecore/thread.h +++ b/src/pulsecore/thread.h @@ -6,6 +6,9 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the diff --git a/src/pulsecore/tokenizer.c b/src/pulsecore/tokenizer.c index 0bc1c095..117c7f88 100644 --- a/src/pulsecore/tokenizer.c +++ b/src/pulsecore/tokenizer.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/tokenizer.h b/src/pulsecore/tokenizer.h index 82cd6db1..68a8db49 100644 --- a/src/pulsecore/tokenizer.h +++ b/src/pulsecore/tokenizer.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/x11prop.c b/src/pulsecore/x11prop.c index 03d7990e..5b85ea42 100644 --- a/src/pulsecore/x11prop.c +++ b/src/pulsecore/x11prop.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/x11prop.h b/src/pulsecore/x11prop.h index bd24951a..388c5a34 100644 --- a/src/pulsecore/x11prop.h +++ b/src/pulsecore/x11prop.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/x11wrap.c b/src/pulsecore/x11wrap.c index e4b048ba..6a6a2692 100644 --- a/src/pulsecore/x11wrap.c +++ b/src/pulsecore/x11wrap.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/pulsecore/x11wrap.h b/src/pulsecore/x11wrap.h index b2e8e534..9bed2fce 100644 --- a/src/pulsecore/x11wrap.h +++ b/src/pulsecore/x11wrap.h @@ -6,6 +6,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/utils/pabrowse.c b/src/utils/pabrowse.c index f756ac01..d88001ef 100644 --- a/src/utils/pabrowse.c +++ b/src/utils/pabrowse.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/utils/pacat.c b/src/utils/pacat.c index cb103c99..96b6adb7 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c index d25b26c3..16e5822f 100644 --- a/src/utils/pacmd.c +++ b/src/utils/pacmd.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 0c418c4f..b95cbfee 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/utils/padsp b/src/utils/padsp index bae5a728..c70c3af7 100755 --- a/src/utils/padsp +++ b/src/utils/padsp @@ -4,6 +4,9 @@ # # This file is part of PulseAudio. # +# Copyright 2006 Lennart Poettering +# Copyright 2006 Pierre Ossman for Cendio AB +# # PulseAudio is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2 of the License, or diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 2b314a9c..444e1b4d 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/utils/paplay.c b/src/utils/paplay.c index 1617b27d..2c779a7a 100644 --- a/src/utils/paplay.c +++ b/src/utils/paplay.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, diff --git a/src/utils/pax11publish.c b/src/utils/pax11publish.c index 00332f65..9a50f8ef 100644 --- a/src/utils/pax11publish.c +++ b/src/utils/pax11publish.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, -- cgit From 3016c7561d1efb322fae6c82932970c89659ad54 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 14 Feb 2007 09:26:48 +0000 Subject: Prefix log lines with a character indicating level. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1427 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/log.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c index 7eb83de7..d8a9efe9 100644 --- a/src/pulsecore/log.c +++ b/src/pulsecore/log.c @@ -129,6 +129,7 @@ void pa_log_levelv_meta( switch (log_target) { case PA_LOG_STDERR: { const char *prefix = "", *suffix = ""; + const char *level_code = ""; char *local_t; #ifndef OS_IS_WIN32 @@ -144,11 +145,33 @@ void pa_log_levelv_meta( } #endif + switch (level) { + case PA_LOG_ERROR: + level_code = "E"; + break; + case PA_LOG_WARN: + level_code = "W"; + break; + case PA_LOG_NOTICE: + level_code = "N"; + break; + case PA_LOG_INFO: + level_code = "I"; + break; + case PA_LOG_DEBUG: + level_code = "D"; + break; + default: + level_code = "?"; + } + local_t = pa_utf8_to_locale(t); - if (!local_t) - fprintf(stderr, "%s%s%s%s\n", location, prefix, t, suffix); - else { - fprintf(stderr, "%s%s%s%s\n", location, prefix, local_t, suffix); + if (!local_t) { + fprintf(stderr, "%s: %s%s%s%s\n", level_code, location, + prefix, t, suffix); + } else { + fprintf(stderr, "%s: %s%s%s%s\n", level_code, location, + prefix, local_t, suffix); pa_xfree(local_t); } -- cgit From 8bf7943e8e03922de8c4a0990057a6fbf07935c6 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 14 Feb 2007 09:27:19 +0000 Subject: Allow a formatted string in the validation warning. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1428 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index ae6612ae..49a78d41 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -280,9 +280,9 @@ static int format_native2esd(pa_sample_spec *ss) { return format; } -#define CHECK_VALIDITY(expression, string) do { \ +#define CHECK_VALIDITY(expression, ...) do { \ if (!(expression)) { \ - pa_log_warn(__FILE__ ": " string); \ + pa_log_warn(__FILE__ ": " __VA_ARGS__); \ return -1; \ } \ } while(0); @@ -350,7 +350,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t if (c->protocol->sink_name) { sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1); - CHECK_VALIDITY(sink, "No such sink"); + CHECK_VALIDITY(sink, "No such sink: %s", c->protocol->sink_name); } strncpy(name, data, sizeof(name)); @@ -719,7 +719,7 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ sc_length = MAYBE_INT32_SWAP(c->swap_byte_order, sc_length); data = (const char*)data + sizeof(int32_t); - CHECK_VALIDITY(sc_length <= MAX_CACHE_SAMPLE_SIZE, "Sample too large."); + CHECK_VALIDITY(sc_length <= MAX_CACHE_SAMPLE_SIZE, "Sample too large (%d bytes).", (int)sc_length); strcpy(name, SCACHE_PREFIX); strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX); -- cgit From df47c7b828c02afbabc4d024008fabb07a882397 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 14 Feb 2007 12:13:49 +0000 Subject: Add a wrapper around close() to work around Windows' ass backwards way of handling sockets. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1429 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/core-util.c | 22 +++++++++++++++++++++- src/pulsecore/core-util.h | 4 +++- src/pulsecore/iochannel.c | 7 +++---- src/pulsecore/pipe.c | 10 +++++----- src/pulsecore/socket-client.c | 8 ++++---- src/pulsecore/socket-server.c | 14 +++++++------- src/pulsecore/socket-util.c | 4 ++-- 7 files changed, 45 insertions(+), 24 deletions(-) diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index ac1023a0..cc0fb205 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -5,7 +5,7 @@ Copyright 2004-2006 Lennart Poettering Copyright 2004 Joe Marcus Clarke - Copyright 2006 Pierre Ossman for Cendio AB + Copyright 2006-2007 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -348,6 +348,26 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size, int *type) { return ret; } +/** Platform independent read function. Necessary since not all + * systems treat all file descriptors equal. */ +int pa_close(int fd) +{ +#ifdef OS_IS_WIN32 + int ret; + + ret = closesocket(fd); + if (ret == 0) + return 0; + + if (WSAGetLastError() != WSAENOTSOCK) { + errno = WSAGetLastError(); + return ret; + } +#endif + + return close(fd); +} + /* Print a warning messages in case that the given signal is not * blocked or trapped */ void pa_check_signal_is_blocked(int sig) { diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index a1da3e28..1d921e03 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -7,7 +7,7 @@ This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering - Copyright 2006 Pierre Ossman for Cendio AB + Copyright 2006-2007 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -44,6 +44,8 @@ ssize_t pa_write(int fd, const void *buf, size_t count, int *type); ssize_t pa_loop_read(int fd, void*data, size_t size, int *type); ssize_t pa_loop_write(int fd, const void*data, size_t size, int *type); +int pa_close(int fd); + void pa_check_signal_is_blocked(int sig); char *pa_sprintf_malloc(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c index 2f6fdd39..6f58ae75 100644 --- a/src/pulsecore/iochannel.c +++ b/src/pulsecore/iochannel.c @@ -4,7 +4,7 @@ This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering - Copyright 2006 Pierre Ossman for Cendio AB + Copyright 2006-2007 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -174,10 +174,9 @@ void pa_iochannel_free(pa_iochannel*io) { if (!io->no_close) { if (io->ifd >= 0) - - close(io->ifd); + pa_close(io->ifd); if (io->ofd >= 0 && io->ofd != io->ifd) - close(io->ofd); + pa_close(io->ofd); } pa_xfree(io); diff --git a/src/pulsecore/pipe.c b/src/pulsecore/pipe.c index a659915e..7f6bb2e9 100644 --- a/src/pulsecore/pipe.c +++ b/src/pulsecore/pipe.c @@ -3,7 +3,7 @@ /*** This file is part of PulseAudio. - Copyright 2006 Pierre Ossman for Cendio AB + Copyright 2006-2007 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published @@ -144,17 +144,17 @@ int pipe(int filedes[2]) { if ((addr.sin_port != peer.sin_port) || (addr.sin_addr.s_addr != peer.sin_addr.s_addr)) goto error; - close(listener); + pa_close(listener); return 0; error: if (listener >= 0) - close(listener); + pa_close(listener); if (filedes[0] >= 0) - close(filedes[0]); + pa_close(filedes[0]); if (filedes[1] >= 0) - close(filedes[0]); + pa_close(filedes[0]); return -1; } diff --git a/src/pulsecore/socket-client.c b/src/pulsecore/socket-client.c index 4ea81113..b99c8025 100644 --- a/src/pulsecore/socket-client.c +++ b/src/pulsecore/socket-client.c @@ -4,7 +4,7 @@ This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering - Copyright 2006 Pierre Ossman for Cendio AB + Copyright 2006-2007 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -163,7 +163,7 @@ static void do_call(pa_socket_client *c) { finish: if (!io && c->fd >= 0) - close(c->fd); + pa_close(c->fd); c->fd = -1; free_events(c); @@ -310,7 +310,7 @@ static void socket_client_free(pa_socket_client *c) { free_events(c); if (c->fd >= 0) - close(c->fd); + pa_close(c->fd); #ifdef HAVE_LIBASYNCNS if (c->asyncns_query) @@ -403,7 +403,7 @@ static void timeout_cb(pa_mainloop_api *m, pa_time_event *e, const struct timeva assert(c); if (c->fd >= 0) { - close(c->fd); + pa_close(c->fd); c->fd = -1; } diff --git a/src/pulsecore/socket-server.c b/src/pulsecore/socket-server.c index eaa8eb91..b5a6dc31 100644 --- a/src/pulsecore/socket-server.c +++ b/src/pulsecore/socket-server.c @@ -4,7 +4,7 @@ This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering - Copyright 2006 Pierre Ossman for Cendio AB + Copyright 2006-2007 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published @@ -106,7 +106,7 @@ static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_U pa_fd_set_cloexec(nfd, 1); if (!s->on_connection) { - close(nfd); + pa_close(nfd); goto finish; } @@ -119,7 +119,7 @@ static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_U fromhost(&req); if (!hosts_access(&req)) { pa_log_warn("TCP connection refused by tcpwrap."); - close(nfd); + pa_close(nfd); goto finish; } @@ -216,7 +216,7 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file fail: if (fd >= 0) - close(fd); + pa_close(fd); return NULL; } @@ -275,7 +275,7 @@ pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address fail: if (fd >= 0) - close(fd); + pa_close(fd); return NULL; } @@ -331,7 +331,7 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad fail: if (fd >= 0) - close(fd); + pa_close(fd); return NULL; } @@ -398,7 +398,7 @@ static void socket_server_free(pa_socket_server*s) { pa_xfree(s->filename); } - close(s->fd); + pa_close(s->fd); pa_xfree(s->tcpwrap_service); diff --git a/src/pulsecore/socket-util.c b/src/pulsecore/socket-util.c index 5e2cfe03..673058e2 100644 --- a/src/pulsecore/socket-util.c +++ b/src/pulsecore/socket-util.c @@ -5,7 +5,7 @@ Copyright 2004-2006 Lennart Poettering Copyright 2004 Joe Marcus Clarke - Copyright 2006 Pierre Ossman for Cendio AB + Copyright 2006-2007 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published @@ -236,7 +236,7 @@ int pa_unix_socket_is_stale(const char *fn) { finish: if (fd >= 0) - close(fd); + pa_close(fd); return ret; } -- cgit From 6ba21d4a0bdc031162a1755a15d5a2088a04fb2f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 1 Mar 2007 17:11:10 +0000 Subject: Add some debugging output from sample cache subsystem. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1430 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/core-scache.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/pulsecore/core-scache.c b/src/pulsecore/core-scache.c index 75fb47f0..cb272784 100644 --- a/src/pulsecore/core-scache.c +++ b/src/pulsecore/core-scache.c @@ -138,6 +138,7 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx) { pa_scache_entry *e; + char st[PA_SAMPLE_SPEC_SNPRINT_MAX]; assert(c && name); if (chunk && chunk->length > PA_SCACHE_ENTRY_SIZE_MAX) @@ -163,6 +164,10 @@ int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, c if (idx) *idx = e->index; + pa_log_debug("created sample \"%s\" (#%d), %d bytes with sample spec %s", + name, e->index, e->memchunk.length, + pa_sample_spec_snprint(st, sizeof(st), &e->sample_spec)); + return 0; } @@ -229,7 +234,10 @@ int pa_scache_remove_item(pa_core *c, const char *name) { if (pa_idxset_remove_by_data(c->scache, e, NULL) != e) assert(0); + pa_log_debug("removed sample \"%s\"", name); + free_entry(e); + return 0; } @@ -276,6 +284,8 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t if (!e->memchunk.memblock) return -1; + pa_log_debug("playing sample \"%s\" on \"%s\"", name, sink->name); + t = pa_sprintf_malloc("sample:%s", name); pa_cvolume_set(&r, e->volume.channels, volume); -- cgit From bb812433a8847704ab7681aad812558439e176ee Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 1 Mar 2007 17:13:26 +0000 Subject: Handle when ALSA tweaks our sample spec so much that the frame size changes. (closes #57). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1431 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 6 ++++-- configure.ac | 1 + src/modules/module-alsa-sink.c | 9 ++++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index 1b77187d..765e8fa4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,8 +17,8 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -EXTRA_DIST = bootstrap.sh LICENSE GPL LGPL doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in README todo -SUBDIRS=libltdl src doxygen +EXTRA_DIST = config.rpath m4/ChangeLog bootstrap.sh LICENSE GPL LGPL doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in README todo +SUBDIRS= libltdl src doxygen MAINTAINERCLEANFILES = noinst_DATA = @@ -46,3 +46,5 @@ doxygen: $(MAKE) -C doxygen doxygen .PHONY: homepage distcleancheck doxygen + +ACLOCAL_AMFLAGS = -I m4 diff --git a/configure.ac b/configure.ac index 65a99a00..68ad6727 100644 --- a/configure.ac +++ b/configure.ac @@ -772,6 +772,7 @@ AM_CONDITIONAL([FORCE_PREOPEN], [test "x$FORCE_PREOPEN" = "x1"]) AC_CONFIG_FILES([ Makefile src/Makefile +po/Makefile.in libpulse.pc libpulse-simple.pc libpulse-browse.pc diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 74a57f37..6f8f270d 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -159,7 +159,11 @@ static void do_write(struct userdata *u) { memchunk = &u->memchunk; } - assert(memchunk->memblock && memchunk->memblock->data && memchunk->length && memchunk->memblock->length && (memchunk->length % u->frame_size) == 0); + assert(memchunk->memblock); + assert(memchunk->memblock->data); + assert(memchunk->length); + assert(memchunk->memblock->length); + assert((memchunk->length % u->frame_size) == 0); if ((frames = snd_pcm_writei(u->pcm_handle, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length / u->frame_size)) < 0) { if (frames == -EAGAIN) @@ -415,6 +419,9 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } + /* ALSA might tweak the sample spec, so recalculate the frame size */ + frame_size = pa_frame_size(&ss); + if (ss.channels != map.channels) /* Seems ALSA didn't like the channel number, so let's fix the channel map */ pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); -- cgit From 19b17ff50447875d55ef4c819fd0f3c45537cce9 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 1 Mar 2007 17:15:43 +0000 Subject: Revert stuff from commit 1431 that wasn't supposed to be there. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1432 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 6 ++---- configure.ac | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Makefile.am b/Makefile.am index 765e8fa4..1b77187d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,8 +17,8 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -EXTRA_DIST = config.rpath m4/ChangeLog bootstrap.sh LICENSE GPL LGPL doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in README todo -SUBDIRS= libltdl src doxygen +EXTRA_DIST = bootstrap.sh LICENSE GPL LGPL doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in README todo +SUBDIRS=libltdl src doxygen MAINTAINERCLEANFILES = noinst_DATA = @@ -46,5 +46,3 @@ doxygen: $(MAKE) -C doxygen doxygen .PHONY: homepage distcleancheck doxygen - -ACLOCAL_AMFLAGS = -I m4 diff --git a/configure.ac b/configure.ac index 68ad6727..65a99a00 100644 --- a/configure.ac +++ b/configure.ac @@ -772,7 +772,6 @@ AM_CONDITIONAL([FORCE_PREOPEN], [test "x$FORCE_PREOPEN" = "x1"]) AC_CONFIG_FILES([ Makefile src/Makefile -po/Makefile.in libpulse.pc libpulse-simple.pc libpulse-browse.pc -- cgit From 2b82336df2eb8cf1c9ae150b1850540a88f68ecf Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 2 Mar 2007 09:20:54 +0000 Subject: Handle suspended alsa devices. Based on patch by ranma. (closes #26) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1433 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-sink.c | 38 ++++++++++++++++++++++++++++++++++++++ src/modules/module-alsa-source.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 6f8f270d..3d9f7577 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -141,6 +141,33 @@ static int xrun_recovery(struct userdata *u) { return ret; } +static int suspend_recovery(struct userdata *u) { + int ret; + assert(u); + + pa_log_info("*** ALSA-SUSPEND (playback) ***"); + + if ((ret = snd_pcm_resume(u->pcm_handle)) < 0) { + if (ret == -EAGAIN) + return -1; + + if (ret != -ENOSYS) + pa_log("snd_pcm_resume() failed: %s", snd_strerror(-ret)); + else { + if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) + pa_log("snd_pcm_prepare() failed: %s", snd_strerror(-ret)); + } + + if (ret < 0) { + clear_up(u); + pa_module_unload_request(u->module); + return -1; + } + } + + return ret; +} + static void do_write(struct userdata *u) { assert(u); @@ -176,6 +203,13 @@ static void do_write(struct userdata *u) { continue; } + if (frames == -ESTRPIPE) { + if (suspend_recovery(u) < 0) + return; + + continue; + } + pa_log("snd_pcm_writei() failed: %s", snd_strerror(-frames)); clear_up(u); @@ -207,6 +241,10 @@ static void fdl_callback(void *userdata) { if (xrun_recovery(u) < 0) return; + if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_SUSPENDED) + if (suspend_recovery(u) < 0) + return; + do_write(u); } diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 2ea551cb..4061d668 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -143,6 +143,34 @@ static int xrun_recovery(struct userdata *u) { return 0; } + +static int suspend_recovery(struct userdata *u) { + int ret; + assert(u); + + pa_log_info("*** ALSA-SUSPEND (capture) ***"); + + if ((ret = snd_pcm_resume(u->pcm_handle)) < 0) { + if (ret == -EAGAIN) + return -1; + + if (ret != -ENOSYS) + pa_log("snd_pcm_resume() failed: %s", snd_strerror(-ret)); + else { + if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) + pa_log("snd_pcm_prepare() failed: %s", snd_strerror(-ret)); + } + + if (ret < 0) { + clear_up(u); + pa_module_unload_request(u->module); + return -1; + } + } + + return ret; +} + static void do_read(struct userdata *u) { assert(u); @@ -175,6 +203,13 @@ static void do_read(struct userdata *u) { continue; } + if (frames == -ESTRPIPE) { + if (suspend_recovery(u) < 0) + return; + + continue; + } + pa_log("snd_pcm_readi() failed: %s", snd_strerror(-frames)); clear_up(u); @@ -210,6 +245,10 @@ static void fdl_callback(void *userdata) { if (xrun_recovery(u) < 0) return; + if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_SUSPENDED) + if (suspend_recovery(u) < 0) + return; + do_read(u); } -- cgit From 0b14c026890ee6806971d179a66aee5b03e1d763 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 6 Mar 2007 13:31:29 +0000 Subject: Don't fail if hal doesn't currently contain any devices. (closes #55) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1434 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-hal-detect.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index 56a3efc1..a28b6f0d 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -488,7 +488,6 @@ fail: } int pa__init(pa_core *c, pa_module*m) { - int n; DBusError error; pa_dbus_connection *conn; struct userdata *u = NULL; @@ -519,16 +518,11 @@ int pa__init(pa_core *c, pa_module*m) { m->userdata = (void*) u; #ifdef HAVE_ALSA - if ((n = hal_device_add_all(u, CAP_ALSA)) <= 0) + hal_device_add_all(u, CAP_ALSA); #endif #ifdef HAVE_OSS - if ((n = hal_device_add_all(u, CAP_OSS)) <= 0) + hal_device_add_all(u, CAP_OSS); #endif - { - pa_log_warn("failed to detect any sound hardware."); - userdata_free(u); - return -1; - } libhal_ctx_set_user_data(hal_ctx, (void*) u); libhal_ctx_set_device_added(hal_ctx, device_added_cb); -- cgit From e042a90a53b7c7b387e3acd06a23638f4826c30f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 6 Mar 2007 13:42:30 +0000 Subject: Pulsecore should be linked into all modules. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1435 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index 0b509ac9..7ee5354a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1149,7 +1149,7 @@ module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA module_x11_publish_la_SOURCES = modules/module-x11-publish.c module_x11_publish_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) module_x11_publish_la_LDFLAGS = -module -avoid-version -module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la libauthkey.la libauthkey-prop.la libx11prop.la libstrlist.la +module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la libauthkey.la libauthkey-prop.la libx11prop.la libstrlist.la libpulsecore.la # OSS -- cgit From f6023cb5ee2c6562c7a47d96828a80a64e3ea59c Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 6 Mar 2007 15:47:11 +0000 Subject: Fix some instances where we printed a string without first checking that the pointer was valid. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1436 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/cli-command.c | 7 +++++-- src/pulsecore/cli-text.c | 13 ++++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index aa2beba2..e87b257b 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -246,6 +246,7 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G char s[256]; const pa_mempool_stat *stat; unsigned k; + const char *def_sink, *def_source; static const char* const type_table[PA_MEMBLOCK_TYPE_MAX] = { [PA_MEMBLOCK_POOL] = "POOL", @@ -283,10 +284,12 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G pa_strbuf_printf(buf, "Default sample spec: %s\n", pa_sample_spec_snprint(s, sizeof(s), &c->default_sample_spec)); + def_sink = pa_namereg_get_default_sink_name(c); + def_source = pa_namereg_get_default_source_name(c); pa_strbuf_printf(buf, "Default sink name: %s\n" "Default source name: %s\n", - pa_namereg_get_default_sink_name(c), - pa_namereg_get_default_source_name(c)); + def_sink ? def_sink : "none", + def_source ? def_source : "none"); for (k = 0; k < PA_MEMBLOCK_TYPE_MAX; k++) pa_strbuf_printf(buf, diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index e97f0574..413f9334 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -55,8 +55,15 @@ char *pa_module_list_to_string(pa_core *c) { pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_size(c->modules)); - for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) - pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\targument: <%s>\n\tused: %i\n\tauto unload: %s\n", m->index, m->name, m->argument, m->n_used, m->auto_unload ? "yes" : "no"); + for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) { + pa_strbuf_printf(s, " index: %u\n" + "\tname: <%s>\n" + "\targument: <%s>\n" + "\tused: %i\n" + "\tauto unload: %s\n", + m->index, m->name, m->argument ? m->argument : "", m->n_used, + m->auto_unload ? "yes" : "no"); + } return pa_strbuf_tostring_free(s); } @@ -337,7 +344,7 @@ char *pa_autoload_list_to_string(pa_core *c) { e->type == PA_NAMEREG_SOURCE ? "source" : "sink", e->index, e->module, - e->argument); + e->argument ? e->argument : ""); } } -- cgit From 9ee398107e524ca71a0cfd23e003daa300d1e227 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 7 Mar 2007 09:27:30 +0000 Subject: Add support for SNDCTL_DSP_SETTRIGGER. (closes #56) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1437 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 87 insertions(+), 9 deletions(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 444e1b4d..fddd8fb4 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -4,7 +4,7 @@ This file is part of PulseAudio. Copyright 2006 Lennart Poettering - Copyright 2006 Pierre Ossman for Cendio AB + Copyright 2006-2007 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published @@ -84,6 +84,8 @@ struct fd_info { pa_context *context; pa_stream *play_stream; pa_stream *rec_stream; + int play_precork; + int rec_precork; pa_io_event *io_event; pa_io_event_flags_t io_flags; @@ -197,7 +199,7 @@ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY) { \ debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ goto label; \ } \ -} while(0); +} while(0) #define PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, label) do { \ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ @@ -205,7 +207,7 @@ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ goto label; \ } \ -} while(0); +} while(0) #define RECORD_STREAM_CHECK_DEAD_GOTO(i, label) do { \ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ @@ -213,7 +215,7 @@ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \ goto label; \ } \ -} while(0); +} while(0) static void debug(int level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); @@ -572,6 +574,8 @@ static fd_info* fd_info_new(fd_info_type_t type, int *_errno) { i->context = NULL; i->play_stream = NULL; i->rec_stream = NULL; + i->play_precork = 0; + i->rec_precork = 0; i->io_event = NULL; i->io_flags = 0; pthread_mutex_init(&i->mutex, NULL); @@ -937,7 +941,7 @@ static void stream_state_cb(pa_stream *s, void * userdata) { static int create_playback_stream(fd_info *i) { pa_buffer_attr attr; - int n; + int n, flags; assert(i); @@ -958,7 +962,12 @@ static int create_playback_stream(fd_info *i) { attr.prebuf = i->fragment_size; attr.minreq = i->fragment_size; - if (pa_stream_connect_playback(i->play_stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) { + flags = PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE; + if (i->play_precork) { + flags |= PA_STREAM_START_CORKED; + debug(DEBUG_LEVEL_NORMAL, __FILE__": creating stream corked\n"); + } + if (pa_stream_connect_playback(i->play_stream, NULL, &attr, flags, NULL, NULL) < 0) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -976,7 +985,7 @@ fail: static int create_record_stream(fd_info *i) { pa_buffer_attr attr; - int n; + int n, flags; assert(i); @@ -995,7 +1004,12 @@ static int create_record_stream(fd_info *i) { attr.maxlength = i->fragment_size * (i->n_fragments+1); attr.fragsize = i->fragment_size; - if (pa_stream_connect_record(i->rec_stream, NULL, &attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE) < 0) { + flags = PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE; + if (i->rec_precork) { + flags |= PA_STREAM_START_CORKED; + debug(DEBUG_LEVEL_NORMAL, __FILE__": creating stream corked\n"); + } + if (pa_stream_connect_record(i->rec_stream, NULL, &attr, flags) < 0) { debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_record() failed: %s\n", pa_strerror(pa_context_errno(i->context))); goto fail; } @@ -1800,6 +1814,44 @@ fail: return 0; } +static int dsp_cork(fd_info *i, pa_stream *s, int b) { + pa_operation *o = NULL; + int r = -1; + + pa_threaded_mainloop_lock(i->mainloop); + + if (!(o = pa_stream_cork(s, b, stream_success_cb, i))) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_cork(): %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + i->operation_success = 0; + while (!pa_operation_get_state(o) != PA_OPERATION_DONE) { + if (s == i->play_stream) + PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, fail); + else if (s == i->rec_stream) + RECORD_STREAM_CHECK_DEAD_GOTO(i, fail); + + pa_threaded_mainloop_wait(i->mainloop); + } + + if (!i->operation_success) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_cork(): %s\n", pa_strerror(pa_context_errno(i->context))); + goto fail; + } + + r = 0; + +fail: + + if (o) + pa_operation_unref(o); + + pa_threaded_mainloop_unlock(i->mainloop); + + return 0; +} + static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) { int ret = -1; @@ -1929,7 +1981,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_GETCAPS: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CAPS\n"); - *(int*) argp = DSP_CAP_DUPLEX + *(int*) argp = DSP_CAP_DUPLEX | DSP_CAP_TRIGGER #ifdef DSP_CAP_MULTI | DSP_CAP_MULTI #endif @@ -2009,6 +2061,32 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) *_errno = EIO; break; + case SNDCTL_DSP_SETTRIGGER: + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETTRIGGER: 0x%08x\n", *(int*) argp); + + if (!i->io_event) { + *_errno = EIO; + break; + } + + i->play_precork = !((*(int*) argp) & PCM_ENABLE_OUTPUT); + + if (i->play_stream) { + if (dsp_cork(i, i->play_stream, !((*(int*) argp) & PCM_ENABLE_OUTPUT)) < 0) + *_errno = EIO; + if (dsp_trigger(i) < 0) + *_errno = EIO; + } + + i->rec_precork = !((*(int*) argp) & PCM_ENABLE_INPUT); + + if (i->rec_stream) { + if (dsp_cork(i, i->rec_stream, !((*(int*) argp) & PCM_ENABLE_INPUT)) < 0) + *_errno = EIO; + } + + break; + case SNDCTL_DSP_SYNC: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SYNC\n"); -- cgit From 16dd5f78729578257dcde66e08393a59114a7402 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 22 May 2007 23:08:34 +0000 Subject: fix comment git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1438 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/g711.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/g711.h b/src/pulsecore/g711.h index b5c9e6a2..37ebcf72 100644 --- a/src/pulsecore/g711.h +++ b/src/pulsecore/g711.h @@ -13,7 +13,7 @@ ** implied warranty. */ -/** Copied from sox -- Lennart Poettring*/ +/** Copied from sox -- Lennart Poettering */ #include -- cgit From e41b91eec984c2ff61222d56872e9c3966a87375 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 22 May 2007 23:37:27 +0000 Subject: drop unused variable git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1439 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/tests/flist-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/flist-test.c b/src/tests/flist-test.c index 17ba55c1..7e54454e 100644 --- a/src/tests/flist-test.c +++ b/src/tests/flist-test.c @@ -54,7 +54,7 @@ static void thread_func(void *data) { int b = 1; while (!quit) { - char *text, *t; + char *text; /* Allocate some memory, if possible take it from the flist */ if (b && (text = pa_flist_pop(flist))) -- cgit From 960b5cbd10105df4cd6320e005b73e3c9aa32cc6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 22 May 2007 23:38:22 +0000 Subject: Fix build and only load OSS xor ALSA modules if both are available git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1440 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-hal-detect.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index a28b6f0d..27cd449e 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -85,6 +85,9 @@ struct userdata { capability_t capability; pa_dbus_connection *conn; pa_hashmap *devices; +#if defined(HAVE_ALSA) && defined(HAVE_OSS) + int use_oss; +#endif }; struct timerdata { @@ -185,6 +188,8 @@ static pa_module* hal_device_load_alsa(struct userdata *u, const char *udi, snprintf(args, sizeof(args), "device=hw:%u source_name=alsa_input.%s", card, strip_udi(udi)); } + pa_log_debug("Loading %s with arguments '%s'", module_name, args); + return pa_module_load(u->core, module_name, args); } @@ -242,6 +247,8 @@ static pa_module* hal_device_load_oss(struct userdata *u, const char *udi, snprintf(args, sizeof(args), "device=%s sink_name=oss_output.%s source_name=oss_input.%s", device, strip_udi(udi), strip_udi(udi)); libhal_free_string(device); + pa_log_debug("Loading module-oss with arguments '%s'", args); + return pa_module_load(u->core, "module-oss", args); } #endif @@ -249,7 +256,7 @@ static pa_module* hal_device_load_oss(struct userdata *u, const char *udi, static dbus_bool_t hal_device_add(struct userdata *u, const char *udi, DBusError *error) { - pa_module* m; + pa_module* m = NULL; struct device *d; switch(u->capability) { @@ -260,7 +267,10 @@ static dbus_bool_t hal_device_add(struct userdata *u, const char *udi, #endif #ifdef HAVE_OSS case CAP_OSS: - m = hal_device_load_oss(u, udi, error); +#ifdef HAVE_ALSA + if (u->use_oss) +#endif + m = hal_device_load_oss(u, udi, error); break; #endif default: @@ -492,6 +502,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_dbus_connection *conn; struct userdata *u = NULL; LibHalContext *hal_ctx = NULL; + int n = 0; assert(c); assert(m); @@ -518,13 +529,26 @@ int pa__init(pa_core *c, pa_module*m) { m->userdata = (void*) u; #ifdef HAVE_ALSA - hal_device_add_all(u, CAP_ALSA); + n = hal_device_add_all(u, CAP_ALSA); #endif +#if defined(HAVE_ALSA) && defined(HAVE_OSS) + u->use_oss = 0; + + if (n <= 0) { +#endif #ifdef HAVE_OSS - hal_device_add_all(u, CAP_OSS); + n += hal_device_add_all(u, CAP_OSS); #endif +#if defined(HAVE_ALSA) && defined(HAVE_OSS) + + /* We found something with OSS, but didn't find anything with + * ALSA. Then let's use only OSS from now on. */ + if (n > 0) + u->use_oss = 1; + } +#endif - libhal_ctx_set_user_data(hal_ctx, (void*) u); + libhal_ctx_set_user_data(hal_ctx, u); libhal_ctx_set_device_added(hal_ctx, device_added_cb); libhal_ctx_set_device_removed(hal_ctx, device_removed_cb); libhal_ctx_set_device_new_capability(hal_ctx, new_capability_cb); -- cgit From 01ddb5488982e1ee78eee381f707e3a066f91c43 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 22 May 2007 23:39:47 +0000 Subject: show socket directory when we fail to create it. (Closes #85) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1441 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-protocol-stub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index 4728f750..5c8733fb 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -271,7 +271,7 @@ int pa__init(pa_core *c, pa_module*m) { * /tmp/.esd/, hence we have to create the dir first */ if (pa_make_secure_parent_dir(u->socket_path, c->is_system_instance ? 0755 : 0700, (uid_t)-1, (gid_t)-1) < 0) { - pa_log("Failed to create socket directory: %s\n", pa_cstrerror(errno)); + pa_log("Failed to create socket directory '%s': %s\n", u->socket_path, pa_cstrerror(errno)); goto fail; } #endif -- cgit From 312c326def9b4cc20642ea8f2692d4f2da1406ad Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 May 2007 01:02:06 +0000 Subject: Fix module-oss for devices that return EAGAIN when we don't expect it. (Closes #66) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1442 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 965944a7..22b12ef7 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -169,10 +169,14 @@ static void do_write(struct userdata *u) { assert(memchunk->length); if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { - pa_log("write() failed: %s", pa_cstrerror(errno)); - clear_up(u); - pa_module_unload_request(u->module); + if (errno != EAGAIN) { + pa_log("write() failed: %s", pa_cstrerror(errno)); + + clear_up(u); + pa_module_unload_request(u->module); + } + break; } @@ -224,11 +228,14 @@ static void do_read(struct userdata *u) { assert(memchunk.memblock); if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); + if (errno != EAGAIN) { pa_log("read() failed: %s", pa_cstrerror(errno)); + clear_up(u); pa_module_unload_request(u->module); } + break; } -- cgit From 0e53f939c011a5f2ebc15658029f0a578e0bd68f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 May 2007 12:32:37 +0000 Subject: Treat empty :0.0 identically to unset :0.0 when trying to find a PA server. (Closes #87) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1443 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/client-conf-x11.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulse/client-conf-x11.c b/src/pulse/client-conf-x11.c index b5ac8d9f..e8de9553 100644 --- a/src/pulse/client-conf-x11.c +++ b/src/pulse/client-conf-x11.c @@ -44,7 +44,7 @@ int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) { int ret = -1; char t[1024]; - if (!dname && !getenv("DISPLAY")) + if (!dname && (!(dname = getenv("DISPLAY")) || *dname == '\0')) goto finish; if (!(d = XOpenDisplay(dname))) { -- cgit From 8e738ede9b2050a29400d4218b96b68863290857 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 May 2007 15:30:34 +0000 Subject: fix a few obvious copynpaste errors when handling volumes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1444 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index fddd8fb4..0ac48254 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1511,14 +1511,14 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno case SOUND_MIXER_WRITE_IGAIN: { pa_cvolume v, *pv; - if (request == SOUND_MIXER_READ_PCM) + if (request == SOUND_MIXER_WRITE_PCM) debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_PCM\n"); else debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_IGAIN\n"); pa_threaded_mainloop_lock(i->mainloop); - if (request == SOUND_MIXER_READ_PCM) { + if (request == SOUND_MIXER_WRITE_PCM) { v = i->sink_volume; pv = &i->sink_volume; } else { @@ -1532,7 +1532,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno if (!pa_cvolume_equal(pv, &v)) { pa_operation *o; - if (request == SOUND_MIXER_READ_PCM) + if (request == SOUND_MIXER_WRITE_PCM) o = pa_context_set_sink_volume_by_index(i->context, i->sink_index, pv, context_success_cb, i); else o = pa_context_set_source_volume_by_index(i->context, i->source_index, pv, context_success_cb, i); -- cgit From 407a1b6efe059797fcbf583007de411321ed76b7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 May 2007 16:24:54 +0000 Subject: fix a DoS vulnerability (re #67), originally identified by Luigi Auriemma git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1445 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/pstream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index 3398df0d..dbee7763 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -632,7 +632,7 @@ static int do_read(pa_pstream *p) { flags = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]); - if (!p->import && (flags & PA_FLAG_SHMMASK) != 0) { + if (!p->use_shm && (flags & PA_FLAG_SHMMASK) != 0) { pa_log_warn("Recieved SHM frame on a socket where SHM is disabled."); return -1; } -- cgit From f90339528b5f72aabf0008b83ff25bd6b78d05a0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 May 2007 16:29:18 +0000 Subject: Fix another DoS vulnerability, also identified Luigi Auriemma (closes #67) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1446 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/pstream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index dbee7763..897e4295 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -662,7 +662,7 @@ static int do_read(pa_pstream *p) { length = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]); - if (length > FRAME_SIZE_MAX_ALLOW) { + if (length > FRAME_SIZE_MAX_ALLOW || length <= 0) { pa_log_warn("Recieved invalid frame size : %lu", (unsigned long) length); return -1; } -- cgit From c3b5de77bc2cacc4aa94b1ee982c93222eb9261c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 May 2007 16:30:57 +0000 Subject: fix minor typo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1447 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/pstream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index 897e4295..fdb1a66a 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -663,7 +663,7 @@ static int do_read(pa_pstream *p) { length = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]); if (length > FRAME_SIZE_MAX_ALLOW || length <= 0) { - pa_log_warn("Recieved invalid frame size : %lu", (unsigned long) length); + pa_log_warn("Recieved invalid frame size: %lu", (unsigned long) length); return -1; } -- cgit From cf925b10e157c0ae87ff876dd8047586226afa87 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 May 2007 16:42:26 +0000 Subject: Fix yet another DoS vulnerability, also identified Luigi Auriemma (re #67) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1448 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-native.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 4e861f85..774f6918 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -763,7 +763,8 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, maxlength > 0 && maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); - + CHECK_VALIDITY(c->pstream, maxlength >= pa_frame_size(&ss), tag, PA_ERR_INVALID); + if (sink_index != PA_INVALID_INDEX) { sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); -- cgit From 4a05bc9bdcb4404f3e23cef367ff378b9e39d220 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 May 2007 16:57:35 +0000 Subject: don't allow excessively high sample rates git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1449 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/sample.c | 1 + src/pulse/sample.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/pulse/sample.c b/src/pulse/sample.c index aafafc83..ffdeedf7 100644 --- a/src/pulse/sample.c +++ b/src/pulse/sample.c @@ -80,6 +80,7 @@ int pa_sample_spec_valid(const pa_sample_spec *spec) { assert(spec); if (spec->rate <= 0 || + spec->rate > PA_RATE_MAX || spec->channels <= 0 || spec->channels > PA_CHANNELS_MAX || spec->format >= PA_SAMPLE_MAX || diff --git a/src/pulse/sample.h b/src/pulse/sample.h index 5e603685..683167cc 100644 --- a/src/pulse/sample.h +++ b/src/pulse/sample.h @@ -105,6 +105,9 @@ PA_C_DECL_BEGIN /** Maximum number of allowed channels */ #define PA_CHANNELS_MAX 32 +/** Maximum allowed sample rate */ +#define PA_RATE_MAX (48000*4) + /** Sample format */ typedef enum pa_sample_format { PA_SAMPLE_U8, /**< Unsigned 8 Bit PCM */ -- cgit From 33304ba1181bde267c8a54f6587778fe0cfd28b6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 May 2007 16:59:03 +0000 Subject: Fix a DoS with allocating overly large silence buffers. (Identified by Luigi Auriemma (re #67) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1450 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/sample-util.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index 411787af..c8e7acf0 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -38,13 +38,25 @@ #include "sample-util.h" #include "endianmacros.h" +#define PA_SILENCE_MAX (1024*1024*1) + pa_memblock *pa_silence_memblock_new(pa_mempool *pool, const pa_sample_spec *spec, size_t length) { + size_t fs; assert(pool); assert(spec); if (length == 0) length = pa_bytes_per_second(spec)/20; /* 50 ms */ + if (length > PA_SILENCE_MAX) + length = PA_SILENCE_MAX; + + fs = pa_frame_size(spec); + length = ((PA_SILENCE_MAX+fs-1) / fs) * fs; + + if (length <= 0) + length = fs; + return pa_silence_memblock(pa_memblock_new(pool, length), spec); } -- cgit From 30c52e56c34268d992384aa0cd3370150d90ec43 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 May 2007 17:12:07 +0000 Subject: add a missing initialization that causes a crash when parsing invalid volume restoration tables (Problem identified by Luigi Auriemma, re #67) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1451 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-volume-restore.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index 0df270df..61a17aef 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -435,6 +435,7 @@ int pa__init(pa_core *c, pa_module*m) { u->subscription = NULL; u->table_file = pa_xstrdup(pa_modargs_get_value(ma, "table", NULL)); u->modified = 0; + u->sink_input_hook_slot = u->source_output_hook_slot = NULL; m->userdata = u; -- cgit From 79c94db7a62773c2b7ba428a0f4275ca23441a62 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 May 2007 17:24:06 +0000 Subject: Fix another DoS vulnerability that has been identified by Luigi Auriemma. (Finally closes #67) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1452 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/rtp/sap.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c index f61c0efe..a6e92187 100644 --- a/src/modules/rtp/sap.c +++ b/src/modules/rtp/sap.c @@ -144,9 +144,6 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) { goto fail; } - if (!size) - return 0; - buf = pa_xnew(char, size+1); buf[size] = 0; -- cgit From 003264213cd8e5e6535ed3cf672a78b27055bf28 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 May 2007 23:38:28 +0000 Subject: only browse for ipv4 pa servers for now. Needs better fixing which however is not trivial and probably breaks the API git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1453 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/browser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulse/browser.c b/src/pulse/browser.c index 27c5a2ea..ea2706e4 100644 --- a/src/pulse/browser.c +++ b/src/pulse/browser.c @@ -337,7 +337,7 @@ pa_browser *pa_browser_new_full(pa_mainloop_api *mainloop, pa_browse_flags_t fla !(b->server_browser = avahi_service_browser_new( b->client, AVAHI_IF_UNSPEC, - AVAHI_PROTO_UNSPEC, + AVAHI_PROTO_INET, SERVICE_TYPE_SERVER, NULL, 0, -- cgit From 65e87616833252884e4ab6b87373f98939fc446a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 25 May 2007 20:24:55 +0000 Subject: fix suid Makefile target git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1454 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 7ee5354a..e05b5364 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1283,9 +1283,9 @@ gconf_helper_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) # Some minor stuff # ################################### -suid: pulse - chown root $< - chmod u+s $< +suid: pulseaudio .libs/lt-pulseaudio + chown root $^ + chmod u+s $^ CLEANFILES = esdcompat client.conf default.pa daemon.conf -- cgit From 4d88fcd59da84ac4f09113855c8f15384a4e05c3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 25 May 2007 20:35:30 +0000 Subject: when called with the setid bit change euid to uid sooner to make sure that we can access our own files even when we dropped most capabilities. (Closes #21) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1455 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/caps.c | 33 +++++++++++++++------------------ src/daemon/main.c | 29 ++++++++++++++++++----------- src/pulsecore/core-util.c | 36 +++++++++++++++++++++++++++++++++--- 3 files changed, 66 insertions(+), 32 deletions(-) diff --git a/src/daemon/caps.c b/src/daemon/caps.c index 2ea51c9f..8043230c 100644 --- a/src/daemon/caps.c +++ b/src/daemon/caps.c @@ -35,6 +35,9 @@ #ifdef HAVE_SYS_CAPABILITY_H #include #endif +#ifdef HAVE_SYS_PRCTL_H +#include +#endif #include @@ -76,35 +79,31 @@ void pa_drop_root(void) { #endif -#ifdef HAVE_SYS_CAPABILITY_H +#if defined(HAVE_SYS_CAPABILITY_H) && defined(HAVE_SYS_PRCTL_H) -/* Limit capabilities set to CAPSYS_NICE */ +/* Limit permitted capabilities set to CAPSYS_NICE */ int pa_limit_caps(void) { int r = -1; cap_t caps; cap_value_t nice_cap = CAP_SYS_NICE; - /* Only drop caps when called SUID */ - if (getuid() == 0) - return 0; - caps = cap_init(); assert(caps); - cap_clear(caps); - - cap_set_flag(caps, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET); cap_set_flag(caps, CAP_PERMITTED, 1, &nice_cap, CAP_SET); if (cap_set_proc(caps) < 0) goto fail; + if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) + goto fail; + pa_log_info("dropped capabilities successfully."); - - r = 0; + + r = 1; fail: - cap_free (caps); + cap_free(caps); return r; } @@ -114,24 +113,22 @@ int pa_drop_caps(void) { cap_t caps; int r = -1; - /* Only drop caps when called SUID */ - if (getuid() == 0) - return 0; - caps = cap_init(); assert(caps); cap_clear(caps); + prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0); + if (cap_set_proc(caps) < 0) { pa_log("failed to drop capabilities: %s", pa_cstrerror(errno)); goto fail; } - + r = 0; fail: - cap_free (caps); + cap_free(caps); return r; } diff --git a/src/daemon/main.c b/src/daemon/main.c index 211dd30c..72e47975 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -329,22 +329,29 @@ int main(int argc, char *argv[]) { struct timeval tv; #endif - setlocale(LC_ALL, ""); - - pa_limit_caps(); - #ifdef HAVE_GETUID real_root = getuid() == 0; suid_root = !real_root && geteuid() == 0; +#else + real_root = 0; + suid_root = 0; +#endif + + if (suid_root) { + if (pa_limit_caps() > 0) + /* We managed to drop capabilities except the needed + * ones. Hence we can drop the uid. */ + pa_drop_root(); + } + + setlocale(LC_ALL, ""); if (suid_root && (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) <= 0 || gid >= 1000)) { pa_log_warn("WARNING: called SUID root, but not in group '"PA_REALTIME_GROUP"'."); + pa_drop_caps(); pa_drop_root(); + suid_root = real_root = 0; } -#else - real_root = 0; - suid_root = 0; -#endif LTDL_SET_PRELOADED_SYMBOLS(); @@ -381,10 +388,10 @@ int main(int argc, char *argv[]) { if (conf->high_priority && conf->cmd == PA_CMD_DAEMON) pa_raise_priority(); - pa_drop_caps(); - - if (suid_root) + if (suid_root) { + pa_drop_caps(); pa_drop_root(); + } if (conf->dl_search_path) lt_dlsetsearchpath(conf->dl_search_path); diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index cc0fb205..480ac3b7 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -51,6 +51,10 @@ #include #endif +#ifdef HAVE_SYS_CAPABILITY_H +#include +#endif + #ifdef HAVE_PTHREAD #include #endif @@ -481,7 +485,23 @@ char *pa_strlcpy(char *b, const char *s, size_t l) { sensible: set the nice level to -15 and enable realtime scheduling if supported.*/ void pa_raise_priority(void) { - +#if defined(HAVE_SYS_CAPABILITY_H) + cap_t caps; + + /* Temporarily acquire CAP_SYS_NICE in the effective set */ + if ((caps = cap_get_proc())) { + cap_t caps_new; + cap_value_t nice_cap = CAP_SYS_NICE; + + if ((caps_new = cap_dup(caps))) { + cap_set_flag(caps_new, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET); + cap_set_flag(caps_new, CAP_PERMITTED, 1, &nice_cap, CAP_SET); + cap_set_proc(caps_new); + cap_free(caps_new); + } + } +#endif + #ifdef HAVE_SYS_RESOURCE_H if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) pa_log_warn("setpriority(): %s", pa_cstrerror(errno)); @@ -495,13 +515,13 @@ void pa_raise_priority(void) { if (sched_getparam(0, &sp) < 0) { pa_log("sched_getparam(): %s", pa_cstrerror(errno)); - return; + goto fail; } sp.sched_priority = 1; if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) { pa_log_warn("sched_setscheduler(): %s", pa_cstrerror(errno)); - return; + goto fail; } pa_log_info("Successfully enabled SCHED_FIFO scheduling."); @@ -514,6 +534,16 @@ void pa_raise_priority(void) { else pa_log_info("Successfully gained high priority class."); #endif + +fail: + +#if defined(HAVE_SYS_CAPABILITY_H) + if (caps) { + /* Restore original caps */ + cap_set_proc(caps); + cap_free(caps); + } +#endif } /* Reset the priority to normal, inverting the changes made by pa_raise_priority() */ -- cgit From d949983845cdc514aebe08cf43cfc13c49495ea8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 26 May 2007 23:39:33 +0000 Subject: Add a new meta command ".ifexists" to the CLI language, to execute commands only if a specified file exists. Original patch from cjvdb. Closes #36 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1456 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/cli-command.c | 81 ++++++++++++++++++++++++++++++++++++++------- src/pulsecore/cli-command.h | 3 ++ src/pulsecore/pdispatch.c | 2 +- 3 files changed, 73 insertions(+), 13 deletions(-) diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index e87b257b..2755c5c9 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -63,9 +64,18 @@ struct command { unsigned args; }; -#define INCLUDE_META ".include" -#define FAIL_META ".fail" -#define NOFAIL_META ".nofail" +#define META_INCLUDE ".include" +#define META_FAIL ".fail" +#define META_NOFAIL ".nofail" +#define META_IFEXISTS ".ifexists" +#define META_ELSE ".else" +#define META_ENDIF ".endif" + +enum { + IFSTATE_NONE = -1, + IFSTATE_FALSE = 0, + IFSTATE_TRUE = 1, +}; /* Prototypes for all available commands */ static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); @@ -959,7 +969,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G return 0; } -int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { +int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *buf, int *fail, int *ifstate) { const char *cs; cs = s+strspn(s, whitespace); @@ -967,19 +977,50 @@ int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int * if (*cs == '#' || !*cs) return 0; else if (*cs == '.') { - if (!strcmp(cs, FAIL_META)) + if (!strcmp(cs, META_ELSE)) { + if (!ifstate || *ifstate == IFSTATE_NONE) { + pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs); + return -1; + } else if (*ifstate == IFSTATE_TRUE) + *ifstate = IFSTATE_FALSE; + else + *ifstate = IFSTATE_TRUE; + return 0; + } else if (!strcmp(cs, META_ENDIF)) { + if (!ifstate || *ifstate == IFSTATE_NONE) { + pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs); + return -1; + } else + *ifstate = IFSTATE_NONE; + return 0; + } + if (ifstate && *ifstate == IFSTATE_FALSE) + return 0; + if (!strcmp(cs, META_FAIL)) *fail = 1; - else if (!strcmp(cs, NOFAIL_META)) + else if (!strcmp(cs, META_NOFAIL)) *fail = 0; else { size_t l; l = strcspn(cs, whitespace); - if (l == sizeof(INCLUDE_META)-1 && !strncmp(cs, INCLUDE_META, l)) { + if (l == sizeof(META_INCLUDE)-1 && !strncmp(cs, META_INCLUDE, l)) { const char *filename = cs+l+strspn(cs+l, whitespace); if (pa_cli_command_execute_file(c, filename, buf, fail) < 0) if (*fail) return -1; + } else if (l == sizeof(META_IFEXISTS)-1 && !strncmp(cs, META_IFEXISTS, l)) { + if (!ifstate) { + pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs); + return -1; + } else if (*ifstate != IFSTATE_NONE) { + pa_strbuf_printf(buf, "Nested %s commands not supported\n", cs); + return -1; + } else { + const char *filename = cs+l+strspn(cs+l, whitespace); + + *ifstate = access(filename, F_OK) == 0 ? IFSTATE_TRUE : IFSTATE_FALSE; + } } else { pa_strbuf_printf(buf, "Invalid meta command: %s\n", cs); if (*fail) return -1; @@ -990,8 +1031,12 @@ int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int * int unknown = 1; size_t l; - l = strcspn(cs, whitespace); + if (ifstate && *ifstate == IFSTATE_FALSE) + return 0; + + l = strcspn(cs, whitespace); + for (command = commands; command->name; command++) if (strlen(command->name) == l && !strncmp(cs, command->name, l)) { int ret; @@ -1017,11 +1062,19 @@ int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int * return 0; } +int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { + return pa_cli_command_execute_line_stateful(c, s, buf, fail, NULL); +} + int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int *fail) { char line[256]; FILE *f = NULL; + int ifstate = IFSTATE_NONE; int ret = -1; - assert(c && fn && buf); + + assert(c); + assert(fn); + assert(buf); if (!(f = fopen(fn, "r"))) { pa_strbuf_printf(buf, "open('%s') failed: %s\n", fn, pa_cstrerror(errno)); @@ -1034,7 +1087,7 @@ int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int char *e = line + strcspn(line, linebreak); *e = 0; - if (pa_cli_command_execute_line(c, line, buf, fail) < 0 && *fail) + if (pa_cli_command_execute_line_stateful(c, line, buf, fail, &ifstate) < 0 && *fail) goto fail; } @@ -1049,14 +1102,18 @@ fail: int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { const char *p; - assert(c && s && buf && fail); + int ifstate = IFSTATE_NONE; + + assert(c); + assert(s); + assert(buf); p = s; while (*p) { size_t l = strcspn(p, linebreak); char *line = pa_xstrndup(p, l); - if (pa_cli_command_execute_line(c, line, buf, fail) < 0&& *fail) { + if (pa_cli_command_execute_line_stateful(c, line, buf, fail, &ifstate) < 0 && *fail) { pa_xfree(line); return -1; } diff --git a/src/pulsecore/cli-command.h b/src/pulsecore/cli-command.h index 10d50f37..01bca8be 100644 --- a/src/pulsecore/cli-command.h +++ b/src/pulsecore/cli-command.h @@ -39,4 +39,7 @@ int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int /* Split the specified string into lines and run pa_cli_command_execute_line() for each. */ int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail); +/* Same as pa_cli_command_execute_line() but also take ifstate var. */ +int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *buf, int *fail, int *ifstate); + #endif diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c index 758beaff..10238acb 100644 --- a/src/pulsecore/pdispatch.c +++ b/src/pulsecore/pdispatch.c @@ -258,7 +258,7 @@ void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa struct timeval tv; assert(pd && pd->ref >= 1 && cb); - r = pa_xmalloc(sizeof(struct reply_info)); + r = pa_xnew(struct reply_info, 1); r->pdispatch = pd; r->callback = cb; r->userdata = userdata; -- cgit From 872018efc855e8ea7f3277d1e08c855c63c96897 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 27 May 2007 16:37:05 +0000 Subject: Minor optimization: read log level character code from array git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1457 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/log.c | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c index d8a9efe9..0033adb9 100644 --- a/src/pulsecore/log.c +++ b/src/pulsecore/log.c @@ -62,6 +62,14 @@ static const int level_to_syslog[] = { }; #endif +static const char level_to_char[] = { + [PA_LOG_ERROR] = 'E', + [PA_LOG_WARN] = 'W', + [PA_LOG_NOTICE] = 'N', + [PA_LOG_INFO] = 'I', + [PA_LOG_DEBUG] = 'D' +}; + void pa_log_set_ident(const char *p) { if (log_ident) pa_xfree(log_ident); @@ -129,7 +137,6 @@ void pa_log_levelv_meta( switch (log_target) { case PA_LOG_STDERR: { const char *prefix = "", *suffix = ""; - const char *level_code = ""; char *local_t; #ifndef OS_IS_WIN32 @@ -145,33 +152,11 @@ void pa_log_levelv_meta( } #endif - switch (level) { - case PA_LOG_ERROR: - level_code = "E"; - break; - case PA_LOG_WARN: - level_code = "W"; - break; - case PA_LOG_NOTICE: - level_code = "N"; - break; - case PA_LOG_INFO: - level_code = "I"; - break; - case PA_LOG_DEBUG: - level_code = "D"; - break; - default: - level_code = "?"; - } - local_t = pa_utf8_to_locale(t); - if (!local_t) { - fprintf(stderr, "%s: %s%s%s%s\n", level_code, location, - prefix, t, suffix); - } else { - fprintf(stderr, "%s: %s%s%s%s\n", level_code, location, - prefix, local_t, suffix); + if (!local_t) + fprintf(stderr, "%c: %s%s%s%s\n", level_to_char[level], location, prefix, t, suffix); + else { + fprintf(stderr, "%c: %s%s%s%s\n", level_to_char[level], location, prefix, local_t, suffix); pa_xfree(local_t); } -- cgit From 6a2dffd78af88ec3c3089c3a852af6d3a6b499bf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 27 May 2007 16:59:34 +0000 Subject: unfortunately we cannot detect if a foreign thread is still running. Thus sucks. But what can we do? U. Drepper thinks our use case is invalid. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1458 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/thread-posix.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c index 7ff5e7c3..b3274426 100644 --- a/src/pulsecore/thread-posix.c +++ b/src/pulsecore/thread-posix.c @@ -111,17 +111,12 @@ pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) { int pa_thread_is_running(pa_thread *t) { assert(t); - - if (!t->thread_func) { - /* Mhmm, this is a foreign thread, t->running is not - * necessarily valid. We misuse pthread_getschedparam() to - * check if the thread is valid. This might not be portable. */ - - int policy; - struct sched_param param; - - return pthread_getschedparam(t->id, &policy, ¶m) >= 0 || errno != ESRCH; - } + + /* Unfortunately there is no way to tell whether a "foreign" + * thread is still running. See + * http://udrepper.livejournal.com/16844.html for more + * information */ + assert(t->thread_func); return pa_atomic_load(&t->running) > 0; } -- cgit From 918cacb4f4efa80a0bc4b7183da1e9c1cb10ed9c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 27 May 2007 20:38:14 +0000 Subject: Replace AO_xxx usage with pa_atomic_xxx and friends wherever it makes sense git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1459 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/atomic.h | 4 +++ src/pulsecore/cli-command.c | 20 ++++++------- src/pulsecore/memblock.c | 66 ++++++++++++++++++++--------------------- src/pulsecore/memblock.h | 29 +++++++++--------- src/pulsecore/protocol-native.c | 8 ++--- src/tests/memblock-test.c | 28 ++++++++--------- 6 files changed, 80 insertions(+), 75 deletions(-) diff --git a/src/pulsecore/atomic.h b/src/pulsecore/atomic.h index 8867f884..013e8c20 100644 --- a/src/pulsecore/atomic.h +++ b/src/pulsecore/atomic.h @@ -53,6 +53,10 @@ static inline int pa_atomic_add(pa_atomic_int_t *a, int i) { return AO_fetch_and_add_full(&a->value, (AO_t) i); } +static inline int pa_atomic_sub(pa_atomic_int_t *a, int i) { + return AO_fetch_and_add_full(&a->value, (AO_t) -i); +} + static inline int pa_atomic_inc(pa_atomic_int_t *a) { return AO_fetch_and_add1_full(&a->value); } diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index 2755c5c9..4dbf3afa 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -273,20 +273,20 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G stat = pa_mempool_get_stat(c->mempool); pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n", - (unsigned) AO_load_acquire_read((AO_t*) &stat->n_allocated), - pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->allocated_size))); + (unsigned) pa_atomic_load(&stat->n_allocated), + pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->allocated_size))); pa_strbuf_printf(buf, "Memory blocks allocated during the whole lifetime: %u, size: %s.\n", - (unsigned) AO_load_acquire_read((AO_t*) &stat->n_accumulated), - pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->accumulated_size))); + (unsigned) pa_atomic_load(&stat->n_accumulated), + pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->accumulated_size))); pa_strbuf_printf(buf, "Memory blocks imported from other processes: %u, size: %s.\n", - (unsigned) AO_load_acquire_read((AO_t*) &stat->n_imported), - pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->imported_size))); + (unsigned) pa_atomic_load(&stat->n_imported), + pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->imported_size))); pa_strbuf_printf(buf, "Memory blocks exported to other processes: %u, size: %s.\n", - (unsigned) AO_load_acquire_read((AO_t*) &stat->n_exported), - pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->exported_size))); + (unsigned) pa_atomic_load(&stat->n_exported), + pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->exported_size))); pa_strbuf_printf(buf, "Total sample cache size: %s.\n", pa_bytes_snprint(s, sizeof(s), pa_scache_total_size(c))); @@ -305,8 +305,8 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G pa_strbuf_printf(buf, "Memory blocks of type %s: %u allocated/%u accumulated.\n", type_table[k], - (unsigned) AO_load_acquire_read(&stat->n_allocated_by_type[k]), - (unsigned) AO_load_acquire_read(&stat->n_accumulated_by_type[k])); + (unsigned) pa_atomic_load(&stat->n_allocated_by_type[k]), + (unsigned) pa_atomic_load(&stat->n_accumulated_by_type[k])); return 0; } diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 5e7d6e48..6f09a906 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -114,40 +114,40 @@ static void stat_add(pa_memblock*b) { assert(b); assert(b->pool); - AO_fetch_and_add1_release_write(&b->pool->stat.n_allocated); - AO_fetch_and_add_release_write(&b->pool->stat.allocated_size, (AO_t) b->length); + pa_atomic_inc(&b->pool->stat.n_allocated); + pa_atomic_add(&b->pool->stat.allocated_size, b->length); - AO_fetch_and_add1_release_write(&b->pool->stat.n_accumulated); - AO_fetch_and_add_release_write(&b->pool->stat.accumulated_size, (AO_t) b->length); + pa_atomic_inc(&b->pool->stat.n_accumulated); + pa_atomic_add(&b->pool->stat.accumulated_size, b->length); if (b->type == PA_MEMBLOCK_IMPORTED) { - AO_fetch_and_add1_release_write(&b->pool->stat.n_imported); - AO_fetch_and_add_release_write(&b->pool->stat.imported_size, (AO_t) b->length); + pa_atomic_inc(&b->pool->stat.n_imported); + pa_atomic_add(&b->pool->stat.imported_size, b->length); } - AO_fetch_and_add1_release_write(&b->pool->stat.n_allocated_by_type[b->type]); - AO_fetch_and_add1_release_write(&b->pool->stat.n_accumulated_by_type[b->type]); + pa_atomic_inc(&b->pool->stat.n_allocated_by_type[b->type]); + pa_atomic_inc(&b->pool->stat.n_accumulated_by_type[b->type]); } static void stat_remove(pa_memblock *b) { assert(b); assert(b->pool); - assert(AO_load_acquire_read(&b->pool->stat.n_allocated) > 0); - assert(AO_load_acquire_read(&b->pool->stat.allocated_size) >= (AO_t) b->length); + assert(pa_atomic_load(&b->pool->stat.n_allocated) > 0); + assert(pa_atomic_load(&b->pool->stat.allocated_size) >= (int) b->length); - AO_fetch_and_sub1_release_write(&b->pool->stat.n_allocated); - AO_fetch_and_add_release_write(&b->pool->stat.allocated_size, (AO_t) (-b->length)); + pa_atomic_dec(&b->pool->stat.n_allocated); + pa_atomic_sub(&b->pool->stat.allocated_size, b->length); if (b->type == PA_MEMBLOCK_IMPORTED) { - assert(AO_load_acquire_read(&b->pool->stat.n_imported) > 0); - assert(AO_load_acquire_read(&b->pool->stat.imported_size) >= (AO_t) b->length); + assert(pa_atomic_load(&b->pool->stat.n_imported) > 0); + assert(pa_atomic_load(&b->pool->stat.imported_size) >= (int) b->length); - AO_fetch_and_sub1_release_write(&b->pool->stat.n_imported); - AO_fetch_and_add_release_write(&b->pool->stat.imported_size, (AO_t) (-b->length)); + pa_atomic_dec(&b->pool->stat.n_imported); + pa_atomic_sub(&b->pool->stat.imported_size, b->length); } - AO_fetch_and_sub1_release_write(&b->pool->stat.n_allocated_by_type[b->type]); + pa_atomic_dec(&b->pool->stat.n_allocated_by_type[b->type]); } static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length); @@ -193,7 +193,7 @@ static struct mempool_slot* mempool_allocate_slot(pa_mempool *p) { slot = (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->block_size * p->n_init++)); else { pa_log_debug("Pool full"); - AO_fetch_and_add1_release_write(&p->stat.n_pool_full); + pa_atomic_inc(&p->stat.n_pool_full); return NULL; } @@ -249,7 +249,7 @@ pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) { b->data = mempool_slot_data(slot); } else { pa_log_debug("Memory block too large for pool: %u > %u", length, p->block_size - sizeof(struct mempool_slot)); - AO_fetch_and_add1_release_write(&p->stat.n_too_large_for_pool); + pa_atomic_inc(&p->stat.n_too_large_for_pool); return NULL; } @@ -372,7 +372,7 @@ void pa_memblock_unref(pa_memblock*b) { static void memblock_make_local(pa_memblock *b) { assert(b); - AO_fetch_and_sub1_release_write(&b->pool->stat.n_allocated_by_type[b->type]); + pa_atomic_dec(&b->pool->stat.n_allocated_by_type[b->type]); if (b->length <= b->pool->block_size - sizeof(struct mempool_slot)) { struct mempool_slot *slot; @@ -398,8 +398,8 @@ static void memblock_make_local(pa_memblock *b) { b->data = pa_xmemdup(b->data, b->length); finish: - AO_fetch_and_add1_release_write(&b->pool->stat.n_allocated_by_type[b->type]); - AO_fetch_and_add1_release_write(&b->pool->stat.n_accumulated_by_type[b->type]); + pa_atomic_inc(&b->pool->stat.n_allocated_by_type[b->type]); + pa_atomic_inc(&b->pool->stat.n_accumulated_by_type[b->type]); } void pa_memblock_unref_fixed(pa_memblock *b) { @@ -419,10 +419,10 @@ static void memblock_replace_import(pa_memblock *b) { assert(b); assert(b->type == PA_MEMBLOCK_IMPORTED); - assert(AO_load_acquire_read(&b->pool->stat.n_imported) > 0); - assert(AO_load_acquire_read(&b->pool->stat.imported_size) >= (AO_t) b->length); - AO_fetch_and_sub1_release_write(&b->pool->stat.n_imported); - AO_fetch_and_add_release_write(&b->pool->stat.imported_size, (AO_t) - b->length); + assert(pa_atomic_load(&b->pool->stat.n_imported) > 0); + assert(pa_atomic_load(&b->pool->stat.imported_size) >= (int) b->length); + pa_atomic_dec(&b->pool->stat.n_imported); + pa_atomic_sub(&b->pool->stat.imported_size, b->length); seg = b->per_type.imported.segment; assert(seg); @@ -486,7 +486,7 @@ void pa_mempool_free(pa_mempool *p) { while (p->exports) pa_memexport_free(p->exports); - if (AO_load_acquire_read(&p->stat.n_allocated) > 0) + if (pa_atomic_load(&p->stat.n_allocated) > 0) pa_log_warn("WARNING! Memory pool destroyed but not all memory blocks freed!"); pa_shm_free(&p->memory); @@ -684,11 +684,11 @@ int pa_memexport_process_release(pa_memexport *e, uint32_t id) { /* pa_log("Processing release for %u", id); */ - assert(AO_load_acquire_read(&e->pool->stat.n_exported) > 0); - assert(AO_load_acquire_read(&e->pool->stat.exported_size) >= (AO_t) e->slots[id].block->length); + assert(pa_atomic_load(&e->pool->stat.n_exported) > 0); + assert(pa_atomic_load(&e->pool->stat.exported_size) >= (int) e->slots[id].block->length); - AO_fetch_and_sub1_release_write(&e->pool->stat.n_exported); - AO_fetch_and_add_release_write(&e->pool->stat.exported_size, (AO_t) -e->slots[id].block->length); + pa_atomic_dec(&e->pool->stat.n_exported); + pa_atomic_sub(&e->pool->stat.exported_size, e->slots[id].block->length); pa_memblock_unref(e->slots[id].block); e->slots[id].block = NULL; @@ -785,8 +785,8 @@ int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32 *offset = (uint8_t*) b->data - (uint8_t*) memory->ptr; *size = b->length; - AO_fetch_and_add1_release_write(&e->pool->stat.n_exported); - AO_fetch_and_add_release_write(&e->pool->stat.exported_size, (AO_t) b->length); + pa_atomic_inc(&e->pool->stat.n_exported); + pa_atomic_add(&e->pool->stat.exported_size, b->length); return 0; } diff --git a/src/pulsecore/memblock.h b/src/pulsecore/memblock.h index 3eace92c..fe4773d4 100644 --- a/src/pulsecore/memblock.h +++ b/src/pulsecore/memblock.h @@ -30,6 +30,7 @@ #include #include +#include /* A pa_memblock is a reference counted memory block. PulseAudio * passed references to pa_memblocks around instead of copying @@ -82,20 +83,20 @@ struct pa_memblock { * n_accumulated is not yet. Take these values with a grain of salt, * threy are here for purely statistical reasons.*/ struct pa_mempool_stat { - AO_t n_allocated; - AO_t n_accumulated; - AO_t n_imported; - AO_t n_exported; - AO_t allocated_size; - AO_t accumulated_size; - AO_t imported_size; - AO_t exported_size; - - AO_t n_too_large_for_pool; - AO_t n_pool_full; - - AO_t n_allocated_by_type[PA_MEMBLOCK_TYPE_MAX]; - AO_t n_accumulated_by_type[PA_MEMBLOCK_TYPE_MAX]; + pa_atomic_int_t n_allocated; + pa_atomic_int_t n_accumulated; + pa_atomic_int_t n_imported; + pa_atomic_int_t n_exported; + pa_atomic_int_t allocated_size; + pa_atomic_int_t accumulated_size; + pa_atomic_int_t imported_size; + pa_atomic_int_t exported_size; + + pa_atomic_int_t n_too_large_for_pool; + pa_atomic_int_t n_pool_full; + + pa_atomic_int_t n_allocated_by_type[PA_MEMBLOCK_TYPE_MAX]; + pa_atomic_int_t n_accumulated_by_type[PA_MEMBLOCK_TYPE_MAX]; }; /* Allocate a new memory block of type PA_MEMBLOCK_MEMPOOL or PA_MEMBLOCK_APPENDED, depending on the size */ diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 774f6918..dbdb7dd4 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -1116,10 +1116,10 @@ static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t stat = pa_mempool_get_stat(c->protocol->core->mempool); reply = reply_new(tag); - pa_tagstruct_putu32(reply, (uint32_t) AO_load_acquire_read((AO_t*) &stat->n_allocated)); - pa_tagstruct_putu32(reply, (uint32_t) AO_load_acquire_read((AO_t*) &stat->allocated_size)); - pa_tagstruct_putu32(reply, (uint32_t) AO_load_acquire_read((AO_t*) &stat->n_accumulated)); - pa_tagstruct_putu32(reply, (uint32_t) AO_load_acquire_read((AO_t*) &stat->accumulated_size)); + pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated)); + pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size)); + pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated)); + pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size)); pa_tagstruct_putu32(reply, pa_scache_total_size(c->protocol->core)); pa_pstream_send_tagstruct(c->pstream, reply); } diff --git a/src/tests/memblock-test.c b/src/tests/memblock-test.c index 13bfdf0d..8d25ba38 100644 --- a/src/tests/memblock-test.c +++ b/src/tests/memblock-test.c @@ -46,24 +46,24 @@ static void print_stats(pa_mempool *p, const char *text) { "n_accumulated = %u\n" "n_imported = %u\n" "n_exported = %u\n" - "allocated_size = %lu\n" - "accumulated_size = %lu\n" - "imported_size = %lu\n" - "exported_size = %lu\n" + "allocated_size = %u\n" + "accumulated_size = %u\n" + "imported_size = %u\n" + "exported_size = %u\n" "n_too_large_for_pool = %u\n" "n_pool_full = %u\n" "}\n", text, - (unsigned) AO_load_acquire_read((AO_t*) &s->n_allocated), - (unsigned) AO_load_acquire_read((AO_t*) &s->n_accumulated), - (unsigned) AO_load_acquire_read((AO_t*) &s->n_imported), - (unsigned) AO_load_acquire_read((AO_t*) &s->n_exported), - (unsigned long) AO_load_acquire_read((AO_t*) &s->allocated_size), - (unsigned long) AO_load_acquire_read((AO_t*) &s->accumulated_size), - (unsigned long) AO_load_acquire_read((AO_t*) &s->imported_size), - (unsigned long) AO_load_acquire_read((AO_t*) &s->exported_size), - (unsigned) AO_load_acquire_read((AO_t*) &s->n_too_large_for_pool), - (unsigned) AO_load_acquire_read((AO_t*) &s->n_pool_full)); + (unsigned) pa_atomic_load(&s->n_allocated), + (unsigned) pa_atomic_load(&s->n_accumulated), + (unsigned) pa_atomic_load(&s->n_imported), + (unsigned) pa_atomic_load(&s->n_exported), + (unsigned) pa_atomic_load(&s->allocated_size), + (unsigned) pa_atomic_load(&s->accumulated_size), + (unsigned) pa_atomic_load(&s->imported_size), + (unsigned) pa_atomic_load(&s->exported_size), + (unsigned) pa_atomic_load(&s->n_too_large_for_pool), + (unsigned) pa_atomic_load(&s->n_pool_full)); } int main(int argc, char *argv[]) { -- cgit From 707def14fc4cebc3b2407768c7ac03019a39c87f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 27 May 2007 20:58:29 +0000 Subject: Bump revision of libs and package git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1460 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 65a99a00..9a1e6c51 100644 --- a/configure.ac +++ b/configure.ac @@ -26,7 +26,7 @@ AC_PREREQ(2.57) m4_define(PA_MAJOR, [0]) m4_define(PA_MINOR, [9]) -m4_define(PA_MICRO, [5]) +m4_define(PA_MICRO, [6]) AC_INIT([pulseaudio], PA_MAJOR.PA_MINOR.PA_MICRO,[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([src/daemon/main.c]) @@ -39,8 +39,8 @@ AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/pulseaudio/]) AC_SUBST(PA_API_VERSION, 10) AC_SUBST(PA_PROTOCOL_VERSION, 10) -AC_SUBST(LIBPULSE_VERSION_INFO, [1:0:1]) -AC_SUBST(LIBPULSECORE_VERSION_INFO, [2:0:0]) +AC_SUBST(LIBPULSE_VERSION_INFO, [2:0:2]) +AC_SUBST(LIBPULSECORE_VERSION_INFO, [3:0:0]) AC_SUBST(LIBPULSE_SIMPLE_VERSION_INFO, [0:0:0]) AC_SUBST(LIBPULSE_BROWSE_VERSION_INFO, [1:0:1]) AC_SUBST(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO, [0:2:0]) -- cgit From 67cb77575f98a78b7365a972b08fb2013782eda3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 28 May 2007 15:52:13 +0000 Subject: build fix for systems lacking capability suppoort. (Problem identified and original patch supplied by Diego Petteno git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1462 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/core-util.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 480ac3b7..5159934d 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -544,6 +544,10 @@ fail: cap_free(caps); } #endif + + ; /* We put this here to get the code to compile when + * HAVE_SYS_CAPABILITY_H is not defined. Don't remove unless you + * know what you do */ } /* Reset the priority to normal, inverting the changes made by pa_raise_priority() */ -- cgit From 5530d3295a3e65905346e98314f884a09a2be325 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 29 May 2007 07:47:02 +0000 Subject: We now use gid unconditionally, so make sure it's defined. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1463 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/daemon/main.c b/src/daemon/main.c index 72e47975..91cc3a2f 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -320,9 +320,7 @@ int main(int argc, char *argv[]) { int suid_root, real_root; int valid_pid_file = 0; -#ifdef HAVE_GETUID gid_t gid = (gid_t) -1; -#endif #ifdef OS_IS_WIN32 pa_time_event *timer; -- cgit From e4d63d0d8026446aec99ef8390554c5afd87cef4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 29 May 2007 17:16:24 +0000 Subject: add target "eolspace" to makefil to remove trailing newlines from all source files git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1464 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile.am b/Makefile.am index 1b77187d..abc3d776 100644 --- a/Makefile.am +++ b/Makefile.am @@ -45,4 +45,7 @@ homepage: all dist doxygen doxygen: $(MAKE) -C doxygen doxygen +eolspace: + find \( -name '*.c' -o -name '*.h' -o -name 'Makefile.am' \) -exec perl -i -pe 's/\s+\n$$/\1\n/;' \{\} \; + .PHONY: homepage distcleancheck doxygen -- cgit From 1e12e0ee8dfdda1632b9c082aba6fc1956813a5b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 29 May 2007 17:24:48 +0000 Subject: Kill spaces on EOL git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1465 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 30 +- src/daemon/caps.c | 8 +- src/modules/gconf/gconf-helper.c | 30 +- src/modules/gconf/module-gconf.c | 62 +- src/modules/module-hal-detect.c | 10 +- src/modules/module-oss.c | 10 +- src/modules/rtp/module-rtp-recv.c | 64 +- src/modules/rtp/module-rtp-send.c | 36 +- src/modules/rtp/rtp.c | 34 +- src/modules/rtp/rtp.h | 6 +- src/modules/rtp/sap.c | 28 +- src/modules/rtp/sap.h | 6 +- src/modules/rtp/sdp.c | 30 +- src/modules/rtp/sdp.h | 6 +- src/pulsecore/cli-command.c | 8 +- src/pulsecore/core-util.c | 4 +- src/pulsecore/g711.c | 5062 ++++++++++++++++++------------------- src/pulsecore/protocol-native.c | 2 +- src/pulsecore/sample-util.c | 2 +- src/pulsecore/thread-posix.c | 2 +- src/utils/padsp.c | 2 +- 21 files changed, 2721 insertions(+), 2721 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index e05b5364..d90361f3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -126,7 +126,7 @@ pulseaudio_SOURCES = \ pulsecore/gccmacro.h pulseaudio_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) -pulseaudio_CPPFLAGS = $(AM_CPPFLAGS) +pulseaudio_CPPFLAGS = $(AM_CPPFLAGS) pulseaudio_LDADD = $(AM_LDADD) libpulsecore.la $(LIBLTDL) \ $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) $(LIBOIL_LIBS) # This is needed because automake doesn't properly expand the foreach below @@ -168,8 +168,8 @@ endif bin_SCRIPTS = esdcompat pacat_SOURCES = utils/pacat.c -pacat_LDADD = $(AM_LDADD) libpulse.la -pacat_CFLAGS = $(AM_CFLAGS) +pacat_LDADD = $(AM_LDADD) libpulse.la +pacat_CFLAGS = $(AM_CFLAGS) pacat_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) paplay_SOURCES = utils/paplay.c @@ -247,7 +247,7 @@ utf8_test_CFLAGS = $(AM_CFLAGS) utf8_test_LDADD = $(AM_LDADD) libpulsecore.la utf8_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -get_binary_name_test_SOURCES = tests/get-binary-name-test.c +get_binary_name_test_SOURCES = tests/get-binary-name-test.c get_binary_name_test_CFLAGS = $(AM_CFLAGS) get_binary_name_test_LDADD = $(AM_LDADD) libpulse.la get_binary_name_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -264,22 +264,22 @@ hook_list_test_CFLAGS = $(AM_CFLAGS) hook_list_test_LDADD = $(AM_LDADD) libpulsecore.la hook_list_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -memblock_test_SOURCES = tests/memblock-test.c +memblock_test_SOURCES = tests/memblock-test.c memblock_test_CFLAGS = $(AM_CFLAGS) memblock_test_LDADD = $(AM_LDADD) libpulsecore.la -memblock_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +memblock_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) thread_test_SOURCES = tests/thread-test.c thread_test_CFLAGS = $(AM_CFLAGS) thread_test_LDADD = $(AM_LDADD) libpulsecore.la -thread_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +thread_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) flist_test_SOURCES = tests/flist-test.c \ pulsecore/atomic.h \ pulsecore/flist.c pulsecore/flist.h flist_test_CFLAGS = $(AM_CFLAGS) flist_test_LDADD = $(AM_LDADD) libpulsecore.la -flist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +flist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) mcalign_test_SOURCES = tests/mcalign-test.c mcalign_test_CFLAGS = $(AM_CFLAGS) @@ -333,12 +333,12 @@ memblockq_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) sync_playback_SOURCES = tests/sync-playback.c sync_playback_LDADD = $(AM_LDADD) libpulse.la -sync_playback_CFLAGS = $(AM_CFLAGS) +sync_playback_CFLAGS = $(AM_CFLAGS) sync_playback_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) interpol_test_SOURCES = tests/interpol-test.c interpol_test_LDADD = $(AM_LDADD) libpulse.la -interpol_test_CFLAGS = $(AM_CFLAGS) +interpol_test_CFLAGS = $(AM_CFLAGS) interpol_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) ################################### @@ -459,7 +459,7 @@ libpulse_la_SOURCES += \ if OS_IS_WIN32 libpulse_la_SOURCES += \ - pulsecore/dllmain.c + pulsecore/dllmain.c endif if HAVE_X11 @@ -482,7 +482,7 @@ libpulse_la_CFLAGS += $(LIBASYNCNS_CFLAGS) libpulse_la_LIBADD += $(LIBASYNCNS_LIBS) endif -libpulse_simple_la_SOURCES = pulse/simple.c pulse/simple.h +libpulse_simple_la_SOURCES = pulse/simple.c pulse/simple.h libpulse_simple_la_CFLAGS = $(AM_CFLAGS) libpulse_simple_la_LIBADD = $(AM_LIBADD) libpulse.la libpulse_simple_la_LDFLAGS = -version-info $(LIBPULSE_SIMPLE_VERSION_INFO) @@ -640,7 +640,7 @@ libpulsecore_la_SOURCES += \ if OS_IS_WIN32 libpulsecore_la_SOURCES += \ - pulsecore/dllmain.c + pulsecore/dllmain.c endif libpulsecore_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBOIL_CFLAGS) @@ -820,7 +820,7 @@ libsocket_util_la_SOURCES = \ libsocket_util_la_LDFLAGS = -avoid-version libsocket_util_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) libpulsecore.la -librtp_la_SOURCES = modules/rtp/rtp.c modules/rtp/rtp.h modules/rtp/sdp.c modules/rtp/sdp.h modules/rtp/sap.c modules/rtp/sap.h +librtp_la_SOURCES = modules/rtp/rtp.c modules/rtp/rtp.h modules/rtp/sdp.c modules/rtp/sdp.h modules/rtp/sap.c modules/rtp/sap.h librtp_la_LDFLAGS = -avoid-version librtp_la_LIBADD = $(AM_LIBADD) libpulsecore.la @@ -1298,7 +1298,7 @@ esdcompat: daemon/esdcompat.in Makefile client.conf: pulse/client.conf.in Makefile sed -e 's,@PA_BINARY\@,$(PA_BINARY),g' < $< > $@ -if OS_IS_WIN32 +if OS_IS_WIN32 default.pa: daemon/default.pa.win32 cp $< $@ else diff --git a/src/daemon/caps.c b/src/daemon/caps.c index 8043230c..f92db743 100644 --- a/src/daemon/caps.c +++ b/src/daemon/caps.c @@ -97,9 +97,9 @@ int pa_limit_caps(void) { if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) goto fail; - + pa_log_info("dropped capabilities successfully."); - + r = 1; fail: @@ -119,12 +119,12 @@ int pa_drop_caps(void) { cap_clear(caps); prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0); - + if (cap_set_proc(caps) < 0) { pa_log("failed to drop capabilities: %s", pa_cstrerror(errno)); goto fail; } - + r = 0; fail: diff --git a/src/modules/gconf/gconf-helper.c b/src/modules/gconf/gconf-helper.c index 5f6def4d..3483b845 100644 --- a/src/modules/gconf/gconf-helper.c +++ b/src/modules/gconf/gconf-helper.c @@ -4,17 +4,17 @@ This file is part of PulseAudio. Copyright 2006 Lennart Poettering - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -48,30 +48,30 @@ static void handle_module(GConfClient *client, const char *name) { snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/enabled", name); enabled = gconf_client_get_bool(client, p, FALSE); - + printf("%c%s%c", enabled ? '+' : '-', name, 0); if (enabled) { - + for (i = 0; i < 10; i++) { gchar *n, *a; - + snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/name%i", name, i); if (!(n = gconf_client_get_string(client, p, NULL)) || !*n) break; - + snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/args%i", name, i); a = gconf_client_get_string(client, p, NULL); - + printf("%s%c%s%c", n, 0, a ? a : "", 0); - + g_free(n); g_free(a); } - + printf("%c", 0); } - + fflush(stdout); } @@ -83,7 +83,7 @@ static void modules_callback( const char *n; char buf[128]; - + g_assert(strncmp(entry->key, PA_GCONF_PATH_MODULES"/", sizeof(PA_GCONF_PATH_MODULES)) == 0); n = entry->key + sizeof(PA_GCONF_PATH_MODULES); @@ -113,17 +113,17 @@ int main(int argc, char *argv[]) { char *e = strrchr(m->data, '/'); handle_module(client, e ? e+1 : m->data); } - + g_slist_free(modules); /* Signal the parent that we are now initialized */ printf("!"); fflush(stdout); - + g = g_main_loop_new(NULL, FALSE); g_main_loop_run(g); g_main_loop_unref(g); - + g_object_unref(G_OBJECT(client)); return 0; diff --git a/src/modules/gconf/module-gconf.c b/src/modules/gconf/module-gconf.c index df7b1643..cbe17d20 100644 --- a/src/modules/gconf/module-gconf.c +++ b/src/modules/gconf/module-gconf.c @@ -4,17 +4,17 @@ This file is part of PulseAudio. Copyright 2006 Lennart Poettering - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -80,7 +80,7 @@ struct module_info { struct userdata { pa_core *core; pa_module *module; - + pa_hashmap *module_infos; pid_t pid; @@ -129,7 +129,7 @@ static char *read_string(struct userdata *u) { for (;;) { char *e; - + if ((e = memchr(u->buf, 0, u->buf_fill))) { char *ret = pa_xstrdup(u->buf); u->buf_fill -= e - u->buf +1; @@ -149,7 +149,7 @@ static void unload_one_module(struct userdata *u, struct module_info*m, unsigned if (m->items[i].index == PA_INVALID_INDEX) return; - + pa_log_debug("Unloading module #%i", m->items[i].index); pa_module_unload_by_index(u->core, m->items[i].index); m->items[i].index = PA_INVALID_INDEX; @@ -160,7 +160,7 @@ static void unload_one_module(struct userdata *u, struct module_info*m, unsigned static void unload_all_modules(struct userdata *u, struct module_info*m) { unsigned i; - + assert(u); assert(m); @@ -179,7 +179,7 @@ static void load_module( int is_new) { pa_module *mod; - + assert(u); assert(m); assert(name); @@ -193,18 +193,18 @@ static void load_module( unload_one_module(u, m, i); } - + pa_log_debug("Loading module '%s' with args '%s' due to GConf configuration.", name, args); m->items[i].name = pa_xstrdup(name); m->items[i].args = pa_xstrdup(args); m->items[i].index = PA_INVALID_INDEX; - + if (!(mod = pa_module_load(u->core, name, args))) { pa_log("pa_module_load() failed"); return; } - + m->items[i].index = mod->index; } @@ -227,18 +227,18 @@ static int handle_event(struct userdata *u) { do { if ((opcode = read_byte(u)) < 0) goto fail; - + switch (opcode) { case '!': /* The helper tool is now initialized */ ret = 1; break; - + case '+': { char *name; struct module_info *m; unsigned i, j; - + if (!(name = read_string(u))) goto fail; @@ -282,16 +282,16 @@ static int handle_event(struct userdata *u) { /* Unload all removed modules */ for (j = i; j < m->n_items; j++) unload_one_module(u, m, j); - + m->n_items = i; - + break; } - + case '-': { char *name; struct module_info *m; - + if (!(name = read_string(u))) goto fail; @@ -301,7 +301,7 @@ static int handle_event(struct userdata *u) { } pa_xfree(name); - + break; } } @@ -324,12 +324,12 @@ static void io_event_cb( struct userdata *u = userdata; if (handle_event(u) < 0) { - + if (u->io_event) { u->core->mainloop->io_free(u->io_event); u->io_event = NULL; } - + pa_module_unload_request(u->module); } } @@ -342,7 +342,7 @@ static int start_client(const char *n, pid_t *pid) { pa_log("pipe() failed: %s", pa_cstrerror(errno)); goto fail; } - + if ((child = fork()) == (pid_t) -1) { pa_log("fork() failed: %s", pa_cstrerror(errno)); goto fail; @@ -357,7 +357,7 @@ static int start_client(const char *n, pid_t *pid) { return pipe_fds[0]; } else { int max_fd, i; - + /* child */ close(pipe_fds[0]); @@ -373,7 +373,7 @@ static int start_client(const char *n, pid_t *pid) { open("/dev/null", O_WRONLY); max_fd = 1024; - + #ifdef HAVE_SYS_RESOURCE_H { struct rlimit r; @@ -381,7 +381,7 @@ static int start_client(const char *n, pid_t *pid) { max_fd = r.rlim_max; } #endif - + for (i = 3; i < max_fd; i++) close(i); @@ -402,14 +402,14 @@ static int start_client(const char *n, pid_t *pid) { execl(n, n, NULL); _exit(1); } - + fail: if (pipe_fds[0] >= 0) close(pipe_fds[0]); if (pipe_fds[1] >= 0) close(pipe_fds[1]); - + return -1; } @@ -427,17 +427,17 @@ int pa__init(pa_core *c, pa_module*m) { u->fd_type = 0; u->io_event = NULL; u->buf_fill = 0; - + if ((u->fd = start_client(PA_GCONF_HELPER, &u->pid)) < 0) goto fail; - + u->io_event = c->mainloop->io_new( c->mainloop, u->fd, PA_IO_EVENT_INPUT, io_event_cb, u); - + do { if ((r = handle_event(u)) < 0) goto fail; @@ -445,7 +445,7 @@ int pa__init(pa_core *c, pa_module*m) { /* Read until the client signalled us that it is ready with * initialization */ } while (r != 1); - + return 0; fail: diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index 27cd449e..1f48a452 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -87,7 +87,7 @@ struct userdata { pa_hashmap *devices; #if defined(HAVE_ALSA) && defined(HAVE_OSS) int use_oss; -#endif +#endif }; struct timerdata { @@ -269,7 +269,7 @@ static dbus_bool_t hal_device_add(struct userdata *u, const char *udi, case CAP_OSS: #ifdef HAVE_ALSA if (u->use_oss) -#endif +#endif m = hal_device_load_oss(u, udi, error); break; #endif @@ -533,9 +533,9 @@ int pa__init(pa_core *c, pa_module*m) { #endif #if defined(HAVE_ALSA) && defined(HAVE_OSS) u->use_oss = 0; - + if (n <= 0) { -#endif +#endif #ifdef HAVE_OSS n += hal_device_add_all(u, CAP_OSS); #endif @@ -546,7 +546,7 @@ int pa__init(pa_core *c, pa_module*m) { if (n > 0) u->use_oss = 1; } -#endif +#endif libhal_ctx_set_user_data(hal_ctx, u); libhal_ctx_set_device_added(hal_ctx, device_added_cb); diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 22b12ef7..9d4d0eac 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -172,11 +172,11 @@ static void do_write(struct userdata *u) { if (errno != EAGAIN) { pa_log("write() failed: %s", pa_cstrerror(errno)); - + clear_up(u); pa_module_unload_request(u->module); } - + break; } @@ -228,14 +228,14 @@ static void do_read(struct userdata *u) { assert(memchunk.memblock); if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); - + if (errno != EAGAIN) { pa_log("read() failed: %s", pa_cstrerror(errno)); - + clear_up(u); pa_module_unload_request(u->module); } - + break; } diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index db83756a..62ef561f 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -3,17 +3,17 @@ This file is part of PulseAudio. Copyright 2006 Lennart Poettering - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -145,7 +145,7 @@ static void rtp_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event pa_memchunk chunk; int64_t k, j, delta; struct timeval tv; - + assert(m); assert(e); assert(s); @@ -159,7 +159,7 @@ static void rtp_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event pa_memblock_unref(chunk.memblock); return; } - + if (!s->first_packet) { s->first_packet = 1; @@ -183,7 +183,7 @@ static void rtp_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event delta = k; else delta = j; - + pa_memblockq_seek(s->memblockq, delta * s->rtp_context.frame_size, PA_SEEK_RELATIVE); if (pa_memblockq_push(s->memblockq, &chunk) < 0) { @@ -191,10 +191,10 @@ static void rtp_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event pa_memblockq_flush(s->memblockq); pa_memblockq_push(s->memblockq, &chunk); } - + /* The next timestamp we expect */ s->offset = s->rtp_context.timestamp + (chunk.length / s->rtp_context.frame_size); - + pa_memblock_unref(chunk.memblock); /* Reset death timer */ @@ -205,7 +205,7 @@ static void rtp_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event static void death_event_cb(pa_mainloop_api *m, pa_time_event *t, const struct timeval *tv, void *userdata) { struct session *s = userdata; - + assert(m); assert(t); assert(tv); @@ -216,7 +216,7 @@ static void death_event_cb(pa_mainloop_api *m, pa_time_event *t, const struct ti static int mcast_socket(const struct sockaddr* sa, socklen_t salen) { int af, fd = -1, r, one; - + af = sa->sa_family; if ((fd = socket(af, SOCK_DGRAM, 0)) < 0) { pa_log("Failed to create socket: %s", pa_cstrerror(errno)); @@ -228,7 +228,7 @@ static int mcast_socket(const struct sockaddr* sa, socklen_t salen) { pa_log("SO_REUSEADDR failed: %s", pa_cstrerror(errno)); goto fail; } - + if (af == AF_INET) { struct ip_mreq mr4; memset(&mr4, 0, sizeof(mr4)); @@ -245,14 +245,14 @@ static int mcast_socket(const struct sockaddr* sa, socklen_t salen) { pa_log_info("Joining mcast group failed: %s", pa_cstrerror(errno)); goto fail; } - + if (bind(fd, sa, salen) < 0) { pa_log("bind() failed: %s", pa_cstrerror(errno)); goto fail; } return fd; - + fail: if (fd >= 0) close(fd); @@ -273,7 +273,7 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in pa_log("session limit reached."); goto fail; } - + if (!(sink = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) { pa_log("sink does not exist."); goto fail; @@ -289,7 +289,7 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in c = pa_sprintf_malloc("RTP Stream%s%s%s", sdp_info->session_name ? " (" : "", - sdp_info->session_name ? sdp_info->session_name : "", + sdp_info->session_name ? sdp_info->session_name : "", sdp_info->session_name ? ")" : ""); pa_sink_input_new_data_init(&data); @@ -298,10 +298,10 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in data.name = c; data.module = u->module; pa_sink_input_new_data_set_sample_spec(&data, &sdp_info->sample_spec); - + s->sink_input = pa_sink_input_new(u->core, &data, 0); pa_xfree(c); - + if (!s->sink_input) { pa_log("failed to create sink input."); goto fail; @@ -318,7 +318,7 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in &s->sink_input->sample_spec, (pa_bytes_per_second(&s->sink_input->sample_spec)/128/pa_frame_size(&s->sink_input->sample_spec))* pa_frame_size(&s->sink_input->sample_spec)); - + s->memblockq = pa_memblockq_new( 0, MEMBLOCKQ_MAXLENGTH, @@ -331,7 +331,7 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in pa_memblock_unref(silence); s->rtp_event = u->core->mainloop->io_new(u->core->mainloop, fd, PA_IO_EVENT_INPUT, rtp_event_cb, s); - + pa_gettimeofday(&tv); pa_timeval_add(&tv, DEATH_TIMEOUT); s->death_event = u->core->mainloop->time_new(u->core->mainloop, &tv, death_event_cb, s); @@ -343,14 +343,14 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in pa_log_info("Found new session '%s'", s->sdp_info.session_name); u->n_sessions++; - + return s; fail: if (s) { if (fd >= 0) close(fd); - + pa_xfree(s); } @@ -377,7 +377,7 @@ static void session_free(struct session *s, int from_hash) { assert(s->userdata->n_sessions >= 1); s->userdata->n_sessions--; - + pa_xfree(s); } @@ -386,7 +386,7 @@ static void sap_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event int goodbye; pa_sdp_info info; struct session *s; - + assert(m); assert(e); assert(u); @@ -410,14 +410,14 @@ static void sap_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event if (!(s = pa_hashmap_get(u->by_origin, info.origin))) { if (!(s = session_new(u, &info))) pa_sdp_info_destroy(&info); - + } else { struct timeval tv; - + pa_gettimeofday(&tv); pa_timeval_add(&tv, DEATH_TIMEOUT); m->time_restart(s->death_event, &tv); - + pa_sdp_info_destroy(&info); } } @@ -432,7 +432,7 @@ int pa__init(pa_core *c, pa_module*m) { socklen_t salen; const char *sap_address; int fd = -1; - + assert(c); assert(m); @@ -442,7 +442,7 @@ int pa__init(pa_core *c, pa_module*m) { } sap_address = pa_modargs_get_value(ma, "sap_address", DEFAULT_SAP_ADDRESS); - + if (inet_pton(AF_INET6, sap_address, &sa6.sin6_addr) > 0) { sa6.sin6_family = AF_INET6; sa6.sin6_port = htons(SAP_PORT); @@ -471,9 +471,9 @@ int pa__init(pa_core *c, pa_module*m) { u->sap_event = c->mainloop->io_new(c->mainloop, fd, PA_IO_EVENT_INPUT, sap_event_cb, u); u->by_origin = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - + pa_sap_context_init_recv(&u->sap_context, fd); - + pa_modargs_free(ma); return 0; @@ -484,7 +484,7 @@ fail: if (fd >= 0) close(fd); - + return -1; } @@ -504,7 +504,7 @@ void pa__done(pa_core *c, pa_module*m) { pa_sap_context_destroy(&u->sap_context); pa_hashmap_free(u->by_origin, free_func, NULL); - + pa_xfree(u->sink_name); pa_xfree(u); } diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 18e5e055..8c9e5f23 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -4,17 +4,17 @@ This file is part of PulseAudio. Copyright 2006 Lennart Poettering - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -111,7 +111,7 @@ static void source_output_push(pa_source_output *o, const pa_memchunk *chunk) { pa_log("Failed to push chunk into memblockq."); return; } - + pa_rtp_send(&u->rtp_context, u->mtu, u->memblockq); } @@ -138,7 +138,7 @@ static pa_usec_t source_output_get_latency (pa_source_output *o) { static void sap_event_cb(pa_mainloop_api *m, pa_time_event *t, const struct timeval *tv, void *userdata) { struct userdata *u = userdata; struct timeval next; - + assert(m); assert(t); assert(tv); @@ -172,7 +172,7 @@ int pa__init(pa_core *c, pa_module*m) { char hn[128], *n; int loop = 0; pa_source_output_new_data data; - + assert(c); assert(m); @@ -210,7 +210,7 @@ int pa__init(pa_core *c, pa_module*m) { payload = pa_rtp_payload_from_sample_spec(&ss); mtu = (DEFAULT_MTU/pa_frame_size(&ss))*pa_frame_size(&ss); - + if (pa_modargs_get_value_u32(ma, "mtu", &mtu) < 0 || mtu < 1 || mtu % pa_frame_size(&ss) != 0) { pa_log("invalid mtu."); goto fail; @@ -241,7 +241,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("invalid destination '%s'", dest); goto fail; } - + if ((fd = socket(af, SOCK_DGRAM, 0)) < 0) { pa_log("socket() failed: %s", pa_cstrerror(errno)); goto fail; @@ -275,7 +275,7 @@ int pa__init(pa_core *c, pa_module*m) { data.source = s; pa_source_output_new_data_set_sample_spec(&data, &ss); pa_source_output_new_data_set_channel_map(&data, &cm); - + if (!(o = pa_source_output_new(c, &data, 0))) { pa_log("failed to create source output."); goto fail; @@ -284,7 +284,7 @@ int pa__init(pa_core *c, pa_module*m) { o->push = source_output_push; o->kill = source_output_kill; o->get_latency = source_output_get_latency; - + u = pa_xnew(struct userdata, 1); m->userdata = u; o->userdata = u; @@ -292,7 +292,7 @@ int pa__init(pa_core *c, pa_module*m) { u->module = m; u->core = c; u->source_output = o; - + u->memblockq = pa_memblockq_new( 0, MEMBLOCKQ_MAXLENGTH, @@ -303,20 +303,20 @@ int pa__init(pa_core *c, pa_module*m) { NULL); u->mtu = mtu; - + k = sizeof(sa_dst); r = getsockname(fd, (struct sockaddr*) &sa_dst, &k); assert(r >= 0); n = pa_sprintf_malloc("PulseAudio RTP Stream on %s", pa_get_fqdn(hn, sizeof(hn))); - + p = pa_sdp_build(af, af == AF_INET ? (void*) &((struct sockaddr_in*) &sa_dst)->sin_addr : (void*) &((struct sockaddr_in6*) &sa_dst)->sin6_addr, af == AF_INET ? (void*) &sa4.sin_addr : (void*) &sa6.sin6_addr, n, port, payload, &ss); pa_xfree(n); - + pa_rtp_context_init_send(&u->rtp_context, fd, c->cookie, payload, pa_frame_size(&ss)); pa_sap_context_init_send(&u->sap_context, sap_fd, p); @@ -339,7 +339,7 @@ fail: if (fd >= 0) close(fd); - + if (sap_fd >= 0) close(sap_fd); @@ -347,7 +347,7 @@ fail: pa_source_output_disconnect(o); pa_source_output_unref(o); } - + return -1; } @@ -360,7 +360,7 @@ void pa__done(pa_core *c, pa_module*m) { return; c->mainloop->time_free(u->sap_event); - + if (u->source_output) { pa_source_output_disconnect(u->source_output); pa_source_output_unref(u->source_output); @@ -372,6 +372,6 @@ void pa__done(pa_core *c, pa_module*m) { pa_sap_context_destroy(&u->sap_context); pa_memblockq_free(u->memblockq); - + pa_xfree(u); } diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c index bc5260a8..03a01412 100644 --- a/src/modules/rtp/rtp.c +++ b/src/modules/rtp/rtp.c @@ -4,17 +4,17 @@ This file is part of PulseAudio. Copyright 2006 Lennart Poettering - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -53,7 +53,7 @@ pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssr c->ssrc = ssrc ? ssrc : (uint32_t) (rand()*rand()); c->payload = payload & 127; c->frame_size = frame_size; - + return c; } @@ -64,14 +64,14 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { pa_memblock* mb[MAX_IOVECS]; int iov_idx = 1; size_t n = 0, skip = 0; - + assert(c); assert(size > 0); assert(q); if (pa_memblockq_get_length(q) < size) return 0; - + for (;;) { int r; pa_memchunk chunk; @@ -105,7 +105,7 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { iov[0].iov_base = (void*)header; iov[0].iov_len = sizeof(header); - + m.msg_name = NULL; m.msg_namelen = 0; m.msg_iov = iov; @@ -113,7 +113,7 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { m.msg_control = NULL; m.msg_controllen = 0; m.msg_flags = 0; - + k = sendmsg(c->fd, &m, MSG_DONTWAIT); for (i = 1; i < iov_idx; i++) @@ -124,13 +124,13 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { k = 0; c->timestamp += skip/c->frame_size; - + if (k < 0) { if (errno != EAGAIN) /* If the queue is full, just ignore it */ pa_log("sendmsg() failed: %s", pa_cstrerror(errno)); return -1; } - + if (r < 0 || pa_memblockq_get_length(q) < size) break; @@ -158,7 +158,7 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { uint32_t header; int cc; ssize_t r; - + assert(c); assert(chunk); @@ -184,7 +184,7 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { m.msg_control = NULL; m.msg_controllen = 0; m.msg_flags = 0; - + if ((r = recvmsg(c->fd, &m, 0)) != size) { pa_log("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch"); goto fail; @@ -198,7 +198,7 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { memcpy(&header, chunk->memblock->data, sizeof(uint32_t)); memcpy(&c->timestamp, (uint8_t*) chunk->memblock->data + 4, sizeof(uint32_t)); memcpy(&c->ssrc, (uint8_t*) chunk->memblock->data + 8, sizeof(uint32_t)); - + header = ntohl(header); c->timestamp = ntohl(c->timestamp); c->ssrc = ntohl(c->ssrc); @@ -234,7 +234,7 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { pa_log("Vad RTP packet size."); goto fail; } - + return 0; fail: @@ -255,7 +255,7 @@ uint8_t pa_rtp_payload_from_sample_spec(const pa_sample_spec *ss) { return 10; if (ss->format == PA_SAMPLE_S16BE && ss->rate == 44100 && ss->channels == 1) return 11; - + return 127; } @@ -280,7 +280,7 @@ pa_sample_spec *pa_rtp_sample_spec_from_payload(uint8_t payload, pa_sample_spec ss->format = PA_SAMPLE_S16BE; ss->rate = 44100; break; - + case 11: ss->channels = 1; ss->format = PA_SAMPLE_S16BE; @@ -340,7 +340,7 @@ const char* pa_rtp_format_to_string(pa_sample_format_t f) { pa_sample_format_t pa_rtp_string_to_format(const char *s) { assert(s); - + if (!(strcmp(s, "L16"))) return PA_SAMPLE_S16BE; else if (!strcmp(s, "L8")) diff --git a/src/modules/rtp/rtp.h b/src/modules/rtp/rtp.h index db7acd98..ad7175ca 100644 --- a/src/modules/rtp/rtp.h +++ b/src/modules/rtp/rtp.h @@ -7,17 +7,17 @@ This file is part of PulseAudio. Copyright 2006 Lennart Poettering - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c index a6e92187..82421807 100644 --- a/src/modules/rtp/sap.c +++ b/src/modules/rtp/sap.c @@ -4,17 +4,17 @@ This file is part of PulseAudio. Copyright 2006 Lennart Poettering - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -60,8 +60,8 @@ pa_sap_context* pa_sap_context_init_send(pa_sap_context *c, int fd, char *sdp_da c->fd = fd; c->sdp_data = sdp_data; c->msg_id_hash = (uint16_t) (rand()*rand()); - - return c; + + return c; } void pa_sap_context_destroy(pa_sap_context *c) { @@ -86,7 +86,7 @@ int pa_sap_send(pa_sap_context *c, int goodbye) { } assert(sa->sa_family == AF_INET || sa->sa_family == AF_INET6); - + header = htonl(((uint32_t) 1 << 29) | (sa->sa_family == AF_INET6 ? (uint32_t) 1 << 28 : 0) | (goodbye ? (uint32_t) 1 << 26 : 0) | @@ -103,7 +103,7 @@ int pa_sap_send(pa_sap_context *c, int goodbye) { iov[3].iov_base = c->sdp_data; iov[3].iov_len = strlen(c->sdp_data); - + m.msg_name = NULL; m.msg_namelen = 0; m.msg_iov = iov; @@ -111,7 +111,7 @@ int pa_sap_send(pa_sap_context *c, int goodbye) { m.msg_control = NULL; m.msg_controllen = 0; m.msg_flags = 0; - + if ((k = sendmsg(c->fd, &m, MSG_DONTWAIT)) < 0) pa_log("sendmsg() failed: %s\n", pa_cstrerror(errno)); @@ -135,7 +135,7 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) { uint32_t header; int six, ac; ssize_t r; - + assert(c); assert(goodbye); @@ -146,7 +146,7 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) { buf = pa_xnew(char, size+1); buf[size] = 0; - + iov.iov_base = buf; iov.iov_len = size; @@ -157,7 +157,7 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) { m.msg_control = NULL; m.msg_controllen = 0; m.msg_flags = 0; - + if ((r = recvmsg(c->fd, &m, 0)) != size) { pa_log("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch"); goto fail; @@ -208,12 +208,12 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) { if (c->sdp_data) pa_xfree(c->sdp_data); - + c->sdp_data = pa_xstrndup(e, size); pa_xfree(buf); - + *goodbye = !!((header >> 26) & 1); - + return 0; fail: diff --git a/src/modules/rtp/sap.h b/src/modules/rtp/sap.h index cac697e6..f906a32b 100644 --- a/src/modules/rtp/sap.h +++ b/src/modules/rtp/sap.h @@ -7,17 +7,17 @@ This file is part of PulseAudio. Copyright 2006 Lennart Poettering - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/modules/rtp/sdp.c b/src/modules/rtp/sdp.c index 7f0e7027..8b0bd535 100644 --- a/src/modules/rtp/sdp.c +++ b/src/modules/rtp/sdp.c @@ -4,17 +4,17 @@ This file is part of PulseAudio. Copyright 2006 Lennart Poettering - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -54,18 +54,18 @@ char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, u f = pa_rtp_format_to_string(ss->format); assert(f); - + if (!(u = getenv("USER"))) if (!(u = getenv("USERNAME"))) u = "-"; - + ntp = time(NULL) + 2208988800U; a = inet_ntop(af, src, buf_src, sizeof(buf_src)); assert(a); a = inet_ntop(af, dst, buf_dst, sizeof(buf_dst)); assert(a); - + return pa_sprintf_malloc( PA_SDP_HEADER "o=%s %lu 0 IN %s %s\n" @@ -125,11 +125,11 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { assert(t); assert(i); - + i->origin = i->session_name = NULL; i->salen = 0; i->payload = 255; - + if (!pa_startswith(t, PA_SDP_HEADER)) { pa_log("Failed to parse SDP data: invalid header."); goto fail; @@ -156,7 +156,7 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { size_t k; k = l-8 > sizeof(a) ? sizeof(a) : l-8; - + pa_strlcpy(a, t+9, k); a[strcspn(a, "/")] = 0; @@ -173,7 +173,7 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { size_t k; k = l-8 > sizeof(a) ? sizeof(a) : l-8; - + pa_strlcpy(a, t+9, k); a[strcspn(a, "/")] = 0; @@ -189,7 +189,7 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { if (i->payload > 127) { int _port, _payload; - + if (sscanf(t+8, "%i RTP/AVP %i", &_port, &_payload) == 2) { if (_port <= 0 || _port > 0xFFFF) { @@ -224,16 +224,16 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { if (_payload == i->payload) { c[strcspn(c, "\n")] = 0; - + if (parse_sdp_sample_spec(&i->sample_spec, c)) ss_valid = 1; } } } } - + t += l; - + if (*t == '\n') t++; } @@ -247,7 +247,7 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { ((struct sockaddr_in*) &i->sa)->sin_port = htons(port); else ((struct sockaddr_in6*) &i->sa)->sin6_port = htons(port); - + return i; fail: diff --git a/src/modules/rtp/sdp.h b/src/modules/rtp/sdp.h index 4c68ac5a..7c91fca6 100644 --- a/src/modules/rtp/sdp.h +++ b/src/modules/rtp/sdp.h @@ -7,17 +7,17 @@ This file is part of PulseAudio. Copyright 2006 Lennart Poettering - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index 4dbf3afa..6989069d 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -1033,10 +1033,10 @@ int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *b if (ifstate && *ifstate == IFSTATE_FALSE) return 0; - + l = strcspn(cs, whitespace); - + for (command = commands; command->name; command++) if (strlen(command->name) == l && !strncmp(cs, command->name, l)) { int ret; @@ -1071,7 +1071,7 @@ int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int FILE *f = NULL; int ifstate = IFSTATE_NONE; int ret = -1; - + assert(c); assert(fn); assert(buf); @@ -1103,7 +1103,7 @@ fail: int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { const char *p; int ifstate = IFSTATE_NONE; - + assert(c); assert(s); assert(buf); diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 5159934d..e5766b2f 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -492,7 +492,7 @@ void pa_raise_priority(void) { if ((caps = cap_get_proc())) { cap_t caps_new; cap_value_t nice_cap = CAP_SYS_NICE; - + if ((caps_new = cap_dup(caps))) { cap_set_flag(caps_new, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET); cap_set_flag(caps_new, CAP_PERMITTED, 1, &nice_cap, CAP_SET); @@ -501,7 +501,7 @@ void pa_raise_priority(void) { } } #endif - + #ifdef HAVE_SYS_RESOURCE_H if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) pa_log_warn("setpriority(): %s", pa_cstrerror(errno)); diff --git a/src/pulsecore/g711.c b/src/pulsecore/g711.c index 55a82396..8c2bbf00 100644 --- a/src/pulsecore/g711.c +++ b/src/pulsecore/g711.c @@ -1,2531 +1,2531 @@ -/* - * This source code is a product of Sun Microsystems, Inc. and is provided - * for unrestricted use. Users may copy or modify this source code without - * charge. - * - * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING - * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR - * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * - * Sun source code is provided with no support and without any obligation on - * the part of Sun Microsystems, Inc. to assist in its use, correction, - * modification or enhancement. - * - * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE - * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE - * OR ANY PART THEREOF. - * - * In no event will Sun Microsystems, Inc. be liable for any lost revenue - * or profits or other special, indirect and consequential damages, even if - * Sun has been advised of the possibility of such damages. - * - * Sun Microsystems, Inc. - * 2550 Garcia Avenue - * Mountain View, California 94043 - */ - -/* - * g711.c - * - * u-law, A-law and linear PCM conversions. - */ - -/* - * December 30, 1994: - * Functions linear2alaw, linear2ulaw have been updated to correctly - * convert unquantized 16 bit values. - * Tables for direct u- to A-law and A- to u-law conversions have been - * corrected. - * Borge Lindberg, Center for PersonKommunikation, Aalborg University. - * bli@cpk.auc.dk - * - */ - -#include "g711.h" - -#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ -#define QUANT_MASK (0xf) /* Quantization field mask. */ -#define NSEGS (8) /* Number of A-law segments. */ -#define SEG_SHIFT (4) /* Left shift for segment number. */ -#define SEG_MASK (0x70) /* Segment field mask. */ - -#if !defined(FAST_ALAW_CONVERSION) || !defined(FAST_ULAW_CONVERSION) -static int16_t seg_aend[8] = {0x1F, 0x3F, 0x7F, 0xFF, - 0x1FF, 0x3FF, 0x7FF, 0xFFF}; -static int16_t seg_uend[8] = {0x3F, 0x7F, 0xFF, 0x1FF, - 0x3FF, 0x7FF, 0xFFF, 0x1FFF}; - -static int16_t search( - int16_t val, - int16_t *table, - int size) -{ - int i; - - for (i = 0; i < size; i++) { - if (val <= *table++) - return (i); - } - return (size); -} -#endif /* !FAST_*_CONVERSION */ - -#ifndef FAST_ALAW_CONVERSION -/* - * linear2alaw() accepts an 13-bit signed integer and encodes it as A-law data - * stored in a unsigned char. This function should only be called with - * the data shifted such that it only contains information in the lower - * 13-bits. - * - * Linear Input Code Compressed Code - * ------------------------ --------------- - * 0000000wxyza 000wxyz - * 0000001wxyza 001wxyz - * 000001wxyzab 010wxyz - * 00001wxyzabc 011wxyz - * 0001wxyzabcd 100wxyz - * 001wxyzabcde 101wxyz - * 01wxyzabcdef 110wxyz - * 1wxyzabcdefg 111wxyz - * - * For further information see John C. Bellamy's Digital Telephony, 1982, - * John Wiley & Sons, pps 98-111 and 472-476. - */ -unsigned char st_13linear2alaw( - int16_t pcm_val) /* 2's complement (13-bit range) */ -{ - int16_t mask; - short seg; - unsigned char aval; - - /* Have calling software do it since its already doing a shift - * from 32-bits down to 16-bits. - */ - /* pcm_val = pcm_val >> 3; */ - - /* A-law using even bit inversion */ - if (pcm_val >= 0) { - mask = 0xD5; /* sign (7th) bit = 1 */ - } else { - mask = 0x55; /* sign bit = 0 */ - pcm_val = -pcm_val - 1; - } - - /* Convert the scaled magnitude to segment number. */ - seg = search(pcm_val, seg_aend, 8); - - /* Combine the sign, segment, and quantization bits. */ - - if (seg >= 8) /* out of range, return maximum value. */ - return (unsigned char) (0x7F ^ mask); - else { - aval = (unsigned char) seg << SEG_SHIFT; - if (seg < 2) - aval |= (pcm_val >> 1) & QUANT_MASK; - else - aval |= (pcm_val >> seg) & QUANT_MASK; - return (aval ^ mask); - } -} - -/* - * alaw2linear() - Convert an A-law value to 16-bit signed linear PCM - * - */ -int16_t st_alaw2linear16( - unsigned char a_val) -{ - int16_t t; - int16_t seg; - - a_val ^= 0x55; - - t = (a_val & QUANT_MASK) << 4; - seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT; - switch (seg) { - case 0: - t += 8; - break; - case 1: - t += 0x108; - break; - default: - t += 0x108; - t <<= seg - 1; - } - return ((a_val & SIGN_BIT) ? t : -t); -} -#endif /* !FAST_ALAW_CONVERSION */ - -#define BIAS (0x84) /* Bias for linear code. */ -#define CLIP 8159 - -#ifndef FAST_ULAW_CONVERSION -/* - * linear2ulaw() accepts a 14-bit signed integer and encodes it as u-law data - * stored in a unsigned char. This function should only be called with - * the data shifted such that it only contains information in the lower - * 14-bits. - * - * In order to simplify the encoding process, the original linear magnitude - * is biased by adding 33 which shifts the encoding range from (0 - 8158) to - * (33 - 8191). The result can be seen in the following encoding table: - * - * Biased Linear Input Code Compressed Code - * ------------------------ --------------- - * 00000001wxyza 000wxyz - * 0000001wxyzab 001wxyz - * 000001wxyzabc 010wxyz - * 00001wxyzabcd 011wxyz - * 0001wxyzabcde 100wxyz - * 001wxyzabcdef 101wxyz - * 01wxyzabcdefg 110wxyz - * 1wxyzabcdefgh 111wxyz - * - * Each biased linear code has a leading 1 which identifies the segment - * number. The value of the segment number is equal to 7 minus the number - * of leading 0's. The quantization interval is directly available as the - * four bits wxyz. * The trailing bits (a - h) are ignored. - * - * Ordinarily the complement of the resulting code word is used for - * transmission, and so the code word is complemented before it is returned. - * - * For further information see John C. Bellamy's Digital Telephony, 1982, - * John Wiley & Sons, pps 98-111 and 472-476. - */ -unsigned char st_14linear2ulaw( - int16_t pcm_val) /* 2's complement (14-bit range) */ -{ - int16_t mask; - int16_t seg; - unsigned char uval; - - /* Have calling software do it since its already doing a shift - * from 32-bits down to 16-bits. - */ - /* pcm_val = pcm_val >> 2; */ - - /* u-law inverts all bits */ - /* Get the sign and the magnitude of the value. */ - if (pcm_val < 0) { - pcm_val = -pcm_val; - mask = 0x7F; - } else { - mask = 0xFF; - } - if ( pcm_val > CLIP ) pcm_val = CLIP; /* clip the magnitude */ - pcm_val += (BIAS >> 2); - - /* Convert the scaled magnitude to segment number. */ - seg = search(pcm_val, seg_uend, 8); - - /* - * Combine the sign, segment, quantization bits; - * and complement the code word. - */ - if (seg >= 8) /* out of range, return maximum value. */ - return (unsigned char) (0x7F ^ mask); - else { - uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF); - return (uval ^ mask); - } - -} - -/* - * ulaw2linear() - Convert a u-law value to 16-bit linear PCM - * - * First, a biased linear code is derived from the code word. An unbiased - * output can then be obtained by subtracting 33 from the biased code. - * - * Note that this function expects to be passed the complement of the - * original code word. This is in keeping with ISDN conventions. - */ -int16_t st_ulaw2linear16( - unsigned char u_val) -{ - int16_t t; - - /* Complement to obtain normal u-law value. */ - u_val = ~u_val; - - /* - * Extract and bias the quantization bits. Then - * shift up by the segment number and subtract out the bias. - */ - t = ((u_val & QUANT_MASK) << 3) + BIAS; - t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; - - return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); -} -#endif /* !FAST_ULAW_CONVERSION */ - -#ifdef FAST_ALAW_CONVERSION - -int16_t _st_alaw2linear16[256] = { - -5504, -5248, -6016, -5760, -4480, -4224, -4992, - -4736, -7552, -7296, -8064, -7808, -6528, -6272, - -7040, -6784, -2752, -2624, -3008, -2880, -2240, - -2112, -2496, -2368, -3776, -3648, -4032, -3904, - -3264, -3136, -3520, -3392, -22016, -20992, -24064, - -23040, -17920, -16896, -19968, -18944, -30208, -29184, - -32256, -31232, -26112, -25088, -28160, -27136, -11008, - -10496, -12032, -11520, -8960, -8448, -9984, -9472, - -15104, -14592, -16128, -15616, -13056, -12544, -14080, - -13568, -344, -328, -376, -360, -280, -264, - -312, -296, -472, -456, -504, -488, -408, - -392, -440, -424, -88, -72, -120, -104, - -24, -8, -56, -40, -216, -200, -248, - -232, -152, -136, -184, -168, -1376, -1312, - -1504, -1440, -1120, -1056, -1248, -1184, -1888, - -1824, -2016, -1952, -1632, -1568, -1760, -1696, - -688, -656, -752, -720, -560, -528, -624, - -592, -944, -912, -1008, -976, -816, -784, - -880, -848, 5504, 5248, 6016, 5760, 4480, - 4224, 4992, 4736, 7552, 7296, 8064, 7808, - 6528, 6272, 7040, 6784, 2752, 2624, 3008, - 2880, 2240, 2112, 2496, 2368, 3776, 3648, - 4032, 3904, 3264, 3136, 3520, 3392, 22016, - 20992, 24064, 23040, 17920, 16896, 19968, 18944, - 30208, 29184, 32256, 31232, 26112, 25088, 28160, - 27136, 11008, 10496, 12032, 11520, 8960, 8448, - 9984, 9472, 15104, 14592, 16128, 15616, 13056, - 12544, 14080, 13568, 344, 328, 376, 360, - 280, 264, 312, 296, 472, 456, 504, - 488, 408, 392, 440, 424, 88, 72, - 120, 104, 24, 8, 56, 40, 216, - 200, 248, 232, 152, 136, 184, 168, - 1376, 1312, 1504, 1440, 1120, 1056, 1248, - 1184, 1888, 1824, 2016, 1952, 1632, 1568, - 1760, 1696, 688, 656, 752, 720, 560, - 528, 624, 592, 944, 912, 1008, 976, - 816, 784, 880, 848 -}; - -uint8_t _st_13linear2alaw[0x2000] = { - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, - 0x6b, 0x6b, 0x6b, 0x6b, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, - 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x6e, 0x6e, 0x6e, 0x6e, - 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, - 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, - 0x6d, 0x6d, 0x6d, 0x6d, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x60, 0x60, 0x60, 0x60, - 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, - 0x67, 0x67, 0x67, 0x67, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, - 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x7a, 0x7a, 0x7a, 0x7a, - 0x7b, 0x7b, 0x7b, 0x7b, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, - 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7c, 0x7c, 0x7c, 0x7c, - 0x7d, 0x7d, 0x7d, 0x7d, 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x73, - 0x70, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x71, 0x76, 0x76, 0x76, 0x76, - 0x77, 0x77, 0x77, 0x77, 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x75, - 0x4a, 0x4a, 0x4b, 0x4b, 0x48, 0x48, 0x49, 0x49, 0x4e, 0x4e, 0x4f, 0x4f, - 0x4c, 0x4c, 0x4d, 0x4d, 0x42, 0x42, 0x43, 0x43, 0x40, 0x40, 0x41, 0x41, - 0x46, 0x46, 0x47, 0x47, 0x44, 0x44, 0x45, 0x45, 0x5a, 0x5a, 0x5b, 0x5b, - 0x58, 0x58, 0x59, 0x59, 0x5e, 0x5e, 0x5f, 0x5f, 0x5c, 0x5c, 0x5d, 0x5d, - 0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51, 0x56, 0x56, 0x57, 0x57, - 0x54, 0x54, 0x55, 0x55, 0xd5, 0xd5, 0xd4, 0xd4, 0xd7, 0xd7, 0xd6, 0xd6, - 0xd1, 0xd1, 0xd0, 0xd0, 0xd3, 0xd3, 0xd2, 0xd2, 0xdd, 0xdd, 0xdc, 0xdc, - 0xdf, 0xdf, 0xde, 0xde, 0xd9, 0xd9, 0xd8, 0xd8, 0xdb, 0xdb, 0xda, 0xda, - 0xc5, 0xc5, 0xc4, 0xc4, 0xc7, 0xc7, 0xc6, 0xc6, 0xc1, 0xc1, 0xc0, 0xc0, - 0xc3, 0xc3, 0xc2, 0xc2, 0xcd, 0xcd, 0xcc, 0xcc, 0xcf, 0xcf, 0xce, 0xce, - 0xc9, 0xc9, 0xc8, 0xc8, 0xcb, 0xcb, 0xca, 0xca, 0xf5, 0xf5, 0xf5, 0xf5, - 0xf4, 0xf4, 0xf4, 0xf4, 0xf7, 0xf7, 0xf7, 0xf7, 0xf6, 0xf6, 0xf6, 0xf6, - 0xf1, 0xf1, 0xf1, 0xf1, 0xf0, 0xf0, 0xf0, 0xf0, 0xf3, 0xf3, 0xf3, 0xf3, - 0xf2, 0xf2, 0xf2, 0xf2, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xf9, 0xf9, 0xf9, 0xf9, - 0xf8, 0xf8, 0xf8, 0xf8, 0xfb, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xfa, - 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4, - 0xe4, 0xe4, 0xe4, 0xe4, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, - 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe1, 0xe1, 0xe1, 0xe1, - 0xe1, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, - 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, - 0xe2, 0xe2, 0xe2, 0xe2, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, - 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xef, 0xef, 0xef, 0xef, - 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, - 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, - 0xe8, 0xe8, 0xe8, 0xe8, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, - 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa -}; - -#endif /* FAST_ALAW_CONVERSION */ - -#ifdef FAST_ULAW_CONVERSION - -int16_t _st_ulaw2linear16[256] = { - -32124, -31100, -30076, -29052, -28028, -27004, -25980, - -24956, -23932, -22908, -21884, -20860, -19836, -18812, - -17788, -16764, -15996, -15484, -14972, -14460, -13948, - -13436, -12924, -12412, -11900, -11388, -10876, -10364, - -9852, -9340, -8828, -8316, -7932, -7676, -7420, - -7164, -6908, -6652, -6396, -6140, -5884, -5628, - -5372, -5116, -4860, -4604, -4348, -4092, -3900, - -3772, -3644, -3516, -3388, -3260, -3132, -3004, - -2876, -2748, -2620, -2492, -2364, -2236, -2108, - -1980, -1884, -1820, -1756, -1692, -1628, -1564, - -1500, -1436, -1372, -1308, -1244, -1180, -1116, - -1052, -988, -924, -876, -844, -812, -780, - -748, -716, -684, -652, -620, -588, -556, - -524, -492, -460, -428, -396, -372, -356, - -340, -324, -308, -292, -276, -260, -244, - -228, -212, -196, -180, -164, -148, -132, - -120, -112, -104, -96, -88, -80, -72, - -64, -56, -48, -40, -32, -24, -16, - -8, 0, 32124, 31100, 30076, 29052, 28028, - 27004, 25980, 24956, 23932, 22908, 21884, 20860, - 19836, 18812, 17788, 16764, 15996, 15484, 14972, - 14460, 13948, 13436, 12924, 12412, 11900, 11388, - 10876, 10364, 9852, 9340, 8828, 8316, 7932, - 7676, 7420, 7164, 6908, 6652, 6396, 6140, - 5884, 5628, 5372, 5116, 4860, 4604, 4348, - 4092, 3900, 3772, 3644, 3516, 3388, 3260, - 3132, 3004, 2876, 2748, 2620, 2492, 2364, - 2236, 2108, 1980, 1884, 1820, 1756, 1692, - 1628, 1564, 1500, 1436, 1372, 1308, 1244, - 1180, 1116, 1052, 988, 924, 876, 844, - 812, 780, 748, 716, 684, 652, 620, - 588, 556, 524, 492, 460, 428, 396, - 372, 356, 340, 324, 308, 292, 276, - 260, 244, 228, 212, 196, 180, 164, - 148, 132, 120, 112, 104, 96, 88, - 80, 72, 64, 56, 48, 40, 32, - 24, 16, 8, 0 -}; - -uint8_t _st_14linear2ulaw[0x4000] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x40, 0x40, - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, - 0x40, 0x40, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, - 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, - 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, - 0x43, 0x43, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, - 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, - 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x46, 0x46, - 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, - 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, - 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, - 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, - 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, - 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, - 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, - 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, - 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, - 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, - 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, - 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, - 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, - 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, - 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, - 0x52, 0x52, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, - 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x57, 0x57, - 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, - 0x58, 0x58, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a, 0x5a, - 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, - 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, - 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, - 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x60, 0x60, - 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x62, 0x63, 0x63, - 0x63, 0x63, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, - 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, - 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, - 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, - 0x6f, 0x6f, 0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x74, 0x74, - 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a, - 0x7b, 0x7b, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0xff, 0xfe, 0xfe, 0xfd, - 0xfd, 0xfc, 0xfc, 0xfb, 0xfb, 0xfa, 0xfa, 0xf9, 0xf9, 0xf8, 0xf8, 0xf7, - 0xf7, 0xf6, 0xf6, 0xf5, 0xf5, 0xf4, 0xf4, 0xf3, 0xf3, 0xf2, 0xf2, 0xf1, - 0xf1, 0xf0, 0xf0, 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xed, - 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xeb, 0xeb, 0xeb, 0xeb, 0xea, - 0xea, 0xea, 0xea, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, 0xe7, - 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, - 0xe4, 0xe4, 0xe4, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, 0xe1, - 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, - 0xdf, 0xdf, 0xdf, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, - 0xdc, 0xdc, 0xdc, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xda, - 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, - 0xd9, 0xd9, 0xd9, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd7, - 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, - 0xd6, 0xd6, 0xd6, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd4, - 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, - 0xd3, 0xd3, 0xd3, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd1, - 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, - 0xd0, 0xd0, 0xd0, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, - 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xce, 0xce, 0xce, 0xce, 0xce, - 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xcd, - 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, - 0xcd, 0xcd, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, - 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, - 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xca, - 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, - 0xca, 0xca, 0xca, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, - 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, - 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc7, - 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, - 0xc7, 0xc7, 0xc7, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, - 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, - 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc4, - 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, - 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, - 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, - 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc1, - 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, - 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, - 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80 -}; - -#endif /* FAST_ULAW_CONVERSION */ - -/* The following code was used to generate the lookup tables */ -#if 0 -int main() -{ - int x, y, find2a = 0; - - y = 0; - printf("int16_t _st_alaw2linear16[256] = {\n "); - for (x = 0; x < 256; x++) - { - printf("%8d,", st_alaw2linear16(x)); - y++; - if (y == 7) - { - y = 0; - printf("\n "); - } - } - - printf("\n};\n\nuint8_t _st_13linear2alaw[0x2000] = {\n "); - y = 0; - for (x = 0; x < 0x2000; x++) - { - printf(" 0x%02x,", st_13linear2alaw((-0x1000)+x)); - y++; - if (y == 12) - { - y = 0; - printf("\n "); - } - } - - printf("\n};\n\nint16_t _st_ulaw2linear16[256] = {\n "); - y = 0; - for (x = 0; x < 256; x++) - { - printf("%8d,", st_ulaw2linear16(x)); - y++; - if (y == 7) - { - y = 0; - printf("\n "); - } - } - - printf("\n};\n\nuint8_t _st_14linear2ulaw[0x4000] = {\n "); - y = 0; - for (x = 0; x < 0x4000; x++) - { - printf(" 0x%02x,", st_14linear2ulaw((-0x2000)+x)); - y++; - if (y == 12) - { - y = 0; - printf("\n "); - } - } - printf("\n};\n"); - -} -#endif - -/* The following is not used by SoX but kept for reference */ -#if 0 -/* copy from CCITT G.711 specifications */ -unsigned char _u2a[128] = { /* u- to A-law conversions */ - 1, 1, 2, 2, 3, 3, 4, 4, - 5, 5, 6, 6, 7, 7, 8, 8, - 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, - 25, 27, 29, 31, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, - 46, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, - 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, -/* corrected: - 81, 82, 83, 84, 85, 86, 87, 88, - should be: */ - 80, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, 126, 127, 128}; - -unsigned char _a2u[128] = { /* A- to u-law conversions */ - 1, 3, 5, 7, 9, 11, 13, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 32, 33, 33, 34, 34, 35, 35, - 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 48, 49, 49, - 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 64, - 65, 66, 67, 68, 69, 70, 71, 72, -/* corrected: - 73, 74, 75, 76, 77, 78, 79, 79, - should be: */ - 73, 74, 75, 76, 77, 78, 79, 80, - - 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127}; - -/* A-law to u-law conversion */ -unsigned char st_alaw2ulaw( - unsigned char aval) -{ - aval &= 0xff; - return (unsigned char) ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) : - (0x7F ^ _a2u[aval ^ 0x55])); -} - -/* u-law to A-law conversion */ -unsigned char st_ulaw2alaw( - unsigned char uval) -{ - uval &= 0xff; - return (unsigned char) ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) : - (unsigned char) (0x55 ^ (_u2a[0x7F ^ uval] - 1))); -} -#endif +/* + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * g711.c + * + * u-law, A-law and linear PCM conversions. + */ + +/* + * December 30, 1994: + * Functions linear2alaw, linear2ulaw have been updated to correctly + * convert unquantized 16 bit values. + * Tables for direct u- to A-law and A- to u-law conversions have been + * corrected. + * Borge Lindberg, Center for PersonKommunikation, Aalborg University. + * bli@cpk.auc.dk + * + */ + +#include "g711.h" + +#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ +#define QUANT_MASK (0xf) /* Quantization field mask. */ +#define NSEGS (8) /* Number of A-law segments. */ +#define SEG_SHIFT (4) /* Left shift for segment number. */ +#define SEG_MASK (0x70) /* Segment field mask. */ + +#if !defined(FAST_ALAW_CONVERSION) || !defined(FAST_ULAW_CONVERSION) +static int16_t seg_aend[8] = {0x1F, 0x3F, 0x7F, 0xFF, + 0x1FF, 0x3FF, 0x7FF, 0xFFF}; +static int16_t seg_uend[8] = {0x3F, 0x7F, 0xFF, 0x1FF, + 0x3FF, 0x7FF, 0xFFF, 0x1FFF}; + +static int16_t search( + int16_t val, + int16_t *table, + int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (val <= *table++) + return (i); + } + return (size); +} +#endif /* !FAST_*_CONVERSION */ + +#ifndef FAST_ALAW_CONVERSION +/* + * linear2alaw() accepts an 13-bit signed integer and encodes it as A-law data + * stored in a unsigned char. This function should only be called with + * the data shifted such that it only contains information in the lower + * 13-bits. + * + * Linear Input Code Compressed Code + * ------------------------ --------------- + * 0000000wxyza 000wxyz + * 0000001wxyza 001wxyz + * 000001wxyzab 010wxyz + * 00001wxyzabc 011wxyz + * 0001wxyzabcd 100wxyz + * 001wxyzabcde 101wxyz + * 01wxyzabcdef 110wxyz + * 1wxyzabcdefg 111wxyz + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ +unsigned char st_13linear2alaw( + int16_t pcm_val) /* 2's complement (13-bit range) */ +{ + int16_t mask; + short seg; + unsigned char aval; + + /* Have calling software do it since its already doing a shift + * from 32-bits down to 16-bits. + */ + /* pcm_val = pcm_val >> 3; */ + + /* A-law using even bit inversion */ + if (pcm_val >= 0) { + mask = 0xD5; /* sign (7th) bit = 1 */ + } else { + mask = 0x55; /* sign bit = 0 */ + pcm_val = -pcm_val - 1; + } + + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_aend, 8); + + /* Combine the sign, segment, and quantization bits. */ + + if (seg >= 8) /* out of range, return maximum value. */ + return (unsigned char) (0x7F ^ mask); + else { + aval = (unsigned char) seg << SEG_SHIFT; + if (seg < 2) + aval |= (pcm_val >> 1) & QUANT_MASK; + else + aval |= (pcm_val >> seg) & QUANT_MASK; + return (aval ^ mask); + } +} + +/* + * alaw2linear() - Convert an A-law value to 16-bit signed linear PCM + * + */ +int16_t st_alaw2linear16( + unsigned char a_val) +{ + int16_t t; + int16_t seg; + + a_val ^= 0x55; + + t = (a_val & QUANT_MASK) << 4; + seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT; + switch (seg) { + case 0: + t += 8; + break; + case 1: + t += 0x108; + break; + default: + t += 0x108; + t <<= seg - 1; + } + return ((a_val & SIGN_BIT) ? t : -t); +} +#endif /* !FAST_ALAW_CONVERSION */ + +#define BIAS (0x84) /* Bias for linear code. */ +#define CLIP 8159 + +#ifndef FAST_ULAW_CONVERSION +/* + * linear2ulaw() accepts a 14-bit signed integer and encodes it as u-law data + * stored in a unsigned char. This function should only be called with + * the data shifted such that it only contains information in the lower + * 14-bits. + * + * In order to simplify the encoding process, the original linear magnitude + * is biased by adding 33 which shifts the encoding range from (0 - 8158) to + * (33 - 8191). The result can be seen in the following encoding table: + * + * Biased Linear Input Code Compressed Code + * ------------------------ --------------- + * 00000001wxyza 000wxyz + * 0000001wxyzab 001wxyz + * 000001wxyzabc 010wxyz + * 00001wxyzabcd 011wxyz + * 0001wxyzabcde 100wxyz + * 001wxyzabcdef 101wxyz + * 01wxyzabcdefg 110wxyz + * 1wxyzabcdefgh 111wxyz + * + * Each biased linear code has a leading 1 which identifies the segment + * number. The value of the segment number is equal to 7 minus the number + * of leading 0's. The quantization interval is directly available as the + * four bits wxyz. * The trailing bits (a - h) are ignored. + * + * Ordinarily the complement of the resulting code word is used for + * transmission, and so the code word is complemented before it is returned. + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ +unsigned char st_14linear2ulaw( + int16_t pcm_val) /* 2's complement (14-bit range) */ +{ + int16_t mask; + int16_t seg; + unsigned char uval; + + /* Have calling software do it since its already doing a shift + * from 32-bits down to 16-bits. + */ + /* pcm_val = pcm_val >> 2; */ + + /* u-law inverts all bits */ + /* Get the sign and the magnitude of the value. */ + if (pcm_val < 0) { + pcm_val = -pcm_val; + mask = 0x7F; + } else { + mask = 0xFF; + } + if ( pcm_val > CLIP ) pcm_val = CLIP; /* clip the magnitude */ + pcm_val += (BIAS >> 2); + + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_uend, 8); + + /* + * Combine the sign, segment, quantization bits; + * and complement the code word. + */ + if (seg >= 8) /* out of range, return maximum value. */ + return (unsigned char) (0x7F ^ mask); + else { + uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF); + return (uval ^ mask); + } + +} + +/* + * ulaw2linear() - Convert a u-law value to 16-bit linear PCM + * + * First, a biased linear code is derived from the code word. An unbiased + * output can then be obtained by subtracting 33 from the biased code. + * + * Note that this function expects to be passed the complement of the + * original code word. This is in keeping with ISDN conventions. + */ +int16_t st_ulaw2linear16( + unsigned char u_val) +{ + int16_t t; + + /* Complement to obtain normal u-law value. */ + u_val = ~u_val; + + /* + * Extract and bias the quantization bits. Then + * shift up by the segment number and subtract out the bias. + */ + t = ((u_val & QUANT_MASK) << 3) + BIAS; + t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; + + return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); +} +#endif /* !FAST_ULAW_CONVERSION */ + +#ifdef FAST_ALAW_CONVERSION + +int16_t _st_alaw2linear16[256] = { + -5504, -5248, -6016, -5760, -4480, -4224, -4992, + -4736, -7552, -7296, -8064, -7808, -6528, -6272, + -7040, -6784, -2752, -2624, -3008, -2880, -2240, + -2112, -2496, -2368, -3776, -3648, -4032, -3904, + -3264, -3136, -3520, -3392, -22016, -20992, -24064, + -23040, -17920, -16896, -19968, -18944, -30208, -29184, + -32256, -31232, -26112, -25088, -28160, -27136, -11008, + -10496, -12032, -11520, -8960, -8448, -9984, -9472, + -15104, -14592, -16128, -15616, -13056, -12544, -14080, + -13568, -344, -328, -376, -360, -280, -264, + -312, -296, -472, -456, -504, -488, -408, + -392, -440, -424, -88, -72, -120, -104, + -24, -8, -56, -40, -216, -200, -248, + -232, -152, -136, -184, -168, -1376, -1312, + -1504, -1440, -1120, -1056, -1248, -1184, -1888, + -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, + -592, -944, -912, -1008, -976, -816, -784, + -880, -848, 5504, 5248, 6016, 5760, 4480, + 4224, 4992, 4736, 7552, 7296, 8064, 7808, + 6528, 6272, 7040, 6784, 2752, 2624, 3008, + 2880, 2240, 2112, 2496, 2368, 3776, 3648, + 4032, 3904, 3264, 3136, 3520, 3392, 22016, + 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, + 27136, 11008, 10496, 12032, 11520, 8960, 8448, + 9984, 9472, 15104, 14592, 16128, 15616, 13056, + 12544, 14080, 13568, 344, 328, 376, 360, + 280, 264, 312, 296, 472, 456, 504, + 488, 408, 392, 440, 424, 88, 72, + 120, 104, 24, 8, 56, 40, 216, + 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, + 1184, 1888, 1824, 2016, 1952, 1632, 1568, + 1760, 1696, 688, 656, 752, 720, 560, + 528, 624, 592, 944, 912, 1008, 976, + 816, 784, 880, 848 +}; + +uint8_t _st_13linear2alaw[0x2000] = { + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, + 0x6b, 0x6b, 0x6b, 0x6b, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, + 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x6e, 0x6e, 0x6e, 0x6e, + 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, + 0x6d, 0x6d, 0x6d, 0x6d, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x60, 0x60, 0x60, 0x60, + 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, + 0x67, 0x67, 0x67, 0x67, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, + 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x7a, 0x7a, 0x7a, 0x7a, + 0x7b, 0x7b, 0x7b, 0x7b, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7c, 0x7c, 0x7c, 0x7c, + 0x7d, 0x7d, 0x7d, 0x7d, 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x73, + 0x70, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x71, 0x76, 0x76, 0x76, 0x76, + 0x77, 0x77, 0x77, 0x77, 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x75, + 0x4a, 0x4a, 0x4b, 0x4b, 0x48, 0x48, 0x49, 0x49, 0x4e, 0x4e, 0x4f, 0x4f, + 0x4c, 0x4c, 0x4d, 0x4d, 0x42, 0x42, 0x43, 0x43, 0x40, 0x40, 0x41, 0x41, + 0x46, 0x46, 0x47, 0x47, 0x44, 0x44, 0x45, 0x45, 0x5a, 0x5a, 0x5b, 0x5b, + 0x58, 0x58, 0x59, 0x59, 0x5e, 0x5e, 0x5f, 0x5f, 0x5c, 0x5c, 0x5d, 0x5d, + 0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51, 0x56, 0x56, 0x57, 0x57, + 0x54, 0x54, 0x55, 0x55, 0xd5, 0xd5, 0xd4, 0xd4, 0xd7, 0xd7, 0xd6, 0xd6, + 0xd1, 0xd1, 0xd0, 0xd0, 0xd3, 0xd3, 0xd2, 0xd2, 0xdd, 0xdd, 0xdc, 0xdc, + 0xdf, 0xdf, 0xde, 0xde, 0xd9, 0xd9, 0xd8, 0xd8, 0xdb, 0xdb, 0xda, 0xda, + 0xc5, 0xc5, 0xc4, 0xc4, 0xc7, 0xc7, 0xc6, 0xc6, 0xc1, 0xc1, 0xc0, 0xc0, + 0xc3, 0xc3, 0xc2, 0xc2, 0xcd, 0xcd, 0xcc, 0xcc, 0xcf, 0xcf, 0xce, 0xce, + 0xc9, 0xc9, 0xc8, 0xc8, 0xcb, 0xcb, 0xca, 0xca, 0xf5, 0xf5, 0xf5, 0xf5, + 0xf4, 0xf4, 0xf4, 0xf4, 0xf7, 0xf7, 0xf7, 0xf7, 0xf6, 0xf6, 0xf6, 0xf6, + 0xf1, 0xf1, 0xf1, 0xf1, 0xf0, 0xf0, 0xf0, 0xf0, 0xf3, 0xf3, 0xf3, 0xf3, + 0xf2, 0xf2, 0xf2, 0xf2, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xf9, 0xf9, 0xf9, 0xf9, + 0xf8, 0xf8, 0xf8, 0xf8, 0xfb, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xfa, + 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4, + 0xe4, 0xe4, 0xe4, 0xe4, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, + 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe1, 0xe1, 0xe1, 0xe1, + 0xe1, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, + 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, + 0xe2, 0xe2, 0xe2, 0xe2, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, + 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xef, 0xef, 0xef, 0xef, + 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, + 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, + 0xe8, 0xe8, 0xe8, 0xe8, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa +}; + +#endif /* FAST_ALAW_CONVERSION */ + +#ifdef FAST_ULAW_CONVERSION + +int16_t _st_ulaw2linear16[256] = { + -32124, -31100, -30076, -29052, -28028, -27004, -25980, + -24956, -23932, -22908, -21884, -20860, -19836, -18812, + -17788, -16764, -15996, -15484, -14972, -14460, -13948, + -13436, -12924, -12412, -11900, -11388, -10876, -10364, + -9852, -9340, -8828, -8316, -7932, -7676, -7420, + -7164, -6908, -6652, -6396, -6140, -5884, -5628, + -5372, -5116, -4860, -4604, -4348, -4092, -3900, + -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, + -1980, -1884, -1820, -1756, -1692, -1628, -1564, + -1500, -1436, -1372, -1308, -1244, -1180, -1116, + -1052, -988, -924, -876, -844, -812, -780, + -748, -716, -684, -652, -620, -588, -556, + -524, -492, -460, -428, -396, -372, -356, + -340, -324, -308, -292, -276, -260, -244, + -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, + -64, -56, -48, -40, -32, -24, -16, + -8, 0, 32124, 31100, 30076, 29052, 28028, + 27004, 25980, 24956, 23932, 22908, 21884, 20860, + 19836, 18812, 17788, 16764, 15996, 15484, 14972, + 14460, 13948, 13436, 12924, 12412, 11900, 11388, + 10876, 10364, 9852, 9340, 8828, 8316, 7932, + 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, + 4092, 3900, 3772, 3644, 3516, 3388, 3260, + 3132, 3004, 2876, 2748, 2620, 2492, 2364, + 2236, 2108, 1980, 1884, 1820, 1756, 1692, + 1628, 1564, 1500, 1436, 1372, 1308, 1244, + 1180, 1116, 1052, 988, 924, 876, 844, + 812, 780, 748, 716, 684, 652, 620, + 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, + 260, 244, 228, 212, 196, 180, 164, + 148, 132, 120, 112, 104, 96, 88, + 80, 72, 64, 56, 48, 40, 32, + 24, 16, 8, 0 +}; + +uint8_t _st_14linear2ulaw[0x4000] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, + 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, + 0x43, 0x43, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, + 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, + 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, + 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, + 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, + 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, + 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, + 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, + 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, + 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, + 0x52, 0x52, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, + 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x57, 0x57, + 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a, 0x5a, + 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, + 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, + 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x60, 0x60, + 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x62, 0x63, 0x63, + 0x63, 0x63, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, + 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, + 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, + 0x6f, 0x6f, 0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x74, 0x74, + 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a, + 0x7b, 0x7b, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0xff, 0xfe, 0xfe, 0xfd, + 0xfd, 0xfc, 0xfc, 0xfb, 0xfb, 0xfa, 0xfa, 0xf9, 0xf9, 0xf8, 0xf8, 0xf7, + 0xf7, 0xf6, 0xf6, 0xf5, 0xf5, 0xf4, 0xf4, 0xf3, 0xf3, 0xf2, 0xf2, 0xf1, + 0xf1, 0xf0, 0xf0, 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xed, + 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xeb, 0xeb, 0xeb, 0xeb, 0xea, + 0xea, 0xea, 0xea, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, + 0xe4, 0xe4, 0xe4, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, 0xe1, + 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, + 0xdf, 0xdf, 0xdf, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, + 0xdc, 0xdc, 0xdc, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xda, + 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, + 0xd9, 0xd9, 0xd9, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd7, + 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, + 0xd6, 0xd6, 0xd6, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd4, + 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, + 0xd3, 0xd3, 0xd3, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd1, + 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, + 0xd0, 0xd0, 0xd0, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, + 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xce, 0xce, 0xce, 0xce, 0xce, + 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, + 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xca, + 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, + 0xca, 0xca, 0xca, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, + 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, + 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc7, + 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, + 0xc7, 0xc7, 0xc7, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, + 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, + 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc1, + 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, + 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, + 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80 +}; + +#endif /* FAST_ULAW_CONVERSION */ + +/* The following code was used to generate the lookup tables */ +#if 0 +int main() +{ + int x, y, find2a = 0; + + y = 0; + printf("int16_t _st_alaw2linear16[256] = {\n "); + for (x = 0; x < 256; x++) + { + printf("%8d,", st_alaw2linear16(x)); + y++; + if (y == 7) + { + y = 0; + printf("\n "); + } + } + + printf("\n};\n\nuint8_t _st_13linear2alaw[0x2000] = {\n "); + y = 0; + for (x = 0; x < 0x2000; x++) + { + printf(" 0x%02x,", st_13linear2alaw((-0x1000)+x)); + y++; + if (y == 12) + { + y = 0; + printf("\n "); + } + } + + printf("\n};\n\nint16_t _st_ulaw2linear16[256] = {\n "); + y = 0; + for (x = 0; x < 256; x++) + { + printf("%8d,", st_ulaw2linear16(x)); + y++; + if (y == 7) + { + y = 0; + printf("\n "); + } + } + + printf("\n};\n\nuint8_t _st_14linear2ulaw[0x4000] = {\n "); + y = 0; + for (x = 0; x < 0x4000; x++) + { + printf(" 0x%02x,", st_14linear2ulaw((-0x2000)+x)); + y++; + if (y == 12) + { + y = 0; + printf("\n "); + } + } + printf("\n};\n"); + +} +#endif + +/* The following is not used by SoX but kept for reference */ +#if 0 +/* copy from CCITT G.711 specifications */ +unsigned char _u2a[128] = { /* u- to A-law conversions */ + 1, 1, 2, 2, 3, 3, 4, 4, + 5, 5, 6, 6, 7, 7, 8, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 27, 29, 31, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, + 46, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, +/* corrected: + 81, 82, 83, 84, 85, 86, 87, 88, + should be: */ + 80, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128}; + +unsigned char _a2u[128] = { /* A- to u-law conversions */ + 1, 3, 5, 7, 9, 11, 13, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 32, 33, 33, 34, 34, 35, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 48, 49, 49, + 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 64, + 65, 66, 67, 68, 69, 70, 71, 72, +/* corrected: + 73, 74, 75, 76, 77, 78, 79, 79, + should be: */ + 73, 74, 75, 76, 77, 78, 79, 80, + + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127}; + +/* A-law to u-law conversion */ +unsigned char st_alaw2ulaw( + unsigned char aval) +{ + aval &= 0xff; + return (unsigned char) ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) : + (0x7F ^ _a2u[aval ^ 0x55])); +} + +/* u-law to A-law conversion */ +unsigned char st_ulaw2alaw( + unsigned char uval) +{ + uval &= 0xff; + return (unsigned char) ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) : + (unsigned char) (0x55 ^ (_u2a[0x7F ^ uval] - 1))); +} +#endif diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index dbdb7dd4..dd41b3d5 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -764,7 +764,7 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, maxlength > 0 && maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, maxlength >= pa_frame_size(&ss), tag, PA_ERR_INVALID); - + if (sink_index != PA_INVALID_INDEX) { sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index c8e7acf0..a9971408 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -56,7 +56,7 @@ pa_memblock *pa_silence_memblock_new(pa_mempool *pool, const pa_sample_spec *spe if (length <= 0) length = fs; - + return pa_silence_memblock(pa_memblock_new(pool, length), spec); } diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c index b3274426..4271fa42 100644 --- a/src/pulsecore/thread-posix.c +++ b/src/pulsecore/thread-posix.c @@ -111,7 +111,7 @@ pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) { int pa_thread_is_running(pa_thread *t) { assert(t); - + /* Unfortunately there is no way to tell whether a "foreign" * thread is still running. See * http://udrepper.livejournal.com/16844.html for more diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 0ac48254..955bd2f1 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -2230,7 +2230,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETDUPLEX\n"); /* this is a no-op */ break; - + default: debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request); -- cgit From 13a4c5290a5a80025c72e9f40c28c2e6437c82e8 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 4 Jun 2007 09:52:03 +0000 Subject: Add support for the poorly documented SNDCTL_DSP_GETTRIGGER. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1466 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 955bd2f1..b9c26f09 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -2061,6 +2061,17 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) *_errno = EIO; break; + case SNDCTL_DSP_GETTRIGGER: + debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETTRIGGER\n"); + + *(int*) argp = 0; + if (!i->play_precork) + *(int*) argp |= PCM_ENABLE_OUTPUT; + if (!i->rec_precork) + *(int*) argp |= PCM_ENABLE_INPUT; + + break; + case SNDCTL_DSP_SETTRIGGER: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETTRIGGER: 0x%08x\n", *(int*) argp); -- cgit From 14cbbe1096ef10091a0073009a3c65eb13d2da27 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 11 Jun 2007 11:22:30 +0000 Subject: Support stat() and friends as some programs (audacity) likes to check if the device node is there first. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1467 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index b9c26f09..9a2bad44 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -116,9 +116,17 @@ static int (*_ioctl)(int, int, void*) = NULL; static int (*_close)(int) = NULL; static int (*_open)(const char *, int, mode_t) = NULL; static FILE* (*_fopen)(const char *path, const char *mode) = NULL; +static int (*_stat)(const char *, struct stat *) = NULL; +#ifdef _STAT_VER +static int (*___xstat)(int, const char *, struct stat *) = NULL; +#endif #ifdef HAVE_OPEN64 static int (*_open64)(const char *, int, mode_t) = NULL; static FILE* (*_fopen64)(const char *path, const char *mode) = NULL; +static int (*_stat64)(const char *, struct stat64 *) = NULL; +#ifdef _STAT_VER +static int (*___xstat64)(int, const char *, struct stat64 *) = NULL; +#endif #endif static int (*_fclose)(FILE *f) = NULL; static int (*_access)(const char *, int) = NULL; @@ -170,6 +178,38 @@ do { \ pthread_mutex_unlock(&func_mutex); \ } while(0) +#define LOAD_STAT_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_stat) \ + _stat = (int (*)(const char *, struct stat *)) dlsym_fn(RTLD_NEXT, "stat"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +#define LOAD_STAT64_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!_stat64) \ + _stat64 = (int (*)(const char *, struct stat64 *)) dlsym_fn(RTLD_NEXT, "stat64"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +#define LOAD_XSTAT_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!___xstat) \ + ___xstat = (int (*)(int, const char *, struct stat *)) dlsym_fn(RTLD_NEXT, "__xstat"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + +#define LOAD_XSTAT64_FUNC() \ +do { \ + pthread_mutex_lock(&func_mutex); \ + if (!___xstat64) \ + ___xstat64 = (int (*)(int, const char *, struct stat64 *)) dlsym_fn(RTLD_NEXT, "__xstat64"); \ + pthread_mutex_unlock(&func_mutex); \ +} while(0) + #define LOAD_FOPEN_FUNC() \ do { \ pthread_mutex_lock(&func_mutex); \ @@ -2348,7 +2388,107 @@ int access(const char *pathname, int mode) { return 0; } +int stat(const char *pathname, struct stat *buf) { #ifdef HAVE_OPEN64 + struct stat64 parent; +#else + struct stat parent; +#endif + int ret; + + if (!pathname || !buf) { + errno = EFAULT; + return -1; + } + + if (strcmp(pathname, "/dev/dsp") != 0 && + strcmp(pathname, "/dev/adsp") != 0 && + strcmp(pathname, "/dev/sndstat") != 0 && + strcmp(pathname, "/dev/mixer") != 0) { + debug(DEBUG_LEVEL_VERBOSE, __FILE__": stat(%s)\n", pathname); + LOAD_STAT_FUNC(); + return _stat(pathname, buf); + } + + debug(DEBUG_LEVEL_NORMAL, __FILE__": stat(%s)\n", pathname); + +#ifdef _STAT_VER +#ifdef HAVE_OPEN64 + ret = __xstat64(_STAT_VER, "/dev", &parent); +#else + ret = __xstat(_STAT_VER, "/dev", &parent); +#endif +#else +#ifdef HAVE_OPEN64 + ret = stat64("/dev", &parent); +#else + ret = stat("/dev", &parent); +#endif +#endif + + if (ret) { + debug(DEBUG_LEVEL_NORMAL, __FILE__": unable to stat \"/dev\"\n"); + return -1; + } + + buf->st_dev = parent.st_dev; + buf->st_ino = 0xDEADBEEF; /* FIXME: Can we do this in a safe way? */ + buf->st_mode = S_IFCHR | S_IRUSR | S_IWUSR; + buf->st_nlink = 1; + buf->st_uid = getuid(); + buf->st_gid = getgid(); + buf->st_rdev = 0x0E03; /* FIXME: Linux specific */ + buf->st_size = 0; + buf->st_atime = 1181557705; + buf->st_mtime = 1181557705; + buf->st_ctime = 1181557705; + buf->st_blksize = 1; + buf->st_blocks = 0; + + return 0; +} + +#ifdef HAVE_OPEN64 + +int stat64(const char *pathname, struct stat64 *buf) { + struct stat oldbuf; + int ret; + + if (!pathname || !buf) { + errno = EFAULT; + return -1; + } + + debug(DEBUG_LEVEL_VERBOSE, __FILE__": stat64(%s)\n", pathname); + + if (strcmp(pathname, "/dev/dsp") != 0 && + strcmp(pathname, "/dev/adsp") != 0 && + strcmp(pathname, "/dev/sndstat") != 0 && + strcmp(pathname, "/dev/mixer") != 0) { + LOAD_STAT64_FUNC(); + return _stat64(pathname, buf); + } + + ret = stat(pathname, &oldbuf); + if (ret) + return ret; + + buf->st_dev = oldbuf.st_dev; + buf->st_ino = oldbuf.st_ino; + buf->st_mode = oldbuf.st_mode; + buf->st_nlink = oldbuf.st_nlink; + buf->st_uid = oldbuf.st_uid; + buf->st_gid = oldbuf.st_gid; + buf->st_rdev = oldbuf.st_rdev; + buf->st_size = oldbuf.st_size; + buf->st_atime = oldbuf.st_atime; + buf->st_mtime = oldbuf.st_mtime; + buf->st_ctime = oldbuf.st_ctime; + buf->st_blksize = oldbuf.st_blksize; + buf->st_blocks = oldbuf.st_blocks; + + return 0; +} int open64(const char *filename, int flags, ...) { va_list args; @@ -2374,6 +2514,62 @@ int open64(const char *filename, int flags, ...) { #endif +#ifdef _STAT_VER + +int __xstat(int ver, const char *pathname, struct stat *buf) { + if (!pathname || !buf) { + errno = EFAULT; + return -1; + } + + debug(DEBUG_LEVEL_VERBOSE, __FILE__": __xstat(%s)\n", pathname); + + if (strcmp(pathname, "/dev/dsp") != 0 && + strcmp(pathname, "/dev/adsp") != 0 && + strcmp(pathname, "/dev/sndstat") != 0 && + strcmp(pathname, "/dev/mixer") != 0) { + LOAD_XSTAT_FUNC(); + return ___xstat(ver, pathname, buf); + } + + if (ver != _STAT_VER) { + errno = EINVAL; + return -1; + } + + return stat(pathname, buf); +} + +#ifdef HAVE_OPEN64 + +int __xstat64(int ver, const char *pathname, struct stat64 *buf) { + if (!pathname || !buf) { + errno = EFAULT; + return -1; + } + + debug(DEBUG_LEVEL_VERBOSE, __FILE__": __xstat64(%s)\n", pathname); + + if (strcmp(pathname, "/dev/dsp") != 0 && + strcmp(pathname, "/dev/adsp") != 0 && + strcmp(pathname, "/dev/sndstat") != 0 && + strcmp(pathname, "/dev/mixer") != 0) { + LOAD_XSTAT64_FUNC(); + return ___xstat64(ver, pathname, buf); + } + + if (ver != _STAT_VER) { + errno = EINVAL; + return -1; + } + + return stat64(pathname, buf); +} + +#endif + +#endif + FILE* fopen(const char *filename, const char *mode) { FILE *f = NULL; int fd; -- cgit From 0694d2ae3549ed4e7cb8fca3558fb90ed844fca1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 13 Jun 2007 07:21:57 +0000 Subject: Make sure mixer ioctls work on /dev/dsp aswell. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1473 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/padsp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 9a2bad44..95fc9ed3 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -2279,11 +2279,12 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) case SNDCTL_DSP_SETDUPLEX: debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETDUPLEX\n"); - /* this is a no-op */ - break; + /* this is a no-op */ + break; default: - debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request); + /* Mixer ioctls are valid on /dev/dsp aswell */ + return mixer_ioctl(i, request, argp, _errno); inval: *_errno = EINVAL; -- cgit From 405d6758efdaa571b5b37b4802ebf2fcf968b19b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 10 Jul 2007 14:36:20 +0000 Subject: Move pthreads detection as it gets confused by things in LIBS. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1502 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 9a1e6c51..8054b0fa 100644 --- a/configure.ac +++ b/configure.ac @@ -208,6 +208,10 @@ AC_CHECK_DEFINE([INADDR_NONE], [netinet/in.h], [], [AC_CHECK_DEFINE([INADDR_NONE], [winsock2.h], [], [AC_DEFINE([INADDR_NONE], [0xffffffff], [Define INADDR_NONE if not found in ])])]) +#### POSIX threads #### + +ACX_PTHREAD + #### Check for libs #### # ISO @@ -256,10 +260,6 @@ AC_CHECK_FUNCS([lstat]) AC_CHECK_FUNCS([setresuid setresgid setreuid setregid seteuid setegid]) -#### POSIX threads #### - -ACX_PTHREAD - #### Large File-Support (LFS) #### AC_SYS_LARGEFILE -- cgit From 689fd706effaead1a5efbe1fd7f8fcc86f320375 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 10 Jul 2007 14:36:58 +0000 Subject: Make -no-undefined actually work (and fix up error found by it). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1503 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index d90361f3..b1c218dc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -63,7 +63,7 @@ AM_LIBADD = $(PTHREAD_LIBS) AM_LDADD = $(PTHREAD_LIBS) # Only required on some platforms but defined for all to avoid errors -AM_LDFLAGS = -no-undefined +AM_LDFLAGS = -Wl,-no-undefined if STATIC_BINS BINLDFLAGS = -static @@ -1159,7 +1159,7 @@ liboss_util_la_LIBADD = libpulsecore.la module_oss_la_SOURCES = modules/module-oss.c module_oss_la_LDFLAGS = -module -avoid-version -module_oss_la_LIBADD = $(AM_LIBADD) libiochannel.la liboss-util.la +module_oss_la_LIBADD = $(AM_LIBADD) libiochannel.la liboss-util.la libpulsecore.la module_oss_mmap_la_SOURCES = modules/module-oss-mmap.c module_oss_mmap_la_LDFLAGS = -module -avoid-version -- cgit From a228a517c4fec83b5aba5f60425f25943e9fc727 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 10 Jul 2007 15:20:39 +0000 Subject: Solaris hides inet_ntop in nsl. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1504 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 8054b0fa..eef8eb47 100644 --- a/configure.ac +++ b/configure.ac @@ -221,6 +221,7 @@ AC_SEARCH_LIBS([pow], [m]) AC_SEARCH_LIBS([sched_setscheduler], [rt]) AC_SEARCH_LIBS([dlopen], [dl]) AC_SEARCH_LIBS([shm_open], [rt]) +AC_SEARCH_LIBS([inet_ntop], [nsl]) # BSD AC_SEARCH_LIBS([connect], [socket]) -- cgit From b0f692c45d26d9633e4e2f9f6a503f427c9d730c Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 10 Jul 2007 15:21:03 +0000 Subject: Make sure we link to the core to get all symbols. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1505 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index b1c218dc..fc13bb22 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1186,7 +1186,7 @@ module_alsa_source_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) module_solaris_la_SOURCES = modules/module-solaris.c module_solaris_la_LDFLAGS = -module -avoid-version -module_solaris_la_LIBADD = $(AM_LIBADD) libiochannel.la +module_solaris_la_LIBADD = $(AM_LIBADD) libiochannel.la libpulsecore.la # Avahi -- cgit From 7455571dd9cb4d1b90c35da77f9e2ba08fcc8b1e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 4 Aug 2007 19:53:37 +0000 Subject: jack driver build fix which became apparent on fedora git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1567 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index fc13bb22..93f331d6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1250,12 +1250,12 @@ module_rtp_recv_la_CFLAGS = $(AM_CFLAGS) module_jack_sink_la_SOURCES = modules/module-jack-sink.c module_jack_sink_la_LDFLAGS = -module -avoid-version module_jack_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la $(JACK_LIBS) -module_jack_sink_la_CFLAGS = $(AM_LIBADD) $(JACK_CFLAGS) +module_jack_sink_la_CFLAGS = $(AM_CFLAGS) $(JACK_CFLAGS) module_jack_source_la_SOURCES = modules/module-jack-source.c module_jack_source_la_LDFLAGS = -module -avoid-version module_jack_source_la_LIBADD = $(AM_LIBADD) libpulsecore.la $(JACK_LIBS) -module_jack_source_la_CFLAGS = $(AM_LIBADD) $(JACK_CFLAGS) +module_jack_source_la_CFLAGS = $(AM_CFLAGS) $(JACK_CFLAGS) # HAL libdbus_util_la_SOURCES = modules/dbus-util.c modules/dbus-util.h -- cgit From 5ecaf31b6f0963ae79dc1b12c6468f5fb0676c38 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 4 Aug 2007 19:53:51 +0000 Subject: compat with automake 1.10 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1568 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index eef8eb47..a195da20 100644 --- a/configure.ac +++ b/configure.ac @@ -67,6 +67,7 @@ esac # CC AC_PROG_CC +AM_PROG_CC_C_O AC_PROG_GCC_TRADITIONAL AC_GNU_SOURCE -- cgit From eaafb79858fff11add29c8a1126a18e90d7785f9 Mon Sep 17 00:00:00 2001 From: Tanu Kaskinen Date: Mon, 20 Aug 2007 06:22:21 +0000 Subject: Modified the JACK sink heavily: * Made the sink realtime-safe. * To achieve the previous item, internal buffering was be added. New module argument: buffersize. * Removed the user's need to set the JACK transport to playing state before he could hear anything from PulseAudio. * In process of achieving the previous item, latency calculation got more inaccurate: the reported latency is now always a multiple of the JACK processing block size, and constant. * The JACK ports now have a running numbering in their names. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1680 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-jack-sink.c | 957 ++++++++++++++++++++++++++++++----------- 1 file changed, 716 insertions(+), 241 deletions(-) diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index c6a7e33f..09a72e3a 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -3,7 +3,7 @@ /*** This file is part of PulseAudio. - Copyright 2006 Lennart Poettering + Copyright 2006, 2007 Lennart Poettering and Tanu Kaskinen PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published @@ -25,33 +25,32 @@ #include #endif -#include -#include -#include +#include #include #include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include #include -#include -#include #include #include +#include +#include #include +#include +#include #include -#include -#include +#include #include "module-jack-sink-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_AUTHOR("Lennart Poettering & Tanu Kaskinen") PA_MODULE_DESCRIPTION("Jack Sink") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE( @@ -59,335 +58,806 @@ PA_MODULE_USAGE( "server_name= " "client_name= " "channels= " - "connect= " + "connect= " + "buffersize= " "channel_map=") #define DEFAULT_SINK_NAME "jack_out" +#define DEFAULT_CLIENT_NAME "PulseAudio(output)" +#define DEFAULT_RINGBUFFER_SIZE 4096 -struct userdata { - pa_core *core; - pa_module *module; +struct userdata { pa_sink *sink; unsigned channels; + unsigned frame_size; + + jack_port_t* j_ports[PA_CHANNELS_MAX]; + jack_client_t *j_client; - jack_port_t* port[PA_CHANNELS_MAX]; - jack_client_t *client; + jack_nframes_t j_buffersize; - pthread_mutex_t mutex; - pthread_cond_t cond; + /* For avoiding j_buffersize changes at a wrong moment. */ + pthread_mutex_t buffersize_mutex; - void * buffer[PA_CHANNELS_MAX]; - jack_nframes_t frames_requested; + /* The intermediate store where the pulse side writes to and the jack side + reads from. */ + jack_ringbuffer_t* ringbuffer; + + /* For signaling when there's room in the ringbuffer. */ + pthread_mutex_t cond_mutex; + pthread_cond_t ringbuffer_cond; + + pthread_t filler_thread; /* Keeps the ringbuffer filled. */ + + int ringbuffer_is_full; + int filler_thread_is_running; int quit_requested; int pipe_fd_type; int pipe_fds[2]; pa_io_event *io_event; +}; - jack_nframes_t frames_in_buffer; - jack_nframes_t timestamp; + +struct options { + char* sink_name; + int sink_name_given; + + char* server_name; /* May be NULL */ + int server_name_given; + + char* client_name; + int client_name_given; + + unsigned channels; + int channels_given; + + int connect; + int connect_given; + + unsigned buffersize; + int buffersize_given; + + pa_channel_map map; + int map_given; }; + static const char* const valid_modargs[] = { "sink_name", "server_name", "client_name", "channels", "connect", + "buffersize", "channel_map", NULL }; -static void stop_sink(struct userdata *u) { - assert (u); - - jack_client_close(u->client); - u->client = NULL; - u->core->mainloop->io_free(u->io_event); - u->io_event = NULL; - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - u->sink = NULL; - pa_module_unload_request(u->module); -} - -static void io_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) { - struct userdata *u = userdata; - char x; - - assert(m); - assert(e); - assert(flags == PA_IO_EVENT_INPUT); - assert(u); - assert(u->pipe_fds[0] == fd); - - pa_read(fd, &x, 1, &u->pipe_fd_type); - if (u->quit_requested) { - stop_sink(u); - u->quit_requested = 0; - return; - } - - pthread_mutex_lock(&u->mutex); +/* Initialization functions. */ +static int parse_options(struct options* o, const char* argument); +static void set_default_channels(pa_module* self, struct options* o); +static int create_sink(pa_module* self, struct options *o); +static void connect_ports(pa_module* self); +static int start_filling_ringbuffer(pa_module* self); - if (u->frames_requested > 0) { - unsigned fs; - jack_nframes_t frame_idx; - pa_memchunk chunk; +/* Various callbacks. */ +static void jack_error_func(const char* t); +static pa_usec_t sink_get_latency_cb(pa_sink* s); +static int jack_process(jack_nframes_t nframes, void* arg); +static int jack_blocksize_cb(jack_nframes_t nframes, void* arg); +static void jack_shutdown(void* arg); +static void io_event_cb(pa_mainloop_api* m, pa_io_event* e, int fd, + pa_io_event_flags_t flags, void* userdata); - fs = pa_frame_size(&u->sink->sample_spec); +/* The ringbuffer filler thread runs in this function. */ +static void* fill_ringbuffer(void* arg); - pa_sink_render_full(u->sink, u->frames_requested * fs, &chunk); +/* request_render asks asynchronously the mainloop to call io_event_cb. */ +static void request_render(struct userdata* u); - for (frame_idx = 0; frame_idx < u->frames_requested; frame_idx ++) { - unsigned c; - for (c = 0; c < u->channels; c++) { - float *s = ((float*) ((uint8_t*) chunk.memblock->data + chunk.index)) + (frame_idx * u->channels) + c; - float *d = ((float*) u->buffer[c]) + frame_idx; - - *d = *s; - } +int pa__init(pa_core* c, pa_module* self) { + struct userdata* u = NULL; + struct options o; + unsigned i; + + assert(c); + assert(self); + + o.sink_name = NULL; + o.server_name = NULL; + o.client_name = NULL; + + self->userdata = pa_xnew0(struct userdata, 1); + u = self->userdata; + + u->pipe_fds[0] = u->pipe_fds[1] = -1; + u->pipe_fd_type = 0; + u->ringbuffer_is_full = 0; + u->filler_thread_is_running = 0; + u->quit_requested = 0; + pthread_mutex_init(&u->buffersize_mutex, NULL); + pthread_mutex_init(&u->cond_mutex, NULL); + pthread_cond_init(&u->ringbuffer_cond, NULL); + + if (parse_options(&o, self->argument) != 0) + goto fail; + + jack_set_error_function(jack_error_func); + + if (!(u->j_client = jack_client_open( + o.client_name, + o.server_name ? JackServerName : JackNullOption, + NULL, o.server_name))) { + pa_log_error("jack_client_open() failed."); + goto fail; + } + pa_log_info("Successfully connected as '%s'", + jack_get_client_name(u->j_client)); + + if (!o.channels_given) + set_default_channels(self, &o); + + u->channels = o.channels; + + if (!o.map_given) + pa_channel_map_init_auto(&o.map, u->channels, PA_CHANNEL_MAP_ALSA); + + for (i = 0; i < u->channels; i++) { + char* port_name = pa_sprintf_malloc( + "out_%i:%s", i+1, + pa_channel_position_to_string(o.map.map[i])); + + if (!(u->j_ports[i] = jack_port_register( + u->j_client, port_name, + JACK_DEFAULT_AUDIO_TYPE, + JackPortIsOutput|JackPortIsTerminal, 0))) { + pa_log("jack_port_register() failed."); + goto fail; } + + pa_xfree(port_name); + } + + if (pipe(u->pipe_fds) < 0) { + pa_log("pipe() failed: %s", pa_cstrerror(errno)); + goto fail; + } + pa_make_nonblock_fd(u->pipe_fds[1]); + + if (create_sink(self, &o) != 0) + goto fail; - pa_memblock_unref(chunk.memblock); - - u->frames_requested = 0; - - pthread_cond_signal(&u->cond); + u->frame_size = pa_frame_size(&u->sink->sample_spec); + u->j_buffersize = jack_get_buffer_size(u->j_client); + + /* If the ringbuffer size were equal to the jack buffer size, a full block + would never fit in the ringbuffer, because the ringbuffer can never be + totally full: one slot is always wasted. */ + if (o.buffersize <= u->j_buffersize) { + o.buffersize = u->j_buffersize + 1; + } + /* The actual ringbuffer size will be rounded up to the nearest power of + two. */ + if (!(u->ringbuffer = jack_ringbuffer_create( + o.buffersize * u->frame_size))) { + pa_log("jack_ringbuffer_create() failed."); + goto fail; + } + assert((u->ringbuffer->size % sizeof(float)) == 0); + pa_log_info("buffersize is %u frames (%u samples, %u bytes).", + u->ringbuffer->size / u->frame_size, + u->ringbuffer->size / sizeof(float), + u->ringbuffer->size); + + jack_set_process_callback(u->j_client, jack_process, u); + jack_set_buffer_size_callback(u->j_client, jack_blocksize_cb, u); + jack_on_shutdown(u->j_client, jack_shutdown, u); + + if (jack_activate(u->j_client)) { + pa_log("jack_activate() failed."); + goto fail; } - pthread_mutex_unlock(&u->mutex); -} + if (o.connect) + connect_ports(self); -static void request_render(struct userdata *u) { - char c = 'x'; - assert(u); + u->io_event = c->mainloop->io_new(c->mainloop, u->pipe_fds[0], + PA_IO_EVENT_INPUT, io_event_cb, self); + + if (start_filling_ringbuffer(self) != 0) + goto fail; - assert(u->pipe_fds[1] >= 0); - pa_write(u->pipe_fds[1], &c, 1, &u->pipe_fd_type); -} + pa_xfree(o.sink_name); + pa_xfree(o.server_name); + pa_xfree(o.client_name); + + return 0; -static void jack_shutdown(void *arg) { - struct userdata *u = arg; - assert(u); +fail: + pa_xfree(o.sink_name); + pa_xfree(o.server_name); + pa_xfree(o.client_name); + pa__done(c, self); - u->quit_requested = 1; - request_render(u); + return -1; } -static int jack_process(jack_nframes_t nframes, void *arg) { - struct userdata *u = arg; - assert(u); - - if (jack_transport_query(u->client, NULL) == JackTransportRolling) { - unsigned c; - pthread_mutex_lock(&u->mutex); +static int parse_options(struct options* o, const char* argument) { + pa_modargs *ma = NULL; + const char* arg_val; + pa_strbuf* strbuf; + + assert(o); - u->frames_requested = nframes; + if (!(ma = pa_modargs_new(argument, valid_modargs))) { + pa_log_error("Failed to parse module arguments."); + goto fail; + } - for (c = 0; c < u->channels; c++) { - u->buffer[c] = jack_port_get_buffer(u->port[c], nframes); - assert(u->buffer[c]); + strbuf = pa_strbuf_new(); + if ((arg_val = pa_modargs_get_value(ma, "sink_name", NULL))) { + pa_strbuf_puts(strbuf, arg_val); + o->sink_name = pa_strbuf_tostring(strbuf); + o->sink_name_given = 1; + } else { + pa_strbuf_puts(strbuf, DEFAULT_SINK_NAME); + o->sink_name = pa_strbuf_tostring(strbuf); + o->sink_name_given = 0; + } + pa_strbuf_free(strbuf); + + strbuf = pa_strbuf_new(); + if ((arg_val = pa_modargs_get_value(ma, "server_name", NULL))) { + pa_strbuf_puts(strbuf, arg_val); + o->server_name = pa_strbuf_tostring(strbuf); + o->server_name_given = 1; + } else { + o->server_name = NULL; + o->server_name_given = 0; + } + pa_strbuf_free(strbuf); + + strbuf = pa_strbuf_new(); + if ((arg_val = pa_modargs_get_value(ma, "client_name", NULL))) { + pa_strbuf_puts(strbuf, arg_val); + o->client_name = pa_strbuf_tostring(strbuf); + o->client_name_given = 1; + } else { + pa_strbuf_puts(strbuf, DEFAULT_CLIENT_NAME); + o->client_name = pa_strbuf_tostring(strbuf); + o->client_name_given = 1; + } + pa_strbuf_free(strbuf); + + if (pa_modargs_get_value(ma, "channels", NULL)) { + o->channels_given = 1; + if (pa_modargs_get_value_u32(ma, "channels", &o->channels) < 0 || + o->channels == 0 || + o->channels >= PA_CHANNELS_MAX) { + pa_log_error("Failed to parse the \"channels\" argument."); + goto fail; } + } else { + o->channels = 0; /* The actual default value is the number of physical + input ports in jack (unknown at the moment), or if + that's zero, then the default_sample_spec.channels + of the core. */ + o->channels_given = 0; + } - request_render(u); - - pthread_cond_wait(&u->cond, &u->mutex); - - u->frames_in_buffer = nframes; - u->timestamp = jack_get_current_transport_frame(u->client); - - pthread_mutex_unlock(&u->mutex); + if (pa_modargs_get_value(ma, "connect", NULL)) { + o->connect_given = 1; + if (pa_modargs_get_value_boolean(ma, "connect", &o->connect) < 0) { + pa_log_error("Failed to parse the \"connect\" argument."); + goto fail; + } + } else { + o->connect = 1; + o->connect_given = 0; } - return 0; -} + if (pa_modargs_get_value(ma, "buffersize", NULL)) { + o->buffersize_given = 1; + if (pa_modargs_get_value_u32(ma, "buffersize", &o->buffersize) < 0) { + pa_log_error("Failed to parse the \"buffersize\" argument."); + goto fail; + } + } else { + o->buffersize = DEFAULT_RINGBUFFER_SIZE; + o->buffersize_given = 0; + } -static pa_usec_t sink_get_latency_cb(pa_sink *s) { - struct userdata *u; - jack_nframes_t n, l, d; + if (pa_modargs_get_value(ma, "channel_map", NULL)) { + o->map_given = 1; + if (pa_modargs_get_channel_map(ma, &o->map) < 0) { + pa_log_error("Failed to parse the \"channel_map\" argument."); + goto fail; + } - assert(s); - u = s->userdata; + /* channel_map specifies the channel count too. */ + if (o->channels_given && (o->channels != o->map.channels)) { + pa_log_error( + "\"channels\" and \"channel_map\" arguments conficted. If you " + "use the \"channel_map\" argument, you can omit the " + "\"channels\" argument."); + goto fail; + } else { + o->channels = o->map.channels; + o->channels_given = 1; + } + } else { + /* The actual default value is the default alsa mappings, but that + can't be set until the channel count is known. Here we initialize + the map to some valid value, although the value won't be used. */ + pa_channel_map_init_stereo(&o->map); + o->map_given = 0; + } - if (jack_transport_query(u->client, NULL) != JackTransportRolling) - return 0; + pa_modargs_free(ma); - n = jack_get_current_transport_frame(u->client); + return 0; - if (n < u->timestamp) - return 0; +fail: + if (ma) + pa_modargs_free(ma); - d = n - u->timestamp; - l = jack_port_get_total_latency(u->client, u->port[0]) + u->frames_in_buffer; + return -1; +} - if (d >= l) - return 0; - return pa_bytes_to_usec((l - d) * pa_frame_size(&s->sample_spec), &s->sample_spec); +static void set_default_channels(pa_module* self, struct options* o) { + struct userdata* u; + const char **ports, **p; + + assert(self); + assert(o); + assert(self->userdata); + + u = self->userdata; + + assert(u->j_client); + assert(self->core); + + o->channels = 0; + + ports = jack_get_ports(u->j_client, NULL, JACK_DEFAULT_AUDIO_TYPE, + JackPortIsPhysical|JackPortIsInput); + + for (p = ports; *p; p++) + o->channels++; + + free(ports); + + if (o->channels >= PA_CHANNELS_MAX) + o->channels = PA_CHANNELS_MAX - 1; + + if (o->channels == 0) + o->channels = self->core->default_sample_spec.channels; } -static void jack_error_func(const char*t) { - pa_log_warn("JACK error >%s<", t); -} -int pa__init(pa_core *c, pa_module*m) { - struct userdata *u = NULL; +static int create_sink(pa_module* self, struct options* o) { + struct userdata* u; pa_sample_spec ss; - pa_channel_map map; - pa_modargs *ma = NULL; - jack_status_t status; - const char *server_name, *client_name; - uint32_t channels = 0; - int do_connect = 1; - unsigned i; - const char **ports = NULL, **p; char *t; + + assert(self); + assert(o); + assert(self->userdata); + + u = self->userdata; + + assert(u->j_client); + + ss.channels = u->channels; + ss.rate = jack_get_sample_rate(u->j_client); + ss.format = PA_SAMPLE_FLOAT32NE; + assert(pa_sample_spec_valid(&ss)); - assert(c); - assert(m); - - jack_set_error_function(jack_error_func); - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log("failed to parse module arguments."); - goto fail; + if (!(u->sink = pa_sink_new(self->core, __FILE__, o->sink_name, 0, &ss, + &o->map))) { + pa_log("failed to create sink."); + return -1; } + + u->sink->userdata = u; + pa_sink_set_owner(u->sink, self); + + pa_sink_set_description( + u->sink, + t = pa_sprintf_malloc("Jack sink (%s)", + jack_get_client_name(u->j_client))); + pa_xfree(t); + + u->sink->get_latency = sink_get_latency_cb; + + return 0; +} - if (pa_modargs_get_value_boolean(ma, "connect", &do_connect) < 0) { - pa_log("failed to parse connect= argument."); - goto fail; + +static void connect_ports(pa_module* self) { + struct userdata* u; + unsigned i; + const char **ports, **p; + + assert(self); + assert(self->userdata); + + u = self->userdata; + + assert(u->j_client); + + ports = jack_get_ports(u->j_client, NULL, JACK_DEFAULT_AUDIO_TYPE, + JackPortIsPhysical|JackPortIsInput); + + for (i = 0, p = ports; i < u->channels; i++, p++) { + assert(u->j_ports[i]); + + if (!*p) { + pa_log("Not enough physical output ports, leaving unconnected."); + break; + } + + pa_log_info("connecting %s to %s", + jack_port_name(u->j_ports[i]), *p); + + if (jack_connect(u->j_client, jack_port_name(u->j_ports[i]), *p)) { + pa_log("Failed to connect %s to %s, leaving unconnected.", + jack_port_name(u->j_ports[i]), *p); + break; + } } + + free(ports); +} - server_name = pa_modargs_get_value(ma, "server_name", NULL); - client_name = pa_modargs_get_value(ma, "client_name", "PulseAudio"); - u = pa_xnew0(struct userdata, 1); - m->userdata = u; - u->core = c; - u->module = m; - u->pipe_fds[0] = u->pipe_fds[1] = -1; - u->pipe_fd_type = 0; +static int start_filling_ringbuffer(pa_module* self) { + struct userdata* u; + pthread_attr_t thread_attributes; - pthread_mutex_init(&u->mutex, NULL); - pthread_cond_init(&u->cond, NULL); + assert(self); + assert(self->userdata); - if (pipe(u->pipe_fds) < 0) { - pa_log("pipe() failed: %s", pa_cstrerror(errno)); + u = self->userdata; + + pthread_attr_init(&thread_attributes); + + if (pthread_attr_setinheritsched(&thread_attributes, + PTHREAD_INHERIT_SCHED) != 0) { + pa_log("pthread_attr_setinheritsched() failed."); goto fail; } - - pa_make_nonblock_fd(u->pipe_fds[1]); - - if (!(u->client = jack_client_open(client_name, server_name ? JackServerName : JackNullOption, &status, server_name))) { - pa_log("jack_client_open() failed."); + else if (pthread_create(&u->filler_thread, &thread_attributes, + fill_ringbuffer, u) != 0) { + pa_log("pthread_create() failed."); goto fail; } + + u->filler_thread_is_running = 1; + + pthread_attr_destroy(&thread_attributes); - ports = jack_get_ports(u->client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); - - channels = 0; - for (p = ports; *p; p++) - channels++; + return 0; + +fail: + pthread_attr_destroy(&thread_attributes); + return -1; +} - if (!channels) - channels = c->default_sample_spec.channels; - if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0 || channels <= 0 || channels >= PA_CHANNELS_MAX) { - pa_log("failed to parse channels= argument."); - goto fail; - } +static void jack_error_func(const char* t) { + pa_log_warn("JACK error >%s<", t); +} - pa_channel_map_init_auto(&map, channels, PA_CHANNEL_MAP_ALSA); - if (pa_modargs_get_channel_map(ma, &map) < 0 || map.channels != channels) { - pa_log("failed to parse channel_map= argument."); - goto fail; - } - pa_log_info("Successfully connected as '%s'", jack_get_client_name(u->client)); +static pa_usec_t sink_get_latency_cb(pa_sink* s) { + /* The latency is approximately the sum of the first port's latency, + buffersize of jack and the ringbuffer size. Maybe instead of using just + the first port, the max of all ports' latencies should be used? */ + struct userdata* u; + jack_nframes_t l; + + assert(s); + assert(s->userdata); - ss.channels = u->channels = channels; - ss.rate = jack_get_sample_rate(u->client); - ss.format = PA_SAMPLE_FLOAT32NE; + u = s->userdata; + + l = jack_port_get_total_latency(u->j_client, u->j_ports[0]) + + u->j_buffersize + u->ringbuffer->size / u->frame_size; + + return pa_bytes_to_usec(l * u->frame_size, &s->sample_spec); +} - assert(pa_sample_spec_valid(&ss)); - for (i = 0; i < ss.channels; i++) { - if (!(u->port[i] = jack_port_register(u->client, pa_channel_position_to_string(map.map[i]), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput|JackPortIsTerminal, 0))) { - pa_log("jack_port_register() failed."); - goto fail; - } +static int jack_process(jack_nframes_t nframes, void* arg) { + struct userdata* u = arg; + float* j_buffers[PA_CHANNELS_MAX]; + unsigned nsamples = u->channels * nframes; + unsigned sample_idx_part1, sample_idx_part2; + jack_nframes_t frame_idx; + jack_ringbuffer_data_t data[2]; /* In case the readable area in the + ringbuffer is non-continuous, the data + will be split in two parts. */ + unsigned chan; + unsigned samples_left_over; + + for (chan = 0; chan < u->channels; chan++) { + j_buffers[chan] = jack_port_get_buffer(u->j_ports[chan], nframes); + } + + jack_ringbuffer_get_read_vector(u->ringbuffer, data); + + /* We assume that the possible discontinuity doesn't happen in the middle + * of a sample. Should be a safe assumption. */ + assert(((data[0].len % sizeof(float)) == 0) || + (data[1].len == 0)); + + /* Copy from the first part of data until enough samples are copied or the + first part ends. */ + sample_idx_part1 = 0; + chan = 0; + frame_idx = 0; + while (sample_idx_part1 < nsamples && + ((sample_idx_part1 + 1) * sizeof(float)) <= data[0].len) { + float *s = ((float*) data[0].buf) + sample_idx_part1; + float *d = j_buffers[chan] + frame_idx; + *d = *s; + + sample_idx_part1++; + chan = (chan + 1) % u->channels; + frame_idx = sample_idx_part1 / u->channels; + } + + samples_left_over = nsamples - sample_idx_part1; + + /* Copy from the second part of data until enough samples are copied or the + second part ends. */ + sample_idx_part2 = 0; + while (sample_idx_part2 < samples_left_over && + ((sample_idx_part2 + 1) * sizeof(float)) <= data[1].len) { + float *s = ((float*) data[1].buf) + sample_idx_part2; + float *d = j_buffers[chan] + frame_idx; + *d = *s; + + sample_idx_part2++; + chan = (chan + 1) % u->channels; + frame_idx = (sample_idx_part1 + sample_idx_part2) / u->channels; } + + samples_left_over -= sample_idx_part2; + + /* If there's still samples left, fill the buffers with zeros. */ + while (samples_left_over > 0) { + float *d = j_buffers[chan] + frame_idx; + *d = 0.0; + + samples_left_over--; + chan = (chan + 1) % u->channels; + frame_idx = (nsamples - samples_left_over) / u->channels; + } + + jack_ringbuffer_read_advance( + u->ringbuffer, (sample_idx_part1 + sample_idx_part2) * sizeof(float)); + + /* Tell the rendering part that there is room in the ringbuffer. */ + u->ringbuffer_is_full = 0; + pthread_cond_signal(&u->ringbuffer_cond); + + return 0; +} - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { - pa_log("failed to create sink."); - goto fail; + +static int jack_blocksize_cb(jack_nframes_t nframes, void* arg) { + /* This gets called in the processing thread, so do we have to be realtime + safe? No, we can do whatever we want. User gets silence while we do it. + + In addition to just updating the j_buffersize field in userdata, we have + to create a new ringbuffer, if the new buffer size is bigger or equal to + the old ringbuffer size. */ + struct userdata* u = arg; + + assert(u); + + /* We don't want to change the blocksize and the ringbuffer while rendering + is going on. */ + pthread_mutex_lock(&u->buffersize_mutex); + + u->j_buffersize = nframes; + + if ((u->ringbuffer->size / u->frame_size) <= nframes) { + /* We have to create a new ringbuffer. What are we going to do with the + old data in the old buffer? We throw it away, because we're lazy + coders. The listening experience is likely to get ruined anyway + during the blocksize change. */ + jack_ringbuffer_free(u->ringbuffer); + + /* The actual ringbuffer size will be rounded up to the nearest power + of two. */ + if (!(u->ringbuffer = + jack_ringbuffer_create((nframes + 1) * u->frame_size))) { + pa_log_error( + "jack_ringbuffer_create() failed while changing jack's buffer " + "size, module exiting."); + jack_client_close(u->j_client); + u->quit_requested = 1; + } + assert((u->ringbuffer->size % sizeof(float)) == 0); + pa_log_info("buffersize is %u frames (%u samples, %u bytes).", + u->ringbuffer->size / u->frame_size, + u->ringbuffer->size / sizeof(float), + u->ringbuffer->size); } + + pthread_mutex_unlock(&u->buffersize_mutex); + + return 0; +} - u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Jack sink (%s)", jack_get_client_name(u->client))); - pa_xfree(t); - u->sink->get_latency = sink_get_latency_cb; - jack_set_process_callback(u->client, jack_process, u); - jack_on_shutdown(u->client, jack_shutdown, u); +static void jack_shutdown(void* arg) { + struct userdata* u = arg; + assert(u); - if (jack_activate(u->client)) { - pa_log("jack_activate() failed"); - goto fail; - } + u->quit_requested = 1; + request_render(u); +} - if (do_connect) { - for (i = 0, p = ports; i < ss.channels; i++, p++) { - if (!*p) { - pa_log("not enough physical output ports, leaving unconnected."); - break; - } +static void io_event_cb(pa_mainloop_api* m, pa_io_event* e, int fd, + pa_io_event_flags_t flags, void* userdata) { + pa_module* self = userdata; + struct userdata* u; + char x; + jack_ringbuffer_data_t buffer[2]; /* The write area in the ringbuffer may + be split in two parts. */ + pa_memchunk chunk; /* This is the data source. */ + unsigned part1_length, part2_length; + unsigned sample_idx_part1, sample_idx_part2; + unsigned chan; + unsigned frame_size; + int rem; + + assert(m); + assert(e); + assert(flags == PA_IO_EVENT_INPUT); + assert(self); + assert(self->userdata); - pa_log_info("connecting %s to %s", jack_port_name(u->port[i]), *p); + u = self->userdata; + + assert(u->pipe_fds[0] == fd); - if (jack_connect(u->client, jack_port_name(u->port[i]), *p)) { - pa_log("failed to connect %s to %s, leaving unconnected.", jack_port_name(u->port[i]), *p); - break; - } - } + pa_read(fd, &x, 1, &u->pipe_fd_type); + if (u->quit_requested) { + pa_module_unload_request(self); + return; } - u->io_event = c->mainloop->io_new(c->mainloop, u->pipe_fds[0], PA_IO_EVENT_INPUT, io_event_cb, u); - - free(ports); - pa_modargs_free(ma); + frame_size = u->frame_size; + + /* No blocksize changes during rendering, please. */ + pthread_mutex_lock(&u->buffersize_mutex); + + jack_ringbuffer_get_write_vector(u->ringbuffer, buffer); + assert(((buffer[0].len % sizeof(float)) == 0) || (buffer[1].len == 0)); + + part1_length = buffer[0].len / sizeof(float); + part2_length = buffer[1].len / sizeof(float); + + /* If the amount of free space is not a multiple of the frame size, we have + to adjust the lengths in order to not get confused with which sample is + which channel. */ + if ((rem = (part1_length + part2_length) % u->channels) != 0) { + if (part2_length >= rem) { + part2_length -= rem; + } else { + part1_length -= rem - part2_length; + part2_length = 0; + } + } + + /* pa_sink_render_full doesn't accept zero length, so we have do the + copying only if there's data to copy, which actually makes a kind of + sense. */ + if (part1_length > 0 || part2_length > 0) { + pa_sink_render_full(u->sink, + (part1_length + part2_length) * sizeof(float), + &chunk); + + /* Write to the first part of the buffer. */ + for (sample_idx_part1 = 0; + sample_idx_part1 < part1_length; + sample_idx_part1++) { + float *s = + ((float*) ((uint8_t*) chunk.memblock->data + chunk.index)) + + sample_idx_part1; + float *d = ((float*) buffer[0].buf) + sample_idx_part1; + *d = *s; + } + + /* Write to the second part of the buffer. */ + for (sample_idx_part2 = 0; + sample_idx_part2 < part2_length; + sample_idx_part2++) { + float *s = + ((float*) ((uint8_t*) chunk.memblock->data + chunk.index)) + + sample_idx_part1 + sample_idx_part2; + float *d = ((float*) buffer[1].buf) + sample_idx_part2; + *d = *s; + } + + pa_memblock_unref(chunk.memblock); + + jack_ringbuffer_write_advance( + u->ringbuffer, (part1_length + part2_length) * sizeof(float)); + } + + /* Blocksize can be changed again. */ + pthread_mutex_unlock(&u->buffersize_mutex); +} - return 0; -fail: - if (ma) - pa_modargs_free(ma); +static void* fill_ringbuffer(void* arg) { + struct userdata* u = arg; + + assert(u); + + while (!u->quit_requested) { + if (u->ringbuffer_is_full) { + pthread_mutex_lock(&u->cond_mutex); + pthread_cond_wait(&u->ringbuffer_cond, + &u->cond_mutex); + pthread_mutex_unlock(&u->cond_mutex); + } + /* No, it's not full yet, but this must be set to one as soon as + possible, because if the jack thread manages to process another + block before we set this to one, we may end up waiting without + a reason. */ + u->ringbuffer_is_full = 1; - free(ports); + request_render(u); + } + + return NULL; +} - pa__done(c, m); - return -1; +static void request_render(struct userdata* u) { + char c = 'x'; + + assert(u); + + assert(u->pipe_fds[1] >= 0); + pa_write(u->pipe_fds[1], &c, 1, &u->pipe_fd_type); } -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u; - assert(c && m); +void pa__done(pa_core* c, pa_module* self) { + struct userdata* u; + + assert(c); + assert(self); - if (!(u = m->userdata)) + if (!self->userdata) return; - if (u->client) - jack_client_close(u->client); + u = self->userdata; + + if (u->filler_thread_is_running) { + u->quit_requested = 1; + pthread_cond_signal(&u->ringbuffer_cond); + pthread_join(u->filler_thread, NULL); + } + + if (u->j_client) + jack_client_close(u->j_client); if (u->io_event) c->mainloop->io_free(u->io_event); @@ -396,13 +866,18 @@ void pa__done(pa_core *c, pa_module*m) { pa_sink_disconnect(u->sink); pa_sink_unref(u->sink); } + + if (u->ringbuffer) + jack_ringbuffer_free(u->ringbuffer); if (u->pipe_fds[0] >= 0) - close(u->pipe_fds[0]); + pa_close(u->pipe_fds[0]); if (u->pipe_fds[1] >= 0) - close(u->pipe_fds[1]); - - pthread_mutex_destroy(&u->mutex); - pthread_cond_destroy(&u->cond); - pa_xfree(u); + pa_close(u->pipe_fds[1]); + + pthread_mutex_destroy(&u->buffersize_mutex); + pthread_cond_destroy(&u->ringbuffer_cond); + pthread_mutex_destroy(&u->cond_mutex); + pa_xfree(self->userdata); + self->userdata = NULL; } -- cgit From 6687dd013169fd8436aa1b45ccdacff074a40d05 Mon Sep 17 00:00:00 2001 From: Tanu Kaskinen Date: Fri, 24 Aug 2007 07:12:47 +0000 Subject: Corrected a bogus comment. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1716 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-jack-sink.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index 09a72e3a..a40ebe29 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -753,8 +753,7 @@ static void io_event_cb(pa_mainloop_api* m, pa_io_event* e, int fd, part2_length = buffer[1].len / sizeof(float); /* If the amount of free space is not a multiple of the frame size, we have - to adjust the lengths in order to not get confused with which sample is - which channel. */ + to truncate the lengths so that we process only complete frames. */ if ((rem = (part1_length + part2_length) % u->channels) != 0) { if (part2_length >= rem) { part2_length -= rem; -- cgit From a67c21f093202f142438689d3f7cfbdf4ea82eea Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 28 Oct 2007 19:13:50 +0000 Subject: merge 'lennart' branch back into trunk. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1971 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 6 + bootstrap.sh | 7 +- configure.ac | 233 +- libltdl/COPYING.LIB | 515 + libltdl/Makefile.am | 32 + libltdl/Makefile.in | 656 + libltdl/README | 10 + libltdl/acinclude.m4 | 7025 ++++++++ libltdl/aclocal.m4 | 875 + libltdl/config-h.in | 195 + libltdl/config.guess | 1516 ++ libltdl/config.h | 196 + libltdl/config.sub | 1622 ++ libltdl/configure | 23853 ++++++++++++++++++++++++++ libltdl/configure.ac | 79 + libltdl/install-sh | 519 + libltdl/ltdl.c | 4530 +++++ libltdl/ltdl.h | 367 + libltdl/ltmain.sh | 6938 ++++++++ libltdl/missing | 360 + libltdl/mkinstalldirs | 161 + libltdl/stamp-h1 | 1 + pulseaudio-text.svg | 388 + src/Makefile.am | 249 +- src/daemon/caps.c | 13 +- src/daemon/cmdline.c | 37 +- src/daemon/cpulimit.c | 52 +- src/daemon/daemon-conf.c | 257 +- src/daemon/daemon-conf.h | 7 +- src/daemon/daemon.conf.in | 13 +- src/daemon/default.pa.in | 63 +- src/daemon/dumpmodules.c | 18 +- src/daemon/ltdl-bind-now.c | 160 + src/daemon/ltdl-bind-now.h | 32 + src/daemon/main.c | 164 +- src/daemon/pulseaudio-module-xsmp.desktop | 10 + src/modules/alsa-util.c | 202 +- src/modules/alsa-util.h | 9 +- src/modules/dbus-util.c | 285 +- src/modules/gconf/gconf-helper.c | 10 +- src/modules/gconf/module-gconf.c | 99 +- src/modules/ladspa.h | 603 + src/modules/module-alsa-sink.c | 954 +- src/modules/module-alsa-source.c | 913 +- src/modules/module-cli.c | 30 +- src/modules/module-combine.c | 1064 +- src/modules/module-default-device-restore.c | 103 + src/modules/module-defs.h.m4 | 4 +- src/modules/module-detect.c | 47 +- src/modules/module-esound-compat-spawnfd.c | 17 +- src/modules/module-esound-compat-spawnpid.c | 14 +- src/modules/module-esound-sink.c | 477 +- src/modules/module-hal-detect.c | 858 +- src/modules/module-jack-sink.c | 1025 +- src/modules/module-jack-source.c | 315 +- src/modules/module-ladspa-sink.c | 673 + src/modules/module-lirc.c | 50 +- src/modules/module-match.c | 27 +- src/modules/module-mmkbd-evdev.c | 44 +- src/modules/module-native-protocol-fd.c | 19 +- src/modules/module-null-sink.c | 167 +- src/modules/module-oss-mmap.c | 637 - src/modules/module-oss.c | 1469 +- src/modules/module-pipe-sink.c | 281 +- src/modules/module-pipe-source.c | 244 +- src/modules/module-protocol-stub.c | 49 +- src/modules/module-remap-sink.c | 334 + src/modules/module-rescue-streams.c | 54 +- src/modules/module-sine.c | 81 +- src/modules/module-solaris.c | 690 +- src/modules/module-suspend-on-idle.c | 473 + src/modules/module-tunnel.c | 4 +- src/modules/module-volume-restore.c | 47 +- src/modules/module-x11-bell.c | 54 +- src/modules/module-x11-publish.c | 24 +- src/modules/module-x11-xsmp.c | 195 + src/modules/module-zeroconf-publish.c | 569 +- src/modules/oss-util.c | 136 +- src/modules/oss-util.h | 9 +- src/modules/rtp/module-rtp-recv.c | 327 +- src/modules/rtp/module-rtp-send.c | 122 +- src/modules/rtp/rtp.c | 101 +- src/modules/rtp/sap.c | 40 +- src/modules/rtp/sdp.c | 36 +- src/pulse/browser.c | 62 +- src/pulse/cdecl.h | 18 + src/pulse/channelmap.c | 108 +- src/pulse/channelmap.h | 9 +- src/pulse/client-conf-x11.c | 6 +- src/pulse/client-conf.c | 19 +- src/pulse/context.c | 198 +- src/pulse/glib-mainloop.c | 2 - src/pulse/internal.h | 9 +- src/pulse/introspect.c | 372 +- src/pulse/introspect.h | 16 + src/pulse/mainloop-api.c | 22 +- src/pulse/mainloop-signal.c | 55 +- src/pulse/mainloop.c | 173 +- src/pulse/operation.c | 41 +- src/pulse/sample.c | 79 +- src/pulse/sample.h | 18 +- src/pulse/scache.c | 17 +- src/pulse/simple.c | 49 +- src/pulse/simple.h | 2 +- src/pulse/stream.c | 319 +- src/pulse/subscribe.c | 19 +- src/pulse/thread-mainloop.c | 56 +- src/pulse/thread-mainloop.h | 3 + src/pulse/timeval.c | 59 +- src/pulse/timeval.h | 17 +- src/pulse/utf8.c | 32 +- src/pulse/utf8.h | 2 +- src/pulse/util.c | 42 +- src/pulse/util.h | 2 +- src/pulse/volume.c | 34 +- src/pulse/volume.h | 20 +- src/pulse/xmalloc.c | 14 +- src/pulse/xmalloc.h | 9 + src/pulsecore/anotify.c | 145 - src/pulsecore/anotify.h | 40 - src/pulsecore/asyncmsgq.c | 303 + src/pulsecore/asyncmsgq.h | 75 + src/pulsecore/asyncq.c | 213 + src/pulsecore/asyncq.h | 56 + src/pulsecore/atomic.h | 193 +- src/pulsecore/authkey-prop.c | 49 +- src/pulsecore/authkey.c | 80 +- src/pulsecore/autoload.c | 43 +- src/pulsecore/avahi-wrap.c | 52 +- src/pulsecore/cli-command.c | 497 +- src/pulsecore/cli-text.c | 122 +- src/pulsecore/cli.c | 30 +- src/pulsecore/client.c | 25 +- src/pulsecore/conf-parser.c | 35 +- src/pulsecore/core-def.h | 5 +- src/pulsecore/core-error.c | 178 +- src/pulsecore/core-scache.c | 94 +- src/pulsecore/core-scache.h | 1 + src/pulsecore/core-subscribe.c | 40 +- src/pulsecore/core-util.c | 639 +- src/pulsecore/core-util.h | 44 +- src/pulsecore/core.c | 73 +- src/pulsecore/core.h | 55 +- src/pulsecore/creds.h | 4 +- src/pulsecore/dynarray.c | 20 +- src/pulsecore/endianmacros.h | 78 +- src/pulsecore/esound.h | 2 +- src/pulsecore/fdsem.c | 276 + src/pulsecore/fdsem.h | 49 + src/pulsecore/ffmpeg/Makefile | 13 + src/pulsecore/ffmpeg/avcodec.h | 82 + src/pulsecore/ffmpeg/dsputil.h | 1 + src/pulsecore/ffmpeg/resample2.c | 324 + src/pulsecore/flist.c | 62 +- src/pulsecore/flist.h | 27 + src/pulsecore/g711.c | 392 +- src/pulsecore/gccmacro.h | 25 + src/pulsecore/hashmap.c | 39 +- src/pulsecore/hashmap.h | 4 +- src/pulsecore/hook-list.c | 26 +- src/pulsecore/idxset.c | 130 +- src/pulsecore/idxset.h | 5 - src/pulsecore/inet_ntop.c | 4 +- src/pulsecore/iochannel.c | 168 +- src/pulsecore/iochannel.h | 18 +- src/pulsecore/ioline.c | 95 +- src/pulsecore/ipacl.c | 24 +- src/pulsecore/llist.h | 123 +- src/pulsecore/log.c | 29 +- src/pulsecore/ltdl-helper.c | 64 + src/pulsecore/ltdl-helper.h | 34 + src/pulsecore/macro.h | 149 + src/pulsecore/mcalign.c | 49 +- src/pulsecore/memblock.c | 685 +- src/pulsecore/memblock.h | 65 +- src/pulsecore/memblockq.c | 331 +- src/pulsecore/memblockq.h | 22 +- src/pulsecore/memchunk.c | 52 +- src/pulsecore/memchunk.h | 11 +- src/pulsecore/modargs.c | 50 +- src/pulsecore/modargs.h | 4 +- src/pulsecore/modinfo.c | 31 +- src/pulsecore/modinfo.h | 2 +- src/pulsecore/module.c | 122 +- src/pulsecore/module.h | 10 +- src/pulsecore/msgobject.c | 49 + src/pulsecore/msgobject.h | 54 + src/pulsecore/mutex-posix.c | 70 +- src/pulsecore/mutex-win32.c | 2 +- src/pulsecore/mutex.h | 10 +- src/pulsecore/namereg.c | 35 +- src/pulsecore/native-common.h | 5 + src/pulsecore/object.c | 72 + src/pulsecore/object.h | 106 + src/pulsecore/once-posix.c | 71 - src/pulsecore/once-win32.c | 69 - src/pulsecore/once.c | 96 + src/pulsecore/once.h | 48 +- src/pulsecore/packet.c | 28 +- src/pulsecore/packet.h | 4 +- src/pulsecore/parseaddr.c | 14 +- src/pulsecore/pdispatch.c | 73 +- src/pulsecore/pid.c | 74 +- src/pulsecore/pipe.c | 16 +- src/pulsecore/play-memblockq.c | 194 +- src/pulsecore/play-memblockq.h | 10 + src/pulsecore/play-memchunk.c | 160 +- src/pulsecore/poll.c | 2 +- src/pulsecore/props.c | 43 +- src/pulsecore/protocol-cli.c | 22 +- src/pulsecore/protocol-esound.c | 640 +- src/pulsecore/protocol-http.c | 39 +- src/pulsecore/protocol-native.c | 1651 +- src/pulsecore/protocol-simple.c | 368 +- src/pulsecore/pstream-util.c | 24 +- src/pulsecore/pstream.c | 367 +- src/pulsecore/pstream.h | 8 +- src/pulsecore/queue.c | 52 +- src/pulsecore/random.c | 21 +- src/pulsecore/refcnt.h | 10 +- src/pulsecore/resampler.c | 1099 +- src/pulsecore/resampler.h | 31 +- src/pulsecore/rtclock.c | 98 + src/pulsecore/rtclock.h | 43 + src/pulsecore/rtpoll.c | 751 + src/pulsecore/rtpoll.h | 116 + src/pulsecore/rtsig.c | 133 + src/pulsecore/rtsig.h | 41 + src/pulsecore/sample-util.c | 288 +- src/pulsecore/sample-util.h | 10 +- src/pulsecore/sconv-s16be.c | 7 +- src/pulsecore/sconv-s16be.h | 15 +- src/pulsecore/sconv-s16le.c | 65 +- src/pulsecore/sconv-s16le.h | 15 +- src/pulsecore/sconv.c | 273 +- src/pulsecore/sconv.h | 10 +- src/pulsecore/semaphore-posix.c | 69 + src/pulsecore/semaphore-win32.c | 65 + src/pulsecore/semaphore.h | 35 + src/pulsecore/shm.c | 247 +- src/pulsecore/shm.h | 2 + src/pulsecore/sink-input.c | 832 +- src/pulsecore/sink-input.h | 163 +- src/pulsecore/sink.c | 984 +- src/pulsecore/sink.h | 161 +- src/pulsecore/sioman.c | 14 +- src/pulsecore/socket-client.c | 180 +- src/pulsecore/socket-server.c | 121 +- src/pulsecore/socket-util.c | 118 +- src/pulsecore/socket-util.h | 5 +- src/pulsecore/sound-file-stream.c | 249 +- src/pulsecore/sound-file.c | 71 +- src/pulsecore/source-output.c | 376 +- src/pulsecore/source-output.h | 97 +- src/pulsecore/source.c | 560 +- src/pulsecore/source.h | 140 +- src/pulsecore/speex/Makefile | 13 + src/pulsecore/speex/arch.h | 197 + src/pulsecore/speex/fixed_generic.h | 106 + src/pulsecore/speex/resample.c | 1114 ++ src/pulsecore/speex/speex_resampler.h | 328 + src/pulsecore/speexwrap.h | 48 + src/pulsecore/strbuf.c | 49 +- src/pulsecore/strlist.c | 39 +- src/pulsecore/tagstruct.c | 125 +- src/pulsecore/thread-mq.c | 112 + src/pulsecore/thread-mq.h | 49 + src/pulsecore/thread-posix.c | 59 +- src/pulsecore/thread-win32.c | 19 +- src/pulsecore/thread.h | 61 + src/pulsecore/time-smoother.c | 378 + src/pulsecore/time-smoother.h | 43 + src/pulsecore/tokenizer.c | 34 +- src/pulsecore/winsock.h | 2 + src/pulsecore/x11prop.c | 1 - src/pulsecore/x11wrap.c | 92 +- src/tests/asyncmsgq-test.c | 110 + src/tests/asyncq-test.c | 87 + src/tests/hook-list-test.c | 4 + src/tests/interpol-test.c | 2 +- src/tests/mcalign-test.c | 17 +- src/tests/memblock-test.c | 42 +- src/tests/memblockq-test.c | 20 +- src/tests/queue-test.c | 69 + src/tests/resampler-test.c | 227 + src/tests/rtpoll-test.c | 91 + src/tests/sig2str-test.c | 39 + src/tests/smoother-test.c | 80 + src/tests/thread-mainloop-test.c | 13 +- src/tests/thread-test.c | 6 +- src/utils/pactl.c | 123 +- src/utils/padsp.c | 71 +- src/utils/paplay.c | 2 +- src/utils/pasuspender.c | 316 + todo | 11 +- 295 files changed, 78734 insertions(+), 11291 deletions(-) create mode 100644 libltdl/COPYING.LIB create mode 100644 libltdl/Makefile.am create mode 100644 libltdl/Makefile.in create mode 100644 libltdl/README create mode 100644 libltdl/acinclude.m4 create mode 100644 libltdl/aclocal.m4 create mode 100644 libltdl/config-h.in create mode 100755 libltdl/config.guess create mode 100644 libltdl/config.h create mode 100755 libltdl/config.sub create mode 100755 libltdl/configure create mode 100644 libltdl/configure.ac create mode 100755 libltdl/install-sh create mode 100644 libltdl/ltdl.c create mode 100644 libltdl/ltdl.h create mode 100644 libltdl/ltmain.sh create mode 100755 libltdl/missing create mode 100755 libltdl/mkinstalldirs create mode 100644 libltdl/stamp-h1 create mode 100644 pulseaudio-text.svg create mode 100644 src/daemon/ltdl-bind-now.c create mode 100644 src/daemon/ltdl-bind-now.h create mode 100644 src/daemon/pulseaudio-module-xsmp.desktop create mode 100644 src/modules/ladspa.h create mode 100644 src/modules/module-default-device-restore.c create mode 100644 src/modules/module-ladspa-sink.c delete mode 100644 src/modules/module-oss-mmap.c create mode 100644 src/modules/module-remap-sink.c create mode 100644 src/modules/module-suspend-on-idle.c create mode 100644 src/modules/module-x11-xsmp.c delete mode 100644 src/pulsecore/anotify.c delete mode 100644 src/pulsecore/anotify.h create mode 100644 src/pulsecore/asyncmsgq.c create mode 100644 src/pulsecore/asyncmsgq.h create mode 100644 src/pulsecore/asyncq.c create mode 100644 src/pulsecore/asyncq.h create mode 100644 src/pulsecore/fdsem.c create mode 100644 src/pulsecore/fdsem.h create mode 100644 src/pulsecore/ffmpeg/Makefile create mode 100644 src/pulsecore/ffmpeg/avcodec.h create mode 100644 src/pulsecore/ffmpeg/dsputil.h create mode 100644 src/pulsecore/ffmpeg/resample2.c create mode 100644 src/pulsecore/ltdl-helper.c create mode 100644 src/pulsecore/ltdl-helper.h create mode 100644 src/pulsecore/macro.h create mode 100644 src/pulsecore/msgobject.c create mode 100644 src/pulsecore/msgobject.h create mode 100644 src/pulsecore/object.c create mode 100644 src/pulsecore/object.h delete mode 100644 src/pulsecore/once-posix.c delete mode 100644 src/pulsecore/once-win32.c create mode 100644 src/pulsecore/once.c create mode 100644 src/pulsecore/rtclock.c create mode 100644 src/pulsecore/rtclock.h create mode 100644 src/pulsecore/rtpoll.c create mode 100644 src/pulsecore/rtpoll.h create mode 100644 src/pulsecore/rtsig.c create mode 100644 src/pulsecore/rtsig.h create mode 100644 src/pulsecore/semaphore-posix.c create mode 100644 src/pulsecore/semaphore-win32.c create mode 100644 src/pulsecore/semaphore.h create mode 100644 src/pulsecore/speex/Makefile create mode 100644 src/pulsecore/speex/arch.h create mode 100644 src/pulsecore/speex/fixed_generic.h create mode 100644 src/pulsecore/speex/resample.c create mode 100644 src/pulsecore/speex/speex_resampler.h create mode 100644 src/pulsecore/speexwrap.h create mode 100644 src/pulsecore/thread-mq.c create mode 100644 src/pulsecore/thread-mq.h create mode 100644 src/pulsecore/time-smoother.c create mode 100644 src/pulsecore/time-smoother.h create mode 100644 src/tests/asyncmsgq-test.c create mode 100644 src/tests/asyncq-test.c create mode 100644 src/tests/queue-test.c create mode 100644 src/tests/resampler-test.c create mode 100644 src/tests/rtpoll-test.c create mode 100644 src/tests/sig2str-test.c create mode 100644 src/tests/smoother-test.c create mode 100644 src/utils/pasuspender.c diff --git a/Makefile.am b/Makefile.am index abc3d776..288c24ef 100644 --- a/Makefile.am +++ b/Makefile.am @@ -48,4 +48,10 @@ doxygen: eolspace: find \( -name '*.c' -o -name '*.h' -o -name 'Makefile.am' \) -exec perl -i -pe 's/\s+\n$$/\1\n/;' \{\} \; +untabify: + find \( -name '*.c' -o -name '*.h' \) -exec perl -i -pe 's/\t/ /g;' \{\} \; + +fedora-snapshot: dist + cp $(distdir).tar.gz $$HOME/cvs.fedora/pulseaudio/devel/$(distdir).svn`date +%Y%m%d`.tar.gz + .PHONY: homepage distcleancheck doxygen diff --git a/bootstrap.sh b/bootstrap.sh index b85f025e..f23acbfe 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -25,10 +25,10 @@ run_versioned() { V=$(echo "$2" | sed -e 's,\.,,g') - if [ -e "`which $1$V`" ] ; then + if [ -e "`which $1$V 2> /dev/null`" ] ; then P="$1$V" else - if [ -e "`which $1-$2`" ] ; then + if [ -e "`which $1-$2 2> /dev/null`" ] ; then P="$1-$2" else P="$1" @@ -48,13 +48,14 @@ else rm -rf autom4te.cache rm -f config.cache + touch config.rpath test "x$LIBTOOLIZE" = "x" && LIBTOOLIZE=libtoolize "$LIBTOOLIZE" -c --force --ltdl run_versioned aclocal "$VERSION" run_versioned autoconf 2.59 -Wall run_versioned autoheader 2.59 - run_versioned automake "$VERSION" -a -c --foreign + run_versioned automake "$VERSION" --copy --foreign --add-missing if test "x$NOCONFIGURE" = "x"; then CFLAGS="-g -O0" ./configure --sysconfdir=/etc --localstatedir=/var --enable-force-preopen "$@" diff --git a/configure.ac b/configure.ac index a195da20..567dc4ed 100644 --- a/configure.ac +++ b/configure.ac @@ -26,7 +26,7 @@ AC_PREREQ(2.57) m4_define(PA_MAJOR, [0]) m4_define(PA_MINOR, [9]) -m4_define(PA_MICRO, [6]) +m4_define(PA_MICRO, [7]) AC_INIT([pulseaudio], PA_MAJOR.PA_MINOR.PA_MICRO,[mzcbylcnhqvb (at) 0pointer (dot) de]) AC_CONFIG_SRCDIR([src/daemon/main.c]) @@ -34,13 +34,13 @@ AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) AC_SUBST(PA_MAJORMINOR, "PA_MAJOR.PA_MINOR") -AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/pulseaudio/]) +AC_SUBST(PACKAGE_URL, [http://pulseaudio.org/]) AC_SUBST(PA_API_VERSION, 10) -AC_SUBST(PA_PROTOCOL_VERSION, 10) +AC_SUBST(PA_PROTOCOL_VERSION, 11) -AC_SUBST(LIBPULSE_VERSION_INFO, [2:0:2]) -AC_SUBST(LIBPULSECORE_VERSION_INFO, [3:0:0]) +AC_SUBST(LIBPULSE_VERSION_INFO, [3:0:3]) +AC_SUBST(LIBPULSECORE_VERSION_INFO, [4:0:0]) AC_SUBST(LIBPULSE_SIMPLE_VERSION_INFO, [0:0:0]) AC_SUBST(LIBPULSE_BROWSE_VERSION_INFO, [1:0:1]) AC_SUBST(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO, [0:2:0]) @@ -81,8 +81,8 @@ fi # GCC flags test_gcc_flag() { - AC_LANG_CONFTEST([int main() {}]) - $CC -c conftest.c $CFLAGS $@ > /dev/null 2> /dev/null + AC_LANG_CONFTEST([int main(int argc, char*argv[]) {}]) + $CC -c conftest.c $CFLAGS -o conftest.o > /dev/null 2> /dev/null ret=$? rm -f conftest.o return $ret @@ -93,28 +93,64 @@ if test "x$GCC" = "xyes" ; then # We use gnu99 instead of c99 because many have interpreted the standard # in a way that int64_t isn't defined on non-64 bit platforms. - DESIRED_FLAGS="-std=gnu99 -Wall -W -Wextra -pedantic -pipe -Wformat -Wold-style-definition -Wdeclaration-after-statement -Wfloat-equal -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-noreturn -Wshadow -Wendif-labels -Wpointer-arith -Wcast-align -Wwrite-strings -Winline -Wno-unused-parameter" + DESIRED_FLAGS="-std=gnu99 -Wall -W -Wextra -pedantic -pipe -Wformat -Wold-style-definition -Wdeclaration-after-statement -Wfloat-equal -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-noreturn -Wshadow -Wendif-labels -Wpointer-arith -Wcast-align -Wwrite-strings -Winline -Wno-unused-parameter -ffast-math" for flag in $DESIRED_FLAGS ; do AC_MSG_CHECKING([whether $CC accepts $flag]) - if test_gcc_flag $flag ; then + if test_gcc_flag $flag ; then CFLAGS="$CFLAGS $flag" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi - done + done +fi + +AC_MSG_CHECKING([whether $CC knows __sync_bool_compare_and_swap()]) +AC_LANG_CONFTEST([int main() { int a = 4; __sync_bool_compare_and_swap(&a, 4, 5); }]) +$CC conftest.c $CFLAGS -o conftest > /dev/null 2> /dev/null +ret=$? +rm -f conftest.o conftest +if test $ret -eq 0 ; then + AC_DEFINE([HAVE_ATOMIC_BUILTINS], 1, [Have __sync_bool_compare_and_swap() and friends.]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +AC_MSG_CHECKING([whether $CC knows __thread]) +AC_LANG_CONFTEST([static __thread int a = 6; int main() { a = 5; }]) +$CC conftest.c $CFLAGS -o conftest > /dev/null 2> /dev/null +ret=$? +rm -f conftest.o conftest +if test $ret -eq 0 ; then + AC_DEFINE([HAVE_TLS_BUILTIN], 1, [Have __thread().]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +AC_MSG_CHECKING([whether $CC knows _Bool]) +AC_LANG_CONFTEST([int main() { _Bool b; }]) +$CC conftest.c $CFLAGS -o conftest > /dev/null 2> /dev/null +ret=$? +rm -f conftest.o conftest +if test $ret -eq 0 ; then + AC_DEFINE([HAVE_STD_BOOL], 1, [Have _Bool.]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) fi #### libtool stuff #### AC_LTDL_ENABLE_INSTALL AC_LIBLTDL_INSTALLABLE -AC_SUBST(LTDLINCL) -AC_SUBST(LIBLTDL) AC_LIBTOOL_DLOPEN AC_LIBTOOL_WIN32_DLL AC_PROG_LIBTOOL +AC_SUBST(LTDLINCL) +AC_SUBST(LIBLTDL) AC_CONFIG_SUBDIRS(libltdl) if test "x$enable_ltdl_install" = "xno" && test "x$ac_cv_lib_ltdl_lt_dlinit" = "xno" ; then @@ -149,9 +185,9 @@ AC_HEADER_STDC # POSIX AC_CHECK_HEADERS([arpa/inet.h glob.h grp.h netdb.h netinet/in.h \ - netinet/in_systm.h netinet/tcp.h pwd.h sched.h \ + netinet/in_systm.h netinet/tcp.h poll.h pwd.h sched.h \ sys/mman.h sys/resource.h sys/select.h sys/socket.h sys/wait.h \ - syslog.h]) + syslog.h sys/dl.h dlfcn.h linux/sockios.h]) AC_CHECK_HEADERS([netinet/ip.h], [], [], [#include #if HAVE_NETINET_IN_H @@ -167,9 +203,6 @@ AC_CHECK_HEADERS([sys/un.h], [HAVE_AF_UNIX=1], [HAVE_AF_UNIX=0]) AM_CONDITIONAL(HAVE_REGEX, test "x$HAVE_REGEX" = "x1") AM_CONDITIONAL(HAVE_AF_UNIX, test "x$HAVE_AF_UNIX" = "x1") -# XPG4-UNIX -AC_CHECK_HEADERS([sys/poll.h]) - # Linux AC_CHECK_HEADERS([linux/input.h], [HAVE_EVDEV=1], [HAVE_EVDEV=0]) @@ -185,6 +218,8 @@ AC_CHECK_HEADERS([windows.h winsock2.h ws2tcpip.h]) # Other AC_CHECK_HEADERS([sys/ioctl.h]) +AC_CHECK_HEADERS([byteswap.h]) +AC_CHECK_HEADERS([sys/syscall.h]) #### Typdefs, structures, etc. #### @@ -235,13 +270,17 @@ AC_CHECK_FUNCS([getopt_long], [], [AC_CHECK_LIB([iberty], [getopt_long])]) #### Check for functions #### +# ISO +AC_CHECK_FUNCS([lrintf strtof]) + # POSIX AC_FUNC_FORK AC_FUNC_GETGROUPS AC_FUNC_SELECT_ARGTYPES -AC_CHECK_FUNCS([chmod chown getaddrinfo getgrgid_r getpwuid_r gettimeofday \ - getuid inet_ntop inet_pton nanosleep pipe posix_memalign setpgid setsid \ - shm_open sigaction sleep sysconf]) +AC_CHECK_FUNCS([chmod chown clock_gettime getaddrinfo getgrgid_r \ + getpwuid_r gettimeofday getuid inet_ntop inet_pton mlock nanosleep \ + pipe posix_fadvise posix_madvise posix_memalign setpgid setsid shm_open \ + sigaction sleep sysconf]) AC_CHECK_FUNCS([mkfifo], [HAVE_MKFIFO=1], [HAVE_MKFIFO=0]) AM_CONDITIONAL(HAVE_MKFIFO, test "x$HAVE_MKFIFO" = "x1") @@ -260,7 +299,22 @@ AC_CHECK_FUNCS([lstat]) # Non-standard -AC_CHECK_FUNCS([setresuid setresgid setreuid setregid seteuid setegid]) +AC_CHECK_FUNCS([setresuid setresgid setreuid setregid seteuid setegid ppoll strsignal sig2str strtof_l]) + +AC_MSG_CHECKING([for PTHREAD_PRIO_INHERIT]) +AC_LANG_CONFTEST([AC_LANG_SOURCE([[ +#include +int main() { int i = PTHREAD_PRIO_INHERIT; }]])]) +$PTHREAD_CC conftest.c $PTHREAD_CFLAGS $CFLAGS $PTHREAD_LIBS -o conftest > /dev/null 2> /dev/null +ret=$? +rm -f conftest.o conftest + +if test $ret -eq 0 ; then + AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi #### Large File-Support (LFS) #### @@ -324,12 +378,6 @@ fi PKG_PROG_PKG_CONFIG -#### Sample rate conversion #### - -PKG_CHECK_MODULES(LIBSAMPLERATE, [ samplerate >= 0.1.0 ]) -AC_SUBST(LIBSAMPLERATE_CFLAGS) -AC_SUBST(LIBSAMPLERATE_LIBS) - #### Sound file #### PKG_CHECK_MODULES(LIBSNDFILE, [ sndfile >= 1.0.10 ]) @@ -347,10 +395,45 @@ if test "x$os_is_win32" != "x1" ; then LIBS="$LIBS -latomic_ops" fi +#### Libsamplerate support (optional) #### + +AC_ARG_ENABLE([samplerate], + AC_HELP_STRING([--disable-samplerate], [Disable optional libsamplerate support]), + [ + case "${enableval}" in + yes) samplerate=yes ;; + no) samplerate=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-samplerate) ;; + esac + ], + [samplerate=auto]) + +if test "x${samplerate}" != xno ; then + PKG_CHECK_MODULES(LIBSAMPLERATE, [ samplerate >= 0.1.0 ], + HAVE_LIBSAMPLERATE=1, + [ + HAVE_LIBSAMPLERATE=0 + if test "x$samplerate" = xyes ; then + AC_MSG_ERROR([*** Libsamplerate not found]) + fi + ]) +else + HAVE_LIBSAMPLERATE=0 +fi + +if test "x${HAVE_LIBSAMPLERATE}" = x1 ; then + AC_DEFINE([HAVE_LIBSAMPLERATE], 1, [Have libsamplerate?]) +fi + +AC_SUBST(LIBSAMPLERATE_CFLAGS) +AC_SUBST(LIBSAMPLERATE_LIBS) +AC_SUBST(HAVE_LIBSAMPLERATE) +AM_CONDITIONAL([HAVE_LIBSAMPLERATE], [test "x$HAVE_LIBSAMPLERATE" = x1]) + #### OSS support (optional) #### -AC_ARG_ENABLE([oss], - AC_HELP_STRING([--disable-oss], [Disable optional OSS support]), +AC_ARG_ENABLE([oss], + AC_HELP_STRING([--disable-oss], [Disable optional OSS support]), [ case "${enableval}" in yes) oss=yes ;; @@ -382,8 +465,8 @@ AM_CONDITIONAL([HAVE_OSS], [test "x$HAVE_OSS" = x1]) #### ALSA support (optional) #### -AC_ARG_ENABLE([alsa], - AC_HELP_STRING([--disable-alsa], [Disable optional ALSA support]), +AC_ARG_ENABLE([alsa], + AC_HELP_STRING([--disable-alsa], [Disable optional ALSA support]), [ case "${enableval}" in yes) alsa=yes ;; @@ -410,14 +493,14 @@ else fi AC_SUBST(ASOUNDLIB_CFLAGS) -AC_SUBST(ASOUNDLIB_LIBS) +AC_SUBST(ASOUNDLIB_LIBS) AC_SUBST(HAVE_ALSA) AM_CONDITIONAL([HAVE_ALSA], [test "x$HAVE_ALSA" = x1]) #### Solaris audio support (optional) #### -AC_ARG_ENABLE([solaris], - AC_HELP_STRING([--disable-solaris], [Disable optional Solaris audio support]), +AC_ARG_ENABLE([solaris], + AC_HELP_STRING([--disable-solaris], [Disable optional Solaris audio support]), [ case "${enableval}" in yes) solaris=yes ;; @@ -448,8 +531,8 @@ AM_CONDITIONAL([HAVE_SOLARIS], [test "x$HAVE_SOLARIS" = x1]) #### GLib 2 support (optional) #### -AC_ARG_ENABLE([glib2], - AC_HELP_STRING([--disable-glib2], [Disable optional GLib 2 support]), +AC_ARG_ENABLE([glib2], + AC_HELP_STRING([--disable-glib2], [Disable optional GLib 2 support]), [ case "${enableval}" in yes) glib2=yes ;; @@ -479,8 +562,8 @@ AM_CONDITIONAL([HAVE_GLIB20], [test "x$HAVE_GLIB20" = x1]) #### GConf support (optional) #### -AC_ARG_ENABLE([gconf], - AC_HELP_STRING([--disable-gconf], [Disable optional GConf support]), +AC_ARG_ENABLE([gconf], + AC_HELP_STRING([--disable-gconf], [Disable optional GConf support]), [ case "${enableval}" in yes) gconf=yes ;; @@ -510,8 +593,8 @@ AM_CONDITIONAL([HAVE_GCONF], [test "x$HAVE_GCONF" = x1]) #### Avahi support (optional) #### -AC_ARG_ENABLE([avahi], - AC_HELP_STRING([--disable-avahi], [Disable optional Avahi support]), +AC_ARG_ENABLE([avahi], + AC_HELP_STRING([--disable-avahi], [Disable optional Avahi support]), [ case "${enableval}" in yes) avahi=yes ;; @@ -547,8 +630,8 @@ AC_SUBST(LIBOIL_LIBS) ### JACK (optional) #### -AC_ARG_ENABLE([jack], - AC_HELP_STRING([--disable-jack], [Disable optional JACK support]), +AC_ARG_ENABLE([jack], + AC_HELP_STRING([--disable-jack], [Disable optional JACK support]), [ case "${enableval}" in yes) jack=yes ;; @@ -578,8 +661,8 @@ AM_CONDITIONAL([HAVE_JACK], [test "x$HAVE_JACK" = x1]) #### Async DNS support (optional) #### -AC_ARG_ENABLE([asyncns], - AC_HELP_STRING([--disable-asyncns], [Disable optional Async DNS support]), +AC_ARG_ENABLE([asyncns], + AC_HELP_STRING([--disable-asyncns], [Disable optional Async DNS support]), [ case "${enableval}" in yes) asyncns=yes ;; @@ -613,8 +696,8 @@ fi #### TCP wrappers (optional) #### -AC_ARG_ENABLE([tcpwrap], - AC_HELP_STRING([--disable-tcpwrap], [Disable optional TCP wrappers support]), +AC_ARG_ENABLE([tcpwrap], + AC_HELP_STRING([--disable-tcpwrap], [Disable optional TCP wrappers support]), [ case "${enableval}" in yes) tcpwrap=yes ;; @@ -637,8 +720,8 @@ AC_SUBST(LIBWRAP_LIBS) #### LIRC support (optional) #### -AC_ARG_ENABLE([lirc], - AC_HELP_STRING([--disable-lirc], [Disable optional LIRC support]), +AC_ARG_ENABLE([lirc], + AC_HELP_STRING([--disable-lirc], [Disable optional LIRC support]), [ case "${enableval}" in yes) lirc=yes ;; @@ -663,8 +746,8 @@ AM_CONDITIONAL([HAVE_LIRC], [test "x$HAVE_LIRC" = x1]) #### HAL support (optional) #### -AC_ARG_ENABLE([hal], - AC_HELP_STRING([--disable-hal], [Disable optional HAL support]), +AC_ARG_ENABLE([hal], + AC_HELP_STRING([--disable-hal], [Disable optional HAL support]), [ case "${enableval}" in yes) hal=yes ;; @@ -673,7 +756,6 @@ AC_ARG_ENABLE([hal], esac ], [hal=auto]) - if test "x${hal}" != xno -a \( "x$HAVE_OSS" = "x1" -o "x$HAVE_ALSA" = "x1" \) ; then PKG_CHECK_MODULES(HAL, [ hal >= 0.5.7 ], HAVE_HAL=1, @@ -692,6 +774,49 @@ AC_SUBST(HAL_LIBS) AC_SUBST(HAVE_HAL) AM_CONDITIONAL([HAVE_HAL], [test "x$HAVE_HAL" = x1]) +#### D-Bus support (optional) #### + +AC_ARG_ENABLE([dbus], + AC_HELP_STRING([--disable-dbus], [Disable optional D-Bus support]), + [ + case "${enableval}" in + yes) dbus=yes ;; + no) dbus=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-dbus) ;; + esac + ], + [dbus=auto]) + +if test "x$HAVE_HAL" = x1 ; then + dbus=yes +fi + +if test "x${dbus}" != xno ; then + + PKG_CHECK_MODULES(DBUS, [ dbus-1 >= 1.0.0 ], + [ + HAVE_DBUS=1 + saved_LIBS="$LIBS" + LIBS="$LIBS $DBUS_LIBS" + AC_CHECK_FUNCS(dbus_watch_get_unix_fd) + LIBS="$saved_LIBS" + AC_DEFINE([HAVE_DBUS], 1, [Have D-Bus.]) + ], + [ + HAVE_DBUS=0 + if test "x$dbus" = xyes ; then + AC_MSG_ERROR([*** D-Bus support not found]) + fi + ]) +else + HAVE_DBUS=0 +fi + +AC_SUBST(DBUS_CFLAGS) +AC_SUBST(DBUS_LIBS) +AC_SUBST(HAVE_DBUS) +AM_CONDITIONAL([HAVE_DBUS], [test "x$HAVE_DBUS" = x1]) + #### PulseAudio system group & user ##### AC_ARG_WITH(system_user, AS_HELP_STRING([--with-system-user=],[User for running the PulseAudio daemon as a system-wide instance (pulse)])) @@ -845,6 +970,11 @@ if test "x${LIBWRAP_LIBS}" != x ; then ENABLE_TCPWRAP=yes fi +ENABLE_LIBSAMPLERATE=no +if test "x${HAVE_LIBSAMPLERATE}" = "x1" ; then + ENABLE_LIBSAMPLERATE=yes +fi + echo " ---{ $PACKAGE_NAME $VERSION }--- @@ -866,6 +996,7 @@ echo " Enable LIRC: ${ENABLE_LIRC} Enable HAL: ${ENABLE_HAL} Enable TCP Wrappers: ${ENABLE_TCPWRAP} + Enable libsamplerate: ${ENABLE_LIBSAMPLERATE} System User: ${PA_SYSTEM_USER} System Group: ${PA_SYSTEM_GROUP} Realtime Group: ${PA_REALTIME_GROUP} diff --git a/libltdl/COPYING.LIB b/libltdl/COPYING.LIB new file mode 100644 index 00000000..ba2be481 --- /dev/null +++ b/libltdl/COPYING.LIB @@ -0,0 +1,515 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. +^L + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. +^L + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. +^L + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. +^L + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. +^L + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. +^L + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. +^L + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS +^L + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper +mail. + +You should also get your employer (if you work as a programmer) or +your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James +Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/libltdl/Makefile.am b/libltdl/Makefile.am new file mode 100644 index 00000000..2a1e7019 --- /dev/null +++ b/libltdl/Makefile.am @@ -0,0 +1,32 @@ +## Process this file with automake to produce Makefile.in + +AUTOMAKE_OPTIONS = no-dependencies foreign + +if INSTALL_LTDL +include_HEADERS = ltdl.h +lib_LTLIBRARIES = libltdl.la +else +noinst_HEADERS = ltdl.h +endif + +if CONVENIENCE_LTDL +noinst_LTLIBRARIES = libltdlc.la +endif + +## Make sure these will be cleaned even when they're not built by +## default. +CLEANFILES = libltdl.la libltdlc.la + +libltdl_la_SOURCES = ltdl.c +libltdl_la_LDFLAGS = -no-undefined -version-info 4:5:1 +libltdl_la_LIBADD = $(LIBADD_DL) + +libltdlc_la_SOURCES = ltdl.c +libltdlc_la_LIBADD = $(LIBADD_DL) + +## Because we do not have automatic dependency tracking: +ltdl.lo: ltdl.h config.h + +$(libltdl_la_OBJECTS) $(libltdlc_la_OBJECTS): libtool +libtool: $(LIBTOOL_DEPS) + $(SHELL) ./config.status --recheck diff --git a/libltdl/Makefile.in b/libltdl/Makefile.in new file mode 100644 index 00000000..4319156e --- /dev/null +++ b/libltdl/Makefile.in @@ -0,0 +1,656 @@ +# Makefile.in generated by automake 1.10 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = . +DIST_COMMON = README $(am__configure_deps) $(am__include_HEADERS_DIST) \ + $(am__noinst_HEADERS_DIST) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(srcdir)/config-h.in \ + $(top_srcdir)/configure COPYING.LIB config.guess config.sub \ + install-sh ltmain.sh missing mkinstalldirs +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" +libLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) +am__DEPENDENCIES_1 = +libltdl_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_libltdl_la_OBJECTS = ltdl.lo +libltdl_la_OBJECTS = $(am_libltdl_la_OBJECTS) +libltdl_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libltdl_la_LDFLAGS) $(LDFLAGS) -o $@ +@INSTALL_LTDL_TRUE@am_libltdl_la_rpath = -rpath $(libdir) +libltdlc_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_libltdlc_la_OBJECTS = ltdl.lo +libltdlc_la_OBJECTS = $(am_libltdlc_la_OBJECTS) +@CONVENIENCE_LTDL_TRUE@am_libltdlc_la_rpath = +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libltdl_la_SOURCES) $(libltdlc_la_SOURCES) +DIST_SOURCES = $(libltdl_la_SOURCES) $(libltdlc_la_SOURCES) +am__include_HEADERS_DIST = ltdl.h +includeHEADERS_INSTALL = $(INSTALL_HEADER) +am__noinst_HEADERS_DIST = ltdl.h +HEADERS = $(include_HEADERS) $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_DEPS = @LIBTOOL_DEPS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = no-dependencies foreign +@INSTALL_LTDL_TRUE@include_HEADERS = ltdl.h +@INSTALL_LTDL_TRUE@lib_LTLIBRARIES = libltdl.la +@INSTALL_LTDL_FALSE@noinst_HEADERS = ltdl.h +@CONVENIENCE_LTDL_TRUE@noinst_LTLIBRARIES = libltdlc.la +CLEANFILES = libltdl.la libltdlc.la +libltdl_la_SOURCES = ltdl.c +libltdl_la_LDFLAGS = -no-undefined -version-info 4:5:1 +libltdl_la_LIBADD = $(LIBADD_DL) +libltdlc_la_SOURCES = ltdl.c +libltdlc_la_LIBADD = $(LIBADD_DL) +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \ + cd $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) + +config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/config-h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config-h.in: $(am__configure_deps) + cd $(top_srcdir) && $(AUTOHEADER) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libltdl.la: $(libltdl_la_OBJECTS) $(libltdl_la_DEPENDENCIES) + $(libltdl_la_LINK) $(am_libltdl_la_rpath) $(libltdl_la_OBJECTS) $(libltdl_la_LIBADD) $(LIBS) +libltdlc.la: $(libltdlc_la_OBJECTS) $(libltdlc_la_DEPENDENCIES) + $(LINK) $(am_libltdlc_la_rpath) $(libltdlc_la_OBJECTS) $(libltdlc_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: + $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +install-includeHEADERS: $(include_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" + @list='$(include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \ + $(includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \ + done + +uninstall-includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_HEADERS)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \ + rm -f "$(DESTDIR)$(includedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) config-h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) config-h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) config-h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) config-h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d $(distdir) || mkdir $(distdir) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && cd $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @cd $(distuninstallcheck_dir) \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) config.h +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + clean-noinstLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-includeHEADERS + +install-dvi: install-dvi-am + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \ + clean-generic clean-libLTLIBRARIES clean-libtool \ + clean-noinstLTLIBRARIES ctags dist dist-all dist-bzip2 \ + dist-gzip dist-shar dist-tarZ dist-zip distcheck distclean \ + distclean-compile distclean-generic distclean-hdr \ + distclean-libtool distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-includeHEADERS install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-includeHEADERS \ + uninstall-libLTLIBRARIES + + +ltdl.lo: ltdl.h config.h + +$(libltdl_la_OBJECTS) $(libltdlc_la_OBJECTS): libtool +libtool: $(LIBTOOL_DEPS) + $(SHELL) ./config.status --recheck +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libltdl/README b/libltdl/README new file mode 100644 index 00000000..da0a449c --- /dev/null +++ b/libltdl/README @@ -0,0 +1,10 @@ +This is GNU libltdl, a system independent dlopen wrapper for GNU libtool. + +It supports the following dlopen interfaces: +* dlopen (Solaris, Linux and various BSD flavors) +* shl_load (HP-UX) +* LoadLibrary (Win16 and Win32) +* load_add_on (BeOS) +* GNU DLD (emulates dynamic linking for static libraries) +* dyld (darwin/Mac OS X) +* libtool's dlpreopen diff --git a/libltdl/acinclude.m4 b/libltdl/acinclude.m4 new file mode 100644 index 00000000..79d94868 --- /dev/null +++ b/libltdl/acinclude.m4 @@ -0,0 +1,7025 @@ +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +## Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 +## Free Software Foundation, Inc. +## Originally by Gordon Matzigkeit , 1996 +## +## This file is free software; the Free Software Foundation gives +## unlimited permission to copy and/or distribute it, with or without +## modifications, as long as this notice is preserved. + +# serial 51 Debian 1.5.24-1 AC_PROG_LIBTOOL + + +# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED) +# ----------------------------------------------------------- +# If this macro is not defined by Autoconf, define it here. +m4_ifdef([AC_PROVIDE_IFELSE], + [], + [m4_define([AC_PROVIDE_IFELSE], + [m4_ifdef([AC_PROVIDE_$1], + [$2], [$3])])]) + + +# AC_PROG_LIBTOOL +# --------------- +AC_DEFUN([AC_PROG_LIBTOOL], +[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl +dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX +dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. + AC_PROVIDE_IFELSE([AC_PROG_CXX], + [AC_LIBTOOL_CXX], + [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX + ])]) +dnl And a similar setup for Fortran 77 support + AC_PROVIDE_IFELSE([AC_PROG_F77], + [AC_LIBTOOL_F77], + [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77 +])]) + +dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. +dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run +dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. + AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [ifdef([AC_PROG_GCJ], + [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([A][M_PROG_GCJ], + [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([LT_AC_PROG_GCJ], + [define([LT_AC_PROG_GCJ], + defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])]) +])])# AC_PROG_LIBTOOL + + +# _AC_PROG_LIBTOOL +# ---------------- +AC_DEFUN([_AC_PROG_LIBTOOL], +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl +AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl +AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl +AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +# Prevent multiple expansion +define([AC_PROG_LIBTOOL], []) +])# _AC_PROG_LIBTOOL + + +# AC_LIBTOOL_SETUP +# ---------------- +AC_DEFUN([AC_LIBTOOL_SETUP], +[AC_PREREQ(2.50)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl +AC_REQUIRE([AC_PROG_NM])dnl + +AC_REQUIRE([AC_PROG_LN_S])dnl +AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! +AC_REQUIRE([AC_OBJEXT])dnl +AC_REQUIRE([AC_EXEEXT])dnl +dnl + +AC_LIBTOOL_SYS_MAX_CMD_LEN +AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +AC_LIBTOOL_OBJDIR + +AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +_LT_AC_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e 1s/^X//' +[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] + +# Same as above, but do not quote variable references. +[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" + +AC_CHECK_TOOL(AR, ar, false) +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(STRIP, strip, :) + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$SED" && SED=sed +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + AC_PATH_MAGIC + fi + ;; +esac + +AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +enable_win32_dll=yes, enable_win32_dll=no) + +AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +AC_ARG_WITH([pic], + [AC_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) +test -z "$pic_mode" && pic_mode=default + +# Use C for the default configuration in the libtool script +tagname= +AC_LIBTOOL_LANG_C_CONFIG +_LT_AC_TAGCONFIG +])# AC_LIBTOOL_SETUP + + +# _LT_AC_SYS_COMPILER +# ------------------- +AC_DEFUN([_LT_AC_SYS_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_AC_SYS_COMPILER + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +AC_DEFUN([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` +]) + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +AC_DEFUN([_LT_COMPILER_BOILERPLATE], +[AC_REQUIRE([LT_AC_PROG_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +AC_DEFUN([_LT_LINKER_BOILERPLATE], +[AC_REQUIRE([LT_AC_PROG_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* +])# _LT_LINKER_BOILERPLATE + + +# _LT_AC_SYS_LIBPATH_AIX +# ---------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX], +[AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_AC_SYS_LIBPATH_AIX + + +# _LT_AC_SHELL_INIT(ARG) +# ---------------------- +AC_DEFUN([_LT_AC_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_AC_SHELL_INIT + + +# _LT_AC_PROG_ECHO_BACKSLASH +# -------------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], +[_LT_AC_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +echo=${ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null 2>&1 && unset CDPATH + +if test -z "$ECHO"; then +if test "X${echo_test_string+set}" != Xset; then +# find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string=`eval $cmd`) 2>/dev/null && + echo_test_string=`eval $cmd` && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(ECHO) +])])# _LT_AC_PROG_ECHO_BACKSLASH + + +# _LT_AC_LOCK +# ----------- +AC_DEFUN([_LT_AC_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) LD="${LD-ld} -64" ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw* | *-*-pw32*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; + ]) +esac + +need_locks="$enable_libtool_lock" + +])# _LT_AC_LOCK + + +# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], +[AC_REQUIRE([LT_AC_PROG_SED]) +AC_CACHE_CHECK([$1], [$2], + [$2=no + ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $rm conftest* +]) + +if test x"[$]$2" = xyes; then + ifelse([$5], , :, [$5]) +else + ifelse([$6], , :, [$6]) +fi +])# AC_LIBTOOL_COMPILER_OPTION + + +# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ------------------------------------------------------------ +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], +[AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + ifelse([$4], , :, [$4]) +else + ifelse([$5], , :, [$5]) +fi +])# AC_LIBTOOL_LINKER_OPTION + + +# AC_LIBTOOL_SYS_MAX_CMD_LEN +# -------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], +[# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \ + = "XX$teststring") >/dev/null 2>&1 && + new_result=`expr "X$teststring" : ".*" 2>&1` && + lt_cv_sys_max_cmd_len=$new_result && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + teststring= + # Add a significant safety factor because C++ compilers can tack on massive + # amounts of additional arguments before passing them to the linker. + # It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +])# AC_LIBTOOL_SYS_MAX_CMD_LEN + + +# _LT_AC_CHECK_DLFCN +# ------------------ +AC_DEFUN([_LT_AC_CHECK_DLFCN], +[AC_CHECK_HEADERS(dlfcn.h)dnl +])# _LT_AC_CHECK_DLFCN + + +# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# --------------------------------------------------------------------- +AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + exit (status); +}] +EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_AC_TRY_DLOPEN_SELF + + +# AC_LIBTOOL_DLOPEN_SELF +# ---------------------- +AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +])# AC_LIBTOOL_DLOPEN_SELF + + +# AC_LIBTOOL_PROG_CC_C_O([TAGNAME]) +# --------------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler +AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O], +[AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* +]) +])# AC_LIBTOOL_PROG_CC_C_O + + +# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME]) +# ----------------------------------------- +# Check to see if we can do hard links to lock some files if needed +AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], +[AC_REQUIRE([_LT_AC_LOCK])dnl + +hard_links="nottested" +if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS + + +# AC_LIBTOOL_OBJDIR +# ----------------- +AC_DEFUN([AC_LIBTOOL_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +])# AC_LIBTOOL_OBJDIR + + +# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME]) +# ---------------------------------------------- +# Check hardcoding attributes. +AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_AC_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \ + test -n "$_LT_AC_TAGVAR(runpath_var, $1)" || \ + test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_AC_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_AC_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_AC_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH + + +# AC_LIBTOOL_SYS_LIB_STRIP +# ------------------------ +AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP], +[striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) +fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +])# AC_LIBTOOL_SYS_LIB_STRIP + + +# AC_LIBTOOL_SYS_DYNAMIC_LINKER +# ----------------------------- +# PORTME Fill in your ld.so characteristics +AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +m4_if($1,[],[ +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$lt_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`echo "$lt_search_path_spec" | $SED -e 's/;/ /g'` + else + lt_search_path_spec=`echo "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`echo $lt_tmp_lt_search_path_spec | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + sys_lib_search_path_spec=`echo $lt_search_path_spec` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[123]]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[[3-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi +])# AC_LIBTOOL_SYS_DYNAMIC_LINKER + + +# _LT_AC_TAGCONFIG +# ---------------- +AC_DEFUN([_LT_AC_TAGCONFIG], +[AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_ARG_WITH([tags], + [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@], + [include additional configurations @<:@automatic@:>@])], + [tagnames="$withval"]) + +if test -f "$ltmain" && test -n "$tagnames"; then + if test ! -f "${ofile}"; then + AC_MSG_WARN([output file `$ofile' does not exist]) + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) + else + AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) + fi + fi + if test -z "$LTCFLAGS"; then + eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`" + fi + + # Extract list of available tagged configurations in $ofile. + # Note that this assumes the entire list is on one line. + available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` + + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for tagname in $tagnames; do + IFS="$lt_save_ifs" + # Check whether tagname contains only valid characters + case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in + "") ;; + *) AC_MSG_ERROR([invalid tag name: $tagname]) + ;; + esac + + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null + then + AC_MSG_ERROR([tag name \"$tagname\" already exists]) + fi + + # Update the list of available tags. + if test -n "$tagname"; then + echo appending configuration tag \"$tagname\" to $ofile + + case $tagname in + CXX) + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_LIBTOOL_LANG_CXX_CONFIG + else + tagname="" + fi + ;; + + F77) + if test -n "$F77" && test "X$F77" != "Xno"; then + AC_LIBTOOL_LANG_F77_CONFIG + else + tagname="" + fi + ;; + + GCJ) + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + AC_LIBTOOL_LANG_GCJ_CONFIG + else + tagname="" + fi + ;; + + RC) + AC_LIBTOOL_LANG_RC_CONFIG + ;; + + *) + AC_MSG_ERROR([Unsupported tag name: $tagname]) + ;; + esac + + # Append the new tag name to the list of available tags. + if test -n "$tagname" ; then + available_tags="$available_tags $tagname" + fi + fi + done + IFS="$lt_save_ifs" + + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + else + rm -f "${ofile}T" + AC_MSG_ERROR([unable to update list of available tagged configurations.]) + fi +fi +])# _LT_AC_TAGCONFIG + + +# AC_LIBTOOL_DLOPEN +# ----------------- +# enable checks for dlopen support +AC_DEFUN([AC_LIBTOOL_DLOPEN], + [AC_BEFORE([$0],[AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_DLOPEN + + +# AC_LIBTOOL_WIN32_DLL +# -------------------- +# declare package support for building win32 DLLs +AC_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_BEFORE([$0], [AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_WIN32_DLL + + +# AC_ENABLE_SHARED([DEFAULT]) +# --------------------------- +# implement the --enable-shared flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_SHARED], +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([shared], + [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]AC_ENABLE_SHARED_DEFAULT) +])# AC_ENABLE_SHARED + + +# AC_DISABLE_SHARED +# ----------------- +# set the default shared flag to --disable-shared +AC_DEFUN([AC_DISABLE_SHARED], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no) +])# AC_DISABLE_SHARED + + +# AC_ENABLE_STATIC([DEFAULT]) +# --------------------------- +# implement the --enable-static flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_STATIC], +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([static], + [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]AC_ENABLE_STATIC_DEFAULT) +])# AC_ENABLE_STATIC + + +# AC_DISABLE_STATIC +# ----------------- +# set the default static flag to --disable-static +AC_DEFUN([AC_DISABLE_STATIC], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no) +])# AC_DISABLE_STATIC + + +# AC_ENABLE_FAST_INSTALL([DEFAULT]) +# --------------------------------- +# implement the --enable-fast-install flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_FAST_INSTALL], +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([fast-install], + [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT) +])# AC_ENABLE_FAST_INSTALL + + +# AC_DISABLE_FAST_INSTALL +# ----------------------- +# set the default to --disable-fast-install +AC_DEFUN([AC_DISABLE_FAST_INSTALL], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no) +])# AC_DISABLE_FAST_INSTALL + + +# AC_LIBTOOL_PICMODE([MODE]) +# -------------------------- +# implement the --with-pic flag +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +AC_DEFUN([AC_LIBTOOL_PICMODE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +pic_mode=ifelse($#,1,$1,default) +])# AC_LIBTOOL_PICMODE + + +# AC_PROG_EGREP +# ------------- +# This is predefined starting with Autoconf 2.54, so this conditional +# definition can be removed once we require Autoconf 2.54 or later. +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP], +[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], + [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi]) + EGREP=$ac_cv_prog_egrep + AC_SUBST([EGREP]) +])]) + + +# AC_PATH_TOOL_PREFIX +# ------------------- +# find a file program which can recognize shared library +AC_DEFUN([AC_PATH_TOOL_PREFIX], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +])# AC_PATH_TOOL_PREFIX + + +# AC_PATH_MAGIC +# ------------- +# find a file program which can recognize a shared library +AC_DEFUN([AC_PATH_MAGIC], +[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# AC_PATH_MAGIC + + +# AC_PROG_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH([gnu-ld], + [AC_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no]) +AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +nto-qnx*) + lt_cv_deplibs_check_method=unknown + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown +])# AC_DEPLIBS_CHECK_METHOD + + +# AC_PROG_NM +# ---------- +# find the pathname to a BSD-compatible name lister +AC_DEFUN([AC_PROG_NM], +[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi]) +NM="$lt_cv_path_NM" +])# AC_PROG_NM + + +# AC_CHECK_LIBM +# ------------- +# check for math library +AC_DEFUN([AC_CHECK_LIBM], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +])# AC_CHECK_LIBM + + +# AC_LIBLTDL_CONVENIENCE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl convenience library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-convenience to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided, +# it is assumed to be `libltdl'. LIBLTDL will be prefixed with +# '${top_builddir}/' and LTDLINCL will be prefixed with '${top_srcdir}/' +# (note the single quotes!). If your package is not flat and you're not +# using automake, define top_builddir and top_srcdir appropriately in +# the Makefiles. +AC_DEFUN([AC_LIBLTDL_CONVENIENCE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_CONVENIENCE + + +# AC_LIBLTDL_INSTALLABLE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl installable library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-install to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided, +# and an installed libltdl is not found, it is assumed to be `libltdl'. +# LIBLTDL will be prefixed with '${top_builddir}/'# and LTDLINCL with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and top_srcdir +# appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN([AC_LIBLTDL_INSTALLABLE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, lt_dlinit, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + LTDLINCL= + fi + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_INSTALLABLE + + +# AC_LIBTOOL_CXX +# -------------- +# enable support for C++ libraries +AC_DEFUN([AC_LIBTOOL_CXX], +[AC_REQUIRE([_LT_AC_LANG_CXX]) +])# AC_LIBTOOL_CXX + + +# _LT_AC_LANG_CXX +# --------------- +AC_DEFUN([_LT_AC_LANG_CXX], +[AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([_LT_AC_PROG_CXXCPP]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX]) +])# _LT_AC_LANG_CXX + +# _LT_AC_PROG_CXXCPP +# ------------------ +AC_DEFUN([_LT_AC_PROG_CXXCPP], +[ +AC_REQUIRE([AC_PROG_CXX]) +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +fi +])# _LT_AC_PROG_CXXCPP + +# AC_LIBTOOL_F77 +# -------------- +# enable support for Fortran 77 libraries +AC_DEFUN([AC_LIBTOOL_F77], +[AC_REQUIRE([_LT_AC_LANG_F77]) +])# AC_LIBTOOL_F77 + + +# _LT_AC_LANG_F77 +# --------------- +AC_DEFUN([_LT_AC_LANG_F77], +[AC_REQUIRE([AC_PROG_F77]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77]) +])# _LT_AC_LANG_F77 + + +# AC_LIBTOOL_GCJ +# -------------- +# enable support for GCJ libraries +AC_DEFUN([AC_LIBTOOL_GCJ], +[AC_REQUIRE([_LT_AC_LANG_GCJ]) +])# AC_LIBTOOL_GCJ + + +# _LT_AC_LANG_GCJ +# --------------- +AC_DEFUN([_LT_AC_LANG_GCJ], +[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], + [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], + [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], + [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ]) +])# _LT_AC_LANG_GCJ + + +# AC_LIBTOOL_RC +# ------------- +# enable support for Windows resource files +AC_DEFUN([AC_LIBTOOL_RC], +[AC_REQUIRE([LT_AC_PROG_RC]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC]) +])# AC_LIBTOOL_RC + + +# AC_LIBTOOL_LANG_C_CONFIG +# ------------------------ +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG]) +AC_DEFUN([_LT_AC_LANG_C_CONFIG], +[lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_DLOPEN_SELF + +# Report which library types will actually be built +AC_MSG_CHECKING([if libtool supports shared libraries]) +AC_MSG_RESULT([$can_build_shared]) + +AC_MSG_CHECKING([whether to build shared libraries]) +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case $host_os in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4* | aix5*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +AC_MSG_RESULT([$enable_shared]) + +AC_MSG_CHECKING([whether to build static libraries]) +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +AC_MSG_RESULT([$enable_static]) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_C_CONFIG + + +# AC_LIBTOOL_LANG_CXX_CONFIG +# -------------------------- +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)]) +AC_DEFUN([_LT_AC_LANG_CXX_CONFIG], +[AC_LANG_PUSH(C++) +AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([_LT_AC_PROG_CXXCPP]) + +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_AC_TAGVAR(allow_undefined_flag, $1)= +_LT_AC_TAGVAR(always_export_symbols, $1)=no +_LT_AC_TAGVAR(archive_expsym_cmds, $1)= +_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_direct, $1)=no +_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_AC_TAGVAR(hardcode_libdir_separator, $1)= +_LT_AC_TAGVAR(hardcode_minus_L, $1)=no +_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_AC_TAGVAR(hardcode_automatic, $1)=no +_LT_AC_TAGVAR(module_cmds, $1)= +_LT_AC_TAGVAR(module_expsym_cmds, $1)= +_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown +_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_AC_TAGVAR(no_undefined_flag, $1)= +_LT_AC_TAGVAR(whole_archive_flag_spec, $1)= +_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Dependencies to place before and after the object being linked: +_LT_AC_TAGVAR(predep_objects, $1)= +_LT_AC_TAGVAR(postdep_objects, $1)= +_LT_AC_TAGVAR(predeps, $1)= +_LT_AC_TAGVAR(postdeps, $1)= +_LT_AC_TAGVAR(compiler_lib_search_path, $1)= + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_LD=$LD +lt_save_GCC=$GCC +GCC=$GXX +lt_save_with_gnu_ld=$with_gnu_ld +lt_save_path_LD=$lt_cv_path_LD +if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx +else + $as_unset lt_cv_prog_gnu_ld +fi +if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX +else + $as_unset lt_cv_path_LD +fi +test -z "${LDCXX+set}" || LD=$LDCXX +CC=${CXX-"c++"} +compiler=$CC +_LT_AC_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) + +# We don't want -fno-exception wen compiling C++ code, so set the +# no_builtin_flag separately +if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' +else + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= +fi + +if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + AC_PROG_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ + grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + +else + GXX=no + with_gnu_ld=no + wlarc= +fi + +# PORTME: fill in a description of your system's C++ link characteristics +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +_LT_AC_TAGVAR(ld_shlibs, $1)=yes +case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes ; then + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + fi + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + freebsd[[12]]*) + # C++ shared libraries reported to be fairly broken before switch to ELF + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + freebsd-elf*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + ;; + gnu*) + ;; + hpux9*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[[-]]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) ;; + *) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + interix[[3-9]]*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' + fi + fi + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc*) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC*) + # Portland Group C++ compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + lynxos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + m88k*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + openbsd2*) + # C++ shared libraries are fairly broken + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd='echo' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + osf3*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~ + $rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + psos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | grep -v '^2\.7' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + fi + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + # So that behaviour is only enabled if SCOABSPATH is set to a + # non-empty value in the environment. Most likely only useful for + # creating official distributions of packages. + # This is a hack until libtool officially supports absolute path + # names for shared libraries. + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + vxworks*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; +esac +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_AC_TAGVAR(GCC, $1)="$GXX" +_LT_AC_TAGVAR(LD, $1)="$LD" + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +AC_LIBTOOL_POSTDEP_PREDEP($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC=$lt_save_CC +LDCXX=$LD +LD=$lt_save_LD +GCC=$lt_save_GCC +with_gnu_ldcxx=$with_gnu_ld +with_gnu_ld=$lt_save_with_gnu_ld +lt_cv_path_LDCXX=$lt_cv_path_LD +lt_cv_path_LD=$lt_save_path_LD +lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld +lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +])# AC_LIBTOOL_LANG_CXX_CONFIG + +# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME]) +# ------------------------------------ +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[ +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +ifelse([$1],[],[cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext <&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + # + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + if test "$solaris_use_stlport4" != yes; then + _LT_AC_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + _LT_AC_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac +]) + +case " $_LT_AC_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac +])# AC_LIBTOOL_POSTDEP_PREDEP + +# AC_LIBTOOL_LANG_F77_CONFIG +# -------------------------- +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG], [_LT_AC_LANG_F77_CONFIG(F77)]) +AC_DEFUN([_LT_AC_LANG_F77_CONFIG], +[AC_REQUIRE([AC_PROG_F77]) +AC_LANG_PUSH(Fortran 77) + +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_AC_TAGVAR(allow_undefined_flag, $1)= +_LT_AC_TAGVAR(always_export_symbols, $1)=no +_LT_AC_TAGVAR(archive_expsym_cmds, $1)= +_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_direct, $1)=no +_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_AC_TAGVAR(hardcode_libdir_separator, $1)= +_LT_AC_TAGVAR(hardcode_minus_L, $1)=no +_LT_AC_TAGVAR(hardcode_automatic, $1)=no +_LT_AC_TAGVAR(module_cmds, $1)= +_LT_AC_TAGVAR(module_expsym_cmds, $1)= +_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown +_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_AC_TAGVAR(no_undefined_flag, $1)= +_LT_AC_TAGVAR(whole_archive_flag_spec, $1)= +_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="\ + subroutine t + return + end +" + +# Code to be used in simple link tests +lt_simple_link_test_code="\ + program t + end +" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${F77-"f77"} +compiler=$CC +_LT_AC_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) + +AC_MSG_CHECKING([if libtool supports shared libraries]) +AC_MSG_RESULT([$can_build_shared]) + +AC_MSG_CHECKING([whether to build shared libraries]) +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case $host_os in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; +aix4* | aix5*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +AC_MSG_RESULT([$enable_shared]) + +AC_MSG_CHECKING([whether to build static libraries]) +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +AC_MSG_RESULT([$enable_static]) + +_LT_AC_TAGVAR(GCC, $1)="$G77" +_LT_AC_TAGVAR(LD, $1)="$LD" + +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_F77_CONFIG + + +# AC_LIBTOOL_LANG_GCJ_CONFIG +# -------------------------- +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG], [_LT_AC_LANG_GCJ_CONFIG(GCJ)]) +AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG], +[AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${GCJ-"gcj"} +compiler=$CC +_LT_AC_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_RESTORE +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_GCJ_CONFIG + + +# AC_LIBTOOL_LANG_RC_CONFIG +# ------------------------- +# Ensure that the configuration vars for the Windows resource compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG], [_LT_AC_LANG_RC_CONFIG(RC)]) +AC_DEFUN([_LT_AC_LANG_RC_CONFIG], +[AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${RC-"windres"} +compiler=$CC +_LT_AC_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_RESTORE +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_RC_CONFIG + + +# AC_LIBTOOL_CONFIG([TAGNAME]) +# ---------------------------- +# If TAGNAME is not passed, then create an initial libtool script +# with a default configuration from the untagged config vars. Otherwise +# add code to config.status for appending the configuration named by +# TAGNAME from the matching tagged config vars. +AC_DEFUN([AC_LIBTOOL_CONFIG], +[# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + _LT_AC_TAGVAR(compiler, $1) \ + _LT_AC_TAGVAR(CC, $1) \ + _LT_AC_TAGVAR(LD, $1) \ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1) \ + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1) \ + _LT_AC_TAGVAR(lt_prog_compiler_static, $1) \ + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) \ + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1) \ + _LT_AC_TAGVAR(thread_safe_flag_spec, $1) \ + _LT_AC_TAGVAR(whole_archive_flag_spec, $1) \ + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) \ + _LT_AC_TAGVAR(old_archive_cmds, $1) \ + _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) \ + _LT_AC_TAGVAR(predep_objects, $1) \ + _LT_AC_TAGVAR(postdep_objects, $1) \ + _LT_AC_TAGVAR(predeps, $1) \ + _LT_AC_TAGVAR(postdeps, $1) \ + _LT_AC_TAGVAR(compiler_lib_search_path, $1) \ + _LT_AC_TAGVAR(archive_cmds, $1) \ + _LT_AC_TAGVAR(archive_expsym_cmds, $1) \ + _LT_AC_TAGVAR(postinstall_cmds, $1) \ + _LT_AC_TAGVAR(postuninstall_cmds, $1) \ + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) \ + _LT_AC_TAGVAR(allow_undefined_flag, $1) \ + _LT_AC_TAGVAR(no_undefined_flag, $1) \ + _LT_AC_TAGVAR(export_symbols_cmds, $1) \ + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) \ + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) \ + _LT_AC_TAGVAR(hardcode_libdir_separator, $1) \ + _LT_AC_TAGVAR(hardcode_automatic, $1) \ + _LT_AC_TAGVAR(module_cmds, $1) \ + _LT_AC_TAGVAR(module_expsym_cmds, $1) \ + _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) \ + _LT_AC_TAGVAR(fix_srcfile_path, $1) \ + _LT_AC_TAGVAR(exclude_expsyms, $1) \ + _LT_AC_TAGVAR(include_expsyms, $1); do + + case $var in + _LT_AC_TAGVAR(old_archive_cmds, $1) | \ + _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) | \ + _LT_AC_TAGVAR(archive_cmds, $1) | \ + _LT_AC_TAGVAR(archive_expsym_cmds, $1) | \ + _LT_AC_TAGVAR(module_cmds, $1) | \ + _LT_AC_TAGVAR(module_expsym_cmds, $1) | \ + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) | \ + _LT_AC_TAGVAR(export_symbols_cmds, $1) | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\[$]0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\[$]0 --fallback-echo"[$]/[$]0 --fallback-echo"/'` + ;; + esac + +ifelse([$1], [], + [cfgfile="${ofile}T" + trap "$rm \"$cfgfile\"; exit 1" 1 2 15 + $rm -f "$cfgfile" + AC_MSG_NOTICE([creating $ofile])], + [cfgfile="$ofile"]) + + cat <<__EOF__ >> "$cfgfile" +ifelse([$1], [], +[#! $SHELL + +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="$SED -e 1s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# The names of the tagged configurations supported by this script. +available_tags= + +# ### BEGIN LIBTOOL CONFIG], +[# ### BEGIN LIBTOOL TAG CONFIG: $tagname]) + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1) + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_[]_LT_AC_TAGVAR(compiler, $1) + +# Is the compiler the GNU C compiler? +with_gcc=$_LT_AC_TAGVAR(GCC, $1) + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_[]_LT_AC_TAGVAR(LD, $1) + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1) + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1) + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1) + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1) + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1) +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1) + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) + +# Commands used to build and install a shared archive. +archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1) +archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1) +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1) +module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1) + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1) + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1) + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1) + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1) + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1) + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1) + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1) + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1) + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1) + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1) + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1) + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1) + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to yes if exported symbols are required. +always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1) + +# The commands to list exported symbols. +export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1) + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1) + +# Symbols that must always be exported. +include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1) + +ifelse([$1],[], +[# ### END LIBTOOL CONFIG], +[# ### END LIBTOOL TAG CONFIG: $tagname]) + +__EOF__ + +ifelse([$1],[], [ + case $host_os in + aix3*) + cat <<\EOF >> "$cfgfile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || \ + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +]) +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi +])# AC_LIBTOOL_CONFIG + + +# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl + +_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI + + +# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +# --------------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([LT_AC_PROG_SED]) +AC_REQUIRE([AC_PROG_NM]) +AC_REQUIRE([AC_OBJEXT]) +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) # Its linker distinguishes data from code symbols + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +linux* | k*bsd*-gnu) + if test "$host_cpu" = ia64; then + symcode='[[ABCDGIRSTW]]' + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if grep ' nm_test_var$' "$nlist" >/dev/null; then + if grep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[[]] = +{ +EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi +]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE + + +# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME]) +# --------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC], +[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) + ifelse([$1],[CXX],[ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix4* | aix5*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + icpc* | ecpc*) + # Intel C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC*) + # Portland Group C++ compiler. + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + esac + ;; + + mingw* | cygwin* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + newsos6) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + icc* | ecc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + esac + ;; + esac + ;; + + osf3* | osf4* | osf5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then + AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1), + [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_AC_TAGVAR(lt_prog_compiler_static, $1)\" +AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=]) +]) + + +# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME]) +# ------------------------------------ +# See if the linker supports building shared libraries. +AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS], +[AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +ifelse([$1],[CXX],[ + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix4* | aix5*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + ;; + linux* | k*bsd*-gnu) + _LT_AC_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +],[ + runpath_var= + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)= + _LT_AC_TAGVAR(archive_expsym_cmds, $1)= + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)= + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + _LT_AC_TAGVAR(thread_safe_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown + _LT_AC_TAGVAR(hardcode_automatic, $1)=no + _LT_AC_TAGVAR(module_cmds, $1)= + _LT_AC_TAGVAR(module_expsym_cmds, $1)= + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_AC_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + # Just being paranoid about ensuring that cc_basename is set. + _LT_CC_BASENAME([$compiler]) + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + interix[[3-9]]*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | k*bsd*-gnu) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + *) + tmp_sharedflag='-shared' ;; + esac + _LT_AC_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test $supports_anon_versioning = yes; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + $echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + _LT_AC_TAGVAR(link_all_deplibs, $1)=no + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + # see comment about different semantics on the GNU ld section + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + bsdi[[45]]*) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_AC_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_AC_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi + ;; + + dgux*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + wlarc='' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_AC_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $rm conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1) + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) + then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac +])# AC_LIBTOOL_PROG_LD_SHLIBS + + +# _LT_AC_FILE_LTDLL_C +# ------------------- +# Be careful that the start marker always follows a newline. +AC_DEFUN([_LT_AC_FILE_LTDLL_C], [ +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include +# #undef WIN32_LEAN_AND_MEAN +# #include +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ +])# _LT_AC_FILE_LTDLL_C + + +# _LT_AC_TAGVAR(VARNAME, [TAGNAME]) +# --------------------------------- +AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])]) + + +# old names +AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) +AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) +AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) +AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) +AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) + +# This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL]) + +AC_DEFUN([LT_AC_PROG_GCJ], +[AC_CHECK_TOOL(GCJ, gcj, no) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS) +]) + +AC_DEFUN([LT_AC_PROG_RC], +[AC_CHECK_TOOL(RC, windres, no) +]) + + +# Cheap backport of AS_EXECUTABLE_P and required macros +# from Autoconf 2.59; we should not use $as_executable_p directly. + +# _AS_TEST_PREPARE +# ---------------- +m4_ifndef([_AS_TEST_PREPARE], +[m4_defun([_AS_TEST_PREPARE], +[if test -x / >/dev/null 2>&1; then + as_executable_p='test -x' +else + as_executable_p='test -f' +fi +])])# _AS_TEST_PREPARE + +# AS_EXECUTABLE_P +# --------------- +# Check whether a file is executable. +m4_ifndef([AS_EXECUTABLE_P], +[m4_defun([AS_EXECUTABLE_P], +[AS_REQUIRE([_AS_TEST_PREPARE])dnl +$as_executable_p $1[]dnl +])])# AS_EXECUTABLE_P + +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ +# LT_AC_PROG_SED +# -------------- +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +AC_DEFUN([LT_AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if AS_EXECUTABLE_P(["$as_dir/$lt_ac_prog$ac_exec_ext"]); then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +]) +## ltdl.m4 - Configure ltdl for the target system. -*-Autoconf-*- +## Copyright (C) 1999-2006 Free Software Foundation, Inc. +## +## This file is free software; the Free Software Foundation gives +## unlimited permission to copy and/or distribute it, with or without +## modifications, as long as this notice is preserved. + +# serial 8 AC_LIB_LTDL + +# AC_WITH_LTDL +# ------------ +# Clients of libltdl can use this macro to allow the installer to +# choose between a shipped copy of the ltdl sources or a preinstalled +# version of the library. +AC_DEFUN([AC_WITH_LTDL], +[AC_REQUIRE([AC_LIB_LTDL]) +AC_SUBST([LIBLTDL]) +AC_SUBST([INCLTDL]) + +# Unless the user asks us to check, assume no installed ltdl exists. +use_installed_libltdl=no + +AC_ARG_WITH([included_ltdl], + [ --with-included-ltdl use the GNU ltdl sources included here]) + +if test "x$with_included_ltdl" != xyes; then + # We are not being forced to use the included libltdl sources, so + # decide whether there is a useful installed version we can use. + AC_CHECK_HEADER([ltdl.h], + [AC_CHECK_LIB([ltdl], [lt_dlcaller_register], + [with_included_ltdl=no], + [with_included_ltdl=yes]) + ]) +fi + +if test "x$enable_ltdl_install" != xyes; then + # If the user did not specify an installable libltdl, then default + # to a convenience lib. + AC_LIBLTDL_CONVENIENCE +fi + +if test "x$with_included_ltdl" = xno; then + # If the included ltdl is not to be used. then Use the + # preinstalled libltdl we found. + AC_DEFINE([HAVE_LTDL], [1], + [Define this if a modern libltdl is already installed]) + LIBLTDL=-lltdl +fi + +# Report our decision... +AC_MSG_CHECKING([whether to use included libltdl]) +AC_MSG_RESULT([$with_included_ltdl]) + +AC_CONFIG_SUBDIRS([libltdl]) +])# AC_WITH_LTDL + + +# AC_LIB_LTDL +# ----------- +# Perform all the checks necessary for compilation of the ltdl objects +# -- including compiler checks and header checks. +AC_DEFUN([AC_LIB_LTDL], +[AC_PREREQ(2.50) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AC_C_CONST]) +AC_REQUIRE([AC_HEADER_STDC]) +AC_REQUIRE([AC_HEADER_DIRENT]) +AC_REQUIRE([_LT_AC_CHECK_DLFCN]) +AC_REQUIRE([AC_LTDL_ENABLE_INSTALL]) +AC_REQUIRE([AC_LTDL_SHLIBEXT]) +AC_REQUIRE([AC_LTDL_SHLIBPATH]) +AC_REQUIRE([AC_LTDL_SYSSEARCHPATH]) +AC_REQUIRE([AC_LTDL_OBJDIR]) +AC_REQUIRE([AC_LTDL_DLPREOPEN]) +AC_REQUIRE([AC_LTDL_DLLIB]) +AC_REQUIRE([AC_LTDL_SYMBOL_USCORE]) +AC_REQUIRE([AC_LTDL_DLSYM_USCORE]) +AC_REQUIRE([AC_LTDL_SYS_DLOPEN_DEPLIBS]) +AC_REQUIRE([AC_LTDL_FUNC_ARGZ]) + +AC_CHECK_HEADERS([assert.h ctype.h errno.h malloc.h memory.h stdlib.h \ + stdio.h unistd.h]) +AC_CHECK_HEADERS([dl.h sys/dl.h dld.h mach-o/dyld.h]) +AC_CHECK_HEADERS([string.h strings.h], [break]) + +AC_CHECK_FUNCS([strchr index], [break]) +AC_CHECK_FUNCS([strrchr rindex], [break]) +AC_CHECK_FUNCS([memcpy bcopy], [break]) +AC_CHECK_FUNCS([memmove strcmp]) +AC_CHECK_FUNCS([closedir opendir readdir]) +])# AC_LIB_LTDL + + +# AC_LTDL_ENABLE_INSTALL +# ---------------------- +AC_DEFUN([AC_LTDL_ENABLE_INSTALL], +[AC_ARG_ENABLE([ltdl-install], + [AC_HELP_STRING([--enable-ltdl-install], [install libltdl])]) + +AM_CONDITIONAL(INSTALL_LTDL, test x"${enable_ltdl_install-no}" != xno) +AM_CONDITIONAL(CONVENIENCE_LTDL, test x"${enable_ltdl_convenience-no}" != xno) +])# AC_LTDL_ENABLE_INSTALL + + +# AC_LTDL_SYS_DLOPEN_DEPLIBS +# -------------------------- +AC_DEFUN([AC_LTDL_SYS_DLOPEN_DEPLIBS], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_CACHE_CHECK([whether deplibs are loaded by dlopen], + [libltdl_cv_sys_dlopen_deplibs], + [# PORTME does your system automatically load deplibs for dlopen? + # or its logical equivalent (e.g. shl_load for HP-UX < 11) + # For now, we just catch OSes we know something about -- in the + # future, we'll try test this programmatically. + libltdl_cv_sys_dlopen_deplibs=unknown + case "$host_os" in + aix3*|aix4.1.*|aix4.2.*) + # Unknown whether this is true for these versions of AIX, but + # we want this `case' here to explicitly catch those versions. + libltdl_cv_sys_dlopen_deplibs=unknown + ;; + aix[[45]]*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + darwin*) + # Assuming the user has installed a libdl from somewhere, this is true + # If you are looking for one http://www.opendarwin.org/projects/dlcompat + libltdl_cv_sys_dlopen_deplibs=yes + ;; + freebsd* | dragonfly*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + gnu* | linux* | k*bsd*-gnu) + # GNU and its variants, using gnu ld.so (Glibc) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + hpux10*|hpux11*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + interix*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + irix[[12345]]*|irix6.[[01]]*) + # Catch all versions of IRIX before 6.2, and indicate that we don't + # know how it worked for any of those versions. + libltdl_cv_sys_dlopen_deplibs=unknown + ;; + irix*) + # The case above catches anything before 6.2, and it's known that + # at 6.2 and later dlopen does load deplibs. + libltdl_cv_sys_dlopen_deplibs=yes + ;; + netbsd* | netbsdelf*-gnu) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + openbsd*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + osf[[1234]]*) + # dlopen did load deplibs (at least at 4.x), but until the 5.x series, + # it did *not* use an RPATH in a shared library to find objects the + # library depends on, so we explictly say `no'. + libltdl_cv_sys_dlopen_deplibs=no + ;; + osf5.0|osf5.0a|osf5.1) + # dlopen *does* load deplibs and with the right loader patch applied + # it even uses RPATH in a shared library to search for shared objects + # that the library depends on, but there's no easy way to know if that + # patch is installed. Since this is the case, all we can really + # say is unknown -- it depends on the patch being installed. If + # it is, this changes to `yes'. Without it, it would be `no'. + libltdl_cv_sys_dlopen_deplibs=unknown + ;; + osf*) + # the two cases above should catch all versions of osf <= 5.1. Read + # the comments above for what we know about them. + # At > 5.1, deplibs are loaded *and* any RPATH in a shared library + # is used to find them so we can finally say `yes'. + libltdl_cv_sys_dlopen_deplibs=yes + ;; + solaris*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + esac + ]) +if test "$libltdl_cv_sys_dlopen_deplibs" != yes; then + AC_DEFINE([LTDL_DLOPEN_DEPLIBS], [1], + [Define if the OS needs help to load dependent libraries for dlopen().]) +fi +])# AC_LTDL_SYS_DLOPEN_DEPLIBS + + +# AC_LTDL_SHLIBEXT +# ---------------- +AC_DEFUN([AC_LTDL_SHLIBEXT], +[AC_REQUIRE([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) +AC_CACHE_CHECK([which extension is used for loadable modules], + [libltdl_cv_shlibext], +[ +module=yes +eval libltdl_cv_shlibext=$shrext_cmds + ]) +if test -n "$libltdl_cv_shlibext"; then + AC_DEFINE_UNQUOTED([LTDL_SHLIB_EXT], ["$libltdl_cv_shlibext"], + [Define to the extension used for shared libraries, say, ".so".]) +fi +])# AC_LTDL_SHLIBEXT + + +# AC_LTDL_SHLIBPATH +# ----------------- +AC_DEFUN([AC_LTDL_SHLIBPATH], +[AC_REQUIRE([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) +AC_CACHE_CHECK([which variable specifies run-time library path], + [libltdl_cv_shlibpath_var], [libltdl_cv_shlibpath_var="$shlibpath_var"]) +if test -n "$libltdl_cv_shlibpath_var"; then + AC_DEFINE_UNQUOTED([LTDL_SHLIBPATH_VAR], ["$libltdl_cv_shlibpath_var"], + [Define to the name of the environment variable that determines the dynamic library search path.]) +fi +])# AC_LTDL_SHLIBPATH + + +# AC_LTDL_SYSSEARCHPATH +# --------------------- +AC_DEFUN([AC_LTDL_SYSSEARCHPATH], +[AC_REQUIRE([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) +AC_CACHE_CHECK([for the default library search path], + [libltdl_cv_sys_search_path], + [libltdl_cv_sys_search_path="$sys_lib_dlsearch_path_spec"]) +if test -n "$libltdl_cv_sys_search_path"; then + sys_search_path= + for dir in $libltdl_cv_sys_search_path; do + if test -z "$sys_search_path"; then + sys_search_path="$dir" + else + sys_search_path="$sys_search_path$PATH_SEPARATOR$dir" + fi + done + AC_DEFINE_UNQUOTED([LTDL_SYSSEARCHPATH], ["$sys_search_path"], + [Define to the system default library search path.]) +fi +])# AC_LTDL_SYSSEARCHPATH + + +# AC_LTDL_OBJDIR +# -------------- +AC_DEFUN([AC_LTDL_OBJDIR], +[AC_CACHE_CHECK([for objdir], + [libltdl_cv_objdir], + [libltdl_cv_objdir="$objdir" + if test -n "$objdir"; then + : + else + rm -f .libs 2>/dev/null + mkdir .libs 2>/dev/null + if test -d .libs; then + libltdl_cv_objdir=.libs + else + # MS-DOS does not allow filenames that begin with a dot. + libltdl_cv_objdir=_libs + fi + rmdir .libs 2>/dev/null + fi + ]) +AC_DEFINE_UNQUOTED([LTDL_OBJDIR], ["$libltdl_cv_objdir/"], + [Define to the sub-directory in which libtool stores uninstalled libraries.]) +])# AC_LTDL_OBJDIR + + +# AC_LTDL_DLPREOPEN +# ----------------- +AC_DEFUN([AC_LTDL_DLPREOPEN], +[AC_REQUIRE([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE]) +AC_CACHE_CHECK([whether libtool supports -dlopen/-dlpreopen], + [libltdl_cv_preloaded_symbols], + [if test -n "$lt_cv_sys_global_symbol_pipe"; then + libltdl_cv_preloaded_symbols=yes + else + libltdl_cv_preloaded_symbols=no + fi + ]) +if test x"$libltdl_cv_preloaded_symbols" = xyes; then + AC_DEFINE([HAVE_PRELOADED_SYMBOLS], [1], + [Define if libtool can extract symbol lists from object files.]) +fi +])# AC_LTDL_DLPREOPEN + + +# AC_LTDL_DLLIB +# ------------- +AC_DEFUN([AC_LTDL_DLLIB], +[LIBADD_DL= +AC_SUBST(LIBADD_DL) +AC_LANG_PUSH([C]) + +AC_CHECK_FUNC([shl_load], + [AC_DEFINE([HAVE_SHL_LOAD], [1], + [Define if you have the shl_load function.])], + [AC_CHECK_LIB([dld], [shl_load], + [AC_DEFINE([HAVE_SHL_LOAD], [1], + [Define if you have the shl_load function.]) + LIBADD_DL="$LIBADD_DL -ldld"], + [AC_CHECK_LIB([dl], [dlopen], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) + LIBADD_DL="-ldl" libltdl_cv_lib_dl_dlopen="yes"], + [AC_TRY_LINK([#if HAVE_DLFCN_H +# include +#endif + ], + [dlopen(0, 0);], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) libltdl_cv_func_dlopen="yes"], + [AC_CHECK_LIB([svld], [dlopen], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) + LIBADD_DL="-lsvld" libltdl_cv_func_dlopen="yes"], + [AC_CHECK_LIB([dld], [dld_link], + [AC_DEFINE([HAVE_DLD], [1], + [Define if you have the GNU dld library.]) + LIBADD_DL="$LIBADD_DL -ldld"], + [AC_CHECK_FUNC([_dyld_func_lookup], + [AC_DEFINE([HAVE_DYLD], [1], + [Define if you have the _dyld_func_lookup function.])]) + ]) + ]) + ]) + ]) + ]) +]) + +if test x"$libltdl_cv_func_dlopen" = xyes || test x"$libltdl_cv_lib_dl_dlopen" = xyes +then + lt_save_LIBS="$LIBS" + LIBS="$LIBS $LIBADD_DL" + AC_CHECK_FUNCS([dlerror]) + LIBS="$lt_save_LIBS" +fi +AC_LANG_POP +])# AC_LTDL_DLLIB + + +# AC_LTDL_SYMBOL_USCORE +# --------------------- +# does the compiler prefix global symbols with an underscore? +AC_DEFUN([AC_LTDL_SYMBOL_USCORE], +[AC_REQUIRE([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE]) +AC_CACHE_CHECK([for _ prefix in compiled symbols], + [ac_cv_sys_symbol_underscore], + [ac_cv_sys_symbol_underscore=no + cat > conftest.$ac_ext < $ac_nlist) && test -s "$ac_nlist"; then + # See whether the symbols have a leading underscore. + if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then + ac_cv_sys_symbol_underscore=yes + else + if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then + : + else + echo "configure: cannot find nm_test_func in $ac_nlist" >&AC_FD_CC + fi + fi + else + echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&AC_FD_CC + fi + else + echo "configure: failed program was:" >&AC_FD_CC + cat conftest.c >&AC_FD_CC + fi + rm -rf conftest* + ]) +])# AC_LTDL_SYMBOL_USCORE + + +# AC_LTDL_DLSYM_USCORE +# -------------------- +AC_DEFUN([AC_LTDL_DLSYM_USCORE], +[AC_REQUIRE([AC_LTDL_SYMBOL_USCORE]) +if test x"$ac_cv_sys_symbol_underscore" = xyes; then + if test x"$libltdl_cv_func_dlopen" = xyes || + test x"$libltdl_cv_lib_dl_dlopen" = xyes ; then + AC_CACHE_CHECK([whether we have to add an underscore for dlsym], + [libltdl_cv_need_uscore], + [libltdl_cv_need_uscore=unknown + save_LIBS="$LIBS" + LIBS="$LIBS $LIBADD_DL" + _LT_AC_TRY_DLOPEN_SELF( + [libltdl_cv_need_uscore=no], [libltdl_cv_need_uscore=yes], + [], [libltdl_cv_need_uscore=cross]) + LIBS="$save_LIBS" + ]) + fi +fi + +if test x"$libltdl_cv_need_uscore" = xyes; then + AC_DEFINE([NEED_USCORE], [1], + [Define if dlsym() requires a leading underscore in symbol names.]) +fi +])# AC_LTDL_DLSYM_USCORE + +# AC_LTDL_FUNC_ARGZ +# ----------------- +AC_DEFUN([AC_LTDL_FUNC_ARGZ], +[AC_CHECK_HEADERS([argz.h]) + +AC_CHECK_TYPES([error_t], + [], + [AC_DEFINE([error_t], [int], + [Define to a type to use for `error_t' if it is not otherwise available.])], + [#if HAVE_ARGZ_H +# include +#endif]) + +AC_CHECK_FUNCS([argz_append argz_create_sep argz_insert argz_next argz_stringify]) +])# AC_LTDL_FUNC_ARGZ diff --git a/libltdl/aclocal.m4 b/libltdl/aclocal.m4 new file mode 100644 index 00000000..fcc414d3 --- /dev/null +++ b/libltdl/aclocal.m4 @@ -0,0 +1,875 @@ +# generated automatically by aclocal 1.10 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_if(m4_PACKAGE_VERSION, [2.61],, +[m4_fatal([this file was generated for autoconf 2.61. +You have another version of autoconf. If you want to use that, +you should regenerate the build system entirely.], [63])]) + +# Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.10' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.10], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.10])dnl +_AM_AUTOCONF_VERSION(m4_PACKAGE_VERSION)]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 9 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], UPC, [depcc="$UPC" am_compiler_list=], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 3 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed 10q "$mf" | grep '^#.*generated by automake' > /dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. +AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 12 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.60])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $1 | $1:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputing VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([acinclude.m4]) diff --git a/libltdl/config-h.in b/libltdl/config-h.in new file mode 100644 index 00000000..b8640710 --- /dev/null +++ b/libltdl/config-h.in @@ -0,0 +1,195 @@ +/* config-h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the `argz_append' function. */ +#undef HAVE_ARGZ_APPEND + +/* Define to 1 if you have the `argz_create_sep' function. */ +#undef HAVE_ARGZ_CREATE_SEP + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARGZ_H + +/* Define to 1 if you have the `argz_insert' function. */ +#undef HAVE_ARGZ_INSERT + +/* Define to 1 if you have the `argz_next' function. */ +#undef HAVE_ARGZ_NEXT + +/* Define to 1 if you have the `argz_stringify' function. */ +#undef HAVE_ARGZ_STRINGIFY + +/* Define to 1 if you have the header file. */ +#undef HAVE_ASSERT_H + +/* Define to 1 if you have the `bcopy' function. */ +#undef HAVE_BCOPY + +/* Define to 1 if you have the `closedir' function. */ +#undef HAVE_CLOSEDIR + +/* Define to 1 if you have the header file. */ +#undef HAVE_CTYPE_H + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_DIRENT_H + +/* Define if you have the GNU dld library. */ +#undef HAVE_DLD + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLD_H + +/* Define to 1 if you have the `dlerror' function. */ +#undef HAVE_DLERROR + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_DL_H + +/* Define if you have the _dyld_func_lookup function. */ +#undef HAVE_DYLD + +/* Define to 1 if you have the header file. */ +#undef HAVE_ERRNO_H + +/* Define to 1 if the system has the type `error_t'. */ +#undef HAVE_ERROR_T + +/* Define to 1 if you have the `index' function. */ +#undef HAVE_INDEX + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define if you have the libdl library or equivalent. */ +#undef HAVE_LIBDL + +/* Define to 1 if you have the header file. */ +#undef HAVE_MACH_O_DYLD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the `memcpy' function. */ +#undef HAVE_MEMCPY + +/* Define to 1 if you have the `memmove' function. */ +#undef HAVE_MEMMOVE + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +#undef HAVE_NDIR_H + +/* Define to 1 if you have the `opendir' function. */ +#undef HAVE_OPENDIR + +/* Define if libtool can extract symbol lists from object files. */ +#undef HAVE_PRELOADED_SYMBOLS + +/* Define to 1 if you have the `readdir' function. */ +#undef HAVE_READDIR + +/* Define to 1 if you have the `rindex' function. */ +#undef HAVE_RINDEX + +/* Define if you have the shl_load function. */ +#undef HAVE_SHL_LOAD + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strcmp' function. */ +#undef HAVE_STRCMP + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strrchr' function. */ +#undef HAVE_STRRCHR + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_SYS_DIR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_DL_H + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_SYS_NDIR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define if the OS needs help to load dependent libraries for dlopen(). */ +#undef LTDL_DLOPEN_DEPLIBS + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LTDL_OBJDIR + +/* Define to the name of the environment variable that determines the dynamic + library search path. */ +#undef LTDL_SHLIBPATH_VAR + +/* Define to the extension used for shared libraries, say, ".so". */ +#undef LTDL_SHLIB_EXT + +/* Define to the system default library search path. */ +#undef LTDL_SYSSEARCHPATH + +/* Define if dlsym() requires a leading underscore in symbol names. */ +#undef NEED_USCORE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to a type to use for `error_t' if it is not otherwise available. */ +#undef error_t + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif diff --git a/libltdl/config.guess b/libltdl/config.guess new file mode 100755 index 00000000..0f0fe712 --- /dev/null +++ b/libltdl/config.guess @@ -0,0 +1,1516 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, +# Inc. + +timestamp='2007-03-06' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:[3456]*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + EM64T | authenticamd) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + xtensa:Linux:*:*) + echo xtensa-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^LIBC/{ + s: ::g + p + }'`" + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/libltdl/config.h b/libltdl/config.h new file mode 100644 index 00000000..a04820a7 --- /dev/null +++ b/libltdl/config.h @@ -0,0 +1,196 @@ +/* config.h. Generated from config-h.in by configure. */ +/* config-h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the `argz_append' function. */ +#define HAVE_ARGZ_APPEND 1 + +/* Define to 1 if you have the `argz_create_sep' function. */ +#define HAVE_ARGZ_CREATE_SEP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARGZ_H 1 + +/* Define to 1 if you have the `argz_insert' function. */ +#define HAVE_ARGZ_INSERT 1 + +/* Define to 1 if you have the `argz_next' function. */ +#define HAVE_ARGZ_NEXT 1 + +/* Define to 1 if you have the `argz_stringify' function. */ +#define HAVE_ARGZ_STRINGIFY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ASSERT_H 1 + +/* Define to 1 if you have the `bcopy' function. */ +/* #undef HAVE_BCOPY */ + +/* Define to 1 if you have the `closedir' function. */ +#define HAVE_CLOSEDIR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_CTYPE_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define if you have the GNU dld library. */ +/* #undef HAVE_DLD */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DLD_H */ + +/* Define to 1 if you have the `dlerror' function. */ +#define HAVE_DLERROR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DL_H */ + +/* Define if you have the _dyld_func_lookup function. */ +/* #undef HAVE_DYLD */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if the system has the type `error_t'. */ +#define HAVE_ERROR_T 1 + +/* Define to 1 if you have the `index' function. */ +/* #undef HAVE_INDEX */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define if you have the libdl library or equivalent. */ +#define HAVE_LIBDL 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACH_O_DYLD_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MALLOC_H 1 + +/* Define to 1 if you have the `memcpy' function. */ +#define HAVE_MEMCPY 1 + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the `opendir' function. */ +#define HAVE_OPENDIR 1 + +/* Define if libtool can extract symbol lists from object files. */ +#define HAVE_PRELOADED_SYMBOLS 1 + +/* Define to 1 if you have the `readdir' function. */ +#define HAVE_READDIR 1 + +/* Define to 1 if you have the `rindex' function. */ +/* #undef HAVE_RINDEX */ + +/* Define if you have the shl_load function. */ +/* #undef HAVE_SHL_LOAD */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strcmp' function. */ +#define HAVE_STRCMP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strrchr' function. */ +#define HAVE_STRRCHR 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_DL_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if the OS needs help to load dependent libraries for dlopen(). */ +/* #undef LTDL_DLOPEN_DEPLIBS */ + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LTDL_OBJDIR ".libs/" + +/* Define to the name of the environment variable that determines the dynamic + library search path. */ +#define LTDL_SHLIBPATH_VAR "LD_LIBRARY_PATH" + +/* Define to the extension used for shared libraries, say, ".so". */ +#define LTDL_SHLIB_EXT ".so" + +/* Define to the system default library search path. */ +#define LTDL_SYSSEARCHPATH "/lib:/usr/lib:/usr/lib/atlas:/usr/local/lib:/lib/i486-linux-gnu:/usr/lib/i486-linux-gnu:/usr/local/lib" + +/* Define if dlsym() requires a leading underscore in symbol names. */ +/* #undef NEED_USCORE */ + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "bug-libtool@gnu.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libltdl" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libltdl 1.2" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libltdl" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.2" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to a type to use for `error_t' if it is not otherwise available. */ +/* #undef error_t */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif diff --git a/libltdl/config.sub b/libltdl/config.sub new file mode 100755 index 00000000..5defff65 --- /dev/null +++ b/libltdl/config.sub @@ -0,0 +1,1622 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, +# Inc. + +timestamp='2007-01-18' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | score \ + | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16c) + basic_machine=cr16c-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/libltdl/configure b/libltdl/configure new file mode 100755 index 00000000..aa2994e0 --- /dev/null +++ b/libltdl/configure @@ -0,0 +1,23853 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.61 for libltdl 1.2. +# +# Report bugs to . +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + +if test "x$CONFIG_SHELL" = x; then + if (eval ":") 2>/dev/null; then + as_have_required=yes +else + as_have_required=no +fi + + if test $as_have_required = yes && (eval ": +(as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=\$LINENO + as_lineno_2=\$LINENO + test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && + test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } +") 2> /dev/null; then + : +else + as_candidate_shells= + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + case $as_dir in + /*) + for as_base in sh bash ksh sh5; do + as_candidate_shells="$as_candidate_shells $as_dir/$as_base" + done;; + esac +done +IFS=$as_save_IFS + + + for as_shell in $as_candidate_shells $SHELL; do + # Try only shells that exist, to save several forks. + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { ("$as_shell") 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +_ASEOF +}; then + CONFIG_SHELL=$as_shell + as_have_required=yes + if { "$as_shell" 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +(as_func_return () { + (exit $1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = "$1" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test $exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } + +_ASEOF +}; then + break +fi + +fi + + done + + if test "x$CONFIG_SHELL" != x; then + for as_var in BASH_ENV ENV + do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + done + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + + if test $as_have_required = no; then + echo This script requires a shell more modern than all the + echo shells that I found on your system. Please install a + echo modern shell, or manually run the script under such a + echo shell if you do have one. + { (exit 1); exit 1; } +fi + + +fi + +fi + + + +(eval "as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0") || { + echo No shell found that supports shell functions. + echo Please tell autoconf@gnu.org about your system, + echo including any error possibly output before this + echo message +} + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\$\\$0,'$0','` + ;; +esac + +echo=${ECHO-echo} +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null 2>&1 && unset CDPATH + +if test -z "$ECHO"; then +if test "X${echo_test_string+set}" != Xset; then +# find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string=`eval $cmd`) 2>/dev/null && + echo_test_string=`eval $cmd` && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL $0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL $0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "$0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" +fi + + + + +tagnames=${tagnames+${tagnames},}CXX + +tagnames=${tagnames+${tagnames},}F77 + +exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Identity of this package. +PACKAGE_NAME='libltdl' +PACKAGE_TARNAME='libltdl' +PACKAGE_VERSION='1.2' +PACKAGE_STRING='libltdl 1.2' +PACKAGE_BUGREPORT='bug-libtool@gnu.org' + +ac_unique_file="ltdl.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL +PATH_SEPARATOR +PACKAGE_NAME +PACKAGE_TARNAME +PACKAGE_VERSION +PACKAGE_STRING +PACKAGE_BUGREPORT +exec_prefix +prefix +program_transform_name +bindir +sbindir +libexecdir +datarootdir +datadir +sysconfdir +sharedstatedir +localstatedir +includedir +oldincludedir +docdir +infodir +htmldir +dvidir +pdfdir +psdir +libdir +localedir +mandir +DEFS +ECHO_C +ECHO_N +ECHO_T +LIBS +build_alias +host_alias +target_alias +INSTALL_PROGRAM +INSTALL_SCRIPT +INSTALL_DATA +am__isrc +CYGPATH_W +PACKAGE +VERSION +ACLOCAL +AUTOCONF +AUTOMAKE +AUTOHEADER +MAKEINFO +install_sh +STRIP +INSTALL_STRIP_PROGRAM +mkdir_p +AWK +SET_MAKE +am__leading_dot +AMTAR +am__tar +am__untar +CC +CFLAGS +LDFLAGS +CPPFLAGS +ac_ct_CC +EXEEXT +OBJEXT +DEPDIR +am__include +am__quote +AMDEP_TRUE +AMDEP_FALSE +AMDEPBACKSLASH +CCDEPMODE +am__fastdepCC_TRUE +am__fastdepCC_FALSE +build +build_cpu +build_vendor +build_os +host +host_cpu +host_vendor +host_os +SED +GREP +EGREP +LN_S +ECHO +AR +RANLIB +DLLTOOL +AS +OBJDUMP +CPP +CXX +CXXFLAGS +ac_ct_CXX +CXXDEPMODE +am__fastdepCXX_TRUE +am__fastdepCXX_FALSE +CXXCPP +F77 +FFLAGS +ac_ct_F77 +LIBTOOL +LIBTOOL_DEPS +INSTALL_LTDL_TRUE +INSTALL_LTDL_FALSE +CONVENIENCE_LTDL_TRUE +CONVENIENCE_LTDL_FALSE +LIBADD_DL +LIBOBJS +LTLIBOBJS' +ac_subst_files='' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP +CXX +CXXFLAGS +CCC +CXXCPP +F77 +FFLAGS' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=\$ac_optarg ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute directory names. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; } +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + { echo "$as_me: error: Working directory cannot be determined" >&2 + { (exit 1); exit 1; }; } +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + { echo "$as_me: error: pwd does not report name of working directory" >&2 + { (exit 1); exit 1; }; } + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$0" || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2 + { (exit 1); exit 1; }; } + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures libltdl 1.2 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/libltdl] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of libltdl 1.2:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-static[=PKGS] build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + --enable-ltdl-install install libltdl + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-pic try to use only PIC/non-PIC objects [default=use + both] + --with-tags[=TAGS] include additional configurations [automatic] + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CXXCPP C++ preprocessor + F77 Fortran 77 compiler command + FFLAGS Fortran 77 compiler flags + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +libltdl configure 1.2 +generated by GNU Autoconf 2.61 + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by libltdl $as_me 1.2, which was +generated by GNU Autoconf 2.61. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -n "$CONFIG_SITE"; then + set x "$CONFIG_SITE" +elif test "x$prefix" != xNONE; then + set x "$prefix/share/config.site" "$prefix/etc/config.site" +else + set x "$ac_default_prefix/share/config.site" \ + "$ac_default_prefix/etc/config.site" +fi +shift +for ac_site_file +do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + + + + + + + + + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + +## ------------------------------- ## +## Libltdl specific configuration. ## +## ------------------------------- ## + +ac_aux_dir= +for ac_dir in . "$srcdir"/.; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in . \"$srcdir\"/." >&5 +echo "$as_me: error: cannot find install-sh or install.sh in . \"$srcdir\"/." >&2;} + { (exit 1); exit 1; }; } +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + + +if test -z "$enable_ltdl_install$enable_ltdl_convenience"; then + if test -f ${srcdir}/ltmain.sh; then + # if libltdl is libtoolized, it is assumed to be stand-alone and + # installed unless the command line overrides it (tested above) + enable_ltdl_install=yes + else + { echo "$as_me:$LINENO: WARNING: *** The top-level configure must select either" >&5 +echo "$as_me: WARNING: *** The top-level configure must select either" >&2;} + { echo "$as_me:$LINENO: WARNING: *** A\"\"C_LIBLTDL_INSTALLABLE or A\"\"C_LIBLTDL_CONVENIENCE." >&5 +echo "$as_me: WARNING: *** A\"\"C_LIBLTDL_INSTALLABLE or A\"\"C_LIBLTDL_CONVENIENCE." >&2;} + { { echo "$as_me:$LINENO: error: *** Maybe you want to --enable-ltdl-install?" >&5 +echo "$as_me: error: *** Maybe you want to --enable-ltdl-install?" >&2;} + { (exit 1); exit 1; }; } + fi +fi + + +## ------------------------ ## +## Automake Initialisation. ## +## ------------------------ ## +am__api_version='1.10' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done +IFS=$as_save_IFS + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm -f conftest.sed + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +{ echo "$as_me:$LINENO: checking for a thread-safe mkdir -p" >&5 +echo $ECHO_N "checking for a thread-safe mkdir -p... $ECHO_C" >&6; } +if test -z "$MKDIR_P"; then + if test "${ac_cv_path_mkdir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done +done +IFS=$as_save_IFS + +fi + + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + test -d ./--version && rmdir ./--version + MKDIR_P="$ac_install_sh -d" + fi +fi +{ echo "$as_me:$LINENO: result: $MKDIR_P" >&5 +echo "${ECHO_T}$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { echo "$as_me:$LINENO: result: $AWK" >&5 +echo "${ECHO_T}$AWK" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; } +set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + SET_MAKE= +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE=libltdl + VERSION=1.2 + + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + +ac_config_headers="$ac_config_headers config.h:config-h.in" + + + +## ------------------ ## +## C compiler checks. ## +## ------------------ ## +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; } +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +# +# List of possible output files, starting from the most likely. +# The algorithm is not robust to junk in `.', hence go to wildcards (a.*) +# only as a last resort. b.out is created by i960 compilers. +ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out' +# +# The IRIX 6 linker writes into existing files which may not be +# executable, retaining their permissions. Remove them first so a +# subsequent execution test works. +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { (ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi + +{ echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6; } +if test -z "$ac_file"; then + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; } +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; } +{ echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6; } + +{ echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; } +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; } +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; } +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 +echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_c89=$ac_arg +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6; } ;; + xno) + { echo "$as_me:$LINENO: result: unsupported" >&5 +echo "${ECHO_T}unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;; +esac + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi + + +{ echo "$as_me:$LINENO: result: $_am_result" >&5 +echo "${ECHO_T}$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +depcc="$CC" am_compiler_list= + +{ echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; } +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + + +{ echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6; } +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset cs; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *pcpcc; + char **ppc; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + pcpcc = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++pcpcc; + ppc = (char**) pcpcc; + pcpcc = (char const *const *) ppc; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + if (s) return 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + if (!foo) return 0; + } + return !cs[0] && !zero.x; +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_c_const=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6; } +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + +{ echo "$as_me:$LINENO: checking for inline" >&5 +echo $ECHO_N "checking for inline... $ECHO_C" >&6; } +if test "${ac_cv_c_inline+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo () {return 0; } +$ac_kw foo_t foo () {return 0; } +#endif + +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_c_inline=$ac_kw +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_inline" != no && break +done + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5 +echo "${ECHO_T}$ac_cv_c_inline" >&6; } + + +case $ac_cv_c_inline in + inline | yes) ;; + *) + case $ac_cv_c_inline in + no) ac_val=;; + *) ac_val=$ac_cv_c_inline;; + esac + cat >>confdefs.h <<_ACEOF +#ifndef __cplusplus +#define inline $ac_val +#endif +_ACEOF + ;; +esac + + + +## ----------------------- ## +## Libtool initialisation. ## +## ----------------------- ## + + +# Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi + + +# Check whether --enable-static was given. +if test "${enable_static+set}" = set; then + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=yes +fi + + +# Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + { { echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5 +echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;} + { (exit 1); exit 1; }; } + +{ echo "$as_me:$LINENO: checking build system type" >&5 +echo $ECHO_N "checking build system type... $ECHO_C" >&6; } +if test "${ac_cv_build+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5 +echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +echo "${ECHO_T}$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) { { echo "$as_me:$LINENO: error: invalid value of canonical build" >&5 +echo "$as_me: error: invalid value of canonical build" >&2;} + { (exit 1); exit 1; }; };; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ echo "$as_me:$LINENO: checking host system type" >&5 +echo $ECHO_N "checking host system type... $ECHO_C" >&6; } +if test "${ac_cv_host+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5 +echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;} + { (exit 1); exit 1; }; } +fi + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +echo "${ECHO_T}$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) { { echo "$as_me:$LINENO: error: invalid value of canonical host" >&5 +echo "$as_me: error: invalid value of canonical host" >&2;} + { (exit 1); exit 1; }; };; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5 +echo $ECHO_N "checking for a sed that does not truncate output... $ECHO_C" >&6; } +if test "${lt_cv_path_SED+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$lt_ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$lt_ac_prog$ac_exec_ext"; }; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done + +fi + +SED=$lt_cv_path_SED + +{ echo "$as_me:$LINENO: result: $SED" >&5 +echo "${ECHO_T}$SED" >&6; } + +{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 +echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; } +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Extract the first word of "grep ggrep" to use in msg output +if test -z "$GREP"; then +set dummy grep ggrep; ac_prog_name=$2 +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_GREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue + # Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_GREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +GREP="$ac_cv_path_GREP" +if test -z "$GREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_GREP=$GREP +fi + + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 +echo "${ECHO_T}$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + # Extract the first word of "egrep" to use in msg output +if test -z "$EGREP"; then +set dummy egrep; ac_prog_name=$2 +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_EGREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue + # Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_EGREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +EGREP="$ac_cv_path_EGREP" +if test -z "$EGREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_EGREP=$EGREP +fi + + + fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 +echo "${ECHO_T}$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { echo "$as_me:$LINENO: checking for ld used by $CC" >&5 +echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { echo "$as_me:$LINENO: checking for GNU ld" >&5 +echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6; } +else + { echo "$as_me:$LINENO: checking for non-GNU ld" >&5 +echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6; } +fi +if test "${lt_cv_path_LD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +echo "${ECHO_T}$LD" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi +test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 +echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} + { (exit 1); exit 1; }; } +{ echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 +echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6; } +if test "${lt_cv_prog_gnu_ld+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + +{ echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5 +echo $ECHO_N "checking for $LD option to reload object files... $ECHO_C" >&6; } +if test "${lt_cv_ld_reload_flag+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5 +echo "${ECHO_T}$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + +{ echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5 +echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6; } +if test "${lt_cv_path_NM+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi +fi +{ echo "$as_me:$LINENO: result: $lt_cv_path_NM" >&5 +echo "${ECHO_T}$lt_cv_path_NM" >&6; } +NM="$lt_cv_path_NM" + +{ echo "$as_me:$LINENO: checking whether ln -s works" >&5 +echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } +else + { echo "$as_me:$LINENO: result: no, using $LN_S" >&5 +echo "${ECHO_T}no, using $LN_S" >&6; } +fi + +{ echo "$as_me:$LINENO: checking how to recognize dependent libraries" >&5 +echo $ECHO_N "checking how to recognize dependent libraries... $ECHO_C" >&6; } +if test "${lt_cv_deplibs_check_method+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix4* | aix5*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + if ( file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +nto-qnx*) + lt_cv_deplibs_check_method=unknown + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5 +echo "${ECHO_T}$lt_cv_deplibs_check_method" >&6; } +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then + enableval=$enable_libtool_lock; +fi + +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line 4531 "configure"' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + { echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5 +echo $ECHO_N "checking whether the C compiler needs -belf... $ECHO_C" >&6; } +if test "${lt_cv_cc_needs_belf+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + lt_cv_cc_needs_belf=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + lt_cv_cc_needs_belf=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5 +echo "${ECHO_T}$lt_cv_cc_needs_belf" >&6; } + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) LD="${LD-ld} -64" ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-cygwin* | *-*-mingw* | *-*-pw32*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_DLLTOOL+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + { echo "$as_me:$LINENO: result: $DLLTOOL" >&5 +echo "${ECHO_T}$DLLTOOL" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_DLLTOOL+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DLLTOOL="dlltool" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + { echo "$as_me:$LINENO: result: $ac_ct_DLLTOOL" >&5 +echo "${ECHO_T}$ac_ct_DLLTOOL" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_DLLTOOL" = x; then + DLLTOOL="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + DLLTOOL=$ac_ct_DLLTOOL + fi +else + DLLTOOL="$ac_cv_prog_DLLTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. +set dummy ${ac_tool_prefix}as; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_AS+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AS"; then + ac_cv_prog_AS="$AS" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AS="${ac_tool_prefix}as" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +AS=$ac_cv_prog_AS +if test -n "$AS"; then + { echo "$as_me:$LINENO: result: $AS" >&5 +echo "${ECHO_T}$AS" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AS"; then + ac_ct_AS=$AS + # Extract the first word of "as", so it can be a program name with args. +set dummy as; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_AS+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_AS"; then + ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_AS="as" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_AS=$ac_cv_prog_ac_ct_AS +if test -n "$ac_ct_AS"; then + { echo "$as_me:$LINENO: result: $ac_ct_AS" >&5 +echo "${ECHO_T}$ac_ct_AS" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_AS" = x; then + AS="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + AS=$ac_ct_AS + fi +else + AS="$ac_cv_prog_AS" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_OBJDUMP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { echo "$as_me:$LINENO: result: $OBJDUMP" >&5 +echo "${ECHO_T}$OBJDUMP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { echo "$as_me:$LINENO: result: $ac_ct_OBJDUMP" >&5 +echo "${ECHO_T}$ac_ct_OBJDUMP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + + ;; + +esac + +need_locks="$enable_libtool_lock" + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_header_stdc=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +for ac_header in dlfcn.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ---------------------------------- ## +## Report this to bug-libtool@gnu.org ## +## ---------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { echo "$as_me:$LINENO: result: $CXX" >&5 +echo "${ECHO_T}$CXX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 +echo "${ECHO_T}$ac_ct_CXX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C++ compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +{ echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6; } +GXX=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 +echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CXXFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; } +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + + + +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5 +echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6; } +if test -z "$CXXCPP"; then + if test "${ac_cv_prog_CXXCPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ echo "$as_me:$LINENO: result: $CXXCPP" >&5 +echo "${ECHO_T}$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +fi + + +ac_ext=f +ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' +ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_f77_compiler_gnu +if test -n "$ac_tool_prefix"; then + for ac_prog in g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77 xlf90 f90 pgf90 pghpf epcf90 gfortran g95 xlf95 f95 fort ifort ifc efc pgf95 lf95 ftn + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$F77"; then + ac_cv_prog_F77="$F77" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_F77="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +F77=$ac_cv_prog_F77 +if test -n "$F77"; then + { echo "$as_me:$LINENO: result: $F77" >&5 +echo "${ECHO_T}$F77" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$F77" && break + done +fi +if test -z "$F77"; then + ac_ct_F77=$F77 + for ac_prog in g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77 xlf90 f90 pgf90 pghpf epcf90 gfortran g95 xlf95 f95 fort ifort ifc efc pgf95 lf95 ftn +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_F77"; then + ac_cv_prog_ac_ct_F77="$ac_ct_F77" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_F77="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_F77=$ac_cv_prog_ac_ct_F77 +if test -n "$ac_ct_F77"; then + { echo "$as_me:$LINENO: result: $ac_ct_F77" >&5 +echo "${ECHO_T}$ac_ct_F77" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_F77" && break +done + + if test "x$ac_ct_F77" = x; then + F77="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + F77=$ac_ct_F77 + fi +fi + + +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for Fortran 77 compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +rm -f a.out + +# If we don't use `.F' as extension, the preprocessor is not run on the +# input file. (Note that this only needs to work for GNU compilers.) +ac_save_ext=$ac_ext +ac_ext=F +{ echo "$as_me:$LINENO: checking whether we are using the GNU Fortran 77 compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU Fortran 77 compiler... $ECHO_C" >&6; } +if test "${ac_cv_f77_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF + program main +#ifndef __GNUC__ + choke me +#endif + + end +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_f77_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_f77_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_f77_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_f77_compiler_gnu" >&6; } +ac_ext=$ac_save_ext +ac_test_FFLAGS=${FFLAGS+set} +ac_save_FFLAGS=$FFLAGS +FFLAGS= +{ echo "$as_me:$LINENO: checking whether $F77 accepts -g" >&5 +echo $ECHO_N "checking whether $F77 accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_f77_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + FFLAGS=-g +cat >conftest.$ac_ext <<_ACEOF + program main + + end +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_f77_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_f77_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_prog_f77_g=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_f77_g" >&5 +echo "${ECHO_T}$ac_cv_prog_f77_g" >&6; } +if test "$ac_test_FFLAGS" = set; then + FFLAGS=$ac_save_FFLAGS +elif test $ac_cv_prog_f77_g = yes; then + if test "x$ac_cv_f77_compiler_gnu" = xyes; then + FFLAGS="-g -O2" + else + FFLAGS="-g" + fi +else + if test "x$ac_cv_f77_compiler_gnu" = xyes; then + FFLAGS="-O2" + else + FFLAGS= + fi +fi + +G77=`test $ac_compiler_gnu = yes && echo yes` +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! + +# find the maximum length of command line arguments +{ echo "$as_me:$LINENO: checking the maximum length of command line arguments" >&5 +echo $ECHO_N "checking the maximum length of command line arguments... $ECHO_C" >&6; } +if test "${lt_cv_sys_max_cmd_len+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + while (test "X"`$SHELL $0 --fallback-echo "X$teststring" 2>/dev/null` \ + = "XX$teststring") >/dev/null 2>&1 && + new_result=`expr "X$teststring" : ".*" 2>&1` && + lt_cv_sys_max_cmd_len=$new_result && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + teststring= + # Add a significant safety factor because C++ compilers can tack on massive + # amounts of additional arguments before passing them to the linker. + # It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + { echo "$as_me:$LINENO: result: $lt_cv_sys_max_cmd_len" >&5 +echo "${ECHO_T}$lt_cv_sys_max_cmd_len" >&6; } +else + { echo "$as_me:$LINENO: result: none" >&5 +echo "${ECHO_T}none" >&6; } +fi + + + + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ echo "$as_me:$LINENO: checking command to parse $NM output from $compiler object" >&5 +echo $ECHO_N "checking command to parse $NM output from $compiler object... $ECHO_C" >&6; } +if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32*) + symcode='[ABCDGISTW]' + ;; +hpux*) # Its linker distinguishes data from code symbols + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +linux* | k*bsd*-gnu) + if test "$host_cpu" = ia64; then + symcode='[ABCDGIRSTW]' + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5 + (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if grep ' nm_test_var$' "$nlist" >/dev/null; then + if grep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[] = +{ +EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { echo "$as_me:$LINENO: result: failed" >&5 +echo "${ECHO_T}failed" >&6; } +else + { echo "$as_me:$LINENO: result: ok" >&5 +echo "${ECHO_T}ok" >&6; } +fi + +{ echo "$as_me:$LINENO: checking for objdir" >&5 +echo $ECHO_N "checking for objdir... $ECHO_C" >&6; } +if test "${lt_cv_objdir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ echo "$as_me:$LINENO: result: $lt_cv_objdir" >&5 +echo "${ECHO_T}$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e 1s/^X//' +sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_AR+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { echo "$as_me:$LINENO: result: $AR" >&5 +echo "${ECHO_T}$AR" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_AR+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_AR="ar" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { echo "$as_me:$LINENO: result: $ac_ct_AR" >&5 +echo "${ECHO_T}$ac_ct_AR" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$SED" && SED=sed +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5 +echo $ECHO_N "checking for ${ac_tool_prefix}file... $ECHO_C" >&6; } +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 +echo "${ECHO_T}$MAGIC_CMD" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { echo "$as_me:$LINENO: checking for file" >&5 +echo $ECHO_N "checking for file... $ECHO_C" >&6; } +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 +echo "${ECHO_T}$MAGIC_CMD" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +enable_dlopen=no +enable_win32_dll=yes + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then + enableval=$enable_libtool_lock; +fi + +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then + withval=$with_pic; pic_mode="$withval" +else + pic_mode=default +fi + +test -z "$pic_mode" && pic_mode=default + +# Use C for the default configuration in the libtool script +tagname= +lt_save_CC="$CC" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* + + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + lt_prog_compiler_no_builtin_flag=' -fno-builtin' + + +{ echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:7567: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:7571: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + +lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + +{ echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6; } + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + lt_prog_compiler_pic='-qnocommon' + lt_prog_compiler_wl='-Wl,' + ;; + esac + ;; + + mingw* | cygwin* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + icc* | ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + esac + ;; + esac + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic" >&6; } + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + +{ echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic works... $ECHO_C" >&6; } +if test "${lt_prog_compiler_pic_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:7857: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:7861: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_pic_works=yes + fi + fi + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_works" >&6; } + +if test x"$lt_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6; } +if test "${lt_prog_compiler_static_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_static_works=yes + fi + else + lt_prog_compiler_static_works=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works" >&5 +echo "${ECHO_T}$lt_prog_compiler_static_works" >&6; } + +if test x"$lt_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + +{ echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_c_o+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:7961: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:7965: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o" >&6; } + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6; } + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6; } + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +{ echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6; } + + runpath_var= + allow_undefined_flag= + enable_shared_with_static_runtimes=no + archive_cmds= + archive_expsym_cmds= + old_archive_From_new_cmds= + old_archive_from_expsyms_cmds= + export_dynamic_flag_spec= + whole_archive_flag_spec= + thread_safe_flag_spec= + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld= + hardcode_libdir_separator= + hardcode_direct=no + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + link_all_deplibs=unknown + hardcode_automatic=no + module_cmds= + module_expsym_cmds= + always_export_symbols=no + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + # Just being paranoid about ensuring that cc_basename is set. + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + ld_shlibs=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | k*bsd*-gnu) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + *) + tmp_sharedflag='-shared' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test $supports_anon_versioning = yes; then + archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + $echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + link_all_deplibs=no + else + ld_shlibs=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = no; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_From_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes=yes + ;; + + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[012]) + allow_undefined_flag='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + allow_undefined_flag='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + whole_archive_flag_spec='' + link_all_deplibs=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + archive_cmds='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring' + module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs=no + ;; + esac + fi + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + freebsd1*) + ld_shlibs=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + hardcode_direct=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_libdir_flag_spec_ld='+b $libdir' + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_ld='-rpath $libdir' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + link_all_deplibs=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_From_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z text' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + wlarc='' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='${wl}-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + fi + +{ echo "$as_me:$LINENO: result: $ld_shlibs" >&5 +echo "${ECHO_T}$ld_shlibs" >&6; } +test "$ld_shlibs" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6; } + $rm conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc=no + else + archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + { echo "$as_me:$LINENO: result: $archive_cmds_need_lc" >&5 +echo "${ECHO_T}$archive_cmds_need_lc" >&6; } + ;; + esac + fi + ;; +esac + +{ echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6; } +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" + +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$lt_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`echo "$lt_search_path_spec" | $SED -e 's/;/ /g'` + else + lt_search_path_spec=`echo "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`echo $lt_tmp_lt_search_path_spec | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + sys_lib_search_path_spec=`echo $lt_search_path_spec` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +{ echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || \ + test -n "$runpath_var" || \ + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ echo "$as_me:$LINENO: result: $hardcode_action" >&5 +echo "${ECHO_T}$hardcode_action" >&6; } + +if test "$hardcode_action" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + +striplib= +old_striplib= +{ echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5 +echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + ;; + *) + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + ;; + esac +fi + +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6; } +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dl_dlopen=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6; } +if test $ac_cv_lib_dl_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + { echo "$as_me:$LINENO: checking for shl_load" >&5 +echo $ECHO_N "checking for shl_load... $ECHO_C" >&6; } +if test "${ac_cv_func_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define shl_load to an innocuous variant, in case declares shl_load. + For example, HP-UX 11i declares gettimeofday. */ +#define shl_load innocuous_shl_load + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char shl_load (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef shl_load + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_shl_load || defined __stub___shl_load +choke me +#endif + +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_func_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_shl_load=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5 +echo "${ECHO_T}$ac_cv_func_shl_load" >&6; } +if test $ac_cv_func_shl_load = yes; then + lt_cv_dlopen="shl_load" +else + { echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 +echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6; } +if test "${ac_cv_lib_dld_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_dld_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dld_shl_load=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6; } +if test $ac_cv_lib_dld_shl_load = yes; then + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld" +else + { echo "$as_me:$LINENO: checking for dlopen" >&5 +echo $ECHO_N "checking for dlopen... $ECHO_C" >&6; } +if test "${ac_cv_func_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define dlopen to an innocuous variant, in case declares dlopen. + For example, HP-UX 11i declares gettimeofday. */ +#define dlopen innocuous_dlopen + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char dlopen (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef dlopen + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_dlopen || defined __stub___dlopen +choke me +#endif + +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_func_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_dlopen=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5 +echo "${ECHO_T}$ac_cv_func_dlopen" >&6; } +if test $ac_cv_func_dlopen = yes; then + lt_cv_dlopen="dlopen" +else + { echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6; } +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dl_dlopen=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6; } +if test $ac_cv_lib_dl_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + { echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5 +echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6; } +if test "${ac_cv_lib_svld_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_svld_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_svld_dlopen=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6; } +if test $ac_cv_lib_svld_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + { echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5 +echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6; } +if test "${ac_cv_lib_dld_dld_link+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_dld_dld_link=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dld_dld_link=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6; } +if test $ac_cv_lib_dld_dld_link = yes; then + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + { echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5 +echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6; } +if test "${lt_cv_dlopen_self+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + exit (status); +} +EOF + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self" >&6; } + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5 +echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6; } +if test "${lt_cv_dlopen_self_static+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + exit (status); +} +EOF + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + +# Report which library types will actually be built +{ echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5 +echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6; } +{ echo "$as_me:$LINENO: result: $can_build_shared" >&5 +echo "${ECHO_T}$can_build_shared" >&6; } + +{ echo "$as_me:$LINENO: checking whether to build shared libraries" >&5 +echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6; } +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case $host_os in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4* | aix5*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +{ echo "$as_me:$LINENO: result: $enable_shared" >&5 +echo "${ECHO_T}$enable_shared" >&6; } + +{ echo "$as_me:$LINENO: checking whether to build static libraries" >&5 +echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6; } +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +{ echo "$as_me:$LINENO: result: $enable_static" >&5 +echo "${ECHO_T}$enable_static" >&6; } + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler \ + CC \ + LD \ + lt_prog_compiler_wl \ + lt_prog_compiler_pic \ + lt_prog_compiler_static \ + lt_prog_compiler_no_builtin_flag \ + export_dynamic_flag_spec \ + thread_safe_flag_spec \ + whole_archive_flag_spec \ + enable_shared_with_static_runtimes \ + old_archive_cmds \ + old_archive_from_new_cmds \ + predep_objects \ + postdep_objects \ + predeps \ + postdeps \ + compiler_lib_search_path \ + archive_cmds \ + archive_expsym_cmds \ + postinstall_cmds \ + postuninstall_cmds \ + old_archive_from_expsyms_cmds \ + allow_undefined_flag \ + no_undefined_flag \ + export_symbols_cmds \ + hardcode_libdir_flag_spec \ + hardcode_libdir_flag_spec_ld \ + hardcode_libdir_separator \ + hardcode_automatic \ + module_cmds \ + module_expsym_cmds \ + lt_cv_prog_compiler_c_o \ + fix_srcfile_path \ + exclude_expsyms \ + include_expsyms; do + + case $var in + old_archive_cmds | \ + old_archive_from_new_cmds | \ + archive_cmds | \ + archive_expsym_cmds | \ + module_cmds | \ + module_expsym_cmds | \ + old_archive_from_expsyms_cmds | \ + export_symbols_cmds | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="${ofile}T" + trap "$rm \"$cfgfile\"; exit 1" 1 2 15 + $rm -f "$cfgfile" + { echo "$as_me:$LINENO: creating $ofile" >&5 +echo "$as_me: creating $ofile" >&6;} + + cat <<__EOF__ >> "$cfgfile" +#! $SHELL + +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="$SED -e 1s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# The names of the tagged configurations supported by this script. +available_tags= + +# ### BEGIN LIBTOOL CONFIG + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU C compiler? +with_gcc=$GCC + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# ### END LIBTOOL CONFIG + +__EOF__ + + + case $host_os in + aix3*) + cat <<\EOF >> "$cfgfile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || \ + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + +# Check whether --with-tags was given. +if test "${with_tags+set}" = set; then + withval=$with_tags; tagnames="$withval" +fi + + +if test -f "$ltmain" && test -n "$tagnames"; then + if test ! -f "${ofile}"; then + { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not exist" >&5 +echo "$as_me: WARNING: output file \`$ofile' does not exist" >&2;} + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not look like a libtool script" >&5 +echo "$as_me: WARNING: output file \`$ofile' does not look like a libtool script" >&2;} + else + { echo "$as_me:$LINENO: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&5 +echo "$as_me: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&2;} + fi + fi + if test -z "$LTCFLAGS"; then + eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`" + fi + + # Extract list of available tagged configurations in $ofile. + # Note that this assumes the entire list is on one line. + available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` + + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for tagname in $tagnames; do + IFS="$lt_save_ifs" + # Check whether tagname contains only valid characters + case `$echo "X$tagname" | $Xsed -e 's:[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]::g'` in + "") ;; + *) { { echo "$as_me:$LINENO: error: invalid tag name: $tagname" >&5 +echo "$as_me: error: invalid tag name: $tagname" >&2;} + { (exit 1); exit 1; }; } + ;; + esac + + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null + then + { { echo "$as_me:$LINENO: error: tag name \"$tagname\" already exists" >&5 +echo "$as_me: error: tag name \"$tagname\" already exists" >&2;} + { (exit 1); exit 1; }; } + fi + + # Update the list of available tags. + if test -n "$tagname"; then + echo appending configuration tag \"$tagname\" to $ofile + + case $tagname in + CXX) + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + + +archive_cmds_need_lc_CXX=no +allow_undefined_flag_CXX= +always_export_symbols_CXX=no +archive_expsym_cmds_CXX= +export_dynamic_flag_spec_CXX= +hardcode_direct_CXX=no +hardcode_libdir_flag_spec_CXX= +hardcode_libdir_flag_spec_ld_CXX= +hardcode_libdir_separator_CXX= +hardcode_minus_L_CXX=no +hardcode_shlibpath_var_CXX=unsupported +hardcode_automatic_CXX=no +module_cmds_CXX= +module_expsym_cmds_CXX= +link_all_deplibs_CXX=unknown +old_archive_cmds_CXX=$old_archive_cmds +no_undefined_flag_CXX= +whole_archive_flag_spec_CXX= +enable_shared_with_static_runtimes_CXX=no + +# Dependencies to place before and after the object being linked: +predep_objects_CXX= +postdep_objects_CXX= +predeps_CXX= +postdeps_CXX= +compiler_lib_search_path_CXX= + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +objext_CXX=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(int, char *[]) { return(0); }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* + + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_LD=$LD +lt_save_GCC=$GCC +GCC=$GXX +lt_save_with_gnu_ld=$with_gnu_ld +lt_save_path_LD=$lt_cv_path_LD +if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx +else + $as_unset lt_cv_prog_gnu_ld +fi +if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX +else + $as_unset lt_cv_path_LD +fi +test -z "${LDCXX+set}" || LD=$LDCXX +CC=${CXX-"c++"} +compiler=$CC +compiler_CXX=$CC +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +# We don't want -fno-exception wen compiling C++ code, so set the +# no_builtin_flag separately +if test "$GXX" = yes; then + lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' +else + lt_prog_compiler_no_builtin_flag_CXX= +fi + +if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { echo "$as_me:$LINENO: checking for ld used by $CC" >&5 +echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { echo "$as_me:$LINENO: checking for GNU ld" >&5 +echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6; } +else + { echo "$as_me:$LINENO: checking for non-GNU ld" >&5 +echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6; } +fi +if test "${lt_cv_path_LD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +echo "${ECHO_T}$LD" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi +test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 +echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} + { (exit 1); exit 1; }; } +{ echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 +echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6; } +if test "${lt_cv_prog_gnu_ld+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ + grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_CXX= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + +else + GXX=no + with_gnu_ld=no + wlarc= +fi + +# PORTME: fill in a description of your system's C++ link characteristics +{ echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6; } +ld_shlibs_CXX=yes +case $host_os in + aix3*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_CXX='' + hardcode_direct_CXX=yes + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct_CXX=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_CXX=yes + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_libdir_separator_CXX= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols_CXX=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_CXX='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + + archive_expsym_cmds_CXX="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_CXX="-z nodefs" + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_CXX=' ${wl}-bernotok' + allow_undefined_flag_CXX=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_CXX='$convenience' + archive_cmds_need_lc_CXX=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_CXX=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_CXX=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_CXX='-L$libdir' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=no + enable_shared_with_static_runtimes_CXX=yes + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_CXX=no + fi + ;; + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[012]) + allow_undefined_flag_CXX='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + allow_undefined_flag_CXX='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + allow_undefined_flag_CXX='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + allow_undefined_flag_CXX='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes + hardcode_shlibpath_var_CXX=unsupported + whole_archive_flag_spec_CXX='' + link_all_deplibs_CXX=yes + + if test "$GXX" = yes ; then + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + archive_cmds_CXX='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + else + archive_cmds_CXX='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + fi + module_cmds_CXX='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds_CXX='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring' + module_cmds_CXX='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs_CXX=no + ;; + esac + fi + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + freebsd[12]*) + # C++ shared libraries reported to be fairly broken before switch to ELF + ld_shlibs_CXX=no + ;; + freebsd-elf*) + archive_cmds_need_lc_CXX=no + ;; + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + ld_shlibs_CXX=yes + ;; + gnu*) + ;; + hpux9*) + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + export_dynamic_flag_spec_CXX='${wl}-E' + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + archive_cmds_CXX='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[-]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + archive_cmds_CXX='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + case $host_cpu in + hppa*64*|ia64*) ;; + *) + export_dynamic_flag_spec_CXX='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + ;; + *) + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + interix[3-9]*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' + fi + fi + link_all_deplibs_CXX=yes + ;; + esac + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + hardcode_libdir_flag_spec_CXX='${wl}--rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc*) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC*) + # Portland Group C++ compiler + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + hardcode_libdir_flag_spec_CXX='-R$libdir' + whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + lynxos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + m88k*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + openbsd2*) + # C++ shared libraries are fairly broken + ld_shlibs_CXX=no + ;; + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + export_dynamic_flag_spec_CXX='${wl}-E' + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd='echo' + else + ld_shlibs_CXX=no + fi + ;; + osf3*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + allow_undefined_flag_CXX=' -expect_unresolved \*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~ + $rm $lib.exp' + + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + psos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + archive_cmds_need_lc_CXX=yes + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_shlibpath_var_CXX=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' + ;; + esac + link_all_deplibs_CXX=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + no_undefined_flag_CXX=' ${wl}-z ${wl}defs' + if $CC --version | grep -v '^2\.7' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + fi + + hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_CXX='${wl}-z,text' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + # So that behaviour is only enabled if SCOABSPATH is set to a + # non-empty value in the environment. Most likely only useful for + # creating official distributions of packages. + # This is a hack until libtool officially supports absolute path + # names for shared libraries. + no_undefined_flag_CXX='${wl}-z,text' + allow_undefined_flag_CXX='${wl}-z,nodefs' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + export_dynamic_flag_spec_CXX='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + vxworks*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; +esac +{ echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5 +echo "${ECHO_T}$ld_shlibs_CXX" >&6; } +test "$ld_shlibs_CXX" = no && can_build_shared=no + +GCC_CXX="$GXX" +LD_CXX="$LD" + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... + +cat > conftest.$ac_ext <&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + # The `*' in the case matches for architectures that use `case' in + # $output_verbose_cmd can trigger glob expansion during the loop + # eval without this substitution. + output_verbose_link_cmd=`$echo "X$output_verbose_link_cmd" | $Xsed -e "$no_glob_subst"` + + for p in `eval $output_verbose_link_cmd`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" \ + || test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$compiler_lib_search_path_CXX"; then + compiler_lib_search_path_CXX="${prev}${p}" + else + compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$postdeps_CXX"; then + postdeps_CXX="${prev}${p}" + else + postdeps_CXX="${postdeps_CXX} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$predep_objects_CXX"; then + predep_objects_CXX="$p" + else + predep_objects_CXX="$predep_objects_CXX $p" + fi + else + if test -z "$postdep_objects_CXX"; then + postdep_objects_CXX="$p" + else + postdep_objects_CXX="$postdep_objects_CXX $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling CXX test program" +fi + +$rm -f confest.$objext + +# PORTME: override above test on systems where it is broken +case $host_os in +interix[3-9]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + predep_objects_CXX= + postdep_objects_CXX= + postdeps_CXX= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + # + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac + + +case " $postdeps_CXX " in +*" -lc "*) archive_cmds_need_lc_CXX=no ;; +esac + +lt_prog_compiler_wl_CXX= +lt_prog_compiler_pic_CXX= +lt_prog_compiler_static_CXX= + +{ echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6; } + + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + fi + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_CXX='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + lt_prog_compiler_pic_CXX= + ;; + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_CXX=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + else + case $host_os in + aix4* | aix5*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + else + lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_AC_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + lt_prog_compiler_pic_CXX='-qnocommon' + lt_prog_compiler_wl_CXX='-Wl,' + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + lt_prog_compiler_pic_CXX='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + lt_prog_compiler_pic_CXX='+Z' + fi + ;; + aCC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_CXX='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + lt_prog_compiler_wl_CXX='--backend -Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + ;; + icpc* | ecpc*) + # Intel C++ + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-static' + ;; + pgCC*) + # Portland Group C++ compiler. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fpic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + lt_prog_compiler_pic_CXX='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + lt_prog_compiler_wl_CXX='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + lt_prog_compiler_pic_CXX='-pic' + ;; + cxx*) + # Digital/Compaq C++ + lt_prog_compiler_wl_CXX='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + lt_prog_compiler_pic_CXX='-pic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + lcc*) + # Lucid + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + lt_prog_compiler_pic_CXX='-KPIC' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + esac + ;; + vxworks*) + ;; + *) + lt_prog_compiler_can_build_shared_CXX=no + ;; + esac + fi + +{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_CXX" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_CXX" >&6; } + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_CXX"; then + +{ echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... $ECHO_C" >&6; } +if test "${lt_prog_compiler_pic_works_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_pic_works_CXX=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:12847: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:12851: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_pic_works_CXX=yes + fi + fi + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_CXX" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_works_CXX" >&6; } + +if test x"$lt_prog_compiler_pic_works_CXX" = xyes; then + case $lt_prog_compiler_pic_CXX in + "" | " "*) ;; + *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; + esac +else + lt_prog_compiler_pic_CXX= + lt_prog_compiler_can_build_shared_CXX=no +fi + +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_CXX= + ;; + *) + lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" +{ echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6; } +if test "${lt_prog_compiler_static_works_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_static_works_CXX=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_static_works_CXX=yes + fi + else + lt_prog_compiler_static_works_CXX=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works_CXX" >&5 +echo "${ECHO_T}$lt_prog_compiler_static_works_CXX" >&6; } + +if test x"$lt_prog_compiler_static_works_CXX" = xyes; then + : +else + lt_prog_compiler_static_CXX= +fi + + +{ echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:12951: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:12955: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o_CXX" >&6; } + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6; } + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6; } + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +{ echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6; } + + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix4* | aix5*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + export_symbols_cmds_CXX="$ltdll_cmds" + ;; + cygwin* | mingw*) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;/^.*[ ]__nm__/s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + ;; + linux* | k*bsd*-gnu) + link_all_deplibs_CXX=no + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + +{ echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5 +echo "${ECHO_T}$ld_shlibs_CXX" >&6; } +test "$ld_shlibs_CXX" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_CXX" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_CXX=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_CXX in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6; } + $rm conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_CXX + pic_flag=$lt_prog_compiler_pic_CXX + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_CXX + allow_undefined_flag_CXX= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc_CXX=no + else + archive_cmds_need_lc_CXX=yes + fi + allow_undefined_flag_CXX=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + { echo "$as_me:$LINENO: result: $archive_cmds_need_lc_CXX" >&5 +echo "${ECHO_T}$archive_cmds_need_lc_CXX" >&6; } + ;; + esac + fi + ;; +esac + +{ echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6; } +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" + +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +{ echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6; } +hardcode_action_CXX= +if test -n "$hardcode_libdir_flag_spec_CXX" || \ + test -n "$runpath_var_CXX" || \ + test "X$hardcode_automatic_CXX" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct_CXX" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, CXX)" != no && + test "$hardcode_minus_L_CXX" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_CXX=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_CXX=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_CXX=unsupported +fi +{ echo "$as_me:$LINENO: result: $hardcode_action_CXX" >&5 +echo "${ECHO_T}$hardcode_action_CXX" >&6; } + +if test "$hardcode_action_CXX" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_CXX \ + CC_CXX \ + LD_CXX \ + lt_prog_compiler_wl_CXX \ + lt_prog_compiler_pic_CXX \ + lt_prog_compiler_static_CXX \ + lt_prog_compiler_no_builtin_flag_CXX \ + export_dynamic_flag_spec_CXX \ + thread_safe_flag_spec_CXX \ + whole_archive_flag_spec_CXX \ + enable_shared_with_static_runtimes_CXX \ + old_archive_cmds_CXX \ + old_archive_from_new_cmds_CXX \ + predep_objects_CXX \ + postdep_objects_CXX \ + predeps_CXX \ + postdeps_CXX \ + compiler_lib_search_path_CXX \ + archive_cmds_CXX \ + archive_expsym_cmds_CXX \ + postinstall_cmds_CXX \ + postuninstall_cmds_CXX \ + old_archive_from_expsyms_cmds_CXX \ + allow_undefined_flag_CXX \ + no_undefined_flag_CXX \ + export_symbols_cmds_CXX \ + hardcode_libdir_flag_spec_CXX \ + hardcode_libdir_flag_spec_ld_CXX \ + hardcode_libdir_separator_CXX \ + hardcode_automatic_CXX \ + module_cmds_CXX \ + module_expsym_cmds_CXX \ + lt_cv_prog_compiler_c_o_CXX \ + fix_srcfile_path_CXX \ + exclude_expsyms_CXX \ + include_expsyms_CXX; do + + case $var in + old_archive_cmds_CXX | \ + old_archive_from_new_cmds_CXX | \ + archive_cmds_CXX | \ + archive_expsym_cmds_CXX | \ + module_cmds_CXX | \ + module_expsym_cmds_CXX | \ + old_archive_from_expsyms_cmds_CXX | \ + export_symbols_cmds_CXX | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_CXX + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler_CXX + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_CXX + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_CXX + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_CXX + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_CXX +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_CXX + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_CXX + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_CXX +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_CXX +archive_expsym_cmds=$lt_archive_expsym_cmds_CXX +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_CXX +module_expsym_cmds=$lt_module_expsym_cmds_CXX + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_CXX + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_CXX + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_CXX + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_CXX + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_CXX + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_CXX + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_CXX + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_CXX + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_CXX + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_CXX + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_CXX + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_CXX + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_CXX + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_CXX + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_CXX + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_CXX + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC=$lt_save_CC +LDCXX=$LD +LD=$lt_save_LD +GCC=$lt_save_GCC +with_gnu_ldcxx=$with_gnu_ld +with_gnu_ld=$lt_save_with_gnu_ld +lt_cv_path_LDCXX=$lt_cv_path_LD +lt_cv_path_LD=$lt_save_path_LD +lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld +lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld + + else + tagname="" + fi + ;; + + F77) + if test -n "$F77" && test "X$F77" != "Xno"; then + +ac_ext=f +ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' +ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_f77_compiler_gnu + + +archive_cmds_need_lc_F77=no +allow_undefined_flag_F77= +always_export_symbols_F77=no +archive_expsym_cmds_F77= +export_dynamic_flag_spec_F77= +hardcode_direct_F77=no +hardcode_libdir_flag_spec_F77= +hardcode_libdir_flag_spec_ld_F77= +hardcode_libdir_separator_F77= +hardcode_minus_L_F77=no +hardcode_automatic_F77=no +module_cmds_F77= +module_expsym_cmds_F77= +link_all_deplibs_F77=unknown +old_archive_cmds_F77=$old_archive_cmds +no_undefined_flag_F77= +whole_archive_flag_spec_F77= +enable_shared_with_static_runtimes_F77=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +objext_F77=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="\ + subroutine t + return + end +" + +# Code to be used in simple link tests +lt_simple_link_test_code="\ + program t + end +" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* + + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${F77-"f77"} +compiler=$CC +compiler_F77=$CC +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +{ echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5 +echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6; } +{ echo "$as_me:$LINENO: result: $can_build_shared" >&5 +echo "${ECHO_T}$can_build_shared" >&6; } + +{ echo "$as_me:$LINENO: checking whether to build shared libraries" >&5 +echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6; } +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case $host_os in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; +aix4* | aix5*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +{ echo "$as_me:$LINENO: result: $enable_shared" >&5 +echo "${ECHO_T}$enable_shared" >&6; } + +{ echo "$as_me:$LINENO: checking whether to build static libraries" >&5 +echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6; } +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +{ echo "$as_me:$LINENO: result: $enable_static" >&5 +echo "${ECHO_T}$enable_static" >&6; } + +GCC_F77="$G77" +LD_F77="$LD" + +lt_prog_compiler_wl_F77= +lt_prog_compiler_pic_F77= +lt_prog_compiler_static_F77= + +{ echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6; } + + if test "$GCC" = yes; then + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_static_F77='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_F77='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_F77='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic_F77='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_F77='-fno-common' + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared_F77=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_F77=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_F77='-fPIC' + ;; + esac + ;; + + *) + lt_prog_compiler_pic_F77='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl_F77='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_F77='-Bstatic' + else + lt_prog_compiler_static_F77='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + lt_prog_compiler_pic_F77='-qnocommon' + lt_prog_compiler_wl_F77='-Wl,' + ;; + esac + ;; + + mingw* | cygwin* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_F77='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl_F77='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_F77='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static_F77='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl_F77='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static_F77='-non_shared' + ;; + + newsos6) + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + icc* | ecc*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-fpic' + lt_prog_compiler_static_F77='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl_F77='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static_F77='-non_shared' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + lt_prog_compiler_wl_F77='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + lt_prog_compiler_wl_F77='' + ;; + esac + ;; + esac + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl_F77='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static_F77='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static_F77='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl_F77='-Qoption ld ';; + *) + lt_prog_compiler_wl_F77='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl_F77='-Qoption ld ' + lt_prog_compiler_pic_F77='-PIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic_F77='-Kconform_pic' + lt_prog_compiler_static_F77='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_can_build_shared_F77=no + ;; + + uts4*) + lt_prog_compiler_pic_F77='-pic' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared_F77=no + ;; + esac + fi + +{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_F77" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_F77" >&6; } + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_F77"; then + +{ echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works... $ECHO_C" >&6; } +if test "${lt_prog_compiler_pic_works_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_pic_works_F77=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_F77" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:14528: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:14532: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_pic_works_F77=yes + fi + fi + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_F77" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_works_F77" >&6; } + +if test x"$lt_prog_compiler_pic_works_F77" = xyes; then + case $lt_prog_compiler_pic_F77 in + "" | " "*) ;; + *) lt_prog_compiler_pic_F77=" $lt_prog_compiler_pic_F77" ;; + esac +else + lt_prog_compiler_pic_F77= + lt_prog_compiler_can_build_shared_F77=no +fi + +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_F77= + ;; + *) + lt_prog_compiler_pic_F77="$lt_prog_compiler_pic_F77" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_F77 eval lt_tmp_static_flag=\"$lt_prog_compiler_static_F77\" +{ echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6; } +if test "${lt_prog_compiler_static_works_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_static_works_F77=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_static_works_F77=yes + fi + else + lt_prog_compiler_static_works_F77=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works_F77" >&5 +echo "${ECHO_T}$lt_prog_compiler_static_works_F77" >&6; } + +if test x"$lt_prog_compiler_static_works_F77" = xyes; then + : +else + lt_prog_compiler_static_F77= +fi + + +{ echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_c_o_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o_F77=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:14632: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:14636: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_F77=yes + fi + fi + chmod u+w . 2>&5 + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_F77" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o_F77" >&6; } + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_F77" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6; } + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6; } + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +{ echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6; } + + runpath_var= + allow_undefined_flag_F77= + enable_shared_with_static_runtimes_F77=no + archive_cmds_F77= + archive_expsym_cmds_F77= + old_archive_From_new_cmds_F77= + old_archive_from_expsyms_cmds_F77= + export_dynamic_flag_spec_F77= + whole_archive_flag_spec_F77= + thread_safe_flag_spec_F77= + hardcode_libdir_flag_spec_F77= + hardcode_libdir_flag_spec_ld_F77= + hardcode_libdir_separator_F77= + hardcode_direct_F77=no + hardcode_minus_L_F77=no + hardcode_shlibpath_var_F77=unsupported + link_all_deplibs_F77=unknown + hardcode_automatic_F77=no + module_cmds_F77= + module_expsym_cmds_F77= + always_export_symbols_F77=no + export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms_F77= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms_F77="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + # Just being paranoid about ensuring that cc_basename is set. + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs_F77=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_F77='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_F77='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_F77="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_F77= + fi + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs_F77=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_minus_L_F77=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + ld_shlibs_F77=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_F77=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_F77='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_F77=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, F77) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_F77='-L$libdir' + allow_undefined_flag_F77=unsupported + always_export_symbols_F77=no + enable_shared_with_static_runtimes_F77=yes + export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_F77='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_F77=no + fi + ;; + + interix[3-9]*) + hardcode_direct_F77=no + hardcode_shlibpath_var_F77=no + hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' + export_dynamic_flag_spec_F77='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_F77='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_F77='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | k*bsd*-gnu) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec_F77='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + whole_archive_flag_spec_F77='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec_F77='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + *) + tmp_sharedflag='-shared' ;; + esac + archive_cmds_F77='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test $supports_anon_versioning = yes; then + archive_expsym_cmds_F77='$echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + $echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + link_all_deplibs_F77=no + else + ld_shlibs_F77=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_F77='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs_F77=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_F77=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs_F77=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec_F77='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' + archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' + else + ld_shlibs_F77=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds_F77='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_F77=no + fi + ;; + esac + + if test "$ld_shlibs_F77" = no; then + runpath_var= + hardcode_libdir_flag_spec_F77= + export_dynamic_flag_spec_F77= + whole_archive_flag_spec_F77= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag_F77=unsupported + always_export_symbols_F77=yes + archive_expsym_cmds_F77='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L_F77=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct_F77=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds_F77='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_F77='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_F77='' + hardcode_direct_F77=yes + hardcode_libdir_separator_F77=':' + link_all_deplibs_F77=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct_F77=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_F77=yes + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_libdir_separator_F77= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols_F77=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_F77='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF + program main + + end +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_f77_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds_F77="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_F77='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_F77="-z nodefs" + archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF + program main + + end +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_f77_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_F77=' ${wl}-bernotok' + allow_undefined_flag_F77=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_F77='$convenience' + archive_cmds_need_lc_F77=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_minus_L_F77=yes + # see comment about different semantics on the GNU ld section + ld_shlibs_F77=no + ;; + + bsdi[45]*) + export_dynamic_flag_spec_F77=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec_F77=' ' + allow_undefined_flag_F77=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds_F77='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_From_new_cmds_F77='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds_F77='lib -OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path_F77='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes_F77=yes + ;; + + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[012]) + allow_undefined_flag_F77='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + allow_undefined_flag_F77='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + allow_undefined_flag_F77='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + allow_undefined_flag_F77='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + archive_cmds_need_lc_F77=no + hardcode_direct_F77=no + hardcode_automatic_F77=yes + hardcode_shlibpath_var_F77=unsupported + whole_archive_flag_spec_F77='' + link_all_deplibs_F77=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + archive_cmds_F77='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + module_cmds_F77='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds_F77='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring' + module_cmds_F77='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs_F77=no + ;; + esac + fi + ;; + + dgux*) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_shlibpath_var_F77=no + ;; + + freebsd1*) + ld_shlibs_F77=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=yes + hardcode_minus_L_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds_F77='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds_F77='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds_F77='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_F77=: + hardcode_direct_F77=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_F77=yes + export_dynamic_flag_spec_F77='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_F77='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_F77=: + + hardcode_direct_F77=yes + export_dynamic_flag_spec_F77='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_F77=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_F77=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_libdir_flag_spec_ld_F77='+b $libdir' + hardcode_direct_F77=no + hardcode_shlibpath_var_F77=no + ;; + *) + hardcode_direct_F77=yes + export_dynamic_flag_spec_F77='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_F77=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_F77='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_ld_F77='-rpath $libdir' + fi + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_F77=: + link_all_deplibs_F77=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds_F77='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + newsos6) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=yes + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_F77=: + hardcode_shlibpath_var_F77=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' + export_dynamic_flag_spec_F77='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_F77='-R$libdir' + ;; + *) + archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs_F77=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_minus_L_F77=yes + allow_undefined_flag_F77=unsupported + archive_cmds_F77='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_From_new_cmds_F77='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag_F77=' -expect_unresolved \*' + archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_F77=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag_F77=' -expect_unresolved \*' + archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_F77='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec_F77='-rpath $libdir' + fi + hardcode_libdir_separator_F77=: + ;; + + solaris*) + no_undefined_flag_F77=' -z text' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + wlarc='' + archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_shlibpath_var_F77=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec_F77='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec_F77='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs_F77=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds_F77='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_F77='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_direct_F77=yes + hardcode_minus_L_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds_F77='$CC -r -o $output$reload_objs' + hardcode_direct_F77=no + ;; + motorola) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var_F77=no + ;; + + sysv4.3*) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_F77=no + export_dynamic_flag_spec_F77='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_F77=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs_F77=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_F77='${wl}-z,text' + archive_cmds_need_lc_F77=no + hardcode_shlibpath_var_F77=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds_F77='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_F77='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_F77='${wl}-z,text' + allow_undefined_flag_F77='${wl}-z,nodefs' + archive_cmds_need_lc_F77=no + hardcode_shlibpath_var_F77=no + hardcode_libdir_flag_spec_F77='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator_F77=':' + link_all_deplibs_F77=yes + export_dynamic_flag_spec_F77='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds_F77='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_F77='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_shlibpath_var_F77=no + ;; + + *) + ld_shlibs_F77=no + ;; + esac + fi + +{ echo "$as_me:$LINENO: result: $ld_shlibs_F77" >&5 +echo "${ECHO_T}$ld_shlibs_F77" >&6; } +test "$ld_shlibs_F77" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_F77" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_F77=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_F77 in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6; } + $rm conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_F77 + pic_flag=$lt_prog_compiler_pic_F77 + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_F77 + allow_undefined_flag_F77= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc_F77=no + else + archive_cmds_need_lc_F77=yes + fi + allow_undefined_flag_F77=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + { echo "$as_me:$LINENO: result: $archive_cmds_need_lc_F77" >&5 +echo "${ECHO_T}$archive_cmds_need_lc_F77" >&6; } + ;; + esac + fi + ;; +esac + +{ echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6; } +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" + +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +{ echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6; } +hardcode_action_F77= +if test -n "$hardcode_libdir_flag_spec_F77" || \ + test -n "$runpath_var_F77" || \ + test "X$hardcode_automatic_F77" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct_F77" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, F77)" != no && + test "$hardcode_minus_L_F77" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_F77=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_F77=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_F77=unsupported +fi +{ echo "$as_me:$LINENO: result: $hardcode_action_F77" >&5 +echo "${ECHO_T}$hardcode_action_F77" >&6; } + +if test "$hardcode_action_F77" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_F77 \ + CC_F77 \ + LD_F77 \ + lt_prog_compiler_wl_F77 \ + lt_prog_compiler_pic_F77 \ + lt_prog_compiler_static_F77 \ + lt_prog_compiler_no_builtin_flag_F77 \ + export_dynamic_flag_spec_F77 \ + thread_safe_flag_spec_F77 \ + whole_archive_flag_spec_F77 \ + enable_shared_with_static_runtimes_F77 \ + old_archive_cmds_F77 \ + old_archive_from_new_cmds_F77 \ + predep_objects_F77 \ + postdep_objects_F77 \ + predeps_F77 \ + postdeps_F77 \ + compiler_lib_search_path_F77 \ + archive_cmds_F77 \ + archive_expsym_cmds_F77 \ + postinstall_cmds_F77 \ + postuninstall_cmds_F77 \ + old_archive_from_expsyms_cmds_F77 \ + allow_undefined_flag_F77 \ + no_undefined_flag_F77 \ + export_symbols_cmds_F77 \ + hardcode_libdir_flag_spec_F77 \ + hardcode_libdir_flag_spec_ld_F77 \ + hardcode_libdir_separator_F77 \ + hardcode_automatic_F77 \ + module_cmds_F77 \ + module_expsym_cmds_F77 \ + lt_cv_prog_compiler_c_o_F77 \ + fix_srcfile_path_F77 \ + exclude_expsyms_F77 \ + include_expsyms_F77; do + + case $var in + old_archive_cmds_F77 | \ + old_archive_from_new_cmds_F77 | \ + archive_cmds_F77 | \ + archive_expsym_cmds_F77 | \ + module_cmds_F77 | \ + module_expsym_cmds_F77 | \ + old_archive_from_expsyms_cmds_F77 | \ + export_symbols_cmds_F77 | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_F77 + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_F77 + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler_F77 + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_F77 + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_F77 + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_F77 + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_F77 +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_F77 + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_F77 + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_F77 + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_F77 + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_F77 + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_F77 + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_F77 +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_F77 + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_F77 + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_F77 +archive_expsym_cmds=$lt_archive_expsym_cmds_F77 +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_F77 +module_expsym_cmds=$lt_module_expsym_cmds_F77 + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_F77 + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_F77 + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_F77 + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_F77 + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_F77 + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_F77 + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_F77 + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_F77 + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_F77 + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_F77 + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_F77 + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_F77 + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_F77 + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_F77 + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_F77 + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_F77 + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_F77 + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_F77 + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_F77 + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_F77 + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + else + tagname="" + fi + ;; + + GCJ) + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +objext_GCJ=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* + + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${GCJ-"gcj"} +compiler=$CC +compiler_GCJ=$CC +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +archive_cmds_need_lc_GCJ=no + +old_archive_cmds_GCJ=$old_archive_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... + +lt_prog_compiler_no_builtin_flag_GCJ= + +if test "$GCC" = yes; then + lt_prog_compiler_no_builtin_flag_GCJ=' -fno-builtin' + + +{ echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:16836: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:16840: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag_GCJ="$lt_prog_compiler_no_builtin_flag_GCJ -fno-rtti -fno-exceptions" +else + : +fi + +fi + +lt_prog_compiler_wl_GCJ= +lt_prog_compiler_pic_GCJ= +lt_prog_compiler_static_GCJ= + +{ echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6; } + + if test "$GCC" = yes; then + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_static_GCJ='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_GCJ='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_GCJ='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic_GCJ='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_GCJ='-fno-common' + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared_GCJ=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_GCJ=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_GCJ='-fPIC' + ;; + esac + ;; + + *) + lt_prog_compiler_pic_GCJ='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl_GCJ='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_GCJ='-Bstatic' + else + lt_prog_compiler_static_GCJ='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + lt_prog_compiler_pic_GCJ='-qnocommon' + lt_prog_compiler_wl_GCJ='-Wl,' + ;; + esac + ;; + + mingw* | cygwin* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_GCJ='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl_GCJ='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_GCJ='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static_GCJ='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl_GCJ='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static_GCJ='-non_shared' + ;; + + newsos6) + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + icc* | ecc*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-fpic' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl_GCJ='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static_GCJ='-non_shared' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + lt_prog_compiler_wl_GCJ='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + lt_prog_compiler_wl_GCJ='' + ;; + esac + ;; + esac + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl_GCJ='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static_GCJ='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static_GCJ='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl_GCJ='-Qoption ld ';; + *) + lt_prog_compiler_wl_GCJ='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl_GCJ='-Qoption ld ' + lt_prog_compiler_pic_GCJ='-PIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic_GCJ='-Kconform_pic' + lt_prog_compiler_static_GCJ='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_can_build_shared_GCJ=no + ;; + + uts4*) + lt_prog_compiler_pic_GCJ='-pic' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared_GCJ=no + ;; + esac + fi + +{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_GCJ" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_GCJ" >&6; } + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_GCJ"; then + +{ echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works... $ECHO_C" >&6; } +if test "${lt_prog_compiler_pic_works_GCJ+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_pic_works_GCJ=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_GCJ" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:17126: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:17130: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_pic_works_GCJ=yes + fi + fi + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_GCJ" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_works_GCJ" >&6; } + +if test x"$lt_prog_compiler_pic_works_GCJ" = xyes; then + case $lt_prog_compiler_pic_GCJ in + "" | " "*) ;; + *) lt_prog_compiler_pic_GCJ=" $lt_prog_compiler_pic_GCJ" ;; + esac +else + lt_prog_compiler_pic_GCJ= + lt_prog_compiler_can_build_shared_GCJ=no +fi + +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_GCJ= + ;; + *) + lt_prog_compiler_pic_GCJ="$lt_prog_compiler_pic_GCJ" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_GCJ eval lt_tmp_static_flag=\"$lt_prog_compiler_static_GCJ\" +{ echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6; } +if test "${lt_prog_compiler_static_works_GCJ+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_static_works_GCJ=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_static_works_GCJ=yes + fi + else + lt_prog_compiler_static_works_GCJ=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works_GCJ" >&5 +echo "${ECHO_T}$lt_prog_compiler_static_works_GCJ" >&6; } + +if test x"$lt_prog_compiler_static_works_GCJ" = xyes; then + : +else + lt_prog_compiler_static_GCJ= +fi + + +{ echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_c_o_GCJ+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o_GCJ=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:17230: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:17234: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_GCJ=yes + fi + fi + chmod u+w . 2>&5 + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_GCJ" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o_GCJ" >&6; } + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_GCJ" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6; } + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6; } + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +{ echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6; } + + runpath_var= + allow_undefined_flag_GCJ= + enable_shared_with_static_runtimes_GCJ=no + archive_cmds_GCJ= + archive_expsym_cmds_GCJ= + old_archive_From_new_cmds_GCJ= + old_archive_from_expsyms_cmds_GCJ= + export_dynamic_flag_spec_GCJ= + whole_archive_flag_spec_GCJ= + thread_safe_flag_spec_GCJ= + hardcode_libdir_flag_spec_GCJ= + hardcode_libdir_flag_spec_ld_GCJ= + hardcode_libdir_separator_GCJ= + hardcode_direct_GCJ=no + hardcode_minus_L_GCJ=no + hardcode_shlibpath_var_GCJ=unsupported + link_all_deplibs_GCJ=unknown + hardcode_automatic_GCJ=no + module_cmds_GCJ= + module_expsym_cmds_GCJ= + always_export_symbols_GCJ=no + export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms_GCJ= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms_GCJ="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + # Just being paranoid about ensuring that cc_basename is set. + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs_GCJ=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_GCJ='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_GCJ='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_GCJ="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_GCJ= + fi + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs_GCJ=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_minus_L_GCJ=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + ld_shlibs_GCJ=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_GCJ=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_GCJ='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_GCJ=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, GCJ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_GCJ='-L$libdir' + allow_undefined_flag_GCJ=unsupported + always_export_symbols_GCJ=no + enable_shared_with_static_runtimes_GCJ=yes + export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_GCJ='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_GCJ=no + fi + ;; + + interix[3-9]*) + hardcode_direct_GCJ=no + hardcode_shlibpath_var_GCJ=no + hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' + export_dynamic_flag_spec_GCJ='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_GCJ='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_GCJ='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | k*bsd*-gnu) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec_GCJ='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + whole_archive_flag_spec_GCJ='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec_GCJ='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + *) + tmp_sharedflag='-shared' ;; + esac + archive_cmds_GCJ='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test $supports_anon_versioning = yes; then + archive_expsym_cmds_GCJ='$echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + $echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + link_all_deplibs_GCJ=no + else + ld_shlibs_GCJ=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_GCJ='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs_GCJ=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_GCJ=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs_GCJ=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec_GCJ='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' + archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' + else + ld_shlibs_GCJ=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds_GCJ='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_GCJ=no + fi + ;; + esac + + if test "$ld_shlibs_GCJ" = no; then + runpath_var= + hardcode_libdir_flag_spec_GCJ= + export_dynamic_flag_spec_GCJ= + whole_archive_flag_spec_GCJ= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag_GCJ=unsupported + always_export_symbols_GCJ=yes + archive_expsym_cmds_GCJ='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L_GCJ=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct_GCJ=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds_GCJ='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_GCJ='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_GCJ='' + hardcode_direct_GCJ=yes + hardcode_libdir_separator_GCJ=':' + link_all_deplibs_GCJ=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct_GCJ=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_GCJ=yes + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_libdir_separator_GCJ= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols_GCJ=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_GCJ='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds_GCJ="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_GCJ='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_GCJ="-z nodefs" + archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_GCJ=' ${wl}-bernotok' + allow_undefined_flag_GCJ=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_GCJ='$convenience' + archive_cmds_need_lc_GCJ=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_minus_L_GCJ=yes + # see comment about different semantics on the GNU ld section + ld_shlibs_GCJ=no + ;; + + bsdi[45]*) + export_dynamic_flag_spec_GCJ=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec_GCJ=' ' + allow_undefined_flag_GCJ=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds_GCJ='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_From_new_cmds_GCJ='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds_GCJ='lib -OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path_GCJ='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes_GCJ=yes + ;; + + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[012]) + allow_undefined_flag_GCJ='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + allow_undefined_flag_GCJ='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + allow_undefined_flag_GCJ='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + allow_undefined_flag_GCJ='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + archive_cmds_need_lc_GCJ=no + hardcode_direct_GCJ=no + hardcode_automatic_GCJ=yes + hardcode_shlibpath_var_GCJ=unsupported + whole_archive_flag_spec_GCJ='' + link_all_deplibs_GCJ=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + archive_cmds_GCJ='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + module_cmds_GCJ='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds_GCJ='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring' + module_cmds_GCJ='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs_GCJ=no + ;; + esac + fi + ;; + + dgux*) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_shlibpath_var_GCJ=no + ;; + + freebsd1*) + ld_shlibs_GCJ=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=yes + hardcode_minus_L_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds_GCJ='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds_GCJ='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds_GCJ='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + hardcode_direct_GCJ=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_GCJ=yes + export_dynamic_flag_spec_GCJ='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_GCJ='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + + hardcode_direct_GCJ=yes + export_dynamic_flag_spec_GCJ='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_GCJ=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_libdir_flag_spec_ld_GCJ='+b $libdir' + hardcode_direct_GCJ=no + hardcode_shlibpath_var_GCJ=no + ;; + *) + hardcode_direct_GCJ=yes + export_dynamic_flag_spec_GCJ='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_GCJ=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_GCJ='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_ld_GCJ='-rpath $libdir' + fi + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + link_all_deplibs_GCJ=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds_GCJ='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + newsos6) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=yes + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + hardcode_shlibpath_var_GCJ=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' + export_dynamic_flag_spec_GCJ='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_GCJ='-R$libdir' + ;; + *) + archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs_GCJ=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_minus_L_GCJ=yes + allow_undefined_flag_GCJ=unsupported + archive_cmds_GCJ='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_From_new_cmds_GCJ='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag_GCJ=' -expect_unresolved \*' + archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag_GCJ=' -expect_unresolved \*' + archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_GCJ='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec_GCJ='-rpath $libdir' + fi + hardcode_libdir_separator_GCJ=: + ;; + + solaris*) + no_undefined_flag_GCJ=' -z text' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + wlarc='' + archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_shlibpath_var_GCJ=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec_GCJ='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec_GCJ='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs_GCJ=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds_GCJ='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_GCJ='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_direct_GCJ=yes + hardcode_minus_L_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds_GCJ='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds_GCJ='$CC -r -o $output$reload_objs' + hardcode_direct_GCJ=no + ;; + motorola) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var_GCJ=no + ;; + + sysv4.3*) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_GCJ=no + export_dynamic_flag_spec_GCJ='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_GCJ=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs_GCJ=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_GCJ='${wl}-z,text' + archive_cmds_need_lc_GCJ=no + hardcode_shlibpath_var_GCJ=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds_GCJ='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_GCJ='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_GCJ='${wl}-z,text' + allow_undefined_flag_GCJ='${wl}-z,nodefs' + archive_cmds_need_lc_GCJ=no + hardcode_shlibpath_var_GCJ=no + hardcode_libdir_flag_spec_GCJ='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator_GCJ=':' + link_all_deplibs_GCJ=yes + export_dynamic_flag_spec_GCJ='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds_GCJ='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_GCJ='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_shlibpath_var_GCJ=no + ;; + + *) + ld_shlibs_GCJ=no + ;; + esac + fi + +{ echo "$as_me:$LINENO: result: $ld_shlibs_GCJ" >&5 +echo "${ECHO_T}$ld_shlibs_GCJ" >&6; } +test "$ld_shlibs_GCJ" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_GCJ" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_GCJ=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_GCJ in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6; } + $rm conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_GCJ + pic_flag=$lt_prog_compiler_pic_GCJ + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_GCJ + allow_undefined_flag_GCJ= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc_GCJ=no + else + archive_cmds_need_lc_GCJ=yes + fi + allow_undefined_flag_GCJ=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + { echo "$as_me:$LINENO: result: $archive_cmds_need_lc_GCJ" >&5 +echo "${ECHO_T}$archive_cmds_need_lc_GCJ" >&6; } + ;; + esac + fi + ;; +esac + +{ echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6; } +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" + +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +{ echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6; } +hardcode_action_GCJ= +if test -n "$hardcode_libdir_flag_spec_GCJ" || \ + test -n "$runpath_var_GCJ" || \ + test "X$hardcode_automatic_GCJ" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct_GCJ" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, GCJ)" != no && + test "$hardcode_minus_L_GCJ" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_GCJ=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_GCJ=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_GCJ=unsupported +fi +{ echo "$as_me:$LINENO: result: $hardcode_action_GCJ" >&5 +echo "${ECHO_T}$hardcode_action_GCJ" >&6; } + +if test "$hardcode_action_GCJ" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_GCJ \ + CC_GCJ \ + LD_GCJ \ + lt_prog_compiler_wl_GCJ \ + lt_prog_compiler_pic_GCJ \ + lt_prog_compiler_static_GCJ \ + lt_prog_compiler_no_builtin_flag_GCJ \ + export_dynamic_flag_spec_GCJ \ + thread_safe_flag_spec_GCJ \ + whole_archive_flag_spec_GCJ \ + enable_shared_with_static_runtimes_GCJ \ + old_archive_cmds_GCJ \ + old_archive_from_new_cmds_GCJ \ + predep_objects_GCJ \ + postdep_objects_GCJ \ + predeps_GCJ \ + postdeps_GCJ \ + compiler_lib_search_path_GCJ \ + archive_cmds_GCJ \ + archive_expsym_cmds_GCJ \ + postinstall_cmds_GCJ \ + postuninstall_cmds_GCJ \ + old_archive_from_expsyms_cmds_GCJ \ + allow_undefined_flag_GCJ \ + no_undefined_flag_GCJ \ + export_symbols_cmds_GCJ \ + hardcode_libdir_flag_spec_GCJ \ + hardcode_libdir_flag_spec_ld_GCJ \ + hardcode_libdir_separator_GCJ \ + hardcode_automatic_GCJ \ + module_cmds_GCJ \ + module_expsym_cmds_GCJ \ + lt_cv_prog_compiler_c_o_GCJ \ + fix_srcfile_path_GCJ \ + exclude_expsyms_GCJ \ + include_expsyms_GCJ; do + + case $var in + old_archive_cmds_GCJ | \ + old_archive_from_new_cmds_GCJ | \ + archive_cmds_GCJ | \ + archive_expsym_cmds_GCJ | \ + module_cmds_GCJ | \ + module_expsym_cmds_GCJ | \ + old_archive_from_expsyms_cmds_GCJ | \ + export_symbols_cmds_GCJ | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_GCJ + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_GCJ + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler_GCJ + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_GCJ + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_GCJ + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_GCJ + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_GCJ +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_GCJ + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_GCJ + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_GCJ + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_GCJ + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_GCJ + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_GCJ + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_GCJ +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_GCJ + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_GCJ + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_GCJ +archive_expsym_cmds=$lt_archive_expsym_cmds_GCJ +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_GCJ +module_expsym_cmds=$lt_module_expsym_cmds_GCJ + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_GCJ + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_GCJ + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_GCJ + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_GCJ + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_GCJ + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_GCJ + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_GCJ + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_GCJ + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_GCJ + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_GCJ + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_GCJ + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_GCJ + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_GCJ + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_GCJ + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_GCJ + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_GCJ + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_GCJ + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_GCJ + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_GCJ + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_GCJ + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + else + tagname="" + fi + ;; + + RC) + + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +objext_RC=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* + + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${RC-"windres"} +compiler=$CC +compiler_RC=$CC +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + +lt_cv_prog_compiler_c_o_RC=yes + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_RC \ + CC_RC \ + LD_RC \ + lt_prog_compiler_wl_RC \ + lt_prog_compiler_pic_RC \ + lt_prog_compiler_static_RC \ + lt_prog_compiler_no_builtin_flag_RC \ + export_dynamic_flag_spec_RC \ + thread_safe_flag_spec_RC \ + whole_archive_flag_spec_RC \ + enable_shared_with_static_runtimes_RC \ + old_archive_cmds_RC \ + old_archive_from_new_cmds_RC \ + predep_objects_RC \ + postdep_objects_RC \ + predeps_RC \ + postdeps_RC \ + compiler_lib_search_path_RC \ + archive_cmds_RC \ + archive_expsym_cmds_RC \ + postinstall_cmds_RC \ + postuninstall_cmds_RC \ + old_archive_from_expsyms_cmds_RC \ + allow_undefined_flag_RC \ + no_undefined_flag_RC \ + export_symbols_cmds_RC \ + hardcode_libdir_flag_spec_RC \ + hardcode_libdir_flag_spec_ld_RC \ + hardcode_libdir_separator_RC \ + hardcode_automatic_RC \ + module_cmds_RC \ + module_expsym_cmds_RC \ + lt_cv_prog_compiler_c_o_RC \ + fix_srcfile_path_RC \ + exclude_expsyms_RC \ + include_expsyms_RC; do + + case $var in + old_archive_cmds_RC | \ + old_archive_from_new_cmds_RC | \ + archive_cmds_RC | \ + archive_expsym_cmds_RC | \ + module_cmds_RC | \ + module_expsym_cmds_RC | \ + old_archive_from_expsyms_cmds_RC | \ + export_symbols_cmds_RC | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_RC + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_RC + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler_RC + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_RC + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_RC + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_RC + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_RC +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_RC + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_RC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_RC + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_RC + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_RC + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_RC + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_RC +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_RC + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_RC + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_RC +archive_expsym_cmds=$lt_archive_expsym_cmds_RC +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_RC +module_expsym_cmds=$lt_module_expsym_cmds_RC + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_RC + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_RC + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_RC + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_RC + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_RC + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_RC + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_RC + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_RC + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_RC + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_RC + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_RC + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_RC + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_RC + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_RC + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_RC + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_RC + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_RC + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_RC + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_RC + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_RC + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + ;; + + *) + { { echo "$as_me:$LINENO: error: Unsupported tag name: $tagname" >&5 +echo "$as_me: error: Unsupported tag name: $tagname" >&2;} + { (exit 1); exit 1; }; } + ;; + esac + + # Append the new tag name to the list of available tags. + if test -n "$tagname" ; then + available_tags="$available_tags $tagname" + fi + fi + done + IFS="$lt_save_ifs" + + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + else + rm -f "${ofile}T" + { { echo "$as_me:$LINENO: error: unable to update list of available tagged configurations." >&5 +echo "$as_me: error: unable to update list of available tagged configurations." >&2;} + { (exit 1); exit 1; }; } + fi +fi + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + +# Prevent multiple expansion + + + + + + + + + + + + + + + + + + + + + + + + + + + +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do + as_ac_Header=`echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_hdr that defines DIR" >&5 +echo $ECHO_N "checking for $ac_hdr that defines DIR... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include <$ac_hdr> + +int +main () +{ +if ((DIR *) 0) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 +_ACEOF + +ac_header_dirent=$ac_hdr; break +fi + +done +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then + { echo "$as_me:$LINENO: checking for library containing opendir" >&5 +echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6; } +if test "${ac_cv_search_opendir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_func_search_save_LIBS=$LIBS +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char opendir (); +int +main () +{ +return opendir (); + ; + return 0; +} +_ACEOF +for ac_lib in '' dir; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_search_opendir=$ac_res +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext + if test "${ac_cv_search_opendir+set}" = set; then + break +fi +done +if test "${ac_cv_search_opendir+set}" = set; then + : +else + ac_cv_search_opendir=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5 +echo "${ECHO_T}$ac_cv_search_opendir" >&6; } +ac_res=$ac_cv_search_opendir +if test "$ac_res" != no; then + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +else + { echo "$as_me:$LINENO: checking for library containing opendir" >&5 +echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6; } +if test "${ac_cv_search_opendir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_func_search_save_LIBS=$LIBS +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char opendir (); +int +main () +{ +return opendir (); + ; + return 0; +} +_ACEOF +for ac_lib in '' x; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_search_opendir=$ac_res +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext + if test "${ac_cv_search_opendir+set}" = set; then + break +fi +done +if test "${ac_cv_search_opendir+set}" = set; then + : +else + ac_cv_search_opendir=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5 +echo "${ECHO_T}$ac_cv_search_opendir" >&6; } +ac_res=$ac_cv_search_opendir +if test "$ac_res" != no; then + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +fi + +# Check whether --enable-ltdl-install was given. +if test "${enable_ltdl_install+set}" = set; then + enableval=$enable_ltdl_install; +fi + + + if test x"${enable_ltdl_install-no}" != xno; then + INSTALL_LTDL_TRUE= + INSTALL_LTDL_FALSE='#' +else + INSTALL_LTDL_TRUE='#' + INSTALL_LTDL_FALSE= +fi + + if test x"${enable_ltdl_convenience-no}" != xno; then + CONVENIENCE_LTDL_TRUE= + CONVENIENCE_LTDL_FALSE='#' +else + CONVENIENCE_LTDL_TRUE='#' + CONVENIENCE_LTDL_FALSE= +fi + + + +{ echo "$as_me:$LINENO: checking which extension is used for loadable modules" >&5 +echo $ECHO_N "checking which extension is used for loadable modules... $ECHO_C" >&6; } +if test "${libltdl_cv_shlibext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + +module=yes +eval libltdl_cv_shlibext=$shrext_cmds + +fi +{ echo "$as_me:$LINENO: result: $libltdl_cv_shlibext" >&5 +echo "${ECHO_T}$libltdl_cv_shlibext" >&6; } +if test -n "$libltdl_cv_shlibext"; then + +cat >>confdefs.h <<_ACEOF +#define LTDL_SHLIB_EXT "$libltdl_cv_shlibext" +_ACEOF + +fi + + +{ echo "$as_me:$LINENO: checking which variable specifies run-time library path" >&5 +echo $ECHO_N "checking which variable specifies run-time library path... $ECHO_C" >&6; } +if test "${libltdl_cv_shlibpath_var+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + libltdl_cv_shlibpath_var="$shlibpath_var" +fi +{ echo "$as_me:$LINENO: result: $libltdl_cv_shlibpath_var" >&5 +echo "${ECHO_T}$libltdl_cv_shlibpath_var" >&6; } +if test -n "$libltdl_cv_shlibpath_var"; then + +cat >>confdefs.h <<_ACEOF +#define LTDL_SHLIBPATH_VAR "$libltdl_cv_shlibpath_var" +_ACEOF + +fi + + +{ echo "$as_me:$LINENO: checking for the default library search path" >&5 +echo $ECHO_N "checking for the default library search path... $ECHO_C" >&6; } +if test "${libltdl_cv_sys_search_path+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + libltdl_cv_sys_search_path="$sys_lib_dlsearch_path_spec" +fi +{ echo "$as_me:$LINENO: result: $libltdl_cv_sys_search_path" >&5 +echo "${ECHO_T}$libltdl_cv_sys_search_path" >&6; } +if test -n "$libltdl_cv_sys_search_path"; then + sys_search_path= + for dir in $libltdl_cv_sys_search_path; do + if test -z "$sys_search_path"; then + sys_search_path="$dir" + else + sys_search_path="$sys_search_path$PATH_SEPARATOR$dir" + fi + done + +cat >>confdefs.h <<_ACEOF +#define LTDL_SYSSEARCHPATH "$sys_search_path" +_ACEOF + +fi + +{ echo "$as_me:$LINENO: checking for objdir" >&5 +echo $ECHO_N "checking for objdir... $ECHO_C" >&6; } +if test "${libltdl_cv_objdir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + libltdl_cv_objdir="$objdir" + if test -n "$objdir"; then + : + else + rm -f .libs 2>/dev/null + mkdir .libs 2>/dev/null + if test -d .libs; then + libltdl_cv_objdir=.libs + else + # MS-DOS does not allow filenames that begin with a dot. + libltdl_cv_objdir=_libs + fi + rmdir .libs 2>/dev/null + fi + +fi +{ echo "$as_me:$LINENO: result: $libltdl_cv_objdir" >&5 +echo "${ECHO_T}$libltdl_cv_objdir" >&6; } + +cat >>confdefs.h <<_ACEOF +#define LTDL_OBJDIR "$libltdl_cv_objdir/" +_ACEOF + + + +{ echo "$as_me:$LINENO: checking whether libtool supports -dlopen/-dlpreopen" >&5 +echo $ECHO_N "checking whether libtool supports -dlopen/-dlpreopen... $ECHO_C" >&6; } +if test "${libltdl_cv_preloaded_symbols+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$lt_cv_sys_global_symbol_pipe"; then + libltdl_cv_preloaded_symbols=yes + else + libltdl_cv_preloaded_symbols=no + fi + +fi +{ echo "$as_me:$LINENO: result: $libltdl_cv_preloaded_symbols" >&5 +echo "${ECHO_T}$libltdl_cv_preloaded_symbols" >&6; } +if test x"$libltdl_cv_preloaded_symbols" = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_PRELOADED_SYMBOLS 1 +_ACEOF + +fi + +LIBADD_DL= + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ echo "$as_me:$LINENO: checking for shl_load" >&5 +echo $ECHO_N "checking for shl_load... $ECHO_C" >&6; } +if test "${ac_cv_func_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define shl_load to an innocuous variant, in case declares shl_load. + For example, HP-UX 11i declares gettimeofday. */ +#define shl_load innocuous_shl_load + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char shl_load (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef shl_load + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_shl_load || defined __stub___shl_load +choke me +#endif + +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_func_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_shl_load=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5 +echo "${ECHO_T}$ac_cv_func_shl_load" >&6; } +if test $ac_cv_func_shl_load = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SHL_LOAD 1 +_ACEOF + +else + { echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 +echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6; } +if test "${ac_cv_lib_dld_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_dld_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dld_shl_load=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6; } +if test $ac_cv_lib_dld_shl_load = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SHL_LOAD 1 +_ACEOF + + LIBADD_DL="$LIBADD_DL -ldld" +else + { echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6; } +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dl_dlopen=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6; } +if test $ac_cv_lib_dl_dlopen = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBDL 1 +_ACEOF + + LIBADD_DL="-ldl" libltdl_cv_lib_dl_dlopen="yes" +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#if HAVE_DLFCN_H +# include +#endif + +int +main () +{ +dlopen(0, 0); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBDL 1 +_ACEOF + libltdl_cv_func_dlopen="yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5 +echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6; } +if test "${ac_cv_lib_svld_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_svld_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_svld_dlopen=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6; } +if test $ac_cv_lib_svld_dlopen = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBDL 1 +_ACEOF + + LIBADD_DL="-lsvld" libltdl_cv_func_dlopen="yes" +else + { echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5 +echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6; } +if test "${ac_cv_lib_dld_dld_link+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_dld_dld_link=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dld_dld_link=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6; } +if test $ac_cv_lib_dld_dld_link = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DLD 1 +_ACEOF + + LIBADD_DL="$LIBADD_DL -ldld" +else + { echo "$as_me:$LINENO: checking for _dyld_func_lookup" >&5 +echo $ECHO_N "checking for _dyld_func_lookup... $ECHO_C" >&6; } +if test "${ac_cv_func__dyld_func_lookup+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define _dyld_func_lookup to an innocuous variant, in case declares _dyld_func_lookup. + For example, HP-UX 11i declares gettimeofday. */ +#define _dyld_func_lookup innocuous__dyld_func_lookup + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char _dyld_func_lookup (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef _dyld_func_lookup + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char _dyld_func_lookup (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub__dyld_func_lookup || defined __stub____dyld_func_lookup +choke me +#endif + +int +main () +{ +return _dyld_func_lookup (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_func__dyld_func_lookup=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func__dyld_func_lookup=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_func__dyld_func_lookup" >&5 +echo "${ECHO_T}$ac_cv_func__dyld_func_lookup" >&6; } +if test $ac_cv_func__dyld_func_lookup = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DYLD 1 +_ACEOF + +fi + + +fi + + +fi + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + +fi + + +fi + + +fi + + +if test x"$libltdl_cv_func_dlopen" = xyes || test x"$libltdl_cv_lib_dl_dlopen" = xyes +then + lt_save_LIBS="$LIBS" + LIBS="$LIBS $LIBADD_DL" + +for ac_func in dlerror +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + LIBS="$lt_save_LIBS" +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +{ echo "$as_me:$LINENO: checking for _ prefix in compiled symbols" >&5 +echo $ECHO_N "checking for _ prefix in compiled symbols... $ECHO_C" >&6; } +if test "${ac_cv_sys_symbol_underscore+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_sys_symbol_underscore=no + cat > conftest.$ac_ext <&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Now try to grab the symbols. + ac_nlist=conftest.nm + if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist\"") >&5 + (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s "$ac_nlist"; then + # See whether the symbols have a leading underscore. + if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then + ac_cv_sys_symbol_underscore=yes + else + if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then + : + else + echo "configure: cannot find nm_test_func in $ac_nlist" >&5 + fi + fi + else + echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "configure: failed program was:" >&5 + cat conftest.c >&5 + fi + rm -rf conftest* + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_sys_symbol_underscore" >&5 +echo "${ECHO_T}$ac_cv_sys_symbol_underscore" >&6; } + + +if test x"$ac_cv_sys_symbol_underscore" = xyes; then + if test x"$libltdl_cv_func_dlopen" = xyes || + test x"$libltdl_cv_lib_dl_dlopen" = xyes ; then + { echo "$as_me:$LINENO: checking whether we have to add an underscore for dlsym" >&5 +echo $ECHO_N "checking whether we have to add an underscore for dlsym... $ECHO_C" >&6; } +if test "${libltdl_cv_need_uscore+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + libltdl_cv_need_uscore=unknown + save_LIBS="$LIBS" + LIBS="$LIBS $LIBADD_DL" + if test "$cross_compiling" = yes; then : + libltdl_cv_need_uscore=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + exit (status); +} +EOF + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) libltdl_cv_need_uscore=no ;; + x$lt_dlneed_uscore) libltdl_cv_need_uscore=yes ;; + x$lt_dlunknown|x*) ;; + esac + else : + # compilation failed + + fi +fi +rm -fr conftest* + + LIBS="$save_LIBS" + +fi +{ echo "$as_me:$LINENO: result: $libltdl_cv_need_uscore" >&5 +echo "${ECHO_T}$libltdl_cv_need_uscore" >&6; } + fi +fi + +if test x"$libltdl_cv_need_uscore" = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define NEED_USCORE 1 +_ACEOF + +fi + + +{ echo "$as_me:$LINENO: checking whether deplibs are loaded by dlopen" >&5 +echo $ECHO_N "checking whether deplibs are loaded by dlopen... $ECHO_C" >&6; } +if test "${libltdl_cv_sys_dlopen_deplibs+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # PORTME does your system automatically load deplibs for dlopen? + # or its logical equivalent (e.g. shl_load for HP-UX < 11) + # For now, we just catch OSes we know something about -- in the + # future, we'll try test this programmatically. + libltdl_cv_sys_dlopen_deplibs=unknown + case "$host_os" in + aix3*|aix4.1.*|aix4.2.*) + # Unknown whether this is true for these versions of AIX, but + # we want this `case' here to explicitly catch those versions. + libltdl_cv_sys_dlopen_deplibs=unknown + ;; + aix[45]*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + darwin*) + # Assuming the user has installed a libdl from somewhere, this is true + # If you are looking for one http://www.opendarwin.org/projects/dlcompat + libltdl_cv_sys_dlopen_deplibs=yes + ;; + freebsd* | dragonfly*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + gnu* | linux* | k*bsd*-gnu) + # GNU and its variants, using gnu ld.so (Glibc) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + hpux10*|hpux11*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + interix*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + irix[12345]*|irix6.[01]*) + # Catch all versions of IRIX before 6.2, and indicate that we don't + # know how it worked for any of those versions. + libltdl_cv_sys_dlopen_deplibs=unknown + ;; + irix*) + # The case above catches anything before 6.2, and it's known that + # at 6.2 and later dlopen does load deplibs. + libltdl_cv_sys_dlopen_deplibs=yes + ;; + netbsd* | netbsdelf*-gnu) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + openbsd*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + osf[1234]*) + # dlopen did load deplibs (at least at 4.x), but until the 5.x series, + # it did *not* use an RPATH in a shared library to find objects the + # library depends on, so we explictly say `no'. + libltdl_cv_sys_dlopen_deplibs=no + ;; + osf5.0|osf5.0a|osf5.1) + # dlopen *does* load deplibs and with the right loader patch applied + # it even uses RPATH in a shared library to search for shared objects + # that the library depends on, but there's no easy way to know if that + # patch is installed. Since this is the case, all we can really + # say is unknown -- it depends on the patch being installed. If + # it is, this changes to `yes'. Without it, it would be `no'. + libltdl_cv_sys_dlopen_deplibs=unknown + ;; + osf*) + # the two cases above should catch all versions of osf <= 5.1. Read + # the comments above for what we know about them. + # At > 5.1, deplibs are loaded *and* any RPATH in a shared library + # is used to find them so we can finally say `yes'. + libltdl_cv_sys_dlopen_deplibs=yes + ;; + solaris*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + esac + +fi +{ echo "$as_me:$LINENO: result: $libltdl_cv_sys_dlopen_deplibs" >&5 +echo "${ECHO_T}$libltdl_cv_sys_dlopen_deplibs" >&6; } +if test "$libltdl_cv_sys_dlopen_deplibs" != yes; then + +cat >>confdefs.h <<\_ACEOF +#define LTDL_DLOPEN_DEPLIBS 1 +_ACEOF + +fi + + +for ac_header in argz.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ---------------------------------- ## +## Report this to bug-libtool@gnu.org ## +## ---------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +{ echo "$as_me:$LINENO: checking for error_t" >&5 +echo $ECHO_N "checking for error_t... $ECHO_C" >&6; } +if test "${ac_cv_type_error_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#if HAVE_ARGZ_H +# include +#endif + +typedef error_t ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_error_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_error_t=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_error_t" >&5 +echo "${ECHO_T}$ac_cv_type_error_t" >&6; } +if test $ac_cv_type_error_t = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_ERROR_T 1 +_ACEOF + + +else + +cat >>confdefs.h <<\_ACEOF +#define error_t int +_ACEOF + +fi + + + + + + + +for ac_func in argz_append argz_create_sep argz_insert argz_next argz_stringify +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + + + + + + + + + + + + + + + + + + + + + + + + + + +for ac_header in assert.h ctype.h errno.h malloc.h memory.h stdlib.h \ + stdio.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ---------------------------------- ## +## Report this to bug-libtool@gnu.org ## +## ---------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + +for ac_header in dl.h sys/dl.h dld.h mach-o/dyld.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ---------------------------------- ## +## Report this to bug-libtool@gnu.org ## +## ---------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +for ac_header in string.h strings.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ---------------------------------- ## +## Report this to bug-libtool@gnu.org ## +## ---------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + break +fi + +done + + + + +for ac_func in strchr index +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + break +fi +done + + + +for ac_func in strrchr rindex +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + break +fi +done + + + +for ac_func in memcpy bcopy +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + break +fi +done + + + +for ac_func in memmove strcmp +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + + +for ac_func in closedir opendir readdir +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + + +## -------- ## +## Outputs. ## +## -------- ## +ac_config_files="$ac_config_files Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { echo "$as_me:$LINENO: updating cache $cache_file" >&5 +echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 +echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${INSTALL_LTDL_TRUE}" && test -z "${INSTALL_LTDL_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"INSTALL_LTDL\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"INSTALL_LTDL\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${CONVENIENCE_LTDL_TRUE}" && test -z "${CONVENIENCE_LTDL_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"CONVENIENCE_LTDL\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"CONVENIENCE_LTDL\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 + +# Save the log message, to keep $[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by libltdl $as_me 1.2, which was +generated by GNU Autoconf 2.61. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +libltdl config.status 1.2 +configured by $0, generated by GNU Autoconf 2.61, + with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2006 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + { echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + CONFIG_SHELL=$SHELL + export CONFIG_SHELL + exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h:config-h.in" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +# +# Set up the sed scripts for CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "$CONFIG_FILES"; then + +_ACEOF + + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF +SHELL!$SHELL$ac_delim +PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim +PACKAGE_NAME!$PACKAGE_NAME$ac_delim +PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim +PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim +PACKAGE_STRING!$PACKAGE_STRING$ac_delim +PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim +exec_prefix!$exec_prefix$ac_delim +prefix!$prefix$ac_delim +program_transform_name!$program_transform_name$ac_delim +bindir!$bindir$ac_delim +sbindir!$sbindir$ac_delim +libexecdir!$libexecdir$ac_delim +datarootdir!$datarootdir$ac_delim +datadir!$datadir$ac_delim +sysconfdir!$sysconfdir$ac_delim +sharedstatedir!$sharedstatedir$ac_delim +localstatedir!$localstatedir$ac_delim +includedir!$includedir$ac_delim +oldincludedir!$oldincludedir$ac_delim +docdir!$docdir$ac_delim +infodir!$infodir$ac_delim +htmldir!$htmldir$ac_delim +dvidir!$dvidir$ac_delim +pdfdir!$pdfdir$ac_delim +psdir!$psdir$ac_delim +libdir!$libdir$ac_delim +localedir!$localedir$ac_delim +mandir!$mandir$ac_delim +DEFS!$DEFS$ac_delim +ECHO_C!$ECHO_C$ac_delim +ECHO_N!$ECHO_N$ac_delim +ECHO_T!$ECHO_T$ac_delim +LIBS!$LIBS$ac_delim +build_alias!$build_alias$ac_delim +host_alias!$host_alias$ac_delim +target_alias!$target_alias$ac_delim +INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim +INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim +INSTALL_DATA!$INSTALL_DATA$ac_delim +am__isrc!$am__isrc$ac_delim +CYGPATH_W!$CYGPATH_W$ac_delim +PACKAGE!$PACKAGE$ac_delim +VERSION!$VERSION$ac_delim +ACLOCAL!$ACLOCAL$ac_delim +AUTOCONF!$AUTOCONF$ac_delim +AUTOMAKE!$AUTOMAKE$ac_delim +AUTOHEADER!$AUTOHEADER$ac_delim +MAKEINFO!$MAKEINFO$ac_delim +install_sh!$install_sh$ac_delim +STRIP!$STRIP$ac_delim +INSTALL_STRIP_PROGRAM!$INSTALL_STRIP_PROGRAM$ac_delim +mkdir_p!$mkdir_p$ac_delim +AWK!$AWK$ac_delim +SET_MAKE!$SET_MAKE$ac_delim +am__leading_dot!$am__leading_dot$ac_delim +AMTAR!$AMTAR$ac_delim +am__tar!$am__tar$ac_delim +am__untar!$am__untar$ac_delim +CC!$CC$ac_delim +CFLAGS!$CFLAGS$ac_delim +LDFLAGS!$LDFLAGS$ac_delim +CPPFLAGS!$CPPFLAGS$ac_delim +ac_ct_CC!$ac_ct_CC$ac_delim +EXEEXT!$EXEEXT$ac_delim +OBJEXT!$OBJEXT$ac_delim +DEPDIR!$DEPDIR$ac_delim +am__include!$am__include$ac_delim +am__quote!$am__quote$ac_delim +AMDEP_TRUE!$AMDEP_TRUE$ac_delim +AMDEP_FALSE!$AMDEP_FALSE$ac_delim +AMDEPBACKSLASH!$AMDEPBACKSLASH$ac_delim +CCDEPMODE!$CCDEPMODE$ac_delim +am__fastdepCC_TRUE!$am__fastdepCC_TRUE$ac_delim +am__fastdepCC_FALSE!$am__fastdepCC_FALSE$ac_delim +build!$build$ac_delim +build_cpu!$build_cpu$ac_delim +build_vendor!$build_vendor$ac_delim +build_os!$build_os$ac_delim +host!$host$ac_delim +host_cpu!$host_cpu$ac_delim +host_vendor!$host_vendor$ac_delim +host_os!$host_os$ac_delim +SED!$SED$ac_delim +GREP!$GREP$ac_delim +EGREP!$EGREP$ac_delim +LN_S!$LN_S$ac_delim +ECHO!$ECHO$ac_delim +AR!$AR$ac_delim +RANLIB!$RANLIB$ac_delim +DLLTOOL!$DLLTOOL$ac_delim +AS!$AS$ac_delim +OBJDUMP!$OBJDUMP$ac_delim +CPP!$CPP$ac_delim +CXX!$CXX$ac_delim +CXXFLAGS!$CXXFLAGS$ac_delim +ac_ct_CXX!$ac_ct_CXX$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` +if test -n "$ac_eof"; then + ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` + ac_eof=`expr $ac_eof + 1` +fi + +cat >>$CONFIG_STATUS <<_ACEOF +cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +_ACEOF +sed ' +s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g +s/^/s,@/; s/!/@,|#_!!_#|/ +:n +t n +s/'"$ac_delim"'$/,g/; t +s/$/\\/; p +N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n +' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF +CEOF$ac_eof +_ACEOF + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF +CXXDEPMODE!$CXXDEPMODE$ac_delim +am__fastdepCXX_TRUE!$am__fastdepCXX_TRUE$ac_delim +am__fastdepCXX_FALSE!$am__fastdepCXX_FALSE$ac_delim +CXXCPP!$CXXCPP$ac_delim +F77!$F77$ac_delim +FFLAGS!$FFLAGS$ac_delim +ac_ct_F77!$ac_ct_F77$ac_delim +LIBTOOL!$LIBTOOL$ac_delim +LIBTOOL_DEPS!$LIBTOOL_DEPS$ac_delim +INSTALL_LTDL_TRUE!$INSTALL_LTDL_TRUE$ac_delim +INSTALL_LTDL_FALSE!$INSTALL_LTDL_FALSE$ac_delim +CONVENIENCE_LTDL_TRUE!$CONVENIENCE_LTDL_TRUE$ac_delim +CONVENIENCE_LTDL_FALSE!$CONVENIENCE_LTDL_FALSE$ac_delim +LIBADD_DL!$LIBADD_DL$ac_delim +LIBOBJS!$LIBOBJS$ac_delim +LTLIBOBJS!$LTLIBOBJS$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 16; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` +if test -n "$ac_eof"; then + ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` + ac_eof=`expr $ac_eof + 1` +fi + +cat >>$CONFIG_STATUS <<_ACEOF +cat >"\$tmp/subs-2.sed" <<\CEOF$ac_eof +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end +_ACEOF +sed ' +s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g +s/^/s,@/; s/!/@,|#_!!_#|/ +:n +t n +s/'"$ac_delim"'$/,g/; t +s/$/\\/; p +N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n +' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF +:end +s/|#_!!_#|//g +CEOF$ac_eof +_ACEOF + + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF +fi # test -n "$CONFIG_FILES" + + +for ac_tag in :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 +echo "$as_me: error: Invalid tag $ac_tag." >&2;} + { (exit 1); exit 1; }; };; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +echo "$as_me: error: cannot find input file: $ac_f" >&2;} + { (exit 1); exit 1; }; };; + esac + ac_file_inputs="$ac_file_inputs $ac_f" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input="Generated from "`IFS=: + echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + fi + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin";; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir="$ac_dir" + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= + +case `sed -n '/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p +' $ac_file_inputs` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s&@configure_input@&$configure_input&;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" $ac_file_inputs | sed -f "$tmp/subs-1.sed" | sed -f "$tmp/subs-2.sed" >$tmp/out + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out"; rm -f "$tmp/out";; + *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; + esac + ;; + :H) + # + # CONFIG_HEADER + # +_ACEOF + +# Transform confdefs.h into a sed script `conftest.defines', that +# substitutes the proper values into config.h.in to produce config.h. +rm -f conftest.defines conftest.tail +# First, append a space to every undef/define line, to ease matching. +echo 's/$/ /' >conftest.defines +# Then, protect against being on the right side of a sed subst, or in +# an unquoted here document, in config.status. If some macros were +# called several times there might be several #defines for the same +# symbol, which is useless. But do not sort them, since the last +# AC_DEFINE must be honored. +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where +# NAME is the cpp macro being defined, VALUE is the value it is being given. +# PARAMS is the parameter list in the macro definition--in most cases, it's +# just an empty string. +ac_dA='s,^\\([ #]*\\)[^ ]*\\([ ]*' +ac_dB='\\)[ (].*,\\1define\\2' +ac_dC=' ' +ac_dD=' ,' + +uniq confdefs.h | + sed -n ' + t rset + :rset + s/^[ ]*#[ ]*define[ ][ ]*// + t ok + d + :ok + s/[\\&,]/\\&/g + s/^\('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p + s/^\('"$ac_word_re"'\)[ ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p + ' >>conftest.defines + +# Remove the space that was appended to ease matching. +# Then replace #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +# (The regexp can be short, since the line contains either #define or #undef.) +echo 's/ $// +s,^[ #]*u.*,/* & */,' >>conftest.defines + +# Break up conftest.defines: +ac_max_sed_lines=50 + +# First sed command is: sed -f defines.sed $ac_file_inputs >"$tmp/out1" +# Second one is: sed -f defines.sed "$tmp/out1" >"$tmp/out2" +# Third one will be: sed -f defines.sed "$tmp/out2" >"$tmp/out1" +# et cetera. +ac_in='$ac_file_inputs' +ac_out='"$tmp/out1"' +ac_nxt='"$tmp/out2"' + +while : +do + # Write a here document: + cat >>$CONFIG_STATUS <<_ACEOF + # First, check the format of the line: + cat >"\$tmp/defines.sed" <<\\CEOF +/^[ ]*#[ ]*undef[ ][ ]*$ac_word_re[ ]*\$/b def +/^[ ]*#[ ]*define[ ][ ]*$ac_word_re[( ]/b def +b +:def +_ACEOF + sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS + ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in + sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail + grep . conftest.tail >/dev/null || break + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines conftest.tail + +echo "ac_result=$ac_in" >>$CONFIG_STATUS +cat >>$CONFIG_STATUS <<\_ACEOF + if test x"$ac_file" != x-; then + echo "/* $configure_input */" >"$tmp/config.h" + cat "$ac_result" >>"$tmp/config.h" + if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f $ac_file + mv "$tmp/config.h" $ac_file + fi + else + echo "/* $configure_input */" + cat "$ac_result" + fi + rm -f "$tmp/out12" +# Compute $ac_file's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $ac_file | $ac_file:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $ac_file" >`$as_dirname -- $ac_file || +$as_expr X$ac_file : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X$ac_file : 'X\(//\)[^/]' \| \ + X$ac_file : 'X\(//\)$' \| \ + X$ac_file : 'X\(/\)' \| . 2>/dev/null || +echo X$ac_file | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { echo "$as_me:$LINENO: executing $ac_file commands" >&5 +echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed 10q "$mf" | grep '^#.*generated by automake' > /dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir=$dirpart/$fdir + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done + ;; + + esac +done # for ac_tag + + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/libltdl/configure.ac b/libltdl/configure.ac new file mode 100644 index 00000000..1446efbd --- /dev/null +++ b/libltdl/configure.ac @@ -0,0 +1,79 @@ +## Process this file with autoconf to create configure. -*- autoconf -*- +# Copyright 2001 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA + + +dnl FIXME: Is this really new enough? +AC_PREREQ(2.50) + + +## ------------------------ ## +## Autoconf initialisation. ## +## ------------------------ ## +AC_INIT([libltdl], [1.2], [bug-libtool@gnu.org]) +AC_CONFIG_SRCDIR([ltdl.c]) + + +## ------------------------------- ## +## Libltdl specific configuration. ## +## ------------------------------- ## + +AC_CONFIG_AUX_DIR([.]) + +if test -z "$enable_ltdl_install$enable_ltdl_convenience"; then + if test -f ${srcdir}/ltmain.sh; then + # if libltdl is libtoolized, it is assumed to be stand-alone and + # installed unless the command line overrides it (tested above) + enable_ltdl_install=yes + else + AC_MSG_WARN([*** The top-level configure must select either]) + AC_MSG_WARN([*** [A""C_LIBLTDL_INSTALLABLE] or [A""C_LIBLTDL_CONVENIENCE].]) + AC_MSG_ERROR([*** Maybe you want to --enable-ltdl-install?]) + fi +fi + + +## ------------------------ ## +## Automake Initialisation. ## +## ------------------------ ## +AM_INIT_AUTOMAKE(AC_PACKAGE_TARNAME, AC_PACKAGE_VERSION, -) +AM_CONFIG_HEADER([config.h:config-h.in]) + + +## ------------------ ## +## C compiler checks. ## +## ------------------ ## +AC_PROG_CC +AC_C_CONST +AC_C_INLINE + + +## ----------------------- ## +## Libtool initialisation. ## +## ----------------------- ## +AC_LIBTOOL_WIN32_DLL +AC_PROG_LIBTOOL +AC_SUBST([LIBTOOL_DEPS]) + +AC_LIB_LTDL + + +## -------- ## +## Outputs. ## +## -------- ## +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/libltdl/install-sh b/libltdl/install-sh new file mode 100755 index 00000000..a5897de6 --- /dev/null +++ b/libltdl/install-sh @@ -0,0 +1,519 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2006-12-25.00 + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + trap '(exit $?); exit' 1 2 13 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dst_arg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + -*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test -z "$d" && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/libltdl/ltdl.c b/libltdl/ltdl.c new file mode 100644 index 00000000..3a76ff10 --- /dev/null +++ b/libltdl/ltdl.c @@ -0,0 +1,4530 @@ +/* ltdl.c -- system independent dlopen wrapper + Copyright (C) 1998, 1999, 2000, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + Originally by Thomas Tanner + This file is part of GNU Libtool. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +As a special exception to the GNU Lesser General Public License, +if you distribute this file as part of a program or library that +is built using GNU libtool, you may include it under the same +distribution terms that you use for the rest of that program. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA + +*/ + +#if HAVE_CONFIG_H +# include +#endif + +#if HAVE_UNISTD_H +# include +#endif + +#if HAVE_STDIO_H +# include +#endif + +/* Include the header defining malloc. On K&R C compilers, + that's , on ANSI C and ISO C compilers, that's . */ +#if HAVE_STDLIB_H +# include +#else +# if HAVE_MALLOC_H +# include +# endif +#endif + +#if HAVE_STRING_H +# include +#else +# if HAVE_STRINGS_H +# include +# endif +#endif + +#if HAVE_CTYPE_H +# include +#endif + +#if HAVE_MEMORY_H +# include +#endif + +#if HAVE_ERRNO_H +# include +#endif + + +#ifndef __WINDOWS__ +# ifdef __WIN32__ +# define __WINDOWS__ +# endif +#endif + + +#undef LT_USE_POSIX_DIRENT +#ifdef HAVE_CLOSEDIR +# ifdef HAVE_OPENDIR +# ifdef HAVE_READDIR +# ifdef HAVE_DIRENT_H +# define LT_USE_POSIX_DIRENT +# endif /* HAVE_DIRENT_H */ +# endif /* HAVE_READDIR */ +# endif /* HAVE_OPENDIR */ +#endif /* HAVE_CLOSEDIR */ + + +#undef LT_USE_WINDOWS_DIRENT_EMULATION +#ifndef LT_USE_POSIX_DIRENT +# ifdef __WINDOWS__ +# define LT_USE_WINDOWS_DIRENT_EMULATION +# endif /* __WINDOWS__ */ +#endif /* LT_USE_POSIX_DIRENT */ + + +#ifdef LT_USE_POSIX_DIRENT +# include +# define LT_D_NAMLEN(dirent) (strlen((dirent)->d_name)) +#else +# ifdef LT_USE_WINDOWS_DIRENT_EMULATION +# define LT_D_NAMLEN(dirent) (strlen((dirent)->d_name)) +# else +# define dirent direct +# define LT_D_NAMLEN(dirent) ((dirent)->d_namlen) +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# endif +# endif +#endif + +#if HAVE_ARGZ_H +# include +#endif + +#if HAVE_ASSERT_H +# include +#else +# define assert(arg) ((void) 0) +#endif + +#include "ltdl.h" + +#if WITH_DMALLOC +# include +#endif + + + + +/* --- WINDOWS SUPPORT --- */ + +/* DLL building support on win32 hosts; mostly to workaround their + ridiculous implementation of data symbol exporting. */ +#ifndef LT_GLOBAL_DATA +# if defined(__WINDOWS__) || defined(__CYGWIN__) +# ifdef DLL_EXPORT /* defined by libtool (if required) */ +# define LT_GLOBAL_DATA __declspec(dllexport) +# endif +# endif +# ifndef LT_GLOBAL_DATA /* static linking or !__WINDOWS__ */ +# define LT_GLOBAL_DATA +# endif +#endif + +/* fopen() mode flags for reading a text file */ +#undef LT_READTEXT_MODE +#if defined(__WINDOWS__) || defined(__CYGWIN__) +# define LT_READTEXT_MODE "rt" +#else +# define LT_READTEXT_MODE "r" +#endif + +#ifdef LT_USE_WINDOWS_DIRENT_EMULATION + +#include + +#define dirent lt_dirent +#define DIR lt_DIR + +struct dirent +{ + char d_name[2048]; + int d_namlen; +}; + +typedef struct _DIR +{ + HANDLE hSearch; + WIN32_FIND_DATA Win32FindData; + BOOL firsttime; + struct dirent file_info; +} DIR; + +#endif /* LT_USE_WINDOWS_DIRENT_EMULATION */ + + +/* --- MANIFEST CONSTANTS --- */ + + +/* Standard libltdl search path environment variable name */ +#undef LTDL_SEARCHPATH_VAR +#define LTDL_SEARCHPATH_VAR "LTDL_LIBRARY_PATH" + +/* Standard libtool archive file extension. */ +#undef LTDL_ARCHIVE_EXT +#define LTDL_ARCHIVE_EXT ".la" + +/* max. filename length */ +#ifndef LT_FILENAME_MAX +# define LT_FILENAME_MAX 1024 +#endif + +/* This is the maximum symbol size that won't require malloc/free */ +#undef LT_SYMBOL_LENGTH +#define LT_SYMBOL_LENGTH 128 + +/* This accounts for the _LTX_ separator */ +#undef LT_SYMBOL_OVERHEAD +#define LT_SYMBOL_OVERHEAD 5 + + + + +/* --- MEMORY HANDLING --- */ + + +/* These are the functions used internally. In addition to making + use of the associated function pointers above, they also perform + error handling. */ +static char *lt_estrdup LT_PARAMS((const char *str)); +static lt_ptr lt_emalloc LT_PARAMS((size_t size)); +static lt_ptr lt_erealloc LT_PARAMS((lt_ptr addr, size_t size)); + +/* static lt_ptr rpl_realloc LT_PARAMS((lt_ptr ptr, size_t size)); */ +#define rpl_realloc realloc + +/* These are the pointers that can be changed by the caller: */ +LT_GLOBAL_DATA lt_ptr (*lt_dlmalloc) LT_PARAMS((size_t size)) + = (lt_ptr (*) LT_PARAMS((size_t))) malloc; +LT_GLOBAL_DATA lt_ptr (*lt_dlrealloc) LT_PARAMS((lt_ptr ptr, size_t size)) + = (lt_ptr (*) LT_PARAMS((lt_ptr, size_t))) rpl_realloc; +LT_GLOBAL_DATA void (*lt_dlfree) LT_PARAMS((lt_ptr ptr)) + = (void (*) LT_PARAMS((lt_ptr))) free; + +/* The following macros reduce the amount of typing needed to cast + assigned memory. */ +#if WITH_DMALLOC + +#define LT_DLMALLOC(tp, n) ((tp *) xmalloc ((n) * sizeof(tp))) +#define LT_DLREALLOC(tp, p, n) ((tp *) xrealloc ((p), (n) * sizeof(tp))) +#define LT_DLFREE(p) \ + LT_STMT_START { if (p) (p) = (xfree (p), (lt_ptr) 0); } LT_STMT_END + +#define LT_EMALLOC(tp, n) ((tp *) xmalloc ((n) * sizeof(tp))) +#define LT_EREALLOC(tp, p, n) ((tp *) xrealloc ((p), (n) * sizeof(tp))) + +#else + +#define LT_DLMALLOC(tp, n) ((tp *) lt_dlmalloc ((n) * sizeof(tp))) +#define LT_DLREALLOC(tp, p, n) ((tp *) lt_dlrealloc ((p), (n) * sizeof(tp))) +#define LT_DLFREE(p) \ + LT_STMT_START { if (p) (p) = (lt_dlfree (p), (lt_ptr) 0); } LT_STMT_END + +#define LT_EMALLOC(tp, n) ((tp *) lt_emalloc ((n) * sizeof(tp))) +#define LT_EREALLOC(tp, p, n) ((tp *) lt_erealloc ((p), (n) * sizeof(tp))) + +#endif + +#define LT_DLMEM_REASSIGN(p, q) LT_STMT_START { \ + if ((p) != (q)) { if (p) lt_dlfree (p); (p) = (q); (q) = 0; } \ + } LT_STMT_END + + +/* --- REPLACEMENT FUNCTIONS --- */ + + +#undef strdup +#define strdup rpl_strdup + +static char *strdup LT_PARAMS((const char *str)); + +static char * +strdup(str) + const char *str; +{ + char *tmp = 0; + + if (str) + { + tmp = LT_DLMALLOC (char, 1+ strlen (str)); + if (tmp) + { + strcpy(tmp, str); + } + } + + return tmp; +} + + +#if ! HAVE_STRCMP + +#undef strcmp +#define strcmp rpl_strcmp + +static int strcmp LT_PARAMS((const char *str1, const char *str2)); + +static int +strcmp (str1, str2) + const char *str1; + const char *str2; +{ + if (str1 == str2) + return 0; + if (str1 == 0) + return -1; + if (str2 == 0) + return 1; + + for (;*str1 && *str2; ++str1, ++str2) + { + if (*str1 != *str2) + break; + } + + return (int)(*str1 - *str2); +} +#endif + + +#if ! HAVE_STRCHR + +# if HAVE_INDEX +# define strchr index +# else +# define strchr rpl_strchr + +static const char *strchr LT_PARAMS((const char *str, int ch)); + +static const char* +strchr(str, ch) + const char *str; + int ch; +{ + const char *p; + + for (p = str; *p != (char)ch && *p != LT_EOS_CHAR; ++p) + /*NOWORK*/; + + return (*p == (char)ch) ? p : 0; +} + +# endif +#endif /* !HAVE_STRCHR */ + + +#if ! HAVE_STRRCHR + +# if HAVE_RINDEX +# define strrchr rindex +# else +# define strrchr rpl_strrchr + +static const char *strrchr LT_PARAMS((const char *str, int ch)); + +static const char* +strrchr(str, ch) + const char *str; + int ch; +{ + const char *p, *q = 0; + + for (p = str; *p != LT_EOS_CHAR; ++p) + { + if (*p == (char) ch) + { + q = p; + } + } + + return q; +} + +# endif +#endif + +/* NOTE: Neither bcopy nor the memcpy implementation below can + reliably handle copying in overlapping areas of memory. Use + memmove (for which there is a fallback implmentation below) + if you need that behaviour. */ +#if ! HAVE_MEMCPY + +# if HAVE_BCOPY +# define memcpy(dest, src, size) bcopy (src, dest, size) +# else +# define memcpy rpl_memcpy + +static lt_ptr memcpy LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size)); + +static lt_ptr +memcpy (dest, src, size) + lt_ptr dest; + const lt_ptr src; + size_t size; +{ + const char * s = src; + char * d = dest; + size_t i = 0; + + for (i = 0; i < size; ++i) + { + d[i] = s[i]; + } + + return dest; +} + +# endif /* !HAVE_BCOPY */ +#endif /* !HAVE_MEMCPY */ + +#if ! HAVE_MEMMOVE +# define memmove rpl_memmove + +static lt_ptr memmove LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size)); + +static lt_ptr +memmove (dest, src, size) + lt_ptr dest; + const lt_ptr src; + size_t size; +{ + const char * s = src; + char * d = dest; + size_t i; + + if (d < s) + for (i = 0; i < size; ++i) + { + d[i] = s[i]; + } + else if (d > s && size > 0) + for (i = size -1; ; --i) + { + d[i] = s[i]; + if (i == 0) + break; + } + + return dest; +} + +#endif /* !HAVE_MEMMOVE */ + +#ifdef LT_USE_WINDOWS_DIRENT_EMULATION + +static void closedir LT_PARAMS((DIR *entry)); + +static void +closedir(entry) + DIR *entry; +{ + assert(entry != (DIR *) NULL); + FindClose(entry->hSearch); + lt_dlfree((lt_ptr)entry); +} + + +static DIR * opendir LT_PARAMS((const char *path)); + +static DIR* +opendir (path) + const char *path; +{ + char file_specification[LT_FILENAME_MAX]; + DIR *entry; + + assert(path != (char *) NULL); + /* allow space for: path + '\\' '\\' '*' '.' '*' + '\0' */ + (void) strncpy (file_specification, path, LT_FILENAME_MAX-6); + file_specification[LT_FILENAME_MAX-6] = LT_EOS_CHAR; + (void) strcat(file_specification,"\\"); + entry = LT_DLMALLOC (DIR,sizeof(DIR)); + if (entry != (DIR *) 0) + { + entry->firsttime = TRUE; + entry->hSearch = FindFirstFile(file_specification,&entry->Win32FindData); + } + if (entry->hSearch == INVALID_HANDLE_VALUE) + { + (void) strcat(file_specification,"\\*.*"); + entry->hSearch = FindFirstFile(file_specification,&entry->Win32FindData); + if (entry->hSearch == INVALID_HANDLE_VALUE) + { + LT_DLFREE (entry); + return (DIR *) 0; + } + } + return(entry); +} + + +static struct dirent *readdir LT_PARAMS((DIR *entry)); + +static struct dirent *readdir(entry) + DIR *entry; +{ + int + status; + + if (entry == (DIR *) 0) + return((struct dirent *) 0); + if (!entry->firsttime) + { + status = FindNextFile(entry->hSearch,&entry->Win32FindData); + if (status == 0) + return((struct dirent *) 0); + } + entry->firsttime = FALSE; + (void) strncpy(entry->file_info.d_name,entry->Win32FindData.cFileName, + LT_FILENAME_MAX-1); + entry->file_info.d_name[LT_FILENAME_MAX - 1] = LT_EOS_CHAR; + entry->file_info.d_namlen = strlen(entry->file_info.d_name); + return(&entry->file_info); +} + +#endif /* LT_USE_WINDOWS_DIRENT_EMULATION */ + +/* According to Alexandre Oliva , + ``realloc is not entirely portable'' + In any case we want to use the allocator supplied by the user without + burdening them with an lt_dlrealloc function pointer to maintain. + Instead implement our own version (with known boundary conditions) + using lt_dlmalloc and lt_dlfree. */ + +/* #undef realloc + #define realloc rpl_realloc +*/ +#if 0 + /* You can't (re)define realloc unless you also (re)define malloc. + Right now, this code uses the size of the *destination* to decide + how much to copy. That's not right, but you can't know the size + of the source unless you know enough about, or wrote malloc. So + this code is disabled... */ + +static lt_ptr +realloc (ptr, size) + lt_ptr ptr; + size_t size; +{ + if (size == 0) + { + /* For zero or less bytes, free the original memory */ + if (ptr != 0) + { + lt_dlfree (ptr); + } + + return (lt_ptr) 0; + } + else if (ptr == 0) + { + /* Allow reallocation of a NULL pointer. */ + return lt_dlmalloc (size); + } + else + { + /* Allocate a new block, copy and free the old block. */ + lt_ptr mem = lt_dlmalloc (size); + + if (mem) + { + memcpy (mem, ptr, size); + lt_dlfree (ptr); + } + + /* Note that the contents of PTR are not damaged if there is + insufficient memory to realloc. */ + return mem; + } +} +#endif + + +#if ! HAVE_ARGZ_APPEND +# define argz_append rpl_argz_append + +static error_t argz_append LT_PARAMS((char **pargz, size_t *pargz_len, + const char *buf, size_t buf_len)); + +static error_t +argz_append (pargz, pargz_len, buf, buf_len) + char **pargz; + size_t *pargz_len; + const char *buf; + size_t buf_len; +{ + size_t argz_len; + char *argz; + + assert (pargz); + assert (pargz_len); + assert ((*pargz && *pargz_len) || (!*pargz && !*pargz_len)); + + /* If nothing needs to be appended, no more work is required. */ + if (buf_len == 0) + return 0; + + /* Ensure there is enough room to append BUF_LEN. */ + argz_len = *pargz_len + buf_len; + argz = LT_DLREALLOC (char, *pargz, argz_len); + if (!argz) + return ENOMEM; + + /* Copy characters from BUF after terminating '\0' in ARGZ. */ + memcpy (argz + *pargz_len, buf, buf_len); + + /* Assign new values. */ + *pargz = argz; + *pargz_len = argz_len; + + return 0; +} +#endif /* !HAVE_ARGZ_APPEND */ + + +#if ! HAVE_ARGZ_CREATE_SEP +# define argz_create_sep rpl_argz_create_sep + +static error_t argz_create_sep LT_PARAMS((const char *str, int delim, + char **pargz, size_t *pargz_len)); + +static error_t +argz_create_sep (str, delim, pargz, pargz_len) + const char *str; + int delim; + char **pargz; + size_t *pargz_len; +{ + size_t argz_len; + char *argz = 0; + + assert (str); + assert (pargz); + assert (pargz_len); + + /* Make a copy of STR, but replacing each occurrence of + DELIM with '\0'. */ + argz_len = 1+ LT_STRLEN (str); + if (argz_len) + { + const char *p; + char *q; + + argz = LT_DLMALLOC (char, argz_len); + if (!argz) + return ENOMEM; + + for (p = str, q = argz; *p != LT_EOS_CHAR; ++p) + { + if (*p == delim) + { + /* Ignore leading delimiters, and fold consecutive + delimiters in STR into a single '\0' in ARGZ. */ + if ((q > argz) && (q[-1] != LT_EOS_CHAR)) + *q++ = LT_EOS_CHAR; + else + --argz_len; + } + else + *q++ = *p; + } + /* Copy terminating LT_EOS_CHAR. */ + *q = *p; + } + + /* If ARGZ_LEN has shrunk to nothing, release ARGZ's memory. */ + if (!argz_len) + LT_DLFREE (argz); + + /* Assign new values. */ + *pargz = argz; + *pargz_len = argz_len; + + return 0; +} +#endif /* !HAVE_ARGZ_CREATE_SEP */ + + +#if ! HAVE_ARGZ_INSERT +# define argz_insert rpl_argz_insert + +static error_t argz_insert LT_PARAMS((char **pargz, size_t *pargz_len, + char *before, const char *entry)); + +static error_t +argz_insert (pargz, pargz_len, before, entry) + char **pargz; + size_t *pargz_len; + char *before; + const char *entry; +{ + assert (pargz); + assert (pargz_len); + assert (entry && *entry); + + /* No BEFORE address indicates ENTRY should be inserted after the + current last element. */ + if (!before) + return argz_append (pargz, pargz_len, entry, 1+ LT_STRLEN (entry)); + + /* This probably indicates a programmer error, but to preserve + semantics, scan back to the start of an entry if BEFORE points + into the middle of it. */ + while ((before > *pargz) && (before[-1] != LT_EOS_CHAR)) + --before; + + { + size_t entry_len = 1+ LT_STRLEN (entry); + size_t argz_len = *pargz_len + entry_len; + size_t offset = before - *pargz; + char *argz = LT_DLREALLOC (char, *pargz, argz_len); + + if (!argz) + return ENOMEM; + + /* Make BEFORE point to the equivalent offset in ARGZ that it + used to have in *PARGZ incase realloc() moved the block. */ + before = argz + offset; + + /* Move the ARGZ entries starting at BEFORE up into the new + space at the end -- making room to copy ENTRY into the + resulting gap. */ + memmove (before + entry_len, before, *pargz_len - offset); + memcpy (before, entry, entry_len); + + /* Assign new values. */ + *pargz = argz; + *pargz_len = argz_len; + } + + return 0; +} +#endif /* !HAVE_ARGZ_INSERT */ + + +#if ! HAVE_ARGZ_NEXT +# define argz_next rpl_argz_next + +static char *argz_next LT_PARAMS((char *argz, size_t argz_len, + const char *entry)); + +static char * +argz_next (argz, argz_len, entry) + char *argz; + size_t argz_len; + const char *entry; +{ + assert ((argz && argz_len) || (!argz && !argz_len)); + + if (entry) + { + /* Either ARGZ/ARGZ_LEN is empty, or ENTRY points into an address + within the ARGZ vector. */ + assert ((!argz && !argz_len) + || ((argz <= entry) && (entry < (argz + argz_len)))); + + /* Move to the char immediately after the terminating + '\0' of ENTRY. */ + entry = 1+ strchr (entry, LT_EOS_CHAR); + + /* Return either the new ENTRY, or else NULL if ARGZ is + exhausted. */ + return (entry >= argz + argz_len) ? 0 : (char *) entry; + } + else + { + /* This should probably be flagged as a programmer error, + since starting an argz_next loop with the iterator set + to ARGZ is safer. To preserve semantics, handle the NULL + case by returning the start of ARGZ (if any). */ + if (argz_len > 0) + return argz; + else + return 0; + } +} +#endif /* !HAVE_ARGZ_NEXT */ + + + +#if ! HAVE_ARGZ_STRINGIFY +# define argz_stringify rpl_argz_stringify + +static void argz_stringify LT_PARAMS((char *argz, size_t argz_len, + int sep)); + +static void +argz_stringify (argz, argz_len, sep) + char *argz; + size_t argz_len; + int sep; +{ + assert ((argz && argz_len) || (!argz && !argz_len)); + + if (sep) + { + --argz_len; /* don't stringify the terminating EOS */ + while (--argz_len > 0) + { + if (argz[argz_len] == LT_EOS_CHAR) + argz[argz_len] = sep; + } + } +} +#endif /* !HAVE_ARGZ_STRINGIFY */ + + + + +/* --- TYPE DEFINITIONS -- */ + + +/* This type is used for the array of caller data sets in each handler. */ +typedef struct { + lt_dlcaller_id key; + lt_ptr data; +} lt_caller_data; + + + + +/* --- OPAQUE STRUCTURES DECLARED IN LTDL.H --- */ + + +/* Extract the diagnostic strings from the error table macro in the same + order as the enumerated indices in ltdl.h. */ + +static const char *lt_dlerror_strings[] = + { +#define LT_ERROR(name, diagnostic) (diagnostic), + lt_dlerror_table +#undef LT_ERROR + + 0 + }; + +/* This structure is used for the list of registered loaders. */ +struct lt_dlloader { + struct lt_dlloader *next; + const char *loader_name; /* identifying name for each loader */ + const char *sym_prefix; /* prefix for symbols */ + lt_module_open *module_open; + lt_module_close *module_close; + lt_find_sym *find_sym; + lt_dlloader_exit *dlloader_exit; + lt_user_data dlloader_data; +}; + +struct lt_dlhandle_struct { + struct lt_dlhandle_struct *next; + lt_dlloader *loader; /* dlopening interface */ + lt_dlinfo info; + int depcount; /* number of dependencies */ + lt_dlhandle *deplibs; /* dependencies */ + lt_module module; /* system module handle */ + lt_ptr system; /* system specific data */ + lt_caller_data *caller_data; /* per caller associated data */ + int flags; /* various boolean stats */ +}; + +/* Various boolean flags can be stored in the flags field of an + lt_dlhandle_struct... */ +#define LT_DLGET_FLAG(handle, flag) (((handle)->flags & (flag)) == (flag)) +#define LT_DLSET_FLAG(handle, flag) ((handle)->flags |= (flag)) + +#define LT_DLRESIDENT_FLAG (0x01 << 0) +/* ...add more flags here... */ + +#define LT_DLIS_RESIDENT(handle) LT_DLGET_FLAG(handle, LT_DLRESIDENT_FLAG) + + +#define LT_DLSTRERROR(name) lt_dlerror_strings[LT_CONC(LT_ERROR_,name)] + +static const char objdir[] = LTDL_OBJDIR; +static const char archive_ext[] = LTDL_ARCHIVE_EXT; +#ifdef LTDL_SHLIB_EXT +static const char shlib_ext[] = LTDL_SHLIB_EXT; +#endif +#ifdef LTDL_SYSSEARCHPATH +static const char sys_search_path[] = LTDL_SYSSEARCHPATH; +#endif + + + + +/* --- MUTEX LOCKING --- */ + + +/* Macros to make it easier to run the lock functions only if they have + been registered. The reason for the complicated lock macro is to + ensure that the stored error message from the last error is not + accidentally erased if the current function doesn't generate an + error of its own. */ +#define LT_DLMUTEX_LOCK() LT_STMT_START { \ + if (lt_dlmutex_lock_func) (*lt_dlmutex_lock_func)(); \ + } LT_STMT_END +#define LT_DLMUTEX_UNLOCK() LT_STMT_START { \ + if (lt_dlmutex_unlock_func) (*lt_dlmutex_unlock_func)();\ + } LT_STMT_END +#define LT_DLMUTEX_SETERROR(errormsg) LT_STMT_START { \ + if (lt_dlmutex_seterror_func) \ + (*lt_dlmutex_seterror_func) (errormsg); \ + else lt_dllast_error = (errormsg); } LT_STMT_END +#define LT_DLMUTEX_GETERROR(errormsg) LT_STMT_START { \ + if (lt_dlmutex_geterror_func) \ + (errormsg) = (*lt_dlmutex_geterror_func) (); \ + else (errormsg) = lt_dllast_error; } LT_STMT_END + +/* The mutex functions stored here are global, and are necessarily the + same for all threads that wish to share access to libltdl. */ +static lt_dlmutex_lock *lt_dlmutex_lock_func = 0; +static lt_dlmutex_unlock *lt_dlmutex_unlock_func = 0; +static lt_dlmutex_seterror *lt_dlmutex_seterror_func = 0; +static lt_dlmutex_geterror *lt_dlmutex_geterror_func = 0; +static const char *lt_dllast_error = 0; + + +/* Either set or reset the mutex functions. Either all the arguments must + be valid functions, or else all can be NULL to turn off locking entirely. + The registered functions should be manipulating a static global lock + from the lock() and unlock() callbacks, which needs to be reentrant. */ +int +lt_dlmutex_register (lock, unlock, seterror, geterror) + lt_dlmutex_lock *lock; + lt_dlmutex_unlock *unlock; + lt_dlmutex_seterror *seterror; + lt_dlmutex_geterror *geterror; +{ + lt_dlmutex_unlock *old_unlock = lt_dlmutex_unlock_func; + int errors = 0; + + /* Lock using the old lock() callback, if any. */ + LT_DLMUTEX_LOCK (); + + if ((lock && unlock && seterror && geterror) + || !(lock || unlock || seterror || geterror)) + { + lt_dlmutex_lock_func = lock; + lt_dlmutex_unlock_func = unlock; + lt_dlmutex_seterror_func = seterror; + lt_dlmutex_geterror_func = geterror; + } + else + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_MUTEX_ARGS)); + ++errors; + } + + /* Use the old unlock() callback we saved earlier, if any. Otherwise + record any errors using internal storage. */ + if (old_unlock) + (*old_unlock) (); + + /* Return the number of errors encountered during the execution of + this function. */ + return errors; +} + + + + +/* --- ERROR HANDLING --- */ + + +static const char **user_error_strings = 0; +static int errorcount = LT_ERROR_MAX; + +int +lt_dladderror (diagnostic) + const char *diagnostic; +{ + int errindex = 0; + int result = -1; + const char **temp = (const char **) 0; + + assert (diagnostic); + + LT_DLMUTEX_LOCK (); + + errindex = errorcount - LT_ERROR_MAX; + temp = LT_EREALLOC (const char *, user_error_strings, 1 + errindex); + if (temp) + { + user_error_strings = temp; + user_error_strings[errindex] = diagnostic; + result = errorcount++; + } + + LT_DLMUTEX_UNLOCK (); + + return result; +} + +int +lt_dlseterror (errindex) + int errindex; +{ + int errors = 0; + + LT_DLMUTEX_LOCK (); + + if (errindex >= errorcount || errindex < 0) + { + /* Ack! Error setting the error message! */ + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_ERRORCODE)); + ++errors; + } + else if (errindex < LT_ERROR_MAX) + { + /* No error setting the error message! */ + LT_DLMUTEX_SETERROR (lt_dlerror_strings[errindex]); + } + else + { + /* No error setting the error message! */ + LT_DLMUTEX_SETERROR (user_error_strings[errindex - LT_ERROR_MAX]); + } + + LT_DLMUTEX_UNLOCK (); + + return errors; +} + +static lt_ptr +lt_emalloc (size) + size_t size; +{ + lt_ptr mem = lt_dlmalloc (size); + if (size && !mem) + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); + return mem; +} + +static lt_ptr +lt_erealloc (addr, size) + lt_ptr addr; + size_t size; +{ + lt_ptr mem = lt_dlrealloc (addr, size); + if (size && !mem) + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); + return mem; +} + +static char * +lt_estrdup (str) + const char *str; +{ + char *copy = strdup (str); + if (LT_STRLEN (str) && !copy) + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); + return copy; +} + + + + +/* --- DLOPEN() INTERFACE LOADER --- */ + + +#if HAVE_LIBDL + +/* dynamic linking with dlopen/dlsym */ + +#if HAVE_DLFCN_H +# include +#endif + +#if HAVE_SYS_DL_H +# include +#endif + +/* We may have to define LT_LAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_LAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_LAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_LAZY_OR_NOW DL_LAZY +# endif +# endif /* !RTLD_LAZY */ +#endif +#ifndef LT_LAZY_OR_NOW +# ifdef RTLD_NOW +# define LT_LAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_LAZY_OR_NOW DL_NOW +# endif +# endif /* !RTLD_NOW */ +#endif +#ifndef LT_LAZY_OR_NOW +# define LT_LAZY_OR_NOW 0 +#endif /* !LT_LAZY_OR_NOW */ + +#if HAVE_DLERROR +# define DLERROR(arg) dlerror () +#else +# define DLERROR(arg) LT_DLSTRERROR (arg) +#endif + +static lt_module +sys_dl_open (loader_data, filename) + lt_user_data loader_data; + const char *filename; +{ + lt_module module = dlopen (filename, LT_LAZY_OR_NOW); + + if (!module) + { + LT_DLMUTEX_SETERROR (DLERROR (CANNOT_OPEN)); + } + + return module; +} + +static int +sys_dl_close (loader_data, module) + lt_user_data loader_data; + lt_module module; +{ + int errors = 0; + + if (dlclose (module) != 0) + { + LT_DLMUTEX_SETERROR (DLERROR (CANNOT_CLOSE)); + ++errors; + } + + return errors; +} + +static lt_ptr +sys_dl_sym (loader_data, module, symbol) + lt_user_data loader_data; + lt_module module; + const char *symbol; +{ + lt_ptr address = dlsym (module, symbol); + + if (!address) + { + LT_DLMUTEX_SETERROR (DLERROR (SYMBOL_NOT_FOUND)); + } + + return address; +} + +static struct lt_user_dlloader sys_dl = + { +# ifdef NEED_USCORE + "_", +# else + 0, +# endif + sys_dl_open, sys_dl_close, sys_dl_sym, 0, 0 }; + + +#endif /* HAVE_LIBDL */ + + + +/* --- SHL_LOAD() INTERFACE LOADER --- */ + +#if HAVE_SHL_LOAD + +/* dynamic linking with shl_load (HP-UX) (comments from gmodule) */ + +#ifdef HAVE_DL_H +# include +#endif + +/* some flags are missing on some systems, so we provide + * harmless defaults. + * + * Mandatory: + * BIND_IMMEDIATE - Resolve symbol references when the library is loaded. + * BIND_DEFERRED - Delay code symbol resolution until actual reference. + * + * Optionally: + * BIND_FIRST - Place the library at the head of the symbol search + * order. + * BIND_NONFATAL - The default BIND_IMMEDIATE behavior is to treat all + * unsatisfied symbols as fatal. This flag allows + * binding of unsatisfied code symbols to be deferred + * until use. + * [Perl: For certain libraries, like DCE, deferred + * binding often causes run time problems. Adding + * BIND_NONFATAL to BIND_IMMEDIATE still allows + * unresolved references in situations like this.] + * BIND_NOSTART - Do not call the initializer for the shared library + * when the library is loaded, nor on a future call to + * shl_unload(). + * BIND_VERBOSE - Print verbose messages concerning possible + * unsatisfied symbols. + * + * hp9000s700/hp9000s800: + * BIND_RESTRICTED - Restrict symbols visible by the library to those + * present at library load time. + * DYNAMIC_PATH - Allow the loader to dynamically search for the + * library specified by the path argument. + */ + +#ifndef DYNAMIC_PATH +# define DYNAMIC_PATH 0 +#endif +#ifndef BIND_RESTRICTED +# define BIND_RESTRICTED 0 +#endif + +#define LT_BIND_FLAGS (BIND_IMMEDIATE | BIND_NONFATAL | DYNAMIC_PATH) + +static lt_module +sys_shl_open (loader_data, filename) + lt_user_data loader_data; + const char *filename; +{ + static shl_t self = (shl_t) 0; + lt_module module = shl_load (filename, LT_BIND_FLAGS, 0L); + + /* Since searching for a symbol against a NULL module handle will also + look in everything else that was already loaded and exported with + the -E compiler flag, we always cache a handle saved before any + modules are loaded. */ + if (!self) + { + lt_ptr address; + shl_findsym (&self, "main", TYPE_UNDEFINED, &address); + } + + if (!filename) + { + module = self; + } + else + { + module = shl_load (filename, LT_BIND_FLAGS, 0L); + + if (!module) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); + } + } + + return module; +} + +static int +sys_shl_close (loader_data, module) + lt_user_data loader_data; + lt_module module; +{ + int errors = 0; + + if (module && (shl_unload ((shl_t) (module)) != 0)) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); + ++errors; + } + + return errors; +} + +static lt_ptr +sys_shl_sym (loader_data, module, symbol) + lt_user_data loader_data; + lt_module module; + const char *symbol; +{ + lt_ptr address = 0; + + /* sys_shl_open should never return a NULL module handle */ + if (module == (lt_module) 0) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); + } + else if (!shl_findsym((shl_t*) &module, symbol, TYPE_UNDEFINED, &address)) + { + if (!address) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); + } + } + + return address; +} + +static struct lt_user_dlloader sys_shl = { + 0, sys_shl_open, sys_shl_close, sys_shl_sym, 0, 0 +}; + +#endif /* HAVE_SHL_LOAD */ + + + + +/* --- LOADLIBRARY() INTERFACE LOADER --- */ + +#ifdef __WINDOWS__ + +/* dynamic linking for Win32 */ + +#include + +/* Forward declaration; required to implement handle search below. */ +static lt_dlhandle handles; + +static lt_module +sys_wll_open (loader_data, filename) + lt_user_data loader_data; + const char *filename; +{ + lt_dlhandle cur; + lt_module module = 0; + const char *errormsg = 0; + char *searchname = 0; + char *ext; + char self_name_buf[MAX_PATH]; + + if (!filename) + { + /* Get the name of main module */ + *self_name_buf = 0; + GetModuleFileName (NULL, self_name_buf, sizeof (self_name_buf)); + filename = ext = self_name_buf; + } + else + { + ext = strrchr (filename, '.'); + } + + if (ext) + { + /* FILENAME already has an extension. */ + searchname = lt_estrdup (filename); + } + else + { + /* Append a `.' to stop Windows from adding an + implicit `.dll' extension. */ + searchname = LT_EMALLOC (char, 2+ LT_STRLEN (filename)); + if (searchname) + sprintf (searchname, "%s.", filename); + } + if (!searchname) + return 0; + + { + /* Silence dialog from LoadLibrary on some failures. + No way to get the error mode, but to set it, + so set it twice to preserve any previous flags. */ + UINT errormode = SetErrorMode(SEM_FAILCRITICALERRORS); + SetErrorMode(errormode | SEM_FAILCRITICALERRORS); + +#if defined(__CYGWIN__) + { + char wpath[MAX_PATH]; + cygwin_conv_to_full_win32_path (searchname, wpath); + module = LoadLibrary (wpath); + } +#else + module = LoadLibrary (searchname); +#endif + + /* Restore the error mode. */ + SetErrorMode(errormode); + } + + LT_DLFREE (searchname); + + /* libltdl expects this function to fail if it is unable + to physically load the library. Sadly, LoadLibrary + will search the loaded libraries for a match and return + one of them if the path search load fails. + + We check whether LoadLibrary is returning a handle to + an already loaded module, and simulate failure if we + find one. */ + LT_DLMUTEX_LOCK (); + cur = handles; + while (cur) + { + if (!cur->module) + { + cur = 0; + break; + } + + if (cur->module == module) + { + break; + } + + cur = cur->next; + } + LT_DLMUTEX_UNLOCK (); + + if (cur || !module) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); + module = 0; + } + + return module; +} + +static int +sys_wll_close (loader_data, module) + lt_user_data loader_data; + lt_module module; +{ + int errors = 0; + + if (FreeLibrary(module) == 0) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); + ++errors; + } + + return errors; +} + +static lt_ptr +sys_wll_sym (loader_data, module, symbol) + lt_user_data loader_data; + lt_module module; + const char *symbol; +{ + lt_ptr address = GetProcAddress (module, symbol); + + if (!address) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); + } + + return address; +} + +static struct lt_user_dlloader sys_wll = { + 0, sys_wll_open, sys_wll_close, sys_wll_sym, 0, 0 +}; + +#endif /* __WINDOWS__ */ + + + + +/* --- LOAD_ADD_ON() INTERFACE LOADER --- */ + + +#ifdef __BEOS__ + +/* dynamic linking for BeOS */ + +#include + +static lt_module +sys_bedl_open (loader_data, filename) + lt_user_data loader_data; + const char *filename; +{ + image_id image = 0; + + if (filename) + { + image = load_add_on (filename); + } + else + { + image_info info; + int32 cookie = 0; + if (get_next_image_info (0, &cookie, &info) == B_OK) + image = load_add_on (info.name); + } + + if (image <= 0) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); + image = 0; + } + + return (lt_module) image; +} + +static int +sys_bedl_close (loader_data, module) + lt_user_data loader_data; + lt_module module; +{ + int errors = 0; + + if (unload_add_on ((image_id) module) != B_OK) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); + ++errors; + } + + return errors; +} + +static lt_ptr +sys_bedl_sym (loader_data, module, symbol) + lt_user_data loader_data; + lt_module module; + const char *symbol; +{ + lt_ptr address = 0; + image_id image = (image_id) module; + + if (get_image_symbol (image, symbol, B_SYMBOL_TYPE_ANY, address) != B_OK) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); + address = 0; + } + + return address; +} + +static struct lt_user_dlloader sys_bedl = { + 0, sys_bedl_open, sys_bedl_close, sys_bedl_sym, 0, 0 +}; + +#endif /* __BEOS__ */ + + + + +/* --- DLD_LINK() INTERFACE LOADER --- */ + + +#if HAVE_DLD + +/* dynamic linking with dld */ + +#if HAVE_DLD_H +#include +#endif + +static lt_module +sys_dld_open (loader_data, filename) + lt_user_data loader_data; + const char *filename; +{ + lt_module module = strdup (filename); + + if (dld_link (filename) != 0) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); + LT_DLFREE (module); + module = 0; + } + + return module; +} + +static int +sys_dld_close (loader_data, module) + lt_user_data loader_data; + lt_module module; +{ + int errors = 0; + + if (dld_unlink_by_file ((char*)(module), 1) != 0) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); + ++errors; + } + else + { + LT_DLFREE (module); + } + + return errors; +} + +static lt_ptr +sys_dld_sym (loader_data, module, symbol) + lt_user_data loader_data; + lt_module module; + const char *symbol; +{ + lt_ptr address = dld_get_func (symbol); + + if (!address) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); + } + + return address; +} + +static struct lt_user_dlloader sys_dld = { + 0, sys_dld_open, sys_dld_close, sys_dld_sym, 0, 0 +}; + +#endif /* HAVE_DLD */ + +/* --- DYLD() MACOSX/DARWIN INTERFACE LOADER --- */ +#if HAVE_DYLD + + +#if HAVE_MACH_O_DYLD_H +#if !defined(__APPLE_CC__) && !defined(__MWERKS__) && !defined(__private_extern__) +/* Is this correct? Does it still function properly? */ +#define __private_extern__ extern +#endif +# include +#endif +#include + +/* We have to put some stuff here that isn't in older dyld.h files */ +#ifndef ENUM_DYLD_BOOL +# define ENUM_DYLD_BOOL +# undef FALSE +# undef TRUE + enum DYLD_BOOL { + FALSE, + TRUE + }; +#endif +#ifndef LC_REQ_DYLD +# define LC_REQ_DYLD 0x80000000 +#endif +#ifndef LC_LOAD_WEAK_DYLIB +# define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD) +#endif +static const struct mach_header * (*ltdl_NSAddImage)(const char *image_name, unsigned long options) = 0; +static NSSymbol (*ltdl_NSLookupSymbolInImage)(const struct mach_header *image,const char *symbolName, unsigned long options) = 0; +static enum DYLD_BOOL (*ltdl_NSIsSymbolNameDefinedInImage)(const struct mach_header *image, const char *symbolName) = 0; +static enum DYLD_BOOL (*ltdl_NSMakePrivateModulePublic)(NSModule module) = 0; + +#ifndef NSADDIMAGE_OPTION_NONE +#define NSADDIMAGE_OPTION_NONE 0x0 +#endif +#ifndef NSADDIMAGE_OPTION_RETURN_ON_ERROR +#define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1 +#endif +#ifndef NSADDIMAGE_OPTION_WITH_SEARCHING +#define NSADDIMAGE_OPTION_WITH_SEARCHING 0x2 +#endif +#ifndef NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED +#define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4 +#endif +#ifndef NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME +#define NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME 0x8 +#endif +#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND +#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0 +#endif +#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW +#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW 0x1 +#endif +#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY +#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY 0x2 +#endif +#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR +#define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4 +#endif + + +static const char * +lt_int_dyld_error(othererror) + char* othererror; +{ +/* return the dyld error string, or the passed in error string if none */ + NSLinkEditErrors ler; + int lerno; + const char *errstr; + const char *file; + NSLinkEditError(&ler,&lerno,&file,&errstr); + if (!errstr || !strlen(errstr)) errstr = othererror; + return errstr; +} + +static const struct mach_header * +lt_int_dyld_get_mach_header_from_nsmodule(module) + NSModule module; +{ +/* There should probably be an apple dyld api for this */ + int i=_dyld_image_count(); + int j; + const char *modname=NSNameOfModule(module); + const struct mach_header *mh=NULL; + if (!modname) return NULL; + for (j = 0; j < i; j++) + { + if (!strcmp(_dyld_get_image_name(j),modname)) + { + mh=_dyld_get_image_header(j); + break; + } + } + return mh; +} + +static const char* lt_int_dyld_lib_install_name(mh) + const struct mach_header *mh; +{ +/* NSAddImage is also used to get the loaded image, but it only works if the lib + is installed, for uninstalled libs we need to check the install_names against + each other. Note that this is still broken if DYLD_IMAGE_SUFFIX is set and a + different lib was loaded as a result +*/ + int j; + struct load_command *lc; + unsigned long offset = sizeof(struct mach_header); + const char* retStr=NULL; + for (j = 0; j < mh->ncmds; j++) + { + lc = (struct load_command*)(((unsigned long)mh) + offset); + if (LC_ID_DYLIB == lc->cmd) + { + retStr=(char*)(((struct dylib_command*)lc)->dylib.name.offset + + (unsigned long)lc); + } + offset += lc->cmdsize; + } + return retStr; +} + +static const struct mach_header * +lt_int_dyld_match_loaded_lib_by_install_name(const char *name) +{ + int i=_dyld_image_count(); + int j; + const struct mach_header *mh=NULL; + const char *id=NULL; + for (j = 0; j < i; j++) + { + id=lt_int_dyld_lib_install_name(_dyld_get_image_header(j)); + if ((id) && (!strcmp(id,name))) + { + mh=_dyld_get_image_header(j); + break; + } + } + return mh; +} + +static NSSymbol +lt_int_dyld_NSlookupSymbolInLinkedLibs(symbol,mh) + const char *symbol; + const struct mach_header *mh; +{ + /* Safe to assume our mh is good */ + int j; + struct load_command *lc; + unsigned long offset = sizeof(struct mach_header); + NSSymbol retSym = 0; + const struct mach_header *mh1; + if ((ltdl_NSLookupSymbolInImage) && NSIsSymbolNameDefined(symbol) ) + { + for (j = 0; j < mh->ncmds; j++) + { + lc = (struct load_command*)(((unsigned long)mh) + offset); + if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd)) + { + mh1=lt_int_dyld_match_loaded_lib_by_install_name((char*)(((struct dylib_command*)lc)->dylib.name.offset + + (unsigned long)lc)); + if (!mh1) + { + /* Maybe NSAddImage can find it */ + mh1=ltdl_NSAddImage((char*)(((struct dylib_command*)lc)->dylib.name.offset + + (unsigned long)lc), + NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED + + NSADDIMAGE_OPTION_WITH_SEARCHING + + NSADDIMAGE_OPTION_RETURN_ON_ERROR ); + } + if (mh1) + { + retSym = ltdl_NSLookupSymbolInImage(mh1, + symbol, + NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW + | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR + ); + if (retSym) break; + } + } + offset += lc->cmdsize; + } + } + return retSym; +} + +static int +sys_dyld_init() +{ + int retCode = 0; + int err = 0; + if (!_dyld_present()) { + retCode=1; + } + else { + err = _dyld_func_lookup("__dyld_NSAddImage",(unsigned long*)<dl_NSAddImage); + err = _dyld_func_lookup("__dyld_NSLookupSymbolInImage",(unsigned long*)<dl_NSLookupSymbolInImage); + err = _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage",(unsigned long*)<dl_NSIsSymbolNameDefinedInImage); + err = _dyld_func_lookup("__dyld_NSMakePrivateModulePublic",(unsigned long*)<dl_NSMakePrivateModulePublic); + } + return retCode; +} + +static lt_module +sys_dyld_open (loader_data, filename) + lt_user_data loader_data; + const char *filename; +{ + lt_module module = 0; + NSObjectFileImage ofi = 0; + NSObjectFileImageReturnCode ofirc; + + if (!filename) + return (lt_module)-1; + ofirc = NSCreateObjectFileImageFromFile(filename, &ofi); + switch (ofirc) + { + case NSObjectFileImageSuccess: + module = NSLinkModule(ofi, filename, + NSLINKMODULE_OPTION_RETURN_ON_ERROR + | NSLINKMODULE_OPTION_PRIVATE + | NSLINKMODULE_OPTION_BINDNOW); + NSDestroyObjectFileImage(ofi); + if (module) + ltdl_NSMakePrivateModulePublic(module); + break; + case NSObjectFileImageInappropriateFile: + if (ltdl_NSIsSymbolNameDefinedInImage && ltdl_NSLookupSymbolInImage) + { + module = (lt_module)ltdl_NSAddImage(filename, NSADDIMAGE_OPTION_RETURN_ON_ERROR); + break; + } + default: + LT_DLMUTEX_SETERROR (lt_int_dyld_error(LT_DLSTRERROR(CANNOT_OPEN))); + return 0; + } + if (!module) LT_DLMUTEX_SETERROR (lt_int_dyld_error(LT_DLSTRERROR(CANNOT_OPEN))); + return module; +} + +static int +sys_dyld_close (loader_data, module) + lt_user_data loader_data; + lt_module module; +{ + int retCode = 0; + int flags = 0; + if (module == (lt_module)-1) return 0; +#ifdef __BIG_ENDIAN__ + if (((struct mach_header *)module)->magic == MH_MAGIC) +#else + if (((struct mach_header *)module)->magic == MH_CIGAM) +#endif + { + LT_DLMUTEX_SETERROR("Can not close a dylib"); + retCode = 1; + } + else + { +#if 1 +/* Currently, if a module contains c++ static destructors and it is unloaded, we + get a segfault in atexit(), due to compiler and dynamic loader differences of + opinion, this works around that. +*/ + if ((const struct section *)NULL != + getsectbynamefromheader(lt_int_dyld_get_mach_header_from_nsmodule(module), + "__DATA","__mod_term_func")) + { + flags += NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED; + } +#endif +#ifdef __ppc__ + flags += NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES; +#endif + if (!NSUnLinkModule(module,flags)) + { + retCode=1; + LT_DLMUTEX_SETERROR (lt_int_dyld_error(LT_DLSTRERROR(CANNOT_CLOSE))); + } + } + + return retCode; +} + +static lt_ptr +sys_dyld_sym (loader_data, module, symbol) + lt_user_data loader_data; + lt_module module; + const char *symbol; +{ + lt_ptr address = 0; + NSSymbol *nssym = 0; + void *unused; + const struct mach_header *mh=NULL; + char saveError[256] = "Symbol not found"; + if (module == (lt_module)-1) + { + _dyld_lookup_and_bind(symbol,(unsigned long*)&address,&unused); + return address; + } +#ifdef __BIG_ENDIAN__ + if (((struct mach_header *)module)->magic == MH_MAGIC) +#else + if (((struct mach_header *)module)->magic == MH_CIGAM) +#endif + { + if (ltdl_NSIsSymbolNameDefinedInImage && ltdl_NSLookupSymbolInImage) + { + mh=module; + if (ltdl_NSIsSymbolNameDefinedInImage((struct mach_header*)module,symbol)) + { + nssym = ltdl_NSLookupSymbolInImage((struct mach_header*)module, + symbol, + NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW + | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR + ); + } + } + + } + else { + nssym = NSLookupSymbolInModule(module, symbol); + } + if (!nssym) + { + strncpy(saveError, lt_int_dyld_error(LT_DLSTRERROR(SYMBOL_NOT_FOUND)), 255); + saveError[255] = 0; + if (!mh) mh=lt_int_dyld_get_mach_header_from_nsmodule(module); + nssym = lt_int_dyld_NSlookupSymbolInLinkedLibs(symbol,mh); + } + if (!nssym) + { + LT_DLMUTEX_SETERROR (saveError); + return NULL; + } + return NSAddressOfSymbol(nssym); +} + +static struct lt_user_dlloader sys_dyld = + { "_", sys_dyld_open, sys_dyld_close, sys_dyld_sym, 0, 0 }; + + +#endif /* HAVE_DYLD */ + + +/* --- DLPREOPEN() INTERFACE LOADER --- */ + + +/* emulate dynamic linking using preloaded_symbols */ + +typedef struct lt_dlsymlists_t +{ + struct lt_dlsymlists_t *next; + const lt_dlsymlist *syms; +} lt_dlsymlists_t; + +static const lt_dlsymlist *default_preloaded_symbols = 0; +static lt_dlsymlists_t *preloaded_symbols = 0; + +static int +presym_init (loader_data) + lt_user_data loader_data; +{ + int errors = 0; + + LT_DLMUTEX_LOCK (); + + preloaded_symbols = 0; + if (default_preloaded_symbols) + { + errors = lt_dlpreload (default_preloaded_symbols); + } + + LT_DLMUTEX_UNLOCK (); + + return errors; +} + +static int +presym_free_symlists () +{ + lt_dlsymlists_t *lists; + + LT_DLMUTEX_LOCK (); + + lists = preloaded_symbols; + while (lists) + { + lt_dlsymlists_t *tmp = lists; + + lists = lists->next; + LT_DLFREE (tmp); + } + preloaded_symbols = 0; + + LT_DLMUTEX_UNLOCK (); + + return 0; +} + +static int +presym_exit (loader_data) + lt_user_data loader_data; +{ + presym_free_symlists (); + return 0; +} + +static int +presym_add_symlist (preloaded) + const lt_dlsymlist *preloaded; +{ + lt_dlsymlists_t *tmp; + lt_dlsymlists_t *lists; + int errors = 0; + + LT_DLMUTEX_LOCK (); + + lists = preloaded_symbols; + while (lists) + { + if (lists->syms == preloaded) + { + goto done; + } + lists = lists->next; + } + + tmp = LT_EMALLOC (lt_dlsymlists_t, 1); + if (tmp) + { + memset (tmp, 0, sizeof(lt_dlsymlists_t)); + tmp->syms = preloaded; + tmp->next = preloaded_symbols; + preloaded_symbols = tmp; + } + else + { + ++errors; + } + + done: + LT_DLMUTEX_UNLOCK (); + return errors; +} + +static lt_module +presym_open (loader_data, filename) + lt_user_data loader_data; + const char *filename; +{ + lt_dlsymlists_t *lists; + lt_module module = (lt_module) 0; + + LT_DLMUTEX_LOCK (); + lists = preloaded_symbols; + + if (!lists) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_SYMBOLS)); + goto done; + } + + /* Can't use NULL as the reflective symbol header, as NULL is + used to mark the end of the entire symbol list. Self-dlpreopened + symbols follow this magic number, chosen to be an unlikely + clash with a real module name. */ + if (!filename) + { + filename = "@PROGRAM@"; + } + + while (lists) + { + const lt_dlsymlist *syms = lists->syms; + + while (syms->name) + { + if (!syms->address && strcmp(syms->name, filename) == 0) + { + module = (lt_module) syms; + goto done; + } + ++syms; + } + + lists = lists->next; + } + + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); + + done: + LT_DLMUTEX_UNLOCK (); + return module; +} + +static int +presym_close (loader_data, module) + lt_user_data loader_data; + lt_module module; +{ + /* Just to silence gcc -Wall */ + module = 0; + return 0; +} + +static lt_ptr +presym_sym (loader_data, module, symbol) + lt_user_data loader_data; + lt_module module; + const char *symbol; +{ + lt_dlsymlist *syms = (lt_dlsymlist*) module; + + ++syms; + while (syms->address) + { + if (strcmp(syms->name, symbol) == 0) + { + return syms->address; + } + + ++syms; + } + + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); + + return 0; +} + +static struct lt_user_dlloader presym = { + 0, presym_open, presym_close, presym_sym, presym_exit, 0 +}; + + + + + +/* --- DYNAMIC MODULE LOADING --- */ + + +/* The type of a function used at each iteration of foreach_dirinpath(). */ +typedef int foreach_callback_func LT_PARAMS((char *filename, lt_ptr data1, + lt_ptr data2)); + +static int foreach_dirinpath LT_PARAMS((const char *search_path, + const char *base_name, + foreach_callback_func *func, + lt_ptr data1, lt_ptr data2)); + +static int find_file_callback LT_PARAMS((char *filename, lt_ptr data, + lt_ptr ignored)); +static int find_handle_callback LT_PARAMS((char *filename, lt_ptr data, + lt_ptr ignored)); +static int foreachfile_callback LT_PARAMS((char *filename, lt_ptr data1, + lt_ptr data2)); + + +static int canonicalize_path LT_PARAMS((const char *path, + char **pcanonical)); +static int argzize_path LT_PARAMS((const char *path, + char **pargz, + size_t *pargz_len)); +static FILE *find_file LT_PARAMS((const char *search_path, + const char *base_name, + char **pdir)); +static lt_dlhandle *find_handle LT_PARAMS((const char *search_path, + const char *base_name, + lt_dlhandle *handle)); +static int find_module LT_PARAMS((lt_dlhandle *handle, + const char *dir, + const char *libdir, + const char *dlname, + const char *old_name, + int installed)); +static int free_vars LT_PARAMS((char *dlname, char *oldname, + char *libdir, char *deplibs)); +static int load_deplibs LT_PARAMS((lt_dlhandle handle, + char *deplibs)); +static int trim LT_PARAMS((char **dest, + const char *str)); +static int try_dlopen LT_PARAMS((lt_dlhandle *handle, + const char *filename)); +static int tryall_dlopen LT_PARAMS((lt_dlhandle *handle, + const char *filename)); +static int unload_deplibs LT_PARAMS((lt_dlhandle handle)); +static int lt_argz_insert LT_PARAMS((char **pargz, + size_t *pargz_len, + char *before, + const char *entry)); +static int lt_argz_insertinorder LT_PARAMS((char **pargz, + size_t *pargz_len, + const char *entry)); +static int lt_argz_insertdir LT_PARAMS((char **pargz, + size_t *pargz_len, + const char *dirnam, + struct dirent *dp)); +static int lt_dlpath_insertdir LT_PARAMS((char **ppath, + char *before, + const char *dir)); +static int list_files_by_dir LT_PARAMS((const char *dirnam, + char **pargz, + size_t *pargz_len)); +static int file_not_found LT_PARAMS((void)); + +static char *user_search_path= 0; +static lt_dlloader *loaders = 0; +static lt_dlhandle handles = 0; +static int initialized = 0; + +/* Initialize libltdl. */ +int +lt_dlinit () +{ + int errors = 0; + + LT_DLMUTEX_LOCK (); + + /* Initialize only at first call. */ + if (++initialized == 1) + { + handles = 0; + user_search_path = 0; /* empty search path */ + +#if HAVE_LIBDL + errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dl, "dlopen"); +#endif +#if HAVE_SHL_LOAD + errors += lt_dlloader_add (lt_dlloader_next (0), &sys_shl, "dlopen"); +#endif +#ifdef __WINDOWS__ + errors += lt_dlloader_add (lt_dlloader_next (0), &sys_wll, "dlopen"); +#endif +#ifdef __BEOS__ + errors += lt_dlloader_add (lt_dlloader_next (0), &sys_bedl, "dlopen"); +#endif +#if HAVE_DLD + errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dld, "dld"); +#endif +#if HAVE_DYLD + errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dyld, "dyld"); + errors += sys_dyld_init(); +#endif + errors += lt_dlloader_add (lt_dlloader_next (0), &presym, "dlpreload"); + + if (presym_init (presym.dlloader_data)) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INIT_LOADER)); + ++errors; + } + else if (errors != 0) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (DLOPEN_NOT_SUPPORTED)); + ++errors; + } + } + + LT_DLMUTEX_UNLOCK (); + + return errors; +} + +int +lt_dlpreload (preloaded) + const lt_dlsymlist *preloaded; +{ + int errors = 0; + + if (preloaded) + { + errors = presym_add_symlist (preloaded); + } + else + { + presym_free_symlists(); + + LT_DLMUTEX_LOCK (); + if (default_preloaded_symbols) + { + errors = lt_dlpreload (default_preloaded_symbols); + } + LT_DLMUTEX_UNLOCK (); + } + + return errors; +} + +int +lt_dlpreload_default (preloaded) + const lt_dlsymlist *preloaded; +{ + LT_DLMUTEX_LOCK (); + default_preloaded_symbols = preloaded; + LT_DLMUTEX_UNLOCK (); + return 0; +} + +int +lt_dlexit () +{ + /* shut down libltdl */ + lt_dlloader *loader; + int errors = 0; + + LT_DLMUTEX_LOCK (); + loader = loaders; + + if (!initialized) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SHUTDOWN)); + ++errors; + goto done; + } + + /* shut down only at last call. */ + if (--initialized == 0) + { + int level; + + while (handles && LT_DLIS_RESIDENT (handles)) + { + handles = handles->next; + } + + /* close all modules */ + for (level = 1; handles; ++level) + { + lt_dlhandle cur = handles; + int saw_nonresident = 0; + + while (cur) + { + lt_dlhandle tmp = cur; + cur = cur->next; + if (!LT_DLIS_RESIDENT (tmp)) + saw_nonresident = 1; + if (!LT_DLIS_RESIDENT (tmp) && tmp->info.ref_count <= level) + { + if (lt_dlclose (tmp)) + { + ++errors; + } + /* Make sure that the handle pointed to by 'cur' still exists. + lt_dlclose recursively closes dependent libraries which removes + them from the linked list. One of these might be the one + pointed to by 'cur'. */ + if (cur) + { + for (tmp = handles; tmp; tmp = tmp->next) + if (tmp == cur) + break; + if (! tmp) + cur = handles; + } + } + } + /* done if only resident modules are left */ + if (!saw_nonresident) + break; + } + + /* close all loaders */ + while (loader) + { + lt_dlloader *next = loader->next; + lt_user_data data = loader->dlloader_data; + if (loader->dlloader_exit && loader->dlloader_exit (data)) + { + ++errors; + } + + LT_DLMEM_REASSIGN (loader, next); + } + loaders = 0; + } + + done: + LT_DLMUTEX_UNLOCK (); + return errors; +} + +static int +tryall_dlopen (handle, filename) + lt_dlhandle *handle; + const char *filename; +{ + lt_dlhandle cur; + lt_dlloader *loader; + const char *saved_error; + int errors = 0; + + LT_DLMUTEX_GETERROR (saved_error); + LT_DLMUTEX_LOCK (); + + cur = handles; + loader = loaders; + + /* check whether the module was already opened */ + while (cur) + { + /* try to dlopen the program itself? */ + if (!cur->info.filename && !filename) + { + break; + } + + if (cur->info.filename && filename + && strcmp (cur->info.filename, filename) == 0) + { + break; + } + + cur = cur->next; + } + + if (cur) + { + ++cur->info.ref_count; + *handle = cur; + goto done; + } + + cur = *handle; + if (filename) + { + /* Comment out the check of file permissions using access. + This call seems to always return -1 with error EACCES. + */ + /* We need to catch missing file errors early so that + file_not_found() can detect what happened. + if (access (filename, R_OK) != 0) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); + ++errors; + goto done; + } */ + + cur->info.filename = lt_estrdup (filename); + if (!cur->info.filename) + { + ++errors; + goto done; + } + } + else + { + cur->info.filename = 0; + } + + while (loader) + { + lt_user_data data = loader->dlloader_data; + + cur->module = loader->module_open (data, filename); + + if (cur->module != 0) + { + break; + } + loader = loader->next; + } + + if (!loader) + { + LT_DLFREE (cur->info.filename); + ++errors; + goto done; + } + + cur->loader = loader; + LT_DLMUTEX_SETERROR (saved_error); + + done: + LT_DLMUTEX_UNLOCK (); + + return errors; +} + +static int +tryall_dlopen_module (handle, prefix, dirname, dlname) + lt_dlhandle *handle; + const char *prefix; + const char *dirname; + const char *dlname; +{ + int error = 0; + char *filename = 0; + size_t filename_len = 0; + size_t dirname_len = LT_STRLEN (dirname); + + assert (handle); + assert (dirname); + assert (dlname); +#ifdef LT_DIRSEP_CHAR + /* Only canonicalized names (i.e. with DIRSEP chars already converted) + should make it into this function: */ + assert (strchr (dirname, LT_DIRSEP_CHAR) == 0); +#endif + + if (dirname_len > 0) + if (dirname[dirname_len -1] == '/') + --dirname_len; + filename_len = dirname_len + 1 + LT_STRLEN (dlname); + + /* Allocate memory, and combine DIRNAME and MODULENAME into it. + The PREFIX (if any) is handled below. */ + filename = LT_EMALLOC (char, dirname_len + 1 + filename_len + 1); + if (!filename) + return 1; + + sprintf (filename, "%.*s/%s", (int) dirname_len, dirname, dlname); + + /* Now that we have combined DIRNAME and MODULENAME, if there is + also a PREFIX to contend with, simply recurse with the arguments + shuffled. Otherwise, attempt to open FILENAME as a module. */ + if (prefix) + { + error += tryall_dlopen_module (handle, + (const char *) 0, prefix, filename); + } + else if (tryall_dlopen (handle, filename) != 0) + { + ++error; + } + + LT_DLFREE (filename); + return error; +} + +static int +find_module (handle, dir, libdir, dlname, old_name, installed) + lt_dlhandle *handle; + const char *dir; + const char *libdir; + const char *dlname; + const char *old_name; + int installed; +{ + /* Try to open the old library first; if it was dlpreopened, + we want the preopened version of it, even if a dlopenable + module is available. */ + if (old_name && tryall_dlopen (handle, old_name) == 0) + { + return 0; + } + + /* Try to open the dynamic library. */ + if (dlname) + { + /* try to open the installed module */ + if (installed && libdir) + { + if (tryall_dlopen_module (handle, + (const char *) 0, libdir, dlname) == 0) + return 0; + } + + /* try to open the not-installed module */ + if (!installed) + { + if (tryall_dlopen_module (handle, dir, objdir, dlname) == 0) + return 0; + } + + /* maybe it was moved to another directory */ + { + if (dir && (tryall_dlopen_module (handle, + (const char *) 0, dir, dlname) == 0)) + return 0; + } + } + + return 1; +} + + +static int +canonicalize_path (path, pcanonical) + const char *path; + char **pcanonical; +{ + char *canonical = 0; + + assert (path && *path); + assert (pcanonical); + + canonical = LT_EMALLOC (char, 1+ LT_STRLEN (path)); + if (!canonical) + return 1; + + { + size_t dest = 0; + size_t src; + for (src = 0; path[src] != LT_EOS_CHAR; ++src) + { + /* Path separators are not copied to the beginning or end of + the destination, or if another separator would follow + immediately. */ + if (path[src] == LT_PATHSEP_CHAR) + { + if ((dest == 0) + || (path[1+ src] == LT_PATHSEP_CHAR) + || (path[1+ src] == LT_EOS_CHAR)) + continue; + } + + /* Anything other than a directory separator is copied verbatim. */ + if ((path[src] != '/') +#ifdef LT_DIRSEP_CHAR + && (path[src] != LT_DIRSEP_CHAR) +#endif + ) + { + canonical[dest++] = path[src]; + } + /* Directory separators are converted and copied only if they are + not at the end of a path -- i.e. before a path separator or + NULL terminator. */ + else if ((path[1+ src] != LT_PATHSEP_CHAR) + && (path[1+ src] != LT_EOS_CHAR) +#ifdef LT_DIRSEP_CHAR + && (path[1+ src] != LT_DIRSEP_CHAR) +#endif + && (path[1+ src] != '/')) + { + canonical[dest++] = '/'; + } + } + + /* Add an end-of-string marker at the end. */ + canonical[dest] = LT_EOS_CHAR; + } + + /* Assign new value. */ + *pcanonical = canonical; + + return 0; +} + +static int +argzize_path (path, pargz, pargz_len) + const char *path; + char **pargz; + size_t *pargz_len; +{ + error_t error; + + assert (path); + assert (pargz); + assert (pargz_len); + + if ((error = argz_create_sep (path, LT_PATHSEP_CHAR, pargz, pargz_len))) + { + switch (error) + { + case ENOMEM: + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); + break; + default: + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN)); + break; + } + + return 1; + } + + return 0; +} + +/* Repeatedly call FUNC with each LT_PATHSEP_CHAR delimited element + of SEARCH_PATH and references to DATA1 and DATA2, until FUNC returns + non-zero or all elements are exhausted. If BASE_NAME is non-NULL, + it is appended to each SEARCH_PATH element before FUNC is called. */ +static int +foreach_dirinpath (search_path, base_name, func, data1, data2) + const char *search_path; + const char *base_name; + foreach_callback_func *func; + lt_ptr data1; + lt_ptr data2; +{ + int result = 0; + int filenamesize = 0; + size_t lenbase = LT_STRLEN (base_name); + size_t argz_len = 0; + char *argz = 0; + char *filename = 0; + char *canonical = 0; + + LT_DLMUTEX_LOCK (); + + if (!search_path || !*search_path) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); + goto cleanup; + } + + if (canonicalize_path (search_path, &canonical) != 0) + goto cleanup; + + if (argzize_path (canonical, &argz, &argz_len) != 0) + goto cleanup; + + { + char *dir_name = 0; + while ((dir_name = argz_next (argz, argz_len, dir_name))) + { + size_t lendir = LT_STRLEN (dir_name); + + if (lendir +1 +lenbase >= filenamesize) + { + LT_DLFREE (filename); + filenamesize = lendir +1 +lenbase +1; /* "/d" + '/' + "f" + '\0' */ + filename = LT_EMALLOC (char, filenamesize); + if (!filename) + goto cleanup; + } + + assert (filenamesize > lendir); + strcpy (filename, dir_name); + + if (base_name && *base_name) + { + if (filename[lendir -1] != '/') + filename[lendir++] = '/'; + strcpy (filename +lendir, base_name); + } + + if ((result = (*func) (filename, data1, data2))) + { + break; + } + } + } + + cleanup: + LT_DLFREE (argz); + LT_DLFREE (canonical); + LT_DLFREE (filename); + + LT_DLMUTEX_UNLOCK (); + + return result; +} + +/* If FILEPATH can be opened, store the name of the directory component + in DATA1, and the opened FILE* structure address in DATA2. Otherwise + DATA1 is unchanged, but DATA2 is set to a pointer to NULL. */ +static int +find_file_callback (filename, data1, data2) + char *filename; + lt_ptr data1; + lt_ptr data2; +{ + char **pdir = (char **) data1; + FILE **pfile = (FILE **) data2; + int is_done = 0; + + assert (filename && *filename); + assert (pdir); + assert (pfile); + + if ((*pfile = fopen (filename, LT_READTEXT_MODE))) + { + char *dirend = strrchr (filename, '/'); + + if (dirend > filename) + *dirend = LT_EOS_CHAR; + + LT_DLFREE (*pdir); + *pdir = lt_estrdup (filename); + is_done = (*pdir == 0) ? -1 : 1; + } + + return is_done; +} + +static FILE * +find_file (search_path, base_name, pdir) + const char *search_path; + const char *base_name; + char **pdir; +{ + FILE *file = 0; + + foreach_dirinpath (search_path, base_name, find_file_callback, pdir, &file); + + return file; +} + +static int +find_handle_callback (filename, data, ignored) + char *filename; + lt_ptr data; + lt_ptr ignored; +{ + lt_dlhandle *handle = (lt_dlhandle *) data; + int notfound = access (filename, R_OK); + + /* Bail out if file cannot be read... */ + if (notfound) + return 0; + + /* Try to dlopen the file, but do not continue searching in any + case. */ + if (tryall_dlopen (handle, filename) != 0) + *handle = 0; + + return 1; +} + +/* If HANDLE was found return it, otherwise return 0. If HANDLE was + found but could not be opened, *HANDLE will be set to 0. */ +static lt_dlhandle * +find_handle (search_path, base_name, handle) + const char *search_path; + const char *base_name; + lt_dlhandle *handle; +{ + if (!search_path) + return 0; + + if (!foreach_dirinpath (search_path, base_name, find_handle_callback, + handle, 0)) + return 0; + + return handle; +} + +static int +load_deplibs (handle, deplibs) + lt_dlhandle handle; + char *deplibs; +{ +#if LTDL_DLOPEN_DEPLIBS + char *p, *save_search_path = 0; + int depcount = 0; + int i; + char **names = 0; +#endif + int errors = 0; + + handle->depcount = 0; + +#if LTDL_DLOPEN_DEPLIBS + if (!deplibs) + { + return errors; + } + ++errors; + + LT_DLMUTEX_LOCK (); + if (user_search_path) + { + save_search_path = lt_estrdup (user_search_path); + if (!save_search_path) + goto cleanup; + } + + /* extract search paths and count deplibs */ + p = deplibs; + while (*p) + { + if (!isspace ((int) *p)) + { + char *end = p+1; + while (*end && !isspace((int) *end)) + { + ++end; + } + + if (strncmp(p, "-L", 2) == 0 || strncmp(p, "-R", 2) == 0) + { + char save = *end; + *end = 0; /* set a temporary string terminator */ + if (lt_dladdsearchdir(p+2)) + { + goto cleanup; + } + *end = save; + } + else + { + ++depcount; + } + + p = end; + } + else + { + ++p; + } + } + + if (!depcount) + { + errors = 0; + goto cleanup; + } + + names = LT_EMALLOC (char *, depcount * sizeof (char*)); + if (!names) + goto cleanup; + + /* now only extract the actual deplibs */ + depcount = 0; + p = deplibs; + while (*p) + { + if (isspace ((int) *p)) + { + ++p; + } + else + { + char *end = p+1; + while (*end && !isspace ((int) *end)) + { + ++end; + } + + if (strncmp(p, "-L", 2) != 0 && strncmp(p, "-R", 2) != 0) + { + char *name; + char save = *end; + *end = 0; /* set a temporary string terminator */ + if (strncmp(p, "-l", 2) == 0) + { + size_t name_len = 3+ /* "lib" */ LT_STRLEN (p + 2); + name = LT_EMALLOC (char, 1+ name_len); + if (name) + sprintf (name, "lib%s", p+2); + } + else + name = lt_estrdup(p); + + if (!name) + goto cleanup_names; + + names[depcount++] = name; + *end = save; + } + p = end; + } + } + + /* load the deplibs (in reverse order) + At this stage, don't worry if the deplibs do not load correctly, + they may already be statically linked into the loading application + for instance. There will be a more enlightening error message + later on if the loaded module cannot resolve all of its symbols. */ + if (depcount) + { + int j = 0; + + handle->deplibs = (lt_dlhandle*) LT_EMALLOC (lt_dlhandle *, depcount); + if (!handle->deplibs) + goto cleanup_names; + + for (i = 0; i < depcount; ++i) + { + handle->deplibs[j] = lt_dlopenext(names[depcount-1-i]); + if (handle->deplibs[j]) + { + ++j; + } + } + + handle->depcount = j; /* Number of successfully loaded deplibs */ + errors = 0; + } + + cleanup_names: + for (i = 0; i < depcount; ++i) + { + LT_DLFREE (names[i]); + } + + cleanup: + LT_DLFREE (names); + /* restore the old search path */ + if (user_search_path) { + LT_DLFREE (user_search_path); + user_search_path = save_search_path; + } + LT_DLMUTEX_UNLOCK (); + +#endif + + return errors; +} + +static int +unload_deplibs (handle) + lt_dlhandle handle; +{ + int i; + int errors = 0; + + if (handle->depcount) + { + for (i = 0; i < handle->depcount; ++i) + { + if (!LT_DLIS_RESIDENT (handle->deplibs[i])) + { + errors += lt_dlclose (handle->deplibs[i]); + } + } + LT_DLFREE (handle->deplibs); + } + + return errors; +} + +static int +trim (dest, str) + char **dest; + const char *str; +{ + /* remove the leading and trailing "'" from str + and store the result in dest */ + const char *end = strrchr (str, '\''); + size_t len = LT_STRLEN (str); + char *tmp; + + LT_DLFREE (*dest); + + if (!end) + return 1; + + if (len > 3 && str[0] == '\'') + { + tmp = LT_EMALLOC (char, end - str); + if (!tmp) + return 1; + + strncpy(tmp, &str[1], (end - str) - 1); + tmp[len-3] = LT_EOS_CHAR; + *dest = tmp; + } + else + { + *dest = 0; + } + + return 0; +} + +static int +free_vars (dlname, oldname, libdir, deplibs) + char *dlname; + char *oldname; + char *libdir; + char *deplibs; +{ + LT_DLFREE (dlname); + LT_DLFREE (oldname); + LT_DLFREE (libdir); + LT_DLFREE (deplibs); + + return 0; +} + +static int +try_dlopen (phandle, filename) + lt_dlhandle *phandle; + const char *filename; +{ + const char * ext = 0; + const char * saved_error = 0; + char * canonical = 0; + char * base_name = 0; + char * dir = 0; + char * name = 0; + int errors = 0; + lt_dlhandle newhandle; + + assert (phandle); + assert (*phandle == 0); + + LT_DLMUTEX_GETERROR (saved_error); + + /* dlopen self? */ + if (!filename) + { + *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1); + if (*phandle == 0) + return 1; + + memset (*phandle, 0, sizeof(struct lt_dlhandle_struct)); + newhandle = *phandle; + + /* lt_dlclose()ing yourself is very bad! Disallow it. */ + LT_DLSET_FLAG (*phandle, LT_DLRESIDENT_FLAG); + + if (tryall_dlopen (&newhandle, 0) != 0) + { + LT_DLFREE (*phandle); + return 1; + } + + goto register_handle; + } + + assert (filename && *filename); + + /* Doing this immediately allows internal functions to safely + assume only canonicalized paths are passed. */ + if (canonicalize_path (filename, &canonical) != 0) + { + ++errors; + goto cleanup; + } + + /* If the canonical module name is a path (relative or absolute) + then split it into a directory part and a name part. */ + base_name = strrchr (canonical, '/'); + if (base_name) + { + size_t dirlen = (1+ base_name) - canonical; + + dir = LT_EMALLOC (char, 1+ dirlen); + if (!dir) + { + ++errors; + goto cleanup; + } + + strncpy (dir, canonical, dirlen); + dir[dirlen] = LT_EOS_CHAR; + + ++base_name; + } + else + base_name = canonical; + + assert (base_name && *base_name); + + /* Check whether we are opening a libtool module (.la extension). */ + ext = strrchr (base_name, '.'); + if (ext && strcmp (ext, archive_ext) == 0) + { + /* this seems to be a libtool module */ + FILE * file = 0; + char * dlname = 0; + char * old_name = 0; + char * libdir = 0; + char * deplibs = 0; + char * line = 0; + size_t line_len; + + /* if we can't find the installed flag, it is probably an + installed libtool archive, produced with an old version + of libtool */ + int installed = 1; + + /* extract the module name from the file name */ + name = LT_EMALLOC (char, ext - base_name + 1); + if (!name) + { + ++errors; + goto cleanup; + } + + /* canonicalize the module name */ + { + size_t i; + for (i = 0; i < ext - base_name; ++i) + { + if (isalnum ((int)(base_name[i]))) + { + name[i] = base_name[i]; + } + else + { + name[i] = '_'; + } + } + name[ext - base_name] = LT_EOS_CHAR; + } + + /* Now try to open the .la file. If there is no directory name + component, try to find it first in user_search_path and then other + prescribed paths. Otherwise (or in any case if the module was not + yet found) try opening just the module name as passed. */ + if (!dir) + { + const char *search_path; + + LT_DLMUTEX_LOCK (); + search_path = user_search_path; + if (search_path) + file = find_file (user_search_path, base_name, &dir); + LT_DLMUTEX_UNLOCK (); + + if (!file) + { + search_path = getenv (LTDL_SEARCHPATH_VAR); + if (search_path) + file = find_file (search_path, base_name, &dir); + } + +#ifdef LTDL_SHLIBPATH_VAR + if (!file) + { + search_path = getenv (LTDL_SHLIBPATH_VAR); + if (search_path) + file = find_file (search_path, base_name, &dir); + } +#endif +#ifdef LTDL_SYSSEARCHPATH + if (!file && sys_search_path) + { + file = find_file (sys_search_path, base_name, &dir); + } +#endif + } + if (!file) + { + file = fopen (filename, LT_READTEXT_MODE); + } + + /* If we didn't find the file by now, it really isn't there. Set + the status flag, and bail out. */ + if (!file) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); + ++errors; + goto cleanup; + } + + line_len = LT_FILENAME_MAX; + line = LT_EMALLOC (char, line_len); + if (!line) + { + fclose (file); + ++errors; + goto cleanup; + } + + /* read the .la file */ + while (!feof (file)) + { + if (!fgets (line, (int) line_len, file)) + { + break; + } + + /* Handle the case where we occasionally need to read a line + that is longer than the initial buffer size. */ + while ((line[LT_STRLEN(line) -1] != '\n') && (!feof (file))) + { + line = LT_DLREALLOC (char, line, line_len *2); + if (!fgets (&line[line_len -1], (int) line_len +1, file)) + { + break; + } + line_len *= 2; + } + + if (line[0] == '\n' || line[0] == '#') + { + continue; + } + +#undef STR_DLNAME +#define STR_DLNAME "dlname=" + if (strncmp (line, STR_DLNAME, sizeof (STR_DLNAME) - 1) == 0) + { + errors += trim (&dlname, &line[sizeof (STR_DLNAME) - 1]); + } + +#undef STR_OLD_LIBRARY +#define STR_OLD_LIBRARY "old_library=" + else if (strncmp (line, STR_OLD_LIBRARY, + sizeof (STR_OLD_LIBRARY) - 1) == 0) + { + errors += trim (&old_name, &line[sizeof (STR_OLD_LIBRARY) - 1]); + } +#undef STR_LIBDIR +#define STR_LIBDIR "libdir=" + else if (strncmp (line, STR_LIBDIR, sizeof (STR_LIBDIR) - 1) == 0) + { + errors += trim (&libdir, &line[sizeof(STR_LIBDIR) - 1]); + } + +#undef STR_DL_DEPLIBS +#define STR_DL_DEPLIBS "dependency_libs=" + else if (strncmp (line, STR_DL_DEPLIBS, + sizeof (STR_DL_DEPLIBS) - 1) == 0) + { + errors += trim (&deplibs, &line[sizeof (STR_DL_DEPLIBS) - 1]); + } + else if (strcmp (line, "installed=yes\n") == 0) + { + installed = 1; + } + else if (strcmp (line, "installed=no\n") == 0) + { + installed = 0; + } + +#undef STR_LIBRARY_NAMES +#define STR_LIBRARY_NAMES "library_names=" + else if (! dlname && strncmp (line, STR_LIBRARY_NAMES, + sizeof (STR_LIBRARY_NAMES) - 1) == 0) + { + char *last_libname; + errors += trim (&dlname, &line[sizeof (STR_LIBRARY_NAMES) - 1]); + if (!errors + && dlname + && (last_libname = strrchr (dlname, ' ')) != 0) + { + last_libname = lt_estrdup (last_libname + 1); + if (!last_libname) + { + ++errors; + goto cleanup; + } + LT_DLMEM_REASSIGN (dlname, last_libname); + } + } + + if (errors) + break; + } + + fclose (file); + LT_DLFREE (line); + + /* allocate the handle */ + *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1); + if (*phandle == 0) + ++errors; + + if (errors) + { + free_vars (dlname, old_name, libdir, deplibs); + LT_DLFREE (*phandle); + goto cleanup; + } + + assert (*phandle); + + memset (*phandle, 0, sizeof(struct lt_dlhandle_struct)); + if (load_deplibs (*phandle, deplibs) == 0) + { + newhandle = *phandle; + /* find_module may replace newhandle */ + if (find_module (&newhandle, dir, libdir, dlname, old_name, installed)) + { + unload_deplibs (*phandle); + ++errors; + } + } + else + { + ++errors; + } + + free_vars (dlname, old_name, libdir, deplibs); + if (errors) + { + LT_DLFREE (*phandle); + goto cleanup; + } + + if (*phandle != newhandle) + { + unload_deplibs (*phandle); + } + } + else + { + /* not a libtool module */ + *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1); + if (*phandle == 0) + { + ++errors; + goto cleanup; + } + + memset (*phandle, 0, sizeof (struct lt_dlhandle_struct)); + newhandle = *phandle; + + /* If the module has no directory name component, try to find it + first in user_search_path and then other prescribed paths. + Otherwise (or in any case if the module was not yet found) try + opening just the module name as passed. */ + if ((dir || (!find_handle (user_search_path, base_name, &newhandle) + && !find_handle (getenv (LTDL_SEARCHPATH_VAR), base_name, + &newhandle) +#ifdef LTDL_SHLIBPATH_VAR + && !find_handle (getenv (LTDL_SHLIBPATH_VAR), base_name, + &newhandle) +#endif +#ifdef LTDL_SYSSEARCHPATH + && !find_handle (sys_search_path, base_name, &newhandle) +#endif + ))) + { + if (tryall_dlopen (&newhandle, filename) != 0) + { + newhandle = NULL; + } + } + + if (!newhandle) + { + LT_DLFREE (*phandle); + ++errors; + goto cleanup; + } + } + + register_handle: + LT_DLMEM_REASSIGN (*phandle, newhandle); + + if ((*phandle)->info.ref_count == 0) + { + (*phandle)->info.ref_count = 1; + LT_DLMEM_REASSIGN ((*phandle)->info.name, name); + + LT_DLMUTEX_LOCK (); + (*phandle)->next = handles; + handles = *phandle; + LT_DLMUTEX_UNLOCK (); + } + + LT_DLMUTEX_SETERROR (saved_error); + + cleanup: + LT_DLFREE (dir); + LT_DLFREE (name); + LT_DLFREE (canonical); + + return errors; +} + +lt_dlhandle +lt_dlopen (filename) + const char *filename; +{ + lt_dlhandle handle = 0; + + /* Just incase we missed a code path in try_dlopen() that reports + an error, but forgets to reset handle... */ + if (try_dlopen (&handle, filename) != 0) + return 0; + + return handle; +} + +/* If the last error messge store was `FILE_NOT_FOUND', then return + non-zero. */ +static int +file_not_found () +{ + const char *error = 0; + + LT_DLMUTEX_GETERROR (error); + if (error == LT_DLSTRERROR (FILE_NOT_FOUND)) + return 1; + + return 0; +} + +/* If FILENAME has an ARCHIVE_EXT or SHLIB_EXT extension, try to + open the FILENAME as passed. Otherwise try appending ARCHIVE_EXT, + and if a file is still not found try again with SHLIB_EXT appended + instead. */ +lt_dlhandle +lt_dlopenext (filename) + const char *filename; +{ + lt_dlhandle handle = 0; + char * tmp = 0; + char * ext = 0; + size_t len; + int errors = 0; + + if (!filename) + { + return lt_dlopen (filename); + } + + assert (filename); + + len = LT_STRLEN (filename); + ext = strrchr (filename, '.'); + + /* If FILENAME already bears a suitable extension, there is no need + to try appending additional extensions. */ + if (ext && ((strcmp (ext, archive_ext) == 0) +#ifdef LTDL_SHLIB_EXT + || (strcmp (ext, shlib_ext) == 0) +#endif + )) + { + return lt_dlopen (filename); + } + + /* First try appending ARCHIVE_EXT. */ + tmp = LT_EMALLOC (char, len + LT_STRLEN (archive_ext) + 1); + if (!tmp) + return 0; + + strcpy (tmp, filename); + strcat (tmp, archive_ext); + errors = try_dlopen (&handle, tmp); + + /* If we found FILENAME, stop searching -- whether we were able to + load the file as a module or not. If the file exists but loading + failed, it is better to return an error message here than to + report FILE_NOT_FOUND when the alternatives (foo.so etc) are not + in the module search path. */ + if (handle || ((errors > 0) && !file_not_found ())) + { + LT_DLFREE (tmp); + return handle; + } + +#ifdef LTDL_SHLIB_EXT + /* Try appending SHLIB_EXT. */ + if (LT_STRLEN (shlib_ext) > LT_STRLEN (archive_ext)) + { + LT_DLFREE (tmp); + tmp = LT_EMALLOC (char, len + LT_STRLEN (shlib_ext) + 1); + if (!tmp) + return 0; + + strcpy (tmp, filename); + } + else + { + tmp[len] = LT_EOS_CHAR; + } + + strcat(tmp, shlib_ext); + errors = try_dlopen (&handle, tmp); + + /* As before, if the file was found but loading failed, return now + with the current error message. */ + if (handle || ((errors > 0) && !file_not_found ())) + { + LT_DLFREE (tmp); + return handle; + } +#endif + + /* Still here? Then we really did fail to locate any of the file + names we tried. */ + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); + LT_DLFREE (tmp); + return 0; +} + + +static int +lt_argz_insert (pargz, pargz_len, before, entry) + char **pargz; + size_t *pargz_len; + char *before; + const char *entry; +{ + error_t error; + + /* Prior to Sep 8, 2005, newlib had a bug where argz_insert(pargz, + pargz_len, NULL, entry) failed with EINVAL. */ + if (before) + error = argz_insert (pargz, pargz_len, before, entry); + else + error = argz_append (pargz, pargz_len, entry, 1 + LT_STRLEN (entry)); + + if (error) + { + switch (error) + { + case ENOMEM: + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); + break; + default: + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN)); + break; + } + return 1; + } + + return 0; +} + +static int +lt_argz_insertinorder (pargz, pargz_len, entry) + char **pargz; + size_t *pargz_len; + const char *entry; +{ + char *before = 0; + + assert (pargz); + assert (pargz_len); + assert (entry && *entry); + + if (*pargz) + while ((before = argz_next (*pargz, *pargz_len, before))) + { + int cmp = strcmp (entry, before); + + if (cmp < 0) break; + if (cmp == 0) return 0; /* No duplicates! */ + } + + return lt_argz_insert (pargz, pargz_len, before, entry); +} + +static int +lt_argz_insertdir (pargz, pargz_len, dirnam, dp) + char **pargz; + size_t *pargz_len; + const char *dirnam; + struct dirent *dp; +{ + char *buf = 0; + size_t buf_len = 0; + char *end = 0; + size_t end_offset = 0; + size_t dir_len = 0; + int errors = 0; + + assert (pargz); + assert (pargz_len); + assert (dp); + + dir_len = LT_STRLEN (dirnam); + end = dp->d_name + LT_D_NAMLEN(dp); + + /* Ignore version numbers. */ + { + char *p; + for (p = end; p -1 > dp->d_name; --p) + if (strchr (".0123456789", p[-1]) == 0) + break; + + if (*p == '.') + end = p; + } + + /* Ignore filename extension. */ + { + char *p; + for (p = end -1; p > dp->d_name; --p) + if (*p == '.') + { + end = p; + break; + } + } + + /* Prepend the directory name. */ + end_offset = end - dp->d_name; + buf_len = dir_len + 1+ end_offset; + buf = LT_EMALLOC (char, 1+ buf_len); + if (!buf) + return ++errors; + + assert (buf); + + strcpy (buf, dirnam); + strcat (buf, "/"); + strncat (buf, dp->d_name, end_offset); + buf[buf_len] = LT_EOS_CHAR; + + /* Try to insert (in order) into ARGZ/ARGZ_LEN. */ + if (lt_argz_insertinorder (pargz, pargz_len, buf) != 0) + ++errors; + + LT_DLFREE (buf); + + return errors; +} + +static int +list_files_by_dir (dirnam, pargz, pargz_len) + const char *dirnam; + char **pargz; + size_t *pargz_len; +{ + DIR *dirp = 0; + int errors = 0; + + assert (dirnam && *dirnam); + assert (pargz); + assert (pargz_len); + assert (dirnam[LT_STRLEN(dirnam) -1] != '/'); + + dirp = opendir (dirnam); + if (dirp) + { + struct dirent *dp = 0; + + while ((dp = readdir (dirp))) + if (dp->d_name[0] != '.') + if (lt_argz_insertdir (pargz, pargz_len, dirnam, dp)) + { + ++errors; + break; + } + + closedir (dirp); + } + else + ++errors; + + return errors; +} + + +/* If there are any files in DIRNAME, call the function passed in + DATA1 (with the name of each file and DATA2 as arguments). */ +static int +foreachfile_callback (dirname, data1, data2) + char *dirname; + lt_ptr data1; + lt_ptr data2; +{ + int (*func) LT_PARAMS((const char *filename, lt_ptr data)) + = (int (*) LT_PARAMS((const char *filename, lt_ptr data))) data1; + + int is_done = 0; + char *argz = 0; + size_t argz_len = 0; + + if (list_files_by_dir (dirname, &argz, &argz_len) != 0) + goto cleanup; + if (!argz) + goto cleanup; + + { + char *filename = 0; + while ((filename = argz_next (argz, argz_len, filename))) + if ((is_done = (*func) (filename, data2))) + break; + } + + cleanup: + LT_DLFREE (argz); + + return is_done; +} + + +/* Call FUNC for each unique extensionless file in SEARCH_PATH, along + with DATA. The filenames passed to FUNC would be suitable for + passing to lt_dlopenext. The extensions are stripped so that + individual modules do not generate several entries (e.g. libfoo.la, + libfoo.so, libfoo.so.1, libfoo.so.1.0.0). If SEARCH_PATH is NULL, + then the same directories that lt_dlopen would search are examined. */ +int +lt_dlforeachfile (search_path, func, data) + const char *search_path; + int (*func) LT_PARAMS ((const char *filename, lt_ptr data)); + lt_ptr data; +{ + int is_done = 0; + + if (search_path) + { + /* If a specific path was passed, search only the directories + listed in it. */ + is_done = foreach_dirinpath (search_path, 0, + foreachfile_callback, func, data); + } + else + { + /* Otherwise search the default paths. */ + is_done = foreach_dirinpath (user_search_path, 0, + foreachfile_callback, func, data); + if (!is_done) + { + is_done = foreach_dirinpath (getenv("LTDL_LIBRARY_PATH"), 0, + foreachfile_callback, func, data); + } + +#ifdef LTDL_SHLIBPATH_VAR + if (!is_done) + { + is_done = foreach_dirinpath (getenv(LTDL_SHLIBPATH_VAR), 0, + foreachfile_callback, func, data); + } +#endif +#ifdef LTDL_SYSSEARCHPATH + if (!is_done) + { + is_done = foreach_dirinpath (getenv(LTDL_SYSSEARCHPATH), 0, + foreachfile_callback, func, data); + } +#endif + } + + return is_done; +} + +int +lt_dlclose (handle) + lt_dlhandle handle; +{ + lt_dlhandle cur, last; + int errors = 0; + + LT_DLMUTEX_LOCK (); + + /* check whether the handle is valid */ + last = cur = handles; + while (cur && handle != cur) + { + last = cur; + cur = cur->next; + } + + if (!cur) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); + ++errors; + goto done; + } + + handle->info.ref_count--; + + /* Note that even with resident modules, we must track the ref_count + correctly incase the user decides to reset the residency flag + later (even though the API makes no provision for that at the + moment). */ + if (handle->info.ref_count <= 0 && !LT_DLIS_RESIDENT (handle)) + { + lt_user_data data = handle->loader->dlloader_data; + + if (handle != handles) + { + last->next = handle->next; + } + else + { + handles = handle->next; + } + + errors += handle->loader->module_close (data, handle->module); + errors += unload_deplibs(handle); + + /* It is up to the callers to free the data itself. */ + LT_DLFREE (handle->caller_data); + + LT_DLFREE (handle->info.filename); + LT_DLFREE (handle->info.name); + LT_DLFREE (handle); + + goto done; + } + + if (LT_DLIS_RESIDENT (handle)) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CLOSE_RESIDENT_MODULE)); + ++errors; + } + + done: + LT_DLMUTEX_UNLOCK (); + + return errors; +} + +lt_ptr +lt_dlsym (handle, symbol) + lt_dlhandle handle; + const char *symbol; +{ + size_t lensym; + char lsym[LT_SYMBOL_LENGTH]; + char *sym; + lt_ptr address; + lt_user_data data; + + if (!handle) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); + return 0; + } + + if (!symbol) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); + return 0; + } + + lensym = LT_STRLEN (symbol) + LT_STRLEN (handle->loader->sym_prefix) + + LT_STRLEN (handle->info.name); + + if (lensym + LT_SYMBOL_OVERHEAD < LT_SYMBOL_LENGTH) + { + sym = lsym; + } + else + { + sym = LT_EMALLOC (char, lensym + LT_SYMBOL_OVERHEAD + 1); + if (!sym) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (BUFFER_OVERFLOW)); + return 0; + } + } + + data = handle->loader->dlloader_data; + if (handle->info.name) + { + const char *saved_error; + + LT_DLMUTEX_GETERROR (saved_error); + + /* this is a libtool module */ + if (handle->loader->sym_prefix) + { + strcpy(sym, handle->loader->sym_prefix); + strcat(sym, handle->info.name); + } + else + { + strcpy(sym, handle->info.name); + } + + strcat(sym, "_LTX_"); + strcat(sym, symbol); + + /* try "modulename_LTX_symbol" */ + address = handle->loader->find_sym (data, handle->module, sym); + if (address) + { + if (sym != lsym) + { + LT_DLFREE (sym); + } + return address; + } + LT_DLMUTEX_SETERROR (saved_error); + } + + /* otherwise try "symbol" */ + if (handle->loader->sym_prefix) + { + strcpy(sym, handle->loader->sym_prefix); + strcat(sym, symbol); + } + else + { + strcpy(sym, symbol); + } + + address = handle->loader->find_sym (data, handle->module, sym); + if (sym != lsym) + { + LT_DLFREE (sym); + } + + return address; +} + +const char * +lt_dlerror () +{ + const char *error; + + LT_DLMUTEX_GETERROR (error); + LT_DLMUTEX_SETERROR (0); + + return error ? error : NULL; +} + +static int +lt_dlpath_insertdir (ppath, before, dir) + char **ppath; + char *before; + const char *dir; +{ + int errors = 0; + char *canonical = 0; + char *argz = 0; + size_t argz_len = 0; + + assert (ppath); + assert (dir && *dir); + + if (canonicalize_path (dir, &canonical) != 0) + { + ++errors; + goto cleanup; + } + + assert (canonical && *canonical); + + /* If *PPATH is empty, set it to DIR. */ + if (*ppath == 0) + { + assert (!before); /* BEFORE cannot be set without PPATH. */ + assert (dir); /* Without DIR, don't call this function! */ + + *ppath = lt_estrdup (dir); + if (*ppath == 0) + ++errors; + + return errors; + } + + assert (ppath && *ppath); + + if (argzize_path (*ppath, &argz, &argz_len) != 0) + { + ++errors; + goto cleanup; + } + + /* Convert BEFORE into an equivalent offset into ARGZ. This only works + if *PPATH is already canonicalized, and hence does not change length + with respect to ARGZ. We canonicalize each entry as it is added to + the search path, and don't call this function with (uncanonicalized) + user paths, so this is a fair assumption. */ + if (before) + { + assert (*ppath <= before); + assert (before - *ppath <= strlen (*ppath)); + + before = before - *ppath + argz; + } + + if (lt_argz_insert (&argz, &argz_len, before, dir) != 0) + { + ++errors; + goto cleanup; + } + + argz_stringify (argz, argz_len, LT_PATHSEP_CHAR); + LT_DLMEM_REASSIGN (*ppath, argz); + + cleanup: + LT_DLFREE (canonical); + LT_DLFREE (argz); + + return errors; +} + +int +lt_dladdsearchdir (search_dir) + const char *search_dir; +{ + int errors = 0; + + if (search_dir && *search_dir) + { + LT_DLMUTEX_LOCK (); + if (lt_dlpath_insertdir (&user_search_path, 0, search_dir) != 0) + ++errors; + LT_DLMUTEX_UNLOCK (); + } + + return errors; +} + +int +lt_dlinsertsearchdir (before, search_dir) + const char *before; + const char *search_dir; +{ + int errors = 0; + + if (before) + { + LT_DLMUTEX_LOCK (); + if ((before < user_search_path) + || (before >= user_search_path + LT_STRLEN (user_search_path))) + { + LT_DLMUTEX_UNLOCK (); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_POSITION)); + return 1; + } + LT_DLMUTEX_UNLOCK (); + } + + if (search_dir && *search_dir) + { + LT_DLMUTEX_LOCK (); + if (lt_dlpath_insertdir (&user_search_path, + (char *) before, search_dir) != 0) + { + ++errors; + } + LT_DLMUTEX_UNLOCK (); + } + + return errors; +} + +int +lt_dlsetsearchpath (search_path) + const char *search_path; +{ + int errors = 0; + + LT_DLMUTEX_LOCK (); + LT_DLFREE (user_search_path); + LT_DLMUTEX_UNLOCK (); + + if (!search_path || !LT_STRLEN (search_path)) + { + return errors; + } + + LT_DLMUTEX_LOCK (); + if (canonicalize_path (search_path, &user_search_path) != 0) + ++errors; + LT_DLMUTEX_UNLOCK (); + + return errors; +} + +const char * +lt_dlgetsearchpath () +{ + const char *saved_path; + + LT_DLMUTEX_LOCK (); + saved_path = user_search_path; + LT_DLMUTEX_UNLOCK (); + + return saved_path; +} + +int +lt_dlmakeresident (handle) + lt_dlhandle handle; +{ + int errors = 0; + + if (!handle) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); + ++errors; + } + else + { + LT_DLSET_FLAG (handle, LT_DLRESIDENT_FLAG); + } + + return errors; +} + +int +lt_dlisresident (handle) + lt_dlhandle handle; +{ + if (!handle) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); + return -1; + } + + return LT_DLIS_RESIDENT (handle); +} + + + + +/* --- MODULE INFORMATION --- */ + +const lt_dlinfo * +lt_dlgetinfo (handle) + lt_dlhandle handle; +{ + if (!handle) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); + return 0; + } + + return &(handle->info); +} + +lt_dlhandle +lt_dlhandle_next (place) + lt_dlhandle place; +{ + return place ? place->next : handles; +} + +int +lt_dlforeach (func, data) + int (*func) LT_PARAMS((lt_dlhandle handle, lt_ptr data)); + lt_ptr data; +{ + int errors = 0; + lt_dlhandle cur; + + LT_DLMUTEX_LOCK (); + + cur = handles; + while (cur) + { + lt_dlhandle tmp = cur; + + cur = cur->next; + if ((*func) (tmp, data)) + { + ++errors; + break; + } + } + + LT_DLMUTEX_UNLOCK (); + + return errors; +} + +lt_dlcaller_id +lt_dlcaller_register () +{ + static lt_dlcaller_id last_caller_id = 0; + int result; + + LT_DLMUTEX_LOCK (); + result = ++last_caller_id; + LT_DLMUTEX_UNLOCK (); + + return result; +} + +lt_ptr +lt_dlcaller_set_data (key, handle, data) + lt_dlcaller_id key; + lt_dlhandle handle; + lt_ptr data; +{ + int n_elements = 0; + lt_ptr stale = (lt_ptr) 0; + int i; + + /* This needs to be locked so that the caller data can be updated + simultaneously by different threads. */ + LT_DLMUTEX_LOCK (); + + if (handle->caller_data) + while (handle->caller_data[n_elements].key) + ++n_elements; + + for (i = 0; i < n_elements; ++i) + { + if (handle->caller_data[i].key == key) + { + stale = handle->caller_data[i].data; + break; + } + } + + /* Ensure that there is enough room in this handle's caller_data + array to accept a new element (and an empty end marker). */ + if (i == n_elements) + { + lt_caller_data *temp + = LT_DLREALLOC (lt_caller_data, handle->caller_data, 2+ n_elements); + + if (!temp) + { + stale = 0; + goto done; + } + + handle->caller_data = temp; + + /* We only need this if we needed to allocate a new caller_data. */ + handle->caller_data[i].key = key; + handle->caller_data[1+ i].key = 0; + } + + handle->caller_data[i].data = data; + + done: + LT_DLMUTEX_UNLOCK (); + + return stale; +} + +lt_ptr +lt_dlcaller_get_data (key, handle) + lt_dlcaller_id key; + lt_dlhandle handle; +{ + lt_ptr result = (lt_ptr) 0; + + /* This needs to be locked so that the caller data isn't updated by + another thread part way through this function. */ + LT_DLMUTEX_LOCK (); + + /* Locate the index of the element with a matching KEY. */ + { + int i; + for (i = 0; handle->caller_data[i].key; ++i) + { + if (handle->caller_data[i].key == key) + { + result = handle->caller_data[i].data; + break; + } + } + } + + LT_DLMUTEX_UNLOCK (); + + return result; +} + + + +/* --- USER MODULE LOADER API --- */ + + +int +lt_dlloader_add (place, dlloader, loader_name) + lt_dlloader *place; + const struct lt_user_dlloader *dlloader; + const char *loader_name; +{ + int errors = 0; + lt_dlloader *node = 0, *ptr = 0; + + if ((dlloader == 0) /* diagnose null parameters */ + || (dlloader->module_open == 0) + || (dlloader->module_close == 0) + || (dlloader->find_sym == 0)) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); + return 1; + } + + /* Create a new dlloader node with copies of the user callbacks. */ + node = LT_EMALLOC (lt_dlloader, 1); + if (!node) + return 1; + + node->next = 0; + node->loader_name = loader_name; + node->sym_prefix = dlloader->sym_prefix; + node->dlloader_exit = dlloader->dlloader_exit; + node->module_open = dlloader->module_open; + node->module_close = dlloader->module_close; + node->find_sym = dlloader->find_sym; + node->dlloader_data = dlloader->dlloader_data; + + LT_DLMUTEX_LOCK (); + if (!loaders) + { + /* If there are no loaders, NODE becomes the list! */ + loaders = node; + } + else if (!place) + { + /* If PLACE is not set, add NODE to the end of the + LOADERS list. */ + for (ptr = loaders; ptr->next; ptr = ptr->next) + { + /*NOWORK*/; + } + + ptr->next = node; + } + else if (loaders == place) + { + /* If PLACE is the first loader, NODE goes first. */ + node->next = place; + loaders = node; + } + else + { + /* Find the node immediately preceding PLACE. */ + for (ptr = loaders; ptr->next != place; ptr = ptr->next) + { + /*NOWORK*/; + } + + if (ptr->next != place) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); + ++errors; + } + else + { + /* Insert NODE between PTR and PLACE. */ + node->next = place; + ptr->next = node; + } + } + + LT_DLMUTEX_UNLOCK (); + + return errors; +} + +int +lt_dlloader_remove (loader_name) + const char *loader_name; +{ + lt_dlloader *place = lt_dlloader_find (loader_name); + lt_dlhandle handle; + int errors = 0; + + if (!place) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); + return 1; + } + + LT_DLMUTEX_LOCK (); + + /* Fail if there are any open modules which use this loader. */ + for (handle = handles; handle; handle = handle->next) + { + if (handle->loader == place) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (REMOVE_LOADER)); + ++errors; + goto done; + } + } + + if (place == loaders) + { + /* PLACE is the first loader in the list. */ + loaders = loaders->next; + } + else + { + /* Find the loader before the one being removed. */ + lt_dlloader *prev; + for (prev = loaders; prev->next; prev = prev->next) + { + if (!strcmp (prev->next->loader_name, loader_name)) + { + break; + } + } + + place = prev->next; + prev->next = prev->next->next; + } + + if (place->dlloader_exit) + { + errors = place->dlloader_exit (place->dlloader_data); + } + + LT_DLFREE (place); + + done: + LT_DLMUTEX_UNLOCK (); + + return errors; +} + +lt_dlloader * +lt_dlloader_next (place) + lt_dlloader *place; +{ + lt_dlloader *next; + + LT_DLMUTEX_LOCK (); + next = place ? place->next : loaders; + LT_DLMUTEX_UNLOCK (); + + return next; +} + +const char * +lt_dlloader_name (place) + lt_dlloader *place; +{ + const char *name = 0; + + if (place) + { + LT_DLMUTEX_LOCK (); + name = place ? place->loader_name : 0; + LT_DLMUTEX_UNLOCK (); + } + else + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); + } + + return name; +} + +lt_user_data * +lt_dlloader_data (place) + lt_dlloader *place; +{ + lt_user_data *data = 0; + + if (place) + { + LT_DLMUTEX_LOCK (); + data = place ? &(place->dlloader_data) : 0; + LT_DLMUTEX_UNLOCK (); + } + else + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); + } + + return data; +} + +lt_dlloader * +lt_dlloader_find (loader_name) + const char *loader_name; +{ + lt_dlloader *place = 0; + + LT_DLMUTEX_LOCK (); + for (place = loaders; place; place = place->next) + { + if (strcmp (place->loader_name, loader_name) == 0) + { + break; + } + } + LT_DLMUTEX_UNLOCK (); + + return place; +} diff --git a/libltdl/ltdl.h b/libltdl/ltdl.h new file mode 100644 index 00000000..1f2b9716 --- /dev/null +++ b/libltdl/ltdl.h @@ -0,0 +1,367 @@ +/* ltdl.h -- generic dlopen functions + Copyright (C) 1998-2001, 2003, 2004, 2007 Free Software Foundation, Inc. + Originally by Thomas Tanner + This file is part of GNU Libtool. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +As a special exception to the GNU Lesser General Public License, +if you distribute this file as part of a program or library that +is built using GNU libtool, you may include it under the same +distribution terms that you use for the rest of that program. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free +Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA +*/ + +/* Only include this header file once. */ +#ifndef LTDL_H +#define LTDL_H 1 + +#include /* for size_t declaration */ + + +/* --- MACROS FOR PORTABILITY --- */ + + +/* Saves on those hard to debug '\0' typos.... */ +#define LT_EOS_CHAR '\0' + +/* LTDL_BEGIN_C_DECLS should be used at the beginning of your declarations, + so that C++ compilers don't mangle their names. Use LTDL_END_C_DECLS at + the end of C declarations. */ +#ifdef __cplusplus +# define LT_BEGIN_C_DECLS extern "C" { +# define LT_END_C_DECLS } +#else +# define LT_BEGIN_C_DECLS /* empty */ +# define LT_END_C_DECLS /* empty */ +#endif + +LT_BEGIN_C_DECLS + + +/* LT_PARAMS is a macro used to wrap function prototypes, so that compilers + that don't understand ANSI C prototypes still work, and ANSI C + compilers can issue warnings about type mismatches. */ +#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(WIN32) || defined(__cplusplus) +# define LT_PARAMS(protos) protos +# define lt_ptr void* +#else +# define LT_PARAMS(protos) () +# define lt_ptr char* +#endif + +/* LT_STMT_START/END are used to create macros which expand to a + a single compound statement in a portable way. */ +#if defined (__GNUC__) && !defined (__STRICT_ANSI__) && !defined (__cplusplus) +# define LT_STMT_START (void)( +# define LT_STMT_END ) +#else +# if (defined (sun) || defined (__sun__)) +# define LT_STMT_START if (1) +# define LT_STMT_END else (void)0 +# else +# define LT_STMT_START do +# define LT_STMT_END while (0) +# endif +#endif + +/* LT_CONC creates a new concatenated symbol for the compiler + in a portable way. */ +#if defined(__STDC__) || defined(__cplusplus) || defined(_MSC_VER) || defined(_AIX) +# define LT_CONC(s,t) s##t +#else +# define LT_CONC(s,t) s/**/t +#endif + +/* LT_STRLEN can be used safely on NULL pointers. */ +#define LT_STRLEN(s) (((s) && (s)[0]) ? strlen (s) : 0) + + + +/* --- WINDOWS SUPPORT --- */ + + +/* Canonicalise Windows and Cygwin recognition macros. */ +#ifdef __CYGWIN32__ +# ifndef __CYGWIN__ +# define __CYGWIN__ __CYGWIN32__ +# endif +#endif +#if defined(_WIN32) || defined(WIN32) +# ifndef __WINDOWS__ +# ifdef _WIN32 +# define __WINDOWS__ _WIN32 +# else +# ifdef WIN32 +# define __WINDOWS__ WIN32 +# endif +# endif +# endif +#endif + + +#ifdef __WINDOWS__ +# ifndef __CYGWIN__ +/* LT_DIRSEP_CHAR is accepted *in addition* to '/' as a directory + separator when it is set. */ +# define LT_DIRSEP_CHAR '\\' +# define LT_PATHSEP_CHAR ';' +# endif +#endif +#ifndef LT_PATHSEP_CHAR +# define LT_PATHSEP_CHAR ':' +#endif + +/* DLL building support on win32 hosts; mostly to workaround their + ridiculous implementation of data symbol exporting. */ +#ifndef LT_SCOPE +# if defined(__WINDOWS__) || defined(__CYGWIN__) +# ifdef DLL_EXPORT /* defined by libtool (if required) */ +# define LT_SCOPE __declspec(dllexport) +# endif +# ifdef LIBLTDL_DLL_IMPORT /* define if linking with this dll */ + /* note: cygwin/mingw compilers can rely instead on auto-import */ +# define LT_SCOPE extern __declspec(dllimport) +# endif +# endif +# ifndef LT_SCOPE /* static linking or !__WINDOWS__ */ +# define LT_SCOPE extern +# endif +#endif + + +#if defined(_MSC_VER) /* Visual Studio */ +# define R_OK 4 +#endif + + + +/* --- DYNAMIC MODULE LOADING API --- */ + + +typedef struct lt_dlhandle_struct *lt_dlhandle; /* A loaded module. */ + +/* Initialisation and finalisation functions for libltdl. */ +LT_SCOPE int lt_dlinit LT_PARAMS((void)); +LT_SCOPE int lt_dlexit LT_PARAMS((void)); + +/* Module search path manipulation. */ +LT_SCOPE int lt_dladdsearchdir LT_PARAMS((const char *search_dir)); +LT_SCOPE int lt_dlinsertsearchdir LT_PARAMS((const char *before, + const char *search_dir)); +LT_SCOPE int lt_dlsetsearchpath LT_PARAMS((const char *search_path)); +LT_SCOPE const char *lt_dlgetsearchpath LT_PARAMS((void)); +LT_SCOPE int lt_dlforeachfile LT_PARAMS(( + const char *search_path, + int (*func) (const char *filename, lt_ptr data), + lt_ptr data)); + +/* Portable libltdl versions of the system dlopen() API. */ +LT_SCOPE lt_dlhandle lt_dlopen LT_PARAMS((const char *filename)); +LT_SCOPE lt_dlhandle lt_dlopenext LT_PARAMS((const char *filename)); +LT_SCOPE lt_ptr lt_dlsym LT_PARAMS((lt_dlhandle handle, + const char *name)); +LT_SCOPE const char *lt_dlerror LT_PARAMS((void)); +LT_SCOPE int lt_dlclose LT_PARAMS((lt_dlhandle handle)); + +/* Module residency management. */ +LT_SCOPE int lt_dlmakeresident LT_PARAMS((lt_dlhandle handle)); +LT_SCOPE int lt_dlisresident LT_PARAMS((lt_dlhandle handle)); + + + + +/* --- MUTEX LOCKING --- */ + + +typedef void lt_dlmutex_lock LT_PARAMS((void)); +typedef void lt_dlmutex_unlock LT_PARAMS((void)); +typedef void lt_dlmutex_seterror LT_PARAMS((const char *errmsg)); +typedef const char *lt_dlmutex_geterror LT_PARAMS((void)); + +LT_SCOPE int lt_dlmutex_register LT_PARAMS((lt_dlmutex_lock *lock, + lt_dlmutex_unlock *unlock, + lt_dlmutex_seterror *seterror, + lt_dlmutex_geterror *geterror)); + + + + +/* --- MEMORY HANDLING --- */ + + +/* By default, the realloc function pointer is set to our internal + realloc implementation which iself uses lt_dlmalloc and lt_dlfree. + libltdl relies on a featureful realloc, but if you are sure yours + has the right semantics then you can assign it directly. Generally, + it is safe to assign just a malloc() and a free() function. */ +LT_SCOPE lt_ptr (*lt_dlmalloc) LT_PARAMS((size_t size)); +LT_SCOPE lt_ptr (*lt_dlrealloc) LT_PARAMS((lt_ptr ptr, size_t size)); +LT_SCOPE void (*lt_dlfree) LT_PARAMS((lt_ptr ptr)); + + + + +/* --- PRELOADED MODULE SUPPORT --- */ + + +/* A preopened symbol. Arrays of this type comprise the exported + symbols for a dlpreopened module. */ +typedef struct { + const char *name; + lt_ptr address; +} lt_dlsymlist; + +LT_SCOPE int lt_dlpreload LT_PARAMS((const lt_dlsymlist *preloaded)); +LT_SCOPE int lt_dlpreload_default + LT_PARAMS((const lt_dlsymlist *preloaded)); + +#define LTDL_SET_PRELOADED_SYMBOLS() LT_STMT_START{ \ + extern const lt_dlsymlist lt_preloaded_symbols[]; \ + lt_dlpreload_default(lt_preloaded_symbols); \ + }LT_STMT_END + + + + +/* --- MODULE INFORMATION --- */ + + +/* Read only information pertaining to a loaded module. */ +typedef struct { + char *filename; /* file name */ + char *name; /* module name */ + int ref_count; /* number of times lt_dlopened minus + number of times lt_dlclosed. */ +} lt_dlinfo; + +LT_SCOPE const lt_dlinfo *lt_dlgetinfo LT_PARAMS((lt_dlhandle handle)); +LT_SCOPE lt_dlhandle lt_dlhandle_next LT_PARAMS((lt_dlhandle place)); +LT_SCOPE int lt_dlforeach LT_PARAMS(( + int (*func) (lt_dlhandle handle, lt_ptr data), + lt_ptr data)); + +/* Associating user data with loaded modules. */ +typedef unsigned lt_dlcaller_id; + +LT_SCOPE lt_dlcaller_id lt_dlcaller_register LT_PARAMS((void)); +LT_SCOPE lt_ptr lt_dlcaller_set_data LT_PARAMS((lt_dlcaller_id key, + lt_dlhandle handle, + lt_ptr data)); +LT_SCOPE lt_ptr lt_dlcaller_get_data LT_PARAMS((lt_dlcaller_id key, + lt_dlhandle handle)); + + + +/* --- USER MODULE LOADER API --- */ + + +typedef struct lt_dlloader lt_dlloader; +typedef lt_ptr lt_user_data; +typedef lt_ptr lt_module; + +/* Function pointer types for creating user defined module loaders. */ +typedef lt_module lt_module_open LT_PARAMS((lt_user_data loader_data, + const char *filename)); +typedef int lt_module_close LT_PARAMS((lt_user_data loader_data, + lt_module handle)); +typedef lt_ptr lt_find_sym LT_PARAMS((lt_user_data loader_data, + lt_module handle, + const char *symbol)); +typedef int lt_dlloader_exit LT_PARAMS((lt_user_data loader_data)); + +struct lt_user_dlloader { + const char *sym_prefix; + lt_module_open *module_open; + lt_module_close *module_close; + lt_find_sym *find_sym; + lt_dlloader_exit *dlloader_exit; + lt_user_data dlloader_data; +}; + +LT_SCOPE lt_dlloader *lt_dlloader_next LT_PARAMS((lt_dlloader *place)); +LT_SCOPE lt_dlloader *lt_dlloader_find LT_PARAMS(( + const char *loader_name)); +LT_SCOPE const char *lt_dlloader_name LT_PARAMS((lt_dlloader *place)); +LT_SCOPE lt_user_data *lt_dlloader_data LT_PARAMS((lt_dlloader *place)); +LT_SCOPE int lt_dlloader_add LT_PARAMS((lt_dlloader *place, + const struct lt_user_dlloader *dlloader, + const char *loader_name)); +LT_SCOPE int lt_dlloader_remove LT_PARAMS(( + const char *loader_name)); + + + +/* --- ERROR MESSAGE HANDLING --- */ + + +/* Defining error strings alongside their symbolic names in a macro in + this way allows us to expand the macro in different contexts with + confidence that the enumeration of symbolic names will map correctly + onto the table of error strings. */ +#define lt_dlerror_table \ + LT_ERROR(UNKNOWN, "unknown error") \ + LT_ERROR(DLOPEN_NOT_SUPPORTED, "dlopen support not available") \ + LT_ERROR(INVALID_LOADER, "invalid loader") \ + LT_ERROR(INIT_LOADER, "loader initialization failed") \ + LT_ERROR(REMOVE_LOADER, "loader removal failed") \ + LT_ERROR(FILE_NOT_FOUND, "file not found") \ + LT_ERROR(DEPLIB_NOT_FOUND, "dependency library not found") \ + LT_ERROR(NO_SYMBOLS, "no symbols defined") \ + LT_ERROR(CANNOT_OPEN, "can't open the module") \ + LT_ERROR(CANNOT_CLOSE, "can't close the module") \ + LT_ERROR(SYMBOL_NOT_FOUND, "symbol not found") \ + LT_ERROR(NO_MEMORY, "not enough memory") \ + LT_ERROR(INVALID_HANDLE, "invalid module handle") \ + LT_ERROR(BUFFER_OVERFLOW, "internal buffer overflow") \ + LT_ERROR(INVALID_ERRORCODE, "invalid errorcode") \ + LT_ERROR(SHUTDOWN, "library already shutdown") \ + LT_ERROR(CLOSE_RESIDENT_MODULE, "can't close resident module") \ + LT_ERROR(INVALID_MUTEX_ARGS, "invalid mutex handler registration") \ + LT_ERROR(INVALID_POSITION, "invalid search path insert position") + +/* Enumerate the symbolic error names. */ +enum { +#define LT_ERROR(name, diagnostic) LT_CONC(LT_ERROR_, name), + lt_dlerror_table +#undef LT_ERROR + + LT_ERROR_MAX +}; + +/* These functions are only useful from inside custom module loaders. */ +LT_SCOPE int lt_dladderror LT_PARAMS((const char *diagnostic)); +LT_SCOPE int lt_dlseterror LT_PARAMS((int errorcode)); + + + + +/* --- SOURCE COMPATIBILITY WITH OLD LIBLTDL --- */ + + +#ifdef LT_NON_POSIX_NAMESPACE +# define lt_ptr_t lt_ptr +# define lt_module_t lt_module +# define lt_module_open_t lt_module_open +# define lt_module_close_t lt_module_close +# define lt_find_sym_t lt_find_sym +# define lt_dlloader_exit_t lt_dlloader_exit +# define lt_dlloader_t lt_dlloader +# define lt_dlloader_data_t lt_user_data +#endif + +LT_END_C_DECLS + +#endif /* !LTDL_H */ diff --git a/libltdl/ltmain.sh b/libltdl/ltmain.sh new file mode 100644 index 00000000..f924d309 --- /dev/null +++ b/libltdl/ltmain.sh @@ -0,0 +1,6938 @@ +# ltmain.sh - Provide generalized library-building support services. +# NOTE: Changing this file will not affect anything until you rerun configure. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, +# 2007 Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +basename="s,^.*/,,g" + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + +# The name of this program: +progname=`echo "$progpath" | $SED $basename` +modename="$progname" + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 + +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION="1.5.24 Debian 1.5.24-1" +TIMESTAMP=" (1.1220.2.456 2007/06/24 02:25:32)" + +# Be Bourne compatible (taken from Autoconf:_AS_BOURNE_COMPATIBLE). +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# Check that we have a working $echo. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell, and then maybe $echo will work. + exec $SHELL "$progpath" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= +duplicate_deps=no +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" +extracted_archives= +extracted_serial=0 + +##################################### +# Shell function definitions: +# This seems to be the best place for them + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $mkdir "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || { + $echo "cannot create temporary directory \`$my_tmpdir'" 1>&2 + exit $EXIT_FAILURE + } + fi + + $echo "X$my_tmpdir" | $Xsed +} + + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +func_win32_libid () +{ + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \ + $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then + win32_nmres=`eval $NM -f posix -A $1 | \ + $SED -n -e '1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $echo $win32_libid_type +} + + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + CC_quoted="$CC_quoted $arg" + done + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + CC_quoted="$CC_quoted $arg" + done + case "$@ " in + " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + $echo "$modename: unable to infer tagged configuration" + $echo "$modename: specify a tag with \`--tag'" 1>&2 + exit $EXIT_FAILURE +# else +# $echo "$modename: using $tagname tagged configuration" + fi + ;; + esac + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + + $show "(cd $f_ex_an_ar_dir && $AR x $f_ex_an_ar_oldlib)" + $run eval "(cd \$f_ex_an_ar_dir && $AR x \$f_ex_an_ar_oldlib)" || exit $? + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "$modename: ERROR: object name conflicts: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" 1>&2 + exit $EXIT_FAILURE + fi +} + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + my_status="" + + $show "${rm}r $my_gentop" + $run ${rm}r "$my_gentop" + $show "$mkdir $my_gentop" + $run $mkdir "$my_gentop" + my_status=$? + if test "$my_status" -ne 0 && test ! -d "$my_gentop"; then + exit $my_status + fi + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + my_xlib=`$echo "X$my_xlib" | $Xsed -e 's%^.*/%%'` + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + extracted_serial=`expr $extracted_serial + 1` + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + $show "${rm}r $my_xdir" + $run ${rm}r "$my_xdir" + $show "$mkdir $my_xdir" + $run $mkdir "$my_xdir" + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$my_xdir"; then + exit $exit_status + fi + case $host in + *-darwin*) + $show "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + if test -z "$run"; then + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`$echo "X$darwin_archive" | $Xsed -e 's%^.*/%%'` + darwin_arches=`lipo -info "$darwin_archive" 2>/dev/null | $EGREP Architectures 2>/dev/null` + if test -n "$darwin_arches"; then + darwin_arches=`echo "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + $show "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + mkdir -p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + lipo -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $rm "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we have a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print| xargs basename | sort -u | $NL2SP` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` + lipo -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + ${rm}r unfat-$$ + cd "$darwin_orig_dir" + else + cd "$darwin_orig_dir" + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + fi # $run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + func_extract_archives_result="$my_oldobjs" +} +# End of Shell function definitions +##################################### + +# Darwin sucks +eval std_shrext=\"$shrext_cmds\" + +disable_libs=no + +# Parse our command line options once, thoroughly. +while test "$#" -gt 0 +do + arg="$1" + shift + + case $arg in + -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + execute_dlfiles) + execute_dlfiles="$execute_dlfiles $arg" + ;; + tag) + tagname="$arg" + preserve_args="${preserve_args}=$arg" + + # Check whether tagname contains only valid characters + case $tagname in + *[!-_A-Za-z0-9,/]*) + $echo "$progname: invalid tag name: $tagname" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $tagname in + CC) + # Don't test for the "default" C tag, as we know, it's there, but + # not specially marked. + ;; + *) + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then + taglist="$taglist $tagname" + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`" + else + $echo "$progname: ignoring unknown tag $tagname" 1>&2 + fi + ;; + esac + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case $arg in + --help) + show_help=yes + ;; + + --version) + echo "\ +$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP + +Copyright (C) 2007 Free Software Foundation, Inc. +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + exit $? + ;; + + --config) + ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath + # Now print the configurations for the tags. + for tagname in $taglist; do + ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath" + done + exit $? + ;; + + --debug) + $echo "$progname: enabling shell trace mode" + set -x + preserve_args="$preserve_args $arg" + ;; + + --dry-run | -n) + run=: + ;; + + --features) + $echo "host: $host" + if test "$build_libtool_libs" = yes; then + $echo "enable shared libraries" + else + $echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + $echo "enable static libraries" + else + $echo "disable static libraries" + fi + exit $? + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --preserve-dup-deps) duplicate_deps="yes" ;; + + --quiet | --silent) + show=: + preserve_args="$preserve_args $arg" + ;; + + --tag) + prevopt="--tag" + prev=tag + preserve_args="$preserve_args --tag" + ;; + --tag=*) + set tag "$optarg" ${1+"$@"} + shift + prev=tag + preserve_args="$preserve_args --tag" + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$modename: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$modename: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE +fi + +case $disable_libs in +no) + ;; +shared) + build_libtool_libs=no + build_old_libs=yes + ;; +static) + build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` + ;; +esac + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2 + $echo "*** Future versions of Libtool will require --mode=MODE be specified." 1>&2 + case $nonopt in + *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*) + mode=link + for arg + do + case $arg in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx | *strace | *truss) + mode=execute + ;; + *install*|cp|mv) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$modename: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$modename --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case $mode in + # libtool compile mode + compile) + modename="$modename: compile" + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + if test -n "$libobj" ; then + $echo "$modename: you cannot specify \`-o' more than once" 1>&2 + exit $EXIT_FAILURE + fi + arg_mode=target + continue + ;; + + -static | -prefer-pic | -prefer-non-pic) + later="$later $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + lastarg="$lastarg $arg" + done + IFS="$save_ifs" + lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` + + # Add the arguments to base_compile. + base_compile="$base_compile $lastarg" + continue + ;; + + * ) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` + + case $lastarg in + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, and some SunOS ksh mistreat backslash-escaping + # in scan sets (worked around with variable expansion), + # and furthermore cannot handle '|' '&' '(' ')' in scan sets + # at all, so we specify them separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + lastarg="\"$lastarg\"" + ;; + esac + + base_compile="$base_compile $lastarg" + done # for arg + + case $arg_mode in + arg) + $echo "$modename: you must specify an argument for -Xcompile" + exit $EXIT_FAILURE + ;; + target) + $echo "$modename: you must specify a target with \`-o'" 1>&2 + exit $EXIT_FAILURE + ;; + *) + # Get the name of the library object. + [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + xform='[cCFSifmso]' + case $libobj in + *.ada) xform=ada ;; + *.adb) xform=adb ;; + *.ads) xform=ads ;; + *.asm) xform=asm ;; + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.ii) xform=ii ;; + *.class) xform=class ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.[fF][09]?) xform=[fF][09]. ;; + *.for) xform=for ;; + *.java) xform=java ;; + *.obj) xform=obj ;; + esac + + libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` + + case $libobj in + *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; + *) + $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -static) + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + qlibobj=`$echo "X$libobj" | $Xsed -e "$sed_quote_subst"` + case $qlibobj in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qlibobj="\"$qlibobj\"" ;; + esac + test "X$libobj" != "X$qlibobj" \ + && $echo "X$libobj" | grep '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && $echo "$modename: libobj name \`$libobj' may not contain shell special characters." + objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir= + else + xdir=$xdir/ + fi + lobj=${xdir}$objdir/$objname + + if test -z "$base_compile"; then + $echo "$modename: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + $run $rm $removelist + trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + removelist="$removelist $output_obj $lockfile" + trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $run ln "$progpath" "$lockfile" 2>/dev/null; do + $show "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $echo "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + $echo "$srcfile" > "$lockfile" + fi + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + qsrcfile=`$echo "X$srcfile" | $Xsed -e "$sed_quote_subst"` + case $qsrcfile in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qsrcfile="\"$qsrcfile\"" ;; + esac + + $run $rm "$libobj" "${libobj}T" + + # Create a libtool object file (analogous to a ".la" file), + # but don't create it if we're doing a dry run. + test -z "$run" && cat > ${libobj}T </dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + $show "$mv $output_obj $lobj" + if $run $mv $output_obj $lobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the PIC object to the libtool object file. + test -z "$run" && cat >> ${libobj}T <> ${libobj}T </dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + $show "$mv $output_obj $obj" + if $run $mv $output_obj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the non-PIC object the libtool object file. + # Only append if the libtool object file exists. + test -z "$run" && cat >> ${libobj}T <> ${libobj}T <&2 + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test + ;; + *) qarg=$arg ;; + esac + libtool_args="$libtool_args $qarg" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + if test ! -f "$arg"; then + $echo "$modename: symbol file \`$arg' does not exist" + exit $EXIT_FAILURE + fi + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat $save_arg` + do +# moreargs="$moreargs $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit $EXIT_FAILURE + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit $EXIT_FAILURE + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + done + else + $echo "$modename: link input file \`$save_arg' does not exist" + exit $EXIT_FAILURE + fi + arg=$save_arg + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit $EXIT_FAILURE + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + compile_command="$compile_command $wl$qarg" + finalize_command="$finalize_command $wl$qarg" + continue + ;; + xcclinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + darwin_framework|darwin_framework_skip) + test "$prev" = "darwin_framework" && compiler_flags="$compiler_flags $arg" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + prev= + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 + continue + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: more than one -exported-symbols argument is not allowed" + exit $EXIT_FAILURE + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework|-arch|-isysroot) + case " $CC " in + *" ${arg} ${1} "* | *" ${arg} ${1} "*) + prev=darwin_framework_skip ;; + *) compiler_flags="$compiler_flags $arg" + prev=darwin_framework ;; + esac + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + ;; + esac + continue + ;; + + -L*) + dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + notinst_path="$notinst_path $dir" + fi + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + testbindir=`$echo "X$dir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + deplibs="$deplibs -framework System" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + -model) + compile_command="$compile_command $arg" + compiler_flags="$compiler_flags $arg" + finalize_command="$finalize_command $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + compiler_flags="$compiler_flags $arg" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # -64, -mips[0-9] enable 64-bit mode on the SGI compiler + # -r[0-9][0-9]* specifies the processor on the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler + # +DA*, +DD* enable 64-bit mode on the HP compiler + # -q* pass through compiler args for the IBM compiler + # -m* pass through architecture-specific compiler args for GCC + # -m*, -t[45]*, -txscale* pass through architecture-specific + # compiler args for GCC + # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC + # -F/path gives path to uninstalled frameworks, gcc on darwin + # @file GCC response files + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*) + + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + compiler_flags="$compiler_flags $arg" + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 + $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit $EXIT_FAILURE + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Wl,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $wl$flag" + linker_flags="$linker_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + + *.$objext) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit $EXIT_FAILURE + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit $EXIT_FAILURE + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + done # argument parsing loop + + if test -n "$prev"; then + $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` + if test "X$output_objdir" = "X$output"; then + output_objdir="$objdir" + else + output_objdir="$output_objdir/$objdir" + fi + # Create the object directory. + if test ! -d "$output_objdir"; then + $show "$mkdir $output_objdir" + $run $mkdir $output_objdir + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$output_objdir"; then + exit $exit_status + fi + fi + + # Determine the type of output + case $output in + "") + $echo "$modename: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + case $host in + *cygwin* | *mingw* | *pw32*) + # don't eliminate duplications in $postdeps and $predeps + duplicate_compiler_generated_deps=yes + ;; + *) + duplicate_compiler_generated_deps=$duplicate_deps + ;; + esac + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if test "X$duplicate_deps" = "Xyes" ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + esac + pre_post_deps="$pre_post_deps $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + case $linkmode in + lib) + passes="conv link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 + exit $EXIT_FAILURE + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + for pass in $passes; do + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) + libs="$deplibs %DEPLIBS%" + test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" + ;; + esac + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + compiler_flags="$compiler_flags $deplib" + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2 + continue + fi + name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` + for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if (${SED} -e '2q' $lib | + grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + library_names= + old_library= + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + *) + $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2 + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + if eval $echo \"$deplib\" 2>/dev/null \ + | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + $echo + $echo "*** Warning: Trying to link with static lib archive $deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because the file extensions .$libext of this argument makes me believe" + $echo "*** that it is just a static archive that I should not used here." + else + $echo + $echo "*** Warning: Linking the shared library $output against the" + $echo "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + if test "$found" = yes || test -f "$lib"; then : + else + $echo "$modename: cannot find the library \`$lib' or unhandled argument \`$deplib'" 1>&2 + exit $EXIT_FAILURE + fi + + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + elif test "$linkmode" != prog && test "$linkmode" != lib; then + $echo "$modename: \`$lib' is not a convenience library" 1>&2 + exit $EXIT_FAILURE + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + dlprefiles="$dlprefiles $lib $dependency_libs" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + abs_ladir="$ladir" + fi + ;; + esac + laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + $echo "$modename: warning: library \`$lib' was moved." 1>&2 + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi + fi # $installed = yes + name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *" $absdir "*) ;; + *) temp_rpath="$temp_rpath $absdir" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes ; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + # This is a shared library + + # Warn about portability, can't link against -module's on + # some systems (darwin) + if test "$shouldnotlink" = yes && test "$pass" = link ; then + $echo + if test "$linkmode" = prog; then + $echo "*** Warning: Linking the executable $output against the loadable module" + else + $echo "*** Warning: Linking the shared library $output against the loadable module" + fi + $echo "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + realname="$2" + shift; shift + libname=`eval \\$echo \"$libname_spec\"` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw*) + major=`expr $current - $age` + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + soname=`$echo $soroot | ${SED} -e 's/^.*\///'` + newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a" + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + $show "extracting exported symbol list from \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$extract_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + $show "generating import library for \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$old_archive_from_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a module then we can not link against + # it, someone is ignoring the new warnings I added + if /usr/bin/file -L $add 2> /dev/null | + $EGREP ": [^:]* bundle" >/dev/null ; then + $echo "** Warning, lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + $echo + $echo "** And there doesn't seem to be a static archive available" + $echo "** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + $echo "$modename: configuration error: unsupported hardcode properties" + exit $EXIT_FAILURE + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && \ + test "$hardcode_minus_L" != yes && \ + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + $echo + $echo "*** Warning: This system can not link to static lib archive $lib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + $echo "*** But as you try to build a module library, libtool will still create " + $echo "*** a static module, that should work as long as the dlopening application" + $echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + case $deplib in + -L*) path="$deplib" ;; + *.la) + dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$deplib" && dir="." + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + fi + ;; + esac + if grep "^installed=no" $deplib > /dev/null; then + path="$absdir/$objdir" + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + if test "$absdir" != "$libdir"; then + $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 + fi + path="$absdir" + fi + depdepl= + case $host in + *-*-darwin*) + # we do not want to link against static libs, + # but need to link against shared + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$path/$depdepl" ; then + depdepl="$path/$depdepl" + fi + # do not add paths which are already there + case " $newlib_search_path " in + *" $path "*) ;; + *) newlib_search_path="$newlib_search_path $path";; + esac + fi + path="" + ;; + *) + path="-L$path" + ;; + esac + ;; + -l*) + case $host in + *-*-darwin*) + # Again, we only want to link against shared libraries + eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"` + for tmp in $newlib_search_path ; do + if test -f "$tmp/lib$tmp_libs.dylib" ; then + eval depdepl="$tmp/lib$tmp_libs.dylib" + break + fi + done + path="" + ;; + *) continue ;; + esac + ;; + *) continue ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + case " $deplibs " in + *" $depdepl "*) ;; + *) deplibs="$depdepl $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + tmp_libs="$tmp_libs $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 + fi + + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 + fi + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + if test "$module" = no; then + $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 + exit $EXIT_FAILURE + else + $echo + $echo "*** Warning: Linking the shared library $output against the non-libtool" + $echo "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + if test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 + fi + + set dummy $rpath + if test "$#" -gt 2; then + $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 + fi + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + IFS="$save_ifs" + + if test -n "$8"; then + $echo "$modename: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$2" + number_minor="$3" + number_revision="$4" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows|none) + current=`expr $number_major + $number_minor` + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + current=`expr $number_major + $number_minor` + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE + ;; + esac + ;; + no) + current="$2" + revision="$3" + age="$4" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: CURRENT \`$current' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: REVISION \`$revision' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: AGE \`$age' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + if test "$age" -gt "$current"; then + $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + minor_current=`expr $current + 1` + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current"; + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + major=`expr $current - $age` + else + major=`expr $current - $age + 1` + fi + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + iface=`expr $revision - $loop` + loop=`expr $loop - 1` + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + major=.`expr $current - $age` + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + major=`expr $current - $age` + versuffix="-$major" + ;; + + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + fi + + if test "$mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$echo "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + removelist="$removelist $p" + ;; + *) ;; + esac + done + if test -n "$removelist"; then + $show "${rm}r $removelist" + $run ${rm}r $removelist + fi + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$echo "$lib_search_path " | ${SED} -e "s% $path % %g"` + # deplibs=`$echo "$deplibs " | ${SED} -e "s% -L$path % %g"` + # dependency_libs=`$echo "$dependency_libs " | ${SED} -e "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs -framework System" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $rm conftest.c + cat > conftest.c </dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null \ + | grep " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for file magic test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a file magic. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + for a_deplib in $deplibs; do + name=`expr $a_deplib : '-l\(.*\)'` + # If $name is empty we are operating on a -L argument. + if test -n "$name" && test "$name" != "0"; then + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval \\$echo \"$libname_spec\"` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval $echo \"$potent_lib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a regex pattern. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ + -e 's/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"` + done + fi + if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \ + | grep . >/dev/null; then + $echo + if test "X$deplibs_check_method" = "Xnone"; then + $echo "*** Warning: inter-library dependencies are not supported in this platform." + else + $echo "*** Warning: inter-library dependencies are not known to be supported." + fi + $echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + $echo + $echo "*** Warning: libtool could not satisfy all declared inter-library" + $echo "*** dependencies of module $libname. Therefore, libtool will create" + $echo "*** a static module, that should work as long as the dlopening" + $echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + $echo "*** The inter-library dependencies that have been dropped here will be" + $echo "*** automatically added whenever a program is linked with this library" + $echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + $echo + $echo "*** Since this library must not contain undefined symbols," + $echo "*** because either the platform does not support them or" + $echo "*** it was explicitly requested with -no-undefined," + $echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + deplibs="$new_libs" + + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + case $archive_cmds in + *\$LD*) eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" ;; + *) eval dep_rpath=\"$hardcode_libdir_flag_spec\" ;; + esac + else + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + if len=`expr "X$cmd" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + $show "$cmd" + $run eval "$cmd" || exit $? + skipped_export=false + else + # The command line is too long to execute in one step. + $show "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex"; then + $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" + $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + $show "$mv \"${export_symbols}T\" \"$export_symbols\"" + $run eval '$mv "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + libobjs="$libobjs $func_extract_archives_result" + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise. + $echo "creating reloadable object files..." + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + output_la=`$echo "X$output" | $Xsed -e "$basename"` + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + delfiles= + last_robj= + k=1 + output=$output_objdir/$output_la-${k}.$objext + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + eval test_cmds=\"$reload_cmds $objlist $last_robj\" + if test "X$objlist" = X || + { len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len"; }; then + objlist="$objlist $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + eval concat_cmds=\"$reload_cmds $objlist $last_robj\" + else + # All subsequent reloadable object files will link in + # the last one created. + eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + k=`expr $k + 1` + output=$output_objdir/$output_la-${k}.$objext + objlist=$obj + len=1 + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" + + if ${skipped_export-false}; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + libobjs=$output + # Append the command to create the export file. + eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\" + fi + + # Set up a command to remove the reloadable object files + # after they are used. + i=0 + while test "$i" -lt "$k" + do + i=`expr $i + 1` + delfiles="$delfiles $output_objdir/$output_la-${i}.$objext" + done + + $echo "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + + # Append the command to remove the reloadable object files + # to the just-reset $cmds. + eval cmds=\"\$cmds~\$rm $delfiles\" + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 + fi + + case $output in + *.lo) + if test -n "$objs$old_deplibs"; then + $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit $EXIT_FAILURE + fi + libobj="$output" + obj=`$echo "X$output" | $Xsed -e "$lo2o"` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + reload_conv_objs=$reload_objs\ `$echo "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $run eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;; + esac + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 + fi + + if test "$preload" = yes; then + if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && + test "$dlopen_self_static" = unknown; then + $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." + fi + fi + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + case $host in + *darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + if test "$tagname" = CXX ; then + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + fi + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + testbindir=`$echo "X$libdir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + dlsyms= + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${outputname}S.c" + else + $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 + fi + fi + + if test -n "$dlsyms"; then + case $dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${outputname}.nm" + + $show "$rm $nlist ${nlist}S ${nlist}T" + $run $rm "$nlist" "${nlist}S" "${nlist}T" + + # Parse the name list into a source file. + $show "creating $output_objdir/$dlsyms" + + test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ +/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define lt_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + $show "generating symbol list for \`$output'" + + test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for arg in $progfiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + if test -n "$export_symbols_regex"; then + $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $run $rm $export_symbols + $run eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* ) + $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + $run eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + else + $run eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + $run eval 'grep -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + $run eval 'mv "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* ) + $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + $run eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + name=`$echo "$arg" | ${SED} -e 's%^.*/%%'` + $run eval '$echo ": $name " >> "$nlist"' + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -z "$run"; then + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $mv "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if grep -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + grep -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' + else + $echo '/* NONE */' >> "$output_objdir/$dlsyms" + fi + + $echo >> "$output_objdir/$dlsyms" "\ + +#undef lt_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define lt_ptr void * +#else +# define lt_ptr char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +" + + case $host in + *cygwin* | *mingw* ) + $echo >> "$output_objdir/$dlsyms" "\ +/* DATA imports from DLLs on WIN32 can't be const, because + runtime relocations are performed -- see ld's documentation + on pseudo-relocs */ +struct { +" + ;; + * ) + $echo >> "$output_objdir/$dlsyms" "\ +const struct { +" + ;; + esac + + + $echo >> "$output_objdir/$dlsyms" "\ + const char *name; + lt_ptr address; +} +lt_preloaded_symbols[] = +{\ +" + + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms" + + $echo >> "$output_objdir/$dlsyms" "\ + {0, (lt_ptr) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + fi + + pic_flag_for_symtable= + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";; + esac;; + *-*-hpux*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag";; + esac + esac + + # Now compile the dynamic symbol file. + $show "(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" + $run eval '(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? + + # Clean up the generated files. + $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" + $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" + + # Transform the symbol file into the correct name. + case $host in + *cygwin* | *mingw* ) + if test -f "$output_objdir/${outputname}.def" ; then + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%" | $NL2SP` + else + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` + fi + ;; + * ) + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` + ;; + esac + ;; + *) + $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 + exit $EXIT_FAILURE + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s% @SYMFILE@%%" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s% @SYMFILE@%%" | $NL2SP` + fi + + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e 's%@OUTPUT@%'"$output"'%g' | $NL2SP` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + $show "$link_command" + $run eval "$link_command" + exit_status=$? + + # Delete the generated files. + if test -n "$dlsyms"; then + $show "$rm $output_objdir/${outputname}S.${objext}" + $run $rm "$output_objdir/${outputname}S.${objext}" + fi + + exit $exit_status + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $run $rm $output + # Link the executable and exit + $show "$link_command" + $run eval "$link_command" || exit $? + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 + $echo "$modename: \`$output' will be relinked during installation" 1>&2 + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $SP2NL | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g' | $NL2SP` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname + + $show "$link_command" + $run eval "$link_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e "$sed_quote_subst" | $NL2SP` + fi + + # Quote $echo for shipping. + if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then + case $progpath in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; + *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; + esac + qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + output_name=`basename $output` + output_path=`dirname $output` + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $rm $cwrappersource $cwrapper + trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + cat > $cwrappersource <> $cwrappersource<<"EOF" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +/* -DDEBUG is fairly common in CFLAGS. */ +#undef DEBUG +#if defined DEBUGWRAPPER +# define DEBUG(format, ...) fprintf(stderr, format, __VA_ARGS__) +#else +# define DEBUG(format, ...) +#endif + +const char *program_name = NULL; + +void * xmalloc (size_t num); +char * xstrdup (const char *string); +const char * base_name (const char *name); +char * find_executable(const char *wrapper); +int check_executable(const char *path); +char * strendzap(char *str, const char *pat); +void lt_fatal (const char *message, ...); + +int +main (int argc, char *argv[]) +{ + char **newargz; + int i; + + program_name = (char *) xstrdup (base_name (argv[0])); + DEBUG("(main) argv[0] : %s\n",argv[0]); + DEBUG("(main) program_name : %s\n",program_name); + newargz = XMALLOC(char *, argc+2); +EOF + + cat >> $cwrappersource <> $cwrappersource <<"EOF" + newargz[1] = find_executable(argv[0]); + if (newargz[1] == NULL) + lt_fatal("Couldn't find %s", argv[0]); + DEBUG("(main) found exe at : %s\n",newargz[1]); + /* we know the script has the same name, without the .exe */ + /* so make sure newargz[1] doesn't end in .exe */ + strendzap(newargz[1],".exe"); + for (i = 1; i < argc; i++) + newargz[i+1] = xstrdup(argv[i]); + newargz[argc+1] = NULL; + + for (i=0; i> $cwrappersource <> $cwrappersource <> $cwrappersource <<"EOF" + return 127; +} + +void * +xmalloc (size_t num) +{ + void * p = (void *) malloc (num); + if (!p) + lt_fatal ("Memory exhausted"); + + return p; +} + +char * +xstrdup (const char *string) +{ + return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL +; +} + +const char * +base_name (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (isalpha ((unsigned char)name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + return base; +} + +int +check_executable(const char * path) +{ + struct stat st; + + DEBUG("(check_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!"); + if ((!path) || (!*path)) + return 0; + + if ((stat (path, &st) >= 0) && + ( + /* MinGW & native WIN32 do not support S_IXOTH or S_IXGRP */ +#if defined (S_IXOTH) + ((st.st_mode & S_IXOTH) == S_IXOTH) || +#endif +#if defined (S_IXGRP) + ((st.st_mode & S_IXGRP) == S_IXGRP) || +#endif + ((st.st_mode & S_IXUSR) == S_IXUSR)) + ) + return 1; + else + return 0; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise */ +char * +find_executable (const char* wrapper) +{ + int has_slash = 0; + const char* p; + const char* p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char* concat_name; + + DEBUG("(find_executable) : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!"); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char)wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char* path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char* q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR(*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen(tmp); + concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = XMALLOC(char, p_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen(tmp); + concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + return NULL; +} + +char * +strendzap(char *str, const char *pat) +{ + size_t len, patlen; + + assert(str != NULL); + assert(pat != NULL); + + len = strlen(str); + patlen = strlen(pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp(str, pat) == 0) + *str = '\0'; + } + return str; +} + +static void +lt_error_core (int exit_status, const char * mode, + const char * message, va_list ap) +{ + fprintf (stderr, "%s: %s: ", program_name, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, "FATAL", message, ap); + va_end (ap); +} +EOF + # we should really use a build-platform specific compiler + # here, but OTOH, the wrappers (shell script and this C one) + # are only useful if you want to execute the "real" binary. + # Since the "real" binary is built for $host, then this + # wrapper might as well be built for $host, too. + $run $LTCC $LTCFLAGS -s -o $cwrapper $cwrappersource + ;; + esac + $rm $output + trap "$rm $output; exit $EXIT_FAILURE" 1 2 15 + + $echo > $output "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='${SED} -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible (taken from Autoconf:_AS_BOURNE_COMPATIBLE). +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variable: + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$echo are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + echo=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$echo works! + : + else + # Restart under the correct shell, and then maybe \$echo will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $echo >> $output "\ + + # Find the directory that this script lives in. + thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $echo >> $output "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || \\ + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $mkdir \"\$progdir\" + else + $rm \"\$progdir/\$file\" + fi" + + $echo >> $output "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $echo \"\$relink_command_output\" >&2 + $rm \"\$progdir/\$file\" + exit $EXIT_FAILURE + fi + fi + + $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $rm \"\$progdir/\$program\"; + $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $rm \"\$progdir/\$file\" + fi" + else + $echo >> $output "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $echo >> $output "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $echo >> $output "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $echo >> $output "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $echo >> $output "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2*) + $echo >> $output "\ + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $echo >> $output "\ + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $echo >> $output "\ + \$echo \"\$0: cannot exec \$program \$*\" + exit $EXIT_FAILURE + fi + else + # The program doesn't exist. + \$echo \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$echo \"This script is just a wrapper for \$program.\" 1>&2 + $echo \"See the $PACKAGE documentation for more information.\" 1>&2 + exit $EXIT_FAILURE + fi +fi\ +" + chmod +x $output + fi + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $addlibs + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + $echo "X$obj" | $Xsed -e 's%^.*/%%' + done | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "copying selected object files to avoid basename conflicts..." + + if test -z "$gentop"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "$mkdir $gentop" + $run $mkdir "$gentop" + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$gentop"; then + exit $exit_status + fi + fi + + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + objbase=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + counter=`expr $counter + 1` + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + $show "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + $run ln "$obj" "$gentop/$newobj" || + $run cp "$obj" "$gentop/$newobj" + oldobjs="$oldobjs $gentop/$newobj" + ;; + *) oldobjs="$oldobjs $obj" ;; + esac + done + fi + + eval cmds=\"$old_archive_cmds\" + + if len=`expr "X$cmds" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + $echo "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + for obj in $save_oldobjs + do + oldobjs="$objlist $obj" + objlist="$objlist $obj" + eval test_cmds=\"$old_archive_cmds\" + if len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + eval cmd=\"$cmd\" + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$generated"; then + $show "${rm}r$generated" + $run ${rm}r$generated + fi + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + $show "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e "$sed_quote_subst" | $NL2SP` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + + # Only create the output if not a dry run. + if test -z "$run"; then + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + for lib in $dlfiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdlfiles="$newdlfiles $libdir/$name" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdlprefiles="$newdlprefiles $libdir/$name" + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlfiles="$newdlfiles $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlprefiles="$newdlprefiles $abs" + done + dlprefiles="$newdlprefiles" + fi + $rm $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $echo > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $echo >> $output "\ +relink_command=\"$relink_command\"" + fi + done + fi + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" + $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? + ;; + esac + exit $EXIT_SUCCESS + ;; + + # libtool install mode + install) + modename="$modename: install" + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $echo "X$nonopt" | grep shtool > /dev/null; then + # Aesthetically quote it. + arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + case " $install_prog " in + *[\\\ /]cp\ *) ;; + *) prev=$arg ;; + esac + ;; + -g | -m | -o) prev=$arg ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$modename: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test -n "$prev"; then + $echo "$modename: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$modename: no file or destination specified" 1>&2 + else + $echo "$modename: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Strip any trailing slash from the destination. + dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test "$#" -gt 2; then + $echo "$modename: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + library_names= + old_library= + relink_command= + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + if test "$inst_prefix_dir" = "$destdir"; then + $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2 + exit $EXIT_FAILURE + fi + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$echo "$relink_command" | $SP2NL | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%" | $NL2SP` + else + relink_command=`$echo "$relink_command" | $SP2NL | $SED "s%@inst_prefix_dir@%%" | $NL2SP` + fi + + $echo "$modename: warning: relinking \`$file'" 1>&2 + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + exit $EXIT_FAILURE + fi + fi + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$srcname $destdir/$realname" + $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? + if test -n "$stripme" && test -n "$striplib"; then + $show "$striplib $destdir/$realname" + $run eval "$striplib $destdir/$realname" || exit $? + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + if test "$linkname" != "$realname"; then + $show "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" + $run eval "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" + fi + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + cmds=$postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + instname="$dir/$name"i + $show "$install_prog $instname $destdir/$name" + $run eval "$install_prog $instname $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + file=`$echo $file|${SED} 's,.exe$,,'` + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin*|*mingw*) + wrapper=`$echo $file | ${SED} -e 's,.exe$,,'` + ;; + *) + wrapper=$file + ;; + esac + if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then + notinst_deplibs= + relink_command= + + # Note that it is not necessary on cygwin/mingw to append a dot to + # foo even if both foo and FILE.exe exist: automatic-append-.exe + # behavior happens only for exec(3), not for open(2)! Also, sourcing + # `FILE.' does not work on cygwin managed mounts. + # + # If there is no directory component, then add one. + case $wrapper in + */* | *\\*) . ${wrapper} ;; + *) . ./${wrapper} ;; + esac + + # Check the variables that should have been set. + if test -z "$notinst_deplibs"; then + $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2 + exit $EXIT_FAILURE + fi + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + relink_command= + # Note that it is not necessary on cygwin/mingw to append a dot to + # foo even if both foo and FILE.exe exist: automatic-append-.exe + # behavior happens only for exec(3), not for open(2)! Also, sourcing + # `FILE.' does not work on cygwin managed mounts. + # + # If there is no directory component, then add one. + case $wrapper in + */* | *\\*) . ${wrapper} ;; + *) . ./${wrapper} ;; + esac + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + if test "$finalize" = yes && test -z "$run"; then + tmpdir=`func_mktempdir` + file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'` + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g' | $NL2SP` + + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + ${rm}r "$tmpdir" + continue + fi + file="$outputname" + else + $echo "$modename: warning: cannot relink \`$file'" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'` + ;; + esac + ;; + esac + $show "$install_prog$stripme $file $destfile" + $run eval "$install_prog\$stripme \$file \$destfile" || exit $? + test -n "$outputname" && ${rm}r "$tmpdir" + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + if test -n "$stripme" && test -n "$old_striplib"; then + $show "$old_striplib $oldlib" + $run eval "$old_striplib $oldlib" || exit $? + fi + + # Do each command in the postinstall commands. + cmds=$old_postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi + ;; + + # libtool finish mode + finish) + modename="$modename: finish" + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + cmds=$finish_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || admincmds="$admincmds + $cmd" + done + IFS="$save_ifs" + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $run eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + test "$show" = : && exit $EXIT_SUCCESS + + $echo "X----------------------------------------------------------------------" | $Xsed + $echo "Libraries have been installed in:" + for libdir in $libdirs; do + $echo " $libdir" + done + $echo + $echo "If you ever happen to want to link against installed libraries" + $echo "in a given directory, LIBDIR, you must either use libtool, and" + $echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + $echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + $echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + $echo " during execution" + fi + if test -n "$runpath_var"; then + $echo " - add LIBDIR to the \`$runpath_var' environment variable" + $echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $echo " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $echo " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + $echo + $echo "See any operating system documentation about shared libraries for" + $echo "more information, such as the ld(1) and ld.so(8) manual pages." + $echo "X----------------------------------------------------------------------" | $Xsed + exit $EXIT_SUCCESS + ;; + + # libtool execute mode + execute) + modename="$modename: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$modename: you must specify a COMMAND" 1>&2 + $echo "$help" + exit $EXIT_FAILURE + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test ! -f "$file"; then + $echo "$modename: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + if test ! -f "$dir/$dlname"; then + $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit $EXIT_FAILURE + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + fi + $echo "$cmd$args" + exit $EXIT_SUCCESS + fi + ;; + + # libtool clean and uninstall mode + clean | uninstall) + modename="$modename: $mode" + rm="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) rm="$rm $arg"; rmforce=yes ;; + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$modename: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + rmdirs= + + origobjdir="$objdir" + for file in $files; do + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$file"; then + dir=. + objdir="$origobjdir" + else + objdir="$dir/$origobjdir" + fi + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + test "$mode" = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test "$mode" = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if (test -L "$file") >/dev/null 2>&1 \ + || (test -h "$file") >/dev/null 2>&1 \ + || test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + + case "$mode" in + clean) + case " $library_names " in + # " " in the beginning catches empty $dlname + *" $dlname "*) ;; + *) rmfiles="$rmfiles $objdir/$dlname" ;; + esac + test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + cmds=$postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + cmds=$old_postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + + # Read the .lo file + . $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" \ + && test "$pic_object" != none; then + rmfiles="$rmfiles $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" \ + && test "$non_pic_object" != none; then + rmfiles="$rmfiles $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$mode" = clean ; then + noexename=$name + case $file in + *.exe) + file=`$echo $file|${SED} 's,.exe$,,'` + noexename=`$echo $name|${SED} 's,.exe$,,'` + # $file with .exe has already been added to rmfiles, + # add $file without .exe + rmfiles="$rmfiles $file" + ;; + esac + # Do a test to see if this is a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + relink_command= + . $dir/$noexename + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + rmfiles="$rmfiles $objdir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + $show "$rm $rmfiles" + $run $rm $rmfiles || exit_status=1 + done + objdir="$origobjdir" + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + $show "rmdir $dir" + $run rmdir $dir >/dev/null 2>&1 + fi + done + + exit $exit_status + ;; + + "") + $echo "$modename: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + if test -z "$exec_cmd"; then + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit $EXIT_FAILURE + fi +fi # test -z "$show_help" + +if test -n "$exec_cmd"; then + eval exec $exec_cmd + exit $EXIT_FAILURE +fi + +# We need to display help for each of the modes. +case $mode in +"") $echo \ +"Usage: $modename [OPTION]... [MODE-ARG]... + +Provide generalized library-building support services. + + --config show all configuration variables + --debug enable verbose shell tracing +-n, --dry-run display commands without modifying any files + --features display basic configuration information and exit + --finish same as \`--mode=finish' + --help display this help message and exit + --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] + --quiet same as \`--silent' + --silent don't print informational messages + --tag=TAG use configuration variables from tag TAG + --version print version information + +MODE must be one of the following: + + clean remove files from the build directory + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for +a more detailed description of MODE. + +Report bugs to ." + exit $EXIT_SUCCESS + ;; + +clean) + $echo \ +"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + +compile) + $echo \ +"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -static always build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + +execute) + $echo \ +"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + +finish) + $echo \ +"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + +install) + $echo \ +"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + +link) + $echo \ +"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + +uninstall) + $echo \ +"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + +*) + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; +esac + +$echo +$echo "Try \`$modename --help' for more information about other modes." + +exit $? + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +disable_libs=shared +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +disable_libs=static +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/libltdl/missing b/libltdl/missing new file mode 100755 index 00000000..894e786e --- /dev/null +++ b/libltdl/missing @@ -0,0 +1,360 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2005-06-08.21 + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). +case "$1" in + lex|yacc) + # Not GNU programs, they don't have --version. + ;; + + tar) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/libltdl/mkinstalldirs b/libltdl/mkinstalldirs new file mode 100755 index 00000000..ef7e16fd --- /dev/null +++ b/libltdl/mkinstalldirs @@ -0,0 +1,161 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy + +scriptversion=2006-05-11.19 + +# Original author: Noah Friedman +# Created: 1993-05-16 +# Public domain. +# +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +nl=' +' +IFS=" "" $nl" +errstatus=0 +dirmode= + +usage="\ +Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... + +Create each directory DIR (with mode MODE, if specified), including all +leading file name components. + +Report bugs to ." + +# process command line arguments +while test $# -gt 0 ; do + case $1 in + -h | --help | --h*) # -h for help + echo "$usage" + exit $? + ;; + -m) # -m PERM arg + shift + test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } + dirmode=$1 + shift + ;; + --version) + echo "$0 $scriptversion" + exit $? + ;; + --) # stop option processing + shift + break + ;; + -*) # unknown option + echo "$usage" 1>&2 + exit 1 + ;; + *) # first non-opt arg + break + ;; + esac +done + +for file +do + if test -d "$file"; then + shift + else + break + fi +done + +case $# in + 0) exit 0 ;; +esac + +# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and +# mkdir -p a/c at the same time, both will detect that a is missing, +# one will create a, then the other will try to create a and die with +# a "File exists" error. This is a problem when calling mkinstalldirs +# from a parallel make. We use --version in the probe to restrict +# ourselves to GNU mkdir, which is thread-safe. +case $dirmode in + '') + if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + echo "mkdir -p -- $*" + exec mkdir -p -- "$@" + else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + test -d ./-p && rmdir ./-p + test -d ./--version && rmdir ./--version + fi + ;; + *) + if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && + test ! -d ./--version; then + echo "mkdir -m $dirmode -p -- $*" + exec mkdir -m "$dirmode" -p -- "$@" + else + # Clean up after NextStep and OpenStep mkdir. + for d in ./-m ./-p ./--version "./$dirmode"; + do + test -d $d && rmdir $d + done + fi + ;; +esac + +for file +do + case $file in + /*) pathcomp=/ ;; + *) pathcomp= ;; + esac + oIFS=$IFS + IFS=/ + set fnord $file + shift + IFS=$oIFS + + for d + do + test "x$d" = x && continue + + pathcomp=$pathcomp$d + case $pathcomp in + -*) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + else + if test ! -z "$dirmode"; then + echo "chmod $dirmode $pathcomp" + lasterr= + chmod "$dirmode" "$pathcomp" || lasterr=$? + + if test ! -z "$lasterr"; then + errstatus=$lasterr + fi + fi + fi + fi + + pathcomp=$pathcomp/ + done +done + +exit $errstatus + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/libltdl/stamp-h1 b/libltdl/stamp-h1 new file mode 100644 index 00000000..4547fe1b --- /dev/null +++ b/libltdl/stamp-h1 @@ -0,0 +1 @@ +timestamp for config.h diff --git a/pulseaudio-text.svg b/pulseaudio-text.svg new file mode 100644 index 00000000..0e126130 --- /dev/null +++ b/pulseaudio-text.svg @@ -0,0 +1,388 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + PulseAudio logotype + 2006-08-28 + + + Pierre Ossman <ossman@cendio.se> for Cendio AB + + + + + + + + + + Rafael Jannone (basic idea) + + + + + + + + + + + + + + + + + + + + + + + + + + PulseAudio + + diff --git a/src/Makefile.am b/src/Makefile.am index 93f331d6..e17e5ece 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,6 +30,7 @@ pulseincludedir=$(includedir)/pulse pulsecoreincludedir=$(includedir)/pulsecore pulseconfdir=$(sysconfdir)/pulse pulselibexecdir=$(libexecdir)/pulse +xdgautostartdir=$(sysconfdir)/xdg/autostart ################################### # Defines # @@ -76,15 +77,14 @@ endif if OS_IS_WIN32 PA_THREAD_OBJS = \ - pulsecore/once-win32.c pulsecore/once.h \ pulsecore/mutex-win32.c pulsecore/mutex.h \ - pulsecore/thread-win32.c pulsecore/thread.h + pulsecore/thread-win32.c pulsecore/thread.h \ + pulsecore/semaphore-win32.c pulsecore/semaphore.h else PA_THREAD_OBJS = \ - pulsecore/atomic.h \ - pulsecore/once-posix.c pulsecore/once.h \ pulsecore/mutex-posix.c pulsecore/mutex.h \ - pulsecore/thread-posix.c pulsecore/thread.h + pulsecore/thread-posix.c pulsecore/thread.h \ + pulsecore/semaphore-posix.c pulsecore/semaphore.h endif ################################### @@ -100,13 +100,19 @@ EXTRA_DIST = \ depmod.py \ daemon/esdcompat.in \ utils/padsp \ - modules/module-defs.h.m4 + modules/module-defs.h.m4 \ + daemon/pulseaudio-module-xsmp.desktop pulseconf_DATA = \ default.pa \ daemon.conf \ client.conf +if HAVE_X11 +xdgautostart_DATA = \ + daemon/pulseaudio-module-xsmp.desktop +endif + BUILT_SOURCES = \ pulse/version.h @@ -122,13 +128,13 @@ pulseaudio_SOURCES = \ daemon/cpulimit.c daemon/cpulimit.h \ daemon/daemon-conf.c daemon/daemon-conf.h \ daemon/dumpmodules.c daemon/dumpmodules.h \ + daemon/ltdl-bind-now.c daemon/ltdl-bind-now.h \ daemon/main.c \ pulsecore/gccmacro.h -pulseaudio_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) +pulseaudio_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) $(CAP_CFLAGS) $(LIBOIL_CFLAGS) $(DBUS_CFLAGS) pulseaudio_CPPFLAGS = $(AM_CPPFLAGS) -pulseaudio_LDADD = $(AM_LDADD) libpulsecore.la $(LIBLTDL) \ - $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) $(LIBOIL_LIBS) +pulseaudio_LDADD = $(AM_LDADD) libpulsecore.la $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) $(LIBOIL_LIBS) $(DBUS_LIBS) # This is needed because automake doesn't properly expand the foreach below pulseaudio_DEPENDENCIES = libpulsecore.la $(PREOPEN_LIBS) @@ -151,7 +157,8 @@ endif bin_PROGRAMS += \ pacat \ pactl \ - paplay + paplay \ + pasuspender if HAVE_AF_UNIX bin_PROGRAMS += pacmd @@ -182,6 +189,11 @@ pactl_LDADD = $(AM_LDADD) libpulse.la $(LIBSNDFILE_LIBS) pactl_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) pactl_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +pasuspender_SOURCES = utils/pasuspender.c +pasuspender_LDADD = $(AM_LDADD) libpulse.la $(LIBSNDFILE_LIBS) +pasuspender_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) +pasuspender_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + pacmd_SOURCES = utils/pacmd.c pulsecore/pid.c pulsecore/pid.h pacmd_CFLAGS = $(AM_CFLAGS) pacmd_LDADD = $(AM_LDADD) libpulse.la @@ -219,7 +231,14 @@ noinst_PROGRAMS = \ hook-list-test \ memblock-test \ thread-test \ - flist-test + flist-test \ + asyncq-test \ + asyncmsgq-test \ + queue-test \ + rtpoll-test \ + sig2str-test \ + resampler-test \ + smoother-test if HAVE_SIGXCPU noinst_PROGRAMS += \ @@ -274,13 +293,31 @@ thread_test_CFLAGS = $(AM_CFLAGS) thread_test_LDADD = $(AM_LDADD) libpulsecore.la thread_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -flist_test_SOURCES = tests/flist-test.c \ - pulsecore/atomic.h \ - pulsecore/flist.c pulsecore/flist.h +flist_test_SOURCES = tests/flist-test.c flist_test_CFLAGS = $(AM_CFLAGS) flist_test_LDADD = $(AM_LDADD) libpulsecore.la flist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +asyncq_test_SOURCES = tests/asyncq-test.c +asyncq_test_CFLAGS = $(AM_CFLAGS) +asyncq_test_LDADD = $(AM_LDADD) libpulsecore.la +asyncq_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +asyncmsgq_test_SOURCES = tests/asyncmsgq-test.c +asyncmsgq_test_CFLAGS = $(AM_CFLAGS) +asyncmsgq_test_LDADD = $(AM_LDADD) libpulsecore.la +asyncmsgq_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +queue_test_SOURCES = tests/queue-test.c +queue_test_CFLAGS = $(AM_CFLAGS) +queue_test_LDADD = $(AM_LDADD) libpulsecore.la +queue_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +rtpoll_test_SOURCES = tests/rtpoll-test.c +rtpoll_test_CFLAGS = $(AM_CFLAGS) +rtpoll_test_LDADD = $(AM_LDADD) libpulsecore.la +rtpoll_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + mcalign_test_SOURCES = tests/mcalign-test.c mcalign_test_CFLAGS = $(AM_CFLAGS) mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpulsecore.la @@ -341,6 +378,21 @@ interpol_test_LDADD = $(AM_LDADD) libpulse.la interpol_test_CFLAGS = $(AM_CFLAGS) interpol_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +sig2str_test_SOURCES = tests/sig2str-test.c +sig2str_test_LDADD = $(AM_LDADD) libpulsecore.la +sig2str_test_CFLAGS = $(AM_CFLAGS) +sig2str_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + +resampler_test_SOURCES = tests/resampler-test.c +resampler_test_LDADD = $(AM_LDADD) libpulsecore.la +resampler_test_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) +resampler_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS) + +smoother_test_SOURCES = tests/smoother-test.c +smoother_test_LDADD = $(AM_LDADD) libpulsecore.la +smoother_test_CFLAGS = $(AM_CFLAGS) +smoother_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + ################################### # Client library # ################################### @@ -455,6 +507,10 @@ libpulse_la_SOURCES += \ pulsecore/core-error.c pulsecore/core-error.h \ pulsecore/winsock.h pulsecore/creds.h \ pulsecore/shm.c pulsecore/shm.h \ + pulsecore/flist.c pulsecore/flist.h \ + pulsecore/object.c pulsecore/object.h \ + pulsecore/msgobject.c pulsecore/msgobject.h \ + pulsecore/once.c pulsecore/once.h \ $(PA_THREAD_OBJS) if OS_IS_WIN32 @@ -514,11 +570,27 @@ libpulsedsp_la_CFLAGS = $(AM_CFLAGS) libpulsedsp_la_LIBADD = $(AM_LIBADD) libpulse.la libpulsedsp_la_LDFLAGS = -avoid-version +################################### +# Speex Resampler # +################################### + +noinst_LTLIBRARIES = libspeex-resampler-fixed.la libspeex-resampler-float.la libffmpeg-resampler.la + +libspeex_resampler_fixed_la_CPPFLAGS = $(AM_CPPFLAGS) -DRANDOM_PREFIX=paspfx -DOUTSIDE_SPEEX -DFIXED_POINT +libspeex_resampler_fixed_la_SOURCES = pulsecore/speex/resample.c pulsecore/speex/speex_resampler.h pulsecore/speex/arch.h pulsecore/speex/fixed_generic.h pulsecore/speexwrap.h + +libspeex_resampler_float_la_CPPFLAGS = $(AM_CPPFLAGS) -DRANDOM_PREFIX=paspfl -DOUTSIDE_SPEEX +libspeex_resampler_float_la_SOURCES = pulsecore/speex/resample.c pulsecore/speex/speex_resampler.h pulsecore/speex/arch.h + +libffmpeg_resampler_la_CPPFLAGS = $(AM_CPPFLAGS) +libffmpeg_resampler_la_SOURCES = pulsecore/ffmpeg/resample2.c pulsecore/ffmpeg/avcodec.h pulsecore/ffmpeg/dsputil.h + ################################### # Daemon core library # ################################### -pulsecoreinclude_HEADERS = \ +#pulsecoreinclude_HEADERS = +noinst_HEADERS = \ pulsecore/autoload.h \ pulsecore/atomic.h \ pulsecore/cli-command.h \ @@ -567,6 +639,7 @@ pulsecoreinclude_HEADERS = \ pulsecore/refcnt.h \ pulsecore/mutex.h \ pulsecore/thread.h \ + pulsecore/semaphore.h \ pulsecore/once.h lib_LTLIBRARIES += libpulsecore.la @@ -608,6 +681,7 @@ libpulsecore_la_SOURCES += \ pulsecore/memchunk.c pulsecore/memchunk.h \ pulsecore/modargs.c pulsecore/modargs.h \ pulsecore/modinfo.c pulsecore/modinfo.h \ + pulsecore/ltdl-helper.c pulsecore/ltdl-helper.h \ pulsecore/module.c pulsecore/module.h \ pulsecore/namereg.c pulsecore/namereg.h \ pulsecore/pid.c pulsecore/pid.h \ @@ -636,6 +710,19 @@ libpulsecore_la_SOURCES += \ pulsecore/core-error.c pulsecore/core-error.h \ pulsecore/hook-list.c pulsecore/hook-list.h \ pulsecore/shm.c pulsecore/shm.h \ + pulsecore/flist.c pulsecore/flist.h \ + pulsecore/asyncmsgq.c pulsecore/asyncmsgq.h \ + pulsecore/asyncq.c pulsecore/asyncq.h \ + pulsecore/thread-mq.c pulsecore/thread-mq.h \ + pulsecore/fdsem.c pulsecore/fdsem.h \ + pulsecore/object.c pulsecore/object.h \ + pulsecore/msgobject.c pulsecore/msgobject.h \ + pulsecore/rtsig.c pulsecore/rtsig.h \ + pulsecore/rtpoll.c pulsecore/rtpoll.h \ + pulsecore/rtclock.c pulsecore/rtclock.h \ + pulsecore/macro.h \ + pulsecore/once.c pulsecore/once.h \ + pulsecore/time-smoother.c pulsecore/time-smoother.h \ $(PA_THREAD_OBJS) if OS_IS_WIN32 @@ -645,13 +732,14 @@ endif libpulsecore_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBOIL_CFLAGS) libpulsecore_la_LDFLAGS = -version-info $(LIBPULSECORE_VERSION_INFO) -libpulsecore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) $(LIBOIL_LIBS) $(LIBICONV) +libpulsecore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) $(LIBOIL_LIBS) $(LIBICONV) libspeex-resampler-fixed.la libspeex-resampler-float.la libffmpeg-resampler.la ################################### # Plug-in support libraries # ################################### -pulsecoreinclude_HEADERS += \ +#pulsecoreinclude_HEADERS += +noinst_HEADERS += \ pulsecore/socket-util.h \ pulsecore/iochannel.h \ pulsecore/socket-server.h \ @@ -700,9 +788,9 @@ modlibexec_LTLIBRARIES = \ libauthkey-prop.la \ libstrlist.la \ libprotocol-simple.la \ - libprotocol-esound.la \ + libprotocol-http.la \ libprotocol-native.la \ - libprotocol-http.la + libprotocol-esound.la # We need to emulate sendmsg/recvmsg to support this on Win32 if !OS_IS_WIN32 @@ -711,7 +799,8 @@ modlibexec_LTLIBRARIES += \ endif if HAVE_X11 -pulsecoreinclude_HEADERS += \ +#pulsecoreinclude_HEADERS += +noinst_HEADERS += \ pulsecore/x11wrap.h \ pulsecore/x11prop.h @@ -721,7 +810,8 @@ modlibexec_LTLIBRARIES += \ endif if HAVE_AVAHI -pulsecoreinclude_HEADERS += \ +#pulsecoreinclude_HEADERS += +noinst_HEADERS += \ pulsecore/avahi-wrap.h modlibexec_LTLIBRARIES += \ @@ -851,19 +941,23 @@ modlibexec_LTLIBRARIES += \ module-cli.la \ module-cli-protocol-tcp.la \ module-simple-protocol-tcp.la \ - module-esound-protocol-tcp.la \ - module-native-protocol-tcp.la \ - module-native-protocol-fd.la \ - module-sine.la \ - module-combine.la \ - module-tunnel-sink.la \ - module-tunnel-source.la \ module-null-sink.la \ - module-esound-sink.la \ - module-http-protocol-tcp.la \ module-detect.la \ module-volume-restore.la \ - module-rescue-streams.la + module-default-device-restore.la \ + module-rescue-streams.la \ + module-suspend-on-idle.la \ + module-http-protocol-tcp.la \ + module-sine.la \ + module-native-protocol-tcp.la \ + module-native-protocol-fd.la \ + module-esound-protocol-tcp.la \ + module-combine.la \ + module-remap-sink.la \ + module-ladspa-sink.la \ + module-esound-sink.la +# module-tunnel-sink.la +# module-tunnel-source.la # See comment at librtp.la above if !OS_IS_WIN32 @@ -876,9 +970,9 @@ if HAVE_AF_UNIX modlibexec_LTLIBRARIES += \ module-cli-protocol-unix.la \ module-simple-protocol-unix.la \ - module-esound-protocol-unix.la \ + module-http-protocol-unix.la \ module-native-protocol-unix.la \ - module-http-protocol-unix.la + module-esound-protocol-unix.la endif if HAVE_MKFIFO @@ -901,14 +995,14 @@ endif if HAVE_X11 modlibexec_LTLIBRARIES += \ module-x11-bell.la \ - module-x11-publish.la + module-x11-publish.la \ + module-x11-xsmp.la endif if HAVE_OSS modlibexec_LTLIBRARIES += \ liboss-util.la \ - module-oss.la \ - module-oss-mmap.la + module-oss.la endif if HAVE_ALSA @@ -952,10 +1046,10 @@ pulselibexec_PROGRAMS = \ gconf-helper endif -if OS_IS_WIN32 -modlibexec_LTLIBRARIES += \ - module-waveout.la -endif +#if OS_IS_WIN32 +#modlibexec_LTLIBRARIES += \ +# module-waveout.la +#endif if HAVE_HAL modlibexec_LTLIBRARIES += \ @@ -980,6 +1074,8 @@ SYMDEF_FILES = \ modules/module-native-protocol-fd-symdef.h \ modules/module-sine-symdef.h \ modules/module-combine-symdef.h \ + modules/module-remap-sink-symdef.h \ + modules/module-ladspa-sink-symdef.h \ modules/module-esound-compat-spawnfd-symdef.h \ modules/module-esound-compat-spawnpid-symdef.h \ modules/module-match-symdef.h \ @@ -994,8 +1090,8 @@ SYMDEF_FILES = \ modules/module-http-protocol-unix-symdef.h \ modules/module-x11-bell-symdef.h \ modules/module-x11-publish-symdef.h \ + modules/module-x11-xsmp-symdef.h \ modules/module-oss-symdef.h \ - modules/module-oss-mmap-symdef.h \ modules/module-alsa-sink-symdef.h \ modules/module-alsa-source-symdef.h \ modules/module-solaris-symdef.h \ @@ -1006,7 +1102,9 @@ SYMDEF_FILES = \ modules/module-jack-sink-symdef.h \ modules/module-jack-source-symdef.h \ modules/module-volume-restore-symdef.h \ + modules/module-default-device-restore-symdef.h \ modules/module-rescue-streams-symdef.h \ + modules/module-suspend-on-idle-symdef.h \ modules/module-hal-detect-symdef.h \ modules/gconf/module-gconf-symdef.h @@ -1126,18 +1224,27 @@ module_combine_la_SOURCES = modules/module-combine.c module_combine_la_LDFLAGS = -module -avoid-version module_combine_la_LIBADD = $(AM_LIBADD) libpulsecore.la +module_remap_sink_la_SOURCES = modules/module-remap-sink.c +module_remap_sink_la_LDFLAGS = -module -avoid-version +module_remap_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la + +module_ladspa_sink_la_SOURCES = modules/module-ladspa-sink.c modules/ladspa.h +module_ladspa_sink_la_CFLAGS = -DLADSPA_PATH=\"$(libdir)/ladspa:/usr/local/lib/ladspa:/usr/lib/ladspa\" $(AM_CFLAGS) +module_ladspa_sink_la_LDFLAGS = -module -avoid-version +module_ladspa_sink_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) libpulsecore.la + module_match_la_SOURCES = modules/module-match.c module_match_la_LDFLAGS = -module -avoid-version module_match_la_LIBADD = $(AM_LIBADD) libpulsecore.la -module_tunnel_sink_la_SOURCES = modules/module-tunnel.c -module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS) -module_tunnel_sink_la_LDFLAGS = -module -avoid-version -module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la +#module_tunnel_sink_la_SOURCES = modules/module-tunnel.c +#module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS) +#module_tunnel_sink_la_LDFLAGS = -module -avoid-version +#module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la -module_tunnel_source_la_SOURCES = modules/module-tunnel.c -module_tunnel_source_la_LDFLAGS = -module -avoid-version -module_tunnel_source_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la +#module_tunnel_source_la_SOURCES = modules/module-tunnel.c +#module_tunnel_source_la_LDFLAGS = -module -avoid-version +#module_tunnel_source_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la # X11 @@ -1151,6 +1258,11 @@ module_x11_publish_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) module_x11_publish_la_LDFLAGS = -module -avoid-version module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la libauthkey.la libauthkey-prop.la libx11prop.la libstrlist.la libpulsecore.la +module_x11_xsmp_la_SOURCES = modules/module-x11-xsmp.c +module_x11_xsmp_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) +module_x11_xsmp_la_LDFLAGS = -module -avoid-version +module_x11_xsmp_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libpulsecore.la + # OSS liboss_util_la_SOURCES = modules/oss-util.c modules/oss-util.h @@ -1161,10 +1273,6 @@ module_oss_la_SOURCES = modules/module-oss.c module_oss_la_LDFLAGS = -module -avoid-version module_oss_la_LIBADD = $(AM_LIBADD) libiochannel.la liboss-util.la libpulsecore.la -module_oss_mmap_la_SOURCES = modules/module-oss-mmap.c -module_oss_mmap_la_LDFLAGS = -module -avoid-version -module_oss_mmap_la_LIBADD = $(AM_LIBADD) liboss-util.la libpulsecore.la - # ALSA libalsa_util_la_SOURCES = modules/alsa-util.c modules/alsa-util.h @@ -1211,10 +1319,10 @@ module_mmkbd_evdev_la_CFLAGS = $(AM_CFLAGS) # Windows waveout -module_waveout_la_SOURCES = modules/module-waveout.c -module_waveout_la_LDFLAGS = -module -avoid-version -module_waveout_la_LIBADD = $(AM_LIBADD) libpulsecore.la -lwinmm -module_waveout_la_CFLAGS = $(AM_CFLAGS) +#module_waveout_la_SOURCES = modules/module-waveout.c +#module_waveout_la_LDFLAGS = -module -avoid-version +#module_waveout_la_LIBADD = $(AM_LIBADD) libpulsecore.la -lwinmm +#module_waveout_la_CFLAGS = $(AM_CFLAGS) # Hardware autodetection module module_detect_la_SOURCES = modules/module-detect.c @@ -1228,16 +1336,28 @@ module_volume_restore_la_LDFLAGS = -module -avoid-version module_volume_restore_la_LIBADD = $(AM_LIBADD) libpulsecore.la module_volume_restore_la_CFLAGS = $(AM_CFLAGS) +# Default sink/source restore module +module_default_device_restore_la_SOURCES = modules/module-default-device-restore.c +module_default_device_restore_la_LDFLAGS = -module -avoid-version +module_default_device_restore_la_LIBADD = $(AM_LIBADD) libpulsecore.la +module_default_device_restore_la_CFLAGS = $(AM_CFLAGS) + # Rescue streams module module_rescue_streams_la_SOURCES = modules/module-rescue-streams.c module_rescue_streams_la_LDFLAGS = -module -avoid-version module_rescue_streams_la_LIBADD = $(AM_LIBADD) libpulsecore.la module_rescue_streams_la_CFLAGS = $(AM_CFLAGS) +# Suspend-on-idle module +module_suspend_on_idle_la_SOURCES = modules/module-suspend-on-idle.c +module_suspend_on_idle_la_LDFLAGS = -module -avoid-version +module_suspend_on_idle_la_LIBADD = $(AM_LIBADD) libpulsecore.la +module_suspend_on_idle_la_CFLAGS = $(AM_CFLAGS) + # RTP modules module_rtp_send_la_SOURCES = modules/rtp/module-rtp-send.c module_rtp_send_la_LDFLAGS = -module -avoid-version -module_rtp_send_la_LIBADD = $(AM_LIBADD) libpulsecore.la librtp.la +module_rtp_send_la_LIBADD = $(AM_LIBADD) libpulsecore.la librtp.la libsocket-util.la module_rtp_send_la_CFLAGS = $(AM_CFLAGS) module_rtp_recv_la_SOURCES = modules/rtp/module-rtp-recv.c @@ -1275,7 +1395,7 @@ module_gconf_la_LIBADD = $(AM_LIBADD) libpulsecore.la module_gconf_la_CFLAGS = $(AM_CFLAGS) -DPA_GCONF_HELPER=\"$(pulselibexecdir)/gconf-helper\" gconf_helper_SOURCES = modules/gconf/gconf-helper.c -gconf_helper_LDADD = $(AM_LDADD) $(GCONF_LIBS) +gconf_helper_LDADD = $(AM_LDADD) $(GCONF_LIBS) libpulsecore.la gconf_helper_CFLAGS = $(AM_CFLAGS) $(GCONF_CFLAGS) gconf_helper_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -1304,8 +1424,8 @@ default.pa: daemon/default.pa.win32 else default.pa: daemon/default.pa.in Makefile sed -e 's,@PA_BINARY\@,$(PA_BINARY),g' \ - -e 's,@HAVE_HAL_TRUE\@,@HAVE_HAL_TRUE@,g' \ - -e 's,@HAVE_HAL_FALSE\@,@HAVE_HAL_FALSE@,g' < $< > $@ + -e 's,@PA_DLSEARCHPATH\@,$(modlibexecdir),g' \ + -e 's,@PA_SOEXT\@,.so,g' < $< > $@ endif daemon.conf: daemon/daemon.conf.in Makefile @@ -1323,4 +1443,13 @@ install-exec-hook: massif: pulseaudio libtool --mode=execute valgrind --tool=massif --depth=6 --alloc-fn=pa_xmalloc --alloc-fn=pa_xmalloc0 --alloc-fn=pa_xrealloc --alloc-fn=dbus_realloc --alloc-fn=pa_xnew0_internal --alloc-fn=pa_xnew_internal ./pulseaudio +update-speex: + wget -O pulsecore/speex/speex_resampler.h http://svn.xiph.org/trunk/speex/include/speex/speex_resampler.h + wget -O pulsecore/speex/resample.c http://svn.xiph.org/trunk/speex/libspeex/resample.c + wget -O pulsecore/speex/arch.h http://svn.xiph.org/trunk/speex/libspeex/arch.h + wget -O pulsecore/speex/fixed_generic.h http://svn.xiph.org/trunk/speex/libspeex/fixed_generic.h + +update-ffmpeg: + wget -O pulsecore/ffmpeg/resample2.c http://svn.mplayerhq.hu/ffmpeg/trunk/libavcodec/resample2.c?view=co + .PHONY: utils/padsp diff --git a/src/daemon/caps.c b/src/daemon/caps.c index f92db743..5b4008a5 100644 --- a/src/daemon/caps.c +++ b/src/daemon/caps.c @@ -26,11 +26,11 @@ #include #endif -#include #include #include #include #include +#include #ifdef HAVE_SYS_CAPABILITY_H #include @@ -60,7 +60,7 @@ void pa_drop_root(void) { if (uid == 0 || geteuid() != 0) return; - pa_log_info("dropping root rights."); + pa_log_info("Dropping root priviliges."); #if defined(HAVE_SETRESUID) setresuid(uid, uid, uid); @@ -88,8 +88,9 @@ int pa_limit_caps(void) { cap_value_t nice_cap = CAP_SYS_NICE; caps = cap_init(); - assert(caps); + pa_assert(caps); cap_clear(caps); + cap_set_flag(caps, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET); cap_set_flag(caps, CAP_PERMITTED, 1, &nice_cap, CAP_SET); if (cap_set_proc(caps) < 0) @@ -98,7 +99,7 @@ int pa_limit_caps(void) { if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) goto fail; - pa_log_info("dropped capabilities successfully."); + pa_log_info("Dropped capabilities successfully."); r = 1; @@ -114,14 +115,14 @@ int pa_drop_caps(void) { int r = -1; caps = cap_init(); - assert(caps); + pa_assert(caps); cap_clear(caps); prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0); if (cap_set_proc(caps) < 0) { - pa_log("failed to drop capabilities: %s", pa_cstrerror(errno)); + pa_log("Failed to drop capabilities: %s", pa_cstrerror(errno)); goto fail; } diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c index dc757c9c..6b7b2671 100644 --- a/src/daemon/cmdline.c +++ b/src/daemon/cmdline.c @@ -26,7 +26,6 @@ #endif #include -#include #include #include #include @@ -36,6 +35,7 @@ #include #include +#include #include "cmdline.h" @@ -63,7 +63,9 @@ enum { ARG_CHECK, ARG_NO_CPU_LIMIT, ARG_DISABLE_SHM, - ARG_SYSTEM + ARG_DUMP_RESAMPLE_METHODS, + ARG_SYSTEM, + ARG_CLEANUP_SHM }; /* Tabel for getopt_long() */ @@ -92,12 +94,16 @@ static struct option long_options[] = { {"system", 2, 0, ARG_SYSTEM}, {"no-cpu-limit", 2, 0, ARG_NO_CPU_LIMIT}, {"disable-shm", 2, 0, ARG_DISABLE_SHM}, + {"dump-resample-methods", 2, 0, ARG_DUMP_RESAMPLE_METHODS}, + {"cleanup-shm", 2, 0, ARG_CLEANUP_SHM}, {NULL, 0, 0, 0} }; void pa_cmdline_help(const char *argv0) { const char *e; + pa_assert(argv0); + if ((e = strrchr(argv0, '/'))) e++; else @@ -109,6 +115,8 @@ void pa_cmdline_help(const char *argv0) { " --version Show version\n" " --dump-conf Dump default configuration\n" " --dump-modules Dump list of available modules\n" + " --dump-resample-methods Dump available resample methods\n" + " --cleanup-shm Cleanup stale shared memory segments\n" " -k --kill Kill a running daemon\n" " --check Check for a running daemon\n\n" @@ -131,9 +139,8 @@ void pa_cmdline_help(const char *argv0) { " -p, --dl-search-path=PATH Set the search path for dynamic shared\n" " objects (plugins)\n" " --resample-method=[METHOD] Use the specified resampling method\n" - " (one of src-sinc-medium-quality,\n" - " src-sinc-best-quality,src-sinc-fastest\n" - " src-zero-order-hold,src-linear,trivial)\n" + " (See --dump-resample-methods for\n" + " possible values)\n" " --use-pid-file[=BOOL] Create a PID file\n" " --no-cpu-limit[=BOOL] Do not install CPU load limiter on\n" " platforms that support it.\n" @@ -152,7 +159,10 @@ void pa_cmdline_help(const char *argv0) { int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d) { pa_strbuf *buf = NULL; int c; - assert(conf && argc && argv); + + pa_assert(conf); + pa_assert(argc > 0); + pa_assert(argv); buf = pa_strbuf_new(); @@ -178,6 +188,14 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d conf->cmd = PA_CMD_DUMP_MODULES; break; + case ARG_DUMP_RESAMPLE_METHODS: + conf->cmd = PA_CMD_DUMP_RESAMPLE_METHODS; + break; + + case ARG_CLEANUP_SHM: + conf->cmd = PA_CMD_CLEANUP_SHM; + break; + case 'k': case ARG_KILL: conf->cmd = PA_CMD_KILL; @@ -193,9 +211,12 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d break; case ARG_FILE: - case 'F': - pa_strbuf_printf(buf, ".include %s\n", optarg); + case 'F': { + char *p; + pa_strbuf_printf(buf, ".include %s\n", p = pa_make_path_absolute(optarg)); + pa_xfree(p); break; + } case 'C': pa_strbuf_puts(buf, "load-module module-cli exit_on_eof=1\n"); diff --git a/src/daemon/cpulimit.c b/src/daemon/cpulimit.c index d4ac1d86..ab212129 100644 --- a/src/daemon/cpulimit.c +++ b/src/daemon/cpulimit.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "cpulimit.h" @@ -38,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -92,23 +92,18 @@ static enum { /* Reset the SIGXCPU timer to the next t seconds */ static void reset_cpu_time(int t) { - int r; long n; struct rlimit rl; struct rusage ru; /* Get the current CPU time of the current process */ - r = getrusage(RUSAGE_SELF, &ru); - assert(r >= 0); + pa_assert_se(getrusage(RUSAGE_SELF, &ru) >= 0); n = ru.ru_utime.tv_sec + ru.ru_stime.tv_sec + t; - - r = getrlimit(RLIMIT_CPU, &rl); - assert(r >= 0); + pa_assert_se(getrlimit(RLIMIT_CPU, &rl) >= 0); rl.rlim_cur = n; - r = setrlimit(RLIMIT_CPU, &rl); - assert(r >= 0); + pa_assert_se(setrlimit(RLIMIT_CPU, &rl) >= 0); } /* A simple, thread-safe puts() work-alike */ @@ -118,7 +113,7 @@ static void write_err(const char *p) { /* The signal handler, called on every SIGXCPU */ static void signal_handler(int sig) { - assert(sig == SIGXCPU); + pa_assert(sig == SIGXCPU); if (phase == PHASE_IDLE) { time_t now; @@ -130,7 +125,7 @@ static void signal_handler(int sig) { time(&now); #ifdef PRINT_CPU_LOAD - snprintf(t, sizeof(t), "Using %0.1f%% CPU\n", (double)CPUTIME_INTERVAL_SOFT/(now-last_time)*100); + pa_snprintf(t, sizeof(t), "Using %0.1f%% CPU\n", (double)CPUTIME_INTERVAL_SOFT/(now-last_time)*100); write_err(t); #endif @@ -160,7 +155,12 @@ static void signal_handler(int sig) { /* Callback for IO events on the FIFO */ static void callback(pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata) { char c; - assert(m && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == the_pipe[0]); + pa_assert(m); + pa_assert(e); + pa_assert(f == PA_IO_EVENT_INPUT); + pa_assert(e == io_event); + pa_assert(fd == the_pipe[0]); + pa_read(the_pipe[0], &c, sizeof(c), NULL); m->quit(m, 1); /* Quit the main loop */ } @@ -168,7 +168,13 @@ static void callback(pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags /* Initializes CPU load limiter */ int pa_cpu_limit_init(pa_mainloop_api *m) { struct sigaction sa; - assert(m && !api && !io_event && the_pipe[0] == -1 && the_pipe[1] == -1 && !installed); + + pa_assert(m); + pa_assert(!api); + pa_assert(!io_event); + pa_assert(the_pipe[0] == -1); + pa_assert(the_pipe[1] == -1); + pa_assert(!installed); time(&last_time); @@ -178,10 +184,10 @@ int pa_cpu_limit_init(pa_mainloop_api *m) { return -1; } - pa_make_nonblock_fd(the_pipe[0]); - pa_make_nonblock_fd(the_pipe[1]); - pa_fd_set_cloexec(the_pipe[0], 1); - pa_fd_set_cloexec(the_pipe[1], 1); + pa_make_fd_nonblock(the_pipe[0]); + pa_make_fd_nonblock(the_pipe[1]); + pa_make_fd_cloexec(the_pipe[0]); + pa_make_fd_cloexec(the_pipe[1]); api = m; io_event = api->io_new(m, the_pipe[0], PA_IO_EVENT_INPUT, callback, NULL); @@ -208,24 +214,18 @@ int pa_cpu_limit_init(pa_mainloop_api *m) { /* Shutdown CPU load limiter */ void pa_cpu_limit_done(void) { - int r; if (io_event) { - assert(api); + pa_assert(api); api->io_free(io_event); io_event = NULL; api = NULL; } - if (the_pipe[0] >= 0) - close(the_pipe[0]); - if (the_pipe[1] >= 0) - close(the_pipe[1]); - the_pipe[0] = the_pipe[1] = -1; + pa_close_pipe(the_pipe); if (installed) { - r = sigaction(SIGXCPU, &sigaction_prev, NULL); - assert(r >= 0); + pa_assert_se(sigaction(SIGXCPU, &sigaction_prev, NULL) >= 0); installed = 0; } } diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 8cab327f..920e3717 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -39,19 +38,14 @@ #include #include #include +#include #include "daemon-conf.h" -#ifndef OS_IS_WIN32 -# define PATH_SEP "/" -#else -# define PATH_SEP "\\" -#endif - -#define DEFAULT_SCRIPT_FILE PA_DEFAULT_CONFIG_DIR PATH_SEP "default.pa" -#define DEFAULT_SCRIPT_FILE_USER PATH_SEP "default.pa" -#define DEFAULT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PATH_SEP "daemon.conf" -#define DEFAULT_CONFIG_FILE_USER PATH_SEP "daemon.conf" +#define DEFAULT_SCRIPT_FILE PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "default.pa" +#define DEFAULT_SCRIPT_FILE_USER PA_PATH_SEP "default.pa" +#define DEFAULT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "daemon.conf" +#define DEFAULT_CONFIG_FILE_USER PA_PATH_SEP "daemon.conf" #define ENV_SCRIPT_FILE "PULSE_SCRIPT" #define ENV_CONFIG_FILE "PULSE_CONFIG" @@ -72,31 +66,34 @@ static const pa_daemon_conf default_conf = { .default_script_file = NULL, .log_target = PA_LOG_SYSLOG, .log_level = PA_LOG_NOTICE, - .resample_method = PA_RESAMPLER_SRC_SINC_FASTEST, + .resample_method = PA_RESAMPLER_AUTO, .config_file = NULL, .use_pid_file = 1, .system_instance = 0, .no_cpu_limit = 0, - .disable_shm = 0 + .disable_shm = 0, + .default_n_fragments = 4, + .default_fragment_size_msec = 25, + .default_sample_spec = { .format = PA_SAMPLE_S16NE, .rate = 44100, .channels = 2 } #ifdef HAVE_SYS_RESOURCE_H , .rlimit_as = { .value = 0, .is_set = 0 }, .rlimit_core = { .value = 0, .is_set = 0 }, .rlimit_data = { .value = 0, .is_set = 0 }, .rlimit_fsize = { .value = 0, .is_set = 0 }, - .rlimit_nofile = { .value = 200, .is_set = 1 }, + .rlimit_nofile = { .value = 256, .is_set = 1 }, .rlimit_stack = { .value = 0, .is_set = 0 } #ifdef RLIMIT_NPROC , .rlimit_nproc = { .value = 0, .is_set = 0 } #endif #ifdef RLIMIT_MEMLOCK - , .rlimit_memlock = { .value = 0, .is_set = 1 } + , .rlimit_memlock = { .value = 16384, .is_set = 1 } #endif #endif }; pa_daemon_conf* pa_daemon_conf_new(void) { FILE *f; - pa_daemon_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); + pa_daemon_conf *c = pa_xnewdup(pa_daemon_conf, &default_conf, 1); if ((f = pa_open_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE, &c->default_script_file, "r"))) fclose(f); @@ -106,7 +103,7 @@ pa_daemon_conf* pa_daemon_conf_new(void) { } void pa_daemon_conf_free(pa_daemon_conf *c) { - assert(c); + pa_assert(c); pa_xfree(c->script_commands); pa_xfree(c->dl_search_path); pa_xfree(c->default_script_file); @@ -115,7 +112,8 @@ void pa_daemon_conf_free(pa_daemon_conf *c) { } int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string) { - assert(c && string); + pa_assert(c); + pa_assert(string); if (!strcmp(string, "auto")) c->auto_log_target = 1; @@ -133,7 +131,8 @@ int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string) { int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string) { uint32_t u; - assert(c && string); + pa_assert(c); + pa_assert(string); if (pa_atou(string, &u) >= 0) { if (u >= PA_LOG_LEVEL_MAX) @@ -158,7 +157,8 @@ int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string) { int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string) { int m; - assert(c && string); + pa_assert(c); + pa_assert(string); if ((m = pa_parse_resample_method(string)) < 0) return -1; @@ -169,7 +169,11 @@ int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string) { static int parse_log_target(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { pa_daemon_conf *c = data; - assert(filename && lvalue && rvalue && data); + + pa_assert(filename); + pa_assert(lvalue); + pa_assert(rvalue); + pa_assert(data); if (pa_daemon_conf_set_log_target(c, rvalue) < 0) { pa_log("[%s:%u] Invalid log target '%s'.", filename, line, rvalue); @@ -181,7 +185,11 @@ static int parse_log_target(const char *filename, unsigned line, const char *lva static int parse_log_level(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { pa_daemon_conf *c = data; - assert(filename && lvalue && rvalue && data); + + pa_assert(filename); + pa_assert(lvalue); + pa_assert(rvalue); + pa_assert(data); if (pa_daemon_conf_set_log_level(c, rvalue) < 0) { pa_log("[%s:%u] Invalid log level '%s'.", filename, line, rvalue); @@ -193,10 +201,14 @@ static int parse_log_level(const char *filename, unsigned line, const char *lval static int parse_resample_method(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { pa_daemon_conf *c = data; - assert(filename && lvalue && rvalue && data); + + pa_assert(filename); + pa_assert(lvalue); + pa_assert(rvalue); + pa_assert(data); if (pa_daemon_conf_set_resample_method(c, rvalue) < 0) { - pa_log("[%s:%u] Inavalid resample method '%s'.", filename, line, rvalue); + pa_log("[%s:%u] Invalid resample method '%s'.", filename, line, rvalue); return -1; } @@ -206,10 +218,11 @@ static int parse_resample_method(const char *filename, unsigned line, const char static int parse_rlimit(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { #ifdef HAVE_SYS_RESOURCE_H struct pa_rlimit *r = data; - assert(filename); - assert(lvalue); - assert(rvalue); - assert(r); + + pa_assert(filename); + pa_assert(lvalue); + pa_assert(rvalue); + pa_assert(r); if (rvalue[strspn(rvalue, "\t ")] == 0) { /* Empty string */ @@ -218,7 +231,7 @@ static int parse_rlimit(const char *filename, unsigned line, const char *lvalue, } else { int32_t k; if (pa_atoi(rvalue, &k) < 0) { - pa_log("[%s:%u] Inavalid rlimit '%s'.", filename, line, rvalue); + pa_log("[%s:%u] Invalid rlimit '%s'.", filename, line, rvalue); return -1; } r->is_set = k >= 0; @@ -231,43 +244,138 @@ static int parse_rlimit(const char *filename, unsigned line, const char *lvalue, return 0; } +static int parse_sample_format(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + pa_daemon_conf *c = data; + pa_sample_format_t f; + + pa_assert(filename); + pa_assert(lvalue); + pa_assert(rvalue); + pa_assert(data); + + if ((f = pa_parse_sample_format(rvalue)) < 0) { + pa_log("[%s:%u] Invalid sample format '%s'.", filename, line, rvalue); + return -1; + } + + c->default_sample_spec.format = f; + return 0; +} + +static int parse_sample_rate(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + pa_daemon_conf *c = data; + int32_t r; + + pa_assert(filename); + pa_assert(lvalue); + pa_assert(rvalue); + pa_assert(data); + + if (pa_atoi(rvalue, &r) < 0 || r > PA_RATE_MAX || r <= 0) { + pa_log("[%s:%u] Invalid sample rate '%s'.", filename, line, rvalue); + return -1; + } + + c->default_sample_spec.rate = r; + return 0; +} + +static int parse_sample_channels(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + pa_daemon_conf *c = data; + int32_t n; + + pa_assert(filename); + pa_assert(lvalue); + pa_assert(rvalue); + pa_assert(data); + + if (pa_atoi(rvalue, &n) < 0 || n > PA_CHANNELS_MAX || n <= 0) { + pa_log("[%s:%u] Invalid sample channels '%s'.", filename, line, rvalue); + return -1; + } + + c->default_sample_spec.channels = (uint8_t) n; + return 0; +} + +static int parse_fragments(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + pa_daemon_conf *c = data; + int32_t n; + + pa_assert(filename); + pa_assert(lvalue); + pa_assert(rvalue); + pa_assert(data); + + if (pa_atoi(rvalue, &n) < 0 || n < 2) { + pa_log("[%s:%u] Invalid number of fragments '%s'.", filename, line, rvalue); + return -1; + } + + c->default_n_fragments = (unsigned) n; + return 0; +} + +static int parse_fragment_size_msec(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + pa_daemon_conf *c = data; + int32_t n; + + pa_assert(filename); + pa_assert(lvalue); + pa_assert(rvalue); + pa_assert(data); + + if (pa_atoi(rvalue, &n) < 0 || n < 1) { + pa_log("[%s:%u] Invalid fragment size '%s'.", filename, line, rvalue); + return -1; + } + + c->default_fragment_size_msec = (unsigned) n; + return 0; +} + int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { int r = -1; FILE *f = NULL; pa_config_item table[] = { - { "daemonize", pa_config_parse_bool, NULL }, - { "fail", pa_config_parse_bool, NULL }, - { "high-priority", pa_config_parse_bool, NULL }, - { "disallow-module-loading", pa_config_parse_bool, NULL }, - { "exit-idle-time", pa_config_parse_int, NULL }, - { "module-idle-time", pa_config_parse_int, NULL }, - { "scache-idle-time", pa_config_parse_int, NULL }, - { "dl-search-path", pa_config_parse_string, NULL }, - { "default-script-file", pa_config_parse_string, NULL }, - { "log-target", parse_log_target, NULL }, - { "log-level", parse_log_level, NULL }, - { "verbose", parse_log_level, NULL }, - { "resample-method", parse_resample_method, NULL }, - { "use-pid-file", pa_config_parse_bool, NULL }, - { "system-instance", pa_config_parse_bool, NULL }, - { "no-cpu-limit", pa_config_parse_bool, NULL }, - { "disable-shm", pa_config_parse_bool, NULL }, + { "daemonize", pa_config_parse_bool, NULL }, + { "fail", pa_config_parse_bool, NULL }, + { "high-priority", pa_config_parse_bool, NULL }, + { "disallow-module-loading", pa_config_parse_bool, NULL }, + { "exit-idle-time", pa_config_parse_int, NULL }, + { "module-idle-time", pa_config_parse_int, NULL }, + { "scache-idle-time", pa_config_parse_int, NULL }, + { "dl-search-path", pa_config_parse_string, NULL }, + { "default-script-file", pa_config_parse_string, NULL }, + { "log-target", parse_log_target, NULL }, + { "log-level", parse_log_level, NULL }, + { "verbose", parse_log_level, NULL }, + { "resample-method", parse_resample_method, NULL }, + { "use-pid-file", pa_config_parse_bool, NULL }, + { "system-instance", pa_config_parse_bool, NULL }, + { "no-cpu-limit", pa_config_parse_bool, NULL }, + { "disable-shm", pa_config_parse_bool, NULL }, + { "default-sample-format", parse_sample_format, NULL }, + { "default-sample-rate", parse_sample_rate, NULL }, + { "default-sample-channels", parse_sample_channels, NULL }, + { "default-fragments", parse_fragments, NULL }, + { "default-fragment-size-msec", parse_fragment_size_msec, NULL }, #ifdef HAVE_SYS_RESOURCE_H - { "rlimit-as", parse_rlimit, NULL }, - { "rlimit-core", parse_rlimit, NULL }, - { "rlimit-data", parse_rlimit, NULL }, - { "rlimit-fsize", parse_rlimit, NULL }, - { "rlimit-nofile", parse_rlimit, NULL }, - { "rlimit-stack", parse_rlimit, NULL }, + { "rlimit-as", parse_rlimit, NULL }, + { "rlimit-core", parse_rlimit, NULL }, + { "rlimit-data", parse_rlimit, NULL }, + { "rlimit-fsize", parse_rlimit, NULL }, + { "rlimit-nofile", parse_rlimit, NULL }, + { "rlimit-stack", parse_rlimit, NULL }, #ifdef RLIMIT_NPROC - { "rlimit-nproc", parse_rlimit, NULL }, + { "rlimit-nproc", parse_rlimit, NULL }, #endif #ifdef RLIMIT_MEMLOCK - { "rlimit-memlock", parse_rlimit, NULL }, + { "rlimit-memlock", parse_rlimit, NULL }, #endif #endif - { NULL, NULL, NULL }, + { NULL, NULL, NULL }, }; table[0].data = &c->daemonize; @@ -287,25 +395,29 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { table[14].data = &c->system_instance; table[15].data = &c->no_cpu_limit; table[16].data = &c->disable_shm; + table[17].data = c; + table[18].data = c; + table[19].data = c; + table[20].data = c; + table[21].data = c; #ifdef HAVE_SYS_RESOURCE_H - table[17].data = &c->rlimit_as; - table[18].data = &c->rlimit_core; - table[19].data = &c->rlimit_data; - table[20].data = &c->rlimit_fsize; - table[21].data = &c->rlimit_nofile; - table[22].data = &c->rlimit_stack; + table[22].data = &c->rlimit_as; + table[23].data = &c->rlimit_core; + table[24].data = &c->rlimit_data; + table[25].data = &c->rlimit_fsize; + table[26].data = &c->rlimit_nofile; + table[27].data = &c->rlimit_stack; #ifdef RLIMIT_NPROC - table[23].data = &c->rlimit_nproc; + table[28].data = &c->rlimit_nproc; #endif #ifdef RLIMIT_MEMLOCK #ifndef RLIMIT_NPROC #error "Houston, we have a numbering problem!" #endif - table[24].data = &c->rlimit_memlock; + table[29].data = &c->rlimit_memlock; #endif #endif - pa_xfree(c->config_file); c->config_file = NULL; @@ -314,7 +426,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { pa_open_config_file(DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file, "r"); if (!f && errno != ENOENT) { - pa_log("WARNING: failed to open configuration file '%s': %s", c->config_file, pa_cstrerror(errno)); + pa_log_warn("Failed to open configuration file '%s': %s", c->config_file, pa_cstrerror(errno)); goto finish; } @@ -351,12 +463,16 @@ static const char* const log_level_to_string[] = { }; char *pa_daemon_conf_dump(pa_daemon_conf *c) { - pa_strbuf *s = pa_strbuf_new(); + pa_strbuf *s; + + pa_assert(c); + + s = pa_strbuf_new(); if (c->config_file) pa_strbuf_printf(s, "### Read from configuration file: %s ###\n", c->config_file); - assert(c->log_level <= PA_LOG_LEVEL_MAX); + pa_assert(c->log_level <= PA_LOG_LEVEL_MAX); pa_strbuf_printf(s, "daemonize = %i\n", !!c->daemonize); pa_strbuf_printf(s, "fail = %i\n", !!c->fail); @@ -373,7 +489,12 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { pa_strbuf_printf(s, "use-pid-file = %i\n", c->use_pid_file); pa_strbuf_printf(s, "system-instance = %i\n", !!c->system_instance); pa_strbuf_printf(s, "no-cpu-limit = %i\n", !!c->no_cpu_limit); - pa_strbuf_printf(s, "disable_shm = %i\n", !!c->disable_shm); + pa_strbuf_printf(s, "disable-shm = %i\n", !!c->disable_shm); + pa_strbuf_printf(s, "default-sample-format = %s\n", pa_sample_format_to_string(c->default_sample_spec.format)); + pa_strbuf_printf(s, "default-sample-rate = %u\n", c->default_sample_spec.rate); + pa_strbuf_printf(s, "default-sample-channels = %u\n", c->default_sample_spec.channels); + pa_strbuf_printf(s, "default-fragments = %u\n", c->default_n_fragments); + pa_strbuf_printf(s, "default-fragment-size-msec = %u\n", c->default_fragment_size_msec); #ifdef HAVE_SYS_RESOURCE_H pa_strbuf_printf(s, "rlimit-as = %li\n", c->rlimit_as.is_set ? (long int) c->rlimit_as.value : -1); pa_strbuf_printf(s, "rlimit-core = %li\n", c->rlimit_core.is_set ? (long int) c->rlimit_core.value : -1); diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h index 4843a610..4d37861d 100644 --- a/src/daemon/daemon-conf.h +++ b/src/daemon/daemon-conf.h @@ -26,6 +26,7 @@ ***/ #include +#include #ifdef HAVE_SYS_RESOURCE_H #include @@ -39,7 +40,9 @@ typedef enum pa_daemon_conf_cmd { PA_CMD_DUMP_CONF, PA_CMD_DUMP_MODULES, PA_CMD_KILL, - PA_CMD_CHECK + PA_CMD_CHECK, + PA_CMD_DUMP_RESAMPLE_METHODS, + PA_CMD_CLEANUP_SHM } pa_daemon_conf_cmd_t; #ifdef HAVE_SYS_RESOURCE_H @@ -80,6 +83,8 @@ typedef struct pa_daemon_conf { #endif #endif + unsigned default_n_fragments, default_fragment_size_msec; + pa_sample_spec default_sample_spec; } pa_daemon_conf; /* Allocate a new structure and fill it with sane defaults */ diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in index 29b22a42..2132bf3d 100644 --- a/src/daemon/daemon.conf.in +++ b/src/daemon/daemon.conf.in @@ -92,10 +92,19 @@ ; rlimit-core = -1 ; rlimit-data = -1 ; rlimit-fsize = -1 -; rlimit-nofile = 200 +; rlimit-nofile = 256 ; rlimit-stack = -1 ; rlimit-nproc = -1 -; rlimit-memlock = 25 +; rlimit-memlock = 16384 ## Disable shared memory data transfer ; disable-shm = 0 + +## Default sample format +; default-sample-format = s16le +; default-sample-rate = 44100 +; default-sample-channels = 2 + +## Default fragment settings, for device drivers that need this +; default-fragments = 4 +; default-fragment-size-msec = 25 diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in index af2a6789..597993c4 100755 --- a/src/daemon/default.pa.in +++ b/src/daemon/default.pa.in @@ -1,5 +1,4 @@ -#!@PA_BINARY@ -nF - +#!@PA_BINARY@ -nF # # This file is part of PulseAudio. # @@ -17,8 +16,19 @@ # along with PulseAudio; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +.nofail + +### Load something into the sample cache +#load-sample-lazy x11-bell /usr/share/sounds/gtk-events/activate.wav +load-sample-lazy pulse-hotplug /usr/share/sounds/startup3.wav +#load-sample-lazy pulse-coldplug /usr/share/sounds/startup3.wav +#load-sample-lazy pulse-access /usr/share/sounds/generic.wav -### Load audio drivers statically +.fail + +### Load audio drivers statically (it's probably better to not load +### these drivers manually, but instead use module-hal-detect -- +### see below -- for doing this automatically) #load-module module-alsa-sink #load-module module-alsa-source device=hw:1,0 #load-module module-oss device="/dev/dsp" sink_name=output source_name=input @@ -27,19 +37,13 @@ #load-module module-pipe-sink ### Automatically load driver modules depending on the hardware available -@HAVE_HAL_TRUE@load-module module-hal-detect - +.ifexists @PA_DLSEARCHPATH@/module-hal-detect@PA_SOEXT@ +load-module module-hal-detect +.else ### Alternatively use the static hardware detection module (for systems that -### lack HAL support -@HAVE_HAL_FALSE@load-module module-detect - -### Load audio drivers automatically on access -#add-autoload-sink output module-oss device="/dev/dsp" sink_name=output source_name=input -#add-autoload-source input module-oss device="/dev/dsp" sink_name=output source_name=input -#add-autoload-sink output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#add-autoload-source input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#add-autoload-sink output module-alsa-sink sink_name=output -#add-autoload-source input module-alsa-source source_name=input +### lack HAL support) +load-module module-detect +.endif ### Load several protocols load-module module-esound-protocol-unix @@ -61,27 +65,36 @@ load-module module-native-protocol-unix ### Automatically restore the volume of playback streams load-module module-volume-restore +### Automatically restore the default sink/source when changed by the user during runtime +load-module module-default-device-restore + ### Automatically move streams to the default sink if the sink they are ### connected to dies, similar for sources load-module module-rescue-streams -### Make some devices default -#set-default-sink output -#set-default-source input - -.nofail - -### Load something to the sample cache -load-sample x11-bell /usr/share/sounds/gtk-events/activate.wav -#load-sample-dir-lazy /usr/share/sounds/*.wav +### Automatically suspend sinks/sources that become idle for too long +load-module module-suspend-on-idle ### Load X11 bell module -load-module module-x11-bell sample=x11-bell +#load-module module-x11-bell sample=x11-bell ### Publish connection data in the X11 root window +.ifexists @PA_DLSEARCHPATH@/module-x11-publish@PA_SOEXT@ load-module module-x11-publish +.endif + +### Register ourselves in the X11 session manager +# Deactivated by default, to avoid deadlock when PA is started as esd from gnome-session +# Instead we load this via /etc/xdg/autostart/ and "pactl load-module" now +# load-module module-x11-xsmp ### Load additional modules from GConf settings. This can be configured with the paprefs tool. ### Please keep in mind that the modules configured by paprefs might conflict with manually ### loaded modules. +.ifexists @PA_DLSEARCHPATH@/module-gconf@PA_SOEXT@ load-module module-gconf +.endif + +### Make some devices default +#set-default-sink output +#set-default-source input diff --git a/src/daemon/dumpmodules.c b/src/daemon/dumpmodules.c index 6743622a..ad7fab20 100644 --- a/src/daemon/dumpmodules.c +++ b/src/daemon/dumpmodules.c @@ -28,26 +28,30 @@ #include #include -#include #include #include #include #include +#include +#include #include "dumpmodules.h" #define PREFIX "module-" static void short_info(const char *name, PA_GCC_UNUSED const char *path, pa_modinfo *i) { - assert(name && i); + pa_assert(name); + pa_assert(i); + printf("%-40s%s\n", name, i->description ? i->description : "n/a"); } static void long_info(const char *name, const char *path, pa_modinfo *i) { static int nl = 0; - assert(name && i); + pa_assert(name); + pa_assert(i); if (nl) printf("\n"); @@ -76,6 +80,8 @@ static void long_info(const char *name, const char *path, pa_modinfo *i) { static void show_info(const char *name, const char *path, void (*info)(const char *name, const char *path, pa_modinfo*i)) { pa_modinfo *i; + pa_assert(name); + if ((i = pa_modinfo_get_by_name(path ? path : name))) { info(name, path, i); pa_modinfo_free(i); @@ -93,7 +99,7 @@ static int is_preloaded(const char *name) { if (l->address) continue; - snprintf(buf, sizeof(buf), "%s", l->name); + pa_snprintf(buf, sizeof(buf), "%s", l->name); if ((e = strrchr(buf, '.'))) *e = 0; @@ -121,6 +127,8 @@ static int callback(const char *path, lt_ptr data) { } void pa_dump_modules(pa_daemon_conf *c, int argc, char * const argv[]) { + pa_assert(c); + if (argc > 0) { int i; for (i = 0; i < argc; i++) @@ -137,7 +145,7 @@ void pa_dump_modules(pa_daemon_conf *c, int argc, char * const argv[]) { if (strlen(l->name) <= sizeof(PREFIX)-1 || strncmp(l->name, PREFIX, sizeof(PREFIX)-1)) continue; - snprintf(buf, sizeof(buf), "%s", l->name); + pa_snprintf(buf, sizeof(buf), "%s", l->name); if ((e = strrchr(buf, '.'))) *e = 0; diff --git a/src/daemon/ltdl-bind-now.c b/src/daemon/ltdl-bind-now.c new file mode 100644 index 00000000..6025c6e3 --- /dev/null +++ b/src/daemon/ltdl-bind-now.c @@ -0,0 +1,160 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if HAVE_DLFCN_H +#include +#endif + +#if HAVE_SYS_DL_H +#include +#endif + +#include + +#include +#include +#include +#include + +#include "ltdl-bind-now.h" + +#ifdef RTLD_NOW +#define PA_BIND_NOW RTLD_NOW +#elif defined(DL_NOW) +#define PA_BIND_NOW DL_NOW +#else +#undef PA_BIND_NOW +#endif + +static pa_mutex *libtool_mutex = NULL; + +PA_STATIC_TLS_DECLARE_NO_FREE(libtool_tls); + +static void libtool_lock(void) { + pa_mutex_lock(libtool_mutex); +} + +static void libtool_unlock(void) { + pa_mutex_unlock(libtool_mutex); +} + +static void libtool_set_error(const char *error) { + PA_STATIC_TLS_SET(libtool_tls, (char*) error); +} + +static const char *libtool_get_error(void) { + return PA_STATIC_TLS_GET(libtool_tls); +} + +#ifdef PA_BIND_NOW + +/* + To avoid lazy relocations during runtime in our RT threads we add + our own shared object loader with uses RTLD_NOW if it is + available. The standard ltdl loader prefers RTLD_LAZY. + + Please note that this loader doesn't have any influence on + relocations on any libraries that are already loaded into our + process, i.e. because the pulseaudio binary links directly to + them. To disable lazy relocations for those libraries it is possible + to set $LT_BIND_NOW before starting the pulsaudio binary. +*/ + +static lt_module bind_now_open(lt_user_data d, const char *fname) { + lt_module m; + + pa_assert(fname); + + if (!(m = dlopen(fname, PA_BIND_NOW))) { + libtool_set_error(dlerror()); + return NULL; + } + + return m; +} + +static int bind_now_close(lt_user_data d, lt_module m) { + + pa_assert(m); + + if (dlclose(m) != 0){ + libtool_set_error(dlerror()); + return 1; + } + + return 0; +} + +static lt_ptr bind_now_find_sym(lt_user_data d, lt_module m, const char *symbol) { + lt_ptr ptr; + + pa_assert(m); + pa_assert(symbol); + + if (!(ptr = dlsym(m, symbol))) { + libtool_set_error(dlerror()); + return NULL; + } + + return ptr; +} + +#endif + +void pa_ltdl_init(void) { + +#ifdef PA_BIND_NOW + lt_dlloader *place; + static const struct lt_user_dlloader loader = { + .module_open = bind_now_open, + .module_close = bind_now_close, + .find_sym = bind_now_find_sym + }; +#endif + + pa_assert_se(lt_dlinit() == 0); + pa_assert_se(libtool_mutex = pa_mutex_new(TRUE, FALSE)); + pa_assert_se(lt_dlmutex_register(libtool_lock, libtool_unlock, libtool_set_error, libtool_get_error) == 0); + +#ifdef PA_BIND_NOW + + if (!(place = lt_dlloader_find("dlopen"))) + place = lt_dlloader_next(NULL); + + /* Add our BIND_NOW loader as the default module loader. */ + if (lt_dlloader_add(place, &loader, "bind-now-loader") != 0) + pa_log_warn("Failed to add bind-now-loader."); +#endif +} + +void pa_ltdl_done(void) { + pa_assert_se(lt_dlexit() == 0); + pa_mutex_free(libtool_mutex); + libtool_mutex = NULL; +} + diff --git a/src/daemon/ltdl-bind-now.h b/src/daemon/ltdl-bind-now.h new file mode 100644 index 00000000..e19c7bc1 --- /dev/null +++ b/src/daemon/ltdl-bind-now.h @@ -0,0 +1,32 @@ +#ifndef foopulsecoreltdlbindnowhfoo +#define foopulsecoreltdlbindnowhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + + +void pa_ltdl_init(void); +void pa_ltdl_done(void); + +#endif + diff --git a/src/daemon/main.c b/src/daemon/main.c index 91cc3a2f..6c9f6627 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -59,13 +58,16 @@ #include #endif -#include "../pulsecore/winsock.h" +#ifdef HAVE_DBUS +#include +#endif #include #include #include #include +#include #include #include #include @@ -78,12 +80,20 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #include "cmdline.h" #include "cpulimit.h" #include "daemon-conf.h" #include "dumpmodules.h" #include "caps.h" +#include "ltdl-bind-now.h" #ifdef HAVE_LIBWRAP /* Only one instance of these variables */ @@ -120,7 +130,7 @@ static void message_cb(pa_mainloop_api*a, pa_time_event*e, PA_GCC_UNUSED const s #endif static void signal_callback(pa_mainloop_api*m, PA_GCC_UNUSED pa_signal_event *e, int sig, void *userdata) { - pa_log_info("Got signal %s.", pa_strsignal(sig)); + pa_log_info("Got signal %s.", pa_sig2str(sig)); switch (sig) { #ifdef SIGUSR1 @@ -153,14 +163,6 @@ static void signal_callback(pa_mainloop_api*m, PA_GCC_UNUSED pa_signal_event *e, } } -static void close_pipe(int p[2]) { - if (p[0] != -1) - close(p[0]); - if (p[1] != -1) - close(p[1]); - p[0] = p[1] = -1; -} - #define set_env(key, value) putenv(pa_sprintf_malloc("%s=%s", (key), (value))) #if defined(HAVE_PWD_H) && defined(HAVE_GRP_H) @@ -281,7 +283,7 @@ static int create_runtime_dir(void) { static void set_one_rlimit(const pa_rlimit *r, int resource, const char *name) { struct rlimit rl; - assert(r); + pa_assert(r); if (!r->is_set) return; @@ -313,13 +315,11 @@ int main(int argc, char *argv[]) { pa_strbuf *buf = NULL; pa_daemon_conf *conf = NULL; pa_mainloop *mainloop = NULL; - char *s; - int r, retval = 1, d = 0; + int r = 0, retval = 1, d = 0; int daemon_pipe[2] = { -1, -1 }; int suid_root, real_root; int valid_pid_file = 0; - gid_t gid = (gid_t) -1; #ifdef OS_IS_WIN32 @@ -327,6 +327,23 @@ int main(int argc, char *argv[]) { struct timeval tv; #endif + +#if defined(__linux__) && defined(__OPTIMIZE__) + /* + Disable lazy relocations to make usage of external libraries + more deterministic for our RT threads. We abuse __OPTIMIZE__ as + a check whether we are a debug build or not. + */ + + if (!getenv("LD_BIND_NOW")) { + putenv(pa_xstrdup("LD_BIND_NOW=1")); + + /* We have to execute ourselves, because the libc caches the + * value of $LD_BIND_NOW on initialization. */ + pa_assert_se(execv("/proc/self/exe", argv) == 0); + } +#endif + #ifdef HAVE_GETUID real_root = getuid() == 0; suid_root = !real_root && geteuid() == 0; @@ -336,16 +353,26 @@ int main(int argc, char *argv[]) { #endif if (suid_root) { - if (pa_limit_caps() > 0) - /* We managed to drop capabilities except the needed - * ones. Hence we can drop the uid. */ - pa_drop_root(); + /* Drop all capabilities except CAP_SYS_NICE */ + pa_limit_caps(); + + /* Drop priviliges, but keep CAP_SYS_NICE */ + pa_drop_root(); + + /* After dropping root, the effective set is reset, hence, + * let's raise it again */ + pa_limit_caps(); + + /* When capabilities are not supported we will not be able to + * aquire RT sched anymore. But yes, that's the way it is. It + * is just too risky tun let PA run as root all the time. */ } setlocale(LC_ALL, ""); - if (suid_root && (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) <= 0 || gid >= 1000)) { - pa_log_warn("WARNING: called SUID root, but not in group '"PA_REALTIME_GROUP"'."); + if (suid_root && (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) <= 0)) { + pa_log_info("Warning: Called SUID root, but not in group '"PA_REALTIME_GROUP"'. " + "For enabling real-time scheduling please become a member of '"PA_REALTIME_GROUP"' , or increase the RLIMIT_RTPRIO user limit."); pa_drop_caps(); pa_drop_root(); suid_root = real_root = 0; @@ -353,8 +380,7 @@ int main(int argc, char *argv[]) { LTDL_SET_PRELOADED_SYMBOLS(); - r = lt_dlinit(); - assert(r == 0); + pa_ltdl_init(); #ifdef OS_IS_WIN32 { @@ -386,7 +412,7 @@ int main(int argc, char *argv[]) { if (conf->high_priority && conf->cmd == PA_CMD_DAEMON) pa_raise_priority(); - if (suid_root) { + if (suid_root && (conf->cmd != PA_CMD_DAEMON || !conf->high_priority)) { pa_drop_caps(); pa_drop_root(); } @@ -408,6 +434,16 @@ int main(int argc, char *argv[]) { goto finish; } + case PA_CMD_DUMP_RESAMPLE_METHODS: { + int i; + + for (i = 0; i < PA_RESAMPLER_MAX; i++) + if (pa_resample_method_supported(i)) + printf("%s\n", pa_resample_method_to_string(i)); + + goto finish; + } + case PA_CMD_HELP : pa_cmdline_help(argv[0]); retval = 0; @@ -440,8 +476,15 @@ int main(int argc, char *argv[]) { goto finish; + case PA_CMD_CLEANUP_SHM: + + if (pa_shm_cleanup() >= 0) + retval = 0; + + goto finish; + default: - assert(conf->cmd == PA_CMD_DAEMON); + pa_assert(conf->cmd == PA_CMD_DAEMON); } if (real_root && !conf->system_instance) { @@ -474,7 +517,7 @@ int main(int argc, char *argv[]) { if (child != 0) { /* Father */ - close(daemon_pipe[1]); + pa_assert_se(pa_close(daemon_pipe[1]) == 0); daemon_pipe[1] = -1; if (pa_loop_read(daemon_pipe[0], &retval, sizeof(retval), NULL) != sizeof(retval)) { @@ -490,7 +533,7 @@ int main(int argc, char *argv[]) { goto finish; } - close(daemon_pipe[0]); + pa_assert_se(pa_close(daemon_pipe[0]) == 0); daemon_pipe[0] = -1; #endif @@ -505,9 +548,9 @@ int main(int argc, char *argv[]) { #endif #ifndef OS_IS_WIN32 - close(0); - close(1); - close(2); + pa_close(0); + pa_close(1); + pa_close(2); open("/dev/null", O_RDONLY); open("/dev/null", O_WRONLY); @@ -529,12 +572,12 @@ int main(int argc, char *argv[]) { #ifdef TIOCNOTTY if ((tty_fd = open("/dev/tty", O_RDWR)) >= 0) { ioctl(tty_fd, TIOCNOTTY, (char*) 0); - close(tty_fd); + pa_assert_se(pa_close(tty_fd) == 0); } #endif } - chdir("/"); + pa_assert_se(chdir("/") == 0); umask(0022); if (conf->system_instance) { @@ -564,18 +607,37 @@ int main(int argc, char *argv[]) { signal(SIGPIPE, SIG_IGN); #endif - mainloop = pa_mainloop_new(); - assert(mainloop); + pa_log_info("Page size is %lu bytes", (unsigned long) PA_PAGE_SIZE); + + if (pa_rtclock_hrtimer()) + pa_log_info("Fresh high-resolution timers available! Bon appetit!"); + else + pa_log_info("Dude, your kernel stinks! The chef's recommendation today is Linux with high-resolution timers enabled!"); + +#ifdef SIGRTMIN + /* Valgrind uses SIGRTMAX. To easy debugging we don't use it here */ + pa_rtsig_configure(SIGRTMIN, SIGRTMAX-1); +#endif + + pa_assert_se(mainloop = pa_mainloop_new()); if (!(c = pa_core_new(pa_mainloop_get_api(mainloop), !conf->disable_shm))) { - pa_log("pa_core_new() failed."); + pa_log("pa_core_new() failed."); goto finish; } c->is_system_instance = !!conf->system_instance; - - r = pa_signal_init(pa_mainloop_get_api(mainloop)); - assert(r == 0); + c->high_priority = !!conf->high_priority; + c->default_sample_spec = conf->default_sample_spec; + c->default_n_fragments = conf->default_n_fragments; + c->default_fragment_size_msec = conf->default_fragment_size_msec; + c->disallow_module_loading = conf->disallow_module_loading; + c->exit_idle_time = conf->exit_idle_time; + c->module_idle_time = conf->module_idle_time; + c->scache_idle_time = conf->scache_idle_time; + c->resample_method = conf->resample_method; + + pa_assert_se(pa_signal_init(pa_mainloop_get_api(mainloop)) == 0); pa_signal_new(SIGINT, signal_callback, c); pa_signal_new(SIGTERM, signal_callback, c); @@ -590,9 +652,7 @@ int main(int argc, char *argv[]) { #endif #ifdef OS_IS_WIN32 - timer = pa_mainloop_get_api(mainloop)->time_new( - pa_mainloop_get_api(mainloop), pa_gettimeofday(&tv), message_cb, NULL); - assert(timer); + pa_assert_se(timer = pa_mainloop_get_api(mainloop)->time_new(pa_mainloop_get_api(mainloop), pa_gettimeofday(&tv), message_cb, NULL)); #endif if (conf->daemonize) @@ -600,10 +660,8 @@ int main(int argc, char *argv[]) { oil_init(); - if (!conf->no_cpu_limit) { - r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop)); - assert(r == 0); - } + if (!conf->no_cpu_limit) + pa_assert_se(pa_cpu_limit_init(pa_mainloop_get_api(mainloop)) == 0); buf = pa_strbuf_new(); if (conf->default_script_file) @@ -634,12 +692,6 @@ int main(int argc, char *argv[]) { pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL); #endif - c->disallow_module_loading = conf->disallow_module_loading; - c->exit_idle_time = conf->exit_idle_time; - c->module_idle_time = conf->module_idle_time; - c->scache_idle_time = conf->scache_idle_time; - c->resample_method = conf->resample_method; - if (c->default_sink_name && pa_namereg_get(c, c->default_sink_name, PA_NAMEREG_SINK, 1) == NULL) { pa_log_error("%s : Fatal error. Default sink name (%s) does not exist in name register.", __FILE__, c->default_sink_name); @@ -656,7 +708,7 @@ int main(int argc, char *argv[]) { pa_mainloop_get_api(mainloop)->time_free(timer); #endif - pa_core_free(c); + pa_core_unref(c); if (!conf->no_cpu_limit) pa_cpu_limit_done(); @@ -676,13 +728,17 @@ finish: if (valid_pid_file) pa_pid_file_remove(); - close_pipe(daemon_pipe); + pa_close_pipe(daemon_pipe); #ifdef OS_IS_WIN32 WSACleanup(); #endif - lt_dlexit(); + pa_ltdl_done(); + +#ifdef HAVE_DBUS + dbus_shutdown(); +#endif return retval; } diff --git a/src/daemon/pulseaudio-module-xsmp.desktop b/src/daemon/pulseaudio-module-xsmp.desktop new file mode 100644 index 00000000..fa719a73 --- /dev/null +++ b/src/daemon/pulseaudio-module-xsmp.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Version=1.0 +Encoding=UTF-8 +Name=PulseAudio Session Management +Comment=Load module-x11-xsmp into PulseAudio +Exec=pactl load-module module-x11-xsmp +Terminal=false +Type=Application +Categories= +GenericName= diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 40be5311..906de58d 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -33,6 +33,7 @@ #include #include +#include #include "alsa-util.h" @@ -42,7 +43,6 @@ struct pa_alsa_fdlist { /* This is a temporary buffer used to avoid lots of mallocs */ struct pollfd *work_fds; - snd_pcm_t *pcm; snd_mixer_t *mixer; pa_mainloop_api *m; @@ -56,11 +56,16 @@ struct pa_alsa_fdlist { }; static void io_cb(pa_mainloop_api*a, pa_io_event* e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void *userdata) { - struct pa_alsa_fdlist *fdl = (struct pa_alsa_fdlist*)userdata; + + struct pa_alsa_fdlist *fdl = userdata; int err, i; unsigned short revents; - assert(a && fdl && (fdl->pcm || fdl->mixer) && fdl->fds && fdl->work_fds); + pa_assert(a); + pa_assert(fdl); + pa_assert(fdl->mixer); + pa_assert(fdl->fds); + pa_assert(fdl->work_fds); if (fdl->polled) return; @@ -69,7 +74,7 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, PA_GCC_UNUSED int fd, pa_io memcpy(fdl->work_fds, fdl->fds, sizeof(struct pollfd) * fdl->num_fds); - for (i = 0;i < fdl->num_fds;i++) { + for (i = 0;i < fdl->num_fds; i++) { if (e == fdl->ios[i]) { if (events & PA_IO_EVENT_INPUT) fdl->work_fds[i].revents |= POLLIN; @@ -83,63 +88,46 @@ static void io_cb(pa_mainloop_api*a, pa_io_event* e, PA_GCC_UNUSED int fd, pa_io } } - assert(i != fdl->num_fds); - - if (fdl->pcm) - err = snd_pcm_poll_descriptors_revents(fdl->pcm, fdl->work_fds, fdl->num_fds, &revents); - else - err = snd_mixer_poll_descriptors_revents(fdl->mixer, fdl->work_fds, fdl->num_fds, &revents); + pa_assert(i != fdl->num_fds); - if (err < 0) { - pa_log_error("Unable to get poll revent: %s", - snd_strerror(err)); + if ((err = snd_mixer_poll_descriptors_revents(fdl->mixer, fdl->work_fds, fdl->num_fds, &revents)) < 0) { + pa_log_error("Unable to get poll revent: %s", snd_strerror(err)); return; } a->defer_enable(fdl->defer, 1); - if (revents) { - if (fdl->pcm) - fdl->cb(fdl->userdata); - else - snd_mixer_handle_events(fdl->mixer); - } + if (revents) + snd_mixer_handle_events(fdl->mixer); } static void defer_cb(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event* e, void *userdata) { - struct pa_alsa_fdlist *fdl = (struct pa_alsa_fdlist*)userdata; + struct pa_alsa_fdlist *fdl = userdata; int num_fds, i, err; struct pollfd *temp; - assert(a && fdl && (fdl->pcm || fdl->mixer)); + pa_assert(a); + pa_assert(fdl); + pa_assert(fdl->mixer); a->defer_enable(fdl->defer, 0); - if (fdl->pcm) - num_fds = snd_pcm_poll_descriptors_count(fdl->pcm); - else - num_fds = snd_mixer_poll_descriptors_count(fdl->mixer); - assert(num_fds > 0); + num_fds = snd_mixer_poll_descriptors_count(fdl->mixer); + pa_assert(num_fds > 0); if (num_fds != fdl->num_fds) { if (fdl->fds) pa_xfree(fdl->fds); if (fdl->work_fds) pa_xfree(fdl->work_fds); - fdl->fds = pa_xmalloc0(sizeof(struct pollfd) * num_fds); - fdl->work_fds = pa_xmalloc(sizeof(struct pollfd) * num_fds); + fdl->fds = pa_xnew0(struct pollfd, num_fds); + fdl->work_fds = pa_xnew(struct pollfd, num_fds); } memset(fdl->work_fds, 0, sizeof(struct pollfd) * num_fds); - if (fdl->pcm) - err = snd_pcm_poll_descriptors(fdl->pcm, fdl->work_fds, num_fds); - else - err = snd_mixer_poll_descriptors(fdl->mixer, fdl->work_fds, num_fds); - - if (err < 0) { - pa_log_error("Unable to get poll descriptors: %s", - snd_strerror(err)); + if ((err = snd_mixer_poll_descriptors(fdl->mixer, fdl->work_fds, num_fds)) < 0) { + pa_log_error("Unable to get poll descriptors: %s", snd_strerror(err)); return; } @@ -149,18 +137,18 @@ static void defer_cb(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event* e, void *u return; if (fdl->ios) { - for (i = 0;i < fdl->num_fds;i++) + for (i = 0; i < fdl->num_fds; i++) a->io_free(fdl->ios[i]); + if (num_fds != fdl->num_fds) { pa_xfree(fdl->ios); - fdl->ios = pa_xmalloc(sizeof(pa_io_event*) * num_fds); - assert(fdl->ios); + fdl->ios = NULL; } - } else { - fdl->ios = pa_xmalloc(sizeof(pa_io_event*) * num_fds); - assert(fdl->ios); } + if (!fdl->ios) + fdl->ios = pa_xnew(pa_io_event*, num_fds); + /* Swap pointers */ temp = fdl->work_fds; fdl->work_fds = fdl->fds; @@ -168,47 +156,41 @@ static void defer_cb(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event* e, void *u fdl->num_fds = num_fds; - for (i = 0;i < num_fds;i++) { + for (i = 0;i < num_fds;i++) fdl->ios[i] = a->io_new(a, fdl->fds[i].fd, ((fdl->fds[i].events & POLLIN) ? PA_IO_EVENT_INPUT : 0) | ((fdl->fds[i].events & POLLOUT) ? PA_IO_EVENT_OUTPUT : 0), io_cb, fdl); - assert(fdl->ios[i]); - } } struct pa_alsa_fdlist *pa_alsa_fdlist_new(void) { struct pa_alsa_fdlist *fdl; - fdl = pa_xmalloc(sizeof(struct pa_alsa_fdlist)); + fdl = pa_xnew0(struct pa_alsa_fdlist, 1); fdl->num_fds = 0; fdl->fds = NULL; fdl->work_fds = NULL; - - fdl->pcm = NULL; fdl->mixer = NULL; - fdl->m = NULL; fdl->defer = NULL; fdl->ios = NULL; - fdl->polled = 0; return fdl; } void pa_alsa_fdlist_free(struct pa_alsa_fdlist *fdl) { - assert(fdl); + pa_assert(fdl); if (fdl->defer) { - assert(fdl->m); + pa_assert(fdl->m); fdl->m->defer_free(fdl->defer); } if (fdl->ios) { int i; - assert(fdl->m); + pa_assert(fdl->m); for (i = 0;i < fdl->num_fds;i++) fdl->m->io_free(fdl->ios[i]); pa_xfree(fdl->ios); @@ -222,29 +204,15 @@ void pa_alsa_fdlist_free(struct pa_alsa_fdlist *fdl) { pa_xfree(fdl); } -int pa_alsa_fdlist_init_pcm(struct pa_alsa_fdlist *fdl, snd_pcm_t *pcm_handle, pa_mainloop_api* m, void (*cb)(void *userdata), void *userdata) { - assert(fdl && pcm_handle && m && !fdl->m && cb); - - fdl->pcm = pcm_handle; - fdl->m = m; - - fdl->defer = m->defer_new(m, defer_cb, fdl); - assert(fdl->defer); - - fdl->cb = cb; - fdl->userdata = userdata; - - return 0; -} - -int pa_alsa_fdlist_init_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, pa_mainloop_api* m) { - assert(fdl && mixer_handle && m && !fdl->m); +int pa_alsa_fdlist_set_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, pa_mainloop_api* m) { + pa_assert(fdl); + pa_assert(mixer_handle); + pa_assert(m); + pa_assert(!fdl->m); fdl->mixer = mixer_handle; fdl->m = m; - fdl->defer = m->defer_new(m, defer_cb, fdl); - assert(fdl->defer); return 0; } @@ -274,8 +242,8 @@ static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_s int i, ret; - assert(pcm_handle); - assert(f); + pa_assert(pcm_handle); + pa_assert(f); if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0) return ret; @@ -308,7 +276,7 @@ try_auto: /* Set the hardware parameters of the given ALSA device. Returns the * selected fragment settings in *period and *period_size */ -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) { +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size, int *use_mmap) { int ret = -1; snd_pcm_uframes_t buffer_size; unsigned int r = ss->rate; @@ -316,17 +284,32 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p pa_sample_format_t f = ss->format; snd_pcm_hw_params_t *hwparams; - assert(pcm_handle); - assert(ss); - assert(periods); - assert(period_size); + pa_assert(pcm_handle); + pa_assert(ss); + pa_assert(periods); + pa_assert(period_size); + + snd_pcm_hw_params_alloca(&hwparams); buffer_size = *periods * *period_size; - if ((ret = snd_pcm_hw_params_malloc(&hwparams)) < 0 || - (ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 || - (ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0 || - (ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) + if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 || + (ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0) + goto finish; + + if (use_mmap && *use_mmap) { + if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) { + + /* mmap() didn't work, fall back to interleaved */ + + if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) + goto finish; + + if (use_mmap) + *use_mmap = 0; + } + + } else if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) goto finish; if ((ret = set_format(pcm_handle, hwparams, &f)) < 0) @@ -346,7 +329,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p goto finish; if (ss->rate != r) { - pa_log_warn("device doesn't support %u Hz, changed to %u Hz.", ss->rate, r); + pa_log_warn("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, r); /* If the sample rate deviates too much, we need to resample */ if (r < ss->rate*.95 || r > ss->rate*1.05) @@ -354,12 +337,12 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p } if (ss->channels != c) { - pa_log_warn("device doesn't support %u channels, changed to %u.", ss->channels, c); + pa_log_warn("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, c); ss->channels = c; } if (ss->format != f) { - pa_log_warn("device doesn't support sample format %s, changed to %s.", pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f)); + pa_log_warn("Device %s doesn't support sample format %s, changed to %s.", snd_pcm_name(pcm_handle), pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f)); ss->format = f; } @@ -370,24 +353,54 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p (ret = snd_pcm_hw_params_get_period_size(hwparams, period_size, NULL)) < 0) goto finish; - assert(buffer_size > 0); - assert(*period_size > 0); + pa_assert(buffer_size > 0); + pa_assert(*period_size > 0); *periods = buffer_size / *period_size; - assert(*periods > 0); + pa_assert(*periods > 0); ret = 0; finish: - if (hwparams) - snd_pcm_hw_params_free(hwparams); return ret; } +int pa_alsa_set_sw_params(snd_pcm_t *pcm) { + snd_pcm_sw_params_t *swparams; + int err; + + pa_assert(pcm); + + snd_pcm_sw_params_alloca(&swparams); + + if ((err = snd_pcm_sw_params_current(pcm, swparams) < 0)) { + pa_log_warn("Unable to determine current swparams: %s\n", snd_strerror(err)); + return err; + } + + if ((err = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, (snd_pcm_uframes_t) -1)) < 0) { + pa_log_warn("Unable to set stop threshold: %s\n", snd_strerror(err)); + return err; + } + + if ((err = snd_pcm_sw_params_set_start_threshold(pcm, swparams, (snd_pcm_uframes_t) -1)) < 0) { + pa_log_warn("Unable to set start threshold: %s\n", snd_strerror(err)); + return err; + } + + if ((err = snd_pcm_sw_params(pcm, swparams)) < 0) { + pa_log_warn("Unable to set sw params: %s\n", snd_strerror(err)); + return err; + } + + return 0; +} + int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { int err; - assert(mixer && dev); + pa_assert(mixer); + pa_assert(dev); if ((err = snd_mixer_attach(mixer, dev)) < 0) { pa_log_warn("Unable to attach to mixer %s: %s", dev, snd_strerror(err)); @@ -410,10 +423,11 @@ int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback) { snd_mixer_elem_t *elem; snd_mixer_selem_id_t *sid = NULL; + snd_mixer_selem_id_alloca(&sid); - assert(mixer); - assert(name); + pa_assert(mixer); + pa_assert(name); snd_mixer_selem_id_set_name(sid, name); diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h index ea6c7e1d..6f1f927e 100644 --- a/src/modules/alsa-util.h +++ b/src/modules/alsa-util.h @@ -32,15 +32,14 @@ #include -struct pa_alsa_fdlist; +typedef struct pa_alsa_fdlist pa_alsa_fdlist; struct pa_alsa_fdlist *pa_alsa_fdlist_new(void); void pa_alsa_fdlist_free(struct pa_alsa_fdlist *fdl); +int pa_alsa_fdlist_set_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, pa_mainloop_api* m); -int pa_alsa_fdlist_init_pcm(struct pa_alsa_fdlist *fdl, snd_pcm_t *pcm_handle, pa_mainloop_api* m, void (*cb)(void *userdata), void *userdata); -int pa_alsa_fdlist_init_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, pa_mainloop_api* m); - -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size); +int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size, int *use_mmap); +int pa_alsa_set_sw_params(snd_pcm_t *pcm); int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev); snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback); diff --git a/src/modules/dbus-util.c b/src/modules/dbus-util.c index 48a45174..fc1e91ea 100644 --- a/src/modules/dbus-util.c +++ b/src/modules/dbus-util.c @@ -26,25 +26,25 @@ #include #endif -#include -#include -#include #include #include +#include +#include #include "dbus-util.h" struct pa_dbus_connection { - int refcount; + PA_REFCNT_DECLARE; + pa_core *core; DBusConnection *connection; const char *property_name; pa_defer_event* dispatch_event; }; -static void dispatch_cb(pa_mainloop_api *ea, pa_defer_event *ev, void *userdata) -{ - DBusConnection *conn = (DBusConnection *) userdata; +static void dispatch_cb(pa_mainloop_api *ea, pa_defer_event *ev, void *userdata) { + DBusConnection *conn = userdata; + if (dbus_connection_dispatch(conn) == DBUS_DISPATCH_COMPLETE) { /* no more data to process, disable the deferred */ ea->defer_enable(ev, 0); @@ -52,14 +52,17 @@ static void dispatch_cb(pa_mainloop_api *ea, pa_defer_event *ev, void *userdata) } /* DBusDispatchStatusFunction callback for the pa mainloop */ -static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, - void *userdata) -{ - pa_dbus_connection *c = (pa_dbus_connection*) userdata; +static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, void *userdata) { + pa_dbus_connection *c = userdata; + + pa_assert(c); + switch(status) { + case DBUS_DISPATCH_COMPLETE: c->core->mainloop->defer_enable(c->dispatch_event, 0); break; + case DBUS_DISPATCH_DATA_REMAINS: case DBUS_DISPATCH_NEED_MEMORY: default: @@ -68,11 +71,13 @@ static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, } } -static pa_io_event_flags_t -get_watch_flags(DBusWatch *watch) -{ - unsigned int flags = dbus_watch_get_flags(watch); - pa_io_event_flags_t events = PA_IO_EVENT_HANGUP | PA_IO_EVENT_ERROR; +static pa_io_event_flags_t get_watch_flags(DBusWatch *watch) { + unsigned int flags; + pa_io_event_flags_t events = 0; + + pa_assert(watch); + + flags = dbus_watch_get_flags(watch); /* no watch flags for disabled watches */ if (!dbus_watch_get_enabled(watch)) @@ -83,21 +88,22 @@ get_watch_flags(DBusWatch *watch) if (flags & DBUS_WATCH_WRITABLE) events |= PA_IO_EVENT_OUTPUT; - return events; + return events | PA_IO_EVENT_HANGUP | PA_IO_EVENT_ERROR; } /* pa_io_event_cb_t IO event handler */ -static void handle_io_event(PA_GCC_UNUSED pa_mainloop_api *ea, pa_io_event *e, - int fd, pa_io_event_flags_t events, void *userdata) -{ +static void handle_io_event(PA_GCC_UNUSED pa_mainloop_api *ea, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) { unsigned int flags = 0; - DBusWatch *watch = (DBusWatch*) userdata; + DBusWatch *watch = userdata; - assert(fd == dbus_watch_get_fd(watch)); +#if HAVE_DBUS_WATCH_GET_UNIX_FD + pa_assert(fd == dbus_watch_get_unix_fd(watch)); +#else + pa_assert(fd == dbus_watch_get_fd(watch)); +#endif if (!dbus_watch_get_enabled(watch)) { - pa_log_warn("Asked to handle disabled watch: %p %i", - (void *) watch, fd); + pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch, fd); return; } @@ -114,10 +120,8 @@ static void handle_io_event(PA_GCC_UNUSED pa_mainloop_api *ea, pa_io_event *e, } /* pa_time_event_cb_t timer event handler */ -static void handle_time_event(pa_mainloop_api *ea, pa_time_event* e, - const struct timeval *tv, void *userdata) -{ - DBusTimeout *timeout = (DBusTimeout*) userdata; +static void handle_time_event(pa_mainloop_api *ea, pa_time_event* e, const struct timeval *tv, void *userdata) { + DBusTimeout *timeout = userdata; if (dbus_timeout_get_enabled(timeout)) { struct timeval next = *tv; @@ -130,218 +134,195 @@ static void handle_time_event(pa_mainloop_api *ea, pa_time_event* e, } /* DBusAddWatchFunction callback for pa mainloop */ -static dbus_bool_t add_watch(DBusWatch *watch, void *data) -{ +static dbus_bool_t add_watch(DBusWatch *watch, void *data) { + pa_core *c = PA_CORE(data); pa_io_event *ev; - pa_core *c = (pa_core*) data; - ev = c->mainloop->io_new(c->mainloop, dbus_watch_get_fd(watch), - get_watch_flags(watch), - handle_io_event, (void*) watch); - if (NULL == ev) - return FALSE; + pa_assert(watch); + pa_assert(c); - /* dbus_watch_set_data(watch, (void*) ev, c->mainloop->io_free); */ - dbus_watch_set_data(watch, (void*) ev, NULL); + ev = c->mainloop->io_new( + c->mainloop, +#if HAVE_DBUS_WATCH_GET_UNIX_FD + dbus_watch_get_unix_fd(watch), +#else + dbus_watch_get_fd(watch), +#endif + get_watch_flags(watch), handle_io_event, watch); + + dbus_watch_set_data(watch, ev, NULL); return TRUE; } /* DBusRemoveWatchFunction callback for pa mainloop */ -static void remove_watch(DBusWatch *watch, void *data) -{ - pa_core *c = (pa_core*) data; - pa_io_event *ev = (pa_io_event*) dbus_watch_get_data(watch); +static void remove_watch(DBusWatch *watch, void *data) { + pa_core *c = PA_CORE(data); + pa_io_event *ev; - /* free the event */ - if (NULL != ev) + pa_assert(watch); + pa_assert(c); + + if ((ev = dbus_watch_get_data(watch))) c->mainloop->io_free(ev); } /* DBusWatchToggledFunction callback for pa mainloop */ -static void toggle_watch(DBusWatch *watch, void *data) -{ - pa_core *c = (pa_core*) data; - pa_io_event *ev = (pa_io_event*) dbus_watch_get_data(watch); +static void toggle_watch(DBusWatch *watch, void *data) { + pa_core *c = PA_CORE(data); + pa_io_event *ev; + + pa_assert(watch); + pa_core_assert_ref(c); + + pa_assert_se(ev = dbus_watch_get_data(watch)); /* get_watch_flags() checks if the watch is enabled */ c->mainloop->io_enable(ev, get_watch_flags(watch)); } /* DBusAddTimeoutFunction callback for pa mainloop */ -static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) -{ - struct timeval tv; +static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) { + pa_core *c = PA_CORE(data); pa_time_event *ev; - pa_core *c = (pa_core*) data; + struct timeval tv; + + pa_assert(timeout); + pa_assert(c); if (!dbus_timeout_get_enabled(timeout)) return FALSE; - if (!pa_gettimeofday(&tv)) - return -1; - + pa_gettimeofday(&tv); pa_timeval_add(&tv, dbus_timeout_get_interval(timeout) * 1000); - ev = c->mainloop->time_new(c->mainloop, &tv, handle_time_event, - (void*) timeout); - if (NULL == ev) - return FALSE; + ev = c->mainloop->time_new(c->mainloop, &tv, handle_time_event, timeout); - /* dbus_timeout_set_data(timeout, (void*) ev, c->mainloop->time_free); */ - dbus_timeout_set_data(timeout, (void*) ev, NULL); + dbus_timeout_set_data(timeout, ev, NULL); return TRUE; } /* DBusRemoveTimeoutFunction callback for pa mainloop */ -static void remove_timeout(DBusTimeout *timeout, void *data) -{ - pa_core *c = (pa_core*) data; - pa_time_event *ev = (pa_time_event*) dbus_timeout_get_data(timeout); +static void remove_timeout(DBusTimeout *timeout, void *data) { + pa_core *c = PA_CORE(data); + pa_time_event *ev; + + pa_assert(timeout); + pa_assert(c); - /* free the event */ - if (NULL != ev) + if ((ev = dbus_timeout_get_data(timeout))) c->mainloop->time_free(ev); } /* DBusTimeoutToggledFunction callback for pa mainloop */ -static void toggle_timeout(DBusTimeout *timeout, void *data) -{ - struct timeval tv; - pa_core *c = (pa_core*) data; - pa_time_event *ev = (pa_time_event*) dbus_timeout_get_data(timeout); +static void toggle_timeout(DBusTimeout *timeout, void *data) { + pa_core *c = PA_CORE(data); + pa_time_event *ev; + + pa_assert(timeout); + pa_assert(c); + + pa_assert_se(ev = dbus_timeout_get_data(timeout)); if (dbus_timeout_get_enabled(timeout)) { + struct timeval tv; + pa_gettimeofday(&tv); pa_timeval_add(&tv, dbus_timeout_get_interval(timeout) * 1000); + c->mainloop->time_restart(ev, &tv); - } else { - /* disable the timeout */ + } else c->mainloop->time_restart(ev, NULL); - } } -static void -pa_dbus_connection_free(pa_dbus_connection *c) -{ - assert(c); - assert(!dbus_connection_get_is_connected(c->connection)); +static void wakeup_main(void *userdata) { + pa_dbus_connection *c = userdata; - /* already disconnected, just free */ - pa_property_remove(c->core, c->property_name); - c->core->mainloop->defer_free(c->dispatch_event); - dbus_connection_unref(c->connection); - pa_xfree(c); -} + pa_assert(c); -static void -wakeup_main(void *userdata) -{ - pa_dbus_connection *c = (pa_dbus_connection*) userdata; /* this will wakeup the mainloop and dispatch events, although * it may not be the cleanest way of accomplishing it */ c->core->mainloop->defer_enable(c->dispatch_event, 1); } -static pa_dbus_connection* pa_dbus_connection_new(pa_core* c, DBusConnection *conn, const char* name) -{ - pa_dbus_connection *pconn = pa_xnew(pa_dbus_connection, 1); +static pa_dbus_connection* pa_dbus_connection_new(pa_core* c, DBusConnection *conn, const char* name) { + pa_dbus_connection *pconn; - pconn->refcount = 1; + pconn = pa_xnew(pa_dbus_connection, 1); + PA_REFCNT_INIT(pconn); pconn->core = c; pconn->property_name = name; pconn->connection = conn; - pconn->dispatch_event = c->mainloop->defer_new(c->mainloop, dispatch_cb, - (void*) conn); + pconn->dispatch_event = c->mainloop->defer_new(c->mainloop, dispatch_cb, conn); pa_property_set(c, name, pconn); return pconn; } -DBusConnection* pa_dbus_connection_get(pa_dbus_connection *c) -{ - assert(c && c->connection); +DBusConnection* pa_dbus_connection_get(pa_dbus_connection *c){ + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) > 0); + pa_assert(c->connection); + return c->connection; } -void pa_dbus_connection_unref(pa_dbus_connection *c) -{ - assert(c); +void pa_dbus_connection_unref(pa_dbus_connection *c) { + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) > 0); - /* non-zero refcount, still outstanding refs */ - if (--(c->refcount)) + if (PA_REFCNT_DEC(c) > 0) return; - /* refcount is zero */ if (dbus_connection_get_is_connected(c->connection)) { - /* disconnect as we have no more internal references */ dbus_connection_close(c->connection); - /* must process remaining messages, bit of a kludge to - * handle both unload and shutdown */ - while(dbus_connection_read_write_dispatch(c->connection, -1)); + /* must process remaining messages, bit of a kludge to handle + * both unload and shutdown */ + while (dbus_connection_read_write_dispatch(c->connection, -1)); } - pa_dbus_connection_free(c); + + /* already disconnected, just free */ + pa_property_remove(c->core, c->property_name); + c->core->mainloop->defer_free(c->dispatch_event); + dbus_connection_unref(c->connection); + pa_xfree(c); } -pa_dbus_connection* pa_dbus_connection_ref(pa_dbus_connection *c) -{ - assert(c); +pa_dbus_connection* pa_dbus_connection_ref(pa_dbus_connection *c) { + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) > 0); - ++(c->refcount); + PA_REFCNT_INC(c); return c; } -pa_dbus_connection* pa_dbus_bus_get(pa_core *c, DBusBusType type, - DBusError *error) -{ - const char* name; +pa_dbus_connection* pa_dbus_bus_get(pa_core *c, DBusBusType type, DBusError *error) { + + static const char *const prop_name[] = { + [DBUS_BUS_SESSION] = "dbus-connection-session", + [DBUS_BUS_SYSTEM] = "dbus-connection-system", + [DBUS_BUS_STARTER] = "dbus-connection-starter" + }; DBusConnection *conn; pa_dbus_connection *pconn; - switch (type) { - case DBUS_BUS_SYSTEM: - name = "dbus-connection-system"; - break; - case DBUS_BUS_SESSION: - name = "dbus-connection-session"; - break; - case DBUS_BUS_STARTER: - name = "dbus-connection-starter"; - break; - default: - assert(0); /* never reached */ - break; - } + pa_assert(type == DBUS_BUS_SYSTEM || type == DBUS_BUS_SESSION || type == DBUS_BUS_STARTER); - if ((pconn = pa_property_get(c, name))) + if ((pconn = pa_property_get(c, prop_name[type]))) return pa_dbus_connection_ref(pconn); - /* else */ - conn = dbus_bus_get_private(type, error); - if (conn == NULL || dbus_error_is_set(error)) { + if (!(conn = dbus_bus_get_private(type, error))) return NULL; - } - pconn = pa_dbus_connection_new(c, conn, name); + pconn = pa_dbus_connection_new(c, conn, prop_name[type]); - /* don't exit on disconnect */ dbus_connection_set_exit_on_disconnect(conn, FALSE); - /* set up the DBUS call backs */ - dbus_connection_set_dispatch_status_function(conn, dispatch_status, - (void*) pconn, NULL); - dbus_connection_set_watch_functions(conn, - add_watch, - remove_watch, - toggle_watch, - (void*) c, NULL); - dbus_connection_set_timeout_functions(conn, - add_timeout, - remove_timeout, - toggle_timeout, - (void*) c, NULL); + dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL); + dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggle_watch, c, NULL); + dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, toggle_timeout, c, NULL); dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL); return pconn; diff --git a/src/modules/gconf/gconf-helper.c b/src/modules/gconf/gconf-helper.c index 3483b845..abd13287 100644 --- a/src/modules/gconf/gconf-helper.c +++ b/src/modules/gconf/gconf-helper.c @@ -32,6 +32,8 @@ #include #include +#include + #define PA_GCONF_ROOT "/system/pulseaudio" #define PA_GCONF_PATH_MODULES PA_GCONF_ROOT"/modules" @@ -40,13 +42,13 @@ static void handle_module(GConfClient *client, const char *name) { gboolean enabled, locked; int i; - snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/locked", name); + pa_snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/locked", name); locked = gconf_client_get_bool(client, p, FALSE); if (locked) return; - snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/enabled", name); + pa_snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/enabled", name); enabled = gconf_client_get_bool(client, p, FALSE); printf("%c%s%c", enabled ? '+' : '-', name, 0); @@ -56,11 +58,11 @@ static void handle_module(GConfClient *client, const char *name) { for (i = 0; i < 10; i++) { gchar *n, *a; - snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/name%i", name, i); + pa_snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/name%i", name, i); if (!(n = gconf_client_get_string(client, p, NULL)) || !*n) break; - snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/args%i", name, i); + pa_snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/args%i", name, i); a = gconf_client_get_string(client, p, NULL); printf("%s%c%s%c", n, 0, a ? a : "", 0); diff --git a/src/modules/gconf/module-gconf.c b/src/modules/gconf/module-gconf.c index cbe17d20..1c8866de 100644 --- a/src/modules/gconf/module-gconf.c +++ b/src/modules/gconf/module-gconf.c @@ -25,7 +25,6 @@ #include #endif -#include #include #include #include @@ -34,6 +33,7 @@ #include #include #include +#include #ifdef HAVE_SYS_PRCTL_H #include @@ -95,7 +95,7 @@ struct userdata { static int fill_buf(struct userdata *u) { ssize_t r; - assert(u); + pa_assert(u); if (u->buf_fill >= BUF_MAX) { pa_log("read buffer overflow"); @@ -111,21 +111,21 @@ static int fill_buf(struct userdata *u) { static int read_byte(struct userdata *u) { int ret; - assert(u); + pa_assert(u); if (u->buf_fill < 1) if (fill_buf(u) < 0) return -1; ret = u->buf[0]; - assert(u->buf_fill > 0); + pa_assert(u->buf_fill > 0); u->buf_fill--; memmove(u->buf, u->buf+1, u->buf_fill); return ret; } static char *read_string(struct userdata *u) { - assert(u); + pa_assert(u); for (;;) { char *e; @@ -143,9 +143,9 @@ static char *read_string(struct userdata *u) { } static void unload_one_module(struct userdata *u, struct module_info*m, unsigned i) { - assert(u); - assert(m); - assert(i < m->n_items); + pa_assert(u); + pa_assert(m); + pa_assert(i < m->n_items); if (m->items[i].index == PA_INVALID_INDEX) return; @@ -161,8 +161,8 @@ static void unload_one_module(struct userdata *u, struct module_info*m, unsigned static void unload_all_modules(struct userdata *u, struct module_info*m) { unsigned i; - assert(u); - assert(m); + pa_assert(u); + pa_assert(m); for (i = 0; i < m->n_items; i++) unload_one_module(u, m, i); @@ -180,10 +180,10 @@ static void load_module( pa_module *mod; - assert(u); - assert(m); - assert(name); - assert(args); + pa_assert(u); + pa_assert(m); + pa_assert(name); + pa_assert(args); if (!is_new) { if (m->items[i].index != PA_INVALID_INDEX && @@ -212,8 +212,8 @@ static void module_info_free(void *p, void *userdata) { struct module_info *m = p; struct userdata *u = userdata; - assert(m); - assert(u); + pa_assert(m); + pa_assert(u); unload_all_modules(u, m); pa_xfree(m->name); @@ -356,8 +356,10 @@ static int start_client(const char *n, pid_t *pid) { return pipe_fds[0]; } else { +#ifdef __linux__ + DIR* d; +#endif int max_fd, i; - /* child */ close(pipe_fds[0]); @@ -372,18 +374,48 @@ static int start_client(const char *n, pid_t *pid) { close(2); open("/dev/null", O_WRONLY); - max_fd = 1024; +#ifdef __linux__ + + if ((d = opendir("/proc/self/fd/"))) { + + struct dirent *de; + + while ((de = readdir(d))) { + char *e = NULL; + int fd; + + if (de->d_name[0] == '.') + continue; + + errno = 0; + fd = strtol(de->d_name, &e, 10); + pa_assert(errno == 0 && e && *e == 0); + + if (fd >= 3 && dirfd(d) != fd) + close(fd); + } + + closedir(d); + } else { + +#endif + + max_fd = 1024; #ifdef HAVE_SYS_RESOURCE_H - { - struct rlimit r; - if (getrlimit(RLIMIT_NOFILE, &r) == 0) - max_fd = r.rlim_max; - } + { + struct rlimit r; + if (getrlimit(RLIMIT_NOFILE, &r) == 0) + max_fd = r.rlim_max; + } #endif - for (i = 3; i < max_fd; i++) - close(i); + for (i = 3; i < max_fd; i++) + close(i); +# +#ifdef __linux__ + } +#endif #ifdef PR_SET_PDEATHSIG /* On Linux we can use PR_SET_PDEATHSIG to have the helper @@ -413,12 +445,12 @@ fail: return -1; } -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { struct userdata *u; int r; u = pa_xnew(struct userdata, 1); - u->core = c; + u->core = m->core; u->module = m; m->userdata = u; u->module_infos = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); @@ -431,8 +463,8 @@ int pa__init(pa_core *c, pa_module*m) { if ((u->fd = start_client(PA_GCONF_HELPER, &u->pid)) < 0) goto fail; - u->io_event = c->mainloop->io_new( - c->mainloop, + u->io_event = m->core->mainloop->io_new( + m->core->mainloop, u->fd, PA_IO_EVENT_INPUT, io_event_cb, @@ -449,21 +481,20 @@ int pa__init(pa_core *c, pa_module*m) { return 0; fail: - pa__done(c, m); + pa__done(m); return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata *u; - assert(c); - assert(m); + pa_assert(m); if (!(u = m->userdata)) return; if (u->io_event) - c->mainloop->io_free(u->io_event); + m->core->mainloop->io_free(u->io_event); if (u->fd >= 0) close(u->fd); diff --git a/src/modules/ladspa.h b/src/modules/ladspa.h new file mode 100644 index 00000000..b1a9c4e5 --- /dev/null +++ b/src/modules/ladspa.h @@ -0,0 +1,603 @@ +/* ladspa.h + + Linux Audio Developer's Simple Plugin API Version 1.1[LGPL]. + Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis, + Stefan Westerfeld. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. */ + +#ifndef LADSPA_INCLUDED +#define LADSPA_INCLUDED + +#define LADSPA_VERSION "1.1" +#define LADSPA_VERSION_MAJOR 1 +#define LADSPA_VERSION_MINOR 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*****************************************************************************/ + +/* Overview: + + There is a large number of synthesis packages in use or development + on the Linux platform at this time. This API (`The Linux Audio + Developer's Simple Plugin API') attempts to give programmers the + ability to write simple `plugin' audio processors in C/C++ and link + them dynamically (`plug') into a range of these packages (`hosts'). + It should be possible for any host and any plugin to communicate + completely through this interface. + + This API is deliberately short and simple. To achieve compatibility + with a range of promising Linux sound synthesis packages it + attempts to find the `greatest common divisor' in their logical + behaviour. Having said this, certain limiting decisions are + implicit, notably the use of a fixed type (LADSPA_Data) for all + data transfer and absence of a parameterised `initialisation' + phase. See below for the LADSPA_Data typedef. + + Plugins are expected to distinguish between control and audio + data. Plugins have `ports' that are inputs or outputs for audio or + control data and each plugin is `run' for a `block' corresponding + to a short time interval measured in samples. Audio data is + communicated using arrays of LADSPA_Data, allowing a block of audio + to be processed by the plugin in a single pass. Control data is + communicated using single LADSPA_Data values. Control data has a + single value at the start of a call to the `run()' or `run_adding()' + function, and may be considered to remain this value for its + duration. The plugin may assume that all its input and output ports + have been connected to the relevant data location (see the + `connect_port()' function below) before it is asked to run. + + Plugins will reside in shared object files suitable for dynamic + linking by dlopen() and family. The file will provide a number of + `plugin types' that can be used to instantiate actual plugins + (sometimes known as `plugin instances') that can be connected + together to perform tasks. + + This API contains very limited error-handling. */ + +/*****************************************************************************/ + +/* Fundamental data type passed in and out of plugin. This data type + is used to communicate audio samples and control values. It is + assumed that the plugin will work sensibly given any numeric input + value although it may have a preferred range (see hints below). + + For audio it is generally assumed that 1.0f is the `0dB' reference + amplitude and is a `normal' signal level. */ + +typedef float LADSPA_Data; + +/*****************************************************************************/ + +/* Special Plugin Properties: + + Optional features of the plugin type are encapsulated in the + LADSPA_Properties type. This is assembled by ORing individual + properties together. */ + +typedef int LADSPA_Properties; + +/* Property LADSPA_PROPERTY_REALTIME indicates that the plugin has a + real-time dependency (e.g. listens to a MIDI device) and so its + output must not be cached or subject to significant latency. */ +#define LADSPA_PROPERTY_REALTIME 0x1 + +/* Property LADSPA_PROPERTY_INPLACE_BROKEN indicates that the plugin + may cease to work correctly if the host elects to use the same data + location for both input and output (see connect_port()). This + should be avoided as enabling this flag makes it impossible for + hosts to use the plugin to process audio `in-place.' */ +#define LADSPA_PROPERTY_INPLACE_BROKEN 0x2 + +/* Property LADSPA_PROPERTY_HARD_RT_CAPABLE indicates that the plugin + is capable of running not only in a conventional host but also in a + `hard real-time' environment. To qualify for this the plugin must + satisfy all of the following: + + (1) The plugin must not use malloc(), free() or other heap memory + management within its run() or run_adding() functions. All new + memory used in run() must be managed via the stack. These + restrictions only apply to the run() function. + + (2) The plugin will not attempt to make use of any library + functions with the exceptions of functions in the ANSI standard C + and C maths libraries, which the host is expected to provide. + + (3) The plugin will not access files, devices, pipes, sockets, IPC + or any other mechanism that might result in process or thread + blocking. + + (4) The plugin will take an amount of time to execute a run() or + run_adding() call approximately of form (A+B*SampleCount) where A + and B depend on the machine and host in use. This amount of time + may not depend on input signals or plugin state. The host is left + the responsibility to perform timings to estimate upper bounds for + A and B. */ +#define LADSPA_PROPERTY_HARD_RT_CAPABLE 0x4 + +#define LADSPA_IS_REALTIME(x) ((x) & LADSPA_PROPERTY_REALTIME) +#define LADSPA_IS_INPLACE_BROKEN(x) ((x) & LADSPA_PROPERTY_INPLACE_BROKEN) +#define LADSPA_IS_HARD_RT_CAPABLE(x) ((x) & LADSPA_PROPERTY_HARD_RT_CAPABLE) + +/*****************************************************************************/ + +/* Plugin Ports: + + Plugins have `ports' that are inputs or outputs for audio or + data. Ports can communicate arrays of LADSPA_Data (for audio + inputs/outputs) or single LADSPA_Data values (for control + input/outputs). This information is encapsulated in the + LADSPA_PortDescriptor type which is assembled by ORing individual + properties together. + + Note that a port must be an input or an output port but not both + and that a port must be a control or audio port but not both. */ + +typedef int LADSPA_PortDescriptor; + +/* Property LADSPA_PORT_INPUT indicates that the port is an input. */ +#define LADSPA_PORT_INPUT 0x1 + +/* Property LADSPA_PORT_OUTPUT indicates that the port is an output. */ +#define LADSPA_PORT_OUTPUT 0x2 + +/* Property LADSPA_PORT_CONTROL indicates that the port is a control + port. */ +#define LADSPA_PORT_CONTROL 0x4 + +/* Property LADSPA_PORT_AUDIO indicates that the port is a audio + port. */ +#define LADSPA_PORT_AUDIO 0x8 + +#define LADSPA_IS_PORT_INPUT(x) ((x) & LADSPA_PORT_INPUT) +#define LADSPA_IS_PORT_OUTPUT(x) ((x) & LADSPA_PORT_OUTPUT) +#define LADSPA_IS_PORT_CONTROL(x) ((x) & LADSPA_PORT_CONTROL) +#define LADSPA_IS_PORT_AUDIO(x) ((x) & LADSPA_PORT_AUDIO) + +/*****************************************************************************/ + +/* Plugin Port Range Hints: + + The host may wish to provide a representation of data entering or + leaving a plugin (e.g. to generate a GUI automatically). To make + this more meaningful, the plugin should provide `hints' to the host + describing the usual values taken by the data. + + Note that these are only hints. The host may ignore them and the + plugin must not assume that data supplied to it is meaningful. If + the plugin receives invalid input data it is expected to continue + to run without failure and, where possible, produce a sensible + output (e.g. a high-pass filter given a negative cutoff frequency + might switch to an all-pass mode). + + Hints are meaningful for all input and output ports but hints for + input control ports are expected to be particularly useful. + + More hint information is encapsulated in the + LADSPA_PortRangeHintDescriptor type which is assembled by ORing + individual hint types together. Hints may require further + LowerBound and UpperBound information. + + All the hint information for a particular port is aggregated in the + LADSPA_PortRangeHint structure. */ + +typedef int LADSPA_PortRangeHintDescriptor; + +/* Hint LADSPA_HINT_BOUNDED_BELOW indicates that the LowerBound field + of the LADSPA_PortRangeHint should be considered meaningful. The + value in this field should be considered the (inclusive) lower + bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also + specified then the value of LowerBound should be multiplied by the + sample rate. */ +#define LADSPA_HINT_BOUNDED_BELOW 0x1 + +/* Hint LADSPA_HINT_BOUNDED_ABOVE indicates that the UpperBound field + of the LADSPA_PortRangeHint should be considered meaningful. The + value in this field should be considered the (inclusive) upper + bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also + specified then the value of UpperBound should be multiplied by the + sample rate. */ +#define LADSPA_HINT_BOUNDED_ABOVE 0x2 + +/* Hint LADSPA_HINT_TOGGLED indicates that the data item should be + considered a Boolean toggle. Data less than or equal to zero should + be considered `off' or `false,' and data above zero should be + considered `on' or `true.' LADSPA_HINT_TOGGLED may not be used in + conjunction with any other hint except LADSPA_HINT_DEFAULT_0 or + LADSPA_HINT_DEFAULT_1. */ +#define LADSPA_HINT_TOGGLED 0x4 + +/* Hint LADSPA_HINT_SAMPLE_RATE indicates that any bounds specified + should be interpreted as multiples of the sample rate. For + instance, a frequency range from 0Hz to the Nyquist frequency (half + the sample rate) could be requested by this hint in conjunction + with LowerBound = 0 and UpperBound = 0.5. Hosts that support bounds + at all must support this hint to retain meaning. */ +#define LADSPA_HINT_SAMPLE_RATE 0x8 + +/* Hint LADSPA_HINT_LOGARITHMIC indicates that it is likely that the + user will find it more intuitive to view values using a logarithmic + scale. This is particularly useful for frequencies and gains. */ +#define LADSPA_HINT_LOGARITHMIC 0x10 + +/* Hint LADSPA_HINT_INTEGER indicates that a user interface would + probably wish to provide a stepped control taking only integer + values. Any bounds set should be slightly wider than the actual + integer range required to avoid floating point rounding errors. For + instance, the integer set {0,1,2,3} might be described as [-0.1, + 3.1]. */ +#define LADSPA_HINT_INTEGER 0x20 + +/* The various LADSPA_HINT_HAS_DEFAULT_* hints indicate a `normal' + value for the port that is sensible as a default. For instance, + this value is suitable for use as an initial value in a user + interface or as a value the host might assign to a control port + when the user has not provided one. Defaults are encoded using a + mask so only one default may be specified for a port. Some of the + hints make use of lower and upper bounds, in which case the + relevant bound or bounds must be available and + LADSPA_HINT_SAMPLE_RATE must be applied as usual. The resulting + default must be rounded if LADSPA_HINT_INTEGER is present. Default + values were introduced in LADSPA v1.1. */ +#define LADSPA_HINT_DEFAULT_MASK 0x3C0 + +/* This default values indicates that no default is provided. */ +#define LADSPA_HINT_DEFAULT_NONE 0x0 + +/* This default hint indicates that the suggested lower bound for the + port should be used. */ +#define LADSPA_HINT_DEFAULT_MINIMUM 0x40 + +/* This default hint indicates that a low value between the suggested + lower and upper bounds should be chosen. For ports with + LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.75 + + log(upper) * 0.25). Otherwise, this should be (lower * 0.75 + upper + * 0.25). */ +#define LADSPA_HINT_DEFAULT_LOW 0x80 + +/* This default hint indicates that a middle value between the + suggested lower and upper bounds should be chosen. For ports with + LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.5 + + log(upper) * 0.5). Otherwise, this should be (lower * 0.5 + upper * + 0.5). */ +#define LADSPA_HINT_DEFAULT_MIDDLE 0xC0 + +/* This default hint indicates that a high value between the suggested + lower and upper bounds should be chosen. For ports with + LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.25 + + log(upper) * 0.75). Otherwise, this should be (lower * 0.25 + upper + * 0.75). */ +#define LADSPA_HINT_DEFAULT_HIGH 0x100 + +/* This default hint indicates that the suggested upper bound for the + port should be used. */ +#define LADSPA_HINT_DEFAULT_MAXIMUM 0x140 + +/* This default hint indicates that the number 0 should be used. Note + that this default may be used in conjunction with + LADSPA_HINT_TOGGLED. */ +#define LADSPA_HINT_DEFAULT_0 0x200 + +/* This default hint indicates that the number 1 should be used. Note + that this default may be used in conjunction with + LADSPA_HINT_TOGGLED. */ +#define LADSPA_HINT_DEFAULT_1 0x240 + +/* This default hint indicates that the number 100 should be used. */ +#define LADSPA_HINT_DEFAULT_100 0x280 + +/* This default hint indicates that the Hz frequency of `concert A' + should be used. This will be 440 unless the host uses an unusual + tuning convention, in which case it may be within a few Hz. */ +#define LADSPA_HINT_DEFAULT_440 0x2C0 + +#define LADSPA_IS_HINT_BOUNDED_BELOW(x) ((x) & LADSPA_HINT_BOUNDED_BELOW) +#define LADSPA_IS_HINT_BOUNDED_ABOVE(x) ((x) & LADSPA_HINT_BOUNDED_ABOVE) +#define LADSPA_IS_HINT_TOGGLED(x) ((x) & LADSPA_HINT_TOGGLED) +#define LADSPA_IS_HINT_SAMPLE_RATE(x) ((x) & LADSPA_HINT_SAMPLE_RATE) +#define LADSPA_IS_HINT_LOGARITHMIC(x) ((x) & LADSPA_HINT_LOGARITHMIC) +#define LADSPA_IS_HINT_INTEGER(x) ((x) & LADSPA_HINT_INTEGER) + +#define LADSPA_IS_HINT_HAS_DEFAULT(x) ((x) & LADSPA_HINT_DEFAULT_MASK) +#define LADSPA_IS_HINT_DEFAULT_MINIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_MINIMUM) +#define LADSPA_IS_HINT_DEFAULT_LOW(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_LOW) +#define LADSPA_IS_HINT_DEFAULT_MIDDLE(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_MIDDLE) +#define LADSPA_IS_HINT_DEFAULT_HIGH(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_HIGH) +#define LADSPA_IS_HINT_DEFAULT_MAXIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_MAXIMUM) +#define LADSPA_IS_HINT_DEFAULT_0(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_0) +#define LADSPA_IS_HINT_DEFAULT_1(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_1) +#define LADSPA_IS_HINT_DEFAULT_100(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_100) +#define LADSPA_IS_HINT_DEFAULT_440(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_440) + +typedef struct _LADSPA_PortRangeHint { + + /* Hints about the port. */ + LADSPA_PortRangeHintDescriptor HintDescriptor; + + /* Meaningful when hint LADSPA_HINT_BOUNDED_BELOW is active. When + LADSPA_HINT_SAMPLE_RATE is also active then this value should be + multiplied by the relevant sample rate. */ + LADSPA_Data LowerBound; + + /* Meaningful when hint LADSPA_HINT_BOUNDED_ABOVE is active. When + LADSPA_HINT_SAMPLE_RATE is also active then this value should be + multiplied by the relevant sample rate. */ + LADSPA_Data UpperBound; + +} LADSPA_PortRangeHint; + +/*****************************************************************************/ + +/* Plugin Handles: + + This plugin handle indicates a particular instance of the plugin + concerned. It is valid to compare this to NULL (0 for C++) but + otherwise the host should not attempt to interpret it. The plugin + may use it to reference internal instance data. */ + +typedef void * LADSPA_Handle; + +/*****************************************************************************/ + +/* Descriptor for a Type of Plugin: + + This structure is used to describe a plugin type. It provides a + number of functions to examine the type, instantiate it, link it to + buffers and workspaces and to run it. */ + +typedef struct _LADSPA_Descriptor { + + /* This numeric identifier indicates the plugin type + uniquely. Plugin programmers may reserve ranges of IDs from a + central body to avoid clashes. Hosts may assume that IDs are + below 0x1000000. */ + unsigned long UniqueID; + + /* This identifier can be used as a unique, case-sensitive + identifier for the plugin type within the plugin file. Plugin + types should be identified by file and label rather than by index + or plugin name, which may be changed in new plugin + versions. Labels must not contain white-space characters. */ + const char * Label; + + /* This indicates a number of properties of the plugin. */ + LADSPA_Properties Properties; + + /* This member points to the null-terminated name of the plugin + (e.g. "Sine Oscillator"). */ + const char * Name; + + /* This member points to the null-terminated string indicating the + maker of the plugin. This can be an empty string but not NULL. */ + const char * Maker; + + /* This member points to the null-terminated string indicating any + copyright applying to the plugin. If no Copyright applies the + string "None" should be used. */ + const char * Copyright; + + /* This indicates the number of ports (input AND output) present on + the plugin. */ + unsigned long PortCount; + + /* This member indicates an array of port descriptors. Valid indices + vary from 0 to PortCount-1. */ + const LADSPA_PortDescriptor * PortDescriptors; + + /* This member indicates an array of null-terminated strings + describing ports (e.g. "Frequency (Hz)"). Valid indices vary from + 0 to PortCount-1. */ + const char * const * PortNames; + + /* This member indicates an array of range hints for each port (see + above). Valid indices vary from 0 to PortCount-1. */ + const LADSPA_PortRangeHint * PortRangeHints; + + /* This may be used by the plugin developer to pass any custom + implementation data into an instantiate call. It must not be used + or interpreted by the host. It is expected that most plugin + writers will not use this facility as LADSPA_Handle should be + used to hold instance data. */ + void * ImplementationData; + + /* This member is a function pointer that instantiates a plugin. A + handle is returned indicating the new plugin instance. The + instantiation function accepts a sample rate as a parameter. The + plugin descriptor from which this instantiate function was found + must also be passed. This function must return NULL if + instantiation fails. + + Note that instance initialisation should generally occur in + activate() rather than here. */ + LADSPA_Handle (*instantiate)(const struct _LADSPA_Descriptor * Descriptor, + unsigned long SampleRate); + + /* This member is a function pointer that connects a port on an + instantiated plugin to a memory location at which a block of data + for the port will be read/written. The data location is expected + to be an array of LADSPA_Data for audio ports or a single + LADSPA_Data value for control ports. Memory issues will be + managed by the host. The plugin must read/write the data at these + locations every time run() or run_adding() is called and the data + present at the time of this connection call should not be + considered meaningful. + + connect_port() may be called more than once for a plugin instance + to allow the host to change the buffers that the plugin is + reading or writing. These calls may be made before or after + activate() or deactivate() calls. + + connect_port() must be called at least once for each port before + run() or run_adding() is called. When working with blocks of + LADSPA_Data the plugin should pay careful attention to the block + size passed to the run function as the block allocated may only + just be large enough to contain the block of samples. + + Plugin writers should be aware that the host may elect to use the + same buffer for more than one port and even use the same buffer + for both input and output (see LADSPA_PROPERTY_INPLACE_BROKEN). + However, overlapped buffers or use of a single buffer for both + audio and control data may result in unexpected behaviour. */ + void (*connect_port)(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation); + + /* This member is a function pointer that initialises a plugin + instance and activates it for use. This is separated from + instantiate() to aid real-time support and so that hosts can + reinitialise a plugin instance by calling deactivate() and then + activate(). In this case the plugin instance must reset all state + information dependent on the history of the plugin instance + except for any data locations provided by connect_port() and any + gain set by set_run_adding_gain(). If there is nothing for + activate() to do then the plugin writer may provide a NULL rather + than an empty function. + + When present, hosts must call this function once before run() (or + run_adding()) is called for the first time. This call should be + made as close to the run() call as possible and indicates to + real-time plugins that they are now live. Plugins should not rely + on a prompt call to run() after activate(). activate() may not be + called again unless deactivate() is called first. Note that + connect_port() may be called before or after a call to + activate(). */ + void (*activate)(LADSPA_Handle Instance); + + /* This method is a function pointer that runs an instance of a + plugin for a block. Two parameters are required: the first is a + handle to the particular instance to be run and the second + indicates the block size (in samples) for which the plugin + instance may run. + + Note that if an activate() function exists then it must be called + before run() or run_adding(). If deactivate() is called for a + plugin instance then the plugin instance may not be reused until + activate() has been called again. + + If the plugin has the property LADSPA_PROPERTY_HARD_RT_CAPABLE + then there are various things that the plugin should not do + within the run() or run_adding() functions (see above). */ + void (*run)(LADSPA_Handle Instance, + unsigned long SampleCount); + + /* This method is a function pointer that runs an instance of a + plugin for a block. This has identical behaviour to run() except + in the way data is output from the plugin. When run() is used, + values are written directly to the memory areas associated with + the output ports. However when run_adding() is called, values + must be added to the values already present in the memory + areas. Furthermore, output values written must be scaled by the + current gain set by set_run_adding_gain() (see below) before + addition. + + run_adding() is optional. When it is not provided by a plugin, + this function pointer must be set to NULL. When it is provided, + the function set_run_adding_gain() must be provided also. */ + void (*run_adding)(LADSPA_Handle Instance, + unsigned long SampleCount); + + /* This method is a function pointer that sets the output gain for + use when run_adding() is called (see above). If this function is + never called the gain is assumed to default to 1. Gain + information should be retained when activate() or deactivate() + are called. + + This function should be provided by the plugin if and only if the + run_adding() function is provided. When it is absent this + function pointer must be set to NULL. */ + void (*set_run_adding_gain)(LADSPA_Handle Instance, + LADSPA_Data Gain); + + /* This is the counterpart to activate() (see above). If there is + nothing for deactivate() to do then the plugin writer may provide + a NULL rather than an empty function. + + Hosts must deactivate all activated units after they have been + run() (or run_adding()) for the last time. This call should be + made as close to the last run() call as possible and indicates to + real-time plugins that they are no longer live. Plugins should + not rely on prompt deactivation. Note that connect_port() may be + called before or after a call to deactivate(). + + Deactivation is not similar to pausing as the plugin instance + will be reinitialised when activate() is called to reuse it. */ + void (*deactivate)(LADSPA_Handle Instance); + + /* Once an instance of a plugin has been finished with it can be + deleted using the following function. The instance handle passed + ceases to be valid after this call. + + If activate() was called for a plugin instance then a + corresponding call to deactivate() must be made before cleanup() + is called. */ + void (*cleanup)(LADSPA_Handle Instance); + +} LADSPA_Descriptor; + +/**********************************************************************/ + +/* Accessing a Plugin: */ + +/* The exact mechanism by which plugins are loaded is host-dependent, + however all most hosts will need to know is the name of shared + object file containing the plugin types. To allow multiple hosts to + share plugin types, hosts may wish to check for environment + variable LADSPA_PATH. If present, this should contain a + colon-separated path indicating directories that should be searched + (in order) when loading plugin types. + + A plugin programmer must include a function called + "ladspa_descriptor" with the following function prototype within + the shared object file. This function will have C-style linkage (if + you are using C++ this is taken care of by the `extern "C"' clause + at the top of the file). + + A host will find the plugin shared object file by one means or + another, find the ladspa_descriptor() function, call it, and + proceed from there. + + Plugin types are accessed by index (not ID) using values from 0 + upwards. Out of range indexes must result in this function + returning NULL, so the plugin count can be determined by checking + for the least index that results in NULL being returned. */ + +const LADSPA_Descriptor * ladspa_descriptor(unsigned long Index); + +/* Datatype corresponding to the ladspa_descriptor() function. */ +typedef const LADSPA_Descriptor * +(*LADSPA_Descriptor_Function)(unsigned long Index); + +/**********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* LADSPA_INCLUDED */ + +/* EOF */ diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 3d9f7577..a09247fe 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -26,18 +26,12 @@ #include #endif -#include #include -#ifdef HAVE_SYS_POLL_H -#include -#else -#include "poll.h" -#endif - #include #include +#include #include #include @@ -47,6 +41,11 @@ #include #include #include +#include +#include +#include +#include +#include #include "alsa-util.h" #include "module-alsa-sink-symdef.h" @@ -62,20 +61,38 @@ PA_MODULE_USAGE( "rate= " "fragments= " "fragment_size= " - "channel_map=") + "channel_map= " + "mmap=") + +#define DEFAULT_DEVICE "default" struct userdata { + pa_core *core; + pa_module *module; + pa_sink *sink; + + pa_thread *thread; + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; + snd_pcm_t *pcm_handle; + + pa_alsa_fdlist *mixer_fdl; snd_mixer_t *mixer_handle; snd_mixer_elem_t *mixer_elem; - pa_sink *sink; - struct pa_alsa_fdlist *pcm_fdl; - struct pa_alsa_fdlist *mixer_fdl; long hw_volume_max, hw_volume_min; - size_t frame_size, fragment_size; - pa_memchunk memchunk, silence; - pa_module *module; + size_t frame_size, fragment_size, hwbuf_size; + unsigned nfragments; + pa_memchunk memchunk; + + char *device_name; + + int use_mmap; + + int first; + + pa_rtpoll_item *alsa_rtpoll_item; }; static const char* const valid_modargs[] = { @@ -87,260 +104,440 @@ static const char* const valid_modargs[] = { "fragments", "fragment_size", "channel_map", + "mmap", NULL }; -#define DEFAULT_DEVICE "default" +static int mmap_write(struct userdata *u) { + int work_done = 0; -static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, u->sink ? pa_sink_used_by(u->sink) : 0); -} + pa_assert(u); + pa_sink_assert_ref(u->sink); -static void clear_up(struct userdata *u) { - assert(u); + for (;;) { + pa_memchunk chunk; + void *p; + snd_pcm_sframes_t n; + int err; + const snd_pcm_channel_area_t *areas; + snd_pcm_uframes_t offset, frames; + + if ((n = snd_pcm_avail_update(u->pcm_handle)) < 0) { + + if (n == -EPIPE) { + pa_log_debug("snd_pcm_avail_update: Buffer underrun!"); + u->first = 1; + } - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - u->sink = NULL; - } + if ((err = snd_pcm_recover(u->pcm_handle, n, 1)) == 0) + continue; - if (u->pcm_fdl) - pa_alsa_fdlist_free(u->pcm_fdl); - if (u->mixer_fdl) - pa_alsa_fdlist_free(u->mixer_fdl); + if (err == -EAGAIN) + return work_done; - u->pcm_fdl = u->mixer_fdl = NULL; + pa_log("snd_pcm_avail_update: %s", snd_strerror(err)); + return -1; + } - if (u->mixer_handle) { - snd_mixer_close(u->mixer_handle); - u->mixer_handle = NULL; - } +/* pa_log("Got request for %i samples", (int) n); */ - if (u->pcm_handle) { - snd_pcm_drop(u->pcm_handle); - snd_pcm_close(u->pcm_handle); - u->pcm_handle = NULL; - } -} + if (n <= 0) + return work_done; -static int xrun_recovery(struct userdata *u) { - int ret; - assert(u); + frames = n; - pa_log_info("*** ALSA-XRUN (playback) ***"); + if ((err = snd_pcm_mmap_begin(u->pcm_handle, &areas, &offset, &frames)) < 0) { - if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) { - pa_log("snd_pcm_prepare() failed: %s", snd_strerror(-ret)); + if (err == -EPIPE) { + pa_log_debug("snd_pcm_mmap_begin: Buffer underrun!"); + u->first = 1; + } - clear_up(u); - pa_module_unload_request(u->module); - return -1; - } + if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0) + continue; - return ret; -} + if (err == -EAGAIN) + return work_done; -static int suspend_recovery(struct userdata *u) { - int ret; - assert(u); + pa_log("Failed to write data to DSP: %s", snd_strerror(err)); + return -1; + } - pa_log_info("*** ALSA-SUSPEND (playback) ***"); + /* Check these are multiples of 8 bit */ + pa_assert((areas[0].first & 7) == 0); + pa_assert((areas[0].step & 7)== 0); - if ((ret = snd_pcm_resume(u->pcm_handle)) < 0) { - if (ret == -EAGAIN) - return -1; + /* We assume a single interleaved memory buffer */ + pa_assert((areas[0].first >> 3) == 0); + pa_assert((areas[0].step >> 3) == u->frame_size); - if (ret != -ENOSYS) - pa_log("snd_pcm_resume() failed: %s", snd_strerror(-ret)); - else { - if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) - pa_log("snd_pcm_prepare() failed: %s", snd_strerror(-ret)); - } + p = (uint8_t*) areas[0].addr + (offset * u->frame_size); + + chunk.memblock = pa_memblock_new_fixed(u->core->mempool, p, frames * u->frame_size, 1); + chunk.length = pa_memblock_get_length(chunk.memblock); + chunk.index = 0; + + pa_sink_render_into_full(u->sink, &chunk); + + /* FIXME: Maybe we can do something to keep this memory block + * a little bit longer around? */ + pa_memblock_unref_fixed(chunk.memblock); + + if ((err = snd_pcm_mmap_commit(u->pcm_handle, offset, frames)) < 0) { + + if (err == -EPIPE) { + pa_log_debug("snd_pcm_mmap_commit: Buffer underrun!"); + u->first = 1; + } + + if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0) + continue; - if (ret < 0) { - clear_up(u); - pa_module_unload_request(u->module); + if (err == -EAGAIN) + return work_done; + + pa_log("Failed to write data to DSP: %s", snd_strerror(err)); return -1; } - } - return ret; + work_done = 1; + + if (frames >= (snd_pcm_uframes_t) n) + return work_done; + +/* pa_log("wrote %i samples", (int) frames); */ + } } -static void do_write(struct userdata *u) { - assert(u); +static int unix_write(struct userdata *u) { + snd_pcm_status_t *status; + int work_done = 0; - update_usage(u); + snd_pcm_status_alloca(&status); + + pa_assert(u); + pa_sink_assert_ref(u->sink); for (;;) { - pa_memchunk *memchunk = NULL; - snd_pcm_sframes_t frames; - - if (u->memchunk.memblock) - memchunk = &u->memchunk; - else { - if (pa_sink_render(u->sink, u->fragment_size, &u->memchunk) < 0) - memchunk = &u->silence; - else - memchunk = &u->memchunk; + void *p; + snd_pcm_sframes_t t; + ssize_t l; + int err; + + if ((err = snd_pcm_status(u->pcm_handle, status)) < 0) { + pa_log("Failed to query DSP status data: %s", snd_strerror(err)); + return -1; } - assert(memchunk->memblock); - assert(memchunk->memblock->data); - assert(memchunk->length); - assert(memchunk->memblock->length); - assert((memchunk->length % u->frame_size) == 0); + if (snd_pcm_status_get_avail_max(status)*u->frame_size >= u->hwbuf_size) + pa_log_debug("Buffer underrun!"); - if ((frames = snd_pcm_writei(u->pcm_handle, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length / u->frame_size)) < 0) { - if (frames == -EAGAIN) - return; + l = snd_pcm_status_get_avail(status) * u->frame_size; - if (frames == -EPIPE) { - if (xrun_recovery(u) < 0) - return; +/* pa_log("%u bytes to write", l); */ - continue; - } + if (l <= 0) + return work_done; + + if (u->memchunk.length <= 0) + pa_sink_render(u->sink, l, &u->memchunk); + + pa_assert(u->memchunk.length > 0); - if (frames == -ESTRPIPE) { - if (suspend_recovery(u) < 0) - return; + p = pa_memblock_acquire(u->memchunk.memblock); + t = snd_pcm_writei(u->pcm_handle, (const uint8_t*) p + u->memchunk.index, u->memchunk.length / u->frame_size); + pa_memblock_release(u->memchunk.memblock); +/* pa_log("wrote %i bytes of %u (%u)", t*u->frame_size, u->memchunk.length, l); */ + + pa_assert(t != 0); + + if (t < 0) { + + if ((t = snd_pcm_recover(u->pcm_handle, t, 1)) == 0) continue; + + if (t == -EAGAIN) { + pa_log_debug("EAGAIN"); + return work_done; + } else { + pa_log("Failed to write data to DSP: %s", snd_strerror(t)); + return -1; } + } - pa_log("snd_pcm_writei() failed: %s", snd_strerror(-frames)); + u->memchunk.index += t * u->frame_size; + u->memchunk.length -= t * u->frame_size; - clear_up(u); - pa_module_unload_request(u->module); - return; + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + pa_memchunk_reset(&u->memchunk); } - if (memchunk == &u->memchunk) { - size_t l = frames * u->frame_size; - memchunk->index += l; - memchunk->length -= l; + work_done = 1; - if (memchunk->length == 0) { - pa_memblock_unref(memchunk->memblock); - memchunk->memblock = NULL; - memchunk->index = memchunk->length = 0; - } - } + if (t * u->frame_size >= (unsigned) l) + return work_done; + } +} - break; +static pa_usec_t sink_get_latency(struct userdata *u) { + pa_usec_t r = 0; + snd_pcm_status_t *status; + snd_pcm_sframes_t frames = 0; + int err; + + snd_pcm_status_alloca(&status); + + pa_assert(u); + pa_assert(u->pcm_handle); + + if ((err = snd_pcm_status(u->pcm_handle, status)) < 0) + pa_log("Failed to get delay: %s", snd_strerror(err)); + else + frames = snd_pcm_status_get_delay(status); + + if (frames > 0) + r = pa_bytes_to_usec(frames * u->frame_size, &u->sink->sample_spec); + + if (u->memchunk.memblock) + r += pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec); + + return r; +} + +static int build_pollfd(struct userdata *u) { + int err; + struct pollfd *pollfd; + int n; + + pa_assert(u); + pa_assert(u->pcm_handle); + + if ((n = snd_pcm_poll_descriptors_count(u->pcm_handle)) < 0) { + pa_log("snd_pcm_poll_descriptors_count() failed: %s", snd_strerror(n)); + return -1; + } + + if (u->alsa_rtpoll_item) + pa_rtpoll_item_free(u->alsa_rtpoll_item); + + u->alsa_rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, n); + pollfd = pa_rtpoll_item_get_pollfd(u->alsa_rtpoll_item, NULL); + + if ((err = snd_pcm_poll_descriptors(u->pcm_handle, pollfd, n)) < 0) { + pa_log("snd_pcm_poll_descriptors() failed: %s", snd_strerror(err)); + return -1; } + + return 0; } -static void fdl_callback(void *userdata) { - struct userdata *u = userdata; - assert(u); +static int suspend(struct userdata *u) { + pa_assert(u); + pa_assert(u->pcm_handle); - if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) - if (xrun_recovery(u) < 0) - return; + /* Let's suspend */ + snd_pcm_drain(u->pcm_handle); + snd_pcm_close(u->pcm_handle); + u->pcm_handle = NULL; - if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_SUSPENDED) - if (suspend_recovery(u) < 0) - return; + if (u->alsa_rtpoll_item) { + pa_rtpoll_item_free(u->alsa_rtpoll_item); + u->alsa_rtpoll_item = NULL; + } + + pa_log_info("Device suspended..."); - do_write(u); + return 0; } -static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { - struct userdata *u = snd_mixer_elem_get_callback_private(elem); +static int unsuspend(struct userdata *u) { + pa_sample_spec ss; + int err, b; + unsigned nfrags; + snd_pcm_uframes_t period_size; - assert(u && u->mixer_handle); + pa_assert(u); + pa_assert(!u->pcm_handle); - if (mask == SND_CTL_EVENT_MASK_REMOVE) - return 0; + pa_log_info("Trying resume..."); - if (mask & SND_CTL_EVENT_MASK_VALUE) { - if (u->sink->get_hw_volume) - u->sink->get_hw_volume(u->sink); - if (u->sink->get_hw_mute) - u->sink->get_hw_mute(u->sink); - pa_subscription_post(u->sink->core, - PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, - u->sink->index); + snd_config_update_free_global(); + if ((err = snd_pcm_open(&u->pcm_handle, u->device_name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { + pa_log("Error opening PCM device %s: %s", u->device_name, snd_strerror(err)); + goto fail; + } + + ss = u->sink->sample_spec; + nfrags = u->nfragments; + period_size = u->fragment_size / u->frame_size; + b = u->use_mmap; + + if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b)) < 0) { + pa_log("Failed to set hardware parameters: %s", snd_strerror(err)); + goto fail; + } + + if (b != u->use_mmap) { + pa_log_warn("Resume failed, couldn't get original access mode."); + goto fail; + } + + if (!pa_sample_spec_equal(&ss, &u->sink->sample_spec)) { + pa_log_warn("Resume failed, couldn't restore original sample settings."); + goto fail; + } + + if (nfrags != u->nfragments || period_size*u->frame_size != u->fragment_size) { + pa_log_warn("Resume failed, couldn't restore original fragment settings."); + goto fail; + } + + if ((err = pa_alsa_set_sw_params(u->pcm_handle)) < 0) { + pa_log("Failed to set software parameters: %s", snd_strerror(err)); + goto fail; } + if (build_pollfd(u) < 0) + goto fail; + + /* FIXME: We need to reload the volume somehow */ + + u->first = 1; + + pa_log_info("Resumed successfully..."); + return 0; + +fail: + if (u->pcm_handle) { + snd_pcm_close(u->pcm_handle); + u->pcm_handle = NULL; + } + + return -1; } -static pa_usec_t sink_get_latency_cb(pa_sink *s) { - pa_usec_t r = 0; - struct userdata *u = s->userdata; - snd_pcm_sframes_t frames; - int err; +static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SINK(o)->userdata; - assert(s && u && u->sink); + switch (code) { - if ((err = snd_pcm_delay(u->pcm_handle, &frames)) < 0) { - pa_log("failed to get delay: %s", snd_strerror(err)); - s->get_latency = NULL; - return 0; + case PA_SINK_MESSAGE_GET_LATENCY: { + pa_usec_t r = 0; + + if (u->pcm_handle) + r = sink_get_latency(u); + + *((pa_usec_t*) data) = r; + + return 0; + } + + case PA_SINK_MESSAGE_SET_STATE: + + switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) { + + case PA_SINK_SUSPENDED: + pa_assert(PA_SINK_OPENED(u->sink->thread_info.state)); + + if (suspend(u) < 0) + return -1; + + break; + + case PA_SINK_IDLE: + case PA_SINK_RUNNING: + + if (u->sink->thread_info.state == PA_SINK_INIT) { + if (build_pollfd(u) < 0) + return -1; + } + + if (u->sink->thread_info.state == PA_SINK_SUSPENDED) { + if (unsuspend(u) < 0) + return -1; + } + + break; + + case PA_SINK_UNLINKED: + case PA_SINK_INIT: + ; + } + + break; } - if (frames < 0) - frames = 0; + return pa_sink_process_msg(o, code, data, offset, chunk); +} - r += pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec); +static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { + struct userdata *u = snd_mixer_elem_get_callback_private(elem); - if (u->memchunk.memblock) - r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec); + pa_assert(u); + pa_assert(u->mixer_handle); - return r; + if (mask == SND_CTL_EVENT_MASK_REMOVE) + return 0; + + if (mask & SND_CTL_EVENT_MASK_VALUE) { + pa_sink_get_volume(u->sink); + pa_sink_get_mute(u->sink); + } + + return 0; } -static int sink_get_hw_volume_cb(pa_sink *s) { +static int sink_get_volume_cb(pa_sink *s) { struct userdata *u = s->userdata; int err; int i; - assert(u); - assert(u->mixer_elem); + pa_assert(u); + pa_assert(u->mixer_elem); - for (i = 0; i < s->hw_volume.channels; i++) { + for (i = 0; i < s->sample_spec.channels; i++) { long set_vol, vol; - assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, i)); + pa_assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, i)); if ((err = snd_mixer_selem_get_playback_volume(u->mixer_elem, i, &vol)) < 0) goto fail; - set_vol = (long) roundf(((float) s->hw_volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; + set_vol = (long) roundf(((float) s->volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; /* Try to avoid superfluous volume changes */ if (set_vol != vol) - s->hw_volume.values[i] = (pa_volume_t) roundf(((float) (vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min)); + s->volume.values[i] = (pa_volume_t) roundf(((float) (vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min)); } return 0; fail: pa_log_error("Unable to read volume: %s", snd_strerror(err)); - s->get_hw_volume = NULL; - s->set_hw_volume = NULL; + + s->get_volume = NULL; + s->set_volume = NULL; return -1; } -static int sink_set_hw_volume_cb(pa_sink *s) { +static int sink_set_volume_cb(pa_sink *s) { struct userdata *u = s->userdata; int err; int i; - pa_volume_t vol; - assert(u); - assert(u->mixer_elem); + pa_assert(u); + pa_assert(u->mixer_elem); - for (i = 0; i < s->hw_volume.channels; i++) { + for (i = 0; i < s->sample_spec.channels; i++) { long alsa_vol; + pa_volume_t vol; - assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, i)); + pa_assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, i)); - vol = s->hw_volume.values[i]; + vol = s->volume.values[i]; if (vol > PA_VOLUME_NORM) vol = PA_VOLUME_NORM; @@ -355,55 +552,166 @@ static int sink_set_hw_volume_cb(pa_sink *s) { fail: pa_log_error("Unable to set volume: %s", snd_strerror(err)); - s->get_hw_volume = NULL; - s->set_hw_volume = NULL; + + s->get_volume = NULL; + s->set_volume = NULL; return -1; } -static int sink_get_hw_mute_cb(pa_sink *s) { +static int sink_get_mute_cb(pa_sink *s) { struct userdata *u = s->userdata; int err, sw; - assert(u && u->mixer_elem); + pa_assert(u); + pa_assert(u->mixer_elem); - err = snd_mixer_selem_get_playback_switch(u->mixer_elem, 0, &sw); - if (err) { + if ((err = snd_mixer_selem_get_playback_switch(u->mixer_elem, 0, &sw)) < 0) { pa_log_error("Unable to get switch: %s", snd_strerror(err)); - s->get_hw_mute = NULL; - s->set_hw_mute = NULL; + + s->get_mute = NULL; + s->set_mute = NULL; return -1; } - s->hw_muted = !sw; + s->muted = !sw; return 0; } -static int sink_set_hw_mute_cb(pa_sink *s) { +static int sink_set_mute_cb(pa_sink *s) { struct userdata *u = s->userdata; int err; - assert(u && u->mixer_elem); + pa_assert(u); + pa_assert(u->mixer_elem); - err = snd_mixer_selem_set_playback_switch_all(u->mixer_elem, !s->hw_muted); - if (err) { + if ((err = snd_mixer_selem_set_playback_switch_all(u->mixer_elem, !s->muted)) < 0) { pa_log_error("Unable to set switch: %s", snd_strerror(err)); - s->get_hw_mute = NULL; - s->set_hw_mute = NULL; + + s->get_mute = NULL; + s->set_mute = NULL; return -1; } return 0; } -int pa__init(pa_core *c, pa_module*m) { +static void thread_func(void *userdata) { + struct userdata *u = userdata; + + pa_assert(u); + + pa_log_debug("Thread starting up"); + + if (u->core->high_priority) + pa_make_realtime(); + + pa_thread_mq_install(&u->thread_mq); + pa_rtpoll_install(u->rtpoll); + + for (;;) { + int ret; + + /* Render some data and write it to the dsp */ + if (PA_SINK_OPENED(u->sink->thread_info.state)) { + int work_done = 0; + + if (u->use_mmap) { + if ((work_done = mmap_write(u)) < 0) + goto fail; + } else { + if ((work_done = unix_write(u)) < 0) + goto fail; + } + + if (work_done && u->first) { + pa_log_info("Starting playback."); + snd_pcm_start(u->pcm_handle); + u->first = 0; + continue; + } + } + + /* Hmm, nothing to do. Let's sleep */ + if ((ret = pa_rtpoll_run(u->rtpoll, 1)) < 0) + goto fail; + + if (ret == 0) + goto finish; + + /* Tell ALSA about this and process its response */ + if (PA_SINK_OPENED(u->sink->thread_info.state)) { + struct pollfd *pollfd; + unsigned short revents = 0; + int err; + unsigned n; + + pollfd = pa_rtpoll_item_get_pollfd(u->alsa_rtpoll_item, &n); + + if ((err = snd_pcm_poll_descriptors_revents(u->pcm_handle, pollfd, n, &revents)) < 0) { + pa_log("snd_pcm_poll_descriptors_revents() failed: %s", snd_strerror(err)); + goto fail; + } + + if (revents & (POLLERR|POLLNVAL|POLLHUP)) { + + if (revents & POLLERR) + pa_log_warn("Got POLLERR from ALSA"); + if (revents & POLLNVAL) + pa_log_warn("Got POLLNVAL from ALSA"); + if (revents & POLLHUP) + pa_log_warn("Got POLLHUP from ALSA"); + + /* Try to recover from this error */ + + switch (snd_pcm_state(u->pcm_handle)) { + + case SND_PCM_STATE_XRUN: + if ((err = snd_pcm_recover(u->pcm_handle, -EPIPE, 1)) != 0) { + pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN: %s", snd_strerror(err)); + goto fail; + } + break; + + case SND_PCM_STATE_SUSPENDED: + if ((err = snd_pcm_recover(u->pcm_handle, -ESTRPIPE, 1)) != 0) { + pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED: %s", snd_strerror(err)); + goto fail; + } + break; + + default: + + snd_pcm_drop(u->pcm_handle); + + if ((err = snd_pcm_prepare(u->pcm_handle)) < 0) { + pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare(): %s", snd_strerror(err)); + goto fail; + } + break; + } + } + } + } + +fail: + /* If this was no regular exit from the loop we have to continue + * processing messages until we received PA_MESSAGE_SHUTDOWN */ + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); + +finish: + pa_log_debug("Thread shutting down"); +} + +int pa__init(pa_module*m) { + pa_modargs *ma = NULL; - int ret = -1; struct userdata *u = NULL; - const char *dev; + char *dev; pa_sample_spec ss; pa_channel_map map; - uint32_t periods, fragsize; + uint32_t nfrags, frag_size; snd_pcm_uframes_t period_size; size_t frame_size; snd_pcm_info_t *pcm_info = NULL; @@ -412,48 +720,107 @@ int pa__init(pa_core *c, pa_module*m) { const char *name; char *name_buf = NULL; int namereg_fail; + int use_mmap = 1, b; + + snd_pcm_info_alloca(&pcm_info); + + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log("failed to parse module arguments"); + pa_log("Failed to parse module arguments"); goto fail; } - ss = c->default_sample_spec; + ss = m->core->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) { - pa_log("failed to parse sample specification and channel map"); + pa_log("Failed to parse sample specification and channel map"); goto fail; } frame_size = pa_frame_size(&ss); - /* Fix latency to 100ms */ - periods = 8; - fragsize = pa_bytes_per_second(&ss)/128; + nfrags = m->core->default_n_fragments; + frag_size = pa_usec_to_bytes(m->core->default_fragment_size_msec*1000, &ss); + if (frag_size <= 0) + frag_size = frame_size; + + if (pa_modargs_get_value_u32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &frag_size) < 0) { + pa_log("Failed to parse buffer metrics"); + goto fail; + } + period_size = frag_size/frame_size; - if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { - pa_log("failed to parse buffer metrics"); + if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) { + pa_log("Failed to parse mmap argument."); goto fail; } - period_size = fragsize/frame_size; u = pa_xnew0(struct userdata, 1); - m->userdata = u; + u->core = m->core; u->module = m; + m->userdata = u; + u->use_mmap = use_mmap; + u->first = 1; + pa_thread_mq_init(&u->thread_mq, m->core->mainloop); + u->rtpoll = pa_rtpoll_new(); + u->alsa_rtpoll_item = NULL; + pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq); snd_config_update_free_global(); - if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { - pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err)); - goto fail; + + dev = pa_xstrdup(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE)); + + for (;;) { + + if ((err = snd_pcm_open(&u->pcm_handle, dev, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { + pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err)); + pa_xfree(dev); + goto fail; + } + + b = use_mmap; + if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b)) < 0) { + + if (err == -EPERM) { + /* Hmm, some hw is very exotic, so we retry with plughw, if hw didn't work */ + + if (pa_startswith(dev, "hw:")) { + char *d = pa_sprintf_malloc("plughw:%s", dev+3); + pa_log_debug("Opening the device as '%s' didn't work, retrying with '%s'.", dev, d); + pa_xfree(dev); + dev = d; + + snd_pcm_close(u->pcm_handle); + u->pcm_handle = NULL; + continue; + } + } + + pa_log("Failed to set hardware parameters: %s", snd_strerror(err)); + pa_xfree(dev); + goto fail; + } + + break; } - if ((err = snd_pcm_info_malloc(&pcm_info)) < 0 || - (err = snd_pcm_info(u->pcm_handle, pcm_info)) < 0) { + u->device_name = dev; + + if (use_mmap && !b) { + pa_log_info("Device doesn't support mmap(), falling back to UNIX read/write mode."); + u->use_mmap = use_mmap = b; + } + + if (u->use_mmap) + pa_log_info("Successfully enabled mmap() mode."); + + if ((err = snd_pcm_info(u->pcm_handle, pcm_info)) < 0) { pa_log("Error fetching PCM info: %s", snd_strerror(err)); goto fail; } - if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) { - pa_log("Failed to set hardware parameters: %s", snd_strerror(err)); + if ((err = pa_alsa_set_sw_params(u->pcm_handle)) < 0) { + pa_log("Failed to set software parameters: %s", snd_strerror(err)); goto fail; } @@ -464,15 +831,16 @@ int pa__init(pa_core *c, pa_module*m) { /* Seems ALSA didn't like the channel number, so let's fix the channel map */ pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); - if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) { - pa_log("Error opening mixer: %s", snd_strerror(err)); - goto fail; - } + if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) + pa_log_warn("Error opening mixer: %s", snd_strerror(err)); + else { - if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) || - !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "PCM", "Master"))) { - snd_mixer_close(u->mixer_handle); - u->mixer_handle = NULL; + if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) || + !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Master", "PCM"))) { + + snd_mixer_close(u->mixer_handle); + u->mixer_handle = NULL; + } } if ((name = pa_modargs_get_value(ma, "sink_name", NULL))) @@ -482,114 +850,146 @@ int pa__init(pa_core *c, pa_module*m) { namereg_fail = 0; } - if (!(u->sink = pa_sink_new(c, __FILE__, name, namereg_fail, &ss, &map))) { + u->sink = pa_sink_new(m->core, __FILE__, name, namereg_fail, &ss, &map); + pa_xfree(name_buf); + + if (!u->sink) { pa_log("Failed to create sink object"); goto fail; } - u->sink->is_hardware = 1; - u->sink->get_latency = sink_get_latency_cb; + u->sink->parent.process_msg = sink_process_msg; + u->sink->userdata = u; + + pa_sink_set_module(u->sink, m); + pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); + pa_sink_set_rtpoll(u->sink, u->rtpoll); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc( + "ALSA PCM on %s (%s)%s", + dev, + snd_pcm_info_get_name(pcm_info), + use_mmap ? " via DMA" : "")); + pa_xfree(t); + + u->sink->flags = PA_SINK_HARDWARE|PA_SINK_HW_VOLUME_CTRL|PA_SINK_LATENCY; + + u->frame_size = frame_size; + u->fragment_size = frag_size = period_size * frame_size; + u->nfragments = nfrags; + u->hwbuf_size = u->fragment_size * nfrags; + + pa_log_info("Using %u fragments of size %lu bytes.", nfrags, (long unsigned) u->fragment_size); + + pa_memchunk_reset(&u->memchunk); + if (u->mixer_handle) { - assert(u->mixer_elem); + /* Initialize mixer code */ + + pa_assert(u->mixer_elem); + if (snd_mixer_selem_has_playback_volume(u->mixer_elem)) { int i; - for (i = 0;i < ss.channels;i++) { + for (i = 0; i < ss.channels; i++) if (!snd_mixer_selem_has_playback_channel(u->mixer_elem, i)) break; - } if (i == ss.channels) { - u->sink->get_hw_volume = sink_get_hw_volume_cb; - u->sink->set_hw_volume = sink_set_hw_volume_cb; - snd_mixer_selem_get_playback_volume_range( - u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max); - } + pa_log_debug("ALSA device has separate volumes controls for all %u channels.", ss.channels); + u->sink->get_volume = sink_get_volume_cb; + u->sink->set_volume = sink_set_volume_cb; + snd_mixer_selem_get_playback_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max); + } else + pa_log_info("ALSA device lacks separate volumes controls for all %u channels (%u available), falling back to software volume control.", ss.channels, i+1); } + if (snd_mixer_selem_has_playback_switch(u->mixer_elem)) { - u->sink->get_hw_mute = sink_get_hw_mute_cb; - u->sink->set_hw_mute = sink_set_hw_mute_cb; + u->sink->get_mute = sink_get_mute_cb; + u->sink->set_mute = sink_set_mute_cb; } - } - u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - pa_sink_set_description(u->sink, t = pa_sprintf_malloc("ALSA PCM on %s (%s)", dev, snd_pcm_info_get_name(pcm_info))); - pa_xfree(t); - - u->pcm_fdl = pa_alsa_fdlist_new(); - assert(u->pcm_fdl); - if (pa_alsa_fdlist_init_pcm(u->pcm_fdl, u->pcm_handle, c->mainloop, fdl_callback, u) < 0) { - pa_log("failed to initialise file descriptor monitoring"); - goto fail; - } - if (u->mixer_handle) { u->mixer_fdl = pa_alsa_fdlist_new(); - assert(u->mixer_fdl); - if (pa_alsa_fdlist_init_mixer(u->mixer_fdl, u->mixer_handle, c->mainloop) < 0) { + + if (pa_alsa_fdlist_set_mixer(u->mixer_fdl, u->mixer_handle, m->core->mainloop) < 0) { pa_log("failed to initialise file descriptor monitoring"); goto fail; } + snd_mixer_elem_set_callback(u->mixer_elem, mixer_callback); snd_mixer_elem_set_callback_private(u->mixer_elem, u); } else u->mixer_fdl = NULL; - u->frame_size = frame_size; - u->fragment_size = period_size * frame_size; - - pa_log_info("using %u fragments of size %lu bytes.", periods, (long unsigned)u->fragment_size); - - u->silence.memblock = pa_memblock_new(c->mempool, u->silence.length = u->fragment_size); - assert(u->silence.memblock); - pa_silence_memblock(u->silence.memblock, &ss); - u->silence.index = 0; - - u->memchunk.memblock = NULL; - u->memchunk.index = u->memchunk.length = 0; - - ret = 0; + if (!(u->thread = pa_thread_new(thread_func, u))) { + pa_log("Failed to create thread."); + goto fail; + } /* Get initial mixer settings */ - if (u->sink->get_hw_volume) - u->sink->get_hw_volume(u->sink); - if (u->sink->get_hw_mute) - u->sink->get_hw_mute(u->sink); + if (u->sink->get_volume) + u->sink->get_volume(u->sink); + if (u->sink->get_mute) + u->sink->get_mute(u->sink); -finish: - - pa_xfree(name_buf); + pa_sink_put(u->sink); - if (ma) - pa_modargs_free(ma); + pa_modargs_free(ma); - if (pcm_info) - snd_pcm_info_free(pcm_info); - - return ret; + return 0; fail: - if (u) - pa__done(c, m); + if (ma) + pa_modargs_free(ma); - goto finish; + pa__done(m); + + return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata *u; - assert(c && m); + + pa_assert(m); if (!(u = m->userdata)) return; - clear_up(u); + if (u->sink) + pa_sink_unlink(u->sink); + + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); + } + + pa_thread_mq_done(&u->thread_mq); + + if (u->sink) + pa_sink_unref(u->sink); if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); - if (u->silence.memblock) - pa_memblock_unref(u->silence.memblock); + if (u->alsa_rtpoll_item) + pa_rtpoll_item_free(u->alsa_rtpoll_item); + + if (u->rtpoll) + pa_rtpoll_free(u->rtpoll); + + if (u->mixer_fdl) + pa_alsa_fdlist_free(u->mixer_fdl); + + if (u->mixer_handle) + snd_mixer_close(u->mixer_handle); + + if (u->pcm_handle) { + snd_pcm_drop(u->pcm_handle); + snd_pcm_close(u->pcm_handle); + } + + pa_xfree(u->device_name); pa_xfree(u); -} + snd_config_update_free_global(); +} diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 4061d668..d840cac3 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -26,18 +26,12 @@ #include #endif -#include #include -#ifdef HAVE_SYS_POLL_H -#include -#else -#include "poll.h" -#endif - #include #include +#include #include #include @@ -48,6 +42,11 @@ #include #include #include +#include +#include +#include +#include +#include #include "alsa-util.h" #include "module-alsa-source-symdef.h" @@ -63,20 +62,35 @@ PA_MODULE_USAGE( "rate= " "fragments= " "fragment_size= " - "channel_map=") + "channel_map= " + "mmap=") + +#define DEFAULT_DEVICE "default" struct userdata { + pa_core *core; + pa_module *module; + pa_source *source; + + pa_thread *thread; + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; + snd_pcm_t *pcm_handle; + + pa_alsa_fdlist *mixer_fdl; snd_mixer_t *mixer_handle; snd_mixer_elem_t *mixer_elem; - pa_source *source; - struct pa_alsa_fdlist *pcm_fdl; - struct pa_alsa_fdlist *mixer_fdl; long hw_volume_max, hw_volume_min; - size_t frame_size, fragment_size; - pa_memchunk memchunk; - pa_module *module; + size_t frame_size, fragment_size, hwbuf_size; + unsigned nfragments; + + char *device_name; + + int use_mmap; + + pa_rtpoll_item *alsa_rtpoll_item; }; static const char* const valid_modargs[] = { @@ -88,257 +102,438 @@ static const char* const valid_modargs[] = { "fragments", "fragment_size", "channel_map", + "mmap", NULL }; -#define DEFAULT_DEVICE "default" +static int mmap_read(struct userdata *u) { + int work_done = 0; -static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, u->source ? pa_source_used_by(u->source) : 0); -} + pa_assert(u); + pa_source_assert_ref(u->source); -static void clear_up(struct userdata *u) { - assert(u); + for (;;) { + snd_pcm_sframes_t n; + int err; + const snd_pcm_channel_area_t *areas; + snd_pcm_uframes_t offset, frames; + pa_memchunk chunk; + void *p; - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - u->source = NULL; - } + if ((n = snd_pcm_avail_update(u->pcm_handle)) < 0) { - if (u->pcm_fdl) - pa_alsa_fdlist_free(u->pcm_fdl); - if (u->mixer_fdl) - pa_alsa_fdlist_free(u->mixer_fdl); + if (n == -EPIPE) + pa_log_debug("snd_pcm_avail_update: Buffer underrun!"); - u->pcm_fdl = u->mixer_fdl = NULL; + if ((err = snd_pcm_recover(u->pcm_handle, n, 1)) == 0) + continue; - if (u->mixer_handle) { - snd_mixer_close(u->mixer_handle); - u->mixer_handle = NULL; - } + if (err == -EAGAIN) + return work_done; - if (u->pcm_handle) { - snd_pcm_drop(u->pcm_handle); - snd_pcm_close(u->pcm_handle); - u->pcm_handle = NULL; - } -} + pa_log("snd_pcm_avail_update: %s", snd_strerror(err)); + return -1; + } -static int xrun_recovery(struct userdata *u) { - int ret; - assert(u); +/* pa_log("Got request for %i samples", (int) n); */ - pa_log_info("*** ALSA-XRUN (capture) ***"); + if (n <= 0) + return work_done; - if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) { - pa_log("snd_pcm_prepare() failed: %s", snd_strerror(-ret)); + frames = n; - clear_up(u); - pa_module_unload_request(u->module); + if ((err = snd_pcm_mmap_begin(u->pcm_handle, &areas, &offset, &frames)) < 0) { - return -1; - } + if (err == -EPIPE) + pa_log_debug("snd_pcm_mmap_begin: Buffer underrun!"); - return 0; -} + if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0) + continue; + if (err == -EAGAIN) + return work_done; -static int suspend_recovery(struct userdata *u) { - int ret; - assert(u); + pa_log("Failed to write data to DSP: %s", snd_strerror(err)); + return -1; + } - pa_log_info("*** ALSA-SUSPEND (capture) ***"); + /* Check these are multiples of 8 bit */ + pa_assert((areas[0].first & 7) == 0); + pa_assert((areas[0].step & 7)== 0); - if ((ret = snd_pcm_resume(u->pcm_handle)) < 0) { - if (ret == -EAGAIN) - return -1; + /* We assume a single interleaved memory buffer */ + pa_assert((areas[0].first >> 3) == 0); + pa_assert((areas[0].step >> 3) == u->frame_size); - if (ret != -ENOSYS) - pa_log("snd_pcm_resume() failed: %s", snd_strerror(-ret)); - else { - if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) - pa_log("snd_pcm_prepare() failed: %s", snd_strerror(-ret)); - } + p = (uint8_t*) areas[0].addr + (offset * u->frame_size); + + chunk.memblock = pa_memblock_new_fixed(u->core->mempool, p, frames * u->frame_size, 1); + chunk.length = pa_memblock_get_length(chunk.memblock); + chunk.index = 0; + + pa_source_post(u->source, &chunk); + + /* FIXME: Maybe we can do something to keep this memory block + * a little bit longer around? */ + pa_memblock_unref_fixed(chunk.memblock); + + if ((err = snd_pcm_mmap_commit(u->pcm_handle, offset, frames)) < 0) { + + if (err == -EPIPE) + pa_log_debug("snd_pcm_mmap_commit: Buffer underrun!"); - if (ret < 0) { - clear_up(u); - pa_module_unload_request(u->module); + if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0) + continue; + + if (err == -EAGAIN) + return work_done; + + pa_log("Failed to write data to DSP: %s", snd_strerror(err)); return -1; } - } - return ret; + work_done = 1; + +/* pa_log("wrote %i samples", (int) frames); */ + } } -static void do_read(struct userdata *u) { - assert(u); +static int unix_read(struct userdata *u) { + snd_pcm_status_t *status; + int work_done = 0; - update_usage(u); + snd_pcm_status_alloca(&status); - for (;;) { - pa_memchunk post_memchunk; - snd_pcm_sframes_t frames; - size_t l; + pa_assert(u); + pa_source_assert_ref(u->source); - if (!u->memchunk.memblock) { - u->memchunk.memblock = pa_memblock_new(u->source->core->mempool, u->memchunk.length = u->fragment_size); - u->memchunk.index = 0; + for (;;) { + void *p; + snd_pcm_sframes_t t, k; + ssize_t l; + int err; + pa_memchunk chunk; + + if ((err = snd_pcm_status(u->pcm_handle, status)) < 0) { + pa_log("Failed to query DSP status data: %s", snd_strerror(err)); + return -1; } - assert(u->memchunk.memblock); - assert(u->memchunk.length); - assert(u->memchunk.memblock->data); - assert(u->memchunk.memblock->length); - assert(u->memchunk.length % u->frame_size == 0); + if (snd_pcm_status_get_avail_max(status)*u->frame_size >= u->hwbuf_size) + pa_log_debug("Buffer overrun!"); - if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { - if (frames == -EAGAIN) - return; + l = snd_pcm_status_get_avail(status) * u->frame_size; - if (frames == -EPIPE) { - if (xrun_recovery(u) < 0) - return; + if (l <= 0) + return work_done; - continue; - } + chunk.memblock = pa_memblock_new(u->core->mempool, (size_t) -1); + + k = pa_memblock_get_length(chunk.memblock); + + if (k > l) + k = l; + + k = (k/u->frame_size)*u->frame_size; - if (frames == -ESTRPIPE) { - if (suspend_recovery(u) < 0) - return; + p = pa_memblock_acquire(chunk.memblock); + t = snd_pcm_readi(u->pcm_handle, (uint8_t*) p, k / u->frame_size); + pa_memblock_release(chunk.memblock); +/* pa_log("wrote %i bytes of %u (%u)", t*u->frame_size, u->memchunk.length, l); */ + + pa_assert(t != 0); + + if (t < 0) { + pa_memblock_unref(chunk.memblock); + + if ((t = snd_pcm_recover(u->pcm_handle, t, 1)) == 0) continue; + + if (t == -EAGAIN) { + pa_log_debug("EAGAIN"); + return work_done; + } else { + pa_log("Failed to read data from DSP: %s", snd_strerror(t)); + return -1; } + } - pa_log("snd_pcm_readi() failed: %s", snd_strerror(-frames)); + chunk.index = 0; + chunk.length = t * u->frame_size; - clear_up(u); - pa_module_unload_request(u->module); - return; - } + pa_source_post(u->source, &chunk); + pa_memblock_unref(chunk.memblock); - l = frames * u->frame_size; + work_done = 1; - post_memchunk = u->memchunk; - post_memchunk.length = l; + if (t * u->frame_size >= (unsigned) l) + return work_done; + } +} - pa_source_post(u->source, &post_memchunk); +static pa_usec_t source_get_latency(struct userdata *u) { + pa_usec_t r = 0; + snd_pcm_status_t *status; + snd_pcm_sframes_t frames = 0; + int err; - u->memchunk.index += l; - u->memchunk.length -= l; + snd_pcm_status_alloca(&status); - if (u->memchunk.length == 0) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - u->memchunk.index = u->memchunk.length = 0; - } + pa_assert(u); + pa_assert(u->pcm_handle); - break; + if ((err = snd_pcm_status(u->pcm_handle, status)) < 0) + pa_log("Failed to get delay: %s", snd_strerror(err)); + else + frames = snd_pcm_status_get_delay(status); + + if (frames > 0) + r = pa_bytes_to_usec(frames * u->frame_size, &u->source->sample_spec); + + return r; +} + +static int build_pollfd(struct userdata *u) { + int err; + struct pollfd *pollfd; + int n; + + pa_assert(u); + pa_assert(u->pcm_handle); + + if ((n = snd_pcm_poll_descriptors_count(u->pcm_handle)) < 0) { + pa_log("snd_pcm_poll_descriptors_count() failed: %s", snd_strerror(n)); + return -1; } + + if (u->alsa_rtpoll_item) + pa_rtpoll_item_free(u->alsa_rtpoll_item); + + u->alsa_rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, n); + pollfd = pa_rtpoll_item_get_pollfd(u->alsa_rtpoll_item, NULL); + + if ((err = snd_pcm_poll_descriptors(u->pcm_handle, pollfd, n)) < 0) { + pa_log("snd_pcm_poll_descriptors() failed: %s", snd_strerror(err)); + return -1; + } + + return 0; } -static void fdl_callback(void *userdata) { - struct userdata *u = userdata; - assert(u); +static int suspend(struct userdata *u) { + pa_assert(u); + pa_assert(u->pcm_handle); - if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) - if (xrun_recovery(u) < 0) - return; + /* Let's suspend */ + snd_pcm_close(u->pcm_handle); + u->pcm_handle = NULL; - if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_SUSPENDED) - if (suspend_recovery(u) < 0) - return; + if (u->alsa_rtpoll_item) { + pa_rtpoll_item_free(u->alsa_rtpoll_item); + u->alsa_rtpoll_item = NULL; + } - do_read(u); + pa_log_info("Device suspended..."); + + return 0; } -static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { - struct userdata *u = snd_mixer_elem_get_callback_private(elem); +static int unsuspend(struct userdata *u) { + pa_sample_spec ss; + int err, b; + unsigned nfrags; + snd_pcm_uframes_t period_size; - assert(u && u->mixer_handle); + pa_assert(u); + pa_assert(!u->pcm_handle); - if (mask == SND_CTL_EVENT_MASK_REMOVE) - return 0; + pa_log_info("Trying resume..."); - if (mask & SND_CTL_EVENT_MASK_VALUE) { - if (u->source->get_hw_volume) - u->source->get_hw_volume(u->source); - if (u->source->get_hw_mute) - u->source->get_hw_mute(u->source); + snd_config_update_free_global(); + if ((err = snd_pcm_open(&u->pcm_handle, u->device_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { + pa_log("Error opening PCM device %s: %s", u->device_name, snd_strerror(err)); + goto fail; + } - pa_subscription_post(u->source->core, - PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, - u->source->index); + ss = u->source->sample_spec; + nfrags = u->nfragments; + period_size = u->fragment_size / u->frame_size; + b = u->use_mmap; + + if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b)) < 0) { + pa_log("Failed to set hardware parameters: %s", snd_strerror(err)); + goto fail; } + if (b != u->use_mmap) { + pa_log_warn("Resume failed, couldn't get original access mode."); + goto fail; + } + + if (!pa_sample_spec_equal(&ss, &u->source->sample_spec)) { + pa_log_warn("Resume failed, couldn't restore original sample settings."); + goto fail; + } + + if (nfrags != u->nfragments || period_size*u->frame_size != u->fragment_size) { + pa_log_warn("Resume failed, couldn't restore original fragment settings."); + goto fail; + } + + if ((err = pa_alsa_set_sw_params(u->pcm_handle)) < 0) { + pa_log("Failed to set software parameters: %s", snd_strerror(err)); + goto fail; + } + + if (build_pollfd(u) < 0) + goto fail; + + snd_pcm_start(u->pcm_handle); + + /* FIXME: We need to reload the volume somehow */ + + pa_log_info("Resumed successfully..."); + return 0; + +fail: + if (u->pcm_handle) { + snd_pcm_close(u->pcm_handle); + u->pcm_handle = NULL; + } + + return -1; } -static pa_usec_t source_get_latency_cb(pa_source *s) { - struct userdata *u = s->userdata; - snd_pcm_sframes_t frames; - assert(s && u && u->source); +static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SOURCE(o)->userdata; + + switch (code) { + + case PA_SOURCE_MESSAGE_GET_LATENCY: { + pa_usec_t r = 0; + + if (u->pcm_handle) + r = source_get_latency(u); + + *((pa_usec_t*) data) = r; + + return 0; + } + + case PA_SOURCE_MESSAGE_SET_STATE: + + switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) { + + case PA_SOURCE_SUSPENDED: + pa_assert(PA_SOURCE_OPENED(u->source->thread_info.state)); + + if (suspend(u) < 0) + return -1; + + break; + + case PA_SOURCE_IDLE: + case PA_SOURCE_RUNNING: + + if (u->source->thread_info.state == PA_SOURCE_INIT) { + if (build_pollfd(u) < 0) + return -1; + + snd_pcm_start(u->pcm_handle); + } + + if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) { + if (unsuspend(u) < 0) + return -1; + } + + break; - if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { - pa_log("failed to get delay"); - s->get_latency = NULL; + case PA_SOURCE_UNLINKED: + case PA_SOURCE_INIT: + ; + } + + break; + } + + return pa_source_process_msg(o, code, data, offset, chunk); +} + +static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { + struct userdata *u = snd_mixer_elem_get_callback_private(elem); + + pa_assert(u); + pa_assert(u->mixer_handle); + + if (mask == SND_CTL_EVENT_MASK_REMOVE) return 0; + + if (mask & SND_CTL_EVENT_MASK_VALUE) { + pa_source_get_volume(u->source); + pa_source_get_mute(u->source); } - return pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec); + return 0; } -static int source_get_hw_volume_cb(pa_source *s) { +static int source_get_volume_cb(pa_source *s) { struct userdata *u = s->userdata; - long vol; int err; int i; - assert(u && u->mixer_elem); + pa_assert(u); + pa_assert(u->mixer_elem); - for (i = 0;i < s->hw_volume.channels;i++) { - long set_vol; + for (i = 0; i < s->sample_spec.channels; i++) { + long set_vol, vol; - assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); + pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, i, &vol)) < 0) goto fail; - set_vol = (long) roundf(((float) s->hw_volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; + set_vol = (long) roundf(((float) s->volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; /* Try to avoid superfluous volume changes */ if (set_vol != vol) - s->hw_volume.values[i] = (pa_volume_t) roundf(((float) (vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min)); + s->volume.values[i] = (pa_volume_t) roundf(((float) (vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min)); } return 0; fail: pa_log_error("Unable to read volume: %s", snd_strerror(err)); - s->get_hw_volume = NULL; - s->set_hw_volume = NULL; + + s->get_volume = NULL; + s->set_volume = NULL; return -1; } -static int source_set_hw_volume_cb(pa_source *s) { +static int source_set_volume_cb(pa_source *s) { struct userdata *u = s->userdata; int err; - pa_volume_t vol; int i; - assert(u && u->mixer_elem); + pa_assert(u); + pa_assert(u->mixer_elem); - for (i = 0;i < s->hw_volume.channels;i++) { - assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); + for (i = 0; i < s->sample_spec.channels; i++) { + long alsa_vol; + pa_volume_t vol; - vol = s->hw_volume.values[i]; + pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); + + vol = s->volume.values[i]; if (vol > PA_VOLUME_NORM) vol = PA_VOLUME_NORM; - vol = (long) roundf(((float) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; + alsa_vol = (long) roundf(((float) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; - if ((err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, vol)) < 0) + if ((err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, alsa_vol)) < 0) goto fail; } @@ -346,55 +541,159 @@ static int source_set_hw_volume_cb(pa_source *s) { fail: pa_log_error("Unable to set volume: %s", snd_strerror(err)); - s->get_hw_volume = NULL; - s->set_hw_volume = NULL; + + s->get_volume = NULL; + s->set_volume = NULL; return -1; } -static int source_get_hw_mute_cb(pa_source *s) { +static int source_get_mute_cb(pa_source *s) { struct userdata *u = s->userdata; int err, sw; - assert(u && u->mixer_elem); + pa_assert(u); + pa_assert(u->mixer_elem); - err = snd_mixer_selem_get_capture_switch(u->mixer_elem, 0, &sw); - if (err) { + if ((err = snd_mixer_selem_get_capture_switch(u->mixer_elem, 0, &sw)) < 0) { pa_log_error("Unable to get switch: %s", snd_strerror(err)); - s->get_hw_mute = NULL; - s->set_hw_mute = NULL; + + s->get_mute = NULL; + s->set_mute = NULL; return -1; } - s->hw_muted = !sw; + s->muted = !sw; return 0; } -static int source_set_hw_mute_cb(pa_source *s) { +static int source_set_mute_cb(pa_source *s) { struct userdata *u = s->userdata; int err; - assert(u && u->mixer_elem); + pa_assert(u); + pa_assert(u->mixer_elem); - err = snd_mixer_selem_set_capture_switch_all(u->mixer_elem, !s->hw_muted); - if (err) { + if ((err = snd_mixer_selem_set_capture_switch_all(u->mixer_elem, !s->muted)) < 0) { pa_log_error("Unable to set switch: %s", snd_strerror(err)); - s->get_hw_mute = NULL; - s->set_hw_mute = NULL; + + s->get_mute = NULL; + s->set_mute = NULL; return -1; } return 0; } -int pa__init(pa_core *c, pa_module*m) { +static void thread_func(void *userdata) { + struct userdata *u = userdata; + + pa_assert(u); + + pa_log_debug("Thread starting up"); + + if (u->core->high_priority) + pa_make_realtime(); + + pa_thread_mq_install(&u->thread_mq); + pa_rtpoll_install(u->rtpoll); + + for (;;) { + int ret; + + /* Read some data and pass it to the sources */ + if (PA_SOURCE_OPENED(u->source->thread_info.state)) { + + if (u->use_mmap) { + if (mmap_read(u) < 0) + goto fail; + + } else { + if (unix_read(u) < 0) + goto fail; + } + } + + /* Hmm, nothing to do. Let's sleep */ + if ((ret = pa_rtpoll_run(u->rtpoll, 1)) < 0) + goto fail; + + if (ret == 0) + goto finish; + + /* Tell ALSA about this and process its response */ + if (PA_SOURCE_OPENED(u->source->thread_info.state)) { + struct pollfd *pollfd; + unsigned short revents = 0; + int err; + unsigned n; + + pollfd = pa_rtpoll_item_get_pollfd(u->alsa_rtpoll_item, &n); + + if ((err = snd_pcm_poll_descriptors_revents(u->pcm_handle, pollfd, n, &revents)) < 0) { + pa_log("snd_pcm_poll_descriptors_revents() failed: %s", snd_strerror(err)); + goto fail; + } + + if (revents & (POLLERR|POLLNVAL|POLLHUP)) { + + if (revents & POLLERR) + pa_log_warn("Got POLLERR from ALSA"); + if (revents & POLLNVAL) + pa_log_warn("Got POLLNVAL from ALSA"); + if (revents & POLLHUP) + pa_log_warn("Got POLLHUP from ALSA"); + + /* Try to recover from this error */ + + switch (snd_pcm_state(u->pcm_handle)) { + + case SND_PCM_STATE_XRUN: + if ((err = snd_pcm_recover(u->pcm_handle, -EPIPE, 1)) != 0) { + pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN: %s", snd_strerror(err)); + goto fail; + } + break; + + case SND_PCM_STATE_SUSPENDED: + if ((err = snd_pcm_recover(u->pcm_handle, -ESTRPIPE, 1)) != 0) { + pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED: %s", snd_strerror(err)); + goto fail; + } + break; + + default: + + snd_pcm_drop(u->pcm_handle); + + if ((err = snd_pcm_prepare(u->pcm_handle)) < 0) { + pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare(): %s", snd_strerror(err)); + goto fail; + } + break; + } + } + } + } + +fail: + /* If this was no regular exit from the loop we have to continue + * processing messages until we received PA_MESSAGE_SHUTDOWN */ + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); + +finish: + pa_log_debug("Thread shutting down"); +} + +int pa__init(pa_module*m) { + pa_modargs *ma = NULL; - int ret = -1; struct userdata *u = NULL; - const char *dev; + char *dev; pa_sample_spec ss; pa_channel_map map; - unsigned periods, fragsize; + unsigned nfrags, frag_size; snd_pcm_uframes_t period_size; size_t frame_size; snd_pcm_info_t *pcm_info = NULL; @@ -403,64 +702,125 @@ int pa__init(pa_core *c, pa_module*m) { const char *name; char *name_buf = NULL; int namereg_fail; + int use_mmap = 1, b; + + snd_pcm_info_alloca(&pcm_info); + + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log("failed to parse module arguments"); + pa_log("Failed to parse module arguments"); goto fail; } - ss = c->default_sample_spec; + ss = m->core->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) { - pa_log("failed to parse sample specification"); + pa_log("Failed to parse sample specification"); goto fail; } frame_size = pa_frame_size(&ss); - /* Fix latency to 100ms */ - periods = 12; - fragsize = pa_bytes_per_second(&ss)/128; + nfrags = m->core->default_n_fragments; + frag_size = pa_usec_to_bytes(m->core->default_fragment_size_msec*1000, &ss); + if (frag_size <= 0) + frag_size = frame_size; + + if (pa_modargs_get_value_u32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &frag_size) < 0) { + pa_log("Failed to parse buffer metrics"); + goto fail; + } + period_size = frag_size/frame_size; - if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { - pa_log("failed to parse buffer metrics"); + if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) { + pa_log("Failed to parse mmap argument."); goto fail; } - period_size = fragsize/frame_size; u = pa_xnew0(struct userdata, 1); - m->userdata = u; + u->core = m->core; u->module = m; + m->userdata = u; + u->use_mmap = use_mmap; + pa_thread_mq_init(&u->thread_mq, m->core->mainloop); + u->rtpoll = pa_rtpoll_new(); + u->alsa_rtpoll_item = NULL; + pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq); snd_config_update_free_global(); - if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { - pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err)); - goto fail; + + dev = pa_xstrdup(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE)); + + for (;;) { + + if ((err = snd_pcm_open(&u->pcm_handle, dev, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { + pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err)); + pa_xfree(dev); + goto fail; + } + + b = use_mmap; + if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b)) < 0) { + + if (err == -EPERM) { + /* Hmm, some hw is very exotic, so we retry with plughw, if hw didn't work */ + + if (pa_startswith(dev, "hw:")) { + char *d = pa_sprintf_malloc("plughw:%s", dev+3); + pa_log_debug("Opening the device as '%s' didn't work, retrying with '%s'.", dev, d); + pa_xfree(dev); + dev = d; + + snd_pcm_close(u->pcm_handle); + u->pcm_handle = NULL; + continue; + } + } + + pa_log("Failed to set hardware parameters: %s", snd_strerror(err)); + pa_xfree(dev); + goto fail; + } + + break; } - if ((err = snd_pcm_info_malloc(&pcm_info)) < 0 || - (err = snd_pcm_info(u->pcm_handle, pcm_info)) < 0) { + u->device_name = dev; + + if (use_mmap && !b) { + pa_log_info("Device doesn't support mmap(), falling back to UNIX read/write mode."); + u->use_mmap = use_mmap = b; + } + + if (u->use_mmap) + pa_log_info("Successfully enabled mmap() mode."); + + if ((err = snd_pcm_info(u->pcm_handle, pcm_info)) < 0) { pa_log("Error fetching PCM info: %s", snd_strerror(err)); goto fail; } - if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) { - pa_log("Failed to set hardware parameters: %s", snd_strerror(err)); + if ((err = pa_alsa_set_sw_params(u->pcm_handle)) < 0) { + pa_log("Failed to set software parameters: %s", snd_strerror(err)); goto fail; } + /* ALSA might tweak the sample spec, so recalculate the frame size */ + frame_size = pa_frame_size(&ss); + if (ss.channels != map.channels) /* Seems ALSA didn't like the channel number, so let's fix the channel map */ pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); - if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) { + if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) pa_log("Error opening mixer: %s", snd_strerror(err)); - goto fail; - } + else { - if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) || - !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", "Mic"))) { - snd_mixer_close(u->mixer_handle); - u->mixer_handle = NULL; + if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) || + !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", NULL))) { + snd_mixer_close(u->mixer_handle); + u->mixer_handle = NULL; + } } if ((name = pa_modargs_get_value(ma, "source_name", NULL))) @@ -470,16 +830,39 @@ int pa__init(pa_core *c, pa_module*m) { namereg_fail = 0; } - if (!(u->source = pa_source_new(c, __FILE__, name, namereg_fail, &ss, &map))) { + u->source = pa_source_new(m->core, __FILE__, name, namereg_fail, &ss, &map); + pa_xfree(name_buf); + + if (!u->source) { pa_log("Failed to create source object"); goto fail; } - u->source->is_hardware = 1; + u->source->parent.process_msg = source_process_msg; u->source->userdata = u; - u->source->get_latency = source_get_latency_cb; + + pa_source_set_module(u->source, m); + pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); + pa_source_set_rtpoll(u->source, u->rtpoll); + pa_source_set_description(u->source, t = pa_sprintf_malloc( + "ALSA PCM on %s (%s)%s", + dev, + snd_pcm_info_get_name(pcm_info), + use_mmap ? " via DMA" : "")); + pa_xfree(t); + + u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL; + + u->frame_size = frame_size; + u->fragment_size = frag_size = period_size * frame_size; + u->nfragments = nfrags; + u->hwbuf_size = u->fragment_size * nfrags; + + pa_log_info("Using %u fragments of size %lu bytes.", nfrags, (long unsigned) u->fragment_size); + if (u->mixer_handle) { - assert(u->mixer_elem); + pa_assert(u->mixer_elem); + if (snd_mixer_selem_has_capture_volume(u->mixer_elem)) { int i; @@ -489,89 +872,95 @@ int pa__init(pa_core *c, pa_module*m) { } if (i == ss.channels) { - u->source->get_hw_volume = source_get_hw_volume_cb; - u->source->set_hw_volume = source_set_hw_volume_cb; - snd_mixer_selem_get_capture_volume_range( - u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max); + u->source->get_volume = source_get_volume_cb; + u->source->set_volume = source_set_volume_cb; + snd_mixer_selem_get_capture_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max); } } + if (snd_mixer_selem_has_capture_switch(u->mixer_elem)) { - u->source->get_hw_mute = source_get_hw_mute_cb; - u->source->set_hw_mute = source_set_hw_mute_cb; + u->source->get_mute = source_get_mute_cb; + u->source->set_mute = source_set_mute_cb; } - } - pa_source_set_owner(u->source, m); - pa_source_set_description(u->source, t = pa_sprintf_malloc("ALSA PCM on %s (%s)", dev, snd_pcm_info_get_name(pcm_info))); - pa_xfree(t); - u->pcm_fdl = pa_alsa_fdlist_new(); - assert(u->pcm_fdl); - if (pa_alsa_fdlist_init_pcm(u->pcm_fdl, u->pcm_handle, c->mainloop, fdl_callback, u) < 0) { - pa_log("failed to initialise file descriptor monitoring"); - goto fail; - } - - if (u->mixer_handle) { u->mixer_fdl = pa_alsa_fdlist_new(); - assert(u->mixer_fdl); - if (pa_alsa_fdlist_init_mixer(u->mixer_fdl, u->mixer_handle, c->mainloop) < 0) { + + if (pa_alsa_fdlist_set_mixer(u->mixer_fdl, u->mixer_handle, m->core->mainloop) < 0) { pa_log("failed to initialise file descriptor monitoring"); goto fail; } + snd_mixer_elem_set_callback(u->mixer_elem, mixer_callback); snd_mixer_elem_set_callback_private(u->mixer_elem, u); } else u->mixer_fdl = NULL; - u->frame_size = frame_size; - u->fragment_size = period_size * frame_size; - - pa_log_info("using %u fragments of size %lu bytes.", periods, (long unsigned) u->fragment_size); - - u->memchunk.memblock = NULL; - u->memchunk.index = u->memchunk.length = 0; - - snd_pcm_start(u->pcm_handle); - - ret = 0; - + if (!(u->thread = pa_thread_new(thread_func, u))) { + pa_log("Failed to create thread."); + goto fail; + } /* Get initial mixer settings */ - if (u->source->get_hw_volume) - u->source->get_hw_volume(u->source); - if (u->source->get_hw_mute) - u->source->get_hw_mute(u->source); + if (u->source->get_volume) + u->source->get_volume(u->source); + if (u->source->get_mute) + u->source->get_mute(u->source); -finish: - pa_xfree(name_buf); - - if (ma) - pa_modargs_free(ma); + pa_source_put(u->source); - if (pcm_info) - snd_pcm_info_free(pcm_info); + pa_modargs_free(ma); - return ret; + return 0; fail: - if (u) - pa__done(c, m); + if (ma) + pa_modargs_free(ma); - goto finish; + pa__done(m); + + return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata *u; - assert(c && m); + + pa_assert(m); if (!(u = m->userdata)) return; - clear_up(u); + if (u->source) + pa_source_unlink(u->source); - if (u->memchunk.memblock) - pa_memblock_unref(u->memchunk.memblock); + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); + } + pa_thread_mq_done(&u->thread_mq); + + if (u->source) + pa_source_unref(u->source); + + if (u->alsa_rtpoll_item) + pa_rtpoll_item_free(u->alsa_rtpoll_item); + + if (u->rtpoll) + pa_rtpoll_free(u->rtpoll); + + if (u->mixer_fdl) + pa_alsa_fdlist_free(u->mixer_fdl); + + if (u->mixer_handle) + snd_mixer_close(u->mixer_handle); + + if (u->pcm_handle) { + snd_pcm_drop(u->pcm_handle); + snd_pcm_close(u->pcm_handle); + } + + pa_xfree(u->device_name); pa_xfree(u); -} + snd_config_update_free_global(); +} diff --git a/src/modules/module-cli.c b/src/modules/module-cli.c index 19ac0c26..84125214 100644 --- a/src/modules/module-cli.c +++ b/src/modules/module-cli.c @@ -26,7 +26,6 @@ #endif #include -#include #include #include @@ -35,6 +34,7 @@ #include #include #include +#include #include "module-cli-symdef.h" @@ -51,8 +51,8 @@ static const char* const valid_modargs[] = { static void eof_and_unload_cb(pa_cli*c, void *userdata) { pa_module *m = userdata; - assert(c); - assert(m); + pa_assert(c); + pa_assert(m); pa_module_unload_request(m); } @@ -60,21 +60,20 @@ static void eof_and_unload_cb(pa_cli*c, void *userdata) { static void eof_and_exit_cb(pa_cli*c, void *userdata) { pa_module *m = userdata; - assert(c); - assert(m); + pa_assert(c); + pa_assert(m); m->core->mainloop->quit(m->core->mainloop, 0); } -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { pa_iochannel *io; pa_modargs *ma; int exit_on_eof = 0; - assert(c); - assert(m); + pa_assert(m); - if (c->running_as_daemon) { + if (m->core->running_as_daemon) { pa_log_info("Running as daemon, refusing to load this module."); return 0; } @@ -94,12 +93,10 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - io = pa_iochannel_new(c->mainloop, STDIN_FILENO, STDOUT_FILENO); - assert(io); + io = pa_iochannel_new(m->core->mainloop, STDIN_FILENO, STDOUT_FILENO); pa_iochannel_set_noclose(io, 1); - m->userdata = pa_cli_new(c, io, m); - assert(m->userdata); + m->userdata = pa_cli_new(m->core, io, m); pa_cli_set_eof_callback(m->userdata, exit_on_eof ? eof_and_exit_cb : eof_and_unload_cb, m); @@ -115,11 +112,10 @@ fail: return -1; } -void pa__done(pa_core *c, pa_module*m) { - assert(c); - assert(m); +void pa__done(pa_module*m) { + pa_assert(m); - if (c->running_as_daemon == 0) { + if (m->core->running_as_daemon == 0) { pa_cli_free(m->userdata); pa_stdio_release(); } diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 716c20b2..665bf9dd 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -25,12 +25,13 @@ #include #endif -#include #include +#include #include #include +#include #include #include #include @@ -40,6 +41,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include "module-combine-symdef.h" @@ -55,13 +62,12 @@ PA_MODULE_USAGE( "format= " "channels= " "rate= " - "channel_map= ") + "channel_map=") #define DEFAULT_SINK_NAME "combined" #define MEMBLOCKQ_MAXLENGTH (1024*170) -#define RENDER_SIZE (1024*10) -#define DEFAULT_ADJUST_TIME 20 +#define DEFAULT_ADJUST_TIME 10 static const char* const valid_modargs[] = { "sink_name", @@ -78,170 +84,689 @@ static const char* const valid_modargs[] = { struct output { struct userdata *userdata; + + pa_sink *sink; pa_sink_input *sink_input; - size_t counter; + + pa_asyncmsgq *inq, /* Message queue from the sink thread to this sink input */ + *outq; /* Message queue from this sink input to the sink thread */ + pa_rtpoll_item *inq_rtpoll_item, *outq_rtpoll_item; + pa_memblockq *memblockq; + pa_usec_t total_latency; + PA_LLIST_FIELDS(struct output); }; struct userdata { - pa_module *module; pa_core *core; + pa_module *module; pa_sink *sink; - unsigned n_outputs; - struct output *master; + + pa_thread *thread; + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; + pa_time_event *time_event; uint32_t adjust_time; - PA_LLIST_HEAD(struct output, outputs); + pa_bool_t automatic; + size_t block_size; + + pa_hook_slot *sink_new_slot, *sink_unlink_slot, *sink_state_changed_slot; + + pa_resample_method_t resample_method; + + struct timeval adjust_timestamp; + + struct output *master; + pa_idxset* outputs; /* managed in main context */ + + struct { + PA_LLIST_HEAD(struct output, active_outputs); /* managed in IO thread context */ + pa_atomic_t running; /* we cache that value here, so that every thread can query it cheaply */ + struct timeval timestamp; + pa_bool_t in_null_mode; + } thread_info; }; -static void output_free(struct output *o); -static void clear_up(struct userdata *u); +enum { + SINK_MESSAGE_ADD_OUTPUT = PA_SINK_MESSAGE_MAX, + SINK_MESSAGE_REMOVE_OUTPUT, + SINK_MESSAGE_NEED +}; -static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, u->sink ? pa_sink_used_by(u->sink) : 0); -} +enum { + SINK_INPUT_MESSAGE_POST = PA_SINK_INPUT_MESSAGE_MAX +}; + +static void output_free(struct output *o); +static int output_create_sink_input(struct output *o); +static void update_master(struct userdata *u, struct output *o); +static void pick_master(struct userdata *u, struct output *except); static void adjust_rates(struct userdata *u) { struct output *o; pa_usec_t max_sink_latency = 0, min_total_latency = (pa_usec_t) -1, target_latency; uint32_t base_rate; - assert(u && u->sink); + uint32_t idx; - for (o = u->outputs; o; o = o->next) { - uint32_t sink_latency = o->sink_input->sink ? pa_sink_get_latency(o->sink_input->sink) : 0; + pa_assert(u); + pa_sink_assert_ref(u->sink); + if (pa_idxset_size(u->outputs) <= 0) + return; + + if (!u->master) + return; + + if (!PA_SINK_OPENED(pa_sink_get_state(u->sink))) + return; + + for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) { + pa_usec_t sink_latency; + + if (!o->sink_input || !PA_SINK_OPENED(pa_sink_get_state(o->sink))) + continue; + + sink_latency = pa_sink_get_latency(o->sink); o->total_latency = sink_latency + pa_sink_input_get_latency(o->sink_input); if (sink_latency > max_sink_latency) max_sink_latency = sink_latency; - if (o->total_latency < min_total_latency) + if (min_total_latency == (pa_usec_t) -1 || o->total_latency < min_total_latency) min_total_latency = o->total_latency; } - assert(min_total_latency != (pa_usec_t) -1); + if (min_total_latency == (pa_usec_t) -1) + return; target_latency = max_sink_latency > min_total_latency ? max_sink_latency : min_total_latency; pa_log_info("[%s] target latency is %0.0f usec.", u->sink->name, (float) target_latency); + pa_log_info("[%s] master %s latency %0.0f usec.", u->sink->name, u->master->sink->name, (float) u->master->total_latency); base_rate = u->sink->sample_spec.rate; - for (o = u->outputs; o; o = o->next) { + for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) { uint32_t r = base_rate; + if (!o->sink_input || !PA_SINK_OPENED(pa_sink_get_state(o->sink))) + continue; + if (o->total_latency < target_latency) - r -= (uint32_t) (((((double) target_latency - o->total_latency))/u->adjust_time)*r/ 1000000); + r -= (uint32_t) (((((double) target_latency - o->total_latency))/u->adjust_time)*r/PA_USEC_PER_SEC); else if (o->total_latency > target_latency) - r += (uint32_t) (((((double) o->total_latency - target_latency))/u->adjust_time)*r/ 1000000); + r += (uint32_t) (((((double) o->total_latency - target_latency))/u->adjust_time)*r/PA_USEC_PER_SEC); - if (r < (uint32_t) (base_rate*0.9) || r > (uint32_t) (base_rate*1.1)) + if (r < (uint32_t) (base_rate*0.9) || r > (uint32_t) (base_rate*1.1)) { pa_log_warn("[%s] sample rates too different, not adjusting (%u vs. %u).", o->sink_input->name, base_rate, r); - else { + pa_sink_input_set_rate(o->sink_input, base_rate); + } else { pa_log_info("[%s] new rate is %u Hz; ratio is %0.3f; latency is %0.0f usec.", o->sink_input->name, r, (double) r / base_rate, (float) o->total_latency); pa_sink_input_set_rate(o->sink_input, r); } } } -static void request_memblock(struct userdata *u) { - pa_memchunk chunk; - struct output *o; - assert(u && u->sink); +static void time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata) { + struct userdata *u = userdata; + struct timeval n; + + pa_assert(u); + pa_assert(a); + pa_assert(u->time_event == e); - update_usage(u); + adjust_rates(u); + + pa_gettimeofday(&n); + n.tv_sec += u->adjust_time; + u->sink->core->mainloop->time_restart(e, &n); +} + +static void thread_func(void *userdata) { + struct userdata *u = userdata; - if (pa_sink_render(u->sink, RENDER_SIZE, &chunk) < 0) + pa_assert(u); + + pa_log_debug("Thread starting up"); + + if (u->core->high_priority) + pa_make_realtime(); + + pa_thread_mq_install(&u->thread_mq); + pa_rtpoll_install(u->rtpoll); + + pa_rtclock_get(&u->thread_info.timestamp); + u->thread_info.in_null_mode = FALSE; + + for (;;) { + int ret; + + /* If no outputs are connected, render some data and drop it immediately. */ + if (u->sink->thread_info.state == PA_SINK_RUNNING && !u->thread_info.active_outputs) { + struct timeval now; + + pa_rtclock_get(&now); + + if (!u->thread_info.in_null_mode || pa_timeval_cmp(&u->thread_info.timestamp, &now) <= 0) { + pa_sink_skip(u->sink, u->block_size); + + if (!u->thread_info.in_null_mode) + u->thread_info.timestamp = now; + + pa_timeval_add(&u->thread_info.timestamp, pa_bytes_to_usec(u->block_size, &u->sink->sample_spec)); + } + + pa_rtpoll_set_timer_absolute(u->rtpoll, &u->thread_info.timestamp); + u->thread_info.in_null_mode = TRUE; + + } else { + pa_rtpoll_set_timer_disabled(u->rtpoll); + u->thread_info.in_null_mode = FALSE; + } + + /* Hmm, nothing to do. Let's sleep */ + if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0) { + pa_log_info("pa_rtpoll_run() = %i", ret); + goto fail; + } + + if (ret == 0) + goto finish; + } + +fail: + /* If this was no regular exit from the loop we have to continue + * processing messages until we received PA_MESSAGE_SHUTDOWN */ + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); + +finish: + pa_log_debug("Thread shutting down"); +} + +/* Called from I/O thread context */ +static void render_memblock(struct userdata *u, struct output *o, size_t length) { + pa_assert(u); + pa_assert(o); + + /* We are run by the sink thread, on behalf of an output (o). The + * other output is waiting for us, hence it is safe to access its + * mainblockq and asyncmsgq directly. */ + + /* If we are not running, we cannot produce any data */ + if (!pa_atomic_load(&u->thread_info.running)) return; - for (o = u->outputs; o; o = o->next) - pa_memblockq_push_align(o->memblockq, &chunk); + /* Maybe there's some data in the requesting output's queue + * now? */ + while (pa_asyncmsgq_process_one(o->inq) > 0) + ; + + /* Ok, now let's prepare some data if we really have to */ + while (!pa_memblockq_is_readable(o->memblockq)) { + struct output *j; + pa_memchunk chunk; + + /* Render data! */ + pa_sink_render(u->sink, length, &chunk); + + /* OK, let's send this data to the other threads */ + for (j = u->thread_info.active_outputs; j; j = j->next) - pa_memblock_unref(chunk.memblock); + /* Send to other outputs, which are not the requesting + * one */ + + if (j != o) + pa_asyncmsgq_post(j->inq, PA_MSGOBJECT(j->sink_input), SINK_INPUT_MESSAGE_POST, NULL, 0, &chunk, NULL); + + /* And place it directly into the requesting output's queue */ + if (o) + pa_memblockq_push_align(o->memblockq, &chunk); + + pa_memblock_unref(chunk.memblock); + } } -static void time_callback(pa_mainloop_api*a, pa_time_event* e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - struct userdata *u = userdata; - struct timeval n; - assert(u && a && u->time_event == e); +/* Called from I/O thread context */ +static void request_memblock(struct output *o, size_t length) { + pa_assert(o); + pa_sink_input_assert_ref(o->sink_input); + pa_sink_assert_ref(o->userdata->sink); - adjust_rates(u); + /* If another thread already prepared some data we received + * the data over the asyncmsgq, hence let's first process + * it. */ + while (pa_asyncmsgq_process_one(o->inq) > 0) + ; - pa_gettimeofday(&n); - n.tv_sec += u->adjust_time; - u->sink->core->mainloop->time_restart(e, &n); + /* Check whether we're now readable */ + if (pa_memblockq_is_readable(o->memblockq)) + return; + + /* OK, we need to prepare new data, but only if the sink is actually running */ + if (pa_atomic_load(&o->userdata->thread_info.running)) + pa_asyncmsgq_send(o->outq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_NEED, o, length, NULL); } -static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { - struct output *o = i->userdata; - assert(i && o && o->sink_input && chunk); +/* Called from I/O thread context */ +static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) { + struct output *o; - if (pa_memblockq_peek(o->memblockq, chunk) >= 0) - return 0; + pa_sink_input_assert_ref(i); + pa_assert_se(o = i->userdata); - /* Try harder */ - request_memblock(o->userdata); + /* If necessary, get some new data */ + request_memblock(o, length); return pa_memblockq_peek(o->memblockq, chunk); } -static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { - struct output *o = i->userdata; - assert(i && o && o->sink_input && chunk && length); +/* Called from I/O thread context */ +static void sink_input_drop_cb(pa_sink_input *i, size_t length) { + struct output *o; + + pa_sink_input_assert_ref(i); + pa_assert(length > 0); + pa_assert_se(o = i->userdata); + + pa_memblockq_drop(o->memblockq, length); +} + +/* Called from I/O thread context */ +static void sink_input_attach_cb(pa_sink_input *i) { + struct output *o; + + pa_sink_input_assert_ref(i); + pa_assert_se(o = i->userdata); + + /* Set up the queue from the sink thread to us */ + pa_assert(!o->inq_rtpoll_item); + o->inq_rtpoll_item = pa_rtpoll_item_new_asyncmsgq( + i->sink->rtpoll, + PA_RTPOLL_LATE, /* This one is not that important, since we check for data in _peek() anyway. */ + o->inq); +} + +/* Called from I/O thread context */ +static void sink_input_detach_cb(pa_sink_input *i) { + struct output *o; + + pa_sink_input_assert_ref(i); + pa_assert_se(o = i->userdata); - pa_memblockq_drop(o->memblockq, chunk, length); - o->counter += length; + /* Shut down the queue from the sink thread to us */ + pa_assert(o->inq_rtpoll_item); + pa_rtpoll_item_free(o->inq_rtpoll_item); + o->inq_rtpoll_item = NULL; } +/* Called from main context */ static void sink_input_kill_cb(pa_sink_input *i) { - struct output *o = i->userdata; - assert(i && o && o->sink_input); + struct output *o; + + pa_sink_input_assert_ref(i); + pa_assert(o = i->userdata); + pa_module_unload_request(o->userdata->module); - clear_up(o->userdata); + output_free(o); +} + +/* Called from thread context */ +static int sink_input_process_msg(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct output *o = PA_SINK_INPUT(obj)->userdata; + + switch (code) { + + case PA_SINK_INPUT_MESSAGE_GET_LATENCY: { + pa_usec_t *r = data; + + *r = pa_bytes_to_usec(pa_memblockq_get_length(o->memblockq), &o->sink_input->sample_spec); + + /* Fall through, the default handler will add in the extra + * latency added by the resampler */ + break; + } + + case SINK_INPUT_MESSAGE_POST: + + if (PA_SINK_OPENED(o->sink_input->sink->thread_info.state)) + pa_memblockq_push_align(o->memblockq, chunk); + else + pa_memblockq_flush(o->memblockq); + + break; + } + + return pa_sink_input_process_msg(obj, code, data, offset, chunk); } -static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { - struct output *o = i->userdata; - assert(i && o && o->sink_input); +/* Called from main context */ +static void disable_output(struct output *o) { + pa_assert(o); + + if (!o->sink_input) + return; + + pa_asyncmsgq_send(o->userdata->sink->asyncmsgq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_REMOVE_OUTPUT, o, 0, NULL); + pa_sink_input_unlink(o->sink_input); + pa_sink_input_unref(o->sink_input); + o->sink_input = NULL; - return pa_bytes_to_usec(pa_memblockq_get_length(o->memblockq), &i->sample_spec); } -static pa_usec_t sink_get_latency_cb(pa_sink *s) { - struct userdata *u = s->userdata; - assert(s && u && u->sink && u->master); +/* Called from main context */ +static void enable_output(struct output *o) { + pa_assert(o); + + if (o->sink_input) + return; + + if (output_create_sink_input(o) >= 0) { + + pa_memblockq_flush(o->memblockq); + + pa_sink_input_put(o->sink_input); + + if (o->userdata->sink && PA_SINK_LINKED(pa_sink_get_state(o->userdata->sink))) + pa_asyncmsgq_send(o->userdata->sink->asyncmsgq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_ADD_OUTPUT, o, 0, NULL); + } +} + +/* Called from main context */ +static void suspend(struct userdata *u) { + struct output *o; + uint32_t idx; + + pa_assert(u); + + /* Let's suspend by unlinking all streams */ + for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) + disable_output(o); + + pick_master(u, NULL); + + pa_log_info("Device suspended..."); +} + +/* Called from main context */ +static void unsuspend(struct userdata *u) { + struct output *o; + uint32_t idx; + + pa_assert(u); + + /* Let's resume */ + for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) { + + pa_sink_suspend(o->sink, FALSE); + + if (PA_SINK_OPENED(pa_sink_get_state(o->sink))) + enable_output(o); + } + + pick_master(u, NULL); + + pa_log_info("Resumed successfully..."); +} + +/* Called from main context */ +static int sink_set_state(pa_sink *sink, pa_sink_state_t state) { + struct userdata *u; + + pa_sink_assert_ref(sink); + pa_assert_se(u = sink->userdata); + + /* Please note that in contrast to the ALSA modules we call + * suspend/unsuspend from main context here! */ + + switch (state) { + case PA_SINK_SUSPENDED: + pa_assert(PA_SINK_OPENED(pa_sink_get_state(u->sink))); + + suspend(u); + break; + + case PA_SINK_IDLE: + case PA_SINK_RUNNING: + + if (pa_sink_get_state(u->sink) == PA_SINK_SUSPENDED) + unsuspend(u); + + break; + + case PA_SINK_UNLINKED: + case PA_SINK_INIT: + ; + } + + return 0; +} + +/* Called from thread context of the master */ +static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SINK(o)->userdata; + + switch (code) { + + case PA_SINK_MESSAGE_SET_STATE: + pa_atomic_store(&u->thread_info.running, PA_PTR_TO_UINT(data) == PA_SINK_RUNNING); + break; + + case PA_SINK_MESSAGE_GET_LATENCY: + + /* This code will only be called when running in NULL + * mode, i.e. when no output is attached. See + * sink_get_latency_cb() below */ + + if (u->thread_info.in_null_mode) { + struct timeval now; + + if (pa_timeval_cmp(&u->thread_info.timestamp, pa_rtclock_get(&now)) > 0) { + *((pa_usec_t*) data) = pa_timeval_diff(&u->thread_info.timestamp, &now); + break; + } + } + + *((pa_usec_t*) data) = 0; + + break; + + case SINK_MESSAGE_ADD_OUTPUT: { + struct output *op = data; + + PA_LLIST_PREPEND(struct output, u->thread_info.active_outputs, op); + + pa_assert(!op->outq_rtpoll_item); + + /* Create pa_asyncmsgq to the sink thread */ + + op->outq_rtpoll_item = pa_rtpoll_item_new_asyncmsgq( + u->rtpoll, + PA_RTPOLL_EARLY-1, /* This item is very important */ + op->outq); + + return 0; + } + + case SINK_MESSAGE_REMOVE_OUTPUT: { + struct output *op = data; - return - pa_sink_input_get_latency(u->master->sink_input) + - pa_sink_get_latency(u->master->sink_input->sink); + PA_LLIST_REMOVE(struct output, u->thread_info.active_outputs, op); + + /* Remove the q that leads from this output to the sink thread */ + + pa_assert(op->outq_rtpoll_item); + pa_rtpoll_item_free(op->outq_rtpoll_item); + op->outq_rtpoll_item = NULL; + + return 0; + } + + case SINK_MESSAGE_NEED: + render_memblock(u, data, (size_t) offset); + return 0; + } + + return pa_sink_process_msg(o, code, data, offset, chunk); } -static void sink_notify(pa_sink *s) { +/* Called from main context */ +static pa_usec_t sink_get_latency_cb(pa_sink *s) { struct userdata *u; + + pa_sink_assert_ref(s); + pa_assert_se(u = s->userdata); + + if (u->master) { + /* If we have a master sink, we just return the latency of it + * and add our own buffering on top */ + + if (!u->master->sink_input) + return 0; + + return + pa_sink_input_get_latency(u->master->sink_input) + + pa_sink_get_latency(u->master->sink); + + } else { + pa_usec_t usec = 0; + + /* We have no master, hence let's ask our own thread which + * implements the NULL sink */ + + if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0) + return 0; + + return usec; + } +} + +static void update_description(struct userdata *u) { + int first = 1; + char *t; + struct output *o; + uint32_t idx; + + pa_assert(u); + + if (pa_idxset_isempty(u->outputs)) { + pa_sink_set_description(u->sink, "Simultaneous output"); + return; + } + + t = pa_xstrdup("Simultaneous output to"); + + for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) { + char *e; + + if (first) { + e = pa_sprintf_malloc("%s %s", t, o->sink->description); + first = 0; + } else + e = pa_sprintf_malloc("%s, %s", t, o->sink->description); + + pa_xfree(t); + t = e; + } + + pa_sink_set_description(u->sink, t); + pa_xfree(t); +} + +static void update_master(struct userdata *u, struct output *o) { + pa_assert(u); + + if (u->master == o) + return; + + if ((u->master = o)) + pa_log_info("Master sink is now '%s'", o->sink_input->sink->name); + else + pa_log_info("No master selected, lacking suitable outputs."); +} + +static void pick_master(struct userdata *u, struct output *except) { struct output *o; + uint32_t idx; + pa_assert(u); + + if (u->master && + u->master != except && + u->master->sink_input && + PA_SINK_OPENED(pa_sink_get_state(u->master->sink))) { + update_master(u, u->master); + return; + } - assert(s); - u = s->userdata; - assert(u); + for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) + if (o != except && + o->sink_input && + PA_SINK_OPENED(pa_sink_get_state(o->sink))) { + update_master(u, o); + return; + } - for (o = u->outputs; o; o = o->next) - pa_sink_notify(o->sink_input->sink); + update_master(u, NULL); } -static struct output *output_new(struct userdata *u, pa_sink *sink, int resample_method) { - struct output *o = NULL; - char t[256]; +static int output_create_sink_input(struct output *o) { pa_sink_input_new_data data; + char *t; - assert(u && sink && u->sink); + pa_assert(o); - o = pa_xmalloc(sizeof(struct output)); - o->userdata = u; + if (o->sink_input) + return 0; + + t = pa_sprintf_malloc("Simultaneous output on %s", o->sink->description); - o->counter = 0; + pa_sink_input_new_data_init(&data); + data.sink = o->sink; + data.driver = __FILE__; + data.name = t; + pa_sink_input_new_data_set_sample_spec(&data, &o->userdata->sink->sample_spec); + pa_sink_input_new_data_set_channel_map(&data, &o->userdata->sink->channel_map); + data.module = o->userdata->module; + data.resample_method = o->userdata->resample_method; + + o->sink_input = pa_sink_input_new(o->userdata->core, &data, PA_SINK_INPUT_VARIABLE_RATE|PA_SINK_INPUT_DONT_MOVE); + + pa_xfree(t); + + if (!o->sink_input) + return -1; + + o->sink_input->parent.process_msg = sink_input_process_msg; + o->sink_input->peek = sink_input_peek_cb; + o->sink_input->drop = sink_input_drop_cb; + o->sink_input->attach = sink_input_attach_cb; + o->sink_input->detach = sink_input_detach_cb; + o->sink_input->kill = sink_input_kill_cb; + o->sink_input->userdata = o; + + + return 0; +} + +static struct output *output_new(struct userdata *u, pa_sink *sink) { + struct output *o; + + pa_assert(u); + pa_assert(sink); + pa_assert(u->sink); + + o = pa_xnew(struct output, 1); + o->userdata = u; + o->inq = pa_asyncmsgq_new(0); + o->outq = pa_asyncmsgq_new(0); + o->inq_rtpoll_item = NULL; + o->outq_rtpoll_item = NULL; + o->sink = sink; + o->sink_input = NULL; o->memblockq = pa_memblockq_new( 0, MEMBLOCKQ_MAXLENGTH, @@ -251,90 +776,151 @@ static struct output *output_new(struct userdata *u, pa_sink *sink, int resample 0, NULL); - snprintf(t, sizeof(t), "Output stream #%u of sink %s", u->n_outputs+1, u->sink->name); + pa_assert_se(pa_idxset_put(u->outputs, o, NULL) == 0); - pa_sink_input_new_data_init(&data); - data.sink = sink; - data.driver = __FILE__; - data.name = t; - pa_sink_input_new_data_set_sample_spec(&data, &u->sink->sample_spec); - pa_sink_input_new_data_set_channel_map(&data, &u->sink->channel_map); - data.module = u->module; + if (u->sink && PA_SINK_LINKED(pa_sink_get_state(u->sink))) + pa_asyncmsgq_send(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_ADD_OUTPUT, o, 0, NULL); + else { + /* If the sink is not yet started, we need to do the activation ourselves */ + PA_LLIST_PREPEND(struct output, u->thread_info.active_outputs, o); - if (!(o->sink_input = pa_sink_input_new(u->core, &data, PA_SINK_INPUT_VARIABLE_RATE))) - goto fail; + o->outq_rtpoll_item = pa_rtpoll_item_new_asyncmsgq( + u->rtpoll, + PA_RTPOLL_EARLY-1, /* This item is very important */ + o->outq); + } - o->sink_input->get_latency = sink_input_get_latency_cb; - o->sink_input->peek = sink_input_peek_cb; - o->sink_input->drop = sink_input_drop_cb; - o->sink_input->kill = sink_input_kill_cb; - o->sink_input->userdata = o; + if (PA_SINK_OPENED(pa_sink_get_state(u->sink)) || pa_sink_get_state(u->sink) == PA_SINK_INIT) { + pa_sink_suspend(sink, FALSE); + + if (PA_SINK_OPENED(pa_sink_get_state(sink))) + if (output_create_sink_input(o) < 0) + goto fail; + } + + + update_description(u); - PA_LLIST_PREPEND(struct output, u->outputs, o); - u->n_outputs++; return o; fail: if (o) { + pa_idxset_remove_by_data(u->outputs, o, NULL); + if (o->sink_input) { - pa_sink_input_disconnect(o->sink_input); + pa_sink_input_unlink(o->sink_input); pa_sink_input_unref(o->sink_input); } if (o->memblockq) pa_memblockq_free(o->memblockq); + if (o->inq) + pa_asyncmsgq_unref(o->inq); + + if (o->outq) + pa_asyncmsgq_unref(o->outq); + pa_xfree(o); } return NULL; } -static void output_free(struct output *o) { - assert(o); - PA_LLIST_REMOVE(struct output, o->userdata->outputs, o); - o->userdata->n_outputs--; - pa_memblockq_free(o->memblockq); - pa_sink_input_disconnect(o->sink_input); - pa_sink_input_unref(o->sink_input); - pa_xfree(o); +static pa_hook_result_t sink_new_hook_cb(pa_core *c, pa_sink *s, struct userdata* u) { + struct output *o; + + pa_core_assert_ref(c); + pa_sink_assert_ref(s); + pa_assert(u); + pa_assert(u->automatic); + + if (!(s->flags & PA_SINK_HARDWARE) || s == u->sink) + return PA_HOOK_OK; + + pa_log_info("Configuring new sink: %s", s->name); + + if (!(o = output_new(u, s))) { + pa_log("Failed to create sink input on sink '%s'.", s->name); + return PA_HOOK_OK; + } + + if (o->sink_input) + pa_sink_input_put(o->sink_input); + + pick_master(u, NULL); + + return PA_HOOK_OK; } -static void clear_up(struct userdata *u) { +static pa_hook_result_t sink_unlink_hook_cb(pa_core *c, pa_sink *s, struct userdata* u) { struct output *o; - assert(u); + uint32_t idx; - if (u->time_event) { - u->core->mainloop->time_free(u->time_event); - u->time_event = NULL; - } + pa_assert(c); + pa_sink_assert_ref(s); + pa_assert(u); - while ((o = u->outputs)) - output_free(o); + if (s == u->sink) + return PA_HOOK_OK; - u->master = NULL; + for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) + if (o->sink == s) + break; - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - u->sink = NULL; + if (!o) + return PA_HOOK_OK; + + pa_log_info("Unconfiguring sink: %s", s->name); + + output_free(o); + + return PA_HOOK_OK; +} + +static pa_hook_result_t sink_state_changed_hook_cb(pa_core *c, pa_sink *s, struct userdata* u) { + struct output *o; + uint32_t idx; + pa_sink_state_t state; + + if (s == u->sink) + return PA_HOOK_OK; + + for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) + if (o->sink == s) + break; + + if (!o) + return PA_HOOK_OK; + + state = pa_sink_get_state(s); + + if (PA_SINK_OPENED(state) && PA_SINK_OPENED(pa_sink_get_state(u->sink)) && !o->sink_input) { + enable_output(o); + pick_master(u, NULL); + } + + if (state == PA_SINK_SUSPENDED && o->sink_input) { + disable_output(o); + pick_master(u, o); } + + return PA_HOOK_OK; } -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { struct userdata *u; pa_modargs *ma = NULL; const char *master_name, *slaves, *rm; - pa_sink *master_sink; - char *n = NULL; - const char*split_state; - struct timeval tv; - int resample_method = -1; + pa_sink *master_sink = NULL; + int resample_method = PA_RESAMPLER_TRIVIAL; pa_sample_spec ss; pa_channel_map map; + struct output *o; + uint32_t idx; - assert(c && m); + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("failed to parse module arguments"); @@ -349,116 +935,256 @@ int pa__init(pa_core *c, pa_module*m) { } u = pa_xnew(struct userdata, 1); + u->core = m->core; + u->module = m; m->userdata = u; u->sink = NULL; - u->n_outputs = 0; u->master = NULL; - u->module = m; - u->core = c; u->time_event = NULL; u->adjust_time = DEFAULT_ADJUST_TIME; - PA_LLIST_HEAD_INIT(struct output, u->outputs); + pa_thread_mq_init(&u->thread_mq, m->core->mainloop); + u->rtpoll = pa_rtpoll_new(); + u->thread = NULL; + u->resample_method = resample_method; + u->outputs = pa_idxset_new(NULL, NULL); + memset(&u->adjust_timestamp, 0, sizeof(u->adjust_timestamp)); + u->sink_new_slot = u->sink_unlink_slot = u->sink_state_changed_slot = NULL; + PA_LLIST_HEAD_INIT(struct output, u->thread_info.active_outputs); + pa_atomic_store(&u->thread_info.running, FALSE); + u->thread_info.in_null_mode = FALSE; + pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq); if (pa_modargs_get_value_u32(ma, "adjust_time", &u->adjust_time) < 0) { - pa_log("failed to parse adjust_time value"); + pa_log("Failed to parse adjust_time value"); goto fail; } - if (!(master_name = pa_modargs_get_value(ma, "master", NULL)) || !(slaves = pa_modargs_get_value(ma, "slaves", NULL))) { - pa_log("no master or slave sinks specified"); + master_name = pa_modargs_get_value(ma, "master", NULL); + slaves = pa_modargs_get_value(ma, "slaves", NULL); + if (!master_name != !slaves) { + pa_log("No master or slave sinks specified"); goto fail; } - if (!(master_sink = pa_namereg_get(c, master_name, PA_NAMEREG_SINK, 1))) { - pa_log("invalid master sink '%s'", master_name); - goto fail; + if (master_name) { + if (!(master_sink = pa_namereg_get(m->core, master_name, PA_NAMEREG_SINK, 1))) { + pa_log("Invalid master sink '%s'", master_name); + goto fail; + } + + ss = master_sink->sample_spec; + u->automatic = FALSE; + } else { + master_sink = NULL; + ss = m->core->default_sample_spec; + u->automatic = TRUE; } - ss = master_sink->sample_spec; if ((pa_modargs_get_sample_spec(ma, &ss) < 0)) { - pa_log("invalid sample specification."); + pa_log("Invalid sample specification."); goto fail; } - if (ss.channels == master_sink->sample_spec.channels) + if (master_sink && ss.channels == master_sink->sample_spec.channels) map = master_sink->channel_map; else pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_DEFAULT); - if ((pa_modargs_get_channel_map(ma, &map) < 0)) { - pa_log("invalid channel map."); + if ((pa_modargs_get_channel_map(ma, NULL, &map) < 0)) { + pa_log("Invalid channel map."); goto fail; } if (ss.channels != map.channels) { - pa_log("channel map and sample specification don't match."); + pa_log("Channel map and sample specification don't match."); goto fail; } - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { - pa_log("failed to create sink"); + if (!(u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { + pa_log("Failed to create sink"); goto fail; } - pa_sink_set_owner(u->sink, m); - pa_sink_set_description(u->sink, "Combined Sink"); + u->sink->parent.process_msg = sink_process_msg; u->sink->get_latency = sink_get_latency_cb; - u->sink->notify = sink_notify; + u->sink->set_state = sink_set_state; u->sink->userdata = u; - if (!(u->master = output_new(u, master_sink, resample_method))) { - pa_log("failed to create master sink input on sink '%s'.", u->sink->name); - goto fail; - } + u->sink->flags = PA_SINK_LATENCY; + pa_sink_set_module(u->sink, m); + pa_sink_set_description(u->sink, "Simultaneous output"); + pa_sink_set_rtpoll(u->sink, u->rtpoll); + pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); + + u->block_size = pa_bytes_per_second(&ss) / 20; /* 50 ms */ + if (u->block_size <= 0) + u->block_size = pa_frame_size(&ss); - split_state = NULL; - while ((n = pa_split(slaves, ",", &split_state))) { - pa_sink *slave_sink; + if (!u->automatic) { + const char*split_state; + char *n = NULL; + pa_assert(slaves); - if (!(slave_sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) { - pa_log("invalid slave sink '%s'", n); + /* The master and slaves have been specified manually */ + + if (!(u->master = output_new(u, master_sink))) { + pa_log("Failed to create master sink input on sink '%s'.", master_sink->name); goto fail; } - pa_xfree(n); + split_state = NULL; + while ((n = pa_split(slaves, ",", &split_state))) { + pa_sink *slave_sink; - if (!output_new(u, slave_sink, resample_method)) { - pa_log("failed to create slave sink input on sink '%s'.", slave_sink->name); - goto fail; + if (!(slave_sink = pa_namereg_get(m->core, n, PA_NAMEREG_SINK, 1)) || slave_sink == u->sink) { + pa_log("Invalid slave sink '%s'", n); + pa_xfree(n); + goto fail; + } + + pa_xfree(n); + + if (!output_new(u, slave_sink)) { + pa_log("Failed to create slave sink input on sink '%s'.", slave_sink->name); + goto fail; + } } + + if (pa_idxset_size(u->outputs) <= 1) + pa_log_warn("No slave sinks specified."); + + u->sink_new_slot = NULL; + + } else { + pa_sink *s; + + /* We're in automatic mode, we elect one hw sink to the master + * and attach all other hw sinks as slaves to it */ + + for (s = pa_idxset_first(m->core->sinks, &idx); s; s = pa_idxset_next(m->core->sinks, &idx)) { + + if (!(s->flags & PA_SINK_HARDWARE) || s == u->sink) + continue; + + if (!output_new(u, s)) { + pa_log("Failed to create sink input on sink '%s'.", s->name); + goto fail; + } + } + + u->sink_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_NEW_POST], (pa_hook_cb_t) sink_new_hook_cb, u); } - if (u->n_outputs <= 1) - pa_log_warn("WARNING: no slave sinks specified."); + u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], (pa_hook_cb_t) sink_unlink_hook_cb, u); + u->sink_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], (pa_hook_cb_t) sink_state_changed_hook_cb, u); + + pick_master(u, NULL); + + if (!(u->thread = pa_thread_new(thread_func, u))) { + pa_log("Failed to create thread."); + goto fail; + } + + /* Activate the sink and the sink inputs */ + pa_sink_put(u->sink); + + for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) + if (o->sink_input) + pa_sink_input_put(o->sink_input); if (u->adjust_time > 0) { + struct timeval tv; pa_gettimeofday(&tv); tv.tv_sec += u->adjust_time; - u->time_event = c->mainloop->time_new(c->mainloop, &tv, time_callback, u); + u->time_event = m->core->mainloop->time_new(m->core->mainloop, &tv, time_callback, u); } pa_modargs_free(ma); + return 0; fail: - pa_xfree(n); if (ma) pa_modargs_free(ma); - pa__done(c, m); + pa__done(m); + return -1; } -void pa__done(pa_core *c, pa_module*m) { +static void output_free(struct output *o) { + pa_assert(o); + + pick_master(o->userdata, o); + + disable_output(o); + + pa_assert_se(pa_idxset_remove_by_data(o->userdata->outputs, o, NULL)); + + update_description(o->userdata); + + if (o->inq_rtpoll_item) + pa_rtpoll_item_free(o->inq_rtpoll_item); + + if (o->outq_rtpoll_item) + pa_rtpoll_item_free(o->outq_rtpoll_item); + + if (o->inq) + pa_asyncmsgq_unref(o->inq); + + if (o->outq) + pa_asyncmsgq_unref(o->outq); + + if (o->memblockq) + pa_memblockq_free(o->memblockq); + + pa_xfree(o); +} + +void pa__done(pa_module*m) { struct userdata *u; - assert(c && m); + struct output *o; + + pa_assert(m); if (!(u = m->userdata)) return; - clear_up(u); - pa_xfree(u); -} + if (u->sink_new_slot) + pa_hook_slot_free(u->sink_new_slot); + + if (u->sink_unlink_slot) + pa_hook_slot_free(u->sink_unlink_slot); + + if (u->sink_state_changed_slot) + pa_hook_slot_free(u->sink_state_changed_slot); + + if (u->outputs) { + while ((o = pa_idxset_first(u->outputs, NULL))) + output_free(o); + + pa_idxset_free(u->outputs, NULL, NULL); + } + if (u->sink) + pa_sink_unlink(u->sink); + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); + } + + pa_thread_mq_done(&u->thread_mq); + + if (u->sink) + pa_sink_unref(u->sink); + + if (u->rtpoll) + pa_rtpoll_free(u->rtpoll); + + if (u->time_event) + u->core->mainloop->time_free(u->time_event); + + pa_xfree(u); +} diff --git a/src/modules/module-default-device-restore.c b/src/modules/module-default-device-restore.c new file mode 100644 index 00000000..a816eae8 --- /dev/null +++ b/src/modules/module-default-device-restore.c @@ -0,0 +1,103 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "module-default-device-restore-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Automatically restore the default sink and source") +PA_MODULE_VERSION(PACKAGE_VERSION) + +#define DEFAULT_SINK_FILE "default-sink" +#define DEFAULT_SOURCE_FILE "default-source" + +int pa__init(pa_module *m) { + FILE *f; + + /* We never overwrite manually configured settings */ + + if (m->core->default_sink_name) + pa_log_info("Manually configured default sink, not overwriting."); + else if ((f = pa_open_config_file(NULL, DEFAULT_SINK_FILE, NULL, NULL, "r"))) { + char ln[256] = ""; + + fgets(ln, sizeof(ln)-1, f); + pa_strip_nl(ln); + fclose(f); + + if (!ln[0]) + pa_log_debug("No previous default sink setting, ignoring."); + else if (pa_namereg_get(m->core, ln, PA_NAMEREG_SINK, 1)) { + pa_namereg_set_default(m->core, ln, PA_NAMEREG_SINK); + pa_log_debug("Restored default sink '%s'.", ln); + } else + pa_log_info("Saved default sink '%s' not existant, not restoring default sink setting.", ln); + } + + if (m->core->default_source_name) + pa_log_info("Manually configured default source, not overwriting."); + else if ((f = pa_open_config_file(NULL, DEFAULT_SOURCE_FILE, NULL, NULL, "r"))) { + char ln[256] = ""; + + fgets(ln, sizeof(ln)-1, f); + pa_strip_nl(ln); + fclose(f); + + if (!ln[0]) + pa_log_debug("No previous default source setting, ignoring."); + else if (pa_namereg_get(m->core, ln, PA_NAMEREG_SOURCE, 1)) { + pa_namereg_set_default(m->core, ln, PA_NAMEREG_SOURCE); + pa_log_debug("Restored default source '%s'.", ln); + } else + pa_log_info("Saved default source '%s' not existant, not restoring default source setting.", ln); + } + + return 0; +} + +void pa__done(pa_module*m) { + FILE *f; + + if ((f = pa_open_config_file(NULL, DEFAULT_SINK_FILE, NULL, NULL, "w"))) { + const char *n = pa_namereg_get_default_sink_name(m->core); + fprintf(f, "%s\n", n ? n : ""); + fclose(f); + } + + if ((f = pa_open_config_file(NULL, DEFAULT_SOURCE_FILE, NULL, NULL, "w"))) { + const char *n = pa_namereg_get_default_source_name(m->core); + fprintf(f, "%s\n", n ? n : ""); + fclose(f); + } +} + + + diff --git a/src/modules/module-defs.h.m4 b/src/modules/module-defs.h.m4 index c961412d..5bff748e 100644 --- a/src/modules/module-defs.h.m4 +++ b/src/modules/module-defs.h.m4 @@ -18,8 +18,8 @@ gen_symbol(pa__get_description) gen_symbol(pa__get_usage) gen_symbol(pa__get_version) -int pa__init(struct pa_core *c, struct pa_module*m); -void pa__done(struct pa_core *c, struct pa_module*m); +int pa__init(pa_module*m); +void pa__done(pa_module*m); const char* pa__get_author(void); const char* pa__get_description(void); diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index 41b68ac3..7dc25243 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -28,7 +28,6 @@ #endif #include -#include #include #include #include @@ -44,6 +43,7 @@ #include #include #include +#include #include "module-detect-symdef.h" @@ -52,6 +52,11 @@ PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("just-one=") +static const char* const valid_modargs[] = { + "just-one", + NULL +}; + #ifdef HAVE_ALSA static int detect_alsa(pa_core *c, int just_one) { @@ -96,7 +101,7 @@ static int detect_alsa(pa_core *c, int just_one) { if (subdevice != 0) continue; - snprintf(args, sizeof(args), "device=hw:%u", device); + pa_snprintf(args, sizeof(args), "device=hw:%u", device); if (!pa_module_load(c, is_sink ? "module-alsa-sink" : "module-alsa-source", args)) continue; @@ -139,7 +144,7 @@ static int detect_oss(pa_core *c, int just_one) { line[strcspn(line, "\r\n")] = 0; if (!b) { - b = strcmp(line, "Audio devices:") == 0 || strcmp(line, "Installed devices:") == 0; + b = strcmp(line, "Audio devices:") == 0 || strcmp(line, "Installed devices:") == 0; continue; } @@ -148,20 +153,20 @@ static int detect_oss(pa_core *c, int just_one) { if (sscanf(line, "%u: ", &device) == 1) { if (device == 0) - snprintf(args, sizeof(args), "device=/dev/dsp"); + pa_snprintf(args, sizeof(args), "device=/dev/dsp"); else - snprintf(args, sizeof(args), "device=/dev/dsp%u", device); + pa_snprintf(args, sizeof(args), "device=/dev/dsp%u", device); if (!pa_module_load(c, "module-oss", args)) continue; - } else if (sscanf(line, "pcm%u: ", &device) == 1) { + } else if (sscanf(line, "pcm%u: ", &device) == 1) { /* FreeBSD support, the devices are named /dev/dsp0.0, dsp0.1 and so on */ - snprintf(args, sizeof(args), "device=/dev/dsp%u.0", device); + pa_snprintf(args, sizeof(args), "device=/dev/dsp%u.0", device); if (!pa_module_load(c, "module-oss", args)) continue; - } + } n++; @@ -193,7 +198,7 @@ static int detect_solaris(pa_core *c, int just_one) { if (!S_ISCHR(s.st_mode)) return 0; - snprintf(args, sizeof(args), "device=%s", dev); + pa_snprintf(args, sizeof(args), "device=%s", dev); if (!pa_module_load(c, "module-solaris", args)) return 0; @@ -215,17 +220,11 @@ static int detect_waveout(pa_core *c, int just_one) { } #endif -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { int just_one = 0, n = 0; pa_modargs *ma; - static const char* const valid_modargs[] = { - "just-one", - NULL - }; - - assert(c); - assert(m); + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments"); @@ -238,16 +237,16 @@ int pa__init(pa_core *c, pa_module*m) { } #if HAVE_ALSA - if ((n = detect_alsa(c, just_one)) <= 0) + if ((n = detect_alsa(m->core, just_one)) <= 0) #endif #if HAVE_OSS - if ((n = detect_oss(c, just_one)) <= 0) + if ((n = detect_oss(m->core, just_one)) <= 0) #endif #if HAVE_SOLARIS - if ((n = detect_solaris(c, just_one)) <= 0) + if ((n = detect_solaris(m->core, just_one)) <= 0) #endif #if OS_IS_WIN32 - if ((n = detect_waveout(c, just_one)) <= 0) + if ((n = detect_waveout(m->core, just_one)) <= 0) #endif { pa_log_warn("failed to detect any sound hardware."); @@ -269,9 +268,3 @@ fail: return -1; } - - -void pa__done(PA_GCC_UNUSED pa_core *c, PA_GCC_UNUSED pa_module*m) { - /* NOP */ -} - diff --git a/src/modules/module-esound-compat-spawnfd.c b/src/modules/module-esound-compat-spawnfd.c index 1aecade5..f0f73fcf 100644 --- a/src/modules/module-esound-compat-spawnfd.c +++ b/src/modules/module-esound-compat-spawnfd.c @@ -26,7 +26,6 @@ #endif #include -#include #include #include @@ -48,23 +47,25 @@ static const char* const valid_modargs[] = { NULL, }; -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { pa_modargs *ma = NULL; int ret = -1, fd = -1; char x = 1; - assert(c && m); + + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs)) || pa_modargs_get_value_s32(ma, "fd", &fd) < 0 || fd < 0) { + pa_log("Failed to parse module arguments"); goto finish; } if (pa_loop_write(fd, &x, sizeof(x), NULL) != sizeof(x)) - pa_log("WARNING: write(%u, 1, 1) failed: %s", fd, pa_cstrerror(errno)); + pa_log_warn("write(%u, 1, 1) failed: %s", fd, pa_cstrerror(errno)); - close(fd); + pa_assert_se(pa_close(fd) == 0); pa_module_unload_request(m); @@ -76,9 +77,3 @@ finish: return ret; } - -void pa__done(pa_core *c, pa_module*m) { - assert(c && m); -} - - diff --git a/src/modules/module-esound-compat-spawnpid.c b/src/modules/module-esound-compat-spawnpid.c index a9fd166d..6562fe28 100644 --- a/src/modules/module-esound-compat-spawnpid.c +++ b/src/modules/module-esound-compat-spawnpid.c @@ -25,7 +25,6 @@ #endif #include -#include #include #include #include @@ -48,11 +47,12 @@ static const char* const valid_modargs[] = { NULL, }; -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { pa_modargs *ma = NULL; int ret = -1; uint32_t pid = 0; - assert(c && m); + + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs)) || pa_modargs_get_value_u32(ma, "pid", &pid) < 0 || @@ -62,7 +62,7 @@ int pa__init(pa_core *c, pa_module*m) { } if (kill(pid, SIGUSR1) < 0) - pa_log("WARNING: kill(%u) failed: %s", pid, pa_cstrerror(errno)); + pa_log_warn("kill(%u) failed: %s", pid, pa_cstrerror(errno)); pa_module_unload_request(m); @@ -74,9 +74,3 @@ finish: return ret; } - -void pa__done(pa_core *c, pa_module*m) { - assert(c && m); -} - - diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index 26638d9d..8b46637e 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -28,14 +28,23 @@ #include #include #include -#include #include #include #include #include #include +#include +#include +#include +#include +#include + +#ifdef HAVE_LINUX_SOCKIOS_H +#include +#endif #include +#include #include #include @@ -47,27 +56,37 @@ #include #include #include +#include +#include +#include +#include +#include #include "module-esound-sink-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ESOUND Sink") PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= server=
        cookie= format= channels= rate=") +PA_MODULE_USAGE( + "sink_name= " + "server=
        cookie= " + "format= " + "channels= " + "rate=") -#define DEFAULT_SINK_NAME "esound_output" +#define DEFAULT_SINK_NAME "esound_out" struct userdata { pa_core *core; - + pa_module *module; pa_sink *sink; - pa_iochannel *io; - pa_socket_client *client; - pa_defer_event *defer_event; + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; + pa_rtpoll_item *rtpoll_item; + pa_thread *thread; pa_memchunk memchunk; - pa_module *module; void *write_data; size_t write_length, write_index; @@ -75,12 +94,28 @@ struct userdata { void *read_data; size_t read_length, read_index; - enum { STATE_AUTH, STATE_LATENCY, STATE_RUNNING, STATE_DEAD } state; + enum { + STATE_AUTH, + STATE_LATENCY, + STATE_PREPARE, + STATE_RUNNING, + STATE_DEAD + } state; pa_usec_t latency; esd_format_t format; int32_t rate; + + pa_smoother *smoother; + int fd; + + int64_t offset; + + pa_iochannel *io; + pa_socket_client *client; + + size_t block_size; }; static const char* const valid_modargs[] = { @@ -93,42 +128,211 @@ static const char* const valid_modargs[] = { NULL }; -static void cancel(struct userdata *u) { - assert(u); +enum { + SINK_MESSAGE_PASS_SOCKET = PA_SINK_MESSAGE_MAX +}; - u->state = STATE_DEAD; +static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SINK(o)->userdata; - if (u->io) { - pa_iochannel_free(u->io); - u->io = NULL; - } + switch (code) { - if (u->defer_event) { - u->core->mainloop->defer_free(u->defer_event); - u->defer_event = NULL; - } + case PA_SINK_MESSAGE_SET_STATE: - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - u->sink = NULL; + switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) { + + case PA_SINK_SUSPENDED: + pa_assert(PA_SINK_OPENED(u->sink->thread_info.state)); + + pa_smoother_pause(u->smoother, pa_rtclock_usec()); + break; + + case PA_SINK_IDLE: + case PA_SINK_RUNNING: + + if (u->sink->thread_info.state == PA_SINK_SUSPENDED) + pa_smoother_resume(u->smoother, pa_rtclock_usec()); + + break; + + case PA_SINK_UNLINKED: + case PA_SINK_INIT: + ; + } + + break; + + case PA_SINK_MESSAGE_GET_LATENCY: { + pa_usec_t w, r; + + r = pa_smoother_get(u->smoother, pa_rtclock_usec()); + w = pa_bytes_to_usec(u->offset + u->memchunk.length, &u->sink->sample_spec); + + *((pa_usec_t*) data) = w > r ? w - r : 0; + break; + } + + case SINK_MESSAGE_PASS_SOCKET: { + struct pollfd *pollfd; + + pa_assert(!u->rtpoll_item); + + u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + pollfd->fd = u->fd; + pollfd->events = pollfd->revents = 0; + + return 0; + } } - if (u->module) { - pa_module_unload_request(u->module); - u->module = NULL; + return pa_sink_process_msg(o, code, data, offset, chunk); +} + +static void thread_func(void *userdata) { + struct userdata *u = userdata; + int write_type = 0; + + pa_assert(u); + + pa_log_debug("Thread starting up"); + + pa_thread_mq_install(&u->thread_mq); + pa_rtpoll_install(u->rtpoll); + + pa_smoother_set_time_offset(u->smoother, pa_rtclock_usec()); + + for (;;) { + int ret; + + if (u->rtpoll_item) { + struct pollfd *pollfd; + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + + /* Render some data and write it to the fifo */ + if (PA_SINK_OPENED(u->sink->thread_info.state) && pollfd->revents) { + pa_usec_t usec; + int64_t n; + + for (;;) { + ssize_t l; + void *p; + + if (u->memchunk.length <= 0) + pa_sink_render(u->sink, u->block_size, &u->memchunk); + + pa_assert(u->memchunk.length > 0); + + p = pa_memblock_acquire(u->memchunk.memblock); + l = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, &write_type); + pa_memblock_release(u->memchunk.memblock); + + pa_assert(l != 0); + + if (l < 0) { + + if (errno == EINTR) + continue; + else if (errno == EAGAIN) { + + /* OK, we filled all socket buffers up + * now. */ + goto filled_up; + + } else { + pa_log("Failed to write data to FIFO: %s", pa_cstrerror(errno)); + goto fail; + } + + } else { + u->offset += l; + + u->memchunk.index += l; + u->memchunk.length -= l; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + pa_memchunk_reset(&u->memchunk); + } + + pollfd->revents = 0; + + if (u->memchunk.length > 0) + + /* OK, we wrote less that we asked for, + * hence we can assume that the socket + * buffers are full now */ + goto filled_up; + } + } + + filled_up: + + /* At this spot we know that the socket buffers are + * fully filled up. This is the best time to estimate + * the playback position of the server */ + + n = u->offset; + +#ifdef SIOCOUTQ + { + int l; + if (ioctl(u->fd, SIOCOUTQ, &l) >= 0 && l > 0) + n -= l; + } +#endif + + usec = pa_bytes_to_usec(n, &u->sink->sample_spec); + + if (usec > u->latency) + usec -= u->latency; + else + usec = 0; + + pa_smoother_put(u->smoother, pa_rtclock_usec(), usec); + } + + /* Hmm, nothing to do. Let's sleep */ + pollfd->events = PA_SINK_OPENED(u->sink->thread_info.state) ? POLLOUT : 0; + } + + if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0) + goto fail; + + if (ret == 0) + goto finish; + + if (u->rtpoll_item) { + struct pollfd* pollfd; + + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + + if (pollfd->revents & ~POLLOUT) { + pa_log("FIFO shutdown."); + goto fail; + } + } } + +fail: + /* If this was no regular exit from the loop we have to continue + * processing messages until we received PA_MESSAGE_SHUTDOWN */ + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); + +finish: + pa_log_debug("Thread shutting down"); } static int do_write(struct userdata *u) { ssize_t r; - assert(u); + pa_assert(u); if (!pa_iochannel_is_writable(u->io)) return 0; if (u->write_data) { - assert(u->write_index < u->write_length); + pa_assert(u->write_index < u->write_length); if ((r = pa_iochannel_write(u->io, (uint8_t*) u->write_data + u->write_index, u->write_length - u->write_index)) <= 0) { pa_log("write() failed: %s", pa_cstrerror(errno)); @@ -136,45 +340,44 @@ static int do_write(struct userdata *u) { } u->write_index += r; - assert(u->write_index <= u->write_length); + pa_assert(u->write_index <= u->write_length); if (u->write_index == u->write_length) { - free(u->write_data); + pa_xfree(u->write_data); u->write_data = NULL; u->write_index = u->write_length = 0; } - } else if (u->state == STATE_RUNNING) { - pa_module_set_used(u->module, pa_sink_used_by(u->sink)); + } - if (!u->memchunk.length) - if (pa_sink_render(u->sink, 8192, &u->memchunk) < 0) - return 0; + if (!u->write_data && u->state == STATE_PREPARE) { + /* OK, we're done with sending all control data we need to, so + * let's hand the socket over to the IO thread now */ - assert(u->memchunk.memblock && u->memchunk.length); + pa_assert(u->fd < 0); + u->fd = pa_iochannel_get_send_fd(u->io); - if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { - pa_log("write() failed: %s", pa_cstrerror(errno)); - return -1; - } + pa_iochannel_set_noclose(u->io, TRUE); + pa_iochannel_free(u->io); + u->io = NULL; - u->memchunk.index += r; - u->memchunk.length -= r; + pa_make_tcp_socket_low_delay(u->fd); - if (u->memchunk.length <= 0) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - } + pa_log_info("Connection authenticated, handing fd to IO thread..."); + + pa_asyncmsgq_post(u->thread_mq.inq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_PASS_SOCKET, NULL, 0, NULL, NULL); + u->state = STATE_RUNNING; } return 0; } static int handle_response(struct userdata *u) { - assert(u); + pa_assert(u); switch (u->state) { + case STATE_AUTH: - assert(u->read_length == sizeof(int32_t)); + pa_assert(u->read_length == sizeof(int32_t)); /* Process auth data */ if (!*(int32_t*) u->read_data) { @@ -183,14 +386,14 @@ static int handle_response(struct userdata *u) { } /* Request latency data */ - assert(!u->write_data); + pa_assert(!u->write_data); *(int32_t*) (u->write_data = pa_xmalloc(u->write_length = sizeof(int32_t))) = ESD_PROTO_LATENCY; u->write_index = 0; u->state = STATE_LATENCY; /* Space for next response */ - assert(u->read_length >= sizeof(int32_t)); + pa_assert(u->read_length >= sizeof(int32_t)); u->read_index = 0; u->read_length = sizeof(int32_t); @@ -198,17 +401,17 @@ static int handle_response(struct userdata *u) { case STATE_LATENCY: { int32_t *p; - assert(u->read_length == sizeof(int32_t)); + pa_assert(u->read_length == sizeof(int32_t)); /* Process latency info */ u->latency = (pa_usec_t) ((double) (*(int32_t*) u->read_data) * 1000000 / 44100); if (u->latency > 10000000) { - pa_log("WARNING! Invalid latency information received from server"); + pa_log_warn("Invalid latency information received from server"); u->latency = 0; } /* Create stream */ - assert(!u->write_data); + pa_assert(!u->write_data); p = u->write_data = pa_xmalloc0(u->write_length = sizeof(int32_t)*3+ESD_NAME_MAX); *(p++) = ESD_PROTO_STREAM_PLAY; *(p++) = u->format; @@ -216,7 +419,7 @@ static int handle_response(struct userdata *u) { pa_strlcpy((char*) p, "PulseAudio Tunnel", ESD_NAME_MAX); u->write_index = 0; - u->state = STATE_RUNNING; + u->state = STATE_PREPARE; /* Don't read any further */ pa_xfree(u->read_data); @@ -227,14 +430,14 @@ static int handle_response(struct userdata *u) { } default: - abort(); + pa_assert_not_reached(); } return 0; } static int do_read(struct userdata *u) { - assert(u); + pa_assert(u); if (!pa_iochannel_is_readable(u->io)) return 0; @@ -245,16 +448,15 @@ static int do_read(struct userdata *u) { if (!u->read_data) return 0; - assert(u->read_index < u->read_length); + pa_assert(u->read_index < u->read_length); if ((r = pa_iochannel_read(u->io, (uint8_t*) u->read_data + u->read_index, u->read_length - u->read_index)) <= 0) { pa_log("read() failed: %s", r < 0 ? pa_cstrerror(errno) : "EOF"); - cancel(u); return -1; } u->read_index += r; - assert(u->read_index <= u->read_length); + pa_assert(u->read_index <= u->read_length); if (u->read_index == u->read_length) return handle_response(u); @@ -263,42 +465,19 @@ static int do_read(struct userdata *u) { return 0; } -static void do_work(struct userdata *u) { - assert(u); - - u->core->mainloop->defer_enable(u->defer_event, 0); - - if (do_read(u) < 0 || do_write(u) < 0) - cancel(u); -} - -static void notify_cb(pa_sink*s) { - struct userdata *u = s->userdata; - assert(s && u); - - if (pa_iochannel_is_writable(u->io)) - u->core->mainloop->defer_enable(u->defer_event, 1); -} - -static pa_usec_t get_latency_cb(pa_sink *s) { - struct userdata *u = s->userdata; - assert(s && u); +static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { + struct userdata *u = userdata; + pa_assert(u); - return - u->latency + - (u->memchunk.memblock ? pa_bytes_to_usec(u->memchunk.length, &s->sample_spec) : 0); -} + if (do_read(u) < 0 || do_write(u) < 0) { -static void defer_callback(PA_GCC_UNUSED pa_mainloop_api *m, PA_GCC_UNUSED pa_defer_event*e, void *userdata) { - struct userdata *u = userdata; - assert(u); - do_work(u); -} + if (u->io) { + pa_iochannel_free(u->io); + u->io = NULL; + } -static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { - struct userdata *u = userdata; - assert(u); - do_work(u); + pa_module_unload_request(u->module); + } } static void on_connection(PA_GCC_UNUSED pa_socket_client *c, pa_iochannel*io, void *userdata) { @@ -308,30 +487,34 @@ static void on_connection(PA_GCC_UNUSED pa_socket_client *c, pa_iochannel*io, vo u->client = NULL; if (!io) { - pa_log("connection failed: %s", pa_cstrerror(errno)); - cancel(u); + pa_log("Connection failed: %s", pa_cstrerror(errno)); + pa_module_unload_request(u->module); return; } + pa_assert(!u->io); u->io = io; pa_iochannel_set_callback(u->io, io_callback, u); + + pa_log_info("Connection established, authenticating ..."); } -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { struct userdata *u = NULL; const char *p; pa_sample_spec ss; pa_modargs *ma = NULL; char *t; + const char *espeaker; - assert(c && m); + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("failed to parse module arguments"); goto fail; } - ss = c->default_sample_spec; + ss = m->core->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { pa_log("invalid sample format specification"); goto fail; @@ -343,37 +526,62 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - u = pa_xmalloc0(sizeof(struct userdata)); - u->core = c; + u = pa_xnew0(struct userdata, 1); + u->core = m->core; u->module = m; m->userdata = u; + u->fd = -1; + u->smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC*2, TRUE); + pa_memchunk_reset(&u->memchunk); + u->offset = 0; + + pa_thread_mq_init(&u->thread_mq, m->core->mainloop); + u->rtpoll = pa_rtpoll_new(); + pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq); + u->rtpoll_item = NULL; + u->format = (ss.format == PA_SAMPLE_U8 ? ESD_BITS8 : ESD_BITS16) | (ss.channels == 2 ? ESD_STEREO : ESD_MONO); u->rate = ss.rate; - u->sink = NULL; - u->client = NULL; - u->io = NULL; + u->block_size = pa_usec_to_bytes(PA_USEC_PER_SEC/20, &ss); + u->read_data = u->write_data = NULL; u->read_index = u->write_index = u->read_length = u->write_length = 0; + u->state = STATE_AUTH; u->latency = 0; - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { + if (!(u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { pa_log("failed to create sink."); goto fail; } - if (!(u->client = pa_socket_client_new_string(u->core->mainloop, p = pa_modargs_get_value(ma, "server", ESD_UNIX_SOCKET_NAME), ESD_DEFAULT_PORT))) { - pa_log("failed to connect to server."); + u->sink->parent.process_msg = sink_process_msg; + u->sink->userdata = u; + u->sink->flags = PA_SINK_LATENCY; + + pa_sink_set_module(u->sink, m); + pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); + pa_sink_set_rtpoll(u->sink, u->rtpoll); + + if (!(espeaker = getenv("ESPEAKER"))) + espeaker = ESD_UNIX_SOCKET_NAME; + + if (!(u->client = pa_socket_client_new_string(u->core->mainloop, p = pa_modargs_get_value(ma, "server", espeaker), ESD_DEFAULT_PORT))) { + pa_log("Failed to connect to server."); goto fail; } + + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Esound sink '%s'", p)); + pa_xfree(t); + pa_socket_client_set_callback(u->client, on_connection, u); /* Prepare the initial request */ u->write_data = pa_xmalloc(u->write_length = ESD_KEY_LEN + sizeof(int32_t)); if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", ".esd_auth"), u->write_data, ESD_KEY_LEN) < 0) { - pa_log("failed to load cookie"); + pa_log("Failed to load cookie"); goto fail; } *(int32_t*) ((uint8_t*) u->write_data + ESD_KEY_LEN) = ESD_ENDIAN_KEY; @@ -381,19 +589,12 @@ int pa__init(pa_core *c, pa_module*m) { /* Reserve space for the response */ u->read_data = pa_xmalloc(u->read_length = sizeof(int32_t)); - u->sink->notify = notify_cb; - u->sink->get_latency = get_latency_cb; - u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Esound sink '%s'", p)); - pa_xfree(t); - - u->memchunk.memblock = NULL; - u->memchunk.length = 0; - - u->defer_event = c->mainloop->defer_new(c->mainloop, defer_callback, u); - c->mainloop->defer_enable(u->defer_event, 0); + if (!(u->thread = pa_thread_new(thread_func, u))) { + pa_log("Failed to create thread."); + goto fail; + } + pa_sink_put(u->sink); pa_modargs_free(ma); @@ -403,20 +604,39 @@ fail: if (ma) pa_modargs_free(ma); - pa__done(c, m); + pa__done(m); return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata *u; - assert(c && m); + pa_assert(m); if (!(u = m->userdata)) return; - u->module = NULL; - cancel(u); + if (u->sink) + pa_sink_unlink(u->sink); + + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); + } + + pa_thread_mq_done(&u->thread_mq); + + if (u->sink) + pa_sink_unref(u->sink); + + if (u->io) + pa_iochannel_free(u->io); + + if (u->rtpoll_item) + pa_rtpoll_item_free(u->rtpoll_item); + + if (u->rtpoll) + pa_rtpoll_free(u->rtpoll); if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); @@ -427,8 +647,11 @@ void pa__done(pa_core *c, pa_module*m) { pa_xfree(u->read_data); pa_xfree(u->write_data); - pa_xfree(u); -} - + if (u->smoother) + pa_smoother_free(u->smoother); + if (u->fd >= 0) + pa_close(u->fd); + pa_xfree(u); +} diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index 1f48a452..a8ca7df3 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -1,25 +1,25 @@ /* $Id$ */ /*** - This file is part of PulseAudio. + This file is part of PulseAudio. - Copyright 2006 Lennart Poettering - Copyright 2006 Shams E. King + Copyright 2006 Lennart Poettering + Copyright 2006 Shams E. King - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. - You should have received a copy of the GNU Lesser General Public License - along with PulseAudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. ***/ #ifdef HAVE_CONFIG_H @@ -27,7 +27,6 @@ #endif #include -#include #include #include #include @@ -45,6 +44,9 @@ #include #include #include +#include +#include +#include #include @@ -54,40 +56,27 @@ PA_MODULE_AUTHOR("Shahms King") PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers") PA_MODULE_VERSION(PACKAGE_VERSION) - -typedef enum { -#ifdef HAVE_ALSA - CAP_ALSA, -#endif -#ifdef HAVE_OSS - CAP_OSS, -#endif - CAP_MAX -} capability_t; - -static const char* const capabilities[CAP_MAX] = { -#ifdef HAVE_ALSA - [CAP_ALSA] = "alsa", -#endif -#ifdef HAVE_OSS - [CAP_OSS] = "oss", +#if defined(HAVE_ALSA) && defined(HAVE_OSS) +PA_MODULE_USAGE("api=") +#elif defined(HAVE_ALSA) +PA_MODULE_USAGE("api=") +#elif defined(HAVE_OSS) +PA_MODULE_USAGE("api=") #endif -}; struct device { uint32_t index; char *udi; + char *sink_name, *source_name; + int acl_race_fix; }; struct userdata { pa_core *core; - LibHalContext *ctx; - capability_t capability; - pa_dbus_connection *conn; + LibHalContext *context; + pa_dbus_connection *connection; pa_hashmap *devices; -#if defined(HAVE_ALSA) && defined(HAVE_OSS) - int use_oss; -#endif + const char *capability; }; struct timerdata { @@ -95,23 +84,30 @@ struct timerdata { char *udi; }; -static const char* get_capability_name(capability_t cap) { - if (cap >= CAP_MAX) - return NULL; - return capabilities[cap]; -} +#define CAPABILITY_ALSA "alsa" +#define CAPABILITY_OSS "oss" + +static const char* const valid_modargs[] = { + "api", + NULL +}; static void hal_device_free(struct device* d) { + pa_assert(d); + pa_xfree(d->udi); + pa_xfree(d->sink_name); + pa_xfree(d->source_name); pa_xfree(d); } static void hal_device_free_cb(void *d, PA_GCC_UNUSED void *data) { - hal_device_free((struct device*) d); + hal_device_free(d); } static const char *strip_udi(const char *udi) { const char *slash; + if ((slash = strrchr(udi, '/'))) return slash+1; @@ -119,6 +115,7 @@ static const char *strip_udi(const char *udi) { } #ifdef HAVE_ALSA + typedef enum { ALSA_TYPE_SINK, ALSA_TYPE_SOURCE, @@ -126,234 +123,297 @@ typedef enum { ALSA_TYPE_MAX } alsa_type_t; -static alsa_type_t hal_device_get_alsa_type(LibHalContext *ctx, const char *udi, - DBusError *error) -{ +static alsa_type_t hal_alsa_device_get_type(LibHalContext *context, const char *udi, DBusError *error) { char *type; alsa_type_t t; - type = libhal_device_get_property_string(ctx, udi, "alsa.type", error); - if (!type || dbus_error_is_set(error)) - return FALSE; + if (!(type = libhal_device_get_property_string(context, udi, "alsa.type", error))) + return ALSA_TYPE_OTHER; - if (!strcmp(type, "playback")) { + if (!strcmp(type, "playback")) t = ALSA_TYPE_SINK; - } else if (!strcmp(type, "capture")) { + else if (!strcmp(type, "capture")) t = ALSA_TYPE_SOURCE; - } else { + else t = ALSA_TYPE_OTHER; - } + libhal_free_string(type); return t; } -static int hal_device_get_alsa_card(LibHalContext *ctx, const char *udi, - DBusError *error) -{ - return libhal_device_get_property_int(ctx, udi, "alsa.card", error); -} +static int hal_alsa_device_is_modem(LibHalContext *context, const char *udi, DBusError *error) { + char *class; + int r; + + if (!(class = libhal_device_get_property_string(context, udi, "alsa.pcm_class", error))) + return 0; + + r = strcmp(class, "modem") == 0; + pa_xfree(class); -static int hal_device_get_alsa_device(LibHalContext *ctx, const char *udi, - DBusError *error) -{ - return libhal_device_get_property_int(ctx, udi, "alsa.device", error); + return r; } -static pa_module* hal_device_load_alsa(struct userdata *u, const char *udi, - DBusError *error) -{ - char args[128]; +static pa_module* hal_device_load_alsa(struct userdata *u, const char *udi, char **sink_name, char **source_name) { + char *args; alsa_type_t type; int device, card; const char *module_name; + DBusError error; + pa_module *m; - type = hal_device_get_alsa_type(u->ctx, udi, error); - if (dbus_error_is_set(error) || type == ALSA_TYPE_OTHER) - return NULL; + dbus_error_init(&error); - device = hal_device_get_alsa_device(u->ctx, udi, error); - if (dbus_error_is_set(error) || device != 0) - return NULL; + pa_assert(u); + pa_assert(sink_name); + pa_assert(source_name); - card = hal_device_get_alsa_card(u->ctx, udi, error); - if (dbus_error_is_set(error)) - return NULL; + *sink_name = *source_name = NULL; + + type = hal_alsa_device_get_type(u->context, udi, &error); + if (dbus_error_is_set(&error) || type == ALSA_TYPE_OTHER) + goto fail; + + device = libhal_device_get_property_int(u->context, udi, "alsa.device", &error); + if (dbus_error_is_set(&error) || device != 0) + goto fail; + + card = libhal_device_get_property_int(u->context, udi, "alsa.card", &error); + if (dbus_error_is_set(&error)) + goto fail; + + if (hal_alsa_device_is_modem(u->context, udi, &error)) + goto fail; if (type == ALSA_TYPE_SINK) { + *sink_name = pa_sprintf_malloc("alsa_output.%s", strip_udi(udi)); + module_name = "module-alsa-sink"; - snprintf(args, sizeof(args), "device=hw:%u sink_name=alsa_output.%s", card, strip_udi(udi)); + args = pa_sprintf_malloc("device=hw:%u sink_name=%s", card, *sink_name); } else { + *source_name = pa_sprintf_malloc("alsa_input.%s", strip_udi(udi)); + module_name = "module-alsa-source"; - snprintf(args, sizeof(args), "device=hw:%u source_name=alsa_input.%s", card, strip_udi(udi)); + args = pa_sprintf_malloc("device=hw:%u source_name=%s", card, *source_name); } pa_log_debug("Loading %s with arguments '%s'", module_name, args); - return pa_module_load(u->core, module_name, args); + m = pa_module_load(u->core, module_name, args); + + pa_xfree(args); + + if (!m) { + pa_xfree(*sink_name); + pa_xfree(*source_name); + *sink_name = *source_name = NULL; + } + + return m; + +fail: + if (dbus_error_is_set(&error)) { + pa_log_error("D-Bus error while parsing ALSA data: %s: %s", error.name, error.message); + dbus_error_free(&error); + } + + return NULL; } #endif #ifdef HAVE_OSS -static dbus_bool_t hal_device_is_oss_pcm(LibHalContext *ctx, const char *udi, - DBusError *error) -{ - dbus_bool_t rv = FALSE; - char* type, *device_file = NULL; + +static int hal_oss_device_is_pcm(LibHalContext *context, const char *udi, DBusError *error) { + char *class = NULL, *dev = NULL, *e; int device; + int r = 0; - type = libhal_device_get_property_string(ctx, udi, "oss.type", error); - if (!type || dbus_error_is_set(error)) - return FALSE; + class = libhal_device_get_property_string(context, udi, "oss.type", error); + if (dbus_error_is_set(error) || !class) + goto finish; - if (!strcmp(type, "pcm")) { - char *e; + if (strcmp(class, "pcm")) + goto finish; - device = libhal_device_get_property_int(ctx, udi, "oss.device", error); - if (dbus_error_is_set(error) || device != 0) - goto exit; + dev = libhal_device_get_property_string(context, udi, "oss.device_file", error); + if (dbus_error_is_set(error) || !dev) + goto finish; - device_file = libhal_device_get_property_string(ctx, udi, "oss.device_file", - error); - if (!device_file || dbus_error_is_set(error)) - goto exit; + if ((e = strrchr(dev, '/'))) + if (pa_startswith(e + 1, "audio")) + goto finish; - /* hack to ignore /dev/audio style devices */ - if ((e = strrchr(device_file, '/'))) - rv = !pa_startswith(e + 1, "audio"); - } + device = libhal_device_get_property_int(context, udi, "oss.device", error); + if (dbus_error_is_set(error) || device != 0) + goto finish; -exit: - libhal_free_string(type); - libhal_free_string(device_file); - return rv; + r = 1; + +finish: + + libhal_free_string(class); + libhal_free_string(dev); + + return r; } -static pa_module* hal_device_load_oss(struct userdata *u, const char *udi, - DBusError *error) -{ - char args[256]; +static pa_module* hal_device_load_oss(struct userdata *u, const char *udi, char **sink_name, char **source_name) { + char* args; char* device; + DBusError error; + pa_module *m; - if (!hal_device_is_oss_pcm(u->ctx, udi, error) || dbus_error_is_set(error)) - return NULL; + dbus_error_init(&error); - device = libhal_device_get_property_string(u->ctx, udi, "oss.device_file", - error); - if (!device || dbus_error_is_set(error)) - return NULL; + pa_assert(u); + pa_assert(sink_name); + pa_assert(source_name); + + *sink_name = *source_name = NULL; - snprintf(args, sizeof(args), "device=%s sink_name=oss_output.%s source_name=oss_input.%s", device, strip_udi(udi), strip_udi(udi)); + if (!hal_oss_device_is_pcm(u->context, udi, &error) || dbus_error_is_set(&error)) + goto fail; + + device = libhal_device_get_property_string(u->context, udi, "oss.device_file", &error); + if (!device || dbus_error_is_set(&error)) + goto fail; + + *sink_name = pa_sprintf_malloc("oss_output.%s", strip_udi(udi)); + *source_name = pa_sprintf_malloc("oss_input.%s", strip_udi(udi)); + + args = pa_sprintf_malloc("device=%s sink_name=%s source_name=%s", device, *sink_name, *source_name); libhal_free_string(device); pa_log_debug("Loading module-oss with arguments '%s'", args); + m = pa_module_load(u->core, "module-oss", args); + pa_xfree(args); + + if (!m) { + pa_xfree(*sink_name); + pa_xfree(*source_name); + *sink_name = *source_name = NULL; + } + + return m; + +fail: + if (dbus_error_is_set(&error)) { + pa_log_error("D-Bus error while parsing OSS data: %s: %s", error.name, error.message); + dbus_error_free(&error); + } - return pa_module_load(u->core, "module-oss", args); + return NULL; } #endif -static dbus_bool_t hal_device_add(struct userdata *u, const char *udi, - DBusError *error) -{ +static struct device* hal_device_add(struct userdata *u, const char *udi) { pa_module* m = NULL; struct device *d; + char *sink_name = NULL, *source_name = NULL; + + pa_assert(u); + pa_assert(u->capability); + pa_assert(!pa_hashmap_get(u->devices, udi)); - switch(u->capability) { #ifdef HAVE_ALSA - case CAP_ALSA: - m = hal_device_load_alsa(u, udi, error); - break; + if (strcmp(u->capability, CAPABILITY_ALSA) == 0) + m = hal_device_load_alsa(u, udi, &sink_name, &source_name); #endif #ifdef HAVE_OSS - case CAP_OSS: -#ifdef HAVE_ALSA - if (u->use_oss) -#endif - m = hal_device_load_oss(u, udi, error); - break; + if (strcmp(u->capability, CAPABILITY_OSS) == 0) + m = hal_device_load_oss(u, udi, &sink_name, &source_name); #endif - default: - assert(FALSE); /* never reached */ - break; - } - if (!m || dbus_error_is_set(error)) - return FALSE; + if (!m) + return NULL; d = pa_xnew(struct device, 1); + d->acl_race_fix = 0; d->udi = pa_xstrdup(udi); d->index = m->index; - + d->sink_name = sink_name; + d->source_name = source_name; pa_hashmap_put(u->devices, d->udi, d); - return TRUE; + return d; } -static int hal_device_add_all(struct userdata *u, capability_t capability) -{ +static int hal_device_add_all(struct userdata *u, const char *capability) { DBusError error; - int i,n,count; - dbus_bool_t r; + int i, n, count = 0; char** udis; - const char* cap = get_capability_name(capability); - assert(capability < CAP_MAX); + pa_assert(u); - pa_log_info("Trying capability %u (%s)", capability, cap); dbus_error_init(&error); - udis = libhal_find_device_by_capability(u->ctx, cap, &n, &error); + + if (u->capability && strcmp(u->capability, capability) != 0) + return 0; + + pa_log_info("Trying capability %s", capability); + + udis = libhal_find_device_by_capability(u->context, capability, &n, &error); if (dbus_error_is_set(&error)) { - pa_log_error("Error finding devices: %s: %s", error.name, - error.message); + pa_log_error("Error finding devices: %s: %s", error.name, error.message); dbus_error_free(&error); return -1; } - count = 0; - u->capability = capability; - for (i = 0; i < n; ++i) { - r = hal_device_add(u, udis[i], &error); - if (dbus_error_is_set(&error)) { - pa_log_error("Error adding device: %s: %s", error.name, - error.message); - dbus_error_free(&error); - count = -1; - break; + + if (n > 0) { + u->capability = capability; + + for (i = 0; i < n; i++) { + struct device *d; + + if (!(d = hal_device_add(u, udis[i]))) + pa_log_debug("Not loaded device %s", udis[i]); + else { + if (d->sink_name) + pa_scache_play_item_by_name(u->core, "pulse-coldplug", d->sink_name, PA_VOLUME_NORM, 0); + count++; + } } - if (r) - ++count; } libhal_free_string_array(udis); return count; } -static dbus_bool_t device_has_capability(LibHalContext *ctx, const char *udi, - const char* cap, DBusError *error) -{ +static dbus_bool_t device_has_capability(LibHalContext *context, const char *udi, const char* cap, DBusError *error){ dbus_bool_t has_prop; - has_prop = libhal_device_property_exists(ctx, udi, "info.capabilities", - error); + + has_prop = libhal_device_property_exists(context, udi, "info.capabilities", error); if (!has_prop || dbus_error_is_set(error)) return FALSE; - return libhal_device_query_capability(ctx, udi, cap, error); + return libhal_device_query_capability(context, udi, cap, error); } -static void device_added_time_cb(pa_mainloop_api *ea, pa_time_event *ev, - const struct timeval *tv, void *userdata) -{ +static void device_added_time_cb(pa_mainloop_api *ea, pa_time_event *ev, const struct timeval *tv, void *userdata) { DBusError error; - struct timerdata *td = (struct timerdata*) userdata; + struct timerdata *td = userdata; dbus_error_init(&error); - if (libhal_device_exists(td->u->ctx, td->udi, &error)) - hal_device_add(td->u, td->udi, &error); - if (dbus_error_is_set(&error)) { - pa_log_error("Error adding device: %s: %s", error.name, - error.message); - dbus_error_free(&error); + if (!pa_hashmap_get(td->u->devices, td->udi)) { + int b; + struct device *d; + + b = libhal_device_exists(td->u->context, td->udi, &error); + + if (dbus_error_is_set(&error)) { + pa_log_error("Error adding device: %s: %s", error.name, error.message); + dbus_error_free(&error); + } else if (b) { + if (!(d = hal_device_add(td->u, td->udi))) + pa_log_debug("Not loaded device %s", td->udi); + else { + if (d->sink_name) + pa_scache_play_item_by_name(td->u->core, "pulse-hotplug", d->sink_name, PA_VOLUME_NORM, 0); + } + } } pa_xfree(td->udi); @@ -361,28 +421,68 @@ static void device_added_time_cb(pa_mainloop_api *ea, pa_time_event *ev, ea->time_free(ev); } -static void device_added_cb(LibHalContext *ctx, const char *udi) -{ +static void device_added_cb(LibHalContext *context, const char *udi) { DBusError error; struct timeval tv; - dbus_bool_t has_cap; struct timerdata *t; - struct userdata *u = (struct userdata*) libhal_ctx_get_user_data(ctx); - const char* cap = get_capability_name(u->capability); + struct userdata *u; + int good = 0; + + pa_assert_se(u = libhal_ctx_get_user_data(context)); + + if (pa_hashmap_get(u->devices, udi)) + return; pa_log_debug("HAL Device added: %s", udi); dbus_error_init(&error); - has_cap = device_has_capability(ctx, udi, cap, &error); - if (dbus_error_is_set(&error)) { - pa_log_error("Error getting capability: %s: %s", error.name, - error.message); - dbus_error_free(&error); - return; + + if (u->capability) { + + good = device_has_capability(context, udi, u->capability, &error); + + if (dbus_error_is_set(&error)) { + pa_log_error("Error getting capability: %s: %s", error.name, error.message); + dbus_error_free(&error); + return; + } + + } else { + +#ifdef HAVE_ALSA + good = device_has_capability(context, udi, CAPABILITY_ALSA, &error); + + if (dbus_error_is_set(&error)) { + pa_log_error("Error getting capability: %s: %s", error.name, error.message); + dbus_error_free(&error); + return; + } + + if (good) + u->capability = CAPABILITY_ALSA; +#endif +#if defined(HAVE_OSS) && defined(HAVE_ALSA) + if (!good) { +#endif +#ifdef HAS_OSS + good = device_has_capability(context, udi, CAPABILITY_OSS, &error); + + if (dbus_error_is_set(&error)) { + pa_log_error("Error getting capability: %s: %s", error.name, error.message); + dbus_error_free(&error); + return; + } + + if (good) + u->capability = CAPABILITY_OSS; + +#endif +#if defined(HAVE_OSS) && defined(HAVE_ALSA) + } +#endif } - /* skip it */ - if (!has_cap) + if (!good) return; /* actually add the device 1/2 second later */ @@ -392,187 +492,359 @@ static void device_added_cb(LibHalContext *ctx, const char *udi) pa_gettimeofday(&tv); pa_timeval_add(&tv, 500000); - u->core->mainloop->time_new(u->core->mainloop, &tv, - device_added_time_cb, t); + u->core->mainloop->time_new(u->core->mainloop, &tv, device_added_time_cb, t); } -static void device_removed_cb(LibHalContext* ctx, const char *udi) -{ +static void device_removed_cb(LibHalContext* context, const char *udi) { struct device *d; - struct userdata *u = (struct userdata*) libhal_ctx_get_user_data(ctx); + struct userdata *u; + + pa_assert_se(u = libhal_ctx_get_user_data(context)); pa_log_debug("Device removed: %s", udi); + if ((d = pa_hashmap_remove(u->devices, udi))) { pa_module_unload_by_index(u->core, d->index); hal_device_free(d); } } -static void new_capability_cb(LibHalContext *ctx, const char *udi, - const char* capability) -{ - struct userdata *u = (struct userdata*) libhal_ctx_get_user_data(ctx); - const char* capname = get_capability_name(u->capability); +static void new_capability_cb(LibHalContext *context, const char *udi, const char* capability) { + struct userdata *u; + + pa_assert_se(u = libhal_ctx_get_user_data(context)); - if (capname && !strcmp(capname, capability)) { + if (!u->capability || strcmp(u->capability, capability) == 0) /* capability we care about, pretend it's a new device */ - device_added_cb(ctx, udi); - } + device_added_cb(context, udi); } -static void lost_capability_cb(LibHalContext *ctx, const char *udi, - const char* capability) -{ - struct userdata *u = (struct userdata*) libhal_ctx_get_user_data(ctx); - const char* capname = get_capability_name(u->capability); +static void lost_capability_cb(LibHalContext *context, const char *udi, const char* capability) { + struct userdata *u; - if (capname && !strcmp(capname, capability)) { - /* capability we care about, pretend it was removed */ - device_removed_cb(ctx, udi); - } -} + pa_assert_se(u = libhal_ctx_get_user_data(context)); -#if 0 -static void property_modified_cb(LibHalContext *ctx, const char *udi, - const char* key, - dbus_bool_t is_removed, - dbus_bool_t is_added) -{ + if (u->capability && strcmp(u->capability, capability) == 0) + /* capability we care about, pretend it was removed */ + device_removed_cb(context, udi); } -#endif -static void pa_hal_context_free(LibHalContext* hal_ctx) -{ +static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata) { + struct userdata*u = userdata; DBusError error; + pa_assert(bus); + pa_assert(message); + pa_assert(u); + dbus_error_init(&error); - libhal_ctx_shutdown(hal_ctx, &error); - libhal_ctx_free(hal_ctx); - if (dbus_error_is_set(&error)) { - dbus_error_free(&error); + pa_log_debug("dbus: interface=%s, path=%s, member=%s\n", + dbus_message_get_interface(message), + dbus_message_get_path(message), + dbus_message_get_member(message)); + + if (dbus_message_is_signal(message, "org.freedesktop.Hal.Device.AccessControl", "ACLAdded") || + dbus_message_is_signal(message, "org.freedesktop.Hal.Device.AccessControl", "ACLRemoved")) { + uint32_t uid; + int suspend = strcmp(dbus_message_get_member(message), "ACLRemoved") == 0; + + if (!dbus_message_get_args(message, &error, DBUS_TYPE_UINT32, &uid, DBUS_TYPE_INVALID) || dbus_error_is_set(&error)) { + pa_log_error("Failed to parse ACL message: %s: %s", error.name, error.message); + goto finish; + } + + if (uid == getuid() || uid == geteuid()) { + struct device *d; + const char *udi; + + udi = dbus_message_get_path(message); + + if ((d = pa_hashmap_get(u->devices, udi))) { + int send_acl_race_fix_message = 0; + + d->acl_race_fix = 0; + + if (d->sink_name) { + pa_sink *sink; + + if ((sink = pa_namereg_get(u->core, d->sink_name, PA_NAMEREG_SINK, 0))) { + int prev_suspended = pa_sink_get_state(sink) == PA_SINK_SUSPENDED; + + if (prev_suspended && !suspend) { + /* resume */ + if (pa_sink_suspend(sink, 0) >= 0) + pa_scache_play_item_by_name(u->core, "pulse-access", d->sink_name, PA_VOLUME_NORM, 0); + else + d->acl_race_fix = 1; + + } else if (!prev_suspended && suspend) { + /* suspend */ + if (pa_sink_suspend(sink, 1) >= 0) + send_acl_race_fix_message = 1; + } + } + } + + if (d->source_name) { + pa_source *source; + + if ((source = pa_namereg_get(u->core, d->source_name, PA_NAMEREG_SOURCE, 0))) { + int prev_suspended = pa_source_get_state(source) == PA_SOURCE_SUSPENDED; + + if (prev_suspended && !suspend) { + /* resume */ + if (pa_source_suspend(source, 0) < 0) + d->acl_race_fix = 1; + + } else if (!prev_suspended && suspend) { + /* suspend */ + if (pa_source_suspend(source, 0) >= 0) + send_acl_race_fix_message = 1; + } + } + } + + if (send_acl_race_fix_message) { + DBusMessage *msg; + msg = dbus_message_new_signal(udi, "org.pulseaudio.Server", "DirtyGiveUpMessage"); + dbus_connection_send(pa_dbus_connection_get(u->connection), msg, NULL); + dbus_message_unref(msg); + } + + } else if (!suspend) + device_added_cb(u->context, udi); + } + + } else if (dbus_message_is_signal(message, "org.pulseaudio.Server", "DirtyGiveUpMessage")) { + /* We use this message to avoid a dirty race condition when we + get an ACLAdded message before the previously owning PA + sever has closed the device. We can remove this as + soon as HAL learns frevoke() */ + + const char *udi; + struct device *d; + + udi = dbus_message_get_path(message); + + if ((d = pa_hashmap_get(u->devices, udi)) && d->acl_race_fix) { + pa_log_debug("Got dirty give up message for '%s', trying resume ...", udi); + + d->acl_race_fix = 0; + + if (d->sink_name) { + pa_sink *sink; + + if ((sink = pa_namereg_get(u->core, d->sink_name, PA_NAMEREG_SINK, 0))) { + + int prev_suspended = pa_sink_get_state(sink) == PA_SINK_SUSPENDED; + + if (prev_suspended) { + /* resume */ + if (pa_sink_suspend(sink, 0) >= 0) + pa_scache_play_item_by_name(u->core, "pulse-access", d->sink_name, PA_VOLUME_NORM, 0); + } + } + } + + if (d->source_name) { + pa_source *source; + + if ((source = pa_namereg_get(u->core, d->source_name, PA_NAMEREG_SOURCE, 0))) { + + int prev_suspended = pa_source_get_state(source) == PA_SOURCE_SUSPENDED; + + if (prev_suspended) + pa_source_suspend(source, 0); + } + } + + } else + /* Yes, we don't check the UDI for validity, but hopefully HAL will */ + device_added_cb(u->context, udi); } + +finish: + dbus_error_free(&error); + + return DBUS_HANDLER_RESULT_HANDLED; } -static void userdata_free(struct userdata *u) { - pa_hal_context_free(u->ctx); - /* free the devices with the hashmap */ - pa_hashmap_free(u->devices, hal_device_free_cb, NULL); - pa_dbus_connection_unref(u->conn); - pa_xfree(u); +static void hal_context_free(LibHalContext* hal_context) { + DBusError error; + + dbus_error_init(&error); + + libhal_ctx_shutdown(hal_context, &error); + libhal_ctx_free(hal_context); + + dbus_error_free(&error); } -static LibHalContext* pa_hal_context_new(pa_core* c, DBusConnection *conn) -{ +static LibHalContext* hal_context_new(pa_core* c, DBusConnection *conn) { DBusError error; - LibHalContext *hal_ctx = NULL; + LibHalContext *hal_context = NULL; dbus_error_init(&error); - if (!(hal_ctx = libhal_ctx_new())) { + + if (!(hal_context = libhal_ctx_new())) { pa_log_error("libhal_ctx_new() failed"); goto fail; } - if (!libhal_ctx_set_dbus_connection(hal_ctx, conn)) { - pa_log_error("Error establishing DBUS connection: %s: %s", - error.name, error.message); + if (!libhal_ctx_set_dbus_connection(hal_context, conn)) { + pa_log_error("Error establishing DBUS connection: %s: %s", error.name, error.message); goto fail; } - if (!libhal_ctx_init(hal_ctx, &error)) { - pa_log_error("Couldn't connect to hald: %s: %s", - error.name, error.message); + if (!libhal_ctx_init(hal_context, &error)) { + pa_log_error("Couldn't connect to hald: %s: %s", error.name, error.message); goto fail; } - return hal_ctx; + return hal_context; fail: - if (hal_ctx) - pa_hal_context_free(hal_ctx); + if (hal_context) + hal_context_free(hal_context); - if (dbus_error_is_set(&error)) - dbus_error_free(&error); + dbus_error_free(&error); return NULL; } -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { DBusError error; pa_dbus_connection *conn; struct userdata *u = NULL; - LibHalContext *hal_ctx = NULL; + LibHalContext *hal_context = NULL; int n = 0; + pa_modargs *ma; + const char *api; - assert(c); - assert(m); + pa_assert(m); dbus_error_init(&error); - if (!(conn = pa_dbus_bus_get(c, DBUS_BUS_SYSTEM, &error))) { - pa_log_error("Unable to contact DBUS system bus: %s: %s", - error.name, error.message); - dbus_error_free(&error); - return -1; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log("Failed to parse module arguments"); + goto fail; } - if (!(hal_ctx = pa_hal_context_new(c, pa_dbus_connection_get(conn)))) { + if ((api = pa_modargs_get_value(ma, "api", NULL))) { + int good = 0; + +#ifdef HAVE_ALSA + if (strcmp(api, CAPABILITY_ALSA) == 0) { + good = 1; + api = CAPABILITY_ALSA; + } +#endif +#ifdef HAVE_OSS + if (strcmp(api, CAPABILITY_OSS) == 0) { + good = 1; + api = CAPABILITY_OSS; + } +#endif + + if (!good) { + pa_log_error("Invalid API specification."); + goto fail; + } + } + + if (!(conn = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) { + if (conn) + pa_dbus_connection_unref(conn); + pa_log_error("Unable to contact DBUS system bus: %s: %s", error.name, error.message); + goto fail; + } + + if (!(hal_context = hal_context_new(m->core, pa_dbus_connection_get(conn)))) { /* pa_hal_context_new() logs appropriate errors */ - return -1; + pa_dbus_connection_unref(conn); + goto fail; } u = pa_xnew(struct userdata, 1); - u->core = c; - u->ctx = hal_ctx; - u->conn = conn; - u->devices = pa_hashmap_new(pa_idxset_string_hash_func, - pa_idxset_string_compare_func); - m->userdata = (void*) u; + u->core = m->core; + u->context = hal_context; + u->connection = conn; + u->devices = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + u->capability = api; + m->userdata = u; #ifdef HAVE_ALSA - n = hal_device_add_all(u, CAP_ALSA); + n = hal_device_add_all(u, CAPABILITY_ALSA); #endif #if defined(HAVE_ALSA) && defined(HAVE_OSS) - u->use_oss = 0; - - if (n <= 0) { + if (n <= 0) #endif #ifdef HAVE_OSS - n += hal_device_add_all(u, CAP_OSS); + n += hal_device_add_all(u, CAPABILITY_OSS); #endif -#if defined(HAVE_ALSA) && defined(HAVE_OSS) - /* We found something with OSS, but didn't find anything with - * ALSA. Then let's use only OSS from now on. */ - if (n > 0) - u->use_oss = 1; + libhal_ctx_set_user_data(hal_context, u); + libhal_ctx_set_device_added(hal_context, device_added_cb); + libhal_ctx_set_device_removed(hal_context, device_removed_cb); + libhal_ctx_set_device_new_capability(hal_context, new_capability_cb); + libhal_ctx_set_device_lost_capability(hal_context, lost_capability_cb); + + if (!libhal_device_property_watch_all(hal_context, &error)) { + pa_log_error("Error monitoring device list: %s: %s", error.name, error.message); + goto fail; } -#endif - libhal_ctx_set_user_data(hal_ctx, u); - libhal_ctx_set_device_added(hal_ctx, device_added_cb); - libhal_ctx_set_device_removed(hal_ctx, device_removed_cb); - libhal_ctx_set_device_new_capability(hal_ctx, new_capability_cb); - libhal_ctx_set_device_lost_capability(hal_ctx, lost_capability_cb); - /*libhal_ctx_set_device_property_modified(hal_ctx, property_modified_cb);*/ + if (!dbus_connection_add_filter(pa_dbus_connection_get(conn), filter_cb, u, NULL)) { + pa_log_error("Failed to add filter function"); + goto fail; + } - dbus_error_init(&error); - if (!libhal_device_property_watch_all(hal_ctx, &error)) { - pa_log_error("error monitoring device list: %s: %s", - error.name, error.message); - dbus_error_free(&error); - userdata_free(u); - return -1; + dbus_bus_add_match(pa_dbus_connection_get(conn), "type='signal',sender='org.freedesktop.Hal', interface='org.freedesktop.Hal.Device.AccessControl'", &error); + if (dbus_error_is_set(&error)) { + pa_log_error("Unable to subscribe to HAL ACL signals: %s: %s", error.name, error.message); + goto fail; + } + + dbus_bus_add_match(pa_dbus_connection_get(conn), "type='signal',interface='org.pulseaudio.Server'", &error); + if (dbus_error_is_set(&error)) { + pa_log_error("Unable to subscribe to PulseAudio signals: %s: %s", error.name, error.message); + goto fail; } - pa_log_info("loaded %i modules.", n); + pa_log_info("Loaded %i modules.", n); + + pa_modargs_free(ma); return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + dbus_error_free(&error); + pa__done(m); + + return -1; } -void pa__done(PA_GCC_UNUSED pa_core *c, pa_module *m) { - assert (c && m); +void pa__done(pa_module *m) { + struct userdata *u; + + pa_assert(m); + + if (!(u = m->userdata)) + return; + + if (u->context) + hal_context_free(u->context); - /* free the user data */ - userdata_free(m->userdata); + if (u->devices) + pa_hashmap_free(u->devices, hal_device_free_cb, NULL); + + if (u->connection) + pa_dbus_connection_unref(u->connection); + + pa_xfree(u); } diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index a40ebe29..5019d656 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -3,7 +3,7 @@ /*** This file is part of PulseAudio. - Copyright 2006, 2007 Lennart Poettering and Tanu Kaskinen + Copyright 2006 Lennart Poettering PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published @@ -25,858 +25,431 @@ #include #endif -#include +#include +#include +#include #include #include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include #include +#include #include #include -#include -#include #include -#include -#include #include -#include +#include +#include +#include +#include +#include #include "module-jack-sink-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering & Tanu Kaskinen") -PA_MODULE_DESCRIPTION("Jack Sink") +/* General overview: + * + * Because JACK has a very unflexible event loop management, which + * doesn't allow us to add our own event sources to the event thread + * we cannot use the JACK real-time thread for dispatching our PA + * work. Instead, we run an additional RT thread which does most of + * the PA handling, and have the JACK RT thread request data from it + * via pa_asyncmsgq. The cost is an additional context switch which + * should hopefully not be that expensive if RT scheduling is + * enabled. A better fix would only be possible with additional event + * source support in JACK. + */ + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("JACK Sink") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE( "sink_name= " "server_name= " "client_name= " "channels= " - "connect= " - "buffersize= " + "connect= " "channel_map=") #define DEFAULT_SINK_NAME "jack_out" -#define DEFAULT_CLIENT_NAME "PulseAudio(output)" -#define DEFAULT_RINGBUFFER_SIZE 4096 - struct userdata { + pa_core *core; + pa_module *module; pa_sink *sink; unsigned channels; - unsigned frame_size; - jack_port_t* j_ports[PA_CHANNELS_MAX]; - jack_client_t *j_client; + jack_port_t* port[PA_CHANNELS_MAX]; + jack_client_t *client; - jack_nframes_t j_buffersize; + void *buffer[PA_CHANNELS_MAX]; - /* For avoiding j_buffersize changes at a wrong moment. */ - pthread_mutex_t buffersize_mutex; + pa_thread_mq thread_mq; + pa_asyncmsgq *jack_msgq; + pa_rtpoll *rtpoll; + pa_rtpoll_item *rtpoll_item; - /* The intermediate store where the pulse side writes to and the jack side - reads from. */ - jack_ringbuffer_t* ringbuffer; - - /* For signaling when there's room in the ringbuffer. */ - pthread_mutex_t cond_mutex; - pthread_cond_t ringbuffer_cond; + pa_thread *thread; - pthread_t filler_thread; /* Keeps the ringbuffer filled. */ + jack_nframes_t frames_in_buffer; + jack_nframes_t saved_frame_time; + pa_bool_t saved_frame_time_valid; +}; - int ringbuffer_is_full; - int filler_thread_is_running; - int quit_requested; +static const char* const valid_modargs[] = { + "sink_name", + "server_name", + "client_name", + "channels", + "connect", + "channel_map", + NULL +}; - int pipe_fd_type; - int pipe_fds[2]; - pa_io_event *io_event; +enum { + SINK_MESSAGE_RENDER = PA_SINK_MESSAGE_MAX, + SINK_MESSAGE_ON_SHUTDOWN }; +static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *memchunk) { + struct userdata *u = PA_SINK(o)->userdata; -struct options { - char* sink_name; - int sink_name_given; + switch (code) { - char* server_name; /* May be NULL */ - int server_name_given; + case SINK_MESSAGE_RENDER: - char* client_name; - int client_name_given; + /* Handle the request from the JACK thread */ - unsigned channels; - int channels_given; + if (u->sink->thread_info.state == PA_SINK_RUNNING) { + pa_memchunk chunk; + size_t nbytes; + void *p; - int connect; - int connect_given; + pa_assert(offset > 0); + nbytes = offset * pa_frame_size(&u->sink->sample_spec); - unsigned buffersize; - int buffersize_given; + pa_sink_render_full(u->sink, nbytes, &chunk); - pa_channel_map map; - int map_given; -}; + p = (uint8_t*) pa_memblock_acquire(chunk.memblock) + chunk.index; + pa_deinterleave(p, u->buffer, u->channels, sizeof(float), offset); + pa_memblock_release(chunk.memblock); + pa_memblock_unref(chunk.memblock); + } else { + unsigned c; + pa_sample_spec ss; -static const char* const valid_modargs[] = { - "sink_name", - "server_name", - "client_name", - "channels", - "connect", - "buffersize", - "channel_map", - NULL -}; + /* Humm, we're not RUNNING, hence let's write some silence */ + ss = u->sink->sample_spec; + ss.channels = 1; -/* Initialization functions. */ -static int parse_options(struct options* o, const char* argument); -static void set_default_channels(pa_module* self, struct options* o); -static int create_sink(pa_module* self, struct options *o); -static void connect_ports(pa_module* self); -static int start_filling_ringbuffer(pa_module* self); + for (c = 0; c < u->channels; c++) + pa_silence_memory(u->buffer[c], offset * pa_sample_size(&ss), &ss); + } -/* Various callbacks. */ -static void jack_error_func(const char* t); -static pa_usec_t sink_get_latency_cb(pa_sink* s); -static int jack_process(jack_nframes_t nframes, void* arg); -static int jack_blocksize_cb(jack_nframes_t nframes, void* arg); -static void jack_shutdown(void* arg); -static void io_event_cb(pa_mainloop_api* m, pa_io_event* e, int fd, - pa_io_event_flags_t flags, void* userdata); + u->frames_in_buffer = offset; + u->saved_frame_time = * (jack_nframes_t*) data; + u->saved_frame_time_valid = TRUE; -/* The ringbuffer filler thread runs in this function. */ -static void* fill_ringbuffer(void* arg); + return 0; -/* request_render asks asynchronously the mainloop to call io_event_cb. */ -static void request_render(struct userdata* u); + case SINK_MESSAGE_ON_SHUTDOWN: + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + return 0; + case PA_SINK_MESSAGE_GET_LATENCY: { + jack_nframes_t l, ft, d; + size_t n; -int pa__init(pa_core* c, pa_module* self) { - struct userdata* u = NULL; - struct options o; - unsigned i; - - assert(c); - assert(self); - - o.sink_name = NULL; - o.server_name = NULL; - o.client_name = NULL; - - self->userdata = pa_xnew0(struct userdata, 1); - u = self->userdata; - - u->pipe_fds[0] = u->pipe_fds[1] = -1; - u->pipe_fd_type = 0; - u->ringbuffer_is_full = 0; - u->filler_thread_is_running = 0; - u->quit_requested = 0; - pthread_mutex_init(&u->buffersize_mutex, NULL); - pthread_mutex_init(&u->cond_mutex, NULL); - pthread_cond_init(&u->ringbuffer_cond, NULL); - - if (parse_options(&o, self->argument) != 0) - goto fail; - - jack_set_error_function(jack_error_func); - - if (!(u->j_client = jack_client_open( - o.client_name, - o.server_name ? JackServerName : JackNullOption, - NULL, o.server_name))) { - pa_log_error("jack_client_open() failed."); - goto fail; - } - pa_log_info("Successfully connected as '%s'", - jack_get_client_name(u->j_client)); - - if (!o.channels_given) - set_default_channels(self, &o); - - u->channels = o.channels; - - if (!o.map_given) - pa_channel_map_init_auto(&o.map, u->channels, PA_CHANNEL_MAP_ALSA); - - for (i = 0; i < u->channels; i++) { - char* port_name = pa_sprintf_malloc( - "out_%i:%s", i+1, - pa_channel_position_to_string(o.map.map[i])); - - if (!(u->j_ports[i] = jack_port_register( - u->j_client, port_name, - JACK_DEFAULT_AUDIO_TYPE, - JackPortIsOutput|JackPortIsTerminal, 0))) { - pa_log("jack_port_register() failed."); - goto fail; + /* This is the "worst-case" latency */ + l = jack_port_get_total_latency(u->client, u->port[0]) + u->frames_in_buffer; + + if (u->saved_frame_time_valid) { + /* Adjust the worst case latency by the time that + * passed since we last handed data to JACK */ + + ft = jack_frame_time(u->client); + d = ft > u->saved_frame_time ? ft - u->saved_frame_time : 0; + l = l > d ? l - d : 0; + } + + /* Convert it to usec */ + n = l * pa_frame_size(&u->sink->sample_spec); + *((pa_usec_t*) data) = pa_bytes_to_usec(n, &u->sink->sample_spec); + + return 0; } - - pa_xfree(port_name); } - - if (pipe(u->pipe_fds) < 0) { - pa_log("pipe() failed: %s", pa_cstrerror(errno)); - goto fail; - } - pa_make_nonblock_fd(u->pipe_fds[1]); - - if (create_sink(self, &o) != 0) - goto fail; - u->frame_size = pa_frame_size(&u->sink->sample_spec); - u->j_buffersize = jack_get_buffer_size(u->j_client); - - /* If the ringbuffer size were equal to the jack buffer size, a full block - would never fit in the ringbuffer, because the ringbuffer can never be - totally full: one slot is always wasted. */ - if (o.buffersize <= u->j_buffersize) { - o.buffersize = u->j_buffersize + 1; - } - /* The actual ringbuffer size will be rounded up to the nearest power of - two. */ - if (!(u->ringbuffer = jack_ringbuffer_create( - o.buffersize * u->frame_size))) { - pa_log("jack_ringbuffer_create() failed."); - goto fail; - } - assert((u->ringbuffer->size % sizeof(float)) == 0); - pa_log_info("buffersize is %u frames (%u samples, %u bytes).", - u->ringbuffer->size / u->frame_size, - u->ringbuffer->size / sizeof(float), - u->ringbuffer->size); - - jack_set_process_callback(u->j_client, jack_process, u); - jack_set_buffer_size_callback(u->j_client, jack_blocksize_cb, u); - jack_on_shutdown(u->j_client, jack_shutdown, u); - - if (jack_activate(u->j_client)) { - pa_log("jack_activate() failed."); - goto fail; - } + return pa_sink_process_msg(o, code, data, offset, memchunk); +} - if (o.connect) - connect_ports(self); +static int jack_process(jack_nframes_t nframes, void *arg) { + struct userdata *u = arg; + unsigned c; + jack_nframes_t frame_time; + pa_assert(u); - u->io_event = c->mainloop->io_new(c->mainloop, u->pipe_fds[0], - PA_IO_EVENT_INPUT, io_event_cb, self); - - if (start_filling_ringbuffer(self) != 0) - goto fail; + /* We just forward the request to our other RT thread */ - pa_xfree(o.sink_name); - pa_xfree(o.server_name); - pa_xfree(o.client_name); - - return 0; + for (c = 0; c < u->channels; c++) + pa_assert_se(u->buffer[c] = jack_port_get_buffer(u->port[c], nframes)); -fail: - pa_xfree(o.sink_name); - pa_xfree(o.server_name); - pa_xfree(o.client_name); - pa__done(c, self); + frame_time = jack_frame_time(u->client); - return -1; + pa_assert_se(pa_asyncmsgq_send(u->jack_msgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_RENDER, &frame_time, nframes, NULL) == 0); + return 0; } +static void thread_func(void *userdata) { + struct userdata *u = userdata; -static int parse_options(struct options* o, const char* argument) { - pa_modargs *ma = NULL; - const char* arg_val; - pa_strbuf* strbuf; - - assert(o); + pa_assert(u); - if (!(ma = pa_modargs_new(argument, valid_modargs))) { - pa_log_error("Failed to parse module arguments."); - goto fail; - } + pa_log_debug("Thread starting up"); - strbuf = pa_strbuf_new(); - if ((arg_val = pa_modargs_get_value(ma, "sink_name", NULL))) { - pa_strbuf_puts(strbuf, arg_val); - o->sink_name = pa_strbuf_tostring(strbuf); - o->sink_name_given = 1; - } else { - pa_strbuf_puts(strbuf, DEFAULT_SINK_NAME); - o->sink_name = pa_strbuf_tostring(strbuf); - o->sink_name_given = 0; - } - pa_strbuf_free(strbuf); - - strbuf = pa_strbuf_new(); - if ((arg_val = pa_modargs_get_value(ma, "server_name", NULL))) { - pa_strbuf_puts(strbuf, arg_val); - o->server_name = pa_strbuf_tostring(strbuf); - o->server_name_given = 1; - } else { - o->server_name = NULL; - o->server_name_given = 0; - } - pa_strbuf_free(strbuf); - - strbuf = pa_strbuf_new(); - if ((arg_val = pa_modargs_get_value(ma, "client_name", NULL))) { - pa_strbuf_puts(strbuf, arg_val); - o->client_name = pa_strbuf_tostring(strbuf); - o->client_name_given = 1; - } else { - pa_strbuf_puts(strbuf, DEFAULT_CLIENT_NAME); - o->client_name = pa_strbuf_tostring(strbuf); - o->client_name_given = 1; - } - pa_strbuf_free(strbuf); - - if (pa_modargs_get_value(ma, "channels", NULL)) { - o->channels_given = 1; - if (pa_modargs_get_value_u32(ma, "channels", &o->channels) < 0 || - o->channels == 0 || - o->channels >= PA_CHANNELS_MAX) { - pa_log_error("Failed to parse the \"channels\" argument."); - goto fail; - } - } else { - o->channels = 0; /* The actual default value is the number of physical - input ports in jack (unknown at the moment), or if - that's zero, then the default_sample_spec.channels - of the core. */ - o->channels_given = 0; - } + if (u->core->high_priority) + pa_make_realtime(); - if (pa_modargs_get_value(ma, "connect", NULL)) { - o->connect_given = 1; - if (pa_modargs_get_value_boolean(ma, "connect", &o->connect) < 0) { - pa_log_error("Failed to parse the \"connect\" argument."); - goto fail; - } - } else { - o->connect = 1; - o->connect_given = 0; - } + pa_thread_mq_install(&u->thread_mq); + pa_rtpoll_install(u->rtpoll); - if (pa_modargs_get_value(ma, "buffersize", NULL)) { - o->buffersize_given = 1; - if (pa_modargs_get_value_u32(ma, "buffersize", &o->buffersize) < 0) { - pa_log_error("Failed to parse the \"buffersize\" argument."); - goto fail; - } - } else { - o->buffersize = DEFAULT_RINGBUFFER_SIZE; - o->buffersize_given = 0; - } + for (;;) { + int ret; - if (pa_modargs_get_value(ma, "channel_map", NULL)) { - o->map_given = 1; - if (pa_modargs_get_channel_map(ma, &o->map) < 0) { - pa_log_error("Failed to parse the \"channel_map\" argument."); + if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0) goto fail; - } - /* channel_map specifies the channel count too. */ - if (o->channels_given && (o->channels != o->map.channels)) { - pa_log_error( - "\"channels\" and \"channel_map\" arguments conficted. If you " - "use the \"channel_map\" argument, you can omit the " - "\"channels\" argument."); - goto fail; - } else { - o->channels = o->map.channels; - o->channels_given = 1; - } - } else { - /* The actual default value is the default alsa mappings, but that - can't be set until the channel count is known. Here we initialize - the map to some valid value, although the value won't be used. */ - pa_channel_map_init_stereo(&o->map); - o->map_given = 0; + if (ret == 0) + goto finish; } - pa_modargs_free(ma); - - return 0; - fail: - if (ma) - pa_modargs_free(ma); + /* If this was no regular exit from the loop we have to continue + * processing messages until we received PA_MESSAGE_SHUTDOWN */ + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); - return -1; +finish: + pa_log_debug("Thread shutting down"); } +static void jack_error_func(const char*t) { + char *s; -static void set_default_channels(pa_module* self, struct options* o) { - struct userdata* u; - const char **ports, **p; - - assert(self); - assert(o); - assert(self->userdata); - - u = self->userdata; - - assert(u->j_client); - assert(self->core); - - o->channels = 0; - - ports = jack_get_ports(u->j_client, NULL, JACK_DEFAULT_AUDIO_TYPE, - JackPortIsPhysical|JackPortIsInput); - - for (p = ports; *p; p++) - o->channels++; - - free(ports); - - if (o->channels >= PA_CHANNELS_MAX) - o->channels = PA_CHANNELS_MAX - 1; - - if (o->channels == 0) - o->channels = self->core->default_sample_spec.channels; + s = pa_xstrndup(t, strcspn(t, "\n\r")); + pa_log_warn("JACK error >%s<", s); + pa_xfree(s); } +static void jack_init(void *arg) { + struct userdata *u = arg; -static int create_sink(pa_module* self, struct options* o) { - struct userdata* u; - pa_sample_spec ss; - char *t; - - assert(self); - assert(o); - assert(self->userdata); - - u = self->userdata; - - assert(u->j_client); - - ss.channels = u->channels; - ss.rate = jack_get_sample_rate(u->j_client); - ss.format = PA_SAMPLE_FLOAT32NE; - assert(pa_sample_spec_valid(&ss)); + pa_log_info("JACK thread starting up."); - if (!(u->sink = pa_sink_new(self->core, __FILE__, o->sink_name, 0, &ss, - &o->map))) { - pa_log("failed to create sink."); - return -1; - } - - u->sink->userdata = u; - pa_sink_set_owner(u->sink, self); - - pa_sink_set_description( - u->sink, - t = pa_sprintf_malloc("Jack sink (%s)", - jack_get_client_name(u->j_client))); - pa_xfree(t); - - u->sink->get_latency = sink_get_latency_cb; - - return 0; + if (u->core->high_priority) + pa_make_realtime(); } +static void jack_shutdown(void* arg) { + struct userdata *u = arg; -static void connect_ports(pa_module* self) { - struct userdata* u; - unsigned i; - const char **ports, **p; - - assert(self); - assert(self->userdata); - - u = self->userdata; - - assert(u->j_client); - - ports = jack_get_ports(u->j_client, NULL, JACK_DEFAULT_AUDIO_TYPE, - JackPortIsPhysical|JackPortIsInput); - - for (i = 0, p = ports; i < u->channels; i++, p++) { - assert(u->j_ports[i]); - - if (!*p) { - pa_log("Not enough physical output ports, leaving unconnected."); - break; - } - - pa_log_info("connecting %s to %s", - jack_port_name(u->j_ports[i]), *p); - - if (jack_connect(u->j_client, jack_port_name(u->j_ports[i]), *p)) { - pa_log("Failed to connect %s to %s, leaving unconnected.", - jack_port_name(u->j_ports[i]), *p); - break; - } - } - - free(ports); + pa_log_info("JACK thread shutting down.."); + pa_asyncmsgq_post(u->jack_msgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_ON_SHUTDOWN, NULL, 0, NULL, NULL); } +int pa__init(pa_module*m) { + struct userdata *u = NULL; + pa_sample_spec ss; + pa_channel_map map; + pa_modargs *ma = NULL; + jack_status_t status; + const char *server_name, *client_name; + uint32_t channels = 0; + int do_connect = 1; + unsigned i; + const char **ports = NULL, **p; + char *t; -static int start_filling_ringbuffer(pa_module* self) { - struct userdata* u; - pthread_attr_t thread_attributes; + pa_assert(m); - assert(self); - assert(self->userdata); + jack_set_error_function(jack_error_func); - u = self->userdata; - - pthread_attr_init(&thread_attributes); - - if (pthread_attr_setinheritsched(&thread_attributes, - PTHREAD_INHERIT_SCHED) != 0) { - pa_log("pthread_attr_setinheritsched() failed."); + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log("Failed to parse module arguments."); goto fail; } - else if (pthread_create(&u->filler_thread, &thread_attributes, - fill_ringbuffer, u) != 0) { - pa_log("pthread_create() failed."); + + if (pa_modargs_get_value_boolean(ma, "connect", &do_connect) < 0) { + pa_log("Failed to parse connect= argument."); goto fail; } - - u->filler_thread_is_running = 1; - - pthread_attr_destroy(&thread_attributes); - - return 0; - -fail: - pthread_attr_destroy(&thread_attributes); - return -1; -} + server_name = pa_modargs_get_value(ma, "server_name", NULL); + client_name = pa_modargs_get_value(ma, "client_name", "PulseAudio JACK Sink"); + + u = pa_xnew0(struct userdata, 1); + u->core = m->core; + u->module = m; + m->userdata = u; + u->saved_frame_time_valid = FALSE; + pa_thread_mq_init(&u->thread_mq, m->core->mainloop); + u->rtpoll = pa_rtpoll_new(); + pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq); + + /* The queue linking the JACK thread and our RT thread */ + u->jack_msgq = pa_asyncmsgq_new(0); + + /* The msgq from the JACK RT thread should have an even higher + * priority than the normal message queues, to match the guarantee + * all other drivers make: supplying the audio device with data is + * the top priority -- and as long as that is possible we don't do + * anything else */ + u->rtpoll_item = pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY-1, u->jack_msgq); + + if (!(u->client = jack_client_open(client_name, server_name ? JackServerName : JackNullOption, &status, server_name))) { + pa_log("jack_client_open() failed."); + goto fail; + } -static void jack_error_func(const char* t) { - pa_log_warn("JACK error >%s<", t); -} - + ports = jack_get_ports(u->client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); -static pa_usec_t sink_get_latency_cb(pa_sink* s) { - /* The latency is approximately the sum of the first port's latency, - buffersize of jack and the ringbuffer size. Maybe instead of using just - the first port, the max of all ports' latencies should be used? */ - struct userdata* u; - jack_nframes_t l; - - assert(s); - assert(s->userdata); - - u = s->userdata; - - l = jack_port_get_total_latency(u->j_client, u->j_ports[0]) + - u->j_buffersize + u->ringbuffer->size / u->frame_size; - - return pa_bytes_to_usec(l * u->frame_size, &s->sample_spec); -} + channels = 0; + for (p = ports; *p; p++) + channels++; + if (!channels) + channels = m->core->default_sample_spec.channels; -static int jack_process(jack_nframes_t nframes, void* arg) { - struct userdata* u = arg; - float* j_buffers[PA_CHANNELS_MAX]; - unsigned nsamples = u->channels * nframes; - unsigned sample_idx_part1, sample_idx_part2; - jack_nframes_t frame_idx; - jack_ringbuffer_data_t data[2]; /* In case the readable area in the - ringbuffer is non-continuous, the data - will be split in two parts. */ - unsigned chan; - unsigned samples_left_over; - - for (chan = 0; chan < u->channels; chan++) { - j_buffers[chan] = jack_port_get_buffer(u->j_ports[chan], nframes); - } - - jack_ringbuffer_get_read_vector(u->ringbuffer, data); - - /* We assume that the possible discontinuity doesn't happen in the middle - * of a sample. Should be a safe assumption. */ - assert(((data[0].len % sizeof(float)) == 0) || - (data[1].len == 0)); - - /* Copy from the first part of data until enough samples are copied or the - first part ends. */ - sample_idx_part1 = 0; - chan = 0; - frame_idx = 0; - while (sample_idx_part1 < nsamples && - ((sample_idx_part1 + 1) * sizeof(float)) <= data[0].len) { - float *s = ((float*) data[0].buf) + sample_idx_part1; - float *d = j_buffers[chan] + frame_idx; - *d = *s; - - sample_idx_part1++; - chan = (chan + 1) % u->channels; - frame_idx = sample_idx_part1 / u->channels; - } - - samples_left_over = nsamples - sample_idx_part1; - - /* Copy from the second part of data until enough samples are copied or the - second part ends. */ - sample_idx_part2 = 0; - while (sample_idx_part2 < samples_left_over && - ((sample_idx_part2 + 1) * sizeof(float)) <= data[1].len) { - float *s = ((float*) data[1].buf) + sample_idx_part2; - float *d = j_buffers[chan] + frame_idx; - *d = *s; - - sample_idx_part2++; - chan = (chan + 1) % u->channels; - frame_idx = (sample_idx_part1 + sample_idx_part2) / u->channels; + if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0 || channels <= 0 || channels >= PA_CHANNELS_MAX) { + pa_log("Failed to parse channels= argument."); + goto fail; } - - samples_left_over -= sample_idx_part2; - - /* If there's still samples left, fill the buffers with zeros. */ - while (samples_left_over > 0) { - float *d = j_buffers[chan] + frame_idx; - *d = 0.0; - - samples_left_over--; - chan = (chan + 1) % u->channels; - frame_idx = (nsamples - samples_left_over) / u->channels; + + pa_channel_map_init_auto(&map, channels, PA_CHANNEL_MAP_ALSA); + if (pa_modargs_get_channel_map(ma, NULL, &map) < 0 || map.channels != channels) { + pa_log("Failed to parse channel_map= argument."); + goto fail; } - - jack_ringbuffer_read_advance( - u->ringbuffer, (sample_idx_part1 + sample_idx_part2) * sizeof(float)); - - /* Tell the rendering part that there is room in the ringbuffer. */ - u->ringbuffer_is_full = 0; - pthread_cond_signal(&u->ringbuffer_cond); - - return 0; -} + pa_log_info("Successfully connected as '%s'", jack_get_client_name(u->client)); + + ss.channels = u->channels = channels; + ss.rate = jack_get_sample_rate(u->client); + ss.format = PA_SAMPLE_FLOAT32NE; -static int jack_blocksize_cb(jack_nframes_t nframes, void* arg) { - /* This gets called in the processing thread, so do we have to be realtime - safe? No, we can do whatever we want. User gets silence while we do it. - - In addition to just updating the j_buffersize field in userdata, we have - to create a new ringbuffer, if the new buffer size is bigger or equal to - the old ringbuffer size. */ - struct userdata* u = arg; - - assert(u); - - /* We don't want to change the blocksize and the ringbuffer while rendering - is going on. */ - pthread_mutex_lock(&u->buffersize_mutex); - - u->j_buffersize = nframes; - - if ((u->ringbuffer->size / u->frame_size) <= nframes) { - /* We have to create a new ringbuffer. What are we going to do with the - old data in the old buffer? We throw it away, because we're lazy - coders. The listening experience is likely to get ruined anyway - during the blocksize change. */ - jack_ringbuffer_free(u->ringbuffer); - - /* The actual ringbuffer size will be rounded up to the nearest power - of two. */ - if (!(u->ringbuffer = - jack_ringbuffer_create((nframes + 1) * u->frame_size))) { - pa_log_error( - "jack_ringbuffer_create() failed while changing jack's buffer " - "size, module exiting."); - jack_client_close(u->j_client); - u->quit_requested = 1; + pa_assert(pa_sample_spec_valid(&ss)); + + for (i = 0; i < ss.channels; i++) { + if (!(u->port[i] = jack_port_register(u->client, pa_channel_position_to_string(map.map[i]), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput|JackPortIsTerminal, 0))) { + pa_log("jack_port_register() failed."); + goto fail; } - assert((u->ringbuffer->size % sizeof(float)) == 0); - pa_log_info("buffersize is %u frames (%u samples, %u bytes).", - u->ringbuffer->size / u->frame_size, - u->ringbuffer->size / sizeof(float), - u->ringbuffer->size); } - - pthread_mutex_unlock(&u->buffersize_mutex); - - return 0; -} + if (!(u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { + pa_log("failed to create sink."); + goto fail; + } -static void jack_shutdown(void* arg) { - struct userdata* u = arg; - assert(u); + u->sink->parent.process_msg = sink_process_msg; + u->sink->userdata = u; + u->sink->flags = PA_SINK_LATENCY; - u->quit_requested = 1; - request_render(u); -} + pa_sink_set_module(u->sink, m); + pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); + pa_sink_set_rtpoll(u->sink, u->rtpoll); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Jack sink (%s)", jack_get_client_name(u->client))); + pa_xfree(t); + jack_set_process_callback(u->client, jack_process, u); + jack_on_shutdown(u->client, jack_shutdown, u); + jack_set_thread_init_callback(u->client, jack_init, u); -static void io_event_cb(pa_mainloop_api* m, pa_io_event* e, int fd, - pa_io_event_flags_t flags, void* userdata) { - pa_module* self = userdata; - struct userdata* u; - char x; - jack_ringbuffer_data_t buffer[2]; /* The write area in the ringbuffer may - be split in two parts. */ - pa_memchunk chunk; /* This is the data source. */ - unsigned part1_length, part2_length; - unsigned sample_idx_part1, sample_idx_part2; - unsigned chan; - unsigned frame_size; - int rem; - - assert(m); - assert(e); - assert(flags == PA_IO_EVENT_INPUT); - assert(self); - assert(self->userdata); - - u = self->userdata; - - assert(u->pipe_fds[0] == fd); - - pa_read(fd, &x, 1, &u->pipe_fd_type); - - if (u->quit_requested) { - pa_module_unload_request(self); - return; + if (!(u->thread = pa_thread_new(thread_func, u))) { + pa_log("Failed to create thread."); + goto fail; } - frame_size = u->frame_size; - - /* No blocksize changes during rendering, please. */ - pthread_mutex_lock(&u->buffersize_mutex); - - jack_ringbuffer_get_write_vector(u->ringbuffer, buffer); - assert(((buffer[0].len % sizeof(float)) == 0) || (buffer[1].len == 0)); - - part1_length = buffer[0].len / sizeof(float); - part2_length = buffer[1].len / sizeof(float); - - /* If the amount of free space is not a multiple of the frame size, we have - to truncate the lengths so that we process only complete frames. */ - if ((rem = (part1_length + part2_length) % u->channels) != 0) { - if (part2_length >= rem) { - part2_length -= rem; - } else { - part1_length -= rem - part2_length; - part2_length = 0; - } + if (jack_activate(u->client)) { + pa_log("jack_activate() failed"); + goto fail; } - - /* pa_sink_render_full doesn't accept zero length, so we have do the - copying only if there's data to copy, which actually makes a kind of - sense. */ - if (part1_length > 0 || part2_length > 0) { - pa_sink_render_full(u->sink, - (part1_length + part2_length) * sizeof(float), - &chunk); - - /* Write to the first part of the buffer. */ - for (sample_idx_part1 = 0; - sample_idx_part1 < part1_length; - sample_idx_part1++) { - float *s = - ((float*) ((uint8_t*) chunk.memblock->data + chunk.index)) + - sample_idx_part1; - float *d = ((float*) buffer[0].buf) + sample_idx_part1; - *d = *s; - } - - /* Write to the second part of the buffer. */ - for (sample_idx_part2 = 0; - sample_idx_part2 < part2_length; - sample_idx_part2++) { - float *s = - ((float*) ((uint8_t*) chunk.memblock->data + chunk.index)) + - sample_idx_part1 + sample_idx_part2; - float *d = ((float*) buffer[1].buf) + sample_idx_part2; - *d = *s; + + if (do_connect) { + for (i = 0, p = ports; i < ss.channels; i++, p++) { + + if (!*p) { + pa_log("Not enough physical output ports, leaving unconnected."); + break; + } + + pa_log_info("Connecting %s to %s", jack_port_name(u->port[i]), *p); + + if (jack_connect(u->client, jack_port_name(u->port[i]), *p)) { + pa_log("Failed to connect %s to %s, leaving unconnected.", jack_port_name(u->port[i]), *p); + break; + } } - - pa_memblock_unref(chunk.memblock); - - jack_ringbuffer_write_advance( - u->ringbuffer, (part1_length + part2_length) * sizeof(float)); } - - /* Blocksize can be changed again. */ - pthread_mutex_unlock(&u->buffersize_mutex); -} + pa_sink_put(u->sink); -static void* fill_ringbuffer(void* arg) { - struct userdata* u = arg; - - assert(u); - - while (!u->quit_requested) { - if (u->ringbuffer_is_full) { - pthread_mutex_lock(&u->cond_mutex); - pthread_cond_wait(&u->ringbuffer_cond, - &u->cond_mutex); - pthread_mutex_unlock(&u->cond_mutex); - } - /* No, it's not full yet, but this must be set to one as soon as - possible, because if the jack thread manages to process another - block before we set this to one, we may end up waiting without - a reason. */ - u->ringbuffer_is_full = 1; + free(ports); + pa_modargs_free(ma); - request_render(u); - } - - return NULL; -} + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + free(ports); + pa__done(m); -static void request_render(struct userdata* u) { - char c = 'x'; - - assert(u); - - assert(u->pipe_fds[1] >= 0); - pa_write(u->pipe_fds[1], &c, 1, &u->pipe_fd_type); + return -1; } -void pa__done(pa_core* c, pa_module* self) { - struct userdata* u; - - assert(c); - assert(self); +void pa__done(pa_module*m) { + struct userdata *u; + + pa_assert(m); - if (!self->userdata) + if (!(u = m->userdata)) return; - u = self->userdata; - - if (u->filler_thread_is_running) { - u->quit_requested = 1; - pthread_cond_signal(&u->ringbuffer_cond); - pthread_join(u->filler_thread, NULL); + if (u->client) + jack_client_close(u->client); + + if (u->sink) + pa_sink_unlink(u->sink); + + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); } - - if (u->j_client) - jack_client_close(u->j_client); - if (u->io_event) - c->mainloop->io_free(u->io_event); + pa_thread_mq_done(&u->thread_mq); - if (u->sink) { - pa_sink_disconnect(u->sink); + if (u->sink) pa_sink_unref(u->sink); - } - - if (u->ringbuffer) - jack_ringbuffer_free(u->ringbuffer); - - if (u->pipe_fds[0] >= 0) - pa_close(u->pipe_fds[0]); - if (u->pipe_fds[1] >= 0) - pa_close(u->pipe_fds[1]); - - pthread_mutex_destroy(&u->buffersize_mutex); - pthread_cond_destroy(&u->ringbuffer_cond); - pthread_mutex_destroy(&u->cond_mutex); - pa_xfree(self->userdata); - self->userdata = NULL; + + if (u->rtpoll_item) + pa_rtpoll_item_free(u->rtpoll_item); + + if (u->jack_msgq) + pa_asyncmsgq_unref(u->jack_msgq); + + if (u->rtpoll) + pa_rtpoll_free(u->rtpoll); + + pa_xfree(u); } diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index 8ca24035..b62ebe7a 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -28,31 +28,34 @@ #include #include #include -#include #include #include #include #include #include -#include #include #include #include -#include #include #include #include #include #include -#include +#include +#include +#include +#include #include "module-jack-source-symdef.h" +/* See module-jack-sink for a few comments how this module basically + * works */ + PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Jack Source") +PA_MODULE_DESCRIPTION("JACK Source") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE( "source_name= " @@ -67,7 +70,6 @@ PA_MODULE_USAGE( struct userdata { pa_core *core; pa_module *module; - pa_source *source; unsigned channels; @@ -75,19 +77,15 @@ struct userdata { jack_port_t* port[PA_CHANNELS_MAX]; jack_client_t *client; - pthread_mutex_t mutex; - pthread_cond_t cond; + pa_thread_mq thread_mq; + pa_asyncmsgq *jack_msgq; + pa_rtpoll *rtpoll; + pa_rtpoll_item *rtpoll_item; - void * buffer[PA_CHANNELS_MAX]; - jack_nframes_t frames_posted; - int quit_requested; + pa_thread *thread; - int pipe_fds[2]; - int pipe_fd_type; - pa_io_event *io_event; - - jack_nframes_t frames_in_buffer; - jack_nframes_t timestamp; + jack_nframes_t saved_frame_time; + pa_bool_t saved_frame_time_valid; }; static const char* const valid_modargs[] = { @@ -100,141 +98,150 @@ static const char* const valid_modargs[] = { NULL }; -static void stop_source(struct userdata *u) { - assert (u); - - jack_client_close(u->client); - u->client = NULL; - u->core->mainloop->io_free(u->io_event); - u->io_event = NULL; - pa_source_disconnect(u->source); - pa_source_unref(u->source); - u->source = NULL; - pa_module_unload_request(u->module); -} +enum { + SOURCE_MESSAGE_POST = PA_SOURCE_MESSAGE_MAX, + SOURCE_MESSAGE_ON_SHUTDOWN +}; -static void io_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) { - struct userdata *u = userdata; - char x; +static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SOURCE(o)->userdata; - assert(m); - assert(flags == PA_IO_EVENT_INPUT); - assert(u); - assert(u->pipe_fds[0] == fd); + switch (code) { - pa_read(fd, &x, 1, &u->pipe_fd_type); + case SOURCE_MESSAGE_POST: - if (u->quit_requested) { - stop_source(u); - u->quit_requested = 0; - return; - } + /* Handle the new block from the JACK thread */ + pa_assert(chunk); + pa_assert(chunk->length > 0); - pthread_mutex_lock(&u->mutex); + if (u->source->thread_info.state == PA_SOURCE_RUNNING) + pa_source_post(u->source, chunk); - if (u->frames_posted > 0) { - unsigned fs; - jack_nframes_t frame_idx; - pa_memchunk chunk; + u->saved_frame_time = offset; + u->saved_frame_time_valid = TRUE; - fs = pa_frame_size(&u->source->sample_spec); + return 0; - chunk.memblock = pa_memblock_new(u->core->mempool, chunk.length = u->frames_posted * fs); - chunk.index = 0; + case SOURCE_MESSAGE_ON_SHUTDOWN: + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + return 0; - for (frame_idx = 0; frame_idx < u->frames_posted; frame_idx ++) { - unsigned c; + case PA_SOURCE_MESSAGE_GET_LATENCY: { + jack_nframes_t l, ft, d; + size_t n; - for (c = 0; c < u->channels; c++) { - float *s = ((float*) u->buffer[c]) + frame_idx; - float *d = ((float*) ((uint8_t*) chunk.memblock->data + chunk.index)) + (frame_idx * u->channels) + c; + /* This is the "worst-case" latency */ + l = jack_port_get_total_latency(u->client, u->port[0]); - *d = *s; - } - } + if (u->saved_frame_time_valid) { + /* Adjust the worst case latency by the time that + * passed since we last handed data to JACK */ - pa_source_post(u->source, &chunk); - pa_memblock_unref(chunk.memblock); + ft = jack_frame_time(u->client); + d = ft > u->saved_frame_time ? ft - u->saved_frame_time : 0; + l += d; + } - u->frames_posted = 0; + /* Convert it to usec */ + n = l * pa_frame_size(&u->source->sample_spec); + *((pa_usec_t*) data) = pa_bytes_to_usec(n, &u->source->sample_spec); - pthread_cond_signal(&u->cond); + return 0; + } } - pthread_mutex_unlock(&u->mutex); -} - -static void request_post(struct userdata *u) { - char c = 'x'; - assert(u); - - assert(u->pipe_fds[1] >= 0); - pa_write(u->pipe_fds[1], &c, 1, &u->pipe_fd_type); -} - -static void jack_shutdown(void *arg) { - struct userdata *u = arg; - assert(u); - - u->quit_requested = 1; - request_post(u); + return pa_source_process_msg(o, code, data, offset, chunk); } static int jack_process(jack_nframes_t nframes, void *arg) { + unsigned c; struct userdata *u = arg; - assert(u); - - if (jack_transport_query(u->client, NULL) == JackTransportRolling) { - unsigned c; + const void *buffer[PA_CHANNELS_MAX]; + void *p; + jack_nframes_t frame_time; + pa_memchunk chunk; - pthread_mutex_lock(&u->mutex); + pa_assert(u); - u->frames_posted = nframes; + for (c = 0; c < u->channels; c++) + pa_assert(buffer[c] = jack_port_get_buffer(u->port[c], nframes)); - for (c = 0; c < u->channels; c++) { - u->buffer[c] = jack_port_get_buffer(u->port[c], nframes); - assert(u->buffer[c]); - } + /* We interleave the data and pass it on to the other RT thread */ - request_post(u); + pa_memchunk_reset(&chunk); + chunk.length = nframes * pa_frame_size(&u->source->sample_spec); + chunk.memblock = pa_memblock_new(u->core->mempool, chunk.length); + p = pa_memblock_acquire(chunk.memblock); + pa_interleave(buffer, u->channels, p, sizeof(float), nframes); + pa_memblock_release(chunk.memblock); - pthread_cond_wait(&u->cond, &u->mutex); + frame_time = jack_frame_time(u->client); - u->frames_in_buffer = nframes; - u->timestamp = jack_get_current_transport_frame(u->client); + pa_asyncmsgq_post(u->jack_msgq, PA_MSGOBJECT(u->source), SOURCE_MESSAGE_POST, NULL, frame_time, &chunk, NULL); - pthread_mutex_unlock(&u->mutex); - } + pa_memblock_unref(chunk.memblock); return 0; } -static pa_usec_t source_get_latency_cb(pa_source *s) { - struct userdata *u; - jack_nframes_t n, l, d; +static void thread_func(void *userdata) { + struct userdata *u = userdata; + + pa_assert(u); - assert(s); - u = s->userdata; + pa_log_debug("Thread starting up"); - if (jack_transport_query(u->client, NULL) != JackTransportRolling) - return 0; + if (u->core->high_priority) + pa_make_realtime(); - n = jack_get_current_transport_frame(u->client); + pa_thread_mq_install(&u->thread_mq); + pa_rtpoll_install(u->rtpoll); - if (n < u->timestamp) - return 0; + for (;;) { + int ret; - d = n - u->timestamp; - l = jack_port_get_total_latency(u->client, u->port[0]); + if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0) + goto fail; + + if (ret == 0) + goto finish; + } - return pa_bytes_to_usec((l + d) * pa_frame_size(&s->sample_spec), &s->sample_spec); +fail: + /* If this was no regular exit from the loop we have to continue + * processing messages until we received PA_MESSAGE_SHUTDOWN */ + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); + +finish: + pa_log_debug("Thread shutting down"); } static void jack_error_func(const char*t) { - pa_log_warn("JACK error >%s<", t); + char *s; + + s = pa_xstrndup(t, strcspn(t, "\n\r")); + pa_log_warn("JACK error >%s<", s); + pa_xfree(s); +} + +static void jack_init(void *arg) { + struct userdata *u = arg; + + pa_log_info("JACK thread starting up."); + + if (u->core->high_priority) + pa_make_realtime(); } -int pa__init(pa_core *c, pa_module*m) { +static void jack_shutdown(void* arg) { + struct userdata *u = arg; + + pa_log_info("JACK thread shutting down.."); + pa_asyncmsgq_post(u->jack_msgq, PA_MSGOBJECT(u->source), SOURCE_MESSAGE_ON_SHUTDOWN, NULL, 0, NULL, NULL); +} + +int pa__init(pa_module*m) { struct userdata *u = NULL; pa_sample_spec ss; pa_channel_map map; @@ -247,40 +254,35 @@ int pa__init(pa_core *c, pa_module*m) { const char **ports = NULL, **p; char *t; - assert(c); - assert(m); + pa_assert(m); jack_set_error_function(jack_error_func); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log("failed to parse module arguments."); + pa_log("Failed to parse module arguments."); goto fail; } if (pa_modargs_get_value_boolean(ma, "connect", &do_connect) < 0) { - pa_log("failed to parse connect= argument."); + pa_log("Failed to parse connect= argument."); goto fail; } server_name = pa_modargs_get_value(ma, "server_name", NULL); - client_name = pa_modargs_get_value(ma, "client_name", "PulseAudio"); + client_name = pa_modargs_get_value(ma, "client_name", "PulseAudio JACK Source"); u = pa_xnew0(struct userdata, 1); - m->userdata = u; - u->core = c; + u->core = m->core; u->module = m; - u->pipe_fds[0] = u->pipe_fds[1] = -1; - u->pipe_fd_type = 0; - - pthread_mutex_init(&u->mutex, NULL); - pthread_cond_init(&u->cond, NULL); + m->userdata = u; + u->saved_frame_time_valid = FALSE; - if (pipe(u->pipe_fds) < 0) { - pa_log("pipe() failed: %s", pa_cstrerror(errno)); - goto fail; - } + pa_thread_mq_init(&u->thread_mq, m->core->mainloop); + u->rtpoll = pa_rtpoll_new(); + pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq); - pa_make_nonblock_fd(u->pipe_fds[1]); + u->jack_msgq = pa_asyncmsgq_new(0); + u->rtpoll_item = pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY-1, u->jack_msgq); if (!(u->client = jack_client_open(client_name, server_name ? JackServerName : JackNullOption, &status, server_name))) { pa_log("jack_client_open() failed."); @@ -294,7 +296,7 @@ int pa__init(pa_core *c, pa_module*m) { channels++; if (!channels) - channels = c->default_sample_spec.channels; + channels = m->core->default_sample_spec.channels; if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0 || channels <= 0 || channels >= PA_CHANNELS_MAX) { pa_log("failed to parse channels= argument."); @@ -302,7 +304,7 @@ int pa__init(pa_core *c, pa_module*m) { } pa_channel_map_init_auto(&map, channels, PA_CHANNEL_MAP_ALSA); - if (pa_modargs_get_channel_map(ma, &map) < 0 || map.channels != channels) { + if (pa_modargs_get_channel_map(ma, NULL, &map) < 0 || map.channels != channels) { pa_log("failed to parse channel_map= argument."); goto fail; } @@ -313,7 +315,7 @@ int pa__init(pa_core *c, pa_module*m) { ss.rate = jack_get_sample_rate(u->client); ss.format = PA_SAMPLE_FLOAT32NE; - assert(pa_sample_spec_valid(&ss)); + pa_assert(pa_sample_spec_valid(&ss)); for (i = 0; i < ss.channels; i++) { if (!(u->port[i] = jack_port_register(u->client, pa_channel_position_to_string(map.map[i]), JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput|JackPortIsTerminal, 0))) { @@ -322,19 +324,29 @@ int pa__init(pa_core *c, pa_module*m) { } } - if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) { + if (!(u->source = pa_source_new(m->core, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) { pa_log("failed to create source."); goto fail; } + u->source->parent.process_msg = source_process_msg; u->source->userdata = u; - pa_source_set_owner(u->source, m); + u->source->flags = PA_SOURCE_LATENCY; + + pa_source_set_module(u->source, m); + pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); + pa_source_set_rtpoll(u->source, u->rtpoll); pa_source_set_description(u->source, t = pa_sprintf_malloc("Jack source (%s)", jack_get_client_name(u->client))); pa_xfree(t); - u->source->get_latency = source_get_latency_cb; jack_set_process_callback(u->client, jack_process, u); jack_on_shutdown(u->client, jack_shutdown, u); + jack_set_thread_init_callback(u->client, jack_init, u); + + if (!(u->thread = pa_thread_new(thread_func, u))) { + pa_log("Failed to create thread."); + goto fail; + } if (jack_activate(u->client)) { pa_log("jack_activate() failed"); @@ -359,7 +371,7 @@ int pa__init(pa_core *c, pa_module*m) { } - u->io_event = c->mainloop->io_new(c->mainloop, u->pipe_fds[0], PA_IO_EVENT_INPUT, io_event_cb, u); + pa_source_put(u->source); free(ports); pa_modargs_free(ma); @@ -372,14 +384,14 @@ fail: free(ports); - pa__done(c, m); + pa__done(m); return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata *u; - assert(c && m); + pa_assert(m); if (!(u = m->userdata)) return; @@ -387,20 +399,27 @@ void pa__done(pa_core *c, pa_module*m) { if (u->client) jack_client_close(u->client); - if (u->io_event) - c->mainloop->io_free(u->io_event); + if (u->source) + pa_source_unlink(u->source); - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); } - if (u->pipe_fds[0] >= 0) - close(u->pipe_fds[0]); - if (u->pipe_fds[1] >= 0) - close(u->pipe_fds[1]); + pa_thread_mq_done(&u->thread_mq); + + if (u->source) + pa_source_unref(u->source); + + if (u->rtpoll_item) + pa_rtpoll_item_free(u->rtpoll_item); + + if (u->jack_msgq) + pa_asyncmsgq_unref(u->jack_msgq); + + if (u->rtpoll) + pa_rtpoll_free(u->rtpoll); - pthread_mutex_destroy(&u->mutex); - pthread_cond_destroy(&u->cond); pa_xfree(u); } diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c new file mode 100644 index 00000000..0265d971 --- /dev/null +++ b/src/modules/module-ladspa-sink.c @@ -0,0 +1,673 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* TODO: Some plugins cause latency, and some even report it by using a control + out port. We don't currently use the latency information. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-ladspa-sink-symdef.h" +#include "ladspa.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Virtual LADSPA sink") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE( + "sink_name= " + "master= " + "format= " + "channels= " + "rate= " + "channel_map= " + "plugin= " + "label= " + "control=") + +struct userdata { + pa_core *core; + pa_module *module; + + pa_sink *sink, *master; + pa_sink_input *sink_input; + + const LADSPA_Descriptor *descriptor; + unsigned channels; + LADSPA_Handle handle[PA_CHANNELS_MAX]; + LADSPA_Data *input, *output; + size_t block_size; + unsigned long input_port, output_port; + LADSPA_Data *control; + + /* This is a dummy buffer. Every port must be connected, but we don't care + about control out ports. We connect them all to this single buffer. */ + LADSPA_Data control_out; + + pa_memchunk memchunk; +}; + +static const char* const valid_modargs[] = { + "sink_name", + "master", + "format", + "channels", + "rate", + "channel_map", + "plugin", + "label", + "control", + NULL +}; + +/* Called from I/O thread context */ +static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SINK(o)->userdata; + + switch (code) { + + case PA_SINK_MESSAGE_GET_LATENCY: { + pa_usec_t usec = 0; + + if (PA_MSGOBJECT(u->master)->process_msg(PA_MSGOBJECT(u->master), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0) + usec = 0; + + *((pa_usec_t*) data) = usec + pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec); + return 0; + } + } + + return pa_sink_process_msg(o, code, data, offset, chunk); +} + +/* Called from main context */ +static int sink_set_state(pa_sink *s, pa_sink_state_t state) { + struct userdata *u; + + pa_sink_assert_ref(s); + pa_assert_se(u = s->userdata); + + if (PA_SINK_LINKED(state) && u->sink_input && PA_SINK_INPUT_LINKED(pa_sink_input_get_state(u->sink_input))) + pa_sink_input_cork(u->sink_input, state == PA_SINK_SUSPENDED); + + return 0; +} + +/* Called from I/O thread context */ +static int sink_input_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SINK_INPUT(o)->userdata; + + switch (code) { + case PA_SINK_INPUT_MESSAGE_GET_LATENCY: + *((pa_usec_t*) data) = pa_bytes_to_usec(u->memchunk.length, &u->sink_input->sample_spec); + + /* Fall through, the default handler will add in the extra + * latency added by the resampler */ + break; + } + + return pa_sink_input_process_msg(o, code, data, offset, chunk); +} + +/* Called from I/O thread context */ +static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_assert_se(u = i->userdata); + + if (!u->memchunk.memblock) { + pa_memchunk tchunk; + float *src, *dst; + size_t fs; + unsigned n, c; + + pa_sink_render(u->sink, length, &tchunk); + + fs = pa_frame_size(&i->sample_spec); + n = tchunk.length / fs; + + pa_assert(n > 0); + + u->memchunk.memblock = pa_memblock_new(i->sink->core->mempool, tchunk.length); + u->memchunk.index = 0; + u->memchunk.length = tchunk.length; + + src = (float*) ((uint8_t*) pa_memblock_acquire(tchunk.memblock) + tchunk.index); + dst = (float*) pa_memblock_acquire(u->memchunk.memblock); + + for (c = 0; c < u->channels; c++) { + unsigned j; + float *p, *q; + + p = src + c; + q = u->input; + for (j = 0; j < n; j++, p += u->channels, q++) + *q = CLAMP(*p, -1.0, 1.0); + + u->descriptor->run(u->handle[c], n); + + q = u->output; + p = dst + c; + for (j = 0; j < n; j++, q++, p += u->channels) + *p = CLAMP(*q, -1.0, 1.0); + } + + pa_memblock_release(tchunk.memblock); + pa_memblock_release(u->memchunk.memblock); + + pa_memblock_unref(tchunk.memblock); + } + + pa_assert(u->memchunk.length > 0); + pa_assert(u->memchunk.memblock); + + *chunk = u->memchunk; + pa_memblock_ref(chunk->memblock); + + return 0; +} + +/* Called from I/O thread context */ +static void sink_input_drop_cb(pa_sink_input *i, size_t length) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_assert_se(u = i->userdata); + pa_assert(length > 0); + + if (u->memchunk.memblock) { + + if (length < u->memchunk.length) { + u->memchunk.index += length; + u->memchunk.length -= length; + return; + } + + pa_memblock_unref(u->memchunk.memblock); + length -= u->memchunk.length; + pa_memchunk_reset(&u->memchunk); + } + + if (length > 0) + pa_sink_skip(u->sink, length); +} + +/* Called from I/O thread context */ +static void sink_input_detach_cb(pa_sink_input *i) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_assert_se(u = i->userdata); + + pa_sink_detach_within_thread(u->sink); +} + +/* Called from I/O thread context */ +static void sink_input_attach_cb(pa_sink_input *i) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_assert_se(u = i->userdata); + + pa_sink_set_asyncmsgq(u->sink, i->sink->asyncmsgq); + pa_sink_set_rtpoll(u->sink, i->sink->rtpoll); + + pa_sink_attach_within_thread(u->sink); +} + +/* Called from main context */ +static void sink_input_kill_cb(pa_sink_input *i) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_assert_se(u = i->userdata); + + pa_sink_input_unlink(u->sink_input); + pa_sink_input_unref(u->sink_input); + u->sink_input = NULL; + + pa_sink_unlink(u->sink); + pa_sink_unref(u->sink); + u->sink = NULL; + + pa_module_unload_request(u->module); +} + +int pa__init(pa_module*m) { + struct userdata *u; + pa_sample_spec ss; + pa_channel_map map; + pa_modargs *ma; + char *t; + pa_sink *master; + pa_sink_input_new_data data; + const char *plugin, *label; + LADSPA_Descriptor_Function descriptor_func; + const char *e, *cdata; + const LADSPA_Descriptor *d; + unsigned long input_port, output_port, p, j, n_control; + unsigned c; + pa_bool_t *use_default = NULL; + char *default_sink_name = NULL; + + pa_assert(m); + + pa_assert(sizeof(LADSPA_Data) == sizeof(float)); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log("Failed to parse module arguments."); + goto fail; + } + + if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "master", NULL), PA_NAMEREG_SINK, 1))) { + pa_log("Master sink not found"); + goto fail; + } + + ss = master->sample_spec; + ss.format = PA_SAMPLE_FLOAT32; + map = master->channel_map; + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { + pa_log("Invalid sample format specification or channel map"); + goto fail; + } + + if (!(plugin = pa_modargs_get_value(ma, "plugin", NULL))) { + pa_log("Missing LADSPA plugin name"); + goto fail; + } + + if (!(label = pa_modargs_get_value(ma, "label", NULL))) { + pa_log("Missing LADSPA plugin label"); + goto fail; + } + + cdata = pa_modargs_get_value(ma, "control", NULL); + + u = pa_xnew0(struct userdata, 1); + u->core = m->core; + u->module = m; + m->userdata = u; + u->master = master; + pa_memchunk_reset(&u->memchunk); + + if (!(e = getenv("LADSPA_PATH"))) + e = LADSPA_PATH; + + /* FIXME: This is not exactly thread safe */ + t = pa_xstrdup(lt_dlgetsearchpath()); + lt_dlsetsearchpath(e); + m->dl = lt_dlopenext(plugin); + lt_dlsetsearchpath(t); + pa_xfree(t); + + if (!m->dl) { + pa_log("Failed to load LADSPA plugin: %s", lt_dlerror()); + goto fail; + } + + if (!(descriptor_func = (LADSPA_Descriptor_Function) lt_dlsym(m->dl, "ladspa_descriptor"))) { + pa_log("LADSPA module lacks ladspa_descriptor() symbol."); + goto fail; + } + + for (j = 0;; j++) { + + if (!(d = descriptor_func(j))) { + pa_log("Failed to find plugin label '%s' in plugin '%s'.", plugin, label); + goto fail; + } + + if (strcmp(d->Label, label) == 0) + break; + } + + u->descriptor = d; + + pa_log_debug("Module: %s", plugin); + pa_log_debug("Label: %s", d->Label); + pa_log_debug("Unique ID: %lu", d->UniqueID); + pa_log_debug("Name: %s", d->Name); + pa_log_debug("Maker: %s", d->Maker); + pa_log_debug("Copyright: %s", d->Copyright); + + input_port = output_port = (unsigned long) -1; + n_control = 0; + + for (p = 0; p < d->PortCount; p++) { + + if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) { + + if (strcmp(d->PortNames[p], "Input") == 0) { + pa_assert(input_port == (unsigned long) -1); + input_port = p; + } else { + pa_log("Found audio input port on plugin we cannot handle: %s", d->PortNames[p]); + goto fail; + } + + } else if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) { + + if (strcmp(d->PortNames[p], "Output") == 0) { + pa_assert(output_port == (unsigned long) -1); + output_port = p; + } else { + pa_log("Found audio output port on plugin we cannot handle: %s", d->PortNames[p]); + goto fail; + } + + } else if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p])) + n_control++; + else { + pa_assert(LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p])); + pa_log_info("Ignored port \"%s\", because we ignore all control out ports.", d->PortNames[p]); + } + } + + if ((input_port == (unsigned long) -1) || (output_port == (unsigned long) -1)) { + pa_log("Failed to identify input and output ports. " + "Right now this module can only deal with plugins which provide an 'Input' and an 'Output' audio port. " + "Patches welcome!"); + goto fail; + } + + u->block_size = pa_frame_align(pa_mempool_block_size_max(m->core->mempool), &ss); + + u->input = (LADSPA_Data*) pa_xnew(uint8_t, u->block_size); + if (LADSPA_IS_INPLACE_BROKEN(d->Properties)) + u->output = (LADSPA_Data*) pa_xnew(uint8_t, u->block_size); + else + u->output = u->input; + + u->channels = ss.channels; + + for (c = 0; c < ss.channels; c++) { + if (!(u->handle[c] = d->instantiate(d, ss.rate))) { + pa_log("Failed to instantiate plugin %s with label %s for channel %i", plugin, d->Label, c); + goto fail; + } + + d->connect_port(u->handle[c], input_port, u->input); + d->connect_port(u->handle[c], output_port, u->output); + } + + if (!cdata && n_control > 0) { + pa_log("This plugin requires specification of %lu control parameters.", n_control); + goto fail; + } + + if (n_control > 0) { + const char *state = NULL; + char *k; + unsigned long h; + + u->control = pa_xnew(LADSPA_Data, n_control); + use_default = pa_xnew(pa_bool_t, n_control); + p = 0; + + while ((k = pa_split(cdata, ",", &state))) { + float f; + + if (*k == 0) { + use_default[p++] = TRUE; + pa_xfree(k); + continue; + } + + if (pa_atof(k, &f) < 0) { + pa_log("Failed to parse control value '%s'", k); + pa_xfree(k); + goto fail; + } + + pa_xfree(k); + + if (p >= n_control) { + pa_log("Too many control values passed, %lu expected.", n_control); + goto fail; + } + + use_default[p] = FALSE; + u->control[p++] = f; + } + + if (p < n_control) { + pa_log("Not enough control values passed, %lu expected, %lu passed.", n_control, p); + goto fail; + } + + h = 0; + for (p = 0; p < d->PortCount; p++) { + LADSPA_PortRangeHintDescriptor hint = d->PortRangeHints[p].HintDescriptor; + + if (!LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p])) + continue; + + if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p])) { + for (c = 0; c < ss.channels; c++) + d->connect_port(u->handle[c], p, &u->control_out); + continue; + } + + pa_assert(h < n_control); + + if (use_default[h]) { + LADSPA_Data lower, upper; + + if (!LADSPA_IS_HINT_HAS_DEFAULT(hint)) { + pa_log("Control port value left empty but plugin defines no default."); + goto fail; + } + + lower = d->PortRangeHints[p].LowerBound; + upper = d->PortRangeHints[p].UpperBound; + + if (LADSPA_IS_HINT_SAMPLE_RATE(hint)) { + lower *= ss.rate; + upper *= ss.rate; + } + + switch (hint & LADSPA_HINT_DEFAULT_MASK) { + + case LADSPA_HINT_DEFAULT_MINIMUM: + u->control[h] = lower; + break; + + case LADSPA_HINT_DEFAULT_MAXIMUM: + u->control[h] = upper; + break; + + case LADSPA_HINT_DEFAULT_LOW: + if (LADSPA_IS_HINT_LOGARITHMIC(hint)) + u->control[h] = exp(log(lower) * 0.75 + log(upper) * 0.25); + else + u->control[h] = lower * 0.75 + upper * 0.25; + break; + + case LADSPA_HINT_DEFAULT_MIDDLE: + if (LADSPA_IS_HINT_LOGARITHMIC(hint)) + u->control[h] = exp(log(lower) * 0.5 + log(upper) * 0.5); + else + u->control[h] = lower * 0.5 + upper * 0.5; + break; + + case LADSPA_HINT_DEFAULT_HIGH: + if (LADSPA_IS_HINT_LOGARITHMIC(hint)) + u->control[h] = exp(log(lower) * 0.25 + log(upper) * 0.75); + else + u->control[h] = lower * 0.25 + upper * 0.75; + break; + + case LADSPA_HINT_DEFAULT_0: + u->control[h] = 0; + break; + + case LADSPA_HINT_DEFAULT_1: + u->control[h] = 1; + break; + + case LADSPA_HINT_DEFAULT_100: + u->control[h] = 100; + break; + + case LADSPA_HINT_DEFAULT_440: + u->control[h] = 440; + break; + + default: + pa_assert_not_reached(); + } + } + + if (LADSPA_IS_HINT_INTEGER(hint)) + u->control[h] = roundf(u->control[h]); + + pa_log_debug("Binding %f to port %s", u->control[h], d->PortNames[p]); + + for (c = 0; c < ss.channels; c++) + d->connect_port(u->handle[c], p, &u->control[h]); + + h++; + } + + pa_assert(h == n_control); + } + + if (d->activate) + for (c = 0; c < u->channels; c++) + d->activate(u->handle[c]); + + default_sink_name = pa_sprintf_malloc("%s.ladspa", master->name); + + /* Create sink */ + if (!(u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", default_sink_name), 0, &ss, &map))) { + pa_log("Failed to create sink."); + goto fail; + } + + u->sink->parent.process_msg = sink_process_msg; + u->sink->set_state = sink_set_state; + u->sink->userdata = u; + u->sink->flags = PA_SINK_LATENCY; + + pa_sink_set_module(u->sink, m); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("LADSPA plugin '%s' on '%s'", label, master->description)); + pa_xfree(t); + pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq); + pa_sink_set_rtpoll(u->sink, master->rtpoll); + + /* Create sink input */ + pa_sink_input_new_data_init(&data); + data.sink = u->master; + data.driver = __FILE__; + data.name = "LADSPA Stream"; + pa_sink_input_new_data_set_sample_spec(&data, &ss); + pa_sink_input_new_data_set_channel_map(&data, &map); + data.module = m; + + if (!(u->sink_input = pa_sink_input_new(m->core, &data, PA_SINK_INPUT_DONT_MOVE))) + goto fail; + + u->sink_input->parent.process_msg = sink_input_process_msg; + u->sink_input->peek = sink_input_peek_cb; + u->sink_input->drop = sink_input_drop_cb; + u->sink_input->kill = sink_input_kill_cb; + u->sink_input->attach = sink_input_attach_cb; + u->sink_input->detach = sink_input_detach_cb; + u->sink_input->userdata = u; + + pa_sink_put(u->sink); + pa_sink_input_put(u->sink_input); + + pa_modargs_free(ma); + + pa_xfree(use_default); + pa_xfree(default_sink_name); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + pa_xfree(use_default); + pa_xfree(default_sink_name); + + pa__done(m); + + return -1; +} + +void pa__done(pa_module*m) { + struct userdata *u; + unsigned c; + + pa_assert(m); + + if (!(u = m->userdata)) + return; + + if (u->sink_input) { + pa_sink_input_unlink(u->sink_input); + pa_sink_input_unref(u->sink_input); + } + + if (u->sink) { + pa_sink_unlink(u->sink); + pa_sink_unref(u->sink); + } + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + + for (c = 0; c < u->channels; c++) + if (u->handle[c]) { + if (u->descriptor->deactivate) + u->descriptor->deactivate(u->handle[c]); + u->descriptor->cleanup(u->handle[c]); + } + + if (u->output != u->input) + pa_xfree(u->output); + + pa_xfree(u->input); + + pa_xfree(u->control); + + pa_xfree(u); +} diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c index c8adbc8b..21d93837 100644 --- a/src/modules/module-lirc.c +++ b/src/modules/module-lirc.c @@ -26,12 +26,12 @@ #endif #include -#include #include #include -#include #include +#include + #include #include @@ -39,6 +39,7 @@ #include #include #include +#include #include "module-lirc-symdef.h" @@ -68,11 +69,12 @@ static int lirc_in_use = 0; static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void*userdata) { struct userdata *u = userdata; char *name = NULL, *code = NULL; - assert(io); - assert(u); + + pa_assert(io); + pa_assert(u); if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { - pa_log("lost connection to LIRC daemon."); + pa_log("Lost connection to LIRC daemon."); goto fail; } @@ -86,7 +88,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC c = pa_xstrdup(code); c[strcspn(c, "\n\r")] = 0; - pa_log_debug("raw IR code '%s'", c); + pa_log_debug("Raw IR code '%s'", c); pa_xfree(c); while (lirc_code2char(u->config, code, &name) == 0 && name) { @@ -99,7 +101,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC MUTE_TOGGLE } volchange = INVALID; - pa_log_info("translated IR code '%s'", name); + pa_log_info("Translated IR code '%s'", name); if (strcasecmp(name, "volume-up") == 0) volchange = UP; @@ -113,15 +115,15 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC volchange = RESET; if (volchange == INVALID) - pa_log_warn("recieved unknown IR code '%s'", name); + pa_log_warn("Recieved unknown IR code '%s'", name); else { pa_sink *s; if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) - pa_log("failed to get sink '%s'", u->sink_name); + pa_log("Failed to get sink '%s'", u->sink_name); else { int i; - pa_cvolume cv = *pa_sink_get_volume(s, PA_MIXER_HARDWARE); + pa_cvolume cv = *pa_sink_get_volume(s); #define DELTA (PA_VOLUME_NORM/20) @@ -134,7 +136,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC cv.values[i] = PA_VOLUME_NORM; } - pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); + pa_sink_set_volume(s, &cv); break; case DOWN: @@ -145,20 +147,20 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC cv.values[i] = PA_VOLUME_MUTED; } - pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); + pa_sink_set_volume(s, &cv); break; case MUTE: - pa_sink_set_mute(s, PA_MIXER_HARDWARE, 0); + pa_sink_set_mute(s, 0); break; case RESET: - pa_sink_set_mute(s, PA_MIXER_HARDWARE, 1); + pa_sink_set_mute(s, 1); break; case MUTE_TOGGLE: - pa_sink_set_mute(s, PA_MIXER_HARDWARE, !pa_sink_get_mute(s, PA_MIXER_HARDWARE)); + pa_sink_set_mute(s, !pa_sink_get_mute(s)); break; case INVALID: @@ -179,13 +181,14 @@ fail: pa_module_unload_request(u->module); - free(code); + pa_xfree(code); } -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { pa_modargs *ma = NULL; struct userdata *u; - assert(c && m); + + pa_assert(m); if (lirc_in_use) { pa_log("module-lirc may no be loaded twice."); @@ -197,7 +200,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - m->userdata = u = pa_xmalloc(sizeof(struct userdata)); + m->userdata = u = pa_xnew(struct userdata, 1); u->module = m; u->io = NULL; u->config = NULL; @@ -215,7 +218,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - u->io = c->mainloop->io_new(c->mainloop, u->lirc_fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u); + u->io = m->core->mainloop->io_new(m->core->mainloop, u->lirc_fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u); lirc_in_use = 1; @@ -228,14 +231,13 @@ fail: if (ma) pa_modargs_free(ma); - pa__done(c, m); + pa__done(m); return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata *u; - assert(c); - assert(m); + pa_assert(m); if (!(u = m->userdata)) return; diff --git a/src/modules/module-match.c b/src/modules/module-match.c index 0b051fac..0155b2af 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -26,7 +26,6 @@ #endif #include -#include #include #include #include @@ -80,6 +79,8 @@ static int load_rules(struct userdata *u, const char *filename) { struct rule *end = NULL; char *fn = NULL; + pa_assert(u); + f = filename ? fopen(fn = pa_xstrdup(filename), "r") : pa_open_config_file(DEFAULT_MATCH_TABLE_FILE, DEFAULT_MATCH_TABLE_FILE_USER, NULL, &fn, "r"); @@ -132,7 +133,7 @@ static int load_rules(struct userdata *u, const char *filename) { goto finish; } - rule = pa_xmalloc(sizeof(struct rule)); + rule = pa_xnew(struct rule, 1); rule->regex = regex; rule->volume = volume; rule->next = NULL; @@ -164,7 +165,9 @@ static void callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, v struct userdata *u = userdata; pa_sink_input *si; struct rule *r; - assert(c && u); + + pa_assert(c); + pa_assert(u); if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW)) return; @@ -179,23 +182,24 @@ static void callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, v if (!regexec(&r->regex, si->name, 0, NULL, 0)) { pa_cvolume cv; pa_log_debug("changing volume of sink input '%s' to 0x%03x", si->name, r->volume); - pa_cvolume_set(&cv, r->volume, si->sample_spec.channels); + pa_cvolume_set(&cv, si->sample_spec.channels, r->volume); pa_sink_input_set_volume(si, &cv); } } } -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { pa_modargs *ma = NULL; struct userdata *u; - assert(c && m); + + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments"); goto fail; } - u = pa_xmalloc(sizeof(struct userdata)); + u = pa_xnew(struct userdata, 1); u->rules = NULL; u->subscription = NULL; m->userdata = u; @@ -203,23 +207,24 @@ int pa__init(pa_core *c, pa_module*m) { if (load_rules(u, pa_modargs_get_value(ma, "table", NULL)) < 0) goto fail; - u->subscription = pa_subscription_new(c, PA_SUBSCRIPTION_MASK_SINK_INPUT, callback, u); + u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK_INPUT, callback, u); pa_modargs_free(ma); return 0; fail: - pa__done(c, m); + pa__done(m); if (ma) pa_modargs_free(ma); return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata* u; struct rule *r, *n; - assert(c && m); + + pa_assert(m); if (!(u = m->userdata)) return; diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c index b7433ac8..47a10645 100644 --- a/src/modules/module-mmkbd-evdev.c +++ b/src/modules/module-mmkbd-evdev.c @@ -26,7 +26,6 @@ #endif #include -#include #include #include #include @@ -80,11 +79,12 @@ struct userdata { static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void*userdata) { struct userdata *u = userdata; - assert(io); - assert(u); + + pa_assert(io); + pa_assert(u); if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { - pa_log("lost connection to evdev device."); + pa_log("Lost connection to evdev device."); goto fail; } @@ -92,14 +92,14 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC struct input_event ev; if (pa_loop_read(u->fd, &ev, sizeof(ev), &u->fd_type) <= 0) { - pa_log("failed to read from event device: %s", pa_cstrerror(errno)); + pa_log("Failed to read from event device: %s", pa_cstrerror(errno)); goto fail; } if (ev.type == EV_KEY && (ev.value == 1 || ev.value == 2)) { enum { INVALID, UP, DOWN, MUTE_TOGGLE } volchange = INVALID; - pa_log_debug("key code=%u, value=%u", ev.code, ev.value); + pa_log_debug("Key code=%u, value=%u", ev.code, ev.value); switch (ev.code) { case KEY_VOLUMEDOWN: volchange = DOWN; break; @@ -111,10 +111,10 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC pa_sink *s; if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) - pa_log("failed to get sink '%s'", u->sink_name); + pa_log("Failed to get sink '%s'", u->sink_name); else { int i; - pa_cvolume cv = *pa_sink_get_volume(s, PA_MIXER_HARDWARE); + pa_cvolume cv = *pa_sink_get_volume(s); #define DELTA (PA_VOLUME_NORM/20) @@ -127,7 +127,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC cv.values[i] = PA_VOLUME_NORM; } - pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); + pa_sink_set_volume(s, &cv); break; case DOWN: @@ -138,12 +138,12 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC cv.values[i] = PA_VOLUME_MUTED; } - pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); + pa_sink_set_volume(s, &cv); break; case MUTE_TOGGLE: - pa_sink_set_mute(s, PA_MIXER_HARDWARE, !pa_sink_get_mute(s, PA_MIXER_HARDWARE)); + pa_sink_set_mute(s, !pa_sink_get_mute(s)); break; case INVALID: @@ -165,21 +165,23 @@ fail: #define test_bit(bit, array) (array[bit/8] & (1<<(bit%8))) -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { + pa_modargs *ma = NULL; struct userdata *u; int version; struct _input_id input_id; char name[256]; uint8_t evtype_bitmask[EV_MAX/8 + 1]; - assert(c && m); + + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments"); goto fail; } - m->userdata = u = pa_xmalloc(sizeof(struct userdata)); + m->userdata = u = pa_xnew(struct userdata,1); u->module = m; u->io = NULL; u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); @@ -221,11 +223,11 @@ int pa__init(pa_core *c, pa_module*m) { } if (!test_bit(EV_KEY, evtype_bitmask)) { - pa_log("device has no keys."); + pa_log("Device has no keys."); goto fail; } - u->io = c->mainloop->io_new(c->mainloop, u->fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u); + u->io = m->core->mainloop->io_new(m->core->mainloop, u->fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u); pa_modargs_free(ma); @@ -236,14 +238,14 @@ fail: if (ma) pa_modargs_free(ma); - pa__done(c, m); + pa__done(m); return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata *u; - assert(c); - assert(m); + + pa_assert(m); if (!(u = m->userdata)) return; @@ -252,7 +254,7 @@ void pa__done(pa_core *c, pa_module*m) { m->core->mainloop->io_free(u->io); if (u->fd >= 0) - close(u->fd); + pa_assert_se(pa_close(u->fd) == 0); pa_xfree(u->sink_name); pa_xfree(u); diff --git a/src/modules/module-native-protocol-fd.c b/src/modules/module-native-protocol-fd.c index 3c1c2bca..2ef61c88 100644 --- a/src/modules/module-native-protocol-fd.c +++ b/src/modules/module-native-protocol-fd.c @@ -26,10 +26,10 @@ #endif #include -#include #include #include +#include #include #include #include @@ -48,25 +48,26 @@ static const char* const valid_modargs[] = { NULL, }; -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { pa_iochannel *io; pa_modargs *ma; int fd, r = -1; - assert(c && m); + + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log("failed to parse module arguments."); + pa_log("Failed to parse module arguments."); goto finish; } if (pa_modargs_get_value_s32(ma, "fd", &fd) < 0) { - pa_log("invalid file descriptor."); + pa_log("Invalid file descriptor."); goto finish; } - io = pa_iochannel_new(c->mainloop, fd, fd); + io = pa_iochannel_new(m->core->mainloop, fd, fd); - if (!(m->userdata = pa_protocol_native_new_iochannel(c, io, m, ma))) { + if (!(m->userdata = pa_protocol_native_new_iochannel(m->core, io, m, ma))) { pa_iochannel_free(io); goto finish; } @@ -80,8 +81,8 @@ finish: return r; } -void pa__done(pa_core *c, pa_module*m) { - assert(c && m); +void pa__done(pa_module*m) { + pa_assert(m); pa_protocol_native_free(m->userdata); } diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index 54a8e890..3a4edec7 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -38,12 +37,17 @@ #include #include -#include +#include #include #include #include +#include #include #include +#include +#include +#include +#include #include "module-null-sink-symdef.h" @@ -64,11 +68,14 @@ struct userdata { pa_core *core; pa_module *module; pa_sink *sink; - pa_time_event *time_event; + + pa_thread *thread; + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; + size_t block_size; - uint64_t n_bytes; - struct timeval start_time; + struct timeval timestamp; }; static const char* const valid_modargs[] = { @@ -81,78 +88,132 @@ static const char* const valid_modargs[] = { NULL }; -static void time_callback(pa_mainloop_api *m, pa_time_event*e, const struct timeval *tv, void *userdata) { - struct userdata *u = userdata; - pa_memchunk chunk; - struct timeval ntv = *tv; - size_t l; +static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SINK(o)->userdata; + + switch (code) { + case PA_SINK_MESSAGE_SET_STATE: - assert(u); + if (PA_PTR_TO_UINT(data) == PA_SINK_RUNNING) + pa_rtclock_get(&u->timestamp); - if (pa_sink_render(u->sink, u->block_size, &chunk) >= 0) { - l = chunk.length; - pa_memblock_unref(chunk.memblock); - } else - l = u->block_size; + break; - pa_timeval_add(&ntv, pa_bytes_to_usec(l, &u->sink->sample_spec)); - m->time_restart(e, &ntv); + case PA_SINK_MESSAGE_GET_LATENCY: { + struct timeval now; - u->n_bytes += l; + pa_rtclock_get(&now); + + if (pa_timeval_cmp(&u->timestamp, &now) > 0) + *((pa_usec_t*) data) = 0; + else + *((pa_usec_t*) data) = pa_timeval_diff(&u->timestamp, &now); + break; + } + } + + return pa_sink_process_msg(o, code, data, offset, chunk); } -static pa_usec_t get_latency(pa_sink *s) { - struct userdata *u = s->userdata; - pa_usec_t a, b; - struct timeval now; +static void thread_func(void *userdata) { + struct userdata *u = userdata; + + pa_assert(u); + + pa_log_debug("Thread starting up"); + + pa_thread_mq_install(&u->thread_mq); + pa_rtpoll_install(u->rtpoll); + + pa_rtclock_get(&u->timestamp); + + for (;;) { + int ret; + + /* Render some data and drop it immediately */ + if (u->sink->thread_info.state == PA_SINK_RUNNING) { + struct timeval now; + + pa_rtclock_get(&now); - a = pa_timeval_diff(pa_gettimeofday(&now), &u->start_time); - b = pa_bytes_to_usec(u->n_bytes, &s->sample_spec); + if (pa_timeval_cmp(&u->timestamp, &now) <= 0) { + pa_sink_skip(u->sink, u->block_size); + pa_timeval_add(&u->timestamp, pa_bytes_to_usec(u->block_size, &u->sink->sample_spec)); + } - return b > a ? b - a : 0; + pa_rtpoll_set_timer_absolute(u->rtpoll, &u->timestamp); + } else + pa_rtpoll_set_timer_disabled(u->rtpoll); + + /* Hmm, nothing to do. Let's sleep */ + if ((ret = pa_rtpoll_run(u->rtpoll, 1)) < 0) + goto fail; + + if (ret == 0) + goto finish; + } + +fail: + /* If this was no regular exit from the loop we have to continue + * processing messages until we received PA_MESSAGE_SHUTDOWN */ + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); + +finish: + pa_log_debug("Thread shutting down"); } -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { struct userdata *u = NULL; pa_sample_spec ss; pa_channel_map map; pa_modargs *ma = NULL; - assert(c); - assert(m); + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log("failed to parse module arguments."); + pa_log("Failed to parse module arguments."); goto fail; } - ss = c->default_sample_spec; + ss = m->core->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { - pa_log("invalid sample format specification or channel map."); + pa_log("Invalid sample format specification or channel map"); goto fail; } u = pa_xnew0(struct userdata, 1); - u->core = c; + u->core = m->core; u->module = m; m->userdata = u; + pa_thread_mq_init(&u->thread_mq, m->core->mainloop); + u->rtpoll = pa_rtpoll_new(); + pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq); - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { - pa_log("failed to create sink."); + if (!(u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { + pa_log("Failed to create sink."); goto fail; } - u->sink->get_latency = get_latency; + u->sink->parent.process_msg = sink_process_msg; u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); + u->sink->flags = PA_SINK_LATENCY; + + pa_sink_set_module(u->sink, m); + pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); + pa_sink_set_rtpoll(u->sink, u->rtpoll); pa_sink_set_description(u->sink, pa_modargs_get_value(ma, "description", "NULL sink")); - u->n_bytes = 0; - pa_gettimeofday(&u->start_time); + u->block_size = pa_bytes_per_second(&ss) / 20; /* 50 ms */ + if (u->block_size <= 0) + u->block_size = pa_frame_size(&ss); - u->time_event = c->mainloop->time_new(c->mainloop, &u->start_time, time_callback, u); + if (!(u->thread = pa_thread_new(thread_func, u))) { + pa_log("Failed to create thread."); + goto fail; + } - u->block_size = pa_bytes_per_second(&ss) / 10; + pa_sink_put(u->sink); pa_modargs_free(ma); @@ -162,22 +223,34 @@ fail: if (ma) pa_modargs_free(ma); - pa__done(c, m); + pa__done(m); return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata *u; - assert(c && m); + + pa_assert(m); if (!(u = m->userdata)) return; - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); + if (u->sink) + pa_sink_unlink(u->sink); + + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); + } + + pa_thread_mq_done(&u->thread_mq); + + if (u->sink) + pa_sink_unref(u->sink); - u->core->mainloop->time_free(u->time_event); + if (u->rtpoll) + pa_rtpoll_free(u->rtpoll); pa_xfree(u); } diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c deleted file mode 100644 index 16c9b311..00000000 --- a/src/modules/module-oss-mmap.c +++ /dev/null @@ -1,637 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of PulseAudio. - - Copyright 2004-2006 Lennart Poettering - Copyright 2006 Pierre Ossman for Cendio AB - - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PulseAudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_MMAN_H -#include -#endif - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "oss-util.h" -#include "module-oss-mmap-symdef.h" - -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("OSS Sink/Source (mmap)") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE( - "sink_name= " - "source_name= " - "device= " - "record= " - "playback= " - "format= " - "channels= " - "rate= " - "fragments= " - "fragment_size= " - "channel_map=") - -struct userdata { - pa_sink *sink; - pa_source *source; - pa_core *core; - pa_sample_spec sample_spec; - - size_t in_fragment_size, out_fragment_size; - unsigned in_fragments, out_fragments; - unsigned out_blocks_saved, in_blocks_saved; - - int fd; - - void *in_mmap, *out_mmap; - size_t in_mmap_length, out_mmap_length; - - pa_io_event *io_event; - - pa_memblock **in_memblocks, **out_memblocks; - unsigned out_current, in_current; - pa_module *module; -}; - -static const char* const valid_modargs[] = { - "sink_name", - "source_name", - "device", - "record", - "playback", - "fragments", - "fragment_size", - "format", - "rate", - "channels", - "channel_map", - NULL -}; - -#define DEFAULT_DEVICE "/dev/dsp" -#define DEFAULT_NFRAGS 12 -#define DEFAULT_FRAGSIZE 1024 - -static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, - (u->sink ? pa_sink_used_by(u->sink) : 0) + - (u->source ? pa_source_used_by(u->source) : 0)); -} - -static void clear_up(struct userdata *u) { - assert(u); - - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - u->sink = NULL; - } - - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - u->source = NULL; - } - - if (u->in_mmap && u->in_mmap != MAP_FAILED) { - munmap(u->in_mmap, u->in_mmap_length); - u->in_mmap = NULL; - } - - if (u->out_mmap && u->out_mmap != MAP_FAILED) { - munmap(u->out_mmap, u->out_mmap_length); - u->out_mmap = NULL; - } - - if (u->io_event) { - u->core->mainloop->io_free(u->io_event); - u->io_event = NULL; - } - - if (u->fd >= 0) { - close(u->fd); - u->fd = -1; - } -} - -static void out_fill_memblocks(struct userdata *u, unsigned n) { - assert(u && u->out_memblocks); - - while (n > 0) { - pa_memchunk chunk; - - if (u->out_memblocks[u->out_current]) - pa_memblock_unref_fixed(u->out_memblocks[u->out_current]); - - chunk.memblock = u->out_memblocks[u->out_current] = - pa_memblock_new_fixed( - u->core->mempool, - (uint8_t*) u->out_mmap+u->out_fragment_size*u->out_current, - u->out_fragment_size, - 1); - assert(chunk.memblock); - chunk.length = chunk.memblock->length; - chunk.index = 0; - - pa_sink_render_into_full(u->sink, &chunk); - - u->out_current++; - while (u->out_current >= u->out_fragments) - u->out_current -= u->out_fragments; - - n--; - } -} - -static void do_write(struct userdata *u) { - struct count_info info; - assert(u && u->sink); - - update_usage(u); - - if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { - pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno)); - - clear_up(u); - pa_module_unload_request(u->module); - return; - } - - info.blocks += u->out_blocks_saved; - u->out_blocks_saved = 0; - - if (!info.blocks) - return; - - out_fill_memblocks(u, info.blocks); -} - -static void in_post_memblocks(struct userdata *u, unsigned n) { - assert(u && u->in_memblocks); - - while (n > 0) { - pa_memchunk chunk; - - if (!u->in_memblocks[u->in_current]) { - chunk.memblock = u->in_memblocks[u->in_current] = pa_memblock_new_fixed(u->core->mempool, (uint8_t*) u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size, 1); - chunk.length = chunk.memblock->length; - chunk.index = 0; - - pa_source_post(u->source, &chunk); - } - - u->in_current++; - while (u->in_current >= u->in_fragments) - u->in_current -= u->in_fragments; - - n--; - } -} - -static void in_clear_memblocks(struct userdata*u, unsigned n) { - unsigned i = u->in_current; - assert(u && u->in_memblocks); - - if (n > u->in_fragments) - n = u->in_fragments; - - while (n > 0) { - if (u->in_memblocks[i]) { - pa_memblock_unref_fixed(u->in_memblocks[i]); - u->in_memblocks[i] = NULL; - } - - i++; - while (i >= u->in_fragments) - i -= u->in_fragments; - - n--; - } -} - -static void do_read(struct userdata *u) { - struct count_info info; - assert(u && u->source); - - update_usage(u); - - if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { - pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno)); - - clear_up(u); - pa_module_unload_request(u->module); - return; - } - - info.blocks += u->in_blocks_saved; - u->in_blocks_saved = 0; - - if (!info.blocks) - return; - - in_post_memblocks(u, info.blocks); - in_clear_memblocks(u, u->in_fragments/2); -} - -static void io_callback(pa_mainloop_api *m, pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t f, void *userdata) { - struct userdata *u = userdata; - assert (u && u->core->mainloop == m && u->io_event == e); - - if (f & PA_IO_EVENT_ERROR) { - clear_up(u); - pa_module_unload_request(u->module); - return; - } - - if (f & PA_IO_EVENT_INPUT) - do_read(u); - if (f & PA_IO_EVENT_OUTPUT) - do_write(u); -} - -static pa_usec_t sink_get_latency_cb(pa_sink *s) { - struct userdata *u = s->userdata; - struct count_info info; - size_t bpos, n, total; - assert(s && u); - - if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { - pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno)); - return 0; - } - - u->out_blocks_saved += info.blocks; - - total = u->out_fragments * u->out_fragment_size; - bpos = ((u->out_current + u->out_blocks_saved) * u->out_fragment_size) % total; - - if (bpos <= (size_t) info.ptr) - n = total - (info.ptr - bpos); - else - n = bpos - info.ptr; - -/* pa_log("n = %u, bpos = %u, ptr = %u, total=%u, fragsize = %u, n_frags = %u\n", n, bpos, (unsigned) info.ptr, total, u->out_fragment_size, u->out_fragments); */ - - return pa_bytes_to_usec(n, &s->sample_spec); -} - -static pa_usec_t source_get_latency_cb(pa_source *s) { - struct userdata *u = s->userdata; - struct count_info info; - size_t bpos, n, total; - assert(s && u); - - if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { - pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno)); - return 0; - } - - u->in_blocks_saved += info.blocks; - - total = u->in_fragments * u->in_fragment_size; - bpos = ((u->in_current + u->in_blocks_saved) * u->in_fragment_size) % total; - - if (bpos <= (size_t) info.ptr) - n = info.ptr - bpos; - else - n = (u->in_fragments * u->in_fragment_size) - bpos + info.ptr; - -/* pa_log("n = %u, bpos = %u, ptr = %u, total=%u, fragsize = %u, n_frags = %u\n", n, bpos, (unsigned) info.ptr, total, u->in_fragment_size, u->in_fragments); */ - - return pa_bytes_to_usec(n, &s->sample_spec); -} - -static int sink_get_hw_volume(pa_sink *s) { - struct userdata *u = s->userdata; - - if (pa_oss_get_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info("device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); - s->get_hw_volume = NULL; - return -1; - } - - return 0; -} - -static int sink_set_hw_volume(pa_sink *s) { - struct userdata *u = s->userdata; - - if (pa_oss_set_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info("device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); - s->set_hw_volume = NULL; - return -1; - } - - return 0; -} - -static int source_get_hw_volume(pa_source *s) { - struct userdata *u = s->userdata; - - if (pa_oss_get_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info("device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); - s->get_hw_volume = NULL; - return -1; - } - - return 0; -} - -static int source_set_hw_volume(pa_source *s) { - struct userdata *u = s->userdata; - - if (pa_oss_set_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info("device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); - s->set_hw_volume = NULL; - return -1; - } - - return 0; -} - -int pa__init(pa_core *c, pa_module*m) { - struct audio_buf_info info; - struct userdata *u = NULL; - const char *p; - int nfrags, frag_size; - int mode, caps; - int enable_bits = 0, zero = 0; - int playback = 1, record = 1; - pa_modargs *ma = NULL; - char hwdesc[64], *t; - pa_channel_map map; - const char *name; - char *name_buf = NULL; - int namereg_fail; - - assert(c); - assert(m); - - m->userdata = u = pa_xnew0(struct userdata, 1); - u->module = m; - u->fd = -1; - u->core = c; - - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log("failed to parse module arguments."); - goto fail; - } - - if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { - pa_log("record= and playback= expect numeric arguments."); - goto fail; - } - - if (!playback && !record) { - pa_log("neither playback nor record enabled for device."); - goto fail; - } - - mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); - - nfrags = DEFAULT_NFRAGS; - frag_size = DEFAULT_FRAGSIZE; - if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { - pa_log("failed to parse fragments arguments"); - goto fail; - } - - u->sample_spec = c->default_sample_spec; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &u->sample_spec, &map, PA_CHANNEL_MAP_OSS) < 0) { - pa_log("failed to parse sample specification or channel map"); - goto fail; - } - - if ((u->fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0) - goto fail; - - if (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_TRIGGER)) { - pa_log("OSS device not mmap capable."); - goto fail; - } - - pa_log_info("device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); - - if (pa_oss_get_hw_description(p, hwdesc, sizeof(hwdesc)) >= 0) - pa_log_info("hardware name is '%s'.", hwdesc); - else - hwdesc[0] = 0; - - if (nfrags >= 2 && frag_size >= 1) - if (pa_oss_set_fragments(u->fd, nfrags, frag_size) < 0) - goto fail; - - if (pa_oss_auto_format(u->fd, &u->sample_spec) < 0) - goto fail; - - if (mode != O_WRONLY) { - if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { - pa_log("SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno)); - goto fail; - } - - pa_log_info("input -- %u fragments of size %u.", info.fragstotal, info.fragsize); - u->in_mmap_length = (u->in_fragment_size = info.fragsize) * (u->in_fragments = info.fragstotal); - - if ((u->in_mmap = mmap(NULL, u->in_mmap_length, PROT_READ, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { - if (mode == O_RDWR) { - pa_log("mmap failed for input. Changing to O_WRONLY mode."); - mode = O_WRONLY; - } else { - pa_log("mmap(): %s", pa_cstrerror(errno)); - goto fail; - } - } else { - if ((name = pa_modargs_get_value(ma, "source_name", NULL))) - namereg_fail = 1; - else { - name = name_buf = pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(p)); - namereg_fail = 0; - } - - if (!(u->source = pa_source_new(c, __FILE__, name, namereg_fail, &u->sample_spec, &map))) - goto fail; - - u->source->userdata = u; - u->source->get_latency = source_get_latency_cb; - u->source->get_hw_volume = source_get_hw_volume; - u->source->set_hw_volume = source_set_hw_volume; - pa_source_set_owner(u->source, m); - pa_source_set_description(u->source, t = pa_sprintf_malloc("OSS PCM/mmap() on %s%s%s%s", - p, - hwdesc[0] ? " (" : "", - hwdesc[0] ? hwdesc : "", - hwdesc[0] ? ")" : "")); - pa_xfree(t); - u->source->is_hardware = 1; - - u->in_memblocks = pa_xnew0(pa_memblock*, u->in_fragments); - - enable_bits |= PCM_ENABLE_INPUT; - } - } - - pa_xfree(name_buf); - name_buf = NULL; - - if (mode != O_RDONLY) { - if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { - pa_log("SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno)); - goto fail; - } - - pa_log_info("output -- %u fragments of size %u.", info.fragstotal, info.fragsize); - u->out_mmap_length = (u->out_fragment_size = info.fragsize) * (u->out_fragments = info.fragstotal); - - if ((u->out_mmap = mmap(NULL, u->out_mmap_length, PROT_WRITE, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { - if (mode == O_RDWR) { - pa_log("mmap filed for output. Changing to O_RDONLY mode."); - mode = O_RDONLY; - } else { - pa_log("mmap(): %s", pa_cstrerror(errno)); - goto fail; - } - } else { - pa_silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec); - - if ((name = pa_modargs_get_value(ma, "sink_name", NULL))) - namereg_fail = 1; - else { - name = name_buf = pa_sprintf_malloc("oss_output.%s", pa_path_get_filename(p)); - namereg_fail = 0; - } - - if (!(u->sink = pa_sink_new(c, __FILE__, name, namereg_fail, &u->sample_spec, &map))) - goto fail; - - u->sink->get_latency = sink_get_latency_cb; - u->sink->get_hw_volume = sink_get_hw_volume; - u->sink->set_hw_volume = sink_set_hw_volume; - u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - pa_sink_set_description(u->sink, t = pa_sprintf_malloc("OSS PCM/mmap() on %s%s%s%s", - p, - hwdesc[0] ? " (" : "", - hwdesc[0] ? hwdesc : "", - hwdesc[0] ? ")" : "")); - pa_xfree(t); - - u->sink->is_hardware = 1; - u->out_memblocks = pa_xmalloc0(sizeof(struct memblock *)*u->out_fragments); - - enable_bits |= PCM_ENABLE_OUTPUT; - } - } - - pa_xfree(name_buf); - name_buf = NULL; - - zero = 0; - if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero) < 0) { - pa_log("SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno)); - goto fail; - } - - if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0) { - pa_log("SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno)); - goto fail; - } - - assert(u->source || u->sink); - - u->io_event = c->mainloop->io_new(c->mainloop, u->fd, (u->source ? PA_IO_EVENT_INPUT : 0) | (u->sink ? PA_IO_EVENT_OUTPUT : 0), io_callback, u); - assert(u->io_event); - - pa_modargs_free(ma); - - /* Read mixer settings */ - if (u->source) - source_get_hw_volume(u->source); - if (u->sink) - sink_get_hw_volume(u->sink); - - return 0; - -fail: - pa__done(c, m); - - if (ma) - pa_modargs_free(ma); - - pa_xfree(name_buf); - - return -1; -} - -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u; - - assert(c); - assert(m); - - if (!(u = m->userdata)) - return; - - clear_up(u); - - if (u->out_memblocks) { - unsigned i; - for (i = 0; i < u->out_fragments; i++) - if (u->out_memblocks[i]) - pa_memblock_unref_fixed(u->out_memblocks[i]); - pa_xfree(u->out_memblocks); - } - - if (u->in_memblocks) { - unsigned i; - for (i = 0; i < u->in_fragments; i++) - if (u->in_memblocks[i]) - pa_memblock_unref_fixed(u->in_memblocks[i]); - pa_xfree(u->in_memblocks); - } - - pa_xfree(u); -} diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 9d4d0eac..19dceef2 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -22,27 +22,46 @@ USA. ***/ +/* General power management rules: + * + * When SUSPENDED we close the audio device. + * + * We make no difference between IDLE and RUNNING in our handling. + * + * As long as we are in RUNNING/IDLE state we will *always* write data to + * the device. If none is avilable from the inputs, we write silence + * instead. + * + * If power should be saved on IDLE module-suspend-on-idle should be used. + * + */ + #ifdef HAVE_CONFIG_H #include #endif +#ifdef HAVE_SYS_MMAN_H +#include +#endif + #include #include #include #include #include -#include #include #include #include #include #include +#include +#include #include #include #include -#include +#include #include #include #include @@ -50,6 +69,9 @@ #include #include #include +#include +#include +#include #include "oss-util.h" #include "module-oss-symdef.h" @@ -68,21 +90,48 @@ PA_MODULE_USAGE( "rate= " "fragments= " "fragment_size= " - "channel_map=") + "channel_map= " + "mmap=") + +#define DEFAULT_DEVICE "/dev/dsp" struct userdata { + pa_core *core; + pa_module *module; pa_sink *sink; pa_source *source; - pa_iochannel *io; - pa_core *core; - pa_memchunk memchunk, silence; + pa_thread *thread; + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; + + char *device_name; + + pa_memchunk memchunk; - uint32_t in_fragment_size, out_fragment_size, sample_size; - int use_getospace, use_getispace; + size_t frame_size; + uint32_t in_fragment_size, out_fragment_size, in_nfrags, out_nfrags, in_hwbuf_size, out_hwbuf_size; + pa_bool_t use_getospace, use_getispace; + pa_bool_t use_getodelay; + + pa_bool_t sink_suspended, source_suspended; int fd; - pa_module *module; + int mode; + + int mixer_fd; + int mixer_devmask; + + int nfrags, frag_size; + + pa_bool_t use_mmap; + unsigned out_mmap_current, in_mmap_current; + void *in_mmap, *out_mmap; + pa_memblock **in_mmap_memblocks, **out_mmap_memblocks; + + int in_mmap_saved_nfrags, out_mmap_saved_nfrags; + + pa_rtpoll_item *rtpoll_item; }; static const char* const valid_modargs[] = { @@ -97,280 +146,1010 @@ static const char* const valid_modargs[] = { "rate", "channels", "channel_map", + "mmap", NULL }; -#define DEFAULT_DEVICE "/dev/dsp" +static void trigger(struct userdata *u, pa_bool_t quick) { + int enable_bits = 0, zero = 0; -static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, - (u->sink ? pa_sink_used_by(u->sink) : 0) + - (u->source ? pa_source_used_by(u->source) : 0)); -} + pa_assert(u); -static void clear_up(struct userdata *u) { - assert(u); + if (u->fd < 0) + return; - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - u->sink = NULL; - } + pa_log_debug("trigger"); - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - u->source = NULL; - } + if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state)) + enable_bits |= PCM_ENABLE_INPUT; - if (u->io) { - pa_iochannel_free(u->io); - u->io = NULL; - } -} + if (u->sink && PA_SINK_OPENED(u->sink->thread_info.state)) + enable_bits |= PCM_ENABLE_OUTPUT; -static void do_write(struct userdata *u) { - pa_memchunk *memchunk; - ssize_t r; - size_t l; - int loop = 0; + pa_log_debug("trigger: %i", enable_bits); - assert(u); - if (!u->sink || !pa_iochannel_is_writable(u->io)) - return; + if (u->use_mmap) { - update_usage(u); + if (!quick) + ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero); - l = u->out_fragment_size; +#ifdef SNDCTL_DSP_HALT + if (enable_bits == 0) + if (ioctl(u->fd, SNDCTL_DSP_HALT, NULL) < 0) + pa_log_warn("SNDCTL_DSP_HALT: %s", pa_cstrerror(errno)); +#endif - if (u->use_getospace) { - audio_buf_info info; + if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0) + pa_log_warn("SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno)); - if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) - u->use_getospace = 0; - else { - if (info.bytes/l > 0) { - l = (info.bytes/l)*l; - loop = 1; + if (u->sink && !(enable_bits & PCM_ENABLE_OUTPUT)) { + pa_log_debug("clearing playback buffer"); + pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &u->sink->sample_spec); + } + + } else { + + if (enable_bits) + if (ioctl(u->fd, SNDCTL_DSP_POST, NULL) < 0) + pa_log_warn("SNDCTL_DSP_POST: %s", pa_cstrerror(errno)); + + if (!quick) { + /* + * Some crappy drivers do not start the recording until we + * read something. Without this snippet, poll will never + * register the fd as ready. + */ + + if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state)) { + uint8_t *buf = pa_xnew(uint8_t, u->in_fragment_size); + pa_read(u->fd, buf, u->in_fragment_size, NULL); + pa_xfree(buf); } } } +} - do { - memchunk = &u->memchunk; +static void mmap_fill_memblocks(struct userdata *u, unsigned n) { + pa_assert(u); + pa_assert(u->out_mmap_memblocks); - if (!memchunk->length) - if (pa_sink_render(u->sink, l, memchunk) < 0) - memchunk = &u->silence; +/* pa_log("Mmmap writing %u blocks", n); */ - assert(memchunk->memblock); - assert(memchunk->memblock->data); - assert(memchunk->length); + while (n > 0) { + pa_memchunk chunk; - if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { + if (u->out_mmap_memblocks[u->out_mmap_current]) + pa_memblock_unref_fixed(u->out_mmap_memblocks[u->out_mmap_current]); - if (errno != EAGAIN) { - pa_log("write() failed: %s", pa_cstrerror(errno)); + chunk.memblock = u->out_mmap_memblocks[u->out_mmap_current] = + pa_memblock_new_fixed( + u->core->mempool, + (uint8_t*) u->out_mmap + u->out_fragment_size * u->out_mmap_current, + u->out_fragment_size, + 1); - clear_up(u); - pa_module_unload_request(u->module); - } + chunk.length = pa_memblock_get_length(chunk.memblock); + chunk.index = 0; - break; - } + pa_sink_render_into_full(u->sink, &chunk); - if (memchunk == &u->silence) - assert(r % u->sample_size == 0); - else { - u->memchunk.index += r; - u->memchunk.length -= r; + u->out_mmap_current++; + while (u->out_mmap_current >= u->out_nfrags) + u->out_mmap_current -= u->out_nfrags; - if (u->memchunk.length <= 0) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - } - } + n--; + } +} + +static int mmap_write(struct userdata *u) { + struct count_info info; + + pa_assert(u); + pa_assert(u->sink); + +/* pa_log("Mmmap writing..."); */ + + if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { + pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno)); + return -1; + } + + info.blocks += u->out_mmap_saved_nfrags; + u->out_mmap_saved_nfrags = 0; + + if (info.blocks > 0) + mmap_fill_memblocks(u, info.blocks); - l = l > (size_t) r ? l - r : 0; - } while (loop && l > 0); + return info.blocks; } -static void do_read(struct userdata *u) { - pa_memchunk memchunk; - ssize_t r; - size_t l; - int loop = 0; - assert(u); +static void mmap_post_memblocks(struct userdata *u, unsigned n) { + pa_assert(u); + pa_assert(u->in_mmap_memblocks); - if (!u->source || !pa_iochannel_is_readable(u->io) || !pa_idxset_size(u->source->outputs)) - return; +/* pa_log("Mmmap reading %u blocks", n); */ - update_usage(u); + while (n > 0) { + pa_memchunk chunk; - l = u->in_fragment_size; + if (!u->in_mmap_memblocks[u->in_mmap_current]) { - if (u->use_getispace) { - audio_buf_info info; + chunk.memblock = u->in_mmap_memblocks[u->in_mmap_current] = + pa_memblock_new_fixed( + u->core->mempool, + (uint8_t*) u->in_mmap + u->in_fragment_size*u->in_mmap_current, + u->in_fragment_size, + 1); - if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) - u->use_getispace = 0; - else { - if (info.bytes/l > 0) { - l = (info.bytes/l)*l; - loop = 1; - } + chunk.length = pa_memblock_get_length(chunk.memblock); + chunk.index = 0; + + pa_source_post(u->source, &chunk); } + + u->in_mmap_current++; + while (u->in_mmap_current >= u->in_nfrags) + u->in_mmap_current -= u->in_nfrags; + + n--; } +} - do { - memchunk.memblock = pa_memblock_new(u->core->mempool, l); - assert(memchunk.memblock); - if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { - pa_memblock_unref(memchunk.memblock); +static void mmap_clear_memblocks(struct userdata*u, unsigned n) { + unsigned i = u->in_mmap_current; - if (errno != EAGAIN) { - pa_log("read() failed: %s", pa_cstrerror(errno)); + pa_assert(u); + pa_assert(u->in_mmap_memblocks); - clear_up(u); - pa_module_unload_request(u->module); - } + if (n > u->in_nfrags) + n = u->in_nfrags; - break; + while (n > 0) { + if (u->in_mmap_memblocks[i]) { + pa_memblock_unref_fixed(u->in_mmap_memblocks[i]); + u->in_mmap_memblocks[i] = NULL; } - assert(r <= (ssize_t) memchunk.memblock->length); - memchunk.length = memchunk.memblock->length = r; - memchunk.index = 0; + i++; + while (i >= u->in_nfrags) + i -= u->in_nfrags; - pa_source_post(u->source, &memchunk); - pa_memblock_unref(memchunk.memblock); + n--; + } +} - l = l > (size_t) r ? l - r : 0; - } while (loop && l > 0); +static int mmap_read(struct userdata *u) { + struct count_info info; + pa_assert(u); + pa_assert(u->source); + +/* pa_log("Mmmap reading..."); */ + + if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { + pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno)); + return -1; + } + +/* pa_log("... %i", info.blocks); */ + + info.blocks += u->in_mmap_saved_nfrags; + u->in_mmap_saved_nfrags = 0; + + if (info.blocks > 0) { + mmap_post_memblocks(u, info.blocks); + mmap_clear_memblocks(u, u->in_nfrags/2); + } + + return info.blocks; } -static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { - struct userdata *u = userdata; - assert(u); - do_write(u); - do_read(u); +static pa_usec_t mmap_sink_get_latency(struct userdata *u) { + struct count_info info; + size_t bpos, n; + + pa_assert(u); + + if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { + pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno)); + return 0; + } + + u->out_mmap_saved_nfrags += info.blocks; + + bpos = ((u->out_mmap_current + u->out_mmap_saved_nfrags) * u->out_fragment_size) % u->out_hwbuf_size; + + if (bpos <= (size_t) info.ptr) + n = u->out_hwbuf_size - (info.ptr - bpos); + else + n = bpos - info.ptr; + +/* pa_log("n = %u, bpos = %u, ptr = %u, total=%u, fragsize = %u, n_frags = %u\n", n, bpos, (unsigned) info.ptr, total, u->out_fragment_size, u->out_fragments); */ + + return pa_bytes_to_usec(n, &u->sink->sample_spec); } -static void source_notify_cb(pa_source *s) { - struct userdata *u = s->userdata; - assert(u); - do_read(u); +static pa_usec_t mmap_source_get_latency(struct userdata *u) { + struct count_info info; + size_t bpos, n; + + pa_assert(u); + + if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { + pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno)); + return 0; + } + + u->in_mmap_saved_nfrags += info.blocks; + bpos = ((u->in_mmap_current + u->in_mmap_saved_nfrags) * u->in_fragment_size) % u->in_hwbuf_size; + + if (bpos <= (size_t) info.ptr) + n = info.ptr - bpos; + else + n = u->in_hwbuf_size - bpos + info.ptr; + +/* pa_log("n = %u, bpos = %u, ptr = %u, total=%u, fragsize = %u, n_frags = %u\n", n, bpos, (unsigned) info.ptr, total, u->in_fragment_size, u->in_fragments); */ + + return pa_bytes_to_usec(n, &u->source->sample_spec); } -static pa_usec_t sink_get_latency_cb(pa_sink *s) { +static pa_usec_t io_sink_get_latency(struct userdata *u) { pa_usec_t r = 0; - int arg; - struct userdata *u = s->userdata; - assert(s && u && u->sink); - if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { - pa_log_info("device doesn't support SNDCTL_DSP_GETODELAY: %s", pa_cstrerror(errno)); - s->get_latency = NULL; - return 0; + pa_assert(u); + + if (u->use_getodelay) { + int arg; + + if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { + pa_log_info("Device doesn't support SNDCTL_DSP_GETODELAY: %s", pa_cstrerror(errno)); + u->use_getodelay = 0; + } else + r = pa_bytes_to_usec(arg, &u->sink->sample_spec); + } - r += pa_bytes_to_usec(arg, &s->sample_spec); + if (!u->use_getodelay && u->use_getospace) { + struct audio_buf_info info; + + if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { + pa_log_info("Device doesn't support SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno)); + u->use_getospace = 0; + } else + r = pa_bytes_to_usec(info.bytes, &u->sink->sample_spec); + } if (u->memchunk.memblock) - r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec); + r += pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec); return r; } -static pa_usec_t source_get_latency_cb(pa_source *s) { - struct userdata *u = s->userdata; - audio_buf_info info; - assert(s && u && u->source); - if (!u->use_getispace) - return 0; +static pa_usec_t io_source_get_latency(struct userdata *u) { + pa_usec_t r = 0; - if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { - u->use_getispace = 0; - return 0; + pa_assert(u); + + if (u->use_getispace) { + struct audio_buf_info info; + + if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { + pa_log_info("Device doesn't support SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno)); + u->use_getispace = 0; + } else + r = pa_bytes_to_usec(info.bytes, &u->source->sample_spec); } - if (info.bytes <= 0) - return 0; + return r; +} + +static void build_pollfd(struct userdata *u) { + struct pollfd *pollfd; - return pa_bytes_to_usec(info.bytes, &s->sample_spec); + pa_assert(u); + pa_assert(u->fd >= 0); + + if (u->rtpoll_item) + pa_rtpoll_item_free(u->rtpoll_item); + + u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + pollfd->fd = u->fd; + pollfd->events = 0; + pollfd->revents = 0; } -static int sink_get_hw_volume(pa_sink *s) { - struct userdata *u = s->userdata; +static int suspend(struct userdata *u) { + pa_assert(u); + pa_assert(u->fd >= 0); - if (pa_oss_get_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info("device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); - s->get_hw_volume = NULL; - return -1; + pa_log_info("Suspending..."); + + if (u->out_mmap_memblocks) { + unsigned i; + for (i = 0; i < u->out_nfrags; i++) + if (u->out_mmap_memblocks[i]) { + pa_memblock_unref_fixed(u->out_mmap_memblocks[i]); + u->out_mmap_memblocks[i] = NULL; + } } + if (u->in_mmap_memblocks) { + unsigned i; + for (i = 0; i < u->in_nfrags; i++) + if (u->in_mmap_memblocks[i]) { + pa_memblock_unref_fixed(u->in_mmap_memblocks[i]); + u->in_mmap_memblocks[i] = NULL; + } + } + + if (u->in_mmap && u->in_mmap != MAP_FAILED) { + munmap(u->in_mmap, u->in_hwbuf_size); + u->in_mmap = NULL; + } + + if (u->out_mmap && u->out_mmap != MAP_FAILED) { + munmap(u->out_mmap, u->out_hwbuf_size); + u->out_mmap = NULL; + } + + /* Let's suspend */ + ioctl(u->fd, SNDCTL_DSP_SYNC, NULL); + pa_close(u->fd); + u->fd = -1; + + if (u->rtpoll_item) { + pa_rtpoll_item_free(u->rtpoll_item); + u->rtpoll_item = NULL; + } + + pa_log_info("Device suspended..."); + return 0; } -static int sink_set_hw_volume(pa_sink *s) { - struct userdata *u = s->userdata; +static int unsuspend(struct userdata *u) { + int m; + pa_sample_spec ss, *ss_original; + int frag_size, in_frag_size, out_frag_size; + int in_nfrags, out_nfrags; + struct audio_buf_info info; + + pa_assert(u); + pa_assert(u->fd < 0); + + m = u->mode; + + pa_log_info("Trying resume..."); - if (pa_oss_set_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info("device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); - s->set_hw_volume = NULL; + if ((u->fd = pa_oss_open(u->device_name, &m, NULL)) < 0) { + pa_log_warn("Resume failed, device busy (%s)", pa_cstrerror(errno)); return -1; + + if (m != u->mode) + pa_log_warn("Resume failed, couldn't open device with original access mode."); + goto fail; + } + + if (u->nfrags >= 2 && u->frag_size >= 1) + if (pa_oss_set_fragments(u->fd, u->nfrags, u->frag_size) < 0) { + pa_log_warn("Resume failed, couldn't set original fragment settings."); + goto fail; + } + + ss = *(ss_original = u->sink ? &u->sink->sample_spec : &u->source->sample_spec); + if (pa_oss_auto_format(u->fd, &ss) < 0 || !pa_sample_spec_equal(&ss, ss_original)) { + pa_log_warn("Resume failed, couldn't set original sample format settings."); + goto fail; + } + + if (ioctl(u->fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) { + pa_log_warn("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno)); + goto fail; + } + + in_frag_size = out_frag_size = frag_size; + in_nfrags = out_nfrags = u->nfrags; + + if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { + in_frag_size = info.fragsize; + in_nfrags = info.fragstotal; + } + + if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) { + out_frag_size = info.fragsize; + out_nfrags = info.fragstotal; + } + + if ((u->source && (in_frag_size != (int) u->in_fragment_size || in_nfrags != (int) u->in_nfrags)) || + (u->sink && (out_frag_size != (int) u->out_fragment_size || out_nfrags != (int) u->out_nfrags))) { + pa_log_warn("Resume failed, input fragment settings don't match."); + goto fail; + } + + if (u->use_mmap) { + if (u->source) { + if ((u->in_mmap = mmap(NULL, u->in_hwbuf_size, PROT_READ, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { + pa_log("Resume failed, mmap(): %s", pa_cstrerror(errno)); + goto fail; + } + } + + if (u->sink) { + if ((u->out_mmap = mmap(NULL, u->out_hwbuf_size, PROT_WRITE, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { + pa_log("Resume failed, mmap(): %s", pa_cstrerror(errno)); + if (u->in_mmap && u->in_mmap != MAP_FAILED) { + munmap(u->in_mmap, u->in_hwbuf_size); + u->in_mmap = NULL; + } + + goto fail; + } + + pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &ss); + } } + u->out_mmap_current = u->in_mmap_current = 0; + u->out_mmap_saved_nfrags = u->in_mmap_saved_nfrags = 0; + + pa_assert(!u->rtpoll_item); + + build_pollfd(u); + + if (u->sink) + pa_sink_get_volume(u->sink); + if (u->source) + pa_source_get_volume(u->source); + + pa_log_info("Resumed successfully..."); + return 0; + +fail: + pa_close(u->fd); + u->fd = -1; + return -1; } -static int source_get_hw_volume(pa_source *s) { - struct userdata *u = s->userdata; +static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SINK(o)->userdata; + int ret; + pa_bool_t do_trigger = FALSE, quick = TRUE; + + switch (code) { + + case PA_SINK_MESSAGE_GET_LATENCY: { + pa_usec_t r = 0; + + if (u->fd >= 0) { + if (u->use_mmap) + r = mmap_sink_get_latency(u); + else + r = io_sink_get_latency(u); + } + + *((pa_usec_t*) data) = r; + + return 0; + } + + case PA_SINK_MESSAGE_SET_STATE: + + switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) { + + case PA_SINK_SUSPENDED: + pa_assert(PA_SINK_OPENED(u->sink->thread_info.state)); + + if (!u->source || u->source_suspended) { + if (suspend(u) < 0) + return -1; + } + + do_trigger = TRUE; + + u->sink_suspended = TRUE; + break; + + case PA_SINK_IDLE: + case PA_SINK_RUNNING: + + if (u->sink->thread_info.state == PA_SINK_INIT) { + do_trigger = TRUE; + quick = u->source && PA_SOURCE_OPENED(u->source->thread_info.state); + } + + if (u->sink->thread_info.state == PA_SINK_SUSPENDED) { + + if (!u->source || u->source_suspended) { + if (unsuspend(u) < 0) + return -1; + quick = FALSE; + } + + do_trigger = TRUE; + + u->out_mmap_current = 0; + u->out_mmap_saved_nfrags = 0; + + u->sink_suspended = FALSE; + } + + break; + + case PA_SINK_UNLINKED: + case PA_SINK_INIT: + ; + } + + break; - if (pa_oss_get_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info("device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); - s->get_hw_volume = NULL; - return -1; } - return 0; + ret = pa_sink_process_msg(o, code, data, offset, chunk); + + if (do_trigger) + trigger(u, quick); + + return ret; } -static int source_set_hw_volume(pa_source *s) { - struct userdata *u = s->userdata; +static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SOURCE(o)->userdata; + int ret; + int do_trigger = FALSE, quick = TRUE; + + switch (code) { + + case PA_SOURCE_MESSAGE_GET_LATENCY: { + pa_usec_t r = 0; + + if (u->fd >= 0) { + if (u->use_mmap) + r = mmap_source_get_latency(u); + else + r = io_source_get_latency(u); + } + + *((pa_usec_t*) data) = r; + return 0; + } + + case PA_SOURCE_MESSAGE_SET_STATE: + + switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) { + case PA_SOURCE_SUSPENDED: + pa_assert(PA_SOURCE_OPENED(u->source->thread_info.state)); + + if (!u->sink || u->sink_suspended) { + if (suspend(u) < 0) + return -1; + } + + do_trigger = TRUE; + + u->source_suspended = TRUE; + break; + + case PA_SOURCE_IDLE: + case PA_SOURCE_RUNNING: + + if (u->source->thread_info.state == PA_SOURCE_INIT) { + do_trigger = TRUE; + quick = u->sink && PA_SINK_OPENED(u->sink->thread_info.state); + } + + if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) { + + if (!u->sink || u->sink_suspended) { + if (unsuspend(u) < 0) + return -1; + quick = FALSE; + } + + do_trigger = TRUE; + + u->in_mmap_current = 0; + u->in_mmap_saved_nfrags = 0; + + u->source_suspended = FALSE; + } + break; + + case PA_SOURCE_UNLINKED: + case PA_SOURCE_INIT: + ; + + } + break; - if (pa_oss_set_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info("device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); - s->set_hw_volume = NULL; - return -1; } - return 0; + ret = pa_source_process_msg(o, code, data, offset, chunk); + + if (do_trigger) + trigger(u, quick); + + return ret; +} + +static int sink_get_volume(pa_sink *s) { + struct userdata *u; + int r; + + pa_assert_se(u = s->userdata); + + pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM)); + + if (u->mixer_devmask & SOUND_MASK_VOLUME) + if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_VOLUME, &s->sample_spec, &s->volume)) >= 0) + return r; + + if (u->mixer_devmask & SOUND_MASK_PCM) + if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_PCM, &s->sample_spec, &s->volume)) >= 0) + return r; + + pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); + return -1; +} + +static int sink_set_volume(pa_sink *s) { + struct userdata *u; + int r; + + pa_assert_se(u = s->userdata); + + pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM)); + + if (u->mixer_devmask & SOUND_MASK_VOLUME) + if ((r = pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_VOLUME, &s->sample_spec, &s->volume)) >= 0) + return r; + + if (u->mixer_devmask & SOUND_MASK_PCM) + if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_PCM, &s->sample_spec, &s->volume)) >= 0) + return r; + + pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); + return -1; } -int pa__init(pa_core *c, pa_module*m) { +static int source_get_volume(pa_source *s) { + struct userdata *u; + int r; + + pa_assert_se(u = s->userdata); + + pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV)); + + if (u->mixer_devmask & SOUND_MASK_IGAIN) + if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_IGAIN, &s->sample_spec, &s->volume)) >= 0) + return r; + + if (u->mixer_devmask & SOUND_MASK_RECLEV) + if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_RECLEV, &s->sample_spec, &s->volume)) >= 0) + return r; + + pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); + return -1; +} + +static int source_set_volume(pa_source *s) { + struct userdata *u; + int r; + + pa_assert_se(u = s->userdata); + + pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV)); + + if (u->mixer_devmask & SOUND_MASK_IGAIN) + if ((r = pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_IGAIN, &s->sample_spec, &s->volume)) >= 0) + return r; + + if (u->mixer_devmask & SOUND_MASK_RECLEV) + if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_RECLEV, &s->sample_spec, &s->volume)) >= 0) + return r; + + pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); + return -1; +} + +static void thread_func(void *userdata) { + struct userdata *u = userdata; + int write_type = 0, read_type = 0; + unsigned short revents = 0; + + pa_assert(u); + + pa_log_debug("Thread starting up"); + + if (u->core->high_priority) + pa_make_realtime(); + + pa_thread_mq_install(&u->thread_mq); + pa_rtpoll_install(u->rtpoll); + + for (;;) { + int ret; + +/* pa_log("loop"); */ + + /* Render some data and write it to the dsp */ + + if (u->sink && PA_SINK_OPENED(u->sink->thread_info.state) && ((revents & POLLOUT) || u->use_mmap || u->use_getospace)) { + + if (u->use_mmap) { + + if ((ret = mmap_write(u)) < 0) + goto fail; + + revents &= ~POLLOUT; + + if (ret > 0) + continue; + + } else { + ssize_t l; + pa_bool_t loop = FALSE, work_done = FALSE; + + l = u->out_fragment_size; + + if (u->use_getospace) { + audio_buf_info info; + + if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { + pa_log_info("Device doesn't support SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno)); + u->use_getospace = FALSE; + } else { + l = info.bytes; + + /* We loop only if GETOSPACE worked and we + * actually *know* that we can write more than + * one fragment at a time */ + loop = TRUE; + } + } + + /* Round down to multiples of the fragment size, + * because OSS needs that (at least some versions + * do) */ + l = (l/u->out_fragment_size) * u->out_fragment_size; + + /* Hmm, so poll() signalled us that we can read + * something, but GETOSPACE told us there was nothing? + * Hmm, make the best of it, try to read some data, to + * avoid spinning forever. */ + if (l <= 0 && (revents & POLLOUT)) { + l = u->out_fragment_size; + loop = FALSE; + } + + while (l > 0) { + void *p; + ssize_t t; + + if (u->memchunk.length <= 0) + pa_sink_render(u->sink, l, &u->memchunk); + + pa_assert(u->memchunk.length > 0); + + p = pa_memblock_acquire(u->memchunk.memblock); + t = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, &write_type); + pa_memblock_release(u->memchunk.memblock); + +/* pa_log("wrote %i bytes of %u", t, l); */ + + pa_assert(t != 0); + + if (t < 0) { + + if (errno == EINTR) + continue; + + else if (errno == EAGAIN) { + pa_log_debug("EAGAIN"); + + revents &= ~POLLOUT; + break; + + } else { + pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno)); + goto fail; + } + + } else { + + u->memchunk.index += t; + u->memchunk.length -= t; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + pa_memchunk_reset(&u->memchunk); + } + + l -= t; + + revents &= ~POLLOUT; + work_done = TRUE; + } + + if (!loop) + break; + } + + if (work_done) + continue; + } + } + + /* Try to read some data and pass it on to the source driver. */ + + if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state) && ((revents & POLLIN) || u->use_mmap || u->use_getispace)) { + + if (u->use_mmap) { + + if ((ret = mmap_read(u)) < 0) + goto fail; + + revents &= ~POLLIN; + + if (ret > 0) + continue; + + } else { + + void *p; + ssize_t l; + pa_memchunk memchunk; + pa_bool_t loop = FALSE, work_done = FALSE; + + l = u->in_fragment_size; + + if (u->use_getispace) { + audio_buf_info info; + + if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { + pa_log_info("Device doesn't support SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno)); + u->use_getispace = FALSE; + } else { + l = info.bytes; + loop = TRUE; + } + } + + l = (l/u->in_fragment_size) * u->in_fragment_size; + + if (l <= 0 && (revents & POLLIN)) { + l = u->in_fragment_size; + loop = FALSE; + } + + while (l > 0) { + ssize_t t, k; + + pa_assert(l > 0); + + memchunk.memblock = pa_memblock_new(u->core->mempool, (size_t) -1); + + k = pa_memblock_get_length(memchunk.memblock); + + if (k > l) + k = l; + + k = (k/u->frame_size)*u->frame_size; + + p = pa_memblock_acquire(memchunk.memblock); + t = pa_read(u->fd, p, k, &read_type); + pa_memblock_release(memchunk.memblock); + + pa_assert(t != 0); /* EOF cannot happen */ + +/* pa_log("read %i bytes of %u", t, l); */ + + if (t < 0) { + pa_memblock_unref(memchunk.memblock); + + if (errno == EINTR) + continue; + + else if (errno == EAGAIN) { + pa_log_debug("EAGAIN"); + + revents &= ~POLLIN; + break; + + } else { + pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno)); + goto fail; + } + + } else { + memchunk.index = 0; + memchunk.length = t; + + pa_source_post(u->source, &memchunk); + pa_memblock_unref(memchunk.memblock); + + l -= t; + + revents &= ~POLLIN; + work_done = TRUE; + } + + if (!loop) + break; + } + + if (work_done) + continue; + } + } + +/* pa_log("loop2 revents=%i", revents); */ + + if (u->rtpoll_item) { + struct pollfd *pollfd; + + pa_assert(u->fd >= 0); + + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + pollfd->events = + ((u->source && PA_SOURCE_OPENED(u->source->thread_info.state)) ? POLLIN : 0) | + ((u->sink && PA_SINK_OPENED(u->sink->thread_info.state)) ? POLLOUT : 0); + } + + /* Hmm, nothing to do. Let's sleep */ + if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0) + goto fail; + + if (ret == 0) + goto finish; + + if (u->rtpoll_item) { + struct pollfd *pollfd; + + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + + if (pollfd->revents & ~(POLLOUT|POLLIN)) { + pa_log("DSP shutdown."); + goto fail; + } + + revents = pollfd->revents; + } else + revents = 0; + } + +fail: + /* If this was no regular exit from the loop we have to continue + * processing messages until we received PA_MESSAGE_SHUTDOWN */ + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); + +finish: + pa_log_debug("Thread shutting down"); +} + +int pa__init(pa_module*m) { + struct audio_buf_info info; struct userdata *u = NULL; - const char *p; + const char *dev; int fd = -1; - int nfrags, frag_size, in_frag_size, out_frag_size; - int mode; - int record = 1, playback = 1; + int nfrags, frag_size; + int mode, caps; + int record = 1, playback = 1, use_mmap = 1; pa_sample_spec ss; pa_channel_map map; pa_modargs *ma = NULL; char hwdesc[64], *t; const char *name; - char *name_buf = NULL; int namereg_fail; - assert(c); - assert(m); + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log("failed to parse module arguments."); + pa_log("Failed to parse module arguments."); goto fail; } @@ -380,36 +1159,52 @@ int pa__init(pa_core *c, pa_module*m) { } if (!playback && !record) { - pa_log("neither playback nor record enabled for device."); + pa_log("Neither playback nor record enabled for device."); goto fail; } - mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); + mode = (playback && record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); - ss = c->default_sample_spec; + ss = m->core->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_OSS) < 0) { - pa_log("failed to parse sample specification or channel map"); + pa_log("Failed to parse sample specification or channel map"); goto fail; } - /* Fix latency to 100ms */ - nfrags = 12; - frag_size = pa_bytes_per_second(&ss)/128; + nfrags = m->core->default_n_fragments; + frag_size = pa_usec_to_bytes(m->core->default_fragment_size_msec*1000, &ss); + if (frag_size <= 0) + frag_size = pa_frame_size(&ss); if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { - pa_log("failed to parse fragments arguments"); + pa_log("Failed to parse fragments arguments"); goto fail; } - if ((fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, NULL)) < 0) + if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) { + pa_log("Failed to parse mmap argument."); goto fail; + } - if (pa_oss_get_hw_description(p, hwdesc, sizeof(hwdesc)) >= 0) - pa_log_info("hardware name is '%s'.", hwdesc); + if ((fd = pa_oss_open(dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0) + goto fail; + + if (use_mmap && (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_TRIGGER))) { + pa_log_info("OSS device not mmap capable, falling back to UNIX read/write mode."); + use_mmap = 0; + } + + if (use_mmap && mode == O_WRONLY) { + pa_log_info("Device opened for playback only, cannot do memory mapping, falling back to UNIX write() mode."); + use_mmap = 0; + } + + if (pa_oss_get_hw_description(dev, hwdesc, sizeof(hwdesc)) >= 0) + pa_log_info("Hardware name is '%s'.", hwdesc); else hwdesc[0] = 0; - pa_log_info("device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + pa_log_info("Device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); if (nfrags >= 2 && frag_size >= 1) if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) @@ -422,152 +1217,282 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno)); goto fail; } - assert(frag_size); - in_frag_size = out_frag_size = frag_size; + pa_assert(frag_size > 0); - u = pa_xmalloc(sizeof(struct userdata)); - u->core = c; - u->use_getospace = u->use_getispace = 0; + u = pa_xnew0(struct userdata, 1); + u->core = m->core; + u->module = m; + m->userdata = u; + u->fd = fd; + u->mixer_fd = -1; + u->use_getospace = u->use_getispace = 1; + u->use_getodelay = 1; + u->mode = mode; + u->frame_size = pa_frame_size(&ss); + u->device_name = pa_xstrdup(dev); + u->in_nfrags = u->out_nfrags = u->nfrags = nfrags; + u->out_fragment_size = u->in_fragment_size = u->frag_size = frag_size; + u->use_mmap = use_mmap; + pa_thread_mq_init(&u->thread_mq, m->core->mainloop); + u->rtpoll = pa_rtpoll_new(); + pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq); + u->rtpoll_item = NULL; + build_pollfd(u); if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { - pa_log_info("input -- %u fragments of size %u.", info.fragstotal, info.fragsize); - in_frag_size = info.fragsize; + pa_log_info("Input -- %u fragments of size %u.", info.fragstotal, info.fragsize); + u->in_fragment_size = info.fragsize; + u->in_nfrags = info.fragstotal; u->use_getispace = 1; } if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) { - pa_log_info("output -- %u fragments of size %u.", info.fragstotal, info.fragsize); - out_frag_size = info.fragsize; + pa_log_info("Output -- %u fragments of size %u.", info.fragstotal, info.fragsize); + u->out_fragment_size = info.fragsize; + u->out_nfrags = info.fragstotal; u->use_getospace = 1; } + u->in_hwbuf_size = u->in_nfrags * u->in_fragment_size; + u->out_hwbuf_size = u->out_nfrags * u->out_fragment_size; + if (mode != O_WRONLY) { + char *name_buf = NULL; + + if (use_mmap) { + if ((u->in_mmap = mmap(NULL, u->in_hwbuf_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { + pa_log_warn("mmap(PROT_READ) failed, reverting to non-mmap mode: %s", pa_cstrerror(errno)); + use_mmap = u->use_mmap = 0; + u->in_mmap = NULL; + } else + pa_log_debug("Successfully mmap()ed input buffer."); + } + if ((name = pa_modargs_get_value(ma, "source_name", NULL))) namereg_fail = 1; else { - name = name_buf = pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(p)); + name = name_buf = pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(dev)); namereg_fail = 0; } - if (!(u->source = pa_source_new(c, __FILE__, name, namereg_fail, &ss, &map))) + u->source = pa_source_new(m->core, __FILE__, name, namereg_fail, &ss, &map); + pa_xfree(name_buf); + if (!u->source) { + pa_log("Failed to create source object"); goto fail; + } + u->source->parent.process_msg = source_process_msg; u->source->userdata = u; - u->source->notify = source_notify_cb; - u->source->get_latency = source_get_latency_cb; - u->source->get_hw_volume = source_get_hw_volume; - u->source->set_hw_volume = source_set_hw_volume; - pa_source_set_owner(u->source, m); - pa_source_set_description(u->source, t = pa_sprintf_malloc("OSS PCM on %s%s%s%s", - p, - hwdesc[0] ? " (" : "", - hwdesc[0] ? hwdesc : "", - hwdesc[0] ? ")" : "")); + + pa_source_set_module(u->source, m); + pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); + pa_source_set_rtpoll(u->source, u->rtpoll); + pa_source_set_description(u->source, t = pa_sprintf_malloc( + "OSS PCM on %s%s%s%s%s", + dev, + hwdesc[0] ? " (" : "", + hwdesc[0] ? hwdesc : "", + hwdesc[0] ? ")" : "", + use_mmap ? " via DMA" : "")); pa_xfree(t); - u->source->is_hardware = 1; - } else - u->source = NULL; + u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY; + u->source->refresh_volume = TRUE; - pa_xfree(name_buf); - name_buf = NULL; + if (use_mmap) + u->in_mmap_memblocks = pa_xnew0(pa_memblock*, u->in_nfrags); + } if (mode != O_RDONLY) { + char *name_buf = NULL; + + if (use_mmap) { + if ((u->out_mmap = mmap(NULL, u->out_hwbuf_size, PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { + if (mode == O_RDWR) { + pa_log_debug("mmap() failed for input. Changing to O_WRONLY mode."); + mode = O_WRONLY; + goto go_on; + } else { + pa_log_warn("mmap(PROT_WRITE) failed, reverting to non-mmap mode: %s", pa_cstrerror(errno)); + u->use_mmap = (use_mmap = FALSE); + u->out_mmap = NULL; + } + } else { + pa_log_debug("Successfully mmap()ed output buffer."); + pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &ss); + } + } + if ((name = pa_modargs_get_value(ma, "sink_name", NULL))) namereg_fail = 1; else { - name = name_buf = pa_sprintf_malloc("oss_output.%s", pa_path_get_filename(p)); + name = name_buf = pa_sprintf_malloc("oss_output.%s", pa_path_get_filename(dev)); namereg_fail = 0; } - if (!(u->sink = pa_sink_new(c, __FILE__, name, namereg_fail, &ss, &map))) + u->sink = pa_sink_new(m->core, __FILE__, name, namereg_fail, &ss, &map); + pa_xfree(name_buf); + if (!u->sink) { + pa_log("Failed to create sink object"); goto fail; + } - u->sink->get_latency = sink_get_latency_cb; - u->sink->get_hw_volume = sink_get_hw_volume; - u->sink->set_hw_volume = sink_set_hw_volume; + u->sink->parent.process_msg = sink_process_msg; u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - pa_sink_set_description(u->sink, t = pa_sprintf_malloc("OSS PCM on %s%s%s%s", - p, - hwdesc[0] ? " (" : "", - hwdesc[0] ? hwdesc : "", - hwdesc[0] ? ")" : "")); + + pa_sink_set_module(u->sink, m); + pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); + pa_sink_set_rtpoll(u->sink, u->rtpoll); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc( + "OSS PCM on %s%s%s%s%s", + dev, + hwdesc[0] ? " (" : "", + hwdesc[0] ? hwdesc : "", + hwdesc[0] ? ")" : "", + use_mmap ? " via DMA" : "")); pa_xfree(t); - u->sink->is_hardware = 1; - } else - u->sink = NULL; + u->sink->flags = PA_SINK_HARDWARE|PA_SINK_LATENCY; + u->sink->refresh_volume = TRUE; - pa_xfree(name_buf); - name_buf = NULL; + if (use_mmap) + u->out_mmap_memblocks = pa_xnew0(pa_memblock*, u->out_nfrags); + } - assert(u->source || u->sink); + if ((u->mixer_fd = pa_oss_open_mixer_for_device(u->device_name)) >= 0) { + int do_close = 1; + u->mixer_devmask = 0; - u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : -1); - assert(u->io); - pa_iochannel_set_callback(u->io, io_callback, u); - u->fd = fd; + if (ioctl(fd, SOUND_MIXER_READ_DEVMASK, &u->mixer_devmask) < 0) + pa_log_warn("SOUND_MIXER_READ_DEVMASK failed: %s", pa_cstrerror(errno)); - u->memchunk.memblock = NULL; - u->memchunk.length = 0; - u->sample_size = pa_frame_size(&ss); + else { + if (u->sink && (u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM))) { + pa_log_debug("Found hardware mixer track for playback."); + u->sink->flags |= PA_SINK_HW_VOLUME_CTRL; + u->sink->get_volume = sink_get_volume; + u->sink->set_volume = sink_set_volume; + do_close = 0; + } - u->out_fragment_size = out_frag_size; - u->in_fragment_size = in_frag_size; - u->silence.memblock = pa_memblock_new(u->core->mempool, u->silence.length = u->out_fragment_size); - assert(u->silence.memblock); - pa_silence_memblock(u->silence.memblock, &ss); - u->silence.index = 0; + if (u->source && (u->mixer_devmask & (SOUND_MASK_RECLEV|SOUND_MASK_IGAIN))) { + pa_log_debug("Found hardware mixer track for recording."); + u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL; + u->source->get_volume = source_get_volume; + u->source->set_volume = source_set_volume; + do_close = 0; + } + } - u->module = m; - m->userdata = u; + if (do_close) { + pa_close(u->mixer_fd); + u->mixer_fd = -1; + } + } - pa_modargs_free(ma); +go_on: + + pa_assert(u->source || u->sink); - /* - * Some crappy drivers do not start the recording until we read something. - * Without this snippet, poll will never register the fd as ready. - */ - if (u->source) { - char *buf = pa_xnew(char, u->sample_size); - pa_read(u->fd, buf, u->sample_size, NULL); - pa_xfree(buf); + pa_memchunk_reset(&u->memchunk); + + if (!(u->thread = pa_thread_new(thread_func, u))) { + pa_log("Failed to create thread."); + goto fail; } /* Read mixer settings */ - if (u->source) - source_get_hw_volume(u->source); + if (u->sink && u->sink->get_volume) + sink_get_volume(u->sink); + if (u->source && u->source->get_volume) + source_get_volume(u->source); + if (u->sink) - sink_get_hw_volume(u->sink); + pa_sink_put(u->sink); + if (u->source) + pa_source_put(u->source); + + pa_modargs_free(ma); return 0; fail: - if (fd >= 0) - close(fd); + + if (u) + pa__done(m); + else if (fd >= 0) + pa_close(fd); if (ma) pa_modargs_free(ma); - pa_xfree(name_buf); - return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata *u; - assert(c); - assert(m); + pa_assert(m); if (!(u = m->userdata)) return; - clear_up(u); + if (u->sink) + pa_sink_unlink(u->sink); + + if (u->source) + pa_source_unlink(u->source); + + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); + } + + pa_thread_mq_done(&u->thread_mq); + + if (u->sink) + pa_sink_unref(u->sink); + + if (u->source) + pa_source_unref(u->source); if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); - if (u->silence.memblock) - pa_memblock_unref(u->silence.memblock); + + if (u->rtpoll_item) + pa_rtpoll_item_free(u->rtpoll_item); + + if (u->rtpoll) + pa_rtpoll_free(u->rtpoll); + + if (u->out_mmap_memblocks) { + unsigned i; + for (i = 0; i < u->out_nfrags; i++) + if (u->out_mmap_memblocks[i]) + pa_memblock_unref_fixed(u->out_mmap_memblocks[i]); + pa_xfree(u->out_mmap_memblocks); + } + + if (u->in_mmap_memblocks) { + unsigned i; + for (i = 0; i < u->in_nfrags; i++) + if (u->in_mmap_memblocks[i]) + pa_memblock_unref_fixed(u->in_mmap_memblocks[i]); + pa_xfree(u->in_mmap_memblocks); + } + + if (u->in_mmap && u->in_mmap != MAP_FAILED) + munmap(u->in_mmap, u->in_hwbuf_size); + + if (u->out_mmap && u->out_mmap != MAP_FAILED) + munmap(u->out_mmap, u->out_hwbuf_size); + + if (u->fd >= 0) + pa_close(u->fd); + + if (u->mixer_fd >= 0) + pa_close(u->mixer_fd); + + pa_xfree(u->device_name); pa_xfree(u); } diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index 170b046e..75748474 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -28,22 +28,25 @@ #include #include #include -#include #include #include #include #include #include +#include +#include #include #include -#include #include #include #include #include #include +#include +#include +#include #include "module-pipe-sink-symdef.h" @@ -58,20 +61,24 @@ PA_MODULE_USAGE( "rate=" "channel_map=") -#define DEFAULT_FIFO_NAME "/tmp/music.output" +#define DEFAULT_FILE_NAME "/tmp/music.output" #define DEFAULT_SINK_NAME "fifo_output" struct userdata { pa_core *core; + pa_module *module; + pa_sink *sink; - char *filename; + pa_thread *thread; + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; - pa_sink *sink; - pa_iochannel *io; - pa_defer_event *defer_event; + char *filename; + int fd; pa_memchunk memchunk; - pa_module *module; + + pa_rtpoll_item *rtpoll_item; }; static const char* const valid_modargs[] = { @@ -84,133 +91,191 @@ static const char* const valid_modargs[] = { NULL }; -static void do_write(struct userdata *u) { - ssize_t r; - assert(u); +static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SINK(o)->userdata; - u->core->mainloop->defer_enable(u->defer_event, 0); + switch (code) { - if (!pa_iochannel_is_writable(u->io)) - return; + case PA_SINK_MESSAGE_GET_LATENCY: { + size_t n = 0; + int l; - pa_module_set_used(u->module, pa_sink_used_by(u->sink)); - - if (!u->memchunk.length) - if (pa_sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0) - return; +#ifdef TIOCINQ + if (ioctl(u->fd, TIOCINQ, &l) >= 0 && l > 0) + n = (size_t) l; +#endif - assert(u->memchunk.memblock && u->memchunk.length); + n += u->memchunk.length; - if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) { - pa_log("write(): %s", pa_cstrerror(errno)); - return; + *((pa_usec_t*) data) = pa_bytes_to_usec(n, &u->sink->sample_spec); + break; + } } - u->memchunk.index += r; - u->memchunk.length -= r; - - if (u->memchunk.length <= 0) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - } + return pa_sink_process_msg(o, code, data, offset, chunk); } -static void notify_cb(pa_sink*s) { - struct userdata *u = s->userdata; - assert(s && u); +static void thread_func(void *userdata) { + struct userdata *u = userdata; + int write_type = 0; - if (pa_iochannel_is_writable(u->io)) - u->core->mainloop->defer_enable(u->defer_event, 1); -} + pa_assert(u); -static pa_usec_t get_latency_cb(pa_sink *s) { - struct userdata *u = s->userdata; - assert(s && u); + pa_log_debug("Thread starting up"); - return u->memchunk.memblock ? pa_bytes_to_usec(u->memchunk.length, &s->sample_spec) : 0; -} + pa_thread_mq_install(&u->thread_mq); + pa_rtpoll_install(u->rtpoll); -static void defer_callback(PA_GCC_UNUSED pa_mainloop_api *m, PA_GCC_UNUSED pa_defer_event*e, void *userdata) { - struct userdata *u = userdata; - assert(u); - do_write(u); -} + for (;;) { + struct pollfd *pollfd; + int ret; -static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { - struct userdata *u = userdata; - assert(u); - do_write(u); + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + + /* Render some data and write it to the fifo */ + if (u->sink->thread_info.state == PA_SINK_RUNNING && pollfd->revents) { + ssize_t l; + void *p; + + if (u->memchunk.length <= 0) + pa_sink_render(u->sink, PIPE_BUF, &u->memchunk); + + pa_assert(u->memchunk.length > 0); + + p = pa_memblock_acquire(u->memchunk.memblock); + l = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, &write_type); + pa_memblock_release(u->memchunk.memblock); + + pa_assert(l != 0); + + if (l < 0) { + + if (errno == EINTR) + continue; + else if (errno != EAGAIN) { + pa_log("Failed to write data to FIFO: %s", pa_cstrerror(errno)); + goto fail; + } + + } else { + + u->memchunk.index += l; + u->memchunk.length -= l; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + pa_memchunk_reset(&u->memchunk); + } + + pollfd->revents = 0; + } + } + + /* Hmm, nothing to do. Let's sleep */ + pollfd->events = u->sink->thread_info.state == PA_SINK_RUNNING ? POLLOUT : 0; + + if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0) + goto fail; + + if (ret == 0) + goto finish; + + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + + if (pollfd->revents & ~POLLOUT) { + pa_log("FIFO shutdown."); + goto fail; + } + } + +fail: + /* If this was no regular exit from the loop we have to continue + * processing messages until we received PA_MESSAGE_SHUTDOWN */ + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); + +finish: + pa_log_debug("Thread shutting down"); } -int pa__init(pa_core *c, pa_module*m) { - struct userdata *u = NULL; +int pa__init(pa_module*m) { + struct userdata *u; struct stat st; - const char *p; - int fd = -1; pa_sample_spec ss; pa_channel_map map; - pa_modargs *ma = NULL; + pa_modargs *ma; char *t; + struct pollfd *pollfd; - assert(c && m); + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log("failed to parse module arguments"); + pa_log("Failed to parse module arguments."); goto fail; } - ss = c->default_sample_spec; + ss = m->core->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { - pa_log("invalid sample format specification"); + pa_log("Invalid sample format specification or channel map"); goto fail; } - mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777); + u = pa_xnew0(struct userdata, 1); + u->core = m->core; + u->module = m; + m->userdata = u; + pa_memchunk_reset(&u->memchunk); + pa_thread_mq_init(&u->thread_mq, m->core->mainloop); + u->rtpoll = pa_rtpoll_new(); + pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq); - if ((fd = open(p, O_RDWR)) < 0) { - pa_log("open('%s'): %s", p, pa_cstrerror(errno)); + u->filename = pa_xstrdup(pa_modargs_get_value(ma, "file", DEFAULT_FILE_NAME)); + + mkfifo(u->filename, 0666); + if ((u->fd = open(u->filename, O_RDWR|O_NOCTTY)) < 0) { + pa_log("open('%s'): %s", u->filename, pa_cstrerror(errno)); goto fail; } - pa_fd_set_cloexec(fd, 1); + pa_make_fd_cloexec(u->fd); + pa_make_fd_nonblock(u->fd); - if (fstat(fd, &st) < 0) { - pa_log("fstat('%s'): %s", p, pa_cstrerror(errno)); + if (fstat(u->fd, &st) < 0) { + pa_log("fstat('%s'): %s", u->filename, pa_cstrerror(errno)); goto fail; } if (!S_ISFIFO(st.st_mode)) { - pa_log("'%s' is not a FIFO.", p); + pa_log("'%s' is not a FIFO.", u->filename); goto fail; } - u = pa_xmalloc0(sizeof(struct userdata)); - u->filename = pa_xstrdup(p); - u->core = c; - u->module = m; - m->userdata = u; - - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { - pa_log("failed to create sink."); + if (!(u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { + pa_log("Failed to create sink."); goto fail; } - u->sink->notify = notify_cb; - u->sink->get_latency = get_latency_cb; + + u->sink->parent.process_msg = sink_process_msg; u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Unix FIFO sink '%s'", p)); + u->sink->flags = PA_SINK_LATENCY; + + pa_sink_set_module(u->sink, m); + pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); + pa_sink_set_rtpoll(u->sink, u->rtpoll); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Unix FIFO sink '%s'", u->filename)); pa_xfree(t); - u->io = pa_iochannel_new(c->mainloop, -1, fd); - assert(u->io); - pa_iochannel_set_callback(u->io, io_callback, u); + u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + pollfd->fd = u->fd; + pollfd->events = pollfd->revents = 0; - u->memchunk.memblock = NULL; - u->memchunk.length = 0; + if (!(u->thread = pa_thread_new(thread_func, u))) { + pa_log("Failed to create thread."); + goto fail; + } - u->defer_event = c->mainloop->defer_new(c->mainloop, defer_callback, u); - assert(u->defer_event); - c->mainloop->defer_enable(u->defer_event, 0); + pa_sink_put(u->sink); pa_modargs_free(ma); @@ -220,32 +285,48 @@ fail: if (ma) pa_modargs_free(ma); - if (fd >= 0) - close(fd); - - pa__done(c, m); + pa__done(m); return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata *u; - assert(c && m); + + pa_assert(m); if (!(u = m->userdata)) return; + if (u->sink) + pa_sink_unlink(u->sink); + + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); + } + + pa_thread_mq_done(&u->thread_mq); + + if (u->sink) + pa_sink_unref(u->sink); + if (u->memchunk.memblock) - pa_memblock_unref(u->memchunk.memblock); + pa_memblock_unref(u->memchunk.memblock); - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - pa_iochannel_free(u->io); - u->core->mainloop->defer_free(u->defer_event); + if (u->rtpoll_item) + pa_rtpoll_item_free(u->rtpoll_item); + + if (u->rtpoll) + pa_rtpoll_free(u->rtpoll); + + if (u->filename) { + unlink(u->filename); + pa_xfree(u->filename); + } - assert(u->filename); - unlink(u->filename); - pa_xfree(u->filename); + if (u->fd >= 0) + pa_assert_se(pa_close(u->fd) == 0); pa_xfree(u); } diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index 56c721b0..45708c68 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -28,22 +28,24 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include -#include #include #include #include #include #include +#include +#include +#include #include "module-pipe-source-symdef.h" @@ -58,18 +60,24 @@ PA_MODULE_USAGE( "rate= " "channel_map=") -#define DEFAULT_FIFO_NAME "/tmp/music.input" +#define DEFAULT_FILE_NAME "/tmp/music.input" #define DEFAULT_SOURCE_NAME "fifo_input" struct userdata { pa_core *core; + pa_module *module; + pa_source *source; + + pa_thread *thread; + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; char *filename; + int fd; - pa_source *source; - pa_iochannel *io; - pa_module *module; - pa_memchunk chunk; + pa_memchunk memchunk; + + pa_rtpoll_item *rtpoll_item; }; static const char* const valid_modargs[] = { @@ -82,109 +90,168 @@ static const char* const valid_modargs[] = { NULL }; -static void do_read(struct userdata *u) { - ssize_t r; - pa_memchunk chunk; - assert(u); +static void thread_func(void *userdata) { + struct userdata *u = userdata; + int read_type = 0; - if (!pa_iochannel_is_readable(u->io)) - return; + pa_assert(u); - pa_module_set_used(u->module, pa_idxset_size(u->source->outputs)); + pa_log_debug("Thread starting up"); - if (!u->chunk.memblock) { - u->chunk.memblock = pa_memblock_new(u->core->mempool, PIPE_BUF); - u->chunk.index = chunk.length = 0; - } + pa_thread_mq_install(&u->thread_mq); + pa_rtpoll_install(u->rtpoll); - assert(u->chunk.memblock && u->chunk.memblock->length > u->chunk.index); - if ((r = pa_iochannel_read(u->io, (uint8_t*) u->chunk.memblock->data + u->chunk.index, u->chunk.memblock->length - u->chunk.index)) <= 0) { - pa_log("read(): %s", pa_cstrerror(errno)); - return; - } + for (;;) { + int ret; + struct pollfd *pollfd; + + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + + /* Try to read some data and pass it on to the source driver */ + if (u->source->thread_info.state == PA_SOURCE_RUNNING && pollfd->revents) { + ssize_t l; + void *p; - u->chunk.length = r; - pa_source_post(u->source, &u->chunk); - u->chunk.index += r; + if (!u->memchunk.memblock) { + u->memchunk.memblock = pa_memblock_new(u->core->mempool, PIPE_BUF); + u->memchunk.index = u->memchunk.length = 0; + } - if (u->chunk.index >= u->chunk.memblock->length) { - u->chunk.index = u->chunk.length = 0; - pa_memblock_unref(u->chunk.memblock); - u->chunk.memblock = NULL; + pa_assert(pa_memblock_get_length(u->memchunk.memblock) > u->memchunk.index); + + p = pa_memblock_acquire(u->memchunk.memblock); + l = pa_read(u->fd, (uint8_t*) p + u->memchunk.index, pa_memblock_get_length(u->memchunk.memblock) - u->memchunk.index, &read_type); + pa_memblock_release(u->memchunk.memblock); + + pa_assert(l != 0); /* EOF cannot happen, since we opened the fifo for both reading and writing */ + + if (l < 0) { + + if (errno == EINTR) + continue; + else if (errno != EAGAIN) { + pa_log("Faile to read data from FIFO: %s", pa_cstrerror(errno)); + goto fail; + } + + } else { + + u->memchunk.length = l; + pa_source_post(u->source, &u->memchunk); + u->memchunk.index += l; + + if (u->memchunk.index >= pa_memblock_get_length(u->memchunk.memblock)) { + pa_memblock_unref(u->memchunk.memblock); + pa_memchunk_reset(&u->memchunk); + } + + pollfd->revents = 0; + } + } + + /* Hmm, nothing to do. Let's sleep */ + pollfd->events = u->source->thread_info.state == PA_SOURCE_RUNNING ? POLLIN : 0; + + if ((ret = pa_rtpoll_run(u->rtpoll, 1)) < 0) + goto fail; + + if (ret == 0) + goto finish; + + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + if (pollfd->revents & ~POLLIN) { + pa_log("FIFO shutdown."); + goto fail; + } } -} -static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { - struct userdata *u = userdata; - assert(u); - do_read(u); +fail: + /* If this was no regular exit from the loop we have to continue + * processing messages until we received PA_MESSAGE_SHUTDOWN */ + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); + +finish: + pa_log_debug("Thread shutting down"); } -int pa__init(pa_core *c, pa_module*m) { - struct userdata *u = NULL; +int pa__init(pa_module*m) { + struct userdata *u; struct stat st; - const char *p; - int fd = -1; pa_sample_spec ss; pa_channel_map map; - pa_modargs *ma = NULL; + pa_modargs *ma; char *t; + struct pollfd *pollfd; - assert(c && m); + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log("failed to parse module arguments"); + pa_log("failed to parse module arguments."); goto fail; } - ss = c->default_sample_spec; + ss = m->core->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { pa_log("invalid sample format specification or channel map"); goto fail; } - mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777); + u = pa_xnew0(struct userdata, 1); + u->core = m->core; + u->module = m; + m->userdata = u; + pa_memchunk_reset(&u->memchunk); + pa_thread_mq_init(&u->thread_mq, m->core->mainloop); + u->rtpoll = pa_rtpoll_new(); + pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq); + + u->filename = pa_xstrdup(pa_modargs_get_value(ma, "file", DEFAULT_FILE_NAME)); - if ((fd = open(p, O_RDWR)) < 0) { - pa_log("open('%s'): %s", p, pa_cstrerror(errno)); + mkfifo(u->filename, 0666); + if ((u->fd = open(u->filename, O_RDWR|O_NOCTTY)) < 0) { + pa_log("open('%s'): %s", u->filename, pa_cstrerror(errno)); goto fail; } - pa_fd_set_cloexec(fd, 1); + pa_make_fd_cloexec(u->fd); + pa_make_fd_nonblock(u->fd); - if (fstat(fd, &st) < 0) { - pa_log("fstat('%s'): %s", p, pa_cstrerror(errno)); + if (fstat(u->fd, &st) < 0) { + pa_log("fstat('%s'): %s",u->filename, pa_cstrerror(errno)); goto fail; } if (!S_ISFIFO(st.st_mode)) { - pa_log("'%s' is not a FIFO.", p); + pa_log("'%s' is not a FIFO.", u->filename); goto fail; } - u = pa_xmalloc0(sizeof(struct userdata)); - - u->filename = pa_xstrdup(p); - u->core = c; - - if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) { - pa_log("failed to create source."); + if (!(u->source = pa_source_new(m->core, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) { + pa_log("Failed to create source."); goto fail; } + u->source->userdata = u; - pa_source_set_owner(u->source, m); - pa_source_set_description(u->source, t = pa_sprintf_malloc("Unix FIFO source '%s'", p)); + u->source->flags = 0; + + pa_source_set_module(u->source, m); + pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); + pa_source_set_rtpoll(u->source, u->rtpoll); + pa_source_set_description(u->source, t = pa_sprintf_malloc("Unix FIFO source '%s'", u->filename)); pa_xfree(t); - u->io = pa_iochannel_new(c->mainloop, fd, -1); - assert(u->io); - pa_iochannel_set_callback(u->io, io_callback, u); + u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + pollfd->fd = u->fd; + pollfd->events = pollfd->revents = 0; - u->chunk.memblock = NULL; - u->chunk.index = u->chunk.length = 0; + if (!(u->thread = pa_thread_new(thread_func, u))) { + pa_log("Failed to create thread."); + goto fail; + } - u->module = m; - m->userdata = u; + pa_source_put(u->source); pa_modargs_free(ma); @@ -194,31 +261,48 @@ fail: if (ma) pa_modargs_free(ma); - if (fd >= 0) - close(fd); - - pa__done(c, m); + pa__done(m); return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata *u; - assert(c && m); + + pa_assert(m); if (!(u = m->userdata)) return; - if (u->chunk.memblock) - pa_memblock_unref(u->chunk.memblock); + if (u->source) + pa_source_unlink(u->source); + + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); + } + + pa_thread_mq_done(&u->thread_mq); + + if (u->source) + pa_source_unref(u->source); + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); - pa_source_disconnect(u->source); - pa_source_unref(u->source); - pa_iochannel_free(u->io); + if (u->rtpoll_item) + pa_rtpoll_item_free(u->rtpoll_item); + + if (u->rtpoll) + pa_rtpoll_free(u->rtpoll); + + if (u->filename) { + unlink(u->filename); + pa_xfree(u->filename); + } - assert(u->filename); - unlink(u->filename); - pa_xfree(u->filename); + if (u->fd >= 0) + pa_assert_se(pa_close(u->fd) == 0); pa_xfree(u); } diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index 5c8733fb..6bd78079 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -43,10 +42,9 @@ #include #endif -#include "../pulsecore/winsock.h" - #include +#include #include #include #include @@ -154,7 +152,6 @@ #define protocol_free pa_protocol_esound_free #define TCPWRAP_SERVICE "esound" #define IPV4_PORT ESD_DEFAULT_PORT - #define UNIX_SOCKET ESD_UNIX_SOCKET_NAME #define MODULE_ARGUMENTS_COMMON "sink", "source", "auth-anonymous", "cookie", #ifdef USE_TCP_SOCKETS #include "module-esound-protocol-tcp-symdef.h" @@ -205,10 +202,9 @@ struct userdata { #endif }; -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { pa_modargs *ma = NULL; int ret = -1; - struct userdata *u = NULL; #if defined(USE_TCP_SOCKETS) @@ -219,9 +215,13 @@ int pa__init(pa_core *c, pa_module*m) { pa_socket_server *s; int r; char tmp[PATH_MAX]; + +#if defined(USE_PROTOCOL_ESOUND) + char tmp2[PATH_MAX]; +#endif #endif - assert(c && m); + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments"); @@ -239,22 +239,22 @@ int pa__init(pa_core *c, pa_module*m) { listen_on = pa_modargs_get_value(ma, "listen", NULL); if (listen_on) { - s_ipv6 = pa_socket_server_new_ipv6_string(c->mainloop, listen_on, port, TCPWRAP_SERVICE); - s_ipv4 = pa_socket_server_new_ipv4_string(c->mainloop, listen_on, port, TCPWRAP_SERVICE); + s_ipv6 = pa_socket_server_new_ipv6_string(m->core->mainloop, listen_on, port, TCPWRAP_SERVICE); + s_ipv4 = pa_socket_server_new_ipv4_string(m->core->mainloop, listen_on, port, TCPWRAP_SERVICE); } else { - s_ipv6 = pa_socket_server_new_ipv6_any(c->mainloop, port, TCPWRAP_SERVICE); - s_ipv4 = pa_socket_server_new_ipv4_any(c->mainloop, port, TCPWRAP_SERVICE); + s_ipv6 = pa_socket_server_new_ipv6_any(m->core->mainloop, port, TCPWRAP_SERVICE); + s_ipv4 = pa_socket_server_new_ipv4_any(m->core->mainloop, port, TCPWRAP_SERVICE); } if (!s_ipv4 && !s_ipv6) goto fail; if (s_ipv4) - if (!(u->protocol_ipv4 = protocol_new(c, s_ipv4, m, ma))) + if (!(u->protocol_ipv4 = protocol_new(m->core, s_ipv4, m, ma))) pa_socket_server_unref(s_ipv4); if (s_ipv6) - if (!(u->protocol_ipv6 = protocol_new(c, s_ipv6, m, ma))) + if (!(u->protocol_ipv6 = protocol_new(m->core, s_ipv6, m, ma))) pa_socket_server_unref(s_ipv6); if (!u->protocol_ipv4 && !u->protocol_ipv6) @@ -262,18 +262,23 @@ int pa__init(pa_core *c, pa_module*m) { #else - pa_runtime_path(pa_modargs_get_value(ma, "socket", UNIX_SOCKET), tmp, sizeof(tmp)); - u->socket_path = pa_xstrdup(tmp); - #if defined(USE_PROTOCOL_ESOUND) + snprintf(tmp2, sizeof(tmp2), "/tmp/.esd-%lu/socket", (unsigned long) getuid()); + pa_runtime_path(pa_modargs_get_value(ma, "socket", tmp2), tmp, sizeof(tmp)); + u->socket_path = pa_xstrdup(tmp); + /* This socket doesn't reside in our own runtime dir but in * /tmp/.esd/, hence we have to create the dir first */ - if (pa_make_secure_parent_dir(u->socket_path, c->is_system_instance ? 0755 : 0700, (uid_t)-1, (gid_t)-1) < 0) { + if (pa_make_secure_parent_dir(u->socket_path, m->core->is_system_instance ? 0755 : 0700, (uid_t)-1, (gid_t)-1) < 0) { pa_log("Failed to create socket directory '%s': %s\n", u->socket_path, pa_cstrerror(errno)); goto fail; } + +#else + pa_runtime_path(pa_modargs_get_value(ma, "socket", UNIX_SOCKET), tmp, sizeof(tmp)); + u->socket_path = pa_xstrdup(tmp); #endif if ((r = pa_unix_socket_remove_stale(tmp)) < 0) { @@ -284,10 +289,10 @@ int pa__init(pa_core *c, pa_module*m) { if (r) pa_log("Removed stale UNIX socket '%s'.", tmp); - if (!(s = pa_socket_server_new_unix(c->mainloop, tmp))) + if (!(s = pa_socket_server_new_unix(m->core->mainloop, tmp))) goto fail; - if (!(u->protocol_unix = protocol_new(c, s, m, ma))) + if (!(u->protocol_unix = protocol_new(m->core, s, m, ma))) goto fail; #endif @@ -333,11 +338,10 @@ fail: goto finish; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata *u; - assert(c); - assert(m); + pa_assert(m); u = m->userdata; @@ -358,7 +362,6 @@ void pa__done(pa_core *c, pa_module*m) { } #endif - pa_xfree(u->socket_path); #endif diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c new file mode 100644 index 00000000..e863c0c3 --- /dev/null +++ b/src/modules/module-remap-sink.c @@ -0,0 +1,334 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-remap-sink-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("Virtual channel remapping sink") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE( + "sink_name= " + "master= " + "master_channel_map= " + "format= " + "channels= " + "rate= " + "channel_map=") + +struct userdata { + pa_core *core; + pa_module *module; + + pa_sink *sink, *master; + pa_sink_input *sink_input; + + pa_memchunk memchunk; +}; + +static const char* const valid_modargs[] = { + "sink_name", + "master", + "master_channel_map", + "rate", + "format", + "channels", + "channel_map", + NULL +}; + +/* Called from I/O thread context */ +static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SINK(o)->userdata; + + switch (code) { + + case PA_SINK_MESSAGE_GET_LATENCY: { + pa_usec_t usec = 0; + + if (PA_MSGOBJECT(u->master)->process_msg(PA_MSGOBJECT(u->master), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0) + usec = 0; + + *((pa_usec_t*) data) = usec + pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec); + return 0; + } + } + + return pa_sink_process_msg(o, code, data, offset, chunk); +} + +/* Called from main context */ +static int sink_set_state(pa_sink *s, pa_sink_state_t state) { + struct userdata *u; + + pa_sink_assert_ref(s); + pa_assert_se(u = s->userdata); + + if (PA_SINK_LINKED(state) && u->sink_input && PA_SINK_INPUT_LINKED(pa_sink_input_get_state(u->sink_input))) + pa_sink_input_cork(u->sink_input, state == PA_SINK_SUSPENDED); + + return 0; +} + +/* Called from I/O thread context */ +static int sink_input_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SINK_INPUT(o)->userdata; + + switch (code) { + case PA_SINK_INPUT_MESSAGE_GET_LATENCY: + *((pa_usec_t*) data) = pa_bytes_to_usec(u->memchunk.length, &u->sink_input->sample_spec); + + /* Fall through, the default handler will add in the extra + * latency added by the resampler */ + break; + } + + return pa_sink_input_process_msg(o, code, data, offset, chunk); +} + +/* Called from I/O thread context */ +static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_assert_se(u = i->userdata); + + if (!u->memchunk.memblock) + pa_sink_render(u->sink, length, &u->memchunk); + + pa_assert(u->memchunk.memblock); + *chunk = u->memchunk; + pa_memblock_ref(chunk->memblock); + return 0; +} + +/* Called from I/O thread context */ +static void sink_input_drop_cb(pa_sink_input *i, size_t length) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_assert_se(u = i->userdata); + pa_assert(length > 0); + + if (u->memchunk.memblock) { + + if (length < u->memchunk.length) { + u->memchunk.index += length; + u->memchunk.length -= length; + return; + } + + pa_memblock_unref(u->memchunk.memblock); + length -= u->memchunk.length; + pa_memchunk_reset(&u->memchunk); + } + + if (length > 0) + pa_sink_skip(u->sink, length); +} + +/* Called from I/O thread context */ +static void sink_input_detach_cb(pa_sink_input *i) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_assert_se(u = i->userdata); + + pa_sink_detach_within_thread(u->sink); +} + +/* Called from I/O thread context */ +static void sink_input_attach_cb(pa_sink_input *i) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_assert_se(u = i->userdata); + + pa_sink_set_asyncmsgq(u->sink, i->sink->asyncmsgq); + pa_sink_set_rtpoll(u->sink, i->sink->rtpoll); + + pa_sink_attach_within_thread(u->sink); +} + +/* Called from main context */ +static void sink_input_kill_cb(pa_sink_input *i) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_assert_se(u = i->userdata); + + pa_sink_input_unlink(u->sink_input); + pa_sink_input_unref(u->sink_input); + u->sink_input = NULL; + + pa_sink_unlink(u->sink); + pa_sink_unref(u->sink); + u->sink = NULL; + + pa_module_unload_request(u->module); +} + +int pa__init(pa_module*m) { + struct userdata *u; + pa_sample_spec ss; + pa_channel_map sink_map, stream_map; + pa_modargs *ma; + char *t; + pa_sink *master; + pa_sink_input_new_data data; + char *default_sink_name = NULL; + + pa_assert(m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log("Failed to parse module arguments."); + goto fail; + } + + if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "master", NULL), PA_NAMEREG_SINK, 1))) { + pa_log("Master sink not found"); + goto fail; + } + + ss = master->sample_spec; + sink_map = master->channel_map; + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &sink_map, PA_CHANNEL_MAP_DEFAULT) < 0) { + pa_log("Invalid sample format specification or channel map"); + goto fail; + } + + stream_map = sink_map; + if (pa_modargs_get_channel_map(ma, "master_channel_map", &stream_map) < 0) { + pa_log("Invalid master hannel map"); + goto fail; + } + + if (stream_map.channels != ss.channels) { + pa_log("Number of channels doesn't match"); + goto fail; + } + + u = pa_xnew0(struct userdata, 1); + u->core = m->core; + u->module = m; + m->userdata = u; + u->master = master; + pa_memchunk_reset(&u->memchunk); + + default_sink_name = pa_sprintf_malloc("%s.remapped", master->name); + + /* Create sink */ + if (!(u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", default_sink_name), 0, &ss, &sink_map))) { + pa_log("Failed to create sink."); + goto fail; + } + + u->sink->parent.process_msg = sink_process_msg; + u->sink->set_state = sink_set_state; + u->sink->userdata = u; + u->sink->flags = PA_SINK_LATENCY; + + pa_sink_set_module(u->sink, m); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Remapped %s", master->description)); + pa_xfree(t); + pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq); + pa_sink_set_rtpoll(u->sink, master->rtpoll); + + /* Create sink input */ + pa_sink_input_new_data_init(&data); + data.sink = u->master; + data.driver = __FILE__; + data.name = "Remapped Stream"; + pa_sink_input_new_data_set_sample_spec(&data, &ss); + pa_sink_input_new_data_set_channel_map(&data, &stream_map); + data.module = m; + + if (!(u->sink_input = pa_sink_input_new(m->core, &data, PA_SINK_INPUT_DONT_MOVE))) + goto fail; + + u->sink_input->parent.process_msg = sink_input_process_msg; + u->sink_input->peek = sink_input_peek_cb; + u->sink_input->drop = sink_input_drop_cb; + u->sink_input->kill = sink_input_kill_cb; + u->sink_input->attach = sink_input_attach_cb; + u->sink_input->detach = sink_input_detach_cb; + u->sink_input->userdata = u; + + pa_sink_put(u->sink); + pa_sink_input_put(u->sink_input); + + pa_modargs_free(ma); + pa_xfree(default_sink_name); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + pa__done(m); + + pa_xfree(default_sink_name); + + return -1; +} + +void pa__done(pa_module*m) { + struct userdata *u; + + pa_assert(m); + + if (!(u = m->userdata)) + return; + + if (u->sink_input) { + pa_sink_input_unlink(u->sink_input); + pa_sink_input_unref(u->sink_input); + } + + if (u->sink) { + pa_sink_unlink(u->sink); + pa_sink_unref(u->sink); + } + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + + pa_xfree(u); +} diff --git a/src/modules/module-rescue-streams.c b/src/modules/module-rescue-streams.c index 25005f25..5cabef76 100644 --- a/src/modules/module-rescue-streams.c +++ b/src/modules/module-rescue-streams.c @@ -52,20 +52,26 @@ static pa_hook_result_t sink_hook_callback(pa_core *c, pa_sink *sink, void* user pa_sink_input *i; pa_sink *target; - assert(c); - assert(sink); + pa_assert(c); + pa_assert(sink); if (!pa_idxset_size(sink->inputs)) { pa_log_debug("No sink inputs to move away."); return PA_HOOK_OK; } - if (!(target = pa_namereg_get(c, NULL, PA_NAMEREG_SINK, 0))) { - pa_log_info("No evacuation sink found."); - return PA_HOOK_OK; - } + if (!(target = pa_namereg_get(c, NULL, PA_NAMEREG_SINK, 0)) || target == sink) { + uint32_t idx; + + for (target = pa_idxset_first(c->sinks, &idx); target; target = pa_idxset_next(c->sinks, &idx)) + if (target != sink) + break; - assert(target != sink); + if (!target) { + pa_log_info("No evacuation sink found."); + return PA_HOOK_OK; + } + } while ((i = pa_idxset_first(sink->inputs, NULL))) { if (pa_sink_input_move_to(i, target, 1) < 0) { @@ -84,20 +90,28 @@ static pa_hook_result_t source_hook_callback(pa_core *c, pa_source *source, void pa_source_output *o; pa_source *target; - assert(c); - assert(source); + pa_assert(c); + pa_assert(source); if (!pa_idxset_size(source->outputs)) { pa_log_debug("No source outputs to move away."); return PA_HOOK_OK; } - if (!(target = pa_namereg_get(c, NULL, PA_NAMEREG_SOURCE, 0))) { - pa_log_info("No evacuation source found."); - return PA_HOOK_OK; + if (!(target = pa_namereg_get(c, NULL, PA_NAMEREG_SOURCE, 0)) || target == source) { + uint32_t idx; + + for (target = pa_idxset_first(c->sources, &idx); target; target = pa_idxset_next(c->sources, &idx)) + if (target != source && !target->monitor_of == !source->monitor_of) + break; + + if (!target) { + pa_log_info("No evacuation source found."); + return PA_HOOK_OK; + } } - assert(target != source); + pa_assert(target != source); while ((o = pa_idxset_first(source->outputs, NULL))) { if (pa_source_output_move_to(o, target) < 0) { @@ -112,12 +126,11 @@ static pa_hook_result_t source_hook_callback(pa_core *c, pa_source *source, void return PA_HOOK_OK; } -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { pa_modargs *ma = NULL; struct userdata *u; - assert(c); - assert(m); + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments"); @@ -125,18 +138,17 @@ int pa__init(pa_core *c, pa_module*m) { } m->userdata = u = pa_xnew(struct userdata, 1); - u->sink_slot = pa_hook_connect(&c->hook_sink_disconnect, (pa_hook_cb_t) sink_hook_callback, NULL); - u->source_slot = pa_hook_connect(&c->hook_source_disconnect, (pa_hook_cb_t) source_hook_callback, NULL); + u->sink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], (pa_hook_cb_t) sink_hook_callback, NULL); + u->source_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], (pa_hook_cb_t) source_hook_callback, NULL); pa_modargs_free(ma); return 0; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata *u; - assert(c); - assert(m); + pa_assert(m); if (!m->userdata) return; diff --git a/src/modules/module-sine.c b/src/modules/module-sine.c index 661455b3..65b8ee7f 100644 --- a/src/modules/module-sine.c +++ b/src/modules/module-sine.c @@ -26,7 +26,6 @@ #endif #include -#include #include #include @@ -36,6 +35,7 @@ #include #include #include +#include #include "module-sine-symdef.h" @@ -58,36 +58,46 @@ static const char* const valid_modargs[] = { NULL, }; -static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { +static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) { struct userdata *u; - assert(i && chunk && i->userdata); + + pa_assert(i); u = i->userdata; + pa_assert(u); + pa_assert(chunk); chunk->memblock = pa_memblock_ref(u->memblock); chunk->index = u->peek_index; - chunk->length = u->memblock->length - u->peek_index; + chunk->length = pa_memblock_get_length(u->memblock) - u->peek_index; + return 0; } -static void sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { +static void sink_input_drop_cb(pa_sink_input *i, size_t length) { struct userdata *u; - assert(i && chunk && length && i->userdata); - u = i->userdata; + size_t l; - assert(chunk->memblock == u->memblock && length <= u->memblock->length-u->peek_index); + pa_assert(i); + u = i->userdata; + pa_assert(u); + pa_assert(length > 0); u->peek_index += length; - if (u->peek_index >= u->memblock->length) - u->peek_index = 0; + l = pa_memblock_get_length(u->memblock); + + while (u->peek_index >= l) + u->peek_index -= l; } -static void sink_input_kill(pa_sink_input *i) { +static void sink_input_kill_cb(pa_sink_input *i) { struct userdata *u; - assert(i && i->userdata); + + pa_assert(i); u = i->userdata; + pa_assert(u); - pa_sink_input_disconnect(u->sink_input); + pa_sink_input_unlink(u->sink_input); pa_sink_input_unref(u->sink_input); u->sink_input = NULL; @@ -103,14 +113,14 @@ static void calc_sine(float *f, size_t l, float freq) { f[i] = (float) sin((double) i/l*M_PI*2*freq)/2; } -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { pa_modargs *ma = NULL; struct userdata *u; pa_sink *sink; - const char *sink_name; pa_sample_spec ss; uint32_t frequency; char t[256]; + void *p; pa_sink_input_new_data data; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -118,15 +128,14 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - m->userdata = u = pa_xmalloc(sizeof(struct userdata)); - u->core = c; + m->userdata = u = pa_xnew0(struct userdata, 1); + u->core = m->core; u->module = m; u->sink_input = NULL; u->memblock = NULL; + u->peek_index = 0; - sink_name = pa_modargs_get_value(ma, "sink", NULL); - - if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) { + if (!(sink = pa_namereg_get(m->core, pa_modargs_get_value(ma, "sink", NULL), PA_NAMEREG_SINK, 1))) { pa_log("No such sink."); goto fail; } @@ -141,10 +150,12 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - u->memblock = pa_memblock_new(c->mempool, pa_bytes_per_second(&ss)); - calc_sine(u->memblock->data, u->memblock->length, frequency); + u->memblock = pa_memblock_new(m->core->mempool, pa_bytes_per_second(&ss)); + p = pa_memblock_acquire(u->memblock); + calc_sine(p, pa_memblock_get_length(u->memblock), frequency); + pa_memblock_release(u->memblock); - snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency); + pa_snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency); pa_sink_input_new_data_init(&data); data.sink = sink; @@ -153,15 +164,15 @@ int pa__init(pa_core *c, pa_module*m) { pa_sink_input_new_data_set_sample_spec(&data, &ss); data.module = m; - if (!(u->sink_input = pa_sink_input_new(c, &data, 0))) + if (!(u->sink_input = pa_sink_input_new(m->core, &data, 0))) goto fail; - u->sink_input->peek = sink_input_peek; - u->sink_input->drop = sink_input_drop; - u->sink_input->kill = sink_input_kill; + u->sink_input->peek = sink_input_peek_cb; + u->sink_input->drop = sink_input_drop_cb; + u->sink_input->kill = sink_input_kill_cb; u->sink_input->userdata = u; - u->peek_index = 0; + pa_sink_input_put(u->sink_input); pa_modargs_free(ma); return 0; @@ -170,24 +181,26 @@ fail: if (ma) pa_modargs_free(ma); - pa__done(c, m); + pa__done(m); return -1; } -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u = m->userdata; - assert(c && m); +void pa__done(pa_module*m) { + struct userdata *u; + + pa_assert(m); - if (!u) + if (!(u = m->userdata)) return; if (u->sink_input) { - pa_sink_input_disconnect(u->sink_input); + pa_sink_input_unlink(u->sink_input); pa_sink_input_unref(u->sink_input); } if (u->memblock) pa_memblock_unref(u->memblock); + pa_xfree(u); } diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index a50f1ecf..a8a94712 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -4,7 +4,7 @@ This file is part of PulseAudio. Copyright 2006 Lennart Poettering - Copyright 2006 Pierre Ossman for Cendio AB + Copyright 2006-2007 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published @@ -57,6 +57,9 @@ #include #include #include +#include +#include +#include #include "module-solaris-symdef.h" @@ -75,12 +78,14 @@ PA_MODULE_USAGE( "channel_map=") struct userdata { + pa_core *core; pa_sink *sink; pa_source *source; - pa_iochannel *io; - pa_core *core; - pa_time_event *timer; - pa_usec_t poll_timeout; + + pa_thread *thread; + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; + pa_signal_event *sig; pa_memchunk memchunk; @@ -90,9 +95,9 @@ struct userdata { uint32_t frame_size; uint32_t buffer_size; unsigned int written_bytes, read_bytes; - int sink_underflow; int fd; + pa_rtpoll_item *rtpoll_item; pa_module *module; }; @@ -114,309 +119,357 @@ static const char* const valid_modargs[] = { #define DEFAULT_SOURCE_NAME "solaris_input" #define DEFAULT_DEVICE "/dev/audio" -#define CHUNK_SIZE 2048 - -static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, - (u->sink ? pa_sink_used_by(u->sink) : 0) + - (u->source ? pa_source_used_by(u->source) : 0)); -} - -static void do_write(struct userdata *u) { - audio_info_t info; +static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SINK(o)->userdata; int err; - size_t len; - ssize_t r; + audio_info_t info; - assert(u); + switch (code) { + case PA_SINK_MESSAGE_GET_LATENCY: { + pa_usec_t r = 0; - /* We cannot check pa_iochannel_is_writable() because of our buffer hack */ - if (!u->sink) - return; + if (u->fd >= 0) { - update_usage(u); + err = ioctl(u->fd, AUDIO_GETINFO, &info); + pa_assert(err >= 0); - err = ioctl(u->fd, AUDIO_GETINFO, &info); - assert(err >= 0); + r += pa_bytes_to_usec(u->written_bytes, &PA_SINK(o)->sample_spec); + r -= pa_bytes_to_usec(info.play.samples * u->frame_size, &PA_SINK(o)->sample_spec); - /* - * Since we cannot modify the size of the output buffer we fake it - * by not filling it more than u->buffer_size. - */ - len = u->buffer_size; - len -= u->written_bytes - (info.play.samples * u->frame_size); + if (u->memchunk.memblock) + r += pa_bytes_to_usec(u->memchunk.length, &PA_SINK(o)->sample_spec); + } - /* The sample counter can sometimes go backwards :( */ - if (len > u->buffer_size) - len = 0; + *((pa_usec_t*) data) = r; - if (!u->sink_underflow && (len == u->buffer_size)) - pa_log_debug("Solaris buffer underflow!"); + return 0; + } - len -= len % u->frame_size; + case PA_SINK_MESSAGE_SET_VOLUME: + if (u->fd >= 0) { + AUDIO_INITINFO(&info); + + info.play.gain = pa_cvolume_avg((pa_cvolume*)data) * AUDIO_MAX_GAIN / PA_VOLUME_NORM; + assert(info.play.gain <= AUDIO_MAX_GAIN); + + if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { + if (errno == EINVAL) + pa_log("AUDIO_SETINFO: Unsupported volume."); + else + pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); + } else { + return 0; + } + } + break; - if (len == 0) - return; + case PA_SINK_MESSAGE_GET_VOLUME: + if (u->fd >= 0) { + err = ioctl(u->fd, AUDIO_GETINFO, &info); + assert(err >= 0); - if (!u->memchunk.length) { - if (pa_sink_render(u->sink, len, &u->memchunk) < 0) { - u->sink_underflow = 1; - return; - } - } + pa_cvolume_set((pa_cvolume*) data, ((pa_cvolume*) data)->channels, + info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN); - u->sink_underflow = 0; + return 0; + } + break; - assert(u->memchunk.memblock); - assert(u->memchunk.memblock->data); - assert(u->memchunk.length); + case PA_SINK_MESSAGE_SET_MUTE: + if (u->fd >= 0) { + AUDIO_INITINFO(&info); - if (u->memchunk.length < len) { - len = u->memchunk.length; - len -= len % u->frame_size; - assert(len); - } + info.output_muted = !!PA_PTR_TO_UINT(data); - if ((r = pa_iochannel_write(u->io, - (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, len)) < 0) { - pa_log("write() failed: %s", pa_cstrerror(errno)); - return; - } + if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) + pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); + else + return 0; + } + break; - assert(r % u->frame_size == 0); + case PA_SINK_MESSAGE_GET_MUTE: + if (u->fd >= 0) { + err = ioctl(u->fd, AUDIO_GETINFO, &info); + pa_assert(err >= 0); - u->memchunk.index += r; - u->memchunk.length -= r; + *(int*)data = !!info.output_muted; - if (u->memchunk.length <= 0) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; + return 0; + } + break; } - u->written_bytes += r; + return pa_sink_process_msg(o, code, data, offset, chunk); } -static void do_read(struct userdata *u) { - pa_memchunk memchunk; +static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SOURCE(o)->userdata; int err; - size_t l; - ssize_t r; - assert(u); + audio_info_t info; - if (!u->source || !pa_iochannel_is_readable(u->io)) - return; + switch (code) { + case PA_SOURCE_MESSAGE_GET_LATENCY: { + pa_usec_t r = 0; - update_usage(u); + if (u->fd) { + err = ioctl(u->fd, AUDIO_GETINFO, &info); + pa_assert(err >= 0); - err = ioctl(u->fd, I_NREAD, &l); - assert(err >= 0); + r += pa_bytes_to_usec(info.record.samples * u->frame_size, &PA_SOURCE(o)->sample_spec); + r -= pa_bytes_to_usec(u->read_bytes, &PA_SOURCE(o)->sample_spec); + } - /* This is to make sure it fits in the memory pool. Also, a page - should be the most efficient transfer size. */ - if (l > u->page_size) - l = u->page_size; + *((pa_usec_t*) data) = r; - memchunk.memblock = pa_memblock_new(u->core->mempool, l); - assert(memchunk.memblock); - if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { - pa_memblock_unref(memchunk.memblock); - if (errno != EAGAIN) - pa_log("read() failed: %s", pa_cstrerror(errno)); - return; - } + return 0; + } - assert(r <= (ssize_t) memchunk.memblock->length); - memchunk.length = memchunk.memblock->length = r; - memchunk.index = 0; + case PA_SOURCE_MESSAGE_SET_VOLUME: + if (u->fd >= 0) { + AUDIO_INITINFO(&info); + + info.record.gain = pa_cvolume_avg((pa_cvolume*) data) * AUDIO_MAX_GAIN / PA_VOLUME_NORM; + assert(info.record.gain <= AUDIO_MAX_GAIN); + + if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { + if (errno == EINVAL) + pa_log("AUDIO_SETINFO: Unsupported volume."); + else + pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); + } else { + return 0; + } + } + break; - pa_source_post(u->source, &memchunk); - pa_memblock_unref(memchunk.memblock); + case PA_SOURCE_MESSAGE_GET_VOLUME: + if (u->fd >= 0) { + err = ioctl(u->fd, AUDIO_GETINFO, &info); + pa_assert(err >= 0); - u->read_bytes += r; -} + pa_cvolume_set((pa_cvolume*) data, ((pa_cvolume*) data)->channels, + info.record.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN); -static void io_callback(pa_iochannel *io, void*userdata) { - struct userdata *u = userdata; - assert(u); - do_write(u); - do_read(u); -} + return 0; + } + break; + } -static void timer_cb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) { - struct userdata *u = userdata; - struct timeval ntv; + return pa_source_process_msg(o, code, data, offset, chunk); +} - assert(u); +static void clear_underflow(struct userdata *u) +{ + audio_info_t info; - do_write(u); + AUDIO_INITINFO(&info); - pa_gettimeofday(&ntv); - pa_timeval_add(&ntv, u->poll_timeout); + info.play.error = 0; - a->time_restart(e, &ntv); + if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) + pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); } -static void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata) { - struct userdata *u = userdata; - pa_cvolume old_vol; +static void clear_overflow(struct userdata *u) +{ + audio_info_t info; - assert(u); + AUDIO_INITINFO(&info); - if (u->sink) { - assert(u->sink->get_hw_volume); - memcpy(&old_vol, &u->sink->hw_volume, sizeof(pa_cvolume)); - if (u->sink->get_hw_volume(u->sink) < 0) - return; - if (memcmp(&old_vol, &u->sink->hw_volume, sizeof(pa_cvolume)) != 0) { - pa_subscription_post(u->sink->core, - PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, - u->sink->index); - } - } + info.record.error = 0; - if (u->source) { - assert(u->source->get_hw_volume); - memcpy(&old_vol, &u->source->hw_volume, sizeof(pa_cvolume)); - if (u->source->get_hw_volume(u->source) < 0) - return; - if (memcmp(&old_vol, &u->source->hw_volume, sizeof(pa_cvolume)) != 0) { - pa_subscription_post(u->source->core, - PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, - u->source->index); - } - } + if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) + pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); } -static pa_usec_t sink_get_latency_cb(pa_sink *s) { - pa_usec_t r = 0; - audio_info_t info; - int err; - struct userdata *u = s->userdata; - assert(s && u && u->sink); +static void thread_func(void *userdata) { + struct userdata *u = userdata; + unsigned short revents = 0; + int ret; - err = ioctl(u->fd, AUDIO_GETINFO, &info); - assert(err >= 0); + pa_assert(u); - r += pa_bytes_to_usec(u->written_bytes, &s->sample_spec); - r -= pa_bytes_to_usec(info.play.samples * u->frame_size, &s->sample_spec); + pa_log_debug("Thread starting up"); - if (u->memchunk.memblock) - r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec); + if (u->core->high_priority) + pa_make_realtime(); - return r; -} + pa_thread_mq_install(&u->thread_mq); + pa_rtpoll_install(u->rtpoll); -static pa_usec_t source_get_latency_cb(pa_source *s) { - pa_usec_t r = 0; - struct userdata *u = s->userdata; - audio_info_t info; - int err; - assert(s && u && u->source); + for (;;) { + /* Render some data and write it to the dsp */ - err = ioctl(u->fd, AUDIO_GETINFO, &info); - assert(err >= 0); + if (u->sink && PA_SINK_OPENED(u->sink->thread_info.state)) { + audio_info_t info; + int err; + size_t len; - r += pa_bytes_to_usec(info.record.samples * u->frame_size, &s->sample_spec); - r -= pa_bytes_to_usec(u->read_bytes, &s->sample_spec); + err = ioctl(u->fd, AUDIO_GETINFO, &info); + pa_assert(err >= 0); - return r; -} + /* + * Since we cannot modify the size of the output buffer we fake it + * by not filling it more than u->buffer_size. + */ + len = u->buffer_size; + len -= u->written_bytes - (info.play.samples * u->frame_size); -static int sink_get_hw_volume_cb(pa_sink *s) { - struct userdata *u = s->userdata; - audio_info_t info; - int err; + /* The sample counter can sometimes go backwards :( */ + if (len > u->buffer_size) + len = 0; - err = ioctl(u->fd, AUDIO_GETINFO, &info); - assert(err >= 0); + if (info.play.error) { + pa_log_debug("Solaris buffer underflow!"); + clear_underflow(u); + } - pa_cvolume_set(&s->hw_volume, s->hw_volume.channels, - info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN); + len -= len % u->frame_size; - return 0; -} + while (len) { + void *p; + ssize_t r; -static int sink_set_hw_volume_cb(pa_sink *s) { - struct userdata *u = s->userdata; - audio_info_t info; + if (!u->memchunk.length) + pa_sink_render(u->sink, len, &u->memchunk); - AUDIO_INITINFO(&info); + pa_assert(u->memchunk.length); - info.play.gain = pa_cvolume_avg(&s->hw_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM; - assert(info.play.gain <= AUDIO_MAX_GAIN); + p = pa_memblock_acquire(u->memchunk.memblock); + r = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, NULL); + pa_memblock_release(u->memchunk.memblock); - if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { - if (errno == EINVAL) - pa_log("AUDIO_SETINFO: Unsupported volume."); - else - pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); - return -1; - } + if (r < 0) { + if (errno == EINTR) + continue; + else if (errno != EAGAIN) { + pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno)); + goto fail; + } + } else { + pa_assert(r % u->frame_size == 0); - return 0; -} + u->memchunk.index += r; + u->memchunk.length -= r; -static int sink_get_hw_mute_cb(pa_sink *s) { - struct userdata *u = s->userdata; - audio_info_t info; - int err; + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + pa_memchunk_reset(&u->memchunk); + } - err = ioctl(u->fd, AUDIO_GETINFO, &info); - assert(err >= 0); + len -= r; + u->written_bytes += r; + } + } + } - s->hw_muted = !!info.output_muted; + /* Try to read some data and pass it on to the source driver */ + + if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state) && ((revents & POLLIN))) { + pa_memchunk memchunk; + int err; + size_t l; + void *p; + ssize_t r; + audio_info_t info; + + err = ioctl(u->fd, AUDIO_GETINFO, &info); + pa_assert(err >= 0); + + if (info.record.error) { + pa_log_debug("Solaris buffer overflow!"); + clear_overflow(u); + } + + err = ioctl(u->fd, I_NREAD, &l); + pa_assert(err >= 0); + + if (l > 0) { + /* This is to make sure it fits in the memory pool. Also, a page + should be the most efficient transfer size. */ + if (l > u->page_size) + l = u->page_size; + + memchunk.memblock = pa_memblock_new(u->core->mempool, l); + pa_assert(memchunk.memblock); + + p = pa_memblock_acquire(memchunk.memblock); + r = pa_read(u->fd, p, l, NULL); + pa_memblock_release(memchunk.memblock); + + if (r < 0) { + pa_memblock_unref(memchunk.memblock); + if (errno != EAGAIN) { + pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno)); + goto fail; + } + } else { + memchunk.index = 0; + memchunk.length = r; + + pa_source_post(u->source, &memchunk); + pa_memblock_unref(memchunk.memblock); + + u->read_bytes += r; + + revents &= ~POLLIN; + } + } + } - return 0; -} + if (u->fd >= 0) { + struct pollfd *pollfd; -static int sink_set_hw_mute_cb(pa_sink *s) { - struct userdata *u = s->userdata; - audio_info_t info; + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + pollfd->events = + ((u->source && PA_SOURCE_OPENED(u->source->thread_info.state)) ? POLLIN : 0); + } - AUDIO_INITINFO(&info); + /* Hmm, nothing to do. Let's sleep */ + if ((ret = pa_rtpoll_run(u->rtpoll, 1)) < 0) + goto fail; - info.output_muted = !!s->hw_muted; + if (ret == 0) + goto finish; - if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { - pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); - return -1; - } + if (u->fd >= 0) { + struct pollfd *pollfd; - return 0; -} + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); -static int source_get_hw_volume_cb(pa_source *s) { - struct userdata *u = s->userdata; - audio_info_t info; - int err; + if (pollfd->revents & ~(POLLOUT|POLLIN)) { + pa_log("DSP shutdown."); + goto fail; + } - err = ioctl(u->fd, AUDIO_GETINFO, &info); - assert(err >= 0); + revents = pollfd->revents; + } else + revents = 0; + } - pa_cvolume_set(&s->hw_volume, s->hw_volume.channels, - info.record.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN); +fail: + /* We have to continue processing messages until we receive the + * SHUTDOWN message */ + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); - return 0; +finish: + pa_log_debug("Thread shutting down"); } -static int source_set_hw_volume_cb(pa_source *s) { - struct userdata *u = s->userdata; - audio_info_t info; - - AUDIO_INITINFO(&info); +static void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata) { + struct userdata *u = userdata; - info.record.gain = pa_cvolume_avg(&s->hw_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM; - assert(info.record.gain <= AUDIO_MAX_GAIN); + assert(u); - if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { - if (errno == EINVAL) - pa_log("AUDIO_SETINFO: Unsupported volume."); - else - pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); - return -1; + if (u->sink) { + pa_sink_get_volume(u->sink); + pa_sink_get_mute(u->sink); } - return 0; + if (u->source) + pa_source_get_volume(u->source); } static int pa_solaris_auto_format(int fd, int mode, pa_sample_spec *ss) { @@ -490,6 +543,7 @@ static int pa_solaris_set_buffer(int fd, int buffer_size) { AUDIO_INITINFO(&info); + info.play.buffer_size = buffer_size; info.record.buffer_size = buffer_size; if (ioctl(fd, AUDIO_SETINFO, &info) < 0) { @@ -503,7 +557,7 @@ static int pa_solaris_set_buffer(int fd, int buffer_size) { return 0; } -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module *m) { struct userdata *u = NULL; const char *p; int fd = -1; @@ -513,9 +567,10 @@ int pa__init(pa_core *c, pa_module*m) { pa_sample_spec ss; pa_channel_map map; pa_modargs *ma = NULL; - struct timeval tv; char *t; - assert(c && m); + struct pollfd *pollfd; + + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("failed to parse module arguments."); @@ -540,7 +595,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - ss = c->default_sample_spec; + ss = m->core->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { pa_log("failed to parse sample specification"); goto fail; @@ -554,55 +609,18 @@ int pa__init(pa_core *c, pa_module*m) { if (pa_solaris_auto_format(fd, mode, &ss) < 0) goto fail; - if ((mode != O_WRONLY) && (buffer_size >= 1)) - if (pa_solaris_set_buffer(fd, buffer_size) < 0) - goto fail; + if (pa_solaris_set_buffer(fd, buffer_size) < 0) + goto fail; u = pa_xmalloc(sizeof(struct userdata)); - u->core = c; + u->core = m->core; - if (mode != O_WRONLY) { - u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map); - assert(u->source); - u->source->userdata = u; - u->source->get_latency = source_get_latency_cb; - u->source->get_hw_volume = source_get_hw_volume_cb; - u->source->set_hw_volume = source_set_hw_volume_cb; - pa_source_set_owner(u->source, m); - pa_source_set_description(u->source, t = pa_sprintf_malloc("Solaris PCM on '%s'", p)); - pa_xfree(t); - u->source->is_hardware = 1; - } else - u->source = NULL; - - if (mode != O_RDONLY) { - u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map); - assert(u->sink); - u->sink->get_latency = sink_get_latency_cb; - u->sink->get_hw_volume = sink_get_hw_volume_cb; - u->sink->set_hw_volume = sink_set_hw_volume_cb; - u->sink->get_hw_mute = sink_get_hw_mute_cb; - u->sink->set_hw_mute = sink_set_hw_mute_cb; - u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Solaris PCM on '%s'", p)); - pa_xfree(t); - u->sink->is_hardware = 1; - } else - u->sink = NULL; - - assert(u->source || u->sink); - - u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : 0); - assert(u->io); - pa_iochannel_set_callback(u->io, io_callback, u); u->fd = fd; - u->memchunk.memblock = NULL; - u->memchunk.length = 0; + pa_memchunk_reset(&u->memchunk); /* We use this to get a reasonable chunk size */ - u->page_size = sysconf(_SC_PAGESIZE); + u->page_size = PA_PAGE_SIZE; u->frame_size = pa_frame_size(&ss); u->buffer_size = buffer_size; @@ -610,37 +628,91 @@ int pa__init(pa_core *c, pa_module*m) { u->written_bytes = 0; u->read_bytes = 0; - u->sink_underflow = 1; - u->module = m; m->userdata = u; - u->poll_timeout = pa_bytes_to_usec(u->buffer_size / 10, &ss); + pa_thread_mq_init(&u->thread_mq, m->core->mainloop); + + u->rtpoll = pa_rtpoll_new(); + pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq); + + pa_rtpoll_set_timer_periodic(u->rtpoll, pa_bytes_to_usec(u->buffer_size / 10, &ss)); - pa_gettimeofday(&tv); - pa_timeval_add(&tv, u->poll_timeout); + u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + pollfd->fd = fd; + pollfd->events = 0; + pollfd->revents = 0; - u->timer = c->mainloop->time_new(c->mainloop, &tv, timer_cb, u); - assert(u->timer); + if (mode != O_WRONLY) { + u->source = pa_source_new(m->core, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map); + pa_assert(u->source); + + u->source->userdata = u; + u->source->parent.process_msg = source_process_msg; + + pa_source_set_module(u->source, m); + pa_source_set_description(u->source, t = pa_sprintf_malloc("Solaris PCM on '%s'", p)); + pa_xfree(t); + pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); + pa_source_set_rtpoll(u->source, u->rtpoll); + + u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL; + u->source->refresh_volume = 1; + } else + u->source = NULL; + + if (mode != O_RDONLY) { + u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map); + pa_assert(u->sink); + + u->sink->userdata = u; + u->sink->parent.process_msg = sink_process_msg; + + pa_sink_set_module(u->sink, m); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Solaris PCM on '%s'", p)); + pa_xfree(t); + pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); + pa_sink_set_rtpoll(u->sink, u->rtpoll); + + u->sink->flags = PA_SINK_HARDWARE|PA_SINK_LATENCY|PA_SINK_HW_VOLUME_CTRL; + u->sink->refresh_volume = 1; + u->sink->refresh_mute = 1; + } else + u->sink = NULL; + + pa_assert(u->source || u->sink); u->sig = pa_signal_new(SIGPOLL, sig_callback, u); - assert(u->sig); + pa_assert(u->sig); ioctl(u->fd, I_SETSIG, S_MSG); - pa_modargs_free(ma); + if (!(u->thread = pa_thread_new(thread_func, u))) { + pa_log("Failed to create thread."); + goto fail; + } /* Read mixer settings */ if (u->source) - source_get_hw_volume_cb(u->source); + pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->source), PA_SOURCE_MESSAGE_GET_VOLUME, &u->source->volume, 0, NULL); if (u->sink) { - sink_get_hw_volume_cb(u->sink); - sink_get_hw_mute_cb(u->sink); + pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->sink), PA_SINK_MESSAGE_GET_VOLUME, &u->sink->volume, 0, NULL); + pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->sink), PA_SINK_MESSAGE_GET_MUTE, &u->sink->muted, 0, NULL); } + if (u->sink) + pa_sink_put(u->sink); + if (u->source) + pa_source_put(u->source); + + pa_modargs_free(ma); + return 0; fail: - if (fd >= 0) + if (u) + pa__done(m); + else if (fd >= 0) close(fd); if (ma) @@ -649,31 +721,47 @@ fail: return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module *m) { struct userdata *u; - assert(c && m); + + pa_assert(m); if (!(u = m->userdata)) return; - if (u->timer) - c->mainloop->time_free(u->timer); ioctl(u->fd, I_SETSIG, 0); pa_signal_free(u->sig); - if (u->memchunk.memblock) - pa_memblock_unref(u->memchunk.memblock); + if (u->sink) + pa_sink_unlink(u->sink); - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); + if (u->source) + pa_source_unlink(u->source); + + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); } - if (u->source) { - pa_source_disconnect(u->source); + pa_thread_mq_done(&u->thread_mq); + + if (u->sink) + pa_sink_unref(u->sink); + + if (u->source) pa_source_unref(u->source); - } - pa_iochannel_free(u->io); + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + + if (u->rtpoll_item) + pa_rtpoll_item_free(u->rtpoll_item); + + if (u->rtpoll) + pa_rtpoll_free(u->rtpoll); + + if (u->fd >= 0) + close(u->fd); + pa_xfree(u); } diff --git a/src/modules/module-suspend-on-idle.c b/src/modules/module-suspend-on-idle.c new file mode 100644 index 00000000..5a711390 --- /dev/null +++ b/src/modules/module-suspend-on-idle.c @@ -0,0 +1,473 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "module-suspend-on-idle-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("When a sink/source is idle for too long, suspend it") +PA_MODULE_VERSION(PACKAGE_VERSION) + +static const char* const valid_modargs[] = { + "timeout", + NULL, +}; + +struct userdata { + pa_core *core; + pa_usec_t timeout; + pa_hashmap *device_infos; + pa_hook_slot + *sink_new_slot, + *source_new_slot, + *sink_unlink_slot, + *source_unlink_slot, + *sink_state_changed_slot, + *source_state_changed_slot; + + pa_hook_slot + *sink_input_new_slot, + *source_output_new_slot, + *sink_input_unlink_slot, + *source_output_unlink_slot, + *sink_input_move_slot, + *source_output_move_slot, + *sink_input_move_post_slot, + *source_output_move_post_slot, + *sink_input_state_changed_slot, + *source_output_state_changed_slot; +}; + +struct device_info { + struct userdata *userdata; + pa_sink *sink; + pa_source *source; + struct timeval last_use; + pa_time_event *time_event; +}; + +static void timeout_cb(pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata) { + struct device_info *d = userdata; + + pa_assert(d); + + d->userdata->core->mainloop->time_restart(d->time_event, NULL); + + if (d->sink && pa_sink_used_by(d->sink) <= 0 && pa_sink_get_state(d->sink) != PA_SINK_SUSPENDED) { + pa_log_info("Sink %s idle for too long, suspending ...", d->sink->name); + pa_sink_suspend(d->sink, TRUE); + } + + if (d->source && pa_source_used_by(d->source) <= 0 && pa_source_get_state(d->source) != PA_SOURCE_SUSPENDED) { + pa_log_info("Source %s idle for too long, suspending ...", d->source->name); + pa_source_suspend(d->source, TRUE); + } +} + +static void restart(struct device_info *d) { + struct timeval tv; + pa_assert(d); + + pa_gettimeofday(&tv); + d->last_use = tv; + pa_timeval_add(&tv, d->userdata->timeout*1000000); + d->userdata->core->mainloop->time_restart(d->time_event, &tv); + + if (d->sink) + pa_log_debug("Sink %s becomes idle.", d->sink->name); + if (d->source) + pa_log_debug("Source %s becomes idle.", d->source->name); +} + +static void resume(struct device_info *d) { + pa_assert(d); + + d->userdata->core->mainloop->time_restart(d->time_event, NULL); + + if (d->sink) { + pa_sink_suspend(d->sink, FALSE); + + pa_log_debug("Sink %s becomes busy.", d->sink->name); + } + + if (d->source) { + pa_source_suspend(d->source, FALSE); + + pa_log_debug("Source %s becomes busy.", d->source->name); + } +} + +static pa_hook_result_t sink_input_new_hook_cb(pa_core *c, pa_sink_input *s, struct userdata *u) { + struct device_info *d; + + pa_assert(c); + pa_sink_input_assert_ref(s); + pa_assert(u); + + if ((d = pa_hashmap_get(u->device_infos, s->sink))) + resume(d); + + return PA_HOOK_OK; +} + +static pa_hook_result_t source_output_new_hook_cb(pa_core *c, pa_source_output *s, struct userdata *u) { + struct device_info *d; + + pa_assert(c); + pa_source_output_assert_ref(s); + pa_assert(u); + + if ((d = pa_hashmap_get(u->device_infos, s->source))) + resume(d); + + return PA_HOOK_OK; +} + +static pa_hook_result_t sink_input_unlink_hook_cb(pa_core *c, pa_sink_input *s, struct userdata *u) { + pa_assert(c); + pa_sink_input_assert_ref(s); + pa_assert(u); + + if (pa_sink_used_by(s->sink) <= 0) { + struct device_info *d; + if ((d = pa_hashmap_get(u->device_infos, s->sink))) + restart(d); + } + + return PA_HOOK_OK; +} + +static pa_hook_result_t source_output_unlink_hook_cb(pa_core *c, pa_source_output *s, struct userdata *u) { + pa_assert(c); + pa_source_output_assert_ref(s); + pa_assert(u); + + if (pa_source_used_by(s->source) <= 0) { + struct device_info *d; + if ((d = pa_hashmap_get(u->device_infos, s->source))) + restart(d); + } + + return PA_HOOK_OK; +} + +static pa_hook_result_t sink_input_move_hook_cb(pa_core *c, pa_sink_input *s, struct userdata *u) { + pa_assert(c); + pa_sink_input_assert_ref(s); + pa_assert(u); + + if (pa_sink_used_by(s->sink) <= 1) { + struct device_info *d; + if ((d = pa_hashmap_get(u->device_infos, s->sink))) + restart(d); + } + + return PA_HOOK_OK; +} + +static pa_hook_result_t sink_input_move_post_hook_cb(pa_core *c, pa_sink_input *s, struct userdata *u) { + struct device_info *d; + pa_assert(c); + pa_sink_input_assert_ref(s); + pa_assert(u); + + if ((d = pa_hashmap_get(u->device_infos, s->sink))) + resume(d); + + return PA_HOOK_OK; +} + +static pa_hook_result_t source_output_move_hook_cb(pa_core *c, pa_source_output *s, struct userdata *u) { + pa_assert(c); + pa_source_output_assert_ref(s); + pa_assert(u); + + if (pa_source_used_by(s->source) <= 1) { + struct device_info *d; + + if ((d = pa_hashmap_get(u->device_infos, s->source))) + restart(d); + } + + return PA_HOOK_OK; +} + +static pa_hook_result_t source_output_move_post_hook_cb(pa_core *c, pa_source_output *s, struct userdata *u) { + struct device_info *d; + pa_assert(c); + pa_source_output_assert_ref(s); + pa_assert(u); + + if ((d = pa_hashmap_get(u->device_infos, s->source))) + resume(d); + + return PA_HOOK_OK; +} + +static pa_hook_result_t sink_input_state_changed_hook_cb(pa_core *c, pa_sink_input *s, struct userdata *u) { + struct device_info *d; + pa_sink_input_state_t state; + pa_assert(c); + pa_sink_input_assert_ref(s); + pa_assert(u); + + state = pa_sink_input_get_state(s); + if (state == PA_SINK_INPUT_RUNNING || state == PA_SINK_INPUT_DRAINED) + if ((d = pa_hashmap_get(u->device_infos, s->sink))) + resume(d); + + return PA_HOOK_OK; +} + +static pa_hook_result_t source_output_state_changed_hook_cb(pa_core *c, pa_source_output *s, struct userdata *u) { + struct device_info *d; + pa_source_output_state_t state; + pa_assert(c); + pa_source_output_assert_ref(s); + pa_assert(u); + + state = pa_source_output_get_state(s); + if (state == PA_SOURCE_OUTPUT_RUNNING) + if ((d = pa_hashmap_get(u->device_infos, s->source))) + resume(d); + + return PA_HOOK_OK; +} + +static pa_hook_result_t device_new_hook_cb(pa_core *c, pa_object *o, struct userdata *u) { + struct device_info *d; + pa_source *source; + pa_sink *sink; + + pa_assert(c); + pa_object_assert_ref(o); + pa_assert(u); + + source = pa_source_isinstance(o) ? PA_SOURCE(o) : NULL; + sink = pa_sink_isinstance(o) ? PA_SINK(o) : NULL; + + pa_assert(source || sink); + + d = pa_xnew(struct device_info, 1); + d->userdata = u; + d->source = source ? pa_source_ref(source) : NULL; + d->sink = sink ? pa_sink_ref(sink) : NULL; + d->time_event = c->mainloop->time_new(c->mainloop, NULL, timeout_cb, d); + pa_hashmap_put(u->device_infos, o, d); + + if ((d->sink && pa_sink_used_by(d->sink) <= 0) || + (d->source && pa_source_used_by(d->source) <= 0)) + restart(d); + + return PA_HOOK_OK; +} + +static void device_info_free(struct device_info *d) { + pa_assert(d); + + if (d->source) + pa_source_unref(d->source); + if (d->sink) + pa_sink_unref(d->sink); + + d->userdata->core->mainloop->time_free(d->time_event); + + pa_xfree(d); +} + +static pa_hook_result_t device_unlink_hook_cb(pa_core *c, pa_object *o, struct userdata *u) { + struct device_info *d; + + pa_assert(c); + pa_object_assert_ref(o); + pa_assert(u); + + if ((d = pa_hashmap_remove(u->device_infos, o))) + device_info_free(d); + + return PA_HOOK_OK; +} + +static pa_hook_result_t device_state_changed_hook_cb(pa_core *c, pa_object *o, struct userdata *u) { + struct device_info *d; + + pa_assert(c); + pa_object_assert_ref(o); + pa_assert(u); + + if (!(d = pa_hashmap_get(u->device_infos, o))) + return PA_HOOK_OK; + + if (pa_sink_isinstance(o)) { + pa_sink *s = PA_SINK(o); + pa_sink_state_t state = pa_sink_get_state(s); + + if (pa_sink_used_by(s) <= 0) { + + if (PA_SINK_OPENED(state)) + restart(d); + + } + + } else if (pa_source_isinstance(o)) { + pa_source *s = PA_SOURCE(o); + pa_source_state_t state = pa_source_get_state(s); + + if (pa_source_used_by(s) <= 0) { + + if (PA_SOURCE_OPENED(state)) + restart(d); + } + } + + return PA_HOOK_OK; +} + +int pa__init(pa_module*m) { + pa_modargs *ma = NULL; + struct userdata *u; + uint32_t timeout = 1; + uint32_t idx; + pa_sink *sink; + pa_source *source; + + pa_assert(m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log("Failed to parse module arguments."); + goto fail; + } + + if (pa_modargs_get_value_u32(ma, "timeout", &timeout) < 0) { + pa_log("Failed to parse timeout value."); + goto fail; + } + + m->userdata = u = pa_xnew(struct userdata, 1); + u->core = m->core; + u->timeout = timeout; + u->device_infos = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + + for (sink = pa_idxset_first(m->core->sinks, &idx); sink; sink = pa_idxset_next(m->core->sinks, &idx)) + device_new_hook_cb(m->core, PA_OBJECT(sink), u); + + for (source = pa_idxset_first(m->core->sources, &idx); source; source = pa_idxset_next(m->core->sources, &idx)) + device_new_hook_cb(m->core, PA_OBJECT(source), u); + + u->sink_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_NEW_POST], (pa_hook_cb_t) device_new_hook_cb, u); + u->source_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_NEW_POST], (pa_hook_cb_t) device_new_hook_cb, u); + u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], (pa_hook_cb_t) device_unlink_hook_cb, u); + u->source_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK_POST], (pa_hook_cb_t) device_unlink_hook_cb, u); + u->sink_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], (pa_hook_cb_t) device_state_changed_hook_cb, u); + u->source_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], (pa_hook_cb_t) device_state_changed_hook_cb, u); + + u->sink_input_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], (pa_hook_cb_t) sink_input_new_hook_cb, u); + u->source_output_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], (pa_hook_cb_t) source_output_new_hook_cb, u); + u->sink_input_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK_POST], (pa_hook_cb_t) sink_input_unlink_hook_cb, u); + u->source_output_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], (pa_hook_cb_t) source_output_unlink_hook_cb, u); + u->sink_input_move_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE], (pa_hook_cb_t) sink_input_move_hook_cb, u); + u->source_output_move_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE], (pa_hook_cb_t) source_output_move_hook_cb, u); + u->sink_input_move_post_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_POST], (pa_hook_cb_t) sink_input_move_post_hook_cb, u); + u->source_output_move_post_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_POST], (pa_hook_cb_t) source_output_move_post_hook_cb, u); + u->sink_input_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], (pa_hook_cb_t) sink_input_state_changed_hook_cb, u); + u->source_output_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], (pa_hook_cb_t) source_output_state_changed_hook_cb, u); + + + pa_modargs_free(ma); + return 0; + +fail: + + if (ma) + pa_modargs_free(ma); + + return -1; +} + +void pa__done(pa_module*m) { + struct userdata *u; + struct device_info *d; + + pa_assert(m); + + if (!m->userdata) + return; + + u = m->userdata; + + if (u->sink_new_slot) + pa_hook_slot_free(u->sink_new_slot); + if (u->sink_unlink_slot) + pa_hook_slot_free(u->sink_unlink_slot); + if (u->sink_state_changed_slot) + pa_hook_slot_free(u->sink_state_changed_slot); + + if (u->source_new_slot) + pa_hook_slot_free(u->source_new_slot); + if (u->source_unlink_slot) + pa_hook_slot_free(u->source_unlink_slot); + if (u->source_state_changed_slot) + pa_hook_slot_free(u->source_state_changed_slot); + + if (u->sink_input_new_slot) + pa_hook_slot_free(u->sink_input_new_slot); + if (u->sink_input_unlink_slot) + pa_hook_slot_free(u->sink_input_unlink_slot); + if (u->sink_input_move_slot) + pa_hook_slot_free(u->sink_input_move_slot); + if (u->sink_input_move_post_slot) + pa_hook_slot_free(u->sink_input_move_post_slot); + if (u->sink_input_state_changed_slot) + pa_hook_slot_free(u->sink_input_state_changed_slot); + + if (u->source_output_new_slot) + pa_hook_slot_free(u->source_output_new_slot); + if (u->source_output_unlink_slot) + pa_hook_slot_free(u->source_output_unlink_slot); + if (u->source_output_move_slot) + pa_hook_slot_free(u->source_output_move_slot); + if (u->source_output_move_post_slot) + pa_hook_slot_free(u->source_output_move_post_slot); + if (u->source_output_state_changed_slot) + pa_hook_slot_free(u->source_output_state_changed_slot); + + while ((d = pa_hashmap_steal_first(u->device_infos))) + device_info_free(d); + + pa_hashmap_free(u->device_infos, NULL, NULL); + + pa_xfree(u); +} diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 288e049e..b96d46b3 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -596,12 +596,12 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t } #ifdef TUNNEL_SINK - snprintf(name, sizeof(name), "Tunnel from host %s, user %s, sink %s", + pa_snprintf(name, sizeof(name), "Tunnel from host %s, user %s, sink %s", pa_get_host_name(hn, sizeof(hn)), pa_get_user_name(un, sizeof(un)), u->sink->name); #else - snprintf(name, sizeof(name), "Tunnel from host %s, user %s, source %s", + pa_snprintf(name, sizeof(name), "Tunnel from host %s, user %s, source %s", pa_get_host_name(hn, sizeof(hn)), pa_get_user_name(un, sizeof(un)), u->source->name); diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index 61a17aef..77e6174f 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -26,7 +26,6 @@ #endif #include -#include #include #include #include @@ -35,6 +34,7 @@ #include #include +#include #include #include @@ -44,9 +44,7 @@ #include #include #include -#include #include -#include #include "module-volume-restore-symdef.h" @@ -85,8 +83,8 @@ static pa_cvolume* parse_volume(const char *s, pa_cvolume *v) { long k; unsigned i; - assert(s); - assert(v); + pa_assert(s); + pa_assert(v); if (!isdigit(*s)) return NULL; @@ -170,7 +168,7 @@ static int load_rules(struct userdata *u) { continue; } - assert(ln == buf_source); + pa_assert(ln == buf_source); if (buf_volume[0]) { if (!parse_volume(buf_volume, &v)) { @@ -297,8 +295,8 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 struct rule *r; char *name; - assert(c); - assert(u); + pa_assert(c); + pa_assert(u); if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW) && t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) && @@ -313,7 +311,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 if (!si->client || !(name = client_name(si->client))) return; } else { - assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT); + pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT); if (!(so = pa_idxset_get_by_index(c->source_outputs, idx))) return; @@ -341,7 +339,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 u->modified = 1; } } else { - assert(so); + pa_assert(so); if (!r->source || strcmp(so->source->name, r->source) != 0) { pa_log_info("Saving source for <%s>", r->name); @@ -363,7 +361,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 r->sink = pa_xstrdup(si->sink->name); r->source = NULL; } else { - assert(so); + pa_assert(so); r->volume_is_set = 0; r->sink = NULL; r->source = pa_xstrdup(so->source->name); @@ -378,7 +376,7 @@ static pa_hook_result_t sink_input_hook_callback(pa_core *c, pa_sink_input_new_d struct rule *r; char *name; - assert(data); + pa_assert(data); if (!data->client || !(name = client_name(data->client))) return PA_HOOK_OK; @@ -396,6 +394,8 @@ static pa_hook_result_t sink_input_hook_callback(pa_core *c, pa_sink_input_new_d } } + pa_xfree(name); + return PA_HOOK_OK; } @@ -403,7 +403,7 @@ static pa_hook_result_t source_output_hook_callback(pa_core *c, pa_source_output struct rule *r; char *name; - assert(data); + pa_assert(data); if (!data->client || !(name = client_name(data->client))) return PA_HOOK_OK; @@ -418,12 +418,11 @@ static pa_hook_result_t source_output_hook_callback(pa_core *c, pa_source_output return PA_HOOK_OK; } -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { pa_modargs *ma = NULL; struct userdata *u; - assert(c); - assert(m); + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments"); @@ -442,16 +441,15 @@ int pa__init(pa_core *c, pa_module*m) { if (load_rules(u) < 0) goto fail; - u->subscription = pa_subscription_new(c, PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscribe_callback, u); - u->sink_input_hook_slot = pa_hook_connect(&c->hook_sink_input_new, (pa_hook_cb_t) sink_input_hook_callback, u); - u->source_output_hook_slot = pa_hook_connect(&c->hook_source_output_new, (pa_hook_cb_t) source_output_hook_callback, u); + u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscribe_callback, u); + u->sink_input_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], (pa_hook_cb_t) sink_input_hook_callback, u); + u->source_output_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], (pa_hook_cb_t) source_output_hook_callback, u); pa_modargs_free(ma); return 0; fail: - pa__done(c, m); - + pa__done(m); if (ma) pa_modargs_free(ma); @@ -460,7 +458,7 @@ fail: static void free_func(void *p, void *userdata) { struct rule *r = p; - assert(r); + pa_assert(r); pa_xfree(r->name); pa_xfree(r->sink); @@ -468,11 +466,10 @@ static void free_func(void *p, void *userdata) { pa_xfree(r); } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata* u; - assert(c); - assert(m); + pa_assert(m); if (!(u = m->userdata)) return; diff --git a/src/modules/module-x11-bell.c b/src/modules/module-x11-bell.c index b9c4ad49..4eacbb1e 100644 --- a/src/modules/module-x11-bell.c +++ b/src/modules/module-x11-bell.c @@ -26,7 +26,6 @@ #endif #include -#include #include #include @@ -67,30 +66,21 @@ static const char* const valid_modargs[] = { NULL }; -static int ring_bell(struct userdata *u, int percent) { - pa_sink *s; - assert(u); - - if (!(s = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log("Invalid sink: %s", u->sink_name); - return -1; - } - - pa_scache_play_item(u->core, u->scache_item, s, (percent*PA_VOLUME_NORM)/100); - return 0; -} - static int x11_event_callback(pa_x11_wrapper *w, XEvent *e, void *userdata) { XkbBellNotifyEvent *bne; struct userdata *u = userdata; - assert(w && e && u && u->x11_wrapper == w); + + pa_assert(w); + pa_assert(e); + pa_assert(u); + pa_assert(u->x11_wrapper == w); if (((XkbEvent*) e)->any.xkb_type != XkbBellNotify) return 0; bne = (XkbBellNotifyEvent*) e; - if (ring_bell(u, bne->percent) < 0) { + if (pa_scache_play_item_by_name(u->core, u->scache_item, u->sink_name, (bne->percent*PA_VOLUME_NORM)/100, 1) < 0) { pa_log_info("Ringing bell failed, reverting to X11 device bell."); XkbForceDeviceBell(pa_x11_wrapper_get_display(w), bne->device, bne->bell_class, bne->bell_id, bne->percent); } @@ -98,25 +88,27 @@ static int x11_event_callback(pa_x11_wrapper *w, XEvent *e, void *userdata) { return 1; } -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { + struct userdata *u = NULL; pa_modargs *ma = NULL; int major, minor; unsigned int auto_ctrls, auto_values; - assert(c && m); + + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log("failed to parse module arguments"); + pa_log("Failed to parse module arguments"); goto fail; } - m->userdata = u = pa_xmalloc(sizeof(struct userdata)); - u->core = c; + m->userdata = u = pa_xnew(struct userdata, 1); + u->core = m->core; u->scache_item = pa_xstrdup(pa_modargs_get_value(ma, "sample", "x11-bell")); u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); u->x11_client = NULL; - if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL)))) + if (!(u->x11_wrapper = pa_x11_wrapper_get(m->core, pa_modargs_get_value(ma, "display", NULL)))) goto fail; major = XkbMajorVersion; @@ -130,7 +122,6 @@ int pa__init(pa_core *c, pa_module*m) { major = XkbMajorVersion; minor = XkbMinorVersion; - if (!XkbQueryExtension(pa_x11_wrapper_get_display(u->x11_wrapper), NULL, &u->xkb_event_base, NULL, &major, &minor)) { pa_log("XkbQueryExtension() failed"); goto fail; @@ -150,14 +141,21 @@ int pa__init(pa_core *c, pa_module*m) { fail: if (ma) pa_modargs_free(ma); - if (m->userdata) - pa__done(c, m); + + pa__done(m); + return -1; } -void pa__done(pa_core *c, pa_module*m) { - struct userdata *u = m->userdata; - assert(c && m && u); +void pa__done(pa_module*m) { + struct userdata *u; + + pa_assert(m); + + if (!m->userdata) + return; + + u = m->userdata; pa_xfree(u->scache_item); pa_xfree(u->sink_name); diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c index fd1d532f..e0550e20 100644 --- a/src/modules/module-x11-publish.c +++ b/src/modules/module-x11-publish.c @@ -26,7 +26,6 @@ #endif #include -#include #include #include #include @@ -76,7 +75,7 @@ struct userdata { }; static int load_key(struct userdata *u, const char*fn) { - assert(u); + pa_assert(u); u->auth_cookie_in_property = 0; @@ -93,7 +92,7 @@ static int load_key(struct userdata *u, const char*fn) { if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) return -1; - pa_log_debug("loading cookie from disk."); + pa_log_debug("Loading cookie from disk."); if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) u->auth_cookie_in_property = 1; @@ -101,7 +100,7 @@ static int load_key(struct userdata *u, const char*fn) { return 0; } -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { struct userdata *u; pa_modargs *ma = NULL; char hn[256], un[128]; @@ -110,23 +109,25 @@ int pa__init(pa_core *c, pa_module*m) { char *s; pa_strlist *l; + pa_assert(m); + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("failed to parse module arguments"); goto fail; } m->userdata = u = pa_xmalloc(sizeof(struct userdata)); - u->core = c; + u->core = m->core; u->id = NULL; u->auth_cookie_in_property = 0; if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0) goto fail; - if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL)))) + if (!(u->x11_wrapper = pa_x11_wrapper_get(m->core, pa_modargs_get_value(ma, "display", NULL)))) goto fail; - if (!(l = pa_property_get(c, PA_NATIVE_SERVER_PROPERTY_NAME))) + if (!(l = pa_property_get(m->core, PA_NATIVE_SERVER_PROPERTY_NAME))) goto fail; s = pa_strlist_tostring(l); @@ -154,13 +155,14 @@ fail: if (ma) pa_modargs_free(ma); - pa__done(c, m); + pa__done(m); return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata*u; - assert(c && m); + + pa_assert(m); if (!(u = m->userdata)) return; @@ -185,7 +187,7 @@ void pa__done(pa_core *c, pa_module*m) { pa_x11_wrapper_unref(u->x11_wrapper); if (u->auth_cookie_in_property) - pa_authkey_prop_unref(c, PA_NATIVE_COOKIE_PROPERTY_NAME); + pa_authkey_prop_unref(m->core, PA_NATIVE_COOKIE_PROPERTY_NAME); pa_xfree(u->id); pa_xfree(u); diff --git a/src/modules/module-x11-xsmp.c b/src/modules/module-x11-xsmp.c new file mode 100644 index 00000000..3e353caf --- /dev/null +++ b/src/modules/module-x11-xsmp.c @@ -0,0 +1,195 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "module-x11-xsmp-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("X11 session management") +PA_MODULE_VERSION(PACKAGE_VERSION) + +static int ice_in_use = 0; + +static const char* const valid_modargs[] = { + NULL +}; + +static void die_cb(SmcConn connection, SmPointer client_data){ + pa_core *c = PA_CORE(client_data); + + pa_log_debug("Got die message from XSM. Exiting..."); + + pa_core_assert_ref(c); + c->mainloop->quit(c->mainloop, 0); +} + +static void save_complete_cb(SmcConn connection, SmPointer client_data) { +} + +static void shutdown_cancelled_cb(SmcConn connection, SmPointer client_data) { + SmcSaveYourselfDone(connection, True); +} + +static void save_yourself_cb(SmcConn connection, SmPointer client_data, int save_type, Bool _shutdown, int interact_style, Bool fast) { + SmcSaveYourselfDone(connection, True); +} + +static void ice_io_cb(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) { + IceConn connection = userdata; + + if (IceProcessMessages(connection, NULL, NULL) == IceProcessMessagesIOError) { + IceSetShutdownNegotiation(connection, False); + IceCloseConnection(connection); + } +} + +static void new_ice_connection(IceConn connection, IcePointer client_data, Bool opening, IcePointer *watch_data) { + pa_core *c = client_data; + + pa_assert(c); + + if (opening) + *watch_data = c->mainloop->io_new(c->mainloop, IceConnectionNumber(connection), PA_IO_EVENT_INPUT, ice_io_cb, connection); + else + c->mainloop->io_free(*watch_data); +} + +int pa__init(pa_module*m) { + + pa_modargs *ma = NULL; + char t[256], *vendor, *client_id; + SmcCallbacks callbacks; + SmProp prop_program, prop_user; + SmProp *prop_list[2]; + SmPropValue val_program, val_user; + SmcConn connection; + + pa_assert(m); + + if (ice_in_use) { + pa_log("module-x11-xsmp may no be loaded twice."); + return -1; + } + + IceAddConnectionWatch(new_ice_connection, m->core); + ice_in_use = 1; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log("Failed to parse module arguments"); + goto fail; + } + + if (!getenv("SESSION_MANAGER")) { + pa_log("X11 session manager not running."); + goto fail; + } + + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.die.callback = die_cb; + callbacks.die.client_data = m->core; + callbacks.save_yourself.callback = save_yourself_cb; + callbacks.save_yourself.client_data = m->core; + callbacks.save_complete.callback = save_complete_cb; + callbacks.save_complete.client_data = m->core; + callbacks.shutdown_cancelled.callback = shutdown_cancelled_cb; + callbacks.shutdown_cancelled.client_data = m->core; + + if (!(m->userdata = connection = SmcOpenConnection( + NULL, m->core, + SmProtoMajor, SmProtoMinor, + SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask, + &callbacks, NULL, &client_id, + sizeof(t), t))) { + + pa_log("Failed to open connection to session manager: %s", t); + goto fail; + } + + prop_program.name = (char*) SmProgram; + prop_program.type = (char*) SmARRAY8; + val_program.value = (char*) PACKAGE_NAME; + val_program.length = strlen(val_program.value); + prop_program.num_vals = 1; + prop_program.vals = &val_program; + prop_list[0] = &prop_program; + + prop_user.name = (char*) SmUserID; + prop_user.type = (char*) SmARRAY8; + pa_get_user_name(t, sizeof(t)); + val_user.value = t; + val_user.length = strlen(val_user.value); + prop_user.num_vals = 1; + prop_user.vals = &val_user; + prop_list[1] = &prop_user; + + SmcSetProperties(connection, PA_ELEMENTSOF(prop_list), prop_list); + + pa_log_info("Connected to session manager '%s' as '%s'.", vendor = SmcVendor(connection), client_id); + free(vendor); + free(client_id); + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + pa__done(m); + + return -1; +} + +void pa__done(pa_module*m) { + pa_assert(m); + + if (m->userdata) + SmcCloseConnection(m->userdata, 0, NULL); + + if (ice_in_use) { + IceRemoveConnectionWatch(new_ice_connection, m->core); + ice_in_use = 0; + } +} diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index 69508ad0..113686cf 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -26,7 +26,6 @@ #endif #include -#include #include #include #include @@ -35,11 +34,11 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -71,56 +70,52 @@ struct service { struct userdata *userdata; AvahiEntryGroup *entry_group; char *service_name; - char *name; - enum { UNPUBLISHED, PUBLISHED_REAL, PUBLISHED_AUTOLOAD } published ; - - struct { - int valid; - pa_namereg_type_t type; - uint32_t index; - } loaded; - - struct { - int valid; - pa_namereg_type_t type; - uint32_t index; - } autoload; + pa_object *device; }; struct userdata { pa_core *core; AvahiPoll *avahi_poll; AvahiClient *client; + pa_hashmap *services; - pa_dynarray *sink_dynarray, *source_dynarray, *autoload_dynarray; - pa_subscription *subscription; char *service_name; AvahiEntryGroup *main_entry_group; uint16_t port; + + pa_hook_slot *sink_new_slot, *source_new_slot, *sink_unlink_slot, *source_unlink_slot, *sink_changed_slot, *source_changed_slot; }; -static void get_service_data(struct userdata *u, struct service *s, pa_sample_spec *ret_ss, char **ret_description) { - assert(u && s && s->loaded.valid && ret_ss && ret_description); +static void get_service_data(struct service *s, pa_sample_spec *ret_ss, pa_channel_map *ret_map, const char **ret_name, const char **ret_description) { + pa_assert(s); + pa_assert(ret_ss); + pa_assert(ret_description); + + if (pa_sink_isinstance(s->device)) { + pa_sink *sink = PA_SINK(s->device); - if (s->loaded.type == PA_NAMEREG_SINK) { - pa_sink *sink = pa_idxset_get_by_index(u->core->sinks, s->loaded.index); - assert(sink); *ret_ss = sink->sample_spec; + *ret_map = sink->channel_map; + *ret_name = sink->name; *ret_description = sink->description; - } else if (s->loaded.type == PA_NAMEREG_SOURCE) { - pa_source *source = pa_idxset_get_by_index(u->core->sources, s->loaded.index); - assert(source); + + } else if (pa_source_isinstance(s->device)) { + pa_source *source = PA_SOURCE(s->device); + *ret_ss = source->sample_spec; + *ret_map = source->channel_map; + *ret_name = source->name; *ret_description = source->description; } else - assert(0); + pa_assert_not_reached(); } static AvahiStringList* txt_record_server_data(pa_core *c, AvahiStringList *l) { char s[128]; - assert(c); + + pa_assert(c); l = avahi_string_list_add_pair(l, "server-version", PACKAGE_NAME" "PACKAGE_VERSION); l = avahi_string_list_add_pair(l, "user-name", pa_get_user_name(s, sizeof(s))); @@ -130,325 +125,217 @@ static AvahiStringList* txt_record_server_data(pa_core *c, AvahiStringList *l) { return l; } -static int publish_service(struct userdata *u, struct service *s); +static int publish_service(struct service *s); static void service_entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) { struct service *s = userdata; - if (state == AVAHI_ENTRY_GROUP_COLLISION) { - char *t; + pa_assert(s); + + switch (state) { + + case AVAHI_ENTRY_GROUP_ESTABLISHED: + pa_log_info("Successfully established service %s.", s->service_name); + break; + + case AVAHI_ENTRY_GROUP_COLLISION: { + char *t; + + t = avahi_alternative_service_name(s->service_name); + pa_log_info("Name collision, renaming %s to %s.", s->service_name, t); + pa_xfree(s->service_name); + s->service_name = t; + + publish_service(s); + break; + } + + case AVAHI_ENTRY_GROUP_FAILURE: { + pa_log("Failed to register service: %s", avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g)))); - t = avahi_alternative_service_name(s->service_name); - pa_xfree(s->service_name); - s->service_name = t; + avahi_entry_group_free(g); + s->entry_group = NULL; - publish_service(s->userdata, s); + break; + } + + case AVAHI_ENTRY_GROUP_UNCOMMITED: + case AVAHI_ENTRY_GROUP_REGISTERING: + ; } } -static int publish_service(struct userdata *u, struct service *s) { +static void service_free(struct service *s); + +static int publish_service(struct service *s) { int r = -1; AvahiStringList *txt = NULL; + const char *description = NULL, *name = NULL; + pa_sample_spec ss; + pa_channel_map map; + char cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - assert(u); - assert(s); + pa_assert(s); - if (!u->client || avahi_client_get_state(u->client) != AVAHI_CLIENT_S_RUNNING) + if (!s->userdata->client || avahi_client_get_state(s->userdata->client) != AVAHI_CLIENT_S_RUNNING) return 0; - if ((s->published == PUBLISHED_REAL && s->loaded.valid) || - (s->published == PUBLISHED_AUTOLOAD && s->autoload.valid && !s->loaded.valid)) - return 0; - - if (s->published != UNPUBLISHED) { + if (!s->entry_group) { + if (!(s->entry_group = avahi_entry_group_new(s->userdata->client, service_entry_group_callback, s))) { + pa_log("avahi_entry_group_new(): %s", avahi_strerror(avahi_client_errno(s->userdata->client))); + goto finish; + } + } else avahi_entry_group_reset(s->entry_group); - s->published = UNPUBLISHED; - } - if (s->loaded.valid || s->autoload.valid) { - pa_namereg_type_t type; + txt = txt_record_server_data(s->userdata->core, txt); - if (!s->entry_group) { - if (!(s->entry_group = avahi_entry_group_new(u->client, service_entry_group_callback, s))) { - pa_log("avahi_entry_group_new(): %s", avahi_strerror(avahi_client_errno(u->client))); - goto finish; - } - } + get_service_data(s, &ss, &map, &name, &description); + txt = avahi_string_list_add_pair(txt, "device", name); + txt = avahi_string_list_add_printf(txt, "rate=%u", ss.rate); + txt = avahi_string_list_add_printf(txt, "channels=%u", ss.channels); + txt = avahi_string_list_add_pair(txt, "format", pa_sample_format_to_string(ss.format)); + txt = avahi_string_list_add_pair(txt, "channel_map", pa_channel_map_snprint(cm, sizeof(cm), &map)); - txt = avahi_string_list_add_pair(txt, "device", s->name); - txt = txt_record_server_data(u->core, txt); - - if (s->loaded.valid) { - char *description; - pa_sample_spec ss; - - get_service_data(u, s, &ss, &description); - - txt = avahi_string_list_add_printf(txt, "rate=%u", ss.rate); - txt = avahi_string_list_add_printf(txt, "channels=%u", ss.channels); - txt = avahi_string_list_add_pair(txt, "format", pa_sample_format_to_string(ss.format)); - if (description) - txt = avahi_string_list_add_pair(txt, "description", description); - - type = s->loaded.type; - } else if (s->autoload.valid) - type = s->autoload.type; - - if (avahi_entry_group_add_service_strlst( - s->entry_group, - AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, - 0, - s->service_name, - type == PA_NAMEREG_SINK ? SERVICE_TYPE_SINK : SERVICE_TYPE_SOURCE, - NULL, - NULL, - u->port, - txt) < 0) { - - pa_log("avahi_entry_group_add_service_strlst(): %s", avahi_strerror(avahi_client_errno(u->client))); - goto finish; - } + if (avahi_entry_group_add_service_strlst( + s->entry_group, + AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, + 0, + s->service_name, + pa_sink_isinstance(s->device) ? SERVICE_TYPE_SINK : SERVICE_TYPE_SOURCE, + NULL, + NULL, + s->userdata->port, + txt) < 0) { - if (avahi_entry_group_commit(s->entry_group) < 0) { - pa_log("avahi_entry_group_commit(): %s", avahi_strerror(avahi_client_errno(u->client))); - goto finish; - } + pa_log("avahi_entry_group_add_service_strlst(): %s", avahi_strerror(avahi_client_errno(s->userdata->client))); + goto finish; + } - if (s->loaded.valid) - s->published = PUBLISHED_REAL; - else if (s->autoload.valid) - s->published = PUBLISHED_AUTOLOAD; + if (avahi_entry_group_commit(s->entry_group) < 0) { + pa_log("avahi_entry_group_commit(): %s", avahi_strerror(avahi_client_errno(s->userdata->client))); + goto finish; } r = 0; + pa_log_debug("Successfully created entry group for %s.", s->service_name); finish: - if (s->published == UNPUBLISHED) { - /* Remove this service */ - - if (s->entry_group) - avahi_entry_group_free(s->entry_group); + /* Remove this service */ + if (r < 0) + service_free(s); - pa_hashmap_remove(u->services, s->name); - pa_xfree(s->name); - pa_xfree(s->service_name); - pa_xfree(s); - } - - if (txt) - avahi_string_list_free(txt); + avahi_string_list_free(txt); return r; } -static struct service *get_service(struct userdata *u, const char *name, const char *description) { +static struct service *get_service(struct userdata *u, pa_object *device) { struct service *s; - char hn[64]; + char hn[64], un[64]; + const char *n; + + pa_assert(u); + pa_object_assert_ref(device); - if ((s = pa_hashmap_get(u->services, name))) + if ((s = pa_hashmap_get(u->services, device))) return s; s = pa_xnew(struct service, 1); s->userdata = u; s->entry_group = NULL; - s->published = UNPUBLISHED; - s->name = pa_xstrdup(name); - s->loaded.valid = s->autoload.valid = 0; - s->service_name = pa_sprintf_malloc("%s on %s", description ? description : s->name, pa_get_host_name(hn, sizeof(hn))); - - pa_hashmap_put(u->services, s->name, s); - - return s; -} - -static int publish_sink(struct userdata *u, pa_sink *s) { - struct service *svc; - int ret; - assert(u && s); - - svc = get_service(u, s->name, s->description); - if (svc->loaded.valid) - return publish_service(u, svc); - - svc->loaded.valid = 1; - svc->loaded.type = PA_NAMEREG_SINK; - svc->loaded.index = s->index; - - if ((ret = publish_service(u, svc)) < 0) - return ret; - - pa_dynarray_put(u->sink_dynarray, s->index, svc); - return ret; -} - -static int publish_source(struct userdata *u, pa_source *s) { - struct service *svc; - int ret; - - assert(u && s); - - svc = get_service(u, s->name, s->description); - if (svc->loaded.valid) - return publish_service(u, svc); - - svc->loaded.valid = 1; - svc->loaded.type = PA_NAMEREG_SOURCE; - svc->loaded.index = s->index; + s->device = device; + + if (pa_sink_isinstance(device)) { + if (!(n = PA_SINK(device)->description)) + n = PA_SINK(device)->name; + } else { + if (!(n = PA_SOURCE(device)->description)) + n = PA_SOURCE(device)->name; + } - pa_dynarray_put(u->source_dynarray, s->index, svc); + s->service_name = pa_truncate_utf8(pa_sprintf_malloc("%s@%s: %s", + pa_get_user_name(un, sizeof(un)), + pa_get_host_name(hn, sizeof(hn)), + n), + AVAHI_LABEL_MAX-1); - if ((ret = publish_service(u, svc)) < 0) - return ret; + pa_hashmap_put(u->services, s->device, s); - pa_dynarray_put(u->sink_dynarray, s->index, svc); - return ret; + return s; } -static int publish_autoload(struct userdata *u, pa_autoload_entry *s) { - struct service *svc; - int ret; +static void service_free(struct service *s) { + pa_assert(s); - assert(u && s); + pa_hashmap_remove(s->userdata->services, s->device); - svc = get_service(u, s->name, NULL); - if (svc->autoload.valid) - return publish_service(u, svc); - - svc->autoload.valid = 1; - svc->autoload.type = s->type; - svc->autoload.index = s->index; - - if ((ret = publish_service(u, svc)) < 0) - return ret; + if (s->entry_group) { + pa_log_debug("Removing entry group for %s.", s->service_name); + avahi_entry_group_free(s->entry_group); + } - pa_dynarray_put(u->autoload_dynarray, s->index, svc); - return ret; + pa_xfree(s->service_name); + pa_xfree(s); } -static int remove_sink(struct userdata *u, uint32_t idx) { - struct service *svc; - assert(u && idx != PA_INVALID_INDEX); - - if (!(svc = pa_dynarray_get(u->sink_dynarray, idx))) - return 0; - - if (!svc->loaded.valid || svc->loaded.type != PA_NAMEREG_SINK) - return 0; +static pa_hook_result_t device_new_or_changed_cb(pa_core *c, pa_object *o, struct userdata *u) { + pa_assert(c); + pa_object_assert_ref(o); - svc->loaded.valid = 0; - pa_dynarray_put(u->sink_dynarray, idx, NULL); + publish_service(get_service(u, o)); - return publish_service(u, svc); + return PA_HOOK_OK; } -static int remove_source(struct userdata *u, uint32_t idx) { - struct service *svc; - assert(u && idx != PA_INVALID_INDEX); - - if (!(svc = pa_dynarray_get(u->source_dynarray, idx))) - return 0; +static pa_hook_result_t device_unlink_cb(pa_core *c, pa_object *o, struct userdata *u) { + struct service *s; - if (!svc->loaded.valid || svc->loaded.type != PA_NAMEREG_SOURCE) - return 0; + pa_assert(c); + pa_object_assert_ref(o); - svc->loaded.valid = 0; - pa_dynarray_put(u->source_dynarray, idx, NULL); + if ((s = pa_hashmap_get(u->services, o))) + service_free(s); - return publish_service(u, svc); + return PA_HOOK_OK; } -static int remove_autoload(struct userdata *u, uint32_t idx) { - struct service *svc; - assert(u && idx != PA_INVALID_INDEX); - - if (!(svc = pa_dynarray_get(u->autoload_dynarray, idx))) - return 0; - - if (!svc->autoload.valid) - return 0; - - svc->autoload.valid = 0; - pa_dynarray_put(u->autoload_dynarray, idx, NULL); - - return publish_service(u, svc); -} +static int publish_main_service(struct userdata *u); -static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { +static void main_entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) { struct userdata *u = userdata; - assert(u && c); - - switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) - case PA_SUBSCRIPTION_EVENT_SINK: { - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { - pa_sink *sink; - - if ((sink = pa_idxset_get_by_index(c->sinks, idx))) { - if (publish_sink(u, sink) < 0) - goto fail; - } - } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - if (remove_sink(u, idx) < 0) - goto fail; - } + pa_assert(u); - break; + switch (state) { - case PA_SUBSCRIPTION_EVENT_SOURCE: + case AVAHI_ENTRY_GROUP_ESTABLISHED: + pa_log_info("Successfully established main service."); + break; - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { - pa_source *source; + case AVAHI_ENTRY_GROUP_COLLISION: { + char *t; - if ((source = pa_idxset_get_by_index(c->sources, idx))) { - if (publish_source(u, source) < 0) - goto fail; - } - } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - if (remove_source(u, idx) < 0) - goto fail; - } + t = avahi_alternative_service_name(u->service_name); + pa_log_info("Name collision: renaming main service %s to %s.", u->service_name, t); + pa_xfree(u->service_name); + u->service_name = t; + publish_main_service(u); break; + } - case PA_SUBSCRIPTION_EVENT_AUTOLOAD: - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { - pa_autoload_entry *autoload; - - if ((autoload = pa_idxset_get_by_index(c->autoload_idxset, idx))) { - if (publish_autoload(u, autoload) < 0) - goto fail; - } - } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - if (remove_autoload(u, idx) < 0) - goto fail; - } + case AVAHI_ENTRY_GROUP_FAILURE: { + pa_log("Failed to register main service: %s", avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g)))); + avahi_entry_group_free(g); + u->main_entry_group = NULL; break; - } - - return; - -fail: - if (u->subscription) { - pa_subscription_free(u->subscription); - u->subscription = NULL; - } -} - -static int publish_main_service(struct userdata *u); - -static void main_entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) { - struct userdata *u = userdata; - assert(u); - - if (state == AVAHI_ENTRY_GROUP_COLLISION) { - char *t; - - t = avahi_alternative_service_name(u->service_name); - pa_xfree(u->service_name); - u->service_name = t; + } - publish_main_service(u); + case AVAHI_ENTRY_GROUP_UNCOMMITED: + case AVAHI_ENTRY_GROUP_REGISTERING: + break; } } @@ -456,6 +343,8 @@ static int publish_main_service(struct userdata *u) { AvahiStringList *txt = NULL; int r = -1; + pa_assert(u); + if (!u->main_entry_group) { if (!(u->main_entry_group = avahi_entry_group_new(u->client, main_entry_group_callback, u))) { pa_log("avahi_entry_group_new() failed: %s", avahi_strerror(avahi_client_errno(u->client))); @@ -464,7 +353,7 @@ static int publish_main_service(struct userdata *u) { } else avahi_entry_group_reset(u->main_entry_group); - txt = txt_record_server_data(u->core, NULL); + txt = txt_record_server_data(u->core, txt); if (avahi_entry_group_add_service_strlst( u->main_entry_group, @@ -497,26 +386,18 @@ fail: static int publish_all_services(struct userdata *u) { pa_sink *sink; pa_source *source; - pa_autoload_entry *autoload; int r = -1; uint32_t idx; - assert(u); + pa_assert(u); pa_log_debug("Publishing services in Zeroconf"); - for (sink = pa_idxset_first(u->core->sinks, &idx); sink; sink = pa_idxset_next(u->core->sinks, &idx)) - if (publish_sink(u, sink) < 0) - goto fail; - - for (source = pa_idxset_first(u->core->sources, &idx); source; source = pa_idxset_next(u->core->sources, &idx)) - if (publish_source(u, source) < 0) - goto fail; + for (sink = PA_SINK(pa_idxset_first(u->core->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(u->core->sinks, &idx))) + publish_service(get_service(u, PA_OBJECT(sink))); - if (u->core->autoload_idxset) - for (autoload = pa_idxset_first(u->core->autoload_idxset, &idx); autoload; autoload = pa_idxset_next(u->core->autoload_idxset, &idx)) - if (publish_autoload(u, autoload) < 0) - goto fail; + for (source = PA_SOURCE(pa_idxset_first(u->core->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(u->core->sources, &idx))) + publish_service(get_service(u, PA_OBJECT(source))); if (publish_main_service(u) < 0) goto fail; @@ -527,38 +408,44 @@ fail: return r; } -static void unpublish_all_services(struct userdata *u, int rem) { +static void unpublish_all_services(struct userdata *u, pa_bool_t rem) { void *state = NULL; struct service *s; - assert(u); + pa_assert(u); pa_log_debug("Unpublishing services in Zeroconf"); while ((s = pa_hashmap_iterate(u->services, &state, NULL))) { if (s->entry_group) { if (rem) { + pa_log_debug("Removing entry group for %s.", s->service_name); avahi_entry_group_free(s->entry_group); s->entry_group = NULL; - } else + } else { avahi_entry_group_reset(s->entry_group); + pa_log_debug("Resetting entry group for %s.", s->service_name); + } } - - s->published = UNPUBLISHED; } if (u->main_entry_group) { if (rem) { + pa_log_debug("Removing main entry group."); avahi_entry_group_free(u->main_entry_group); u->main_entry_group = NULL; - } else + } else { avahi_entry_group_reset(u->main_entry_group); + pa_log_debug("Resetting main entry group."); + } } } static void client_callback(AvahiClient *c, AvahiClientState state, void *userdata) { struct userdata *u = userdata; - assert(c); + + pa_assert(c); + pa_assert(u); u->client = c; @@ -568,13 +455,17 @@ static void client_callback(AvahiClient *c, AvahiClientState state, void *userda break; case AVAHI_CLIENT_S_COLLISION: - unpublish_all_services(u, 0); + pa_log_debug("Host name collision"); + unpublish_all_services(u, FALSE); break; case AVAHI_CLIENT_FAILURE: if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) { int error; - unpublish_all_services(u, 1); + + pa_log_debug("Avahi daemon disconnected."); + + unpublish_all_services(u, TRUE); avahi_client_free(u->client); if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error))) @@ -587,11 +478,12 @@ static void client_callback(AvahiClient *c, AvahiClientState state, void *userda } } -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { + struct userdata *u; uint32_t port = PA_NATIVE_DEFAULT_PORT; pa_modargs *ma = NULL; - char hn[256]; + char hn[256], un[256]; int error; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -599,30 +491,29 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port == 0 || port >= 0xFFFF) { + if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port <= 0 || port > 0xFFFF) { pa_log("invalid port specified."); goto fail; } m->userdata = u = pa_xnew(struct userdata, 1); - u->core = c; + u->core = m->core; u->port = (uint16_t) port; - u->avahi_poll = pa_avahi_poll_new(c->mainloop); + u->avahi_poll = pa_avahi_poll_new(m->core->mainloop); - u->services = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - u->sink_dynarray = pa_dynarray_new(); - u->source_dynarray = pa_dynarray_new(); - u->autoload_dynarray = pa_dynarray_new(); + u->services = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - u->subscription = pa_subscription_new(c, - PA_SUBSCRIPTION_MASK_SINK| - PA_SUBSCRIPTION_MASK_SOURCE| - PA_SUBSCRIPTION_MASK_AUTOLOAD, subscribe_callback, u); + u->sink_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_NEW_POST], (pa_hook_cb_t) device_new_or_changed_cb, u); + u->sink_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_DESCRIPTION_CHANGED], (pa_hook_cb_t) device_new_or_changed_cb, u); + u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], (pa_hook_cb_t) device_unlink_cb, u); + u->source_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_NEW_POST], (pa_hook_cb_t) device_new_or_changed_cb, u); + u->source_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_DESCRIPTION_CHANGED], (pa_hook_cb_t) device_new_or_changed_cb, u); + u->source_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], (pa_hook_cb_t) device_unlink_cb, u); u->main_entry_group = NULL; - u->service_name = pa_xstrdup(pa_get_host_name(hn, sizeof(hn))); + u->service_name = pa_truncate_utf8(pa_sprintf_malloc("%s@%s", pa_get_user_name(un, sizeof(un)), pa_get_host_name(hn, sizeof(hn))), AVAHI_LABEL_MAX); if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error))) { pa_log("pa_avahi_client_new() failed: %s", avahi_strerror(error)); @@ -634,7 +525,7 @@ int pa__init(pa_core *c, pa_module*m) { return 0; fail: - pa__done(c, m); + pa__done(m); if (ma) pa_modargs_free(ma); @@ -642,41 +533,34 @@ fail: return -1; } -static void service_free(void *p, void *userdata) { - struct service *s = p; - struct userdata *u = userdata; - - assert(s); - assert(u); - - if (s->entry_group) - avahi_entry_group_free(s->entry_group); - - pa_xfree(s->service_name); - pa_xfree(s->name); - pa_xfree(s); -} - -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata*u; - assert(c && m); + pa_assert(m); if (!(u = m->userdata)) return; - if (u->services) - pa_hashmap_free(u->services, service_free, u); + if (u->services) { + struct service *s; - if (u->subscription) - pa_subscription_free(u->subscription); + while ((s = pa_hashmap_get_first(u->services))) + service_free(s); - if (u->sink_dynarray) - pa_dynarray_free(u->sink_dynarray, NULL, NULL); - if (u->source_dynarray) - pa_dynarray_free(u->source_dynarray, NULL, NULL); - if (u->autoload_dynarray) - pa_dynarray_free(u->autoload_dynarray, NULL, NULL); + pa_hashmap_free(u->services, NULL, NULL); + } + if (u->sink_new_slot) + pa_hook_slot_free(u->sink_new_slot); + if (u->source_new_slot) + pa_hook_slot_free(u->source_new_slot); + if (u->sink_changed_slot) + pa_hook_slot_free(u->sink_changed_slot); + if (u->source_changed_slot) + pa_hook_slot_free(u->source_changed_slot); + if (u->sink_unlink_slot) + pa_hook_slot_free(u->sink_unlink_slot); + if (u->source_unlink_slot) + pa_hook_slot_free(u->source_unlink_slot); if (u->main_entry_group) avahi_entry_group_free(u->main_entry_group); @@ -690,4 +574,3 @@ void pa__done(pa_core *c, pa_module*m) { pa_xfree(u->service_name); pa_xfree(u); } - diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index fb531468..25e45a35 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -26,7 +26,6 @@ #include #endif -#include #include #include #include @@ -37,9 +36,11 @@ #include #include +#include #include #include #include +#include #include "oss-util.h" @@ -47,46 +48,43 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { int fd = -1; int caps; - assert(device && mode && (*mode == O_RDWR || *mode == O_RDONLY || *mode == O_WRONLY)); + pa_assert(device); + pa_assert(mode); + pa_assert(*mode == O_RDWR || *mode == O_RDONLY || *mode == O_WRONLY); if(!pcaps) pcaps = ∩︀ if (*mode == O_RDWR) { - if ((fd = open(device, O_RDWR|O_NDELAY)) >= 0) { - int dcaps, *tcaps; + if ((fd = open(device, O_RDWR|O_NDELAY|O_NOCTTY)) >= 0) { ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0); - tcaps = pcaps ? pcaps : &dcaps; - - if (ioctl(fd, SNDCTL_DSP_GETCAPS, tcaps) < 0) { + if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { pa_log("SNDCTL_DSP_GETCAPS: %s", pa_cstrerror(errno)); goto fail; } - if (*tcaps & DSP_CAP_DUPLEX) + if (*pcaps & DSP_CAP_DUPLEX) goto success; pa_log_warn("'%s' doesn't support full duplex", device); - close(fd); + pa_close(fd); } - if ((fd = open(device, (*mode = O_WRONLY)|O_NDELAY)) < 0) { - if ((fd = open(device, (*mode = O_RDONLY)|O_NDELAY)) < 0) { + if ((fd = open(device, (*mode = O_WRONLY)|O_NDELAY|O_NOCTTY)) < 0) { + if ((fd = open(device, (*mode = O_RDONLY)|O_NDELAY|O_NOCTTY)) < 0) { pa_log("open('%s'): %s", device, pa_cstrerror(errno)); goto fail; } } } else { - if ((fd = open(device, *mode|O_NDELAY)) < 0) { + if ((fd = open(device, *mode|O_NDELAY|O_NOCTTY)) < 0) { pa_log("open('%s'): %s", device, pa_cstrerror(errno)); goto fail; } } -success: - *pcaps = 0; if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { @@ -94,12 +92,14 @@ success: goto fail; } +success: + pa_log_debug("capabilities:%s%s%s%s%s%s%s%s%s%s%s%s%s%s", *pcaps & DSP_CAP_BATCH ? " BATCH" : "", #ifdef DSP_CAP_BIND *pcaps & DSP_CAP_BIND ? " BIND" : "", #else - "", + "", #endif *pcaps & DSP_CAP_COPROC ? " COPROC" : "", *pcaps & DSP_CAP_DUPLEX ? " DUPLEX" : "", @@ -122,7 +122,7 @@ success: #ifdef DSP_CAP_MULTI *pcaps & DSP_CAP_MULTI ? " MULTI" : "", #else - "", + "", #endif #ifdef DSP_CAP_OUTPUT *pcaps & DSP_CAP_OUTPUT ? " OUTPUT" : "", @@ -142,13 +142,13 @@ success: #endif *pcaps & DSP_CAP_TRIGGER ? " TRIGGER" : ""); - pa_fd_set_cloexec(fd, 1); + pa_make_fd_cloexec(fd); return fd; fail: if (fd >= 0) - close(fd); + pa_close(fd); return -1; } @@ -166,7 +166,8 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss) { [PA_SAMPLE_FLOAT32BE] = AFMT_QUERY, /* not supported */ }; - assert(fd >= 0 && ss); + pa_assert(fd >= 0); + pa_assert(ss); orig_format = ss->format; @@ -199,7 +200,7 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss) { pa_log("SNDCTL_DSP_CHANNELS: %s", pa_cstrerror(errno)); return -1; } - assert(channels > 0); + pa_assert(channels > 0); if (ss->channels != channels) { pa_log_warn("device doesn't support %i channels, using %i channels.", ss->channels, channels); @@ -211,7 +212,7 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss) { pa_log("SNDCTL_DSP_SPEED: %s", pa_cstrerror(errno)); return -1; } - assert(speed > 0); + pa_assert(speed > 0); if (ss->rate != (unsigned) speed) { pa_log_warn("device doesn't support %i Hz, changed to %i Hz.", ss->rate, speed); @@ -248,27 +249,29 @@ int pa_oss_set_fragments(int fd, int nfrags, int frag_size) { return 0; } -static int pa_oss_get_volume(int fd, int mixer, const pa_sample_spec *ss, pa_cvolume *volume) { +int pa_oss_get_volume(int fd, int mixer, const pa_sample_spec *ss, pa_cvolume *volume) { char cv[PA_CVOLUME_SNPRINT_MAX]; unsigned vol; - assert(fd >= 0); - assert(ss); - assert(volume); + pa_assert(fd >= 0); + pa_assert(ss); + pa_assert(volume); if (ioctl(fd, mixer, &vol) < 0) return -1; + pa_cvolume_reset(volume, ss->channels); + volume->values[0] = ((vol & 0xFF) * PA_VOLUME_NORM) / 100; - if ((volume->channels = ss->channels) >= 2) + if (volume->channels >= 2) volume->values[1] = (((vol >> 8) & 0xFF) * PA_VOLUME_NORM) / 100; pa_log_debug("Read mixer settings: %s", pa_cvolume_snprint(cv, sizeof(cv), volume)); return 0; } -static int pa_oss_set_volume(int fd, int mixer, const pa_sample_spec *ss, const pa_cvolume *volume) { +int pa_oss_set_volume(int fd, long mixer, const pa_sample_spec *ss, const pa_cvolume *volume) { char cv[PA_CVOLUME_SNPRINT_MAX]; unsigned vol; pa_volume_t l, r; @@ -289,40 +292,38 @@ static int pa_oss_set_volume(int fd, int mixer, const pa_sample_spec *ss, const return 0; } -int pa_oss_get_pcm_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume) { - return pa_oss_get_volume(fd, SOUND_MIXER_READ_PCM, ss, volume); -} +static int get_device_number(const char *dev) { + char buf[PATH_MAX]; + const char *p, *e; -int pa_oss_set_pcm_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume) { - return pa_oss_set_volume(fd, SOUND_MIXER_WRITE_PCM, ss, volume); -} + if (readlink(dev, buf, sizeof(buf)) < 0) { + if (errno != EINVAL && errno != ENOLINK) + return -1; -int pa_oss_get_input_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume) { - return pa_oss_get_volume(fd, SOUND_MIXER_READ_IGAIN, ss, volume); -} + p = dev; + } else + p = buf; + + if ((e = strrchr(p, '/'))) + p = e+1; -int pa_oss_set_input_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume) { - return pa_oss_set_volume(fd, SOUND_MIXER_WRITE_IGAIN, ss, volume); + if (p == 0) + return 0; + + p = strchr(p, 0) -1; + + if (*p >= '0' && *p <= '9') + return *p - '0'; + + return -1; } int pa_oss_get_hw_description(const char *dev, char *name, size_t l) { FILE *f; - const char *e = NULL; int n, r = -1; int b = 0; - if (strncmp(dev, "/dev/dsp", 8) == 0) - e = dev+8; - else if (strncmp(dev, "/dev/adsp", 9) == 0) - e = dev+9; - else - return -1; - - if (*e == 0) - n = 0; - else if (*e >= '0' && *e <= '9' && *(e+1) == 0) - n = *e - '0'; - else + if ((n = get_device_number(dev)) < 0) return -1; if (!(f = fopen("/dev/sndstat", "r")) && @@ -357,7 +358,7 @@ int pa_oss_get_hw_description(const char *dev, char *name, size_t l) { if (device == n) { char *k = strchr(line, ':'); - assert(k); + pa_assert(k); k++; k += strspn(k, " "); @@ -373,3 +374,34 @@ int pa_oss_get_hw_description(const char *dev, char *name, size_t l) { fclose(f); return r; } + +static int open_mixer(const char *mixer) { + int fd; + + if ((fd = open(mixer, O_RDWR|O_NDELAY|O_NOCTTY)) >= 0) + return fd; + + return -1; +} + +int pa_oss_open_mixer_for_device(const char *device) { + int n; + char *fn; + int fd; + + if ((n = get_device_number(device)) < 0) + return -1; + + if (n == 0) + if ((fd = open_mixer("/dev/mixer")) >= 0) + return fd; + + fn = pa_sprintf_malloc("/dev/mixer%i", n); + fd = open_mixer(fn); + pa_xfree(fn); + + if (fd < 0) + pa_log_warn("Failed to open mixer '%s': %s", device, pa_cstrerror(errno)); + + return fd; +} diff --git a/src/modules/oss-util.h b/src/modules/oss-util.h index 087e0d22..259a622a 100644 --- a/src/modules/oss-util.h +++ b/src/modules/oss-util.h @@ -33,12 +33,11 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss); int pa_oss_set_fragments(int fd, int frags, int frag_size); -int pa_oss_get_pcm_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume); -int pa_oss_set_pcm_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume); - -int pa_oss_get_input_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume); -int pa_oss_set_input_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume); +int pa_oss_set_volume(int fd, long mixer, const pa_sample_spec *ss, const pa_cvolume *volume); +int pa_oss_get_volume(int fd, int mixer, const pa_sample_spec *ss, pa_cvolume *volume); int pa_oss_get_hw_description(const char *dev, char *name, size_t l); +int pa_oss_open_mixer_for_device(const char *device); + #endif diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index 62ef561f..6c018931 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -24,7 +24,6 @@ #include #endif -#include #include #include #include @@ -32,6 +31,7 @@ #include #include #include +#include #include #include @@ -47,6 +47,10 @@ #include #include #include +#include +#include +#include +#include #include "module-rtp-recv-symdef.h" @@ -66,7 +70,7 @@ PA_MODULE_USAGE( #define DEFAULT_SAP_ADDRESS "224.0.0.56" #define MEMBLOCKQ_MAXLENGTH (1024*170) #define MAX_SESSIONS 16 -#define DEATH_TIMEOUT 20000000 +#define DEATH_TIMEOUT 20 static const char* const valid_modargs[] = { "sink", @@ -76,102 +80,126 @@ static const char* const valid_modargs[] = { struct session { struct userdata *userdata; + PA_LLIST_FIELDS(struct session); pa_sink_input *sink_input; pa_memblockq *memblockq; - pa_time_event *death_event; - - int first_packet; + pa_bool_t first_packet; uint32_t ssrc; uint32_t offset; struct pa_sdp_info sdp_info; pa_rtp_context rtp_context; - pa_io_event* rtp_event; + + pa_rtpoll_item *rtpoll_item; + + pa_atomic_t timestamp; }; struct userdata { pa_module *module; - pa_core *core; pa_sap_context sap_context; pa_io_event* sap_event; - pa_hashmap *by_origin; + pa_time_event *check_death_event; char *sink_name; + PA_LLIST_HEAD(struct session, sessions); + pa_hashmap *by_origin; int n_sessions; }; -static void session_free(struct session *s, int from_hash); +static void session_free(struct session *s); -static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { - struct session *s; - assert(i); - s = i->userdata; +/* Called from I/O thread context */ +static int sink_input_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct session *s = PA_SINK_INPUT(o)->userdata; - return pa_memblockq_peek(s->memblockq, chunk); + switch (code) { + case PA_SINK_INPUT_MESSAGE_GET_LATENCY: + *((pa_usec_t*) data) = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec); + + /* Fall through, the default handler will add in the extra + * latency added by the resampler */ + break; + } + + return pa_sink_input_process_msg(o, code, data, offset, chunk); } -static void sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { +/* Called from I/O thread context */ +static int sink_input_peek(pa_sink_input *i, size_t length, pa_memchunk *chunk) { struct session *s; - assert(i); - s = i->userdata; + pa_sink_input_assert_ref(i); + pa_assert_se(s = i->userdata); - pa_memblockq_drop(s->memblockq, chunk, length); + return pa_memblockq_peek(s->memblockq, chunk); } -static void sink_input_kill(pa_sink_input* i) { +/* Called from I/O thread context */ +static void sink_input_drop(pa_sink_input *i, size_t length) { struct session *s; - assert(i); - s = i->userdata; + pa_sink_input_assert_ref(i); + pa_assert_se(s = i->userdata); - session_free(s, 1); + pa_memblockq_drop(s->memblockq, length); } -static pa_usec_t sink_input_get_latency(pa_sink_input *i) { +/* Called from main context */ +static void sink_input_kill(pa_sink_input* i) { struct session *s; - assert(i); - s = i->userdata; + pa_sink_input_assert_ref(i); + pa_assert_se(s = i->userdata); - return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec); + session_free(s); } -static void rtp_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) { - struct session *s = userdata; +/* Called from I/O thread context */ +static int rtpoll_work_cb(pa_rtpoll_item *i) { pa_memchunk chunk; int64_t k, j, delta; - struct timeval tv; + struct timeval now; + struct session *s; + struct pollfd *p; - assert(m); - assert(e); - assert(s); - assert(fd == s->rtp_context.fd); - assert(flags == PA_IO_EVENT_INPUT); + pa_assert_se(s = pa_rtpoll_item_get_userdata(i)); - if (pa_rtp_recv(&s->rtp_context, &chunk, s->userdata->core->mempool) < 0) - return; + p = pa_rtpoll_item_get_pollfd(i, NULL); + + if (p->revents & (POLLERR|POLLNVAL|POLLHUP|POLLOUT)) { + pa_log("poll() signalled bad revents."); + return -1; + } + + if ((p->revents & POLLIN) == 0) + return 0; + + p->revents = 0; + + if (pa_rtp_recv(&s->rtp_context, &chunk, s->userdata->module->core->mempool) < 0) + return 0; if (s->sdp_info.payload != s->rtp_context.payload) { pa_memblock_unref(chunk.memblock); - return; + return 0; } if (!s->first_packet) { - s->first_packet = 1; + s->first_packet = TRUE; s->ssrc = s->rtp_context.ssrc; s->offset = s->rtp_context.timestamp; - if (s->ssrc == s->userdata->core->cookie) - pa_log_warn("WARNING! Detected RTP packet loop!"); + if (s->ssrc == s->userdata->module->core->cookie) + pa_log_warn("Detected RTP packet loop!"); } else { if (s->ssrc != s->rtp_context.ssrc) { pa_memblock_unref(chunk.memblock); - return; + return 0; } } @@ -197,26 +225,49 @@ static void rtp_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event pa_memblock_unref(chunk.memblock); - /* Reset death timer */ - pa_gettimeofday(&tv); - pa_timeval_add(&tv, DEATH_TIMEOUT); - m->time_restart(s->death_event, &tv); + pa_rtclock_get(&now); + pa_atomic_store(&s->timestamp, now.tv_sec); + + return 1; } -static void death_event_cb(pa_mainloop_api *m, pa_time_event *t, const struct timeval *tv, void *userdata) { - struct session *s = userdata; +/* Called from I/O thread context */ +static void sink_input_attach(pa_sink_input *i) { + struct session *s; + struct pollfd *p; + + pa_sink_input_assert_ref(i); + pa_assert_se(s = i->userdata); + + pa_assert(!s->rtpoll_item); + s->rtpoll_item = pa_rtpoll_item_new(i->sink->rtpoll, PA_RTPOLL_LATE, 1); + + p = pa_rtpoll_item_get_pollfd(s->rtpoll_item, NULL); + p->fd = s->rtp_context.fd; + p->events = POLLIN; + p->revents = 0; + + pa_rtpoll_item_set_work_callback(s->rtpoll_item, rtpoll_work_cb); + pa_rtpoll_item_set_userdata(s->rtpoll_item, s); +} - assert(m); - assert(t); - assert(tv); - assert(s); +/* Called from I/O thread context */ +static void sink_input_detach(pa_sink_input *i) { + struct session *s; + pa_sink_input_assert_ref(i); + pa_assert_se(s = i->userdata); - session_free(s, 1); + pa_assert(s->rtpoll_item); + pa_rtpoll_item_free(s->rtpoll_item); + s->rtpoll_item = NULL; } static int mcast_socket(const struct sockaddr* sa, socklen_t salen) { int af, fd = -1, r, one; + pa_assert(sa); + pa_assert(salen > 0); + af = sa->sa_family; if ((fd = socket(af, SOCK_DGRAM, 0)) < 0) { pa_log("Failed to create socket: %s", pa_cstrerror(errno)); @@ -262,27 +313,34 @@ fail: static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_info) { struct session *s = NULL; - struct timeval tv; char *c; pa_sink *sink; int fd = -1; pa_memblock *silence; pa_sink_input_new_data data; + struct timeval now; + + pa_assert(u); + pa_assert(sdp_info); if (u->n_sessions >= MAX_SESSIONS) { - pa_log("session limit reached."); + pa_log("Session limit reached."); goto fail; } - if (!(sink = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log("sink does not exist."); + if (!(sink = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) { + pa_log("Sink does not exist."); goto fail; } s = pa_xnew0(struct session, 1); s->userdata = u; - s->first_packet = 0; + s->first_packet = FALSE; s->sdp_info = *sdp_info; + s->rtpoll_item = NULL; + + pa_rtclock_get(&now); + pa_atomic_store(&s->timestamp, now.tv_sec); if ((fd = mcast_socket((const struct sockaddr*) &sdp_info->sa, sdp_info->salen)) < 0) goto fail; @@ -299,25 +357,27 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in data.module = u->module; pa_sink_input_new_data_set_sample_spec(&data, &sdp_info->sample_spec); - s->sink_input = pa_sink_input_new(u->core, &data, 0); + s->sink_input = pa_sink_input_new(u->module->core, &data, 0); pa_xfree(c); if (!s->sink_input) { - pa_log("failed to create sink input."); + pa_log("Failed to create sink input."); goto fail; } s->sink_input->userdata = s; + s->sink_input->parent.process_msg = sink_input_process_msg; s->sink_input->peek = sink_input_peek; s->sink_input->drop = sink_input_drop; s->sink_input->kill = sink_input_kill; - s->sink_input->get_latency = sink_input_get_latency; + s->sink_input->attach = sink_input_attach; + s->sink_input->detach = sink_input_detach; - silence = pa_silence_memblock_new(s->userdata->core->mempool, - &s->sink_input->sample_spec, - (pa_bytes_per_second(&s->sink_input->sample_spec)/128/pa_frame_size(&s->sink_input->sample_spec))* - pa_frame_size(&s->sink_input->sample_spec)); + silence = pa_silence_memblock_new( + s->userdata->module->core->mempool, + &s->sink_input->sample_spec, + pa_frame_align(pa_bytes_per_second(&s->sink_input->sample_spec)/128, &s->sink_input->sample_spec)); s->memblockq = pa_memblockq_new( 0, @@ -330,54 +390,44 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in pa_memblock_unref(silence); - s->rtp_event = u->core->mainloop->io_new(u->core->mainloop, fd, PA_IO_EVENT_INPUT, rtp_event_cb, s); - - pa_gettimeofday(&tv); - pa_timeval_add(&tv, DEATH_TIMEOUT); - s->death_event = u->core->mainloop->time_new(u->core->mainloop, &tv, death_event_cb, s); + pa_rtp_context_init_recv(&s->rtp_context, fd, pa_frame_size(&s->sdp_info.sample_spec)); pa_hashmap_put(s->userdata->by_origin, s->sdp_info.origin, s); + u->n_sessions++; + PA_LLIST_PREPEND(struct session, s->userdata->sessions, s); - pa_rtp_context_init_recv(&s->rtp_context, fd, pa_frame_size(&s->sdp_info.sample_spec)); - - pa_log_info("Found new session '%s'", s->sdp_info.session_name); + pa_sink_input_put(s->sink_input); - u->n_sessions++; + pa_log_info("New session '%s'", s->sdp_info.session_name); return s; fail: - if (s) { - if (fd >= 0) - close(fd); + pa_xfree(s); - pa_xfree(s); - } + if (fd >= 0) + pa_close(fd); return NULL; } -static void session_free(struct session *s, int from_hash) { - assert(s); +static void session_free(struct session *s) { + pa_assert(s); pa_log_info("Freeing session '%s'", s->sdp_info.session_name); - s->userdata->core->mainloop->time_free(s->death_event); - s->userdata->core->mainloop->io_free(s->rtp_event); - - if (from_hash) - pa_hashmap_remove(s->userdata->by_origin, s->sdp_info.origin); - - pa_sink_input_disconnect(s->sink_input); + pa_sink_input_unlink(s->sink_input); pa_sink_input_unref(s->sink_input); + PA_LLIST_REMOVE(struct session, s->userdata->sessions, s); + pa_assert(s->userdata->n_sessions >= 1); + s->userdata->n_sessions--; + pa_hashmap_remove(s->userdata->by_origin, s->sdp_info.origin); + pa_memblockq_free(s->memblockq); pa_sdp_info_destroy(&s->sdp_info); pa_rtp_context_destroy(&s->rtp_context); - assert(s->userdata->n_sessions >= 1); - s->userdata->n_sessions--; - pa_xfree(s); } @@ -387,11 +437,11 @@ static void sap_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event pa_sdp_info info; struct session *s; - assert(m); - assert(e); - assert(u); - assert(fd == u->sap_context.fd); - assert(flags == PA_IO_EVENT_INPUT); + pa_assert(m); + pa_assert(e); + pa_assert(u); + pa_assert(fd == u->sap_context.fd); + pa_assert(flags == PA_IO_EVENT_INPUT); if (pa_sap_recv(&u->sap_context, &goodbye) < 0) return; @@ -402,7 +452,7 @@ static void sap_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event if (goodbye) { if ((s = pa_hashmap_get(u->by_origin, info.origin))) - session_free(s, 1); + session_free(s); pa_sdp_info_destroy(&info); } else { @@ -412,18 +462,47 @@ static void sap_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event pa_sdp_info_destroy(&info); } else { - struct timeval tv; - - pa_gettimeofday(&tv); - pa_timeval_add(&tv, DEATH_TIMEOUT); - m->time_restart(s->death_event, &tv); + struct timeval now; + pa_rtclock_get(&now); + pa_atomic_store(&s->timestamp, now.tv_sec); pa_sdp_info_destroy(&info); } } } -int pa__init(pa_core *c, pa_module*m) { +static void check_death_event_cb(pa_mainloop_api *m, pa_time_event *t, const struct timeval *ptv, void *userdata) { + struct session *s, *n; + struct userdata *u = userdata; + struct timeval now; + struct timeval tv; + + pa_assert(m); + pa_assert(t); + pa_assert(ptv); + pa_assert(u); + + pa_rtclock_get(&now); + + pa_log_debug("Checking for dead streams ..."); + + for (s = u->sessions; s; s = n) { + int k; + n = s->next; + + k = pa_atomic_load(&s->timestamp); + + if (k + DEATH_TIMEOUT < now.tv_sec) + session_free(s); + } + + /* Restart timer */ + pa_gettimeofday(&tv); + pa_timeval_add(&tv, DEATH_TIMEOUT*PA_USEC_PER_SEC); + m->time_restart(t, &tv); +} + +int pa__init(pa_module*m) { struct userdata *u; pa_modargs *ma = NULL; struct sockaddr_in sa4; @@ -432,9 +511,9 @@ int pa__init(pa_core *c, pa_module*m) { socklen_t salen; const char *sap_address; int fd = -1; + struct timeval tv; - assert(c); - assert(m); + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("failed to parse module arguments"); @@ -454,7 +533,7 @@ int pa__init(pa_core *c, pa_module*m) { sa = (struct sockaddr*) &sa4; salen = sizeof(sa4); } else { - pa_log("invalid SAP address '%s'", sap_address); + pa_log("Invalid SAP address '%s'", sap_address); goto fail; } @@ -464,15 +543,18 @@ int pa__init(pa_core *c, pa_module*m) { u = pa_xnew(struct userdata, 1); m->userdata = u; u->module = m; - u->core = c; u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); - u->n_sessions = 0; - u->sap_event = c->mainloop->io_new(c->mainloop, fd, PA_IO_EVENT_INPUT, sap_event_cb, u); + u->sap_event = m->core->mainloop->io_new(m->core->mainloop, fd, PA_IO_EVENT_INPUT, sap_event_cb, u); + pa_sap_context_init_recv(&u->sap_context, fd); + PA_LLIST_HEAD_INIT(struct session, u->sessions); + u->n_sessions = 0; u->by_origin = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - pa_sap_context_init_recv(&u->sap_context, fd); + pa_gettimeofday(&tv); + pa_timeval_add(&tv, DEATH_TIMEOUT * PA_USEC_PER_SEC); + u->check_death_event = m->core->mainloop->time_new(m->core->mainloop, &tv, check_death_event_cb, u); pa_modargs_free(ma); @@ -483,27 +565,34 @@ fail: pa_modargs_free(ma); if (fd >= 0) - close(fd); + pa_close(fd); return -1; } -static void free_func(void *p, PA_GCC_UNUSED void *userdata) { - session_free(p, 0); -} - -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata *u; - assert(c); - assert(m); + struct session *s; + + pa_assert(m); if (!(u = m->userdata)) return; - c->mainloop->io_free(u->sap_event); + if (u->sap_event) + m->core->mainloop->io_free(u->sap_event); + + if (u->check_death_event) + m->core->mainloop->time_free(u->check_death_event); + pa_sap_context_destroy(&u->sap_context); - pa_hashmap_free(u->by_origin, free_func, NULL); + if (u->by_origin) { + while ((s = pa_hashmap_get_first(u->by_origin))) + session_free(s); + + pa_hashmap_free(u->by_origin, NULL, NULL); + } pa_xfree(u->sink_name); pa_xfree(u); diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 8c9e5f23..f36989bd 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -25,7 +25,6 @@ #include #endif -#include #include #include #include @@ -48,6 +47,9 @@ #include #include #include +#include +#include +#include #include "module-rtp-send-symdef.h" @@ -74,7 +76,7 @@ PA_MODULE_USAGE( #define DEFAULT_DESTINATION "224.0.0.56" #define MEMBLOCKQ_MAXLENGTH (1024*170) #define DEFAULT_MTU 1280 -#define SAP_INTERVAL 5000000 +#define SAP_INTERVAL 5 static const char* const valid_modargs[] = { "source", @@ -90,7 +92,6 @@ static const char* const valid_modargs[] = { struct userdata { pa_module *module; - pa_core *core; pa_source_output *source_output; pa_memblockq *memblockq; @@ -102,56 +103,67 @@ struct userdata { pa_time_event *sap_event; }; +/* Called from I/O thread context */ +static int source_output_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u; + pa_assert_se(u = PA_SOURCE_OUTPUT(o)->userdata); + + switch (code) { + case PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY: + *((pa_usec_t*) data) = pa_bytes_to_usec(pa_memblockq_get_length(u->memblockq), &u->source_output->sample_spec); + + /* Fall through, the default handler will add in the extra + * latency added by the resampler */ + break; + } + + return pa_source_output_process_msg(o, code, data, offset, chunk); +} + +/* Called from I/O thread context */ static void source_output_push(pa_source_output *o, const pa_memchunk *chunk) { struct userdata *u; - assert(o); - u = o->userdata; + pa_source_output_assert_ref(o); + pa_assert_se(u = o->userdata); if (pa_memblockq_push(u->memblockq, chunk) < 0) { - pa_log("Failed to push chunk into memblockq."); + pa_log_warn("Failed to push chunk into memblockq."); return; } pa_rtp_send(&u->rtp_context, u->mtu, u->memblockq); } +/* Called from main context */ static void source_output_kill(pa_source_output* o) { struct userdata *u; - assert(o); - u = o->userdata; + pa_source_output_assert_ref(o); + pa_assert_se(u = o->userdata); pa_module_unload_request(u->module); - pa_source_output_disconnect(u->source_output); + pa_source_output_unlink(u->source_output); pa_source_output_unref(u->source_output); u->source_output = NULL; } -static pa_usec_t source_output_get_latency (pa_source_output *o) { - struct userdata *u; - assert(o); - u = o->userdata; - - return pa_bytes_to_usec(pa_memblockq_get_length(u->memblockq), &o->sample_spec); -} - static void sap_event_cb(pa_mainloop_api *m, pa_time_event *t, const struct timeval *tv, void *userdata) { struct userdata *u = userdata; struct timeval next; - assert(m); - assert(t); - assert(tv); - assert(u); + pa_assert(m); + pa_assert(t); + pa_assert(tv); + pa_assert(u); pa_sap_send(&u->sap_context, 0); pa_gettimeofday(&next); - pa_timeval_add(&next, SAP_INTERVAL); + pa_timeval_add(&next, SAP_INTERVAL * PA_USEC_PER_SEC); m->time_restart(t, &next); } -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { struct userdata *u; pa_modargs *ma = NULL; const char *dest; @@ -173,21 +185,20 @@ int pa__init(pa_core *c, pa_module*m) { int loop = 0; pa_source_output_new_data data; - assert(c); - assert(m); + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log("failed to parse module arguments"); + pa_log("Failed to parse module arguments"); goto fail; } if (!(s = pa_namereg_get(m->core, pa_modargs_get_value(ma, "source", NULL), PA_NAMEREG_SOURCE, 1))) { - pa_log("source does not exist."); + pa_log("Source does not exist."); goto fail; } if (pa_modargs_get_value_boolean(ma, "loop", &loop) < 0) { - pa_log("failed to parse \"loop\" parameter."); + pa_log("Failed to parse \"loop\" parameter."); goto fail; } @@ -195,12 +206,12 @@ int pa__init(pa_core *c, pa_module*m) { pa_rtp_sample_spec_fixup(&ss); cm = s->channel_map; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log("failed to parse sample specification"); + pa_log("Failed to parse sample specification"); goto fail; } if (!pa_rtp_sample_spec_valid(&ss)) { - pa_log("specified sample type not compatible with RTP"); + pa_log("Specified sample type not compatible with RTP"); goto fail; } @@ -209,10 +220,10 @@ int pa__init(pa_core *c, pa_module*m) { payload = pa_rtp_payload_from_sample_spec(&ss); - mtu = (DEFAULT_MTU/pa_frame_size(&ss))*pa_frame_size(&ss); + mtu = pa_frame_align(DEFAULT_MTU, &ss); if (pa_modargs_get_value_u32(ma, "mtu", &mtu) < 0 || mtu < 1 || mtu % pa_frame_size(&ss) != 0) { - pa_log("invalid mtu."); + pa_log("Invalid MTU."); goto fail; } @@ -223,7 +234,7 @@ int pa__init(pa_core *c, pa_module*m) { } if (port & 1) - pa_log_warn("WARNING: port number not even as suggested in RFC3550!"); + pa_log_warn("Port number not even as suggested in RFC3550!"); dest = pa_modargs_get_value(ma, "destination", DEFAULT_DESTINATION); @@ -238,7 +249,7 @@ int pa__init(pa_core *c, pa_module*m) { sap_sa4 = sa4; sap_sa4.sin_port = htons(SAP_PORT); } else { - pa_log("invalid destination '%s'", dest); + pa_log("Invalid destination '%s'", dest); goto fail; } @@ -268,6 +279,12 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } + /* If the socket queue is full, let's drop packets */ + pa_make_fd_nonblock(fd); + pa_make_udp_socket_low_delay(fd); + pa_make_fd_cloexec(fd); + pa_make_fd_cloexec(sap_fd); + pa_source_output_new_data_init(&data); data.name = "RTP Monitor Stream"; data.driver = __FILE__; @@ -276,21 +293,20 @@ int pa__init(pa_core *c, pa_module*m) { pa_source_output_new_data_set_sample_spec(&data, &ss); pa_source_output_new_data_set_channel_map(&data, &cm); - if (!(o = pa_source_output_new(c, &data, 0))) { + if (!(o = pa_source_output_new(m->core, &data, 0))) { pa_log("failed to create source output."); goto fail; } + o->parent.process_msg = source_output_process_msg; o->push = source_output_push; o->kill = source_output_kill; - o->get_latency = source_output_get_latency; u = pa_xnew(struct userdata, 1); m->userdata = u; o->userdata = u; u->module = m; - u->core = c; u->source_output = o; u->memblockq = pa_memblockq_new( @@ -305,8 +321,7 @@ int pa__init(pa_core *c, pa_module*m) { u->mtu = mtu; k = sizeof(sa_dst); - r = getsockname(fd, (struct sockaddr*) &sa_dst, &k); - assert(r >= 0); + pa_assert_se((r = getsockname(fd, (struct sockaddr*) &sa_dst, &k)) >= 0); n = pa_sprintf_malloc("PulseAudio RTP Stream on %s", pa_get_fqdn(hn, sizeof(hn))); @@ -317,17 +332,19 @@ int pa__init(pa_core *c, pa_module*m) { pa_xfree(n); - pa_rtp_context_init_send(&u->rtp_context, fd, c->cookie, payload, pa_frame_size(&ss)); + pa_rtp_context_init_send(&u->rtp_context, fd, m->core->cookie, payload, pa_frame_size(&ss)); pa_sap_context_init_send(&u->sap_context, sap_fd, p); pa_log_info("RTP stream initialized with mtu %u on %s:%u, SSRC=0x%08x, payload=%u, initial sequence #%u", mtu, dest, port, u->rtp_context.ssrc, payload, u->rtp_context.sequence); - pa_log_info("SDP-Data:\n%s\n"__FILE__": EOF", p); + pa_log_info("SDP-Data:\n%s\nEOF", p); pa_sap_send(&u->sap_context, 0); pa_gettimeofday(&tv); - pa_timeval_add(&tv, SAP_INTERVAL); - u->sap_event = c->mainloop->time_new(c->mainloop, &tv, sap_event_cb, u); + pa_timeval_add(&tv, SAP_INTERVAL * PA_USEC_PER_SEC); + u->sap_event = m->core->mainloop->time_new(m->core->mainloop, &tv, sap_event_cb, u); + + pa_source_output_put(u->source_output); pa_modargs_free(ma); @@ -338,31 +355,31 @@ fail: pa_modargs_free(ma); if (fd >= 0) - close(fd); + pa_close(fd); if (sap_fd >= 0) - close(sap_fd); + pa_close(sap_fd); if (o) { - pa_source_output_disconnect(o); + pa_source_output_unlink(o); pa_source_output_unref(o); } return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata *u; - assert(c); - assert(m); + pa_assert(m); if (!(u = m->userdata)) return; - c->mainloop->time_free(u->sap_event); + if (u->sap_event) + m->core->mainloop->time_free(u->sap_event); if (u->source_output) { - pa_source_output_disconnect(u->source_output); + pa_source_output_unlink(u->source_output); pa_source_output_unref(u->source_output); } @@ -371,7 +388,8 @@ void pa__done(pa_core *c, pa_module*m) { pa_sap_send(&u->sap_context, 1); pa_sap_context_destroy(&u->sap_context); - pa_memblockq_free(u->memblockq); + if (u->memblockq) + pa_memblockq_free(u->memblockq); pa_xfree(u); } diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c index 03a01412..997fcc34 100644 --- a/src/modules/rtp/rtp.c +++ b/src/modules/rtp/rtp.c @@ -25,7 +25,6 @@ #include #endif -#include #include #include #include @@ -40,12 +39,14 @@ #include #include +#include +#include #include "rtp.h" pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssrc, uint8_t payload, size_t frame_size) { - assert(c); - assert(fd >= 0); + pa_assert(c); + pa_assert(fd >= 0); c->fd = fd; c->sequence = (uint16_t) (rand()*rand()); @@ -63,11 +64,11 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { struct iovec iov[MAX_IOVECS]; pa_memblock* mb[MAX_IOVECS]; int iov_idx = 1; - size_t n = 0, skip = 0; + size_t n = 0; - assert(c); - assert(size > 0); - assert(q); + pa_assert(c); + pa_assert(size > 0); + pa_assert(q); if (pa_memblockq_get_length(q) < size) return 0; @@ -76,24 +77,26 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { int r; pa_memchunk chunk; + pa_memchunk_reset(&chunk); + if ((r = pa_memblockq_peek(q, &chunk)) >= 0) { size_t k = n + chunk.length > size ? size - n : chunk.length; - if (chunk.memblock) { - iov[iov_idx].iov_base = (void*)((uint8_t*) chunk.memblock->data + chunk.index); - iov[iov_idx].iov_len = k; - mb[iov_idx] = chunk.memblock; - iov_idx ++; + pa_assert(chunk.memblock); - n += k; - } + iov[iov_idx].iov_base = ((uint8_t*) pa_memblock_acquire(chunk.memblock) + chunk.index); + iov[iov_idx].iov_len = k; + mb[iov_idx] = chunk.memblock; + iov_idx ++; - skip += k; - pa_memblockq_drop(q, &chunk, k); + n += k; + pa_memblockq_drop(q, k); } - if (r < 0 || !chunk.memblock || n >= size || iov_idx >= MAX_IOVECS) { + pa_assert(n % c->frame_size == 0); + + if (r < 0 || n >= size || iov_idx >= MAX_IOVECS) { uint32_t header[3]; struct msghdr m; int k, i; @@ -116,17 +119,19 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { k = sendmsg(c->fd, &m, MSG_DONTWAIT); - for (i = 1; i < iov_idx; i++) + for (i = 1; i < iov_idx; i++) { + pa_memblock_release(mb[i]); pa_memblock_unref(mb[i]); + } c->sequence++; } else k = 0; - c->timestamp += skip/c->frame_size; + c->timestamp += n/c->frame_size; if (k < 0) { - if (errno != EAGAIN) /* If the queue is full, just ignore it */ + if (errno != EAGAIN && errno != EINTR) /* If the queue is full, just ignore it */ pa_log("sendmsg() failed: %s", pa_cstrerror(errno)); return -1; } @@ -135,7 +140,6 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { break; n = 0; - skip = 0; iov_idx = 1; } } @@ -144,7 +148,7 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) { } pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd, size_t frame_size) { - assert(c); + pa_assert(c); c->fd = fd; c->frame_size = frame_size; @@ -159,13 +163,13 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { int cc; ssize_t r; - assert(c); - assert(chunk); + pa_assert(c); + pa_assert(chunk); - chunk->memblock = NULL; + pa_memchunk_reset(chunk); if (ioctl(c->fd, FIONREAD, &size) < 0) { - pa_log("FIONREAD failed: %s", pa_cstrerror(errno)); + pa_log_warn("FIONREAD failed: %s", pa_cstrerror(errno)); goto fail; } @@ -174,7 +178,7 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { chunk->memblock = pa_memblock_new(pool, size); - iov.iov_base = chunk->memblock->data; + iov.iov_base = pa_memblock_acquire(chunk->memblock); iov.iov_len = size; m.msg_name = NULL; @@ -185,36 +189,41 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { m.msg_controllen = 0; m.msg_flags = 0; - if ((r = recvmsg(c->fd, &m, 0)) != size) { - pa_log("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch"); + r = recvmsg(c->fd, &m, 0); + pa_memblock_release(chunk->memblock); + + if (r != size) { + if (r < 0 && errno != EAGAIN && errno != EINTR) + pa_log_warn("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch"); + goto fail; } if (size < 12) { - pa_log("RTP packet too short."); + pa_log_warn("RTP packet too short."); goto fail; } - memcpy(&header, chunk->memblock->data, sizeof(uint32_t)); - memcpy(&c->timestamp, (uint8_t*) chunk->memblock->data + 4, sizeof(uint32_t)); - memcpy(&c->ssrc, (uint8_t*) chunk->memblock->data + 8, sizeof(uint32_t)); + memcpy(&header, iov.iov_base, sizeof(uint32_t)); + memcpy(&c->timestamp, (uint8_t*) iov.iov_base + 4, sizeof(uint32_t)); + memcpy(&c->ssrc, (uint8_t*) iov.iov_base + 8, sizeof(uint32_t)); header = ntohl(header); c->timestamp = ntohl(c->timestamp); c->ssrc = ntohl(c->ssrc); if ((header >> 30) != 2) { - pa_log("Unsupported RTP version."); + pa_log_warn("Unsupported RTP version."); goto fail; } if ((header >> 29) & 1) { - pa_log("RTP padding not supported."); + pa_log_warn("RTP padding not supported."); goto fail; } if ((header >> 28) & 1) { - pa_log("RTP header extensions not supported."); + pa_log_warn("RTP header extensions not supported."); goto fail; } @@ -223,7 +232,7 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { c->sequence = header & 0xFFFF; if (12 + cc*4 > size) { - pa_log("RTP packet too short. (CSRC)"); + pa_log_warn("RTP packet too short. (CSRC)"); goto fail; } @@ -231,7 +240,7 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) { chunk->length = size - chunk->index; if (chunk->length % c->frame_size != 0) { - pa_log("Vad RTP packet size."); + pa_log_warn("Bad RTP packet size."); goto fail; } @@ -245,7 +254,7 @@ fail: } uint8_t pa_rtp_payload_from_sample_spec(const pa_sample_spec *ss) { - assert(ss); + pa_assert(ss); if (ss->format == PA_SAMPLE_ULAW && ss->rate == 8000 && ss->channels == 1) return 0; @@ -260,7 +269,7 @@ uint8_t pa_rtp_payload_from_sample_spec(const pa_sample_spec *ss) { } pa_sample_spec *pa_rtp_sample_spec_from_payload(uint8_t payload, pa_sample_spec *ss) { - assert(ss); + pa_assert(ss); switch (payload) { case 0: @@ -295,17 +304,17 @@ pa_sample_spec *pa_rtp_sample_spec_from_payload(uint8_t payload, pa_sample_spec } pa_sample_spec *pa_rtp_sample_spec_fixup(pa_sample_spec * ss) { - assert(ss); + pa_assert(ss); if (!pa_rtp_sample_spec_valid(ss)) ss->format = PA_SAMPLE_S16BE; - assert(pa_rtp_sample_spec_valid(ss)); + pa_assert(pa_rtp_sample_spec_valid(ss)); return ss; } int pa_rtp_sample_spec_valid(const pa_sample_spec *ss) { - assert(ss); + pa_assert(ss); if (!pa_sample_spec_valid(ss)) return 0; @@ -318,9 +327,9 @@ int pa_rtp_sample_spec_valid(const pa_sample_spec *ss) { } void pa_rtp_context_destroy(pa_rtp_context *c) { - assert(c); + pa_assert(c); - close(c->fd); + pa_close(c->fd); } const char* pa_rtp_format_to_string(pa_sample_format_t f) { @@ -339,7 +348,7 @@ const char* pa_rtp_format_to_string(pa_sample_format_t f) { } pa_sample_format_t pa_rtp_string_to_format(const char *s) { - assert(s); + pa_assert(s); if (!(strcmp(s, "L16"))) return PA_SAMPLE_S16BE; diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c index 82421807..ed7eb0be 100644 --- a/src/modules/rtp/sap.c +++ b/src/modules/rtp/sap.c @@ -25,7 +25,6 @@ #include #endif -#include #include #include #include @@ -46,6 +45,7 @@ #include #include #include +#include #include "sap.h" #include "sdp.h" @@ -53,9 +53,9 @@ #define MIME_TYPE "application/sdp" pa_sap_context* pa_sap_context_init_send(pa_sap_context *c, int fd, char *sdp_data) { - assert(c); - assert(fd >= 0); - assert(sdp_data); + pa_assert(c); + pa_assert(fd >= 0); + pa_assert(sdp_data); c->fd = fd; c->sdp_data = sdp_data; @@ -65,9 +65,9 @@ pa_sap_context* pa_sap_context_init_send(pa_sap_context *c, int fd, char *sdp_da } void pa_sap_context_destroy(pa_sap_context *c) { - assert(c); + pa_assert(c); - close(c->fd); + pa_close(c->fd); pa_xfree(c->sdp_data); } @@ -85,7 +85,7 @@ int pa_sap_send(pa_sap_context *c, int goodbye) { return -1; } - assert(sa->sa_family == AF_INET || sa->sa_family == AF_INET6); + pa_assert(sa->sa_family == AF_INET || sa->sa_family == AF_INET6); header = htonl(((uint32_t) 1 << 29) | (sa->sa_family == AF_INET6 ? (uint32_t) 1 << 28 : 0) | @@ -113,14 +113,14 @@ int pa_sap_send(pa_sap_context *c, int goodbye) { m.msg_flags = 0; if ((k = sendmsg(c->fd, &m, MSG_DONTWAIT)) < 0) - pa_log("sendmsg() failed: %s\n", pa_cstrerror(errno)); + pa_log_warn("sendmsg() failed: %s\n", pa_cstrerror(errno)); return k; } pa_sap_context* pa_sap_context_init_recv(pa_sap_context *c, int fd) { - assert(c); - assert(fd >= 0); + pa_assert(c); + pa_assert(fd >= 0); c->fd = fd; c->sdp_data = NULL; @@ -136,11 +136,11 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) { int six, ac; ssize_t r; - assert(c); - assert(goodbye); + pa_assert(c); + pa_assert(goodbye); if (ioctl(c->fd, FIONREAD, &size) < 0) { - pa_log("FIONREAD failed: %s", pa_cstrerror(errno)); + pa_log_warn("FIONREAD failed: %s", pa_cstrerror(errno)); goto fail; } @@ -159,12 +159,12 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) { m.msg_flags = 0; if ((r = recvmsg(c->fd, &m, 0)) != size) { - pa_log("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch"); + pa_log_warn("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch"); goto fail; } if (size < 4) { - pa_log("SAP packet too short."); + pa_log_warn("SAP packet too short."); goto fail; } @@ -172,17 +172,17 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) { header = ntohl(header); if (header >> 29 != 1) { - pa_log("Unsupported SAP version."); + pa_log_warn("Unsupported SAP version."); goto fail; } if ((header >> 25) & 1) { - pa_log("Encrypted SAP not supported."); + pa_log_warn("Encrypted SAP not supported."); goto fail; } if ((header >> 24) & 1) { - pa_log("Compressed SAP not supported."); + pa_log_warn("Compressed SAP not supported."); goto fail; } @@ -191,7 +191,7 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) { k = 4 + (six ? 16 : 4) + ac*4; if (size < k) { - pa_log("SAP packet too short (AD)."); + pa_log_warn("SAP packet too short (AD)."); goto fail; } @@ -202,7 +202,7 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) { e += sizeof(MIME_TYPE); size -= sizeof(MIME_TYPE); } else if ((unsigned) size < sizeof(PA_SDP_HEADER)-1 || strncmp(e, PA_SDP_HEADER, sizeof(PA_SDP_HEADER)-1)) { - pa_log("Invalid SDP header."); + pa_log_warn("Invalid SDP header."); goto fail; } diff --git a/src/modules/rtp/sdp.c b/src/modules/rtp/sdp.c index 8b0bd535..50ac157a 100644 --- a/src/modules/rtp/sdp.c +++ b/src/modules/rtp/sdp.c @@ -25,7 +25,6 @@ #include #endif -#include #include #include #include @@ -35,36 +34,33 @@ #include #include +#include #include #include +#include #include "sdp.h" #include "rtp.h" - char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, uint16_t port, uint8_t payload, const pa_sample_spec *ss) { uint32_t ntp; - char buf_src[64], buf_dst[64]; + char buf_src[64], buf_dst[64], un[64]; const char *u, *f, *a; - assert(src); - assert(dst); - assert(af == AF_INET || af == AF_INET6); + pa_assert(src); + pa_assert(dst); + pa_assert(af == AF_INET || af == AF_INET6); - f = pa_rtp_format_to_string(ss->format); - assert(f); + pa_assert_se(f = pa_rtp_format_to_string(ss->format)); - if (!(u = getenv("USER"))) - if (!(u = getenv("USERNAME"))) - u = "-"; + if (!(u = pa_get_user_name(un, sizeof(un)))) + u = "-"; ntp = time(NULL) + 2208988800U; - a = inet_ntop(af, src, buf_src, sizeof(buf_src)); - assert(a); - a = inet_ntop(af, dst, buf_dst, sizeof(buf_dst)); - assert(a); + pa_assert_se(a = inet_ntop(af, src, buf_src, sizeof(buf_src))); + pa_assert_se(a = inet_ntop(af, dst, buf_dst, sizeof(buf_dst))); return pa_sprintf_malloc( PA_SDP_HEADER @@ -86,8 +82,8 @@ char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, u static pa_sample_spec *parse_sdp_sample_spec(pa_sample_spec *ss, char *c) { unsigned rate, channels; - assert(ss); - assert(c); + pa_assert(ss); + pa_assert(c); if (pa_startswith(c, "L16/")) { ss->format = PA_SAMPLE_S16BE; @@ -123,8 +119,8 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { uint16_t port = 0; int ss_valid = 0; - assert(t); - assert(i); + pa_assert(t); + pa_assert(i); i->origin = i->session_name = NULL; i->salen = 0; @@ -258,7 +254,7 @@ fail: } void pa_sdp_info_destroy(pa_sdp_info *i) { - assert(i); + pa_assert(i); pa_xfree(i->origin); pa_xfree(i->session_name); diff --git a/src/pulse/browser.c b/src/pulse/browser.c index ea2706e4..55e0b2cd 100644 --- a/src/pulse/browser.c +++ b/src/pulse/browser.c @@ -25,7 +25,6 @@ #include "config.h" #endif -#include #include #include @@ -36,8 +35,9 @@ #include #include - #include +#include +#include #include "browser.h" @@ -46,7 +46,8 @@ #define SERVICE_TYPE_SERVER "_pulse-server._tcp." struct pa_browser { - int ref; + PA_REFCNT_DECLARE; + pa_mainloop_api *mainloop; AvahiPoll* avahi_poll; @@ -62,6 +63,7 @@ struct pa_browser { }; static int map_to_opcode(const char *type, int new) { + if (avahi_domain_equal(type, SERVICE_TYPE_SINK)) return new ? PA_BROWSE_NEW_SINK : PA_BROWSE_REMOVE_SINK; else if (avahi_domain_equal(type, SERVICE_TYPE_SOURCE)) @@ -97,7 +99,8 @@ static void resolve_callback( int ss_valid = 0; char *key = NULL, *value = NULL; - assert(b); + pa_assert(b); + pa_assert(PA_REFCNT_VALUE(b) >= 1); memset(&i, 0, sizeof(i)); i.name = name; @@ -109,13 +112,13 @@ static void resolve_callback( goto fail; opcode = map_to_opcode(type, 1); - assert(opcode >= 0); + pa_assert(opcode >= 0); if (aa->proto == AVAHI_PROTO_INET) - snprintf(a, sizeof(a), "tcp:%s:%u", avahi_address_snprint(ip, sizeof(ip), aa), port); + pa_snprintf(a, sizeof(a), "tcp:%s:%u", avahi_address_snprint(ip, sizeof(ip), aa), port); else { - assert(aa->proto == AVAHI_PROTO_INET6); - snprintf(a, sizeof(a), "tcp6:%s:%u", avahi_address_snprint(ip, sizeof(ip), aa), port); + pa_assert(aa->proto == AVAHI_PROTO_INET6); + pa_snprintf(a, sizeof(a), "tcp6:%s:%u", avahi_address_snprint(ip, sizeof(ip), aa), port); } i.server = a; @@ -146,7 +149,7 @@ static void resolve_callback( value = NULL; l = strlen(a); - assert(l+1 <= sizeof(a)); + pa_assert(l+1 <= sizeof(a)); strncat(a, " ", sizeof(a)-l-1); strncat(a, i.fqdn, sizeof(a)-l-2); } else if (!strcmp(key, "cookie")) { @@ -211,7 +214,9 @@ fail: static void handle_failure(pa_browser *b) { const char *e = NULL; - assert(b); + + pa_assert(b); + pa_assert(PA_REFCNT_VALUE(b) >= 1); if (b->sink_browser) avahi_service_browser_free(b->sink_browser); @@ -245,7 +250,9 @@ static void browse_callback( void *userdata) { pa_browser *b = userdata; - assert(b); + + pa_assert(b); + pa_assert(PA_REFCNT_VALUE(b) >= 1); switch (event) { case AVAHI_BROWSER_NEW: { @@ -276,7 +283,7 @@ static void browse_callback( i.name = name; opcode = map_to_opcode(type, 0); - assert(opcode >= 0); + pa_assert(opcode >= 0); b->callback(b, opcode, &i, b->userdata); } @@ -295,7 +302,10 @@ static void browse_callback( static void client_callback(AvahiClient *s, AvahiClientState state, void *userdata) { pa_browser *b = userdata; - assert(s); + + pa_assert(s); + pa_assert(b); + pa_assert(PA_REFCNT_VALUE(b) >= 1); if (state == AVAHI_CLIENT_FAILURE) handle_failure(b); @@ -311,14 +321,14 @@ pa_browser *pa_browser_new_full(pa_mainloop_api *mainloop, pa_browse_flags_t fla pa_browser *b; int error; - assert(mainloop); + pa_assert(mainloop); if (flags & ~(PA_BROWSE_FOR_SERVERS|PA_BROWSE_FOR_SINKS|PA_BROWSE_FOR_SOURCES) || flags == 0) return NULL; b = pa_xnew(pa_browser, 1); b->mainloop = mainloop; - b->ref = 1; + PA_REFCNT_INIT(b); b->callback = NULL; b->userdata = NULL; b->error_callback = NULL; @@ -391,7 +401,8 @@ fail: } static void browser_free(pa_browser *b) { - assert(b && b->mainloop); + pa_assert(b); + pa_assert(b->mainloop); if (b->sink_browser) avahi_service_browser_free(b->sink_browser); @@ -410,29 +421,32 @@ static void browser_free(pa_browser *b) { } pa_browser *pa_browser_ref(pa_browser *b) { - assert(b); - assert(b->ref >= 1); - b->ref++; + pa_assert(b); + pa_assert(PA_REFCNT_VALUE(b) >= 1); + + PA_REFCNT_INC(b); return b; } void pa_browser_unref(pa_browser *b) { - assert(b); - assert(b->ref >= 1); + pa_assert(b); + pa_assert(PA_REFCNT_VALUE(b) >= 1); - if ((-- (b->ref)) <= 0) + if (PA_REFCNT_DEC(b) <= 0) browser_free(b); } void pa_browser_set_callback(pa_browser *b, pa_browse_cb_t cb, void *userdata) { - assert(b); + pa_assert(b); + pa_assert(PA_REFCNT_VALUE(b) >= 1); b->callback = cb; b->userdata = userdata; } void pa_browser_set_error_callback(pa_browser *b, pa_browser_error_cb_t cb, void *userdata) { - assert(b); + pa_assert(b); + pa_assert(PA_REFCNT_VALUE(b) >= 1); b->error_callback = cb; b->error_userdata = userdata; diff --git a/src/pulse/cdecl.h b/src/pulse/cdecl.h index 922ad276..e1f23d25 100644 --- a/src/pulse/cdecl.h +++ b/src/pulse/cdecl.h @@ -41,4 +41,22 @@ #endif +#ifndef PA_GCC_PURE +#ifdef __GNUCC__ +#define PA_GCC_PURE __attribute__ ((pure)) +#else +/** This function's return value depends only the arguments list and global state **/ +#define PA_GCC_PURE +#endif +#endif + +#ifndef PA_GCC_CONST +#ifdef __GNUCC__ +#define PA_GCC_CONST __attribute__ ((pure)) +#else +/** This function's return value depends only the arguments list (stricter version of PA_GCC_CONST) **/ +#define PA_GCC_CONST +#endif +#endif + #endif diff --git a/src/pulse/channelmap.c b/src/pulse/channelmap.c index d5b8f743..2b8ef2b0 100644 --- a/src/pulse/channelmap.c +++ b/src/pulse/channelmap.c @@ -27,12 +27,12 @@ #endif #include -#include #include #include #include #include +#include #include "channelmap.h" @@ -90,18 +90,81 @@ const char *const table[] = { [PA_CHANNEL_POSITION_TOP_CENTER] = "top-center", + [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = "top-front-center", [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = "top-front-left", [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = "top-front-right", - [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = "top-front-center", + [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = "top-rear-center", [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = "top-rear-left", - [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = "top-rear-right", - [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = "top-rear-center" + [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = "top-rear-right" +}; + +const char *const pretty_table[] = { + [PA_CHANNEL_POSITION_MONO] = "Mono", + + [PA_CHANNEL_POSITION_FRONT_CENTER] = "Front Center", + [PA_CHANNEL_POSITION_FRONT_LEFT] = "Front Left", + [PA_CHANNEL_POSITION_FRONT_RIGHT] = "Front Right", + + [PA_CHANNEL_POSITION_REAR_CENTER] = "Rear Center", + [PA_CHANNEL_POSITION_REAR_LEFT] = "Rear Left", + [PA_CHANNEL_POSITION_REAR_RIGHT] = "Rear Right", + + [PA_CHANNEL_POSITION_LFE] = "Low Frequency Emmiter", + + [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = "Front Left-of-center", + [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = "Front Right-of-center", + + [PA_CHANNEL_POSITION_SIDE_LEFT] = "Side Left", + [PA_CHANNEL_POSITION_SIDE_RIGHT] = "Side Right", + + [PA_CHANNEL_POSITION_AUX0] = "Auxiliary 0", + [PA_CHANNEL_POSITION_AUX1] = "Auxiliary 1", + [PA_CHANNEL_POSITION_AUX2] = "Auxiliary 2", + [PA_CHANNEL_POSITION_AUX3] = "Auxiliary 3", + [PA_CHANNEL_POSITION_AUX4] = "Auxiliary 4", + [PA_CHANNEL_POSITION_AUX5] = "Auxiliary 5", + [PA_CHANNEL_POSITION_AUX6] = "Auxiliary 6", + [PA_CHANNEL_POSITION_AUX7] = "Auxiliary 7", + [PA_CHANNEL_POSITION_AUX8] = "Auxiliary 8", + [PA_CHANNEL_POSITION_AUX9] = "Auxiliary 9", + [PA_CHANNEL_POSITION_AUX10] = "Auxiliary 10", + [PA_CHANNEL_POSITION_AUX11] = "Auxiliary 11", + [PA_CHANNEL_POSITION_AUX12] = "Auxiliary 12", + [PA_CHANNEL_POSITION_AUX13] = "Auxiliary 13", + [PA_CHANNEL_POSITION_AUX14] = "Auxiliary 14", + [PA_CHANNEL_POSITION_AUX15] = "Auxiliary 15", + [PA_CHANNEL_POSITION_AUX16] = "Auxiliary 16", + [PA_CHANNEL_POSITION_AUX17] = "Auxiliary 17", + [PA_CHANNEL_POSITION_AUX18] = "Auxiliary 18", + [PA_CHANNEL_POSITION_AUX19] = "Auxiliary 19", + [PA_CHANNEL_POSITION_AUX20] = "Auxiliary 20", + [PA_CHANNEL_POSITION_AUX21] = "Auxiliary 21", + [PA_CHANNEL_POSITION_AUX22] = "Auxiliary 22", + [PA_CHANNEL_POSITION_AUX23] = "Auxiliary 23", + [PA_CHANNEL_POSITION_AUX24] = "Auxiliary 24", + [PA_CHANNEL_POSITION_AUX25] = "Auxiliary 25", + [PA_CHANNEL_POSITION_AUX26] = "Auxiliary 26", + [PA_CHANNEL_POSITION_AUX27] = "Auxiliary 27", + [PA_CHANNEL_POSITION_AUX28] = "Auxiliary 28", + [PA_CHANNEL_POSITION_AUX29] = "Auxiliary 29", + [PA_CHANNEL_POSITION_AUX30] = "Auxiliary 30", + [PA_CHANNEL_POSITION_AUX31] = "Auxiliary 31", + + [PA_CHANNEL_POSITION_TOP_CENTER] = "Top Center", + + [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = "Top Front Center", + [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = "Top Front Left", + [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = "Top Front Right", + + [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = "Top Rear Center", + [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = "Top Rear left", + [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = "Top Rear Right" }; pa_channel_map* pa_channel_map_init(pa_channel_map *m) { unsigned c; - assert(m); + pa_assert(m); m->channels = 0; @@ -112,7 +175,7 @@ pa_channel_map* pa_channel_map_init(pa_channel_map *m) { } pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m) { - assert(m); + pa_assert(m); pa_channel_map_init(m); @@ -122,7 +185,7 @@ pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m) { } pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m) { - assert(m); + pa_assert(m); pa_channel_map_init(m); @@ -133,9 +196,9 @@ pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m) { } pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) { - assert(m); - assert(channels > 0); - assert(channels <= PA_CHANNELS_MAX); + pa_assert(m); + pa_assert(channels > 0); + pa_assert(channels <= PA_CHANNELS_MAX); pa_channel_map_init(m); @@ -342,11 +405,18 @@ const char* pa_channel_position_to_string(pa_channel_position_t pos) { return table[pos]; } +const char* pa_channel_position_to_pretty_string(pa_channel_position_t pos) { + if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX) + return NULL; + + return pretty_table[pos]; +} + int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) { unsigned c; - assert(a); - assert(b); + pa_assert(a); + pa_assert(b); if (a->channels != b->channels) return 0; @@ -363,14 +433,14 @@ char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) { int first = 1; char *e; - assert(s); - assert(l > 0); - assert(map); + pa_assert(s); + pa_assert(l > 0); + pa_assert(map); *(e = s) = 0; for (channel = 0; channel < map->channels && l > 1; channel++) { - l -= snprintf(e, l, "%s%s", + l -= pa_snprintf(e, l, "%s%s", first ? "" : ",", pa_channel_position_to_string(map->map[channel])); @@ -386,8 +456,8 @@ pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) { pa_channel_map map; char *p; - assert(rmap); - assert(s); + pa_assert(rmap); + pa_assert(s); memset(&map, 0, sizeof(map)); @@ -447,7 +517,7 @@ finish: int pa_channel_map_valid(const pa_channel_map *map) { unsigned c; - assert(map); + pa_assert(map); if (map->channels <= 0 || map->channels > PA_CHANNELS_MAX) return 0; diff --git a/src/pulse/channelmap.h b/src/pulse/channelmap.h index f0c8f475..a05e1911 100644 --- a/src/pulse/channelmap.h +++ b/src/pulse/channelmap.h @@ -172,7 +172,10 @@ pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m); pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def); /** Return a text label for the specified channel position */ -const char* pa_channel_position_to_string(pa_channel_position_t pos); +const char* pa_channel_position_to_string(pa_channel_position_t pos) PA_GCC_PURE; + +/** Return a human readable text label for the specified channel position. \since 0.9.7 */ +const char* pa_channel_position_to_pretty_string(pa_channel_position_t pos); /** The maximum length of strings returned by pa_channel_map_snprint() */ #define PA_CHANNEL_MAP_SNPRINT_MAX 336 @@ -184,10 +187,10 @@ char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map); pa_channel_map *pa_channel_map_parse(pa_channel_map *map, const char *s); /** Compare two channel maps. Return 1 if both match. */ -int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b); +int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) PA_GCC_PURE; /** Return non-zero of the specified channel map is considered valid */ -int pa_channel_map_valid(const pa_channel_map *map); +int pa_channel_map_valid(const pa_channel_map *map) PA_GCC_PURE; PA_C_DECL_END diff --git a/src/pulse/client-conf-x11.c b/src/pulse/client-conf-x11.c index e8de9553..e240ba88 100644 --- a/src/pulse/client-conf-x11.c +++ b/src/pulse/client-conf-x11.c @@ -26,7 +26,6 @@ #endif #include -#include #include #include @@ -36,6 +35,7 @@ #include #include #include +#include #include "client-conf-x11.h" @@ -44,6 +44,8 @@ int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) { int ret = -1; char t[1024]; + pa_assert(c); + if (!dname && (!(dname = getenv("DISPLAY")) || *dname == '\0')) goto finish; @@ -75,7 +77,7 @@ int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) { goto finish; } - assert(sizeof(cookie) == sizeof(c->cookie)); + pa_assert(sizeof(cookie) == sizeof(c->cookie)); memcpy(c->cookie, cookie, sizeof(cookie)); c->cookie_valid = 1; diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c index bb912335..abd277a6 100644 --- a/src/pulse/client-conf.c +++ b/src/pulse/client-conf.c @@ -27,14 +27,14 @@ #endif #include -#include #include #include #include -#include #include +#include +#include #include #include #include @@ -42,13 +42,7 @@ #include "client-conf.h" -#ifndef OS_IS_WIN32 -# define PATH_SEP "/" -#else -# define PATH_SEP "\\" -#endif - -#define DEFAULT_CLIENT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PATH_SEP "client.conf" +#define DEFAULT_CLIENT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "client.conf" #define DEFAULT_CLIENT_CONFIG_FILE_USER "client.conf" #define ENV_CLIENT_CONFIG_FILE "PULSE_CLIENTCONFIG" @@ -81,7 +75,7 @@ pa_client_conf *pa_client_conf_new(void) { } void pa_client_conf_free(pa_client_conf *c) { - assert(c); + pa_assert(c); pa_xfree(c->daemon_binary); pa_xfree(c->extra_arguments); pa_xfree(c->default_sink); @@ -90,6 +84,7 @@ void pa_client_conf_free(pa_client_conf *c) { pa_xfree(c->cookie_file); pa_xfree(c); } + int pa_client_conf_load(pa_client_conf *c, const char *filename) { FILE *f = NULL; char *fn = NULL; @@ -122,7 +117,7 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) { pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn, "r"); if (!f && errno != EINTR) { - pa_log("WARNING: failed to open configuration file '%s': %s", fn, pa_cstrerror(errno)); + pa_log_warn("Failed to open configuration file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } @@ -175,7 +170,7 @@ int pa_client_conf_env(pa_client_conf *c) { } int pa_client_conf_load_cookie(pa_client_conf* c) { - assert(c); + pa_assert(c); c->cookie_valid = 0; diff --git a/src/pulse/context.c b/src/pulse/context.c index 58a5a879..805cd44e 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -27,7 +27,6 @@ #endif #include -#include #include #include #include @@ -67,6 +66,7 @@ #include #include #include +#include #include "internal.h" @@ -90,7 +90,7 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { }; static void unlock_autospawn_lock_file(pa_context *c) { - assert(c); + pa_assert(c); if (c->autospawn_lock_fd >= 0) { char lf[PATH_MAX]; @@ -106,11 +106,11 @@ static void context_free(pa_context *c); pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { pa_context *c; - assert(mainloop); - assert(name); + pa_assert(mainloop); + pa_assert(name); c = pa_xnew(pa_context, 1); - c->ref = 1; + PA_REFCNT_INIT(c); c->name = pa_xstrdup(name); c->mainloop = mainloop; c->client = NULL; @@ -168,7 +168,7 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { } static void context_free(pa_context *c) { - assert(c); + pa_assert(c); unlock_autospawn_lock_file(c); @@ -183,7 +183,7 @@ static void context_free(pa_context *c) { if (c->pdispatch) pa_pdispatch_unref(c->pdispatch); if (c->pstream) { - pa_pstream_close(c->pstream); + pa_pstream_unlink(c->pstream); pa_pstream_unref(c->pstream); } @@ -206,24 +206,24 @@ static void context_free(pa_context *c) { } pa_context* pa_context_ref(pa_context *c) { - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); - c->ref++; + PA_REFCNT_INC(c); return c; } void pa_context_unref(pa_context *c) { - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); - if (--c->ref <= 0) + if (PA_REFCNT_DEC(c) <= 0) context_free(c); } void pa_context_set_state(pa_context *c, pa_context_state_t st) { - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); if (c->state == st) return; @@ -250,7 +250,7 @@ void pa_context_set_state(pa_context *c, pa_context_state_t st) { c->pdispatch = NULL; if (c->pstream) { - pa_pstream_close(c->pstream); + pa_pstream_unlink(c->pstream); pa_pstream_unref(c->pstream); } c->pstream = NULL; @@ -264,16 +264,16 @@ void pa_context_set_state(pa_context *c, pa_context_state_t st) { } void pa_context_fail(pa_context *c, int error) { - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); pa_context_set_error(c, error); pa_context_set_state(c, PA_CONTEXT_FAILED); } int pa_context_set_error(pa_context *c, int error) { - assert(error >= 0); - assert(error < PA_ERR_MAX); + pa_assert(error >= 0); + pa_assert(error < PA_ERR_MAX); if (c) c->error = error; @@ -284,8 +284,8 @@ int pa_context_set_error(pa_context *c, int error) { static void pstream_die_callback(pa_pstream *p, void *userdata) { pa_context *c = userdata; - assert(p); - assert(c); + pa_assert(p); + pa_assert(c); pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED); } @@ -293,9 +293,9 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) { pa_context *c = userdata; - assert(p); - assert(packet); - assert(c); + pa_assert(p); + pa_assert(packet); + pa_assert(c); pa_context_ref(c); @@ -309,18 +309,19 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o pa_context *c = userdata; pa_stream *s; - assert(p); - assert(chunk); - assert(chunk->memblock); - assert(chunk->length); - assert(c); - assert(c->ref >= 1); + pa_assert(p); + pa_assert(chunk); + pa_assert(chunk->memblock); + pa_assert(chunk->length); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); pa_context_ref(c); if ((s = pa_dynarray_get(c->record_streams, channel))) { - assert(seek == PA_SEEK_RELATIVE && offset == 0); + pa_assert(seek == PA_SEEK_RELATIVE); + pa_assert(offset == 0); pa_memblockq_seek(s->record_memblockq, offset, seek); pa_memblockq_push_align(s->record_memblockq, chunk); @@ -337,11 +338,11 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o } int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t) { - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); if (command == PA_COMMAND_ERROR) { - assert(t); + pa_assert(t); if (pa_tagstruct_getu32(t, &c->error) < 0) { pa_context_fail(c, PA_ERR_PROTOCOL); @@ -361,9 +362,9 @@ int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t) { static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_context *c = userdata; - assert(pd); - assert(c); - assert(c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME); + pa_assert(pd); + pa_assert(c); + pa_assert(c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME); pa_context_ref(c); @@ -423,7 +424,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t break; default: - assert(0); + pa_assert(0); } finish: @@ -434,19 +435,19 @@ static void setup_context(pa_context *c, pa_iochannel *io) { pa_tagstruct *t; uint32_t tag; - assert(c); - assert(io); + pa_assert(c); + pa_assert(io); pa_context_ref(c); - assert(!c->pstream); + pa_assert(!c->pstream); c->pstream = pa_pstream_new(c->mainloop, io, c->mempool); pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - assert(!c->pdispatch); + pa_assert(!c->pdispatch); c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); if (!c->conf->cookie_valid) @@ -497,10 +498,10 @@ static int context_connect_spawn(pa_context *c) { goto fail; } - pa_fd_set_cloexec(fds[0], 1); + pa_make_fd_cloexec(fds[0]); - pa_socket_low_delay(fds[0]); - pa_socket_low_delay(fds[1]); + pa_make_socket_low_delay(fds[0]); + pa_make_socket_low_delay(fds[1]); if (c->spawn_api.prefork) c->spawn_api.prefork(); @@ -523,7 +524,7 @@ static int context_connect_spawn(pa_context *c) { int n; /* Not required, since fds[0] has CLOEXEC enabled anyway */ - close(fds[0]); + pa_assert_se(pa_close(fds[0]) == 0); if (c->spawn_api.atfork) c->spawn_api.atfork(); @@ -535,7 +536,7 @@ static int context_connect_spawn(pa_context *c) { argv[n++] = c->conf->daemon_binary; argv[n++] = "--daemonize=yes"; - snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]); + pa_snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]); argv[n++] = strdup(t); while (n < MAX_ARGS) { @@ -570,7 +571,7 @@ static int context_connect_spawn(pa_context *c) { goto fail; } - close(fds[1]); + pa_assert_se(pa_close(fds[1]) == 0); c->is_local = 1; @@ -584,10 +585,7 @@ static int context_connect_spawn(pa_context *c) { return 0; fail: - if (fds[0] != -1) - close(fds[0]); - if (fds[1] != -1) - close(fds[1]); + pa_close_pipe(fds); unlock_autospawn_lock_file(c); @@ -602,8 +600,8 @@ static int try_next_connection(pa_context *c) { char *u = NULL; int r = -1; - assert(c); - assert(!c->client); + pa_assert(c); + pa_assert(!c->client); for (;;) { pa_xfree(u); @@ -648,9 +646,9 @@ finish: static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata) { pa_context *c = userdata; - assert(client); - assert(c); - assert(c->state == PA_CONTEXT_CONNECTING); + pa_assert(client); + pa_assert(c); + pa_assert(c->state == PA_CONTEXT_CONNECTING); pa_context_ref(c); @@ -683,8 +681,8 @@ int pa_context_connect( int r = -1; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_UNCONNECTED, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(c, !(flags & ~PA_CONTEXT_NOAUTOSPAWN), PA_ERR_INVALID); @@ -695,7 +693,7 @@ int pa_context_connect( pa_context_ref(c); - assert(!c->server_list); + pa_assert(!c->server_list); if (server) { if (!(c->server_list = pa_strlist_parse(server))) { @@ -735,7 +733,7 @@ int pa_context_connect( pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); pa_make_secure_parent_dir(lf, 0700, (uid_t)-1, (gid_t)-1); - assert(c->autospawn_lock_fd <= 0); + pa_assert(c->autospawn_lock_fd <= 0); c->autospawn_lock_fd = pa_lock_lockfile(lf); if (api) @@ -755,37 +753,37 @@ finish: } void pa_context_disconnect(pa_context *c) { - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); pa_context_set_state(c, PA_CONTEXT_TERMINATED); } pa_context_state_t pa_context_get_state(pa_context *c) { - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); return c->state; } int pa_context_errno(pa_context *c) { - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); return c->error; } void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) { - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); c->state_callback = cb; c->state_userdata = userdata; } int pa_context_is_pending(pa_context *c) { - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_CONNECTING || @@ -811,11 +809,11 @@ static void pstream_drain_callback(PA_GCC_UNUSED pa_pstream *s, void *userdata) static void set_dispatch_callbacks(pa_operation *o) { int done = 1; - assert(o); - assert(o->ref >= 1); - assert(o->context); - assert(o->context->ref >= 1); - assert(o->context->state == PA_CONTEXT_READY); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); + pa_assert(o->context); + pa_assert(PA_REFCNT_VALUE(o->context) >= 1); + pa_assert(o->context->state == PA_CONTEXT_READY); pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL); pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL); @@ -844,8 +842,8 @@ static void set_dispatch_callbacks(pa_operation *o) { pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) { pa_operation *o; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, pa_context_is_pending(c), PA_ERR_BADSTATE); @@ -860,9 +858,9 @@ void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_U pa_operation *o = userdata; int success = 1; - assert(pd); - assert(o); - assert(o->ref >= 1); + pa_assert(pd); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); if (!o->context) goto finish; @@ -892,8 +890,8 @@ pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, pa_operation *o; uint32_t tag; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); @@ -911,8 +909,8 @@ pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, pa pa_operation *o; uint32_t tag; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); @@ -930,8 +928,8 @@ pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_co pa_operation *o; uint32_t tag; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); @@ -950,8 +948,8 @@ pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_ pa_operation *o; uint32_t tag; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); @@ -966,7 +964,7 @@ pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_ } int pa_context_is_local(pa_context *c) { - assert(c); + pa_assert(c); return c->is_local; } @@ -976,9 +974,9 @@ pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_su pa_operation *o; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(name); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(name); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); @@ -997,8 +995,8 @@ const char* pa_get_library_version(void) { } const char* pa_context_get_server(pa_context *c) { - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); if (!c->server) return NULL; @@ -1016,8 +1014,8 @@ uint32_t pa_context_get_protocol_version(PA_GCC_UNUSED pa_context *c) { } uint32_t pa_context_get_server_protocol_version(pa_context *c) { - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); return c->version; } @@ -1025,8 +1023,8 @@ uint32_t pa_context_get_server_protocol_version(pa_context *c) { pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag) { pa_tagstruct *t; - assert(c); - assert(tag); + pa_assert(c); + pa_assert(tag); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, command); diff --git a/src/pulse/glib-mainloop.c b/src/pulse/glib-mainloop.c index 5b399aa2..b7a7537a 100644 --- a/src/pulse/glib-mainloop.c +++ b/src/pulse/glib-mainloop.c @@ -25,8 +25,6 @@ #include #endif -#include - #include #include diff --git a/src/pulse/internal.h b/src/pulse/internal.h index 52354fdc..95593adb 100644 --- a/src/pulse/internal.h +++ b/src/pulse/internal.h @@ -41,13 +41,14 @@ #include #include #include +#include #include "client-conf.h" #define DEFAULT_TIMEOUT (30) struct pa_context { - int ref; + PA_REFCNT_DECLARE; char *name; pa_mainloop_api* mainloop; @@ -96,7 +97,7 @@ typedef struct pa_index_correction { } pa_index_correction; struct pa_stream { - int ref; + PA_REFCNT_DECLARE; pa_context *context; pa_mainloop_api *mainloop; PA_LLIST_FIELDS(pa_stream); @@ -116,6 +117,7 @@ struct pa_stream { uint32_t requested_bytes; pa_memchunk peek_memchunk; + void *peek_data; pa_memblockq *record_memblockq; int corked; @@ -160,7 +162,8 @@ struct pa_stream { typedef void (*pa_operation_cb_t)(void); struct pa_operation { - int ref; + PA_REFCNT_DECLARE; + pa_context *context; pa_stream *stream; diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c index 7f6406cf..6610a724 100644 --- a/src/pulse/introspect.c +++ b/src/pulse/introspect.c @@ -26,11 +26,10 @@ #include #endif -#include - #include #include +#include #include #include "internal.h" @@ -43,9 +42,11 @@ static void context_stat_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNU pa_operation *o = userdata; pa_stat_info i, *p = &i; - assert(pd); - assert(o); - assert(o->ref >= 1); + pa_assert(pd); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); + + memset(&i, 0, sizeof(i)); if (!o->context) goto finish; @@ -59,8 +60,7 @@ static void context_stat_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNU pa_tagstruct_getu32(t, &i.memblock_total_size) < 0 || pa_tagstruct_getu32(t, &i.memblock_allocated) < 0 || pa_tagstruct_getu32(t, &i.memblock_allocated_size) < 0 || - pa_tagstruct_getu32(t, &i.scache_size) < 0 || - !pa_tagstruct_eof(t)) { + pa_tagstruct_getu32(t, &i.scache_size) < 0) { pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } @@ -85,9 +85,11 @@ static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command, pa_operation *o = userdata; pa_server_info i, *p = &i; - assert(pd); - assert(o); - assert(o->ref >= 1); + pa_assert(pd); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); + + memset(&i, 0, sizeof(i)); if (!o->context) goto finish; @@ -104,8 +106,7 @@ static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command, pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || pa_tagstruct_gets(t, &i.default_sink_name) < 0 || pa_tagstruct_gets(t, &i.default_source_name) < 0 || - pa_tagstruct_getu32(t, &i.cookie) < 0 || - !pa_tagstruct_eof(t)) { + pa_tagstruct_getu32(t, &i.cookie) < 0) { pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; @@ -131,9 +132,9 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P pa_operation *o = userdata; int eol = 1; - assert(pd); - assert(o); - assert(o->ref >= 1); + pa_assert(pd); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); if (!o->context) goto finish; @@ -148,6 +149,7 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P while (!pa_tagstruct_eof(t)) { pa_sink_info i; + memset(&i, 0, sizeof(i)); if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || @@ -195,9 +197,9 @@ pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, pa_ pa_operation *o; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(cb); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(cb); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); @@ -217,9 +219,9 @@ pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, pa_operation *o; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(cb); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(cb); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); @@ -241,9 +243,9 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, pa_operation *o = userdata; int eol = 1; - assert(pd); - assert(o); - assert(o->ref >= 1); + pa_assert(pd); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); if (!o->context) goto finish; @@ -258,6 +260,7 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, while (!pa_tagstruct_eof(t)) { pa_source_info i; uint32_t flags; + memset(&i, 0, sizeof(i)); if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || @@ -305,9 +308,9 @@ pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, p pa_operation *o; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(cb); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(cb); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); @@ -327,9 +330,9 @@ pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name pa_operation *o; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(cb); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(cb); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); @@ -351,9 +354,9 @@ static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, pa_operation *o = userdata; int eol = 1; - assert(pd); - assert(o); - assert(o->ref >= 1); + pa_assert(pd); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); if (!o->context) goto finish; @@ -367,6 +370,7 @@ static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, while (!pa_tagstruct_eof(t)) { pa_client_info i; + memset(&i, 0, sizeof(i)); if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || @@ -398,9 +402,9 @@ pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, pa_client_ pa_operation *o; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(cb); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(cb); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); @@ -425,9 +429,9 @@ static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command, pa_operation *o = userdata; int eol = 1; - assert(pd); - assert(o); - assert(o->ref >= 1); + pa_assert(pd); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); if (!o->context) goto finish; @@ -441,6 +445,7 @@ static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command, while (!pa_tagstruct_eof(t)) { pa_module_info i; + memset(&i, 0, sizeof(i)); if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || @@ -473,9 +478,9 @@ pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_ pa_operation *o; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(cb); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(cb); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); @@ -500,9 +505,9 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm pa_operation *o = userdata; int eol = 1; - assert(pd); - assert(o); - assert(o->ref >= 1); + pa_assert(pd); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); if (!o->context) goto finish; @@ -516,6 +521,7 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm while (!pa_tagstruct_eof(t)) { pa_sink_input_info i; + memset(&i, 0, sizeof(i)); if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || @@ -528,7 +534,8 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || pa_tagstruct_gets(t, &i.resample_method) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0) { + pa_tagstruct_gets(t, &i.driver) < 0 || + (o->context->version >= 11 && pa_tagstruct_get_boolean(t, &i.mute) < 0)) { pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; @@ -556,9 +563,9 @@ pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sin pa_operation *o; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(cb); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(cb); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); @@ -583,9 +590,9 @@ static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t c pa_operation *o = userdata; int eol = 1; - assert(pd); - assert(o); - assert(o->ref >= 1); + pa_assert(pd); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); if (!o->context) goto finish; @@ -600,6 +607,8 @@ static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t c while (!pa_tagstruct_eof(t)) { pa_source_output_info i; + memset(&i, 0, sizeof(i)); + if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_getu32(t, &i.owner_module) < 0 || @@ -638,9 +647,9 @@ pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, pa_ pa_operation *o; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(cb); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(cb); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); @@ -666,9 +675,9 @@ pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, c pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(volume); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(volume); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); @@ -690,10 +699,10 @@ pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(name); - assert(volume); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(name); + pa_assert(volume); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); @@ -716,8 +725,8 @@ pa_operation* pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); @@ -738,9 +747,9 @@ pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name, pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(name); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(name); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); @@ -762,9 +771,9 @@ pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, cons pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(volume); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(volume); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); @@ -781,14 +790,37 @@ pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, cons return o; } +pa_operation* pa_context_set_sink_input_mute(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 11, PA_ERR_NOTSUPPORTED); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_INPUT_MUTE, &tag); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_put_boolean(t, mute); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(volume); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(volume); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); @@ -810,10 +842,10 @@ pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *na pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(name); - assert(volume); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(name); + pa_assert(volume); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); @@ -836,8 +868,8 @@ pa_operation* pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, i pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); @@ -858,9 +890,9 @@ pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(name); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(name); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); @@ -883,9 +915,9 @@ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, pa_operation *o = userdata; int eol = 1; - assert(pd); - assert(o); - assert(o->ref >= 1); + pa_assert(pd); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); if (!o->context) goto finish; @@ -900,6 +932,8 @@ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, while (!pa_tagstruct_eof(t)) { pa_sample_info i; + memset(&i, 0, sizeof(i)); + if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_get_cvolume(t, &i.volume) < 0 || @@ -936,9 +970,9 @@ pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name pa_operation *o; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(cb); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(cb); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); @@ -959,9 +993,9 @@ pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, p pa_operation *o; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(cb); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(cb); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); @@ -986,8 +1020,8 @@ static pa_operation* command_kill(pa_context *c, uint32_t command, uint32_t idx, pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); @@ -1018,9 +1052,9 @@ static void context_index_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN pa_operation *o = userdata; uint32_t idx; - assert(pd); - assert(o); - assert(o->ref >= 1); + pa_assert(pd); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); if (!o->context) goto finish; @@ -1052,8 +1086,8 @@ pa_operation* pa_context_load_module(pa_context *c, const char*name, const char pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); @@ -1079,9 +1113,9 @@ static void context_get_autoload_info_callback(pa_pdispatch *pd, uint32_t comman pa_operation *o = userdata; int eol = 1; - assert(pd); - assert(o); - assert(o->ref >= 1); + pa_assert(pd); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); if (!o->context) goto finish; @@ -1096,6 +1130,8 @@ static void context_get_autoload_info_callback(pa_pdispatch *pd, uint32_t comman while (!pa_tagstruct_eof(t)) { pa_autoload_info i; + memset(&i, 0, sizeof(i)); + if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_getu32(t, &i.type) < 0 || @@ -1127,9 +1163,9 @@ pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *na pa_operation *o; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(cb); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(cb); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); @@ -1151,9 +1187,9 @@ pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, pa_operation *o; uint32_t tag; - assert(c); - assert(c->ref >= 1); - assert(cb); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(cb); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); @@ -1177,8 +1213,8 @@ pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autolo pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); @@ -1203,8 +1239,8 @@ pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); @@ -1226,8 +1262,8 @@ pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, p pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); @@ -1247,8 +1283,8 @@ pa_operation* pa_context_move_sink_input_by_name(pa_context *c, uint32_t idx, ch pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 10, PA_ERR_NOTSUPPORTED); @@ -1272,8 +1308,8 @@ pa_operation* pa_context_move_sink_input_by_index(pa_context *c, uint32_t idx, u pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 10, PA_ERR_NOTSUPPORTED); @@ -1297,8 +1333,8 @@ pa_operation* pa_context_move_source_output_by_name(pa_context *c, uint32_t idx, pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 10, PA_ERR_NOTSUPPORTED); @@ -1322,8 +1358,8 @@ pa_operation* pa_context_move_source_output_by_index(pa_context *c, uint32_t idx pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 10, PA_ERR_NOTSUPPORTED); @@ -1341,3 +1377,97 @@ pa_operation* pa_context_move_source_output_by_index(pa_context *c, uint32_t idx return o; } + +pa_operation* pa_context_suspend_sink_by_name(pa_context *c, char *sink_name, int suspend, pa_context_success_cb_t cb, void* userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 11, PA_ERR_NOTSUPPORTED); + PA_CHECK_VALIDITY_RETURN_NULL(c, !sink_name || *sink_name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SUSPEND_SINK, &tag); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, sink_name); + pa_tagstruct_put_boolean(t, suspend); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_suspend_sink_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 11, PA_ERR_NOTSUPPORTED); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SUSPEND_SINK, &tag); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, idx == PA_INVALID_INDEX ? "" : NULL); + pa_tagstruct_put_boolean(t, suspend); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_suspend_source_by_name(pa_context *c, char *source_name, int suspend, pa_context_success_cb_t cb, void* userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 11, PA_ERR_NOTSUPPORTED); + PA_CHECK_VALIDITY_RETURN_NULL(c, !source_name || *source_name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SUSPEND_SOURCE, &tag); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, source_name); + pa_tagstruct_put_boolean(t, suspend); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_suspend_source_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 11, PA_ERR_NOTSUPPORTED); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_SUSPEND_SOURCE, &tag); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, idx == PA_INVALID_INDEX ? "" : NULL); + pa_tagstruct_put_boolean(t, suspend); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h index 43e430b2..c148ee5e 100644 --- a/src/pulse/introspect.h +++ b/src/pulse/introspect.h @@ -331,6 +331,7 @@ typedef struct pa_sink_input_info { pa_usec_t sink_usec; /**< Latency of the sink device, see pa_latency_info for details */ const char *resample_method; /**< Thre resampling method used by this sink input. \since 0.7 */ const char *driver; /**< Driver name \since 0.8 */ + int mute; /**< Stream muted \since 0.9.7 */ } pa_sink_input_info; /** Callback prototype for pa_context_get_sink_input_info() and firends*/ @@ -381,6 +382,9 @@ pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name, /** Set the volume of a sink input stream */ pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); +/** Set the mute switch of a sink input stream \since 0.9.7 */ +pa_operation* pa_context_set_sink_input_mute(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata); + /** Set the volume of a source device specified by its index \since 0.8 */ pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); @@ -499,6 +503,18 @@ pa_operation* pa_context_move_source_output_by_name(pa_context *c, uint32_t idx, /** Move the specified source output to a different source. \since 0.9.5 */ pa_operation* pa_context_move_source_output_by_index(pa_context *c, uint32_t idx, uint32_t source_idx, pa_context_success_cb_t cb, void* userdata); +/** Suspend/Resume a sink. \since 0.9.7 */ +pa_operation* pa_context_suspend_sink_by_name(pa_context *c, char *sink_name, int suspend, pa_context_success_cb_t cb, void* userdata); + +/** Suspend/Resume a sink. If idx is PA_INVALID_INDEX all sinks will be suspended. \since 0.9.7 */ +pa_operation* pa_context_suspend_sink_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata); + +/** Suspend/Resume a source. \since 0.9.7 */ +pa_operation* pa_context_suspend_source_by_name(pa_context *c, char *source_name, int suspend, pa_context_success_cb_t cb, void* userdata); + +/** Suspend/Resume a source. If idx is PA_INVALID_INDEX all sources will be suspended. \since 0.9.7 */ +pa_operation* pa_context_suspend_source_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata); + PA_C_DECL_END #endif diff --git a/src/pulse/mainloop-api.c b/src/pulse/mainloop-api.c index 001ff314..b2ed3434 100644 --- a/src/pulse/mainloop-api.c +++ b/src/pulse/mainloop-api.c @@ -25,12 +25,12 @@ #include #endif -#include #include #include #include +#include #include "mainloop-api.h" @@ -41,32 +41,38 @@ struct once_info { static void once_callback(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { struct once_info *i = userdata; - assert(m && i && i->callback); + pa_assert(m); + pa_assert(i); + + pa_assert(i->callback); i->callback(m, i->userdata); - assert(m->defer_free); + pa_assert(m->defer_free); m->defer_free(e); } static void free_callback(pa_mainloop_api *m, PA_GCC_UNUSED pa_defer_event *e, void *userdata) { struct once_info *i = userdata; - assert(m && i); + + pa_assert(m); + pa_assert(i); pa_xfree(i); } void pa_mainloop_api_once(pa_mainloop_api* m, void (*callback)(pa_mainloop_api *m, void *userdata), void *userdata) { struct once_info *i; pa_defer_event *e; - assert(m && callback); + + pa_assert(m); + pa_assert(callback); i = pa_xnew(struct once_info, 1); i->callback = callback; i->userdata = userdata; - assert(m->defer_new); - e = m->defer_new(m, once_callback, i); - assert(e); + pa_assert(m->defer_new); + pa_assert_se(e = m->defer_new(m, once_callback, i)); m->defer_set_destroy(e, free_callback); } diff --git a/src/pulse/mainloop-signal.c b/src/pulse/mainloop-signal.c index 28ddec49..7d3017e2 100644 --- a/src/pulse/mainloop-signal.c +++ b/src/pulse/mainloop-signal.c @@ -27,7 +27,6 @@ #endif #include -#include #include #include #include @@ -39,12 +38,13 @@ #include #endif -#include #include +#include #include #include #include +#include #include "mainloop-signal.h" @@ -74,11 +74,11 @@ static void signal_handler(int sig) { } static void dispatch(pa_mainloop_api*a, int sig) { - pa_signal_event*s; + pa_signal_event *s; for (s = signals; s; s = s->next) if (s->sig == sig) { - assert(s->callback); + pa_assert(s->callback); s->callback(a, s, sig, s->userdata); break; } @@ -87,7 +87,12 @@ static void dispatch(pa_mainloop_api*a, int sig) { static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags_t f, PA_GCC_UNUSED void *userdata) { ssize_t r; int sig; - assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]); + + pa_assert(a); + pa_assert(e); + pa_assert(f == PA_IO_EVENT_INPUT); + pa_assert(e == io_event); + pa_assert(fd == signal_pipe[0]); if ((r = pa_read(signal_pipe[0], &sig, sizeof(sig), NULL)) < 0) { if (errno == EAGAIN) @@ -107,28 +112,34 @@ static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags int pa_signal_init(pa_mainloop_api *a) { - assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event); + pa_assert(a); + pa_assert(!api); + pa_assert(signal_pipe[0] == -1); + pa_assert(signal_pipe[1] == -1); + pa_assert(!io_event); if (pipe(signal_pipe) < 0) { pa_log("pipe(): %s", pa_cstrerror(errno)); return -1; } - pa_make_nonblock_fd(signal_pipe[0]); - pa_make_nonblock_fd(signal_pipe[1]); - pa_fd_set_cloexec(signal_pipe[0], 1); - pa_fd_set_cloexec(signal_pipe[1], 1); + pa_make_fd_nonblock(signal_pipe[0]); + pa_make_fd_nonblock(signal_pipe[1]); + pa_make_fd_cloexec(signal_pipe[0]); + pa_make_fd_cloexec(signal_pipe[1]); api = a; - io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL); - assert(io_event); + pa_assert_se(io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL)); return 0; } void pa_signal_done(void) { - assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && io_event); + pa_assert(api); + pa_assert(signal_pipe[0] >= 0); + pa_assert(signal_pipe[1] >= 0); + pa_assert(io_event); while (signals) pa_signal_free(signals); @@ -136,9 +147,7 @@ void pa_signal_done(void) { api->io_free(io_event); io_event = NULL; - close(signal_pipe[0]); - close(signal_pipe[1]); - signal_pipe[0] = signal_pipe[1] = -1; + pa_close_pipe(signal_pipe); api = NULL; } @@ -150,13 +159,14 @@ pa_signal_event* pa_signal_new(int sig, void (*_callback) (pa_mainloop_api *api, struct sigaction sa; #endif - assert(sig > 0 && _callback); + pa_assert(sig > 0); + pa_assert(_callback); for (e = signals; e; e = e->next) if (e->sig == sig) goto fail; - e = pa_xmalloc(sizeof(pa_signal_event)); + e = pa_xnew(pa_signal_event, 1); e->sig = sig; e->callback = _callback; e->userdata = userdata; @@ -186,7 +196,7 @@ fail: } void pa_signal_free(pa_signal_event *e) { - assert(e); + pa_assert(e); if (e->next) e->next->previous = e->previous; @@ -196,9 +206,9 @@ void pa_signal_free(pa_signal_event *e) { signals = e->next; #ifdef HAVE_SIGACTION - sigaction(e->sig, &e->saved_sigaction, NULL); + pa_assert_se(sigaction(e->sig, &e->saved_sigaction, NULL) == 0); #else - signal(e->sig, e->saved_handler); + pa_assert_se(signal(e->sig, e->saved_handler) == signal_handler); #endif if (e->destroy_callback) @@ -208,6 +218,7 @@ void pa_signal_free(pa_signal_event *e) { } void pa_signal_set_destroy(pa_signal_event *e, void (*_callback) (pa_mainloop_api *api, pa_signal_event*e, void *userdata)) { - assert(e); + pa_assert(e); + e->destroy_callback = _callback; } diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c index 43cbb19f..ad4e4e97 100644 --- a/src/pulse/mainloop.c +++ b/src/pulse/mainloop.c @@ -31,29 +31,28 @@ #include #include #include -#include #include #include -#ifdef HAVE_SYS_POLL_H -#include +#ifdef HAVE_POLL_H +#include #else -#include "../pulsecore/poll.h" +#include #endif -#include "../pulsecore/winsock.h" - #ifndef HAVE_PIPE -#include "../pulsecore/pipe.h" +#include #endif -#include #include #include #include #include #include +#include +#include +#include #include "mainloop.h" @@ -161,13 +160,13 @@ static pa_io_event* mainloop_io_new( pa_mainloop *m; pa_io_event *e; - assert(a); - assert(a->userdata); - assert(fd >= 0); - assert(callback); + pa_assert(a); + pa_assert(a->userdata); + pa_assert(fd >= 0); + pa_assert(callback); m = a->userdata; - assert(a == &m->api); + pa_assert(a == &m->api); e = pa_xnew(pa_io_event, 1); e->mainloop = m; @@ -195,7 +194,7 @@ static pa_io_event* mainloop_io_new( if ((select((SELECT_TYPE_ARG1) fd, NULL, NULL, SELECT_TYPE_ARG234 &xset, SELECT_TYPE_ARG5 &tv) == -1) && (WSAGetLastError() == WSAENOTSOCK)) { - pa_log_warn("WARNING: cannot monitor non-socket file descriptors."); + pa_log_warn("Cannot monitor non-socket file descriptors."); e->dead = 1; } } @@ -211,8 +210,8 @@ static pa_io_event* mainloop_io_new( } static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags_t events) { - assert(e); - assert(!e->dead); + pa_assert(e); + pa_assert(!e->dead); if (e->events == events) return; @@ -228,8 +227,8 @@ static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags_t events) { } static void mainloop_io_free(pa_io_event *e) { - assert(e); - assert(!e->dead); + pa_assert(e); + pa_assert(!e->dead); e->dead = 1; e->mainloop->io_events_please_scan ++; @@ -241,7 +240,7 @@ static void mainloop_io_free(pa_io_event *e) { } static void mainloop_io_set_destroy(pa_io_event *e, pa_io_event_destroy_cb_t callback) { - assert(e); + pa_assert(e); e->destroy_callback = callback; } @@ -255,12 +254,12 @@ static pa_defer_event* mainloop_defer_new( pa_mainloop *m; pa_defer_event *e; - assert(a); - assert(a->userdata); - assert(callback); + pa_assert(a); + pa_assert(a->userdata); + pa_assert(callback); m = a->userdata; - assert(a == &m->api); + pa_assert(a == &m->api); e = pa_xnew(pa_defer_event, 1); e->mainloop = m; @@ -281,11 +280,11 @@ static pa_defer_event* mainloop_defer_new( } static void mainloop_defer_enable(pa_defer_event *e, int b) { - assert(e); - assert(!e->dead); + pa_assert(e); + pa_assert(!e->dead); if (e->enabled && !b) { - assert(e->mainloop->n_enabled_defer_events > 0); + pa_assert(e->mainloop->n_enabled_defer_events > 0); e->mainloop->n_enabled_defer_events--; } else if (!e->enabled && b) { e->mainloop->n_enabled_defer_events++; @@ -296,21 +295,22 @@ static void mainloop_defer_enable(pa_defer_event *e, int b) { } static void mainloop_defer_free(pa_defer_event *e) { - assert(e); - assert(!e->dead); + pa_assert(e); + pa_assert(!e->dead); e->dead = 1; e->mainloop->defer_events_please_scan ++; if (e->enabled) { - assert(e->mainloop->n_enabled_defer_events > 0); + pa_assert(e->mainloop->n_enabled_defer_events > 0); e->mainloop->n_enabled_defer_events--; + e->enabled = 0; } } static void mainloop_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t callback) { - assert(e); - assert(!e->dead); + pa_assert(e); + pa_assert(!e->dead); e->destroy_callback = callback; } @@ -325,12 +325,12 @@ static pa_time_event* mainloop_time_new( pa_mainloop *m; pa_time_event *e; - assert(a); - assert(a->userdata); - assert(callback); + pa_assert(a); + pa_assert(a->userdata); + pa_assert(callback); m = a->userdata; - assert(a == &m->api); + pa_assert(a == &m->api); e = pa_xnew(pa_time_event, 1); e->mainloop = m; @@ -342,7 +342,7 @@ static pa_time_event* mainloop_time_new( m->n_enabled_time_events++; if (m->cached_next_time_event) { - assert(m->cached_next_time_event->enabled); + pa_assert(m->cached_next_time_event->enabled); if (pa_timeval_cmp(tv, &m->cached_next_time_event->timeval) < 0) m->cached_next_time_event = e; @@ -362,11 +362,11 @@ static pa_time_event* mainloop_time_new( } static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) { - assert(e); - assert(!e->dead); + pa_assert(e); + pa_assert(!e->dead); if (e->enabled && !tv) { - assert(e->mainloop->n_enabled_time_events > 0); + pa_assert(e->mainloop->n_enabled_time_events > 0); e->mainloop->n_enabled_time_events--; } else if (!e->enabled && tv) e->mainloop->n_enabled_time_events++; @@ -377,7 +377,7 @@ static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) { } if (e->mainloop->cached_next_time_event && e->enabled) { - assert(e->mainloop->cached_next_time_event->enabled); + pa_assert(e->mainloop->cached_next_time_event->enabled); if (pa_timeval_cmp(tv, &e->mainloop->cached_next_time_event->timeval) < 0) e->mainloop->cached_next_time_event = e; @@ -386,15 +386,16 @@ static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) { } static void mainloop_time_free(pa_time_event *e) { - assert(e); - assert(!e->dead); + pa_assert(e); + pa_assert(!e->dead); e->dead = 1; e->mainloop->time_events_please_scan ++; if (e->enabled) { - assert(e->mainloop->n_enabled_time_events > 0); + pa_assert(e->mainloop->n_enabled_time_events > 0); e->mainloop->n_enabled_time_events--; + e->enabled = 0; } if (e->mainloop->cached_next_time_event == e) @@ -404,8 +405,8 @@ static void mainloop_time_free(pa_time_event *e) { } static void mainloop_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t callback) { - assert(e); - assert(!e->dead); + pa_assert(e); + pa_assert(!e->dead); e->destroy_callback = callback; } @@ -415,10 +416,10 @@ static void mainloop_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb static void mainloop_quit(pa_mainloop_api*a, int retval) { pa_mainloop *m; - assert(a); - assert(a->userdata); + pa_assert(a); + pa_assert(a->userdata); m = a->userdata; - assert(a == &m->api); + pa_assert(a == &m->api); pa_mainloop_quit(m, retval); } @@ -456,8 +457,10 @@ pa_mainloop *pa_mainloop_new(void) { return NULL; } - pa_make_nonblock_fd(m->wakeup_pipe[0]); - pa_make_nonblock_fd(m->wakeup_pipe[1]); + pa_make_fd_nonblock(m->wakeup_pipe[0]); + pa_make_fd_nonblock(m->wakeup_pipe[1]); + pa_make_fd_cloexec(m->wakeup_pipe[0]); + pa_make_fd_cloexec(m->wakeup_pipe[1]); m->wakeup_requested = 0; PA_LLIST_HEAD_INIT(pa_io_event, m->io_events); @@ -502,7 +505,7 @@ static void cleanup_io_events(pa_mainloop *m, int force) { PA_LLIST_REMOVE(pa_io_event, m->io_events, e); if (e->dead) { - assert(m->io_events_please_scan > 0); + pa_assert(m->io_events_please_scan > 0); m->io_events_please_scan--; } @@ -517,7 +520,7 @@ static void cleanup_io_events(pa_mainloop *m, int force) { e = n; } - assert(m->io_events_please_scan == 0); + pa_assert(m->io_events_please_scan == 0); } static void cleanup_time_events(pa_mainloop *m, int force) { @@ -534,13 +537,14 @@ static void cleanup_time_events(pa_mainloop *m, int force) { PA_LLIST_REMOVE(pa_time_event, m->time_events, e); if (e->dead) { - assert(m->time_events_please_scan > 0); + pa_assert(m->time_events_please_scan > 0); m->time_events_please_scan--; } if (!e->dead && e->enabled) { - assert(m->n_enabled_time_events > 0); + pa_assert(m->n_enabled_time_events > 0); m->n_enabled_time_events--; + e->enabled = 0; } if (e->destroy_callback) @@ -552,7 +556,7 @@ static void cleanup_time_events(pa_mainloop *m, int force) { e = n; } - assert(m->time_events_please_scan == 0); + pa_assert(m->time_events_please_scan == 0); } static void cleanup_defer_events(pa_mainloop *m, int force) { @@ -569,13 +573,14 @@ static void cleanup_defer_events(pa_mainloop *m, int force) { PA_LLIST_REMOVE(pa_defer_event, m->defer_events, e); if (e->dead) { - assert(m->defer_events_please_scan > 0); + pa_assert(m->defer_events_please_scan > 0); m->defer_events_please_scan--; } if (!e->dead && e->enabled) { - assert(m->n_enabled_defer_events > 0); + pa_assert(m->n_enabled_defer_events > 0); m->n_enabled_defer_events--; + e->enabled = 0; } if (e->destroy_callback) @@ -587,12 +592,12 @@ static void cleanup_defer_events(pa_mainloop *m, int force) { e = n; } - assert(m->defer_events_please_scan == 0); + pa_assert(m->defer_events_please_scan == 0); } void pa_mainloop_free(pa_mainloop* m) { - assert(m); + pa_assert(m); cleanup_io_events(m, 1); cleanup_defer_events(m, 1); @@ -600,16 +605,13 @@ void pa_mainloop_free(pa_mainloop* m) { pa_xfree(m->pollfds); - if (m->wakeup_pipe[0] >= 0) - close(m->wakeup_pipe[0]); - if (m->wakeup_pipe[1] >= 0) - close(m->wakeup_pipe[1]); + pa_close_pipe(m->wakeup_pipe); pa_xfree(m); } static void scan_dead(pa_mainloop *m) { - assert(m); + pa_assert(m); if (m->io_events_please_scan) cleanup_io_events(m, 0); @@ -666,13 +668,14 @@ static int dispatch_pollfds(pa_mainloop *m) { pa_io_event *e; int r = 0, k; - assert(m->poll_func_ret > 0); + pa_assert(m->poll_func_ret > 0); for (e = m->io_events, k = m->poll_func_ret; e && !m->quit && k > 0; e = e->next) { if (e->dead || !e->pollfd || !e->pollfd->revents) continue; - assert(e->pollfd->fd == e->fd && e->callback); + pa_assert(e->pollfd->fd == e->fd); + pa_assert(e->callback); e->callback(&m->api, e, e->fd, map_flags_from_libc(e->pollfd->revents), e->userdata); e->pollfd->revents = 0; r++; @@ -694,7 +697,7 @@ static int dispatch_defer(pa_mainloop *m) { if (e->dead || !e->enabled) continue; - assert(e->callback); + pa_assert(e->callback); e->callback(&m->api, e, e->userdata); r++; } @@ -704,7 +707,7 @@ static int dispatch_defer(pa_mainloop *m) { static pa_time_event* find_next_time_event(pa_mainloop *m) { pa_time_event *t, *n = NULL; - assert(m); + pa_assert(m); if (m->cached_next_time_event) return m->cached_next_time_event; @@ -736,7 +739,7 @@ static int calc_next_timeout(pa_mainloop *m) { return -1; t = find_next_time_event(m); - assert(t); + pa_assert(t); if (t->timeval.tv_sec <= 0) return 0; @@ -754,7 +757,7 @@ static int dispatch_timeout(pa_mainloop *m) { pa_time_event *e; struct timeval now; int r = 0; - assert(m); + pa_assert(m); if (m->n_enabled_time_events <= 0) return 0; @@ -767,7 +770,7 @@ static int dispatch_timeout(pa_mainloop *m) { continue; if (pa_timeval_cmp(&e->timeval, &now) <= 0) { - assert(e->callback); + pa_assert(e->callback); /* Disable time event */ mainloop_time_restart(e, NULL); @@ -783,7 +786,7 @@ static int dispatch_timeout(pa_mainloop *m) { void pa_mainloop_wakeup(pa_mainloop *m) { char c = 'W'; - assert(m); + pa_assert(m); if (m->wakeup_pipe[1] >= 0 && m->state == STATE_POLLING) { pa_write(m->wakeup_pipe[1], &c, sizeof(c), &m->wakeup_pipe_type); @@ -794,7 +797,7 @@ void pa_mainloop_wakeup(pa_mainloop *m) { static void clear_wakeup(pa_mainloop *m) { char c[10]; - assert(m); + pa_assert(m); if (m->wakeup_pipe[0] < 0) return; @@ -806,8 +809,8 @@ static void clear_wakeup(pa_mainloop *m) { } int pa_mainloop_prepare(pa_mainloop *m, int timeout) { - assert(m); - assert(m->state == STATE_PASSIVE); + pa_assert(m); + pa_assert(m->state == STATE_PASSIVE); clear_wakeup(m); scan_dead(m); @@ -833,8 +836,8 @@ quit: } int pa_mainloop_poll(pa_mainloop *m) { - assert(m); - assert(m->state == STATE_PREPARED); + pa_assert(m); + pa_assert(m->state == STATE_PREPARED); if (m->quit) goto quit; @@ -844,7 +847,7 @@ int pa_mainloop_poll(pa_mainloop *m) { if (m->n_enabled_defer_events ) m->poll_func_ret = 0; else { - assert(!m->rebuild_pollfds); + pa_assert(!m->rebuild_pollfds); if (m->poll_func) m->poll_func_ret = m->poll_func(m->pollfds, m->n_pollfds, m->prepared_timeout, m->poll_func_userdata); @@ -870,8 +873,8 @@ quit: int pa_mainloop_dispatch(pa_mainloop *m) { int dispatched = 0; - assert(m); - assert(m->state == STATE_POLLED); + pa_assert(m); + pa_assert(m->state == STATE_POLLED); if (m->quit) goto quit; @@ -902,13 +905,13 @@ quit: } int pa_mainloop_get_retval(pa_mainloop *m) { - assert(m); + pa_assert(m); return m->retval; } int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) { int r; - assert(m); + pa_assert(m); if ((r = pa_mainloop_prepare(m, block ? -1 : 0)) < 0) goto quit; @@ -942,7 +945,7 @@ int pa_mainloop_run(pa_mainloop *m, int *retval) { } void pa_mainloop_quit(pa_mainloop *m, int retval) { - assert(m); + pa_assert(m); m->quit = 1; m->retval = retval; @@ -950,12 +953,12 @@ void pa_mainloop_quit(pa_mainloop *m, int retval) { } pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m) { - assert(m); + pa_assert(m); return &m->api; } void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata) { - assert(m); + pa_assert(m); m->poll_func = poll_func; m->poll_func_userdata = userdata; diff --git a/src/pulse/operation.c b/src/pulse/operation.c index f23def50..ed5eb4aa 100644 --- a/src/pulse/operation.c +++ b/src/pulse/operation.c @@ -25,19 +25,18 @@ #include #endif -#include - #include +#include #include "internal.h" #include "operation.h" pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t cb, void *userdata) { pa_operation *o; - assert(c); + pa_assert(c); o = pa_xnew(pa_operation, 1); - o->ref = 1; + PA_REFCNT_INIT(o); o->context = c; o->stream = s; @@ -53,27 +52,27 @@ pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t cb } pa_operation *pa_operation_ref(pa_operation *o) { - assert(o); - assert(o->ref >= 1); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); - o->ref++; + PA_REFCNT_INC(o); return o; } void pa_operation_unref(pa_operation *o) { - assert(o); - assert(o->ref >= 1); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); - if ((--(o->ref)) == 0) { - assert(!o->context); - assert(!o->stream); + if (PA_REFCNT_DEC(o) <= 0) { + pa_assert(!o->context); + pa_assert(!o->stream); pa_xfree(o); } } static void operation_set_state(pa_operation *o, pa_operation_state_t st) { - assert(o); - assert(o->ref >= 1); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); if (st == o->state) return; @@ -85,7 +84,7 @@ static void operation_set_state(pa_operation *o, pa_operation_state_t st) { if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) { if (o->context) { - assert(o->ref >= 2); + pa_assert(PA_REFCNT_VALUE(o) >= 2); PA_LLIST_REMOVE(pa_operation, o->context->operations, o); pa_operation_unref(o); @@ -101,22 +100,22 @@ static void operation_set_state(pa_operation *o, pa_operation_state_t st) { } void pa_operation_cancel(pa_operation *o) { - assert(o); - assert(o->ref >= 1); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); operation_set_state(o, PA_OPERATION_CANCELED); } void pa_operation_done(pa_operation *o) { - assert(o); - assert(o->ref >= 1); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); operation_set_state(o, PA_OPERATION_DONE); } pa_operation_state_t pa_operation_get_state(pa_operation *o) { - assert(o); - assert(o->ref >= 1); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); return o->state; } diff --git a/src/pulse/sample.c b/src/pulse/sample.c index ffdeedf7..ae2a0b9f 100644 --- a/src/pulse/sample.c +++ b/src/pulse/sample.c @@ -27,57 +27,58 @@ #endif #include -#include #include #include +#include +#include + #include "sample.h" size_t pa_sample_size(const pa_sample_spec *spec) { - assert(spec); - - switch (spec->format) { - case PA_SAMPLE_U8: - case PA_SAMPLE_ULAW: - case PA_SAMPLE_ALAW: - return 1; - case PA_SAMPLE_S16LE: - case PA_SAMPLE_S16BE: - return 2; - case PA_SAMPLE_FLOAT32LE: - case PA_SAMPLE_FLOAT32BE: - return 4; - default: - assert(0); - return 0; - } + + static const size_t table[] = { + [PA_SAMPLE_U8] = 1, + [PA_SAMPLE_ULAW] = 1, + [PA_SAMPLE_ALAW] = 1, + [PA_SAMPLE_S16LE] = 2, + [PA_SAMPLE_S16BE] = 2, + [PA_SAMPLE_FLOAT32LE] = 4, + [PA_SAMPLE_FLOAT32BE] = 4 + }; + + pa_assert(spec); + pa_assert(spec->format >= 0); + pa_assert(spec->format < PA_SAMPLE_MAX); + + return table[spec->format]; } size_t pa_frame_size(const pa_sample_spec *spec) { - assert(spec); + pa_assert(spec); return pa_sample_size(spec) * spec->channels; } size_t pa_bytes_per_second(const pa_sample_spec *spec) { - assert(spec); + pa_assert(spec); return spec->rate*pa_frame_size(spec); } pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) { - assert(spec); + pa_assert(spec); return (pa_usec_t) (((double) length/pa_frame_size(spec)*1000000)/spec->rate); } size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec) { - assert(spec); + pa_assert(spec); return (size_t) (((double) t * spec->rate / 1000000))*pa_frame_size(spec); } int pa_sample_spec_valid(const pa_sample_spec *spec) { - assert(spec); + pa_assert(spec); if (spec->rate <= 0 || spec->rate > PA_RATE_MAX || @@ -91,7 +92,8 @@ int pa_sample_spec_valid(const pa_sample_spec *spec) { } int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b) { - assert(a && b); + pa_assert(a); + pa_assert(b); return (a->format == b->format) && (a->rate == b->rate) && (a->channels == b->channels); } @@ -107,37 +109,42 @@ const char *pa_sample_format_to_string(pa_sample_format_t f) { [PA_SAMPLE_FLOAT32BE] = "float32be", }; - if (f >= PA_SAMPLE_MAX) + if (f < 0 || f >= PA_SAMPLE_MAX) return NULL; return table[f]; } char *pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec) { - assert(s && l && spec); + pa_assert(s); + pa_assert(l); + pa_assert(spec); if (!pa_sample_spec_valid(spec)) - snprintf(s, l, "Invalid"); + pa_snprintf(s, l, "Invalid"); else - snprintf(s, l, "%s %uch %uHz", pa_sample_format_to_string(spec->format), spec->channels, spec->rate); + pa_snprintf(s, l, "%s %uch %uHz", pa_sample_format_to_string(spec->format), spec->channels, spec->rate); return s; } char* pa_bytes_snprint(char *s, size_t l, unsigned v) { + pa_assert(s); + if (v >= ((unsigned) 1024)*1024*1024) - snprintf(s, l, "%0.1f GiB", ((double) v)/1024/1024/1024); + pa_snprintf(s, l, "%0.1f GiB", ((double) v)/1024/1024/1024); else if (v >= ((unsigned) 1024)*1024) - snprintf(s, l, "%0.1f MiB", ((double) v)/1024/1024); + pa_snprintf(s, l, "%0.1f MiB", ((double) v)/1024/1024); else if (v >= (unsigned) 1024) - snprintf(s, l, "%0.1f KiB", ((double) v)/1024); + pa_snprintf(s, l, "%0.1f KiB", ((double) v)/1024); else - snprintf(s, l, "%u B", (unsigned) v); + pa_snprintf(s, l, "%u B", (unsigned) v); return s; } pa_sample_format_t pa_parse_sample_format(const char *format) { + pa_assert(format); if (strcasecmp(format, "s16le") == 0) return PA_SAMPLE_S16LE; @@ -145,15 +152,19 @@ pa_sample_format_t pa_parse_sample_format(const char *format) { return PA_SAMPLE_S16BE; else if (strcasecmp(format, "s16ne") == 0 || strcasecmp(format, "s16") == 0 || strcasecmp(format, "16") == 0) return PA_SAMPLE_S16NE; + else if (strcasecmp(format, "s16re") == 0) + return PA_SAMPLE_S16RE; else if (strcasecmp(format, "u8") == 0 || strcasecmp(format, "8") == 0) return PA_SAMPLE_U8; else if (strcasecmp(format, "float32") == 0 || strcasecmp(format, "float32ne") == 0) - return PA_SAMPLE_FLOAT32; + return PA_SAMPLE_FLOAT32NE; + else if (strcasecmp(format, "float32re") == 0) + return PA_SAMPLE_FLOAT32RE; else if (strcasecmp(format, "float32le") == 0) return PA_SAMPLE_FLOAT32LE; else if (strcasecmp(format, "float32be") == 0) return PA_SAMPLE_FLOAT32BE; - else if (strcasecmp(format, "ulaw") == 0) + else if (strcasecmp(format, "ulaw") == 0 || strcasecmp(format, "mulaw") == 0) return PA_SAMPLE_ULAW; else if (strcasecmp(format, "alaw") == 0) return PA_SAMPLE_ALAW; diff --git a/src/pulse/sample.h b/src/pulse/sample.h index 683167cc..b307621e 100644 --- a/src/pulse/sample.h +++ b/src/pulse/sample.h @@ -155,31 +155,31 @@ typedef struct pa_sample_spec { typedef uint64_t pa_usec_t; /** Return the amount of bytes playback of a second of audio with the specified sample type takes */ -size_t pa_bytes_per_second(const pa_sample_spec *spec); +size_t pa_bytes_per_second(const pa_sample_spec *spec) PA_GCC_PURE; /** Return the size of a frame with the specific sample type */ -size_t pa_frame_size(const pa_sample_spec *spec); +size_t pa_frame_size(const pa_sample_spec *spec) PA_GCC_PURE; /** Return the size of a sample with the specific sample type */ -size_t pa_sample_size(const pa_sample_spec *spec); +size_t pa_sample_size(const pa_sample_spec *spec) PA_GCC_PURE; /** Calculate the time the specified bytes take to play with the specified sample type */ -pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec); +pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) PA_GCC_PURE; /** Calculates the number of bytes that are required for the specified time. \since 0.9 */ -size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec); +size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec) PA_GCC_PURE; /** Return non-zero when the sample type specification is valid */ -int pa_sample_spec_valid(const pa_sample_spec *spec); +int pa_sample_spec_valid(const pa_sample_spec *spec) PA_GCC_PURE; /** Return non-zero when the two sample type specifications match */ -int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b); +int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b) PA_GCC_PURE; /** Return a descriptive string for the specified sample format. \since 0.8 */ -const char *pa_sample_format_to_string(pa_sample_format_t f); +const char *pa_sample_format_to_string(pa_sample_format_t f) PA_GCC_PURE; /** Parse a sample format text. Inverse of pa_sample_format_to_string() */ -pa_sample_format_t pa_parse_sample_format(const char *format); +pa_sample_format_t pa_parse_sample_format(const char *format) PA_GCC_PURE; /** Maximum required string length for pa_sample_spec_snprint() */ #define PA_SAMPLE_SPEC_SNPRINT_MAX 32 diff --git a/src/pulse/scache.c b/src/pulse/scache.c index 09bc1078..186b0a3e 100644 --- a/src/pulse/scache.c +++ b/src/pulse/scache.c @@ -25,12 +25,12 @@ #include #endif -#include #include #include #include #include +#include #include "internal.h" @@ -40,7 +40,8 @@ int pa_stream_connect_upload(pa_stream *s, size_t length) { pa_tagstruct *t; uint32_t tag; - assert(s); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, length > 0, PA_ERR_INVALID); @@ -66,7 +67,9 @@ int pa_stream_connect_upload(pa_stream *s, size_t length) { int pa_stream_finish_upload(pa_stream *s) { pa_tagstruct *t; uint32_t tag; - assert(s); + + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); PA_CHECK_VALIDITY(s->context, s->channel_valid, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, s->context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); @@ -87,8 +90,8 @@ pa_operation *pa_context_play_sample(pa_context *c, const char *name, const char pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); @@ -115,8 +118,8 @@ pa_operation* pa_context_remove_sample(pa_context *c, const char *name, pa_conte pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); diff --git a/src/pulse/simple.c b/src/pulse/simple.c index 3cf862d2..1072fb4d 100644 --- a/src/pulse/simple.c +++ b/src/pulse/simple.c @@ -1,3 +1,4 @@ + /* $Id$ */ /*** @@ -27,7 +28,6 @@ #include #include -#include #include #include @@ -36,6 +36,7 @@ #include #include +#include #include "simple.h" @@ -83,8 +84,8 @@ if (!(p)->context || pa_context_get_state((p)->context) != PA_CONTEXT_READY || \ static void context_state_cb(pa_context *c, void *userdata) { pa_simple *p = userdata; - assert(c); - assert(p); + pa_assert(c); + pa_assert(p); switch (pa_context_get_state(c)) { case PA_CONTEXT_READY: @@ -103,8 +104,8 @@ static void context_state_cb(pa_context *c, void *userdata) { static void stream_state_cb(pa_stream *s, void * userdata) { pa_simple *p = userdata; - assert(s); - assert(p); + pa_assert(s); + pa_assert(p); switch (pa_stream_get_state(s)) { @@ -122,7 +123,7 @@ static void stream_state_cb(pa_stream *s, void * userdata) { static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { pa_simple *p = userdata; - assert(p); + pa_assert(p); pa_threaded_mainloop_signal(p->mainloop, 0); } @@ -130,21 +131,21 @@ static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { static void stream_latency_update_cb(pa_stream *s, void *userdata) { pa_simple *p = userdata; - assert(p); + pa_assert(p); pa_threaded_mainloop_signal(p->mainloop, 0); } pa_simple* pa_simple_new( - const char *server, - const char *name, - pa_stream_direction_t dir, - const char *dev, - const char *stream_name, - const pa_sample_spec *ss, - const pa_channel_map *map, - const pa_buffer_attr *attr, - int *rerror) { + const char *server, + const char *name, + pa_stream_direction_t dir, + const char *dev, + const char *stream_name, + const pa_sample_spec *ss, + const pa_channel_map *map, + const pa_buffer_attr *attr, + int *rerror) { pa_simple *p; int error = PA_ERR_INTERNAL, r; @@ -232,7 +233,7 @@ fail: } void pa_simple_free(pa_simple *s) { - assert(s); + pa_assert(s); if (s->mainloop) pa_threaded_mainloop_stop(s->mainloop); @@ -250,7 +251,7 @@ void pa_simple_free(pa_simple *s) { } int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { - assert(p); + pa_assert(p); CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1); @@ -289,7 +290,7 @@ unlock_and_fail: } int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { - assert(p); + pa_assert(p); CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, -1); CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1); @@ -346,8 +347,8 @@ unlock_and_fail: static void success_cb(pa_stream *s, int success, void *userdata) { pa_simple *p = userdata; - assert(s); - assert(p); + pa_assert(s); + pa_assert(p); p->operation_success = success; pa_threaded_mainloop_signal(p->mainloop, 0); @@ -356,7 +357,7 @@ static void success_cb(pa_stream *s, int success, void *userdata) { int pa_simple_drain(pa_simple *p, int *rerror) { pa_operation *o = NULL; - assert(p); + pa_assert(p); CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); @@ -392,7 +393,7 @@ unlock_and_fail: int pa_simple_flush(pa_simple *p, int *rerror) { pa_operation *o = NULL; - assert(p); + pa_assert(p); CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); @@ -429,7 +430,7 @@ pa_usec_t pa_simple_get_latency(pa_simple *p, int *rerror) { pa_usec_t t; int negative; - assert(p); + pa_assert(p); pa_threaded_mainloop_lock(p->mainloop); diff --git a/src/pulse/simple.h b/src/pulse/simple.h index 128d2716..f76c1d67 100644 --- a/src/pulse/simple.h +++ b/src/pulse/simple.h @@ -51,7 +51,7 @@ * pa_simple *s; * pa_sample_spec ss; * - * ss.format = PA_SAMPLE_S16_NE; + * ss.format = PA_SAMPLE_S16NE; * ss.channels = 2; * ss.rate = 44100; * diff --git a/src/pulse/stream.c b/src/pulse/stream.c index f20c17ae..47906a5c 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -26,7 +26,6 @@ #include #endif -#include #include #include #include @@ -38,6 +37,7 @@ #include #include #include +#include #include "internal.h" @@ -47,13 +47,14 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * pa_stream *s; int i; - assert(c); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID); PA_CHECK_VALIDITY_RETURN_NULL(c, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID); s = pa_xnew(pa_stream, 1); - s->ref = 1; + PA_REFCNT_INIT(s); s->context = c; s->mainloop = c->mainloop; @@ -91,6 +92,7 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->peek_memchunk.index = 0; s->peek_memchunk.length = 0; s->peek_memchunk.memblock = NULL; + s->peek_data = NULL; s->record_memblockq = NULL; @@ -118,15 +120,20 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * } static void stream_free(pa_stream *s) { - assert(s && !s->context && !s->channel_valid); + pa_assert(s); + pa_assert(!s->context); + pa_assert(!s->channel_valid); if (s->auto_timing_update_event) { - assert(s->mainloop); + pa_assert(s->mainloop); s->mainloop->time_free(s->auto_timing_update_event); } - if (s->peek_memchunk.memblock) + if (s->peek_memchunk.memblock) { + if (s->peek_data) + pa_memblock_release(s->peek_memchunk.memblock); pa_memblock_unref(s->peek_memchunk.memblock); + } if (s->record_memblockq) pa_memblockq_free(s->record_memblockq); @@ -136,38 +143,38 @@ static void stream_free(pa_stream *s) { } void pa_stream_unref(pa_stream *s) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); - if (--(s->ref) == 0) + if (PA_REFCNT_DEC(s) <= 0) stream_free(s); } pa_stream* pa_stream_ref(pa_stream *s) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); - s->ref++; + PA_REFCNT_INC(s); return s; } pa_stream_state_t pa_stream_get_state(pa_stream *s) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); return s->state; } pa_context* pa_stream_get_context(pa_stream *s) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); return s->context; } uint32_t pa_stream_get_index(pa_stream *s) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX); @@ -175,8 +182,8 @@ uint32_t pa_stream_get_index(pa_stream *s) { } void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); if (s->state == st) return; @@ -214,6 +221,13 @@ void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { s->channel_valid = 0; s->context = NULL; + + s->read_callback = NULL; + s->write_callback = NULL; + s->state_callback = NULL; + s->overflow_callback = NULL; + s->underflow_callback = NULL; + s->latency_update_callback = NULL; } pa_stream_unref(s); @@ -224,10 +238,11 @@ void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED pa_stream *s; uint32_t channel; - assert(pd); - assert(command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED); - assert(t); - assert(c); + pa_assert(pd); + pa_assert(command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED); + pa_assert(t); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); pa_context_ref(c); @@ -252,10 +267,11 @@ void pa_command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32 pa_context *c = userdata; uint32_t bytes, channel; - assert(pd); - assert(command == PA_COMMAND_REQUEST); - assert(t); - assert(c); + pa_assert(pd); + pa_assert(command == PA_COMMAND_REQUEST); + pa_assert(t); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); pa_context_ref(c); @@ -285,10 +301,11 @@ void pa_command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, PA_GCC pa_context *c = userdata; uint32_t channel; - assert(pd); - assert(command == PA_COMMAND_OVERFLOW || command == PA_COMMAND_UNDERFLOW); - assert(t); - assert(c); + pa_assert(pd); + pa_assert(command == PA_COMMAND_OVERFLOW || command == PA_COMMAND_UNDERFLOW); + pa_assert(t); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); pa_context_ref(c); @@ -317,8 +334,8 @@ void pa_command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, PA_GCC } static void request_auto_timing_update(pa_stream *s, int force) { - struct timeval next; - assert(s); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); if (!(s->flags & PA_STREAM_AUTO_TIMING_UPDATE)) return; @@ -335,13 +352,17 @@ static void request_auto_timing_update(pa_stream *s, int force) { } } - pa_gettimeofday(&next); - pa_timeval_add(&next, LATENCY_IPOL_INTERVAL_USEC); - s->mainloop->time_restart(s->auto_timing_update_event, &next); + if (s->auto_timing_update_event) { + struct timeval next; + pa_gettimeofday(&next); + pa_timeval_add(&next, LATENCY_IPOL_INTERVAL_USEC); + s->mainloop->time_restart(s->auto_timing_update_event, &next); + } } static void invalidate_indexes(pa_stream *s, int r, int w) { - assert(s); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); /* pa_log("invalidate r:%u w:%u tag:%u", r, w, s->context->ctag); */ @@ -376,6 +397,9 @@ static void invalidate_indexes(pa_stream *s, int r, int w) { static void auto_timing_update_callback(PA_GCC_UNUSED pa_mainloop_api *m, PA_GCC_UNUSED pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { pa_stream *s = userdata; + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + /* pa_log("time event"); */ pa_stream_ref(s); @@ -383,12 +407,32 @@ static void auto_timing_update_callback(PA_GCC_UNUSED pa_mainloop_api *m, PA_GCC pa_stream_unref(s); } +static void create_stream_complete(pa_stream *s) { + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + pa_assert(s->state == PA_STREAM_CREATING); + + pa_stream_set_state(s, PA_STREAM_READY); + + if (s->requested_bytes > 0 && s->write_callback) + s->write_callback(s, s->requested_bytes, s->write_userdata); + + if (s->flags & PA_STREAM_AUTO_TIMING_UPDATE) { + struct timeval tv; + pa_gettimeofday(&tv); + tv.tv_usec += LATENCY_IPOL_INTERVAL_USEC; /* every 100 ms */ + pa_assert(!s->auto_timing_update_event); + s->auto_timing_update_event = s->mainloop->time_new(s->mainloop, &tv, &auto_timing_update_callback, s); + } +} + void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_stream *s = userdata; - assert(pd); - assert(s); - assert(s->state == PA_STREAM_CREATING); + pa_assert(pd); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + pa_assert(s->state == PA_STREAM_CREATING); pa_stream_ref(s); @@ -431,7 +475,7 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED } if (s->direction == PA_STREAM_RECORD) { - assert(!s->record_memblockq); + pa_assert(!s->record_memblockq); s->record_memblockq = pa_memblockq_new( 0, @@ -446,23 +490,16 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED s->channel_valid = 1; pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - pa_stream_set_state(s, PA_STREAM_READY); - - if (s->direction != PA_STREAM_UPLOAD && - s->flags & PA_STREAM_AUTO_TIMING_UPDATE) { - struct timeval tv; - - pa_gettimeofday(&tv); - tv.tv_usec += LATENCY_IPOL_INTERVAL_USEC; /* every 100 ms */ - - assert(!s->auto_timing_update_event); - s->auto_timing_update_event = s->mainloop->time_new(s->mainloop, &tv, &auto_timing_update_callback, s); - + if (s->direction != PA_STREAM_UPLOAD && s->flags & PA_STREAM_AUTO_TIMING_UPDATE) { + /* If automatic timing updates are active, we wait for the + * first timing update before going to PA_STREAM_READY + * state */ + s->state = PA_STREAM_READY; request_auto_timing_update(s, 1); - } + s->state = PA_STREAM_CREATING; - if (s->requested_bytes > 0 && s->ref > 1 && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); + } else + create_stream_complete(s); finish: pa_stream_unref(s); @@ -480,8 +517,8 @@ static int create_stream( pa_tagstruct *t; uint32_t tag; - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, !(flags & ~((direction != PA_STREAM_UPLOAD ? @@ -503,12 +540,12 @@ static int create_stream( if (attr) s->buffer_attr = *attr; else { - /* half a second */ + /* half a second, with minimum request of 10 ms */ s->buffer_attr.tlength = pa_bytes_per_second(&s->sample_spec)/2; s->buffer_attr.maxlength = (s->buffer_attr.tlength*3)/2; - s->buffer_attr.minreq = s->buffer_attr.tlength/100; + s->buffer_attr.minreq = s->buffer_attr.tlength/50; s->buffer_attr.prebuf = s->buffer_attr.tlength - s->buffer_attr.minreq; - s->buffer_attr.fragsize = s->buffer_attr.tlength/100; + s->buffer_attr.fragsize = s->buffer_attr.tlength/50; } if (!dev) @@ -565,8 +602,8 @@ int pa_stream_connect_playback( pa_cvolume *volume, pa_stream *sync_stream) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); return create_stream(PA_STREAM_PLAYBACK, s, dev, attr, flags, volume, sync_stream); } @@ -577,8 +614,8 @@ int pa_stream_connect_record( const pa_buffer_attr *attr, pa_stream_flags_t flags) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); return create_stream(PA_STREAM_RECORD, s, dev, attr, flags, NULL, NULL); } @@ -593,9 +630,9 @@ int pa_stream_write( pa_memchunk chunk; - assert(s); - assert(s->ref >= 1); - assert(data); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + pa_assert(data); PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE); @@ -608,8 +645,11 @@ int pa_stream_write( if (free_cb) chunk.memblock = pa_memblock_new_user(s->context->mempool, (void*) data, length, free_cb, 1); else { + void *tdata; chunk.memblock = pa_memblock_new(s->context->mempool, length); - memcpy(chunk.memblock->data, data, length); + tdata = pa_memblock_acquire(chunk.memblock); + memcpy(tdata, data, length); + pa_memblock_release(chunk.memblock); } chunk.index = 0; @@ -660,10 +700,10 @@ int pa_stream_write( } int pa_stream_peek(pa_stream *s, const void **data, size_t *length) { - assert(s); - assert(s->ref >= 1); - assert(data); - assert(length); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + pa_assert(data); + pa_assert(length); PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE); @@ -675,27 +715,32 @@ int pa_stream_peek(pa_stream *s, const void **data, size_t *length) { *length = 0; return 0; } + + s->peek_data = pa_memblock_acquire(s->peek_memchunk.memblock); } - *data = (const char*) s->peek_memchunk.memblock->data + s->peek_memchunk.index; + pa_assert(s->peek_data); + *data = (uint8_t*) s->peek_data + s->peek_memchunk.index; *length = s->peek_memchunk.length; return 0; } int pa_stream_drop(pa_stream *s) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, s->peek_memchunk.memblock, PA_ERR_BADSTATE); - pa_memblockq_drop(s->record_memblockq, &s->peek_memchunk, s->peek_memchunk.length); + pa_memblockq_drop(s->record_memblockq, s->peek_memchunk.length); /* Fix the simulated local read index */ if (s->timing_info_valid && !s->timing_info.read_index_corrupt) s->timing_info.read_index += s->peek_memchunk.length; + pa_assert(s->peek_data); + pa_memblock_release(s->peek_memchunk.memblock); pa_memblock_unref(s->peek_memchunk.memblock); s->peek_memchunk.length = 0; s->peek_memchunk.index = 0; @@ -705,8 +750,8 @@ int pa_stream_drop(pa_stream *s) { } size_t pa_stream_writable_size(pa_stream *s) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (size_t) -1); PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_RECORD, PA_ERR_BADSTATE, (size_t) -1); @@ -715,8 +760,8 @@ size_t pa_stream_writable_size(pa_stream *s) { } size_t pa_stream_readable_size(pa_stream *s) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (size_t) -1); PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, (size_t) -1); @@ -729,8 +774,8 @@ pa_operation * pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *us pa_tagstruct *t; uint32_t tag; - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); @@ -750,8 +795,9 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, struct timeval local, remote, now; pa_timing_info *i; - assert(pd); - assert(o); + pa_assert(pd); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); if (!o->context || !o->stream) goto finish; @@ -874,6 +920,10 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, } } + /* First, let's complete the initialization, if necessary. */ + if (o->stream->state == PA_STREAM_CREATING) + create_stream_complete(o->stream); + if (o->stream->latency_update_callback) o->stream->latency_update_callback(o->stream, o->stream->latency_update_userdata); @@ -895,8 +945,8 @@ pa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t struct timeval now; int cidx = 0; - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); @@ -938,9 +988,9 @@ pa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_stream *s = userdata; - assert(pd); - assert(s); - assert(s->ref >= 1); + pa_assert(pd); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); pa_stream_ref(s); @@ -965,8 +1015,8 @@ int pa_stream_disconnect(pa_stream *s) { pa_tagstruct *t; uint32_t tag; - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); PA_CHECK_VALIDITY(s->context, s->channel_valid, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, s->context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); @@ -987,48 +1037,48 @@ int pa_stream_disconnect(pa_stream *s) { } void pa_stream_set_read_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); s->read_callback = cb; s->read_userdata = userdata; } void pa_stream_set_write_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); s->write_callback = cb; s->write_userdata = userdata; } void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); s->state_callback = cb; s->state_userdata = userdata; } void pa_stream_set_overflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); s->overflow_callback = cb; s->overflow_userdata = userdata; } void pa_stream_set_underflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); s->underflow_callback = cb; s->underflow_userdata = userdata; } void pa_stream_set_latency_update_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); s->latency_update_callback = cb; s->latency_update_userdata = userdata; @@ -1038,9 +1088,9 @@ void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN pa_operation *o = userdata; int success = 1; - assert(pd); - assert(o); - assert(o->ref >= 1); + pa_assert(pd); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); if (!o->context) goto finish; @@ -1070,8 +1120,8 @@ pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, voi pa_tagstruct *t; uint32_t tag; - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); @@ -1100,8 +1150,8 @@ static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, pa_operation *o; uint32_t tag; - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); @@ -1118,6 +1168,9 @@ static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { pa_operation *o; + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); if ((o = stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata))) { @@ -1143,6 +1196,9 @@ pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *use pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { pa_operation *o; + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE); @@ -1155,6 +1211,9 @@ pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *us pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { pa_operation *o; + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE); @@ -1169,9 +1228,9 @@ pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_succe pa_tagstruct *t; uint32_t tag; - assert(s); - assert(s->ref >= 1); - assert(name); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + pa_assert(name); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); @@ -1193,8 +1252,8 @@ pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_succe int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) { pa_usec_t usec = 0; - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); @@ -1277,8 +1336,8 @@ int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) { } static pa_usec_t time_counter_diff(pa_stream *s, pa_usec_t a, pa_usec_t b, int *negative) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); if (negative) *negative = 0; @@ -1299,9 +1358,9 @@ int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative) { int r; int64_t cindex; - assert(s); - assert(s->ref >= 1); - assert(r_usec); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + pa_assert(r_usec); PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); @@ -1331,8 +1390,8 @@ int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative) { } const pa_timing_info* pa_stream_get_timing_info(pa_stream *s) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); @@ -1342,22 +1401,22 @@ const pa_timing_info* pa_stream_get_timing_info(pa_stream *s) { } const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); return &s->sample_spec; } const pa_channel_map* pa_stream_get_channel_map(pa_stream *s) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); return &s->channel_map; } const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s) { - assert(s); - assert(s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); diff --git a/src/pulse/subscribe.c b/src/pulse/subscribe.c index 5d8f1252..580038cc 100644 --- a/src/pulse/subscribe.c +++ b/src/pulse/subscribe.c @@ -25,10 +25,10 @@ #include #endif -#include #include #include +#include #include #include "internal.h" @@ -40,10 +40,11 @@ void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSE pa_subscription_event_type_t e; uint32_t idx; - assert(pd); - assert(command == PA_COMMAND_SUBSCRIBE_EVENT); - assert(t); - assert(c); + pa_assert(pd); + pa_assert(command == PA_COMMAND_SUBSCRIBE_EVENT); + pa_assert(t); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); pa_context_ref(c); @@ -67,8 +68,8 @@ pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_c pa_tagstruct *t; uint32_t tag; - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); @@ -83,8 +84,8 @@ pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_c } void pa_context_set_subscribe_callback(pa_context *c, pa_context_subscribe_cb_t cb, void *userdata) { - assert(c); - assert(c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); c->subscribe_callback = cb; c->subscribe_userdata = userdata; diff --git a/src/pulse/thread-mainloop.c b/src/pulse/thread-mainloop.c index 4f3cacc9..9dd47ae3 100644 --- a/src/pulse/thread-mainloop.c +++ b/src/pulse/thread-mainloop.c @@ -26,24 +26,24 @@ #include #endif -#include #include #include -#ifdef HAVE_SYS_POLL_H -#include +#ifdef HAVE_POLL_H +#include #else -#include "../pulsecore/poll.h" +#include #endif #include +#include #include #include #include #include +#include -#include "mainloop.h" #include "thread-mainloop.h" struct pa_threaded_mainloop { @@ -63,7 +63,7 @@ static int poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void pa_mutex *mutex = userdata; int r; - assert(mutex); + pa_assert(mutex); /* Before entering poll() we unlock the mutex, so that * avahi_simple_poll_quit() can succeed from another thread. */ @@ -103,7 +103,7 @@ pa_threaded_mainloop *pa_threaded_mainloop_new(void) { return NULL; } - m->mutex = pa_mutex_new(1); + m->mutex = pa_mutex_new(TRUE, FALSE); m->cond = pa_cond_new(); m->accept_cond = pa_cond_new(); m->thread = NULL; @@ -116,10 +116,10 @@ pa_threaded_mainloop *pa_threaded_mainloop_new(void) { } void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { - assert(m); + pa_assert(m); /* Make sure that this function is not called from the helper thread */ - assert((m->thread && !pa_thread_is_running(m->thread)) || !in_worker(m)); + pa_assert((m->thread && !pa_thread_is_running(m->thread)) || !in_worker(m)); pa_threaded_mainloop_stop(m); @@ -136,9 +136,9 @@ void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { } int pa_threaded_mainloop_start(pa_threaded_mainloop *m) { - assert(m); + pa_assert(m); - assert(!m->thread || !pa_thread_is_running(m->thread)); + pa_assert(!m->thread || !pa_thread_is_running(m->thread)); if (!(m->thread = pa_thread_new(thread, m))) return -1; @@ -147,13 +147,13 @@ int pa_threaded_mainloop_start(pa_threaded_mainloop *m) { } void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) { - assert(m); + pa_assert(m); if (!m->thread || !pa_thread_is_running(m->thread)) return; /* Make sure that this function is not called from the helper thread */ - assert(!in_worker(m)); + pa_assert(!in_worker(m)); pa_mutex_lock(m->mutex); pa_mainloop_quit(m->real_mainloop, 0); @@ -163,25 +163,25 @@ void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) { } void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) { - assert(m); + pa_assert(m); /* Make sure that this function is not called from the helper thread */ - assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); + pa_assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); pa_mutex_lock(m->mutex); } void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { - assert(m); + pa_assert(m); /* Make sure that this function is not called from the helper thread */ - assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); + pa_assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); pa_mutex_unlock(m->mutex); } void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept) { - assert(m); + pa_assert(m); pa_cond_signal(m->cond, 1); @@ -190,36 +190,42 @@ void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept) { } void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { - assert(m); + pa_assert(m); /* Make sure that this function is not called from the helper thread */ - assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); + pa_assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); m->n_waiting ++; pa_cond_wait(m->cond, m->mutex); - assert(m->n_waiting > 0); + pa_assert(m->n_waiting > 0); m->n_waiting --; } void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) { - assert(m); + pa_assert(m); /* Make sure that this function is not called from the helper thread */ - assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); + pa_assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); pa_cond_signal(m->accept_cond, 0); } int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) { - assert(m); + pa_assert(m); return pa_mainloop_get_retval(m->real_mainloop); } pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) { - assert(m); + pa_assert(m); return pa_mainloop_get_api(m->real_mainloop); } + +int pa_threaded_mainloop_in_thread(pa_threaded_mainloop *m) { + pa_assert(m); + + return m->thread && pa_thread_self() == m->thread; +} diff --git a/src/pulse/thread-mainloop.h b/src/pulse/thread-mainloop.h index b78c1583..ea08f72a 100644 --- a/src/pulse/thread-mainloop.h +++ b/src/pulse/thread-mainloop.h @@ -297,6 +297,9 @@ int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m); /** Return the abstract main loop abstraction layer vtable for this main loop. */ pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m); +/** Returns non-zero when called from withing the event loop thread. \since 0.9.7 */ +int pa_threaded_mainloop_in_thread(pa_threaded_mainloop *m); + PA_C_DECL_END #endif diff --git a/src/pulse/timeval.c b/src/pulse/timeval.c index 78ece061..70ceb71e 100644 --- a/src/pulse/timeval.c +++ b/src/pulse/timeval.c @@ -26,7 +26,6 @@ #include #endif -#include #include #include @@ -34,15 +33,17 @@ #include #endif -#include "../pulsecore/winsock.h" +#include +#include #include "timeval.h" struct timeval *pa_gettimeofday(struct timeval *tv) { #ifdef HAVE_GETTIMEOFDAY - assert(tv); + pa_assert(tv); - return gettimeofday(tv, NULL) < 0 ? NULL : tv; + pa_assert_se(gettimeofday(tv, NULL) == 0); + return tv; #elif defined(OS_IS_WIN32) /* * Copied from implementation by Steven Edwards (LGPL). @@ -59,7 +60,7 @@ struct timeval *pa_gettimeofday(struct timeval *tv) { LARGE_INTEGER li; __int64 t; - assert(tv); + pa_assert(tv); GetSystemTimeAsFileTime(&ft); li.LowPart = ft.dwLowDateTime; @@ -67,8 +68,8 @@ struct timeval *pa_gettimeofday(struct timeval *tv) { t = li.QuadPart; /* In 100-nanosecond intervals */ t -= EPOCHFILETIME; /* Offset to the Epoch time */ t /= 10; /* In microseconds */ - tv->tv_sec = (long)(t / 1000000); - tv->tv_usec = (long)(t % 1000000); + tv->tv_sec = (time_t) (t / PA_USEC_PER_SEC); + tv->tv_usec = (suseconds_t) (t % PA_USEC_PER_SEC); return tv; #else @@ -78,9 +79,11 @@ struct timeval *pa_gettimeofday(struct timeval *tv) { pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { pa_usec_t r; - assert(a && b); - /* Check which whan is the earlier time and swap the two arguments if reuqired. */ + pa_assert(a); + pa_assert(b); + + /* Check which whan is the earlier time and swap the two arguments if required. */ if (pa_timeval_cmp(a, b) < 0) { const struct timeval *c; c = a; @@ -89,7 +92,7 @@ pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { } /* Calculate the second difference*/ - r = ((pa_usec_t) a->tv_sec - b->tv_sec)* 1000000; + r = ((pa_usec_t) a->tv_sec - b->tv_sec) * PA_USEC_PER_SEC; /* Calculate the microsecond difference */ if (a->tv_usec > b->tv_usec) @@ -101,7 +104,8 @@ pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { } int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { - assert(a && b); + pa_assert(a); + pa_assert(b); if (a->tv_sec < b->tv_sec) return -1; @@ -120,26 +124,43 @@ int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { pa_usec_t pa_timeval_age(const struct timeval *tv) { struct timeval now; - assert(tv); + pa_assert(tv); return pa_timeval_diff(pa_gettimeofday(&now), tv); } struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v) { unsigned long secs; - assert(tv); + pa_assert(tv); - secs = (v/1000000); - tv->tv_sec += (unsigned long) secs; - v -= secs*1000000; + secs = (unsigned long) (v/PA_USEC_PER_SEC); + tv->tv_sec += secs; + v -= ((pa_usec_t) secs) * PA_USEC_PER_SEC; - tv->tv_usec += v; + tv->tv_usec += (suseconds_t) v; /* Normalize */ - while (tv->tv_usec >= 1000000) { + while (tv->tv_usec >= PA_USEC_PER_SEC) { tv->tv_sec++; - tv->tv_usec -= 1000000; + tv->tv_usec -= PA_USEC_PER_SEC; } return tv; } + +struct timeval* pa_timeval_store(struct timeval *tv, pa_usec_t v) { + pa_assert(tv); + + tv->tv_sec = v / PA_USEC_PER_SEC; + tv->tv_usec = v % PA_USEC_PER_SEC; + + return tv; +} + +pa_usec_t pa_timeval_load(const struct timeval *tv) { + pa_assert(tv); + + return + (pa_usec_t) tv->tv_sec * PA_USEC_PER_SEC + + (pa_usec_t) tv->tv_usec; +} diff --git a/src/pulse/timeval.h b/src/pulse/timeval.h index 1e5627e3..65a0e513 100644 --- a/src/pulse/timeval.h +++ b/src/pulse/timeval.h @@ -33,6 +33,11 @@ PA_C_DECL_BEGIN +#define PA_MSEC_PER_SEC 1000 +#define PA_USEC_PER_SEC 1000000 +#define PA_NSEC_PER_SEC 1000000000 +#define PA_USEC_PER_MSEC 1000 + struct timeval; /** Return the current timestamp, just like UNIX gettimeofday() */ @@ -40,16 +45,22 @@ struct timeval *pa_gettimeofday(struct timeval *tv); /** Calculate the difference between the two specified timeval * structs. */ -pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); +pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) PA_GCC_PURE; /** Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwse */ -int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); +int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) PA_GCC_PURE; /** Return the time difference between now and the specified timestamp */ pa_usec_t pa_timeval_age(const struct timeval *tv); /** Add the specified time inmicroseconds to the specified timeval structure */ -struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v); +struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v) PA_GCC_PURE; + +/** Store the specified uec value in the timeval struct. \since 0.9.7 */ +struct timeval* pa_timeval_store(struct timeval *tv, pa_usec_t v); + +/** Load the specified tv value and return it in usec. \since 0.9.7 */ +pa_usec_t pa_timeval_load(const struct timeval *tv); PA_C_DECL_END diff --git a/src/pulse/utf8.c b/src/pulse/utf8.c index 2ac2d106..b2f6c3bd 100644 --- a/src/pulse/utf8.c +++ b/src/pulse/utf8.c @@ -37,7 +37,7 @@ * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public @@ -50,7 +50,6 @@ #include #endif -#include #include #include #include @@ -60,12 +59,15 @@ #include #endif +#include +#include + #include "utf8.h" -#include "xmalloc.h" #define FILTER_CHAR '_' static inline int is_unicode_valid(uint32_t ch) { + if (ch >= 0x110000) /* End of unicode space */ return 0; if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ @@ -74,6 +76,7 @@ static inline int is_unicode_valid(uint32_t ch) { return 0; if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ return 0; + return 1; } @@ -95,6 +98,8 @@ static char* utf8_validate(const char *str, char *output) { int size; uint8_t *o; + pa_assert(str); + o = (uint8_t*) output; for (p = (const uint8_t*) str; *p; p++) { if (*p < 128) { @@ -178,15 +183,15 @@ failure: return NULL; } -const char* pa_utf8_valid (const char *str) { +char* pa_utf8_valid (const char *str) { return utf8_validate(str, NULL); } char* pa_utf8_filter (const char *str) { char *new_str; + pa_assert(str); new_str = pa_xnew(char, strlen(str) + 1); - return utf8_validate(str, new_str); } @@ -195,22 +200,24 @@ char* pa_utf8_filter (const char *str) { static char* iconv_simple(const char *str, const char *to, const char *from) { char *new_str; size_t len, inlen; - iconv_t cd; ICONV_CONST char *inbuf; char *outbuf; size_t res, inbytes, outbytes; + pa_assert(str); + pa_assert(to); + pa_assert(from); + cd = iconv_open(to, from); if (cd == (iconv_t)-1) return NULL; inlen = len = strlen(str) + 1; - new_str = pa_xmalloc(len); - assert(new_str); + new_str = pa_xnew(char, len); - while (1) { - inbuf = (ICONV_CONST char*)str; /* Brain dead prototype for iconv() */ + for (;;) { + inbuf = (ICONV_CONST char*) str; /* Brain dead prototype for iconv() */ inbytes = inlen; outbuf = new_str; outbytes = len; @@ -226,11 +233,10 @@ static char* iconv_simple(const char *str, const char *to, const char *from) { break; } - assert(inbytes != 0); + pa_assert(inbytes != 0); len += inbytes; new_str = pa_xrealloc(new_str, len); - assert(new_str); } iconv_close(cd); @@ -249,10 +255,12 @@ char* pa_locale_to_utf8 (const char *str) { #else char* pa_utf8_to_locale (const char *str) { + pa_assert(str); return NULL; } char* pa_locale_to_utf8 (const char *str) { + pa_assert(str); return NULL; } diff --git a/src/pulse/utf8.h b/src/pulse/utf8.h index ff8dc215..1e08047c 100644 --- a/src/pulse/utf8.h +++ b/src/pulse/utf8.h @@ -34,7 +34,7 @@ PA_C_DECL_BEGIN /** Test if the specified strings qualifies as valid UTF8. Return the string if so, otherwise NULL */ -const char *pa_utf8_valid(const char *str); +char *pa_utf8_valid(const char *str) PA_GCC_PURE; /** Filter all invalid UTF8 characters from the specified string, returning a new fully UTF8 valid string. Don't forget to free the returned string with pa_xfree() */ char *pa_utf8_filter(const char *str); diff --git a/src/pulse/util.c b/src/pulse/util.c index d561329c..5dbb670b 100644 --- a/src/pulse/util.c +++ b/src/pulse/util.c @@ -26,7 +26,6 @@ #include #endif -#include #include #include #include @@ -56,20 +55,14 @@ #include #endif -#include "../pulsecore/winsock.h" - +#include #include #include #include +#include #include "util.h" -#ifndef OS_IS_WIN32 -#define PATH_SEP '/' -#else -#define PATH_SEP '\\' -#endif - char *pa_get_user_name(char *s, size_t l) { char *p; char buf[1024]; @@ -78,7 +71,8 @@ char *pa_get_user_name(char *s, size_t l) { struct passwd pw, *r; #endif - assert(s && l > 0); + pa_assert(s); + pa_assert(l > 0); if (!(p = getenv("USER")) && !(p = getenv("LOGNAME")) && !(p = getenv("USERNAME"))) { #ifdef HAVE_PWD_H @@ -90,7 +84,7 @@ char *pa_get_user_name(char *s, size_t l) { * that do not support getpwuid_r. */ if ((r = getpwuid(getuid())) == NULL) { #endif - snprintf(s, l, "%lu", (unsigned long) getuid()); + pa_snprintf(s, l, "%lu", (unsigned long) getuid()); return s; } @@ -113,11 +107,15 @@ char *pa_get_user_name(char *s, size_t l) { } char *pa_get_host_name(char *s, size_t l) { - assert(s && l > 0); + + pa_assert(s); + pa_assert(l > 0); + if (gethostname(s, l) < 0) { pa_log("gethostname(): %s", pa_cstrerror(errno)); return NULL; } + s[l-1] = 0; return s; } @@ -130,7 +128,8 @@ char *pa_get_home_dir(char *s, size_t l) { struct passwd pw, *r; #endif - assert(s && l); + pa_assert(s); + pa_assert(l > 0); if ((e = getenv("HOME"))) return pa_strlcpy(s, e, l); @@ -159,8 +158,8 @@ char *pa_get_home_dir(char *s, size_t l) { char *pa_get_binary_name(char *s, size_t l) { - assert(s); - assert(l); + pa_assert(s); + pa_assert(l > 0); #if defined(OS_IS_WIN32) { @@ -171,7 +170,7 @@ char *pa_get_binary_name(char *s, size_t l) { } #endif -#ifdef HAVE_READLINK +#ifdef __linux__ { int i; char path[PATH_MAX]; @@ -206,13 +205,15 @@ char *pa_get_binary_name(char *s, size_t l) { return NULL; } -const char *pa_path_get_filename(const char *p) { +char *pa_path_get_filename(const char *p) { char *fn; - if ((fn = strrchr(p, PATH_SEP))) + pa_assert(p); + + if ((fn = strrchr(p, PA_PATH_SEP_CHAR))) return fn+1; - return (const char*) p; + return (char*) p; } char *pa_get_fqdn(char *s, size_t l) { @@ -221,6 +222,9 @@ char *pa_get_fqdn(char *s, size_t l) { struct addrinfo *a, hints; #endif + pa_assert(s); + pa_assert(l > 0); + if (!pa_get_host_name(hn, sizeof(hn))) return NULL; diff --git a/src/pulse/util.h b/src/pulse/util.h index 95bd86f3..764678e5 100644 --- a/src/pulse/util.h +++ b/src/pulse/util.h @@ -52,7 +52,7 @@ char *pa_get_binary_name(char *s, size_t l); /** Return a pointer to the filename inside a path (which is the last * component). */ -const char *pa_path_get_filename(const char *p); +char *pa_path_get_filename(const char *p); /** Wait t milliseconds */ int pa_msleep(unsigned long t); diff --git a/src/pulse/volume.c b/src/pulse/volume.c index feb33f07..3688b847 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -25,16 +25,18 @@ #include #endif -#include #include #include +#include +#include + #include "volume.h" int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) { int i; - assert(a); - assert(b); + pa_assert(a); + pa_assert(b); if (a->channels != b->channels) return 0; @@ -49,9 +51,9 @@ int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) { pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) { int i; - assert(a); - assert(channels > 0); - assert(channels <= PA_CHANNELS_MAX); + pa_assert(a); + pa_assert(channels > 0); + pa_assert(channels <= PA_CHANNELS_MAX); a->channels = channels; @@ -64,7 +66,7 @@ pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) { pa_volume_t pa_cvolume_avg(const pa_cvolume *a) { uint64_t sum = 0; int i; - assert(a); + pa_assert(a); for (i = 0; i < a->channels; i++) sum += a->values[i]; @@ -118,14 +120,14 @@ char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) { int first = 1; char *e; - assert(s); - assert(l > 0); - assert(c); + pa_assert(s); + pa_assert(l > 0); + pa_assert(c); *(e = s) = 0; for (channel = 0; channel < c->channels && l > 1; channel++) { - l -= snprintf(e, l, "%s%u: %3u%%", + l -= pa_snprintf(e, l, "%s%u: %3u%%", first ? "" : " ", channel, (c->values[channel]*100)/PA_VOLUME_NORM); @@ -140,7 +142,7 @@ char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) { /** Return non-zero if the volume of all channels is equal to the specified value */ int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) { unsigned c; - assert(a); + pa_assert(a); for (c = 0; c < a->channels; c++) if (a->values[c] != v) @@ -152,9 +154,9 @@ int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) { pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { unsigned i; - assert(dest); - assert(a); - assert(b); + pa_assert(dest); + pa_assert(a); + pa_assert(b); for (i = 0; i < a->channels && i < b->channels && i < PA_CHANNELS_MAX; i++) { @@ -169,7 +171,7 @@ pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const } int pa_cvolume_valid(const pa_cvolume *v) { - assert(v); + pa_assert(v); if (v->channels <= 0 || v->channels > PA_CHANNELS_MAX) return 0; diff --git a/src/pulse/volume.h b/src/pulse/volume.h index a928ff71..22e5b8a4 100644 --- a/src/pulse/volume.h +++ b/src/pulse/volume.h @@ -113,7 +113,7 @@ typedef struct pa_cvolume { } pa_cvolume; /** Return non-zero when *a == *b */ -int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b); +int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) PA_GCC_PURE; /** Set the volume of all channels to PA_VOLUME_NORM */ #define pa_cvolume_reset(a, n) pa_cvolume_set((a), (n), PA_VOLUME_NORM) @@ -131,13 +131,13 @@ pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v); char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c); /** Return the average volume of all channels */ -pa_volume_t pa_cvolume_avg(const pa_cvolume *a); +pa_volume_t pa_cvolume_avg(const pa_cvolume *a) PA_GCC_PURE; /** Return TRUE when the passed cvolume structure is valid, FALSE otherwise */ -int pa_cvolume_valid(const pa_cvolume *v); +int pa_cvolume_valid(const pa_cvolume *v) PA_GCC_PURE; /** Return non-zero if the volume of all channels is equal to the specified value */ -int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v); +int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) PA_GCC_PURE; /** Return 1 if the specified volume has all channels muted */ #define pa_cvolume_is_muted(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_MUTED) @@ -146,22 +146,22 @@ int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v); #define pa_cvolume_is_norm(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_NORM) /** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. This is only valid for software volumes! */ -pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b); +pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) PA_GCC_CONST; /** Multiply to per-channel volumes and return the result in *dest. This is only valid for software volumes! */ -pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b); +pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) PA_GCC_PURE; /** Convert a decibel value to a volume. This is only valid for software volumes! \since 0.4 */ -pa_volume_t pa_sw_volume_from_dB(double f); +pa_volume_t pa_sw_volume_from_dB(double f) PA_GCC_CONST; /** Convert a volume to a decibel value. This is only valid for software volumes! \since 0.4 */ -double pa_sw_volume_to_dB(pa_volume_t v); +double pa_sw_volume_to_dB(pa_volume_t v) PA_GCC_CONST; /** Convert a linear factor to a volume. This is only valid for software volumes! \since 0.8 */ -pa_volume_t pa_sw_volume_from_linear(double v); +pa_volume_t pa_sw_volume_from_linear(double v) PA_GCC_CONST; /** Convert a volume to a linear factor. This is only valid for software volumes! \since 0.8 */ -double pa_sw_volume_to_linear(pa_volume_t v); +double pa_sw_volume_to_linear(pa_volume_t v) PA_GCC_CONST; #ifdef INFINITY #define PA_DECIBEL_MININFTY (-INFINITY) diff --git a/src/pulse/xmalloc.c b/src/pulse/xmalloc.c index 1f0734c2..5348dda4 100644 --- a/src/pulse/xmalloc.c +++ b/src/pulse/xmalloc.c @@ -27,12 +27,12 @@ #include #include -#include #include #include #include #include +#include #include "xmalloc.h" @@ -60,8 +60,8 @@ static void oom(void) { void* pa_xmalloc(size_t size) { void *p; - assert(size > 0); - assert(size < MAX_ALLOC_SIZE); + pa_assert(size > 0); + pa_assert(size < MAX_ALLOC_SIZE); if (!(p = malloc(size))) oom(); @@ -71,8 +71,8 @@ void* pa_xmalloc(size_t size) { void* pa_xmalloc0(size_t size) { void *p; - assert(size > 0); - assert(size < MAX_ALLOC_SIZE); + pa_assert(size > 0); + pa_assert(size < MAX_ALLOC_SIZE); if (!(p = calloc(1, size))) oom(); @@ -82,8 +82,8 @@ void* pa_xmalloc0(size_t size) { void *pa_xrealloc(void *ptr, size_t size) { void *p; - assert(size > 0); - assert(size < MAX_ALLOC_SIZE); + pa_assert(size > 0); + pa_assert(size < MAX_ALLOC_SIZE); if (!(p = realloc(ptr, size))) oom(); diff --git a/src/pulse/xmalloc.h b/src/pulse/xmalloc.h index 2f6399c5..62a450dc 100644 --- a/src/pulse/xmalloc.h +++ b/src/pulse/xmalloc.h @@ -75,6 +75,15 @@ static inline void* pa_xnew0_internal(unsigned n, size_t k) { /** Same as pa_xnew() but set the memory to zero */ #define pa_xnew0(type, n) ((type*) pa_xnew0_internal((n), sizeof(type))) +/** Internal helper for pa_xnew0() */ +static inline void* pa_xnewdup_internal(const void *p, unsigned n, size_t k) { + assert(n < INT_MAX/k); + return pa_xmemdup(p, n*k); +} + +/** Same as pa_xnew() but set the memory to zero */ +#define pa_xnewdup(type, p, n) ((type*) pa_xnewdup_internal((p), (n), sizeof(type))) + PA_C_DECL_END #endif diff --git a/src/pulsecore/anotify.c b/src/pulsecore/anotify.c deleted file mode 100644 index 25c5fe7d..00000000 --- a/src/pulsecore/anotify.c +++ /dev/null @@ -1,145 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of PulseAudio. - - Copyright 2006 Lennart Poettering - - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with PulseAudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include - -#include "anotify.h" - -#define EVENTS_MAX 16 - -struct pa_anotify { - pa_mainloop_api *api; - pa_anotify_cb_t callback; - void *userdata; - int fds[2]; - pa_io_event *io_event; - pa_defer_event *defer_event; - - uint8_t queued_events[EVENTS_MAX]; - unsigned n_queued_events, queue_index; -}; - -static void dispatch_event(pa_anotify *a) { - assert(a); - assert(a->queue_index < a->n_queued_events); - - a->callback(a->queued_events[a->queue_index++], a->userdata); - - if (a->queue_index >= a->n_queued_events) { - a->n_queued_events = 0; - a->queue_index = 0; - - a->api->io_enable(a->io_event, PA_IO_EVENT_INPUT); - a->api->defer_enable(a->defer_event, 0); - } else { - a->api->io_enable(a->io_event, 0); - a->api->defer_enable(a->defer_event, 1); - } -} - -static void io_callback( - pa_mainloop_api *api, - pa_io_event *e, - int fd, - pa_io_event_flags_t events, - void *userdata) { - - pa_anotify *a = userdata; - ssize_t r; - - assert(a); - assert(events == PA_IO_EVENT_INPUT); - assert(a->n_queued_events == 0); - - r = read(fd, a->queued_events, sizeof(a->queued_events)); - assert(r > 0); - - a->n_queued_events = (unsigned) r; - a->queue_index = 0; - - /* Only dispatch a single event */ - dispatch_event(a); -} - -static void defer_callback(pa_mainloop_api *api, pa_defer_event *e, void *userdata) { - pa_anotify *a = userdata; - assert(a); - - dispatch_event(a); -} - -pa_anotify *pa_anotify_new(pa_mainloop_api*api, pa_anotify_cb_t cb, void *userdata) { - pa_anotify *a; - - assert(api); - assert(cb); - - a = pa_xnew(pa_anotify, 1); - - if (pipe(a->fds) < 0) { - pa_xfree(a); - return NULL; - } - - a->api = api; - a->callback = cb; - a->userdata = userdata; - - a->io_event = api->io_new(api, a->fds[0], PA_IO_EVENT_INPUT, io_callback, a); - a->defer_event = api->defer_new(api, defer_callback, a); - a->api->defer_enable(a->defer_event, 0); - - a->n_queued_events = 0; - - return a; -} - -void pa_anotify_free(pa_anotify *a) { - assert(a); - - a->api->io_free(a->io_event); - a->api->defer_free(a->defer_event); - - if (a->fds[0] >= 0) - close(a->fds[0]); - if (a->fds[1] >= 0) - close(a->fds[1]); - - pa_xfree(a); -} - -int pa_anotify_signal(pa_anotify *a, uint8_t event) { - ssize_t r; - assert(a); - - r = write(a->fds[1], &event, 1); - return r != 1 ? -1 : 0; -} diff --git a/src/pulsecore/anotify.h b/src/pulsecore/anotify.h deleted file mode 100644 index b3f75b7e..00000000 --- a/src/pulsecore/anotify.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef foopulseanotifyhfoo -#define foopulseanotifyhfoo - -/* $Id$ */ - -/*** - This file is part of PulseAudio. - - Copyright 2006 Lennart Poettering - - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with PulseAudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -/* Asynchronous thread-safe notification of mainloops */ - - -#include -#include - -typedef struct pa_anotify pa_anotify; -typedef void (*pa_anotify_cb_t)(uint8_t event, void *userdata); - -pa_anotify *pa_anotify_new(pa_mainloop_api*api, pa_anotify_cb_t cb, void *userdata); -void pa_anotify_free(pa_anotify *a); -int pa_anotify_signal(pa_anotify *a, uint8_t event); - -#endif diff --git a/src/pulsecore/asyncmsgq.c b/src/pulsecore/asyncmsgq.c new file mode 100644 index 00000000..96b43a71 --- /dev/null +++ b/src/pulsecore/asyncmsgq.c @@ -0,0 +1,303 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "asyncmsgq.h" + +PA_STATIC_FLIST_DECLARE(asyncmsgq, 0, pa_xfree); +PA_STATIC_FLIST_DECLARE(semaphores, 0, (void(*)(void*)) pa_semaphore_free); + +struct asyncmsgq_item { + int code; + pa_msgobject *object; + void *userdata; + pa_free_cb_t free_cb; + int64_t offset; + pa_memchunk memchunk; + pa_semaphore *semaphore; + int ret; +}; + +struct pa_asyncmsgq { + PA_REFCNT_DECLARE; + pa_asyncq *asyncq; + pa_mutex *mutex; /* only for the writer side */ + + struct asyncmsgq_item *current; +}; + +pa_asyncmsgq *pa_asyncmsgq_new(unsigned size) { + pa_asyncmsgq *a; + + a = pa_xnew(pa_asyncmsgq, 1); + + PA_REFCNT_INIT(a); + pa_assert_se(a->asyncq = pa_asyncq_new(size)); + pa_assert_se(a->mutex = pa_mutex_new(FALSE, TRUE)); + a->current = NULL; + + return a; +} + +static void asyncmsgq_free(pa_asyncmsgq *a) { + struct asyncmsgq_item *i; + pa_assert(a); + + while ((i = pa_asyncq_pop(a->asyncq, 0))) { + + pa_assert(!i->semaphore); + + if (i->object) + pa_msgobject_unref(i->object); + + if (i->memchunk.memblock) + pa_memblock_unref(i->memchunk.memblock); + + if (i->free_cb) + i->free_cb(i->userdata); + + if (pa_flist_push(PA_STATIC_FLIST_GET(asyncmsgq), i) < 0) + pa_xfree(i); + } + + pa_asyncq_free(a->asyncq, NULL); + pa_mutex_free(a->mutex); + pa_xfree(a); +} + +pa_asyncmsgq* pa_asyncmsgq_ref(pa_asyncmsgq *q) { + pa_assert(PA_REFCNT_VALUE(q) > 0); + + PA_REFCNT_INC(q); + return q; +} + +void pa_asyncmsgq_unref(pa_asyncmsgq* q) { + pa_assert(PA_REFCNT_VALUE(q) > 0); + + if (PA_REFCNT_DEC(q) <= 0) + asyncmsgq_free(q); +} + +void pa_asyncmsgq_post(pa_asyncmsgq *a, pa_msgobject *object, int code, const void *userdata, int64_t offset, const pa_memchunk *chunk, pa_free_cb_t free_cb) { + struct asyncmsgq_item *i; + pa_assert(PA_REFCNT_VALUE(a) > 0); + + if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(asyncmsgq)))) + i = pa_xnew(struct asyncmsgq_item, 1); + + i->code = code; + i->object = object ? pa_msgobject_ref(object) : NULL; + i->userdata = (void*) userdata; + i->free_cb = free_cb; + i->offset = offset; + if (chunk) { + pa_assert(chunk->memblock); + i->memchunk = *chunk; + pa_memblock_ref(i->memchunk.memblock); + } else + pa_memchunk_reset(&i->memchunk); + i->semaphore = NULL; + + /* This mutex makes the queue multiple-writer safe. This lock is only used on the writing side */ + pa_mutex_lock(a->mutex); + pa_assert_se(pa_asyncq_push(a->asyncq, i, 1) == 0); + pa_mutex_unlock(a->mutex); +} + +int pa_asyncmsgq_send(pa_asyncmsgq *a, pa_msgobject *object, int code, const void *userdata, int64_t offset, const pa_memchunk *chunk) { + struct asyncmsgq_item i; + pa_assert(PA_REFCNT_VALUE(a) > 0); + + i.code = code; + i.object = object; + i.userdata = (void*) userdata; + i.free_cb = NULL; + i.ret = -1; + i.offset = offset; + if (chunk) { + pa_assert(chunk->memblock); + i.memchunk = *chunk; + } else + pa_memchunk_reset(&i.memchunk); + + if (!(i.semaphore = pa_flist_pop(PA_STATIC_FLIST_GET(semaphores)))) + i.semaphore = pa_semaphore_new(0); + + pa_assert_se(i.semaphore); + + /* Thus mutex makes the queue multiple-writer safe. This lock is only used on the writing side */ + pa_mutex_lock(a->mutex); + pa_assert_se(pa_asyncq_push(a->asyncq, &i, 1) == 0); + pa_mutex_unlock(a->mutex); + + pa_semaphore_wait(i.semaphore); + + if (pa_flist_push(PA_STATIC_FLIST_GET(semaphores), i.semaphore) < 0) + pa_semaphore_free(i.semaphore); + + return i.ret; +} + +int pa_asyncmsgq_get(pa_asyncmsgq *a, pa_msgobject **object, int *code, void **userdata, int64_t *offset, pa_memchunk *chunk, int wait) { + pa_assert(PA_REFCNT_VALUE(a) > 0); + pa_assert(!a->current); + + if (!(a->current = pa_asyncq_pop(a->asyncq, wait))) { +/* pa_log("failure"); */ + return -1; + } + +/* pa_log("success"); */ + + if (code) + *code = a->current->code; + if (userdata) + *userdata = a->current->userdata; + if (offset) + *offset = a->current->offset; + if (object) { + if ((*object = a->current->object)) + pa_msgobject_assert_ref(*object); + } + if (chunk) + *chunk = a->current->memchunk; + +/* pa_log_debug("Get q=%p object=%p (%s) code=%i data=%p chunk.length=%lu", (void*) a, (void*) a->current->object, a->current->object ? a->current->object->parent.type_name : NULL, a->current->code, (void*) a->current->userdata, (unsigned long) a->current->memchunk.length); */ + + return 0; +} + +void pa_asyncmsgq_done(pa_asyncmsgq *a, int ret) { + pa_assert(PA_REFCNT_VALUE(a) > 0); + pa_assert(a); + pa_assert(a->current); + + if (a->current->semaphore) { + a->current->ret = ret; + pa_semaphore_post(a->current->semaphore); + } else { + + if (a->current->free_cb) + a->current->free_cb(a->current->userdata); + + if (a->current->object) + pa_msgobject_unref(a->current->object); + + if (a->current->memchunk.memblock) + pa_memblock_unref(a->current->memchunk.memblock); + + if (pa_flist_push(PA_STATIC_FLIST_GET(asyncmsgq), a->current) < 0) + pa_xfree(a->current); + } + + a->current = NULL; +} + +int pa_asyncmsgq_wait_for(pa_asyncmsgq *a, int code) { + int c; + pa_assert(PA_REFCNT_VALUE(a) > 0); + + pa_asyncmsgq_ref(a); + + do { + pa_msgobject *o; + void *data; + int64_t offset; + pa_memchunk chunk; + int ret; + + if (pa_asyncmsgq_get(a, &o, &c, &data, &offset, &chunk, 1) < 0) + return -1; + + ret = pa_asyncmsgq_dispatch(o, c, data, offset, &chunk); + pa_asyncmsgq_done(a, ret); + + } while (c != code); + + pa_asyncmsgq_unref(a); + + return 0; +} + +int pa_asyncmsgq_process_one(pa_asyncmsgq *a) { + pa_msgobject *object; + int code; + void *data; + pa_memchunk chunk; + int64_t offset; + int ret; + + pa_assert(PA_REFCNT_VALUE(a) > 0); + + if (pa_asyncmsgq_get(a, &object, &code, &data, &offset, &chunk, 0) < 0) + return 0; + + pa_asyncmsgq_ref(a); + ret = pa_asyncmsgq_dispatch(object, code, data, offset, &chunk); + pa_asyncmsgq_done(a, ret); + pa_asyncmsgq_unref(a); + + return 1; +} + +int pa_asyncmsgq_get_fd(pa_asyncmsgq *a) { + pa_assert(PA_REFCNT_VALUE(a) > 0); + + return pa_asyncq_get_fd(a->asyncq); +} + +int pa_asyncmsgq_before_poll(pa_asyncmsgq *a) { + pa_assert(PA_REFCNT_VALUE(a) > 0); + + return pa_asyncq_before_poll(a->asyncq); +} + +void pa_asyncmsgq_after_poll(pa_asyncmsgq *a) { + pa_assert(PA_REFCNT_VALUE(a) > 0); + + pa_asyncq_after_poll(a->asyncq); +} + +int pa_asyncmsgq_dispatch(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *memchunk) { + + if (object) + return object->process_msg(object, code, userdata, offset, memchunk); + + return 0; +} diff --git a/src/pulsecore/asyncmsgq.h b/src/pulsecore/asyncmsgq.h new file mode 100644 index 00000000..5d3867ba --- /dev/null +++ b/src/pulsecore/asyncmsgq.h @@ -0,0 +1,75 @@ +#ifndef foopulseasyncmsgqhfoo +#define foopulseasyncmsgqhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include +#include + +/* A simple asynchronous message queue, based on pa_asyncq. In + * contrast to pa_asyncq this one is multiple-writer safe, though + * still not multiple-reader safe. This queue is intended to be used + * for controlling real-time threads from normal-priority + * threads. Multiple-writer-safety is accomplished by using a mutex on + * the writer side. This queue is thus not useful for communication + * between several real-time threads. + * + * The queue takes messages consisting of: + * "Object" for which this messages is intended (may be NULL) + * A numeric message code + * Arbitrary userdata pointer (may be NULL) + * A memchunk (may be NULL) + * + * There are two functions for submitting messages: _post and + * _send. The former just enqueues the message asynchronously, the + * latter waits for completion, synchronously. */ + +enum { + PA_MESSAGE_SHUTDOWN = -1/* A generic message to inform the handler of this queue to quit */ +}; + +typedef struct pa_asyncmsgq pa_asyncmsgq; + +pa_asyncmsgq* pa_asyncmsgq_new(unsigned size); +pa_asyncmsgq* pa_asyncmsgq_ref(pa_asyncmsgq *q); +void pa_asyncmsgq_unref(pa_asyncmsgq* q); + +void pa_asyncmsgq_post(pa_asyncmsgq *q, pa_msgobject *object, int code, const void *userdata, int64_t offset, const pa_memchunk *memchunk, pa_free_cb_t userdata_free_cb); +int pa_asyncmsgq_send(pa_asyncmsgq *q, pa_msgobject *object, int code, const void *userdata, int64_t offset, const pa_memchunk *memchunk); + +int pa_asyncmsgq_get(pa_asyncmsgq *q, pa_msgobject **object, int *code, void **userdata, int64_t *offset, pa_memchunk *memchunk, int wait); +int pa_asyncmsgq_dispatch(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *memchunk); +void pa_asyncmsgq_done(pa_asyncmsgq *q, int ret); +int pa_asyncmsgq_wait_for(pa_asyncmsgq *a, int code); +int pa_asyncmsgq_process_one(pa_asyncmsgq *a); + +/* Just for the reading side */ +int pa_asyncmsgq_get_fd(pa_asyncmsgq *q); +int pa_asyncmsgq_before_poll(pa_asyncmsgq *a); +void pa_asyncmsgq_after_poll(pa_asyncmsgq *a); + +#endif diff --git a/src/pulsecore/asyncq.c b/src/pulsecore/asyncq.c new file mode 100644 index 00000000..75b15c0e --- /dev/null +++ b/src/pulsecore/asyncq.c @@ -0,0 +1,213 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "asyncq.h" +#include "fdsem.h" + +#define ASYNCQ_SIZE 128 + +/* For debugging purposes we can define _Y to put and extra thread + * yield between each operation. */ + +/* #define PROFILE */ + +#ifdef PROFILE +#define _Y pa_thread_yield() +#else +#define _Y do { } while(0) +#endif + +struct pa_asyncq { + unsigned size; + unsigned read_idx; + unsigned write_idx; + pa_fdsem *read_fdsem, *write_fdsem; +}; + +#define PA_ASYNCQ_CELLS(x) ((pa_atomic_ptr_t*) ((uint8_t*) (x) + PA_ALIGN(sizeof(struct pa_asyncq)))) + +static int is_power_of_two(unsigned size) { + return !(size & (size - 1)); +} + +static int reduce(pa_asyncq *l, int value) { + return value & (unsigned) (l->size - 1); +} + +pa_asyncq *pa_asyncq_new(unsigned size) { + pa_asyncq *l; + + if (!size) + size = ASYNCQ_SIZE; + + pa_assert(is_power_of_two(size)); + + l = pa_xmalloc0(PA_ALIGN(sizeof(pa_asyncq)) + (sizeof(pa_atomic_ptr_t) * size)); + + l->size = size; + + if (!(l->read_fdsem = pa_fdsem_new())) { + pa_xfree(l); + return NULL; + } + + if (!(l->write_fdsem = pa_fdsem_new())) { + pa_fdsem_free(l->read_fdsem); + pa_xfree(l); + return NULL; + } + + return l; +} + +void pa_asyncq_free(pa_asyncq *l, pa_free_cb_t free_cb) { + pa_assert(l); + + if (free_cb) { + void *p; + + while ((p = pa_asyncq_pop(l, 0))) + free_cb(p); + } + + pa_fdsem_free(l->read_fdsem); + pa_fdsem_free(l->write_fdsem); + pa_xfree(l); +} + +int pa_asyncq_push(pa_asyncq*l, void *p, int wait) { + int idx; + pa_atomic_ptr_t *cells; + + pa_assert(l); + pa_assert(p); + + cells = PA_ASYNCQ_CELLS(l); + + _Y; + idx = reduce(l, l->write_idx); + + if (!pa_atomic_ptr_cmpxchg(&cells[idx], NULL, p)) { + + if (!wait) + return -1; + +/* pa_log("sleeping on push"); */ + + do { + pa_fdsem_wait(l->read_fdsem); + } while (!pa_atomic_ptr_cmpxchg(&cells[idx], NULL, p)); + } + + _Y; + l->write_idx++; + + pa_fdsem_post(l->write_fdsem); + + return 0; +} + +void* pa_asyncq_pop(pa_asyncq*l, int wait) { + int idx; + void *ret; + pa_atomic_ptr_t *cells; + + pa_assert(l); + + cells = PA_ASYNCQ_CELLS(l); + + _Y; + idx = reduce(l, l->read_idx); + + if (!(ret = pa_atomic_ptr_load(&cells[idx]))) { + + if (!wait) + return NULL; + +/* pa_log("sleeping on pop"); */ + + do { + pa_fdsem_wait(l->write_fdsem); + } while (!(ret = pa_atomic_ptr_load(&cells[idx]))); + } + + pa_assert(ret); + + /* Guaranteed to succeed if we only have a single reader */ + pa_assert_se(pa_atomic_ptr_cmpxchg(&cells[idx], ret, NULL)); + + _Y; + l->read_idx++; + + pa_fdsem_post(l->read_fdsem); + + return ret; +} + +int pa_asyncq_get_fd(pa_asyncq *q) { + pa_assert(q); + + return pa_fdsem_get(q->write_fdsem); +} + +int pa_asyncq_before_poll(pa_asyncq *l) { + int idx; + pa_atomic_ptr_t *cells; + + pa_assert(l); + + cells = PA_ASYNCQ_CELLS(l); + + _Y; + idx = reduce(l, l->read_idx); + + for (;;) { + if (pa_atomic_ptr_load(&cells[idx])) + return -1; + + if (pa_fdsem_before_poll(l->write_fdsem) >= 0) + return 0; + } + + return 0; +} + +void pa_asyncq_after_poll(pa_asyncq *l) { + pa_assert(l); + + pa_fdsem_after_poll(l->write_fdsem); +} diff --git a/src/pulsecore/asyncq.h b/src/pulsecore/asyncq.h new file mode 100644 index 00000000..53d45866 --- /dev/null +++ b/src/pulsecore/asyncq.h @@ -0,0 +1,56 @@ +#ifndef foopulseasyncqhfoo +#define foopulseasyncqhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/* A simple, asynchronous, lock-free (if requested also wait-free) + * queue. Not multiple-reader/multiple-writer safe. If that is + * required both sides can be protected by a mutex each. --- Which is + * not a bad thing in most cases, since this queue is intended for + * communication between a normal thread and a single real-time + * thread. Only the real-time side needs to be lock-free/wait-free. + * + * If the queue is full and another entry shall be pushed, or when the + * queue is empty and another entry shall be popped and the "wait" + * argument is non-zero, the queue will block on a UNIX FIFO object -- + * that will probably require locking on the kernel side -- which + * however is probably not problematic, because we do it only on + * starvation or overload in which case we have to block anyway. */ + +typedef struct pa_asyncq pa_asyncq; + +pa_asyncq* pa_asyncq_new(unsigned size); +void pa_asyncq_free(pa_asyncq* q, pa_free_cb_t free_cb); + +void* pa_asyncq_pop(pa_asyncq *q, int wait); +int pa_asyncq_push(pa_asyncq *q, void *p, int wait); + +int pa_asyncq_get_fd(pa_asyncq *q); +int pa_asyncq_before_poll(pa_asyncq *a); +void pa_asyncq_after_poll(pa_asyncq *a); + +#endif diff --git a/src/pulsecore/atomic.h b/src/pulsecore/atomic.h index 013e8c20..c2c99888 100644 --- a/src/pulsecore/atomic.h +++ b/src/pulsecore/atomic.h @@ -24,48 +24,201 @@ USA. ***/ -#include - -/* atomic_ops guarantees us that sizeof(AO_t) == sizeof(void*). +/* + * atomic_ops guarantees us that sizeof(AO_t) == sizeof(void*). It is + * not guaranteed however, that sizeof(AO_t) == sizeof(size_t). + * however very likely. + * + * For now we do only full memory barriers. Eventually we might want + * to support more elaborate memory barriers, in which case we will add + * suffixes to the function names. * - * It is not guaranteed however, that sizeof(AO_t) == sizeof(size_t). - * however very likely. */ + * On gcc >= 4.1 we use the builtin atomic functions. otherwise we use + * libatomic_ops + */ -typedef struct pa_atomic_int { - volatile AO_t value; -} pa_atomic_int_t; +#ifndef PACKAGE +#error "Please include config.h before including this file!" +#endif + +#ifdef HAVE_ATOMIC_BUILTINS + +/* __sync based implementation */ + +typedef struct pa_atomic { + volatile int value; +} pa_atomic_t; #define PA_ATOMIC_INIT(v) { .value = (v) } -/* For now we do only full memory barriers. Eventually we might want - * to support more elaborate memory barriers, in which case we will add - * suffixes to the function names */ +static inline int pa_atomic_load(const pa_atomic_t *a) { + __sync_synchronize(); + return a->value; +} + +static inline void pa_atomic_store(pa_atomic_t *a, int i) { + a->value = i; + __sync_synchronize(); +} + +/* Returns the previously set value */ +static inline int pa_atomic_add(pa_atomic_t *a, int i) { + return __sync_fetch_and_add(&a->value, i); +} + +/* Returns the previously set value */ +static inline int pa_atomic_sub(pa_atomic_t *a, int i) { + return __sync_fetch_and_sub(&a->value, i); +} + +/* Returns the previously set value */ +static inline int pa_atomic_inc(pa_atomic_t *a) { + return pa_atomic_add(a, 1); +} + +/* Returns the previously set value */ +static inline int pa_atomic_dec(pa_atomic_t *a) { + return pa_atomic_sub(a, 1); +} + +/* Returns non-zero when the operation was successful. */ +static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) { + return __sync_bool_compare_and_swap(&a->value, old_i, new_i); +} + +typedef struct pa_atomic_ptr { + volatile unsigned long value; +} pa_atomic_ptr_t; + +#define PA_ATOMIC_PTR_INIT(v) { .value = (long) (v) } + +static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) { + __sync_synchronize(); + return (void*) a->value; +} + +static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) { + a->value = (unsigned long) p; + __sync_synchronize(); +} + +static inline int pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) { + return __sync_bool_compare_and_swap(&a->value, (long) old_p, (long) new_p); +} + +#elif defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__)) + +#error "The native atomic operations implementation for AMD64 has not been tested. libatomic_ops is known to not work properly on AMD64 and your gcc version is too old for the gcc-builtin atomic ops support. You have three options now: make the native atomic operations implementation for AMD64 work, fix libatomic_ops, or upgrade your GCC." + +/* Addapted from glibc */ + +typedef struct pa_atomic { + volatile int value; +} pa_atomic_t; + +#define PA_ATOMIC_INIT(v) { .value = (v) } + +static inline int pa_atomic_load(const pa_atomic_t *a) { + return a->value; +} + +static inline void pa_atomic_store(pa_atomic_t *a, int i) { + a->value = i; +} + +static inline int pa_atomic_add(pa_atomic_t *a, int i) { + int result; + + __asm __volatile ("lock; xaddl %0, %1" + : "=r" (result), "=m" (a->value) + : "0" (i), "m" (a->value)); + + return result; +} + +static inline int pa_atomic_sub(pa_atomic_t *a, int i) { + return pa_atomic_add(a, -i); +} + +static inline int pa_atomic_inc(pa_atomic_t *a) { + return pa_atomic_add(a, 1); +} -static inline int pa_atomic_load(const pa_atomic_int_t *a) { +static inline int pa_atomic_dec(pa_atomic_t *a) { + return pa_atomic_sub(a, 1); +} + +static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) { + int result; + + __asm__ __volatile__ ("lock; cmpxchgl %2, %1" + : "=a" (result), "=m" (a->value) + : "r" (new_i), "m" (a->value), "0" (old_i)); + + return result == oldval; +} + +typedef struct pa_atomic_ptr { + volatile unsigned long value; +} pa_atomic_ptr_t; + +#define PA_ATOMIC_PTR_INIT(v) { .value = (long) (v) } + +static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) { + return (void*) a->value; +} + +static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) { + a->value = (unsigned long) p; +} + +static inline int pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) { + void *result; + + __asm__ __volatile__ ("lock; cmpxchgq %q2, %1" + : "=a" (result), "=m" (a->value) + : "r" (new_p), "m" (a->value), "0" (old_p)); + + return result; +} + +#else + +/* libatomic_ops based implementation */ + +#include + +typedef struct pa_atomic { + volatile AO_t value; +} pa_atomic_t; + +#define PA_ATOMIC_INIT(v) { .value = (v) } + +static inline int pa_atomic_load(const pa_atomic_t *a) { return (int) AO_load_full((AO_t*) &a->value); } -static inline void pa_atomic_store(pa_atomic_int_t *a, int i) { +static inline void pa_atomic_store(pa_atomic_t *a, int i) { AO_store_full(&a->value, (AO_t) i); } -static inline int pa_atomic_add(pa_atomic_int_t *a, int i) { +static inline int pa_atomic_add(pa_atomic_t *a, int i) { return AO_fetch_and_add_full(&a->value, (AO_t) i); } -static inline int pa_atomic_sub(pa_atomic_int_t *a, int i) { +static inline int pa_atomic_sub(pa_atomic_t *a, int i) { return AO_fetch_and_add_full(&a->value, (AO_t) -i); } -static inline int pa_atomic_inc(pa_atomic_int_t *a) { +static inline int pa_atomic_inc(pa_atomic_t *a) { return AO_fetch_and_add1_full(&a->value); } -static inline int pa_atomic_dec(pa_atomic_int_t *a) { +static inline int pa_atomic_dec(pa_atomic_t *a) { return AO_fetch_and_sub1_full(&a->value); } -static inline int pa_atomic_cmpxchg(pa_atomic_int_t *a, int old_i, int new_i) { +static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) { return AO_compare_and_swap_full(&a->value, old_i, new_i); } @@ -73,6 +226,8 @@ typedef struct pa_atomic_ptr { volatile AO_t value; } pa_atomic_ptr_t; +#define PA_ATOMIC_PTR_INIT(v) { .value = (AO_t) (v) } + static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) { return (void*) AO_load_full((AO_t*) &a->value); } @@ -86,3 +241,5 @@ static inline int pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* n } #endif + +#endif diff --git a/src/pulsecore/authkey-prop.c b/src/pulsecore/authkey-prop.c index 3b8304b2..54154500 100644 --- a/src/pulsecore/authkey-prop.c +++ b/src/pulsecore/authkey-prop.c @@ -21,44 +21,56 @@ USA. ***/ -#include +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include +#include #include +#include #include "authkey-prop.h" struct authkey_data { - int ref; + PA_REFCNT_DECLARE; size_t length; }; int pa_authkey_prop_get(pa_core *c, const char *name, void *data, size_t len) { struct authkey_data *a; - assert(c && name && data && len > 0); + + pa_assert(c); + pa_assert(name); + pa_assert(data); + pa_assert(len > 0); if (!(a = pa_property_get(c, name))) return -1; - assert(a->length == len); - memcpy(data, a+1, len); + pa_assert(a->length == len); + memcpy(data, (uint8_t*) a + PA_ALIGN(sizeof(struct authkey_data)), len); + return 0; } int pa_authkey_prop_put(pa_core *c, const char *name, const void *data, size_t len) { struct authkey_data *a; - assert(c && name); + + pa_assert(c); + pa_assert(name); if (pa_property_get(c, name)) return -1; - a = pa_xmalloc(sizeof(struct authkey_data) + len); - a->ref = 1; + a = pa_xmalloc(PA_ALIGN(sizeof(struct authkey_data)) + len); + PA_REFCNT_INIT(a); a->length = len; - memcpy(a+1, data, len); + memcpy((uint8_t*) a + PA_ALIGN(sizeof(struct authkey_data)), data, len); pa_property_set(c, name, a); @@ -67,22 +79,27 @@ int pa_authkey_prop_put(pa_core *c, const char *name, const void *data, size_t l void pa_authkey_prop_ref(pa_core *c, const char *name) { struct authkey_data *a; - assert(c && name); - a = pa_property_get(c, name); - assert(a && a->ref >= 1); + pa_assert(c); + pa_assert(name); - a->ref++; + a = pa_property_get(c, name); + pa_assert(a); + pa_assert(PA_REFCNT_VALUE(a) >= 1); + PA_REFCNT_INC(a); } void pa_authkey_prop_unref(pa_core *c, const char *name) { struct authkey_data *a; - assert(c && name); + + pa_assert(c); + pa_assert(name); a = pa_property_get(c, name); - assert(a && a->ref >= 1); + pa_assert(a); + pa_assert(PA_REFCNT_VALUE(a) >= 1); - if (!(--a->ref)) { + if (PA_REFCNT_DEC(a) <= 0) { pa_property_remove(c, name); pa_xfree(a); } diff --git a/src/pulsecore/authkey.c b/src/pulsecore/authkey.c index a6150d0e..80bc8576 100644 --- a/src/pulsecore/authkey.c +++ b/src/pulsecore/authkey.c @@ -26,7 +26,6 @@ #include #endif -#include #include #include #include @@ -43,21 +42,25 @@ #include #include #include +#include #include "authkey.h" /* Generate a new authorization key, store it in file fd and return it in *data */ static int generate(int fd, void *ret_data, size_t length) { ssize_t r; - assert(fd >= 0 && ret_data && length); + + pa_assert(fd >= 0); + pa_assert(ret_data); + pa_assert(length > 0); pa_random(ret_data, length); lseek(fd, 0, SEEK_SET); - ftruncate(fd, 0); + (void) ftruncate(fd, 0); if ((r = pa_loop_write(fd, ret_data, length, NULL)) < 0 || (size_t) r != length) { - pa_log("failed to write cookie file: %s", pa_cstrerror(errno)); + pa_log("Failed to write cookie file: %s", pa_cstrerror(errno)); return -1; } @@ -68,6 +71,10 @@ static int generate(int fd, void *ret_data, size_t length) { #define O_BINARY 0 #endif +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + /* Load an euthorization cookie from file fn and store it in data. If * the cookie file doesn't exist, create it */ static int load(const char *fn, void *data, size_t length) { @@ -75,11 +82,15 @@ static int load(const char *fn, void *data, size_t length) { int writable = 1; int unlock = 0, ret = -1; ssize_t r; - assert(fn && data && length); - if ((fd = open(fn, O_RDWR|O_CREAT|O_BINARY, S_IRUSR|S_IWUSR)) < 0) { - if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY)) < 0) { - pa_log("failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); + pa_assert(fn); + pa_assert(data); + pa_assert(length > 0); + + if ((fd = open(fn, O_RDWR|O_CREAT|O_BINARY|O_NOCTTY, S_IRUSR|S_IWUSR)) < 0) { + + if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY|O_NOCTTY)) < 0) { + pa_log("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } else writable = 0; @@ -88,15 +99,15 @@ static int load(const char *fn, void *data, size_t length) { unlock = pa_lock_fd(fd, 1) >= 0; if ((r = pa_loop_read(fd, data, length, NULL)) < 0) { - pa_log("failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); + pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } if ((size_t) r != length) { - pa_log_debug("got %d bytes from cookie file '%s', expected %d", (int)r, fn, (int)length); + pa_log_debug("Got %d bytes from cookie file '%s', expected %d", (int) r, fn, (int) length); if (!writable) { - pa_log("unable to write cookie to read only file"); + pa_log("Unable to write cookie to read only file"); goto finish; } @@ -113,7 +124,10 @@ finish: if (unlock) pa_lock_fd(fd, 0); - close(fd); + if (pa_close(fd) < 0) { + pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno)); + ret = -1; + } } return ret; @@ -123,13 +137,12 @@ finish: int pa_authkey_load(const char *path, void *data, size_t length) { int ret; - assert(path && data && length); + pa_assert(path); + pa_assert(data); + pa_assert(length > 0); - ret = load(path, data, length); - - if (ret < 0) - pa_log("Failed to load authorization key '%s': %s", path, - (ret == -1) ? pa_cstrerror(errno) : "file corrupt"); + if ((ret = load(path, data, length)) < 0) + pa_log("Failed to load authorization key '%s': %s", path, (ret < 0) ? pa_cstrerror(errno) : "File corrupt"); return ret; } @@ -137,7 +150,10 @@ int pa_authkey_load(const char *path, void *data, size_t length) { /* If the specified file path starts with / return it, otherwise * return path prepended with home directory */ static const char *normalize_path(const char *fn, char *s, size_t l) { - assert(fn && s && l > 0); + + pa_assert(fn); + pa_assert(s); + pa_assert(l > 0); #ifndef OS_IS_WIN32 if (fn[0] != '/') { @@ -145,13 +161,14 @@ static const char *normalize_path(const char *fn, char *s, size_t l) { if (strlen(fn) < 3 || !isalpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') { #endif char homedir[PATH_MAX]; + if (!pa_get_home_dir(homedir, sizeof(homedir))) return NULL; #ifndef OS_IS_WIN32 - snprintf(s, l, "%s/%s", homedir, fn); + pa_snprintf(s, l, "%s/%s", homedir, fn); #else - snprintf(s, l, "%s\\%s", homedir, fn); + pa_snprintf(s, l, "%s\\%s", homedir, fn); #endif return s; } @@ -164,7 +181,10 @@ static const char *normalize_path(const char *fn, char *s, size_t l) { int pa_authkey_load_auto(const char *fn, void *data, size_t length) { char path[PATH_MAX]; const char *p; - assert(fn && data && length); + + pa_assert(fn); + pa_assert(data); + pa_assert(length > 0); if (!(p = normalize_path(fn, path, sizeof(path)))) return -2; @@ -179,20 +199,23 @@ int pa_authkey_save(const char *fn, const void *data, size_t length) { ssize_t r; char path[PATH_MAX]; const char *p; - assert(fn && data && length); + + pa_assert(fn); + pa_assert(data); + pa_assert(length > 0); if (!(p = normalize_path(fn, path, sizeof(path)))) return -2; - if ((fd = open(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { - pa_log("failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); + if ((fd = open(p, O_RDWR|O_CREAT|O_NOCTTY, S_IRUSR|S_IWUSR)) < 0) { + pa_log("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } unlock = pa_lock_fd(fd, 1) >= 0; if ((r = pa_loop_write(fd, data, length, NULL)) < 0 || (size_t) r != length) { - pa_log("failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); + pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } @@ -205,7 +228,10 @@ finish: if (unlock) pa_lock_fd(fd, 0); - close(fd); + if (pa_close(fd) < 0) { + pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno)); + ret = -1; + } } return ret; diff --git a/src/pulsecore/autoload.c b/src/pulsecore/autoload.c index 6f888526..a1d3e02d 100644 --- a/src/pulsecore/autoload.c +++ b/src/pulsecore/autoload.c @@ -26,7 +26,6 @@ #include #endif -#include #include #include @@ -36,13 +35,14 @@ #include #include #include +#include #include #include #include "autoload.h" static void entry_free(pa_autoload_entry *e) { - assert(e); + pa_assert(e); pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_AUTOLOAD|PA_SUBSCRIPTION_EVENT_REMOVE, PA_INVALID_INDEX); pa_xfree(e->name); pa_xfree(e->module); @@ -51,7 +51,8 @@ static void entry_free(pa_autoload_entry *e) { } static void entry_remove_and_free(pa_autoload_entry *e) { - assert(e && e->core); + pa_assert(e); + pa_assert(e->core); pa_idxset_remove_by_data(e->core->autoload_idxset, e, NULL); pa_hashmap_remove(e->core->autoload_hashmap, e->name); @@ -60,12 +61,14 @@ static void entry_remove_and_free(pa_autoload_entry *e) { static pa_autoload_entry* entry_new(pa_core *c, const char *name) { pa_autoload_entry *e = NULL; - assert(c && name); + + pa_core_assert_ref(c); + pa_assert(name); if (c->autoload_hashmap && (e = pa_hashmap_get(c->autoload_hashmap, name))) return NULL; - e = pa_xmalloc(sizeof(pa_autoload_entry)); + e = pa_xnew(pa_autoload_entry, 1); e->core = c; e->name = pa_xstrdup(name); e->module = e->argument = NULL; @@ -73,7 +76,7 @@ static pa_autoload_entry* entry_new(pa_core *c, const char *name) { if (!c->autoload_hashmap) c->autoload_hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - assert(c->autoload_hashmap); + pa_assert(c->autoload_hashmap); pa_hashmap_put(c->autoload_hashmap, e->name, e); @@ -88,7 +91,11 @@ static pa_autoload_entry* entry_new(pa_core *c, const char *name) { int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const char*module, const char *argument, uint32_t *idx) { pa_autoload_entry *e = NULL; - assert(c && name && module && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); + + pa_assert(c); + pa_assert(name); + pa_assert(module); + pa_assert(type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE); if (!(e = entry_new(c, name))) return -1; @@ -105,7 +112,10 @@ int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const c int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type_t type) { pa_autoload_entry *e; - assert(c && name && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); + + pa_assert(c); + pa_assert(name); + pa_assert(type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE); if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type) return -1; @@ -116,7 +126,9 @@ int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type_t ty int pa_autoload_remove_by_index(pa_core *c, uint32_t idx) { pa_autoload_entry *e; - assert(c && idx != PA_IDXSET_INVALID); + + pa_assert(c); + pa_assert(idx != PA_IDXSET_INVALID); if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, idx))) return -1; @@ -128,7 +140,9 @@ int pa_autoload_remove_by_index(pa_core *c, uint32_t idx) { void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type_t type) { pa_autoload_entry *e; pa_module *m; - assert(c && name); + + pa_assert(c); + pa_assert(name); if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || (e->type != type)) return; @@ -153,6 +167,7 @@ static void free_func(void *p, PA_GCC_UNUSED void *userdata) { } void pa_autoload_free(pa_core *c) { + if (c->autoload_hashmap) { pa_hashmap_free(c->autoload_hashmap, free_func, NULL); c->autoload_hashmap = NULL; @@ -166,7 +181,9 @@ void pa_autoload_free(pa_core *c) { const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type_t type) { pa_autoload_entry *e; - assert(c && name); + + pa_core_assert_ref(c); + pa_assert(name); if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type) return NULL; @@ -176,7 +193,9 @@ const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa const pa_autoload_entry* pa_autoload_get_by_index(pa_core *c, uint32_t idx) { pa_autoload_entry *e; - assert(c && idx != PA_IDXSET_INVALID); + + pa_core_assert_ref(c); + pa_assert(idx != PA_IDXSET_INVALID); if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, idx))) return NULL; diff --git a/src/pulsecore/avahi-wrap.c b/src/pulsecore/avahi-wrap.c index 855ed567..fae54810 100644 --- a/src/pulsecore/avahi-wrap.c +++ b/src/pulsecore/avahi-wrap.c @@ -21,11 +21,14 @@ USA. ***/ -#include +#ifdef HAVE_CONFIG_H +#include +#endif #include #include +#include #include "avahi-wrap.h" @@ -61,9 +64,9 @@ static pa_io_event_flags_t translate_io_flags(AvahiWatchEvent e) { static void watch_callback(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) { AvahiWatch *w = userdata; - assert(a); - assert(e); - assert(w); + pa_assert(a); + pa_assert(e); + pa_assert(w); w->current_event = translate_io_flags_back(events); w->callback(w, fd, w->current_event, w->userdata); @@ -74,12 +77,10 @@ static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event pa_avahi_poll *p; AvahiWatch *w; - assert(api); - assert(fd >= 0); - assert(callback); - - p = api->userdata; - assert(p); + pa_assert(api); + pa_assert(fd >= 0); + pa_assert(callback); + pa_assert_se(p = api->userdata); w = pa_xnew(AvahiWatch, 1); w->avahi_poll = p; @@ -92,19 +93,19 @@ static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event } static void watch_update(AvahiWatch *w, AvahiWatchEvent event) { - assert(w); + pa_assert(w); w->avahi_poll->mainloop->io_enable(w->io_event, translate_io_flags(event)); } static AvahiWatchEvent watch_get_events(AvahiWatch *w) { - assert(w); + pa_assert(w); return w->current_event; } static void watch_free(AvahiWatch *w) { - assert(w); + pa_assert(w); w->avahi_poll->mainloop->io_free(w->io_event); pa_xfree(w); @@ -120,9 +121,9 @@ struct AvahiTimeout { static void timeout_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata) { AvahiTimeout *t = userdata; - assert(a); - assert(e); - assert(t); + pa_assert(a); + pa_assert(e); + pa_assert(t); t->callback(t, t->userdata); } @@ -131,11 +132,9 @@ static AvahiTimeout* timeout_new(const AvahiPoll *api, const struct timeval *tv, pa_avahi_poll *p; AvahiTimeout *t; - assert(api); - assert(callback); - - p = api->userdata; - assert(p); + pa_assert(api); + pa_assert(callback); + pa_assert_se(p = api->userdata); t = pa_xnew(AvahiTimeout, 1); t->avahi_poll = p; @@ -148,7 +147,7 @@ static AvahiTimeout* timeout_new(const AvahiPoll *api, const struct timeval *tv, } static void timeout_update(AvahiTimeout *t, const struct timeval *tv) { - assert(t); + pa_assert(t); if (t->time_event && tv) t->avahi_poll->mainloop->time_restart(t->time_event, tv); @@ -161,7 +160,7 @@ static void timeout_update(AvahiTimeout *t, const struct timeval *tv) { } static void timeout_free(AvahiTimeout *t) { - assert(t); + pa_assert(t); if (t->time_event) t->avahi_poll->mainloop->time_free(t->time_event); @@ -171,7 +170,7 @@ static void timeout_free(AvahiTimeout *t) { AvahiPoll* pa_avahi_poll_new(pa_mainloop_api *m) { pa_avahi_poll *p; - assert(m); + pa_assert(m); p = pa_xnew(pa_avahi_poll, 1); @@ -190,9 +189,8 @@ AvahiPoll* pa_avahi_poll_new(pa_mainloop_api *m) { void pa_avahi_poll_free(AvahiPoll *api) { pa_avahi_poll *p; - assert(api); - p = api->userdata; - assert(p); + pa_assert(api); + pa_assert_se(p = api->userdata); pa_xfree(p); } diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index 6989069d..539fd34d 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -28,7 +28,6 @@ #include #include -#include #include #include #include @@ -95,6 +94,7 @@ static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strb static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); @@ -114,6 +114,9 @@ static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); /* A method table for all available commands */ @@ -130,13 +133,14 @@ static const struct command commands[] = { { "info", pa_cli_command_info, "Show comprehensive status", 1 }, { "ls", pa_cli_command_info, NULL, 1 }, { "list", pa_cli_command_info, NULL, 1 }, - { "load-module", pa_cli_command_load, "Load a module (args: name, arguments)", 3}, - { "unload-module", pa_cli_command_unload, "Unload a module (args: index)", 2}, - { "set-sink-volume", pa_cli_command_sink_volume, "Set the volume of a sink (args: index|name, volume)", 3}, - { "set-sink-input-volume", pa_cli_command_sink_input_volume, "Set the volume of a sink input (args: index|name, volume)", 3}, + { "load-module", pa_cli_command_load, "Load a module (args: name, arguments)", 3}, + { "unload-module", pa_cli_command_unload, "Unload a module (args: index)", 2}, + { "set-sink-volume", pa_cli_command_sink_volume, "Set the volume of a sink (args: index|name, volume)", 3}, + { "set-sink-input-volume", pa_cli_command_sink_input_volume, "Set the volume of a sink input (args: index, volume)", 3}, { "set-source-volume", pa_cli_command_source_volume, "Set the volume of a source (args: index|name, volume)", 3}, - { "set-sink-mute", pa_cli_command_sink_mute, "Set the mute switch of a sink (args: index|name, mute)", 3}, - { "set-source-mute", pa_cli_command_source_mute, "Set the mute switch of a source (args: index|name, mute)", 3}, + { "set-sink-mute", pa_cli_command_sink_mute, "Set the mute switch of a sink (args: index|name, bool)", 3}, + { "set-sink-input-mute", pa_cli_command_sink_input_mute, "Set the mute switch of a sink input (args: index, bool)", 3}, + { "set-source-mute", pa_cli_command_source_mute, "Set the mute switch of a source (args: index|name, bool)", 3}, { "set-default-sink", pa_cli_command_sink_default, "Set the default sink (args: index|name)", 2}, { "set-default-source", 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}, @@ -159,6 +163,9 @@ static const struct command commands[] = { { "move-sink-input", pa_cli_command_move_sink_input, "Move sink input to another sink (args: index, sink)", 3}, { "move-source-output", pa_cli_command_move_source_output, "Move source output to another source (args: index, source)", 3}, { "vacuum", pa_cli_command_vacuum, NULL, 1}, + { "suspend-sink", pa_cli_command_suspend_sink, "Suspend sink (args: index|name, bool)", 3}, + { "suspend-source", pa_cli_command_suspend_source, "Suspend source (args: index|name, bool)", 3}, + { "suspend", pa_cli_command_suspend, "Suspend all sinks and all sources (args: bool)", 2}, { NULL, NULL, NULL, 0 } }; @@ -174,15 +181,23 @@ static uint32_t parse_index(const char *n) { return idx; } -static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, PA_GCC_UNUSED pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - assert(c && c->mainloop && t); +static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + c->mainloop->quit(c->mainloop, 0); return 0; } -static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const struct command*command; - assert(c && t && buf); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); pa_strbuf_puts(buf, "Available commands:\n"); @@ -192,67 +207,91 @@ static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G return 0; } -static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { char *s; - assert(c && t); - s = pa_module_list_to_string(c); - assert(s); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + + pa_assert_se(s = pa_module_list_to_string(c)); pa_strbuf_puts(buf, s); pa_xfree(s); return 0; } -static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { char *s; - assert(c && t); - s = pa_client_list_to_string(c); - assert(s); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + + pa_assert_se(s = pa_client_list_to_string(c)); pa_strbuf_puts(buf, s); pa_xfree(s); return 0; } -static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { char *s; - assert(c && t); - s = pa_sink_list_to_string(c); - assert(s); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + + pa_assert_se(s = pa_sink_list_to_string(c)); pa_strbuf_puts(buf, s); pa_xfree(s); return 0; } -static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { char *s; - assert(c && t); - s = pa_source_list_to_string(c); - assert(s); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + + pa_assert_se(s = pa_source_list_to_string(c)); pa_strbuf_puts(buf, s); pa_xfree(s); return 0; } -static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { char *s; - assert(c && t); - s = pa_sink_input_list_to_string(c); - assert(s); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + + pa_assert_se(s = pa_sink_input_list_to_string(c)); pa_strbuf_puts(buf, s); pa_xfree(s); return 0; } -static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { char *s; - assert(c && t); - s = pa_source_output_list_to_string(c); - assert(s); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + + pa_assert_se(s = pa_source_output_list_to_string(c)); pa_strbuf_puts(buf, s); pa_xfree(s); return 0; } -static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { char s[256]; const pa_mempool_stat *stat; unsigned k; @@ -267,8 +306,10 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G [PA_MEMBLOCK_IMPORTED] = "IMPORTED", }; - assert(c); - assert(t); + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); stat = pa_mempool_get_stat(c->mempool); @@ -312,7 +353,11 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G } static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { - assert(c && t); + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + pa_cli_command_stat(c, t, buf, fail); pa_cli_command_modules(c, t, buf, fail); pa_cli_command_sinks(c, t, buf, fail); @@ -325,10 +370,14 @@ static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int return 0; } -static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { pa_module *m; const char *name; - assert(c && t); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); if (!(name = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify the module name and optionally arguments.\n"); @@ -343,12 +392,16 @@ static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G return 0; } -static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { pa_module *m; uint32_t idx; const char *i; char *e; - assert(c && t); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); if (!(i = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify the module index.\n"); @@ -365,12 +418,17 @@ static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA return 0; } -static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *n, *v; pa_sink *sink; uint32_t volume; pa_cvolume cvolume; + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + 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; @@ -392,17 +450,22 @@ static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *bu } pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume); - pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &cvolume); + pa_sink_set_volume(sink, &cvolume); return 0; } -static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *n, *v; pa_sink_input *si; pa_volume_t volume; pa_cvolume cvolume; uint32_t idx; + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + if (!(n = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n"); return -1; @@ -433,12 +496,17 @@ static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strb return 0; } -static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *n, *v; pa_source *source; uint32_t volume; pa_cvolume cvolume; + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + 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; @@ -460,15 +528,20 @@ static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf * } pa_cvolume_set(&cvolume, source->sample_spec.channels, volume); - pa_source_set_volume(source, PA_MIXER_HARDWARE, &cvolume); + pa_source_set_volume(source, &cvolume); return 0; } -static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *n, *m; pa_sink *sink; int mute; + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + 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; @@ -489,15 +562,20 @@ static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, return -1; } - pa_sink_set_mute(sink, PA_MIXER_HARDWARE, mute); + pa_sink_set_mute(sink, mute); return 0; } -static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *n, *m; pa_source *source; int mute; + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + 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; @@ -518,13 +596,57 @@ static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *bu return -1; } - pa_source_set_mute(source, PA_MIXER_HARDWARE, mute); + pa_source_set_mute(source, mute); return 0; } -static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *n, *v; + pa_sink_input *si; + uint32_t idx; + int mute; + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + + 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 ((idx = 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; + } + + if (pa_atoi(v, &mute) < 0) { + pa_strbuf_puts(buf, "Failed to parse mute switch.\n"); + return -1; + } + + if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) { + pa_strbuf_puts(buf, "No sink input found with this index.\n"); + return -1; + } + + pa_sink_input_set_mute(si, mute); + return 0; +} + +static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *n; - assert(c && t); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); 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"); @@ -535,9 +657,13 @@ static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *b return 0; } -static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *n; - assert(c && t); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); 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"); @@ -548,11 +674,15 @@ static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf return 0; } -static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *n; pa_client *client; uint32_t idx; - assert(c && t); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); if (!(n = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify a client by its index.\n"); @@ -573,11 +703,15 @@ static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *bu return 0; } -static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *n; pa_sink_input *sink_input; uint32_t idx; - assert(c && t); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); if (!(n = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n"); @@ -598,11 +732,15 @@ static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf return 0; } -static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *n; pa_source_output *source_output; uint32_t idx; - assert(c && t); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); if (!(n = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify a source output by its index.\n"); @@ -623,20 +761,29 @@ static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_str return 0; } -static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { char *s; - assert(c && t); - s = pa_scache_list_to_string(c); - assert(s); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + + pa_assert_se(s = pa_scache_list_to_string(c)); pa_strbuf_puts(buf, s); pa_xfree(s); + return 0; } static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *n, *sink_name; pa_sink *sink; - assert(c && t && buf && fail); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); if (!(n = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) { pa_strbuf_puts(buf, "You need to specify a sample name and a sink name.\n"); @@ -658,7 +805,11 @@ static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *bu static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *n; - assert(c && t && buf && fail); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); if (!(n = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify a sample name.\n"); @@ -676,7 +827,11 @@ static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf * static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *fname, *n; int r; - assert(c && t && buf && fail); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); if (!(fname = pa_tokenizer_get(t, 2)) || !(n = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify a file name and a sample name.\n"); @@ -696,7 +851,11 @@ static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *bu static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *pname; - assert(c && t && buf && fail); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); if (!(pname = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify a path name.\n"); @@ -714,7 +873,11 @@ static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *fname, *sink_name; pa_sink *sink; - assert(c && t && buf && fail); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) { pa_strbuf_puts(buf, "You need to specify a file name and a sink name.\n"); @@ -732,7 +895,11 @@ static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *a, *b; - assert(c && t && buf && fail); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); if (!(a = pa_tokenizer_get(t, 1)) || !(b = pa_tokenizer_get(t, 2))) { pa_strbuf_puts(buf, "You need to specify a device name, a filename or a module name and optionally module arguments\n"); @@ -746,7 +913,11 @@ static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *b static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { const char *name; - assert(c && t && buf && fail); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); if (!(name = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify a device name\n"); @@ -761,25 +932,36 @@ static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf return 0; } -static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { char *s; - assert(c && t); - s = pa_autoload_list_to_string(c); - assert(s); + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + + pa_assert_se(s = pa_autoload_list_to_string(c)); pa_strbuf_puts(buf, s); pa_xfree(s); + return 0; } -static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { - assert(c && t); +static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + pa_property_dump(c, buf); return 0; } static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { - assert(c); - assert(t); + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); pa_mempool_vacuum(c->mempool); @@ -792,6 +974,11 @@ static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf pa_sink *sink; uint32_t idx; + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + if (!(n = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n"); return -1; @@ -830,6 +1017,11 @@ static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_str pa_source *source; uint32_t idx; + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + if (!(n = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify a source output by its index.\n"); return -1; @@ -862,7 +1054,105 @@ static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_str return 0; } -static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { +static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *n, *m; + pa_sink *sink; + int suspend; + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + + 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 (!(m = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n"); + return -1; + } + + if (pa_atoi(m, &suspend) < 0) { + pa_strbuf_puts(buf, "Failed to parse suspend switch.\n"); + return -1; + } + + if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) { + pa_strbuf_puts(buf, "No sink found by this name or index.\n"); + return -1; + } + + pa_sink_suspend(sink, suspend); + return 0; +} + +static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *n, *m; + pa_source *source; + int suspend; + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + + 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 (!(m = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n"); + return -1; + } + + if (pa_atoi(m, &suspend) < 0) { + pa_strbuf_puts(buf, "Failed to parse suspend switch.\n"); + return -1; + } + + if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE, 1))) { + pa_strbuf_puts(buf, "No source found by this name or index.\n"); + return -1; + } + + pa_source_suspend(source, suspend); + return 0; +} + +static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { + const char *m; + int suspend; + int ret; + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + + if (!(m = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n"); + return -1; + } + + if (pa_atoi(m, &suspend) < 0) { + pa_strbuf_puts(buf, "Failed to parse suspend switch.\n"); + return -1; + } + + ret = - (pa_sink_suspend_all(c, suspend) < 0); + if (pa_source_suspend_all(c, suspend) < 0) + ret = -1; + + if (ret < 0) + pa_strbuf_puts(buf, "Failed to resume/suspend all sinks/sources.\n"); + + return 0; +} + +static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { pa_module *m; pa_sink *sink; pa_source *source; @@ -874,7 +1164,10 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G void *i; pa_autoload_entry *a; - assert(c && t); + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); time(&now); @@ -884,7 +1177,6 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now)); #endif - for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) { if (m->auto_unload) continue; @@ -900,7 +1192,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G nl = 0; for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) { - if (sink->owner && sink->owner->auto_unload) + if (sink->module && sink->module->auto_unload) continue; if (!nl) { @@ -908,12 +1200,12 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G nl = 1; } - pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, PA_MIXER_HARDWARE))); - pa_strbuf_printf(buf, "set-sink-mute %s %d\n", sink->name, pa_sink_get_mute(sink, PA_MIXER_HARDWARE)); + pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink))); + pa_strbuf_printf(buf, "set-sink-mute %s %d\n", sink->name, pa_sink_get_mute(sink)); } for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) { - if (source->owner && source->owner->auto_unload) + if (source->module && source->module->auto_unload) continue; if (!nl) { @@ -921,8 +1213,8 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G nl = 1; } - pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_avg(pa_source_get_volume(source, PA_MIXER_HARDWARE))); - pa_strbuf_printf(buf, "set-source-mute %s %d\n", source->name, pa_source_get_mute(source, PA_MIXER_HARDWARE)); + pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_avg(pa_source_get_volume(source))); + pa_strbuf_printf(buf, "set-source-mute %s %d\n", source->name, pa_source_get_mute(source)); } @@ -972,6 +1264,10 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *buf, int *fail, int *ifstate) { const char *cs; + pa_assert(c); + pa_assert(s); + pa_assert(buf); + cs = s+strspn(s, whitespace); if (*cs == '#' || !*cs) @@ -1006,9 +1302,9 @@ int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *b if (l == sizeof(META_INCLUDE)-1 && !strncmp(cs, META_INCLUDE, l)) { const char *filename = cs+l+strspn(cs+l, whitespace); - if (pa_cli_command_execute_file(c, filename, buf, fail) < 0) - if (*fail) return -1; + if (*fail) + return -1; } else if (l == sizeof(META_IFEXISTS)-1 && !strncmp(cs, META_IFEXISTS, l)) { if (!ifstate) { pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs); @@ -1020,6 +1316,7 @@ int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *b const char *filename = cs+l+strspn(cs+l, whitespace); *ifstate = access(filename, F_OK) == 0 ? IFSTATE_TRUE : IFSTATE_FALSE; + pa_log_debug("Checking for existance of '%s': %s", filename, *ifstate == IFSTATE_TRUE ? "success" : "failure"); } } else { pa_strbuf_printf(buf, "Invalid meta command: %s\n", cs); @@ -1034,14 +1331,13 @@ int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *b if (ifstate && *ifstate == IFSTATE_FALSE) return 0; - l = strcspn(cs, whitespace); for (command = commands; command->name; command++) if (strlen(command->name) == l && !strncmp(cs, command->name, l)) { int ret; pa_tokenizer *t = pa_tokenizer_new(cs, command->args); - assert(t); + pa_assert(t); ret = command->proc(c, t, buf, fail); pa_tokenizer_free(t); unknown = 0; @@ -1072,9 +1368,9 @@ int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int int ifstate = IFSTATE_NONE; int ret = -1; - assert(c); - assert(fn); - assert(buf); + pa_assert(c); + pa_assert(fn); + pa_assert(buf); if (!(f = fopen(fn, "r"))) { pa_strbuf_printf(buf, "open('%s') failed: %s\n", fn, pa_cstrerror(errno)); @@ -1104,9 +1400,9 @@ int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail) const char *p; int ifstate = IFSTATE_NONE; - assert(c); - assert(s); - assert(buf); + pa_assert(c); + pa_assert(s); + pa_assert(buf); p = s; while (*p) { @@ -1125,3 +1421,4 @@ int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail) return 0; } + diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index 413f9334..6683e697 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -25,7 +25,6 @@ #include #endif -#include #include #include @@ -41,6 +40,7 @@ #include #include #include +#include #include "cli-text.h" @@ -48,10 +48,9 @@ char *pa_module_list_to_string(pa_core *c) { pa_strbuf *s; pa_module *m; uint32_t idx = PA_IDXSET_INVALID; - assert(c); + pa_assert(c); s = pa_strbuf_new(); - assert(s); pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_size(c->modules)); @@ -72,10 +71,9 @@ char *pa_client_list_to_string(pa_core *c) { pa_strbuf *s; pa_client *client; uint32_t idx = PA_IDXSET_INVALID; - assert(c); + pa_assert(c); s = pa_strbuf_new(); - assert(s); pa_strbuf_printf(s, "%u client(s) logged in.\n", pa_idxset_size(c->clients)); @@ -93,10 +91,15 @@ char *pa_sink_list_to_string(pa_core *c) { pa_strbuf *s; pa_sink *sink; uint32_t idx = PA_IDXSET_INVALID; - assert(c); + static const char* const state_table[] = { + [PA_SINK_RUNNING] = "RUNNING", + [PA_SINK_SUSPENDED] = "SUSPENDED", + [PA_SINK_IDLE] = "IDLE", + [PA_SINK_UNLINKED] = "UNLINKED" + }; + pa_assert(c); s = pa_strbuf_new(); - assert(s); pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_size(c->sinks)); @@ -108,22 +111,35 @@ char *pa_sink_list_to_string(pa_core *c) { " %c index: %u\n" "\tname: <%s>\n" "\tdriver: <%s>\n" + "\tflags: %s%s%s\n" + "\tstate: %s\n" "\tvolume: <%s>\n" + "\tmute: <%i>\n" "\tlatency: <%0.0f usec>\n" - "\tmonitor_source: <%u>\n" + "\tmonitor source: <%u>\n" "\tsample spec: <%s>\n" - "\tchannel map: <%s>\n", + "\tchannel map: <%s>\n" + "\tused by: <%u>\n" + "\tlinked by: <%u>\n", c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ', - sink->index, sink->name, + sink->index, + sink->name, sink->driver, - pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, PA_MIXER_HARDWARE)), + sink->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", + sink->flags & PA_SINK_LATENCY ? "LATENCY " : "", + sink->flags & PA_SINK_HARDWARE ? "HARDWARE " : "", + state_table[pa_sink_get_state(sink)], + pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink)), + !!pa_sink_get_mute(sink), (double) pa_sink_get_latency(sink), sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX, pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec), - pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map)); + pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map), + pa_sink_used_by(sink), + pa_sink_linked_by(sink)); - if (sink->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", sink->owner->index); + if (sink->module) + pa_strbuf_printf(s, "\tmodule: <%u>\n", sink->module->index); if (sink->description) pa_strbuf_printf(s, "\tdescription: <%s>\n", sink->description); } @@ -135,15 +151,20 @@ char *pa_source_list_to_string(pa_core *c) { pa_strbuf *s; pa_source *source; uint32_t idx = PA_IDXSET_INVALID; - assert(c); + static const char* const state_table[] = { + [PA_SOURCE_RUNNING] = "RUNNING", + [PA_SOURCE_SUSPENDED] = "SUSPENDED", + [PA_SOURCE_IDLE] = "IDLE", + [PA_SOURCE_UNLINKED] = "UNLINKED" + }; + pa_assert(c); s = pa_strbuf_new(); - assert(s); pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_size(c->sources)); for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) { - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX]; pa_strbuf_printf( @@ -151,21 +172,35 @@ char *pa_source_list_to_string(pa_core *c) { " %c index: %u\n" "\tname: <%s>\n" "\tdriver: <%s>\n" + "\tflags: %s%s%s\n" + "\tstate: %s\n" + "\tvolume: <%s>\n" + "\tmute: <%u>\n" "\tlatency: <%0.0f usec>\n" "\tsample spec: <%s>\n" - "\tchannel map: <%s>\n", + "\tchannel map: <%s>\n" + "\tused by: <%u>\n" + "\tlinked by: <%u>\n", c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ', source->index, source->name, source->driver, + source->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", + source->flags & PA_SOURCE_LATENCY ? "LATENCY " : "", + source->flags & PA_SOURCE_HARDWARE ? "HARDWARE " : "", + state_table[pa_source_get_state(source)], + pa_cvolume_snprint(cv, sizeof(cv), pa_source_get_volume(source)), + !!pa_source_get_mute(source), (double) pa_source_get_latency(source), pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec), - pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map)); + pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map), + pa_source_used_by(source), + pa_source_linked_by(source)); if (source->monitor_of) pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index); - if (source->owner) - pa_strbuf_printf(s, "\towner module: <%u>\n", source->owner->index); + if (source->module) + pa_strbuf_printf(s, "\tmodule: <%u>\n", source->module->index); if (source->description) pa_strbuf_printf(s, "\tdescription: <%s>\n", source->description); } @@ -179,37 +214,41 @@ char *pa_source_output_list_to_string(pa_core *c) { pa_source_output *o; uint32_t idx = PA_IDXSET_INVALID; static const char* const state_table[] = { - "RUNNING", - "CORKED", - "DISCONNECTED" + [PA_SOURCE_OUTPUT_RUNNING] = "RUNNING", + [PA_SOURCE_OUTPUT_CORKED] = "CORKED", + [PA_SOURCE_OUTPUT_UNLINKED] = "UNLINKED" }; - assert(c); + pa_assert(c); s = pa_strbuf_new(); - assert(s); pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_size(c->source_outputs)); for (o = pa_idxset_first(c->source_outputs, &idx); o; o = pa_idxset_next(c->source_outputs, &idx)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - assert(o->source); + pa_assert(o->source); pa_strbuf_printf( s, " index: %u\n" "\tname: '%s'\n" "\tdriver: <%s>\n" + "\tflags: %s%s\n" "\tstate: %s\n" "\tsource: <%u> '%s'\n" + "\tlatency: <%0.0f usec>\n" "\tsample spec: <%s>\n" "\tchannel map: <%s>\n" "\tresample method: %s\n", o->index, o->name, o->driver, - state_table[o->state], + o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE ? "VARIABLE_RATE " : "", + o->flags & PA_SOURCE_OUTPUT_DONT_MOVE ? "DONT_MOVE " : "", + state_table[pa_source_output_get_state(o)], o->source->index, o->source->name, + (double) pa_source_output_get_latency(o), pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map), pa_resample_method_to_string(pa_source_output_get_resample_method(o))); @@ -227,30 +266,32 @@ char *pa_sink_input_list_to_string(pa_core *c) { pa_sink_input *i; uint32_t idx = PA_IDXSET_INVALID; static const char* const state_table[] = { - "RUNNING", - "CORKED", - "DISCONNECTED" + [PA_SINK_INPUT_RUNNING] = "RUNNING", + [PA_SINK_INPUT_DRAINED] = "DRAINED", + [PA_SINK_INPUT_CORKED] = "CORKED", + [PA_SINK_INPUT_UNLINKED] = "UNLINKED" }; - assert(c); + pa_assert(c); s = pa_strbuf_new(); - assert(s); pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_size(c->sink_inputs)); for (i = pa_idxset_first(c->sink_inputs, &idx); i; i = pa_idxset_next(c->sink_inputs, &idx)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - assert(i->sink); + pa_assert(i->sink); pa_strbuf_printf( s, " index: %u\n" "\tname: <%s>\n" "\tdriver: <%s>\n" + "\tflags: %s%s\n" "\tstate: %s\n" "\tsink: <%u> '%s'\n" "\tvolume: <%s>\n" + "\tmute: <%i>\n" "\tlatency: <%0.0f usec>\n" "\tsample spec: <%s>\n" "\tchannel map: <%s>\n" @@ -258,16 +299,19 @@ char *pa_sink_input_list_to_string(pa_core *c) { i->index, i->name, i->driver, - state_table[i->state], + i->flags & PA_SINK_INPUT_VARIABLE_RATE ? "VARIABLE_RATE " : "", + i->flags & PA_SINK_INPUT_DONT_MOVE ? "DONT_MOVE " : "", + state_table[pa_sink_input_get_state(i)], i->sink->index, i->sink->name, pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)), + !!pa_sink_input_get_mute(i), (double) pa_sink_input_get_latency(i), pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), pa_resample_method_to_string(pa_sink_input_get_resample_method(i))); if (i->module) - pa_strbuf_printf(s, "\towner module: <%u>\n", i->module->index); + pa_strbuf_printf(s, "\tmodule: <%u>\n", i->module->index); if (i->client) pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", i->client->index, i->client->name); } @@ -277,10 +321,9 @@ char *pa_sink_input_list_to_string(pa_core *c) { char *pa_scache_list_to_string(pa_core *c) { pa_strbuf *s; - assert(c); + pa_assert(c); s = pa_strbuf_new(); - assert(s); pa_strbuf_printf(s, "%u cache entries available.\n", c->scache ? pa_idxset_size(c->scache) : 0); @@ -326,10 +369,9 @@ char *pa_scache_list_to_string(pa_core *c) { char *pa_autoload_list_to_string(pa_core *c) { pa_strbuf *s; - assert(c); + pa_assert(c); s = pa_strbuf_new(); - assert(s); pa_strbuf_printf(s, "%u autoload entries available.\n", c->autoload_hashmap ? pa_hashmap_size(c->autoload_hashmap) : 0); diff --git a/src/pulsecore/cli.c b/src/pulsecore/cli.c index ee05d7f9..3f3c9cde 100644 --- a/src/pulsecore/cli.c +++ b/src/pulsecore/cli.c @@ -27,7 +27,6 @@ #include #include -#include #include #include @@ -45,6 +44,7 @@ #include #include #include +#include #include "cli.h" @@ -68,19 +68,17 @@ static void client_kill(pa_client *c); pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m) { char cname[256]; pa_cli *c; - assert(io); + pa_assert(io); - c = pa_xmalloc(sizeof(pa_cli)); + c = pa_xnew(pa_cli, 1); c->core = core; - c->line = pa_ioline_new(io); - assert(c->line); + pa_assert_se(c->line = pa_ioline_new(io)); c->userdata = NULL; c->eof_callback = NULL; pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); - c->client = pa_client_new(core, __FILE__, cname); - assert(c->client); + pa_assert_se(c->client = pa_client_new(core, __FILE__, cname)); c->client->kill = client_kill; c->client->userdata = c; c->client->owner = m; @@ -94,7 +92,8 @@ pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m) { } void pa_cli_free(pa_cli *c) { - assert(c); + pa_assert(c); + pa_ioline_close(c->line); pa_ioline_unref(c->line); pa_client_free(c->client); @@ -103,8 +102,9 @@ void pa_cli_free(pa_cli *c) { static void client_kill(pa_client *client) { pa_cli *c; - assert(client && client->userdata); - c = client->userdata; + + pa_assert(client); + pa_assert_se(c = client->userdata); pa_log_debug("CLI client killed."); if (c->defer_kill) @@ -119,7 +119,9 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) { pa_strbuf *buf; pa_cli *c = userdata; char *p; - assert(line && c); + + pa_assert(line); + pa_assert(c); if (!s) { pa_log_debug("CLI got EOF from user."); @@ -129,8 +131,7 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) { return; } - buf = pa_strbuf_new(); - assert(buf); + pa_assert_se(buf = pa_strbuf_new()); c->defer_kill++; pa_cli_command_execute_line(c->core, s, buf, &c->fail); c->defer_kill--; @@ -145,7 +146,8 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) { } void pa_cli_set_eof_callback(pa_cli *c, void (*cb)(pa_cli*c, void *userdata), void *userdata) { - assert(c); + pa_assert(c); + c->eof_callback = cb; c->userdata = userdata; } diff --git a/src/pulsecore/client.c b/src/pulsecore/client.c index 0d792bb4..319b8387 100644 --- a/src/pulsecore/client.c +++ b/src/pulsecore/client.c @@ -27,7 +27,6 @@ #endif #include -#include #include #include @@ -35,15 +34,16 @@ #include #include +#include #include "client.h" pa_client *pa_client_new(pa_core *core, const char *driver, const char *name) { pa_client *c; - int r; - assert(core); - c = pa_xmalloc(sizeof(pa_client)); + pa_core_assert_ref(core); + + c = pa_xnew(pa_client, 1); c->name = pa_xstrdup(name); c->driver = pa_xstrdup(driver); c->owner = NULL; @@ -52,10 +52,9 @@ pa_client *pa_client_new(pa_core *core, const char *driver, const char *name) { c->kill = NULL; c->userdata = NULL; - r = pa_idxset_put(core->clients, c, &c->index); - assert(c->index != PA_IDXSET_INVALID && r >= 0); + pa_assert_se(pa_idxset_put(core->clients, c, &c->index) >= 0); - pa_log_info("created %u \"%s\"", c->index, c->name); + pa_log_info("Created %u \"%s\"", c->index, c->name); pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index); pa_core_check_quit(core); @@ -64,13 +63,14 @@ pa_client *pa_client_new(pa_core *core, const char *driver, const char *name) { } void pa_client_free(pa_client *c) { - assert(c && c->core); + pa_assert(c); + pa_assert(c->core); pa_idxset_remove_by_data(c->core->clients, c, NULL); pa_core_check_quit(c->core); - pa_log_info("freed %u \"%s\"", c->index, c->name); + pa_log_info("Freed %u \"%s\"", c->index, c->name); pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index); pa_xfree(c->name); pa_xfree(c->driver); @@ -78,7 +78,8 @@ void pa_client_free(pa_client *c) { } void pa_client_kill(pa_client *c) { - assert(c); + pa_assert(c); + if (!c->kill) { pa_log_warn("kill() operation not implemented for client %u", c->index); return; @@ -88,9 +89,9 @@ void pa_client_kill(pa_client *c) { } void pa_client_set_name(pa_client *c, const char *name) { - assert(c); + pa_assert(c); - pa_log_info("client %u changed name from \"%s\" to \"%s\"", c->index, c->name, name); + pa_log_info("Client %u changed name from \"%s\" to \"%s\"", c->index, c->name, name); pa_xfree(c->name); c->name = pa_xstrdup(name); diff --git a/src/pulsecore/conf-parser.c b/src/pulsecore/conf-parser.c index 12efbd2c..0e0ba95a 100644 --- a/src/pulsecore/conf-parser.c +++ b/src/pulsecore/conf-parser.c @@ -25,7 +25,6 @@ #include #endif -#include #include #include #include @@ -35,6 +34,7 @@ #include #include #include +#include #include "conf-parser.h" @@ -43,7 +43,10 @@ /* Run the user supplied parser for an assignment */ static int next_assignment(const char *filename, unsigned line, const pa_config_item *t, const char *lvalue, const char *rvalue, void *userdata) { - assert(filename && t && lvalue && rvalue); + pa_assert(filename); + pa_assert(t); + pa_assert(lvalue); + pa_assert(rvalue); for (; t->parse; t++) if (!strcmp(lvalue, t->lvalue)) @@ -56,7 +59,7 @@ static int next_assignment(const char *filename, unsigned line, const pa_config_ /* Returns non-zero when c is contained in s */ static int in_string(char c, const char *s) { - assert(s); + pa_assert(s); for (; *s; s++) if (*s == c) @@ -107,7 +110,9 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void int r = -1; unsigned line = 0; int do_close = !f; - assert(filename && t); + + pa_assert(filename); + pa_assert(t); if (!f && !(f = fopen(filename, "r"))) { if (errno == ENOENT) { @@ -115,7 +120,7 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void goto finish; } - pa_log_warn("WARNING: failed to open configuration file '%s': %s", + pa_log_warn("Failed to open configuration file '%s': %s", filename, pa_cstrerror(errno)); goto finish; } @@ -126,7 +131,7 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void if (feof(f)) break; - pa_log_warn("WARNING: failed to read configuration file '%s': %s", + pa_log_warn("Failed to read configuration file '%s': %s", filename, pa_cstrerror(errno)); goto finish; } @@ -148,7 +153,11 @@ finish: int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { int *i = data; int32_t k; - assert(filename && lvalue && rvalue && data); + + pa_assert(filename); + pa_assert(lvalue); + pa_assert(rvalue); + pa_assert(data); if (pa_atoi(rvalue, &k) < 0) { pa_log("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); @@ -161,7 +170,11 @@ int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { int *b = data, k; - assert(filename && lvalue && rvalue && data); + + pa_assert(filename); + pa_assert(lvalue); + pa_assert(rvalue); + pa_assert(data); if ((k = pa_parse_boolean(rvalue)) < 0) { pa_log("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue); @@ -175,7 +188,11 @@ int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue int pa_config_parse_string(const char *filename, PA_GCC_UNUSED unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { char **s = data; - assert(filename && lvalue && rvalue && data); + + pa_assert(filename); + pa_assert(lvalue); + pa_assert(rvalue); + pa_assert(data); pa_xfree(*s); *s = *rvalue ? pa_xstrdup(rvalue) : NULL; diff --git a/src/pulsecore/core-def.h b/src/pulsecore/core-def.h index 10a3be42..4bc05137 100644 --- a/src/pulsecore/core-def.h +++ b/src/pulsecore/core-def.h @@ -24,9 +24,6 @@ USA. ***/ -typedef enum pa_mixer { - PA_MIXER_SOFTWARE, - PA_MIXER_HARDWARE -} pa_mixer_t; +/* FIXME: Remove this shit */ #endif diff --git a/src/pulsecore/core-error.c b/src/pulsecore/core-error.c index 044bea12..8a61e726 100644 --- a/src/pulsecore/core-error.c +++ b/src/pulsecore/core-error.c @@ -31,178 +31,50 @@ #include #include -#ifdef HAVE_PTHREAD -#include -#endif - -#ifdef HAVE_WINDOWS_H -#include -#endif - #include #include #include #include +#include +#include +#include #include "core-error.h" -#ifdef HAVE_PTHREAD - -static pthread_once_t cstrerror_once = PTHREAD_ONCE_INIT; -static pthread_key_t tlsstr_key; - -static void inittls(void) { - int ret; - - ret = pthread_key_create(&tlsstr_key, pa_xfree); - if (ret) { - fprintf(stderr, __FILE__ ": CRITICAL: Unable to allocate TLS key (%d)\n", errno); - exit(-1); - } -} - -#elif HAVE_WINDOWS_H - -static DWORD tlsstr_key = TLS_OUT_OF_INDEXES; -static DWORD monitor_key = TLS_OUT_OF_INDEXES; - -static void inittls(void) { - HANDLE mutex; - char name[64]; - - sprintf(name, "pulse%d", (int)GetCurrentProcessId()); - - mutex = CreateMutex(NULL, FALSE, name); - if (!mutex) { - fprintf(stderr, __FILE__ ": CRITICAL: Unable to create named mutex (%d)\n", (int)GetLastError()); - exit(-1); - } - - WaitForSingleObject(mutex, INFINITE); - - if (tlsstr_key == TLS_OUT_OF_INDEXES) { - tlsstr_key = TlsAlloc(); - monitor_key = TlsAlloc(); - if ((tlsstr_key == TLS_OUT_OF_INDEXES) || (monitor_key == TLS_OUT_OF_INDEXES)) { - fprintf(stderr, __FILE__ ": CRITICAL: Unable to allocate TLS key (%d)\n", (int)GetLastError()); - exit(-1); - } - } - - ReleaseMutex(mutex); - - CloseHandle(mutex); -} - -/* - * This is incredibly brain dead, but this is necessary when dealing with - * the hell that is Win32. - */ -struct monitor_data { - HANDLE thread; - void *data; -}; - -static DWORD WINAPI monitor_thread(LPVOID param) { - struct monitor_data *data; - - data = (struct monitor_data*)param; - assert(data); - - WaitForSingleObject(data->thread, INFINITE); - - CloseHandle(data->thread); - pa_xfree(data->data); - pa_xfree(data); - - return 0; -} - -static void start_monitor(void) { - HANDLE thread; - struct monitor_data *data; - - data = pa_xnew(struct monitor_data, 1); - assert(data); - - DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), - GetCurrentProcess(), &data->thread, 0, FALSE, DUPLICATE_SAME_ACCESS); - - thread = CreateThread(NULL, 0, monitor_thread, data, 0, NULL); - assert(thread); - - TlsSetValue(monitor_key, data); - - CloseHandle(thread); -} - -#else - -/* Unsafe, but we have no choice */ -static char *tlsstr; - -#endif +PA_STATIC_TLS_DECLARE(cstrerror, pa_xfree); const char* pa_cstrerror(int errnum) { - const char *origbuf; - -#ifdef HAVE_STRERROR_R + const char *original = NULL; + char *translated, *t; char errbuf[128]; -#endif -#ifdef HAVE_PTHREAD - char *tlsstr; + if ((t = PA_STATIC_TLS_GET(cstrerror))) + pa_xfree(t); - pthread_once(&cstrerror_once, inittls); - - tlsstr = pthread_getspecific(tlsstr_key); -#elif defined(HAVE_WINDOWS_H) - char *tlsstr; - struct monitor_data *data; - - inittls(); - - tlsstr = TlsGetValue(tlsstr_key); - if (!tlsstr) - start_monitor(); - data = TlsGetValue(monitor_key); -#endif - - if (tlsstr) - pa_xfree(tlsstr); - -#ifdef HAVE_STRERROR_R - -#ifdef __GLIBC__ - origbuf = strerror_r(errnum, errbuf, sizeof(errbuf)); - if (origbuf == NULL) - origbuf = ""; -#else +#if defined(HAVE_STRERROR_R) && defined(__GLIBC__) + original = strerror_r(errnum, errbuf, sizeof(errbuf)); +#elif defined(HAVE_STRERROR_R) if (strerror_r(errnum, errbuf, sizeof(errbuf)) == 0) { - origbuf = errbuf; - errbuf[sizeof(errbuf) - 1] = '\0'; - } else - origbuf = ""; -#endif - + errbuf[sizeof(errbuf) - 1] = 0; + original = errbuf; + } #else /* This might not be thread safe, but we hope for the best */ - origbuf = strerror(errnum); + original = strerror(errnum); #endif - tlsstr = pa_locale_to_utf8(origbuf); - if (!tlsstr) { - fprintf(stderr, "Unable to convert, filtering\n"); - tlsstr = pa_utf8_filter(origbuf); + if (!original) { + pa_snprintf(errbuf, sizeof(errbuf), "Unknown error %i", errnum); + original = errbuf; } -#ifdef HAVE_PTHREAD - pthread_setspecific(tlsstr_key, tlsstr); -#elif defined(HAVE_WINDOWS_H) - TlsSetValue(tlsstr_key, tlsstr); - data->data = tlsstr; -#endif + if (!(translated = pa_locale_to_utf8(original))) { + pa_log_warn("Unable to convert error string to locale, filtering."); + translated = pa_utf8_filter(original); + } + + PA_STATIC_TLS_SET(cstrerror, translated); - return tlsstr; + return translated; } diff --git a/src/pulsecore/core-scache.c b/src/pulsecore/core-scache.c index cb272784..732d90dd 100644 --- a/src/pulsecore/core-scache.c +++ b/src/pulsecore/core-scache.c @@ -26,7 +26,6 @@ #include #endif -#include #include #include #include @@ -60,6 +59,7 @@ #include #include #include +#include #include "core-scache.h" @@ -68,7 +68,10 @@ static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { pa_core *c = userdata; struct timeval ntv; - assert(c && c->mainloop == m && c->scache_auto_unload_event == e); + + pa_assert(c); + pa_assert(c->mainloop == m); + pa_assert(c->scache_auto_unload_event == e); pa_scache_unload_unused(c); @@ -78,7 +81,8 @@ static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED } static void free_entry(pa_scache_entry *e) { - assert(e); + pa_assert(e); + pa_namereg_unregister(e->core, e->name); pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_REMOVE, e->index); pa_xfree(e->name); @@ -90,7 +94,9 @@ static void free_entry(pa_scache_entry *e) { static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { pa_scache_entry *e; - assert(c && name); + + pa_assert(c); + pa_assert(name); if ((e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) { if (e->memchunk.memblock) @@ -98,11 +104,11 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { pa_xfree(e->filename); - assert(e->core == c); + pa_assert(e->core == c); pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); } else { - e = pa_xmalloc(sizeof(pa_scache_entry)); + e = pa_xnew(pa_scache_entry, 1); if (!pa_namereg_register(c, name, PA_NAMEREG_SAMPLE, e, 1)) { pa_xfree(e); @@ -114,7 +120,7 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { if (!c->scache) { c->scache = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - assert(c->scache); + pa_assert(c->scache); } pa_idxset_put(c->scache, e, &e->index); @@ -139,7 +145,9 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx) { pa_scache_entry *e; char st[PA_SAMPLE_SPEC_SNPRINT_MAX]; - assert(c && name); + + pa_assert(c); + pa_assert(name); if (chunk && chunk->length > PA_SCACHE_ENTRY_SIZE_MAX) return -1; @@ -164,9 +172,9 @@ int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, c if (idx) *idx = e->index; - pa_log_debug("created sample \"%s\" (#%d), %d bytes with sample spec %s", - name, e->index, e->memchunk.length, - pa_sample_spec_snprint(st, sizeof(st), &e->sample_spec)); + pa_log_debug("Created sample \"%s\" (#%d), %lu bytes with sample spec %s", + name, e->index, (unsigned long) e->memchunk.length, + pa_sample_spec_snprint(st, sizeof(st), &e->sample_spec)); return 0; } @@ -184,6 +192,10 @@ int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint3 filename = buf; #endif + pa_assert(c); + pa_assert(name); + pa_assert(filename); + if (pa_sound_file_load(c->mempool, filename, &ss, &map, &chunk) < 0) return -1; @@ -203,7 +215,9 @@ int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, filename = buf; #endif - assert(c && name); + pa_assert(c); + pa_assert(name); + pa_assert(filename); if (!(e = scache_add_item(c, name))) return -1; @@ -226,15 +240,17 @@ int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, int pa_scache_remove_item(pa_core *c, const char *name) { pa_scache_entry *e; - assert(c && name); + + pa_assert(c); + pa_assert(name); if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) return -1; if (pa_idxset_remove_by_data(c->scache, e, NULL) != e) - assert(0); + pa_assert(0); - pa_log_debug("removed sample \"%s\"", name); + pa_log_debug("Removed sample \"%s\"", name); free_entry(e); @@ -243,12 +259,13 @@ int pa_scache_remove_item(pa_core *c, const char *name) { static void free_cb(void *p, PA_GCC_UNUSED void *userdata) { pa_scache_entry *e = p; - assert(e); + pa_assert(e); + free_entry(e); } void pa_scache_free(pa_core *c) { - assert(c); + pa_assert(c); if (c->scache) { pa_idxset_free(c->scache, free_cb, NULL); @@ -264,9 +281,9 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t char *t; pa_cvolume r; - assert(c); - assert(name); - assert(sink); + pa_assert(c); + pa_assert(name); + pa_assert(sink); if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1))) return -1; @@ -284,7 +301,7 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t if (!e->memchunk.memblock) return -1; - pa_log_debug("playing sample \"%s\" on \"%s\"", name, sink->name); + pa_log_debug("Playing sample \"%s\" on \"%s\"", name, sink->name); t = pa_sprintf_malloc("sample:%s", name); @@ -304,9 +321,23 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t return 0; } +int pa_scache_play_item_by_name(pa_core *c, const char *name, const char*sink_name, pa_volume_t volume, int autoload) { + pa_sink *sink; + + pa_assert(c); + pa_assert(name); + + if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, autoload))) + return -1; + + return pa_scache_play_item(c, name, sink, volume); +} + const char * pa_scache_get_name_by_id(pa_core *c, uint32_t id) { pa_scache_entry *e; - assert(c && id != PA_IDXSET_INVALID); + + pa_assert(c); + pa_assert(id != PA_IDXSET_INVALID); if (!c->scache || !(e = pa_idxset_get_by_index(c->scache, id))) return NULL; @@ -316,7 +347,9 @@ const char * pa_scache_get_name_by_id(pa_core *c, uint32_t id) { uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name) { pa_scache_entry *e; - assert(c && name); + + pa_assert(c); + pa_assert(name); if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) return PA_IDXSET_INVALID; @@ -327,7 +360,8 @@ uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name) { uint32_t pa_scache_total_size(pa_core *c) { pa_scache_entry *e; uint32_t idx, sum = 0; - assert(c); + + pa_assert(c); if (!c->scache || !pa_idxset_size(c->scache)) return 0; @@ -343,7 +377,8 @@ void pa_scache_unload_unused(pa_core *c) { pa_scache_entry *e; time_t now; uint32_t idx; - assert(c); + + pa_assert(c); if (!c->scache || !pa_idxset_size(c->scache)) return; @@ -370,6 +405,9 @@ static void add_file(pa_core *c, const char *pathname) { struct stat st; const char *e; + pa_core_assert_ref(c); + pa_assert(pathname); + e = pa_path_get_filename(pathname); if (stat(pathname, &st) < 0) { @@ -385,7 +423,9 @@ static void add_file(pa_core *c, const char *pathname) { int pa_scache_add_directory_lazy(pa_core *c, const char *pathname) { DIR *dir; - assert(c && pathname); + + pa_core_assert_ref(c); + pa_assert(pathname); /* First try to open this as directory */ if (!(dir = opendir(pathname))) { @@ -415,7 +455,7 @@ int pa_scache_add_directory_lazy(pa_core *c, const char *pathname) { if (e->d_name[0] == '.') continue; - snprintf(p, sizeof(p), "%s/%s", pathname, e->d_name); + pa_snprintf(p, sizeof(p), "%s/%s", pathname, e->d_name); add_file(c, p); } } diff --git a/src/pulsecore/core-scache.h b/src/pulsecore/core-scache.h index bbf13f15..ab7ec0ef 100644 --- a/src/pulsecore/core-scache.h +++ b/src/pulsecore/core-scache.h @@ -55,6 +55,7 @@ int pa_scache_add_directory_lazy(pa_core *c, const char *pathname); int pa_scache_remove_item(pa_core *c, const char *name); int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t volume); +int pa_scache_play_item_by_name(pa_core *c, const char *name, const char*sink_name, pa_volume_t volume, int autoload); void pa_scache_free(pa_core *c); const char *pa_scache_get_name_by_id(pa_core *c, uint32_t id); diff --git a/src/pulsecore/core-subscribe.c b/src/pulsecore/core-subscribe.c index 6608d57a..06c5a4ad 100644 --- a/src/pulsecore/core-subscribe.c +++ b/src/pulsecore/core-subscribe.c @@ -26,12 +26,12 @@ #endif #include -#include #include #include #include +#include #include "core-subscribe.h" @@ -68,9 +68,9 @@ static void sched_event(pa_core *c); pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, pa_subscription_cb_t callback, void *userdata) { pa_subscription *s; - assert(c); - assert(m); - assert(callback); + pa_assert(c); + pa_assert(m); + pa_assert(callback); s = pa_xnew(pa_subscription, 1); s->core = c; @@ -85,24 +85,24 @@ pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, pa_su /* Free a subscription object, effectively marking it for deletion */ void pa_subscription_free(pa_subscription*s) { - assert(s); - assert(!s->dead); + pa_assert(s); + pa_assert(!s->dead); s->dead = 1; sched_event(s->core); } static void free_subscription(pa_subscription *s) { - assert(s); - assert(s->core); + pa_assert(s); + pa_assert(s->core); PA_LLIST_REMOVE(pa_subscription, s->core->subscriptions, s); pa_xfree(s); } static void free_event(pa_subscription_event *s) { - assert(s); - assert(s->core); + pa_assert(s); + pa_assert(s->core); if (!s->next) s->core->subscription_event_last = s->prev; @@ -113,7 +113,7 @@ static void free_event(pa_subscription_event *s) { /* Free all subscription objects */ void pa_subscription_free_all(pa_core *c) { - assert(c); + pa_assert(c); while (c->subscriptions) free_subscription(c->subscriptions); @@ -160,9 +160,9 @@ static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) { pa_core *c = userdata; pa_subscription *s; - assert(c->mainloop == m); - assert(c); - assert(c->subscription_defer_event == de); + pa_assert(c->mainloop == m); + pa_assert(c); + pa_assert(c->subscription_defer_event == de); c->mainloop->defer_enable(c->subscription_defer_event, 0); @@ -196,20 +196,20 @@ static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) { /* Schedule an mainloop event so that a pending subscription event is dispatched */ static void sched_event(pa_core *c) { - assert(c); + pa_assert(c); if (!c->subscription_defer_event) { c->subscription_defer_event = c->mainloop->defer_new(c->mainloop, defer_cb, c); - assert(c->subscription_defer_event); + pa_assert(c->subscription_defer_event); } c->mainloop->defer_enable(c->subscription_defer_event, 1); } /* Append a new subscription event to the subscription event queue and schedule a main loop event */ -void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t index) { +void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t idx) { pa_subscription_event *e; - assert(c); + pa_assert(c); /* No need for queuing subscriptions of noone is listening */ if (!c->subscriptions) @@ -227,7 +227,7 @@ void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t i continue; /* not the same object */ - if (i->index != index) + if (i->index != idx) continue; if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { @@ -253,7 +253,7 @@ void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t i e = pa_xnew(pa_subscription_event, 1); e->core = c; e->type = t; - e->index = index; + e->index = idx; PA_LLIST_INSERT_AFTER(pa_subscription_event, c->subscription_event_queue, c->subscription_event_last, e); c->subscription_event_last = e; diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index e5766b2f..a644b664 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -43,6 +42,10 @@ #include #include +#ifdef HAVE_STRTOF_L +#include +#endif + #ifdef HAVE_SCHED_H #include #endif @@ -55,6 +58,10 @@ #include #endif +#ifdef HAVE_SYS_MMAN_H +#include +#endif + #ifdef HAVE_PTHREAD #include #endif @@ -75,14 +82,19 @@ #include #endif +#ifdef HAVE_LIBSAMPLERATE #include +#endif #include #include +#include #include #include #include +#include +#include #include "core-util.h" @@ -93,10 +105,8 @@ #ifndef OS_IS_WIN32 #define PA_USER_RUNTIME_PATH_PREFIX "/tmp/pulse-" -#define PATH_SEP '/' #else #define PA_USER_RUNTIME_PATH_PREFIX "%TEMP%\\pulse-" -#define PATH_SEP '\\' #endif #ifdef OS_IS_WIN32 @@ -111,7 +121,7 @@ int pa_set_root(HANDLE handle) { if (!GetModuleFileName(handle, library_path + sizeof(PULSE_ROOTENV), MAX_PATH)) return 0; - sep = strrchr(library_path, '\\'); + sep = strrchr(library_path, PA_PATH_SEP_CHAR); if (sep) *sep = '\0'; @@ -124,23 +134,42 @@ int pa_set_root(HANDLE handle) { #endif /** Make a file descriptor nonblock. Doesn't do any error checking */ -void pa_make_nonblock_fd(int fd) { +void pa_make_fd_nonblock(int fd) { + #ifdef O_NONBLOCK int v; - assert(fd >= 0); + pa_assert(fd >= 0); + + pa_assert_se((v = fcntl(fd, F_GETFL)) >= 0); + + if (!(v & O_NONBLOCK)) + pa_assert_se(fcntl(fd, F_SETFL, v|O_NONBLOCK) >= 0); - if ((v = fcntl(fd, F_GETFL)) >= 0) - if (!(v & O_NONBLOCK)) - fcntl(fd, F_SETFL, v|O_NONBLOCK); #elif defined(OS_IS_WIN32) u_long arg = 1; if (ioctlsocket(fd, FIONBIO, &arg) < 0) { - if (WSAGetLastError() == WSAENOTSOCK) - pa_log_warn("WARNING: Only sockets can be made non-blocking!"); + pa_assert_se(WSAGetLastError() == WSAENOTSOCK); + pa_log_warn("Only sockets can be made non-blocking!"); } #else - pa_log_warn("WARNING: Non-blocking I/O not supported.!"); + pa_log_warn("Non-blocking I/O not supported.!"); #endif + +} + +/* Set the FD_CLOEXEC flag for a fd */ +void pa_make_fd_cloexec(int fd) { + +#ifdef FD_CLOEXEC + int v; + pa_assert(fd >= 0); + + pa_assert_se((v = fcntl(fd, F_GETFD, 0)) >= 0); + + if (!(v & FD_CLOEXEC)) + pa_assert_se(fcntl(fd, F_SETFD, v|FD_CLOEXEC) >= 0); +#endif + } /** Creates a directory securely */ @@ -148,7 +177,7 @@ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) { struct stat st; int r; - assert(dir); + pa_assert(dir); #ifdef OS_IS_WIN32 r = mkdir(dir); @@ -169,7 +198,7 @@ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) { uid = getuid(); if (gid == (gid_t)-1) gid = getgid(); - chown(dir, uid, gid); + (void) chown(dir, uid, gid); #endif #ifdef HAVE_CHMOD @@ -295,9 +324,9 @@ ssize_t pa_loop_read(int fd, void*data, size_t size, int *type) { ssize_t ret = 0; int _type; - assert(fd >= 0); - assert(data); - assert(size); + pa_assert(fd >= 0); + pa_assert(data); + pa_assert(size); if (!type) { _type = 0; @@ -326,9 +355,9 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size, int *type) { ssize_t ret = 0; int _type; - assert(fd >= 0); - assert(data); - assert(size); + pa_assert(fd >= 0); + pa_assert(data); + pa_assert(size); if (!type) { _type = 0; @@ -354,13 +383,12 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size, int *type) { /** Platform independent read function. Necessary since not all * systems treat all file descriptors equal. */ -int pa_close(int fd) -{ +int pa_close(int fd) { + #ifdef OS_IS_WIN32 int ret; - ret = closesocket(fd); - if (ret == 0) + if ((ret = closesocket(fd)) == 0) return 0; if (WSAGetLastError() != WSAENOTSOCK) { @@ -407,9 +435,9 @@ void pa_check_signal_is_blocked(int sig) { if (sa.sa_handler != SIG_DFL) return; - pa_log("WARNING: %s is not trapped. This might cause malfunction!", pa_strsignal(sig)); + pa_log_warn("%s is not trapped. This might cause malfunction!", pa_sig2str(sig)); #else /* HAVE_SIGACTION */ - pa_log("WARNING: %s might not be trapped. This might cause malfunction!", pa_strsignal(sig)); + pa_log_warn("%s might not be trapped. This might cause malfunction!", pa_sig2str(sig)); #endif } @@ -419,7 +447,7 @@ char *pa_sprintf_malloc(const char *format, ...) { int size = 100; char *c = NULL; - assert(format); + pa_assert(format); for(;;) { int r; @@ -431,6 +459,8 @@ char *pa_sprintf_malloc(const char *format, ...) { r = vsnprintf(c, size, format, ap); va_end(ap); + c[size-1] = 0; + if (r > -1 && r < size) return c; @@ -447,19 +477,20 @@ char *pa_vsprintf_malloc(const char *format, va_list ap) { int size = 100; char *c = NULL; - assert(format); + pa_assert(format); for(;;) { int r; va_list aq; - va_copy(aq, ap); - c = pa_xrealloc(c, size); - r = vsnprintf(c, size, format, aq); + va_copy(aq, ap); + r = vsnprintf(c, size, format, aq); va_end(aq); + c[size-1] = 0; + if (r > -1 && r < size) return c; @@ -472,36 +503,47 @@ char *pa_vsprintf_malloc(const char *format, va_list ap) { /* Similar to OpenBSD's strlcpy() function */ char *pa_strlcpy(char *b, const char *s, size_t l) { - assert(b && s && l > 0); + pa_assert(b); + pa_assert(s); + pa_assert(l > 0); strncpy(b, s, l); b[l-1] = 0; return b; } -#define NICE_LEVEL (-15) +/* Make the current thread a realtime thread*/ +void pa_make_realtime(void) { -/* Raise the priority of the current process as much as possible and -sensible: set the nice level to -15 and enable realtime scheduling if -supported.*/ -void pa_raise_priority(void) { -#if defined(HAVE_SYS_CAPABILITY_H) - cap_t caps; - - /* Temporarily acquire CAP_SYS_NICE in the effective set */ - if ((caps = cap_get_proc())) { - cap_t caps_new; - cap_value_t nice_cap = CAP_SYS_NICE; - - if ((caps_new = cap_dup(caps))) { - cap_set_flag(caps_new, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET); - cap_set_flag(caps_new, CAP_PERMITTED, 1, &nice_cap, CAP_SET); - cap_set_proc(caps_new); - cap_free(caps_new); - } +#ifdef _POSIX_PRIORITY_SCHEDULING + struct sched_param sp; + int r, policy; + + memset(&sp, 0, sizeof(sp)); + policy = 0; + + if ((r = pthread_getschedparam(pthread_self(), &policy, &sp)) != 0) { + pa_log("pthread_getschedgetparam(): %s", pa_cstrerror(r)); + return; + } + + sp.sched_priority = 1; + if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) != 0) { + pa_log_warn("pthread_setschedparam(): %s", pa_cstrerror(r)); + return; } + + pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread."); #endif +} + +#define NICE_LEVEL (-11) + +/* Raise the priority of the current process as much as possible and +sensible: set the nice level to -15.*/ +void pa_raise_priority(void) { + #ifdef HAVE_SYS_RESOURCE_H if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) pa_log_warn("setpriority(): %s", pa_cstrerror(errno)); @@ -509,86 +551,26 @@ void pa_raise_priority(void) { pa_log_info("Successfully gained nice level %i.", NICE_LEVEL); #endif -#ifdef _POSIX_PRIORITY_SCHEDULING - { - struct sched_param sp; - - if (sched_getparam(0, &sp) < 0) { - pa_log("sched_getparam(): %s", pa_cstrerror(errno)); - goto fail; - } - - sp.sched_priority = 1; - if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) { - pa_log_warn("sched_setscheduler(): %s", pa_cstrerror(errno)); - goto fail; - } - - pa_log_info("Successfully enabled SCHED_FIFO scheduling."); - } -#endif - #ifdef OS_IS_WIN32 if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError()); else pa_log_info("Successfully gained high priority class."); #endif - -fail: - -#if defined(HAVE_SYS_CAPABILITY_H) - if (caps) { - /* Restore original caps */ - cap_set_proc(caps); - cap_free(caps); - } -#endif - - ; /* We put this here to get the code to compile when - * HAVE_SYS_CAPABILITY_H is not defined. Don't remove unless you - * know what you do */ } -/* Reset the priority to normal, inverting the changes made by pa_raise_priority() */ +/* Reset the priority to normal, inverting the changes made by + * pa_raise_priority() */ void pa_reset_priority(void) { #ifdef OS_IS_WIN32 SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); #endif -#ifdef _POSIX_PRIORITY_SCHEDULING - { - struct sched_param sp; - sched_getparam(0, &sp); - sp.sched_priority = 0; - sched_setscheduler(0, SCHED_OTHER, &sp); - } -#endif - #ifdef HAVE_SYS_RESOURCE_H setpriority(PRIO_PROCESS, 0, 0); #endif } -/* Set the FD_CLOEXEC flag for a fd */ -int pa_fd_set_cloexec(int fd, int b) { - -#ifdef FD_CLOEXEC - int v; - assert(fd >= 0); - - if ((v = fcntl(fd, F_GETFD, 0)) < 0) - return -1; - - v = (v & ~FD_CLOEXEC) | (b ? FD_CLOEXEC : 0); - - if (fcntl(fd, F_SETFD, v) < 0) - return -1; -#endif - - return 0; -} - /* Try to parse a boolean string value.*/ int pa_parse_boolean(const char *v) { @@ -639,31 +621,134 @@ char *pa_split_spaces(const char *c, const char **state) { return pa_xstrndup(current, l); } -/* Return the name of an UNIX signal. Similar to GNU's strsignal() */ -const char *pa_strsignal(int sig) { +PA_STATIC_TLS_DECLARE(signame, pa_xfree); + +/* Return the name of an UNIX signal. Similar to Solaris sig2str() */ +const char *pa_sig2str(int sig) { + char *t; + + if (sig <= 0) + goto fail; + +#ifdef NSIG + if (sig >= NSIG) + goto fail; +#endif + +#ifdef HAVE_SIG2STR + { + char buf[SIG2STR_MAX]; + + if (sig2str(sig, buf) == 0) { + pa_xfree(PA_STATIC_TLS_GET(signame)); + t = pa_sprintf_malloc("SIG%s", buf); + PA_STATIC_TLS_SET(signame, t); + return t; + } + } +#else + switch(sig) { - case SIGINT: return "SIGINT"; - case SIGTERM: return "SIGTERM"; +#ifdef SIGHUP + case SIGHUP: return "SIGHUP"; +#endif + case SIGINT: return "SIGINT"; +#ifdef SIGQUIT + case SIGQUIT: return "SIGQUIT"; +#endif + case SIGILL: return "SIGULL"; +#ifdef SIGTRAP + case SIGTRAP: return "SIGTRAP"; +#endif + case SIGABRT: return "SIGABRT"; +#ifdef SIGBUS + case SIGBUS: return "SIGBUS"; +#endif + case SIGFPE: return "SIGFPE"; +#ifdef SIGKILL + case SIGKILL: return "SIGKILL"; +#endif #ifdef SIGUSR1 - case SIGUSR1: return "SIGUSR1"; + case SIGUSR1: return "SIGUSR1"; #endif + case SIGSEGV: return "SIGSEGV"; #ifdef SIGUSR2 - case SIGUSR2: return "SIGUSR2"; -#endif -#ifdef SIGXCPU - case SIGXCPU: return "SIGXCPU"; + case SIGUSR2: return "SIGUSR2"; #endif #ifdef SIGPIPE - case SIGPIPE: return "SIGPIPE"; + case SIGPIPE: return "SIGPIPE"; +#endif +#ifdef SIGALRM + case SIGALRM: return "SIGALRM"; +#endif + case SIGTERM: return "SIGTERM"; +#ifdef SIGSTKFLT + case SIGSTKFLT: return "SIGSTKFLT"; #endif #ifdef SIGCHLD - case SIGCHLD: return "SIGCHLD"; + case SIGCHLD: return "SIGCHLD"; #endif -#ifdef SIGHUP - case SIGHUP: return "SIGHUP"; +#ifdef SIGCONT + case SIGCONT: return "SIGCONT"; +#endif +#ifdef SIGSTOP + case SIGSTOP: return "SIGSTOP"; +#endif +#ifdef SIGTSTP + case SIGTSTP: return "SIGTSTP"; +#endif +#ifdef SIGTTIN + case SIGTTIN: return "SIGTTIN"; +#endif +#ifdef SIGTTOU + case SIGTTOU: return "SIGTTOU"; +#endif +#ifdef SIGURG + case SIGURG: return "SIGURG"; +#endif +#ifdef SIGXCPU + case SIGXCPU: return "SIGXCPU"; +#endif +#ifdef SIGXFSZ + case SIGXFSZ: return "SIGXFSZ"; #endif - default: return "UNKNOWN SIGNAL"; +#ifdef SIGVTALRM + case SIGVTALRM: return "SIGVTALRM"; +#endif +#ifdef SIGPROF + case SIGPROF: return "SIGPROF"; +#endif +#ifdef SIGWINCH + case SIGWINCH: return "SIGWINCH"; +#endif +#ifdef SIGIO + case SIGIO: return "SIGIO"; +#endif +#ifdef SIGPWR + case SIGPWR: return "SIGPWR"; +#endif +#ifdef SIGSYS + case SIGSYS: return "SIGSYS"; +#endif + } + +#ifdef SIGRTMIN + if (sig >= SIGRTMIN && sig <= SIGRTMAX) { + pa_xfree(PA_STATIC_TLS_GET(signame)); + t = pa_sprintf_malloc("SIGRTMIN+%i", sig - SIGRTMIN); + PA_STATIC_TLS_SET(signame, t); + return t; } +#endif + +#endif + +fail: + + pa_xfree(PA_STATIC_TLS_GET(signame)); + t = pa_sprintf_malloc("SIG%i", sig); + PA_STATIC_TLS_SET(signame, t); + return t; } #ifdef HAVE_GRP_H @@ -715,7 +800,7 @@ int pa_own_uid_in_group(const char *name, gid_t *gid) { int n = sysconf(_SC_NGROUPS_MAX); int r = -1, i; - assert(n > 0); + pa_assert(n > 0); gids = pa_xmalloc(sizeof(GETGROUPS_T)*n); @@ -861,8 +946,7 @@ int pa_lock_fd(int fd, int b) { return 0; } - pa_log("%slock: %s", !b? "un" : "", - pa_cstrerror(errno)); + pa_log("%slock: %s", !b? "un" : "", pa_cstrerror(errno)); #endif #ifdef OS_IS_WIN32 @@ -881,7 +965,7 @@ int pa_lock_fd(int fd, int b) { /* Remove trailing newlines from a string */ char* pa_strip_nl(char *s) { - assert(s); + pa_assert(s); s[strcspn(s, "\r\n")] = 0; return s; @@ -890,38 +974,46 @@ char* pa_strip_nl(char *s) { /* Create a temporary lock file and lock it. */ int pa_lock_lockfile(const char *fn) { int fd = -1; - assert(fn); + pa_assert(fn); for (;;) { struct stat st; - if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) { - pa_log("failed to create lock file '%s': %s", fn, - pa_cstrerror(errno)); + if ((fd = open(fn, O_CREAT|O_RDWR +#ifdef O_NOCTTY + |O_NOCTTY +#endif +#ifdef O_NOFOLLOW + |O_NOFOLLOW +#endif + , S_IRUSR|S_IWUSR)) < 0) { + pa_log_warn("Failed to create lock file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } if (pa_lock_fd(fd, 1) < 0) { - pa_log("failed to lock file '%s'.", fn); + pa_log_warn("Failed to lock file '%s'.", fn); goto fail; } if (fstat(fd, &st) < 0) { - pa_log("failed to fstat() file '%s'.", fn); + pa_log_warn("Failed to fstat() file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } - /* Check wheter the file has been removed meanwhile. When yes, restart this loop, otherwise, we're done */ + /* Check wheter the file has been removed meanwhile. When yes, + * restart this loop, otherwise, we're done */ if (st.st_nlink >= 1) break; if (pa_lock_fd(fd, 0) < 0) { - pa_log("failed to unlock file '%s'.", fn); + pa_log_warn("Failed to unlock file '%s'.", fn); goto fail; } - if (close(fd) < 0) { - pa_log("failed to close file '%s'.", fn); + if (pa_close(fd) < 0) { + pa_log_warn("Failed to close file '%s': %s", fn, pa_cstrerror(errno)); + fd = -1; goto fail; } @@ -933,7 +1025,7 @@ int pa_lock_lockfile(const char *fn) { fail: if (fd >= 0) - close(fd); + pa_close(fd); return -1; } @@ -941,22 +1033,21 @@ fail: /* Unlock a temporary lcok file */ int pa_unlock_lockfile(const char *fn, int fd) { int r = 0; - assert(fn && fd >= 0); + pa_assert(fn); + pa_assert(fd >= 0); if (unlink(fn) < 0) { - pa_log_warn("WARNING: unable to remove lock file '%s': %s", - fn, pa_cstrerror(errno)); + pa_log_warn("Unable to remove lock file '%s': %s", fn, pa_cstrerror(errno)); r = -1; } if (pa_lock_fd(fd, 0) < 0) { - pa_log_warn("WARNING: failed to unlock file '%s'.", fn); + pa_log_warn("Failed to unlock file '%s'.", fn); r = -1; } - if (close(fd) < 0) { - pa_log_warn("WARNING: failed to close lock file '%s': %s", - fn, pa_cstrerror(errno)); + if (pa_close(fd) < 0) { + pa_log_warn("Failed to close '%s': %s", fn, pa_cstrerror(errno)); r = -1; } @@ -1019,10 +1110,8 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env return f; } - if (errno != ENOENT) { - pa_log_warn("WARNING: failed to open configuration file '%s': %s", - lfn, pa_cstrerror(errno)); - } + if (errno != ENOENT) + pa_log_warn("Failed to open configuration file '%s': %s", lfn, pa_cstrerror(errno)); pa_xfree(lfn); } @@ -1051,7 +1140,10 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) { size_t i = 0, j = 0; const char hex[] = "0123456789abcdef"; - assert(d && s && slength > 0); + + pa_assert(d); + pa_assert(s); + pa_assert(slength > 0); while (i < dlength && j+3 <= slength) { s[j++] = hex[*d >> 4]; @@ -1082,7 +1174,9 @@ static int hexc(char c) { /* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */ size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) { size_t j = 0; - assert(p && d); + + pa_assert(p); + pa_assert(d); while (j < dlength && *p) { int b; @@ -1109,8 +1203,8 @@ size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) { int pa_startswith(const char *s, const char *pfx) { size_t l; - assert(s); - assert(pfx); + pa_assert(s); + pa_assert(pfx); l = strlen(pfx); @@ -1121,8 +1215,8 @@ int pa_startswith(const char *s, const char *pfx) { int pa_endswith(const char *s, const char *sfx) { size_t l1, l2; - assert(s); - assert(sfx); + pa_assert(s); + pa_assert(sfx); l1 = strlen(s); l2 = strlen(sfx); @@ -1146,17 +1240,17 @@ char *pa_runtime_path(const char *fn, char *s, size_t l) { if ((e = getenv("PULSE_RUNTIME_PATH"))) { if (fn) - snprintf(s, l, "%s%c%s", e, PATH_SEP, fn); + pa_snprintf(s, l, "%s%c%s", e, PA_PATH_SEP_CHAR, fn); else - snprintf(s, l, "%s", e); + pa_snprintf(s, l, "%s", e); } else { char u[256]; if (fn) - snprintf(s, l, "%s%s%c%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn); + pa_snprintf(s, l, "%s%s%c%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PA_PATH_SEP_CHAR, fn); else - snprintf(s, l, "%s%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u))); + pa_snprintf(s, l, "%s%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u))); } @@ -1175,11 +1269,17 @@ char *pa_runtime_path(const char *fn, char *s, size_t l) { int pa_atoi(const char *s, int32_t *ret_i) { char *x = NULL; long l; - assert(s && ret_i); + pa_assert(s); + pa_assert(ret_i); + + errno = 0; l = strtol(s, &x, 0); - if (!x || *x) + if (!x || *x || errno != 0) + return -1; + + if ((int32_t) l != l) return -1; *ret_i = (int32_t) l; @@ -1191,14 +1291,219 @@ int pa_atoi(const char *s, int32_t *ret_i) { int pa_atou(const char *s, uint32_t *ret_u) { char *x = NULL; unsigned long l; - assert(s && ret_u); + pa_assert(s); + pa_assert(ret_u); + + errno = 0; l = strtoul(s, &x, 0); - if (!x || *x) + if (!x || *x || errno != 0) + return -1; + + if ((uint32_t) l != l) return -1; *ret_u = (uint32_t) l; return 0; } + +#ifdef HAVE_STRTOF_L +static locale_t c_locale = NULL; + +static void c_locale_destroy(void) { + freelocale(c_locale); +} +#endif + +int pa_atof(const char *s, float *ret_f) { + char *x = NULL; + float f; + int r = 0; + + pa_assert(s); + pa_assert(ret_f); + + /* This should be locale independent */ + +#ifdef HAVE_STRTOF_L + + PA_ONCE_BEGIN { + + if ((c_locale = newlocale(LC_ALL_MASK, "C", NULL))) + atexit(c_locale_destroy); + + } PA_ONCE_END; + + if (c_locale) { + errno = 0; + f = strtof_l(s, &x, c_locale); + } else +#endif + { + errno = 0; +#ifdef HAVE_STRTOF + f = strtof(s, &x); +#else + f = strtod(s, &x); +#endif + } + + if (!x || *x || errno != 0) + r = -1; + else + *ret_f = f; + + return r; +} + +/* Same as snprintf, but guarantees NUL-termination on every platform */ +int pa_snprintf(char *str, size_t size, const char *format, ...) { + int ret; + va_list ap; + + pa_assert(str); + pa_assert(size > 0); + pa_assert(format); + + va_start(ap, format); + ret = vsnprintf(str, size, format, ap); + va_end(ap); + + str[size-1] = 0; + + return ret; +} + +/* Truncate the specified string, but guarantee that the string + * returned still validates as UTF8 */ +char *pa_truncate_utf8(char *c, size_t l) { + pa_assert(c); + pa_assert(pa_utf8_valid(c)); + + if (strlen(c) <= l) + return c; + + c[l] = 0; + + while (l > 0 && !pa_utf8_valid(c)) + c[--l] = 0; + + return c; +} + +char *pa_getcwd(void) { + size_t l = 128; + + for (;;) { + char *p = pa_xnew(char, l); + if (getcwd(p, l)) + return p; + + if (errno != ERANGE) + return NULL; + + pa_xfree(p); + l *= 2; + } +} + +char *pa_make_path_absolute(const char *p) { + char *r; + char *cwd; + + pa_assert(p); + + if (p[0] == '/') + return pa_xstrdup(p); + + if (!(cwd = pa_getcwd())) + return pa_xstrdup(p); + + r = pa_sprintf_malloc("%s/%s", cwd, p); + pa_xfree(cwd); + return r; +} + +void *pa_will_need(const void *p, size_t l) { +#ifdef RLIMIT_MEMLOCK + struct rlimit rlim; +#endif + const void *a; + size_t size; + int r; + size_t bs; + + pa_assert(p); + pa_assert(l > 0); + + a = PA_PAGE_ALIGN_PTR(p); + size = (const uint8_t*) p + l - (const uint8_t*) a; + +#ifdef HAVE_POSIX_MADVISE + if ((r = posix_madvise((void*) a, size, POSIX_MADV_WILLNEED)) == 0) { + pa_log_debug("posix_madvise() worked fine!"); + return (void*) p; + } +#endif + + /* Most likely the memory was not mmap()ed from a file and thus + * madvise() didn't work, so let's misuse mlock() do page this + * stuff back into RAM. Yeah, let's fuck with the MM! It's so + * inviting, the man page of mlock() tells us: "All pages that + * contain a part of the specified address range are guaranteed to + * be resident in RAM when the call returns successfully." */ + +#ifdef RLIMIT_MEMLOCK + pa_assert_se(getrlimit(RLIMIT_MEMLOCK, &rlim) == 0); + + if (rlim.rlim_cur < PA_PAGE_SIZE) { + pa_log_debug("posix_madvise() failed (or doesn't exist), resource limits don't allow mlock(), can't page in data: %s", pa_cstrerror(r)); + return (void*) p; + } + + bs = PA_PAGE_ALIGN(rlim.rlim_cur); +#else + bs = PA_PAGE_SIZE*4; +#endif + + pa_log_debug("posix_madvise() failed (or doesn't exist), trying mlock(): %s", pa_cstrerror(r)); + +#ifdef HAVE_MLOCK + while (size > 0 && bs > 0) { + + if (bs > size) + bs = size; + + if (mlock(a, bs) < 0) { + bs = PA_PAGE_ALIGN(bs / 2); + continue; + } + + pa_assert_se(munlock(a, bs) == 0); + + a = (const uint8_t*) a + bs; + size -= bs; + } +#endif + + if (bs <= 0) + pa_log_debug("mlock() failed too (or doesn't exist), giving up: %s", pa_cstrerror(errno)); + else + pa_log_debug("mlock() worked fine!"); + + return (void*) p; +} + +void pa_close_pipe(int fds[2]) { + pa_assert(fds); + + if (fds[0] >= 0) + pa_assert_se(pa_close(fds[0]) == 0); + + if (fds[1] >= 0) + pa_assert_se(pa_close(fds[1]) == 0); + + fds[0] = fds[1] = -1; +} diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index 1d921e03..0fe865ec 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -34,7 +34,8 @@ struct timeval; -void pa_make_nonblock_fd(int fd); +void pa_make_fd_nonblock(int fd); +void pa_make_fd_cloexec(int fd); int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid); int pa_make_secure_parent_dir(const char *fn, mode_t, uid_t uid, gid_t gid); @@ -55,19 +56,18 @@ char *pa_strlcpy(char *b, const char *s, size_t l); char *pa_parent_dir(const char *fn); +void pa_make_realtime(void); void pa_raise_priority(void); void pa_reset_priority(void); -int pa_fd_set_cloexec(int fd, int b); - -int pa_parse_boolean(const char *s); +int pa_parse_boolean(const char *s) PA_GCC_PURE; char *pa_split(const char *c, const char*delimiters, const char **state); char *pa_split_spaces(const char *c, const char **state); char *pa_strip_nl(char *s); -const char *pa_strsignal(int sig); +const char *pa_sig2str(int sig) PA_GCC_PURE; int pa_own_uid_in_group(const char *name, gid_t *gid); int pa_uid_in_group(uid_t uid, const char *name); @@ -84,12 +84,42 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength); size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength); -int pa_startswith(const char *s, const char *pfx); -int pa_endswith(const char *s, const char *sfx); +int pa_startswith(const char *s, const char *pfx) PA_GCC_PURE; +int pa_endswith(const char *s, const char *sfx) PA_GCC_PURE; char *pa_runtime_path(const char *fn, char *s, size_t l); int pa_atoi(const char *s, int32_t *ret_i); int pa_atou(const char *s, uint32_t *ret_u); +int pa_atof(const char *s, float *ret_f); + +int pa_snprintf(char *str, size_t size, const char *format, ...); + +char *pa_truncate_utf8(char *c, size_t l); + +char *pa_getcwd(void); +char *pa_make_path_absolute(const char *p); + +void *pa_will_need(const void *p, size_t l); + +static inline int pa_is_power_of_two(unsigned n) { + return !(n & (n - 1)); +} + +static inline unsigned pa_make_power_of_two(unsigned n) { + unsigned j = n; + + if (pa_is_power_of_two(n)) + return n; + + while (j) { + j = j >> 1; + n = n | j; + } + + return n + 1; +} + +void pa_close_pipe(int fds[2]); #endif diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index 31b6c188..e9008833 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -27,7 +27,6 @@ #endif #include -#include #include #include @@ -45,12 +44,36 @@ #include #include #include +#include #include "core.h" +static PA_DEFINE_CHECK_TYPE(pa_core, pa_msgobject); + +static int core_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) { + pa_core *c = PA_CORE(o); + + pa_core_assert_ref(c); + + switch (code) { + + case PA_CORE_MESSAGE_UNLOAD_MODULE: + pa_module_unload(c, userdata); + return 0; + + default: + return -1; + } +} + +static void core_free(pa_object *o); + pa_core* pa_core_new(pa_mainloop_api *m, int shared) { pa_core* c; pa_mempool *pool; + int j; + + pa_assert(m); if (shared) { if (!(pool = pa_mempool_new(shared))) { @@ -66,7 +89,9 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) { } } - c = pa_xnew(pa_core, 1); + c = pa_msgobject_new(pa_core); + c->parent.parent.free = core_free; + c->parent.process_msg = core_process_msg; c->mainloop = m; c->clients = pa_idxset_new(NULL, NULL); @@ -87,6 +112,8 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) { c->default_sample_spec.format = PA_SAMPLE_S16NE; c->default_sample_spec.rate = 44100; c->default_sample_spec.channels = 2; + c->default_n_fragments = 4; + c->default_fragment_size_msec = 25; c->module_auto_unload_event = NULL; c->module_defer_unload_event = NULL; @@ -99,22 +126,21 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) { c->mempool = pool; - c->disallow_module_loading = 0; - c->quit_event = NULL; c->exit_idle_time = -1; c->module_idle_time = 20; c->scache_idle_time = 20; - c->resample_method = PA_RESAMPLER_SRC_SINC_FASTEST; + c->resample_method = PA_RESAMPLER_SPEEX_FLOAT_BASE; c->is_system_instance = 0; + c->disallow_module_loading = 0; + c->high_priority = 0; + - pa_hook_init(&c->hook_sink_input_new, c); - pa_hook_init(&c->hook_sink_disconnect, c); - pa_hook_init(&c->hook_source_output_new, c); - pa_hook_init(&c->hook_source_disconnect, c); + for (j = 0; j < PA_CORE_HOOK_MAX; j++) + pa_hook_init(&c->hooks[j], c); pa_property_init(c); @@ -123,28 +149,31 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) { #ifdef SIGPIPE pa_check_signal_is_blocked(SIGPIPE); #endif + return c; } -void pa_core_free(pa_core *c) { - assert(c); +static void core_free(pa_object *o) { + pa_core *c = PA_CORE(o); + int j; + pa_assert(c); pa_module_unload_all(c); - assert(!c->modules); + pa_assert(!c->modules); - assert(pa_idxset_isempty(c->clients)); + pa_assert(pa_idxset_isempty(c->clients)); pa_idxset_free(c->clients, NULL, NULL); - assert(pa_idxset_isempty(c->sinks)); + pa_assert(pa_idxset_isempty(c->sinks)); pa_idxset_free(c->sinks, NULL, NULL); - assert(pa_idxset_isempty(c->sources)); + pa_assert(pa_idxset_isempty(c->sources)); pa_idxset_free(c->sources, NULL, NULL); - assert(pa_idxset_isempty(c->source_outputs)); + pa_assert(pa_idxset_isempty(c->source_outputs)); pa_idxset_free(c->source_outputs, NULL, NULL); - assert(pa_idxset_isempty(c->sink_inputs)); + pa_assert(pa_idxset_isempty(c->sink_inputs)); pa_idxset_free(c->sink_inputs, NULL, NULL); pa_scache_free(c); @@ -162,23 +191,21 @@ void pa_core_free(pa_core *c) { pa_property_cleanup(c); - pa_hook_free(&c->hook_sink_input_new); - pa_hook_free(&c->hook_sink_disconnect); - pa_hook_free(&c->hook_source_output_new); - pa_hook_free(&c->hook_source_disconnect); + for (j = 0; j < PA_CORE_HOOK_MAX; j++) + pa_hook_free(&c->hooks[j]); pa_xfree(c); } static void quit_callback(pa_mainloop_api*m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { pa_core *c = userdata; - assert(c->quit_event = e); + pa_assert(c->quit_event == e); m->quit(m, 0); } void pa_core_check_quit(pa_core *c) { - assert(c); + pa_assert(c); if (!c->quit_event && c->exit_idle_time >= 0 && pa_idxset_size(c->clients) == 0) { struct timeval tv; diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index 51a18b62..dfa80f8d 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -34,17 +34,51 @@ #include #include #include +#include typedef struct pa_core pa_core; #include #include +#include + +typedef enum pa_core_hook { + PA_CORE_HOOK_SINK_NEW_POST, + PA_CORE_HOOK_SINK_UNLINK, + PA_CORE_HOOK_SINK_UNLINK_POST, + PA_CORE_HOOK_SINK_STATE_CHANGED, + PA_CORE_HOOK_SINK_DESCRIPTION_CHANGED, + PA_CORE_HOOK_SOURCE_NEW_POST, + PA_CORE_HOOK_SOURCE_UNLINK, + PA_CORE_HOOK_SOURCE_UNLINK_POST, + PA_CORE_HOOK_SOURCE_STATE_CHANGED, + PA_CORE_HOOK_SOURCE_DESCRIPTION_CHANGED, + PA_CORE_HOOK_SINK_INPUT_NEW, + PA_CORE_HOOK_SINK_INPUT_PUT, + PA_CORE_HOOK_SINK_INPUT_UNLINK, + PA_CORE_HOOK_SINK_INPUT_UNLINK_POST, + PA_CORE_HOOK_SINK_INPUT_MOVE, + PA_CORE_HOOK_SINK_INPUT_MOVE_POST, + PA_CORE_HOOK_SINK_INPUT_NAME_CHANGED, + PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED, + PA_CORE_HOOK_SOURCE_OUTPUT_NEW, + PA_CORE_HOOK_SOURCE_OUTPUT_PUT, + PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK, + PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST, + PA_CORE_HOOK_SOURCE_OUTPUT_MOVE, + PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_POST, + PA_CORE_HOOK_SOURCE_OUTPUT_NAME_CHANGED, + PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED, + PA_CORE_HOOK_MAX +} pa_core_hook_t; /* The core structure of PulseAudio. Every PulseAudio daemon contains * exactly one of these. It is used for storing kind of global * variables for the daemon. */ struct pa_core { + pa_msgobject parent; + /* A random value which may be used to identify this instance of * PulseAudio. Not cryptographically secure in any way. */ uint32_t cookie; @@ -61,6 +95,8 @@ struct pa_core { char *default_source_name, *default_sink_name; pa_sample_spec default_sample_spec; + unsigned default_n_fragments, default_fragment_size_msec; + pa_time_event *module_auto_unload_event; pa_defer_event *module_defer_unload_event; @@ -71,27 +107,30 @@ struct pa_core { pa_mempool *mempool; - int disallow_module_loading, running_as_daemon; int exit_idle_time, module_idle_time, scache_idle_time; pa_time_event *quit_event; pa_time_event *scache_auto_unload_event; + int disallow_module_loading, running_as_daemon; pa_resample_method_t resample_method; - int is_system_instance; + int high_priority; /* hooks */ - pa_hook - hook_sink_input_new, - hook_sink_disconnect, - hook_source_output_new, - hook_source_disconnect; + pa_hook hooks[PA_CORE_HOOK_MAX]; +}; + +PA_DECLARE_CLASS(pa_core); +#define PA_CORE(o) pa_core_cast(o) + +enum { + PA_CORE_MESSAGE_UNLOAD_MODULE, + PA_CORE_MESSAGE_MAX }; pa_core* pa_core_new(pa_mainloop_api *m, int shared); -void pa_core_free(pa_core*c); /* Check whether noone is connected to this core */ void pa_core_check_quit(pa_core *c); diff --git a/src/pulsecore/creds.h b/src/pulsecore/creds.h index e0a025bd..51dfc33d 100644 --- a/src/pulsecore/creds.h +++ b/src/pulsecore/creds.h @@ -26,7 +26,9 @@ #include -/* config.h must be included before this file */ +#ifndef PACKAGE +#error "Please include config.h before including this file!" +#endif #ifdef HAVE_SYS_SOCKET_H #include diff --git a/src/pulsecore/dynarray.c b/src/pulsecore/dynarray.c index 944e3570..8bdb46fa 100644 --- a/src/pulsecore/dynarray.c +++ b/src/pulsecore/dynarray.c @@ -26,10 +26,10 @@ #endif #include -#include #include #include +#include #include "dynarray.h" @@ -52,7 +52,7 @@ pa_dynarray* pa_dynarray_new(void) { void pa_dynarray_free(pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata) { unsigned i; - assert(a); + pa_assert(a); if (func) for (i = 0; i < a->n_entries; i++) @@ -64,7 +64,7 @@ void pa_dynarray_free(pa_dynarray* a, void (*func)(void *p, void *userdata), voi } void pa_dynarray_put(pa_dynarray*a, unsigned i, void *p) { - assert(a); + pa_assert(a); if (i >= a->n_allocated) { unsigned n; @@ -85,21 +85,27 @@ void pa_dynarray_put(pa_dynarray*a, unsigned i, void *p) { } unsigned pa_dynarray_append(pa_dynarray*a, void *p) { - unsigned i = a->n_entries; + unsigned i; + + pa_assert(a); + + i = a->n_entries; pa_dynarray_put(a, i, p); return i; } void *pa_dynarray_get(pa_dynarray*a, unsigned i) { - assert(a); + pa_assert(a); + if (i >= a->n_entries) return NULL; - assert(a->data); + pa_assert(a->data); return a->data[i]; } unsigned pa_dynarray_size(pa_dynarray*a) { - assert(a); + pa_assert(a); + return a->n_entries; } diff --git a/src/pulsecore/endianmacros.h b/src/pulsecore/endianmacros.h index c0c3a6d8..8f7cfade 100644 --- a/src/pulsecore/endianmacros.h +++ b/src/pulsecore/endianmacros.h @@ -27,54 +27,68 @@ #include -#ifdef HAVE_CONFIG_H -#include +#ifndef PACKAGE +#error "Please include config.h before including this file!" #endif -#define INT16_SWAP(x) ( (int16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) ) -#define UINT16_SWAP(x) ( (uint16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) ) -#define INT32_SWAP(x) ( (int32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) ) -#define UINT32_SWAP(x) ( (uint32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) ) +#ifdef HAVE_BYTESWAP_H +#include +#endif + +#ifdef HAVE_BYTESWAP_H +#define PA_INT16_SWAP(x) ((int16_t) bswap_16((uint16_t) x)) +#define PA_UINT16_SWAP(x) ((uint16_t) bswap_16((uint16_t) x)) +#define PA_INT32_SWAP(x) ((int32_t) bswap_32((uint32_t) x)) +#define PA_UINT32_SWAP(x) ((uint32_t) bswap_32((uint32_t) x)) +#else +#define PA_INT16_SWAP(x) ( (int16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) ) +#define PA_UINT16_SWAP(x) ( (uint16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) ) +#define PA_INT32_SWAP(x) ( (int32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) ) +#define PA_UINT32_SWAP(x) ( (uint32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) ) +#endif + +#define PA_MAYBE_INT16_SWAP(c,x) ((c) ? PA_INT32_SWAP(x) : x) +#define PA_MAYBE_UINT16_SWAP(c,x) ((c) ? PA_UINT32_SWAP(x) : x) -#define MAYBE_INT32_SWAP(c,x) ((c) ? INT32_SWAP(x) : x) -#define MAYBE_UINT32_SWAP(c,x) ((c) ? UINT32_SWAP(x) : x) +#define PA_MAYBE_INT32_SWAP(c,x) ((c) ? PA_INT32_SWAP(x) : x) +#define PA_MAYBE_UINT32_SWAP(c,x) ((c) ? PA_UINT32_SWAP(x) : x) #ifdef WORDS_BIGENDIAN - #define INT16_FROM_LE(x) INT16_SWAP(x) - #define INT16_FROM_BE(x) ((int16_t)(x)) + #define PA_INT16_FROM_LE(x) PA_INT16_SWAP(x) + #define PA_INT16_FROM_BE(x) ((int16_t)(x)) - #define INT16_TO_LE(x) INT16_SWAP(x) - #define INT16_TO_BE(x) ((int16_t)(x)) + #define PA_INT16_TO_LE(x) PA_INT16_SWAP(x) + #define PA_INT16_TO_BE(x) ((int16_t)(x)) - #define UINT16_FROM_LE(x) UINT16_SWAP(x) - #define UINT16_FROM_BE(x) ((uint16_t)(x)) + #define PA_UINT16_FROM_LE(x) PA_UINT16_SWAP(x) + #define PA_UINT16_FROM_BE(x) ((uint16_t)(x)) - #define INT32_FROM_LE(x) INT32_SWAP(x) - #define INT32_FROM_BE(x) ((int32_t)(x)) + #define PA_INT32_FROM_LE(x) PA_INT32_SWAP(x) + #define PA_INT32_FROM_BE(x) ((int32_t)(x)) - #define UINT32_FROM_LE(x) UINT32_SWAP(x) - #define UINT32_FROM_BE(x) ((uint32_t)(x)) + #define PA_UINT32_FROM_LE(x) PA_UINT32_SWAP(x) + #define PA_UINT32_FROM_BE(x) ((uint32_t)(x)) - #define UINT32_TO_LE(x) UINT32_SWAP(x) - #define UINT32_TO_BE(x) ((uint32_t)(x)) + #define PA_UINT32_TO_LE(x) PA_UINT32_SWAP(x) + #define PA_UINT32_TO_BE(x) ((uint32_t)(x)) #else - #define INT16_FROM_LE(x) ((int16_t)(x)) - #define INT16_FROM_BE(x) INT16_SWAP(x) + #define PA_INT16_FROM_LE(x) ((int16_t)(x)) + #define PA_INT16_FROM_BE(x) PA_INT16_SWAP(x) - #define INT16_TO_LE(x) ((int16_t)(x)) - #define INT16_TO_BE(x) INT16_SWAP(x) + #define PA_INT16_TO_LE(x) ((int16_t)(x)) + #define PA_INT16_TO_BE(x) PA_INT16_SWAP(x) - #define UINT16_FROM_LE(x) ((uint16_t)(x)) - #define UINT16_FROM_BE(x) UINT16_SWAP(x) + #define PA_UINT16_FROM_LE(x) ((uint16_t)(x)) + #define PA_UINT16_FROM_BE(x) PA_UINT16_SWAP(x) - #define INT32_FROM_LE(x) ((int32_t)(x)) - #define INT32_FROM_BE(x) INT32_SWAP(x) + #define PA_INT32_FROM_LE(x) ((int32_t)(x)) + #define PA_INT32_FROM_BE(x) PA_INT32_SWAP(x) - #define UINT32_FROM_LE(x) ((uint32_t)(x)) - #define UINT32_FROM_BE(x) UINT32_SWAP(x) + #define PA_UINT32_FROM_LE(x) ((uint32_t)(x)) + #define PA_UINT32_FROM_BE(x) PA_UINT32_SWAP(x) - #define UINT32_TO_LE(x) ((uint32_t)(x)) - #define UINT32_TO_BE(x) UINT32_SWAP(x) + #define PA_UINT32_TO_LE(x) ((uint32_t)(x)) + #define PA_UINT32_TO_BE(x) PA_UINT32_SWAP(x) #endif #endif diff --git a/src/pulsecore/esound.h b/src/pulsecore/esound.h index 3778a535..ea6a5665 100644 --- a/src/pulsecore/esound.h +++ b/src/pulsecore/esound.h @@ -205,7 +205,7 @@ typedef int esd_client_state_t; /* the endian key is transferred in binary, if it's read into int, */ /* and matches ESD_ENDIAN_KEY (ENDN), then the endianness of the */ /* server and the client match; if it's SWAP_ENDIAN_KEY, swap data */ -#define ESD_SWAP_ENDIAN_KEY (UINT32_SWAP(ESD_ENDIAN_KEY)) +#define ESD_SWAP_ENDIAN_KEY (PA_UINT32_SWAP(ESD_ENDIAN_KEY)) #endif diff --git a/src/pulsecore/fdsem.c b/src/pulsecore/fdsem.c new file mode 100644 index 00000000..927bf00c --- /dev/null +++ b/src/pulsecore/fdsem.c @@ -0,0 +1,276 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_SYS_SYSCALL_H +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifndef HAVE_PIPE +#include +#endif + +#ifdef __linux__ + +#if !defined(__NR_eventfd) && defined(__i386__) +#define __NR_eventfd 323 +#endif + +#if !defined(__NR_eventfd) && defined(__x86_64__) +#define __NR_eventfd 284 +#endif + +#if !defined(SYS_eventfd) && defined(__NR_eventfd) +#define SYS_eventfd __NR_eventfd +#endif + +#ifdef SYS_eventfd +#define HAVE_EVENTFD + +static inline long eventfd(unsigned count) { + return syscall(SYS_eventfd, count); +} + +#endif +#endif + +#include "fdsem.h" + +struct pa_fdsem { + int fds[2]; +#ifdef HAVE_EVENTFD + int efd; +#endif + pa_atomic_t waiting; + pa_atomic_t signalled; + pa_atomic_t in_pipe; +}; + +pa_fdsem *pa_fdsem_new(void) { + pa_fdsem *f; + + f = pa_xnew(pa_fdsem, 1); + +#ifdef HAVE_EVENTFD + if ((f->efd = eventfd(0)) >= 0) { + pa_make_fd_cloexec(f->efd); + f->fds[0] = f->fds[1] = -1; + + } else +#endif + { + if (pipe(f->fds) < 0) { + pa_xfree(f); + return NULL; + } + + pa_make_fd_cloexec(f->fds[0]); + pa_make_fd_cloexec(f->fds[1]); + } + + pa_atomic_store(&f->waiting, 0); + pa_atomic_store(&f->signalled, 0); + pa_atomic_store(&f->in_pipe, 0); + + return f; +} + +void pa_fdsem_free(pa_fdsem *f) { + pa_assert(f); + +#ifdef HAVE_EVENTFD + if (f->efd >= 0) + pa_close(f->efd); +#endif + pa_close_pipe(f->fds); + + pa_xfree(f); +} + +static void flush(pa_fdsem *f) { + ssize_t r; + pa_assert(f); + + if (pa_atomic_load(&f->in_pipe) <= 0) + return; + + do { + char x[10]; + +#ifdef HAVE_EVENTFD + if (f->efd >= 0) { + uint64_t u; + + if ((r = read(f->efd, &u, sizeof(u))) != sizeof(u)) { + pa_assert(r < 0 && errno == EINTR); + continue; + } + r = (ssize_t) u; + } else +#endif + + if ((r = read(f->fds[0], &x, sizeof(x))) <= 0) { + pa_assert(r < 0 && errno == EINTR); + continue; + } + + } while (pa_atomic_sub(&f->in_pipe, r) > r); +} + +void pa_fdsem_post(pa_fdsem *f) { + pa_assert(f); + + if (pa_atomic_cmpxchg(&f->signalled, 0, 1)) { + + if (pa_atomic_load(&f->waiting)) { + ssize_t r; + char x = 'x'; + + pa_atomic_inc(&f->in_pipe); + + for (;;) { + +#ifdef HAVE_EVENTFD + if (f->efd >= 0) { + uint64_t u = 1; + + if ((r = write(f->efd, &u, sizeof(u))) != sizeof(u)) { + pa_assert(r < 0 && errno == EINTR); + continue; + } + } else +#endif + + if ((r = write(f->fds[1], &x, 1)) != 1) { + pa_assert(r < 0 && errno == EINTR); + continue; + } + + break; + } + } + } +} + +void pa_fdsem_wait(pa_fdsem *f) { + pa_assert(f); + + flush(f); + + if (pa_atomic_cmpxchg(&f->signalled, 1, 0)) + return; + + pa_atomic_inc(&f->waiting); + + while (!pa_atomic_cmpxchg(&f->signalled, 1, 0)) { + char x[10]; + ssize_t r; + +#ifdef HAVE_EVENTFD + if (f->efd >= 0) { + uint64_t u; + + if ((r = read(f->efd, &u, sizeof(u))) != sizeof(u)) { + pa_assert(r < 0 && errno == EINTR); + continue; + } + + r = (ssize_t) u; + } else +#endif + + if ((r = read(f->fds[0], &x, sizeof(x))) <= 0) { + pa_assert(r < 0 && errno == EINTR); + continue; + } + + pa_atomic_sub(&f->in_pipe, r); + } + + pa_assert_se(pa_atomic_dec(&f->waiting) >= 1); +} + +int pa_fdsem_try(pa_fdsem *f) { + pa_assert(f); + + flush(f); + + if (pa_atomic_cmpxchg(&f->signalled, 1, 0)) + return 1; + + return 0; +} + +int pa_fdsem_get(pa_fdsem *f) { + pa_assert(f); + +#ifdef HAVE_EVENTFD + if (f->efd >= 0) + return f->efd; +#endif + + return f->fds[0]; +} + +int pa_fdsem_before_poll(pa_fdsem *f) { + pa_assert(f); + + flush(f); + + if (pa_atomic_cmpxchg(&f->signalled, 1, 0)) + return -1; + + pa_atomic_inc(&f->waiting); + + if (pa_atomic_cmpxchg(&f->signalled, 1, 0)) { + pa_assert_se(pa_atomic_dec(&f->waiting) >= 1); + return -1; + } + return 0; +} + +int pa_fdsem_after_poll(pa_fdsem *f) { + pa_assert(f); + + pa_assert_se(pa_atomic_dec(&f->waiting) >= 1); + + flush(f); + + if (pa_atomic_cmpxchg(&f->signalled, 1, 0)) + return 1; + + return 0; +} diff --git a/src/pulsecore/fdsem.h b/src/pulsecore/fdsem.h new file mode 100644 index 00000000..f38ef205 --- /dev/null +++ b/src/pulsecore/fdsem.h @@ -0,0 +1,49 @@ +#ifndef foopulsefdsemhfoo +#define foopulsefdsemhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/* A simple, asynchronous semaphore which uses fds for sleeping. In + * the best case all functions are lock-free unless sleeping is + * required. */ + +typedef struct pa_fdsem pa_fdsem; + +pa_fdsem *pa_fdsem_new(void); +void pa_fdsem_free(pa_fdsem *f); + +void pa_fdsem_post(pa_fdsem *f); +void pa_fdsem_wait(pa_fdsem *f); +int pa_fdsem_try(pa_fdsem *f); + +int pa_fdsem_get(pa_fdsem *f); + +int pa_fdsem_before_poll(pa_fdsem *f); +int pa_fdsem_after_poll(pa_fdsem *f); + + +#endif diff --git a/src/pulsecore/ffmpeg/Makefile b/src/pulsecore/ffmpeg/Makefile new file mode 100644 index 00000000..316beb72 --- /dev/null +++ b/src/pulsecore/ffmpeg/Makefile @@ -0,0 +1,13 @@ +# This is a dirty trick just to ease compilation with emacs +# +# This file is not intended to be distributed or anything +# +# So: don't touch it, even better ignore it! + +all: + $(MAKE) -C ../.. + +clean: + $(MAKE) -C ../.. clean + +.PHONY: all clean diff --git a/src/pulsecore/ffmpeg/avcodec.h b/src/pulsecore/ffmpeg/avcodec.h new file mode 100644 index 00000000..696fc986 --- /dev/null +++ b/src/pulsecore/ffmpeg/avcodec.h @@ -0,0 +1,82 @@ +/* + * copyright (c) 2001 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_H +#define AVCODEC_H + +/* Just a heavily bastardized version of the original file from + * ffmpeg, just enough to get resample2.c to compile without + * modification -- Lennart */ + +#if !defined(PACKAGE) && defined(HAVE_CONFIG_H) +#include +#endif + +#include +#include +#include +#include +#include +#include + +#define av_mallocz(l) calloc(1, (l)) +#define av_malloc(l) malloc(l) +#define av_realloc(p,l) realloc((p),(l)) +#define av_free(p) free(p) + +static inline void av_freep(void *k) { + void **p = k; + + if (p) { + free(*p); + *p = NULL; + } +} + +static inline int av_clip(int a, int amin, int amax) +{ + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +#define av_log(a,b,c) + +#define FFABS(a) ((a) >= 0 ? (a) : (-(a))) +#define FFSIGN(a) ((a) > 0 ? 1 : -1) + +#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) +#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) + +struct AVResampleContext; +struct AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_length, int log2_phase_count, int linear, double cutoff); +int av_resample(struct AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx); +void av_resample_compensate(struct AVResampleContext *c, int sample_delta, int compensation_distance); +void av_resample_close(struct AVResampleContext *c); +void av_build_filter(int16_t *filter, double factor, int tap_count, int phase_count, int scale, int type); + +/* + * crude lrintf for non-C99 systems. + */ +#ifndef HAVE_LRINTF +#define lrintf(x) ((long int)(x)) +#endif + +#endif /* AVCODEC_H */ diff --git a/src/pulsecore/ffmpeg/dsputil.h b/src/pulsecore/ffmpeg/dsputil.h new file mode 100644 index 00000000..8da742d0 --- /dev/null +++ b/src/pulsecore/ffmpeg/dsputil.h @@ -0,0 +1 @@ +/* empty file, just here to allow us to compile an unmodified resampler2.c */ diff --git a/src/pulsecore/ffmpeg/resample2.c b/src/pulsecore/ffmpeg/resample2.c new file mode 100644 index 00000000..da1443d9 --- /dev/null +++ b/src/pulsecore/ffmpeg/resample2.c @@ -0,0 +1,324 @@ +/* + * audio resampling + * Copyright (c) 2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file resample2.c + * audio resampling + * @author Michael Niedermayer + */ + +#include "avcodec.h" +#include "dsputil.h" + +#ifndef CONFIG_RESAMPLE_HP +#define FILTER_SHIFT 15 + +#define FELEM int16_t +#define FELEM2 int32_t +#define FELEML int64_t +#define FELEM_MAX INT16_MAX +#define FELEM_MIN INT16_MIN +#define WINDOW_TYPE 9 +#elif !defined(CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE) +#define FILTER_SHIFT 30 + +#define FELEM int32_t +#define FELEM2 int64_t +#define FELEML int64_t +#define FELEM_MAX INT32_MAX +#define FELEM_MIN INT32_MIN +#define WINDOW_TYPE 12 +#else +#define FILTER_SHIFT 0 + +#define FELEM double +#define FELEM2 double +#define FELEML double +#define WINDOW_TYPE 24 +#endif + + +typedef struct AVResampleContext{ + FELEM *filter_bank; + int filter_length; + int ideal_dst_incr; + int dst_incr; + int index; + int frac; + int src_incr; + int compensation_distance; + int phase_shift; + int phase_mask; + int linear; +}AVResampleContext; + +/** + * 0th order modified bessel function of the first kind. + */ +static double bessel(double x){ + double v=1; + double t=1; + int i; + + x= x*x/4; + for(i=1; i<50; i++){ + t *= x/(i*i); + v += t; + } + return v; +} + +/** + * builds a polyphase filterbank. + * @param factor resampling factor + * @param scale wanted sum of coefficients for each filter + * @param type 0->cubic, 1->blackman nuttall windowed sinc, 2..16->kaiser windowed sinc beta=2..16 + */ +void av_build_filter(FELEM *filter, double factor, int tap_count, int phase_count, int scale, int type){ + int ph, i; + double x, y, w, tab[tap_count]; + const int center= (tap_count-1)/2; + + /* if upsampling, only need to interpolate, no filter */ + if (factor > 1.0) + factor = 1.0; + + for(ph=0;phphase_shift= phase_shift; + c->phase_mask= phase_count-1; + c->linear= linear; + + c->filter_length= FFMAX((int)ceil(filter_size/factor), 1); + c->filter_bank= av_mallocz(c->filter_length*(phase_count+1)*sizeof(FELEM)); + av_build_filter(c->filter_bank, factor, c->filter_length, phase_count, 1<filter_bank[c->filter_length*phase_count+1], c->filter_bank, (c->filter_length-1)*sizeof(FELEM)); + c->filter_bank[c->filter_length*phase_count]= c->filter_bank[c->filter_length - 1]; + + c->src_incr= out_rate; + c->ideal_dst_incr= c->dst_incr= in_rate * phase_count; + c->index= -phase_count*((c->filter_length-1)/2); + + return c; +} + +void av_resample_close(AVResampleContext *c){ + av_freep(&c->filter_bank); + av_freep(&c); +} + +/** + * Compensates samplerate/timestamp drift. The compensation is done by changing + * the resampler parameters, so no audible clicks or similar distortions ocur + * @param compensation_distance distance in output samples over which the compensation should be performed + * @param sample_delta number of output samples which should be output less + * + * example: av_resample_compensate(c, 10, 500) + * here instead of 510 samples only 500 samples would be output + * + * note, due to rounding the actual compensation might be slightly different, + * especially if the compensation_distance is large and the in_rate used during init is small + */ +void av_resample_compensate(AVResampleContext *c, int sample_delta, int compensation_distance){ +// sample_delta += (c->ideal_dst_incr - c->dst_incr)*(int64_t)c->compensation_distance / c->ideal_dst_incr; + c->compensation_distance= compensation_distance; + c->dst_incr = c->ideal_dst_incr - c->ideal_dst_incr * (int64_t)sample_delta / compensation_distance; +} + +/** + * resamples. + * @param src an array of unconsumed samples + * @param consumed the number of samples of src which have been consumed are returned here + * @param src_size the number of unconsumed samples available + * @param dst_size the amount of space in samples available in dst + * @param update_ctx if this is 0 then the context wont be modified, that way several channels can be resampled with the same context + * @return the number of samples written in dst or -1 if an error occured + */ +int av_resample(AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx){ + int dst_index, i; + int index= c->index; + int frac= c->frac; + int dst_incr_frac= c->dst_incr % c->src_incr; + int dst_incr= c->dst_incr / c->src_incr; + int compensation_distance= c->compensation_distance; + + if(compensation_distance == 0 && c->filter_length == 1 && c->phase_shift==0){ + int64_t index2= ((int64_t)index)<<32; + int64_t incr= (1LL<<32) * c->dst_incr / c->src_incr; + dst_size= FFMIN(dst_size, (src_size-1-index) * (int64_t)c->src_incr / c->dst_incr); + + for(dst_index=0; dst_index < dst_size; dst_index++){ + dst[dst_index] = src[index2>>32]; + index2 += incr; + } + frac += dst_index * dst_incr_frac; + index += dst_index * dst_incr; + index += frac / c->src_incr; + frac %= c->src_incr; + }else{ + for(dst_index=0; dst_index < dst_size; dst_index++){ + FELEM *filter= c->filter_bank + c->filter_length*(index & c->phase_mask); + int sample_index= index >> c->phase_shift; + FELEM2 val=0; + + if(sample_index < 0){ + for(i=0; ifilter_length; i++) + val += src[FFABS(sample_index + i) % src_size] * filter[i]; + }else if(sample_index + c->filter_length > src_size){ + break; + }else if(c->linear){ + FELEM2 v2=0; + for(i=0; ifilter_length; i++){ + val += src[sample_index + i] * (FELEM2)filter[i]; + v2 += src[sample_index + i] * (FELEM2)filter[i + c->filter_length]; + } + val+=(v2-val)*(FELEML)frac / c->src_incr; + }else{ + for(i=0; ifilter_length; i++){ + val += src[sample_index + i] * (FELEM2)filter[i]; + } + } + +#ifdef CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE + dst[dst_index] = av_clip_int16(lrintf(val)); +#else + val = (val + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT; + dst[dst_index] = (unsigned)(val + 32768) > 65535 ? (val>>31) ^ 32767 : val; +#endif + + frac += dst_incr_frac; + index += dst_incr; + if(frac >= c->src_incr){ + frac -= c->src_incr; + index++; + } + + if(dst_index + 1 == compensation_distance){ + compensation_distance= 0; + dst_incr_frac= c->ideal_dst_incr % c->src_incr; + dst_incr= c->ideal_dst_incr / c->src_incr; + } + } + } + *consumed= FFMAX(index, 0) >> c->phase_shift; + if(index>=0) index &= c->phase_mask; + + if(compensation_distance){ + compensation_distance -= dst_index; + assert(compensation_distance > 0); + } + if(update_ctx){ + c->frac= frac; + c->index= index; + c->dst_incr= dst_incr_frac + c->src_incr*dst_incr; + c->compensation_distance= compensation_distance; + } +#if 0 + if(update_ctx && !c->compensation_distance){ +#undef rand + av_resample_compensate(c, rand() % (8000*2) - 8000, 8000*2); +av_log(NULL, AV_LOG_DEBUG, "%d %d %d\n", c->dst_incr, c->ideal_dst_incr, c->compensation_distance); + } +#endif + + return dst_index; +} diff --git a/src/pulsecore/flist.c b/src/pulsecore/flist.c index 00567ab3..d9740777 100644 --- a/src/pulsecore/flist.c +++ b/src/pulsecore/flist.c @@ -25,12 +25,14 @@ #include #endif -#include +#include #include #include #include -#include +#include +#include +#include #include "flist.h" @@ -90,21 +92,18 @@ enum { }; struct cell { - pa_atomic_int_t state; + pa_atomic_t state; void *data; }; struct pa_flist { - struct cell *cells; unsigned size; - pa_atomic_int_t length; - pa_atomic_int_t read_idx; - pa_atomic_int_t write_idx; + pa_atomic_t length; + pa_atomic_t read_idx; + pa_atomic_t write_idx; }; -static int is_power_of_two(unsigned size) { - return !(size & (size - 1)); -} +#define PA_FLIST_CELLS(x) ((struct cell*) ((uint8_t*) (x) + PA_ALIGN(sizeof(struct pa_flist)))) pa_flist *pa_flist_new(unsigned size) { pa_flist *l; @@ -112,12 +111,11 @@ pa_flist *pa_flist_new(unsigned size) { if (!size) size = FLIST_SIZE; - assert(is_power_of_two(size)); + pa_assert(pa_is_power_of_two(size)); - l = pa_xnew(pa_flist, 1); + l = pa_xmalloc0(PA_ALIGN(sizeof(pa_flist)) + (sizeof(struct cell) * size)); l->size = size; - l->cells = pa_xnew0(struct cell, size); pa_atomic_store(&l->read_idx, 0); pa_atomic_store(&l->write_idx, 0); @@ -131,32 +129,37 @@ static int reduce(pa_flist *l, int value) { } void pa_flist_free(pa_flist *l, pa_free_cb_t free_cb) { - assert(l); + pa_assert(l); if (free_cb) { + struct cell *cells; int len, idx; + cells = PA_FLIST_CELLS(l); + idx = reduce(l, pa_atomic_load(&l->read_idx)); len = pa_atomic_load(&l->length); for (; len > 0; len--) { - if (pa_atomic_load(&l->cells[idx].state) == STATE_USED) - free_cb(l->cells[idx].data); + if (pa_atomic_load(&cells[idx].state) == STATE_USED) + free_cb(cells[idx].data); idx = reduce(l, idx + 1); } } - pa_xfree(l->cells); pa_xfree(l); } int pa_flist_push(pa_flist*l, void *p) { int idx, len, n; + struct cell *cells; + + pa_assert(l); + pa_assert(p); - assert(l); - assert(p); + cells = PA_FLIST_CELLS(l); n = len = (int) l->size - pa_atomic_load(&l->length) + N_EXTRA_SCAN; _Y; @@ -165,13 +168,13 @@ int pa_flist_push(pa_flist*l, void *p) { for (; n > 0 ; n--) { _Y; - if (pa_atomic_cmpxchg(&l->cells[idx].state, STATE_UNUSED, STATE_BUSY)) { + if (pa_atomic_cmpxchg(&cells[idx].state, STATE_UNUSED, STATE_BUSY)) { _Y; pa_atomic_inc(&l->write_idx); _Y; - l->cells[idx].data = p; + cells[idx].data = p; _Y; - pa_atomic_store(&l->cells[idx].state, STATE_USED); + pa_atomic_store(&cells[idx].state, STATE_USED); _Y; pa_atomic_inc(&l->length); return 0; @@ -183,7 +186,7 @@ int pa_flist_push(pa_flist*l, void *p) { #ifdef PROFILE if (len > N_EXTRA_SCAN) - pa_log("WARNING: Didn't find free cell after %u iterations.", len); + pa_log_warn("Didn't find free cell after %u iterations.", len); #endif return -1; @@ -191,8 +194,11 @@ int pa_flist_push(pa_flist*l, void *p) { void* pa_flist_pop(pa_flist*l) { int idx, len, n; + struct cell *cells; + + pa_assert(l); - assert(l); + cells = PA_FLIST_CELLS(l); n = len = pa_atomic_load(&l->length) + N_EXTRA_SCAN; _Y; @@ -201,14 +207,14 @@ void* pa_flist_pop(pa_flist*l) { for (; n > 0 ; n--) { _Y; - if (pa_atomic_cmpxchg(&l->cells[idx].state, STATE_USED, STATE_BUSY)) { + if (pa_atomic_cmpxchg(&cells[idx].state, STATE_USED, STATE_BUSY)) { void *p; _Y; pa_atomic_inc(&l->read_idx); _Y; - p = l->cells[idx].data; + p = cells[idx].data; _Y; - pa_atomic_store(&l->cells[idx].state, STATE_UNUSED); + pa_atomic_store(&cells[idx].state, STATE_UNUSED); _Y; pa_atomic_dec(&l->length); @@ -221,7 +227,7 @@ void* pa_flist_pop(pa_flist*l) { #ifdef PROFILE if (len > N_EXTRA_SCAN) - pa_log("WARNING: Didn't find used cell after %u iterations.", len); + pa_log_warn("Didn't find used cell after %u iterations.", len); #endif return NULL; diff --git a/src/pulsecore/flist.h b/src/pulsecore/flist.h index bf702bf3..daf0fec4 100644 --- a/src/pulsecore/flist.h +++ b/src/pulsecore/flist.h @@ -26,6 +26,9 @@ #include +#include +#include + /* A multiple-reader multipler-write lock-free free list implementation */ typedef struct pa_flist pa_flist; @@ -38,4 +41,28 @@ void pa_flist_free(pa_flist *l, pa_free_cb_t free_cb); int pa_flist_push(pa_flist*l, void *p); void* pa_flist_pop(pa_flist*l); +/* Please not that the destructor stuff is not really necesary, we do + * this just to make valgrind output more useful. */ + +#define PA_STATIC_FLIST_DECLARE(name, size, free_cb) \ + static struct { \ + pa_flist *flist; \ + pa_once once; \ + } name##_flist = { NULL, PA_ONCE_INIT }; \ + static void name##_flist_init(void) { \ + name##_flist.flist = pa_flist_new(size); \ + } \ + static inline pa_flist* name##_flist_get(void) { \ + pa_run_once(&name##_flist.once, name##_flist_init); \ + return name##_flist.flist; \ + } \ + static void name##_flist_destructor(void) PA_GCC_DESTRUCTOR; \ + static void name##_flist_destructor(void) { \ + if (name##_flist.flist) \ + pa_flist_free(name##_flist.flist, (free_cb)); \ + } \ + struct __stupid_useless_struct_to_allow_trailing_semicolon + +#define PA_STATIC_FLIST_GET(name) (name##_flist_get()) + #endif diff --git a/src/pulsecore/g711.c b/src/pulsecore/g711.c index 8c2bbf00..aa2d703a 100644 --- a/src/pulsecore/g711.c +++ b/src/pulsecore/g711.c @@ -43,30 +43,30 @@ #include "g711.h" -#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ -#define QUANT_MASK (0xf) /* Quantization field mask. */ -#define NSEGS (8) /* Number of A-law segments. */ -#define SEG_SHIFT (4) /* Left shift for segment number. */ -#define SEG_MASK (0x70) /* Segment field mask. */ +#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ +#define QUANT_MASK (0xf) /* Quantization field mask. */ +#define NSEGS (8) /* Number of A-law segments. */ +#define SEG_SHIFT (4) /* Left shift for segment number. */ +#define SEG_MASK (0x70) /* Segment field mask. */ #if !defined(FAST_ALAW_CONVERSION) || !defined(FAST_ULAW_CONVERSION) static int16_t seg_aend[8] = {0x1F, 0x3F, 0x7F, 0xFF, - 0x1FF, 0x3FF, 0x7FF, 0xFFF}; + 0x1FF, 0x3FF, 0x7FF, 0xFFF}; static int16_t seg_uend[8] = {0x3F, 0x7F, 0xFF, 0x1FF, - 0x3FF, 0x7FF, 0xFFF, 0x1FFF}; + 0x3FF, 0x7FF, 0xFFF, 0x1FFF}; static int16_t search( - int16_t val, - int16_t *table, - int size) + int16_t val, + int16_t *table, + int size) { - int i; + int i; - for (i = 0; i < size; i++) { - if (val <= *table++) - return (i); - } - return (size); + for (i = 0; i < size; i++) { + if (val <= *table++) + return (i); + } + return (size); } #endif /* !FAST_*_CONVERSION */ @@ -77,55 +77,55 @@ static int16_t search( * the data shifted such that it only contains information in the lower * 13-bits. * - * Linear Input Code Compressed Code - * ------------------------ --------------- - * 0000000wxyza 000wxyz - * 0000001wxyza 001wxyz - * 000001wxyzab 010wxyz - * 00001wxyzabc 011wxyz - * 0001wxyzabcd 100wxyz - * 001wxyzabcde 101wxyz - * 01wxyzabcdef 110wxyz - * 1wxyzabcdefg 111wxyz + * Linear Input Code Compressed Code + * ------------------------ --------------- + * 0000000wxyza 000wxyz + * 0000001wxyza 001wxyz + * 000001wxyzab 010wxyz + * 00001wxyzabc 011wxyz + * 0001wxyzabcd 100wxyz + * 001wxyzabcde 101wxyz + * 01wxyzabcdef 110wxyz + * 1wxyzabcdefg 111wxyz * * For further information see John C. Bellamy's Digital Telephony, 1982, * John Wiley & Sons, pps 98-111 and 472-476. */ unsigned char st_13linear2alaw( - int16_t pcm_val) /* 2's complement (13-bit range) */ + int16_t pcm_val) /* 2's complement (13-bit range) */ { - int16_t mask; - short seg; - unsigned char aval; + int16_t mask; + short seg; + unsigned char aval; - /* Have calling software do it since its already doing a shift - * from 32-bits down to 16-bits. - */ - /* pcm_val = pcm_val >> 3; */ + /* Have calling software do it since its already doing a shift + * from 32-bits down to 16-bits. + */ + /* pcm_val = pcm_val >> 3; */ - /* A-law using even bit inversion */ - if (pcm_val >= 0) { - mask = 0xD5; /* sign (7th) bit = 1 */ - } else { - mask = 0x55; /* sign bit = 0 */ - pcm_val = -pcm_val - 1; - } + /* A-law using even bit inversion */ + if (pcm_val >= 0) { + mask = 0xD5; /* sign (7th) bit = 1 */ + } else { + mask = 0x55; /* sign bit = 0 */ + pcm_val = -pcm_val - 1; + } - /* Convert the scaled magnitude to segment number. */ - seg = search(pcm_val, seg_aend, 8); + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_aend, 8); - /* Combine the sign, segment, and quantization bits. */ + /* Combine the sign, segment, and quantization bits. */ - if (seg >= 8) /* out of range, return maximum value. */ - return (unsigned char) (0x7F ^ mask); - else { - aval = (unsigned char) seg << SEG_SHIFT; - if (seg < 2) - aval |= (pcm_val >> 1) & QUANT_MASK; - else - aval |= (pcm_val >> seg) & QUANT_MASK; - return (aval ^ mask); - } + if (seg >= 8) /* out of range, return maximum value. */ + return (unsigned char) (0x7F ^ mask); + else { + aval = (unsigned char) seg << SEG_SHIFT; + if (seg < 2) + aval |= (pcm_val >> 1) & QUANT_MASK; + else + aval |= (pcm_val >> seg) & QUANT_MASK; + return (aval ^ mask); + } } /* @@ -133,31 +133,31 @@ unsigned char st_13linear2alaw( * */ int16_t st_alaw2linear16( - unsigned char a_val) + unsigned char a_val) { - int16_t t; - int16_t seg; + int16_t t; + int16_t seg; - a_val ^= 0x55; + a_val ^= 0x55; - t = (a_val & QUANT_MASK) << 4; - seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT; - switch (seg) { - case 0: - t += 8; - break; - case 1: - t += 0x108; - break; - default: - t += 0x108; - t <<= seg - 1; - } - return ((a_val & SIGN_BIT) ? t : -t); + t = (a_val & QUANT_MASK) << 4; + seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT; + switch (seg) { + case 0: + t += 8; + break; + case 1: + t += 0x108; + break; + default: + t += 0x108; + t <<= seg - 1; + } + return ((a_val & SIGN_BIT) ? t : -t); } #endif /* !FAST_ALAW_CONVERSION */ -#define BIAS (0x84) /* Bias for linear code. */ +#define BIAS (0x84) /* Bias for linear code. */ #define CLIP 8159 #ifndef FAST_ULAW_CONVERSION @@ -171,16 +171,16 @@ int16_t st_alaw2linear16( * is biased by adding 33 which shifts the encoding range from (0 - 8158) to * (33 - 8191). The result can be seen in the following encoding table: * - * Biased Linear Input Code Compressed Code - * ------------------------ --------------- - * 00000001wxyza 000wxyz - * 0000001wxyzab 001wxyz - * 000001wxyzabc 010wxyz - * 00001wxyzabcd 011wxyz - * 0001wxyzabcde 100wxyz - * 001wxyzabcdef 101wxyz - * 01wxyzabcdefg 110wxyz - * 1wxyzabcdefgh 111wxyz + * Biased Linear Input Code Compressed Code + * ------------------------ --------------- + * 00000001wxyza 000wxyz + * 0000001wxyzab 001wxyz + * 000001wxyzabc 010wxyz + * 00001wxyzabcd 011wxyz + * 0001wxyzabcde 100wxyz + * 001wxyzabcdef 101wxyz + * 01wxyzabcdefg 110wxyz + * 1wxyzabcdefgh 111wxyz * * Each biased linear code has a leading 1 which identifies the segment * number. The value of the segment number is equal to 7 minus the number @@ -194,41 +194,41 @@ int16_t st_alaw2linear16( * John Wiley & Sons, pps 98-111 and 472-476. */ unsigned char st_14linear2ulaw( - int16_t pcm_val) /* 2's complement (14-bit range) */ + int16_t pcm_val) /* 2's complement (14-bit range) */ { - int16_t mask; - int16_t seg; - unsigned char uval; + int16_t mask; + int16_t seg; + unsigned char uval; - /* Have calling software do it since its already doing a shift - * from 32-bits down to 16-bits. - */ - /* pcm_val = pcm_val >> 2; */ + /* Have calling software do it since its already doing a shift + * from 32-bits down to 16-bits. + */ + /* pcm_val = pcm_val >> 2; */ - /* u-law inverts all bits */ - /* Get the sign and the magnitude of the value. */ - if (pcm_val < 0) { - pcm_val = -pcm_val; - mask = 0x7F; - } else { - mask = 0xFF; - } - if ( pcm_val > CLIP ) pcm_val = CLIP; /* clip the magnitude */ - pcm_val += (BIAS >> 2); + /* u-law inverts all bits */ + /* Get the sign and the magnitude of the value. */ + if (pcm_val < 0) { + pcm_val = -pcm_val; + mask = 0x7F; + } else { + mask = 0xFF; + } + if ( pcm_val > CLIP ) pcm_val = CLIP; /* clip the magnitude */ + pcm_val += (BIAS >> 2); - /* Convert the scaled magnitude to segment number. */ - seg = search(pcm_val, seg_uend, 8); + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_uend, 8); - /* - * Combine the sign, segment, quantization bits; - * and complement the code word. - */ - if (seg >= 8) /* out of range, return maximum value. */ - return (unsigned char) (0x7F ^ mask); - else { - uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF); - return (uval ^ mask); - } + /* + * Combine the sign, segment, quantization bits; + * and complement the code word. + */ + if (seg >= 8) /* out of range, return maximum value. */ + return (unsigned char) (0x7F ^ mask); + else { + uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF); + return (uval ^ mask); + } } @@ -242,21 +242,21 @@ unsigned char st_14linear2ulaw( * original code word. This is in keeping with ISDN conventions. */ int16_t st_ulaw2linear16( - unsigned char u_val) + unsigned char u_val) { - int16_t t; + int16_t t; - /* Complement to obtain normal u-law value. */ - u_val = ~u_val; + /* Complement to obtain normal u-law value. */ + u_val = ~u_val; - /* - * Extract and bias the quantization bits. Then - * shift up by the segment number and subtract out the bias. - */ - t = ((u_val & QUANT_MASK) << 3) + BIAS; - t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; + /* + * Extract and bias the quantization bits. Then + * shift up by the segment number and subtract out the bias. + */ + t = ((u_val & QUANT_MASK) << 3) + BIAS; + t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; - return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); + return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); } #endif /* !FAST_ULAW_CONVERSION */ @@ -2413,52 +2413,52 @@ int main() printf("int16_t _st_alaw2linear16[256] = {\n "); for (x = 0; x < 256; x++) { - printf("%8d,", st_alaw2linear16(x)); - y++; - if (y == 7) - { - y = 0; - printf("\n "); - } + printf("%8d,", st_alaw2linear16(x)); + y++; + if (y == 7) + { + y = 0; + printf("\n "); + } } printf("\n};\n\nuint8_t _st_13linear2alaw[0x2000] = {\n "); y = 0; for (x = 0; x < 0x2000; x++) { - printf(" 0x%02x,", st_13linear2alaw((-0x1000)+x)); - y++; - if (y == 12) - { - y = 0; - printf("\n "); - } + printf(" 0x%02x,", st_13linear2alaw((-0x1000)+x)); + y++; + if (y == 12) + { + y = 0; + printf("\n "); + } } printf("\n};\n\nint16_t _st_ulaw2linear16[256] = {\n "); y = 0; for (x = 0; x < 256; x++) { - printf("%8d,", st_ulaw2linear16(x)); - y++; - if (y == 7) - { - y = 0; - printf("\n "); - } + printf("%8d,", st_ulaw2linear16(x)); + y++; + if (y == 7) + { + y = 0; + printf("\n "); + } } printf("\n};\n\nuint8_t _st_14linear2ulaw[0x4000] = {\n "); y = 0; for (x = 0; x < 0x4000; x++) { - printf(" 0x%02x,", st_14linear2ulaw((-0x2000)+x)); - y++; - if (y == 12) - { - y = 0; - printf("\n "); - } + printf(" 0x%02x,", st_14linear2ulaw((-0x2000)+x)); + y++; + if (y == 12) + { + y = 0; + printf("\n "); + } } printf("\n};\n"); @@ -2468,64 +2468,64 @@ int main() /* The following is not used by SoX but kept for reference */ #if 0 /* copy from CCITT G.711 specifications */ -unsigned char _u2a[128] = { /* u- to A-law conversions */ - 1, 1, 2, 2, 3, 3, 4, 4, - 5, 5, 6, 6, 7, 7, 8, 8, - 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, - 25, 27, 29, 31, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, - 46, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, - 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, +unsigned char _u2a[128] = { /* u- to A-law conversions */ + 1, 1, 2, 2, 3, 3, 4, 4, + 5, 5, 6, 6, 7, 7, 8, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 27, 29, 31, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, + 46, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, /* corrected: - 81, 82, 83, 84, 85, 86, 87, 88, + 81, 82, 83, 84, 85, 86, 87, 88, should be: */ - 80, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, 126, 127, 128}; + 80, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128}; -unsigned char _a2u[128] = { /* A- to u-law conversions */ - 1, 3, 5, 7, 9, 11, 13, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 32, 33, 33, 34, 34, 35, 35, - 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 48, 49, 49, - 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 64, - 65, 66, 67, 68, 69, 70, 71, 72, +unsigned char _a2u[128] = { /* A- to u-law conversions */ + 1, 3, 5, 7, 9, 11, 13, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 32, 33, 33, 34, 34, 35, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 48, 49, 49, + 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 64, + 65, 66, 67, 68, 69, 70, 71, 72, /* corrected: - 73, 74, 75, 76, 77, 78, 79, 79, + 73, 74, 75, 76, 77, 78, 79, 79, should be: */ - 73, 74, 75, 76, 77, 78, 79, 80, + 73, 74, 75, 76, 77, 78, 79, 80, - 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127}; + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127}; /* A-law to u-law conversion */ unsigned char st_alaw2ulaw( - unsigned char aval) + unsigned char aval) { - aval &= 0xff; - return (unsigned char) ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) : - (0x7F ^ _a2u[aval ^ 0x55])); + aval &= 0xff; + return (unsigned char) ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) : + (0x7F ^ _a2u[aval ^ 0x55])); } /* u-law to A-law conversion */ unsigned char st_ulaw2alaw( - unsigned char uval) + unsigned char uval) { - uval &= 0xff; - return (unsigned char) ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) : - (unsigned char) (0x55 ^ (_u2a[0x7F ^ uval] - 1))); + uval &= 0xff; + return (unsigned char) ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) : + (unsigned char) (0x55 ^ (_u2a[0x7F ^ uval] - 1))); } #endif diff --git a/src/pulsecore/gccmacro.h b/src/pulsecore/gccmacro.h index 57d28006..e9f0d093 100644 --- a/src/pulsecore/gccmacro.h +++ b/src/pulsecore/gccmacro.h @@ -52,4 +52,29 @@ #define PA_GCC_UNUSED #endif +#ifdef __GNUC__ +#define PA_GCC_DESTRUCTOR __attribute__ ((destructor)) +#else +/** Call this function when process terminates */ +#define PA_GCC_DESTRUCTOR +#endif + +#ifndef PA_GCC_PURE +#ifdef __GNUCC__ +#define PA_GCC_PURE __attribute__ ((pure)) +#else +/** This function's return value depends only the arguments list and global state **/ +#define PA_GCC_PURE +#endif +#endif + +#ifndef PA_GCC_CONST +#ifdef __GNUCC__ +#define PA_GCC_CONST __attribute__ ((const)) +#else +/** This function's return value depends only the arguments list (stricter version of PA_GCC_PURE) **/ +#define PA_GCC_CONST +#endif +#endif + #endif diff --git a/src/pulsecore/hashmap.c b/src/pulsecore/hashmap.c index 818e12bf..f5589664 100644 --- a/src/pulsecore/hashmap.c +++ b/src/pulsecore/hashmap.c @@ -26,13 +26,14 @@ #endif #include -#include #include #include #include #include +#include +#include #include "hashmap.h" @@ -55,6 +56,8 @@ struct pa_hashmap { pa_compare_func_t compare_func; }; +PA_STATIC_FLIST_DECLARE(entries, 0, pa_xfree); + pa_hashmap *pa_hashmap_new(pa_hash_func_t hash_func, pa_compare_func_t compare_func) { pa_hashmap *h; @@ -69,8 +72,8 @@ pa_hashmap *pa_hashmap_new(pa_hash_func_t hash_func, pa_compare_func_t compare_f } static void remove(pa_hashmap *h, struct hashmap_entry *e) { - assert(h); - assert(e); + pa_assert(h); + pa_assert(e); if (e->next) e->next->previous = e->previous; @@ -84,16 +87,18 @@ static void remove(pa_hashmap *h, struct hashmap_entry *e) { if (e->bucket_previous) e->bucket_previous->bucket_next = e->bucket_next; else { - assert(e->hash < h->size); + pa_assert(e->hash < h->size); h->data[e->hash] = e->bucket_next; } - pa_xfree(e); + if (pa_flist_push(PA_STATIC_FLIST_GET(entries), e) < 0) + pa_xfree(e); + h->n_entries--; } void pa_hashmap_free(pa_hashmap*h, void (*free_func)(void *p, void *userdata), void *userdata) { - assert(h); + pa_assert(h); while (h->first_entry) { if (free_func) @@ -107,8 +112,8 @@ void pa_hashmap_free(pa_hashmap*h, void (*free_func)(void *p, void *userdata), v static struct hashmap_entry *get(pa_hashmap *h, unsigned hash, const void *key) { struct hashmap_entry *e; - assert(h); - assert(hash < h->size); + pa_assert(h); + pa_assert(hash < h->size); for (e = h->data[hash]; e; e = e->bucket_next) if (h->compare_func(e->key, key) == 0) @@ -120,14 +125,16 @@ static struct hashmap_entry *get(pa_hashmap *h, unsigned hash, const void *key) int pa_hashmap_put(pa_hashmap *h, const void *key, void *value) { struct hashmap_entry *e; unsigned hash; - assert(h); + pa_assert(h); hash = h->hash_func(key) % h->size; if ((e = get(h, hash, key))) return -1; - e = pa_xnew(struct hashmap_entry, 1); + if (!(e = pa_flist_pop(PA_STATIC_FLIST_GET(entries)))) + e = pa_xnew(struct hashmap_entry, 1); + e->hash = hash; e->key = key; e->value = value; @@ -152,7 +159,7 @@ void* pa_hashmap_get(pa_hashmap *h, const void *key) { unsigned hash; struct hashmap_entry *e; - assert(h); + pa_assert(h); hash = h->hash_func(key) % h->size; @@ -167,7 +174,7 @@ void* pa_hashmap_remove(pa_hashmap *h, const void *key) { unsigned hash; void *data; - assert(h); + pa_assert(h); hash = h->hash_func(key) % h->size; @@ -184,8 +191,8 @@ unsigned pa_hashmap_size(pa_hashmap *h) { } void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void **key) { - assert(h); - assert(state); + pa_assert(h); + pa_assert(state); if (!*state) *state = h->first_entry; @@ -207,7 +214,7 @@ void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void **key) { void* pa_hashmap_steal_first(pa_hashmap *h) { void *data; - assert(h); + pa_assert(h); if (!h->first_entry) return NULL; @@ -218,7 +225,7 @@ void* pa_hashmap_steal_first(pa_hashmap *h) { } void *pa_hashmap_get_first(pa_hashmap *h) { - assert(h); + pa_assert(h); if (!h->first_entry) return NULL; diff --git a/src/pulsecore/hashmap.h b/src/pulsecore/hashmap.h index 3ca2a479..98df4502 100644 --- a/src/pulsecore/hashmap.h +++ b/src/pulsecore/hashmap.h @@ -32,11 +32,13 @@ typedef struct pa_hashmap pa_hashmap; +typedef void (*pa_free2_cb_t)(void *p, void *userdata); + /* Create a new hashmap. Use the specified functions for hashing and comparing objects in the map */ pa_hashmap *pa_hashmap_new(pa_hash_func_t hash_func, pa_compare_func_t compare_func); /* Free the hash table. Calls the specified function for every value in the table. The function may be NULL */ -void pa_hashmap_free(pa_hashmap*, void (*free_func)(void *p, void *userdata), void *userdata); +void pa_hashmap_free(pa_hashmap*, pa_free2_cb_t free_cb, void *userdata); /* Returns non-zero when the entry already exists */ int pa_hashmap_put(pa_hashmap *h, const void *key, void *value); diff --git a/src/pulsecore/hook-list.c b/src/pulsecore/hook-list.c index 4f884187..3a6874c4 100644 --- a/src/pulsecore/hook-list.c +++ b/src/pulsecore/hook-list.c @@ -21,10 +21,16 @@ USA. ***/ -#include +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "hook-list.h" void pa_hook_init(pa_hook *hook, void *data) { - assert(hook); + pa_assert(hook); PA_LLIST_HEAD_INIT(pa_hook_slot, hook->slots); hook->last = NULL; @@ -33,8 +39,8 @@ void pa_hook_init(pa_hook *hook, void *data) { } static void slot_free(pa_hook *hook, pa_hook_slot *slot) { - assert(hook); - assert(slot); + pa_assert(hook); + pa_assert(slot); if (hook->last == slot) hook->last = slot->prev; @@ -45,8 +51,8 @@ static void slot_free(pa_hook *hook, pa_hook_slot *slot) { } void pa_hook_free(pa_hook *hook) { - assert(hook); - assert(!hook->firing); + pa_assert(hook); + pa_assert(!hook->firing); while (hook->slots) slot_free(hook, hook->slots); @@ -57,7 +63,7 @@ void pa_hook_free(pa_hook *hook) { pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t cb, void *data) { pa_hook_slot *slot; - assert(cb); + pa_assert(cb); slot = pa_xnew(pa_hook_slot, 1); slot->hook = hook; @@ -72,8 +78,8 @@ pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t cb, void *data) { } void pa_hook_slot_free(pa_hook_slot *slot) { - assert(slot); - assert(!slot->dead); + pa_assert(slot); + pa_assert(!slot->dead); if (slot->hook->firing > 0) { slot->dead = 1; @@ -86,7 +92,7 @@ pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data) { pa_hook_slot *slot, *next; pa_hook_result_t result = PA_HOOK_OK; - assert(hook); + pa_assert(hook); hook->firing ++; diff --git a/src/pulsecore/idxset.c b/src/pulsecore/idxset.c index 70ef7ba7..8a88471f 100644 --- a/src/pulsecore/idxset.c +++ b/src/pulsecore/idxset.c @@ -27,32 +27,35 @@ #endif #include -#include #include #include #include +#include +#include #include "idxset.h" -typedef struct idxset_entry { +struct idxset_entry { void *data; uint32_t index; unsigned hash_value; struct idxset_entry *hash_prev, *hash_next; struct idxset_entry* iterate_prev, *iterate_next; -} idxset_entry; +}; struct pa_idxset { pa_hash_func_t hash_func; pa_compare_func_t compare_func; unsigned hash_table_size, n_entries; - idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail; + struct idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail; uint32_t index, start_index, array_size; }; +PA_STATIC_FLIST_DECLARE(entries, 0, pa_xfree); + unsigned pa_idxset_string_hash_func(const void *p) { unsigned hash = 0; const char *c; @@ -82,7 +85,7 @@ pa_idxset* pa_idxset_new(pa_hash_func_t hash_func, pa_compare_func_t compare_fun s->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; s->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; s->hash_table_size = 127; - s->hash_table = pa_xnew0(idxset_entry*, s->hash_table_size); + s->hash_table = pa_xnew0(struct idxset_entry*, s->hash_table_size); s->array = NULL; s->array_size = 0; s->index = 0; @@ -95,15 +98,17 @@ pa_idxset* pa_idxset_new(pa_hash_func_t hash_func, pa_compare_func_t compare_fun } void pa_idxset_free(pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata) { - assert(s); + pa_assert(s); while (s->iterate_list_head) { - idxset_entry *e = s->iterate_list_head; + struct idxset_entry *e = s->iterate_list_head; s->iterate_list_head = s->iterate_list_head->iterate_next; if (free_func) free_func(e->data, userdata); - pa_xfree(e); + + if (pa_flist_push(PA_STATIC_FLIST_GET(entries), e) < 0) + pa_xfree(e); } pa_xfree(s->hash_table); @@ -111,10 +116,10 @@ void pa_idxset_free(pa_idxset *s, void (*free_func) (void *p, void *userdata), v pa_xfree(s); } -static idxset_entry* hash_scan(pa_idxset *s, idxset_entry* e, const void *p) { - assert(p); +static struct idxset_entry* hash_scan(pa_idxset *s, struct idxset_entry* e, const void *p) { + pa_assert(p); - assert(s->compare_func); + pa_assert(s->compare_func); for (; e; e = e->hash_next) if (s->compare_func(e->data, p) == 0) return e; @@ -124,8 +129,10 @@ static idxset_entry* hash_scan(pa_idxset *s, idxset_entry* e, const void *p) { static void extend_array(pa_idxset *s, uint32_t idx) { uint32_t i, j, l; - idxset_entry** n; - assert(idx >= s->start_index); + struct idxset_entry** n; + + pa_assert(s); + pa_assert(idx >= s->start_index); if (idx < s->start_index + s->array_size) return; @@ -135,7 +142,7 @@ static void extend_array(pa_idxset *s, uint32_t idx) { break; l = idx - s->start_index - i + 100; - n = pa_xnew0(idxset_entry*, l); + n = pa_xnew0(struct idxset_entry*, l); for (j = 0; j < s->array_size-i; j++) n[j] = s->array[i+j]; @@ -147,7 +154,9 @@ static void extend_array(pa_idxset *s, uint32_t idx) { s->start_index += i; } -static idxset_entry** array_index(pa_idxset*s, uint32_t idx) { +static struct idxset_entry** array_index(pa_idxset*s, uint32_t idx) { + pa_assert(s); + if (idx >= s->start_index + s->array_size) return NULL; @@ -159,15 +168,15 @@ static idxset_entry** array_index(pa_idxset*s, uint32_t idx) { int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) { unsigned h; - idxset_entry *e, **a; + struct idxset_entry *e, **a; - assert(s); - assert(p); + pa_assert(s); + pa_assert(p); - assert(s->hash_func); + pa_assert(s->hash_func); h = s->hash_func(p) % s->hash_table_size; - assert(s->hash_table); + pa_assert(s->hash_table); if ((e = hash_scan(s, s->hash_table[h], p))) { if (idx) *idx = e->index; @@ -175,7 +184,8 @@ int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) { return -1; } - e = pa_xmalloc(sizeof(idxset_entry)); + if (!(e = pa_flist_pop(PA_STATIC_FLIST_GET(entries)))) + e = pa_xnew(struct idxset_entry, 1); e->data = p; e->index = s->index++; e->hash_value = h; @@ -190,23 +200,23 @@ int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) { /* Insert into array */ extend_array(s, e->index); a = array_index(s, e->index); - assert(a && !*a); + pa_assert(a && !*a); *a = e; /* Insert into linked list */ e->iterate_next = NULL; e->iterate_prev = s->iterate_list_tail; if (s->iterate_list_tail) { - assert(s->iterate_list_head); + pa_assert(s->iterate_list_head); s->iterate_list_tail->iterate_next = e; } else { - assert(!s->iterate_list_head); + pa_assert(!s->iterate_list_head); s->iterate_list_head = e; } s->iterate_list_tail = e; s->n_entries++; - assert(s->n_entries >= 1); + pa_assert(s->n_entries >= 1); if (idx) *idx = e->index; @@ -215,8 +225,8 @@ int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) { } void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx) { - idxset_entry **a; - assert(s); + struct idxset_entry **a; + pa_assert(s); if (!(a = array_index(s, idx))) return NULL; @@ -229,13 +239,15 @@ void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx) { void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx) { unsigned h; - idxset_entry *e; - assert(s && p); + struct idxset_entry *e; - assert(s->hash_func); + pa_assert(s); + pa_assert(p); + + pa_assert(s->hash_func); h = s->hash_func(p) % s->hash_table_size; - assert(s->hash_table); + pa_assert(s->hash_table); if (!(e = hash_scan(s, s->hash_table[h], p))) return NULL; @@ -245,13 +257,15 @@ void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx) { return e->data; } -static void remove_entry(pa_idxset *s, idxset_entry *e) { - idxset_entry **a; - assert(s && e); +static void remove_entry(pa_idxset *s, struct idxset_entry *e) { + struct idxset_entry **a; + + pa_assert(s); + pa_assert(e); /* Remove from array */ a = array_index(s, e->index); - assert(a && *a && *a == e); + pa_assert(a && *a && *a == e); *a = NULL; /* Remove from linked list */ @@ -274,17 +288,18 @@ static void remove_entry(pa_idxset *s, idxset_entry *e) { else s->hash_table[e->hash_value] = e->hash_next; - pa_xfree(e); + if (pa_flist_push(PA_STATIC_FLIST_GET(entries), e) < 0) + pa_xfree(e); - assert(s->n_entries >= 1); + pa_assert(s->n_entries >= 1); s->n_entries--; } void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx) { - idxset_entry **a; + struct idxset_entry **a; void *data; - assert(s); + pa_assert(s); if (!(a = array_index(s, idx))) return NULL; @@ -299,14 +314,16 @@ void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx) { } void* pa_idxset_remove_by_data(pa_idxset*s, const void *data, uint32_t *idx) { - idxset_entry *e; + struct idxset_entry *e; unsigned h; void *r; - assert(s->hash_func); + pa_assert(s); + + pa_assert(s->hash_func); h = s->hash_func(data) % s->hash_table_size; - assert(s->hash_table); + pa_assert(s->hash_table); if (!(e = hash_scan(s, s->hash_table[h], data))) return NULL; @@ -320,8 +337,10 @@ void* pa_idxset_remove_by_data(pa_idxset*s, const void *data, uint32_t *idx) { } void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx) { - idxset_entry **a, *e = NULL; - assert(s && idx); + struct idxset_entry **a, *e = NULL; + + pa_assert(s); + pa_assert(idx); if ((a = array_index(s, *idx)) && *a) e = (*a)->iterate_next; @@ -337,7 +356,7 @@ void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx) { } void* pa_idxset_first(pa_idxset *s, uint32_t *idx) { - assert(s); + pa_assert(s); if (!s->iterate_list_head) return NULL; @@ -348,9 +367,10 @@ void* pa_idxset_first(pa_idxset *s, uint32_t *idx) { } void *pa_idxset_next(pa_idxset *s, uint32_t *idx) { - idxset_entry **a, *e = NULL; - assert(s); - assert(idx); + struct idxset_entry **a, *e = NULL; + + pa_assert(s); + pa_assert(idx); if ((a = array_index(s, *idx)) && *a) e = (*a)->iterate_next; @@ -365,13 +385,15 @@ void *pa_idxset_next(pa_idxset *s, uint32_t *idx) { } int pa_idxset_foreach(pa_idxset*s, int (*func)(void *p, uint32_t idx, int *del, void*userdata), void *userdata) { - idxset_entry *e; - assert(s && func); + struct idxset_entry *e; + + pa_assert(s); + pa_assert(func); e = s->iterate_list_head; while (e) { int del = 0, r; - idxset_entry *n = e->iterate_next; + struct idxset_entry *n = e->iterate_next; r = func(e->data, e->index, &del, userdata); @@ -388,12 +410,14 @@ int pa_idxset_foreach(pa_idxset*s, int (*func)(void *p, uint32_t idx, int *del, } unsigned pa_idxset_size(pa_idxset*s) { - assert(s); + pa_assert(s); + return s->n_entries; } int pa_idxset_isempty(pa_idxset *s) { - assert(s); + pa_assert(s); + return s->n_entries == 0; } diff --git a/src/pulsecore/idxset.h b/src/pulsecore/idxset.h index 17a70f4f..5b55cec2 100644 --- a/src/pulsecore/idxset.h +++ b/src/pulsecore/idxset.h @@ -44,11 +44,6 @@ int pa_idxset_trivial_compare_func(const void *a, const void *b); unsigned pa_idxset_string_hash_func(const void *p); int pa_idxset_string_compare_func(const void *a, const void *b); -#define PA_PTR_TO_UINT(p) ((unsigned int) (unsigned long) (p)) -#define PA_UINT_TO_PTR(u) ((void*) (unsigned long) (u)) -#define PA_PTR_TO_UINT32(p) ((uint32_t) PA_PTR_TO_UINT(p)) -#define PA_UINT32_TO_PTR(u) PA_UINT_TO_PTR(u) - typedef unsigned (*pa_hash_func_t)(const void *p); typedef int (*pa_compare_func_t)(const void *a, const void *b); diff --git a/src/pulsecore/inet_ntop.c b/src/pulsecore/inet_ntop.c index 302369f7..041bc09b 100644 --- a/src/pulsecore/inet_ntop.c +++ b/src/pulsecore/inet_ntop.c @@ -47,7 +47,7 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) { switch (af) { case AF_INET: - snprintf(dst, cnt, "%d.%d.%d.%d", + pa_snprintf(dst, cnt, "%d.%d.%d.%d", #ifdef WORDS_BIGENDIAN (int)(in->s_addr >> 24) & 0xff, (int)(in->s_addr >> 16) & 0xff, @@ -61,7 +61,7 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) { #endif break; case AF_INET6: - snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x", + pa_snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x", in6->s6_addr[ 0] << 8 | in6->s6_addr[ 1], in6->s6_addr[ 2] << 8 | in6->s6_addr[ 3], in6->s6_addr[ 4] << 8 | in6->s6_addr[ 5], diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c index 6f58ae75..01f17ab3 100644 --- a/src/pulsecore/iochannel.c +++ b/src/pulsecore/iochannel.c @@ -27,7 +27,6 @@ #endif #include -#include #include #include #include @@ -47,6 +46,7 @@ #include #include #include +#include #include "iochannel.h" @@ -58,21 +58,21 @@ struct pa_iochannel { pa_iochannel_cb_t callback; void*userdata; - int readable; - int writable; - int hungup; + pa_bool_t readable; + pa_bool_t writable; + pa_bool_t hungup; - int no_close; + pa_bool_t no_close; pa_io_event* input_event, *output_event; }; static void enable_mainloop_sources(pa_iochannel *io) { - assert(io); + pa_assert(io); if (io->input_event == io->output_event && io->input_event) { pa_io_event_flags_t f = PA_IO_EVENT_NULL; - assert(io->input_event); + pa_assert(io->input_event); if (!io->readable) f |= PA_IO_EVENT_INPUT; @@ -90,28 +90,28 @@ static void enable_mainloop_sources(pa_iochannel *io) { static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { pa_iochannel *io = userdata; - int changed = 0; + pa_bool_t changed = FALSE; - assert(m); - assert(e); - assert(fd >= 0); - assert(userdata); + pa_assert(m); + pa_assert(e); + pa_assert(fd >= 0); + pa_assert(userdata); if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) { - io->hungup = 1; - changed = 1; + io->hungup = TRUE; + changed = TRUE; } if ((f & PA_IO_EVENT_INPUT) && !io->readable) { - io->readable = 1; - changed = 1; - assert(e == io->input_event); + io->readable = TRUE; + changed = TRUE; + pa_assert(e == io->input_event); } if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) { - io->writable = 1; - changed = 1; - assert(e == io->output_event); + io->writable = TRUE; + changed = TRUE; + pa_assert(e == io->output_event); } if (changed) { @@ -125,8 +125,8 @@ static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_fla pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) { pa_iochannel *io; - assert(m); - assert(ifd >= 0 || ofd >= 0); + pa_assert(m); + pa_assert(ifd >= 0 || ofd >= 0); io = pa_xnew(pa_iochannel, 1); io->ifd = ifd; @@ -136,26 +136,26 @@ pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) { io->userdata = NULL; io->callback = NULL; - io->readable = 0; - io->writable = 0; - io->hungup = 0; - io->no_close = 0; + io->readable = FALSE; + io->writable = FALSE; + io->hungup = FALSE; + io->no_close = FALSE; io->input_event = io->output_event = NULL; if (ifd == ofd) { - assert(ifd >= 0); - pa_make_nonblock_fd(io->ifd); + pa_assert(ifd >= 0); + pa_make_fd_nonblock(io->ifd); io->input_event = io->output_event = m->io_new(m, ifd, PA_IO_EVENT_INPUT|PA_IO_EVENT_OUTPUT, callback, io); } else { if (ifd >= 0) { - pa_make_nonblock_fd(io->ifd); + pa_make_fd_nonblock(io->ifd); io->input_event = m->io_new(m, ifd, PA_IO_EVENT_INPUT, callback, io); } if (ofd >= 0) { - pa_make_nonblock_fd(io->ofd); + pa_make_fd_nonblock(io->ofd); io->output_event = m->io_new(m, ofd, PA_IO_EVENT_OUTPUT, callback, io); } } @@ -164,7 +164,7 @@ pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) { } void pa_iochannel_free(pa_iochannel*io) { - assert(io); + pa_assert(io); if (io->input_event) io->mainloop->io_free(io->input_event); @@ -182,20 +182,20 @@ void pa_iochannel_free(pa_iochannel*io) { pa_xfree(io); } -int pa_iochannel_is_readable(pa_iochannel*io) { - assert(io); +pa_bool_t pa_iochannel_is_readable(pa_iochannel*io) { + pa_assert(io); return io->readable || io->hungup; } -int pa_iochannel_is_writable(pa_iochannel*io) { - assert(io); +pa_bool_t pa_iochannel_is_writable(pa_iochannel*io) { + pa_assert(io); return io->writable && !io->hungup; } -int pa_iochannel_is_hungup(pa_iochannel*io) { - assert(io); +pa_bool_t pa_iochannel_is_hungup(pa_iochannel*io) { + pa_assert(io); return io->hungup; } @@ -203,14 +203,13 @@ int pa_iochannel_is_hungup(pa_iochannel*io) { ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) { ssize_t r; - assert(io); - assert(data); - assert(l); - assert(io->ofd >= 0); + pa_assert(io); + pa_assert(data); + pa_assert(l); + pa_assert(io->ofd >= 0); - r = pa_write(io->ofd, data, l, &io->ofd_type); - if (r >= 0) { - io->writable = 0; + if ((r = pa_write(io->ofd, data, l, &io->ofd_type)) >= 0) { + io->writable = FALSE; enable_mainloop_sources(io); } @@ -220,13 +219,12 @@ ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) { ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) { ssize_t r; - assert(io); - assert(data); - assert(io->ifd >= 0); + pa_assert(io); + pa_assert(data); + pa_assert(io->ifd >= 0); - r = pa_read(io->ifd, data, l, &io->ifd_type); - if (r >= 0) { - io->readable = 0; + if ((r = pa_read(io->ifd, data, l, &io->ifd_type)) >= 0) { + io->readable = FALSE; enable_mainloop_sources(io); } @@ -235,13 +233,13 @@ ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) { #ifdef HAVE_CREDS -int pa_iochannel_creds_supported(pa_iochannel *io) { +pa_bool_t pa_iochannel_creds_supported(pa_iochannel *io) { struct sockaddr_un sa; socklen_t l; - assert(io); - assert(io->ifd >= 0); - assert(io->ofd == io->ifd); + pa_assert(io); + pa_assert(io->ifd >= 0); + pa_assert(io->ofd == io->ifd); l = sizeof(sa); @@ -254,8 +252,8 @@ int pa_iochannel_creds_supported(pa_iochannel *io) { int pa_iochannel_creds_enable(pa_iochannel *io) { int t = 1; - assert(io); - assert(io->ifd >= 0); + pa_assert(io); + pa_assert(io->ifd >= 0); if (setsockopt(io->ifd, SOL_SOCKET, SO_PASSCRED, &t, sizeof(t)) < 0) { pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno)); @@ -273,10 +271,10 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l struct ucred *u; struct cmsghdr *cmsg; - assert(io); - assert(data); - assert(l); - assert(io->ofd >= 0); + pa_assert(io); + pa_assert(data); + pa_assert(l); + pa_assert(io->ofd >= 0); memset(&iov, 0, sizeof(iov)); iov.iov_base = (void*) data; @@ -309,25 +307,25 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l mh.msg_flags = 0; if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) { - io->writable = 0; + io->writable = FALSE; enable_mainloop_sources(io); } return r; } -ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *creds, int *creds_valid) { +ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *creds, pa_bool_t *creds_valid) { ssize_t r; struct msghdr mh; struct iovec iov; uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))]; - assert(io); - assert(data); - assert(l); - assert(io->ifd >= 0); - assert(creds); - assert(creds_valid); + pa_assert(io); + pa_assert(data); + pa_assert(l); + pa_assert(io->ifd >= 0); + pa_assert(creds); + pa_assert(creds_valid); memset(&iov, 0, sizeof(iov)); iov.iov_base = data; @@ -353,17 +351,17 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_cr if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) { struct ucred u; - assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))); + pa_assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))); memcpy(&u, CMSG_DATA(cmsg), sizeof(struct ucred)); creds->gid = u.gid; creds->uid = u.uid; - *creds_valid = 1; + *creds_valid = TRUE; break; } } - io->readable = 0; + io->readable = FALSE; enable_mainloop_sources(io); } @@ -373,46 +371,52 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_cr #endif /* HAVE_CREDS */ void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) { - assert(io); + pa_assert(io); io->callback = _callback; io->userdata = userdata; } -void pa_iochannel_set_noclose(pa_iochannel*io, int b) { - assert(io); +void pa_iochannel_set_noclose(pa_iochannel*io, pa_bool_t b) { + pa_assert(io); - io->no_close = b; + io->no_close = !!b; } void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) { - assert(io); - assert(s); - assert(l); + pa_assert(io); + pa_assert(s); + pa_assert(l); pa_socket_peer_to_string(io->ifd, s, l); } int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) { - assert(io); + pa_assert(io); return pa_socket_set_rcvbuf(io->ifd, l); } int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) { - assert(io); + pa_assert(io); return pa_socket_set_sndbuf(io->ofd, l); } pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) { - assert(io); + pa_assert(io); return io->mainloop; } int pa_iochannel_get_recv_fd(pa_iochannel *io) { - assert(io); + pa_assert(io); return io->ifd; } + +int pa_iochannel_get_send_fd(pa_iochannel *io) { + pa_assert(io); + + return io->ofd; +} diff --git a/src/pulsecore/iochannel.h b/src/pulsecore/iochannel.h index c22fefd3..c9794d99 100644 --- a/src/pulsecore/iochannel.h +++ b/src/pulsecore/iochannel.h @@ -25,10 +25,15 @@ USA. ***/ +#ifndef PACKAGE +#error "Please include config.h before including this file!" +#endif + #include #include #include +#include /* A wrapper around UNIX file descriptors for attaching them to the a main event loop. Everytime new data may be read or be written to @@ -54,20 +59,20 @@ ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l); ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l); #ifdef HAVE_CREDS -int pa_iochannel_creds_supported(pa_iochannel *io); +pa_bool_t pa_iochannel_creds_supported(pa_iochannel *io); int pa_iochannel_creds_enable(pa_iochannel *io); ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const pa_creds *ucred); -ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *ucred, int *creds_valid); +ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *ucred, pa_bool_t *creds_valid); #endif -int pa_iochannel_is_readable(pa_iochannel*io); -int pa_iochannel_is_writable(pa_iochannel*io); -int pa_iochannel_is_hungup(pa_iochannel*io); +pa_bool_t pa_iochannel_is_readable(pa_iochannel*io); +pa_bool_t pa_iochannel_is_writable(pa_iochannel*io); +pa_bool_t pa_iochannel_is_hungup(pa_iochannel*io); /* Don't close the file descirptors when the io channel is freed. By * default the file descriptors are closed. */ -void pa_iochannel_set_noclose(pa_iochannel*io, int b); +void pa_iochannel_set_noclose(pa_iochannel*io, pa_bool_t b); /* Set the callback function that is called whenever data becomes available for read or write */ typedef void (*pa_iochannel_cb_t)(pa_iochannel*io, void *userdata); @@ -83,5 +88,6 @@ int pa_iochannel_socket_set_sndbuf(pa_iochannel*io, size_t l); pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io); int pa_iochannel_get_recv_fd(pa_iochannel *io); +int pa_iochannel_get_send_fd(pa_iochannel *io); #endif diff --git a/src/pulsecore/ioline.c b/src/pulsecore/ioline.c index 07b60bee..5fd2189b 100644 --- a/src/pulsecore/ioline.c +++ b/src/pulsecore/ioline.c @@ -27,14 +27,16 @@ #include #include -#include #include #include #include +#include #include #include +#include +#include #include "ioline.h" @@ -42,10 +44,11 @@ #define READ_SIZE (1024) struct pa_ioline { + PA_REFCNT_DECLARE; + pa_iochannel *io; pa_defer_event *defer_event; pa_mainloop_api *mainloop; - int ref; int dead; char *wbuf; @@ -65,9 +68,10 @@ static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata); pa_ioline* pa_ioline_new(pa_iochannel *io) { pa_ioline *l; - assert(io); + pa_assert(io); l = pa_xnew(pa_ioline, 1); + PA_REFCNT_INIT(l); l->io = io; l->dead = 0; @@ -79,7 +83,6 @@ pa_ioline* pa_ioline_new(pa_iochannel *io) { l->callback = NULL; l->userdata = NULL; - l->ref = 1; l->mainloop = pa_iochannel_get_mainloop_api(io); @@ -94,7 +97,7 @@ pa_ioline* pa_ioline_new(pa_iochannel *io) { } static void ioline_free(pa_ioline *l) { - assert(l); + pa_assert(l); if (l->io) pa_iochannel_free(l->io); @@ -108,24 +111,24 @@ static void ioline_free(pa_ioline *l) { } void pa_ioline_unref(pa_ioline *l) { - assert(l); - assert(l->ref >= 1); + pa_assert(l); + pa_assert(PA_REFCNT_VALUE(l) >= 1); - if ((--l->ref) <= 0) + if (PA_REFCNT_DEC(l) <= 0) ioline_free(l); } pa_ioline* pa_ioline_ref(pa_ioline *l) { - assert(l); - assert(l->ref >= 1); + pa_assert(l); + pa_assert(PA_REFCNT_VALUE(l) >= 1); - l->ref++; + PA_REFCNT_INC(l); return l; } void pa_ioline_close(pa_ioline *l) { - assert(l); - assert(l->ref >= 1); + pa_assert(l); + pa_assert(PA_REFCNT_VALUE(l) >= 1); l->dead = 1; @@ -146,9 +149,9 @@ void pa_ioline_close(pa_ioline *l) { void pa_ioline_puts(pa_ioline *l, const char *c) { size_t len; - assert(l); - assert(l->ref >= 1); - assert(c); + pa_assert(l); + pa_assert(PA_REFCNT_VALUE(l) >= 1); + pa_assert(c); if (l->dead) return; @@ -158,7 +161,7 @@ void pa_ioline_puts(pa_ioline *l, const char *c) { len = BUFFER_LIMIT - l->wbuf_valid_length; if (len) { - assert(l->wbuf_length >= l->wbuf_valid_length); + pa_assert(l->wbuf_length >= l->wbuf_valid_length); /* In case the allocated buffer is too small, enlarge it. */ if (l->wbuf_valid_length + len > l->wbuf_length) { @@ -178,7 +181,7 @@ void pa_ioline_puts(pa_ioline *l, const char *c) { l->wbuf_index = 0; } - assert(l->wbuf_index + l->wbuf_valid_length + len <= l->wbuf_length); + pa_assert(l->wbuf_index + l->wbuf_valid_length + len <= l->wbuf_length); /* Append the new string */ memcpy(l->wbuf + l->wbuf_index + l->wbuf_valid_length, c, len); @@ -189,17 +192,17 @@ void pa_ioline_puts(pa_ioline *l, const char *c) { } void pa_ioline_set_callback(pa_ioline*l, void (*callback)(pa_ioline*io, const char *s, void *userdata), void *userdata) { - assert(l); - assert(l->ref >= 1); + pa_assert(l); + pa_assert(PA_REFCNT_VALUE(l) >= 1); l->callback = callback; l->userdata = userdata; } static void failure(pa_ioline *l, int process_leftover) { - assert(l); - assert(l->ref >= 1); - assert(!l->dead); + pa_assert(l); + pa_assert(PA_REFCNT_VALUE(l) >= 1); + pa_assert(!l->dead); if (process_leftover && l->rbuf_valid_length > 0) { /* Pass the last missing bit to the client */ @@ -220,7 +223,9 @@ static void failure(pa_ioline *l, int process_leftover) { } static void scan_for_lines(pa_ioline *l, size_t skip) { - assert(l && l->ref >= 1 && skip < l->rbuf_valid_length); + pa_assert(l); + pa_assert(PA_REFCNT_VALUE(l) >= 1); + pa_assert(skip < l->rbuf_valid_length); while (!l->dead && l->rbuf_valid_length > skip) { char *e, *p; @@ -255,7 +260,8 @@ static void scan_for_lines(pa_ioline *l, size_t skip) { static int do_write(pa_ioline *l); static int do_read(pa_ioline *l) { - assert(l && l->ref >= 1); + pa_assert(l); + pa_assert(PA_REFCNT_VALUE(l) >= 1); while (!l->dead && pa_iochannel_is_readable(l->io)) { ssize_t r; @@ -289,11 +295,11 @@ static int do_read(pa_ioline *l) { len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length; - assert(len >= READ_SIZE); + pa_assert(len >= READ_SIZE); /* Read some data */ if ((r = pa_iochannel_read(l->io, l->rbuf+l->rbuf_index+l->rbuf_valid_length, len)) <= 0) { - if (r < 0) { + if (r < 0 && errno != ECONNRESET) { pa_log("read(): %s", pa_cstrerror(errno)); failure(l, 0); } else @@ -314,13 +320,19 @@ static int do_read(pa_ioline *l) { /* Try to flush the buffer */ static int do_write(pa_ioline *l) { ssize_t r; - assert(l && l->ref >= 1); + + pa_assert(l); + pa_assert(PA_REFCNT_VALUE(l) >= 1); while (!l->dead && pa_iochannel_is_writable(l->io) && l->wbuf_valid_length) { - if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0) { - pa_log("write(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) <= 0) { + + if (r < 0 && errno != EPIPE) + pa_log("write(): %s", pa_cstrerror(errno)); + failure(l, 0); + return -1; } @@ -337,8 +349,8 @@ static int do_write(pa_ioline *l) { /* Try to flush read/write data */ static void do_work(pa_ioline *l) { - assert(l); - assert(l->ref >= 1); + pa_assert(l); + pa_assert(PA_REFCNT_VALUE(l) >= 1); pa_ioline_ref(l); @@ -358,21 +370,28 @@ static void do_work(pa_ioline *l) { static void io_callback(pa_iochannel*io, void *userdata) { pa_ioline *l = userdata; - assert(io && l && l->ref >= 1); + + pa_assert(io); + pa_assert(l); + pa_assert(PA_REFCNT_VALUE(l) >= 1); do_work(l); } static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata) { pa_ioline *l = userdata; - assert(l && l->ref >= 1 && l->mainloop == m && l->defer_event == e); + + pa_assert(l); + pa_assert(PA_REFCNT_VALUE(l) >= 1); + pa_assert(l->mainloop == m); + pa_assert(l->defer_event == e); do_work(l); } void pa_ioline_defer_close(pa_ioline *l) { - assert(l); - assert(l->ref >= 1); + pa_assert(l); + pa_assert(PA_REFCNT_VALUE(l) >= 1); l->defer_close = 1; @@ -384,8 +403,8 @@ void pa_ioline_printf(pa_ioline *l, const char *format, ...) { char *t; va_list ap; - assert(l); - assert(l->ref >= 1); + pa_assert(l); + pa_assert(PA_REFCNT_VALUE(l) >= 1); va_start(ap, format); t = pa_vsprintf_malloc(format, ap); diff --git a/src/pulsecore/ipacl.c b/src/pulsecore/ipacl.c index a240d2a0..9b22e8f5 100644 --- a/src/pulsecore/ipacl.c +++ b/src/pulsecore/ipacl.c @@ -46,13 +46,13 @@ #include #endif -#include "winsock.h" - #include #include #include #include +#include +#include #ifndef HAVE_INET_PTON #include "inet_pton.h" @@ -77,7 +77,7 @@ pa_ip_acl* pa_ip_acl_new(const char *s) { char *a; pa_ip_acl *acl; - assert(s); + pa_assert(s); acl = pa_xnew(pa_ip_acl, 1); PA_LLIST_HEAD_INIT(struct acl_entry, acl->entries); @@ -91,7 +91,7 @@ pa_ip_acl* pa_ip_acl_new(const char *s) { *slash = 0; slash++; if (pa_atou(slash, &bits) < 0) { - pa_log("failed to parse number of bits: %s", slash); + pa_log_warn("Failed to parse number of bits: %s", slash); goto fail; } } else @@ -102,21 +102,21 @@ pa_ip_acl* pa_ip_acl_new(const char *s) { e.bits = bits == (uint32_t) -1 ? 32 : (int) bits; if (e.bits > 32) { - pa_log("number of bits out of range: %i", e.bits); + pa_log_warn("Number of bits out of range: %i", e.bits); goto fail; } e.family = AF_INET; if (e.bits < 32 && (uint32_t) (ntohl(e.address_ipv4.s_addr) << e.bits) != 0) - pa_log_warn("WARNING: Host part of ACL entry '%s/%u' is not zero!", a, e.bits); + pa_log_warn("Host part of ACL entry '%s/%u' is not zero!", a, e.bits); } else if (inet_pton(AF_INET6, a, &e.address_ipv6) > 0) { e.bits = bits == (uint32_t) -1 ? 128 : (int) bits; if (e.bits > 128) { - pa_log("number of bits out of range: %i", e.bits); + pa_log_warn("Number of bits out of range: %i", e.bits); goto fail; } e.family = AF_INET6; @@ -138,11 +138,11 @@ pa_ip_acl* pa_ip_acl_new(const char *s) { } if (t) - pa_log_warn("WARNING: Host part of ACL entry '%s/%u' is not zero!", a, e.bits); + pa_log_warn("Host part of ACL entry '%s/%u' is not zero!", a, e.bits); } } else { - pa_log("failed to parse address: %s", a); + pa_log_warn("Failed to parse address: %s", a); goto fail; } @@ -162,7 +162,7 @@ fail: } void pa_ip_acl_free(pa_ip_acl *acl) { - assert(acl); + pa_assert(acl); while (acl->entries) { struct acl_entry *e = acl->entries; @@ -178,8 +178,8 @@ int pa_ip_acl_check(pa_ip_acl *acl, int fd) { struct acl_entry *e; socklen_t salen; - assert(acl); - assert(fd >= 0); + pa_assert(acl); + pa_assert(fd >= 0); salen = sizeof(sa); if (getpeername(fd, (struct sockaddr*) &sa, &salen) < 0) diff --git a/src/pulsecore/llist.h b/src/pulsecore/llist.h index 8fc8e22b..e62f15b4 100644 --- a/src/pulsecore/llist.h +++ b/src/pulsecore/llist.h @@ -24,77 +24,86 @@ USA. ***/ -#include +#include /* Some macros for maintaining doubly linked lists */ /* The head of the linked list. Use this in the structure that shall * contain the head of the linked list */ -#define PA_LLIST_HEAD(t,name) t *name +#define PA_LLIST_HEAD(t,name) \ + t *name /* The pointers in the linked list's items. Use this in the item structure */ -#define PA_LLIST_FIELDS(t) t *next, *prev +#define PA_LLIST_FIELDS(t) \ + t *next, *prev /* Initialize the list's head */ -#define PA_LLIST_HEAD_INIT(t,item) do { (item) = (t*) NULL; } while(0) +#define PA_LLIST_HEAD_INIT(t,item) \ + do { \ + (item) = (t*) NULL; } \ + while(0) /* Initialize a list item */ -#define PA_LLIST_INIT(t,item) do { \ - t *_item = (item); \ - assert(_item); \ - _item->prev = _item->next = NULL; \ - } while(0) +#define PA_LLIST_INIT(t,item) \ + do { \ + t *_item = (item); \ + pa_assert(_item); \ + _item->prev = _item->next = NULL; \ + } while(0) /* Prepend an item to the list */ -#define PA_LLIST_PREPEND(t,head,item) do { \ - t **_head = &(head), *_item = (item); \ - assert(_item); \ - if ((_item->next = *_head)) \ - _item->next->prev = _item; \ - _item->prev = NULL; \ - *_head = _item; \ - } while (0) +#define PA_LLIST_PREPEND(t,head,item) \ + do { \ + t **_head = &(head), *_item = (item); \ + pa_assert(_item); \ + if ((_item->next = *_head)) \ + _item->next->prev = _item; \ + _item->prev = NULL; \ + *_head = _item; \ + } while (0) /* Remove an item from the list */ -#define PA_LLIST_REMOVE(t,head,item) do { \ - t **_head = &(head), *_item = (item); \ - assert(_item); \ - if (_item->next) \ - _item->next->prev = _item->prev; \ - if (_item->prev) \ - _item->prev->next = _item->next; \ - else {\ - assert(*_head == _item); \ - *_head = _item->next; \ - } \ - _item->next = _item->prev = NULL; \ - } while(0) - -#define PA_LLIST_FIND_HEAD(t,item,head) \ -do { \ - t **_head = (head), *_item = (item); \ - *_head = _item; \ - assert(_head); \ - while ((*_head)->prev) \ - *_head = (*_head)->prev; \ -} while (0) - -#define PA_LLIST_INSERT_AFTER(t,head,a,b) \ -do { \ - t **_head = &(head), *_a = (a), *_b = (b); \ - assert(_b); \ - if (!_a) { \ - if ((_b->next = *_head)) \ - _b->next->prev = _b; \ - _b->prev = NULL; \ - *_head = _b; \ - } else { \ - if ((_b->next = _a->next)) \ - _b->next->prev = _b; \ - _b->prev = _a; \ - _a->next = _b; \ - } \ -} while (0) - +#define PA_LLIST_REMOVE(t,head,item) \ + do { \ + t **_head = &(head), *_item = (item); \ + pa_assert(_item); \ + if (_item->next) \ + _item->next->prev = _item->prev; \ + if (_item->prev) \ + _item->prev->next = _item->next; \ + else { \ + pa_assert(*_head == _item); \ + *_head = _item->next; \ + } \ + _item->next = _item->prev = NULL; \ + } while(0) + +/* Find the head of the list */ +#define PA_LLIST_FIND_HEAD(t,item,head) \ + do { \ + t **_head = (head), *_item = (item); \ + *_head = _item; \ + pa_assert(_head); \ + while ((*_head)->prev) \ + *_head = (*_head)->prev; \ + } while (0) + +/* Insert an item after another one (a = where, b = what) */ +#define PA_LLIST_INSERT_AFTER(t,head,a,b) \ + do { \ + t **_head = &(head), *_a = (a), *_b = (b); \ + pa_assert(_b); \ + if (!_a) { \ + if ((_b->next = *_head)) \ + _b->next->prev = _b; \ + _b->prev = NULL; \ + *_head = _b; \ + } else { \ + if ((_b->next = _a->next)) \ + _b->next->prev = _b; \ + _b->prev = _a; \ + _a->next = _b; \ + } \ + } while (0) #endif diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c index 0033adb9..c824e84d 100644 --- a/src/pulsecore/log.c +++ b/src/pulsecore/log.c @@ -26,7 +26,6 @@ #include #endif -#include #include #include #include @@ -40,6 +39,7 @@ #include #include +#include #include #include "log.h" @@ -71,24 +71,30 @@ static const char level_to_char[] = { }; void pa_log_set_ident(const char *p) { - if (log_ident) - pa_xfree(log_ident); - if (log_ident_local) - pa_xfree(log_ident_local); + pa_xfree(log_ident); + pa_xfree(log_ident_local); log_ident = pa_xstrdup(p); - log_ident_local = pa_utf8_to_locale(log_ident); - if (!log_ident_local) + if (!(log_ident_local = pa_utf8_to_locale(log_ident))) log_ident_local = pa_xstrdup(log_ident); } +/* To make valgrind shut up. */ +static void ident_destructor(void) PA_GCC_DESTRUCTOR; +static void ident_destructor(void) { + pa_xfree(log_ident); + pa_xfree(log_ident_local); +} + void pa_log_set_maximal_level(pa_log_level_t l) { - assert(l < PA_LOG_LEVEL_MAX); + pa_assert(l < PA_LOG_LEVEL_MAX); + maximal_level = l; } void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t l, const char*s)) { - assert(t == PA_LOG_USER || !func); + pa_assert(t == PA_LOG_USER || !func); + log_target = t; user_log_func = func; } @@ -104,8 +110,8 @@ void pa_log_levelv_meta( const char *e; char *text, *t, *n, *location; - assert(level < PA_LOG_LEVEL_MAX); - assert(format); + pa_assert(level < PA_LOG_LEVEL_MAX); + pa_assert(format); if ((e = getenv(ENV_LOGLEVEL))) maximal_level = atoi(e); @@ -221,6 +227,7 @@ void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { void pa_log_level(pa_log_level_t level, const char *format, ...) { va_list ap; + va_start(ap, format); pa_log_levelv_meta(level, NULL, 0, NULL, format, ap); va_end(ap); diff --git a/src/pulsecore/ltdl-helper.c b/src/pulsecore/ltdl-helper.c new file mode 100644 index 00000000..711396d8 --- /dev/null +++ b/src/pulsecore/ltdl-helper.c @@ -0,0 +1,64 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include + +#include +#include + +#include "ltdl-helper.h" + +pa_void_func_t pa_load_sym(lt_dlhandle handle, const char *module, const char *symbol) { + char *sn, *c; + pa_void_func_t f; + + pa_assert(handle); + pa_assert(module); + pa_assert(symbol); + + if ((f = ((pa_void_func_t) (long) lt_dlsym(handle, symbol)))) + return f; + + /* As the .la files might have been cleansed from the system, we should + * try with the ltdl prefix as well. */ + + sn = pa_sprintf_malloc("%s_LTX_%s", module, symbol); + + for (c = sn; *c; c++) + if (!isalnum(*c)) + *c = '_'; + + f = (pa_void_func_t) (long) lt_dlsym(handle, sn); + pa_xfree(sn); + + return f; +} diff --git a/src/pulsecore/ltdl-helper.h b/src/pulsecore/ltdl-helper.h new file mode 100644 index 00000000..5c7388a1 --- /dev/null +++ b/src/pulsecore/ltdl-helper.h @@ -0,0 +1,34 @@ +#ifndef foopulsecoreltdlhelperhfoo +#define foopulsecoreltdlhelperhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef void (*pa_void_func_t)(void); + +pa_void_func_t pa_load_sym(lt_dlhandle handle, const char*module, const char *symbol); + +#endif + diff --git a/src/pulsecore/macro.h b/src/pulsecore/macro.h new file mode 100644 index 00000000..c6bba437 --- /dev/null +++ b/src/pulsecore/macro.h @@ -0,0 +1,149 @@ +#ifndef foopulsemacrohfoo +#define foopulsemacrohfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include +#include +#include +#include + +#include + +#ifndef PACKAGE +#error "Please include config.h before including this file!" +#endif + +#if defined(PAGE_SIZE) +#define PA_PAGE_SIZE ((size_t) PAGE_SIZE) +#elif defined(PAGESIZE) +#define PA_PAGE_SIZE ((size_t) PAGESIZE) +#elif defined(HAVE_SYSCONF) +#define PA_PAGE_SIZE ((size_t) (sysconf(_SC_PAGE_SIZE))) +#else +/* Let's hope it's like x86. */ +#define PA_PAGE_SIZE ((size_t) 4096) +#endif + +static inline size_t pa_align(size_t l) { + return (((l + sizeof(void*) - 1) / sizeof(void*)) * sizeof(void*)); +} +#define PA_ALIGN(x) (pa_align(x)) + +static inline void* pa_page_align_ptr(const void *p) { + return (void*) (((size_t) p) & ~(PA_PAGE_SIZE-1)); +} +#define PA_PAGE_ALIGN_PTR(x) (pa_page_align_ptr(x)) + +static inline size_t pa_page_align(size_t l) { + return l & ~(PA_PAGE_SIZE-1); +} +#define PA_PAGE_ALIGN(x) (pa_page_align(x)) + +#define PA_ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef CLAMP +#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) +#endif + +/* This type is not intended to be used in exported APIs! Use classic "int" there! */ +#ifdef HAVE_STD_BOOL +typedef _Bool pa_bool_t; +#else +typedef int pa_bool_t; +#endif + +#ifndef FALSE +#define FALSE ((pa_bool_t) 0) +#endif + +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +#ifdef __GNUC__ +#define PA_PRETTY_FUNCTION __PRETTY_FUNCTION__ +#else +#define PA_PRETTY_FUNCTION "" +#endif + +#define pa_return_if_fail(expr) \ + do { \ + if (!(expr)) { \ + pa_log_debug("%s: Assertion <%s> failed.\n", PA_PRETTY_FUNCTION, #expr ); \ + return; \ + } \ + } while(0) + +#define pa_return_val_if_fail(expr, val) \ + do { \ + if (!(expr)) { \ + pa_log_debug("%s: Assertion <%s> failed.\n", PA_PRETTY_FUNCTION, #expr ); \ + return (val); \ + } \ + } while(0) + +#define pa_return_null_if_fail(expr) pa_return_val_if_fail(expr, NULL) + +#define pa_assert assert + +#define pa_assert_not_reached() pa_assert(!"Should not be reached.") + +/* An assert which guarantees side effects of x */ +#ifdef NDEBUG +#define pa_assert_se(x) x +#else +#define pa_assert_se(x) pa_assert(x) +#endif + +#define PA_PTR_TO_UINT(p) ((unsigned int) (unsigned long) (p)) +#define PA_UINT_TO_PTR(u) ((void*) (unsigned long) (u)) + +#define PA_PTR_TO_UINT32(p) ((uint32_t) PA_PTR_TO_UINT(p)) +#define PA_UINT32_TO_PTR(u) PA_UINT_TO_PTR((uint32_t) u) + +#define PA_PTR_TO_INT(p) ((int) PA_PTR_TO_UINT(p)) +#define PA_INT_TO_PTR(u) PA_UINT_TO_PTR((int) u) + +#define PA_PTR_TO_INT32(p) ((int32_t) PA_PTR_TO_UINT(p)) +#define PA_INT32_TO_PTR(u) PA_UINT_TO_PTR((int32_t) u) + +#ifdef OS_IS_WIN32 +#define PA_PATH_SEP "\\" +#define PA_PATH_SEP_CHAR '\\' +#else +#define PA_PATH_SEP "/" +#define PA_PATH_SEP_CHAR '/' +#endif + +#endif diff --git a/src/pulsecore/mcalign.c b/src/pulsecore/mcalign.c index dd1d71f3..8ca7c962 100644 --- a/src/pulsecore/mcalign.c +++ b/src/pulsecore/mcalign.c @@ -27,10 +27,10 @@ #include #include -#include #include #include +#include #include "mcalign.h" @@ -41,7 +41,7 @@ struct pa_mcalign { pa_mcalign *pa_mcalign_new(size_t base) { pa_mcalign *m; - assert(base); + pa_assert(base); m = pa_xnew(pa_mcalign, 1); @@ -53,7 +53,7 @@ pa_mcalign *pa_mcalign_new(size_t base) { } void pa_mcalign_free(pa_mcalign *m) { - assert(m); + pa_assert(m); if (m->leftover.memblock) pa_memblock_unref(m->leftover.memblock); @@ -65,13 +65,13 @@ void pa_mcalign_free(pa_mcalign *m) { } void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { - assert(m); - assert(c); + pa_assert(m); + pa_assert(c); - assert(c->memblock); - assert(c->length > 0); + pa_assert(c->memblock); + pa_assert(c->length > 0); - assert(!m->current.memblock); + pa_assert(!m->current.memblock); /* Append to the leftover memory block */ if (m->leftover.memblock) { @@ -91,9 +91,10 @@ void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { } else { size_t l; + void *lo_data, *m_data; /* We have to copy */ - assert(m->leftover.length < m->base); + pa_assert(m->leftover.length < m->base); l = m->base - m->leftover.length; if (l > c->length) @@ -102,10 +103,15 @@ void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { /* Can we use the current block? */ pa_memchunk_make_writable(&m->leftover, m->base); - memcpy((uint8_t*) m->leftover.memblock->data + m->leftover.index + m->leftover.length, (uint8_t*) c->memblock->data + c->index, l); + lo_data = pa_memblock_acquire(m->leftover.memblock); + m_data = pa_memblock_acquire(c->memblock); + memcpy((uint8_t*) lo_data + m->leftover.index + m->leftover.length, (uint8_t*) m_data + c->index, l); + pa_memblock_release(m->leftover.memblock); + pa_memblock_release(c->memblock); m->leftover.length += l; - assert(m->leftover.length <= m->base && m->leftover.length <= m->leftover.memblock->length); + pa_assert(m->leftover.length <= m->base); + pa_assert(m->leftover.length <= pa_memblock_get_length(m->leftover.memblock)); if (c->length > l) { /* Save the remainder of the memory block */ @@ -128,12 +134,13 @@ void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) { } int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) { - assert(m); - assert(c); + pa_assert(m); + pa_assert(c); /* First test if there's a leftover memory block available */ if (m->leftover.memblock) { - assert(m->leftover.length > 0 && m->leftover.length <= m->base); + pa_assert(m->leftover.length > 0); + pa_assert(m->leftover.length <= m->base); /* The leftover memory block is not yet complete */ if (m->leftover.length < m->base) @@ -155,13 +162,13 @@ int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) { /* Now let's see if there is other data available */ if (m->current.memblock) { size_t l; - assert(m->current.length >= m->base); + pa_assert(m->current.length >= m->base); /* The length of the returned memory block */ l = m->current.length; l /= m->base; l *= m->base; - assert(l > 0); + pa_assert(l > 0); /* Prepare the returned block */ *c = m->current; @@ -169,7 +176,7 @@ int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) { c->length = l; /* Drop that from the current memory block */ - assert(l <= m->current.length); + pa_assert(l <= m->current.length); m->current.index += l; m->current.length -= l; @@ -178,7 +185,7 @@ int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) { pa_memblock_unref(m->current.memblock); else { /* Move the raimainder to leftover */ - assert(m->current.length < m->base && !m->leftover.memblock); + pa_assert(m->current.length < m->base && !m->leftover.memblock); m->leftover = m->current; } @@ -194,10 +201,10 @@ int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) { } size_t pa_mcalign_csize(pa_mcalign *m, size_t l) { - assert(m); - assert(l > 0); + pa_assert(m); + pa_assert(l > 0); - assert(!m->current.memblock); + pa_assert(!m->current.memblock); if (m->leftover.memblock) l += m->leftover.length; diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 6f09a906..99b5a13f 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -14,7 +14,7 @@ PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + Lesser General Public License for more details You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software @@ -28,15 +28,21 @@ #include #include -#include #include #include +#include +#include #include +#include #include #include #include +#include +#include +#include +#include #include "memblock.h" @@ -48,6 +54,32 @@ #define PA_MEMIMPORT_SLOTS_MAX 128 #define PA_MEMIMPORT_SEGMENTS_MAX 16 +struct pa_memblock { + PA_REFCNT_DECLARE; /* the reference counter */ + pa_mempool *pool; + + pa_memblock_type_t type; + int read_only; /* boolean */ + + pa_atomic_ptr_t data; + size_t length; + + pa_atomic_t n_acquired; + pa_atomic_t please_signal; + + union { + struct { + /* If type == PA_MEMBLOCK_USER this points to a function for freeing this memory block */ + pa_free_cb_t free_cb; + } user; + + struct { + uint32_t id; + pa_memimport_segment *segment; + } imported; + } per_type; +}; + struct pa_memimport_segment { pa_memimport *import; pa_shm memory; @@ -55,6 +87,8 @@ struct pa_memimport_segment { }; struct pa_memimport { + pa_mutex *mutex; + pa_mempool *pool; pa_hashmap *segments; pa_hashmap *blocks; @@ -73,9 +107,11 @@ struct memexport_slot { }; struct pa_memexport { + pa_mutex *mutex; pa_mempool *pool; struct memexport_slot slots[PA_MEMEXPORT_SLOTS_MAX]; + PA_LLIST_HEAD(struct memexport_slot, free_slots); PA_LLIST_HEAD(struct memexport_slot, used_slots); unsigned n_init; @@ -95,24 +131,32 @@ struct mempool_slot { }; struct pa_mempool { + pa_semaphore *semaphore; + pa_mutex *mutex; + pa_shm memory; size_t block_size; - unsigned n_blocks, n_init; + unsigned n_blocks; + + pa_atomic_t n_init; PA_LLIST_HEAD(pa_memimport, imports); PA_LLIST_HEAD(pa_memexport, exports); /* A list of free slots that may be reused */ - PA_LLIST_HEAD(struct mempool_slot, free_slots); + pa_flist *free_slots; pa_mempool_stat stat; }; static void segment_detach(pa_memimport_segment *seg); +PA_STATIC_FLIST_DECLARE(unused_memblocks, 0, pa_xfree); + +/* No lock necessary */ static void stat_add(pa_memblock*b) { - assert(b); - assert(b->pool); + pa_assert(b); + pa_assert(b->pool); pa_atomic_inc(&b->pool->stat.n_allocated); pa_atomic_add(&b->pool->stat.allocated_size, b->length); @@ -129,19 +173,20 @@ static void stat_add(pa_memblock*b) { pa_atomic_inc(&b->pool->stat.n_accumulated_by_type[b->type]); } +/* No lock necessary */ static void stat_remove(pa_memblock *b) { - assert(b); - assert(b->pool); + pa_assert(b); + pa_assert(b->pool); - assert(pa_atomic_load(&b->pool->stat.n_allocated) > 0); - assert(pa_atomic_load(&b->pool->stat.allocated_size) >= (int) b->length); + pa_assert(pa_atomic_load(&b->pool->stat.n_allocated) > 0); + pa_assert(pa_atomic_load(&b->pool->stat.allocated_size) >= (int) b->length); pa_atomic_dec(&b->pool->stat.n_allocated); pa_atomic_sub(&b->pool->stat.allocated_size, b->length); if (b->type == PA_MEMBLOCK_IMPORTED) { - assert(pa_atomic_load(&b->pool->stat.n_imported) > 0); - assert(pa_atomic_load(&b->pool->stat.imported_size) >= (int) b->length); + pa_assert(pa_atomic_load(&b->pool->stat.n_imported) > 0); + pa_assert(pa_atomic_load(&b->pool->stat.imported_size) >= (int) b->length); pa_atomic_dec(&b->pool->stat.n_imported); pa_atomic_sub(&b->pool->stat.imported_size, b->length); @@ -152,11 +197,12 @@ static void stat_remove(pa_memblock *b) { static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length); +/* No lock necessary */ pa_memblock *pa_memblock_new(pa_mempool *p, size_t length) { pa_memblock *b; - assert(p); - assert(length > 0); + pa_assert(p); + pa_assert(length > 0); if (!(b = pa_memblock_new_pool(p, length))) b = memblock_new_appended(p, length); @@ -164,56 +210,75 @@ pa_memblock *pa_memblock_new(pa_mempool *p, size_t length) { return b; } +/* No lock necessary */ static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length) { pa_memblock *b; - assert(p); - assert(length > 0); + pa_assert(p); + pa_assert(length > 0); - b = pa_xmalloc(sizeof(pa_memblock) + length); + /* If -1 is passed as length we choose the size for the caller. */ + + if (length == (size_t) -1) + length = p->block_size - PA_ALIGN(sizeof(struct mempool_slot)) - PA_ALIGN(sizeof(pa_memblock)); + + b = pa_xmalloc(PA_ALIGN(sizeof(pa_memblock)) + length); + PA_REFCNT_INIT(b); + b->pool = p; b->type = PA_MEMBLOCK_APPENDED; b->read_only = 0; - PA_REFCNT_INIT(b); + pa_atomic_ptr_store(&b->data, (uint8_t*) b + PA_ALIGN(sizeof(pa_memblock))); b->length = length; - b->data = (uint8_t*) b + sizeof(pa_memblock); - b->pool = p; + pa_atomic_store(&b->n_acquired, 0); + pa_atomic_store(&b->please_signal, 0); stat_add(b); return b; } +/* No lock necessary */ static struct mempool_slot* mempool_allocate_slot(pa_mempool *p) { struct mempool_slot *slot; - assert(p); + pa_assert(p); - if (p->free_slots) { - slot = p->free_slots; - PA_LLIST_REMOVE(struct mempool_slot, p->free_slots, slot); - } else if (p->n_init < p->n_blocks) - slot = (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->block_size * p->n_init++)); - else { - pa_log_debug("Pool full"); - pa_atomic_inc(&p->stat.n_pool_full); - return NULL; + if (!(slot = pa_flist_pop(p->free_slots))) { + int idx; + + /* The free list was empty, we have to allocate a new entry */ + + if ((unsigned) (idx = pa_atomic_inc(&p->n_init)) >= p->n_blocks) + pa_atomic_dec(&p->n_init); + else + slot = (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->block_size * idx)); + + if (!slot) { + pa_log_debug("Pool full"); + pa_atomic_inc(&p->stat.n_pool_full); + return NULL; + } } return slot; } +/* No lock necessary */ static void* mempool_slot_data(struct mempool_slot *slot) { - assert(slot); + pa_assert(slot); - return (uint8_t*) slot + sizeof(struct mempool_slot); + return (uint8_t*) slot + PA_ALIGN(sizeof(struct mempool_slot)); } +/* No lock necessary */ static unsigned mempool_slot_idx(pa_mempool *p, void *ptr) { - assert(p); - assert((uint8_t*) ptr >= (uint8_t*) p->memory.ptr); - assert((uint8_t*) ptr < (uint8_t*) p->memory.ptr + p->memory.size); + pa_assert(p); + + pa_assert((uint8_t*) ptr >= (uint8_t*) p->memory.ptr); + pa_assert((uint8_t*) ptr < (uint8_t*) p->memory.ptr + p->memory.size); return ((uint8_t*) ptr - (uint8_t*) p->memory.ptr) / p->block_size; } +/* No lock necessary */ static struct mempool_slot* mempool_slot_by_ptr(pa_mempool *p, void *ptr) { unsigned idx; @@ -223,189 +288,321 @@ static struct mempool_slot* mempool_slot_by_ptr(pa_mempool *p, void *ptr) { return (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (idx * p->block_size)); } +/* No lock necessary */ pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) { pa_memblock *b = NULL; struct mempool_slot *slot; - assert(p); - assert(length > 0); + pa_assert(p); + pa_assert(length > 0); + + /* If -1 is passed as length we choose the size for the caller: we + * take the largest size that fits in one of our slots. */ - if (p->block_size - sizeof(struct mempool_slot) >= sizeof(pa_memblock) + length) { + if (length == (size_t) -1) + length = pa_mempool_block_size_max(p); + + if (p->block_size - PA_ALIGN(sizeof(struct mempool_slot)) >= PA_ALIGN(sizeof(pa_memblock)) + length) { if (!(slot = mempool_allocate_slot(p))) return NULL; b = mempool_slot_data(slot); b->type = PA_MEMBLOCK_POOL; - b->data = (uint8_t*) b + sizeof(pa_memblock); + pa_atomic_ptr_store(&b->data, (uint8_t*) b + PA_ALIGN(sizeof(pa_memblock))); - } else if (p->block_size - sizeof(struct mempool_slot) >= length) { + } else if (p->block_size - PA_ALIGN(sizeof(struct mempool_slot)) >= length) { if (!(slot = mempool_allocate_slot(p))) return NULL; - b = pa_xnew(pa_memblock, 1); + if (!(b = pa_flist_pop(PA_STATIC_FLIST_GET(unused_memblocks)))) + b = pa_xnew(pa_memblock, 1); + b->type = PA_MEMBLOCK_POOL_EXTERNAL; - b->data = mempool_slot_data(slot); + pa_atomic_ptr_store(&b->data, mempool_slot_data(slot)); + } else { - pa_log_debug("Memory block too large for pool: %u > %u", length, p->block_size - sizeof(struct mempool_slot)); + pa_log_debug("Memory block too large for pool: %lu > %lu", (unsigned long) length, (unsigned long) (p->block_size - PA_ALIGN(sizeof(struct mempool_slot)))); pa_atomic_inc(&p->stat.n_too_large_for_pool); return NULL; } - b->length = length; - b->read_only = 0; PA_REFCNT_INIT(b); b->pool = p; + b->read_only = 0; + b->length = length; + pa_atomic_store(&b->n_acquired, 0); + pa_atomic_store(&b->please_signal, 0); stat_add(b); return b; } +/* No lock necessary */ pa_memblock *pa_memblock_new_fixed(pa_mempool *p, void *d, size_t length, int read_only) { pa_memblock *b; - assert(p); - assert(d); - assert(length > 0); + pa_assert(p); + pa_assert(d); + pa_assert(length != (size_t) -1); + pa_assert(length > 0); - b = pa_xnew(pa_memblock, 1); + if (!(b = pa_flist_pop(PA_STATIC_FLIST_GET(unused_memblocks)))) + b = pa_xnew(pa_memblock, 1); + PA_REFCNT_INIT(b); + b->pool = p; b->type = PA_MEMBLOCK_FIXED; b->read_only = read_only; - PA_REFCNT_INIT(b); + pa_atomic_ptr_store(&b->data, d); b->length = length; - b->data = d; - b->pool = p; + pa_atomic_store(&b->n_acquired, 0); + pa_atomic_store(&b->please_signal, 0); stat_add(b); return b; } +/* No lock necessary */ pa_memblock *pa_memblock_new_user(pa_mempool *p, void *d, size_t length, void (*free_cb)(void *p), int read_only) { pa_memblock *b; - assert(p); - assert(d); - assert(length > 0); - assert(free_cb); + pa_assert(p); + pa_assert(d); + pa_assert(length > 0); + pa_assert(length != (size_t) -1); + pa_assert(free_cb); - b = pa_xnew(pa_memblock, 1); + if (!(b = pa_flist_pop(PA_STATIC_FLIST_GET(unused_memblocks)))) + b = pa_xnew(pa_memblock, 1); + PA_REFCNT_INIT(b); + b->pool = p; b->type = PA_MEMBLOCK_USER; b->read_only = read_only; - PA_REFCNT_INIT(b); + pa_atomic_ptr_store(&b->data, d); b->length = length; - b->data = d; + pa_atomic_store(&b->n_acquired, 0); + pa_atomic_store(&b->please_signal, 0); + b->per_type.user.free_cb = free_cb; - b->pool = p; stat_add(b); return b; } +/* No lock necessary */ +int pa_memblock_is_read_only(pa_memblock *b) { + pa_assert(b); + pa_assert(PA_REFCNT_VALUE(b) > 0); + + return b->read_only && PA_REFCNT_VALUE(b) == 1; +} + +/* No lock necessary */ +int pa_memblock_ref_is_one(pa_memblock *b) { + int r; + + pa_assert(b); + + r = PA_REFCNT_VALUE(b); + pa_assert(r > 0); + + return r == 1; +} + +/* No lock necessary */ +void* pa_memblock_acquire(pa_memblock *b) { + pa_assert(b); + pa_assert(PA_REFCNT_VALUE(b) > 0); + + pa_atomic_inc(&b->n_acquired); + + return pa_atomic_ptr_load(&b->data); +} + +/* No lock necessary, in corner cases locks by its own */ +void pa_memblock_release(pa_memblock *b) { + int r; + pa_assert(b); + pa_assert(PA_REFCNT_VALUE(b) > 0); + + r = pa_atomic_dec(&b->n_acquired); + pa_assert(r >= 1); + + /* Signal a waiting thread that this memblock is no longer used */ + if (r == 1 && pa_atomic_load(&b->please_signal)) + pa_semaphore_post(b->pool->semaphore); +} + +size_t pa_memblock_get_length(pa_memblock *b) { + pa_assert(b); + pa_assert(PA_REFCNT_VALUE(b) > 0); + + return b->length; +} + +pa_mempool* pa_memblock_get_pool(pa_memblock *b) { + pa_assert(b); + pa_assert(PA_REFCNT_VALUE(b) > 0); + + return b->pool; +} + +/* No lock necessary */ pa_memblock* pa_memblock_ref(pa_memblock*b) { - assert(b); - assert(PA_REFCNT_VALUE(b) > 0); + pa_assert(b); + pa_assert(PA_REFCNT_VALUE(b) > 0); PA_REFCNT_INC(b); return b; } -void pa_memblock_unref(pa_memblock*b) { - assert(b); - assert(PA_REFCNT_VALUE(b) > 0); +static void memblock_free(pa_memblock *b) { + pa_assert(b); - if (PA_REFCNT_DEC(b) > 0) - return; + pa_assert(pa_atomic_load(&b->n_acquired) == 0); stat_remove(b); switch (b->type) { case PA_MEMBLOCK_USER : - assert(b->per_type.user.free_cb); - b->per_type.user.free_cb(b->data); + pa_assert(b->per_type.user.free_cb); + b->per_type.user.free_cb(pa_atomic_ptr_load(&b->data)); /* Fall through */ case PA_MEMBLOCK_FIXED: case PA_MEMBLOCK_APPENDED : - pa_xfree(b); + if (pa_flist_push(PA_STATIC_FLIST_GET(unused_memblocks), b) < 0) + pa_xfree(b); + break; case PA_MEMBLOCK_IMPORTED : { pa_memimport_segment *segment; + pa_memimport *import; - segment = b->per_type.imported.segment; - assert(segment); - assert(segment->import); + /* FIXME! This should be implemented lock-free */ - pa_hashmap_remove(segment->import->blocks, PA_UINT32_TO_PTR(b->per_type.imported.id)); - segment->import->release_cb(segment->import, b->per_type.imported.id, segment->import->userdata); + segment = b->per_type.imported.segment; + pa_assert(segment); + import = segment->import; + pa_assert(import); + pa_mutex_lock(import->mutex); + pa_hashmap_remove(import->blocks, PA_UINT32_TO_PTR(b->per_type.imported.id)); if (-- segment->n_blocks <= 0) segment_detach(segment); - pa_xfree(b); + pa_mutex_unlock(import->mutex); + + import->release_cb(import, b->per_type.imported.id, import->userdata); + + if (pa_flist_push(PA_STATIC_FLIST_GET(unused_memblocks), b) < 0) + pa_xfree(b); break; } case PA_MEMBLOCK_POOL_EXTERNAL: case PA_MEMBLOCK_POOL: { struct mempool_slot *slot; + int call_free; - slot = mempool_slot_by_ptr(b->pool, b->data); - assert(slot); + slot = mempool_slot_by_ptr(b->pool, pa_atomic_ptr_load(&b->data)); + pa_assert(slot); - PA_LLIST_PREPEND(struct mempool_slot, b->pool->free_slots, slot); + call_free = b->type == PA_MEMBLOCK_POOL_EXTERNAL; - if (b->type == PA_MEMBLOCK_POOL_EXTERNAL) - pa_xfree(b); + /* The free list dimensions should easily allow all slots + * to fit in, hence try harder if pushing this slot into + * the free list fails */ + while (pa_flist_push(b->pool->free_slots, slot) < 0) + ; + + if (call_free) + if (pa_flist_push(PA_STATIC_FLIST_GET(unused_memblocks), b) < 0) + pa_xfree(b); break; } case PA_MEMBLOCK_TYPE_MAX: default: - abort(); + pa_assert_not_reached(); } } +/* No lock necessary */ +void pa_memblock_unref(pa_memblock*b) { + pa_assert(b); + pa_assert(PA_REFCNT_VALUE(b) > 0); + + if (PA_REFCNT_DEC(b) > 0) + return; + + memblock_free(b); +} + +/* Self locked */ +static void memblock_wait(pa_memblock *b) { + pa_assert(b); + + if (pa_atomic_load(&b->n_acquired) > 0) { + /* We need to wait until all threads gave up access to the + * memory block before we can go on. Unfortunately this means + * that we have to lock and wait here. Sniff! */ + + pa_atomic_inc(&b->please_signal); + + while (pa_atomic_load(&b->n_acquired) > 0) + pa_semaphore_wait(b->pool->semaphore); + + pa_atomic_dec(&b->please_signal); + } +} + +/* No lock necessary. This function is not multiple caller safe! */ static void memblock_make_local(pa_memblock *b) { - assert(b); + pa_assert(b); pa_atomic_dec(&b->pool->stat.n_allocated_by_type[b->type]); - if (b->length <= b->pool->block_size - sizeof(struct mempool_slot)) { + if (b->length <= b->pool->block_size - PA_ALIGN(sizeof(struct mempool_slot))) { struct mempool_slot *slot; if ((slot = mempool_allocate_slot(b->pool))) { void *new_data; /* We can move it into a local pool, perfect! */ + new_data = mempool_slot_data(slot); + memcpy(new_data, pa_atomic_ptr_load(&b->data), b->length); + pa_atomic_ptr_store(&b->data, new_data); + b->type = PA_MEMBLOCK_POOL_EXTERNAL; b->read_only = 0; - new_data = mempool_slot_data(slot); - memcpy(new_data, b->data, b->length); - b->data = new_data; goto finish; } } /* Humm, not enough space in the pool, so lets allocate the memory with malloc() */ - b->type = PA_MEMBLOCK_USER; b->per_type.user.free_cb = pa_xfree; + pa_atomic_ptr_store(&b->data, pa_xmemdup(pa_atomic_ptr_load(&b->data), b->length)); + + b->type = PA_MEMBLOCK_USER; b->read_only = 0; - b->data = pa_xmemdup(b->data, b->length); finish: pa_atomic_inc(&b->pool->stat.n_allocated_by_type[b->type]); pa_atomic_inc(&b->pool->stat.n_accumulated_by_type[b->type]); + memblock_wait(b); } +/* No lock necessary. This function is not multiple caller safe*/ void pa_memblock_unref_fixed(pa_memblock *b) { - assert(b); - assert(PA_REFCNT_VALUE(b) > 0); - assert(b->type == PA_MEMBLOCK_FIXED); + pa_assert(b); + pa_assert(PA_REFCNT_VALUE(b) > 0); + pa_assert(b->type == PA_MEMBLOCK_FIXED); if (PA_REFCNT_VALUE(b) > 1) memblock_make_local(b); @@ -413,20 +610,37 @@ void pa_memblock_unref_fixed(pa_memblock *b) { pa_memblock_unref(b); } +/* No lock necessary. */ +pa_memblock *pa_memblock_will_need(pa_memblock *b) { + void *p; + + pa_assert(b); + pa_assert(PA_REFCNT_VALUE(b) > 0); + + p = pa_memblock_acquire(b); + pa_will_need(p, b->length); + pa_memblock_release(b); + + return b; +} + +/* Self-locked. This function is not multiple-caller safe */ static void memblock_replace_import(pa_memblock *b) { pa_memimport_segment *seg; - assert(b); - assert(b->type == PA_MEMBLOCK_IMPORTED); + pa_assert(b); + pa_assert(b->type == PA_MEMBLOCK_IMPORTED); - assert(pa_atomic_load(&b->pool->stat.n_imported) > 0); - assert(pa_atomic_load(&b->pool->stat.imported_size) >= (int) b->length); + pa_assert(pa_atomic_load(&b->pool->stat.n_imported) > 0); + pa_assert(pa_atomic_load(&b->pool->stat.imported_size) >= (int) b->length); pa_atomic_dec(&b->pool->stat.n_imported); pa_atomic_sub(&b->pool->stat.imported_size, b->length); seg = b->per_type.imported.segment; - assert(seg); - assert(seg->import); + pa_assert(seg); + pa_assert(seg->import); + + pa_mutex_lock(seg->import->mutex); pa_hashmap_remove( seg->import->blocks, @@ -434,51 +648,49 @@ static void memblock_replace_import(pa_memblock *b) { memblock_make_local(b); - if (-- seg->n_blocks <= 0) + if (-- seg->n_blocks <= 0) { + pa_mutex_unlock(seg->import->mutex); segment_detach(seg); + } else + pa_mutex_unlock(seg->import->mutex); } pa_mempool* pa_mempool_new(int shared) { - size_t ps; pa_mempool *p; p = pa_xnew(pa_mempool, 1); -#ifdef HAVE_SYSCONF - ps = (size_t) sysconf(_SC_PAGESIZE); -#elif defined(PAGE_SIZE) - ps = (size_t) PAGE_SIZE; -#else - ps = 4096; /* Let's hope it's like x86. */ -#endif - - p->block_size = (PA_MEMPOOL_SLOT_SIZE/ps)*ps; + p->mutex = pa_mutex_new(TRUE, TRUE); + p->semaphore = pa_semaphore_new(0); - if (p->block_size < ps) - p->block_size = ps; + p->block_size = PA_PAGE_ALIGN(PA_MEMPOOL_SLOT_SIZE); + if (p->block_size < PA_PAGE_SIZE) + p->block_size = PA_PAGE_SIZE; p->n_blocks = PA_MEMPOOL_SLOTS_MAX; - assert(p->block_size > sizeof(struct mempool_slot)); + pa_assert(p->block_size > PA_ALIGN(sizeof(struct mempool_slot))); if (pa_shm_create_rw(&p->memory, p->n_blocks * p->block_size, shared, 0700) < 0) { pa_xfree(p); return NULL; } - p->n_init = 0; + memset(&p->stat, 0, sizeof(p->stat)); + pa_atomic_store(&p->n_init, 0); PA_LLIST_HEAD_INIT(pa_memimport, p->imports); PA_LLIST_HEAD_INIT(pa_memexport, p->exports); - PA_LLIST_HEAD_INIT(struct mempool_slot, p->free_slots); - memset(&p->stat, 0, sizeof(p->stat)); + p->free_slots = pa_flist_new(p->n_blocks*2); return p; } void pa_mempool_free(pa_mempool *p) { - assert(p); + pa_assert(p); + + pa_mutex_lock(p->mutex); while (p->imports) pa_memimport_free(p->imports); @@ -486,30 +698,65 @@ void pa_mempool_free(pa_mempool *p) { while (p->exports) pa_memexport_free(p->exports); - if (pa_atomic_load(&p->stat.n_allocated) > 0) - pa_log_warn("WARNING! Memory pool destroyed but not all memory blocks freed!"); + pa_mutex_unlock(p->mutex); + + pa_flist_free(p->free_slots, NULL); + + if (pa_atomic_load(&p->stat.n_allocated) > 0) { +/* raise(SIGTRAP); */ + pa_log_warn("Memory pool destroyed but not all memory blocks freed! %u remain.", pa_atomic_load(&p->stat.n_allocated)); + } pa_shm_free(&p->memory); + + pa_mutex_free(p->mutex); + pa_semaphore_free(p->semaphore); + pa_xfree(p); } +/* No lock necessary */ const pa_mempool_stat* pa_mempool_get_stat(pa_mempool *p) { - assert(p); + pa_assert(p); return &p->stat; } +/* No lock necessary */ +size_t pa_mempool_block_size_max(pa_mempool *p) { + pa_assert(p); + + return p->block_size - PA_ALIGN(sizeof(struct mempool_slot)) - PA_ALIGN(sizeof(pa_memblock)); +} + +/* No lock necessary */ void pa_mempool_vacuum(pa_mempool *p) { struct mempool_slot *slot; + pa_flist *list; + + pa_assert(p); + + list = pa_flist_new(p->n_blocks*2); - assert(p); + while ((slot = pa_flist_pop(p->free_slots))) + while (pa_flist_push(list, slot) < 0) + ; - for (slot = p->free_slots; slot; slot = slot->next) - pa_shm_punch(&p->memory, (uint8_t*) slot + sizeof(struct mempool_slot) - (uint8_t*) p->memory.ptr, p->block_size - sizeof(struct mempool_slot)); + while ((slot = pa_flist_pop(list))) { + pa_shm_punch(&p->memory, + (uint8_t*) slot - (uint8_t*) p->memory.ptr + PA_ALIGN(sizeof(struct mempool_slot)), + p->block_size - PA_ALIGN(sizeof(struct mempool_slot))); + + while (pa_flist_push(p->free_slots, slot)) + ; + } + + pa_flist_free(list, NULL); } +/* No lock necessary */ int pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id) { - assert(p); + pa_assert(p); if (!p->memory.shared) return -1; @@ -519,8 +766,9 @@ int pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id) { return 0; } +/* No lock necessary */ int pa_mempool_is_shared(pa_mempool *p) { - assert(p); + pa_assert(p); return !!p->memory.shared; } @@ -529,22 +777,27 @@ int pa_mempool_is_shared(pa_mempool *p) { pa_memimport* pa_memimport_new(pa_mempool *p, pa_memimport_release_cb_t cb, void *userdata) { pa_memimport *i; - assert(p); - assert(cb); + pa_assert(p); + pa_assert(cb); i = pa_xnew(pa_memimport, 1); + i->mutex = pa_mutex_new(TRUE, TRUE); i->pool = p; i->segments = pa_hashmap_new(NULL, NULL); i->blocks = pa_hashmap_new(NULL, NULL); i->release_cb = cb; i->userdata = userdata; + pa_mutex_lock(p->mutex); PA_LLIST_PREPEND(pa_memimport, p->imports, i); + pa_mutex_unlock(p->mutex); + return i; } static void memexport_revoke_blocks(pa_memexport *e, pa_memimport *i); +/* Should be called locked */ static pa_memimport_segment* segment_attach(pa_memimport *i, uint32_t shm_id) { pa_memimport_segment* seg; @@ -565,59 +818,79 @@ static pa_memimport_segment* segment_attach(pa_memimport *i, uint32_t shm_id) { return seg; } +/* Should be called locked */ static void segment_detach(pa_memimport_segment *seg) { - assert(seg); + pa_assert(seg); pa_hashmap_remove(seg->import->segments, PA_UINT32_TO_PTR(seg->memory.id)); pa_shm_free(&seg->memory); pa_xfree(seg); } +/* Self-locked. Not multiple-caller safe */ void pa_memimport_free(pa_memimport *i) { pa_memexport *e; pa_memblock *b; - assert(i); + pa_assert(i); + + pa_mutex_lock(i->mutex); + + while ((b = pa_hashmap_get_first(i->blocks))) + memblock_replace_import(b); + + pa_assert(pa_hashmap_size(i->segments) == 0); + + pa_mutex_unlock(i->mutex); + + pa_mutex_lock(i->pool->mutex); /* If we've exported this block further we need to revoke that export */ for (e = i->pool->exports; e; e = e->next) memexport_revoke_blocks(e, i); - while ((b = pa_hashmap_get_first(i->blocks))) - memblock_replace_import(b); + PA_LLIST_REMOVE(pa_memimport, i->pool->imports, i); - assert(pa_hashmap_size(i->segments) == 0); + pa_mutex_unlock(i->pool->mutex); pa_hashmap_free(i->blocks, NULL, NULL); pa_hashmap_free(i->segments, NULL, NULL); - PA_LLIST_REMOVE(pa_memimport, i->pool->imports, i); + pa_mutex_free(i->mutex); + pa_xfree(i); } +/* Self-locked */ pa_memblock* pa_memimport_get(pa_memimport *i, uint32_t block_id, uint32_t shm_id, size_t offset, size_t size) { - pa_memblock *b; + pa_memblock *b = NULL; pa_memimport_segment *seg; - assert(i); + pa_assert(i); + + pa_mutex_lock(i->mutex); if (pa_hashmap_size(i->blocks) >= PA_MEMIMPORT_SLOTS_MAX) - return NULL; + goto finish; if (!(seg = pa_hashmap_get(i->segments, PA_UINT32_TO_PTR(shm_id)))) if (!(seg = segment_attach(i, shm_id))) - return NULL; + goto finish; if (offset+size > seg->memory.size) - return NULL; + goto finish; - b = pa_xnew(pa_memblock, 1); + if (!(b = pa_flist_pop(PA_STATIC_FLIST_GET(unused_memblocks)))) + b = pa_xnew(pa_memblock, 1); + + PA_REFCNT_INIT(b); + b->pool = i->pool; b->type = PA_MEMBLOCK_IMPORTED; b->read_only = 1; - PA_REFCNT_INIT(b); + pa_atomic_ptr_store(&b->data, (uint8_t*) seg->memory.ptr + offset); b->length = size; - b->data = (uint8_t*) seg->memory.ptr + offset; - b->pool = i->pool; + pa_atomic_store(&b->n_acquired, 0); + pa_atomic_store(&b->please_signal, 0); b->per_type.imported.id = block_id; b->per_type.imported.segment = seg; @@ -625,6 +898,10 @@ pa_memblock* pa_memimport_get(pa_memimport *i, uint32_t block_id, uint32_t shm_i seg->n_blocks++; +finish: + pa_mutex_unlock(i->mutex); + + if (b) stat_add(b); return b; @@ -632,26 +909,36 @@ pa_memblock* pa_memimport_get(pa_memimport *i, uint32_t block_id, uint32_t shm_i int pa_memimport_process_revoke(pa_memimport *i, uint32_t id) { pa_memblock *b; - assert(i); + int ret = 0; + pa_assert(i); - if (!(b = pa_hashmap_get(i->blocks, PA_UINT32_TO_PTR(id)))) - return -1; + pa_mutex_lock(i->mutex); + + if (!(b = pa_hashmap_get(i->blocks, PA_UINT32_TO_PTR(id)))) { + ret = -1; + goto finish; + } memblock_replace_import(b); - return 0; + +finish: + pa_mutex_unlock(i->mutex); + + return ret; } /* For sending blocks to other nodes */ pa_memexport* pa_memexport_new(pa_mempool *p, pa_memexport_revoke_cb_t cb, void *userdata) { pa_memexport *e; - assert(p); - assert(cb); + pa_assert(p); + pa_assert(cb); if (!p->memory.shared) return NULL; e = pa_xnew(pa_memexport, 1); + e->mutex = pa_mutex_new(TRUE, TRUE); e->pool = p; PA_LLIST_HEAD_INIT(struct memexport_slot, e->free_slots); PA_LLIST_HEAD_INIT(struct memexport_slot, e->used_slots); @@ -659,50 +946,75 @@ pa_memexport* pa_memexport_new(pa_mempool *p, pa_memexport_revoke_cb_t cb, void e->revoke_cb = cb; e->userdata = userdata; + pa_mutex_lock(p->mutex); PA_LLIST_PREPEND(pa_memexport, p->exports, e); + pa_mutex_unlock(p->mutex); return e; } void pa_memexport_free(pa_memexport *e) { - assert(e); + pa_assert(e); + pa_mutex_lock(e->mutex); while (e->used_slots) pa_memexport_process_release(e, e->used_slots - e->slots); + pa_mutex_unlock(e->mutex); + pa_mutex_lock(e->pool->mutex); PA_LLIST_REMOVE(pa_memexport, e->pool->exports, e); + pa_mutex_unlock(e->pool->mutex); + + pa_mutex_free(e->mutex); pa_xfree(e); } +/* Self-locked */ int pa_memexport_process_release(pa_memexport *e, uint32_t id) { - assert(e); + pa_memblock *b; + + pa_assert(e); + + pa_mutex_lock(e->mutex); if (id >= e->n_init) - return -1; + goto fail; if (!e->slots[id].block) - return -1; + goto fail; + + b = e->slots[id].block; + e->slots[id].block = NULL; + + PA_LLIST_REMOVE(struct memexport_slot, e->used_slots, &e->slots[id]); + PA_LLIST_PREPEND(struct memexport_slot, e->free_slots, &e->slots[id]); + + pa_mutex_unlock(e->mutex); /* pa_log("Processing release for %u", id); */ - assert(pa_atomic_load(&e->pool->stat.n_exported) > 0); - assert(pa_atomic_load(&e->pool->stat.exported_size) >= (int) e->slots[id].block->length); + pa_assert(pa_atomic_load(&e->pool->stat.n_exported) > 0); + pa_assert(pa_atomic_load(&e->pool->stat.exported_size) >= (int) b->length); pa_atomic_dec(&e->pool->stat.n_exported); - pa_atomic_sub(&e->pool->stat.exported_size, e->slots[id].block->length); + pa_atomic_sub(&e->pool->stat.exported_size, b->length); - pa_memblock_unref(e->slots[id].block); - e->slots[id].block = NULL; - - PA_LLIST_REMOVE(struct memexport_slot, e->used_slots, &e->slots[id]); - PA_LLIST_PREPEND(struct memexport_slot, e->free_slots, &e->slots[id]); + pa_memblock_unref(b); return 0; + +fail: + pa_mutex_unlock(e->mutex); + + return -1; } +/* Self-locked */ static void memexport_revoke_blocks(pa_memexport *e, pa_memimport *i) { struct memexport_slot *slot, *next; - assert(e); - assert(i); + pa_assert(e); + pa_assert(i); + + pa_mutex_lock(e->mutex); for (slot = e->used_slots; slot; slot = next) { uint32_t idx; @@ -716,49 +1028,57 @@ static void memexport_revoke_blocks(pa_memexport *e, pa_memimport *i) { e->revoke_cb(e, idx, e->userdata); pa_memexport_process_release(e, idx); } + + pa_mutex_unlock(e->mutex); } +/* No lock necessary */ static pa_memblock *memblock_shared_copy(pa_mempool *p, pa_memblock *b) { pa_memblock *n; - assert(p); - assert(b); + pa_assert(p); + pa_assert(b); if (b->type == PA_MEMBLOCK_IMPORTED || b->type == PA_MEMBLOCK_POOL || b->type == PA_MEMBLOCK_POOL_EXTERNAL) { - assert(b->pool == p); + pa_assert(b->pool == p); return pa_memblock_ref(b); } if (!(n = pa_memblock_new_pool(p, b->length))) return NULL; - memcpy(n->data, b->data, b->length); + memcpy(pa_atomic_ptr_load(&n->data), pa_atomic_ptr_load(&b->data), b->length); return n; } +/* Self-locked */ int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32_t *shm_id, size_t *offset, size_t * size) { pa_shm *memory; struct memexport_slot *slot; + void *data; - assert(e); - assert(b); - assert(block_id); - assert(shm_id); - assert(offset); - assert(size); - assert(b->pool == e->pool); + pa_assert(e); + pa_assert(b); + pa_assert(block_id); + pa_assert(shm_id); + pa_assert(offset); + pa_assert(size); + pa_assert(b->pool == e->pool); if (!(b = memblock_shared_copy(e->pool, b))) return -1; + pa_mutex_lock(e->mutex); + if (e->free_slots) { slot = e->free_slots; PA_LLIST_REMOVE(struct memexport_slot, e->free_slots, slot); - } else if (e->n_init < PA_MEMEXPORT_SLOTS_MAX) { + } else if (e->n_init < PA_MEMEXPORT_SLOTS_MAX) slot = &e->slots[e->n_init++]; - } else { + else { + pa_mutex_unlock(e->mutex); pa_memblock_unref(b); return -1; } @@ -767,24 +1087,29 @@ int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32 slot->block = b; *block_id = slot - e->slots; + pa_mutex_unlock(e->mutex); /* pa_log("Got block id %u", *block_id); */ + data = pa_memblock_acquire(b); + if (b->type == PA_MEMBLOCK_IMPORTED) { - assert(b->per_type.imported.segment); + pa_assert(b->per_type.imported.segment); memory = &b->per_type.imported.segment->memory; } else { - assert(b->type == PA_MEMBLOCK_POOL || b->type == PA_MEMBLOCK_POOL_EXTERNAL); - assert(b->pool); + pa_assert(b->type == PA_MEMBLOCK_POOL || b->type == PA_MEMBLOCK_POOL_EXTERNAL); + pa_assert(b->pool); memory = &b->pool->memory; } - assert(b->data >= memory->ptr); - assert((uint8_t*) b->data + b->length <= (uint8_t*) memory->ptr + memory->size); + pa_assert(data >= memory->ptr); + pa_assert((uint8_t*) data + b->length <= (uint8_t*) memory->ptr + memory->size); *shm_id = memory->id; - *offset = (uint8_t*) b->data - (uint8_t*) memory->ptr; + *offset = (uint8_t*) data - (uint8_t*) memory->ptr; *size = b->length; + pa_memblock_release(b); + pa_atomic_inc(&e->pool->stat.n_exported); pa_atomic_add(&e->pool->stat.exported_size, b->length); diff --git a/src/pulsecore/memblock.h b/src/pulsecore/memblock.h index fe4773d4..c704014a 100644 --- a/src/pulsecore/memblock.h +++ b/src/pulsecore/memblock.h @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -58,45 +59,25 @@ typedef struct pa_memexport pa_memexport; typedef void (*pa_memimport_release_cb_t)(pa_memimport *i, uint32_t block_id, void *userdata); typedef void (*pa_memexport_revoke_cb_t)(pa_memexport *e, uint32_t block_id, void *userdata); -struct pa_memblock { - pa_memblock_type_t type; - int read_only; /* boolean */ - PA_REFCNT_DECLARE; /* the reference counter */ - size_t length; - void *data; - pa_mempool *pool; - - union { - struct { - void (*free_cb)(void *p); /* If type == PA_MEMBLOCK_USER this points to a function for freeing this memory block */ - } user; - - struct { - uint32_t id; - pa_memimport_segment *segment; - } imported; - } per_type; -}; - /* Please note that updates to this structure are not locked, * i.e. n_allocated might be updated at a point in time where * n_accumulated is not yet. Take these values with a grain of salt, - * threy are here for purely statistical reasons.*/ + * they are here for purely statistical reasons.*/ struct pa_mempool_stat { - pa_atomic_int_t n_allocated; - pa_atomic_int_t n_accumulated; - pa_atomic_int_t n_imported; - pa_atomic_int_t n_exported; - pa_atomic_int_t allocated_size; - pa_atomic_int_t accumulated_size; - pa_atomic_int_t imported_size; - pa_atomic_int_t exported_size; - - pa_atomic_int_t n_too_large_for_pool; - pa_atomic_int_t n_pool_full; - - pa_atomic_int_t n_allocated_by_type[PA_MEMBLOCK_TYPE_MAX]; - pa_atomic_int_t n_accumulated_by_type[PA_MEMBLOCK_TYPE_MAX]; + pa_atomic_t n_allocated; + pa_atomic_t n_accumulated; + pa_atomic_t n_imported; + pa_atomic_t n_exported; + pa_atomic_t allocated_size; + pa_atomic_t accumulated_size; + pa_atomic_t imported_size; + pa_atomic_t exported_size; + + pa_atomic_t n_too_large_for_pool; + pa_atomic_t n_pool_full; + + pa_atomic_t n_allocated_by_type[PA_MEMBLOCK_TYPE_MAX]; + pa_atomic_t n_accumulated_by_type[PA_MEMBLOCK_TYPE_MAX]; }; /* Allocate a new memory block of type PA_MEMBLOCK_MEMPOOL or PA_MEMBLOCK_APPENDED, depending on the size */ @@ -120,9 +101,20 @@ pa_memblock* pa_memblock_ref(pa_memblock*b); /* This special unref function has to be called by the owner of the memory of a static memory block when he wants to release all references to the memory. This causes the memory to be copied and -converted into a PA_MEMBLOCK_DYNAMIC type memory block */ +converted into a pool or malloc'ed memory block. Please note that this +function is not multiple caller safe, i.e. needs to be locked +manually if called from more than one thread at the same time. */ void pa_memblock_unref_fixed(pa_memblock*b); +int pa_memblock_is_read_only(pa_memblock *b); +int pa_memblock_ref_is_one(pa_memblock *b); +void* pa_memblock_acquire(pa_memblock *b); +void pa_memblock_release(pa_memblock *b); +size_t pa_memblock_get_length(pa_memblock *b); +pa_mempool * pa_memblock_get_pool(pa_memblock *b); + +pa_memblock *pa_memblock_will_need(pa_memblock *b); + /* The memory block manager */ pa_mempool* pa_mempool_new(int shared); void pa_mempool_free(pa_mempool *p); @@ -130,6 +122,7 @@ const pa_mempool_stat* pa_mempool_get_stat(pa_mempool *p); void pa_mempool_vacuum(pa_mempool *p); int pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id); int pa_mempool_is_shared(pa_mempool *p); +size_t pa_mempool_block_size_max(pa_mempool *p); /* For recieving blocks from other nodes */ pa_memimport* pa_memimport_new(pa_mempool *p, pa_memimport_release_cb_t cb, void *userdata); diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index e31fb6df..a46155a9 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -36,23 +35,29 @@ #include #include +#include +#include #include "memblockq.h" -struct memblock_list { - struct memblock_list *next, *prev; +struct list_item { + struct list_item *next, *prev; int64_t index; pa_memchunk chunk; }; +PA_STATIC_FLIST_DECLARE(list_items, 0, pa_xfree); + struct pa_memblockq { - struct memblock_list *blocks, *blocks_tail; + struct list_item *blocks, *blocks_tail; unsigned n_blocks; size_t maxlength, tlength, base, prebuf, minreq; int64_t read_index, write_index; - enum { PREBUF, RUNNING } state; + pa_bool_t in_prebuf; pa_memblock *silence; pa_mcalign *mcalign; + int64_t missing; + size_t requested; }; pa_memblockq* pa_memblockq_new( @@ -66,8 +71,8 @@ pa_memblockq* pa_memblockq_new( pa_memblockq* bq; - assert(base > 0); - assert(maxlength >= base); + pa_assert(base > 0); + pa_assert(maxlength >= base); bq = pa_xnew(pa_memblockq, 1); bq->blocks = bq->blocks_tail = NULL; @@ -77,13 +82,13 @@ pa_memblockq* pa_memblockq_new( bq->read_index = bq->write_index = idx; pa_log_debug("memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", - (unsigned long)maxlength, (unsigned long)tlength, (unsigned long)base, (unsigned long)prebuf, (unsigned long)minreq); + (unsigned long) maxlength, (unsigned long) tlength, (unsigned long) base, (unsigned long) prebuf, (unsigned long) minreq); bq->maxlength = ((maxlength+base-1)/base)*base; - assert(bq->maxlength >= base); + pa_assert(bq->maxlength >= base); bq->tlength = ((tlength+base-1)/base)*base; - if (!bq->tlength || bq->tlength >= bq->maxlength) + if (bq->tlength <= 0 || bq->tlength > bq->maxlength) bq->tlength = bq->maxlength; bq->prebuf = (prebuf == (size_t) -1) ? bq->tlength/2 : prebuf; @@ -102,15 +107,18 @@ pa_memblockq* pa_memblockq_new( pa_log_debug("memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", (unsigned long)bq->maxlength, (unsigned long)bq->tlength, (unsigned long)bq->base, (unsigned long)bq->prebuf, (unsigned long)bq->minreq); - bq->state = bq->prebuf ? PREBUF : RUNNING; + bq->in_prebuf = bq->prebuf > 0; bq->silence = silence ? pa_memblock_ref(silence) : NULL; bq->mcalign = NULL; + bq->missing = bq->tlength; + bq->requested = 0; + return bq; } void pa_memblockq_free(pa_memblockq* bq) { - assert(bq); + pa_assert(bq); pa_memblockq_flush(bq); @@ -123,11 +131,11 @@ void pa_memblockq_free(pa_memblockq* bq) { pa_xfree(bq); } -static void drop_block(pa_memblockq *bq, struct memblock_list *q) { - assert(bq); - assert(q); +static void drop_block(pa_memblockq *bq, struct list_item *q) { + pa_assert(bq); + pa_assert(q); - assert(bq->n_blocks >= 1); + pa_assert(bq->n_blocks >= 1); if (q->prev) q->prev->next = q->next; @@ -140,15 +148,17 @@ static void drop_block(pa_memblockq *bq, struct memblock_list *q) { bq->blocks_tail = q->prev; pa_memblock_unref(q->chunk.memblock); - pa_xfree(q); + + if (pa_flist_push(PA_STATIC_FLIST_GET(list_items), q) < 0) + pa_xfree(q); bq->n_blocks--; } -static int can_push(pa_memblockq *bq, size_t l) { +static pa_bool_t can_push(pa_memblockq *bq, size_t l) { int64_t end; - assert(bq); + pa_assert(bq); if (bq->read_index > bq->write_index) { size_t d = bq->read_index - bq->write_index; @@ -156,7 +166,7 @@ static int can_push(pa_memblockq *bq, size_t l) { if (l > d) l -= d; else - return 1; + return TRUE; } end = bq->blocks_tail ? bq->blocks_tail->index + bq->blocks_tail->chunk.length : 0; @@ -164,21 +174,21 @@ static int can_push(pa_memblockq *bq, size_t l) { /* Make sure that the list doesn't get too long */ if (bq->write_index + (int64_t)l > end) if (bq->write_index + l - bq->read_index > bq->maxlength) - return 0; + return FALSE; - return 1; + return TRUE; } int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { - - struct memblock_list *q, *n; + struct list_item *q, *n; pa_memchunk chunk; + int64_t old, delta; - assert(bq); - assert(uchunk); - assert(uchunk->memblock); - assert(uchunk->length > 0); - assert(uchunk->index + uchunk->length <= uchunk->memblock->length); + pa_assert(bq); + pa_assert(uchunk); + pa_assert(uchunk->memblock); + pa_assert(uchunk->length > 0); + pa_assert(uchunk->index + uchunk->length <= pa_memblock_get_length(uchunk->memblock)); if (uchunk->length % bq->base) return -1; @@ -186,6 +196,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { if (!can_push(bq, uchunk->length)) return -1; + old = bq->write_index; chunk = *uchunk; if (bq->read_index > bq->write_index) { @@ -198,11 +209,11 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { if (chunk.length > d) { chunk.index += d; chunk.length -= d; - bq->write_index = bq->read_index; + bq->write_index += d; } else { /* We drop the incoming data completely */ bq->write_index += chunk.length; - return 0; + goto finish; } } @@ -212,10 +223,10 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { q = bq->blocks_tail; while (q) { - if (bq->write_index >= q->index + (int64_t)q->chunk.length) + if (bq->write_index >= q->index + (int64_t) q->chunk.length) /* We found the entry where we need to place the new entry immediately after */ break; - else if (bq->write_index + (int64_t)chunk.length <= q->index) { + else if (bq->write_index + (int64_t) chunk.length <= q->index) { /* This entry isn't touched at all, let's skip it */ q = q->prev; } else if (bq->write_index <= q->index && @@ -223,7 +234,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { /* This entry is fully replaced by the new entry, so let's drop it */ - struct memblock_list *p; + struct list_item *p; p = q; q = q->prev; drop_block(bq, p); @@ -234,17 +245,19 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { if (bq->write_index + chunk.length < q->index + q->chunk.length) { /* We need to save the end of this memchunk */ - struct memblock_list *p; + struct list_item *p; size_t d; /* Create a new list entry for the end of thie memchunk */ - p = pa_xnew(struct memblock_list, 1); + if (!(p = pa_flist_pop(PA_STATIC_FLIST_GET(list_items)))) + p = pa_xnew(struct list_item, 1); + p->chunk = q->chunk; pa_memblock_ref(p->chunk.memblock); /* Calculate offset */ d = bq->write_index + chunk.length - q->index; - assert(d > 0); + pa_assert(d > 0); /* Drop it from the new entry */ p->index = q->index + d; @@ -263,7 +276,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { /* Truncate the chunk */ if (!(q->chunk.length = bq->write_index - q->index)) { - struct memblock_list *p; + struct list_item *p; p = q; q = q->prev; drop_block(bq, p); @@ -274,7 +287,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { } else { size_t d; - assert(bq->write_index + (int64_t)chunk.length > q->index && + pa_assert(bq->write_index + (int64_t)chunk.length > q->index && bq->write_index + (int64_t)chunk.length < q->index + (int64_t)q->chunk.length && bq->write_index < q->index); @@ -287,12 +300,11 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { q = q->prev; } - } if (q) { - assert(bq->write_index >= q->index + (int64_t)q->chunk.length); - assert(!q->next || (bq->write_index + (int64_t)chunk.length <= q->next->index)); + pa_assert(bq->write_index >= q->index + (int64_t)q->chunk.length); + pa_assert(!q->next || (bq->write_index + (int64_t)chunk.length <= q->next->index)); /* Try to merge memory blocks */ @@ -302,13 +314,14 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { q->chunk.length += chunk.length; bq->write_index += chunk.length; - return 0; + goto finish; } } else - assert(!bq->blocks || (bq->write_index + (int64_t)chunk.length <= bq->blocks->index)); + pa_assert(!bq->blocks || (bq->write_index + (int64_t)chunk.length <= bq->blocks->index)); + if (!(n = pa_flist_pop(PA_STATIC_FLIST_GET(list_items)))) + n = pa_xnew(struct list_item, 1); - n = pa_xnew(struct memblock_list, 1); n->chunk = chunk; pa_memblock_ref(n->chunk.memblock); n->index = bq->write_index; @@ -328,27 +341,52 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { bq->blocks = n; bq->n_blocks++; + +finish: + + delta = bq->write_index - old; + + if (delta >= bq->requested) { + delta -= bq->requested; + bq->requested = 0; + } else { + bq->requested -= delta; + delta = 0; + } + + bq->missing -= delta; + return 0; } -int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { - assert(bq); - assert(chunk); +static pa_bool_t memblockq_check_prebuf(pa_memblockq *bq) { + pa_assert(bq); - if (bq->state == PREBUF) { + if (bq->in_prebuf) { - /* We need to pre-buffer */ if (pa_memblockq_get_length(bq) < bq->prebuf) - return -1; + return TRUE; - bq->state = RUNNING; + bq->in_prebuf = FALSE; + return FALSE; + } else { - } else if (bq->prebuf > 0 && bq->read_index >= bq->write_index) { + if (bq->prebuf > 0 && bq->read_index >= bq->write_index) { + bq->in_prebuf = TRUE; + return TRUE; + } - /* Buffer underflow protection */ - bq->state = PREBUF; - return -1; + return FALSE; } +} + +int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { + pa_assert(bq); + pa_assert(chunk); + + /* We need to pre-buffer */ + if (memblockq_check_prebuf(bq)) + return -1; /* Do we need to spit out silence? */ if (!bq->blocks || bq->blocks->index > bq->read_index) { @@ -362,8 +400,8 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { if (bq->silence) { chunk->memblock = pa_memblock_ref(bq->silence); - if (!length || length > chunk->memblock->length) - length = chunk->memblock->length; + if (!length || length > pa_memblock_get_length(chunk->memblock)) + length = pa_memblock_get_length(chunk->memblock); chunk->length = length; } else { @@ -382,7 +420,7 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { } /* Ok, let's pass real data to the caller */ - assert(bq->blocks->index == bq->read_index); + pa_assert(bq->blocks->index == bq->read_index); *chunk = bq->blocks->chunk; pa_memblock_ref(chunk->memblock); @@ -390,48 +428,23 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { return 0; } -void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length) { - assert(bq); - assert(length % bq->base == 0); - - assert(!chunk || length <= chunk->length); +void pa_memblockq_drop(pa_memblockq *bq, size_t length) { + int64_t old, delta; + pa_assert(bq); + pa_assert(length % bq->base == 0); - if (chunk) { - - if (bq->blocks && bq->blocks->index == bq->read_index) { - /* The first item in queue is valid */ - - /* Does the chunk match with what the user supplied us? */ - if (memcmp(chunk, &bq->blocks->chunk, sizeof(pa_memchunk)) != 0) - return; - - } else { - size_t l; - - /* The first item in the queue is not yet relevant */ - - assert(!bq->blocks || bq->blocks->index > bq->read_index); - l = bq->blocks ? bq->blocks->index - bq->read_index : 0; - - if (bq->silence) { - - if (!l || l > bq->silence->length) - l = bq->silence->length; - - } - - /* Do the entries still match? */ - if (chunk->index != 0 || chunk->length != l || chunk->memblock != bq->silence) - return; - } - } + old = bq->read_index; while (length > 0) { + /* Do not drop any data when we are in prebuffering mode */ + if (memblockq_check_prebuf(bq)) + break; + if (bq->blocks) { size_t d; - assert(bq->blocks->index >= bq->read_index); + pa_assert(bq->blocks->index >= bq->read_index); d = (size_t) (bq->blocks->index - bq->read_index); @@ -446,7 +459,7 @@ void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length bq->read_index += d; } - assert(bq->blocks->index == bq->read_index); + pa_assert(bq->blocks->index == bq->read_index); if (bq->blocks->chunk.length <= length) { /* We need to drop the full block */ @@ -472,35 +485,25 @@ void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length break; } } + + delta = bq->read_index - old; + bq->missing += delta; } int pa_memblockq_is_readable(pa_memblockq *bq) { - assert(bq); - - if (bq->prebuf > 0) { - size_t l = pa_memblockq_get_length(bq); - - if (bq->state == PREBUF && l < bq->prebuf) - return 0; - - if (l <= 0) - return 0; - } - - return 1; -} + pa_assert(bq); -int pa_memblockq_is_writable(pa_memblockq *bq, size_t length) { - assert(bq); + if (memblockq_check_prebuf(bq)) + return 0; - if (length % bq->base) + if (pa_memblockq_get_length(bq) <= 0) return 0; - return pa_memblockq_get_length(bq) + length <= bq->tlength; + return 1; } size_t pa_memblockq_get_length(pa_memblockq *bq) { - assert(bq); + pa_assert(bq); if (bq->write_index <= bq->read_index) return 0; @@ -510,76 +513,106 @@ size_t pa_memblockq_get_length(pa_memblockq *bq) { size_t pa_memblockq_missing(pa_memblockq *bq) { size_t l; - assert(bq); + pa_assert(bq); if ((l = pa_memblockq_get_length(bq)) >= bq->tlength) return 0; l = bq->tlength - l; - return (l >= bq->minreq) ? l : 0; + + return l >= bq->minreq ? l : 0; } size_t pa_memblockq_get_minreq(pa_memblockq *bq) { - assert(bq); + pa_assert(bq); return bq->minreq; } void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek) { - assert(bq); + int64_t old, delta; + pa_assert(bq); + + old = bq->write_index; switch (seek) { case PA_SEEK_RELATIVE: bq->write_index += offset; - return; + break; case PA_SEEK_ABSOLUTE: bq->write_index = offset; - return; + break; case PA_SEEK_RELATIVE_ON_READ: bq->write_index = bq->read_index + offset; - return; + break; case PA_SEEK_RELATIVE_END: - bq->write_index = (bq->blocks_tail ? bq->blocks_tail->index + (int64_t)bq->blocks_tail->chunk.length : bq->read_index) + offset; - return; + bq->write_index = (bq->blocks_tail ? bq->blocks_tail->index + (int64_t) bq->blocks_tail->chunk.length : bq->read_index) + offset; + break; + default: + pa_assert_not_reached(); } - assert(0); + delta = bq->write_index - old; + + if (delta >= bq->requested) { + delta -= bq->requested; + bq->requested = 0; + } else if (delta >= 0) { + bq->requested -= delta; + delta = 0; + } + + bq->missing -= delta; } void pa_memblockq_flush(pa_memblockq *bq) { - assert(bq); + int64_t old, delta; + pa_assert(bq); while (bq->blocks) drop_block(bq, bq->blocks); - assert(bq->n_blocks == 0); + pa_assert(bq->n_blocks == 0); + old = bq->write_index; bq->write_index = bq->read_index; pa_memblockq_prebuf_force(bq); + + delta = bq->write_index - old; + + if (delta > bq->requested) { + delta -= bq->requested; + bq->requested = 0; + } else if (delta >= 0) { + bq->requested -= delta; + delta = 0; + } + + bq->missing -= delta; } size_t pa_memblockq_get_tlength(pa_memblockq *bq) { - assert(bq); + pa_assert(bq); return bq->tlength; } int64_t pa_memblockq_get_read_index(pa_memblockq *bq) { - assert(bq); + pa_assert(bq); return bq->read_index; } int64_t pa_memblockq_get_write_index(pa_memblockq *bq) { - assert(bq); + pa_assert(bq); return bq->write_index; } int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk) { pa_memchunk rchunk; - assert(bq); - assert(chunk && bq->base); + pa_assert(bq); + pa_assert(chunk); if (bq->base == 1) return pa_memblockq_push(bq, chunk); @@ -606,36 +639,52 @@ int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk) { void pa_memblockq_shorten(pa_memblockq *bq, size_t length) { size_t l; - assert(bq); + pa_assert(bq); l = pa_memblockq_get_length(bq); if (l > length) - pa_memblockq_drop(bq, NULL, l - length); + pa_memblockq_drop(bq, l - length); } void pa_memblockq_prebuf_disable(pa_memblockq *bq) { - assert(bq); + pa_assert(bq); - if (bq->state == PREBUF) - bq->state = RUNNING; + bq->in_prebuf = FALSE; } void pa_memblockq_prebuf_force(pa_memblockq *bq) { - assert(bq); + pa_assert(bq); - if (bq->state == RUNNING && bq->prebuf > 0) - bq->state = PREBUF; + if (!bq->in_prebuf && bq->prebuf > 0) + bq->in_prebuf = TRUE; } size_t pa_memblockq_get_maxlength(pa_memblockq *bq) { - assert(bq); + pa_assert(bq); return bq->maxlength; } size_t pa_memblockq_get_prebuf(pa_memblockq *bq) { - assert(bq); + pa_assert(bq); return bq->prebuf; } + +size_t pa_memblockq_pop_missing(pa_memblockq *bq) { + size_t l; + + pa_assert(bq); + +/* pa_log("pop: %lli", bq->missing); */ + + if (bq->missing <= 0) + return 0; + + l = (size_t) bq->missing; + bq->missing = 0; + bq->requested += l; + + return l; +} diff --git a/src/pulsecore/memblockq.h b/src/pulsecore/memblockq.h index 437c5a41..8c3e70fc 100644 --- a/src/pulsecore/memblockq.h +++ b/src/pulsecore/memblockq.h @@ -62,7 +62,7 @@ typedef struct pa_memblockq pa_memblockq; - minreq: pa_memblockq_missing() will only return values greater than this value. Pass 0 for the default. - - silence: return this memblock whzen reading unitialized data + - silence: return this memblock when reading unitialized data */ pa_memblockq* pa_memblockq_new( int64_t idx, @@ -83,26 +83,30 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *chunk); * you know what you do. */ int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk); -/* Return a copy of the next memory chunk in the queue. It is not removed from the queue */ +/* Return a copy of the next memory chunk in the queue. It is not + * removed from the queue. There are two reasons this function might + * fail: 1. prebuffering is active, 2. queue is empty and no silence + * memblock was passed at initialization. If the queue is not empty, + * but we're currently at a hole in the queue and no silence memblock + * was passed we return the length of the hole in chunk->length. */ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk); -/* Drop the specified bytes from the queue, but only if the first - * chunk in the queue matches the one passed here. If NULL is passed, - * this check isn't done. */ -void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length); +/* Drop the specified bytes from the queue. */ +void pa_memblockq_drop(pa_memblockq *bq, size_t length); /* Test if the pa_memblockq is currently readable, that is, more data than base */ int pa_memblockq_is_readable(pa_memblockq *bq); -/* Test if the pa_memblockq is currently writable for the specified amount of bytes */ -int pa_memblockq_is_writable(pa_memblockq *bq, size_t length); - /* Return the length of the queue in bytes */ size_t pa_memblockq_get_length(pa_memblockq *bq); /* Return how many bytes are missing in queue to the specified fill amount */ size_t pa_memblockq_missing(pa_memblockq *bq); +/* Return the number of bytes that are missing since the last call to + * this function, reset the internal counter to 0. */ +size_t pa_memblockq_pop_missing(pa_memblockq *bq); + /* Returns the minimal request value */ size_t pa_memblockq_get_minreq(pa_memblockq *bq); diff --git a/src/pulsecore/memchunk.c b/src/pulsecore/memchunk.c index 7111e1ec..4e73b636 100644 --- a/src/pulsecore/memchunk.c +++ b/src/pulsecore/memchunk.c @@ -27,40 +27,66 @@ #include #include -#include #include +#include #include +#include +#include #include "memchunk.h" -void pa_memchunk_make_writable(pa_memchunk *c, size_t min) { +pa_memchunk* pa_memchunk_make_writable(pa_memchunk *c, size_t min) { pa_memblock *n; size_t l; + void *tdata, *sdata; - assert(c); - assert(c->memblock); - assert(PA_REFCNT_VALUE(c->memblock) > 0); + pa_assert(c); + pa_assert(c->memblock); - if (PA_REFCNT_VALUE(c->memblock) == 1 && - !c->memblock->read_only && - c->memblock->length >= c->index+min) - return; + if (pa_memblock_ref_is_one(c->memblock) && + !pa_memblock_is_read_only(c->memblock) && + pa_memblock_get_length(c->memblock) >= c->index+min) + return c; l = c->length; if (l < min) l = min; - n = pa_memblock_new(c->memblock->pool, l); - memcpy(n->data, (uint8_t*) c->memblock->data + c->index, c->length); + n = pa_memblock_new(pa_memblock_get_pool(c->memblock), l); + tdata = pa_memblock_acquire(n); + sdata = pa_memblock_acquire(c->memblock); + memcpy(tdata, (uint8_t*) sdata + c->index, c->length); + pa_memblock_release(n); + pa_memblock_release(c->memblock); pa_memblock_unref(c->memblock); c->memblock = n; c->index = 0; + + return c; } -void pa_memchunk_reset(pa_memchunk *c) { - assert(c); +pa_memchunk* pa_memchunk_reset(pa_memchunk *c) { + pa_assert(c); c->memblock = NULL; c->length = c->index = 0; + + return c; +} + +pa_memchunk *pa_memchunk_will_need(const pa_memchunk *c) { + void *p; + + pa_assert(c); + pa_assert(c->memblock); + + /* A version of pa_memblock_will_need() that works on memchunks + * instead of memblocks */ + + p = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index; + pa_will_need(p, c->length); + pa_memblock_release(c->memblock); + + return (pa_memchunk*) c; } diff --git a/src/pulsecore/memchunk.h b/src/pulsecore/memchunk.h index 0b982b6d..e6105ace 100644 --- a/src/pulsecore/memchunk.h +++ b/src/pulsecore/memchunk.h @@ -37,11 +37,16 @@ typedef struct pa_memchunk { /* Make a memchunk writable, i.e. make sure that the caller may have * exclusive access to the memblock and it is not read_only. If needed - * the memblock in the structure is replaced by a copy. */ -void pa_memchunk_make_writable(pa_memchunk *c, size_t min); + * the memblock in the structure is replaced by a copy. If min is not + * 0 it is made sure that the returned memblock is at least of the + * specified size, i.e. is enlarged if necessary. */ +pa_memchunk* pa_memchunk_make_writable(pa_memchunk *c, size_t min); /* Invalidate a memchunk. This does not free the cotaining memblock, * but sets all members to zero. */ -void pa_memchunk_reset(pa_memchunk *c); +pa_memchunk* pa_memchunk_reset(pa_memchunk *c); + +/* Map a memory chunk back into memory if it was swapped out */ +pa_memchunk *pa_memchunk_will_need(const pa_memchunk *c); #endif diff --git a/src/pulsecore/modargs.c b/src/pulsecore/modargs.c index 3733f655..1311af3c 100644 --- a/src/pulsecore/modargs.c +++ b/src/pulsecore/modargs.c @@ -26,7 +26,6 @@ #endif #include -#include #include #include @@ -39,6 +38,7 @@ #include #include #include +#include #include "modargs.h" @@ -48,7 +48,10 @@ struct entry { static int add_key_value(pa_hashmap *map, char *key, char *value, const char* const valid_keys[]) { struct entry *e; - assert(map && key && value); + + pa_assert(map); + pa_assert(key); + pa_assert(value); if (valid_keys) { const char*const* v; @@ -63,10 +66,11 @@ static int add_key_value(pa_hashmap *map, char *key, char *value, const char* co } } - e = pa_xmalloc(sizeof(struct entry)); + e = pa_xnew(struct entry, 1); e->key = key; e->value = value; pa_hashmap_put(map, key, e); + return 0; } @@ -74,7 +78,6 @@ pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) { pa_hashmap *map = NULL; map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - assert(map); if (args) { enum { WHITESPACE, KEY, VALUE_START, VALUE_SIMPLE, VALUE_DOUBLE_QUOTES, VALUE_TICKS } state; @@ -166,10 +169,10 @@ fail: return NULL; } - static void free_func(void *p, PA_GCC_UNUSED void*userdata) { struct entry *e = p; - assert(e); + pa_assert(e); + pa_xfree(e->key); pa_xfree(e->value); pa_xfree(e); @@ -192,7 +195,10 @@ const char *pa_modargs_get_value(pa_modargs *ma, const char *key, const char *de int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value) { const char *v; - assert(ma && key && value); + + pa_assert(ma); + pa_assert(key); + pa_assert(value); if (!(v = pa_modargs_get_value(ma, key, NULL))) return 0; @@ -205,7 +211,10 @@ int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value) { int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value) { const char *v; - assert(ma && key && value); + + pa_assert(ma); + pa_assert(key); + pa_assert(value); if (!(v = pa_modargs_get_value(ma, key, NULL))) return 0; @@ -219,7 +228,10 @@ int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value) { int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value) { const char *v; int r; - assert(ma && key && value); + + pa_assert(ma); + pa_assert(key); + pa_assert(value); if (!(v = pa_modargs_get_value(ma, key, NULL))) return 0; @@ -238,9 +250,9 @@ int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) { const char *format; uint32_t channels; pa_sample_spec ss; - assert(ma && rss); -/* DEBUG_TRAP;*/ + pa_assert(ma); + pa_assert(rss); ss = *rss; if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0) @@ -263,16 +275,16 @@ int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) { return 0; } -int pa_modargs_get_channel_map(pa_modargs *ma, pa_channel_map *rmap) { +int pa_modargs_get_channel_map(pa_modargs *ma, const char *name, pa_channel_map *rmap) { pa_channel_map map; const char *cm; - assert(ma); - assert(rmap); + pa_assert(ma); + pa_assert(rmap); map = *rmap; - if ((cm = pa_modargs_get_value(ma, "channel_map", NULL))) + if ((cm = pa_modargs_get_value(ma, name ? name : "channel_map", NULL))) if (!pa_channel_map_parse(&map, cm)) return -1; @@ -287,9 +299,9 @@ int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *r pa_sample_spec ss; pa_channel_map map; - assert(ma); - assert(rss); - assert(rmap); + pa_assert(ma); + pa_assert(rss); + pa_assert(rmap); ss = *rss; @@ -299,7 +311,7 @@ int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *r if (!pa_channel_map_init_auto(&map, ss.channels, def)) map.channels = 0; - if (pa_modargs_get_channel_map(ma, &map) < 0) + if (pa_modargs_get_channel_map(ma, NULL, &map) < 0) return -1; if (map.channels != ss.channels) diff --git a/src/pulsecore/modargs.h b/src/pulsecore/modargs.h index 77262e1e..aa175885 100644 --- a/src/pulsecore/modargs.h +++ b/src/pulsecore/modargs.h @@ -49,8 +49,8 @@ int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value); /* Return sample spec data from the three arguments "rate", "format" and "channels" */ int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *ss); -/* Return channel map data from the argument "channel_map" */ -int pa_modargs_get_channel_map(pa_modargs *ma, pa_channel_map *map); +/* Return channel map data from the argument "channel_map" if name is NULL, otherwise read from the specified argument */ +int pa_modargs_get_channel_map(pa_modargs *ma, const char *name, pa_channel_map *map); /* Combination of pa_modargs_get_sample_spec() and pa_modargs_get_channel_map(). Not always suitable, since this routine diff --git a/src/pulsecore/modinfo.c b/src/pulsecore/modinfo.c index 58394e59..da2df653 100644 --- a/src/pulsecore/modinfo.c +++ b/src/pulsecore/modinfo.c @@ -26,12 +26,13 @@ #endif #include -#include #include #include #include +#include +#include #include "modinfo.h" @@ -40,30 +41,24 @@ #define PA_SYMBOL_USAGE "pa__get_usage" #define PA_SYMBOL_VERSION "pa__get_version" -/* lt_dlsym() violates ISO C, so confide the breakage into this function to - * avoid warnings. */ -typedef void (*fnptr)(void); -static inline fnptr lt_dlsym_fn(lt_dlhandle handle, const char *symbol) { - return (fnptr) (long) lt_dlsym(handle, symbol); -} - -pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl) { +pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl, const char *module_name) { pa_modinfo *i; const char* (*func)(void); - assert(dl); + + pa_assert(dl); i = pa_xnew0(pa_modinfo, 1); - if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_AUTHOR))) + if ((func = (const char* (*)(void)) pa_load_sym(dl, module_name, PA_SYMBOL_AUTHOR))) i->author = pa_xstrdup(func()); - if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_DESCRIPTION))) + if ((func = (const char* (*)(void)) pa_load_sym(dl, module_name, PA_SYMBOL_DESCRIPTION))) i->description = pa_xstrdup(func()); - if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_USAGE))) + if ((func = (const char* (*)(void)) pa_load_sym(dl, module_name, PA_SYMBOL_USAGE))) i->usage = pa_xstrdup(func()); - if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_VERSION))) + if ((func = (const char* (*)(void)) pa_load_sym(dl, module_name, PA_SYMBOL_VERSION))) i->version = pa_xstrdup(func()); return i; @@ -72,21 +67,23 @@ pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl) { pa_modinfo *pa_modinfo_get_by_name(const char *name) { lt_dlhandle dl; pa_modinfo *i; - assert(name); + + pa_assert(name); if (!(dl = lt_dlopenext(name))) { pa_log("Failed to open module \"%s\": %s", name, lt_dlerror()); return NULL; } - i = pa_modinfo_get_by_handle(dl); + i = pa_modinfo_get_by_handle(dl, name); lt_dlclose(dl); return i; } void pa_modinfo_free(pa_modinfo *i) { - assert(i); + pa_assert(i); + pa_xfree(i->author); pa_xfree(i->description); pa_xfree(i->usage); diff --git a/src/pulsecore/modinfo.h b/src/pulsecore/modinfo.h index 3ee33ede..02e536c6 100644 --- a/src/pulsecore/modinfo.h +++ b/src/pulsecore/modinfo.h @@ -34,7 +34,7 @@ typedef struct pa_modinfo { } pa_modinfo; /* Read meta data from an libtool handle */ -pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl); +pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl, const char *module_name); /* Read meta data from a module file */ pa_modinfo *pa_modinfo_get_by_name(const char *name); diff --git a/src/pulsecore/module.c b/src/pulsecore/module.c index 09b15b8b..dce91a71 100644 --- a/src/pulsecore/module.c +++ b/src/pulsecore/module.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -40,6 +39,8 @@ #include #include #include +#include +#include #include "module.h" @@ -48,69 +49,31 @@ #define UNLOAD_POLL_TIME 2 -/* lt_dlsym() violates ISO C, so confide the breakage into this function to - * avoid warnings. */ -typedef void (*fnptr)(void); -static inline fnptr lt_dlsym_fn(lt_dlhandle handle, const char *symbol) { - return (fnptr) (long) lt_dlsym(handle, symbol); -} - static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - pa_core *c = userdata; + pa_core *c = PA_CORE(userdata); struct timeval ntv; - assert(c && c->mainloop == m && c->module_auto_unload_event == e); + + pa_core_assert_ref(c); + pa_assert(c->mainloop == m); + pa_assert(c->module_auto_unload_event == e); pa_module_unload_unused(c); pa_gettimeofday(&ntv); - ntv.tv_sec += UNLOAD_POLL_TIME; + pa_timeval_add(&ntv, UNLOAD_POLL_TIME*1000000); m->time_restart(e, &ntv); } -static inline fnptr load_sym(lt_dlhandle handle, const char *module, const char *symbol) { - char *buffer, *ch; - size_t buflen; - fnptr res; - - res = lt_dlsym_fn(handle, symbol); - if (res) - return res; - - /* As the .la files might have been cleansed from the system, we should - * try with the ltdl prefix as well. */ - - buflen = strlen(symbol) + strlen(module) + strlen("_LTX_") + 1; - buffer = pa_xmalloc(buflen); - assert(buffer); - - strcpy(buffer, module); - - for (ch = buffer;*ch != '\0';ch++) { - if (!isalnum(*ch)) - *ch = '_'; - } - - strcat(buffer, "_LTX_"); - strcat(buffer, symbol); - - res = lt_dlsym_fn(handle, buffer); - - pa_xfree(buffer); - - return res; -} - pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { pa_module *m = NULL; - int r; - assert(c && name); + pa_assert(c); + pa_assert(name); if (c->disallow_module_loading) goto fail; - m = pa_xmalloc(sizeof(pa_module)); - + m = pa_xnew(pa_module, 1); m->name = pa_xstrdup(name); m->argument = pa_xstrdup(argument); @@ -119,24 +82,19 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { goto fail; } - if (!(m->init = (int (*)(pa_core *_c, pa_module*_m)) load_sym(m->dl, name, PA_SYMBOL_INIT))) { + if (!(m->init = (int (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_INIT))) { pa_log("Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.", name); goto fail; } - if (!(m->done = (void (*)(pa_core *_c, pa_module*_m)) load_sym(m->dl, name, PA_SYMBOL_DONE))) { - pa_log("Failed to load module \"%s\": symbol \""PA_SYMBOL_DONE"\" not found.", name); - goto fail; - } - + m->done = (void (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_DONE); m->userdata = NULL; m->core = c; m->n_used = -1; m->auto_unload = 0; m->unload_requested = 0; - assert(m->init); - if (m->init(c, m) < 0) { + if (m->init(m) < 0) { pa_log_error("Failed to load module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : ""); goto fail; } @@ -147,14 +105,12 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { if (!c->module_auto_unload_event) { struct timeval ntv; pa_gettimeofday(&ntv); - ntv.tv_sec += UNLOAD_POLL_TIME; + pa_timeval_add(&ntv, UNLOAD_POLL_TIME*1000000); c->module_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); } - assert(c->module_auto_unload_event); - assert(c->modules); - r = pa_idxset_put(c->modules, m, &m->index); - assert(r >= 0 && m->index != PA_IDXSET_INVALID); + pa_assert_se(pa_idxset_put(c->modules, m, &m->index) >= 0); + pa_assert(m->index != PA_IDXSET_INVALID); pa_log_info("Loaded \"%s\" (index: #%u; argument: \"%s\").", m->name, m->index, m->argument ? m->argument : ""); @@ -178,14 +134,16 @@ fail: } static void pa_module_free(pa_module *m) { - assert(m && m->done && m->core); + pa_assert(m); + pa_assert(m->core); if (m->core->disallow_module_loading) return; pa_log_info("Unloading \"%s\" (index: #%u).", m->name, m->index); - m->done(m->core, m); + if (m->done) + m->done(m); lt_dlclose(m->dl); @@ -199,9 +157,10 @@ static void pa_module_free(pa_module *m) { } void pa_module_unload(pa_core *c, pa_module *m) { - assert(c && m); + pa_assert(c); + pa_assert(m); - assert(c->modules); + pa_assert(c->modules); if (!(m = pa_idxset_remove_by_data(c->modules, m, NULL))) return; @@ -210,9 +169,9 @@ void pa_module_unload(pa_core *c, pa_module *m) { void pa_module_unload_by_index(pa_core *c, uint32_t idx) { pa_module *m; - assert(c && idx != PA_IDXSET_INVALID); + pa_assert(c); + pa_assert(idx != PA_IDXSET_INVALID); - assert(c->modules); if (!(m = pa_idxset_remove_by_index(c->modules, idx))) return; @@ -221,13 +180,14 @@ void pa_module_unload_by_index(pa_core *c, uint32_t idx) { static void free_callback(void *p, PA_GCC_UNUSED void *userdata) { pa_module *m = p; - assert(m); + pa_assert(m); pa_module_free(m); } void pa_module_unload_all(pa_core *c) { pa_module *m; - assert(c); + + pa_assert(c); if (!c->modules) return; @@ -252,7 +212,10 @@ void pa_module_unload_all(pa_core *c) { static int unused_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void *userdata) { pa_module *m = p; time_t *now = userdata; - assert(p && del && now); + + pa_assert(m); + pa_assert(del); + pa_assert(now); if (m->n_used == 0 && m->auto_unload && m->last_used_time+m->core->module_idle_time <= *now) { pa_module_free(m); @@ -264,7 +227,7 @@ static int unused_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void * void pa_module_unload_unused(pa_core *c) { time_t now; - assert(c); + pa_assert(c); if (!c->modules) return; @@ -275,7 +238,7 @@ void pa_module_unload_unused(pa_core *c) { static int unload_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, PA_GCC_UNUSED void *userdata) { pa_module *m = p; - assert(m); + pa_assert(m); if (m->unload_requested) { pa_module_free(m); @@ -286,18 +249,19 @@ static int unload_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, PA_GCC } static void defer_cb(pa_mainloop_api*api, pa_defer_event *e, void *userdata) { - pa_core *core = userdata; + pa_core *core = PA_CORE(userdata); + + pa_core_assert_ref(core); api->defer_enable(e, 0); if (!core->modules) return; pa_idxset_foreach(core->modules, unload_callback, NULL); - } void pa_module_unload_request(pa_module *m) { - assert(m); + pa_assert(m); m->unload_requested = 1; @@ -308,19 +272,19 @@ void pa_module_unload_request(pa_module *m) { } void pa_module_set_used(pa_module*m, int used) { - assert(m); + pa_assert(m); if (m->n_used != used) pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_CHANGE, m->index); - if (m->n_used != used && used == 0) + if (used == 0 && m->n_used > 0) time(&m->last_used_time); m->n_used = used; } pa_modinfo *pa_module_get_info(pa_module *m) { - assert(m); + pa_assert(m); - return pa_modinfo_get_by_handle(m->dl); + return pa_modinfo_get_by_handle(m->dl, m->name); } diff --git a/src/pulsecore/module.h b/src/pulsecore/module.h index 750dfaa8..7a93a071 100644 --- a/src/pulsecore/module.h +++ b/src/pulsecore/module.h @@ -39,8 +39,8 @@ struct pa_module { lt_dlhandle dl; - int (*init)(pa_core *c, pa_module*m); - void (*done)(pa_core *c, pa_module*m); + int (*init)(pa_module*m); + void (*done)(pa_module*m); void *userdata; @@ -62,9 +62,9 @@ void pa_module_unload_request(pa_module *m); void pa_module_set_used(pa_module*m, int used); -#define PA_MODULE_AUTHOR(s) const char * pa__get_author(void) { return s; } -#define PA_MODULE_DESCRIPTION(s) const char * pa__get_description(void) { return s; } -#define PA_MODULE_USAGE(s) const char * pa__get_usage(void) { return s; } +#define PA_MODULE_AUTHOR(s) const char *pa__get_author(void) { return s; } +#define PA_MODULE_DESCRIPTION(s) const char *pa__get_description(void) { return s; } +#define PA_MODULE_USAGE(s) const char *pa__get_usage(void) { return s; } #define PA_MODULE_VERSION(s) const char * pa__get_version(void) { return s; } pa_modinfo *pa_module_get_info(pa_module *m); diff --git a/src/pulsecore/msgobject.c b/src/pulsecore/msgobject.c new file mode 100644 index 00000000..f54e69f2 --- /dev/null +++ b/src/pulsecore/msgobject.c @@ -0,0 +1,49 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "msgobject.h" + +PA_DEFINE_CHECK_TYPE(pa_msgobject, pa_object); + +pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_name, int (*check_type)(const char *type_name)) { + pa_msgobject *o; + + pa_assert(size > sizeof(pa_msgobject)); + pa_assert(type_name); + + if (!check_type) + check_type = pa_msgobject_check_type; + + pa_assert(check_type(type_name)); + pa_assert(check_type("pa_object")); + pa_assert(check_type("pa_msgobject")); + + o = PA_MSGOBJECT(pa_object_new_internal(size, type_name, check_type)); + o->process_msg = NULL; + return o; +} diff --git a/src/pulsecore/msgobject.h b/src/pulsecore/msgobject.h new file mode 100644 index 00000000..8221cc33 --- /dev/null +++ b/src/pulsecore/msgobject.h @@ -0,0 +1,54 @@ +#ifndef foopulsemsgobjecthfoo +#define foopulsemsgobjecthfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include +#include +#include +#include + +typedef struct pa_msgobject pa_msgobject; + +struct pa_msgobject { + pa_object parent; + int (*process_msg)(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk); +}; + +pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_name, int (*check_type)(const char *type_name)); + +int pa_msgobject_check_type(const char *type); + +#define pa_msgobject_new(type) ((type*) pa_msgobject_new_internal(sizeof(type), #type, type##_check_type)) +#define pa_msgobject_free ((void (*) (pa_msgobject* o)) pa_object_free) + +#define PA_MSGOBJECT(o) pa_msgobject_cast(o) + +PA_DECLARE_CLASS(pa_msgobject); + +#endif diff --git a/src/pulsecore/mutex-posix.c b/src/pulsecore/mutex-posix.c index 52e731b3..1b13ede1 100644 --- a/src/pulsecore/mutex-posix.c +++ b/src/pulsecore/mutex-posix.c @@ -25,20 +25,16 @@ #include #endif -#include #include - -#include +#include #include +#include +#include +#include #include "mutex.h" -#define ASSERT_SUCCESS(x) do { \ - int _r = (x); \ - assert(_r == 0); \ -} while(0) - struct pa_mutex { pthread_mutex_t mutex; }; @@ -47,68 +43,88 @@ struct pa_cond { pthread_cond_t cond; }; -pa_mutex* pa_mutex_new(int recursive) { +pa_mutex* pa_mutex_new(pa_bool_t recursive, pa_bool_t inherit_priority) { pa_mutex *m; pthread_mutexattr_t attr; + int r; - pthread_mutexattr_init(&attr); + pa_assert_se(pthread_mutexattr_init(&attr) == 0); if (recursive) - ASSERT_SUCCESS(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)); + pa_assert_se(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) == 0); + +#ifdef HAVE_PTHREAD_PRIO_INHERIT + if (inherit_priority) + pa_assert_se(pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT) == 0); +#endif m = pa_xnew(pa_mutex, 1); - ASSERT_SUCCESS(pthread_mutex_init(&m->mutex, &attr)); +#ifndef HAVE_PTHREAD_PRIO_INHERIT + pa_assert_se(pthread_mutex_init(&m->mutex, &attr) == 0); + +#else + if ((r = pthread_mutex_init(&m->mutex, &attr))) { + + /* If this failed, then this was probably due to non-available + * priority inheritance. In which case we fall back to normal + * mutexes. */ + pa_assert(r == ENOTSUP && inherit_priority); + + pa_assert_se(pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_NONE) == 0); + pa_assert_se(pthread_mutex_init(&m->mutex, &attr) == 0); + } +#endif + return m; } void pa_mutex_free(pa_mutex *m) { - assert(m); + pa_assert(m); - ASSERT_SUCCESS(pthread_mutex_destroy(&m->mutex)); + pa_assert_se(pthread_mutex_destroy(&m->mutex) == 0); pa_xfree(m); } void pa_mutex_lock(pa_mutex *m) { - assert(m); + pa_assert(m); - ASSERT_SUCCESS(pthread_mutex_lock(&m->mutex)); + pa_assert_se(pthread_mutex_lock(&m->mutex) == 0); } void pa_mutex_unlock(pa_mutex *m) { - assert(m); + pa_assert(m); - ASSERT_SUCCESS(pthread_mutex_unlock(&m->mutex)); + pa_assert_se(pthread_mutex_unlock(&m->mutex) == 0); } pa_cond *pa_cond_new(void) { pa_cond *c; c = pa_xnew(pa_cond, 1); - - ASSERT_SUCCESS(pthread_cond_init(&c->cond, NULL)); + pa_assert_se(pthread_cond_init(&c->cond, NULL) == 0); return c; } void pa_cond_free(pa_cond *c) { - assert(c); + pa_assert(c); - ASSERT_SUCCESS(pthread_cond_destroy(&c->cond)); + pa_assert_se(pthread_cond_destroy(&c->cond) == 0); pa_xfree(c); } void pa_cond_signal(pa_cond *c, int broadcast) { - assert(c); + pa_assert(c); if (broadcast) - ASSERT_SUCCESS(pthread_cond_broadcast(&c->cond)); + pa_assert_se(pthread_cond_broadcast(&c->cond) == 0); else - ASSERT_SUCCESS(pthread_cond_signal(&c->cond)); + pa_assert_se(pthread_cond_signal(&c->cond) == 0); } int pa_cond_wait(pa_cond *c, pa_mutex *m) { - assert(c); - assert(m); + pa_assert(c); + pa_assert(m); return pthread_cond_wait(&c->cond, &m->mutex); } diff --git a/src/pulsecore/mutex-win32.c b/src/pulsecore/mutex-win32.c index 1f16e24c..77d63d15 100644 --- a/src/pulsecore/mutex-win32.c +++ b/src/pulsecore/mutex-win32.c @@ -40,7 +40,7 @@ struct pa_cond { pa_hashmap *wait_events; }; -pa_mutex* pa_mutex_new(int recursive) { +pa_mutex* pa_mutex_new(pa_bool_t recursive, pa_bool_t inherit_priority) { pa_mutex *m; m = pa_xnew(pa_mutex, 1); diff --git a/src/pulsecore/mutex.h b/src/pulsecore/mutex.h index b2e34c07..72e88781 100644 --- a/src/pulsecore/mutex.h +++ b/src/pulsecore/mutex.h @@ -24,9 +24,17 @@ USA. ***/ +#include + typedef struct pa_mutex pa_mutex; -pa_mutex* pa_mutex_new(int recursive); +/* Please think twice before enabling priority inheritance. This is no + * magic wand! Use it only when the potentially priorized threads are + * good candidates for it. Don't use this blindly! Also, note that + * only very few operating systems actually implement this, hence this + * is merely a hint. */ +pa_mutex* pa_mutex_new(pa_bool_t recursive, pa_bool_t inherit_priority); + void pa_mutex_free(pa_mutex *m); void pa_mutex_lock(pa_mutex *m); void pa_mutex_unlock(pa_mutex *m); diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c index 7f66af05..fe2be467 100644 --- a/src/pulsecore/namereg.c +++ b/src/pulsecore/namereg.c @@ -27,7 +27,6 @@ #include #include -#include #include #include @@ -38,6 +37,7 @@ #include #include #include +#include #include "namereg.h" @@ -90,23 +90,22 @@ static char* cleanup_name(const char *name) { } void pa_namereg_free(pa_core *c) { - assert(c); + pa_assert(c); if (!c->namereg) return; - assert(pa_hashmap_size(c->namereg) == 0); + pa_assert(pa_hashmap_size(c->namereg) == 0); pa_hashmap_free(c->namereg, NULL, NULL); } const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, int fail) { struct namereg_entry *e; char *n = NULL; - int r; - assert(c); - assert(name); - assert(data); + pa_assert(c); + pa_assert(name); + pa_assert(data); if (!*name) return NULL; @@ -142,7 +141,7 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t k = pa_xnew(char, l+4); for (i = 2; i <= 99; i++) { - snprintf(k, l+4, "%s.%u", name, i); + pa_snprintf(k, l+4, "%s.%u", name, i); if (!(e = pa_hashmap_get(c->namereg, k))) break; @@ -163,8 +162,7 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t e->name = n ? n : pa_xstrdup(name); e->data = data; - r = pa_hashmap_put(c->namereg, e->name, e); - assert (r >= 0); + pa_assert_se(pa_hashmap_put(c->namereg, e->name, e) >= 0); return e->name; } @@ -172,11 +170,10 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t void pa_namereg_unregister(pa_core *c, const char *name) { struct namereg_entry *e; - assert(c); - assert(name); + pa_assert(c); + pa_assert(name); - e = pa_hashmap_remove(c->namereg, name); - assert(e); + pa_assert_se(e = pa_hashmap_remove(c->namereg, name)); pa_xfree(e->name); pa_xfree(e); @@ -185,7 +182,7 @@ void pa_namereg_unregister(pa_core *c, const char *name) { void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int autoload) { struct namereg_entry *e; uint32_t idx; - assert(c); + pa_assert(c); if (!name) { @@ -245,8 +242,8 @@ void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int a int pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type) { char **s; - assert(c); - assert(type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE); + pa_assert(c); + pa_assert(type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE); s = type == PA_NAMEREG_SINK ? &c->default_sink_name : &c->default_source_name; @@ -269,7 +266,7 @@ int pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type) const char *pa_namereg_get_default_sink_name(pa_core *c) { pa_sink *s; - assert(c); + pa_assert(c); if (c->default_sink_name) return c->default_sink_name; @@ -284,7 +281,7 @@ const char *pa_namereg_get_default_source_name(pa_core *c) { pa_source *s; uint32_t idx; - assert(c); + pa_assert(c); if (c->default_source_name) return c->default_source_name; diff --git a/src/pulsecore/native-common.h b/src/pulsecore/native-common.h index f7a7da1d..9defc4a5 100644 --- a/src/pulsecore/native-common.h +++ b/src/pulsecore/native-common.h @@ -115,6 +115,11 @@ enum { PA_COMMAND_MOVE_SINK_INPUT, PA_COMMAND_MOVE_SOURCE_OUTPUT, + PA_COMMAND_SET_SINK_INPUT_MUTE, + + PA_COMMAND_SUSPEND_SINK, + PA_COMMAND_SUSPEND_SOURCE, + PA_COMMAND_MAX }; diff --git a/src/pulsecore/object.c b/src/pulsecore/object.c new file mode 100644 index 00000000..6c36242b --- /dev/null +++ b/src/pulsecore/object.c @@ -0,0 +1,72 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "object.h" + +pa_object *pa_object_new_internal(size_t size, const char *type_name, int (*check_type)(const char *type_name)) { + pa_object *o; + + pa_assert(size > sizeof(pa_object)); + pa_assert(type_name); + + if (!check_type) + check_type = pa_object_check_type; + + pa_assert(check_type(type_name)); + pa_assert(check_type("pa_object")); + + o = pa_xmalloc(size); + PA_REFCNT_INIT(o); + o->type_name = type_name; + o->free = pa_object_free; + o->check_type = check_type; + + return o; +} + +pa_object *pa_object_ref(pa_object *o) { + pa_object_assert_ref(o); + + PA_REFCNT_INC(o); + return o; +} + +void pa_object_unref(pa_object *o) { + pa_object_assert_ref(o); + + if (PA_REFCNT_DEC(o) <= 0) { + pa_assert(o->free); + o->free(o); + } +} + +int pa_object_check_type(const char *type_name) { + pa_assert(type_name); + + return strcmp(type_name, "pa_object") == 0; +} diff --git a/src/pulsecore/object.h b/src/pulsecore/object.h new file mode 100644 index 00000000..562fd113 --- /dev/null +++ b/src/pulsecore/object.h @@ -0,0 +1,106 @@ +#ifndef foopulseobjecthfoo +#define foopulseobjecthfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include +#include +#include + +typedef struct pa_object pa_object; + +struct pa_object { + PA_REFCNT_DECLARE; + const char *type_name; + void (*free)(pa_object *o); + int (*check_type)(const char *type_name); +}; + +pa_object *pa_object_new_internal(size_t size, const char *type_name, int (*check_type)(const char *type_name)); +#define pa_object_new(type) ((type*) pa_object_new_internal(sizeof(type), #type, type##_check_type) + +#define pa_object_free ((void (*) (pa_object* o)) pa_xfree) + +int pa_object_check_type(const char *type); + +static inline int pa_object_isinstance(void *o) { + pa_object *obj = (pa_object*) o; + return obj ? obj->check_type("pa_object") : 0; +} + +pa_object *pa_object_ref(pa_object *o); +void pa_object_unref(pa_object *o); + +static inline int pa_object_refcnt(pa_object *o) { + return o ? PA_REFCNT_VALUE(o) : 0; +} + +static inline pa_object* pa_object_cast(void *o) { + pa_object *obj = (pa_object*) o; + pa_assert(!obj || obj->check_type("pa_object")); + return obj; +} + +#define pa_object_assert_ref(o) pa_assert(pa_object_refcnt(o) > 0) + +#define PA_OBJECT(o) pa_object_cast(o) + +#define PA_DECLARE_CLASS(c) \ + static inline int c##_isinstance(void *o) { \ + pa_object *obj = (pa_object*) o; \ + return obj ? obj->check_type(#c) : 1; \ + } \ + static inline c* c##_cast(void *o) { \ + pa_assert(c##_isinstance(o)); \ + return (c*) o; \ + } \ + static inline c* c##_ref(c *o) { \ + return (c*) pa_object_ref(PA_OBJECT(o)); \ + } \ + static inline void c##_unref(c* o) { \ + pa_object_unref(PA_OBJECT(o)); \ + } \ + static inline int c##_refcnt(c* o) { \ + return pa_object_refcnt(PA_OBJECT(o)); \ + } \ + static inline void c##_assert_ref(c *o) { \ + pa_object_assert_ref(PA_OBJECT(o)); \ + } \ + struct __stupid_useless_struct_to_allow_trailing_semicolon + +#define PA_DEFINE_CHECK_TYPE(c, parent) \ + int c##_check_type(const char *type) { \ + pa_assert(type); \ + if (strcmp(type, #c) == 0) \ + return 1; \ + return parent##_check_type(type); \ + } \ + struct __stupid_useless_struct_to_allow_trailing_semicolon + + +#endif diff --git a/src/pulsecore/once-posix.c b/src/pulsecore/once-posix.c deleted file mode 100644 index 4af7b36e..00000000 --- a/src/pulsecore/once-posix.c +++ /dev/null @@ -1,71 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of PulseAudio. - - Copyright 2006 Lennart Poettering - - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PulseAudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include - -#include "once.h" - -#define ASSERT_SUCCESS(x) do { \ - int _r = (x); \ - assert(_r == 0); \ -} while(0) - -static pa_mutex *global_mutex; -static pthread_once_t global_mutex_once = PTHREAD_ONCE_INIT; - -static void global_mutex_once_func(void) { - global_mutex = pa_mutex_new(0); -} - -void pa_once(pa_once_t *control, pa_once_func_t func) { - assert(control); - assert(func); - - /* Create the global mutex */ - ASSERT_SUCCESS(pthread_once(&global_mutex_once, global_mutex_once_func)); - - /* Create the local mutex */ - pa_mutex_lock(global_mutex); - if (!control->mutex) - control->mutex = pa_mutex_new(1); - pa_mutex_unlock(global_mutex); - - /* Execute function */ - pa_mutex_lock(control->mutex); - if (!control->once_value) { - control->once_value = 1; - func(); - } - pa_mutex_unlock(control->mutex); - - /* Caveat: We have to make sure that the once func has completed - * before returning, even if the once func is not actually - * executed by us. Hence the awkward locking. */ -} diff --git a/src/pulsecore/once-win32.c b/src/pulsecore/once-win32.c deleted file mode 100644 index b30097c8..00000000 --- a/src/pulsecore/once-win32.c +++ /dev/null @@ -1,69 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of PulseAudio. - - Copyright 2006 Pierre Ossman for Cendio AB - - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PulseAudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include - -#include - -#include "once.h" - -void pa_once(pa_once_t *control, pa_once_func_t func) { - HANDLE mutex; - char name[64]; - - assert(control); - assert(func); - - /* Create the global mutex */ - sprintf(name, "pulse%d", (int)GetCurrentProcessId()); - - mutex = CreateMutex(NULL, FALSE, name); - assert(mutex); - - /* Create the local mutex */ - WaitForSingleObject(mutex, INFINITE); - if (!control->mutex) - control->mutex = pa_mutex_new(1); - ReleaseMutex(mutex); - - CloseHandle(mutex); - - /* Execute function */ - pa_mutex_lock(control->mutex); - if (!control->once_value) { - control->once_value = 1; - func(); - } - pa_mutex_unlock(control->mutex); - - /* Caveat: We have to make sure that the once func has completed - * before returning, even if the once func is not actually - * executed by us. Hence the awkward locking. */ -} diff --git a/src/pulsecore/once.c b/src/pulsecore/once.c new file mode 100644 index 00000000..a358cf65 --- /dev/null +++ b/src/pulsecore/once.c @@ -0,0 +1,96 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "once.h" + +int pa_once_begin(pa_once *control) { + pa_mutex *m; + + pa_assert(control); + + if (pa_atomic_load(&control->done)) + return 0; + + pa_atomic_inc(&control->ref); + + /* Caveat: We have to make sure that the once func has completed + * before returning, even if the once func is not actually + * executed by us. Hence the awkward locking. */ + + for (;;) { + + if ((m = pa_atomic_ptr_load(&control->mutex))) { + + /* The mutex is stored in locked state, hence let's just + * wait until it is unlocked */ + pa_mutex_lock(m); + + pa_once_end(control); + return 0; + } + + pa_assert_se(m = pa_mutex_new(FALSE, FALSE)); + pa_mutex_lock(m); + + if (pa_atomic_ptr_cmpxchg(&control->mutex, NULL, m)) + return 1; + + pa_mutex_unlock(m); + pa_mutex_free(m); + } +} + +void pa_once_end(pa_once *control) { + pa_mutex *m; + + pa_assert(control); + + pa_atomic_store(&control->done, 1); + + pa_assert_se(m = pa_atomic_ptr_load(&control->mutex)); + pa_mutex_unlock(m); + + if (pa_atomic_dec(&control->ref) <= 1) { + pa_assert_se(pa_atomic_ptr_cmpxchg(&control->mutex, m, NULL)); + pa_mutex_free(m); + } +} + +/* Not reentrant -- how could it be? */ +void pa_run_once(pa_once *control, pa_once_func_t func) { + pa_assert(control); + pa_assert(func); + + if (pa_once_begin(control)) { + func(); + pa_once_end(control); + } +} + diff --git a/src/pulsecore/once.h b/src/pulsecore/once.h index c20fc0b4..c9fe6d0a 100644 --- a/src/pulsecore/once.h +++ b/src/pulsecore/once.h @@ -25,16 +25,52 @@ ***/ #include +#include typedef struct pa_once { - unsigned int once_value; - pa_mutex *mutex; -} pa_once_t; + pa_atomic_ptr_t mutex; + pa_atomic_t ref, done; +} pa_once; -#define PA_ONCE_INIT { .once_value = 0, .mutex = NULL } +#define PA_ONCE_INIT \ + { \ + .mutex = PA_ATOMIC_PTR_INIT(NULL), \ + .ref = PA_ATOMIC_INIT(0), \ + .done = PA_ATOMIC_INIT(0) \ + } -typedef void (*pa_once_func_t) (void); +/* Not to be called directly, use the macros defined below instead */ +int pa_once_begin(pa_once *o); +void pa_once_end(pa_once *o); + +#define PA_ONCE_BEGIN \ + do { \ + static pa_once _once = PA_ONCE_INIT; \ + if (pa_once_begin(&_once)) {{ + +#define PA_ONCE_END \ + } \ + pa_once_end(&_once); \ + } \ + } while(0) + +/* + + Usage of these macros is like this: + + void foo() { -void pa_once(pa_once_t *o, pa_once_func_t f); + PA_ONCE_BEGIN { + + ... stuff to be called just once ... + + } PA_ONCE_END; + } + +*/ + +/* Same API but calls a function */ +typedef void (*pa_once_func_t) (void); +void pa_run_once(pa_once *o, pa_once_func_t f); #endif diff --git a/src/pulsecore/packet.c b/src/pulsecore/packet.c index ce57cb3e..2706efea 100644 --- a/src/pulsecore/packet.c +++ b/src/pulsecore/packet.c @@ -25,22 +25,22 @@ #include #endif -#include #include #include +#include #include "packet.h" pa_packet* pa_packet_new(size_t length) { pa_packet *p; - assert(length); + pa_assert(length > 0); - p = pa_xmalloc(sizeof(pa_packet)+length); - p->ref = 1; + p = pa_xmalloc(PA_ALIGN(sizeof(pa_packet)) + length); + PA_REFCNT_INIT(p); p->length = length; - p->data = (uint8_t*) (p+1); + p->data = (uint8_t*) p + PA_ALIGN(sizeof(pa_packet)); p->type = PA_PACKET_APPENDED; return p; @@ -49,11 +49,11 @@ pa_packet* pa_packet_new(size_t length) { pa_packet* pa_packet_new_dynamic(void* data, size_t length) { pa_packet *p; - assert(data); - assert(length); + pa_assert(data); + pa_assert(length > 0); p = pa_xnew(pa_packet, 1); - p->ref = 1; + PA_REFCNT_INIT(p); p->length = length; p->data = data; p->type = PA_PACKET_DYNAMIC; @@ -62,18 +62,18 @@ pa_packet* pa_packet_new_dynamic(void* data, size_t length) { } pa_packet* pa_packet_ref(pa_packet *p) { - assert(p); - assert(p->ref >= 1); + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) >= 1); - p->ref++; + PA_REFCNT_INC(p); return p; } void pa_packet_unref(pa_packet *p) { - assert(p); - assert(p->ref >= 1); + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) >= 1); - if (--p->ref == 0) { + if (PA_REFCNT_DEC(p) <= 0) { if (p->type == PA_PACKET_DYNAMIC) pa_xfree(p->data); pa_xfree(p); diff --git a/src/pulsecore/packet.h b/src/pulsecore/packet.h index 842582c8..bcac4a7f 100644 --- a/src/pulsecore/packet.h +++ b/src/pulsecore/packet.h @@ -27,9 +27,11 @@ #include #include +#include + typedef struct pa_packet { + PA_REFCNT_DECLARE; enum { PA_PACKET_APPENDED, PA_PACKET_DYNAMIC } type; - unsigned ref; size_t length; uint8_t *data; } pa_packet; diff --git a/src/pulsecore/parseaddr.c b/src/pulsecore/parseaddr.c index a49a09ed..65ba64c1 100644 --- a/src/pulsecore/parseaddr.c +++ b/src/pulsecore/parseaddr.c @@ -26,13 +26,13 @@ #endif #include -#include #include #include - #include + #include +#include #include "parseaddr.h" @@ -45,7 +45,9 @@ * Return a newly allocated string of the hostname and fill in *ret_port if specified */ static char *parse_host(const char *s, uint16_t *ret_port) { - assert(s && ret_port); + pa_assert(s); + pa_assert(ret_port); + if (*s == '[') { char *e; if (!(e = strchr(s+1, ']'))) @@ -70,7 +72,10 @@ static char *parse_host(const char *s, uint16_t *ret_port) { int pa_parse_address(const char *name, pa_parsed_address *ret_p) { const char *p; - assert(name && ret_p); + + pa_assert(name); + pa_assert(ret_p); + memset(ret_p, 0, sizeof(pa_parsed_address)); ret_p->type = PA_PARSED_ADDRESS_TCP_AUTO; @@ -112,6 +117,5 @@ int pa_parse_address(const char *name, pa_parsed_address *ret_p) { if (!(ret_p->path_or_host = parse_host(p, &ret_p->port))) return -1; - return 0; } diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c index 10238acb..2c95d740 100644 --- a/src/pulsecore/pdispatch.c +++ b/src/pulsecore/pdispatch.c @@ -28,7 +28,6 @@ #include #include -#include #include #include @@ -37,6 +36,8 @@ #include #include #include +#include +#include #include "pdispatch.h" @@ -108,7 +109,7 @@ struct reply_info { }; struct pa_pdispatch { - int ref; + PA_REFCNT_DECLARE; pa_mainloop_api *mainloop; const pa_pdispatch_cb_t *callback_table; unsigned n_commands; @@ -119,7 +120,9 @@ struct pa_pdispatch { }; static void reply_info_free(struct reply_info *r) { - assert(r && r->pdispatch && r->pdispatch->mainloop); + pa_assert(r); + pa_assert(r->pdispatch); + pa_assert(r->pdispatch->mainloop); if (r->time_event) r->pdispatch->mainloop->time_free(r->time_event); @@ -131,12 +134,12 @@ static void reply_info_free(struct reply_info *r) { pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_cb_t*table, unsigned entries) { pa_pdispatch *pd; - assert(mainloop); + pa_assert(mainloop); - assert((entries && table) || (!entries && !table)); + pa_assert((entries && table) || (!entries && !table)); - pd = pa_xmalloc(sizeof(pa_pdispatch)); - pd->ref = 1; + pd = pa_xnew(pa_pdispatch, 1); + PA_REFCNT_INIT(pd); pd->mainloop = mainloop; pd->callback_table = table; pd->n_commands = entries; @@ -149,7 +152,7 @@ pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_cb_ } static void pdispatch_free(pa_pdispatch *pd) { - assert(pd); + pa_assert(pd); while (pd->replies) { if (pd->replies->free_cb) @@ -165,7 +168,7 @@ static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command, pa_pdispatch_cb_t callback; void *userdata; uint32_t tag; - assert(r); + pa_assert(r); pa_pdispatch_ref(pd); @@ -187,7 +190,12 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds, uint32_t tag, command; pa_tagstruct *ts = NULL; int ret = -1; - assert(pd && packet && packet->data); + + pa_assert(pd); + pa_assert(PA_REFCNT_VALUE(pd) >= 1); + pa_assert(packet); + pa_assert(PA_REFCNT_VALUE(packet) >= 1); + pa_assert(packet->data); pa_pdispatch_ref(pd); @@ -195,7 +203,6 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds, goto finish; ts = pa_tagstruct_new(packet->data, packet->length); - assert(ts); if (pa_tagstruct_getu32(ts, &command) < 0 || pa_tagstruct_getu32(ts, &tag) < 0) @@ -206,7 +213,7 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds, char t[256]; char const *p; if (!(p = command_names[command])) - snprintf((char*) (p = t), sizeof(t), "%u", command); + pa_snprintf((char*) (p = t), sizeof(t), "%u", command); pa_log("Recieved opcode <%s>", p); } @@ -248,7 +255,12 @@ finish: static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { struct reply_info*r = userdata; - assert(r && r->time_event == e && r->pdispatch && r->pdispatch->mainloop == m && r->callback); + + pa_assert(r); + pa_assert(r->time_event == e); + pa_assert(r->pdispatch); + pa_assert(r->pdispatch->mainloop == m); + pa_assert(r->callback); run_action(r->pdispatch, r, PA_COMMAND_TIMEOUT, NULL); } @@ -256,7 +268,10 @@ static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, PA_GCC_UNUSED c void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t cb, void *userdata, pa_free_cb_t free_cb) { struct reply_info *r; struct timeval tv; - assert(pd && pd->ref >= 1 && cb); + + pa_assert(pd); + pa_assert(PA_REFCNT_VALUE(pd) >= 1); + pa_assert(cb); r = pa_xnew(struct reply_info, 1); r->pdispatch = pd; @@ -268,21 +283,22 @@ void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa pa_gettimeofday(&tv); tv.tv_sec += timeout; - r->time_event = pd->mainloop->time_new(pd->mainloop, &tv, timeout_callback, r); - assert(r->time_event); + pa_assert_se(r->time_event = pd->mainloop->time_new(pd->mainloop, &tv, timeout_callback, r)); PA_LLIST_PREPEND(struct reply_info, pd->replies, r); } int pa_pdispatch_is_pending(pa_pdispatch *pd) { - assert(pd); + pa_assert(pd); + pa_assert(PA_REFCNT_VALUE(pd) >= 1); return !!pd->replies; } void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, void (*cb)(pa_pdispatch *pd, void *userdata), void *userdata) { - assert(pd); - assert(!cb || pa_pdispatch_is_pending(pd)); + pa_assert(pd); + pa_assert(PA_REFCNT_VALUE(pd) >= 1); + pa_assert(!cb || pa_pdispatch_is_pending(pd)); pd->drain_callback = cb; pd->drain_userdata = userdata; @@ -290,7 +306,9 @@ void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, void (*cb)(pa_pdispatch * void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata) { struct reply_info *r, *n; - assert(pd); + + pa_assert(pd); + pa_assert(PA_REFCNT_VALUE(pd) >= 1); for (r = pd->replies; r; r = n) { n = r->next; @@ -301,21 +319,24 @@ void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata) { } void pa_pdispatch_unref(pa_pdispatch *pd) { - assert(pd && pd->ref >= 1); + pa_assert(pd); + pa_assert(PA_REFCNT_VALUE(pd) >= 1); - if (!(--(pd->ref))) + if (PA_REFCNT_DEC(pd) <= 0) pdispatch_free(pd); } pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd) { - assert(pd && pd->ref >= 1); - pd->ref++; + pa_assert(pd); + pa_assert(PA_REFCNT_VALUE(pd) >= 1); + + PA_REFCNT_INC(pd); return pd; } const pa_creds * pa_pdispatch_creds(pa_pdispatch *pd) { - assert(pd); - assert(pd->ref >= 1); + pa_assert(pd); + pa_assert(PA_REFCNT_VALUE(pd) >= 1); return pd->creds; } diff --git a/src/pulsecore/pid.c b/src/pulsecore/pid.c index 5e670e17..55ff2088 100644 --- a/src/pulsecore/pid.c +++ b/src/pulsecore/pid.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -47,6 +46,7 @@ #include #include #include +#include #include "pid.h" @@ -57,11 +57,11 @@ static pid_t read_pid(const char *fn, int fd) { char t[20], *e; uint32_t pid; - assert(fn && fd >= 0); + pa_assert(fn); + pa_assert(fd >= 0); if ((r = pa_loop_read(fd, t, sizeof(t)-1, NULL)) < 0) { - pa_log_warn("WARNING: failed to read PID file '%s': %s", - fn, pa_cstrerror(errno)); + pa_log_warn("Failed to read PID file '%s': %s", fn, pa_cstrerror(errno)); return (pid_t) -1; } @@ -73,7 +73,7 @@ static pid_t read_pid(const char *fn, int fd) { *e = 0; if (pa_atou(t, &pid) < 0) { - pa_log("WARNING: failed to parse PID file '%s'", fn); + pa_log_warn("Failed to parse PID file '%s'", fn); return (pid_t) -1; } @@ -83,13 +83,22 @@ static pid_t read_pid(const char *fn, int fd) { static int open_pid_file(const char *fn, int mode) { int fd = -1; + pa_assert(fn); + for (;;) { struct stat st; - if ((fd = open(fn, mode, S_IRUSR|S_IWUSR)) < 0) { + if ((fd = open(fn, mode +#ifdef O_NOCTTY + |O_NOCTTY +#endif +#ifdef O_NOFOLLOW + |O_NOFOLLOW +#endif + , S_IRUSR|S_IWUSR + )) < 0) { if (mode != O_RDONLY || errno != ENOENT) - pa_log_warn("WARNING: failed to open PID file '%s': %s", - fn, pa_cstrerror(errno)); + pa_log_warn("Failed to open PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } @@ -98,8 +107,7 @@ static int open_pid_file(const char *fn, int mode) { goto fail; if (fstat(fd, &st) < 0) { - pa_log_warn("WARNING: failed to fstat() PID file '%s': %s", - fn, pa_cstrerror(errno)); + pa_log_warn("Failed to fstat() PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } @@ -110,9 +118,9 @@ static int open_pid_file(const char *fn, int mode) { if (pa_lock_fd(fd, 0) < 0) goto fail; - if (close(fd) < 0) { - pa_log_warn("WARNING: failed to close file '%s': %s", - fn, pa_cstrerror(errno)); + if (pa_close(fd) < 0) { + pa_log_warn("Failed to close file '%s': %s", fn, pa_cstrerror(errno)); + fd = -1; goto fail; } @@ -125,7 +133,7 @@ fail: if (fd >= 0) { pa_lock_fd(fd, 0); - close(fd); + pa_close(fd); } return -1; @@ -150,7 +158,7 @@ int pa_pid_file_create(void) { goto fail; if ((pid = read_pid(fn, fd)) == (pid_t) -1) - pa_log("corrupt PID file, overwriting."); + pa_log_warn("Corrupt PID file, overwriting."); else if (pid > 0) { #ifdef OS_IS_WIN32 if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)) != NULL) { @@ -158,25 +166,24 @@ int pa_pid_file_create(void) { #else if (kill(pid, 0) >= 0 || errno != ESRCH) { #endif - pa_log("daemon already running."); + pa_log("Daemon already running."); goto fail; } - pa_log("stale PID file, overwriting."); + pa_log_warn("Stale PID file, overwriting."); } /* Overwrite the current PID file */ if (lseek(fd, 0, SEEK_SET) == (off_t) -1 || ftruncate(fd, 0) < 0) { - pa_log("failed to truncate PID file '%s': %s", - fn, pa_cstrerror(errno)); + pa_log("Failed to truncate PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } - snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid()); + pa_snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid()); l = strlen(t); if (pa_loop_write(fd, t, l, NULL) != (ssize_t) l) { - pa_log("failed to write PID file."); + pa_log("Failed to write PID file."); goto fail; } @@ -185,7 +192,11 @@ int pa_pid_file_create(void) { fail: if (fd >= 0) { pa_lock_fd(fd, 0); - close(fd); + + if (pa_close(fd) < 0) { + pa_log("Failed to close PID file '%s': %s", fn, pa_cstrerror(errno)); + ret = -1; + } } return ret; @@ -201,8 +212,7 @@ int pa_pid_file_remove(void) { pa_runtime_path("pid", fn, sizeof(fn)); if ((fd = open_pid_file(fn, O_RDWR)) < 0) { - pa_log_warn("WARNING: failed to open PID file '%s': %s", - fn, pa_cstrerror(errno)); + pa_log_warn("Failed to open PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } @@ -210,13 +220,12 @@ int pa_pid_file_remove(void) { goto fail; if (pid != getpid()) { - pa_log("WARNING: PID file '%s' not mine!", fn); + pa_log("PID file '%s' not mine!", fn); goto fail; } if (ftruncate(fd, 0) < 0) { - pa_log_warn("WARNING: failed to truncate PID file '%s': %s", - fn, pa_cstrerror(errno)); + pa_log_warn("Failed to truncate PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } @@ -227,8 +236,7 @@ int pa_pid_file_remove(void) { #endif if (unlink(fn) < 0) { - pa_log_warn("WARNING: failed to remove PID file '%s': %s", - fn, pa_cstrerror(errno)); + pa_log_warn("Failed to remove PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } @@ -238,7 +246,11 @@ fail: if (fd >= 0) { pa_lock_fd(fd, 0); - close(fd); + + if (pa_close(fd) < 0) { + pa_log_warn("Failed to close PID file '%s': %s", fn, pa_cstrerror(errno)); + ret = -1; + } } return ret; @@ -280,7 +292,7 @@ fail: if (fd >= 0) { pa_lock_fd(fd, 0); - close(fd); + pa_close(fd); } return ret; diff --git a/src/pulsecore/pipe.c b/src/pulsecore/pipe.c index 7f6bb2e9..e614c9c6 100644 --- a/src/pulsecore/pipe.c +++ b/src/pulsecore/pipe.c @@ -149,14 +149,14 @@ int pipe(int filedes[2]) { return 0; error: - if (listener >= 0) - pa_close(listener); - if (filedes[0] >= 0) - pa_close(filedes[0]); - if (filedes[1] >= 0) - pa_close(filedes[0]); - - return -1; + if (listener >= 0) + pa_close(listener); + if (filedes[0] >= 0) + pa_close(filedes[0]); + if (filedes[1] >= 0) + pa_close(filedes[0]); + + return -1; } #endif /* HAVE_PIPE */ diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c index 76edd27a..5d3c2d39 100644 --- a/src/pulsecore/play-memblockq.c +++ b/src/pulsecore/play-memblockq.c @@ -26,7 +26,6 @@ #endif #include -#include #include #include @@ -34,53 +33,106 @@ #include #include +#include #include "play-memblockq.h" -static void sink_input_kill(pa_sink_input *i) { - pa_memblockq *q; - assert(i); - assert(i->userdata); +typedef struct memblockq_stream { + pa_msgobject parent; + pa_core *core; + pa_sink_input *sink_input; + pa_memblockq *memblockq; +} memblockq_stream; - q = i->userdata; +enum { + MEMBLOCKQ_STREAM_MESSAGE_UNLINK, +}; - pa_sink_input_disconnect(i); - pa_sink_input_unref(i); +PA_DECLARE_CLASS(memblockq_stream); +#define MEMBLOCKQ_STREAM(o) (memblockq_stream_cast(o)) +static PA_DEFINE_CHECK_TYPE(memblockq_stream, pa_msgobject); + +static void memblockq_stream_unlink(memblockq_stream *u) { + pa_assert(u); + + if (!u->sink_input) + return; + + pa_sink_input_unlink(u->sink_input); - pa_memblockq_free(q); + pa_sink_input_unref(u->sink_input); + u->sink_input = NULL; + + memblockq_stream_unref(u); } -static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { - pa_memblockq *q; - assert(i); - assert(chunk); - assert(i->userdata); +static void memblockq_stream_free(pa_object *o) { + memblockq_stream *u = MEMBLOCKQ_STREAM(o); + pa_assert(u); + + memblockq_stream_unlink(u); - q = i->userdata; + if (u->memblockq) + pa_memblockq_free(u->memblockq); - return pa_memblockq_peek(q, chunk); + pa_xfree(u); } -static void si_kill(PA_GCC_UNUSED pa_mainloop_api *m, void *i) { - sink_input_kill(i); +static int memblockq_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) { + memblockq_stream *u = MEMBLOCKQ_STREAM(o); + memblockq_stream_assert_ref(u); + + switch (code) { + case MEMBLOCKQ_STREAM_MESSAGE_UNLINK: + memblockq_stream_unlink(u); + break; + } + + return 0; +} + +static void sink_input_kill_cb(pa_sink_input *i) { + pa_sink_input_assert_ref(i); + + memblockq_stream_unlink(MEMBLOCKQ_STREAM(i->userdata)); } -static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) { - pa_memblockq *q; +static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) { + memblockq_stream *u; - assert(i); - assert(length > 0); - assert( i->userdata); + pa_assert(i); + pa_assert(chunk); + u = MEMBLOCKQ_STREAM(i->userdata); + memblockq_stream_assert_ref(u); - q = i->userdata; + if (!u->memblockq) + return -1; - pa_memblockq_drop(q, chunk, length); + if (pa_memblockq_peek(u->memblockq, chunk) < 0) { + pa_memblockq_free(u->memblockq); + u->memblockq = NULL; + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u), MEMBLOCKQ_STREAM_MESSAGE_UNLINK, NULL, 0, NULL, NULL); + return -1; + } - if (pa_memblockq_get_length(q) <= 0) - pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i); + return 0; } -int pa_play_memblockq( +static void sink_input_drop_cb(pa_sink_input *i, size_t length) { + memblockq_stream *u; + + pa_assert(i); + pa_assert(length > 0); + u = MEMBLOCKQ_STREAM(i->userdata); + memblockq_stream_assert_ref(u); + + if (!u->memblockq) + return; + + pa_memblockq_drop(u->memblockq, length); +} + +pa_sink_input* pa_memblockq_sink_input_new( pa_sink *sink, const char *name, const pa_sample_spec *ss, @@ -88,41 +140,97 @@ int pa_play_memblockq( pa_memblockq *q, pa_cvolume *volume) { - pa_sink_input *si; + memblockq_stream *u = NULL; pa_sink_input_new_data data; - assert(sink); - assert(ss); - assert(q); + pa_assert(sink); + pa_assert(ss); - if (pa_memblockq_get_length(q) <= 0) { + /* We allow creating this stream with no q set, so that it can be + * filled in later */ + + if (q && pa_memblockq_get_length(q) <= 0) { pa_memblockq_free(q); - return 0; + return NULL; } if (volume && pa_cvolume_is_muted(volume)) { pa_memblockq_free(q); - return 0; + return NULL; } + u = pa_msgobject_new(memblockq_stream); + u->parent.parent.free = memblockq_stream_free; + u->parent.process_msg = memblockq_stream_process_msg; + u->core = sink->core; + u->sink_input = NULL; + u->memblockq = q; + pa_sink_input_new_data_init(&data); data.sink = sink; data.name = name; data.driver = __FILE__; - pa_sink_input_new_data_set_channel_map(&data, map); pa_sink_input_new_data_set_sample_spec(&data, ss); + pa_sink_input_new_data_set_channel_map(&data, map); pa_sink_input_new_data_set_volume(&data, volume); - if (!(si = pa_sink_input_new(sink->core, &data, 0))) - return -1; + if (!(u->sink_input = pa_sink_input_new(sink->core, &data, 0))) + goto fail; + + u->sink_input->peek = sink_input_peek_cb; + u->sink_input->drop = sink_input_drop_cb; + u->sink_input->kill = sink_input_kill_cb; + u->sink_input->userdata = u; + + if (q) + pa_memblockq_prebuf_disable(q); - si->peek = sink_input_peek; - si->drop = sink_input_drop; - si->kill = sink_input_kill; + /* The reference to u is dangling here, because we want + * to keep this stream around until it is fully played. */ - si->userdata = q; + /* This sink input is not "put" yet, i.e. pa_sink_input_put() has + * not been called! */ - pa_sink_notify(si->sink); + return pa_sink_input_ref(u->sink_input); + +fail: + if (u) + memblockq_stream_unref(u); + + return NULL; +} + +int pa_play_memblockq( + pa_sink *sink, + const char *name, + const pa_sample_spec *ss, + const pa_channel_map *map, + pa_memblockq *q, + pa_cvolume *volume) { + + pa_sink_input *i; + + pa_assert(sink); + pa_assert(ss); + pa_assert(q); + + if (!(i = pa_memblockq_sink_input_new(sink, name, ss, map, q, volume))) + return -1; + + pa_sink_input_put(i); + pa_sink_input_unref(i); return 0; } + +void pa_memblockq_sink_input_set_queue(pa_sink_input *i, pa_memblockq *q) { + memblockq_stream *u; + + pa_sink_input_assert_ref(i); + u = MEMBLOCKQ_STREAM(i->userdata); + memblockq_stream_assert_ref(u); + + if (u->memblockq) + pa_memblockq_free(u->memblockq); + u->memblockq = q; +} diff --git a/src/pulsecore/play-memblockq.h b/src/pulsecore/play-memblockq.h index 8248e859..d8790316 100644 --- a/src/pulsecore/play-memblockq.h +++ b/src/pulsecore/play-memblockq.h @@ -27,6 +27,16 @@ #include #include +pa_sink_input* pa_memblockq_sink_input_new( + pa_sink *sink, + const char *name, + const pa_sample_spec *ss, + const pa_channel_map *map, + pa_memblockq *q, + pa_cvolume *volume); + +void pa_memblockq_sink_input_set_queue(pa_sink_input *i, pa_memblockq *q); + int pa_play_memblockq( pa_sink *sink, const char *name, diff --git a/src/pulsecore/play-memchunk.c b/src/pulsecore/play-memchunk.c index 9132e294..6aaec567 100644 --- a/src/pulsecore/play-memchunk.c +++ b/src/pulsecore/play-memchunk.c @@ -26,7 +26,6 @@ #endif #include -#include #include #include @@ -34,53 +33,108 @@ #include #include +#include #include "play-memchunk.h" -static void sink_input_kill(pa_sink_input *i) { - pa_memchunk *c; - assert(i && i->userdata); - c = i->userdata; +typedef struct memchunk_stream { + pa_msgobject parent; + pa_core *core; + pa_sink_input *sink_input; + pa_memchunk memchunk; +} memchunk_stream; - pa_sink_input_disconnect(i); - pa_sink_input_unref(i); +enum { + MEMCHUNK_STREAM_MESSAGE_UNLINK, +}; - pa_memblock_unref(c->memblock); - pa_xfree(c); +PA_DECLARE_CLASS(memchunk_stream); +#define MEMCHUNK_STREAM(o) (memchunk_stream_cast(o)) +static PA_DEFINE_CHECK_TYPE(memchunk_stream, pa_msgobject); + +static void memchunk_stream_unlink(memchunk_stream *u) { + pa_assert(u); + + if (!u->sink_input) + return; + + pa_sink_input_unlink(u->sink_input); + + pa_sink_input_unref(u->sink_input); + u->sink_input = NULL; + + memchunk_stream_unref(u); } -static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { - pa_memchunk *c; - assert(i && chunk && i->userdata); - c = i->userdata; +static void memchunk_stream_free(pa_object *o) { + memchunk_stream *u = MEMCHUNK_STREAM(o); + pa_assert(u); - if (c->length <= 0) - return -1; + memchunk_stream_unlink(u); + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + + pa_xfree(u); +} + +static int memchunk_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) { + memchunk_stream *u = MEMCHUNK_STREAM(o); + memchunk_stream_assert_ref(u); - assert(c->memblock && c->memblock->length); - *chunk = *c; - pa_memblock_ref(c->memblock); + switch (code) { + case MEMCHUNK_STREAM_MESSAGE_UNLINK: + memchunk_stream_unlink(u); + break; + } return 0; } -static void si_kill(PA_GCC_UNUSED pa_mainloop_api *m, void *i) { - sink_input_kill(i); +static void sink_input_kill_cb(pa_sink_input *i) { + pa_sink_input_assert_ref(i); + + memchunk_stream_unlink(MEMCHUNK_STREAM(i->userdata)); } -static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) { - pa_memchunk *c; - assert(i && length && i->userdata); - c = i->userdata; +static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) { + memchunk_stream *u; + + pa_assert(i); + pa_assert(chunk); + u = MEMCHUNK_STREAM(i->userdata); + memchunk_stream_assert_ref(u); - assert(!memcmp(chunk, c, sizeof(chunk))); - assert(length <= c->length); + if (!u->memchunk.memblock) + return -1; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u), MEMCHUNK_STREAM_MESSAGE_UNLINK, NULL, 0, NULL, NULL); + return -1; + } - c->length -= length; - c->index += length; + pa_assert(u->memchunk.memblock); + *chunk = u->memchunk; + pa_memblock_ref(chunk->memblock); - if (c->length <= 0) - pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i); + return 0; +} + +static void sink_input_drop_cb(pa_sink_input *i, size_t length) { + memchunk_stream *u; + + pa_assert(i); + pa_assert(length > 0); + u = MEMCHUNK_STREAM(i->userdata); + memchunk_stream_assert_ref(u); + + if (length < u->memchunk.length) { + u->memchunk.length -= length; + u->memchunk.index += length; + } else + u->memchunk.length = 0; } int pa_play_memchunk( @@ -91,38 +145,52 @@ int pa_play_memchunk( const pa_memchunk *chunk, pa_cvolume *volume) { - pa_sink_input *si; - pa_memchunk *nchunk; + memchunk_stream *u = NULL; pa_sink_input_new_data data; - assert(sink); - assert(ss); - assert(chunk); + pa_assert(sink); + pa_assert(ss); + pa_assert(chunk); if (volume && pa_cvolume_is_muted(volume)) return 0; + pa_memchunk_will_need(chunk); + + u = pa_msgobject_new(memchunk_stream); + u->parent.parent.free = memchunk_stream_free; + u->parent.process_msg = memchunk_stream_process_msg; + u->core = sink->core; + u->memchunk = *chunk; + pa_memblock_ref(u->memchunk.memblock); + pa_sink_input_new_data_init(&data); data.sink = sink; - data.name = name; data.driver = __FILE__; + data.name = name; pa_sink_input_new_data_set_sample_spec(&data, ss); pa_sink_input_new_data_set_channel_map(&data, map); pa_sink_input_new_data_set_volume(&data, volume); - if (!(si = pa_sink_input_new(sink->core, &data, 0))) - return -1; - - si->peek = sink_input_peek; - si->drop = sink_input_drop; - si->kill = sink_input_kill; + if (!(u->sink_input = pa_sink_input_new(sink->core, &data, 0))) + goto fail; - si->userdata = nchunk = pa_xnew(pa_memchunk, 1); - *nchunk = *chunk; + u->sink_input->peek = sink_input_peek_cb; + u->sink_input->drop = sink_input_drop_cb; + u->sink_input->kill = sink_input_kill_cb; + u->sink_input->userdata = u; - pa_memblock_ref(chunk->memblock); + pa_sink_input_put(u->sink_input); - pa_sink_notify(si->sink); + /* The reference to u is dangling here, because we want to keep + * this stream around until it is fully played. */ return 0; + +fail: + if (u) + memchunk_stream_unref(u); + + return -1; } + diff --git a/src/pulsecore/poll.c b/src/pulsecore/poll.c index 2f8eae89..288f7dfb 100644 --- a/src/pulsecore/poll.c +++ b/src/pulsecore/poll.c @@ -45,7 +45,7 @@ #include "winsock.h" -#ifndef HAVE_SYS_POLL_H +#ifndef HAVE_POLL_H #include diff --git a/src/pulsecore/props.c b/src/pulsecore/props.c index 4a39f0fb..cbf748df 100644 --- a/src/pulsecore/props.c +++ b/src/pulsecore/props.c @@ -21,11 +21,13 @@ USA. ***/ -#include +#ifdef HAVE_CONFIG_H +#include +#endif #include - #include +#include #include "props.h" @@ -37,9 +39,11 @@ typedef struct pa_property { /* Allocate a new property object */ static pa_property* property_new(const char *name, void *data) { pa_property* p; - assert(name && data); - p = pa_xmalloc(sizeof(pa_property)); + pa_assert(name); + pa_assert(data); + + p = pa_xnew(pa_property, 1); p->name = pa_xstrdup(name); p->data = data; @@ -48,7 +52,7 @@ static pa_property* property_new(const char *name, void *data) { /* Free a property object */ static void property_free(pa_property *p) { - assert(p); + pa_assert(p); pa_xfree(p->name); pa_xfree(p); @@ -56,7 +60,10 @@ static void property_free(pa_property *p) { void* pa_property_get(pa_core *c, const char *name) { pa_property *p; - assert(c && name && c->properties); + + pa_assert(c); + pa_assert(name); + pa_assert(c->properties); if (!(p = pa_hashmap_get(c->properties, name))) return NULL; @@ -66,7 +73,11 @@ void* pa_property_get(pa_core *c, const char *name) { int pa_property_set(pa_core *c, const char *name, void *data) { pa_property *p; - assert(c && name && data && c->properties); + + pa_assert(c); + pa_assert(name); + pa_assert(data); + pa_assert(c->properties); if (pa_hashmap_get(c->properties, name)) return -1; @@ -78,7 +89,10 @@ int pa_property_set(pa_core *c, const char *name, void *data) { int pa_property_remove(pa_core *c, const char *name) { pa_property *p; - assert(c && name && c->properties); + + pa_assert(c); + pa_assert(name); + pa_assert(c->properties); if (!(p = pa_hashmap_remove(c->properties, name))) return -1; @@ -88,18 +102,18 @@ int pa_property_remove(pa_core *c, const char *name) { } void pa_property_init(pa_core *c) { - assert(c); + pa_assert(c); c->properties = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); } void pa_property_cleanup(pa_core *c) { - assert(c); + pa_assert(c); if (!c->properties) return; - assert(!pa_hashmap_size(c->properties)); + pa_assert(!pa_hashmap_size(c->properties)); pa_hashmap_free(c->properties, NULL, NULL); c->properties = NULL; @@ -109,14 +123,17 @@ void pa_property_cleanup(pa_core *c) { void pa_property_dump(pa_core *c, pa_strbuf *s) { void *state = NULL; pa_property *p; - assert(c && s); + + pa_assert(c); + pa_assert(s); while ((p = pa_hashmap_iterate(c->properties, &state, NULL))) pa_strbuf_printf(s, "[%s] -> [%p]\n", p->name, p->data); } int pa_property_replace(pa_core *c, const char *name, void *data) { - assert(c && name); + pa_assert(c); + pa_assert(name); pa_property_remove(c, name); return pa_property_set(c, name, data); diff --git a/src/pulsecore/protocol-cli.c b/src/pulsecore/protocol-cli.c index 1d543ae5..ceb6ae4d 100644 --- a/src/pulsecore/protocol-cli.c +++ b/src/pulsecore/protocol-cli.c @@ -25,13 +25,13 @@ #include #endif -#include #include #include #include #include +#include #include "protocol-cli.h" @@ -47,7 +47,8 @@ struct pa_protocol_cli { static void cli_eof_cb(pa_cli*c, void*userdata) { pa_protocol_cli *p = userdata; - assert(p); + pa_assert(p); + pa_idxset_remove_by_data(p->connections, c, NULL); pa_cli_free(c); } @@ -55,7 +56,10 @@ static void cli_eof_cb(pa_cli*c, void*userdata) { static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { pa_protocol_cli *p = userdata; pa_cli *c; - assert(s && io && p); + + pa_assert(s); + pa_assert(io); + pa_assert(p); if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); @@ -64,7 +68,6 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) } c = pa_cli_new(p->core, io, p->module); - assert(c); pa_cli_set_eof_callback(c, cli_eof_cb, p); pa_idxset_put(p->connections, c, NULL); @@ -72,9 +75,11 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) pa_protocol_cli* pa_protocol_cli_new(pa_core *core, pa_socket_server *server, pa_module *m, PA_GCC_UNUSED pa_modargs *ma) { pa_protocol_cli* p; - assert(core && server); - p = pa_xmalloc(sizeof(pa_protocol_cli)); + pa_core_assert_ref(core); + pa_assert(server); + + p = pa_xnew(pa_protocol_cli, 1); p->module = m; p->core = core; p->server = server; @@ -86,12 +91,13 @@ pa_protocol_cli* pa_protocol_cli_new(pa_core *core, pa_socket_server *server, pa } static void free_connection(void *p, PA_GCC_UNUSED void *userdata) { - assert(p); + pa_assert(p); + pa_cli_free(p); } void pa_protocol_cli_free(pa_protocol_cli *p) { - assert(p); + pa_assert(p); pa_idxset_free(p->connections, free_connection, NULL); pa_socket_server_unref(p->server); diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 49a78d41..76ba9dd0 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -53,6 +52,8 @@ #include #include #include +#include +#include #include "endianmacros.h" @@ -77,13 +78,15 @@ /* This is heavily based on esound's code */ -struct connection { +typedef struct connection { + pa_msgobject parent; + uint32_t index; - int dead; + pa_bool_t dead; pa_protocol_esound *protocol; pa_iochannel *io; pa_client *client; - int authorized, swap_byte_order; + pa_bool_t authorized, swap_byte_order; void *write_data; size_t write_data_alloc, write_data_index, write_data_length; void *read_data; @@ -100,6 +103,7 @@ struct connection { struct { pa_memblock *current_memblock; size_t memblock_index, fragment_size; + pa_atomic_t missing; } playback; struct { @@ -109,46 +113,62 @@ struct connection { } scache; pa_time_event *auth_timeout_event; -}; +} connection; + +PA_DECLARE_CLASS(connection); +#define CONNECTION(o) (connection_cast(o)) +static PA_DEFINE_CHECK_TYPE(connection, pa_msgobject); struct pa_protocol_esound { - int public; pa_module *module; pa_core *core; + int public; pa_socket_server *server; pa_idxset *connections; + char *sink_name, *source_name; unsigned n_player; uint8_t esd_key[ESD_KEY_LEN]; pa_ip_acl *auth_ip_acl; }; +enum { + SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */ + SINK_INPUT_MESSAGE_DISABLE_PREBUF +}; + +enum { + CONNECTION_MESSAGE_REQUEST_DATA, + CONNECTION_MESSAGE_POST_DATA, + CONNECTION_MESSAGE_UNLINK_CONNECTION +}; + typedef struct proto_handler { size_t data_length; - int (*proc)(struct connection *c, esd_proto_t request, const void *data, size_t length); + int (*proc)(connection *c, esd_proto_t request, const void *data, size_t length); const char *description; } esd_proto_handler_info_t; -static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length); -static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk); +static void sink_input_drop_cb(pa_sink_input *i, size_t length); +static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk); static void sink_input_kill_cb(pa_sink_input *i); -static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i); +static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk); static pa_usec_t source_output_get_latency_cb(pa_source_output *o); static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk); static void source_output_kill_cb(pa_source_output *o); -static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_stream_play(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_get_latency(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_server_info(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_sample_get_id(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_standby_or_resume(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_connect(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_play(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_record(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_get_latency(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_server_info(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_all_info(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_pan(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_sample_cache(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_sample_free_or_play(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_sample_get_id(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_standby_or_resume(connection *c, esd_proto_t request, const void *data, size_t length); /* the big map of protocol handler info */ static struct proto_handler proto_map[ESD_PROTO_MAX] = { @@ -185,25 +205,56 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = { { 0, esd_proto_get_latency, "get latency" } }; -static void connection_free(struct connection *c) { - assert(c); - pa_idxset_remove_by_data(c->protocol->connections, c, NULL); +static void connection_unlink(connection *c) { + pa_assert(c); - if (c->state == ESD_STREAMING_DATA) - c->protocol->n_player--; - - pa_client_free(c->client); + if (!c->protocol) + return; if (c->sink_input) { - pa_sink_input_disconnect(c->sink_input); + pa_sink_input_unlink(c->sink_input); pa_sink_input_unref(c->sink_input); + c->sink_input = NULL; } if (c->source_output) { - pa_source_output_disconnect(c->source_output); + pa_source_output_unlink(c->source_output); pa_source_output_unref(c->source_output); + c->source_output = NULL; } + if (c->client) { + pa_client_free(c->client); + c->client = NULL; + } + + if (c->state == ESD_STREAMING_DATA) + c->protocol->n_player--; + + if (c->io) { + pa_iochannel_free(c->io); + c->io = NULL; + } + + if (c->defer_event) { + c->protocol->core->mainloop->defer_free(c->defer_event); + c->defer_event = NULL; + } + + if (c->auth_timeout_event) { + c->protocol->core->mainloop->time_free(c->auth_timeout_event); + c->auth_timeout_event = NULL; + } + + pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c); + c->protocol = NULL; + connection_unref(c); +} + +static void connection_free(pa_object *obj) { + connection *c = CONNECTION(obj); + pa_assert(c); + if (c->input_memblockq) pa_memblockq_free(c->input_memblockq); if (c->output_memblockq) @@ -215,54 +266,44 @@ static void connection_free(struct connection *c) { pa_xfree(c->read_data); pa_xfree(c->write_data); - if (c->io) - pa_iochannel_free(c->io); - - if (c->defer_event) - c->protocol->core->mainloop->defer_free(c->defer_event); - if (c->scache.memchunk.memblock) pa_memblock_unref(c->scache.memchunk.memblock); pa_xfree(c->scache.name); - if (c->auth_timeout_event) - c->protocol->core->mainloop->time_free(c->auth_timeout_event); - pa_xfree(c->original_name); pa_xfree(c); } -static void connection_write_prepare(struct connection *c, size_t length) { +static void connection_write_prepare(connection *c, size_t length) { size_t t; - assert(c); + pa_assert(c); t = c->write_data_length+length; if (c->write_data_alloc < t) c->write_data = pa_xrealloc(c->write_data, c->write_data_alloc = t); - assert(c->write_data); + pa_assert(c->write_data); } -static void connection_write(struct connection *c, const void *data, size_t length) { +static void connection_write(connection *c, const void *data, size_t length) { size_t i; - assert(c); + pa_assert(c); - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); c->protocol->core->mainloop->defer_enable(c->defer_event, 1); connection_write_prepare(c, length); - assert(c->write_data); + pa_assert(c->write_data); i = c->write_data_length; c->write_data_length += length; - memcpy((char*)c->write_data + i, data, length); + memcpy((uint8_t*) c->write_data + i, data, length); } -static void format_esd2native(int format, int swap_bytes, pa_sample_spec *ss) { - assert(ss); +static void format_esd2native(int format, pa_bool_t swap_bytes, pa_sample_spec *ss) { + pa_assert(ss); ss->channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; if ((format & ESD_MASK_BITS) == ESD_BITS16) @@ -289,11 +330,13 @@ static int format_native2esd(pa_sample_spec *ss) { /*** esound commands ***/ -static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_connect(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { uint32_t ekey; int ok; - assert(length == (ESD_KEY_LEN + sizeof(uint32_t))); + connection_assert_ref(c); + pa_assert(data); + pa_assert(length == (ESD_KEY_LEN + sizeof(uint32_t))); if (!c->authorized) { if (memcmp(data, c->protocol->esd_key, ESD_KEY_LEN) != 0) { @@ -301,7 +344,7 @@ static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t req return -1; } - c->authorized = 1; + c->authorized = TRUE; if (c->auth_timeout_event) { c->protocol->core->mainloop->time_free(c->auth_timeout_event); c->auth_timeout_event = NULL; @@ -312,11 +355,11 @@ static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t req memcpy(&ekey, data, sizeof(uint32_t)); if (ekey == ESD_ENDIAN_KEY) - c->swap_byte_order = 0; + c->swap_byte_order = FALSE; else if (ekey == ESD_SWAP_ENDIAN_KEY) - c->swap_byte_order = 1; + c->swap_byte_order = TRUE; else { - pa_log("client sent invalid endian key"); + pa_log_warn("Client sent invalid endian key"); return -1; } @@ -325,7 +368,7 @@ static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t req return 0; } -static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_stream_play(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { char name[ESD_NAME_MAX], *utf8_name; int32_t format, rate; pa_sample_spec ss; @@ -333,15 +376,17 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t pa_sink *sink = NULL; pa_sink_input_new_data sdata; - assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); + connection_assert_ref(c); + pa_assert(data); + pa_assert(length == (sizeof(int32_t)*2+ESD_NAME_MAX)); memcpy(&format, data, sizeof(int32_t)); - format = MAYBE_INT32_SWAP(c->swap_byte_order, format); - data = (const char*)data + sizeof(int32_t); + format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format); + data = (const char*) data + sizeof(int32_t); memcpy(&rate, data, sizeof(int32_t)); - rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); - data = (const char*)data + sizeof(int32_t); + rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rate); + data = (const char*) data + sizeof(int32_t); ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); @@ -362,7 +407,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t c->original_name = pa_xstrdup(name); - assert(!c->sink_input && !c->input_memblockq); + pa_assert(!c->sink_input && !c->input_memblockq); pa_sink_input_new_data_init(&sdata); sdata.sink = sink; @@ -385,22 +430,26 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t l/PLAYBACK_BUFFER_FRAGMENTS, NULL); pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2); - c->playback.fragment_size = l/10; + c->playback.fragment_size = l/PLAYBACK_BUFFER_FRAGMENTS; + c->sink_input->parent.process_msg = sink_input_process_msg; c->sink_input->peek = sink_input_peek_cb; c->sink_input->drop = sink_input_drop_cb; c->sink_input->kill = sink_input_kill_cb; - c->sink_input->get_latency = sink_input_get_latency_cb; c->sink_input->userdata = c; c->state = ESD_STREAMING_DATA; c->protocol->n_player++; + pa_atomic_store(&c->playback.missing, pa_memblockq_missing(c->input_memblockq)); + + pa_sink_input_put(c->sink_input); + return 0; } -static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length) { +static int esd_proto_stream_record(connection *c, esd_proto_t request, const void *data, size_t length) { char name[ESD_NAME_MAX], *utf8_name; int32_t format, rate; pa_source *source = NULL; @@ -408,15 +457,17 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co size_t l; pa_source_output_new_data sdata; - assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); + connection_assert_ref(c); + pa_assert(data); + pa_assert(length == (sizeof(int32_t)*2+ESD_NAME_MAX)); memcpy(&format, data, sizeof(int32_t)); - format = MAYBE_INT32_SWAP(c->swap_byte_order, format); - data = (const char*)data + sizeof(int32_t); + format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format); + data = (const char*) data + sizeof(int32_t); memcpy(&rate, data, sizeof(int32_t)); - rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); - data = (const char*)data + sizeof(int32_t); + rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rate); + data = (const char*) data + sizeof(int32_t); ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); @@ -436,7 +487,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co return -1; } } else { - assert(request == ESD_PROTO_STREAM_REC); + pa_assert(request == ESD_PROTO_STREAM_REC); if (c->protocol->source_name) { if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) { @@ -455,7 +506,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co c->original_name = pa_xstrdup(name); - assert(!c->output_memblockq && !c->source_output); + pa_assert(!c->output_memblockq && !c->source_output); pa_source_output_new_data_init(&sdata); sdata.source = source; @@ -488,14 +539,18 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co c->protocol->n_player++; + pa_source_output_put(c->source_output); + return 0; } -static int esd_proto_get_latency(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_get_latency(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { pa_sink *sink; int32_t latency; - assert(c && !data && length == 0); + connection_ref(c); + pa_assert(!data); + pa_assert(length == 0); if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) latency = 0; @@ -504,17 +559,19 @@ static int esd_proto_get_latency(struct connection *c, PA_GCC_UNUSED esd_proto_t latency = (int) ((usec*44100)/1000000); } - latency = MAYBE_INT32_SWAP(c->swap_byte_order, latency); + latency = PA_MAYBE_INT32_SWAP(c->swap_byte_order, latency); connection_write(c, &latency, sizeof(int32_t)); return 0; } -static int esd_proto_server_info(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_server_info(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { int32_t rate = 44100, format = ESD_STEREO|ESD_BITS16; int32_t response; pa_sink *sink; - assert(c && data && length == sizeof(int32_t)); + connection_ref(c); + pa_assert(data); + pa_assert(length == sizeof(int32_t)); if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { rate = sink->sample_spec.rate; @@ -525,22 +582,24 @@ static int esd_proto_server_info(struct connection *c, PA_GCC_UNUSED esd_proto_t response = 0; connection_write(c, &response, sizeof(int32_t)); - rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rate); connection_write(c, &rate, sizeof(int32_t)); - format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format); connection_write(c, &format, sizeof(int32_t)); return 0; } -static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length) { +static int esd_proto_all_info(connection *c, esd_proto_t request, const void *data, size_t length) { size_t t, k, s; - struct connection *conn; + connection *conn; uint32_t idx = PA_IDXSET_INVALID; unsigned nsamples; char terminator[sizeof(int32_t)*6+ESD_NAME_MAX]; - assert(c && data && length == sizeof(int32_t)); + connection_ref(c); + pa_assert(data); + pa_assert(length == sizeof(int32_t)); if (esd_proto_server_info(c, request, data, length) < 0) return -1; @@ -561,7 +620,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v if (conn->state != ESD_STREAMING_DATA) continue; - assert(t >= k*2+s); + pa_assert(t >= k*2+s); if (conn->sink_input) { pa_cvolume volume = *pa_sink_input_get_volume(conn->sink_input); @@ -572,7 +631,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v } /* id */ - id = MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) (conn->index+1)); + id = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) (conn->index+1)); connection_write(c, &id, sizeof(int32_t)); /* name */ @@ -584,25 +643,25 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v connection_write(c, name, ESD_NAME_MAX); /* rate */ - rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rate); connection_write(c, &rate, sizeof(int32_t)); /* left */ - lvolume = MAYBE_INT32_SWAP(c->swap_byte_order, lvolume); + lvolume = PA_MAYBE_INT32_SWAP(c->swap_byte_order, lvolume); connection_write(c, &lvolume, sizeof(int32_t)); /*right*/ - rvolume = MAYBE_INT32_SWAP(c->swap_byte_order, rvolume); + rvolume = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rvolume); connection_write(c, &rvolume, sizeof(int32_t)); /*format*/ - format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format); connection_write(c, &format, sizeof(int32_t)); t -= k; } - assert(t == s*(nsamples+1)+k); + pa_assert(t == s*(nsamples+1)+k); t -= k; connection_write(c, terminator, k); @@ -615,10 +674,10 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v int32_t id, rate, lvolume, rvolume, format, len; char name[ESD_NAME_MAX]; - assert(t >= s*2); + pa_assert(t >= s*2); /* id */ - id = MAYBE_INT32_SWAP(c->swap_byte_order, (int) (ce->index+1)); + id = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int) (ce->index+1)); connection_write(c, &id, sizeof(int32_t)); /* name */ @@ -626,57 +685,59 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v if (strncmp(ce->name, SCACHE_PREFIX, sizeof(SCACHE_PREFIX)-1) == 0) strncpy(name, ce->name+sizeof(SCACHE_PREFIX)-1, ESD_NAME_MAX); else - snprintf(name, ESD_NAME_MAX, "native.%s", ce->name); + pa_snprintf(name, ESD_NAME_MAX, "native.%s", ce->name); connection_write(c, name, ESD_NAME_MAX); /* rate */ - rate = MAYBE_UINT32_SWAP(c->swap_byte_order, ce->sample_spec.rate); + rate = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, ce->sample_spec.rate); connection_write(c, &rate, sizeof(int32_t)); /* left */ - lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); + lvolume = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); connection_write(c, &lvolume, sizeof(int32_t)); /*right*/ - rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); + rvolume = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); connection_write(c, &rvolume, sizeof(int32_t)); /*format*/ - format = MAYBE_INT32_SWAP(c->swap_byte_order, format_native2esd(&ce->sample_spec)); + format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format_native2esd(&ce->sample_spec)); connection_write(c, &format, sizeof(int32_t)); /*length*/ - len = MAYBE_INT32_SWAP(c->swap_byte_order, (int) ce->memchunk.length); + len = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int) ce->memchunk.length); connection_write(c, &len, sizeof(int32_t)); t -= s; } } - assert(t == s); + pa_assert(t == s); connection_write(c, terminator, s); return 0; } -static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_stream_pan(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { int32_t ok; uint32_t idx, lvolume, rvolume; - struct connection *conn; + connection *conn; - assert(c && data && length == sizeof(int32_t)*3); + connection_assert_ref(c); + pa_assert(data); + pa_assert(length == sizeof(int32_t)*3); memcpy(&idx, data, sizeof(uint32_t)); - idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; + idx = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; data = (const char*)data + sizeof(uint32_t); memcpy(&lvolume, data, sizeof(uint32_t)); - lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, lvolume); + lvolume = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, lvolume); data = (const char*)data + sizeof(uint32_t); memcpy(&rvolume, data, sizeof(uint32_t)); - rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, rvolume); + rvolume = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, rvolume); data = (const char*)data + sizeof(uint32_t); if ((conn = pa_idxset_get_by_index(c->protocol->connections, idx)) && conn->sink_input) { @@ -694,20 +755,22 @@ static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t return 0; } -static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_sample_cache(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { pa_sample_spec ss; int32_t format, rate, sc_length; uint32_t idx; char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; - assert(c && data && length == (ESD_NAME_MAX+3*sizeof(int32_t))); + connection_assert_ref(c); + pa_assert(data); + pa_assert(length == (ESD_NAME_MAX+3*sizeof(int32_t))); memcpy(&format, data, sizeof(int32_t)); - format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format); data = (const char*)data + sizeof(int32_t); memcpy(&rate, data, sizeof(int32_t)); - rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rate); data = (const char*)data + sizeof(int32_t); ss.rate = rate; @@ -716,7 +779,7 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification."); memcpy(&sc_length, data, sizeof(int32_t)); - sc_length = MAYBE_INT32_SWAP(c->swap_byte_order, sc_length); + sc_length = PA_MAYBE_INT32_SWAP(c->swap_byte_order, sc_length); data = (const char*)data + sizeof(int32_t); CHECK_VALIDITY(sc_length <= MAX_CACHE_SAMPLE_SIZE, "Sample too large (%d bytes).", (int)sc_length); @@ -727,12 +790,12 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in sample name."); - assert(!c->scache.memchunk.memblock); + pa_assert(!c->scache.memchunk.memblock); c->scache.memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, sc_length); c->scache.memchunk.index = 0; c->scache.memchunk.length = sc_length; c->scache.sample_spec = ss; - assert(!c->scache.name); + pa_assert(!c->scache.name); c->scache.name = pa_xstrdup(name); c->state = ESD_CACHING_SAMPLE; @@ -745,12 +808,14 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ return 0; } -static int esd_proto_sample_get_id(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_sample_get_id(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { int32_t ok; uint32_t idx; char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; - assert(c && data && length == ESD_NAME_MAX); + connection_assert_ref(c); + pa_assert(data); + pa_assert(length == ESD_NAME_MAX); strcpy(name, SCACHE_PREFIX); strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX); @@ -767,15 +832,17 @@ static int esd_proto_sample_get_id(struct connection *c, PA_GCC_UNUSED esd_proto return 0; } -static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length) { +static int esd_proto_sample_free_or_play(connection *c, esd_proto_t request, const void *data, size_t length) { int32_t ok; const char *name; uint32_t idx; - assert(c && data && length == sizeof(int32_t)); + connection_assert_ref(c); + pa_assert(data); + pa_assert(length == sizeof(int32_t)); memcpy(&idx, data, sizeof(uint32_t)); - idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; + idx = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; ok = 0; @@ -787,7 +854,7 @@ static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t reque if (pa_scache_play_item(c->protocol->core, name, sink, PA_VOLUME_NORM) >= 0) ok = idx + 1; } else { - assert(request == ESD_PROTO_SAMPLE_FREE); + pa_assert(request == ESD_PROTO_SAMPLE_FREE); if (pa_scache_remove_item(c->protocol->core, name) >= 0) ok = idx + 1; @@ -799,9 +866,11 @@ static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t reque return 0; } -static int esd_proto_standby_or_resume(struct connection *c, PA_GCC_UNUSED esd_proto_t request, PA_GCC_UNUSED const void *data, PA_GCC_UNUSED size_t length) { +static int esd_proto_standby_or_resume(connection *c, PA_GCC_UNUSED esd_proto_t request, PA_GCC_UNUSED const void *data, PA_GCC_UNUSED size_t length) { int32_t ok; + connection_assert_ref(c); + connection_write_prepare(c, sizeof(int32_t) * 2); ok = 1; @@ -814,20 +883,21 @@ static int esd_proto_standby_or_resume(struct connection *c, PA_GCC_UNUSED esd_p /*** client callbacks ***/ static void client_kill_cb(pa_client *c) { - assert(c && c->userdata); - connection_free(c->userdata); + pa_assert(c); + + connection_unlink(CONNECTION(c->userdata)); } /*** pa_iochannel callbacks ***/ -static int do_read(struct connection *c) { - assert(c && c->io); +static int do_read(connection *c) { + connection_assert_ref(c); -/* pa_log("READ"); */ +/* pa_log("READ"); */ if (c->state == ESD_NEXT_REQUEST) { ssize_t r; - assert(c->read_data_length < sizeof(c->request)); + pa_assert(c->read_data_length < sizeof(c->request)); if ((r = pa_iochannel_read(c->io, ((uint8_t*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); @@ -837,7 +907,7 @@ static int do_read(struct connection *c) { if ((c->read_data_length+= r) >= sizeof(c->request)) { struct proto_handler *handler; - c->request = MAYBE_INT32_SWAP(c->swap_byte_order, c->request); + c->request = PA_MAYBE_INT32_SWAP(c->swap_byte_order, c->request); if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) { pa_log("recieved invalid request."); @@ -862,7 +932,7 @@ static int do_read(struct connection *c) { } else { if (c->read_data_alloc < handler->data_length) c->read_data = pa_xrealloc(c->read_data, c->read_data_alloc = handler->data_length); - assert(c->read_data); + pa_assert(c->read_data); c->state = ESD_NEEDS_REQDATA; c->read_data_length = 0; @@ -873,18 +943,21 @@ static int do_read(struct connection *c) { ssize_t r; struct proto_handler *handler = proto_map+c->request; - assert(handler->proc); + pa_assert(handler->proc); - assert(c->read_data && c->read_data_length < handler->data_length); + pa_assert(c->read_data && c->read_data_length < handler->data_length); if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { + if (r < 0 && (errno == EINTR || errno == EAGAIN)) + return 0; + pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } if ((c->read_data_length += r) >= handler->data_length) { size_t l = c->read_data_length; - assert(handler->proc); + pa_assert(handler->proc); c->state = ESD_NEXT_REQUEST; c->read_data_length = 0; @@ -894,16 +967,26 @@ static int do_read(struct connection *c) { } } else if (c->state == ESD_CACHING_SAMPLE) { ssize_t r; + void *p; - assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); + pa_assert(c->scache.memchunk.memblock); + pa_assert(c->scache.name); + pa_assert(c->scache.memchunk.index < c->scache.memchunk.length); + + p = pa_memblock_acquire(c->scache.memchunk.memblock); + r = pa_iochannel_read(c->io, (uint8_t*) p+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index); + pa_memblock_release(c->scache.memchunk.memblock); + + if (r <= 0) { + if (r < 0 && (errno == EINTR || errno == EAGAIN)) + return 0; - if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } c->scache.memchunk.index += r; - assert(c->scache.memchunk.index <= c->scache.memchunk.length); + pa_assert(c->scache.memchunk.index <= c->scache.memchunk.length); if (c->scache.memchunk.index == c->scache.memchunk.length) { uint32_t idx; @@ -928,31 +1011,39 @@ static int do_read(struct connection *c) { pa_memchunk chunk; ssize_t r; size_t l; + void *p; - assert(c->input_memblockq); + pa_assert(c->input_memblockq); /* pa_log("STREAMING_DATA"); */ - if (!(l = pa_memblockq_missing(c->input_memblockq))) + if (!(l = pa_atomic_load(&c->playback.missing))) return 0; if (l > c->playback.fragment_size) l = c->playback.fragment_size; if (c->playback.current_memblock) - if (c->playback.current_memblock->length - c->playback.memblock_index < l) { + if (pa_memblock_get_length(c->playback.current_memblock) - c->playback.memblock_index < l) { pa_memblock_unref(c->playback.current_memblock); c->playback.current_memblock = NULL; c->playback.memblock_index = 0; } if (!c->playback.current_memblock) { - c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, c->playback.fragment_size*2); - assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); + pa_assert_se(c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, c->playback.fragment_size*2)); c->playback.memblock_index = 0; } - if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { + p = pa_memblock_acquire(c->playback.current_memblock); + r = pa_iochannel_read(c->io, (uint8_t*) p+c->playback.memblock_index, l); + pa_memblock_release(c->playback.current_memblock); + + if (r <= 0) { + + if (r < 0 && (errno == EINTR || errno == EAGAIN)) + return 0; + pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } @@ -960,29 +1051,30 @@ static int do_read(struct connection *c) { chunk.memblock = c->playback.current_memblock; chunk.index = c->playback.memblock_index; chunk.length = r; - assert(chunk.memblock); c->playback.memblock_index += r; - assert(c->input_memblockq); - pa_memblockq_push_align(c->input_memblockq, &chunk); - assert(c->sink_input); - pa_sink_notify(c->sink_input->sink); + pa_asyncmsgq_post(c->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, &chunk, NULL); + pa_atomic_sub(&c->playback.missing, r); } return 0; } -static int do_write(struct connection *c) { - assert(c && c->io); +static int do_write(connection *c) { + connection_assert_ref(c); /* pa_log("WRITE"); */ if (c->write_data_length) { ssize_t r; - assert(c->write_data_index < c->write_data_length); + pa_assert(c->write_data_index < c->write_data_length); if ((r = pa_iochannel_write(c->io, (uint8_t*) c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { + + if (r < 0 && (errno == EINTR || errno == EAGAIN)) + return 0; + pa_log("write(): %s", pa_cstrerror(errno)); return -1; } @@ -993,32 +1085,38 @@ static int do_write(struct connection *c) { } else if (c->state == ESD_STREAMING_DATA && c->source_output) { pa_memchunk chunk; ssize_t r; + void *p; - assert(c->output_memblockq); if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) return 0; - assert(chunk.memblock && chunk.length); + pa_assert(chunk.memblock); + pa_assert(chunk.length); + + p = pa_memblock_acquire(chunk.memblock); + r = pa_iochannel_write(c->io, (uint8_t*) p+chunk.index, chunk.length); + pa_memblock_release(chunk.memblock); + + pa_memblock_unref(chunk.memblock); + + if (r < 0) { + + if (r < 0 && (errno == EINTR || errno == EAGAIN)) + return 0; - if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { - pa_memblock_unref(chunk.memblock); pa_log("write(): %s", pa_cstrerror(errno)); return -1; } - pa_memblockq_drop(c->output_memblockq, &chunk, r); - pa_memblock_unref(chunk.memblock); - - pa_source_notify(c->source_output->source); + pa_memblockq_drop(c->output_memblockq, r); } return 0; } -static void do_work(struct connection *c) { - assert(c); +static void do_work(connection *c) { + connection_assert_ref(c); - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); c->protocol->core->mainloop->defer_enable(c->defer_event, 0); if (c->dead) @@ -1044,122 +1142,196 @@ static void do_work(struct connection *c) { fail: if (c->state == ESD_STREAMING_DATA && c->sink_input) { - c->dead = 1; + c->dead = TRUE; pa_iochannel_free(c->io); c->io = NULL; - pa_memblockq_prebuf_disable(c->input_memblockq); - pa_sink_notify(c->sink_input->sink); + pa_asyncmsgq_post(c->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_DISABLE_PREBUF, NULL, 0, NULL, NULL); } else - connection_free(c); + connection_unlink(c); } static void io_callback(pa_iochannel*io, void *userdata) { - struct connection *c = userdata; - assert(io && c && c->io == io); + connection *c = CONNECTION(userdata); + + connection_assert_ref(c); + pa_assert(io); do_work(c); } -/*** defer callback ***/ - static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { - struct connection *c = userdata; - assert(a && c && c->defer_event == e); + connection *c = CONNECTION(userdata); -/* pa_log("DEFER"); */ + connection_assert_ref(c); + pa_assert(e); do_work(c); } -/*** sink_input callbacks ***/ +static int connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) { + connection *c = CONNECTION(o); + connection_assert_ref(c); -static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { - struct connection*c; - assert(i && i->userdata && chunk); - c = i->userdata; + switch (code) { + case CONNECTION_MESSAGE_REQUEST_DATA: + do_work(c); + break; - if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) { + case CONNECTION_MESSAGE_POST_DATA: +/* pa_log("got data %u", chunk->length); */ + pa_memblockq_push_align(c->output_memblockq, chunk); + do_work(c); + break; - if (c->dead) - connection_free(c); - - return -1; + case CONNECTION_MESSAGE_UNLINK_CONNECTION: + connection_unlink(c); + break; } return 0; } -static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { - struct connection*c = i->userdata; - assert(i && c && length); +/*** sink_input callbacks ***/ + +/* Called from thread context */ +static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) { + pa_sink_input *i = PA_SINK_INPUT(o); + connection*c; + + pa_sink_input_assert_ref(i); + c = CONNECTION(i->userdata); + connection_assert_ref(c); + + switch (code) { + + case SINK_INPUT_MESSAGE_POST_DATA: { + pa_assert(chunk); + + /* New data from the main loop */ + pa_memblockq_push_align(c->input_memblockq, chunk); + +/* pa_log("got data, %u", pa_memblockq_get_length(c->input_memblockq)); */ + + return 0; + } -/* pa_log("DROP"); */ + case SINK_INPUT_MESSAGE_DISABLE_PREBUF: { + pa_memblockq_prebuf_disable(c->input_memblockq); + return 0; + } - pa_memblockq_drop(c->input_memblockq, chunk, length); + case PA_SINK_INPUT_MESSAGE_GET_LATENCY: { + pa_usec_t *r = userdata; - /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + *r = pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); - if (!c->dead) - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + /* Fall through, the default handler will add in the extra + * latency added by the resampler */ + } -/* assert(pa_memblockq_get_length(c->input_memblockq) > 2048); */ + default: + return pa_sink_input_process_msg(o, code, userdata, offset, chunk); + } } -static void sink_input_kill_cb(pa_sink_input *i) { - assert(i && i->userdata); - connection_free((struct connection *) i->userdata); +/* Called from thread context */ +static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) { + connection*c; + int r; + + pa_assert(i); + c = CONNECTION(i->userdata); + connection_assert_ref(c); + pa_assert(chunk); + + if ((r = pa_memblockq_peek(c->input_memblockq, chunk)) < 0 && c->dead) + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_UNLINK_CONNECTION, NULL, 0, NULL, NULL); + + return r; +} + +/* Called from thread context */ +static void sink_input_drop_cb(pa_sink_input *i, size_t length) { + connection*c; + size_t old, new; + + pa_assert(i); + c = CONNECTION(i->userdata); + connection_assert_ref(c); + pa_assert(length); + + /* pa_log("DROP"); */ + + old = pa_memblockq_missing(c->input_memblockq); + pa_memblockq_drop(c->input_memblockq, length); + new = pa_memblockq_missing(c->input_memblockq); + + if (new > old) { + if (pa_atomic_add(&c->playback.missing, new - old) <= 0) + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL); + } } -static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { - struct connection*c = i->userdata; - assert(i && c); - return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); +static void sink_input_kill_cb(pa_sink_input *i) { + pa_sink_input_assert_ref(i); + + connection_unlink(CONNECTION(i->userdata)); } /*** source_output callbacks ***/ +/* Called from thread context */ static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { - struct connection *c = o->userdata; - assert(o && c && chunk); - - pa_memblockq_push(c->output_memblockq, chunk); + connection *c; - /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + pa_assert(o); + c = CONNECTION(o->userdata); + pa_assert(c); + pa_assert(chunk); - if (!c->dead) - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_POST_DATA, NULL, 0, chunk, NULL); } static void source_output_kill_cb(pa_source_output *o) { - assert(o && o->userdata); - connection_free((struct connection *) o->userdata); + pa_source_output_assert_ref(o); + + connection_unlink(CONNECTION(o->userdata)); } static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { - struct connection*c = o->userdata; - assert(o && c); + connection*c; + + pa_assert(o); + c = CONNECTION(o->userdata); + pa_assert(c); + return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec); } /*** socket server callback ***/ static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { - struct connection *c = userdata; - assert(m && tv && c && c->auth_timeout_event == e); + connection *c = CONNECTION(userdata); + + pa_assert(m); + pa_assert(tv); + connection_assert_ref(c); + pa_assert(c->auth_timeout_event == e); if (!c->authorized) - connection_free(c); + connection_unlink(c); } static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { - struct connection *c; + connection *c; pa_protocol_esound *p = userdata; char cname[256], pname[128]; - assert(s && io && p); + + pa_assert(s); + pa_assert(io); + pa_assert(p); if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); @@ -1167,23 +1339,23 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) return; } - c = pa_xnew(struct connection, 1); + c = pa_msgobject_new(connection); + c->parent.parent.free = connection_free; + c->parent.process_msg = connection_process_msg; c->protocol = p; c->io = io; pa_iochannel_set_callback(c->io, io_callback, c); pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname)); - snprintf(cname, sizeof(cname), "EsounD client (%s)", pname); - assert(p->core); + pa_snprintf(cname, sizeof(cname), "EsounD client (%s)", pname); c->client = pa_client_new(p->core, __FILE__, cname); - assert(c->client); c->client->owner = p->module; c->client->kill = client_kill_cb; c->client->userdata = c; c->authorized = !!p->public; - c->swap_byte_order = 0; - c->dead = 0; + c->swap_byte_order = FALSE; + c->dead = FALSE; c->read_data_length = 0; c->read_data = pa_xmalloc(c->read_data_alloc = proto_map[ESD_PROTO_CONNECT].data_length); @@ -1203,6 +1375,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->playback.current_memblock = NULL; c->playback.memblock_index = 0; c->playback.fragment_size = 0; + pa_atomic_store(&c->playback.missing, 0); c->scache.memchunk.length = c->scache.memchunk.index = 0; c->scache.memchunk.memblock = NULL; @@ -1212,7 +1385,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) if (!c->authorized && p->auth_ip_acl && pa_ip_acl_check(p->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) { pa_log_info("Client authenticated by IP ACL."); - c->authorized = 1; + c->authorized = TRUE; } if (!c->authorized) { @@ -1224,7 +1397,6 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->auth_timeout_event = NULL; c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c); - assert(c->defer_event); p->core->mainloop->defer_enable(c->defer_event, 0); pa_idxset_put(p->connections, c, &c->index); @@ -1233,22 +1405,22 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) /*** entry points ***/ pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { - pa_protocol_esound *p; + pa_protocol_esound *p = NULL; int public = 0; const char *acl; - assert(core); - assert(server); - assert(m); - assert(ma); - - p = pa_xnew(pa_protocol_esound, 1); + pa_assert(core); + pa_assert(server); + pa_assert(m); + pa_assert(ma); if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) { pa_log("auth-anonymous= expects a boolean argument."); goto fail; } + p = pa_xnew(pa_protocol_esound, 1); + if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", DEFAULT_COOKIE_FILE), p->esd_key, sizeof(p->esd_key)) < 0) goto fail; @@ -1261,13 +1433,12 @@ pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *serve } else p->auth_ip_acl = NULL; + p->core = core; p->module = m; p->public = public; p->server = server; pa_socket_server_set_callback(p->server, on_connection, p); - p->core = core; p->connections = pa_idxset_new(NULL, NULL); - assert(p->connections); p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL)); @@ -1281,17 +1452,20 @@ fail: } void pa_protocol_esound_free(pa_protocol_esound *p) { - struct connection *c; - assert(p); + connection *c; + pa_assert(p); while ((c = pa_idxset_first(p->connections, NULL))) - connection_free(c); - + connection_unlink(c); pa_idxset_free(p->connections, NULL, NULL); + pa_socket_server_unref(p->server); if (p->auth_ip_acl) pa_ip_acl_free(p->auth_ip_acl); + pa_xfree(p->sink_name); + pa_xfree(p->source_name); + pa_xfree(p); } diff --git a/src/pulsecore/protocol-http.c b/src/pulsecore/protocol-http.c index 3541721a..d91ae142 100644 --- a/src/pulsecore/protocol-http.c +++ b/src/pulsecore/protocol-http.c @@ -25,7 +25,6 @@ #include #endif -#include #include #include #include @@ -34,6 +33,7 @@ #include #include +#include #include #include #include @@ -65,11 +65,12 @@ struct pa_protocol_http { static void http_response(struct connection *c, int code, const char *msg, const char *mime) { char s[256]; - assert(c); - assert(msg); - assert(mime); - snprintf(s, sizeof(s), + pa_assert(c); + pa_assert(msg); + pa_assert(mime); + + pa_snprintf(s, sizeof(s), "HTTP/1.0 %i %s\n" "Connection: close\n" "Content-Type: %s\n" @@ -83,14 +84,14 @@ static void http_response(struct connection *c, int code, const char *msg, const static void http_message(struct connection *c, int code, const char *msg, const char *text) { char s[256]; - assert(c); + pa_assert(c); http_response(c, code, msg, "text/html"); if (!text) text = msg; - snprintf(s, sizeof(s), + pa_snprintf(s, sizeof(s), "\n" "\n" "%s\n" @@ -103,21 +104,22 @@ static void http_message(struct connection *c, int code, const char *msg, const static void connection_free(struct connection *c, int del) { - assert(c); + pa_assert(c); if (c->url) pa_xfree(c->url); if (del) pa_idxset_remove_by_data(c->protocol->connections, c, NULL); + pa_ioline_unref(c->line); pa_xfree(c); } static void line_callback(pa_ioline *line, const char *s, void *userdata) { struct connection *c = userdata; - assert(line); - assert(c); + pa_assert(line); + pa_assert(c); if (!s) { /* EOF */ @@ -223,7 +225,10 @@ fail: static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { pa_protocol_http *p = userdata; struct connection *c; - assert(s && io && p); + + pa_assert(s); + pa_assert(io); + pa_assert(p); if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); @@ -231,7 +236,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) return; } - c = pa_xmalloc(sizeof(struct connection)); + c = pa_xnew(struct connection, 1); c->protocol = p; c->line = pa_ioline_new(io); c->state = REQUEST_LINE; @@ -243,9 +248,11 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) pa_protocol_http* pa_protocol_http_new(pa_core *core, pa_socket_server *server, pa_module *m, PA_GCC_UNUSED pa_modargs *ma) { pa_protocol_http* p; - assert(core && server); - p = pa_xmalloc(sizeof(pa_protocol_http)); + pa_core_assert_ref(core); + pa_assert(server); + + p = pa_xnew(pa_protocol_http, 1); p->module = m; p->core = core; p->server = server; @@ -257,12 +264,12 @@ pa_protocol_http* pa_protocol_http_new(pa_core *core, pa_socket_server *server, } static void free_connection(void *p, PA_GCC_UNUSED void *userdata) { - assert(p); + pa_assert(p); connection_free(p, 0); } void pa_protocol_http_free(pa_protocol_http *p) { - assert(p); + pa_assert(p); pa_idxset_free(p->connections, free_connection, NULL); pa_socket_server_unref(p->server); diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index dd41b3d5..9ae0f083 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -28,7 +28,6 @@ #include #include -#include #include #include @@ -61,6 +60,7 @@ #include #include #include +#include #include "protocol-native.h" @@ -72,54 +72,61 @@ #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */ -struct connection; +typedef struct connection connection; struct pa_protocol_native; -struct record_stream { - struct connection *connection; +typedef struct record_stream { + pa_msgobject parent; + + connection *connection; uint32_t index; + pa_source_output *source_output; pa_memblockq *memblockq; size_t fragment_size; -}; +} record_stream; + +typedef struct output_stream { + pa_msgobject parent; +} output_stream; -struct playback_stream { - int type; - struct connection *connection; +typedef struct playback_stream { + output_stream parent; + + connection *connection; uint32_t index; + pa_sink_input *sink_input; pa_memblockq *memblockq; - size_t requested_bytes; int drain_request; uint32_t drain_tag; uint32_t syncid; int underrun; - /* Sync group members */ - PA_LLIST_FIELDS(struct playback_stream); -}; + pa_atomic_t missing; + size_t minreq; + + /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */ + int64_t read_index, write_index; + size_t resampled_chunk_length; +} playback_stream; -struct upload_stream { - int type; - struct connection *connection; +typedef struct upload_stream { + output_stream parent; + + connection *connection; uint32_t index; + pa_memchunk memchunk; size_t length; char *name; pa_sample_spec sample_spec; pa_channel_map channel_map; -}; - -struct output_stream { - int type; -}; - -enum { - UPLOAD_STREAM, - PLAYBACK_STREAM -}; +} upload_stream; struct connection { + pa_msgobject parent; + int authorized; uint32_t version; pa_protocol_native *protocol; @@ -132,10 +139,30 @@ struct connection { pa_time_event *auth_timeout_event; }; +PA_DECLARE_CLASS(record_stream); +#define RECORD_STREAM(o) (record_stream_cast(o)) +static PA_DEFINE_CHECK_TYPE(record_stream, pa_msgobject); + +PA_DECLARE_CLASS(output_stream); +#define OUTPUT_STREAM(o) (output_stream_cast(o)) +static PA_DEFINE_CHECK_TYPE(output_stream, pa_msgobject); + +PA_DECLARE_CLASS(playback_stream); +#define PLAYBACK_STREAM(o) (playback_stream_cast(o)) +static PA_DEFINE_CHECK_TYPE(playback_stream, output_stream); + +PA_DECLARE_CLASS(upload_stream); +#define UPLOAD_STREAM(o) (upload_stream_cast(o)) +static PA_DEFINE_CHECK_TYPE(upload_stream, output_stream); + +PA_DECLARE_CLASS(connection); +#define CONNECTION(o) (connection_cast(o)) +static PA_DEFINE_CHECK_TYPE(connection, pa_msgobject); + struct pa_protocol_native { pa_module *module; - int public; pa_core *core; + int public; pa_socket_server *server; pa_idxset *connections; uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; @@ -146,17 +173,45 @@ struct pa_protocol_native { pa_ip_acl *auth_ip_acl; }; -static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk); -static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length); +enum { + SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */ + SINK_INPUT_MESSAGE_DRAIN, /* disabled prebuf, get playback started. */ + SINK_INPUT_MESSAGE_FLUSH, + SINK_INPUT_MESSAGE_TRIGGER, + SINK_INPUT_MESSAGE_SEEK, + SINK_INPUT_MESSAGE_PREBUF_FORCE, + SINK_INPUT_MESSAGE_UPDATE_LATENCY +}; + +enum { + PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, /* data requested from sink input from the main loop */ + PLAYBACK_STREAM_MESSAGE_UNDERFLOW, + PLAYBACK_STREAM_MESSAGE_OVERFLOW, + PLAYBACK_STREAM_MESSAGE_DRAIN_ACK +}; + +enum { + RECORD_STREAM_MESSAGE_POST_DATA /* data from source output to main loop */ +}; + +enum { + CONNECTION_MESSAGE_RELEASE, + CONNECTION_MESSAGE_REVOKE +}; + +static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk); +static void sink_input_drop_cb(pa_sink_input *i, size_t length); static void sink_input_kill_cb(pa_sink_input *i); -static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i); +static void send_memblock(connection *c); static void request_bytes(struct playback_stream*s); static void source_output_kill_cb(pa_source_output *o); static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk); static pa_usec_t source_output_get_latency_cb(pa_source_output *o); +static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk); + static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); @@ -179,8 +234,7 @@ static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_set_mute(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_flush_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_trigger_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); @@ -193,6 +247,7 @@ static void command_get_autoload_info_list(pa_pdispatch *pd, uint32_t command, u static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = NULL, @@ -239,12 +294,16 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume, [PA_COMMAND_SET_SINK_MUTE] = command_set_mute, + [PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute, [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute, + [PA_COMMAND_SUSPEND_SINK] = command_suspend, + [PA_COMMAND_SUSPEND_SOURCE] = command_suspend, + [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream, - [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_flush_playback_stream, - [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_prebuf_playback_stream, - [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_prebuf_playback_stream, + [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream, + [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream, + [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream, [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream, [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream, @@ -269,74 +328,146 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { /* structure management */ -static struct upload_stream* upload_stream_new( - struct connection *c, - const pa_sample_spec *ss, - const pa_channel_map *map, - const char *name, size_t length) { +static void upload_stream_unlink(upload_stream *s) { + pa_assert(s); + + if (!s->connection) + return; + + pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s); + s->connection = NULL; + upload_stream_unref(s); +} + +static void upload_stream_free(pa_object *o) { + upload_stream *s = UPLOAD_STREAM(o); + pa_assert(s); + + upload_stream_unlink(s); + + pa_xfree(s->name); - struct upload_stream *s; - assert(c && ss && name && length); + if (s->memchunk.memblock) + pa_memblock_unref(s->memchunk.memblock); - s = pa_xnew(struct upload_stream, 1); - s->type = UPLOAD_STREAM; + pa_xfree(s); +} + +static upload_stream* upload_stream_new( + connection *c, + const pa_sample_spec *ss, + const pa_channel_map *map, + const char *name, size_t length) { + + upload_stream *s; + + pa_assert(c); + pa_assert(ss); + pa_assert(name); + pa_assert(length > 0); + + s = pa_msgobject_new(upload_stream); + s->parent.parent.parent.free = upload_stream_free; s->connection = c; s->sample_spec = *ss; s->channel_map = *map; s->name = pa_xstrdup(name); - - s->memchunk.memblock = NULL; - s->memchunk.index = 0; - s->memchunk.length = 0; - + pa_memchunk_reset(&s->memchunk); s->length = length; pa_idxset_put(c->output_streams, s, &s->index); + return s; } -static void upload_stream_free(struct upload_stream *o) { - assert(o && o->connection); +static void record_stream_unlink(record_stream *s) { + pa_assert(s); + + if (!s->connection) + return; + + if (s->source_output) { + pa_source_output_unlink(s->source_output); + pa_source_output_unref(s->source_output); + s->source_output = NULL; + } + + pa_assert_se(pa_idxset_remove_by_data(s->connection->record_streams, s, NULL) == s); + s->connection = NULL; + record_stream_unref(s); +} + +static void record_stream_free(pa_object *o) { + record_stream *s = RECORD_STREAM(o); + pa_assert(s); + + record_stream_unlink(s); + + pa_memblockq_free(s->memblockq); + pa_xfree(s); +} + +static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) { + record_stream *s = RECORD_STREAM(o); + record_stream_assert_ref(s); - pa_idxset_remove_by_data(o->connection->output_streams, o, NULL); + if (!s->connection) + return -1; - pa_xfree(o->name); + switch (code) { - if (o->memchunk.memblock) - pa_memblock_unref(o->memchunk.memblock); + case RECORD_STREAM_MESSAGE_POST_DATA: - pa_xfree(o); + if (pa_memblockq_push_align(s->memblockq, chunk) < 0) { +/* pa_log_warn("Failed to push data into output queue."); */ + return -1; + } + + if (!pa_pstream_is_pending(s->connection->pstream)) + send_memblock(s->connection); + + break; + } + + return 0; } -static struct record_stream* record_stream_new( - struct connection *c, - pa_source *source, - const pa_sample_spec *ss, - const pa_channel_map *map, - const char *name, - size_t maxlength, - size_t fragment_size) { +static record_stream* record_stream_new( + connection *c, + pa_source *source, + const pa_sample_spec *ss, + const pa_channel_map *map, + const char *name, + uint32_t *maxlength, + uint32_t fragment_size, + int corked) { - struct record_stream *s; + record_stream *s; pa_source_output *source_output; size_t base; pa_source_output_new_data data; - assert(c && ss && name && maxlength); + pa_assert(c); + pa_assert(ss); + pa_assert(name); + pa_assert(maxlength); + pa_assert(*maxlength > 0); pa_source_output_new_data_init(&data); + data.module = c->protocol->module; + data.client = c->client; data.source = source; data.driver = __FILE__; data.name = name; pa_source_output_new_data_set_sample_spec(&data, ss); pa_source_output_new_data_set_channel_map(&data, map); - data.module = c->protocol->module; - data.client = c->client; - if (!(source_output = pa_source_output_new(c->protocol->core, &data, 0))) + if (!(source_output = pa_source_output_new(c->protocol->core, &data, corked ? PA_SOURCE_OUTPUT_START_CORKED : 0))) return NULL; - s = pa_xnew(struct record_stream, 1); + s = pa_msgobject_new(record_stream); + s->parent.parent.free = record_stream_free; + s->parent.process_msg = record_stream_process_msg; s->connection = c; s->source_output = source_output; s->source_output->push = source_output_push_cb; @@ -346,58 +477,159 @@ static struct record_stream* record_stream_new( s->memblockq = pa_memblockq_new( 0, - maxlength, + *maxlength, 0, base = pa_frame_size(ss), 1, 0, NULL); - assert(s->memblockq); s->fragment_size = (fragment_size/base)*base; - if (!s->fragment_size) + if (s->fragment_size <= 0) s->fragment_size = base; + *maxlength = pa_memblockq_get_maxlength(s->memblockq); pa_idxset_put(c->record_streams, s, &s->index); + + pa_source_output_put(s->source_output); return s; } -static void record_stream_free(struct record_stream* r) { - assert(r && r->connection); +static void playback_stream_unlink(playback_stream *s) { + pa_assert(s); + + if (!s->connection) + return; + + if (s->sink_input) { + pa_sink_input_unlink(s->sink_input); + pa_sink_input_unref(s->sink_input); + s->sink_input = NULL; + } + + if (s->drain_request) + pa_pstream_send_error(s->connection->pstream, s->drain_tag, PA_ERR_NOENTITY); + + pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s); + s->connection = NULL; + playback_stream_unref(s); +} + +static void playback_stream_free(pa_object* o) { + playback_stream *s = PLAYBACK_STREAM(o); + pa_assert(s); + + playback_stream_unlink(s); + + pa_memblockq_free(s->memblockq); + pa_xfree(s); +} + +static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) { + playback_stream *s = PLAYBACK_STREAM(o); + playback_stream_assert_ref(s); + + if (!s->connection) + return -1; + + switch (code) { + case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: { + pa_tagstruct *t; + uint32_t l = 0; + + for (;;) { + int32_t k; + + if ((k = pa_atomic_load(&s->missing)) <= 0) + break; + + l += k; + + if (l < s->minreq) + break; + + if (pa_atomic_sub(&s->missing, k) <= k) + break; + } + + if (l < s->minreq) + break; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_REQUEST); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, s->index); + pa_tagstruct_putu32(t, l); + pa_pstream_send_tagstruct(s->connection->pstream, t); + +/* pa_log("Requesting %u bytes", l); */ + break; + } + + case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: { + pa_tagstruct *t; + + /* Report that we're empty */ + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, s->index); + pa_pstream_send_tagstruct(s->connection->pstream, t); + break; + } + + case PLAYBACK_STREAM_MESSAGE_OVERFLOW: { + pa_tagstruct *t; + + /* Notify the user we're overflowed*/ + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, s->index); + pa_pstream_send_tagstruct(s->connection->pstream, t); + break; + } - pa_idxset_remove_by_data(r->connection->record_streams, r, NULL); - pa_source_output_disconnect(r->source_output); - pa_source_output_unref(r->source_output); - pa_memblockq_free(r->memblockq); - pa_xfree(r); + case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK: + pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata)); + break; + + } + + return 0; } -static struct playback_stream* playback_stream_new( - struct connection *c, +static playback_stream* playback_stream_new( + connection *c, pa_sink *sink, const pa_sample_spec *ss, const pa_channel_map *map, const char *name, - size_t maxlength, - size_t tlength, - size_t prebuf, - size_t minreq, + uint32_t *maxlength, + uint32_t *tlength, + uint32_t *prebuf, + uint32_t *minreq, pa_cvolume *volume, - uint32_t syncid) { + uint32_t syncid, + int corked, + uint32_t *missing) { - struct playback_stream *s, *ssync; + playback_stream *s, *ssync; pa_sink_input *sink_input; pa_memblock *silence; uint32_t idx; int64_t start_index; pa_sink_input_new_data data; - assert(c && ss && name && maxlength); + pa_assert(c); + pa_assert(ss); + pa_assert(name); + pa_assert(maxlength); /* Find syncid group */ for (ssync = pa_idxset_first(c->output_streams, &idx); ssync; ssync = pa_idxset_next(c->output_streams, &idx)) { - if (ssync->type != PLAYBACK_STREAM) + if (!playback_stream_isinstance(ssync)) continue; if (ssync->syncid == syncid) @@ -405,8 +637,13 @@ static struct playback_stream* playback_stream_new( } /* Synced streams must connect to the same sink */ - if (ssync) - sink = ssync->sink_input->sink; + if (ssync) { + + if (!sink) + sink = ssync->sink_input->sink; + else if (sink != ssync->sink_input->sink) + return NULL; + } pa_sink_input_new_data_init(&data); data.sink = sink; @@ -417,146 +654,158 @@ static struct playback_stream* playback_stream_new( pa_sink_input_new_data_set_volume(&data, volume); data.module = c->protocol->module; data.client = c->client; + data.sync_base = ssync ? ssync->sink_input : NULL; - if (!(sink_input = pa_sink_input_new(c->protocol->core, &data, 0))) + if (!(sink_input = pa_sink_input_new(c->protocol->core, &data, corked ? PA_SINK_INPUT_START_CORKED : 0))) return NULL; - s = pa_xnew(struct playback_stream, 1); - s->type = PLAYBACK_STREAM; + s = pa_msgobject_new(playback_stream); + s->parent.parent.parent.free = playback_stream_free; + s->parent.parent.process_msg = playback_stream_process_msg; s->connection = c; s->syncid = syncid; s->sink_input = sink_input; s->underrun = 1; + s->sink_input->parent.process_msg = sink_input_process_msg; s->sink_input->peek = sink_input_peek_cb; s->sink_input->drop = sink_input_drop_cb; s->sink_input->kill = sink_input_kill_cb; - s->sink_input->get_latency = sink_input_get_latency_cb; s->sink_input->userdata = s; - if (ssync) { - /* Sync id found, now find head of list */ - PA_LLIST_FIND_HEAD(struct playback_stream, ssync, &ssync); - - /* Prepend ourselves */ - PA_LLIST_PREPEND(struct playback_stream, ssync, s); - - /* Set our start index to the current read index of the other grozp member(s) */ - assert(ssync->next); - start_index = pa_memblockq_get_read_index(ssync->next->memblockq); - } else { - /* This ia a new sync group */ - PA_LLIST_INIT(struct playback_stream, s); - start_index = 0; - } + start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0; silence = pa_silence_memblock_new(c->protocol->core->mempool, ss, 0); s->memblockq = pa_memblockq_new( start_index, - maxlength, - tlength, + *maxlength, + *tlength, pa_frame_size(ss), - prebuf, - minreq, + *prebuf, + *minreq, silence); pa_memblock_unref(silence); - s->requested_bytes = 0; + *maxlength = (uint32_t) pa_memblockq_get_maxlength(s->memblockq); + *tlength = (uint32_t) pa_memblockq_get_tlength(s->memblockq); + *prebuf = (uint32_t) pa_memblockq_get_prebuf(s->memblockq); + *minreq = (uint32_t) pa_memblockq_get_minreq(s->memblockq); + *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq); + + s->minreq = pa_memblockq_get_minreq(s->memblockq); + pa_atomic_store(&s->missing, 0); s->drain_request = 0; pa_idxset_put(c->output_streams, s, &s->index); + pa_sink_input_put(s->sink_input); + return s; } -static void playback_stream_free(struct playback_stream* p) { - struct playback_stream *head; - assert(p && p->connection); +static int connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) { + connection *c = CONNECTION(o); + connection_assert_ref(c); - if (p->drain_request) - pa_pstream_send_error(p->connection->pstream, p->drain_tag, PA_ERR_NOENTITY); + if (!c->protocol) + return -1; - PA_LLIST_FIND_HEAD(struct playback_stream, p, &head); - PA_LLIST_REMOVE(struct playback_stream, head, p); + switch (code) { - pa_idxset_remove_by_data(p->connection->output_streams, p, NULL); - pa_sink_input_disconnect(p->sink_input); - pa_sink_input_unref(p->sink_input); - pa_memblockq_free(p->memblockq); - pa_xfree(p); + case CONNECTION_MESSAGE_REVOKE: + pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata)); + break; + + case CONNECTION_MESSAGE_RELEASE: + pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata)); + break; + } + + return 0; } -static void connection_free(struct connection *c) { - struct record_stream *r; - struct output_stream *o; - assert(c && c->protocol); +static void connection_unlink(connection *c) { + record_stream *r; + output_stream *o; + + pa_assert(c); + + if (!c->protocol) + return; - pa_idxset_remove_by_data(c->protocol->connections, c, NULL); while ((r = pa_idxset_first(c->record_streams, NULL))) - record_stream_free(r); - pa_idxset_free(c->record_streams, NULL, NULL); + record_stream_unlink(r); while ((o = pa_idxset_first(c->output_streams, NULL))) - if (o->type == PLAYBACK_STREAM) - playback_stream_free((struct playback_stream*) o); + if (playback_stream_isinstance(o)) + playback_stream_unlink(PLAYBACK_STREAM(o)); else - upload_stream_free((struct upload_stream*) o); - pa_idxset_free(c->output_streams, NULL, NULL); - - pa_pdispatch_unref(c->pdispatch); - pa_pstream_close(c->pstream); - pa_pstream_unref(c->pstream); - pa_client_free(c->client); + upload_stream_unlink(UPLOAD_STREAM(o)); if (c->subscription) pa_subscription_free(c->subscription); - if (c->auth_timeout_event) + if (c->pstream) + pa_pstream_unlink(c->pstream); + + if (c->auth_timeout_event) { c->protocol->core->mainloop->time_free(c->auth_timeout_event); + c->auth_timeout_event = NULL; + } - pa_xfree(c); + pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c); + c->protocol = NULL; + connection_unref(c); } -static void request_bytes(struct playback_stream *s) { - pa_tagstruct *t; - size_t l; - assert(s); +static void connection_free(pa_object *o) { + connection *c = CONNECTION(o); - if (!(l = pa_memblockq_missing(s->memblockq))) - return; + pa_assert(c); - if (l <= s->requested_bytes) - return; + connection_unlink(c); - l -= s->requested_bytes; + pa_idxset_free(c->record_streams, NULL, NULL); + pa_idxset_free(c->output_streams, NULL, NULL); - if (l < pa_memblockq_get_minreq(s->memblockq)) - return; + pa_pdispatch_unref(c->pdispatch); + pa_pstream_unref(c->pstream); + pa_client_free(c->client); - s->requested_bytes += l; + pa_xfree(c); +} - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REQUEST); - pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ - pa_tagstruct_putu32(t, s->index); - pa_tagstruct_putu32(t, l); - pa_pstream_send_tagstruct(s->connection->pstream, t); +/* Called from thread context */ +static void request_bytes(playback_stream *s) { + size_t m, previous_missing; -/* pa_log("Requesting %u bytes", l); */ + playback_stream_assert_ref(s); + + m = pa_memblockq_pop_missing(s->memblockq); + + if (m <= 0) + return; + +/* pa_log("request_bytes(%u)", m); */ + + previous_missing = pa_atomic_add(&s->missing, m); + if (previous_missing < s->minreq && previous_missing+m >= s->minreq) { + pa_assert(pa_thread_mq_get()); + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL); + } } -static void send_memblock(struct connection *c) { +static void send_memblock(connection *c) { uint32_t start; - struct record_stream *r; + record_stream *r; start = PA_IDXSET_INVALID; for (;;) { pa_memchunk chunk; - if (!(r = pa_idxset_rrobin(c->record_streams, &c->rrobin_index))) + if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index)))) return; if (start == PA_IDXSET_INVALID) @@ -571,7 +820,8 @@ static void send_memblock(struct connection *c) { schunk.length = r->fragment_size; pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk); - pa_memblockq_drop(r->memblockq, &chunk, schunk.length); + + pa_memblockq_drop(r->memblockq, schunk.length); pa_memblock_unref(schunk.memblock); return; @@ -579,9 +829,9 @@ static void send_memblock(struct connection *c) { } } -static void send_playback_stream_killed(struct playback_stream *p) { +static void send_playback_stream_killed(playback_stream *p) { pa_tagstruct *t; - assert(p); + playback_stream_assert_ref(p); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED); @@ -590,9 +840,9 @@ static void send_playback_stream_killed(struct playback_stream *p) { pa_pstream_send_tagstruct(p->connection->pstream, t); } -static void send_record_stream_killed(struct record_stream *r) { +static void send_record_stream_killed(record_stream *r) { pa_tagstruct *t; - assert(r); + record_stream_assert_ref(r); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED); @@ -601,96 +851,219 @@ static void send_record_stream_killed(struct record_stream *r) { pa_pstream_send_tagstruct(r->connection->pstream, t); } -/*** sinkinput callbacks ***/ +/*** sink input callbacks ***/ -static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { - struct playback_stream *s; - assert(i && i->userdata && chunk); - s = i->userdata; +/* Called from thread context */ +static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) { + pa_sink_input *i = PA_SINK_INPUT(o); + playback_stream *s; - if (pa_memblockq_get_length(s->memblockq) <= 0 && !s->underrun) { - pa_tagstruct *t; + pa_sink_input_assert_ref(i); + s = PLAYBACK_STREAM(i->userdata); + playback_stream_assert_ref(s); + + switch (code) { + + case SINK_INPUT_MESSAGE_SEEK: + pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata)); + request_bytes(s); + return 0; + + case SINK_INPUT_MESSAGE_POST_DATA: { + pa_assert(chunk); + +/* pa_log("sink input post: %u", chunk->length); */ + + if (pa_memblockq_push_align(s->memblockq, chunk) < 0) { + + pa_log_warn("Failed to push data into queue"); + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL); + pa_memblockq_seek(s->memblockq, chunk->length, PA_SEEK_RELATIVE); + } - /* Report that we're empty */ + request_bytes(s); - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW); - pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ - pa_tagstruct_putu32(t, s->index); - pa_pstream_send_tagstruct(s->connection->pstream, t); + s->underrun = 0; + return 0; + } + + case SINK_INPUT_MESSAGE_DRAIN: { + + pa_memblockq_prebuf_disable(s->memblockq); + if (!pa_memblockq_is_readable(s->memblockq)) + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL); + else { + s->drain_tag = PA_PTR_TO_UINT(userdata); + s->drain_request = 1; + } + request_bytes(s); + + return 0; + } + + case SINK_INPUT_MESSAGE_FLUSH: + case SINK_INPUT_MESSAGE_PREBUF_FORCE: + case SINK_INPUT_MESSAGE_TRIGGER: { + + pa_sink_input *isync; + void (*func)(pa_memblockq *bq); + + switch (code) { + case SINK_INPUT_MESSAGE_FLUSH: + func = pa_memblockq_flush; + break; + + case SINK_INPUT_MESSAGE_PREBUF_FORCE: + func = pa_memblockq_prebuf_force; + break; + + case SINK_INPUT_MESSAGE_TRIGGER: + func = pa_memblockq_prebuf_disable; + break; + + default: + pa_assert_not_reached(); + } + + func(s->memblockq); + s->underrun = 0; + request_bytes(s); + + /* Do the same for all other members in the sync group */ + for (isync = i->sync_prev; isync; isync = isync->sync_prev) { + playback_stream *ssync = PLAYBACK_STREAM(isync->userdata); + func(ssync->memblockq); + ssync->underrun = 0; + request_bytes(ssync); + } + + for (isync = i->sync_next; isync; isync = isync->sync_next) { + playback_stream *ssync = PLAYBACK_STREAM(isync->userdata); + func(ssync->memblockq); + ssync->underrun = 0; + request_bytes(ssync); + } + + return 0; + } + + case SINK_INPUT_MESSAGE_UPDATE_LATENCY: + + s->read_index = pa_memblockq_get_read_index(s->memblockq); + s->write_index = pa_memblockq_get_write_index(s->memblockq); + s->resampled_chunk_length = s->sink_input->thread_info.resampled_chunk.memblock ? s->sink_input->thread_info.resampled_chunk.length : 0; + return 0; + + case PA_SINK_INPUT_MESSAGE_SET_STATE: + + pa_memblockq_prebuf_force(s->memblockq); + request_bytes(s); + break; + + case PA_SINK_INPUT_MESSAGE_GET_LATENCY: { + pa_usec_t *r = userdata; + + *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec); + + /* Fall through, the default handler will add in the extra + * latency added by the resampler */ + break; + } + } + + return pa_sink_input_process_msg(o, code, userdata, offset, chunk); +} + +/* Called from thread context */ +static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) { + playback_stream *s; + + pa_sink_input_assert_ref(i); + s = PLAYBACK_STREAM(i->userdata); + playback_stream_assert_ref(s); + pa_assert(chunk); + + if (pa_memblockq_get_length(s->memblockq) <= 0 && !s->underrun) { + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, 0, NULL, NULL); s->underrun = 1; } if (pa_memblockq_peek(s->memblockq, chunk) < 0) { -/* pa_log("peek: failure"); */ +/* pa_log("peek: failure"); */ return -1; } -/* pa_log("peek: %u", chunk->length); */ +/* pa_log("peek: %u", chunk->length); */ + + request_bytes(s); return 0; } -static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { - struct playback_stream *s; - assert(i && i->userdata && length); - s = i->userdata; +/* Called from thread context */ +static void sink_input_drop_cb(pa_sink_input *i, size_t length) { + playback_stream *s; - pa_memblockq_drop(s->memblockq, chunk, length); + pa_sink_input_assert_ref(i); + s = PLAYBACK_STREAM(i->userdata); + playback_stream_assert_ref(s); + pa_assert(length > 0); - request_bytes(s); + pa_memblockq_drop(s->memblockq, length); if (s->drain_request && !pa_memblockq_is_readable(s->memblockq)) { - pa_pstream_send_simple_ack(s->connection->pstream, s->drain_tag); s->drain_request = 0; + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, PA_UINT_TO_PTR(s->drain_tag), 0, NULL, NULL); } -/* pa_log("after_drop: %u %u", pa_memblockq_get_length(s->memblockq), pa_memblockq_is_readable(s->memblockq)); */ -} + request_bytes(s); -static void sink_input_kill_cb(pa_sink_input *i) { - assert(i && i->userdata); - send_playback_stream_killed((struct playback_stream *) i->userdata); - playback_stream_free((struct playback_stream *) i->userdata); +/* pa_log("after_drop: %u %u", pa_memblockq_get_length(s->memblockq), pa_memblockq_is_readable(s->memblockq)); */ } -static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { - struct playback_stream *s; - assert(i && i->userdata); - s = i->userdata; +static void sink_input_kill_cb(pa_sink_input *i) { + playback_stream *s; - /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/ + pa_sink_input_assert_ref(i); + s = PLAYBACK_STREAM(i->userdata); + playback_stream_assert_ref(s); - return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec); + send_playback_stream_killed(s); + playback_stream_unlink(s); } /*** source_output callbacks ***/ +/* Called from thread context */ static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { - struct record_stream *s; - assert(o && o->userdata && chunk); - s = o->userdata; + record_stream *s; - if (pa_memblockq_push_align(s->memblockq, chunk) < 0) { - pa_log_warn("Failed to push data into output queue."); - return; - } + pa_source_output_assert_ref(o); + s = RECORD_STREAM(o->userdata); + record_stream_assert_ref(s); + pa_assert(chunk); - if (!pa_pstream_is_pending(s->connection->pstream)) - send_memblock(s->connection); + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL); } static void source_output_kill_cb(pa_source_output *o) { - assert(o && o->userdata); - send_record_stream_killed((struct record_stream *) o->userdata); - record_stream_free((struct record_stream *) o->userdata); + record_stream *s; + + pa_source_output_assert_ref(o); + s = RECORD_STREAM(o->userdata); + record_stream_assert_ref(s); + + send_record_stream_killed(s); + record_stream_unlink(s); } static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { - struct record_stream *s; - assert(o && o->userdata); - s = o->userdata; + record_stream *s; + + pa_source_output_assert_ref(o); + s = RECORD_STREAM(o->userdata); + record_stream_assert_ref(s); /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/ @@ -699,9 +1072,9 @@ static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { /*** pdispatch callbacks ***/ -static void protocol_error(struct connection *c) { +static void protocol_error(connection *c) { pa_log("protocol error, kicking client"); - connection_free(c); + connection_unlink(c); } #define CHECK_VALIDITY(pstream, expression, tag, error) do { \ @@ -721,9 +1094,9 @@ static pa_tagstruct *reply_new(uint32_t tag) { } static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - struct playback_stream *s; - uint32_t maxlength, tlength, prebuf, minreq, sink_index, syncid; + connection *c = CONNECTION(userdata); + playback_stream *s; + uint32_t maxlength, tlength, prebuf, minreq, sink_index, syncid, missing; const char *name, *sink_name; pa_sample_spec ss; pa_channel_map map; @@ -732,7 +1105,8 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC pa_cvolume volume; int corked; - assert(c && t && c->protocol && c->protocol->core); + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_get( t, @@ -773,34 +1147,35 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); } - s = playback_stream_new(c, sink, &ss, &map, name, maxlength, tlength, prebuf, minreq, &volume, syncid); + s = playback_stream_new(c, sink, &ss, &map, name, &maxlength, &tlength, &prebuf, &minreq, &volume, syncid, corked, &missing); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); - pa_sink_input_cork(s->sink_input, corked); - reply = reply_new(tag); pa_tagstruct_putu32(reply, s->index); - assert(s->sink_input); + pa_assert(s->sink_input); pa_tagstruct_putu32(reply, s->sink_input->index); - pa_tagstruct_putu32(reply, s->requested_bytes = pa_memblockq_missing(s->memblockq)); + pa_tagstruct_putu32(reply, missing); + +/* pa_log("initial request is %u", missing); */ if (c->version >= 9) { /* Since 0.9 we support sending the buffer metrics back to the client */ - pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_maxlength(s->memblockq)); - pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_tlength(s->memblockq)); - pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_prebuf(s->memblockq)); - pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_minreq(s->memblockq)); + pa_tagstruct_putu32(reply, (uint32_t) maxlength); + pa_tagstruct_putu32(reply, (uint32_t) tlength); + pa_tagstruct_putu32(reply, (uint32_t) prebuf); + pa_tagstruct_putu32(reply, (uint32_t) minreq); } pa_pstream_send_tagstruct(c->pstream, reply); - request_bytes(s); } static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); uint32_t channel; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_getu32(t, &channel) < 0 || !pa_tagstruct_eof(t)) { @@ -810,39 +1185,52 @@ static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - if (command == PA_COMMAND_DELETE_PLAYBACK_STREAM) { - struct playback_stream *s; - if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != PLAYBACK_STREAM)) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); - return; + switch (command) { + + case PA_COMMAND_DELETE_PLAYBACK_STREAM: { + playback_stream *s; + if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); + return; + } + + playback_stream_unlink(s); + break; } - playback_stream_free(s); - } else if (command == PA_COMMAND_DELETE_RECORD_STREAM) { - struct record_stream *s; - if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); - return; + case PA_COMMAND_DELETE_RECORD_STREAM: { + record_stream *s; + if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); + return; + } + + record_stream_unlink(s); + break; } - record_stream_free(s); - } else { - struct upload_stream *s; - assert(command == PA_COMMAND_DELETE_UPLOAD_STREAM); - if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != UPLOAD_STREAM)) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); - return; + case PA_COMMAND_DELETE_UPLOAD_STREAM: { + upload_stream *s; + + if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); + return; + } + + upload_stream_unlink(s); + break; } - upload_stream_free(s); + default: + pa_assert_not_reached(); } pa_pstream_send_simple_ack(c->pstream, tag); } static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - struct record_stream *s; + connection *c = CONNECTION(userdata); + record_stream *s; uint32_t maxlength, fragment_size; uint32_t source_index; const char *name, *source_name; @@ -851,7 +1239,9 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_tagstruct *reply; pa_source *source = NULL; int corked; - assert(c && t && c->protocol && c->protocol->core); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_get_sample_spec(t, &ss) < 0 || @@ -882,20 +1272,18 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY); } - s = record_stream_new(c, source, &ss, &map, name, maxlength, fragment_size); + s = record_stream_new(c, source, &ss, &map, name, &maxlength, fragment_size, corked); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); - pa_source_output_cork(s->source_output, corked); - reply = reply_new(tag); pa_tagstruct_putu32(reply, s->index); - assert(s->source_output); + pa_assert(s->source_output); pa_tagstruct_putu32(reply, s->source_output->index); if (c->version >= 9) { /* Since 0.9 we support sending the buffer metrics back to the client */ - pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_maxlength(s->memblockq)); + pa_tagstruct_putu32(reply, (uint32_t) maxlength); pa_tagstruct_putu32(reply, (uint32_t) s->fragment_size); } @@ -903,8 +1291,10 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ } static void command_exit(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - assert(c && t); + connection *c = CONNECTION(userdata); + + connection_assert_ref(c); + pa_assert(t); if (!pa_tagstruct_eof(t)) { protocol_error(c); @@ -913,16 +1303,17 @@ static void command_exit(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop); c->protocol->core->mainloop->quit(c->protocol->core->mainloop, 0); pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */ } static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); const void*cookie; pa_tagstruct *reply; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_getu32(t, &c->version) < 0 || pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 || @@ -1015,9 +1406,11 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t } static void command_set_client_name(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); const char *name; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_gets(t, &name) < 0 || !pa_tagstruct_eof(t)) { @@ -1032,10 +1425,12 @@ static void command_set_client_name(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE } static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); const char *name; uint32_t idx = PA_IDXSET_INVALID; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_gets(t, &name) < 0 || !pa_tagstruct_eof(t)) { @@ -1052,7 +1447,7 @@ static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uin idx = sink->index; } else { pa_source *source; - assert(command == PA_COMMAND_LOOKUP_SOURCE); + pa_assert(command == PA_COMMAND_LOOKUP_SOURCE); if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1))) idx = source->index; } @@ -1068,10 +1463,12 @@ static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uin } static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); uint32_t idx; - struct playback_stream *s; - assert(c && t); + playback_stream *s; + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_getu32(t, &idx) < 0 || !pa_tagstruct_eof(t)) { @@ -1082,29 +1479,18 @@ static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); s = pa_idxset_get_by_index(c->output_streams, idx); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY); - s->drain_request = 0; - - pa_memblockq_prebuf_disable(s->memblockq); - - if (!pa_memblockq_is_readable(s->memblockq)) { -/* pa_log("immediate drain: %u", pa_memblockq_get_length(s->memblockq)); */ - pa_pstream_send_simple_ack(c->pstream, tag); - } else { -/* pa_log("slow drain triggered"); */ - s->drain_request = 1; - s->drain_tag = tag; - - pa_sink_notify(s->sink_input->sink); - } + pa_asyncmsgq_post(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_DRAIN, PA_UINT_TO_PTR(tag), 0, NULL, NULL); } static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); pa_tagstruct *reply; const pa_mempool_stat *stat; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (!pa_tagstruct_eof(t)) { protocol_error(c); @@ -1125,13 +1511,15 @@ static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t } static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); pa_tagstruct *reply; - struct playback_stream *s; + playback_stream *s; struct timeval tv, now; uint32_t idx; pa_usec_t latency; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_get_timeval(t, &tv) < 0 || @@ -1143,31 +1531,34 @@ static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); s = pa_idxset_get_by_index(c->output_streams, idx); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_UPDATE_LATENCY, s, 0, NULL) == 0, tag, PA_ERR_NOENTITY) reply = reply_new(tag); latency = pa_sink_get_latency(s->sink_input->sink); - if (s->sink_input->resampled_chunk.memblock) - latency += pa_bytes_to_usec(s->sink_input->resampled_chunk.length, &s->sink_input->sample_spec); + latency += pa_bytes_to_usec(s->resampled_chunk_length, &s->sink_input->sample_spec); + pa_tagstruct_put_usec(reply, latency); pa_tagstruct_put_usec(reply, 0); - pa_tagstruct_put_boolean(reply, s->sink_input->state == PA_SINK_INPUT_RUNNING); + pa_tagstruct_put_boolean(reply, pa_sink_input_get_state(s->sink_input) == PA_SINK_INPUT_RUNNING); pa_tagstruct_put_timeval(reply, &tv); pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now)); - pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq)); - pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq)); + pa_tagstruct_puts64(reply, s->write_index); + pa_tagstruct_puts64(reply, s->read_index); pa_pstream_send_tagstruct(c->pstream, reply); } static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); pa_tagstruct *reply; - struct record_stream *s; + record_stream *s; struct timeval tv, now; uint32_t idx; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_get_timeval(t, &tv) < 0 || @@ -1192,14 +1583,16 @@ static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN } static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - struct upload_stream *s; + connection *c = CONNECTION(userdata); + upload_stream *s; uint32_t length; const char *name; pa_sample_spec ss; pa_channel_map map; pa_tagstruct *reply; - assert(c && t && c->protocol && c->protocol->core); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_get_sample_spec(t, &ss) < 0 || @@ -1228,11 +1621,13 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ } static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); uint32_t channel; - struct upload_stream *s; + upload_stream *s; uint32_t idx; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_getu32(t, &channel) < 0 || !pa_tagstruct_eof(t)) { @@ -1244,23 +1639,25 @@ static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ s = pa_idxset_get_by_index(c->output_streams, channel); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - CHECK_VALIDITY(c->pstream, s->type == UPLOAD_STREAM, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY); if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, &idx) < 0) pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL); else pa_pstream_send_simple_ack(c->pstream, tag); - upload_stream_free(s); + upload_stream_unlink(s); } static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); uint32_t sink_index; pa_volume_t volume; pa_sink *sink; const char *name, *sink_name; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_getu32(t, &sink_index) < 0 || pa_tagstruct_gets(t, &sink_name) < 0 || @@ -1291,9 +1688,11 @@ static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui } static void command_remove_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); const char *name; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_gets(t, &name) < 0 || !pa_tagstruct_eof(t)) { @@ -1313,7 +1712,9 @@ static void command_remove_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED } static void sink_fill_tagstruct(pa_tagstruct *t, pa_sink *sink) { - assert(t && sink); + pa_assert(t); + pa_sink_assert_ref(sink); + pa_tagstruct_put( t, PA_TAG_U32, sink->index, @@ -1321,22 +1722,21 @@ static void sink_fill_tagstruct(pa_tagstruct *t, pa_sink *sink) { PA_TAG_STRING, sink->description, PA_TAG_SAMPLE_SPEC, &sink->sample_spec, PA_TAG_CHANNEL_MAP, &sink->channel_map, - PA_TAG_U32, sink->owner ? sink->owner->index : PA_INVALID_INDEX, - PA_TAG_CVOLUME, pa_sink_get_volume(sink, PA_MIXER_HARDWARE), - PA_TAG_BOOLEAN, pa_sink_get_mute(sink, PA_MIXER_HARDWARE), + PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX, + PA_TAG_CVOLUME, pa_sink_get_volume(sink), + PA_TAG_BOOLEAN, pa_sink_get_mute(sink), PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX, PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL, PA_TAG_USEC, pa_sink_get_latency(sink), PA_TAG_STRING, sink->driver, - PA_TAG_U32, - (sink->get_hw_volume ? PA_SINK_HW_VOLUME_CTRL : 0) | - (sink->get_latency ? PA_SINK_LATENCY : 0) | - (sink->is_hardware ? PA_SINK_HARDWARE : 0), + PA_TAG_U32, sink->flags, PA_TAG_INVALID); } static void source_fill_tagstruct(pa_tagstruct *t, pa_source *source) { - assert(t && source); + pa_assert(t); + pa_source_assert_ref(source); + pa_tagstruct_put( t, PA_TAG_U32, source->index, @@ -1344,22 +1744,21 @@ static void source_fill_tagstruct(pa_tagstruct *t, pa_source *source) { PA_TAG_STRING, source->description, PA_TAG_SAMPLE_SPEC, &source->sample_spec, PA_TAG_CHANNEL_MAP, &source->channel_map, - PA_TAG_U32, source->owner ? source->owner->index : PA_INVALID_INDEX, - PA_TAG_CVOLUME, pa_source_get_volume(source, PA_MIXER_HARDWARE), - PA_TAG_BOOLEAN, pa_source_get_mute(source, PA_MIXER_HARDWARE), + PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX, + PA_TAG_CVOLUME, pa_source_get_volume(source), + PA_TAG_BOOLEAN, pa_source_get_mute(source), PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX, PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL, PA_TAG_USEC, pa_source_get_latency(source), PA_TAG_STRING, source->driver, - PA_TAG_U32, - (source->get_hw_volume ? PA_SOURCE_HW_VOLUME_CTRL : 0) | - (source->get_latency ? PA_SOURCE_LATENCY : 0) | - (source->is_hardware ? PA_SOURCE_HARDWARE : 0), + PA_TAG_U32, source->flags, PA_TAG_INVALID); } static void client_fill_tagstruct(pa_tagstruct *t, pa_client *client) { - assert(t && client); + pa_assert(t); + pa_assert(client); + pa_tagstruct_putu32(t, client->index); pa_tagstruct_puts(t, client->name); pa_tagstruct_putu32(t, client->owner ? client->owner->index : PA_INVALID_INDEX); @@ -1367,7 +1766,9 @@ static void client_fill_tagstruct(pa_tagstruct *t, pa_client *client) { } static void module_fill_tagstruct(pa_tagstruct *t, pa_module *module) { - assert(t && module); + pa_assert(t); + pa_assert(module); + pa_tagstruct_putu32(t, module->index); pa_tagstruct_puts(t, module->name); pa_tagstruct_puts(t, module->argument); @@ -1375,8 +1776,10 @@ static void module_fill_tagstruct(pa_tagstruct *t, pa_module *module) { pa_tagstruct_put_boolean(t, module->auto_unload); } -static void sink_input_fill_tagstruct(pa_tagstruct *t, pa_sink_input *s) { - assert(t && s); +static void sink_input_fill_tagstruct(connection *c, pa_tagstruct *t, pa_sink_input *s) { + pa_assert(t); + pa_sink_input_assert_ref(s); + pa_tagstruct_putu32(t, s->index); pa_tagstruct_puts(t, s->name); pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX); @@ -1389,10 +1792,14 @@ static void sink_input_fill_tagstruct(pa_tagstruct *t, pa_sink_input *s) { pa_tagstruct_put_usec(t, pa_sink_get_latency(s->sink)); pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s))); pa_tagstruct_puts(t, s->driver); + if (c->version >= 11) + pa_tagstruct_put_boolean(t, pa_sink_input_get_mute(s)); } static void source_output_fill_tagstruct(pa_tagstruct *t, pa_source_output *s) { - assert(t && s); + pa_assert(t); + pa_source_output_assert_ref(s); + pa_tagstruct_putu32(t, s->index); pa_tagstruct_puts(t, s->name); pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX); @@ -1407,7 +1814,9 @@ static void source_output_fill_tagstruct(pa_tagstruct *t, pa_source_output *s) { } static void scache_fill_tagstruct(pa_tagstruct *t, pa_scache_entry *e) { - assert(t && e); + pa_assert(t); + pa_assert(e); + pa_tagstruct_putu32(t, e->index); pa_tagstruct_puts(t, e->name); pa_tagstruct_put_cvolume(t, &e->volume); @@ -1420,7 +1829,7 @@ static void scache_fill_tagstruct(pa_tagstruct *t, pa_scache_entry *e) { } static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); uint32_t idx; pa_sink *sink = NULL; pa_source *source = NULL; @@ -1431,7 +1840,9 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u pa_scache_entry *sce = NULL; const char *name; pa_tagstruct *reply; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_getu32(t, &idx) < 0 || (command != PA_COMMAND_GET_CLIENT_INFO && @@ -1466,7 +1877,7 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO) so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); else { - assert(command == PA_COMMAND_GET_SAMPLE_INFO); + pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO); if (idx != PA_INVALID_INDEX) sce = pa_idxset_get_by_index(c->protocol->core->scache, idx); else @@ -1488,7 +1899,7 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u else if (module) module_fill_tagstruct(reply, module); else if (si) - sink_input_fill_tagstruct(reply, si); + sink_input_fill_tagstruct(c, reply, si); else if (so) source_output_fill_tagstruct(reply, so); else @@ -1497,12 +1908,14 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u } static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); pa_idxset *i; uint32_t idx; void *p; pa_tagstruct *reply; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (!pa_tagstruct_eof(t)) { protocol_error(c); @@ -1526,7 +1939,7 @@ static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST) i = c->protocol->core->source_outputs; else { - assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); + pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); i = c->protocol->core->scache; } @@ -1541,11 +1954,11 @@ static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma else if (command == PA_COMMAND_GET_MODULE_INFO_LIST) module_fill_tagstruct(reply, p); else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) - sink_input_fill_tagstruct(reply, p); + sink_input_fill_tagstruct(c, reply, p); else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST) source_output_fill_tagstruct(reply, p); else { - assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); + pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); scache_fill_tagstruct(reply, p); } } @@ -1555,11 +1968,13 @@ static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma } static void command_get_server_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); pa_tagstruct *reply; char txt[256]; const char *n; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (!pa_tagstruct_eof(t)) { protocol_error(c); @@ -1587,8 +2002,9 @@ static void command_get_server_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) { pa_tagstruct *t; - struct connection *c = userdata; - assert(c && core); + connection *c = CONNECTION(userdata); + + connection_assert_ref(c); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT); @@ -1599,9 +2015,11 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint3 } static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); pa_subscription_mask_t m; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_getu32(t, &m) < 0 || !pa_tagstruct_eof(t)) { @@ -1617,7 +2035,7 @@ static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint if (m != 0) { c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c); - assert(c->subscription); + pa_assert(c->subscription); } else c->subscription = NULL; @@ -1631,14 +2049,16 @@ static void command_set_volume( pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); uint32_t idx; pa_cvolume volume; pa_sink *sink = NULL; pa_source *source = NULL; pa_sink_input *si = NULL; const char *name = NULL; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_getu32(t, &idx) < 0 || (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) || @@ -1653,27 +2073,36 @@ static void command_set_volume( CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID); - if (command == PA_COMMAND_SET_SINK_VOLUME) { - if (idx != PA_INVALID_INDEX) - sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); - else - sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); - } else if (command == PA_COMMAND_SET_SOURCE_VOLUME) { - if (idx != (uint32_t) -1) - source = pa_idxset_get_by_index(c->protocol->core->sources, idx); - else - source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); - } else { - assert(command == PA_COMMAND_SET_SINK_INPUT_VOLUME); - si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); + switch (command) { + + case PA_COMMAND_SET_SINK_VOLUME: + if (idx != PA_INVALID_INDEX) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); + else + sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); + break; + + case PA_COMMAND_SET_SOURCE_VOLUME: + if (idx != PA_INVALID_INDEX) + source = pa_idxset_get_by_index(c->protocol->core->sources, idx); + else + source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); + break; + + case PA_COMMAND_SET_SINK_INPUT_VOLUME: + si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); + break; + + default: + pa_assert_not_reached(); } CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY); if (sink) - pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &volume); + pa_sink_set_volume(sink, &volume); else if (source) - pa_source_set_volume(source, PA_MIXER_HARDWARE, &volume); + pa_source_set_volume(source, &volume); else if (si) pa_sink_input_set_volume(si, &volume); @@ -1687,16 +2116,20 @@ static void command_set_mute( pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); uint32_t idx; int mute; pa_sink *sink = NULL; pa_source *source = NULL; + pa_sink_input *si = NULL; const char *name = NULL; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_getu32(t, &idx) < 0 || - pa_tagstruct_gets(t, &name) < 0 || + (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) || + (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) || pa_tagstruct_get_boolean(t, &mute) || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1706,35 +2139,53 @@ static void command_set_mute( CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); - if (command == PA_COMMAND_SET_SINK_MUTE) { - if (idx != PA_INVALID_INDEX) - sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); - else - sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); - } else { - assert(command == PA_COMMAND_SET_SOURCE_MUTE); - if (idx != (uint32_t) -1) - source = pa_idxset_get_by_index(c->protocol->core->sources, idx); - else - source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); + switch (command) { + + case PA_COMMAND_SET_SINK_MUTE: + + if (idx != PA_INVALID_INDEX) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); + else + sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); + + break; + + case PA_COMMAND_SET_SOURCE_MUTE: + if (idx != PA_INVALID_INDEX) + source = pa_idxset_get_by_index(c->protocol->core->sources, idx); + else + source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); + + break; + + case PA_COMMAND_SET_SINK_INPUT_MUTE: + si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); + break; + + default: + pa_assert_not_reached(); } - CHECK_VALIDITY(c->pstream, sink || source, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY); if (sink) - pa_sink_set_mute(sink, PA_MIXER_HARDWARE, mute); + pa_sink_set_mute(sink, mute); else if (source) - pa_source_set_mute(source, PA_MIXER_HARDWARE, mute); + pa_source_set_mute(source, mute); + else if (si) + pa_sink_input_set_mute(si, mute); pa_pstream_send_simple_ack(c->pstream, tag); } static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); uint32_t idx; int b; - struct playback_stream *s, *ssync; - assert(c && t); + playback_stream *s; + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_get_boolean(t, &b) < 0 || @@ -1747,73 +2198,19 @@ static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); s = pa_idxset_get_by_index(c->output_streams, idx); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY); pa_sink_input_cork(s->sink_input, b); - pa_memblockq_prebuf_force(s->memblockq); - - /* Do the same for all other members in the sync group */ - for (ssync = s->prev; ssync; ssync = ssync->prev) { - pa_sink_input_cork(ssync->sink_input, b); - pa_memblockq_prebuf_force(ssync->memblockq); - } - - for (ssync = s->next; ssync; ssync = ssync->next) { - pa_sink_input_cork(ssync->sink_input, b); - pa_memblockq_prebuf_force(ssync->memblockq); - } - pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_flush_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; +static void command_trigger_or_flush_or_prebuf_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + connection *c = CONNECTION(userdata); uint32_t idx; - struct playback_stream *s, *ssync; - assert(c && t); - - if (pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); - s = pa_idxset_get_by_index(c->output_streams, idx); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); - - pa_memblockq_flush(s->memblockq); - s->underrun = 0; + playback_stream *s; - /* Do the same for all other members in the sync group */ - for (ssync = s->prev; ssync; ssync = ssync->prev) { - pa_memblockq_flush(ssync->memblockq); - ssync->underrun = 0; - } - - for (ssync = s->next; ssync; ssync = ssync->next) { - pa_memblockq_flush(ssync->memblockq); - ssync->underrun = 0; - } - - pa_pstream_send_simple_ack(c->pstream, tag); - pa_sink_notify(s->sink_input->sink); - request_bytes(s); - - for (ssync = s->prev; ssync; ssync = ssync->prev) - request_bytes(ssync); - - for (ssync = s->next; ssync; ssync = ssync->next) - request_bytes(ssync); -} - -static void command_trigger_or_prebuf_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; - uint32_t idx; - struct playback_stream *s; - assert(c && t); + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_getu32(t, &idx) < 0 || !pa_tagstruct_eof(t)) { @@ -1825,32 +2222,36 @@ static void command_trigger_or_prebuf_playback_stream(PA_GCC_UNUSED pa_pdispatch CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); s = pa_idxset_get_by_index(c->output_streams, idx); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY); switch (command) { + case PA_COMMAND_FLUSH_PLAYBACK_STREAM: + pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL); + break; + case PA_COMMAND_PREBUF_PLAYBACK_STREAM: - pa_memblockq_prebuf_force(s->memblockq); + pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL); break; case PA_COMMAND_TRIGGER_PLAYBACK_STREAM: - pa_memblockq_prebuf_disable(s->memblockq); + pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL); break; default: - abort(); + pa_assert_not_reached(); } - pa_sink_notify(s->sink_input->sink); pa_pstream_send_simple_ack(c->pstream, tag); - request_bytes(s); } static void command_cork_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); uint32_t idx; - struct record_stream *s; + record_stream *s; int b; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_get_boolean(t, &b) < 0 || @@ -1869,10 +2270,12 @@ static void command_cork_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN } static void command_flush_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); uint32_t idx; - struct record_stream *s; - assert(c && t); + record_stream *s; + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_getu32(t, &idx) < 0 || !pa_tagstruct_eof(t)) { @@ -1889,9 +2292,11 @@ static void command_flush_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_U } static void command_set_default_sink_or_source(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); const char *s; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_gets(t, &s) < 0 || !pa_tagstruct_eof(t)) { @@ -1907,10 +2312,12 @@ static void command_set_default_sink_or_source(PA_GCC_UNUSED pa_pdispatch *pd, u } static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); uint32_t idx; const char *name; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_gets(t, &name) < 0 || @@ -1923,16 +2330,16 @@ static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t com CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID); if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) { - struct playback_stream *s; + playback_stream *s; s = pa_idxset_get_by_index(c->output_streams, idx); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); - CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY); pa_sink_input_set_name(s->sink_input, name); } else { - struct record_stream *s; + record_stream *s; s = pa_idxset_get_by_index(c->record_streams, idx); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); @@ -1944,9 +2351,11 @@ static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t com } static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); uint32_t idx; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_getu32(t, &idx) < 0 || !pa_tagstruct_eof(t)) { @@ -1961,6 +2370,8 @@ static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint3 client = pa_idxset_get_by_index(c->protocol->core->clients, idx); CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY); + + connection_ref(c); pa_client_kill(client); } else if (command == PA_COMMAND_KILL_SINK_INPUT) { @@ -1969,27 +2380,32 @@ static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint3 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + connection_ref(c); pa_sink_input_kill(s); } else { pa_source_output *s; - assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT); + pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT); s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + connection_ref(c); pa_source_output_kill(s); } pa_pstream_send_simple_ack(c->pstream, tag); + connection_unref(c); } static void command_load_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); pa_module *m; const char *name, *argument; pa_tagstruct *reply; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_gets(t, &argument) < 0 || @@ -2013,10 +2429,12 @@ static void command_load_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui } static void command_unload_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); uint32_t idx; pa_module *m; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_getu32(t, &idx) < 0 || !pa_tagstruct_eof(t)) { @@ -2033,12 +2451,14 @@ static void command_unload_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED } static void command_add_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); const char *name, *module, *argument; uint32_t type; uint32_t idx; pa_tagstruct *reply; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_getu32(t, &type) < 0 || @@ -2066,11 +2486,13 @@ static void command_add_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED u } static void command_remove_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); const char *name = NULL; uint32_t type, idx = PA_IDXSET_INVALID; int r; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if ((pa_tagstruct_getu32(t, &idx) < 0 && (pa_tagstruct_gets(t, &name) < 0 || @@ -2095,7 +2517,7 @@ static void command_remove_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE } static void autoload_fill_tagstruct(pa_tagstruct *t, const pa_autoload_entry *e) { - assert(t && e); + pa_assert(t && e); pa_tagstruct_putu32(t, e->index); pa_tagstruct_puts(t, e->name); @@ -2105,12 +2527,14 @@ static void autoload_fill_tagstruct(pa_tagstruct *t, const pa_autoload_entry *e) } static void command_get_autoload_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); const pa_autoload_entry *a = NULL; uint32_t type, idx; const char *name; pa_tagstruct *reply; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if ((pa_tagstruct_getu32(t, &idx) < 0 && (pa_tagstruct_gets(t, &name) < 0 || @@ -2137,9 +2561,11 @@ static void command_get_autoload_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNU } static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); pa_tagstruct *reply; - assert(c && t); + + connection_assert_ref(c); + pa_assert(t); if (!pa_tagstruct_eof(t)) { protocol_error(c); @@ -2162,12 +2588,12 @@ static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC } static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - struct connection *c = userdata; + connection *c = CONNECTION(userdata); uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX; const char *name = NULL; - assert(c); - assert(t); + connection_assert_ref(c); + pa_assert(t); if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_getu32(t, &idx_device) < 0 || @@ -2202,6 +2628,8 @@ static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag pa_source_output *so = NULL; pa_source *source; + pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT); + so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); if (idx_device != PA_INVALID_INDEX) @@ -2218,67 +2646,122 @@ static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag } pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + connection *c = CONNECTION(userdata); + uint32_t idx = PA_INVALID_INDEX; + const char *name = NULL; + int b; + + connection_assert_ref(c); + pa_assert(t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_get_boolean(t, &b) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || !*name || pa_utf8_valid(name), tag, PA_ERR_INVALID); + if (command == PA_COMMAND_SUSPEND_SINK) { + + if (idx == PA_INVALID_INDEX && name && !*name) { + + if (pa_sink_suspend_all(c->protocol->core, b) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); + return; + } + } else { + pa_sink *sink = NULL; + + if (idx != PA_INVALID_INDEX) + sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); + else + sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); + + CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); + + if (pa_sink_suspend(sink, b) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); + return; + } + } + } else { + + pa_assert(command == PA_COMMAND_SUSPEND_SOURCE); + + if (idx == PA_INVALID_INDEX && name && !*name) { + + if (pa_source_suspend_all(c->protocol->core, b) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); + return; + } + + } else { + pa_source *source; + + if (idx != PA_INVALID_INDEX) + source = pa_idxset_get_by_index(c->protocol->core->sources, idx); + else + source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); + + CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY); + + if (pa_source_suspend(source, b) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); + return; + } + } + } + + pa_pstream_send_simple_ack(c->pstream, tag); } /*** pstream callbacks ***/ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) { - struct connection *c = userdata; - assert(p && packet && packet->data && c); + connection *c = CONNECTION(userdata); + + pa_assert(p); + pa_assert(packet); + connection_assert_ref(c); if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) { pa_log("invalid packet."); - connection_free(c); + connection_unlink(c); } } static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { - struct connection *c = userdata; - struct output_stream *stream; - assert(p && chunk && userdata); + connection *c = CONNECTION(userdata); + output_stream *stream; + + pa_assert(p); + pa_assert(chunk); + connection_assert_ref(c); - if (!(stream = pa_idxset_get_by_index(c->output_streams, channel))) { + if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) { pa_log("client sent block for invalid stream."); /* Ignoring */ return; } - if (stream->type == PLAYBACK_STREAM) { - struct playback_stream *ps = (struct playback_stream*) stream; - if (chunk->length >= ps->requested_bytes) - ps->requested_bytes = 0; - else - ps->requested_bytes -= chunk->length; - - pa_memblockq_seek(ps->memblockq, offset, seek); - - if (pa_memblockq_push_align(ps->memblockq, chunk) < 0) { - pa_tagstruct *t; - - pa_log_warn("failed to push data into queue"); - - /* Pushing this block into the queue failed, so we simulate - * it by skipping ahead */ - - pa_memblockq_seek(ps->memblockq, chunk->length, PA_SEEK_RELATIVE); + if (playback_stream_isinstance(stream)) { + playback_stream *ps = PLAYBACK_STREAM(stream); - /* Notify the user */ - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW); - pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ - pa_tagstruct_putu32(t, ps->index); - pa_pstream_send_tagstruct(p, t); - } + if (seek != PA_SEEK_RELATIVE || offset != 0) + pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset, NULL, NULL); - ps->underrun = 0; - - pa_sink_notify(ps->sink_input->sink); + pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL); } else { - struct upload_stream *u = (struct upload_stream*) stream; + upload_stream *u = UPLOAD_STREAM(stream); size_t l; - assert(u->type == UPLOAD_STREAM); if (!u->memchunk.memblock) { if (u->length == chunk->length) { @@ -2291,15 +2774,24 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o } } - assert(u->memchunk.memblock); + pa_assert(u->memchunk.memblock); l = u->length; if (l > chunk->length) l = chunk->length; + if (l > 0) { - memcpy((uint8_t*) u->memchunk.memblock->data + u->memchunk.index + u->memchunk.length, - (uint8_t*) chunk->memblock->data+chunk->index, l); + void *src, *dst; + dst = pa_memblock_acquire(u->memchunk.memblock); + src = pa_memblock_acquire(chunk->memblock); + + memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length, + (uint8_t*) src+chunk->index, l); + + pa_memblock_release(u->memchunk.memblock); + pa_memblock_release(chunk->memblock); + u->memchunk.length += l; u->length -= l; } @@ -2307,43 +2799,72 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o } static void pstream_die_callback(pa_pstream *p, void *userdata) { - struct connection *c = userdata; - assert(p && c); - connection_free(c); + connection *c = CONNECTION(userdata); -/* pa_log("connection died.");*/ -} + pa_assert(p); + connection_assert_ref(c); + connection_unlink(c); + pa_log_info("connection died."); +} static void pstream_drain_callback(pa_pstream *p, void *userdata) { - struct connection *c = userdata; - assert(p && c); + connection *c = CONNECTION(userdata); + + pa_assert(p); + connection_assert_ref(c); send_memblock(c); } +static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) { + pa_thread_mq *q; + + if (!(q = pa_thread_mq_get())) + pa_pstream_send_revoke(p, block_id); + else + pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL); +} + +static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) { + pa_thread_mq *q; + + if (!(q = pa_thread_mq_get())) + pa_pstream_send_release(p, block_id); + else + pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL); +} + /*** client callbacks ***/ static void client_kill_cb(pa_client *c) { - assert(c && c->userdata); - connection_free(c->userdata); + pa_assert(c); + + connection_unlink(CONNECTION(c->userdata)); } /*** socket server callbacks ***/ static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { - struct connection *c = userdata; - assert(m && tv && c && c->auth_timeout_event == e); + connection *c = CONNECTION(userdata); + + pa_assert(m); + pa_assert(tv); + connection_assert_ref(c); + pa_assert(c->auth_timeout_event == e); if (!c->authorized) - connection_free(c); + connection_unlink(c); } static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, void *userdata) { pa_protocol_native *p = userdata; - struct connection *c; + connection *c; char cname[256], pname[128]; - assert(io && p); + + pa_assert(s); + pa_assert(io); + pa_assert(p); if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); @@ -2351,7 +2872,9 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo return; } - c = pa_xmalloc(sizeof(struct connection)); + c = pa_msgobject_new(connection); + c->parent.parent.free = connection_free; + c->parent.process_msg = connection_process_msg; c->authorized = !!p->public; @@ -2371,35 +2894,31 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo c->version = 8; c->protocol = p; pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname)); - snprintf(cname, sizeof(cname), "Native client (%s)", pname); - assert(p->core); + pa_snprintf(cname, sizeof(cname), "Native client (%s)", pname); c->client = pa_client_new(p->core, __FILE__, cname); - assert(c->client); c->client->kill = client_kill_cb; c->client->userdata = c; c->client->owner = p->module; c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool); - assert(c->pstream); pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); + pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c); + pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c); c->pdispatch = pa_pdispatch_new(p->core->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); c->record_streams = pa_idxset_new(NULL, NULL); c->output_streams = pa_idxset_new(NULL, NULL); - assert(c->record_streams && c->output_streams); c->rrobin_index = PA_IDXSET_INVALID; c->subscription = NULL; pa_idxset_put(p->connections, c, NULL); - #ifdef HAVE_CREDS if (pa_iochannel_creds_supported(io)) pa_iochannel_creds_enable(io); @@ -2410,7 +2929,7 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo /*** module entry points ***/ static int load_key(pa_protocol_native*p, const char*fn) { - assert(p); + pa_assert(p); p->auth_cookie_in_property = 0; @@ -2440,8 +2959,8 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo int public = 0; const char *acl; - assert(c); - assert(ma); + pa_assert(c); + pa_assert(ma); if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) { pa_log("auth-anonymous= expects a boolean argument."); @@ -2482,7 +3001,6 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo goto fail; p->connections = pa_idxset_new(NULL, NULL); - assert(p->connections); return p; @@ -2517,11 +3035,11 @@ pa_protocol_native* pa_protocol_native_new(pa_core *core, pa_socket_server *serv } void pa_protocol_native_free(pa_protocol_native *p) { - struct connection *c; - assert(p); + connection *c; + pa_assert(p); while ((c = pa_idxset_first(p->connections, NULL))) - connection_free(c); + connection_unlink(c); pa_idxset_free(p->connections, NULL, NULL); if (p->server) { @@ -2553,7 +3071,12 @@ void pa_protocol_native_free(pa_protocol_native *p) { pa_xfree(p); } -pa_protocol_native* pa_protocol_native_new_iochannel(pa_core*core, pa_iochannel *io, pa_module *m, pa_modargs *ma) { +pa_protocol_native* pa_protocol_native_new_iochannel( + pa_core*core, + pa_iochannel *io, + pa_module *m, + pa_modargs *ma) { + pa_protocol_native *p; if (!(p = protocol_new_internal(core, m, ma))) diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c index 31ad6ddd..64e2a81c 100644 --- a/src/pulsecore/protocol-simple.c +++ b/src/pulsecore/protocol-simple.c @@ -25,7 +25,6 @@ #include #endif -#include #include #include #include @@ -41,101 +40,154 @@ #include #include #include +#include +#include #include "protocol-simple.h" /* Don't allow more than this many concurrent connections */ #define MAX_CONNECTIONS 10 -struct connection { +typedef struct connection { + pa_msgobject parent; pa_protocol_simple *protocol; pa_iochannel *io; pa_sink_input *sink_input; pa_source_output *source_output; pa_client *client; pa_memblockq *input_memblockq, *output_memblockq; - pa_defer_event *defer_event; int dead; struct { pa_memblock *current_memblock; size_t memblock_index, fragment_size; + pa_atomic_t missing; } playback; -}; +} connection; + +PA_DECLARE_CLASS(connection); +#define CONNECTION(o) (connection_cast(o)) +static PA_DEFINE_CHECK_TYPE(connection, pa_msgobject); struct pa_protocol_simple { pa_module *module; pa_core *core; pa_socket_server*server; pa_idxset *connections; + enum { RECORD = 1, PLAYBACK = 2, DUPLEX = 3 } mode; + pa_sample_spec sample_spec; char *source_name, *sink_name; }; +enum { + SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */ + SINK_INPUT_MESSAGE_DISABLE_PREBUF /* disabled prebuf, get playback started. */ +}; + +enum { + CONNECTION_MESSAGE_REQUEST_DATA, /* data requested from sink input from the main loop */ + CONNECTION_MESSAGE_POST_DATA, /* data from source output to main loop */ + CONNECTION_MESSAGE_UNLINK_CONNECTION /* Please drop a aconnection now */ +}; + + #define PLAYBACK_BUFFER_SECONDS (.5) #define PLAYBACK_BUFFER_FRAGMENTS (10) #define RECORD_BUFFER_SECONDS (5) #define RECORD_BUFFER_FRAGMENTS (100) -static void connection_free(struct connection *c) { - assert(c); +static void connection_unlink(connection *c) { + pa_assert(c); - pa_idxset_remove_by_data(c->protocol->connections, c, NULL); + if (!c->protocol) + return; - if (c->playback.current_memblock) - pa_memblock_unref(c->playback.current_memblock); if (c->sink_input) { - pa_sink_input_disconnect(c->sink_input); + pa_sink_input_unlink(c->sink_input); pa_sink_input_unref(c->sink_input); + c->sink_input = NULL; } + if (c->source_output) { - pa_source_output_disconnect(c->source_output); + pa_source_output_unlink(c->source_output); pa_source_output_unref(c->source_output); + c->source_output = NULL; } - if (c->client) + + if (c->client) { pa_client_free(c->client); - if (c->io) + c->client = NULL; + } + + if (c->io) { pa_iochannel_free(c->io); + c->io = NULL; + } + + pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c); + c->protocol = NULL; + connection_unref(c); +} + +static void connection_free(pa_object *o) { + connection *c = CONNECTION(o); + pa_assert(c); + + connection_unref(c); + + if (c->playback.current_memblock) + pa_memblock_unref(c->playback.current_memblock); + if (c->input_memblockq) pa_memblockq_free(c->input_memblockq); if (c->output_memblockq) pa_memblockq_free(c->output_memblockq); - if (c->defer_event) - c->protocol->core->mainloop->defer_free(c->defer_event); + pa_xfree(c); } -static int do_read(struct connection *c) { +static int do_read(connection *c) { pa_memchunk chunk; ssize_t r; size_t l; + void *p; + + connection_assert_ref(c); - if (!c->sink_input || !(l = pa_memblockq_missing(c->input_memblockq))) + if (!c->sink_input || (l = pa_atomic_load(&c->playback.missing)) <= 0) return 0; if (l > c->playback.fragment_size) l = c->playback.fragment_size; if (c->playback.current_memblock) - if (c->playback.current_memblock->length - c->playback.memblock_index < l) { + if (pa_memblock_get_length(c->playback.current_memblock) - c->playback.memblock_index < l) { pa_memblock_unref(c->playback.current_memblock); c->playback.current_memblock = NULL; c->playback.memblock_index = 0; } if (!c->playback.current_memblock) { - c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, c->playback.fragment_size*2); - assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); + pa_assert_se(c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, l)); c->playback.memblock_index = 0; } - if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { + p = pa_memblock_acquire(c->playback.current_memblock); + r = pa_iochannel_read(c->io, (uint8_t*) p + c->playback.memblock_index, l); + pa_memblock_release(c->playback.current_memblock); + + if (r <= 0) { + + if (r < 0 && (errno == EINTR || errno == EAGAIN)) + return 0; + pa_log_debug("read(): %s", r == 0 ? "EOF" : pa_cstrerror(errno)); return -1; } @@ -143,50 +195,55 @@ static int do_read(struct connection *c) { chunk.memblock = c->playback.current_memblock; chunk.index = c->playback.memblock_index; chunk.length = r; - assert(chunk.memblock); c->playback.memblock_index += r; - assert(c->input_memblockq); - pa_memblockq_push_align(c->input_memblockq, &chunk); - assert(c->sink_input); - pa_sink_notify(c->sink_input->sink); + pa_asyncmsgq_post(c->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, &chunk, NULL); + pa_atomic_sub(&c->playback.missing, r); return 0; } -static int do_write(struct connection *c) { +static int do_write(connection *c) { pa_memchunk chunk; ssize_t r; + void *p; + + connection_assert_ref(c); if (!c->source_output) return 0; - assert(c->output_memblockq); - if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) + if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) { +/* pa_log("peek failed"); */ return 0; + } + + pa_assert(chunk.memblock); + pa_assert(chunk.length); - assert(chunk.memblock && chunk.length); + p = pa_memblock_acquire(chunk.memblock); + r = pa_iochannel_write(c->io, (uint8_t*) p+chunk.index, chunk.length); + pa_memblock_release(chunk.memblock); + + pa_memblock_unref(chunk.memblock); + + if (r < 0) { + + if (errno == EINTR || errno == EAGAIN) + return 0; - if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { - pa_memblock_unref(chunk.memblock); pa_log("write(): %s", pa_cstrerror(errno)); return -1; } - pa_memblockq_drop(c->output_memblockq, &chunk, r); - pa_memblock_unref(chunk.memblock); - - pa_source_notify(c->source_output->source); + pa_memblockq_drop(c->output_memblockq, r); return 0; } -static void do_work(struct connection *c) { - assert(c); - - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - c->protocol->core->mainloop->defer_enable(c->defer_event, 0); +static void do_work(connection *c) { + connection_assert_ref(c); if (c->dead) return; @@ -207,103 +264,182 @@ static void do_work(struct connection *c) { fail: if (c->sink_input) { + + /* If there is a sink input, we first drain what we already have read before shutting down the connection */ c->dead = 1; pa_iochannel_free(c->io); c->io = NULL; - pa_memblockq_prebuf_disable(c->input_memblockq); - pa_sink_notify(c->sink_input->sink); + pa_asyncmsgq_post(c->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_DISABLE_PREBUF, NULL, 0, NULL, NULL); } else - connection_free(c); + connection_unlink(c); } -/*** sink_input callbacks ***/ +static int connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) { + connection *c = CONNECTION(o); + connection_assert_ref(c); -static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { - struct connection*c; - assert(i && i->userdata && chunk); - c = i->userdata; + switch (code) { + case CONNECTION_MESSAGE_REQUEST_DATA: + do_work(c); + break; - if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) { + case CONNECTION_MESSAGE_POST_DATA: +/* pa_log("got data %u", chunk->length); */ + pa_memblockq_push_align(c->output_memblockq, chunk); + do_work(c); + break; - if (c->dead) - connection_free(c); - - return -1; + case CONNECTION_MESSAGE_UNLINK_CONNECTION: + connection_unlink(c); + break; } return 0; } -static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { - struct connection*c = i->userdata; - assert(i && c && length); +/*** sink_input callbacks ***/ + +/* Called from thread context */ +static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) { + pa_sink_input *i = PA_SINK_INPUT(o); + connection*c; + + pa_sink_input_assert_ref(i); + c = CONNECTION(i->userdata); + connection_assert_ref(c); + + switch (code) { + + case SINK_INPUT_MESSAGE_POST_DATA: { + pa_assert(chunk); + + /* New data from the main loop */ + pa_memblockq_push_align(c->input_memblockq, chunk); + +/* pa_log("got data, %u", pa_memblockq_get_length(c->input_memblockq)); */ + + return 0; + } + + case SINK_INPUT_MESSAGE_DISABLE_PREBUF: { + pa_memblockq_prebuf_disable(c->input_memblockq); + return 0; + } + + case PA_SINK_INPUT_MESSAGE_GET_LATENCY: { + pa_usec_t *r = userdata; - pa_memblockq_drop(c->input_memblockq, chunk, length); + *r = pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); - /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + /* Fall through, the default handler will add in the extra + * latency added by the resampler */ + } + + default: + return pa_sink_input_process_msg(o, code, userdata, offset, chunk); + } } -static void sink_input_kill_cb(pa_sink_input *i) { - assert(i && i->userdata); - connection_free((struct connection *) i->userdata); +/* Called from thread context */ +static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) { + connection *c; + int r; + + pa_assert(i); + c = CONNECTION(i->userdata); + connection_assert_ref(c); + pa_assert(chunk); + + r = pa_memblockq_peek(c->input_memblockq, chunk); + +/* pa_log("peeked %u %i", r >= 0 ? chunk->length: 0, r); */ + + if (c->dead && r < 0) + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_UNLINK_CONNECTION, NULL, 0, NULL, NULL); + + return r; } +/* Called from thread context */ +static void sink_input_drop_cb(pa_sink_input *i, size_t length) { + connection *c; + size_t old, new; + + pa_assert(i); + c = CONNECTION(i->userdata); + connection_assert_ref(c); + pa_assert(length); + + old = pa_memblockq_missing(c->input_memblockq); + pa_memblockq_drop(c->input_memblockq, length); + new = pa_memblockq_missing(c->input_memblockq); -static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { - struct connection*c = i->userdata; - assert(i && c); - return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); + if (new > old) { + if (pa_atomic_add(&c->playback.missing, new - old) <= 0) + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL); + } +} + +/* Called from main context */ +static void sink_input_kill_cb(pa_sink_input *i) { + pa_sink_input_assert_ref(i); + + connection_unlink(CONNECTION(i->userdata)); } /*** source_output callbacks ***/ +/* Called from thread context */ static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { - struct connection *c = o->userdata; - assert(o && c && chunk); + connection *c; - pa_memblockq_push(c->output_memblockq, chunk); + pa_assert(o); + c = CONNECTION(o->userdata); + pa_assert(c); + pa_assert(chunk); - /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_POST_DATA, NULL, 0, chunk, NULL); } +/* Called from main context */ static void source_output_kill_cb(pa_source_output *o) { - assert(o && o->userdata); - connection_free((struct connection *) o->userdata); + pa_source_output_assert_ref(o); + + connection_unlink(CONNECTION(o->userdata)); } +/* Called from main context */ static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { - struct connection*c = o->userdata; - assert(o && c); + connection*c; + + pa_assert(o); + c = CONNECTION(o->userdata); + pa_assert(c); + return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec); } /*** client callbacks ***/ -static void client_kill_cb(pa_client *c) { - assert(c && c->userdata); - connection_free((struct connection *) c->userdata); +static void client_kill_cb(pa_client *client) { + connection*c; + + pa_assert(client); + c = CONNECTION(client->userdata); + pa_assert(c); + + connection_unlink(c); } /*** pa_iochannel callbacks ***/ static void io_callback(pa_iochannel*io, void *userdata) { - struct connection *c = userdata; - assert(io && c && c->io == io); - - do_work(c); -} - -/*** fixed callback ***/ + connection *c = CONNECTION(userdata); -static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { - struct connection *c = userdata; - assert(a && c && c->defer_event == e); + connection_assert_ref(c); + pa_assert(io); do_work(c); } @@ -312,9 +448,12 @@ static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { pa_protocol_simple *p = userdata; - struct connection *c = NULL; + connection *c = NULL; char cname[256]; - assert(s && io && p); + + pa_assert(s); + pa_assert(io); + pa_assert(p); if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); @@ -322,21 +461,22 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) return; } - c = pa_xmalloc(sizeof(struct connection)); + c = pa_msgobject_new(connection); + c->parent.parent.free = connection_free; + c->parent.process_msg = connection_process_msg; c->io = io; c->sink_input = NULL; c->source_output = NULL; - c->defer_event = NULL; c->input_memblockq = c->output_memblockq = NULL; c->protocol = p; c->playback.current_memblock = NULL; c->playback.memblock_index = 0; c->playback.fragment_size = 0; c->dead = 0; + pa_atomic_store(&c->playback.missing, 0); pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); - c->client = pa_client_new(p->core, __FILE__, cname); - assert(c->client); + pa_assert_se(c->client = pa_client_new(p->core, __FILE__, cname)); c->client->owner = p->module; c->client->kill = client_kill_cb; c->client->userdata = c; @@ -357,10 +497,10 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) goto fail; } + c->sink_input->parent.process_msg = sink_input_process_msg; c->sink_input->peek = sink_input_peek_cb; c->sink_input->drop = sink_input_drop_cb; c->sink_input->kill = sink_input_kill_cb; - c->sink_input->get_latency = sink_input_get_latency_cb; c->sink_input->userdata = c; l = (size_t) (pa_bytes_per_second(&p->sample_spec)*PLAYBACK_BUFFER_SECONDS); @@ -372,11 +512,12 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) (size_t) -1, l/PLAYBACK_BUFFER_FRAGMENTS, NULL); - assert(c->input_memblockq); pa_iochannel_socket_set_rcvbuf(io, l/PLAYBACK_BUFFER_FRAGMENTS*5); - c->playback.fragment_size = l/10; + c->playback.fragment_size = l/PLAYBACK_BUFFER_FRAGMENTS; + + pa_atomic_store(&c->playback.missing, pa_memblockq_missing(c->input_memblockq)); - pa_sink_notify(c->sink_input->sink); + pa_sink_input_put(c->sink_input); } if (p->mode & RECORD) { @@ -409,29 +550,29 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) 0, NULL); pa_iochannel_socket_set_sndbuf(io, l/RECORD_BUFFER_FRAGMENTS*2); - pa_source_notify(c->source_output->source); + + pa_source_output_put(c->source_output); } pa_iochannel_set_callback(c->io, io_callback, c); pa_idxset_put(p->connections, c, NULL); - c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c); - assert(c->defer_event); - p->core->mainloop->defer_enable(c->defer_event, 0); - return; fail: if (c) - connection_free(c); + connection_unlink(c); } pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { pa_protocol_simple* p = NULL; int enable; - assert(core && server && ma); - p = pa_xmalloc0(sizeof(pa_protocol_simple)); + pa_assert(core); + pa_assert(server); + pa_assert(ma); + + p = pa_xnew0(pa_protocol_simple, 1); p->module = m; p->core = core; p->server = server; @@ -472,23 +613,24 @@ pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *serv fail: if (p) pa_protocol_simple_free(p); + return NULL; } void pa_protocol_simple_free(pa_protocol_simple *p) { - struct connection *c; - assert(p); + connection *c; + pa_assert(p); if (p->connections) { while((c = pa_idxset_first(p->connections, NULL))) - connection_free(c); + connection_unlink(c); pa_idxset_free(p->connections, NULL, NULL); } if (p->server) pa_socket_server_unref(p->server); + pa_xfree(p); } - diff --git a/src/pulsecore/pstream-util.c b/src/pulsecore/pstream-util.c index fae1e49b..a6932158 100644 --- a/src/pulsecore/pstream-util.c +++ b/src/pulsecore/pstream-util.c @@ -25,9 +25,8 @@ #include #endif -#include - #include +#include #include "pstream-util.h" @@ -35,20 +34,20 @@ void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, const size_t length; uint8_t *data; pa_packet *packet; - assert(p); - assert(t); - data = pa_tagstruct_free_data(t, &length); - assert(data && length); - packet = pa_packet_new_dynamic(data, length); - assert(packet); + pa_assert(p); + pa_assert(t); + + pa_assert_se(data = pa_tagstruct_free_data(t, &length)); + pa_assert_se(packet = pa_packet_new_dynamic(data, length)); pa_pstream_send_packet(p, packet, creds); pa_packet_unref(packet); } void pa_pstream_send_error(pa_pstream *p, uint32_t tag, uint32_t error) { - pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); + pa_tagstruct *t; + + pa_assert_se(t = pa_tagstruct_new(NULL, 0)); pa_tagstruct_putu32(t, PA_COMMAND_ERROR); pa_tagstruct_putu32(t, tag); pa_tagstruct_putu32(t, error); @@ -56,8 +55,9 @@ void pa_pstream_send_error(pa_pstream *p, uint32_t tag, uint32_t error) { } void pa_pstream_send_simple_ack(pa_pstream *p, uint32_t tag) { - pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); + pa_tagstruct *t; + + pa_assert_se(t = pa_tagstruct_new(NULL, 0)); pa_tagstruct_putu32(t, PA_COMMAND_REPLY); pa_tagstruct_putu32(t, tag); pa_pstream_send_tagstruct(p, t); diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index fdb1a66a..9d32a363 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -28,7 +28,6 @@ #include #include -#include #include #ifdef HAVE_SYS_SOCKET_H @@ -41,16 +40,17 @@ #include #endif -#include "winsock.h" #include +#include #include #include #include #include -#include #include +#include +#include #include "pstream.h" @@ -84,7 +84,8 @@ typedef uint32_t pa_pstream_descriptor[PA_PSTREAM_DESCRIPTOR_MAX]; #define PA_PSTREAM_DESCRIPTOR_SIZE (PA_PSTREAM_DESCRIPTOR_MAX*sizeof(uint32_t)) #define FRAME_SIZE_MAX_ALLOW PA_SCACHE_ENTRY_SIZE_MAX /* allow uploading a single sample in one frame at max */ -#define FRAME_SIZE_MAX_USE (1024*64) + +PA_STATIC_FLIST_DECLARE(items, 0, pa_xfree); struct item_info { enum { @@ -94,7 +95,6 @@ struct item_info { PA_PSTREAM_ITEM_SHMREVOKE } type; - /* packet info */ pa_packet *packet; #ifdef HAVE_CREDS @@ -118,8 +118,8 @@ struct pa_pstream { pa_mainloop_api *mainloop; pa_defer_event *defer_event; pa_iochannel *io; + pa_queue *send_queue; - pa_mutex *mutex; int dead; @@ -129,6 +129,7 @@ struct pa_pstream { uint32_t shm_info[PA_PSTREAM_SHM_MAX]; void *data; size_t index; + pa_memchunk memchunk; } write; struct { @@ -156,6 +157,12 @@ struct pa_pstream { pa_pstream_notify_cb_t die_callback; void *die_callback_userdata; + pa_pstream_block_id_cb_t revoke_callback; + void *revoke_callback_userdata; + + pa_pstream_block_id_cb_t release_callback; + void *release_callback_userdata; + pa_mempool *mempool; #ifdef HAVE_CREDS @@ -168,13 +175,11 @@ static int do_write(pa_pstream *p); static int do_read(pa_pstream *p); static void do_something(pa_pstream *p) { - assert(p); - assert(PA_REFCNT_VALUE(p) > 0); + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); pa_pstream_ref(p); - pa_mutex_lock(p->mutex); - p->mainloop->defer_enable(p->defer_event, 0); if (!p->dead && pa_iochannel_is_readable(p->io)) { @@ -188,28 +193,24 @@ static void do_something(pa_pstream *p) { goto fail; } - pa_mutex_unlock(p->mutex); - pa_pstream_unref(p); return; fail: - p->dead = 1; - if (p->die_callback) p->die_callback(p, p->die_callback_userdata); - pa_mutex_unlock(p->mutex); - + pa_pstream_unlink(p); pa_pstream_unref(p); } static void io_callback(pa_iochannel*io, void *userdata) { pa_pstream *p = userdata; - assert(p); - assert(p->io == io); + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); + pa_assert(p->io == io); do_something(p); } @@ -217,9 +218,10 @@ static void io_callback(pa_iochannel*io, void *userdata) { static void defer_callback(pa_mainloop_api *m, pa_defer_event *e, void*userdata) { pa_pstream *p = userdata; - assert(p); - assert(p->defer_event == e); - assert(p->mainloop == m); + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); + pa_assert(p->defer_event == e); + pa_assert(p->mainloop == m); do_something(p); } @@ -229,9 +231,9 @@ static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userd pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *pool) { pa_pstream *p; - assert(m); - assert(io); - assert(pool); + pa_assert(m); + pa_assert(io); + pa_assert(pool); p = pa_xnew(pa_pstream, 1); PA_REFCNT_INIT(p); @@ -239,17 +241,15 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *poo pa_iochannel_set_callback(io, io_callback, p); p->dead = 0; - p->mutex = pa_mutex_new(1); - p->mainloop = m; p->defer_event = m->defer_new(m, defer_callback, p); m->defer_enable(p->defer_event, 0); p->send_queue = pa_queue_new(); - assert(p->send_queue); p->write.current = NULL; p->write.index = 0; + pa_memchunk_reset(&p->write.memchunk); p->read.memblock = NULL; p->read.packet = NULL; p->read.index = 0; @@ -262,6 +262,10 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *poo p->drain_callback_userdata = NULL; p->die_callback = NULL; p->die_callback_userdata = NULL; + p->revoke_callback = NULL; + p->revoke_callback_userdata = NULL; + p->release_callback = NULL; + p->release_callback_userdata = NULL; p->mempool = pool; @@ -281,56 +285,57 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *poo return p; } -static void item_free(void *item, PA_GCC_UNUSED void *p) { +static void item_free(void *item, PA_GCC_UNUSED void *q) { struct item_info *i = item; - assert(i); + pa_assert(i); if (i->type == PA_PSTREAM_ITEM_MEMBLOCK) { - assert(i->chunk.memblock); + pa_assert(i->chunk.memblock); pa_memblock_unref(i->chunk.memblock); } else if (i->type == PA_PSTREAM_ITEM_PACKET) { - assert(i->packet); + pa_assert(i->packet); pa_packet_unref(i->packet); } - pa_xfree(i); + if (pa_flist_push(PA_STATIC_FLIST_GET(items), i) < 0) + pa_xfree(i); } static void pstream_free(pa_pstream *p) { - assert(p); + pa_assert(p); - pa_pstream_close(p); + pa_pstream_unlink(p); pa_queue_free(p->send_queue, item_free, NULL); if (p->write.current) item_free(p->write.current, NULL); + if (p->write.memchunk.memblock) + pa_memblock_unref(p->write.memchunk.memblock); + if (p->read.memblock) pa_memblock_unref(p->read.memblock); if (p->read.packet) pa_packet_unref(p->read.packet); - if (p->mutex) - pa_mutex_free(p->mutex); - pa_xfree(p); } void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *creds) { struct item_info *i; - assert(p); - assert(PA_REFCNT_VALUE(p) > 0); - assert(packet); - - pa_mutex_lock(p->mutex); + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); + pa_assert(packet); if (p->dead) - goto finish; + return; + + if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items)))) + i = pa_xnew(struct item_info, 1); - i = pa_xnew(struct item_info, 1); i->type = PA_PSTREAM_ITEM_PACKET; i->packet = pa_packet_ref(packet); @@ -340,37 +345,36 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *cre #endif pa_queue_push(p->send_queue, i); - p->mainloop->defer_enable(p->defer_event, 1); -finish: - - pa_mutex_unlock(p->mutex); + p->mainloop->defer_enable(p->defer_event, 1); } void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek_mode, const pa_memchunk *chunk) { size_t length, idx; + size_t bsm; - assert(p); - assert(PA_REFCNT_VALUE(p) > 0); - assert(channel != (uint32_t) -1); - assert(chunk); - - pa_mutex_lock(p->mutex); + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); + pa_assert(channel != (uint32_t) -1); + pa_assert(chunk); if (p->dead) - goto finish; + return; - length = chunk->length; idx = 0; + length = chunk->length; + + bsm = pa_mempool_block_size_max(p->mempool); while (length > 0) { struct item_info *i; size_t n; - i = pa_xnew(struct item_info, 1); + if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items)))) + i = pa_xnew(struct item_info, 1); i->type = PA_PSTREAM_ITEM_MEMBLOCK; - n = length < FRAME_SIZE_MAX_USE ? length : FRAME_SIZE_MAX_USE; + n = MIN(length, bsm); i->chunk.index = chunk->index + idx; i->chunk.length = n; i->chunk.memblock = pa_memblock_ref(chunk->memblock); @@ -389,27 +393,20 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa } p->mainloop->defer_enable(p->defer_event, 1); - -finish: - - pa_mutex_unlock(p->mutex); } -static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userdata) { +void pa_pstream_send_release(pa_pstream *p, uint32_t block_id) { struct item_info *item; - pa_pstream *p = userdata; - - assert(p); - assert(PA_REFCNT_VALUE(p) > 0); - - pa_mutex_lock(p->mutex); + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); if (p->dead) - goto finish; + return; /* pa_log("Releasing block %u", block_id); */ - item = pa_xnew(struct item_info, 1); + if (!(item = pa_flist_pop(PA_STATIC_FLIST_GET(items)))) + item = pa_xnew(struct item_info, 1); item->type = PA_PSTREAM_ITEM_SHMRELEASE; item->block_id = block_id; #ifdef HAVE_CREDS @@ -418,27 +415,35 @@ static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userd pa_queue_push(p->send_queue, item); p->mainloop->defer_enable(p->defer_event, 1); - -finish: - - pa_mutex_unlock(p->mutex); } -static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userdata) { - struct item_info *item; +/* might be called from thread context */ +static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userdata) { pa_pstream *p = userdata; - assert(p); - assert(PA_REFCNT_VALUE(p) > 0); - - pa_mutex_lock(p->mutex); + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); if (p->dead) - goto finish; + return; + if (p->release_callback) + p->release_callback(p, block_id, p->release_callback_userdata); + else + pa_pstream_send_release(p, block_id); +} + +void pa_pstream_send_revoke(pa_pstream *p, uint32_t block_id) { + struct item_info *item; + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); + + if (p->dead) + return; /* pa_log("Revoking block %u", block_id); */ - item = pa_xnew(struct item_info, 1); + if (!(item = pa_flist_pop(PA_STATIC_FLIST_GET(items)))) + item = pa_xnew(struct item_info, 1); item->type = PA_PSTREAM_ITEM_SHMREVOKE; item->block_id = block_id; #ifdef HAVE_CREDS @@ -447,21 +452,33 @@ static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userda pa_queue_push(p->send_queue, item); p->mainloop->defer_enable(p->defer_event, 1); +} + +/* might be called from thread context */ +static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userdata) { + pa_pstream *p = userdata; -finish: + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); - pa_mutex_unlock(p->mutex); + if (p->revoke_callback) + p->revoke_callback(p, block_id, p->revoke_callback_userdata); + else + pa_pstream_send_revoke(p, block_id); } static void prepare_next_write_item(pa_pstream *p) { - assert(p); - assert(PA_REFCNT_VALUE(p) > 0); + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); - if (!(p->write.current = pa_queue_pop(p->send_queue))) + p->write.current = pa_queue_pop(p->send_queue); + + if (!p->write.current) return; p->write.index = 0; p->write.data = NULL; + pa_memchunk_reset(&p->write.memchunk); p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = 0; p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl((uint32_t) -1); @@ -471,7 +488,7 @@ static void prepare_next_write_item(pa_pstream *p) { if (p->write.current->type == PA_PSTREAM_ITEM_PACKET) { - assert(p->write.current->packet); + pa_assert(p->write.current->packet); p->write.data = p->write.current->packet->data; p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->packet->length); @@ -489,8 +506,8 @@ static void prepare_next_write_item(pa_pstream *p) { uint32_t flags; int send_payload = 1; - assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK); - assert(p->write.current->chunk.memblock); + pa_assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK); + pa_assert(p->write.current->chunk.memblock); p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl(p->write.current->channel); p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = htonl((uint32_t) (((uint64_t) p->write.current->offset) >> 32)); @@ -502,7 +519,7 @@ static void prepare_next_write_item(pa_pstream *p) { uint32_t block_id, shm_id; size_t offset, length; - assert(p->export); + pa_assert(p->export); if (pa_memexport_put(p->export, p->write.current->chunk.memblock, @@ -528,7 +545,9 @@ static void prepare_next_write_item(pa_pstream *p) { if (send_payload) { p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length); - p->write.data = (uint8_t*) p->write.current->chunk.memblock->data + p->write.current->chunk.index; + p->write.memchunk = p->write.current->chunk; + pa_memblock_ref(p->write.memchunk.memblock); + p->write.data = NULL; } p->write.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS] = htonl(flags); @@ -544,9 +563,10 @@ static int do_write(pa_pstream *p) { void *d; size_t l; ssize_t r; + pa_memblock *release_memblock = NULL; - assert(p); - assert(PA_REFCNT_VALUE(p) > 0); + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); if (!p->write.current) prepare_next_write_item(p); @@ -558,72 +578,105 @@ static int do_write(pa_pstream *p) { d = (uint8_t*) p->write.descriptor + p->write.index; l = PA_PSTREAM_DESCRIPTOR_SIZE - p->write.index; } else { - assert(p->write.data); + pa_assert(p->write.data || p->write.memchunk.memblock); + + if (p->write.data) + d = p->write.data; + else { + d = (uint8_t*) pa_memblock_acquire(p->write.memchunk.memblock) + p->write.memchunk.index; + release_memblock = p->write.memchunk.memblock; + } - d = (uint8_t*) p->write.data + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE; + d = (uint8_t*) d + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE; l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE); } - assert(l > 0); + pa_assert(l > 0); #ifdef HAVE_CREDS if (p->send_creds_now) { if ((r = pa_iochannel_write_with_creds(p->io, d, l, &p->write_creds)) < 0) - return -1; + goto fail; p->send_creds_now = 0; } else #endif if ((r = pa_iochannel_write(p->io, d, l)) < 0) - return -1; + goto fail; + + if (release_memblock) + pa_memblock_release(release_memblock); p->write.index += r; if (p->write.index >= PA_PSTREAM_DESCRIPTOR_SIZE + ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])) { - assert(p->write.current); - item_free(p->write.current, (void *) 1); + pa_assert(p->write.current); + item_free(p->write.current, NULL); p->write.current = NULL; + if (p->write.memchunk.memblock) + pa_memblock_unref(p->write.memchunk.memblock); + + pa_memchunk_reset(&p->write.memchunk); + if (p->drain_callback && !pa_pstream_is_pending(p)) p->drain_callback(p, p->drain_callback_userdata); } return 0; + +fail: + + if (release_memblock) + pa_memblock_release(release_memblock); + + return -1; } static int do_read(pa_pstream *p) { void *d; size_t l; ssize_t r; - - assert(p); - assert(PA_REFCNT_VALUE(p) > 0); + pa_memblock *release_memblock = NULL; + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); if (p->read.index < PA_PSTREAM_DESCRIPTOR_SIZE) { d = (uint8_t*) p->read.descriptor + p->read.index; l = PA_PSTREAM_DESCRIPTOR_SIZE - p->read.index; } else { - assert(p->read.data); - d = (uint8_t*) p->read.data + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE; + pa_assert(p->read.data || p->read.memblock); + + if (p->read.data) + d = p->read.data; + else { + d = pa_memblock_acquire(p->read.memblock); + release_memblock = p->read.memblock; + } + + d = (uint8_t*) d + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE; l = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE); } #ifdef HAVE_CREDS { - int b = 0; + pa_bool_t b = 0; if ((r = pa_iochannel_read_with_creds(p->io, d, l, &p->read_creds, &b)) <= 0) - return -1; + goto fail; p->read_creds_valid = p->read_creds_valid || b; } #else if ((r = pa_iochannel_read(p->io, d, l)) <= 0) - return -1; + goto fail; #endif + if (release_memblock) + pa_memblock_release(release_memblock); + p->read.index += r; if (p->read.index == PA_PSTREAM_DESCRIPTOR_SIZE) { @@ -643,7 +696,7 @@ static int do_read(pa_pstream *p) { /* pa_log("Got release frame for %u", ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); */ - assert(p->export); + pa_assert(p->export); pa_memexport_process_release(p->export, ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); goto frame_done; @@ -654,7 +707,7 @@ static int do_read(pa_pstream *p) { /* pa_log("Got revoke frame for %u", ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); */ - assert(p->import); + pa_assert(p->import); pa_memimport_process_revoke(p->import, ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); goto frame_done; @@ -667,7 +720,7 @@ static int do_read(pa_pstream *p) { return -1; } - assert(!p->read.packet && !p->read.memblock); + pa_assert(!p->read.packet && !p->read.memblock); channel = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]); @@ -704,7 +757,7 @@ static int do_read(pa_pstream *p) { /* Frame is a memblock frame */ p->read.memblock = pa_memblock_new(p->mempool, length); - p->read.data = p->read.memblock->data; + p->read.data = NULL; } else { pa_log_warn("Recieved memblock frame with invalid flags value."); @@ -771,9 +824,9 @@ static int do_read(pa_pstream *p) { } else { pa_memblock *b; - assert((ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]) & PA_FLAG_SHMMASK) == PA_FLAG_SHMDATA); + pa_assert((ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]) & PA_FLAG_SHMMASK) == PA_FLAG_SHMDATA); - assert(p->import); + pa_assert(p->import); if (!(b = pa_memimport_get(p->import, ntohl(p->read.shm_info[PA_PSTREAM_SHM_BLOCKID]), @@ -791,7 +844,7 @@ static int do_read(pa_pstream *p) { chunk.memblock = b; chunk.index = 0; - chunk.length = b->length; + chunk.length = pa_memblock_get_length(b); offset = (int64_t) ( (((uint64_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])) << 32) | @@ -819,92 +872,104 @@ frame_done: p->read.memblock = NULL; p->read.packet = NULL; p->read.index = 0; + p->read.data = NULL; #ifdef HAVE_CREDS p->read_creds_valid = 0; #endif return 0; + +fail: + if (release_memblock) + pa_memblock_release(release_memblock); + + return -1; } void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) { - assert(p); - assert(PA_REFCNT_VALUE(p) > 0); + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); - pa_mutex_lock(p->mutex); p->die_callback = cb; p->die_callback_userdata = userdata; - pa_mutex_unlock(p->mutex); } void pa_pstream_set_drain_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) { - assert(p); - assert(PA_REFCNT_VALUE(p) > 0); + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); - pa_mutex_lock(p->mutex); p->drain_callback = cb; p->drain_callback_userdata = userdata; - pa_mutex_unlock(p->mutex); } void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata) { - assert(p); - assert(PA_REFCNT_VALUE(p) > 0); + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); - pa_mutex_lock(p->mutex); p->recieve_packet_callback = cb; p->recieve_packet_callback_userdata = userdata; - pa_mutex_unlock(p->mutex); } void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, pa_pstream_memblock_cb_t cb, void *userdata) { - assert(p); - assert(PA_REFCNT_VALUE(p) > 0); + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); - pa_mutex_lock(p->mutex); p->recieve_memblock_callback = cb; p->recieve_memblock_callback_userdata = userdata; - pa_mutex_unlock(p->mutex); +} + +void pa_pstream_set_release_callback(pa_pstream *p, pa_pstream_block_id_cb_t cb, void *userdata) { + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); + + p->release_callback = cb; + p->release_callback_userdata = userdata; +} + +void pa_pstream_set_revoke_callback(pa_pstream *p, pa_pstream_block_id_cb_t cb, void *userdata) { + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); + + p->release_callback = cb; + p->release_callback_userdata = userdata; } int pa_pstream_is_pending(pa_pstream *p) { int b; - assert(p); - assert(PA_REFCNT_VALUE(p) > 0); - - pa_mutex_lock(p->mutex); + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); if (p->dead) b = 0; else b = p->write.current || !pa_queue_is_empty(p->send_queue); - pa_mutex_unlock(p->mutex); - return b; } void pa_pstream_unref(pa_pstream*p) { - assert(p); - assert(PA_REFCNT_VALUE(p) > 0); + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); if (PA_REFCNT_DEC(p) <= 0) pstream_free(p); } pa_pstream* pa_pstream_ref(pa_pstream*p) { - assert(p); - assert(PA_REFCNT_VALUE(p) > 0); + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); PA_REFCNT_INC(p); return p; } -void pa_pstream_close(pa_pstream *p) { - assert(p); +void pa_pstream_unlink(pa_pstream *p) { + pa_assert(p); - pa_mutex_lock(p->mutex); + if (p->dead) + return; p->dead = 1; @@ -932,15 +997,11 @@ void pa_pstream_close(pa_pstream *p) { p->drain_callback = NULL; p->recieve_packet_callback = NULL; p->recieve_memblock_callback = NULL; - - pa_mutex_unlock(p->mutex); } void pa_pstream_use_shm(pa_pstream *p, int enable) { - assert(p); - assert(PA_REFCNT_VALUE(p) > 0); - - pa_mutex_lock(p->mutex); + pa_assert(p); + pa_assert(PA_REFCNT_VALUE(p) > 0); p->use_shm = enable; @@ -956,6 +1017,4 @@ void pa_pstream_use_shm(pa_pstream *p, int enable) { p->export = NULL; } } - - pa_mutex_unlock(p->mutex); } diff --git a/src/pulsecore/pstream.h b/src/pulsecore/pstream.h index 5900ecea..72babea9 100644 --- a/src/pulsecore/pstream.h +++ b/src/pulsecore/pstream.h @@ -41,6 +41,7 @@ typedef struct pa_pstream pa_pstream; typedef void (*pa_pstream_packet_cb_t)(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata); typedef void (*pa_pstream_memblock_cb_t)(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata); typedef void (*pa_pstream_notify_cb_t)(pa_pstream *p, void *userdata); +typedef void (*pa_pstream_block_id_cb_t)(pa_pstream *p, uint32_t block_id, void *userdata); pa_pstream* pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *p); void pa_pstream_unref(pa_pstream*p); @@ -48,17 +49,20 @@ pa_pstream* pa_pstream_ref(pa_pstream*p); void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *creds); void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk); +void pa_pstream_send_release(pa_pstream *p, uint32_t block_id); +void pa_pstream_send_revoke(pa_pstream *p, uint32_t block_id); void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata); void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, pa_pstream_memblock_cb_t cb, void *userdata); void pa_pstream_set_drain_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata); - void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata); +void pa_pstream_set_release_callback(pa_pstream *p, pa_pstream_block_id_cb_t cb, void *userdata); +void pa_pstream_set_revoke_callback(pa_pstream *p, pa_pstream_block_id_cb_t cb, void *userdata); int pa_pstream_is_pending(pa_pstream *p); void pa_pstream_use_shm(pa_pstream *p, int enable); -void pa_pstream_close(pa_pstream *p); +void pa_pstream_unlink(pa_pstream *p); #endif diff --git a/src/pulsecore/queue.c b/src/pulsecore/queue.c index 1dd0f606..9b6a37f0 100644 --- a/src/pulsecore/queue.c +++ b/src/pulsecore/queue.c @@ -25,13 +25,16 @@ #include #endif -#include #include #include +#include +#include #include "queue.h" +PA_STATIC_FLIST_DECLARE(entries, 0, pa_xfree); + struct queue_entry { struct queue_entry *next; void *data; @@ -44,25 +47,24 @@ struct pa_queue { pa_queue* pa_queue_new(void) { pa_queue *q = pa_xnew(pa_queue, 1); + q->front = q->back = NULL; q->length = 0; + return q; } void pa_queue_free(pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata) { - struct queue_entry *e; - assert(q); - - e = q->front; - while (e) { - struct queue_entry *n = e->next; + void *data; + pa_assert(q); + while ((data = pa_queue_pop(q))) if (destroy) - destroy(e->data, userdata); + destroy(data, userdata); - pa_xfree(e); - e = n; - } + pa_assert(!q->front); + pa_assert(!q->back); + pa_assert(q->length == 0); pa_xfree(q); } @@ -70,14 +72,20 @@ void pa_queue_free(pa_queue* q, void (*destroy)(void *p, void *userdata), void * void pa_queue_push(pa_queue *q, void *p) { struct queue_entry *e; - e = pa_xnew(struct queue_entry, 1); + pa_assert(q); + pa_assert(p); + + if (!(e = pa_flist_pop(PA_STATIC_FLIST_GET(entries)))) + e = pa_xnew(struct queue_entry, 1); + e->data = p; e->next = NULL; - if (q->back) + if (q->back) { + pa_assert(q->front); q->back->next = e; - else { - assert(!q->front); + } else { + pa_assert(!q->front); q->front = e; } @@ -88,17 +96,22 @@ void pa_queue_push(pa_queue *q, void *p) { void* pa_queue_pop(pa_queue *q) { void *p; struct queue_entry *e; - assert(q); + pa_assert(q); if (!(e = q->front)) return NULL; q->front = e->next; - if (q->back == e) + + if (q->back == e) { + pa_assert(!e->next); q->back = NULL; + } p = e->data; - pa_xfree(e); + + if (pa_flist_push(PA_STATIC_FLIST_GET(entries), e) < 0) + pa_xfree(e); q->length--; @@ -106,6 +119,7 @@ void* pa_queue_pop(pa_queue *q) { } int pa_queue_is_empty(pa_queue *q) { - assert(q); + pa_assert(q); + return q->length == 0; } diff --git a/src/pulsecore/random.c b/src/pulsecore/random.c index 3f591917..87afebfa 100644 --- a/src/pulsecore/random.c +++ b/src/pulsecore/random.c @@ -31,21 +31,22 @@ #include #include #include -#include #include #include #include +#include #include "random.h" static int has_whined = 0; -static const char *devices[] = { "/dev/urandom", "/dev/random", NULL }; +static const char * const devices[] = { "/dev/urandom", "/dev/random", NULL }; static int random_proper(void *ret_data, size_t length) { #ifdef OS_IS_WIN32 - assert(ret_data && length); + pa_assert(ret_data); + pa_assert(length > 0); return -1; @@ -53,9 +54,10 @@ static int random_proper(void *ret_data, size_t length) { int fd, ret = -1; ssize_t r = 0; - const char **device; + const char *const * device; - assert(ret_data && length); + pa_assert(ret_data); + pa_assert(length > 0); device = devices; @@ -67,7 +69,7 @@ static int random_proper(void *ret_data, size_t length) { if ((r = pa_loop_read(fd, ret_data, length, NULL)) < 0 || (size_t) r != length) ret = -1; - close(fd); + pa_close(fd); } else ret = -1; @@ -84,7 +86,7 @@ void pa_random_seed(void) { if (random_proper(&seed, sizeof(unsigned int)) < 0) { if (!has_whined) - pa_log_warn("failed to get proper entropy. Falling back to seeding with current time."); + pa_log_warn("Failed to get proper entropy. Falling back to seeding with current time."); has_whined = 1; seed = (unsigned int) time(NULL); @@ -97,13 +99,14 @@ void pa_random(void *ret_data, size_t length) { uint8_t *p; size_t l; - assert(ret_data && length); + pa_assert(ret_data); + pa_assert(length > 0); if (random_proper(ret_data, length) >= 0) return; if (!has_whined) - pa_log_warn("failed to get proper entropy. Falling back to unsecure pseudo RNG."); + pa_log_warn("Failed to get proper entropy. Falling back to unsecure pseudo RNG."); has_whined = 1; for (p = ret_data, l = length; l > 0; p++, l--) diff --git a/src/pulsecore/refcnt.h b/src/pulsecore/refcnt.h index 43433ff8..64271ab2 100644 --- a/src/pulsecore/refcnt.h +++ b/src/pulsecore/refcnt.h @@ -27,18 +27,18 @@ #include #define PA_REFCNT_DECLARE \ - pa_atomic_int_t _ref + pa_atomic_t _ref #define PA_REFCNT_INIT(p) \ - pa_atomic_store(&p->_ref, 1) + pa_atomic_store(&(p)->_ref, 1) #define PA_REFCNT_INC(p) \ - pa_atomic_inc(&p->_ref) + pa_atomic_inc(&(p)->_ref) #define PA_REFCNT_DEC(p) \ - (pa_atomic_dec(&p->_ref)-1) + (pa_atomic_dec(&(p)->_ref)-1) #define PA_REFCNT_VALUE(p) \ - pa_atomic_load(&p->_ref) + pa_atomic_load(&(p)->_ref) #endif diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index 3827ff94..5bbc6bf4 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -25,53 +25,133 @@ #include #endif -#include #include +#if HAVE_LIBSAMPLERATE #include +#endif + #include #include #include - #include #include +#include + +#include "speexwrap.h" + +#include "ffmpeg/avcodec.h" #include "resampler.h" +/* Number of samples of extra space we allow the resamplers to return */ +#define EXTRA_SAMPLES 128 + struct pa_resampler { pa_resample_method_t resample_method; pa_sample_spec i_ss, o_ss; pa_channel_map i_cm, o_cm; - size_t i_fz, o_fz; + size_t i_fz, o_fz, w_sz; pa_mempool *mempool; - void (*impl_free)(pa_resampler *r); - void (*impl_update_input_rate)(pa_resampler *r, uint32_t rate); - void (*impl_run)(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out); - void *impl_data; -}; - -struct impl_libsamplerate { - pa_memblock *buf1_block, *buf2_block, *buf3_block, *buf4_block; - float* buf1, *buf2, *buf3, *buf4; + pa_memchunk buf1, buf2, buf3, buf4; unsigned buf1_samples, buf2_samples, buf3_samples, buf4_samples; - pa_convert_to_float32ne_func_t to_float32ne_func; - pa_convert_from_float32ne_func_t from_float32ne_func; - SRC_STATE *src_state; + pa_sample_format_t work_format; + + pa_convert_func_t to_work_format_func; + pa_convert_func_t from_work_format_func; int map_table[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; int map_required; -}; -struct impl_trivial { - unsigned o_counter; - unsigned i_counter; + void (*impl_free)(pa_resampler *r); + void (*impl_update_rates)(pa_resampler *r); + void (*impl_resample)(pa_resampler *r, const pa_memchunk *in, unsigned in_samples, pa_memchunk *out, unsigned *out_samples); + + struct { /* data specific to the trivial resampler */ + unsigned o_counter; + unsigned i_counter; + } trivial; + +#ifdef HAVE_LIBSAMPLERATE + struct { /* data specific to libsamplerate */ + SRC_STATE *state; + } src; +#endif + + struct { /* data specific to speex */ + SpeexResamplerState* state; + } speex; + + struct { /* data specific to ffmpeg */ + struct AVResampleContext *state; + pa_memchunk buf[PA_CHANNELS_MAX]; + } ffmpeg; }; -static int libsamplerate_init(pa_resampler*r); +static int copy_init(pa_resampler *r); static int trivial_init(pa_resampler*r); +static int speex_init(pa_resampler*r); +static int ffmpeg_init(pa_resampler*r); +#ifdef HAVE_LIBSAMPLERATE +static int libsamplerate_init(pa_resampler*r); +#endif + +static void calc_map_table(pa_resampler *r); + +static int (* const init_table[])(pa_resampler*r) = { +#ifdef HAVE_LIBSAMPLERATE + [PA_RESAMPLER_SRC_SINC_BEST_QUALITY] = libsamplerate_init, + [PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY] = libsamplerate_init, + [PA_RESAMPLER_SRC_SINC_FASTEST] = libsamplerate_init, + [PA_RESAMPLER_SRC_ZERO_ORDER_HOLD] = libsamplerate_init, + [PA_RESAMPLER_SRC_LINEAR] = libsamplerate_init, +#else + [PA_RESAMPLER_SRC_SINC_BEST_QUALITY] = NULL, + [PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY] = NULL, + [PA_RESAMPLER_SRC_SINC_FASTEST] = NULL, + [PA_RESAMPLER_SRC_ZERO_ORDER_HOLD] = NULL, + [PA_RESAMPLER_SRC_LINEAR] = NULL, +#endif + [PA_RESAMPLER_TRIVIAL] = trivial_init, + [PA_RESAMPLER_SPEEX_FLOAT_BASE+0] = speex_init, + [PA_RESAMPLER_SPEEX_FLOAT_BASE+1] = speex_init, + [PA_RESAMPLER_SPEEX_FLOAT_BASE+2] = speex_init, + [PA_RESAMPLER_SPEEX_FLOAT_BASE+3] = speex_init, + [PA_RESAMPLER_SPEEX_FLOAT_BASE+4] = speex_init, + [PA_RESAMPLER_SPEEX_FLOAT_BASE+5] = speex_init, + [PA_RESAMPLER_SPEEX_FLOAT_BASE+6] = speex_init, + [PA_RESAMPLER_SPEEX_FLOAT_BASE+7] = speex_init, + [PA_RESAMPLER_SPEEX_FLOAT_BASE+8] = speex_init, + [PA_RESAMPLER_SPEEX_FLOAT_BASE+9] = speex_init, + [PA_RESAMPLER_SPEEX_FLOAT_BASE+10] = speex_init, + [PA_RESAMPLER_SPEEX_FIXED_BASE+0] = speex_init, + [PA_RESAMPLER_SPEEX_FIXED_BASE+1] = speex_init, + [PA_RESAMPLER_SPEEX_FIXED_BASE+2] = speex_init, + [PA_RESAMPLER_SPEEX_FIXED_BASE+3] = speex_init, + [PA_RESAMPLER_SPEEX_FIXED_BASE+4] = speex_init, + [PA_RESAMPLER_SPEEX_FIXED_BASE+5] = speex_init, + [PA_RESAMPLER_SPEEX_FIXED_BASE+6] = speex_init, + [PA_RESAMPLER_SPEEX_FIXED_BASE+7] = speex_init, + [PA_RESAMPLER_SPEEX_FIXED_BASE+8] = speex_init, + [PA_RESAMPLER_SPEEX_FIXED_BASE+9] = speex_init, + [PA_RESAMPLER_SPEEX_FIXED_BASE+10] = speex_init, + [PA_RESAMPLER_FFMPEG] = ffmpeg_init, + [PA_RESAMPLER_AUTO] = NULL, + [PA_RESAMPLER_COPY] = copy_init +}; + +static inline size_t sample_size(pa_sample_format_t f) { + pa_sample_spec ss = { + .format = f, + .rate = 0, + .channels = 1 + }; + + return pa_sample_size(&ss); +} pa_resampler* pa_resampler_new( pa_mempool *pool, @@ -79,25 +159,51 @@ pa_resampler* pa_resampler_new( const pa_channel_map *am, const pa_sample_spec *b, const pa_channel_map *bm, - pa_resample_method_t resample_method) { + pa_resample_method_t resample_method, + int variable_rate) { pa_resampler *r = NULL; - assert(pool); - assert(a); - assert(b); - assert(pa_sample_spec_valid(a)); - assert(pa_sample_spec_valid(b)); - assert(resample_method != PA_RESAMPLER_INVALID); + pa_assert(pool); + pa_assert(a); + pa_assert(b); + pa_assert(pa_sample_spec_valid(a)); + pa_assert(pa_sample_spec_valid(b)); + pa_assert(resample_method >= 0); + pa_assert(resample_method < PA_RESAMPLER_MAX); + + /* Fix method */ + + if (!variable_rate && a->rate == b->rate) { + pa_log_info("Forcing resampler 'copy', because of fixed, identical sample rates."); + resample_method = PA_RESAMPLER_COPY; + } + + if (!pa_resample_method_supported(resample_method)) { + pa_log_warn("Support for resampler '%s' not compiled in, reverting to 'auto'.", pa_resample_method_to_string(resample_method)); + resample_method = PA_RESAMPLER_AUTO; + } + + if (resample_method == PA_RESAMPLER_FFMPEG && variable_rate) { + pa_log_info("Resampler 'ffmpeg' cannot do variable rate, reverting to resampler 'auto'."); + resample_method = PA_RESAMPLER_AUTO; + } + + if (resample_method == PA_RESAMPLER_COPY && (variable_rate || a->rate != b->rate)) { + pa_log_info("Resampler 'copy' cannot change sampling rate, reverting to resampler 'auto'."); + resample_method = PA_RESAMPLER_AUTO; + } + + if (resample_method == PA_RESAMPLER_AUTO) + resample_method = PA_RESAMPLER_SPEEX_FLOAT_BASE + 0; r = pa_xnew(pa_resampler, 1); - r->impl_data = NULL; r->mempool = pool; r->resample_method = resample_method; r->impl_free = NULL; - r->impl_update_input_rate = NULL; - r->impl_run = NULL; + r->impl_update_rates = NULL; + r->impl_resample = NULL; /* Fill sample specs */ r->i_ss = *a; @@ -116,25 +222,66 @@ pa_resampler* pa_resampler_new( r->i_fz = pa_frame_size(a); r->o_fz = pa_frame_size(b); - /* Choose implementation */ - if (a->channels != b->channels || - a->format != b->format || - !pa_channel_map_equal(&r->i_cm, &r->o_cm) || - resample_method != PA_RESAMPLER_TRIVIAL) { + pa_memchunk_reset(&r->buf1); + pa_memchunk_reset(&r->buf2); + pa_memchunk_reset(&r->buf3); + pa_memchunk_reset(&r->buf4); + + r->buf1_samples = r->buf2_samples = r->buf3_samples = r->buf4_samples = 0; + + calc_map_table(r); + + pa_log_info("Using resampler '%s'", pa_resample_method_to_string(resample_method)); + + if ((resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX) || + (resample_method == PA_RESAMPLER_FFMPEG)) + r->work_format = PA_SAMPLE_S16NE; + else if (resample_method == PA_RESAMPLER_TRIVIAL || resample_method == PA_RESAMPLER_COPY) { - /* Use the libsamplerate based resampler for the complicated cases */ - if (resample_method == PA_RESAMPLER_TRIVIAL) - r->resample_method = PA_RESAMPLER_SRC_ZERO_ORDER_HOLD; + if (r->map_required || a->format != b->format) { - if (libsamplerate_init(r) < 0) + if (a->format == PA_SAMPLE_FLOAT32NE || a->format == PA_SAMPLE_FLOAT32RE || + b->format == PA_SAMPLE_FLOAT32NE || b->format == PA_SAMPLE_FLOAT32RE) + r->work_format = PA_SAMPLE_FLOAT32NE; + else + r->work_format = PA_SAMPLE_S16NE; + + } else + r->work_format = a->format; + + } else + r->work_format = PA_SAMPLE_FLOAT32NE; + + pa_log_info("Using %s as working format.", pa_sample_format_to_string(r->work_format)); + + r->w_sz = sample_size(r->work_format); + + if (r->i_ss.format == r->work_format) + r->to_work_format_func = NULL; + else if (r->work_format == PA_SAMPLE_FLOAT32NE) { + if (!(r->to_work_format_func = pa_get_convert_to_float32ne_function(r->i_ss.format))) + goto fail; + } else { + pa_assert(r->work_format == PA_SAMPLE_S16NE); + if (!(r->to_work_format_func = pa_get_convert_to_s16ne_function(r->i_ss.format))) goto fail; + } + if (r->o_ss.format == r->work_format) + r->from_work_format_func = NULL; + else if (r->work_format == PA_SAMPLE_FLOAT32NE) { + if (!(r->from_work_format_func = pa_get_convert_from_float32ne_function(r->o_ss.format))) + goto fail; } else { - /* Use our own simple non-fp resampler for the trivial cases and when the user selects it */ - if (trivial_init(r) < 0) + pa_assert(r->work_format == PA_SAMPLE_S16NE); + if (!(r->from_work_format_func = pa_get_convert_from_s16ne_function(r->o_ss.format))) goto fail; } + /* initialize implementation */ + if (init_table[resample_method](r) < 0) + goto fail; + return r; fail: @@ -145,41 +292,85 @@ fail: } void pa_resampler_free(pa_resampler *r) { - assert(r); + pa_assert(r); if (r->impl_free) r->impl_free(r); + if (r->buf1.memblock) + pa_memblock_unref(r->buf1.memblock); + if (r->buf2.memblock) + pa_memblock_unref(r->buf2.memblock); + if (r->buf3.memblock) + pa_memblock_unref(r->buf3.memblock); + if (r->buf4.memblock) + pa_memblock_unref(r->buf4.memblock); + pa_xfree(r); } void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate) { - assert(r); - assert(rate > 0); + pa_assert(r); + pa_assert(rate > 0); if (r->i_ss.rate == rate) return; r->i_ss.rate = rate; - if (r->impl_update_input_rate) - r->impl_update_input_rate(r, rate); + r->impl_update_rates(r); } -void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { - assert(r && in && out && r->impl_run); +void pa_resampler_set_output_rate(pa_resampler *r, uint32_t rate) { + pa_assert(r); + pa_assert(rate > 0); - r->impl_run(r, in, out); + if (r->o_ss.rate == rate) + return; + + r->o_ss.rate = rate; + + r->impl_update_rates(r); } size_t pa_resampler_request(pa_resampler *r, size_t out_length) { - assert(r); + pa_assert(r); return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz; } +size_t pa_resampler_max_block_size(pa_resampler *r) { + size_t block_size_max; + pa_sample_spec ss; + size_t fs; + + pa_assert(r); + + block_size_max = pa_mempool_block_size_max(r->mempool); + + /* We deduce the "largest" sample spec we're using during the + * conversion */ + ss = r->i_ss; + if (r->o_ss.channels > ss.channels) + ss.channels = r->o_ss.channels; + + /* We silently assume that the format enum is ordered by size */ + if (r->o_ss.format > ss.format) + ss.format = r->o_ss.format; + if (r->work_format > ss.format) + ss.format = r->work_format; + + if (r->o_ss.rate > ss.rate) + ss.rate = r->o_ss.rate; + + fs = pa_frame_size(&ss); + + return (((block_size_max/fs + EXTRA_SAMPLES)*r->i_ss.rate)/ss.rate)*r->i_fz; +} + pa_resample_method_t pa_resampler_get_method(pa_resampler *r) { - assert(r); + pa_assert(r); + return r->resample_method; } @@ -189,7 +380,32 @@ static const char * const resample_methods[] = { "src-sinc-fastest", "src-zero-order-hold", "src-linear", - "trivial" + "trivial", + "speex-float-0", + "speex-float-1", + "speex-float-2", + "speex-float-3", + "speex-float-4", + "speex-float-5", + "speex-float-6", + "speex-float-7", + "speex-float-8", + "speex-float-9", + "speex-float-10", + "speex-fixed-0", + "speex-fixed-1", + "speex-fixed-2", + "speex-fixed-3", + "speex-fixed-4", + "speex-fixed-5", + "speex-fixed-6", + "speex-fixed-7", + "speex-fixed-8", + "speex-fixed-9", + "speex-fixed-10", + "ffmpeg", + "auto", + "copy" }; const char *pa_resample_method_to_string(pa_resample_method_t m) { @@ -200,52 +416,43 @@ const char *pa_resample_method_to_string(pa_resample_method_t m) { return resample_methods[m]; } -pa_resample_method_t pa_parse_resample_method(const char *string) { - pa_resample_method_t m; +int pa_resample_method_supported(pa_resample_method_t m) { - assert(string); + if (m < 0 || m >= PA_RESAMPLER_MAX) + return 0; - for (m = 0; m < PA_RESAMPLER_MAX; m++) - if (!strcmp(string, resample_methods[m])) - return m; +#ifndef HAVE_LIBSAMPLERATE + if (m <= PA_RESAMPLER_SRC_LINEAR) + return 0; +#endif - return PA_RESAMPLER_INVALID; + return 1; } +pa_resample_method_t pa_parse_resample_method(const char *string) { + pa_resample_method_t m; -/*** libsamplerate based implementation ***/ - -static void libsamplerate_free(pa_resampler *r) { - struct impl_libsamplerate *u; + pa_assert(string); - assert(r); - assert(r->impl_data); + for (m = 0; m < PA_RESAMPLER_MAX; m++) + if (!strcmp(string, resample_methods[m])) + return m; - u = r->impl_data; + if (!strcmp(string, "speex-fixed")) + return PA_RESAMPLER_SPEEX_FIXED_BASE + 0; - if (u->src_state) - src_delete(u->src_state); + if (!strcmp(string, "speex-float")) + return PA_RESAMPLER_SPEEX_FLOAT_BASE + 0; - if (u->buf1_block) - pa_memblock_unref(u->buf1_block); - if (u->buf2_block) - pa_memblock_unref(u->buf2_block); - if (u->buf3_block) - pa_memblock_unref(u->buf3_block); - if (u->buf4_block) - pa_memblock_unref(u->buf4_block); - pa_xfree(u); + return PA_RESAMPLER_INVALID; } static void calc_map_table(pa_resampler *r) { - struct impl_libsamplerate *u; unsigned oc; - assert(r); - assert(r->impl_data); - u = r->impl_data; + pa_assert(r); - if (!(u->map_required = (!pa_channel_map_equal(&r->i_cm, &r->o_cm) || r->i_ss.channels != r->o_ss.channels))) + if (!(r->map_required = (r->i_ss.channels != r->o_ss.channels || !pa_channel_map_equal(&r->i_cm, &r->o_cm)))) return; for (oc = 0; oc < r->o_ss.channels; oc++) { @@ -263,392 +470,590 @@ static void calc_map_table(pa_resampler *r) { (a == PA_CHANNEL_POSITION_LEFT && b == PA_CHANNEL_POSITION_MONO) || (a == PA_CHANNEL_POSITION_RIGHT && b == PA_CHANNEL_POSITION_MONO)) - u->map_table[oc][i++] = ic; + r->map_table[oc][i++] = ic; } /* Add an end marker */ if (i < PA_CHANNELS_MAX) - u->map_table[oc][i] = -1; + r->map_table[oc][i] = -1; } } -static float * convert_to_float(pa_resampler *r, void *input, unsigned n_frames) { - struct impl_libsamplerate *u; +static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) { unsigned n_samples; + void *src, *dst; - assert(r); - assert(input); - assert(r->impl_data); - u = r->impl_data; + pa_assert(r); + pa_assert(input); + pa_assert(input->memblock); - /* Convert the incoming sample into floats and place them in buf1 */ + /* Convert the incoming sample into the work sample format and place them in buf1 */ - if (!u->to_float32ne_func) + if (!r->to_work_format_func || !input->length) return input; - n_samples = n_frames * r->i_ss.channels; + n_samples = (input->length / r->i_fz) * r->i_ss.channels; - if (u->buf1_samples < n_samples) { - if (u->buf1_block) - pa_memblock_unref(u->buf1_block); + r->buf1.index = 0; + r->buf1.length = r->w_sz * n_samples; - u->buf1_samples = n_samples; - u->buf1_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples); - u->buf1 = u->buf1_block->data; + if (!r->buf1.memblock || r->buf1_samples < n_samples) { + if (r->buf1.memblock) + pa_memblock_unref(r->buf1.memblock); + + r->buf1_samples = n_samples; + r->buf1.memblock = pa_memblock_new(r->mempool, r->buf1.length); } - u->to_float32ne_func(n_samples, input, u->buf1); + src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index; + dst = (uint8_t*) pa_memblock_acquire(r->buf1.memblock); + + r->to_work_format_func(n_samples, src, dst); + + pa_memblock_release(input->memblock); + pa_memblock_release(r->buf1.memblock); - return u->buf1; + return &r->buf1; } -static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) { - struct impl_libsamplerate *u; - unsigned n_samples; +static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { + unsigned in_n_samples, out_n_samples, n_frames; int i_skip, o_skip; unsigned oc; + void *src, *dst; - assert(r); - assert(input); - assert(r->impl_data); - u = r->impl_data; + pa_assert(r); + pa_assert(input); + pa_assert(input->memblock); /* Remap channels and place the result int buf2 */ - if (!u->map_required) + if (!r->map_required || !input->length) return input; - n_samples = n_frames * r->o_ss.channels; + in_n_samples = input->length / r->w_sz; + n_frames = in_n_samples / r->i_ss.channels; + out_n_samples = n_frames * r->o_ss.channels; + + r->buf2.index = 0; + r->buf2.length = r->w_sz * out_n_samples; - if (u->buf2_samples < n_samples) { - if (u->buf2_block) - pa_memblock_unref(u->buf2_block); + if (!r->buf2.memblock || r->buf2_samples < out_n_samples) { + if (r->buf2.memblock) + pa_memblock_unref(r->buf2.memblock); - u->buf2_samples = n_samples; - u->buf2_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples); - u->buf2 = u->buf2_block->data; + r->buf2_samples = out_n_samples; + r->buf2.memblock = pa_memblock_new(r->mempool, r->buf2.length); } - memset(u->buf2, 0, n_samples * sizeof(float)); + src = ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index); + dst = pa_memblock_acquire(r->buf2.memblock); - o_skip = sizeof(float) * r->o_ss.channels; - i_skip = sizeof(float) * r->i_ss.channels; + memset(dst, 0, r->buf2.length); - for (oc = 0; oc < r->o_ss.channels; oc++) { - unsigned i; - static const float one = 1.0; - - for (i = 0; i < PA_CHANNELS_MAX && u->map_table[oc][i] >= 0; i++) - oil_vectoradd_f32( - u->buf2 + oc, o_skip, - u->buf2 + oc, o_skip, - input + u->map_table[oc][i], i_skip, - n_frames, - &one, &one); + o_skip = r->w_sz * r->o_ss.channels; + i_skip = r->w_sz * r->i_ss.channels; + + switch (r->work_format) { + case PA_SAMPLE_FLOAT32NE: + + for (oc = 0; oc < r->o_ss.channels; oc++) { + unsigned i; + static const float one = 1.0; + + for (i = 0; i < PA_CHANNELS_MAX && r->map_table[oc][i] >= 0; i++) + oil_vectoradd_f32( + (float*) dst + oc, o_skip, + (float*) dst + oc, o_skip, + (float*) src + r->map_table[oc][i], i_skip, + n_frames, + &one, &one); + } + + break; + + case PA_SAMPLE_S16NE: + + for (oc = 0; oc < r->o_ss.channels; oc++) { + unsigned i; + static const int16_t one = 1; + + for (i = 0; i < PA_CHANNELS_MAX && r->map_table[oc][i] >= 0; i++) + oil_vectoradd_s16( + (int16_t*) dst + oc, o_skip, + (int16_t*) dst + oc, o_skip, + (int16_t*) src + r->map_table[oc][i], i_skip, + n_frames, + &one, &one); + } + + break; + + default: + pa_assert_not_reached(); } - return u->buf2; + pa_memblock_release(input->memblock); + pa_memblock_release(r->buf2.memblock); + + r->buf2.length = out_n_samples * r->w_sz; + + return &r->buf2; } -static float *resample(pa_resampler *r, float *input, unsigned *n_frames) { - struct impl_libsamplerate *u; - SRC_DATA data; +static pa_memchunk *resample(pa_resampler *r, pa_memchunk *input) { + unsigned in_n_frames, in_n_samples; unsigned out_n_frames, out_n_samples; - int ret; - assert(r); - assert(input); - assert(n_frames); - assert(r->impl_data); - u = r->impl_data; + pa_assert(r); + pa_assert(input); /* Resample the data and place the result in buf3 */ - if (!u->src_state) + if (!r->impl_resample || !input->length) return input; - out_n_frames = (*n_frames*r->o_ss.rate/r->i_ss.rate)+1024; + in_n_samples = input->length / r->w_sz; + in_n_frames = in_n_samples / r->o_ss.channels; + + out_n_frames = ((in_n_frames*r->o_ss.rate)/r->i_ss.rate)+EXTRA_SAMPLES; out_n_samples = out_n_frames * r->o_ss.channels; - if (u->buf3_samples < out_n_samples) { - if (u->buf3_block) - pa_memblock_unref(u->buf3_block); + r->buf3.index = 0; + r->buf3.length = r->w_sz * out_n_samples; + + if (!r->buf3.memblock || r->buf3_samples < out_n_samples) { + if (r->buf3.memblock) + pa_memblock_unref(r->buf3.memblock); - u->buf3_samples = out_n_samples; - u->buf3_block = pa_memblock_new(r->mempool, sizeof(float) * out_n_samples); - u->buf3 = u->buf3_block->data; + r->buf3_samples = out_n_samples; + r->buf3.memblock = pa_memblock_new(r->mempool, r->buf3.length); } - data.data_in = input; - data.input_frames = *n_frames; + r->impl_resample(r, input, in_n_frames, &r->buf3, &out_n_frames); + r->buf3.length = out_n_frames * r->w_sz * r->o_ss.channels; - data.data_out = u->buf3; - data.output_frames = out_n_frames; + return &r->buf3; +} - data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate; - data.end_of_input = 0; +static pa_memchunk *convert_from_work_format(pa_resampler *r, pa_memchunk *input) { + unsigned n_samples, n_frames; + void *src, *dst; + + pa_assert(r); + pa_assert(input); + + /* Convert the data into the correct sample type and place the result in buf4 */ + + if (!r->from_work_format_func || !input->length) + return input; + + n_samples = input->length / r->w_sz; + n_frames = n_samples / r->o_ss.channels; + + r->buf4.index = 0; + r->buf4.length = r->o_fz * n_frames; + + if (!r->buf4.memblock || r->buf4_samples < n_samples) { + if (r->buf4.memblock) + pa_memblock_unref(r->buf4.memblock); + + r->buf4_samples = n_samples; + r->buf4.memblock = pa_memblock_new(r->mempool, r->buf4.length); + } - ret = src_process(u->src_state, &data); - assert(ret == 0); - assert((unsigned) data.input_frames_used == *n_frames); + src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index; + dst = pa_memblock_acquire(r->buf4.memblock); + r->from_work_format_func(n_samples, src, dst); + pa_memblock_release(input->memblock); + pa_memblock_release(r->buf4.memblock); - *n_frames = data.output_frames_gen; + r->buf4.length = r->o_fz * n_frames; - return u->buf3; + return &r->buf4; } -static void *convert_from_float(pa_resampler *r, float *input, unsigned n_frames) { - struct impl_libsamplerate *u; - unsigned n_samples; +void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { + pa_memchunk *buf; + + pa_assert(r); + pa_assert(in); + pa_assert(out); + pa_assert(in->length); + pa_assert(in->memblock); + pa_assert(in->length % r->i_fz == 0); + + buf = (pa_memchunk*) in; + buf = convert_to_work_format(r, buf); + buf = remap_channels(r, buf); + buf = resample(r, buf); + + if (buf->length) { + buf = convert_from_work_format(r, buf); + *out = *buf; + + if (buf == in) + pa_memblock_ref(buf->memblock); + else + pa_memchunk_reset(buf); + } else + pa_memchunk_reset(out); +} - assert(r); - assert(input); - assert(r->impl_data); - u = r->impl_data; +/*** libsamplerate based implementation ***/ - /* Convert the data into the correct sample type and place the result in buf4 */ +#ifdef HAVE_LIBSAMPLERATE +static void libsamplerate_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) { + SRC_DATA data; - if (!u->from_float32ne_func) - return input; + pa_assert(r); + pa_assert(input); + pa_assert(output); + pa_assert(out_n_frames); - n_samples = n_frames * r->o_ss.channels; + memset(&data, 0, sizeof(data)); - if (u->buf4_samples < n_samples) { - if (u->buf4_block) - pa_memblock_unref(u->buf4_block); + data.data_in = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index); + data.input_frames = in_n_frames; - u->buf4_samples = n_samples; - u->buf4_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples); - u->buf4 = u->buf4_block->data; - } + data.data_out = (float*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index); + data.output_frames = *out_n_frames; - u->from_float32ne_func(n_samples, input, u->buf4); - - return u->buf4; -} - -static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { - struct impl_libsamplerate *u; - float *buf; - void *input, *output; - unsigned n_frames; - - assert(r); - assert(in); - assert(out); - assert(in->length); - assert(in->memblock); - assert(in->length % r->i_fz == 0); - assert(r->impl_data); - - u = r->impl_data; - - input = ((uint8_t*) in->memblock->data + in->index); - n_frames = in->length / r->i_fz; - assert(n_frames > 0); - - buf = convert_to_float(r, input, n_frames); - buf = remap_channels(r, buf, n_frames); - buf = resample(r, buf, &n_frames); - - if (n_frames) { - output = convert_from_float(r, buf, n_frames); - - if (output == input) { - /* Mm, no adjustment has been necessary, so let's return the original block */ - out->memblock = pa_memblock_ref(in->memblock); - out->index = in->index; - out->length = in->length; - } else { - out->length = n_frames * r->o_fz; - out->index = 0; - out->memblock = NULL; - - if (output == u->buf1) { - u->buf1 = NULL; - u->buf1_samples = 0; - out->memblock = u->buf1_block; - u->buf1_block = NULL; - } else if (output == u->buf2) { - u->buf2 = NULL; - u->buf2_samples = 0; - out->memblock = u->buf2_block; - u->buf2_block = NULL; - } else if (output == u->buf3) { - u->buf3 = NULL; - u->buf3_samples = 0; - out->memblock = u->buf3_block; - u->buf3_block = NULL; - } else if (output == u->buf4) { - u->buf4 = NULL; - u->buf4_samples = 0; - out->memblock = u->buf4_block; - u->buf4_block = NULL; - } + data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate; + data.end_of_input = 0; - assert(out->memblock); - } - } else { - out->memblock = NULL; - out->index = out->length = 0; - } + pa_assert_se(src_process(r->src.state, &data) == 0); + pa_assert((unsigned) data.input_frames_used == in_n_frames); + + pa_memblock_release(input->memblock); + pa_memblock_release(output->memblock); + + *out_n_frames = data.output_frames_gen; } -static void libsamplerate_update_input_rate(pa_resampler *r, uint32_t rate) { - struct impl_libsamplerate *u; +static void libsamplerate_update_rates(pa_resampler *r) { + pa_assert(r); - assert(r); - assert(rate > 0); - assert(r->impl_data); - u = r->impl_data; + pa_assert_se(src_set_ratio(r->src.state, (double) r->o_ss.rate / r->i_ss.rate) == 0); +} - if (!u->src_state) { - int err; - u->src_state = src_new(r->resample_method, r->o_ss.channels, &err); - assert(u->src_state); - } else { - int ret = src_set_ratio(u->src_state, (double) r->o_ss.rate / rate); - assert(ret == 0); - } +static void libsamplerate_free(pa_resampler *r) { + pa_assert(r); + + if (r->src.state) + src_delete(r->src.state); } static int libsamplerate_init(pa_resampler *r) { - struct impl_libsamplerate *u = NULL; int err; - r->impl_data = u = pa_xnew(struct impl_libsamplerate, 1); + pa_assert(r); - u->buf1 = u->buf2 = u->buf3 = u->buf4 = NULL; - u->buf1_block = u->buf2_block = u->buf3_block = u->buf4_block = NULL; - u->buf1_samples = u->buf2_samples = u->buf3_samples = u->buf4_samples = 0; + if (!(r->src.state = src_new(r->resample_method, r->o_ss.channels, &err))) + return -1; - if (r->i_ss.format == PA_SAMPLE_FLOAT32NE) - u->to_float32ne_func = NULL; - else if (!(u->to_float32ne_func = pa_get_convert_to_float32ne_function(r->i_ss.format))) - goto fail; + r->impl_free = libsamplerate_free; + r->impl_update_rates = libsamplerate_update_rates; + r->impl_resample = libsamplerate_resample; - if (r->o_ss.format == PA_SAMPLE_FLOAT32NE) - u->from_float32ne_func = NULL; - else if (!(u->from_float32ne_func = pa_get_convert_from_float32ne_function(r->o_ss.format))) - goto fail; + return 0; +} +#endif - if (r->o_ss.rate == r->i_ss.rate) - u->src_state = NULL; - else if (!(u->src_state = src_new(r->resample_method, r->o_ss.channels, &err))) - goto fail; +/*** speex based implementation ***/ - r->impl_free = libsamplerate_free; - r->impl_update_input_rate = libsamplerate_update_input_rate; - r->impl_run = libsamplerate_run; +static void speex_resample_float(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) { + float *in, *out; + uint32_t inf = in_n_frames, outf = *out_n_frames; - calc_map_table(r); + pa_assert(r); + pa_assert(input); + pa_assert(output); + pa_assert(out_n_frames); - return 0; + in = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index); + out = (float*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index); -fail: - pa_xfree(u); - return -1; + pa_assert_se(paspfl_resampler_process_interleaved_float(r->speex.state, in, &inf, out, &outf) == 0); + + pa_memblock_release(input->memblock); + pa_memblock_release(output->memblock); + + pa_assert(inf == in_n_frames); + *out_n_frames = outf; } -/* Trivial implementation */ +static void speex_resample_int(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) { + int16_t *in, *out; + uint32_t inf = in_n_frames, outf = *out_n_frames; -static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { - size_t fz; - unsigned n_frames; - struct impl_trivial *u; + pa_assert(r); + pa_assert(input); + pa_assert(output); + pa_assert(out_n_frames); + + in = (int16_t*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index); + out = (int16_t*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index); + + pa_assert_se(paspfx_resampler_process_interleaved_int(r->speex.state, in, &inf, out, &outf) == 0); + + pa_memblock_release(input->memblock); + pa_memblock_release(output->memblock); - assert(r); - assert(in); - assert(out); - assert(r->impl_data); + pa_assert(inf == in_n_frames); + *out_n_frames = outf; +} - u = r->impl_data; +static void speex_update_rates(pa_resampler *r) { + pa_assert(r); - fz = r->i_fz; - assert(fz == r->o_fz); + if (r->resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX) + pa_assert_se(paspfx_resampler_set_rate(r->speex.state, r->i_ss.rate, r->o_ss.rate) == 0); + else { + pa_assert(r->resample_method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FLOAT_MAX); + pa_assert_se(paspfl_resampler_set_rate(r->speex.state, r->i_ss.rate, r->o_ss.rate) == 0); + } +} - n_frames = in->length/fz; +static void speex_free(pa_resampler *r) { + pa_assert(r); - if (r->i_ss.rate == r->o_ss.rate) { + if (!r->speex.state) + return; + + if (r->resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX) + paspfx_resampler_destroy(r->speex.state); + else { + pa_assert(r->resample_method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FLOAT_MAX); + paspfl_resampler_destroy(r->speex.state); + } +} - /* In case there's no diefference in sample types, do nothing */ - *out = *in; - pa_memblock_ref(out->memblock); +static int speex_init(pa_resampler *r) { + int q, err; - u->o_counter += n_frames; + pa_assert(r); + + r->impl_free = speex_free; + r->impl_update_rates = speex_update_rates; + + if (r->resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX) { + q = r->resample_method - PA_RESAMPLER_SPEEX_FIXED_BASE; + + pa_log_info("Choosing speex quality setting %i.", q); + + if (!(r->speex.state = paspfx_resampler_init(r->o_ss.channels, r->i_ss.rate, r->o_ss.rate, q, &err))) + return -1; + + r->impl_resample = speex_resample_int; } else { - /* Do real resampling */ - size_t l; - unsigned o_index; + pa_assert(r->resample_method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FLOAT_MAX); + q = r->resample_method - PA_RESAMPLER_SPEEX_FLOAT_BASE; + + pa_log_info("Choosing speex quality setting %i.", q); - /* The length of the new memory block rounded up */ - l = ((((n_frames+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz; + if (!(r->speex.state = paspfl_resampler_init(r->o_ss.channels, r->i_ss.rate, r->o_ss.rate, q, &err))) + return -1; - out->index = 0; - out->memblock = pa_memblock_new(r->mempool, l); + r->impl_resample = speex_resample_float; + } - for (o_index = 0;; o_index++, u->o_counter++) { - unsigned j; + return 0; +} - j = (u->o_counter * r->i_ss.rate / r->o_ss.rate); - j = j > u->i_counter ? j - u->i_counter : 0; +/* Trivial implementation */ - if (j >= n_frames) - break; +static void trivial_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) { + size_t fz; + unsigned o_index; + void *src, *dst; - assert(o_index*fz < out->memblock->length); + pa_assert(r); + pa_assert(input); + pa_assert(output); + pa_assert(out_n_frames); - memcpy((uint8_t*) out->memblock->data + fz*o_index, - (uint8_t*) in->memblock->data + in->index + fz*j, fz); + fz = r->w_sz * r->o_ss.channels; - } + src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index; + dst = (uint8_t*) pa_memblock_acquire(output->memblock) + output->index; + + for (o_index = 0;; o_index++, r->trivial.o_counter++) { + unsigned j; - out->length = o_index*fz; + j = ((r->trivial.o_counter * r->i_ss.rate) / r->o_ss.rate); + j = j > r->trivial.i_counter ? j - r->trivial.i_counter : 0; + + if (j >= in_n_frames) + break; + + pa_assert(o_index * fz < pa_memblock_get_length(output->memblock)); + + oil_memcpy((uint8_t*) dst + fz * o_index, + (uint8_t*) src + fz * j, fz); } - u->i_counter += n_frames; + pa_memblock_release(input->memblock); + pa_memblock_release(output->memblock); + + *out_n_frames = o_index; + + r->trivial.i_counter += in_n_frames; /* Normalize counters */ - while (u->i_counter >= r->i_ss.rate) { - u->i_counter -= r->i_ss.rate; - assert(u->o_counter >= r->o_ss.rate); - u->o_counter -= r->o_ss.rate; + while (r->trivial.i_counter >= r->i_ss.rate) { + pa_assert(r->trivial.o_counter >= r->o_ss.rate); + + r->trivial.i_counter -= r->i_ss.rate; + r->trivial.o_counter -= r->o_ss.rate; } } -static void trivial_free(pa_resampler *r) { - assert(r); +static void trivial_update_rates(pa_resampler *r) { + pa_assert(r); - pa_xfree(r->impl_data); + r->trivial.i_counter = 0; + r->trivial.o_counter = 0; } -static void trivial_update_input_rate(pa_resampler *r, uint32_t rate) { - struct impl_trivial *u; +static int trivial_init(pa_resampler*r) { + pa_assert(r); + + r->trivial.o_counter = r->trivial.i_counter = 0; - assert(r); - assert(rate > 0); - assert(r->impl_data); + r->impl_resample = trivial_resample; + r->impl_update_rates = trivial_update_rates; + r->impl_free = NULL; - u = r->impl_data; - u->i_counter = 0; - u->o_counter = 0; + return 0; } -static int trivial_init(pa_resampler*r) { - struct impl_trivial *u; +/*** ffmpeg based implementation ***/ + +static void ffmpeg_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) { + unsigned used_frames = 0, c; + + pa_assert(r); + pa_assert(input); + pa_assert(output); + pa_assert(out_n_frames); + + for (c = 0; c < r->o_ss.channels; c++) { + unsigned u; + pa_memblock *b, *w; + int16_t *p, *t, *k, *q, *s; + int consumed_frames; + unsigned in, l; + + /* Allocate a new block */ + b = pa_memblock_new(r->mempool, r->ffmpeg.buf[c].length + in_n_frames * sizeof(int16_t)); + p = pa_memblock_acquire(b); + + /* Copy the remaining data into it */ + l = r->ffmpeg.buf[c].length; + if (r->ffmpeg.buf[c].memblock) { + t = (int16_t*) ((uint8_t*) pa_memblock_acquire(r->ffmpeg.buf[c].memblock) + r->ffmpeg.buf[c].index); + memcpy(p, t, l); + pa_memblock_release(r->ffmpeg.buf[c].memblock); + pa_memblock_unref(r->ffmpeg.buf[c].memblock); + pa_memchunk_reset(&r->ffmpeg.buf[c]); + } + + /* Now append the new data, splitting up channels */ + t = ((int16_t*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index)) + c; + k = (int16_t*) ((uint8_t*) p + l); + for (u = 0; u < in_n_frames; u++) { + *k = *t; + t += r->o_ss.channels; + k ++; + } + pa_memblock_release(input->memblock); + + /* Calculate the resulting number of frames */ + in = in_n_frames + l / sizeof(int16_t); + + /* Allocate buffer for the result */ + w = pa_memblock_new(r->mempool, *out_n_frames * sizeof(int16_t)); + q = pa_memblock_acquire(w); + + /* Now, resample */ + used_frames = av_resample(r->ffmpeg.state, + q, p, + &consumed_frames, + in, *out_n_frames, + c >= (unsigned) r->o_ss.channels-1); + + pa_memblock_release(b); + + /* Now store the remaining samples away */ + pa_assert(consumed_frames <= (int) in); + if (consumed_frames < (int) in) { + r->ffmpeg.buf[c].memblock = b; + r->ffmpeg.buf[c].index = consumed_frames * sizeof(int16_t); + r->ffmpeg.buf[c].length = (in - consumed_frames) * sizeof(int16_t); + } else + pa_memblock_unref(b); + + /* And place the results in the output buffer */ + s = (short*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index) + c; + for (u = 0; u < used_frames; u++) { + *s = *q; + q++; + s += r->o_ss.channels; + } + pa_memblock_release(output->memblock); + pa_memblock_release(w); + pa_memblock_unref(w); + } + + *out_n_frames = used_frames; +} + +static void ffmpeg_free(pa_resampler *r) { + unsigned c; - assert(r); - assert(r->i_ss.format == r->o_ss.format); - assert(r->i_ss.channels == r->o_ss.channels); + pa_assert(r); - r->impl_data = u = pa_xnew(struct impl_trivial, 1); - u->o_counter = u->i_counter = 0; + if (r->ffmpeg.state) + av_resample_close(r->ffmpeg.state); - r->impl_run = trivial_run; - r->impl_free = trivial_free; - r->impl_update_input_rate = trivial_update_input_rate; + for (c = 0; c < PA_ELEMENTSOF(r->ffmpeg.buf); c++) + if (r->ffmpeg.buf[c].memblock) + pa_memblock_unref(r->ffmpeg.buf[c].memblock); +} + +static int ffmpeg_init(pa_resampler *r) { + unsigned c; + + pa_assert(r); + + /* We could probably implement different quality levels by + * adjusting the filter parameters here. However, ffmpeg + * internally only uses these hardcoded values, so let's use them + * here for now as well until ffmpeg makes this configurable. */ + + if (!(r->ffmpeg.state = av_resample_init(r->o_ss.rate, r->i_ss.rate, 16, 10, 0, 0.8))) + return -1; + + r->impl_free = ffmpeg_free; + r->impl_resample = ffmpeg_resample; + + for (c = 0; c < PA_ELEMENTSOF(r->ffmpeg.buf); c++) + pa_memchunk_reset(&r->ffmpeg.buf[c]); return 0; } +/*** copy (noop) implementation ***/ +static int copy_init(pa_resampler *r) { + pa_assert(r); + + pa_assert(r->o_ss.rate == r->i_ss.rate); + + r->impl_free = NULL; + r->impl_resample = NULL; + r->impl_update_rates = NULL; + + return 0; +} diff --git a/src/pulsecore/resampler.h b/src/pulsecore/resampler.h index c283593d..23e1acb7 100644 --- a/src/pulsecore/resampler.h +++ b/src/pulsecore/resampler.h @@ -24,8 +24,6 @@ USA. ***/ -#include - #include #include #include @@ -35,12 +33,19 @@ typedef struct pa_resampler pa_resampler; typedef enum pa_resample_method { PA_RESAMPLER_INVALID = -1, - PA_RESAMPLER_SRC_SINC_BEST_QUALITY = SRC_SINC_BEST_QUALITY, - PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY = SRC_SINC_MEDIUM_QUALITY, - PA_RESAMPLER_SRC_SINC_FASTEST = SRC_SINC_FASTEST, - PA_RESAMPLER_SRC_ZERO_ORDER_HOLD = SRC_ZERO_ORDER_HOLD, - PA_RESAMPLER_SRC_LINEAR = SRC_LINEAR, + PA_RESAMPLER_SRC_SINC_BEST_QUALITY = 0, /* = SRC_SINC_BEST_QUALITY */ + PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY = 1, /* = SRC_SINC_MEDIUM_QUALITY */ + PA_RESAMPLER_SRC_SINC_FASTEST = 2, /* = SRC_SINC_FASTEST */ + PA_RESAMPLER_SRC_ZERO_ORDER_HOLD = 3, /* = SRC_ZERO_ORDER_HOLD */ + PA_RESAMPLER_SRC_LINEAR = 4, /* = SRC_LINEAR */ PA_RESAMPLER_TRIVIAL, + PA_RESAMPLER_SPEEX_FLOAT_BASE, + PA_RESAMPLER_SPEEX_FLOAT_MAX = PA_RESAMPLER_SPEEX_FLOAT_BASE + 10, + PA_RESAMPLER_SPEEX_FIXED_BASE, + PA_RESAMPLER_SPEEX_FIXED_MAX = PA_RESAMPLER_SPEEX_FIXED_BASE + 10, + PA_RESAMPLER_FFMPEG, + PA_RESAMPLER_AUTO, /* automatic select based on sample format */ + PA_RESAMPLER_COPY, PA_RESAMPLER_MAX } pa_resample_method_t; @@ -50,19 +55,26 @@ pa_resampler* pa_resampler_new( const pa_channel_map *am, const pa_sample_spec *b, const pa_channel_map *bm, - pa_resample_method_t resample_method); + pa_resample_method_t resample_method, + int variable_rate); void pa_resampler_free(pa_resampler *r); /* Returns the size of an input memory block which is required to return the specified amount of output data */ size_t pa_resampler_request(pa_resampler *r, size_t out_length); +/* Returns the maximum size of input blocks we can process without needing bounce buffers larger than the mempool tile size. */ +size_t pa_resampler_max_block_size(pa_resampler *r); + /* Pass the specified memory chunk to the resampler and return the newly resampled data */ void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out); /* Change the input rate of the resampler object */ void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate); +/* Change the output rate of the resampler object */ +void pa_resampler_set_output_rate(pa_resampler *r, uint32_t rate); + /* Return the resampling method of the resampler object */ pa_resample_method_t pa_resampler_get_method(pa_resampler *r); @@ -72,4 +84,7 @@ pa_resample_method_t pa_parse_resample_method(const char *string); /* return a human readable string for the specified resampling method. Inverse of pa_parse_resample_method() */ const char *pa_resample_method_to_string(pa_resample_method_t m); +/* Return 1 when the specified resampling method is supported */ +int pa_resample_method_supported(pa_resample_method_t m); + #endif diff --git a/src/pulsecore/rtclock.c b/src/pulsecore/rtclock.c new file mode 100644 index 00000000..07d776e4 --- /dev/null +++ b/src/pulsecore/rtclock.c @@ -0,0 +1,98 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +#include "rtclock.h" + +pa_usec_t pa_rtclock_age(const struct timeval *tv) { + struct timeval now; + pa_assert(tv); + + return pa_timeval_diff(pa_rtclock_get(&now), tv); +} + +struct timeval *pa_rtclock_get(struct timeval *tv) { +#ifdef HAVE_CLOCK_GETTIME + struct timespec ts; + +#ifdef CLOCK_MONOTONIC + /* No locking or atomic ops for no_monotonic here */ + static pa_bool_t no_monotonic = FALSE; + + if (!no_monotonic) + if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) + no_monotonic = TRUE; + + if (no_monotonic) +#endif + pa_assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0); + + pa_assert(tv); + + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / 1000; + + return tv; + +#else /* HAVE_CLOCK_GETTIME */ + + return pa_gettimeofday(tv); + +#endif +} + +pa_bool_t pa_rtclock_hrtimer(void) { +#ifdef HAVE_CLOCK_GETTIME + struct timespec ts; + +#ifdef CLOCK_MONOTONIC + if (clock_getres(CLOCK_MONOTONIC, &ts) >= 0) + return ts.tv_sec == 0 && ts.tv_nsec <= PA_HRTIMER_THRESHOLD_USEC*1000; +#endif + + pa_assert_se(clock_getres(CLOCK_REALTIME, &ts) == 0); + return ts.tv_sec == 0 && ts.tv_nsec <= PA_HRTIMER_THRESHOLD_USEC*1000; + +#else /* HAVE_CLOCK_GETTIME */ + + return FALSE; + +#endif +} + +pa_usec_t pa_rtclock_usec(void) { + struct timeval tv; + + return pa_timeval_load(pa_rtclock_get(&tv)); +} diff --git a/src/pulsecore/rtclock.h b/src/pulsecore/rtclock.h new file mode 100644 index 00000000..f0360af3 --- /dev/null +++ b/src/pulsecore/rtclock.h @@ -0,0 +1,43 @@ +#ifndef foopulsertclockhfoo +#define foopulsertclockhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +struct timeval; + +/* Something like pulse/timeval.h but based on CLOCK_MONOTONIC */ + +struct timeval *pa_rtclock_get(struct timeval *ts); + +pa_usec_t pa_rtclock_usec(void); + +pa_usec_t pa_rtclock_age(const struct timeval *tv); +pa_bool_t pa_rtclock_hrtimer(void); + +/* timer with a resolution better than this are considered high-resolution */ +#define PA_HRTIMER_THRESHOLD_USEC 10 + +#endif diff --git a/src/pulsecore/rtpoll.c b/src/pulsecore/rtpoll.c new file mode 100644 index 00000000..354c4c0e --- /dev/null +++ b/src/pulsecore/rtpoll.c @@ -0,0 +1,751 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#endif + +#ifdef HAVE_POLL_H +#include +#else +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "rtpoll.h" + +struct pa_rtpoll { + struct pollfd *pollfd, *pollfd2; + unsigned n_pollfd_alloc, n_pollfd_used; + + pa_bool_t timer_enabled; + struct timeval next_elapse; + pa_usec_t period; + + pa_bool_t scan_for_dead; + pa_bool_t running, installed, rebuild_needed, quit; + +#ifdef HAVE_PPOLL + int rtsig; + sigset_t sigset_unblocked; + timer_t timer; +#ifdef __linux__ + pa_bool_t dont_use_ppoll; +#endif +#endif + + PA_LLIST_HEAD(pa_rtpoll_item, items); +}; + +struct pa_rtpoll_item { + pa_rtpoll *rtpoll; + pa_bool_t dead; + + pa_rtpoll_priority_t priority; + + struct pollfd *pollfd; + unsigned n_pollfd; + + int (*work_cb)(pa_rtpoll_item *i); + int (*before_cb)(pa_rtpoll_item *i); + void (*after_cb)(pa_rtpoll_item *i); + void *userdata; + + PA_LLIST_FIELDS(pa_rtpoll_item); +}; + +PA_STATIC_FLIST_DECLARE(items, 0, pa_xfree); + +static void signal_handler_noop(int s) { } + +pa_rtpoll *pa_rtpoll_new(void) { + pa_rtpoll *p; + + p = pa_xnew(pa_rtpoll, 1); + +#ifdef HAVE_PPOLL + +#ifdef __linux__ + /* ppoll is broken on Linux < 2.6.16 */ + p->dont_use_ppoll = FALSE; + + { + struct utsname u; + unsigned major, minor, micro; + + pa_assert_se(uname(&u) == 0); + + if (sscanf(u.release, "%u.%u.%u", &major, &minor, µ) != 3 || + (major < 2) || + (major == 2 && minor < 6) || + (major == 2 && minor == 6 && micro < 16)) + + p->dont_use_ppoll = TRUE; + } + +#endif + + p->rtsig = -1; + sigemptyset(&p->sigset_unblocked); + p->timer = (timer_t) -1; + +#endif + + p->n_pollfd_alloc = 32; + p->pollfd = pa_xnew(struct pollfd, p->n_pollfd_alloc); + p->pollfd2 = pa_xnew(struct pollfd, p->n_pollfd_alloc); + p->n_pollfd_used = 0; + + p->period = 0; + memset(&p->next_elapse, 0, sizeof(p->next_elapse)); + p->timer_enabled = FALSE; + + p->running = FALSE; + p->installed = FALSE; + p->scan_for_dead = FALSE; + p->rebuild_needed = FALSE; + p->quit = FALSE; + + PA_LLIST_HEAD_INIT(pa_rtpoll_item, p->items); + + return p; +} + +void pa_rtpoll_install(pa_rtpoll *p) { + pa_assert(p); + pa_assert(!p->installed); + + p->installed = 1; + +#ifdef HAVE_PPOLL + if (p->dont_use_ppoll) + return; + + if ((p->rtsig = pa_rtsig_get_for_thread()) < 0) { + pa_log_warn("Failed to reserve POSIX realtime signal."); + return; + } + + pa_log_debug("Acquired POSIX realtime signal %s", pa_sig2str(p->rtsig)); + + { + sigset_t ss; + struct sigaction sa; + + pa_assert_se(sigemptyset(&ss) == 0); + pa_assert_se(sigaddset(&ss, p->rtsig) == 0); + pa_assert_se(pthread_sigmask(SIG_BLOCK, &ss, &p->sigset_unblocked) == 0); + pa_assert_se(sigdelset(&p->sigset_unblocked, p->rtsig) == 0); + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = signal_handler_noop; + pa_assert_se(sigemptyset(&sa.sa_mask) == 0); + + pa_assert_se(sigaction(p->rtsig, &sa, NULL) == 0); + + /* We never reset the signal handler. Why should we? */ + } + +#endif +} + +static void rtpoll_rebuild(pa_rtpoll *p) { + + struct pollfd *e, *t; + pa_rtpoll_item *i; + int ra = 0; + + pa_assert(p); + + p->rebuild_needed = FALSE; + + if (p->n_pollfd_used > p->n_pollfd_alloc) { + /* Hmm, we have to allocate some more space */ + p->n_pollfd_alloc = p->n_pollfd_used * 2; + p->pollfd2 = pa_xrealloc(p->pollfd2, p->n_pollfd_alloc * sizeof(struct pollfd)); + ra = 1; + } + + e = p->pollfd2; + + for (i = p->items; i; i = i->next) { + + if (i->n_pollfd > 0) { + size_t l = i->n_pollfd * sizeof(struct pollfd); + + if (i->pollfd) + memcpy(e, i->pollfd, l); + else + memset(e, 0, l); + + i->pollfd = e; + } else + i->pollfd = NULL; + + e += i->n_pollfd; + } + + pa_assert((unsigned) (e - p->pollfd2) == p->n_pollfd_used); + t = p->pollfd; + p->pollfd = p->pollfd2; + p->pollfd2 = t; + + if (ra) + p->pollfd2 = pa_xrealloc(p->pollfd2, p->n_pollfd_alloc * sizeof(struct pollfd)); + +} + +static void rtpoll_item_destroy(pa_rtpoll_item *i) { + pa_rtpoll *p; + + pa_assert(i); + + p = i->rtpoll; + + PA_LLIST_REMOVE(pa_rtpoll_item, p->items, i); + + p->n_pollfd_used -= i->n_pollfd; + + if (pa_flist_push(PA_STATIC_FLIST_GET(items), i) < 0) + pa_xfree(i); + + p->rebuild_needed = TRUE; +} + +void pa_rtpoll_free(pa_rtpoll *p) { + pa_assert(p); + + while (p->items) + rtpoll_item_destroy(p->items); + + pa_xfree(p->pollfd); + pa_xfree(p->pollfd2); + +#ifdef HAVE_PPOLL + if (p->timer != (timer_t) -1) + timer_delete(p->timer); +#endif + + pa_xfree(p); +} + +static void reset_revents(pa_rtpoll_item *i) { + struct pollfd *f; + unsigned n; + + pa_assert(i); + + if (!(f = pa_rtpoll_item_get_pollfd(i, &n))) + return; + + for (; n > 0; n--) + f[n-1].revents = 0; +} + +static void reset_all_revents(pa_rtpoll *p) { + pa_rtpoll_item *i; + + pa_assert(p); + + for (i = p->items; i; i = i->next) { + + if (i->dead) + continue; + + reset_revents(i); + } +} + +int pa_rtpoll_run(pa_rtpoll *p, pa_bool_t wait) { + pa_rtpoll_item *i; + int r = 0; + struct timeval timeout; + + pa_assert(p); + pa_assert(!p->running); + pa_assert(p->installed); + + p->running = TRUE; + + /* First, let's do some work */ + for (i = p->items; i && i->priority < PA_RTPOLL_NEVER; i = i->next) { + int k; + + if (i->dead) + continue; + + if (!i->work_cb) + continue; + + if (p->quit) + goto finish; + + if ((k = i->work_cb(i)) != 0) { + if (k < 0) + r = k; + + goto finish; + } + } + + /* Now let's prepare for entering the sleep */ + for (i = p->items; i && i->priority < PA_RTPOLL_NEVER; i = i->next) { + int k = 0; + + if (i->dead) + continue; + + if (!i->before_cb) + continue; + + if (p->quit || (k = i->before_cb(i)) != 0) { + + /* Hmm, this one doesn't let us enter the poll, so rewind everything */ + + for (i = i->prev; i; i = i->prev) { + + if (i->dead) + continue; + + if (!i->after_cb) + continue; + + i->after_cb(i); + } + + if (k < 0) + r = k; + + goto finish; + } + } + + if (p->rebuild_needed) + rtpoll_rebuild(p); + + /* Calculate timeout */ + if (!wait || p->quit) { + timeout.tv_sec = 0; + timeout.tv_usec = 0; + } else if (p->timer_enabled) { + struct timeval now; + pa_rtclock_get(&now); + + memset(&timeout, 0, sizeof(timeout)); + if (pa_timeval_cmp(&p->next_elapse, &now) > 0) + pa_timeval_add(&timeout, pa_timeval_diff(&p->next_elapse, &now)); + } + + /* OK, now let's sleep */ +#ifdef HAVE_PPOLL + +#ifdef __linux__ + if (!p->dont_use_ppoll) +#endif + { + struct timespec ts; + ts.tv_sec = timeout.tv_sec; + ts.tv_nsec = timeout.tv_usec * 1000; + r = ppoll(p->pollfd, p->n_pollfd_used, p->timer_enabled ? &ts : NULL, p->rtsig < 0 ? NULL : &p->sigset_unblocked); + } +#ifdef __linux__ + else +#endif + +#endif + r = poll(p->pollfd, p->n_pollfd_used, p->timer_enabled ? (timeout.tv_sec*1000) + (timeout.tv_usec / 1000) : -1); + + if (r < 0) { + if (errno == EAGAIN || errno == EINTR) + r = 0; + else + pa_log_error("poll(): %s", pa_cstrerror(errno)); + + reset_all_revents(p); + } + + if (p->timer_enabled) { + if (p->period > 0) { + struct timeval now; + pa_rtclock_get(&now); + + pa_timeval_add(&p->next_elapse, p->period); + + /* Guarantee that the next timeout will happen in the future */ + if (pa_timeval_cmp(&p->next_elapse, &now) < 0) + pa_timeval_add(&p->next_elapse, (pa_timeval_diff(&now, &p->next_elapse) / p->period + 1) * p->period); + + } else + p->timer_enabled = FALSE; + } + + /* Let's tell everyone that we left the sleep */ + for (i = p->items; i && i->priority < PA_RTPOLL_NEVER; i = i->next) { + + if (i->dead) + continue; + + if (!i->after_cb) + continue; + + i->after_cb(i); + } + +finish: + + p->running = FALSE; + + if (p->scan_for_dead) { + pa_rtpoll_item *n; + + p->scan_for_dead = FALSE; + + for (i = p->items; i; i = n) { + n = i->next; + + if (i->dead) + rtpoll_item_destroy(i); + } + } + + return r < 0 ? r : !p->quit; +} + +static void update_timer(pa_rtpoll *p) { + pa_assert(p); + +#ifdef HAVE_PPOLL + +#ifdef __linux__ + if (!p->dont_use_ppoll) { +#endif + + if (p->timer == (timer_t) -1) { + struct sigevent se; + + memset(&se, 0, sizeof(se)); + se.sigev_notify = SIGEV_SIGNAL; + se.sigev_signo = p->rtsig; + + if (timer_create(CLOCK_MONOTONIC, &se, &p->timer) < 0) + if (timer_create(CLOCK_REALTIME, &se, &p->timer) < 0) { + pa_log_warn("Failed to allocate POSIX timer: %s", pa_cstrerror(errno)); + p->timer = (timer_t) -1; + } + } + + if (p->timer != (timer_t) -1) { + struct itimerspec its; + memset(&its, 0, sizeof(its)); + + if (p->timer_enabled) { + its.it_value.tv_sec = p->next_elapse.tv_sec; + its.it_value.tv_nsec = p->next_elapse.tv_usec*1000; + + /* Make sure that 0,0 is not understood as + * "disarming" */ + if (its.it_value.tv_sec == 0) + its.it_value.tv_nsec = 1; + + if (p->period > 0) { + struct timeval tv; + pa_timeval_store(&tv, p->period); + its.it_interval.tv_sec = tv.tv_sec; + its.it_interval.tv_nsec = tv.tv_usec*1000; + } + } + + pa_assert_se(timer_settime(p->timer, TIMER_ABSTIME, &its, NULL) == 0); + } + +#ifdef __linux__ + } +#endif + +#endif +} + +void pa_rtpoll_set_timer_absolute(pa_rtpoll *p, const struct timeval *ts) { + pa_assert(p); + pa_assert(ts); + + p->next_elapse = *ts; + p->period = 0; + p->timer_enabled = TRUE; + + update_timer(p); +} + +void pa_rtpoll_set_timer_periodic(pa_rtpoll *p, pa_usec_t usec) { + pa_assert(p); + + p->period = usec; + pa_rtclock_get(&p->next_elapse); + pa_timeval_add(&p->next_elapse, usec); + p->timer_enabled = TRUE; + + update_timer(p); +} + +void pa_rtpoll_set_timer_relative(pa_rtpoll *p, pa_usec_t usec) { + pa_assert(p); + + p->period = 0; + pa_rtclock_get(&p->next_elapse); + pa_timeval_add(&p->next_elapse, usec); + p->timer_enabled = TRUE; + + update_timer(p); +} + +void pa_rtpoll_set_timer_disabled(pa_rtpoll *p) { + pa_assert(p); + + p->period = 0; + memset(&p->next_elapse, 0, sizeof(p->next_elapse)); + p->timer_enabled = FALSE; + + update_timer(p); +} + +pa_rtpoll_item *pa_rtpoll_item_new(pa_rtpoll *p, pa_rtpoll_priority_t prio, unsigned n_fds) { + pa_rtpoll_item *i, *j, *l = NULL; + + pa_assert(p); + + if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items)))) + i = pa_xnew(pa_rtpoll_item, 1); + + i->rtpoll = p; + i->dead = FALSE; + i->n_pollfd = n_fds; + i->pollfd = NULL; + i->priority = prio; + + i->userdata = NULL; + i->before_cb = NULL; + i->after_cb = NULL; + i->work_cb = NULL; + + for (j = p->items; j; j = j->next) { + if (prio <= j->priority) + break; + + l = j; + } + + PA_LLIST_INSERT_AFTER(pa_rtpoll_item, p->items, j ? j->prev : l, i); + + if (n_fds > 0) { + p->rebuild_needed = 1; + p->n_pollfd_used += n_fds; + } + + return i; +} + +void pa_rtpoll_item_free(pa_rtpoll_item *i) { + pa_assert(i); + + if (i->rtpoll->running) { + i->dead = TRUE; + i->rtpoll->scan_for_dead = TRUE; + return; + } + + rtpoll_item_destroy(i); +} + +struct pollfd *pa_rtpoll_item_get_pollfd(pa_rtpoll_item *i, unsigned *n_fds) { + pa_assert(i); + + if (i->n_pollfd > 0) + if (i->rtpoll->rebuild_needed) + rtpoll_rebuild(i->rtpoll); + + if (n_fds) + *n_fds = i->n_pollfd; + + return i->pollfd; +} + +void pa_rtpoll_item_set_before_callback(pa_rtpoll_item *i, int (*before_cb)(pa_rtpoll_item *i)) { + pa_assert(i); + pa_assert(i->priority < PA_RTPOLL_NEVER); + + i->before_cb = before_cb; +} + +void pa_rtpoll_item_set_after_callback(pa_rtpoll_item *i, void (*after_cb)(pa_rtpoll_item *i)) { + pa_assert(i); + pa_assert(i->priority < PA_RTPOLL_NEVER); + + i->after_cb = after_cb; +} + +void pa_rtpoll_item_set_work_callback(pa_rtpoll_item *i, int (*work_cb)(pa_rtpoll_item *i)) { + pa_assert(i); + pa_assert(i->priority < PA_RTPOLL_NEVER); + + i->work_cb = work_cb; +} + +void pa_rtpoll_item_set_userdata(pa_rtpoll_item *i, void *userdata) { + pa_assert(i); + + i->userdata = userdata; +} + +void* pa_rtpoll_item_get_userdata(pa_rtpoll_item *i) { + pa_assert(i); + + return i->userdata; +} + +static int fdsem_before(pa_rtpoll_item *i) { + + if (pa_fdsem_before_poll(i->userdata) < 0) + return 1; /* 1 means immediate restart of the loop */ + + return 0; +} + +static void fdsem_after(pa_rtpoll_item *i) { + pa_assert(i); + + pa_assert((i->pollfd[0].revents & ~POLLIN) == 0); + pa_fdsem_after_poll(i->userdata); +} + +pa_rtpoll_item *pa_rtpoll_item_new_fdsem(pa_rtpoll *p, pa_rtpoll_priority_t prio, pa_fdsem *f) { + pa_rtpoll_item *i; + struct pollfd *pollfd; + + pa_assert(p); + pa_assert(f); + + i = pa_rtpoll_item_new(p, prio, 1); + + pollfd = pa_rtpoll_item_get_pollfd(i, NULL); + + pollfd->fd = pa_fdsem_get(f); + pollfd->events = POLLIN; + + i->before_cb = fdsem_before; + i->after_cb = fdsem_after; + i->userdata = f; + + return i; +} + +static int asyncmsgq_before(pa_rtpoll_item *i) { + pa_assert(i); + + if (pa_asyncmsgq_before_poll(i->userdata) < 0) + return 1; /* 1 means immediate restart of the loop */ + + return 0; +} + +static void asyncmsgq_after(pa_rtpoll_item *i) { + pa_assert(i); + + pa_assert((i->pollfd[0].revents & ~POLLIN) == 0); + pa_asyncmsgq_after_poll(i->userdata); +} + +static int asyncmsgq_work(pa_rtpoll_item *i) { + pa_msgobject *object; + int code; + void *data; + pa_memchunk chunk; + int64_t offset; + + pa_assert(i); + + if (pa_asyncmsgq_get(i->userdata, &object, &code, &data, &offset, &chunk, 0) == 0) { + int ret; + + if (!object && code == PA_MESSAGE_SHUTDOWN) { + pa_asyncmsgq_done(i->userdata, 0); + pa_rtpoll_quit(i->rtpoll); + return 1; + } + + ret = pa_asyncmsgq_dispatch(object, code, data, offset, &chunk); + pa_asyncmsgq_done(i->userdata, ret); + return 1; + } + + return 0; +} + +pa_rtpoll_item *pa_rtpoll_item_new_asyncmsgq(pa_rtpoll *p, pa_rtpoll_priority_t prio, pa_asyncmsgq *q) { + pa_rtpoll_item *i; + struct pollfd *pollfd; + + pa_assert(p); + pa_assert(q); + + i = pa_rtpoll_item_new(p, prio, 1); + + pollfd = pa_rtpoll_item_get_pollfd(i, NULL); + pollfd->fd = pa_asyncmsgq_get_fd(q); + pollfd->events = POLLIN; + + i->before_cb = asyncmsgq_before; + i->after_cb = asyncmsgq_after; + i->work_cb = asyncmsgq_work; + i->userdata = q; + + return i; +} + +void pa_rtpoll_quit(pa_rtpoll *p) { + pa_assert(p); + + p->quit = TRUE; +} diff --git a/src/pulsecore/rtpoll.h b/src/pulsecore/rtpoll.h new file mode 100644 index 00000000..02f5c7c2 --- /dev/null +++ b/src/pulsecore/rtpoll.h @@ -0,0 +1,116 @@ +#ifndef foopulsertpollhfoo +#define foopulsertpollhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include +#include +#include +#include + +/* An implementation of a "real-time" poll loop. Basically, this is + * yet another wrapper around poll(). However it has certain + * advantages over pa_mainloop and suchlike: + * + * 1) It uses timer_create() and POSIX real time signals to guarantee + * optimal high-resolution timing. Starting with Linux 2.6.21 hrtimers + * are available, and since right now only nanosleep() and the POSIX + * clock and timer interfaces have been ported to hrtimers (and not + * ppoll/pselect!) we have to combine ppoll() with timer_create(). The + * fact that POSIX timers and POSIX rt signals are used internally is + * completely hidden. + * + * 2) It allows raw access to the pollfd data to users + * + * 3) It allows arbitrary functions to be run before entering the + * actual poll() and after it. + * + * Only a single interval timer is supported..*/ + +typedef struct pa_rtpoll pa_rtpoll; +typedef struct pa_rtpoll_item pa_rtpoll_item; + +typedef enum pa_rtpoll_priority { + PA_RTPOLL_EARLY = -100, /* For veeery important stuff, like handling control messages */ + PA_RTPOLL_NORMAL = 0, /* For normal stuff */ + PA_RTPOLL_LATE = +100, /* For housekeeping */ + PA_RTPOLL_NEVER = INT_MAX, /* For stuff that doesn't register any callbacks, but only fds to listen on */ +} pa_rtpoll_priority_t; + +pa_rtpoll *pa_rtpoll_new(void); +void pa_rtpoll_free(pa_rtpoll *p); + +/* Install the rtpoll in the current thread */ +void pa_rtpoll_install(pa_rtpoll *p); + +/* Sleep on the rtpoll until the time event, or any of the fd events + * is triggered. If "wait" is 0 we don't sleep but only update the + * struct pollfd. Returns negative on error, positive if the loop + * should continue to run, 0 when the loop should be terminated + * cleanly. */ +int pa_rtpoll_run(pa_rtpoll *f, pa_bool_t wait); + +void pa_rtpoll_set_timer_absolute(pa_rtpoll *p, const struct timeval *ts); +void pa_rtpoll_set_timer_periodic(pa_rtpoll *p, pa_usec_t usec); +void pa_rtpoll_set_timer_relative(pa_rtpoll *p, pa_usec_t usec); +void pa_rtpoll_set_timer_disabled(pa_rtpoll *p); + +/* A new fd wakeup item for pa_rtpoll */ +pa_rtpoll_item *pa_rtpoll_item_new(pa_rtpoll *p, pa_rtpoll_priority_t prio, unsigned n_fds); +void pa_rtpoll_item_free(pa_rtpoll_item *i); + +/* Please note that this pointer might change on every call and when + * pa_rtpoll_run() is called. Hence: call this immediately before + * using the pointer and don't save the result anywhere */ +struct pollfd *pa_rtpoll_item_get_pollfd(pa_rtpoll_item *i, unsigned *n_fds); + +/* Set the callback that shall be called when there's time to do some work: If the + * callback returns a value > 0, the poll is skipped and the next + * iteraton of the loop will start immediately. */ +void pa_rtpoll_item_set_work_callback(pa_rtpoll_item *i, int (*work_cb)(pa_rtpoll_item *i)); + +/* Set the callback that shall be called immediately before entering + * the sleeping poll: If the callback returns a value > 0, the poll is + * skipped and the next iteraton of the loop will start + * immediately.. */ +void pa_rtpoll_item_set_before_callback(pa_rtpoll_item *i, int (*before_cb)(pa_rtpoll_item *i)); + +/* Set the callback that shall be called immediately after having + * entered the sleeping poll */ +void pa_rtpoll_item_set_after_callback(pa_rtpoll_item *i, void (*after_cb)(pa_rtpoll_item *i)); + +void pa_rtpoll_item_set_userdata(pa_rtpoll_item *i, void *userdata); +void* pa_rtpoll_item_get_userdata(pa_rtpoll_item *i); + +pa_rtpoll_item *pa_rtpoll_item_new_fdsem(pa_rtpoll *p, pa_rtpoll_priority_t prio, pa_fdsem *s); +pa_rtpoll_item *pa_rtpoll_item_new_asyncmsgq(pa_rtpoll *p, pa_rtpoll_priority_t prio, pa_asyncmsgq *q); + +/* Requests the loop to exit. Will cause the next iteration of + * pa_rtpoll_run() to return 0 */ +void pa_rtpoll_quit(pa_rtpoll *p); + +#endif diff --git a/src/pulsecore/rtsig.c b/src/pulsecore/rtsig.c new file mode 100644 index 00000000..bfc49c88 --- /dev/null +++ b/src/pulsecore/rtsig.c @@ -0,0 +1,133 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include +#include + +#include "rtsig.h" + +#ifdef SIGRTMIN + +static void _free_rtsig(void *p) { + pa_rtsig_put(PA_PTR_TO_INT(p)); +} + +PA_STATIC_FLIST_DECLARE(rtsig_flist, pa_make_power_of_two(SIGRTMAX-SIGRTMIN+1), NULL); +PA_STATIC_TLS_DECLARE(rtsig_tls, _free_rtsig); + +static pa_atomic_t rtsig_current = PA_ATOMIC_INIT(-1); + +static int rtsig_start = -1, rtsig_end = -1; + +int pa_rtsig_get(void) { + void *p; + int sig; + + if ((p = pa_flist_pop(PA_STATIC_FLIST_GET(rtsig_flist)))) + return PA_PTR_TO_INT(p); + + sig = pa_atomic_dec(&rtsig_current); + + pa_assert(sig <= SIGRTMAX); + pa_assert(sig <= rtsig_end); + + if (sig < rtsig_start) { + pa_atomic_inc(&rtsig_current); + return -1; + } + + return sig; +} + +int pa_rtsig_get_for_thread(void) { + int sig; + void *p; + + if ((p = PA_STATIC_TLS_GET(rtsig_tls))) + return PA_PTR_TO_INT(p); + + if ((sig = pa_rtsig_get()) < 0) + return -1; + + PA_STATIC_TLS_SET(rtsig_tls, PA_INT_TO_PTR(sig)); + return sig; +} + +void pa_rtsig_put(int sig) { + pa_assert(sig >= rtsig_start); + pa_assert(sig <= rtsig_end); + + pa_assert_se(pa_flist_push(PA_STATIC_FLIST_GET(rtsig_flist), PA_INT_TO_PTR(sig)) >= 0); +} + +void pa_rtsig_configure(int start, int end) { + int s; + sigset_t ss; + + pa_assert(pa_atomic_load(&rtsig_current) == -1); + + pa_assert(SIGRTMIN <= start); + pa_assert(start <= end); + pa_assert(end <= SIGRTMAX); + + rtsig_start = start; + rtsig_end = end; + + sigemptyset(&ss); + + for (s = rtsig_start; s <= rtsig_end; s++) + pa_assert_se(sigaddset(&ss, s) == 0); + + pa_assert(pthread_sigmask(SIG_BLOCK, &ss, NULL) == 0); + + /* We allocate starting from the end */ + pa_atomic_store(&rtsig_current, rtsig_end); +} + +#else /* SIGRTMIN */ + +int pa_rtsig_get(void) { + return -1; +} + +int pa_rtsig_get_for_thread(void) { + return -1; +} + +void pa_rtsig_put(int sig) { +} + +void pa_rtsig_configure(int start, int end) { +} + +#endif /* SIGRTMIN */ diff --git a/src/pulsecore/rtsig.h b/src/pulsecore/rtsig.h new file mode 100644 index 00000000..7830d272 --- /dev/null +++ b/src/pulsecore/rtsig.h @@ -0,0 +1,41 @@ +#ifndef foopulsertsighfoo +#define foopulsertsighfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* Return the next unused POSIX Realtime signals */ +int pa_rtsig_get(void); + +/* If not called before in the current thread, return the next unused + * rtsig, and install it in a TLS region and give it up automatically + * when the thread shuts down */ +int pa_rtsig_get_for_thread(void); + +/* Give an rtsig back. */ +void pa_rtsig_put(int sig); + +/* Block all RT signals */ +void pa_rtsig_configure(int start, int end); + +#endif diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index a9971408..21771302 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -28,53 +28,71 @@ #include #include -#include #include #include +#include #include +#include #include "sample-util.h" #include "endianmacros.h" -#define PA_SILENCE_MAX (1024*1024*1) +#define PA_SILENCE_MAX (PA_PAGE_SIZE*16) pa_memblock *pa_silence_memblock_new(pa_mempool *pool, const pa_sample_spec *spec, size_t length) { size_t fs; - assert(pool); - assert(spec); + pa_assert(pool); + pa_assert(spec); - if (length == 0) + if (length <= 0) length = pa_bytes_per_second(spec)/20; /* 50 ms */ if (length > PA_SILENCE_MAX) length = PA_SILENCE_MAX; fs = pa_frame_size(spec); - length = ((PA_SILENCE_MAX+fs-1) / fs) * fs; + + length = (length+fs-1)/fs; if (length <= 0) - length = fs; + length = 1; + + length *= fs; return pa_silence_memblock(pa_memblock_new(pool, length), spec); } pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) { - assert(b && b->data && spec); - pa_silence_memory(b->data, b->length, spec); + void *data; + + pa_assert(b); + pa_assert(spec); + + data = pa_memblock_acquire(b); + pa_silence_memory(data, pa_memblock_get_length(b), spec); + pa_memblock_release(b); return b; } void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) { - assert(c && c->memblock && c->memblock->data && spec && c->length); + void *data; - pa_silence_memory((uint8_t*) c->memblock->data+c->index, c->length, spec); + pa_assert(c); + pa_assert(c->memblock); + pa_assert(spec); + + data = pa_memblock_acquire(c->memblock); + pa_silence_memory((uint8_t*) data+c->index, c->length, spec); + pa_memblock_release(c->memblock); } void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { uint8_t c = 0; - assert(p && length && spec); + pa_assert(p); + pa_assert(length > 0); + pa_assert(spec); switch (spec->format) { case PA_SAMPLE_U8: @@ -87,37 +105,51 @@ void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { c = 0; break; case PA_SAMPLE_ALAW: + c = 0xd5; + break; case PA_SAMPLE_ULAW: - c = 80; + c = 0xff; break; default: - assert(0); + pa_assert_not_reached(); } memset(p, c, length); } size_t pa_mix( - const pa_mix_info streams[], - unsigned nstreams, - void *data, - size_t length, - const pa_sample_spec *spec, - const pa_cvolume *volume, - int mute) { + pa_mix_info streams[], + unsigned nstreams, + void *data, + size_t length, + const pa_sample_spec *spec, + const pa_cvolume *volume, + int mute) { + + pa_cvolume full_volume; + size_t d = 0; + unsigned k; + + pa_assert(streams); + pa_assert(data); + pa_assert(length); + pa_assert(spec); - assert(streams && data && length && spec); + if (!volume) + volume = pa_cvolume_reset(&full_volume, spec->channels); + + for (k = 0; k < nstreams; k++) + streams[k].internal = pa_memblock_acquire(streams[k].chunk.memblock); switch (spec->format) { case PA_SAMPLE_S16NE:{ - size_t d; unsigned channel = 0; for (d = 0;; d += sizeof(int16_t)) { int32_t sum = 0; if (d >= length) - return d; + goto finish; if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { unsigned i; @@ -127,12 +159,12 @@ size_t pa_mix( pa_volume_t cvolume = streams[i].volume.values[channel]; if (d >= streams[i].chunk.length) - return d; + goto finish; if (cvolume == PA_VOLUME_MUTED) v = 0; else { - v = *((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); + v = *((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d)); if (cvolume != PA_VOLUME_NORM) v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); @@ -144,28 +176,27 @@ size_t pa_mix( if (volume->values[channel] != PA_VOLUME_NORM) sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); - if (sum < -0x8000) sum = -0x8000; - if (sum > 0x7FFF) sum = 0x7FFF; - + sum = CLAMP(sum, -0x8000, 0x7FFF); } - *((int16_t*) data) = sum; + *((int16_t*) data) = (int16_t) sum; data = (uint8_t*) data + sizeof(int16_t); if (++channel >= spec->channels) channel = 0; } + + break; } case PA_SAMPLE_S16RE:{ - size_t d; unsigned channel = 0; for (d = 0;; d += sizeof(int16_t)) { int32_t sum = 0; if (d >= length) - return d; + goto finish; if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { unsigned i; @@ -175,12 +206,12 @@ size_t pa_mix( pa_volume_t cvolume = streams[i].volume.values[channel]; if (d >= streams[i].chunk.length) - return d; + goto finish; if (cvolume == PA_VOLUME_MUTED) v = 0; else { - v = INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d))); + v = PA_INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d))); if (cvolume != PA_VOLUME_NORM) v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); @@ -192,28 +223,27 @@ size_t pa_mix( if (volume->values[channel] != PA_VOLUME_NORM) sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); - if (sum < -0x8000) sum = -0x8000; - if (sum > 0x7FFF) sum = 0x7FFF; - + sum = CLAMP(sum, -0x8000, 0x7FFF); } - *((int16_t*) data) = INT16_SWAP(sum); + *((int16_t*) data) = PA_INT16_SWAP((int16_t) sum); data = (uint8_t*) data + sizeof(int16_t); if (++channel >= spec->channels) channel = 0; } + + break; } case PA_SAMPLE_U8: { - size_t d; unsigned channel = 0; for (d = 0;; d ++) { int32_t sum = 0; if (d >= length) - return d; + goto finish; if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { unsigned i; @@ -223,12 +253,12 @@ size_t pa_mix( pa_volume_t cvolume = streams[i].volume.values[channel]; if (d >= streams[i].chunk.length) - return d; + goto finish; if (cvolume == PA_VOLUME_MUTED) v = 0; else { - v = (int32_t) *((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d) - 0x80; + v = (int32_t) *((uint8_t*) streams[i].internal + streams[i].chunk.index + d) - 0x80; if (cvolume != PA_VOLUME_NORM) v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); @@ -240,9 +270,7 @@ size_t pa_mix( if (volume->values[channel] != PA_VOLUME_NORM) sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); - if (sum < -0x80) sum = -0x80; - if (sum > 0x7F) sum = 0x7F; - + sum = CLAMP(sum, -0x80, 0x7F); } *((uint8_t*) data) = (uint8_t) (sum + 0x80); @@ -251,17 +279,18 @@ size_t pa_mix( if (++channel >= spec->channels) channel = 0; } + + break; } case PA_SAMPLE_FLOAT32NE: { - size_t d; unsigned channel = 0; for (d = 0;; d += sizeof(float)) { float sum = 0; if (d >= length) - return d; + goto finish; if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { unsigned i; @@ -271,12 +300,12 @@ size_t pa_mix( pa_volume_t cvolume = streams[i].volume.values[channel]; if (d >= streams[i].chunk.length) - return d; + goto finish; if (cvolume == PA_VOLUME_MUTED) v = 0; else { - v = *((float*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); + v = *((float*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d)); if (cvolume != PA_VOLUME_NORM) v *= pa_sw_volume_to_linear(cvolume); @@ -295,18 +324,35 @@ size_t pa_mix( if (++channel >= spec->channels) channel = 0; } + + break; } default: pa_log_error("ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format)); abort(); } + +finish: + + for (k = 0; k < nstreams; k++) + pa_memblock_release(streams[k].chunk.memblock); + + return d; } -void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvolume *volume) { - assert(c && spec && (c->length % pa_frame_size(spec) == 0)); - assert(volume); +void pa_volume_memchunk( + pa_memchunk*c, + const pa_sample_spec *spec, + const pa_cvolume *volume) { + + void *ptr; + + pa_assert(c); + pa_assert(spec); + pa_assert(c->length % pa_frame_size(spec) == 0); + pa_assert(volume); if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM)) return; @@ -316,24 +362,25 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol return; } + ptr = pa_memblock_acquire(c->memblock); + switch (spec->format) { + case PA_SAMPLE_S16NE: { int16_t *d; size_t n; unsigned channel; - double linear[PA_CHANNELS_MAX]; + int32_t linear[PA_CHANNELS_MAX]; for (channel = 0; channel < spec->channels; channel++) - linear[channel] = pa_sw_volume_to_linear(volume->values[channel]); - - for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { - int32_t t = (int32_t)(*d); + linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000); - t = (int32_t) (t * linear[channel]); - - if (t < -0x8000) t = -0x8000; - if (t > 0x7FFF) t = 0x7FFF; + for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { + int32_t t; + t = (int32_t)(*d); + t = (t * linear[channel]) / 0x10000; + t = CLAMP(t, -0x8000, 0x7FFF); *d = (int16_t) t; if (++channel >= spec->channels) @@ -346,20 +393,18 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol int16_t *d; size_t n; unsigned channel; - double linear[PA_CHANNELS_MAX]; + int32_t linear[PA_CHANNELS_MAX]; for (channel = 0; channel < spec->channels; channel++) - linear[channel] = pa_sw_volume_to_linear(volume->values[channel]); - - for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { - int32_t t = (int32_t)(INT16_SWAP(*d)); + linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000); - t = (int32_t) (t * linear[channel]); + for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { + int32_t t; - if (t < -0x8000) t = -0x8000; - if (t > 0x7FFF) t = 0x7FFF; - - *d = INT16_SWAP((int16_t) t); + t = (int32_t)(PA_INT16_SWAP(*d)); + t = (t * linear[channel]) / 0x10000; + t = CLAMP(t, -0x8000, 0x7FFF); + *d = PA_INT16_SWAP((int16_t) t); if (++channel >= spec->channels) channel = 0; @@ -371,16 +416,18 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol case PA_SAMPLE_U8: { uint8_t *d; size_t n; - unsigned channel = 0; - - for (d = (uint8_t*) c->memblock->data + c->index, n = c->length; n > 0; d++, n--) { - int32_t t = (int32_t) *d - 0x80; + unsigned channel; + int32_t linear[PA_CHANNELS_MAX]; - t = (int32_t) (t * pa_sw_volume_to_linear(volume->values[channel])); + for (channel = 0; channel < spec->channels; channel++) + linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000); - if (t < -0x80) t = -0x80; - if (t > 0x7F) t = 0x7F; + for (channel = 0, d = (uint8_t*) ptr + c->index, n = c->length; n > 0; d++, n--) { + int32_t t; + t = (int32_t) *d - 0x80; + t = (t * linear[channel]) / 0x10000; + t = CLAMP(t, -0x80, 0x7F); *d = (uint8_t) (t + 0x80); if (++channel >= spec->channels) @@ -395,7 +442,7 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol unsigned n; unsigned channel; - d = (float*) ((uint8_t*) c->memblock->data + c->index); + d = (float*) ((uint8_t*) ptr + c->index); skip = spec->channels * sizeof(float); n = c->length/sizeof(float)/spec->channels; @@ -406,7 +453,6 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol continue; v = (float) pa_sw_volume_to_linear(volume->values[channel]); - t = d + channel; oil_scalarmult_f32(t, skip, t, skip, &v, n); } @@ -414,9 +460,85 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol } default: - pa_log_error("ERROR: Unable to change volume of format %s.", - pa_sample_format_to_string(spec->format)); - abort(); + pa_log_warn(" Unable to change volume of format %s.", pa_sample_format_to_string(spec->format)); + /* If we cannot change the volume, we just don't do it */ } + + pa_memblock_release(c->memblock); +} + +size_t pa_frame_align(size_t l, const pa_sample_spec *ss) { + size_t fs; + + pa_assert(ss); + + fs = pa_frame_size(ss); + + return (l/fs) * fs; } +int pa_frame_aligned(size_t l, const pa_sample_spec *ss) { + size_t fs; + + pa_assert(ss); + + fs = pa_frame_size(ss); + + return l % fs == 0; +} + +void pa_interleave(const void *src[], unsigned channels, void *dst, size_t ss, unsigned n) { + unsigned c; + size_t fs; + + pa_assert(src); + pa_assert(channels > 0); + pa_assert(dst); + pa_assert(ss > 0); + pa_assert(n > 0); + + fs = ss * channels; + + for (c = 0; c < channels; c++) { + unsigned j; + void *d; + const void *s; + + s = src[c]; + d = (uint8_t*) dst + c * ss; + + for (j = 0; j < n; j ++) { + oil_memcpy(d, s, ss); + s = (uint8_t*) s + ss; + d = (uint8_t*) d + fs; + } + } +} + +void pa_deinterleave(const void *src, void *dst[], unsigned channels, size_t ss, unsigned n) { + size_t fs; + unsigned c; + + pa_assert(src); + pa_assert(dst); + pa_assert(channels > 0); + pa_assert(ss > 0); + pa_assert(n > 0); + + fs = ss * channels; + + for (c = 0; c < channels; c++) { + unsigned j; + const void *s; + void *d; + + s = (uint8_t*) src + c * ss; + d = dst[c]; + + for (j = 0; j < n; j ++) { + oil_memcpy(d, s, ss); + s = (uint8_t*) s + fs; + d = (uint8_t*) d + ss; + } + } +} diff --git a/src/pulsecore/sample-util.h b/src/pulsecore/sample-util.h index 3ff065ab..0a39d5ca 100644 --- a/src/pulsecore/sample-util.h +++ b/src/pulsecore/sample-util.h @@ -39,10 +39,11 @@ typedef struct pa_mix_info { pa_memchunk chunk; pa_cvolume volume; void *userdata; + void *internal; /* Used internally by pa_mix(), should not be initialised when calling pa_mix() */ } pa_mix_info; size_t pa_mix( - const pa_mix_info channels[], + pa_mix_info channels[], unsigned nchannels, void *data, size_t length, @@ -55,4 +56,11 @@ void pa_volume_memchunk( const pa_sample_spec *spec, const pa_cvolume *volume); +size_t pa_frame_align(size_t l, const pa_sample_spec *ss) PA_GCC_PURE; + +int pa_frame_aligned(size_t l, const pa_sample_spec *ss) PA_GCC_PURE; + +void pa_interleave(const void *src[], unsigned channels, void *dst, size_t ss, unsigned n); +void pa_deinterleave(const void *src, void *dst[], unsigned channels, size_t ss, unsigned n); + #endif diff --git a/src/pulsecore/sconv-s16be.c b/src/pulsecore/sconv-s16be.c index c530e79b..f74d0282 100644 --- a/src/pulsecore/sconv-s16be.c +++ b/src/pulsecore/sconv-s16be.c @@ -27,12 +27,15 @@ #include "endianmacros.h" -#define INT16_FROM INT16_FROM_BE -#define INT16_TO INT16_TO_BE +#define INT16_FROM PA_INT16_FROM_BE +#define INT16_TO PA_INT16_TO_BE #define pa_sconv_s16le_to_float32ne pa_sconv_s16be_to_float32ne #define pa_sconv_s16le_from_float32ne pa_sconv_s16be_from_float32ne +#define pa_sconv_s16le_to_float32re pa_sconv_s16be_to_float32re +#define pa_sconv_s16le_from_float32re pa_sconv_s16be_from_float32re + #ifdef WORDS_BIGENDIAN #define SWAP_WORDS 0 #else diff --git a/src/pulsecore/sconv-s16be.h b/src/pulsecore/sconv-s16be.h index 6b736f69..ad034489 100644 --- a/src/pulsecore/sconv-s16be.h +++ b/src/pulsecore/sconv-s16be.h @@ -24,7 +24,18 @@ USA. ***/ -void pa_sconv_s16be_to_float32ne(unsigned n, const void *a, float *b); -void pa_sconv_s16be_from_float32ne(unsigned n, const float *a, void *b); +#include + +void pa_sconv_s16be_to_float32ne(unsigned n, const int16_t *a, float *b); +void pa_sconv_s16be_from_float32ne(unsigned n, const float *a, int16_t *b); +void pa_sconv_s16be_to_float32re(unsigned n, const int16_t *a, float *b); +void pa_sconv_s16be_from_float32re(unsigned n, const float *a, int16_t *b); + +#ifdef WORDS_BIGENDIAN +#define pa_sconv_float32be_to_s16ne pa_sconv_s16be_from_float32ne +#define pa_sconv_float32be_from_s16ne pa_sconv_s16be_to_float32ne +#define pa_sconv_float32le_to_s16ne pa_sconv_s16be_from_float32re +#define pa_sconv_float32le_from_s16ne pa_sconv_s16be_to_float32re +#endif #endif diff --git a/src/pulsecore/sconv-s16le.c b/src/pulsecore/sconv-s16le.c index 5f45ef66..6925052c 100644 --- a/src/pulsecore/sconv-s16le.c +++ b/src/pulsecore/sconv-s16le.c @@ -25,12 +25,12 @@ #include #endif -#include #include #include #include +#include #include #include "endianmacros.h" @@ -38,11 +38,11 @@ #include "sconv-s16le.h" #ifndef INT16_FROM -#define INT16_FROM INT16_FROM_LE +#define INT16_FROM PA_INT16_FROM_LE #endif #ifndef INT16_TO -#define INT16_TO INT16_TO_LE +#define INT16_TO PA_INT16_TO_LE #endif #ifndef SWAP_WORDS @@ -53,32 +53,28 @@ #endif #endif -void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b) { - const int16_t *ca = a; - - assert(a); - assert(b); +void pa_sconv_s16le_to_float32ne(unsigned n, const int16_t *a, float *b) { + pa_assert(a); + pa_assert(b); #if SWAP_WORDS == 1 for (; n > 0; n--) { - int16_t s = *(ca++); + int16_t s = *(a++); *(b++) = ((float) INT16_FROM(s))/0x7FFF; } #else { static const double add = 0, factor = 1.0/0x7FFF; - oil_scaleconv_f32_s16(b, ca, n, &add, &factor); + oil_scaleconv_f32_s16(b, a, n, &add, &factor); } #endif } -void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b) { - int16_t *cb = b; - - assert(a); - assert(b); +void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, int16_t *b) { + pa_assert(a); + pa_assert(b); #if SWAP_WORDS == 1 @@ -86,20 +82,43 @@ void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b) { int16_t s; float v = *(a++); - if (v > 1) - v = 1; - - if (v < -1) - v = -1; - + v = CLAMP(v, -1, 1); s = (int16_t) (v * 0x7FFF); - *(cb++) = INT16_TO(s); + *(b++) = INT16_TO(s); } #else { static const double add = 0, factor = 0x7FFF; - oil_scaleconv_s16_f32(cb, a, n, &add, &factor); + oil_scaleconv_s16_f32(b, a, n, &add, &factor); } #endif } + +void pa_sconv_s16le_to_float32re(unsigned n, const int16_t *a, float *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--) { + int16_t s = *(a++); + float k = ((float) INT16_FROM(s))/0x7FFF; + uint32_t *j = (uint32_t*) &k; + *j = PA_UINT32_SWAP(*j); + *(b++) = k; + } +} + +void pa_sconv_s16le_from_float32re(unsigned n, const float *a, int16_t *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--) { + int16_t s; + float v = *(a++); + uint32_t *j = (uint32_t*) &v; + *j = PA_UINT32_SWAP(*j); + v = CLAMP(v, -1, 1); + s = (int16_t) (v * 0x7FFF); + *(b++) = INT16_TO(s); + } +} diff --git a/src/pulsecore/sconv-s16le.h b/src/pulsecore/sconv-s16le.h index c4e4911a..4203315a 100644 --- a/src/pulsecore/sconv-s16le.h +++ b/src/pulsecore/sconv-s16le.h @@ -24,7 +24,18 @@ USA. ***/ -void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b); -void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b); +#include + +void pa_sconv_s16le_to_float32ne(unsigned n, const int16_t *a, float *b); +void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, int16_t *b); +void pa_sconv_s16le_to_float32re(unsigned n, const int16_t *a, float *b); +void pa_sconv_s16le_from_float32re(unsigned n, const float *a, int16_t *b); + +#ifndef WORDS_BIGENDIAN +#define pa_sconv_float32be_to_s16ne pa_sconv_s16le_from_float32re +#define pa_sconv_float32be_from_s16ne pa_sconv_s16le_to_float32re +#define pa_sconv_float32le_to_s16ne pa_sconv_s16le_from_float32ne +#define pa_sconv_float32le_from_s16ne pa_sconv_s16le_to_float32ne +#endif #endif diff --git a/src/pulsecore/sconv.c b/src/pulsecore/sconv.c index d15cec84..7f5da63f 100644 --- a/src/pulsecore/sconv.c +++ b/src/pulsecore/sconv.c @@ -28,12 +28,12 @@ #include #include -#include #include #include #include +#include #include "endianmacros.h" #include "sconv-s16le.h" @@ -41,152 +41,223 @@ #include "sconv.h" -static void u8_to_float32ne(unsigned n, const void *a, float *b) { - const uint8_t *ca = a; - static const double add = -128.0/127.0, factor = 1.0/127.0; +/* u8 */ +static void u8_to_float32ne(unsigned n, const uint8_t *a, float *b) { + static const double add = -1, factor = 1.0/128.0; - assert(a); - assert(b); + pa_assert(a); + pa_assert(b); - oil_scaleconv_f32_u8(b, ca, n, &add, &factor); + oil_scaleconv_f32_u8(b, a, n, &add, &factor); } -static void u8_from_float32ne(unsigned n, const float *a, void *b) { - uint8_t *cb = b; - static const double add = 128.0, factor = 127.0; +static void u8_from_float32ne(unsigned n, const float *a, uint8_t *b) { + static const double add = 128, factor = 127.0; - assert(a); - assert(b); + pa_assert(a); + pa_assert(b); - oil_scaleconv_u8_f32(cb, a, n, &add, &factor); + oil_scaleconv_u8_f32(b, a, n, &add, &factor); } -static void float32ne_to_float32ne(unsigned n, const void *a, float *b) { - assert(a); - assert(b); +static void u8_to_s16ne(unsigned n, const uint8_t *a, int16_t *b) { + static const int16_t add = -0x80, factor = 0x100; - oil_memcpy(b, a, sizeof(float) * n); + pa_assert(a); + pa_assert(b); + + oil_conv_s16_u8(b, 2, a, 1, n); + oil_scalaradd_s16(b, 2, b, 2, &add, n); + oil_scalarmult_s16(b, 2, b, 2, &factor, n); +} + +static void u8_from_s16ne(unsigned n, const int16_t *a, uint8_t *b) { + + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--, a++, b++) + *b = (uint8_t) (*a / 0x100 + 0x80); } -static void float32ne_from_float32ne(unsigned n, const float *a, void *b) { - assert(a); - assert(b); +/* float32 */ + +static void float32ne_to_float32ne(unsigned n, const float *a, float *b) { + pa_assert(a); + pa_assert(b); oil_memcpy(b, a, sizeof(float) * n); } -static void float32re_to_float32ne(unsigned n, const void *a, float *b) { - assert(a); - assert(b); +static void float32re_to_float32ne(unsigned n, const float *a, float *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--, a++, b++) + *((uint32_t *) b) = PA_UINT32_SWAP(*((uint32_t *) a)); +} + +/* s16 */ - while (n-- > 0) - ((uint32_t *)b)[n] = UINT32_SWAP (((uint32_t *)a)[n]); +static void s16ne_to_s16ne(unsigned n, const int16_t *a, int16_t *b) { + pa_assert(a); + pa_assert(b); + + oil_memcpy(b, a, sizeof(int16_t) * n); } -static void float32re_from_float32ne(unsigned n, const float *a, void *b) { - assert(a); - assert(b); +static void s16re_to_s16ne(unsigned n, const int16_t *a, int16_t *b) { + pa_assert(a); + pa_assert(b); - while (n-- > 0) - ((uint32_t *)b)[n] = UINT32_SWAP (((uint32_t *)a)[n]); + for (; n > 0; n--, a++, b++) + *b = PA_UINT16_SWAP(*a); } -static void ulaw_to_float32ne(unsigned n, const void *a, float *b) { - const uint8_t *ca = a; +/* ulaw */ - assert(a); - assert(b); +static void ulaw_to_float32ne(unsigned n, const uint8_t *a, float *b) { + pa_assert(a); + pa_assert(b); for (; n > 0; n--) - *(b++) = st_ulaw2linear16(*(ca++)) * 1.0F / 0x7FFF; + *(b++) = (float) st_ulaw2linear16(*(a++)) / 0x8000; } -static void ulaw_from_float32ne(unsigned n, const float *a, void *b) { - uint8_t *cb = b; - - assert(a); - assert(b); +static void ulaw_from_float32ne(unsigned n, const float *a, uint8_t *b) { + pa_assert(a); + pa_assert(b); for (; n > 0; n--) { float v = *(a++); + v = CLAMP(v, -1, 1); + v *= 0x1FFF; + *(b++) = st_14linear2ulaw((int16_t) v); + } +} + +static void ulaw_to_s16ne(unsigned n, const uint8_t *a, int16_t *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--, a++, b++) + *b = st_ulaw2linear16(*a); +} + +static void ulaw_from_s16ne(unsigned n, const int16_t *a, uint8_t *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--, a++, b++) + *b = st_14linear2ulaw(*a >> 2); +} - if (v > 1) - v = 1; +/* alaw */ - if (v < -1) - v = -1; +static void alaw_to_float32ne(unsigned n, const uint8_t *a, float *b) { + pa_assert(a); + pa_assert(b); - *(cb++) = st_14linear2ulaw((int16_t) (v * 0x1FFF)); + for (; n > 0; n--, a++, b++) + *b = (float) st_alaw2linear16(*a) / 0x8000; +} + +static void alaw_from_float32ne(unsigned n, const float *a, uint8_t *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--, a++, b++) { + float v = *a; + v = CLAMP(v, -1, 1); + v *= 0xFFF; + *b = st_13linear2alaw((int16_t) v); } } -static void alaw_to_float32ne(unsigned n, const void *a, float *b) { - const uint8_t *ca = a; +static void alaw_to_s16ne(unsigned n, const int8_t *a, int16_t *b) { + pa_assert(a); + pa_assert(b); - assert(a); - assert(b); + for (; n > 0; n--, a++, b++) + *b = st_alaw2linear16(*a); +} - for (; n > 0; n--) - *(b++) = st_alaw2linear16(*(ca++)) * 1.0F / 0x7FFF; +static void alaw_from_s16ne(unsigned n, const int16_t *a, uint8_t *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--, a++, b++) + *b = st_13linear2alaw(*a >> 3); } -static void alaw_from_float32ne(unsigned n, const float *a, void *b) { - uint8_t *cb = b; +pa_convert_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f) { - assert(a); - assert(b); + static const pa_convert_func_t table[] = { + [PA_SAMPLE_U8] = (pa_convert_func_t) u8_to_float32ne, + [PA_SAMPLE_ALAW] = (pa_convert_func_t) alaw_to_float32ne, + [PA_SAMPLE_ULAW] = (pa_convert_func_t) ulaw_to_float32ne, + [PA_SAMPLE_S16LE] = (pa_convert_func_t) pa_sconv_s16le_to_float32ne, + [PA_SAMPLE_S16BE] = (pa_convert_func_t) pa_sconv_s16be_to_float32ne, + [PA_SAMPLE_FLOAT32NE] = (pa_convert_func_t) float32ne_to_float32ne, + [PA_SAMPLE_FLOAT32RE] = (pa_convert_func_t) float32re_to_float32ne, + }; - for (; n > 0; n--) { - float v = *(a++); + pa_assert(f >= 0); + pa_assert(f < PA_SAMPLE_MAX); - if (v > 1) - v = 1; + return table[f]; +} - if (v < -1) - v = -1; +pa_convert_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f) { - *(cb++) = st_13linear2alaw((int16_t) (v * 0xFFF)); - } + static const pa_convert_func_t table[] = { + [PA_SAMPLE_U8] = (pa_convert_func_t) u8_from_float32ne, + [PA_SAMPLE_S16LE] = (pa_convert_func_t) pa_sconv_s16le_from_float32ne, + [PA_SAMPLE_S16BE] = (pa_convert_func_t) pa_sconv_s16be_from_float32ne, + [PA_SAMPLE_FLOAT32NE] = (pa_convert_func_t) float32ne_to_float32ne, + [PA_SAMPLE_FLOAT32RE] = (pa_convert_func_t) float32re_to_float32ne, + [PA_SAMPLE_ALAW] = (pa_convert_func_t) alaw_from_float32ne, + [PA_SAMPLE_ULAW] = (pa_convert_func_t) ulaw_from_float32ne + }; + + pa_assert(f >= 0); + pa_assert(f < PA_SAMPLE_MAX); + + return table[f]; } -pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f) { - switch(f) { - case PA_SAMPLE_U8: - return u8_to_float32ne; - case PA_SAMPLE_S16LE: - return pa_sconv_s16le_to_float32ne; - case PA_SAMPLE_S16BE: - return pa_sconv_s16be_to_float32ne; - case PA_SAMPLE_FLOAT32NE: - return float32ne_to_float32ne; - case PA_SAMPLE_FLOAT32RE: - return float32re_to_float32ne; - case PA_SAMPLE_ALAW: - return alaw_to_float32ne; - case PA_SAMPLE_ULAW: - return ulaw_to_float32ne; - default: - return NULL; - } +pa_convert_func_t pa_get_convert_to_s16ne_function(pa_sample_format_t f) { + + static const pa_convert_func_t table[] = { + [PA_SAMPLE_U8] = (pa_convert_func_t) u8_to_s16ne, + [PA_SAMPLE_S16NE] = (pa_convert_func_t) s16ne_to_s16ne, + [PA_SAMPLE_S16RE] = (pa_convert_func_t) s16re_to_s16ne, + [PA_SAMPLE_FLOAT32BE] = (pa_convert_func_t) pa_sconv_float32be_to_s16ne, + [PA_SAMPLE_FLOAT32LE] = (pa_convert_func_t) pa_sconv_float32le_to_s16ne, + [PA_SAMPLE_ALAW] = (pa_convert_func_t) alaw_to_s16ne, + [PA_SAMPLE_ULAW] = (pa_convert_func_t) ulaw_to_s16ne + }; + + pa_assert(f >= 0); + pa_assert(f < PA_SAMPLE_MAX); + + return table[f]; } -pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f) { - switch(f) { - case PA_SAMPLE_U8: - return u8_from_float32ne; - case PA_SAMPLE_S16LE: - return pa_sconv_s16le_from_float32ne; - case PA_SAMPLE_S16BE: - return pa_sconv_s16be_from_float32ne; - case PA_SAMPLE_FLOAT32NE: - return float32ne_from_float32ne; - case PA_SAMPLE_FLOAT32RE: - return float32re_from_float32ne; - case PA_SAMPLE_ALAW: - return alaw_from_float32ne; - case PA_SAMPLE_ULAW: - return ulaw_from_float32ne; - default: - return NULL; - } +pa_convert_func_t pa_get_convert_from_s16ne_function(pa_sample_format_t f) { + + static const pa_convert_func_t table[] = { + [PA_SAMPLE_U8] = (pa_convert_func_t) u8_from_s16ne, + [PA_SAMPLE_S16NE] = (pa_convert_func_t) s16ne_to_s16ne, + [PA_SAMPLE_S16RE] = (pa_convert_func_t) s16re_to_s16ne, + [PA_SAMPLE_FLOAT32BE] = (pa_convert_func_t) pa_sconv_float32be_from_s16ne, + [PA_SAMPLE_FLOAT32LE] = (pa_convert_func_t) pa_sconv_float32le_from_s16ne, + [PA_SAMPLE_ALAW] = (pa_convert_func_t) alaw_from_s16ne, + [PA_SAMPLE_ULAW] = (pa_convert_func_t) ulaw_from_s16ne, + }; + + pa_assert(f >= 0); + pa_assert(f < PA_SAMPLE_MAX); + + return table[f]; } diff --git a/src/pulsecore/sconv.h b/src/pulsecore/sconv.h index 1e97aad9..901f50a3 100644 --- a/src/pulsecore/sconv.h +++ b/src/pulsecore/sconv.h @@ -27,10 +27,12 @@ #include -typedef void (*pa_convert_to_float32ne_func_t)(unsigned n, const void *a, float *b); -typedef void (*pa_convert_from_float32ne_func_t)(unsigned n, const float *a, void *b); +typedef void (*pa_convert_func_t)(unsigned n, const void *a, void *b); -pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f); -pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f); +pa_convert_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f) PA_GCC_PURE; +pa_convert_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f) PA_GCC_PURE; + +pa_convert_func_t pa_get_convert_to_s16ne_function(pa_sample_format_t f) PA_GCC_PURE; +pa_convert_func_t pa_get_convert_from_s16ne_function(pa_sample_format_t f) PA_GCC_PURE; #endif diff --git a/src/pulsecore/semaphore-posix.c b/src/pulsecore/semaphore-posix.c new file mode 100644 index 00000000..750c2afc --- /dev/null +++ b/src/pulsecore/semaphore-posix.c @@ -0,0 +1,69 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +#include "semaphore.h" + +struct pa_semaphore { + sem_t sem; +}; + +pa_semaphore* pa_semaphore_new(unsigned value) { + pa_semaphore *s; + + s = pa_xnew(pa_semaphore, 1); + pa_assert_se(sem_init(&s->sem, 0, value) == 0); + return s; +} + +void pa_semaphore_free(pa_semaphore *s) { + pa_assert(s); + pa_assert_se(sem_destroy(&s->sem) == 0); + pa_xfree(s); +} + +void pa_semaphore_post(pa_semaphore *s) { + pa_assert(s); + pa_assert_se(sem_post(&s->sem) == 0); +} + +void pa_semaphore_wait(pa_semaphore *s) { + int ret; + pa_assert(s); + + do { + ret = sem_wait(&s->sem); + } while (ret < 0 && errno == EINTR); + + pa_assert(ret == 0); +} diff --git a/src/pulsecore/semaphore-win32.c b/src/pulsecore/semaphore-win32.c new file mode 100644 index 00000000..f6576348 --- /dev/null +++ b/src/pulsecore/semaphore-win32.c @@ -0,0 +1,65 @@ +/* $Id: mutex-win32.c 1426 2007-02-13 15:35:19Z ossman $ */ + +/*** + This file is part of PulseAudio. + + Copyright 2006 Pierre Ossman for Cendio AB + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include "semaphore.h" + +struct pa_semaphore +{ + HANDLE sema; +}; + +pa_semaphore* pa_semaphore_new(unsigned value) { + pa_semaphore *s; + + s = pa_xnew(pa_semaphore, 1); + + s->sema = CreateSemaphore(NULL, value, 32767, NULL); + pa_assert(s->sema != NULL); + + return s; +} + +void pa_semaphore_free(pa_semaphore *s) { + pa_assert(s); + CloseHandle(s->sema); + pa_xfree(s); +} + +void pa_semaphore_post(pa_semaphore *s) { + pa_assert(s); + ReleaseSemaphore(s->sema, 1, NULL); +} + +void pa_semaphore_wait(pa_semaphore *s) { + pa_assert(s); + WaitForSingleObject(s->sema, INFINITE); +} diff --git a/src/pulsecore/semaphore.h b/src/pulsecore/semaphore.h new file mode 100644 index 00000000..c394e0f2 --- /dev/null +++ b/src/pulsecore/semaphore.h @@ -0,0 +1,35 @@ +#ifndef foopulsesemaphorehfoo +#define foopulsesemaphorehfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +typedef struct pa_semaphore pa_semaphore; + +pa_semaphore* pa_semaphore_new(unsigned value); +void pa_semaphore_free(pa_semaphore *m); + +void pa_semaphore_post(pa_semaphore *m); +void pa_semaphore_wait(pa_semaphore *m); + +#endif diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c index 444d4010..6882e7f8 100644 --- a/src/pulsecore/shm.c +++ b/src/pulsecore/shm.c @@ -1,32 +1,31 @@ /* $Id$ */ /*** - This file is part of PulseAudio. + This file is part of PulseAudio. - Copyright 2006 Lennart Poettering - Copyright 2006 Pierre Ossman for Cendio AB + Copyright 2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public - License along with PulseAudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. ***/ #ifdef HAVE_CONFIG_H #include #endif -#include #include #include #include @@ -34,15 +33,22 @@ #include #include #include +#include +#include +#include #ifdef HAVE_SYS_MMAN_H #include #endif +#include + #include #include #include -#include +#include +#include +#include #include "shm.h" @@ -50,10 +56,31 @@ #define MADV_REMOVE 9 #endif -#define MAX_SHM_SIZE (1024*1024*20) +#define MAX_SHM_SIZE (PA_ALIGN(1024*1024*20)) + +#ifdef __linux__ +/* On Linux we know that the shared memory blocks are files in + * /dev/shm. We can use that information to list all blocks and + * cleanup unused ones */ +#define SHM_PATH "/dev/shm/" +#else +#undef SHM_PATH +#endif + +#define SHM_MARKER ((int) 0xbeefcafe) + +/* We now put this SHM marker at the end of each segment. It's optional to not require a reboot when upgrading, though */ +struct shm_marker { + pa_atomic_t marker; /* 0xbeefcafe */ + pa_atomic_t pid; + void *_reserverd1; + void *_reserverd2; + void *_reserverd3; + void *_reserverd4; +}; static char *segment_name(char *fn, size_t l, unsigned id) { - snprintf(fn, l, "/pulse-shm-%u", id); + pa_snprintf(fn, l, "/pulse-shm-%u", id); return fn; } @@ -61,10 +88,17 @@ int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { char fn[32]; int fd = -1; - assert(m); - assert(size > 0); - assert(size < MAX_SHM_SIZE); - assert(mode >= 0600); + pa_assert(m); + pa_assert(size > 0); + pa_assert(size < MAX_SHM_SIZE); + pa_assert(mode >= 0600); + + /* Each time we create a new SHM area, let's first drop all stale + * ones */ + pa_shm_cleanup(); + + /* Round up to make it aligned */ + size = PA_ALIGN(size); if (!shared) { m->id = 0; @@ -79,7 +113,7 @@ int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { { int r; - if ((r = posix_memalign(&m->ptr, sysconf(_SC_PAGESIZE), size)) < 0) { + if ((r = posix_memalign(&m->ptr, PA_PAGE_SIZE, size)) < 0) { pa_log("posix_memalign() failed: %s", pa_cstrerror(r)); goto fail; } @@ -92,6 +126,8 @@ int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { } else { #ifdef HAVE_SHM_OPEN + struct shm_marker *marker; + pa_random(&m->id, sizeof(m->id)); segment_name(fn, sizeof(fn), m->id); @@ -100,7 +136,9 @@ int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { goto fail; } - if (ftruncate(fd, m->size = size) < 0) { + m->size = size + PA_ALIGN(sizeof(struct shm_marker)); + + if (ftruncate(fd, m->size) < 0) { pa_log("ftruncate() failed: %s", pa_cstrerror(errno)); goto fail; } @@ -110,10 +148,16 @@ int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) { goto fail; } - close(fd); + /* We store our PID at the end of the shm block, so that we + * can check for dead shm segments later */ + marker = (struct shm_marker*) ((uint8_t*) m->ptr + m->size - PA_ALIGN(sizeof(struct shm_marker))); + pa_atomic_store(&marker->pid, (int) getpid()); + pa_atomic_store(&marker->marker, SHM_MARKER); + + pa_assert_se(close(fd) == 0); m->do_unlink = 1; #else - return -1; + return -1; #endif } @@ -126,7 +170,7 @@ fail: #ifdef HAVE_SHM_OPEN if (fd >= 0) { shm_unlink(fn); - close(fd); + pa_close(fd); } #endif @@ -134,76 +178,70 @@ fail: } void pa_shm_free(pa_shm *m) { - assert(m); - assert(m->ptr); - assert(m->size > 0); + pa_assert(m); + pa_assert(m->ptr); + pa_assert(m->size > 0); #ifdef MAP_FAILED - assert(m->ptr != MAP_FAILED); + pa_assert(m->ptr != MAP_FAILED); #endif - if (!m->shared) { + if (!m->shared) { #ifdef MAP_ANONYMOUS - if (munmap(m->ptr, m->size) < 0) - pa_log("munmap() failed: %s", pa_cstrerror(errno)); + if (munmap(m->ptr, m->size) < 0) + pa_log("munmap() failed: %s", pa_cstrerror(errno)); #elif defined(HAVE_POSIX_MEMALIGN) free(m->ptr); #else pa_xfree(m->ptr); #endif - } else { + } else { #ifdef HAVE_SHM_OPEN - if (munmap(m->ptr, m->size) < 0) - pa_log("munmap() failed: %s", pa_cstrerror(errno)); + if (munmap(m->ptr, m->size) < 0) + pa_log("munmap() failed: %s", pa_cstrerror(errno)); - if (m->do_unlink) { - char fn[32]; + if (m->do_unlink) { + char fn[32]; - segment_name(fn, sizeof(fn), m->id); + segment_name(fn, sizeof(fn), m->id); - if (shm_unlink(fn) < 0) - pa_log(" shm_unlink(%s) failed: %s", fn, pa_cstrerror(errno)); - } + if (shm_unlink(fn) < 0) + pa_log(" shm_unlink(%s) failed: %s", fn, pa_cstrerror(errno)); + } #else - /* We shouldn't be here without shm support */ - assert(0); + /* We shouldn't be here without shm support */ + pa_assert_not_reached(); #endif - } + } memset(m, 0, sizeof(*m)); } void pa_shm_punch(pa_shm *m, size_t offset, size_t size) { void *ptr; + size_t o, ps; - assert(m); - assert(m->ptr); - assert(m->size > 0); - assert(offset+size <= m->size); + pa_assert(m); + pa_assert(m->ptr); + pa_assert(m->size > 0); + pa_assert(offset+size <= m->size); #ifdef MAP_FAILED - assert(m->ptr != MAP_FAILED); + pa_assert(m->ptr != MAP_FAILED); #endif /* You're welcome to implement this as NOOP on systems that don't * support it */ + /* Align this to multiples of the page size */ ptr = (uint8_t*) m->ptr + offset; - -#ifdef __linux__ -{ - /* On Linux ptr must be page aligned */ - long psz = sysconf(_SC_PAGESIZE); - unsigned o; - - o = ((unsigned long) ptr) - ((((unsigned long) ptr)/psz) * psz); + o = (uint8_t*) ptr - (uint8_t*) PA_PAGE_ALIGN_PTR(ptr); if (o > 0) { - ptr = (uint8_t*) ptr + (psz - o); - size -= psz - o; + ps = PA_PAGE_SIZE; + ptr = (uint8_t*) ptr + (ps - o); + size -= ps - o; } -} -#endif #ifdef MADV_REMOVE if (madvise(ptr, size, MADV_REMOVE) >= 0) @@ -216,7 +254,9 @@ void pa_shm_punch(pa_shm *m, size_t offset, size_t size) { #endif #ifdef MADV_DONTNEED - madvise(ptr, size, MADV_DONTNEED); + pa_assert_se(madvise(ptr, size, MADV_DONTNEED) == 0); +#elif defined(POSIX_MADV_DONTNEED) + pa_assert_se(posix_madvise(ptr, size, POSIX_MADV_DONTNEED) == 0); #endif } @@ -227,12 +267,13 @@ int pa_shm_attach_ro(pa_shm *m, unsigned id) { int fd = -1; struct stat st; - assert(m); + pa_assert(m); segment_name(fn, sizeof(fn), m->id = id); if ((fd = shm_open(fn, O_RDONLY, 0)) < 0) { - pa_log("shm_open() failed: %s", pa_cstrerror(errno)); + if (errno != EACCES) + pa_log("shm_open() failed: %s", pa_cstrerror(errno)); goto fail; } @@ -241,7 +282,7 @@ int pa_shm_attach_ro(pa_shm *m, unsigned id) { goto fail; } - if (st.st_size <= 0 || st.st_size > MAX_SHM_SIZE) { + if (st.st_size <= 0 || st.st_size > MAX_SHM_SIZE+PA_ALIGN(sizeof(struct shm_marker)) || PA_ALIGN(st.st_size) != st.st_size) { pa_log("Invalid shared memory segment size"); goto fail; } @@ -256,13 +297,13 @@ int pa_shm_attach_ro(pa_shm *m, unsigned id) { m->do_unlink = 0; m->shared = 1; - close(fd); + pa_assert_se(pa_close(fd) == 0); return 0; fail: if (fd >= 0) - close(fd); + pa_close(fd); return -1; } @@ -270,7 +311,71 @@ fail: #else /* HAVE_SHM_OPEN */ int pa_shm_attach_ro(pa_shm *m, unsigned id) { - return -1; + return -1; } #endif /* HAVE_SHM_OPEN */ + +int pa_shm_cleanup(void) { + +#ifdef SHM_PATH + DIR *d; + struct dirent *de; + + if (!(d = opendir(SHM_PATH))) { + pa_log_warn("Failed to read "SHM_PATH": %s", pa_cstrerror(errno)); + return -1; + } + + while ((de = readdir(d))) { + pa_shm seg; + unsigned id; + pid_t pid; + char fn[128]; + struct shm_marker *m; + + if (strncmp(de->d_name, "pulse-shm-", 10)) + continue; + + if (pa_atou(de->d_name + 10, &id) < 0) + continue; + + if (pa_shm_attach_ro(&seg, id) < 0) + continue; + + if (seg.size < PA_ALIGN(sizeof(struct shm_marker))) { + pa_shm_free(&seg); + continue; + } + + m = (struct shm_marker*) ((uint8_t*) seg.ptr + seg.size - PA_ALIGN(sizeof(struct shm_marker))); + + if (pa_atomic_load(&m->marker) != SHM_MARKER) { + pa_shm_free(&seg); + continue; + } + + if (!(pid = (pid_t) pa_atomic_load(&m->pid))) { + pa_shm_free(&seg); + continue; + } + + if (kill(pid, 0) == 0 || errno != ESRCH) { + pa_shm_free(&seg); + continue; + } + + pa_shm_free(&seg); + + /* Ok, the owner of this shms segment is dead, so, let's remove the segment */ + segment_name(fn, sizeof(fn), id); + + if (shm_unlink(fn) < 0 && errno != EACCES) + pa_log_warn("Failed to remove SHM segment %s: %s\n", fn, pa_cstrerror(errno)); + } + + closedir(d); +#endif + + return 0; +} diff --git a/src/pulsecore/shm.h b/src/pulsecore/shm.h index e695a2a1..270591de 100644 --- a/src/pulsecore/shm.h +++ b/src/pulsecore/shm.h @@ -41,4 +41,6 @@ void pa_shm_punch(pa_shm *m, size_t offset, size_t size); void pa_shm_free(pa_shm *m); +int pa_shm_cleanup(void); + #endif diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 3ddd7435..6f654b61 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -27,7 +27,6 @@ #endif #include -#include #include #include @@ -42,45 +41,51 @@ #include "sink-input.h" -#define CONVERT_BUFFER_LENGTH 4096 -#define MOVE_BUFFER_LENGTH (1024*1024) -#define SILENCE_BUFFER_LENGTH (64*1024) +#define CONVERT_BUFFER_LENGTH (PA_PAGE_SIZE) +#define SILENCE_BUFFER_LENGTH (PA_PAGE_SIZE*12) +#define MOVE_BUFFER_LENGTH (PA_PAGE_SIZE*256) -#define CHECK_VALIDITY_RETURN_NULL(condition) \ -do {\ -if (!(condition)) \ - return NULL; \ -} while (0) +static PA_DEFINE_CHECK_TYPE(pa_sink_input, pa_msgobject); + +static void sink_input_free(pa_object *o); pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data) { - assert(data); + pa_assert(data); memset(data, 0, sizeof(*data)); data->resample_method = PA_RESAMPLER_INVALID; + return data; } void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const pa_channel_map *map) { - assert(data); + pa_assert(data); if ((data->channel_map_is_set = !!map)) data->channel_map = *map; } void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume) { - assert(data); + pa_assert(data); if ((data->volume_is_set = !!volume)) data->volume = *volume; } void pa_sink_input_new_data_set_sample_spec(pa_sink_input_new_data *data, const pa_sample_spec *spec) { - assert(data); + pa_assert(data); if ((data->sample_spec_is_set = !!spec)) data->sample_spec = *spec; } +void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, pa_bool_t mute) { + pa_assert(data); + + data->muted_is_set = TRUE; + data->muted = !!mute; +} + pa_sink_input* pa_sink_input_new( pa_core *core, pa_sink_input_new_data *data, @@ -88,46 +93,52 @@ pa_sink_input* pa_sink_input_new( pa_sink_input *i; pa_resampler *resampler = NULL; - int r; char st[PA_SAMPLE_SPEC_SNPRINT_MAX]; - assert(core); - assert(data); + pa_assert(core); + pa_assert(data); - if (!(flags & PA_SINK_INPUT_NO_HOOKS)) - if (pa_hook_fire(&core->hook_sink_input_new, data) < 0) - return NULL; + if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], data) < 0) + return NULL; - CHECK_VALIDITY_RETURN_NULL(!data->driver || pa_utf8_valid(data->driver)); - CHECK_VALIDITY_RETURN_NULL(!data->name || pa_utf8_valid(data->name)); + pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver)); + pa_return_null_if_fail(!data->name || pa_utf8_valid(data->name)); if (!data->sink) data->sink = pa_namereg_get(core, NULL, PA_NAMEREG_SINK, 1); - CHECK_VALIDITY_RETURN_NULL(data->sink); - CHECK_VALIDITY_RETURN_NULL(data->sink->state == PA_SINK_RUNNING); + pa_return_null_if_fail(data->sink); + pa_return_null_if_fail(pa_sink_get_state(data->sink) != PA_SINK_UNLINKED); + pa_return_null_if_fail(!data->sync_base || (data->sync_base->sink == data->sink && pa_sink_input_get_state(data->sync_base) == PA_SINK_INPUT_CORKED)); if (!data->sample_spec_is_set) data->sample_spec = data->sink->sample_spec; - CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(&data->sample_spec)); + pa_return_null_if_fail(pa_sample_spec_valid(&data->sample_spec)); - if (!data->channel_map_is_set) - pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); + if (!data->channel_map_is_set) { + if (data->sink->channel_map.channels == data->sample_spec.channels) + data->channel_map = data->sink->channel_map; + else + pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); + } - CHECK_VALIDITY_RETURN_NULL(pa_channel_map_valid(&data->channel_map)); - CHECK_VALIDITY_RETURN_NULL(data->channel_map.channels == data->sample_spec.channels); + pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map)); + pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels); if (!data->volume_is_set) pa_cvolume_reset(&data->volume, data->sample_spec.channels); - CHECK_VALIDITY_RETURN_NULL(pa_cvolume_valid(&data->volume)); - CHECK_VALIDITY_RETURN_NULL(data->volume.channels == data->sample_spec.channels); + pa_return_null_if_fail(pa_cvolume_valid(&data->volume)); + pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels); + + if (!data->muted_is_set) + data->muted = 0; if (data->resample_method == PA_RESAMPLER_INVALID) data->resample_method = core->resample_method; - CHECK_VALIDITY_RETURN_NULL(data->resample_method < PA_RESAMPLER_MAX); + pa_return_null_if_fail(data->resample_method < PA_RESAMPLER_MAX); if (pa_idxset_size(data->sink->inputs) >= PA_MAX_INPUTS_PER_SINK) { pa_log_warn("Failed to create sink input: too many inputs per sink."); @@ -136,20 +147,27 @@ pa_sink_input* pa_sink_input_new( if ((flags & PA_SINK_INPUT_VARIABLE_RATE) || !pa_sample_spec_equal(&data->sample_spec, &data->sink->sample_spec) || - !pa_channel_map_equal(&data->channel_map, &data->sink->channel_map)) + !pa_channel_map_equal(&data->channel_map, &data->sink->channel_map)) { if (!(resampler = pa_resampler_new( core->mempool, &data->sample_spec, &data->channel_map, &data->sink->sample_spec, &data->sink->channel_map, - data->resample_method))) { + data->resample_method, + !!(flags & PA_SINK_INPUT_VARIABLE_RATE)))) { pa_log_warn("Unsupported resampling operation."); return NULL; } - i = pa_xnew(pa_sink_input, 1); - i->ref = 1; - i->state = PA_SINK_INPUT_DRAINED; + data->resample_method = pa_resampler_get_method(resampler); + } + + i = pa_msgobject_new(pa_sink_input); + i->parent.parent.free = sink_input_free; + i->parent.process_msg = pa_sink_input_process_msg; + + i->core = core; + i->state = PA_SINK_INPUT_INIT; i->flags = flags; i->name = pa_xstrdup(data->name); i->driver = pa_xstrdup(data->driver); @@ -157,105 +175,203 @@ pa_sink_input* pa_sink_input_new( i->sink = data->sink; i->client = data->client; + i->resample_method = data->resample_method; i->sample_spec = data->sample_spec; i->channel_map = data->channel_map; + i->volume = data->volume; + i->muted = data->muted; + + if (data->sync_base) { + i->sync_next = data->sync_base->sync_next; + i->sync_prev = data->sync_base; + + if (data->sync_base->sync_next) + data->sync_base->sync_next->sync_prev = i; + data->sync_base->sync_next = i; + } else + i->sync_next = i->sync_prev = NULL; i->peek = NULL; i->drop = NULL; i->kill = NULL; i->get_latency = NULL; - i->underrun = NULL; + i->attach = NULL; + i->detach = NULL; + i->suspend = NULL; i->userdata = NULL; - i->move_silence = 0; - - pa_memchunk_reset(&i->resampled_chunk); - i->resampler = resampler; - i->resample_method = data->resample_method; - i->silence_memblock = NULL; - - r = pa_idxset_put(core->sink_inputs, i, &i->index); - assert(r == 0); - r = pa_idxset_put(i->sink->inputs, i, NULL); - assert(r == 0); - - pa_log_info("created %u \"%s\" on %s with sample spec %s", + i->thread_info.state = i->state; + pa_atomic_store(&i->thread_info.drained, 1); + i->thread_info.sample_spec = i->sample_spec; + i->thread_info.silence_memblock = NULL; + i->thread_info.move_silence = 0; + pa_memchunk_reset(&i->thread_info.resampled_chunk); + i->thread_info.resampler = resampler; + i->thread_info.volume = i->volume; + i->thread_info.muted = i->muted; + i->thread_info.attached = FALSE; + + pa_assert_se(pa_idxset_put(core->sink_inputs, pa_sink_input_ref(i), &i->index) == 0); + pa_assert_se(pa_idxset_put(i->sink->inputs, i, NULL) == 0); + + pa_log_info("Created input %u \"%s\" on %s with sample spec %s", i->index, i->name, i->sink->name, pa_sample_spec_snprint(st, sizeof(st), &i->sample_spec)); - pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index); - - /* We do not call pa_sink_notify() here, because the virtual - * functions have not yet been initialized */ + /* Don't forget to call pa_sink_input_put! */ return i; } -void pa_sink_input_disconnect(pa_sink_input *i) { - assert(i); - assert(i->state != PA_SINK_INPUT_DISCONNECTED); - assert(i->sink); - assert(i->sink->core); +static void update_n_corked(pa_sink_input *i, pa_sink_input_state_t state) { + pa_assert(i); + + if (i->state == PA_SINK_INPUT_CORKED && state != PA_SINK_INPUT_CORKED) + pa_assert_se(i->sink->n_corked -- >= 1); + else if (i->state != PA_SINK_INPUT_CORKED && state == PA_SINK_INPUT_CORKED) + i->sink->n_corked++; + + pa_sink_update_status(i->sink); +} + +static int sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) { + pa_sink_input *ssync; + pa_assert(i); + + if (state == PA_SINK_INPUT_DRAINED) + state = PA_SINK_INPUT_RUNNING; + + if (i->state == state) + return 0; + + if (pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) < 0) + return -1; + + update_n_corked(i, state); + i->state = state; + + for (ssync = i->sync_prev; ssync; ssync = ssync->sync_prev) { + update_n_corked(ssync, state); + ssync->state = state; + } + for (ssync = i->sync_next; ssync; ssync = ssync->sync_next) { + update_n_corked(ssync, state); + ssync->state = state; + } + + if (state != PA_SINK_INPUT_UNLINKED) + pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], i); + + return 0; +} + +void pa_sink_input_unlink(pa_sink_input *i) { + pa_bool_t linked; + pa_assert(i); + + /* See pa_sink_unlink() for a couple of comments how this function + * works */ + + pa_sink_input_ref(i); + + linked = PA_SINK_INPUT_LINKED(i->state); + + if (linked) + pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], i); + + if (i->sync_prev) + i->sync_prev->sync_next = i->sync_next; + if (i->sync_next) + i->sync_next->sync_prev = i->sync_prev; + + i->sync_prev = i->sync_next = NULL; pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); - pa_idxset_remove_by_data(i->sink->inputs, i, NULL); + if (pa_idxset_remove_by_data(i->sink->inputs, i, NULL)) + pa_sink_input_unref(i); - pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index); - i->sink = NULL; + if (linked) { + pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_REMOVE_INPUT, i, 0, NULL); + sink_input_set_state(i, PA_SINK_INPUT_UNLINKED); + pa_sink_update_status(i->sink); + } else + i->state = PA_SINK_INPUT_UNLINKED; i->peek = NULL; i->drop = NULL; i->kill = NULL; i->get_latency = NULL; - i->underrun = NULL; + i->attach = NULL; + i->detach = NULL; + i->suspend = NULL; + + if (linked) { + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index); + pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK_POST], i); + } - i->state = PA_SINK_INPUT_DISCONNECTED; + i->sink = NULL; + pa_sink_input_unref(i); } -static void sink_input_free(pa_sink_input* i) { - assert(i); +static void sink_input_free(pa_object *o) { + pa_sink_input* i = PA_SINK_INPUT(o); - if (i->state != PA_SINK_INPUT_DISCONNECTED) - pa_sink_input_disconnect(i); + pa_assert(i); + pa_assert(pa_sink_input_refcnt(i) == 0); - pa_log_info("freed %u \"%s\"", i->index, i->name); + if (PA_SINK_INPUT_LINKED(i->state)) + pa_sink_input_unlink(i); - if (i->resampled_chunk.memblock) - pa_memblock_unref(i->resampled_chunk.memblock); + pa_log_info("Freeing output %u \"%s\"", i->index, i->name); - if (i->resampler) - pa_resampler_free(i->resampler); + pa_assert(!i->thread_info.attached); - if (i->silence_memblock) - pa_memblock_unref(i->silence_memblock); + if (i->thread_info.resampled_chunk.memblock) + pa_memblock_unref(i->thread_info.resampled_chunk.memblock); + + if (i->thread_info.resampler) + pa_resampler_free(i->thread_info.resampler); + + if (i->thread_info.silence_memblock) + pa_memblock_unref(i->thread_info.silence_memblock); pa_xfree(i->name); pa_xfree(i->driver); pa_xfree(i); } -void pa_sink_input_unref(pa_sink_input *i) { - assert(i); - assert(i->ref >= 1); +void pa_sink_input_put(pa_sink_input *i) { + pa_sink_input_assert_ref(i); - if (!(--i->ref)) - sink_input_free(i); -} + pa_assert(i->state == PA_SINK_INPUT_INIT); + pa_assert(i->peek); + pa_assert(i->drop); -pa_sink_input* pa_sink_input_ref(pa_sink_input *i) { - assert(i); - assert(i->ref >= 1); + i->thread_info.state = i->state = i->flags & PA_SINK_INPUT_START_CORKED ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING; + i->thread_info.volume = i->volume; + i->thread_info.muted = i->muted; - i->ref++; - return i; + if (i->state == PA_SINK_INPUT_CORKED) + i->sink->n_corked++; + + pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_ADD_INPUT, i, 0, NULL); + pa_sink_update_status(i->sink); + + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index); + pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], i); + + /* Please note that if you change something here, you have to + change something in pa_sink_input_move() with the ghost stream + registration too. */ } void pa_sink_input_kill(pa_sink_input*i) { - assert(i); - assert(i->ref >= 1); + pa_sink_input_assert_ref(i); + pa_assert(PA_SINK_INPUT_LINKED(i->state)); if (i->kill) i->kill(i); @@ -264,108 +380,127 @@ void pa_sink_input_kill(pa_sink_input*i) { pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) { pa_usec_t r = 0; - assert(i); - assert(i->ref >= 1); + pa_sink_input_assert_ref(i); + pa_assert(PA_SINK_INPUT_LINKED(i->state)); + + if (pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_GET_LATENCY, &r, 0, NULL) < 0) + r = 0; if (i->get_latency) r += i->get_latency(i); - if (i->resampled_chunk.memblock) - r += pa_bytes_to_usec(i->resampled_chunk.length, &i->sink->sample_spec); - - if (i->move_silence) - r += pa_bytes_to_usec(i->move_silence, &i->sink->sample_spec); - return r; } -int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) { +/* Called from thread context */ +int pa_sink_input_peek(pa_sink_input *i, size_t length, pa_memchunk *chunk, pa_cvolume *volume) { int ret = -1; int do_volume_adj_here; int volume_is_norm; + size_t block_size_max; - assert(i); - assert(i->ref >= 1); - assert(chunk); - assert(volume); - - pa_sink_input_ref(i); + pa_sink_input_assert_ref(i); + pa_assert(PA_SINK_INPUT_LINKED(i->thread_info.state)); + pa_assert(pa_frame_aligned(length, &i->sink->sample_spec)); + pa_assert(chunk); + pa_assert(volume); - if (!i->peek || !i->drop || i->state == PA_SINK_INPUT_CORKED) + if (!i->peek || !i->drop || i->thread_info.state == PA_SINK_INPUT_CORKED) goto finish; - assert(i->state == PA_SINK_INPUT_RUNNING || i->state == PA_SINK_INPUT_DRAINED); + pa_assert(i->thread_info.state == PA_SINK_INPUT_RUNNING || i->thread_info.state == PA_SINK_INPUT_DRAINED); - if (i->move_silence > 0) { + /* Default buffer size */ + if (length <= 0) + length = pa_frame_align(CONVERT_BUFFER_LENGTH, &i->sink->sample_spec); + + /* Make sure the buffer fits in the mempool tile */ + block_size_max = pa_mempool_block_size_max(i->sink->core->mempool); + if (length > block_size_max) + length = pa_frame_align(block_size_max, &i->sink->sample_spec); + + if (i->thread_info.move_silence > 0) { + size_t l; /* We have just been moved and shall play some silence for a * while until the old sink has drained its playback buffer */ - if (!i->silence_memblock) - i->silence_memblock = pa_silence_memblock_new(i->sink->core->mempool, &i->sink->sample_spec, SILENCE_BUFFER_LENGTH); + if (!i->thread_info.silence_memblock) + i->thread_info.silence_memblock = pa_silence_memblock_new( + i->sink->core->mempool, + &i->sink->sample_spec, + pa_frame_align(SILENCE_BUFFER_LENGTH, &i->sink->sample_spec)); - chunk->memblock = pa_memblock_ref(i->silence_memblock); + chunk->memblock = pa_memblock_ref(i->thread_info.silence_memblock); chunk->index = 0; - chunk->length = i->move_silence < chunk->memblock->length ? i->move_silence : chunk->memblock->length; + l = pa_memblock_get_length(chunk->memblock); + chunk->length = i->thread_info.move_silence < l ? i->thread_info.move_silence : l; ret = 0; do_volume_adj_here = 1; goto finish; } - if (!i->resampler) { - do_volume_adj_here = 0; - ret = i->peek(i, chunk); + if (!i->thread_info.resampler) { + do_volume_adj_here = 0; /* FIXME??? */ + ret = i->peek(i, length, chunk); goto finish; } do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map); - volume_is_norm = pa_cvolume_is_norm(&i->volume); + volume_is_norm = pa_cvolume_is_norm(&i->thread_info.volume) && !i->thread_info.muted; - while (!i->resampled_chunk.memblock) { + while (!i->thread_info.resampled_chunk.memblock) { pa_memchunk tchunk; - size_t l; + size_t l, rmbs; - if ((ret = i->peek(i, &tchunk)) < 0) - goto finish; + l = pa_resampler_request(i->thread_info.resampler, length); - assert(tchunk.length); + if (l <= 0) + l = pa_frame_align(CONVERT_BUFFER_LENGTH, &i->sample_spec); - l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); + rmbs = pa_resampler_max_block_size(i->thread_info.resampler); + if (l > rmbs) + l = rmbs; - if (l > tchunk.length) - l = tchunk.length; + if ((ret = i->peek(i, l, &tchunk)) < 0) + goto finish; + + pa_assert(tchunk.length > 0); + + if (tchunk.length > l) + tchunk.length = l; - i->drop(i, &tchunk, l); - tchunk.length = l; + i->drop(i, tchunk.length); /* It might be necessary to adjust the volume here */ if (do_volume_adj_here && !volume_is_norm) { pa_memchunk_make_writable(&tchunk, 0); - pa_volume_memchunk(&tchunk, &i->sample_spec, &i->volume); + + if (i->thread_info.muted) + pa_silence_memchunk(&tchunk, &i->thread_info.sample_spec); + else + pa_volume_memchunk(&tchunk, &i->thread_info.sample_spec, &i->thread_info.volume); } - pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk); + pa_resampler_run(i->thread_info.resampler, &tchunk, &i->thread_info.resampled_chunk); pa_memblock_unref(tchunk.memblock); } - assert(i->resampled_chunk.memblock); - assert(i->resampled_chunk.length); + pa_assert(i->thread_info.resampled_chunk.memblock); + pa_assert(i->thread_info.resampled_chunk.length > 0); - *chunk = i->resampled_chunk; - pa_memblock_ref(i->resampled_chunk.memblock); + *chunk = i->thread_info.resampled_chunk; + pa_memblock_ref(i->thread_info.resampled_chunk.memblock); ret = 0; finish: - if (ret < 0 && i->state == PA_SINK_INPUT_RUNNING && i->underrun) - i->underrun(i); - if (ret >= 0) - i->state = PA_SINK_INPUT_RUNNING; - else if (ret < 0 && i->state == PA_SINK_INPUT_RUNNING) - i->state = PA_SINK_INPUT_DRAINED; + pa_atomic_store(&i->thread_info.drained, 0); + else if (ret < 0) + pa_atomic_store(&i->thread_info.drained, 1); if (ret >= 0) { /* Let's see if we had to apply the volume adjustment @@ -374,120 +509,179 @@ finish: if (do_volume_adj_here) /* We had different channel maps, so we already did the adjustment */ pa_cvolume_reset(volume, i->sink->sample_spec.channels); - else + else if (i->thread_info.muted) /* We've both the same channel map, so let's have the sink do the adjustment for us*/ - *volume = i->volume; + pa_cvolume_mute(volume, i->sink->sample_spec.channels); + else + *volume = i->thread_info.volume; } - pa_sink_input_unref(i); - return ret; } -void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { - assert(i); - assert(i->ref >= 1); - assert(length > 0); +/* Called from thread context */ +void pa_sink_input_drop(pa_sink_input *i, size_t length) { + pa_sink_input_assert_ref(i); + pa_assert(PA_SINK_INPUT_LINKED(i->thread_info.state)); + pa_assert(pa_frame_aligned(length, &i->sink->sample_spec)); + pa_assert(length > 0); - if (i->move_silence > 0) { + if (!i->peek || !i->drop || i->thread_info.state == PA_SINK_INPUT_CORKED) + return; - if (chunk) { + if (i->thread_info.move_silence > 0) { - if (chunk->memblock != i->silence_memblock || - chunk->index != 0 || - (chunk->memblock && (chunk->length != (i->silence_memblock->length < i->move_silence ? i->silence_memblock->length : i->move_silence)))) - return; + if (i->thread_info.move_silence >= length) { + i->thread_info.move_silence -= length; + length = 0; + } else { + length -= i->thread_info.move_silence; + i->thread_info.move_silence = 0; + } + if (i->thread_info.move_silence <= 0) { + if (i->thread_info.silence_memblock) { + pa_memblock_unref(i->thread_info.silence_memblock); + i->thread_info.silence_memblock = NULL; + } } - assert(i->move_silence >= length); + if (length <= 0) + return; + } + + if (i->thread_info.resampled_chunk.memblock) { + size_t l = length; + + if (l > i->thread_info.resampled_chunk.length) + l = i->thread_info.resampled_chunk.length; - i->move_silence -= length; + i->thread_info.resampled_chunk.index += l; + i->thread_info.resampled_chunk.length -= l; - if (i->move_silence <= 0) { - assert(i->silence_memblock); - pa_memblock_unref(i->silence_memblock); - i->silence_memblock = NULL; + if (i->thread_info.resampled_chunk.length <= 0) { + pa_memblock_unref(i->thread_info.resampled_chunk.memblock); + pa_memchunk_reset(&i->thread_info.resampled_chunk); } - return; + length -= l; } - if (!i->resampler) { - if (i->drop) - i->drop(i, chunk, length); - return; - } + if (length > 0) { + + if (i->thread_info.resampler) { + /* So, we have a resampler. To avoid discontinuities we + * have to actually read all data that could be read and + * pass it through the resampler. */ + + while (length > 0) { + pa_memchunk chunk; + pa_cvolume volume; + + if (pa_sink_input_peek(i, length, &chunk, &volume) >= 0) { + size_t l; + + pa_memblock_unref(chunk.memblock); + + l = chunk.length; + if (l > length) + l = length; + + pa_sink_input_drop(i, l); + length -= l; - assert(i->resampled_chunk.memblock); - assert(i->resampled_chunk.length >= length); + } else { + size_t l; - i->resampled_chunk.index += length; - i->resampled_chunk.length -= length; + l = pa_resampler_request(i->thread_info.resampler, length); + + /* Hmmm, peeking failed, so let's at least drop + * the right amount of data */ + + if (l > 0) + if (i->drop) + i->drop(i, l); + + break; + } + } - if (i->resampled_chunk.length <= 0) { - pa_memblock_unref(i->resampled_chunk.memblock); - i->resampled_chunk.memblock = NULL; - i->resampled_chunk.index = i->resampled_chunk.length = 0; + } else { + + /* We have no resampler, hence let's just drop the data */ + + if (i->drop) + i->drop(i, length); + } } } void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) { - assert(i); - assert(i->ref >= 1); - assert(i->sink); - assert(i->sink->core); + pa_sink_input_assert_ref(i); + pa_assert(PA_SINK_INPUT_LINKED(i->state)); if (pa_cvolume_equal(&i->volume, volume)) return; i->volume = *volume; + + pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), 0, NULL, pa_xfree); pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); } -const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i) { - assert(i); - assert(i->ref >= 1); +const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i) { + pa_sink_input_assert_ref(i); + pa_assert(PA_SINK_INPUT_LINKED(i->state)); return &i->volume; } -void pa_sink_input_cork(pa_sink_input *i, int b) { - int n; +void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute) { + pa_assert(i); + pa_sink_input_assert_ref(i); + pa_assert(PA_SINK_INPUT_LINKED(i->state)); - assert(i); - assert(i->ref >= 1); + if (!i->muted == !mute) + return; - assert(i->state != PA_SINK_INPUT_DISCONNECTED); + i->muted = mute; - n = i->state == PA_SINK_INPUT_CORKED && !b; + pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_MUTE, PA_UINT_TO_PTR(mute), 0, NULL, NULL); + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); +} + +int pa_sink_input_get_mute(pa_sink_input *i) { + pa_sink_input_assert_ref(i); + pa_assert(PA_SINK_INPUT_LINKED(i->state)); + + return !!i->muted; +} - if (b) - i->state = PA_SINK_INPUT_CORKED; - else if (i->state == PA_SINK_INPUT_CORKED) - i->state = PA_SINK_INPUT_DRAINED; +void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b) { + pa_sink_input_assert_ref(i); + pa_assert(PA_SINK_INPUT_LINKED(i->state)); - if (n) - pa_sink_notify(i->sink); + sink_input_set_state(i, b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING); } -void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) { - assert(i); - assert(i->resampler); - assert(i->ref >= 1); +int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) { + pa_sink_input_assert_ref(i); + pa_assert(PA_SINK_INPUT_LINKED(i->state)); + pa_return_val_if_fail(i->thread_info.resampler, -1); if (i->sample_spec.rate == rate) - return; + return 0; i->sample_spec.rate = rate; - pa_resampler_set_input_rate(i->resampler, rate); + + pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), 0, NULL, NULL); pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); + return 0; } void pa_sink_input_set_name(pa_sink_input *i, const char *name) { - assert(i); - assert(i->ref >= 1); + pa_sink_input_assert_ref(i); if (!i->name && !name) return; @@ -498,47 +692,56 @@ void pa_sink_input_set_name(pa_sink_input *i, const char *name) { pa_xfree(i->name); i->name = pa_xstrdup(name); - pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); + if (PA_SINK_INPUT_LINKED(i->state)) { + pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_NAME_CHANGED], i); + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); + } } pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) { - assert(i); - assert(i->ref >= 1); + pa_sink_input_assert_ref(i); - if (!i->resampler) - return i->resample_method; - - return pa_resampler_get_method(i->resampler); + return i->resample_method; } int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { - pa_resampler *new_resampler = NULL; - pa_memblockq *buffer = NULL; + pa_resampler *new_resampler; pa_sink *origin; + pa_usec_t silence_usec = 0; + pa_sink_input_move_info info; - assert(i); - assert(dest); + pa_sink_input_assert_ref(i); + pa_assert(PA_SINK_INPUT_LINKED(i->state)); + pa_sink_assert_ref(dest); origin = i->sink; if (dest == origin) return 0; + if (i->flags & PA_SINK_INPUT_DONT_MOVE) + return -1; + + if (i->sync_next || i->sync_prev) { + pa_log_warn("Moving synchronised streams not supported."); + return -1; + } + if (pa_idxset_size(dest->inputs) >= PA_MAX_INPUTS_PER_SINK) { pa_log_warn("Failed to move sink input: too many inputs per sink."); return -1; } - if (i->resampler && + if (i->thread_info.resampler && pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) && pa_channel_map_equal(&origin->channel_map, &dest->channel_map)) /* Try to reuse the old resampler if possible */ - new_resampler = i->resampler; + new_resampler = i->thread_info.resampler; else if ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) || - !pa_sample_spec_equal(&i->sample_spec, &dest->sample_spec) || - !pa_channel_map_equal(&i->channel_map, &dest->channel_map)) { + !pa_sample_spec_equal(&i->sample_spec, &dest->sample_spec) || + !pa_channel_map_equal(&i->channel_map, &dest->channel_map)) { /* Okey, we need a new resampler for the new sink */ @@ -546,20 +749,26 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { dest->core->mempool, &i->sample_spec, &i->channel_map, &dest->sample_spec, &dest->channel_map, - i->resample_method))) { + i->resample_method, + !!(i->flags & PA_SINK_INPUT_VARIABLE_RATE)))) { pa_log_warn("Unsupported resampling operation."); return -1; } - } + } else + new_resampler = NULL; + + pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE], i); + + memset(&info, 0, sizeof(info)); + info.sink_input = i; if (!immediately) { pa_usec_t old_latency, new_latency; - pa_usec_t silence_usec = 0; - - buffer = pa_memblockq_new(0, MOVE_BUFFER_LENGTH, 0, pa_frame_size(&origin->sample_spec), 0, 0, NULL); /* Let's do a little bit of Voodoo for compensating latency - * differences */ + * differences. We assume that the accuracy for our + * estimations is still good enough, even though we do these + * operations non-atomic. */ old_latency = pa_sink_get_latency(origin); new_latency = pa_sink_get_latency(dest); @@ -576,8 +785,6 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { silence_usec = old_latency - new_latency; } else { - size_t l; - int volume_is_norm; /* The latency of new sink is larger than the latency of * the old sink. Therefore we have to precompute a little @@ -585,87 +792,164 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { * sink, until we can play the first sample on the new * sink.*/ - l = pa_usec_to_bytes(new_latency - old_latency, &origin->sample_spec); + info.buffer_bytes = pa_usec_to_bytes(new_latency - old_latency, &origin->sample_spec); + } - volume_is_norm = pa_cvolume_is_norm(&i->volume); + /* Okey, let's move it */ - while (l > 0) { - pa_memchunk chunk; - pa_cvolume volume; - size_t n; + if (info.buffer_bytes > 0) { - if (pa_sink_input_peek(i, &chunk, &volume) < 0) - break; + info.ghost_sink_input = pa_memblockq_sink_input_new( + origin, + "Ghost Stream", + &origin->sample_spec, + &origin->channel_map, + NULL, + NULL); - n = chunk.length > l ? l : chunk.length; - pa_sink_input_drop(i, &chunk, n); - chunk.length = n; + info.ghost_sink_input->thread_info.state = info.ghost_sink_input->state = PA_SINK_INPUT_RUNNING; + info.ghost_sink_input->thread_info.volume = info.ghost_sink_input->volume; + info.ghost_sink_input->thread_info.muted = info.ghost_sink_input->muted; - if (!volume_is_norm) { - pa_memchunk_make_writable(&chunk, 0); - pa_volume_memchunk(&chunk, &origin->sample_spec, &volume); - } - - if (pa_memblockq_push(buffer, &chunk) < 0) { - pa_memblock_unref(chunk.memblock); - break; - } - - pa_memblock_unref(chunk.memblock); - l -= n; - } + info.buffer = pa_memblockq_new(0, MOVE_BUFFER_LENGTH, 0, pa_frame_size(&origin->sample_spec), 0, 0, NULL); } + } - if (i->resampled_chunk.memblock) { - - /* There is still some data left in the already resampled - * memory block. Hence, let's output it on the old sink - * and sleep so long on the new sink */ + pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_REMOVE_INPUT_AND_BUFFER, &info, 0, NULL); - pa_memblockq_push(buffer, &i->resampled_chunk); - silence_usec += pa_bytes_to_usec(i->resampled_chunk.length, &origin->sample_spec); - } + if (info.ghost_sink_input) { + /* Basically, do what pa_sink_input_put() does ...*/ - /* Calculate the new sleeping time */ - i->move_silence = pa_usec_to_bytes( - pa_bytes_to_usec(i->move_silence, &i->sample_spec) + - silence_usec, - &i->sample_spec); + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, info.ghost_sink_input->index); + pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], info.ghost_sink_input); + pa_sink_input_unref(info.ghost_sink_input); } - /* Okey, let's move it */ pa_idxset_remove_by_data(origin->inputs, i, NULL); pa_idxset_put(dest->inputs, i, NULL); i->sink = dest; + if (pa_sink_input_get_state(i) == PA_SINK_INPUT_CORKED) { + pa_assert_se(origin->n_corked-- >= 1); + dest->n_corked++; + } + /* Replace resampler */ - if (new_resampler != i->resampler) { - if (i->resampler) - pa_resampler_free(i->resampler); - i->resampler = new_resampler; + if (new_resampler != i->thread_info.resampler) { + if (i->thread_info.resampler) + pa_resampler_free(i->thread_info.resampler); + i->thread_info.resampler = new_resampler; /* if the resampler changed, the silence memblock is * probably invalid now, too */ - if (i->silence_memblock) { - pa_memblock_unref(i->silence_memblock); - i->silence_memblock = NULL; + if (i->thread_info.silence_memblock) { + pa_memblock_unref(i->thread_info.silence_memblock); + i->thread_info.silence_memblock = NULL; } } /* Dump already resampled data */ - if (i->resampled_chunk.memblock) { - pa_memblock_unref(i->resampled_chunk.memblock); - i->resampled_chunk.memblock = NULL; - i->resampled_chunk.index = i->resampled_chunk.length = 0; + if (i->thread_info.resampled_chunk.memblock) { + /* Hmm, this data has already been added to the ghost queue, presumably, hence let's sleep a little bit longer */ + silence_usec += pa_bytes_to_usec(i->thread_info.resampled_chunk.length, &origin->sample_spec); + pa_memblock_unref(i->thread_info.resampled_chunk.memblock); + pa_memchunk_reset(&i->thread_info.resampled_chunk); } + /* Calculate the new sleeping time */ + if (immediately) + i->thread_info.move_silence = 0; + else + i->thread_info.move_silence = pa_usec_to_bytes( + pa_bytes_to_usec(i->thread_info.move_silence, &origin->sample_spec) + + silence_usec, + &dest->sample_spec); + + pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_ADD_INPUT, i, 0, NULL); + + pa_sink_update_status(origin); + pa_sink_update_status(dest); + + pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_POST], i); + + pa_log_debug("Successfully moved sink input %i from %s to %s.", i->index, origin->name, dest->name); + /* Notify everyone */ pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); - pa_sink_notify(i->sink); - - /* Ok, no let's feed the precomputed buffer to the old sink */ - if (buffer) - pa_play_memblockq(origin, "Ghost Stream", &origin->sample_spec, &origin->channel_map, buffer, NULL); return 0; } + +/* Called from thread context */ +int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) { + pa_sink_input *i = PA_SINK_INPUT(o); + + pa_sink_input_assert_ref(i); + pa_assert(PA_SINK_INPUT_LINKED(i->thread_info.state)); + + switch (code) { + case PA_SINK_INPUT_MESSAGE_SET_VOLUME: + i->thread_info.volume = *((pa_cvolume*) userdata); + return 0; + + case PA_SINK_INPUT_MESSAGE_SET_MUTE: + i->thread_info.muted = PA_PTR_TO_UINT(userdata); + return 0; + + case PA_SINK_INPUT_MESSAGE_GET_LATENCY: { + pa_usec_t *r = userdata; + + if (i->thread_info.resampled_chunk.memblock) + *r += pa_bytes_to_usec(i->thread_info.resampled_chunk.length, &i->sink->sample_spec); + + if (i->thread_info.move_silence) + *r += pa_bytes_to_usec(i->thread_info.move_silence, &i->sink->sample_spec); + + return 0; + } + + case PA_SINK_INPUT_MESSAGE_SET_RATE: + + i->thread_info.sample_spec.rate = PA_PTR_TO_UINT(userdata); + pa_resampler_set_input_rate(i->thread_info.resampler, PA_PTR_TO_UINT(userdata)); + + return 0; + + case PA_SINK_INPUT_MESSAGE_SET_STATE: { + pa_sink_input *ssync; + + if ((PA_PTR_TO_UINT(userdata) == PA_SINK_INPUT_DRAINED || PA_PTR_TO_UINT(userdata) == PA_SINK_INPUT_RUNNING) && + (i->thread_info.state != PA_SINK_INPUT_DRAINED) && (i->thread_info.state != PA_SINK_INPUT_RUNNING)) + pa_atomic_store(&i->thread_info.drained, 1); + + i->thread_info.state = PA_PTR_TO_UINT(userdata); + + for (ssync = i->thread_info.sync_prev; ssync; ssync = ssync->thread_info.sync_prev) { + if ((PA_PTR_TO_UINT(userdata) == PA_SINK_INPUT_DRAINED || PA_PTR_TO_UINT(userdata) == PA_SINK_INPUT_RUNNING) && + (ssync->thread_info.state != PA_SINK_INPUT_DRAINED) && (ssync->thread_info.state != PA_SINK_INPUT_RUNNING)) + pa_atomic_store(&ssync->thread_info.drained, 1); + ssync->thread_info.state = PA_PTR_TO_UINT(userdata); + } + + for (ssync = i->thread_info.sync_next; ssync; ssync = ssync->thread_info.sync_next) { + if ((PA_PTR_TO_UINT(userdata) == PA_SINK_INPUT_DRAINED || PA_PTR_TO_UINT(userdata) == PA_SINK_INPUT_RUNNING) && + (ssync->thread_info.state != PA_SINK_INPUT_DRAINED) && (ssync->thread_info.state != PA_SINK_INPUT_RUNNING)) + pa_atomic_store(&ssync->thread_info.drained, 1); + ssync->thread_info.state = PA_PTR_TO_UINT(userdata); + } + + return 0; + } + } + + return -1; +} + +pa_sink_input_state_t pa_sink_input_get_state(pa_sink_input *i) { + pa_sink_input_assert_ref(i); + + if (i->state == PA_SINK_INPUT_RUNNING || i->state == PA_SINK_INPUT_DRAINED) + return pa_atomic_load(&i->thread_info.drained) ? PA_SINK_INPUT_DRAINED : PA_SINK_INPUT_RUNNING; + + return i->state; +} diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 51d9ec78..3f8e2039 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -1,5 +1,5 @@ -#ifndef foosinkinputhfoo -#define foosinkinputhfoo +#ifndef foopulsesinkinputhfoo +#define foopulsesinkinputhfoo /* $Id$ */ @@ -39,20 +39,32 @@ typedef struct pa_sink_input pa_sink_input; #include typedef enum pa_sink_input_state { - PA_SINK_INPUT_RUNNING, /*< The stream is alive and kicking */ + PA_SINK_INPUT_INIT, /*< The stream is not active yet, because pa_sink_put() has not been called yet */ PA_SINK_INPUT_DRAINED, /*< The stream stopped playing because there was no data to play */ + PA_SINK_INPUT_RUNNING, /*< The stream is alive and kicking */ PA_SINK_INPUT_CORKED, /*< The stream was corked on user request */ - PA_SINK_INPUT_DISCONNECTED /*< The stream is dead */ + PA_SINK_INPUT_UNLINKED /*< The stream is dead */ } pa_sink_input_state_t; +static inline pa_bool_t PA_SINK_INPUT_LINKED(pa_sink_input_state_t x) { + return x == PA_SINK_INPUT_DRAINED || x == PA_SINK_INPUT_RUNNING || x == PA_SINK_INPUT_CORKED; +} + typedef enum pa_sink_input_flags { PA_SINK_INPUT_VARIABLE_RATE = 1, - PA_SINK_INPUT_NO_HOOKS = 2 + PA_SINK_INPUT_DONT_MOVE = 2, + PA_SINK_INPUT_START_CORKED = 4 } pa_sink_input_flags_t; struct pa_sink_input { - int ref; + pa_msgobject parent; + uint32_t index; + pa_core *core; + + /* Please note that this state should only be read with + * pa_sink_input_get_state(). That function will transparently + * merge the thread_info.drained value in. */ pa_sink_input_state_t state; pa_sink_input_flags_t flags; @@ -64,27 +76,87 @@ struct pa_sink_input { pa_sample_spec sample_spec; pa_channel_map channel_map; - pa_cvolume volume; - /* Some silence to play before the actual data. This is used to - * compensate for latency differences when moving a sink input - * "hot" between sinks. */ - size_t move_silence; + pa_sink_input *sync_prev, *sync_next; - int (*peek) (pa_sink_input *i, pa_memchunk *chunk); - void (*drop) (pa_sink_input *i, const pa_memchunk *chunk, size_t length); + pa_cvolume volume; + pa_bool_t muted; + + /* Returns the chunk of audio data (but doesn't drop it + * yet!). Returns -1 on failure. Called from IO thread context. If + * data needs to be generated from scratch then please in the + * specified length. This is an optimization only. If less data is + * available, it's fine to return a smaller block. If more data is + * already ready, it is better to return the full block.*/ + int (*peek) (pa_sink_input *i, size_t length, pa_memchunk *chunk); + + /* Drops the specified number of bytes, usually called right after + * peek(), but not necessarily. Called from IO thread context. */ + void (*drop) (pa_sink_input *i, size_t length); + + /* If non-NULL this function is called when the input is first + * connected to a sink or when the rtpoll/asyncmsgq fields + * change. You usually don't need to implement this function + * unless you rewrite a sink that is piggy-backed onto + * another. Called from IO thread context */ + void (*attach) (pa_sink_input *i); /* may be NULL */ + + /* If non-NULL this function is called when the output is + * disconnected from its sink. Called from IO thread context */ + void (*detach) (pa_sink_input *i); /* may be NULL */ + + /* If non-NULL called whenever the the sink this input is attached + * to suspends or resumes. Called from main context */ + void (*suspend) (pa_sink_input *i, int b); /* may be NULL */ + + /* Supposed to unlink and destroy this stream. Called from main + * context. */ void (*kill) (pa_sink_input *i); /* may be NULL */ + + /* Return the current latency (i.e. length of bufferd audio) of + this stream. Called from main context. If NULL a + PA_SINK_INPUT_MESSAGE_GET_LATENCY message is sent to the IO thread + instead. */ pa_usec_t (*get_latency) (pa_sink_input *i); /* may be NULL */ - void (*underrun) (pa_sink_input *i); /* may be NULL */ - void *userdata; + pa_resample_method_t resample_method; - pa_memchunk resampled_chunk; - pa_resampler *resampler; /* may be NULL */ + struct { + pa_sink_input_state_t state; + pa_atomic_t drained; - pa_resample_method_t resample_method; + pa_bool_t attached; /* True only between ->attach() and ->detach() calls */ + + pa_sample_spec sample_spec; + + pa_memchunk resampled_chunk; + pa_resampler *resampler; /* may be NULL */ + + /* Some silence to play before the actual data. This is used to + * compensate for latency differences when moving a sink input + * "hot" between sinks. */ + size_t move_silence; + pa_memblock *silence_memblock; /* may be NULL */ + + pa_sink_input *sync_prev, *sync_next; + + pa_cvolume volume; + pa_bool_t muted; + } thread_info; + + void *userdata; +}; + +PA_DECLARE_CLASS(pa_sink_input); +#define PA_SINK_INPUT(o) pa_sink_input_cast(o) - pa_memblock *silence_memblock; /* may be NULL */ +enum { + PA_SINK_INPUT_MESSAGE_SET_VOLUME, + PA_SINK_INPUT_MESSAGE_SET_MUTE, + PA_SINK_INPUT_MESSAGE_GET_LATENCY, + PA_SINK_INPUT_MESSAGE_SET_RATE, + PA_SINK_INPUT_MESSAGE_SET_STATE, + PA_SINK_INPUT_MESSAGE_MAX }; typedef struct pa_sink_input_new_data { @@ -95,50 +167,71 @@ typedef struct pa_sink_input_new_data { pa_sink *sink; pa_sample_spec sample_spec; - int sample_spec_is_set; + pa_bool_t sample_spec_is_set; pa_channel_map channel_map; - int channel_map_is_set; + pa_bool_t channel_map_is_set; + pa_cvolume volume; - int volume_is_set; + pa_bool_t volume_is_set; + pa_bool_t muted; + pa_bool_t muted_is_set; pa_resample_method_t resample_method; + + pa_sink_input *sync_base; } pa_sink_input_new_data; pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data); void pa_sink_input_new_data_set_sample_spec(pa_sink_input_new_data *data, const pa_sample_spec *spec); void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const pa_channel_map *map); void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume); +void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, pa_bool_t mute); + +/* To be called by the implementing module only */ pa_sink_input* pa_sink_input_new( pa_core *core, pa_sink_input_new_data *data, pa_sink_input_flags_t flags); -void pa_sink_input_unref(pa_sink_input* i); -pa_sink_input* pa_sink_input_ref(pa_sink_input* i); +void pa_sink_input_put(pa_sink_input *i); +void pa_sink_input_unlink(pa_sink_input* i); -/* To be called by the implementing module only */ -void pa_sink_input_disconnect(pa_sink_input* i); +void pa_sink_input_set_name(pa_sink_input *i, const char *name); -/* External code may request disconnection with this funcion */ +/* Callable by everyone */ + +/* External code may request disconnection with this function */ void pa_sink_input_kill(pa_sink_input*i); pa_usec_t pa_sink_input_get_latency(pa_sink_input *i); -int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume); -void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length); - void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume); -const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i); +const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i); +void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute); +int pa_sink_input_get_mute(pa_sink_input *i); -void pa_sink_input_cork(pa_sink_input *i, int b); +void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b); -void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate); - -void pa_sink_input_set_name(pa_sink_input *i, const char *name); +int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate); pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i); int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately); +pa_sink_input_state_t pa_sink_input_get_state(pa_sink_input *i); + +/* To be used exclusively by the sink driver thread */ + +int pa_sink_input_peek(pa_sink_input *i, size_t length, pa_memchunk *chunk, pa_cvolume *volume); +void pa_sink_input_drop(pa_sink_input *i, size_t length); +int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk); + +typedef struct pa_sink_input_move_info { + pa_sink_input *sink_input; + pa_sink_input *ghost_sink_input; + pa_memblockq *buffer; + size_t buffer_bytes; +} pa_sink_input_move_info; + #endif diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 9588c2c3..dccb34cc 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -27,7 +27,6 @@ #endif #include -#include #include #include @@ -41,16 +40,18 @@ #include #include #include +#include +#include #include "sink.h" #define MAX_MIX_CHANNELS 32 +#define MIX_BUFFER_LENGTH (PA_PAGE_SIZE) +#define SILENCE_BUFFER_LENGTH (PA_PAGE_SIZE*12) -#define CHECK_VALIDITY_RETURN_NULL(condition) \ -do {\ -if (!(condition)) \ - return NULL; \ -} while (0) +static PA_DEFINE_CHECK_TYPE(pa_sink, pa_msgobject); + +static void sink_free(pa_object *s); pa_sink* pa_sink_new( pa_core *core, @@ -63,68 +64,71 @@ pa_sink* pa_sink_new( pa_sink *s; char *n = NULL; char st[256]; - int r; pa_channel_map tmap; - assert(core); - assert(name); - assert(spec); + pa_assert(core); + pa_assert(name); + pa_assert(spec); - CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec)); + pa_return_null_if_fail(pa_sample_spec_valid(spec)); if (!map) map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT); - CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map)); - CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels); - CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver)); - CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name) && *name); + pa_return_null_if_fail(map && pa_channel_map_valid(map)); + pa_return_null_if_fail(map->channels == spec->channels); + pa_return_null_if_fail(!driver || pa_utf8_valid(driver)); + pa_return_null_if_fail(name && pa_utf8_valid(name) && *name); - s = pa_xnew(pa_sink, 1); + s = pa_msgobject_new(pa_sink); if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) { pa_xfree(s); return NULL; } - s->ref = 1; + s->parent.parent.free = sink_free; + s->parent.process_msg = pa_sink_process_msg; + s->core = core; - s->state = PA_SINK_RUNNING; + s->state = PA_SINK_INIT; + s->flags = 0; s->name = pa_xstrdup(name); s->description = NULL; s->driver = pa_xstrdup(driver); - s->owner = NULL; + s->module = NULL; s->sample_spec = *spec; s->channel_map = *map; s->inputs = pa_idxset_new(NULL, NULL); + s->n_corked = 0; - pa_cvolume_reset(&s->sw_volume, spec->channels); - pa_cvolume_reset(&s->hw_volume, spec->channels); - s->sw_muted = 0; - s->hw_muted = 0; - - s->is_hardware = 0; + pa_cvolume_reset(&s->volume, spec->channels); + s->muted = FALSE; + s->refresh_volume = s->refresh_mute = FALSE; s->get_latency = NULL; - s->notify = NULL; - s->set_hw_volume = NULL; - s->get_hw_volume = NULL; - s->set_hw_mute = NULL; - s->get_hw_mute = NULL; + s->set_volume = NULL; + s->get_volume = NULL; + s->set_mute = NULL; + s->get_mute = NULL; + s->set_state = NULL; s->userdata = NULL; - r = pa_idxset_put(core->sinks, s, &s->index); - assert(s->index != PA_IDXSET_INVALID && r >= 0); + s->asyncmsgq = NULL; + s->rtpoll = NULL; + s->silence = NULL; + + pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0); pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info("created %u \"%s\" with sample spec \"%s\"", s->index, s->name, st); + pa_log_info("Created sink %u \"%s\" with sample spec \"%s\"", s->index, s->name, st); n = pa_sprintf_malloc("%s.monitor", name); if (!(s->monitor_source = pa_source_new(core, driver, n, 0, spec, map))) - pa_log_warn("failed to create monitor source."); + pa_log_warn("Failed to create monitor source."); else { char *d; s->monitor_source->monitor_of = s; @@ -135,51 +139,124 @@ pa_sink* pa_sink_new( pa_xfree(n); - pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index); + s->thread_info.inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + s->thread_info.soft_volume = s->volume; + s->thread_info.soft_muted = s->muted; + s->thread_info.state = s->state; return s; } -void pa_sink_disconnect(pa_sink* s) { +static int sink_set_state(pa_sink *s, pa_sink_state_t state) { + int ret; + + pa_assert(s); + + if (s->state == state) + return 0; + + if ((s->state == PA_SINK_SUSPENDED && PA_SINK_OPENED(state)) || + (PA_SINK_OPENED(s->state) && state == PA_SINK_SUSPENDED)) { + pa_sink_input *i; + uint32_t idx; + + /* We're suspending or resuming, tell everyone about it */ + + for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) + if (i->suspend) + i->suspend(i, state == PA_SINK_SUSPENDED); + } + + if (s->set_state) + if ((ret = s->set_state(s, state)) < 0) + return -1; + + if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) < 0) + return -1; + + s->state = state; + + if (state != PA_SINK_UNLINKED) /* if we enter UNLINKED state pa_sink_unlink() will fire the apropriate events */ + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], s); + return 0; +} + +void pa_sink_put(pa_sink* s) { + pa_sink_assert_ref(s); + + pa_assert(s->state == PA_SINK_INIT); + pa_assert(s->asyncmsgq); + pa_assert(s->rtpoll); + + pa_assert_se(sink_set_state(s, PA_SINK_IDLE) == 0); + + pa_source_put(s->monitor_source); + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index); + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_NEW_POST], s); +} + +void pa_sink_unlink(pa_sink* s) { + pa_bool_t linked; pa_sink_input *i, *j = NULL; - assert(s); - assert(s->state == PA_SINK_RUNNING); + pa_assert(s); + + /* Please note that pa_sink_unlink() does more than simply + * reversing pa_sink_put(). It also undoes the registrations + * already done in pa_sink_new()! */ - s->state = PA_SINK_DISCONNECTED; - pa_namereg_unregister(s->core, s->name); + /* All operations here shall be idempotent, i.e. pa_sink_unlink() + * may be called multiple times on the same sink without bad + * effects. */ - pa_hook_fire(&s->core->hook_sink_disconnect, s); + linked = PA_SINK_LINKED(s->state); + + if (linked) + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK], s); + + if (s->state != PA_SINK_UNLINKED) + pa_namereg_unregister(s->core, s->name); + pa_idxset_remove_by_data(s->core->sinks, s, NULL); while ((i = pa_idxset_first(s->inputs, NULL))) { - assert(i != j); + pa_assert(i != j); pa_sink_input_kill(i); j = i; } - if (s->monitor_source) - pa_source_disconnect(s->monitor_source); - - pa_idxset_remove_by_data(s->core->sinks, s, NULL); + if (linked) + sink_set_state(s, PA_SINK_UNLINKED); + else + s->state = PA_SINK_UNLINKED; s->get_latency = NULL; - s->notify = NULL; - s->get_hw_volume = NULL; - s->set_hw_volume = NULL; - s->set_hw_mute = NULL; - s->get_hw_mute = NULL; + s->get_volume = NULL; + s->set_volume = NULL; + s->set_mute = NULL; + s->get_mute = NULL; + s->set_state = NULL; - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); + if (s->monitor_source) + pa_source_unlink(s->monitor_source); + + if (linked) { + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], s); + } } -static void sink_free(pa_sink *s) { - assert(s); - assert(!s->ref); +static void sink_free(pa_object *o) { + pa_sink *s = PA_SINK(o); + pa_sink_input *i; + + pa_assert(s); + pa_assert(pa_sink_refcnt(s) == 0); - if (s->state != PA_SINK_DISCONNECTED) - pa_sink_disconnect(s); + if (PA_SINK_LINKED(s->state)) + pa_sink_unlink(s); - pa_log_info("freed %u \"%s\"", s->index, s->name); + pa_log_info("Freeing sink %u \"%s\"", s->index, s->name); if (s->monitor_source) { pa_source_unref(s->monitor_source); @@ -188,108 +265,192 @@ static void sink_free(pa_sink *s) { pa_idxset_free(s->inputs, NULL, NULL); + while ((i = pa_hashmap_steal_first(s->thread_info.inputs))) + pa_sink_input_unref(i); + + pa_hashmap_free(s->thread_info.inputs, NULL, NULL); + + if (s->silence) + pa_memblock_unref(s->silence); + pa_xfree(s->name); pa_xfree(s->description); pa_xfree(s->driver); pa_xfree(s); } -void pa_sink_unref(pa_sink*s) { - assert(s); - assert(s->ref >= 1); +void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) { + pa_sink_assert_ref(s); + pa_assert(q); + + s->asyncmsgq = q; - if (!(--s->ref)) - sink_free(s); + if (s->monitor_source) + pa_source_set_asyncmsgq(s->monitor_source, q); } -pa_sink* pa_sink_ref(pa_sink *s) { - assert(s); - assert(s->ref >= 1); +void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) { + pa_sink_assert_ref(s); + pa_assert(p); - s->ref++; - return s; + s->rtpoll = p; + if (s->monitor_source) + pa_source_set_rtpoll(s->monitor_source, p); +} + +int pa_sink_update_status(pa_sink*s) { + pa_sink_assert_ref(s); + pa_assert(PA_SINK_LINKED(s->state)); + + if (s->state == PA_SINK_SUSPENDED) + return 0; + + return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE); +} + +int pa_sink_suspend(pa_sink *s, pa_bool_t suspend) { + pa_sink_assert_ref(s); + pa_assert(PA_SINK_LINKED(s->state)); + + if (suspend) + return sink_set_state(s, PA_SINK_SUSPENDED); + else + return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE); } -void pa_sink_notify(pa_sink*s) { - assert(s); - assert(s->ref >= 1); +void pa_sink_ping(pa_sink *s) { + pa_sink_assert_ref(s); + pa_assert(PA_SINK_LINKED(s->state)); - if (s->notify) - s->notify(s); + pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_PING, NULL, 0, NULL, NULL); } -static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) { - uint32_t idx = PA_IDXSET_INVALID; +static unsigned fill_mix_info(pa_sink *s, size_t length, pa_mix_info *info, unsigned maxinfo) { pa_sink_input *i; unsigned n = 0; + void *state = NULL; - assert(s); - assert(s->ref >= 1); - assert(info); + pa_sink_assert_ref(s); + pa_assert(info); - for (i = pa_idxset_first(s->inputs, &idx); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &idx)) { - /* Increase ref counter, to make sure that this input doesn't - * vanish while we still need it */ - pa_sink_input_ref(i); + while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)) && maxinfo > 0) { + pa_sink_input_assert_ref(i); - if (pa_sink_input_peek(i, &info->chunk, &info->volume) < 0) { - pa_sink_input_unref(i); + if (pa_sink_input_peek(i, length, &info->chunk, &info->volume) < 0) continue; - } - info->userdata = i; + info->userdata = pa_sink_input_ref(i); - assert(info->chunk.memblock); - assert(info->chunk.memblock->data); - assert(info->chunk.length); + pa_assert(info->chunk.memblock); + pa_assert(info->chunk.length > 0); info++; - maxinfo--; n++; + maxinfo--; } return n; } -static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned maxinfo, size_t length) { - assert(s); - assert(s->ref >= 1); - assert(info); +static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, size_t length) { + pa_sink_input *i; + void *state = NULL; + unsigned p = 0; + unsigned n_unreffed = 0; + + pa_sink_assert_ref(s); + + /* We optimize for the case where the order of the inputs has not changed */ + + while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) { + unsigned j; + pa_mix_info* m; + + pa_sink_input_assert_ref(i); - for (; maxinfo > 0; maxinfo--, info++) { - pa_sink_input *i = info->userdata; + m = NULL; - assert(i); - assert(info->chunk.memblock); + /* Let's try to find the matching entry info the pa_mix_info array */ + for (j = 0; j < n; j ++) { + + if (info[p].userdata == i) { + m = info + p; + break; + } + + p++; + if (p >= n) + p = 0; + } /* Drop read data */ - pa_sink_input_drop(i, &info->chunk, length); - pa_memblock_unref(info->chunk.memblock); + pa_sink_input_drop(i, length); - /* Decrease ref counter */ - pa_sink_input_unref(i); - info->userdata = NULL; + if (m) { + pa_sink_input_unref(m->userdata); + m->userdata = NULL; + if (m->chunk.memblock) + pa_memblock_unref(m->chunk.memblock); + pa_memchunk_reset(&m->chunk); + + n_unreffed += 1; + } + } + + /* Now drop references to entries that are included in the + * pa_mix_info array but don't exist anymore */ + + if (n_unreffed < n) { + for (; n > 0; info++, n--) { + if (info->userdata) + pa_sink_input_unref(info->userdata); + if (info->chunk.memblock) + pa_memblock_unref(info->chunk.memblock); + } } } -int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { +void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; - int r = -1; + size_t block_size_max; - assert(s); - assert(s->ref >= 1); - assert(length); - assert(result); + pa_sink_assert_ref(s); + pa_assert(PA_SINK_OPENED(s->thread_info.state)); + pa_assert(pa_frame_aligned(length, &s->sample_spec)); + pa_assert(result); pa_sink_ref(s); - n = fill_mix_info(s, info, MAX_MIX_CHANNELS); + if (length <= 0) + length = pa_frame_align(MIX_BUFFER_LENGTH, &s->sample_spec); + + block_size_max = pa_mempool_block_size_max(s->core->mempool); + if (length > block_size_max) + length = pa_frame_align(block_size_max, &s->sample_spec); + + pa_assert(length > 0); + + n = s->thread_info.state == PA_SINK_RUNNING ? fill_mix_info(s, length, info, MAX_MIX_CHANNELS) : 0; + + if (n == 0) { + + if (length > SILENCE_BUFFER_LENGTH) + length = pa_frame_align(SILENCE_BUFFER_LENGTH, &s->sample_spec); - if (n <= 0) - goto finish; + pa_assert(length > 0); - if (n == 1) { + if (!s->silence || pa_memblock_get_length(s->silence) < length) { + if (s->silence) + pa_memblock_unref(s->silence); + s->silence = pa_silence_memblock_new(s->core->mempool, &s->sample_spec, length); + } + + result->memblock = pa_memblock_ref(s->silence); + result->length = length; + result->index = 0; + + } else if (n == 1) { pa_cvolume volume; *result = info[0].chunk; @@ -298,105 +459,112 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { if (result->length > length) result->length = length; - pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); + pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume); - if (s->sw_muted || !pa_cvolume_is_norm(&volume)) { + if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) { pa_memchunk_make_writable(result, 0); - if (s->sw_muted) + if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume)) pa_silence_memchunk(result, &s->sample_spec); else pa_volume_memchunk(result, &s->sample_spec, &volume); } } else { + void *ptr; result->memblock = pa_memblock_new(s->core->mempool, length); - assert(result->memblock); -/* pa_log("mixing %i", n); */ + ptr = pa_memblock_acquire(result->memblock); + result->length = pa_mix(info, n, ptr, length, &s->sample_spec, &s->thread_info.soft_volume, s->thread_info.soft_muted); + pa_memblock_release(result->memblock); - result->length = pa_mix(info, n, result->memblock->data, length, - &s->sample_spec, &s->sw_volume, s->sw_muted); result->index = 0; } - inputs_drop(s, info, n, result->length); + if (s->thread_info.state == PA_SINK_RUNNING) + inputs_drop(s, info, n, result->length); - if (s->monitor_source) + if (s->monitor_source && PA_SOURCE_OPENED(pa_source_get_state(s->monitor_source))) pa_source_post(s->monitor_source, result); - r = 0; - -finish: pa_sink_unref(s); - - return r; } -int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { +void pa_sink_render_into(pa_sink*s, pa_memchunk *target) { pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; - int r = -1; - assert(s); - assert(s->ref >= 1); - assert(target); - assert(target->memblock); - assert(target->length); - assert(target->memblock->data); + pa_sink_assert_ref(s); + pa_assert(PA_SINK_OPENED(s->thread_info.state)); + pa_assert(target); + pa_assert(target->memblock); + pa_assert(target->length > 0); + pa_assert(pa_frame_aligned(target->length, &s->sample_spec)); pa_sink_ref(s); - n = fill_mix_info(s, info, MAX_MIX_CHANNELS); - - if (n <= 0) - goto finish; - - if (n == 1) { - pa_cvolume volume; + n = s->thread_info.state == PA_SINK_RUNNING ? fill_mix_info(s, target->length, info, MAX_MIX_CHANNELS) : 0; + if (n == 0) { + pa_silence_memchunk(target, &s->sample_spec); + } else if (n == 1) { if (target->length > info[0].chunk.length) target->length = info[0].chunk.length; - memcpy((uint8_t*) target->memblock->data + target->index, - (uint8_t*) info[0].chunk.memblock->data + info[0].chunk.index, - target->length); + if (s->thread_info.soft_muted) + pa_silence_memchunk(target, &s->sample_spec); + else { + void *src, *ptr; + pa_cvolume volume; - pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); + ptr = pa_memblock_acquire(target->memblock); + src = pa_memblock_acquire(info[0].chunk.memblock); + + memcpy((uint8_t*) ptr + target->index, + (uint8_t*) src + info[0].chunk.index, + target->length); + + pa_memblock_release(target->memblock); + pa_memblock_release(info[0].chunk.memblock); + + pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume); + + if (!pa_cvolume_is_norm(&volume)) + pa_volume_memchunk(target, &s->sample_spec, &volume); + } + + } else { + void *ptr; + + ptr = pa_memblock_acquire(target->memblock); - if (s->sw_muted) - pa_silence_memchunk(target, &s->sample_spec); - else if (!pa_cvolume_is_norm(&volume)) - pa_volume_memchunk(target, &s->sample_spec, &volume); - } else target->length = pa_mix(info, n, - (uint8_t*) target->memblock->data + target->index, + (uint8_t*) ptr + target->index, target->length, &s->sample_spec, - &s->sw_volume, - s->sw_muted); + &s->thread_info.soft_volume, + s->thread_info.soft_muted); - inputs_drop(s, info, n, target->length); + pa_memblock_release(target->memblock); + } - if (s->monitor_source) - pa_source_post(s->monitor_source, target); + if (s->thread_info.state == PA_SINK_RUNNING) + inputs_drop(s, info, n, target->length); - r = 0; + if (s->monitor_source && PA_SOURCE_OPENED(pa_source_get_state(s->monitor_source))) + pa_source_post(s->monitor_source, target); -finish: pa_sink_unref(s); - - return r; } void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { pa_memchunk chunk; size_t l, d; - assert(s); - assert(s->ref >= 1); - assert(target); - assert(target->memblock); - assert(target->length); - assert(target->memblock->data); + pa_sink_assert_ref(s); + pa_assert(PA_SINK_OPENED(s->thread_info.state)); + pa_assert(target); + pa_assert(target->memblock); + pa_assert(target->length > 0); + pa_assert(pa_frame_aligned(target->length, &s->sample_spec)); pa_sink_ref(s); @@ -407,140 +575,177 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { chunk.index += d; chunk.length -= d; - if (pa_sink_render_into(s, &chunk) < 0) - break; + pa_sink_render_into(s, &chunk); d += chunk.length; l -= chunk.length; } - if (l > 0) { - chunk = *target; - chunk.index += d; - chunk.length -= d; - pa_silence_memchunk(&chunk, &s->sample_spec); - } - pa_sink_unref(s); } void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { - assert(s); - assert(s->ref >= 1); - assert(length); - assert(result); + pa_sink_assert_ref(s); + pa_assert(PA_SINK_OPENED(s->thread_info.state)); + pa_assert(length > 0); + pa_assert(pa_frame_aligned(length, &s->sample_spec)); + pa_assert(result); /*** This needs optimization ***/ - result->memblock = pa_memblock_new(s->core->mempool, result->length = length); result->index = 0; + result->length = length; + result->memblock = pa_memblock_new(s->core->mempool, length); pa_sink_render_into_full(s, result); } +void pa_sink_skip(pa_sink *s, size_t length) { + pa_sink_input *i; + void *state = NULL; + + pa_sink_assert_ref(s); + pa_assert(PA_SINK_OPENED(s->thread_info.state)); + pa_assert(length > 0); + pa_assert(pa_frame_aligned(length, &s->sample_spec)); + + if (pa_source_used_by(s->monitor_source)) { + pa_memchunk chunk; + + /* If something is connected to our monitor source, we have to + * pass valid data to it */ + + while (length > 0) { + pa_sink_render(s, length, &chunk); + pa_memblock_unref(chunk.memblock); + + pa_assert(chunk.length <= length); + length -= chunk.length; + } + + } else { + /* Ok, noone cares about the rendered data, so let's not even render it */ + + while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) { + pa_sink_input_assert_ref(i); + pa_sink_input_drop(i, length); + } + } +} + pa_usec_t pa_sink_get_latency(pa_sink *s) { - assert(s); - assert(s->ref >= 1); + pa_usec_t usec = 0; - if (!s->get_latency) + pa_sink_assert_ref(s); + pa_assert(PA_SINK_LINKED(s->state)); + + if (!PA_SINK_OPENED(s->state)) + return 0; + + if (s->get_latency) + return s->get_latency(s); + + if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0) return 0; - return s->get_latency(s); + return usec; } -void pa_sink_set_owner(pa_sink *s, pa_module *m) { - assert(s); - assert(s->ref >= 1); +void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume) { + int changed; - if (s->owner == m) - return; + pa_sink_assert_ref(s); + pa_assert(PA_SINK_LINKED(s->state)); + pa_assert(volume); - s->owner = m; + changed = !pa_cvolume_equal(volume, &s->volume); + s->volume = *volume; - if (s->monitor_source) - pa_source_set_owner(s->monitor_source, m); + if (s->set_volume && s->set_volume(s) < 0) + s->set_volume = NULL; - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + if (!s->set_volume) + pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), 0, NULL, pa_xfree); + + if (changed) + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } -void pa_sink_set_volume(pa_sink *s, pa_mixer_t m, const pa_cvolume *volume) { - pa_cvolume *v; +const pa_cvolume *pa_sink_get_volume(pa_sink *s) { + struct pa_cvolume old_volume; - assert(s); - assert(s->ref >= 1); - assert(volume); + pa_sink_assert_ref(s); + pa_assert(PA_SINK_LINKED(s->state)); - if (m == PA_MIXER_HARDWARE && s->set_hw_volume) - v = &s->hw_volume; - else - v = &s->sw_volume; + old_volume = s->volume; - if (pa_cvolume_equal(v, volume)) - return; + if (s->get_volume && s->get_volume(s) < 0) + s->get_volume = NULL; - *v = *volume; + if (!s->get_volume && s->refresh_volume) + pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, &s->volume, 0, NULL); - if (v == &s->hw_volume) - if (s->set_hw_volume(s) < 0) - s->sw_volume = *volume; + if (!pa_cvolume_equal(&old_volume, &s->volume)) + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + return &s->volume; } -const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_mixer_t m) { - assert(s); - assert(s->ref >= 1); +void pa_sink_set_mute(pa_sink *s, pa_bool_t mute) { + int changed; + + pa_sink_assert_ref(s); + pa_assert(PA_SINK_LINKED(s->state)); - if (m == PA_MIXER_HARDWARE && s->set_hw_volume) { + changed = s->muted != mute; + s->muted = mute; - if (s->get_hw_volume) - s->get_hw_volume(s); + if (s->set_mute && s->set_mute(s) < 0) + s->set_mute = NULL; - return &s->hw_volume; - } else - return &s->sw_volume; + if (!s->set_mute) + pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, PA_UINT_TO_PTR(mute), 0, NULL, NULL); + + if (changed) + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } -void pa_sink_set_mute(pa_sink *s, pa_mixer_t m, int mute) { - int *t; +pa_bool_t pa_sink_get_mute(pa_sink *s) { + pa_bool_t old_muted; - assert(s); - assert(s->ref >= 1); + pa_sink_assert_ref(s); + pa_assert(PA_SINK_LINKED(s->state)); - if (m == PA_MIXER_HARDWARE && s->set_hw_mute) - t = &s->hw_muted; - else - t = &s->sw_muted; + old_muted = s->muted; - if (!!*t == !!mute) - return; + if (s->get_mute && s->get_mute(s) < 0) + s->get_mute = NULL; - *t = !!mute; + if (!s->get_mute && s->refresh_mute) + pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, &s->muted, 0, NULL); - if (t == &s->hw_muted) - if (s->set_hw_mute(s) < 0) - s->sw_muted = !!mute; + if (old_muted != s->muted) + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + return s->muted; } -int pa_sink_get_mute(pa_sink *s, pa_mixer_t m) { - assert(s); - assert(s->ref >= 1); +void pa_sink_set_module(pa_sink *s, pa_module *m) { + pa_sink_assert_ref(s); - if (m == PA_MIXER_HARDWARE && s->set_hw_mute) { + if (s->module == m) + return; + + s->module = m; - if (s->get_hw_mute) - s->get_hw_mute(s); + if (s->monitor_source) + pa_source_set_module(s->monitor_source, m); - return s->hw_muted; - } else - return s->sw_muted; + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } void pa_sink_set_description(pa_sink *s, const char *description) { - assert(s); - assert(s->ref >= 1); + pa_sink_assert_ref(s); if (!description && !s->description) return; @@ -559,19 +764,298 @@ void pa_sink_set_description(pa_sink *s, const char *description) { pa_xfree(n); } - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + if (PA_SINK_LINKED(s->state)) { + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_DESCRIPTION_CHANGED], s); + } } -unsigned pa_sink_used_by(pa_sink *s) { +unsigned pa_sink_linked_by(pa_sink *s) { unsigned ret; - assert(s); - assert(s->ref >= 1); + pa_sink_assert_ref(s); + pa_assert(PA_SINK_LINKED(s->state)); ret = pa_idxset_size(s->inputs); + /* We add in the number of streams connected to us here. Please + * not the asymmmetry to pa_sink_used_by()! */ + if (s->monitor_source) - ret += pa_source_used_by(s->monitor_source); + ret += pa_source_linked_by(s->monitor_source); return ret; } + +unsigned pa_sink_used_by(pa_sink *s) { + unsigned ret; + + pa_sink_assert_ref(s); + pa_assert(PA_SINK_LINKED(s->state)); + + ret = pa_idxset_size(s->inputs); + pa_assert(ret >= s->n_corked); + ret -= s->n_corked; + + /* Streams connected to our monitor source do not matter for + * pa_sink_used_by()!.*/ + + return ret; +} + +int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) { + pa_sink *s = PA_SINK(o); + pa_sink_assert_ref(s); + pa_assert(s->thread_info.state != PA_SINK_UNLINKED); + + switch ((pa_sink_message_t) code) { + + case PA_SINK_MESSAGE_ADD_INPUT: { + pa_sink_input *i = PA_SINK_INPUT(userdata); + pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i)); + + /* Since the caller sleeps in pa_sink_input_put(), we can + * safely access data outside of thread_info even though + * it is mutable */ + + if ((i->thread_info.sync_prev = i->sync_prev)) { + pa_assert(i->sink == i->thread_info.sync_prev->sink); + pa_assert(i->sync_prev->sync_next == i); + i->thread_info.sync_prev->thread_info.sync_next = i; + } + + if ((i->thread_info.sync_next = i->sync_next)) { + pa_assert(i->sink == i->thread_info.sync_next->sink); + pa_assert(i->sync_next->sync_prev == i); + i->thread_info.sync_next->thread_info.sync_prev = i; + } + + pa_assert(!i->thread_info.attached); + i->thread_info.attached = TRUE; + + if (i->attach) + i->attach(i); + + /* If you change anything here, make sure to change the + * ghost sink input handling a few lines down at + * PA_SINK_MESSAGE_REMOVE_INPUT_AND_BUFFER, too. */ + + return 0; + } + + case PA_SINK_MESSAGE_REMOVE_INPUT: { + pa_sink_input *i = PA_SINK_INPUT(userdata); + + /* If you change anything here, make sure to change the + * sink input handling a few lines down at + * PA_SINK_MESSAGE_REMOVE_INPUT_AND_BUFFER, too. */ + + if (i->detach) + i->detach(i); + + pa_assert(i->thread_info.attached); + i->thread_info.attached = FALSE; + + /* Since the caller sleeps in pa_sink_input_unlink(), + * we can safely access data outside of thread_info even + * though it is mutable */ + + pa_assert(!i->thread_info.sync_prev); + pa_assert(!i->thread_info.sync_next); + + if (i->thread_info.sync_prev) { + i->thread_info.sync_prev->thread_info.sync_next = i->thread_info.sync_prev->sync_next; + i->thread_info.sync_prev = NULL; + } + + if (i->thread_info.sync_next) { + i->thread_info.sync_next->thread_info.sync_prev = i->thread_info.sync_next->sync_prev; + i->thread_info.sync_next = NULL; + } + + if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index))) + pa_sink_input_unref(i); + + return 0; + } + + case PA_SINK_MESSAGE_REMOVE_INPUT_AND_BUFFER: { + pa_sink_input_move_info *info = userdata; + int volume_is_norm; + + /* We don't support moving synchronized streams. */ + pa_assert(!info->sink_input->sync_prev); + pa_assert(!info->sink_input->sync_next); + pa_assert(!info->sink_input->thread_info.sync_next); + pa_assert(!info->sink_input->thread_info.sync_prev); + + if (info->sink_input->detach) + info->sink_input->detach(info->sink_input); + + pa_assert(info->sink_input->thread_info.attached); + info->sink_input->thread_info.attached = FALSE; + + if (info->ghost_sink_input) { + pa_assert(info->buffer_bytes > 0); + pa_assert(info->buffer); + + volume_is_norm = pa_cvolume_is_norm(&info->sink_input->thread_info.volume); + + pa_log_debug("Buffering %lu bytes ...", (unsigned long) info->buffer_bytes); + + while (info->buffer_bytes > 0) { + pa_memchunk memchunk; + pa_cvolume volume; + size_t n; + + if (pa_sink_input_peek(info->sink_input, info->buffer_bytes, &memchunk, &volume) < 0) + break; + + n = memchunk.length > info->buffer_bytes ? info->buffer_bytes : memchunk.length; + pa_sink_input_drop(info->sink_input, n); + memchunk.length = n; + + if (!volume_is_norm) { + pa_memchunk_make_writable(&memchunk, 0); + pa_volume_memchunk(&memchunk, &s->sample_spec, &volume); + } + + if (pa_memblockq_push(info->buffer, &memchunk) < 0) { + pa_memblock_unref(memchunk.memblock); + break; + } + + pa_memblock_unref(memchunk.memblock); + info->buffer_bytes -= n; + } + + /* Add the remaining already resampled chunk to the buffer */ + if (info->sink_input->thread_info.resampled_chunk.memblock) + pa_memblockq_push(info->buffer, &info->sink_input->thread_info.resampled_chunk); + + pa_memblockq_sink_input_set_queue(info->ghost_sink_input, info->buffer); + + pa_log_debug("Buffered %lu bytes ...", (unsigned long) pa_memblockq_get_length(info->buffer)); + } + + /* Let's remove the sink input ...*/ + if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(info->sink_input->index))) + pa_sink_input_unref(info->sink_input); + + /* .. and add the ghost sink input instead */ + if (info->ghost_sink_input) { + pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(info->ghost_sink_input->index), pa_sink_input_ref(info->ghost_sink_input)); + info->ghost_sink_input->thread_info.sync_prev = info->ghost_sink_input->thread_info.sync_next = NULL; + + pa_assert(!info->ghost_sink_input->thread_info.attached); + info->ghost_sink_input->thread_info.attached = TRUE; + + if (info->ghost_sink_input->attach) + info->ghost_sink_input->attach(info->ghost_sink_input); + } + + return 0; + } + + case PA_SINK_MESSAGE_SET_VOLUME: + s->thread_info.soft_volume = *((pa_cvolume*) userdata); + return 0; + + case PA_SINK_MESSAGE_SET_MUTE: + s->thread_info.soft_muted = PA_PTR_TO_UINT(userdata); + return 0; + + case PA_SINK_MESSAGE_GET_VOLUME: + *((pa_cvolume*) userdata) = s->thread_info.soft_volume; + return 0; + + case PA_SINK_MESSAGE_GET_MUTE: + *((pa_bool_t*) userdata) = s->thread_info.soft_muted; + return 0; + + case PA_SINK_MESSAGE_PING: + return 0; + + case PA_SINK_MESSAGE_SET_STATE: + + s->thread_info.state = PA_PTR_TO_UINT(userdata); + return 0; + + case PA_SINK_MESSAGE_DETACH: + + /* We're detaching all our input streams so that the + * asyncmsgq and rtpoll fields can be changed without + * problems */ + pa_sink_detach_within_thread(s); + break; + + case PA_SINK_MESSAGE_ATTACH: + + /* Reattach all streams */ + pa_sink_attach_within_thread(s); + break; + + case PA_SINK_MESSAGE_GET_LATENCY: + case PA_SINK_MESSAGE_MAX: + ; + } + + return -1; +} + +int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend) { + pa_sink *sink; + uint32_t idx; + int ret = 0; + + pa_core_assert_ref(c); + + for (sink = PA_SINK(pa_idxset_first(c->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(c->sinks, &idx))) + ret -= pa_sink_suspend(sink, suspend) < 0; + + return ret; +} + +void pa_sink_detach(pa_sink *s) { + pa_sink_assert_ref(s); + pa_assert(PA_SINK_LINKED(s->state)); + + pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_DETACH, NULL, 0, NULL); +} + +void pa_sink_attach(pa_sink *s) { + pa_sink_assert_ref(s); + pa_assert(PA_SINK_LINKED(s->state)); + + pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_ATTACH, NULL, 0, NULL); +} + +void pa_sink_detach_within_thread(pa_sink *s) { + pa_sink_input *i; + void *state = NULL; + + pa_sink_assert_ref(s); + pa_assert(PA_SINK_LINKED(s->thread_info.state)); + + while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) + if (i->detach) + i->detach(i); + + if (s->monitor_source) + pa_source_detach_within_thread(s->monitor_source); +} + +void pa_sink_attach_within_thread(pa_sink *s) { + pa_sink_input *i; + void *state = NULL; + + pa_sink_assert_ref(s); + pa_assert(PA_SINK_LINKED(s->thread_info.state)); + + while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) + if (i->attach) + i->attach(i); + + if (s->monitor_source) + pa_source_attach_within_thread(s->monitor_source); +} diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index ef73f67d..e9969309 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -1,5 +1,5 @@ -#ifndef foosinkhfoo -#define foosinkhfoo +#ifndef foopulsesinkhfoo +#define foopulsesinkhfoo /* $Id$ */ @@ -25,87 +25,164 @@ USA. ***/ -#include - typedef struct pa_sink pa_sink; +#include + #include #include #include + #include #include #include #include #include +#include +#include +#include #define PA_MAX_INPUTS_PER_SINK 32 typedef enum pa_sink_state { + PA_SINK_INIT, PA_SINK_RUNNING, - PA_SINK_DISCONNECTED + PA_SINK_SUSPENDED, + PA_SINK_IDLE, + PA_SINK_UNLINKED } pa_sink_state_t; +static inline pa_bool_t PA_SINK_OPENED(pa_sink_state_t x) { + return x == PA_SINK_RUNNING || x == PA_SINK_IDLE; +} + +static inline pa_bool_t PA_SINK_LINKED(pa_sink_state_t x) { + return x == PA_SINK_RUNNING || x == PA_SINK_IDLE || x == PA_SINK_SUSPENDED; +} + struct pa_sink { - int ref; + pa_msgobject parent; + uint32_t index; pa_core *core; pa_sink_state_t state; + pa_sink_flags_t flags; char *name; char *description, *driver; /* may be NULL */ - int is_hardware; - pa_module *owner; /* may be NULL */ + pa_module *module; /* may be NULL */ pa_sample_spec sample_spec; pa_channel_map channel_map; pa_idxset *inputs; - pa_source *monitor_source; /* may be NULL */ - - pa_cvolume hw_volume, sw_volume; - int hw_muted, sw_muted; - - void (*notify)(pa_sink*sink); /* may be NULL */ - pa_usec_t (*get_latency)(pa_sink *s); /* dito */ - int (*set_hw_volume)(pa_sink *s); /* dito */ - int (*get_hw_volume)(pa_sink *s); /* dito */ - int (*set_hw_mute)(pa_sink *s); /* dito */ - int (*get_hw_mute)(pa_sink *s); /* dito */ + unsigned n_corked; + pa_source *monitor_source; + + pa_cvolume volume; + pa_bool_t muted; + pa_bool_t refresh_volume; + pa_bool_t refresh_mute; + + int (*set_state)(pa_sink *s, pa_sink_state_t state); /* may be NULL */ + int (*set_volume)(pa_sink *s); /* dito */ + int (*get_volume)(pa_sink *s); /* dito */ + int (*get_mute)(pa_sink *s); /* dito */ + int (*set_mute)(pa_sink *s); /* dito */ + pa_usec_t (*get_latency)(pa_sink *s); /* dito */ + + pa_asyncmsgq *asyncmsgq; + pa_rtpoll *rtpoll; + + /* Contains copies of the above data so that the real-time worker + * thread can work without access locking */ + struct { + pa_sink_state_t state; + pa_hashmap *inputs; + pa_cvolume soft_volume; + pa_bool_t soft_muted; + } thread_info; + + pa_memblock *silence; void *userdata; }; +PA_DECLARE_CLASS(pa_sink); +#define PA_SINK(s) (pa_sink_cast(s)) + +typedef enum pa_sink_message { + PA_SINK_MESSAGE_ADD_INPUT, + PA_SINK_MESSAGE_REMOVE_INPUT, + PA_SINK_MESSAGE_GET_VOLUME, + PA_SINK_MESSAGE_SET_VOLUME, + PA_SINK_MESSAGE_GET_MUTE, + PA_SINK_MESSAGE_SET_MUTE, + PA_SINK_MESSAGE_GET_LATENCY, + PA_SINK_MESSAGE_SET_STATE, + PA_SINK_MESSAGE_PING, + PA_SINK_MESSAGE_REMOVE_INPUT_AND_BUFFER, + PA_SINK_MESSAGE_ATTACH, + PA_SINK_MESSAGE_DETACH, + PA_SINK_MESSAGE_MAX +} pa_sink_message_t; + +/* To be called exclusively by the sink driver, from main context */ + pa_sink* pa_sink_new( - pa_core *core, - const char *driver, - const char *name, - int namereg_fail, - const pa_sample_spec *spec, - const pa_channel_map *map); - -void pa_sink_disconnect(pa_sink* s); -void pa_sink_unref(pa_sink*s); -pa_sink* pa_sink_ref(pa_sink *s); - -int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result); -void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result); -int pa_sink_render_into(pa_sink*s, pa_memchunk *target); -void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target); + pa_core *core, + const char *driver, + const char *name, + int namereg_fail, + const pa_sample_spec *spec, + const pa_channel_map *map); + +void pa_sink_put(pa_sink *s); +void pa_sink_unlink(pa_sink* s); + +void pa_sink_set_module(pa_sink *sink, pa_module *m); +void pa_sink_set_description(pa_sink *s, const char *description); +void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q); +void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p); + +void pa_sink_detach(pa_sink *s); +void pa_sink_attach(pa_sink *s); + +/* May be called by everyone, from main context */ pa_usec_t pa_sink_get_latency(pa_sink *s); -void pa_sink_notify(pa_sink*s); +int pa_sink_update_status(pa_sink*s); +int pa_sink_suspend(pa_sink *s, pa_bool_t suspend); +int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend); -void pa_sink_set_owner(pa_sink *sink, pa_module *m); +/* Sends a ping message to the sink thread, to make it wake up and + * check for data to process even if there is no real message is + * sent */ +void pa_sink_ping(pa_sink *s); -void pa_sink_set_volume(pa_sink *sink, pa_mixer_t m, const pa_cvolume *volume); -const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_mixer_t m); -void pa_sink_set_mute(pa_sink *sink, pa_mixer_t m, int mute); -int pa_sink_get_mute(pa_sink *sink, pa_mixer_t m); +void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume); +const pa_cvolume *pa_sink_get_volume(pa_sink *sink); +void pa_sink_set_mute(pa_sink *sink, pa_bool_t mute); +pa_bool_t pa_sink_get_mute(pa_sink *sink); -void pa_sink_set_description(pa_sink *s, const char *description); +unsigned pa_sink_linked_by(pa_sink *s); /* Number of connected streams */ +unsigned pa_sink_used_by(pa_sink *s); /* Number of connected streams which are not corked */ +#define pa_sink_get_state(s) ((s)->state) + +/* To be called exclusively by the sink driver, from IO context */ + +void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result); +void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result); +void pa_sink_render_into(pa_sink*s, pa_memchunk *target); +void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target); + +void pa_sink_skip(pa_sink *s, size_t length); + +int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk); -unsigned pa_sink_used_by(pa_sink *s); +void pa_sink_attach_within_thread(pa_sink *s); +void pa_sink_detach_within_thread(pa_sink *s); #endif diff --git a/src/pulsecore/sioman.c b/src/pulsecore/sioman.c index d3d7538e..8d4c6fa7 100644 --- a/src/pulsecore/sioman.c +++ b/src/pulsecore/sioman.c @@ -25,21 +25,17 @@ #include #endif -#include +#include +#include #include "sioman.h" -static int stdio_inuse = 0; +static pa_atomic_t stdio_inuse = PA_ATOMIC_INIT(0); int pa_stdio_acquire(void) { - if (stdio_inuse) - return -1; - - stdio_inuse = 1; - return 0; + return pa_atomic_cmpxchg(&stdio_inuse, 0, 1) ? 0 : -1; } void pa_stdio_release(void) { - assert(stdio_inuse); - stdio_inuse = 0; + pa_assert_se(pa_atomic_cmpxchg(&stdio_inuse, 1, 0)); } diff --git a/src/pulsecore/socket-client.c b/src/pulsecore/socket-client.c index b99c8025..5b5bc5ca 100644 --- a/src/pulsecore/socket-client.c +++ b/src/pulsecore/socket-client.c @@ -1,25 +1,25 @@ /* $Id$ */ /*** - This file is part of PulseAudio. + This file is part of PulseAudio. - Copyright 2004-2006 Lennart Poettering - Copyright 2006-2007 Pierre Ossman for Cendio AB + Copyright 2004-2006 Lennart Poettering + Copyright 2006-2007 Pierre Ossman for Cendio AB - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public - License along with PulseAudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. ***/ #ifdef HAVE_CONFIG_H @@ -32,7 +32,6 @@ #include #include #include -#include #include #ifdef HAVE_SYS_SOCKET_H @@ -55,23 +54,24 @@ #include #endif -#include "winsock.h" - #include #include +#include #include #include #include #include #include +#include +#include #include "socket-client.h" #define CONNECT_TIMEOUT 5 struct pa_socket_client { - int ref; + PA_REFCNT_DECLARE; pa_mainloop_api *mainloop; int fd; pa_io_event *io_event; @@ -89,10 +89,10 @@ struct pa_socket_client { static pa_socket_client*pa_socket_client_new(pa_mainloop_api *m) { pa_socket_client *c; - assert(m); + pa_assert(m); - c = pa_xmalloc(sizeof(pa_socket_client)); - c->ref = 1; + c = pa_xnew(pa_socket_client, 1); + PA_REFCNT_INIT(c); c->mainloop = m; c->fd = -1; c->io_event = NULL; @@ -112,7 +112,7 @@ static pa_socket_client*pa_socket_client_new(pa_mainloop_api *m) { } static void free_events(pa_socket_client *c) { - assert(c); + pa_assert(c); if (c->io_event) { c->mainloop->io_free(c->io_event); @@ -134,7 +134,10 @@ static void do_call(pa_socket_client *c) { pa_iochannel *io = NULL; int error; socklen_t lerror; - assert(c && c->callback); + + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(c->callback); pa_socket_client_ref(c); @@ -153,13 +156,13 @@ static void do_call(pa_socket_client *c) { } if (error != 0) { - pa_log_debug("connect(): %s", pa_cstrerror(errno)); + pa_log_debug("connect(): %s", pa_cstrerror(error)); errno = error; goto finish; } io = pa_iochannel_new(c->mainloop, c->fd, c->fd); - assert(io); + pa_assert(io); finish: if (!io && c->fd >= 0) @@ -168,7 +171,7 @@ finish: free_events(c); - assert(c->callback); + pa_assert(c->callback); c->callback(c, io, c->userdata); pa_socket_client_unref(c); @@ -176,21 +179,36 @@ finish: static void connect_fixed_cb(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { pa_socket_client *c = userdata; - assert(m && c && c->defer_event == e); + + pa_assert(m); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(c->defer_event == e); + do_call(c); } static void connect_io_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { pa_socket_client *c = userdata; - assert(m && c && c->io_event == e && fd >= 0); + + pa_assert(m); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(c->io_event == e); + pa_assert(fd >= 0); + do_call(c); } static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t len) { int r; - assert(c && sa && len); - pa_make_nonblock_fd(c->fd); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(sa); + pa_assert(len > 0); + + pa_make_fd_nonblock(c->fd); if ((r = connect(c->fd, sa, len)) < 0) { #ifdef OS_IS_WIN32 @@ -203,19 +221,18 @@ static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t return -1; } - c->io_event = c->mainloop->io_new(c->mainloop, c->fd, PA_IO_EVENT_OUTPUT, connect_io_cb, c); - assert(c->io_event); - } else { - c->defer_event = c->mainloop->defer_new(c->mainloop, connect_fixed_cb, c); - assert(c->defer_event); - } + pa_assert_se(c->io_event = c->mainloop->io_new(c->mainloop, c->fd, PA_IO_EVENT_OUTPUT, connect_io_cb, c)); + } else + pa_assert_se(c->defer_event = c->mainloop->defer_new(c->mainloop, connect_fixed_cb, c)); return 0; } pa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port) { struct sockaddr_in sa; - assert(m && port > 0); + + pa_assert(m); + pa_assert(port > 0); memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; @@ -229,7 +246,9 @@ pa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) { struct sockaddr_un sa; - assert(m && filename); + + pa_assert(m); + pa_assert(filename); memset(&sa, 0, sizeof(sa)); sa.sun_family = AF_UNIX; @@ -248,9 +267,9 @@ pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *file #endif /* HAVE_SYS_UN_H */ static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size_t salen) { - assert(c); - assert(sa); - assert(salen); + pa_assert(c); + pa_assert(sa); + pa_assert(salen); switch (sa->sa_family) { case AF_UNIX: @@ -274,11 +293,11 @@ static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size return -1; } - pa_fd_set_cloexec(c->fd, 1); + pa_make_fd_cloexec(c->fd); if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) - pa_socket_tcp_low_delay(c->fd); + pa_make_tcp_socket_low_delay(c->fd); else - pa_socket_low_delay(c->fd); + pa_make_socket_low_delay(c->fd); if (do_connect(c, sa, salen) < 0) return -1; @@ -288,9 +307,12 @@ static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) { pa_socket_client *c; - assert(m && sa); - c = pa_socket_client_new(m); - assert(c); + + pa_assert(m); + pa_assert(sa); + pa_assert(salen > 0); + + pa_assert_se(c = pa_socket_client_new(m)); if (sockaddr_prepare(c, sa, salen) < 0) goto fail; @@ -300,12 +322,11 @@ pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct fail: pa_socket_client_unref(c); return NULL; - } static void socket_client_free(pa_socket_client *c) { - assert(c && c->mainloop); - + pa_assert(c); + pa_assert(c->mainloop); free_events(c); @@ -325,20 +346,25 @@ static void socket_client_free(pa_socket_client *c) { } void pa_socket_client_unref(pa_socket_client *c) { - assert(c && c->ref >= 1); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); - if (!(--(c->ref))) + if (PA_REFCNT_DEC(c) <= 0) socket_client_free(c); } pa_socket_client* pa_socket_client_ref(pa_socket_client *c) { - assert(c && c->ref >= 1); - c->ref++; + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + + PA_REFCNT_INC(c); return c; } void pa_socket_client_set_callback(pa_socket_client *c, void (*on_connection)(pa_socket_client *c, pa_iochannel*io, void *userdata), void *userdata) { - assert(c); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + c->callback = on_connection; c->userdata = userdata; } @@ -346,6 +372,10 @@ void pa_socket_client_set_callback(pa_socket_client *c, void (*on_connection)(pa pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[16], uint16_t port) { struct sockaddr_in6 sa; + pa_assert(m); + pa_assert(address); + pa_assert(port > 0); + memset(&sa, 0, sizeof(sa)); sa.sin6_family = AF_INET6; sa.sin6_port = htons(port); @@ -360,7 +390,12 @@ static void asyncns_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_socket_client *c = userdata; struct addrinfo *res = NULL; int ret; - assert(m && c && c->asyncns_io_event == e && fd >= 0); + + pa_assert(m); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + pa_assert(c->asyncns_io_event == e); + pa_assert(fd >= 0); if (asyncns_wait(c->asyncns, 0) < 0) goto fail; @@ -397,10 +432,11 @@ fail: static void timeout_cb(pa_mainloop_api *m, pa_time_event *e, const struct timeval *tv, void *userdata) { pa_socket_client *c = userdata; - assert(m); - assert(e); - assert(tv); - assert(c); + + pa_assert(m); + pa_assert(e); + pa_assert(tv); + pa_assert(c); if (c->fd >= 0) { pa_close(c->fd); @@ -413,8 +449,8 @@ static void timeout_cb(pa_mainloop_api *m, pa_time_event *e, const struct timeva static void start_timeout(pa_socket_client *c) { struct timeval tv; - assert(c); - assert(!c->timeout_event); + pa_assert(c); + pa_assert(!c->timeout_event); pa_gettimeofday(&tv); pa_timeval_add(&tv, CONNECT_TIMEOUT * 1000000); @@ -424,7 +460,9 @@ static void start_timeout(pa_socket_client *c) { pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*name, uint16_t default_port) { pa_socket_client *c = NULL; pa_parsed_address a; - assert(m && name); + + pa_assert(m); + pa_assert(name); if (pa_parse_address(name, &a) < 0) return NULL; @@ -435,7 +473,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam switch (a.type) { case PA_PARSED_ADDRESS_UNIX: if ((c = pa_socket_client_new_unix(m, a.path_or_host))) - start_timeout(c); + start_timeout(c); break; case PA_PARSED_ADDRESS_TCP4: /* Fallthrough */ @@ -445,7 +483,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam struct addrinfo hints; char port[12]; - snprintf(port, sizeof(port), "%u", (unsigned) a.port); + pa_snprintf(port, sizeof(port), "%u", (unsigned) a.port); memset(&hints, 0, sizeof(hints)); hints.ai_family = a.type == PA_PARSED_ADDRESS_TCP4 ? PF_INET : (a.type == PA_PARSED_ADDRESS_TCP6 ? PF_INET6 : PF_UNSPEC); @@ -462,7 +500,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam c->asyncns = asyncns; c->asyncns_io_event = m->io_new(m, asyncns_fd(c->asyncns), PA_IO_EVENT_INPUT, asyncns_cb, c); c->asyncns_query = asyncns_getaddrinfo(c->asyncns, a.path_or_host, port, &hints); - assert(c->asyncns_query); + pa_assert(c->asyncns_query); start_timeout(c); } #else /* HAVE_LIBASYNCNS */ @@ -479,7 +517,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam if (res->ai_addr) { if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen))) start_timeout(c); - } + } freeaddrinfo(res); #else /* HAVE_GETADDRINFO */ @@ -507,7 +545,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam s.sin_port = htons(a.port); if ((c = pa_socket_client_new_sockaddr(m, (struct sockaddr*)&s, sizeof(s)))) - start_timeout(c); + start_timeout(c); #endif /* HAVE_GETADDRINFO */ } #endif /* HAVE_LIBASYNCNS */ @@ -524,6 +562,8 @@ finish: local. "local" means UNIX socket or TCP socket on localhost. Other local IP addresses are not considered local. */ int pa_socket_client_is_local(pa_socket_client *c) { - assert(c); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + return c->local; } diff --git a/src/pulsecore/socket-server.c b/src/pulsecore/socket-server.c index b5a6dc31..162a1aac 100644 --- a/src/pulsecore/socket-server.c +++ b/src/pulsecore/socket-server.c @@ -27,7 +27,6 @@ #endif #include -#include #include #include #include @@ -72,12 +71,14 @@ #include #include #include +#include #include +#include #include "socket-server.h" struct pa_socket_server { - int ref; + PA_REFCNT_DECLARE; int fd; char *filename; char *tcpwrap_service; @@ -94,7 +95,14 @@ static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_U pa_socket_server *s = userdata; pa_iochannel *io; int nfd; - assert(s && s->mainloop == mainloop && s->io_event == e && e && fd >= 0 && fd == s->fd); + + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + pa_assert(s->mainloop == mainloop); + pa_assert(s->io_event == e); + pa_assert(e); + pa_assert(fd >= 0); + pa_assert(fd == s->fd); pa_socket_server_ref(s); @@ -103,7 +111,7 @@ static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_U goto finish; } - pa_fd_set_cloexec(nfd, 1); + pa_make_fd_cloexec(nfd); if (!s->on_connection) { pa_close(nfd); @@ -129,12 +137,11 @@ static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_U /* There should be a check for socket type here */ if (s->type == SOCKET_SERVER_IPV4) - pa_socket_tcp_low_delay(fd); + pa_make_tcp_socket_low_delay(fd); else - pa_socket_low_delay(fd); + pa_make_socket_low_delay(fd); - io = pa_iochannel_new(s->mainloop, nfd, nfd); - assert(io); + pa_assert_se(io = pa_iochannel_new(s->mainloop, nfd, nfd)); s->on_connection(s, io, s->userdata); finish: @@ -143,10 +150,12 @@ finish: pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) { pa_socket_server *s; - assert(m && fd >= 0); - s = pa_xmalloc(sizeof(pa_socket_server)); - s->ref = 1; + pa_assert(m); + pa_assert(fd >= 0); + + s = pa_xnew(pa_socket_server, 1); + PA_REFCNT_INIT(s); s->fd = fd; s->filename = NULL; s->on_connection = NULL; @@ -154,8 +163,7 @@ pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) { s->tcpwrap_service = NULL; s->mainloop = m; - s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s); - assert(s->io_event); + pa_assert_se(s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s)); s->type = SOCKET_SERVER_GENERIC; @@ -163,8 +171,10 @@ pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) { } pa_socket_server* pa_socket_server_ref(pa_socket_server *s) { - assert(s && s->ref >= 1); - s->ref++; + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + + PA_REFCNT_INC(s); return s; } @@ -175,20 +185,21 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file struct sockaddr_un sa; pa_socket_server *s; - assert(m && filename); + pa_assert(m); + pa_assert(filename); if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { pa_log("socket(): %s", pa_cstrerror(errno)); goto fail; } - pa_fd_set_cloexec(fd, 1); + pa_make_fd_cloexec(fd); sa.sun_family = AF_UNIX; strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); sa.sun_path[sizeof(sa.sun_path) - 1] = 0; - pa_socket_low_delay(fd); + pa_make_socket_low_delay(fd); if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) { pa_log("bind(): %s", pa_cstrerror(errno)); @@ -206,8 +217,7 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file goto fail; } - s = pa_socket_server_new(m, fd); - assert(s); + pa_assert_se(s = pa_socket_server_new(m, fd)); s->filename = pa_xstrdup(filename); s->type = SOCKET_SERVER_UNIX; @@ -235,21 +245,22 @@ pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address struct sockaddr_in sa; int on = 1; - assert(m && port); + pa_assert(m); + pa_assert(port); if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { pa_log("socket(PF_INET): %s", pa_cstrerror(errno)); goto fail; } - pa_fd_set_cloexec(fd, 1); + pa_make_fd_cloexec(fd); #ifdef SO_REUSEADDR if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) pa_log("setsockopt(): %s", pa_cstrerror(errno)); #endif - pa_socket_tcp_low_delay(fd); + pa_make_tcp_socket_low_delay(fd); memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; @@ -286,14 +297,15 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad struct sockaddr_in6 sa; int on = 1; - assert(m && port); + pa_assert(m); + pa_assert(port > 0); if ((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) { pa_log("socket(PF_INET6): %s", pa_cstrerror(errno)); goto fail; } - pa_fd_set_cloexec(fd, 1); + pa_make_fd_cloexec(fd); #ifdef IPV6_V6ONLY if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) @@ -305,7 +317,7 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad pa_log("setsockopt(SOL_SOCKET, SO_REUSEADDR, 1): %s", pa_cstrerror(errno)); #endif - pa_socket_tcp_low_delay(fd); + pa_make_tcp_socket_low_delay(fd); memset(&sa, 0, sizeof(sa)); sa.sin6_family = AF_INET6; @@ -337,29 +349,29 @@ fail: } pa_socket_server* pa_socket_server_new_ipv4_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { - assert(m); - assert(port > 0); + pa_assert(m); + pa_assert(port > 0); return pa_socket_server_new_ipv4(m, INADDR_LOOPBACK, port, tcpwrap_service); } pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { - assert(m); - assert(port > 0); + pa_assert(m); + pa_assert(port > 0); return pa_socket_server_new_ipv6(m, in6addr_loopback.s6_addr, port, tcpwrap_service); } pa_socket_server* pa_socket_server_new_ipv4_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { - assert(m); - assert(port > 0); + pa_assert(m); + pa_assert(port > 0); return pa_socket_server_new_ipv4(m, INADDR_ANY, port, tcpwrap_service); } pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) { - assert(m); - assert(port > 0); + pa_assert(m); + pa_assert(port > 0); return pa_socket_server_new_ipv6(m, in6addr_any.s6_addr, port, tcpwrap_service); } @@ -367,9 +379,9 @@ pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t por pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) { struct in_addr ipv4; - assert(m); - assert(name); - assert(port > 0); + pa_assert(m); + pa_assert(name); + pa_assert(port > 0); if (inet_pton(AF_INET, name, &ipv4) > 0) return pa_socket_server_new_ipv4(m, ntohl(ipv4.s_addr), port, tcpwrap_service); @@ -380,9 +392,9 @@ pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const cha pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) { struct in6_addr ipv6; - assert(m); - assert(name); - assert(port > 0); + pa_assert(m); + pa_assert(name); + pa_assert(port > 0); if (inet_pton(AF_INET6, name, &ipv6) > 0) return pa_socket_server_new_ipv6(m, ipv6.s6_addr, port, tcpwrap_service); @@ -391,7 +403,7 @@ pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const cha } static void socket_server_free(pa_socket_server*s) { - assert(s); + pa_assert(s); if (s->filename) { unlink(s->filename); @@ -407,21 +419,26 @@ static void socket_server_free(pa_socket_server*s) { } void pa_socket_server_unref(pa_socket_server *s) { - assert(s && s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); - if (!(--(s->ref))) + if (PA_REFCNT_DEC(s) <= 0) socket_server_free(s); } void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata), void *userdata) { - assert(s && s->ref >= 1); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); s->on_connection = on_connection; s->userdata = userdata; } char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { - assert(s && c && l > 0); + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + pa_assert(c); + pa_assert(l > 0); switch (s->type) { case SOCKET_SERVER_IPV6: { @@ -438,14 +455,14 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { if (!pa_get_fqdn(fqdn, sizeof(fqdn))) return NULL; - snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port)); + pa_snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port)); } else if (memcmp(&in6addr_loopback, &sa.sin6_addr, sizeof(in6addr_loopback)) == 0) { char hn[256]; if (!pa_get_host_name(hn, sizeof(hn))) return NULL; - snprintf(c, l, "{%s}tcp6:localhost:%u", hn, (unsigned) ntohs(sa.sin6_port)); + pa_snprintf(c, l, "{%s}tcp6:localhost:%u", hn, (unsigned) ntohs(sa.sin6_port)); } else { char ip[INET6_ADDRSTRLEN]; @@ -454,7 +471,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { return NULL; } - snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port)); + pa_snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port)); } return c; @@ -474,13 +491,13 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { if (!pa_get_fqdn(fqdn, sizeof(fqdn))) return NULL; - snprintf(c, l, "tcp:%s:%u", fqdn, (unsigned) ntohs(sa.sin_port)); + pa_snprintf(c, l, "tcp:%s:%u", fqdn, (unsigned) ntohs(sa.sin_port)); } else if (sa.sin_addr.s_addr == INADDR_LOOPBACK) { char hn[256]; if (!pa_get_host_name(hn, sizeof(hn))) return NULL; - snprintf(c, l, "{%s}tcp:localhost:%u", hn, (unsigned) ntohs(sa.sin_port)); + pa_snprintf(c, l, "{%s}tcp:localhost:%u", hn, (unsigned) ntohs(sa.sin_port)); } else { char ip[INET_ADDRSTRLEN]; @@ -489,7 +506,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { return NULL; } - snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port)); + pa_snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port)); } @@ -505,7 +522,7 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { if (!pa_get_host_name(hn, sizeof(hn))) return NULL; - snprintf(c, l, "{%s}unix:%s", hn, s->filename); + pa_snprintf(c, l, "{%s}unix:%s", hn, s->filename); return c; } diff --git a/src/pulsecore/socket-util.c b/src/pulsecore/socket-util.c index 673058e2..456accb8 100644 --- a/src/pulsecore/socket-util.c +++ b/src/pulsecore/socket-util.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -75,19 +74,19 @@ #include #include #include +#include #include "socket-util.h" void pa_socket_peer_to_string(int fd, char *c, size_t l) { struct stat st; - assert(c && l && fd >= 0); + pa_assert(fd >= 0); + pa_assert(c); + pa_assert(l > 0); #ifndef OS_IS_WIN32 - if (fstat(fd, &st) < 0) { - snprintf(c, l, "Invalid client fd"); - return; - } + pa_assert_se(fstat(fd, &st) == 0); #endif #ifndef OS_IS_WIN32 @@ -108,12 +107,12 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) { if (sa.sa.sa_family == AF_INET) { uint32_t ip = ntohl(sa.in.sin_addr.s_addr); - snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u", - ip >> 24, - (ip >> 16) & 0xFF, - (ip >> 8) & 0xFF, - ip & 0xFF, - ntohs(sa.in.sin_port)); + pa_snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u", + ip >> 24, + (ip >> 16) & 0xFF, + (ip >> 8) & 0xFF, + ip & 0xFF, + ntohs(sa.in.sin_port)); return; } else if (sa.sa.sa_family == AF_INET6) { char buf[INET6_ADDRSTRLEN]; @@ -121,94 +120,107 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) { res = inet_ntop(AF_INET6, &sa.in6.sin6_addr, buf, sizeof(buf)); if (res) { - snprintf(c, l, "TCP/IP client from [%s]:%u", buf, ntohs(sa.in6.sin6_port)); + pa_snprintf(c, l, "TCP/IP client from [%s]:%u", buf, ntohs(sa.in6.sin6_port)); return; } #ifdef HAVE_SYS_UN_H } else if (sa.sa.sa_family == AF_UNIX) { - snprintf(c, l, "UNIX socket client"); + pa_snprintf(c, l, "UNIX socket client"); return; #endif } } #ifndef OS_IS_WIN32 - snprintf(c, l, "Unknown network client"); + pa_snprintf(c, l, "Unknown network client"); return; } else if (S_ISCHR(st.st_mode) && (fd == 0 || fd == 1)) { - snprintf(c, l, "STDIN/STDOUT client"); + pa_snprintf(c, l, "STDIN/STDOUT client"); return; } #endif /* OS_IS_WIN32 */ - snprintf(c, l, "Unknown client"); + pa_snprintf(c, l, "Unknown client"); } -int pa_socket_low_delay(int fd) { +void pa_make_socket_low_delay(int fd) { + #ifdef SO_PRIORITY int priority; - assert(fd >= 0); + pa_assert(fd >= 0); - priority = 7; + priority = 6; if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (void*)&priority, sizeof(priority)) < 0) - return -1; + pa_log_warn("SO_PRIORITY failed: %s", pa_cstrerror(errno)); #endif - - return 0; } -int pa_socket_tcp_low_delay(int fd) { - int ret, tos, on; +void pa_make_tcp_socket_low_delay(int fd) { + pa_assert(fd >= 0); - assert(fd >= 0); - - ret = pa_socket_low_delay(fd); - - on = 1; - tos = 0; + pa_make_socket_low_delay(fd); #if defined(SOL_TCP) || defined(IPPROTO_TCP) + { + int on = 1; #if defined(SOL_TCP) - if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0) + if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0) #else - if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0) + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0) #endif - ret = -1; + pa_log_warn("TCP_NODELAY failed: %s", pa_cstrerror(errno)); + } #endif -#if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || \ - defined(IPPROTO_IP)) - tos = IPTOS_LOWDELAY; +#if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP)) + { + int tos = IPTOS_LOWDELAY; #ifdef SOL_IP - if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) + if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) #else - if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) + if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) #endif - ret = -1; + pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno)); + } #endif +} - return ret; +void pa_make_udp_socket_low_delay(int fd) { + pa_assert(fd >= 0); + pa_make_socket_low_delay(fd); + +#if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP)) + { + int tos = IPTOS_LOWDELAY; +#ifdef SOL_IP + if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) +#else + if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0) +#endif + pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno)); + } +#endif } int pa_socket_set_rcvbuf(int fd, size_t l) { - assert(fd >= 0); + pa_assert(fd >= 0); -/* if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&l, sizeof(l)) < 0) { */ -/* pa_log("SO_RCVBUF: %s", strerror(errno)); */ -/* return -1; */ -/* } */ + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&l, sizeof(l)) < 0) { + pa_log_warn("SO_RCVBUF: %s", pa_cstrerror(errno)); + return -1; + } return 0; } int pa_socket_set_sndbuf(int fd, size_t l) { - assert(fd >= 0); + pa_assert(fd >= 0); -/* if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&l, sizeof(l)) < 0) { */ -/* pa_log("SO_SNDBUF: %s", strerror(errno)); */ -/* return -1; */ -/* } */ + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&l, sizeof(l)) < 0) { + pa_log("SO_SNDBUF: %s", pa_cstrerror(errno)); + return -1; + } return 0; } @@ -219,6 +231,8 @@ int pa_unix_socket_is_stale(const char *fn) { struct sockaddr_un sa; int fd = -1, ret = -1; + pa_assert(fn); + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { pa_log("socket(): %s", pa_cstrerror(errno)); goto finish; @@ -244,6 +258,8 @@ finish: int pa_unix_socket_remove_stale(const char *fn) { int r; + pa_assert(fn); + if ((r = pa_unix_socket_is_stale(fn)) < 0) return errno != ENOENT ? -1 : 0; diff --git a/src/pulsecore/socket-util.h b/src/pulsecore/socket-util.h index 616c40ac..a0344c68 100644 --- a/src/pulsecore/socket-util.h +++ b/src/pulsecore/socket-util.h @@ -29,8 +29,9 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l); -int pa_socket_low_delay(int fd); -int pa_socket_tcp_low_delay(int fd); +void pa_make_socket_low_delay(int fd); +void pa_make_tcp_socket_low_delay(int fd); +void pa_make_udp_socket_low_delay(int fd); int pa_socket_set_sndbuf(int fd, size_t l); int pa_socket_set_rcvbuf(int fd, size_t l); diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c index 7a43c743..bb1f3e9a 100644 --- a/src/pulsecore/sound-file-stream.c +++ b/src/pulsecore/sound-file-stream.c @@ -26,100 +26,196 @@ #endif #include -#include #include #include +#include +#include +#include #include #include +#include #include #include +#include +#include #include "sound-file-stream.h" -#define BUF_SIZE (1024*10) - -struct userdata { +typedef struct file_stream { + pa_msgobject parent; + pa_core *core; SNDFILE *sndfile; pa_sink_input *sink_input; pa_memchunk memchunk; sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames); + size_t drop; +} file_stream; + +enum { + FILE_STREAM_MESSAGE_UNLINK }; -static void free_userdata(struct userdata *u) { - assert(u); - if (u->sink_input) { - pa_sink_input_disconnect(u->sink_input); - pa_sink_input_unref(u->sink_input); - } +PA_DECLARE_CLASS(file_stream); +#define FILE_STREAM(o) (file_stream_cast(o)) +static PA_DEFINE_CHECK_TYPE(file_stream, pa_msgobject); + +static void file_stream_unlink(file_stream *u) { + pa_assert(u); + + if (!u->sink_input) + return; + + pa_sink_input_unlink(u->sink_input); + + pa_sink_input_unref(u->sink_input); + u->sink_input = NULL; + + /* Make sure we don't decrease the ref count twice. */ + file_stream_unref(u); +} + +static void file_stream_free(pa_object *o) { + file_stream *u = FILE_STREAM(o); + pa_assert(u); + + file_stream_unlink(u); if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); + if (u->sndfile) sf_close(u->sndfile); pa_xfree(u); } -static void sink_input_kill(pa_sink_input *i) { - assert(i && i->userdata); - free_userdata(i->userdata); +static int file_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) { + file_stream *u = FILE_STREAM(o); + file_stream_assert_ref(u); + + switch (code) { + case FILE_STREAM_MESSAGE_UNLINK: + file_stream_unlink(u); + break; + } + + return 0; +} + +static void sink_input_kill_cb(pa_sink_input *i) { + pa_sink_input_assert_ref(i); + + file_stream_unlink(FILE_STREAM(i->userdata)); } -static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { - struct userdata *u; - assert(i && chunk && i->userdata); - u = i->userdata; +static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) { + file_stream *u; + + pa_assert(i); + pa_assert(chunk); + u = FILE_STREAM(i->userdata); + file_stream_assert_ref(u); + + if (!u->sndfile) + return -1; + + for (;;) { + + if (!u->memchunk.memblock) { + + u->memchunk.memblock = pa_memblock_new(i->sink->core->mempool, length); + u->memchunk.index = 0; + + if (u->readf_function) { + sf_count_t n; + void *p; + size_t fs = pa_frame_size(&i->sample_spec); + + p = pa_memblock_acquire(u->memchunk.memblock); + n = u->readf_function(u->sndfile, p, length/fs); + pa_memblock_release(u->memchunk.memblock); - if (!u->memchunk.memblock) { - uint32_t fs = pa_frame_size(&i->sample_spec); - sf_count_t n; + if (n <= 0) + n = 0; - u->memchunk.memblock = pa_memblock_new(i->sink->core->mempool, BUF_SIZE); - u->memchunk.index = 0; + u->memchunk.length = n * fs; + } else { + sf_count_t n; + void *p; - if (u->readf_function) { - if ((n = u->readf_function(u->sndfile, u->memchunk.memblock->data, BUF_SIZE/fs)) <= 0) - n = 0; + p = pa_memblock_acquire(u->memchunk.memblock); + n = sf_read_raw(u->sndfile, p, length); + pa_memblock_release(u->memchunk.memblock); - u->memchunk.length = n * fs; - } else { - if ((n = sf_read_raw(u->sndfile, u->memchunk.memblock->data, BUF_SIZE)) <= 0) - n = 0; + if (n <= 0) + n = 0; - u->memchunk.length = n; + u->memchunk.length = n; + } + + if (u->memchunk.length <= 0) { + + pa_memblock_unref(u->memchunk.memblock); + pa_memchunk_reset(&u->memchunk); + + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u), FILE_STREAM_MESSAGE_UNLINK, NULL, 0, NULL, NULL); + + sf_close(u->sndfile); + u->sndfile = NULL; + + return -1; + } } - if (!u->memchunk.length) { - free_userdata(u); - return -1; + pa_assert(u->memchunk.memblock); + pa_assert(u->memchunk.length > 0); + + if (u->drop < u->memchunk.length) { + u->memchunk.index += u->drop; + u->memchunk.length -= u->drop; + u->drop = 0; + break; } + + u->drop -= u->memchunk.length; + pa_memblock_unref(u->memchunk.memblock); + pa_memchunk_reset(&u->memchunk); } *chunk = u->memchunk; pa_memblock_ref(chunk->memblock); - assert(chunk->length); + + pa_assert(chunk->length > 0); + pa_assert(u->drop <= 0); + return 0; } -static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) { - struct userdata *u; - assert(i && chunk && length && i->userdata); - u = i->userdata; +static void sink_input_drop_cb(pa_sink_input *i, size_t length) { + file_stream *u; - assert(!memcmp(chunk, &u->memchunk, sizeof(chunk))); - assert(length <= u->memchunk.length); + pa_assert(i); + pa_assert(length > 0); + u = FILE_STREAM(i->userdata); + file_stream_assert_ref(u); - u->memchunk.index += length; - u->memchunk.length -= length; + if (u->memchunk.memblock) { - if (u->memchunk.length <= 0) { + if (length < u->memchunk.length) { + u->memchunk.index += length; + u->memchunk.length -= length; + return; + } + + length -= u->memchunk.length; pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - u->memchunk.index = u->memchunk.length = 0; + pa_memchunk_reset(&u->memchunk); } + + u->drop += length; } int pa_play_file( @@ -127,28 +223,60 @@ int pa_play_file( const char *fname, const pa_cvolume *volume) { - struct userdata *u = NULL; + file_stream *u = NULL; SF_INFO sfinfo; pa_sample_spec ss; pa_sink_input_new_data data; + int fd; - assert(sink); - assert(fname); + pa_assert(sink); + pa_assert(fname); - u = pa_xnew(struct userdata, 1); + u = pa_msgobject_new(file_stream); + u->parent.parent.free = file_stream_free; + u->parent.process_msg = file_stream_process_msg; + u->core = sink->core; u->sink_input = NULL; - u->memchunk.memblock = NULL; - u->memchunk.index = u->memchunk.length = 0; + pa_memchunk_reset(&u->memchunk); u->sndfile = NULL; + u->readf_function = NULL; + u->drop = 0; memset(&sfinfo, 0, sizeof(sfinfo)); - if (!(u->sndfile = sf_open(fname, SFM_READ, &sfinfo))) { - pa_log("Failed to open file %s", fname); + if ((fd = open(fname, O_RDONLY +#ifdef O_NOCTTY + |O_NOCTTY +#endif + )) < 0) { + pa_log("Failed to open file %s: %s", fname, pa_cstrerror(errno)); goto fail; } - u->readf_function = NULL; + /* FIXME: For now we just use posix_fadvise to avoid page faults + * when accessing the file data. Eventually we should move the + * file reader into the main event loop and pass the data over the + * asyncmsgq. */ + +#ifdef HAVE_POSIX_FADVISE + if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL) < 0) { + pa_log_warn("POSIX_FADV_SEQUENTIAL failed: %s", pa_cstrerror(errno)); + goto fail; + } else + pa_log_debug("POSIX_FADV_SEQUENTIAL succeeded."); + + if (posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED) < 0) { + pa_log_warn("POSIX_FADV_WILLNEED failed: %s", pa_cstrerror(errno)); + goto fail; + } else + pa_log_debug("POSIX_FADV_WILLNEED succeeded."); +#endif + + if (!(u->sndfile = sf_open_fd(fd, SFM_READ, &sfinfo, 1))) { + pa_log("Failed to open file %s", fname); + pa_close(fd); + goto fail; + } switch (sfinfo.format & 0xFF) { case SF_FORMAT_PCM_16: @@ -191,18 +319,21 @@ int pa_play_file( if (!(u->sink_input = pa_sink_input_new(sink->core, &data, 0))) goto fail; - u->sink_input->peek = sink_input_peek; - u->sink_input->drop = sink_input_drop; - u->sink_input->kill = sink_input_kill; + u->sink_input->peek = sink_input_peek_cb; + u->sink_input->drop = sink_input_drop_cb; + u->sink_input->kill = sink_input_kill_cb; u->sink_input->userdata = u; - pa_sink_notify(u->sink_input->sink); + pa_sink_input_put(u->sink_input); + + /* The reference to u is dangling here, because we want to keep + * this stream around until it is fully played. */ return 0; fail: if (u) - free_userdata(u); + file_stream_unref(u); return -1; } diff --git a/src/pulsecore/sound-file.c b/src/pulsecore/sound-file.c index 69b543ab..7e88734c 100644 --- a/src/pulsecore/sound-file.c +++ b/src/pulsecore/sound-file.c @@ -26,31 +26,63 @@ #endif #include -#include +#include +#include +#include #include #include #include +#include +#include +#include #include "sound-file.h" #include "core-scache.h" -int pa_sound_file_load(pa_mempool *pool, const char *fname, pa_sample_spec *ss, pa_channel_map *map, pa_memchunk *chunk) { - SNDFILE*sf = NULL; +int pa_sound_file_load( + pa_mempool *pool, + const char *fname, + pa_sample_spec *ss, + pa_channel_map *map, + pa_memchunk *chunk) { + + SNDFILE *sf = NULL; SF_INFO sfinfo; int ret = -1; size_t l; sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames) = NULL; - assert(fname && ss && chunk); + void *ptr = NULL; + int fd; - chunk->memblock = NULL; - chunk->index = chunk->length = 0; + pa_assert(fname); + pa_assert(ss); + pa_assert(chunk); + pa_memchunk_reset(chunk); memset(&sfinfo, 0, sizeof(sfinfo)); - if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) { + if ((fd = open(fname, O_RDONLY +#ifdef O_NOCTTY + |O_NOCTTY +#endif + )) < 0) { + pa_log("Failed to open file %s: %s", fname, pa_cstrerror(errno)); + goto finish; + } + +#ifdef HAVE_POSIX_FADVISE + if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL) < 0) { + pa_log_warn("POSIX_FADV_SEQUENTIAL failed: %s", pa_cstrerror(errno)); + goto finish; + } else + pa_log_debug("POSIX_FADV_SEQUENTIAL succeeded."); +#endif + + if (!(sf = sf_open_fd(fd, SFM_READ, &sfinfo, 1))) { pa_log("Failed to open file %s", fname); + pa_close(fd); goto finish; } @@ -89,18 +121,19 @@ int pa_sound_file_load(pa_mempool *pool, const char *fname, pa_sample_spec *ss, if (map) pa_channel_map_init_auto(map, ss->channels, PA_CHANNEL_MAP_DEFAULT); - if ((l = pa_frame_size(ss)*sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) { + if ((l = pa_frame_size(ss) * sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) { pa_log("File too large"); goto finish; } chunk->memblock = pa_memblock_new(pool, l); - assert(chunk->memblock); chunk->index = 0; chunk->length = l; - if ((readf_function && readf_function(sf, chunk->memblock->data, sfinfo.frames) != sfinfo.frames) || - (!readf_function && sf_read_raw(sf, chunk->memblock->data, l) != l)) { + ptr = pa_memblock_acquire(chunk->memblock); + + if ((readf_function && readf_function(sf, ptr, sfinfo.frames) != sfinfo.frames) || + (!readf_function && sf_read_raw(sf, ptr, l) != (sf_count_t) l)) { pa_log("Premature file end"); goto finish; } @@ -112,21 +145,26 @@ finish: if (sf) sf_close(sf); + if (ptr) + pa_memblock_release(chunk->memblock); + if (ret != 0 && chunk->memblock) pa_memblock_unref(chunk->memblock); return ret; - } int pa_sound_file_too_big_to_cache(const char *fname) { + SNDFILE*sf = NULL; SF_INFO sfinfo; pa_sample_spec ss; + pa_assert(fname); + if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) { pa_log("Failed to open file %s", fname); - return 0; + return -1; } sf_close(sf); @@ -156,8 +194,13 @@ int pa_sound_file_too_big_to_cache(const char *fname) { ss.rate = sfinfo.samplerate; ss.channels = sfinfo.channels; + if (!pa_sample_spec_valid(&ss)) { + pa_log("Unsupported sample format in file %s", fname); + return -1; + } + if ((pa_frame_size(&ss) * sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) { - pa_log("File too large %s", fname); + pa_log("File too large: %s", fname); return 1; } diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index c7a9858c..2a902dc2 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -26,7 +26,6 @@ #endif #include -#include #include #include @@ -39,14 +38,12 @@ #include "source-output.h" -#define CHECK_VALIDITY_RETURN_NULL(condition) \ -do {\ -if (!(condition)) \ - return NULL; \ -} while (0) +static PA_DEFINE_CHECK_TYPE(pa_source_output, pa_msgobject); + +static void source_output_free(pa_object* mo); pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_data *data) { - assert(data); + pa_assert(data); memset(data, 0, sizeof(*data)); data->resample_method = PA_RESAMPLER_INVALID; @@ -54,14 +51,14 @@ pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_d } void pa_source_output_new_data_set_channel_map(pa_source_output_new_data *data, const pa_channel_map *map) { - assert(data); + pa_assert(data); if ((data->channel_map_is_set = !!map)) data->channel_map = *map; } void pa_source_output_new_data_set_sample_spec(pa_source_output_new_data *data, const pa_sample_spec *spec) { - assert(data); + pa_assert(data); if ((data->sample_spec_is_set = !!spec)) data->sample_spec = *spec; @@ -74,288 +71,415 @@ pa_source_output* pa_source_output_new( pa_source_output *o; pa_resampler *resampler = NULL; - int r; char st[PA_SAMPLE_SPEC_SNPRINT_MAX]; - assert(core); - assert(data); + pa_assert(core); + pa_assert(data); - if (!(flags & PA_SOURCE_OUTPUT_NO_HOOKS)) - if (pa_hook_fire(&core->hook_source_output_new, data) < 0) - return NULL; + if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], data) < 0) + return NULL; - CHECK_VALIDITY_RETURN_NULL(!data->driver || pa_utf8_valid(data->driver)); - CHECK_VALIDITY_RETURN_NULL(!data->name || pa_utf8_valid(data->name)); + pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver)); + pa_return_null_if_fail(!data->name || pa_utf8_valid(data->name)); if (!data->source) data->source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE, 1); - CHECK_VALIDITY_RETURN_NULL(data->source); - CHECK_VALIDITY_RETURN_NULL(data->source->state == PA_SOURCE_RUNNING); + pa_return_null_if_fail(data->source); + pa_return_null_if_fail(pa_source_get_state(data->source) != PA_SOURCE_UNLINKED); if (!data->sample_spec_is_set) data->sample_spec = data->source->sample_spec; - CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(&data->sample_spec)); + pa_return_null_if_fail(pa_sample_spec_valid(&data->sample_spec)); - if (!data->channel_map_is_set) - pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); + if (!data->channel_map_is_set) { + if (data->source->channel_map.channels == data->sample_spec.channels) + data->channel_map = data->source->channel_map; + else + pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); + } - CHECK_VALIDITY_RETURN_NULL(pa_channel_map_valid(&data->channel_map)); - CHECK_VALIDITY_RETURN_NULL(data->channel_map.channels == data->sample_spec.channels); + pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map)); + pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels); if (data->resample_method == PA_RESAMPLER_INVALID) data->resample_method = core->resample_method; - CHECK_VALIDITY_RETURN_NULL(data->resample_method < PA_RESAMPLER_MAX); + pa_return_null_if_fail(data->resample_method < PA_RESAMPLER_MAX); if (pa_idxset_size(data->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { pa_log("Failed to create source output: too many outputs per source."); return NULL; } - if (!pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec) || - !pa_channel_map_equal(&data->channel_map, &data->source->channel_map)) + if ((flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) || + !pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec) || + !pa_channel_map_equal(&data->channel_map, &data->source->channel_map)) { + if (!(resampler = pa_resampler_new( core->mempool, &data->source->sample_spec, &data->source->channel_map, &data->sample_spec, &data->channel_map, - data->resample_method))) { + data->resample_method, + !!(flags & PA_SOURCE_OUTPUT_VARIABLE_RATE)))) { pa_log_warn("Unsupported resampling operation."); return NULL; } - o = pa_xnew(pa_source_output, 1); - o->ref = 1; - o->state = PA_SOURCE_OUTPUT_RUNNING; + data->resample_method = pa_resampler_get_method(resampler); + } + + o = pa_msgobject_new(pa_source_output); + o->parent.parent.free = source_output_free; + o->parent.process_msg = pa_source_output_process_msg; + + o->core = core; + o->state = PA_SOURCE_OUTPUT_INIT; + o->flags = flags; o->name = pa_xstrdup(data->name); o->driver = pa_xstrdup(data->driver); o->module = data->module; o->source = data->source; o->client = data->client; + o->resample_method = data->resample_method; o->sample_spec = data->sample_spec; o->channel_map = data->channel_map; o->push = NULL; o->kill = NULL; o->get_latency = NULL; + o->detach = NULL; + o->attach = NULL; + o->suspend = NULL; o->userdata = NULL; - o->resampler = resampler; - o->resample_method = data->resample_method; + o->thread_info.state = o->state; + o->thread_info.attached = FALSE; + o->thread_info.sample_spec = o->sample_spec; + o->thread_info.resampler = resampler; - r = pa_idxset_put(core->source_outputs, o, &o->index); - assert(r == 0); - r = pa_idxset_put(o->source->outputs, o, NULL); - assert(r == 0); + pa_assert_se(pa_idxset_put(core->source_outputs, o, &o->index) == 0); + pa_assert_se(pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL) == 0); - pa_log_info("created %u \"%s\" on %s with sample spec %s", + pa_log_info("Created output %u \"%s\" on %s with sample spec %s", o->index, o->name, o->source->name, pa_sample_spec_snprint(st, sizeof(st), &o->sample_spec)); - pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); - - /* We do not call pa_source_notify() here, because the virtual - * functions have not yet been initialized */ + /* Don't forget to call pa_source_output_put! */ return o; } -void pa_source_output_disconnect(pa_source_output*o) { - assert(o); - assert(o->state != PA_SOURCE_OUTPUT_DISCONNECTED); - assert(o->source); - assert(o->source->core); +static int source_output_set_state(pa_source_output *o, pa_source_output_state_t state) { + pa_assert(o); + + if (o->state == state) + return 0; + + if (pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) < 0) + return -1; + + if (o->state == PA_SOURCE_OUTPUT_CORKED && state != PA_SOURCE_OUTPUT_CORKED) + pa_assert_se(o->source->n_corked -- >= 1); + else if (o->state != PA_SOURCE_OUTPUT_CORKED && state == PA_SOURCE_OUTPUT_CORKED) + o->source->n_corked++; + + pa_source_update_status(o->source); + + o->state = state; + + if (state != PA_SOURCE_OUTPUT_UNLINKED) + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], o); + + return 0; +} + +void pa_source_output_unlink(pa_source_output*o) { + pa_bool_t linked; + pa_assert(o); + + /* See pa_sink_unlink() for a couple of comments how this function + * works */ + + pa_source_output_ref(o); + + linked = PA_SOURCE_OUTPUT_LINKED(o->state); + + if (linked) + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], o); pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); - pa_idxset_remove_by_data(o->source->outputs, o, NULL); + if (pa_idxset_remove_by_data(o->source->outputs, o, NULL)) + pa_source_output_unref(o); - pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); - o->source = NULL; + if (linked) { + pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL); + source_output_set_state(o, PA_SOURCE_OUTPUT_UNLINKED); + pa_source_update_status(o->source); + } else + o->state = PA_SOURCE_OUTPUT_UNLINKED; o->push = NULL; o->kill = NULL; o->get_latency = NULL; + o->attach = NULL; + o->detach = NULL; + o->suspend = NULL; + + if (linked) { + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], o); + } - o->state = PA_SOURCE_OUTPUT_DISCONNECTED; + o->source = NULL; + pa_source_output_unref(o); } -static void source_output_free(pa_source_output* o) { - assert(o); +static void source_output_free(pa_object* mo) { + pa_source_output *o = PA_SOURCE_OUTPUT(mo); + + pa_assert(pa_source_output_refcnt(o) == 0); + + if (PA_SOURCE_OUTPUT_LINKED(o->state)) + pa_source_output_unlink(o); - if (o->state != PA_SOURCE_OUTPUT_DISCONNECTED) - pa_source_output_disconnect(o); + pa_log_info("Freeing output %u \"%s\"", o->index, o->name); - pa_log_info("freed %u \"%s\"", o->index, o->name); + pa_assert(!o->thread_info.attached); - if (o->resampler) - pa_resampler_free(o->resampler); + if (o->thread_info.resampler) + pa_resampler_free(o->thread_info.resampler); pa_xfree(o->name); pa_xfree(o->driver); pa_xfree(o); } -void pa_source_output_unref(pa_source_output* o) { - assert(o); - assert(o->ref >= 1); +void pa_source_output_put(pa_source_output *o) { + pa_source_output_assert_ref(o); - if (!(--o->ref)) - source_output_free(o); -} + pa_assert(o->state == PA_SOURCE_OUTPUT_INIT); + pa_assert(o->push); -pa_source_output* pa_source_output_ref(pa_source_output *o) { - assert(o); - assert(o->ref >= 1); + o->thread_info.state = o->state = o->flags & PA_SOURCE_OUTPUT_START_CORKED ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; - o->ref++; - return o; + if (o->state == PA_SOURCE_OUTPUT_CORKED) + o->source->n_corked++; + + pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL); + pa_source_update_status(o->source); + + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); + + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], o); } void pa_source_output_kill(pa_source_output*o) { - assert(o); - assert(o->ref >= 1); + pa_source_output_assert_ref(o); + pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state)); if (o->kill) o->kill(o); } +pa_usec_t pa_source_output_get_latency(pa_source_output *o) { + pa_usec_t r = 0; + + pa_source_output_assert_ref(o); + pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state)); + + if (pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY, &r, 0, NULL) < 0) + r = 0; + + if (o->get_latency) + r += o->get_latency(o); + + return r; +} + +/* Called from thread context */ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { pa_memchunk rchunk; - assert(o); - assert(chunk); - assert(chunk->length); - assert(o->push); + pa_source_output_assert_ref(o); + pa_assert(PA_SOURCE_OUTPUT_LINKED(o->thread_info.state)); + pa_assert(chunk); + pa_assert(chunk->length); - if (o->state == PA_SOURCE_OUTPUT_CORKED) + if (!o->push || o->state == PA_SOURCE_OUTPUT_CORKED) return; - if (!o->resampler) { + pa_assert(o->state == PA_SOURCE_OUTPUT_RUNNING); + + if (!o->thread_info.resampler) { o->push(o, chunk); return; } - pa_resampler_run(o->resampler, chunk, &rchunk); + pa_resampler_run(o->thread_info.resampler, chunk, &rchunk); if (!rchunk.length) return; - assert(rchunk.memblock); + pa_assert(rchunk.memblock); o->push(o, &rchunk); pa_memblock_unref(rchunk.memblock); } -void pa_source_output_set_name(pa_source_output *o, const char *name) { - assert(o); - assert(o->ref >= 1); - - if (!o->name && !name) - return; +void pa_source_output_cork(pa_source_output *o, pa_bool_t b) { + pa_source_output_assert_ref(o); + pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state)); - if (o->name && name && !strcmp(o->name, name)) - return; + source_output_set_state(o, b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING); +} - pa_xfree(o->name); - o->name = pa_xstrdup(name); +int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) { + pa_source_output_assert_ref(o); + pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state)); + pa_return_val_if_fail(o->thread_info.resampler, -1); - pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); -} + if (o->sample_spec.rate == rate) + return 0; -pa_usec_t pa_source_output_get_latency(pa_source_output *o) { - assert(o); - assert(o->ref >= 1); + o->sample_spec.rate = rate; - if (o->get_latency) - return o->get_latency(o); + pa_asyncmsgq_post(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), 0, NULL, NULL); + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); return 0; } -void pa_source_output_cork(pa_source_output *o, int b) { - int n; - - assert(o); - assert(o->ref >= 1); +void pa_source_output_set_name(pa_source_output *o, const char *name) { + pa_source_output_assert_ref(o); - if (o->state == PA_SOURCE_OUTPUT_DISCONNECTED) + if (!o->name && !name) return; - n = o->state == PA_SOURCE_OUTPUT_CORKED && !b; + if (o->name && name && !strcmp(o->name, name)) + return; - o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; + pa_xfree(o->name); + o->name = pa_xstrdup(name); - if (n) - pa_source_notify(o->source); + if (PA_SOURCE_OUTPUT_LINKED(o->state)) { + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NAME_CHANGED], o); + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); + } } pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { - assert(o); - assert(o->ref >= 1); + pa_source_output_assert_ref(o); - if (!o->resampler) - return o->resample_method; - - return pa_resampler_get_method(o->resampler); + return o->resample_method; } int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { pa_source *origin; pa_resampler *new_resampler = NULL; - assert(o); - assert(o->ref >= 1); - assert(dest); + pa_source_output_assert_ref(o); + pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state)); + pa_source_assert_ref(dest); origin = o->source; if (dest == origin) return 0; + if (o->flags & PA_SOURCE_OUTPUT_DONT_MOVE) + return -1; + if (pa_idxset_size(dest->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { pa_log_warn("Failed to move source output: too many outputs per source."); return -1; } - if (o->resampler && + if (o->thread_info.resampler && pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) && pa_channel_map_equal(&origin->channel_map, &dest->channel_map)) /* Try to reuse the old resampler if possible */ - new_resampler = o->resampler; + new_resampler = o->thread_info.resampler; - else if (!pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec) || - !pa_channel_map_equal(&o->channel_map, &dest->channel_map)) { + else if ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) || + !pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec) || + !pa_channel_map_equal(&o->channel_map, &dest->channel_map)) { - /* Okey, we need a new resampler for the new sink */ + /* Okey, we need a new resampler for the new source */ if (!(new_resampler = pa_resampler_new( dest->core->mempool, &dest->sample_spec, &dest->channel_map, &o->sample_spec, &o->channel_map, - o->resample_method))) { + o->resample_method, + !!(o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE)))) { pa_log_warn("Unsupported resampling operation."); return -1; } } + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE], o); + /* Okey, let's move it */ + pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL); + pa_idxset_remove_by_data(origin->outputs, o, NULL); pa_idxset_put(dest->outputs, o, NULL); o->source = dest; + if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED) { + pa_assert_se(origin->n_corked-- >= 1); + dest->n_corked++; + } + /* Replace resampler */ - if (new_resampler != o->resampler) { - if (o->resampler) - pa_resampler_free(o->resampler); - o->resampler = new_resampler; + if (new_resampler != o->thread_info.resampler) { + if (o->thread_info.resampler) + pa_resampler_free(o->thread_info.resampler); + o->thread_info.resampler = new_resampler; } + pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL); + + pa_source_update_status(origin); + pa_source_update_status(dest); + + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_POST], o); + + pa_log_debug("Successfully moved source output %i from %s to %s.", o->index, origin->name, dest->name); + /* Notify everyone */ pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); - pa_source_notify(o->source); return 0; } + +/* Called from thread context */ +int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int64_t offset, pa_memchunk* chunk) { + pa_source_output *o = PA_SOURCE_OUTPUT(mo); + + pa_source_output_assert_ref(o); + pa_assert(PA_SOURCE_OUTPUT_LINKED(o->thread_info.state)); + + switch (code) { + + case PA_SOURCE_OUTPUT_MESSAGE_SET_RATE: { + + o->thread_info.sample_spec.rate = PA_PTR_TO_UINT(userdata); + pa_resampler_set_output_rate(o->thread_info.resampler, PA_PTR_TO_UINT(userdata)); + + return 0; + } + + case PA_SOURCE_OUTPUT_MESSAGE_SET_STATE: { + o->thread_info.state = PA_PTR_TO_UINT(userdata); + + return 0; + } + } + + return -1; +} diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index 3da6caac..e38a1e5a 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -1,5 +1,5 @@ -#ifndef foosourceoutputhfoo -#define foosourceoutputhfoo +#ifndef foopulsesourceoutputhfoo +#define foopulsesourceoutputhfoo /* $Id$ */ @@ -35,40 +35,91 @@ typedef struct pa_source_output pa_source_output; #include #include -typedef enum { +typedef enum pa_source_output_state { + PA_SOURCE_OUTPUT_INIT, PA_SOURCE_OUTPUT_RUNNING, PA_SOURCE_OUTPUT_CORKED, - PA_SOURCE_OUTPUT_DISCONNECTED + PA_SOURCE_OUTPUT_UNLINKED } pa_source_output_state_t; +static inline pa_bool_t PA_SOURCE_OUTPUT_LINKED(pa_source_output_state_t x) { + return x == PA_SOURCE_OUTPUT_RUNNING || x == PA_SOURCE_OUTPUT_CORKED; +} + typedef enum pa_source_output_flags { - PA_SOURCE_OUTPUT_NO_HOOKS = 1 + PA_SOURCE_OUTPUT_VARIABLE_RATE = 1, + PA_SOURCE_OUTPUT_DONT_MOVE = 2, + PA_SOURCE_OUTPUT_START_CORKED = 4 } pa_source_output_flags_t; struct pa_source_output { - int ref; + pa_msgobject parent; + uint32_t index; + pa_core *core; pa_source_output_state_t state; + pa_source_output_flags_t flags; char *name, *driver; /* may be NULL */ pa_module *module; /* may be NULL */ + pa_client *client; /* may be NULL */ pa_source *source; - pa_client *client; /* may be NULL */ pa_sample_spec sample_spec; pa_channel_map channel_map; + /* Pushes a new memchunk into the output. Called from IO thread + * context. */ void (*push)(pa_source_output *o, const pa_memchunk *chunk); + + /* If non-NULL this function is called when the output is first + * connected to a source. Called from IO thread context */ + void (*attach) (pa_source_output *o); /* may be NULL */ + + /* If non-NULL this function is called when the output is + * disconnected from its source. Called from IO thread context */ + void (*detach) (pa_source_output *o); /* may be NULL */ + + /* If non-NULL called whenever the the source this output is attached + * to suspends or resumes. Called from main context */ + void (*suspend) (pa_source_output *o, int b); /* may be NULL */ + + /* Supposed to unlink and destroy this stream. Called from main + * context. */ void (*kill)(pa_source_output* o); /* may be NULL */ + + /* Return the current latency (i.e. length of bufferd audio) of + this stream. Called from main context. If NULL a + PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY message is sent to the IO + thread instead. */ pa_usec_t (*get_latency) (pa_source_output *o); /* may be NULL */ - pa_resampler* resampler; /* may be NULL */ pa_resample_method_t resample_method; + struct { + pa_source_output_state_t state; + + pa_bool_t attached; /* True only between ->attach() and ->detach() calls */ + + pa_sample_spec sample_spec; + + pa_resampler* resampler; /* may be NULL */ + } thread_info; + void *userdata; }; +PA_DECLARE_CLASS(pa_source_output); +#define PA_SOURCE_OUTPUT(o) pa_source_output_cast(o) + +enum { + PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY, + PA_SOURCE_OUTPUT_MESSAGE_SET_RATE, + PA_SOURCE_OUTPUT_MESSAGE_SET_STATE, + PA_SOURCE_OUTPUT_MESSAGE_MAX +}; + typedef struct pa_source_output_new_data { const char *name, *driver; pa_module *module; @@ -77,9 +128,9 @@ typedef struct pa_source_output_new_data { pa_source *source; pa_sample_spec sample_spec; - int sample_spec_is_set; + pa_bool_t sample_spec_is_set; pa_channel_map channel_map; - int channel_map_is_set; + pa_bool_t channel_map_is_set; pa_resample_method_t resample_method; } pa_source_output_new_data; @@ -89,30 +140,38 @@ void pa_source_output_new_data_set_sample_spec(pa_source_output_new_data *data, void pa_source_output_new_data_set_channel_map(pa_source_output_new_data *data, const pa_channel_map *map); void pa_source_output_new_data_set_volume(pa_source_output_new_data *data, const pa_cvolume *volume); +/* To be called by the implementing module only */ + pa_source_output* pa_source_output_new( pa_core *core, pa_source_output_new_data *data, pa_source_output_flags_t flags); -void pa_source_output_unref(pa_source_output* o); -pa_source_output* pa_source_output_ref(pa_source_output *o); +void pa_source_output_put(pa_source_output *o); +void pa_source_output_unlink(pa_source_output*o); -/* To be called by the implementing module only */ -void pa_source_output_disconnect(pa_source_output*o); +void pa_source_output_set_name(pa_source_output *i, const char *name); + +/* Callable by everyone */ /* External code may request disconnection with this funcion */ void pa_source_output_kill(pa_source_output*o); -void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk); - -void pa_source_output_set_name(pa_source_output *i, const char *name); - pa_usec_t pa_source_output_get_latency(pa_source_output *i); -void pa_source_output_cork(pa_source_output *i, int b); +void pa_source_output_cork(pa_source_output *i, pa_bool_t b); + +int pa_source_output_set_rate(pa_source_output *o, uint32_t rate); pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o); int pa_source_output_move_to(pa_source_output *o, pa_source *dest); +#define pa_source_output_get_state(o) ((o)->state) + +/* To be used exclusively by the source driver thread */ + +void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk); +int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int64_t offset, pa_memchunk *chunk); + #endif diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 9bb2d342..9a6902ae 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -27,7 +27,6 @@ #endif #include -#include #include #include @@ -42,11 +41,9 @@ #include "source.h" -#define CHECK_VALIDITY_RETURN_NULL(condition) \ -do {\ -if (!(condition)) \ - return NULL; \ -} while (0) +static PA_DEFINE_CHECK_TYPE(pa_source, pa_msgobject); + +static void source_free(pa_object *o); pa_source* pa_source_new( pa_core *core, @@ -58,274 +55,359 @@ pa_source* pa_source_new( pa_source *s; char st[256]; - int r; pa_channel_map tmap; - assert(core); - assert(name); - assert(spec); + pa_assert(core); + pa_assert(name); + pa_assert(spec); - CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec)); + pa_return_null_if_fail(pa_sample_spec_valid(spec)); if (!map) map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT); - CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map)); - CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels); - CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver)); - CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name) && *name); + pa_return_null_if_fail(map && pa_channel_map_valid(map)); + pa_return_null_if_fail(map->channels == spec->channels); + pa_return_null_if_fail(!driver || pa_utf8_valid(driver)); + pa_return_null_if_fail(pa_utf8_valid(name) && *name); - s = pa_xnew(pa_source, 1); + s = pa_msgobject_new(pa_source); if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SOURCE, s, fail))) { pa_xfree(s); return NULL; } - s->ref = 1; + s->parent.parent.free = source_free; + s->parent.process_msg = pa_source_process_msg; + s->core = core; - s->state = PA_SOURCE_RUNNING; + s->state = PA_SOURCE_INIT; + s->flags = 0; s->name = pa_xstrdup(name); s->description = NULL; s->driver = pa_xstrdup(driver); - s->owner = NULL; + s->module = NULL; s->sample_spec = *spec; s->channel_map = *map; s->outputs = pa_idxset_new(NULL, NULL); + s->n_corked = 0; s->monitor_of = NULL; - pa_cvolume_reset(&s->sw_volume, spec->channels); - pa_cvolume_reset(&s->hw_volume, spec->channels); - s->sw_muted = 0; - s->hw_muted = 0; - - s->is_hardware = 0; + pa_cvolume_reset(&s->volume, spec->channels); + s->muted = FALSE; + s->refresh_volume = s->refresh_muted = FALSE; s->get_latency = NULL; - s->notify = NULL; - s->set_hw_volume = NULL; - s->get_hw_volume = NULL; - s->set_hw_mute = NULL; - s->get_hw_mute = NULL; + s->set_volume = NULL; + s->get_volume = NULL; + s->set_mute = NULL; + s->get_mute = NULL; + s->set_state = NULL; s->userdata = NULL; - r = pa_idxset_put(core->sources, s, &s->index); - assert(s->index != PA_IDXSET_INVALID && r >= 0); + s->asyncmsgq = NULL; + s->rtpoll = NULL; + + pa_assert_se(pa_idxset_put(core->sources, s, &s->index) >= 0); pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info("created %u \"%s\" with sample spec \"%s\"", s->index, s->name, st); + pa_log_info("Created source %u \"%s\" with sample spec \"%s\"", s->index, s->name, st); - pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index); + s->thread_info.outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + s->thread_info.soft_volume = s->volume; + s->thread_info.soft_muted = s->muted; + s->thread_info.state = s->state; return s; } -void pa_source_disconnect(pa_source *s) { +static int source_set_state(pa_source *s, pa_source_state_t state) { + int ret; + + pa_assert(s); + + if (s->state == state) + return 0; + + if ((s->state == PA_SOURCE_SUSPENDED && PA_SOURCE_OPENED(state)) || + (PA_SOURCE_OPENED(s->state) && state == PA_SOURCE_SUSPENDED)) { + pa_source_output *o; + uint32_t idx; + + /* We're suspending or resuming, tell everyone about it */ + + for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx))) + if (o->suspend) + o->suspend(o, state == PA_SINK_SUSPENDED); + } + + if (s->set_state) + if ((ret = s->set_state(s, state)) < 0) + return -1; + + if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) < 0) + return -1; + + s->state = state; + + if (state != PA_SOURCE_UNLINKED) /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */ + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], s); + return 0; +} + +void pa_source_put(pa_source *s) { + pa_source_assert_ref(s); + + pa_assert(s->state == PA_SINK_INIT); + pa_assert(s->rtpoll); + pa_assert(s->asyncmsgq); + + pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0); + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index); + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_NEW_POST], s); +} + +void pa_source_unlink(pa_source *s) { + pa_bool_t linked; pa_source_output *o, *j = NULL; - assert(s); - assert(s->state == PA_SOURCE_RUNNING); + pa_assert(s); + + /* See pa_sink_unlink() for a couple of comments how this function + * works. */ - s->state = PA_SOURCE_DISCONNECTED; - pa_namereg_unregister(s->core, s->name); + linked = PA_SOURCE_LINKED(s->state); - pa_hook_fire(&s->core->hook_source_disconnect, s); + if (linked) + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], s); + + if (s->state != PA_SOURCE_UNLINKED) + pa_namereg_unregister(s->core, s->name); + pa_idxset_remove_by_data(s->core->sources, s, NULL); while ((o = pa_idxset_first(s->outputs, NULL))) { - assert(o != j); + pa_assert(o != j); pa_source_output_kill(o); j = o; } - pa_idxset_remove_by_data(s->core->sources, s, NULL); + if (linked) + source_set_state(s, PA_SOURCE_UNLINKED); + else + s->state = PA_SOURCE_UNLINKED; s->get_latency = NULL; - s->notify = NULL; - s->get_hw_volume = NULL; - s->set_hw_volume = NULL; - s->set_hw_mute = NULL; - s->get_hw_mute = NULL; - - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); + s->get_volume = NULL; + s->set_volume = NULL; + s->set_mute = NULL; + s->get_mute = NULL; + s->set_state = NULL; + + if (linked) { + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK_POST], s); + } } -static void source_free(pa_source *s) { - assert(s); - assert(!s->ref); +static void source_free(pa_object *o) { + pa_source_output *so; + pa_source *s = PA_SOURCE(o); - if (s->state != PA_SOURCE_DISCONNECTED) - pa_source_disconnect(s); + pa_assert(s); + pa_assert(pa_source_refcnt(s) == 0); - pa_log_info("freed %u \"%s\"", s->index, s->name); + if (PA_SOURCE_LINKED(s->state)) + pa_source_unlink(s); + + pa_log_info("Freeing source %u \"%s\"", s->index, s->name); pa_idxset_free(s->outputs, NULL, NULL); + while ((so = pa_hashmap_steal_first(s->thread_info.outputs))) + pa_source_output_unref(so); + + pa_hashmap_free(s->thread_info.outputs, NULL, NULL); + pa_xfree(s->name); pa_xfree(s->description); pa_xfree(s->driver); pa_xfree(s); } -void pa_source_unref(pa_source *s) { - assert(s); - assert(s->ref >= 1); - - if (!(--s->ref)) - source_free(s); -} +int pa_source_update_status(pa_source*s) { + pa_source_assert_ref(s); + pa_assert(PA_SOURCE_LINKED(s->state)); -pa_source* pa_source_ref(pa_source *s) { - assert(s); - assert(s->ref >= 1); + if (s->state == PA_SOURCE_SUSPENDED) + return 0; - s->ref++; - return s; + return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE); } -void pa_source_notify(pa_source*s) { - assert(s); - assert(s->ref >= 1); +int pa_source_suspend(pa_source *s, pa_bool_t suspend) { + pa_source_assert_ref(s); + pa_assert(PA_SOURCE_LINKED(s->state)); - if (s->notify) - s->notify(s); + if (suspend) + return source_set_state(s, PA_SOURCE_SUSPENDED); + else + return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE); } -static int do_post(void *p, PA_GCC_UNUSED uint32_t idx, PA_GCC_UNUSED int *del, void*userdata) { - pa_source_output *o = p; - const pa_memchunk *chunk = userdata; +void pa_source_ping(pa_source *s) { + pa_source_assert_ref(s); + pa_assert(PA_SOURCE_LINKED(s->state)); - assert(o); - assert(chunk); - - pa_source_output_push(o, chunk); - return 0; + pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_PING, NULL, 0, NULL, NULL); } void pa_source_post(pa_source*s, const pa_memchunk *chunk) { - assert(s); - assert(s->ref >= 1); - assert(chunk); + pa_source_output *o; + void *state = NULL; - pa_source_ref(s); + pa_source_assert_ref(s); + pa_assert(PA_SOURCE_OPENED(s->thread_info.state)); + pa_assert(chunk); - if (s->sw_muted || !pa_cvolume_is_norm(&s->sw_volume)) { + if (s->thread_info.state != PA_SOURCE_RUNNING) + return; + + if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) { pa_memchunk vchunk = *chunk; pa_memblock_ref(vchunk.memblock); pa_memchunk_make_writable(&vchunk, 0); - if (s->sw_muted) + + if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume)) pa_silence_memchunk(&vchunk, &s->sample_spec); else - pa_volume_memchunk(&vchunk, &s->sample_spec, &s->sw_volume); - pa_idxset_foreach(s->outputs, do_post, &vchunk); + pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume); + + while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) + pa_source_output_push(o, &vchunk); + pa_memblock_unref(vchunk.memblock); - } else - pa_idxset_foreach(s->outputs, do_post, (void*) chunk); + } else { - pa_source_unref(s); + while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) + pa_source_output_push(o, chunk); + } } -void pa_source_set_owner(pa_source *s, pa_module *m) { - assert(s); - assert(s->ref >= 1); +pa_usec_t pa_source_get_latency(pa_source *s) { + pa_usec_t usec; - if (m == s->owner) - return; + pa_source_assert_ref(s); + pa_assert(PA_SOURCE_LINKED(s->state)); - s->owner = m; - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); -} + if (!PA_SOURCE_OPENED(s->state)) + return 0; -pa_usec_t pa_source_get_latency(pa_source *s) { - assert(s); - assert(s->ref >= 1); + if (s->get_latency) + return s->get_latency(s); - if (!s->get_latency) + if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0) return 0; - return s->get_latency(s); + return usec; } -void pa_source_set_volume(pa_source *s, pa_mixer_t m, const pa_cvolume *volume) { - pa_cvolume *v; +void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) { + int changed; - assert(s); - assert(s->ref >= 1); - assert(volume); + pa_source_assert_ref(s); + pa_assert(PA_SOURCE_LINKED(s->state)); + pa_assert(volume); - if (m == PA_MIXER_HARDWARE && s->set_hw_volume) - v = &s->hw_volume; - else - v = &s->sw_volume; + changed = !pa_cvolume_equal(volume, &s->volume); + s->volume = *volume; - if (pa_cvolume_equal(v, volume)) - return; + if (s->set_volume && s->set_volume(s) < 0) + s->set_volume = NULL; - *v = *volume; + if (!s->set_volume) + pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), 0, NULL, pa_xfree); - if (v == &s->hw_volume) - if (s->set_hw_volume(s) < 0) - s->sw_volume = *volume; + if (changed) + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); +} - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); +const pa_cvolume *pa_source_get_volume(pa_source *s) { + pa_cvolume old_volume; + + pa_source_assert_ref(s); + pa_assert(PA_SOURCE_LINKED(s->state)); + + old_volume = s->volume; + + if (s->get_volume && s->get_volume(s) < 0) + s->get_volume = NULL; + + if (!s->get_volume && s->refresh_volume) + pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, &s->volume, 0, NULL); + + if (!pa_cvolume_equal(&old_volume, &s->volume)) + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + + return &s->volume; } -const pa_cvolume *pa_source_get_volume(pa_source *s, pa_mixer_t m) { - assert(s); - assert(s->ref >= 1); +void pa_source_set_mute(pa_source *s, pa_bool_t mute) { + int changed; + + pa_source_assert_ref(s); + pa_assert(PA_SOURCE_LINKED(s->state)); + + changed = s->muted != mute; + s->muted = mute; - if (m == PA_MIXER_HARDWARE && s->set_hw_volume) { + if (s->set_mute && s->set_mute(s) < 0) + s->set_mute = NULL; - if (s->get_hw_volume) - s->get_hw_volume(s); + if (!s->set_mute) + pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, PA_UINT_TO_PTR(mute), 0, NULL, NULL); - return &s->hw_volume; - } else - return &s->sw_volume; + if (changed) + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } -void pa_source_set_mute(pa_source *s, pa_mixer_t m, int mute) { - int *t; +pa_bool_t pa_source_get_mute(pa_source *s) { + pa_bool_t old_muted; - assert(s); - assert(s->ref >= 1); + pa_source_assert_ref(s); + pa_assert(PA_SOURCE_LINKED(s->state)); - if (m == PA_MIXER_HARDWARE && s->set_hw_mute) - t = &s->hw_muted; - else - t = &s->sw_muted; + old_muted = s->muted; - if (!!*t == !!mute) - return; + if (s->get_mute && s->get_mute(s) < 0) + s->get_mute = NULL; - *t = !!mute; + if (!s->get_mute && s->refresh_muted) + pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, &s->muted, 0, NULL); - if (t == &s->hw_muted) - if (s->set_hw_mute(s) < 0) - s->sw_muted = !!mute; + if (old_muted != s->muted) + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + return s->muted; } -int pa_source_get_mute(pa_source *s, pa_mixer_t m) { - assert(s); - assert(s->ref >= 1); +void pa_source_set_module(pa_source *s, pa_module *m) { + pa_source_assert_ref(s); - if (m == PA_MIXER_HARDWARE && s->set_hw_mute) { + if (m == s->module) + return; - if (s->get_hw_mute) - s->get_hw_mute(s); + s->module = m; - return s->hw_muted; - } else - return s->sw_muted; + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } void pa_source_set_description(pa_source *s, const char *description) { - assert(s); - assert(s->ref >= 1); + pa_source_assert_ref(s); if (!description && !s->description) return; @@ -336,12 +418,172 @@ void pa_source_set_description(pa_source *s, const char *description) { pa_xfree(s->description); s->description = pa_xstrdup(description); - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + if (PA_SOURCE_LINKED(s->state)) { + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_DESCRIPTION_CHANGED], s); + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + } } -unsigned pa_source_used_by(pa_source *s) { - assert(s); - assert(s->ref >= 1); +void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) { + pa_source_assert_ref(s); + pa_assert(q); + + s->asyncmsgq = q; +} + +void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) { + pa_source_assert_ref(s); + pa_assert(p); + + s->rtpoll = p; +} + +unsigned pa_source_linked_by(pa_source *s) { + pa_source_assert_ref(s); + pa_assert(PA_SOURCE_LINKED(s->state)); return pa_idxset_size(s->outputs); } + +unsigned pa_source_used_by(pa_source *s) { + unsigned ret; + + pa_source_assert_ref(s); + pa_assert(PA_SOURCE_LINKED(s->state)); + + ret = pa_idxset_size(s->outputs); + pa_assert(ret >= s->n_corked); + + return ret - s->n_corked; +} + +int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *chunk) { + pa_source *s = PA_SOURCE(object); + pa_source_assert_ref(s); + pa_assert(s->thread_info.state != PA_SOURCE_UNLINKED); + + switch ((pa_source_message_t) code) { + case PA_SOURCE_MESSAGE_ADD_OUTPUT: { + pa_source_output *o = PA_SOURCE_OUTPUT(userdata); + pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index), pa_source_output_ref(o)); + + pa_assert(!o->thread_info.attached); + o->thread_info.attached = TRUE; + + if (o->attach) + o->attach(o); + + return 0; + } + + case PA_SOURCE_MESSAGE_REMOVE_OUTPUT: { + pa_source_output *o = PA_SOURCE_OUTPUT(userdata); + + if (o->detach) + o->detach(o); + + pa_assert(o->thread_info.attached); + o->thread_info.attached = FALSE; + + if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index))) + pa_source_output_unref(o); + + return 0; + } + + case PA_SOURCE_MESSAGE_SET_VOLUME: + s->thread_info.soft_volume = *((pa_cvolume*) userdata); + return 0; + + case PA_SOURCE_MESSAGE_SET_MUTE: + s->thread_info.soft_muted = PA_PTR_TO_UINT(userdata); + return 0; + + case PA_SOURCE_MESSAGE_GET_VOLUME: + *((pa_cvolume*) userdata) = s->thread_info.soft_volume; + return 0; + + case PA_SOURCE_MESSAGE_GET_MUTE: + *((pa_bool_t*) userdata) = s->thread_info.soft_muted; + return 0; + + case PA_SOURCE_MESSAGE_PING: + return 0; + + case PA_SOURCE_MESSAGE_SET_STATE: + s->thread_info.state = PA_PTR_TO_UINT(userdata); + return 0; + + case PA_SOURCE_MESSAGE_DETACH: + + /* We're detaching all our output streams so that the + * asyncmsgq and rtpoll fields can be changed without + * problems */ + pa_source_detach_within_thread(s); + break; + + case PA_SOURCE_MESSAGE_ATTACH: + + /* Reattach all streams */ + pa_source_attach_within_thread(s); + break; + + case PA_SOURCE_MESSAGE_GET_LATENCY: + case PA_SOURCE_MESSAGE_MAX: + ; + } + + return -1; +} + +int pa_source_suspend_all(pa_core *c, pa_bool_t suspend) { + uint32_t idx; + pa_source *source; + int ret = 0; + + pa_core_assert_ref(c); + + for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(c->sources, &idx))) + ret -= pa_source_suspend(source, suspend) < 0; + + return ret; +} + +void pa_source_detach(pa_source *s) { + pa_source_assert_ref(s); + pa_assert(PA_SOURCE_LINKED(s->state)); + + pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL); +} + +void pa_source_attach(pa_source *s) { + pa_source_assert_ref(s); + pa_assert(PA_SOURCE_LINKED(s->state)); + + pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL); +} + +void pa_source_detach_within_thread(pa_source *s) { + pa_source_output *o; + void *state = NULL; + + pa_source_assert_ref(s); + pa_assert(PA_SOURCE_LINKED(s->thread_info.state)); + + while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) + if (o->detach) + o->detach(o); +} + +void pa_source_attach_within_thread(pa_source *s) { + pa_source_output *o; + void *state = NULL; + + pa_source_assert_ref(s); + pa_assert(PA_SOURCE_LINKED(s->thread_info.state)); + + while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) + if (o->attach) + o->attach(o); + +} diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index 5a28cf4b..bd0a9122 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -1,5 +1,5 @@ -#ifndef foosourcehfoo -#define foosourcehfoo +#ifndef foopulsesourcehfoo +#define foopulsesourcehfoo /* $Id$ */ @@ -32,6 +32,7 @@ typedef struct pa_source pa_source; #include #include #include + #include #include #include @@ -39,73 +40,140 @@ typedef struct pa_source pa_source; #include #include #include +#include +#include +#include -#define PA_MAX_OUTPUTS_PER_SOURCE 16 +#define PA_MAX_OUTPUTS_PER_SOURCE 32 typedef enum pa_source_state { + PA_SOURCE_INIT, PA_SOURCE_RUNNING, - PA_SOURCE_DISCONNECTED + PA_SOURCE_SUSPENDED, + PA_SOURCE_IDLE, + PA_SOURCE_UNLINKED } pa_source_state_t; +static inline pa_bool_t PA_SOURCE_OPENED(pa_source_state_t x) { + return x == PA_SOURCE_RUNNING || x == PA_SOURCE_IDLE; +} + +static inline pa_bool_t PA_SOURCE_LINKED(pa_source_state_t x) { + return x == PA_SOURCE_RUNNING || x == PA_SOURCE_IDLE || x == PA_SOURCE_SUSPENDED; +} + struct pa_source { - int ref; + pa_msgobject parent; + uint32_t index; pa_core *core; pa_source_state_t state; + pa_source_flags_t flags; char *name; char *description, *driver; /* may be NULL */ - pa_module *owner; /* may be NULL */ + pa_module *module; /* may be NULL */ pa_sample_spec sample_spec; pa_channel_map channel_map; pa_idxset *outputs; + unsigned n_corked; pa_sink *monitor_of; /* may be NULL */ - pa_cvolume hw_volume, sw_volume; - int hw_muted, sw_muted; - - int is_hardware; + pa_cvolume volume; + pa_bool_t muted; + pa_bool_t refresh_volume; + pa_bool_t refresh_muted; - void (*notify)(pa_source*source); /* may be NULL */ + int (*set_state)(pa_source*source, pa_source_state_t state); /* may be NULL */ + int (*set_volume)(pa_source *s); /* dito */ + int (*get_volume)(pa_source *s); /* dito */ + int (*set_mute)(pa_source *s); /* dito */ + int (*get_mute)(pa_source *s); /* dito */ pa_usec_t (*get_latency)(pa_source *s); /* dito */ - int (*set_hw_volume)(pa_source *s); /* dito */ - int (*get_hw_volume)(pa_source *s); /* dito */ - int (*set_hw_mute)(pa_source *s); /* dito */ - int (*get_hw_mute)(pa_source *s); /* dito */ + + pa_asyncmsgq *asyncmsgq; + pa_rtpoll *rtpoll; + + /* Contains copies of the above data so that the real-time worker + * thread can work without access locking */ + struct { + pa_source_state_t state; + pa_hashmap *outputs; + pa_cvolume soft_volume; + pa_bool_t soft_muted; + } thread_info; void *userdata; }; +PA_DECLARE_CLASS(pa_source); +#define PA_SOURCE(s) pa_source_cast(s) + +typedef enum pa_source_message { + PA_SOURCE_MESSAGE_ADD_OUTPUT, + PA_SOURCE_MESSAGE_REMOVE_OUTPUT, + PA_SOURCE_MESSAGE_GET_VOLUME, + PA_SOURCE_MESSAGE_SET_VOLUME, + PA_SOURCE_MESSAGE_GET_MUTE, + PA_SOURCE_MESSAGE_SET_MUTE, + PA_SOURCE_MESSAGE_GET_LATENCY, + PA_SOURCE_MESSAGE_SET_STATE, + PA_SOURCE_MESSAGE_PING, + PA_SOURCE_MESSAGE_ATTACH, + PA_SOURCE_MESSAGE_DETACH, + PA_SOURCE_MESSAGE_MAX +} pa_source_message_t; + +/* To be called exclusively by the source driver, from main context */ + pa_source* pa_source_new( - pa_core *core, - const char *driver, - const char *name, - int namereg_fail, - const pa_sample_spec *spec, - const pa_channel_map *map); - -void pa_source_disconnect(pa_source *s); -void pa_source_unref(pa_source *s); -pa_source* pa_source_ref(pa_source *c); - -/* Pass a new memory block to all output streams */ -void pa_source_post(pa_source*s, const pa_memchunk *b); + pa_core *core, + const char *driver, + const char *name, + int namereg_fail, + const pa_sample_spec *spec, + const pa_channel_map *map); + +void pa_source_put(pa_source *s); +void pa_source_unlink(pa_source *s); -void pa_source_notify(pa_source *s); +void pa_source_set_module(pa_source *s, pa_module *m); +void pa_source_set_description(pa_source *s, const char *description); +void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q); +void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p); + +void pa_source_detach(pa_source *s); +void pa_source_attach(pa_source *s); -void pa_source_set_owner(pa_source *s, pa_module *m); +/* May be called by everyone, from main context */ pa_usec_t pa_source_get_latency(pa_source *s); -void pa_source_set_volume(pa_source *source, pa_mixer_t m, const pa_cvolume *volume); -const pa_cvolume *pa_source_get_volume(pa_source *source, pa_mixer_t m); -void pa_source_set_mute(pa_source *source, pa_mixer_t m, int mute); -int pa_source_get_mute(pa_source *source, pa_mixer_t m); +int pa_source_update_status(pa_source*s); +int pa_source_suspend(pa_source *s, pa_bool_t suspend); +int pa_source_suspend_all(pa_core *c, pa_bool_t suspend); -void pa_source_set_description(pa_source *s, const char *description); +void pa_source_ping(pa_source *s); + +void pa_source_set_volume(pa_source *source, const pa_cvolume *volume); +const pa_cvolume *pa_source_get_volume(pa_source *source); +void pa_source_set_mute(pa_source *source, pa_bool_t mute); +pa_bool_t pa_source_get_mute(pa_source *source); + +unsigned pa_source_linked_by(pa_source *s); /* Number of connected streams */ +unsigned pa_source_used_by(pa_source *s); /* Number of connected streams that are not corked */ +#define pa_source_get_state(s) ((pa_source_state_t) (s)->state) + +/* To be called exclusively by the source driver, from IO context */ + +void pa_source_post(pa_source*s, const pa_memchunk *b); + +int pa_source_process_msg(pa_msgobject *o, int code, void *userdata, int64_t, pa_memchunk *chunk); + +void pa_source_attach_within_thread(pa_source *s); +void pa_source_detach_within_thread(pa_source *s); -unsigned pa_source_used_by(pa_source *s); #endif diff --git a/src/pulsecore/speex/Makefile b/src/pulsecore/speex/Makefile new file mode 100644 index 00000000..316beb72 --- /dev/null +++ b/src/pulsecore/speex/Makefile @@ -0,0 +1,13 @@ +# This is a dirty trick just to ease compilation with emacs +# +# This file is not intended to be distributed or anything +# +# So: don't touch it, even better ignore it! + +all: + $(MAKE) -C ../.. + +clean: + $(MAKE) -C ../.. clean + +.PHONY: all clean diff --git a/src/pulsecore/speex/arch.h b/src/pulsecore/speex/arch.h new file mode 100644 index 00000000..4be693c3 --- /dev/null +++ b/src/pulsecore/speex/arch.h @@ -0,0 +1,197 @@ +/* Copyright (C) 2003 Jean-Marc Valin */ +/** + @file arch.h + @brief Various architecture definitions Speex +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef ARCH_H +#define ARCH_H + +#ifndef OUTSIDE_SPEEX +#include "speex/speex_types.h" +#endif + +#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */ +#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */ +#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 16-bit value. */ +#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */ +#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */ +#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 32-bit value. */ +#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */ + +#ifdef FIXED_POINT + +typedef spx_int16_t spx_word16_t; +typedef spx_int32_t spx_word32_t; +typedef spx_word32_t spx_mem_t; +typedef spx_word16_t spx_coef_t; +typedef spx_word16_t spx_lsp_t; +typedef spx_word32_t spx_sig_t; + +#define Q15ONE 32767 + +#define LPC_SCALING 8192 +#define SIG_SCALING 16384 +#define LSP_SCALING 8192. +#define GAMMA_SCALING 32768. +#define GAIN_SCALING 64 +#define GAIN_SCALING_1 0.015625 + +#define LPC_SHIFT 13 +#define LSP_SHIFT 13 +#define SIG_SHIFT 14 + +#define VERY_SMALL 0 +#define VERY_LARGE32 ((spx_word32_t)2147483647) +#define VERY_LARGE16 ((spx_word16_t)32767) +#define Q15_ONE ((spx_word16_t)32767) + + +#ifdef FIXED_DEBUG +#include "fixed_debug.h" +#else + +#include "fixed_generic.h" + +#ifdef ARM5E_ASM +#include "fixed_arm5e.h" +#elif defined (ARM4_ASM) +#include "fixed_arm4.h" +#elif defined (ARM5E_ASM) +#include "fixed_arm5e.h" +#elif defined (BFIN_ASM) +#include "fixed_bfin.h" +#endif + +#endif + + +#else + +typedef float spx_mem_t; +typedef float spx_coef_t; +typedef float spx_lsp_t; +typedef float spx_sig_t; +typedef float spx_word16_t; +typedef float spx_word32_t; + +#define Q15ONE 1.0f +#define LPC_SCALING 1.f +#define SIG_SCALING 1.f +#define LSP_SCALING 1.f +#define GAMMA_SCALING 1.f +#define GAIN_SCALING 1.f +#define GAIN_SCALING_1 1.f + +#define LPC_SHIFT 0 +#define LSP_SHIFT 0 +#define SIG_SHIFT 0 + +#define VERY_SMALL 1e-15f +#define VERY_LARGE32 1e15f +#define VERY_LARGE16 1e15f +#define Q15_ONE ((spx_word16_t)1.f) + +#define QCONST16(x,bits) (x) +#define QCONST32(x,bits) (x) + +#define NEG16(x) (-(x)) +#define NEG32(x) (-(x)) +#define EXTRACT16(x) (x) +#define EXTEND32(x) (x) +#define SHR16(a,shift) (a) +#define SHL16(a,shift) (a) +#define SHR32(a,shift) (a) +#define SHL32(a,shift) (a) +#define PSHR16(a,shift) (a) +#define PSHR32(a,shift) (a) +#define VSHR32(a,shift) (a) +#define SATURATE16(x,a) (x) +#define SATURATE32(x,a) (x) + +#define PSHR(a,shift) (a) +#define SHR(a,shift) (a) +#define SHL(a,shift) (a) +#define SATURATE(x,a) (x) + +#define ADD16(a,b) ((a)+(b)) +#define SUB16(a,b) ((a)-(b)) +#define ADD32(a,b) ((a)+(b)) +#define SUB32(a,b) ((a)-(b)) +#define MULT16_16_16(a,b) ((a)*(b)) +#define MULT16_16(a,b) ((spx_word32_t)(a)*(spx_word32_t)(b)) +#define MAC16_16(c,a,b) ((c)+(spx_word32_t)(a)*(spx_word32_t)(b)) + +#define MULT16_32_Q11(a,b) ((a)*(b)) +#define MULT16_32_Q13(a,b) ((a)*(b)) +#define MULT16_32_Q14(a,b) ((a)*(b)) +#define MULT16_32_Q15(a,b) ((a)*(b)) +#define MULT16_32_P15(a,b) ((a)*(b)) + +#define MAC16_32_Q11(c,a,b) ((c)+(a)*(b)) +#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) + +#define MAC16_16_Q11(c,a,b) ((c)+(a)*(b)) +#define MAC16_16_Q13(c,a,b) ((c)+(a)*(b)) +#define MAC16_16_P13(c,a,b) ((c)+(a)*(b)) +#define MULT16_16_Q11_32(a,b) ((a)*(b)) +#define MULT16_16_Q13(a,b) ((a)*(b)) +#define MULT16_16_Q14(a,b) ((a)*(b)) +#define MULT16_16_Q15(a,b) ((a)*(b)) +#define MULT16_16_P15(a,b) ((a)*(b)) +#define MULT16_16_P13(a,b) ((a)*(b)) +#define MULT16_16_P14(a,b) ((a)*(b)) + +#define DIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b)) +#define PDIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b)) +#define DIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) +#define PDIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) + + +#endif + + +#if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) + +/* 2 on TI C5x DSP */ +#define BYTES_PER_CHAR 2 +#define BITS_PER_CHAR 16 +#define LOG2_BITS_PER_CHAR 4 + +#else + +#define BYTES_PER_CHAR 1 +#define BITS_PER_CHAR 8 +#define LOG2_BITS_PER_CHAR 3 + +#endif + +#endif diff --git a/src/pulsecore/speex/fixed_generic.h b/src/pulsecore/speex/fixed_generic.h new file mode 100644 index 00000000..547e22c7 --- /dev/null +++ b/src/pulsecore/speex/fixed_generic.h @@ -0,0 +1,106 @@ +/* Copyright (C) 2003 Jean-Marc Valin */ +/** + @file fixed_generic.h + @brief Generic fixed-point operations +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_GENERIC_H +#define FIXED_GENERIC_H + +#define QCONST16(x,bits) ((spx_word16_t)(.5+(x)*(((spx_word32_t)1)<<(bits)))) +#define QCONST32(x,bits) ((spx_word32_t)(.5+(x)*(((spx_word32_t)1)<<(bits)))) + +#define NEG16(x) (-(x)) +#define NEG32(x) (-(x)) +#define EXTRACT16(x) ((spx_word16_t)(x)) +#define EXTEND32(x) ((spx_word32_t)(x)) +#define SHR16(a,shift) ((a) >> (shift)) +#define SHL16(a,shift) ((a) << (shift)) +#define SHR32(a,shift) ((a) >> (shift)) +#define SHL32(a,shift) ((a) << (shift)) +#define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift)) +#define PSHR32(a,shift) (SHR32((a)+((1<<((shift))>>1)),shift)) +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) +#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) +#define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + +#define SHR(a,shift) ((a) >> (shift)) +#define SHL(a,shift) ((spx_word32_t)(a) << (shift)) +#define PSHR(a,shift) (SHR((a)+((1<<((shift))>>1)),shift)) +#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + + +#define ADD16(a,b) ((spx_word16_t)((spx_word16_t)(a)+(spx_word16_t)(b))) +#define SUB16(a,b) ((spx_word16_t)(a)-(spx_word16_t)(b)) +#define ADD32(a,b) ((spx_word32_t)(a)+(spx_word32_t)(b)) +#define SUB32(a,b) ((spx_word32_t)(a)-(spx_word32_t)(b)) + + +/* result fits in 16 bits */ +#define MULT16_16_16(a,b) ((((spx_word16_t)(a))*((spx_word16_t)(b)))) + +/* (spx_word32_t)(spx_word16_t) gives TI compiler a hint that it's 16x16->32 multiply */ +#define MULT16_16(a,b) (((spx_word32_t)(spx_word16_t)(a))*((spx_word32_t)(spx_word16_t)(b))) + +#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b)))) +#define MULT16_32_Q12(a,b) ADD32(MULT16_16((a),SHR((b),12)), SHR(MULT16_16((a),((b)&0x00000fff)),12)) +#define MULT16_32_Q13(a,b) ADD32(MULT16_16((a),SHR((b),13)), SHR(MULT16_16((a),((b)&0x00001fff)),13)) +#define MULT16_32_Q14(a,b) ADD32(MULT16_16((a),SHR((b),14)), SHR(MULT16_16((a),((b)&0x00003fff)),14)) + +#define MULT16_32_Q11(a,b) ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11)) +#define MAC16_32_Q11(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11))) + +#define MULT16_32_P15(a,b) ADD32(MULT16_16((a),SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15)) +#define MULT16_32_Q15(a,b) ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)) +#define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))) + + +#define MAC16_16_Q11(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),11))) +#define MAC16_16_Q13(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),13))) +#define MAC16_16_P13(c,a,b) (ADD32((c),SHR(ADD32(4096,MULT16_16((a),(b))),13))) + +#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11)) +#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13)) +#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14)) +#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15)) + +#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13)) +#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14)) +#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15)) + +#define MUL_16_32_R15(a,bh,bl) ADD32(MULT16_16((a),(bh)), SHR(MULT16_16((a),(bl)),15)) + +#define DIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a))/((spx_word16_t)(b)))) +#define PDIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word16_t)(b)))) +#define DIV32(a,b) (((spx_word32_t)(a))/((spx_word32_t)(b))) +#define PDIV32(a,b) (((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word32_t)(b))) + +#endif diff --git a/src/pulsecore/speex/resample.c b/src/pulsecore/speex/resample.c new file mode 100644 index 00000000..bf1f88b4 --- /dev/null +++ b/src/pulsecore/speex/resample.c @@ -0,0 +1,1114 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: resample.c + Arbitrary resampling code + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + The design goals of this code are: + - Very fast algorithm + - SIMD-friendly algorithm + - Low memory requirement + - Good *perceptual* quality (and not best SNR) + + The code is working, but it's in a very early stage, so it may have + artifacts, noise or subliminal messages from satan. Also, the API + isn't stable and I can actually promise that I *will* change the API + some time in the future. + +TODO list: + - Variable calculation resolution depending on quality setting + - Single vs double in float mode + - 16-bit vs 32-bit (sinc only) in fixed-point mode + - Make sure the filter update works even when changing params + after only a few samples procesed +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef OUTSIDE_SPEEX +#include +static void *speex_alloc (int size) {return calloc(size,1);} +static void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);} +static void speex_free (void *ptr) {free(ptr);} +#include "speex_resampler.h" +#include "arch.h" +#else /* OUTSIDE_SPEEX */ + +#include "speex/speex_resampler.h" +#include "misc.h" +#endif /* OUTSIDE_SPEEX */ + +#include + +#ifndef M_PI +#define M_PI 3.14159263 +#endif + +#ifdef FIXED_POINT +#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) +#else +#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) +#endif + +/*#define float double*/ +#define FILTER_SIZE 64 +#define OVERSAMPLE 8 + +#define IMAX(a,b) ((a) > (b) ? (a) : (b)) +#define IMIN(a,b) ((a) < (b) ? (a) : (b)) + +#ifndef NULL +#define NULL 0 +#endif + +typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *); + +struct SpeexResamplerState_ { + spx_uint32_t in_rate; + spx_uint32_t out_rate; + spx_uint32_t num_rate; + spx_uint32_t den_rate; + + int quality; + spx_uint32_t nb_channels; + spx_uint32_t filt_len; + spx_uint32_t mem_alloc_size; + int int_advance; + int frac_advance; + float cutoff; + spx_uint32_t oversample; + int initialised; + int started; + + /* These are per-channel */ + spx_int32_t *last_sample; + spx_uint32_t *samp_frac_num; + spx_uint32_t *magic_samples; + + spx_word16_t *mem; + spx_word16_t *sinc_table; + spx_uint32_t sinc_table_length; + resampler_basic_func resampler_ptr; + + int in_stride; + int out_stride; +} ; + +static double kaiser12_table[68] = { + 0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076, + 0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014, + 0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601, + 0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014, + 0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490, + 0.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546, + 0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178, + 0.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947, + 0.02584161, 0.02127838, 0.01736250, 0.01402878, 0.01121463, 0.00886058, + 0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438, + 0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734, + 0.00001000, 0.00000000}; +/* +static double kaiser12_table[36] = { + 0.99440475, 1.00000000, 0.99440475, 0.97779076, 0.95066529, 0.91384741, + 0.86843014, 0.81573067, 0.75723148, 0.69451601, 0.62920216, 0.56287762, + 0.49704014, 0.43304576, 0.37206735, 0.31506490, 0.26276832, 0.21567274, + 0.17404546, 0.13794294, 0.10723616, 0.08164178, 0.06075685, 0.04409466, + 0.03111947, 0.02127838, 0.01402878, 0.00886058, 0.00531256, 0.00298291, + 0.00153438, 0.00069463, 0.00025272, 0.0000527734, 0.00000500, 0.00000000}; +*/ +static double kaiser10_table[36] = { + 0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446, + 0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347, + 0.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962, + 0.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451, + 0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739, + 0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000}; + +static double kaiser8_table[36] = { + 0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200, + 0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126, + 0.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272, + 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758, + 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490, + 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000}; + +static double kaiser6_table[36] = { + 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003, + 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565, + 0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561, + 0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058, + 0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600, + 0.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000}; + +struct FuncDef { + double *table; + int oversample; +}; + +static struct FuncDef _KAISER12 = {kaiser12_table, 64}; +#define KAISER12 (&_KAISER12) +/*static struct FuncDef _KAISER12 = {kaiser12_table, 32}; +#define KAISER12 (&_KAISER12)*/ +static struct FuncDef _KAISER10 = {kaiser10_table, 32}; +#define KAISER10 (&_KAISER10) +static struct FuncDef _KAISER8 = {kaiser8_table, 32}; +#define KAISER8 (&_KAISER8) +static struct FuncDef _KAISER6 = {kaiser6_table, 32}; +#define KAISER6 (&_KAISER6) + +struct QualityMapping { + int base_length; + int oversample; + float downsample_bandwidth; + float upsample_bandwidth; + struct FuncDef *window_func; +}; + + +/* This table maps conversion quality to internal parameters. There are two + reasons that explain why the up-sampling bandwidth is larger than the + down-sampling bandwidth: + 1) When up-sampling, we can assume that the spectrum is already attenuated + close to the Nyquist rate (from an A/D or a previous resampling filter) + 2) Any aliasing that occurs very close to the Nyquist rate will be masked + by the sinusoids/noise just below the Nyquist rate (guaranteed only for + up-sampling). +*/ +static const struct QualityMapping quality_map[11] = { + { 8, 4, 0.830f, 0.860f, KAISER6 }, /* Q0 */ + { 16, 4, 0.850f, 0.880f, KAISER6 }, /* Q1 */ + { 32, 4, 0.882f, 0.910f, KAISER6 }, /* Q2 */ /* 82.3% cutoff ( ~60 dB stop) 6 */ + { 48, 8, 0.895f, 0.917f, KAISER8 }, /* Q3 */ /* 84.9% cutoff ( ~80 dB stop) 8 */ + { 64, 8, 0.921f, 0.940f, KAISER8 }, /* Q4 */ /* 88.7% cutoff ( ~80 dB stop) 8 */ + { 80, 16, 0.922f, 0.940f, KAISER10}, /* Q5 */ /* 89.1% cutoff (~100 dB stop) 10 */ + { 96, 16, 0.940f, 0.945f, KAISER10}, /* Q6 */ /* 91.5% cutoff (~100 dB stop) 10 */ + {128, 16, 0.950f, 0.950f, KAISER10}, /* Q7 */ /* 93.1% cutoff (~100 dB stop) 10 */ + {160, 16, 0.960f, 0.960f, KAISER10}, /* Q8 */ /* 94.5% cutoff (~100 dB stop) 10 */ + {192, 32, 0.968f, 0.968f, KAISER12}, /* Q9 */ /* 95.5% cutoff (~100 dB stop) 10 */ + {256, 32, 0.975f, 0.975f, KAISER12}, /* Q10 */ /* 96.6% cutoff (~100 dB stop) 10 */ +}; +/*8,24,40,56,80,104,128,160,200,256,320*/ +static double compute_func(float x, struct FuncDef *func) +{ + float y, frac; + double interp[4]; + int ind; + y = x*func->oversample; + ind = (int)floor(y); + frac = (y-ind); + /* CSE with handle the repeated powers */ + interp[3] = -0.1666666667*frac + 0.1666666667*(frac*frac*frac); + interp[2] = frac + 0.5*(frac*frac) - 0.5*(frac*frac*frac); + /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/ + interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac); + /* Just to make sure we don't have rounding problems */ + interp[1] = 1.f-interp[3]-interp[2]-interp[0]; + + /*sum = frac*accum[1] + (1-frac)*accum[2];*/ + return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3]; +} + +#if 0 +#include +int main(int argc, char **argv) +{ + int i; + for (i=0;i<256;i++) + { + printf ("%f\n", compute_func(i/256., KAISER12)); + } + return 0; +} +#endif + +#ifdef FIXED_POINT +/* The slow way of computing a sinc for the table. Should improve that some day */ +static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func) +{ + /*fprintf (stderr, "%f ", x);*/ + float xx = x * cutoff; + if (fabs(x)<1e-6f) + return WORD2INT(32768.*cutoff); + else if (fabs(x) > .5f*N) + return 0; + /*FIXME: Can it really be any slower than this? */ + return WORD2INT(32768.*cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func)); +} +#else +/* The slow way of computing a sinc for the table. Should improve that some day */ +static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func) +{ + /*fprintf (stderr, "%f ", x);*/ + float xx = x * cutoff; + if (fabs(x)<1e-6) + return cutoff; + else if (fabs(x) > .5*N) + return 0; + /*FIXME: Can it really be any slower than this? */ + return cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func); +} +#endif + +#ifdef FIXED_POINT +static void cubic_coef(spx_word16_t x, spx_word16_t interp[4]) +{ + /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation + but I know it's MMSE-optimal on a sinc */ + spx_word16_t x2, x3; + x2 = MULT16_16_P15(x, x); + x3 = MULT16_16_P15(x, x2); + interp[0] = PSHR32(MULT16_16(QCONST16(-0.16667f, 15),x) + MULT16_16(QCONST16(0.16667f, 15),x3),15); + interp[1] = EXTRACT16(EXTEND32(x) + SHR32(SUB32(EXTEND32(x2),EXTEND32(x3)),1)); + interp[3] = PSHR32(MULT16_16(QCONST16(-0.33333f, 15),x) + MULT16_16(QCONST16(.5f,15),x2) - MULT16_16(QCONST16(0.16667f, 15),x3),15); + /* Just to make sure we don't have rounding problems */ + interp[2] = Q15_ONE-interp[0]-interp[1]-interp[3]; + if (interp[2]<32767) + interp[2]+=1; +} +#else +static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4]) +{ + /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation + but I know it's MMSE-optimal on a sinc */ + interp[0] = -0.16667f*frac + 0.16667f*frac*frac*frac; + interp[1] = frac + 0.5f*frac*frac - 0.5f*frac*frac*frac; + /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/ + interp[3] = -0.33333f*frac + 0.5f*frac*frac - 0.16667f*frac*frac*frac; + /* Just to make sure we don't have rounding problems */ + interp[2] = 1.-interp[0]-interp[1]-interp[3]; +} +#endif + +static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + int N = st->filt_len; + int out_sample = 0; + spx_word16_t *mem; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + mem = st->mem + channel_index * st->mem_alloc_size; + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + int j; + spx_word32_t sum=0; + + /* We already have all the filter coefficients pre-computed in the table */ + const spx_word16_t *ptr; + /* Do the memory part */ + for (j=0;last_sample-N+1+j < 0;j++) + { + sum += MULT16_16(mem[last_sample+j],st->sinc_table[samp_frac_num*st->filt_len+j]); + } + + /* Do the new part */ + ptr = in+st->in_stride*(last_sample-N+1+j); + for (;jsinc_table[samp_frac_num*st->filt_len+j]); + ptr += st->in_stride; + } + + *out = PSHR32(sum,15); + out += st->out_stride; + out_sample++; + last_sample += st->int_advance; + samp_frac_num += st->frac_advance; + if (samp_frac_num >= st->den_rate) + { + samp_frac_num -= st->den_rate; + last_sample++; + } + } + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} + +#ifdef FIXED_POINT +#else +/* This is the same as the previous function, except with a double-precision accumulator */ +static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + int N = st->filt_len; + int out_sample = 0; + spx_word16_t *mem; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + mem = st->mem + channel_index * st->mem_alloc_size; + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + int j; + double sum=0; + + /* We already have all the filter coefficients pre-computed in the table */ + const spx_word16_t *ptr; + /* Do the memory part */ + for (j=0;last_sample-N+1+j < 0;j++) + { + sum += MULT16_16(mem[last_sample+j],(double)st->sinc_table[samp_frac_num*st->filt_len+j]); + } + + /* Do the new part */ + ptr = in+st->in_stride*(last_sample-N+1+j); + for (;jsinc_table[samp_frac_num*st->filt_len+j]); + ptr += st->in_stride; + } + + *out = sum; + out += st->out_stride; + out_sample++; + last_sample += st->int_advance; + samp_frac_num += st->frac_advance; + if (samp_frac_num >= st->den_rate) + { + samp_frac_num -= st->den_rate; + last_sample++; + } + } + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} +#endif + +static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + int N = st->filt_len; + int out_sample = 0; + spx_word16_t *mem; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + mem = st->mem + channel_index * st->mem_alloc_size; + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + int j; + spx_word32_t sum=0; + + /* We need to interpolate the sinc filter */ + spx_word32_t accum[4] = {0.f,0.f, 0.f, 0.f}; + spx_word16_t interp[4]; + const spx_word16_t *ptr; + int offset; + spx_word16_t frac; + offset = samp_frac_num*st->oversample/st->den_rate; +#ifdef FIXED_POINT + frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); +#else + frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; +#endif + /* This code is written like this to make it easy to optimise with SIMD. + For most DSPs, it would be best to split the loops in two because most DSPs + have only two accumulators */ + for (j=0;last_sample-N+1+j < 0;j++) + { + spx_word16_t curr_mem = mem[last_sample+j]; + accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]); + accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]); + accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]); + accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]); + } + ptr = in+st->in_stride*(last_sample-N+1+j); + /* Do the new part */ + for (;jin_stride; + accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]); + accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); + accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); + accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); + } + cubic_coef(frac, interp); + sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]); + + *out = PSHR32(sum,15); + out += st->out_stride; + out_sample++; + last_sample += st->int_advance; + samp_frac_num += st->frac_advance; + if (samp_frac_num >= st->den_rate) + { + samp_frac_num -= st->den_rate; + last_sample++; + } + } + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} + +#ifdef FIXED_POINT +#else +/* This is the same as the previous function, except with a double-precision accumulator */ +static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + int N = st->filt_len; + int out_sample = 0; + spx_word16_t *mem; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + mem = st->mem + channel_index * st->mem_alloc_size; + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + int j; + spx_word32_t sum=0; + + /* We need to interpolate the sinc filter */ + double accum[4] = {0.f,0.f, 0.f, 0.f}; + float interp[4]; + const spx_word16_t *ptr; + float alpha = ((float)samp_frac_num)/st->den_rate; + int offset = samp_frac_num*st->oversample/st->den_rate; + float frac = alpha*st->oversample - offset; + /* This code is written like this to make it easy to optimise with SIMD. + For most DSPs, it would be best to split the loops in two because most DSPs + have only two accumulators */ + for (j=0;last_sample-N+1+j < 0;j++) + { + double curr_mem = mem[last_sample+j]; + accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]); + accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]); + accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]); + accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]); + } + ptr = in+st->in_stride*(last_sample-N+1+j); + /* Do the new part */ + for (;jin_stride; + accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]); + accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); + accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); + accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); + } + cubic_coef(frac, interp); + sum = interp[0]*accum[0] + interp[1]*accum[1] + interp[2]*accum[2] + interp[3]*accum[3]; + + *out = PSHR32(sum,15); + out += st->out_stride; + out_sample++; + last_sample += st->int_advance; + samp_frac_num += st->frac_advance; + if (samp_frac_num >= st->den_rate) + { + samp_frac_num -= st->den_rate; + last_sample++; + } + } + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} +#endif + +static void update_filter(SpeexResamplerState *st) +{ + spx_uint32_t old_length; + + old_length = st->filt_len; + st->oversample = quality_map[st->quality].oversample; + st->filt_len = quality_map[st->quality].base_length; + + if (st->num_rate > st->den_rate) + { + /* down-sampling */ + st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate; + /* FIXME: divide the numerator and denominator by a certain amount if they're too large */ + st->filt_len = st->filt_len*st->num_rate / st->den_rate; + /* Round down to make sure we have a multiple of 4 */ + st->filt_len &= (~0x3); + if (2*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (4*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (8*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (16*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (st->oversample < 1) + st->oversample = 1; + } else { + /* up-sampling */ + st->cutoff = quality_map[st->quality].upsample_bandwidth; + } + + /* Choose the resampling type that requires the least amount of memory */ + if (st->den_rate <= st->oversample) + { + spx_uint32_t i; + if (!st->sinc_table) + st->sinc_table = (spx_word16_t *)speex_alloc(st->filt_len*st->den_rate*sizeof(spx_word16_t)); + else if (st->sinc_table_length < st->filt_len*st->den_rate) + { + st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,st->filt_len*st->den_rate*sizeof(spx_word16_t)); + st->sinc_table_length = st->filt_len*st->den_rate; + } + for (i=0;iden_rate;i++) + { + spx_int32_t j; + for (j=0;jfilt_len;j++) + { + st->sinc_table[i*st->filt_len+j] = sinc(st->cutoff,((j-(spx_int32_t)st->filt_len/2+1)-((float)i)/st->den_rate), st->filt_len, quality_map[st->quality].window_func); + } + } +#ifdef FIXED_POINT + st->resampler_ptr = resampler_basic_direct_single; +#else + if (st->quality>8) + st->resampler_ptr = resampler_basic_direct_double; + else + st->resampler_ptr = resampler_basic_direct_single; +#endif + /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/ + } else { + spx_int32_t i; + if (!st->sinc_table) + st->sinc_table = (spx_word16_t *)speex_alloc((st->filt_len*st->oversample+8)*sizeof(spx_word16_t)); + else if (st->sinc_table_length < st->filt_len*st->oversample+8) + { + st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,(st->filt_len*st->oversample+8)*sizeof(spx_word16_t)); + st->sinc_table_length = st->filt_len*st->oversample+8; + } + for (i=-4;i<(spx_int32_t)(st->oversample*st->filt_len+4);i++) + st->sinc_table[i+4] = sinc(st->cutoff,(i/(float)st->oversample - st->filt_len/2), st->filt_len, quality_map[st->quality].window_func); +#ifdef FIXED_POINT + st->resampler_ptr = resampler_basic_interpolate_single; +#else + if (st->quality>8) + st->resampler_ptr = resampler_basic_interpolate_double; + else + st->resampler_ptr = resampler_basic_interpolate_single; +#endif + /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/ + } + st->int_advance = st->num_rate/st->den_rate; + st->frac_advance = st->num_rate%st->den_rate; + + + /* Here's the place where we update the filter memory to take into account + the change in filter length. It's probably the messiest part of the code + due to handling of lots of corner cases. */ + if (!st->mem) + { + spx_uint32_t i; + st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); + for (i=0;inb_channels*(st->filt_len-1);i++) + st->mem[i] = 0; + st->mem_alloc_size = st->filt_len-1; + /*speex_warning("init filter");*/ + } else if (!st->started) + { + spx_uint32_t i; + st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); + for (i=0;inb_channels*(st->filt_len-1);i++) + st->mem[i] = 0; + st->mem_alloc_size = st->filt_len-1; + /*speex_warning("reinit filter");*/ + } else if (st->filt_len > old_length) + { + spx_int32_t i; + /* Increase the filter length */ + /*speex_warning("increase filter size");*/ + int old_alloc_size = st->mem_alloc_size; + if (st->filt_len-1 > st->mem_alloc_size) + { + st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); + st->mem_alloc_size = st->filt_len-1; + } + for (i=st->nb_channels-1;i>=0;i--) + { + spx_int32_t j; + spx_uint32_t olen = old_length; + /*if (st->magic_samples[i])*/ + { + /* Try and remove the magic samples as if nothing had happened */ + + /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */ + olen = old_length + 2*st->magic_samples[i]; + for (j=old_length-2+st->magic_samples[i];j>=0;j--) + st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]] = st->mem[i*old_alloc_size+j]; + for (j=0;jmagic_samples[i];j++) + st->mem[i*st->mem_alloc_size+j] = 0; + st->magic_samples[i] = 0; + } + if (st->filt_len > olen) + { + /* If the new filter length is still bigger than the "augmented" length */ + /* Copy data going backward */ + for (j=0;jmem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*st->mem_alloc_size+(olen-2-j)]; + /* Then put zeros for lack of anything better */ + for (;jfilt_len-1;j++) + st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0; + /* Adjust last_sample */ + st->last_sample[i] += (st->filt_len - olen)/2; + } else { + /* Put back some of the magic! */ + st->magic_samples[i] = (olen - st->filt_len)/2; + for (j=0;jfilt_len-1+st->magic_samples[i];j++) + st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]]; + } + } + } else if (st->filt_len < old_length) + { + spx_uint32_t i; + /* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic" + samples so they can be used directly as input the next time(s) */ + for (i=0;inb_channels;i++) + { + spx_uint32_t j; + spx_uint32_t old_magic = st->magic_samples[i]; + st->magic_samples[i] = (old_length - st->filt_len)/2; + /* We must copy some of the memory that's no longer used */ + /* Copy data going backward */ + for (j=0;jfilt_len-1+st->magic_samples[i]+old_magic;j++) + st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]]; + st->magic_samples[i] += old_magic; + } + } + +} + +SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) +{ + return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err); +} + +SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) +{ + spx_uint32_t i; + SpeexResamplerState *st; + if (quality > 10 || quality < 0) + { + if (err) + *err = RESAMPLER_ERR_INVALID_ARG; + return NULL; + } + st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState)); + st->initialised = 0; + st->started = 0; + st->in_rate = 0; + st->out_rate = 0; + st->num_rate = 0; + st->den_rate = 0; + st->quality = -1; + st->sinc_table_length = 0; + st->mem_alloc_size = 0; + st->filt_len = 0; + st->mem = 0; + st->resampler_ptr = 0; + + st->cutoff = 1.f; + st->nb_channels = nb_channels; + st->in_stride = 1; + st->out_stride = 1; + + /* Per channel data */ + st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int)); + st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int)); + st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int)); + for (i=0;ilast_sample[i] = 0; + st->magic_samples[i] = 0; + st->samp_frac_num[i] = 0; + } + + speex_resampler_set_quality(st, quality); + speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate); + + + update_filter(st); + + st->initialised = 1; + if (err) + *err = RESAMPLER_ERR_SUCCESS; + + return st; +} + +void speex_resampler_destroy(SpeexResamplerState *st) +{ + speex_free(st->mem); + speex_free(st->sinc_table); + speex_free(st->last_sample); + speex_free(st->magic_samples); + speex_free(st->samp_frac_num); + speex_free(st); +} + + + +static int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + int j=0; + int N = st->filt_len; + int out_sample = 0; + spx_word16_t *mem; + spx_uint32_t tmp_out_len = 0; + mem = st->mem + channel_index * st->mem_alloc_size; + st->started = 1; + + /* Handle the case where we have samples left from a reduction in filter length */ + if (st->magic_samples[channel_index]) + { + int istride_save; + spx_uint32_t tmp_in_len; + spx_uint32_t tmp_magic; + + istride_save = st->in_stride; + tmp_in_len = st->magic_samples[channel_index]; + tmp_out_len = *out_len; + /* magic_samples needs to be set to zero to avoid infinite recursion */ + tmp_magic = st->magic_samples[channel_index]; + st->magic_samples[channel_index] = 0; + st->in_stride = 1; + speex_resampler_process_native(st, channel_index, mem+N-1, &tmp_in_len, out, &tmp_out_len); + st->in_stride = istride_save; + /*speex_warning_int("extra samples:", tmp_out_len);*/ + /* If we couldn't process all "magic" input samples, save the rest for next time */ + if (tmp_in_len < tmp_magic) + { + spx_uint32_t i; + st->magic_samples[channel_index] = tmp_magic-tmp_in_len; + for (i=0;imagic_samples[channel_index];i++) + mem[N-1+i]=mem[N-1+i+tmp_in_len]; + } + out += tmp_out_len*st->out_stride; + *out_len -= tmp_out_len; + } + + /* Call the right resampler through the function ptr */ + out_sample = st->resampler_ptr(st, channel_index, in, in_len, out, out_len); + + if (st->last_sample[channel_index] < (spx_int32_t)*in_len) + *in_len = st->last_sample[channel_index]; + *out_len = out_sample+tmp_out_len; + st->last_sample[channel_index] -= *in_len; + + for (j=0;jin_stride*(j+*in_len-N+1)]; + + return RESAMPLER_ERR_SUCCESS; +} + +#define FIXED_STACK_ALLOC 1024 + +#ifdef FIXED_POINT +int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) +{ + spx_uint32_t i; + int istride_save, ostride_save; +#ifdef VAR_ARRAYS + spx_word16_t x[*in_len]; + spx_word16_t y[*out_len]; + /*VARDECL(spx_word16_t *x); + VARDECL(spx_word16_t *y); + ALLOC(x, *in_len, spx_word16_t); + ALLOC(y, *out_len, spx_word16_t);*/ + istride_save = st->in_stride; + ostride_save = st->out_stride; + for (i=0;i<*in_len;i++) + x[i] = WORD2INT(in[i*st->in_stride]); + st->in_stride = st->out_stride = 1; + speex_resampler_process_native(st, channel_index, x, in_len, y, out_len); + st->in_stride = istride_save; + st->out_stride = ostride_save; + for (i=0;i<*out_len;i++) + out[i*st->out_stride] = y[i]; +#else + spx_word16_t x[FIXED_STACK_ALLOC]; + spx_word16_t y[FIXED_STACK_ALLOC]; + spx_uint32_t ilen=*in_len, olen=*out_len; + istride_save = st->in_stride; + ostride_save = st->out_stride; + while (ilen && olen) + { + spx_uint32_t ichunk, ochunk; + ichunk = ilen; + ochunk = olen; + if (ichunk>FIXED_STACK_ALLOC) + ichunk=FIXED_STACK_ALLOC; + if (ochunk>FIXED_STACK_ALLOC) + ochunk=FIXED_STACK_ALLOC; + for (i=0;iin_stride]); + st->in_stride = st->out_stride = 1; + speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk); + st->in_stride = istride_save; + st->out_stride = ostride_save; + for (i=0;iout_stride] = y[i]; + out += ochunk; + in += ichunk; + ilen -= ichunk; + olen -= ochunk; + } + *in_len -= ilen; + *out_len -= olen; +#endif + return RESAMPLER_ERR_SUCCESS; +} +int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) +{ + return speex_resampler_process_native(st, channel_index, in, in_len, out, out_len); +} +#else +int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) +{ + return speex_resampler_process_native(st, channel_index, in, in_len, out, out_len); +} +int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) +{ + spx_uint32_t i; + int istride_save, ostride_save; +#ifdef VAR_ARRAYS + spx_word16_t x[*in_len]; + spx_word16_t y[*out_len]; + /*VARDECL(spx_word16_t *x); + VARDECL(spx_word16_t *y); + ALLOC(x, *in_len, spx_word16_t); + ALLOC(y, *out_len, spx_word16_t);*/ + istride_save = st->in_stride; + ostride_save = st->out_stride; + for (i=0;i<*in_len;i++) + x[i] = in[i*st->in_stride]; + st->in_stride = st->out_stride = 1; + speex_resampler_process_native(st, channel_index, x, in_len, y, out_len); + st->in_stride = istride_save; + st->out_stride = ostride_save; + for (i=0;i<*out_len;i++) + out[i*st->out_stride] = WORD2INT(y[i]); +#else + spx_word16_t x[FIXED_STACK_ALLOC]; + spx_word16_t y[FIXED_STACK_ALLOC]; + spx_uint32_t ilen=*in_len, olen=*out_len; + istride_save = st->in_stride; + ostride_save = st->out_stride; + while (ilen && olen) + { + spx_uint32_t ichunk, ochunk; + ichunk = ilen; + ochunk = olen; + if (ichunk>FIXED_STACK_ALLOC) + ichunk=FIXED_STACK_ALLOC; + if (ochunk>FIXED_STACK_ALLOC) + ochunk=FIXED_STACK_ALLOC; + for (i=0;iin_stride]; + st->in_stride = st->out_stride = 1; + speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk); + st->in_stride = istride_save; + st->out_stride = ostride_save; + for (i=0;iout_stride] = WORD2INT(y[i]); + out += ochunk; + in += ichunk; + ilen -= ichunk; + olen -= ochunk; + } + *in_len -= ilen; + *out_len -= olen; +#endif + return RESAMPLER_ERR_SUCCESS; +} +#endif + +int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) +{ + spx_uint32_t i; + int istride_save, ostride_save; + spx_uint32_t bak_len = *out_len; + istride_save = st->in_stride; + ostride_save = st->out_stride; + st->in_stride = st->out_stride = st->nb_channels; + for (i=0;inb_channels;i++) + { + *out_len = bak_len; + speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len); + } + st->in_stride = istride_save; + st->out_stride = ostride_save; + return RESAMPLER_ERR_SUCCESS; +} + + +int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) +{ + spx_uint32_t i; + int istride_save, ostride_save; + spx_uint32_t bak_len = *out_len; + istride_save = st->in_stride; + ostride_save = st->out_stride; + st->in_stride = st->out_stride = st->nb_channels; + for (i=0;inb_channels;i++) + { + *out_len = bak_len; + speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len); + } + st->in_stride = istride_save; + st->out_stride = ostride_save; + return RESAMPLER_ERR_SUCCESS; +} + +int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate) +{ + return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate); +} + +void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate) +{ + *in_rate = st->in_rate; + *out_rate = st->out_rate; +} + +int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate) +{ + spx_uint32_t fact; + spx_uint32_t old_den; + spx_uint32_t i; + if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den) + return RESAMPLER_ERR_SUCCESS; + + old_den = st->den_rate; + st->in_rate = in_rate; + st->out_rate = out_rate; + st->num_rate = ratio_num; + st->den_rate = ratio_den; + /* FIXME: This is terribly inefficient, but who cares (at least for now)? */ + for (fact=2;fact<=IMIN(st->num_rate, st->den_rate);fact++) + { + while ((st->num_rate % fact == 0) && (st->den_rate % fact == 0)) + { + st->num_rate /= fact; + st->den_rate /= fact; + } + } + + if (old_den > 0) + { + for (i=0;inb_channels;i++) + { + st->samp_frac_num[i]=st->samp_frac_num[i]*st->den_rate/old_den; + /* Safety net */ + if (st->samp_frac_num[i] >= st->den_rate) + st->samp_frac_num[i] = st->den_rate-1; + } + } + + if (st->initialised) + update_filter(st); + return RESAMPLER_ERR_SUCCESS; +} + +void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den) +{ + *ratio_num = st->num_rate; + *ratio_den = st->den_rate; +} + +int speex_resampler_set_quality(SpeexResamplerState *st, int quality) +{ + if (quality > 10 || quality < 0) + return RESAMPLER_ERR_INVALID_ARG; + if (st->quality == quality) + return RESAMPLER_ERR_SUCCESS; + st->quality = quality; + if (st->initialised) + update_filter(st); + return RESAMPLER_ERR_SUCCESS; +} + +void speex_resampler_get_quality(SpeexResamplerState *st, int *quality) +{ + *quality = st->quality; +} + +void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride) +{ + st->in_stride = stride; +} + +void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride) +{ + *stride = st->in_stride; +} + +void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride) +{ + st->out_stride = stride; +} + +void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride) +{ + *stride = st->out_stride; +} + +int speex_resampler_skip_zeros(SpeexResamplerState *st) +{ + spx_uint32_t i; + for (i=0;inb_channels;i++) + st->last_sample[i] = st->filt_len/2; + return RESAMPLER_ERR_SUCCESS; +} + +int speex_resampler_reset_mem(SpeexResamplerState *st) +{ + spx_uint32_t i; + for (i=0;inb_channels*(st->filt_len-1);i++) + st->mem[i] = 0; + return RESAMPLER_ERR_SUCCESS; +} + +const char *speex_resampler_strerror(int err) +{ + switch (err) + { + case RESAMPLER_ERR_SUCCESS: + return "Success."; + case RESAMPLER_ERR_ALLOC_FAILED: + return "Memory allocation failed."; + case RESAMPLER_ERR_BAD_STATE: + return "Bad resampler state."; + case RESAMPLER_ERR_INVALID_ARG: + return "Invalid argument."; + case RESAMPLER_ERR_PTR_OVERLAP: + return "Input and output buffers overlap."; + default: + return "Unknown error. Bad error code or strange version mismatch."; + } +} diff --git a/src/pulsecore/speex/speex_resampler.h b/src/pulsecore/speex/speex_resampler.h new file mode 100644 index 00000000..8629eeb3 --- /dev/null +++ b/src/pulsecore/speex/speex_resampler.h @@ -0,0 +1,328 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: speex_resampler.h + Resampling code + + The design goals of this code are: + - Very fast algorithm + - Low memory requirement + - Good *perceptual* quality (and not best SNR) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef SPEEX_RESAMPLER_H +#define SPEEX_RESAMPLER_H + +#ifdef OUTSIDE_SPEEX + +/********* WARNING: MENTAL SANITY ENDS HERE *************/ + +/* If the resampler is defined outside of Speex, we change the symbol names so that + there won't be any clash if linking with Speex later on. */ + +/* #define RANDOM_PREFIX your software name here */ +#ifndef RANDOM_PREFIX +#error "Please define RANDOM_PREFIX (above) to something specific to your project to prevent symbol name clashes" +#endif + +#define CAT_PREFIX2(a,b) a ## b +#define CAT_PREFIX(a,b) CAT_PREFIX2(a, b) + +#define speex_resampler_init CAT_PREFIX(RANDOM_PREFIX,_resampler_init) +#define speex_resampler_init_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_init_frac) +#define speex_resampler_destroy CAT_PREFIX(RANDOM_PREFIX,_resampler_destroy) +#define speex_resampler_process_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_float) +#define speex_resampler_process_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_int) +#define speex_resampler_process_interleaved_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_float) +#define speex_resampler_process_interleaved_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_int) +#define speex_resampler_set_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate) +#define speex_resampler_get_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_get_rate) +#define speex_resampler_set_rate_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate_frac) +#define speex_resampler_get_ratio CAT_PREFIX(RANDOM_PREFIX,_resampler_get_ratio) +#define speex_resampler_set_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_set_quality) +#define speex_resampler_get_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_get_quality) +#define speex_resampler_set_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_input_stride) +#define speex_resampler_get_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_stride) +#define speex_resampler_set_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_output_stride) +#define speex_resampler_get_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_stride) +#define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros) +#define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem) +#define speex_resampler_strerror CAT_PREFIX(RANDOM_PREFIX,_resampler_strerror) + +#define spx_int16_t short +#define spx_int32_t int +#define spx_uint16_t unsigned short +#define spx_uint32_t unsigned int + +#else /* OUTSIDE_SPEEX */ + +#include "speex/speex_types.h" + +#endif /* OUTSIDE_SPEEX */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define SPEEX_RESAMPLER_QUALITY_MAX 10 +#define SPEEX_RESAMPLER_QUALITY_MIN 0 +#define SPEEX_RESAMPLER_QUALITY_DEFAULT 4 +#define SPEEX_RESAMPLER_QUALITY_VOIP 3 +#define SPEEX_RESAMPLER_QUALITY_DESKTOP 5 + +enum { + RESAMPLER_ERR_SUCCESS = 0, + RESAMPLER_ERR_ALLOC_FAILED = 1, + RESAMPLER_ERR_BAD_STATE = 2, + RESAMPLER_ERR_INVALID_ARG = 3, + RESAMPLER_ERR_PTR_OVERLAP = 4, + + RESAMPLER_ERR_MAX_ERROR +}; + +struct SpeexResamplerState_; +typedef struct SpeexResamplerState_ SpeexResamplerState; + +/** Create a new resampler with integer input and output rates. + * @param nb_channels Number of channels to be processed + * @param in_rate Input sampling rate (integer number of Hz). + * @param out_rate Output sampling rate (integer number of Hz). + * @param quality Resampling quality between 0 and 10, where 0 has poor quality + * and 10 has very high quality. + * @return Newly created resampler state + * @retval NULL Error: not enough memory + */ +SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, + spx_uint32_t in_rate, + spx_uint32_t out_rate, + int quality, + int *err); + +/** Create a new resampler with fractional input/output rates. The sampling + * rate ratio is an arbitrary rational number with both the numerator and + * denominator being 32-bit integers. + * @param nb_channels Number of channels to be processed + * @param ratio_num Numerator of the sampling rate ratio + * @param ratio_den Denominator of the sampling rate ratio + * @param in_rate Input sampling rate rounded to the nearest integer (in Hz). + * @param out_rate Output sampling rate rounded to the nearest integer (in Hz). + * @param quality Resampling quality between 0 and 10, where 0 has poor quality + * and 10 has very high quality. + * @return Newly created resampler state + * @retval NULL Error: not enough memory + */ +SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, + spx_uint32_t ratio_num, + spx_uint32_t ratio_den, + spx_uint32_t in_rate, + spx_uint32_t out_rate, + int quality, + int *err); + +/** Destroy a resampler state. + * @param st Resampler state + */ +void speex_resampler_destroy(SpeexResamplerState *st); + +/** Resample a float array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param channel_index Index of the channel to process for the multi-channel + * base (0 otherwise) + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the + * number of samples processed + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written + */ +int speex_resampler_process_float(SpeexResamplerState *st, + spx_uint32_t channel_index, + const float *in, + spx_uint32_t *in_len, + float *out, + spx_uint32_t *out_len); + +/** Resample an int array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param channel_index Index of the channel to process for the multi-channel + * base (0 otherwise) + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the number + * of samples processed + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written + */ +int speex_resampler_process_int(SpeexResamplerState *st, + spx_uint32_t channel_index, + const spx_int16_t *in, + spx_uint32_t *in_len, + spx_int16_t *out, + spx_uint32_t *out_len); + +/** Resample an interleaved float array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the number + * of samples processed. This is all per-channel. + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written. + * This is all per-channel. + */ +int speex_resampler_process_interleaved_float(SpeexResamplerState *st, + const float *in, + spx_uint32_t *in_len, + float *out, + spx_uint32_t *out_len); + +/** Resample an interleaved int array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the number + * of samples processed. This is all per-channel. + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written. + * This is all per-channel. + */ +int speex_resampler_process_interleaved_int(SpeexResamplerState *st, + const spx_int16_t *in, + spx_uint32_t *in_len, + spx_int16_t *out, + spx_uint32_t *out_len); + +/** Set (change) the input/output sampling rates (integer value). + * @param st Resampler state + * @param in_rate Input sampling rate (integer number of Hz). + * @param out_rate Output sampling rate (integer number of Hz). + */ +int speex_resampler_set_rate(SpeexResamplerState *st, + spx_uint32_t in_rate, + spx_uint32_t out_rate); + +/** Get the current input/output sampling rates (integer value). + * @param st Resampler state + * @param in_rate Input sampling rate (integer number of Hz) copied. + * @param out_rate Output sampling rate (integer number of Hz) copied. + */ +void speex_resampler_get_rate(SpeexResamplerState *st, + spx_uint32_t *in_rate, + spx_uint32_t *out_rate); + +/** Set (change) the input/output sampling rates and resampling ratio + * (fractional values in Hz supported). + * @param st Resampler state + * @param ratio_num Numerator of the sampling rate ratio + * @param ratio_den Denominator of the sampling rate ratio + * @param in_rate Input sampling rate rounded to the nearest integer (in Hz). + * @param out_rate Output sampling rate rounded to the nearest integer (in Hz). + */ +int speex_resampler_set_rate_frac(SpeexResamplerState *st, + spx_uint32_t ratio_num, + spx_uint32_t ratio_den, + spx_uint32_t in_rate, + spx_uint32_t out_rate); + +/** Get the current resampling ratio. This will be reduced to the least + * common denominator. + * @param st Resampler state + * @param ratio_num Numerator of the sampling rate ratio copied + * @param ratio_den Denominator of the sampling rate ratio copied + */ +void speex_resampler_get_ratio(SpeexResamplerState *st, + spx_uint32_t *ratio_num, + spx_uint32_t *ratio_den); + +/** Set (change) the conversion quality. + * @param st Resampler state + * @param quality Resampling quality between 0 and 10, where 0 has poor + * quality and 10 has very high quality. + */ +int speex_resampler_set_quality(SpeexResamplerState *st, + int quality); + +/** Get the conversion quality. + * @param st Resampler state + * @param quality Resampling quality between 0 and 10, where 0 has poor + * quality and 10 has very high quality. + */ +void speex_resampler_get_quality(SpeexResamplerState *st, + int *quality); + +/** Set (change) the input stride. + * @param st Resampler state + * @param stride Input stride + */ +void speex_resampler_set_input_stride(SpeexResamplerState *st, + spx_uint32_t stride); + +/** Get the input stride. + * @param st Resampler state + * @param stride Input stride copied + */ +void speex_resampler_get_input_stride(SpeexResamplerState *st, + spx_uint32_t *stride); + +/** Set (change) the output stride. + * @param st Resampler state + * @param stride Output stride + */ +void speex_resampler_set_output_stride(SpeexResamplerState *st, + spx_uint32_t stride); + +/** Get the output stride. + * @param st Resampler state copied + * @param stride Output stride + */ +void speex_resampler_get_output_stride(SpeexResamplerState *st, + spx_uint32_t *stride); + +/** Make sure that the first samples to go out of the resamplers don't have + * leading zeros. This is only useful before starting to use a newly created + * resampler. It is recommended to use that when resampling an audio file, as + * it will generate a file with the same length. For real-time processing, + * it is probably easier not to use this call (so that the output duration + * is the same for the first frame). + * @param st Resampler state + */ +int speex_resampler_skip_zeros(SpeexResamplerState *st); + +/** Reset a resampler so a new (unrelated) stream can be processed. + * @param st Resampler state + */ +int speex_resampler_reset_mem(SpeexResamplerState *st); + +/** Returns the English meaning for an error code + * @param err Error code + * @return English string + */ +const char *speex_resampler_strerror(int err); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/pulsecore/speexwrap.h b/src/pulsecore/speexwrap.h new file mode 100644 index 00000000..c0d5c0c0 --- /dev/null +++ b/src/pulsecore/speexwrap.h @@ -0,0 +1,48 @@ +#ifndef foopulsespeexwraphfoo +#define foopulsespeexwraphfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* We define a minimal version of speex_resampler.h however define one + * version for fixed and another one for float. Yes, somewhat ugly */ + +#define spx_int16_t short +#define spx_int32_t int +#define spx_uint16_t unsigned short +#define spx_uint32_t unsigned int + +typedef struct SpeexResamplerState_ SpeexResamplerState; + +SpeexResamplerState *paspfx_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err); +void paspfx_resampler_destroy(SpeexResamplerState *st); +int paspfx_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len); +int paspfx_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate); + +SpeexResamplerState *paspfl_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err); +void paspfl_resampler_destroy(SpeexResamplerState *st); +int paspfl_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len); +int paspfl_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate); + +#endif diff --git a/src/pulsecore/strbuf.c b/src/pulsecore/strbuf.c index a3ddc114..7c576c67 100644 --- a/src/pulsecore/strbuf.c +++ b/src/pulsecore/strbuf.c @@ -27,12 +27,12 @@ #include #include -#include #include #include #include #include +#include #include "strbuf.h" @@ -42,7 +42,7 @@ struct chunk { size_t length; }; -#define CHUNK_TO_TEXT(c) ((char*) (c) + sizeof(struct chunk)) +#define CHUNK_TO_TEXT(c) ((char*) (c) + PA_ALIGN(sizeof(struct chunk))) struct pa_strbuf { size_t length; @@ -50,14 +50,18 @@ struct pa_strbuf { }; pa_strbuf *pa_strbuf_new(void) { - pa_strbuf *sb = pa_xmalloc(sizeof(pa_strbuf)); + pa_strbuf *sb; + + sb = pa_xnew(pa_strbuf, 1); sb->length = 0; sb->head = sb->tail = NULL; + return sb; } void pa_strbuf_free(pa_strbuf *sb) { - assert(sb); + pa_assert(sb); + while (sb->head) { struct chunk *c = sb->head; sb->head = sb->head->next; @@ -72,12 +76,13 @@ void pa_strbuf_free(pa_strbuf *sb) { char *pa_strbuf_tostring(pa_strbuf *sb) { char *t, *e; struct chunk *c; - assert(sb); - e = t = pa_xmalloc(sb->length+1); + pa_assert(sb); + + e = t = pa_xnew(char, sb->length+1); for (c = sb->head; c; c = c->next) { - assert((size_t) (e-t) <= sb->length); + pa_assert((size_t) (e-t) <= sb->length); memcpy(e, CHUNK_TO_TEXT(c), c->length); e += c->length; } @@ -85,7 +90,7 @@ char *pa_strbuf_tostring(pa_strbuf *sb) { /* Trailing NUL */ *e = 0; - assert(e == t+sb->length); + pa_assert(e == t+sb->length); return t; } @@ -93,27 +98,33 @@ char *pa_strbuf_tostring(pa_strbuf *sb) { /* Combination of pa_strbuf_free() and pa_strbuf_tostring() */ char *pa_strbuf_tostring_free(pa_strbuf *sb) { char *t; - assert(sb); + + pa_assert(sb); t = pa_strbuf_tostring(sb); pa_strbuf_free(sb); + return t; } /* Append a string to the string buffer */ void pa_strbuf_puts(pa_strbuf *sb, const char *t) { - assert(sb && t); + + pa_assert(sb); + pa_assert(t); + pa_strbuf_putsn(sb, t, strlen(t)); } /* Append a new chunk to the linked list */ static void append(pa_strbuf *sb, struct chunk *c) { - assert(sb && c); + pa_assert(sb); + pa_assert(c); if (sb->tail) { - assert(sb->head); + pa_assert(sb->head); sb->tail->next = c; } else { - assert(!sb->head); + pa_assert(!sb->head); sb->head = c; } @@ -125,12 +136,14 @@ static void append(pa_strbuf *sb, struct chunk *c) { /* Append up to l bytes of a string to the string buffer */ void pa_strbuf_putsn(pa_strbuf *sb, const char *t, size_t l) { struct chunk *c; - assert(sb && t); + + pa_assert(sb); + pa_assert(t); if (!l) return; - c = pa_xmalloc(sizeof(struct chunk)+l); + c = pa_xmalloc(PA_ALIGN(sizeof(struct chunk)) + l); c->length = l; memcpy(CHUNK_TO_TEXT(c), t, l); @@ -143,16 +156,18 @@ int pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) { int size = 100; struct chunk *c = NULL; - assert(sb); + pa_assert(sb); + pa_assert(format); for(;;) { va_list ap; int r; - c = pa_xrealloc(c, sizeof(struct chunk)+size); + c = pa_xrealloc(c, PA_ALIGN(sizeof(struct chunk)) + size); va_start(ap, format); r = vsnprintf(CHUNK_TO_TEXT(c), size, format, ap); + CHUNK_TO_TEXT(c)[size-1] = 0; va_end(ap); if (r > -1 && r < size) { diff --git a/src/pulsecore/strlist.c b/src/pulsecore/strlist.c index 955b78e4..792af0ff 100644 --- a/src/pulsecore/strlist.c +++ b/src/pulsecore/strlist.c @@ -26,26 +26,31 @@ #endif #include -#include #include #include +#include #include #include "strlist.h" struct pa_strlist { pa_strlist *next; - char *str; }; +#define ITEM_TO_TEXT(c) ((char*) (c) + PA_ALIGN(sizeof(pa_strlist))) + pa_strlist* pa_strlist_prepend(pa_strlist *l, const char *s) { pa_strlist *n; - assert(s); - n = pa_xmalloc(sizeof(pa_strlist)); - n->str = pa_xstrdup(s); + size_t size; + + pa_assert(s); + size = strlen(s); + n = pa_xmalloc(PA_ALIGN(sizeof(pa_strlist)) + size + 1); + memcpy(ITEM_TO_TEXT(n), s, size + 1); n->next = l; + return n; } @@ -58,7 +63,7 @@ char *pa_strlist_tostring(pa_strlist *l) { if (!first) pa_strbuf_puts(b, " "); first = 0; - pa_strbuf_puts(b, l->str); + pa_strbuf_puts(b, ITEM_TO_TEXT(l)); } return pa_strbuf_tostring_free(b); @@ -66,19 +71,20 @@ char *pa_strlist_tostring(pa_strlist *l) { pa_strlist* pa_strlist_remove(pa_strlist *l, const char *s) { pa_strlist *ret = l, *prev = NULL; - assert(l && s); + + pa_assert(l); + pa_assert(s); while (l) { - if (!strcmp(l->str, s)) { + if (!strcmp(ITEM_TO_TEXT(l), s)) { pa_strlist *n = l->next; if (!prev) { - assert(ret == l); + pa_assert(ret == l); ret = n; } else prev->next = n; - pa_xfree(l->str); pa_xfree(l); l = n; @@ -96,22 +102,21 @@ void pa_strlist_free(pa_strlist *l) { while (l) { pa_strlist *c = l; l = l->next; - - pa_xfree(c->str); pa_xfree(c); } } pa_strlist* pa_strlist_pop(pa_strlist *l, char **s) { pa_strlist *r; - assert(s); + + pa_assert(s); if (!l) { *s = NULL; return NULL; } - *s = l->str; + *s = pa_xstrdup(ITEM_TO_TEXT(l)); r = l->next; pa_xfree(l); return r; @@ -124,10 +129,12 @@ pa_strlist* pa_strlist_parse(const char *s) { while ((r = pa_split_spaces(s, &state))) { pa_strlist *n; + size_t size = strlen(r); - n = pa_xmalloc(sizeof(pa_strlist)); - n->str = r; + n = pa_xmalloc(PA_ALIGN(sizeof(pa_strlist)) + size + 1); n->next = NULL; + memcpy(ITEM_TO_TEXT(n), r, size+1); + pa_xfree(r); if (p) p->next = n; diff --git a/src/pulsecore/tagstruct.c b/src/pulsecore/tagstruct.c index ac7ae1ab..556fe806 100644 --- a/src/pulsecore/tagstruct.c +++ b/src/pulsecore/tagstruct.c @@ -29,19 +29,18 @@ #include #include #include -#include #include #ifdef HAVE_NETINET_IN_H #include #endif -#include "winsock.h" - #include -#include "tagstruct.h" +#include +#include +#include "tagstruct.h" struct pa_tagstruct { uint8_t *data; @@ -54,18 +53,20 @@ struct pa_tagstruct { pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) { pa_tagstruct*t; - assert(!data || (data && length)); + pa_assert(!data || (data && length)); - t = pa_xmalloc(sizeof(pa_tagstruct)); + t = pa_xnew(pa_tagstruct, 1); t->data = (uint8_t*) data; t->allocated = t->length = data ? length : 0; t->rindex = 0; t->dynamic = !data; + return t; } void pa_tagstruct_free(pa_tagstruct*t) { - assert(t); + pa_assert(t); + if (t->dynamic) pa_xfree(t->data); pa_xfree(t); @@ -73,7 +74,11 @@ void pa_tagstruct_free(pa_tagstruct*t) { uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l) { uint8_t *p; - assert(t && t->dynamic && l); + + pa_assert(t); + pa_assert(t->dynamic); + pa_assert(l); + p = t->data; *l = t->length; pa_xfree(t); @@ -81,8 +86,8 @@ uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l) { } static void extend(pa_tagstruct*t, size_t l) { - assert(t); - assert(t->dynamic); + pa_assert(t); + pa_assert(t->dynamic); if (t->length+l <= t->allocated) return; @@ -92,7 +97,8 @@ static void extend(pa_tagstruct*t, size_t l) { void pa_tagstruct_puts(pa_tagstruct*t, const char *s) { size_t l; - assert(t); + pa_assert(t); + if (s) { l = strlen(s)+2; extend(t, l); @@ -107,7 +113,8 @@ void pa_tagstruct_puts(pa_tagstruct*t, const char *s) { } void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i) { - assert(t); + pa_assert(t); + extend(t, 5); t->data[t->length] = PA_TAG_U32; i = htonl(i); @@ -116,7 +123,8 @@ void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i) { } void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c) { - assert(t); + pa_assert(t); + extend(t, 2); t->data[t->length] = PA_TAG_U8; *(t->data+t->length+1) = c; @@ -125,7 +133,10 @@ void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c) { void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss) { uint32_t rate; - assert(t && ss); + + pa_assert(t); + pa_assert(ss); + extend(t, 7); t->data[t->length] = PA_TAG_SAMPLE_SPEC; t->data[t->length+1] = (uint8_t) ss->format; @@ -137,7 +148,9 @@ void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss) { void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) { uint32_t tmp; - assert(t && p); + + pa_assert(t); + pa_assert(p); extend(t, 5+length); t->data[t->length] = PA_TAG_ARBITRARY; @@ -149,7 +162,8 @@ void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) { } void pa_tagstruct_put_boolean(pa_tagstruct*t, int b) { - assert(t); + pa_assert(t); + extend(t, 1); t->data[t->length] = b ? PA_TAG_BOOLEAN_TRUE : PA_TAG_BOOLEAN_FALSE; t->length += 1; @@ -157,7 +171,8 @@ void pa_tagstruct_put_boolean(pa_tagstruct*t, int b) { void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv) { uint32_t tmp; - assert(t); + pa_assert(t); + extend(t, 9); t->data[t->length] = PA_TAG_TIMEVAL; tmp = htonl(tv->tv_sec); @@ -169,7 +184,9 @@ void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv) { void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u) { uint32_t tmp; - assert(t); + + pa_assert(t); + extend(t, 9); t->data[t->length] = PA_TAG_USEC; tmp = htonl((uint32_t) (u >> 32)); @@ -181,7 +198,9 @@ void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u) { void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) { uint32_t tmp; - assert(t); + + pa_assert(t); + extend(t, 9); t->data[t->length] = PA_TAG_U64; tmp = htonl((uint32_t) (u >> 32)); @@ -193,7 +212,9 @@ void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) { void pa_tagstruct_puts64(pa_tagstruct*t, int64_t u) { uint32_t tmp; - assert(t); + + pa_assert(t); + extend(t, 9); t->data[t->length] = PA_TAG_S64; tmp = htonl((uint32_t) ((uint64_t) u >> 32)); @@ -206,7 +227,7 @@ void pa_tagstruct_puts64(pa_tagstruct*t, int64_t u) { void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) { unsigned i; - assert(t); + pa_assert(t); extend(t, 2 + map->channels); t->data[t->length++] = PA_TAG_CHANNEL_MAP; @@ -220,7 +241,7 @@ void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) { unsigned i; pa_volume_t vol; - assert(t); + pa_assert(t); extend(t, 2 + cvolume->channels * sizeof(pa_volume_t)); t->data[t->length++] = PA_TAG_CVOLUME; @@ -237,7 +258,9 @@ int pa_tagstruct_gets(pa_tagstruct*t, const char **s) { int error = 0; size_t n; char *c; - assert(t && s); + + pa_assert(t); + pa_assert(s); if (t->rindex+1 > t->length) return -1; @@ -271,7 +294,8 @@ int pa_tagstruct_gets(pa_tagstruct*t, const char **s) { } int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) { - assert(t && i); + pa_assert(t); + pa_assert(i); if (t->rindex+5 > t->length) return -1; @@ -286,7 +310,8 @@ int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) { } int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) { - assert(t && c); + pa_assert(t); + pa_assert(c); if (t->rindex+2 > t->length) return -1; @@ -300,7 +325,8 @@ int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) { } int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) { - assert(t && ss); + pa_assert(t); + pa_assert(ss); if (t->rindex+7 > t->length) return -1; @@ -319,7 +345,9 @@ int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) { int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) { uint32_t len; - assert(t && p); + + pa_assert(t); + pa_assert(p); if (t->rindex+5+length > t->length) return -1; @@ -337,18 +365,23 @@ int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) { } int pa_tagstruct_eof(pa_tagstruct*t) { - assert(t); + pa_assert(t); + return t->rindex >= t->length; } const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) { - assert(t && t->dynamic && l); + pa_assert(t); + pa_assert(t->dynamic); + pa_assert(l); + *l = t->length; return t->data; } int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) { - assert(t && b); + pa_assert(t); + pa_assert(b); if (t->rindex+1 > t->length) return -1; @@ -366,6 +399,9 @@ int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) { int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) { + pa_assert(t); + pa_assert(tv); + if (t->rindex+9 > t->length) return -1; @@ -382,7 +418,9 @@ int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) { int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) { uint32_t tmp; - assert(t && u); + + pa_assert(t); + pa_assert(u); if (t->rindex+9 > t->length) return -1; @@ -400,7 +438,9 @@ int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) { int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) { uint32_t tmp; - assert(t && u); + + pa_assert(t); + pa_assert(u); if (t->rindex+9 > t->length) return -1; @@ -418,7 +458,9 @@ int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) { int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *u) { uint32_t tmp; - assert(t && u); + + pa_assert(t); + pa_assert(u); if (t->rindex+9 > t->length) return -1; @@ -437,8 +479,8 @@ int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *u) { int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) { unsigned i; - assert(t); - assert(map); + pa_assert(t); + pa_assert(map); if (t->rindex+2 > t->length) return -1; @@ -463,8 +505,8 @@ int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) { unsigned i; pa_volume_t vol; - assert(t); - assert(cvolume); + pa_assert(t); + pa_assert(cvolume); if (t->rindex+2 > t->length) return -1; @@ -489,7 +531,7 @@ int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) { void pa_tagstruct_put(pa_tagstruct *t, ...) { va_list va; - assert(t); + pa_assert(t); va_start(va, t); @@ -550,7 +592,7 @@ void pa_tagstruct_put(pa_tagstruct *t, ...) { break; default: - abort(); + pa_assert_not_reached(); } } @@ -561,7 +603,7 @@ int pa_tagstruct_get(pa_tagstruct *t, ...) { va_list va; int ret = 0; - assert(t); + pa_assert(t); va_start(va, t); while (ret == 0) { @@ -620,9 +662,8 @@ int pa_tagstruct_get(pa_tagstruct *t, ...) { ret = pa_tagstruct_get_cvolume(t, va_arg(va, pa_cvolume *)); break; - default: - abort(); + pa_assert_not_reached(); } } diff --git a/src/pulsecore/thread-mq.c b/src/pulsecore/thread-mq.c new file mode 100644 index 00000000..9b879425 --- /dev/null +++ b/src/pulsecore/thread-mq.c @@ -0,0 +1,112 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "thread-mq.h" + +PA_STATIC_TLS_DECLARE_NO_FREE(thread_mq); + +static void asyncmsgq_cb(pa_mainloop_api*api, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) { + pa_thread_mq *q = userdata; + pa_asyncmsgq *aq; + + pa_assert(pa_asyncmsgq_get_fd(q->outq) == fd); + pa_assert(events == PA_IO_EVENT_INPUT); + + pa_asyncmsgq_ref(aq = q->outq); + pa_asyncmsgq_after_poll(aq); + + for (;;) { + pa_msgobject *object; + int code; + void *data; + int64_t offset; + pa_memchunk chunk; + + /* Check whether there is a message for us to process */ + while (pa_asyncmsgq_get(aq, &object, &code, &data, &offset, &chunk, 0) == 0) { + int ret; + + ret = pa_asyncmsgq_dispatch(object, code, data, offset, &chunk); + pa_asyncmsgq_done(aq, ret); + } + + if (pa_asyncmsgq_before_poll(aq) == 0) + break; + } + + pa_asyncmsgq_unref(aq); +} + +void pa_thread_mq_init(pa_thread_mq *q, pa_mainloop_api *mainloop) { + pa_assert(q); + pa_assert(mainloop); + + q->mainloop = mainloop; + pa_assert_se(q->inq = pa_asyncmsgq_new(0)); + pa_assert_se(q->outq = pa_asyncmsgq_new(0)); + + pa_assert_se(pa_asyncmsgq_before_poll(q->outq) == 0); + pa_assert_se(q->io_event = mainloop->io_new(mainloop, pa_asyncmsgq_get_fd(q->outq), PA_IO_EVENT_INPUT, asyncmsgq_cb, q)); +} + +void pa_thread_mq_done(pa_thread_mq *q) { + pa_assert(q); + + q->mainloop->io_free(q->io_event); + q->io_event = NULL; + + pa_asyncmsgq_unref(q->inq); + pa_asyncmsgq_unref(q->outq); + q->inq = q->outq = NULL; + + q->mainloop = NULL; +} + +void pa_thread_mq_install(pa_thread_mq *q) { + pa_assert(q); + + pa_assert(!(PA_STATIC_TLS_GET(thread_mq))); + PA_STATIC_TLS_SET(thread_mq, q); +} + +pa_thread_mq *pa_thread_mq_get(void) { + return PA_STATIC_TLS_GET(thread_mq); +} diff --git a/src/pulsecore/thread-mq.h b/src/pulsecore/thread-mq.h new file mode 100644 index 00000000..13b6e01f --- /dev/null +++ b/src/pulsecore/thread-mq.h @@ -0,0 +1,49 @@ +#ifndef foopulsethreadmqhfoo +#define foopulsethreadmqhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +/* Two way communication between a thread and a mainloop. Before the + * thread is started a pa_pthread_mq should be initialized and than + * attached to the thread using pa_thread_mq_install(). */ + +typedef struct pa_thread_mq { + pa_mainloop_api *mainloop; + pa_asyncmsgq *inq, *outq; + pa_io_event *io_event; +} pa_thread_mq; + +void pa_thread_mq_init(pa_thread_mq *q, pa_mainloop_api *mainloop); +void pa_thread_mq_done(pa_thread_mq *q); + +/* Install the specified pa_thread_mq object for the current thread */ +void pa_thread_mq_install(pa_thread_mq *q); + +/* Return the pa_thread_mq object that is set for the current thread */ +pa_thread_mq *pa_thread_mq_get(void); + +#endif diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c index 4271fa42..7f43f43e 100644 --- a/src/pulsecore/thread-posix.c +++ b/src/pulsecore/thread-posix.c @@ -26,7 +26,6 @@ #include #endif -#include #include #include #include @@ -35,56 +34,44 @@ #include #include #include +#include #include "thread.h" -#define ASSERT_SUCCESS(x) do { \ - int _r = (x); \ - assert(_r == 0); \ -} while(0) - struct pa_thread { pthread_t id; pa_thread_func_t thread_func; void *userdata; - pa_atomic_int_t running; + pa_atomic_t running; }; struct pa_tls { pthread_key_t key; }; -static pa_tls *thread_tls; -static pa_once_t thread_tls_once = PA_ONCE_INIT; - -static void tls_free_cb(void *p) { +static void thread_free_cb(void *p) { pa_thread *t = p; - assert(t); + pa_assert(t); if (!t->thread_func) /* This is a foreign thread, we need to free the struct */ pa_xfree(t); } -static void thread_tls_once_func(void) { - thread_tls = pa_tls_new(tls_free_cb); - assert(thread_tls); -} +PA_STATIC_TLS_DECLARE(current_thread, thread_free_cb); static void* internal_thread_func(void *userdata) { pa_thread *t = userdata; - assert(t); + pa_assert(t); t->id = pthread_self(); - pa_once(&thread_tls_once, thread_tls_once_func); - - pa_tls_set(thread_tls, t); + PA_STATIC_TLS_SET(current_thread, t); pa_atomic_inc(&t->running); t->thread_func(t->userdata); - pa_atomic_add(&t->running, -2); + pa_atomic_sub(&t->running, 2); return NULL; } @@ -92,7 +79,7 @@ static void* internal_thread_func(void *userdata) { pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) { pa_thread *t; - assert(thread_func); + pa_assert(thread_func); t = pa_xnew(pa_thread, 1); t->thread_func = thread_func; @@ -110,26 +97,26 @@ pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) { } int pa_thread_is_running(pa_thread *t) { - assert(t); + pa_assert(t); /* Unfortunately there is no way to tell whether a "foreign" * thread is still running. See * http://udrepper.livejournal.com/16844.html for more * information */ - assert(t->thread_func); + pa_assert(t->thread_func); return pa_atomic_load(&t->running) > 0; } void pa_thread_free(pa_thread *t) { - assert(t); + pa_assert(t); pa_thread_join(t); pa_xfree(t); } int pa_thread_join(pa_thread *t) { - assert(t); + pa_assert(t); return pthread_join(t->id, NULL); } @@ -137,9 +124,7 @@ int pa_thread_join(pa_thread *t) { pa_thread* pa_thread_self(void) { pa_thread *t; - pa_once(&thread_tls_once, thread_tls_once_func); - - if ((t = pa_tls_get(thread_tls))) + if ((t = PA_STATIC_TLS_GET(current_thread))) return t; /* This is a foreign thread, let's create a pthread structure to @@ -151,19 +136,19 @@ pa_thread* pa_thread_self(void) { t->userdata = NULL; pa_atomic_store(&t->running, 2); - pa_tls_set(thread_tls, t); + PA_STATIC_TLS_SET(current_thread, t); return t; } void* pa_thread_get_data(pa_thread *t) { - assert(t); + pa_assert(t); return t->userdata; } void pa_thread_set_data(pa_thread *t, void *userdata) { - assert(t); + pa_assert(t); t->userdata = userdata; } @@ -172,7 +157,7 @@ void pa_thread_yield(void) { #ifdef HAVE_PTHREAD_YIELD pthread_yield(); #else - ASSERT_SUCCESS(sched_yield()); + pa_assert_se(sched_yield() == 0); #endif } @@ -190,14 +175,14 @@ pa_tls* pa_tls_new(pa_free_cb_t free_cb) { } void pa_tls_free(pa_tls *t) { - assert(t); + pa_assert(t); - ASSERT_SUCCESS(pthread_key_delete(t->key)); + pa_assert_se(pthread_key_delete(t->key) == 0); pa_xfree(t); } void *pa_tls_get(pa_tls *t) { - assert(t); + pa_assert(t); return pthread_getspecific(t->key); } @@ -206,7 +191,7 @@ void *pa_tls_set(pa_tls *t, void *userdata) { void *r; r = pthread_getspecific(t->key); - ASSERT_SUCCESS(pthread_setspecific(t->key, userdata)); + pa_assert_se(pthread_setspecific(t->key, userdata) == 0); return r; } diff --git a/src/pulsecore/thread-win32.c b/src/pulsecore/thread-win32.c index 46d273b4..cad1420a 100644 --- a/src/pulsecore/thread-win32.c +++ b/src/pulsecore/thread-win32.c @@ -53,9 +53,8 @@ struct pa_tls_monitor { }; static pa_tls *thread_tls; -static pa_once_t thread_tls_once = PA_ONCE_INIT; +static pa_once thread_tls_once = PA_ONCE_INIT; static pa_tls *monitor_tls; -static pa_once_t monitor_tls_once = PA_ONCE_INIT; static void thread_tls_once_func(void) { thread_tls = pa_tls_new(NULL); @@ -66,7 +65,7 @@ static DWORD WINAPI internal_thread_func(LPVOID param) { pa_thread *t = param; assert(t); - pa_once(&thread_tls_once, thread_tls_once_func); + pa_run_once(&thread_tls_once, thread_tls_once_func); pa_tls_set(thread_tls, t); t->thread_func(t->userdata); @@ -122,7 +121,7 @@ int pa_thread_join(pa_thread *t) { } pa_thread* pa_thread_self(void) { - pa_once(&thread_tls_once, thread_tls_once_func); + pa_run_once(&thread_tls_once, thread_tls_once_func); return pa_tls_get(thread_tls); } @@ -130,12 +129,6 @@ void pa_thread_yield(void) { Sleep(0); } -static void monitor_tls_once_func(void) { - monitor_tls = pa_tls_new(NULL); - assert(monitor_tls); - pa_tls_set(monitor_tls, NULL); -} - static DWORD WINAPI monitor_thread_func(LPVOID param) { struct pa_tls_monitor *m = param; assert(m); @@ -191,7 +184,11 @@ void *pa_tls_set(pa_tls *t, void *userdata) { if (t->free_func) { struct pa_tls_monitor *m; - pa_once(&monitor_tls_once, monitor_tls_once_func); + PA_ONCE_BEGIN { + monitor_tls = pa_tls_new(NULL); + assert(monitor_tls); + pa_tls_set(monitor_tls, NULL); + } PA_ONCE_END; m = pa_tls_get(monitor_tls); if (!m) { diff --git a/src/pulsecore/thread.h b/src/pulsecore/thread.h index ca1fe4da..54ef320e 100644 --- a/src/pulsecore/thread.h +++ b/src/pulsecore/thread.h @@ -26,6 +26,11 @@ ***/ #include +#include + +#ifndef PACKAGE +#error "Please include config.h before including this file!" +#endif typedef struct pa_thread pa_thread; @@ -48,4 +53,60 @@ void pa_tls_free(pa_tls *t); void * pa_tls_get(pa_tls *t); void *pa_tls_set(pa_tls *t, void *userdata); +#define PA_STATIC_TLS_DECLARE(name, free_cb) \ + static struct { \ + pa_once once; \ + pa_tls *tls; \ + } name##_tls = { \ + .once = PA_ONCE_INIT, \ + .tls = NULL \ + }; \ + static void name##_tls_init(void) { \ + name##_tls.tls = pa_tls_new(free_cb); \ + } \ + static inline pa_tls* name##_tls_obj(void) { \ + pa_run_once(&name##_tls.once, name##_tls_init); \ + return name##_tls.tls; \ + } \ + static void name##_tls_destructor(void) PA_GCC_DESTRUCTOR; \ + static void name##_tls_destructor(void) { \ + static void (*_free_cb)(void*) = free_cb; \ + if (!name##_tls.tls) \ + return; \ + if (_free_cb) { \ + void *p; \ + if ((p = pa_tls_get(name##_tls.tls))) \ + _free_cb(p); \ + } \ + pa_tls_free(name##_tls.tls); \ + } \ + static inline void* name##_tls_get(void) { \ + return pa_tls_get(name##_tls_obj()); \ + } \ + static inline void* name##_tls_set(void *p) { \ + return pa_tls_set(name##_tls_obj(), p); \ + } \ + struct __stupid_useless_struct_to_allow_trailing_semicolon + +#ifdef HAVE_TLS_BUILTIN +/* An optimized version of the above that requires no dynamic + * allocation if the compiler supports __thread */ +#define PA_STATIC_TLS_DECLARE_NO_FREE(name) \ + static __thread void *name##_tls = NULL; \ + static inline void* name##_tls_get(void) { \ + return name##_tls; \ + } \ + static inline void* name##_tls_set(void *p) { \ + void *r = name##_tls; \ + name##_tls = p; \ + return r; \ + } \ + struct __stupid_useless_struct_to_allow_trailing_semicolon +#else +#define PA_STATIC_TLS_DECLARE_NO_FREE(name) PA_STATIC_TLS_DECLARE(name, NULL) +#endif + +#define PA_STATIC_TLS_GET(name) (name##_tls_get()) +#define PA_STATIC_TLS_SET(name, p) (name##_tls_set(p)) + #endif diff --git a/src/pulsecore/time-smoother.c b/src/pulsecore/time-smoother.c new file mode 100644 index 00000000..6bda3df0 --- /dev/null +++ b/src/pulsecore/time-smoother.c @@ -0,0 +1,378 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2007 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include + +#include "time-smoother.h" + +#define HISTORY_MAX 50 + +/* + * Implementation of a time smoothing algorithm to synchronize remote + * clocks to a local one. Evens out noise, adjusts to clock skew and + * allows cheap estimations of the remote time while clock updates may + * be seldom and recieved in non-equidistant intervals. + * + * Basically, we estimate the gradient of received clock samples in a + * certain history window (of size 'history_time') with linear + * regression. With that info we estimate the remote time in + * 'adjust_time' ahead and smoothen our current estimation function + * towards that point with a 3rd order polynomial interpolation with + * fitting derivatives. (more or less a b-spline) + * + * The larger 'history_time' is chosen the better we will surpress + * noise -- but we'll adjust to clock skew slower.. + * + * The larger 'adjust_time' is chosen the smoother our estimation + * function will be -- but we'll adjust to clock skew slower, too. + * + * If 'monotonic' is TRUE the resulting estimation function is + * guaranteed to be monotonic. + */ + +struct pa_smoother { + pa_usec_t adjust_time, history_time; + pa_bool_t monotonic; + + pa_usec_t time_offset; + + pa_usec_t px, py; /* Point p, where we want to reach stability */ + double dp; /* Gradient we want at point p */ + + pa_usec_t ex, ey; /* Point e, which we estimated before and need to smooth to */ + double de; /* Gradient we estimated for point e */ + + /* History of last measurements */ + pa_usec_t history_x[HISTORY_MAX], history_y[HISTORY_MAX]; + unsigned history_idx, n_history; + + /* To even out for monotonicity */ + pa_usec_t last_y; + + /* Cached parameters for our interpolation polynomial y=ax^3+b^2+cx */ + double a, b, c; + pa_bool_t abc_valid; + + pa_bool_t paused; + pa_usec_t pause_time; +}; + +pa_smoother* pa_smoother_new(pa_usec_t adjust_time, pa_usec_t history_time, pa_bool_t monotonic) { + pa_smoother *s; + + pa_assert(adjust_time > 0); + pa_assert(history_time > 0); + + s = pa_xnew(pa_smoother, 1); + s->adjust_time = adjust_time; + s->history_time = history_time; + s->time_offset = 0; + s->monotonic = monotonic; + + s->px = s->py = 0; + s->dp = 1; + + s->ex = s->ey = 0; + s->de = 1; + + s->history_idx = 0; + s->n_history = 0; + + s->last_y = 0; + + s->abc_valid = FALSE; + + s->paused = FALSE; + + return s; +} + +void pa_smoother_free(pa_smoother* s) { + pa_assert(s); + + pa_xfree(s); +} + +static void drop_old(pa_smoother *s, pa_usec_t x) { + unsigned j; + + /* First drop items from history which are too old, but make sure + * to always keep two entries in the history */ + + for (j = s->n_history; j > 2; j--) { + + if (s->history_x[s->history_idx] + s->history_time >= x) { + /* This item is still valid, and thus all following ones + * are too, so let's quit this loop */ + break; + } + + /* Item is too old, let's drop it */ + s->history_idx ++; + while (s->history_idx >= HISTORY_MAX) + s->history_idx -= HISTORY_MAX; + + s->n_history --; + } +} + +static void add_to_history(pa_smoother *s, pa_usec_t x, pa_usec_t y) { + unsigned j; + pa_assert(s); + + drop_old(s, x); + + /* Calculate position for new entry */ + j = s->history_idx + s->n_history; + while (j >= HISTORY_MAX) + j -= HISTORY_MAX; + + /* Fill in entry */ + s->history_x[j] = x; + s->history_y[j] = y; + + /* Adjust counter */ + s->n_history ++; + + /* And make sure we don't store more entries than fit in */ + if (s->n_history >= HISTORY_MAX) { + s->history_idx += s->n_history - HISTORY_MAX; + s->n_history = HISTORY_MAX; + } +} + +static double avg_gradient(pa_smoother *s, pa_usec_t x) { + unsigned i, j, c = 0; + int64_t ax = 0, ay = 0, k, t; + double r; + + drop_old(s, x); + + /* First, calculate average of all measurements */ + i = s->history_idx; + for (j = s->n_history; j > 0; j--) { + + ax += s->history_x[i]; + ay += s->history_y[i]; + c++; + + i++; + while (i >= HISTORY_MAX) + i -= HISTORY_MAX; + } + + /* Too few measurements, assume gradient of 1 */ + if (c < 2) + return 1; + + ax /= c; + ay /= c; + + /* Now, do linear regression */ + k = t = 0; + + i = s->history_idx; + for (j = s->n_history; j > 0; j--) { + int64_t dx, dy; + + dx = (int64_t) s->history_x[i] - ax; + dy = (int64_t) s->history_y[i] - ay; + + k += dx*dy; + t += dx*dx; + + i++; + while (i >= HISTORY_MAX) + i -= HISTORY_MAX; + } + + r = (double) k / t; + + return s->monotonic && r < 0 ? 0 : r; +} + +static void estimate(pa_smoother *s, pa_usec_t x, pa_usec_t *y, double *deriv) { + pa_assert(s); + pa_assert(y); + + if (x >= s->px) { + int64_t t; + + /* The requested point is right of the point where we wanted + * to be on track again, thus just linearly estimate */ + + t = (int64_t) s->py + (int64_t) (s->dp * (x - s->px)); + + if (t < 0) + t = 0; + + *y = (pa_usec_t) t; + + if (deriv) + *deriv = s->dp; + + } else { + + if (!s->abc_valid) { + pa_usec_t ex, ey, px, py; + int64_t kx, ky; + double de, dp; + + /* Ok, we're not yet on track, thus let's interpolate, and + * make sure that the first derivative is smooth */ + + /* We have two points: (ex|ey) and (px|py) with two gradients + * at these points de and dp. We do a polynomial interpolation + * of degree 3 with these 6 values */ + + ex = s->ex; ey = s->ey; + px = s->px; py = s->py; + de = s->de; dp = s->dp; + + pa_assert(ex < px); + + /* To increase the dynamic range and symplify calculation, we + * move these values to the origin */ + kx = (int64_t) px - (int64_t) ex; + ky = (int64_t) py - (int64_t) ey; + + /* Calculate a, b, c for y=ax^3+b^2+cx */ + s->c = de; + s->b = (((double) (3*ky)/kx - dp - 2*de)) / kx; + s->a = (dp/kx - 2*s->b - de/kx) / (3*kx); + + s->abc_valid = TRUE; + } + + /* Move to origin */ + x -= s->ex; + + /* Horner scheme */ + *y = (pa_usec_t) ((double) x * (s->c + (double) x * (s->b + (double) x * s->a))); + + /* Move back from origin */ + *y += s->ey; + + /* Horner scheme */ + if (deriv) + *deriv = s->c + ((double) x * (s->b*2 + (double) x * s->a*3)); + } + + /* Guarantee monotonicity */ + if (s->monotonic) { + + if (*y < s->last_y) + *y = s->last_y; + else + s->last_y = *y; + + if (deriv && *deriv < 0) + *deriv = 0; + } +} + +void pa_smoother_put(pa_smoother *s, pa_usec_t x, pa_usec_t y) { + pa_usec_t ney; + double nde; + + pa_assert(s); + pa_assert(x >= s->time_offset); + + /* Fix up x value */ + if (s->paused) + x = s->pause_time; + else + x -= s->time_offset; + + pa_assert(x >= s->ex); + + /* First, we calculate the position we'd estimate for x, so that + * we can adjust our position smoothly from this one */ + estimate(s, x, &ney, &nde); + s->ex = x; s->ey = ney; s->de = nde; + + /* Then, we add the new measurement to our history */ + add_to_history(s, x, y); + + /* And determine the average gradient of the history */ + s->dp = avg_gradient(s, x); + + /* And calculate when we want to be on track again */ + s->px = x + s->adjust_time; + s->py = y + s->dp *s->adjust_time; + + s->abc_valid = FALSE; +} + +pa_usec_t pa_smoother_get(pa_smoother *s, pa_usec_t x) { + pa_usec_t y; + + pa_assert(s); + pa_assert(x >= s->time_offset); + + /* Fix up x value */ + if (s->paused) + x = s->pause_time; + else + x -= s->time_offset; + + pa_assert(x >= s->ex); + + estimate(s, x, &y, NULL); + return y; +} + +void pa_smoother_set_time_offset(pa_smoother *s, pa_usec_t offset) { + pa_assert(s); + + s->time_offset = offset; +} + +void pa_smoother_pause(pa_smoother *s, pa_usec_t x) { + pa_assert(s); + + if (s->paused) + return; + + s->paused = TRUE; + s->pause_time = x; +} + +void pa_smoother_resume(pa_smoother *s, pa_usec_t x) { + pa_assert(s); + + if (!s->paused) + return; + + s->paused = FALSE; + s->time_offset += x - s->pause_time; +} diff --git a/src/pulsecore/time-smoother.h b/src/pulsecore/time-smoother.h new file mode 100644 index 00000000..8b8512e2 --- /dev/null +++ b/src/pulsecore/time-smoother.h @@ -0,0 +1,43 @@ +#ifndef foopulsetimesmootherhfoo +#define foopulsetimesmootherhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2007 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +typedef struct pa_smoother pa_smoother; + +pa_smoother* pa_smoother_new(pa_usec_t adjust_time, pa_usec_t history_time, pa_bool_t monotonic); +void pa_smoother_free(pa_smoother* s); + +void pa_smoother_put(pa_smoother *s, pa_usec_t x, pa_usec_t y); +pa_usec_t pa_smoother_get(pa_smoother *s, pa_usec_t x); + +void pa_smoother_set_time_offset(pa_smoother *s, pa_usec_t offset); + +void pa_smoother_pause(pa_smoother *s, pa_usec_t x); +void pa_smoother_resume(pa_smoother *s, pa_usec_t x); + +#endif diff --git a/src/pulsecore/tokenizer.c b/src/pulsecore/tokenizer.c index 117c7f88..f79c19c5 100644 --- a/src/pulsecore/tokenizer.c +++ b/src/pulsecore/tokenizer.c @@ -26,20 +26,16 @@ #endif #include -#include #include #include #include #include +#include #include "tokenizer.h" -struct pa_tokenizer { - pa_dynarray *dynarray; -}; - static void token_free(void *p, PA_GCC_UNUSED void *userdata) { pa_xfree(p); } @@ -48,7 +44,9 @@ static void parse(pa_dynarray*a, const char *s, unsigned args) { int infty = 0; const char delimiter[] = " \t\n\r"; const char *p; - assert(a && s); + + pa_assert(a); + pa_assert(s); if (args == 0) infty = 1; @@ -70,23 +68,23 @@ static void parse(pa_dynarray*a, const char *s, unsigned args) { } pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args) { - pa_tokenizer *t; - - t = pa_xmalloc(sizeof(pa_tokenizer)); - t->dynarray = pa_dynarray_new(); - assert(t->dynarray); + pa_dynarray *a; - parse(t->dynarray, s, args); - return t; + a = pa_dynarray_new(); + parse(a, s, args); + return (pa_tokenizer*) a; } void pa_tokenizer_free(pa_tokenizer *t) { - assert(t); - pa_dynarray_free(t->dynarray, token_free, NULL); - pa_xfree(t); + pa_dynarray *a = (pa_dynarray*) t; + + pa_assert(a); + pa_dynarray_free(a, token_free, NULL); } const char *pa_tokenizer_get(pa_tokenizer *t, unsigned i) { - assert(t); - return pa_dynarray_get(t->dynarray, i); + pa_dynarray *a = (pa_dynarray*) t; + + pa_assert(a); + return pa_dynarray_get(a, i); } diff --git a/src/pulsecore/winsock.h b/src/pulsecore/winsock.h index ae868b38..0352bf4d 100644 --- a/src/pulsecore/winsock.h +++ b/src/pulsecore/winsock.h @@ -15,6 +15,8 @@ #define EHOSTUNREACH WSAEHOSTUNREACH #define EWOULDBLOCK WSAEWOULDBLOCK +typedef long suseconds_t; + #endif #ifdef HAVE_WS2TCPIP_H diff --git a/src/pulsecore/x11prop.c b/src/pulsecore/x11prop.c index 5b85ea42..a740e39b 100644 --- a/src/pulsecore/x11prop.c +++ b/src/pulsecore/x11prop.c @@ -32,7 +32,6 @@ #include "x11prop.h" - void pa_x11_set_prop(Display *d, const char *name, const char *data) { Atom a = XInternAtom(d, name, False); XChangeProperty(d, RootWindow(d, 0), a, XA_STRING, 8, PropModeReplace, (const unsigned char*) data, strlen(data)+1); diff --git a/src/pulsecore/x11wrap.c b/src/pulsecore/x11wrap.c index 6a6a2692..800a9458 100644 --- a/src/pulsecore/x11wrap.c +++ b/src/pulsecore/x11wrap.c @@ -21,7 +21,10 @@ USA. ***/ -#include +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include @@ -29,6 +32,8 @@ #include #include #include +#include +#include #include "x11wrap.h" @@ -42,8 +47,8 @@ struct pa_x11_internal { }; struct pa_x11_wrapper { + PA_REFCNT_DECLARE; pa_core *core; - int ref; char *property_name; Display *display; @@ -64,7 +69,8 @@ struct pa_x11_client { /* Dispatch all pending X11 events */ static void work(pa_x11_wrapper *w) { - assert(w && w->ref >= 1); + pa_assert(w); + pa_assert(PA_REFCNT_VALUE(w) >= 1); while (XPending(w->display)) { pa_x11_client *c; @@ -72,7 +78,7 @@ static void work(pa_x11_wrapper *w) { XNextEvent(w->display, &e); for (c = w->clients; c; c = c->next) { - assert(c->callback); + pa_assert(c->callback); if (c->callback(w, &e, c->userdata) != 0) break; } @@ -82,14 +88,24 @@ static void work(pa_x11_wrapper *w) { /* IO notification event for the X11 display connection */ static void display_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { pa_x11_wrapper *w = userdata; - assert(m && e && fd >= 0 && w && w->ref >= 1); + + pa_assert(m); + pa_assert(e); + pa_assert(fd >= 0); + pa_assert(w); + pa_assert(PA_REFCNT_VALUE(w) >= 1); + work(w); } /* Deferred notification event. Called once each main loop iteration */ static void defer_event(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { pa_x11_wrapper *w = userdata; - assert(m && e && w && w->ref >= 1); + + pa_assert(m); + pa_assert(e); + pa_assert(w); + pa_assert(PA_REFCNT_VALUE(w) >= 1); m->defer_enable(e, 0); @@ -99,7 +115,12 @@ static void defer_event(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { /* IO notification event for X11 internal connections */ static void internal_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { pa_x11_wrapper *w = userdata; - assert(m && e && fd >= 0 && w && w->ref >= 1); + + pa_assert(m); + pa_assert(e); + pa_assert(fd >= 0); + pa_assert(w); + pa_assert(PA_REFCNT_VALUE(w) >= 1); XProcessInternalConnection(w->display, fd); @@ -109,10 +130,9 @@ static void internal_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC /* Add a new IO source for the specified X11 internal connection */ static pa_x11_internal* x11_internal_add(pa_x11_wrapper *w, int fd) { pa_x11_internal *i; - assert(fd >= 0); + pa_assert(fd >= 0); - i = pa_xmalloc(sizeof(pa_x11_internal)); - assert(i); + i = pa_xnew(pa_x11_internal, 1); i->wrapper = w; i->io_event = w->core->mainloop->io_new(w->core->mainloop, fd, PA_IO_EVENT_INPUT, internal_io_event, w); i->fd = fd; @@ -123,7 +143,7 @@ static pa_x11_internal* x11_internal_add(pa_x11_wrapper *w, int fd) { /* Remove an IO source for an X11 internal connection */ static void x11_internal_remove(pa_x11_wrapper *w, pa_x11_internal *i) { - assert(i); + pa_assert(i); PA_LLIST_REMOVE(pa_x11_internal, w->internals, i); w->core->mainloop->io_free(i->io_event); @@ -133,7 +153,10 @@ static void x11_internal_remove(pa_x11_wrapper *w, pa_x11_internal *i) { /* Implementation of XConnectionWatchProc */ static void x11_watch(Display *display, XPointer userdata, int fd, Bool opening, XPointer *watch_data) { pa_x11_wrapper *w = (pa_x11_wrapper*) userdata; - assert(display && w && fd >= 0); + + pa_assert(display); + pa_assert(w); + pa_assert(fd >= 0); if (opening) *watch_data = (XPointer) x11_internal_add(w, fd); @@ -144,16 +167,15 @@ static void x11_watch(Display *display, XPointer userdata, int fd, Bool opening, static pa_x11_wrapper* x11_wrapper_new(pa_core *c, const char *name, const char *t) { pa_x11_wrapper*w; Display *d; - int r; if (!(d = XOpenDisplay(name))) { pa_log("XOpenDisplay() failed"); return NULL; } - w = pa_xmalloc(sizeof(pa_x11_wrapper)); + w = pa_xnew(pa_x11_wrapper, 1); + PA_REFCNT_INIT(w); w->core = c; - w->ref = 1; w->property_name = pa_xstrdup(t); w->display = d; @@ -165,20 +187,17 @@ static pa_x11_wrapper* x11_wrapper_new(pa_core *c, const char *name, const char XAddConnectionWatch(d, x11_watch, (XPointer) w); - r = pa_property_set(c, w->property_name, w); - assert(r >= 0); + pa_assert_se(pa_property_set(c, w->property_name, w) >= 0); return w; } static void x11_wrapper_free(pa_x11_wrapper*w) { - int r; - assert(w); + pa_assert(w); - r = pa_property_remove(w->core, w->property_name); - assert(r >= 0); + pa_assert_se(pa_property_remove(w->core, w->property_name) >= 0); - assert(!w->clients); + pa_assert(!w->clients); XRemoveConnectionWatch(w->display, x11_watch, (XPointer) w); XCloseDisplay(w->display); @@ -196,9 +215,10 @@ static void x11_wrapper_free(pa_x11_wrapper*w) { pa_x11_wrapper* pa_x11_wrapper_get(pa_core *c, const char *name) { char t[256]; pa_x11_wrapper *w; - assert(c); - snprintf(t, sizeof(t), "x11-wrapper%s%s", name ? "-" : "", name ? name : ""); + pa_core_assert_ref(c); + + pa_snprintf(t, sizeof(t), "x11-wrapper%s%s", name ? "-" : "", name ? name : ""); if ((w = pa_property_get(c, t))) return pa_x11_wrapper_ref(w); @@ -206,20 +226,24 @@ pa_x11_wrapper* pa_x11_wrapper_get(pa_core *c, const char *name) { } pa_x11_wrapper* pa_x11_wrapper_ref(pa_x11_wrapper *w) { - assert(w && w->ref >= 1); - w->ref++; + pa_assert(w); + pa_assert(PA_REFCNT_VALUE(w) >= 1); + + PA_REFCNT_INC(w); return w; } void pa_x11_wrapper_unref(pa_x11_wrapper* w) { - assert(w && w->ref >= 1); + pa_assert(w); + pa_assert(PA_REFCNT_VALUE(w) >= 1); - if (!(--w->ref)) + if (PA_REFCNT_DEC(w) <= 0) x11_wrapper_free(w); } Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w) { - assert(w && w->ref >= 1); + pa_assert(w); + pa_assert(PA_REFCNT_VALUE(w) >= 1); /* Somebody is using us, schedule a output buffer flush */ w->core->mainloop->defer_enable(w->defer_event, 1); @@ -229,9 +253,11 @@ Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w) { pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata) { pa_x11_client *c; - assert(w && w->ref >= 1); - c = pa_xmalloc(sizeof(pa_x11_client)); + pa_assert(w); + pa_assert(PA_REFCNT_VALUE(w) >= 1); + + c = pa_xnew(pa_x11_client, 1); c->wrapper = w; c->callback = cb; c->userdata = userdata; @@ -242,7 +268,9 @@ pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w, } void pa_x11_client_free(pa_x11_client *c) { - assert(c && c->wrapper && c->wrapper->ref >= 1); + pa_assert(c); + pa_assert(c->wrapper); + pa_assert(PA_REFCNT_VALUE(c->wrapper) >= 1); PA_LLIST_REMOVE(pa_x11_client, c->wrapper->clients, c); pa_xfree(c); diff --git a/src/tests/asyncmsgq-test.c b/src/tests/asyncmsgq-test.c new file mode 100644 index 00000000..380c5e7f --- /dev/null +++ b/src/tests/asyncmsgq-test.c @@ -0,0 +1,110 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +enum { + OPERATION_A, + OPERATION_B, + OPERATION_C, + QUIT +}; + +static void the_thread(void *_q) { + pa_asyncmsgq *q = _q; + int quit = 0; + + do { + int code = 0; + + pa_assert_se(pa_asyncmsgq_get(q, NULL, &code, NULL, NULL, NULL, 1) == 0); + + switch (code) { + + case OPERATION_A: + printf("Operation A\n"); + break; + + case OPERATION_B: + printf("Operation B\n"); + break; + + case OPERATION_C: + printf("Operation C\n"); + break; + + case QUIT: + printf("quit\n"); + quit = 1; + break; + } + + pa_asyncmsgq_done(q, 0); + + } while (!quit); +} + +int main(int argc, char *argv[]) { + pa_asyncmsgq *q; + pa_thread *t; + + pa_assert_se(q = pa_asyncmsgq_new(0)); + + pa_assert_se(t = pa_thread_new(the_thread, q)); + + printf("Operation A post\n"); + pa_asyncmsgq_post(q, NULL, OPERATION_A, NULL, 0, NULL, NULL); + + pa_thread_yield(); + + printf("Operation B post\n"); + pa_asyncmsgq_post(q, NULL, OPERATION_B, NULL, 0, NULL, NULL); + + pa_thread_yield(); + + printf("Operation C send\n"); + pa_asyncmsgq_send(q, NULL, OPERATION_C, NULL, 0, NULL); + + pa_thread_yield(); + + printf("Quit post\n"); + pa_asyncmsgq_post(q, NULL, QUIT, NULL, 0, NULL, NULL); + + pa_thread_free(t); + + pa_asyncmsgq_unref(q); + + return 0; +} diff --git a/src/tests/asyncq-test.c b/src/tests/asyncq-test.c new file mode 100644 index 00000000..09b20047 --- /dev/null +++ b/src/tests/asyncq-test.c @@ -0,0 +1,87 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static void producer(void *_q) { + pa_asyncq *q = _q; + int i; + + for (i = 0; i < 1000; i++) { + printf("pushing %i\n", i); + pa_asyncq_push(q, PA_UINT_TO_PTR(i+1), 1); + } + + pa_asyncq_push(q, PA_UINT_TO_PTR(-1), 1); + printf("pushed end\n"); +} + +static void consumer(void *_q) { + pa_asyncq *q = _q; + void *p; + int i; + + sleep(1); + + for (i = 0;; i++) { + p = pa_asyncq_pop(q, 1); + + if (p == PA_UINT_TO_PTR(-1)) + break; + + pa_assert(p == PA_UINT_TO_PTR(i+1)); + + printf("popped %i\n", i); + } + + printf("popped end\n"); +} + +int main(int argc, char *argv[]) { + pa_asyncq *q; + pa_thread *t1, *t2; + + pa_assert_se(q = pa_asyncq_new(0)); + + pa_assert_se(t1 = pa_thread_new(producer, q)); + pa_assert_se(t2 = pa_thread_new(consumer, q)); + + pa_thread_free(t1); + pa_thread_free(t2); + + pa_asyncq_free(q, NULL); + + return 0; +} diff --git a/src/tests/hook-list-test.c b/src/tests/hook-list-test.c index 6879eae5..8628f521 100644 --- a/src/tests/hook-list-test.c +++ b/src/tests/hook-list-test.c @@ -1,5 +1,9 @@ /* $Id$ */ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include diff --git a/src/tests/interpol-test.c b/src/tests/interpol-test.c index 3953043f..85a509d4 100644 --- a/src/tests/interpol-test.c +++ b/src/tests/interpol-test.c @@ -137,7 +137,7 @@ int main(int argc, char *argv[]) { pa_gettimeofday(&now); rtc = pa_timeval_diff(&now, &start); - printf("%i\t%llu\t%llu\t%llu\t%llu\t%u\n", k, rtc, t, rtc-old_rtc, t-old_t, changed); + printf("%i\t%llu\t%llu\t%llu\t%llu\t%u\n", k, (unsigned long long) rtc, (unsigned long long) t, (unsigned long long) (rtc-old_rtc), (unsigned long long) (t-old_t), changed); old_t = t; old_rtc = rtc; } diff --git a/src/tests/mcalign-test.c b/src/tests/mcalign-test.c index db76712b..d1013118 100644 --- a/src/tests/mcalign-test.c +++ b/src/tests/mcalign-test.c @@ -59,24 +59,29 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { c.index = c.length = 0; } - assert(c.index < c.memblock->length); + assert(c.index < pa_memblock_get_length(c.memblock)); - l = c.memblock->length - c.index; + l = pa_memblock_get_length(c.memblock) - c.index; l = l <= 1 ? l : rand() % (l-1) +1 ; - if ((r = read(STDIN_FILENO, (uint8_t*) c.memblock->data + c.index, l)) <= 0) { + p = pa_memblock_acquire(c.memblock); + + if ((r = read(STDIN_FILENO, (uint8_t*) p + c.index, l)) <= 0) { + pa_memblock_release(c.memblock); fprintf(stderr, "read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); break; } + pa_memblock_release(c.memblock); + c.length = r; pa_mcalign_push(a, &c); fprintf(stderr, "Read %ld bytes\n", (long)r); c.index += r; - if (c.index >= c.memblock->length) { + if (c.index >= pa_memblock_get_length(c.memblock)) { pa_memblock_unref(c.memblock); pa_memchunk_reset(&c); } @@ -87,7 +92,9 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { if (pa_mcalign_pop(a, &t) < 0) break; - pa_loop_write(STDOUT_FILENO, (uint8_t*) t.memblock->data + t.index, t.length, NULL); + p = pa_memblock_acquire(t.memblock); + pa_loop_write(STDOUT_FILENO, (uint8_t*) p + t.index, t.length, NULL); + pa_memblock_release(t.memblock); fprintf(stderr, "Wrote %lu bytes.\n", (unsigned long) t.length); pa_memblock_unref(t.memblock); diff --git a/src/tests/memblock-test.c b/src/tests/memblock-test.c index 8d25ba38..2b9d3401 100644 --- a/src/tests/memblock-test.c +++ b/src/tests/memblock-test.c @@ -23,11 +23,11 @@ #include #endif -#include #include #include #include +#include #include static void release_cb(pa_memimport *i, uint32_t block_id, void *userdata) { @@ -76,6 +76,7 @@ int main(int argc, char *argv[]) { pa_memblock* blocks[5]; uint32_t id, shm_id; size_t offset, size; + char *x; const char txt[] = "This is a test!"; @@ -87,13 +88,20 @@ int main(int argc, char *argv[]) { pa_mempool_get_shm_id(pool_b, &id_b); pa_mempool_get_shm_id(pool_c, &id_c); - assert(pool_a && pool_b && pool_c); + pa_assert(pool_a && pool_b && pool_c); blocks[0] = pa_memblock_new_fixed(pool_a, (void*) txt, sizeof(txt), 1); + blocks[1] = pa_memblock_new(pool_a, sizeof(txt)); - snprintf(blocks[1]->data, blocks[1]->length, "%s", txt); + x = pa_memblock_acquire(blocks[1]); + snprintf(x, pa_memblock_get_length(blocks[1]), "%s", txt); + pa_memblock_release(blocks[1]); + blocks[2] = pa_memblock_new_pool(pool_a, sizeof(txt)); - snprintf(blocks[2]->data, blocks[2]->length, "%s", txt); + x = pa_memblock_acquire(blocks[2]); + snprintf(x, pa_memblock_get_length(blocks[2]), "%s", txt); + pa_memblock_release(blocks[2]); + blocks[3] = pa_memblock_new_malloced(pool_a, pa_xstrdup(txt), sizeof(txt)); blocks[4] = NULL; @@ -101,43 +109,47 @@ int main(int argc, char *argv[]) { printf("Memory block %u\n", i); mb_a = blocks[i]; - assert(mb_a); + pa_assert(mb_a); export_a = pa_memexport_new(pool_a, revoke_cb, (void*) "A"); export_b = pa_memexport_new(pool_b, revoke_cb, (void*) "B"); - assert(export_a && export_b); + pa_assert(export_a && export_b); import_b = pa_memimport_new(pool_b, release_cb, (void*) "B"); import_c = pa_memimport_new(pool_c, release_cb, (void*) "C"); - assert(import_b && import_c); + pa_assert(import_b && import_c); r = pa_memexport_put(export_a, mb_a, &id, &shm_id, &offset, &size); - assert(r >= 0); - assert(shm_id == id_a); + pa_assert(r >= 0); + pa_assert(shm_id == id_a); printf("A: Memory block exported as %u\n", id); mb_b = pa_memimport_get(import_b, id, shm_id, offset, size); - assert(mb_b); + pa_assert(mb_b); r = pa_memexport_put(export_b, mb_b, &id, &shm_id, &offset, &size); - assert(r >= 0); - assert(shm_id == id_a || shm_id == id_b); + pa_assert(r >= 0); + pa_assert(shm_id == id_a || shm_id == id_b); pa_memblock_unref(mb_b); printf("B: Memory block exported as %u\n", id); mb_c = pa_memimport_get(import_c, id, shm_id, offset, size); - assert(mb_c); - printf("1 data=%s\n", (char*) mb_c->data); + pa_assert(mb_c); + x = pa_memblock_acquire(mb_c); + printf("1 data=%s\n", x); + pa_memblock_release(mb_c); print_stats(pool_a, "A"); print_stats(pool_b, "B"); print_stats(pool_c, "C"); pa_memexport_free(export_b); - printf("2 data=%s\n", (char*) mb_c->data); + x = pa_memblock_acquire(mb_c); + printf("2 data=%s\n", x); + pa_memblock_release(mb_c); pa_memblock_unref(mb_c); pa_memimport_free(import_b); diff --git a/src/tests/memblockq-test.c b/src/tests/memblockq-test.c index 1c0b7fed..25ea399b 100644 --- a/src/tests/memblockq-test.c +++ b/src/tests/memblockq-test.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -48,22 +49,22 @@ int main(int argc, char *argv[]) { bq = pa_memblockq_new(0, 40, 10, 2, 4, 4, silence); assert(bq); - chunk1.memblock = pa_memblock_new_fixed(p, (char*) "AA", 2, 1); + chunk1.memblock = pa_memblock_new_fixed(p, (char*) "11", 2, 1); chunk1.index = 0; chunk1.length = 2; assert(chunk1.memblock); - chunk2.memblock = pa_memblock_new_fixed(p, (char*) "TTBB", 4, 1); + chunk2.memblock = pa_memblock_new_fixed(p, (char*) "XX22", 4, 1); chunk2.index = 2; chunk2.length = 2; assert(chunk2.memblock); - chunk3.memblock = pa_memblock_new_fixed(p, (char*) "ZZZZ", 4, 1); + chunk3.memblock = pa_memblock_new_fixed(p, (char*) "3333", 4, 1); chunk3.index = 0; chunk3.length = 4; assert(chunk3.memblock); - chunk4.memblock = pa_memblock_new_fixed(p, (char*) "KKKKKKKK", 8, 1); + chunk4.memblock = pa_memblock_new_fixed(p, (char*) "44444444", 8, 1); chunk4.index = 0; chunk4.length = 8; assert(chunk4.memblock); @@ -115,13 +116,12 @@ int main(int argc, char *argv[]) { chunk3.index += 2; chunk3.length -= 2; - ret = pa_memblockq_push(bq, &chunk3); assert(ret == 0); - printf(">"); + pa_memblockq_shorten(bq, pa_memblockq_get_length(bq)-2); - pa_memblockq_shorten(bq, 6); + printf(">"); for (;;) { pa_memchunk out; @@ -131,11 +131,13 @@ int main(int argc, char *argv[]) { if (pa_memblockq_peek(bq, &out) < 0) break; - for (e = (char*) out.memblock->data + out.index, n = 0; n < out.length; n++) + p = pa_memblock_acquire(out.memblock); + for (e = (char*) p + out.index, n = 0; n < out.length; n++) printf("%c", *e); + pa_memblock_release(out.memblock); pa_memblock_unref(out.memblock); - pa_memblockq_drop(bq, &out, out.length); + pa_memblockq_drop(bq, out.length); } printf("<\n"); diff --git a/src/tests/queue-test.c b/src/tests/queue-test.c new file mode 100644 index 00000000..b357ab10 --- /dev/null +++ b/src/tests/queue-test.c @@ -0,0 +1,69 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + pa_queue *q; + + pa_assert_se(q = pa_queue_new()); + + pa_assert(pa_queue_is_empty(q)); + + pa_queue_push(q, (void*) "eins"); + pa_log("%s\n", (char*) pa_queue_pop(q)); + + pa_assert(pa_queue_is_empty(q)); + + pa_queue_push(q, (void*) "zwei"); + pa_queue_push(q, (void*) "drei"); + pa_queue_push(q, (void*) "vier"); + + pa_log("%s\n", (char*) pa_queue_pop(q)); + pa_log("%s\n", (char*) pa_queue_pop(q)); + + pa_queue_push(q, (void*) "fuenf"); + + pa_log("%s\n", (char*) pa_queue_pop(q)); + pa_log("%s\n", (char*) pa_queue_pop(q)); + + pa_assert(pa_queue_is_empty(q)); + + pa_queue_push(q, (void*) "sechs"); + pa_queue_push(q, (void*) "sieben"); + + pa_queue_free(q, NULL, NULL); + + return 0; +} diff --git a/src/tests/resampler-test.c b/src/tests/resampler-test.c new file mode 100644 index 00000000..3b4a7386 --- /dev/null +++ b/src/tests/resampler-test.c @@ -0,0 +1,227 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +static float swap_float(float a) { + uint32_t *b = (uint32_t*) &a; + *b = PA_UINT32_SWAP(*b); + return a; +} + +static void dump_block(const pa_sample_spec *ss, const pa_memchunk *chunk) { + void *d; + unsigned i; + + d = pa_memblock_acquire(chunk->memblock); + + switch (ss->format) { + + case PA_SAMPLE_U8: + case PA_SAMPLE_ULAW: + case PA_SAMPLE_ALAW: { + uint8_t *u = d; + + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) + printf("0x%02x ", *(u++)); + + break; + } + + case PA_SAMPLE_S16NE: + case PA_SAMPLE_S16RE: { + uint16_t *u = d; + + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) + printf("0x%04x ", *(u++)); + + break; + } + + case PA_SAMPLE_FLOAT32NE: + case PA_SAMPLE_FLOAT32RE: { + float *u = d; + + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) { + printf("%1.3g ", ss->format == PA_SAMPLE_FLOAT32NE ? *u : swap_float(*u)); + u++; + } + + break; + } + + default: + pa_assert_not_reached(); + } + + printf("\n"); + + pa_memblock_release(chunk->memblock); +} + +static pa_memblock* generate_block(pa_mempool *pool, const pa_sample_spec *ss) { + pa_memblock *r; + void *d; + unsigned i; + + pa_assert_se(r = pa_memblock_new(pool, pa_frame_size(ss) * 10)); + d = pa_memblock_acquire(r); + + switch (ss->format) { + + case PA_SAMPLE_U8: + case PA_SAMPLE_ULAW: + case PA_SAMPLE_ALAW: { + uint8_t *u = d; + + u[0] = 0x00; + u[1] = 0xFF; + u[2] = 0x7F; + u[3] = 0x80; + u[4] = 0x9f; + u[5] = 0x3f; + u[6] = 0x1; + u[7] = 0xF0; + u[8] = 0x20; + u[9] = 0x21; + break; + } + + case PA_SAMPLE_S16NE: + case PA_SAMPLE_S16RE: { + uint16_t *u = d; + + u[0] = 0x0000; + u[1] = 0xFFFF; + u[2] = 0x7FFF; + u[3] = 0x8000; + u[4] = 0x9fff; + u[5] = 0x3fff; + u[6] = 0x1; + u[7] = 0xF000; + u[8] = 0x20; + u[9] = 0x21; + break; + } + + case PA_SAMPLE_FLOAT32NE: + case PA_SAMPLE_FLOAT32RE: { + float *u = d; + + u[0] = 0.0; + u[1] = -1.0; + u[2] = 1.0; + u[3] = 4711; + u[4] = 0.222; + u[5] = 0.33; + u[6] = -.3; + u[7] = 99; + u[8] = -0.555; + u[9] = -.123; + + if (ss->format == PA_SAMPLE_FLOAT32RE) + for (i = 0; i < 10; i++) + u[i] = swap_float(u[i]); + + break; + } + + default: + pa_assert_not_reached(); + } + + pa_memblock_release(r); + + return r; +} + +int main(int argc, char *argv[]) { + pa_mempool *pool; + pa_sample_spec a, b; + pa_cvolume v; + + oil_init(); + pa_log_set_maximal_level(PA_LOG_DEBUG); + + pa_assert_se(pool = pa_mempool_new(FALSE)); + + a.channels = b.channels = 1; + a.rate = b.rate = 44100; + + v.channels = a.channels; + v.values[0] = pa_sw_volume_from_linear(0.5); + + for (a.format = 0; a.format < PA_SAMPLE_MAX; a.format ++) { + for (b.format = 0; b.format < PA_SAMPLE_MAX; b.format ++) { + + pa_resampler *forth, *back; + pa_memchunk i, j, k; + + printf("=== %s -> %s -> %s -> /2\n", + pa_sample_format_to_string(a.format), + pa_sample_format_to_string(b.format), + pa_sample_format_to_string(a.format)); + + pa_assert_se(forth = pa_resampler_new(pool, &a, NULL, &b, NULL, PA_RESAMPLER_AUTO, FALSE)); + pa_assert_se(back = pa_resampler_new(pool, &b, NULL, &a, NULL, PA_RESAMPLER_AUTO, FALSE)); + + i.memblock = generate_block(pool, &a); + i.length = pa_memblock_get_length(i.memblock); + i.index = 0; + pa_resampler_run(forth, &i, &j); + pa_resampler_run(back, &j, &k); + + dump_block(&a, &i); + dump_block(&b, &j); + dump_block(&a, &k); + + pa_memblock_unref(j.memblock); + pa_memblock_unref(k.memblock); + + pa_volume_memchunk(&i, &a, &v); + dump_block(&a, &i); + + pa_memblock_unref(i.memblock); + + pa_resampler_free(forth); + pa_resampler_free(back); + } + } + + pa_mempool_free(pool); + + return 0; +} diff --git a/src/tests/rtpoll-test.c b/src/tests/rtpoll-test.c new file mode 100644 index 00000000..3ab992a1 --- /dev/null +++ b/src/tests/rtpoll-test.c @@ -0,0 +1,91 @@ +/* $Id: thread-test.c 1621 2007-08-10 22:00:22Z lennart $ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include + +static int before(pa_rtpoll_item *i) { + pa_log("before"); + return 0; +} + +static void after(pa_rtpoll_item *i) { + pa_log("after"); +} + +static int worker(pa_rtpoll_item *w) { + pa_log("worker"); + return 0; +} + +int main(int argc, char *argv[]) { + pa_rtpoll *p; + pa_rtpoll_item *i, *w; + struct pollfd *pollfd; + + pa_rtsig_configure(SIGRTMIN+10, SIGRTMAX); + + p = pa_rtpoll_new(); + + i = pa_rtpoll_item_new(p, PA_RTPOLL_EARLY, 1); + pa_rtpoll_item_set_before_callback(i, before); + pa_rtpoll_item_set_after_callback(i, after); + + pollfd = pa_rtpoll_item_get_pollfd(i, NULL); + pollfd->fd = 0; + pollfd->events = POLLIN; + + w = pa_rtpoll_item_new(p, PA_RTPOLL_NORMAL, 0); + pa_rtpoll_item_set_before_callback(w, worker); + + pa_rtpoll_install(p); + pa_rtpoll_set_timer_periodic(p, 10000000); /* 10 s */ + + pa_rtpoll_run(p, 1); + + pa_rtpoll_item_free(i); + + i = pa_rtpoll_item_new(p, PA_RTPOLL_EARLY, 1); + pa_rtpoll_item_set_before_callback(i, before); + pa_rtpoll_item_set_after_callback(i, after); + + pollfd = pa_rtpoll_item_get_pollfd(i, NULL); + pollfd->fd = 0; + pollfd->events = POLLIN; + + pa_rtpoll_run(p, 1); + + pa_rtpoll_item_free(i); + + pa_rtpoll_item_free(w); + + pa_rtpoll_free(p); + + return 0; +} diff --git a/src/tests/sig2str-test.c b/src/tests/sig2str-test.c new file mode 100644 index 00000000..52cb9db4 --- /dev/null +++ b/src/tests/sig2str-test.c @@ -0,0 +1,39 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include + +int main(int argc, char *argv[]) { + int sig; + + for (sig = -1; sig <= NSIG; sig++) + printf("%i = %s\n", sig, pa_sig2str(sig)); + + return 0; +} diff --git a/src/tests/smoother-test.c b/src/tests/smoother-test.c new file mode 100644 index 00000000..caa7df70 --- /dev/null +++ b/src/tests/smoother-test.c @@ -0,0 +1,80 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include + +int main(int argc, char*argv[]) { + pa_usec_t x; + unsigned u = 0; + pa_smoother *s; + int m; + +/* unsigned msec[] = { */ +/* 200, 200, */ +/* 300, 320, */ +/* 400, 400, */ +/* 500, 480, */ +/* 0, 0 */ +/* }; */ + + int msec[200]; + + srand(0); + + for (m = 0, u = 0; u < PA_ELEMENTSOF(msec)-2; u+= 2) { + + msec[u] = m+1; + msec[u+1] = m + rand() % 2000 - 1000; + + m += rand() % 100; + + if (msec[u+1] < 0) + msec[u+1] = 0; + } + + msec[PA_ELEMENTSOF(msec)-2] = 0; + msec[PA_ELEMENTSOF(msec)-1] = 0; + + s = pa_smoother_new(1000*PA_USEC_PER_MSEC, 2000*PA_USEC_PER_MSEC, TRUE); + + for (x = 0, u = 0; x < PA_USEC_PER_SEC * 10; x += PA_USEC_PER_MSEC) { + + while (msec[u] > 0 && (pa_usec_t) msec[u]*PA_USEC_PER_MSEC < x) { + pa_smoother_put(s, msec[u]*PA_USEC_PER_MSEC, msec[u+1]*PA_USEC_PER_MSEC); + printf("%i\t\t%i\n", msec[u], msec[u+1]); + u += 2; + } + + printf("%llu\t%llu\n", x/PA_USEC_PER_MSEC, pa_smoother_get(s, x)/PA_USEC_PER_MSEC); + } + + pa_smoother_free(s); + + return 0; +} diff --git a/src/tests/thread-mainloop-test.c b/src/tests/thread-mainloop-test.c index 9d0e5de1..558e53a5 100644 --- a/src/tests/thread-mainloop-test.c +++ b/src/tests/thread-mainloop-test.c @@ -23,18 +23,19 @@ #include #endif -#include #include #include #include #include #include +#include #include -#include +#include static void tcb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) { + pa_assert_se(pa_threaded_mainloop_in_thread(userdata)); fprintf(stderr, "TIME EVENT START\n"); pa_threaded_mainloop_signal(userdata, 1); fprintf(stderr, "TIME EVENT END\n"); @@ -45,15 +46,15 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { pa_threaded_mainloop *m; struct timeval tv; - m = pa_threaded_mainloop_new(); - assert(m); - a = pa_threaded_mainloop_get_api(m); - assert(a); + pa_assert_se(m = pa_threaded_mainloop_new()); + pa_assert_se(a = pa_threaded_mainloop_get_api(m)); pa_threaded_mainloop_start(m); pa_threaded_mainloop_lock(m); + pa_assert_se(!pa_threaded_mainloop_in_thread(m)); + pa_gettimeofday(&tv); tv.tv_sec += 5; a->time_new(a, &tv, tcb, m); diff --git a/src/tests/thread-test.c b/src/tests/thread-test.c index 2153c985..72dde6cb 100644 --- a/src/tests/thread-test.c +++ b/src/tests/thread-test.c @@ -42,7 +42,7 @@ static void once_func(void) { pa_log("once!"); } -static pa_once_t once = PA_ONCE_INIT; +static pa_once once = PA_ONCE_INIT; static void thread_func(void *data) { pa_tls_set(tls, data); @@ -72,7 +72,7 @@ static void thread_func(void *data) { pa_mutex_unlock(mutex); - pa_once(&once, once_func); + pa_run_once(&once, once_func); pa_cond_signal(cond2, 0); @@ -98,7 +98,7 @@ int main(int argc, char *argv[]) { assert(pa_thread_is_running(pa_thread_self())); - mutex = pa_mutex_new(0); + mutex = pa_mutex_new(FALSE, FALSE); cond1 = pa_cond_new(); cond2 = pa_cond_new(); tls = pa_tls_new(pa_xfree); diff --git a/src/utils/pactl.c b/src/utils/pactl.c index b95cbfee..c963987f 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -48,8 +48,10 @@ static pa_context *context = NULL; static pa_mainloop_api *mainloop_api = NULL; -static char *device = NULL, *sample_name = NULL, *sink_name = NULL, *source_name = NULL; +static char *device = NULL, *sample_name = NULL, *sink_name = NULL, *source_name = NULL, *module_name = NULL, *module_args = NULL; static uint32_t sink_input_idx = PA_INVALID_INDEX, source_output_idx = PA_INVALID_INDEX; +static uint32_t module_index; +static int suspend; static SNDFILE *sndfile = NULL; static pa_stream *sample_stream = NULL; @@ -69,7 +71,11 @@ static enum { REMOVE_SAMPLE, LIST, MOVE_SINK_INPUT, - MOVE_SOURCE_OUTPUT + MOVE_SOURCE_OUTPUT, + LOAD_MODULE, + UNLOAD_MODULE, + SUSPEND_SINK, + SUSPEND_SOURCE, } action = NONE; static void quit(int ret) { @@ -354,7 +360,7 @@ static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info i->sink, pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), - pa_cvolume_snprint(cv, sizeof(cv), &i->volume), + i->mute ? "muted" : pa_cvolume_snprint(cv, sizeof(cv), &i->volume), (double) i->buffer_usec, (double) i->sink_usec, i->resample_method ? i->resample_method : "n/a"); @@ -492,6 +498,18 @@ static void simple_callback(pa_context *c, int success, void *userdata) { complete_action(); } +static void index_callback(pa_context *c, uint32_t idx, void *userdata) { + if (idx == PA_INVALID_INDEX) { + fprintf(stderr, "Failure: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + printf("%u\n", idx); + + complete_action(); +} + static void stream_state_callback(pa_stream *s, void *userdata) { assert(s); @@ -594,6 +612,28 @@ static void context_state_callback(pa_context *c, void *userdata) { pa_operation_unref(pa_context_move_source_output_by_name(c, source_output_idx, source_name, simple_callback, NULL)); break; + case LOAD_MODULE: + pa_operation_unref(pa_context_load_module(c, module_name, module_args, index_callback, NULL)); + break; + + case UNLOAD_MODULE: + pa_operation_unref(pa_context_unload_module(c, module_index, simple_callback, NULL)); + break; + + case SUSPEND_SINK: + if (sink_name) + pa_operation_unref(pa_context_suspend_sink_by_name(c, sink_name, suspend, simple_callback, NULL)); + else + pa_operation_unref(pa_context_suspend_sink_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL)); + break; + + case SUSPEND_SOURCE: + if (source_name) + pa_operation_unref(pa_context_suspend_source_by_name(c, source_name, suspend, simple_callback, NULL)); + else + pa_operation_unref(pa_context_suspend_source_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL)); + break; + default: assert(0); } @@ -624,12 +664,16 @@ static void help(const char *argv0) { "%s [options] play-sample NAME [SINK]\n" "%s [options] move-sink-input ID SINK\n" "%s [options] move-source-output ID SOURCE\n" - "%s [options] remove-sample NAME\n\n" + "%s [options] remove-sample NAME\n" + "%s [options] load-module NAME [ARGS ...]\n" + "%s [options] unload-module ID\n" + "%s [options] suspend-sink [SINK] 1|0\n" + "%s [options] suspend-source [SOURCE] 1|0\n\n" " -h, --help Show this help\n" " --version Show version\n\n" " -s, --server=SERVER The name of the server to connect to\n" " -n, --client-name=NAME How to call this client on the server\n", - argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0); + argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0); } enum { ARG_VERSION = 256 }; @@ -728,7 +772,7 @@ int main(int argc, char *argv[]) { sample_length = sfinfo.frames*pa_frame_size(&sample_spec); } else if (!strcmp(argv[optind], "play-sample")) { action = PLAY_SAMPLE; - if (optind+1 >= argc) { + if (argc != optind+2 && argc != optind+3) { fprintf(stderr, "You have to specify a sample name to play\n"); goto quit; } @@ -740,7 +784,7 @@ int main(int argc, char *argv[]) { } else if (!strcmp(argv[optind], "remove-sample")) { action = REMOVE_SAMPLE; - if (optind+1 >= argc) { + if (argc != optind+2) { fprintf(stderr, "You have to specify a sample name to remove\n"); goto quit; } @@ -748,7 +792,7 @@ int main(int argc, char *argv[]) { sample_name = pa_xstrdup(argv[optind+1]); } else if (!strcmp(argv[optind], "move-sink-input")) { action = MOVE_SINK_INPUT; - if (optind+2 >= argc) { + if (argc != optind+3) { fprintf(stderr, "You have to specify a sink input index and a sink\n"); goto quit; } @@ -757,13 +801,72 @@ int main(int argc, char *argv[]) { sink_name = pa_xstrdup(argv[optind+2]); } else if (!strcmp(argv[optind], "move-source-output")) { action = MOVE_SOURCE_OUTPUT; - if (optind+2 >= argc) { + if (argc != optind+3) { fprintf(stderr, "You have to specify a source output index and a source\n"); goto quit; } source_output_idx = atoi(argv[optind+1]); source_name = pa_xstrdup(argv[optind+2]); + } else if (!strcmp(argv[optind], "load-module")) { + int i; + size_t n = 0; + char *p; + + action = LOAD_MODULE; + + if (argc <= optind+1) { + fprintf(stderr, "You have to specify a module name and arguments.\n"); + goto quit; + } + + module_name = argv[optind+1]; + + for (i = optind+2; i < argc; i++) + n += strlen(argv[i])+1; + + if (n > 0) { + p = module_args = pa_xnew0(char, n); + + for (i = optind+2; i < argc; i++) + p += sprintf(p, "%s%s", p == module_args ? "" : " ", argv[i]); + } + + } else if (!strcmp(argv[optind], "unload-module")) { + action = UNLOAD_MODULE; + + if (argc != optind+2) { + fprintf(stderr, "You have to specify a module index\n"); + goto quit; + } + + module_index = atoi(argv[optind+1]); + + } else if (!strcmp(argv[optind], "suspend-sink")) { + action = SUSPEND_SINK; + + if (argc > optind+3 || optind+1 >= argc) { + fprintf(stderr, "You may not specify more than one sink. You have to specify at least one boolean value.\n"); + goto quit; + } + + suspend = !!atoi(argv[argc-1]); + + if (argc > optind+2) + sink_name = pa_xstrdup(argv[optind+1]); + + } else if (!strcmp(argv[optind], "suspend-source")) { + action = SUSPEND_SOURCE; + + if (argc > optind+3 || optind+1 >= argc) { + fprintf(stderr, "You may not specify more than one source. You have to specify at least one boolean value.\n"); + goto quit; + } + + suspend = !!atoi(argv[argc-1]); + + if (argc > optind+2) + source_name = pa_xstrdup(argv[optind+1]); } } @@ -819,6 +922,8 @@ quit: pa_xfree(sample_name); pa_xfree(sink_name); pa_xfree(source_name); + pa_xfree(module_args); + pa_xfree(client_name); return ret; } diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 95fc9ed3..b48af93c 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -61,6 +61,10 @@ # define SIOCINQ FIONREAD #endif +/* make sure gcc doesn't redefine open and friends as macros */ +#undef open +#undef open64 + typedef enum { FD_INFO_MIXER, FD_INFO_STREAM, @@ -259,9 +263,9 @@ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \ static void debug(int level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); -#define DEBUG_LEVEL_ALWAYS 0 -#define DEBUG_LEVEL_NORMAL 1 -#define DEBUG_LEVEL_VERBOSE 2 +#define DEBUG_LEVEL_ALWAYS 0 +#define DEBUG_LEVEL_NORMAL 1 +#define DEBUG_LEVEL_VERBOSE 2 static void debug(int level, const char *format, ...) { va_list ap; @@ -421,7 +425,7 @@ static void fd_info_unref(fd_info *i) { pthread_mutex_lock(&i->mutex); assert(i->ref >= 1); r = --i->ref; - debug(DEBUG_LEVEL_VERBOSE, __FILE__": ref--, now %i\n", i->ref); + debug(DEBUG_LEVEL_VERBOSE, __FILE__": ref--, now %i\n", i->ref); pthread_mutex_unlock(&i->mutex); if (r <= 0) @@ -1395,7 +1399,7 @@ static int sndstat_open(int flags, int *_errno) { if (flags != O_RDONLY #ifdef O_LARGEFILE - && flags != (O_RDONLY|O_LARGEFILE) + && flags != (O_RDONLY|O_LARGEFILE) #endif ) { *_errno = EACCES; @@ -1436,34 +1440,23 @@ fail: return -1; } -int open(const char *filename, int flags, ...) { - va_list args; - mode_t mode = 0; +static int real_open(const char *filename, int flags, mode_t mode) { int r, _errno = 0; debug(DEBUG_LEVEL_VERBOSE, __FILE__": open(%s)\n", filename); - va_start(args, flags); - if (flags & O_CREAT) { - if (sizeof(mode_t) < sizeof(int)) - mode = va_arg(args, int); - else - mode = va_arg(args, mode_t); - } - va_end(args); - if (!function_enter()) { LOAD_OPEN_FUNC(); return _open(filename, flags, mode); } - if (dsp_cloak_enable() && (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0)) { + if (dsp_cloak_enable() && (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0)) r = dsp_open(flags, &_errno); - } else if (mixer_cloak_enable() && strcmp(filename, "/dev/mixer") == 0) { + else if (mixer_cloak_enable() && strcmp(filename, "/dev/mixer") == 0) r = mixer_open(flags, &_errno); - } else if (sndstat_cloak_enable() && strcmp(filename, "/dev/sndstat") == 0) { + else if (sndstat_cloak_enable() && strcmp(filename, "/dev/sndstat") == 0) r = sndstat_open(flags, &_errno); - } else { + else { function_exit(); LOAD_OPEN_FUNC(); return _open(filename, flags, mode); @@ -1477,6 +1470,22 @@ int open(const char *filename, int flags, ...) { return r; } +int open(const char *filename, int flags, ...) { + va_list args; + mode_t mode = 0; + + if (flags & O_CREAT) { + va_start(args, flags); + if (sizeof(mode_t) < sizeof(int)) + mode = va_arg(args, int); + else + mode = va_arg(args, mode_t); + va_end(args); + } + + return real_open(filename, flags, mode); +} + static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) { int ret = -1; @@ -2023,9 +2032,9 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) *(int*) argp = DSP_CAP_DUPLEX | DSP_CAP_TRIGGER #ifdef DSP_CAP_MULTI - | DSP_CAP_MULTI + | DSP_CAP_MULTI #endif - ; + ; break; case SNDCTL_DSP_GETODELAY: { @@ -2497,10 +2506,14 @@ int open64(const char *filename, int flags, ...) { debug(DEBUG_LEVEL_VERBOSE, __FILE__": open64(%s)\n", filename); - va_start(args, flags); - if (flags & O_CREAT) - mode = va_arg(args, mode_t); - va_end(args); + if (flags & O_CREAT) { + va_start(args, flags); + if (sizeof(mode_t) < sizeof(int)) + mode = va_arg(args, int); + else + mode = va_arg(args, mode_t); + va_end(args); + } if (strcmp(filename, "/dev/dsp") != 0 && strcmp(filename, "/dev/adsp") != 0 && @@ -2510,7 +2523,7 @@ int open64(const char *filename, int flags, ...) { return _open64(filename, flags, mode); } - return open(filename, flags, mode); + return real_open(filename, flags, mode); } #endif @@ -2602,7 +2615,7 @@ FILE* fopen(const char *filename, const char *mode) { if ((((mode[1] == 'b') || (mode[1] == 't')) && (mode[2] == '+')) || (mode[1] == '+')) m = O_RDWR; - if ((fd = open(filename, m)) < 0) + if ((fd = real_open(filename, m, 0)) < 0) return NULL; if (!(f = fdopen(fd, mode))) { diff --git a/src/utils/paplay.c b/src/utils/paplay.c index 2c779a7a..e7076d2d 100644 --- a/src/utils/paplay.c +++ b/src/utils/paplay.c @@ -123,7 +123,7 @@ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { else pa_xfree(data); - if (bytes < length) { + if (bytes < (sf_count_t) length) { sf_close(sndfile); sndfile = NULL; pa_operation_unref(pa_stream_drain(s, stream_drain_complete, NULL)); diff --git a/src/utils/pasuspender.c b/src/utils/pasuspender.c new file mode 100644 index 00000000..ae59086b --- /dev/null +++ b/src/utils/pasuspender.c @@ -0,0 +1,316 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef __linux__ +#include +#endif + +#include +#include + +#if PA_API_VERSION < 10 +#error Invalid PulseAudio API version +#endif + +#define BUFSIZE 1024 + +static pa_context *context = NULL; +static pa_mainloop_api *mainloop_api = NULL; +static char **child_argv = NULL; +static int child_argc = 0; +static pid_t child_pid = (pid_t) -1; +static int child_ret = 0; +static int dead = 1; + +static void quit(int ret) { + pa_assert(mainloop_api); + mainloop_api->quit(mainloop_api, ret); +} + + +static void context_drain_complete(pa_context *c, void *userdata) { + pa_context_disconnect(c); +} + +static void drain(void) { + pa_operation *o; + + if (!(o = pa_context_drain(context, context_drain_complete, NULL))) + pa_context_disconnect(context); + else + pa_operation_unref(o); +} + +static void start_child(void) { + + if ((child_pid = fork()) < 0) { + + fprintf(stderr, "fork(): %s\n", strerror(errno)); + quit(1); + + } else if (child_pid == 0) { + /* Child */ + +#ifdef __linux__ + prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); +#endif + + if (execvp(child_argv[0], child_argv) < 0) + fprintf(stderr, "execvp(): %s\n", strerror(errno)); + + _exit(1); + + } else { + + /* parent */ + dead = 0; + } +} + +static void suspend_complete(pa_context *c, int success, void *userdata) { + static int n = 0; + + n++; + + if (!success) { + fprintf(stderr, "Failure to suspend: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (n >= 2) + start_child(); +} + +static void resume_complete(pa_context *c, int success, void *userdata) { + static int n = 0; + + n++; + + if (!success) { + fprintf(stderr, "Failure to resume: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (n >= 2) + drain(); /* drain and quit */ +} + +static void context_state_callback(pa_context *c, void *userdata) { + pa_assert(c); + + switch (pa_context_get_state(c)) { + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + + case PA_CONTEXT_READY: + if (pa_context_is_local(c)) { + pa_operation_unref(pa_context_suspend_sink_by_index(c, PA_INVALID_INDEX, 1, suspend_complete, NULL)); + pa_operation_unref(pa_context_suspend_source_by_index(c, PA_INVALID_INDEX, 1, suspend_complete, NULL)); + } else + start_child(); + + break; + + case PA_CONTEXT_TERMINATED: + quit(0); + break; + + case PA_CONTEXT_FAILED: + default: + fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c))); + + pa_context_unref(context); + context = NULL; + + if (child_pid == (pid_t) -1) + /* not started yet, then we do it now */ + start_child(); + else if (dead) + /* already started, and dead, so let's quit */ + quit(1); + + break; + } +} + +static void sigint_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) { + fprintf(stderr, "Got SIGINT, exiting.\n"); + quit(0); +} + +static void sigchld_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) { + int status = 0; + pid_t p; + + p = waitpid(-1, &status, WNOHANG); + + if (p != child_pid) + return; + + dead = 1; + + if (WIFEXITED(status)) + child_ret = WEXITSTATUS(status); + else if (WIFSIGNALED(status)) { + fprintf(stderr, "WARNING: Child process terminated by signal %u\n", WTERMSIG(status)); + child_ret = 1; + } + + if (context) { + if (pa_context_is_local(context)) { + /* A context is around, so let's resume */ + pa_operation_unref(pa_context_suspend_sink_by_index(context, PA_INVALID_INDEX, 0, resume_complete, NULL)); + pa_operation_unref(pa_context_suspend_source_by_index(context, PA_INVALID_INDEX, 0, resume_complete, NULL)); + } else + drain(); + } else + /* Hmm, no context here, so let's terminate right away */ + quit(0); +} + +static void help(const char *argv0) { + + printf("%s [options] ... \n\n" + " -h, --help Show this help\n" + " --version Show version\n" + " -s, --server=SERVER The name of the server to connect to\n\n", + argv0); +} + +enum { + ARG_VERSION = 256 +}; + +int main(int argc, char *argv[]) { + pa_mainloop* m = NULL; + int c, ret = 1; + char *server = NULL, *bn; + + static const struct option long_options[] = { + {"server", 1, NULL, 's'}, + {"version", 0, NULL, ARG_VERSION}, + {"help", 0, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + if (!(bn = strrchr(argv[0], '/'))) + bn = argv[0]; + else + bn++; + + while ((c = getopt_long(argc, argv, "s:h", long_options, NULL)) != -1) { + switch (c) { + case 'h' : + help(bn); + ret = 0; + goto quit; + + case ARG_VERSION: + printf("pasuspender "PACKAGE_VERSION"\nCompiled with libpulse %s\nLinked with libpulse %s\n", pa_get_headers_version(), pa_get_library_version()); + ret = 0; + goto quit; + + case 's': + pa_xfree(server); + server = pa_xstrdup(optarg); + break; + + default: + goto quit; + } + } + + child_argv = argv + optind; + child_argc = argc - optind; + + if (child_argc <= 0) { + help(bn); + ret = 0; + goto quit; + } + + if (!(m = pa_mainloop_new())) { + fprintf(stderr, "pa_mainloop_new() failed.\n"); + goto quit; + } + + pa_assert_se(mainloop_api = pa_mainloop_get_api(m)); + pa_assert_se(pa_signal_init(mainloop_api) == 0); + pa_signal_new(SIGINT, sigint_callback, NULL); + pa_signal_new(SIGCHLD, sigchld_callback, NULL); +#ifdef SIGPIPE + signal(SIGPIPE, SIG_IGN); +#endif + + if (!(context = pa_context_new(mainloop_api, bn))) { + fprintf(stderr, "pa_context_new() failed.\n"); + goto quit; + } + + pa_context_set_state_callback(context, context_state_callback, NULL); + pa_context_connect(context, server, PA_CONTEXT_NOAUTOSPAWN, NULL); + + if (pa_mainloop_run(m, &ret) < 0) { + fprintf(stderr, "pa_mainloop_run() failed.\n"); + goto quit; + } + +quit: + if (context) + pa_context_unref(context); + + if (m) { + pa_signal_done(); + pa_mainloop_free(m); + } + + pa_xfree(server); + + if (!dead) + kill(child_pid, SIGTERM); + + return ret == 0 ? child_ret : ret; +} diff --git a/todo b/todo index 7b4ce786..f579bebe 100644 --- a/todo +++ b/todo @@ -4,7 +4,6 @@ Build System: - Remove symdef files and use macros (like most other projects) - Use own name mangling scheme instead of ltdl's, which will eliminate the need for .la files or extra trickery. -- build pulsecore only statically by default, it's not a public API yet Porting: - rtp module ported to Win32 (sendmsg/recvmsg emulation) @@ -13,16 +12,12 @@ I18N: - iconv stuff sent from utils to server (UTF-8) - iconv sample loading in server - Document utf8.h, timeval.h and util.h -- gettextify polypaudio +- gettextify pulseaudio Cleanups: - drop dependency of libpolyp on libX11, instead use an external mini binary -- merge module-oss-mmap into module-oss - module-tunnel: improve latency calculation - use software volume when hardware doesn't support all channels (alsa done) -- silence generation should be moved into the core to avoid races and code - duplication in the backends -- don't read/write audio data from/to ALSA devices if noone is listening - using POSIX monotonous clocks wherever possible instead of gettimeofday() Test: @@ -35,7 +30,6 @@ Auth/Crypto: - sasl auth Features: -- alsa mmap driver - alsa driver with hw mixing - "window manager for sound" - chroot() @@ -52,7 +46,8 @@ Features: - Support for device selection in waveout driver - add an API to libpulse for allocating memory from the pa_context memory pool - allow buffer metric changes during runtime -- "include" command in configuration files. should have glob support. +- better ".include" command in configuration files. should have glob support. +- recursive .if Long term: - pass meta info for hearing impaired -- cgit From c6a7f06e239b58e02c912622d06b72cba3fbc91d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 28 Oct 2007 19:24:25 +0000 Subject: add missing dependency on socket-util git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1972 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index e17e5ece..a827d9f4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1196,7 +1196,7 @@ module_esound_compat_spawnpid_la_LIBADD = $(AM_LIBADD) libpulsecore.la module_esound_sink_la_SOURCES = modules/module-esound-sink.c module_esound_sink_la_LDFLAGS = -module -avoid-version -module_esound_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la libiochannel.la libsocket-client.la libauthkey.la +module_esound_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la libiochannel.la libsocket-client.la libauthkey.la libsocket-util.la # Pipes -- cgit From 1c0690776d45c50b90df037669b4dbfe0467ca8a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 08:34:30 +0000 Subject: make speex-float-3 the default resampler git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1973 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/core.c | 2 +- src/pulsecore/resampler.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index e9008833..e67f15b5 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -132,7 +132,7 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) { c->module_idle_time = 20; c->scache_idle_time = 20; - c->resample_method = PA_RESAMPLER_SPEEX_FLOAT_BASE; + c->resample_method = PA_RESAMPLER_SPEEX_FLOAT_BASE + 3; c->is_system_instance = 0; c->disallow_module_loading = 0; diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index 5bbc6bf4..b4447198 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -195,7 +195,7 @@ pa_resampler* pa_resampler_new( } if (resample_method == PA_RESAMPLER_AUTO) - resample_method = PA_RESAMPLER_SPEEX_FLOAT_BASE + 0; + resample_method = PA_RESAMPLER_SPEEX_FLOAT_BASE + 3; r = pa_xnew(pa_resampler, 1); r->mempool = pool; @@ -439,10 +439,10 @@ pa_resample_method_t pa_parse_resample_method(const char *string) { return m; if (!strcmp(string, "speex-fixed")) - return PA_RESAMPLER_SPEEX_FIXED_BASE + 0; + return PA_RESAMPLER_SPEEX_FIXED_BASE + 3; if (!strcmp(string, "speex-float")) - return PA_RESAMPLER_SPEEX_FLOAT_BASE + 0; + return PA_RESAMPLER_SPEEX_FLOAT_BASE + 3; return PA_RESAMPLER_INVALID; } -- cgit From ca98c544ab7a26bfc840d1470f467a7dea06238c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 15:31:24 +0000 Subject: add new pa_readlink() API git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1974 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/core-util.c | 24 ++++++++++++++++++++++++ src/pulsecore/core-util.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index a644b664..4962112b 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -1507,3 +1507,27 @@ void pa_close_pipe(int fds[2]) { fds[0] = fds[1] = -1; } + +char *pa_readlink(const char *p) { + size_t l = 100; + + for (;;) { + char *c; + ssize_t n; + + c = pa_xnew(char, l); + + if ((n = readlink(p, c, l-1)) < 0) { + pa_xfree(c); + return NULL; + } + + if (n < l-1) { + c[l-1] = 0; + return c; + } + + pa_xfree(c); + l *= 2; + } +} diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index 0fe865ec..d26cf241 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -122,4 +122,6 @@ static inline unsigned pa_make_power_of_two(unsigned n) { void pa_close_pipe(int fds[2]); +char *pa_readlink(const char *p); + #endif -- cgit From 27d6b7b4732f3678ecb6f1e5e53d440f1e8b2547 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 15:32:22 +0000 Subject: make use of new pa_readlink() where applicable git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1975 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/oss-util.c | 32 +++++++++++++++++++++----------- src/pulse/util.c | 11 ++++++----- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index 25e45a35..015db4ca 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -293,29 +293,39 @@ int pa_oss_set_volume(int fd, long mixer, const pa_sample_spec *ss, const pa_cvo } static int get_device_number(const char *dev) { - char buf[PATH_MAX]; const char *p, *e; + char *rp = NULL; + int r; - if (readlink(dev, buf, sizeof(buf)) < 0) { - if (errno != EINVAL && errno != ENOLINK) - return -1; + if (!(p = rp = pa_readlink(dev))) { + if (errno != EINVAL && errno != ENOLINK) { + r = -1; + goto finish; + } p = dev; - } else - p = buf; + } if ((e = strrchr(p, '/'))) p = e+1; - if (p == 0) - return 0; + if (p == 0) { + r = 0; + goto finish; + } p = strchr(p, 0) -1; - if (*p >= '0' && *p <= '9') - return *p - '0'; + if (*p >= '0' && *p <= '9') { + r = *p - '0'; + goto finish; + } - return -1; + r = -1; + +finish: + pa_xfree(rp); + return r; } int pa_oss_get_hw_description(const char *dev, char *name, size_t l) { diff --git a/src/pulse/util.c b/src/pulse/util.c index 5dbb670b..d3ac9f66 100644 --- a/src/pulse/util.c +++ b/src/pulse/util.c @@ -55,6 +55,7 @@ #include #endif +#include #include #include #include @@ -172,13 +173,13 @@ char *pa_get_binary_name(char *s, size_t l) { #ifdef __linux__ { - int i; - char path[PATH_MAX]; + char *rp; /* This works on Linux only */ - if ((i = readlink("/proc/self/exe", path, sizeof(path)-1)) >= 0) { - path[i] = 0; - return pa_strlcpy(s, pa_path_get_filename(path), l); + if ((rp = pa_readlink("/proc/self/exe"))) { + pa_strlcpy(s, pa_path_get_filename(rp), l); + pa_xfree(rp); + return s; } } -- cgit From a46804a8e2ba8aa0e869bcf72015e3b551a7b40d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 15:33:07 +0000 Subject: use real path of binary instead of /proc/self/exe to execute ourselves git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1976 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/daemon/main.c b/src/daemon/main.c index 6c9f6627..cd3cfcc8 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -336,11 +336,14 @@ int main(int argc, char *argv[]) { */ if (!getenv("LD_BIND_NOW")) { - putenv(pa_xstrdup("LD_BIND_NOW=1")); + char *rp; /* We have to execute ourselves, because the libc caches the * value of $LD_BIND_NOW on initialization. */ - pa_assert_se(execv("/proc/self/exe", argv) == 0); + + putenv(pa_xstrdup("LD_BIND_NOW=1")); + pa_assert_se(rp = pa_readlink("/proc/self/exe")); + pa_assert_se(execv(rp, argv) == 0); } #endif -- cgit From 6e1f7bd144d2f5ce8cb5f30772b2ad31652ab213 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 16:38:57 +0000 Subject: properly deal with time pausing git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1977 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/time-smoother.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/pulsecore/time-smoother.c b/src/pulsecore/time-smoother.c index 6bda3df0..4cebded4 100644 --- a/src/pulsecore/time-smoother.c +++ b/src/pulsecore/time-smoother.c @@ -310,8 +310,9 @@ void pa_smoother_put(pa_smoother *s, pa_usec_t x, pa_usec_t y) { /* Fix up x value */ if (s->paused) x = s->pause_time; - else - x -= s->time_offset; + + pa_assert(x >= s->time_offset); + x -= s->time_offset; pa_assert(x >= s->ex); @@ -342,8 +343,9 @@ pa_usec_t pa_smoother_get(pa_smoother *s, pa_usec_t x) { /* Fix up x value */ if (s->paused) x = s->pause_time; - else - x -= s->time_offset; + + pa_assert(x >= s->time_offset); + x -= s->time_offset; pa_assert(x >= s->ex); @@ -373,6 +375,8 @@ void pa_smoother_resume(pa_smoother *s, pa_usec_t x) { if (!s->paused) return; + pa_assert(x >= s->pause_time); + s->paused = FALSE; s->time_offset += x - s->pause_time; } -- cgit From 9ccbd86f8259c6603e5e3ff5a99c4b5d5a51a6c6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 16:39:23 +0000 Subject: downgrade a few log messages git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1978 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-esound-sink.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index 8b46637e..b60e15d7 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -362,7 +362,7 @@ static int do_write(struct userdata *u) { pa_make_tcp_socket_low_delay(u->fd); - pa_log_info("Connection authenticated, handing fd to IO thread..."); + pa_log_debug("Connection authenticated, handing fd to IO thread..."); pa_asyncmsgq_post(u->thread_mq.inq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_PASS_SOCKET, NULL, 0, NULL, NULL); u->state = STATE_RUNNING; @@ -496,7 +496,7 @@ static void on_connection(PA_GCC_UNUSED pa_socket_client *c, pa_iochannel*io, vo u->io = io; pa_iochannel_set_callback(u->io, io_callback, u); - pa_log_info("Connection established, authenticating ..."); + pa_log_debug("Connection established, authenticating ..."); } int pa__init(pa_module*m) { @@ -553,7 +553,7 @@ int pa__init(pa_module*m) { u->latency = 0; if (!(u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { - pa_log("failed to create sink."); + pa_log("Failed to create sink."); goto fail; } -- cgit From ac8363144777ec60cba979666e7195205fe96c97 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 16:54:16 +0000 Subject: bring back module-tunnel, yay! git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1979 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 20 +- src/modules/module-tunnel.c | 977 ++++++++++++++++++++++++++------------------ 2 files changed, 599 insertions(+), 398 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index a827d9f4..911bd7b6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -955,9 +955,9 @@ modlibexec_LTLIBRARIES += \ module-combine.la \ module-remap-sink.la \ module-ladspa-sink.la \ - module-esound-sink.la -# module-tunnel-sink.la -# module-tunnel-source.la + module-esound-sink.la \ + module-tunnel-sink.la \ + module-tunnel-source.la # See comment at librtp.la above if !OS_IS_WIN32 @@ -1237,14 +1237,14 @@ module_match_la_SOURCES = modules/module-match.c module_match_la_LDFLAGS = -module -avoid-version module_match_la_LIBADD = $(AM_LIBADD) libpulsecore.la -#module_tunnel_sink_la_SOURCES = modules/module-tunnel.c -#module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS) -#module_tunnel_sink_la_LDFLAGS = -module -avoid-version -#module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la +module_tunnel_sink_la_SOURCES = modules/module-tunnel.c +module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS) +module_tunnel_sink_la_LDFLAGS = -module -avoid-version +module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la -#module_tunnel_source_la_SOURCES = modules/module-tunnel.c -#module_tunnel_source_la_LDFLAGS = -module -avoid-version -#module_tunnel_source_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la +module_tunnel_source_la_SOURCES = modules/module-tunnel.c +module_tunnel_source_la_LDFLAGS = -module -avoid-version +module_tunnel_source_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la # X11 diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index b96d46b3..1682007a 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -27,7 +27,6 @@ #endif #include -#include #include #include #include @@ -52,6 +51,11 @@ #include #include #include +#include +#include +#include +#include +#include #ifdef TUNNEL_SINK #include "module-tunnel-sink-symdef.h" @@ -82,11 +86,10 @@ PA_MODULE_USAGE( PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_VERSION(PACKAGE_VERSION) -#define DEFAULT_TLENGTH (44100*2*2/10) //(10240*8) -#define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2) -#define DEFAULT_MINREQ 512 -#define DEFAULT_PREBUF (DEFAULT_TLENGTH-DEFAULT_MINREQ) -#define DEFAULT_FRAGSIZE 1024 +#define DEFAULT_TLENGTH_MSEC 100 +#define DEFAULT_MINREQ_MSEC 10 +#define DEFAULT_MAXLENGTH_MSEC ((DEFAULT_TLENGTH_MSEC*3)/2) +#define DEFAULT_FRAGSIZE_MSEC 10 #define DEFAULT_TIMEOUT 5 @@ -109,23 +112,42 @@ static const char* const valid_modargs[] = { NULL, }; -static void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +enum { + SOURCE_MESSAGE_POST = PA_SOURCE_MESSAGE_MAX +}; + +enum { + SINK_MESSAGE_REQUEST = PA_SINK_MESSAGE_MAX, + SINK_MESSAGE_POST +}; #ifdef TUNNEL_SINK static void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); #endif +static void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_overflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { #ifdef TUNNEL_SINK [PA_COMMAND_REQUEST] = command_request, + [PA_COMMAND_SUBSCRIBE_EVENT] = command_subscribe_event, #endif + [PA_COMMAND_OVERFLOW] = command_overflow, + [PA_COMMAND_UNDERFLOW] = command_underflow, [PA_COMMAND_PLAYBACK_STREAM_KILLED] = command_stream_killed, [PA_COMMAND_RECORD_STREAM_KILLED] = command_stream_killed, - [PA_COMMAND_SUBSCRIBE_EVENT] = command_subscribe_event, }; struct userdata { + pa_core *core; + pa_module *module; + + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; + pa_thread *thread; + pa_socket_client *client; pa_pstream *pstream; pa_pdispatch *pdispatch; @@ -140,9 +162,6 @@ struct userdata { pa_source *source; #endif - pa_module *module; - pa_core *core; - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; uint32_t version; @@ -150,174 +169,284 @@ struct userdata { uint32_t device_index; uint32_t channel; - pa_usec_t host_latency; + int64_t counter, counter_delta; pa_time_event *time_event; - int auth_cookie_in_property; -}; - -static void close_stuff(struct userdata *u) { - assert(u); - - if (u->pstream) { - pa_pstream_close(u->pstream); - pa_pstream_unref(u->pstream); - u->pstream = NULL; - } - - if (u->pdispatch) { - pa_pdispatch_unref(u->pdispatch); - u->pdispatch = NULL; - } + pa_bool_t auth_cookie_in_property; - if (u->client) { - pa_socket_client_unref(u->client); - u->client = NULL; - } + pa_smoother *smoother; + uint32_t maxlength; #ifdef TUNNEL_SINK - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - u->sink = NULL; - } + uint32_t tlength; + uint32_t minreq; + uint32_t prebuf; #else - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - u->source = NULL; - } + uint32_t fragsize; #endif +}; - if (u->time_event) { - u->core->mainloop->time_free(u->time_event); - u->time_event = NULL; - } -} +static void command_stream_killed(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + + pa_assert(pd); + pa_assert(t); + pa_assert(u); + pa_assert(u->pdispatch == pd); -static void die(struct userdata *u) { - assert(u); - close_stuff(u); + pa_log_warn("Stream killed"); pa_module_unload_request(u->module); } -static void command_stream_killed(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_overflow(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; - assert(pd && t && u && u->pdispatch == pd); - pa_log("stream killed"); - die(u); -} + pa_assert(pd); + pa_assert(t); + pa_assert(u); + pa_assert(u->pdispatch == pd); -static void request_info(struct userdata *u); + pa_log_warn("Server signalled buffer overrun."); +} -static void command_subscribe_event(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_underflow(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; - pa_subscription_event_type_t e; - uint32_t idx; - - assert(pd && t && u); - assert(command == PA_COMMAND_SUBSCRIBE_EVENT); - - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { - pa_log("invalid protocol reply"); - die(u); - return; - } -#ifdef TUNNEL_SINK - if (e != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE)) - return; -#else - if (e != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE)) - return; -#endif + pa_assert(pd); + pa_assert(t); + pa_assert(u); + pa_assert(u->pdispatch == pd); - request_info(u); + pa_log_warn("Server signalled buffer underrun."); } -#ifdef TUNNEL_SINK -static void send_prebuf_request(struct userdata *u) { +static void stream_cork(struct userdata *u, pa_bool_t cork) { pa_tagstruct *t; + pa_assert(u); + + if (cork) + pa_smoother_pause(u->smoother, pa_rtclock_usec()); + else + pa_smoother_resume(u->smoother, pa_rtclock_usec()); t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_PREBUF_PLAYBACK_STREAM); +#ifdef TUNNEL_SINK + pa_tagstruct_putu32(t, PA_COMMAND_CORK_PLAYBACK_STREAM); +#else + pa_tagstruct_putu32(t, PA_COMMAND_CORK_RECORD_STREAM); +#endif pa_tagstruct_putu32(t, u->ctag++); pa_tagstruct_putu32(t, u->channel); + pa_tagstruct_put_boolean(t, !!cork); pa_pstream_send_tagstruct(u->pstream, t); } -static void send_bytes(struct userdata *u) { - assert(u); +#ifdef TUNNEL_SINK - if (!u->pstream) - return; +static void send_data(struct userdata *u) { + pa_assert(u); while (u->requested_bytes > 0) { - pa_memchunk chunk; - if (pa_sink_render(u->sink, u->requested_bytes, &chunk) < 0) { + pa_memchunk memchunk; + pa_sink_render(u->sink, u->requested_bytes, &memchunk); + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_POST, NULL, 0, &memchunk, NULL); + pa_memblock_unref(memchunk.memblock); + u->requested_bytes -= memchunk.length; + } +} + +/* This function is called from IO context -- except when it is not. */ +static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SINK(o)->userdata; + + switch (code) { - if (u->requested_bytes >= DEFAULT_TLENGTH-DEFAULT_PREBUF) - send_prebuf_request(u); + case PA_SINK_MESSAGE_SET_STATE: { + int r; - return; + /* First, change the state, because otherwide pa_sink_render() would fail */ + if ((r = pa_sink_process_msg(o, code, data, offset, chunk)) >= 0) + if (PA_SINK_OPENED((pa_sink_state_t) PA_PTR_TO_UINT(data))) + send_data(u); + + return r; } - pa_pstream_send_memblock(u->pstream, u->channel, 0, PA_SEEK_RELATIVE, &chunk); - pa_memblock_unref(chunk.memblock); + case SINK_MESSAGE_REQUEST: -/* pa_log("sent %lu", (unsigned long) chunk.length); */ + pa_assert(offset > 0); + u->requested_bytes += (size_t) offset; - if (chunk.length > u->requested_bytes) - u->requested_bytes = 0; - else - u->requested_bytes -= chunk.length; + if (PA_SINK_OPENED(u->sink->thread_info.state)) + send_data(u); + + return 0; + + case SINK_MESSAGE_POST: + + /* OK, This might be a bit confusing. This message is + * delivered to us from the main context -- NOT from the + * IO thread context where the rest of the messages are + * dispatched. Yeah, ugly, but I am a lazy bastard. */ + + pa_pstream_send_memblock(u->pstream, u->channel, 0, PA_SEEK_RELATIVE, chunk); + u->counter += chunk->length; + u->counter_delta += chunk->length; + return 0; + } + + return pa_sink_process_msg(o, code, data, offset, chunk); +} + +static int sink_set_state(pa_sink *s, pa_sink_state_t state) { + struct userdata *u; + pa_sink_assert_ref(s); + u = s->userdata; + + switch ((pa_sink_state_t) state) { + + case PA_SINK_SUSPENDED: + pa_assert(PA_SINK_OPENED(s->state)); + stream_cork(u, TRUE); + break; + + case PA_SINK_IDLE: + case PA_SINK_RUNNING: + if (s->state == PA_SINK_SUSPENDED) + stream_cork(u, FALSE); + break; + + case PA_SINK_UNLINKED: + case PA_SINK_INIT: + ; } + + return 0; +} + +#else + +static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SOURCE(o)->userdata; + + switch (code) { + case SOURCE_MESSAGE_POST: + + if (PA_SOURCE_OPENED(u->source->thread_info.state)) + pa_source_post(u->source, chunk); + return 0; + } + + return pa_source_process_msg(o, code, data, offset, chunk); } +static int source_set_state(pa_source *s, pa_source_state_t state) { + struct userdata *u; + pa_source_assert_ref(s); + u = s->userdata; + + switch ((pa_source_state_t) state) { + + case PA_SOURCE_SUSPENDED: + pa_assert(PA_SOURCE_OPENED(s->state)); + stream_cork(u, TRUE); + break; + + case PA_SOURCE_IDLE: + case PA_SOURCE_RUNNING: + if (s->state == PA_SOURCE_SUSPENDED) + stream_cork(u, FALSE); + break; + + case PA_SOURCE_UNLINKED: + case PA_SOURCE_INIT: + ; + } + + return 0; +} + +#endif + +static void thread_func(void *userdata) { + struct userdata *u = userdata; + + pa_assert(u); + + pa_log_debug("Thread starting up"); + + pa_thread_mq_install(&u->thread_mq); + pa_rtpoll_install(u->rtpoll); + + for (;;) { + int ret; + + if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0) + goto fail; + + if (ret == 0) + goto finish; + } + +fail: + /* If this was no regular exit from the loop we have to continue + * processing messages until we received PA_MESSAGE_SHUTDOWN */ + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); + +finish: + pa_log_debug("Thread shutting down"); +} + +#ifdef TUNNEL_SINK static void command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && u && u->pdispatch == pd); + + pa_assert(pd); + pa_assert(command == PA_COMMAND_REQUEST); + pa_assert(t); + pa_assert(u); + pa_assert(u->pdispatch == pd); if (pa_tagstruct_getu32(t, &channel) < 0 || pa_tagstruct_getu32(t, &bytes) < 0 || !pa_tagstruct_eof(t)) { - pa_log("invalid protocol reply"); - die(u); - return; + pa_log("Invalid protocol reply"); + goto fail; } if (channel != u->channel) { - pa_log("recieved data for invalid channel"); - die(u); - return; + pa_log("Recieved data for invalid channel"); + goto fail; } - u->requested_bytes += bytes; - send_bytes(u); + pa_asyncmsgq_send(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_REQUEST, NULL, bytes, NULL); + return; + +fail: + pa_module_unload_request(u->module); } #endif static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; - pa_usec_t sink_usec, source_usec, transport_usec; + pa_usec_t sink_usec, source_usec, transport_usec, host_usec, k; int playing; int64_t write_index, read_index; struct timeval local, remote, now; - assert(pd && u); + + pa_assert(pd); + pa_assert(u); if (command != PA_COMMAND_REPLY) { if (command == PA_COMMAND_ERROR) - pa_log("failed to get latency."); + pa_log("Failed to get latency."); else - pa_log("protocol error."); - die(u); - return; + pa_log("Protocol error."); + goto fail; } if (pa_tagstruct_get_usec(t, &sink_usec) < 0 || @@ -328,15 +457,12 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G pa_tagstruct_gets64(t, &write_index) < 0 || pa_tagstruct_gets64(t, &read_index) < 0 || !pa_tagstruct_eof(t)) { - pa_log("invalid reply. (latency)"); - die(u); - return; + pa_log("Invalid reply. (latency)"); + goto fail; } pa_gettimeofday(&now); - /* FIXME! This could use some serious love. */ - if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) { /* local and remote seem to have synchronized clocks */ #ifdef TUNNEL_SINK @@ -348,23 +474,40 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G transport_usec = pa_timeval_diff(&now, &local)/2; #ifdef TUNNEL_SINK - u->host_latency = sink_usec + transport_usec; + host_usec = sink_usec + transport_usec; #else - u->host_latency = source_usec + transport_usec; - if (u->host_latency > sink_usec) - u->host_latency -= sink_usec; + host_usec = source_usec + transport_usec; + if (host_usec > sink_usec) + host_usec -= sink_usec; + else + host_usec = 0; +#endif + +#ifdef TUNNEL_SINK + k = pa_bytes_to_usec(u->counter - u->counter_delta, &u->sink->sample_spec); + + if (k > host_usec) + k -= host_usec; else - u->host_latency = 0; + k = 0; +#else + k = pa_bytes_to_usec(u->counter - u->counter_delta, &u->source->sample_spec); + k += host_usec; #endif -/* pa_log("estimated host latency: %0.0f usec", (double) u->host_latency); */ + pa_smoother_put(u->smoother, pa_rtclock_usec(), k); + + return; + +fail: + pa_module_unload_request(u->module); } static void request_latency(struct userdata *u) { pa_tagstruct *t; struct timeval now; uint32_t tag; - assert(u); + pa_assert(u); t = pa_tagstruct_new(NULL, 0); #ifdef TUNNEL_SINK @@ -380,149 +523,183 @@ static void request_latency(struct userdata *u) { pa_pstream_send_tagstruct(u->pstream, t); pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u, NULL); + + u->counter_delta = 0; } -static void stream_get_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { +static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { struct userdata *u = userdata; - uint32_t idx, owner_module, monitor_source; - pa_usec_t latency; - const char *name, *description, *monitor_source_name, *driver; + struct timeval ntv; + + pa_assert(m); + pa_assert(e); + pa_assert(u); + + request_latency(u); + + pa_gettimeofday(&ntv); + ntv.tv_sec += LATENCY_INTERVAL; + m->time_restart(e, &ntv); +} + +#ifdef TUNNEL_SINK +static pa_usec_t sink_get_latency(pa_sink *s) { + pa_usec_t t, c; + struct userdata *u = s->userdata; + + pa_sink_assert_ref(s); + + c = pa_bytes_to_usec(u->counter, &s->sample_spec); + t = pa_smoother_get(u->smoother, pa_rtclock_usec()); + + return c > t ? c - t : 0; +} +#else +static pa_usec_t source_get_latency(pa_source *s) { + pa_usec_t t, c; + struct userdata *u = s->userdata; + + pa_source_assert_ref(s); + + c = pa_bytes_to_usec(u->counter, &s->sample_spec); + t = pa_smoother_get(u->smoother, pa_rtclock_usec()); + + return t > c ? t - c : 0; +} +#endif + +#ifdef TUNNEL_SINK + +static void sink_input_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + uint32_t idx, owner_module, client, sink; + pa_usec_t buffer_usec, sink_usec; + const char *name, *driver, *resample_method; int mute; - uint32_t flags; pa_sample_spec sample_spec; pa_channel_map channel_map; pa_cvolume volume; - assert(pd && u); + + pa_assert(pd); + pa_assert(u); if (command != PA_COMMAND_REPLY) { if (command == PA_COMMAND_ERROR) - pa_log("failed to get info."); + pa_log("Failed to get info."); else - pa_log("protocol error."); - die(u); - return; + pa_log("Protocol error."); + goto fail; } if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_gets(t, &name) < 0 || - pa_tagstruct_gets(t, &description) < 0 || + pa_tagstruct_getu32(t, &owner_module) < 0 || + pa_tagstruct_getu32(t, &client) < 0 || + pa_tagstruct_getu32(t, &sink) < 0 || pa_tagstruct_get_sample_spec(t, &sample_spec) < 0 || pa_tagstruct_get_channel_map(t, &channel_map) < 0 || - pa_tagstruct_getu32(t, &owner_module) < 0 || pa_tagstruct_get_cvolume(t, &volume) < 0 || - pa_tagstruct_get_boolean(t, &mute) < 0 || - pa_tagstruct_getu32(t, &monitor_source) < 0 || - pa_tagstruct_gets(t, &monitor_source_name) < 0 || - pa_tagstruct_get_usec(t, &latency) < 0 || + pa_tagstruct_get_usec(t, &buffer_usec) < 0 || + pa_tagstruct_get_usec(t, &sink_usec) < 0 || + pa_tagstruct_gets(t, &resample_method) < 0 || pa_tagstruct_gets(t, &driver) < 0 || - pa_tagstruct_getu32(t, &flags) < 0 || + (u->version >= 11 && pa_tagstruct_get_boolean(t, &mute) < 0) || !pa_tagstruct_eof(t)) { - pa_log("invalid reply. (get_info)"); - die(u); - return; + pa_log("Invalid reply. (get_info)"); + goto fail; } -#ifdef TUNNEL_SINK - assert(u->sink); - if ((!!mute == !!u->sink->hw_muted) && - pa_cvolume_equal(&volume, &u->sink->hw_volume)) - return; -#else - assert(u->source); - if ((!!mute == !!u->source->hw_muted) && - pa_cvolume_equal(&volume, &u->source->hw_volume)) + pa_assert(u->sink); + + if ((u->version < 11 || !!mute == !!u->sink->muted) && + pa_cvolume_equal(&volume, &u->sink->volume)) return; -#endif -#ifdef TUNNEL_SINK - memcpy(&u->sink->hw_volume, &volume, sizeof(pa_cvolume)); - u->sink->hw_muted = !!mute; + memcpy(&u->sink->volume, &volume, sizeof(pa_cvolume)); - pa_subscription_post(u->sink->core, - PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, - u->sink->index); -#else - memcpy(&u->source->hw_volume, &volume, sizeof(pa_cvolume)); - u->source->hw_muted = !!mute; + if (u->version >= 11) + u->sink->muted = !!mute; - pa_subscription_post(u->source->core, - PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, - u->source->index); -#endif + pa_subscription_post(u->sink->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, u->sink->index); + return; + +fail: + pa_module_unload_request(u->module); } static void request_info(struct userdata *u) { pa_tagstruct *t; uint32_t tag; - assert(u); + pa_assert(u); t = pa_tagstruct_new(NULL, 0); -#ifdef TUNNEL_SINK - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); -#else - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); -#endif + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INPUT_INFO); pa_tagstruct_putu32(t, tag = u->ctag++); + pa_tagstruct_putu32(t, u->device_index); + pa_pstream_send_tagstruct(u->pstream, t); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, sink_input_info_cb, u, NULL); +} - pa_tagstruct_putu32(t, PA_INVALID_INDEX); -#ifdef TUNNEL_SINK - pa_tagstruct_puts(t, u->sink_name); -#else - pa_tagstruct_puts(t, u->source_name); -#endif +static void command_subscribe_event(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + pa_subscription_event_type_t e; + uint32_t idx; - pa_pstream_send_tagstruct(u->pstream, t); - pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_info_callback, u, NULL); + pa_assert(pd); + pa_assert(t); + pa_assert(u); + pa_assert(command == PA_COMMAND_SUBSCRIBE_EVENT); + + if (pa_tagstruct_getu32(t, &e) < 0 || + pa_tagstruct_getu32(t, &idx) < 0 || + !pa_tagstruct_eof(t)) { + pa_log("Invalid protocol reply"); + pa_module_unload_request(u->module); + return; + } + + if (e != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE)) + return; + + request_info(u); } static void start_subscribe(struct userdata *u) { pa_tagstruct *t; uint32_t tag; - assert(u); + pa_assert(u); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); pa_tagstruct_putu32(t, tag = u->ctag++); - -#ifdef TUNNEL_SINK - pa_tagstruct_putu32(t, PA_SUBSCRIPTION_MASK_SINK); -#else - pa_tagstruct_putu32(t, PA_SUBSCRIPTION_MASK_SOURCE); -#endif - + pa_tagstruct_putu32(t, PA_SUBSCRIPTION_MASK_SINK_INPUT); pa_pstream_send_tagstruct(u->pstream, t); } - -static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - struct userdata *u = userdata; - struct timeval ntv; - assert(m && e && u); - - request_latency(u); - - pa_gettimeofday(&ntv); - ntv.tv_sec += LATENCY_INTERVAL; - m->time_restart(e, &ntv); -} +#endif static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; struct timeval ntv; - assert(pd && u && u->pdispatch == pd); +#ifdef TUNNEL_SINK + uint32_t bytes; +#endif + + pa_assert(pd); + pa_assert(u); + pa_assert(u->pdispatch == pd); if (command != PA_COMMAND_REPLY) { if (command == PA_COMMAND_ERROR) - pa_log("failed to create stream."); + pa_log("Failed to create stream."); else - pa_log("protocol error."); - die(u); - return; + pa_log("Protocol error."); + goto fail; } if (pa_tagstruct_getu32(t, &u->channel) < 0 || pa_tagstruct_getu32(t, &u->device_index) < 0 #ifdef TUNNEL_SINK - || pa_tagstruct_getu32(t, &u->requested_bytes) < 0 + || pa_tagstruct_getu32(t, &bytes) < 0 #endif ) goto parse_error; @@ -548,24 +725,31 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN if (!pa_tagstruct_eof(t)) goto parse_error; +#ifdef TUNNEL_SINK start_subscribe(u); request_info(u); +#endif - assert(!u->time_event); + pa_assert(!u->time_event); pa_gettimeofday(&ntv); ntv.tv_sec += LATENCY_INTERVAL; u->time_event = u->core->mainloop->time_new(u->core->mainloop, &ntv, timeout_callback, u); request_latency(u); + + pa_log_debug("Stream created."); + #ifdef TUNNEL_SINK - send_bytes(u); + pa_asyncmsgq_post(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_REQUEST, NULL, bytes, NULL, NULL); #endif return; parse_error: - pa_log("invalid reply. (create stream)"); - die(u); + pa_log("Invalid reply. (Create stream)"); + +fail: + pa_module_unload_request(u->module); } static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -575,24 +759,26 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t #ifdef TUNNEL_SINK pa_cvolume volume; #endif - assert(pd && u && u->pdispatch == pd); + + pa_assert(pd); + pa_assert(u); + pa_assert(u->pdispatch == pd); if (command != PA_COMMAND_REPLY || pa_tagstruct_getu32(t, &u->version) < 0 || !pa_tagstruct_eof(t)) { if (command == PA_COMMAND_ERROR) - pa_log("failed to authenticate"); + pa_log("Failed to authenticate"); else - pa_log("protocol error."); - die(u); - return; + pa_log("Protocol error."); + + goto fail; } /* Minimum supported protocol version */ if (u->version < 8) { - pa_log("incompatible protocol version"); - die(u); - return; + pa_log("Incompatible protocol version"); + goto fail; } #ifdef TUNNEL_SINK @@ -615,6 +801,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t /* We ignore the server's reply here */ reply = pa_tagstruct_new(NULL, 0); + #ifdef TUNNEL_SINK pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_PLAYBACK_STREAM); pa_tagstruct_putu32(reply, tag = u->ctag++); @@ -623,11 +810,11 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_tagstruct_put_channel_map(reply, &u->sink->channel_map); pa_tagstruct_putu32(reply, PA_INVALID_INDEX); pa_tagstruct_puts(reply, u->sink_name); - pa_tagstruct_putu32(reply, DEFAULT_MAXLENGTH); - pa_tagstruct_put_boolean(reply, 0); - pa_tagstruct_putu32(reply, DEFAULT_TLENGTH); - pa_tagstruct_putu32(reply, DEFAULT_PREBUF); - pa_tagstruct_putu32(reply, DEFAULT_MINREQ); + pa_tagstruct_putu32(reply, u->maxlength); + pa_tagstruct_put_boolean(reply, FALSE); + pa_tagstruct_putu32(reply, u->tlength); + pa_tagstruct_putu32(reply, u->prebuf); + pa_tagstruct_putu32(reply, u->minreq); pa_tagstruct_putu32(reply, 0); pa_cvolume_reset(&volume, u->sink->sample_spec.channels); pa_tagstruct_put_cvolume(reply, &volume); @@ -639,59 +826,82 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_tagstruct_put_channel_map(reply, &u->source->channel_map); pa_tagstruct_putu32(reply, PA_INVALID_INDEX); pa_tagstruct_puts(reply, u->source_name); - pa_tagstruct_putu32(reply, DEFAULT_MAXLENGTH); + pa_tagstruct_putu32(reply, u->maxlength); pa_tagstruct_put_boolean(reply, 0); - pa_tagstruct_putu32(reply, DEFAULT_FRAGSIZE); + pa_tagstruct_putu32(reply, u->fragsize); #endif pa_pstream_send_tagstruct(u->pstream, reply); pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, u, NULL); + + pa_log_debug("Connection authenticated, creating stream ..."); + + return; + +fail: + pa_module_unload_request(u->module); } static void pstream_die_callback(pa_pstream *p, void *userdata) { struct userdata *u = userdata; - assert(p && u); - pa_log("stream died."); - die(u); + pa_assert(p); + pa_assert(u); + + pa_log_warn("Stream died."); + pa_module_unload_request(u->module); } static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) { struct userdata *u = userdata; - assert(p && packet && u); + + pa_assert(p); + pa_assert(packet); + pa_assert(u); if (pa_pdispatch_run(u->pdispatch, packet, creds, u) < 0) { - pa_log("invalid packet"); - die(u); + pa_log("Invalid packet"); + pa_module_unload_request(u->module); + return; } } #ifndef TUNNEL_SINK -static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, PA_GCC_UNUSED int64_t offset, PA_GCC_UNUSED pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { +static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { struct userdata *u = userdata; - assert(p && chunk && u); + + pa_assert(p); + pa_assert(chunk); + pa_assert(u); if (channel != u->channel) { - pa_log("recieved memory block on bad channel."); - die(u); + pa_log("Recieved memory block on bad channel."); + pa_module_unload_request(u->module); return; } - pa_source_post(u->source, chunk); + pa_asyncmsgq_send(u->source->asyncmsgq, PA_MSGOBJECT(u->source), SOURCE_MESSAGE_POST, PA_UINT_TO_PTR(seek), offset, chunk); + + u->counter += chunk->length; + u->counter_delta += chunk->length; } + #endif static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata) { struct userdata *u = userdata; pa_tagstruct *t; uint32_t tag; - assert(sc && u && u->client == sc); + + pa_assert(sc); + pa_assert(u); + pa_assert(u->client == sc); pa_socket_client_unref(u->client); u->client = NULL; if (!io) { - pa_log("connection failed."); + pa_log("Connection failed: %s", pa_cstrerror(errno)); pa_module_unload_request(u->module); return; } @@ -710,161 +920,85 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata pa_tagstruct_putu32(t, tag = u->ctag++); pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION); pa_tagstruct_put_arbitrary(t, u->auth_cookie, sizeof(u->auth_cookie)); - pa_pstream_send_tagstruct(u->pstream, t); - pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, u, NULL); - -} - -#ifdef TUNNEL_SINK -static void sink_notify(pa_sink*sink) { - struct userdata *u; - assert(sink && sink->userdata); - u = sink->userdata; - - send_bytes(u); -} - -static pa_usec_t sink_get_latency(pa_sink *sink) { - struct userdata *u; - uint32_t l; - pa_usec_t usec = 0; - assert(sink && sink->userdata); - u = sink->userdata; - l = DEFAULT_TLENGTH; +#ifdef HAVE_CREDS +{ + pa_creds ucred; - if (l > u->requested_bytes) { - l -= u->requested_bytes; - usec += pa_bytes_to_usec(l, &u->sink->sample_spec); - } + if (pa_iochannel_creds_supported(io)) + pa_iochannel_creds_enable(io); - usec += u->host_latency; + ucred.uid = getuid(); + ucred.gid = getgid(); - return usec; + pa_pstream_send_tagstruct_with_creds(u->pstream, t, &ucred); } - -static int sink_get_hw_volume(pa_sink *sink) { - struct userdata *u; - assert(sink && sink->userdata); - u = sink->userdata; - - return 0; -} - -static int sink_set_hw_volume(pa_sink *sink) { - struct userdata *u; - pa_tagstruct *t; - uint32_t tag; - assert(sink && sink->userdata); - u = sink->userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); - pa_tagstruct_putu32(t, tag = u->ctag++); - - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, u->sink_name); - pa_tagstruct_put_cvolume(t, &sink->hw_volume); +#else pa_pstream_send_tagstruct(u->pstream, t); +#endif - return 0; + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, u, NULL); + + pa_log_debug("Connection established, authenticating ..."); } -static int sink_get_hw_mute(pa_sink *sink) { - struct userdata *u; - assert(sink && sink->userdata); - u = sink->userdata; +#ifdef TUNNEL_SINK +static int sink_get_volume(pa_sink *sink) { return 0; } -static int sink_set_hw_mute(pa_sink *sink) { +static int sink_set_volume(pa_sink *sink) { struct userdata *u; pa_tagstruct *t; uint32_t tag; - assert(sink && sink->userdata); + + pa_assert(sink); u = sink->userdata; + pa_assert(u); t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_MUTE); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME); pa_tagstruct_putu32(t, tag = u->ctag++); - - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, u->sink_name); - pa_tagstruct_put_boolean(t, !!sink->hw_muted); + pa_tagstruct_putu32(t, u->device_index); + pa_tagstruct_put_cvolume(t, &sink->volume); pa_pstream_send_tagstruct(u->pstream, t); return 0; } -#else -static pa_usec_t source_get_latency(pa_source *source) { - struct userdata *u; - assert(source && source->userdata); - u = source->userdata; - - return u->host_latency; -} - -static int source_get_hw_volume(pa_source *source) { - struct userdata *u; - assert(source && source->userdata); - u = source->userdata; - +static int sink_get_mute(pa_sink *sink) { return 0; } -static int source_set_hw_volume(pa_source *source) { +static int sink_set_mute(pa_sink *sink) { struct userdata *u; pa_tagstruct *t; uint32_t tag; - assert(source && source->userdata); - u = source->userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_SOURCE_VOLUME); - pa_tagstruct_putu32(t, tag = u->ctag++); - - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, u->source_name); - pa_tagstruct_put_cvolume(t, &source->hw_volume); - pa_pstream_send_tagstruct(u->pstream, t); - - return 0; -} -static int source_get_hw_mute(pa_source *source) { - struct userdata *u; - assert(source && source->userdata); - u = source->userdata; - - return 0; -} + pa_assert(sink); + u = sink->userdata; + pa_assert(u); -static int source_set_hw_mute(pa_source *source) { - struct userdata *u; - pa_tagstruct *t; - uint32_t tag; - assert(source && source->userdata); - u = source->userdata; + if (u->version < 11) + return -1; t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_SOURCE_MUTE); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_MUTE); pa_tagstruct_putu32(t, tag = u->ctag++); - - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, u->source_name); - pa_tagstruct_put_boolean(t, !!source->hw_muted); + pa_tagstruct_putu32(t, u->device_index); + pa_tagstruct_put_boolean(t, !!sink->muted); pa_pstream_send_tagstruct(u->pstream, t); return 0; } + #endif static int load_key(struct userdata *u, const char*fn) { - assert(u); + pa_assert(u); - u->auth_cookie_in_property = 0; + u->auth_cookie_in_property = FALSE; if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { pa_log_debug("using already loaded auth cookie."); @@ -882,29 +1016,29 @@ static int load_key(struct userdata *u, const char*fn) { pa_log_debug("loading cookie from disk."); if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) - u->auth_cookie_in_property = 1; + u->auth_cookie_in_property = TRUE; return 0; } -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { pa_modargs *ma = NULL; struct userdata *u = NULL; pa_sample_spec ss; pa_channel_map map; char *t, *dn = NULL; - assert(c && m); + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("failed to parse module arguments"); goto fail; } - u = pa_xmalloc(sizeof(struct userdata)); + u = pa_xnew(struct userdata, 1); m->userdata = u; u->module = m; - u->core = c; + u->core = m->core; u->client = NULL; u->pdispatch = NULL; u->pstream = NULL; @@ -917,12 +1051,16 @@ int pa__init(pa_core *c, pa_module*m) { u->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));; u->source = NULL; #endif + u->smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC*2, TRUE); u->ctag = 1; u->device_index = u->channel = PA_INVALID_INDEX; - u->host_latency = 0; - u->auth_cookie_in_property = 0; + u->auth_cookie_in_property = FALSE; u->time_event = NULL; + pa_thread_mq_init(&u->thread_mq, m->core->mainloop); + u->rtpoll = pa_rtpoll_new(); + pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq); + if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0) goto fail; @@ -931,20 +1069,17 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - ss = c->default_sample_spec; + ss = m->core->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { pa_log("invalid sample format specification"); goto fail; } - if (!(u->client = pa_socket_client_new_string(c->mainloop, u->server_name, PA_NATIVE_DEFAULT_PORT))) { + if (!(u->client = pa_socket_client_new_string(m->core->mainloop, u->server_name, PA_NATIVE_DEFAULT_PORT))) { pa_log("failed to connect to server '%s'", u->server_name); goto fail; } - if (!u->client) - goto fail; - pa_socket_client_set_callback(u->client, on_connection, u); #ifdef TUNNEL_SINK @@ -952,55 +1087,81 @@ int pa__init(pa_core *c, pa_module*m) { if (!(dn = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", NULL)))) dn = pa_sprintf_malloc("tunnel.%s", u->server_name); - if (!(u->sink = pa_sink_new(c, __FILE__, dn, 0, &ss, &map))) { - pa_log("failed to create sink."); + if (!(u->sink = pa_sink_new(m->core, __FILE__, dn, 0, &ss, &map))) { + pa_log("Failed to create sink."); goto fail; } - u->sink->get_latency = sink_get_latency; - u->sink->get_hw_volume = sink_get_hw_volume; - u->sink->set_hw_volume = sink_set_hw_volume; - u->sink->get_hw_mute = sink_get_hw_mute; - u->sink->set_hw_mute = sink_set_hw_mute; - u->sink->notify = sink_notify; + u->sink->parent.process_msg = sink_process_msg; u->sink->userdata = u; + u->sink->set_state = sink_set_state; + u->sink->get_latency = sink_get_latency; + u->sink->get_volume = sink_get_volume; + u->sink->get_mute = sink_get_mute; + u->sink->set_volume = sink_set_volume; + u->sink->set_mute = sink_set_mute; + + pa_sink_set_module(u->sink, m); + pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); + pa_sink_set_rtpoll(u->sink, u->rtpoll); pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Tunnel to %s%s%s", u->sink_name ? u->sink_name : "", u->sink_name ? " on " : "", u->server_name)); pa_xfree(t); - pa_sink_set_owner(u->sink, m); #else if (!(dn = pa_xstrdup(pa_modargs_get_value(ma, "source_name", NULL)))) dn = pa_sprintf_malloc("tunnel.%s", u->server_name); - if (!(u->source = pa_source_new(c, __FILE__, dn, 0, &ss, &map))) { - pa_log("failed to create source."); + if (!(u->source = pa_source_new(m->core, __FILE__, dn, 0, &ss, &map))) { + pa_log("Failed to create source."); goto fail; } - u->source->get_latency = source_get_latency; - u->source->get_hw_volume = source_get_hw_volume; - u->source->set_hw_volume = source_set_hw_volume; - u->source->get_hw_mute = source_get_hw_mute; - u->source->set_hw_mute = source_set_hw_mute; + u->source->parent.process_msg = source_process_msg; u->source->userdata = u; + u->source->set_state = source_set_state; + u->source->get_latency = source_get_latency; + pa_source_set_module(u->source, m); + pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); + pa_source_set_rtpoll(u->source, u->rtpoll); pa_source_set_description(u->source, t = pa_sprintf_malloc("Tunnel to %s%s%s", u->source_name ? u->source_name : "", u->source_name ? " on " : "", u->server_name)); pa_xfree(t); - - pa_source_set_owner(u->source, m); #endif pa_xfree(dn); u->time_event = NULL; + u->maxlength = pa_usec_to_bytes(PA_USEC_PER_MSEC * DEFAULT_MAXLENGTH_MSEC, &ss); +#ifdef TUNNEL_SINK + u->tlength = pa_usec_to_bytes(PA_USEC_PER_MSEC * DEFAULT_TLENGTH_MSEC, &ss); + u->minreq = pa_usec_to_bytes(PA_USEC_PER_MSEC * DEFAULT_MINREQ_MSEC, &ss); + u->prebuf = u->tlength; +#else + u->fragsize = pa_usec_to_bytes(PA_USEC_PER_MSEC * DEFAULT_FRAGSIZE_MSEC, &ss); +#endif + + u->counter = u->counter_delta = 0; + pa_smoother_set_time_offset(u->smoother, pa_rtclock_usec()); + + if (!(u->thread = pa_thread_new(thread_func, u))) { + pa_log("Failed to create thread."); + goto fail; + } + +#ifdef TUNNEL_SINK + pa_sink_put(u->sink); +#else + pa_source_put(u->source); +#endif + pa_modargs_free(ma); return 0; fail: - pa__done(c, m); + pa__done(m); if (ma) pa_modargs_free(ma); @@ -1010,17 +1171,59 @@ fail: return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata* u; - assert(c && m); + + pa_assert(m); if (!(u = m->userdata)) return; - close_stuff(u); +#ifdef TUNNEL_SINK + if (u->sink) + pa_sink_unlink(u->sink); +#else + if (u->source) + pa_source_unlink(u->source); +#endif + + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); + } + + pa_thread_mq_done(&u->thread_mq); + +#ifdef TUNNEL_SINK + if (u->sink) + pa_sink_unref(u->sink); +#else + if (u->source) + pa_source_unref(u->source); +#endif + + if (u->rtpoll) + pa_rtpoll_free(u->rtpoll); + + if (u->pstream) { + pa_pstream_unlink(u->pstream); + pa_pstream_unref(u->pstream); + } + + if (u->pdispatch) + pa_pdispatch_unref(u->pdispatch); + + if (u->client) + pa_socket_client_unref(u->client); if (u->auth_cookie_in_property) - pa_authkey_prop_unref(c, PA_NATIVE_COOKIE_PROPERTY_NAME); + pa_authkey_prop_unref(m->core, PA_NATIVE_COOKIE_PROPERTY_NAME); + + if (u->smoother) + pa_smoother_free(u->smoother); + + if (u->time_event) + u->core->mainloop->time_free(u->time_event); #ifdef TUNNEL_SINK pa_xfree(u->sink_name); @@ -1031,5 +1234,3 @@ void pa__done(pa_core *c, pa_module*m) { pa_xfree(u); } - - -- cgit From 0ce32bd40c07af44cb13c80f559d18e162266a89 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 20:01:20 +0000 Subject: fail on name clash git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1980 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 1682007a..936821ff 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -1087,7 +1087,7 @@ int pa__init(pa_module*m) { if (!(dn = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", NULL)))) dn = pa_sprintf_malloc("tunnel.%s", u->server_name); - if (!(u->sink = pa_sink_new(m->core, __FILE__, dn, 0, &ss, &map))) { + if (!(u->sink = pa_sink_new(m->core, __FILE__, dn, 1, &ss, &map))) { pa_log("Failed to create sink."); goto fail; } @@ -1112,7 +1112,7 @@ int pa__init(pa_module*m) { if (!(dn = pa_xstrdup(pa_modargs_get_value(ma, "source_name", NULL)))) dn = pa_sprintf_malloc("tunnel.%s", u->server_name); - if (!(u->source = pa_source_new(m->core, __FILE__, dn, 0, &ss, &map))) { + if (!(u->source = pa_source_new(m->core, __FILE__, dn, 1, &ss, &map))) { pa_log("Failed to create source."); goto fail; } -- cgit From 9ca7ed19580063255dd2d781120b057114b1f5cc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 20:01:49 +0000 Subject: export pa_namereg_is_valid_name() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1981 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/namereg.c | 14 +++++++------- src/pulsecore/namereg.h | 3 +++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c index fe2be467..fe520384 100644 --- a/src/pulsecore/namereg.c +++ b/src/pulsecore/namereg.c @@ -56,20 +56,20 @@ static int is_valid_char(char c) { c == '_'; } -static int is_valid_name(const char *name) { +pa_bool_t pa_namereg_is_valid_name(const char *name) { const char *c; if (*name == 0) - return 0; + return FALSE; for (c = name; *c && (c-name < PA_NAME_MAX); c++) if (!is_valid_char(*c)) - return 0; + return FALSE; if (*c) - return 0; + return FALSE; - return 1; + return TRUE; } static char* cleanup_name(const char *name) { @@ -111,7 +111,7 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t return NULL; if ((type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE) && - !is_valid_name(name) ) { + !pa_namereg_is_valid_name(name) ) { if (fail) return NULL; @@ -253,7 +253,7 @@ int pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type) if (name && *s && !strcmp(name, *s)) return 0; - if (!is_valid_name(name)) + if (!pa_namereg_is_valid_name(name)) return -1; pa_xfree(*s); diff --git a/src/pulsecore/namereg.h b/src/pulsecore/namereg.h index 350ba0f6..d0db9e81 100644 --- a/src/pulsecore/namereg.h +++ b/src/pulsecore/namereg.h @@ -25,6 +25,7 @@ ***/ #include +#include #define PA_NAME_MAX 128 @@ -44,4 +45,6 @@ int pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type); const char *pa_namereg_get_default_sink_name(pa_core *c); const char *pa_namereg_get_default_source_name(pa_core *c); +pa_bool_t pa_namereg_is_valid_name(const char *name); + #endif -- cgit From 9f446590e3f5d9ee32b2591b2500464079ba3426 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 20:03:07 +0000 Subject: publish dns-sd subtypes to allow distinction of virtual, hardware and monitor sinks/source git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1982 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-zeroconf-publish.c | 72 +++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 7 deletions(-) diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index 113686cf..b9b9b22c 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -60,21 +60,35 @@ PA_MODULE_USAGE("port=") #define SERVICE_TYPE_SINK "_pulse-sink._tcp" #define SERVICE_TYPE_SOURCE "_pulse-source._tcp" #define SERVICE_TYPE_SERVER "_pulse-server._tcp" +#define SERVICE_SUBTYPE_SINK_HARDWARE "_hardware._sub."SERVICE_TYPE_SINK +#define SERVICE_SUBTYPE_SINK_VIRTUAL "_virtual._sub."SERVICE_TYPE_SINK +#define SERVICE_SUBTYPE_SOURCE_HARDWARE "_hardware._sub."SERVICE_TYPE_SOURCE +#define SERVICE_SUBTYPE_SOURCE_VIRTUAL "_virtual._sub."SERVICE_TYPE_SOURCE +#define SERVICE_SUBTYPE_SOURCE_MONITOR "_monitor._sub."SERVICE_TYPE_SOURCE +#define SERVICE_SUBTYPE_SOURCE_NON_MONITOR "_non-monitor._sub."SERVICE_TYPE_SOURCE static const char* const valid_modargs[] = { "port", NULL }; +enum service_subtype { + SUBTYPE_HARDWARE, + SUBTYPE_VIRTUAL, + SUBTYPE_MONITOR +}; + struct service { struct userdata *userdata; AvahiEntryGroup *entry_group; char *service_name; pa_object *device; + enum service_subtype subtype; }; struct userdata { pa_core *core; + pa_module *module; AvahiPoll *avahi_poll; AvahiClient *client; @@ -88,10 +102,11 @@ struct userdata { pa_hook_slot *sink_new_slot, *source_new_slot, *sink_unlink_slot, *source_unlink_slot, *sink_changed_slot, *source_changed_slot; }; -static void get_service_data(struct service *s, pa_sample_spec *ret_ss, pa_channel_map *ret_map, const char **ret_name, const char **ret_description) { +static void get_service_data(struct service *s, pa_sample_spec *ret_ss, pa_channel_map *ret_map, const char **ret_name, const char **ret_description, enum service_subtype *ret_subtype) { pa_assert(s); pa_assert(ret_ss); pa_assert(ret_description); + pa_assert(ret_subtype); if (pa_sink_isinstance(s->device)) { pa_sink *sink = PA_SINK(s->device); @@ -100,6 +115,7 @@ static void get_service_data(struct service *s, pa_sample_spec *ret_ss, pa_chann *ret_map = sink->channel_map; *ret_name = sink->name; *ret_description = sink->description; + *ret_subtype = sink->flags & PA_SINK_HARDWARE ? SUBTYPE_HARDWARE : SUBTYPE_VIRTUAL; } else if (pa_source_isinstance(s->device)) { pa_source *source = PA_SOURCE(s->device); @@ -108,6 +124,8 @@ static void get_service_data(struct service *s, pa_sample_spec *ret_ss, pa_chann *ret_map = source->channel_map; *ret_name = source->name; *ret_description = source->description; + *ret_subtype = source->monitor_of ? SUBTYPE_MONITOR : (source->flags & PA_SOURCE_HARDWARE ? SUBTYPE_HARDWARE : SUBTYPE_VIRTUAL); + } else pa_assert_not_reached(); } @@ -174,6 +192,13 @@ static int publish_service(struct service *s) { pa_sample_spec ss; pa_channel_map map; char cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + enum service_subtype subtype; + + const char * const subtype_text[] = { + [SUBTYPE_HARDWARE] = "hardware", + [SUBTYPE_VIRTUAL] = "virtual", + [SUBTYPE_MONITOR] = "monitor" + }; pa_assert(s); @@ -190,12 +215,13 @@ static int publish_service(struct service *s) { txt = txt_record_server_data(s->userdata->core, txt); - get_service_data(s, &ss, &map, &name, &description); + get_service_data(s, &ss, &map, &name, &description, &subtype); txt = avahi_string_list_add_pair(txt, "device", name); txt = avahi_string_list_add_printf(txt, "rate=%u", ss.rate); txt = avahi_string_list_add_printf(txt, "channels=%u", ss.channels); txt = avahi_string_list_add_pair(txt, "format", pa_sample_format_to_string(ss.format)); txt = avahi_string_list_add_pair(txt, "channel_map", pa_channel_map_snprint(cm, sizeof(cm), &map)); + txt = avahi_string_list_add_pair(txt, "subtype", subtype_text[subtype]); if (avahi_entry_group_add_service_strlst( s->entry_group, @@ -212,6 +238,35 @@ static int publish_service(struct service *s) { goto finish; } + if (avahi_entry_group_add_service_subtype( + s->entry_group, + AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, + 0, + s->service_name, + pa_sink_isinstance(s->device) ? SERVICE_TYPE_SINK : SERVICE_TYPE_SOURCE, + NULL, + pa_sink_isinstance(s->device) ? (subtype == SUBTYPE_HARDWARE ? SERVICE_SUBTYPE_SINK_HARDWARE : SERVICE_SUBTYPE_SINK_VIRTUAL) : + (subtype == SUBTYPE_HARDWARE ? SERVICE_SUBTYPE_SOURCE_HARDWARE : (subtype == SUBTYPE_VIRTUAL ? SERVICE_SUBTYPE_SOURCE_VIRTUAL : SERVICE_SUBTYPE_SOURCE_MONITOR))) < 0) { + + pa_log("avahi_entry_group_add_service_subtype(): %s", avahi_strerror(avahi_client_errno(s->userdata->client))); + goto finish; + } + + if (pa_source_isinstance(s->device) && subtype != SUBTYPE_MONITOR) { + if (avahi_entry_group_add_service_subtype( + s->entry_group, + AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, + 0, + s->service_name, + SERVICE_TYPE_SOURCE, + NULL, + SERVICE_SUBTYPE_SOURCE_NON_MONITOR) < 0) { + + pa_log("avahi_entry_group_add_service_subtype(): %s", avahi_strerror(avahi_client_errno(s->userdata->client))); + goto finish; + } + } + if (avahi_entry_group_commit(s->entry_group) < 0) { pa_log("avahi_entry_group_commit(): %s", avahi_strerror(avahi_client_errno(s->userdata->client))); goto finish; @@ -468,8 +523,10 @@ static void client_callback(AvahiClient *c, AvahiClientState state, void *userda unpublish_all_services(u, TRUE); avahi_client_free(u->client); - if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error))) - pa_log("pa_avahi_client_new() failed: %s", avahi_strerror(error)); + if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error))) { + pa_log("avahi_client_new() failed: %s", avahi_strerror(error)); + pa_module_unload_request(u->module); + } } break; @@ -487,17 +544,18 @@ int pa__init(pa_module*m) { int error; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log("failed to parse module arguments."); + pa_log("Failed to parse module arguments."); goto fail; } if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port <= 0 || port > 0xFFFF) { - pa_log("invalid port specified."); + pa_log("Invalid port specified."); goto fail; } m->userdata = u = pa_xnew(struct userdata, 1); u->core = m->core; + u->module = m; u->port = (uint16_t) port; u->avahi_poll = pa_avahi_poll_new(m->core->mainloop); @@ -516,7 +574,7 @@ int pa__init(pa_module*m) { u->service_name = pa_truncate_utf8(pa_sprintf_malloc("%s@%s", pa_get_user_name(un, sizeof(un)), pa_get_host_name(hn, sizeof(hn))), AVAHI_LABEL_MAX); if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error))) { - pa_log("pa_avahi_client_new() failed: %s", avahi_strerror(error)); + pa_log("avahi_client_new() failed: %s", avahi_strerror(error)); goto fail; } -- cgit From 87be85618ce0bca05a4776bf7154c34b010fb6e9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 20:03:49 +0000 Subject: add new module module-zeroconf-discover git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1983 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 9 +- src/modules/module-zeroconf-discover.c | 338 +++++++++++++++++++++++++++++++++ 2 files changed, 346 insertions(+), 1 deletion(-) create mode 100644 src/modules/module-zeroconf-discover.c diff --git a/src/Makefile.am b/src/Makefile.am index 911bd7b6..b1393e34 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1019,7 +1019,8 @@ endif if HAVE_AVAHI modlibexec_LTLIBRARIES += \ - module-zeroconf-publish.la + module-zeroconf-publish.la \ + module-zeroconf-discover.la endif if HAVE_LIRC @@ -1084,6 +1085,7 @@ SYMDEF_FILES = \ modules/module-null-sink-symdef.h \ modules/module-esound-sink-symdef.h \ modules/module-zeroconf-publish-symdef.h \ + modules/module-zeroconf-discover-symdef.h \ modules/module-lirc-symdef.h \ modules/module-mmkbd-evdev-symdef.h \ modules/module-http-protocol-tcp-symdef.h \ @@ -1303,6 +1305,11 @@ module_zeroconf_publish_la_LDFLAGS = -module -avoid-version module_zeroconf_publish_la_LIBADD = $(AM_LIBADD) $(AVAHI_LIBS) libavahi-wrap.la libpulsecore.la module_zeroconf_publish_la_CFLAGS = $(AM_CFLAGS) $(AVAHI_CFLAGS) +module_zeroconf_discover_la_SOURCES = modules/module-zeroconf-discover.c +module_zeroconf_discover_la_LDFLAGS = -module -avoid-version +module_zeroconf_discover_la_LIBADD = $(AM_LIBADD) $(AVAHI_LIBS) libavahi-wrap.la libpulsecore.la +module_zeroconf_discover_la_CFLAGS = $(AM_CFLAGS) $(AVAHI_CFLAGS) + # LIRC module_lirc_la_SOURCES = modules/module-lirc.c diff --git a/src/modules/module-zeroconf-discover.c b/src/modules/module-zeroconf-discover.c new file mode 100644 index 00000000..b6f8cf6a --- /dev/null +++ b/src/modules/module-zeroconf-discover.c @@ -0,0 +1,338 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-zeroconf-discover-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Discovery") +PA_MODULE_VERSION(PACKAGE_VERSION) + +#define SERVICE_TYPE_SINK "_pulse-sink._tcp" +#define SERVICE_TYPE_SOURCE "_non-monitor._sub._pulse-source._tcp" + + static const char* const valid_modargs[] = { + NULL +}; + +struct userdata { + pa_core *core; + pa_module *module; + AvahiPoll *avahi_poll; + AvahiClient *client; + AvahiServiceBrowser *source_browser, *sink_browser; +}; + +static void resolver_cb( + AvahiServiceResolver *r, + AvahiIfIndex interface, AvahiProtocol protocol, + AvahiResolverEvent event, + const char *name, const char *type, const char *domain, + const char *host_name, const AvahiAddress *a, uint16_t port, + AvahiStringList *txt, + AvahiLookupResultFlags flags, + void *userdata) { + + struct userdata *u = userdata; + + pa_assert(u); + + if (event != AVAHI_RESOLVER_FOUND) + pa_log("Resolving of '%s' failed: %s", name, avahi_strerror(avahi_client_errno(u->client))); + else { + char *device = NULL, *dname, *module_name, *args; + const char *t; + char at[AVAHI_ADDRESS_STR_MAX], cmt[PA_CHANNEL_MAP_SNPRINT_MAX]; + pa_sample_spec ss; + pa_channel_map cm; + AvahiStringList *l; + pa_bool_t channel_map_set = FALSE; + + ss = u->core->default_sample_spec; + pa_channel_map_init_auto(&cm, ss.channels, PA_CHANNEL_MAP_DEFAULT); + + for (l = txt; l; l = l->next) { + char *key, *value; + pa_assert_se(avahi_string_list_get_pair(l, &key, &value, NULL) == 0); + + if (strcmp(key, "device") == 0) { + pa_xfree(device); + device = value; + value = NULL; + } else if (strcmp(key, "rate") == 0) + ss.rate = atoi(value); + else if (strcmp(key, "channels") == 0) + ss.channels = atoi(value); + else if (strcmp(key, "format") == 0) + ss.format = pa_parse_sample_format(value); + else if (strcmp(key, "channel_map") == 0) { + pa_channel_map_parse(&cm, value); + channel_map_set = TRUE; + } + + avahi_free(key); + avahi_free(value); + } + + if (!channel_map_set && cm.channels != ss.channels) + pa_channel_map_init_auto(&cm, ss.channels, PA_CHANNEL_MAP_DEFAULT); + + if (!pa_sample_spec_valid(&ss)) { + pa_log("Service '%s' contains an invalid sample specification.", name); + avahi_free(device); + goto finish; + } + + if (!pa_channel_map_valid(&cm) || cm.channels != ss.channels) { + pa_log("Service '%s' contains an invalid channel map.", name); + avahi_free(device); + goto finish; + } + + if (device) + dname = pa_sprintf_malloc("tunnel.%s.%s", host_name, device); + else + dname = pa_sprintf_malloc("tunnel.%s", host_name); + + if (!pa_namereg_is_valid_name(dname)) { + pa_log("Cannot construct valid device name from credentials of service '%s'.", dname); + avahi_free(device); + pa_xfree(dname); + goto finish; + } + + t = strstr(type, "sink") ? "sink" : "source"; + + module_name = pa_sprintf_malloc("module-tunnel-%s", t); + args = pa_sprintf_malloc("server=[%s]:%u " + "%s=%s " + "format=%s " + "channels=%u " + "rate=%u " + "%s_name=%s " + "channel_map=%s", + avahi_address_snprint(at, sizeof(at), a), port, + t, device, + pa_sample_format_to_string(ss.format), + ss.channels, + ss.rate, + t, dname, + pa_channel_map_snprint(cmt, sizeof(cmt), &cm)); + + pa_log_debug("Loading module-tunnel-%s with arguments '%s'", module_name, args); + pa_module_load(u->core, module_name, args); + + pa_xfree(module_name); + pa_xfree(dname); + pa_xfree(args); + avahi_free(device); + } + +finish: + + avahi_service_resolver_free(r); +} + +static void browser_cb( + AvahiServiceBrowser *b, + AvahiIfIndex interface, AvahiProtocol protocol, + AvahiBrowserEvent event, + const char *name, const char *type, const char *domain, + AvahiLookupResultFlags flags, + void *userdata) { + + struct userdata *u = userdata; + + pa_assert(u); + + if (event != AVAHI_BROWSER_NEW) + return; + + if (flags & AVAHI_LOOKUP_RESULT_LOCAL) + return; + + if (!(avahi_service_resolver_new(u->client, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolver_cb, u))) + pa_log("avahi_service_resolver_new() failed: %s", avahi_strerror(avahi_client_errno(u->client))); + + /* We ignore the returned resolver object here, since the we don't + * need to attach any special data to it, and we can still destory + * it from the callback */ +} + +static void client_callback(AvahiClient *c, AvahiClientState state, void *userdata) { + struct userdata *u = userdata; + + pa_assert(c); + pa_assert(u); + + u->client = c; + + switch (state) { + case AVAHI_CLIENT_S_REGISTERING: + case AVAHI_CLIENT_S_RUNNING: + case AVAHI_CLIENT_S_COLLISION: + + if (!u->sink_browser) { + + if (!(u->sink_browser = avahi_service_browser_new( + c, + AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, + SERVICE_TYPE_SINK, + NULL, + 0, + browser_cb, u))) { + + pa_log("avahi_service_browser_new() failed: %s", avahi_strerror(avahi_client_errno(c))); + pa_module_unload_request(u->module); + } + } + + if (!u->source_browser) { + + if (!(u->source_browser = avahi_service_browser_new( + c, + AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, + SERVICE_TYPE_SOURCE, + NULL, + 0, + browser_cb, u))) { + + pa_log("avahi_service_browser_new() failed: %s", avahi_strerror(avahi_client_errno(c))); + pa_module_unload_request(u->module); + } + } + + break; + + case AVAHI_CLIENT_FAILURE: + if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) { + int error; + + pa_log_debug("Avahi daemon disconnected."); + + if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error))) { + pa_log("avahi_client_new() failed: %s", avahi_strerror(error)); + pa_module_unload_request(u->module); + } + } + + /* Fall through */ + + case AVAHI_CLIENT_CONNECTING: + + if (u->sink_browser) { + avahi_service_browser_free(u->sink_browser); + u->sink_browser = NULL; + } + + if (u->source_browser) { + avahi_service_browser_free(u->source_browser); + u->source_browser = NULL; + } + + break; + + default: ; + } +} + +int pa__init(pa_module*m) { + + struct userdata *u; + pa_modargs *ma = NULL; + int error; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log("Failed to parse module arguments."); + goto fail; + } + + m->userdata = u = pa_xnew(struct userdata, 1); + u->core = m->core; + u->module = m; + u->sink_browser = u->source_browser = NULL; + + u->avahi_poll = pa_avahi_poll_new(m->core->mainloop); + + if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error))) { + pa_log("pa_avahi_client_new() failed: %s", avahi_strerror(error)); + goto fail; + } + + pa_modargs_free(ma); + + return 0; + +fail: + pa__done(m); + + if (ma) + pa_modargs_free(ma); + + return -1; +} + +void pa__done(pa_module*m) { + struct userdata*u; + pa_assert(m); + + if (!(u = m->userdata)) + return; + + if (u->client) + avahi_client_free(u->client); + + if (u->avahi_poll) + pa_avahi_poll_free(u->avahi_poll); + + pa_xfree(u); +} -- cgit From cc883852bc3c71e2c5c04177a6e4d29af18e2045 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 20:30:15 +0000 Subject: add new API pa_strlist_reverse() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1984 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/strlist.c | 15 +++++++++++++++ src/pulsecore/strlist.h | 3 +++ 2 files changed, 18 insertions(+) diff --git a/src/pulsecore/strlist.c b/src/pulsecore/strlist.c index 792af0ff..ac83f6b1 100644 --- a/src/pulsecore/strlist.c +++ b/src/pulsecore/strlist.c @@ -146,3 +146,18 @@ pa_strlist* pa_strlist_parse(const char *s) { return head; } + +pa_strlist *pa_strlist_reverse(pa_strlist *l) { + pa_strlist *r = NULL; + + while (l) { + pa_strlist *n; + + n = l->next; + l->next = r; + r = l; + l = n; + } + + return r; +} diff --git a/src/pulsecore/strlist.h b/src/pulsecore/strlist.h index 96ad47e2..6e6e2d4a 100644 --- a/src/pulsecore/strlist.h +++ b/src/pulsecore/strlist.h @@ -46,4 +46,7 @@ pa_strlist* pa_strlist_pop(pa_strlist *l, char **s); /* Parse a whitespace separated server list */ pa_strlist* pa_strlist_parse(const char *s); +/* Reverse string list */ +pa_strlist *pa_strlist_reverse(pa_strlist *l); + #endif -- cgit From 43b5c65457e880a3e134f7c4adc745f690717830 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 20:30:53 +0000 Subject: reverse server order for PULSE_SERVER x11 property, to follow order in which modules are loaded git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1985 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-x11-publish.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c index e0550e20..f350126a 100644 --- a/src/modules/module-x11-publish.c +++ b/src/modules/module-x11-publish.c @@ -130,7 +130,10 @@ int pa__init(pa_module*m) { if (!(l = pa_property_get(m->core, PA_NATIVE_SERVER_PROPERTY_NAME))) goto fail; + l = pa_strlist_reverse(l); s = pa_strlist_tostring(l); + l = pa_strlist_reverse(l); + pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SERVER", s); pa_xfree(s); @@ -192,4 +195,3 @@ void pa__done(pa_module*m) { pa_xfree(u->id); pa_xfree(u); } - -- cgit From 1dae2e644f1e7c9810befb95315ec22fec7c100c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 20:32:53 +0000 Subject: we don't want to include assert.h anymore git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1986 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-jack-sink.c | 1 - src/modules/module-solaris.c | 1 - src/modules/module-waveout.c | 1 - src/pulsecore/inet_ntop.c | 1 - src/pulsecore/inet_pton.c | 1 - 5 files changed, 5 deletions(-) diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index 5019d656..2cf8a58c 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index a8a94712..4a5c88e4 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -28,7 +28,6 @@ #include #include -#include #include #include #include diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c index ad3645fc..f8bae02f 100644 --- a/src/modules/module-waveout.c +++ b/src/modules/module-waveout.c @@ -28,7 +28,6 @@ #include #include -#include #include diff --git a/src/pulsecore/inet_ntop.c b/src/pulsecore/inet_ntop.c index 041bc09b..4a4f7aac 100644 --- a/src/pulsecore/inet_ntop.c +++ b/src/pulsecore/inet_ntop.c @@ -27,7 +27,6 @@ #include #include -#include #ifndef HAVE_INET_NTOP diff --git a/src/pulsecore/inet_pton.c b/src/pulsecore/inet_pton.c index 7272e459..84d0c0ea 100644 --- a/src/pulsecore/inet_pton.c +++ b/src/pulsecore/inet_pton.c @@ -27,7 +27,6 @@ #include #include -#include #ifndef HAVE_INET_PTON -- cgit From 625a87276a04c00677f2d54d2ad28991f797eee4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 21:19:05 +0000 Subject: make gcc shut up a bit more git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1987 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/core-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 4962112b..eefcc584 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -1522,7 +1522,7 @@ char *pa_readlink(const char *p) { return NULL; } - if (n < l-1) { + if ((size_t) n < l-1) { c[l-1] = 0; return c; } -- cgit From 33c238b7ef4b6c00f46714f14b3c6e1f29af6fde Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 21:23:08 +0000 Subject: ignore network sinks/sources git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1988 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-esound-sink.c | 2 +- src/modules/module-tunnel.c | 2 ++ src/modules/module-zeroconf-publish.c | 21 ++++++++++++++++++--- src/pulse/def.h | 6 ++++-- src/pulsecore/cli-text.c | 6 ++++-- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index b60e15d7..1c02cdfd 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -559,7 +559,7 @@ int pa__init(pa_module*m) { u->sink->parent.process_msg = sink_process_msg; u->sink->userdata = u; - u->sink->flags = PA_SINK_LATENCY; + u->sink->flags = PA_SINK_LATENCY|PA_SINK_NETWORK; pa_sink_set_module(u->sink, m); pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 936821ff..c6b0a2cb 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -1100,6 +1100,7 @@ int pa__init(pa_module*m) { u->sink->get_mute = sink_get_mute; u->sink->set_volume = sink_set_volume; u->sink->set_mute = sink_set_mute; + u->sink->flags = PA_SINK_NETWORK|PA_SINK_LATENCY|PA_SINK_HW_VOLUME_CTRL; pa_sink_set_module(u->sink, m); pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); @@ -1121,6 +1122,7 @@ int pa__init(pa_module*m) { u->source->userdata = u; u->source->set_state = source_set_state; u->source->get_latency = source_get_latency; + u->source->flags = PA_SOURCE_NETWORK|PA_SOURCE_LATENCY; pa_source_set_module(u->source, m); pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index b9b9b22c..8e0419df 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -335,11 +335,24 @@ static void service_free(struct service *s) { pa_xfree(s); } +static pa_bool_t is_network(pa_object *o) { + pa_object_assert_ref(o); + + if (pa_sink_isinstance(o)) + return !!(PA_SINK(o)->flags & PA_SINK_NETWORK); + + if (pa_source_isinstance(o)) + return !!(PA_SOURCE(o)->flags & PA_SOURCE_NETWORK); + + pa_assert_not_reached(); +} + static pa_hook_result_t device_new_or_changed_cb(pa_core *c, pa_object *o, struct userdata *u) { pa_assert(c); pa_object_assert_ref(o); - publish_service(get_service(u, o)); + if (!is_network(o)) + publish_service(get_service(u, o)); return PA_HOOK_OK; } @@ -449,10 +462,12 @@ static int publish_all_services(struct userdata *u) { pa_log_debug("Publishing services in Zeroconf"); for (sink = PA_SINK(pa_idxset_first(u->core->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(u->core->sinks, &idx))) - publish_service(get_service(u, PA_OBJECT(sink))); + if (!is_network(PA_OBJECT(sink))) + publish_service(get_service(u, PA_OBJECT(sink))); for (source = PA_SOURCE(pa_idxset_first(u->core->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(u->core->sources, &idx))) - publish_service(get_service(u, PA_OBJECT(source))); + if (!is_network(PA_OBJECT(source))) + publish_service(get_service(u, PA_OBJECT(source))); if (publish_main_service(u) < 0) goto fail; diff --git a/src/pulse/def.h b/src/pulse/def.h index c2816234..a7c475db 100644 --- a/src/pulse/def.h +++ b/src/pulse/def.h @@ -300,14 +300,16 @@ typedef enum pa_seek_mode { typedef enum pa_sink_flags { PA_SINK_HW_VOLUME_CTRL = 1, /**< Supports hardware volume control */ PA_SINK_LATENCY = 2, /**< Supports latency querying */ - PA_SINK_HARDWARE = 4 /**< Is a hardware sink of some kind, in contrast to "virtual"/software sinks \since 0.9.3 */ + PA_SINK_HARDWARE = 4, /**< Is a hardware sink of some kind, in contrast to "virtual"/software sinks \since 0.9.3 */ + PA_SINK_NETWORK = 8 /**< Is a networked sink of some kind. \since 0.9.7 */ } pa_sink_flags_t; /** Special source flags. \since 0.8 */ typedef enum pa_source_flags { PA_SOURCE_HW_VOLUME_CTRL = 1, /**< Supports hardware volume control */ PA_SOURCE_LATENCY = 2, /**< Supports latency querying */ - PA_SOURCE_HARDWARE = 4 /**< Is a hardware source of some kind, in contrast to "virtual"/software source \since 0.9.3 */ + PA_SOURCE_HARDWARE = 4, /**< Is a hardware source of some kind, in contrast to "virtual"/software source \since 0.9.3 */ + PA_SOURCE_NETWORK = 8 /**< Is a networked sink of some kind. \since 0.9.7 */ } pa_source_flags_t; /** A generic free() like callback prototype */ diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index 6683e697..a77bcc2c 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -111,7 +111,7 @@ char *pa_sink_list_to_string(pa_core *c) { " %c index: %u\n" "\tname: <%s>\n" "\tdriver: <%s>\n" - "\tflags: %s%s%s\n" + "\tflags: %s%s%s%s\n" "\tstate: %s\n" "\tvolume: <%s>\n" "\tmute: <%i>\n" @@ -128,6 +128,7 @@ char *pa_sink_list_to_string(pa_core *c) { sink->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", sink->flags & PA_SINK_LATENCY ? "LATENCY " : "", sink->flags & PA_SINK_HARDWARE ? "HARDWARE " : "", + sink->flags & PA_SINK_NETWORK ? "NETWORK " : "", state_table[pa_sink_get_state(sink)], pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink)), !!pa_sink_get_mute(sink), @@ -172,7 +173,7 @@ char *pa_source_list_to_string(pa_core *c) { " %c index: %u\n" "\tname: <%s>\n" "\tdriver: <%s>\n" - "\tflags: %s%s%s\n" + "\tflags: %s%s%s%s\n" "\tstate: %s\n" "\tvolume: <%s>\n" "\tmute: <%u>\n" @@ -188,6 +189,7 @@ char *pa_source_list_to_string(pa_core *c) { source->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", source->flags & PA_SOURCE_LATENCY ? "LATENCY " : "", source->flags & PA_SOURCE_HARDWARE ? "HARDWARE " : "", + source->flags & PA_SOURCE_NETWORK ? "NETWORK " : "", state_table[pa_source_get_state(source)], pa_cvolume_snprint(cv, sizeof(cv), pa_source_get_volume(source)), !!pa_source_get_mute(source), -- cgit From 5ef242c5b323a0abaca4cfb44b3a1cba99a4c43d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 22:14:34 +0000 Subject: don't try to send pause request before our stream is properly set up git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1989 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index c6b0a2cb..7b6b1b82 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -230,6 +230,9 @@ static void stream_cork(struct userdata *u, pa_bool_t cork) { else pa_smoother_resume(u->smoother, pa_rtclock_usec()); + if (!u->pstream) + return; + t = pa_tagstruct_new(NULL, 0); #ifdef TUNNEL_SINK pa_tagstruct_putu32(t, PA_COMMAND_CORK_PLAYBACK_STREAM); @@ -811,7 +814,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_tagstruct_putu32(reply, PA_INVALID_INDEX); pa_tagstruct_puts(reply, u->sink_name); pa_tagstruct_putu32(reply, u->maxlength); - pa_tagstruct_put_boolean(reply, FALSE); + pa_tagstruct_put_boolean(reply, !PA_SINK_OPENED(pa_sink_get_state(u->sink))); pa_tagstruct_putu32(reply, u->tlength); pa_tagstruct_putu32(reply, u->prebuf); pa_tagstruct_putu32(reply, u->minreq); @@ -827,7 +830,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_tagstruct_putu32(reply, PA_INVALID_INDEX); pa_tagstruct_puts(reply, u->source_name); pa_tagstruct_putu32(reply, u->maxlength); - pa_tagstruct_put_boolean(reply, 0); + pa_tagstruct_put_boolean(reply, !PA_SOURCE_OPENED(pa_source_get_state(u->source))); pa_tagstruct_putu32(reply, u->fragsize); #endif -- cgit From e406bbaa62e5e93fd9ec844513f0848eda034a9b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 23:54:46 +0000 Subject: don't announce monitor sources git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1990 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-zeroconf-publish.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index 8e0419df..818a1b28 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -335,14 +335,14 @@ static void service_free(struct service *s) { pa_xfree(s); } -static pa_bool_t is_network(pa_object *o) { +static pa_bool_t shall_ignore(pa_object *o) { pa_object_assert_ref(o); if (pa_sink_isinstance(o)) return !!(PA_SINK(o)->flags & PA_SINK_NETWORK); if (pa_source_isinstance(o)) - return !!(PA_SOURCE(o)->flags & PA_SOURCE_NETWORK); + return PA_SOURCE(o)->monitor_of || (PA_SOURCE(o)->flags & PA_SOURCE_NETWORK); pa_assert_not_reached(); } @@ -351,7 +351,7 @@ static pa_hook_result_t device_new_or_changed_cb(pa_core *c, pa_object *o, struc pa_assert(c); pa_object_assert_ref(o); - if (!is_network(o)) + if (!shall_ignore(o)) publish_service(get_service(u, o)); return PA_HOOK_OK; @@ -462,11 +462,11 @@ static int publish_all_services(struct userdata *u) { pa_log_debug("Publishing services in Zeroconf"); for (sink = PA_SINK(pa_idxset_first(u->core->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(u->core->sinks, &idx))) - if (!is_network(PA_OBJECT(sink))) + if (!shall_ignore(PA_OBJECT(sink))) publish_service(get_service(u, PA_OBJECT(sink))); for (source = PA_SOURCE(pa_idxset_first(u->core->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(u->core->sources, &idx))) - if (!is_network(PA_OBJECT(source))) + if (!shall_ignore(PA_OBJECT(source))) publish_service(get_service(u, PA_OBJECT(source))); if (publish_main_service(u) < 0) -- cgit From f1be9312cb97dbbdb0a54568fee9acc8571190c5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 23:55:23 +0000 Subject: keep track of configured tunnels and make sure to unload them when they disappear from zeroconf again git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1991 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-zeroconf-discover.c | 123 ++++++++++++++++++++++++++++++--- 1 file changed, 112 insertions(+), 11 deletions(-) diff --git a/src/modules/module-zeroconf-discover.c b/src/modules/module-zeroconf-discover.c index b6f8cf6a..e4903718 100644 --- a/src/modules/module-zeroconf-discover.c +++ b/src/modules/module-zeroconf-discover.c @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include #include @@ -60,18 +60,79 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define SERVICE_TYPE_SINK "_pulse-sink._tcp" #define SERVICE_TYPE_SOURCE "_non-monitor._sub._pulse-source._tcp" - static const char* const valid_modargs[] = { +static const char* const valid_modargs[] = { NULL }; +struct tunnel { + AvahiIfIndex interface; + AvahiProtocol protocol; + char *name, *type, *domain; + uint32_t module_index; +}; + struct userdata { pa_core *core; pa_module *module; AvahiPoll *avahi_poll; AvahiClient *client; AvahiServiceBrowser *source_browser, *sink_browser; + + pa_hashmap *tunnels; }; +static unsigned tunnel_hash(const void *p) { + const struct tunnel *t = p; + + return + (unsigned) t->interface + + (unsigned) t->protocol + + pa_idxset_string_hash_func(t->name) + + pa_idxset_string_hash_func(t->type) + + pa_idxset_string_hash_func(t->domain); +} + +static int tunnel_compare(const void *a, const void *b) { + const struct tunnel *ta = a, *tb = b; + int r; + + if (ta->interface != tb->interface) + return 1; + if (ta->protocol != tb->protocol) + return 1; + if ((r = strcmp(ta->name, tb->name))) + return r; + if ((r = strcmp(ta->type, tb->type))) + return r; + if ((r = strcmp(ta->domain, tb->domain))) + return r; + + return 0; +} + +static struct tunnel *tunnel_new( + AvahiIfIndex interface, AvahiProtocol protocol, + const char *name, const char *type, const char *domain) { + + struct tunnel *t; + t = pa_xnew(struct tunnel, 1); + t->interface = interface; + t->protocol = protocol; + t->name = pa_xstrdup(name); + t->type = pa_xstrdup(type); + t->domain = pa_xstrdup(domain); + t->module_index = PA_IDXSET_INVALID; + return t; +} + +static void tunnel_free(struct tunnel *t) { + pa_assert(t); + pa_xfree(t->name); + pa_xfree(t->type); + pa_xfree(t->domain); + pa_xfree(t); +} + static void resolver_cb( AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, @@ -83,9 +144,12 @@ static void resolver_cb( void *userdata) { struct userdata *u = userdata; + struct tunnel *tnl; pa_assert(u); + tnl = tunnel_new(interface, protocol, name, type, domain); + if (event != AVAHI_RESOLVER_FOUND) pa_log("Resolving of '%s' failed: %s", name, avahi_strerror(avahi_client_errno(u->client))); else { @@ -96,6 +160,7 @@ static void resolver_cb( pa_channel_map cm; AvahiStringList *l; pa_bool_t channel_map_set = FALSE; + pa_module *m; ss = u->core->default_sample_spec; pa_channel_map_init_auto(&cm, ss.channels, PA_CHANNEL_MAP_DEFAULT); @@ -169,7 +234,12 @@ static void resolver_cb( pa_channel_map_snprint(cmt, sizeof(cmt), &cm)); pa_log_debug("Loading module-tunnel-%s with arguments '%s'", module_name, args); - pa_module_load(u->core, module_name, args); + + if ((m = pa_module_load(u->core, module_name, args))) { + tnl->module_index = m->index; + pa_hashmap_put(u->tunnels, tnl, tnl); + tnl = NULL; + } pa_xfree(module_name); pa_xfree(dname); @@ -180,6 +250,9 @@ static void resolver_cb( finish: avahi_service_resolver_free(r); + + if (tnl) + tunnel_free(tnl); } static void browser_cb( @@ -191,21 +264,36 @@ static void browser_cb( void *userdata) { struct userdata *u = userdata; + struct tunnel *t; pa_assert(u); - if (event != AVAHI_BROWSER_NEW) - return; - if (flags & AVAHI_LOOKUP_RESULT_LOCAL) return; - if (!(avahi_service_resolver_new(u->client, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolver_cb, u))) - pa_log("avahi_service_resolver_new() failed: %s", avahi_strerror(avahi_client_errno(u->client))); + t = tunnel_new(interface, protocol, name, type, domain); + + if (event == AVAHI_BROWSER_NEW) { - /* We ignore the returned resolver object here, since the we don't - * need to attach any special data to it, and we can still destory - * it from the callback */ + if (!pa_hashmap_get(u->tunnels, t)) + if (!(avahi_service_resolver_new(u->client, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolver_cb, u))) + pa_log("avahi_service_resolver_new() failed: %s", avahi_strerror(avahi_client_errno(u->client))); + + /* We ignore the returned resolver object here, since the we don't + * need to attach any special data to it, and we can still destory + * it from the callback */ + + } else if (event == AVAHI_BROWSER_REMOVE) { + struct tunnel *t2; + + if ((t2 = pa_hashmap_get(u->tunnels, t))) { + pa_module_unload_by_index(u->core, t2->module_index); + pa_hashmap_remove(u->tunnels, t2); + tunnel_free(t2); + } + } + + tunnel_free(t); } static void client_callback(AvahiClient *c, AvahiClientState state, void *userdata) { @@ -301,6 +389,8 @@ int pa__init(pa_module*m) { u->module = m; u->sink_browser = u->source_browser = NULL; + u->tunnels = pa_hashmap_new(tunnel_hash, tunnel_compare); + u->avahi_poll = pa_avahi_poll_new(m->core->mainloop); if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error))) { @@ -334,5 +424,16 @@ void pa__done(pa_module*m) { if (u->avahi_poll) pa_avahi_poll_free(u->avahi_poll); + if (u->tunnels) { + struct tunnel *t; + + while ((t = pa_hashmap_steal_first(u->tunnels))) { + pa_module_unload_by_index(u->core, t->module_index); + tunnel_free(t); + } + + pa_hashmap_free(u->tunnels, NULL, NULL); + } + pa_xfree(u); } -- cgit From 2d265a91ccd84e896f2bca9764147630d0d7d003 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Oct 2007 00:17:21 +0000 Subject: deal properly with signals interrupting us when we wait for data from gconf helper git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1992 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/gconf/module-gconf.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/modules/gconf/module-gconf.c b/src/modules/gconf/module-gconf.c index 1c8866de..c2ea7b27 100644 --- a/src/modules/gconf/module-gconf.c +++ b/src/modules/gconf/module-gconf.c @@ -225,8 +225,11 @@ static int handle_event(struct userdata *u) { int ret = 0; do { - if ((opcode = read_byte(u)) < 0) + if ((opcode = read_byte(u)) < 0){ + if (errno == EINTR || errno == EAGAIN) + break; goto fail; + } switch (opcode) { case '!': @@ -509,4 +512,3 @@ void pa__done(pa_module*m) { pa_xfree(u); } - -- cgit From 0991a1ba2d19eeeafe595fdf433a31a47ef3fcd2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Oct 2007 00:32:00 +0000 Subject: remove libltdl from SVN git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1993 fefdeb5f-60dc-0310-8127-8f9354f1896f --- libltdl/COPYING.LIB | 515 -- libltdl/Makefile.am | 32 - libltdl/Makefile.in | 656 -- libltdl/README | 10 - libltdl/acinclude.m4 | 7025 -------------- libltdl/aclocal.m4 | 875 -- libltdl/config-h.in | 195 - libltdl/config.guess | 1516 --- libltdl/config.h | 196 - libltdl/config.sub | 1622 ---- libltdl/configure | 23853 ------------------------------------------------ libltdl/configure.ac | 79 - libltdl/install-sh | 519 -- libltdl/ltdl.c | 4530 --------- libltdl/ltdl.h | 367 - libltdl/ltmain.sh | 6938 -------------- libltdl/missing | 360 - libltdl/mkinstalldirs | 161 - libltdl/stamp-h1 | 1 - 19 files changed, 49450 deletions(-) delete mode 100644 libltdl/COPYING.LIB delete mode 100644 libltdl/Makefile.am delete mode 100644 libltdl/Makefile.in delete mode 100644 libltdl/README delete mode 100644 libltdl/acinclude.m4 delete mode 100644 libltdl/aclocal.m4 delete mode 100644 libltdl/config-h.in delete mode 100755 libltdl/config.guess delete mode 100644 libltdl/config.h delete mode 100755 libltdl/config.sub delete mode 100755 libltdl/configure delete mode 100644 libltdl/configure.ac delete mode 100755 libltdl/install-sh delete mode 100644 libltdl/ltdl.c delete mode 100644 libltdl/ltdl.h delete mode 100644 libltdl/ltmain.sh delete mode 100755 libltdl/missing delete mode 100755 libltdl/mkinstalldirs delete mode 100644 libltdl/stamp-h1 diff --git a/libltdl/COPYING.LIB b/libltdl/COPYING.LIB deleted file mode 100644 index ba2be481..00000000 --- a/libltdl/COPYING.LIB +++ /dev/null @@ -1,515 +0,0 @@ - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations -below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. -^L - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it -becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. -^L - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control -compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. -^L - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. -^L - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. -^L - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. -^L - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply, and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License -may add an explicit geographical distribution limitation excluding those -countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. -^L - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS -^L - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms -of the ordinary General Public License). - - To apply these terms, attach the following notices to the library. -It is safest to attach them to the start of each source file to most -effectively convey the exclusion of warranty; and each file should -have at least the "copyright" line and a pointer to where the full -notice is found. - - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper -mail. - -You should also get your employer (if you work as a programmer) or -your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James -Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/libltdl/Makefile.am b/libltdl/Makefile.am deleted file mode 100644 index 2a1e7019..00000000 --- a/libltdl/Makefile.am +++ /dev/null @@ -1,32 +0,0 @@ -## Process this file with automake to produce Makefile.in - -AUTOMAKE_OPTIONS = no-dependencies foreign - -if INSTALL_LTDL -include_HEADERS = ltdl.h -lib_LTLIBRARIES = libltdl.la -else -noinst_HEADERS = ltdl.h -endif - -if CONVENIENCE_LTDL -noinst_LTLIBRARIES = libltdlc.la -endif - -## Make sure these will be cleaned even when they're not built by -## default. -CLEANFILES = libltdl.la libltdlc.la - -libltdl_la_SOURCES = ltdl.c -libltdl_la_LDFLAGS = -no-undefined -version-info 4:5:1 -libltdl_la_LIBADD = $(LIBADD_DL) - -libltdlc_la_SOURCES = ltdl.c -libltdlc_la_LIBADD = $(LIBADD_DL) - -## Because we do not have automatic dependency tracking: -ltdl.lo: ltdl.h config.h - -$(libltdl_la_OBJECTS) $(libltdlc_la_OBJECTS): libtool -libtool: $(LIBTOOL_DEPS) - $(SHELL) ./config.status --recheck diff --git a/libltdl/Makefile.in b/libltdl/Makefile.in deleted file mode 100644 index 4319156e..00000000 --- a/libltdl/Makefile.in +++ /dev/null @@ -1,656 +0,0 @@ -# Makefile.in generated by automake 1.10 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006 Free Software Foundation, Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - - -VPATH = @srcdir@ -pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = . -DIST_COMMON = README $(am__configure_deps) $(am__include_HEADERS_DIST) \ - $(am__noinst_HEADERS_DIST) $(srcdir)/Makefile.am \ - $(srcdir)/Makefile.in $(srcdir)/config-h.in \ - $(top_srcdir)/configure COPYING.LIB config.guess config.sub \ - install-sh ltmain.sh missing mkinstalldirs -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ - $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ - configure.lineno config.status.lineno -mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs -CONFIG_HEADER = config.h -CONFIG_CLEAN_FILES = -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; -am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" -libLTLIBRARIES_INSTALL = $(INSTALL) -LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) -am__DEPENDENCIES_1 = -libltdl_la_DEPENDENCIES = $(am__DEPENDENCIES_1) -am_libltdl_la_OBJECTS = ltdl.lo -libltdl_la_OBJECTS = $(am_libltdl_la_OBJECTS) -libltdl_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(libltdl_la_LDFLAGS) $(LDFLAGS) -o $@ -@INSTALL_LTDL_TRUE@am_libltdl_la_rpath = -rpath $(libdir) -libltdlc_la_DEPENDENCIES = $(am__DEPENDENCIES_1) -am_libltdlc_la_OBJECTS = ltdl.lo -libltdlc_la_OBJECTS = $(am_libltdlc_la_OBJECTS) -@CONVENIENCE_LTDL_TRUE@am_libltdlc_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ -depcomp = -am__depfiles_maybe = -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ - $(LDFLAGS) -o $@ -SOURCES = $(libltdl_la_SOURCES) $(libltdlc_la_SOURCES) -DIST_SOURCES = $(libltdl_la_SOURCES) $(libltdlc_la_SOURCES) -am__include_HEADERS_DIST = ltdl.h -includeHEADERS_INSTALL = $(INSTALL_HEADER) -am__noinst_HEADERS_DIST = ltdl.h -HEADERS = $(include_HEADERS) $(noinst_HEADERS) -ETAGS = etags -CTAGS = ctags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -distdir = $(PACKAGE)-$(VERSION) -top_distdir = $(distdir) -am__remove_distdir = \ - { test ! -d $(distdir) \ - || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ - && rm -fr $(distdir); }; } -DIST_ARCHIVES = $(distdir).tar.gz -GZIP_ENV = --best -distuninstallcheck_listfiles = find . -type f -print -distcleancheck_listfiles = find . -type f -print -ACLOCAL = @ACLOCAL@ -AMTAR = @AMTAR@ -AR = @AR@ -AS = @AS@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ -ECHO = @ECHO@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -F77 = @F77@ -FFLAGS = @FFLAGS@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LDFLAGS = @LDFLAGS@ -LIBADD_DL = @LIBADD_DL@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIBTOOL_DEPS = @LIBTOOL_DEPS@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINFO = @MAKEINFO@ -MKDIR_P = @MKDIR_P@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -RANLIB = @RANLIB@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -STRIP = @STRIP@ -VERSION = @VERSION@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -ac_ct_F77 = @ac_ct_F77@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -AUTOMAKE_OPTIONS = no-dependencies foreign -@INSTALL_LTDL_TRUE@include_HEADERS = ltdl.h -@INSTALL_LTDL_TRUE@lib_LTLIBRARIES = libltdl.la -@INSTALL_LTDL_FALSE@noinst_HEADERS = ltdl.h -@CONVENIENCE_LTDL_TRUE@noinst_LTLIBRARIES = libltdlc.la -CLEANFILES = libltdl.la libltdlc.la -libltdl_la_SOURCES = ltdl.c -libltdl_la_LDFLAGS = -no-undefined -version-info 4:5:1 -libltdl_la_LIBADD = $(LIBADD_DL) -libltdlc_la_SOURCES = ltdl.c -libltdlc_la_LIBADD = $(LIBADD_DL) -all: config.h - $(MAKE) $(AM_MAKEFLAGS) all-am - -.SUFFIXES: -.SUFFIXES: .c .lo .o .obj -am--refresh: - @: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \ - cd $(srcdir) && $(AUTOMAKE) --foreign \ - && exit 0; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ - cd $(top_srcdir) && \ - $(AUTOMAKE) --foreign Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - echo ' $(SHELL) ./config.status'; \ - $(SHELL) ./config.status;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - $(SHELL) ./config.status --recheck - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(srcdir) && $(AUTOCONF) -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) - -config.h: stamp-h1 - @if test ! -f $@; then \ - rm -f stamp-h1; \ - $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ - else :; fi - -stamp-h1: $(srcdir)/config-h.in $(top_builddir)/config.status - @rm -f stamp-h1 - cd $(top_builddir) && $(SHELL) ./config.status config.h -$(srcdir)/config-h.in: $(am__configure_deps) - cd $(top_srcdir) && $(AUTOHEADER) - rm -f stamp-h1 - touch $@ - -distclean-hdr: - -rm -f config.h stamp-h1 -install-libLTLIBRARIES: $(lib_LTLIBRARIES) - @$(NORMAL_INSTALL) - test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" - @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ - if test -f $$p; then \ - f=$(am__strip_dir) \ - echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ - $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ - else :; fi; \ - done - -uninstall-libLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ - p=$(am__strip_dir) \ - echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ - $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ - done - -clean-libLTLIBRARIES: - -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) - @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ - dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ - test "$$dir" != "$$p" || dir=.; \ - echo "rm -f \"$${dir}/so_locations\""; \ - rm -f "$${dir}/so_locations"; \ - done - -clean-noinstLTLIBRARIES: - -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) - @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ - dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ - test "$$dir" != "$$p" || dir=.; \ - echo "rm -f \"$${dir}/so_locations\""; \ - rm -f "$${dir}/so_locations"; \ - done -libltdl.la: $(libltdl_la_OBJECTS) $(libltdl_la_DEPENDENCIES) - $(libltdl_la_LINK) $(am_libltdl_la_rpath) $(libltdl_la_OBJECTS) $(libltdl_la_LIBADD) $(LIBS) -libltdlc.la: $(libltdlc_la_OBJECTS) $(libltdlc_la_DEPENDENCIES) - $(LINK) $(am_libltdlc_la_rpath) $(libltdlc_la_OBJECTS) $(libltdlc_la_LIBADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -.c.o: - $(COMPILE) -c $< - -.c.obj: - $(COMPILE) -c `$(CYGPATH_W) '$<'` - -.c.lo: - $(LTCOMPILE) -c -o $@ $< - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -distclean-libtool: - -rm -f libtool -install-includeHEADERS: $(include_HEADERS) - @$(NORMAL_INSTALL) - test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" - @list='$(include_HEADERS)'; for p in $$list; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - f=$(am__strip_dir) \ - echo " $(includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \ - $(includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \ - done - -uninstall-includeHEADERS: - @$(NORMAL_UNINSTALL) - @list='$(include_HEADERS)'; for p in $$list; do \ - f=$(am__strip_dir) \ - echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \ - rm -f "$(DESTDIR)$(includedir)/$$f"; \ - done - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) config-h.in $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) config-h.in $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique; \ - fi -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) config-h.in $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) config-h.in $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - test -z "$(CTAGS_ARGS)$$tags$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$tags $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && cd $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) $$here - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - $(am__remove_distdir) - test -d $(distdir) || mkdir $(distdir) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ - fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ - else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ - || exit 1; \ - fi; \ - done - -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ - ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ - || chmod -R a+r $(distdir) -dist-gzip: distdir - tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz - $(am__remove_distdir) - -dist-bzip2: distdir - tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 - $(am__remove_distdir) - -dist-tarZ: distdir - tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z - $(am__remove_distdir) - -dist-shar: distdir - shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz - $(am__remove_distdir) - -dist-zip: distdir - -rm -f $(distdir).zip - zip -rq $(distdir).zip $(distdir) - $(am__remove_distdir) - -dist dist-all: distdir - tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz - $(am__remove_distdir) - -# This target untars the dist file and tries a VPATH configuration. Then -# it guarantees that the distribution is self-contained by making another -# tarfile. -distcheck: dist - case '$(DIST_ARCHIVES)' in \ - *.tar.gz*) \ - GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ - *.tar.bz2*) \ - bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ - *.tar.Z*) \ - uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ - *.shar.gz*) \ - GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ - *.zip*) \ - unzip $(distdir).zip ;;\ - esac - chmod -R a-w $(distdir); chmod a+w $(distdir) - mkdir $(distdir)/_build - mkdir $(distdir)/_inst - chmod a-w $(distdir) - dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ - && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ - && cd $(distdir)/_build \ - && ../configure --srcdir=.. --prefix="$$dc_install_base" \ - $(DISTCHECK_CONFIGURE_FLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) dvi \ - && $(MAKE) $(AM_MAKEFLAGS) check \ - && $(MAKE) $(AM_MAKEFLAGS) install \ - && $(MAKE) $(AM_MAKEFLAGS) installcheck \ - && $(MAKE) $(AM_MAKEFLAGS) uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ - distuninstallcheck \ - && chmod -R a-w "$$dc_install_base" \ - && ({ \ - (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ - distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ - } || { rm -rf "$$dc_destdir"; exit 1; }) \ - && rm -rf "$$dc_destdir" \ - && $(MAKE) $(AM_MAKEFLAGS) dist \ - && rm -rf $(DIST_ARCHIVES) \ - && $(MAKE) $(AM_MAKEFLAGS) distcleancheck - $(am__remove_distdir) - @(echo "$(distdir) archives ready for distribution: "; \ - list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ - sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' -distuninstallcheck: - @cd $(distuninstallcheck_dir) \ - && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ - || { echo "ERROR: files left after uninstall:" ; \ - if test -n "$(DESTDIR)"; then \ - echo " (check DESTDIR support)"; \ - fi ; \ - $(distuninstallcheck_listfiles) ; \ - exit 1; } >&2 -distcleancheck: distclean - @if test '$(srcdir)' = . ; then \ - echo "ERROR: distcleancheck can only run from a VPATH build" ; \ - exit 1 ; \ - fi - @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ - || { echo "ERROR: files left in build directory after distclean:" ; \ - $(distcleancheck_listfiles) ; \ - exit 1; } >&2 -check-am: all-am -check: check-am -all-am: Makefile $(LTLIBRARIES) $(HEADERS) config.h -installdirs: - for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ - clean-noinstLTLIBRARIES mostlyclean-am - -distclean: distclean-am - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-hdr distclean-libtool distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -info: info-am - -info-am: - -install-data-am: install-includeHEADERS - -install-dvi: install-dvi-am - -install-exec-am: install-libLTLIBRARIES - -install-html: install-html-am - -install-info: install-info-am - -install-man: - -install-pdf: install-pdf-am - -install-ps: install-ps-am - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf $(top_srcdir)/autom4te.cache - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES - -.MAKE: install-am install-strip - -.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \ - clean-generic clean-libLTLIBRARIES clean-libtool \ - clean-noinstLTLIBRARIES ctags dist dist-all dist-bzip2 \ - dist-gzip dist-shar dist-tarZ dist-zip distcheck distclean \ - distclean-compile distclean-generic distclean-hdr \ - distclean-libtool distclean-tags distcleancheck distdir \ - distuninstallcheck dvi dvi-am html html-am info info-am \ - install install-am install-data install-data-am install-dvi \ - install-dvi-am install-exec install-exec-am install-html \ - install-html-am install-includeHEADERS install-info \ - install-info-am install-libLTLIBRARIES install-man install-pdf \ - install-pdf-am install-ps install-ps-am install-strip \ - installcheck installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags uninstall uninstall-am uninstall-includeHEADERS \ - uninstall-libLTLIBRARIES - - -ltdl.lo: ltdl.h config.h - -$(libltdl_la_OBJECTS) $(libltdlc_la_OBJECTS): libtool -libtool: $(LIBTOOL_DEPS) - $(SHELL) ./config.status --recheck -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/libltdl/README b/libltdl/README deleted file mode 100644 index da0a449c..00000000 --- a/libltdl/README +++ /dev/null @@ -1,10 +0,0 @@ -This is GNU libltdl, a system independent dlopen wrapper for GNU libtool. - -It supports the following dlopen interfaces: -* dlopen (Solaris, Linux and various BSD flavors) -* shl_load (HP-UX) -* LoadLibrary (Win16 and Win32) -* load_add_on (BeOS) -* GNU DLD (emulates dynamic linking for static libraries) -* dyld (darwin/Mac OS X) -* libtool's dlpreopen diff --git a/libltdl/acinclude.m4 b/libltdl/acinclude.m4 deleted file mode 100644 index 79d94868..00000000 --- a/libltdl/acinclude.m4 +++ /dev/null @@ -1,7025 +0,0 @@ -# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- -## Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 -## Free Software Foundation, Inc. -## Originally by Gordon Matzigkeit , 1996 -## -## This file is free software; the Free Software Foundation gives -## unlimited permission to copy and/or distribute it, with or without -## modifications, as long as this notice is preserved. - -# serial 51 Debian 1.5.24-1 AC_PROG_LIBTOOL - - -# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED) -# ----------------------------------------------------------- -# If this macro is not defined by Autoconf, define it here. -m4_ifdef([AC_PROVIDE_IFELSE], - [], - [m4_define([AC_PROVIDE_IFELSE], - [m4_ifdef([AC_PROVIDE_$1], - [$2], [$3])])]) - - -# AC_PROG_LIBTOOL -# --------------- -AC_DEFUN([AC_PROG_LIBTOOL], -[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl -dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX -dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. - AC_PROVIDE_IFELSE([AC_PROG_CXX], - [AC_LIBTOOL_CXX], - [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX - ])]) -dnl And a similar setup for Fortran 77 support - AC_PROVIDE_IFELSE([AC_PROG_F77], - [AC_LIBTOOL_F77], - [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77 -])]) - -dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. -dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run -dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. - AC_PROVIDE_IFELSE([AC_PROG_GCJ], - [AC_LIBTOOL_GCJ], - [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], - [AC_LIBTOOL_GCJ], - [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], - [AC_LIBTOOL_GCJ], - [ifdef([AC_PROG_GCJ], - [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])]) - ifdef([A][M_PROG_GCJ], - [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])]) - ifdef([LT_AC_PROG_GCJ], - [define([LT_AC_PROG_GCJ], - defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])]) -])])# AC_PROG_LIBTOOL - - -# _AC_PROG_LIBTOOL -# ---------------- -AC_DEFUN([_AC_PROG_LIBTOOL], -[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl -AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl -AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl -AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl - -# This can be used to rebuild libtool when needed -LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" - -# Always use our own libtool. -LIBTOOL='$(SHELL) $(top_builddir)/libtool' -AC_SUBST(LIBTOOL)dnl - -# Prevent multiple expansion -define([AC_PROG_LIBTOOL], []) -])# _AC_PROG_LIBTOOL - - -# AC_LIBTOOL_SETUP -# ---------------- -AC_DEFUN([AC_LIBTOOL_SETUP], -[AC_PREREQ(2.50)dnl -AC_REQUIRE([AC_ENABLE_SHARED])dnl -AC_REQUIRE([AC_ENABLE_STATIC])dnl -AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl -AC_REQUIRE([AC_CANONICAL_HOST])dnl -AC_REQUIRE([AC_CANONICAL_BUILD])dnl -AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([AC_PROG_LD])dnl -AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl -AC_REQUIRE([AC_PROG_NM])dnl - -AC_REQUIRE([AC_PROG_LN_S])dnl -AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl -# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! -AC_REQUIRE([AC_OBJEXT])dnl -AC_REQUIRE([AC_EXEEXT])dnl -dnl - -AC_LIBTOOL_SYS_MAX_CMD_LEN -AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE -AC_LIBTOOL_OBJDIR - -AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl -_LT_AC_PROG_ECHO_BACKSLASH - -case $host_os in -aix3*) - # AIX sometimes has problems with the GCC collect2 program. For some - # reason, if we set the COLLECT_NAMES environment variable, the problems - # vanish in a puff of smoke. - if test "X${COLLECT_NAMES+set}" != Xset; then - COLLECT_NAMES= - export COLLECT_NAMES - fi - ;; -esac - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -Xsed='sed -e 1s/^X//' -[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] - -# Same as above, but do not quote variable references. -[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] - -# Sed substitution to delay expansion of an escaped shell variable in a -# double_quote_subst'ed string. -delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' - -# Sed substitution to avoid accidental globbing in evaled expressions -no_glob_subst='s/\*/\\\*/g' - -# Constants: -rm="rm -f" - -# Global variables: -default_ofile=libtool -can_build_shared=yes - -# All known linkers require a `.a' archive for static linking (except MSVC, -# which needs '.lib'). -libext=a -ltmain="$ac_aux_dir/ltmain.sh" -ofile="$default_ofile" -with_gnu_ld="$lt_cv_prog_gnu_ld" - -AC_CHECK_TOOL(AR, ar, false) -AC_CHECK_TOOL(RANLIB, ranlib, :) -AC_CHECK_TOOL(STRIP, strip, :) - -old_CC="$CC" -old_CFLAGS="$CFLAGS" - -# Set sane defaults for various variables -test -z "$AR" && AR=ar -test -z "$AR_FLAGS" && AR_FLAGS=cru -test -z "$AS" && AS=as -test -z "$CC" && CC=cc -test -z "$LTCC" && LTCC=$CC -test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS -test -z "$DLLTOOL" && DLLTOOL=dlltool -test -z "$LD" && LD=ld -test -z "$LN_S" && LN_S="ln -s" -test -z "$MAGIC_CMD" && MAGIC_CMD=file -test -z "$NM" && NM=nm -test -z "$SED" && SED=sed -test -z "$OBJDUMP" && OBJDUMP=objdump -test -z "$RANLIB" && RANLIB=: -test -z "$STRIP" && STRIP=: -test -z "$ac_objext" && ac_objext=o - -# Determine commands to create old-style static archives. -old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' -old_postinstall_cmds='chmod 644 $oldlib' -old_postuninstall_cmds= - -if test -n "$RANLIB"; then - case $host_os in - openbsd*) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" - ;; - *) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" - ;; - esac - old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" -fi - -_LT_CC_BASENAME([$compiler]) - -# Only perform the check for file, if the check method requires it -case $deplibs_check_method in -file_magic*) - if test "$file_magic_cmd" = '$MAGIC_CMD'; then - AC_PATH_MAGIC - fi - ;; -esac - -AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) -AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], -enable_win32_dll=yes, enable_win32_dll=no) - -AC_ARG_ENABLE([libtool-lock], - [AC_HELP_STRING([--disable-libtool-lock], - [avoid locking (might break parallel builds)])]) -test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes - -AC_ARG_WITH([pic], - [AC_HELP_STRING([--with-pic], - [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], - [pic_mode="$withval"], - [pic_mode=default]) -test -z "$pic_mode" && pic_mode=default - -# Use C for the default configuration in the libtool script -tagname= -AC_LIBTOOL_LANG_C_CONFIG -_LT_AC_TAGCONFIG -])# AC_LIBTOOL_SETUP - - -# _LT_AC_SYS_COMPILER -# ------------------- -AC_DEFUN([_LT_AC_SYS_COMPILER], -[AC_REQUIRE([AC_PROG_CC])dnl - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC -])# _LT_AC_SYS_COMPILER - - -# _LT_CC_BASENAME(CC) -# ------------------- -# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. -AC_DEFUN([_LT_CC_BASENAME], -[for cc_temp in $1""; do - case $cc_temp in - compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; - distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; - \-*) ;; - *) break;; - esac -done -cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` -]) - - -# _LT_COMPILER_BOILERPLATE -# ------------------------ -# Check for compiler boilerplate output or warnings with -# the simple compiler test code. -AC_DEFUN([_LT_COMPILER_BOILERPLATE], -[AC_REQUIRE([LT_AC_PROG_SED])dnl -ac_outfile=conftest.$ac_objext -echo "$lt_simple_compile_test_code" >conftest.$ac_ext -eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_compiler_boilerplate=`cat conftest.err` -$rm conftest* -])# _LT_COMPILER_BOILERPLATE - - -# _LT_LINKER_BOILERPLATE -# ---------------------- -# Check for linker boilerplate output or warnings with -# the simple link test code. -AC_DEFUN([_LT_LINKER_BOILERPLATE], -[AC_REQUIRE([LT_AC_PROG_SED])dnl -ac_outfile=conftest.$ac_objext -echo "$lt_simple_link_test_code" >conftest.$ac_ext -eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_linker_boilerplate=`cat conftest.err` -$rm conftest* -])# _LT_LINKER_BOILERPLATE - - -# _LT_AC_SYS_LIBPATH_AIX -# ---------------------- -# Links a minimal program and checks the executable -# for the system default hardcoded library path. In most cases, -# this is /usr/lib:/lib, but when the MPI compilers are used -# the location of the communication and MPI libs are included too. -# If we don't find anything, use the default library path according -# to the aix ld manual. -AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX], -[AC_REQUIRE([LT_AC_PROG_SED])dnl -AC_LINK_IFELSE(AC_LANG_PROGRAM,[ -lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\(.*\)$/\1/ - p - } - }' -aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -# Check for a 64-bit object if we didn't find anything. -if test -z "$aix_libpath"; then - aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -fi],[]) -if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi -])# _LT_AC_SYS_LIBPATH_AIX - - -# _LT_AC_SHELL_INIT(ARG) -# ---------------------- -AC_DEFUN([_LT_AC_SHELL_INIT], -[ifdef([AC_DIVERSION_NOTICE], - [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], - [AC_DIVERT_PUSH(NOTICE)]) -$1 -AC_DIVERT_POP -])# _LT_AC_SHELL_INIT - - -# _LT_AC_PROG_ECHO_BACKSLASH -# -------------------------- -# Add some code to the start of the generated configure script which -# will find an echo command which doesn't interpret backslashes. -AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], -[_LT_AC_SHELL_INIT([ -# Check that we are running under the correct shell. -SHELL=${CONFIG_SHELL-/bin/sh} - -case X$ECHO in -X*--fallback-echo) - # Remove one level of quotation (which was required for Make). - ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` - ;; -esac - -echo=${ECHO-echo} -if test "X[$]1" = X--no-reexec; then - # Discard the --no-reexec flag, and continue. - shift -elif test "X[$]1" = X--fallback-echo; then - # Avoid inline document here, it may be left over - : -elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then - # Yippee, $echo works! - : -else - # Restart under the correct shell. - exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} -fi - -if test "X[$]1" = X--fallback-echo; then - # used as fallback echo - shift - cat </dev/null 2>&1 && unset CDPATH - -if test -z "$ECHO"; then -if test "X${echo_test_string+set}" != Xset; then -# find a string as large as possible, as long as the shell can cope with it - for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do - # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... - if (echo_test_string=`eval $cmd`) 2>/dev/null && - echo_test_string=`eval $cmd` && - (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null - then - break - fi - done -fi - -if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - : -else - # The Solaris, AIX, and Digital Unix default echo programs unquote - # backslashes. This makes it impossible to quote backslashes using - # echo "$something" | sed 's/\\/\\\\/g' - # - # So, first we look for a working echo in the user's PATH. - - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for dir in $PATH /usr/ucb; do - IFS="$lt_save_ifs" - if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && - test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - echo="$dir/echo" - break - fi - done - IFS="$lt_save_ifs" - - if test "X$echo" = Xecho; then - # We didn't find a better echo, so look for alternatives. - if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - # This shell has a builtin print -r that does the trick. - echo='print -r' - elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && - test "X$CONFIG_SHELL" != X/bin/ksh; then - # If we have ksh, try running configure again with it. - ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} - export ORIGINAL_CONFIG_SHELL - CONFIG_SHELL=/bin/ksh - export CONFIG_SHELL - exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} - else - # Try using printf. - echo='printf %s\n' - if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - # Cool, printf works - : - elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && - test "X$echo_testing_string" = 'X\t' && - echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL - export CONFIG_SHELL - SHELL="$CONFIG_SHELL" - export SHELL - echo="$CONFIG_SHELL [$]0 --fallback-echo" - elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && - test "X$echo_testing_string" = 'X\t' && - echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - echo="$CONFIG_SHELL [$]0 --fallback-echo" - else - # maybe with a smaller string... - prev=: - - for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do - if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null - then - break - fi - prev="$cmd" - done - - if test "$prev" != 'sed 50q "[$]0"'; then - echo_test_string=`eval $prev` - export echo_test_string - exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} - else - # Oops. We lost completely, so just stick with echo. - echo=echo - fi - fi - fi - fi -fi -fi - -# Copy echo and quote the copy suitably for passing to libtool from -# the Makefile, instead of quoting the original, which is used later. -ECHO=$echo -if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then - ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" -fi - -AC_SUBST(ECHO) -])])# _LT_AC_PROG_ECHO_BACKSLASH - - -# _LT_AC_LOCK -# ----------- -AC_DEFUN([_LT_AC_LOCK], -[AC_ARG_ENABLE([libtool-lock], - [AC_HELP_STRING([--disable-libtool-lock], - [avoid locking (might break parallel builds)])]) -test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes - -# Some flags need to be propagated to the compiler or linker for good -# libtool support. -case $host in -ia64-*-hpux*) - # Find out which ABI we are using. - echo 'int i;' > conftest.$ac_ext - if AC_TRY_EVAL(ac_compile); then - case `/usr/bin/file conftest.$ac_objext` in - *ELF-32*) - HPUX_IA64_MODE="32" - ;; - *ELF-64*) - HPUX_IA64_MODE="64" - ;; - esac - fi - rm -rf conftest* - ;; -*-*-irix6*) - # Find out which ABI we are using. - echo '[#]line __oline__ "configure"' > conftest.$ac_ext - if AC_TRY_EVAL(ac_compile); then - if test "$lt_cv_prog_gnu_ld" = yes; then - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -melf32bsmip" - ;; - *N32*) - LD="${LD-ld} -melf32bmipn32" - ;; - *64-bit*) - LD="${LD-ld} -melf64bmip" - ;; - esac - else - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -32" - ;; - *N32*) - LD="${LD-ld} -n32" - ;; - *64-bit*) - LD="${LD-ld} -64" - ;; - esac - fi - fi - rm -rf conftest* - ;; - -x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ -s390*-*linux*|sparc*-*linux*) - # Find out which ABI we are using. - echo 'int i;' > conftest.$ac_ext - if AC_TRY_EVAL(ac_compile); then - case `/usr/bin/file conftest.o` in - *32-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_i386_fbsd" - ;; - x86_64-*linux*) - LD="${LD-ld} -m elf_i386" - ;; - ppc64-*linux*|powerpc64-*linux*) - LD="${LD-ld} -m elf32ppclinux" - ;; - s390x-*linux*) - LD="${LD-ld} -m elf_s390" - ;; - sparc64-*linux*) - LD="${LD-ld} -m elf32_sparc" - ;; - esac - ;; - *64-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_x86_64_fbsd" - ;; - x86_64-*linux*) - LD="${LD-ld} -m elf_x86_64" - ;; - ppc*-*linux*|powerpc*-*linux*) - LD="${LD-ld} -m elf64ppc" - ;; - s390*-*linux*) - LD="${LD-ld} -m elf64_s390" - ;; - sparc*-*linux*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; - -*-*-sco3.2v5*) - # On SCO OpenServer 5, we need -belf to get full-featured binaries. - SAVE_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -belf" - AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, - [AC_LANG_PUSH(C) - AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) - AC_LANG_POP]) - if test x"$lt_cv_cc_needs_belf" != x"yes"; then - # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf - CFLAGS="$SAVE_CFLAGS" - fi - ;; -sparc*-*solaris*) - # Find out which ABI we are using. - echo 'int i;' > conftest.$ac_ext - if AC_TRY_EVAL(ac_compile); then - case `/usr/bin/file conftest.o` in - *64-bit*) - case $lt_cv_prog_gnu_ld in - yes*) LD="${LD-ld} -m elf64_sparc" ;; - *) LD="${LD-ld} -64" ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; - -AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], -[*-*-cygwin* | *-*-mingw* | *-*-pw32*) - AC_CHECK_TOOL(DLLTOOL, dlltool, false) - AC_CHECK_TOOL(AS, as, false) - AC_CHECK_TOOL(OBJDUMP, objdump, false) - ;; - ]) -esac - -need_locks="$enable_libtool_lock" - -])# _LT_AC_LOCK - - -# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, -# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) -# ---------------------------------------------------------------- -# Check whether the given compiler option works -AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], -[AC_REQUIRE([LT_AC_PROG_SED]) -AC_CACHE_CHECK([$1], [$2], - [$2=no - ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$3" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&AS_MESSAGE_LOG_FD - echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - $2=yes - fi - fi - $rm conftest* -]) - -if test x"[$]$2" = xyes; then - ifelse([$5], , :, [$5]) -else - ifelse([$6], , :, [$6]) -fi -])# AC_LIBTOOL_COMPILER_OPTION - - -# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, -# [ACTION-SUCCESS], [ACTION-FAILURE]) -# ------------------------------------------------------------ -# Check whether the given compiler option works -AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], -[AC_REQUIRE([LT_AC_PROG_SED])dnl -AC_CACHE_CHECK([$1], [$2], - [$2=no - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS $3" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&AS_MESSAGE_LOG_FD - $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - $2=yes - fi - else - $2=yes - fi - fi - $rm conftest* - LDFLAGS="$save_LDFLAGS" -]) - -if test x"[$]$2" = xyes; then - ifelse([$4], , :, [$4]) -else - ifelse([$5], , :, [$5]) -fi -])# AC_LIBTOOL_LINKER_OPTION - - -# AC_LIBTOOL_SYS_MAX_CMD_LEN -# -------------------------- -AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], -[# find the maximum length of command line arguments -AC_MSG_CHECKING([the maximum length of command line arguments]) -AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl - i=0 - teststring="ABCD" - - case $build_os in - msdosdjgpp*) - # On DJGPP, this test can blow up pretty badly due to problems in libc - # (any single argument exceeding 2000 bytes causes a buffer overrun - # during glob expansion). Even if it were fixed, the result of this - # check would be larger than it should be. - lt_cv_sys_max_cmd_len=12288; # 12K is about right - ;; - - gnu*) - # Under GNU Hurd, this test is not required because there is - # no limit to the length of command line arguments. - # Libtool will interpret -1 as no limit whatsoever - lt_cv_sys_max_cmd_len=-1; - ;; - - cygwin* | mingw*) - # On Win9x/ME, this test blows up -- it succeeds, but takes - # about 5 minutes as the teststring grows exponentially. - # Worse, since 9x/ME are not pre-emptively multitasking, - # you end up with a "frozen" computer, even though with patience - # the test eventually succeeds (with a max line length of 256k). - # Instead, let's just punt: use the minimum linelength reported by - # all of the supported platforms: 8192 (on NT/2K/XP). - lt_cv_sys_max_cmd_len=8192; - ;; - - amigaos*) - # On AmigaOS with pdksh, this test takes hours, literally. - # So we just punt and use a minimum line length of 8192. - lt_cv_sys_max_cmd_len=8192; - ;; - - netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) - # This has been around since 386BSD, at least. Likely further. - if test -x /sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` - elif test -x /usr/sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` - else - lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs - fi - # And add a safety zone - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - ;; - - interix*) - # We know the value 262144 and hardcode it with a safety zone (like BSD) - lt_cv_sys_max_cmd_len=196608 - ;; - - osf*) - # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure - # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not - # nice to cause kernel panics so lets avoid the loop below. - # First set a reasonable default. - lt_cv_sys_max_cmd_len=16384 - # - if test -x /sbin/sysconfig; then - case `/sbin/sysconfig -q proc exec_disable_arg_limit` in - *1*) lt_cv_sys_max_cmd_len=-1 ;; - esac - fi - ;; - sco3.2v5*) - lt_cv_sys_max_cmd_len=102400 - ;; - sysv5* | sco5v6* | sysv4.2uw2*) - kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` - if test -n "$kargmax"; then - lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` - else - lt_cv_sys_max_cmd_len=32768 - fi - ;; - *) - lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` - if test -n "$lt_cv_sys_max_cmd_len"; then - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - else - SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} - while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \ - = "XX$teststring") >/dev/null 2>&1 && - new_result=`expr "X$teststring" : ".*" 2>&1` && - lt_cv_sys_max_cmd_len=$new_result && - test $i != 17 # 1/2 MB should be enough - do - i=`expr $i + 1` - teststring=$teststring$teststring - done - teststring= - # Add a significant safety factor because C++ compilers can tack on massive - # amounts of additional arguments before passing them to the linker. - # It appears as though 1/2 is a usable value. - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` - fi - ;; - esac -]) -if test -n $lt_cv_sys_max_cmd_len ; then - AC_MSG_RESULT($lt_cv_sys_max_cmd_len) -else - AC_MSG_RESULT(none) -fi -])# AC_LIBTOOL_SYS_MAX_CMD_LEN - - -# _LT_AC_CHECK_DLFCN -# ------------------ -AC_DEFUN([_LT_AC_CHECK_DLFCN], -[AC_CHECK_HEADERS(dlfcn.h)dnl -])# _LT_AC_CHECK_DLFCN - - -# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, -# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) -# --------------------------------------------------------------------- -AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], -[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl -if test "$cross_compiling" = yes; then : - [$4] -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext < -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -#ifdef __cplusplus -extern "C" void exit (int); -#endif - -void fnord() { int i=42;} -int main () -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - /* dlclose (self); */ - } - else - puts (dlerror ()); - - exit (status); -}] -EOF - if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then - (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) $1 ;; - x$lt_dlneed_uscore) $2 ;; - x$lt_dlunknown|x*) $3 ;; - esac - else : - # compilation failed - $3 - fi -fi -rm -fr conftest* -])# _LT_AC_TRY_DLOPEN_SELF - - -# AC_LIBTOOL_DLOPEN_SELF -# ---------------------- -AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], -[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl -if test "x$enable_dlopen" != xyes; then - enable_dlopen=unknown - enable_dlopen_self=unknown - enable_dlopen_self_static=unknown -else - lt_cv_dlopen=no - lt_cv_dlopen_libs= - - case $host_os in - beos*) - lt_cv_dlopen="load_add_on" - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; - - mingw* | pw32*) - lt_cv_dlopen="LoadLibrary" - lt_cv_dlopen_libs= - ;; - - cygwin*) - lt_cv_dlopen="dlopen" - lt_cv_dlopen_libs= - ;; - - darwin*) - # if libdl is installed we need to link against it - AC_CHECK_LIB([dl], [dlopen], - [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ - lt_cv_dlopen="dyld" - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ]) - ;; - - *) - AC_CHECK_FUNC([shl_load], - [lt_cv_dlopen="shl_load"], - [AC_CHECK_LIB([dld], [shl_load], - [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], - [AC_CHECK_FUNC([dlopen], - [lt_cv_dlopen="dlopen"], - [AC_CHECK_LIB([dl], [dlopen], - [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], - [AC_CHECK_LIB([svld], [dlopen], - [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], - [AC_CHECK_LIB([dld], [dld_link], - [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) - ]) - ]) - ]) - ]) - ]) - ;; - esac - - if test "x$lt_cv_dlopen" != xno; then - enable_dlopen=yes - else - enable_dlopen=no - fi - - case $lt_cv_dlopen in - dlopen) - save_CPPFLAGS="$CPPFLAGS" - test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" - - save_LDFLAGS="$LDFLAGS" - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" - - save_LIBS="$LIBS" - LIBS="$lt_cv_dlopen_libs $LIBS" - - AC_CACHE_CHECK([whether a program can dlopen itself], - lt_cv_dlopen_self, [dnl - _LT_AC_TRY_DLOPEN_SELF( - lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, - lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) - ]) - - if test "x$lt_cv_dlopen_self" = xyes; then - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" - AC_CACHE_CHECK([whether a statically linked program can dlopen itself], - lt_cv_dlopen_self_static, [dnl - _LT_AC_TRY_DLOPEN_SELF( - lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, - lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) - ]) - fi - - CPPFLAGS="$save_CPPFLAGS" - LDFLAGS="$save_LDFLAGS" - LIBS="$save_LIBS" - ;; - esac - - case $lt_cv_dlopen_self in - yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; - *) enable_dlopen_self=unknown ;; - esac - - case $lt_cv_dlopen_self_static in - yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; - *) enable_dlopen_self_static=unknown ;; - esac -fi -])# AC_LIBTOOL_DLOPEN_SELF - - -# AC_LIBTOOL_PROG_CC_C_O([TAGNAME]) -# --------------------------------- -# Check to see if options -c and -o are simultaneously supported by compiler -AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O], -[AC_REQUIRE([LT_AC_PROG_SED])dnl -AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl -AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], - [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)], - [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no - $rm -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&AS_MESSAGE_LOG_FD - echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes - fi - fi - chmod u+w . 2>&AS_MESSAGE_LOG_FD - $rm conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files - $rm out/* && rmdir out - cd .. - rmdir conftest - $rm conftest* -]) -])# AC_LIBTOOL_PROG_CC_C_O - - -# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME]) -# ----------------------------------------- -# Check to see if we can do hard links to lock some files if needed -AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], -[AC_REQUIRE([_LT_AC_LOCK])dnl - -hard_links="nottested" -if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then - # do not overwrite the value of need_locks provided by the user - AC_MSG_CHECKING([if we can lock with hard links]) - hard_links=yes - $rm conftest* - ln conftest.a conftest.b 2>/dev/null && hard_links=no - touch conftest.a - ln conftest.a conftest.b 2>&5 || hard_links=no - ln conftest.a conftest.b 2>/dev/null && hard_links=no - AC_MSG_RESULT([$hard_links]) - if test "$hard_links" = no; then - AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) - need_locks=warn - fi -else - need_locks=no -fi -])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS - - -# AC_LIBTOOL_OBJDIR -# ----------------- -AC_DEFUN([AC_LIBTOOL_OBJDIR], -[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], -[rm -f .libs 2>/dev/null -mkdir .libs 2>/dev/null -if test -d .libs; then - lt_cv_objdir=.libs -else - # MS-DOS does not allow filenames that begin with a dot. - lt_cv_objdir=_libs -fi -rmdir .libs 2>/dev/null]) -objdir=$lt_cv_objdir -])# AC_LIBTOOL_OBJDIR - - -# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME]) -# ---------------------------------------------- -# Check hardcoding attributes. -AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], -[AC_MSG_CHECKING([how to hardcode library paths into programs]) -_LT_AC_TAGVAR(hardcode_action, $1)= -if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \ - test -n "$_LT_AC_TAGVAR(runpath_var, $1)" || \ - test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then - - # We can hardcode non-existant directories. - if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no && - # If the only mechanism to avoid hardcoding is shlibpath_var, we - # have to relink, otherwise we might link with an installed library - # when we should be linking with a yet-to-be-installed one - ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no && - test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then - # Linking always hardcodes the temporary library directory. - _LT_AC_TAGVAR(hardcode_action, $1)=relink - else - # We can link without hardcoding, and we can hardcode nonexisting dirs. - _LT_AC_TAGVAR(hardcode_action, $1)=immediate - fi -else - # We cannot hardcode anything, or else we can only hardcode existing - # directories. - _LT_AC_TAGVAR(hardcode_action, $1)=unsupported -fi -AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)]) - -if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then - # Fast installation is not supported - enable_fast_install=no -elif test "$shlibpath_overrides_runpath" = yes || - test "$enable_shared" = no; then - # Fast installation is not necessary - enable_fast_install=needless -fi -])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH - - -# AC_LIBTOOL_SYS_LIB_STRIP -# ------------------------ -AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP], -[striplib= -old_striplib= -AC_MSG_CHECKING([whether stripping libraries is possible]) -if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then - test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" - test -z "$striplib" && striplib="$STRIP --strip-unneeded" - AC_MSG_RESULT([yes]) -else -# FIXME - insert some real tests, host_os isn't really good enough - case $host_os in - darwin*) - if test -n "$STRIP" ; then - striplib="$STRIP -x" - old_striplib="$STRIP -S" - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) -fi - ;; - *) - AC_MSG_RESULT([no]) - ;; - esac -fi -])# AC_LIBTOOL_SYS_LIB_STRIP - - -# AC_LIBTOOL_SYS_DYNAMIC_LINKER -# ----------------------------- -# PORTME Fill in your ld.so characteristics -AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER], -[AC_REQUIRE([LT_AC_PROG_SED])dnl -AC_MSG_CHECKING([dynamic linker characteristics]) -library_names_spec= -libname_spec='lib$name' -soname_spec= -shrext_cmds=".so" -postinstall_cmds= -postuninstall_cmds= -finish_cmds= -finish_eval= -shlibpath_var= -shlibpath_overrides_runpath=unknown -version_type=none -dynamic_linker="$host_os ld.so" -sys_lib_dlsearch_path_spec="/lib /usr/lib" -m4_if($1,[],[ -if test "$GCC" = yes; then - case $host_os in - darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; - *) lt_awk_arg="/^libraries:/" ;; - esac - lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` - if echo "$lt_search_path_spec" | grep ';' >/dev/null ; then - # if the path contains ";" then we assume it to be the separator - # otherwise default to the standard path separator (i.e. ":") - it is - # assumed that no part of a normal pathname contains ";" but that should - # okay in the real world where ";" in dirpaths is itself problematic. - lt_search_path_spec=`echo "$lt_search_path_spec" | $SED -e 's/;/ /g'` - else - lt_search_path_spec=`echo "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi - # Ok, now we have the path, separated by spaces, we can step through it - # and add multilib dir if necessary. - lt_tmp_lt_search_path_spec= - lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` - for lt_sys_path in $lt_search_path_spec; do - if test -d "$lt_sys_path/$lt_multi_os_dir"; then - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" - else - test -d "$lt_sys_path" && \ - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" - fi - done - lt_search_path_spec=`echo $lt_tmp_lt_search_path_spec | awk ' -BEGIN {RS=" "; FS="/|\n";} { - lt_foo=""; - lt_count=0; - for (lt_i = NF; lt_i > 0; lt_i--) { - if ($lt_i != "" && $lt_i != ".") { - if ($lt_i == "..") { - lt_count++; - } else { - if (lt_count == 0) { - lt_foo="/" $lt_i lt_foo; - } else { - lt_count--; - } - } - } - } - if (lt_foo != "") { lt_freq[[lt_foo]]++; } - if (lt_freq[[lt_foo]] == 1) { print lt_foo; } -}'` - sys_lib_search_path_spec=`echo $lt_search_path_spec` -else - sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" -fi]) -need_lib_prefix=unknown -hardcode_into_libs=no - -# when you set need_version to no, make sure it does not cause -set_version -# flags to be left without arguments -need_version=unknown - -case $host_os in -aix3*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' - shlibpath_var=LIBPATH - - # AIX 3 has no versioning support, so we append a major version to the name. - soname_spec='${libname}${release}${shared_ext}$major' - ;; - -aix4* | aix5*) - version_type=linux - need_lib_prefix=no - need_version=no - hardcode_into_libs=yes - if test "$host_cpu" = ia64; then - # AIX 5 supports IA64 - library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - else - # With GCC up to 2.95.x, collect2 would create an import file - # for dependence libraries. The import file would start with - # the line `#! .'. This would cause the generated library to - # depend on `.', always an invalid library. This was fixed in - # development snapshots of GCC prior to 3.0. - case $host_os in - aix4 | aix4.[[01]] | aix4.[[01]].*) - if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' - echo ' yes ' - echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then - : - else - can_build_shared=no - fi - ;; - esac - # AIX (on Power*) has no versioning support, so currently we can not hardcode correct - # soname into executable. Probably we can add versioning support to - # collect2, so additional links can be useful in future. - if test "$aix_use_runtimelinking" = yes; then - # If using run time linking (on AIX 4.2 or later) use lib.so - # instead of lib.a to let people know that these are not - # typical AIX shared libraries. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - else - # We preserve .a as extension for shared libraries through AIX4.2 - # and later when we are not doing run time linking. - library_names_spec='${libname}${release}.a $libname.a' - soname_spec='${libname}${release}${shared_ext}$major' - fi - shlibpath_var=LIBPATH - fi - ;; - -amigaos*) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' - ;; - -beos*) - library_names_spec='${libname}${shared_ext}' - dynamic_linker="$host_os ld.so" - shlibpath_var=LIBRARY_PATH - ;; - -bsdi[[45]]*) - version_type=linux - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" - sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" - # the default ld.so.conf also contains /usr/contrib/lib and - # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow - # libtool to hard-code these into programs - ;; - -cygwin* | mingw* | pw32*) - version_type=windows - shrext_cmds=".dll" - need_version=no - need_lib_prefix=no - - case $GCC,$host_os in - yes,cygwin* | yes,mingw* | yes,pw32*) - library_names_spec='$libname.dll.a' - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \${file}`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $rm \$dlpath' - shlibpath_overrides_runpath=yes - - case $host_os in - cygwin*) - # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' - sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" - ;; - mingw*) - # MinGW DLLs use traditional 'lib' prefix - soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' - sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` - if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then - # It is most probably a Windows format PATH printed by - # mingw gcc, but we are running on Cygwin. Gcc prints its search - # path with ; separators, and with drive letters. We can handle the - # drive letters (cygwin fileutils understands them), so leave them, - # especially as we might pass files found there to a mingw objdump, - # which wouldn't understand a cygwinified path. Ahh. - sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi - ;; - pw32*) - # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' - ;; - esac - ;; - - *) - library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' - ;; - esac - dynamic_linker='Win32 ld.exe' - # FIXME: first we should search . and the directory the executable is in - shlibpath_var=PATH - ;; - -darwin* | rhapsody*) - dynamic_linker="$host_os dyld" - version_type=darwin - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' - soname_spec='${libname}${release}${major}$shared_ext' - shlibpath_overrides_runpath=yes - shlibpath_var=DYLD_LIBRARY_PATH - shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' - m4_if([$1], [],[ - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) - sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' - ;; - -dgux*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -freebsd1*) - dynamic_linker=no - ;; - -freebsd* | dragonfly*) - # DragonFly does not have aout. When/if they implement a new - # versioning mechanism, adjust this. - if test -x /usr/bin/objformat; then - objformat=`/usr/bin/objformat` - else - case $host_os in - freebsd[[123]]*) objformat=aout ;; - *) objformat=elf ;; - esac - fi - version_type=freebsd-$objformat - case $version_type in - freebsd-elf*) - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - need_version=no - need_lib_prefix=no - ;; - freebsd-*) - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' - need_version=yes - ;; - esac - shlibpath_var=LD_LIBRARY_PATH - case $host_os in - freebsd2*) - shlibpath_overrides_runpath=yes - ;; - freebsd3.[[01]]* | freebsdelf3.[[01]]*) - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ - freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - *) # from 4.6 on, and DragonFly - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - esac - ;; - -gnu*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - hardcode_into_libs=yes - ;; - -hpux9* | hpux10* | hpux11*) - # Give a soname corresponding to the major version so that dld.sl refuses to - # link against other versions. - version_type=sunos - need_lib_prefix=no - need_version=no - case $host_cpu in - ia64*) - shrext_cmds='.so' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.so" - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - if test "X$HPUX_IA64_MODE" = X32; then - sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" - else - sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" - fi - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - hppa*64*) - shrext_cmds='.sl' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.sl" - shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - *) - shrext_cmds='.sl' - dynamic_linker="$host_os dld.sl" - shlibpath_var=SHLIB_PATH - shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - ;; - esac - # HP-UX runs *really* slowly unless shared libraries are mode 555. - postinstall_cmds='chmod 555 $lib' - ;; - -interix[[3-9]]*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -irix5* | irix6* | nonstopux*) - case $host_os in - nonstopux*) version_type=nonstopux ;; - *) - if test "$lt_cv_prog_gnu_ld" = yes; then - version_type=linux - else - version_type=irix - fi ;; - esac - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' - case $host_os in - irix5* | nonstopux*) - libsuff= shlibsuff= - ;; - *) - case $LD in # libtool.m4 will add one of these switches to LD - *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") - libsuff= shlibsuff= libmagic=32-bit;; - *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") - libsuff=32 shlibsuff=N32 libmagic=N32;; - *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") - libsuff=64 shlibsuff=64 libmagic=64-bit;; - *) libsuff= shlibsuff= libmagic=never-match;; - esac - ;; - esac - shlibpath_var=LD_LIBRARY${shlibsuff}_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" - sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" - hardcode_into_libs=yes - ;; - -# No shared lib support for Linux oldld, aout, or coff. -linux*oldld* | linux*aout* | linux*coff*) - dynamic_linker=no - ;; - -# This must be Linux ELF. -linux* | k*bsd*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - # Append ld.so.conf contents to the search path - if test -f /etc/ld.so.conf; then - lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` - sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" - fi - - # We used to test for /lib/ld.so.1 and disable shared libraries on - # powerpc, because MkLinux only supported shared libraries with the - # GNU dynamic linker. Since this was broken with cross compilers, - # most powerpc-linux boxes support dynamic linking these days and - # people can always --disable-shared, the test was removed, and we - # assume the GNU/Linux dynamic linker is in use. - dynamic_linker='GNU/Linux ld.so' - ;; - -netbsdelf*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='NetBSD ld.elf_so' - ;; - -netbsd*) - version_type=sunos - need_lib_prefix=no - need_version=no - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - dynamic_linker='NetBSD (a.out) ld.so' - else - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='NetBSD ld.elf_so' - fi - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - -newsos6) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -nto-qnx*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -openbsd*) - version_type=sunos - sys_lib_dlsearch_path_spec="/usr/lib" - need_lib_prefix=no - # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. - case $host_os in - openbsd3.3 | openbsd3.3.*) need_version=yes ;; - *) need_version=no ;; - esac - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - case $host_os in - openbsd2.[[89]] | openbsd2.[[89]].*) - shlibpath_overrides_runpath=no - ;; - *) - shlibpath_overrides_runpath=yes - ;; - esac - else - shlibpath_overrides_runpath=yes - fi - ;; - -os2*) - libname_spec='$name' - shrext_cmds=".dll" - need_lib_prefix=no - library_names_spec='$libname${shared_ext} $libname.a' - dynamic_linker='OS/2 ld.exe' - shlibpath_var=LIBPATH - ;; - -osf3* | osf4* | osf5*) - version_type=osf - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" - ;; - -rdos*) - dynamic_linker=no - ;; - -solaris*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - # ldd complains unless libraries are executable - postinstall_cmds='chmod +x $lib' - ;; - -sunos4*) - version_type=sunos - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - if test "$with_gnu_ld" = yes; then - need_lib_prefix=no - fi - need_version=yes - ;; - -sysv4 | sysv4.3*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - case $host_vendor in - sni) - shlibpath_overrides_runpath=no - need_lib_prefix=no - export_dynamic_flag_spec='${wl}-Blargedynsym' - runpath_var=LD_RUN_PATH - ;; - siemens) - need_lib_prefix=no - ;; - motorola) - need_lib_prefix=no - need_version=no - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' - ;; - esac - ;; - -sysv4*MP*) - if test -d /usr/nec ;then - version_type=linux - library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' - soname_spec='$libname${shared_ext}.$major' - shlibpath_var=LD_LIBRARY_PATH - fi - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - version_type=freebsd-elf - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - hardcode_into_libs=yes - if test "$with_gnu_ld" = yes; then - sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' - shlibpath_overrides_runpath=no - else - sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' - shlibpath_overrides_runpath=yes - case $host_os in - sco3.2v5*) - sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" - ;; - esac - fi - sys_lib_dlsearch_path_spec='/usr/lib' - ;; - -uts4*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -*) - dynamic_linker=no - ;; -esac -AC_MSG_RESULT([$dynamic_linker]) -test "$dynamic_linker" = no && can_build_shared=no - -variables_saved_for_relink="PATH $shlibpath_var $runpath_var" -if test "$GCC" = yes; then - variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" -fi -])# AC_LIBTOOL_SYS_DYNAMIC_LINKER - - -# _LT_AC_TAGCONFIG -# ---------------- -AC_DEFUN([_LT_AC_TAGCONFIG], -[AC_REQUIRE([LT_AC_PROG_SED])dnl -AC_ARG_WITH([tags], - [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@], - [include additional configurations @<:@automatic@:>@])], - [tagnames="$withval"]) - -if test -f "$ltmain" && test -n "$tagnames"; then - if test ! -f "${ofile}"; then - AC_MSG_WARN([output file `$ofile' does not exist]) - fi - - if test -z "$LTCC"; then - eval "`$SHELL ${ofile} --config | grep '^LTCC='`" - if test -z "$LTCC"; then - AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) - else - AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) - fi - fi - if test -z "$LTCFLAGS"; then - eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`" - fi - - # Extract list of available tagged configurations in $ofile. - # Note that this assumes the entire list is on one line. - available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` - - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for tagname in $tagnames; do - IFS="$lt_save_ifs" - # Check whether tagname contains only valid characters - case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in - "") ;; - *) AC_MSG_ERROR([invalid tag name: $tagname]) - ;; - esac - - if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null - then - AC_MSG_ERROR([tag name \"$tagname\" already exists]) - fi - - # Update the list of available tags. - if test -n "$tagname"; then - echo appending configuration tag \"$tagname\" to $ofile - - case $tagname in - CXX) - if test -n "$CXX" && ( test "X$CXX" != "Xno" && - ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || - (test "X$CXX" != "Xg++"))) ; then - AC_LIBTOOL_LANG_CXX_CONFIG - else - tagname="" - fi - ;; - - F77) - if test -n "$F77" && test "X$F77" != "Xno"; then - AC_LIBTOOL_LANG_F77_CONFIG - else - tagname="" - fi - ;; - - GCJ) - if test -n "$GCJ" && test "X$GCJ" != "Xno"; then - AC_LIBTOOL_LANG_GCJ_CONFIG - else - tagname="" - fi - ;; - - RC) - AC_LIBTOOL_LANG_RC_CONFIG - ;; - - *) - AC_MSG_ERROR([Unsupported tag name: $tagname]) - ;; - esac - - # Append the new tag name to the list of available tags. - if test -n "$tagname" ; then - available_tags="$available_tags $tagname" - fi - fi - done - IFS="$lt_save_ifs" - - # Now substitute the updated list of available tags. - if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then - mv "${ofile}T" "$ofile" - chmod +x "$ofile" - else - rm -f "${ofile}T" - AC_MSG_ERROR([unable to update list of available tagged configurations.]) - fi -fi -])# _LT_AC_TAGCONFIG - - -# AC_LIBTOOL_DLOPEN -# ----------------- -# enable checks for dlopen support -AC_DEFUN([AC_LIBTOOL_DLOPEN], - [AC_BEFORE([$0],[AC_LIBTOOL_SETUP]) -])# AC_LIBTOOL_DLOPEN - - -# AC_LIBTOOL_WIN32_DLL -# -------------------- -# declare package support for building win32 DLLs -AC_DEFUN([AC_LIBTOOL_WIN32_DLL], -[AC_BEFORE([$0], [AC_LIBTOOL_SETUP]) -])# AC_LIBTOOL_WIN32_DLL - - -# AC_ENABLE_SHARED([DEFAULT]) -# --------------------------- -# implement the --enable-shared flag -# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. -AC_DEFUN([AC_ENABLE_SHARED], -[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl -AC_ARG_ENABLE([shared], - [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@], - [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])], - [p=${PACKAGE-default} - case $enableval in - yes) enable_shared=yes ;; - no) enable_shared=no ;; - *) - enable_shared=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for pkg in $enableval; do - IFS="$lt_save_ifs" - if test "X$pkg" = "X$p"; then - enable_shared=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac], - [enable_shared=]AC_ENABLE_SHARED_DEFAULT) -])# AC_ENABLE_SHARED - - -# AC_DISABLE_SHARED -# ----------------- -# set the default shared flag to --disable-shared -AC_DEFUN([AC_DISABLE_SHARED], -[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl -AC_ENABLE_SHARED(no) -])# AC_DISABLE_SHARED - - -# AC_ENABLE_STATIC([DEFAULT]) -# --------------------------- -# implement the --enable-static flag -# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. -AC_DEFUN([AC_ENABLE_STATIC], -[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl -AC_ARG_ENABLE([static], - [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@], - [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])], - [p=${PACKAGE-default} - case $enableval in - yes) enable_static=yes ;; - no) enable_static=no ;; - *) - enable_static=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for pkg in $enableval; do - IFS="$lt_save_ifs" - if test "X$pkg" = "X$p"; then - enable_static=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac], - [enable_static=]AC_ENABLE_STATIC_DEFAULT) -])# AC_ENABLE_STATIC - - -# AC_DISABLE_STATIC -# ----------------- -# set the default static flag to --disable-static -AC_DEFUN([AC_DISABLE_STATIC], -[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl -AC_ENABLE_STATIC(no) -])# AC_DISABLE_STATIC - - -# AC_ENABLE_FAST_INSTALL([DEFAULT]) -# --------------------------------- -# implement the --enable-fast-install flag -# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. -AC_DEFUN([AC_ENABLE_FAST_INSTALL], -[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl -AC_ARG_ENABLE([fast-install], - [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], - [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], - [p=${PACKAGE-default} - case $enableval in - yes) enable_fast_install=yes ;; - no) enable_fast_install=no ;; - *) - enable_fast_install=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for pkg in $enableval; do - IFS="$lt_save_ifs" - if test "X$pkg" = "X$p"; then - enable_fast_install=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac], - [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT) -])# AC_ENABLE_FAST_INSTALL - - -# AC_DISABLE_FAST_INSTALL -# ----------------------- -# set the default to --disable-fast-install -AC_DEFUN([AC_DISABLE_FAST_INSTALL], -[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl -AC_ENABLE_FAST_INSTALL(no) -])# AC_DISABLE_FAST_INSTALL - - -# AC_LIBTOOL_PICMODE([MODE]) -# -------------------------- -# implement the --with-pic flag -# MODE is either `yes' or `no'. If omitted, it defaults to `both'. -AC_DEFUN([AC_LIBTOOL_PICMODE], -[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl -pic_mode=ifelse($#,1,$1,default) -])# AC_LIBTOOL_PICMODE - - -# AC_PROG_EGREP -# ------------- -# This is predefined starting with Autoconf 2.54, so this conditional -# definition can be removed once we require Autoconf 2.54 or later. -m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP], -[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], - [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 - then ac_cv_prog_egrep='grep -E' - else ac_cv_prog_egrep='egrep' - fi]) - EGREP=$ac_cv_prog_egrep - AC_SUBST([EGREP]) -])]) - - -# AC_PATH_TOOL_PREFIX -# ------------------- -# find a file program which can recognize shared library -AC_DEFUN([AC_PATH_TOOL_PREFIX], -[AC_REQUIRE([AC_PROG_EGREP])dnl -AC_MSG_CHECKING([for $1]) -AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, -[case $MAGIC_CMD in -[[\\/*] | ?:[\\/]*]) - lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD="$MAGIC_CMD" - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR -dnl $ac_dummy forces splitting on constant user-supplied paths. -dnl POSIX.2 word splitting is done only on the output of word expansions, -dnl not every word. This closes a longstanding sh security hole. - ac_dummy="ifelse([$2], , $PATH, [$2])" - for ac_dir in $ac_dummy; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$1; then - lt_cv_path_MAGIC_CMD="$ac_dir/$1" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD="$lt_cv_path_MAGIC_CMD" - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -EOF - fi ;; - esac - fi - break - fi - done - IFS="$lt_save_ifs" - MAGIC_CMD="$lt_save_MAGIC_CMD" - ;; -esac]) -MAGIC_CMD="$lt_cv_path_MAGIC_CMD" -if test -n "$MAGIC_CMD"; then - AC_MSG_RESULT($MAGIC_CMD) -else - AC_MSG_RESULT(no) -fi -])# AC_PATH_TOOL_PREFIX - - -# AC_PATH_MAGIC -# ------------- -# find a file program which can recognize a shared library -AC_DEFUN([AC_PATH_MAGIC], -[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) -if test -z "$lt_cv_path_MAGIC_CMD"; then - if test -n "$ac_tool_prefix"; then - AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) - else - MAGIC_CMD=: - fi -fi -])# AC_PATH_MAGIC - - -# AC_PROG_LD -# ---------- -# find the pathname to the GNU or non-GNU linker -AC_DEFUN([AC_PROG_LD], -[AC_ARG_WITH([gnu-ld], - [AC_HELP_STRING([--with-gnu-ld], - [assume the C compiler uses GNU ld @<:@default=no@:>@])], - [test "$withval" = no || with_gnu_ld=yes], - [with_gnu_ld=no]) -AC_REQUIRE([LT_AC_PROG_SED])dnl -AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([AC_CANONICAL_HOST])dnl -AC_REQUIRE([AC_CANONICAL_BUILD])dnl -ac_prog=ld -if test "$GCC" = yes; then - # Check if gcc -print-prog-name=ld gives a path. - AC_MSG_CHECKING([for ld used by $CC]) - case $host in - *-*-mingw*) - # gcc leaves a trailing carriage return which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [[\\/]]* | ?:[[\\/]]*) - re_direlt='/[[^/]][[^/]]*/\.\./' - # Canonicalize the pathname of ld - ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` - while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do - ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` - done - test -z "$LD" && LD="$ac_prog" - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test "$with_gnu_ld" = yes; then - AC_MSG_CHECKING([for GNU ld]) -else - AC_MSG_CHECKING([for non-GNU ld]) -fi -AC_CACHE_VAL(lt_cv_path_LD, -[if test -z "$LD"; then - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - lt_cv_path_LD="$ac_dir/$ac_prog" - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some variants of GNU ld only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - else - lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' - lt_cv_file_magic_cmd='$OBJDUMP -f' - fi - ;; - -darwin* | rhapsody*) - lt_cv_deplibs_check_method=pass_all - ;; - -freebsd* | dragonfly*) - if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then - case $host_cpu in - i*86 ) - # Not sure whether the presence of OpenBSD here was a mistake. - # Let's accept both of them until this is cleared up. - lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' - lt_cv_file_magic_cmd=/usr/bin/file - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` - ;; - esac - else - lt_cv_deplibs_check_method=pass_all - fi - ;; - -gnu*) - lt_cv_deplibs_check_method=pass_all - ;; - -hpux10.20* | hpux11*) - lt_cv_file_magic_cmd=/usr/bin/file - case $host_cpu in - ia64*) - lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' - lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so - ;; - hppa*64*) - [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] - lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl - ;; - *) - lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' - lt_cv_file_magic_test_file=/usr/lib/libc.sl - ;; - esac - ;; - -interix[[3-9]]*) - # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here - lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' - ;; - -irix5* | irix6* | nonstopux*) - case $LD in - *-32|*"-32 ") libmagic=32-bit;; - *-n32|*"-n32 ") libmagic=N32;; - *-64|*"-64 ") libmagic=64-bit;; - *) libmagic=never-match;; - esac - lt_cv_deplibs_check_method=pass_all - ;; - -# This must be Linux ELF. -linux* | k*bsd*-gnu) - lt_cv_deplibs_check_method=pass_all - ;; - -netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then - lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' - fi - ;; - -newos6*) - lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' - lt_cv_file_magic_cmd=/usr/bin/file - lt_cv_file_magic_test_file=/usr/lib/libnls.so - ;; - -nto-qnx*) - lt_cv_deplibs_check_method=unknown - ;; - -openbsd*) - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' - fi - ;; - -osf3* | osf4* | osf5*) - lt_cv_deplibs_check_method=pass_all - ;; - -rdos*) - lt_cv_deplibs_check_method=pass_all - ;; - -solaris*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv4 | sysv4.3*) - case $host_vendor in - motorola) - lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` - ;; - ncr) - lt_cv_deplibs_check_method=pass_all - ;; - sequent) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' - ;; - sni) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" - lt_cv_file_magic_test_file=/lib/libc.so - ;; - siemens) - lt_cv_deplibs_check_method=pass_all - ;; - pc) - lt_cv_deplibs_check_method=pass_all - ;; - esac - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - lt_cv_deplibs_check_method=pass_all - ;; -esac -]) -file_magic_cmd=$lt_cv_file_magic_cmd -deplibs_check_method=$lt_cv_deplibs_check_method -test -z "$deplibs_check_method" && deplibs_check_method=unknown -])# AC_DEPLIBS_CHECK_METHOD - - -# AC_PROG_NM -# ---------- -# find the pathname to a BSD-compatible name lister -AC_DEFUN([AC_PROG_NM], -[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM, -[if test -n "$NM"; then - # Let the user override the test. - lt_cv_path_NM="$NM" -else - lt_nm_to_check="${ac_tool_prefix}nm" - if test -n "$ac_tool_prefix" && test "$build" = "$host"; then - lt_nm_to_check="$lt_nm_to_check nm" - fi - for lt_tmp_nm in $lt_nm_to_check; do - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - tmp_nm="$ac_dir/$lt_tmp_nm" - if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then - # Check to see if the nm accepts a BSD-compat flag. - # Adding the `sed 1q' prevents false positives on HP-UX, which says: - # nm: unknown option "B" ignored - # Tru64's nm complains that /dev/null is an invalid object file - case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in - */dev/null* | *'Invalid file or object type'*) - lt_cv_path_NM="$tmp_nm -B" - break - ;; - *) - case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in - */dev/null*) - lt_cv_path_NM="$tmp_nm -p" - break - ;; - *) - lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but - continue # so that we can try to find one that supports BSD flags - ;; - esac - ;; - esac - fi - done - IFS="$lt_save_ifs" - done - test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm -fi]) -NM="$lt_cv_path_NM" -])# AC_PROG_NM - - -# AC_CHECK_LIBM -# ------------- -# check for math library -AC_DEFUN([AC_CHECK_LIBM], -[AC_REQUIRE([AC_CANONICAL_HOST])dnl -LIBM= -case $host in -*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) - # These system don't have libm, or don't need it - ;; -*-ncr-sysv4.3*) - AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") - AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") - ;; -*) - AC_CHECK_LIB(m, cos, LIBM="-lm") - ;; -esac -])# AC_CHECK_LIBM - - -# AC_LIBLTDL_CONVENIENCE([DIRECTORY]) -# ----------------------------------- -# sets LIBLTDL to the link flags for the libltdl convenience library and -# LTDLINCL to the include flags for the libltdl header and adds -# --enable-ltdl-convenience to the configure arguments. Note that -# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided, -# it is assumed to be `libltdl'. LIBLTDL will be prefixed with -# '${top_builddir}/' and LTDLINCL will be prefixed with '${top_srcdir}/' -# (note the single quotes!). If your package is not flat and you're not -# using automake, define top_builddir and top_srcdir appropriately in -# the Makefiles. -AC_DEFUN([AC_LIBLTDL_CONVENIENCE], -[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl - case $enable_ltdl_convenience in - no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; - "") enable_ltdl_convenience=yes - ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; - esac - LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la - LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) - # For backwards non-gettext consistent compatibility... - INCLTDL="$LTDLINCL" -])# AC_LIBLTDL_CONVENIENCE - - -# AC_LIBLTDL_INSTALLABLE([DIRECTORY]) -# ----------------------------------- -# sets LIBLTDL to the link flags for the libltdl installable library and -# LTDLINCL to the include flags for the libltdl header and adds -# --enable-ltdl-install to the configure arguments. Note that -# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided, -# and an installed libltdl is not found, it is assumed to be `libltdl'. -# LIBLTDL will be prefixed with '${top_builddir}/'# and LTDLINCL with -# '${top_srcdir}/' (note the single quotes!). If your package is not -# flat and you're not using automake, define top_builddir and top_srcdir -# appropriately in the Makefiles. -# In the future, this macro may have to be called after AC_PROG_LIBTOOL. -AC_DEFUN([AC_LIBLTDL_INSTALLABLE], -[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl - AC_CHECK_LIB(ltdl, lt_dlinit, - [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], - [if test x"$enable_ltdl_install" = xno; then - AC_MSG_WARN([libltdl not installed, but installation disabled]) - else - enable_ltdl_install=yes - fi - ]) - if test x"$enable_ltdl_install" = x"yes"; then - ac_configure_args="$ac_configure_args --enable-ltdl-install" - LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la - LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) - else - ac_configure_args="$ac_configure_args --enable-ltdl-install=no" - LIBLTDL="-lltdl" - LTDLINCL= - fi - # For backwards non-gettext consistent compatibility... - INCLTDL="$LTDLINCL" -])# AC_LIBLTDL_INSTALLABLE - - -# AC_LIBTOOL_CXX -# -------------- -# enable support for C++ libraries -AC_DEFUN([AC_LIBTOOL_CXX], -[AC_REQUIRE([_LT_AC_LANG_CXX]) -])# AC_LIBTOOL_CXX - - -# _LT_AC_LANG_CXX -# --------------- -AC_DEFUN([_LT_AC_LANG_CXX], -[AC_REQUIRE([AC_PROG_CXX]) -AC_REQUIRE([_LT_AC_PROG_CXXCPP]) -_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX]) -])# _LT_AC_LANG_CXX - -# _LT_AC_PROG_CXXCPP -# ------------------ -AC_DEFUN([_LT_AC_PROG_CXXCPP], -[ -AC_REQUIRE([AC_PROG_CXX]) -if test -n "$CXX" && ( test "X$CXX" != "Xno" && - ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || - (test "X$CXX" != "Xg++"))) ; then - AC_PROG_CXXCPP -fi -])# _LT_AC_PROG_CXXCPP - -# AC_LIBTOOL_F77 -# -------------- -# enable support for Fortran 77 libraries -AC_DEFUN([AC_LIBTOOL_F77], -[AC_REQUIRE([_LT_AC_LANG_F77]) -])# AC_LIBTOOL_F77 - - -# _LT_AC_LANG_F77 -# --------------- -AC_DEFUN([_LT_AC_LANG_F77], -[AC_REQUIRE([AC_PROG_F77]) -_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77]) -])# _LT_AC_LANG_F77 - - -# AC_LIBTOOL_GCJ -# -------------- -# enable support for GCJ libraries -AC_DEFUN([AC_LIBTOOL_GCJ], -[AC_REQUIRE([_LT_AC_LANG_GCJ]) -])# AC_LIBTOOL_GCJ - - -# _LT_AC_LANG_GCJ -# --------------- -AC_DEFUN([_LT_AC_LANG_GCJ], -[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], - [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], - [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], - [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], - [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], - [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) -_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ]) -])# _LT_AC_LANG_GCJ - - -# AC_LIBTOOL_RC -# ------------- -# enable support for Windows resource files -AC_DEFUN([AC_LIBTOOL_RC], -[AC_REQUIRE([LT_AC_PROG_RC]) -_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC]) -])# AC_LIBTOOL_RC - - -# AC_LIBTOOL_LANG_C_CONFIG -# ------------------------ -# Ensure that the configuration vars for the C compiler are -# suitably defined. Those variables are subsequently used by -# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. -AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG]) -AC_DEFUN([_LT_AC_LANG_C_CONFIG], -[lt_save_CC="$CC" -AC_LANG_PUSH(C) - -# Source file extension for C test sources. -ac_ext=c - -# Object file extension for compiled C test sources. -objext=o -_LT_AC_TAGVAR(objext, $1)=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="int some_variable = 0;" - -# Code to be used in simple link tests -lt_simple_link_test_code='int main(){return(0);}' - -_LT_AC_SYS_COMPILER - -# save warnings/boilerplate of simple test code -_LT_COMPILER_BOILERPLATE -_LT_LINKER_BOILERPLATE - -## CAVEAT EMPTOR: -## There is no encapsulation within the following macros, do not change -## the running order or otherwise move them around unless you know exactly -## what you are doing... -AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) -AC_LIBTOOL_PROG_COMPILER_PIC($1) -AC_LIBTOOL_PROG_CC_C_O($1) -AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) -AC_LIBTOOL_PROG_LD_SHLIBS($1) -AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) -AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) -AC_LIBTOOL_SYS_LIB_STRIP -AC_LIBTOOL_DLOPEN_SELF - -# Report which library types will actually be built -AC_MSG_CHECKING([if libtool supports shared libraries]) -AC_MSG_RESULT([$can_build_shared]) - -AC_MSG_CHECKING([whether to build shared libraries]) -test "$can_build_shared" = "no" && enable_shared=no - -# On AIX, shared libraries and static libraries use the same namespace, and -# are all built from PIC. -case $host_os in -aix3*) - test "$enable_shared" = yes && enable_static=no - if test -n "$RANLIB"; then - archive_cmds="$archive_cmds~\$RANLIB \$lib" - postinstall_cmds='$RANLIB $lib' - fi - ;; - -aix4* | aix5*) - if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then - test "$enable_shared" = yes && enable_static=no - fi - ;; -esac -AC_MSG_RESULT([$enable_shared]) - -AC_MSG_CHECKING([whether to build static libraries]) -# Make sure either enable_shared or enable_static is yes. -test "$enable_shared" = yes || enable_static=yes -AC_MSG_RESULT([$enable_static]) - -AC_LIBTOOL_CONFIG($1) - -AC_LANG_POP -CC="$lt_save_CC" -])# AC_LIBTOOL_LANG_C_CONFIG - - -# AC_LIBTOOL_LANG_CXX_CONFIG -# -------------------------- -# Ensure that the configuration vars for the C compiler are -# suitably defined. Those variables are subsequently used by -# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. -AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)]) -AC_DEFUN([_LT_AC_LANG_CXX_CONFIG], -[AC_LANG_PUSH(C++) -AC_REQUIRE([AC_PROG_CXX]) -AC_REQUIRE([_LT_AC_PROG_CXXCPP]) - -_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no -_LT_AC_TAGVAR(allow_undefined_flag, $1)= -_LT_AC_TAGVAR(always_export_symbols, $1)=no -_LT_AC_TAGVAR(archive_expsym_cmds, $1)= -_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= -_LT_AC_TAGVAR(hardcode_direct, $1)=no -_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= -_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= -_LT_AC_TAGVAR(hardcode_libdir_separator, $1)= -_LT_AC_TAGVAR(hardcode_minus_L, $1)=no -_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported -_LT_AC_TAGVAR(hardcode_automatic, $1)=no -_LT_AC_TAGVAR(module_cmds, $1)= -_LT_AC_TAGVAR(module_expsym_cmds, $1)= -_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown -_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds -_LT_AC_TAGVAR(no_undefined_flag, $1)= -_LT_AC_TAGVAR(whole_archive_flag_spec, $1)= -_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no - -# Dependencies to place before and after the object being linked: -_LT_AC_TAGVAR(predep_objects, $1)= -_LT_AC_TAGVAR(postdep_objects, $1)= -_LT_AC_TAGVAR(predeps, $1)= -_LT_AC_TAGVAR(postdeps, $1)= -_LT_AC_TAGVAR(compiler_lib_search_path, $1)= - -# Source file extension for C++ test sources. -ac_ext=cpp - -# Object file extension for compiled C++ test sources. -objext=o -_LT_AC_TAGVAR(objext, $1)=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="int some_variable = 0;" - -# Code to be used in simple link tests -lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' - -# ltmain only uses $CC for tagged configurations so make sure $CC is set. -_LT_AC_SYS_COMPILER - -# save warnings/boilerplate of simple test code -_LT_COMPILER_BOILERPLATE -_LT_LINKER_BOILERPLATE - -# Allow CC to be a program name with arguments. -lt_save_CC=$CC -lt_save_LD=$LD -lt_save_GCC=$GCC -GCC=$GXX -lt_save_with_gnu_ld=$with_gnu_ld -lt_save_path_LD=$lt_cv_path_LD -if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then - lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx -else - $as_unset lt_cv_prog_gnu_ld -fi -if test -n "${lt_cv_path_LDCXX+set}"; then - lt_cv_path_LD=$lt_cv_path_LDCXX -else - $as_unset lt_cv_path_LD -fi -test -z "${LDCXX+set}" || LD=$LDCXX -CC=${CXX-"c++"} -compiler=$CC -_LT_AC_TAGVAR(compiler, $1)=$CC -_LT_CC_BASENAME([$compiler]) - -# We don't want -fno-exception wen compiling C++ code, so set the -# no_builtin_flag separately -if test "$GXX" = yes; then - _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' -else - _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= -fi - -if test "$GXX" = yes; then - # Set up default GNU C++ configuration - - AC_PROG_LD - - # Check if GNU C++ uses GNU ld as the underlying linker, since the - # archiving commands below assume that GNU ld is being used. - if test "$with_gnu_ld" = yes; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' - - # If archive_cmds runs LD, not CC, wlarc should be empty - # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to - # investigate it a little bit more. (MM) - wlarc='${wl}' - - # ancient GNU ld didn't support --whole-archive et. al. - if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ - grep 'no-whole-archive' > /dev/null; then - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - else - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= - fi - else - with_gnu_ld=no - wlarc= - - # A generic and very simple default shared library creation - # command for GNU C++ for the case where it uses the native - # linker, instead of GNU ld. If possible, this setting should - # overridden to take advantage of the native linker features on - # the platform it is being used on. - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' - fi - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' - -else - GXX=no - with_gnu_ld=no - wlarc= -fi - -# PORTME: fill in a description of your system's C++ link characteristics -AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) -_LT_AC_TAGVAR(ld_shlibs, $1)=yes -case $host_os in - aix3*) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - aix4* | aix5*) - if test "$host_cpu" = ia64; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag="" - else - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # need to do runtime linking. - case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) - for ld_flag in $LDFLAGS; do - case $ld_flag in - *-brtl*) - aix_use_runtimelinking=yes - break - ;; - esac - done - ;; - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - _LT_AC_TAGVAR(archive_cmds, $1)='' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' - _LT_AC_TAGVAR(link_all_deplibs, $1)=yes - - if test "$GXX" = yes; then - case $host_os in aix4.[[012]]|aix4.[[012]].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`${CC} -print-prog-name=collect2` - if test -f "$collect2name" && \ - strings "$collect2name" | grep resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= - fi - ;; - esac - shared_flag='-shared' - if test "$aix_use_runtimelinking" = yes; then - shared_flag="$shared_flag "'${wl}-G' - fi - else - # not using gcc - if test "$host_cpu" = ia64; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test "$aix_use_runtimelinking" = yes; then - shared_flag='${wl}-G' - else - shared_flag='${wl}-bM:SRE' - fi - fi - fi - - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to export. - _LT_AC_TAGVAR(always_export_symbols, $1)=yes - if test "$aix_use_runtimelinking" = yes; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' - # Determine the default libpath from the value encoded in an empty executable. - _LT_AC_SYS_LIBPATH_AIX - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" - - _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" - else - if test "$host_cpu" = ia64; then - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' - _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" - _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an empty executable. - _LT_AC_SYS_LIBPATH_AIX - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' - # Exported symbols can be pulled into shared objects from archives - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience' - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes - # This is similar to how AIX traditionally builds its shared libraries. - _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' - fi - fi - ;; - - beos*) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported - # Joseph Beckenbach says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - else - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - - chorus*) - case $cc_basename in - *) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - esac - ;; - - cygwin* | mingw* | pw32*) - # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, - # as there is no search path for DLLs. - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported - _LT_AC_TAGVAR(always_export_symbols, $1)=no - _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes - - if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file (1st line - # is EXPORTS), use it as is; otherwise, prepend... - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - else - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - darwin* | rhapsody*) - case $host_os in - rhapsody* | darwin1.[[012]]) - _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress' - ;; - *) # Darwin 1.3 on - if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then - _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' - else - case ${MACOSX_DEPLOYMENT_TARGET} in - 10.[[012]]) - _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' - ;; - 10.*) - _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup' - ;; - esac - fi - ;; - esac - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no - _LT_AC_TAGVAR(hardcode_direct, $1)=no - _LT_AC_TAGVAR(hardcode_automatic, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' - _LT_AC_TAGVAR(link_all_deplibs, $1)=yes - - if test "$GXX" = yes ; then - lt_int_apple_cc_single_mod=no - output_verbose_link_cmd='echo' - if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then - lt_int_apple_cc_single_mod=yes - fi - if test "X$lt_int_apple_cc_single_mod" = Xyes ; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' - else - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' - fi - _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' - # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds - if test "X$lt_int_apple_cc_single_mod" = Xyes ; then - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - else - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - fi - _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - else - case $cc_basename in - xlc*) - output_verbose_link_cmd='echo' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring' - _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' - # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - ;; - *) - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - esac - fi - ;; - - dgux*) - case $cc_basename in - ec++*) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - ghcx*) - # Green Hills C++ Compiler - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - *) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - esac - ;; - freebsd[[12]]*) - # C++ shared libraries reported to be fairly broken before switch to ELF - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - freebsd-elf*) - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no - ;; - freebsd* | dragonfly*) - # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF - # conventions - _LT_AC_TAGVAR(ld_shlibs, $1)=yes - ;; - gnu*) - ;; - hpux9*) - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, - # but as the default - # location of the library. - - case $cc_basename in - CC*) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - aCC*) - _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[[-]]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' - ;; - *) - if test "$GXX" = yes; then - _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - else - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - esac - ;; - hpux10*|hpux11*) - if test $with_gnu_ld = no; then - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - - case $host_cpu in - hppa*64*|ia64*) ;; - *) - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' - ;; - esac - fi - case $host_cpu in - hppa*64*|ia64*) - _LT_AC_TAGVAR(hardcode_direct, $1)=no - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - *) - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, - # but as the default - # location of the library. - ;; - esac - - case $cc_basename in - CC*) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - aCC*) - case $host_cpu in - hppa*64*) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - ia64*) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - *) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - esac - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' - ;; - *) - if test "$GXX" = yes; then - if test $with_gnu_ld = no; then - case $host_cpu in - hppa*64*) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - ia64*) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - *) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - esac - fi - else - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - esac - ;; - interix[[3-9]]*) - _LT_AC_TAGVAR(hardcode_direct, $1)=no - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' - # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. - # Instead, shared libraries are loaded at an image base (0x10000000 by - # default) and relocated if they conflict, which is a slow very memory - # consuming and fragmenting process. To avoid this, we pick a random, - # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link - # time. Moving up from 0x10000000 also allows more sbrk(2) space. - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - ;; - irix5* | irix6*) - case $cc_basename in - CC*) - # SGI C++ - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - - # Archives containing C++ object files must be created using - # "CC -ar", where "CC" is the IRIX C++ compiler. This is - # necessary to make sure instantiated templates are included - # in the archive. - _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' - ;; - *) - if test "$GXX" = yes; then - if test "$with_gnu_ld" = no; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - else - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' - fi - fi - _LT_AC_TAGVAR(link_all_deplibs, $1)=yes - ;; - esac - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - ;; - linux* | k*bsd*-gnu) - case $cc_basename in - KCC*) - # Kuck and Associates, Inc. (KAI) C++ Compiler - - # KCC will only create a shared library if the output file - # ends with ".so" (or ".sl" for HP-UX), so rename the library - # to its proper name (with version) after linking. - _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir' - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' - - # Archives containing C++ object files must be created using - # "CC -Bstatic", where "CC" is the KAI C++ compiler. - _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' - ;; - icpc*) - # Intel C++ - with_gnu_ld=yes - # version 8.0 and above of icpc choke on multiply defined symbols - # if we add $predep_objects and $postdep_objects, however 7.1 and - # earlier do not add the objects themselves. - case `$CC -V 2>&1` in - *"Version 7."*) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - ;; - *) # Version 8.0 or newer - tmp_idyn= - case $host_cpu in - ia64*) tmp_idyn=' -i_dynamic';; - esac - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - ;; - esac - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' - ;; - pgCC*) - # Portland Group C++ compiler - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' - ;; - cxx*) - # Compaq C++ - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' - - runpath_var=LD_RUN_PATH - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) - # Sun C++ 5.9 - _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' - - # Not sure whether something based on - # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 - # would be better. - output_verbose_link_cmd='echo' - - # Archives containing C++ object files must be created using - # "CC -xar", where "CC" is the Sun C++ compiler. This is - # necessary to make sure instantiated templates are included - # in the archive. - _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' - ;; - esac - ;; - esac - ;; - lynxos*) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - m88k*) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - mvs*) - case $cc_basename in - cxx*) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - *) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - esac - ;; - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' - wlarc= - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - fi - # Workaround some broken pre-1.5 toolchains - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' - ;; - openbsd2*) - # C++ shared libraries are fairly broken - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - openbsd*) - if test -f /usr/libexec/ld.so; then - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - fi - output_verbose_link_cmd='echo' - else - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - osf3*) - case $cc_basename in - KCC*) - # Kuck and Associates, Inc. (KAI) C++ Compiler - - # KCC will only create a shared library if the output file - # ends with ".so" (or ".sl" for HP-UX), so rename the library - # to its proper name (with version) after linking. - _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - - # Archives containing C++ object files must be created using - # "CC -Bstatic", where "CC" is the KAI C++ compiler. - _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' - - ;; - RCC*) - # Rational C++ 2.4.1 - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - cxx*) - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' - ;; - *) - if test "$GXX" = yes && test "$with_gnu_ld" = no; then - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' - - else - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - esac - ;; - osf4* | osf5*) - case $cc_basename in - KCC*) - # Kuck and Associates, Inc. (KAI) C++ Compiler - - # KCC will only create a shared library if the output file - # ends with ".so" (or ".sl" for HP-UX), so rename the library - # to its proper name (with version) after linking. - _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - - # Archives containing C++ object files must be created using - # the KAI C++ compiler. - _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' - ;; - RCC*) - # Rational C++ 2.4.1 - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - cxx*) - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ - echo "-hidden">> $lib.exp~ - $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~ - $rm $lib.exp' - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' - ;; - *) - if test "$GXX" = yes && test "$with_gnu_ld" = no; then - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' - - else - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - esac - ;; - psos*) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - sunos4*) - case $cc_basename in - CC*) - # Sun C++ 4.x - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - lcc*) - # Lucid - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - *) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - esac - ;; - solaris*) - case $cc_basename in - CC*) - # Sun C++ 4.2, 5.x and Centerline C++ - _LT_AC_TAGVAR(archive_cmds_need_lc,$1)=yes - _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - case $host_os in - solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; - *) - # The compiler driver will combine and reorder linker options, - # but understands `-z linker_flag'. - # Supported since Solaris 2.6 (maybe 2.5.1?) - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' - ;; - esac - _LT_AC_TAGVAR(link_all_deplibs, $1)=yes - - output_verbose_link_cmd='echo' - - # Archives containing C++ object files must be created using - # "CC -xar", where "CC" is the Sun C++ compiler. This is - # necessary to make sure instantiated templates are included - # in the archive. - _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' - ;; - gcx*) - # Green Hills C++ Compiler - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' - - # The C++ compiler must be used to create the archive. - _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' - ;; - *) - # GNU C++ compiler with Solaris linker - if test "$GXX" = yes && test "$with_gnu_ld" = no; then - _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' - if $CC --version | grep -v '^2\.7' > /dev/null; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" - else - # g++ 2.7 appears to require `-G' NOT `-shared' on this - # platform. - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" - fi - - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' - case $host_os in - solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; - *) - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' - ;; - esac - fi - ;; - esac - ;; - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) - _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - runpath_var='LD_RUN_PATH' - - case $cc_basename in - CC*) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - ;; - sysv5* | sco3.2v5* | sco5v6*) - # Note: We can NOT use -z defs as we might desire, because we do not - # link with -lc, and that would cause any symbols used from libc to - # always be unresolved, which means just about no library would - # ever link correctly. If we're not using GNU ld we use -z text - # though, which does catch some bad symbols but isn't as heavy-handed - # as -z defs. - # For security reasons, it is highly recommended that you always - # use absolute paths for naming shared libraries, and exclude the - # DT_RUNPATH tag from executables and libraries. But doing so - # requires that you compile everything twice, which is a pain. - # So that behaviour is only enabled if SCOABSPATH is set to a - # non-empty value in the environment. Most likely only useful for - # creating official distributions of packages. - # This is a hack until libtool officially supports absolute path - # names for shared libraries. - _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' - _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' - _LT_AC_TAGVAR(link_all_deplibs, $1)=yes - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' - runpath_var='LD_RUN_PATH' - - case $cc_basename in - CC*) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - ;; - tandem*) - case $cc_basename in - NCC*) - # NonStop-UX NCC 3.20 - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - *) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - esac - ;; - vxworks*) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - *) - # FIXME: insert proper C++ library support - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; -esac -AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) -test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no - -_LT_AC_TAGVAR(GCC, $1)="$GXX" -_LT_AC_TAGVAR(LD, $1)="$LD" - -## CAVEAT EMPTOR: -## There is no encapsulation within the following macros, do not change -## the running order or otherwise move them around unless you know exactly -## what you are doing... -AC_LIBTOOL_POSTDEP_PREDEP($1) -AC_LIBTOOL_PROG_COMPILER_PIC($1) -AC_LIBTOOL_PROG_CC_C_O($1) -AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) -AC_LIBTOOL_PROG_LD_SHLIBS($1) -AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) -AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) - -AC_LIBTOOL_CONFIG($1) - -AC_LANG_POP -CC=$lt_save_CC -LDCXX=$LD -LD=$lt_save_LD -GCC=$lt_save_GCC -with_gnu_ldcxx=$with_gnu_ld -with_gnu_ld=$lt_save_with_gnu_ld -lt_cv_path_LDCXX=$lt_cv_path_LD -lt_cv_path_LD=$lt_save_path_LD -lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld -lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld -])# AC_LIBTOOL_LANG_CXX_CONFIG - -# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME]) -# ------------------------------------ -# Figure out "hidden" library dependencies from verbose -# compiler output when linking a shared library. -# Parse the compiler output and extract the necessary -# objects, libraries and library flags. -AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[ -dnl we can't use the lt_simple_compile_test_code here, -dnl because it contains code intended for an executable, -dnl not a library. It's possible we should let each -dnl tag define a new lt_????_link_test_code variable, -dnl but it's only used here... -ifelse([$1],[],[cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext <&1 | sed 5q` in - *Sun\ C*) - # Sun C++ 5.9 - # - # The more standards-conforming stlport4 library is - # incompatible with the Cstd library. Avoid specifying - # it if it's in CXXFLAGS. Ignore libCrun as - # -library=stlport4 depends on it. - case " $CXX $CXXFLAGS " in - *" -library=stlport4 "*) - solaris_use_stlport4=yes - ;; - esac - if test "$solaris_use_stlport4" != yes; then - _LT_AC_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' - fi - ;; - esac - ;; - -solaris*) - case $cc_basename in - CC*) - # The more standards-conforming stlport4 library is - # incompatible with the Cstd library. Avoid specifying - # it if it's in CXXFLAGS. Ignore libCrun as - # -library=stlport4 depends on it. - case " $CXX $CXXFLAGS " in - *" -library=stlport4 "*) - solaris_use_stlport4=yes - ;; - esac - - # Adding this requires a known-good setup of shared libraries for - # Sun compiler versions before 5.6, else PIC objects from an old - # archive will be linked into the output, leading to subtle bugs. - if test "$solaris_use_stlport4" != yes; then - _LT_AC_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' - fi - ;; - esac - ;; -esac -]) - -case " $_LT_AC_TAGVAR(postdeps, $1) " in -*" -lc "*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;; -esac -])# AC_LIBTOOL_POSTDEP_PREDEP - -# AC_LIBTOOL_LANG_F77_CONFIG -# -------------------------- -# Ensure that the configuration vars for the C compiler are -# suitably defined. Those variables are subsequently used by -# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. -AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG], [_LT_AC_LANG_F77_CONFIG(F77)]) -AC_DEFUN([_LT_AC_LANG_F77_CONFIG], -[AC_REQUIRE([AC_PROG_F77]) -AC_LANG_PUSH(Fortran 77) - -_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no -_LT_AC_TAGVAR(allow_undefined_flag, $1)= -_LT_AC_TAGVAR(always_export_symbols, $1)=no -_LT_AC_TAGVAR(archive_expsym_cmds, $1)= -_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= -_LT_AC_TAGVAR(hardcode_direct, $1)=no -_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= -_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= -_LT_AC_TAGVAR(hardcode_libdir_separator, $1)= -_LT_AC_TAGVAR(hardcode_minus_L, $1)=no -_LT_AC_TAGVAR(hardcode_automatic, $1)=no -_LT_AC_TAGVAR(module_cmds, $1)= -_LT_AC_TAGVAR(module_expsym_cmds, $1)= -_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown -_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds -_LT_AC_TAGVAR(no_undefined_flag, $1)= -_LT_AC_TAGVAR(whole_archive_flag_spec, $1)= -_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no - -# Source file extension for f77 test sources. -ac_ext=f - -# Object file extension for compiled f77 test sources. -objext=o -_LT_AC_TAGVAR(objext, $1)=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="\ - subroutine t - return - end -" - -# Code to be used in simple link tests -lt_simple_link_test_code="\ - program t - end -" - -# ltmain only uses $CC for tagged configurations so make sure $CC is set. -_LT_AC_SYS_COMPILER - -# save warnings/boilerplate of simple test code -_LT_COMPILER_BOILERPLATE -_LT_LINKER_BOILERPLATE - -# Allow CC to be a program name with arguments. -lt_save_CC="$CC" -CC=${F77-"f77"} -compiler=$CC -_LT_AC_TAGVAR(compiler, $1)=$CC -_LT_CC_BASENAME([$compiler]) - -AC_MSG_CHECKING([if libtool supports shared libraries]) -AC_MSG_RESULT([$can_build_shared]) - -AC_MSG_CHECKING([whether to build shared libraries]) -test "$can_build_shared" = "no" && enable_shared=no - -# On AIX, shared libraries and static libraries use the same namespace, and -# are all built from PIC. -case $host_os in -aix3*) - test "$enable_shared" = yes && enable_static=no - if test -n "$RANLIB"; then - archive_cmds="$archive_cmds~\$RANLIB \$lib" - postinstall_cmds='$RANLIB $lib' - fi - ;; -aix4* | aix5*) - if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then - test "$enable_shared" = yes && enable_static=no - fi - ;; -esac -AC_MSG_RESULT([$enable_shared]) - -AC_MSG_CHECKING([whether to build static libraries]) -# Make sure either enable_shared or enable_static is yes. -test "$enable_shared" = yes || enable_static=yes -AC_MSG_RESULT([$enable_static]) - -_LT_AC_TAGVAR(GCC, $1)="$G77" -_LT_AC_TAGVAR(LD, $1)="$LD" - -AC_LIBTOOL_PROG_COMPILER_PIC($1) -AC_LIBTOOL_PROG_CC_C_O($1) -AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) -AC_LIBTOOL_PROG_LD_SHLIBS($1) -AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) -AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) - -AC_LIBTOOL_CONFIG($1) - -AC_LANG_POP -CC="$lt_save_CC" -])# AC_LIBTOOL_LANG_F77_CONFIG - - -# AC_LIBTOOL_LANG_GCJ_CONFIG -# -------------------------- -# Ensure that the configuration vars for the C compiler are -# suitably defined. Those variables are subsequently used by -# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. -AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG], [_LT_AC_LANG_GCJ_CONFIG(GCJ)]) -AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG], -[AC_LANG_SAVE - -# Source file extension for Java test sources. -ac_ext=java - -# Object file extension for compiled Java test sources. -objext=o -_LT_AC_TAGVAR(objext, $1)=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="class foo {}" - -# Code to be used in simple link tests -lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' - -# ltmain only uses $CC for tagged configurations so make sure $CC is set. -_LT_AC_SYS_COMPILER - -# save warnings/boilerplate of simple test code -_LT_COMPILER_BOILERPLATE -_LT_LINKER_BOILERPLATE - -# Allow CC to be a program name with arguments. -lt_save_CC="$CC" -CC=${GCJ-"gcj"} -compiler=$CC -_LT_AC_TAGVAR(compiler, $1)=$CC -_LT_CC_BASENAME([$compiler]) - -# GCJ did not exist at the time GCC didn't implicitly link libc in. -_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no - -_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds - -## CAVEAT EMPTOR: -## There is no encapsulation within the following macros, do not change -## the running order or otherwise move them around unless you know exactly -## what you are doing... -AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) -AC_LIBTOOL_PROG_COMPILER_PIC($1) -AC_LIBTOOL_PROG_CC_C_O($1) -AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) -AC_LIBTOOL_PROG_LD_SHLIBS($1) -AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) -AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) - -AC_LIBTOOL_CONFIG($1) - -AC_LANG_RESTORE -CC="$lt_save_CC" -])# AC_LIBTOOL_LANG_GCJ_CONFIG - - -# AC_LIBTOOL_LANG_RC_CONFIG -# ------------------------- -# Ensure that the configuration vars for the Windows resource compiler are -# suitably defined. Those variables are subsequently used by -# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. -AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG], [_LT_AC_LANG_RC_CONFIG(RC)]) -AC_DEFUN([_LT_AC_LANG_RC_CONFIG], -[AC_LANG_SAVE - -# Source file extension for RC test sources. -ac_ext=rc - -# Object file extension for compiled RC test sources. -objext=o -_LT_AC_TAGVAR(objext, $1)=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' - -# Code to be used in simple link tests -lt_simple_link_test_code="$lt_simple_compile_test_code" - -# ltmain only uses $CC for tagged configurations so make sure $CC is set. -_LT_AC_SYS_COMPILER - -# save warnings/boilerplate of simple test code -_LT_COMPILER_BOILERPLATE -_LT_LINKER_BOILERPLATE - -# Allow CC to be a program name with arguments. -lt_save_CC="$CC" -CC=${RC-"windres"} -compiler=$CC -_LT_AC_TAGVAR(compiler, $1)=$CC -_LT_CC_BASENAME([$compiler]) -_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes - -AC_LIBTOOL_CONFIG($1) - -AC_LANG_RESTORE -CC="$lt_save_CC" -])# AC_LIBTOOL_LANG_RC_CONFIG - - -# AC_LIBTOOL_CONFIG([TAGNAME]) -# ---------------------------- -# If TAGNAME is not passed, then create an initial libtool script -# with a default configuration from the untagged config vars. Otherwise -# add code to config.status for appending the configuration named by -# TAGNAME from the matching tagged config vars. -AC_DEFUN([AC_LIBTOOL_CONFIG], -[# The else clause should only fire when bootstrapping the -# libtool distribution, otherwise you forgot to ship ltmain.sh -# with your package, and you will get complaints that there are -# no rules to generate ltmain.sh. -if test -f "$ltmain"; then - # See if we are running on zsh, and set the options which allow our commands through - # without removal of \ escapes. - if test -n "${ZSH_VERSION+set}" ; then - setopt NO_GLOB_SUBST - fi - # Now quote all the things that may contain metacharacters while being - # careful not to overquote the AC_SUBSTed values. We take copies of the - # variables and quote the copies for generation of the libtool script. - for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ - SED SHELL STRIP \ - libname_spec library_names_spec soname_spec extract_expsyms_cmds \ - old_striplib striplib file_magic_cmd finish_cmds finish_eval \ - deplibs_check_method reload_flag reload_cmds need_locks \ - lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ - lt_cv_sys_global_symbol_to_c_name_address \ - sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ - old_postinstall_cmds old_postuninstall_cmds \ - _LT_AC_TAGVAR(compiler, $1) \ - _LT_AC_TAGVAR(CC, $1) \ - _LT_AC_TAGVAR(LD, $1) \ - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1) \ - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1) \ - _LT_AC_TAGVAR(lt_prog_compiler_static, $1) \ - _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) \ - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1) \ - _LT_AC_TAGVAR(thread_safe_flag_spec, $1) \ - _LT_AC_TAGVAR(whole_archive_flag_spec, $1) \ - _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) \ - _LT_AC_TAGVAR(old_archive_cmds, $1) \ - _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) \ - _LT_AC_TAGVAR(predep_objects, $1) \ - _LT_AC_TAGVAR(postdep_objects, $1) \ - _LT_AC_TAGVAR(predeps, $1) \ - _LT_AC_TAGVAR(postdeps, $1) \ - _LT_AC_TAGVAR(compiler_lib_search_path, $1) \ - _LT_AC_TAGVAR(archive_cmds, $1) \ - _LT_AC_TAGVAR(archive_expsym_cmds, $1) \ - _LT_AC_TAGVAR(postinstall_cmds, $1) \ - _LT_AC_TAGVAR(postuninstall_cmds, $1) \ - _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) \ - _LT_AC_TAGVAR(allow_undefined_flag, $1) \ - _LT_AC_TAGVAR(no_undefined_flag, $1) \ - _LT_AC_TAGVAR(export_symbols_cmds, $1) \ - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) \ - _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) \ - _LT_AC_TAGVAR(hardcode_libdir_separator, $1) \ - _LT_AC_TAGVAR(hardcode_automatic, $1) \ - _LT_AC_TAGVAR(module_cmds, $1) \ - _LT_AC_TAGVAR(module_expsym_cmds, $1) \ - _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) \ - _LT_AC_TAGVAR(fix_srcfile_path, $1) \ - _LT_AC_TAGVAR(exclude_expsyms, $1) \ - _LT_AC_TAGVAR(include_expsyms, $1); do - - case $var in - _LT_AC_TAGVAR(old_archive_cmds, $1) | \ - _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) | \ - _LT_AC_TAGVAR(archive_cmds, $1) | \ - _LT_AC_TAGVAR(archive_expsym_cmds, $1) | \ - _LT_AC_TAGVAR(module_cmds, $1) | \ - _LT_AC_TAGVAR(module_expsym_cmds, $1) | \ - _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) | \ - _LT_AC_TAGVAR(export_symbols_cmds, $1) | \ - extract_expsyms_cmds | reload_cmds | finish_cmds | \ - postinstall_cmds | postuninstall_cmds | \ - old_postinstall_cmds | old_postuninstall_cmds | \ - sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) - # Double-quote double-evaled strings. - eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" - ;; - *) - eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" - ;; - esac - done - - case $lt_echo in - *'\[$]0 --fallback-echo"') - lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\[$]0 --fallback-echo"[$]/[$]0 --fallback-echo"/'` - ;; - esac - -ifelse([$1], [], - [cfgfile="${ofile}T" - trap "$rm \"$cfgfile\"; exit 1" 1 2 15 - $rm -f "$cfgfile" - AC_MSG_NOTICE([creating $ofile])], - [cfgfile="$ofile"]) - - cat <<__EOF__ >> "$cfgfile" -ifelse([$1], [], -[#! $SHELL - -# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. -# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) -# NOTE: Changes made to this file will be lost: look at ltmain.sh. -# -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 -# Free Software Foundation, Inc. -# -# This file is part of GNU Libtool: -# Originally by Gordon Matzigkeit , 1996 -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# A sed program that does not truncate output. -SED=$lt_SED - -# Sed that helps us avoid accidentally triggering echo(1) options like -n. -Xsed="$SED -e 1s/^X//" - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -# The names of the tagged configurations supported by this script. -available_tags= - -# ### BEGIN LIBTOOL CONFIG], -[# ### BEGIN LIBTOOL TAG CONFIG: $tagname]) - -# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: - -# Shell to use when invoking shell scripts. -SHELL=$lt_SHELL - -# Whether or not to build shared libraries. -build_libtool_libs=$enable_shared - -# Whether or not to build static libraries. -build_old_libs=$enable_static - -# Whether or not to add -lc for building shared libraries. -build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1) - -# Whether or not to disallow shared libs when runtime libs are static -allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) - -# Whether or not to optimize for fast installation. -fast_install=$enable_fast_install - -# The host system. -host_alias=$host_alias -host=$host -host_os=$host_os - -# The build system. -build_alias=$build_alias -build=$build -build_os=$build_os - -# An echo program that does not interpret backslashes. -echo=$lt_echo - -# The archiver. -AR=$lt_AR -AR_FLAGS=$lt_AR_FLAGS - -# A C compiler. -LTCC=$lt_LTCC - -# LTCC compiler flags. -LTCFLAGS=$lt_LTCFLAGS - -# A language-specific compiler. -CC=$lt_[]_LT_AC_TAGVAR(compiler, $1) - -# Is the compiler the GNU C compiler? -with_gcc=$_LT_AC_TAGVAR(GCC, $1) - -# An ERE matcher. -EGREP=$lt_EGREP - -# The linker used to build libraries. -LD=$lt_[]_LT_AC_TAGVAR(LD, $1) - -# Whether we need hard or soft links. -LN_S=$lt_LN_S - -# A BSD-compatible nm program. -NM=$lt_NM - -# A symbol stripping program -STRIP=$lt_STRIP - -# Used to examine libraries when file_magic_cmd begins "file" -MAGIC_CMD=$MAGIC_CMD - -# Used on cygwin: DLL creation program. -DLLTOOL="$DLLTOOL" - -# Used on cygwin: object dumper. -OBJDUMP="$OBJDUMP" - -# Used on cygwin: assembler. -AS="$AS" - -# The name of the directory that contains temporary libtool files. -objdir=$objdir - -# How to create reloadable object files. -reload_flag=$lt_reload_flag -reload_cmds=$lt_reload_cmds - -# How to pass a linker flag through the compiler. -wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) - -# Object file suffix (normally "o"). -objext="$ac_objext" - -# Old archive suffix (normally "a"). -libext="$libext" - -# Shared library suffix (normally ".so"). -shrext_cmds='$shrext_cmds' - -# Executable file suffix (normally ""). -exeext="$exeext" - -# Additional compiler flags for building library objects. -pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) -pic_mode=$pic_mode - -# What is the maximum length of a command? -max_cmd_len=$lt_cv_sys_max_cmd_len - -# Does compiler simultaneously support -c and -o options? -compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) - -# Must we lock files when doing compilation? -need_locks=$lt_need_locks - -# Do we need the lib prefix for modules? -need_lib_prefix=$need_lib_prefix - -# Do we need a version for libraries? -need_version=$need_version - -# Whether dlopen is supported. -dlopen_support=$enable_dlopen - -# Whether dlopen of programs is supported. -dlopen_self=$enable_dlopen_self - -# Whether dlopen of statically linked programs is supported. -dlopen_self_static=$enable_dlopen_self_static - -# Compiler flag to prevent dynamic linking. -link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1) - -# Compiler flag to turn off builtin functions. -no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1) - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1) - -# Compiler flag to generate thread-safe objects. -thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1) - -# Library versioning type. -version_type=$version_type - -# Format of library name prefix. -libname_spec=$lt_libname_spec - -# List of archive names. First name is the real one, the rest are links. -# The last name is the one that the linker finds with -lNAME. -library_names_spec=$lt_library_names_spec - -# The coded name of the library, if different from the real name. -soname_spec=$lt_soname_spec - -# Commands used to build and install an old-style archive. -RANLIB=$lt_RANLIB -old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1) -old_postinstall_cmds=$lt_old_postinstall_cmds -old_postuninstall_cmds=$lt_old_postuninstall_cmds - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1) - -# Create a temporary old-style archive to link instead of a shared archive. -old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) - -# Commands used to build and install a shared archive. -archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1) -archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1) -postinstall_cmds=$lt_postinstall_cmds -postuninstall_cmds=$lt_postuninstall_cmds - -# Commands used to build a loadable module (assumed same as above if empty) -module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1) -module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1) - -# Commands to strip libraries. -old_striplib=$lt_old_striplib -striplib=$lt_striplib - -# Dependencies to place before the objects being linked to create a -# shared library. -predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1) - -# Dependencies to place after the objects being linked to create a -# shared library. -postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1) - -# Dependencies to place before the objects being linked to create a -# shared library. -predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1) - -# Dependencies to place after the objects being linked to create a -# shared library. -postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1) - -# The library search path used internally by the compiler when linking -# a shared library. -compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1) - -# Method to check whether dependent libraries are shared objects. -deplibs_check_method=$lt_deplibs_check_method - -# Command to use when deplibs_check_method == file_magic. -file_magic_cmd=$lt_file_magic_cmd - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1) - -# Flag that forces no undefined symbols. -no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1) - -# Commands used to finish a libtool library installation in a directory. -finish_cmds=$lt_finish_cmds - -# Same as above, but a single script fragment to be evaled but not shown. -finish_eval=$lt_finish_eval - -# Take the output of nm and produce a listing of raw symbols and C names. -global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe - -# Transform the output of nm in a proper C declaration -global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl - -# Transform the output of nm in a C name address pair -global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address - -# This is the shared library runtime path variable. -runpath_var=$runpath_var - -# This is the shared library path variable. -shlibpath_var=$shlibpath_var - -# Is shlibpath searched before the hard-coded library search path? -shlibpath_overrides_runpath=$shlibpath_overrides_runpath - -# How to hardcode a shared library path into an executable. -hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1) - -# Whether we should hardcode library paths into libraries. -hardcode_into_libs=$hardcode_into_libs - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist. -hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) - -# If ld is used when linking, flag to hardcode \$libdir into -# a binary during linking. This must work even if \$libdir does -# not exist. -hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) - -# Whether we need a single -rpath flag with a separated argument. -hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1) - -# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the -# resulting binary. -hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1) - -# Set to yes if using the -LDIR flag during linking hardcodes DIR into the -# resulting binary. -hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1) - -# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into -# the resulting binary. -hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1) - -# Set to yes if building a shared library automatically hardcodes DIR into the library -# and all subsequent libraries and executables linked against it. -hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1) - -# Variables whose values should be saved in libtool wrapper scripts and -# restored at relink time. -variables_saved_for_relink="$variables_saved_for_relink" - -# Whether libtool must link a program against all its dependency libraries. -link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1) - -# Compile-time system search path for libraries -sys_lib_search_path_spec=$lt_sys_lib_search_path_spec - -# Run-time system search path for libraries -sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec - -# Fix the shell variable \$srcfile for the compiler. -fix_srcfile_path=$lt_fix_srcfile_path - -# Set to yes if exported symbols are required. -always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1) - -# The commands to list exported symbols. -export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1) - -# The commands to extract the exported symbol list from a shared archive. -extract_expsyms_cmds=$lt_extract_expsyms_cmds - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1) - -# Symbols that must always be exported. -include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1) - -ifelse([$1],[], -[# ### END LIBTOOL CONFIG], -[# ### END LIBTOOL TAG CONFIG: $tagname]) - -__EOF__ - -ifelse([$1],[], [ - case $host_os in - aix3*) - cat <<\EOF >> "$cfgfile" - -# AIX sometimes has problems with the GCC collect2 program. For some -# reason, if we set the COLLECT_NAMES environment variable, the problems -# vanish in a puff of smoke. -if test "X${COLLECT_NAMES+set}" != Xset; then - COLLECT_NAMES= - export COLLECT_NAMES -fi -EOF - ;; - esac - - # We use sed instead of cat because bash on DJGPP gets confused if - # if finds mixed CR/LF and LF-only lines. Since sed operates in - # text mode, it properly converts lines to CR/LF. This bash problem - # is reportedly fixed, but why not run on old versions too? - sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) - - mv -f "$cfgfile" "$ofile" || \ - (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") - chmod +x "$ofile" -]) -else - # If there is no Makefile yet, we rely on a make rule to execute - # `config.status --recheck' to rerun these tests and create the - # libtool script then. - ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` - if test -f "$ltmain_in"; then - test -f Makefile && make "$ltmain" - fi -fi -])# AC_LIBTOOL_CONFIG - - -# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME]) -# ------------------------------------------- -AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], -[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl - -_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= - -if test "$GCC" = yes; then - _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' - - AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], - lt_cv_prog_compiler_rtti_exceptions, - [-fno-rtti -fno-exceptions], [], - [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) -fi -])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI - - -# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE -# --------------------------------- -AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], -[AC_REQUIRE([AC_CANONICAL_HOST]) -AC_REQUIRE([LT_AC_PROG_SED]) -AC_REQUIRE([AC_PROG_NM]) -AC_REQUIRE([AC_OBJEXT]) -# Check for command to grab the raw symbol name followed by C symbol from nm. -AC_MSG_CHECKING([command to parse $NM output from $compiler object]) -AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], -[ -# These are sane defaults that work on at least a few old systems. -# [They come from Ultrix. What could be older than Ultrix?!! ;)] - -# Character class describing NM global symbol codes. -symcode='[[BCDEGRST]]' - -# Regexp to match symbols that can be accessed directly from C. -sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' - -# Transform an extracted symbol line into a proper C declaration -lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" - -# Transform an extracted symbol line into symbol name and symbol address -lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" - -# Define system-specific variables. -case $host_os in -aix*) - symcode='[[BCDT]]' - ;; -cygwin* | mingw* | pw32*) - symcode='[[ABCDGISTW]]' - ;; -hpux*) # Its linker distinguishes data from code symbols - if test "$host_cpu" = ia64; then - symcode='[[ABCDEGRST]]' - fi - lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" - lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" - ;; -linux* | k*bsd*-gnu) - if test "$host_cpu" = ia64; then - symcode='[[ABCDGIRSTW]]' - lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" - lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" - fi - ;; -irix* | nonstopux*) - symcode='[[BCDEGRST]]' - ;; -osf*) - symcode='[[BCDEGQRST]]' - ;; -solaris*) - symcode='[[BDRT]]' - ;; -sco3.2v5*) - symcode='[[DT]]' - ;; -sysv4.2uw2*) - symcode='[[DT]]' - ;; -sysv5* | sco5v6* | unixware* | OpenUNIX*) - symcode='[[ABDT]]' - ;; -sysv4) - symcode='[[DFNSTU]]' - ;; -esac - -# Handle CRLF in mingw tool chain -opt_cr= -case $build_os in -mingw*) - opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp - ;; -esac - -# If we're using GNU nm, then use its standard symbol codes. -case `$NM -V 2>&1` in -*GNU* | *'with BFD'*) - symcode='[[ABCDGIRSTW]]' ;; -esac - -# Try without a prefix undercore, then with it. -for ac_symprfx in "" "_"; do - - # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. - symxfrm="\\1 $ac_symprfx\\2 \\2" - - # Write the raw and C identifiers. - lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" - - # Check to see that the pipe works correctly. - pipe_works=no - - rm -f conftest* - cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then - # Try sorting and uniquifying the output. - if sort "$nlist" | uniq > "$nlist"T; then - mv -f "$nlist"T "$nlist" - else - rm -f "$nlist"T - fi - - # Make sure that we snagged all the symbols we need. - if grep ' nm_test_var$' "$nlist" >/dev/null; then - if grep ' nm_test_func$' "$nlist" >/dev/null; then - cat < conftest.$ac_ext -#ifdef __cplusplus -extern "C" { -#endif - -EOF - # Now generate the symbol file. - eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' - - cat <> conftest.$ac_ext -#if defined (__STDC__) && __STDC__ -# define lt_ptr_t void * -#else -# define lt_ptr_t char * -# define const -#endif - -/* The mapping between symbol names and symbols. */ -const struct { - const char *name; - lt_ptr_t address; -} -lt_preloaded_symbols[[]] = -{ -EOF - $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext - cat <<\EOF >> conftest.$ac_ext - {0, (lt_ptr_t) 0} -}; - -#ifdef __cplusplus -} -#endif -EOF - # Now try linking the two files. - mv conftest.$ac_objext conftstm.$ac_objext - lt_save_LIBS="$LIBS" - lt_save_CFLAGS="$CFLAGS" - LIBS="conftstm.$ac_objext" - CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" - if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then - pipe_works=yes - fi - LIBS="$lt_save_LIBS" - CFLAGS="$lt_save_CFLAGS" - else - echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD - fi - else - echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD - fi - else - echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD - fi - else - echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD - cat conftest.$ac_ext >&5 - fi - rm -f conftest* conftst* - - # Do not use the global_symbol_pipe unless it works. - if test "$pipe_works" = yes; then - break - else - lt_cv_sys_global_symbol_pipe= - fi -done -]) -if test -z "$lt_cv_sys_global_symbol_pipe"; then - lt_cv_sys_global_symbol_to_cdecl= -fi -if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then - AC_MSG_RESULT(failed) -else - AC_MSG_RESULT(ok) -fi -]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE - - -# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME]) -# --------------------------------------- -AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC], -[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)= -_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= -_LT_AC_TAGVAR(lt_prog_compiler_static, $1)= - -AC_MSG_CHECKING([for $compiler option to produce PIC]) - ifelse([$1],[CXX],[ - # C++ specific cases for pic, static, wl, etc. - if test "$GXX" = yes; then - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - fi - ;; - amigaos*) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the `-m68020' flag to GCC prevents building anything better, - # like `-m68040'. - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' - ;; - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - mingw* | cygwin* | os2* | pw32*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' - ;; - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' - ;; - *djgpp*) - # DJGPP does not support shared libraries at all - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= - ;; - interix[[3-9]]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - sysv4*MP*) - if test -d /usr/nec; then - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic - fi - ;; - hpux*) - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - ;; - *) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - esac - ;; - *) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - esac - else - case $host_os in - aix4* | aix5*) - # All AIX code is PIC. - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - else - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' - fi - ;; - chorus*) - case $cc_basename in - cxch68*) - # Green Hills C++ Compiler - # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" - ;; - esac - ;; - darwin*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - case $cc_basename in - xlc*) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - ;; - esac - ;; - dgux*) - case $cc_basename in - ec++*) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - ;; - ghcx*) - # Green Hills C++ Compiler - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' - ;; - *) - ;; - esac - ;; - freebsd* | dragonfly*) - # FreeBSD uses GNU C++ - ;; - hpux9* | hpux10* | hpux11*) - case $cc_basename in - CC*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' - if test "$host_cpu" != ia64; then - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' - fi - ;; - aCC*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' - ;; - esac - ;; - *) - ;; - esac - ;; - interix*) - # This is c89, which is MS Visual C++ (no shared libs) - # Anyone wants to do a port? - ;; - irix5* | irix6* | nonstopux*) - case $cc_basename in - CC*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - # CC pic flag -KPIC is the default. - ;; - *) - ;; - esac - ;; - linux* | k*bsd*-gnu) - case $cc_basename in - KCC*) - # KAI C++ Compiler - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - icpc* | ecpc*) - # Intel C++ - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' - ;; - pgCC*) - # Portland Group C++ compiler. - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - cxx*) - # Compaq C++ - # Make sure the PIC flag is empty. It appears that all Alpha - # Linux and Compaq Tru64 Unix objects are PIC. - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) - # Sun C++ 5.9 - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' - ;; - esac - ;; - esac - ;; - lynxos*) - ;; - m88k*) - ;; - mvs*) - case $cc_basename in - cxx*) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' - ;; - *) - ;; - esac - ;; - netbsd* | netbsdelf*-gnu) - ;; - osf3* | osf4* | osf5*) - case $cc_basename in - KCC*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' - ;; - RCC*) - # Rational C++ 2.4.1 - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' - ;; - cxx*) - # Digital/Compaq C++ - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - # Make sure the PIC flag is empty. It appears that all Alpha - # Linux and Compaq Tru64 Unix objects are PIC. - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - ;; - *) - ;; - esac - ;; - psos*) - ;; - solaris*) - case $cc_basename in - CC*) - # Sun C++ 4.2, 5.x and Centerline C++ - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' - ;; - gcx*) - # Green Hills C++ Compiler - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' - ;; - *) - ;; - esac - ;; - sunos4*) - case $cc_basename in - CC*) - # Sun C++ 4.x - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - lcc*) - # Lucid - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' - ;; - *) - ;; - esac - ;; - tandem*) - case $cc_basename in - NCC*) - # NonStop-UX NCC 3.20 - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - ;; - *) - ;; - esac - ;; - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - case $cc_basename in - CC*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - esac - ;; - vxworks*) - ;; - *) - _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no - ;; - esac - fi -], -[ - if test "$GCC" = yes; then - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - fi - ;; - - amigaos*) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the `-m68020' flag to GCC prevents building anything better, - # like `-m68040'. - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - - mingw* | cygwin* | pw32* | os2*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' - ;; - - interix[[3-9]]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - - msdosdjgpp*) - # Just because we use GCC doesn't mean we suddenly get shared libraries - # on systems that don't support them. - _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no - enable_shared=no - ;; - - sysv4*MP*) - if test -d /usr/nec; then - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic - fi - ;; - - hpux*) - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - esac - ;; - - *) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - esac - else - # PORTME Check for flag to pass linker flags through the system compiler. - case $host_os in - aix*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - else - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' - fi - ;; - darwin*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - case $cc_basename in - xlc*) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - ;; - esac - ;; - - mingw* | cygwin* | pw32* | os2*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' - ;; - - hpux9* | hpux10* | hpux11*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' - ;; - esac - # Is there a better lt_prog_compiler_static that works with the bundled CC? - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' - ;; - - irix5* | irix6* | nonstopux*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - # PIC (with -KPIC) is the default. - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - ;; - - newsos6) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - - linux* | k*bsd*-gnu) - case $cc_basename in - icc* | ecc*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' - ;; - pgcc* | pgf77* | pgf90* | pgf95*) - # Portland Group compilers (*not* the Pentium gcc compiler, - # which looks to be a dead project) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - ccc*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - # All Alpha code is PIC. - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) - # Sun C 5.9 - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - ;; - *Sun\ F*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='' - ;; - esac - ;; - esac - ;; - - osf3* | osf4* | osf5*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - # All OSF/1 code is PIC. - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - ;; - - rdos*) - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - ;; - - solaris*) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - case $cc_basename in - f77* | f90* | f95*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; - *) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; - esac - ;; - - sunos4*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - - sysv4*MP*) - if test -d /usr/nec ;then - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - fi - ;; - - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - - unicos*) - _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no - ;; - - uts4*) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' - _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - - *) - _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no - ;; - esac - fi -]) -AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)]) - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then - AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works], - _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1), - [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [], - [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in - "" | " "*) ;; - *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;; - esac], - [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= - _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) -fi -case $host_os in - # For platforms which do not support PIC, -DPIC is meaningless: - *djgpp*) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= - ;; - *) - _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])" - ;; -esac - -# -# Check to make sure the static flag actually works. -# -wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_AC_TAGVAR(lt_prog_compiler_static, $1)\" -AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], - _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1), - $lt_tmp_static_flag, - [], - [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=]) -]) - - -# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME]) -# ------------------------------------ -# See if the linker supports building shared libraries. -AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS], -[AC_REQUIRE([LT_AC_PROG_SED])dnl -AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) -ifelse([$1],[CXX],[ - _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - case $host_os in - aix4* | aix5*) - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to AIX nm, but means don't demangle with GNU nm - if $NM -V 2>&1 | grep 'GNU' > /dev/null; then - _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' - else - _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' - fi - ;; - pw32*) - _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" - ;; - cygwin* | mingw*) - _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' - ;; - linux* | k*bsd*-gnu) - _LT_AC_TAGVAR(link_all_deplibs, $1)=no - ;; - *) - _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - ;; - esac -],[ - runpath_var= - _LT_AC_TAGVAR(allow_undefined_flag, $1)= - _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no - _LT_AC_TAGVAR(archive_cmds, $1)= - _LT_AC_TAGVAR(archive_expsym_cmds, $1)= - _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)= - _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)= - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= - _LT_AC_TAGVAR(thread_safe_flag_spec, $1)= - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= - _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= - _LT_AC_TAGVAR(hardcode_direct, $1)=no - _LT_AC_TAGVAR(hardcode_minus_L, $1)=no - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported - _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown - _LT_AC_TAGVAR(hardcode_automatic, $1)=no - _LT_AC_TAGVAR(module_cmds, $1)= - _LT_AC_TAGVAR(module_expsym_cmds, $1)= - _LT_AC_TAGVAR(always_export_symbols, $1)=no - _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - # include_expsyms should be a list of space-separated symbols to be *always* - # included in the symbol list - _LT_AC_TAGVAR(include_expsyms, $1)= - # exclude_expsyms can be an extended regexp of symbols to exclude - # it will be wrapped by ` (' and `)$', so one must not match beginning or - # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', - # as well as any symbol that contains `d'. - _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_" - # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out - # platforms (ab)use it in PIC code, but their linkers get confused if - # the symbol is explicitly referenced. Since portable code cannot - # rely on this symbol name, it's probably fine to never include it in - # preloaded symbol tables. - extract_expsyms_cmds= - # Just being paranoid about ensuring that cc_basename is set. - _LT_CC_BASENAME([$compiler]) - case $host_os in - cygwin* | mingw* | pw32*) - # FIXME: the MSVC++ port hasn't been tested in a loooong time - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - if test "$GCC" != yes; then - with_gnu_ld=no - fi - ;; - interix*) - # we just hope/assume this is gcc and not c89 (= MSVC++) - with_gnu_ld=yes - ;; - openbsd*) - with_gnu_ld=no - ;; - esac - - _LT_AC_TAGVAR(ld_shlibs, $1)=yes - if test "$with_gnu_ld" = yes; then - # If archive_cmds runs LD, not CC, wlarc should be empty - wlarc='${wl}' - - # Set some defaults for GNU ld with shared library support. These - # are reset later if shared libraries are not supported. Putting them - # here allows them to be overridden if necessary. - runpath_var=LD_RUN_PATH - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' - # ancient GNU ld didn't support --whole-archive et. al. - if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - else - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= - fi - supports_anon_versioning=no - case `$LD -v 2>/dev/null` in - *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 - *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... - *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... - *\ 2.11.*) ;; # other 2.11 versions - *) supports_anon_versioning=yes ;; - esac - - # See if GNU ld supports shared libraries. - case $host_os in - aix3* | aix4* | aix5*) - # On AIX/PPC, the GNU linker is very broken - if test "$host_cpu" != ia64; then - _LT_AC_TAGVAR(ld_shlibs, $1)=no - cat <&2 - -*** Warning: the GNU linker, at least up to release 2.9.1, is reported -*** to be unable to reliably create shared libraries on AIX. -*** Therefore, libtool is disabling shared libraries support. If you -*** really care for shared libraries, you may want to modify your PATH -*** so that a non-GNU linker is found, and then restart. - -EOF - fi - ;; - - amigaos*) - _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - - # Samuel A. Falvo II reports - # that the semantics of dynamic libraries on AmigaOS, at least up - # to version 4, is to share data among multiple programs linked - # with the same dynamic library. Since this doesn't match the - # behavior of shared libraries on other platforms, we can't use - # them. - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - - beos*) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported - # Joseph Beckenbach says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - else - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - - cygwin* | mingw* | pw32*) - # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, - # as there is no search path for DLLs. - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported - _LT_AC_TAGVAR(always_export_symbols, $1)=no - _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes - _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' - - if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file (1st line - # is EXPORTS), use it as is; otherwise, prepend... - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - else - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - - interix[[3-9]]*) - _LT_AC_TAGVAR(hardcode_direct, $1)=no - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' - # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. - # Instead, shared libraries are loaded at an image base (0x10000000 by - # default) and relocated if they conflict, which is a slow very memory - # consuming and fragmenting process. To avoid this, we pick a random, - # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link - # time. Moving up from 0x10000000 also allows more sbrk(2) space. - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - ;; - - gnu* | linux* | k*bsd*-gnu) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - tmp_addflag= - case $cc_basename,$host_cpu in - pgcc*) # Portland Group C compiler - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' - tmp_addflag=' $pic_flag' - ;; - pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' - tmp_addflag=' $pic_flag -Mnomain' ;; - ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 - tmp_addflag=' -i_dynamic' ;; - efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 - tmp_addflag=' -i_dynamic -nofor_main' ;; - ifc* | ifort*) # Intel Fortran compiler - tmp_addflag=' -nofor_main' ;; - esac - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) # Sun C 5.9 - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' - tmp_sharedflag='-G' ;; - *Sun\ F*) # Sun Fortran 8.3 - tmp_sharedflag='-G' ;; - *) - tmp_sharedflag='-shared' ;; - esac - _LT_AC_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - - if test $supports_anon_versioning = yes; then - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - $echo "local: *; };" >> $output_objdir/$libname.ver~ - $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' - fi - _LT_AC_TAGVAR(link_all_deplibs, $1)=no - else - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' - wlarc= - else - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - fi - ;; - - solaris*) - if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then - _LT_AC_TAGVAR(ld_shlibs, $1)=no - cat <&2 - -*** Warning: The releases 2.8.* of the GNU linker cannot reliably -*** create shared libraries on Solaris systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.9.1 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -EOF - elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) - case `$LD -v 2>&1` in - *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) - _LT_AC_TAGVAR(ld_shlibs, $1)=no - cat <<_LT_EOF 1>&2 - -*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not -*** reliably create shared libraries on SCO systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.16.91.0.3 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - ;; - *) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' - else - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - esac - ;; - - sunos4*) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' - wlarc= - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - *) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - esac - - if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no; then - runpath_var= - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= - fi - else - # PORTME fill in a description of your system's linker (not GNU ld) - case $host_os in - aix3*) - _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported - _LT_AC_TAGVAR(always_export_symbols, $1)=yes - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' - # Note: this linker hardcodes the directories in LIBPATH if there - # are no directories specified by -L. - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then - # Neither direct hardcoding nor static linking is supported with a - # broken collect2. - _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported - fi - ;; - - aix4* | aix5*) - if test "$host_cpu" = ia64; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag="" - else - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to AIX nm, but means don't demangle with GNU nm - if $NM -V 2>&1 | grep 'GNU' > /dev/null; then - _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' - else - _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' - fi - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # need to do runtime linking. - case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) - for ld_flag in $LDFLAGS; do - if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then - aix_use_runtimelinking=yes - break - fi - done - ;; - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - _LT_AC_TAGVAR(archive_cmds, $1)='' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' - _LT_AC_TAGVAR(link_all_deplibs, $1)=yes - - if test "$GCC" = yes; then - case $host_os in aix4.[[012]]|aix4.[[012]].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`${CC} -print-prog-name=collect2` - if test -f "$collect2name" && \ - strings "$collect2name" | grep resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= - fi - ;; - esac - shared_flag='-shared' - if test "$aix_use_runtimelinking" = yes; then - shared_flag="$shared_flag "'${wl}-G' - fi - else - # not using gcc - if test "$host_cpu" = ia64; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test "$aix_use_runtimelinking" = yes; then - shared_flag='${wl}-G' - else - shared_flag='${wl}-bM:SRE' - fi - fi - fi - - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to export. - _LT_AC_TAGVAR(always_export_symbols, $1)=yes - if test "$aix_use_runtimelinking" = yes; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' - # Determine the default libpath from the value encoded in an empty executable. - _LT_AC_SYS_LIBPATH_AIX - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" - _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" - else - if test "$host_cpu" = ia64; then - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' - _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" - _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an empty executable. - _LT_AC_SYS_LIBPATH_AIX - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' - # Exported symbols can be pulled into shared objects from archives - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience' - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes - # This is similar to how AIX traditionally builds its shared libraries. - _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' - fi - fi - ;; - - amigaos*) - _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - # see comment about different semantics on the GNU ld section - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - - bsdi[[45]]*) - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic - ;; - - cygwin* | mingw* | pw32*) - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' - _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=".dll" - # FIXME: Setting linknames here is a bad hack. - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' - # The linker will automatically build a .lib file if we build a DLL. - _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true' - # FIXME: Should let the user specify the lib program. - _LT_AC_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' - _LT_AC_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' - _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes - ;; - - darwin* | rhapsody*) - case $host_os in - rhapsody* | darwin1.[[012]]) - _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress' - ;; - *) # Darwin 1.3 on - if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then - _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' - else - case ${MACOSX_DEPLOYMENT_TARGET} in - 10.[[012]]) - _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' - ;; - 10.*) - _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup' - ;; - esac - fi - ;; - esac - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no - _LT_AC_TAGVAR(hardcode_direct, $1)=no - _LT_AC_TAGVAR(hardcode_automatic, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' - _LT_AC_TAGVAR(link_all_deplibs, $1)=yes - if test "$GCC" = yes ; then - output_verbose_link_cmd='echo' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' - _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' - # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - else - case $cc_basename in - xlc*) - output_verbose_link_cmd='echo' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring' - _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' - # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - ;; - *) - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - esac - fi - ;; - - dgux*) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - freebsd1*) - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - - # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor - # support. Future versions do this automatically, but an explicit c++rt0.o - # does not break anything, and helps significantly (at the cost of a little - # extra space). - freebsd2.2*) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - # Unfortunately, older versions of FreeBSD 2 do not have this feature. - freebsd2*) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - # FreeBSD 3 and greater uses gcc -shared to do shared libraries. - freebsd* | dragonfly*) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - hpux9*) - if test "$GCC" = yes; then - _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - else - _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - fi - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' - ;; - - hpux10*) - if test "$GCC" = yes -a "$with_gnu_ld" = no; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - else - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' - fi - if test "$with_gnu_ld" = no; then - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - fi - ;; - - hpux11*) - if test "$GCC" = yes -a "$with_gnu_ld" = no; then - case $host_cpu in - hppa*64*) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - else - case $host_cpu in - hppa*64*) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - fi - if test "$with_gnu_ld" = no; then - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - - case $host_cpu in - hppa*64*|ia64*) - _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' - _LT_AC_TAGVAR(hardcode_direct, $1)=no - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - *) - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - ;; - esac - fi - ;; - - irix5* | irix6* | nonstopux*) - if test "$GCC" = yes; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - else - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' - fi - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - _LT_AC_TAGVAR(link_all_deplibs, $1)=yes - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out - else - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF - fi - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - newsos6) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - openbsd*) - if test -f /usr/libexec/ld.so; then - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' - else - case $host_os in - openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - ;; - *) - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' - ;; - esac - fi - else - _LT_AC_TAGVAR(ld_shlibs, $1)=no - fi - ;; - - os2*) - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported - _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' - _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' - ;; - - osf3*) - if test "$GCC" = yes; then - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - else - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - fi - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - ;; - - osf4* | osf5*) # as osf3* with the addition of -msym flag - if test "$GCC" = yes; then - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' - else - _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ - $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' - - # Both c and cxx compiler support -rpath directly - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' - fi - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: - ;; - - solaris*) - _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' - if test "$GCC" = yes; then - wlarc='${wl}' - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' - else - wlarc='' - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' - fi - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - case $host_os in - solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; - *) - # The compiler driver will combine and reorder linker options, - # but understands `-z linker_flag'. GCC discards it without `$wl', - # but is careful enough not to reorder. - # Supported since Solaris 2.6 (maybe 2.5.1?) - if test "$GCC" = yes; then - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' - else - _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' - fi - ;; - esac - _LT_AC_TAGVAR(link_all_deplibs, $1)=yes - ;; - - sunos4*) - if test "x$host_vendor" = xsequent; then - # Use $CC to link under sequent, because it throws in some extra .o - # files that make .init and .fini sections work. - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' - else - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' - fi - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes - _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - sysv4) - case $host_vendor in - sni) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true??? - ;; - siemens) - ## LD is ld it makes a PLAMLIB - ## CC just makes a GrossModule. - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' - _LT_AC_TAGVAR(hardcode_direct, $1)=no - ;; - motorola) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie - ;; - esac - runpath_var='LD_RUN_PATH' - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - sysv4.3*) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - runpath_var=LD_RUN_PATH - hardcode_runpath_var=yes - _LT_AC_TAGVAR(ld_shlibs, $1)=yes - fi - ;; - - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) - _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - runpath_var='LD_RUN_PATH' - - if test "$GCC" = yes; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - sysv5* | sco3.2v5* | sco5v6*) - # Note: We can NOT use -z defs as we might desire, because we do not - # link with -lc, and that would cause any symbols used from libc to - # always be unresolved, which means just about no library would - # ever link correctly. If we're not using GNU ld we use -z text - # though, which does catch some bad symbols but isn't as heavy-handed - # as -z defs. - _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' - _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' - _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' - _LT_AC_TAGVAR(link_all_deplibs, $1)=yes - _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' - runpath_var='LD_RUN_PATH' - - if test "$GCC" = yes; then - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - else - _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - uts4*) - _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - *) - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - esac - fi -]) -AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) -test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no - -# -# Do we need to explicitly link libc? -# -case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in -x|xyes) - # Assume -lc should be added - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes - - if test "$enable_shared" = yes && test "$GCC" = yes; then - case $_LT_AC_TAGVAR(archive_cmds, $1) in - *'~'*) - # FIXME: we may have to deal with multi-command sequences. - ;; - '$CC '*) - # Test whether the compiler implicitly links with -lc since on some - # systems, -lgcc has to come before -lc. If gcc already passes -lc - # to ld, don't add -lc before -lgcc. - AC_MSG_CHECKING([whether -lc should be explicitly linked in]) - $rm conftest* - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - if AC_TRY_EVAL(ac_compile) 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) - pic_flag=$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1) - _LT_AC_TAGVAR(allow_undefined_flag, $1)= - if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) - then - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no - else - _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes - fi - _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $rm conftest* - AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)]) - ;; - esac - fi - ;; -esac -])# AC_LIBTOOL_PROG_LD_SHLIBS - - -# _LT_AC_FILE_LTDLL_C -# ------------------- -# Be careful that the start marker always follows a newline. -AC_DEFUN([_LT_AC_FILE_LTDLL_C], [ -# /* ltdll.c starts here */ -# #define WIN32_LEAN_AND_MEAN -# #include -# #undef WIN32_LEAN_AND_MEAN -# #include -# -# #ifndef __CYGWIN__ -# # ifdef __CYGWIN32__ -# # define __CYGWIN__ __CYGWIN32__ -# # endif -# #endif -# -# #ifdef __cplusplus -# extern "C" { -# #endif -# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); -# #ifdef __cplusplus -# } -# #endif -# -# #ifdef __CYGWIN__ -# #include -# DECLARE_CYGWIN_DLL( DllMain ); -# #endif -# HINSTANCE __hDllInstance_base; -# -# BOOL APIENTRY -# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) -# { -# __hDllInstance_base = hInst; -# return TRUE; -# } -# /* ltdll.c ends here */ -])# _LT_AC_FILE_LTDLL_C - - -# _LT_AC_TAGVAR(VARNAME, [TAGNAME]) -# --------------------------------- -AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])]) - - -# old names -AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) -AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) -AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) -AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) -AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) -AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) -AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) - -# This is just to silence aclocal about the macro not being used -ifelse([AC_DISABLE_FAST_INSTALL]) - -AC_DEFUN([LT_AC_PROG_GCJ], -[AC_CHECK_TOOL(GCJ, gcj, no) - test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" - AC_SUBST(GCJFLAGS) -]) - -AC_DEFUN([LT_AC_PROG_RC], -[AC_CHECK_TOOL(RC, windres, no) -]) - - -# Cheap backport of AS_EXECUTABLE_P and required macros -# from Autoconf 2.59; we should not use $as_executable_p directly. - -# _AS_TEST_PREPARE -# ---------------- -m4_ifndef([_AS_TEST_PREPARE], -[m4_defun([_AS_TEST_PREPARE], -[if test -x / >/dev/null 2>&1; then - as_executable_p='test -x' -else - as_executable_p='test -f' -fi -])])# _AS_TEST_PREPARE - -# AS_EXECUTABLE_P -# --------------- -# Check whether a file is executable. -m4_ifndef([AS_EXECUTABLE_P], -[m4_defun([AS_EXECUTABLE_P], -[AS_REQUIRE([_AS_TEST_PREPARE])dnl -$as_executable_p $1[]dnl -])])# AS_EXECUTABLE_P - -############################################################ -# NOTE: This macro has been submitted for inclusion into # -# GNU Autoconf as AC_PROG_SED. When it is available in # -# a released version of Autoconf we should remove this # -# macro and use it instead. # -############################################################ -# LT_AC_PROG_SED -# -------------- -# Check for a fully-functional sed program, that truncates -# as few characters as possible. Prefer GNU sed if found. -AC_DEFUN([LT_AC_PROG_SED], -[AC_MSG_CHECKING([for a sed that does not truncate output]) -AC_CACHE_VAL(lt_cv_path_SED, -[# Loop through the user's path and test for sed and gsed. -# Then use that list of sed's as ones to test for truncation. -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for lt_ac_prog in sed gsed; do - for ac_exec_ext in '' $ac_executable_extensions; do - if AS_EXECUTABLE_P(["$as_dir/$lt_ac_prog$ac_exec_ext"]); then - lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" - fi - done - done -done -IFS=$as_save_IFS -lt_ac_max=0 -lt_ac_count=0 -# Add /usr/xpg4/bin/sed as it is typically found on Solaris -# along with /bin/sed that truncates output. -for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do - test ! -f $lt_ac_sed && continue - cat /dev/null > conftest.in - lt_ac_count=0 - echo $ECHO_N "0123456789$ECHO_C" >conftest.in - # Check for GNU sed and select it if it is found. - if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then - lt_cv_path_SED=$lt_ac_sed - break - fi - while true; do - cat conftest.in conftest.in >conftest.tmp - mv conftest.tmp conftest.in - cp conftest.in conftest.nl - echo >>conftest.nl - $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break - cmp -s conftest.out conftest.nl || break - # 10000 chars as input seems more than enough - test $lt_ac_count -gt 10 && break - lt_ac_count=`expr $lt_ac_count + 1` - if test $lt_ac_count -gt $lt_ac_max; then - lt_ac_max=$lt_ac_count - lt_cv_path_SED=$lt_ac_sed - fi - done -done -]) -SED=$lt_cv_path_SED -AC_SUBST([SED]) -AC_MSG_RESULT([$SED]) -]) -## ltdl.m4 - Configure ltdl for the target system. -*-Autoconf-*- -## Copyright (C) 1999-2006 Free Software Foundation, Inc. -## -## This file is free software; the Free Software Foundation gives -## unlimited permission to copy and/or distribute it, with or without -## modifications, as long as this notice is preserved. - -# serial 8 AC_LIB_LTDL - -# AC_WITH_LTDL -# ------------ -# Clients of libltdl can use this macro to allow the installer to -# choose between a shipped copy of the ltdl sources or a preinstalled -# version of the library. -AC_DEFUN([AC_WITH_LTDL], -[AC_REQUIRE([AC_LIB_LTDL]) -AC_SUBST([LIBLTDL]) -AC_SUBST([INCLTDL]) - -# Unless the user asks us to check, assume no installed ltdl exists. -use_installed_libltdl=no - -AC_ARG_WITH([included_ltdl], - [ --with-included-ltdl use the GNU ltdl sources included here]) - -if test "x$with_included_ltdl" != xyes; then - # We are not being forced to use the included libltdl sources, so - # decide whether there is a useful installed version we can use. - AC_CHECK_HEADER([ltdl.h], - [AC_CHECK_LIB([ltdl], [lt_dlcaller_register], - [with_included_ltdl=no], - [with_included_ltdl=yes]) - ]) -fi - -if test "x$enable_ltdl_install" != xyes; then - # If the user did not specify an installable libltdl, then default - # to a convenience lib. - AC_LIBLTDL_CONVENIENCE -fi - -if test "x$with_included_ltdl" = xno; then - # If the included ltdl is not to be used. then Use the - # preinstalled libltdl we found. - AC_DEFINE([HAVE_LTDL], [1], - [Define this if a modern libltdl is already installed]) - LIBLTDL=-lltdl -fi - -# Report our decision... -AC_MSG_CHECKING([whether to use included libltdl]) -AC_MSG_RESULT([$with_included_ltdl]) - -AC_CONFIG_SUBDIRS([libltdl]) -])# AC_WITH_LTDL - - -# AC_LIB_LTDL -# ----------- -# Perform all the checks necessary for compilation of the ltdl objects -# -- including compiler checks and header checks. -AC_DEFUN([AC_LIB_LTDL], -[AC_PREREQ(2.50) -AC_REQUIRE([AC_PROG_CC]) -AC_REQUIRE([AC_C_CONST]) -AC_REQUIRE([AC_HEADER_STDC]) -AC_REQUIRE([AC_HEADER_DIRENT]) -AC_REQUIRE([_LT_AC_CHECK_DLFCN]) -AC_REQUIRE([AC_LTDL_ENABLE_INSTALL]) -AC_REQUIRE([AC_LTDL_SHLIBEXT]) -AC_REQUIRE([AC_LTDL_SHLIBPATH]) -AC_REQUIRE([AC_LTDL_SYSSEARCHPATH]) -AC_REQUIRE([AC_LTDL_OBJDIR]) -AC_REQUIRE([AC_LTDL_DLPREOPEN]) -AC_REQUIRE([AC_LTDL_DLLIB]) -AC_REQUIRE([AC_LTDL_SYMBOL_USCORE]) -AC_REQUIRE([AC_LTDL_DLSYM_USCORE]) -AC_REQUIRE([AC_LTDL_SYS_DLOPEN_DEPLIBS]) -AC_REQUIRE([AC_LTDL_FUNC_ARGZ]) - -AC_CHECK_HEADERS([assert.h ctype.h errno.h malloc.h memory.h stdlib.h \ - stdio.h unistd.h]) -AC_CHECK_HEADERS([dl.h sys/dl.h dld.h mach-o/dyld.h]) -AC_CHECK_HEADERS([string.h strings.h], [break]) - -AC_CHECK_FUNCS([strchr index], [break]) -AC_CHECK_FUNCS([strrchr rindex], [break]) -AC_CHECK_FUNCS([memcpy bcopy], [break]) -AC_CHECK_FUNCS([memmove strcmp]) -AC_CHECK_FUNCS([closedir opendir readdir]) -])# AC_LIB_LTDL - - -# AC_LTDL_ENABLE_INSTALL -# ---------------------- -AC_DEFUN([AC_LTDL_ENABLE_INSTALL], -[AC_ARG_ENABLE([ltdl-install], - [AC_HELP_STRING([--enable-ltdl-install], [install libltdl])]) - -AM_CONDITIONAL(INSTALL_LTDL, test x"${enable_ltdl_install-no}" != xno) -AM_CONDITIONAL(CONVENIENCE_LTDL, test x"${enable_ltdl_convenience-no}" != xno) -])# AC_LTDL_ENABLE_INSTALL - - -# AC_LTDL_SYS_DLOPEN_DEPLIBS -# -------------------------- -AC_DEFUN([AC_LTDL_SYS_DLOPEN_DEPLIBS], -[AC_REQUIRE([AC_CANONICAL_HOST]) -AC_CACHE_CHECK([whether deplibs are loaded by dlopen], - [libltdl_cv_sys_dlopen_deplibs], - [# PORTME does your system automatically load deplibs for dlopen? - # or its logical equivalent (e.g. shl_load for HP-UX < 11) - # For now, we just catch OSes we know something about -- in the - # future, we'll try test this programmatically. - libltdl_cv_sys_dlopen_deplibs=unknown - case "$host_os" in - aix3*|aix4.1.*|aix4.2.*) - # Unknown whether this is true for these versions of AIX, but - # we want this `case' here to explicitly catch those versions. - libltdl_cv_sys_dlopen_deplibs=unknown - ;; - aix[[45]]*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - darwin*) - # Assuming the user has installed a libdl from somewhere, this is true - # If you are looking for one http://www.opendarwin.org/projects/dlcompat - libltdl_cv_sys_dlopen_deplibs=yes - ;; - freebsd* | dragonfly*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - gnu* | linux* | k*bsd*-gnu) - # GNU and its variants, using gnu ld.so (Glibc) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - hpux10*|hpux11*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - interix*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - irix[[12345]]*|irix6.[[01]]*) - # Catch all versions of IRIX before 6.2, and indicate that we don't - # know how it worked for any of those versions. - libltdl_cv_sys_dlopen_deplibs=unknown - ;; - irix*) - # The case above catches anything before 6.2, and it's known that - # at 6.2 and later dlopen does load deplibs. - libltdl_cv_sys_dlopen_deplibs=yes - ;; - netbsd* | netbsdelf*-gnu) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - openbsd*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - osf[[1234]]*) - # dlopen did load deplibs (at least at 4.x), but until the 5.x series, - # it did *not* use an RPATH in a shared library to find objects the - # library depends on, so we explictly say `no'. - libltdl_cv_sys_dlopen_deplibs=no - ;; - osf5.0|osf5.0a|osf5.1) - # dlopen *does* load deplibs and with the right loader patch applied - # it even uses RPATH in a shared library to search for shared objects - # that the library depends on, but there's no easy way to know if that - # patch is installed. Since this is the case, all we can really - # say is unknown -- it depends on the patch being installed. If - # it is, this changes to `yes'. Without it, it would be `no'. - libltdl_cv_sys_dlopen_deplibs=unknown - ;; - osf*) - # the two cases above should catch all versions of osf <= 5.1. Read - # the comments above for what we know about them. - # At > 5.1, deplibs are loaded *and* any RPATH in a shared library - # is used to find them so we can finally say `yes'. - libltdl_cv_sys_dlopen_deplibs=yes - ;; - solaris*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - esac - ]) -if test "$libltdl_cv_sys_dlopen_deplibs" != yes; then - AC_DEFINE([LTDL_DLOPEN_DEPLIBS], [1], - [Define if the OS needs help to load dependent libraries for dlopen().]) -fi -])# AC_LTDL_SYS_DLOPEN_DEPLIBS - - -# AC_LTDL_SHLIBEXT -# ---------------- -AC_DEFUN([AC_LTDL_SHLIBEXT], -[AC_REQUIRE([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) -AC_CACHE_CHECK([which extension is used for loadable modules], - [libltdl_cv_shlibext], -[ -module=yes -eval libltdl_cv_shlibext=$shrext_cmds - ]) -if test -n "$libltdl_cv_shlibext"; then - AC_DEFINE_UNQUOTED([LTDL_SHLIB_EXT], ["$libltdl_cv_shlibext"], - [Define to the extension used for shared libraries, say, ".so".]) -fi -])# AC_LTDL_SHLIBEXT - - -# AC_LTDL_SHLIBPATH -# ----------------- -AC_DEFUN([AC_LTDL_SHLIBPATH], -[AC_REQUIRE([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) -AC_CACHE_CHECK([which variable specifies run-time library path], - [libltdl_cv_shlibpath_var], [libltdl_cv_shlibpath_var="$shlibpath_var"]) -if test -n "$libltdl_cv_shlibpath_var"; then - AC_DEFINE_UNQUOTED([LTDL_SHLIBPATH_VAR], ["$libltdl_cv_shlibpath_var"], - [Define to the name of the environment variable that determines the dynamic library search path.]) -fi -])# AC_LTDL_SHLIBPATH - - -# AC_LTDL_SYSSEARCHPATH -# --------------------- -AC_DEFUN([AC_LTDL_SYSSEARCHPATH], -[AC_REQUIRE([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) -AC_CACHE_CHECK([for the default library search path], - [libltdl_cv_sys_search_path], - [libltdl_cv_sys_search_path="$sys_lib_dlsearch_path_spec"]) -if test -n "$libltdl_cv_sys_search_path"; then - sys_search_path= - for dir in $libltdl_cv_sys_search_path; do - if test -z "$sys_search_path"; then - sys_search_path="$dir" - else - sys_search_path="$sys_search_path$PATH_SEPARATOR$dir" - fi - done - AC_DEFINE_UNQUOTED([LTDL_SYSSEARCHPATH], ["$sys_search_path"], - [Define to the system default library search path.]) -fi -])# AC_LTDL_SYSSEARCHPATH - - -# AC_LTDL_OBJDIR -# -------------- -AC_DEFUN([AC_LTDL_OBJDIR], -[AC_CACHE_CHECK([for objdir], - [libltdl_cv_objdir], - [libltdl_cv_objdir="$objdir" - if test -n "$objdir"; then - : - else - rm -f .libs 2>/dev/null - mkdir .libs 2>/dev/null - if test -d .libs; then - libltdl_cv_objdir=.libs - else - # MS-DOS does not allow filenames that begin with a dot. - libltdl_cv_objdir=_libs - fi - rmdir .libs 2>/dev/null - fi - ]) -AC_DEFINE_UNQUOTED([LTDL_OBJDIR], ["$libltdl_cv_objdir/"], - [Define to the sub-directory in which libtool stores uninstalled libraries.]) -])# AC_LTDL_OBJDIR - - -# AC_LTDL_DLPREOPEN -# ----------------- -AC_DEFUN([AC_LTDL_DLPREOPEN], -[AC_REQUIRE([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE]) -AC_CACHE_CHECK([whether libtool supports -dlopen/-dlpreopen], - [libltdl_cv_preloaded_symbols], - [if test -n "$lt_cv_sys_global_symbol_pipe"; then - libltdl_cv_preloaded_symbols=yes - else - libltdl_cv_preloaded_symbols=no - fi - ]) -if test x"$libltdl_cv_preloaded_symbols" = xyes; then - AC_DEFINE([HAVE_PRELOADED_SYMBOLS], [1], - [Define if libtool can extract symbol lists from object files.]) -fi -])# AC_LTDL_DLPREOPEN - - -# AC_LTDL_DLLIB -# ------------- -AC_DEFUN([AC_LTDL_DLLIB], -[LIBADD_DL= -AC_SUBST(LIBADD_DL) -AC_LANG_PUSH([C]) - -AC_CHECK_FUNC([shl_load], - [AC_DEFINE([HAVE_SHL_LOAD], [1], - [Define if you have the shl_load function.])], - [AC_CHECK_LIB([dld], [shl_load], - [AC_DEFINE([HAVE_SHL_LOAD], [1], - [Define if you have the shl_load function.]) - LIBADD_DL="$LIBADD_DL -ldld"], - [AC_CHECK_LIB([dl], [dlopen], - [AC_DEFINE([HAVE_LIBDL], [1], - [Define if you have the libdl library or equivalent.]) - LIBADD_DL="-ldl" libltdl_cv_lib_dl_dlopen="yes"], - [AC_TRY_LINK([#if HAVE_DLFCN_H -# include -#endif - ], - [dlopen(0, 0);], - [AC_DEFINE([HAVE_LIBDL], [1], - [Define if you have the libdl library or equivalent.]) libltdl_cv_func_dlopen="yes"], - [AC_CHECK_LIB([svld], [dlopen], - [AC_DEFINE([HAVE_LIBDL], [1], - [Define if you have the libdl library or equivalent.]) - LIBADD_DL="-lsvld" libltdl_cv_func_dlopen="yes"], - [AC_CHECK_LIB([dld], [dld_link], - [AC_DEFINE([HAVE_DLD], [1], - [Define if you have the GNU dld library.]) - LIBADD_DL="$LIBADD_DL -ldld"], - [AC_CHECK_FUNC([_dyld_func_lookup], - [AC_DEFINE([HAVE_DYLD], [1], - [Define if you have the _dyld_func_lookup function.])]) - ]) - ]) - ]) - ]) - ]) -]) - -if test x"$libltdl_cv_func_dlopen" = xyes || test x"$libltdl_cv_lib_dl_dlopen" = xyes -then - lt_save_LIBS="$LIBS" - LIBS="$LIBS $LIBADD_DL" - AC_CHECK_FUNCS([dlerror]) - LIBS="$lt_save_LIBS" -fi -AC_LANG_POP -])# AC_LTDL_DLLIB - - -# AC_LTDL_SYMBOL_USCORE -# --------------------- -# does the compiler prefix global symbols with an underscore? -AC_DEFUN([AC_LTDL_SYMBOL_USCORE], -[AC_REQUIRE([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE]) -AC_CACHE_CHECK([for _ prefix in compiled symbols], - [ac_cv_sys_symbol_underscore], - [ac_cv_sys_symbol_underscore=no - cat > conftest.$ac_ext < $ac_nlist) && test -s "$ac_nlist"; then - # See whether the symbols have a leading underscore. - if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then - ac_cv_sys_symbol_underscore=yes - else - if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then - : - else - echo "configure: cannot find nm_test_func in $ac_nlist" >&AC_FD_CC - fi - fi - else - echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&AC_FD_CC - fi - else - echo "configure: failed program was:" >&AC_FD_CC - cat conftest.c >&AC_FD_CC - fi - rm -rf conftest* - ]) -])# AC_LTDL_SYMBOL_USCORE - - -# AC_LTDL_DLSYM_USCORE -# -------------------- -AC_DEFUN([AC_LTDL_DLSYM_USCORE], -[AC_REQUIRE([AC_LTDL_SYMBOL_USCORE]) -if test x"$ac_cv_sys_symbol_underscore" = xyes; then - if test x"$libltdl_cv_func_dlopen" = xyes || - test x"$libltdl_cv_lib_dl_dlopen" = xyes ; then - AC_CACHE_CHECK([whether we have to add an underscore for dlsym], - [libltdl_cv_need_uscore], - [libltdl_cv_need_uscore=unknown - save_LIBS="$LIBS" - LIBS="$LIBS $LIBADD_DL" - _LT_AC_TRY_DLOPEN_SELF( - [libltdl_cv_need_uscore=no], [libltdl_cv_need_uscore=yes], - [], [libltdl_cv_need_uscore=cross]) - LIBS="$save_LIBS" - ]) - fi -fi - -if test x"$libltdl_cv_need_uscore" = xyes; then - AC_DEFINE([NEED_USCORE], [1], - [Define if dlsym() requires a leading underscore in symbol names.]) -fi -])# AC_LTDL_DLSYM_USCORE - -# AC_LTDL_FUNC_ARGZ -# ----------------- -AC_DEFUN([AC_LTDL_FUNC_ARGZ], -[AC_CHECK_HEADERS([argz.h]) - -AC_CHECK_TYPES([error_t], - [], - [AC_DEFINE([error_t], [int], - [Define to a type to use for `error_t' if it is not otherwise available.])], - [#if HAVE_ARGZ_H -# include -#endif]) - -AC_CHECK_FUNCS([argz_append argz_create_sep argz_insert argz_next argz_stringify]) -])# AC_LTDL_FUNC_ARGZ diff --git a/libltdl/aclocal.m4 b/libltdl/aclocal.m4 deleted file mode 100644 index fcc414d3..00000000 --- a/libltdl/aclocal.m4 +++ /dev/null @@ -1,875 +0,0 @@ -# generated automatically by aclocal 1.10 -*- Autoconf -*- - -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, -# 2005, 2006 Free Software Foundation, Inc. -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -m4_if(m4_PACKAGE_VERSION, [2.61],, -[m4_fatal([this file was generated for autoconf 2.61. -You have another version of autoconf. If you want to use that, -you should regenerate the build system entirely.], [63])]) - -# Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_AUTOMAKE_VERSION(VERSION) -# ---------------------------- -# Automake X.Y traces this macro to ensure aclocal.m4 has been -# generated from the m4 files accompanying Automake X.Y. -# (This private macro should not be called outside this file.) -AC_DEFUN([AM_AUTOMAKE_VERSION], -[am__api_version='1.10' -dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to -dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.10], [], - [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl -]) - -# _AM_AUTOCONF_VERSION(VERSION) -# ----------------------------- -# aclocal traces this macro to find the Autoconf version. -# This is a private macro too. Using m4_define simplifies -# the logic in aclocal, which can simply ignore this definition. -m4_define([_AM_AUTOCONF_VERSION], []) - -# AM_SET_CURRENT_AUTOMAKE_VERSION -# ------------------------------- -# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. -# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. -AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.10])dnl -_AM_AUTOCONF_VERSION(m4_PACKAGE_VERSION)]) - -# AM_AUX_DIR_EXPAND -*- Autoconf -*- - -# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets -# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to -# `$srcdir', `$srcdir/..', or `$srcdir/../..'. -# -# Of course, Automake must honor this variable whenever it calls a -# tool from the auxiliary directory. The problem is that $srcdir (and -# therefore $ac_aux_dir as well) can be either absolute or relative, -# depending on how configure is run. This is pretty annoying, since -# it makes $ac_aux_dir quite unusable in subdirectories: in the top -# source directory, any form will work fine, but in subdirectories a -# relative path needs to be adjusted first. -# -# $ac_aux_dir/missing -# fails when called from a subdirectory if $ac_aux_dir is relative -# $top_srcdir/$ac_aux_dir/missing -# fails if $ac_aux_dir is absolute, -# fails when called from a subdirectory in a VPATH build with -# a relative $ac_aux_dir -# -# The reason of the latter failure is that $top_srcdir and $ac_aux_dir -# are both prefixed by $srcdir. In an in-source build this is usually -# harmless because $srcdir is `.', but things will broke when you -# start a VPATH build or use an absolute $srcdir. -# -# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, -# iff we strip the leading $srcdir from $ac_aux_dir. That would be: -# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` -# and then we would define $MISSING as -# MISSING="\${SHELL} $am_aux_dir/missing" -# This will work as long as MISSING is not called from configure, because -# unfortunately $(top_srcdir) has no meaning in configure. -# However there are other variables, like CC, which are often used in -# configure, and could therefore not use this "fixed" $ac_aux_dir. -# -# Another solution, used here, is to always expand $ac_aux_dir to an -# absolute PATH. The drawback is that using absolute paths prevent a -# configured tree to be moved without reconfiguration. - -AC_DEFUN([AM_AUX_DIR_EXPAND], -[dnl Rely on autoconf to set up CDPATH properly. -AC_PREREQ([2.50])dnl -# expand $ac_aux_dir to an absolute path -am_aux_dir=`cd $ac_aux_dir && pwd` -]) - -# AM_CONDITIONAL -*- Autoconf -*- - -# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006 -# Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 8 - -# AM_CONDITIONAL(NAME, SHELL-CONDITION) -# ------------------------------------- -# Define a conditional. -AC_DEFUN([AM_CONDITIONAL], -[AC_PREREQ(2.52)dnl - ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], - [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl -AC_SUBST([$1_TRUE])dnl -AC_SUBST([$1_FALSE])dnl -_AM_SUBST_NOTMAKE([$1_TRUE])dnl -_AM_SUBST_NOTMAKE([$1_FALSE])dnl -if $2; then - $1_TRUE= - $1_FALSE='#' -else - $1_TRUE='#' - $1_FALSE= -fi -AC_CONFIG_COMMANDS_PRE( -[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then - AC_MSG_ERROR([[conditional "$1" was never defined. -Usually this means the macro was only invoked conditionally.]]) -fi])]) - -# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 -# Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 9 - -# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be -# written in clear, in which case automake, when reading aclocal.m4, -# will think it sees a *use*, and therefore will trigger all it's -# C support machinery. Also note that it means that autoscan, seeing -# CC etc. in the Makefile, will ask for an AC_PROG_CC use... - - -# _AM_DEPENDENCIES(NAME) -# ---------------------- -# See how the compiler implements dependency checking. -# NAME is "CC", "CXX", "GCJ", or "OBJC". -# We try a few techniques and use that to set a single cache variable. -# -# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was -# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular -# dependency, and given that the user is not expected to run this macro, -# just rely on AC_PROG_CC. -AC_DEFUN([_AM_DEPENDENCIES], -[AC_REQUIRE([AM_SET_DEPDIR])dnl -AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl -AC_REQUIRE([AM_MAKE_INCLUDE])dnl -AC_REQUIRE([AM_DEP_TRACK])dnl - -ifelse([$1], CC, [depcc="$CC" am_compiler_list=], - [$1], CXX, [depcc="$CXX" am_compiler_list=], - [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], - [$1], UPC, [depcc="$UPC" am_compiler_list=], - [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], - [depcc="$$1" am_compiler_list=]) - -AC_CACHE_CHECK([dependency style of $depcc], - [am_cv_$1_dependencies_compiler_type], -[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named `D' -- because `-MD' means `put the output - # in D'. - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_$1_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` - fi - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with - # Solaris 8's {/usr,}/bin/sh. - touch sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - case $depmode in - nosideeffect) - # after this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - none) break ;; - esac - # We check with `-c' and `-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle `-M -o', and we need to detect this. - if depmode=$depmode \ - source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_$1_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_$1_dependencies_compiler_type=none -fi -]) -AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) -AM_CONDITIONAL([am__fastdep$1], [ - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) -]) - - -# AM_SET_DEPDIR -# ------------- -# Choose a directory name for dependency files. -# This macro is AC_REQUIREd in _AM_DEPENDENCIES -AC_DEFUN([AM_SET_DEPDIR], -[AC_REQUIRE([AM_SET_LEADING_DOT])dnl -AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl -]) - - -# AM_DEP_TRACK -# ------------ -AC_DEFUN([AM_DEP_TRACK], -[AC_ARG_ENABLE(dependency-tracking, -[ --disable-dependency-tracking speeds up one-time build - --enable-dependency-tracking do not reject slow dependency extractors]) -if test "x$enable_dependency_tracking" != xno; then - am_depcomp="$ac_aux_dir/depcomp" - AMDEPBACKSLASH='\' -fi -AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) -AC_SUBST([AMDEPBACKSLASH])dnl -_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl -]) - -# Generate code to set up dependency tracking. -*- Autoconf -*- - -# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 -# Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -#serial 3 - -# _AM_OUTPUT_DEPENDENCY_COMMANDS -# ------------------------------ -AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], -[for mf in $CONFIG_FILES; do - # Strip MF so we end up with the name of the file. - mf=`echo "$mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile or not. - # We used to match only the files named `Makefile.in', but - # some people rename them; so instead we look at the file content. - # Grep'ing the first line is not enough: some people post-process - # each Makefile.in and add a new line on top of each file to say so. - # Grep'ing the whole file is not good either: AIX grep has a line - # limit of 2048, but all sed's we know have understand at least 4000. - if sed 10q "$mf" | grep '^#.*generated by automake' > /dev/null 2>&1; then - dirpart=`AS_DIRNAME("$mf")` - else - continue - fi - # Extract the definition of DEPDIR, am__include, and am__quote - # from the Makefile without running `make'. - DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` - test -z "$DEPDIR" && continue - am__include=`sed -n 's/^am__include = //p' < "$mf"` - test -z "am__include" && continue - am__quote=`sed -n 's/^am__quote = //p' < "$mf"` - # When using ansi2knr, U may be empty or an underscore; expand it - U=`sed -n 's/^U = //p' < "$mf"` - # Find all dependency output files, they are included files with - # $(DEPDIR) in their names. We invoke sed twice because it is the - # simplest approach to changing $(DEPDIR) to its actual value in the - # expansion. - for file in `sed -n " - s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ - sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do - # Make sure the directory exists. - test -f "$dirpart/$file" && continue - fdir=`AS_DIRNAME(["$file"])` - AS_MKDIR_P([$dirpart/$fdir]) - # echo "creating $dirpart/$file" - echo '# dummy' > "$dirpart/$file" - done -done -])# _AM_OUTPUT_DEPENDENCY_COMMANDS - - -# AM_OUTPUT_DEPENDENCY_COMMANDS -# ----------------------------- -# This macro should only be invoked once -- use via AC_REQUIRE. -# -# This code is only required when automatic dependency tracking -# is enabled. FIXME. This creates each `.P' file that we will -# need in order to bootstrap the dependency handling code. -AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], -[AC_CONFIG_COMMANDS([depfiles], - [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], - [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) -]) - -# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 -# Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 8 - -# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. -AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) - -# Do all the work for Automake. -*- Autoconf -*- - -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, -# 2005, 2006 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 12 - -# This macro actually does too much. Some checks are only needed if -# your package does certain things. But this isn't really a big deal. - -# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) -# AM_INIT_AUTOMAKE([OPTIONS]) -# ----------------------------------------------- -# The call with PACKAGE and VERSION arguments is the old style -# call (pre autoconf-2.50), which is being phased out. PACKAGE -# and VERSION should now be passed to AC_INIT and removed from -# the call to AM_INIT_AUTOMAKE. -# We support both call styles for the transition. After -# the next Automake release, Autoconf can make the AC_INIT -# arguments mandatory, and then we can depend on a new Autoconf -# release and drop the old call support. -AC_DEFUN([AM_INIT_AUTOMAKE], -[AC_PREREQ([2.60])dnl -dnl Autoconf wants to disallow AM_ names. We explicitly allow -dnl the ones we care about. -m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl -AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl -AC_REQUIRE([AC_PROG_INSTALL])dnl -if test "`cd $srcdir && pwd`" != "`pwd`"; then - # Use -I$(srcdir) only when $(srcdir) != ., so that make's output - # is not polluted with repeated "-I." - AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl - # test to see if srcdir already configured - if test -f $srcdir/config.status; then - AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) - fi -fi - -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' - else - CYGPATH_W=echo - fi -fi -AC_SUBST([CYGPATH_W]) - -# Define the identity of the package. -dnl Distinguish between old-style and new-style calls. -m4_ifval([$2], -[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl - AC_SUBST([PACKAGE], [$1])dnl - AC_SUBST([VERSION], [$2])], -[_AM_SET_OPTIONS([$1])dnl -dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. -m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, - [m4_fatal([AC_INIT should be called with package and version arguments])])dnl - AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl - AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl - -_AM_IF_OPTION([no-define],, -[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) - AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl - -# Some tools Automake needs. -AC_REQUIRE([AM_SANITY_CHECK])dnl -AC_REQUIRE([AC_ARG_PROGRAM])dnl -AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) -AM_MISSING_PROG(AUTOCONF, autoconf) -AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) -AM_MISSING_PROG(AUTOHEADER, autoheader) -AM_MISSING_PROG(MAKEINFO, makeinfo) -AM_PROG_INSTALL_SH -AM_PROG_INSTALL_STRIP -AC_REQUIRE([AM_PROG_MKDIR_P])dnl -# We need awk for the "check" target. The system "awk" is bad on -# some platforms. -AC_REQUIRE([AC_PROG_AWK])dnl -AC_REQUIRE([AC_PROG_MAKE_SET])dnl -AC_REQUIRE([AM_SET_LEADING_DOT])dnl -_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], - [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], - [_AM_PROG_TAR([v7])])]) -_AM_IF_OPTION([no-dependencies],, -[AC_PROVIDE_IFELSE([AC_PROG_CC], - [_AM_DEPENDENCIES(CC)], - [define([AC_PROG_CC], - defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl -AC_PROVIDE_IFELSE([AC_PROG_CXX], - [_AM_DEPENDENCIES(CXX)], - [define([AC_PROG_CXX], - defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl -AC_PROVIDE_IFELSE([AC_PROG_OBJC], - [_AM_DEPENDENCIES(OBJC)], - [define([AC_PROG_OBJC], - defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl -]) -]) - - -# When config.status generates a header, we must update the stamp-h file. -# This file resides in the same directory as the config header -# that is generated. The stamp files are numbered to have different names. - -# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the -# loop where config.status creates the headers, so we can generate -# our stamp files there. -AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], -[# Compute $1's index in $config_headers. -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $1 | $1:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) - -# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_PROG_INSTALL_SH -# ------------------ -# Define $install_sh. -AC_DEFUN([AM_PROG_INSTALL_SH], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} -AC_SUBST(install_sh)]) - -# Copyright (C) 2003, 2005 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 2 - -# Check whether the underlying file-system supports filenames -# with a leading dot. For instance MS-DOS doesn't. -AC_DEFUN([AM_SET_LEADING_DOT], -[rm -rf .tst 2>/dev/null -mkdir .tst 2>/dev/null -if test -d .tst; then - am__leading_dot=. -else - am__leading_dot=_ -fi -rmdir .tst 2>/dev/null -AC_SUBST([am__leading_dot])]) - -# Check to see how 'make' treats includes. -*- Autoconf -*- - -# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 3 - -# AM_MAKE_INCLUDE() -# ----------------- -# Check to see how make treats includes. -AC_DEFUN([AM_MAKE_INCLUDE], -[am_make=${MAKE-make} -cat > confinc << 'END' -am__doit: - @echo done -.PHONY: am__doit -END -# If we don't find an include directive, just comment out the code. -AC_MSG_CHECKING([for style of include used by $am_make]) -am__include="#" -am__quote= -_am_result=none -# First try GNU make style include. -echo "include confinc" > confmf -# We grep out `Entering directory' and `Leaving directory' -# messages which can occur if `w' ends up in MAKEFLAGS. -# In particular we don't look at `^make:' because GNU make might -# be invoked under some other name (usually "gmake"), in which -# case it prints its new name instead of `make'. -if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then - am__include=include - am__quote= - _am_result=GNU -fi -# Now try BSD make style include. -if test "$am__include" = "#"; then - echo '.include "confinc"' > confmf - if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then - am__include=.include - am__quote="\"" - _am_result=BSD - fi -fi -AC_SUBST([am__include]) -AC_SUBST([am__quote]) -AC_MSG_RESULT([$_am_result]) -rm -f confinc confmf -]) - -# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- - -# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005 -# Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 5 - -# AM_MISSING_PROG(NAME, PROGRAM) -# ------------------------------ -AC_DEFUN([AM_MISSING_PROG], -[AC_REQUIRE([AM_MISSING_HAS_RUN]) -$1=${$1-"${am_missing_run}$2"} -AC_SUBST($1)]) - - -# AM_MISSING_HAS_RUN -# ------------------ -# Define MISSING if not defined so far and test if it supports --run. -# If it does, set am_missing_run to use it, otherwise, to nothing. -AC_DEFUN([AM_MISSING_HAS_RUN], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -AC_REQUIRE_AUX_FILE([missing])dnl -test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" -# Use eval to expand $SHELL -if eval "$MISSING --run true"; then - am_missing_run="$MISSING --run " -else - am_missing_run= - AC_MSG_WARN([`missing' script is too old or missing]) -fi -]) - -# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_PROG_MKDIR_P -# --------------- -# Check for `mkdir -p'. -AC_DEFUN([AM_PROG_MKDIR_P], -[AC_PREREQ([2.60])dnl -AC_REQUIRE([AC_PROG_MKDIR_P])dnl -dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, -dnl while keeping a definition of mkdir_p for backward compatibility. -dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. -dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of -dnl Makefile.ins that do not define MKDIR_P, so we do our own -dnl adjustment using top_builddir (which is defined more often than -dnl MKDIR_P). -AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl -case $mkdir_p in - [[\\/$]]* | ?:[[\\/]]*) ;; - */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; -esac -]) - -# Helper functions for option handling. -*- Autoconf -*- - -# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 3 - -# _AM_MANGLE_OPTION(NAME) -# ----------------------- -AC_DEFUN([_AM_MANGLE_OPTION], -[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) - -# _AM_SET_OPTION(NAME) -# ------------------------------ -# Set option NAME. Presently that only means defining a flag for this option. -AC_DEFUN([_AM_SET_OPTION], -[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) - -# _AM_SET_OPTIONS(OPTIONS) -# ---------------------------------- -# OPTIONS is a space-separated list of Automake options. -AC_DEFUN([_AM_SET_OPTIONS], -[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) - -# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) -# ------------------------------------------- -# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. -AC_DEFUN([_AM_IF_OPTION], -[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) - -# Check to make sure that the build environment is sane. -*- Autoconf -*- - -# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 -# Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 4 - -# AM_SANITY_CHECK -# --------------- -AC_DEFUN([AM_SANITY_CHECK], -[AC_MSG_CHECKING([whether build environment is sane]) -# Just in case -sleep 1 -echo timestamp > conftest.file -# Do `set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -if ( - set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` - if test "$[*]" = "X"; then - # -L didn't work. - set X `ls -t $srcdir/configure conftest.file` - fi - rm -f conftest.file - if test "$[*]" != "X $srcdir/configure conftest.file" \ - && test "$[*]" != "X conftest.file $srcdir/configure"; then - - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken -alias in your environment]) - fi - - test "$[2]" = conftest.file - ) -then - # Ok. - : -else - AC_MSG_ERROR([newly created file is older than distributed files! -Check your system clock]) -fi -AC_MSG_RESULT(yes)]) - -# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_PROG_INSTALL_STRIP -# --------------------- -# One issue with vendor `install' (even GNU) is that you can't -# specify the program used to strip binaries. This is especially -# annoying in cross-compiling environments, where the build's strip -# is unlikely to handle the host's binaries. -# Fortunately install-sh will honor a STRIPPROG variable, so we -# always use install-sh in `make install-strip', and initialize -# STRIPPROG with the value of the STRIP variable (set by the user). -AC_DEFUN([AM_PROG_INSTALL_STRIP], -[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl -# Installed binaries are usually stripped using `strip' when the user -# run `make install-strip'. However `strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the `STRIP' environment variable to overrule this program. -dnl Don't test for $cross_compiling = yes, because it might be `maybe'. -if test "$cross_compiling" != no; then - AC_CHECK_TOOL([STRIP], [strip], :) -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" -AC_SUBST([INSTALL_STRIP_PROGRAM])]) - -# Copyright (C) 2006 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_SUBST_NOTMAKE(VARIABLE) -# --------------------------- -# Prevent Automake from outputing VARIABLE = @VARIABLE@ in Makefile.in. -# This macro is traced by Automake. -AC_DEFUN([_AM_SUBST_NOTMAKE]) - -# Check how to create a tarball. -*- Autoconf -*- - -# Copyright (C) 2004, 2005 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 2 - -# _AM_PROG_TAR(FORMAT) -# -------------------- -# Check how to create a tarball in format FORMAT. -# FORMAT should be one of `v7', `ustar', or `pax'. -# -# Substitute a variable $(am__tar) that is a command -# writing to stdout a FORMAT-tarball containing the directory -# $tardir. -# tardir=directory && $(am__tar) > result.tar -# -# Substitute a variable $(am__untar) that extract such -# a tarball read from stdin. -# $(am__untar) < result.tar -AC_DEFUN([_AM_PROG_TAR], -[# Always define AMTAR for backward compatibility. -AM_MISSING_PROG([AMTAR], [tar]) -m4_if([$1], [v7], - [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], - [m4_case([$1], [ustar],, [pax],, - [m4_fatal([Unknown tar format])]) -AC_MSG_CHECKING([how to create a $1 tar archive]) -# Loop over all known methods to create a tar archive until one works. -_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' -_am_tools=${am_cv_prog_tar_$1-$_am_tools} -# Do not fold the above two line into one, because Tru64 sh and -# Solaris sh will not grok spaces in the rhs of `-'. -for _am_tool in $_am_tools -do - case $_am_tool in - gnutar) - for _am_tar in tar gnutar gtar; - do - AM_RUN_LOG([$_am_tar --version]) && break - done - am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' - am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' - am__untar="$_am_tar -xf -" - ;; - plaintar) - # Must skip GNU tar: if it does not support --format= it doesn't create - # ustar tarball either. - (tar --version) >/dev/null 2>&1 && continue - am__tar='tar chf - "$$tardir"' - am__tar_='tar chf - "$tardir"' - am__untar='tar xf -' - ;; - pax) - am__tar='pax -L -x $1 -w "$$tardir"' - am__tar_='pax -L -x $1 -w "$tardir"' - am__untar='pax -r' - ;; - cpio) - am__tar='find "$$tardir" -print | cpio -o -H $1 -L' - am__tar_='find "$tardir" -print | cpio -o -H $1 -L' - am__untar='cpio -i -H $1 -d' - ;; - none) - am__tar=false - am__tar_=false - am__untar=false - ;; - esac - - # If the value was cached, stop now. We just wanted to have am__tar - # and am__untar set. - test -n "${am_cv_prog_tar_$1}" && break - - # tar/untar a dummy directory, and stop if the command works - rm -rf conftest.dir - mkdir conftest.dir - echo GrepMe > conftest.dir/file - AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) - rm -rf conftest.dir - if test -s conftest.tar; then - AM_RUN_LOG([$am__untar /dev/null 2>&1 && break - fi -done -rm -rf conftest.dir - -AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) -AC_MSG_RESULT([$am_cv_prog_tar_$1])]) -AC_SUBST([am__tar]) -AC_SUBST([am__untar]) -]) # _AM_PROG_TAR - -m4_include([acinclude.m4]) diff --git a/libltdl/config-h.in b/libltdl/config-h.in deleted file mode 100644 index b8640710..00000000 --- a/libltdl/config-h.in +++ /dev/null @@ -1,195 +0,0 @@ -/* config-h.in. Generated from configure.ac by autoheader. */ - -/* Define to 1 if you have the `argz_append' function. */ -#undef HAVE_ARGZ_APPEND - -/* Define to 1 if you have the `argz_create_sep' function. */ -#undef HAVE_ARGZ_CREATE_SEP - -/* Define to 1 if you have the header file. */ -#undef HAVE_ARGZ_H - -/* Define to 1 if you have the `argz_insert' function. */ -#undef HAVE_ARGZ_INSERT - -/* Define to 1 if you have the `argz_next' function. */ -#undef HAVE_ARGZ_NEXT - -/* Define to 1 if you have the `argz_stringify' function. */ -#undef HAVE_ARGZ_STRINGIFY - -/* Define to 1 if you have the header file. */ -#undef HAVE_ASSERT_H - -/* Define to 1 if you have the `bcopy' function. */ -#undef HAVE_BCOPY - -/* Define to 1 if you have the `closedir' function. */ -#undef HAVE_CLOSEDIR - -/* Define to 1 if you have the header file. */ -#undef HAVE_CTYPE_H - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -#undef HAVE_DIRENT_H - -/* Define if you have the GNU dld library. */ -#undef HAVE_DLD - -/* Define to 1 if you have the header file. */ -#undef HAVE_DLD_H - -/* Define to 1 if you have the `dlerror' function. */ -#undef HAVE_DLERROR - -/* Define to 1 if you have the header file. */ -#undef HAVE_DLFCN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_DL_H - -/* Define if you have the _dyld_func_lookup function. */ -#undef HAVE_DYLD - -/* Define to 1 if you have the header file. */ -#undef HAVE_ERRNO_H - -/* Define to 1 if the system has the type `error_t'. */ -#undef HAVE_ERROR_T - -/* Define to 1 if you have the `index' function. */ -#undef HAVE_INDEX - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define if you have the libdl library or equivalent. */ -#undef HAVE_LIBDL - -/* Define to 1 if you have the header file. */ -#undef HAVE_MACH_O_DYLD_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_MALLOC_H - -/* Define to 1 if you have the `memcpy' function. */ -#undef HAVE_MEMCPY - -/* Define to 1 if you have the `memmove' function. */ -#undef HAVE_MEMMOVE - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have the header file, and it defines `DIR'. */ -#undef HAVE_NDIR_H - -/* Define to 1 if you have the `opendir' function. */ -#undef HAVE_OPENDIR - -/* Define if libtool can extract symbol lists from object files. */ -#undef HAVE_PRELOADED_SYMBOLS - -/* Define to 1 if you have the `readdir' function. */ -#undef HAVE_READDIR - -/* Define to 1 if you have the `rindex' function. */ -#undef HAVE_RINDEX - -/* Define if you have the shl_load function. */ -#undef HAVE_SHL_LOAD - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the `strchr' function. */ -#undef HAVE_STRCHR - -/* Define to 1 if you have the `strcmp' function. */ -#undef HAVE_STRCMP - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the `strrchr' function. */ -#undef HAVE_STRRCHR - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -#undef HAVE_SYS_DIR_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_DL_H - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -#undef HAVE_SYS_NDIR_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define if the OS needs help to load dependent libraries for dlopen(). */ -#undef LTDL_DLOPEN_DEPLIBS - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#undef LTDL_OBJDIR - -/* Define to the name of the environment variable that determines the dynamic - library search path. */ -#undef LTDL_SHLIBPATH_VAR - -/* Define to the extension used for shared libraries, say, ".so". */ -#undef LTDL_SHLIB_EXT - -/* Define to the system default library search path. */ -#undef LTDL_SYSSEARCHPATH - -/* Define if dlsym() requires a leading underscore in symbol names. */ -#undef NEED_USCORE - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Define to empty if `const' does not conform to ANSI C. */ -#undef const - -/* Define to a type to use for `error_t' if it is not otherwise available. */ -#undef error_t - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -#undef inline -#endif diff --git a/libltdl/config.guess b/libltdl/config.guess deleted file mode 100755 index 0f0fe712..00000000 --- a/libltdl/config.guess +++ /dev/null @@ -1,1516 +0,0 @@ -#! /bin/sh -# Attempt to guess a canonical system name. -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, -# Inc. - -timestamp='2007-03-06' - -# This file is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA -# 02110-1301, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - - -# Originally written by Per Bothner . -# Please send patches to . Submit a context -# diff and a properly formatted ChangeLog entry. -# -# This script attempts to guess a canonical system name similar to -# config.sub. If it succeeds, it prints the system name on stdout, and -# exits with 0. Otherwise, it exits with 1. -# -# The plan is that this can be called by configure scripts if you -# don't specify an explicit build system type. - -me=`echo "$0" | sed -e 's,.*/,,'` - -usage="\ -Usage: $0 [OPTION] - -Output the configuration name of the system \`$me' is run on. - -Operation modes: - -h, --help print this help, then exit - -t, --time-stamp print date of last modification, then exit - -v, --version print version number, then exit - -Report bugs and patches to ." - -version="\ -GNU config.guess ($timestamp) - -Originally written by Per Bothner. -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 -Free Software Foundation, Inc. - -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - -help=" -Try \`$me --help' for more information." - -# Parse command line -while test $# -gt 0 ; do - case $1 in - --time-stamp | --time* | -t ) - echo "$timestamp" ; exit ;; - --version | -v ) - echo "$version" ; exit ;; - --help | --h* | -h ) - echo "$usage"; exit ;; - -- ) # Stop option processing - shift; break ;; - - ) # Use stdin as input. - break ;; - -* ) - echo "$me: invalid option $1$help" >&2 - exit 1 ;; - * ) - break ;; - esac -done - -if test $# != 0; then - echo "$me: too many arguments$help" >&2 - exit 1 -fi - -trap 'exit 1' 1 2 15 - -# CC_FOR_BUILD -- compiler used by this script. Note that the use of a -# compiler to aid in system detection is discouraged as it requires -# temporary files to be created and, as you can see below, it is a -# headache to deal with in a portable fashion. - -# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still -# use `HOST_CC' if defined, but it is deprecated. - -# Portable tmp directory creation inspired by the Autoconf team. - -set_cc_for_build=' -trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; -trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; -: ${TMPDIR=/tmp} ; - { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || - { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || - { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || - { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; -dummy=$tmp/dummy ; -tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; -case $CC_FOR_BUILD,$HOST_CC,$CC in - ,,) echo "int x;" > $dummy.c ; - for c in cc gcc c89 c99 ; do - if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then - CC_FOR_BUILD="$c"; break ; - fi ; - done ; - if test x"$CC_FOR_BUILD" = x ; then - CC_FOR_BUILD=no_compiler_found ; - fi - ;; - ,,*) CC_FOR_BUILD=$CC ;; - ,*,*) CC_FOR_BUILD=$HOST_CC ;; -esac ; set_cc_for_build= ;' - -# This is needed to find uname on a Pyramid OSx when run in the BSD universe. -# (ghazi@noc.rutgers.edu 1994-08-24) -if (test -f /.attbin/uname) >/dev/null 2>&1 ; then - PATH=$PATH:/.attbin ; export PATH -fi - -UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown -UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown -UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown -UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown - -# Note: order is significant - the case branches are not exclusive. - -case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - *:NetBSD:*:*) - # NetBSD (nbsd) targets should (where applicable) match one or - # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, - # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently - # switched to ELF, *-*-netbsd* would select the old - # object file format. This provides both forward - # compatibility and a consistent mechanism for selecting the - # object file format. - # - # Note: NetBSD doesn't particularly care about the vendor - # portion of the name. We always set it to "unknown". - sysctl="sysctl -n hw.machine_arch" - UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ - /usr/sbin/$sysctl 2>/dev/null || echo unknown)` - case "${UNAME_MACHINE_ARCH}" in - armeb) machine=armeb-unknown ;; - arm*) machine=arm-unknown ;; - sh3el) machine=shl-unknown ;; - sh3eb) machine=sh-unknown ;; - sh5el) machine=sh5le-unknown ;; - *) machine=${UNAME_MACHINE_ARCH}-unknown ;; - esac - # The Operating System including object format, if it has switched - # to ELF recently, or will in the future. - case "${UNAME_MACHINE_ARCH}" in - arm*|i386|m68k|ns32k|sh3*|sparc|vax) - eval $set_cc_for_build - if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep __ELF__ >/dev/null - then - # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). - # Return netbsd for either. FIX? - os=netbsd - else - os=netbsdelf - fi - ;; - *) - os=netbsd - ;; - esac - # The OS release - # Debian GNU/NetBSD machines have a different userland, and - # thus, need a distinct triplet. However, they do not need - # kernel version information, so it can be replaced with a - # suitable tag, in the style of linux-gnu. - case "${UNAME_VERSION}" in - Debian*) - release='-gnu' - ;; - *) - release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` - ;; - esac - # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: - # contains redundant information, the shorter form: - # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "${machine}-${os}${release}" - exit ;; - *:OpenBSD:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} - exit ;; - *:ekkoBSD:*:*) - echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} - exit ;; - *:SolidBSD:*:*) - echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} - exit ;; - macppc:MirBSD:*:*) - echo powerpc-unknown-mirbsd${UNAME_RELEASE} - exit ;; - *:MirBSD:*:*) - echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} - exit ;; - alpha:OSF1:*:*) - case $UNAME_RELEASE in - *4.0) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` - ;; - *5.*) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` - ;; - esac - # According to Compaq, /usr/sbin/psrinfo has been available on - # OSF/1 and Tru64 systems produced since 1995. I hope that - # covers most systems running today. This code pipes the CPU - # types through head -n 1, so we only detect the type of CPU 0. - ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` - case "$ALPHA_CPU_TYPE" in - "EV4 (21064)") - UNAME_MACHINE="alpha" ;; - "EV4.5 (21064)") - UNAME_MACHINE="alpha" ;; - "LCA4 (21066/21068)") - UNAME_MACHINE="alpha" ;; - "EV5 (21164)") - UNAME_MACHINE="alphaev5" ;; - "EV5.6 (21164A)") - UNAME_MACHINE="alphaev56" ;; - "EV5.6 (21164PC)") - UNAME_MACHINE="alphapca56" ;; - "EV5.7 (21164PC)") - UNAME_MACHINE="alphapca57" ;; - "EV6 (21264)") - UNAME_MACHINE="alphaev6" ;; - "EV6.7 (21264A)") - UNAME_MACHINE="alphaev67" ;; - "EV6.8CB (21264C)") - UNAME_MACHINE="alphaev68" ;; - "EV6.8AL (21264B)") - UNAME_MACHINE="alphaev68" ;; - "EV6.8CX (21264D)") - UNAME_MACHINE="alphaev68" ;; - "EV6.9A (21264/EV69A)") - UNAME_MACHINE="alphaev69" ;; - "EV7 (21364)") - UNAME_MACHINE="alphaev7" ;; - "EV7.9 (21364A)") - UNAME_MACHINE="alphaev79" ;; - esac - # A Pn.n version is a patched version. - # A Vn.n version is a released version. - # A Tn.n version is a released field test version. - # A Xn.n version is an unreleased experimental baselevel. - # 1.2 uses "1.2" for uname -r. - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - exit ;; - Alpha\ *:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # Should we change UNAME_MACHINE based on the output of uname instead - # of the specific Alpha model? - echo alpha-pc-interix - exit ;; - 21064:Windows_NT:50:3) - echo alpha-dec-winnt3.5 - exit ;; - Amiga*:UNIX_System_V:4.0:*) - echo m68k-unknown-sysv4 - exit ;; - *:[Aa]miga[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-amigaos - exit ;; - *:[Mm]orph[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-morphos - exit ;; - *:OS/390:*:*) - echo i370-ibm-openedition - exit ;; - *:z/VM:*:*) - echo s390-ibm-zvmoe - exit ;; - *:OS400:*:*) - echo powerpc-ibm-os400 - exit ;; - arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix${UNAME_RELEASE} - exit ;; - arm:riscos:*:*|arm:RISCOS:*:*) - echo arm-unknown-riscos - exit ;; - SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) - echo hppa1.1-hitachi-hiuxmpp - exit ;; - Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) - # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. - if test "`(/bin/universe) 2>/dev/null`" = att ; then - echo pyramid-pyramid-sysv3 - else - echo pyramid-pyramid-bsd - fi - exit ;; - NILE*:*:*:dcosx) - echo pyramid-pyramid-svr4 - exit ;; - DRS?6000:unix:4.0:6*) - echo sparc-icl-nx6 - exit ;; - DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) - case `/usr/bin/uname -p` in - sparc) echo sparc-icl-nx7; exit ;; - esac ;; - sun4H:SunOS:5.*:*) - echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - i86pc:SunOS:5.*:*) - echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - sun4*:SunOS:6*:*) - # According to config.sub, this is the proper way to canonicalize - # SunOS6. Hard to guess exactly what SunOS6 will be like, but - # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - sun4*:SunOS:*:*) - case "`/usr/bin/arch -k`" in - Series*|S4*) - UNAME_RELEASE=`uname -v` - ;; - esac - # Japanese Language versions have a version number like `4.1.3-JL'. - echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` - exit ;; - sun3*:SunOS:*:*) - echo m68k-sun-sunos${UNAME_RELEASE} - exit ;; - sun*:*:4.2BSD:*) - UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 - case "`/bin/arch`" in - sun3) - echo m68k-sun-sunos${UNAME_RELEASE} - ;; - sun4) - echo sparc-sun-sunos${UNAME_RELEASE} - ;; - esac - exit ;; - aushp:SunOS:*:*) - echo sparc-auspex-sunos${UNAME_RELEASE} - exit ;; - # The situation for MiNT is a little confusing. The machine name - # can be virtually everything (everything which is not - # "atarist" or "atariste" at least should have a processor - # > m68000). The system name ranges from "MiNT" over "FreeMiNT" - # to the lowercase version "mint" (or "freemint"). Finally - # the system name "TOS" denotes a system which is actually not - # MiNT. But MiNT is downward compatible to TOS, so this should - # be no problem. - atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; - atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; - *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; - milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} - exit ;; - hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} - exit ;; - *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} - exit ;; - m68k:machten:*:*) - echo m68k-apple-machten${UNAME_RELEASE} - exit ;; - powerpc:machten:*:*) - echo powerpc-apple-machten${UNAME_RELEASE} - exit ;; - RISC*:Mach:*:*) - echo mips-dec-mach_bsd4.3 - exit ;; - RISC*:ULTRIX:*:*) - echo mips-dec-ultrix${UNAME_RELEASE} - exit ;; - VAX*:ULTRIX*:*:*) - echo vax-dec-ultrix${UNAME_RELEASE} - exit ;; - 2020:CLIX:*:* | 2430:CLIX:*:*) - echo clipper-intergraph-clix${UNAME_RELEASE} - exit ;; - mips:*:*:UMIPS | mips:*:*:RISCos) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c -#ifdef __cplusplus -#include /* for printf() prototype */ - int main (int argc, char *argv[]) { -#else - int main (argc, argv) int argc; char *argv[]; { -#endif - #if defined (host_mips) && defined (MIPSEB) - #if defined (SYSTYPE_SYSV) - printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_SVR4) - printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) - printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); - #endif - #endif - exit (-1); - } -EOF - $CC_FOR_BUILD -o $dummy $dummy.c && - dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && - SYSTEM_NAME=`$dummy $dummyarg` && - { echo "$SYSTEM_NAME"; exit; } - echo mips-mips-riscos${UNAME_RELEASE} - exit ;; - Motorola:PowerMAX_OS:*:*) - echo powerpc-motorola-powermax - exit ;; - Motorola:*:4.3:PL8-*) - echo powerpc-harris-powermax - exit ;; - Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) - echo powerpc-harris-powermax - exit ;; - Night_Hawk:Power_UNIX:*:*) - echo powerpc-harris-powerunix - exit ;; - m88k:CX/UX:7*:*) - echo m88k-harris-cxux7 - exit ;; - m88k:*:4*:R4*) - echo m88k-motorola-sysv4 - exit ;; - m88k:*:3*:R3*) - echo m88k-motorola-sysv3 - exit ;; - AViiON:dgux:*:*) - # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=`/usr/bin/uname -p` - if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] - then - if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ - [ ${TARGET_BINARY_INTERFACE}x = x ] - then - echo m88k-dg-dgux${UNAME_RELEASE} - else - echo m88k-dg-dguxbcs${UNAME_RELEASE} - fi - else - echo i586-dg-dgux${UNAME_RELEASE} - fi - exit ;; - M88*:DolphinOS:*:*) # DolphinOS (SVR3) - echo m88k-dolphin-sysv3 - exit ;; - M88*:*:R3*:*) - # Delta 88k system running SVR3 - echo m88k-motorola-sysv3 - exit ;; - XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) - echo m88k-tektronix-sysv3 - exit ;; - Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) - echo m68k-tektronix-bsd - exit ;; - *:IRIX*:*:*) - echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` - exit ;; - ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. - echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id - exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' - i*86:AIX:*:*) - echo i386-ibm-aix - exit ;; - ia64:AIX:*:*) - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` - else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} - fi - echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} - exit ;; - *:AIX:2:3) - if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #include - - main() - { - if (!__power_pc()) - exit(1); - puts("powerpc-ibm-aix3.2.5"); - exit(0); - } -EOF - if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` - then - echo "$SYSTEM_NAME" - else - echo rs6000-ibm-aix3.2.5 - fi - elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then - echo rs6000-ibm-aix3.2.4 - else - echo rs6000-ibm-aix3.2 - fi - exit ;; - *:AIX:*:[45]) - IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` - if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then - IBM_ARCH=rs6000 - else - IBM_ARCH=powerpc - fi - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` - else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} - fi - echo ${IBM_ARCH}-ibm-aix${IBM_REV} - exit ;; - *:AIX:*:*) - echo rs6000-ibm-aix - exit ;; - ibmrt:4.4BSD:*|romp-ibm:BSD:*) - echo romp-ibm-bsd4.4 - exit ;; - ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and - echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to - exit ;; # report: romp-ibm BSD 4.3 - *:BOSX:*:*) - echo rs6000-bull-bosx - exit ;; - DPX/2?00:B.O.S.:*:*) - echo m68k-bull-sysv3 - exit ;; - 9000/[34]??:4.3bsd:1.*:*) - echo m68k-hp-bsd - exit ;; - hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) - echo m68k-hp-bsd4.4 - exit ;; - 9000/[34678]??:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - case "${UNAME_MACHINE}" in - 9000/31? ) HP_ARCH=m68000 ;; - 9000/[34]?? ) HP_ARCH=m68k ;; - 9000/[678][0-9][0-9]) - if [ -x /usr/bin/getconf ]; then - sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` - sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case "${sc_cpu_version}" in - 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 - 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 - 532) # CPU_PA_RISC2_0 - case "${sc_kernel_bits}" in - 32) HP_ARCH="hppa2.0n" ;; - 64) HP_ARCH="hppa2.0w" ;; - '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 - esac ;; - esac - fi - if [ "${HP_ARCH}" = "" ]; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - - #define _HPUX_SOURCE - #include - #include - - int main () - { - #if defined(_SC_KERNEL_BITS) - long bits = sysconf(_SC_KERNEL_BITS); - #endif - long cpu = sysconf (_SC_CPU_VERSION); - - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1"); break; - case CPU_PA_RISC2_0: - #if defined(_SC_KERNEL_BITS) - switch (bits) - { - case 64: puts ("hppa2.0w"); break; - case 32: puts ("hppa2.0n"); break; - default: puts ("hppa2.0"); break; - } break; - #else /* !defined(_SC_KERNEL_BITS) */ - puts ("hppa2.0"); break; - #endif - default: puts ("hppa1.0"); break; - } - exit (0); - } -EOF - (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` - test -z "$HP_ARCH" && HP_ARCH=hppa - fi ;; - esac - if [ ${HP_ARCH} = "hppa2.0w" ] - then - eval $set_cc_for_build - - # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating - # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler - # generating 64-bit code. GNU and HP use different nomenclature: - # - # $ CC_FOR_BUILD=cc ./config.guess - # => hppa2.0w-hp-hpux11.23 - # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess - # => hppa64-hp-hpux11.23 - - if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | - grep __LP64__ >/dev/null - then - HP_ARCH="hppa2.0w" - else - HP_ARCH="hppa64" - fi - fi - echo ${HP_ARCH}-hp-hpux${HPUX_REV} - exit ;; - ia64:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - echo ia64-hp-hpux${HPUX_REV} - exit ;; - 3050*:HI-UX:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #include - int - main () - { - long cpu = sysconf (_SC_CPU_VERSION); - /* The order matters, because CPU_IS_HP_MC68K erroneously returns - true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct - results, however. */ - if (CPU_IS_PA_RISC (cpu)) - { - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; - case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; - default: puts ("hppa-hitachi-hiuxwe2"); break; - } - } - else if (CPU_IS_HP_MC68K (cpu)) - puts ("m68k-hitachi-hiuxwe2"); - else puts ("unknown-hitachi-hiuxwe2"); - exit (0); - } -EOF - $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && - { echo "$SYSTEM_NAME"; exit; } - echo unknown-hitachi-hiuxwe2 - exit ;; - 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) - echo hppa1.1-hp-bsd - exit ;; - 9000/8??:4.3bsd:*:*) - echo hppa1.0-hp-bsd - exit ;; - *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) - echo hppa1.0-hp-mpeix - exit ;; - hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) - echo hppa1.1-hp-osf - exit ;; - hp8??:OSF1:*:*) - echo hppa1.0-hp-osf - exit ;; - i*86:OSF1:*:*) - if [ -x /usr/sbin/sysversion ] ; then - echo ${UNAME_MACHINE}-unknown-osf1mk - else - echo ${UNAME_MACHINE}-unknown-osf1 - fi - exit ;; - parisc*:Lites*:*:*) - echo hppa1.1-hp-lites - exit ;; - C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) - echo c1-convex-bsd - exit ;; - C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit ;; - C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) - echo c34-convex-bsd - exit ;; - C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) - echo c38-convex-bsd - exit ;; - C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) - echo c4-convex-bsd - exit ;; - CRAY*Y-MP:*:*:*) - echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*[A-Z]90:*:*:*) - echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ - | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ - -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ - -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*TS:*:*:*) - echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*T3E:*:*:*) - echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*SV1:*:*:*) - echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - *:UNICOS/mp:*:*) - echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` - echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; - 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` - echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; - i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) - echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} - exit ;; - sparc*:BSD/OS:*:*) - echo sparc-unknown-bsdi${UNAME_RELEASE} - exit ;; - *:BSD/OS:*:*) - echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} - exit ;; - *:FreeBSD:*:*) - case ${UNAME_MACHINE} in - pc98) - echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - amd64) - echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - *) - echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - esac - exit ;; - i*:CYGWIN*:*) - echo ${UNAME_MACHINE}-pc-cygwin - exit ;; - *:MINGW*:*) - echo ${UNAME_MACHINE}-pc-mingw32 - exit ;; - i*:windows32*:*) - # uname -m includes "-pc" on this system. - echo ${UNAME_MACHINE}-mingw32 - exit ;; - i*:PW*:*) - echo ${UNAME_MACHINE}-pc-pw32 - exit ;; - *:Interix*:[3456]*) - case ${UNAME_MACHINE} in - x86) - echo i586-pc-interix${UNAME_RELEASE} - exit ;; - EM64T | authenticamd) - echo x86_64-unknown-interix${UNAME_RELEASE} - exit ;; - esac ;; - [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) - echo i${UNAME_MACHINE}-pc-mks - exit ;; - i*:Windows_NT*:* | Pentium*:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we - # UNAME_MACHINE based on the output of uname instead of i386? - echo i586-pc-interix - exit ;; - i*:UWIN*:*) - echo ${UNAME_MACHINE}-pc-uwin - exit ;; - amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) - echo x86_64-unknown-cygwin - exit ;; - p*:CYGWIN*:*) - echo powerpcle-unknown-cygwin - exit ;; - prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - *:GNU:*:*) - # the GNU system - echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` - exit ;; - *:GNU/*:*:*) - # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu - exit ;; - i*86:Minix:*:*) - echo ${UNAME_MACHINE}-pc-minix - exit ;; - arm*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - avr32*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - cris:Linux:*:*) - echo cris-axis-linux-gnu - exit ;; - crisv32:Linux:*:*) - echo crisv32-axis-linux-gnu - exit ;; - frv:Linux:*:*) - echo frv-unknown-linux-gnu - exit ;; - ia64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - m32r*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - m68*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - mips:Linux:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #undef CPU - #undef mips - #undef mipsel - #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - CPU=mipsel - #else - #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - CPU=mips - #else - CPU= - #endif - #endif -EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^CPU/{ - s: ::g - p - }'`" - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } - ;; - mips64:Linux:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #undef CPU - #undef mips64 - #undef mips64el - #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - CPU=mips64el - #else - #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - CPU=mips64 - #else - CPU= - #endif - #endif -EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^CPU/{ - s: ::g - p - }'`" - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } - ;; - or32:Linux:*:*) - echo or32-unknown-linux-gnu - exit ;; - ppc:Linux:*:*) - echo powerpc-unknown-linux-gnu - exit ;; - ppc64:Linux:*:*) - echo powerpc64-unknown-linux-gnu - exit ;; - alpha:Linux:*:*) - case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in - EV5) UNAME_MACHINE=alphaev5 ;; - EV56) UNAME_MACHINE=alphaev56 ;; - PCA56) UNAME_MACHINE=alphapca56 ;; - PCA57) UNAME_MACHINE=alphapca56 ;; - EV6) UNAME_MACHINE=alphaev6 ;; - EV67) UNAME_MACHINE=alphaev67 ;; - EV68*) UNAME_MACHINE=alphaev68 ;; - esac - objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null - if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi - echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} - exit ;; - parisc:Linux:*:* | hppa:Linux:*:*) - # Look for CPU level - case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in - PA7*) echo hppa1.1-unknown-linux-gnu ;; - PA8*) echo hppa2.0-unknown-linux-gnu ;; - *) echo hppa-unknown-linux-gnu ;; - esac - exit ;; - parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-gnu - exit ;; - s390:Linux:*:* | s390x:Linux:*:*) - echo ${UNAME_MACHINE}-ibm-linux - exit ;; - sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - sh*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - sparc:Linux:*:* | sparc64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - vax:Linux:*:*) - echo ${UNAME_MACHINE}-dec-linux-gnu - exit ;; - x86_64:Linux:*:*) - echo x86_64-unknown-linux-gnu - exit ;; - xtensa:Linux:*:*) - echo xtensa-unknown-linux-gnu - exit ;; - i*86:Linux:*:*) - # The BFD linker knows what the default object file format is, so - # first see if it will tell us. cd to the root directory to prevent - # problems with other programs or directories called `ld' in the path. - # Set LC_ALL=C to ensure ld outputs messages in English. - ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ - | sed -ne '/supported targets:/!d - s/[ ][ ]*/ /g - s/.*supported targets: *// - s/ .*// - p'` - case "$ld_supported_targets" in - elf32-i386) - TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" - ;; - a.out-i386-linux) - echo "${UNAME_MACHINE}-pc-linux-gnuaout" - exit ;; - coff-i386) - echo "${UNAME_MACHINE}-pc-linux-gnucoff" - exit ;; - "") - # Either a pre-BFD a.out linker (linux-gnuoldld) or - # one that does not give us useful --help. - echo "${UNAME_MACHINE}-pc-linux-gnuoldld" - exit ;; - esac - # Determine whether the default compiler is a.out or elf - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #include - #ifdef __ELF__ - # ifdef __GLIBC__ - # if __GLIBC__ >= 2 - LIBC=gnu - # else - LIBC=gnulibc1 - # endif - # else - LIBC=gnulibc1 - # endif - #else - #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) - LIBC=gnu - #else - LIBC=gnuaout - #endif - #endif - #ifdef __dietlibc__ - LIBC=dietlibc - #endif -EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^LIBC/{ - s: ::g - p - }'`" - test x"${LIBC}" != x && { - echo "${UNAME_MACHINE}-pc-linux-${LIBC}" - exit - } - test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } - ;; - i*86:DYNIX/ptx:4*:*) - # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. - # earlier versions are messed up and put the nodename in both - # sysname and nodename. - echo i386-sequent-sysv4 - exit ;; - i*86:UNIX_SV:4.2MP:2.*) - # Unixware is an offshoot of SVR4, but it has its own version - # number series starting with 2... - # I am not positive that other SVR4 systems won't match this, - # I just have to hope. -- rms. - # Use sysv4.2uw... so that sysv4* matches it. - echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} - exit ;; - i*86:OS/2:*:*) - # If we were able to find `uname', then EMX Unix compatibility - # is probably installed. - echo ${UNAME_MACHINE}-pc-os2-emx - exit ;; - i*86:XTS-300:*:STOP) - echo ${UNAME_MACHINE}-unknown-stop - exit ;; - i*86:atheos:*:*) - echo ${UNAME_MACHINE}-unknown-atheos - exit ;; - i*86:syllable:*:*) - echo ${UNAME_MACHINE}-pc-syllable - exit ;; - i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) - echo i386-unknown-lynxos${UNAME_RELEASE} - exit ;; - i*86:*DOS:*:*) - echo ${UNAME_MACHINE}-pc-msdosdjgpp - exit ;; - i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) - UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` - if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} - else - echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} - fi - exit ;; - i*86:*:5:[678]*) - # UnixWare 7.x, OpenUNIX and OpenServer 6. - case `/bin/uname -X | grep "^Machine"` in - *486*) UNAME_MACHINE=i486 ;; - *Pentium) UNAME_MACHINE=i586 ;; - *Pent*|*Celeron) UNAME_MACHINE=i686 ;; - esac - echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} - exit ;; - i*86:*:3.2:*) - if test -f /usr/options/cb.name; then - UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then - UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` - (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 - (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ - && UNAME_MACHINE=i586 - (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ - && UNAME_MACHINE=i686 - (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ - && UNAME_MACHINE=i686 - echo ${UNAME_MACHINE}-pc-sco$UNAME_REL - else - echo ${UNAME_MACHINE}-pc-sysv32 - fi - exit ;; - pc:*:*:*) - # Left here for compatibility: - # uname -m prints for DJGPP always 'pc', but it prints nothing about - # the processor, so we play safe by assuming i386. - echo i386-pc-msdosdjgpp - exit ;; - Intel:Mach:3*:*) - echo i386-pc-mach3 - exit ;; - paragon:*:*:*) - echo i860-intel-osf1 - exit ;; - i860:*:4.*:*) # i860-SVR4 - if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 - else # Add other i860-SVR4 vendors below as they are discovered. - echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 - fi - exit ;; - mini*:CTIX:SYS*5:*) - # "miniframe" - echo m68010-convergent-sysv - exit ;; - mc68k:UNIX:SYSTEM5:3.51m) - echo m68k-convergent-sysv - exit ;; - M680?0:D-NIX:5.3:*) - echo m68k-diab-dnix - exit ;; - M68*:*:R3V[5678]*:*) - test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; - 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) - OS_REL='' - test -r /etc/.relid \ - && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3${OS_REL}; exit; } - /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; - 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4; exit; } ;; - m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) - echo m68k-unknown-lynxos${UNAME_RELEASE} - exit ;; - mc68030:UNIX_System_V:4.*:*) - echo m68k-atari-sysv4 - exit ;; - TSUNAMI:LynxOS:2.*:*) - echo sparc-unknown-lynxos${UNAME_RELEASE} - exit ;; - rs6000:LynxOS:2.*:*) - echo rs6000-unknown-lynxos${UNAME_RELEASE} - exit ;; - PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) - echo powerpc-unknown-lynxos${UNAME_RELEASE} - exit ;; - SM[BE]S:UNIX_SV:*:*) - echo mips-dde-sysv${UNAME_RELEASE} - exit ;; - RM*:ReliantUNIX-*:*:*) - echo mips-sni-sysv4 - exit ;; - RM*:SINIX-*:*:*) - echo mips-sni-sysv4 - exit ;; - *:SINIX-*:*:*) - if uname -p 2>/dev/null >/dev/null ; then - UNAME_MACHINE=`(uname -p) 2>/dev/null` - echo ${UNAME_MACHINE}-sni-sysv4 - else - echo ns32k-sni-sysv - fi - exit ;; - PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort - # says - echo i586-unisys-sysv4 - exit ;; - *:UNIX_System_V:4*:FTX*) - # From Gerald Hewes . - # How about differentiating between stratus architectures? -djm - echo hppa1.1-stratus-sysv4 - exit ;; - *:*:*:FTX*) - # From seanf@swdc.stratus.com. - echo i860-stratus-sysv4 - exit ;; - i*86:VOS:*:*) - # From Paul.Green@stratus.com. - echo ${UNAME_MACHINE}-stratus-vos - exit ;; - *:VOS:*:*) - # From Paul.Green@stratus.com. - echo hppa1.1-stratus-vos - exit ;; - mc68*:A/UX:*:*) - echo m68k-apple-aux${UNAME_RELEASE} - exit ;; - news*:NEWS-OS:6*:*) - echo mips-sony-newsos6 - exit ;; - R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) - if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} - else - echo mips-unknown-sysv${UNAME_RELEASE} - fi - exit ;; - BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. - echo powerpc-be-beos - exit ;; - BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. - echo powerpc-apple-beos - exit ;; - BePC:BeOS:*:*) # BeOS running on Intel PC compatible. - echo i586-pc-beos - exit ;; - SX-4:SUPER-UX:*:*) - echo sx4-nec-superux${UNAME_RELEASE} - exit ;; - SX-5:SUPER-UX:*:*) - echo sx5-nec-superux${UNAME_RELEASE} - exit ;; - SX-6:SUPER-UX:*:*) - echo sx6-nec-superux${UNAME_RELEASE} - exit ;; - SX-7:SUPER-UX:*:*) - echo sx7-nec-superux${UNAME_RELEASE} - exit ;; - SX-8:SUPER-UX:*:*) - echo sx8-nec-superux${UNAME_RELEASE} - exit ;; - SX-8R:SUPER-UX:*:*) - echo sx8r-nec-superux${UNAME_RELEASE} - exit ;; - Power*:Rhapsody:*:*) - echo powerpc-apple-rhapsody${UNAME_RELEASE} - exit ;; - *:Rhapsody:*:*) - echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} - exit ;; - *:Darwin:*:*) - UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown - case $UNAME_PROCESSOR in - unknown) UNAME_PROCESSOR=powerpc ;; - esac - echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} - exit ;; - *:procnto*:*:* | *:QNX:[0123456789]*:*) - UNAME_PROCESSOR=`uname -p` - if test "$UNAME_PROCESSOR" = "x86"; then - UNAME_PROCESSOR=i386 - UNAME_MACHINE=pc - fi - echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} - exit ;; - *:QNX:*:4*) - echo i386-pc-qnx - exit ;; - NSE-?:NONSTOP_KERNEL:*:*) - echo nse-tandem-nsk${UNAME_RELEASE} - exit ;; - NSR-?:NONSTOP_KERNEL:*:*) - echo nsr-tandem-nsk${UNAME_RELEASE} - exit ;; - *:NonStop-UX:*:*) - echo mips-compaq-nonstopux - exit ;; - BS2000:POSIX*:*:*) - echo bs2000-siemens-sysv - exit ;; - DS/*:UNIX_System_V:*:*) - echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} - exit ;; - *:Plan9:*:*) - # "uname -m" is not consistent, so use $cputype instead. 386 - # is converted to i386 for consistency with other x86 - # operating systems. - if test "$cputype" = "386"; then - UNAME_MACHINE=i386 - else - UNAME_MACHINE="$cputype" - fi - echo ${UNAME_MACHINE}-unknown-plan9 - exit ;; - *:TOPS-10:*:*) - echo pdp10-unknown-tops10 - exit ;; - *:TENEX:*:*) - echo pdp10-unknown-tenex - exit ;; - KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) - echo pdp10-dec-tops20 - exit ;; - XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) - echo pdp10-xkl-tops20 - exit ;; - *:TOPS-20:*:*) - echo pdp10-unknown-tops20 - exit ;; - *:ITS:*:*) - echo pdp10-unknown-its - exit ;; - SEI:*:*:SEIUX) - echo mips-sei-seiux${UNAME_RELEASE} - exit ;; - *:DragonFly:*:*) - echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` - exit ;; - *:*VMS:*:*) - UNAME_MACHINE=`(uname -p) 2>/dev/null` - case "${UNAME_MACHINE}" in - A*) echo alpha-dec-vms ; exit ;; - I*) echo ia64-dec-vms ; exit ;; - V*) echo vax-dec-vms ; exit ;; - esac ;; - *:XENIX:*:SysV) - echo i386-pc-xenix - exit ;; - i*86:skyos:*:*) - echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' - exit ;; - i*86:rdos:*:*) - echo ${UNAME_MACHINE}-pc-rdos - exit ;; -esac - -#echo '(No uname command or uname output not recognized.)' 1>&2 -#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 - -eval $set_cc_for_build -cat >$dummy.c < -# include -#endif -main () -{ -#if defined (sony) -#if defined (MIPSEB) - /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, - I don't know.... */ - printf ("mips-sony-bsd\n"); exit (0); -#else -#include - printf ("m68k-sony-newsos%s\n", -#ifdef NEWSOS4 - "4" -#else - "" -#endif - ); exit (0); -#endif -#endif - -#if defined (__arm) && defined (__acorn) && defined (__unix) - printf ("arm-acorn-riscix\n"); exit (0); -#endif - -#if defined (hp300) && !defined (hpux) - printf ("m68k-hp-bsd\n"); exit (0); -#endif - -#if defined (NeXT) -#if !defined (__ARCHITECTURE__) -#define __ARCHITECTURE__ "m68k" -#endif - int version; - version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; - if (version < 4) - printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); - else - printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); - exit (0); -#endif - -#if defined (MULTIMAX) || defined (n16) -#if defined (UMAXV) - printf ("ns32k-encore-sysv\n"); exit (0); -#else -#if defined (CMU) - printf ("ns32k-encore-mach\n"); exit (0); -#else - printf ("ns32k-encore-bsd\n"); exit (0); -#endif -#endif -#endif - -#if defined (__386BSD__) - printf ("i386-pc-bsd\n"); exit (0); -#endif - -#if defined (sequent) -#if defined (i386) - printf ("i386-sequent-dynix\n"); exit (0); -#endif -#if defined (ns32000) - printf ("ns32k-sequent-dynix\n"); exit (0); -#endif -#endif - -#if defined (_SEQUENT_) - struct utsname un; - - uname(&un); - - if (strncmp(un.version, "V2", 2) == 0) { - printf ("i386-sequent-ptx2\n"); exit (0); - } - if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ - printf ("i386-sequent-ptx1\n"); exit (0); - } - printf ("i386-sequent-ptx\n"); exit (0); - -#endif - -#if defined (vax) -# if !defined (ultrix) -# include -# if defined (BSD) -# if BSD == 43 - printf ("vax-dec-bsd4.3\n"); exit (0); -# else -# if BSD == 199006 - printf ("vax-dec-bsd4.3reno\n"); exit (0); -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# endif -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# else - printf ("vax-dec-ultrix\n"); exit (0); -# endif -#endif - -#if defined (alliant) && defined (i860) - printf ("i860-alliant-bsd\n"); exit (0); -#endif - - exit (1); -} -EOF - -$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && - { echo "$SYSTEM_NAME"; exit; } - -# Apollos put the system type in the environment. - -test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } - -# Convex versions that predate uname can use getsysinfo(1) - -if [ -x /usr/convex/getsysinfo ] -then - case `getsysinfo -f cpu_type` in - c1*) - echo c1-convex-bsd - exit ;; - c2*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit ;; - c34*) - echo c34-convex-bsd - exit ;; - c38*) - echo c38-convex-bsd - exit ;; - c4*) - echo c4-convex-bsd - exit ;; - esac -fi - -cat >&2 < in order to provide the needed -information to handle your system. - -config.guess timestamp = $timestamp - -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null` - -hostinfo = `(hostinfo) 2>/dev/null` -/bin/universe = `(/bin/universe) 2>/dev/null` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` -/bin/arch = `(/bin/arch) 2>/dev/null` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` - -UNAME_MACHINE = ${UNAME_MACHINE} -UNAME_RELEASE = ${UNAME_RELEASE} -UNAME_SYSTEM = ${UNAME_SYSTEM} -UNAME_VERSION = ${UNAME_VERSION} -EOF - -exit 1 - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "timestamp='" -# time-stamp-format: "%:y-%02m-%02d" -# time-stamp-end: "'" -# End: diff --git a/libltdl/config.h b/libltdl/config.h deleted file mode 100644 index a04820a7..00000000 --- a/libltdl/config.h +++ /dev/null @@ -1,196 +0,0 @@ -/* config.h. Generated from config-h.in by configure. */ -/* config-h.in. Generated from configure.ac by autoheader. */ - -/* Define to 1 if you have the `argz_append' function. */ -#define HAVE_ARGZ_APPEND 1 - -/* Define to 1 if you have the `argz_create_sep' function. */ -#define HAVE_ARGZ_CREATE_SEP 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ARGZ_H 1 - -/* Define to 1 if you have the `argz_insert' function. */ -#define HAVE_ARGZ_INSERT 1 - -/* Define to 1 if you have the `argz_next' function. */ -#define HAVE_ARGZ_NEXT 1 - -/* Define to 1 if you have the `argz_stringify' function. */ -#define HAVE_ARGZ_STRINGIFY 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ASSERT_H 1 - -/* Define to 1 if you have the `bcopy' function. */ -/* #undef HAVE_BCOPY */ - -/* Define to 1 if you have the `closedir' function. */ -#define HAVE_CLOSEDIR 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_CTYPE_H 1 - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -#define HAVE_DIRENT_H 1 - -/* Define if you have the GNU dld library. */ -/* #undef HAVE_DLD */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DLD_H */ - -/* Define to 1 if you have the `dlerror' function. */ -#define HAVE_DLERROR 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DL_H */ - -/* Define if you have the _dyld_func_lookup function. */ -/* #undef HAVE_DYLD */ - -/* Define to 1 if you have the header file. */ -#define HAVE_ERRNO_H 1 - -/* Define to 1 if the system has the type `error_t'. */ -#define HAVE_ERROR_T 1 - -/* Define to 1 if you have the `index' function. */ -/* #undef HAVE_INDEX */ - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define if you have the libdl library or equivalent. */ -#define HAVE_LIBDL 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_MACH_O_DYLD_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_MALLOC_H 1 - -/* Define to 1 if you have the `memcpy' function. */ -#define HAVE_MEMCPY 1 - -/* Define to 1 if you have the `memmove' function. */ -#define HAVE_MEMMOVE 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the header file, and it defines `DIR'. */ -/* #undef HAVE_NDIR_H */ - -/* Define to 1 if you have the `opendir' function. */ -#define HAVE_OPENDIR 1 - -/* Define if libtool can extract symbol lists from object files. */ -#define HAVE_PRELOADED_SYMBOLS 1 - -/* Define to 1 if you have the `readdir' function. */ -#define HAVE_READDIR 1 - -/* Define to 1 if you have the `rindex' function. */ -/* #undef HAVE_RINDEX */ - -/* Define if you have the shl_load function. */ -/* #undef HAVE_SHL_LOAD */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDIO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the `strchr' function. */ -#define HAVE_STRCHR 1 - -/* Define to 1 if you have the `strcmp' function. */ -#define HAVE_STRCMP 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strrchr' function. */ -#define HAVE_STRRCHR 1 - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_DIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_DL_H */ - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_NDIR_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define if the OS needs help to load dependent libraries for dlopen(). */ -/* #undef LTDL_DLOPEN_DEPLIBS */ - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#define LTDL_OBJDIR ".libs/" - -/* Define to the name of the environment variable that determines the dynamic - library search path. */ -#define LTDL_SHLIBPATH_VAR "LD_LIBRARY_PATH" - -/* Define to the extension used for shared libraries, say, ".so". */ -#define LTDL_SHLIB_EXT ".so" - -/* Define to the system default library search path. */ -#define LTDL_SYSSEARCHPATH "/lib:/usr/lib:/usr/lib/atlas:/usr/local/lib:/lib/i486-linux-gnu:/usr/lib/i486-linux-gnu:/usr/local/lib" - -/* Define if dlsym() requires a leading underscore in symbol names. */ -/* #undef NEED_USCORE */ - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "bug-libtool@gnu.org" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "libltdl" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "libltdl 1.2" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "libltdl" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "1.2" - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Define to a type to use for `error_t' if it is not otherwise available. */ -/* #undef error_t */ - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -/* #undef inline */ -#endif diff --git a/libltdl/config.sub b/libltdl/config.sub deleted file mode 100755 index 5defff65..00000000 --- a/libltdl/config.sub +++ /dev/null @@ -1,1622 +0,0 @@ -#! /bin/sh -# Configuration validation subroutine script. -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, -# Inc. - -timestamp='2007-01-18' - -# This file is (in principle) common to ALL GNU software. -# The presence of a machine in this file suggests that SOME GNU software -# can handle that machine. It does not imply ALL GNU software can. -# -# This file is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA -# 02110-1301, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - - -# Please send patches to . Submit a context -# diff and a properly formatted ChangeLog entry. -# -# Configuration subroutine to validate and canonicalize a configuration type. -# Supply the specified configuration type as an argument. -# If it is invalid, we print an error message on stderr and exit with code 1. -# Otherwise, we print the canonical config type on stdout and succeed. - -# This file is supposed to be the same for all GNU packages -# and recognize all the CPU types, system types and aliases -# that are meaningful with *any* GNU software. -# Each package is responsible for reporting which valid configurations -# it does not support. The user should be able to distinguish -# a failure to support a valid configuration from a meaningless -# configuration. - -# The goal of this file is to map all the various variations of a given -# machine specification into a single specification in the form: -# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM -# or in some cases, the newer four-part form: -# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM -# It is wrong to echo any other type of specification. - -me=`echo "$0" | sed -e 's,.*/,,'` - -usage="\ -Usage: $0 [OPTION] CPU-MFR-OPSYS - $0 [OPTION] ALIAS - -Canonicalize a configuration name. - -Operation modes: - -h, --help print this help, then exit - -t, --time-stamp print date of last modification, then exit - -v, --version print version number, then exit - -Report bugs and patches to ." - -version="\ -GNU config.sub ($timestamp) - -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 -Free Software Foundation, Inc. - -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - -help=" -Try \`$me --help' for more information." - -# Parse command line -while test $# -gt 0 ; do - case $1 in - --time-stamp | --time* | -t ) - echo "$timestamp" ; exit ;; - --version | -v ) - echo "$version" ; exit ;; - --help | --h* | -h ) - echo "$usage"; exit ;; - -- ) # Stop option processing - shift; break ;; - - ) # Use stdin as input. - break ;; - -* ) - echo "$me: invalid option $1$help" - exit 1 ;; - - *local*) - # First pass through any local machine types. - echo $1 - exit ;; - - * ) - break ;; - esac -done - -case $# in - 0) echo "$me: missing argument$help" >&2 - exit 1;; - 1) ;; - *) echo "$me: too many arguments$help" >&2 - exit 1;; -esac - -# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). -# Here we must recognize all the valid KERNEL-OS combinations. -maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` -case $maybe_os in - nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ - uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ - storm-chaos* | os2-emx* | rtmk-nova*) - os=-$maybe_os - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` - ;; - *) - basic_machine=`echo $1 | sed 's/-[^-]*$//'` - if [ $basic_machine != $1 ] - then os=`echo $1 | sed 's/.*-/-/'` - else os=; fi - ;; -esac - -### Let's recognize common machines as not being operating systems so -### that things like config.sub decstation-3100 work. We also -### recognize some manufacturers as not being operating systems, so we -### can provide default operating systems below. -case $os in - -sun*os*) - # Prevent following clause from handling this invalid input. - ;; - -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ - -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ - -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ - -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ - -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ - -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ - -apple | -axis | -knuth | -cray) - os= - basic_machine=$1 - ;; - -sim | -cisco | -oki | -wec | -winbond) - os= - basic_machine=$1 - ;; - -scout) - ;; - -wrs) - os=-vxworks - basic_machine=$1 - ;; - -chorusos*) - os=-chorusos - basic_machine=$1 - ;; - -chorusrdb) - os=-chorusrdb - basic_machine=$1 - ;; - -hiux*) - os=-hiuxwe2 - ;; - -sco6) - os=-sco5v6 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco5) - os=-sco3.2v5 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco4) - os=-sco3.2v4 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2.[4-9]*) - os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2v[4-9]*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco5v6*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco*) - os=-sco3.2v2 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -udk*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -isc) - os=-isc2.2 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -clix*) - basic_machine=clipper-intergraph - ;; - -isc*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -lynx*) - os=-lynxos - ;; - -ptx*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` - ;; - -windowsnt*) - os=`echo $os | sed -e 's/windowsnt/winnt/'` - ;; - -psos*) - os=-psos - ;; - -mint | -mint[0-9]*) - basic_machine=m68k-atari - os=-mint - ;; -esac - -# Decode aliases for certain CPU-COMPANY combinations. -case $basic_machine in - # Recognize the basic CPU types without company name. - # Some are omitted here because they have special meanings below. - 1750a | 580 \ - | a29k \ - | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ - | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ - | am33_2.0 \ - | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ - | bfin \ - | c4x | clipper \ - | d10v | d30v | dlx | dsp16xx \ - | fido | fr30 | frv \ - | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ - | i370 | i860 | i960 | ia64 \ - | ip2k | iq2000 \ - | m32c | m32r | m32rle | m68000 | m68k | m88k \ - | maxq | mb | microblaze | mcore | mep \ - | mips | mipsbe | mipseb | mipsel | mipsle \ - | mips16 \ - | mips64 | mips64el \ - | mips64vr | mips64vrel \ - | mips64orion | mips64orionel \ - | mips64vr4100 | mips64vr4100el \ - | mips64vr4300 | mips64vr4300el \ - | mips64vr5000 | mips64vr5000el \ - | mips64vr5900 | mips64vr5900el \ - | mipsisa32 | mipsisa32el \ - | mipsisa32r2 | mipsisa32r2el \ - | mipsisa64 | mipsisa64el \ - | mipsisa64r2 | mipsisa64r2el \ - | mipsisa64sb1 | mipsisa64sb1el \ - | mipsisa64sr71k | mipsisa64sr71kel \ - | mipstx39 | mipstx39el \ - | mn10200 | mn10300 \ - | mt \ - | msp430 \ - | nios | nios2 \ - | ns16k | ns32k \ - | or32 \ - | pdp10 | pdp11 | pj | pjl \ - | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ - | pyramid \ - | score \ - | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ - | sh64 | sh64le \ - | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ - | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ - | spu | strongarm \ - | tahoe | thumb | tic4x | tic80 | tron \ - | v850 | v850e \ - | we32k \ - | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ - | z8k) - basic_machine=$basic_machine-unknown - ;; - m6811 | m68hc11 | m6812 | m68hc12) - # Motorola 68HC11/12. - basic_machine=$basic_machine-unknown - os=-none - ;; - m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) - ;; - ms1) - basic_machine=mt-unknown - ;; - - # We use `pc' rather than `unknown' - # because (1) that's what they normally are, and - # (2) the word "unknown" tends to confuse beginning users. - i*86 | x86_64) - basic_machine=$basic_machine-pc - ;; - # Object if more than one company name word. - *-*-*) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 - ;; - # Recognize the basic CPU types with company name. - 580-* \ - | a29k-* \ - | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ - | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ - | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ - | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ - | avr-* | avr32-* \ - | bfin-* | bs2000-* \ - | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ - | clipper-* | craynv-* | cydra-* \ - | d10v-* | d30v-* | dlx-* \ - | elxsi-* \ - | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ - | h8300-* | h8500-* \ - | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ - | i*86-* | i860-* | i960-* | ia64-* \ - | ip2k-* | iq2000-* \ - | m32c-* | m32r-* | m32rle-* \ - | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* \ - | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ - | mips16-* \ - | mips64-* | mips64el-* \ - | mips64vr-* | mips64vrel-* \ - | mips64orion-* | mips64orionel-* \ - | mips64vr4100-* | mips64vr4100el-* \ - | mips64vr4300-* | mips64vr4300el-* \ - | mips64vr5000-* | mips64vr5000el-* \ - | mips64vr5900-* | mips64vr5900el-* \ - | mipsisa32-* | mipsisa32el-* \ - | mipsisa32r2-* | mipsisa32r2el-* \ - | mipsisa64-* | mipsisa64el-* \ - | mipsisa64r2-* | mipsisa64r2el-* \ - | mipsisa64sb1-* | mipsisa64sb1el-* \ - | mipsisa64sr71k-* | mipsisa64sr71kel-* \ - | mipstx39-* | mipstx39el-* \ - | mmix-* \ - | mt-* \ - | msp430-* \ - | nios-* | nios2-* \ - | none-* | np1-* | ns16k-* | ns32k-* \ - | orion-* \ - | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ - | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ - | pyramid-* \ - | romp-* | rs6000-* \ - | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ - | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ - | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ - | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ - | tahoe-* | thumb-* \ - | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ - | tron-* \ - | v850-* | v850e-* | vax-* \ - | we32k-* \ - | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ - | xstormy16-* | xtensa-* \ - | ymp-* \ - | z8k-*) - ;; - # Recognize the various machine names and aliases which stand - # for a CPU type and a company and sometimes even an OS. - 386bsd) - basic_machine=i386-unknown - os=-bsd - ;; - 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) - basic_machine=m68000-att - ;; - 3b*) - basic_machine=we32k-att - ;; - a29khif) - basic_machine=a29k-amd - os=-udi - ;; - abacus) - basic_machine=abacus-unknown - ;; - adobe68k) - basic_machine=m68010-adobe - os=-scout - ;; - alliant | fx80) - basic_machine=fx80-alliant - ;; - altos | altos3068) - basic_machine=m68k-altos - ;; - am29k) - basic_machine=a29k-none - os=-bsd - ;; - amd64) - basic_machine=x86_64-pc - ;; - amd64-*) - basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - amdahl) - basic_machine=580-amdahl - os=-sysv - ;; - amiga | amiga-*) - basic_machine=m68k-unknown - ;; - amigaos | amigados) - basic_machine=m68k-unknown - os=-amigaos - ;; - amigaunix | amix) - basic_machine=m68k-unknown - os=-sysv4 - ;; - apollo68) - basic_machine=m68k-apollo - os=-sysv - ;; - apollo68bsd) - basic_machine=m68k-apollo - os=-bsd - ;; - aux) - basic_machine=m68k-apple - os=-aux - ;; - balance) - basic_machine=ns32k-sequent - os=-dynix - ;; - c90) - basic_machine=c90-cray - os=-unicos - ;; - convex-c1) - basic_machine=c1-convex - os=-bsd - ;; - convex-c2) - basic_machine=c2-convex - os=-bsd - ;; - convex-c32) - basic_machine=c32-convex - os=-bsd - ;; - convex-c34) - basic_machine=c34-convex - os=-bsd - ;; - convex-c38) - basic_machine=c38-convex - os=-bsd - ;; - cray | j90) - basic_machine=j90-cray - os=-unicos - ;; - craynv) - basic_machine=craynv-cray - os=-unicosmp - ;; - cr16c) - basic_machine=cr16c-unknown - os=-elf - ;; - crds | unos) - basic_machine=m68k-crds - ;; - crisv32 | crisv32-* | etraxfs*) - basic_machine=crisv32-axis - ;; - cris | cris-* | etrax*) - basic_machine=cris-axis - ;; - crx) - basic_machine=crx-unknown - os=-elf - ;; - da30 | da30-*) - basic_machine=m68k-da30 - ;; - decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) - basic_machine=mips-dec - ;; - decsystem10* | dec10*) - basic_machine=pdp10-dec - os=-tops10 - ;; - decsystem20* | dec20*) - basic_machine=pdp10-dec - os=-tops20 - ;; - delta | 3300 | motorola-3300 | motorola-delta \ - | 3300-motorola | delta-motorola) - basic_machine=m68k-motorola - ;; - delta88) - basic_machine=m88k-motorola - os=-sysv3 - ;; - djgpp) - basic_machine=i586-pc - os=-msdosdjgpp - ;; - dpx20 | dpx20-*) - basic_machine=rs6000-bull - os=-bosx - ;; - dpx2* | dpx2*-bull) - basic_machine=m68k-bull - os=-sysv3 - ;; - ebmon29k) - basic_machine=a29k-amd - os=-ebmon - ;; - elxsi) - basic_machine=elxsi-elxsi - os=-bsd - ;; - encore | umax | mmax) - basic_machine=ns32k-encore - ;; - es1800 | OSE68k | ose68k | ose | OSE) - basic_machine=m68k-ericsson - os=-ose - ;; - fx2800) - basic_machine=i860-alliant - ;; - genix) - basic_machine=ns32k-ns - ;; - gmicro) - basic_machine=tron-gmicro - os=-sysv - ;; - go32) - basic_machine=i386-pc - os=-go32 - ;; - h3050r* | hiux*) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - h8300hms) - basic_machine=h8300-hitachi - os=-hms - ;; - h8300xray) - basic_machine=h8300-hitachi - os=-xray - ;; - h8500hms) - basic_machine=h8500-hitachi - os=-hms - ;; - harris) - basic_machine=m88k-harris - os=-sysv3 - ;; - hp300-*) - basic_machine=m68k-hp - ;; - hp300bsd) - basic_machine=m68k-hp - os=-bsd - ;; - hp300hpux) - basic_machine=m68k-hp - os=-hpux - ;; - hp3k9[0-9][0-9] | hp9[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k2[0-9][0-9] | hp9k31[0-9]) - basic_machine=m68000-hp - ;; - hp9k3[2-9][0-9]) - basic_machine=m68k-hp - ;; - hp9k6[0-9][0-9] | hp6[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k7[0-79][0-9] | hp7[0-79][0-9]) - basic_machine=hppa1.1-hp - ;; - hp9k78[0-9] | hp78[0-9]) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][13679] | hp8[0-9][13679]) - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][0-9] | hp8[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hppa-next) - os=-nextstep3 - ;; - hppaosf) - basic_machine=hppa1.1-hp - os=-osf - ;; - hppro) - basic_machine=hppa1.1-hp - os=-proelf - ;; - i370-ibm* | ibm*) - basic_machine=i370-ibm - ;; -# I'm not sure what "Sysv32" means. Should this be sysv3.2? - i*86v32) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv32 - ;; - i*86v4*) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv4 - ;; - i*86v) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv - ;; - i*86sol2) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-solaris2 - ;; - i386mach) - basic_machine=i386-mach - os=-mach - ;; - i386-vsta | vsta) - basic_machine=i386-unknown - os=-vsta - ;; - iris | iris4d) - basic_machine=mips-sgi - case $os in - -irix*) - ;; - *) - os=-irix4 - ;; - esac - ;; - isi68 | isi) - basic_machine=m68k-isi - os=-sysv - ;; - m88k-omron*) - basic_machine=m88k-omron - ;; - magnum | m3230) - basic_machine=mips-mips - os=-sysv - ;; - merlin) - basic_machine=ns32k-utek - os=-sysv - ;; - mingw32) - basic_machine=i386-pc - os=-mingw32 - ;; - miniframe) - basic_machine=m68000-convergent - ;; - *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) - basic_machine=m68k-atari - os=-mint - ;; - mips3*-*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` - ;; - mips3*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown - ;; - monitor) - basic_machine=m68k-rom68k - os=-coff - ;; - morphos) - basic_machine=powerpc-unknown - os=-morphos - ;; - msdos) - basic_machine=i386-pc - os=-msdos - ;; - ms1-*) - basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` - ;; - mvs) - basic_machine=i370-ibm - os=-mvs - ;; - ncr3000) - basic_machine=i486-ncr - os=-sysv4 - ;; - netbsd386) - basic_machine=i386-unknown - os=-netbsd - ;; - netwinder) - basic_machine=armv4l-rebel - os=-linux - ;; - news | news700 | news800 | news900) - basic_machine=m68k-sony - os=-newsos - ;; - news1000) - basic_machine=m68030-sony - os=-newsos - ;; - news-3600 | risc-news) - basic_machine=mips-sony - os=-newsos - ;; - necv70) - basic_machine=v70-nec - os=-sysv - ;; - next | m*-next ) - basic_machine=m68k-next - case $os in - -nextstep* ) - ;; - -ns2*) - os=-nextstep2 - ;; - *) - os=-nextstep3 - ;; - esac - ;; - nh3000) - basic_machine=m68k-harris - os=-cxux - ;; - nh[45]000) - basic_machine=m88k-harris - os=-cxux - ;; - nindy960) - basic_machine=i960-intel - os=-nindy - ;; - mon960) - basic_machine=i960-intel - os=-mon960 - ;; - nonstopux) - basic_machine=mips-compaq - os=-nonstopux - ;; - np1) - basic_machine=np1-gould - ;; - nsr-tandem) - basic_machine=nsr-tandem - ;; - op50n-* | op60c-*) - basic_machine=hppa1.1-oki - os=-proelf - ;; - openrisc | openrisc-*) - basic_machine=or32-unknown - ;; - os400) - basic_machine=powerpc-ibm - os=-os400 - ;; - OSE68000 | ose68000) - basic_machine=m68000-ericsson - os=-ose - ;; - os68k) - basic_machine=m68k-none - os=-os68k - ;; - pa-hitachi) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - paragon) - basic_machine=i860-intel - os=-osf - ;; - pbd) - basic_machine=sparc-tti - ;; - pbb) - basic_machine=m68k-tti - ;; - pc532 | pc532-*) - basic_machine=ns32k-pc532 - ;; - pc98) - basic_machine=i386-pc - ;; - pc98-*) - basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentium | p5 | k5 | k6 | nexgen | viac3) - basic_machine=i586-pc - ;; - pentiumpro | p6 | 6x86 | athlon | athlon_*) - basic_machine=i686-pc - ;; - pentiumii | pentium2 | pentiumiii | pentium3) - basic_machine=i686-pc - ;; - pentium4) - basic_machine=i786-pc - ;; - pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) - basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentiumpro-* | p6-* | 6x86-* | athlon-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentium4-*) - basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pn) - basic_machine=pn-gould - ;; - power) basic_machine=power-ibm - ;; - ppc) basic_machine=powerpc-unknown - ;; - ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppcle | powerpclittle | ppc-le | powerpc-little) - basic_machine=powerpcle-unknown - ;; - ppcle-* | powerpclittle-*) - basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppc64) basic_machine=powerpc64-unknown - ;; - ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppc64le | powerpc64little | ppc64-le | powerpc64-little) - basic_machine=powerpc64le-unknown - ;; - ppc64le-* | powerpc64little-*) - basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ps2) - basic_machine=i386-ibm - ;; - pw32) - basic_machine=i586-unknown - os=-pw32 - ;; - rdos) - basic_machine=i386-pc - os=-rdos - ;; - rom68k) - basic_machine=m68k-rom68k - os=-coff - ;; - rm[46]00) - basic_machine=mips-siemens - ;; - rtpc | rtpc-*) - basic_machine=romp-ibm - ;; - s390 | s390-*) - basic_machine=s390-ibm - ;; - s390x | s390x-*) - basic_machine=s390x-ibm - ;; - sa29200) - basic_machine=a29k-amd - os=-udi - ;; - sb1) - basic_machine=mipsisa64sb1-unknown - ;; - sb1el) - basic_machine=mipsisa64sb1el-unknown - ;; - sde) - basic_machine=mipsisa32-sde - os=-elf - ;; - sei) - basic_machine=mips-sei - os=-seiux - ;; - sequent) - basic_machine=i386-sequent - ;; - sh) - basic_machine=sh-hitachi - os=-hms - ;; - sh5el) - basic_machine=sh5le-unknown - ;; - sh64) - basic_machine=sh64-unknown - ;; - sparclite-wrs | simso-wrs) - basic_machine=sparclite-wrs - os=-vxworks - ;; - sps7) - basic_machine=m68k-bull - os=-sysv2 - ;; - spur) - basic_machine=spur-unknown - ;; - st2000) - basic_machine=m68k-tandem - ;; - stratus) - basic_machine=i860-stratus - os=-sysv4 - ;; - sun2) - basic_machine=m68000-sun - ;; - sun2os3) - basic_machine=m68000-sun - os=-sunos3 - ;; - sun2os4) - basic_machine=m68000-sun - os=-sunos4 - ;; - sun3os3) - basic_machine=m68k-sun - os=-sunos3 - ;; - sun3os4) - basic_machine=m68k-sun - os=-sunos4 - ;; - sun4os3) - basic_machine=sparc-sun - os=-sunos3 - ;; - sun4os4) - basic_machine=sparc-sun - os=-sunos4 - ;; - sun4sol2) - basic_machine=sparc-sun - os=-solaris2 - ;; - sun3 | sun3-*) - basic_machine=m68k-sun - ;; - sun4) - basic_machine=sparc-sun - ;; - sun386 | sun386i | roadrunner) - basic_machine=i386-sun - ;; - sv1) - basic_machine=sv1-cray - os=-unicos - ;; - symmetry) - basic_machine=i386-sequent - os=-dynix - ;; - t3e) - basic_machine=alphaev5-cray - os=-unicos - ;; - t90) - basic_machine=t90-cray - os=-unicos - ;; - tic54x | c54x*) - basic_machine=tic54x-unknown - os=-coff - ;; - tic55x | c55x*) - basic_machine=tic55x-unknown - os=-coff - ;; - tic6x | c6x*) - basic_machine=tic6x-unknown - os=-coff - ;; - tx39) - basic_machine=mipstx39-unknown - ;; - tx39el) - basic_machine=mipstx39el-unknown - ;; - toad1) - basic_machine=pdp10-xkl - os=-tops20 - ;; - tower | tower-32) - basic_machine=m68k-ncr - ;; - tpf) - basic_machine=s390x-ibm - os=-tpf - ;; - udi29k) - basic_machine=a29k-amd - os=-udi - ;; - ultra3) - basic_machine=a29k-nyu - os=-sym1 - ;; - v810 | necv810) - basic_machine=v810-nec - os=-none - ;; - vaxv) - basic_machine=vax-dec - os=-sysv - ;; - vms) - basic_machine=vax-dec - os=-vms - ;; - vpp*|vx|vx-*) - basic_machine=f301-fujitsu - ;; - vxworks960) - basic_machine=i960-wrs - os=-vxworks - ;; - vxworks68) - basic_machine=m68k-wrs - os=-vxworks - ;; - vxworks29k) - basic_machine=a29k-wrs - os=-vxworks - ;; - w65*) - basic_machine=w65-wdc - os=-none - ;; - w89k-*) - basic_machine=hppa1.1-winbond - os=-proelf - ;; - xbox) - basic_machine=i686-pc - os=-mingw32 - ;; - xps | xps100) - basic_machine=xps100-honeywell - ;; - ymp) - basic_machine=ymp-cray - os=-unicos - ;; - z8k-*-coff) - basic_machine=z8k-unknown - os=-sim - ;; - none) - basic_machine=none-none - os=-none - ;; - -# Here we handle the default manufacturer of certain CPU types. It is in -# some cases the only manufacturer, in others, it is the most popular. - w89k) - basic_machine=hppa1.1-winbond - ;; - op50n) - basic_machine=hppa1.1-oki - ;; - op60c) - basic_machine=hppa1.1-oki - ;; - romp) - basic_machine=romp-ibm - ;; - mmix) - basic_machine=mmix-knuth - ;; - rs6000) - basic_machine=rs6000-ibm - ;; - vax) - basic_machine=vax-dec - ;; - pdp10) - # there are many clones, so DEC is not a safe bet - basic_machine=pdp10-unknown - ;; - pdp11) - basic_machine=pdp11-dec - ;; - we32k) - basic_machine=we32k-att - ;; - sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) - basic_machine=sh-unknown - ;; - sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) - basic_machine=sparc-sun - ;; - cydra) - basic_machine=cydra-cydrome - ;; - orion) - basic_machine=orion-highlevel - ;; - orion105) - basic_machine=clipper-highlevel - ;; - mac | mpw | mac-mpw) - basic_machine=m68k-apple - ;; - pmac | pmac-mpw) - basic_machine=powerpc-apple - ;; - *-unknown) - # Make sure to match an already-canonicalized machine name. - ;; - *) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 - ;; -esac - -# Here we canonicalize certain aliases for manufacturers. -case $basic_machine in - *-digital*) - basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` - ;; - *-commodore*) - basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` - ;; - *) - ;; -esac - -# Decode manufacturer-specific aliases for certain operating systems. - -if [ x"$os" != x"" ] -then -case $os in - # First match some system type aliases - # that might get confused with valid system types. - # -solaris* is a basic system type, with this one exception. - -solaris1 | -solaris1.*) - os=`echo $os | sed -e 's|solaris1|sunos4|'` - ;; - -solaris) - os=-solaris2 - ;; - -svr4*) - os=-sysv4 - ;; - -unixware*) - os=-sysv4.2uw - ;; - -gnu/linux*) - os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` - ;; - # First accept the basic system types. - # The portable systems comes first. - # Each alternative MUST END IN A *, to match a version number. - # -sysv* is not here because it comes later, after sysvr4. - -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -openbsd* | -solidbsd* \ - | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ - | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ - | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ - | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -chorusos* | -chorusrdb* \ - | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* \ - | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ - | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ - | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ - | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ - | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ - | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) - # Remember, each alternative MUST END IN *, to match a version number. - ;; - -qnx*) - case $basic_machine in - x86-* | i*86-*) - ;; - *) - os=-nto$os - ;; - esac - ;; - -nto-qnx*) - ;; - -nto*) - os=`echo $os | sed -e 's|nto|nto-qnx|'` - ;; - -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ - | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ - | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) - ;; - -mac*) - os=`echo $os | sed -e 's|mac|macos|'` - ;; - -linux-dietlibc) - os=-linux-dietlibc - ;; - -linux*) - os=`echo $os | sed -e 's|linux|linux-gnu|'` - ;; - -sunos5*) - os=`echo $os | sed -e 's|sunos5|solaris2|'` - ;; - -sunos6*) - os=`echo $os | sed -e 's|sunos6|solaris3|'` - ;; - -opened*) - os=-openedition - ;; - -os400*) - os=-os400 - ;; - -wince*) - os=-wince - ;; - -osfrose*) - os=-osfrose - ;; - -osf*) - os=-osf - ;; - -utek*) - os=-bsd - ;; - -dynix*) - os=-bsd - ;; - -acis*) - os=-aos - ;; - -atheos*) - os=-atheos - ;; - -syllable*) - os=-syllable - ;; - -386bsd) - os=-bsd - ;; - -ctix* | -uts*) - os=-sysv - ;; - -nova*) - os=-rtmk-nova - ;; - -ns2 ) - os=-nextstep2 - ;; - -nsk*) - os=-nsk - ;; - # Preserve the version number of sinix5. - -sinix5.*) - os=`echo $os | sed -e 's|sinix|sysv|'` - ;; - -sinix*) - os=-sysv4 - ;; - -tpf*) - os=-tpf - ;; - -triton*) - os=-sysv3 - ;; - -oss*) - os=-sysv3 - ;; - -svr4) - os=-sysv4 - ;; - -svr3) - os=-sysv3 - ;; - -sysvr4) - os=-sysv4 - ;; - # This must come after -sysvr4. - -sysv*) - ;; - -ose*) - os=-ose - ;; - -es1800*) - os=-ose - ;; - -xenix) - os=-xenix - ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) - os=-mint - ;; - -aros*) - os=-aros - ;; - -kaos*) - os=-kaos - ;; - -zvmoe) - os=-zvmoe - ;; - -none) - ;; - *) - # Get rid of the `-' at the beginning of $os. - os=`echo $os | sed 's/[^-]*-//'` - echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 - exit 1 - ;; -esac -else - -# Here we handle the default operating systems that come with various machines. -# The value should be what the vendor currently ships out the door with their -# machine or put another way, the most popular os provided with the machine. - -# Note that if you're going to try to match "-MANUFACTURER" here (say, -# "-sun"), then you have to tell the case statement up towards the top -# that MANUFACTURER isn't an operating system. Otherwise, code above -# will signal an error saying that MANUFACTURER isn't an operating -# system, and we'll never get to this point. - -case $basic_machine in - score-*) - os=-elf - ;; - spu-*) - os=-elf - ;; - *-acorn) - os=-riscix1.2 - ;; - arm*-rebel) - os=-linux - ;; - arm*-semi) - os=-aout - ;; - c4x-* | tic4x-*) - os=-coff - ;; - # This must come before the *-dec entry. - pdp10-*) - os=-tops20 - ;; - pdp11-*) - os=-none - ;; - *-dec | vax-*) - os=-ultrix4.2 - ;; - m68*-apollo) - os=-domain - ;; - i386-sun) - os=-sunos4.0.2 - ;; - m68000-sun) - os=-sunos3 - # This also exists in the configure program, but was not the - # default. - # os=-sunos4 - ;; - m68*-cisco) - os=-aout - ;; - mep-*) - os=-elf - ;; - mips*-cisco) - os=-elf - ;; - mips*-*) - os=-elf - ;; - or32-*) - os=-coff - ;; - *-tti) # must be before sparc entry or we get the wrong os. - os=-sysv3 - ;; - sparc-* | *-sun) - os=-sunos4.1.1 - ;; - *-be) - os=-beos - ;; - *-haiku) - os=-haiku - ;; - *-ibm) - os=-aix - ;; - *-knuth) - os=-mmixware - ;; - *-wec) - os=-proelf - ;; - *-winbond) - os=-proelf - ;; - *-oki) - os=-proelf - ;; - *-hp) - os=-hpux - ;; - *-hitachi) - os=-hiux - ;; - i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) - os=-sysv - ;; - *-cbm) - os=-amigaos - ;; - *-dg) - os=-dgux - ;; - *-dolphin) - os=-sysv3 - ;; - m68k-ccur) - os=-rtu - ;; - m88k-omron*) - os=-luna - ;; - *-next ) - os=-nextstep - ;; - *-sequent) - os=-ptx - ;; - *-crds) - os=-unos - ;; - *-ns) - os=-genix - ;; - i370-*) - os=-mvs - ;; - *-next) - os=-nextstep3 - ;; - *-gould) - os=-sysv - ;; - *-highlevel) - os=-bsd - ;; - *-encore) - os=-bsd - ;; - *-sgi) - os=-irix - ;; - *-siemens) - os=-sysv4 - ;; - *-masscomp) - os=-rtu - ;; - f30[01]-fujitsu | f700-fujitsu) - os=-uxpv - ;; - *-rom68k) - os=-coff - ;; - *-*bug) - os=-coff - ;; - *-apple) - os=-macos - ;; - *-atari*) - os=-mint - ;; - *) - os=-none - ;; -esac -fi - -# Here we handle the case where we know the os, and the CPU type, but not the -# manufacturer. We pick the logical manufacturer. -vendor=unknown -case $basic_machine in - *-unknown) - case $os in - -riscix*) - vendor=acorn - ;; - -sunos*) - vendor=sun - ;; - -aix*) - vendor=ibm - ;; - -beos*) - vendor=be - ;; - -hpux*) - vendor=hp - ;; - -mpeix*) - vendor=hp - ;; - -hiux*) - vendor=hitachi - ;; - -unos*) - vendor=crds - ;; - -dgux*) - vendor=dg - ;; - -luna*) - vendor=omron - ;; - -genix*) - vendor=ns - ;; - -mvs* | -opened*) - vendor=ibm - ;; - -os400*) - vendor=ibm - ;; - -ptx*) - vendor=sequent - ;; - -tpf*) - vendor=ibm - ;; - -vxsim* | -vxworks* | -windiss*) - vendor=wrs - ;; - -aux*) - vendor=apple - ;; - -hms*) - vendor=hitachi - ;; - -mpw* | -macos*) - vendor=apple - ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) - vendor=atari - ;; - -vos*) - vendor=stratus - ;; - esac - basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` - ;; -esac - -echo $basic_machine$os -exit - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "timestamp='" -# time-stamp-format: "%:y-%02m-%02d" -# time-stamp-end: "'" -# End: diff --git a/libltdl/configure b/libltdl/configure deleted file mode 100755 index aa2994e0..00000000 --- a/libltdl/configure +++ /dev/null @@ -1,23853 +0,0 @@ -#! /bin/sh -# Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.61 for libltdl 1.2. -# -# Report bugs to . -# -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. -# This configure script is free software; the Free Software Foundation -# gives unlimited permission to copy, distribute and modify it. -## --------------------- ## -## M4sh Initialization. ## -## --------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in - *posix*) set -o posix ;; -esac - -fi - - - - -# PATH needs CR -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - echo "#! /bin/sh" >conf$$.sh - echo "exit 0" >>conf$$.sh - chmod +x conf$$.sh - if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then - PATH_SEPARATOR=';' - else - PATH_SEPARATOR=: - fi - rm -f conf$$.sh -fi - -# Support unset when possible. -if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then - as_unset=unset -else - as_unset=false -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -as_nl=' -' -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -case $0 in - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break -done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - { (exit 1); exit 1; } -fi - -# Work around bugs in pre-3.0 UWIN ksh. -for as_var in ENV MAIL MAILPATH -do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -for as_var in \ - LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ - LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ - LC_TELEPHONE LC_TIME -do - if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then - eval $as_var=C; export $as_var - else - ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var - fi -done - -# Required to use basename. -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - - -# Name of the executable. -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# CDPATH. -$as_unset CDPATH - - -if test "x$CONFIG_SHELL" = x; then - if (eval ":") 2>/dev/null; then - as_have_required=yes -else - as_have_required=no -fi - - if test $as_have_required = yes && (eval ": -(as_func_return () { - (exit \$1) -} -as_func_success () { - as_func_return 0 -} -as_func_failure () { - as_func_return 1 -} -as_func_ret_success () { - return 0 -} -as_func_ret_failure () { - return 1 -} - -exitcode=0 -if as_func_success; then - : -else - exitcode=1 - echo as_func_success failed. -fi - -if as_func_failure; then - exitcode=1 - echo as_func_failure succeeded. -fi - -if as_func_ret_success; then - : -else - exitcode=1 - echo as_func_ret_success failed. -fi - -if as_func_ret_failure; then - exitcode=1 - echo as_func_ret_failure succeeded. -fi - -if ( set x; as_func_ret_success y && test x = \"\$1\" ); then - : -else - exitcode=1 - echo positional parameters were not saved. -fi - -test \$exitcode = 0) || { (exit 1); exit 1; } - -( - as_lineno_1=\$LINENO - as_lineno_2=\$LINENO - test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && - test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } -") 2> /dev/null; then - : -else - as_candidate_shells= - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - case $as_dir in - /*) - for as_base in sh bash ksh sh5; do - as_candidate_shells="$as_candidate_shells $as_dir/$as_base" - done;; - esac -done -IFS=$as_save_IFS - - - for as_shell in $as_candidate_shells $SHELL; do - # Try only shells that exist, to save several forks. - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { ("$as_shell") 2> /dev/null <<\_ASEOF -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in - *posix*) set -o posix ;; -esac - -fi - - -: -_ASEOF -}; then - CONFIG_SHELL=$as_shell - as_have_required=yes - if { "$as_shell" 2> /dev/null <<\_ASEOF -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in - *posix*) set -o posix ;; -esac - -fi - - -: -(as_func_return () { - (exit $1) -} -as_func_success () { - as_func_return 0 -} -as_func_failure () { - as_func_return 1 -} -as_func_ret_success () { - return 0 -} -as_func_ret_failure () { - return 1 -} - -exitcode=0 -if as_func_success; then - : -else - exitcode=1 - echo as_func_success failed. -fi - -if as_func_failure; then - exitcode=1 - echo as_func_failure succeeded. -fi - -if as_func_ret_success; then - : -else - exitcode=1 - echo as_func_ret_success failed. -fi - -if as_func_ret_failure; then - exitcode=1 - echo as_func_ret_failure succeeded. -fi - -if ( set x; as_func_ret_success y && test x = "$1" ); then - : -else - exitcode=1 - echo positional parameters were not saved. -fi - -test $exitcode = 0) || { (exit 1); exit 1; } - -( - as_lineno_1=$LINENO - as_lineno_2=$LINENO - test "x$as_lineno_1" != "x$as_lineno_2" && - test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } - -_ASEOF -}; then - break -fi - -fi - - done - - if test "x$CONFIG_SHELL" != x; then - for as_var in BASH_ENV ENV - do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var - done - export CONFIG_SHELL - exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} -fi - - - if test $as_have_required = no; then - echo This script requires a shell more modern than all the - echo shells that I found on your system. Please install a - echo modern shell, or manually run the script under such a - echo shell if you do have one. - { (exit 1); exit 1; } -fi - - -fi - -fi - - - -(eval "as_func_return () { - (exit \$1) -} -as_func_success () { - as_func_return 0 -} -as_func_failure () { - as_func_return 1 -} -as_func_ret_success () { - return 0 -} -as_func_ret_failure () { - return 1 -} - -exitcode=0 -if as_func_success; then - : -else - exitcode=1 - echo as_func_success failed. -fi - -if as_func_failure; then - exitcode=1 - echo as_func_failure succeeded. -fi - -if as_func_ret_success; then - : -else - exitcode=1 - echo as_func_ret_success failed. -fi - -if as_func_ret_failure; then - exitcode=1 - echo as_func_ret_failure succeeded. -fi - -if ( set x; as_func_ret_success y && test x = \"\$1\" ); then - : -else - exitcode=1 - echo positional parameters were not saved. -fi - -test \$exitcode = 0") || { - echo No shell found that supports shell functions. - echo Please tell autoconf@gnu.org about your system, - echo including any error possibly output before this - echo message -} - - - - as_lineno_1=$LINENO - as_lineno_2=$LINENO - test "x$as_lineno_1" != "x$as_lineno_2" && - test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { - - # Create $as_me.lineno as a copy of $as_myself, but with $LINENO - # uniformly replaced by the line number. The first 'sed' inserts a - # line-number line after each line using $LINENO; the second 'sed' - # does the real work. The second script uses 'N' to pair each - # line-number line with the line containing $LINENO, and appends - # trailing '-' during substitution so that $LINENO is not a special - # case at line end. - # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the - # scripts with optimization help from Paolo Bonzini. Blame Lee - # E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 - { (exit 1); exit 1; }; } - - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in --n*) - case `echo 'x\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - *) ECHO_C='\c';; - esac;; -*) - ECHO_N='-n';; -esac - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir -fi -echo >conf$$.file -if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -p' -elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln -else - as_ln_s='cp -p' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p=: -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -if test -x / >/dev/null 2>&1; then - as_test_x='test -x' -else - if ls -dL / >/dev/null 2>&1; then - as_ls_L_option=L - else - as_ls_L_option= - fi - as_test_x=' - eval sh -c '\'' - if test -d "$1"; then - test -d "$1/."; - else - case $1 in - -*)set "./$1";; - esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in - ???[sx]*):;;*)false;;esac;fi - '\'' sh - ' -fi -as_executable_p=$as_test_x - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - - - -# Check that we are running under the correct shell. -SHELL=${CONFIG_SHELL-/bin/sh} - -case X$ECHO in -X*--fallback-echo) - # Remove one level of quotation (which was required for Make). - ECHO=`echo "$ECHO" | sed 's,\\\\\$\\$0,'$0','` - ;; -esac - -echo=${ECHO-echo} -if test "X$1" = X--no-reexec; then - # Discard the --no-reexec flag, and continue. - shift -elif test "X$1" = X--fallback-echo; then - # Avoid inline document here, it may be left over - : -elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then - # Yippee, $echo works! - : -else - # Restart under the correct shell. - exec $SHELL "$0" --no-reexec ${1+"$@"} -fi - -if test "X$1" = X--fallback-echo; then - # used as fallback echo - shift - cat </dev/null 2>&1 && unset CDPATH - -if test -z "$ECHO"; then -if test "X${echo_test_string+set}" != Xset; then -# find a string as large as possible, as long as the shell can cope with it - for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do - # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... - if (echo_test_string=`eval $cmd`) 2>/dev/null && - echo_test_string=`eval $cmd` && - (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null - then - break - fi - done -fi - -if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - : -else - # The Solaris, AIX, and Digital Unix default echo programs unquote - # backslashes. This makes it impossible to quote backslashes using - # echo "$something" | sed 's/\\/\\\\/g' - # - # So, first we look for a working echo in the user's PATH. - - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for dir in $PATH /usr/ucb; do - IFS="$lt_save_ifs" - if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && - test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - echo="$dir/echo" - break - fi - done - IFS="$lt_save_ifs" - - if test "X$echo" = Xecho; then - # We didn't find a better echo, so look for alternatives. - if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - # This shell has a builtin print -r that does the trick. - echo='print -r' - elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && - test "X$CONFIG_SHELL" != X/bin/ksh; then - # If we have ksh, try running configure again with it. - ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} - export ORIGINAL_CONFIG_SHELL - CONFIG_SHELL=/bin/ksh - export CONFIG_SHELL - exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} - else - # Try using printf. - echo='printf %s\n' - if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - # Cool, printf works - : - elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && - test "X$echo_testing_string" = 'X\t' && - echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL - export CONFIG_SHELL - SHELL="$CONFIG_SHELL" - export SHELL - echo="$CONFIG_SHELL $0 --fallback-echo" - elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && - test "X$echo_testing_string" = 'X\t' && - echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - echo="$CONFIG_SHELL $0 --fallback-echo" - else - # maybe with a smaller string... - prev=: - - for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do - if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null - then - break - fi - prev="$cmd" - done - - if test "$prev" != 'sed 50q "$0"'; then - echo_test_string=`eval $prev` - export echo_test_string - exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} - else - # Oops. We lost completely, so just stick with echo. - echo=echo - fi - fi - fi - fi -fi -fi - -# Copy echo and quote the copy suitably for passing to libtool from -# the Makefile, instead of quoting the original, which is used later. -ECHO=$echo -if test "X$ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then - ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" -fi - - - - -tagnames=${tagnames+${tagnames},}CXX - -tagnames=${tagnames+${tagnames},}F77 - -exec 7<&0 &1 - -# Name of the host. -# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, -# so uname gets run too. -ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` - -# -# Initializations. -# -ac_default_prefix=/usr/local -ac_clean_files= -ac_config_libobj_dir=. -LIBOBJS= -cross_compiling=no -subdirs= -MFLAGS= -MAKEFLAGS= -SHELL=${CONFIG_SHELL-/bin/sh} - -# Identity of this package. -PACKAGE_NAME='libltdl' -PACKAGE_TARNAME='libltdl' -PACKAGE_VERSION='1.2' -PACKAGE_STRING='libltdl 1.2' -PACKAGE_BUGREPORT='bug-libtool@gnu.org' - -ac_unique_file="ltdl.c" -# Factoring default headers for most tests. -ac_includes_default="\ -#include -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif -#ifdef HAVE_STRING_H -# if !defined STDC_HEADERS && defined HAVE_MEMORY_H -# include -# endif -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif -#ifdef HAVE_INTTYPES_H -# include -#endif -#ifdef HAVE_STDINT_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif" - -ac_subst_vars='SHELL -PATH_SEPARATOR -PACKAGE_NAME -PACKAGE_TARNAME -PACKAGE_VERSION -PACKAGE_STRING -PACKAGE_BUGREPORT -exec_prefix -prefix -program_transform_name -bindir -sbindir -libexecdir -datarootdir -datadir -sysconfdir -sharedstatedir -localstatedir -includedir -oldincludedir -docdir -infodir -htmldir -dvidir -pdfdir -psdir -libdir -localedir -mandir -DEFS -ECHO_C -ECHO_N -ECHO_T -LIBS -build_alias -host_alias -target_alias -INSTALL_PROGRAM -INSTALL_SCRIPT -INSTALL_DATA -am__isrc -CYGPATH_W -PACKAGE -VERSION -ACLOCAL -AUTOCONF -AUTOMAKE -AUTOHEADER -MAKEINFO -install_sh -STRIP -INSTALL_STRIP_PROGRAM -mkdir_p -AWK -SET_MAKE -am__leading_dot -AMTAR -am__tar -am__untar -CC -CFLAGS -LDFLAGS -CPPFLAGS -ac_ct_CC -EXEEXT -OBJEXT -DEPDIR -am__include -am__quote -AMDEP_TRUE -AMDEP_FALSE -AMDEPBACKSLASH -CCDEPMODE -am__fastdepCC_TRUE -am__fastdepCC_FALSE -build -build_cpu -build_vendor -build_os -host -host_cpu -host_vendor -host_os -SED -GREP -EGREP -LN_S -ECHO -AR -RANLIB -DLLTOOL -AS -OBJDUMP -CPP -CXX -CXXFLAGS -ac_ct_CXX -CXXDEPMODE -am__fastdepCXX_TRUE -am__fastdepCXX_FALSE -CXXCPP -F77 -FFLAGS -ac_ct_F77 -LIBTOOL -LIBTOOL_DEPS -INSTALL_LTDL_TRUE -INSTALL_LTDL_FALSE -CONVENIENCE_LTDL_TRUE -CONVENIENCE_LTDL_FALSE -LIBADD_DL -LIBOBJS -LTLIBOBJS' -ac_subst_files='' - ac_precious_vars='build_alias -host_alias -target_alias -CC -CFLAGS -LDFLAGS -LIBS -CPPFLAGS -CPP -CXX -CXXFLAGS -CCC -CXXCPP -F77 -FFLAGS' - - -# Initialize some variables set by options. -ac_init_help= -ac_init_version=false -# The variables have the same names as the options, with -# dashes changed to underlines. -cache_file=/dev/null -exec_prefix=NONE -no_create= -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -verbose= -x_includes=NONE -x_libraries=NONE - -# Installation directory options. -# These are left unexpanded so users can "make install exec_prefix=/foo" -# and all the variables that are supposed to be based on exec_prefix -# by default will actually change. -# Use braces instead of parens because sh, perl, etc. also accept them. -# (The list follows the same order as the GNU Coding Standards.) -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datarootdir='${prefix}/share' -datadir='${datarootdir}' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -includedir='${prefix}/include' -oldincludedir='/usr/include' -docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' -infodir='${datarootdir}/info' -htmldir='${docdir}' -dvidir='${docdir}' -pdfdir='${docdir}' -psdir='${docdir}' -libdir='${exec_prefix}/lib' -localedir='${datarootdir}/locale' -mandir='${datarootdir}/man' - -ac_prev= -ac_dashdash= -for ac_option -do - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval $ac_prev=\$ac_option - ac_prev= - continue - fi - - case $ac_option in - *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *) ac_optarg=yes ;; - esac - - # Accept the important Cygnus configure options, so we can diagnose typos. - - case $ac_dashdash$ac_option in - --) - ac_dashdash=yes ;; - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir=$ac_optarg ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build_alias ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build_alias=$ac_optarg ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file=$ac_optarg ;; - - --config-cache | -C) - cache_file=config.cache ;; - - -datadir | --datadir | --datadi | --datad) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=*) - datadir=$ac_optarg ;; - - -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ - | --dataroo | --dataro | --datar) - ac_prev=datarootdir ;; - -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ - | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) - datarootdir=$ac_optarg ;; - - -disable-* | --disable-*) - ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && - { echo "$as_me: error: invalid feature name: $ac_feature" >&2 - { (exit 1); exit 1; }; } - ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` - eval enable_$ac_feature=no ;; - - -docdir | --docdir | --docdi | --doc | --do) - ac_prev=docdir ;; - -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) - docdir=$ac_optarg ;; - - -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) - ac_prev=dvidir ;; - -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) - dvidir=$ac_optarg ;; - - -enable-* | --enable-*) - ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && - { echo "$as_me: error: invalid feature name: $ac_feature" >&2 - { (exit 1); exit 1; }; } - ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` - eval enable_$ac_feature=\$ac_optarg ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix=$ac_optarg ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he | -h) - ac_init_help=long ;; - -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) - ac_init_help=recursive ;; - -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) - ac_init_help=short ;; - - -host | --host | --hos | --ho) - ac_prev=host_alias ;; - -host=* | --host=* | --hos=* | --ho=*) - host_alias=$ac_optarg ;; - - -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) - ac_prev=htmldir ;; - -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ - | --ht=*) - htmldir=$ac_optarg ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir=$ac_optarg ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir=$ac_optarg ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir=$ac_optarg ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir=$ac_optarg ;; - - -localedir | --localedir | --localedi | --localed | --locale) - ac_prev=localedir ;; - -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) - localedir=$ac_optarg ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst | --locals) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) - localstatedir=$ac_optarg ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir=$ac_optarg ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir=$ac_optarg ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=$ac_optarg ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix=$ac_optarg ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix=$ac_optarg ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name=$ac_optarg ;; - - -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) - ac_prev=pdfdir ;; - -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) - pdfdir=$ac_optarg ;; - - -psdir | --psdir | --psdi | --psd | --ps) - ac_prev=psdir ;; - -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) - psdir=$ac_optarg ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir=$ac_optarg ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir=$ac_optarg ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site=$ac_optarg ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir=$ac_optarg ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir=$ac_optarg ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target_alias ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target_alias=$ac_optarg ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers | -V) - ac_init_version=: ;; - - -with-* | --with-*) - ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && - { echo "$as_me: error: invalid package name: $ac_package" >&2 - { (exit 1); exit 1; }; } - ac_package=`echo $ac_package | sed 's/[-.]/_/g'` - eval with_$ac_package=\$ac_optarg ;; - - -without-* | --without-*) - ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && - { echo "$as_me: error: invalid package name: $ac_package" >&2 - { (exit 1); exit 1; }; } - ac_package=`echo $ac_package | sed 's/[-.]/_/g'` - eval with_$ac_package=no ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes=$ac_optarg ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - - -*) { echo "$as_me: error: unrecognized option: $ac_option -Try \`$0 --help' for more information." >&2 - { (exit 1); exit 1; }; } - ;; - - *=*) - ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` - # Reject names that are not valid shell variable names. - expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && - { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 - { (exit 1); exit 1; }; } - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; - - *) - # FIXME: should be removed in autoconf 3.0. - echo "$as_me: WARNING: you should use --build, --host, --target" >&2 - expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} - ;; - - esac -done - -if test -n "$ac_prev"; then - ac_option=--`echo $ac_prev | sed 's/_/-/g'` - { echo "$as_me: error: missing argument to $ac_option" >&2 - { (exit 1); exit 1; }; } -fi - -# Be sure to have absolute directory names. -for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ - datadir sysconfdir sharedstatedir localstatedir includedir \ - oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir -do - eval ac_val=\$$ac_var - case $ac_val in - [\\/$]* | ?:[\\/]* ) continue;; - NONE | '' ) case $ac_var in *prefix ) continue;; esac;; - esac - { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 - { (exit 1); exit 1; }; } -done - -# There might be people who depend on the old broken behavior: `$host' -# used to hold the argument of --host etc. -# FIXME: To remove some day. -build=$build_alias -host=$host_alias -target=$target_alias - -# FIXME: To remove some day. -if test "x$host_alias" != x; then - if test "x$build_alias" = x; then - cross_compiling=maybe - echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. - If a cross compiler is detected then cross compile mode will be used." >&2 - elif test "x$build_alias" != "x$host_alias"; then - cross_compiling=yes - fi -fi - -ac_tool_prefix= -test -n "$host_alias" && ac_tool_prefix=$host_alias- - -test "$silent" = yes && exec 6>/dev/null - - -ac_pwd=`pwd` && test -n "$ac_pwd" && -ac_ls_di=`ls -di .` && -ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - { echo "$as_me: error: Working directory cannot be determined" >&2 - { (exit 1); exit 1; }; } -test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - { echo "$as_me: error: pwd does not report name of working directory" >&2 - { (exit 1); exit 1; }; } - - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$0" || -$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$0" : 'X\(//\)[^/]' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -echo X"$0" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r "$srcdir/$ac_unique_file"; then - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 - { (exit 1); exit 1; }; } -fi -ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" -ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2 - { (exit 1); exit 1; }; } - pwd)` -# When building in place, set srcdir=. -if test "$ac_abs_confdir" = "$ac_pwd"; then - srcdir=. -fi -# Remove unnecessary trailing slashes from srcdir. -# Double slashes in file names in object file debugging info -# mess up M-x gdb in Emacs. -case $srcdir in -*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; -esac -for ac_var in $ac_precious_vars; do - eval ac_env_${ac_var}_set=\${${ac_var}+set} - eval ac_env_${ac_var}_value=\$${ac_var} - eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} - eval ac_cv_env_${ac_var}_value=\$${ac_var} -done - -# -# Report the --help message. -# -if test "$ac_init_help" = "long"; then - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF -\`configure' configures libltdl 1.2 to adapt to many kinds of systems. - -Usage: $0 [OPTION]... [VAR=VALUE]... - -To assign environment variables (e.g., CC, CFLAGS...), specify them as -VAR=VALUE. See below for descriptions of some of the useful variables. - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking...' messages - --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for \`--cache-file=config.cache' - -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or \`..'] - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [PREFIX] - -By default, \`make install' will install all the files in -\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify -an installation prefix other than \`$ac_default_prefix' using \`--prefix', -for instance \`--prefix=\$HOME'. - -For better control, use the options below. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root [DATAROOTDIR/doc/libltdl] - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] -_ACEOF - - cat <<\_ACEOF - -Program names: - --program-prefix=PREFIX prepend PREFIX to installed program names - --program-suffix=SUFFIX append SUFFIX to installed program names - --program-transform-name=PROGRAM run sed PROGRAM on installed program names - -System types: - --build=BUILD configure for building on BUILD [guessed] - --host=HOST cross-compile to build programs to run on HOST [BUILD] -_ACEOF -fi - -if test -n "$ac_init_help"; then - case $ac_init_help in - short | recursive ) echo "Configuration of libltdl 1.2:";; - esac - cat <<\_ACEOF - -Optional Features: - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --disable-dependency-tracking speeds up one-time build - --enable-dependency-tracking do not reject slow dependency extractors - --enable-shared[=PKGS] build shared libraries [default=yes] - --enable-static[=PKGS] build static libraries [default=yes] - --enable-fast-install[=PKGS] - optimize for fast installation [default=yes] - --disable-libtool-lock avoid locking (might break parallel builds) - --enable-ltdl-install install libltdl - -Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-gnu-ld assume the C compiler uses GNU ld [default=no] - --with-pic try to use only PIC/non-PIC objects [default=use - both] - --with-tags[=TAGS] include additional configurations [automatic] - -Some influential environment variables: - CC C compiler command - CFLAGS C compiler flags - LDFLAGS linker flags, e.g. -L if you have libraries in a - nonstandard directory - LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if - you have headers in a nonstandard directory - CPP C preprocessor - CXX C++ compiler command - CXXFLAGS C++ compiler flags - CXXCPP C++ preprocessor - F77 Fortran 77 compiler command - FFLAGS Fortran 77 compiler flags - -Use these variables to override the choices made by `configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to . -_ACEOF -ac_status=$? -fi - -if test "$ac_init_help" = "recursive"; then - # If there are subdirs, report their specific --help. - for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || continue - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. - if test -f "$ac_srcdir/configure.gnu"; then - echo && - $SHELL "$ac_srcdir/configure.gnu" --help=recursive - elif test -f "$ac_srcdir/configure"; then - echo && - $SHELL "$ac_srcdir/configure" --help=recursive - else - echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi || ac_status=$? - cd "$ac_pwd" || { ac_status=$?; break; } - done -fi - -test -n "$ac_init_help" && exit $ac_status -if $ac_init_version; then - cat <<\_ACEOF -libltdl configure 1.2 -generated by GNU Autoconf 2.61 - -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. -This configure script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it. -_ACEOF - exit -fi -cat >config.log <<_ACEOF -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by libltdl $as_me 1.2, which was -generated by GNU Autoconf 2.61. Invocation command line was - - $ $0 $@ - -_ACEOF -exec 5>>config.log -{ -cat <<_ASUNAME -## --------- ## -## Platform. ## -## --------- ## - -hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` - -/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` -/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` -/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` - -_ASUNAME - -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - echo "PATH: $as_dir" -done -IFS=$as_save_IFS - -} >&5 - -cat >&5 <<_ACEOF - - -## ----------- ## -## Core tests. ## -## ----------- ## - -_ACEOF - - -# Keep a trace of the command line. -# Strip out --no-create and --no-recursion so they do not pile up. -# Strip out --silent because we don't want to record it for future runs. -# Also quote any args containing shell meta-characters. -# Make two passes to allow for proper duplicate-argument suppression. -ac_configure_args= -ac_configure_args0= -ac_configure_args1= -ac_must_keep_next=false -for ac_pass in 1 2 -do - for ac_arg - do - case $ac_arg in - -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - continue ;; - *\'*) - ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case $ac_pass in - 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; - 2) - ac_configure_args1="$ac_configure_args1 '$ac_arg'" - if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. - else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac - fi - ac_configure_args="$ac_configure_args '$ac_arg'" - ;; - esac - done -done -$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } -$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } - -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. We remove comments because anyway the quotes in there -# would cause problems or look ugly. -# WARNING: Use '\'' to represent an apostrophe within the trap. -# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. -trap 'exit_status=$? - # Save into config.log some information that might help in debugging. - { - echo - - cat <<\_ASBOX -## ---------------- ## -## Cache variables. ## -## ---------------- ## -_ASBOX - echo - # The following way of writing the cache mishandles newlines in values, -( - for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 -echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - *) $as_unset $ac_var ;; - esac ;; - esac - done - (set) 2>&1 | - case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - sed -n \ - "s/'\''/'\''\\\\'\'''\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" - ;; #( - *) - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) - echo - - cat <<\_ASBOX -## ----------------- ## -## Output variables. ## -## ----------------- ## -_ASBOX - echo - for ac_var in $ac_subst_vars - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - echo "$ac_var='\''$ac_val'\''" - done | sort - echo - - if test -n "$ac_subst_files"; then - cat <<\_ASBOX -## ------------------- ## -## File substitutions. ## -## ------------------- ## -_ASBOX - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - echo "$ac_var='\''$ac_val'\''" - done | sort - echo - fi - - if test -s confdefs.h; then - cat <<\_ASBOX -## ----------- ## -## confdefs.h. ## -## ----------- ## -_ASBOX - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - echo "$as_me: caught signal $ac_signal" - echo "$as_me: exit $exit_status" - } >&5 - rm -f core *.core core.conftest.* && - rm -f -r conftest* confdefs* conf$$* $ac_clean_files && - exit $exit_status -' 0 -for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal -done -ac_signal=0 - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -f -r conftest* confdefs.h - -# Predefined preprocessor variables. - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF - - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF - - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF - - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF - - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF - - -# Let the site file select an alternate cache file if it wants to. -# Prefer explicitly selected file to automatically selected ones. -if test -n "$CONFIG_SITE"; then - set x "$CONFIG_SITE" -elif test "x$prefix" != xNONE; then - set x "$prefix/share/config.site" "$prefix/etc/config.site" -else - set x "$ac_default_prefix/share/config.site" \ - "$ac_default_prefix/etc/config.site" -fi -shift -for ac_site_file -do - if test -r "$ac_site_file"; then - { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 -echo "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" - fi -done - -if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special - # files actually), so we avoid doing that. - if test -f "$cache_file"; then - { echo "$as_me:$LINENO: loading cache $cache_file" >&5 -echo "$as_me: loading cache $cache_file" >&6;} - case $cache_file in - [\\/]* | ?:[\\/]* ) . "$cache_file";; - *) . "./$cache_file";; - esac - fi -else - { echo "$as_me:$LINENO: creating cache $cache_file" >&5 -echo "$as_me: creating cache $cache_file" >&6;} - >$cache_file -fi - -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 -echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 -echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 -echo "$as_me: former value: $ac_old_val" >&2;} - { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 -echo "$as_me: current value: $ac_new_val" >&2;} - ac_cache_corrupted=: - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 -echo "$as_me: error: changes in the environment can compromise the build" >&2;} - { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 -echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} - { (exit 1); exit 1; }; } -fi - - - - - - - - - - - - - - - - - - - - - - - - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - - - -## ------------------------------- ## -## Libltdl specific configuration. ## -## ------------------------------- ## - -ac_aux_dir= -for ac_dir in . "$srcdir"/.; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi -done -if test -z "$ac_aux_dir"; then - { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in . \"$srcdir\"/." >&5 -echo "$as_me: error: cannot find install-sh or install.sh in . \"$srcdir\"/." >&2;} - { (exit 1); exit 1; }; } -fi - -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. - - - -if test -z "$enable_ltdl_install$enable_ltdl_convenience"; then - if test -f ${srcdir}/ltmain.sh; then - # if libltdl is libtoolized, it is assumed to be stand-alone and - # installed unless the command line overrides it (tested above) - enable_ltdl_install=yes - else - { echo "$as_me:$LINENO: WARNING: *** The top-level configure must select either" >&5 -echo "$as_me: WARNING: *** The top-level configure must select either" >&2;} - { echo "$as_me:$LINENO: WARNING: *** A\"\"C_LIBLTDL_INSTALLABLE or A\"\"C_LIBLTDL_CONVENIENCE." >&5 -echo "$as_me: WARNING: *** A\"\"C_LIBLTDL_INSTALLABLE or A\"\"C_LIBLTDL_CONVENIENCE." >&2;} - { { echo "$as_me:$LINENO: error: *** Maybe you want to --enable-ltdl-install?" >&5 -echo "$as_me: error: *** Maybe you want to --enable-ltdl-install?" >&2;} - { (exit 1); exit 1; }; } - fi -fi - - -## ------------------------ ## -## Automake Initialisation. ## -## ------------------------ ## -am__api_version='1.10' - -# Find a good install program. We prefer a C program (faster), -# so one script is as good as another. But avoid the broken or -# incompatible versions: -# SysV /etc/install, /usr/sbin/install -# SunOS /usr/etc/install -# IRIX /sbin/install -# AIX /bin/install -# AmigaOS /C/install, which installs bootblocks on floppy discs -# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag -# AFS /usr/afsws/bin/install, which mishandles nonexistent args -# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" -# OS/2's system install, which has a completely different semantic -# ./install, which can be erroneously created by make from ./install.sh. -{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 -echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; } -if test -z "$INSTALL"; then -if test "${ac_cv_path_install+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - # Account for people who put trailing slashes in PATH elements. -case $as_dir/ in - ./ | .// | /cC/* | \ - /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ - ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ - /usr/ucb/* ) ;; - *) - # OSF1 and SCO ODT 3.0 have their own names for install. - # Don't use installbsd from OSF since it installs stuff as root - # by default. - for ac_prog in ginstall scoinst install; do - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then - if test $ac_prog = install && - grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # AIX install. It has an incompatible calling convention. - : - elif test $ac_prog = install && - grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # program-specific install script used by HP pwplus--don't use. - : - else - ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" - break 3 - fi - fi - done - done - ;; -esac -done -IFS=$as_save_IFS - - -fi - if test "${ac_cv_path_install+set}" = set; then - INSTALL=$ac_cv_path_install - else - # As a last resort, use the slow shell script. Don't cache a - # value for INSTALL within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - INSTALL=$ac_install_sh - fi -fi -{ echo "$as_me:$LINENO: result: $INSTALL" >&5 -echo "${ECHO_T}$INSTALL" >&6; } - -# Use test -z because SunOS4 sh mishandles braces in ${var-val}. -# It thinks the first close brace ends the variable substitution. -test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - -test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' - -test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' - -{ echo "$as_me:$LINENO: checking whether build environment is sane" >&5 -echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6; } -# Just in case -sleep 1 -echo timestamp > conftest.file -# Do `set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -if ( - set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` - if test "$*" = "X"; then - # -L didn't work. - set X `ls -t $srcdir/configure conftest.file` - fi - rm -f conftest.file - if test "$*" != "X $srcdir/configure conftest.file" \ - && test "$*" != "X conftest.file $srcdir/configure"; then - - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken -alias in your environment" >&5 -echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken -alias in your environment" >&2;} - { (exit 1); exit 1; }; } - fi - - test "$2" = conftest.file - ) -then - # Ok. - : -else - { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! -Check your system clock" >&5 -echo "$as_me: error: newly created file is older than distributed files! -Check your system clock" >&2;} - { (exit 1); exit 1; }; } -fi -{ echo "$as_me:$LINENO: result: yes" >&5 -echo "${ECHO_T}yes" >&6; } -test "$program_prefix" != NONE && - program_transform_name="s&^&$program_prefix&;$program_transform_name" -# Use a double $ so make ignores it. -test "$program_suffix" != NONE && - program_transform_name="s&\$&$program_suffix&;$program_transform_name" -# Double any \ or $. echo might interpret backslashes. -# By default was `s,x,x', remove it if useless. -cat <<\_ACEOF >conftest.sed -s/[\\$]/&&/g;s/;s,x,x,$// -_ACEOF -program_transform_name=`echo $program_transform_name | sed -f conftest.sed` -rm -f conftest.sed - -# expand $ac_aux_dir to an absolute path -am_aux_dir=`cd $ac_aux_dir && pwd` - -test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" -# Use eval to expand $SHELL -if eval "$MISSING --run true"; then - am_missing_run="$MISSING --run " -else - am_missing_run= - { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 -echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} -fi - -{ echo "$as_me:$LINENO: checking for a thread-safe mkdir -p" >&5 -echo $ECHO_N "checking for a thread-safe mkdir -p... $ECHO_C" >&6; } -if test -z "$MKDIR_P"; then - if test "${ac_cv_path_mkdir+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in mkdir gmkdir; do - for ac_exec_ext in '' $ac_executable_extensions; do - { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue - case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( - 'mkdir (GNU coreutils) '* | \ - 'mkdir (coreutils) '* | \ - 'mkdir (fileutils) '4.1*) - ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext - break 3;; - esac - done - done -done -IFS=$as_save_IFS - -fi - - if test "${ac_cv_path_mkdir+set}" = set; then - MKDIR_P="$ac_cv_path_mkdir -p" - else - # As a last resort, use the slow shell script. Don't cache a - # value for MKDIR_P within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - test -d ./--version && rmdir ./--version - MKDIR_P="$ac_install_sh -d" - fi -fi -{ echo "$as_me:$LINENO: result: $MKDIR_P" >&5 -echo "${ECHO_T}$MKDIR_P" >&6; } - -mkdir_p="$MKDIR_P" -case $mkdir_p in - [\\/$]* | ?:[\\/]*) ;; - */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; -esac - -for ac_prog in gawk mawk nawk awk -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_AWK+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$AWK"; then - ac_cv_prog_AWK="$AWK" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_AWK="$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -AWK=$ac_cv_prog_AWK -if test -n "$AWK"; then - { echo "$as_me:$LINENO: result: $AWK" >&5 -echo "${ECHO_T}$AWK" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - - test -n "$AWK" && break -done - -{ echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 -echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; } -set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` -if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.make <<\_ACEOF -SHELL = /bin/sh -all: - @echo '@@@%%%=$(MAKE)=@@@%%%' -_ACEOF -# GNU make sometimes prints "make[1]: Entering...", which would confuse us. -case `${MAKE-make} -f conftest.make 2>/dev/null` in - *@@@%%%=?*=@@@%%%*) - eval ac_cv_prog_make_${ac_make}_set=yes;; - *) - eval ac_cv_prog_make_${ac_make}_set=no;; -esac -rm -f conftest.make -fi -if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then - { echo "$as_me:$LINENO: result: yes" >&5 -echo "${ECHO_T}yes" >&6; } - SET_MAKE= -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } - SET_MAKE="MAKE=${MAKE-make}" -fi - -rm -rf .tst 2>/dev/null -mkdir .tst 2>/dev/null -if test -d .tst; then - am__leading_dot=. -else - am__leading_dot=_ -fi -rmdir .tst 2>/dev/null - -if test "`cd $srcdir && pwd`" != "`pwd`"; then - # Use -I$(srcdir) only when $(srcdir) != ., so that make's output - # is not polluted with repeated "-I." - am__isrc=' -I$(srcdir)' - # test to see if srcdir already configured - if test -f $srcdir/config.status; then - { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 -echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} - { (exit 1); exit 1; }; } - fi -fi - -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' - else - CYGPATH_W=echo - fi -fi - - -# Define the identity of the package. - PACKAGE=libltdl - VERSION=1.2 - - -# Some tools Automake needs. - -ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} - - -AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} - - -AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} - - -AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} - - -MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} - -install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} - -# Installed binaries are usually stripped using `strip' when the user -# run `make install-strip'. However `strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the `STRIP' environment variable to overrule this program. -if test "$cross_compiling" != no; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_STRIP+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { echo "$as_me:$LINENO: result: $STRIP" >&5 -echo "${ECHO_T}$STRIP" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_STRIP="strip" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 -echo "${ECHO_T}$ac_ct_STRIP" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" - -# We need awk for the "check" target. The system "awk" is bad on -# some platforms. -# Always define AMTAR for backward compatibility. - -AMTAR=${AMTAR-"${am_missing_run}tar"} - -am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' - - - - - -ac_config_headers="$ac_config_headers config.h:config-h.in" - - - -## ------------------ ## -## C compiler checks. ## -## ------------------ ## -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { echo "$as_me:$LINENO: result: $CC" >&5 -echo "${ECHO_T}$CC" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_CC="gcc" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 -echo "${ECHO_T}$ac_ct_CC" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { echo "$as_me:$LINENO: result: $CC" >&5 -echo "${ECHO_T}$CC" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - - fi -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $# != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" - fi -fi -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { echo "$as_me:$LINENO: result: $CC" >&5 -echo "${ECHO_T}$CC" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { echo "$as_me:$LINENO: result: $CC" >&5 -echo "${ECHO_T}$CC" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_CC="$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 -echo "${ECHO_T}$ac_ct_CC" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - - test -n "$ac_ct_CC" && break -done - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -fi - -fi - - -test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH -See \`config.log' for more details." >&5 -echo "$as_me: error: no acceptable C compiler found in \$PATH -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } - -# Provide some information about the compiler. -echo "$as_me:$LINENO: checking for C compiler version" >&5 -ac_compiler=`set X $ac_compile; echo $2` -{ (ac_try="$ac_compiler --version >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compiler --version >&5") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (ac_try="$ac_compiler -v >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compiler -v >&5") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (ac_try="$ac_compiler -V >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compiler -V >&5") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.exe b.out" -# Try to create an executable without -o first, disregard a.out. -# It will help us diagnose broken compilers, and finding out an intuition -# of exeext. -{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 -echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; } -ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` -# -# List of possible output files, starting from the most likely. -# The algorithm is not robust to junk in `.', hence go to wildcards (a.*) -# only as a last resort. b.out is created by i960 compilers. -ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out' -# -# The IRIX 6 linker writes into existing files which may not be -# executable, retaining their permissions. Remove them first so a -# subsequent execution test works. -ac_rmfiles= -for ac_file in $ac_files -do - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; - * ) ac_rmfiles="$ac_rmfiles $ac_file";; - esac -done -rm -f $ac_rmfiles - -if { (ac_try="$ac_link_default" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link_default") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then - # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. -# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' -# in a Makefile. We should not override ac_cv_exeext if it was cached, -# so that the user can short-circuit this test for compilers unknown to -# Autoconf. -for ac_file in $ac_files '' -do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) - ;; - [ab].out ) - # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; - then :; else - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - fi - # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an `-o' - # argument, so we may need to know it at that point already. - # Even if this section looks crufty: it has the advantage of - # actually working. - break;; - * ) - break;; - esac -done -test "$ac_cv_exeext" = no && ac_cv_exeext= - -else - ac_file='' -fi - -{ echo "$as_me:$LINENO: result: $ac_file" >&5 -echo "${ECHO_T}$ac_file" >&6; } -if test -z "$ac_file"; then - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { echo "$as_me:$LINENO: error: C compiler cannot create executables -See \`config.log' for more details." >&5 -echo "$as_me: error: C compiler cannot create executables -See \`config.log' for more details." >&2;} - { (exit 77); exit 77; }; } -fi - -ac_exeext=$ac_cv_exeext - -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5 -echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; } -# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 -# If not cross compiling, check that we can run a simple program. -if test "$cross_compiling" != yes; then - if { ac_try='./$ac_file' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { echo "$as_me:$LINENO: error: cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } - fi - fi -fi -{ echo "$as_me:$LINENO: result: yes" >&5 -echo "${ECHO_T}yes" >&6; } - -rm -f a.out a.exe conftest$ac_cv_exeext b.out -ac_clean_files=$ac_clean_files_save -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 -echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; } -{ echo "$as_me:$LINENO: result: $cross_compiling" >&5 -echo "${ECHO_T}$cross_compiling" >&6; } - -{ echo "$as_me:$LINENO: checking for suffix of executables" >&5 -echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; } -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then - # If both `conftest.exe' and `conftest' are `present' (well, observable) -# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will -# work properly (i.e., refer to `conftest.exe'), while it won't with -# `rm'. -for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - break;; - * ) break;; - esac -done -else - { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -fi - -rm -f conftest$ac_cv_exeext -{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 -echo "${ECHO_T}$ac_cv_exeext" >&6; } - -rm -f conftest.$ac_ext -EXEEXT=$ac_cv_exeext -ac_exeext=$EXEEXT -{ echo "$as_me:$LINENO: checking for suffix of object files" >&5 -echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; } -if test "${ac_cv_objext+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.o conftest.obj -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then - for ac_file in conftest.o conftest.obj conftest.*; do - test -f "$ac_file" || continue; - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;; - *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` - break;; - esac -done -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute suffix of object files: cannot compile -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -fi - -rm -f conftest.$ac_cv_objext conftest.$ac_ext -fi -{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 -echo "${ECHO_T}$ac_cv_objext" >&6; } -OBJEXT=$ac_cv_objext -ac_objext=$OBJEXT -{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 -echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; } -if test "${ac_cv_c_compiler_gnu+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_compiler_gnu=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_compiler_gnu=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - -fi -{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 -echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; } -GCC=`test $ac_compiler_gnu = yes && echo yes` -ac_test_CFLAGS=${CFLAGS+set} -ac_save_CFLAGS=$CFLAGS -{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 -echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; } -if test "${ac_cv_prog_cc_g+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_cv_prog_cc_g=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - CFLAGS="" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_cv_prog_cc_g=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag -fi -{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 -echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 -echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; } -if test "${ac_cv_prog_cc_c89+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_cv_prog_cc_c89=no -ac_save_CC=$CC -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -#include -#include -#include -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; - -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} -_ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_cv_prog_cc_c89=$ac_arg -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext - test "x$ac_cv_prog_cc_c89" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC - -fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { echo "$as_me:$LINENO: result: none needed" >&5 -echo "${ECHO_T}none needed" >&6; } ;; - xno) - { echo "$as_me:$LINENO: result: unsupported" >&5 -echo "${ECHO_T}unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 -echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;; -esac - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -DEPDIR="${am__leading_dot}deps" - -ac_config_commands="$ac_config_commands depfiles" - - -am_make=${MAKE-make} -cat > confinc << 'END' -am__doit: - @echo done -.PHONY: am__doit -END -# If we don't find an include directive, just comment out the code. -{ echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 -echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6; } -am__include="#" -am__quote= -_am_result=none -# First try GNU make style include. -echo "include confinc" > confmf -# We grep out `Entering directory' and `Leaving directory' -# messages which can occur if `w' ends up in MAKEFLAGS. -# In particular we don't look at `^make:' because GNU make might -# be invoked under some other name (usually "gmake"), in which -# case it prints its new name instead of `make'. -if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then - am__include=include - am__quote= - _am_result=GNU -fi -# Now try BSD make style include. -if test "$am__include" = "#"; then - echo '.include "confinc"' > confmf - if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then - am__include=.include - am__quote="\"" - _am_result=BSD - fi -fi - - -{ echo "$as_me:$LINENO: result: $_am_result" >&5 -echo "${ECHO_T}$_am_result" >&6; } -rm -f confinc confmf - -# Check whether --enable-dependency-tracking was given. -if test "${enable_dependency_tracking+set}" = set; then - enableval=$enable_dependency_tracking; -fi - -if test "x$enable_dependency_tracking" != xno; then - am_depcomp="$ac_aux_dir/depcomp" - AMDEPBACKSLASH='\' -fi - if test "x$enable_dependency_tracking" != xno; then - AMDEP_TRUE= - AMDEP_FALSE='#' -else - AMDEP_TRUE='#' - AMDEP_FALSE= -fi - - - -depcc="$CC" am_compiler_list= - -{ echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 -echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; } -if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named `D' -- because `-MD' means `put the output - # in D'. - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_CC_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` - fi - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with - # Solaris 8's {/usr,}/bin/sh. - touch sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - case $depmode in - nosideeffect) - # after this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - none) break ;; - esac - # We check with `-c' and `-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle `-M -o', and we need to detect this. - if depmode=$depmode \ - source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_CC_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_CC_dependencies_compiler_type=none -fi - -fi -{ echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 -echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6; } -CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type - - if - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then - am__fastdepCC_TRUE= - am__fastdepCC_FALSE='#' -else - am__fastdepCC_TRUE='#' - am__fastdepCC_FALSE= -fi - - - -{ echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 -echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6; } -if test "${ac_cv_c_const+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ -/* FIXME: Include the comments suggested by Paul. */ -#ifndef __cplusplus - /* Ultrix mips cc rejects this. */ - typedef int charset[2]; - const charset cs; - /* SunOS 4.1.1 cc rejects this. */ - char const *const *pcpcc; - char **ppc; - /* NEC SVR4.0.2 mips cc rejects this. */ - struct point {int x, y;}; - static struct point const zero = {0,0}; - /* AIX XL C 1.02.0.0 rejects this. - It does not let you subtract one const X* pointer from another in - an arm of an if-expression whose if-part is not a constant - expression */ - const char *g = "string"; - pcpcc = &g + (g ? g-g : 0); - /* HPUX 7.0 cc rejects these. */ - ++pcpcc; - ppc = (char**) pcpcc; - pcpcc = (char const *const *) ppc; - { /* SCO 3.2v4 cc rejects this. */ - char *t; - char const *s = 0 ? (char *) 0 : (char const *) 0; - - *t++ = 0; - if (s) return 0; - } - { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ - int x[] = {25, 17}; - const int *foo = &x[0]; - ++foo; - } - { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ - typedef const int *iptr; - iptr p = 0; - ++p; - } - { /* AIX XL C 1.02.0.0 rejects this saying - "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ - struct s { int j; const int *ap[3]; }; - struct s *b; b->j = 5; - } - { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ - const int foo = 10; - if (!foo) return 0; - } - return !cs[0] && !zero.x; -#endif - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_cv_c_const=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_c_const=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 -echo "${ECHO_T}$ac_cv_c_const" >&6; } -if test $ac_cv_c_const = no; then - -cat >>confdefs.h <<\_ACEOF -#define const -_ACEOF - -fi - -{ echo "$as_me:$LINENO: checking for inline" >&5 -echo $ECHO_N "checking for inline... $ECHO_C" >&6; } -if test "${ac_cv_c_inline+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_cv_c_inline=no -for ac_kw in inline __inline__ __inline; do - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#ifndef __cplusplus -typedef int foo_t; -static $ac_kw foo_t static_foo () {return 0; } -$ac_kw foo_t foo () {return 0; } -#endif - -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_cv_c_inline=$ac_kw -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - test "$ac_cv_c_inline" != no && break -done - -fi -{ echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5 -echo "${ECHO_T}$ac_cv_c_inline" >&6; } - - -case $ac_cv_c_inline in - inline | yes) ;; - *) - case $ac_cv_c_inline in - no) ac_val=;; - *) ac_val=$ac_cv_c_inline;; - esac - cat >>confdefs.h <<_ACEOF -#ifndef __cplusplus -#define inline $ac_val -#endif -_ACEOF - ;; -esac - - - -## ----------------------- ## -## Libtool initialisation. ## -## ----------------------- ## - - -# Check whether --enable-shared was given. -if test "${enable_shared+set}" = set; then - enableval=$enable_shared; p=${PACKAGE-default} - case $enableval in - yes) enable_shared=yes ;; - no) enable_shared=no ;; - *) - enable_shared=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for pkg in $enableval; do - IFS="$lt_save_ifs" - if test "X$pkg" = "X$p"; then - enable_shared=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac -else - enable_shared=yes -fi - - -# Check whether --enable-static was given. -if test "${enable_static+set}" = set; then - enableval=$enable_static; p=${PACKAGE-default} - case $enableval in - yes) enable_static=yes ;; - no) enable_static=no ;; - *) - enable_static=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for pkg in $enableval; do - IFS="$lt_save_ifs" - if test "X$pkg" = "X$p"; then - enable_static=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac -else - enable_static=yes -fi - - -# Check whether --enable-fast-install was given. -if test "${enable_fast_install+set}" = set; then - enableval=$enable_fast_install; p=${PACKAGE-default} - case $enableval in - yes) enable_fast_install=yes ;; - no) enable_fast_install=no ;; - *) - enable_fast_install=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for pkg in $enableval; do - IFS="$lt_save_ifs" - if test "X$pkg" = "X$p"; then - enable_fast_install=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac -else - enable_fast_install=yes -fi - - -# Make sure we can run config.sub. -$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || - { { echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5 -echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;} - { (exit 1); exit 1; }; } - -{ echo "$as_me:$LINENO: checking build system type" >&5 -echo $ECHO_N "checking build system type... $ECHO_C" >&6; } -if test "${ac_cv_build+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_build_alias=$build_alias -test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` -test "x$ac_build_alias" = x && - { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 -echo "$as_me: error: cannot guess build type; you must specify one" >&2;} - { (exit 1); exit 1; }; } -ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || - { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5 -echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;} - { (exit 1); exit 1; }; } - -fi -{ echo "$as_me:$LINENO: result: $ac_cv_build" >&5 -echo "${ECHO_T}$ac_cv_build" >&6; } -case $ac_cv_build in -*-*-*) ;; -*) { { echo "$as_me:$LINENO: error: invalid value of canonical build" >&5 -echo "$as_me: error: invalid value of canonical build" >&2;} - { (exit 1); exit 1; }; };; -esac -build=$ac_cv_build -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_build -shift -build_cpu=$1 -build_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -build_os=$* -IFS=$ac_save_IFS -case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac - - -{ echo "$as_me:$LINENO: checking host system type" >&5 -echo $ECHO_N "checking host system type... $ECHO_C" >&6; } -if test "${ac_cv_host+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test "x$host_alias" = x; then - ac_cv_host=$ac_cv_build -else - ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5 -echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;} - { (exit 1); exit 1; }; } -fi - -fi -{ echo "$as_me:$LINENO: result: $ac_cv_host" >&5 -echo "${ECHO_T}$ac_cv_host" >&6; } -case $ac_cv_host in -*-*-*) ;; -*) { { echo "$as_me:$LINENO: error: invalid value of canonical host" >&5 -echo "$as_me: error: invalid value of canonical host" >&2;} - { (exit 1); exit 1; }; };; -esac -host=$ac_cv_host -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_host -shift -host_cpu=$1 -host_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -host_os=$* -IFS=$ac_save_IFS -case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac - - -{ echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5 -echo $ECHO_N "checking for a sed that does not truncate output... $ECHO_C" >&6; } -if test "${lt_cv_path_SED+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - # Loop through the user's path and test for sed and gsed. -# Then use that list of sed's as ones to test for truncation. -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for lt_ac_prog in sed gsed; do - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$lt_ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$lt_ac_prog$ac_exec_ext"; }; then - lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" - fi - done - done -done -IFS=$as_save_IFS -lt_ac_max=0 -lt_ac_count=0 -# Add /usr/xpg4/bin/sed as it is typically found on Solaris -# along with /bin/sed that truncates output. -for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do - test ! -f $lt_ac_sed && continue - cat /dev/null > conftest.in - lt_ac_count=0 - echo $ECHO_N "0123456789$ECHO_C" >conftest.in - # Check for GNU sed and select it if it is found. - if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then - lt_cv_path_SED=$lt_ac_sed - break - fi - while true; do - cat conftest.in conftest.in >conftest.tmp - mv conftest.tmp conftest.in - cp conftest.in conftest.nl - echo >>conftest.nl - $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break - cmp -s conftest.out conftest.nl || break - # 10000 chars as input seems more than enough - test $lt_ac_count -gt 10 && break - lt_ac_count=`expr $lt_ac_count + 1` - if test $lt_ac_count -gt $lt_ac_max; then - lt_ac_max=$lt_ac_count - lt_cv_path_SED=$lt_ac_sed - fi - done -done - -fi - -SED=$lt_cv_path_SED - -{ echo "$as_me:$LINENO: result: $SED" >&5 -echo "${ECHO_T}$SED" >&6; } - -{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 -echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; } -if test "${ac_cv_path_GREP+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - # Extract the first word of "grep ggrep" to use in msg output -if test -z "$GREP"; then -set dummy grep ggrep; ac_prog_name=$2 -if test "${ac_cv_path_GREP+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_path_GREP_found=false -# Loop through the user's path and test for each of PROGNAME-LIST -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue - # Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - echo 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - ac_count=`expr $ac_count + 1` - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - - $ac_path_GREP_found && break 3 - done -done - -done -IFS=$as_save_IFS - - -fi - -GREP="$ac_cv_path_GREP" -if test -z "$GREP"; then - { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 -echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} - { (exit 1); exit 1; }; } -fi - -else - ac_cv_path_GREP=$GREP -fi - - -fi -{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 -echo "${ECHO_T}$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ echo "$as_me:$LINENO: checking for egrep" >&5 -echo $ECHO_N "checking for egrep... $ECHO_C" >&6; } -if test "${ac_cv_path_EGREP+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - # Extract the first word of "egrep" to use in msg output -if test -z "$EGREP"; then -set dummy egrep; ac_prog_name=$2 -if test "${ac_cv_path_EGREP+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_path_EGREP_found=false -# Loop through the user's path and test for each of PROGNAME-LIST -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue - # Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -*) - ac_count=0 - echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - echo 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - ac_count=`expr $ac_count + 1` - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - - $ac_path_EGREP_found && break 3 - done -done - -done -IFS=$as_save_IFS - - -fi - -EGREP="$ac_cv_path_EGREP" -if test -z "$EGREP"; then - { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 -echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} - { (exit 1); exit 1; }; } -fi - -else - ac_cv_path_EGREP=$EGREP -fi - - - fi -fi -{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 -echo "${ECHO_T}$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - - -# Check whether --with-gnu-ld was given. -if test "${with_gnu_ld+set}" = set; then - withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes -else - with_gnu_ld=no -fi - -ac_prog=ld -if test "$GCC" = yes; then - # Check if gcc -print-prog-name=ld gives a path. - { echo "$as_me:$LINENO: checking for ld used by $CC" >&5 -echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6; } - case $host in - *-*-mingw*) - # gcc leaves a trailing carriage return which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [\\/]* | ?:[\\/]*) - re_direlt='/[^/][^/]*/\.\./' - # Canonicalize the pathname of ld - ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` - while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do - ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` - done - test -z "$LD" && LD="$ac_prog" - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test "$with_gnu_ld" = yes; then - { echo "$as_me:$LINENO: checking for GNU ld" >&5 -echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6; } -else - { echo "$as_me:$LINENO: checking for non-GNU ld" >&5 -echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6; } -fi -if test "${lt_cv_path_LD+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -z "$LD"; then - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - lt_cv_path_LD="$ac_dir/$ac_prog" - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some variants of GNU ld only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$lt_cv_path_LD" -v 2>&1 &5 -echo "${ECHO_T}$LD" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi -test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 -echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} - { (exit 1); exit 1; }; } -{ echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 -echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6; } -if test "${lt_cv_prog_gnu_ld+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - # I'd rather use --version here, but apparently some GNU lds only accept -v. -case `$LD -v 2>&1 &5 -echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6; } -with_gnu_ld=$lt_cv_prog_gnu_ld - - -{ echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5 -echo $ECHO_N "checking for $LD option to reload object files... $ECHO_C" >&6; } -if test "${lt_cv_ld_reload_flag+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - lt_cv_ld_reload_flag='-r' -fi -{ echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5 -echo "${ECHO_T}$lt_cv_ld_reload_flag" >&6; } -reload_flag=$lt_cv_ld_reload_flag -case $reload_flag in -"" | " "*) ;; -*) reload_flag=" $reload_flag" ;; -esac -reload_cmds='$LD$reload_flag -o $output$reload_objs' -case $host_os in - darwin*) - if test "$GCC" = yes; then - reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' - else - reload_cmds='$LD$reload_flag -o $output$reload_objs' - fi - ;; -esac - -{ echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5 -echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6; } -if test "${lt_cv_path_NM+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$NM"; then - # Let the user override the test. - lt_cv_path_NM="$NM" -else - lt_nm_to_check="${ac_tool_prefix}nm" - if test -n "$ac_tool_prefix" && test "$build" = "$host"; then - lt_nm_to_check="$lt_nm_to_check nm" - fi - for lt_tmp_nm in $lt_nm_to_check; do - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - tmp_nm="$ac_dir/$lt_tmp_nm" - if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then - # Check to see if the nm accepts a BSD-compat flag. - # Adding the `sed 1q' prevents false positives on HP-UX, which says: - # nm: unknown option "B" ignored - # Tru64's nm complains that /dev/null is an invalid object file - case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in - */dev/null* | *'Invalid file or object type'*) - lt_cv_path_NM="$tmp_nm -B" - break - ;; - *) - case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in - */dev/null*) - lt_cv_path_NM="$tmp_nm -p" - break - ;; - *) - lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but - continue # so that we can try to find one that supports BSD flags - ;; - esac - ;; - esac - fi - done - IFS="$lt_save_ifs" - done - test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm -fi -fi -{ echo "$as_me:$LINENO: result: $lt_cv_path_NM" >&5 -echo "${ECHO_T}$lt_cv_path_NM" >&6; } -NM="$lt_cv_path_NM" - -{ echo "$as_me:$LINENO: checking whether ln -s works" >&5 -echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6; } -LN_S=$as_ln_s -if test "$LN_S" = "ln -s"; then - { echo "$as_me:$LINENO: result: yes" >&5 -echo "${ECHO_T}yes" >&6; } -else - { echo "$as_me:$LINENO: result: no, using $LN_S" >&5 -echo "${ECHO_T}no, using $LN_S" >&6; } -fi - -{ echo "$as_me:$LINENO: checking how to recognize dependent libraries" >&5 -echo $ECHO_N "checking how to recognize dependent libraries... $ECHO_C" >&6; } -if test "${lt_cv_deplibs_check_method+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - lt_cv_file_magic_cmd='$MAGIC_CMD' -lt_cv_file_magic_test_file= -lt_cv_deplibs_check_method='unknown' -# Need to set the preceding variable on all platforms that support -# interlibrary dependencies. -# 'none' -- dependencies not supported. -# `unknown' -- same as none, but documents that we really don't know. -# 'pass_all' -- all dependencies passed with no checks. -# 'test_compile' -- check by making test program. -# 'file_magic [[regex]]' -- check by looking for files in library path -# which responds to the $file_magic_cmd with a given extended regex. -# If you have `file' or equivalent on your system and you're not sure -# whether `pass_all' will *always* work, you probably want this one. - -case $host_os in -aix4* | aix5*) - lt_cv_deplibs_check_method=pass_all - ;; - -beos*) - lt_cv_deplibs_check_method=pass_all - ;; - -bsdi[45]*) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' - lt_cv_file_magic_cmd='/usr/bin/file -L' - lt_cv_file_magic_test_file=/shlib/libc.so - ;; - -cygwin*) - # func_win32_libid is a shell function defined in ltmain.sh - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - ;; - -mingw* | pw32*) - # Base MSYS/MinGW do not provide the 'file' command needed by - # func_win32_libid shell function, so use a weaker test based on 'objdump', - # unless we find 'file', for example because we are cross-compiling. - if ( file / ) >/dev/null 2>&1; then - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - else - lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' - lt_cv_file_magic_cmd='$OBJDUMP -f' - fi - ;; - -darwin* | rhapsody*) - lt_cv_deplibs_check_method=pass_all - ;; - -freebsd* | dragonfly*) - if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then - case $host_cpu in - i*86 ) - # Not sure whether the presence of OpenBSD here was a mistake. - # Let's accept both of them until this is cleared up. - lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' - lt_cv_file_magic_cmd=/usr/bin/file - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` - ;; - esac - else - lt_cv_deplibs_check_method=pass_all - fi - ;; - -gnu*) - lt_cv_deplibs_check_method=pass_all - ;; - -hpux10.20* | hpux11*) - lt_cv_file_magic_cmd=/usr/bin/file - case $host_cpu in - ia64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' - lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so - ;; - hppa*64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]' - lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl - ;; - *) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' - lt_cv_file_magic_test_file=/usr/lib/libc.sl - ;; - esac - ;; - -interix[3-9]*) - # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' - ;; - -irix5* | irix6* | nonstopux*) - case $LD in - *-32|*"-32 ") libmagic=32-bit;; - *-n32|*"-n32 ") libmagic=N32;; - *-64|*"-64 ") libmagic=64-bit;; - *) libmagic=never-match;; - esac - lt_cv_deplibs_check_method=pass_all - ;; - -# This must be Linux ELF. -linux* | k*bsd*-gnu) - lt_cv_deplibs_check_method=pass_all - ;; - -netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' - fi - ;; - -newos6*) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' - lt_cv_file_magic_cmd=/usr/bin/file - lt_cv_file_magic_test_file=/usr/lib/libnls.so - ;; - -nto-qnx*) - lt_cv_deplibs_check_method=unknown - ;; - -openbsd*) - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' - fi - ;; - -osf3* | osf4* | osf5*) - lt_cv_deplibs_check_method=pass_all - ;; - -rdos*) - lt_cv_deplibs_check_method=pass_all - ;; - -solaris*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv4 | sysv4.3*) - case $host_vendor in - motorola) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` - ;; - ncr) - lt_cv_deplibs_check_method=pass_all - ;; - sequent) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' - ;; - sni) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" - lt_cv_file_magic_test_file=/lib/libc.so - ;; - siemens) - lt_cv_deplibs_check_method=pass_all - ;; - pc) - lt_cv_deplibs_check_method=pass_all - ;; - esac - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - lt_cv_deplibs_check_method=pass_all - ;; -esac - -fi -{ echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5 -echo "${ECHO_T}$lt_cv_deplibs_check_method" >&6; } -file_magic_cmd=$lt_cv_file_magic_cmd -deplibs_check_method=$lt_cv_deplibs_check_method -test -z "$deplibs_check_method" && deplibs_check_method=unknown - - - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - -# Check whether --enable-libtool-lock was given. -if test "${enable_libtool_lock+set}" = set; then - enableval=$enable_libtool_lock; -fi - -test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes - -# Some flags need to be propagated to the compiler or linker for good -# libtool support. -case $host in -ia64-*-hpux*) - # Find out which ABI we are using. - echo 'int i;' > conftest.$ac_ext - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then - case `/usr/bin/file conftest.$ac_objext` in - *ELF-32*) - HPUX_IA64_MODE="32" - ;; - *ELF-64*) - HPUX_IA64_MODE="64" - ;; - esac - fi - rm -rf conftest* - ;; -*-*-irix6*) - # Find out which ABI we are using. - echo '#line 4531 "configure"' > conftest.$ac_ext - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then - if test "$lt_cv_prog_gnu_ld" = yes; then - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -melf32bsmip" - ;; - *N32*) - LD="${LD-ld} -melf32bmipn32" - ;; - *64-bit*) - LD="${LD-ld} -melf64bmip" - ;; - esac - else - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -32" - ;; - *N32*) - LD="${LD-ld} -n32" - ;; - *64-bit*) - LD="${LD-ld} -64" - ;; - esac - fi - fi - rm -rf conftest* - ;; - -x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ -s390*-*linux*|sparc*-*linux*) - # Find out which ABI we are using. - echo 'int i;' > conftest.$ac_ext - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then - case `/usr/bin/file conftest.o` in - *32-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_i386_fbsd" - ;; - x86_64-*linux*) - LD="${LD-ld} -m elf_i386" - ;; - ppc64-*linux*|powerpc64-*linux*) - LD="${LD-ld} -m elf32ppclinux" - ;; - s390x-*linux*) - LD="${LD-ld} -m elf_s390" - ;; - sparc64-*linux*) - LD="${LD-ld} -m elf32_sparc" - ;; - esac - ;; - *64-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_x86_64_fbsd" - ;; - x86_64-*linux*) - LD="${LD-ld} -m elf_x86_64" - ;; - ppc*-*linux*|powerpc*-*linux*) - LD="${LD-ld} -m elf64ppc" - ;; - s390*-*linux*) - LD="${LD-ld} -m elf64_s390" - ;; - sparc*-*linux*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; - -*-*-sco3.2v5*) - # On SCO OpenServer 5, we need -belf to get full-featured binaries. - SAVE_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -belf" - { echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5 -echo $ECHO_N "checking whether the C compiler needs -belf... $ECHO_C" >&6; } -if test "${lt_cv_cc_needs_belf+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - lt_cv_cc_needs_belf=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - lt_cv_cc_needs_belf=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -fi -{ echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5 -echo "${ECHO_T}$lt_cv_cc_needs_belf" >&6; } - if test x"$lt_cv_cc_needs_belf" != x"yes"; then - # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf - CFLAGS="$SAVE_CFLAGS" - fi - ;; -sparc*-*solaris*) - # Find out which ABI we are using. - echo 'int i;' > conftest.$ac_ext - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then - case `/usr/bin/file conftest.o` in - *64-bit*) - case $lt_cv_prog_gnu_ld in - yes*) LD="${LD-ld} -m elf64_sparc" ;; - *) LD="${LD-ld} -64" ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; - -*-*-cygwin* | *-*-mingw* | *-*-pw32*) - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. -set dummy ${ac_tool_prefix}dlltool; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_DLLTOOL+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$DLLTOOL"; then - ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -DLLTOOL=$ac_cv_prog_DLLTOOL -if test -n "$DLLTOOL"; then - { echo "$as_me:$LINENO: result: $DLLTOOL" >&5 -echo "${ECHO_T}$DLLTOOL" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_DLLTOOL"; then - ac_ct_DLLTOOL=$DLLTOOL - # Extract the first word of "dlltool", so it can be a program name with args. -set dummy dlltool; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_ac_ct_DLLTOOL+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_DLLTOOL"; then - ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_DLLTOOL="dlltool" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL -if test -n "$ac_ct_DLLTOOL"; then - { echo "$as_me:$LINENO: result: $ac_ct_DLLTOOL" >&5 -echo "${ECHO_T}$ac_ct_DLLTOOL" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - if test "x$ac_ct_DLLTOOL" = x; then - DLLTOOL="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} -ac_tool_warned=yes ;; -esac - DLLTOOL=$ac_ct_DLLTOOL - fi -else - DLLTOOL="$ac_cv_prog_DLLTOOL" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. -set dummy ${ac_tool_prefix}as; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_AS+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$AS"; then - ac_cv_prog_AS="$AS" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_AS="${ac_tool_prefix}as" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -AS=$ac_cv_prog_AS -if test -n "$AS"; then - { echo "$as_me:$LINENO: result: $AS" >&5 -echo "${ECHO_T}$AS" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_AS"; then - ac_ct_AS=$AS - # Extract the first word of "as", so it can be a program name with args. -set dummy as; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_ac_ct_AS+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_AS"; then - ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_AS="as" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -ac_ct_AS=$ac_cv_prog_ac_ct_AS -if test -n "$ac_ct_AS"; then - { echo "$as_me:$LINENO: result: $ac_ct_AS" >&5 -echo "${ECHO_T}$ac_ct_AS" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - if test "x$ac_ct_AS" = x; then - AS="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} -ac_tool_warned=yes ;; -esac - AS=$ac_ct_AS - fi -else - AS="$ac_cv_prog_AS" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. -set dummy ${ac_tool_prefix}objdump; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_OBJDUMP+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$OBJDUMP"; then - ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -OBJDUMP=$ac_cv_prog_OBJDUMP -if test -n "$OBJDUMP"; then - { echo "$as_me:$LINENO: result: $OBJDUMP" >&5 -echo "${ECHO_T}$OBJDUMP" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OBJDUMP"; then - ac_ct_OBJDUMP=$OBJDUMP - # Extract the first word of "objdump", so it can be a program name with args. -set dummy objdump; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_OBJDUMP"; then - ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_OBJDUMP="objdump" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP -if test -n "$ac_ct_OBJDUMP"; then - { echo "$as_me:$LINENO: result: $ac_ct_OBJDUMP" >&5 -echo "${ECHO_T}$ac_ct_OBJDUMP" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - if test "x$ac_ct_OBJDUMP" = x; then - OBJDUMP="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} -ac_tool_warned=yes ;; -esac - OBJDUMP=$ac_ct_OBJDUMP - fi -else - OBJDUMP="$ac_cv_prog_OBJDUMP" -fi - - ;; - -esac - -need_locks="$enable_libtool_lock" - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 -echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; } -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= -fi -if test -z "$CPP"; then - if test "${ac_cv_prog_CPP+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - # Double quotes because CPP needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" - do - ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - : -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - # Broken: fails on valid input. -continue -fi - -rm -f conftest.err conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - # Broken: success on invalid input. -continue -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - # Passes both tests. -ac_preproc_ok=: -break -fi - -rm -f conftest.err conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext -if $ac_preproc_ok; then - break -fi - - done - ac_cv_prog_CPP=$CPP - -fi - CPP=$ac_cv_prog_CPP -else - ac_cv_prog_CPP=$CPP -fi -{ echo "$as_me:$LINENO: result: $CPP" >&5 -echo "${ECHO_T}$CPP" >&6; } -ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - : -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - # Broken: fails on valid input. -continue -fi - -rm -f conftest.err conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - # Broken: success on invalid input. -continue -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - # Passes both tests. -ac_preproc_ok=: -break -fi - -rm -f conftest.err conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext -if $ac_preproc_ok; then - : -else - { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details." >&5 -echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5 -echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } -if test "${ac_cv_header_stdc+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -#include -#include -#include - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_cv_header_stdc=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_header_stdc=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then - : -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then - : -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then - : -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif - -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; - return 0; -} -_ACEOF -rm -f conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - : -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -( exit $ac_status ) -ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi - - -fi -fi -{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 -echo "${ECHO_T}$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then - -cat >>confdefs.h <<\_ACEOF -#define STDC_HEADERS 1 -_ACEOF - -fi - -# On IRIX 5.3, sys/types and inttypes.h are conflicting. - - - - - - - - - -for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ - inttypes.h stdint.h unistd.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -{ echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default - -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - eval "$as_ac_Header=yes" -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - eval "$as_ac_Header=no" -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -if test `eval echo '${'$as_ac_Header'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - - -for ac_header in dlfcn.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - { echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -else - # Is the header compilable? -{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 -echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_header_compiler=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_compiler=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -echo "${ECHO_T}$ac_header_compiler" >&6; } - -# Is the header present? -{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 -echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <$ac_header> -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - ac_header_preproc=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_preproc=no -fi - -rm -f conftest.err conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -echo "${ECHO_T}$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in - yes:no: ) - { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 -echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} - ac_header_preproc=yes - ;; - no:yes:* ) - { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 -echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 -echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 -echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 -echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 -echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - ( cat <<\_ASBOX -## ---------------------------------- ## -## Report this to bug-libtool@gnu.org ## -## ---------------------------------- ## -_ASBOX - ) | sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac -{ echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - eval "$as_ac_Header=\$ac_header_preproc" -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } - -fi -if test `eval echo '${'$as_ac_Header'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -if test -z "$CXX"; then - if test -n "$CCC"; then - CXX=$CCC - else - if test -n "$ac_tool_prefix"; then - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_CXX+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$CXX"; then - ac_cv_prog_CXX="$CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -CXX=$ac_cv_prog_CXX -if test -n "$CXX"; then - { echo "$as_me:$LINENO: result: $CXX" >&5 -echo "${ECHO_T}$CXX" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - - test -n "$CXX" && break - done -fi -if test -z "$CXX"; then - ac_ct_CXX=$CXX - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_CXX"; then - ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_CXX="$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -ac_ct_CXX=$ac_cv_prog_ac_ct_CXX -if test -n "$ac_ct_CXX"; then - { echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 -echo "${ECHO_T}$ac_ct_CXX" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - - test -n "$ac_ct_CXX" && break -done - - if test "x$ac_ct_CXX" = x; then - CXX="g++" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} -ac_tool_warned=yes ;; -esac - CXX=$ac_ct_CXX - fi -fi - - fi -fi -# Provide some information about the compiler. -echo "$as_me:$LINENO: checking for C++ compiler version" >&5 -ac_compiler=`set X $ac_compile; echo $2` -{ (ac_try="$ac_compiler --version >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compiler --version >&5") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (ac_try="$ac_compiler -v >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compiler -v >&5") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (ac_try="$ac_compiler -V >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compiler -V >&5") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - -{ echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 -echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6; } -if test "${ac_cv_cxx_compiler_gnu+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_cxx_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_compiler_gnu=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_compiler_gnu=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_cxx_compiler_gnu=$ac_compiler_gnu - -fi -{ echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 -echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6; } -GXX=`test $ac_compiler_gnu = yes && echo yes` -ac_test_CXXFLAGS=${CXXFLAGS+set} -ac_save_CXXFLAGS=$CXXFLAGS -{ echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 -echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6; } -if test "${ac_cv_prog_cxx_g+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_save_cxx_werror_flag=$ac_cxx_werror_flag - ac_cxx_werror_flag=yes - ac_cv_prog_cxx_g=no - CXXFLAGS="-g" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_cxx_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_cv_prog_cxx_g=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - CXXFLAGS="" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_cxx_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cxx_werror_flag=$ac_save_cxx_werror_flag - CXXFLAGS="-g" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_cxx_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_cv_prog_cxx_g=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_cxx_werror_flag=$ac_save_cxx_werror_flag -fi -{ echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 -echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6; } -if test "$ac_test_CXXFLAGS" = set; then - CXXFLAGS=$ac_save_CXXFLAGS -elif test $ac_cv_prog_cxx_g = yes; then - if test "$GXX" = yes; then - CXXFLAGS="-g -O2" - else - CXXFLAGS="-g" - fi -else - if test "$GXX" = yes; then - CXXFLAGS="-O2" - else - CXXFLAGS= - fi -fi -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - -depcc="$CXX" am_compiler_list= - -{ echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 -echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; } -if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named `D' -- because `-MD' means `put the output - # in D'. - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_CXX_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` - fi - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with - # Solaris 8's {/usr,}/bin/sh. - touch sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - case $depmode in - nosideeffect) - # after this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - none) break ;; - esac - # We check with `-c' and `-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle `-M -o', and we need to detect this. - if depmode=$depmode \ - source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_CXX_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_CXX_dependencies_compiler_type=none -fi - -fi -{ echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5 -echo "${ECHO_T}$am_cv_CXX_dependencies_compiler_type" >&6; } -CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type - - if - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then - am__fastdepCXX_TRUE= - am__fastdepCXX_FALSE='#' -else - am__fastdepCXX_TRUE='#' - am__fastdepCXX_FALSE= -fi - - - - -if test -n "$CXX" && ( test "X$CXX" != "Xno" && - ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || - (test "X$CXX" != "Xg++"))) ; then - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -{ echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5 -echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6; } -if test -z "$CXXCPP"; then - if test "${ac_cv_prog_CXXCPP+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - # Double quotes because CXXCPP needs to be expanded - for CXXCPP in "$CXX -E" "/lib/cpp" - do - ac_preproc_ok=false -for ac_cxx_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || - test ! -s conftest.err - }; then - : -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - # Broken: fails on valid input. -continue -fi - -rm -f conftest.err conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || - test ! -s conftest.err - }; then - # Broken: success on invalid input. -continue -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - # Passes both tests. -ac_preproc_ok=: -break -fi - -rm -f conftest.err conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext -if $ac_preproc_ok; then - break -fi - - done - ac_cv_prog_CXXCPP=$CXXCPP - -fi - CXXCPP=$ac_cv_prog_CXXCPP -else - ac_cv_prog_CXXCPP=$CXXCPP -fi -{ echo "$as_me:$LINENO: result: $CXXCPP" >&5 -echo "${ECHO_T}$CXXCPP" >&6; } -ac_preproc_ok=false -for ac_cxx_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || - test ! -s conftest.err - }; then - : -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - # Broken: fails on valid input. -continue -fi - -rm -f conftest.err conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || - test ! -s conftest.err - }; then - # Broken: success on invalid input. -continue -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - # Passes both tests. -ac_preproc_ok=: -break -fi - -rm -f conftest.err conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext -if $ac_preproc_ok; then - : -else - { { echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check -See \`config.log' for more details." >&5 -echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } -fi - -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - -fi - - -ac_ext=f -ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' -ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_f77_compiler_gnu -if test -n "$ac_tool_prefix"; then - for ac_prog in g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77 xlf90 f90 pgf90 pghpf epcf90 gfortran g95 xlf95 f95 fort ifort ifc efc pgf95 lf95 ftn - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_F77+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$F77"; then - ac_cv_prog_F77="$F77" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_F77="$ac_tool_prefix$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -F77=$ac_cv_prog_F77 -if test -n "$F77"; then - { echo "$as_me:$LINENO: result: $F77" >&5 -echo "${ECHO_T}$F77" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - - test -n "$F77" && break - done -fi -if test -z "$F77"; then - ac_ct_F77=$F77 - for ac_prog in g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77 xlf90 f90 pgf90 pghpf epcf90 gfortran g95 xlf95 f95 fort ifort ifc efc pgf95 lf95 ftn -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_ac_ct_F77+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_F77"; then - ac_cv_prog_ac_ct_F77="$ac_ct_F77" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_F77="$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -ac_ct_F77=$ac_cv_prog_ac_ct_F77 -if test -n "$ac_ct_F77"; then - { echo "$as_me:$LINENO: result: $ac_ct_F77" >&5 -echo "${ECHO_T}$ac_ct_F77" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - - test -n "$ac_ct_F77" && break -done - - if test "x$ac_ct_F77" = x; then - F77="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} -ac_tool_warned=yes ;; -esac - F77=$ac_ct_F77 - fi -fi - - -# Provide some information about the compiler. -echo "$as_me:$LINENO: checking for Fortran 77 compiler version" >&5 -ac_compiler=`set X $ac_compile; echo $2` -{ (ac_try="$ac_compiler --version >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compiler --version >&5") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (ac_try="$ac_compiler -v >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compiler -v >&5") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (ac_try="$ac_compiler -V >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compiler -V >&5") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -rm -f a.out - -# If we don't use `.F' as extension, the preprocessor is not run on the -# input file. (Note that this only needs to work for GNU compilers.) -ac_save_ext=$ac_ext -ac_ext=F -{ echo "$as_me:$LINENO: checking whether we are using the GNU Fortran 77 compiler" >&5 -echo $ECHO_N "checking whether we are using the GNU Fortran 77 compiler... $ECHO_C" >&6; } -if test "${ac_cv_f77_compiler_gnu+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF - program main -#ifndef __GNUC__ - choke me -#endif - - end -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_f77_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_compiler_gnu=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_compiler_gnu=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_f77_compiler_gnu=$ac_compiler_gnu - -fi -{ echo "$as_me:$LINENO: result: $ac_cv_f77_compiler_gnu" >&5 -echo "${ECHO_T}$ac_cv_f77_compiler_gnu" >&6; } -ac_ext=$ac_save_ext -ac_test_FFLAGS=${FFLAGS+set} -ac_save_FFLAGS=$FFLAGS -FFLAGS= -{ echo "$as_me:$LINENO: checking whether $F77 accepts -g" >&5 -echo $ECHO_N "checking whether $F77 accepts -g... $ECHO_C" >&6; } -if test "${ac_cv_prog_f77_g+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - FFLAGS=-g -cat >conftest.$ac_ext <<_ACEOF - program main - - end -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_f77_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_cv_prog_f77_g=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_prog_f77_g=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -fi -{ echo "$as_me:$LINENO: result: $ac_cv_prog_f77_g" >&5 -echo "${ECHO_T}$ac_cv_prog_f77_g" >&6; } -if test "$ac_test_FFLAGS" = set; then - FFLAGS=$ac_save_FFLAGS -elif test $ac_cv_prog_f77_g = yes; then - if test "x$ac_cv_f77_compiler_gnu" = xyes; then - FFLAGS="-g -O2" - else - FFLAGS="-g" - fi -else - if test "x$ac_cv_f77_compiler_gnu" = xyes; then - FFLAGS="-O2" - else - FFLAGS= - fi -fi - -G77=`test $ac_compiler_gnu = yes && echo yes` -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! - -# find the maximum length of command line arguments -{ echo "$as_me:$LINENO: checking the maximum length of command line arguments" >&5 -echo $ECHO_N "checking the maximum length of command line arguments... $ECHO_C" >&6; } -if test "${lt_cv_sys_max_cmd_len+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - i=0 - teststring="ABCD" - - case $build_os in - msdosdjgpp*) - # On DJGPP, this test can blow up pretty badly due to problems in libc - # (any single argument exceeding 2000 bytes causes a buffer overrun - # during glob expansion). Even if it were fixed, the result of this - # check would be larger than it should be. - lt_cv_sys_max_cmd_len=12288; # 12K is about right - ;; - - gnu*) - # Under GNU Hurd, this test is not required because there is - # no limit to the length of command line arguments. - # Libtool will interpret -1 as no limit whatsoever - lt_cv_sys_max_cmd_len=-1; - ;; - - cygwin* | mingw*) - # On Win9x/ME, this test blows up -- it succeeds, but takes - # about 5 minutes as the teststring grows exponentially. - # Worse, since 9x/ME are not pre-emptively multitasking, - # you end up with a "frozen" computer, even though with patience - # the test eventually succeeds (with a max line length of 256k). - # Instead, let's just punt: use the minimum linelength reported by - # all of the supported platforms: 8192 (on NT/2K/XP). - lt_cv_sys_max_cmd_len=8192; - ;; - - amigaos*) - # On AmigaOS with pdksh, this test takes hours, literally. - # So we just punt and use a minimum line length of 8192. - lt_cv_sys_max_cmd_len=8192; - ;; - - netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) - # This has been around since 386BSD, at least. Likely further. - if test -x /sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` - elif test -x /usr/sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` - else - lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs - fi - # And add a safety zone - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - ;; - - interix*) - # We know the value 262144 and hardcode it with a safety zone (like BSD) - lt_cv_sys_max_cmd_len=196608 - ;; - - osf*) - # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure - # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not - # nice to cause kernel panics so lets avoid the loop below. - # First set a reasonable default. - lt_cv_sys_max_cmd_len=16384 - # - if test -x /sbin/sysconfig; then - case `/sbin/sysconfig -q proc exec_disable_arg_limit` in - *1*) lt_cv_sys_max_cmd_len=-1 ;; - esac - fi - ;; - sco3.2v5*) - lt_cv_sys_max_cmd_len=102400 - ;; - sysv5* | sco5v6* | sysv4.2uw2*) - kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` - if test -n "$kargmax"; then - lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` - else - lt_cv_sys_max_cmd_len=32768 - fi - ;; - *) - lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` - if test -n "$lt_cv_sys_max_cmd_len"; then - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - else - SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} - while (test "X"`$SHELL $0 --fallback-echo "X$teststring" 2>/dev/null` \ - = "XX$teststring") >/dev/null 2>&1 && - new_result=`expr "X$teststring" : ".*" 2>&1` && - lt_cv_sys_max_cmd_len=$new_result && - test $i != 17 # 1/2 MB should be enough - do - i=`expr $i + 1` - teststring=$teststring$teststring - done - teststring= - # Add a significant safety factor because C++ compilers can tack on massive - # amounts of additional arguments before passing them to the linker. - # It appears as though 1/2 is a usable value. - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` - fi - ;; - esac - -fi - -if test -n $lt_cv_sys_max_cmd_len ; then - { echo "$as_me:$LINENO: result: $lt_cv_sys_max_cmd_len" >&5 -echo "${ECHO_T}$lt_cv_sys_max_cmd_len" >&6; } -else - { echo "$as_me:$LINENO: result: none" >&5 -echo "${ECHO_T}none" >&6; } -fi - - - - - -# Check for command to grab the raw symbol name followed by C symbol from nm. -{ echo "$as_me:$LINENO: checking command to parse $NM output from $compiler object" >&5 -echo $ECHO_N "checking command to parse $NM output from $compiler object... $ECHO_C" >&6; } -if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - -# These are sane defaults that work on at least a few old systems. -# [They come from Ultrix. What could be older than Ultrix?!! ;)] - -# Character class describing NM global symbol codes. -symcode='[BCDEGRST]' - -# Regexp to match symbols that can be accessed directly from C. -sympat='\([_A-Za-z][_A-Za-z0-9]*\)' - -# Transform an extracted symbol line into a proper C declaration -lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" - -# Transform an extracted symbol line into symbol name and symbol address -lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" - -# Define system-specific variables. -case $host_os in -aix*) - symcode='[BCDT]' - ;; -cygwin* | mingw* | pw32*) - symcode='[ABCDGISTW]' - ;; -hpux*) # Its linker distinguishes data from code symbols - if test "$host_cpu" = ia64; then - symcode='[ABCDEGRST]' - fi - lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" - lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" - ;; -linux* | k*bsd*-gnu) - if test "$host_cpu" = ia64; then - symcode='[ABCDGIRSTW]' - lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" - lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" - fi - ;; -irix* | nonstopux*) - symcode='[BCDEGRST]' - ;; -osf*) - symcode='[BCDEGQRST]' - ;; -solaris*) - symcode='[BDRT]' - ;; -sco3.2v5*) - symcode='[DT]' - ;; -sysv4.2uw2*) - symcode='[DT]' - ;; -sysv5* | sco5v6* | unixware* | OpenUNIX*) - symcode='[ABDT]' - ;; -sysv4) - symcode='[DFNSTU]' - ;; -esac - -# Handle CRLF in mingw tool chain -opt_cr= -case $build_os in -mingw*) - opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp - ;; -esac - -# If we're using GNU nm, then use its standard symbol codes. -case `$NM -V 2>&1` in -*GNU* | *'with BFD'*) - symcode='[ABCDGIRSTW]' ;; -esac - -# Try without a prefix undercore, then with it. -for ac_symprfx in "" "_"; do - - # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. - symxfrm="\\1 $ac_symprfx\\2 \\2" - - # Write the raw and C identifiers. - lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" - - # Check to see that the pipe works correctly. - pipe_works=no - - rm -f conftest* - cat > conftest.$ac_ext <&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then - # Now try to grab the symbols. - nlist=conftest.nm - if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5 - (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && test -s "$nlist"; then - # Try sorting and uniquifying the output. - if sort "$nlist" | uniq > "$nlist"T; then - mv -f "$nlist"T "$nlist" - else - rm -f "$nlist"T - fi - - # Make sure that we snagged all the symbols we need. - if grep ' nm_test_var$' "$nlist" >/dev/null; then - if grep ' nm_test_func$' "$nlist" >/dev/null; then - cat < conftest.$ac_ext -#ifdef __cplusplus -extern "C" { -#endif - -EOF - # Now generate the symbol file. - eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' - - cat <> conftest.$ac_ext -#if defined (__STDC__) && __STDC__ -# define lt_ptr_t void * -#else -# define lt_ptr_t char * -# define const -#endif - -/* The mapping between symbol names and symbols. */ -const struct { - const char *name; - lt_ptr_t address; -} -lt_preloaded_symbols[] = -{ -EOF - $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext - cat <<\EOF >> conftest.$ac_ext - {0, (lt_ptr_t) 0} -}; - -#ifdef __cplusplus -} -#endif -EOF - # Now try linking the two files. - mv conftest.$ac_objext conftstm.$ac_objext - lt_save_LIBS="$LIBS" - lt_save_CFLAGS="$CFLAGS" - LIBS="conftstm.$ac_objext" - CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" - if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && test -s conftest${ac_exeext}; then - pipe_works=yes - fi - LIBS="$lt_save_LIBS" - CFLAGS="$lt_save_CFLAGS" - else - echo "cannot find nm_test_func in $nlist" >&5 - fi - else - echo "cannot find nm_test_var in $nlist" >&5 - fi - else - echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 - fi - else - echo "$progname: failed program was:" >&5 - cat conftest.$ac_ext >&5 - fi - rm -f conftest* conftst* - - # Do not use the global_symbol_pipe unless it works. - if test "$pipe_works" = yes; then - break - else - lt_cv_sys_global_symbol_pipe= - fi -done - -fi - -if test -z "$lt_cv_sys_global_symbol_pipe"; then - lt_cv_sys_global_symbol_to_cdecl= -fi -if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then - { echo "$as_me:$LINENO: result: failed" >&5 -echo "${ECHO_T}failed" >&6; } -else - { echo "$as_me:$LINENO: result: ok" >&5 -echo "${ECHO_T}ok" >&6; } -fi - -{ echo "$as_me:$LINENO: checking for objdir" >&5 -echo $ECHO_N "checking for objdir... $ECHO_C" >&6; } -if test "${lt_cv_objdir+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - rm -f .libs 2>/dev/null -mkdir .libs 2>/dev/null -if test -d .libs; then - lt_cv_objdir=.libs -else - # MS-DOS does not allow filenames that begin with a dot. - lt_cv_objdir=_libs -fi -rmdir .libs 2>/dev/null -fi -{ echo "$as_me:$LINENO: result: $lt_cv_objdir" >&5 -echo "${ECHO_T}$lt_cv_objdir" >&6; } -objdir=$lt_cv_objdir - - - - - -case $host_os in -aix3*) - # AIX sometimes has problems with the GCC collect2 program. For some - # reason, if we set the COLLECT_NAMES environment variable, the problems - # vanish in a puff of smoke. - if test "X${COLLECT_NAMES+set}" != Xset; then - COLLECT_NAMES= - export COLLECT_NAMES - fi - ;; -esac - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -Xsed='sed -e 1s/^X//' -sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g' - -# Same as above, but do not quote variable references. -double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g' - -# Sed substitution to delay expansion of an escaped shell variable in a -# double_quote_subst'ed string. -delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' - -# Sed substitution to avoid accidental globbing in evaled expressions -no_glob_subst='s/\*/\\\*/g' - -# Constants: -rm="rm -f" - -# Global variables: -default_ofile=libtool -can_build_shared=yes - -# All known linkers require a `.a' archive for static linking (except MSVC, -# which needs '.lib'). -libext=a -ltmain="$ac_aux_dir/ltmain.sh" -ofile="$default_ofile" -with_gnu_ld="$lt_cv_prog_gnu_ld" - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. -set dummy ${ac_tool_prefix}ar; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_AR+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$AR"; then - ac_cv_prog_AR="$AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_AR="${ac_tool_prefix}ar" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -AR=$ac_cv_prog_AR -if test -n "$AR"; then - { echo "$as_me:$LINENO: result: $AR" >&5 -echo "${ECHO_T}$AR" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_AR"; then - ac_ct_AR=$AR - # Extract the first word of "ar", so it can be a program name with args. -set dummy ar; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_ac_ct_AR+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_AR"; then - ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_AR="ar" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -ac_ct_AR=$ac_cv_prog_ac_ct_AR -if test -n "$ac_ct_AR"; then - { echo "$as_me:$LINENO: result: $ac_ct_AR" >&5 -echo "${ECHO_T}$ac_ct_AR" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - if test "x$ac_ct_AR" = x; then - AR="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} -ac_tool_warned=yes ;; -esac - AR=$ac_ct_AR - fi -else - AR="$ac_cv_prog_AR" -fi - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. -set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_RANLIB+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$RANLIB"; then - ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -RANLIB=$ac_cv_prog_RANLIB -if test -n "$RANLIB"; then - { echo "$as_me:$LINENO: result: $RANLIB" >&5 -echo "${ECHO_T}$RANLIB" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_RANLIB"; then - ac_ct_RANLIB=$RANLIB - # Extract the first word of "ranlib", so it can be a program name with args. -set dummy ranlib; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_RANLIB"; then - ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_RANLIB="ranlib" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB -if test -n "$ac_ct_RANLIB"; then - { echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 -echo "${ECHO_T}$ac_ct_RANLIB" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - if test "x$ac_ct_RANLIB" = x; then - RANLIB=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} -ac_tool_warned=yes ;; -esac - RANLIB=$ac_ct_RANLIB - fi -else - RANLIB="$ac_cv_prog_RANLIB" -fi - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_STRIP+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { echo "$as_me:$LINENO: result: $STRIP" >&5 -echo "${ECHO_T}$STRIP" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_STRIP="strip" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 -echo "${ECHO_T}$ac_ct_STRIP" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - - -old_CC="$CC" -old_CFLAGS="$CFLAGS" - -# Set sane defaults for various variables -test -z "$AR" && AR=ar -test -z "$AR_FLAGS" && AR_FLAGS=cru -test -z "$AS" && AS=as -test -z "$CC" && CC=cc -test -z "$LTCC" && LTCC=$CC -test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS -test -z "$DLLTOOL" && DLLTOOL=dlltool -test -z "$LD" && LD=ld -test -z "$LN_S" && LN_S="ln -s" -test -z "$MAGIC_CMD" && MAGIC_CMD=file -test -z "$NM" && NM=nm -test -z "$SED" && SED=sed -test -z "$OBJDUMP" && OBJDUMP=objdump -test -z "$RANLIB" && RANLIB=: -test -z "$STRIP" && STRIP=: -test -z "$ac_objext" && ac_objext=o - -# Determine commands to create old-style static archives. -old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' -old_postinstall_cmds='chmod 644 $oldlib' -old_postuninstall_cmds= - -if test -n "$RANLIB"; then - case $host_os in - openbsd*) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" - ;; - *) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" - ;; - esac - old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" -fi - -for cc_temp in $compiler""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac -done -cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` - - -# Only perform the check for file, if the check method requires it -case $deplibs_check_method in -file_magic*) - if test "$file_magic_cmd" = '$MAGIC_CMD'; then - { echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5 -echo $ECHO_N "checking for ${ac_tool_prefix}file... $ECHO_C" >&6; } -if test "${lt_cv_path_MAGIC_CMD+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - case $MAGIC_CMD in -[\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD="$MAGIC_CMD" - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" - for ac_dir in $ac_dummy; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/${ac_tool_prefix}file; then - lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD="$lt_cv_path_MAGIC_CMD" - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -EOF - fi ;; - esac - fi - break - fi - done - IFS="$lt_save_ifs" - MAGIC_CMD="$lt_save_MAGIC_CMD" - ;; -esac -fi - -MAGIC_CMD="$lt_cv_path_MAGIC_CMD" -if test -n "$MAGIC_CMD"; then - { echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 -echo "${ECHO_T}$MAGIC_CMD" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - -if test -z "$lt_cv_path_MAGIC_CMD"; then - if test -n "$ac_tool_prefix"; then - { echo "$as_me:$LINENO: checking for file" >&5 -echo $ECHO_N "checking for file... $ECHO_C" >&6; } -if test "${lt_cv_path_MAGIC_CMD+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - case $MAGIC_CMD in -[\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD="$MAGIC_CMD" - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" - for ac_dir in $ac_dummy; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/file; then - lt_cv_path_MAGIC_CMD="$ac_dir/file" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD="$lt_cv_path_MAGIC_CMD" - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -EOF - fi ;; - esac - fi - break - fi - done - IFS="$lt_save_ifs" - MAGIC_CMD="$lt_save_MAGIC_CMD" - ;; -esac -fi - -MAGIC_CMD="$lt_cv_path_MAGIC_CMD" -if test -n "$MAGIC_CMD"; then - { echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 -echo "${ECHO_T}$MAGIC_CMD" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - - else - MAGIC_CMD=: - fi -fi - - fi - ;; -esac - -enable_dlopen=no -enable_win32_dll=yes - -# Check whether --enable-libtool-lock was given. -if test "${enable_libtool_lock+set}" = set; then - enableval=$enable_libtool_lock; -fi - -test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes - - -# Check whether --with-pic was given. -if test "${with_pic+set}" = set; then - withval=$with_pic; pic_mode="$withval" -else - pic_mode=default -fi - -test -z "$pic_mode" && pic_mode=default - -# Use C for the default configuration in the libtool script -tagname= -lt_save_CC="$CC" -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -# Source file extension for C test sources. -ac_ext=c - -# Object file extension for compiled C test sources. -objext=o -objext=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="int some_variable = 0;" - -# Code to be used in simple link tests -lt_simple_link_test_code='int main(){return(0);}' - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - - -# save warnings/boilerplate of simple test code -ac_outfile=conftest.$ac_objext -echo "$lt_simple_compile_test_code" >conftest.$ac_ext -eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_compiler_boilerplate=`cat conftest.err` -$rm conftest* - -ac_outfile=conftest.$ac_objext -echo "$lt_simple_link_test_code" >conftest.$ac_ext -eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_linker_boilerplate=`cat conftest.err` -$rm conftest* - - -## CAVEAT EMPTOR: -## There is no encapsulation within the following macros, do not change -## the running order or otherwise move them around unless you know exactly -## what you are doing... - -lt_prog_compiler_no_builtin_flag= - -if test "$GCC" = yes; then - lt_prog_compiler_no_builtin_flag=' -fno-builtin' - - -{ echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 -echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6; } -if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - lt_cv_prog_compiler_rtti_exceptions=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="-fno-rtti -fno-exceptions" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7567: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:7571: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_rtti_exceptions=yes - fi - fi - $rm conftest* - -fi -{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 -echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6; } - -if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then - lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" -else - : -fi - -fi - -lt_prog_compiler_wl= -lt_prog_compiler_pic= -lt_prog_compiler_static= - -{ echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 -echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6; } - - if test "$GCC" = yes; then - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_static='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - fi - ;; - - amigaos*) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the `-m68020' flag to GCC prevents building anything better, - # like `-m68040'. - lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - - mingw* | cygwin* | pw32* | os2*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - lt_prog_compiler_pic='-DDLL_EXPORT' - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - ;; - - interix[3-9]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - - msdosdjgpp*) - # Just because we use GCC doesn't mean we suddenly get shared libraries - # on systems that don't support them. - lt_prog_compiler_can_build_shared=no - enable_shared=no - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic=-Kconform_pic - fi - ;; - - hpux*) - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - ;; - - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - else - # PORTME Check for flag to pass linker flags through the system compiler. - case $host_os in - aix*) - lt_prog_compiler_wl='-Wl,' - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - else - lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' - fi - ;; - darwin*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - case $cc_basename in - xlc*) - lt_prog_compiler_pic='-qnocommon' - lt_prog_compiler_wl='-Wl,' - ;; - esac - ;; - - mingw* | cygwin* | pw32* | os2*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - lt_prog_compiler_pic='-DDLL_EXPORT' - ;; - - hpux9* | hpux10* | hpux11*) - lt_prog_compiler_wl='-Wl,' - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='+Z' - ;; - esac - # Is there a better lt_prog_compiler_static that works with the bundled CC? - lt_prog_compiler_static='${wl}-a ${wl}archive' - ;; - - irix5* | irix6* | nonstopux*) - lt_prog_compiler_wl='-Wl,' - # PIC (with -KPIC) is the default. - lt_prog_compiler_static='-non_shared' - ;; - - newsos6) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - linux* | k*bsd*-gnu) - case $cc_basename in - icc* | ecc*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-static' - ;; - pgcc* | pgf77* | pgf90* | pgf95*) - # Portland Group compilers (*not* the Pentium gcc compiler, - # which looks to be a dead project) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - ccc*) - lt_prog_compiler_wl='-Wl,' - # All Alpha code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) - # Sun C 5.9 - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Wl,' - ;; - *Sun\ F*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='' - ;; - esac - ;; - esac - ;; - - osf3* | osf4* | osf5*) - lt_prog_compiler_wl='-Wl,' - # All OSF/1 code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - - rdos*) - lt_prog_compiler_static='-non_shared' - ;; - - solaris*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - case $cc_basename in - f77* | f90* | f95*) - lt_prog_compiler_wl='-Qoption ld ';; - *) - lt_prog_compiler_wl='-Wl,';; - esac - ;; - - sunos4*) - lt_prog_compiler_wl='-Qoption ld ' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4*MP*) - if test -d /usr/nec ;then - lt_prog_compiler_pic='-Kconform_pic' - lt_prog_compiler_static='-Bstatic' - fi - ;; - - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - unicos*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_can_build_shared=no - ;; - - uts4*) - lt_prog_compiler_pic='-pic' - lt_prog_compiler_static='-Bstatic' - ;; - - *) - lt_prog_compiler_can_build_shared=no - ;; - esac - fi - -{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic" >&5 -echo "${ECHO_T}$lt_prog_compiler_pic" >&6; } - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$lt_prog_compiler_pic"; then - -{ echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 -echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic works... $ECHO_C" >&6; } -if test "${lt_prog_compiler_pic_works+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - lt_prog_compiler_pic_works=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic -DPIC" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7857: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:7861: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_prog_compiler_pic_works=yes - fi - fi - $rm conftest* - -fi -{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works" >&5 -echo "${ECHO_T}$lt_prog_compiler_pic_works" >&6; } - -if test x"$lt_prog_compiler_pic_works" = xyes; then - case $lt_prog_compiler_pic in - "" | " "*) ;; - *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; - esac -else - lt_prog_compiler_pic= - lt_prog_compiler_can_build_shared=no -fi - -fi -case $host_os in - # For platforms which do not support PIC, -DPIC is meaningless: - *djgpp*) - lt_prog_compiler_pic= - ;; - *) - lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" - ;; -esac - -# -# Check to make sure the static flag actually works. -# -wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" -{ echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 -echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6; } -if test "${lt_prog_compiler_static_works+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - lt_prog_compiler_static_works=no - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS $lt_tmp_static_flag" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_prog_compiler_static_works=yes - fi - else - lt_prog_compiler_static_works=yes - fi - fi - $rm conftest* - LDFLAGS="$save_LDFLAGS" - -fi -{ echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works" >&5 -echo "${ECHO_T}$lt_prog_compiler_static_works" >&6; } - -if test x"$lt_prog_compiler_static_works" = xyes; then - : -else - lt_prog_compiler_static= -fi - - -{ echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 -echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6; } -if test "${lt_cv_prog_compiler_c_o+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - lt_cv_prog_compiler_c_o=no - $rm -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7961: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:7965: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o=yes - fi - fi - chmod u+w . 2>&5 - $rm conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files - $rm out/* && rmdir out - cd .. - rmdir conftest - $rm conftest* - -fi -{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5 -echo "${ECHO_T}$lt_cv_prog_compiler_c_o" >&6; } - - -hard_links="nottested" -if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then - # do not overwrite the value of need_locks provided by the user - { echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 -echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6; } - hard_links=yes - $rm conftest* - ln conftest.a conftest.b 2>/dev/null && hard_links=no - touch conftest.a - ln conftest.a conftest.b 2>&5 || hard_links=no - ln conftest.a conftest.b 2>/dev/null && hard_links=no - { echo "$as_me:$LINENO: result: $hard_links" >&5 -echo "${ECHO_T}$hard_links" >&6; } - if test "$hard_links" = no; then - { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 -echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} - need_locks=warn - fi -else - need_locks=no -fi - -{ echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 -echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6; } - - runpath_var= - allow_undefined_flag= - enable_shared_with_static_runtimes=no - archive_cmds= - archive_expsym_cmds= - old_archive_From_new_cmds= - old_archive_from_expsyms_cmds= - export_dynamic_flag_spec= - whole_archive_flag_spec= - thread_safe_flag_spec= - hardcode_libdir_flag_spec= - hardcode_libdir_flag_spec_ld= - hardcode_libdir_separator= - hardcode_direct=no - hardcode_minus_L=no - hardcode_shlibpath_var=unsupported - link_all_deplibs=unknown - hardcode_automatic=no - module_cmds= - module_expsym_cmds= - always_export_symbols=no - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - # include_expsyms should be a list of space-separated symbols to be *always* - # included in the symbol list - include_expsyms= - # exclude_expsyms can be an extended regexp of symbols to exclude - # it will be wrapped by ` (' and `)$', so one must not match beginning or - # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', - # as well as any symbol that contains `d'. - exclude_expsyms="_GLOBAL_OFFSET_TABLE_" - # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out - # platforms (ab)use it in PIC code, but their linkers get confused if - # the symbol is explicitly referenced. Since portable code cannot - # rely on this symbol name, it's probably fine to never include it in - # preloaded symbol tables. - extract_expsyms_cmds= - # Just being paranoid about ensuring that cc_basename is set. - for cc_temp in $compiler""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac -done -cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` - - case $host_os in - cygwin* | mingw* | pw32*) - # FIXME: the MSVC++ port hasn't been tested in a loooong time - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - if test "$GCC" != yes; then - with_gnu_ld=no - fi - ;; - interix*) - # we just hope/assume this is gcc and not c89 (= MSVC++) - with_gnu_ld=yes - ;; - openbsd*) - with_gnu_ld=no - ;; - esac - - ld_shlibs=yes - if test "$with_gnu_ld" = yes; then - # If archive_cmds runs LD, not CC, wlarc should be empty - wlarc='${wl}' - - # Set some defaults for GNU ld with shared library support. These - # are reset later if shared libraries are not supported. Putting them - # here allows them to be overridden if necessary. - runpath_var=LD_RUN_PATH - hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' - export_dynamic_flag_spec='${wl}--export-dynamic' - # ancient GNU ld didn't support --whole-archive et. al. - if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then - whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - else - whole_archive_flag_spec= - fi - supports_anon_versioning=no - case `$LD -v 2>/dev/null` in - *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 - *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... - *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... - *\ 2.11.*) ;; # other 2.11 versions - *) supports_anon_versioning=yes ;; - esac - - # See if GNU ld supports shared libraries. - case $host_os in - aix3* | aix4* | aix5*) - # On AIX/PPC, the GNU linker is very broken - if test "$host_cpu" != ia64; then - ld_shlibs=no - cat <&2 - -*** Warning: the GNU linker, at least up to release 2.9.1, is reported -*** to be unable to reliably create shared libraries on AIX. -*** Therefore, libtool is disabling shared libraries support. If you -*** really care for shared libraries, you may want to modify your PATH -*** so that a non-GNU linker is found, and then restart. - -EOF - fi - ;; - - amigaos*) - archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - - # Samuel A. Falvo II reports - # that the semantics of dynamic libraries on AmigaOS, at least up - # to version 4, is to share data among multiple programs linked - # with the same dynamic library. Since this doesn't match the - # behavior of shared libraries on other platforms, we can't use - # them. - ld_shlibs=no - ;; - - beos*) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - allow_undefined_flag=unsupported - # Joseph Beckenbach says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - else - ld_shlibs=no - fi - ;; - - cygwin* | mingw* | pw32*) - # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, - # as there is no search path for DLLs. - hardcode_libdir_flag_spec='-L$libdir' - allow_undefined_flag=unsupported - always_export_symbols=no - enable_shared_with_static_runtimes=yes - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' - - if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file (1st line - # is EXPORTS), use it as is; otherwise, prepend... - archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - else - ld_shlibs=no - fi - ;; - - interix[3-9]*) - hardcode_direct=no - hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - export_dynamic_flag_spec='${wl}-E' - # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. - # Instead, shared libraries are loaded at an image base (0x10000000 by - # default) and relocated if they conflict, which is a slow very memory - # consuming and fragmenting process. To avoid this, we pick a random, - # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link - # time. Moving up from 0x10000000 also allows more sbrk(2) space. - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - ;; - - gnu* | linux* | k*bsd*-gnu) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - tmp_addflag= - case $cc_basename,$host_cpu in - pgcc*) # Portland Group C compiler - whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' - tmp_addflag=' $pic_flag' - ;; - pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers - whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' - tmp_addflag=' $pic_flag -Mnomain' ;; - ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 - tmp_addflag=' -i_dynamic' ;; - efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 - tmp_addflag=' -i_dynamic -nofor_main' ;; - ifc* | ifort*) # Intel Fortran compiler - tmp_addflag=' -nofor_main' ;; - esac - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) # Sun C 5.9 - whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' - tmp_sharedflag='-G' ;; - *Sun\ F*) # Sun Fortran 8.3 - tmp_sharedflag='-G' ;; - *) - tmp_sharedflag='-shared' ;; - esac - archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - - if test $supports_anon_versioning = yes; then - archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - $echo "local: *; };" >> $output_objdir/$libname.ver~ - $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' - fi - link_all_deplibs=no - else - ld_shlibs=no - fi - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' - wlarc= - else - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - fi - ;; - - solaris*) - if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then - ld_shlibs=no - cat <&2 - -*** Warning: The releases 2.8.* of the GNU linker cannot reliably -*** create shared libraries on Solaris systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.9.1 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -EOF - elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) - case `$LD -v 2>&1` in - *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not -*** reliably create shared libraries on SCO systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.16.91.0.3 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - ;; - *) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - esac - ;; - - sunos4*) - archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' - wlarc= - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - *) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - esac - - if test "$ld_shlibs" = no; then - runpath_var= - hardcode_libdir_flag_spec= - export_dynamic_flag_spec= - whole_archive_flag_spec= - fi - else - # PORTME fill in a description of your system's linker (not GNU ld) - case $host_os in - aix3*) - allow_undefined_flag=unsupported - always_export_symbols=yes - archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' - # Note: this linker hardcodes the directories in LIBPATH if there - # are no directories specified by -L. - hardcode_minus_L=yes - if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then - # Neither direct hardcoding nor static linking is supported with a - # broken collect2. - hardcode_direct=unsupported - fi - ;; - - aix4* | aix5*) - if test "$host_cpu" = ia64; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag="" - else - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to AIX nm, but means don't demangle with GNU nm - if $NM -V 2>&1 | grep 'GNU' > /dev/null; then - export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' - else - export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' - fi - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # need to do runtime linking. - case $host_os in aix4.[23]|aix4.[23].*|aix5*) - for ld_flag in $LDFLAGS; do - if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then - aix_use_runtimelinking=yes - break - fi - done - ;; - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - archive_cmds='' - hardcode_direct=yes - hardcode_libdir_separator=':' - link_all_deplibs=yes - - if test "$GCC" = yes; then - case $host_os in aix4.[012]|aix4.[012].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`${CC} -print-prog-name=collect2` - if test -f "$collect2name" && \ - strings "$collect2name" | grep resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - hardcode_direct=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - hardcode_minus_L=yes - hardcode_libdir_flag_spec='-L$libdir' - hardcode_libdir_separator= - fi - ;; - esac - shared_flag='-shared' - if test "$aix_use_runtimelinking" = yes; then - shared_flag="$shared_flag "'${wl}-G' - fi - else - # not using gcc - if test "$host_cpu" = ia64; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test "$aix_use_runtimelinking" = yes; then - shared_flag='${wl}-G' - else - shared_flag='${wl}-bM:SRE' - fi - fi - fi - - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to export. - always_export_symbols=yes - if test "$aix_use_runtimelinking" = yes; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - allow_undefined_flag='-berok' - # Determine the default libpath from the value encoded in an empty executable. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - -lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\(.*\)$/\1/ - p - } - }' -aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -# Check for a 64-bit object if we didn't find anything. -if test -z "$aix_libpath"; then - aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -fi -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi - - hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" - archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" - else - if test "$host_cpu" = ia64; then - hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' - allow_undefined_flag="-z nodefs" - archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an empty executable. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - -lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\(.*\)$/\1/ - p - } - }' -aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -# Check for a 64-bit object if we didn't find anything. -if test -z "$aix_libpath"; then - aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -fi -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi - - hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - no_undefined_flag=' ${wl}-bernotok' - allow_undefined_flag=' ${wl}-berok' - # Exported symbols can be pulled into shared objects from archives - whole_archive_flag_spec='$convenience' - archive_cmds_need_lc=yes - # This is similar to how AIX traditionally builds its shared libraries. - archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' - fi - fi - ;; - - amigaos*) - archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - # see comment about different semantics on the GNU ld section - ld_shlibs=no - ;; - - bsdi[45]*) - export_dynamic_flag_spec=-rdynamic - ;; - - cygwin* | mingw* | pw32*) - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=".dll" - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' - # The linker will automatically build a .lib file if we build a DLL. - old_archive_From_new_cmds='true' - # FIXME: Should let the user specify the lib program. - old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' - fix_srcfile_path='`cygpath -w "$srcfile"`' - enable_shared_with_static_runtimes=yes - ;; - - darwin* | rhapsody*) - case $host_os in - rhapsody* | darwin1.[012]) - allow_undefined_flag='${wl}-undefined ${wl}suppress' - ;; - *) # Darwin 1.3 on - if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then - allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' - else - case ${MACOSX_DEPLOYMENT_TARGET} in - 10.[012]) - allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' - ;; - 10.*) - allow_undefined_flag='${wl}-undefined ${wl}dynamic_lookup' - ;; - esac - fi - ;; - esac - archive_cmds_need_lc=no - hardcode_direct=no - hardcode_automatic=yes - hardcode_shlibpath_var=unsupported - whole_archive_flag_spec='' - link_all_deplibs=yes - if test "$GCC" = yes ; then - output_verbose_link_cmd='echo' - archive_cmds='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' - module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' - # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds - archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - else - case $cc_basename in - xlc*) - output_verbose_link_cmd='echo' - archive_cmds='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring' - module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' - # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds - archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - ;; - *) - ld_shlibs=no - ;; - esac - fi - ;; - - dgux*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - freebsd1*) - ld_shlibs=no - ;; - - # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor - # support. Future versions do this automatically, but an explicit c++rt0.o - # does not break anything, and helps significantly (at the cost of a little - # extra space). - freebsd2.2*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - # Unfortunately, older versions of FreeBSD 2 do not have this feature. - freebsd2*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - # FreeBSD 3 and greater uses gcc -shared to do shared libraries. - freebsd* | dragonfly*) - archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - hpux9*) - if test "$GCC" = yes; then - archive_cmds='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - else - archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - fi - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - export_dynamic_flag_spec='${wl}-E' - ;; - - hpux10*) - if test "$GCC" = yes -a "$with_gnu_ld" = no; then - archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' - fi - if test "$with_gnu_ld" = no; then - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_separator=: - - hardcode_direct=yes - export_dynamic_flag_spec='${wl}-E' - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - fi - ;; - - hpux11*) - if test "$GCC" = yes -a "$with_gnu_ld" = no; then - case $host_cpu in - hppa*64*) - archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - else - case $host_cpu in - hppa*64*) - archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - fi - if test "$with_gnu_ld" = no; then - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_separator=: - - case $host_cpu in - hppa*64*|ia64*) - hardcode_libdir_flag_spec_ld='+b $libdir' - hardcode_direct=no - hardcode_shlibpath_var=no - ;; - *) - hardcode_direct=yes - export_dynamic_flag_spec='${wl}-E' - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - ;; - esac - fi - ;; - - irix5* | irix6* | nonstopux*) - if test "$GCC" = yes; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - else - archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - hardcode_libdir_flag_spec_ld='-rpath $libdir' - fi - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - link_all_deplibs=yes - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out - else - archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF - fi - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - newsos6) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - hardcode_shlibpath_var=no - ;; - - openbsd*) - if test -f /usr/libexec/ld.so; then - hardcode_direct=yes - hardcode_shlibpath_var=no - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - export_dynamic_flag_spec='${wl}-E' - else - case $host_os in - openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-R$libdir' - ;; - *) - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - ;; - esac - fi - else - ld_shlibs=no - fi - ;; - - os2*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - allow_undefined_flag=unsupported - archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' - old_archive_From_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' - ;; - - osf3*) - if test "$GCC" = yes; then - allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - else - allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - fi - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - ;; - - osf4* | osf5*) # as osf3* with the addition of -msym flag - if test "$GCC" = yes; then - allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - else - allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ - $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' - - # Both c and cxx compiler support -rpath directly - hardcode_libdir_flag_spec='-rpath $libdir' - fi - hardcode_libdir_separator=: - ;; - - solaris*) - no_undefined_flag=' -z text' - if test "$GCC" = yes; then - wlarc='${wl}' - archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' - else - wlarc='' - archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' - archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' - fi - hardcode_libdir_flag_spec='-R$libdir' - hardcode_shlibpath_var=no - case $host_os in - solaris2.[0-5] | solaris2.[0-5].*) ;; - *) - # The compiler driver will combine and reorder linker options, - # but understands `-z linker_flag'. GCC discards it without `$wl', - # but is careful enough not to reorder. - # Supported since Solaris 2.6 (maybe 2.5.1?) - if test "$GCC" = yes; then - whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' - else - whole_archive_flag_spec='-z allextract$convenience -z defaultextract' - fi - ;; - esac - link_all_deplibs=yes - ;; - - sunos4*) - if test "x$host_vendor" = xsequent; then - # Use $CC to link under sequent, because it throws in some extra .o - # files that make .init and .fini sections work. - archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' - fi - hardcode_libdir_flag_spec='-L$libdir' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - sysv4) - case $host_vendor in - sni) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes # is this really true??? - ;; - siemens) - ## LD is ld it makes a PLAMLIB - ## CC just makes a GrossModule. - archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' - reload_cmds='$CC -r -o $output$reload_objs' - hardcode_direct=no - ;; - motorola) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=no #Motorola manual says yes, but my tests say they lie - ;; - esac - runpath_var='LD_RUN_PATH' - hardcode_shlibpath_var=no - ;; - - sysv4.3*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var=no - export_dynamic_flag_spec='-Bexport' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var=no - runpath_var=LD_RUN_PATH - hardcode_runpath_var=yes - ld_shlibs=yes - fi - ;; - - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) - no_undefined_flag='${wl}-z,text' - archive_cmds_need_lc=no - hardcode_shlibpath_var=no - runpath_var='LD_RUN_PATH' - - if test "$GCC" = yes; then - archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - sysv5* | sco3.2v5* | sco5v6*) - # Note: We can NOT use -z defs as we might desire, because we do not - # link with -lc, and that would cause any symbols used from libc to - # always be unresolved, which means just about no library would - # ever link correctly. If we're not using GNU ld we use -z text - # though, which does catch some bad symbols but isn't as heavy-handed - # as -z defs. - no_undefined_flag='${wl}-z,text' - allow_undefined_flag='${wl}-z,nodefs' - archive_cmds_need_lc=no - hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' - hardcode_libdir_separator=':' - link_all_deplibs=yes - export_dynamic_flag_spec='${wl}-Bexport' - runpath_var='LD_RUN_PATH' - - if test "$GCC" = yes; then - archive_cmds='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - uts4*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - *) - ld_shlibs=no - ;; - esac - fi - -{ echo "$as_me:$LINENO: result: $ld_shlibs" >&5 -echo "${ECHO_T}$ld_shlibs" >&6; } -test "$ld_shlibs" = no && can_build_shared=no - -# -# Do we need to explicitly link libc? -# -case "x$archive_cmds_need_lc" in -x|xyes) - # Assume -lc should be added - archive_cmds_need_lc=yes - - if test "$enable_shared" = yes && test "$GCC" = yes; then - case $archive_cmds in - *'~'*) - # FIXME: we may have to deal with multi-command sequences. - ;; - '$CC '*) - # Test whether the compiler implicitly links with -lc since on some - # systems, -lgcc has to come before -lc. If gcc already passes -lc - # to ld, don't add -lc before -lgcc. - { echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 -echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6; } - $rm conftest* - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$lt_prog_compiler_wl - pic_flag=$lt_prog_compiler_pic - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$allow_undefined_flag - allow_undefined_flag= - if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 - (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - then - archive_cmds_need_lc=no - else - archive_cmds_need_lc=yes - fi - allow_undefined_flag=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $rm conftest* - { echo "$as_me:$LINENO: result: $archive_cmds_need_lc" >&5 -echo "${ECHO_T}$archive_cmds_need_lc" >&6; } - ;; - esac - fi - ;; -esac - -{ echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 -echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6; } -library_names_spec= -libname_spec='lib$name' -soname_spec= -shrext_cmds=".so" -postinstall_cmds= -postuninstall_cmds= -finish_cmds= -finish_eval= -shlibpath_var= -shlibpath_overrides_runpath=unknown -version_type=none -dynamic_linker="$host_os ld.so" -sys_lib_dlsearch_path_spec="/lib /usr/lib" - -if test "$GCC" = yes; then - case $host_os in - darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; - *) lt_awk_arg="/^libraries:/" ;; - esac - lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` - if echo "$lt_search_path_spec" | grep ';' >/dev/null ; then - # if the path contains ";" then we assume it to be the separator - # otherwise default to the standard path separator (i.e. ":") - it is - # assumed that no part of a normal pathname contains ";" but that should - # okay in the real world where ";" in dirpaths is itself problematic. - lt_search_path_spec=`echo "$lt_search_path_spec" | $SED -e 's/;/ /g'` - else - lt_search_path_spec=`echo "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi - # Ok, now we have the path, separated by spaces, we can step through it - # and add multilib dir if necessary. - lt_tmp_lt_search_path_spec= - lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` - for lt_sys_path in $lt_search_path_spec; do - if test -d "$lt_sys_path/$lt_multi_os_dir"; then - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" - else - test -d "$lt_sys_path" && \ - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" - fi - done - lt_search_path_spec=`echo $lt_tmp_lt_search_path_spec | awk ' -BEGIN {RS=" "; FS="/|\n";} { - lt_foo=""; - lt_count=0; - for (lt_i = NF; lt_i > 0; lt_i--) { - if ($lt_i != "" && $lt_i != ".") { - if ($lt_i == "..") { - lt_count++; - } else { - if (lt_count == 0) { - lt_foo="/" $lt_i lt_foo; - } else { - lt_count--; - } - } - } - } - if (lt_foo != "") { lt_freq[lt_foo]++; } - if (lt_freq[lt_foo] == 1) { print lt_foo; } -}'` - sys_lib_search_path_spec=`echo $lt_search_path_spec` -else - sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" -fi -need_lib_prefix=unknown -hardcode_into_libs=no - -# when you set need_version to no, make sure it does not cause -set_version -# flags to be left without arguments -need_version=unknown - -case $host_os in -aix3*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' - shlibpath_var=LIBPATH - - # AIX 3 has no versioning support, so we append a major version to the name. - soname_spec='${libname}${release}${shared_ext}$major' - ;; - -aix4* | aix5*) - version_type=linux - need_lib_prefix=no - need_version=no - hardcode_into_libs=yes - if test "$host_cpu" = ia64; then - # AIX 5 supports IA64 - library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - else - # With GCC up to 2.95.x, collect2 would create an import file - # for dependence libraries. The import file would start with - # the line `#! .'. This would cause the generated library to - # depend on `.', always an invalid library. This was fixed in - # development snapshots of GCC prior to 3.0. - case $host_os in - aix4 | aix4.[01] | aix4.[01].*) - if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' - echo ' yes ' - echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then - : - else - can_build_shared=no - fi - ;; - esac - # AIX (on Power*) has no versioning support, so currently we can not hardcode correct - # soname into executable. Probably we can add versioning support to - # collect2, so additional links can be useful in future. - if test "$aix_use_runtimelinking" = yes; then - # If using run time linking (on AIX 4.2 or later) use lib.so - # instead of lib.a to let people know that these are not - # typical AIX shared libraries. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - else - # We preserve .a as extension for shared libraries through AIX4.2 - # and later when we are not doing run time linking. - library_names_spec='${libname}${release}.a $libname.a' - soname_spec='${libname}${release}${shared_ext}$major' - fi - shlibpath_var=LIBPATH - fi - ;; - -amigaos*) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' - ;; - -beos*) - library_names_spec='${libname}${shared_ext}' - dynamic_linker="$host_os ld.so" - shlibpath_var=LIBRARY_PATH - ;; - -bsdi[45]*) - version_type=linux - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" - sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" - # the default ld.so.conf also contains /usr/contrib/lib and - # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow - # libtool to hard-code these into programs - ;; - -cygwin* | mingw* | pw32*) - version_type=windows - shrext_cmds=".dll" - need_version=no - need_lib_prefix=no - - case $GCC,$host_os in - yes,cygwin* | yes,mingw* | yes,pw32*) - library_names_spec='$libname.dll.a' - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \${file}`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $rm \$dlpath' - shlibpath_overrides_runpath=yes - - case $host_os in - cygwin*) - # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" - ;; - mingw*) - # MinGW DLLs use traditional 'lib' prefix - soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` - if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then - # It is most probably a Windows format PATH printed by - # mingw gcc, but we are running on Cygwin. Gcc prints its search - # path with ; separators, and with drive letters. We can handle the - # drive letters (cygwin fileutils understands them), so leave them, - # especially as we might pass files found there to a mingw objdump, - # which wouldn't understand a cygwinified path. Ahh. - sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi - ;; - pw32*) - # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - ;; - esac - ;; - - *) - library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' - ;; - esac - dynamic_linker='Win32 ld.exe' - # FIXME: first we should search . and the directory the executable is in - shlibpath_var=PATH - ;; - -darwin* | rhapsody*) - dynamic_linker="$host_os dyld" - version_type=darwin - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' - soname_spec='${libname}${release}${major}$shared_ext' - shlibpath_overrides_runpath=yes - shlibpath_var=DYLD_LIBRARY_PATH - shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' - - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" - sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' - ;; - -dgux*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -freebsd1*) - dynamic_linker=no - ;; - -freebsd* | dragonfly*) - # DragonFly does not have aout. When/if they implement a new - # versioning mechanism, adjust this. - if test -x /usr/bin/objformat; then - objformat=`/usr/bin/objformat` - else - case $host_os in - freebsd[123]*) objformat=aout ;; - *) objformat=elf ;; - esac - fi - version_type=freebsd-$objformat - case $version_type in - freebsd-elf*) - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - need_version=no - need_lib_prefix=no - ;; - freebsd-*) - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' - need_version=yes - ;; - esac - shlibpath_var=LD_LIBRARY_PATH - case $host_os in - freebsd2*) - shlibpath_overrides_runpath=yes - ;; - freebsd3.[01]* | freebsdelf3.[01]*) - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ - freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - *) # from 4.6 on, and DragonFly - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - esac - ;; - -gnu*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - hardcode_into_libs=yes - ;; - -hpux9* | hpux10* | hpux11*) - # Give a soname corresponding to the major version so that dld.sl refuses to - # link against other versions. - version_type=sunos - need_lib_prefix=no - need_version=no - case $host_cpu in - ia64*) - shrext_cmds='.so' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.so" - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - if test "X$HPUX_IA64_MODE" = X32; then - sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" - else - sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" - fi - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - hppa*64*) - shrext_cmds='.sl' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.sl" - shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - *) - shrext_cmds='.sl' - dynamic_linker="$host_os dld.sl" - shlibpath_var=SHLIB_PATH - shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - ;; - esac - # HP-UX runs *really* slowly unless shared libraries are mode 555. - postinstall_cmds='chmod 555 $lib' - ;; - -interix[3-9]*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -irix5* | irix6* | nonstopux*) - case $host_os in - nonstopux*) version_type=nonstopux ;; - *) - if test "$lt_cv_prog_gnu_ld" = yes; then - version_type=linux - else - version_type=irix - fi ;; - esac - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' - case $host_os in - irix5* | nonstopux*) - libsuff= shlibsuff= - ;; - *) - case $LD in # libtool.m4 will add one of these switches to LD - *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") - libsuff= shlibsuff= libmagic=32-bit;; - *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") - libsuff=32 shlibsuff=N32 libmagic=N32;; - *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") - libsuff=64 shlibsuff=64 libmagic=64-bit;; - *) libsuff= shlibsuff= libmagic=never-match;; - esac - ;; - esac - shlibpath_var=LD_LIBRARY${shlibsuff}_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" - sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" - hardcode_into_libs=yes - ;; - -# No shared lib support for Linux oldld, aout, or coff. -linux*oldld* | linux*aout* | linux*coff*) - dynamic_linker=no - ;; - -# This must be Linux ELF. -linux* | k*bsd*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - # Append ld.so.conf contents to the search path - if test -f /etc/ld.so.conf; then - lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` - sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" - fi - - # We used to test for /lib/ld.so.1 and disable shared libraries on - # powerpc, because MkLinux only supported shared libraries with the - # GNU dynamic linker. Since this was broken with cross compilers, - # most powerpc-linux boxes support dynamic linking these days and - # people can always --disable-shared, the test was removed, and we - # assume the GNU/Linux dynamic linker is in use. - dynamic_linker='GNU/Linux ld.so' - ;; - -netbsdelf*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='NetBSD ld.elf_so' - ;; - -netbsd*) - version_type=sunos - need_lib_prefix=no - need_version=no - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - dynamic_linker='NetBSD (a.out) ld.so' - else - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='NetBSD ld.elf_so' - fi - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - -newsos6) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -nto-qnx*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -openbsd*) - version_type=sunos - sys_lib_dlsearch_path_spec="/usr/lib" - need_lib_prefix=no - # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. - case $host_os in - openbsd3.3 | openbsd3.3.*) need_version=yes ;; - *) need_version=no ;; - esac - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - case $host_os in - openbsd2.[89] | openbsd2.[89].*) - shlibpath_overrides_runpath=no - ;; - *) - shlibpath_overrides_runpath=yes - ;; - esac - else - shlibpath_overrides_runpath=yes - fi - ;; - -os2*) - libname_spec='$name' - shrext_cmds=".dll" - need_lib_prefix=no - library_names_spec='$libname${shared_ext} $libname.a' - dynamic_linker='OS/2 ld.exe' - shlibpath_var=LIBPATH - ;; - -osf3* | osf4* | osf5*) - version_type=osf - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" - ;; - -rdos*) - dynamic_linker=no - ;; - -solaris*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - # ldd complains unless libraries are executable - postinstall_cmds='chmod +x $lib' - ;; - -sunos4*) - version_type=sunos - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - if test "$with_gnu_ld" = yes; then - need_lib_prefix=no - fi - need_version=yes - ;; - -sysv4 | sysv4.3*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - case $host_vendor in - sni) - shlibpath_overrides_runpath=no - need_lib_prefix=no - export_dynamic_flag_spec='${wl}-Blargedynsym' - runpath_var=LD_RUN_PATH - ;; - siemens) - need_lib_prefix=no - ;; - motorola) - need_lib_prefix=no - need_version=no - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' - ;; - esac - ;; - -sysv4*MP*) - if test -d /usr/nec ;then - version_type=linux - library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' - soname_spec='$libname${shared_ext}.$major' - shlibpath_var=LD_LIBRARY_PATH - fi - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - version_type=freebsd-elf - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - hardcode_into_libs=yes - if test "$with_gnu_ld" = yes; then - sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' - shlibpath_overrides_runpath=no - else - sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' - shlibpath_overrides_runpath=yes - case $host_os in - sco3.2v5*) - sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" - ;; - esac - fi - sys_lib_dlsearch_path_spec='/usr/lib' - ;; - -uts4*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -*) - dynamic_linker=no - ;; -esac -{ echo "$as_me:$LINENO: result: $dynamic_linker" >&5 -echo "${ECHO_T}$dynamic_linker" >&6; } -test "$dynamic_linker" = no && can_build_shared=no - -variables_saved_for_relink="PATH $shlibpath_var $runpath_var" -if test "$GCC" = yes; then - variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" -fi - -{ echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 -echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6; } -hardcode_action= -if test -n "$hardcode_libdir_flag_spec" || \ - test -n "$runpath_var" || \ - test "X$hardcode_automatic" = "Xyes" ; then - - # We can hardcode non-existant directories. - if test "$hardcode_direct" != no && - # If the only mechanism to avoid hardcoding is shlibpath_var, we - # have to relink, otherwise we might link with an installed library - # when we should be linking with a yet-to-be-installed one - ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, )" != no && - test "$hardcode_minus_L" != no; then - # Linking always hardcodes the temporary library directory. - hardcode_action=relink - else - # We can link without hardcoding, and we can hardcode nonexisting dirs. - hardcode_action=immediate - fi -else - # We cannot hardcode anything, or else we can only hardcode existing - # directories. - hardcode_action=unsupported -fi -{ echo "$as_me:$LINENO: result: $hardcode_action" >&5 -echo "${ECHO_T}$hardcode_action" >&6; } - -if test "$hardcode_action" = relink; then - # Fast installation is not supported - enable_fast_install=no -elif test "$shlibpath_overrides_runpath" = yes || - test "$enable_shared" = no; then - # Fast installation is not necessary - enable_fast_install=needless -fi - -striplib= -old_striplib= -{ echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5 -echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6; } -if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then - test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" - test -z "$striplib" && striplib="$STRIP --strip-unneeded" - { echo "$as_me:$LINENO: result: yes" >&5 -echo "${ECHO_T}yes" >&6; } -else -# FIXME - insert some real tests, host_os isn't really good enough - case $host_os in - darwin*) - if test -n "$STRIP" ; then - striplib="$STRIP -x" - old_striplib="$STRIP -S" - { echo "$as_me:$LINENO: result: yes" >&5 -echo "${ECHO_T}yes" >&6; } - else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi - ;; - *) - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } - ;; - esac -fi - -if test "x$enable_dlopen" != xyes; then - enable_dlopen=unknown - enable_dlopen_self=unknown - enable_dlopen_self_static=unknown -else - lt_cv_dlopen=no - lt_cv_dlopen_libs= - - case $host_os in - beos*) - lt_cv_dlopen="load_add_on" - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; - - mingw* | pw32*) - lt_cv_dlopen="LoadLibrary" - lt_cv_dlopen_libs= - ;; - - cygwin*) - lt_cv_dlopen="dlopen" - lt_cv_dlopen_libs= - ;; - - darwin*) - # if libdl is installed we need to link against it - { echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 -echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6; } -if test "${ac_cv_lib_dl_dlopen+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - ac_cv_lib_dl_dlopen=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_dl_dlopen=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 -echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6; } -if test $ac_cv_lib_dl_dlopen = yes; then - lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" -else - - lt_cv_dlopen="dyld" - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - -fi - - ;; - - *) - { echo "$as_me:$LINENO: checking for shl_load" >&5 -echo $ECHO_N "checking for shl_load... $ECHO_C" >&6; } -if test "${ac_cv_func_shl_load+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -/* Define shl_load to an innocuous variant, in case declares shl_load. - For example, HP-UX 11i declares gettimeofday. */ -#define shl_load innocuous_shl_load - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char shl_load (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef shl_load - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char shl_load (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_shl_load || defined __stub___shl_load -choke me -#endif - -int -main () -{ -return shl_load (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - ac_cv_func_shl_load=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_func_shl_load=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -fi -{ echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5 -echo "${ECHO_T}$ac_cv_func_shl_load" >&6; } -if test $ac_cv_func_shl_load = yes; then - lt_cv_dlopen="shl_load" -else - { echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 -echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6; } -if test "${ac_cv_lib_dld_shl_load+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char shl_load (); -int -main () -{ -return shl_load (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - ac_cv_lib_dld_shl_load=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_dld_shl_load=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 -echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6; } -if test $ac_cv_lib_dld_shl_load = yes; then - lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld" -else - { echo "$as_me:$LINENO: checking for dlopen" >&5 -echo $ECHO_N "checking for dlopen... $ECHO_C" >&6; } -if test "${ac_cv_func_dlopen+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -/* Define dlopen to an innocuous variant, in case declares dlopen. - For example, HP-UX 11i declares gettimeofday. */ -#define dlopen innocuous_dlopen - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char dlopen (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef dlopen - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_dlopen || defined __stub___dlopen -choke me -#endif - -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - ac_cv_func_dlopen=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_func_dlopen=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -fi -{ echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5 -echo "${ECHO_T}$ac_cv_func_dlopen" >&6; } -if test $ac_cv_func_dlopen = yes; then - lt_cv_dlopen="dlopen" -else - { echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 -echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6; } -if test "${ac_cv_lib_dl_dlopen+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - ac_cv_lib_dl_dlopen=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_dl_dlopen=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 -echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6; } -if test $ac_cv_lib_dl_dlopen = yes; then - lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" -else - { echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5 -echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6; } -if test "${ac_cv_lib_svld_dlopen+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lsvld $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - ac_cv_lib_svld_dlopen=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_svld_dlopen=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5 -echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6; } -if test $ac_cv_lib_svld_dlopen = yes; then - lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" -else - { echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5 -echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6; } -if test "${ac_cv_lib_dld_dld_link+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dld_link (); -int -main () -{ -return dld_link (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - ac_cv_lib_dld_dld_link=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_dld_dld_link=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5 -echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6; } -if test $ac_cv_lib_dld_dld_link = yes; then - lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld" -fi - - -fi - - -fi - - -fi - - -fi - - -fi - - ;; - esac - - if test "x$lt_cv_dlopen" != xno; then - enable_dlopen=yes - else - enable_dlopen=no - fi - - case $lt_cv_dlopen in - dlopen) - save_CPPFLAGS="$CPPFLAGS" - test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" - - save_LDFLAGS="$LDFLAGS" - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" - - save_LIBS="$LIBS" - LIBS="$lt_cv_dlopen_libs $LIBS" - - { echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5 -echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6; } -if test "${lt_cv_dlopen_self+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test "$cross_compiling" = yes; then : - lt_cv_dlopen_self=cross -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext < -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -#ifdef __cplusplus -extern "C" void exit (int); -#endif - -void fnord() { int i=42;} -int main () -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - /* dlclose (self); */ - } - else - puts (dlerror ()); - - exit (status); -} -EOF - if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then - (./conftest; exit; ) >&5 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; - x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; - x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; - esac - else : - # compilation failed - lt_cv_dlopen_self=no - fi -fi -rm -fr conftest* - - -fi -{ echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5 -echo "${ECHO_T}$lt_cv_dlopen_self" >&6; } - - if test "x$lt_cv_dlopen_self" = xyes; then - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" - { echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5 -echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6; } -if test "${lt_cv_dlopen_self_static+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test "$cross_compiling" = yes; then : - lt_cv_dlopen_self_static=cross -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext < -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -#ifdef __cplusplus -extern "C" void exit (int); -#endif - -void fnord() { int i=42;} -int main () -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - /* dlclose (self); */ - } - else - puts (dlerror ()); - - exit (status); -} -EOF - if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then - (./conftest; exit; ) >&5 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; - x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; - x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; - esac - else : - # compilation failed - lt_cv_dlopen_self_static=no - fi -fi -rm -fr conftest* - - -fi -{ echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5 -echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6; } - fi - - CPPFLAGS="$save_CPPFLAGS" - LDFLAGS="$save_LDFLAGS" - LIBS="$save_LIBS" - ;; - esac - - case $lt_cv_dlopen_self in - yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; - *) enable_dlopen_self=unknown ;; - esac - - case $lt_cv_dlopen_self_static in - yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; - *) enable_dlopen_self_static=unknown ;; - esac -fi - - -# Report which library types will actually be built -{ echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5 -echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6; } -{ echo "$as_me:$LINENO: result: $can_build_shared" >&5 -echo "${ECHO_T}$can_build_shared" >&6; } - -{ echo "$as_me:$LINENO: checking whether to build shared libraries" >&5 -echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6; } -test "$can_build_shared" = "no" && enable_shared=no - -# On AIX, shared libraries and static libraries use the same namespace, and -# are all built from PIC. -case $host_os in -aix3*) - test "$enable_shared" = yes && enable_static=no - if test -n "$RANLIB"; then - archive_cmds="$archive_cmds~\$RANLIB \$lib" - postinstall_cmds='$RANLIB $lib' - fi - ;; - -aix4* | aix5*) - if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then - test "$enable_shared" = yes && enable_static=no - fi - ;; -esac -{ echo "$as_me:$LINENO: result: $enable_shared" >&5 -echo "${ECHO_T}$enable_shared" >&6; } - -{ echo "$as_me:$LINENO: checking whether to build static libraries" >&5 -echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6; } -# Make sure either enable_shared or enable_static is yes. -test "$enable_shared" = yes || enable_static=yes -{ echo "$as_me:$LINENO: result: $enable_static" >&5 -echo "${ECHO_T}$enable_static" >&6; } - -# The else clause should only fire when bootstrapping the -# libtool distribution, otherwise you forgot to ship ltmain.sh -# with your package, and you will get complaints that there are -# no rules to generate ltmain.sh. -if test -f "$ltmain"; then - # See if we are running on zsh, and set the options which allow our commands through - # without removal of \ escapes. - if test -n "${ZSH_VERSION+set}" ; then - setopt NO_GLOB_SUBST - fi - # Now quote all the things that may contain metacharacters while being - # careful not to overquote the AC_SUBSTed values. We take copies of the - # variables and quote the copies for generation of the libtool script. - for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ - SED SHELL STRIP \ - libname_spec library_names_spec soname_spec extract_expsyms_cmds \ - old_striplib striplib file_magic_cmd finish_cmds finish_eval \ - deplibs_check_method reload_flag reload_cmds need_locks \ - lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ - lt_cv_sys_global_symbol_to_c_name_address \ - sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ - old_postinstall_cmds old_postuninstall_cmds \ - compiler \ - CC \ - LD \ - lt_prog_compiler_wl \ - lt_prog_compiler_pic \ - lt_prog_compiler_static \ - lt_prog_compiler_no_builtin_flag \ - export_dynamic_flag_spec \ - thread_safe_flag_spec \ - whole_archive_flag_spec \ - enable_shared_with_static_runtimes \ - old_archive_cmds \ - old_archive_from_new_cmds \ - predep_objects \ - postdep_objects \ - predeps \ - postdeps \ - compiler_lib_search_path \ - archive_cmds \ - archive_expsym_cmds \ - postinstall_cmds \ - postuninstall_cmds \ - old_archive_from_expsyms_cmds \ - allow_undefined_flag \ - no_undefined_flag \ - export_symbols_cmds \ - hardcode_libdir_flag_spec \ - hardcode_libdir_flag_spec_ld \ - hardcode_libdir_separator \ - hardcode_automatic \ - module_cmds \ - module_expsym_cmds \ - lt_cv_prog_compiler_c_o \ - fix_srcfile_path \ - exclude_expsyms \ - include_expsyms; do - - case $var in - old_archive_cmds | \ - old_archive_from_new_cmds | \ - archive_cmds | \ - archive_expsym_cmds | \ - module_cmds | \ - module_expsym_cmds | \ - old_archive_from_expsyms_cmds | \ - export_symbols_cmds | \ - extract_expsyms_cmds | reload_cmds | finish_cmds | \ - postinstall_cmds | postuninstall_cmds | \ - old_postinstall_cmds | old_postuninstall_cmds | \ - sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) - # Double-quote double-evaled strings. - eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" - ;; - *) - eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" - ;; - esac - done - - case $lt_echo in - *'\$0 --fallback-echo"') - lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` - ;; - esac - -cfgfile="${ofile}T" - trap "$rm \"$cfgfile\"; exit 1" 1 2 15 - $rm -f "$cfgfile" - { echo "$as_me:$LINENO: creating $ofile" >&5 -echo "$as_me: creating $ofile" >&6;} - - cat <<__EOF__ >> "$cfgfile" -#! $SHELL - -# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. -# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) -# NOTE: Changes made to this file will be lost: look at ltmain.sh. -# -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 -# Free Software Foundation, Inc. -# -# This file is part of GNU Libtool: -# Originally by Gordon Matzigkeit , 1996 -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# A sed program that does not truncate output. -SED=$lt_SED - -# Sed that helps us avoid accidentally triggering echo(1) options like -n. -Xsed="$SED -e 1s/^X//" - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -# The names of the tagged configurations supported by this script. -available_tags= - -# ### BEGIN LIBTOOL CONFIG - -# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: - -# Shell to use when invoking shell scripts. -SHELL=$lt_SHELL - -# Whether or not to build shared libraries. -build_libtool_libs=$enable_shared - -# Whether or not to build static libraries. -build_old_libs=$enable_static - -# Whether or not to add -lc for building shared libraries. -build_libtool_need_lc=$archive_cmds_need_lc - -# Whether or not to disallow shared libs when runtime libs are static -allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes - -# Whether or not to optimize for fast installation. -fast_install=$enable_fast_install - -# The host system. -host_alias=$host_alias -host=$host -host_os=$host_os - -# The build system. -build_alias=$build_alias -build=$build -build_os=$build_os - -# An echo program that does not interpret backslashes. -echo=$lt_echo - -# The archiver. -AR=$lt_AR -AR_FLAGS=$lt_AR_FLAGS - -# A C compiler. -LTCC=$lt_LTCC - -# LTCC compiler flags. -LTCFLAGS=$lt_LTCFLAGS - -# A language-specific compiler. -CC=$lt_compiler - -# Is the compiler the GNU C compiler? -with_gcc=$GCC - -# An ERE matcher. -EGREP=$lt_EGREP - -# The linker used to build libraries. -LD=$lt_LD - -# Whether we need hard or soft links. -LN_S=$lt_LN_S - -# A BSD-compatible nm program. -NM=$lt_NM - -# A symbol stripping program -STRIP=$lt_STRIP - -# Used to examine libraries when file_magic_cmd begins "file" -MAGIC_CMD=$MAGIC_CMD - -# Used on cygwin: DLL creation program. -DLLTOOL="$DLLTOOL" - -# Used on cygwin: object dumper. -OBJDUMP="$OBJDUMP" - -# Used on cygwin: assembler. -AS="$AS" - -# The name of the directory that contains temporary libtool files. -objdir=$objdir - -# How to create reloadable object files. -reload_flag=$lt_reload_flag -reload_cmds=$lt_reload_cmds - -# How to pass a linker flag through the compiler. -wl=$lt_lt_prog_compiler_wl - -# Object file suffix (normally "o"). -objext="$ac_objext" - -# Old archive suffix (normally "a"). -libext="$libext" - -# Shared library suffix (normally ".so"). -shrext_cmds='$shrext_cmds' - -# Executable file suffix (normally ""). -exeext="$exeext" - -# Additional compiler flags for building library objects. -pic_flag=$lt_lt_prog_compiler_pic -pic_mode=$pic_mode - -# What is the maximum length of a command? -max_cmd_len=$lt_cv_sys_max_cmd_len - -# Does compiler simultaneously support -c and -o options? -compiler_c_o=$lt_lt_cv_prog_compiler_c_o - -# Must we lock files when doing compilation? -need_locks=$lt_need_locks - -# Do we need the lib prefix for modules? -need_lib_prefix=$need_lib_prefix - -# Do we need a version for libraries? -need_version=$need_version - -# Whether dlopen is supported. -dlopen_support=$enable_dlopen - -# Whether dlopen of programs is supported. -dlopen_self=$enable_dlopen_self - -# Whether dlopen of statically linked programs is supported. -dlopen_self_static=$enable_dlopen_self_static - -# Compiler flag to prevent dynamic linking. -link_static_flag=$lt_lt_prog_compiler_static - -# Compiler flag to turn off builtin functions. -no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec=$lt_export_dynamic_flag_spec - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec=$lt_whole_archive_flag_spec - -# Compiler flag to generate thread-safe objects. -thread_safe_flag_spec=$lt_thread_safe_flag_spec - -# Library versioning type. -version_type=$version_type - -# Format of library name prefix. -libname_spec=$lt_libname_spec - -# List of archive names. First name is the real one, the rest are links. -# The last name is the one that the linker finds with -lNAME. -library_names_spec=$lt_library_names_spec - -# The coded name of the library, if different from the real name. -soname_spec=$lt_soname_spec - -# Commands used to build and install an old-style archive. -RANLIB=$lt_RANLIB -old_archive_cmds=$lt_old_archive_cmds -old_postinstall_cmds=$lt_old_postinstall_cmds -old_postuninstall_cmds=$lt_old_postuninstall_cmds - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds=$lt_old_archive_from_new_cmds - -# Create a temporary old-style archive to link instead of a shared archive. -old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds - -# Commands used to build and install a shared archive. -archive_cmds=$lt_archive_cmds -archive_expsym_cmds=$lt_archive_expsym_cmds -postinstall_cmds=$lt_postinstall_cmds -postuninstall_cmds=$lt_postuninstall_cmds - -# Commands used to build a loadable module (assumed same as above if empty) -module_cmds=$lt_module_cmds -module_expsym_cmds=$lt_module_expsym_cmds - -# Commands to strip libraries. -old_striplib=$lt_old_striplib -striplib=$lt_striplib - -# Dependencies to place before the objects being linked to create a -# shared library. -predep_objects=$lt_predep_objects - -# Dependencies to place after the objects being linked to create a -# shared library. -postdep_objects=$lt_postdep_objects - -# Dependencies to place before the objects being linked to create a -# shared library. -predeps=$lt_predeps - -# Dependencies to place after the objects being linked to create a -# shared library. -postdeps=$lt_postdeps - -# The library search path used internally by the compiler when linking -# a shared library. -compiler_lib_search_path=$lt_compiler_lib_search_path - -# Method to check whether dependent libraries are shared objects. -deplibs_check_method=$lt_deplibs_check_method - -# Command to use when deplibs_check_method == file_magic. -file_magic_cmd=$lt_file_magic_cmd - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag=$lt_allow_undefined_flag - -# Flag that forces no undefined symbols. -no_undefined_flag=$lt_no_undefined_flag - -# Commands used to finish a libtool library installation in a directory. -finish_cmds=$lt_finish_cmds - -# Same as above, but a single script fragment to be evaled but not shown. -finish_eval=$lt_finish_eval - -# Take the output of nm and produce a listing of raw symbols and C names. -global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe - -# Transform the output of nm in a proper C declaration -global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl - -# Transform the output of nm in a C name address pair -global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address - -# This is the shared library runtime path variable. -runpath_var=$runpath_var - -# This is the shared library path variable. -shlibpath_var=$shlibpath_var - -# Is shlibpath searched before the hard-coded library search path? -shlibpath_overrides_runpath=$shlibpath_overrides_runpath - -# How to hardcode a shared library path into an executable. -hardcode_action=$hardcode_action - -# Whether we should hardcode library paths into libraries. -hardcode_into_libs=$hardcode_into_libs - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist. -hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec - -# If ld is used when linking, flag to hardcode \$libdir into -# a binary during linking. This must work even if \$libdir does -# not exist. -hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld - -# Whether we need a single -rpath flag with a separated argument. -hardcode_libdir_separator=$lt_hardcode_libdir_separator - -# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the -# resulting binary. -hardcode_direct=$hardcode_direct - -# Set to yes if using the -LDIR flag during linking hardcodes DIR into the -# resulting binary. -hardcode_minus_L=$hardcode_minus_L - -# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into -# the resulting binary. -hardcode_shlibpath_var=$hardcode_shlibpath_var - -# Set to yes if building a shared library automatically hardcodes DIR into the library -# and all subsequent libraries and executables linked against it. -hardcode_automatic=$hardcode_automatic - -# Variables whose values should be saved in libtool wrapper scripts and -# restored at relink time. -variables_saved_for_relink="$variables_saved_for_relink" - -# Whether libtool must link a program against all its dependency libraries. -link_all_deplibs=$link_all_deplibs - -# Compile-time system search path for libraries -sys_lib_search_path_spec=$lt_sys_lib_search_path_spec - -# Run-time system search path for libraries -sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec - -# Fix the shell variable \$srcfile for the compiler. -fix_srcfile_path=$lt_fix_srcfile_path - -# Set to yes if exported symbols are required. -always_export_symbols=$always_export_symbols - -# The commands to list exported symbols. -export_symbols_cmds=$lt_export_symbols_cmds - -# The commands to extract the exported symbol list from a shared archive. -extract_expsyms_cmds=$lt_extract_expsyms_cmds - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms=$lt_exclude_expsyms - -# Symbols that must always be exported. -include_expsyms=$lt_include_expsyms - -# ### END LIBTOOL CONFIG - -__EOF__ - - - case $host_os in - aix3*) - cat <<\EOF >> "$cfgfile" - -# AIX sometimes has problems with the GCC collect2 program. For some -# reason, if we set the COLLECT_NAMES environment variable, the problems -# vanish in a puff of smoke. -if test "X${COLLECT_NAMES+set}" != Xset; then - COLLECT_NAMES= - export COLLECT_NAMES -fi -EOF - ;; - esac - - # We use sed instead of cat because bash on DJGPP gets confused if - # if finds mixed CR/LF and LF-only lines. Since sed operates in - # text mode, it properly converts lines to CR/LF. This bash problem - # is reportedly fixed, but why not run on old versions too? - sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) - - mv -f "$cfgfile" "$ofile" || \ - (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") - chmod +x "$ofile" - -else - # If there is no Makefile yet, we rely on a make rule to execute - # `config.status --recheck' to rerun these tests and create the - # libtool script then. - ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` - if test -f "$ltmain_in"; then - test -f Makefile && make "$ltmain" - fi -fi - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -CC="$lt_save_CC" - - -# Check whether --with-tags was given. -if test "${with_tags+set}" = set; then - withval=$with_tags; tagnames="$withval" -fi - - -if test -f "$ltmain" && test -n "$tagnames"; then - if test ! -f "${ofile}"; then - { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not exist" >&5 -echo "$as_me: WARNING: output file \`$ofile' does not exist" >&2;} - fi - - if test -z "$LTCC"; then - eval "`$SHELL ${ofile} --config | grep '^LTCC='`" - if test -z "$LTCC"; then - { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not look like a libtool script" >&5 -echo "$as_me: WARNING: output file \`$ofile' does not look like a libtool script" >&2;} - else - { echo "$as_me:$LINENO: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&5 -echo "$as_me: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&2;} - fi - fi - if test -z "$LTCFLAGS"; then - eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`" - fi - - # Extract list of available tagged configurations in $ofile. - # Note that this assumes the entire list is on one line. - available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` - - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for tagname in $tagnames; do - IFS="$lt_save_ifs" - # Check whether tagname contains only valid characters - case `$echo "X$tagname" | $Xsed -e 's:[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]::g'` in - "") ;; - *) { { echo "$as_me:$LINENO: error: invalid tag name: $tagname" >&5 -echo "$as_me: error: invalid tag name: $tagname" >&2;} - { (exit 1); exit 1; }; } - ;; - esac - - if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null - then - { { echo "$as_me:$LINENO: error: tag name \"$tagname\" already exists" >&5 -echo "$as_me: error: tag name \"$tagname\" already exists" >&2;} - { (exit 1); exit 1; }; } - fi - - # Update the list of available tags. - if test -n "$tagname"; then - echo appending configuration tag \"$tagname\" to $ofile - - case $tagname in - CXX) - if test -n "$CXX" && ( test "X$CXX" != "Xno" && - ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || - (test "X$CXX" != "Xg++"))) ; then - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - - - -archive_cmds_need_lc_CXX=no -allow_undefined_flag_CXX= -always_export_symbols_CXX=no -archive_expsym_cmds_CXX= -export_dynamic_flag_spec_CXX= -hardcode_direct_CXX=no -hardcode_libdir_flag_spec_CXX= -hardcode_libdir_flag_spec_ld_CXX= -hardcode_libdir_separator_CXX= -hardcode_minus_L_CXX=no -hardcode_shlibpath_var_CXX=unsupported -hardcode_automatic_CXX=no -module_cmds_CXX= -module_expsym_cmds_CXX= -link_all_deplibs_CXX=unknown -old_archive_cmds_CXX=$old_archive_cmds -no_undefined_flag_CXX= -whole_archive_flag_spec_CXX= -enable_shared_with_static_runtimes_CXX=no - -# Dependencies to place before and after the object being linked: -predep_objects_CXX= -postdep_objects_CXX= -predeps_CXX= -postdeps_CXX= -compiler_lib_search_path_CXX= - -# Source file extension for C++ test sources. -ac_ext=cpp - -# Object file extension for compiled C++ test sources. -objext=o -objext_CXX=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="int some_variable = 0;" - -# Code to be used in simple link tests -lt_simple_link_test_code='int main(int, char *[]) { return(0); }' - -# ltmain only uses $CC for tagged configurations so make sure $CC is set. - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - - -# save warnings/boilerplate of simple test code -ac_outfile=conftest.$ac_objext -echo "$lt_simple_compile_test_code" >conftest.$ac_ext -eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_compiler_boilerplate=`cat conftest.err` -$rm conftest* - -ac_outfile=conftest.$ac_objext -echo "$lt_simple_link_test_code" >conftest.$ac_ext -eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_linker_boilerplate=`cat conftest.err` -$rm conftest* - - -# Allow CC to be a program name with arguments. -lt_save_CC=$CC -lt_save_LD=$LD -lt_save_GCC=$GCC -GCC=$GXX -lt_save_with_gnu_ld=$with_gnu_ld -lt_save_path_LD=$lt_cv_path_LD -if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then - lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx -else - $as_unset lt_cv_prog_gnu_ld -fi -if test -n "${lt_cv_path_LDCXX+set}"; then - lt_cv_path_LD=$lt_cv_path_LDCXX -else - $as_unset lt_cv_path_LD -fi -test -z "${LDCXX+set}" || LD=$LDCXX -CC=${CXX-"c++"} -compiler=$CC -compiler_CXX=$CC -for cc_temp in $compiler""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac -done -cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` - - -# We don't want -fno-exception wen compiling C++ code, so set the -# no_builtin_flag separately -if test "$GXX" = yes; then - lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' -else - lt_prog_compiler_no_builtin_flag_CXX= -fi - -if test "$GXX" = yes; then - # Set up default GNU C++ configuration - - -# Check whether --with-gnu-ld was given. -if test "${with_gnu_ld+set}" = set; then - withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes -else - with_gnu_ld=no -fi - -ac_prog=ld -if test "$GCC" = yes; then - # Check if gcc -print-prog-name=ld gives a path. - { echo "$as_me:$LINENO: checking for ld used by $CC" >&5 -echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6; } - case $host in - *-*-mingw*) - # gcc leaves a trailing carriage return which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [\\/]* | ?:[\\/]*) - re_direlt='/[^/][^/]*/\.\./' - # Canonicalize the pathname of ld - ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` - while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do - ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` - done - test -z "$LD" && LD="$ac_prog" - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test "$with_gnu_ld" = yes; then - { echo "$as_me:$LINENO: checking for GNU ld" >&5 -echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6; } -else - { echo "$as_me:$LINENO: checking for non-GNU ld" >&5 -echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6; } -fi -if test "${lt_cv_path_LD+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -z "$LD"; then - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - lt_cv_path_LD="$ac_dir/$ac_prog" - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some variants of GNU ld only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$lt_cv_path_LD" -v 2>&1 &5 -echo "${ECHO_T}$LD" >&6; } -else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } -fi -test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 -echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} - { (exit 1); exit 1; }; } -{ echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 -echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6; } -if test "${lt_cv_prog_gnu_ld+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - # I'd rather use --version here, but apparently some GNU lds only accept -v. -case `$LD -v 2>&1 &5 -echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6; } -with_gnu_ld=$lt_cv_prog_gnu_ld - - - - # Check if GNU C++ uses GNU ld as the underlying linker, since the - # archiving commands below assume that GNU ld is being used. - if test "$with_gnu_ld" = yes; then - archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - - hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' - export_dynamic_flag_spec_CXX='${wl}--export-dynamic' - - # If archive_cmds runs LD, not CC, wlarc should be empty - # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to - # investigate it a little bit more. (MM) - wlarc='${wl}' - - # ancient GNU ld didn't support --whole-archive et. al. - if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ - grep 'no-whole-archive' > /dev/null; then - whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - else - whole_archive_flag_spec_CXX= - fi - else - with_gnu_ld=no - wlarc= - - # A generic and very simple default shared library creation - # command for GNU C++ for the case where it uses the native - # linker, instead of GNU ld. If possible, this setting should - # overridden to take advantage of the native linker features on - # the platform it is being used on. - archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' - fi - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' - -else - GXX=no - with_gnu_ld=no - wlarc= -fi - -# PORTME: fill in a description of your system's C++ link characteristics -{ echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 -echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6; } -ld_shlibs_CXX=yes -case $host_os in - aix3*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - aix4* | aix5*) - if test "$host_cpu" = ia64; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag="" - else - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # need to do runtime linking. - case $host_os in aix4.[23]|aix4.[23].*|aix5*) - for ld_flag in $LDFLAGS; do - case $ld_flag in - *-brtl*) - aix_use_runtimelinking=yes - break - ;; - esac - done - ;; - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - archive_cmds_CXX='' - hardcode_direct_CXX=yes - hardcode_libdir_separator_CXX=':' - link_all_deplibs_CXX=yes - - if test "$GXX" = yes; then - case $host_os in aix4.[012]|aix4.[012].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`${CC} -print-prog-name=collect2` - if test -f "$collect2name" && \ - strings "$collect2name" | grep resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - hardcode_direct_CXX=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - hardcode_minus_L_CXX=yes - hardcode_libdir_flag_spec_CXX='-L$libdir' - hardcode_libdir_separator_CXX= - fi - ;; - esac - shared_flag='-shared' - if test "$aix_use_runtimelinking" = yes; then - shared_flag="$shared_flag "'${wl}-G' - fi - else - # not using gcc - if test "$host_cpu" = ia64; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test "$aix_use_runtimelinking" = yes; then - shared_flag='${wl}-G' - else - shared_flag='${wl}-bM:SRE' - fi - fi - fi - - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to export. - always_export_symbols_CXX=yes - if test "$aix_use_runtimelinking" = yes; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - allow_undefined_flag_CXX='-berok' - # Determine the default libpath from the value encoded in an empty executable. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_cxx_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - -lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\(.*\)$/\1/ - p - } - }' -aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -# Check for a 64-bit object if we didn't find anything. -if test -z "$aix_libpath"; then - aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -fi -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi - - hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" - - archive_expsym_cmds_CXX="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" - else - if test "$host_cpu" = ia64; then - hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' - allow_undefined_flag_CXX="-z nodefs" - archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an empty executable. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_cxx_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - -lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\(.*\)$/\1/ - p - } - }' -aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -# Check for a 64-bit object if we didn't find anything. -if test -z "$aix_libpath"; then - aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -fi -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi - - hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - no_undefined_flag_CXX=' ${wl}-bernotok' - allow_undefined_flag_CXX=' ${wl}-berok' - # Exported symbols can be pulled into shared objects from archives - whole_archive_flag_spec_CXX='$convenience' - archive_cmds_need_lc_CXX=yes - # This is similar to how AIX traditionally builds its shared libraries. - archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' - fi - fi - ;; - - beos*) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - allow_undefined_flag_CXX=unsupported - # Joseph Beckenbach says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - else - ld_shlibs_CXX=no - fi - ;; - - chorus*) - case $cc_basename in - *) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - esac - ;; - - cygwin* | mingw* | pw32*) - # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, - # as there is no search path for DLLs. - hardcode_libdir_flag_spec_CXX='-L$libdir' - allow_undefined_flag_CXX=unsupported - always_export_symbols_CXX=no - enable_shared_with_static_runtimes_CXX=yes - - if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then - archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file (1st line - # is EXPORTS), use it as is; otherwise, prepend... - archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - else - ld_shlibs_CXX=no - fi - ;; - darwin* | rhapsody*) - case $host_os in - rhapsody* | darwin1.[012]) - allow_undefined_flag_CXX='${wl}-undefined ${wl}suppress' - ;; - *) # Darwin 1.3 on - if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then - allow_undefined_flag_CXX='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' - else - case ${MACOSX_DEPLOYMENT_TARGET} in - 10.[012]) - allow_undefined_flag_CXX='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' - ;; - 10.*) - allow_undefined_flag_CXX='${wl}-undefined ${wl}dynamic_lookup' - ;; - esac - fi - ;; - esac - archive_cmds_need_lc_CXX=no - hardcode_direct_CXX=no - hardcode_automatic_CXX=yes - hardcode_shlibpath_var_CXX=unsupported - whole_archive_flag_spec_CXX='' - link_all_deplibs_CXX=yes - - if test "$GXX" = yes ; then - lt_int_apple_cc_single_mod=no - output_verbose_link_cmd='echo' - if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then - lt_int_apple_cc_single_mod=yes - fi - if test "X$lt_int_apple_cc_single_mod" = Xyes ; then - archive_cmds_CXX='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' - else - archive_cmds_CXX='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' - fi - module_cmds_CXX='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' - # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds - if test "X$lt_int_apple_cc_single_mod" = Xyes ; then - archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - else - archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - fi - module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - else - case $cc_basename in - xlc*) - output_verbose_link_cmd='echo' - archive_cmds_CXX='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring' - module_cmds_CXX='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' - # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds - archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - ;; - *) - ld_shlibs_CXX=no - ;; - esac - fi - ;; - - dgux*) - case $cc_basename in - ec++*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - ghcx*) - # Green Hills C++ Compiler - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - *) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - esac - ;; - freebsd[12]*) - # C++ shared libraries reported to be fairly broken before switch to ELF - ld_shlibs_CXX=no - ;; - freebsd-elf*) - archive_cmds_need_lc_CXX=no - ;; - freebsd* | dragonfly*) - # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF - # conventions - ld_shlibs_CXX=yes - ;; - gnu*) - ;; - hpux9*) - hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' - hardcode_libdir_separator_CXX=: - export_dynamic_flag_spec_CXX='${wl}-E' - hardcode_direct_CXX=yes - hardcode_minus_L_CXX=yes # Not in the search PATH, - # but as the default - # location of the library. - - case $cc_basename in - CC*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - aCC*) - archive_cmds_CXX='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[-]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' - ;; - *) - if test "$GXX" = yes; then - archive_cmds_CXX='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - else - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - fi - ;; - esac - ;; - hpux10*|hpux11*) - if test $with_gnu_ld = no; then - hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' - hardcode_libdir_separator_CXX=: - - case $host_cpu in - hppa*64*|ia64*) ;; - *) - export_dynamic_flag_spec_CXX='${wl}-E' - ;; - esac - fi - case $host_cpu in - hppa*64*|ia64*) - hardcode_direct_CXX=no - hardcode_shlibpath_var_CXX=no - ;; - *) - hardcode_direct_CXX=yes - hardcode_minus_L_CXX=yes # Not in the search PATH, - # but as the default - # location of the library. - ;; - esac - - case $cc_basename in - CC*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - aCC*) - case $host_cpu in - hppa*64*) - archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - ia64*) - archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - *) - archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - esac - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' - ;; - *) - if test "$GXX" = yes; then - if test $with_gnu_ld = no; then - case $host_cpu in - hppa*64*) - archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - ia64*) - archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - *) - archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - esac - fi - else - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - fi - ;; - esac - ;; - interix[3-9]*) - hardcode_direct_CXX=no - hardcode_shlibpath_var_CXX=no - hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' - export_dynamic_flag_spec_CXX='${wl}-E' - # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. - # Instead, shared libraries are loaded at an image base (0x10000000 by - # default) and relocated if they conflict, which is a slow very memory - # consuming and fragmenting process. To avoid this, we pick a random, - # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link - # time. Moving up from 0x10000000 also allows more sbrk(2) space. - archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - ;; - irix5* | irix6*) - case $cc_basename in - CC*) - # SGI C++ - archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - - # Archives containing C++ object files must be created using - # "CC -ar", where "CC" is the IRIX C++ compiler. This is - # necessary to make sure instantiated templates are included - # in the archive. - old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' - ;; - *) - if test "$GXX" = yes; then - if test "$with_gnu_ld" = no; then - archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - else - archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' - fi - fi - link_all_deplibs_CXX=yes - ;; - esac - hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator_CXX=: - ;; - linux* | k*bsd*-gnu) - case $cc_basename in - KCC*) - # Kuck and Associates, Inc. (KAI) C++ Compiler - - # KCC will only create a shared library if the output file - # ends with ".so" (or ".sl" for HP-UX), so rename the library - # to its proper name (with version) after linking. - archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' - archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' - - hardcode_libdir_flag_spec_CXX='${wl}--rpath,$libdir' - export_dynamic_flag_spec_CXX='${wl}--export-dynamic' - - # Archives containing C++ object files must be created using - # "CC -Bstatic", where "CC" is the KAI C++ compiler. - old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' - ;; - icpc*) - # Intel C++ - with_gnu_ld=yes - # version 8.0 and above of icpc choke on multiply defined symbols - # if we add $predep_objects and $postdep_objects, however 7.1 and - # earlier do not add the objects themselves. - case `$CC -V 2>&1` in - *"Version 7."*) - archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - ;; - *) # Version 8.0 or newer - tmp_idyn= - case $host_cpu in - ia64*) tmp_idyn=' -i_dynamic';; - esac - archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - ;; - esac - archive_cmds_need_lc_CXX=no - hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' - export_dynamic_flag_spec_CXX='${wl}--export-dynamic' - whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' - ;; - pgCC*) - # Portland Group C++ compiler - archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' - archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' - - hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' - export_dynamic_flag_spec_CXX='${wl}--export-dynamic' - whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' - ;; - cxx*) - # Compaq C++ - archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' - - runpath_var=LD_RUN_PATH - hardcode_libdir_flag_spec_CXX='-rpath $libdir' - hardcode_libdir_separator_CXX=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) - # Sun C++ 5.9 - no_undefined_flag_CXX=' -zdefs' - archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' - hardcode_libdir_flag_spec_CXX='-R$libdir' - whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' - - # Not sure whether something based on - # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 - # would be better. - output_verbose_link_cmd='echo' - - # Archives containing C++ object files must be created using - # "CC -xar", where "CC" is the Sun C++ compiler. This is - # necessary to make sure instantiated templates are included - # in the archive. - old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' - ;; - esac - ;; - esac - ;; - lynxos*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - m88k*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - mvs*) - case $cc_basename in - cxx*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - *) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - esac - ;; - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' - wlarc= - hardcode_libdir_flag_spec_CXX='-R$libdir' - hardcode_direct_CXX=yes - hardcode_shlibpath_var_CXX=no - fi - # Workaround some broken pre-1.5 toolchains - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' - ;; - openbsd2*) - # C++ shared libraries are fairly broken - ld_shlibs_CXX=no - ;; - openbsd*) - if test -f /usr/libexec/ld.so; then - hardcode_direct_CXX=yes - hardcode_shlibpath_var_CXX=no - archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' - hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' - export_dynamic_flag_spec_CXX='${wl}-E' - whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - fi - output_verbose_link_cmd='echo' - else - ld_shlibs_CXX=no - fi - ;; - osf3*) - case $cc_basename in - KCC*) - # Kuck and Associates, Inc. (KAI) C++ Compiler - - # KCC will only create a shared library if the output file - # ends with ".so" (or ".sl" for HP-UX), so rename the library - # to its proper name (with version) after linking. - archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' - - hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' - hardcode_libdir_separator_CXX=: - - # Archives containing C++ object files must be created using - # "CC -Bstatic", where "CC" is the KAI C++ compiler. - old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' - - ;; - RCC*) - # Rational C++ 2.4.1 - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - cxx*) - allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - - hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator_CXX=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' - ;; - *) - if test "$GXX" = yes && test "$with_gnu_ld" = no; then - allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - - hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator_CXX=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' - - else - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - fi - ;; - esac - ;; - osf4* | osf5*) - case $cc_basename in - KCC*) - # Kuck and Associates, Inc. (KAI) C++ Compiler - - # KCC will only create a shared library if the output file - # ends with ".so" (or ".sl" for HP-UX), so rename the library - # to its proper name (with version) after linking. - archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' - - hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' - hardcode_libdir_separator_CXX=: - - # Archives containing C++ object files must be created using - # the KAI C++ compiler. - old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' - ;; - RCC*) - # Rational C++ 2.4.1 - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - cxx*) - allow_undefined_flag_CXX=' -expect_unresolved \*' - archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ - echo "-hidden">> $lib.exp~ - $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~ - $rm $lib.exp' - - hardcode_libdir_flag_spec_CXX='-rpath $libdir' - hardcode_libdir_separator_CXX=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' - ;; - *) - if test "$GXX" = yes && test "$with_gnu_ld" = no; then - allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - - hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator_CXX=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' - - else - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - fi - ;; - esac - ;; - psos*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - sunos4*) - case $cc_basename in - CC*) - # Sun C++ 4.x - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - lcc*) - # Lucid - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - *) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - esac - ;; - solaris*) - case $cc_basename in - CC*) - # Sun C++ 4.2, 5.x and Centerline C++ - archive_cmds_need_lc_CXX=yes - no_undefined_flag_CXX=' -zdefs' - archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' - - hardcode_libdir_flag_spec_CXX='-R$libdir' - hardcode_shlibpath_var_CXX=no - case $host_os in - solaris2.[0-5] | solaris2.[0-5].*) ;; - *) - # The compiler driver will combine and reorder linker options, - # but understands `-z linker_flag'. - # Supported since Solaris 2.6 (maybe 2.5.1?) - whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' - ;; - esac - link_all_deplibs_CXX=yes - - output_verbose_link_cmd='echo' - - # Archives containing C++ object files must be created using - # "CC -xar", where "CC" is the Sun C++ compiler. This is - # necessary to make sure instantiated templates are included - # in the archive. - old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' - ;; - gcx*) - # Green Hills C++ Compiler - archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' - - # The C++ compiler must be used to create the archive. - old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' - ;; - *) - # GNU C++ compiler with Solaris linker - if test "$GXX" = yes && test "$with_gnu_ld" = no; then - no_undefined_flag_CXX=' ${wl}-z ${wl}defs' - if $CC --version | grep -v '^2\.7' > /dev/null; then - archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' - archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" - else - # g++ 2.7 appears to require `-G' NOT `-shared' on this - # platform. - archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' - archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" - fi - - hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' - case $host_os in - solaris2.[0-5] | solaris2.[0-5].*) ;; - *) - whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' - ;; - esac - fi - ;; - esac - ;; - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) - no_undefined_flag_CXX='${wl}-z,text' - archive_cmds_need_lc_CXX=no - hardcode_shlibpath_var_CXX=no - runpath_var='LD_RUN_PATH' - - case $cc_basename in - CC*) - archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - ;; - sysv5* | sco3.2v5* | sco5v6*) - # Note: We can NOT use -z defs as we might desire, because we do not - # link with -lc, and that would cause any symbols used from libc to - # always be unresolved, which means just about no library would - # ever link correctly. If we're not using GNU ld we use -z text - # though, which does catch some bad symbols but isn't as heavy-handed - # as -z defs. - # For security reasons, it is highly recommended that you always - # use absolute paths for naming shared libraries, and exclude the - # DT_RUNPATH tag from executables and libraries. But doing so - # requires that you compile everything twice, which is a pain. - # So that behaviour is only enabled if SCOABSPATH is set to a - # non-empty value in the environment. Most likely only useful for - # creating official distributions of packages. - # This is a hack until libtool officially supports absolute path - # names for shared libraries. - no_undefined_flag_CXX='${wl}-z,text' - allow_undefined_flag_CXX='${wl}-z,nodefs' - archive_cmds_need_lc_CXX=no - hardcode_shlibpath_var_CXX=no - hardcode_libdir_flag_spec_CXX='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' - hardcode_libdir_separator_CXX=':' - link_all_deplibs_CXX=yes - export_dynamic_flag_spec_CXX='${wl}-Bexport' - runpath_var='LD_RUN_PATH' - - case $cc_basename in - CC*) - archive_cmds_CXX='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - archive_cmds_CXX='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - ;; - tandem*) - case $cc_basename in - NCC*) - # NonStop-UX NCC 3.20 - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - *) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - esac - ;; - vxworks*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - *) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; -esac -{ echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5 -echo "${ECHO_T}$ld_shlibs_CXX" >&6; } -test "$ld_shlibs_CXX" = no && can_build_shared=no - -GCC_CXX="$GXX" -LD_CXX="$LD" - -## CAVEAT EMPTOR: -## There is no encapsulation within the following macros, do not change -## the running order or otherwise move them around unless you know exactly -## what you are doing... - -cat > conftest.$ac_ext <&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then - # Parse the compiler output and extract the necessary - # objects, libraries and library flags. - - # Sentinel used to keep track of whether or not we are before - # the conftest object file. - pre_test_object_deps_done=no - - # The `*' in the case matches for architectures that use `case' in - # $output_verbose_cmd can trigger glob expansion during the loop - # eval without this substitution. - output_verbose_link_cmd=`$echo "X$output_verbose_link_cmd" | $Xsed -e "$no_glob_subst"` - - for p in `eval $output_verbose_link_cmd`; do - case $p in - - -L* | -R* | -l*) - # Some compilers place space between "-{L,R}" and the path. - # Remove the space. - if test $p = "-L" \ - || test $p = "-R"; then - prev=$p - continue - else - prev= - fi - - if test "$pre_test_object_deps_done" = no; then - case $p in - -L* | -R*) - # Internal compiler library paths should come after those - # provided the user. The postdeps already come after the - # user supplied libs so there is no need to process them. - if test -z "$compiler_lib_search_path_CXX"; then - compiler_lib_search_path_CXX="${prev}${p}" - else - compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" - fi - ;; - # The "-l" case would never come before the object being - # linked, so don't bother handling this case. - esac - else - if test -z "$postdeps_CXX"; then - postdeps_CXX="${prev}${p}" - else - postdeps_CXX="${postdeps_CXX} ${prev}${p}" - fi - fi - ;; - - *.$objext) - # This assumes that the test object file only shows up - # once in the compiler output. - if test "$p" = "conftest.$objext"; then - pre_test_object_deps_done=yes - continue - fi - - if test "$pre_test_object_deps_done" = no; then - if test -z "$predep_objects_CXX"; then - predep_objects_CXX="$p" - else - predep_objects_CXX="$predep_objects_CXX $p" - fi - else - if test -z "$postdep_objects_CXX"; then - postdep_objects_CXX="$p" - else - postdep_objects_CXX="$postdep_objects_CXX $p" - fi - fi - ;; - - *) ;; # Ignore the rest. - - esac - done - - # Clean up. - rm -f a.out a.exe -else - echo "libtool.m4: error: problem compiling CXX test program" -fi - -$rm -f confest.$objext - -# PORTME: override above test on systems where it is broken -case $host_os in -interix[3-9]*) - # Interix 3.5 installs completely hosed .la files for C++, so rather than - # hack all around it, let's just trust "g++" to DTRT. - predep_objects_CXX= - postdep_objects_CXX= - postdeps_CXX= - ;; - -linux*) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) - # Sun C++ 5.9 - # - # The more standards-conforming stlport4 library is - # incompatible with the Cstd library. Avoid specifying - # it if it's in CXXFLAGS. Ignore libCrun as - # -library=stlport4 depends on it. - case " $CXX $CXXFLAGS " in - *" -library=stlport4 "*) - solaris_use_stlport4=yes - ;; - esac - if test "$solaris_use_stlport4" != yes; then - postdeps_CXX='-library=Cstd -library=Crun' - fi - ;; - esac - ;; - -solaris*) - case $cc_basename in - CC*) - # The more standards-conforming stlport4 library is - # incompatible with the Cstd library. Avoid specifying - # it if it's in CXXFLAGS. Ignore libCrun as - # -library=stlport4 depends on it. - case " $CXX $CXXFLAGS " in - *" -library=stlport4 "*) - solaris_use_stlport4=yes - ;; - esac - - # Adding this requires a known-good setup of shared libraries for - # Sun compiler versions before 5.6, else PIC objects from an old - # archive will be linked into the output, leading to subtle bugs. - if test "$solaris_use_stlport4" != yes; then - postdeps_CXX='-library=Cstd -library=Crun' - fi - ;; - esac - ;; -esac - - -case " $postdeps_CXX " in -*" -lc "*) archive_cmds_need_lc_CXX=no ;; -esac - -lt_prog_compiler_wl_CXX= -lt_prog_compiler_pic_CXX= -lt_prog_compiler_static_CXX= - -{ echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 -echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6; } - - # C++ specific cases for pic, static, wl, etc. - if test "$GXX" = yes; then - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_static_CXX='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static_CXX='-Bstatic' - fi - ;; - amigaos*) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the `-m68020' flag to GCC prevents building anything better, - # like `-m68040'. - lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' - ;; - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - mingw* | cygwin* | os2* | pw32*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - lt_prog_compiler_pic_CXX='-DDLL_EXPORT' - ;; - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic_CXX='-fno-common' - ;; - *djgpp*) - # DJGPP does not support shared libraries at all - lt_prog_compiler_pic_CXX= - ;; - interix[3-9]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic_CXX=-Kconform_pic - fi - ;; - hpux*) - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - ;; - *) - lt_prog_compiler_pic_CXX='-fPIC' - ;; - esac - ;; - *) - lt_prog_compiler_pic_CXX='-fPIC' - ;; - esac - else - case $host_os in - aix4* | aix5*) - # All AIX code is PIC. - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static_CXX='-Bstatic' - else - lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' - fi - ;; - chorus*) - case $cc_basename in - cxch68*) - # Green Hills C++ Compiler - # _LT_AC_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" - ;; - esac - ;; - darwin*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - case $cc_basename in - xlc*) - lt_prog_compiler_pic_CXX='-qnocommon' - lt_prog_compiler_wl_CXX='-Wl,' - ;; - esac - ;; - dgux*) - case $cc_basename in - ec++*) - lt_prog_compiler_pic_CXX='-KPIC' - ;; - ghcx*) - # Green Hills C++ Compiler - lt_prog_compiler_pic_CXX='-pic' - ;; - *) - ;; - esac - ;; - freebsd* | dragonfly*) - # FreeBSD uses GNU C++ - ;; - hpux9* | hpux10* | hpux11*) - case $cc_basename in - CC*) - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' - if test "$host_cpu" != ia64; then - lt_prog_compiler_pic_CXX='+Z' - fi - ;; - aCC*) - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic_CXX='+Z' - ;; - esac - ;; - *) - ;; - esac - ;; - interix*) - # This is c89, which is MS Visual C++ (no shared libs) - # Anyone wants to do a port? - ;; - irix5* | irix6* | nonstopux*) - case $cc_basename in - CC*) - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_static_CXX='-non_shared' - # CC pic flag -KPIC is the default. - ;; - *) - ;; - esac - ;; - linux* | k*bsd*-gnu) - case $cc_basename in - KCC*) - # KAI C++ Compiler - lt_prog_compiler_wl_CXX='--backend -Wl,' - lt_prog_compiler_pic_CXX='-fPIC' - ;; - icpc* | ecpc*) - # Intel C++ - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_pic_CXX='-KPIC' - lt_prog_compiler_static_CXX='-static' - ;; - pgCC*) - # Portland Group C++ compiler. - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_pic_CXX='-fpic' - lt_prog_compiler_static_CXX='-Bstatic' - ;; - cxx*) - # Compaq C++ - # Make sure the PIC flag is empty. It appears that all Alpha - # Linux and Compaq Tru64 Unix objects are PIC. - lt_prog_compiler_pic_CXX= - lt_prog_compiler_static_CXX='-non_shared' - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) - # Sun C++ 5.9 - lt_prog_compiler_pic_CXX='-KPIC' - lt_prog_compiler_static_CXX='-Bstatic' - lt_prog_compiler_wl_CXX='-Qoption ld ' - ;; - esac - ;; - esac - ;; - lynxos*) - ;; - m88k*) - ;; - mvs*) - case $cc_basename in - cxx*) - lt_prog_compiler_pic_CXX='-W c,exportall' - ;; - *) - ;; - esac - ;; - netbsd* | netbsdelf*-gnu) - ;; - osf3* | osf4* | osf5*) - case $cc_basename in - KCC*) - lt_prog_compiler_wl_CXX='--backend -Wl,' - ;; - RCC*) - # Rational C++ 2.4.1 - lt_prog_compiler_pic_CXX='-pic' - ;; - cxx*) - # Digital/Compaq C++ - lt_prog_compiler_wl_CXX='-Wl,' - # Make sure the PIC flag is empty. It appears that all Alpha - # Linux and Compaq Tru64 Unix objects are PIC. - lt_prog_compiler_pic_CXX= - lt_prog_compiler_static_CXX='-non_shared' - ;; - *) - ;; - esac - ;; - psos*) - ;; - solaris*) - case $cc_basename in - CC*) - # Sun C++ 4.2, 5.x and Centerline C++ - lt_prog_compiler_pic_CXX='-KPIC' - lt_prog_compiler_static_CXX='-Bstatic' - lt_prog_compiler_wl_CXX='-Qoption ld ' - ;; - gcx*) - # Green Hills C++ Compiler - lt_prog_compiler_pic_CXX='-PIC' - ;; - *) - ;; - esac - ;; - sunos4*) - case $cc_basename in - CC*) - # Sun C++ 4.x - lt_prog_compiler_pic_CXX='-pic' - lt_prog_compiler_static_CXX='-Bstatic' - ;; - lcc*) - # Lucid - lt_prog_compiler_pic_CXX='-pic' - ;; - *) - ;; - esac - ;; - tandem*) - case $cc_basename in - NCC*) - # NonStop-UX NCC 3.20 - lt_prog_compiler_pic_CXX='-KPIC' - ;; - *) - ;; - esac - ;; - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - case $cc_basename in - CC*) - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_pic_CXX='-KPIC' - lt_prog_compiler_static_CXX='-Bstatic' - ;; - esac - ;; - vxworks*) - ;; - *) - lt_prog_compiler_can_build_shared_CXX=no - ;; - esac - fi - -{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_CXX" >&5 -echo "${ECHO_T}$lt_prog_compiler_pic_CXX" >&6; } - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$lt_prog_compiler_pic_CXX"; then - -{ echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 -echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... $ECHO_C" >&6; } -if test "${lt_prog_compiler_pic_works_CXX+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - lt_prog_compiler_pic_works_CXX=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:12847: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:12851: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_prog_compiler_pic_works_CXX=yes - fi - fi - $rm conftest* - -fi -{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_CXX" >&5 -echo "${ECHO_T}$lt_prog_compiler_pic_works_CXX" >&6; } - -if test x"$lt_prog_compiler_pic_works_CXX" = xyes; then - case $lt_prog_compiler_pic_CXX in - "" | " "*) ;; - *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; - esac -else - lt_prog_compiler_pic_CXX= - lt_prog_compiler_can_build_shared_CXX=no -fi - -fi -case $host_os in - # For platforms which do not support PIC, -DPIC is meaningless: - *djgpp*) - lt_prog_compiler_pic_CXX= - ;; - *) - lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" - ;; -esac - -# -# Check to make sure the static flag actually works. -# -wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" -{ echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 -echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6; } -if test "${lt_prog_compiler_static_works_CXX+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - lt_prog_compiler_static_works_CXX=no - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS $lt_tmp_static_flag" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_prog_compiler_static_works_CXX=yes - fi - else - lt_prog_compiler_static_works_CXX=yes - fi - fi - $rm conftest* - LDFLAGS="$save_LDFLAGS" - -fi -{ echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works_CXX" >&5 -echo "${ECHO_T}$lt_prog_compiler_static_works_CXX" >&6; } - -if test x"$lt_prog_compiler_static_works_CXX" = xyes; then - : -else - lt_prog_compiler_static_CXX= -fi - - -{ echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 -echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6; } -if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - lt_cv_prog_compiler_c_o_CXX=no - $rm -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:12951: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:12955: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o_CXX=yes - fi - fi - chmod u+w . 2>&5 - $rm conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files - $rm out/* && rmdir out - cd .. - rmdir conftest - $rm conftest* - -fi -{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_CXX" >&5 -echo "${ECHO_T}$lt_cv_prog_compiler_c_o_CXX" >&6; } - - -hard_links="nottested" -if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then - # do not overwrite the value of need_locks provided by the user - { echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 -echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6; } - hard_links=yes - $rm conftest* - ln conftest.a conftest.b 2>/dev/null && hard_links=no - touch conftest.a - ln conftest.a conftest.b 2>&5 || hard_links=no - ln conftest.a conftest.b 2>/dev/null && hard_links=no - { echo "$as_me:$LINENO: result: $hard_links" >&5 -echo "${ECHO_T}$hard_links" >&6; } - if test "$hard_links" = no; then - { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 -echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} - need_locks=warn - fi -else - need_locks=no -fi - -{ echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 -echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6; } - - export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - case $host_os in - aix4* | aix5*) - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to AIX nm, but means don't demangle with GNU nm - if $NM -V 2>&1 | grep 'GNU' > /dev/null; then - export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' - else - export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' - fi - ;; - pw32*) - export_symbols_cmds_CXX="$ltdll_cmds" - ;; - cygwin* | mingw*) - export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;/^.*[ ]__nm__/s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' - ;; - linux* | k*bsd*-gnu) - link_all_deplibs_CXX=no - ;; - *) - export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - ;; - esac - -{ echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5 -echo "${ECHO_T}$ld_shlibs_CXX" >&6; } -test "$ld_shlibs_CXX" = no && can_build_shared=no - -# -# Do we need to explicitly link libc? -# -case "x$archive_cmds_need_lc_CXX" in -x|xyes) - # Assume -lc should be added - archive_cmds_need_lc_CXX=yes - - if test "$enable_shared" = yes && test "$GCC" = yes; then - case $archive_cmds_CXX in - *'~'*) - # FIXME: we may have to deal with multi-command sequences. - ;; - '$CC '*) - # Test whether the compiler implicitly links with -lc since on some - # systems, -lgcc has to come before -lc. If gcc already passes -lc - # to ld, don't add -lc before -lgcc. - { echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 -echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6; } - $rm conftest* - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$lt_prog_compiler_wl_CXX - pic_flag=$lt_prog_compiler_pic_CXX - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$allow_undefined_flag_CXX - allow_undefined_flag_CXX= - if { (eval echo "$as_me:$LINENO: \"$archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 - (eval $archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - then - archive_cmds_need_lc_CXX=no - else - archive_cmds_need_lc_CXX=yes - fi - allow_undefined_flag_CXX=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $rm conftest* - { echo "$as_me:$LINENO: result: $archive_cmds_need_lc_CXX" >&5 -echo "${ECHO_T}$archive_cmds_need_lc_CXX" >&6; } - ;; - esac - fi - ;; -esac - -{ echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 -echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6; } -library_names_spec= -libname_spec='lib$name' -soname_spec= -shrext_cmds=".so" -postinstall_cmds= -postuninstall_cmds= -finish_cmds= -finish_eval= -shlibpath_var= -shlibpath_overrides_runpath=unknown -version_type=none -dynamic_linker="$host_os ld.so" -sys_lib_dlsearch_path_spec="/lib /usr/lib" - -need_lib_prefix=unknown -hardcode_into_libs=no - -# when you set need_version to no, make sure it does not cause -set_version -# flags to be left without arguments -need_version=unknown - -case $host_os in -aix3*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' - shlibpath_var=LIBPATH - - # AIX 3 has no versioning support, so we append a major version to the name. - soname_spec='${libname}${release}${shared_ext}$major' - ;; - -aix4* | aix5*) - version_type=linux - need_lib_prefix=no - need_version=no - hardcode_into_libs=yes - if test "$host_cpu" = ia64; then - # AIX 5 supports IA64 - library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - else - # With GCC up to 2.95.x, collect2 would create an import file - # for dependence libraries. The import file would start with - # the line `#! .'. This would cause the generated library to - # depend on `.', always an invalid library. This was fixed in - # development snapshots of GCC prior to 3.0. - case $host_os in - aix4 | aix4.[01] | aix4.[01].*) - if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' - echo ' yes ' - echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then - : - else - can_build_shared=no - fi - ;; - esac - # AIX (on Power*) has no versioning support, so currently we can not hardcode correct - # soname into executable. Probably we can add versioning support to - # collect2, so additional links can be useful in future. - if test "$aix_use_runtimelinking" = yes; then - # If using run time linking (on AIX 4.2 or later) use lib.so - # instead of lib.a to let people know that these are not - # typical AIX shared libraries. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - else - # We preserve .a as extension for shared libraries through AIX4.2 - # and later when we are not doing run time linking. - library_names_spec='${libname}${release}.a $libname.a' - soname_spec='${libname}${release}${shared_ext}$major' - fi - shlibpath_var=LIBPATH - fi - ;; - -amigaos*) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' - ;; - -beos*) - library_names_spec='${libname}${shared_ext}' - dynamic_linker="$host_os ld.so" - shlibpath_var=LIBRARY_PATH - ;; - -bsdi[45]*) - version_type=linux - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" - sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" - # the default ld.so.conf also contains /usr/contrib/lib and - # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow - # libtool to hard-code these into programs - ;; - -cygwin* | mingw* | pw32*) - version_type=windows - shrext_cmds=".dll" - need_version=no - need_lib_prefix=no - - case $GCC,$host_os in - yes,cygwin* | yes,mingw* | yes,pw32*) - library_names_spec='$libname.dll.a' - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \${file}`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $rm \$dlpath' - shlibpath_overrides_runpath=yes - - case $host_os in - cygwin*) - # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" - ;; - mingw*) - # MinGW DLLs use traditional 'lib' prefix - soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` - if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then - # It is most probably a Windows format PATH printed by - # mingw gcc, but we are running on Cygwin. Gcc prints its search - # path with ; separators, and with drive letters. We can handle the - # drive letters (cygwin fileutils understands them), so leave them, - # especially as we might pass files found there to a mingw objdump, - # which wouldn't understand a cygwinified path. Ahh. - sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi - ;; - pw32*) - # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - ;; - esac - ;; - - *) - library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' - ;; - esac - dynamic_linker='Win32 ld.exe' - # FIXME: first we should search . and the directory the executable is in - shlibpath_var=PATH - ;; - -darwin* | rhapsody*) - dynamic_linker="$host_os dyld" - version_type=darwin - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' - soname_spec='${libname}${release}${major}$shared_ext' - shlibpath_overrides_runpath=yes - shlibpath_var=DYLD_LIBRARY_PATH - shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' - - sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' - ;; - -dgux*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -freebsd1*) - dynamic_linker=no - ;; - -freebsd* | dragonfly*) - # DragonFly does not have aout. When/if they implement a new - # versioning mechanism, adjust this. - if test -x /usr/bin/objformat; then - objformat=`/usr/bin/objformat` - else - case $host_os in - freebsd[123]*) objformat=aout ;; - *) objformat=elf ;; - esac - fi - version_type=freebsd-$objformat - case $version_type in - freebsd-elf*) - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - need_version=no - need_lib_prefix=no - ;; - freebsd-*) - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' - need_version=yes - ;; - esac - shlibpath_var=LD_LIBRARY_PATH - case $host_os in - freebsd2*) - shlibpath_overrides_runpath=yes - ;; - freebsd3.[01]* | freebsdelf3.[01]*) - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ - freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - *) # from 4.6 on, and DragonFly - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - esac - ;; - -gnu*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - hardcode_into_libs=yes - ;; - -hpux9* | hpux10* | hpux11*) - # Give a soname corresponding to the major version so that dld.sl refuses to - # link against other versions. - version_type=sunos - need_lib_prefix=no - need_version=no - case $host_cpu in - ia64*) - shrext_cmds='.so' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.so" - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - if test "X$HPUX_IA64_MODE" = X32; then - sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" - else - sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" - fi - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - hppa*64*) - shrext_cmds='.sl' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.sl" - shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - *) - shrext_cmds='.sl' - dynamic_linker="$host_os dld.sl" - shlibpath_var=SHLIB_PATH - shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - ;; - esac - # HP-UX runs *really* slowly unless shared libraries are mode 555. - postinstall_cmds='chmod 555 $lib' - ;; - -interix[3-9]*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -irix5* | irix6* | nonstopux*) - case $host_os in - nonstopux*) version_type=nonstopux ;; - *) - if test "$lt_cv_prog_gnu_ld" = yes; then - version_type=linux - else - version_type=irix - fi ;; - esac - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' - case $host_os in - irix5* | nonstopux*) - libsuff= shlibsuff= - ;; - *) - case $LD in # libtool.m4 will add one of these switches to LD - *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") - libsuff= shlibsuff= libmagic=32-bit;; - *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") - libsuff=32 shlibsuff=N32 libmagic=N32;; - *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") - libsuff=64 shlibsuff=64 libmagic=64-bit;; - *) libsuff= shlibsuff= libmagic=never-match;; - esac - ;; - esac - shlibpath_var=LD_LIBRARY${shlibsuff}_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" - sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" - hardcode_into_libs=yes - ;; - -# No shared lib support for Linux oldld, aout, or coff. -linux*oldld* | linux*aout* | linux*coff*) - dynamic_linker=no - ;; - -# This must be Linux ELF. -linux* | k*bsd*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - # Append ld.so.conf contents to the search path - if test -f /etc/ld.so.conf; then - lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` - sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" - fi - - # We used to test for /lib/ld.so.1 and disable shared libraries on - # powerpc, because MkLinux only supported shared libraries with the - # GNU dynamic linker. Since this was broken with cross compilers, - # most powerpc-linux boxes support dynamic linking these days and - # people can always --disable-shared, the test was removed, and we - # assume the GNU/Linux dynamic linker is in use. - dynamic_linker='GNU/Linux ld.so' - ;; - -netbsdelf*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='NetBSD ld.elf_so' - ;; - -netbsd*) - version_type=sunos - need_lib_prefix=no - need_version=no - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - dynamic_linker='NetBSD (a.out) ld.so' - else - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='NetBSD ld.elf_so' - fi - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - -newsos6) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -nto-qnx*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -openbsd*) - version_type=sunos - sys_lib_dlsearch_path_spec="/usr/lib" - need_lib_prefix=no - # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. - case $host_os in - openbsd3.3 | openbsd3.3.*) need_version=yes ;; - *) need_version=no ;; - esac - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - case $host_os in - openbsd2.[89] | openbsd2.[89].*) - shlibpath_overrides_runpath=no - ;; - *) - shlibpath_overrides_runpath=yes - ;; - esac - else - shlibpath_overrides_runpath=yes - fi - ;; - -os2*) - libname_spec='$name' - shrext_cmds=".dll" - need_lib_prefix=no - library_names_spec='$libname${shared_ext} $libname.a' - dynamic_linker='OS/2 ld.exe' - shlibpath_var=LIBPATH - ;; - -osf3* | osf4* | osf5*) - version_type=osf - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" - ;; - -rdos*) - dynamic_linker=no - ;; - -solaris*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - # ldd complains unless libraries are executable - postinstall_cmds='chmod +x $lib' - ;; - -sunos4*) - version_type=sunos - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - if test "$with_gnu_ld" = yes; then - need_lib_prefix=no - fi - need_version=yes - ;; - -sysv4 | sysv4.3*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - case $host_vendor in - sni) - shlibpath_overrides_runpath=no - need_lib_prefix=no - export_dynamic_flag_spec='${wl}-Blargedynsym' - runpath_var=LD_RUN_PATH - ;; - siemens) - need_lib_prefix=no - ;; - motorola) - need_lib_prefix=no - need_version=no - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' - ;; - esac - ;; - -sysv4*MP*) - if test -d /usr/nec ;then - version_type=linux - library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' - soname_spec='$libname${shared_ext}.$major' - shlibpath_var=LD_LIBRARY_PATH - fi - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - version_type=freebsd-elf - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - hardcode_into_libs=yes - if test "$with_gnu_ld" = yes; then - sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' - shlibpath_overrides_runpath=no - else - sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' - shlibpath_overrides_runpath=yes - case $host_os in - sco3.2v5*) - sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" - ;; - esac - fi - sys_lib_dlsearch_path_spec='/usr/lib' - ;; - -uts4*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -*) - dynamic_linker=no - ;; -esac -{ echo "$as_me:$LINENO: result: $dynamic_linker" >&5 -echo "${ECHO_T}$dynamic_linker" >&6; } -test "$dynamic_linker" = no && can_build_shared=no - -variables_saved_for_relink="PATH $shlibpath_var $runpath_var" -if test "$GCC" = yes; then - variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" -fi - -{ echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 -echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6; } -hardcode_action_CXX= -if test -n "$hardcode_libdir_flag_spec_CXX" || \ - test -n "$runpath_var_CXX" || \ - test "X$hardcode_automatic_CXX" = "Xyes" ; then - - # We can hardcode non-existant directories. - if test "$hardcode_direct_CXX" != no && - # If the only mechanism to avoid hardcoding is shlibpath_var, we - # have to relink, otherwise we might link with an installed library - # when we should be linking with a yet-to-be-installed one - ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, CXX)" != no && - test "$hardcode_minus_L_CXX" != no; then - # Linking always hardcodes the temporary library directory. - hardcode_action_CXX=relink - else - # We can link without hardcoding, and we can hardcode nonexisting dirs. - hardcode_action_CXX=immediate - fi -else - # We cannot hardcode anything, or else we can only hardcode existing - # directories. - hardcode_action_CXX=unsupported -fi -{ echo "$as_me:$LINENO: result: $hardcode_action_CXX" >&5 -echo "${ECHO_T}$hardcode_action_CXX" >&6; } - -if test "$hardcode_action_CXX" = relink; then - # Fast installation is not supported - enable_fast_install=no -elif test "$shlibpath_overrides_runpath" = yes || - test "$enable_shared" = no; then - # Fast installation is not necessary - enable_fast_install=needless -fi - - -# The else clause should only fire when bootstrapping the -# libtool distribution, otherwise you forgot to ship ltmain.sh -# with your package, and you will get complaints that there are -# no rules to generate ltmain.sh. -if test -f "$ltmain"; then - # See if we are running on zsh, and set the options which allow our commands through - # without removal of \ escapes. - if test -n "${ZSH_VERSION+set}" ; then - setopt NO_GLOB_SUBST - fi - # Now quote all the things that may contain metacharacters while being - # careful not to overquote the AC_SUBSTed values. We take copies of the - # variables and quote the copies for generation of the libtool script. - for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ - SED SHELL STRIP \ - libname_spec library_names_spec soname_spec extract_expsyms_cmds \ - old_striplib striplib file_magic_cmd finish_cmds finish_eval \ - deplibs_check_method reload_flag reload_cmds need_locks \ - lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ - lt_cv_sys_global_symbol_to_c_name_address \ - sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ - old_postinstall_cmds old_postuninstall_cmds \ - compiler_CXX \ - CC_CXX \ - LD_CXX \ - lt_prog_compiler_wl_CXX \ - lt_prog_compiler_pic_CXX \ - lt_prog_compiler_static_CXX \ - lt_prog_compiler_no_builtin_flag_CXX \ - export_dynamic_flag_spec_CXX \ - thread_safe_flag_spec_CXX \ - whole_archive_flag_spec_CXX \ - enable_shared_with_static_runtimes_CXX \ - old_archive_cmds_CXX \ - old_archive_from_new_cmds_CXX \ - predep_objects_CXX \ - postdep_objects_CXX \ - predeps_CXX \ - postdeps_CXX \ - compiler_lib_search_path_CXX \ - archive_cmds_CXX \ - archive_expsym_cmds_CXX \ - postinstall_cmds_CXX \ - postuninstall_cmds_CXX \ - old_archive_from_expsyms_cmds_CXX \ - allow_undefined_flag_CXX \ - no_undefined_flag_CXX \ - export_symbols_cmds_CXX \ - hardcode_libdir_flag_spec_CXX \ - hardcode_libdir_flag_spec_ld_CXX \ - hardcode_libdir_separator_CXX \ - hardcode_automatic_CXX \ - module_cmds_CXX \ - module_expsym_cmds_CXX \ - lt_cv_prog_compiler_c_o_CXX \ - fix_srcfile_path_CXX \ - exclude_expsyms_CXX \ - include_expsyms_CXX; do - - case $var in - old_archive_cmds_CXX | \ - old_archive_from_new_cmds_CXX | \ - archive_cmds_CXX | \ - archive_expsym_cmds_CXX | \ - module_cmds_CXX | \ - module_expsym_cmds_CXX | \ - old_archive_from_expsyms_cmds_CXX | \ - export_symbols_cmds_CXX | \ - extract_expsyms_cmds | reload_cmds | finish_cmds | \ - postinstall_cmds | postuninstall_cmds | \ - old_postinstall_cmds | old_postuninstall_cmds | \ - sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) - # Double-quote double-evaled strings. - eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" - ;; - *) - eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" - ;; - esac - done - - case $lt_echo in - *'\$0 --fallback-echo"') - lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` - ;; - esac - -cfgfile="$ofile" - - cat <<__EOF__ >> "$cfgfile" -# ### BEGIN LIBTOOL TAG CONFIG: $tagname - -# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: - -# Shell to use when invoking shell scripts. -SHELL=$lt_SHELL - -# Whether or not to build shared libraries. -build_libtool_libs=$enable_shared - -# Whether or not to build static libraries. -build_old_libs=$enable_static - -# Whether or not to add -lc for building shared libraries. -build_libtool_need_lc=$archive_cmds_need_lc_CXX - -# Whether or not to disallow shared libs when runtime libs are static -allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX - -# Whether or not to optimize for fast installation. -fast_install=$enable_fast_install - -# The host system. -host_alias=$host_alias -host=$host -host_os=$host_os - -# The build system. -build_alias=$build_alias -build=$build -build_os=$build_os - -# An echo program that does not interpret backslashes. -echo=$lt_echo - -# The archiver. -AR=$lt_AR -AR_FLAGS=$lt_AR_FLAGS - -# A C compiler. -LTCC=$lt_LTCC - -# LTCC compiler flags. -LTCFLAGS=$lt_LTCFLAGS - -# A language-specific compiler. -CC=$lt_compiler_CXX - -# Is the compiler the GNU C compiler? -with_gcc=$GCC_CXX - -# An ERE matcher. -EGREP=$lt_EGREP - -# The linker used to build libraries. -LD=$lt_LD_CXX - -# Whether we need hard or soft links. -LN_S=$lt_LN_S - -# A BSD-compatible nm program. -NM=$lt_NM - -# A symbol stripping program -STRIP=$lt_STRIP - -# Used to examine libraries when file_magic_cmd begins "file" -MAGIC_CMD=$MAGIC_CMD - -# Used on cygwin: DLL creation program. -DLLTOOL="$DLLTOOL" - -# Used on cygwin: object dumper. -OBJDUMP="$OBJDUMP" - -# Used on cygwin: assembler. -AS="$AS" - -# The name of the directory that contains temporary libtool files. -objdir=$objdir - -# How to create reloadable object files. -reload_flag=$lt_reload_flag -reload_cmds=$lt_reload_cmds - -# How to pass a linker flag through the compiler. -wl=$lt_lt_prog_compiler_wl_CXX - -# Object file suffix (normally "o"). -objext="$ac_objext" - -# Old archive suffix (normally "a"). -libext="$libext" - -# Shared library suffix (normally ".so"). -shrext_cmds='$shrext_cmds' - -# Executable file suffix (normally ""). -exeext="$exeext" - -# Additional compiler flags for building library objects. -pic_flag=$lt_lt_prog_compiler_pic_CXX -pic_mode=$pic_mode - -# What is the maximum length of a command? -max_cmd_len=$lt_cv_sys_max_cmd_len - -# Does compiler simultaneously support -c and -o options? -compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX - -# Must we lock files when doing compilation? -need_locks=$lt_need_locks - -# Do we need the lib prefix for modules? -need_lib_prefix=$need_lib_prefix - -# Do we need a version for libraries? -need_version=$need_version - -# Whether dlopen is supported. -dlopen_support=$enable_dlopen - -# Whether dlopen of programs is supported. -dlopen_self=$enable_dlopen_self - -# Whether dlopen of statically linked programs is supported. -dlopen_self_static=$enable_dlopen_self_static - -# Compiler flag to prevent dynamic linking. -link_static_flag=$lt_lt_prog_compiler_static_CXX - -# Compiler flag to turn off builtin functions. -no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX - -# Compiler flag to generate thread-safe objects. -thread_safe_flag_spec=$lt_thread_safe_flag_spec_CXX - -# Library versioning type. -version_type=$version_type - -# Format of library name prefix. -libname_spec=$lt_libname_spec - -# List of archive names. First name is the real one, the rest are links. -# The last name is the one that the linker finds with -lNAME. -library_names_spec=$lt_library_names_spec - -# The coded name of the library, if different from the real name. -soname_spec=$lt_soname_spec - -# Commands used to build and install an old-style archive. -RANLIB=$lt_RANLIB -old_archive_cmds=$lt_old_archive_cmds_CXX -old_postinstall_cmds=$lt_old_postinstall_cmds -old_postuninstall_cmds=$lt_old_postuninstall_cmds - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX - -# Create a temporary old-style archive to link instead of a shared archive. -old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX - -# Commands used to build and install a shared archive. -archive_cmds=$lt_archive_cmds_CXX -archive_expsym_cmds=$lt_archive_expsym_cmds_CXX -postinstall_cmds=$lt_postinstall_cmds -postuninstall_cmds=$lt_postuninstall_cmds - -# Commands used to build a loadable module (assumed same as above if empty) -module_cmds=$lt_module_cmds_CXX -module_expsym_cmds=$lt_module_expsym_cmds_CXX - -# Commands to strip libraries. -old_striplib=$lt_old_striplib -striplib=$lt_striplib - -# Dependencies to place before the objects being linked to create a -# shared library. -predep_objects=$lt_predep_objects_CXX - -# Dependencies to place after the objects being linked to create a -# shared library. -postdep_objects=$lt_postdep_objects_CXX - -# Dependencies to place before the objects being linked to create a -# shared library. -predeps=$lt_predeps_CXX - -# Dependencies to place after the objects being linked to create a -# shared library. -postdeps=$lt_postdeps_CXX - -# The library search path used internally by the compiler when linking -# a shared library. -compiler_lib_search_path=$lt_compiler_lib_search_path_CXX - -# Method to check whether dependent libraries are shared objects. -deplibs_check_method=$lt_deplibs_check_method - -# Command to use when deplibs_check_method == file_magic. -file_magic_cmd=$lt_file_magic_cmd - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag=$lt_allow_undefined_flag_CXX - -# Flag that forces no undefined symbols. -no_undefined_flag=$lt_no_undefined_flag_CXX - -# Commands used to finish a libtool library installation in a directory. -finish_cmds=$lt_finish_cmds - -# Same as above, but a single script fragment to be evaled but not shown. -finish_eval=$lt_finish_eval - -# Take the output of nm and produce a listing of raw symbols and C names. -global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe - -# Transform the output of nm in a proper C declaration -global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl - -# Transform the output of nm in a C name address pair -global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address - -# This is the shared library runtime path variable. -runpath_var=$runpath_var - -# This is the shared library path variable. -shlibpath_var=$shlibpath_var - -# Is shlibpath searched before the hard-coded library search path? -shlibpath_overrides_runpath=$shlibpath_overrides_runpath - -# How to hardcode a shared library path into an executable. -hardcode_action=$hardcode_action_CXX - -# Whether we should hardcode library paths into libraries. -hardcode_into_libs=$hardcode_into_libs - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist. -hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX - -# If ld is used when linking, flag to hardcode \$libdir into -# a binary during linking. This must work even if \$libdir does -# not exist. -hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX - -# Whether we need a single -rpath flag with a separated argument. -hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX - -# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the -# resulting binary. -hardcode_direct=$hardcode_direct_CXX - -# Set to yes if using the -LDIR flag during linking hardcodes DIR into the -# resulting binary. -hardcode_minus_L=$hardcode_minus_L_CXX - -# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into -# the resulting binary. -hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX - -# Set to yes if building a shared library automatically hardcodes DIR into the library -# and all subsequent libraries and executables linked against it. -hardcode_automatic=$hardcode_automatic_CXX - -# Variables whose values should be saved in libtool wrapper scripts and -# restored at relink time. -variables_saved_for_relink="$variables_saved_for_relink" - -# Whether libtool must link a program against all its dependency libraries. -link_all_deplibs=$link_all_deplibs_CXX - -# Compile-time system search path for libraries -sys_lib_search_path_spec=$lt_sys_lib_search_path_spec - -# Run-time system search path for libraries -sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec - -# Fix the shell variable \$srcfile for the compiler. -fix_srcfile_path=$lt_fix_srcfile_path - -# Set to yes if exported symbols are required. -always_export_symbols=$always_export_symbols_CXX - -# The commands to list exported symbols. -export_symbols_cmds=$lt_export_symbols_cmds_CXX - -# The commands to extract the exported symbol list from a shared archive. -extract_expsyms_cmds=$lt_extract_expsyms_cmds - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms=$lt_exclude_expsyms_CXX - -# Symbols that must always be exported. -include_expsyms=$lt_include_expsyms_CXX - -# ### END LIBTOOL TAG CONFIG: $tagname - -__EOF__ - - -else - # If there is no Makefile yet, we rely on a make rule to execute - # `config.status --recheck' to rerun these tests and create the - # libtool script then. - ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` - if test -f "$ltmain_in"; then - test -f Makefile && make "$ltmain" - fi -fi - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -CC=$lt_save_CC -LDCXX=$LD -LD=$lt_save_LD -GCC=$lt_save_GCC -with_gnu_ldcxx=$with_gnu_ld -with_gnu_ld=$lt_save_with_gnu_ld -lt_cv_path_LDCXX=$lt_cv_path_LD -lt_cv_path_LD=$lt_save_path_LD -lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld -lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld - - else - tagname="" - fi - ;; - - F77) - if test -n "$F77" && test "X$F77" != "Xno"; then - -ac_ext=f -ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' -ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_f77_compiler_gnu - - -archive_cmds_need_lc_F77=no -allow_undefined_flag_F77= -always_export_symbols_F77=no -archive_expsym_cmds_F77= -export_dynamic_flag_spec_F77= -hardcode_direct_F77=no -hardcode_libdir_flag_spec_F77= -hardcode_libdir_flag_spec_ld_F77= -hardcode_libdir_separator_F77= -hardcode_minus_L_F77=no -hardcode_automatic_F77=no -module_cmds_F77= -module_expsym_cmds_F77= -link_all_deplibs_F77=unknown -old_archive_cmds_F77=$old_archive_cmds -no_undefined_flag_F77= -whole_archive_flag_spec_F77= -enable_shared_with_static_runtimes_F77=no - -# Source file extension for f77 test sources. -ac_ext=f - -# Object file extension for compiled f77 test sources. -objext=o -objext_F77=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="\ - subroutine t - return - end -" - -# Code to be used in simple link tests -lt_simple_link_test_code="\ - program t - end -" - -# ltmain only uses $CC for tagged configurations so make sure $CC is set. - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - - -# save warnings/boilerplate of simple test code -ac_outfile=conftest.$ac_objext -echo "$lt_simple_compile_test_code" >conftest.$ac_ext -eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_compiler_boilerplate=`cat conftest.err` -$rm conftest* - -ac_outfile=conftest.$ac_objext -echo "$lt_simple_link_test_code" >conftest.$ac_ext -eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_linker_boilerplate=`cat conftest.err` -$rm conftest* - - -# Allow CC to be a program name with arguments. -lt_save_CC="$CC" -CC=${F77-"f77"} -compiler=$CC -compiler_F77=$CC -for cc_temp in $compiler""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac -done -cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` - - -{ echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5 -echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6; } -{ echo "$as_me:$LINENO: result: $can_build_shared" >&5 -echo "${ECHO_T}$can_build_shared" >&6; } - -{ echo "$as_me:$LINENO: checking whether to build shared libraries" >&5 -echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6; } -test "$can_build_shared" = "no" && enable_shared=no - -# On AIX, shared libraries and static libraries use the same namespace, and -# are all built from PIC. -case $host_os in -aix3*) - test "$enable_shared" = yes && enable_static=no - if test -n "$RANLIB"; then - archive_cmds="$archive_cmds~\$RANLIB \$lib" - postinstall_cmds='$RANLIB $lib' - fi - ;; -aix4* | aix5*) - if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then - test "$enable_shared" = yes && enable_static=no - fi - ;; -esac -{ echo "$as_me:$LINENO: result: $enable_shared" >&5 -echo "${ECHO_T}$enable_shared" >&6; } - -{ echo "$as_me:$LINENO: checking whether to build static libraries" >&5 -echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6; } -# Make sure either enable_shared or enable_static is yes. -test "$enable_shared" = yes || enable_static=yes -{ echo "$as_me:$LINENO: result: $enable_static" >&5 -echo "${ECHO_T}$enable_static" >&6; } - -GCC_F77="$G77" -LD_F77="$LD" - -lt_prog_compiler_wl_F77= -lt_prog_compiler_pic_F77= -lt_prog_compiler_static_F77= - -{ echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 -echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6; } - - if test "$GCC" = yes; then - lt_prog_compiler_wl_F77='-Wl,' - lt_prog_compiler_static_F77='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static_F77='-Bstatic' - fi - ;; - - amigaos*) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the `-m68020' flag to GCC prevents building anything better, - # like `-m68040'. - lt_prog_compiler_pic_F77='-m68020 -resident32 -malways-restore-a4' - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - - mingw* | cygwin* | pw32* | os2*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - lt_prog_compiler_pic_F77='-DDLL_EXPORT' - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic_F77='-fno-common' - ;; - - interix[3-9]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - - msdosdjgpp*) - # Just because we use GCC doesn't mean we suddenly get shared libraries - # on systems that don't support them. - lt_prog_compiler_can_build_shared_F77=no - enable_shared=no - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic_F77=-Kconform_pic - fi - ;; - - hpux*) - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic_F77='-fPIC' - ;; - esac - ;; - - *) - lt_prog_compiler_pic_F77='-fPIC' - ;; - esac - else - # PORTME Check for flag to pass linker flags through the system compiler. - case $host_os in - aix*) - lt_prog_compiler_wl_F77='-Wl,' - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static_F77='-Bstatic' - else - lt_prog_compiler_static_F77='-bnso -bI:/lib/syscalls.exp' - fi - ;; - darwin*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - case $cc_basename in - xlc*) - lt_prog_compiler_pic_F77='-qnocommon' - lt_prog_compiler_wl_F77='-Wl,' - ;; - esac - ;; - - mingw* | cygwin* | pw32* | os2*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - lt_prog_compiler_pic_F77='-DDLL_EXPORT' - ;; - - hpux9* | hpux10* | hpux11*) - lt_prog_compiler_wl_F77='-Wl,' - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic_F77='+Z' - ;; - esac - # Is there a better lt_prog_compiler_static that works with the bundled CC? - lt_prog_compiler_static_F77='${wl}-a ${wl}archive' - ;; - - irix5* | irix6* | nonstopux*) - lt_prog_compiler_wl_F77='-Wl,' - # PIC (with -KPIC) is the default. - lt_prog_compiler_static_F77='-non_shared' - ;; - - newsos6) - lt_prog_compiler_pic_F77='-KPIC' - lt_prog_compiler_static_F77='-Bstatic' - ;; - - linux* | k*bsd*-gnu) - case $cc_basename in - icc* | ecc*) - lt_prog_compiler_wl_F77='-Wl,' - lt_prog_compiler_pic_F77='-KPIC' - lt_prog_compiler_static_F77='-static' - ;; - pgcc* | pgf77* | pgf90* | pgf95*) - # Portland Group compilers (*not* the Pentium gcc compiler, - # which looks to be a dead project) - lt_prog_compiler_wl_F77='-Wl,' - lt_prog_compiler_pic_F77='-fpic' - lt_prog_compiler_static_F77='-Bstatic' - ;; - ccc*) - lt_prog_compiler_wl_F77='-Wl,' - # All Alpha code is PIC. - lt_prog_compiler_static_F77='-non_shared' - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) - # Sun C 5.9 - lt_prog_compiler_pic_F77='-KPIC' - lt_prog_compiler_static_F77='-Bstatic' - lt_prog_compiler_wl_F77='-Wl,' - ;; - *Sun\ F*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - lt_prog_compiler_pic_F77='-KPIC' - lt_prog_compiler_static_F77='-Bstatic' - lt_prog_compiler_wl_F77='' - ;; - esac - ;; - esac - ;; - - osf3* | osf4* | osf5*) - lt_prog_compiler_wl_F77='-Wl,' - # All OSF/1 code is PIC. - lt_prog_compiler_static_F77='-non_shared' - ;; - - rdos*) - lt_prog_compiler_static_F77='-non_shared' - ;; - - solaris*) - lt_prog_compiler_pic_F77='-KPIC' - lt_prog_compiler_static_F77='-Bstatic' - case $cc_basename in - f77* | f90* | f95*) - lt_prog_compiler_wl_F77='-Qoption ld ';; - *) - lt_prog_compiler_wl_F77='-Wl,';; - esac - ;; - - sunos4*) - lt_prog_compiler_wl_F77='-Qoption ld ' - lt_prog_compiler_pic_F77='-PIC' - lt_prog_compiler_static_F77='-Bstatic' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3*) - lt_prog_compiler_wl_F77='-Wl,' - lt_prog_compiler_pic_F77='-KPIC' - lt_prog_compiler_static_F77='-Bstatic' - ;; - - sysv4*MP*) - if test -d /usr/nec ;then - lt_prog_compiler_pic_F77='-Kconform_pic' - lt_prog_compiler_static_F77='-Bstatic' - fi - ;; - - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - lt_prog_compiler_wl_F77='-Wl,' - lt_prog_compiler_pic_F77='-KPIC' - lt_prog_compiler_static_F77='-Bstatic' - ;; - - unicos*) - lt_prog_compiler_wl_F77='-Wl,' - lt_prog_compiler_can_build_shared_F77=no - ;; - - uts4*) - lt_prog_compiler_pic_F77='-pic' - lt_prog_compiler_static_F77='-Bstatic' - ;; - - *) - lt_prog_compiler_can_build_shared_F77=no - ;; - esac - fi - -{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_F77" >&5 -echo "${ECHO_T}$lt_prog_compiler_pic_F77" >&6; } - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$lt_prog_compiler_pic_F77"; then - -{ echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works" >&5 -echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works... $ECHO_C" >&6; } -if test "${lt_prog_compiler_pic_works_F77+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - lt_prog_compiler_pic_works_F77=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic_F77" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14528: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:14532: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_prog_compiler_pic_works_F77=yes - fi - fi - $rm conftest* - -fi -{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_F77" >&5 -echo "${ECHO_T}$lt_prog_compiler_pic_works_F77" >&6; } - -if test x"$lt_prog_compiler_pic_works_F77" = xyes; then - case $lt_prog_compiler_pic_F77 in - "" | " "*) ;; - *) lt_prog_compiler_pic_F77=" $lt_prog_compiler_pic_F77" ;; - esac -else - lt_prog_compiler_pic_F77= - lt_prog_compiler_can_build_shared_F77=no -fi - -fi -case $host_os in - # For platforms which do not support PIC, -DPIC is meaningless: - *djgpp*) - lt_prog_compiler_pic_F77= - ;; - *) - lt_prog_compiler_pic_F77="$lt_prog_compiler_pic_F77" - ;; -esac - -# -# Check to make sure the static flag actually works. -# -wl=$lt_prog_compiler_wl_F77 eval lt_tmp_static_flag=\"$lt_prog_compiler_static_F77\" -{ echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 -echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6; } -if test "${lt_prog_compiler_static_works_F77+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - lt_prog_compiler_static_works_F77=no - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS $lt_tmp_static_flag" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_prog_compiler_static_works_F77=yes - fi - else - lt_prog_compiler_static_works_F77=yes - fi - fi - $rm conftest* - LDFLAGS="$save_LDFLAGS" - -fi -{ echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works_F77" >&5 -echo "${ECHO_T}$lt_prog_compiler_static_works_F77" >&6; } - -if test x"$lt_prog_compiler_static_works_F77" = xyes; then - : -else - lt_prog_compiler_static_F77= -fi - - -{ echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 -echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6; } -if test "${lt_cv_prog_compiler_c_o_F77+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - lt_cv_prog_compiler_c_o_F77=no - $rm -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14632: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:14636: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o_F77=yes - fi - fi - chmod u+w . 2>&5 - $rm conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files - $rm out/* && rmdir out - cd .. - rmdir conftest - $rm conftest* - -fi -{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_F77" >&5 -echo "${ECHO_T}$lt_cv_prog_compiler_c_o_F77" >&6; } - - -hard_links="nottested" -if test "$lt_cv_prog_compiler_c_o_F77" = no && test "$need_locks" != no; then - # do not overwrite the value of need_locks provided by the user - { echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 -echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6; } - hard_links=yes - $rm conftest* - ln conftest.a conftest.b 2>/dev/null && hard_links=no - touch conftest.a - ln conftest.a conftest.b 2>&5 || hard_links=no - ln conftest.a conftest.b 2>/dev/null && hard_links=no - { echo "$as_me:$LINENO: result: $hard_links" >&5 -echo "${ECHO_T}$hard_links" >&6; } - if test "$hard_links" = no; then - { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 -echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} - need_locks=warn - fi -else - need_locks=no -fi - -{ echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 -echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6; } - - runpath_var= - allow_undefined_flag_F77= - enable_shared_with_static_runtimes_F77=no - archive_cmds_F77= - archive_expsym_cmds_F77= - old_archive_From_new_cmds_F77= - old_archive_from_expsyms_cmds_F77= - export_dynamic_flag_spec_F77= - whole_archive_flag_spec_F77= - thread_safe_flag_spec_F77= - hardcode_libdir_flag_spec_F77= - hardcode_libdir_flag_spec_ld_F77= - hardcode_libdir_separator_F77= - hardcode_direct_F77=no - hardcode_minus_L_F77=no - hardcode_shlibpath_var_F77=unsupported - link_all_deplibs_F77=unknown - hardcode_automatic_F77=no - module_cmds_F77= - module_expsym_cmds_F77= - always_export_symbols_F77=no - export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - # include_expsyms should be a list of space-separated symbols to be *always* - # included in the symbol list - include_expsyms_F77= - # exclude_expsyms can be an extended regexp of symbols to exclude - # it will be wrapped by ` (' and `)$', so one must not match beginning or - # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', - # as well as any symbol that contains `d'. - exclude_expsyms_F77="_GLOBAL_OFFSET_TABLE_" - # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out - # platforms (ab)use it in PIC code, but their linkers get confused if - # the symbol is explicitly referenced. Since portable code cannot - # rely on this symbol name, it's probably fine to never include it in - # preloaded symbol tables. - extract_expsyms_cmds= - # Just being paranoid about ensuring that cc_basename is set. - for cc_temp in $compiler""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac -done -cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` - - case $host_os in - cygwin* | mingw* | pw32*) - # FIXME: the MSVC++ port hasn't been tested in a loooong time - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - if test "$GCC" != yes; then - with_gnu_ld=no - fi - ;; - interix*) - # we just hope/assume this is gcc and not c89 (= MSVC++) - with_gnu_ld=yes - ;; - openbsd*) - with_gnu_ld=no - ;; - esac - - ld_shlibs_F77=yes - if test "$with_gnu_ld" = yes; then - # If archive_cmds runs LD, not CC, wlarc should be empty - wlarc='${wl}' - - # Set some defaults for GNU ld with shared library support. These - # are reset later if shared libraries are not supported. Putting them - # here allows them to be overridden if necessary. - runpath_var=LD_RUN_PATH - hardcode_libdir_flag_spec_F77='${wl}--rpath ${wl}$libdir' - export_dynamic_flag_spec_F77='${wl}--export-dynamic' - # ancient GNU ld didn't support --whole-archive et. al. - if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then - whole_archive_flag_spec_F77="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - else - whole_archive_flag_spec_F77= - fi - supports_anon_versioning=no - case `$LD -v 2>/dev/null` in - *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 - *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... - *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... - *\ 2.11.*) ;; # other 2.11 versions - *) supports_anon_versioning=yes ;; - esac - - # See if GNU ld supports shared libraries. - case $host_os in - aix3* | aix4* | aix5*) - # On AIX/PPC, the GNU linker is very broken - if test "$host_cpu" != ia64; then - ld_shlibs_F77=no - cat <&2 - -*** Warning: the GNU linker, at least up to release 2.9.1, is reported -*** to be unable to reliably create shared libraries on AIX. -*** Therefore, libtool is disabling shared libraries support. If you -*** really care for shared libraries, you may want to modify your PATH -*** so that a non-GNU linker is found, and then restart. - -EOF - fi - ;; - - amigaos*) - archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec_F77='-L$libdir' - hardcode_minus_L_F77=yes - - # Samuel A. Falvo II reports - # that the semantics of dynamic libraries on AmigaOS, at least up - # to version 4, is to share data among multiple programs linked - # with the same dynamic library. Since this doesn't match the - # behavior of shared libraries on other platforms, we can't use - # them. - ld_shlibs_F77=no - ;; - - beos*) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - allow_undefined_flag_F77=unsupported - # Joseph Beckenbach says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - archive_cmds_F77='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - else - ld_shlibs_F77=no - fi - ;; - - cygwin* | mingw* | pw32*) - # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, F77) is actually meaningless, - # as there is no search path for DLLs. - hardcode_libdir_flag_spec_F77='-L$libdir' - allow_undefined_flag_F77=unsupported - always_export_symbols_F77=no - enable_shared_with_static_runtimes_F77=yes - export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' - - if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then - archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file (1st line - # is EXPORTS), use it as is; otherwise, prepend... - archive_expsym_cmds_F77='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - else - ld_shlibs_F77=no - fi - ;; - - interix[3-9]*) - hardcode_direct_F77=no - hardcode_shlibpath_var_F77=no - hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' - export_dynamic_flag_spec_F77='${wl}-E' - # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. - # Instead, shared libraries are loaded at an image base (0x10000000 by - # default) and relocated if they conflict, which is a slow very memory - # consuming and fragmenting process. To avoid this, we pick a random, - # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link - # time. Moving up from 0x10000000 also allows more sbrk(2) space. - archive_cmds_F77='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - archive_expsym_cmds_F77='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - ;; - - gnu* | linux* | k*bsd*-gnu) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - tmp_addflag= - case $cc_basename,$host_cpu in - pgcc*) # Portland Group C compiler - whole_archive_flag_spec_F77='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' - tmp_addflag=' $pic_flag' - ;; - pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers - whole_archive_flag_spec_F77='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' - tmp_addflag=' $pic_flag -Mnomain' ;; - ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 - tmp_addflag=' -i_dynamic' ;; - efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 - tmp_addflag=' -i_dynamic -nofor_main' ;; - ifc* | ifort*) # Intel Fortran compiler - tmp_addflag=' -nofor_main' ;; - esac - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) # Sun C 5.9 - whole_archive_flag_spec_F77='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' - tmp_sharedflag='-G' ;; - *Sun\ F*) # Sun Fortran 8.3 - tmp_sharedflag='-G' ;; - *) - tmp_sharedflag='-shared' ;; - esac - archive_cmds_F77='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - - if test $supports_anon_versioning = yes; then - archive_expsym_cmds_F77='$echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - $echo "local: *; };" >> $output_objdir/$libname.ver~ - $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' - fi - link_all_deplibs_F77=no - else - ld_shlibs_F77=no - fi - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - archive_cmds_F77='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' - wlarc= - else - archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - fi - ;; - - solaris*) - if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then - ld_shlibs_F77=no - cat <&2 - -*** Warning: The releases 2.8.* of the GNU linker cannot reliably -*** create shared libraries on Solaris systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.9.1 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -EOF - elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs_F77=no - fi - ;; - - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) - case `$LD -v 2>&1` in - *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) - ld_shlibs_F77=no - cat <<_LT_EOF 1>&2 - -*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not -*** reliably create shared libraries on SCO systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.16.91.0.3 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - ;; - *) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - hardcode_libdir_flag_spec_F77='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' - archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' - archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' - else - ld_shlibs_F77=no - fi - ;; - esac - ;; - - sunos4*) - archive_cmds_F77='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' - wlarc= - hardcode_direct_F77=yes - hardcode_shlibpath_var_F77=no - ;; - - *) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs_F77=no - fi - ;; - esac - - if test "$ld_shlibs_F77" = no; then - runpath_var= - hardcode_libdir_flag_spec_F77= - export_dynamic_flag_spec_F77= - whole_archive_flag_spec_F77= - fi - else - # PORTME fill in a description of your system's linker (not GNU ld) - case $host_os in - aix3*) - allow_undefined_flag_F77=unsupported - always_export_symbols_F77=yes - archive_expsym_cmds_F77='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' - # Note: this linker hardcodes the directories in LIBPATH if there - # are no directories specified by -L. - hardcode_minus_L_F77=yes - if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then - # Neither direct hardcoding nor static linking is supported with a - # broken collect2. - hardcode_direct_F77=unsupported - fi - ;; - - aix4* | aix5*) - if test "$host_cpu" = ia64; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag="" - else - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to AIX nm, but means don't demangle with GNU nm - if $NM -V 2>&1 | grep 'GNU' > /dev/null; then - export_symbols_cmds_F77='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' - else - export_symbols_cmds_F77='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' - fi - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # need to do runtime linking. - case $host_os in aix4.[23]|aix4.[23].*|aix5*) - for ld_flag in $LDFLAGS; do - if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then - aix_use_runtimelinking=yes - break - fi - done - ;; - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - archive_cmds_F77='' - hardcode_direct_F77=yes - hardcode_libdir_separator_F77=':' - link_all_deplibs_F77=yes - - if test "$GCC" = yes; then - case $host_os in aix4.[012]|aix4.[012].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`${CC} -print-prog-name=collect2` - if test -f "$collect2name" && \ - strings "$collect2name" | grep resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - hardcode_direct_F77=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - hardcode_minus_L_F77=yes - hardcode_libdir_flag_spec_F77='-L$libdir' - hardcode_libdir_separator_F77= - fi - ;; - esac - shared_flag='-shared' - if test "$aix_use_runtimelinking" = yes; then - shared_flag="$shared_flag "'${wl}-G' - fi - else - # not using gcc - if test "$host_cpu" = ia64; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test "$aix_use_runtimelinking" = yes; then - shared_flag='${wl}-G' - else - shared_flag='${wl}-bM:SRE' - fi - fi - fi - - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to export. - always_export_symbols_F77=yes - if test "$aix_use_runtimelinking" = yes; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - allow_undefined_flag_F77='-berok' - # Determine the default libpath from the value encoded in an empty executable. - cat >conftest.$ac_ext <<_ACEOF - program main - - end -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_f77_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - -lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\(.*\)$/\1/ - p - } - }' -aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -# Check for a 64-bit object if we didn't find anything. -if test -z "$aix_libpath"; then - aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -fi -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi - - hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath" - archive_expsym_cmds_F77="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" - else - if test "$host_cpu" = ia64; then - hardcode_libdir_flag_spec_F77='${wl}-R $libdir:/usr/lib:/lib' - allow_undefined_flag_F77="-z nodefs" - archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an empty executable. - cat >conftest.$ac_ext <<_ACEOF - program main - - end -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_f77_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - -lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\(.*\)$/\1/ - p - } - }' -aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -# Check for a 64-bit object if we didn't find anything. -if test -z "$aix_libpath"; then - aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -fi -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi - - hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - no_undefined_flag_F77=' ${wl}-bernotok' - allow_undefined_flag_F77=' ${wl}-berok' - # Exported symbols can be pulled into shared objects from archives - whole_archive_flag_spec_F77='$convenience' - archive_cmds_need_lc_F77=yes - # This is similar to how AIX traditionally builds its shared libraries. - archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' - fi - fi - ;; - - amigaos*) - archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec_F77='-L$libdir' - hardcode_minus_L_F77=yes - # see comment about different semantics on the GNU ld section - ld_shlibs_F77=no - ;; - - bsdi[45]*) - export_dynamic_flag_spec_F77=-rdynamic - ;; - - cygwin* | mingw* | pw32*) - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - hardcode_libdir_flag_spec_F77=' ' - allow_undefined_flag_F77=unsupported - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=".dll" - # FIXME: Setting linknames here is a bad hack. - archive_cmds_F77='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' - # The linker will automatically build a .lib file if we build a DLL. - old_archive_From_new_cmds_F77='true' - # FIXME: Should let the user specify the lib program. - old_archive_cmds_F77='lib -OUT:$oldlib$oldobjs$old_deplibs' - fix_srcfile_path_F77='`cygpath -w "$srcfile"`' - enable_shared_with_static_runtimes_F77=yes - ;; - - darwin* | rhapsody*) - case $host_os in - rhapsody* | darwin1.[012]) - allow_undefined_flag_F77='${wl}-undefined ${wl}suppress' - ;; - *) # Darwin 1.3 on - if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then - allow_undefined_flag_F77='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' - else - case ${MACOSX_DEPLOYMENT_TARGET} in - 10.[012]) - allow_undefined_flag_F77='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' - ;; - 10.*) - allow_undefined_flag_F77='${wl}-undefined ${wl}dynamic_lookup' - ;; - esac - fi - ;; - esac - archive_cmds_need_lc_F77=no - hardcode_direct_F77=no - hardcode_automatic_F77=yes - hardcode_shlibpath_var_F77=unsupported - whole_archive_flag_spec_F77='' - link_all_deplibs_F77=yes - if test "$GCC" = yes ; then - output_verbose_link_cmd='echo' - archive_cmds_F77='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' - module_cmds_F77='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' - # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds - archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - else - case $cc_basename in - xlc*) - output_verbose_link_cmd='echo' - archive_cmds_F77='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring' - module_cmds_F77='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' - # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds - archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - ;; - *) - ld_shlibs_F77=no - ;; - esac - fi - ;; - - dgux*) - archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec_F77='-L$libdir' - hardcode_shlibpath_var_F77=no - ;; - - freebsd1*) - ld_shlibs_F77=no - ;; - - # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor - # support. Future versions do this automatically, but an explicit c++rt0.o - # does not break anything, and helps significantly (at the cost of a little - # extra space). - freebsd2.2*) - archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' - hardcode_libdir_flag_spec_F77='-R$libdir' - hardcode_direct_F77=yes - hardcode_shlibpath_var_F77=no - ;; - - # Unfortunately, older versions of FreeBSD 2 do not have this feature. - freebsd2*) - archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct_F77=yes - hardcode_minus_L_F77=yes - hardcode_shlibpath_var_F77=no - ;; - - # FreeBSD 3 and greater uses gcc -shared to do shared libraries. - freebsd* | dragonfly*) - archive_cmds_F77='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec_F77='-R$libdir' - hardcode_direct_F77=yes - hardcode_shlibpath_var_F77=no - ;; - - hpux9*) - if test "$GCC" = yes; then - archive_cmds_F77='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - else - archive_cmds_F77='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - fi - hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' - hardcode_libdir_separator_F77=: - hardcode_direct_F77=yes - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L_F77=yes - export_dynamic_flag_spec_F77='${wl}-E' - ;; - - hpux10*) - if test "$GCC" = yes -a "$with_gnu_ld" = no; then - archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds_F77='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' - fi - if test "$with_gnu_ld" = no; then - hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' - hardcode_libdir_separator_F77=: - - hardcode_direct_F77=yes - export_dynamic_flag_spec_F77='${wl}-E' - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L_F77=yes - fi - ;; - - hpux11*) - if test "$GCC" = yes -a "$with_gnu_ld" = no; then - case $host_cpu in - hppa*64*) - archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - else - case $host_cpu in - hppa*64*) - archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - fi - if test "$with_gnu_ld" = no; then - hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' - hardcode_libdir_separator_F77=: - - case $host_cpu in - hppa*64*|ia64*) - hardcode_libdir_flag_spec_ld_F77='+b $libdir' - hardcode_direct_F77=no - hardcode_shlibpath_var_F77=no - ;; - *) - hardcode_direct_F77=yes - export_dynamic_flag_spec_F77='${wl}-E' - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L_F77=yes - ;; - esac - fi - ;; - - irix5* | irix6* | nonstopux*) - if test "$GCC" = yes; then - archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - else - archive_cmds_F77='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - hardcode_libdir_flag_spec_ld_F77='-rpath $libdir' - fi - hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator_F77=: - link_all_deplibs_F77=yes - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out - else - archive_cmds_F77='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF - fi - hardcode_libdir_flag_spec_F77='-R$libdir' - hardcode_direct_F77=yes - hardcode_shlibpath_var_F77=no - ;; - - newsos6) - archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct_F77=yes - hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator_F77=: - hardcode_shlibpath_var_F77=no - ;; - - openbsd*) - if test -f /usr/libexec/ld.so; then - hardcode_direct_F77=yes - hardcode_shlibpath_var_F77=no - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' - hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' - export_dynamic_flag_spec_F77='${wl}-E' - else - case $host_os in - openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) - archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec_F77='-R$libdir' - ;; - *) - archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' - ;; - esac - fi - else - ld_shlibs_F77=no - fi - ;; - - os2*) - hardcode_libdir_flag_spec_F77='-L$libdir' - hardcode_minus_L_F77=yes - allow_undefined_flag_F77=unsupported - archive_cmds_F77='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' - old_archive_From_new_cmds_F77='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' - ;; - - osf3*) - if test "$GCC" = yes; then - allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - else - allow_undefined_flag_F77=' -expect_unresolved \*' - archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - fi - hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator_F77=: - ;; - - osf4* | osf5*) # as osf3* with the addition of -msym flag - if test "$GCC" = yes; then - allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' - else - allow_undefined_flag_F77=' -expect_unresolved \*' - archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - archive_expsym_cmds_F77='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ - $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' - - # Both c and cxx compiler support -rpath directly - hardcode_libdir_flag_spec_F77='-rpath $libdir' - fi - hardcode_libdir_separator_F77=: - ;; - - solaris*) - no_undefined_flag_F77=' -z text' - if test "$GCC" = yes; then - wlarc='${wl}' - archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' - else - wlarc='' - archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' - archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' - fi - hardcode_libdir_flag_spec_F77='-R$libdir' - hardcode_shlibpath_var_F77=no - case $host_os in - solaris2.[0-5] | solaris2.[0-5].*) ;; - *) - # The compiler driver will combine and reorder linker options, - # but understands `-z linker_flag'. GCC discards it without `$wl', - # but is careful enough not to reorder. - # Supported since Solaris 2.6 (maybe 2.5.1?) - if test "$GCC" = yes; then - whole_archive_flag_spec_F77='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' - else - whole_archive_flag_spec_F77='-z allextract$convenience -z defaultextract' - fi - ;; - esac - link_all_deplibs_F77=yes - ;; - - sunos4*) - if test "x$host_vendor" = xsequent; then - # Use $CC to link under sequent, because it throws in some extra .o - # files that make .init and .fini sections work. - archive_cmds_F77='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds_F77='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' - fi - hardcode_libdir_flag_spec_F77='-L$libdir' - hardcode_direct_F77=yes - hardcode_minus_L_F77=yes - hardcode_shlibpath_var_F77=no - ;; - - sysv4) - case $host_vendor in - sni) - archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct_F77=yes # is this really true??? - ;; - siemens) - ## LD is ld it makes a PLAMLIB - ## CC just makes a GrossModule. - archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags' - reload_cmds_F77='$CC -r -o $output$reload_objs' - hardcode_direct_F77=no - ;; - motorola) - archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct_F77=no #Motorola manual says yes, but my tests say they lie - ;; - esac - runpath_var='LD_RUN_PATH' - hardcode_shlibpath_var_F77=no - ;; - - sysv4.3*) - archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var_F77=no - export_dynamic_flag_spec_F77='-Bexport' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var_F77=no - runpath_var=LD_RUN_PATH - hardcode_runpath_var=yes - ld_shlibs_F77=yes - fi - ;; - - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) - no_undefined_flag_F77='${wl}-z,text' - archive_cmds_need_lc_F77=no - hardcode_shlibpath_var_F77=no - runpath_var='LD_RUN_PATH' - - if test "$GCC" = yes; then - archive_cmds_F77='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_F77='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds_F77='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_F77='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - sysv5* | sco3.2v5* | sco5v6*) - # Note: We can NOT use -z defs as we might desire, because we do not - # link with -lc, and that would cause any symbols used from libc to - # always be unresolved, which means just about no library would - # ever link correctly. If we're not using GNU ld we use -z text - # though, which does catch some bad symbols but isn't as heavy-handed - # as -z defs. - no_undefined_flag_F77='${wl}-z,text' - allow_undefined_flag_F77='${wl}-z,nodefs' - archive_cmds_need_lc_F77=no - hardcode_shlibpath_var_F77=no - hardcode_libdir_flag_spec_F77='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' - hardcode_libdir_separator_F77=':' - link_all_deplibs_F77=yes - export_dynamic_flag_spec_F77='${wl}-Bexport' - runpath_var='LD_RUN_PATH' - - if test "$GCC" = yes; then - archive_cmds_F77='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_F77='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds_F77='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_F77='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - uts4*) - archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec_F77='-L$libdir' - hardcode_shlibpath_var_F77=no - ;; - - *) - ld_shlibs_F77=no - ;; - esac - fi - -{ echo "$as_me:$LINENO: result: $ld_shlibs_F77" >&5 -echo "${ECHO_T}$ld_shlibs_F77" >&6; } -test "$ld_shlibs_F77" = no && can_build_shared=no - -# -# Do we need to explicitly link libc? -# -case "x$archive_cmds_need_lc_F77" in -x|xyes) - # Assume -lc should be added - archive_cmds_need_lc_F77=yes - - if test "$enable_shared" = yes && test "$GCC" = yes; then - case $archive_cmds_F77 in - *'~'*) - # FIXME: we may have to deal with multi-command sequences. - ;; - '$CC '*) - # Test whether the compiler implicitly links with -lc since on some - # systems, -lgcc has to come before -lc. If gcc already passes -lc - # to ld, don't add -lc before -lgcc. - { echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 -echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6; } - $rm conftest* - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$lt_prog_compiler_wl_F77 - pic_flag=$lt_prog_compiler_pic_F77 - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$allow_undefined_flag_F77 - allow_undefined_flag_F77= - if { (eval echo "$as_me:$LINENO: \"$archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 - (eval $archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - then - archive_cmds_need_lc_F77=no - else - archive_cmds_need_lc_F77=yes - fi - allow_undefined_flag_F77=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $rm conftest* - { echo "$as_me:$LINENO: result: $archive_cmds_need_lc_F77" >&5 -echo "${ECHO_T}$archive_cmds_need_lc_F77" >&6; } - ;; - esac - fi - ;; -esac - -{ echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 -echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6; } -library_names_spec= -libname_spec='lib$name' -soname_spec= -shrext_cmds=".so" -postinstall_cmds= -postuninstall_cmds= -finish_cmds= -finish_eval= -shlibpath_var= -shlibpath_overrides_runpath=unknown -version_type=none -dynamic_linker="$host_os ld.so" -sys_lib_dlsearch_path_spec="/lib /usr/lib" - -need_lib_prefix=unknown -hardcode_into_libs=no - -# when you set need_version to no, make sure it does not cause -set_version -# flags to be left without arguments -need_version=unknown - -case $host_os in -aix3*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' - shlibpath_var=LIBPATH - - # AIX 3 has no versioning support, so we append a major version to the name. - soname_spec='${libname}${release}${shared_ext}$major' - ;; - -aix4* | aix5*) - version_type=linux - need_lib_prefix=no - need_version=no - hardcode_into_libs=yes - if test "$host_cpu" = ia64; then - # AIX 5 supports IA64 - library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - else - # With GCC up to 2.95.x, collect2 would create an import file - # for dependence libraries. The import file would start with - # the line `#! .'. This would cause the generated library to - # depend on `.', always an invalid library. This was fixed in - # development snapshots of GCC prior to 3.0. - case $host_os in - aix4 | aix4.[01] | aix4.[01].*) - if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' - echo ' yes ' - echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then - : - else - can_build_shared=no - fi - ;; - esac - # AIX (on Power*) has no versioning support, so currently we can not hardcode correct - # soname into executable. Probably we can add versioning support to - # collect2, so additional links can be useful in future. - if test "$aix_use_runtimelinking" = yes; then - # If using run time linking (on AIX 4.2 or later) use lib.so - # instead of lib.a to let people know that these are not - # typical AIX shared libraries. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - else - # We preserve .a as extension for shared libraries through AIX4.2 - # and later when we are not doing run time linking. - library_names_spec='${libname}${release}.a $libname.a' - soname_spec='${libname}${release}${shared_ext}$major' - fi - shlibpath_var=LIBPATH - fi - ;; - -amigaos*) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' - ;; - -beos*) - library_names_spec='${libname}${shared_ext}' - dynamic_linker="$host_os ld.so" - shlibpath_var=LIBRARY_PATH - ;; - -bsdi[45]*) - version_type=linux - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" - sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" - # the default ld.so.conf also contains /usr/contrib/lib and - # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow - # libtool to hard-code these into programs - ;; - -cygwin* | mingw* | pw32*) - version_type=windows - shrext_cmds=".dll" - need_version=no - need_lib_prefix=no - - case $GCC,$host_os in - yes,cygwin* | yes,mingw* | yes,pw32*) - library_names_spec='$libname.dll.a' - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \${file}`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $rm \$dlpath' - shlibpath_overrides_runpath=yes - - case $host_os in - cygwin*) - # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" - ;; - mingw*) - # MinGW DLLs use traditional 'lib' prefix - soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` - if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then - # It is most probably a Windows format PATH printed by - # mingw gcc, but we are running on Cygwin. Gcc prints its search - # path with ; separators, and with drive letters. We can handle the - # drive letters (cygwin fileutils understands them), so leave them, - # especially as we might pass files found there to a mingw objdump, - # which wouldn't understand a cygwinified path. Ahh. - sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi - ;; - pw32*) - # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - ;; - esac - ;; - - *) - library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' - ;; - esac - dynamic_linker='Win32 ld.exe' - # FIXME: first we should search . and the directory the executable is in - shlibpath_var=PATH - ;; - -darwin* | rhapsody*) - dynamic_linker="$host_os dyld" - version_type=darwin - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' - soname_spec='${libname}${release}${major}$shared_ext' - shlibpath_overrides_runpath=yes - shlibpath_var=DYLD_LIBRARY_PATH - shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' - - sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' - ;; - -dgux*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -freebsd1*) - dynamic_linker=no - ;; - -freebsd* | dragonfly*) - # DragonFly does not have aout. When/if they implement a new - # versioning mechanism, adjust this. - if test -x /usr/bin/objformat; then - objformat=`/usr/bin/objformat` - else - case $host_os in - freebsd[123]*) objformat=aout ;; - *) objformat=elf ;; - esac - fi - version_type=freebsd-$objformat - case $version_type in - freebsd-elf*) - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - need_version=no - need_lib_prefix=no - ;; - freebsd-*) - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' - need_version=yes - ;; - esac - shlibpath_var=LD_LIBRARY_PATH - case $host_os in - freebsd2*) - shlibpath_overrides_runpath=yes - ;; - freebsd3.[01]* | freebsdelf3.[01]*) - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ - freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - *) # from 4.6 on, and DragonFly - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - esac - ;; - -gnu*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - hardcode_into_libs=yes - ;; - -hpux9* | hpux10* | hpux11*) - # Give a soname corresponding to the major version so that dld.sl refuses to - # link against other versions. - version_type=sunos - need_lib_prefix=no - need_version=no - case $host_cpu in - ia64*) - shrext_cmds='.so' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.so" - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - if test "X$HPUX_IA64_MODE" = X32; then - sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" - else - sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" - fi - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - hppa*64*) - shrext_cmds='.sl' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.sl" - shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - *) - shrext_cmds='.sl' - dynamic_linker="$host_os dld.sl" - shlibpath_var=SHLIB_PATH - shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - ;; - esac - # HP-UX runs *really* slowly unless shared libraries are mode 555. - postinstall_cmds='chmod 555 $lib' - ;; - -interix[3-9]*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -irix5* | irix6* | nonstopux*) - case $host_os in - nonstopux*) version_type=nonstopux ;; - *) - if test "$lt_cv_prog_gnu_ld" = yes; then - version_type=linux - else - version_type=irix - fi ;; - esac - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' - case $host_os in - irix5* | nonstopux*) - libsuff= shlibsuff= - ;; - *) - case $LD in # libtool.m4 will add one of these switches to LD - *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") - libsuff= shlibsuff= libmagic=32-bit;; - *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") - libsuff=32 shlibsuff=N32 libmagic=N32;; - *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") - libsuff=64 shlibsuff=64 libmagic=64-bit;; - *) libsuff= shlibsuff= libmagic=never-match;; - esac - ;; - esac - shlibpath_var=LD_LIBRARY${shlibsuff}_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" - sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" - hardcode_into_libs=yes - ;; - -# No shared lib support for Linux oldld, aout, or coff. -linux*oldld* | linux*aout* | linux*coff*) - dynamic_linker=no - ;; - -# This must be Linux ELF. -linux* | k*bsd*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - # Append ld.so.conf contents to the search path - if test -f /etc/ld.so.conf; then - lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` - sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" - fi - - # We used to test for /lib/ld.so.1 and disable shared libraries on - # powerpc, because MkLinux only supported shared libraries with the - # GNU dynamic linker. Since this was broken with cross compilers, - # most powerpc-linux boxes support dynamic linking these days and - # people can always --disable-shared, the test was removed, and we - # assume the GNU/Linux dynamic linker is in use. - dynamic_linker='GNU/Linux ld.so' - ;; - -netbsdelf*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='NetBSD ld.elf_so' - ;; - -netbsd*) - version_type=sunos - need_lib_prefix=no - need_version=no - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - dynamic_linker='NetBSD (a.out) ld.so' - else - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='NetBSD ld.elf_so' - fi - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - -newsos6) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -nto-qnx*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -openbsd*) - version_type=sunos - sys_lib_dlsearch_path_spec="/usr/lib" - need_lib_prefix=no - # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. - case $host_os in - openbsd3.3 | openbsd3.3.*) need_version=yes ;; - *) need_version=no ;; - esac - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - case $host_os in - openbsd2.[89] | openbsd2.[89].*) - shlibpath_overrides_runpath=no - ;; - *) - shlibpath_overrides_runpath=yes - ;; - esac - else - shlibpath_overrides_runpath=yes - fi - ;; - -os2*) - libname_spec='$name' - shrext_cmds=".dll" - need_lib_prefix=no - library_names_spec='$libname${shared_ext} $libname.a' - dynamic_linker='OS/2 ld.exe' - shlibpath_var=LIBPATH - ;; - -osf3* | osf4* | osf5*) - version_type=osf - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" - ;; - -rdos*) - dynamic_linker=no - ;; - -solaris*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - # ldd complains unless libraries are executable - postinstall_cmds='chmod +x $lib' - ;; - -sunos4*) - version_type=sunos - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - if test "$with_gnu_ld" = yes; then - need_lib_prefix=no - fi - need_version=yes - ;; - -sysv4 | sysv4.3*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - case $host_vendor in - sni) - shlibpath_overrides_runpath=no - need_lib_prefix=no - export_dynamic_flag_spec='${wl}-Blargedynsym' - runpath_var=LD_RUN_PATH - ;; - siemens) - need_lib_prefix=no - ;; - motorola) - need_lib_prefix=no - need_version=no - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' - ;; - esac - ;; - -sysv4*MP*) - if test -d /usr/nec ;then - version_type=linux - library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' - soname_spec='$libname${shared_ext}.$major' - shlibpath_var=LD_LIBRARY_PATH - fi - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - version_type=freebsd-elf - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - hardcode_into_libs=yes - if test "$with_gnu_ld" = yes; then - sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' - shlibpath_overrides_runpath=no - else - sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' - shlibpath_overrides_runpath=yes - case $host_os in - sco3.2v5*) - sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" - ;; - esac - fi - sys_lib_dlsearch_path_spec='/usr/lib' - ;; - -uts4*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -*) - dynamic_linker=no - ;; -esac -{ echo "$as_me:$LINENO: result: $dynamic_linker" >&5 -echo "${ECHO_T}$dynamic_linker" >&6; } -test "$dynamic_linker" = no && can_build_shared=no - -variables_saved_for_relink="PATH $shlibpath_var $runpath_var" -if test "$GCC" = yes; then - variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" -fi - -{ echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 -echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6; } -hardcode_action_F77= -if test -n "$hardcode_libdir_flag_spec_F77" || \ - test -n "$runpath_var_F77" || \ - test "X$hardcode_automatic_F77" = "Xyes" ; then - - # We can hardcode non-existant directories. - if test "$hardcode_direct_F77" != no && - # If the only mechanism to avoid hardcoding is shlibpath_var, we - # have to relink, otherwise we might link with an installed library - # when we should be linking with a yet-to-be-installed one - ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, F77)" != no && - test "$hardcode_minus_L_F77" != no; then - # Linking always hardcodes the temporary library directory. - hardcode_action_F77=relink - else - # We can link without hardcoding, and we can hardcode nonexisting dirs. - hardcode_action_F77=immediate - fi -else - # We cannot hardcode anything, or else we can only hardcode existing - # directories. - hardcode_action_F77=unsupported -fi -{ echo "$as_me:$LINENO: result: $hardcode_action_F77" >&5 -echo "${ECHO_T}$hardcode_action_F77" >&6; } - -if test "$hardcode_action_F77" = relink; then - # Fast installation is not supported - enable_fast_install=no -elif test "$shlibpath_overrides_runpath" = yes || - test "$enable_shared" = no; then - # Fast installation is not necessary - enable_fast_install=needless -fi - - -# The else clause should only fire when bootstrapping the -# libtool distribution, otherwise you forgot to ship ltmain.sh -# with your package, and you will get complaints that there are -# no rules to generate ltmain.sh. -if test -f "$ltmain"; then - # See if we are running on zsh, and set the options which allow our commands through - # without removal of \ escapes. - if test -n "${ZSH_VERSION+set}" ; then - setopt NO_GLOB_SUBST - fi - # Now quote all the things that may contain metacharacters while being - # careful not to overquote the AC_SUBSTed values. We take copies of the - # variables and quote the copies for generation of the libtool script. - for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ - SED SHELL STRIP \ - libname_spec library_names_spec soname_spec extract_expsyms_cmds \ - old_striplib striplib file_magic_cmd finish_cmds finish_eval \ - deplibs_check_method reload_flag reload_cmds need_locks \ - lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ - lt_cv_sys_global_symbol_to_c_name_address \ - sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ - old_postinstall_cmds old_postuninstall_cmds \ - compiler_F77 \ - CC_F77 \ - LD_F77 \ - lt_prog_compiler_wl_F77 \ - lt_prog_compiler_pic_F77 \ - lt_prog_compiler_static_F77 \ - lt_prog_compiler_no_builtin_flag_F77 \ - export_dynamic_flag_spec_F77 \ - thread_safe_flag_spec_F77 \ - whole_archive_flag_spec_F77 \ - enable_shared_with_static_runtimes_F77 \ - old_archive_cmds_F77 \ - old_archive_from_new_cmds_F77 \ - predep_objects_F77 \ - postdep_objects_F77 \ - predeps_F77 \ - postdeps_F77 \ - compiler_lib_search_path_F77 \ - archive_cmds_F77 \ - archive_expsym_cmds_F77 \ - postinstall_cmds_F77 \ - postuninstall_cmds_F77 \ - old_archive_from_expsyms_cmds_F77 \ - allow_undefined_flag_F77 \ - no_undefined_flag_F77 \ - export_symbols_cmds_F77 \ - hardcode_libdir_flag_spec_F77 \ - hardcode_libdir_flag_spec_ld_F77 \ - hardcode_libdir_separator_F77 \ - hardcode_automatic_F77 \ - module_cmds_F77 \ - module_expsym_cmds_F77 \ - lt_cv_prog_compiler_c_o_F77 \ - fix_srcfile_path_F77 \ - exclude_expsyms_F77 \ - include_expsyms_F77; do - - case $var in - old_archive_cmds_F77 | \ - old_archive_from_new_cmds_F77 | \ - archive_cmds_F77 | \ - archive_expsym_cmds_F77 | \ - module_cmds_F77 | \ - module_expsym_cmds_F77 | \ - old_archive_from_expsyms_cmds_F77 | \ - export_symbols_cmds_F77 | \ - extract_expsyms_cmds | reload_cmds | finish_cmds | \ - postinstall_cmds | postuninstall_cmds | \ - old_postinstall_cmds | old_postuninstall_cmds | \ - sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) - # Double-quote double-evaled strings. - eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" - ;; - *) - eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" - ;; - esac - done - - case $lt_echo in - *'\$0 --fallback-echo"') - lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` - ;; - esac - -cfgfile="$ofile" - - cat <<__EOF__ >> "$cfgfile" -# ### BEGIN LIBTOOL TAG CONFIG: $tagname - -# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: - -# Shell to use when invoking shell scripts. -SHELL=$lt_SHELL - -# Whether or not to build shared libraries. -build_libtool_libs=$enable_shared - -# Whether or not to build static libraries. -build_old_libs=$enable_static - -# Whether or not to add -lc for building shared libraries. -build_libtool_need_lc=$archive_cmds_need_lc_F77 - -# Whether or not to disallow shared libs when runtime libs are static -allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_F77 - -# Whether or not to optimize for fast installation. -fast_install=$enable_fast_install - -# The host system. -host_alias=$host_alias -host=$host -host_os=$host_os - -# The build system. -build_alias=$build_alias -build=$build -build_os=$build_os - -# An echo program that does not interpret backslashes. -echo=$lt_echo - -# The archiver. -AR=$lt_AR -AR_FLAGS=$lt_AR_FLAGS - -# A C compiler. -LTCC=$lt_LTCC - -# LTCC compiler flags. -LTCFLAGS=$lt_LTCFLAGS - -# A language-specific compiler. -CC=$lt_compiler_F77 - -# Is the compiler the GNU C compiler? -with_gcc=$GCC_F77 - -# An ERE matcher. -EGREP=$lt_EGREP - -# The linker used to build libraries. -LD=$lt_LD_F77 - -# Whether we need hard or soft links. -LN_S=$lt_LN_S - -# A BSD-compatible nm program. -NM=$lt_NM - -# A symbol stripping program -STRIP=$lt_STRIP - -# Used to examine libraries when file_magic_cmd begins "file" -MAGIC_CMD=$MAGIC_CMD - -# Used on cygwin: DLL creation program. -DLLTOOL="$DLLTOOL" - -# Used on cygwin: object dumper. -OBJDUMP="$OBJDUMP" - -# Used on cygwin: assembler. -AS="$AS" - -# The name of the directory that contains temporary libtool files. -objdir=$objdir - -# How to create reloadable object files. -reload_flag=$lt_reload_flag -reload_cmds=$lt_reload_cmds - -# How to pass a linker flag through the compiler. -wl=$lt_lt_prog_compiler_wl_F77 - -# Object file suffix (normally "o"). -objext="$ac_objext" - -# Old archive suffix (normally "a"). -libext="$libext" - -# Shared library suffix (normally ".so"). -shrext_cmds='$shrext_cmds' - -# Executable file suffix (normally ""). -exeext="$exeext" - -# Additional compiler flags for building library objects. -pic_flag=$lt_lt_prog_compiler_pic_F77 -pic_mode=$pic_mode - -# What is the maximum length of a command? -max_cmd_len=$lt_cv_sys_max_cmd_len - -# Does compiler simultaneously support -c and -o options? -compiler_c_o=$lt_lt_cv_prog_compiler_c_o_F77 - -# Must we lock files when doing compilation? -need_locks=$lt_need_locks - -# Do we need the lib prefix for modules? -need_lib_prefix=$need_lib_prefix - -# Do we need a version for libraries? -need_version=$need_version - -# Whether dlopen is supported. -dlopen_support=$enable_dlopen - -# Whether dlopen of programs is supported. -dlopen_self=$enable_dlopen_self - -# Whether dlopen of statically linked programs is supported. -dlopen_self_static=$enable_dlopen_self_static - -# Compiler flag to prevent dynamic linking. -link_static_flag=$lt_lt_prog_compiler_static_F77 - -# Compiler flag to turn off builtin functions. -no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_F77 - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_F77 - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec=$lt_whole_archive_flag_spec_F77 - -# Compiler flag to generate thread-safe objects. -thread_safe_flag_spec=$lt_thread_safe_flag_spec_F77 - -# Library versioning type. -version_type=$version_type - -# Format of library name prefix. -libname_spec=$lt_libname_spec - -# List of archive names. First name is the real one, the rest are links. -# The last name is the one that the linker finds with -lNAME. -library_names_spec=$lt_library_names_spec - -# The coded name of the library, if different from the real name. -soname_spec=$lt_soname_spec - -# Commands used to build and install an old-style archive. -RANLIB=$lt_RANLIB -old_archive_cmds=$lt_old_archive_cmds_F77 -old_postinstall_cmds=$lt_old_postinstall_cmds -old_postuninstall_cmds=$lt_old_postuninstall_cmds - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_F77 - -# Create a temporary old-style archive to link instead of a shared archive. -old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_F77 - -# Commands used to build and install a shared archive. -archive_cmds=$lt_archive_cmds_F77 -archive_expsym_cmds=$lt_archive_expsym_cmds_F77 -postinstall_cmds=$lt_postinstall_cmds -postuninstall_cmds=$lt_postuninstall_cmds - -# Commands used to build a loadable module (assumed same as above if empty) -module_cmds=$lt_module_cmds_F77 -module_expsym_cmds=$lt_module_expsym_cmds_F77 - -# Commands to strip libraries. -old_striplib=$lt_old_striplib -striplib=$lt_striplib - -# Dependencies to place before the objects being linked to create a -# shared library. -predep_objects=$lt_predep_objects_F77 - -# Dependencies to place after the objects being linked to create a -# shared library. -postdep_objects=$lt_postdep_objects_F77 - -# Dependencies to place before the objects being linked to create a -# shared library. -predeps=$lt_predeps_F77 - -# Dependencies to place after the objects being linked to create a -# shared library. -postdeps=$lt_postdeps_F77 - -# The library search path used internally by the compiler when linking -# a shared library. -compiler_lib_search_path=$lt_compiler_lib_search_path_F77 - -# Method to check whether dependent libraries are shared objects. -deplibs_check_method=$lt_deplibs_check_method - -# Command to use when deplibs_check_method == file_magic. -file_magic_cmd=$lt_file_magic_cmd - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag=$lt_allow_undefined_flag_F77 - -# Flag that forces no undefined symbols. -no_undefined_flag=$lt_no_undefined_flag_F77 - -# Commands used to finish a libtool library installation in a directory. -finish_cmds=$lt_finish_cmds - -# Same as above, but a single script fragment to be evaled but not shown. -finish_eval=$lt_finish_eval - -# Take the output of nm and produce a listing of raw symbols and C names. -global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe - -# Transform the output of nm in a proper C declaration -global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl - -# Transform the output of nm in a C name address pair -global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address - -# This is the shared library runtime path variable. -runpath_var=$runpath_var - -# This is the shared library path variable. -shlibpath_var=$shlibpath_var - -# Is shlibpath searched before the hard-coded library search path? -shlibpath_overrides_runpath=$shlibpath_overrides_runpath - -# How to hardcode a shared library path into an executable. -hardcode_action=$hardcode_action_F77 - -# Whether we should hardcode library paths into libraries. -hardcode_into_libs=$hardcode_into_libs - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist. -hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_F77 - -# If ld is used when linking, flag to hardcode \$libdir into -# a binary during linking. This must work even if \$libdir does -# not exist. -hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_F77 - -# Whether we need a single -rpath flag with a separated argument. -hardcode_libdir_separator=$lt_hardcode_libdir_separator_F77 - -# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the -# resulting binary. -hardcode_direct=$hardcode_direct_F77 - -# Set to yes if using the -LDIR flag during linking hardcodes DIR into the -# resulting binary. -hardcode_minus_L=$hardcode_minus_L_F77 - -# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into -# the resulting binary. -hardcode_shlibpath_var=$hardcode_shlibpath_var_F77 - -# Set to yes if building a shared library automatically hardcodes DIR into the library -# and all subsequent libraries and executables linked against it. -hardcode_automatic=$hardcode_automatic_F77 - -# Variables whose values should be saved in libtool wrapper scripts and -# restored at relink time. -variables_saved_for_relink="$variables_saved_for_relink" - -# Whether libtool must link a program against all its dependency libraries. -link_all_deplibs=$link_all_deplibs_F77 - -# Compile-time system search path for libraries -sys_lib_search_path_spec=$lt_sys_lib_search_path_spec - -# Run-time system search path for libraries -sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec - -# Fix the shell variable \$srcfile for the compiler. -fix_srcfile_path=$lt_fix_srcfile_path - -# Set to yes if exported symbols are required. -always_export_symbols=$always_export_symbols_F77 - -# The commands to list exported symbols. -export_symbols_cmds=$lt_export_symbols_cmds_F77 - -# The commands to extract the exported symbol list from a shared archive. -extract_expsyms_cmds=$lt_extract_expsyms_cmds - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms=$lt_exclude_expsyms_F77 - -# Symbols that must always be exported. -include_expsyms=$lt_include_expsyms_F77 - -# ### END LIBTOOL TAG CONFIG: $tagname - -__EOF__ - - -else - # If there is no Makefile yet, we rely on a make rule to execute - # `config.status --recheck' to rerun these tests and create the - # libtool script then. - ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` - if test -f "$ltmain_in"; then - test -f Makefile && make "$ltmain" - fi -fi - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -CC="$lt_save_CC" - - else - tagname="" - fi - ;; - - GCJ) - if test -n "$GCJ" && test "X$GCJ" != "Xno"; then - - -# Source file extension for Java test sources. -ac_ext=java - -# Object file extension for compiled Java test sources. -objext=o -objext_GCJ=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="class foo {}" - -# Code to be used in simple link tests -lt_simple_link_test_code='public class conftest { public static void main(String[] argv) {}; }' - -# ltmain only uses $CC for tagged configurations so make sure $CC is set. - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - - -# save warnings/boilerplate of simple test code -ac_outfile=conftest.$ac_objext -echo "$lt_simple_compile_test_code" >conftest.$ac_ext -eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_compiler_boilerplate=`cat conftest.err` -$rm conftest* - -ac_outfile=conftest.$ac_objext -echo "$lt_simple_link_test_code" >conftest.$ac_ext -eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_linker_boilerplate=`cat conftest.err` -$rm conftest* - - -# Allow CC to be a program name with arguments. -lt_save_CC="$CC" -CC=${GCJ-"gcj"} -compiler=$CC -compiler_GCJ=$CC -for cc_temp in $compiler""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac -done -cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` - - -# GCJ did not exist at the time GCC didn't implicitly link libc in. -archive_cmds_need_lc_GCJ=no - -old_archive_cmds_GCJ=$old_archive_cmds - -## CAVEAT EMPTOR: -## There is no encapsulation within the following macros, do not change -## the running order or otherwise move them around unless you know exactly -## what you are doing... - -lt_prog_compiler_no_builtin_flag_GCJ= - -if test "$GCC" = yes; then - lt_prog_compiler_no_builtin_flag_GCJ=' -fno-builtin' - - -{ echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 -echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6; } -if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - lt_cv_prog_compiler_rtti_exceptions=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="-fno-rtti -fno-exceptions" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:16836: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:16840: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_rtti_exceptions=yes - fi - fi - $rm conftest* - -fi -{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 -echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6; } - -if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then - lt_prog_compiler_no_builtin_flag_GCJ="$lt_prog_compiler_no_builtin_flag_GCJ -fno-rtti -fno-exceptions" -else - : -fi - -fi - -lt_prog_compiler_wl_GCJ= -lt_prog_compiler_pic_GCJ= -lt_prog_compiler_static_GCJ= - -{ echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 -echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6; } - - if test "$GCC" = yes; then - lt_prog_compiler_wl_GCJ='-Wl,' - lt_prog_compiler_static_GCJ='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static_GCJ='-Bstatic' - fi - ;; - - amigaos*) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the `-m68020' flag to GCC prevents building anything better, - # like `-m68040'. - lt_prog_compiler_pic_GCJ='-m68020 -resident32 -malways-restore-a4' - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - - mingw* | cygwin* | pw32* | os2*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - lt_prog_compiler_pic_GCJ='-DDLL_EXPORT' - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic_GCJ='-fno-common' - ;; - - interix[3-9]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - - msdosdjgpp*) - # Just because we use GCC doesn't mean we suddenly get shared libraries - # on systems that don't support them. - lt_prog_compiler_can_build_shared_GCJ=no - enable_shared=no - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic_GCJ=-Kconform_pic - fi - ;; - - hpux*) - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic_GCJ='-fPIC' - ;; - esac - ;; - - *) - lt_prog_compiler_pic_GCJ='-fPIC' - ;; - esac - else - # PORTME Check for flag to pass linker flags through the system compiler. - case $host_os in - aix*) - lt_prog_compiler_wl_GCJ='-Wl,' - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static_GCJ='-Bstatic' - else - lt_prog_compiler_static_GCJ='-bnso -bI:/lib/syscalls.exp' - fi - ;; - darwin*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - case $cc_basename in - xlc*) - lt_prog_compiler_pic_GCJ='-qnocommon' - lt_prog_compiler_wl_GCJ='-Wl,' - ;; - esac - ;; - - mingw* | cygwin* | pw32* | os2*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - lt_prog_compiler_pic_GCJ='-DDLL_EXPORT' - ;; - - hpux9* | hpux10* | hpux11*) - lt_prog_compiler_wl_GCJ='-Wl,' - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic_GCJ='+Z' - ;; - esac - # Is there a better lt_prog_compiler_static that works with the bundled CC? - lt_prog_compiler_static_GCJ='${wl}-a ${wl}archive' - ;; - - irix5* | irix6* | nonstopux*) - lt_prog_compiler_wl_GCJ='-Wl,' - # PIC (with -KPIC) is the default. - lt_prog_compiler_static_GCJ='-non_shared' - ;; - - newsos6) - lt_prog_compiler_pic_GCJ='-KPIC' - lt_prog_compiler_static_GCJ='-Bstatic' - ;; - - linux* | k*bsd*-gnu) - case $cc_basename in - icc* | ecc*) - lt_prog_compiler_wl_GCJ='-Wl,' - lt_prog_compiler_pic_GCJ='-KPIC' - lt_prog_compiler_static_GCJ='-static' - ;; - pgcc* | pgf77* | pgf90* | pgf95*) - # Portland Group compilers (*not* the Pentium gcc compiler, - # which looks to be a dead project) - lt_prog_compiler_wl_GCJ='-Wl,' - lt_prog_compiler_pic_GCJ='-fpic' - lt_prog_compiler_static_GCJ='-Bstatic' - ;; - ccc*) - lt_prog_compiler_wl_GCJ='-Wl,' - # All Alpha code is PIC. - lt_prog_compiler_static_GCJ='-non_shared' - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) - # Sun C 5.9 - lt_prog_compiler_pic_GCJ='-KPIC' - lt_prog_compiler_static_GCJ='-Bstatic' - lt_prog_compiler_wl_GCJ='-Wl,' - ;; - *Sun\ F*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - lt_prog_compiler_pic_GCJ='-KPIC' - lt_prog_compiler_static_GCJ='-Bstatic' - lt_prog_compiler_wl_GCJ='' - ;; - esac - ;; - esac - ;; - - osf3* | osf4* | osf5*) - lt_prog_compiler_wl_GCJ='-Wl,' - # All OSF/1 code is PIC. - lt_prog_compiler_static_GCJ='-non_shared' - ;; - - rdos*) - lt_prog_compiler_static_GCJ='-non_shared' - ;; - - solaris*) - lt_prog_compiler_pic_GCJ='-KPIC' - lt_prog_compiler_static_GCJ='-Bstatic' - case $cc_basename in - f77* | f90* | f95*) - lt_prog_compiler_wl_GCJ='-Qoption ld ';; - *) - lt_prog_compiler_wl_GCJ='-Wl,';; - esac - ;; - - sunos4*) - lt_prog_compiler_wl_GCJ='-Qoption ld ' - lt_prog_compiler_pic_GCJ='-PIC' - lt_prog_compiler_static_GCJ='-Bstatic' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3*) - lt_prog_compiler_wl_GCJ='-Wl,' - lt_prog_compiler_pic_GCJ='-KPIC' - lt_prog_compiler_static_GCJ='-Bstatic' - ;; - - sysv4*MP*) - if test -d /usr/nec ;then - lt_prog_compiler_pic_GCJ='-Kconform_pic' - lt_prog_compiler_static_GCJ='-Bstatic' - fi - ;; - - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - lt_prog_compiler_wl_GCJ='-Wl,' - lt_prog_compiler_pic_GCJ='-KPIC' - lt_prog_compiler_static_GCJ='-Bstatic' - ;; - - unicos*) - lt_prog_compiler_wl_GCJ='-Wl,' - lt_prog_compiler_can_build_shared_GCJ=no - ;; - - uts4*) - lt_prog_compiler_pic_GCJ='-pic' - lt_prog_compiler_static_GCJ='-Bstatic' - ;; - - *) - lt_prog_compiler_can_build_shared_GCJ=no - ;; - esac - fi - -{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_GCJ" >&5 -echo "${ECHO_T}$lt_prog_compiler_pic_GCJ" >&6; } - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$lt_prog_compiler_pic_GCJ"; then - -{ echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works" >&5 -echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works... $ECHO_C" >&6; } -if test "${lt_prog_compiler_pic_works_GCJ+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - lt_prog_compiler_pic_works_GCJ=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic_GCJ" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:17126: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:17130: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_prog_compiler_pic_works_GCJ=yes - fi - fi - $rm conftest* - -fi -{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_GCJ" >&5 -echo "${ECHO_T}$lt_prog_compiler_pic_works_GCJ" >&6; } - -if test x"$lt_prog_compiler_pic_works_GCJ" = xyes; then - case $lt_prog_compiler_pic_GCJ in - "" | " "*) ;; - *) lt_prog_compiler_pic_GCJ=" $lt_prog_compiler_pic_GCJ" ;; - esac -else - lt_prog_compiler_pic_GCJ= - lt_prog_compiler_can_build_shared_GCJ=no -fi - -fi -case $host_os in - # For platforms which do not support PIC, -DPIC is meaningless: - *djgpp*) - lt_prog_compiler_pic_GCJ= - ;; - *) - lt_prog_compiler_pic_GCJ="$lt_prog_compiler_pic_GCJ" - ;; -esac - -# -# Check to make sure the static flag actually works. -# -wl=$lt_prog_compiler_wl_GCJ eval lt_tmp_static_flag=\"$lt_prog_compiler_static_GCJ\" -{ echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 -echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6; } -if test "${lt_prog_compiler_static_works_GCJ+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - lt_prog_compiler_static_works_GCJ=no - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS $lt_tmp_static_flag" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_prog_compiler_static_works_GCJ=yes - fi - else - lt_prog_compiler_static_works_GCJ=yes - fi - fi - $rm conftest* - LDFLAGS="$save_LDFLAGS" - -fi -{ echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works_GCJ" >&5 -echo "${ECHO_T}$lt_prog_compiler_static_works_GCJ" >&6; } - -if test x"$lt_prog_compiler_static_works_GCJ" = xyes; then - : -else - lt_prog_compiler_static_GCJ= -fi - - -{ echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 -echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6; } -if test "${lt_cv_prog_compiler_c_o_GCJ+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - lt_cv_prog_compiler_c_o_GCJ=no - $rm -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:17230: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:17234: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o_GCJ=yes - fi - fi - chmod u+w . 2>&5 - $rm conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files - $rm out/* && rmdir out - cd .. - rmdir conftest - $rm conftest* - -fi -{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_GCJ" >&5 -echo "${ECHO_T}$lt_cv_prog_compiler_c_o_GCJ" >&6; } - - -hard_links="nottested" -if test "$lt_cv_prog_compiler_c_o_GCJ" = no && test "$need_locks" != no; then - # do not overwrite the value of need_locks provided by the user - { echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 -echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6; } - hard_links=yes - $rm conftest* - ln conftest.a conftest.b 2>/dev/null && hard_links=no - touch conftest.a - ln conftest.a conftest.b 2>&5 || hard_links=no - ln conftest.a conftest.b 2>/dev/null && hard_links=no - { echo "$as_me:$LINENO: result: $hard_links" >&5 -echo "${ECHO_T}$hard_links" >&6; } - if test "$hard_links" = no; then - { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 -echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} - need_locks=warn - fi -else - need_locks=no -fi - -{ echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 -echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6; } - - runpath_var= - allow_undefined_flag_GCJ= - enable_shared_with_static_runtimes_GCJ=no - archive_cmds_GCJ= - archive_expsym_cmds_GCJ= - old_archive_From_new_cmds_GCJ= - old_archive_from_expsyms_cmds_GCJ= - export_dynamic_flag_spec_GCJ= - whole_archive_flag_spec_GCJ= - thread_safe_flag_spec_GCJ= - hardcode_libdir_flag_spec_GCJ= - hardcode_libdir_flag_spec_ld_GCJ= - hardcode_libdir_separator_GCJ= - hardcode_direct_GCJ=no - hardcode_minus_L_GCJ=no - hardcode_shlibpath_var_GCJ=unsupported - link_all_deplibs_GCJ=unknown - hardcode_automatic_GCJ=no - module_cmds_GCJ= - module_expsym_cmds_GCJ= - always_export_symbols_GCJ=no - export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - # include_expsyms should be a list of space-separated symbols to be *always* - # included in the symbol list - include_expsyms_GCJ= - # exclude_expsyms can be an extended regexp of symbols to exclude - # it will be wrapped by ` (' and `)$', so one must not match beginning or - # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', - # as well as any symbol that contains `d'. - exclude_expsyms_GCJ="_GLOBAL_OFFSET_TABLE_" - # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out - # platforms (ab)use it in PIC code, but their linkers get confused if - # the symbol is explicitly referenced. Since portable code cannot - # rely on this symbol name, it's probably fine to never include it in - # preloaded symbol tables. - extract_expsyms_cmds= - # Just being paranoid about ensuring that cc_basename is set. - for cc_temp in $compiler""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac -done -cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` - - case $host_os in - cygwin* | mingw* | pw32*) - # FIXME: the MSVC++ port hasn't been tested in a loooong time - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - if test "$GCC" != yes; then - with_gnu_ld=no - fi - ;; - interix*) - # we just hope/assume this is gcc and not c89 (= MSVC++) - with_gnu_ld=yes - ;; - openbsd*) - with_gnu_ld=no - ;; - esac - - ld_shlibs_GCJ=yes - if test "$with_gnu_ld" = yes; then - # If archive_cmds runs LD, not CC, wlarc should be empty - wlarc='${wl}' - - # Set some defaults for GNU ld with shared library support. These - # are reset later if shared libraries are not supported. Putting them - # here allows them to be overridden if necessary. - runpath_var=LD_RUN_PATH - hardcode_libdir_flag_spec_GCJ='${wl}--rpath ${wl}$libdir' - export_dynamic_flag_spec_GCJ='${wl}--export-dynamic' - # ancient GNU ld didn't support --whole-archive et. al. - if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then - whole_archive_flag_spec_GCJ="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - else - whole_archive_flag_spec_GCJ= - fi - supports_anon_versioning=no - case `$LD -v 2>/dev/null` in - *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 - *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... - *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... - *\ 2.11.*) ;; # other 2.11 versions - *) supports_anon_versioning=yes ;; - esac - - # See if GNU ld supports shared libraries. - case $host_os in - aix3* | aix4* | aix5*) - # On AIX/PPC, the GNU linker is very broken - if test "$host_cpu" != ia64; then - ld_shlibs_GCJ=no - cat <&2 - -*** Warning: the GNU linker, at least up to release 2.9.1, is reported -*** to be unable to reliably create shared libraries on AIX. -*** Therefore, libtool is disabling shared libraries support. If you -*** really care for shared libraries, you may want to modify your PATH -*** so that a non-GNU linker is found, and then restart. - -EOF - fi - ;; - - amigaos*) - archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec_GCJ='-L$libdir' - hardcode_minus_L_GCJ=yes - - # Samuel A. Falvo II reports - # that the semantics of dynamic libraries on AmigaOS, at least up - # to version 4, is to share data among multiple programs linked - # with the same dynamic library. Since this doesn't match the - # behavior of shared libraries on other platforms, we can't use - # them. - ld_shlibs_GCJ=no - ;; - - beos*) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - allow_undefined_flag_GCJ=unsupported - # Joseph Beckenbach says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - archive_cmds_GCJ='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - else - ld_shlibs_GCJ=no - fi - ;; - - cygwin* | mingw* | pw32*) - # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, GCJ) is actually meaningless, - # as there is no search path for DLLs. - hardcode_libdir_flag_spec_GCJ='-L$libdir' - allow_undefined_flag_GCJ=unsupported - always_export_symbols_GCJ=no - enable_shared_with_static_runtimes_GCJ=yes - export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' - - if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then - archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file (1st line - # is EXPORTS), use it as is; otherwise, prepend... - archive_expsym_cmds_GCJ='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - else - ld_shlibs_GCJ=no - fi - ;; - - interix[3-9]*) - hardcode_direct_GCJ=no - hardcode_shlibpath_var_GCJ=no - hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' - export_dynamic_flag_spec_GCJ='${wl}-E' - # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. - # Instead, shared libraries are loaded at an image base (0x10000000 by - # default) and relocated if they conflict, which is a slow very memory - # consuming and fragmenting process. To avoid this, we pick a random, - # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link - # time. Moving up from 0x10000000 also allows more sbrk(2) space. - archive_cmds_GCJ='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - archive_expsym_cmds_GCJ='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - ;; - - gnu* | linux* | k*bsd*-gnu) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - tmp_addflag= - case $cc_basename,$host_cpu in - pgcc*) # Portland Group C compiler - whole_archive_flag_spec_GCJ='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' - tmp_addflag=' $pic_flag' - ;; - pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers - whole_archive_flag_spec_GCJ='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' - tmp_addflag=' $pic_flag -Mnomain' ;; - ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 - tmp_addflag=' -i_dynamic' ;; - efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 - tmp_addflag=' -i_dynamic -nofor_main' ;; - ifc* | ifort*) # Intel Fortran compiler - tmp_addflag=' -nofor_main' ;; - esac - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) # Sun C 5.9 - whole_archive_flag_spec_GCJ='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' - tmp_sharedflag='-G' ;; - *Sun\ F*) # Sun Fortran 8.3 - tmp_sharedflag='-G' ;; - *) - tmp_sharedflag='-shared' ;; - esac - archive_cmds_GCJ='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - - if test $supports_anon_versioning = yes; then - archive_expsym_cmds_GCJ='$echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - $echo "local: *; };" >> $output_objdir/$libname.ver~ - $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' - fi - link_all_deplibs_GCJ=no - else - ld_shlibs_GCJ=no - fi - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - archive_cmds_GCJ='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' - wlarc= - else - archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - fi - ;; - - solaris*) - if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then - ld_shlibs_GCJ=no - cat <&2 - -*** Warning: The releases 2.8.* of the GNU linker cannot reliably -*** create shared libraries on Solaris systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.9.1 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -EOF - elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs_GCJ=no - fi - ;; - - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) - case `$LD -v 2>&1` in - *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) - ld_shlibs_GCJ=no - cat <<_LT_EOF 1>&2 - -*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not -*** reliably create shared libraries on SCO systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.16.91.0.3 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - ;; - *) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - hardcode_libdir_flag_spec_GCJ='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' - archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' - archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' - else - ld_shlibs_GCJ=no - fi - ;; - esac - ;; - - sunos4*) - archive_cmds_GCJ='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' - wlarc= - hardcode_direct_GCJ=yes - hardcode_shlibpath_var_GCJ=no - ;; - - *) - if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then - archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs_GCJ=no - fi - ;; - esac - - if test "$ld_shlibs_GCJ" = no; then - runpath_var= - hardcode_libdir_flag_spec_GCJ= - export_dynamic_flag_spec_GCJ= - whole_archive_flag_spec_GCJ= - fi - else - # PORTME fill in a description of your system's linker (not GNU ld) - case $host_os in - aix3*) - allow_undefined_flag_GCJ=unsupported - always_export_symbols_GCJ=yes - archive_expsym_cmds_GCJ='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' - # Note: this linker hardcodes the directories in LIBPATH if there - # are no directories specified by -L. - hardcode_minus_L_GCJ=yes - if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then - # Neither direct hardcoding nor static linking is supported with a - # broken collect2. - hardcode_direct_GCJ=unsupported - fi - ;; - - aix4* | aix5*) - if test "$host_cpu" = ia64; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag="" - else - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to AIX nm, but means don't demangle with GNU nm - if $NM -V 2>&1 | grep 'GNU' > /dev/null; then - export_symbols_cmds_GCJ='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' - else - export_symbols_cmds_GCJ='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' - fi - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # need to do runtime linking. - case $host_os in aix4.[23]|aix4.[23].*|aix5*) - for ld_flag in $LDFLAGS; do - if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then - aix_use_runtimelinking=yes - break - fi - done - ;; - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - archive_cmds_GCJ='' - hardcode_direct_GCJ=yes - hardcode_libdir_separator_GCJ=':' - link_all_deplibs_GCJ=yes - - if test "$GCC" = yes; then - case $host_os in aix4.[012]|aix4.[012].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`${CC} -print-prog-name=collect2` - if test -f "$collect2name" && \ - strings "$collect2name" | grep resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - hardcode_direct_GCJ=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - hardcode_minus_L_GCJ=yes - hardcode_libdir_flag_spec_GCJ='-L$libdir' - hardcode_libdir_separator_GCJ= - fi - ;; - esac - shared_flag='-shared' - if test "$aix_use_runtimelinking" = yes; then - shared_flag="$shared_flag "'${wl}-G' - fi - else - # not using gcc - if test "$host_cpu" = ia64; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test "$aix_use_runtimelinking" = yes; then - shared_flag='${wl}-G' - else - shared_flag='${wl}-bM:SRE' - fi - fi - fi - - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to export. - always_export_symbols_GCJ=yes - if test "$aix_use_runtimelinking" = yes; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - allow_undefined_flag_GCJ='-berok' - # Determine the default libpath from the value encoded in an empty executable. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - -lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\(.*\)$/\1/ - p - } - }' -aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -# Check for a 64-bit object if we didn't find anything. -if test -z "$aix_libpath"; then - aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -fi -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi - - hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath" - archive_expsym_cmds_GCJ="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" - else - if test "$host_cpu" = ia64; then - hardcode_libdir_flag_spec_GCJ='${wl}-R $libdir:/usr/lib:/lib' - allow_undefined_flag_GCJ="-z nodefs" - archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an empty executable. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - -lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\(.*\)$/\1/ - p - } - }' -aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -# Check for a 64-bit object if we didn't find anything. -if test -z "$aix_libpath"; then - aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -fi -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi - - hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - no_undefined_flag_GCJ=' ${wl}-bernotok' - allow_undefined_flag_GCJ=' ${wl}-berok' - # Exported symbols can be pulled into shared objects from archives - whole_archive_flag_spec_GCJ='$convenience' - archive_cmds_need_lc_GCJ=yes - # This is similar to how AIX traditionally builds its shared libraries. - archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' - fi - fi - ;; - - amigaos*) - archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec_GCJ='-L$libdir' - hardcode_minus_L_GCJ=yes - # see comment about different semantics on the GNU ld section - ld_shlibs_GCJ=no - ;; - - bsdi[45]*) - export_dynamic_flag_spec_GCJ=-rdynamic - ;; - - cygwin* | mingw* | pw32*) - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - hardcode_libdir_flag_spec_GCJ=' ' - allow_undefined_flag_GCJ=unsupported - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=".dll" - # FIXME: Setting linknames here is a bad hack. - archive_cmds_GCJ='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' - # The linker will automatically build a .lib file if we build a DLL. - old_archive_From_new_cmds_GCJ='true' - # FIXME: Should let the user specify the lib program. - old_archive_cmds_GCJ='lib -OUT:$oldlib$oldobjs$old_deplibs' - fix_srcfile_path_GCJ='`cygpath -w "$srcfile"`' - enable_shared_with_static_runtimes_GCJ=yes - ;; - - darwin* | rhapsody*) - case $host_os in - rhapsody* | darwin1.[012]) - allow_undefined_flag_GCJ='${wl}-undefined ${wl}suppress' - ;; - *) # Darwin 1.3 on - if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then - allow_undefined_flag_GCJ='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' - else - case ${MACOSX_DEPLOYMENT_TARGET} in - 10.[012]) - allow_undefined_flag_GCJ='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' - ;; - 10.*) - allow_undefined_flag_GCJ='${wl}-undefined ${wl}dynamic_lookup' - ;; - esac - fi - ;; - esac - archive_cmds_need_lc_GCJ=no - hardcode_direct_GCJ=no - hardcode_automatic_GCJ=yes - hardcode_shlibpath_var_GCJ=unsupported - whole_archive_flag_spec_GCJ='' - link_all_deplibs_GCJ=yes - if test "$GCC" = yes ; then - output_verbose_link_cmd='echo' - archive_cmds_GCJ='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' - module_cmds_GCJ='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' - # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds - archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - else - case $cc_basename in - xlc*) - output_verbose_link_cmd='echo' - archive_cmds_GCJ='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring' - module_cmds_GCJ='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' - # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds - archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' - ;; - *) - ld_shlibs_GCJ=no - ;; - esac - fi - ;; - - dgux*) - archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec_GCJ='-L$libdir' - hardcode_shlibpath_var_GCJ=no - ;; - - freebsd1*) - ld_shlibs_GCJ=no - ;; - - # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor - # support. Future versions do this automatically, but an explicit c++rt0.o - # does not break anything, and helps significantly (at the cost of a little - # extra space). - freebsd2.2*) - archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' - hardcode_libdir_flag_spec_GCJ='-R$libdir' - hardcode_direct_GCJ=yes - hardcode_shlibpath_var_GCJ=no - ;; - - # Unfortunately, older versions of FreeBSD 2 do not have this feature. - freebsd2*) - archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct_GCJ=yes - hardcode_minus_L_GCJ=yes - hardcode_shlibpath_var_GCJ=no - ;; - - # FreeBSD 3 and greater uses gcc -shared to do shared libraries. - freebsd* | dragonfly*) - archive_cmds_GCJ='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec_GCJ='-R$libdir' - hardcode_direct_GCJ=yes - hardcode_shlibpath_var_GCJ=no - ;; - - hpux9*) - if test "$GCC" = yes; then - archive_cmds_GCJ='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - else - archive_cmds_GCJ='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - fi - hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' - hardcode_libdir_separator_GCJ=: - hardcode_direct_GCJ=yes - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L_GCJ=yes - export_dynamic_flag_spec_GCJ='${wl}-E' - ;; - - hpux10*) - if test "$GCC" = yes -a "$with_gnu_ld" = no; then - archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds_GCJ='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' - fi - if test "$with_gnu_ld" = no; then - hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' - hardcode_libdir_separator_GCJ=: - - hardcode_direct_GCJ=yes - export_dynamic_flag_spec_GCJ='${wl}-E' - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L_GCJ=yes - fi - ;; - - hpux11*) - if test "$GCC" = yes -a "$with_gnu_ld" = no; then - case $host_cpu in - hppa*64*) - archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - else - case $host_cpu in - hppa*64*) - archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - fi - if test "$with_gnu_ld" = no; then - hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' - hardcode_libdir_separator_GCJ=: - - case $host_cpu in - hppa*64*|ia64*) - hardcode_libdir_flag_spec_ld_GCJ='+b $libdir' - hardcode_direct_GCJ=no - hardcode_shlibpath_var_GCJ=no - ;; - *) - hardcode_direct_GCJ=yes - export_dynamic_flag_spec_GCJ='${wl}-E' - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L_GCJ=yes - ;; - esac - fi - ;; - - irix5* | irix6* | nonstopux*) - if test "$GCC" = yes; then - archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - else - archive_cmds_GCJ='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - hardcode_libdir_flag_spec_ld_GCJ='-rpath $libdir' - fi - hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator_GCJ=: - link_all_deplibs_GCJ=yes - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out - else - archive_cmds_GCJ='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF - fi - hardcode_libdir_flag_spec_GCJ='-R$libdir' - hardcode_direct_GCJ=yes - hardcode_shlibpath_var_GCJ=no - ;; - - newsos6) - archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct_GCJ=yes - hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator_GCJ=: - hardcode_shlibpath_var_GCJ=no - ;; - - openbsd*) - if test -f /usr/libexec/ld.so; then - hardcode_direct_GCJ=yes - hardcode_shlibpath_var_GCJ=no - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' - hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' - export_dynamic_flag_spec_GCJ='${wl}-E' - else - case $host_os in - openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) - archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec_GCJ='-R$libdir' - ;; - *) - archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' - ;; - esac - fi - else - ld_shlibs_GCJ=no - fi - ;; - - os2*) - hardcode_libdir_flag_spec_GCJ='-L$libdir' - hardcode_minus_L_GCJ=yes - allow_undefined_flag_GCJ=unsupported - archive_cmds_GCJ='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' - old_archive_From_new_cmds_GCJ='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' - ;; - - osf3*) - if test "$GCC" = yes; then - allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - else - allow_undefined_flag_GCJ=' -expect_unresolved \*' - archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - fi - hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator_GCJ=: - ;; - - osf4* | osf5*) # as osf3* with the addition of -msym flag - if test "$GCC" = yes; then - allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' - else - allow_undefined_flag_GCJ=' -expect_unresolved \*' - archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' - archive_expsym_cmds_GCJ='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ - $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' - - # Both c and cxx compiler support -rpath directly - hardcode_libdir_flag_spec_GCJ='-rpath $libdir' - fi - hardcode_libdir_separator_GCJ=: - ;; - - solaris*) - no_undefined_flag_GCJ=' -z text' - if test "$GCC" = yes; then - wlarc='${wl}' - archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' - else - wlarc='' - archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' - archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' - fi - hardcode_libdir_flag_spec_GCJ='-R$libdir' - hardcode_shlibpath_var_GCJ=no - case $host_os in - solaris2.[0-5] | solaris2.[0-5].*) ;; - *) - # The compiler driver will combine and reorder linker options, - # but understands `-z linker_flag'. GCC discards it without `$wl', - # but is careful enough not to reorder. - # Supported since Solaris 2.6 (maybe 2.5.1?) - if test "$GCC" = yes; then - whole_archive_flag_spec_GCJ='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' - else - whole_archive_flag_spec_GCJ='-z allextract$convenience -z defaultextract' - fi - ;; - esac - link_all_deplibs_GCJ=yes - ;; - - sunos4*) - if test "x$host_vendor" = xsequent; then - # Use $CC to link under sequent, because it throws in some extra .o - # files that make .init and .fini sections work. - archive_cmds_GCJ='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds_GCJ='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' - fi - hardcode_libdir_flag_spec_GCJ='-L$libdir' - hardcode_direct_GCJ=yes - hardcode_minus_L_GCJ=yes - hardcode_shlibpath_var_GCJ=no - ;; - - sysv4) - case $host_vendor in - sni) - archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct_GCJ=yes # is this really true??? - ;; - siemens) - ## LD is ld it makes a PLAMLIB - ## CC just makes a GrossModule. - archive_cmds_GCJ='$LD -G -o $lib $libobjs $deplibs $linker_flags' - reload_cmds_GCJ='$CC -r -o $output$reload_objs' - hardcode_direct_GCJ=no - ;; - motorola) - archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct_GCJ=no #Motorola manual says yes, but my tests say they lie - ;; - esac - runpath_var='LD_RUN_PATH' - hardcode_shlibpath_var_GCJ=no - ;; - - sysv4.3*) - archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var_GCJ=no - export_dynamic_flag_spec_GCJ='-Bexport' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var_GCJ=no - runpath_var=LD_RUN_PATH - hardcode_runpath_var=yes - ld_shlibs_GCJ=yes - fi - ;; - - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) - no_undefined_flag_GCJ='${wl}-z,text' - archive_cmds_need_lc_GCJ=no - hardcode_shlibpath_var_GCJ=no - runpath_var='LD_RUN_PATH' - - if test "$GCC" = yes; then - archive_cmds_GCJ='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_GCJ='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds_GCJ='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_GCJ='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - sysv5* | sco3.2v5* | sco5v6*) - # Note: We can NOT use -z defs as we might desire, because we do not - # link with -lc, and that would cause any symbols used from libc to - # always be unresolved, which means just about no library would - # ever link correctly. If we're not using GNU ld we use -z text - # though, which does catch some bad symbols but isn't as heavy-handed - # as -z defs. - no_undefined_flag_GCJ='${wl}-z,text' - allow_undefined_flag_GCJ='${wl}-z,nodefs' - archive_cmds_need_lc_GCJ=no - hardcode_shlibpath_var_GCJ=no - hardcode_libdir_flag_spec_GCJ='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' - hardcode_libdir_separator_GCJ=':' - link_all_deplibs_GCJ=yes - export_dynamic_flag_spec_GCJ='${wl}-Bexport' - runpath_var='LD_RUN_PATH' - - if test "$GCC" = yes; then - archive_cmds_GCJ='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_GCJ='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds_GCJ='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_GCJ='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - uts4*) - archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec_GCJ='-L$libdir' - hardcode_shlibpath_var_GCJ=no - ;; - - *) - ld_shlibs_GCJ=no - ;; - esac - fi - -{ echo "$as_me:$LINENO: result: $ld_shlibs_GCJ" >&5 -echo "${ECHO_T}$ld_shlibs_GCJ" >&6; } -test "$ld_shlibs_GCJ" = no && can_build_shared=no - -# -# Do we need to explicitly link libc? -# -case "x$archive_cmds_need_lc_GCJ" in -x|xyes) - # Assume -lc should be added - archive_cmds_need_lc_GCJ=yes - - if test "$enable_shared" = yes && test "$GCC" = yes; then - case $archive_cmds_GCJ in - *'~'*) - # FIXME: we may have to deal with multi-command sequences. - ;; - '$CC '*) - # Test whether the compiler implicitly links with -lc since on some - # systems, -lgcc has to come before -lc. If gcc already passes -lc - # to ld, don't add -lc before -lgcc. - { echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 -echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6; } - $rm conftest* - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$lt_prog_compiler_wl_GCJ - pic_flag=$lt_prog_compiler_pic_GCJ - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$allow_undefined_flag_GCJ - allow_undefined_flag_GCJ= - if { (eval echo "$as_me:$LINENO: \"$archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 - (eval $archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } - then - archive_cmds_need_lc_GCJ=no - else - archive_cmds_need_lc_GCJ=yes - fi - allow_undefined_flag_GCJ=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $rm conftest* - { echo "$as_me:$LINENO: result: $archive_cmds_need_lc_GCJ" >&5 -echo "${ECHO_T}$archive_cmds_need_lc_GCJ" >&6; } - ;; - esac - fi - ;; -esac - -{ echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 -echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6; } -library_names_spec= -libname_spec='lib$name' -soname_spec= -shrext_cmds=".so" -postinstall_cmds= -postuninstall_cmds= -finish_cmds= -finish_eval= -shlibpath_var= -shlibpath_overrides_runpath=unknown -version_type=none -dynamic_linker="$host_os ld.so" -sys_lib_dlsearch_path_spec="/lib /usr/lib" - -need_lib_prefix=unknown -hardcode_into_libs=no - -# when you set need_version to no, make sure it does not cause -set_version -# flags to be left without arguments -need_version=unknown - -case $host_os in -aix3*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' - shlibpath_var=LIBPATH - - # AIX 3 has no versioning support, so we append a major version to the name. - soname_spec='${libname}${release}${shared_ext}$major' - ;; - -aix4* | aix5*) - version_type=linux - need_lib_prefix=no - need_version=no - hardcode_into_libs=yes - if test "$host_cpu" = ia64; then - # AIX 5 supports IA64 - library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - else - # With GCC up to 2.95.x, collect2 would create an import file - # for dependence libraries. The import file would start with - # the line `#! .'. This would cause the generated library to - # depend on `.', always an invalid library. This was fixed in - # development snapshots of GCC prior to 3.0. - case $host_os in - aix4 | aix4.[01] | aix4.[01].*) - if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' - echo ' yes ' - echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then - : - else - can_build_shared=no - fi - ;; - esac - # AIX (on Power*) has no versioning support, so currently we can not hardcode correct - # soname into executable. Probably we can add versioning support to - # collect2, so additional links can be useful in future. - if test "$aix_use_runtimelinking" = yes; then - # If using run time linking (on AIX 4.2 or later) use lib.so - # instead of lib.a to let people know that these are not - # typical AIX shared libraries. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - else - # We preserve .a as extension for shared libraries through AIX4.2 - # and later when we are not doing run time linking. - library_names_spec='${libname}${release}.a $libname.a' - soname_spec='${libname}${release}${shared_ext}$major' - fi - shlibpath_var=LIBPATH - fi - ;; - -amigaos*) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' - ;; - -beos*) - library_names_spec='${libname}${shared_ext}' - dynamic_linker="$host_os ld.so" - shlibpath_var=LIBRARY_PATH - ;; - -bsdi[45]*) - version_type=linux - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" - sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" - # the default ld.so.conf also contains /usr/contrib/lib and - # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow - # libtool to hard-code these into programs - ;; - -cygwin* | mingw* | pw32*) - version_type=windows - shrext_cmds=".dll" - need_version=no - need_lib_prefix=no - - case $GCC,$host_os in - yes,cygwin* | yes,mingw* | yes,pw32*) - library_names_spec='$libname.dll.a' - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \${file}`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $rm \$dlpath' - shlibpath_overrides_runpath=yes - - case $host_os in - cygwin*) - # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" - ;; - mingw*) - # MinGW DLLs use traditional 'lib' prefix - soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` - if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then - # It is most probably a Windows format PATH printed by - # mingw gcc, but we are running on Cygwin. Gcc prints its search - # path with ; separators, and with drive letters. We can handle the - # drive letters (cygwin fileutils understands them), so leave them, - # especially as we might pass files found there to a mingw objdump, - # which wouldn't understand a cygwinified path. Ahh. - sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi - ;; - pw32*) - # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - ;; - esac - ;; - - *) - library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' - ;; - esac - dynamic_linker='Win32 ld.exe' - # FIXME: first we should search . and the directory the executable is in - shlibpath_var=PATH - ;; - -darwin* | rhapsody*) - dynamic_linker="$host_os dyld" - version_type=darwin - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' - soname_spec='${libname}${release}${major}$shared_ext' - shlibpath_overrides_runpath=yes - shlibpath_var=DYLD_LIBRARY_PATH - shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' - - sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' - ;; - -dgux*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -freebsd1*) - dynamic_linker=no - ;; - -freebsd* | dragonfly*) - # DragonFly does not have aout. When/if they implement a new - # versioning mechanism, adjust this. - if test -x /usr/bin/objformat; then - objformat=`/usr/bin/objformat` - else - case $host_os in - freebsd[123]*) objformat=aout ;; - *) objformat=elf ;; - esac - fi - version_type=freebsd-$objformat - case $version_type in - freebsd-elf*) - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - need_version=no - need_lib_prefix=no - ;; - freebsd-*) - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' - need_version=yes - ;; - esac - shlibpath_var=LD_LIBRARY_PATH - case $host_os in - freebsd2*) - shlibpath_overrides_runpath=yes - ;; - freebsd3.[01]* | freebsdelf3.[01]*) - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ - freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - *) # from 4.6 on, and DragonFly - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - esac - ;; - -gnu*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - hardcode_into_libs=yes - ;; - -hpux9* | hpux10* | hpux11*) - # Give a soname corresponding to the major version so that dld.sl refuses to - # link against other versions. - version_type=sunos - need_lib_prefix=no - need_version=no - case $host_cpu in - ia64*) - shrext_cmds='.so' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.so" - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - if test "X$HPUX_IA64_MODE" = X32; then - sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" - else - sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" - fi - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - hppa*64*) - shrext_cmds='.sl' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.sl" - shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - *) - shrext_cmds='.sl' - dynamic_linker="$host_os dld.sl" - shlibpath_var=SHLIB_PATH - shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - ;; - esac - # HP-UX runs *really* slowly unless shared libraries are mode 555. - postinstall_cmds='chmod 555 $lib' - ;; - -interix[3-9]*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -irix5* | irix6* | nonstopux*) - case $host_os in - nonstopux*) version_type=nonstopux ;; - *) - if test "$lt_cv_prog_gnu_ld" = yes; then - version_type=linux - else - version_type=irix - fi ;; - esac - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' - case $host_os in - irix5* | nonstopux*) - libsuff= shlibsuff= - ;; - *) - case $LD in # libtool.m4 will add one of these switches to LD - *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") - libsuff= shlibsuff= libmagic=32-bit;; - *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") - libsuff=32 shlibsuff=N32 libmagic=N32;; - *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") - libsuff=64 shlibsuff=64 libmagic=64-bit;; - *) libsuff= shlibsuff= libmagic=never-match;; - esac - ;; - esac - shlibpath_var=LD_LIBRARY${shlibsuff}_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" - sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" - hardcode_into_libs=yes - ;; - -# No shared lib support for Linux oldld, aout, or coff. -linux*oldld* | linux*aout* | linux*coff*) - dynamic_linker=no - ;; - -# This must be Linux ELF. -linux* | k*bsd*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - # Append ld.so.conf contents to the search path - if test -f /etc/ld.so.conf; then - lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` - sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" - fi - - # We used to test for /lib/ld.so.1 and disable shared libraries on - # powerpc, because MkLinux only supported shared libraries with the - # GNU dynamic linker. Since this was broken with cross compilers, - # most powerpc-linux boxes support dynamic linking these days and - # people can always --disable-shared, the test was removed, and we - # assume the GNU/Linux dynamic linker is in use. - dynamic_linker='GNU/Linux ld.so' - ;; - -netbsdelf*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='NetBSD ld.elf_so' - ;; - -netbsd*) - version_type=sunos - need_lib_prefix=no - need_version=no - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - dynamic_linker='NetBSD (a.out) ld.so' - else - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='NetBSD ld.elf_so' - fi - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - -newsos6) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -nto-qnx*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -openbsd*) - version_type=sunos - sys_lib_dlsearch_path_spec="/usr/lib" - need_lib_prefix=no - # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. - case $host_os in - openbsd3.3 | openbsd3.3.*) need_version=yes ;; - *) need_version=no ;; - esac - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - case $host_os in - openbsd2.[89] | openbsd2.[89].*) - shlibpath_overrides_runpath=no - ;; - *) - shlibpath_overrides_runpath=yes - ;; - esac - else - shlibpath_overrides_runpath=yes - fi - ;; - -os2*) - libname_spec='$name' - shrext_cmds=".dll" - need_lib_prefix=no - library_names_spec='$libname${shared_ext} $libname.a' - dynamic_linker='OS/2 ld.exe' - shlibpath_var=LIBPATH - ;; - -osf3* | osf4* | osf5*) - version_type=osf - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" - ;; - -rdos*) - dynamic_linker=no - ;; - -solaris*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - # ldd complains unless libraries are executable - postinstall_cmds='chmod +x $lib' - ;; - -sunos4*) - version_type=sunos - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - if test "$with_gnu_ld" = yes; then - need_lib_prefix=no - fi - need_version=yes - ;; - -sysv4 | sysv4.3*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - case $host_vendor in - sni) - shlibpath_overrides_runpath=no - need_lib_prefix=no - export_dynamic_flag_spec='${wl}-Blargedynsym' - runpath_var=LD_RUN_PATH - ;; - siemens) - need_lib_prefix=no - ;; - motorola) - need_lib_prefix=no - need_version=no - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' - ;; - esac - ;; - -sysv4*MP*) - if test -d /usr/nec ;then - version_type=linux - library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' - soname_spec='$libname${shared_ext}.$major' - shlibpath_var=LD_LIBRARY_PATH - fi - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - version_type=freebsd-elf - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - hardcode_into_libs=yes - if test "$with_gnu_ld" = yes; then - sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' - shlibpath_overrides_runpath=no - else - sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' - shlibpath_overrides_runpath=yes - case $host_os in - sco3.2v5*) - sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" - ;; - esac - fi - sys_lib_dlsearch_path_spec='/usr/lib' - ;; - -uts4*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -*) - dynamic_linker=no - ;; -esac -{ echo "$as_me:$LINENO: result: $dynamic_linker" >&5 -echo "${ECHO_T}$dynamic_linker" >&6; } -test "$dynamic_linker" = no && can_build_shared=no - -variables_saved_for_relink="PATH $shlibpath_var $runpath_var" -if test "$GCC" = yes; then - variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" -fi - -{ echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 -echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6; } -hardcode_action_GCJ= -if test -n "$hardcode_libdir_flag_spec_GCJ" || \ - test -n "$runpath_var_GCJ" || \ - test "X$hardcode_automatic_GCJ" = "Xyes" ; then - - # We can hardcode non-existant directories. - if test "$hardcode_direct_GCJ" != no && - # If the only mechanism to avoid hardcoding is shlibpath_var, we - # have to relink, otherwise we might link with an installed library - # when we should be linking with a yet-to-be-installed one - ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, GCJ)" != no && - test "$hardcode_minus_L_GCJ" != no; then - # Linking always hardcodes the temporary library directory. - hardcode_action_GCJ=relink - else - # We can link without hardcoding, and we can hardcode nonexisting dirs. - hardcode_action_GCJ=immediate - fi -else - # We cannot hardcode anything, or else we can only hardcode existing - # directories. - hardcode_action_GCJ=unsupported -fi -{ echo "$as_me:$LINENO: result: $hardcode_action_GCJ" >&5 -echo "${ECHO_T}$hardcode_action_GCJ" >&6; } - -if test "$hardcode_action_GCJ" = relink; then - # Fast installation is not supported - enable_fast_install=no -elif test "$shlibpath_overrides_runpath" = yes || - test "$enable_shared" = no; then - # Fast installation is not necessary - enable_fast_install=needless -fi - - -# The else clause should only fire when bootstrapping the -# libtool distribution, otherwise you forgot to ship ltmain.sh -# with your package, and you will get complaints that there are -# no rules to generate ltmain.sh. -if test -f "$ltmain"; then - # See if we are running on zsh, and set the options which allow our commands through - # without removal of \ escapes. - if test -n "${ZSH_VERSION+set}" ; then - setopt NO_GLOB_SUBST - fi - # Now quote all the things that may contain metacharacters while being - # careful not to overquote the AC_SUBSTed values. We take copies of the - # variables and quote the copies for generation of the libtool script. - for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ - SED SHELL STRIP \ - libname_spec library_names_spec soname_spec extract_expsyms_cmds \ - old_striplib striplib file_magic_cmd finish_cmds finish_eval \ - deplibs_check_method reload_flag reload_cmds need_locks \ - lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ - lt_cv_sys_global_symbol_to_c_name_address \ - sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ - old_postinstall_cmds old_postuninstall_cmds \ - compiler_GCJ \ - CC_GCJ \ - LD_GCJ \ - lt_prog_compiler_wl_GCJ \ - lt_prog_compiler_pic_GCJ \ - lt_prog_compiler_static_GCJ \ - lt_prog_compiler_no_builtin_flag_GCJ \ - export_dynamic_flag_spec_GCJ \ - thread_safe_flag_spec_GCJ \ - whole_archive_flag_spec_GCJ \ - enable_shared_with_static_runtimes_GCJ \ - old_archive_cmds_GCJ \ - old_archive_from_new_cmds_GCJ \ - predep_objects_GCJ \ - postdep_objects_GCJ \ - predeps_GCJ \ - postdeps_GCJ \ - compiler_lib_search_path_GCJ \ - archive_cmds_GCJ \ - archive_expsym_cmds_GCJ \ - postinstall_cmds_GCJ \ - postuninstall_cmds_GCJ \ - old_archive_from_expsyms_cmds_GCJ \ - allow_undefined_flag_GCJ \ - no_undefined_flag_GCJ \ - export_symbols_cmds_GCJ \ - hardcode_libdir_flag_spec_GCJ \ - hardcode_libdir_flag_spec_ld_GCJ \ - hardcode_libdir_separator_GCJ \ - hardcode_automatic_GCJ \ - module_cmds_GCJ \ - module_expsym_cmds_GCJ \ - lt_cv_prog_compiler_c_o_GCJ \ - fix_srcfile_path_GCJ \ - exclude_expsyms_GCJ \ - include_expsyms_GCJ; do - - case $var in - old_archive_cmds_GCJ | \ - old_archive_from_new_cmds_GCJ | \ - archive_cmds_GCJ | \ - archive_expsym_cmds_GCJ | \ - module_cmds_GCJ | \ - module_expsym_cmds_GCJ | \ - old_archive_from_expsyms_cmds_GCJ | \ - export_symbols_cmds_GCJ | \ - extract_expsyms_cmds | reload_cmds | finish_cmds | \ - postinstall_cmds | postuninstall_cmds | \ - old_postinstall_cmds | old_postuninstall_cmds | \ - sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) - # Double-quote double-evaled strings. - eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" - ;; - *) - eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" - ;; - esac - done - - case $lt_echo in - *'\$0 --fallback-echo"') - lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` - ;; - esac - -cfgfile="$ofile" - - cat <<__EOF__ >> "$cfgfile" -# ### BEGIN LIBTOOL TAG CONFIG: $tagname - -# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: - -# Shell to use when invoking shell scripts. -SHELL=$lt_SHELL - -# Whether or not to build shared libraries. -build_libtool_libs=$enable_shared - -# Whether or not to build static libraries. -build_old_libs=$enable_static - -# Whether or not to add -lc for building shared libraries. -build_libtool_need_lc=$archive_cmds_need_lc_GCJ - -# Whether or not to disallow shared libs when runtime libs are static -allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_GCJ - -# Whether or not to optimize for fast installation. -fast_install=$enable_fast_install - -# The host system. -host_alias=$host_alias -host=$host -host_os=$host_os - -# The build system. -build_alias=$build_alias -build=$build -build_os=$build_os - -# An echo program that does not interpret backslashes. -echo=$lt_echo - -# The archiver. -AR=$lt_AR -AR_FLAGS=$lt_AR_FLAGS - -# A C compiler. -LTCC=$lt_LTCC - -# LTCC compiler flags. -LTCFLAGS=$lt_LTCFLAGS - -# A language-specific compiler. -CC=$lt_compiler_GCJ - -# Is the compiler the GNU C compiler? -with_gcc=$GCC_GCJ - -# An ERE matcher. -EGREP=$lt_EGREP - -# The linker used to build libraries. -LD=$lt_LD_GCJ - -# Whether we need hard or soft links. -LN_S=$lt_LN_S - -# A BSD-compatible nm program. -NM=$lt_NM - -# A symbol stripping program -STRIP=$lt_STRIP - -# Used to examine libraries when file_magic_cmd begins "file" -MAGIC_CMD=$MAGIC_CMD - -# Used on cygwin: DLL creation program. -DLLTOOL="$DLLTOOL" - -# Used on cygwin: object dumper. -OBJDUMP="$OBJDUMP" - -# Used on cygwin: assembler. -AS="$AS" - -# The name of the directory that contains temporary libtool files. -objdir=$objdir - -# How to create reloadable object files. -reload_flag=$lt_reload_flag -reload_cmds=$lt_reload_cmds - -# How to pass a linker flag through the compiler. -wl=$lt_lt_prog_compiler_wl_GCJ - -# Object file suffix (normally "o"). -objext="$ac_objext" - -# Old archive suffix (normally "a"). -libext="$libext" - -# Shared library suffix (normally ".so"). -shrext_cmds='$shrext_cmds' - -# Executable file suffix (normally ""). -exeext="$exeext" - -# Additional compiler flags for building library objects. -pic_flag=$lt_lt_prog_compiler_pic_GCJ -pic_mode=$pic_mode - -# What is the maximum length of a command? -max_cmd_len=$lt_cv_sys_max_cmd_len - -# Does compiler simultaneously support -c and -o options? -compiler_c_o=$lt_lt_cv_prog_compiler_c_o_GCJ - -# Must we lock files when doing compilation? -need_locks=$lt_need_locks - -# Do we need the lib prefix for modules? -need_lib_prefix=$need_lib_prefix - -# Do we need a version for libraries? -need_version=$need_version - -# Whether dlopen is supported. -dlopen_support=$enable_dlopen - -# Whether dlopen of programs is supported. -dlopen_self=$enable_dlopen_self - -# Whether dlopen of statically linked programs is supported. -dlopen_self_static=$enable_dlopen_self_static - -# Compiler flag to prevent dynamic linking. -link_static_flag=$lt_lt_prog_compiler_static_GCJ - -# Compiler flag to turn off builtin functions. -no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_GCJ - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_GCJ - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec=$lt_whole_archive_flag_spec_GCJ - -# Compiler flag to generate thread-safe objects. -thread_safe_flag_spec=$lt_thread_safe_flag_spec_GCJ - -# Library versioning type. -version_type=$version_type - -# Format of library name prefix. -libname_spec=$lt_libname_spec - -# List of archive names. First name is the real one, the rest are links. -# The last name is the one that the linker finds with -lNAME. -library_names_spec=$lt_library_names_spec - -# The coded name of the library, if different from the real name. -soname_spec=$lt_soname_spec - -# Commands used to build and install an old-style archive. -RANLIB=$lt_RANLIB -old_archive_cmds=$lt_old_archive_cmds_GCJ -old_postinstall_cmds=$lt_old_postinstall_cmds -old_postuninstall_cmds=$lt_old_postuninstall_cmds - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_GCJ - -# Create a temporary old-style archive to link instead of a shared archive. -old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_GCJ - -# Commands used to build and install a shared archive. -archive_cmds=$lt_archive_cmds_GCJ -archive_expsym_cmds=$lt_archive_expsym_cmds_GCJ -postinstall_cmds=$lt_postinstall_cmds -postuninstall_cmds=$lt_postuninstall_cmds - -# Commands used to build a loadable module (assumed same as above if empty) -module_cmds=$lt_module_cmds_GCJ -module_expsym_cmds=$lt_module_expsym_cmds_GCJ - -# Commands to strip libraries. -old_striplib=$lt_old_striplib -striplib=$lt_striplib - -# Dependencies to place before the objects being linked to create a -# shared library. -predep_objects=$lt_predep_objects_GCJ - -# Dependencies to place after the objects being linked to create a -# shared library. -postdep_objects=$lt_postdep_objects_GCJ - -# Dependencies to place before the objects being linked to create a -# shared library. -predeps=$lt_predeps_GCJ - -# Dependencies to place after the objects being linked to create a -# shared library. -postdeps=$lt_postdeps_GCJ - -# The library search path used internally by the compiler when linking -# a shared library. -compiler_lib_search_path=$lt_compiler_lib_search_path_GCJ - -# Method to check whether dependent libraries are shared objects. -deplibs_check_method=$lt_deplibs_check_method - -# Command to use when deplibs_check_method == file_magic. -file_magic_cmd=$lt_file_magic_cmd - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag=$lt_allow_undefined_flag_GCJ - -# Flag that forces no undefined symbols. -no_undefined_flag=$lt_no_undefined_flag_GCJ - -# Commands used to finish a libtool library installation in a directory. -finish_cmds=$lt_finish_cmds - -# Same as above, but a single script fragment to be evaled but not shown. -finish_eval=$lt_finish_eval - -# Take the output of nm and produce a listing of raw symbols and C names. -global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe - -# Transform the output of nm in a proper C declaration -global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl - -# Transform the output of nm in a C name address pair -global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address - -# This is the shared library runtime path variable. -runpath_var=$runpath_var - -# This is the shared library path variable. -shlibpath_var=$shlibpath_var - -# Is shlibpath searched before the hard-coded library search path? -shlibpath_overrides_runpath=$shlibpath_overrides_runpath - -# How to hardcode a shared library path into an executable. -hardcode_action=$hardcode_action_GCJ - -# Whether we should hardcode library paths into libraries. -hardcode_into_libs=$hardcode_into_libs - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist. -hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_GCJ - -# If ld is used when linking, flag to hardcode \$libdir into -# a binary during linking. This must work even if \$libdir does -# not exist. -hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_GCJ - -# Whether we need a single -rpath flag with a separated argument. -hardcode_libdir_separator=$lt_hardcode_libdir_separator_GCJ - -# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the -# resulting binary. -hardcode_direct=$hardcode_direct_GCJ - -# Set to yes if using the -LDIR flag during linking hardcodes DIR into the -# resulting binary. -hardcode_minus_L=$hardcode_minus_L_GCJ - -# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into -# the resulting binary. -hardcode_shlibpath_var=$hardcode_shlibpath_var_GCJ - -# Set to yes if building a shared library automatically hardcodes DIR into the library -# and all subsequent libraries and executables linked against it. -hardcode_automatic=$hardcode_automatic_GCJ - -# Variables whose values should be saved in libtool wrapper scripts and -# restored at relink time. -variables_saved_for_relink="$variables_saved_for_relink" - -# Whether libtool must link a program against all its dependency libraries. -link_all_deplibs=$link_all_deplibs_GCJ - -# Compile-time system search path for libraries -sys_lib_search_path_spec=$lt_sys_lib_search_path_spec - -# Run-time system search path for libraries -sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec - -# Fix the shell variable \$srcfile for the compiler. -fix_srcfile_path=$lt_fix_srcfile_path - -# Set to yes if exported symbols are required. -always_export_symbols=$always_export_symbols_GCJ - -# The commands to list exported symbols. -export_symbols_cmds=$lt_export_symbols_cmds_GCJ - -# The commands to extract the exported symbol list from a shared archive. -extract_expsyms_cmds=$lt_extract_expsyms_cmds - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms=$lt_exclude_expsyms_GCJ - -# Symbols that must always be exported. -include_expsyms=$lt_include_expsyms_GCJ - -# ### END LIBTOOL TAG CONFIG: $tagname - -__EOF__ - - -else - # If there is no Makefile yet, we rely on a make rule to execute - # `config.status --recheck' to rerun these tests and create the - # libtool script then. - ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` - if test -f "$ltmain_in"; then - test -f Makefile && make "$ltmain" - fi -fi - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -CC="$lt_save_CC" - - else - tagname="" - fi - ;; - - RC) - - -# Source file extension for RC test sources. -ac_ext=rc - -# Object file extension for compiled RC test sources. -objext=o -objext_RC=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' - -# Code to be used in simple link tests -lt_simple_link_test_code="$lt_simple_compile_test_code" - -# ltmain only uses $CC for tagged configurations so make sure $CC is set. - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - - -# save warnings/boilerplate of simple test code -ac_outfile=conftest.$ac_objext -echo "$lt_simple_compile_test_code" >conftest.$ac_ext -eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_compiler_boilerplate=`cat conftest.err` -$rm conftest* - -ac_outfile=conftest.$ac_objext -echo "$lt_simple_link_test_code" >conftest.$ac_ext -eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_linker_boilerplate=`cat conftest.err` -$rm conftest* - - -# Allow CC to be a program name with arguments. -lt_save_CC="$CC" -CC=${RC-"windres"} -compiler=$CC -compiler_RC=$CC -for cc_temp in $compiler""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac -done -cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` - -lt_cv_prog_compiler_c_o_RC=yes - -# The else clause should only fire when bootstrapping the -# libtool distribution, otherwise you forgot to ship ltmain.sh -# with your package, and you will get complaints that there are -# no rules to generate ltmain.sh. -if test -f "$ltmain"; then - # See if we are running on zsh, and set the options which allow our commands through - # without removal of \ escapes. - if test -n "${ZSH_VERSION+set}" ; then - setopt NO_GLOB_SUBST - fi - # Now quote all the things that may contain metacharacters while being - # careful not to overquote the AC_SUBSTed values. We take copies of the - # variables and quote the copies for generation of the libtool script. - for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ - SED SHELL STRIP \ - libname_spec library_names_spec soname_spec extract_expsyms_cmds \ - old_striplib striplib file_magic_cmd finish_cmds finish_eval \ - deplibs_check_method reload_flag reload_cmds need_locks \ - lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ - lt_cv_sys_global_symbol_to_c_name_address \ - sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ - old_postinstall_cmds old_postuninstall_cmds \ - compiler_RC \ - CC_RC \ - LD_RC \ - lt_prog_compiler_wl_RC \ - lt_prog_compiler_pic_RC \ - lt_prog_compiler_static_RC \ - lt_prog_compiler_no_builtin_flag_RC \ - export_dynamic_flag_spec_RC \ - thread_safe_flag_spec_RC \ - whole_archive_flag_spec_RC \ - enable_shared_with_static_runtimes_RC \ - old_archive_cmds_RC \ - old_archive_from_new_cmds_RC \ - predep_objects_RC \ - postdep_objects_RC \ - predeps_RC \ - postdeps_RC \ - compiler_lib_search_path_RC \ - archive_cmds_RC \ - archive_expsym_cmds_RC \ - postinstall_cmds_RC \ - postuninstall_cmds_RC \ - old_archive_from_expsyms_cmds_RC \ - allow_undefined_flag_RC \ - no_undefined_flag_RC \ - export_symbols_cmds_RC \ - hardcode_libdir_flag_spec_RC \ - hardcode_libdir_flag_spec_ld_RC \ - hardcode_libdir_separator_RC \ - hardcode_automatic_RC \ - module_cmds_RC \ - module_expsym_cmds_RC \ - lt_cv_prog_compiler_c_o_RC \ - fix_srcfile_path_RC \ - exclude_expsyms_RC \ - include_expsyms_RC; do - - case $var in - old_archive_cmds_RC | \ - old_archive_from_new_cmds_RC | \ - archive_cmds_RC | \ - archive_expsym_cmds_RC | \ - module_cmds_RC | \ - module_expsym_cmds_RC | \ - old_archive_from_expsyms_cmds_RC | \ - export_symbols_cmds_RC | \ - extract_expsyms_cmds | reload_cmds | finish_cmds | \ - postinstall_cmds | postuninstall_cmds | \ - old_postinstall_cmds | old_postuninstall_cmds | \ - sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) - # Double-quote double-evaled strings. - eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" - ;; - *) - eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" - ;; - esac - done - - case $lt_echo in - *'\$0 --fallback-echo"') - lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` - ;; - esac - -cfgfile="$ofile" - - cat <<__EOF__ >> "$cfgfile" -# ### BEGIN LIBTOOL TAG CONFIG: $tagname - -# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: - -# Shell to use when invoking shell scripts. -SHELL=$lt_SHELL - -# Whether or not to build shared libraries. -build_libtool_libs=$enable_shared - -# Whether or not to build static libraries. -build_old_libs=$enable_static - -# Whether or not to add -lc for building shared libraries. -build_libtool_need_lc=$archive_cmds_need_lc_RC - -# Whether or not to disallow shared libs when runtime libs are static -allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_RC - -# Whether or not to optimize for fast installation. -fast_install=$enable_fast_install - -# The host system. -host_alias=$host_alias -host=$host -host_os=$host_os - -# The build system. -build_alias=$build_alias -build=$build -build_os=$build_os - -# An echo program that does not interpret backslashes. -echo=$lt_echo - -# The archiver. -AR=$lt_AR -AR_FLAGS=$lt_AR_FLAGS - -# A C compiler. -LTCC=$lt_LTCC - -# LTCC compiler flags. -LTCFLAGS=$lt_LTCFLAGS - -# A language-specific compiler. -CC=$lt_compiler_RC - -# Is the compiler the GNU C compiler? -with_gcc=$GCC_RC - -# An ERE matcher. -EGREP=$lt_EGREP - -# The linker used to build libraries. -LD=$lt_LD_RC - -# Whether we need hard or soft links. -LN_S=$lt_LN_S - -# A BSD-compatible nm program. -NM=$lt_NM - -# A symbol stripping program -STRIP=$lt_STRIP - -# Used to examine libraries when file_magic_cmd begins "file" -MAGIC_CMD=$MAGIC_CMD - -# Used on cygwin: DLL creation program. -DLLTOOL="$DLLTOOL" - -# Used on cygwin: object dumper. -OBJDUMP="$OBJDUMP" - -# Used on cygwin: assembler. -AS="$AS" - -# The name of the directory that contains temporary libtool files. -objdir=$objdir - -# How to create reloadable object files. -reload_flag=$lt_reload_flag -reload_cmds=$lt_reload_cmds - -# How to pass a linker flag through the compiler. -wl=$lt_lt_prog_compiler_wl_RC - -# Object file suffix (normally "o"). -objext="$ac_objext" - -# Old archive suffix (normally "a"). -libext="$libext" - -# Shared library suffix (normally ".so"). -shrext_cmds='$shrext_cmds' - -# Executable file suffix (normally ""). -exeext="$exeext" - -# Additional compiler flags for building library objects. -pic_flag=$lt_lt_prog_compiler_pic_RC -pic_mode=$pic_mode - -# What is the maximum length of a command? -max_cmd_len=$lt_cv_sys_max_cmd_len - -# Does compiler simultaneously support -c and -o options? -compiler_c_o=$lt_lt_cv_prog_compiler_c_o_RC - -# Must we lock files when doing compilation? -need_locks=$lt_need_locks - -# Do we need the lib prefix for modules? -need_lib_prefix=$need_lib_prefix - -# Do we need a version for libraries? -need_version=$need_version - -# Whether dlopen is supported. -dlopen_support=$enable_dlopen - -# Whether dlopen of programs is supported. -dlopen_self=$enable_dlopen_self - -# Whether dlopen of statically linked programs is supported. -dlopen_self_static=$enable_dlopen_self_static - -# Compiler flag to prevent dynamic linking. -link_static_flag=$lt_lt_prog_compiler_static_RC - -# Compiler flag to turn off builtin functions. -no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_RC - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_RC - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec=$lt_whole_archive_flag_spec_RC - -# Compiler flag to generate thread-safe objects. -thread_safe_flag_spec=$lt_thread_safe_flag_spec_RC - -# Library versioning type. -version_type=$version_type - -# Format of library name prefix. -libname_spec=$lt_libname_spec - -# List of archive names. First name is the real one, the rest are links. -# The last name is the one that the linker finds with -lNAME. -library_names_spec=$lt_library_names_spec - -# The coded name of the library, if different from the real name. -soname_spec=$lt_soname_spec - -# Commands used to build and install an old-style archive. -RANLIB=$lt_RANLIB -old_archive_cmds=$lt_old_archive_cmds_RC -old_postinstall_cmds=$lt_old_postinstall_cmds -old_postuninstall_cmds=$lt_old_postuninstall_cmds - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_RC - -# Create a temporary old-style archive to link instead of a shared archive. -old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_RC - -# Commands used to build and install a shared archive. -archive_cmds=$lt_archive_cmds_RC -archive_expsym_cmds=$lt_archive_expsym_cmds_RC -postinstall_cmds=$lt_postinstall_cmds -postuninstall_cmds=$lt_postuninstall_cmds - -# Commands used to build a loadable module (assumed same as above if empty) -module_cmds=$lt_module_cmds_RC -module_expsym_cmds=$lt_module_expsym_cmds_RC - -# Commands to strip libraries. -old_striplib=$lt_old_striplib -striplib=$lt_striplib - -# Dependencies to place before the objects being linked to create a -# shared library. -predep_objects=$lt_predep_objects_RC - -# Dependencies to place after the objects being linked to create a -# shared library. -postdep_objects=$lt_postdep_objects_RC - -# Dependencies to place before the objects being linked to create a -# shared library. -predeps=$lt_predeps_RC - -# Dependencies to place after the objects being linked to create a -# shared library. -postdeps=$lt_postdeps_RC - -# The library search path used internally by the compiler when linking -# a shared library. -compiler_lib_search_path=$lt_compiler_lib_search_path_RC - -# Method to check whether dependent libraries are shared objects. -deplibs_check_method=$lt_deplibs_check_method - -# Command to use when deplibs_check_method == file_magic. -file_magic_cmd=$lt_file_magic_cmd - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag=$lt_allow_undefined_flag_RC - -# Flag that forces no undefined symbols. -no_undefined_flag=$lt_no_undefined_flag_RC - -# Commands used to finish a libtool library installation in a directory. -finish_cmds=$lt_finish_cmds - -# Same as above, but a single script fragment to be evaled but not shown. -finish_eval=$lt_finish_eval - -# Take the output of nm and produce a listing of raw symbols and C names. -global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe - -# Transform the output of nm in a proper C declaration -global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl - -# Transform the output of nm in a C name address pair -global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address - -# This is the shared library runtime path variable. -runpath_var=$runpath_var - -# This is the shared library path variable. -shlibpath_var=$shlibpath_var - -# Is shlibpath searched before the hard-coded library search path? -shlibpath_overrides_runpath=$shlibpath_overrides_runpath - -# How to hardcode a shared library path into an executable. -hardcode_action=$hardcode_action_RC - -# Whether we should hardcode library paths into libraries. -hardcode_into_libs=$hardcode_into_libs - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist. -hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_RC - -# If ld is used when linking, flag to hardcode \$libdir into -# a binary during linking. This must work even if \$libdir does -# not exist. -hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_RC - -# Whether we need a single -rpath flag with a separated argument. -hardcode_libdir_separator=$lt_hardcode_libdir_separator_RC - -# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the -# resulting binary. -hardcode_direct=$hardcode_direct_RC - -# Set to yes if using the -LDIR flag during linking hardcodes DIR into the -# resulting binary. -hardcode_minus_L=$hardcode_minus_L_RC - -# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into -# the resulting binary. -hardcode_shlibpath_var=$hardcode_shlibpath_var_RC - -# Set to yes if building a shared library automatically hardcodes DIR into the library -# and all subsequent libraries and executables linked against it. -hardcode_automatic=$hardcode_automatic_RC - -# Variables whose values should be saved in libtool wrapper scripts and -# restored at relink time. -variables_saved_for_relink="$variables_saved_for_relink" - -# Whether libtool must link a program against all its dependency libraries. -link_all_deplibs=$link_all_deplibs_RC - -# Compile-time system search path for libraries -sys_lib_search_path_spec=$lt_sys_lib_search_path_spec - -# Run-time system search path for libraries -sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec - -# Fix the shell variable \$srcfile for the compiler. -fix_srcfile_path=$lt_fix_srcfile_path - -# Set to yes if exported symbols are required. -always_export_symbols=$always_export_symbols_RC - -# The commands to list exported symbols. -export_symbols_cmds=$lt_export_symbols_cmds_RC - -# The commands to extract the exported symbol list from a shared archive. -extract_expsyms_cmds=$lt_extract_expsyms_cmds - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms=$lt_exclude_expsyms_RC - -# Symbols that must always be exported. -include_expsyms=$lt_include_expsyms_RC - -# ### END LIBTOOL TAG CONFIG: $tagname - -__EOF__ - - -else - # If there is no Makefile yet, we rely on a make rule to execute - # `config.status --recheck' to rerun these tests and create the - # libtool script then. - ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` - if test -f "$ltmain_in"; then - test -f Makefile && make "$ltmain" - fi -fi - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -CC="$lt_save_CC" - - ;; - - *) - { { echo "$as_me:$LINENO: error: Unsupported tag name: $tagname" >&5 -echo "$as_me: error: Unsupported tag name: $tagname" >&2;} - { (exit 1); exit 1; }; } - ;; - esac - - # Append the new tag name to the list of available tags. - if test -n "$tagname" ; then - available_tags="$available_tags $tagname" - fi - fi - done - IFS="$lt_save_ifs" - - # Now substitute the updated list of available tags. - if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then - mv "${ofile}T" "$ofile" - chmod +x "$ofile" - else - rm -f "${ofile}T" - { { echo "$as_me:$LINENO: error: unable to update list of available tagged configurations." >&5 -echo "$as_me: error: unable to update list of available tagged configurations." >&2;} - { (exit 1); exit 1; }; } - fi -fi - - - -# This can be used to rebuild libtool when needed -LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" - -# Always use our own libtool. -LIBTOOL='$(SHELL) $(top_builddir)/libtool' - -# Prevent multiple expansion - - - - - - - - - - - - - - - - - - - - - - - - - - - -ac_header_dirent=no -for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do - as_ac_Header=`echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` -{ echo "$as_me:$LINENO: checking for $ac_hdr that defines DIR" >&5 -echo $ECHO_N "checking for $ac_hdr that defines DIR... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -#include <$ac_hdr> - -int -main () -{ -if ((DIR *) 0) -return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - eval "$as_ac_Header=yes" -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - eval "$as_ac_Header=no" -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -if test `eval echo '${'$as_ac_Header'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 -_ACEOF - -ac_header_dirent=$ac_hdr; break -fi - -done -# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. -if test $ac_header_dirent = dirent.h; then - { echo "$as_me:$LINENO: checking for library containing opendir" >&5 -echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6; } -if test "${ac_cv_search_opendir+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_func_search_save_LIBS=$LIBS -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char opendir (); -int -main () -{ -return opendir (); - ; - return 0; -} -_ACEOF -for ac_lib in '' dir; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - ac_cv_search_opendir=$ac_res -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext - if test "${ac_cv_search_opendir+set}" = set; then - break -fi -done -if test "${ac_cv_search_opendir+set}" = set; then - : -else - ac_cv_search_opendir=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5 -echo "${ECHO_T}$ac_cv_search_opendir" >&6; } -ac_res=$ac_cv_search_opendir -if test "$ac_res" != no; then - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - -else - { echo "$as_me:$LINENO: checking for library containing opendir" >&5 -echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6; } -if test "${ac_cv_search_opendir+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_func_search_save_LIBS=$LIBS -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char opendir (); -int -main () -{ -return opendir (); - ; - return 0; -} -_ACEOF -for ac_lib in '' x; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - ac_cv_search_opendir=$ac_res -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext - if test "${ac_cv_search_opendir+set}" = set; then - break -fi -done -if test "${ac_cv_search_opendir+set}" = set; then - : -else - ac_cv_search_opendir=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5 -echo "${ECHO_T}$ac_cv_search_opendir" >&6; } -ac_res=$ac_cv_search_opendir -if test "$ac_res" != no; then - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - -fi - -# Check whether --enable-ltdl-install was given. -if test "${enable_ltdl_install+set}" = set; then - enableval=$enable_ltdl_install; -fi - - - if test x"${enable_ltdl_install-no}" != xno; then - INSTALL_LTDL_TRUE= - INSTALL_LTDL_FALSE='#' -else - INSTALL_LTDL_TRUE='#' - INSTALL_LTDL_FALSE= -fi - - if test x"${enable_ltdl_convenience-no}" != xno; then - CONVENIENCE_LTDL_TRUE= - CONVENIENCE_LTDL_FALSE='#' -else - CONVENIENCE_LTDL_TRUE='#' - CONVENIENCE_LTDL_FALSE= -fi - - - -{ echo "$as_me:$LINENO: checking which extension is used for loadable modules" >&5 -echo $ECHO_N "checking which extension is used for loadable modules... $ECHO_C" >&6; } -if test "${libltdl_cv_shlibext+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - -module=yes -eval libltdl_cv_shlibext=$shrext_cmds - -fi -{ echo "$as_me:$LINENO: result: $libltdl_cv_shlibext" >&5 -echo "${ECHO_T}$libltdl_cv_shlibext" >&6; } -if test -n "$libltdl_cv_shlibext"; then - -cat >>confdefs.h <<_ACEOF -#define LTDL_SHLIB_EXT "$libltdl_cv_shlibext" -_ACEOF - -fi - - -{ echo "$as_me:$LINENO: checking which variable specifies run-time library path" >&5 -echo $ECHO_N "checking which variable specifies run-time library path... $ECHO_C" >&6; } -if test "${libltdl_cv_shlibpath_var+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - libltdl_cv_shlibpath_var="$shlibpath_var" -fi -{ echo "$as_me:$LINENO: result: $libltdl_cv_shlibpath_var" >&5 -echo "${ECHO_T}$libltdl_cv_shlibpath_var" >&6; } -if test -n "$libltdl_cv_shlibpath_var"; then - -cat >>confdefs.h <<_ACEOF -#define LTDL_SHLIBPATH_VAR "$libltdl_cv_shlibpath_var" -_ACEOF - -fi - - -{ echo "$as_me:$LINENO: checking for the default library search path" >&5 -echo $ECHO_N "checking for the default library search path... $ECHO_C" >&6; } -if test "${libltdl_cv_sys_search_path+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - libltdl_cv_sys_search_path="$sys_lib_dlsearch_path_spec" -fi -{ echo "$as_me:$LINENO: result: $libltdl_cv_sys_search_path" >&5 -echo "${ECHO_T}$libltdl_cv_sys_search_path" >&6; } -if test -n "$libltdl_cv_sys_search_path"; then - sys_search_path= - for dir in $libltdl_cv_sys_search_path; do - if test -z "$sys_search_path"; then - sys_search_path="$dir" - else - sys_search_path="$sys_search_path$PATH_SEPARATOR$dir" - fi - done - -cat >>confdefs.h <<_ACEOF -#define LTDL_SYSSEARCHPATH "$sys_search_path" -_ACEOF - -fi - -{ echo "$as_me:$LINENO: checking for objdir" >&5 -echo $ECHO_N "checking for objdir... $ECHO_C" >&6; } -if test "${libltdl_cv_objdir+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - libltdl_cv_objdir="$objdir" - if test -n "$objdir"; then - : - else - rm -f .libs 2>/dev/null - mkdir .libs 2>/dev/null - if test -d .libs; then - libltdl_cv_objdir=.libs - else - # MS-DOS does not allow filenames that begin with a dot. - libltdl_cv_objdir=_libs - fi - rmdir .libs 2>/dev/null - fi - -fi -{ echo "$as_me:$LINENO: result: $libltdl_cv_objdir" >&5 -echo "${ECHO_T}$libltdl_cv_objdir" >&6; } - -cat >>confdefs.h <<_ACEOF -#define LTDL_OBJDIR "$libltdl_cv_objdir/" -_ACEOF - - - -{ echo "$as_me:$LINENO: checking whether libtool supports -dlopen/-dlpreopen" >&5 -echo $ECHO_N "checking whether libtool supports -dlopen/-dlpreopen... $ECHO_C" >&6; } -if test "${libltdl_cv_preloaded_symbols+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test -n "$lt_cv_sys_global_symbol_pipe"; then - libltdl_cv_preloaded_symbols=yes - else - libltdl_cv_preloaded_symbols=no - fi - -fi -{ echo "$as_me:$LINENO: result: $libltdl_cv_preloaded_symbols" >&5 -echo "${ECHO_T}$libltdl_cv_preloaded_symbols" >&6; } -if test x"$libltdl_cv_preloaded_symbols" = xyes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_PRELOADED_SYMBOLS 1 -_ACEOF - -fi - -LIBADD_DL= - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -{ echo "$as_me:$LINENO: checking for shl_load" >&5 -echo $ECHO_N "checking for shl_load... $ECHO_C" >&6; } -if test "${ac_cv_func_shl_load+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -/* Define shl_load to an innocuous variant, in case declares shl_load. - For example, HP-UX 11i declares gettimeofday. */ -#define shl_load innocuous_shl_load - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char shl_load (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef shl_load - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char shl_load (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_shl_load || defined __stub___shl_load -choke me -#endif - -int -main () -{ -return shl_load (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - ac_cv_func_shl_load=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_func_shl_load=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -fi -{ echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5 -echo "${ECHO_T}$ac_cv_func_shl_load" >&6; } -if test $ac_cv_func_shl_load = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_SHL_LOAD 1 -_ACEOF - -else - { echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 -echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6; } -if test "${ac_cv_lib_dld_shl_load+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char shl_load (); -int -main () -{ -return shl_load (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - ac_cv_lib_dld_shl_load=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_dld_shl_load=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 -echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6; } -if test $ac_cv_lib_dld_shl_load = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_SHL_LOAD 1 -_ACEOF - - LIBADD_DL="$LIBADD_DL -ldld" -else - { echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 -echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6; } -if test "${ac_cv_lib_dl_dlopen+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - ac_cv_lib_dl_dlopen=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_dl_dlopen=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 -echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6; } -if test $ac_cv_lib_dl_dlopen = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_LIBDL 1 -_ACEOF - - LIBADD_DL="-ldl" libltdl_cv_lib_dl_dlopen="yes" -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#if HAVE_DLFCN_H -# include -#endif - -int -main () -{ -dlopen(0, 0); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_LIBDL 1 -_ACEOF - libltdl_cv_func_dlopen="yes" -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - { echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5 -echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6; } -if test "${ac_cv_lib_svld_dlopen+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lsvld $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - ac_cv_lib_svld_dlopen=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_svld_dlopen=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5 -echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6; } -if test $ac_cv_lib_svld_dlopen = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_LIBDL 1 -_ACEOF - - LIBADD_DL="-lsvld" libltdl_cv_func_dlopen="yes" -else - { echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5 -echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6; } -if test "${ac_cv_lib_dld_dld_link+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dld_link (); -int -main () -{ -return dld_link (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - ac_cv_lib_dld_dld_link=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_dld_dld_link=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5 -echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6; } -if test $ac_cv_lib_dld_dld_link = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_DLD 1 -_ACEOF - - LIBADD_DL="$LIBADD_DL -ldld" -else - { echo "$as_me:$LINENO: checking for _dyld_func_lookup" >&5 -echo $ECHO_N "checking for _dyld_func_lookup... $ECHO_C" >&6; } -if test "${ac_cv_func__dyld_func_lookup+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -/* Define _dyld_func_lookup to an innocuous variant, in case declares _dyld_func_lookup. - For example, HP-UX 11i declares gettimeofday. */ -#define _dyld_func_lookup innocuous__dyld_func_lookup - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char _dyld_func_lookup (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef _dyld_func_lookup - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char _dyld_func_lookup (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub__dyld_func_lookup || defined __stub____dyld_func_lookup -choke me -#endif - -int -main () -{ -return _dyld_func_lookup (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - ac_cv_func__dyld_func_lookup=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_func__dyld_func_lookup=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -fi -{ echo "$as_me:$LINENO: result: $ac_cv_func__dyld_func_lookup" >&5 -echo "${ECHO_T}$ac_cv_func__dyld_func_lookup" >&6; } -if test $ac_cv_func__dyld_func_lookup = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_DYLD 1 -_ACEOF - -fi - - -fi - - -fi - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext - -fi - - -fi - - -fi - - -if test x"$libltdl_cv_func_dlopen" = xyes || test x"$libltdl_cv_lib_dl_dlopen" = xyes -then - lt_save_LIBS="$LIBS" - LIBS="$LIBS $LIBADD_DL" - -for ac_func in dlerror -do -as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` -{ echo "$as_me:$LINENO: checking for $ac_func" >&5 -echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } -if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -/* Define $ac_func to an innocuous variant, in case declares $ac_func. - For example, HP-UX 11i declares gettimeofday. */ -#define $ac_func innocuous_$ac_func - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $ac_func - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $ac_func (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$ac_func || defined __stub___$ac_func -choke me -#endif - -int -main () -{ -return $ac_func (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - eval "$as_ac_var=yes" -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - eval "$as_ac_var=no" -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -fi -ac_res=`eval echo '${'$as_ac_var'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -if test `eval echo '${'$as_ac_var'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - - LIBS="$lt_save_LIBS" -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -{ echo "$as_me:$LINENO: checking for _ prefix in compiled symbols" >&5 -echo $ECHO_N "checking for _ prefix in compiled symbols... $ECHO_C" >&6; } -if test "${ac_cv_sys_symbol_underscore+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_cv_sys_symbol_underscore=no - cat > conftest.$ac_ext <&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then - # Now try to grab the symbols. - ac_nlist=conftest.nm - if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist\"") >&5 - (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && test -s "$ac_nlist"; then - # See whether the symbols have a leading underscore. - if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then - ac_cv_sys_symbol_underscore=yes - else - if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then - : - else - echo "configure: cannot find nm_test_func in $ac_nlist" >&5 - fi - fi - else - echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&5 - fi - else - echo "configure: failed program was:" >&5 - cat conftest.c >&5 - fi - rm -rf conftest* - -fi -{ echo "$as_me:$LINENO: result: $ac_cv_sys_symbol_underscore" >&5 -echo "${ECHO_T}$ac_cv_sys_symbol_underscore" >&6; } - - -if test x"$ac_cv_sys_symbol_underscore" = xyes; then - if test x"$libltdl_cv_func_dlopen" = xyes || - test x"$libltdl_cv_lib_dl_dlopen" = xyes ; then - { echo "$as_me:$LINENO: checking whether we have to add an underscore for dlsym" >&5 -echo $ECHO_N "checking whether we have to add an underscore for dlsym... $ECHO_C" >&6; } -if test "${libltdl_cv_need_uscore+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - libltdl_cv_need_uscore=unknown - save_LIBS="$LIBS" - LIBS="$LIBS $LIBADD_DL" - if test "$cross_compiling" = yes; then : - libltdl_cv_need_uscore=cross -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext < -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -#ifdef __cplusplus -extern "C" void exit (int); -#endif - -void fnord() { int i=42;} -int main () -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - /* dlclose (self); */ - } - else - puts (dlerror ()); - - exit (status); -} -EOF - if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then - (./conftest; exit; ) >&5 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) libltdl_cv_need_uscore=no ;; - x$lt_dlneed_uscore) libltdl_cv_need_uscore=yes ;; - x$lt_dlunknown|x*) ;; - esac - else : - # compilation failed - - fi -fi -rm -fr conftest* - - LIBS="$save_LIBS" - -fi -{ echo "$as_me:$LINENO: result: $libltdl_cv_need_uscore" >&5 -echo "${ECHO_T}$libltdl_cv_need_uscore" >&6; } - fi -fi - -if test x"$libltdl_cv_need_uscore" = xyes; then - -cat >>confdefs.h <<\_ACEOF -#define NEED_USCORE 1 -_ACEOF - -fi - - -{ echo "$as_me:$LINENO: checking whether deplibs are loaded by dlopen" >&5 -echo $ECHO_N "checking whether deplibs are loaded by dlopen... $ECHO_C" >&6; } -if test "${libltdl_cv_sys_dlopen_deplibs+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - # PORTME does your system automatically load deplibs for dlopen? - # or its logical equivalent (e.g. shl_load for HP-UX < 11) - # For now, we just catch OSes we know something about -- in the - # future, we'll try test this programmatically. - libltdl_cv_sys_dlopen_deplibs=unknown - case "$host_os" in - aix3*|aix4.1.*|aix4.2.*) - # Unknown whether this is true for these versions of AIX, but - # we want this `case' here to explicitly catch those versions. - libltdl_cv_sys_dlopen_deplibs=unknown - ;; - aix[45]*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - darwin*) - # Assuming the user has installed a libdl from somewhere, this is true - # If you are looking for one http://www.opendarwin.org/projects/dlcompat - libltdl_cv_sys_dlopen_deplibs=yes - ;; - freebsd* | dragonfly*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - gnu* | linux* | k*bsd*-gnu) - # GNU and its variants, using gnu ld.so (Glibc) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - hpux10*|hpux11*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - interix*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - irix[12345]*|irix6.[01]*) - # Catch all versions of IRIX before 6.2, and indicate that we don't - # know how it worked for any of those versions. - libltdl_cv_sys_dlopen_deplibs=unknown - ;; - irix*) - # The case above catches anything before 6.2, and it's known that - # at 6.2 and later dlopen does load deplibs. - libltdl_cv_sys_dlopen_deplibs=yes - ;; - netbsd* | netbsdelf*-gnu) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - openbsd*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - osf[1234]*) - # dlopen did load deplibs (at least at 4.x), but until the 5.x series, - # it did *not* use an RPATH in a shared library to find objects the - # library depends on, so we explictly say `no'. - libltdl_cv_sys_dlopen_deplibs=no - ;; - osf5.0|osf5.0a|osf5.1) - # dlopen *does* load deplibs and with the right loader patch applied - # it even uses RPATH in a shared library to search for shared objects - # that the library depends on, but there's no easy way to know if that - # patch is installed. Since this is the case, all we can really - # say is unknown -- it depends on the patch being installed. If - # it is, this changes to `yes'. Without it, it would be `no'. - libltdl_cv_sys_dlopen_deplibs=unknown - ;; - osf*) - # the two cases above should catch all versions of osf <= 5.1. Read - # the comments above for what we know about them. - # At > 5.1, deplibs are loaded *and* any RPATH in a shared library - # is used to find them so we can finally say `yes'. - libltdl_cv_sys_dlopen_deplibs=yes - ;; - solaris*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - esac - -fi -{ echo "$as_me:$LINENO: result: $libltdl_cv_sys_dlopen_deplibs" >&5 -echo "${ECHO_T}$libltdl_cv_sys_dlopen_deplibs" >&6; } -if test "$libltdl_cv_sys_dlopen_deplibs" != yes; then - -cat >>confdefs.h <<\_ACEOF -#define LTDL_DLOPEN_DEPLIBS 1 -_ACEOF - -fi - - -for ac_header in argz.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - { echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -else - # Is the header compilable? -{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 -echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_header_compiler=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_compiler=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -echo "${ECHO_T}$ac_header_compiler" >&6; } - -# Is the header present? -{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 -echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <$ac_header> -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - ac_header_preproc=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_preproc=no -fi - -rm -f conftest.err conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -echo "${ECHO_T}$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in - yes:no: ) - { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 -echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} - ac_header_preproc=yes - ;; - no:yes:* ) - { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 -echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 -echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 -echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 -echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 -echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - ( cat <<\_ASBOX -## ---------------------------------- ## -## Report this to bug-libtool@gnu.org ## -## ---------------------------------- ## -_ASBOX - ) | sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac -{ echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - eval "$as_ac_Header=\$ac_header_preproc" -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } - -fi -if test `eval echo '${'$as_ac_Header'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - -{ echo "$as_me:$LINENO: checking for error_t" >&5 -echo $ECHO_N "checking for error_t... $ECHO_C" >&6; } -if test "${ac_cv_type_error_t+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#if HAVE_ARGZ_H -# include -#endif - -typedef error_t ac__type_new_; -int -main () -{ -if ((ac__type_new_ *) 0) - return 0; -if (sizeof (ac__type_new_)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_cv_type_error_t=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_type_error_t=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ echo "$as_me:$LINENO: result: $ac_cv_type_error_t" >&5 -echo "${ECHO_T}$ac_cv_type_error_t" >&6; } -if test $ac_cv_type_error_t = yes; then - -cat >>confdefs.h <<_ACEOF -#define HAVE_ERROR_T 1 -_ACEOF - - -else - -cat >>confdefs.h <<\_ACEOF -#define error_t int -_ACEOF - -fi - - - - - - - -for ac_func in argz_append argz_create_sep argz_insert argz_next argz_stringify -do -as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` -{ echo "$as_me:$LINENO: checking for $ac_func" >&5 -echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } -if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -/* Define $ac_func to an innocuous variant, in case declares $ac_func. - For example, HP-UX 11i declares gettimeofday. */ -#define $ac_func innocuous_$ac_func - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $ac_func - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $ac_func (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$ac_func || defined __stub___$ac_func -choke me -#endif - -int -main () -{ -return $ac_func (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - eval "$as_ac_var=yes" -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - eval "$as_ac_var=no" -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -fi -ac_res=`eval echo '${'$as_ac_var'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -if test `eval echo '${'$as_ac_var'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - - - - - - - - - - - - - - - - - - - - - - - - - - - - -for ac_header in assert.h ctype.h errno.h malloc.h memory.h stdlib.h \ - stdio.h unistd.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - { echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -else - # Is the header compilable? -{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 -echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_header_compiler=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_compiler=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -echo "${ECHO_T}$ac_header_compiler" >&6; } - -# Is the header present? -{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 -echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <$ac_header> -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - ac_header_preproc=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_preproc=no -fi - -rm -f conftest.err conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -echo "${ECHO_T}$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in - yes:no: ) - { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 -echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} - ac_header_preproc=yes - ;; - no:yes:* ) - { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 -echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 -echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 -echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 -echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 -echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - ( cat <<\_ASBOX -## ---------------------------------- ## -## Report this to bug-libtool@gnu.org ## -## ---------------------------------- ## -_ASBOX - ) | sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac -{ echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - eval "$as_ac_Header=\$ac_header_preproc" -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } - -fi -if test `eval echo '${'$as_ac_Header'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - - - - -for ac_header in dl.h sys/dl.h dld.h mach-o/dyld.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - { echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -else - # Is the header compilable? -{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 -echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_header_compiler=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_compiler=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -echo "${ECHO_T}$ac_header_compiler" >&6; } - -# Is the header present? -{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 -echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <$ac_header> -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - ac_header_preproc=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_preproc=no -fi - -rm -f conftest.err conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -echo "${ECHO_T}$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in - yes:no: ) - { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 -echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} - ac_header_preproc=yes - ;; - no:yes:* ) - { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 -echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 -echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 -echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 -echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 -echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - ( cat <<\_ASBOX -## ---------------------------------- ## -## Report this to bug-libtool@gnu.org ## -## ---------------------------------- ## -_ASBOX - ) | sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac -{ echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - eval "$as_ac_Header=\$ac_header_preproc" -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } - -fi -if test `eval echo '${'$as_ac_Header'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - - -for ac_header in string.h strings.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - { echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -else - # Is the header compilable? -{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 -echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_header_compiler=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_compiler=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -echo "${ECHO_T}$ac_header_compiler" >&6; } - -# Is the header present? -{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 -echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <$ac_header> -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - ac_header_preproc=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_preproc=no -fi - -rm -f conftest.err conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -echo "${ECHO_T}$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in - yes:no: ) - { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 -echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} - ac_header_preproc=yes - ;; - no:yes:* ) - { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 -echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 -echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 -echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 -echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 -echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - ( cat <<\_ASBOX -## ---------------------------------- ## -## Report this to bug-libtool@gnu.org ## -## ---------------------------------- ## -_ASBOX - ) | sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac -{ echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - eval "$as_ac_Header=\$ac_header_preproc" -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } - -fi -if test `eval echo '${'$as_ac_Header'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - break -fi - -done - - - - -for ac_func in strchr index -do -as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` -{ echo "$as_me:$LINENO: checking for $ac_func" >&5 -echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } -if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -/* Define $ac_func to an innocuous variant, in case declares $ac_func. - For example, HP-UX 11i declares gettimeofday. */ -#define $ac_func innocuous_$ac_func - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $ac_func - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $ac_func (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$ac_func || defined __stub___$ac_func -choke me -#endif - -int -main () -{ -return $ac_func (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - eval "$as_ac_var=yes" -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - eval "$as_ac_var=no" -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -fi -ac_res=`eval echo '${'$as_ac_var'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -if test `eval echo '${'$as_ac_var'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - break -fi -done - - - -for ac_func in strrchr rindex -do -as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` -{ echo "$as_me:$LINENO: checking for $ac_func" >&5 -echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } -if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -/* Define $ac_func to an innocuous variant, in case declares $ac_func. - For example, HP-UX 11i declares gettimeofday. */ -#define $ac_func innocuous_$ac_func - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $ac_func - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $ac_func (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$ac_func || defined __stub___$ac_func -choke me -#endif - -int -main () -{ -return $ac_func (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - eval "$as_ac_var=yes" -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - eval "$as_ac_var=no" -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -fi -ac_res=`eval echo '${'$as_ac_var'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -if test `eval echo '${'$as_ac_var'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - break -fi -done - - - -for ac_func in memcpy bcopy -do -as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` -{ echo "$as_me:$LINENO: checking for $ac_func" >&5 -echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } -if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -/* Define $ac_func to an innocuous variant, in case declares $ac_func. - For example, HP-UX 11i declares gettimeofday. */ -#define $ac_func innocuous_$ac_func - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $ac_func - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $ac_func (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$ac_func || defined __stub___$ac_func -choke me -#endif - -int -main () -{ -return $ac_func (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - eval "$as_ac_var=yes" -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - eval "$as_ac_var=no" -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -fi -ac_res=`eval echo '${'$as_ac_var'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -if test `eval echo '${'$as_ac_var'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - break -fi -done - - - -for ac_func in memmove strcmp -do -as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` -{ echo "$as_me:$LINENO: checking for $ac_func" >&5 -echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } -if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -/* Define $ac_func to an innocuous variant, in case declares $ac_func. - For example, HP-UX 11i declares gettimeofday. */ -#define $ac_func innocuous_$ac_func - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $ac_func - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $ac_func (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$ac_func || defined __stub___$ac_func -choke me -#endif - -int -main () -{ -return $ac_func (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - eval "$as_ac_var=yes" -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - eval "$as_ac_var=no" -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -fi -ac_res=`eval echo '${'$as_ac_var'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -if test `eval echo '${'$as_ac_var'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - - - - -for ac_func in closedir opendir readdir -do -as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` -{ echo "$as_me:$LINENO: checking for $ac_func" >&5 -echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } -if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -/* Define $ac_func to an innocuous variant, in case declares $ac_func. - For example, HP-UX 11i declares gettimeofday. */ -#define $ac_func innocuous_$ac_func - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $ac_func - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $ac_func (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$ac_func || defined __stub___$ac_func -choke me -#endif - -int -main () -{ -return $ac_func (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - eval "$as_ac_var=yes" -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - eval "$as_ac_var=no" -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -fi -ac_res=`eval echo '${'$as_ac_var'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -if test `eval echo '${'$as_ac_var'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - - - - -## -------- ## -## Outputs. ## -## -------- ## -ac_config_files="$ac_config_files Makefile" - -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# `ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 -echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - *) $as_unset $ac_var ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes (double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \). - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # `set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - test "x$cache_file" != "x/dev/null" && - { echo "$as_me:$LINENO: updating cache $cache_file" >&5 -echo "$as_me: updating cache $cache_file" >&6;} - cat confcache >$cache_file - else - { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 -echo "$as_me: not updating unwritable cache $cache_file" >&6;} - fi -fi -rm -f confcache - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -DEFS=-DHAVE_CONFIG_H - -ac_libobjs= -ac_ltlibobjs= -for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`echo "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" - ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIBOBJS=$ac_libobjs - -LTLIBOBJS=$ac_ltlibobjs - - -if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then - { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. -Usually this means the macro was only invoked conditionally." >&5 -echo "$as_me: error: conditional \"AMDEP\" was never defined. -Usually this means the macro was only invoked conditionally." >&2;} - { (exit 1); exit 1; }; } -fi -if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then - { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined. -Usually this means the macro was only invoked conditionally." >&5 -echo "$as_me: error: conditional \"am__fastdepCC\" was never defined. -Usually this means the macro was only invoked conditionally." >&2;} - { (exit 1); exit 1; }; } -fi -if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then - { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined. -Usually this means the macro was only invoked conditionally." >&5 -echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined. -Usually this means the macro was only invoked conditionally." >&2;} - { (exit 1); exit 1; }; } -fi -if test -z "${INSTALL_LTDL_TRUE}" && test -z "${INSTALL_LTDL_FALSE}"; then - { { echo "$as_me:$LINENO: error: conditional \"INSTALL_LTDL\" was never defined. -Usually this means the macro was only invoked conditionally." >&5 -echo "$as_me: error: conditional \"INSTALL_LTDL\" was never defined. -Usually this means the macro was only invoked conditionally." >&2;} - { (exit 1); exit 1; }; } -fi -if test -z "${CONVENIENCE_LTDL_TRUE}" && test -z "${CONVENIENCE_LTDL_FALSE}"; then - { { echo "$as_me:$LINENO: error: conditional \"CONVENIENCE_LTDL\" was never defined. -Usually this means the macro was only invoked conditionally." >&5 -echo "$as_me: error: conditional \"CONVENIENCE_LTDL\" was never defined. -Usually this means the macro was only invoked conditionally." >&2;} - { (exit 1); exit 1; }; } -fi - -: ${CONFIG_STATUS=./config.status} -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 -echo "$as_me: creating $CONFIG_STATUS" >&6;} -cat >$CONFIG_STATUS <<_ACEOF -#! $SHELL -# Generated by $as_me. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false -SHELL=\${CONFIG_SHELL-$SHELL} -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF -## --------------------- ## -## M4sh Initialization. ## -## --------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in - *posix*) set -o posix ;; -esac - -fi - - - - -# PATH needs CR -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - echo "#! /bin/sh" >conf$$.sh - echo "exit 0" >>conf$$.sh - chmod +x conf$$.sh - if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then - PATH_SEPARATOR=';' - else - PATH_SEPARATOR=: - fi - rm -f conf$$.sh -fi - -# Support unset when possible. -if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then - as_unset=unset -else - as_unset=false -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -as_nl=' -' -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -case $0 in - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break -done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - { (exit 1); exit 1; } -fi - -# Work around bugs in pre-3.0 UWIN ksh. -for as_var in ENV MAIL MAILPATH -do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -for as_var in \ - LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ - LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ - LC_TELEPHONE LC_TIME -do - if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then - eval $as_var=C; export $as_var - else - ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var - fi -done - -# Required to use basename. -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - - -# Name of the executable. -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# CDPATH. -$as_unset CDPATH - - - - as_lineno_1=$LINENO - as_lineno_2=$LINENO - test "x$as_lineno_1" != "x$as_lineno_2" && - test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { - - # Create $as_me.lineno as a copy of $as_myself, but with $LINENO - # uniformly replaced by the line number. The first 'sed' inserts a - # line-number line after each line using $LINENO; the second 'sed' - # does the real work. The second script uses 'N' to pair each - # line-number line with the line containing $LINENO, and appends - # trailing '-' during substitution so that $LINENO is not a special - # case at line end. - # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the - # scripts with optimization help from Paolo Bonzini. Blame Lee - # E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 - { (exit 1); exit 1; }; } - - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in --n*) - case `echo 'x\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - *) ECHO_C='\c';; - esac;; -*) - ECHO_N='-n';; -esac - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir -fi -echo >conf$$.file -if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -p' -elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln -else - as_ln_s='cp -p' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p=: -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -if test -x / >/dev/null 2>&1; then - as_test_x='test -x' -else - if ls -dL / >/dev/null 2>&1; then - as_ls_L_option=L - else - as_ls_L_option= - fi - as_test_x=' - eval sh -c '\'' - if test -d "$1"; then - test -d "$1/."; - else - case $1 in - -*)set "./$1";; - esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in - ???[sx]*):;;*)false;;esac;fi - '\'' sh - ' -fi -as_executable_p=$as_test_x - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -exec 6>&1 - -# Save the log message, to keep $[0] and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by libltdl $as_me 1.2, which was -generated by GNU Autoconf 2.61. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -_ACEOF - -cat >>$CONFIG_STATUS <<_ACEOF -# Files that config.status was made for. -config_files="$ac_config_files" -config_headers="$ac_config_headers" -config_commands="$ac_config_commands" - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF -ac_cs_usage="\ -\`$as_me' instantiates files from templates according to the -current configuration. - -Usage: $0 [OPTIONS] [FILE]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - -q, --quiet do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE - --header=FILE[:TEMPLATE] - instantiate the configuration header FILE - -Configuration files: -$config_files - -Configuration headers: -$config_headers - -Configuration commands: -$config_commands - -Report bugs to ." - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF -ac_cs_version="\\ -libltdl config.status 1.2 -configured by $0, generated by GNU Autoconf 2.61, - with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" - -Copyright (C) 2006 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='$ac_pwd' -srcdir='$srcdir' -INSTALL='$INSTALL' -MKDIR_P='$MKDIR_P' -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF -# If no file are specified by the user, then we need to provide default -# value. By we need to know if files were specified by the user. -ac_need_defaults=: -while test $# != 0 -do - case $1 in - --*=*) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` - ac_shift=: - ;; - *) - ac_option=$1 - ac_optarg=$2 - ac_shift=shift - ;; - esac - - case $ac_option in - # Handling of the options. - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - ac_cs_recheck=: ;; - --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - echo "$ac_cs_version"; exit ;; - --debug | --debu | --deb | --de | --d | -d ) - debug=: ;; - --file | --fil | --fi | --f ) - $ac_shift - CONFIG_FILES="$CONFIG_FILES $ac_optarg" - ac_need_defaults=false;; - --header | --heade | --head | --hea ) - $ac_shift - CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" - ac_need_defaults=false;; - --he | --h) - # Conflict between --help and --header - { echo "$as_me: error: ambiguous option: $1 -Try \`$0 --help' for more information." >&2 - { (exit 1); exit 1; }; };; - --help | --hel | -h ) - echo "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil | --si | --s) - ac_cs_silent=: ;; - - # This is an error. - -*) { echo "$as_me: error: unrecognized option: $1 -Try \`$0 --help' for more information." >&2 - { (exit 1); exit 1; }; } ;; - - *) ac_config_targets="$ac_config_targets $1" - ac_need_defaults=false ;; - - esac - shift -done - -ac_configure_extra_args= - -if $ac_cs_silent; then - exec 6>/dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF -if \$ac_cs_recheck; then - echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 - CONFIG_SHELL=$SHELL - export CONFIG_SHELL - exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion -fi - -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX -## Running $as_me. ## -_ASBOX - echo "$ac_log" -} >&5 - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF -# -# INIT-COMMANDS -# -AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h:config-h.in" ;; - "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; - "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - - *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 -echo "$as_me: error: invalid argument: $ac_config_target" >&2;} - { (exit 1); exit 1; }; };; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files - test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers - test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to `$tmp'. -$debug || -{ - tmp= - trap 'exit_status=$? - { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status -' 0 - trap '{ (exit 1); exit 1; }' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -n "$tmp" && test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || -{ - echo "$me: cannot create a temporary directory in ." >&2 - { (exit 1); exit 1; } -} - -# -# Set up the sed scripts for CONFIG_FILES section. -# - -# No need to generate the scripts if there are no CONFIG_FILES. -# This happens for instance when ./config.status config.h -if test -n "$CONFIG_FILES"; then - -_ACEOF - - - -ac_delim='%!_!# ' -for ac_last_try in false false false false false :; do - cat >conf$$subs.sed <<_ACEOF -SHELL!$SHELL$ac_delim -PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim -PACKAGE_NAME!$PACKAGE_NAME$ac_delim -PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim -PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim -PACKAGE_STRING!$PACKAGE_STRING$ac_delim -PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim -exec_prefix!$exec_prefix$ac_delim -prefix!$prefix$ac_delim -program_transform_name!$program_transform_name$ac_delim -bindir!$bindir$ac_delim -sbindir!$sbindir$ac_delim -libexecdir!$libexecdir$ac_delim -datarootdir!$datarootdir$ac_delim -datadir!$datadir$ac_delim -sysconfdir!$sysconfdir$ac_delim -sharedstatedir!$sharedstatedir$ac_delim -localstatedir!$localstatedir$ac_delim -includedir!$includedir$ac_delim -oldincludedir!$oldincludedir$ac_delim -docdir!$docdir$ac_delim -infodir!$infodir$ac_delim -htmldir!$htmldir$ac_delim -dvidir!$dvidir$ac_delim -pdfdir!$pdfdir$ac_delim -psdir!$psdir$ac_delim -libdir!$libdir$ac_delim -localedir!$localedir$ac_delim -mandir!$mandir$ac_delim -DEFS!$DEFS$ac_delim -ECHO_C!$ECHO_C$ac_delim -ECHO_N!$ECHO_N$ac_delim -ECHO_T!$ECHO_T$ac_delim -LIBS!$LIBS$ac_delim -build_alias!$build_alias$ac_delim -host_alias!$host_alias$ac_delim -target_alias!$target_alias$ac_delim -INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim -INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim -INSTALL_DATA!$INSTALL_DATA$ac_delim -am__isrc!$am__isrc$ac_delim -CYGPATH_W!$CYGPATH_W$ac_delim -PACKAGE!$PACKAGE$ac_delim -VERSION!$VERSION$ac_delim -ACLOCAL!$ACLOCAL$ac_delim -AUTOCONF!$AUTOCONF$ac_delim -AUTOMAKE!$AUTOMAKE$ac_delim -AUTOHEADER!$AUTOHEADER$ac_delim -MAKEINFO!$MAKEINFO$ac_delim -install_sh!$install_sh$ac_delim -STRIP!$STRIP$ac_delim -INSTALL_STRIP_PROGRAM!$INSTALL_STRIP_PROGRAM$ac_delim -mkdir_p!$mkdir_p$ac_delim -AWK!$AWK$ac_delim -SET_MAKE!$SET_MAKE$ac_delim -am__leading_dot!$am__leading_dot$ac_delim -AMTAR!$AMTAR$ac_delim -am__tar!$am__tar$ac_delim -am__untar!$am__untar$ac_delim -CC!$CC$ac_delim -CFLAGS!$CFLAGS$ac_delim -LDFLAGS!$LDFLAGS$ac_delim -CPPFLAGS!$CPPFLAGS$ac_delim -ac_ct_CC!$ac_ct_CC$ac_delim -EXEEXT!$EXEEXT$ac_delim -OBJEXT!$OBJEXT$ac_delim -DEPDIR!$DEPDIR$ac_delim -am__include!$am__include$ac_delim -am__quote!$am__quote$ac_delim -AMDEP_TRUE!$AMDEP_TRUE$ac_delim -AMDEP_FALSE!$AMDEP_FALSE$ac_delim -AMDEPBACKSLASH!$AMDEPBACKSLASH$ac_delim -CCDEPMODE!$CCDEPMODE$ac_delim -am__fastdepCC_TRUE!$am__fastdepCC_TRUE$ac_delim -am__fastdepCC_FALSE!$am__fastdepCC_FALSE$ac_delim -build!$build$ac_delim -build_cpu!$build_cpu$ac_delim -build_vendor!$build_vendor$ac_delim -build_os!$build_os$ac_delim -host!$host$ac_delim -host_cpu!$host_cpu$ac_delim -host_vendor!$host_vendor$ac_delim -host_os!$host_os$ac_delim -SED!$SED$ac_delim -GREP!$GREP$ac_delim -EGREP!$EGREP$ac_delim -LN_S!$LN_S$ac_delim -ECHO!$ECHO$ac_delim -AR!$AR$ac_delim -RANLIB!$RANLIB$ac_delim -DLLTOOL!$DLLTOOL$ac_delim -AS!$AS$ac_delim -OBJDUMP!$OBJDUMP$ac_delim -CPP!$CPP$ac_delim -CXX!$CXX$ac_delim -CXXFLAGS!$CXXFLAGS$ac_delim -ac_ct_CXX!$ac_ct_CXX$ac_delim -_ACEOF - - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then - break - elif $ac_last_try; then - { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 -echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} - { (exit 1); exit 1; }; } - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done - -ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` -if test -n "$ac_eof"; then - ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` - ac_eof=`expr $ac_eof + 1` -fi - -cat >>$CONFIG_STATUS <<_ACEOF -cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -_ACEOF -sed ' -s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g -s/^/s,@/; s/!/@,|#_!!_#|/ -:n -t n -s/'"$ac_delim"'$/,g/; t -s/$/\\/; p -N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n -' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF -CEOF$ac_eof -_ACEOF - - -ac_delim='%!_!# ' -for ac_last_try in false false false false false :; do - cat >conf$$subs.sed <<_ACEOF -CXXDEPMODE!$CXXDEPMODE$ac_delim -am__fastdepCXX_TRUE!$am__fastdepCXX_TRUE$ac_delim -am__fastdepCXX_FALSE!$am__fastdepCXX_FALSE$ac_delim -CXXCPP!$CXXCPP$ac_delim -F77!$F77$ac_delim -FFLAGS!$FFLAGS$ac_delim -ac_ct_F77!$ac_ct_F77$ac_delim -LIBTOOL!$LIBTOOL$ac_delim -LIBTOOL_DEPS!$LIBTOOL_DEPS$ac_delim -INSTALL_LTDL_TRUE!$INSTALL_LTDL_TRUE$ac_delim -INSTALL_LTDL_FALSE!$INSTALL_LTDL_FALSE$ac_delim -CONVENIENCE_LTDL_TRUE!$CONVENIENCE_LTDL_TRUE$ac_delim -CONVENIENCE_LTDL_FALSE!$CONVENIENCE_LTDL_FALSE$ac_delim -LIBADD_DL!$LIBADD_DL$ac_delim -LIBOBJS!$LIBOBJS$ac_delim -LTLIBOBJS!$LTLIBOBJS$ac_delim -_ACEOF - - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 16; then - break - elif $ac_last_try; then - { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 -echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} - { (exit 1); exit 1; }; } - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done - -ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` -if test -n "$ac_eof"; then - ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` - ac_eof=`expr $ac_eof + 1` -fi - -cat >>$CONFIG_STATUS <<_ACEOF -cat >"\$tmp/subs-2.sed" <<\CEOF$ac_eof -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end -_ACEOF -sed ' -s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g -s/^/s,@/; s/!/@,|#_!!_#|/ -:n -t n -s/'"$ac_delim"'$/,g/; t -s/$/\\/; p -N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n -' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF -:end -s/|#_!!_#|//g -CEOF$ac_eof -_ACEOF - - -# VPATH may cause trouble with some makes, so we remove $(srcdir), -# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and -# trailing colons and then remove the whole line if VPATH becomes empty -# (actually we leave an empty line to preserve line numbers). -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=/{ -s/:*\$(srcdir):*/:/ -s/:*\${srcdir}:*/:/ -s/:*@srcdir@:*/:/ -s/^\([^=]*=[ ]*\):*/\1/ -s/:*$// -s/^[^=]*=[ ]*$// -}' -fi - -cat >>$CONFIG_STATUS <<\_ACEOF -fi # test -n "$CONFIG_FILES" - - -for ac_tag in :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 -echo "$as_me: error: Invalid tag $ac_tag." >&2;} - { (exit 1); exit 1; }; };; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain `:'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 -echo "$as_me: error: cannot find input file: $ac_f" >&2;} - { (exit 1); exit 1; }; };; - esac - ac_file_inputs="$ac_file_inputs $ac_f" - done - - # Let's still pretend it is `configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input="Generated from "`IFS=: - echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { echo "$as_me:$LINENO: creating $ac_file" >&5 -echo "$as_me: creating $ac_file" >&6;} - fi - - case $ac_tag in - *:-:* | *:-) cat >"$tmp/stdin";; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -echo X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - { as_dir="$ac_dir" - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 -echo "$as_me: error: cannot create directory $as_dir" >&2;} - { (exit 1); exit 1; }; }; } - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - :F) - # - # CONFIG_FILE - # - - case $INSTALL in - [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; - *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; - esac - ac_MKDIR_P=$MKDIR_P - case $MKDIR_P in - [\\/$]* | ?:[\\/]* ) ;; - */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; - esac -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF -# If the template does not know about datarootdir, expand it. -# FIXME: This hack should be removed a few years after 2.60. -ac_datarootdir_hack=; ac_datarootdir_seen= - -case `sed -n '/datarootdir/ { - p - q -} -/@datadir@/p -/@docdir@/p -/@infodir@/p -/@localedir@/p -/@mandir@/p -' $ac_file_inputs` in -*datarootdir*) ac_datarootdir_seen=yes;; -*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF - ac_datarootdir_hack=' - s&@datadir@&$datadir&g - s&@docdir@&$docdir&g - s&@infodir@&$infodir&g - s&@localedir@&$localedir&g - s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; -esac -_ACEOF - -# Neutralize VPATH when `$srcdir' = `.'. -# Shell code in configure.ac might set extrasub. -# FIXME: do we really want to maintain this feature? -cat >>$CONFIG_STATUS <<_ACEOF - sed "$ac_vpsub -$extrasub -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF -:t -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s&@configure_input@&$configure_input&;t t -s&@top_builddir@&$ac_top_builddir_sub&;t t -s&@srcdir@&$ac_srcdir&;t t -s&@abs_srcdir@&$ac_abs_srcdir&;t t -s&@top_srcdir@&$ac_top_srcdir&;t t -s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t -s&@builddir@&$ac_builddir&;t t -s&@abs_builddir@&$ac_abs_builddir&;t t -s&@abs_top_builddir@&$ac_abs_top_builddir&;t t -s&@INSTALL@&$ac_INSTALL&;t t -s&@MKDIR_P@&$ac_MKDIR_P&;t t -$ac_datarootdir_hack -" $ac_file_inputs | sed -f "$tmp/subs-1.sed" | sed -f "$tmp/subs-2.sed" >$tmp/out - -test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && - { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined." >&5 -echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined." >&2;} - - rm -f "$tmp/stdin" - case $ac_file in - -) cat "$tmp/out"; rm -f "$tmp/out";; - *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; - esac - ;; - :H) - # - # CONFIG_HEADER - # -_ACEOF - -# Transform confdefs.h into a sed script `conftest.defines', that -# substitutes the proper values into config.h.in to produce config.h. -rm -f conftest.defines conftest.tail -# First, append a space to every undef/define line, to ease matching. -echo 's/$/ /' >conftest.defines -# Then, protect against being on the right side of a sed subst, or in -# an unquoted here document, in config.status. If some macros were -# called several times there might be several #defines for the same -# symbol, which is useless. But do not sort them, since the last -# AC_DEFINE must be honored. -ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* -# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where -# NAME is the cpp macro being defined, VALUE is the value it is being given. -# PARAMS is the parameter list in the macro definition--in most cases, it's -# just an empty string. -ac_dA='s,^\\([ #]*\\)[^ ]*\\([ ]*' -ac_dB='\\)[ (].*,\\1define\\2' -ac_dC=' ' -ac_dD=' ,' - -uniq confdefs.h | - sed -n ' - t rset - :rset - s/^[ ]*#[ ]*define[ ][ ]*// - t ok - d - :ok - s/[\\&,]/\\&/g - s/^\('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p - s/^\('"$ac_word_re"'\)[ ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p - ' >>conftest.defines - -# Remove the space that was appended to ease matching. -# Then replace #undef with comments. This is necessary, for -# example, in the case of _POSIX_SOURCE, which is predefined and required -# on some systems where configure will not decide to define it. -# (The regexp can be short, since the line contains either #define or #undef.) -echo 's/ $// -s,^[ #]*u.*,/* & */,' >>conftest.defines - -# Break up conftest.defines: -ac_max_sed_lines=50 - -# First sed command is: sed -f defines.sed $ac_file_inputs >"$tmp/out1" -# Second one is: sed -f defines.sed "$tmp/out1" >"$tmp/out2" -# Third one will be: sed -f defines.sed "$tmp/out2" >"$tmp/out1" -# et cetera. -ac_in='$ac_file_inputs' -ac_out='"$tmp/out1"' -ac_nxt='"$tmp/out2"' - -while : -do - # Write a here document: - cat >>$CONFIG_STATUS <<_ACEOF - # First, check the format of the line: - cat >"\$tmp/defines.sed" <<\\CEOF -/^[ ]*#[ ]*undef[ ][ ]*$ac_word_re[ ]*\$/b def -/^[ ]*#[ ]*define[ ][ ]*$ac_word_re[( ]/b def -b -:def -_ACEOF - sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS - echo 'CEOF - sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS - ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in - sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail - grep . conftest.tail >/dev/null || break - rm -f conftest.defines - mv conftest.tail conftest.defines -done -rm -f conftest.defines conftest.tail - -echo "ac_result=$ac_in" >>$CONFIG_STATUS -cat >>$CONFIG_STATUS <<\_ACEOF - if test x"$ac_file" != x-; then - echo "/* $configure_input */" >"$tmp/config.h" - cat "$ac_result" >>"$tmp/config.h" - if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then - { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 -echo "$as_me: $ac_file is unchanged" >&6;} - else - rm -f $ac_file - mv "$tmp/config.h" $ac_file - fi - else - echo "/* $configure_input */" - cat "$ac_result" - fi - rm -f "$tmp/out12" -# Compute $ac_file's index in $config_headers. -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $ac_file | $ac_file:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $ac_file" >`$as_dirname -- $ac_file || -$as_expr X$ac_file : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X$ac_file : 'X\(//\)[^/]' \| \ - X$ac_file : 'X\(//\)$' \| \ - X$ac_file : 'X\(/\)' \| . 2>/dev/null || -echo X$ac_file | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'`/stamp-h$_am_stamp_count - ;; - - :C) { echo "$as_me:$LINENO: executing $ac_file commands" >&5 -echo "$as_me: executing $ac_file commands" >&6;} - ;; - esac - - - case $ac_file$ac_mode in - "depfiles":C) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do - # Strip MF so we end up with the name of the file. - mf=`echo "$mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile or not. - # We used to match only the files named `Makefile.in', but - # some people rename them; so instead we look at the file content. - # Grep'ing the first line is not enough: some people post-process - # each Makefile.in and add a new line on top of each file to say so. - # Grep'ing the whole file is not good either: AIX grep has a line - # limit of 2048, but all sed's we know have understand at least 4000. - if sed 10q "$mf" | grep '^#.*generated by automake' > /dev/null 2>&1; then - dirpart=`$as_dirname -- "$mf" || -$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$mf" : 'X\(//\)[^/]' \| \ - X"$mf" : 'X\(//\)$' \| \ - X"$mf" : 'X\(/\)' \| . 2>/dev/null || -echo X"$mf" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - else - continue - fi - # Extract the definition of DEPDIR, am__include, and am__quote - # from the Makefile without running `make'. - DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` - test -z "$DEPDIR" && continue - am__include=`sed -n 's/^am__include = //p' < "$mf"` - test -z "am__include" && continue - am__quote=`sed -n 's/^am__quote = //p' < "$mf"` - # When using ansi2knr, U may be empty or an underscore; expand it - U=`sed -n 's/^U = //p' < "$mf"` - # Find all dependency output files, they are included files with - # $(DEPDIR) in their names. We invoke sed twice because it is the - # simplest approach to changing $(DEPDIR) to its actual value in the - # expansion. - for file in `sed -n " - s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ - sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do - # Make sure the directory exists. - test -f "$dirpart/$file" && continue - fdir=`$as_dirname -- "$file" || -$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$file" : 'X\(//\)[^/]' \| \ - X"$file" : 'X\(//\)$' \| \ - X"$file" : 'X\(/\)' \| . 2>/dev/null || -echo X"$file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - { as_dir=$dirpart/$fdir - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 -echo "$as_me: error: cannot create directory $as_dir" >&2;} - { (exit 1); exit 1; }; }; } - # echo "creating $dirpart/$file" - echo '# dummy' > "$dirpart/$file" - done -done - ;; - - esac -done # for ac_tag - - -{ (exit 0); exit 0; } -_ACEOF -chmod +x $CONFIG_STATUS -ac_clean_files=$ac_clean_files_save - - -# configure is writing to config.log, and then calls config.status. -# config.status does its own redirection, appending to config.log. -# Unfortunately, on DOS this fails, as config.log is still kept open -# by configure, so config.status won't be able to write to it; its -# output is simply discarded. So we exec the FD to /dev/null, -# effectively closing config.log, so it can be properly (re)opened and -# appended to by config.status. When coming back to configure, we -# need to make the FD available again. -if test "$no_create" != yes; then - ac_cs_success=: - ac_config_status_args= - test "$silent" = yes && - ac_config_status_args="$ac_config_status_args --quiet" - exec 5>/dev/null - $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false - exec 5>>config.log - # Use ||, not &&, to avoid exiting from the if with $? = 1, which - # would make configure fail if this is the last instruction. - $ac_cs_success || { (exit 1); exit 1; } -fi - diff --git a/libltdl/configure.ac b/libltdl/configure.ac deleted file mode 100644 index 1446efbd..00000000 --- a/libltdl/configure.ac +++ /dev/null @@ -1,79 +0,0 @@ -## Process this file with autoconf to create configure. -*- autoconf -*- -# Copyright 2001 Free Software Foundation, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301 USA - - -dnl FIXME: Is this really new enough? -AC_PREREQ(2.50) - - -## ------------------------ ## -## Autoconf initialisation. ## -## ------------------------ ## -AC_INIT([libltdl], [1.2], [bug-libtool@gnu.org]) -AC_CONFIG_SRCDIR([ltdl.c]) - - -## ------------------------------- ## -## Libltdl specific configuration. ## -## ------------------------------- ## - -AC_CONFIG_AUX_DIR([.]) - -if test -z "$enable_ltdl_install$enable_ltdl_convenience"; then - if test -f ${srcdir}/ltmain.sh; then - # if libltdl is libtoolized, it is assumed to be stand-alone and - # installed unless the command line overrides it (tested above) - enable_ltdl_install=yes - else - AC_MSG_WARN([*** The top-level configure must select either]) - AC_MSG_WARN([*** [A""C_LIBLTDL_INSTALLABLE] or [A""C_LIBLTDL_CONVENIENCE].]) - AC_MSG_ERROR([*** Maybe you want to --enable-ltdl-install?]) - fi -fi - - -## ------------------------ ## -## Automake Initialisation. ## -## ------------------------ ## -AM_INIT_AUTOMAKE(AC_PACKAGE_TARNAME, AC_PACKAGE_VERSION, -) -AM_CONFIG_HEADER([config.h:config-h.in]) - - -## ------------------ ## -## C compiler checks. ## -## ------------------ ## -AC_PROG_CC -AC_C_CONST -AC_C_INLINE - - -## ----------------------- ## -## Libtool initialisation. ## -## ----------------------- ## -AC_LIBTOOL_WIN32_DLL -AC_PROG_LIBTOOL -AC_SUBST([LIBTOOL_DEPS]) - -AC_LIB_LTDL - - -## -------- ## -## Outputs. ## -## -------- ## -AC_CONFIG_FILES([Makefile]) -AC_OUTPUT diff --git a/libltdl/install-sh b/libltdl/install-sh deleted file mode 100755 index a5897de6..00000000 --- a/libltdl/install-sh +++ /dev/null @@ -1,519 +0,0 @@ -#!/bin/sh -# install - install a program, script, or datafile - -scriptversion=2006-12-25.00 - -# This originates from X11R5 (mit/util/scripts/install.sh), which was -# later released in X11R6 (xc/config/util/install.sh) with the -# following copyright and license. -# -# Copyright (C) 1994 X Consortium -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- -# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Except as contained in this notice, the name of the X Consortium shall not -# be used in advertising or otherwise to promote the sale, use or other deal- -# ings in this Software without prior written authorization from the X Consor- -# tium. -# -# -# FSF changes to this file are in the public domain. -# -# Calling this script install-sh is preferred over install.sh, to prevent -# `make' implicit rules from creating a file called install from it -# when there is no Makefile. -# -# This script is compatible with the BSD install script, but was written -# from scratch. - -nl=' -' -IFS=" "" $nl" - -# set DOITPROG to echo to test this script - -# Don't use :- since 4.3BSD and earlier shells don't like it. -doit=${DOITPROG-} -if test -z "$doit"; then - doit_exec=exec -else - doit_exec=$doit -fi - -# Put in absolute file names if you don't have them in your path; -# or use environment vars. - -chgrpprog=${CHGRPPROG-chgrp} -chmodprog=${CHMODPROG-chmod} -chownprog=${CHOWNPROG-chown} -cmpprog=${CMPPROG-cmp} -cpprog=${CPPROG-cp} -mkdirprog=${MKDIRPROG-mkdir} -mvprog=${MVPROG-mv} -rmprog=${RMPROG-rm} -stripprog=${STRIPPROG-strip} - -posix_glob='?' -initialize_posix_glob=' - test "$posix_glob" != "?" || { - if (set -f) 2>/dev/null; then - posix_glob= - else - posix_glob=: - fi - } -' - -posix_mkdir= - -# Desired mode of installed file. -mode=0755 - -chgrpcmd= -chmodcmd=$chmodprog -chowncmd= -mvcmd=$mvprog -rmcmd="$rmprog -f" -stripcmd= - -src= -dst= -dir_arg= -dst_arg= - -copy_on_change=false -no_target_directory= - -usage="\ -Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE - or: $0 [OPTION]... SRCFILES... DIRECTORY - or: $0 [OPTION]... -t DIRECTORY SRCFILES... - or: $0 [OPTION]... -d DIRECTORIES... - -In the 1st form, copy SRCFILE to DSTFILE. -In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. -In the 4th, create DIRECTORIES. - -Options: - --help display this help and exit. - --version display version info and exit. - - -c (ignored) - -C install only if different (preserve the last data modification time) - -d create directories instead of installing files. - -g GROUP $chgrpprog installed files to GROUP. - -m MODE $chmodprog installed files to MODE. - -o USER $chownprog installed files to USER. - -s $stripprog installed files. - -t DIRECTORY install into DIRECTORY. - -T report an error if DSTFILE is a directory. - -Environment variables override the default commands: - CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG - RMPROG STRIPPROG -" - -while test $# -ne 0; do - case $1 in - -c) ;; - - -C) copy_on_change=true;; - - -d) dir_arg=true;; - - -g) chgrpcmd="$chgrpprog $2" - shift;; - - --help) echo "$usage"; exit $?;; - - -m) mode=$2 - case $mode in - *' '* | *' '* | *' -'* | *'*'* | *'?'* | *'['*) - echo "$0: invalid mode: $mode" >&2 - exit 1;; - esac - shift;; - - -o) chowncmd="$chownprog $2" - shift;; - - -s) stripcmd=$stripprog;; - - -t) dst_arg=$2 - shift;; - - -T) no_target_directory=true;; - - --version) echo "$0 $scriptversion"; exit $?;; - - --) shift - break;; - - -*) echo "$0: invalid option: $1" >&2 - exit 1;; - - *) break;; - esac - shift -done - -if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then - # When -d is used, all remaining arguments are directories to create. - # When -t is used, the destination is already specified. - # Otherwise, the last argument is the destination. Remove it from $@. - for arg - do - if test -n "$dst_arg"; then - # $@ is not empty: it contains at least $arg. - set fnord "$@" "$dst_arg" - shift # fnord - fi - shift # arg - dst_arg=$arg - done -fi - -if test $# -eq 0; then - if test -z "$dir_arg"; then - echo "$0: no input file specified." >&2 - exit 1 - fi - # It's OK to call `install-sh -d' without argument. - # This can happen when creating conditional directories. - exit 0 -fi - -if test -z "$dir_arg"; then - trap '(exit $?); exit' 1 2 13 15 - - # Set umask so as not to create temps with too-generous modes. - # However, 'strip' requires both read and write access to temps. - case $mode in - # Optimize common cases. - *644) cp_umask=133;; - *755) cp_umask=22;; - - *[0-7]) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw='% 200' - fi - cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; - *) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw=,u+rw - fi - cp_umask=$mode$u_plus_rw;; - esac -fi - -for src -do - # Protect names starting with `-'. - case $src in - -*) src=./$src;; - esac - - if test -n "$dir_arg"; then - dst=$src - dstdir=$dst - test -d "$dstdir" - dstdir_status=$? - else - - # Waiting for this to be detected by the "$cpprog $src $dsttmp" command - # might cause directories to be created, which would be especially bad - # if $src (and thus $dsttmp) contains '*'. - if test ! -f "$src" && test ! -d "$src"; then - echo "$0: $src does not exist." >&2 - exit 1 - fi - - if test -z "$dst_arg"; then - echo "$0: no destination specified." >&2 - exit 1 - fi - - dst=$dst_arg - # Protect names starting with `-'. - case $dst in - -*) dst=./$dst;; - esac - - # If destination is a directory, append the input filename; won't work - # if double slashes aren't ignored. - if test -d "$dst"; then - if test -n "$no_target_directory"; then - echo "$0: $dst_arg: Is a directory" >&2 - exit 1 - fi - dstdir=$dst - dst=$dstdir/`basename "$src"` - dstdir_status=0 - else - # Prefer dirname, but fall back on a substitute if dirname fails. - dstdir=` - (dirname "$dst") 2>/dev/null || - expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$dst" : 'X\(//\)[^/]' \| \ - X"$dst" : 'X\(//\)$' \| \ - X"$dst" : 'X\(/\)' \| . 2>/dev/null || - echo X"$dst" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q' - ` - - test -d "$dstdir" - dstdir_status=$? - fi - fi - - obsolete_mkdir_used=false - - if test $dstdir_status != 0; then - case $posix_mkdir in - '') - # Create intermediate dirs using mode 755 as modified by the umask. - # This is like FreeBSD 'install' as of 1997-10-28. - umask=`umask` - case $stripcmd.$umask in - # Optimize common cases. - *[2367][2367]) mkdir_umask=$umask;; - .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; - - *[0-7]) - mkdir_umask=`expr $umask + 22 \ - - $umask % 100 % 40 + $umask % 20 \ - - $umask % 10 % 4 + $umask % 2 - `;; - *) mkdir_umask=$umask,go-w;; - esac - - # With -d, create the new directory with the user-specified mode. - # Otherwise, rely on $mkdir_umask. - if test -n "$dir_arg"; then - mkdir_mode=-m$mode - else - mkdir_mode= - fi - - posix_mkdir=false - case $umask in - *[123567][0-7][0-7]) - # POSIX mkdir -p sets u+wx bits regardless of umask, which - # is incompatible with FreeBSD 'install' when (umask & 300) != 0. - ;; - *) - tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 - - if (umask $mkdir_umask && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 - then - if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. - # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writeable bit of parent directory when it shouldn't. - # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - ls_ld_tmpdir=`ls -ld "$tmpdir"` - case $ls_ld_tmpdir in - d????-?r-*) different_mode=700;; - d????-?--*) different_mode=755;; - *) false;; - esac && - $mkdirprog -m$different_mode -p -- "$tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$tmpdir"` - test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" - } - } - then posix_mkdir=: - fi - rmdir "$tmpdir/d" "$tmpdir" - else - # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null - fi - trap '' 0;; - esac;; - esac - - if - $posix_mkdir && ( - umask $mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" - ) - then : - else - - # The umask is ridiculous, or mkdir does not conform to POSIX, - # or it failed possibly due to a race condition. Create the - # directory the slow way, step by step, checking for races as we go. - - case $dstdir in - /*) prefix='/';; - -*) prefix='./';; - *) prefix='';; - esac - - eval "$initialize_posix_glob" - - oIFS=$IFS - IFS=/ - $posix_glob set -f - set fnord $dstdir - shift - $posix_glob set +f - IFS=$oIFS - - prefixes= - - for d - do - test -z "$d" && continue - - prefix=$prefix$d - if test -d "$prefix"; then - prefixes= - else - if $posix_mkdir; then - (umask=$mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break - # Don't fail if two instances are running concurrently. - test -d "$prefix" || exit 1 - else - case $prefix in - *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; - *) qprefix=$prefix;; - esac - prefixes="$prefixes '$qprefix'" - fi - fi - prefix=$prefix/ - done - - if test -n "$prefixes"; then - # Don't fail if two instances are running concurrently. - (umask $mkdir_umask && - eval "\$doit_exec \$mkdirprog $prefixes") || - test -d "$dstdir" || exit 1 - obsolete_mkdir_used=true - fi - fi - fi - - if test -n "$dir_arg"; then - { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && - { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || - test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 - else - - # Make a couple of temp file names in the proper directory. - dsttmp=$dstdir/_inst.$$_ - rmtmp=$dstdir/_rm.$$_ - - # Trap to clean up those temp files at exit. - trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 - - # Copy the file name to the temp name. - (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && - - # and set any options; do chmod last to preserve setuid bits. - # - # If any of these fail, we abort the whole thing. If we want to - # ignore errors from any of these, just make sure not to ignore - # errors from the above "$doit $cpprog $src $dsttmp" command. - # - { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && - { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && - { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && - - # If -C, don't bother to copy if it wouldn't change the file. - if $copy_on_change && - old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && - new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && - - eval "$initialize_posix_glob" && - $posix_glob set -f && - set X $old && old=:$2:$4:$5:$6 && - set X $new && new=:$2:$4:$5:$6 && - $posix_glob set +f && - - test "$old" = "$new" && - $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 - then - rm -f "$dsttmp" - else - # Rename the file to the real destination. - $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || - - # The rename failed, perhaps because mv can't rename something else - # to itself, or perhaps because mv is so ancient that it does not - # support -f. - { - # Now remove or move aside any old file at destination location. - # We try this two ways since rm can't unlink itself on some - # systems and the destination file might be busy for other - # reasons. In this case, the final cleanup might fail but the new - # file should still install successfully. - { - test ! -f "$dst" || - $doit $rmcmd -f "$dst" 2>/dev/null || - { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && - { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } - } || - { echo "$0: cannot unlink or rename $dst" >&2 - (exit 1); exit 1 - } - } && - - # Now rename the file to the real destination. - $doit $mvcmd "$dsttmp" "$dst" - } - fi || exit 1 - - trap '' 0 - fi -done - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-end: "$" -# End: diff --git a/libltdl/ltdl.c b/libltdl/ltdl.c deleted file mode 100644 index 3a76ff10..00000000 --- a/libltdl/ltdl.c +++ /dev/null @@ -1,4530 +0,0 @@ -/* ltdl.c -- system independent dlopen wrapper - Copyright (C) 1998, 1999, 2000, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. - Originally by Thomas Tanner - This file is part of GNU Libtool. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2 of the License, or (at your option) any later version. - -As a special exception to the GNU Lesser General Public License, -if you distribute this file as part of a program or library that -is built using GNU libtool, you may include it under the same -distribution terms that you use for the rest of that program. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA - -*/ - -#if HAVE_CONFIG_H -# include -#endif - -#if HAVE_UNISTD_H -# include -#endif - -#if HAVE_STDIO_H -# include -#endif - -/* Include the header defining malloc. On K&R C compilers, - that's , on ANSI C and ISO C compilers, that's . */ -#if HAVE_STDLIB_H -# include -#else -# if HAVE_MALLOC_H -# include -# endif -#endif - -#if HAVE_STRING_H -# include -#else -# if HAVE_STRINGS_H -# include -# endif -#endif - -#if HAVE_CTYPE_H -# include -#endif - -#if HAVE_MEMORY_H -# include -#endif - -#if HAVE_ERRNO_H -# include -#endif - - -#ifndef __WINDOWS__ -# ifdef __WIN32__ -# define __WINDOWS__ -# endif -#endif - - -#undef LT_USE_POSIX_DIRENT -#ifdef HAVE_CLOSEDIR -# ifdef HAVE_OPENDIR -# ifdef HAVE_READDIR -# ifdef HAVE_DIRENT_H -# define LT_USE_POSIX_DIRENT -# endif /* HAVE_DIRENT_H */ -# endif /* HAVE_READDIR */ -# endif /* HAVE_OPENDIR */ -#endif /* HAVE_CLOSEDIR */ - - -#undef LT_USE_WINDOWS_DIRENT_EMULATION -#ifndef LT_USE_POSIX_DIRENT -# ifdef __WINDOWS__ -# define LT_USE_WINDOWS_DIRENT_EMULATION -# endif /* __WINDOWS__ */ -#endif /* LT_USE_POSIX_DIRENT */ - - -#ifdef LT_USE_POSIX_DIRENT -# include -# define LT_D_NAMLEN(dirent) (strlen((dirent)->d_name)) -#else -# ifdef LT_USE_WINDOWS_DIRENT_EMULATION -# define LT_D_NAMLEN(dirent) (strlen((dirent)->d_name)) -# else -# define dirent direct -# define LT_D_NAMLEN(dirent) ((dirent)->d_namlen) -# if HAVE_SYS_NDIR_H -# include -# endif -# if HAVE_SYS_DIR_H -# include -# endif -# if HAVE_NDIR_H -# include -# endif -# endif -#endif - -#if HAVE_ARGZ_H -# include -#endif - -#if HAVE_ASSERT_H -# include -#else -# define assert(arg) ((void) 0) -#endif - -#include "ltdl.h" - -#if WITH_DMALLOC -# include -#endif - - - - -/* --- WINDOWS SUPPORT --- */ - -/* DLL building support on win32 hosts; mostly to workaround their - ridiculous implementation of data symbol exporting. */ -#ifndef LT_GLOBAL_DATA -# if defined(__WINDOWS__) || defined(__CYGWIN__) -# ifdef DLL_EXPORT /* defined by libtool (if required) */ -# define LT_GLOBAL_DATA __declspec(dllexport) -# endif -# endif -# ifndef LT_GLOBAL_DATA /* static linking or !__WINDOWS__ */ -# define LT_GLOBAL_DATA -# endif -#endif - -/* fopen() mode flags for reading a text file */ -#undef LT_READTEXT_MODE -#if defined(__WINDOWS__) || defined(__CYGWIN__) -# define LT_READTEXT_MODE "rt" -#else -# define LT_READTEXT_MODE "r" -#endif - -#ifdef LT_USE_WINDOWS_DIRENT_EMULATION - -#include - -#define dirent lt_dirent -#define DIR lt_DIR - -struct dirent -{ - char d_name[2048]; - int d_namlen; -}; - -typedef struct _DIR -{ - HANDLE hSearch; - WIN32_FIND_DATA Win32FindData; - BOOL firsttime; - struct dirent file_info; -} DIR; - -#endif /* LT_USE_WINDOWS_DIRENT_EMULATION */ - - -/* --- MANIFEST CONSTANTS --- */ - - -/* Standard libltdl search path environment variable name */ -#undef LTDL_SEARCHPATH_VAR -#define LTDL_SEARCHPATH_VAR "LTDL_LIBRARY_PATH" - -/* Standard libtool archive file extension. */ -#undef LTDL_ARCHIVE_EXT -#define LTDL_ARCHIVE_EXT ".la" - -/* max. filename length */ -#ifndef LT_FILENAME_MAX -# define LT_FILENAME_MAX 1024 -#endif - -/* This is the maximum symbol size that won't require malloc/free */ -#undef LT_SYMBOL_LENGTH -#define LT_SYMBOL_LENGTH 128 - -/* This accounts for the _LTX_ separator */ -#undef LT_SYMBOL_OVERHEAD -#define LT_SYMBOL_OVERHEAD 5 - - - - -/* --- MEMORY HANDLING --- */ - - -/* These are the functions used internally. In addition to making - use of the associated function pointers above, they also perform - error handling. */ -static char *lt_estrdup LT_PARAMS((const char *str)); -static lt_ptr lt_emalloc LT_PARAMS((size_t size)); -static lt_ptr lt_erealloc LT_PARAMS((lt_ptr addr, size_t size)); - -/* static lt_ptr rpl_realloc LT_PARAMS((lt_ptr ptr, size_t size)); */ -#define rpl_realloc realloc - -/* These are the pointers that can be changed by the caller: */ -LT_GLOBAL_DATA lt_ptr (*lt_dlmalloc) LT_PARAMS((size_t size)) - = (lt_ptr (*) LT_PARAMS((size_t))) malloc; -LT_GLOBAL_DATA lt_ptr (*lt_dlrealloc) LT_PARAMS((lt_ptr ptr, size_t size)) - = (lt_ptr (*) LT_PARAMS((lt_ptr, size_t))) rpl_realloc; -LT_GLOBAL_DATA void (*lt_dlfree) LT_PARAMS((lt_ptr ptr)) - = (void (*) LT_PARAMS((lt_ptr))) free; - -/* The following macros reduce the amount of typing needed to cast - assigned memory. */ -#if WITH_DMALLOC - -#define LT_DLMALLOC(tp, n) ((tp *) xmalloc ((n) * sizeof(tp))) -#define LT_DLREALLOC(tp, p, n) ((tp *) xrealloc ((p), (n) * sizeof(tp))) -#define LT_DLFREE(p) \ - LT_STMT_START { if (p) (p) = (xfree (p), (lt_ptr) 0); } LT_STMT_END - -#define LT_EMALLOC(tp, n) ((tp *) xmalloc ((n) * sizeof(tp))) -#define LT_EREALLOC(tp, p, n) ((tp *) xrealloc ((p), (n) * sizeof(tp))) - -#else - -#define LT_DLMALLOC(tp, n) ((tp *) lt_dlmalloc ((n) * sizeof(tp))) -#define LT_DLREALLOC(tp, p, n) ((tp *) lt_dlrealloc ((p), (n) * sizeof(tp))) -#define LT_DLFREE(p) \ - LT_STMT_START { if (p) (p) = (lt_dlfree (p), (lt_ptr) 0); } LT_STMT_END - -#define LT_EMALLOC(tp, n) ((tp *) lt_emalloc ((n) * sizeof(tp))) -#define LT_EREALLOC(tp, p, n) ((tp *) lt_erealloc ((p), (n) * sizeof(tp))) - -#endif - -#define LT_DLMEM_REASSIGN(p, q) LT_STMT_START { \ - if ((p) != (q)) { if (p) lt_dlfree (p); (p) = (q); (q) = 0; } \ - } LT_STMT_END - - -/* --- REPLACEMENT FUNCTIONS --- */ - - -#undef strdup -#define strdup rpl_strdup - -static char *strdup LT_PARAMS((const char *str)); - -static char * -strdup(str) - const char *str; -{ - char *tmp = 0; - - if (str) - { - tmp = LT_DLMALLOC (char, 1+ strlen (str)); - if (tmp) - { - strcpy(tmp, str); - } - } - - return tmp; -} - - -#if ! HAVE_STRCMP - -#undef strcmp -#define strcmp rpl_strcmp - -static int strcmp LT_PARAMS((const char *str1, const char *str2)); - -static int -strcmp (str1, str2) - const char *str1; - const char *str2; -{ - if (str1 == str2) - return 0; - if (str1 == 0) - return -1; - if (str2 == 0) - return 1; - - for (;*str1 && *str2; ++str1, ++str2) - { - if (*str1 != *str2) - break; - } - - return (int)(*str1 - *str2); -} -#endif - - -#if ! HAVE_STRCHR - -# if HAVE_INDEX -# define strchr index -# else -# define strchr rpl_strchr - -static const char *strchr LT_PARAMS((const char *str, int ch)); - -static const char* -strchr(str, ch) - const char *str; - int ch; -{ - const char *p; - - for (p = str; *p != (char)ch && *p != LT_EOS_CHAR; ++p) - /*NOWORK*/; - - return (*p == (char)ch) ? p : 0; -} - -# endif -#endif /* !HAVE_STRCHR */ - - -#if ! HAVE_STRRCHR - -# if HAVE_RINDEX -# define strrchr rindex -# else -# define strrchr rpl_strrchr - -static const char *strrchr LT_PARAMS((const char *str, int ch)); - -static const char* -strrchr(str, ch) - const char *str; - int ch; -{ - const char *p, *q = 0; - - for (p = str; *p != LT_EOS_CHAR; ++p) - { - if (*p == (char) ch) - { - q = p; - } - } - - return q; -} - -# endif -#endif - -/* NOTE: Neither bcopy nor the memcpy implementation below can - reliably handle copying in overlapping areas of memory. Use - memmove (for which there is a fallback implmentation below) - if you need that behaviour. */ -#if ! HAVE_MEMCPY - -# if HAVE_BCOPY -# define memcpy(dest, src, size) bcopy (src, dest, size) -# else -# define memcpy rpl_memcpy - -static lt_ptr memcpy LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size)); - -static lt_ptr -memcpy (dest, src, size) - lt_ptr dest; - const lt_ptr src; - size_t size; -{ - const char * s = src; - char * d = dest; - size_t i = 0; - - for (i = 0; i < size; ++i) - { - d[i] = s[i]; - } - - return dest; -} - -# endif /* !HAVE_BCOPY */ -#endif /* !HAVE_MEMCPY */ - -#if ! HAVE_MEMMOVE -# define memmove rpl_memmove - -static lt_ptr memmove LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size)); - -static lt_ptr -memmove (dest, src, size) - lt_ptr dest; - const lt_ptr src; - size_t size; -{ - const char * s = src; - char * d = dest; - size_t i; - - if (d < s) - for (i = 0; i < size; ++i) - { - d[i] = s[i]; - } - else if (d > s && size > 0) - for (i = size -1; ; --i) - { - d[i] = s[i]; - if (i == 0) - break; - } - - return dest; -} - -#endif /* !HAVE_MEMMOVE */ - -#ifdef LT_USE_WINDOWS_DIRENT_EMULATION - -static void closedir LT_PARAMS((DIR *entry)); - -static void -closedir(entry) - DIR *entry; -{ - assert(entry != (DIR *) NULL); - FindClose(entry->hSearch); - lt_dlfree((lt_ptr)entry); -} - - -static DIR * opendir LT_PARAMS((const char *path)); - -static DIR* -opendir (path) - const char *path; -{ - char file_specification[LT_FILENAME_MAX]; - DIR *entry; - - assert(path != (char *) NULL); - /* allow space for: path + '\\' '\\' '*' '.' '*' + '\0' */ - (void) strncpy (file_specification, path, LT_FILENAME_MAX-6); - file_specification[LT_FILENAME_MAX-6] = LT_EOS_CHAR; - (void) strcat(file_specification,"\\"); - entry = LT_DLMALLOC (DIR,sizeof(DIR)); - if (entry != (DIR *) 0) - { - entry->firsttime = TRUE; - entry->hSearch = FindFirstFile(file_specification,&entry->Win32FindData); - } - if (entry->hSearch == INVALID_HANDLE_VALUE) - { - (void) strcat(file_specification,"\\*.*"); - entry->hSearch = FindFirstFile(file_specification,&entry->Win32FindData); - if (entry->hSearch == INVALID_HANDLE_VALUE) - { - LT_DLFREE (entry); - return (DIR *) 0; - } - } - return(entry); -} - - -static struct dirent *readdir LT_PARAMS((DIR *entry)); - -static struct dirent *readdir(entry) - DIR *entry; -{ - int - status; - - if (entry == (DIR *) 0) - return((struct dirent *) 0); - if (!entry->firsttime) - { - status = FindNextFile(entry->hSearch,&entry->Win32FindData); - if (status == 0) - return((struct dirent *) 0); - } - entry->firsttime = FALSE; - (void) strncpy(entry->file_info.d_name,entry->Win32FindData.cFileName, - LT_FILENAME_MAX-1); - entry->file_info.d_name[LT_FILENAME_MAX - 1] = LT_EOS_CHAR; - entry->file_info.d_namlen = strlen(entry->file_info.d_name); - return(&entry->file_info); -} - -#endif /* LT_USE_WINDOWS_DIRENT_EMULATION */ - -/* According to Alexandre Oliva , - ``realloc is not entirely portable'' - In any case we want to use the allocator supplied by the user without - burdening them with an lt_dlrealloc function pointer to maintain. - Instead implement our own version (with known boundary conditions) - using lt_dlmalloc and lt_dlfree. */ - -/* #undef realloc - #define realloc rpl_realloc -*/ -#if 0 - /* You can't (re)define realloc unless you also (re)define malloc. - Right now, this code uses the size of the *destination* to decide - how much to copy. That's not right, but you can't know the size - of the source unless you know enough about, or wrote malloc. So - this code is disabled... */ - -static lt_ptr -realloc (ptr, size) - lt_ptr ptr; - size_t size; -{ - if (size == 0) - { - /* For zero or less bytes, free the original memory */ - if (ptr != 0) - { - lt_dlfree (ptr); - } - - return (lt_ptr) 0; - } - else if (ptr == 0) - { - /* Allow reallocation of a NULL pointer. */ - return lt_dlmalloc (size); - } - else - { - /* Allocate a new block, copy and free the old block. */ - lt_ptr mem = lt_dlmalloc (size); - - if (mem) - { - memcpy (mem, ptr, size); - lt_dlfree (ptr); - } - - /* Note that the contents of PTR are not damaged if there is - insufficient memory to realloc. */ - return mem; - } -} -#endif - - -#if ! HAVE_ARGZ_APPEND -# define argz_append rpl_argz_append - -static error_t argz_append LT_PARAMS((char **pargz, size_t *pargz_len, - const char *buf, size_t buf_len)); - -static error_t -argz_append (pargz, pargz_len, buf, buf_len) - char **pargz; - size_t *pargz_len; - const char *buf; - size_t buf_len; -{ - size_t argz_len; - char *argz; - - assert (pargz); - assert (pargz_len); - assert ((*pargz && *pargz_len) || (!*pargz && !*pargz_len)); - - /* If nothing needs to be appended, no more work is required. */ - if (buf_len == 0) - return 0; - - /* Ensure there is enough room to append BUF_LEN. */ - argz_len = *pargz_len + buf_len; - argz = LT_DLREALLOC (char, *pargz, argz_len); - if (!argz) - return ENOMEM; - - /* Copy characters from BUF after terminating '\0' in ARGZ. */ - memcpy (argz + *pargz_len, buf, buf_len); - - /* Assign new values. */ - *pargz = argz; - *pargz_len = argz_len; - - return 0; -} -#endif /* !HAVE_ARGZ_APPEND */ - - -#if ! HAVE_ARGZ_CREATE_SEP -# define argz_create_sep rpl_argz_create_sep - -static error_t argz_create_sep LT_PARAMS((const char *str, int delim, - char **pargz, size_t *pargz_len)); - -static error_t -argz_create_sep (str, delim, pargz, pargz_len) - const char *str; - int delim; - char **pargz; - size_t *pargz_len; -{ - size_t argz_len; - char *argz = 0; - - assert (str); - assert (pargz); - assert (pargz_len); - - /* Make a copy of STR, but replacing each occurrence of - DELIM with '\0'. */ - argz_len = 1+ LT_STRLEN (str); - if (argz_len) - { - const char *p; - char *q; - - argz = LT_DLMALLOC (char, argz_len); - if (!argz) - return ENOMEM; - - for (p = str, q = argz; *p != LT_EOS_CHAR; ++p) - { - if (*p == delim) - { - /* Ignore leading delimiters, and fold consecutive - delimiters in STR into a single '\0' in ARGZ. */ - if ((q > argz) && (q[-1] != LT_EOS_CHAR)) - *q++ = LT_EOS_CHAR; - else - --argz_len; - } - else - *q++ = *p; - } - /* Copy terminating LT_EOS_CHAR. */ - *q = *p; - } - - /* If ARGZ_LEN has shrunk to nothing, release ARGZ's memory. */ - if (!argz_len) - LT_DLFREE (argz); - - /* Assign new values. */ - *pargz = argz; - *pargz_len = argz_len; - - return 0; -} -#endif /* !HAVE_ARGZ_CREATE_SEP */ - - -#if ! HAVE_ARGZ_INSERT -# define argz_insert rpl_argz_insert - -static error_t argz_insert LT_PARAMS((char **pargz, size_t *pargz_len, - char *before, const char *entry)); - -static error_t -argz_insert (pargz, pargz_len, before, entry) - char **pargz; - size_t *pargz_len; - char *before; - const char *entry; -{ - assert (pargz); - assert (pargz_len); - assert (entry && *entry); - - /* No BEFORE address indicates ENTRY should be inserted after the - current last element. */ - if (!before) - return argz_append (pargz, pargz_len, entry, 1+ LT_STRLEN (entry)); - - /* This probably indicates a programmer error, but to preserve - semantics, scan back to the start of an entry if BEFORE points - into the middle of it. */ - while ((before > *pargz) && (before[-1] != LT_EOS_CHAR)) - --before; - - { - size_t entry_len = 1+ LT_STRLEN (entry); - size_t argz_len = *pargz_len + entry_len; - size_t offset = before - *pargz; - char *argz = LT_DLREALLOC (char, *pargz, argz_len); - - if (!argz) - return ENOMEM; - - /* Make BEFORE point to the equivalent offset in ARGZ that it - used to have in *PARGZ incase realloc() moved the block. */ - before = argz + offset; - - /* Move the ARGZ entries starting at BEFORE up into the new - space at the end -- making room to copy ENTRY into the - resulting gap. */ - memmove (before + entry_len, before, *pargz_len - offset); - memcpy (before, entry, entry_len); - - /* Assign new values. */ - *pargz = argz; - *pargz_len = argz_len; - } - - return 0; -} -#endif /* !HAVE_ARGZ_INSERT */ - - -#if ! HAVE_ARGZ_NEXT -# define argz_next rpl_argz_next - -static char *argz_next LT_PARAMS((char *argz, size_t argz_len, - const char *entry)); - -static char * -argz_next (argz, argz_len, entry) - char *argz; - size_t argz_len; - const char *entry; -{ - assert ((argz && argz_len) || (!argz && !argz_len)); - - if (entry) - { - /* Either ARGZ/ARGZ_LEN is empty, or ENTRY points into an address - within the ARGZ vector. */ - assert ((!argz && !argz_len) - || ((argz <= entry) && (entry < (argz + argz_len)))); - - /* Move to the char immediately after the terminating - '\0' of ENTRY. */ - entry = 1+ strchr (entry, LT_EOS_CHAR); - - /* Return either the new ENTRY, or else NULL if ARGZ is - exhausted. */ - return (entry >= argz + argz_len) ? 0 : (char *) entry; - } - else - { - /* This should probably be flagged as a programmer error, - since starting an argz_next loop with the iterator set - to ARGZ is safer. To preserve semantics, handle the NULL - case by returning the start of ARGZ (if any). */ - if (argz_len > 0) - return argz; - else - return 0; - } -} -#endif /* !HAVE_ARGZ_NEXT */ - - - -#if ! HAVE_ARGZ_STRINGIFY -# define argz_stringify rpl_argz_stringify - -static void argz_stringify LT_PARAMS((char *argz, size_t argz_len, - int sep)); - -static void -argz_stringify (argz, argz_len, sep) - char *argz; - size_t argz_len; - int sep; -{ - assert ((argz && argz_len) || (!argz && !argz_len)); - - if (sep) - { - --argz_len; /* don't stringify the terminating EOS */ - while (--argz_len > 0) - { - if (argz[argz_len] == LT_EOS_CHAR) - argz[argz_len] = sep; - } - } -} -#endif /* !HAVE_ARGZ_STRINGIFY */ - - - - -/* --- TYPE DEFINITIONS -- */ - - -/* This type is used for the array of caller data sets in each handler. */ -typedef struct { - lt_dlcaller_id key; - lt_ptr data; -} lt_caller_data; - - - - -/* --- OPAQUE STRUCTURES DECLARED IN LTDL.H --- */ - - -/* Extract the diagnostic strings from the error table macro in the same - order as the enumerated indices in ltdl.h. */ - -static const char *lt_dlerror_strings[] = - { -#define LT_ERROR(name, diagnostic) (diagnostic), - lt_dlerror_table -#undef LT_ERROR - - 0 - }; - -/* This structure is used for the list of registered loaders. */ -struct lt_dlloader { - struct lt_dlloader *next; - const char *loader_name; /* identifying name for each loader */ - const char *sym_prefix; /* prefix for symbols */ - lt_module_open *module_open; - lt_module_close *module_close; - lt_find_sym *find_sym; - lt_dlloader_exit *dlloader_exit; - lt_user_data dlloader_data; -}; - -struct lt_dlhandle_struct { - struct lt_dlhandle_struct *next; - lt_dlloader *loader; /* dlopening interface */ - lt_dlinfo info; - int depcount; /* number of dependencies */ - lt_dlhandle *deplibs; /* dependencies */ - lt_module module; /* system module handle */ - lt_ptr system; /* system specific data */ - lt_caller_data *caller_data; /* per caller associated data */ - int flags; /* various boolean stats */ -}; - -/* Various boolean flags can be stored in the flags field of an - lt_dlhandle_struct... */ -#define LT_DLGET_FLAG(handle, flag) (((handle)->flags & (flag)) == (flag)) -#define LT_DLSET_FLAG(handle, flag) ((handle)->flags |= (flag)) - -#define LT_DLRESIDENT_FLAG (0x01 << 0) -/* ...add more flags here... */ - -#define LT_DLIS_RESIDENT(handle) LT_DLGET_FLAG(handle, LT_DLRESIDENT_FLAG) - - -#define LT_DLSTRERROR(name) lt_dlerror_strings[LT_CONC(LT_ERROR_,name)] - -static const char objdir[] = LTDL_OBJDIR; -static const char archive_ext[] = LTDL_ARCHIVE_EXT; -#ifdef LTDL_SHLIB_EXT -static const char shlib_ext[] = LTDL_SHLIB_EXT; -#endif -#ifdef LTDL_SYSSEARCHPATH -static const char sys_search_path[] = LTDL_SYSSEARCHPATH; -#endif - - - - -/* --- MUTEX LOCKING --- */ - - -/* Macros to make it easier to run the lock functions only if they have - been registered. The reason for the complicated lock macro is to - ensure that the stored error message from the last error is not - accidentally erased if the current function doesn't generate an - error of its own. */ -#define LT_DLMUTEX_LOCK() LT_STMT_START { \ - if (lt_dlmutex_lock_func) (*lt_dlmutex_lock_func)(); \ - } LT_STMT_END -#define LT_DLMUTEX_UNLOCK() LT_STMT_START { \ - if (lt_dlmutex_unlock_func) (*lt_dlmutex_unlock_func)();\ - } LT_STMT_END -#define LT_DLMUTEX_SETERROR(errormsg) LT_STMT_START { \ - if (lt_dlmutex_seterror_func) \ - (*lt_dlmutex_seterror_func) (errormsg); \ - else lt_dllast_error = (errormsg); } LT_STMT_END -#define LT_DLMUTEX_GETERROR(errormsg) LT_STMT_START { \ - if (lt_dlmutex_geterror_func) \ - (errormsg) = (*lt_dlmutex_geterror_func) (); \ - else (errormsg) = lt_dllast_error; } LT_STMT_END - -/* The mutex functions stored here are global, and are necessarily the - same for all threads that wish to share access to libltdl. */ -static lt_dlmutex_lock *lt_dlmutex_lock_func = 0; -static lt_dlmutex_unlock *lt_dlmutex_unlock_func = 0; -static lt_dlmutex_seterror *lt_dlmutex_seterror_func = 0; -static lt_dlmutex_geterror *lt_dlmutex_geterror_func = 0; -static const char *lt_dllast_error = 0; - - -/* Either set or reset the mutex functions. Either all the arguments must - be valid functions, or else all can be NULL to turn off locking entirely. - The registered functions should be manipulating a static global lock - from the lock() and unlock() callbacks, which needs to be reentrant. */ -int -lt_dlmutex_register (lock, unlock, seterror, geterror) - lt_dlmutex_lock *lock; - lt_dlmutex_unlock *unlock; - lt_dlmutex_seterror *seterror; - lt_dlmutex_geterror *geterror; -{ - lt_dlmutex_unlock *old_unlock = lt_dlmutex_unlock_func; - int errors = 0; - - /* Lock using the old lock() callback, if any. */ - LT_DLMUTEX_LOCK (); - - if ((lock && unlock && seterror && geterror) - || !(lock || unlock || seterror || geterror)) - { - lt_dlmutex_lock_func = lock; - lt_dlmutex_unlock_func = unlock; - lt_dlmutex_seterror_func = seterror; - lt_dlmutex_geterror_func = geterror; - } - else - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_MUTEX_ARGS)); - ++errors; - } - - /* Use the old unlock() callback we saved earlier, if any. Otherwise - record any errors using internal storage. */ - if (old_unlock) - (*old_unlock) (); - - /* Return the number of errors encountered during the execution of - this function. */ - return errors; -} - - - - -/* --- ERROR HANDLING --- */ - - -static const char **user_error_strings = 0; -static int errorcount = LT_ERROR_MAX; - -int -lt_dladderror (diagnostic) - const char *diagnostic; -{ - int errindex = 0; - int result = -1; - const char **temp = (const char **) 0; - - assert (diagnostic); - - LT_DLMUTEX_LOCK (); - - errindex = errorcount - LT_ERROR_MAX; - temp = LT_EREALLOC (const char *, user_error_strings, 1 + errindex); - if (temp) - { - user_error_strings = temp; - user_error_strings[errindex] = diagnostic; - result = errorcount++; - } - - LT_DLMUTEX_UNLOCK (); - - return result; -} - -int -lt_dlseterror (errindex) - int errindex; -{ - int errors = 0; - - LT_DLMUTEX_LOCK (); - - if (errindex >= errorcount || errindex < 0) - { - /* Ack! Error setting the error message! */ - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_ERRORCODE)); - ++errors; - } - else if (errindex < LT_ERROR_MAX) - { - /* No error setting the error message! */ - LT_DLMUTEX_SETERROR (lt_dlerror_strings[errindex]); - } - else - { - /* No error setting the error message! */ - LT_DLMUTEX_SETERROR (user_error_strings[errindex - LT_ERROR_MAX]); - } - - LT_DLMUTEX_UNLOCK (); - - return errors; -} - -static lt_ptr -lt_emalloc (size) - size_t size; -{ - lt_ptr mem = lt_dlmalloc (size); - if (size && !mem) - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - return mem; -} - -static lt_ptr -lt_erealloc (addr, size) - lt_ptr addr; - size_t size; -{ - lt_ptr mem = lt_dlrealloc (addr, size); - if (size && !mem) - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - return mem; -} - -static char * -lt_estrdup (str) - const char *str; -{ - char *copy = strdup (str); - if (LT_STRLEN (str) && !copy) - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - return copy; -} - - - - -/* --- DLOPEN() INTERFACE LOADER --- */ - - -#if HAVE_LIBDL - -/* dynamic linking with dlopen/dlsym */ - -#if HAVE_DLFCN_H -# include -#endif - -#if HAVE_SYS_DL_H -# include -#endif - -/* We may have to define LT_LAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_LAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_LAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_LAZY_OR_NOW DL_LAZY -# endif -# endif /* !RTLD_LAZY */ -#endif -#ifndef LT_LAZY_OR_NOW -# ifdef RTLD_NOW -# define LT_LAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_LAZY_OR_NOW DL_NOW -# endif -# endif /* !RTLD_NOW */ -#endif -#ifndef LT_LAZY_OR_NOW -# define LT_LAZY_OR_NOW 0 -#endif /* !LT_LAZY_OR_NOW */ - -#if HAVE_DLERROR -# define DLERROR(arg) dlerror () -#else -# define DLERROR(arg) LT_DLSTRERROR (arg) -#endif - -static lt_module -sys_dl_open (loader_data, filename) - lt_user_data loader_data; - const char *filename; -{ - lt_module module = dlopen (filename, LT_LAZY_OR_NOW); - - if (!module) - { - LT_DLMUTEX_SETERROR (DLERROR (CANNOT_OPEN)); - } - - return module; -} - -static int -sys_dl_close (loader_data, module) - lt_user_data loader_data; - lt_module module; -{ - int errors = 0; - - if (dlclose (module) != 0) - { - LT_DLMUTEX_SETERROR (DLERROR (CANNOT_CLOSE)); - ++errors; - } - - return errors; -} - -static lt_ptr -sys_dl_sym (loader_data, module, symbol) - lt_user_data loader_data; - lt_module module; - const char *symbol; -{ - lt_ptr address = dlsym (module, symbol); - - if (!address) - { - LT_DLMUTEX_SETERROR (DLERROR (SYMBOL_NOT_FOUND)); - } - - return address; -} - -static struct lt_user_dlloader sys_dl = - { -# ifdef NEED_USCORE - "_", -# else - 0, -# endif - sys_dl_open, sys_dl_close, sys_dl_sym, 0, 0 }; - - -#endif /* HAVE_LIBDL */ - - - -/* --- SHL_LOAD() INTERFACE LOADER --- */ - -#if HAVE_SHL_LOAD - -/* dynamic linking with shl_load (HP-UX) (comments from gmodule) */ - -#ifdef HAVE_DL_H -# include -#endif - -/* some flags are missing on some systems, so we provide - * harmless defaults. - * - * Mandatory: - * BIND_IMMEDIATE - Resolve symbol references when the library is loaded. - * BIND_DEFERRED - Delay code symbol resolution until actual reference. - * - * Optionally: - * BIND_FIRST - Place the library at the head of the symbol search - * order. - * BIND_NONFATAL - The default BIND_IMMEDIATE behavior is to treat all - * unsatisfied symbols as fatal. This flag allows - * binding of unsatisfied code symbols to be deferred - * until use. - * [Perl: For certain libraries, like DCE, deferred - * binding often causes run time problems. Adding - * BIND_NONFATAL to BIND_IMMEDIATE still allows - * unresolved references in situations like this.] - * BIND_NOSTART - Do not call the initializer for the shared library - * when the library is loaded, nor on a future call to - * shl_unload(). - * BIND_VERBOSE - Print verbose messages concerning possible - * unsatisfied symbols. - * - * hp9000s700/hp9000s800: - * BIND_RESTRICTED - Restrict symbols visible by the library to those - * present at library load time. - * DYNAMIC_PATH - Allow the loader to dynamically search for the - * library specified by the path argument. - */ - -#ifndef DYNAMIC_PATH -# define DYNAMIC_PATH 0 -#endif -#ifndef BIND_RESTRICTED -# define BIND_RESTRICTED 0 -#endif - -#define LT_BIND_FLAGS (BIND_IMMEDIATE | BIND_NONFATAL | DYNAMIC_PATH) - -static lt_module -sys_shl_open (loader_data, filename) - lt_user_data loader_data; - const char *filename; -{ - static shl_t self = (shl_t) 0; - lt_module module = shl_load (filename, LT_BIND_FLAGS, 0L); - - /* Since searching for a symbol against a NULL module handle will also - look in everything else that was already loaded and exported with - the -E compiler flag, we always cache a handle saved before any - modules are loaded. */ - if (!self) - { - lt_ptr address; - shl_findsym (&self, "main", TYPE_UNDEFINED, &address); - } - - if (!filename) - { - module = self; - } - else - { - module = shl_load (filename, LT_BIND_FLAGS, 0L); - - if (!module) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); - } - } - - return module; -} - -static int -sys_shl_close (loader_data, module) - lt_user_data loader_data; - lt_module module; -{ - int errors = 0; - - if (module && (shl_unload ((shl_t) (module)) != 0)) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); - ++errors; - } - - return errors; -} - -static lt_ptr -sys_shl_sym (loader_data, module, symbol) - lt_user_data loader_data; - lt_module module; - const char *symbol; -{ - lt_ptr address = 0; - - /* sys_shl_open should never return a NULL module handle */ - if (module == (lt_module) 0) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); - } - else if (!shl_findsym((shl_t*) &module, symbol, TYPE_UNDEFINED, &address)) - { - if (!address) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); - } - } - - return address; -} - -static struct lt_user_dlloader sys_shl = { - 0, sys_shl_open, sys_shl_close, sys_shl_sym, 0, 0 -}; - -#endif /* HAVE_SHL_LOAD */ - - - - -/* --- LOADLIBRARY() INTERFACE LOADER --- */ - -#ifdef __WINDOWS__ - -/* dynamic linking for Win32 */ - -#include - -/* Forward declaration; required to implement handle search below. */ -static lt_dlhandle handles; - -static lt_module -sys_wll_open (loader_data, filename) - lt_user_data loader_data; - const char *filename; -{ - lt_dlhandle cur; - lt_module module = 0; - const char *errormsg = 0; - char *searchname = 0; - char *ext; - char self_name_buf[MAX_PATH]; - - if (!filename) - { - /* Get the name of main module */ - *self_name_buf = 0; - GetModuleFileName (NULL, self_name_buf, sizeof (self_name_buf)); - filename = ext = self_name_buf; - } - else - { - ext = strrchr (filename, '.'); - } - - if (ext) - { - /* FILENAME already has an extension. */ - searchname = lt_estrdup (filename); - } - else - { - /* Append a `.' to stop Windows from adding an - implicit `.dll' extension. */ - searchname = LT_EMALLOC (char, 2+ LT_STRLEN (filename)); - if (searchname) - sprintf (searchname, "%s.", filename); - } - if (!searchname) - return 0; - - { - /* Silence dialog from LoadLibrary on some failures. - No way to get the error mode, but to set it, - so set it twice to preserve any previous flags. */ - UINT errormode = SetErrorMode(SEM_FAILCRITICALERRORS); - SetErrorMode(errormode | SEM_FAILCRITICALERRORS); - -#if defined(__CYGWIN__) - { - char wpath[MAX_PATH]; - cygwin_conv_to_full_win32_path (searchname, wpath); - module = LoadLibrary (wpath); - } -#else - module = LoadLibrary (searchname); -#endif - - /* Restore the error mode. */ - SetErrorMode(errormode); - } - - LT_DLFREE (searchname); - - /* libltdl expects this function to fail if it is unable - to physically load the library. Sadly, LoadLibrary - will search the loaded libraries for a match and return - one of them if the path search load fails. - - We check whether LoadLibrary is returning a handle to - an already loaded module, and simulate failure if we - find one. */ - LT_DLMUTEX_LOCK (); - cur = handles; - while (cur) - { - if (!cur->module) - { - cur = 0; - break; - } - - if (cur->module == module) - { - break; - } - - cur = cur->next; - } - LT_DLMUTEX_UNLOCK (); - - if (cur || !module) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); - module = 0; - } - - return module; -} - -static int -sys_wll_close (loader_data, module) - lt_user_data loader_data; - lt_module module; -{ - int errors = 0; - - if (FreeLibrary(module) == 0) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); - ++errors; - } - - return errors; -} - -static lt_ptr -sys_wll_sym (loader_data, module, symbol) - lt_user_data loader_data; - lt_module module; - const char *symbol; -{ - lt_ptr address = GetProcAddress (module, symbol); - - if (!address) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); - } - - return address; -} - -static struct lt_user_dlloader sys_wll = { - 0, sys_wll_open, sys_wll_close, sys_wll_sym, 0, 0 -}; - -#endif /* __WINDOWS__ */ - - - - -/* --- LOAD_ADD_ON() INTERFACE LOADER --- */ - - -#ifdef __BEOS__ - -/* dynamic linking for BeOS */ - -#include - -static lt_module -sys_bedl_open (loader_data, filename) - lt_user_data loader_data; - const char *filename; -{ - image_id image = 0; - - if (filename) - { - image = load_add_on (filename); - } - else - { - image_info info; - int32 cookie = 0; - if (get_next_image_info (0, &cookie, &info) == B_OK) - image = load_add_on (info.name); - } - - if (image <= 0) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); - image = 0; - } - - return (lt_module) image; -} - -static int -sys_bedl_close (loader_data, module) - lt_user_data loader_data; - lt_module module; -{ - int errors = 0; - - if (unload_add_on ((image_id) module) != B_OK) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); - ++errors; - } - - return errors; -} - -static lt_ptr -sys_bedl_sym (loader_data, module, symbol) - lt_user_data loader_data; - lt_module module; - const char *symbol; -{ - lt_ptr address = 0; - image_id image = (image_id) module; - - if (get_image_symbol (image, symbol, B_SYMBOL_TYPE_ANY, address) != B_OK) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); - address = 0; - } - - return address; -} - -static struct lt_user_dlloader sys_bedl = { - 0, sys_bedl_open, sys_bedl_close, sys_bedl_sym, 0, 0 -}; - -#endif /* __BEOS__ */ - - - - -/* --- DLD_LINK() INTERFACE LOADER --- */ - - -#if HAVE_DLD - -/* dynamic linking with dld */ - -#if HAVE_DLD_H -#include -#endif - -static lt_module -sys_dld_open (loader_data, filename) - lt_user_data loader_data; - const char *filename; -{ - lt_module module = strdup (filename); - - if (dld_link (filename) != 0) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); - LT_DLFREE (module); - module = 0; - } - - return module; -} - -static int -sys_dld_close (loader_data, module) - lt_user_data loader_data; - lt_module module; -{ - int errors = 0; - - if (dld_unlink_by_file ((char*)(module), 1) != 0) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); - ++errors; - } - else - { - LT_DLFREE (module); - } - - return errors; -} - -static lt_ptr -sys_dld_sym (loader_data, module, symbol) - lt_user_data loader_data; - lt_module module; - const char *symbol; -{ - lt_ptr address = dld_get_func (symbol); - - if (!address) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); - } - - return address; -} - -static struct lt_user_dlloader sys_dld = { - 0, sys_dld_open, sys_dld_close, sys_dld_sym, 0, 0 -}; - -#endif /* HAVE_DLD */ - -/* --- DYLD() MACOSX/DARWIN INTERFACE LOADER --- */ -#if HAVE_DYLD - - -#if HAVE_MACH_O_DYLD_H -#if !defined(__APPLE_CC__) && !defined(__MWERKS__) && !defined(__private_extern__) -/* Is this correct? Does it still function properly? */ -#define __private_extern__ extern -#endif -# include -#endif -#include - -/* We have to put some stuff here that isn't in older dyld.h files */ -#ifndef ENUM_DYLD_BOOL -# define ENUM_DYLD_BOOL -# undef FALSE -# undef TRUE - enum DYLD_BOOL { - FALSE, - TRUE - }; -#endif -#ifndef LC_REQ_DYLD -# define LC_REQ_DYLD 0x80000000 -#endif -#ifndef LC_LOAD_WEAK_DYLIB -# define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD) -#endif -static const struct mach_header * (*ltdl_NSAddImage)(const char *image_name, unsigned long options) = 0; -static NSSymbol (*ltdl_NSLookupSymbolInImage)(const struct mach_header *image,const char *symbolName, unsigned long options) = 0; -static enum DYLD_BOOL (*ltdl_NSIsSymbolNameDefinedInImage)(const struct mach_header *image, const char *symbolName) = 0; -static enum DYLD_BOOL (*ltdl_NSMakePrivateModulePublic)(NSModule module) = 0; - -#ifndef NSADDIMAGE_OPTION_NONE -#define NSADDIMAGE_OPTION_NONE 0x0 -#endif -#ifndef NSADDIMAGE_OPTION_RETURN_ON_ERROR -#define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1 -#endif -#ifndef NSADDIMAGE_OPTION_WITH_SEARCHING -#define NSADDIMAGE_OPTION_WITH_SEARCHING 0x2 -#endif -#ifndef NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED -#define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4 -#endif -#ifndef NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME -#define NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME 0x8 -#endif -#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND -#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0 -#endif -#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW -#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW 0x1 -#endif -#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY -#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY 0x2 -#endif -#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR -#define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4 -#endif - - -static const char * -lt_int_dyld_error(othererror) - char* othererror; -{ -/* return the dyld error string, or the passed in error string if none */ - NSLinkEditErrors ler; - int lerno; - const char *errstr; - const char *file; - NSLinkEditError(&ler,&lerno,&file,&errstr); - if (!errstr || !strlen(errstr)) errstr = othererror; - return errstr; -} - -static const struct mach_header * -lt_int_dyld_get_mach_header_from_nsmodule(module) - NSModule module; -{ -/* There should probably be an apple dyld api for this */ - int i=_dyld_image_count(); - int j; - const char *modname=NSNameOfModule(module); - const struct mach_header *mh=NULL; - if (!modname) return NULL; - for (j = 0; j < i; j++) - { - if (!strcmp(_dyld_get_image_name(j),modname)) - { - mh=_dyld_get_image_header(j); - break; - } - } - return mh; -} - -static const char* lt_int_dyld_lib_install_name(mh) - const struct mach_header *mh; -{ -/* NSAddImage is also used to get the loaded image, but it only works if the lib - is installed, for uninstalled libs we need to check the install_names against - each other. Note that this is still broken if DYLD_IMAGE_SUFFIX is set and a - different lib was loaded as a result -*/ - int j; - struct load_command *lc; - unsigned long offset = sizeof(struct mach_header); - const char* retStr=NULL; - for (j = 0; j < mh->ncmds; j++) - { - lc = (struct load_command*)(((unsigned long)mh) + offset); - if (LC_ID_DYLIB == lc->cmd) - { - retStr=(char*)(((struct dylib_command*)lc)->dylib.name.offset + - (unsigned long)lc); - } - offset += lc->cmdsize; - } - return retStr; -} - -static const struct mach_header * -lt_int_dyld_match_loaded_lib_by_install_name(const char *name) -{ - int i=_dyld_image_count(); - int j; - const struct mach_header *mh=NULL; - const char *id=NULL; - for (j = 0; j < i; j++) - { - id=lt_int_dyld_lib_install_name(_dyld_get_image_header(j)); - if ((id) && (!strcmp(id,name))) - { - mh=_dyld_get_image_header(j); - break; - } - } - return mh; -} - -static NSSymbol -lt_int_dyld_NSlookupSymbolInLinkedLibs(symbol,mh) - const char *symbol; - const struct mach_header *mh; -{ - /* Safe to assume our mh is good */ - int j; - struct load_command *lc; - unsigned long offset = sizeof(struct mach_header); - NSSymbol retSym = 0; - const struct mach_header *mh1; - if ((ltdl_NSLookupSymbolInImage) && NSIsSymbolNameDefined(symbol) ) - { - for (j = 0; j < mh->ncmds; j++) - { - lc = (struct load_command*)(((unsigned long)mh) + offset); - if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd)) - { - mh1=lt_int_dyld_match_loaded_lib_by_install_name((char*)(((struct dylib_command*)lc)->dylib.name.offset + - (unsigned long)lc)); - if (!mh1) - { - /* Maybe NSAddImage can find it */ - mh1=ltdl_NSAddImage((char*)(((struct dylib_command*)lc)->dylib.name.offset + - (unsigned long)lc), - NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED + - NSADDIMAGE_OPTION_WITH_SEARCHING + - NSADDIMAGE_OPTION_RETURN_ON_ERROR ); - } - if (mh1) - { - retSym = ltdl_NSLookupSymbolInImage(mh1, - symbol, - NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW - | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR - ); - if (retSym) break; - } - } - offset += lc->cmdsize; - } - } - return retSym; -} - -static int -sys_dyld_init() -{ - int retCode = 0; - int err = 0; - if (!_dyld_present()) { - retCode=1; - } - else { - err = _dyld_func_lookup("__dyld_NSAddImage",(unsigned long*)<dl_NSAddImage); - err = _dyld_func_lookup("__dyld_NSLookupSymbolInImage",(unsigned long*)<dl_NSLookupSymbolInImage); - err = _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage",(unsigned long*)<dl_NSIsSymbolNameDefinedInImage); - err = _dyld_func_lookup("__dyld_NSMakePrivateModulePublic",(unsigned long*)<dl_NSMakePrivateModulePublic); - } - return retCode; -} - -static lt_module -sys_dyld_open (loader_data, filename) - lt_user_data loader_data; - const char *filename; -{ - lt_module module = 0; - NSObjectFileImage ofi = 0; - NSObjectFileImageReturnCode ofirc; - - if (!filename) - return (lt_module)-1; - ofirc = NSCreateObjectFileImageFromFile(filename, &ofi); - switch (ofirc) - { - case NSObjectFileImageSuccess: - module = NSLinkModule(ofi, filename, - NSLINKMODULE_OPTION_RETURN_ON_ERROR - | NSLINKMODULE_OPTION_PRIVATE - | NSLINKMODULE_OPTION_BINDNOW); - NSDestroyObjectFileImage(ofi); - if (module) - ltdl_NSMakePrivateModulePublic(module); - break; - case NSObjectFileImageInappropriateFile: - if (ltdl_NSIsSymbolNameDefinedInImage && ltdl_NSLookupSymbolInImage) - { - module = (lt_module)ltdl_NSAddImage(filename, NSADDIMAGE_OPTION_RETURN_ON_ERROR); - break; - } - default: - LT_DLMUTEX_SETERROR (lt_int_dyld_error(LT_DLSTRERROR(CANNOT_OPEN))); - return 0; - } - if (!module) LT_DLMUTEX_SETERROR (lt_int_dyld_error(LT_DLSTRERROR(CANNOT_OPEN))); - return module; -} - -static int -sys_dyld_close (loader_data, module) - lt_user_data loader_data; - lt_module module; -{ - int retCode = 0; - int flags = 0; - if (module == (lt_module)-1) return 0; -#ifdef __BIG_ENDIAN__ - if (((struct mach_header *)module)->magic == MH_MAGIC) -#else - if (((struct mach_header *)module)->magic == MH_CIGAM) -#endif - { - LT_DLMUTEX_SETERROR("Can not close a dylib"); - retCode = 1; - } - else - { -#if 1 -/* Currently, if a module contains c++ static destructors and it is unloaded, we - get a segfault in atexit(), due to compiler and dynamic loader differences of - opinion, this works around that. -*/ - if ((const struct section *)NULL != - getsectbynamefromheader(lt_int_dyld_get_mach_header_from_nsmodule(module), - "__DATA","__mod_term_func")) - { - flags += NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED; - } -#endif -#ifdef __ppc__ - flags += NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES; -#endif - if (!NSUnLinkModule(module,flags)) - { - retCode=1; - LT_DLMUTEX_SETERROR (lt_int_dyld_error(LT_DLSTRERROR(CANNOT_CLOSE))); - } - } - - return retCode; -} - -static lt_ptr -sys_dyld_sym (loader_data, module, symbol) - lt_user_data loader_data; - lt_module module; - const char *symbol; -{ - lt_ptr address = 0; - NSSymbol *nssym = 0; - void *unused; - const struct mach_header *mh=NULL; - char saveError[256] = "Symbol not found"; - if (module == (lt_module)-1) - { - _dyld_lookup_and_bind(symbol,(unsigned long*)&address,&unused); - return address; - } -#ifdef __BIG_ENDIAN__ - if (((struct mach_header *)module)->magic == MH_MAGIC) -#else - if (((struct mach_header *)module)->magic == MH_CIGAM) -#endif - { - if (ltdl_NSIsSymbolNameDefinedInImage && ltdl_NSLookupSymbolInImage) - { - mh=module; - if (ltdl_NSIsSymbolNameDefinedInImage((struct mach_header*)module,symbol)) - { - nssym = ltdl_NSLookupSymbolInImage((struct mach_header*)module, - symbol, - NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW - | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR - ); - } - } - - } - else { - nssym = NSLookupSymbolInModule(module, symbol); - } - if (!nssym) - { - strncpy(saveError, lt_int_dyld_error(LT_DLSTRERROR(SYMBOL_NOT_FOUND)), 255); - saveError[255] = 0; - if (!mh) mh=lt_int_dyld_get_mach_header_from_nsmodule(module); - nssym = lt_int_dyld_NSlookupSymbolInLinkedLibs(symbol,mh); - } - if (!nssym) - { - LT_DLMUTEX_SETERROR (saveError); - return NULL; - } - return NSAddressOfSymbol(nssym); -} - -static struct lt_user_dlloader sys_dyld = - { "_", sys_dyld_open, sys_dyld_close, sys_dyld_sym, 0, 0 }; - - -#endif /* HAVE_DYLD */ - - -/* --- DLPREOPEN() INTERFACE LOADER --- */ - - -/* emulate dynamic linking using preloaded_symbols */ - -typedef struct lt_dlsymlists_t -{ - struct lt_dlsymlists_t *next; - const lt_dlsymlist *syms; -} lt_dlsymlists_t; - -static const lt_dlsymlist *default_preloaded_symbols = 0; -static lt_dlsymlists_t *preloaded_symbols = 0; - -static int -presym_init (loader_data) - lt_user_data loader_data; -{ - int errors = 0; - - LT_DLMUTEX_LOCK (); - - preloaded_symbols = 0; - if (default_preloaded_symbols) - { - errors = lt_dlpreload (default_preloaded_symbols); - } - - LT_DLMUTEX_UNLOCK (); - - return errors; -} - -static int -presym_free_symlists () -{ - lt_dlsymlists_t *lists; - - LT_DLMUTEX_LOCK (); - - lists = preloaded_symbols; - while (lists) - { - lt_dlsymlists_t *tmp = lists; - - lists = lists->next; - LT_DLFREE (tmp); - } - preloaded_symbols = 0; - - LT_DLMUTEX_UNLOCK (); - - return 0; -} - -static int -presym_exit (loader_data) - lt_user_data loader_data; -{ - presym_free_symlists (); - return 0; -} - -static int -presym_add_symlist (preloaded) - const lt_dlsymlist *preloaded; -{ - lt_dlsymlists_t *tmp; - lt_dlsymlists_t *lists; - int errors = 0; - - LT_DLMUTEX_LOCK (); - - lists = preloaded_symbols; - while (lists) - { - if (lists->syms == preloaded) - { - goto done; - } - lists = lists->next; - } - - tmp = LT_EMALLOC (lt_dlsymlists_t, 1); - if (tmp) - { - memset (tmp, 0, sizeof(lt_dlsymlists_t)); - tmp->syms = preloaded; - tmp->next = preloaded_symbols; - preloaded_symbols = tmp; - } - else - { - ++errors; - } - - done: - LT_DLMUTEX_UNLOCK (); - return errors; -} - -static lt_module -presym_open (loader_data, filename) - lt_user_data loader_data; - const char *filename; -{ - lt_dlsymlists_t *lists; - lt_module module = (lt_module) 0; - - LT_DLMUTEX_LOCK (); - lists = preloaded_symbols; - - if (!lists) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_SYMBOLS)); - goto done; - } - - /* Can't use NULL as the reflective symbol header, as NULL is - used to mark the end of the entire symbol list. Self-dlpreopened - symbols follow this magic number, chosen to be an unlikely - clash with a real module name. */ - if (!filename) - { - filename = "@PROGRAM@"; - } - - while (lists) - { - const lt_dlsymlist *syms = lists->syms; - - while (syms->name) - { - if (!syms->address && strcmp(syms->name, filename) == 0) - { - module = (lt_module) syms; - goto done; - } - ++syms; - } - - lists = lists->next; - } - - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); - - done: - LT_DLMUTEX_UNLOCK (); - return module; -} - -static int -presym_close (loader_data, module) - lt_user_data loader_data; - lt_module module; -{ - /* Just to silence gcc -Wall */ - module = 0; - return 0; -} - -static lt_ptr -presym_sym (loader_data, module, symbol) - lt_user_data loader_data; - lt_module module; - const char *symbol; -{ - lt_dlsymlist *syms = (lt_dlsymlist*) module; - - ++syms; - while (syms->address) - { - if (strcmp(syms->name, symbol) == 0) - { - return syms->address; - } - - ++syms; - } - - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); - - return 0; -} - -static struct lt_user_dlloader presym = { - 0, presym_open, presym_close, presym_sym, presym_exit, 0 -}; - - - - - -/* --- DYNAMIC MODULE LOADING --- */ - - -/* The type of a function used at each iteration of foreach_dirinpath(). */ -typedef int foreach_callback_func LT_PARAMS((char *filename, lt_ptr data1, - lt_ptr data2)); - -static int foreach_dirinpath LT_PARAMS((const char *search_path, - const char *base_name, - foreach_callback_func *func, - lt_ptr data1, lt_ptr data2)); - -static int find_file_callback LT_PARAMS((char *filename, lt_ptr data, - lt_ptr ignored)); -static int find_handle_callback LT_PARAMS((char *filename, lt_ptr data, - lt_ptr ignored)); -static int foreachfile_callback LT_PARAMS((char *filename, lt_ptr data1, - lt_ptr data2)); - - -static int canonicalize_path LT_PARAMS((const char *path, - char **pcanonical)); -static int argzize_path LT_PARAMS((const char *path, - char **pargz, - size_t *pargz_len)); -static FILE *find_file LT_PARAMS((const char *search_path, - const char *base_name, - char **pdir)); -static lt_dlhandle *find_handle LT_PARAMS((const char *search_path, - const char *base_name, - lt_dlhandle *handle)); -static int find_module LT_PARAMS((lt_dlhandle *handle, - const char *dir, - const char *libdir, - const char *dlname, - const char *old_name, - int installed)); -static int free_vars LT_PARAMS((char *dlname, char *oldname, - char *libdir, char *deplibs)); -static int load_deplibs LT_PARAMS((lt_dlhandle handle, - char *deplibs)); -static int trim LT_PARAMS((char **dest, - const char *str)); -static int try_dlopen LT_PARAMS((lt_dlhandle *handle, - const char *filename)); -static int tryall_dlopen LT_PARAMS((lt_dlhandle *handle, - const char *filename)); -static int unload_deplibs LT_PARAMS((lt_dlhandle handle)); -static int lt_argz_insert LT_PARAMS((char **pargz, - size_t *pargz_len, - char *before, - const char *entry)); -static int lt_argz_insertinorder LT_PARAMS((char **pargz, - size_t *pargz_len, - const char *entry)); -static int lt_argz_insertdir LT_PARAMS((char **pargz, - size_t *pargz_len, - const char *dirnam, - struct dirent *dp)); -static int lt_dlpath_insertdir LT_PARAMS((char **ppath, - char *before, - const char *dir)); -static int list_files_by_dir LT_PARAMS((const char *dirnam, - char **pargz, - size_t *pargz_len)); -static int file_not_found LT_PARAMS((void)); - -static char *user_search_path= 0; -static lt_dlloader *loaders = 0; -static lt_dlhandle handles = 0; -static int initialized = 0; - -/* Initialize libltdl. */ -int -lt_dlinit () -{ - int errors = 0; - - LT_DLMUTEX_LOCK (); - - /* Initialize only at first call. */ - if (++initialized == 1) - { - handles = 0; - user_search_path = 0; /* empty search path */ - -#if HAVE_LIBDL - errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dl, "dlopen"); -#endif -#if HAVE_SHL_LOAD - errors += lt_dlloader_add (lt_dlloader_next (0), &sys_shl, "dlopen"); -#endif -#ifdef __WINDOWS__ - errors += lt_dlloader_add (lt_dlloader_next (0), &sys_wll, "dlopen"); -#endif -#ifdef __BEOS__ - errors += lt_dlloader_add (lt_dlloader_next (0), &sys_bedl, "dlopen"); -#endif -#if HAVE_DLD - errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dld, "dld"); -#endif -#if HAVE_DYLD - errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dyld, "dyld"); - errors += sys_dyld_init(); -#endif - errors += lt_dlloader_add (lt_dlloader_next (0), &presym, "dlpreload"); - - if (presym_init (presym.dlloader_data)) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INIT_LOADER)); - ++errors; - } - else if (errors != 0) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (DLOPEN_NOT_SUPPORTED)); - ++errors; - } - } - - LT_DLMUTEX_UNLOCK (); - - return errors; -} - -int -lt_dlpreload (preloaded) - const lt_dlsymlist *preloaded; -{ - int errors = 0; - - if (preloaded) - { - errors = presym_add_symlist (preloaded); - } - else - { - presym_free_symlists(); - - LT_DLMUTEX_LOCK (); - if (default_preloaded_symbols) - { - errors = lt_dlpreload (default_preloaded_symbols); - } - LT_DLMUTEX_UNLOCK (); - } - - return errors; -} - -int -lt_dlpreload_default (preloaded) - const lt_dlsymlist *preloaded; -{ - LT_DLMUTEX_LOCK (); - default_preloaded_symbols = preloaded; - LT_DLMUTEX_UNLOCK (); - return 0; -} - -int -lt_dlexit () -{ - /* shut down libltdl */ - lt_dlloader *loader; - int errors = 0; - - LT_DLMUTEX_LOCK (); - loader = loaders; - - if (!initialized) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SHUTDOWN)); - ++errors; - goto done; - } - - /* shut down only at last call. */ - if (--initialized == 0) - { - int level; - - while (handles && LT_DLIS_RESIDENT (handles)) - { - handles = handles->next; - } - - /* close all modules */ - for (level = 1; handles; ++level) - { - lt_dlhandle cur = handles; - int saw_nonresident = 0; - - while (cur) - { - lt_dlhandle tmp = cur; - cur = cur->next; - if (!LT_DLIS_RESIDENT (tmp)) - saw_nonresident = 1; - if (!LT_DLIS_RESIDENT (tmp) && tmp->info.ref_count <= level) - { - if (lt_dlclose (tmp)) - { - ++errors; - } - /* Make sure that the handle pointed to by 'cur' still exists. - lt_dlclose recursively closes dependent libraries which removes - them from the linked list. One of these might be the one - pointed to by 'cur'. */ - if (cur) - { - for (tmp = handles; tmp; tmp = tmp->next) - if (tmp == cur) - break; - if (! tmp) - cur = handles; - } - } - } - /* done if only resident modules are left */ - if (!saw_nonresident) - break; - } - - /* close all loaders */ - while (loader) - { - lt_dlloader *next = loader->next; - lt_user_data data = loader->dlloader_data; - if (loader->dlloader_exit && loader->dlloader_exit (data)) - { - ++errors; - } - - LT_DLMEM_REASSIGN (loader, next); - } - loaders = 0; - } - - done: - LT_DLMUTEX_UNLOCK (); - return errors; -} - -static int -tryall_dlopen (handle, filename) - lt_dlhandle *handle; - const char *filename; -{ - lt_dlhandle cur; - lt_dlloader *loader; - const char *saved_error; - int errors = 0; - - LT_DLMUTEX_GETERROR (saved_error); - LT_DLMUTEX_LOCK (); - - cur = handles; - loader = loaders; - - /* check whether the module was already opened */ - while (cur) - { - /* try to dlopen the program itself? */ - if (!cur->info.filename && !filename) - { - break; - } - - if (cur->info.filename && filename - && strcmp (cur->info.filename, filename) == 0) - { - break; - } - - cur = cur->next; - } - - if (cur) - { - ++cur->info.ref_count; - *handle = cur; - goto done; - } - - cur = *handle; - if (filename) - { - /* Comment out the check of file permissions using access. - This call seems to always return -1 with error EACCES. - */ - /* We need to catch missing file errors early so that - file_not_found() can detect what happened. - if (access (filename, R_OK) != 0) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); - ++errors; - goto done; - } */ - - cur->info.filename = lt_estrdup (filename); - if (!cur->info.filename) - { - ++errors; - goto done; - } - } - else - { - cur->info.filename = 0; - } - - while (loader) - { - lt_user_data data = loader->dlloader_data; - - cur->module = loader->module_open (data, filename); - - if (cur->module != 0) - { - break; - } - loader = loader->next; - } - - if (!loader) - { - LT_DLFREE (cur->info.filename); - ++errors; - goto done; - } - - cur->loader = loader; - LT_DLMUTEX_SETERROR (saved_error); - - done: - LT_DLMUTEX_UNLOCK (); - - return errors; -} - -static int -tryall_dlopen_module (handle, prefix, dirname, dlname) - lt_dlhandle *handle; - const char *prefix; - const char *dirname; - const char *dlname; -{ - int error = 0; - char *filename = 0; - size_t filename_len = 0; - size_t dirname_len = LT_STRLEN (dirname); - - assert (handle); - assert (dirname); - assert (dlname); -#ifdef LT_DIRSEP_CHAR - /* Only canonicalized names (i.e. with DIRSEP chars already converted) - should make it into this function: */ - assert (strchr (dirname, LT_DIRSEP_CHAR) == 0); -#endif - - if (dirname_len > 0) - if (dirname[dirname_len -1] == '/') - --dirname_len; - filename_len = dirname_len + 1 + LT_STRLEN (dlname); - - /* Allocate memory, and combine DIRNAME and MODULENAME into it. - The PREFIX (if any) is handled below. */ - filename = LT_EMALLOC (char, dirname_len + 1 + filename_len + 1); - if (!filename) - return 1; - - sprintf (filename, "%.*s/%s", (int) dirname_len, dirname, dlname); - - /* Now that we have combined DIRNAME and MODULENAME, if there is - also a PREFIX to contend with, simply recurse with the arguments - shuffled. Otherwise, attempt to open FILENAME as a module. */ - if (prefix) - { - error += tryall_dlopen_module (handle, - (const char *) 0, prefix, filename); - } - else if (tryall_dlopen (handle, filename) != 0) - { - ++error; - } - - LT_DLFREE (filename); - return error; -} - -static int -find_module (handle, dir, libdir, dlname, old_name, installed) - lt_dlhandle *handle; - const char *dir; - const char *libdir; - const char *dlname; - const char *old_name; - int installed; -{ - /* Try to open the old library first; if it was dlpreopened, - we want the preopened version of it, even if a dlopenable - module is available. */ - if (old_name && tryall_dlopen (handle, old_name) == 0) - { - return 0; - } - - /* Try to open the dynamic library. */ - if (dlname) - { - /* try to open the installed module */ - if (installed && libdir) - { - if (tryall_dlopen_module (handle, - (const char *) 0, libdir, dlname) == 0) - return 0; - } - - /* try to open the not-installed module */ - if (!installed) - { - if (tryall_dlopen_module (handle, dir, objdir, dlname) == 0) - return 0; - } - - /* maybe it was moved to another directory */ - { - if (dir && (tryall_dlopen_module (handle, - (const char *) 0, dir, dlname) == 0)) - return 0; - } - } - - return 1; -} - - -static int -canonicalize_path (path, pcanonical) - const char *path; - char **pcanonical; -{ - char *canonical = 0; - - assert (path && *path); - assert (pcanonical); - - canonical = LT_EMALLOC (char, 1+ LT_STRLEN (path)); - if (!canonical) - return 1; - - { - size_t dest = 0; - size_t src; - for (src = 0; path[src] != LT_EOS_CHAR; ++src) - { - /* Path separators are not copied to the beginning or end of - the destination, or if another separator would follow - immediately. */ - if (path[src] == LT_PATHSEP_CHAR) - { - if ((dest == 0) - || (path[1+ src] == LT_PATHSEP_CHAR) - || (path[1+ src] == LT_EOS_CHAR)) - continue; - } - - /* Anything other than a directory separator is copied verbatim. */ - if ((path[src] != '/') -#ifdef LT_DIRSEP_CHAR - && (path[src] != LT_DIRSEP_CHAR) -#endif - ) - { - canonical[dest++] = path[src]; - } - /* Directory separators are converted and copied only if they are - not at the end of a path -- i.e. before a path separator or - NULL terminator. */ - else if ((path[1+ src] != LT_PATHSEP_CHAR) - && (path[1+ src] != LT_EOS_CHAR) -#ifdef LT_DIRSEP_CHAR - && (path[1+ src] != LT_DIRSEP_CHAR) -#endif - && (path[1+ src] != '/')) - { - canonical[dest++] = '/'; - } - } - - /* Add an end-of-string marker at the end. */ - canonical[dest] = LT_EOS_CHAR; - } - - /* Assign new value. */ - *pcanonical = canonical; - - return 0; -} - -static int -argzize_path (path, pargz, pargz_len) - const char *path; - char **pargz; - size_t *pargz_len; -{ - error_t error; - - assert (path); - assert (pargz); - assert (pargz_len); - - if ((error = argz_create_sep (path, LT_PATHSEP_CHAR, pargz, pargz_len))) - { - switch (error) - { - case ENOMEM: - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - break; - default: - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN)); - break; - } - - return 1; - } - - return 0; -} - -/* Repeatedly call FUNC with each LT_PATHSEP_CHAR delimited element - of SEARCH_PATH and references to DATA1 and DATA2, until FUNC returns - non-zero or all elements are exhausted. If BASE_NAME is non-NULL, - it is appended to each SEARCH_PATH element before FUNC is called. */ -static int -foreach_dirinpath (search_path, base_name, func, data1, data2) - const char *search_path; - const char *base_name; - foreach_callback_func *func; - lt_ptr data1; - lt_ptr data2; -{ - int result = 0; - int filenamesize = 0; - size_t lenbase = LT_STRLEN (base_name); - size_t argz_len = 0; - char *argz = 0; - char *filename = 0; - char *canonical = 0; - - LT_DLMUTEX_LOCK (); - - if (!search_path || !*search_path) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); - goto cleanup; - } - - if (canonicalize_path (search_path, &canonical) != 0) - goto cleanup; - - if (argzize_path (canonical, &argz, &argz_len) != 0) - goto cleanup; - - { - char *dir_name = 0; - while ((dir_name = argz_next (argz, argz_len, dir_name))) - { - size_t lendir = LT_STRLEN (dir_name); - - if (lendir +1 +lenbase >= filenamesize) - { - LT_DLFREE (filename); - filenamesize = lendir +1 +lenbase +1; /* "/d" + '/' + "f" + '\0' */ - filename = LT_EMALLOC (char, filenamesize); - if (!filename) - goto cleanup; - } - - assert (filenamesize > lendir); - strcpy (filename, dir_name); - - if (base_name && *base_name) - { - if (filename[lendir -1] != '/') - filename[lendir++] = '/'; - strcpy (filename +lendir, base_name); - } - - if ((result = (*func) (filename, data1, data2))) - { - break; - } - } - } - - cleanup: - LT_DLFREE (argz); - LT_DLFREE (canonical); - LT_DLFREE (filename); - - LT_DLMUTEX_UNLOCK (); - - return result; -} - -/* If FILEPATH can be opened, store the name of the directory component - in DATA1, and the opened FILE* structure address in DATA2. Otherwise - DATA1 is unchanged, but DATA2 is set to a pointer to NULL. */ -static int -find_file_callback (filename, data1, data2) - char *filename; - lt_ptr data1; - lt_ptr data2; -{ - char **pdir = (char **) data1; - FILE **pfile = (FILE **) data2; - int is_done = 0; - - assert (filename && *filename); - assert (pdir); - assert (pfile); - - if ((*pfile = fopen (filename, LT_READTEXT_MODE))) - { - char *dirend = strrchr (filename, '/'); - - if (dirend > filename) - *dirend = LT_EOS_CHAR; - - LT_DLFREE (*pdir); - *pdir = lt_estrdup (filename); - is_done = (*pdir == 0) ? -1 : 1; - } - - return is_done; -} - -static FILE * -find_file (search_path, base_name, pdir) - const char *search_path; - const char *base_name; - char **pdir; -{ - FILE *file = 0; - - foreach_dirinpath (search_path, base_name, find_file_callback, pdir, &file); - - return file; -} - -static int -find_handle_callback (filename, data, ignored) - char *filename; - lt_ptr data; - lt_ptr ignored; -{ - lt_dlhandle *handle = (lt_dlhandle *) data; - int notfound = access (filename, R_OK); - - /* Bail out if file cannot be read... */ - if (notfound) - return 0; - - /* Try to dlopen the file, but do not continue searching in any - case. */ - if (tryall_dlopen (handle, filename) != 0) - *handle = 0; - - return 1; -} - -/* If HANDLE was found return it, otherwise return 0. If HANDLE was - found but could not be opened, *HANDLE will be set to 0. */ -static lt_dlhandle * -find_handle (search_path, base_name, handle) - const char *search_path; - const char *base_name; - lt_dlhandle *handle; -{ - if (!search_path) - return 0; - - if (!foreach_dirinpath (search_path, base_name, find_handle_callback, - handle, 0)) - return 0; - - return handle; -} - -static int -load_deplibs (handle, deplibs) - lt_dlhandle handle; - char *deplibs; -{ -#if LTDL_DLOPEN_DEPLIBS - char *p, *save_search_path = 0; - int depcount = 0; - int i; - char **names = 0; -#endif - int errors = 0; - - handle->depcount = 0; - -#if LTDL_DLOPEN_DEPLIBS - if (!deplibs) - { - return errors; - } - ++errors; - - LT_DLMUTEX_LOCK (); - if (user_search_path) - { - save_search_path = lt_estrdup (user_search_path); - if (!save_search_path) - goto cleanup; - } - - /* extract search paths and count deplibs */ - p = deplibs; - while (*p) - { - if (!isspace ((int) *p)) - { - char *end = p+1; - while (*end && !isspace((int) *end)) - { - ++end; - } - - if (strncmp(p, "-L", 2) == 0 || strncmp(p, "-R", 2) == 0) - { - char save = *end; - *end = 0; /* set a temporary string terminator */ - if (lt_dladdsearchdir(p+2)) - { - goto cleanup; - } - *end = save; - } - else - { - ++depcount; - } - - p = end; - } - else - { - ++p; - } - } - - if (!depcount) - { - errors = 0; - goto cleanup; - } - - names = LT_EMALLOC (char *, depcount * sizeof (char*)); - if (!names) - goto cleanup; - - /* now only extract the actual deplibs */ - depcount = 0; - p = deplibs; - while (*p) - { - if (isspace ((int) *p)) - { - ++p; - } - else - { - char *end = p+1; - while (*end && !isspace ((int) *end)) - { - ++end; - } - - if (strncmp(p, "-L", 2) != 0 && strncmp(p, "-R", 2) != 0) - { - char *name; - char save = *end; - *end = 0; /* set a temporary string terminator */ - if (strncmp(p, "-l", 2) == 0) - { - size_t name_len = 3+ /* "lib" */ LT_STRLEN (p + 2); - name = LT_EMALLOC (char, 1+ name_len); - if (name) - sprintf (name, "lib%s", p+2); - } - else - name = lt_estrdup(p); - - if (!name) - goto cleanup_names; - - names[depcount++] = name; - *end = save; - } - p = end; - } - } - - /* load the deplibs (in reverse order) - At this stage, don't worry if the deplibs do not load correctly, - they may already be statically linked into the loading application - for instance. There will be a more enlightening error message - later on if the loaded module cannot resolve all of its symbols. */ - if (depcount) - { - int j = 0; - - handle->deplibs = (lt_dlhandle*) LT_EMALLOC (lt_dlhandle *, depcount); - if (!handle->deplibs) - goto cleanup_names; - - for (i = 0; i < depcount; ++i) - { - handle->deplibs[j] = lt_dlopenext(names[depcount-1-i]); - if (handle->deplibs[j]) - { - ++j; - } - } - - handle->depcount = j; /* Number of successfully loaded deplibs */ - errors = 0; - } - - cleanup_names: - for (i = 0; i < depcount; ++i) - { - LT_DLFREE (names[i]); - } - - cleanup: - LT_DLFREE (names); - /* restore the old search path */ - if (user_search_path) { - LT_DLFREE (user_search_path); - user_search_path = save_search_path; - } - LT_DLMUTEX_UNLOCK (); - -#endif - - return errors; -} - -static int -unload_deplibs (handle) - lt_dlhandle handle; -{ - int i; - int errors = 0; - - if (handle->depcount) - { - for (i = 0; i < handle->depcount; ++i) - { - if (!LT_DLIS_RESIDENT (handle->deplibs[i])) - { - errors += lt_dlclose (handle->deplibs[i]); - } - } - LT_DLFREE (handle->deplibs); - } - - return errors; -} - -static int -trim (dest, str) - char **dest; - const char *str; -{ - /* remove the leading and trailing "'" from str - and store the result in dest */ - const char *end = strrchr (str, '\''); - size_t len = LT_STRLEN (str); - char *tmp; - - LT_DLFREE (*dest); - - if (!end) - return 1; - - if (len > 3 && str[0] == '\'') - { - tmp = LT_EMALLOC (char, end - str); - if (!tmp) - return 1; - - strncpy(tmp, &str[1], (end - str) - 1); - tmp[len-3] = LT_EOS_CHAR; - *dest = tmp; - } - else - { - *dest = 0; - } - - return 0; -} - -static int -free_vars (dlname, oldname, libdir, deplibs) - char *dlname; - char *oldname; - char *libdir; - char *deplibs; -{ - LT_DLFREE (dlname); - LT_DLFREE (oldname); - LT_DLFREE (libdir); - LT_DLFREE (deplibs); - - return 0; -} - -static int -try_dlopen (phandle, filename) - lt_dlhandle *phandle; - const char *filename; -{ - const char * ext = 0; - const char * saved_error = 0; - char * canonical = 0; - char * base_name = 0; - char * dir = 0; - char * name = 0; - int errors = 0; - lt_dlhandle newhandle; - - assert (phandle); - assert (*phandle == 0); - - LT_DLMUTEX_GETERROR (saved_error); - - /* dlopen self? */ - if (!filename) - { - *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1); - if (*phandle == 0) - return 1; - - memset (*phandle, 0, sizeof(struct lt_dlhandle_struct)); - newhandle = *phandle; - - /* lt_dlclose()ing yourself is very bad! Disallow it. */ - LT_DLSET_FLAG (*phandle, LT_DLRESIDENT_FLAG); - - if (tryall_dlopen (&newhandle, 0) != 0) - { - LT_DLFREE (*phandle); - return 1; - } - - goto register_handle; - } - - assert (filename && *filename); - - /* Doing this immediately allows internal functions to safely - assume only canonicalized paths are passed. */ - if (canonicalize_path (filename, &canonical) != 0) - { - ++errors; - goto cleanup; - } - - /* If the canonical module name is a path (relative or absolute) - then split it into a directory part and a name part. */ - base_name = strrchr (canonical, '/'); - if (base_name) - { - size_t dirlen = (1+ base_name) - canonical; - - dir = LT_EMALLOC (char, 1+ dirlen); - if (!dir) - { - ++errors; - goto cleanup; - } - - strncpy (dir, canonical, dirlen); - dir[dirlen] = LT_EOS_CHAR; - - ++base_name; - } - else - base_name = canonical; - - assert (base_name && *base_name); - - /* Check whether we are opening a libtool module (.la extension). */ - ext = strrchr (base_name, '.'); - if (ext && strcmp (ext, archive_ext) == 0) - { - /* this seems to be a libtool module */ - FILE * file = 0; - char * dlname = 0; - char * old_name = 0; - char * libdir = 0; - char * deplibs = 0; - char * line = 0; - size_t line_len; - - /* if we can't find the installed flag, it is probably an - installed libtool archive, produced with an old version - of libtool */ - int installed = 1; - - /* extract the module name from the file name */ - name = LT_EMALLOC (char, ext - base_name + 1); - if (!name) - { - ++errors; - goto cleanup; - } - - /* canonicalize the module name */ - { - size_t i; - for (i = 0; i < ext - base_name; ++i) - { - if (isalnum ((int)(base_name[i]))) - { - name[i] = base_name[i]; - } - else - { - name[i] = '_'; - } - } - name[ext - base_name] = LT_EOS_CHAR; - } - - /* Now try to open the .la file. If there is no directory name - component, try to find it first in user_search_path and then other - prescribed paths. Otherwise (or in any case if the module was not - yet found) try opening just the module name as passed. */ - if (!dir) - { - const char *search_path; - - LT_DLMUTEX_LOCK (); - search_path = user_search_path; - if (search_path) - file = find_file (user_search_path, base_name, &dir); - LT_DLMUTEX_UNLOCK (); - - if (!file) - { - search_path = getenv (LTDL_SEARCHPATH_VAR); - if (search_path) - file = find_file (search_path, base_name, &dir); - } - -#ifdef LTDL_SHLIBPATH_VAR - if (!file) - { - search_path = getenv (LTDL_SHLIBPATH_VAR); - if (search_path) - file = find_file (search_path, base_name, &dir); - } -#endif -#ifdef LTDL_SYSSEARCHPATH - if (!file && sys_search_path) - { - file = find_file (sys_search_path, base_name, &dir); - } -#endif - } - if (!file) - { - file = fopen (filename, LT_READTEXT_MODE); - } - - /* If we didn't find the file by now, it really isn't there. Set - the status flag, and bail out. */ - if (!file) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); - ++errors; - goto cleanup; - } - - line_len = LT_FILENAME_MAX; - line = LT_EMALLOC (char, line_len); - if (!line) - { - fclose (file); - ++errors; - goto cleanup; - } - - /* read the .la file */ - while (!feof (file)) - { - if (!fgets (line, (int) line_len, file)) - { - break; - } - - /* Handle the case where we occasionally need to read a line - that is longer than the initial buffer size. */ - while ((line[LT_STRLEN(line) -1] != '\n') && (!feof (file))) - { - line = LT_DLREALLOC (char, line, line_len *2); - if (!fgets (&line[line_len -1], (int) line_len +1, file)) - { - break; - } - line_len *= 2; - } - - if (line[0] == '\n' || line[0] == '#') - { - continue; - } - -#undef STR_DLNAME -#define STR_DLNAME "dlname=" - if (strncmp (line, STR_DLNAME, sizeof (STR_DLNAME) - 1) == 0) - { - errors += trim (&dlname, &line[sizeof (STR_DLNAME) - 1]); - } - -#undef STR_OLD_LIBRARY -#define STR_OLD_LIBRARY "old_library=" - else if (strncmp (line, STR_OLD_LIBRARY, - sizeof (STR_OLD_LIBRARY) - 1) == 0) - { - errors += trim (&old_name, &line[sizeof (STR_OLD_LIBRARY) - 1]); - } -#undef STR_LIBDIR -#define STR_LIBDIR "libdir=" - else if (strncmp (line, STR_LIBDIR, sizeof (STR_LIBDIR) - 1) == 0) - { - errors += trim (&libdir, &line[sizeof(STR_LIBDIR) - 1]); - } - -#undef STR_DL_DEPLIBS -#define STR_DL_DEPLIBS "dependency_libs=" - else if (strncmp (line, STR_DL_DEPLIBS, - sizeof (STR_DL_DEPLIBS) - 1) == 0) - { - errors += trim (&deplibs, &line[sizeof (STR_DL_DEPLIBS) - 1]); - } - else if (strcmp (line, "installed=yes\n") == 0) - { - installed = 1; - } - else if (strcmp (line, "installed=no\n") == 0) - { - installed = 0; - } - -#undef STR_LIBRARY_NAMES -#define STR_LIBRARY_NAMES "library_names=" - else if (! dlname && strncmp (line, STR_LIBRARY_NAMES, - sizeof (STR_LIBRARY_NAMES) - 1) == 0) - { - char *last_libname; - errors += trim (&dlname, &line[sizeof (STR_LIBRARY_NAMES) - 1]); - if (!errors - && dlname - && (last_libname = strrchr (dlname, ' ')) != 0) - { - last_libname = lt_estrdup (last_libname + 1); - if (!last_libname) - { - ++errors; - goto cleanup; - } - LT_DLMEM_REASSIGN (dlname, last_libname); - } - } - - if (errors) - break; - } - - fclose (file); - LT_DLFREE (line); - - /* allocate the handle */ - *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1); - if (*phandle == 0) - ++errors; - - if (errors) - { - free_vars (dlname, old_name, libdir, deplibs); - LT_DLFREE (*phandle); - goto cleanup; - } - - assert (*phandle); - - memset (*phandle, 0, sizeof(struct lt_dlhandle_struct)); - if (load_deplibs (*phandle, deplibs) == 0) - { - newhandle = *phandle; - /* find_module may replace newhandle */ - if (find_module (&newhandle, dir, libdir, dlname, old_name, installed)) - { - unload_deplibs (*phandle); - ++errors; - } - } - else - { - ++errors; - } - - free_vars (dlname, old_name, libdir, deplibs); - if (errors) - { - LT_DLFREE (*phandle); - goto cleanup; - } - - if (*phandle != newhandle) - { - unload_deplibs (*phandle); - } - } - else - { - /* not a libtool module */ - *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1); - if (*phandle == 0) - { - ++errors; - goto cleanup; - } - - memset (*phandle, 0, sizeof (struct lt_dlhandle_struct)); - newhandle = *phandle; - - /* If the module has no directory name component, try to find it - first in user_search_path and then other prescribed paths. - Otherwise (or in any case if the module was not yet found) try - opening just the module name as passed. */ - if ((dir || (!find_handle (user_search_path, base_name, &newhandle) - && !find_handle (getenv (LTDL_SEARCHPATH_VAR), base_name, - &newhandle) -#ifdef LTDL_SHLIBPATH_VAR - && !find_handle (getenv (LTDL_SHLIBPATH_VAR), base_name, - &newhandle) -#endif -#ifdef LTDL_SYSSEARCHPATH - && !find_handle (sys_search_path, base_name, &newhandle) -#endif - ))) - { - if (tryall_dlopen (&newhandle, filename) != 0) - { - newhandle = NULL; - } - } - - if (!newhandle) - { - LT_DLFREE (*phandle); - ++errors; - goto cleanup; - } - } - - register_handle: - LT_DLMEM_REASSIGN (*phandle, newhandle); - - if ((*phandle)->info.ref_count == 0) - { - (*phandle)->info.ref_count = 1; - LT_DLMEM_REASSIGN ((*phandle)->info.name, name); - - LT_DLMUTEX_LOCK (); - (*phandle)->next = handles; - handles = *phandle; - LT_DLMUTEX_UNLOCK (); - } - - LT_DLMUTEX_SETERROR (saved_error); - - cleanup: - LT_DLFREE (dir); - LT_DLFREE (name); - LT_DLFREE (canonical); - - return errors; -} - -lt_dlhandle -lt_dlopen (filename) - const char *filename; -{ - lt_dlhandle handle = 0; - - /* Just incase we missed a code path in try_dlopen() that reports - an error, but forgets to reset handle... */ - if (try_dlopen (&handle, filename) != 0) - return 0; - - return handle; -} - -/* If the last error messge store was `FILE_NOT_FOUND', then return - non-zero. */ -static int -file_not_found () -{ - const char *error = 0; - - LT_DLMUTEX_GETERROR (error); - if (error == LT_DLSTRERROR (FILE_NOT_FOUND)) - return 1; - - return 0; -} - -/* If FILENAME has an ARCHIVE_EXT or SHLIB_EXT extension, try to - open the FILENAME as passed. Otherwise try appending ARCHIVE_EXT, - and if a file is still not found try again with SHLIB_EXT appended - instead. */ -lt_dlhandle -lt_dlopenext (filename) - const char *filename; -{ - lt_dlhandle handle = 0; - char * tmp = 0; - char * ext = 0; - size_t len; - int errors = 0; - - if (!filename) - { - return lt_dlopen (filename); - } - - assert (filename); - - len = LT_STRLEN (filename); - ext = strrchr (filename, '.'); - - /* If FILENAME already bears a suitable extension, there is no need - to try appending additional extensions. */ - if (ext && ((strcmp (ext, archive_ext) == 0) -#ifdef LTDL_SHLIB_EXT - || (strcmp (ext, shlib_ext) == 0) -#endif - )) - { - return lt_dlopen (filename); - } - - /* First try appending ARCHIVE_EXT. */ - tmp = LT_EMALLOC (char, len + LT_STRLEN (archive_ext) + 1); - if (!tmp) - return 0; - - strcpy (tmp, filename); - strcat (tmp, archive_ext); - errors = try_dlopen (&handle, tmp); - - /* If we found FILENAME, stop searching -- whether we were able to - load the file as a module or not. If the file exists but loading - failed, it is better to return an error message here than to - report FILE_NOT_FOUND when the alternatives (foo.so etc) are not - in the module search path. */ - if (handle || ((errors > 0) && !file_not_found ())) - { - LT_DLFREE (tmp); - return handle; - } - -#ifdef LTDL_SHLIB_EXT - /* Try appending SHLIB_EXT. */ - if (LT_STRLEN (shlib_ext) > LT_STRLEN (archive_ext)) - { - LT_DLFREE (tmp); - tmp = LT_EMALLOC (char, len + LT_STRLEN (shlib_ext) + 1); - if (!tmp) - return 0; - - strcpy (tmp, filename); - } - else - { - tmp[len] = LT_EOS_CHAR; - } - - strcat(tmp, shlib_ext); - errors = try_dlopen (&handle, tmp); - - /* As before, if the file was found but loading failed, return now - with the current error message. */ - if (handle || ((errors > 0) && !file_not_found ())) - { - LT_DLFREE (tmp); - return handle; - } -#endif - - /* Still here? Then we really did fail to locate any of the file - names we tried. */ - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); - LT_DLFREE (tmp); - return 0; -} - - -static int -lt_argz_insert (pargz, pargz_len, before, entry) - char **pargz; - size_t *pargz_len; - char *before; - const char *entry; -{ - error_t error; - - /* Prior to Sep 8, 2005, newlib had a bug where argz_insert(pargz, - pargz_len, NULL, entry) failed with EINVAL. */ - if (before) - error = argz_insert (pargz, pargz_len, before, entry); - else - error = argz_append (pargz, pargz_len, entry, 1 + LT_STRLEN (entry)); - - if (error) - { - switch (error) - { - case ENOMEM: - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - break; - default: - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN)); - break; - } - return 1; - } - - return 0; -} - -static int -lt_argz_insertinorder (pargz, pargz_len, entry) - char **pargz; - size_t *pargz_len; - const char *entry; -{ - char *before = 0; - - assert (pargz); - assert (pargz_len); - assert (entry && *entry); - - if (*pargz) - while ((before = argz_next (*pargz, *pargz_len, before))) - { - int cmp = strcmp (entry, before); - - if (cmp < 0) break; - if (cmp == 0) return 0; /* No duplicates! */ - } - - return lt_argz_insert (pargz, pargz_len, before, entry); -} - -static int -lt_argz_insertdir (pargz, pargz_len, dirnam, dp) - char **pargz; - size_t *pargz_len; - const char *dirnam; - struct dirent *dp; -{ - char *buf = 0; - size_t buf_len = 0; - char *end = 0; - size_t end_offset = 0; - size_t dir_len = 0; - int errors = 0; - - assert (pargz); - assert (pargz_len); - assert (dp); - - dir_len = LT_STRLEN (dirnam); - end = dp->d_name + LT_D_NAMLEN(dp); - - /* Ignore version numbers. */ - { - char *p; - for (p = end; p -1 > dp->d_name; --p) - if (strchr (".0123456789", p[-1]) == 0) - break; - - if (*p == '.') - end = p; - } - - /* Ignore filename extension. */ - { - char *p; - for (p = end -1; p > dp->d_name; --p) - if (*p == '.') - { - end = p; - break; - } - } - - /* Prepend the directory name. */ - end_offset = end - dp->d_name; - buf_len = dir_len + 1+ end_offset; - buf = LT_EMALLOC (char, 1+ buf_len); - if (!buf) - return ++errors; - - assert (buf); - - strcpy (buf, dirnam); - strcat (buf, "/"); - strncat (buf, dp->d_name, end_offset); - buf[buf_len] = LT_EOS_CHAR; - - /* Try to insert (in order) into ARGZ/ARGZ_LEN. */ - if (lt_argz_insertinorder (pargz, pargz_len, buf) != 0) - ++errors; - - LT_DLFREE (buf); - - return errors; -} - -static int -list_files_by_dir (dirnam, pargz, pargz_len) - const char *dirnam; - char **pargz; - size_t *pargz_len; -{ - DIR *dirp = 0; - int errors = 0; - - assert (dirnam && *dirnam); - assert (pargz); - assert (pargz_len); - assert (dirnam[LT_STRLEN(dirnam) -1] != '/'); - - dirp = opendir (dirnam); - if (dirp) - { - struct dirent *dp = 0; - - while ((dp = readdir (dirp))) - if (dp->d_name[0] != '.') - if (lt_argz_insertdir (pargz, pargz_len, dirnam, dp)) - { - ++errors; - break; - } - - closedir (dirp); - } - else - ++errors; - - return errors; -} - - -/* If there are any files in DIRNAME, call the function passed in - DATA1 (with the name of each file and DATA2 as arguments). */ -static int -foreachfile_callback (dirname, data1, data2) - char *dirname; - lt_ptr data1; - lt_ptr data2; -{ - int (*func) LT_PARAMS((const char *filename, lt_ptr data)) - = (int (*) LT_PARAMS((const char *filename, lt_ptr data))) data1; - - int is_done = 0; - char *argz = 0; - size_t argz_len = 0; - - if (list_files_by_dir (dirname, &argz, &argz_len) != 0) - goto cleanup; - if (!argz) - goto cleanup; - - { - char *filename = 0; - while ((filename = argz_next (argz, argz_len, filename))) - if ((is_done = (*func) (filename, data2))) - break; - } - - cleanup: - LT_DLFREE (argz); - - return is_done; -} - - -/* Call FUNC for each unique extensionless file in SEARCH_PATH, along - with DATA. The filenames passed to FUNC would be suitable for - passing to lt_dlopenext. The extensions are stripped so that - individual modules do not generate several entries (e.g. libfoo.la, - libfoo.so, libfoo.so.1, libfoo.so.1.0.0). If SEARCH_PATH is NULL, - then the same directories that lt_dlopen would search are examined. */ -int -lt_dlforeachfile (search_path, func, data) - const char *search_path; - int (*func) LT_PARAMS ((const char *filename, lt_ptr data)); - lt_ptr data; -{ - int is_done = 0; - - if (search_path) - { - /* If a specific path was passed, search only the directories - listed in it. */ - is_done = foreach_dirinpath (search_path, 0, - foreachfile_callback, func, data); - } - else - { - /* Otherwise search the default paths. */ - is_done = foreach_dirinpath (user_search_path, 0, - foreachfile_callback, func, data); - if (!is_done) - { - is_done = foreach_dirinpath (getenv("LTDL_LIBRARY_PATH"), 0, - foreachfile_callback, func, data); - } - -#ifdef LTDL_SHLIBPATH_VAR - if (!is_done) - { - is_done = foreach_dirinpath (getenv(LTDL_SHLIBPATH_VAR), 0, - foreachfile_callback, func, data); - } -#endif -#ifdef LTDL_SYSSEARCHPATH - if (!is_done) - { - is_done = foreach_dirinpath (getenv(LTDL_SYSSEARCHPATH), 0, - foreachfile_callback, func, data); - } -#endif - } - - return is_done; -} - -int -lt_dlclose (handle) - lt_dlhandle handle; -{ - lt_dlhandle cur, last; - int errors = 0; - - LT_DLMUTEX_LOCK (); - - /* check whether the handle is valid */ - last = cur = handles; - while (cur && handle != cur) - { - last = cur; - cur = cur->next; - } - - if (!cur) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); - ++errors; - goto done; - } - - handle->info.ref_count--; - - /* Note that even with resident modules, we must track the ref_count - correctly incase the user decides to reset the residency flag - later (even though the API makes no provision for that at the - moment). */ - if (handle->info.ref_count <= 0 && !LT_DLIS_RESIDENT (handle)) - { - lt_user_data data = handle->loader->dlloader_data; - - if (handle != handles) - { - last->next = handle->next; - } - else - { - handles = handle->next; - } - - errors += handle->loader->module_close (data, handle->module); - errors += unload_deplibs(handle); - - /* It is up to the callers to free the data itself. */ - LT_DLFREE (handle->caller_data); - - LT_DLFREE (handle->info.filename); - LT_DLFREE (handle->info.name); - LT_DLFREE (handle); - - goto done; - } - - if (LT_DLIS_RESIDENT (handle)) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CLOSE_RESIDENT_MODULE)); - ++errors; - } - - done: - LT_DLMUTEX_UNLOCK (); - - return errors; -} - -lt_ptr -lt_dlsym (handle, symbol) - lt_dlhandle handle; - const char *symbol; -{ - size_t lensym; - char lsym[LT_SYMBOL_LENGTH]; - char *sym; - lt_ptr address; - lt_user_data data; - - if (!handle) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); - return 0; - } - - if (!symbol) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); - return 0; - } - - lensym = LT_STRLEN (symbol) + LT_STRLEN (handle->loader->sym_prefix) - + LT_STRLEN (handle->info.name); - - if (lensym + LT_SYMBOL_OVERHEAD < LT_SYMBOL_LENGTH) - { - sym = lsym; - } - else - { - sym = LT_EMALLOC (char, lensym + LT_SYMBOL_OVERHEAD + 1); - if (!sym) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (BUFFER_OVERFLOW)); - return 0; - } - } - - data = handle->loader->dlloader_data; - if (handle->info.name) - { - const char *saved_error; - - LT_DLMUTEX_GETERROR (saved_error); - - /* this is a libtool module */ - if (handle->loader->sym_prefix) - { - strcpy(sym, handle->loader->sym_prefix); - strcat(sym, handle->info.name); - } - else - { - strcpy(sym, handle->info.name); - } - - strcat(sym, "_LTX_"); - strcat(sym, symbol); - - /* try "modulename_LTX_symbol" */ - address = handle->loader->find_sym (data, handle->module, sym); - if (address) - { - if (sym != lsym) - { - LT_DLFREE (sym); - } - return address; - } - LT_DLMUTEX_SETERROR (saved_error); - } - - /* otherwise try "symbol" */ - if (handle->loader->sym_prefix) - { - strcpy(sym, handle->loader->sym_prefix); - strcat(sym, symbol); - } - else - { - strcpy(sym, symbol); - } - - address = handle->loader->find_sym (data, handle->module, sym); - if (sym != lsym) - { - LT_DLFREE (sym); - } - - return address; -} - -const char * -lt_dlerror () -{ - const char *error; - - LT_DLMUTEX_GETERROR (error); - LT_DLMUTEX_SETERROR (0); - - return error ? error : NULL; -} - -static int -lt_dlpath_insertdir (ppath, before, dir) - char **ppath; - char *before; - const char *dir; -{ - int errors = 0; - char *canonical = 0; - char *argz = 0; - size_t argz_len = 0; - - assert (ppath); - assert (dir && *dir); - - if (canonicalize_path (dir, &canonical) != 0) - { - ++errors; - goto cleanup; - } - - assert (canonical && *canonical); - - /* If *PPATH is empty, set it to DIR. */ - if (*ppath == 0) - { - assert (!before); /* BEFORE cannot be set without PPATH. */ - assert (dir); /* Without DIR, don't call this function! */ - - *ppath = lt_estrdup (dir); - if (*ppath == 0) - ++errors; - - return errors; - } - - assert (ppath && *ppath); - - if (argzize_path (*ppath, &argz, &argz_len) != 0) - { - ++errors; - goto cleanup; - } - - /* Convert BEFORE into an equivalent offset into ARGZ. This only works - if *PPATH is already canonicalized, and hence does not change length - with respect to ARGZ. We canonicalize each entry as it is added to - the search path, and don't call this function with (uncanonicalized) - user paths, so this is a fair assumption. */ - if (before) - { - assert (*ppath <= before); - assert (before - *ppath <= strlen (*ppath)); - - before = before - *ppath + argz; - } - - if (lt_argz_insert (&argz, &argz_len, before, dir) != 0) - { - ++errors; - goto cleanup; - } - - argz_stringify (argz, argz_len, LT_PATHSEP_CHAR); - LT_DLMEM_REASSIGN (*ppath, argz); - - cleanup: - LT_DLFREE (canonical); - LT_DLFREE (argz); - - return errors; -} - -int -lt_dladdsearchdir (search_dir) - const char *search_dir; -{ - int errors = 0; - - if (search_dir && *search_dir) - { - LT_DLMUTEX_LOCK (); - if (lt_dlpath_insertdir (&user_search_path, 0, search_dir) != 0) - ++errors; - LT_DLMUTEX_UNLOCK (); - } - - return errors; -} - -int -lt_dlinsertsearchdir (before, search_dir) - const char *before; - const char *search_dir; -{ - int errors = 0; - - if (before) - { - LT_DLMUTEX_LOCK (); - if ((before < user_search_path) - || (before >= user_search_path + LT_STRLEN (user_search_path))) - { - LT_DLMUTEX_UNLOCK (); - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_POSITION)); - return 1; - } - LT_DLMUTEX_UNLOCK (); - } - - if (search_dir && *search_dir) - { - LT_DLMUTEX_LOCK (); - if (lt_dlpath_insertdir (&user_search_path, - (char *) before, search_dir) != 0) - { - ++errors; - } - LT_DLMUTEX_UNLOCK (); - } - - return errors; -} - -int -lt_dlsetsearchpath (search_path) - const char *search_path; -{ - int errors = 0; - - LT_DLMUTEX_LOCK (); - LT_DLFREE (user_search_path); - LT_DLMUTEX_UNLOCK (); - - if (!search_path || !LT_STRLEN (search_path)) - { - return errors; - } - - LT_DLMUTEX_LOCK (); - if (canonicalize_path (search_path, &user_search_path) != 0) - ++errors; - LT_DLMUTEX_UNLOCK (); - - return errors; -} - -const char * -lt_dlgetsearchpath () -{ - const char *saved_path; - - LT_DLMUTEX_LOCK (); - saved_path = user_search_path; - LT_DLMUTEX_UNLOCK (); - - return saved_path; -} - -int -lt_dlmakeresident (handle) - lt_dlhandle handle; -{ - int errors = 0; - - if (!handle) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); - ++errors; - } - else - { - LT_DLSET_FLAG (handle, LT_DLRESIDENT_FLAG); - } - - return errors; -} - -int -lt_dlisresident (handle) - lt_dlhandle handle; -{ - if (!handle) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); - return -1; - } - - return LT_DLIS_RESIDENT (handle); -} - - - - -/* --- MODULE INFORMATION --- */ - -const lt_dlinfo * -lt_dlgetinfo (handle) - lt_dlhandle handle; -{ - if (!handle) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); - return 0; - } - - return &(handle->info); -} - -lt_dlhandle -lt_dlhandle_next (place) - lt_dlhandle place; -{ - return place ? place->next : handles; -} - -int -lt_dlforeach (func, data) - int (*func) LT_PARAMS((lt_dlhandle handle, lt_ptr data)); - lt_ptr data; -{ - int errors = 0; - lt_dlhandle cur; - - LT_DLMUTEX_LOCK (); - - cur = handles; - while (cur) - { - lt_dlhandle tmp = cur; - - cur = cur->next; - if ((*func) (tmp, data)) - { - ++errors; - break; - } - } - - LT_DLMUTEX_UNLOCK (); - - return errors; -} - -lt_dlcaller_id -lt_dlcaller_register () -{ - static lt_dlcaller_id last_caller_id = 0; - int result; - - LT_DLMUTEX_LOCK (); - result = ++last_caller_id; - LT_DLMUTEX_UNLOCK (); - - return result; -} - -lt_ptr -lt_dlcaller_set_data (key, handle, data) - lt_dlcaller_id key; - lt_dlhandle handle; - lt_ptr data; -{ - int n_elements = 0; - lt_ptr stale = (lt_ptr) 0; - int i; - - /* This needs to be locked so that the caller data can be updated - simultaneously by different threads. */ - LT_DLMUTEX_LOCK (); - - if (handle->caller_data) - while (handle->caller_data[n_elements].key) - ++n_elements; - - for (i = 0; i < n_elements; ++i) - { - if (handle->caller_data[i].key == key) - { - stale = handle->caller_data[i].data; - break; - } - } - - /* Ensure that there is enough room in this handle's caller_data - array to accept a new element (and an empty end marker). */ - if (i == n_elements) - { - lt_caller_data *temp - = LT_DLREALLOC (lt_caller_data, handle->caller_data, 2+ n_elements); - - if (!temp) - { - stale = 0; - goto done; - } - - handle->caller_data = temp; - - /* We only need this if we needed to allocate a new caller_data. */ - handle->caller_data[i].key = key; - handle->caller_data[1+ i].key = 0; - } - - handle->caller_data[i].data = data; - - done: - LT_DLMUTEX_UNLOCK (); - - return stale; -} - -lt_ptr -lt_dlcaller_get_data (key, handle) - lt_dlcaller_id key; - lt_dlhandle handle; -{ - lt_ptr result = (lt_ptr) 0; - - /* This needs to be locked so that the caller data isn't updated by - another thread part way through this function. */ - LT_DLMUTEX_LOCK (); - - /* Locate the index of the element with a matching KEY. */ - { - int i; - for (i = 0; handle->caller_data[i].key; ++i) - { - if (handle->caller_data[i].key == key) - { - result = handle->caller_data[i].data; - break; - } - } - } - - LT_DLMUTEX_UNLOCK (); - - return result; -} - - - -/* --- USER MODULE LOADER API --- */ - - -int -lt_dlloader_add (place, dlloader, loader_name) - lt_dlloader *place; - const struct lt_user_dlloader *dlloader; - const char *loader_name; -{ - int errors = 0; - lt_dlloader *node = 0, *ptr = 0; - - if ((dlloader == 0) /* diagnose null parameters */ - || (dlloader->module_open == 0) - || (dlloader->module_close == 0) - || (dlloader->find_sym == 0)) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); - return 1; - } - - /* Create a new dlloader node with copies of the user callbacks. */ - node = LT_EMALLOC (lt_dlloader, 1); - if (!node) - return 1; - - node->next = 0; - node->loader_name = loader_name; - node->sym_prefix = dlloader->sym_prefix; - node->dlloader_exit = dlloader->dlloader_exit; - node->module_open = dlloader->module_open; - node->module_close = dlloader->module_close; - node->find_sym = dlloader->find_sym; - node->dlloader_data = dlloader->dlloader_data; - - LT_DLMUTEX_LOCK (); - if (!loaders) - { - /* If there are no loaders, NODE becomes the list! */ - loaders = node; - } - else if (!place) - { - /* If PLACE is not set, add NODE to the end of the - LOADERS list. */ - for (ptr = loaders; ptr->next; ptr = ptr->next) - { - /*NOWORK*/; - } - - ptr->next = node; - } - else if (loaders == place) - { - /* If PLACE is the first loader, NODE goes first. */ - node->next = place; - loaders = node; - } - else - { - /* Find the node immediately preceding PLACE. */ - for (ptr = loaders; ptr->next != place; ptr = ptr->next) - { - /*NOWORK*/; - } - - if (ptr->next != place) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); - ++errors; - } - else - { - /* Insert NODE between PTR and PLACE. */ - node->next = place; - ptr->next = node; - } - } - - LT_DLMUTEX_UNLOCK (); - - return errors; -} - -int -lt_dlloader_remove (loader_name) - const char *loader_name; -{ - lt_dlloader *place = lt_dlloader_find (loader_name); - lt_dlhandle handle; - int errors = 0; - - if (!place) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); - return 1; - } - - LT_DLMUTEX_LOCK (); - - /* Fail if there are any open modules which use this loader. */ - for (handle = handles; handle; handle = handle->next) - { - if (handle->loader == place) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (REMOVE_LOADER)); - ++errors; - goto done; - } - } - - if (place == loaders) - { - /* PLACE is the first loader in the list. */ - loaders = loaders->next; - } - else - { - /* Find the loader before the one being removed. */ - lt_dlloader *prev; - for (prev = loaders; prev->next; prev = prev->next) - { - if (!strcmp (prev->next->loader_name, loader_name)) - { - break; - } - } - - place = prev->next; - prev->next = prev->next->next; - } - - if (place->dlloader_exit) - { - errors = place->dlloader_exit (place->dlloader_data); - } - - LT_DLFREE (place); - - done: - LT_DLMUTEX_UNLOCK (); - - return errors; -} - -lt_dlloader * -lt_dlloader_next (place) - lt_dlloader *place; -{ - lt_dlloader *next; - - LT_DLMUTEX_LOCK (); - next = place ? place->next : loaders; - LT_DLMUTEX_UNLOCK (); - - return next; -} - -const char * -lt_dlloader_name (place) - lt_dlloader *place; -{ - const char *name = 0; - - if (place) - { - LT_DLMUTEX_LOCK (); - name = place ? place->loader_name : 0; - LT_DLMUTEX_UNLOCK (); - } - else - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); - } - - return name; -} - -lt_user_data * -lt_dlloader_data (place) - lt_dlloader *place; -{ - lt_user_data *data = 0; - - if (place) - { - LT_DLMUTEX_LOCK (); - data = place ? &(place->dlloader_data) : 0; - LT_DLMUTEX_UNLOCK (); - } - else - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); - } - - return data; -} - -lt_dlloader * -lt_dlloader_find (loader_name) - const char *loader_name; -{ - lt_dlloader *place = 0; - - LT_DLMUTEX_LOCK (); - for (place = loaders; place; place = place->next) - { - if (strcmp (place->loader_name, loader_name) == 0) - { - break; - } - } - LT_DLMUTEX_UNLOCK (); - - return place; -} diff --git a/libltdl/ltdl.h b/libltdl/ltdl.h deleted file mode 100644 index 1f2b9716..00000000 --- a/libltdl/ltdl.h +++ /dev/null @@ -1,367 +0,0 @@ -/* ltdl.h -- generic dlopen functions - Copyright (C) 1998-2001, 2003, 2004, 2007 Free Software Foundation, Inc. - Originally by Thomas Tanner - This file is part of GNU Libtool. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2 of the License, or (at your option) any later version. - -As a special exception to the GNU Lesser General Public License, -if you distribute this file as part of a program or library that -is built using GNU libtool, you may include it under the same -distribution terms that you use for the rest of that program. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free -Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA -*/ - -/* Only include this header file once. */ -#ifndef LTDL_H -#define LTDL_H 1 - -#include /* for size_t declaration */ - - -/* --- MACROS FOR PORTABILITY --- */ - - -/* Saves on those hard to debug '\0' typos.... */ -#define LT_EOS_CHAR '\0' - -/* LTDL_BEGIN_C_DECLS should be used at the beginning of your declarations, - so that C++ compilers don't mangle their names. Use LTDL_END_C_DECLS at - the end of C declarations. */ -#ifdef __cplusplus -# define LT_BEGIN_C_DECLS extern "C" { -# define LT_END_C_DECLS } -#else -# define LT_BEGIN_C_DECLS /* empty */ -# define LT_END_C_DECLS /* empty */ -#endif - -LT_BEGIN_C_DECLS - - -/* LT_PARAMS is a macro used to wrap function prototypes, so that compilers - that don't understand ANSI C prototypes still work, and ANSI C - compilers can issue warnings about type mismatches. */ -#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(WIN32) || defined(__cplusplus) -# define LT_PARAMS(protos) protos -# define lt_ptr void* -#else -# define LT_PARAMS(protos) () -# define lt_ptr char* -#endif - -/* LT_STMT_START/END are used to create macros which expand to a - a single compound statement in a portable way. */ -#if defined (__GNUC__) && !defined (__STRICT_ANSI__) && !defined (__cplusplus) -# define LT_STMT_START (void)( -# define LT_STMT_END ) -#else -# if (defined (sun) || defined (__sun__)) -# define LT_STMT_START if (1) -# define LT_STMT_END else (void)0 -# else -# define LT_STMT_START do -# define LT_STMT_END while (0) -# endif -#endif - -/* LT_CONC creates a new concatenated symbol for the compiler - in a portable way. */ -#if defined(__STDC__) || defined(__cplusplus) || defined(_MSC_VER) || defined(_AIX) -# define LT_CONC(s,t) s##t -#else -# define LT_CONC(s,t) s/**/t -#endif - -/* LT_STRLEN can be used safely on NULL pointers. */ -#define LT_STRLEN(s) (((s) && (s)[0]) ? strlen (s) : 0) - - - -/* --- WINDOWS SUPPORT --- */ - - -/* Canonicalise Windows and Cygwin recognition macros. */ -#ifdef __CYGWIN32__ -# ifndef __CYGWIN__ -# define __CYGWIN__ __CYGWIN32__ -# endif -#endif -#if defined(_WIN32) || defined(WIN32) -# ifndef __WINDOWS__ -# ifdef _WIN32 -# define __WINDOWS__ _WIN32 -# else -# ifdef WIN32 -# define __WINDOWS__ WIN32 -# endif -# endif -# endif -#endif - - -#ifdef __WINDOWS__ -# ifndef __CYGWIN__ -/* LT_DIRSEP_CHAR is accepted *in addition* to '/' as a directory - separator when it is set. */ -# define LT_DIRSEP_CHAR '\\' -# define LT_PATHSEP_CHAR ';' -# endif -#endif -#ifndef LT_PATHSEP_CHAR -# define LT_PATHSEP_CHAR ':' -#endif - -/* DLL building support on win32 hosts; mostly to workaround their - ridiculous implementation of data symbol exporting. */ -#ifndef LT_SCOPE -# if defined(__WINDOWS__) || defined(__CYGWIN__) -# ifdef DLL_EXPORT /* defined by libtool (if required) */ -# define LT_SCOPE __declspec(dllexport) -# endif -# ifdef LIBLTDL_DLL_IMPORT /* define if linking with this dll */ - /* note: cygwin/mingw compilers can rely instead on auto-import */ -# define LT_SCOPE extern __declspec(dllimport) -# endif -# endif -# ifndef LT_SCOPE /* static linking or !__WINDOWS__ */ -# define LT_SCOPE extern -# endif -#endif - - -#if defined(_MSC_VER) /* Visual Studio */ -# define R_OK 4 -#endif - - - -/* --- DYNAMIC MODULE LOADING API --- */ - - -typedef struct lt_dlhandle_struct *lt_dlhandle; /* A loaded module. */ - -/* Initialisation and finalisation functions for libltdl. */ -LT_SCOPE int lt_dlinit LT_PARAMS((void)); -LT_SCOPE int lt_dlexit LT_PARAMS((void)); - -/* Module search path manipulation. */ -LT_SCOPE int lt_dladdsearchdir LT_PARAMS((const char *search_dir)); -LT_SCOPE int lt_dlinsertsearchdir LT_PARAMS((const char *before, - const char *search_dir)); -LT_SCOPE int lt_dlsetsearchpath LT_PARAMS((const char *search_path)); -LT_SCOPE const char *lt_dlgetsearchpath LT_PARAMS((void)); -LT_SCOPE int lt_dlforeachfile LT_PARAMS(( - const char *search_path, - int (*func) (const char *filename, lt_ptr data), - lt_ptr data)); - -/* Portable libltdl versions of the system dlopen() API. */ -LT_SCOPE lt_dlhandle lt_dlopen LT_PARAMS((const char *filename)); -LT_SCOPE lt_dlhandle lt_dlopenext LT_PARAMS((const char *filename)); -LT_SCOPE lt_ptr lt_dlsym LT_PARAMS((lt_dlhandle handle, - const char *name)); -LT_SCOPE const char *lt_dlerror LT_PARAMS((void)); -LT_SCOPE int lt_dlclose LT_PARAMS((lt_dlhandle handle)); - -/* Module residency management. */ -LT_SCOPE int lt_dlmakeresident LT_PARAMS((lt_dlhandle handle)); -LT_SCOPE int lt_dlisresident LT_PARAMS((lt_dlhandle handle)); - - - - -/* --- MUTEX LOCKING --- */ - - -typedef void lt_dlmutex_lock LT_PARAMS((void)); -typedef void lt_dlmutex_unlock LT_PARAMS((void)); -typedef void lt_dlmutex_seterror LT_PARAMS((const char *errmsg)); -typedef const char *lt_dlmutex_geterror LT_PARAMS((void)); - -LT_SCOPE int lt_dlmutex_register LT_PARAMS((lt_dlmutex_lock *lock, - lt_dlmutex_unlock *unlock, - lt_dlmutex_seterror *seterror, - lt_dlmutex_geterror *geterror)); - - - - -/* --- MEMORY HANDLING --- */ - - -/* By default, the realloc function pointer is set to our internal - realloc implementation which iself uses lt_dlmalloc and lt_dlfree. - libltdl relies on a featureful realloc, but if you are sure yours - has the right semantics then you can assign it directly. Generally, - it is safe to assign just a malloc() and a free() function. */ -LT_SCOPE lt_ptr (*lt_dlmalloc) LT_PARAMS((size_t size)); -LT_SCOPE lt_ptr (*lt_dlrealloc) LT_PARAMS((lt_ptr ptr, size_t size)); -LT_SCOPE void (*lt_dlfree) LT_PARAMS((lt_ptr ptr)); - - - - -/* --- PRELOADED MODULE SUPPORT --- */ - - -/* A preopened symbol. Arrays of this type comprise the exported - symbols for a dlpreopened module. */ -typedef struct { - const char *name; - lt_ptr address; -} lt_dlsymlist; - -LT_SCOPE int lt_dlpreload LT_PARAMS((const lt_dlsymlist *preloaded)); -LT_SCOPE int lt_dlpreload_default - LT_PARAMS((const lt_dlsymlist *preloaded)); - -#define LTDL_SET_PRELOADED_SYMBOLS() LT_STMT_START{ \ - extern const lt_dlsymlist lt_preloaded_symbols[]; \ - lt_dlpreload_default(lt_preloaded_symbols); \ - }LT_STMT_END - - - - -/* --- MODULE INFORMATION --- */ - - -/* Read only information pertaining to a loaded module. */ -typedef struct { - char *filename; /* file name */ - char *name; /* module name */ - int ref_count; /* number of times lt_dlopened minus - number of times lt_dlclosed. */ -} lt_dlinfo; - -LT_SCOPE const lt_dlinfo *lt_dlgetinfo LT_PARAMS((lt_dlhandle handle)); -LT_SCOPE lt_dlhandle lt_dlhandle_next LT_PARAMS((lt_dlhandle place)); -LT_SCOPE int lt_dlforeach LT_PARAMS(( - int (*func) (lt_dlhandle handle, lt_ptr data), - lt_ptr data)); - -/* Associating user data with loaded modules. */ -typedef unsigned lt_dlcaller_id; - -LT_SCOPE lt_dlcaller_id lt_dlcaller_register LT_PARAMS((void)); -LT_SCOPE lt_ptr lt_dlcaller_set_data LT_PARAMS((lt_dlcaller_id key, - lt_dlhandle handle, - lt_ptr data)); -LT_SCOPE lt_ptr lt_dlcaller_get_data LT_PARAMS((lt_dlcaller_id key, - lt_dlhandle handle)); - - - -/* --- USER MODULE LOADER API --- */ - - -typedef struct lt_dlloader lt_dlloader; -typedef lt_ptr lt_user_data; -typedef lt_ptr lt_module; - -/* Function pointer types for creating user defined module loaders. */ -typedef lt_module lt_module_open LT_PARAMS((lt_user_data loader_data, - const char *filename)); -typedef int lt_module_close LT_PARAMS((lt_user_data loader_data, - lt_module handle)); -typedef lt_ptr lt_find_sym LT_PARAMS((lt_user_data loader_data, - lt_module handle, - const char *symbol)); -typedef int lt_dlloader_exit LT_PARAMS((lt_user_data loader_data)); - -struct lt_user_dlloader { - const char *sym_prefix; - lt_module_open *module_open; - lt_module_close *module_close; - lt_find_sym *find_sym; - lt_dlloader_exit *dlloader_exit; - lt_user_data dlloader_data; -}; - -LT_SCOPE lt_dlloader *lt_dlloader_next LT_PARAMS((lt_dlloader *place)); -LT_SCOPE lt_dlloader *lt_dlloader_find LT_PARAMS(( - const char *loader_name)); -LT_SCOPE const char *lt_dlloader_name LT_PARAMS((lt_dlloader *place)); -LT_SCOPE lt_user_data *lt_dlloader_data LT_PARAMS((lt_dlloader *place)); -LT_SCOPE int lt_dlloader_add LT_PARAMS((lt_dlloader *place, - const struct lt_user_dlloader *dlloader, - const char *loader_name)); -LT_SCOPE int lt_dlloader_remove LT_PARAMS(( - const char *loader_name)); - - - -/* --- ERROR MESSAGE HANDLING --- */ - - -/* Defining error strings alongside their symbolic names in a macro in - this way allows us to expand the macro in different contexts with - confidence that the enumeration of symbolic names will map correctly - onto the table of error strings. */ -#define lt_dlerror_table \ - LT_ERROR(UNKNOWN, "unknown error") \ - LT_ERROR(DLOPEN_NOT_SUPPORTED, "dlopen support not available") \ - LT_ERROR(INVALID_LOADER, "invalid loader") \ - LT_ERROR(INIT_LOADER, "loader initialization failed") \ - LT_ERROR(REMOVE_LOADER, "loader removal failed") \ - LT_ERROR(FILE_NOT_FOUND, "file not found") \ - LT_ERROR(DEPLIB_NOT_FOUND, "dependency library not found") \ - LT_ERROR(NO_SYMBOLS, "no symbols defined") \ - LT_ERROR(CANNOT_OPEN, "can't open the module") \ - LT_ERROR(CANNOT_CLOSE, "can't close the module") \ - LT_ERROR(SYMBOL_NOT_FOUND, "symbol not found") \ - LT_ERROR(NO_MEMORY, "not enough memory") \ - LT_ERROR(INVALID_HANDLE, "invalid module handle") \ - LT_ERROR(BUFFER_OVERFLOW, "internal buffer overflow") \ - LT_ERROR(INVALID_ERRORCODE, "invalid errorcode") \ - LT_ERROR(SHUTDOWN, "library already shutdown") \ - LT_ERROR(CLOSE_RESIDENT_MODULE, "can't close resident module") \ - LT_ERROR(INVALID_MUTEX_ARGS, "invalid mutex handler registration") \ - LT_ERROR(INVALID_POSITION, "invalid search path insert position") - -/* Enumerate the symbolic error names. */ -enum { -#define LT_ERROR(name, diagnostic) LT_CONC(LT_ERROR_, name), - lt_dlerror_table -#undef LT_ERROR - - LT_ERROR_MAX -}; - -/* These functions are only useful from inside custom module loaders. */ -LT_SCOPE int lt_dladderror LT_PARAMS((const char *diagnostic)); -LT_SCOPE int lt_dlseterror LT_PARAMS((int errorcode)); - - - - -/* --- SOURCE COMPATIBILITY WITH OLD LIBLTDL --- */ - - -#ifdef LT_NON_POSIX_NAMESPACE -# define lt_ptr_t lt_ptr -# define lt_module_t lt_module -# define lt_module_open_t lt_module_open -# define lt_module_close_t lt_module_close -# define lt_find_sym_t lt_find_sym -# define lt_dlloader_exit_t lt_dlloader_exit -# define lt_dlloader_t lt_dlloader -# define lt_dlloader_data_t lt_user_data -#endif - -LT_END_C_DECLS - -#endif /* !LTDL_H */ diff --git a/libltdl/ltmain.sh b/libltdl/ltmain.sh deleted file mode 100644 index f924d309..00000000 --- a/libltdl/ltmain.sh +++ /dev/null @@ -1,6938 +0,0 @@ -# ltmain.sh - Provide generalized library-building support services. -# NOTE: Changing this file will not affect anything until you rerun configure. -# -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, -# 2007 Free Software Foundation, Inc. -# Originally by Gordon Matzigkeit , 1996 -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -basename="s,^.*/,,g" - -# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh -# is ksh but when the shell is invoked as "sh" and the current value of -# the _XPG environment variable is not equal to 1 (one), the special -# positional parameter $0, within a function call, is the name of the -# function. -progpath="$0" - -# The name of this program: -progname=`echo "$progpath" | $SED $basename` -modename="$progname" - -# Global variables: -EXIT_SUCCESS=0 -EXIT_FAILURE=1 - -PROGRAM=ltmain.sh -PACKAGE=libtool -VERSION="1.5.24 Debian 1.5.24-1" -TIMESTAMP=" (1.1220.2.456 2007/06/24 02:25:32)" - -# Be Bourne compatible (taken from Autoconf:_AS_BOURNE_COMPATIBLE). -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac -fi -BIN_SH=xpg4; export BIN_SH # for Tru64 -DUALCASE=1; export DUALCASE # for MKS sh - -# Check that we have a working $echo. -if test "X$1" = X--no-reexec; then - # Discard the --no-reexec flag, and continue. - shift -elif test "X$1" = X--fallback-echo; then - # Avoid inline document here, it may be left over - : -elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then - # Yippee, $echo works! - : -else - # Restart under the correct shell, and then maybe $echo will work. - exec $SHELL "$progpath" --no-reexec ${1+"$@"} -fi - -if test "X$1" = X--fallback-echo; then - # used as fallback echo - shift - cat <&2 - $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 - exit $EXIT_FAILURE -fi - -# Global variables. -mode=$default_mode -nonopt= -prev= -prevopt= -run= -show="$echo" -show_help= -execute_dlfiles= -duplicate_deps=no -preserve_args= -lo2o="s/\\.lo\$/.${objext}/" -o2lo="s/\\.${objext}\$/.lo/" -extracted_archives= -extracted_serial=0 - -##################################### -# Shell function definitions: -# This seems to be the best place for them - -# func_mktempdir [string] -# Make a temporary directory that won't clash with other running -# libtool processes, and avoids race conditions if possible. If -# given, STRING is the basename for that directory. -func_mktempdir () -{ - my_template="${TMPDIR-/tmp}/${1-$progname}" - - if test "$run" = ":"; then - # Return a directory name, but don't create it in dry-run mode - my_tmpdir="${my_template}-$$" - else - - # If mktemp works, use that first and foremost - my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` - - if test ! -d "$my_tmpdir"; then - # Failing that, at least try and use $RANDOM to avoid a race - my_tmpdir="${my_template}-${RANDOM-0}$$" - - save_mktempdir_umask=`umask` - umask 0077 - $mkdir "$my_tmpdir" - umask $save_mktempdir_umask - fi - - # If we're not in dry-run mode, bomb out on failure - test -d "$my_tmpdir" || { - $echo "cannot create temporary directory \`$my_tmpdir'" 1>&2 - exit $EXIT_FAILURE - } - fi - - $echo "X$my_tmpdir" | $Xsed -} - - -# func_win32_libid arg -# return the library type of file 'arg' -# -# Need a lot of goo to handle *both* DLLs and import libs -# Has to be a shell function in order to 'eat' the argument -# that is supplied when $file_magic_command is called. -func_win32_libid () -{ - win32_libid_type="unknown" - win32_fileres=`file -L $1 2>/dev/null` - case $win32_fileres in - *ar\ archive\ import\ library*) # definitely import - win32_libid_type="x86 archive import" - ;; - *ar\ archive*) # could be an import, or static - if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \ - $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then - win32_nmres=`eval $NM -f posix -A $1 | \ - $SED -n -e '1,100{ - / I /{ - s,.*,import, - p - q - } - }'` - case $win32_nmres in - import*) win32_libid_type="x86 archive import";; - *) win32_libid_type="x86 archive static";; - esac - fi - ;; - *DLL*) - win32_libid_type="x86 DLL" - ;; - *executable*) # but shell scripts are "executable" too... - case $win32_fileres in - *MS\ Windows\ PE\ Intel*) - win32_libid_type="x86 DLL" - ;; - esac - ;; - esac - $echo $win32_libid_type -} - - -# func_infer_tag arg -# Infer tagged configuration to use if any are available and -# if one wasn't chosen via the "--tag" command line option. -# Only attempt this if the compiler in the base compile -# command doesn't match the default compiler. -# arg is usually of the form 'gcc ...' -func_infer_tag () -{ - if test -n "$available_tags" && test -z "$tagname"; then - CC_quoted= - for arg in $CC; do - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - arg="\"$arg\"" - ;; - esac - CC_quoted="$CC_quoted $arg" - done - case $@ in - # Blanks in the command may have been stripped by the calling shell, - # but not from the CC environment variable when configure was run. - " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;; - # Blanks at the start of $base_compile will cause this to fail - # if we don't check for them as well. - *) - for z in $available_tags; do - if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then - # Evaluate the configuration. - eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" - CC_quoted= - for arg in $CC; do - # Double-quote args containing other shell metacharacters. - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - arg="\"$arg\"" - ;; - esac - CC_quoted="$CC_quoted $arg" - done - case "$@ " in - " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) - # The compiler in the base compile command matches - # the one in the tagged configuration. - # Assume this is the tagged configuration we want. - tagname=$z - break - ;; - esac - fi - done - # If $tagname still isn't set, then no tagged configuration - # was found and let the user know that the "--tag" command - # line option must be used. - if test -z "$tagname"; then - $echo "$modename: unable to infer tagged configuration" - $echo "$modename: specify a tag with \`--tag'" 1>&2 - exit $EXIT_FAILURE -# else -# $echo "$modename: using $tagname tagged configuration" - fi - ;; - esac - fi -} - - -# func_extract_an_archive dir oldlib -func_extract_an_archive () -{ - f_ex_an_ar_dir="$1"; shift - f_ex_an_ar_oldlib="$1" - - $show "(cd $f_ex_an_ar_dir && $AR x $f_ex_an_ar_oldlib)" - $run eval "(cd \$f_ex_an_ar_dir && $AR x \$f_ex_an_ar_oldlib)" || exit $? - if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then - : - else - $echo "$modename: ERROR: object name conflicts: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" 1>&2 - exit $EXIT_FAILURE - fi -} - -# func_extract_archives gentop oldlib ... -func_extract_archives () -{ - my_gentop="$1"; shift - my_oldlibs=${1+"$@"} - my_oldobjs="" - my_xlib="" - my_xabs="" - my_xdir="" - my_status="" - - $show "${rm}r $my_gentop" - $run ${rm}r "$my_gentop" - $show "$mkdir $my_gentop" - $run $mkdir "$my_gentop" - my_status=$? - if test "$my_status" -ne 0 && test ! -d "$my_gentop"; then - exit $my_status - fi - - for my_xlib in $my_oldlibs; do - # Extract the objects. - case $my_xlib in - [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; - *) my_xabs=`pwd`"/$my_xlib" ;; - esac - my_xlib=`$echo "X$my_xlib" | $Xsed -e 's%^.*/%%'` - my_xlib_u=$my_xlib - while :; do - case " $extracted_archives " in - *" $my_xlib_u "*) - extracted_serial=`expr $extracted_serial + 1` - my_xlib_u=lt$extracted_serial-$my_xlib ;; - *) break ;; - esac - done - extracted_archives="$extracted_archives $my_xlib_u" - my_xdir="$my_gentop/$my_xlib_u" - - $show "${rm}r $my_xdir" - $run ${rm}r "$my_xdir" - $show "$mkdir $my_xdir" - $run $mkdir "$my_xdir" - exit_status=$? - if test "$exit_status" -ne 0 && test ! -d "$my_xdir"; then - exit $exit_status - fi - case $host in - *-darwin*) - $show "Extracting $my_xabs" - # Do not bother doing anything if just a dry run - if test -z "$run"; then - darwin_orig_dir=`pwd` - cd $my_xdir || exit $? - darwin_archive=$my_xabs - darwin_curdir=`pwd` - darwin_base_archive=`$echo "X$darwin_archive" | $Xsed -e 's%^.*/%%'` - darwin_arches=`lipo -info "$darwin_archive" 2>/dev/null | $EGREP Architectures 2>/dev/null` - if test -n "$darwin_arches"; then - darwin_arches=`echo "$darwin_arches" | $SED -e 's/.*are://'` - darwin_arch= - $show "$darwin_base_archive has multiple architectures $darwin_arches" - for darwin_arch in $darwin_arches ; do - mkdir -p "unfat-$$/${darwin_base_archive}-${darwin_arch}" - lipo -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" - cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" - func_extract_an_archive "`pwd`" "${darwin_base_archive}" - cd "$darwin_curdir" - $rm "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" - done # $darwin_arches - ## Okay now we have a bunch of thin objects, gotta fatten them up :) - darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print| xargs basename | sort -u | $NL2SP` - darwin_file= - darwin_files= - for darwin_file in $darwin_filelist; do - darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` - lipo -create -output "$darwin_file" $darwin_files - done # $darwin_filelist - ${rm}r unfat-$$ - cd "$darwin_orig_dir" - else - cd "$darwin_orig_dir" - func_extract_an_archive "$my_xdir" "$my_xabs" - fi # $darwin_arches - fi # $run - ;; - *) - func_extract_an_archive "$my_xdir" "$my_xabs" - ;; - esac - my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` - done - func_extract_archives_result="$my_oldobjs" -} -# End of Shell function definitions -##################################### - -# Darwin sucks -eval std_shrext=\"$shrext_cmds\" - -disable_libs=no - -# Parse our command line options once, thoroughly. -while test "$#" -gt 0 -do - arg="$1" - shift - - case $arg in - -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; - *) optarg= ;; - esac - - # If the previous option needs an argument, assign it. - if test -n "$prev"; then - case $prev in - execute_dlfiles) - execute_dlfiles="$execute_dlfiles $arg" - ;; - tag) - tagname="$arg" - preserve_args="${preserve_args}=$arg" - - # Check whether tagname contains only valid characters - case $tagname in - *[!-_A-Za-z0-9,/]*) - $echo "$progname: invalid tag name: $tagname" 1>&2 - exit $EXIT_FAILURE - ;; - esac - - case $tagname in - CC) - # Don't test for the "default" C tag, as we know, it's there, but - # not specially marked. - ;; - *) - if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then - taglist="$taglist $tagname" - # Evaluate the configuration. - eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`" - else - $echo "$progname: ignoring unknown tag $tagname" 1>&2 - fi - ;; - esac - ;; - *) - eval "$prev=\$arg" - ;; - esac - - prev= - prevopt= - continue - fi - - # Have we seen a non-optional argument yet? - case $arg in - --help) - show_help=yes - ;; - - --version) - echo "\ -$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP - -Copyright (C) 2007 Free Software Foundation, Inc. -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - exit $? - ;; - - --config) - ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath - # Now print the configurations for the tags. - for tagname in $taglist; do - ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath" - done - exit $? - ;; - - --debug) - $echo "$progname: enabling shell trace mode" - set -x - preserve_args="$preserve_args $arg" - ;; - - --dry-run | -n) - run=: - ;; - - --features) - $echo "host: $host" - if test "$build_libtool_libs" = yes; then - $echo "enable shared libraries" - else - $echo "disable shared libraries" - fi - if test "$build_old_libs" = yes; then - $echo "enable static libraries" - else - $echo "disable static libraries" - fi - exit $? - ;; - - --finish) mode="finish" ;; - - --mode) prevopt="--mode" prev=mode ;; - --mode=*) mode="$optarg" ;; - - --preserve-dup-deps) duplicate_deps="yes" ;; - - --quiet | --silent) - show=: - preserve_args="$preserve_args $arg" - ;; - - --tag) - prevopt="--tag" - prev=tag - preserve_args="$preserve_args --tag" - ;; - --tag=*) - set tag "$optarg" ${1+"$@"} - shift - prev=tag - preserve_args="$preserve_args --tag" - ;; - - -dlopen) - prevopt="-dlopen" - prev=execute_dlfiles - ;; - - -*) - $echo "$modename: unrecognized option \`$arg'" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - ;; - - *) - nonopt="$arg" - break - ;; - esac -done - -if test -n "$prevopt"; then - $echo "$modename: option \`$prevopt' requires an argument" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE -fi - -case $disable_libs in -no) - ;; -shared) - build_libtool_libs=no - build_old_libs=yes - ;; -static) - build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` - ;; -esac - -# If this variable is set in any of the actions, the command in it -# will be execed at the end. This prevents here-documents from being -# left over by shells. -exec_cmd= - -if test -z "$show_help"; then - - # Infer the operation mode. - if test -z "$mode"; then - $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2 - $echo "*** Future versions of Libtool will require --mode=MODE be specified." 1>&2 - case $nonopt in - *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*) - mode=link - for arg - do - case $arg in - -c) - mode=compile - break - ;; - esac - done - ;; - *db | *dbx | *strace | *truss) - mode=execute - ;; - *install*|cp|mv) - mode=install - ;; - *rm) - mode=uninstall - ;; - *) - # If we have no mode, but dlfiles were specified, then do execute mode. - test -n "$execute_dlfiles" && mode=execute - - # Just use the default operation mode. - if test -z "$mode"; then - if test -n "$nonopt"; then - $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 - else - $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 - fi - fi - ;; - esac - fi - - # Only execute mode is allowed to have -dlopen flags. - if test -n "$execute_dlfiles" && test "$mode" != execute; then - $echo "$modename: unrecognized option \`-dlopen'" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - - # Change the help message to a mode-specific one. - generic_help="$help" - help="Try \`$modename --help --mode=$mode' for more information." - - # These modes are in order of execution frequency so that they run quickly. - case $mode in - # libtool compile mode - compile) - modename="$modename: compile" - # Get the compilation command and the source file. - base_compile= - srcfile="$nonopt" # always keep a non-empty value in "srcfile" - suppress_opt=yes - suppress_output= - arg_mode=normal - libobj= - later= - - for arg - do - case $arg_mode in - arg ) - # do not "continue". Instead, add this to base_compile - lastarg="$arg" - arg_mode=normal - ;; - - target ) - libobj="$arg" - arg_mode=normal - continue - ;; - - normal ) - # Accept any command-line options. - case $arg in - -o) - if test -n "$libobj" ; then - $echo "$modename: you cannot specify \`-o' more than once" 1>&2 - exit $EXIT_FAILURE - fi - arg_mode=target - continue - ;; - - -static | -prefer-pic | -prefer-non-pic) - later="$later $arg" - continue - ;; - - -no-suppress) - suppress_opt=no - continue - ;; - - -Xcompiler) - arg_mode=arg # the next one goes into the "base_compile" arg list - continue # The current "srcfile" will either be retained or - ;; # replaced later. I would guess that would be a bug. - - -Wc,*) - args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` - lastarg= - save_ifs="$IFS"; IFS=',' - for arg in $args; do - IFS="$save_ifs" - - # Double-quote args containing other shell metacharacters. - # Many Bourne shells cannot handle close brackets correctly - # in scan sets, so we specify it separately. - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - arg="\"$arg\"" - ;; - esac - lastarg="$lastarg $arg" - done - IFS="$save_ifs" - lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` - - # Add the arguments to base_compile. - base_compile="$base_compile $lastarg" - continue - ;; - - * ) - # Accept the current argument as the source file. - # The previous "srcfile" becomes the current argument. - # - lastarg="$srcfile" - srcfile="$arg" - ;; - esac # case $arg - ;; - esac # case $arg_mode - - # Aesthetically quote the previous argument. - lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` - - case $lastarg in - # Double-quote args containing other shell metacharacters. - # Many Bourne shells cannot handle close brackets correctly - # in scan sets, and some SunOS ksh mistreat backslash-escaping - # in scan sets (worked around with variable expansion), - # and furthermore cannot handle '|' '&' '(' ')' in scan sets - # at all, so we specify them separately. - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - lastarg="\"$lastarg\"" - ;; - esac - - base_compile="$base_compile $lastarg" - done # for arg - - case $arg_mode in - arg) - $echo "$modename: you must specify an argument for -Xcompile" - exit $EXIT_FAILURE - ;; - target) - $echo "$modename: you must specify a target with \`-o'" 1>&2 - exit $EXIT_FAILURE - ;; - *) - # Get the name of the library object. - [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` - ;; - esac - - # Recognize several different file suffixes. - # If the user specifies -o file.o, it is replaced with file.lo - xform='[cCFSifmso]' - case $libobj in - *.ada) xform=ada ;; - *.adb) xform=adb ;; - *.ads) xform=ads ;; - *.asm) xform=asm ;; - *.c++) xform=c++ ;; - *.cc) xform=cc ;; - *.ii) xform=ii ;; - *.class) xform=class ;; - *.cpp) xform=cpp ;; - *.cxx) xform=cxx ;; - *.[fF][09]?) xform=[fF][09]. ;; - *.for) xform=for ;; - *.java) xform=java ;; - *.obj) xform=obj ;; - esac - - libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` - - case $libobj in - *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; - *) - $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 - exit $EXIT_FAILURE - ;; - esac - - func_infer_tag $base_compile - - for arg in $later; do - case $arg in - -static) - build_old_libs=yes - continue - ;; - - -prefer-pic) - pic_mode=yes - continue - ;; - - -prefer-non-pic) - pic_mode=no - continue - ;; - esac - done - - qlibobj=`$echo "X$libobj" | $Xsed -e "$sed_quote_subst"` - case $qlibobj in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - qlibobj="\"$qlibobj\"" ;; - esac - test "X$libobj" != "X$qlibobj" \ - && $echo "X$libobj" | grep '[]~#^*{};<>?"'"'"' &()|`$[]' \ - && $echo "$modename: libobj name \`$libobj' may not contain shell special characters." - objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` - xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` - if test "X$xdir" = "X$obj"; then - xdir= - else - xdir=$xdir/ - fi - lobj=${xdir}$objdir/$objname - - if test -z "$base_compile"; then - $echo "$modename: you must specify a compilation command" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - - # Delete any leftover library objects. - if test "$build_old_libs" = yes; then - removelist="$obj $lobj $libobj ${libobj}T" - else - removelist="$lobj $libobj ${libobj}T" - fi - - $run $rm $removelist - trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 - - # On Cygwin there's no "real" PIC flag so we must build both object types - case $host_os in - cygwin* | mingw* | pw32* | os2*) - pic_mode=default - ;; - esac - if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then - # non-PIC code in shared libraries is not supported - pic_mode=default - fi - - # Calculate the filename of the output object if compiler does - # not support -o with -c - if test "$compiler_c_o" = no; then - output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} - lockfile="$output_obj.lock" - removelist="$removelist $output_obj $lockfile" - trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 - else - output_obj= - need_locks=no - lockfile= - fi - - # Lock this critical section if it is needed - # We use this script file to make the link, it avoids creating a new file - if test "$need_locks" = yes; then - until $run ln "$progpath" "$lockfile" 2>/dev/null; do - $show "Waiting for $lockfile to be removed" - sleep 2 - done - elif test "$need_locks" = warn; then - if test -f "$lockfile"; then - $echo "\ -*** ERROR, $lockfile exists and contains: -`cat $lockfile 2>/dev/null` - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support \`-c' and \`-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $run $rm $removelist - exit $EXIT_FAILURE - fi - $echo "$srcfile" > "$lockfile" - fi - - if test -n "$fix_srcfile_path"; then - eval srcfile=\"$fix_srcfile_path\" - fi - qsrcfile=`$echo "X$srcfile" | $Xsed -e "$sed_quote_subst"` - case $qsrcfile in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - qsrcfile="\"$qsrcfile\"" ;; - esac - - $run $rm "$libobj" "${libobj}T" - - # Create a libtool object file (analogous to a ".la" file), - # but don't create it if we're doing a dry run. - test -z "$run" && cat > ${libobj}T </dev/null`" != "X$srcfile"; then - $echo "\ -*** ERROR, $lockfile contains: -`cat $lockfile 2>/dev/null` - -but it should contain: -$srcfile - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support \`-c' and \`-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $run $rm $removelist - exit $EXIT_FAILURE - fi - - # Just move the object if needed, then go on to compile the next one - if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then - $show "$mv $output_obj $lobj" - if $run $mv $output_obj $lobj; then : - else - error=$? - $run $rm $removelist - exit $error - fi - fi - - # Append the name of the PIC object to the libtool object file. - test -z "$run" && cat >> ${libobj}T <> ${libobj}T </dev/null`" != "X$srcfile"; then - $echo "\ -*** ERROR, $lockfile contains: -`cat $lockfile 2>/dev/null` - -but it should contain: -$srcfile - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support \`-c' and \`-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $run $rm $removelist - exit $EXIT_FAILURE - fi - - # Just move the object if needed - if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then - $show "$mv $output_obj $obj" - if $run $mv $output_obj $obj; then : - else - error=$? - $run $rm $removelist - exit $error - fi - fi - - # Append the name of the non-PIC object the libtool object file. - # Only append if the libtool object file exists. - test -z "$run" && cat >> ${libobj}T <> ${libobj}T <&2 - fi - if test -n "$link_static_flag"; then - dlopen_self=$dlopen_self_static - fi - prefer_static_libs=yes - ;; - -static) - if test -z "$pic_flag" && test -n "$link_static_flag"; then - dlopen_self=$dlopen_self_static - fi - prefer_static_libs=built - ;; - -static-libtool-libs) - if test -z "$pic_flag" && test -n "$link_static_flag"; then - dlopen_self=$dlopen_self_static - fi - prefer_static_libs=yes - ;; - esac - build_libtool_libs=no - build_old_libs=yes - break - ;; - esac - done - - # See if our shared archives depend on static archives. - test -n "$old_archive_from_new_cmds" && build_old_libs=yes - - # Go through the arguments, transforming them on the way. - while test "$#" -gt 0; do - arg="$1" - shift - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test - ;; - *) qarg=$arg ;; - esac - libtool_args="$libtool_args $qarg" - - # If the previous option needs an argument, assign it. - if test -n "$prev"; then - case $prev in - output) - compile_command="$compile_command @OUTPUT@" - finalize_command="$finalize_command @OUTPUT@" - ;; - esac - - case $prev in - dlfiles|dlprefiles) - if test "$preload" = no; then - # Add the symbol object into the linking commands. - compile_command="$compile_command @SYMFILE@" - finalize_command="$finalize_command @SYMFILE@" - preload=yes - fi - case $arg in - *.la | *.lo) ;; # We handle these cases below. - force) - if test "$dlself" = no; then - dlself=needless - export_dynamic=yes - fi - prev= - continue - ;; - self) - if test "$prev" = dlprefiles; then - dlself=yes - elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then - dlself=yes - else - dlself=needless - export_dynamic=yes - fi - prev= - continue - ;; - *) - if test "$prev" = dlfiles; then - dlfiles="$dlfiles $arg" - else - dlprefiles="$dlprefiles $arg" - fi - prev= - continue - ;; - esac - ;; - expsyms) - export_symbols="$arg" - if test ! -f "$arg"; then - $echo "$modename: symbol file \`$arg' does not exist" - exit $EXIT_FAILURE - fi - prev= - continue - ;; - expsyms_regex) - export_symbols_regex="$arg" - prev= - continue - ;; - inst_prefix) - inst_prefix_dir="$arg" - prev= - continue - ;; - precious_regex) - precious_files_regex="$arg" - prev= - continue - ;; - release) - release="-$arg" - prev= - continue - ;; - objectlist) - if test -f "$arg"; then - save_arg=$arg - moreargs= - for fil in `cat $save_arg` - do -# moreargs="$moreargs $fil" - arg=$fil - # A libtool-controlled object. - - # Check to see that this really is a libtool object. - if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - pic_object= - non_pic_object= - - # Read the .lo file - # If there is no directory component, then add one. - case $arg in - */* | *\\*) . $arg ;; - *) . ./$arg ;; - esac - - if test -z "$pic_object" || \ - test -z "$non_pic_object" || - test "$pic_object" = none && \ - test "$non_pic_object" = none; then - $echo "$modename: cannot find name of object for \`$arg'" 1>&2 - exit $EXIT_FAILURE - fi - - # Extract subdirectory from the argument. - xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` - if test "X$xdir" = "X$arg"; then - xdir= - else - xdir="$xdir/" - fi - - if test "$pic_object" != none; then - # Prepend the subdirectory the object is found in. - pic_object="$xdir$pic_object" - - if test "$prev" = dlfiles; then - if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then - dlfiles="$dlfiles $pic_object" - prev= - continue - else - # If libtool objects are unsupported, then we need to preload. - prev=dlprefiles - fi - fi - - # CHECK ME: I think I busted this. -Ossama - if test "$prev" = dlprefiles; then - # Preload the old-style object. - dlprefiles="$dlprefiles $pic_object" - prev= - fi - - # A PIC object. - libobjs="$libobjs $pic_object" - arg="$pic_object" - fi - - # Non-PIC object. - if test "$non_pic_object" != none; then - # Prepend the subdirectory the object is found in. - non_pic_object="$xdir$non_pic_object" - - # A standard non-PIC object - non_pic_objects="$non_pic_objects $non_pic_object" - if test -z "$pic_object" || test "$pic_object" = none ; then - arg="$non_pic_object" - fi - else - # If the PIC object exists, use it instead. - # $xdir was prepended to $pic_object above. - non_pic_object="$pic_object" - non_pic_objects="$non_pic_objects $non_pic_object" - fi - else - # Only an error if not doing a dry-run. - if test -z "$run"; then - $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 - exit $EXIT_FAILURE - else - # Dry-run case. - - # Extract subdirectory from the argument. - xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` - if test "X$xdir" = "X$arg"; then - xdir= - else - xdir="$xdir/" - fi - - pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` - non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` - libobjs="$libobjs $pic_object" - non_pic_objects="$non_pic_objects $non_pic_object" - fi - fi - done - else - $echo "$modename: link input file \`$save_arg' does not exist" - exit $EXIT_FAILURE - fi - arg=$save_arg - prev= - continue - ;; - rpath | xrpath) - # We need an absolute path. - case $arg in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - $echo "$modename: only absolute run-paths are allowed" 1>&2 - exit $EXIT_FAILURE - ;; - esac - if test "$prev" = rpath; then - case "$rpath " in - *" $arg "*) ;; - *) rpath="$rpath $arg" ;; - esac - else - case "$xrpath " in - *" $arg "*) ;; - *) xrpath="$xrpath $arg" ;; - esac - fi - prev= - continue - ;; - xcompiler) - compiler_flags="$compiler_flags $qarg" - prev= - compile_command="$compile_command $qarg" - finalize_command="$finalize_command $qarg" - continue - ;; - xlinker) - linker_flags="$linker_flags $qarg" - compiler_flags="$compiler_flags $wl$qarg" - prev= - compile_command="$compile_command $wl$qarg" - finalize_command="$finalize_command $wl$qarg" - continue - ;; - xcclinker) - linker_flags="$linker_flags $qarg" - compiler_flags="$compiler_flags $qarg" - prev= - compile_command="$compile_command $qarg" - finalize_command="$finalize_command $qarg" - continue - ;; - shrext) - shrext_cmds="$arg" - prev= - continue - ;; - darwin_framework|darwin_framework_skip) - test "$prev" = "darwin_framework" && compiler_flags="$compiler_flags $arg" - compile_command="$compile_command $arg" - finalize_command="$finalize_command $arg" - prev= - continue - ;; - *) - eval "$prev=\"\$arg\"" - prev= - continue - ;; - esac - fi # test -n "$prev" - - prevarg="$arg" - - case $arg in - -all-static) - if test -n "$link_static_flag"; then - compile_command="$compile_command $link_static_flag" - finalize_command="$finalize_command $link_static_flag" - fi - continue - ;; - - -allow-undefined) - # FIXME: remove this flag sometime in the future. - $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 - continue - ;; - - -avoid-version) - avoid_version=yes - continue - ;; - - -dlopen) - prev=dlfiles - continue - ;; - - -dlpreopen) - prev=dlprefiles - continue - ;; - - -export-dynamic) - export_dynamic=yes - continue - ;; - - -export-symbols | -export-symbols-regex) - if test -n "$export_symbols" || test -n "$export_symbols_regex"; then - $echo "$modename: more than one -exported-symbols argument is not allowed" - exit $EXIT_FAILURE - fi - if test "X$arg" = "X-export-symbols"; then - prev=expsyms - else - prev=expsyms_regex - fi - continue - ;; - - -framework|-arch|-isysroot) - case " $CC " in - *" ${arg} ${1} "* | *" ${arg} ${1} "*) - prev=darwin_framework_skip ;; - *) compiler_flags="$compiler_flags $arg" - prev=darwin_framework ;; - esac - compile_command="$compile_command $arg" - finalize_command="$finalize_command $arg" - continue - ;; - - -inst-prefix-dir) - prev=inst_prefix - continue - ;; - - # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* - # so, if we see these flags be careful not to treat them like -L - -L[A-Z][A-Z]*:*) - case $with_gcc/$host in - no/*-*-irix* | /*-*-irix*) - compile_command="$compile_command $arg" - finalize_command="$finalize_command $arg" - ;; - esac - continue - ;; - - -L*) - dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` - # We need an absolute path. - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - absdir=`cd "$dir" && pwd` - if test -z "$absdir"; then - $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 - absdir="$dir" - notinst_path="$notinst_path $dir" - fi - dir="$absdir" - ;; - esac - case "$deplibs " in - *" -L$dir "*) ;; - *) - deplibs="$deplibs -L$dir" - lib_search_path="$lib_search_path $dir" - ;; - esac - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) - testbindir=`$echo "X$dir" | $Xsed -e 's*/lib$*/bin*'` - case :$dllsearchpath: in - *":$dir:"*) ;; - *) dllsearchpath="$dllsearchpath:$dir";; - esac - case :$dllsearchpath: in - *":$testbindir:"*) ;; - *) dllsearchpath="$dllsearchpath:$testbindir";; - esac - ;; - esac - continue - ;; - - -l*) - if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos*) - # These systems don't actually have a C or math library (as such) - continue - ;; - *-*-os2*) - # These systems don't actually have a C library (as such) - test "X$arg" = "X-lc" && continue - ;; - *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) - # Do not include libc due to us having libc/libc_r. - test "X$arg" = "X-lc" && continue - ;; - *-*-rhapsody* | *-*-darwin1.[012]) - # Rhapsody C and math libraries are in the System framework - deplibs="$deplibs -framework System" - continue - ;; - *-*-sco3.2v5* | *-*-sco5v6*) - # Causes problems with __ctype - test "X$arg" = "X-lc" && continue - ;; - *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) - # Compiler inserts libc in the correct place for threads to work - test "X$arg" = "X-lc" && continue - ;; - esac - elif test "X$arg" = "X-lc_r"; then - case $host in - *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) - # Do not include libc_r directly, use -pthread flag. - continue - ;; - esac - fi - deplibs="$deplibs $arg" - continue - ;; - - # Tru64 UNIX uses -model [arg] to determine the layout of C++ - # classes, name mangling, and exception handling. - -model) - compile_command="$compile_command $arg" - compiler_flags="$compiler_flags $arg" - finalize_command="$finalize_command $arg" - prev=xcompiler - continue - ;; - - -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) - compiler_flags="$compiler_flags $arg" - compile_command="$compile_command $arg" - finalize_command="$finalize_command $arg" - continue - ;; - - -module) - module=yes - continue - ;; - - # -64, -mips[0-9] enable 64-bit mode on the SGI compiler - # -r[0-9][0-9]* specifies the processor on the SGI compiler - # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler - # +DA*, +DD* enable 64-bit mode on the HP compiler - # -q* pass through compiler args for the IBM compiler - # -m* pass through architecture-specific compiler args for GCC - # -m*, -t[45]*, -txscale* pass through architecture-specific - # compiler args for GCC - # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC - # -F/path gives path to uninstalled frameworks, gcc on darwin - # @file GCC response files - -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ - -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*) - - # Unknown arguments in both finalize_command and compile_command need - # to be aesthetically quoted because they are evaled later. - arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - arg="\"$arg\"" - ;; - esac - compile_command="$compile_command $arg" - finalize_command="$finalize_command $arg" - compiler_flags="$compiler_flags $arg" - continue - ;; - - -shrext) - prev=shrext - continue - ;; - - -no-fast-install) - fast_install=no - continue - ;; - - -no-install) - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin*) - # The PATH hackery in wrapper scripts is required on Windows - # and Darwin in order for the loader to find any dlls it needs. - $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 - $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 - fast_install=no - ;; - *) no_install=yes ;; - esac - continue - ;; - - -no-undefined) - allow_undefined=no - continue - ;; - - -objectlist) - prev=objectlist - continue - ;; - - -o) prev=output ;; - - -precious-files-regex) - prev=precious_regex - continue - ;; - - -release) - prev=release - continue - ;; - - -rpath) - prev=rpath - continue - ;; - - -R) - prev=xrpath - continue - ;; - - -R*) - dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` - # We need an absolute path. - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - $echo "$modename: only absolute run-paths are allowed" 1>&2 - exit $EXIT_FAILURE - ;; - esac - case "$xrpath " in - *" $dir "*) ;; - *) xrpath="$xrpath $dir" ;; - esac - continue - ;; - - -static | -static-libtool-libs) - # The effects of -static are defined in a previous loop. - # We used to do the same as -all-static on platforms that - # didn't have a PIC flag, but the assumption that the effects - # would be equivalent was wrong. It would break on at least - # Digital Unix and AIX. - continue - ;; - - -thread-safe) - thread_safe=yes - continue - ;; - - -version-info) - prev=vinfo - continue - ;; - -version-number) - prev=vinfo - vinfo_number=yes - continue - ;; - - -Wc,*) - args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` - arg= - save_ifs="$IFS"; IFS=',' - for flag in $args; do - IFS="$save_ifs" - case $flag in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - flag="\"$flag\"" - ;; - esac - arg="$arg $wl$flag" - compiler_flags="$compiler_flags $flag" - done - IFS="$save_ifs" - arg=`$echo "X$arg" | $Xsed -e "s/^ //"` - ;; - - -Wl,*) - args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` - arg= - save_ifs="$IFS"; IFS=',' - for flag in $args; do - IFS="$save_ifs" - case $flag in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - flag="\"$flag\"" - ;; - esac - arg="$arg $wl$flag" - compiler_flags="$compiler_flags $wl$flag" - linker_flags="$linker_flags $flag" - done - IFS="$save_ifs" - arg=`$echo "X$arg" | $Xsed -e "s/^ //"` - ;; - - -Xcompiler) - prev=xcompiler - continue - ;; - - -Xlinker) - prev=xlinker - continue - ;; - - -XCClinker) - prev=xcclinker - continue - ;; - - # Some other compiler flag. - -* | +*) - # Unknown arguments in both finalize_command and compile_command need - # to be aesthetically quoted because they are evaled later. - arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - arg="\"$arg\"" - ;; - esac - ;; - - *.$objext) - # A standard object. - objs="$objs $arg" - ;; - - *.lo) - # A libtool-controlled object. - - # Check to see that this really is a libtool object. - if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - pic_object= - non_pic_object= - - # Read the .lo file - # If there is no directory component, then add one. - case $arg in - */* | *\\*) . $arg ;; - *) . ./$arg ;; - esac - - if test -z "$pic_object" || \ - test -z "$non_pic_object" || - test "$pic_object" = none && \ - test "$non_pic_object" = none; then - $echo "$modename: cannot find name of object for \`$arg'" 1>&2 - exit $EXIT_FAILURE - fi - - # Extract subdirectory from the argument. - xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` - if test "X$xdir" = "X$arg"; then - xdir= - else - xdir="$xdir/" - fi - - if test "$pic_object" != none; then - # Prepend the subdirectory the object is found in. - pic_object="$xdir$pic_object" - - if test "$prev" = dlfiles; then - if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then - dlfiles="$dlfiles $pic_object" - prev= - continue - else - # If libtool objects are unsupported, then we need to preload. - prev=dlprefiles - fi - fi - - # CHECK ME: I think I busted this. -Ossama - if test "$prev" = dlprefiles; then - # Preload the old-style object. - dlprefiles="$dlprefiles $pic_object" - prev= - fi - - # A PIC object. - libobjs="$libobjs $pic_object" - arg="$pic_object" - fi - - # Non-PIC object. - if test "$non_pic_object" != none; then - # Prepend the subdirectory the object is found in. - non_pic_object="$xdir$non_pic_object" - - # A standard non-PIC object - non_pic_objects="$non_pic_objects $non_pic_object" - if test -z "$pic_object" || test "$pic_object" = none ; then - arg="$non_pic_object" - fi - else - # If the PIC object exists, use it instead. - # $xdir was prepended to $pic_object above. - non_pic_object="$pic_object" - non_pic_objects="$non_pic_objects $non_pic_object" - fi - else - # Only an error if not doing a dry-run. - if test -z "$run"; then - $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 - exit $EXIT_FAILURE - else - # Dry-run case. - - # Extract subdirectory from the argument. - xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` - if test "X$xdir" = "X$arg"; then - xdir= - else - xdir="$xdir/" - fi - - pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` - non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` - libobjs="$libobjs $pic_object" - non_pic_objects="$non_pic_objects $non_pic_object" - fi - fi - ;; - - *.$libext) - # An archive. - deplibs="$deplibs $arg" - old_deplibs="$old_deplibs $arg" - continue - ;; - - *.la) - # A libtool-controlled library. - - if test "$prev" = dlfiles; then - # This library was specified with -dlopen. - dlfiles="$dlfiles $arg" - prev= - elif test "$prev" = dlprefiles; then - # The library was specified with -dlpreopen. - dlprefiles="$dlprefiles $arg" - prev= - else - deplibs="$deplibs $arg" - fi - continue - ;; - - # Some other compiler argument. - *) - # Unknown arguments in both finalize_command and compile_command need - # to be aesthetically quoted because they are evaled later. - arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - arg="\"$arg\"" - ;; - esac - ;; - esac # arg - - # Now actually substitute the argument into the commands. - if test -n "$arg"; then - compile_command="$compile_command $arg" - finalize_command="$finalize_command $arg" - fi - done # argument parsing loop - - if test -n "$prev"; then - $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - - if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then - eval arg=\"$export_dynamic_flag_spec\" - compile_command="$compile_command $arg" - finalize_command="$finalize_command $arg" - fi - - oldlibs= - # calculate the name of the file, without its directory - outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` - libobjs_save="$libobjs" - - if test -n "$shlibpath_var"; then - # get the directories listed in $shlibpath_var - eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` - else - shlib_search_path= - fi - eval sys_lib_search_path=\"$sys_lib_search_path_spec\" - eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" - - output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` - if test "X$output_objdir" = "X$output"; then - output_objdir="$objdir" - else - output_objdir="$output_objdir/$objdir" - fi - # Create the object directory. - if test ! -d "$output_objdir"; then - $show "$mkdir $output_objdir" - $run $mkdir $output_objdir - exit_status=$? - if test "$exit_status" -ne 0 && test ! -d "$output_objdir"; then - exit $exit_status - fi - fi - - # Determine the type of output - case $output in - "") - $echo "$modename: you must specify an output file" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - ;; - *.$libext) linkmode=oldlib ;; - *.lo | *.$objext) linkmode=obj ;; - *.la) linkmode=lib ;; - *) linkmode=prog ;; # Anything else should be a program. - esac - - case $host in - *cygwin* | *mingw* | *pw32*) - # don't eliminate duplications in $postdeps and $predeps - duplicate_compiler_generated_deps=yes - ;; - *) - duplicate_compiler_generated_deps=$duplicate_deps - ;; - esac - specialdeplibs= - - libs= - # Find all interdependent deplibs by searching for libraries - # that are linked more than once (e.g. -la -lb -la) - for deplib in $deplibs; do - if test "X$duplicate_deps" = "Xyes" ; then - case "$libs " in - *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; - esac - fi - libs="$libs $deplib" - done - - if test "$linkmode" = lib; then - libs="$predeps $libs $compiler_lib_search_path $postdeps" - - # Compute libraries that are listed more than once in $predeps - # $postdeps and mark them as special (i.e., whose duplicates are - # not to be eliminated). - pre_post_deps= - if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then - for pre_post_dep in $predeps $postdeps; do - case "$pre_post_deps " in - *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; - esac - pre_post_deps="$pre_post_deps $pre_post_dep" - done - fi - pre_post_deps= - fi - - deplibs= - newdependency_libs= - newlib_search_path= - need_relink=no # whether we're linking any uninstalled libtool libraries - notinst_deplibs= # not-installed libtool libraries - case $linkmode in - lib) - passes="conv link" - for file in $dlfiles $dlprefiles; do - case $file in - *.la) ;; - *) - $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 - exit $EXIT_FAILURE - ;; - esac - done - ;; - prog) - compile_deplibs= - finalize_deplibs= - alldeplibs=no - newdlfiles= - newdlprefiles= - passes="conv scan dlopen dlpreopen link" - ;; - *) passes="conv" - ;; - esac - for pass in $passes; do - if test "$linkmode,$pass" = "lib,link" || - test "$linkmode,$pass" = "prog,scan"; then - libs="$deplibs" - deplibs= - fi - if test "$linkmode" = prog; then - case $pass in - dlopen) libs="$dlfiles" ;; - dlpreopen) libs="$dlprefiles" ;; - link) - libs="$deplibs %DEPLIBS%" - test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" - ;; - esac - fi - if test "$pass" = dlopen; then - # Collect dlpreopened libraries - save_deplibs="$deplibs" - deplibs= - fi - for deplib in $libs; do - lib= - found=no - case $deplib in - -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) - if test "$linkmode,$pass" = "prog,link"; then - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - compiler_flags="$compiler_flags $deplib" - fi - continue - ;; - -l*) - if test "$linkmode" != lib && test "$linkmode" != prog; then - $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2 - continue - fi - name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` - for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do - for search_ext in .la $std_shrext .so .a; do - # Search the libtool library - lib="$searchdir/lib${name}${search_ext}" - if test -f "$lib"; then - if test "$search_ext" = ".la"; then - found=yes - else - found=no - fi - break 2 - fi - done - done - if test "$found" != yes; then - # deplib doesn't seem to be a libtool library - if test "$linkmode,$pass" = "prog,link"; then - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - deplibs="$deplib $deplibs" - test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" - fi - continue - else # deplib is a libtool library - # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, - # We need to do some special things here, and not later. - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - case " $predeps $postdeps " in - *" $deplib "*) - if (${SED} -e '2q' $lib | - grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - library_names= - old_library= - case $lib in - */* | *\\*) . $lib ;; - *) . ./$lib ;; - esac - for l in $old_library $library_names; do - ll="$l" - done - if test "X$ll" = "X$old_library" ; then # only static version available - found=no - ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` - test "X$ladir" = "X$lib" && ladir="." - lib=$ladir/$old_library - if test "$linkmode,$pass" = "prog,link"; then - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - deplibs="$deplib $deplibs" - test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" - fi - continue - fi - fi - ;; - *) ;; - esac - fi - fi - ;; # -l - -L*) - case $linkmode in - lib) - deplibs="$deplib $deplibs" - test "$pass" = conv && continue - newdependency_libs="$deplib $newdependency_libs" - newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` - ;; - prog) - if test "$pass" = conv; then - deplibs="$deplib $deplibs" - continue - fi - if test "$pass" = scan; then - deplibs="$deplib $deplibs" - else - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - fi - newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` - ;; - *) - $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2 - ;; - esac # linkmode - continue - ;; # -L - -R*) - if test "$pass" = link; then - dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` - # Make sure the xrpath contains only unique directories. - case "$xrpath " in - *" $dir "*) ;; - *) xrpath="$xrpath $dir" ;; - esac - fi - deplibs="$deplib $deplibs" - continue - ;; - *.la) lib="$deplib" ;; - *.$libext) - if test "$pass" = conv; then - deplibs="$deplib $deplibs" - continue - fi - case $linkmode in - lib) - valid_a_lib=no - case $deplibs_check_method in - match_pattern*) - set dummy $deplibs_check_method - match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` - if eval $echo \"$deplib\" 2>/dev/null \ - | $SED 10q \ - | $EGREP "$match_pattern_regex" > /dev/null; then - valid_a_lib=yes - fi - ;; - pass_all) - valid_a_lib=yes - ;; - esac - if test "$valid_a_lib" != yes; then - $echo - $echo "*** Warning: Trying to link with static lib archive $deplib." - $echo "*** I have the capability to make that library automatically link in when" - $echo "*** you link to this library. But I can only do this if you have a" - $echo "*** shared version of the library, which you do not appear to have" - $echo "*** because the file extensions .$libext of this argument makes me believe" - $echo "*** that it is just a static archive that I should not used here." - else - $echo - $echo "*** Warning: Linking the shared library $output against the" - $echo "*** static library $deplib is not portable!" - deplibs="$deplib $deplibs" - fi - continue - ;; - prog) - if test "$pass" != link; then - deplibs="$deplib $deplibs" - else - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - fi - continue - ;; - esac # linkmode - ;; # *.$libext - *.lo | *.$objext) - if test "$pass" = conv; then - deplibs="$deplib $deplibs" - elif test "$linkmode" = prog; then - if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then - # If there is no dlopen support or we're linking statically, - # we need to preload. - newdlprefiles="$newdlprefiles $deplib" - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - newdlfiles="$newdlfiles $deplib" - fi - fi - continue - ;; - %DEPLIBS%) - alldeplibs=yes - continue - ;; - esac # case $deplib - if test "$found" = yes || test -f "$lib"; then : - else - $echo "$modename: cannot find the library \`$lib' or unhandled argument \`$deplib'" 1>&2 - exit $EXIT_FAILURE - fi - - # Check to see that this really is a libtool archive. - if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : - else - $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 - exit $EXIT_FAILURE - fi - - ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` - test "X$ladir" = "X$lib" && ladir="." - - dlname= - dlopen= - dlpreopen= - libdir= - library_names= - old_library= - # If the library was installed with an old release of libtool, - # it will not redefine variables installed, or shouldnotlink - installed=yes - shouldnotlink=no - avoidtemprpath= - - - # Read the .la file - case $lib in - */* | *\\*) . $lib ;; - *) . ./$lib ;; - esac - - if test "$linkmode,$pass" = "lib,link" || - test "$linkmode,$pass" = "prog,scan" || - { test "$linkmode" != prog && test "$linkmode" != lib; }; then - test -n "$dlopen" && dlfiles="$dlfiles $dlopen" - test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" - fi - - if test "$pass" = conv; then - # Only check for convenience libraries - deplibs="$lib $deplibs" - if test -z "$libdir"; then - if test -z "$old_library"; then - $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 - exit $EXIT_FAILURE - fi - # It is a libtool convenience library, so add in its objects. - convenience="$convenience $ladir/$objdir/$old_library" - old_convenience="$old_convenience $ladir/$objdir/$old_library" - tmp_libs= - for deplib in $dependency_libs; do - deplibs="$deplib $deplibs" - if test "X$duplicate_deps" = "Xyes" ; then - case "$tmp_libs " in - *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; - esac - fi - tmp_libs="$tmp_libs $deplib" - done - elif test "$linkmode" != prog && test "$linkmode" != lib; then - $echo "$modename: \`$lib' is not a convenience library" 1>&2 - exit $EXIT_FAILURE - fi - continue - fi # $pass = conv - - - # Get the name of the library we link against. - linklib= - for l in $old_library $library_names; do - linklib="$l" - done - if test -z "$linklib"; then - $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 - exit $EXIT_FAILURE - fi - - # This library was specified with -dlopen. - if test "$pass" = dlopen; then - if test -z "$libdir"; then - $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 - exit $EXIT_FAILURE - fi - if test -z "$dlname" || - test "$dlopen_support" != yes || - test "$build_libtool_libs" = no; then - # If there is no dlname, no dlopen support or we're linking - # statically, we need to preload. We also need to preload any - # dependent libraries so libltdl's deplib preloader doesn't - # bomb out in the load deplibs phase. - dlprefiles="$dlprefiles $lib $dependency_libs" - else - newdlfiles="$newdlfiles $lib" - fi - continue - fi # $pass = dlopen - - # We need an absolute path. - case $ladir in - [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; - *) - abs_ladir=`cd "$ladir" && pwd` - if test -z "$abs_ladir"; then - $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 - $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 - abs_ladir="$ladir" - fi - ;; - esac - laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` - - # Find the relevant object directory and library name. - if test "X$installed" = Xyes; then - if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then - $echo "$modename: warning: library \`$lib' was moved." 1>&2 - dir="$ladir" - absdir="$abs_ladir" - libdir="$abs_ladir" - else - dir="$libdir" - absdir="$libdir" - fi - test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes - else - if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then - dir="$ladir" - absdir="$abs_ladir" - # Remove this search path later - notinst_path="$notinst_path $abs_ladir" - else - dir="$ladir/$objdir" - absdir="$abs_ladir/$objdir" - # Remove this search path later - notinst_path="$notinst_path $abs_ladir" - fi - fi # $installed = yes - name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` - - # This library was specified with -dlpreopen. - if test "$pass" = dlpreopen; then - if test -z "$libdir"; then - $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 - exit $EXIT_FAILURE - fi - # Prefer using a static library (so that no silly _DYNAMIC symbols - # are required to link). - if test -n "$old_library"; then - newdlprefiles="$newdlprefiles $dir/$old_library" - # Otherwise, use the dlname, so that lt_dlopen finds it. - elif test -n "$dlname"; then - newdlprefiles="$newdlprefiles $dir/$dlname" - else - newdlprefiles="$newdlprefiles $dir/$linklib" - fi - fi # $pass = dlpreopen - - if test -z "$libdir"; then - # Link the convenience library - if test "$linkmode" = lib; then - deplibs="$dir/$old_library $deplibs" - elif test "$linkmode,$pass" = "prog,link"; then - compile_deplibs="$dir/$old_library $compile_deplibs" - finalize_deplibs="$dir/$old_library $finalize_deplibs" - else - deplibs="$lib $deplibs" # used for prog,scan pass - fi - continue - fi - - - if test "$linkmode" = prog && test "$pass" != link; then - newlib_search_path="$newlib_search_path $ladir" - deplibs="$lib $deplibs" - - linkalldeplibs=no - if test "$link_all_deplibs" != no || test -z "$library_names" || - test "$build_libtool_libs" = no; then - linkalldeplibs=yes - fi - - tmp_libs= - for deplib in $dependency_libs; do - case $deplib in - -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test - esac - # Need to link against all dependency_libs? - if test "$linkalldeplibs" = yes; then - deplibs="$deplib $deplibs" - else - # Need to hardcode shared library paths - # or/and link against static libraries - newdependency_libs="$deplib $newdependency_libs" - fi - if test "X$duplicate_deps" = "Xyes" ; then - case "$tmp_libs " in - *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; - esac - fi - tmp_libs="$tmp_libs $deplib" - done # for deplib - continue - fi # $linkmode = prog... - - if test "$linkmode,$pass" = "prog,link"; then - if test -n "$library_names" && - { { test "$prefer_static_libs" = no || - test "$prefer_static_libs,$installed" = "built,yes"; } || - test -z "$old_library"; }; then - # We need to hardcode the library path - if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then - # Make sure the rpath contains only unique directories. - case "$temp_rpath " in - *" $dir "*) ;; - *" $absdir "*) ;; - *) temp_rpath="$temp_rpath $absdir" ;; - esac - fi - - # Hardcode the library path. - # Skip directories that are in the system default run-time - # search path. - case " $sys_lib_dlsearch_path " in - *" $absdir "*) ;; - *) - case "$compile_rpath " in - *" $absdir "*) ;; - *) compile_rpath="$compile_rpath $absdir" - esac - ;; - esac - case " $sys_lib_dlsearch_path " in - *" $libdir "*) ;; - *) - case "$finalize_rpath " in - *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" - esac - ;; - esac - fi # $linkmode,$pass = prog,link... - - if test "$alldeplibs" = yes && - { test "$deplibs_check_method" = pass_all || - { test "$build_libtool_libs" = yes && - test -n "$library_names"; }; }; then - # We only need to search for static libraries - continue - fi - fi - - link_static=no # Whether the deplib will be linked statically - use_static_libs=$prefer_static_libs - if test "$use_static_libs" = built && test "$installed" = yes ; then - use_static_libs=no - fi - if test -n "$library_names" && - { test "$use_static_libs" = no || test -z "$old_library"; }; then - if test "$installed" = no; then - notinst_deplibs="$notinst_deplibs $lib" - need_relink=yes - fi - # This is a shared library - - # Warn about portability, can't link against -module's on - # some systems (darwin) - if test "$shouldnotlink" = yes && test "$pass" = link ; then - $echo - if test "$linkmode" = prog; then - $echo "*** Warning: Linking the executable $output against the loadable module" - else - $echo "*** Warning: Linking the shared library $output against the loadable module" - fi - $echo "*** $linklib is not portable!" - fi - if test "$linkmode" = lib && - test "$hardcode_into_libs" = yes; then - # Hardcode the library path. - # Skip directories that are in the system default run-time - # search path. - case " $sys_lib_dlsearch_path " in - *" $absdir "*) ;; - *) - case "$compile_rpath " in - *" $absdir "*) ;; - *) compile_rpath="$compile_rpath $absdir" - esac - ;; - esac - case " $sys_lib_dlsearch_path " in - *" $libdir "*) ;; - *) - case "$finalize_rpath " in - *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" - esac - ;; - esac - fi - - if test -n "$old_archive_from_expsyms_cmds"; then - # figure out the soname - set dummy $library_names - realname="$2" - shift; shift - libname=`eval \\$echo \"$libname_spec\"` - # use dlname if we got it. it's perfectly good, no? - if test -n "$dlname"; then - soname="$dlname" - elif test -n "$soname_spec"; then - # bleh windows - case $host in - *cygwin* | mingw*) - major=`expr $current - $age` - versuffix="-$major" - ;; - esac - eval soname=\"$soname_spec\" - else - soname="$realname" - fi - - # Make a new name for the extract_expsyms_cmds to use - soroot="$soname" - soname=`$echo $soroot | ${SED} -e 's/^.*\///'` - newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a" - - # If the library has no export list, then create one now - if test -f "$output_objdir/$soname-def"; then : - else - $show "extracting exported symbol list from \`$soname'" - save_ifs="$IFS"; IFS='~' - cmds=$extract_expsyms_cmds - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - fi - - # Create $newlib - if test -f "$output_objdir/$newlib"; then :; else - $show "generating import library for \`$soname'" - save_ifs="$IFS"; IFS='~' - cmds=$old_archive_from_expsyms_cmds - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - fi - # make sure the library variables are pointing to the new library - dir=$output_objdir - linklib=$newlib - fi # test -n "$old_archive_from_expsyms_cmds" - - if test "$linkmode" = prog || test "$mode" != relink; then - add_shlibpath= - add_dir= - add= - lib_linked=yes - case $hardcode_action in - immediate | unsupported) - if test "$hardcode_direct" = no; then - add="$dir/$linklib" - case $host in - *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; - *-*-sysv4*uw2*) add_dir="-L$dir" ;; - *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ - *-*-unixware7*) add_dir="-L$dir" ;; - *-*-darwin* ) - # if the lib is a module then we can not link against - # it, someone is ignoring the new warnings I added - if /usr/bin/file -L $add 2> /dev/null | - $EGREP ": [^:]* bundle" >/dev/null ; then - $echo "** Warning, lib $linklib is a module, not a shared library" - if test -z "$old_library" ; then - $echo - $echo "** And there doesn't seem to be a static archive available" - $echo "** The link will probably fail, sorry" - else - add="$dir/$old_library" - fi - fi - esac - elif test "$hardcode_minus_L" = no; then - case $host in - *-*-sunos*) add_shlibpath="$dir" ;; - esac - add_dir="-L$dir" - add="-l$name" - elif test "$hardcode_shlibpath_var" = no; then - add_shlibpath="$dir" - add="-l$name" - else - lib_linked=no - fi - ;; - relink) - if test "$hardcode_direct" = yes; then - add="$dir/$linklib" - elif test "$hardcode_minus_L" = yes; then - add_dir="-L$dir" - # Try looking first in the location we're being installed to. - if test -n "$inst_prefix_dir"; then - case $libdir in - [\\/]*) - add_dir="$add_dir -L$inst_prefix_dir$libdir" - ;; - esac - fi - add="-l$name" - elif test "$hardcode_shlibpath_var" = yes; then - add_shlibpath="$dir" - add="-l$name" - else - lib_linked=no - fi - ;; - *) lib_linked=no ;; - esac - - if test "$lib_linked" != yes; then - $echo "$modename: configuration error: unsupported hardcode properties" - exit $EXIT_FAILURE - fi - - if test -n "$add_shlibpath"; then - case :$compile_shlibpath: in - *":$add_shlibpath:"*) ;; - *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; - esac - fi - if test "$linkmode" = prog; then - test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" - test -n "$add" && compile_deplibs="$add $compile_deplibs" - else - test -n "$add_dir" && deplibs="$add_dir $deplibs" - test -n "$add" && deplibs="$add $deplibs" - if test "$hardcode_direct" != yes && \ - test "$hardcode_minus_L" != yes && \ - test "$hardcode_shlibpath_var" = yes; then - case :$finalize_shlibpath: in - *":$libdir:"*) ;; - *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; - esac - fi - fi - fi - - if test "$linkmode" = prog || test "$mode" = relink; then - add_shlibpath= - add_dir= - add= - # Finalize command for both is simple: just hardcode it. - if test "$hardcode_direct" = yes; then - add="$libdir/$linklib" - elif test "$hardcode_minus_L" = yes; then - add_dir="-L$libdir" - add="-l$name" - elif test "$hardcode_shlibpath_var" = yes; then - case :$finalize_shlibpath: in - *":$libdir:"*) ;; - *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; - esac - add="-l$name" - elif test "$hardcode_automatic" = yes; then - if test -n "$inst_prefix_dir" && - test -f "$inst_prefix_dir$libdir/$linklib" ; then - add="$inst_prefix_dir$libdir/$linklib" - else - add="$libdir/$linklib" - fi - else - # We cannot seem to hardcode it, guess we'll fake it. - add_dir="-L$libdir" - # Try looking first in the location we're being installed to. - if test -n "$inst_prefix_dir"; then - case $libdir in - [\\/]*) - add_dir="$add_dir -L$inst_prefix_dir$libdir" - ;; - esac - fi - add="-l$name" - fi - - if test "$linkmode" = prog; then - test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" - test -n "$add" && finalize_deplibs="$add $finalize_deplibs" - else - test -n "$add_dir" && deplibs="$add_dir $deplibs" - test -n "$add" && deplibs="$add $deplibs" - fi - fi - elif test "$linkmode" = prog; then - # Here we assume that one of hardcode_direct or hardcode_minus_L - # is not unsupported. This is valid on all known static and - # shared platforms. - if test "$hardcode_direct" != unsupported; then - test -n "$old_library" && linklib="$old_library" - compile_deplibs="$dir/$linklib $compile_deplibs" - finalize_deplibs="$dir/$linklib $finalize_deplibs" - else - compile_deplibs="-l$name -L$dir $compile_deplibs" - finalize_deplibs="-l$name -L$dir $finalize_deplibs" - fi - elif test "$build_libtool_libs" = yes; then - # Not a shared library - if test "$deplibs_check_method" != pass_all; then - # We're trying link a shared library against a static one - # but the system doesn't support it. - - # Just print a warning and add the library to dependency_libs so - # that the program can be linked against the static library. - $echo - $echo "*** Warning: This system can not link to static lib archive $lib." - $echo "*** I have the capability to make that library automatically link in when" - $echo "*** you link to this library. But I can only do this if you have a" - $echo "*** shared version of the library, which you do not appear to have." - if test "$module" = yes; then - $echo "*** But as you try to build a module library, libtool will still create " - $echo "*** a static module, that should work as long as the dlopening application" - $echo "*** is linked with the -dlopen flag to resolve symbols at runtime." - if test -z "$global_symbol_pipe"; then - $echo - $echo "*** However, this would only work if libtool was able to extract symbol" - $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" - $echo "*** not find such a program. So, this module is probably useless." - $echo "*** \`nm' from GNU binutils and a full rebuild may help." - fi - if test "$build_old_libs" = no; then - build_libtool_libs=module - build_old_libs=yes - else - build_libtool_libs=no - fi - fi - else - deplibs="$dir/$old_library $deplibs" - link_static=yes - fi - fi # link shared/static library? - - if test "$linkmode" = lib; then - if test -n "$dependency_libs" && - { test "$hardcode_into_libs" != yes || - test "$build_old_libs" = yes || - test "$link_static" = yes; }; then - # Extract -R from dependency_libs - temp_deplibs= - for libdir in $dependency_libs; do - case $libdir in - -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` - case " $xrpath " in - *" $temp_xrpath "*) ;; - *) xrpath="$xrpath $temp_xrpath";; - esac;; - *) temp_deplibs="$temp_deplibs $libdir";; - esac - done - dependency_libs="$temp_deplibs" - fi - - newlib_search_path="$newlib_search_path $absdir" - # Link against this library - test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" - # ... and its dependency_libs - tmp_libs= - for deplib in $dependency_libs; do - newdependency_libs="$deplib $newdependency_libs" - if test "X$duplicate_deps" = "Xyes" ; then - case "$tmp_libs " in - *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; - esac - fi - tmp_libs="$tmp_libs $deplib" - done - - if test "$link_all_deplibs" != no; then - # Add the search paths of all dependency libraries - for deplib in $dependency_libs; do - case $deplib in - -L*) path="$deplib" ;; - *.la) - dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` - test "X$dir" = "X$deplib" && dir="." - # We need an absolute path. - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; - *) - absdir=`cd "$dir" && pwd` - if test -z "$absdir"; then - $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 - absdir="$dir" - fi - ;; - esac - if grep "^installed=no" $deplib > /dev/null; then - path="$absdir/$objdir" - else - eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` - if test -z "$libdir"; then - $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 - exit $EXIT_FAILURE - fi - if test "$absdir" != "$libdir"; then - $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 - fi - path="$absdir" - fi - depdepl= - case $host in - *-*-darwin*) - # we do not want to link against static libs, - # but need to link against shared - eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` - if test -n "$deplibrary_names" ; then - for tmp in $deplibrary_names ; do - depdepl=$tmp - done - if test -f "$path/$depdepl" ; then - depdepl="$path/$depdepl" - fi - # do not add paths which are already there - case " $newlib_search_path " in - *" $path "*) ;; - *) newlib_search_path="$newlib_search_path $path";; - esac - fi - path="" - ;; - *) - path="-L$path" - ;; - esac - ;; - -l*) - case $host in - *-*-darwin*) - # Again, we only want to link against shared libraries - eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"` - for tmp in $newlib_search_path ; do - if test -f "$tmp/lib$tmp_libs.dylib" ; then - eval depdepl="$tmp/lib$tmp_libs.dylib" - break - fi - done - path="" - ;; - *) continue ;; - esac - ;; - *) continue ;; - esac - case " $deplibs " in - *" $path "*) ;; - *) deplibs="$path $deplibs" ;; - esac - case " $deplibs " in - *" $depdepl "*) ;; - *) deplibs="$depdepl $deplibs" ;; - esac - done - fi # link_all_deplibs != no - fi # linkmode = lib - done # for deplib in $libs - dependency_libs="$newdependency_libs" - if test "$pass" = dlpreopen; then - # Link the dlpreopened libraries before other libraries - for deplib in $save_deplibs; do - deplibs="$deplib $deplibs" - done - fi - if test "$pass" != dlopen; then - if test "$pass" != conv; then - # Make sure lib_search_path contains only unique directories. - lib_search_path= - for dir in $newlib_search_path; do - case "$lib_search_path " in - *" $dir "*) ;; - *) lib_search_path="$lib_search_path $dir" ;; - esac - done - newlib_search_path= - fi - - if test "$linkmode,$pass" != "prog,link"; then - vars="deplibs" - else - vars="compile_deplibs finalize_deplibs" - fi - for var in $vars dependency_libs; do - # Add libraries to $var in reverse order - eval tmp_libs=\"\$$var\" - new_libs= - for deplib in $tmp_libs; do - # FIXME: Pedantically, this is the right thing to do, so - # that some nasty dependency loop isn't accidentally - # broken: - #new_libs="$deplib $new_libs" - # Pragmatically, this seems to cause very few problems in - # practice: - case $deplib in - -L*) new_libs="$deplib $new_libs" ;; - -R*) ;; - *) - # And here is the reason: when a library appears more - # than once as an explicit dependence of a library, or - # is implicitly linked in more than once by the - # compiler, it is considered special, and multiple - # occurrences thereof are not removed. Compare this - # with having the same library being listed as a - # dependency of multiple other libraries: in this case, - # we know (pedantically, we assume) the library does not - # need to be listed more than once, so we keep only the - # last copy. This is not always right, but it is rare - # enough that we require users that really mean to play - # such unportable linking tricks to link the library - # using -Wl,-lname, so that libtool does not consider it - # for duplicate removal. - case " $specialdeplibs " in - *" $deplib "*) new_libs="$deplib $new_libs" ;; - *) - case " $new_libs " in - *" $deplib "*) ;; - *) new_libs="$deplib $new_libs" ;; - esac - ;; - esac - ;; - esac - done - tmp_libs= - for deplib in $new_libs; do - case $deplib in - -L*) - case " $tmp_libs " in - *" $deplib "*) ;; - *) tmp_libs="$tmp_libs $deplib" ;; - esac - ;; - *) tmp_libs="$tmp_libs $deplib" ;; - esac - done - eval $var=\"$tmp_libs\" - done # for var - fi - # Last step: remove runtime libs from dependency_libs - # (they stay in deplibs) - tmp_libs= - for i in $dependency_libs ; do - case " $predeps $postdeps $compiler_lib_search_path " in - *" $i "*) - i="" - ;; - esac - if test -n "$i" ; then - tmp_libs="$tmp_libs $i" - fi - done - dependency_libs=$tmp_libs - done # for pass - if test "$linkmode" = prog; then - dlfiles="$newdlfiles" - dlprefiles="$newdlprefiles" - fi - - case $linkmode in - oldlib) - if test -n "$deplibs"; then - $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 - fi - - if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then - $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 - fi - - if test -n "$rpath"; then - $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 - fi - - if test -n "$xrpath"; then - $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 - fi - - if test -n "$vinfo"; then - $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2 - fi - - if test -n "$release"; then - $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 - fi - - if test -n "$export_symbols" || test -n "$export_symbols_regex"; then - $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 - fi - - # Now set the variables for building old libraries. - build_libtool_libs=no - oldlibs="$output" - objs="$objs$old_deplibs" - ;; - - lib) - # Make sure we only generate libraries of the form `libNAME.la'. - case $outputname in - lib*) - name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` - eval shared_ext=\"$shrext_cmds\" - eval libname=\"$libname_spec\" - ;; - *) - if test "$module" = no; then - $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - if test "$need_lib_prefix" != no; then - # Add the "lib" prefix for modules if required - name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` - eval shared_ext=\"$shrext_cmds\" - eval libname=\"$libname_spec\" - else - libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` - fi - ;; - esac - - if test -n "$objs"; then - if test "$deplibs_check_method" != pass_all; then - $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 - exit $EXIT_FAILURE - else - $echo - $echo "*** Warning: Linking the shared library $output against the non-libtool" - $echo "*** objects $objs is not portable!" - libobjs="$libobjs $objs" - fi - fi - - if test "$dlself" != no; then - $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 - fi - - set dummy $rpath - if test "$#" -gt 2; then - $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 - fi - install_libdir="$2" - - oldlibs= - if test -z "$rpath"; then - if test "$build_libtool_libs" = yes; then - # Building a libtool convenience library. - # Some compilers have problems with a `.al' extension so - # convenience libraries should have the same extension an - # archive normally would. - oldlibs="$output_objdir/$libname.$libext $oldlibs" - build_libtool_libs=convenience - build_old_libs=yes - fi - - if test -n "$vinfo"; then - $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2 - fi - - if test -n "$release"; then - $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 - fi - else - - # Parse the version information argument. - save_ifs="$IFS"; IFS=':' - set dummy $vinfo 0 0 0 - IFS="$save_ifs" - - if test -n "$8"; then - $echo "$modename: too many parameters to \`-version-info'" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - - # convert absolute version numbers to libtool ages - # this retains compatibility with .la files and attempts - # to make the code below a bit more comprehensible - - case $vinfo_number in - yes) - number_major="$2" - number_minor="$3" - number_revision="$4" - # - # There are really only two kinds -- those that - # use the current revision as the major version - # and those that subtract age and use age as - # a minor version. But, then there is irix - # which has an extra 1 added just for fun - # - case $version_type in - darwin|linux|osf|windows|none) - current=`expr $number_major + $number_minor` - age="$number_minor" - revision="$number_revision" - ;; - freebsd-aout|freebsd-elf|sunos) - current="$number_major" - revision="$number_minor" - age="0" - ;; - irix|nonstopux) - current=`expr $number_major + $number_minor` - age="$number_minor" - revision="$number_minor" - lt_irix_increment=no - ;; - *) - $echo "$modename: unknown library version type \`$version_type'" 1>&2 - $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 - exit $EXIT_FAILURE - ;; - esac - ;; - no) - current="$2" - revision="$3" - age="$4" - ;; - esac - - # Check that each of the things are valid numbers. - case $current in - 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; - *) - $echo "$modename: CURRENT \`$current' must be a nonnegative integer" 1>&2 - $echo "$modename: \`$vinfo' is not valid version information" 1>&2 - exit $EXIT_FAILURE - ;; - esac - - case $revision in - 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; - *) - $echo "$modename: REVISION \`$revision' must be a nonnegative integer" 1>&2 - $echo "$modename: \`$vinfo' is not valid version information" 1>&2 - exit $EXIT_FAILURE - ;; - esac - - case $age in - 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; - *) - $echo "$modename: AGE \`$age' must be a nonnegative integer" 1>&2 - $echo "$modename: \`$vinfo' is not valid version information" 1>&2 - exit $EXIT_FAILURE - ;; - esac - - if test "$age" -gt "$current"; then - $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 - $echo "$modename: \`$vinfo' is not valid version information" 1>&2 - exit $EXIT_FAILURE - fi - - # Calculate the version variables. - major= - versuffix= - verstring= - case $version_type in - none) ;; - - darwin) - # Like Linux, but with the current version available in - # verstring for coding it into the library header - major=.`expr $current - $age` - versuffix="$major.$age.$revision" - # Darwin ld doesn't like 0 for these options... - minor_current=`expr $current + 1` - xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" - verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" - ;; - - freebsd-aout) - major=".$current" - versuffix=".$current.$revision"; - ;; - - freebsd-elf) - major=".$current" - versuffix=".$current"; - ;; - - irix | nonstopux) - if test "X$lt_irix_increment" = "Xno"; then - major=`expr $current - $age` - else - major=`expr $current - $age + 1` - fi - case $version_type in - nonstopux) verstring_prefix=nonstopux ;; - *) verstring_prefix=sgi ;; - esac - verstring="$verstring_prefix$major.$revision" - - # Add in all the interfaces that we are compatible with. - loop=$revision - while test "$loop" -ne 0; do - iface=`expr $revision - $loop` - loop=`expr $loop - 1` - verstring="$verstring_prefix$major.$iface:$verstring" - done - - # Before this point, $major must not contain `.'. - major=.$major - versuffix="$major.$revision" - ;; - - linux) - major=.`expr $current - $age` - versuffix="$major.$age.$revision" - ;; - - osf) - major=.`expr $current - $age` - versuffix=".$current.$age.$revision" - verstring="$current.$age.$revision" - - # Add in all the interfaces that we are compatible with. - loop=$age - while test "$loop" -ne 0; do - iface=`expr $current - $loop` - loop=`expr $loop - 1` - verstring="$verstring:${iface}.0" - done - - # Make executables depend on our current version. - verstring="$verstring:${current}.0" - ;; - - sunos) - major=".$current" - versuffix=".$current.$revision" - ;; - - windows) - # Use '-' rather than '.', since we only want one - # extension on DOS 8.3 filesystems. - major=`expr $current - $age` - versuffix="-$major" - ;; - - *) - $echo "$modename: unknown library version type \`$version_type'" 1>&2 - $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 - exit $EXIT_FAILURE - ;; - esac - - # Clear the version info if we defaulted, and they specified a release. - if test -z "$vinfo" && test -n "$release"; then - major= - case $version_type in - darwin) - # we can't check for "0.0" in archive_cmds due to quoting - # problems, so we reset it completely - verstring= - ;; - *) - verstring="0.0" - ;; - esac - if test "$need_version" = no; then - versuffix= - else - versuffix=".0.0" - fi - fi - - # Remove version info from name if versioning should be avoided - if test "$avoid_version" = yes && test "$need_version" = no; then - major= - versuffix= - verstring="" - fi - - # Check to see if the archive will have undefined symbols. - if test "$allow_undefined" = yes; then - if test "$allow_undefined_flag" = unsupported; then - $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 - build_libtool_libs=no - build_old_libs=yes - fi - else - # Don't allow undefined symbols. - allow_undefined_flag="$no_undefined_flag" - fi - fi - - if test "$mode" != relink; then - # Remove our outputs, but don't remove object files since they - # may have been created when compiling PIC objects. - removelist= - tempremovelist=`$echo "$output_objdir/*"` - for p in $tempremovelist; do - case $p in - *.$objext) - ;; - $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) - if test "X$precious_files_regex" != "X"; then - if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 - then - continue - fi - fi - removelist="$removelist $p" - ;; - *) ;; - esac - done - if test -n "$removelist"; then - $show "${rm}r $removelist" - $run ${rm}r $removelist - fi - fi - - # Now set the variables for building old libraries. - if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then - oldlibs="$oldlibs $output_objdir/$libname.$libext" - - # Transform .lo files to .o files. - oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` - fi - - # Eliminate all temporary directories. - #for path in $notinst_path; do - # lib_search_path=`$echo "$lib_search_path " | ${SED} -e "s% $path % %g"` - # deplibs=`$echo "$deplibs " | ${SED} -e "s% -L$path % %g"` - # dependency_libs=`$echo "$dependency_libs " | ${SED} -e "s% -L$path % %g"` - #done - - if test -n "$xrpath"; then - # If the user specified any rpath flags, then add them. - temp_xrpath= - for libdir in $xrpath; do - temp_xrpath="$temp_xrpath -R$libdir" - case "$finalize_rpath " in - *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" ;; - esac - done - if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then - dependency_libs="$temp_xrpath $dependency_libs" - fi - fi - - # Make sure dlfiles contains only unique files that won't be dlpreopened - old_dlfiles="$dlfiles" - dlfiles= - for lib in $old_dlfiles; do - case " $dlprefiles $dlfiles " in - *" $lib "*) ;; - *) dlfiles="$dlfiles $lib" ;; - esac - done - - # Make sure dlprefiles contains only unique files - old_dlprefiles="$dlprefiles" - dlprefiles= - for lib in $old_dlprefiles; do - case "$dlprefiles " in - *" $lib "*) ;; - *) dlprefiles="$dlprefiles $lib" ;; - esac - done - - if test "$build_libtool_libs" = yes; then - if test -n "$rpath"; then - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) - # these systems don't actually have a c library (as such)! - ;; - *-*-rhapsody* | *-*-darwin1.[012]) - # Rhapsody C library is in the System framework - deplibs="$deplibs -framework System" - ;; - *-*-netbsd*) - # Don't link with libc until the a.out ld.so is fixed. - ;; - *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) - # Do not include libc due to us having libc/libc_r. - ;; - *-*-sco3.2v5* | *-*-sco5v6*) - # Causes problems with __ctype - ;; - *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) - # Compiler inserts libc in the correct place for threads to work - ;; - *) - # Add libc to deplibs on all other systems if necessary. - if test "$build_libtool_need_lc" = "yes"; then - deplibs="$deplibs -lc" - fi - ;; - esac - fi - - # Transform deplibs into only deplibs that can be linked in shared. - name_save=$name - libname_save=$libname - release_save=$release - versuffix_save=$versuffix - major_save=$major - # I'm not sure if I'm treating the release correctly. I think - # release should show up in the -l (ie -lgmp5) so we don't want to - # add it in twice. Is that correct? - release="" - versuffix="" - major="" - newdeplibs= - droppeddeps=no - case $deplibs_check_method in - pass_all) - # Don't check for shared/static. Everything works. - # This might be a little naive. We might want to check - # whether the library exists or not. But this is on - # osf3 & osf4 and I'm not really sure... Just - # implementing what was already the behavior. - newdeplibs=$deplibs - ;; - test_compile) - # This code stresses the "libraries are programs" paradigm to its - # limits. Maybe even breaks it. We compile a program, linking it - # against the deplibs as a proxy for the library. Then we can check - # whether they linked in statically or dynamically with ldd. - $rm conftest.c - cat > conftest.c </dev/null` - for potent_lib in $potential_libs; do - # Follow soft links. - if ls -lLd "$potent_lib" 2>/dev/null \ - | grep " -> " >/dev/null; then - continue - fi - # The statement above tries to avoid entering an - # endless loop below, in case of cyclic links. - # We might still enter an endless loop, since a link - # loop can be closed while we follow links, - # but so what? - potlib="$potent_lib" - while test -h "$potlib" 2>/dev/null; do - potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` - case $potliblink in - [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; - *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; - esac - done - if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ - | ${SED} 10q \ - | $EGREP "$file_magic_regex" > /dev/null; then - newdeplibs="$newdeplibs $a_deplib" - a_deplib="" - break 2 - fi - done - done - fi - if test -n "$a_deplib" ; then - droppeddeps=yes - $echo - $echo "*** Warning: linker path does not have real file for library $a_deplib." - $echo "*** I have the capability to make that library automatically link in when" - $echo "*** you link to this library. But I can only do this if you have a" - $echo "*** shared version of the library, which you do not appear to have" - $echo "*** because I did check the linker path looking for a file starting" - if test -z "$potlib" ; then - $echo "*** with $libname but no candidates were found. (...for file magic test)" - else - $echo "*** with $libname and none of the candidates passed a file format test" - $echo "*** using a file magic. Last file checked: $potlib" - fi - fi - else - # Add a -L argument. - newdeplibs="$newdeplibs $a_deplib" - fi - done # Gone through all deplibs. - ;; - match_pattern*) - set dummy $deplibs_check_method - match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` - for a_deplib in $deplibs; do - name=`expr $a_deplib : '-l\(.*\)'` - # If $name is empty we are operating on a -L argument. - if test -n "$name" && test "$name" != "0"; then - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - case " $predeps $postdeps " in - *" $a_deplib "*) - newdeplibs="$newdeplibs $a_deplib" - a_deplib="" - ;; - esac - fi - if test -n "$a_deplib" ; then - libname=`eval \\$echo \"$libname_spec\"` - for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do - potential_libs=`ls $i/$libname[.-]* 2>/dev/null` - for potent_lib in $potential_libs; do - potlib="$potent_lib" # see symlink-check above in file_magic test - if eval $echo \"$potent_lib\" 2>/dev/null \ - | ${SED} 10q \ - | $EGREP "$match_pattern_regex" > /dev/null; then - newdeplibs="$newdeplibs $a_deplib" - a_deplib="" - break 2 - fi - done - done - fi - if test -n "$a_deplib" ; then - droppeddeps=yes - $echo - $echo "*** Warning: linker path does not have real file for library $a_deplib." - $echo "*** I have the capability to make that library automatically link in when" - $echo "*** you link to this library. But I can only do this if you have a" - $echo "*** shared version of the library, which you do not appear to have" - $echo "*** because I did check the linker path looking for a file starting" - if test -z "$potlib" ; then - $echo "*** with $libname but no candidates were found. (...for regex pattern test)" - else - $echo "*** with $libname and none of the candidates passed a file format test" - $echo "*** using a regex pattern. Last file checked: $potlib" - fi - fi - else - # Add a -L argument. - newdeplibs="$newdeplibs $a_deplib" - fi - done # Gone through all deplibs. - ;; - none | unknown | *) - newdeplibs="" - tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ - -e 's/ -[LR][^ ]*//g'` - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - for i in $predeps $postdeps ; do - # can't use Xsed below, because $i might contain '/' - tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"` - done - fi - if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \ - | grep . >/dev/null; then - $echo - if test "X$deplibs_check_method" = "Xnone"; then - $echo "*** Warning: inter-library dependencies are not supported in this platform." - else - $echo "*** Warning: inter-library dependencies are not known to be supported." - fi - $echo "*** All declared inter-library dependencies are being dropped." - droppeddeps=yes - fi - ;; - esac - versuffix=$versuffix_save - major=$major_save - release=$release_save - libname=$libname_save - name=$name_save - - case $host in - *-*-rhapsody* | *-*-darwin1.[012]) - # On Rhapsody replace the C library is the System framework - newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` - ;; - esac - - if test "$droppeddeps" = yes; then - if test "$module" = yes; then - $echo - $echo "*** Warning: libtool could not satisfy all declared inter-library" - $echo "*** dependencies of module $libname. Therefore, libtool will create" - $echo "*** a static module, that should work as long as the dlopening" - $echo "*** application is linked with the -dlopen flag." - if test -z "$global_symbol_pipe"; then - $echo - $echo "*** However, this would only work if libtool was able to extract symbol" - $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" - $echo "*** not find such a program. So, this module is probably useless." - $echo "*** \`nm' from GNU binutils and a full rebuild may help." - fi - if test "$build_old_libs" = no; then - oldlibs="$output_objdir/$libname.$libext" - build_libtool_libs=module - build_old_libs=yes - else - build_libtool_libs=no - fi - else - $echo "*** The inter-library dependencies that have been dropped here will be" - $echo "*** automatically added whenever a program is linked with this library" - $echo "*** or is declared to -dlopen it." - - if test "$allow_undefined" = no; then - $echo - $echo "*** Since this library must not contain undefined symbols," - $echo "*** because either the platform does not support them or" - $echo "*** it was explicitly requested with -no-undefined," - $echo "*** libtool will only create a static version of it." - if test "$build_old_libs" = no; then - oldlibs="$output_objdir/$libname.$libext" - build_libtool_libs=module - build_old_libs=yes - else - build_libtool_libs=no - fi - fi - fi - fi - # Done checking deplibs! - deplibs=$newdeplibs - fi - - - # move library search paths that coincide with paths to not yet - # installed libraries to the beginning of the library search list - new_libs= - for path in $notinst_path; do - case " $new_libs " in - *" -L$path/$objdir "*) ;; - *) - case " $deplibs " in - *" -L$path/$objdir "*) - new_libs="$new_libs -L$path/$objdir" ;; - esac - ;; - esac - done - for deplib in $deplibs; do - case $deplib in - -L*) - case " $new_libs " in - *" $deplib "*) ;; - *) new_libs="$new_libs $deplib" ;; - esac - ;; - *) new_libs="$new_libs $deplib" ;; - esac - done - deplibs="$new_libs" - - - # All the library-specific variables (install_libdir is set above). - library_names= - old_library= - dlname= - - # Test again, we may have decided not to build it any more - if test "$build_libtool_libs" = yes; then - if test "$hardcode_into_libs" = yes; then - # Hardcode the library paths - hardcode_libdirs= - dep_rpath= - rpath="$finalize_rpath" - test "$mode" != relink && rpath="$compile_rpath$rpath" - for libdir in $rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - if test -z "$hardcode_libdirs"; then - hardcode_libdirs="$libdir" - else - # Just accumulate the unique libdirs. - case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval flag=\"$hardcode_libdir_flag_spec\" - dep_rpath="$dep_rpath $flag" - fi - elif test -n "$runpath_var"; then - case "$perm_rpath " in - *" $libdir "*) ;; - *) perm_rpath="$perm_rpath $libdir" ;; - esac - fi - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir="$hardcode_libdirs" - if test -n "$hardcode_libdir_flag_spec_ld"; then - case $archive_cmds in - *\$LD*) eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" ;; - *) eval dep_rpath=\"$hardcode_libdir_flag_spec\" ;; - esac - else - eval dep_rpath=\"$hardcode_libdir_flag_spec\" - fi - fi - if test -n "$runpath_var" && test -n "$perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $perm_rpath; do - rpath="$rpath$dir:" - done - eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" - fi - test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" - fi - - shlibpath="$finalize_shlibpath" - test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" - if test -n "$shlibpath"; then - eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" - fi - - # Get the real and link names of the library. - eval shared_ext=\"$shrext_cmds\" - eval library_names=\"$library_names_spec\" - set dummy $library_names - realname="$2" - shift; shift - - if test -n "$soname_spec"; then - eval soname=\"$soname_spec\" - else - soname="$realname" - fi - if test -z "$dlname"; then - dlname=$soname - fi - - lib="$output_objdir/$realname" - linknames= - for link - do - linknames="$linknames $link" - done - - # Use standard objects if they are pic - test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` - - # Prepare the list of exported symbols - if test -z "$export_symbols"; then - if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then - $show "generating symbol list for \`$libname.la'" - export_symbols="$output_objdir/$libname.exp" - $run $rm $export_symbols - cmds=$export_symbols_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - if len=`expr "X$cmd" : ".*"` && - test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then - $show "$cmd" - $run eval "$cmd" || exit $? - skipped_export=false - else - # The command line is too long to execute in one step. - $show "using reloadable object file for export list..." - skipped_export=: - # Break out early, otherwise skipped_export may be - # set to false by a later but shorter cmd. - break - fi - done - IFS="$save_ifs" - if test -n "$export_symbols_regex"; then - $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" - $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' - $show "$mv \"${export_symbols}T\" \"$export_symbols\"" - $run eval '$mv "${export_symbols}T" "$export_symbols"' - fi - fi - fi - - if test -n "$export_symbols" && test -n "$include_expsyms"; then - $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' - fi - - tmp_deplibs= - for test_deplib in $deplibs; do - case " $convenience " in - *" $test_deplib "*) ;; - *) - tmp_deplibs="$tmp_deplibs $test_deplib" - ;; - esac - done - deplibs="$tmp_deplibs" - - if test -n "$convenience"; then - if test -n "$whole_archive_flag_spec"; then - save_libobjs=$libobjs - eval libobjs=\"\$libobjs $whole_archive_flag_spec\" - else - gentop="$output_objdir/${outputname}x" - generated="$generated $gentop" - - func_extract_archives $gentop $convenience - libobjs="$libobjs $func_extract_archives_result" - fi - fi - - if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then - eval flag=\"$thread_safe_flag_spec\" - linker_flags="$linker_flags $flag" - fi - - # Make a backup of the uninstalled library when relinking - if test "$mode" = relink; then - $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? - fi - - # Do each of the archive commands. - if test "$module" = yes && test -n "$module_cmds" ; then - if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then - eval test_cmds=\"$module_expsym_cmds\" - cmds=$module_expsym_cmds - else - eval test_cmds=\"$module_cmds\" - cmds=$module_cmds - fi - else - if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then - eval test_cmds=\"$archive_expsym_cmds\" - cmds=$archive_expsym_cmds - else - eval test_cmds=\"$archive_cmds\" - cmds=$archive_cmds - fi - fi - - if test "X$skipped_export" != "X:" && - len=`expr "X$test_cmds" : ".*" 2>/dev/null` && - test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then - : - else - # The command line is too long to link in one step, link piecewise. - $echo "creating reloadable object files..." - - # Save the value of $output and $libobjs because we want to - # use them later. If we have whole_archive_flag_spec, we - # want to use save_libobjs as it was before - # whole_archive_flag_spec was expanded, because we can't - # assume the linker understands whole_archive_flag_spec. - # This may have to be revisited, in case too many - # convenience libraries get linked in and end up exceeding - # the spec. - if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then - save_libobjs=$libobjs - fi - save_output=$output - output_la=`$echo "X$output" | $Xsed -e "$basename"` - - # Clear the reloadable object creation command queue and - # initialize k to one. - test_cmds= - concat_cmds= - objlist= - delfiles= - last_robj= - k=1 - output=$output_objdir/$output_la-${k}.$objext - # Loop over the list of objects to be linked. - for obj in $save_libobjs - do - eval test_cmds=\"$reload_cmds $objlist $last_robj\" - if test "X$objlist" = X || - { len=`expr "X$test_cmds" : ".*" 2>/dev/null` && - test "$len" -le "$max_cmd_len"; }; then - objlist="$objlist $obj" - else - # The command $test_cmds is almost too long, add a - # command to the queue. - if test "$k" -eq 1 ; then - # The first file doesn't have a previous command to add. - eval concat_cmds=\"$reload_cmds $objlist $last_robj\" - else - # All subsequent reloadable object files will link in - # the last one created. - eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\" - fi - last_robj=$output_objdir/$output_la-${k}.$objext - k=`expr $k + 1` - output=$output_objdir/$output_la-${k}.$objext - objlist=$obj - len=1 - fi - done - # Handle the remaining objects by creating one last - # reloadable object file. All subsequent reloadable object - # files will link in the last one created. - test -z "$concat_cmds" || concat_cmds=$concat_cmds~ - eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" - - if ${skipped_export-false}; then - $show "generating symbol list for \`$libname.la'" - export_symbols="$output_objdir/$libname.exp" - $run $rm $export_symbols - libobjs=$output - # Append the command to create the export file. - eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\" - fi - - # Set up a command to remove the reloadable object files - # after they are used. - i=0 - while test "$i" -lt "$k" - do - i=`expr $i + 1` - delfiles="$delfiles $output_objdir/$output_la-${i}.$objext" - done - - $echo "creating a temporary reloadable object file: $output" - - # Loop through the commands generated above and execute them. - save_ifs="$IFS"; IFS='~' - for cmd in $concat_cmds; do - IFS="$save_ifs" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - - libobjs=$output - # Restore the value of output. - output=$save_output - - if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then - eval libobjs=\"\$libobjs $whole_archive_flag_spec\" - fi - # Expand the library linking commands again to reset the - # value of $libobjs for piecewise linking. - - # Do each of the archive commands. - if test "$module" = yes && test -n "$module_cmds" ; then - if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then - cmds=$module_expsym_cmds - else - cmds=$module_cmds - fi - else - if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then - cmds=$archive_expsym_cmds - else - cmds=$archive_cmds - fi - fi - - # Append the command to remove the reloadable object files - # to the just-reset $cmds. - eval cmds=\"\$cmds~\$rm $delfiles\" - fi - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || { - lt_exit=$? - - # Restore the uninstalled library and exit - if test "$mode" = relink; then - $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' - fi - - exit $lt_exit - } - done - IFS="$save_ifs" - - # Restore the uninstalled library and exit - if test "$mode" = relink; then - $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? - - if test -n "$convenience"; then - if test -z "$whole_archive_flag_spec"; then - $show "${rm}r $gentop" - $run ${rm}r "$gentop" - fi - fi - - exit $EXIT_SUCCESS - fi - - # Create links to the real library. - for linkname in $linknames; do - if test "$realname" != "$linkname"; then - $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" - $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? - fi - done - - # If -module or -export-dynamic was specified, set the dlname. - if test "$module" = yes || test "$export_dynamic" = yes; then - # On all known operating systems, these are identical. - dlname="$soname" - fi - fi - ;; - - obj) - if test -n "$deplibs"; then - $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 - fi - - if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then - $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 - fi - - if test -n "$rpath"; then - $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 - fi - - if test -n "$xrpath"; then - $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 - fi - - if test -n "$vinfo"; then - $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 - fi - - if test -n "$release"; then - $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 - fi - - case $output in - *.lo) - if test -n "$objs$old_deplibs"; then - $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 - exit $EXIT_FAILURE - fi - libobj="$output" - obj=`$echo "X$output" | $Xsed -e "$lo2o"` - ;; - *) - libobj= - obj="$output" - ;; - esac - - # Delete the old objects. - $run $rm $obj $libobj - - # Objects from convenience libraries. This assumes - # single-version convenience libraries. Whenever we create - # different ones for PIC/non-PIC, this we'll have to duplicate - # the extraction. - reload_conv_objs= - gentop= - # reload_cmds runs $LD directly, so let us get rid of - # -Wl from whole_archive_flag_spec and hope we can get by with - # turning comma into space.. - wl= - - if test -n "$convenience"; then - if test -n "$whole_archive_flag_spec"; then - eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" - reload_conv_objs=$reload_objs\ `$echo "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'` - else - gentop="$output_objdir/${obj}x" - generated="$generated $gentop" - - func_extract_archives $gentop $convenience - reload_conv_objs="$reload_objs $func_extract_archives_result" - fi - fi - - # Create the old-style object. - reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test - - output="$obj" - cmds=$reload_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - - # Exit if we aren't doing a library object file. - if test -z "$libobj"; then - if test -n "$gentop"; then - $show "${rm}r $gentop" - $run ${rm}r $gentop - fi - - exit $EXIT_SUCCESS - fi - - if test "$build_libtool_libs" != yes; then - if test -n "$gentop"; then - $show "${rm}r $gentop" - $run ${rm}r $gentop - fi - - # Create an invalid libtool object if no PIC, so that we don't - # accidentally link it into a program. - # $show "echo timestamp > $libobj" - # $run eval "echo timestamp > $libobj" || exit $? - exit $EXIT_SUCCESS - fi - - if test -n "$pic_flag" || test "$pic_mode" != default; then - # Only do commands if we really have different PIC objects. - reload_objs="$libobjs $reload_conv_objs" - output="$libobj" - cmds=$reload_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - fi - - if test -n "$gentop"; then - $show "${rm}r $gentop" - $run ${rm}r $gentop - fi - - exit $EXIT_SUCCESS - ;; - - prog) - case $host in - *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;; - esac - if test -n "$vinfo"; then - $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 - fi - - if test -n "$release"; then - $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 - fi - - if test "$preload" = yes; then - if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && - test "$dlopen_self_static" = unknown; then - $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." - fi - fi - - case $host in - *-*-rhapsody* | *-*-darwin1.[012]) - # On Rhapsody replace the C library is the System framework - compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` - finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` - ;; - esac - - case $host in - *darwin*) - # Don't allow lazy linking, it breaks C++ global constructors - if test "$tagname" = CXX ; then - compile_command="$compile_command ${wl}-bind_at_load" - finalize_command="$finalize_command ${wl}-bind_at_load" - fi - ;; - esac - - - # move library search paths that coincide with paths to not yet - # installed libraries to the beginning of the library search list - new_libs= - for path in $notinst_path; do - case " $new_libs " in - *" -L$path/$objdir "*) ;; - *) - case " $compile_deplibs " in - *" -L$path/$objdir "*) - new_libs="$new_libs -L$path/$objdir" ;; - esac - ;; - esac - done - for deplib in $compile_deplibs; do - case $deplib in - -L*) - case " $new_libs " in - *" $deplib "*) ;; - *) new_libs="$new_libs $deplib" ;; - esac - ;; - *) new_libs="$new_libs $deplib" ;; - esac - done - compile_deplibs="$new_libs" - - - compile_command="$compile_command $compile_deplibs" - finalize_command="$finalize_command $finalize_deplibs" - - if test -n "$rpath$xrpath"; then - # If the user specified any rpath flags, then add them. - for libdir in $rpath $xrpath; do - # This is the magic to use -rpath. - case "$finalize_rpath " in - *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" ;; - esac - done - fi - - # Now hardcode the library paths - rpath= - hardcode_libdirs= - for libdir in $compile_rpath $finalize_rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - if test -z "$hardcode_libdirs"; then - hardcode_libdirs="$libdir" - else - # Just accumulate the unique libdirs. - case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval flag=\"$hardcode_libdir_flag_spec\" - rpath="$rpath $flag" - fi - elif test -n "$runpath_var"; then - case "$perm_rpath " in - *" $libdir "*) ;; - *) perm_rpath="$perm_rpath $libdir" ;; - esac - fi - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) - testbindir=`$echo "X$libdir" | $Xsed -e 's*/lib$*/bin*'` - case :$dllsearchpath: in - *":$libdir:"*) ;; - *) dllsearchpath="$dllsearchpath:$libdir";; - esac - case :$dllsearchpath: in - *":$testbindir:"*) ;; - *) dllsearchpath="$dllsearchpath:$testbindir";; - esac - ;; - esac - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir="$hardcode_libdirs" - eval rpath=\" $hardcode_libdir_flag_spec\" - fi - compile_rpath="$rpath" - - rpath= - hardcode_libdirs= - for libdir in $finalize_rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - if test -z "$hardcode_libdirs"; then - hardcode_libdirs="$libdir" - else - # Just accumulate the unique libdirs. - case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval flag=\"$hardcode_libdir_flag_spec\" - rpath="$rpath $flag" - fi - elif test -n "$runpath_var"; then - case "$finalize_perm_rpath " in - *" $libdir "*) ;; - *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; - esac - fi - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir="$hardcode_libdirs" - eval rpath=\" $hardcode_libdir_flag_spec\" - fi - finalize_rpath="$rpath" - - if test -n "$libobjs" && test "$build_old_libs" = yes; then - # Transform all the library objects into standard objects. - compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` - finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` - fi - - dlsyms= - if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then - if test -n "$NM" && test -n "$global_symbol_pipe"; then - dlsyms="${outputname}S.c" - else - $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 - fi - fi - - if test -n "$dlsyms"; then - case $dlsyms in - "") ;; - *.c) - # Discover the nlist of each of the dlfiles. - nlist="$output_objdir/${outputname}.nm" - - $show "$rm $nlist ${nlist}S ${nlist}T" - $run $rm "$nlist" "${nlist}S" "${nlist}T" - - # Parse the name list into a source file. - $show "creating $output_objdir/$dlsyms" - - test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ -/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ -/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ - -#ifdef __cplusplus -extern \"C\" { -#endif - -/* Prevent the only kind of declaration conflicts we can make. */ -#define lt_preloaded_symbols some_other_symbol - -/* External symbol declarations for the compiler. */\ -" - - if test "$dlself" = yes; then - $show "generating symbol list for \`$output'" - - test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" - - # Add our own program objects to the symbol list. - progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` - for arg in $progfiles; do - $show "extracting global C symbols from \`$arg'" - $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" - done - - if test -n "$exclude_expsyms"; then - $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' - $run eval '$mv "$nlist"T "$nlist"' - fi - - if test -n "$export_symbols_regex"; then - $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' - $run eval '$mv "$nlist"T "$nlist"' - fi - - # Prepare the list of exported symbols - if test -z "$export_symbols"; then - export_symbols="$output_objdir/$outputname.exp" - $run $rm $export_symbols - $run eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' - case $host in - *cygwin* | *mingw* ) - $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' - $run eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' - ;; - esac - else - $run eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' - $run eval 'grep -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' - $run eval 'mv "$nlist"T "$nlist"' - case $host in - *cygwin* | *mingw* ) - $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' - $run eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' - ;; - esac - fi - fi - - for arg in $dlprefiles; do - $show "extracting global C symbols from \`$arg'" - name=`$echo "$arg" | ${SED} -e 's%^.*/%%'` - $run eval '$echo ": $name " >> "$nlist"' - $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" - done - - if test -z "$run"; then - # Make sure we have at least an empty file. - test -f "$nlist" || : > "$nlist" - - if test -n "$exclude_expsyms"; then - $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T - $mv "$nlist"T "$nlist" - fi - - # Try sorting and uniquifying the output. - if grep -v "^: " < "$nlist" | - if sort -k 3 /dev/null 2>&1; then - sort -k 3 - else - sort +2 - fi | - uniq > "$nlist"S; then - : - else - grep -v "^: " < "$nlist" > "$nlist"S - fi - - if test -f "$nlist"S; then - eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' - else - $echo '/* NONE */' >> "$output_objdir/$dlsyms" - fi - - $echo >> "$output_objdir/$dlsyms" "\ - -#undef lt_preloaded_symbols - -#if defined (__STDC__) && __STDC__ -# define lt_ptr void * -#else -# define lt_ptr char * -# define const -#endif - -/* The mapping between symbol names and symbols. */ -" - - case $host in - *cygwin* | *mingw* ) - $echo >> "$output_objdir/$dlsyms" "\ -/* DATA imports from DLLs on WIN32 can't be const, because - runtime relocations are performed -- see ld's documentation - on pseudo-relocs */ -struct { -" - ;; - * ) - $echo >> "$output_objdir/$dlsyms" "\ -const struct { -" - ;; - esac - - - $echo >> "$output_objdir/$dlsyms" "\ - const char *name; - lt_ptr address; -} -lt_preloaded_symbols[] = -{\ -" - - eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms" - - $echo >> "$output_objdir/$dlsyms" "\ - {0, (lt_ptr) 0} -}; - -/* This works around a problem in FreeBSD linker */ -#ifdef FREEBSD_WORKAROUND -static const void *lt_preloaded_setup() { - return lt_preloaded_symbols; -} -#endif - -#ifdef __cplusplus -} -#endif\ -" - fi - - pic_flag_for_symtable= - case $host in - # compiling the symbol table file with pic_flag works around - # a FreeBSD bug that causes programs to crash when -lm is - # linked before any other PIC object. But we must not use - # pic_flag when linking with -static. The problem exists in - # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. - *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) - case "$compile_command " in - *" -static "*) ;; - *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";; - esac;; - *-*-hpux*) - case "$compile_command " in - *" -static "*) ;; - *) pic_flag_for_symtable=" $pic_flag";; - esac - esac - - # Now compile the dynamic symbol file. - $show "(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" - $run eval '(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? - - # Clean up the generated files. - $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" - $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" - - # Transform the symbol file into the correct name. - case $host in - *cygwin* | *mingw* ) - if test -f "$output_objdir/${outputname}.def" ; then - compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%" | $NL2SP` - finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%" | $NL2SP` - else - compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` - finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` - fi - ;; - * ) - compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` - finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` - ;; - esac - ;; - *) - $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 - exit $EXIT_FAILURE - ;; - esac - else - # We keep going just in case the user didn't refer to - # lt_preloaded_symbols. The linker will fail if global_symbol_pipe - # really was required. - - # Nullify the symbol file. - compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s% @SYMFILE@%%" | $NL2SP` - finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s% @SYMFILE@%%" | $NL2SP` - fi - - if test "$need_relink" = no || test "$build_libtool_libs" != yes; then - # Replace the output file specification. - compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e 's%@OUTPUT@%'"$output"'%g' | $NL2SP` - link_command="$compile_command$compile_rpath" - - # We have no uninstalled library dependencies, so finalize right now. - $show "$link_command" - $run eval "$link_command" - exit_status=$? - - # Delete the generated files. - if test -n "$dlsyms"; then - $show "$rm $output_objdir/${outputname}S.${objext}" - $run $rm "$output_objdir/${outputname}S.${objext}" - fi - - exit $exit_status - fi - - if test -n "$shlibpath_var"; then - # We should set the shlibpath_var - rpath= - for dir in $temp_rpath; do - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) - # Absolute path. - rpath="$rpath$dir:" - ;; - *) - # Relative path: add a thisdir entry. - rpath="$rpath\$thisdir/$dir:" - ;; - esac - done - temp_rpath="$rpath" - fi - - if test -n "$compile_shlibpath$finalize_shlibpath"; then - compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" - fi - if test -n "$finalize_shlibpath"; then - finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" - fi - - compile_var= - finalize_var= - if test -n "$runpath_var"; then - if test -n "$perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $perm_rpath; do - rpath="$rpath$dir:" - done - compile_var="$runpath_var=\"$rpath\$$runpath_var\" " - fi - if test -n "$finalize_perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $finalize_perm_rpath; do - rpath="$rpath$dir:" - done - finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " - fi - fi - - if test "$no_install" = yes; then - # We don't need to create a wrapper script. - link_command="$compile_var$compile_command$compile_rpath" - # Replace the output file specification. - link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` - # Delete the old output file. - $run $rm $output - # Link the executable and exit - $show "$link_command" - $run eval "$link_command" || exit $? - exit $EXIT_SUCCESS - fi - - if test "$hardcode_action" = relink; then - # Fast installation is not supported - link_command="$compile_var$compile_command$compile_rpath" - relink_command="$finalize_var$finalize_command$finalize_rpath" - - $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 - $echo "$modename: \`$output' will be relinked during installation" 1>&2 - else - if test "$fast_install" != no; then - link_command="$finalize_var$compile_command$finalize_rpath" - if test "$fast_install" = yes; then - relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $SP2NL | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g' | $NL2SP` - else - # fast_install is set to needless - relink_command= - fi - else - link_command="$compile_var$compile_command$compile_rpath" - relink_command="$finalize_var$finalize_command$finalize_rpath" - fi - fi - - # Replace the output file specification. - link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` - - # Delete the old output files. - $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname - - $show "$link_command" - $run eval "$link_command" || exit $? - - # Now create the wrapper script. - $show "creating $output" - - # Quote the relink command for shipping. - if test -n "$relink_command"; then - # Preserve any variables that may affect compiler behavior - for var in $variables_saved_for_relink; do - if eval test -z \"\${$var+set}\"; then - relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" - elif eval var_value=\$$var; test -z "$var_value"; then - relink_command="$var=; export $var; $relink_command" - else - var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` - relink_command="$var=\"$var_value\"; export $var; $relink_command" - fi - done - relink_command="(cd `pwd`; $relink_command)" - relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e "$sed_quote_subst" | $NL2SP` - fi - - # Quote $echo for shipping. - if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then - case $progpath in - [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; - *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; - esac - qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` - else - qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` - fi - - # Only actually do things if our run command is non-null. - if test -z "$run"; then - # win32 will think the script is a binary if it has - # a .exe suffix, so we strip it off here. - case $output in - *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;; - esac - # test for cygwin because mv fails w/o .exe extensions - case $host in - *cygwin*) - exeext=.exe - outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;; - *) exeext= ;; - esac - case $host in - *cygwin* | *mingw* ) - output_name=`basename $output` - output_path=`dirname $output` - cwrappersource="$output_path/$objdir/lt-$output_name.c" - cwrapper="$output_path/$output_name.exe" - $rm $cwrappersource $cwrapper - trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 - - cat > $cwrappersource <> $cwrappersource<<"EOF" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(PATH_MAX) -# define LT_PATHMAX PATH_MAX -#elif defined(MAXPATHLEN) -# define LT_PATHMAX MAXPATHLEN -#else -# define LT_PATHMAX 1024 -#endif - -#ifndef DIR_SEPARATOR -# define DIR_SEPARATOR '/' -# define PATH_SEPARATOR ':' -#endif - -#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ - defined (__OS2__) -# define HAVE_DOS_BASED_FILE_SYSTEM -# ifndef DIR_SEPARATOR_2 -# define DIR_SEPARATOR_2 '\\' -# endif -# ifndef PATH_SEPARATOR_2 -# define PATH_SEPARATOR_2 ';' -# endif -#endif - -#ifndef DIR_SEPARATOR_2 -# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) -#else /* DIR_SEPARATOR_2 */ -# define IS_DIR_SEPARATOR(ch) \ - (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) -#endif /* DIR_SEPARATOR_2 */ - -#ifndef PATH_SEPARATOR_2 -# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) -#else /* PATH_SEPARATOR_2 */ -# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) -#endif /* PATH_SEPARATOR_2 */ - -#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) -#define XFREE(stale) do { \ - if (stale) { free ((void *) stale); stale = 0; } \ -} while (0) - -/* -DDEBUG is fairly common in CFLAGS. */ -#undef DEBUG -#if defined DEBUGWRAPPER -# define DEBUG(format, ...) fprintf(stderr, format, __VA_ARGS__) -#else -# define DEBUG(format, ...) -#endif - -const char *program_name = NULL; - -void * xmalloc (size_t num); -char * xstrdup (const char *string); -const char * base_name (const char *name); -char * find_executable(const char *wrapper); -int check_executable(const char *path); -char * strendzap(char *str, const char *pat); -void lt_fatal (const char *message, ...); - -int -main (int argc, char *argv[]) -{ - char **newargz; - int i; - - program_name = (char *) xstrdup (base_name (argv[0])); - DEBUG("(main) argv[0] : %s\n",argv[0]); - DEBUG("(main) program_name : %s\n",program_name); - newargz = XMALLOC(char *, argc+2); -EOF - - cat >> $cwrappersource <> $cwrappersource <<"EOF" - newargz[1] = find_executable(argv[0]); - if (newargz[1] == NULL) - lt_fatal("Couldn't find %s", argv[0]); - DEBUG("(main) found exe at : %s\n",newargz[1]); - /* we know the script has the same name, without the .exe */ - /* so make sure newargz[1] doesn't end in .exe */ - strendzap(newargz[1],".exe"); - for (i = 1; i < argc; i++) - newargz[i+1] = xstrdup(argv[i]); - newargz[argc+1] = NULL; - - for (i=0; i> $cwrappersource <> $cwrappersource <> $cwrappersource <<"EOF" - return 127; -} - -void * -xmalloc (size_t num) -{ - void * p = (void *) malloc (num); - if (!p) - lt_fatal ("Memory exhausted"); - - return p; -} - -char * -xstrdup (const char *string) -{ - return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL -; -} - -const char * -base_name (const char *name) -{ - const char *base; - -#if defined (HAVE_DOS_BASED_FILE_SYSTEM) - /* Skip over the disk name in MSDOS pathnames. */ - if (isalpha ((unsigned char)name[0]) && name[1] == ':') - name += 2; -#endif - - for (base = name; *name; name++) - if (IS_DIR_SEPARATOR (*name)) - base = name + 1; - return base; -} - -int -check_executable(const char * path) -{ - struct stat st; - - DEBUG("(check_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!"); - if ((!path) || (!*path)) - return 0; - - if ((stat (path, &st) >= 0) && - ( - /* MinGW & native WIN32 do not support S_IXOTH or S_IXGRP */ -#if defined (S_IXOTH) - ((st.st_mode & S_IXOTH) == S_IXOTH) || -#endif -#if defined (S_IXGRP) - ((st.st_mode & S_IXGRP) == S_IXGRP) || -#endif - ((st.st_mode & S_IXUSR) == S_IXUSR)) - ) - return 1; - else - return 0; -} - -/* Searches for the full path of the wrapper. Returns - newly allocated full path name if found, NULL otherwise */ -char * -find_executable (const char* wrapper) -{ - int has_slash = 0; - const char* p; - const char* p_next; - /* static buffer for getcwd */ - char tmp[LT_PATHMAX + 1]; - int tmp_len; - char* concat_name; - - DEBUG("(find_executable) : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!"); - - if ((wrapper == NULL) || (*wrapper == '\0')) - return NULL; - - /* Absolute path? */ -#if defined (HAVE_DOS_BASED_FILE_SYSTEM) - if (isalpha ((unsigned char)wrapper[0]) && wrapper[1] == ':') - { - concat_name = xstrdup (wrapper); - if (check_executable(concat_name)) - return concat_name; - XFREE(concat_name); - } - else - { -#endif - if (IS_DIR_SEPARATOR (wrapper[0])) - { - concat_name = xstrdup (wrapper); - if (check_executable(concat_name)) - return concat_name; - XFREE(concat_name); - } -#if defined (HAVE_DOS_BASED_FILE_SYSTEM) - } -#endif - - for (p = wrapper; *p; p++) - if (*p == '/') - { - has_slash = 1; - break; - } - if (!has_slash) - { - /* no slashes; search PATH */ - const char* path = getenv ("PATH"); - if (path != NULL) - { - for (p = path; *p; p = p_next) - { - const char* q; - size_t p_len; - for (q = p; *q; q++) - if (IS_PATH_SEPARATOR(*q)) - break; - p_len = q - p; - p_next = (*q == '\0' ? q : q + 1); - if (p_len == 0) - { - /* empty path: current directory */ - if (getcwd (tmp, LT_PATHMAX) == NULL) - lt_fatal ("getcwd failed"); - tmp_len = strlen(tmp); - concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); - memcpy (concat_name, tmp, tmp_len); - concat_name[tmp_len] = '/'; - strcpy (concat_name + tmp_len + 1, wrapper); - } - else - { - concat_name = XMALLOC(char, p_len + 1 + strlen(wrapper) + 1); - memcpy (concat_name, p, p_len); - concat_name[p_len] = '/'; - strcpy (concat_name + p_len + 1, wrapper); - } - if (check_executable(concat_name)) - return concat_name; - XFREE(concat_name); - } - } - /* not found in PATH; assume curdir */ - } - /* Relative path | not found in path: prepend cwd */ - if (getcwd (tmp, LT_PATHMAX) == NULL) - lt_fatal ("getcwd failed"); - tmp_len = strlen(tmp); - concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); - memcpy (concat_name, tmp, tmp_len); - concat_name[tmp_len] = '/'; - strcpy (concat_name + tmp_len + 1, wrapper); - - if (check_executable(concat_name)) - return concat_name; - XFREE(concat_name); - return NULL; -} - -char * -strendzap(char *str, const char *pat) -{ - size_t len, patlen; - - assert(str != NULL); - assert(pat != NULL); - - len = strlen(str); - patlen = strlen(pat); - - if (patlen <= len) - { - str += len - patlen; - if (strcmp(str, pat) == 0) - *str = '\0'; - } - return str; -} - -static void -lt_error_core (int exit_status, const char * mode, - const char * message, va_list ap) -{ - fprintf (stderr, "%s: %s: ", program_name, mode); - vfprintf (stderr, message, ap); - fprintf (stderr, ".\n"); - - if (exit_status >= 0) - exit (exit_status); -} - -void -lt_fatal (const char *message, ...) -{ - va_list ap; - va_start (ap, message); - lt_error_core (EXIT_FAILURE, "FATAL", message, ap); - va_end (ap); -} -EOF - # we should really use a build-platform specific compiler - # here, but OTOH, the wrappers (shell script and this C one) - # are only useful if you want to execute the "real" binary. - # Since the "real" binary is built for $host, then this - # wrapper might as well be built for $host, too. - $run $LTCC $LTCFLAGS -s -o $cwrapper $cwrappersource - ;; - esac - $rm $output - trap "$rm $output; exit $EXIT_FAILURE" 1 2 15 - - $echo > $output "\ -#! $SHELL - -# $output - temporary wrapper script for $objdir/$outputname -# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP -# -# The $output program cannot be directly executed until all the libtool -# libraries that it depends on are installed. -# -# This wrapper script should never be moved out of the build directory. -# If it is, it will not operate correctly. - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -Xsed='${SED} -e 1s/^X//' -sed_quote_subst='$sed_quote_subst' - -# Be Bourne compatible (taken from Autoconf:_AS_BOURNE_COMPATIBLE). -if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which - # is contrary to our usage. Disable this feature. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else - case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac -fi -BIN_SH=xpg4; export BIN_SH # for Tru64 -DUALCASE=1; export DUALCASE # for MKS sh - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -relink_command=\"$relink_command\" - -# This environment variable determines our operation mode. -if test \"\$libtool_install_magic\" = \"$magic\"; then - # install mode needs the following variable: - notinst_deplibs='$notinst_deplibs' -else - # When we are sourced in execute mode, \$file and \$echo are already set. - if test \"\$libtool_execute_magic\" != \"$magic\"; then - echo=\"$qecho\" - file=\"\$0\" - # Make sure echo works. - if test \"X\$1\" = X--no-reexec; then - # Discard the --no-reexec flag, and continue. - shift - elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then - # Yippee, \$echo works! - : - else - # Restart under the correct shell, and then maybe \$echo will work. - exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} - fi - fi\ -" - $echo >> $output "\ - - # Find the directory that this script lives in. - thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` - test \"x\$thisdir\" = \"x\$file\" && thisdir=. - - # Follow symbolic links until we get to the real thisdir. - file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` - while test -n \"\$file\"; do - destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` - - # If there was a directory component, then change thisdir. - if test \"x\$destdir\" != \"x\$file\"; then - case \"\$destdir\" in - [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; - *) thisdir=\"\$thisdir/\$destdir\" ;; - esac - fi - - file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` - file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` - done - - # Try to get the absolute directory name. - absdir=\`cd \"\$thisdir\" && pwd\` - test -n \"\$absdir\" && thisdir=\"\$absdir\" -" - - if test "$fast_install" = yes; then - $echo >> $output "\ - program=lt-'$outputname'$exeext - progdir=\"\$thisdir/$objdir\" - - if test ! -f \"\$progdir/\$program\" || \\ - { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ - test \"X\$file\" != \"X\$progdir/\$program\"; }; then - - file=\"\$\$-\$program\" - - if test ! -d \"\$progdir\"; then - $mkdir \"\$progdir\" - else - $rm \"\$progdir/\$file\" - fi" - - $echo >> $output "\ - - # relink executable if necessary - if test -n \"\$relink_command\"; then - if relink_command_output=\`eval \$relink_command 2>&1\`; then : - else - $echo \"\$relink_command_output\" >&2 - $rm \"\$progdir/\$file\" - exit $EXIT_FAILURE - fi - fi - - $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || - { $rm \"\$progdir/\$program\"; - $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } - $rm \"\$progdir/\$file\" - fi" - else - $echo >> $output "\ - program='$outputname' - progdir=\"\$thisdir/$objdir\" -" - fi - - $echo >> $output "\ - - if test -f \"\$progdir/\$program\"; then" - - # Export our shlibpath_var if we have one. - if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then - $echo >> $output "\ - # Add our own library path to $shlibpath_var - $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" - - # Some systems cannot cope with colon-terminated $shlibpath_var - # The second colon is a workaround for a bug in BeOS R4 sed - $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` - - export $shlibpath_var -" - fi - - # fixup the dll searchpath if we need to. - if test -n "$dllsearchpath"; then - $echo >> $output "\ - # Add the dll search path components to the executable PATH - PATH=$dllsearchpath:\$PATH -" - fi - - $echo >> $output "\ - if test \"\$libtool_execute_magic\" != \"$magic\"; then - # Run the actual program with our arguments. -" - case $host in - # Backslashes separate directories on plain windows - *-*-mingw | *-*-os2*) - $echo >> $output "\ - exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} -" - ;; - - *) - $echo >> $output "\ - exec \"\$progdir/\$program\" \${1+\"\$@\"} -" - ;; - esac - $echo >> $output "\ - \$echo \"\$0: cannot exec \$program \$*\" - exit $EXIT_FAILURE - fi - else - # The program doesn't exist. - \$echo \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 - \$echo \"This script is just a wrapper for \$program.\" 1>&2 - $echo \"See the $PACKAGE documentation for more information.\" 1>&2 - exit $EXIT_FAILURE - fi -fi\ -" - chmod +x $output - fi - exit $EXIT_SUCCESS - ;; - esac - - # See if we need to build an old-fashioned archive. - for oldlib in $oldlibs; do - - if test "$build_libtool_libs" = convenience; then - oldobjs="$libobjs_save" - addlibs="$convenience" - build_libtool_libs=no - else - if test "$build_libtool_libs" = module; then - oldobjs="$libobjs_save" - build_libtool_libs=no - else - oldobjs="$old_deplibs $non_pic_objects" - fi - addlibs="$old_convenience" - fi - - if test -n "$addlibs"; then - gentop="$output_objdir/${outputname}x" - generated="$generated $gentop" - - func_extract_archives $gentop $addlibs - oldobjs="$oldobjs $func_extract_archives_result" - fi - - # Do each command in the archive commands. - if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then - cmds=$old_archive_from_new_cmds - else - # POSIX demands no paths to be encoded in archives. We have - # to avoid creating archives with duplicate basenames if we - # might have to extract them afterwards, e.g., when creating a - # static archive out of a convenience library, or when linking - # the entirety of a libtool archive into another (currently - # not supported by libtool). - if (for obj in $oldobjs - do - $echo "X$obj" | $Xsed -e 's%^.*/%%' - done | sort | sort -uc >/dev/null 2>&1); then - : - else - $echo "copying selected object files to avoid basename conflicts..." - - if test -z "$gentop"; then - gentop="$output_objdir/${outputname}x" - generated="$generated $gentop" - - $show "${rm}r $gentop" - $run ${rm}r "$gentop" - $show "$mkdir $gentop" - $run $mkdir "$gentop" - exit_status=$? - if test "$exit_status" -ne 0 && test ! -d "$gentop"; then - exit $exit_status - fi - fi - - save_oldobjs=$oldobjs - oldobjs= - counter=1 - for obj in $save_oldobjs - do - objbase=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` - case " $oldobjs " in - " ") oldobjs=$obj ;; - *[\ /]"$objbase "*) - while :; do - # Make sure we don't pick an alternate name that also - # overlaps. - newobj=lt$counter-$objbase - counter=`expr $counter + 1` - case " $oldobjs " in - *[\ /]"$newobj "*) ;; - *) if test ! -f "$gentop/$newobj"; then break; fi ;; - esac - done - $show "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" - $run ln "$obj" "$gentop/$newobj" || - $run cp "$obj" "$gentop/$newobj" - oldobjs="$oldobjs $gentop/$newobj" - ;; - *) oldobjs="$oldobjs $obj" ;; - esac - done - fi - - eval cmds=\"$old_archive_cmds\" - - if len=`expr "X$cmds" : ".*"` && - test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then - cmds=$old_archive_cmds - else - # the command line is too long to link in one step, link in parts - $echo "using piecewise archive linking..." - save_RANLIB=$RANLIB - RANLIB=: - objlist= - concat_cmds= - save_oldobjs=$oldobjs - - # Is there a better way of finding the last object in the list? - for obj in $save_oldobjs - do - last_oldobj=$obj - done - for obj in $save_oldobjs - do - oldobjs="$objlist $obj" - objlist="$objlist $obj" - eval test_cmds=\"$old_archive_cmds\" - if len=`expr "X$test_cmds" : ".*" 2>/dev/null` && - test "$len" -le "$max_cmd_len"; then - : - else - # the above command should be used before it gets too long - oldobjs=$objlist - if test "$obj" = "$last_oldobj" ; then - RANLIB=$save_RANLIB - fi - test -z "$concat_cmds" || concat_cmds=$concat_cmds~ - eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" - objlist= - fi - done - RANLIB=$save_RANLIB - oldobjs=$objlist - if test "X$oldobjs" = "X" ; then - eval cmds=\"\$concat_cmds\" - else - eval cmds=\"\$concat_cmds~\$old_archive_cmds\" - fi - fi - fi - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - eval cmd=\"$cmd\" - IFS="$save_ifs" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - done - - if test -n "$generated"; then - $show "${rm}r$generated" - $run ${rm}r$generated - fi - - # Now create the libtool archive. - case $output in - *.la) - old_library= - test "$build_old_libs" = yes && old_library="$libname.$libext" - $show "creating $output" - - # Preserve any variables that may affect compiler behavior - for var in $variables_saved_for_relink; do - if eval test -z \"\${$var+set}\"; then - relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" - elif eval var_value=\$$var; test -z "$var_value"; then - relink_command="$var=; export $var; $relink_command" - else - var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` - relink_command="$var=\"$var_value\"; export $var; $relink_command" - fi - done - # Quote the link command for shipping. - relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" - relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e "$sed_quote_subst" | $NL2SP` - if test "$hardcode_automatic" = yes ; then - relink_command= - fi - - - # Only create the output if not a dry run. - if test -z "$run"; then - for installed in no yes; do - if test "$installed" = yes; then - if test -z "$install_libdir"; then - break - fi - output="$output_objdir/$outputname"i - # Replace all uninstalled libtool libraries with the installed ones - newdependency_libs= - for deplib in $dependency_libs; do - case $deplib in - *.la) - name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` - eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` - if test -z "$libdir"; then - $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 - exit $EXIT_FAILURE - fi - newdependency_libs="$newdependency_libs $libdir/$name" - ;; - *) newdependency_libs="$newdependency_libs $deplib" ;; - esac - done - dependency_libs="$newdependency_libs" - newdlfiles= - for lib in $dlfiles; do - name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` - eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` - if test -z "$libdir"; then - $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 - exit $EXIT_FAILURE - fi - newdlfiles="$newdlfiles $libdir/$name" - done - dlfiles="$newdlfiles" - newdlprefiles= - for lib in $dlprefiles; do - name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` - eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` - if test -z "$libdir"; then - $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 - exit $EXIT_FAILURE - fi - newdlprefiles="$newdlprefiles $libdir/$name" - done - dlprefiles="$newdlprefiles" - else - newdlfiles= - for lib in $dlfiles; do - case $lib in - [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; - *) abs=`pwd`"/$lib" ;; - esac - newdlfiles="$newdlfiles $abs" - done - dlfiles="$newdlfiles" - newdlprefiles= - for lib in $dlprefiles; do - case $lib in - [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; - *) abs=`pwd`"/$lib" ;; - esac - newdlprefiles="$newdlprefiles $abs" - done - dlprefiles="$newdlprefiles" - fi - $rm $output - # place dlname in correct position for cygwin - tdlname=$dlname - case $host,$output,$installed,$module,$dlname in - *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; - esac - $echo > $output "\ -# $outputname - a libtool library file -# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP -# -# Please DO NOT delete this file! -# It is necessary for linking the library. - -# The name that we can dlopen(3). -dlname='$tdlname' - -# Names of this library. -library_names='$library_names' - -# The name of the static archive. -old_library='$old_library' - -# Libraries that this one depends upon. -dependency_libs='$dependency_libs' - -# Version information for $libname. -current=$current -age=$age -revision=$revision - -# Is this an already installed library? -installed=$installed - -# Should we warn about portability when linking against -modules? -shouldnotlink=$module - -# Files to dlopen/dlpreopen -dlopen='$dlfiles' -dlpreopen='$dlprefiles' - -# Directory that this library needs to be installed in: -libdir='$install_libdir'" - if test "$installed" = no && test "$need_relink" = yes; then - $echo >> $output "\ -relink_command=\"$relink_command\"" - fi - done - fi - - # Do a symbolic link so that the libtool archive can be found in - # LD_LIBRARY_PATH before the program is installed. - $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" - $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? - ;; - esac - exit $EXIT_SUCCESS - ;; - - # libtool install mode - install) - modename="$modename: install" - - # There may be an optional sh(1) argument at the beginning of - # install_prog (especially on Windows NT). - if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || - # Allow the use of GNU shtool's install command. - $echo "X$nonopt" | grep shtool > /dev/null; then - # Aesthetically quote it. - arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - arg="\"$arg\"" - ;; - esac - install_prog="$arg " - arg="$1" - shift - else - install_prog= - arg=$nonopt - fi - - # The real first argument should be the name of the installation program. - # Aesthetically quote it. - arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - arg="\"$arg\"" - ;; - esac - install_prog="$install_prog$arg" - - # We need to accept at least all the BSD install flags. - dest= - files= - opts= - prev= - install_type= - isdir=no - stripme= - for arg - do - if test -n "$dest"; then - files="$files $dest" - dest=$arg - continue - fi - - case $arg in - -d) isdir=yes ;; - -f) - case " $install_prog " in - *[\\\ /]cp\ *) ;; - *) prev=$arg ;; - esac - ;; - -g | -m | -o) prev=$arg ;; - -s) - stripme=" -s" - continue - ;; - -*) - ;; - *) - # If the previous option needed an argument, then skip it. - if test -n "$prev"; then - prev= - else - dest=$arg - continue - fi - ;; - esac - - # Aesthetically quote the argument. - arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - arg="\"$arg\"" - ;; - esac - install_prog="$install_prog $arg" - done - - if test -z "$install_prog"; then - $echo "$modename: you must specify an install program" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - - if test -n "$prev"; then - $echo "$modename: the \`$prev' option requires an argument" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - - if test -z "$files"; then - if test -z "$dest"; then - $echo "$modename: no file or destination specified" 1>&2 - else - $echo "$modename: you must specify a destination" 1>&2 - fi - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - - # Strip any trailing slash from the destination. - dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` - - # Check to see that the destination is a directory. - test -d "$dest" && isdir=yes - if test "$isdir" = yes; then - destdir="$dest" - destname= - else - destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` - test "X$destdir" = "X$dest" && destdir=. - destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` - - # Not a directory, so check to see that there is only one file specified. - set dummy $files - if test "$#" -gt 2; then - $echo "$modename: \`$dest' is not a directory" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - fi - case $destdir in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - for file in $files; do - case $file in - *.lo) ;; - *) - $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - ;; - esac - done - ;; - esac - - # This variable tells wrapper scripts just to set variables rather - # than running their programs. - libtool_install_magic="$magic" - - staticlibs= - future_libdirs= - current_libdirs= - for file in $files; do - - # Do each installation. - case $file in - *.$libext) - # Do the static libraries later. - staticlibs="$staticlibs $file" - ;; - - *.la) - # Check to see that this really is a libtool archive. - if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : - else - $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - - library_names= - old_library= - relink_command= - # If there is no directory component, then add one. - case $file in - */* | *\\*) . $file ;; - *) . ./$file ;; - esac - - # Add the libdir to current_libdirs if it is the destination. - if test "X$destdir" = "X$libdir"; then - case "$current_libdirs " in - *" $libdir "*) ;; - *) current_libdirs="$current_libdirs $libdir" ;; - esac - else - # Note the libdir as a future libdir. - case "$future_libdirs " in - *" $libdir "*) ;; - *) future_libdirs="$future_libdirs $libdir" ;; - esac - fi - - dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ - test "X$dir" = "X$file/" && dir= - dir="$dir$objdir" - - if test -n "$relink_command"; then - # Determine the prefix the user has applied to our future dir. - inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"` - - # Don't allow the user to place us outside of our expected - # location b/c this prevents finding dependent libraries that - # are installed to the same prefix. - # At present, this check doesn't affect windows .dll's that - # are installed into $libdir/../bin (currently, that works fine) - # but it's something to keep an eye on. - if test "$inst_prefix_dir" = "$destdir"; then - $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2 - exit $EXIT_FAILURE - fi - - if test -n "$inst_prefix_dir"; then - # Stick the inst_prefix_dir data into the link command. - relink_command=`$echo "$relink_command" | $SP2NL | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%" | $NL2SP` - else - relink_command=`$echo "$relink_command" | $SP2NL | $SED "s%@inst_prefix_dir@%%" | $NL2SP` - fi - - $echo "$modename: warning: relinking \`$file'" 1>&2 - $show "$relink_command" - if $run eval "$relink_command"; then : - else - $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 - exit $EXIT_FAILURE - fi - fi - - # See the names of the shared library. - set dummy $library_names - if test -n "$2"; then - realname="$2" - shift - shift - - srcname="$realname" - test -n "$relink_command" && srcname="$realname"T - - # Install the shared library and build the symlinks. - $show "$install_prog $dir/$srcname $destdir/$realname" - $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? - if test -n "$stripme" && test -n "$striplib"; then - $show "$striplib $destdir/$realname" - $run eval "$striplib $destdir/$realname" || exit $? - fi - - if test "$#" -gt 0; then - # Delete the old symlinks, and create new ones. - # Try `ln -sf' first, because the `ln' binary might depend on - # the symlink we replace! Solaris /bin/ln does not understand -f, - # so we also need to try rm && ln -s. - for linkname - do - if test "$linkname" != "$realname"; then - $show "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" - $run eval "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" - fi - done - fi - - # Do each command in the postinstall commands. - lib="$destdir/$realname" - cmds=$postinstall_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || { - lt_exit=$? - - # Restore the uninstalled library and exit - if test "$mode" = relink; then - $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' - fi - - exit $lt_exit - } - done - IFS="$save_ifs" - fi - - # Install the pseudo-library for information purposes. - name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - instname="$dir/$name"i - $show "$install_prog $instname $destdir/$name" - $run eval "$install_prog $instname $destdir/$name" || exit $? - - # Maybe install the static library, too. - test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" - ;; - - *.lo) - # Install (i.e. copy) a libtool object. - - # Figure out destination file name, if it wasn't already specified. - if test -n "$destname"; then - destfile="$destdir/$destname" - else - destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - destfile="$destdir/$destfile" - fi - - # Deduce the name of the destination old-style object file. - case $destfile in - *.lo) - staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` - ;; - *.$objext) - staticdest="$destfile" - destfile= - ;; - *) - $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - ;; - esac - - # Install the libtool object if requested. - if test -n "$destfile"; then - $show "$install_prog $file $destfile" - $run eval "$install_prog $file $destfile" || exit $? - fi - - # Install the old object if enabled. - if test "$build_old_libs" = yes; then - # Deduce the name of the old-style object file. - staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` - - $show "$install_prog $staticobj $staticdest" - $run eval "$install_prog \$staticobj \$staticdest" || exit $? - fi - exit $EXIT_SUCCESS - ;; - - *) - # Figure out destination file name, if it wasn't already specified. - if test -n "$destname"; then - destfile="$destdir/$destname" - else - destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - destfile="$destdir/$destfile" - fi - - # If the file is missing, and there is a .exe on the end, strip it - # because it is most likely a libtool script we actually want to - # install - stripped_ext="" - case $file in - *.exe) - if test ! -f "$file"; then - file=`$echo $file|${SED} 's,.exe$,,'` - stripped_ext=".exe" - fi - ;; - esac - - # Do a test to see if this is really a libtool program. - case $host in - *cygwin*|*mingw*) - wrapper=`$echo $file | ${SED} -e 's,.exe$,,'` - ;; - *) - wrapper=$file - ;; - esac - if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then - notinst_deplibs= - relink_command= - - # Note that it is not necessary on cygwin/mingw to append a dot to - # foo even if both foo and FILE.exe exist: automatic-append-.exe - # behavior happens only for exec(3), not for open(2)! Also, sourcing - # `FILE.' does not work on cygwin managed mounts. - # - # If there is no directory component, then add one. - case $wrapper in - */* | *\\*) . ${wrapper} ;; - *) . ./${wrapper} ;; - esac - - # Check the variables that should have been set. - if test -z "$notinst_deplibs"; then - $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2 - exit $EXIT_FAILURE - fi - - finalize=yes - for lib in $notinst_deplibs; do - # Check to see that each library is installed. - libdir= - if test -f "$lib"; then - # If there is no directory component, then add one. - case $lib in - */* | *\\*) . $lib ;; - *) . ./$lib ;; - esac - fi - libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test - if test -n "$libdir" && test ! -f "$libfile"; then - $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 - finalize=no - fi - done - - relink_command= - # Note that it is not necessary on cygwin/mingw to append a dot to - # foo even if both foo and FILE.exe exist: automatic-append-.exe - # behavior happens only for exec(3), not for open(2)! Also, sourcing - # `FILE.' does not work on cygwin managed mounts. - # - # If there is no directory component, then add one. - case $wrapper in - */* | *\\*) . ${wrapper} ;; - *) . ./${wrapper} ;; - esac - - outputname= - if test "$fast_install" = no && test -n "$relink_command"; then - if test "$finalize" = yes && test -z "$run"; then - tmpdir=`func_mktempdir` - file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'` - outputname="$tmpdir/$file" - # Replace the output file specification. - relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g' | $NL2SP` - - $show "$relink_command" - if $run eval "$relink_command"; then : - else - $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 - ${rm}r "$tmpdir" - continue - fi - file="$outputname" - else - $echo "$modename: warning: cannot relink \`$file'" 1>&2 - fi - else - # Install the binary that we compiled earlier. - file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` - fi - fi - - # remove .exe since cygwin /usr/bin/install will append another - # one anyway - case $install_prog,$host in - */usr/bin/install*,*cygwin*) - case $file:$destfile in - *.exe:*.exe) - # this is ok - ;; - *.exe:*) - destfile=$destfile.exe - ;; - *:*.exe) - destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'` - ;; - esac - ;; - esac - $show "$install_prog$stripme $file $destfile" - $run eval "$install_prog\$stripme \$file \$destfile" || exit $? - test -n "$outputname" && ${rm}r "$tmpdir" - ;; - esac - done - - for file in $staticlibs; do - name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - - # Set up the ranlib parameters. - oldlib="$destdir/$name" - - $show "$install_prog $file $oldlib" - $run eval "$install_prog \$file \$oldlib" || exit $? - - if test -n "$stripme" && test -n "$old_striplib"; then - $show "$old_striplib $oldlib" - $run eval "$old_striplib $oldlib" || exit $? - fi - - # Do each command in the postinstall commands. - cmds=$old_postinstall_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - done - - if test -n "$future_libdirs"; then - $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 - fi - - if test -n "$current_libdirs"; then - # Maybe just do a dry run. - test -n "$run" && current_libdirs=" -n$current_libdirs" - exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' - else - exit $EXIT_SUCCESS - fi - ;; - - # libtool finish mode - finish) - modename="$modename: finish" - libdirs="$nonopt" - admincmds= - - if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then - for dir - do - libdirs="$libdirs $dir" - done - - for libdir in $libdirs; do - if test -n "$finish_cmds"; then - # Do each command in the finish commands. - cmds=$finish_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || admincmds="$admincmds - $cmd" - done - IFS="$save_ifs" - fi - if test -n "$finish_eval"; then - # Do the single finish_eval. - eval cmds=\"$finish_eval\" - $run eval "$cmds" || admincmds="$admincmds - $cmds" - fi - done - fi - - # Exit here if they wanted silent mode. - test "$show" = : && exit $EXIT_SUCCESS - - $echo "X----------------------------------------------------------------------" | $Xsed - $echo "Libraries have been installed in:" - for libdir in $libdirs; do - $echo " $libdir" - done - $echo - $echo "If you ever happen to want to link against installed libraries" - $echo "in a given directory, LIBDIR, you must either use libtool, and" - $echo "specify the full pathname of the library, or use the \`-LLIBDIR'" - $echo "flag during linking and do at least one of the following:" - if test -n "$shlibpath_var"; then - $echo " - add LIBDIR to the \`$shlibpath_var' environment variable" - $echo " during execution" - fi - if test -n "$runpath_var"; then - $echo " - add LIBDIR to the \`$runpath_var' environment variable" - $echo " during linking" - fi - if test -n "$hardcode_libdir_flag_spec"; then - libdir=LIBDIR - eval flag=\"$hardcode_libdir_flag_spec\" - - $echo " - use the \`$flag' linker flag" - fi - if test -n "$admincmds"; then - $echo " - have your system administrator run these commands:$admincmds" - fi - if test -f /etc/ld.so.conf; then - $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" - fi - $echo - $echo "See any operating system documentation about shared libraries for" - $echo "more information, such as the ld(1) and ld.so(8) manual pages." - $echo "X----------------------------------------------------------------------" | $Xsed - exit $EXIT_SUCCESS - ;; - - # libtool execute mode - execute) - modename="$modename: execute" - - # The first argument is the command name. - cmd="$nonopt" - if test -z "$cmd"; then - $echo "$modename: you must specify a COMMAND" 1>&2 - $echo "$help" - exit $EXIT_FAILURE - fi - - # Handle -dlopen flags immediately. - for file in $execute_dlfiles; do - if test ! -f "$file"; then - $echo "$modename: \`$file' is not a file" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - - dir= - case $file in - *.la) - # Check to see that this really is a libtool archive. - if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : - else - $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - - # Read the libtool library. - dlname= - library_names= - - # If there is no directory component, then add one. - case $file in - */* | *\\*) . $file ;; - *) . ./$file ;; - esac - - # Skip this library if it cannot be dlopened. - if test -z "$dlname"; then - # Warn if it was a shared library. - test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" - continue - fi - - dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` - test "X$dir" = "X$file" && dir=. - - if test -f "$dir/$objdir/$dlname"; then - dir="$dir/$objdir" - else - if test ! -f "$dir/$dlname"; then - $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 - exit $EXIT_FAILURE - fi - fi - ;; - - *.lo) - # Just add the directory containing the .lo file. - dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` - test "X$dir" = "X$file" && dir=. - ;; - - *) - $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 - continue - ;; - esac - - # Get the absolute pathname. - absdir=`cd "$dir" && pwd` - test -n "$absdir" && dir="$absdir" - - # Now add the directory to shlibpath_var. - if eval "test -z \"\$$shlibpath_var\""; then - eval "$shlibpath_var=\"\$dir\"" - else - eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" - fi - done - - # This variable tells wrapper scripts just to set shlibpath_var - # rather than running their programs. - libtool_execute_magic="$magic" - - # Check if any of the arguments is a wrapper script. - args= - for file - do - case $file in - -*) ;; - *) - # Do a test to see if this is really a libtool program. - if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - # If there is no directory component, then add one. - case $file in - */* | *\\*) . $file ;; - *) . ./$file ;; - esac - - # Transform arg to wrapped name. - file="$progdir/$program" - fi - ;; - esac - # Quote arguments (to preserve shell metacharacters). - file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` - args="$args \"$file\"" - done - - if test -z "$run"; then - if test -n "$shlibpath_var"; then - # Export the shlibpath_var. - eval "export $shlibpath_var" - fi - - # Restore saved environment variables - for lt_var in LANG LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES - do - eval "if test \"\${save_$lt_var+set}\" = set; then - $lt_var=\$save_$lt_var; export $lt_var - fi" - done - - # Now prepare to actually exec the command. - exec_cmd="\$cmd$args" - else - # Display what would be done. - if test -n "$shlibpath_var"; then - eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" - $echo "export $shlibpath_var" - fi - $echo "$cmd$args" - exit $EXIT_SUCCESS - fi - ;; - - # libtool clean and uninstall mode - clean | uninstall) - modename="$modename: $mode" - rm="$nonopt" - files= - rmforce= - exit_status=0 - - # This variable tells wrapper scripts just to set variables rather - # than running their programs. - libtool_install_magic="$magic" - - for arg - do - case $arg in - -f) rm="$rm $arg"; rmforce=yes ;; - -*) rm="$rm $arg" ;; - *) files="$files $arg" ;; - esac - done - - if test -z "$rm"; then - $echo "$modename: you must specify an RM program" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - fi - - rmdirs= - - origobjdir="$objdir" - for file in $files; do - dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` - if test "X$dir" = "X$file"; then - dir=. - objdir="$origobjdir" - else - objdir="$dir/$origobjdir" - fi - name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - test "$mode" = uninstall && objdir="$dir" - - # Remember objdir for removal later, being careful to avoid duplicates - if test "$mode" = clean; then - case " $rmdirs " in - *" $objdir "*) ;; - *) rmdirs="$rmdirs $objdir" ;; - esac - fi - - # Don't error if the file doesn't exist and rm -f was used. - if (test -L "$file") >/dev/null 2>&1 \ - || (test -h "$file") >/dev/null 2>&1 \ - || test -f "$file"; then - : - elif test -d "$file"; then - exit_status=1 - continue - elif test "$rmforce" = yes; then - continue - fi - - rmfiles="$file" - - case $name in - *.la) - # Possibly a libtool archive, so verify it. - if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - . $dir/$name - - # Delete the libtool libraries and symlinks. - for n in $library_names; do - rmfiles="$rmfiles $objdir/$n" - done - test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" - - case "$mode" in - clean) - case " $library_names " in - # " " in the beginning catches empty $dlname - *" $dlname "*) ;; - *) rmfiles="$rmfiles $objdir/$dlname" ;; - esac - test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" - ;; - uninstall) - if test -n "$library_names"; then - # Do each command in the postuninstall commands. - cmds=$postuninstall_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" - if test "$?" -ne 0 && test "$rmforce" != yes; then - exit_status=1 - fi - done - IFS="$save_ifs" - fi - - if test -n "$old_library"; then - # Do each command in the old_postuninstall commands. - cmds=$old_postuninstall_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" - if test "$?" -ne 0 && test "$rmforce" != yes; then - exit_status=1 - fi - done - IFS="$save_ifs" - fi - # FIXME: should reinstall the best remaining shared library. - ;; - esac - fi - ;; - - *.lo) - # Possibly a libtool object, so verify it. - if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - - # Read the .lo file - . $dir/$name - - # Add PIC object to the list of files to remove. - if test -n "$pic_object" \ - && test "$pic_object" != none; then - rmfiles="$rmfiles $dir/$pic_object" - fi - - # Add non-PIC object to the list of files to remove. - if test -n "$non_pic_object" \ - && test "$non_pic_object" != none; then - rmfiles="$rmfiles $dir/$non_pic_object" - fi - fi - ;; - - *) - if test "$mode" = clean ; then - noexename=$name - case $file in - *.exe) - file=`$echo $file|${SED} 's,.exe$,,'` - noexename=`$echo $name|${SED} 's,.exe$,,'` - # $file with .exe has already been added to rmfiles, - # add $file without .exe - rmfiles="$rmfiles $file" - ;; - esac - # Do a test to see if this is a libtool program. - if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - relink_command= - . $dir/$noexename - - # note $name still contains .exe if it was in $file originally - # as does the version of $file that was added into $rmfiles - rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" - if test "$fast_install" = yes && test -n "$relink_command"; then - rmfiles="$rmfiles $objdir/lt-$name" - fi - if test "X$noexename" != "X$name" ; then - rmfiles="$rmfiles $objdir/lt-${noexename}.c" - fi - fi - fi - ;; - esac - $show "$rm $rmfiles" - $run $rm $rmfiles || exit_status=1 - done - objdir="$origobjdir" - - # Try to remove the ${objdir}s in the directories where we deleted files - for dir in $rmdirs; do - if test -d "$dir"; then - $show "rmdir $dir" - $run rmdir $dir >/dev/null 2>&1 - fi - done - - exit $exit_status - ;; - - "") - $echo "$modename: you must specify a MODE" 1>&2 - $echo "$generic_help" 1>&2 - exit $EXIT_FAILURE - ;; - esac - - if test -z "$exec_cmd"; then - $echo "$modename: invalid operation mode \`$mode'" 1>&2 - $echo "$generic_help" 1>&2 - exit $EXIT_FAILURE - fi -fi # test -z "$show_help" - -if test -n "$exec_cmd"; then - eval exec $exec_cmd - exit $EXIT_FAILURE -fi - -# We need to display help for each of the modes. -case $mode in -"") $echo \ -"Usage: $modename [OPTION]... [MODE-ARG]... - -Provide generalized library-building support services. - - --config show all configuration variables - --debug enable verbose shell tracing --n, --dry-run display commands without modifying any files - --features display basic configuration information and exit - --finish same as \`--mode=finish' - --help display this help message and exit - --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] - --quiet same as \`--silent' - --silent don't print informational messages - --tag=TAG use configuration variables from tag TAG - --version print version information - -MODE must be one of the following: - - clean remove files from the build directory - compile compile a source file into a libtool object - execute automatically set library path, then run a program - finish complete the installation of libtool libraries - install install libraries or executables - link create a library or an executable - uninstall remove libraries from an installed directory - -MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for -a more detailed description of MODE. - -Report bugs to ." - exit $EXIT_SUCCESS - ;; - -clean) - $echo \ -"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... - -Remove files from the build directory. - -RM is the name of the program to use to delete files associated with each FILE -(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed -to RM. - -If FILE is a libtool library, object or program, all the files associated -with it are deleted. Otherwise, only FILE itself is deleted using RM." - ;; - -compile) - $echo \ -"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE - -Compile a source file into a libtool library object. - -This mode accepts the following additional options: - - -o OUTPUT-FILE set the output file name to OUTPUT-FILE - -prefer-pic try to building PIC objects only - -prefer-non-pic try to building non-PIC objects only - -static always build a \`.o' file suitable for static linking - -COMPILE-COMMAND is a command to be used in creating a \`standard' object file -from the given SOURCEFILE. - -The output file name is determined by removing the directory component from -SOURCEFILE, then substituting the C source code suffix \`.c' with the -library object suffix, \`.lo'." - ;; - -execute) - $echo \ -"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... - -Automatically set library path, then run a program. - -This mode accepts the following additional options: - - -dlopen FILE add the directory containing FILE to the library path - -This mode sets the library path environment variable according to \`-dlopen' -flags. - -If any of the ARGS are libtool executable wrappers, then they are translated -into their corresponding uninstalled binary, and any of their required library -directories are added to the library path. - -Then, COMMAND is executed, with ARGS as arguments." - ;; - -finish) - $echo \ -"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... - -Complete the installation of libtool libraries. - -Each LIBDIR is a directory that contains libtool libraries. - -The commands that this mode executes may require superuser privileges. Use -the \`--dry-run' option if you just want to see what would be executed." - ;; - -install) - $echo \ -"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... - -Install executables or libraries. - -INSTALL-COMMAND is the installation command. The first component should be -either the \`install' or \`cp' program. - -The rest of the components are interpreted as arguments to that command (only -BSD-compatible install options are recognized)." - ;; - -link) - $echo \ -"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... - -Link object files or libraries together to form another library, or to -create an executable program. - -LINK-COMMAND is a command using the C compiler that you would use to create -a program from several object files. - -The following components of LINK-COMMAND are treated specially: - - -all-static do not do any dynamic linking at all - -avoid-version do not add a version suffix if possible - -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime - -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols - -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) - -export-symbols SYMFILE - try to export only the symbols listed in SYMFILE - -export-symbols-regex REGEX - try to export only the symbols matching REGEX - -LLIBDIR search LIBDIR for required installed libraries - -lNAME OUTPUT-FILE requires the installed library libNAME - -module build a library that can dlopened - -no-fast-install disable the fast-install mode - -no-install link a not-installable executable - -no-undefined declare that a library does not refer to external symbols - -o OUTPUT-FILE create OUTPUT-FILE from the specified objects - -objectlist FILE Use a list of object files found in FILE to specify objects - -precious-files-regex REGEX - don't remove output files matching REGEX - -release RELEASE specify package release information - -rpath LIBDIR the created library will eventually be installed in LIBDIR - -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries - -static do not do any dynamic linking of uninstalled libtool libraries - -static-libtool-libs - do not do any dynamic linking of libtool libraries - -version-info CURRENT[:REVISION[:AGE]] - specify library version info [each variable defaults to 0] - -All other options (arguments beginning with \`-') are ignored. - -Every other argument is treated as a filename. Files ending in \`.la' are -treated as uninstalled libtool libraries, other files are standard or library -object files. - -If the OUTPUT-FILE ends in \`.la', then a libtool library is created, -only library objects (\`.lo' files) may be specified, and \`-rpath' is -required, except when creating a convenience library. - -If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created -using \`ar' and \`ranlib', or on Windows using \`lib'. - -If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file -is created, otherwise an executable program is created." - ;; - -uninstall) - $echo \ -"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... - -Remove libraries from an installation directory. - -RM is the name of the program to use to delete files associated with each FILE -(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed -to RM. - -If FILE is a libtool library, all the files associated with it are deleted. -Otherwise, only FILE itself is deleted using RM." - ;; - -*) - $echo "$modename: invalid operation mode \`$mode'" 1>&2 - $echo "$help" 1>&2 - exit $EXIT_FAILURE - ;; -esac - -$echo -$echo "Try \`$modename --help' for more information about other modes." - -exit $? - -# The TAGs below are defined such that we never get into a situation -# in which we disable both kinds of libraries. Given conflicting -# choices, we go for a static library, that is the most portable, -# since we can't tell whether shared libraries were disabled because -# the user asked for that or because the platform doesn't support -# them. This is particularly important on AIX, because we don't -# support having both static and shared libraries enabled at the same -# time on that platform, so we default to a shared-only configuration. -# If a disable-shared tag is given, we'll fallback to a static-only -# configuration. But we'll never go from static-only to shared-only. - -# ### BEGIN LIBTOOL TAG CONFIG: disable-shared -disable_libs=shared -# ### END LIBTOOL TAG CONFIG: disable-shared - -# ### BEGIN LIBTOOL TAG CONFIG: disable-static -disable_libs=static -# ### END LIBTOOL TAG CONFIG: disable-static - -# Local Variables: -# mode:shell-script -# sh-indentation:2 -# End: diff --git a/libltdl/missing b/libltdl/missing deleted file mode 100755 index 894e786e..00000000 --- a/libltdl/missing +++ /dev/null @@ -1,360 +0,0 @@ -#! /bin/sh -# Common stub for a few missing GNU programs while installing. - -scriptversion=2005-06-08.21 - -# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005 -# Free Software Foundation, Inc. -# Originally by Fran,cois Pinard , 1996. - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301, USA. - -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -if test $# -eq 0; then - echo 1>&2 "Try \`$0 --help' for more information" - exit 1 -fi - -run=: - -# In the cases where this matters, `missing' is being run in the -# srcdir already. -if test -f configure.ac; then - configure_ac=configure.ac -else - configure_ac=configure.in -fi - -msg="missing on your system" - -case "$1" in ---run) - # Try to run requested program, and just exit if it succeeds. - run= - shift - "$@" && exit 0 - # Exit code 63 means version mismatch. This often happens - # when the user try to use an ancient version of a tool on - # a file that requires a minimum version. In this case we - # we should proceed has if the program had been absent, or - # if --run hadn't been passed. - if test $? = 63; then - run=: - msg="probably too old" - fi - ;; - - -h|--h|--he|--hel|--help) - echo "\ -$0 [OPTION]... PROGRAM [ARGUMENT]... - -Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an -error status if there is no known handling for PROGRAM. - -Options: - -h, --help display this help and exit - -v, --version output version information and exit - --run try to run the given command, and emulate it if it fails - -Supported PROGRAM values: - aclocal touch file \`aclocal.m4' - autoconf touch file \`configure' - autoheader touch file \`config.h.in' - automake touch all \`Makefile.in' files - bison create \`y.tab.[ch]', if possible, from existing .[ch] - flex create \`lex.yy.c', if possible, from existing .c - help2man touch the output file - lex create \`lex.yy.c', if possible, from existing .c - makeinfo touch the output file - tar try tar, gnutar, gtar, then tar without non-portable flags - yacc create \`y.tab.[ch]', if possible, from existing .[ch] - -Send bug reports to ." - exit $? - ;; - - -v|--v|--ve|--ver|--vers|--versi|--versio|--version) - echo "missing $scriptversion (GNU Automake)" - exit $? - ;; - - -*) - echo 1>&2 "$0: Unknown \`$1' option" - echo 1>&2 "Try \`$0 --help' for more information" - exit 1 - ;; - -esac - -# Now exit if we have it, but it failed. Also exit now if we -# don't have it and --version was passed (most likely to detect -# the program). -case "$1" in - lex|yacc) - # Not GNU programs, they don't have --version. - ;; - - tar) - if test -n "$run"; then - echo 1>&2 "ERROR: \`tar' requires --run" - exit 1 - elif test "x$2" = "x--version" || test "x$2" = "x--help"; then - exit 1 - fi - ;; - - *) - if test -z "$run" && ($1 --version) > /dev/null 2>&1; then - # We have it, but it failed. - exit 1 - elif test "x$2" = "x--version" || test "x$2" = "x--help"; then - # Could not run --version or --help. This is probably someone - # running `$TOOL --version' or `$TOOL --help' to check whether - # $TOOL exists and not knowing $TOOL uses missing. - exit 1 - fi - ;; -esac - -# If it does not exist, or fails to run (possibly an outdated version), -# try to emulate it. -case "$1" in - aclocal*) - echo 1>&2 "\ -WARNING: \`$1' is $msg. You should only need it if - you modified \`acinclude.m4' or \`${configure_ac}'. You might want - to install the \`Automake' and \`Perl' packages. Grab them from - any GNU archive site." - touch aclocal.m4 - ;; - - autoconf) - echo 1>&2 "\ -WARNING: \`$1' is $msg. You should only need it if - you modified \`${configure_ac}'. You might want to install the - \`Autoconf' and \`GNU m4' packages. Grab them from any GNU - archive site." - touch configure - ;; - - autoheader) - echo 1>&2 "\ -WARNING: \`$1' is $msg. You should only need it if - you modified \`acconfig.h' or \`${configure_ac}'. You might want - to install the \`Autoconf' and \`GNU m4' packages. Grab them - from any GNU archive site." - files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` - test -z "$files" && files="config.h" - touch_files= - for f in $files; do - case "$f" in - *:*) touch_files="$touch_files "`echo "$f" | - sed -e 's/^[^:]*://' -e 's/:.*//'`;; - *) touch_files="$touch_files $f.in";; - esac - done - touch $touch_files - ;; - - automake*) - echo 1>&2 "\ -WARNING: \`$1' is $msg. You should only need it if - you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. - You might want to install the \`Automake' and \`Perl' packages. - Grab them from any GNU archive site." - find . -type f -name Makefile.am -print | - sed 's/\.am$/.in/' | - while read f; do touch "$f"; done - ;; - - autom4te) - echo 1>&2 "\ -WARNING: \`$1' is needed, but is $msg. - You might have modified some files without having the - proper tools for further handling them. - You can get \`$1' as part of \`Autoconf' from any GNU - archive site." - - file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` - test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` - if test -f "$file"; then - touch $file - else - test -z "$file" || exec >$file - echo "#! /bin/sh" - echo "# Created by GNU Automake missing as a replacement of" - echo "# $ $@" - echo "exit 0" - chmod +x $file - exit 1 - fi - ;; - - bison|yacc) - echo 1>&2 "\ -WARNING: \`$1' $msg. You should only need it if - you modified a \`.y' file. You may need the \`Bison' package - in order for those modifications to take effect. You can get - \`Bison' from any GNU archive site." - rm -f y.tab.c y.tab.h - if [ $# -ne 1 ]; then - eval LASTARG="\${$#}" - case "$LASTARG" in - *.y) - SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` - if [ -f "$SRCFILE" ]; then - cp "$SRCFILE" y.tab.c - fi - SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` - if [ -f "$SRCFILE" ]; then - cp "$SRCFILE" y.tab.h - fi - ;; - esac - fi - if [ ! -f y.tab.h ]; then - echo >y.tab.h - fi - if [ ! -f y.tab.c ]; then - echo 'main() { return 0; }' >y.tab.c - fi - ;; - - lex|flex) - echo 1>&2 "\ -WARNING: \`$1' is $msg. You should only need it if - you modified a \`.l' file. You may need the \`Flex' package - in order for those modifications to take effect. You can get - \`Flex' from any GNU archive site." - rm -f lex.yy.c - if [ $# -ne 1 ]; then - eval LASTARG="\${$#}" - case "$LASTARG" in - *.l) - SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` - if [ -f "$SRCFILE" ]; then - cp "$SRCFILE" lex.yy.c - fi - ;; - esac - fi - if [ ! -f lex.yy.c ]; then - echo 'main() { return 0; }' >lex.yy.c - fi - ;; - - help2man) - echo 1>&2 "\ -WARNING: \`$1' is $msg. You should only need it if - you modified a dependency of a manual page. You may need the - \`Help2man' package in order for those modifications to take - effect. You can get \`Help2man' from any GNU archive site." - - file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` - if test -z "$file"; then - file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` - fi - if [ -f "$file" ]; then - touch $file - else - test -z "$file" || exec >$file - echo ".ab help2man is required to generate this page" - exit 1 - fi - ;; - - makeinfo) - echo 1>&2 "\ -WARNING: \`$1' is $msg. You should only need it if - you modified a \`.texi' or \`.texinfo' file, or any other file - indirectly affecting the aspect of the manual. The spurious - call might also be the consequence of using a buggy \`make' (AIX, - DU, IRIX). You might want to install the \`Texinfo' package or - the \`GNU make' package. Grab either from any GNU archive site." - # The file to touch is that specified with -o ... - file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` - if test -z "$file"; then - # ... or it is the one specified with @setfilename ... - infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` - file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile` - # ... or it is derived from the source name (dir/f.texi becomes f.info) - test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info - fi - # If the file does not exist, the user really needs makeinfo; - # let's fail without touching anything. - test -f $file || exit 1 - touch $file - ;; - - tar) - shift - - # We have already tried tar in the generic part. - # Look for gnutar/gtar before invocation to avoid ugly error - # messages. - if (gnutar --version > /dev/null 2>&1); then - gnutar "$@" && exit 0 - fi - if (gtar --version > /dev/null 2>&1); then - gtar "$@" && exit 0 - fi - firstarg="$1" - if shift; then - case "$firstarg" in - *o*) - firstarg=`echo "$firstarg" | sed s/o//` - tar "$firstarg" "$@" && exit 0 - ;; - esac - case "$firstarg" in - *h*) - firstarg=`echo "$firstarg" | sed s/h//` - tar "$firstarg" "$@" && exit 0 - ;; - esac - fi - - echo 1>&2 "\ -WARNING: I can't seem to be able to run \`tar' with the given arguments. - You may want to install GNU tar or Free paxutils, or check the - command line arguments." - exit 1 - ;; - - *) - echo 1>&2 "\ -WARNING: \`$1' is needed, and is $msg. - You might have modified some files without having the - proper tools for further handling them. Check the \`README' file, - it often tells you about the needed prerequisites for installing - this package. You may also peek at any GNU archive site, in case - some other package would contain this missing \`$1' program." - exit 1 - ;; -esac - -exit 0 - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-end: "$" -# End: diff --git a/libltdl/mkinstalldirs b/libltdl/mkinstalldirs deleted file mode 100755 index ef7e16fd..00000000 --- a/libltdl/mkinstalldirs +++ /dev/null @@ -1,161 +0,0 @@ -#! /bin/sh -# mkinstalldirs --- make directory hierarchy - -scriptversion=2006-05-11.19 - -# Original author: Noah Friedman -# Created: 1993-05-16 -# Public domain. -# -# This file is maintained in Automake, please report -# bugs to or send patches to -# . - -nl=' -' -IFS=" "" $nl" -errstatus=0 -dirmode= - -usage="\ -Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... - -Create each directory DIR (with mode MODE, if specified), including all -leading file name components. - -Report bugs to ." - -# process command line arguments -while test $# -gt 0 ; do - case $1 in - -h | --help | --h*) # -h for help - echo "$usage" - exit $? - ;; - -m) # -m PERM arg - shift - test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } - dirmode=$1 - shift - ;; - --version) - echo "$0 $scriptversion" - exit $? - ;; - --) # stop option processing - shift - break - ;; - -*) # unknown option - echo "$usage" 1>&2 - exit 1 - ;; - *) # first non-opt arg - break - ;; - esac -done - -for file -do - if test -d "$file"; then - shift - else - break - fi -done - -case $# in - 0) exit 0 ;; -esac - -# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and -# mkdir -p a/c at the same time, both will detect that a is missing, -# one will create a, then the other will try to create a and die with -# a "File exists" error. This is a problem when calling mkinstalldirs -# from a parallel make. We use --version in the probe to restrict -# ourselves to GNU mkdir, which is thread-safe. -case $dirmode in - '') - if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then - echo "mkdir -p -- $*" - exec mkdir -p -- "$@" - else - # On NextStep and OpenStep, the `mkdir' command does not - # recognize any option. It will interpret all options as - # directories to create, and then abort because `.' already - # exists. - test -d ./-p && rmdir ./-p - test -d ./--version && rmdir ./--version - fi - ;; - *) - if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && - test ! -d ./--version; then - echo "mkdir -m $dirmode -p -- $*" - exec mkdir -m "$dirmode" -p -- "$@" - else - # Clean up after NextStep and OpenStep mkdir. - for d in ./-m ./-p ./--version "./$dirmode"; - do - test -d $d && rmdir $d - done - fi - ;; -esac - -for file -do - case $file in - /*) pathcomp=/ ;; - *) pathcomp= ;; - esac - oIFS=$IFS - IFS=/ - set fnord $file - shift - IFS=$oIFS - - for d - do - test "x$d" = x && continue - - pathcomp=$pathcomp$d - case $pathcomp in - -*) pathcomp=./$pathcomp ;; - esac - - if test ! -d "$pathcomp"; then - echo "mkdir $pathcomp" - - mkdir "$pathcomp" || lasterr=$? - - if test ! -d "$pathcomp"; then - errstatus=$lasterr - else - if test ! -z "$dirmode"; then - echo "chmod $dirmode $pathcomp" - lasterr= - chmod "$dirmode" "$pathcomp" || lasterr=$? - - if test ! -z "$lasterr"; then - errstatus=$lasterr - fi - fi - fi - fi - - pathcomp=$pathcomp/ - done -done - -exit $errstatus - -# Local Variables: -# mode: shell-script -# sh-indentation: 2 -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-end: "$" -# End: diff --git a/libltdl/stamp-h1 b/libltdl/stamp-h1 deleted file mode 100644 index 4547fe1b..00000000 --- a/libltdl/stamp-h1 +++ /dev/null @@ -1 +0,0 @@ -timestamp for config.h -- cgit From bb2e1afd5181ac67a7daf769b9adc506665a8ed4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Oct 2007 00:49:50 +0000 Subject: initialize userdata struct with 0 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1994 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 7b6b1b82..5ad4711d 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -448,7 +448,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G if (command == PA_COMMAND_ERROR) pa_log("Failed to get latency."); else - pa_log("Protocol error."); + pa_log("Protocol error 1."); goto fail; } @@ -590,7 +590,7 @@ static void sink_input_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED if (command == PA_COMMAND_ERROR) pa_log("Failed to get info."); else - pa_log("Protocol error."); + pa_log("Protocol error 2."); goto fail; } @@ -695,7 +695,7 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN if (command == PA_COMMAND_ERROR) pa_log("Failed to create stream."); else - pa_log("Protocol error."); + pa_log("Protocol error 3."); goto fail; } @@ -773,7 +773,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t if (command == PA_COMMAND_ERROR) pa_log("Failed to authenticate"); else - pa_log("Protocol error."); + pa_log("Protocol error 4."); goto fail; } @@ -1038,7 +1038,7 @@ int pa__init(pa_module*m) { goto fail; } - u = pa_xnew(struct userdata, 1); + u = pa_xnew0(struct userdata, 1); m->userdata = u; u->module = m; u->core = m->core; -- cgit From 1e0454eb74485d0f323e7cecd55470a38bd5683e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Oct 2007 01:50:22 +0000 Subject: rework the tunnel naming scheme, and make it follow the description changes of the underlying devices; never check for tagstruct eof, to ease later extensions git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1995 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 260 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 231 insertions(+), 29 deletions(-) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 5ad4711d..c36e70b7 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -123,8 +123,8 @@ enum { #ifdef TUNNEL_SINK static void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); #endif +static void command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_overflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); @@ -132,8 +132,8 @@ static void command_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { #ifdef TUNNEL_SINK [PA_COMMAND_REQUEST] = command_request, - [PA_COMMAND_SUBSCRIBE_EVENT] = command_subscribe_event, #endif + [PA_COMMAND_SUBSCRIBE_EVENT] = command_subscribe_event, [PA_COMMAND_OVERFLOW] = command_overflow, [PA_COMMAND_UNDERFLOW] = command_underflow, [PA_COMMAND_PLAYBACK_STREAM_KILLED] = command_stream_killed, @@ -177,6 +177,10 @@ struct userdata { pa_smoother *smoother; + char *device_description; + char *server_fqdn; + char *user_name; + uint32_t maxlength; #ifdef TUNNEL_SINK uint32_t tlength; @@ -414,8 +418,7 @@ static void command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED ui pa_assert(u->pdispatch == pd); if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { + pa_tagstruct_getu32(t, &bytes) < 0) { pa_log("Invalid protocol reply"); goto fail; } @@ -458,8 +461,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G pa_tagstruct_get_timeval(t, &local) < 0 || pa_tagstruct_get_timeval(t, &remote) < 0 || pa_tagstruct_gets64(t, &write_index) < 0 || - pa_tagstruct_gets64(t, &read_index) < 0 || - !pa_tagstruct_eof(t)) { + pa_tagstruct_gets64(t, &read_index) < 0) { pa_log("Invalid reply. (latency)"); goto fail; } @@ -571,8 +573,119 @@ static pa_usec_t source_get_latency(pa_source *s) { } #endif +static void update_description(struct userdata *u) { + char *d; + + pa_assert(u); + + if (!u->server_fqdn || !u->user_name || !u->device_description) + return; + + d = pa_sprintf_malloc("%s's %s on %s", u->user_name, u->device_description, u->server_fqdn); + +#ifdef TUNNEL_SINK + pa_sink_set_description(u->sink, d); +#else + pa_source_set_description(u->source, d); +#endif + + pa_xfree(d); +} + +static void server_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + pa_sample_spec ss; + const char *server_name, *server_version, *user_name, *host_name, *default_sink_name, *default_source_name; + uint32_t cookie; + + pa_assert(pd); + pa_assert(u); + + if (command != PA_COMMAND_REPLY) { + if (command == PA_COMMAND_ERROR) + pa_log("Failed to get info."); + else + pa_log("Protocol error 6."); + goto fail; + } + + if (pa_tagstruct_gets(t, &server_name) < 0 || + pa_tagstruct_gets(t, &server_version) < 0 || + pa_tagstruct_gets(t, &user_name) < 0 || + pa_tagstruct_gets(t, &host_name) < 0 || + pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_gets(t, &default_sink_name) < 0 || + pa_tagstruct_gets(t, &default_source_name) < 0 || + pa_tagstruct_getu32(t, &cookie) < 0) { + pa_log("Invalid reply. (get_server_info)"); + goto fail; + } + + pa_xfree(u->server_fqdn); + u->server_fqdn = pa_xstrdup(host_name); + + pa_xfree(u->user_name); + u->user_name = pa_xstrdup(user_name); + + update_description(u); + + return; + +fail: + pa_module_unload_request(u->module); +} + #ifdef TUNNEL_SINK +static void sink_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + uint32_t idx, owner_module, monitor_source, flags; + const char *name, *description, *monitor_source_name, *driver; + pa_sample_spec ss; + pa_channel_map cm; + pa_cvolume volume; + int mute; + pa_usec_t latency; + + pa_assert(pd); + pa_assert(u); + + if (command != PA_COMMAND_REPLY) { + if (command == PA_COMMAND_ERROR) + pa_log("Failed to get info."); + else + pa_log("Protocol error 5."); + goto fail; + } + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_gets(t, &description) < 0 || + pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_get_channel_map(t, &cm) < 0 || + pa_tagstruct_getu32(t, &owner_module) < 0 || + pa_tagstruct_get_cvolume(t, &volume) < 0 || + pa_tagstruct_get_boolean(t, &mute) < 0 || + pa_tagstruct_getu32(t, &monitor_source) < 0 || + pa_tagstruct_gets(t, &monitor_source_name) < 0 || + pa_tagstruct_get_usec(t, &latency) < 0 || + pa_tagstruct_gets(t, &driver) < 0 || + pa_tagstruct_getu32(t, &flags) < 0) { + pa_log("Invalid reply. (get_sink_info)"); + goto fail; + } + + pa_xfree(u->device_description); + u->device_description = pa_xstrdup(description); + + update_description(u); + + return; + +fail: + pa_module_unload_request(u->module); +} + static void sink_input_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; uint32_t idx, owner_module, client, sink; @@ -606,12 +719,14 @@ static void sink_input_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED pa_tagstruct_get_usec(t, &sink_usec) < 0 || pa_tagstruct_gets(t, &resample_method) < 0 || pa_tagstruct_gets(t, &driver) < 0 || - (u->version >= 11 && pa_tagstruct_get_boolean(t, &mute) < 0) || - !pa_tagstruct_eof(t)) { + (u->version >= 11 && pa_tagstruct_get_boolean(t, &mute) < 0)) { pa_log("Invalid reply. (get_info)"); goto fail; } + if (idx != u->device_index) + return; + pa_assert(u->sink); if ((u->version < 11 || !!mute == !!u->sink->muted) && @@ -630,17 +745,94 @@ fail: pa_module_unload_request(u->module); } +#else + +static void source_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + uint32_t idx, owner_module, monitor_of_sink, flags; + const char *name, *description, *monitor_of_sink_name, *driver; + pa_sample_spec ss; + pa_channel_map cm; + pa_cvolume volume; + int mute; + pa_usec_t latency; + + pa_assert(pd); + pa_assert(u); + + if (command != PA_COMMAND_REPLY) { + if (command == PA_COMMAND_ERROR) + pa_log("Failed to get info."); + else + pa_log("Protocol error 5."); + goto fail; + } + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_gets(t, &description) < 0 || + pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_get_channel_map(t, &cm) < 0 || + pa_tagstruct_getu32(t, &owner_module) < 0 || + pa_tagstruct_get_cvolume(t, &volume) < 0 || + pa_tagstruct_get_boolean(t, &mute) < 0 || + pa_tagstruct_getu32(t, &monitor_of_sink) < 0 || + pa_tagstruct_gets(t, &monitor_of_sink_name) < 0 || + pa_tagstruct_get_usec(t, &latency) < 0 || + pa_tagstruct_gets(t, &driver) < 0 || + pa_tagstruct_getu32(t, &flags) < 0) { + pa_log("Invalid reply. (get_source_info)"); + goto fail; + } + + pa_xfree(u->device_description); + u->device_description = pa_xstrdup(description); + + update_description(u); + + return; + +fail: + pa_module_unload_request(u->module); +} + +#endif + static void request_info(struct userdata *u) { pa_tagstruct *t; uint32_t tag; pa_assert(u); + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); + pa_tagstruct_putu32(t, tag = u->ctag++); + pa_pstream_send_tagstruct(u->pstream, t); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, server_info_cb, u, NULL); + +#ifdef TUNNEL_SINK t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INPUT_INFO); pa_tagstruct_putu32(t, tag = u->ctag++); pa_tagstruct_putu32(t, u->device_index); pa_pstream_send_tagstruct(u->pstream, t); pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, sink_input_info_cb, u, NULL); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); + pa_tagstruct_putu32(t, tag = u->ctag++); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, u->sink_name); + pa_pstream_send_tagstruct(u->pstream, t); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, sink_info_cb, u, NULL); +#else + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); + pa_tagstruct_putu32(t, tag = u->ctag++); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, u->source_name); + pa_pstream_send_tagstruct(u->pstream, t); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, source_info_cb, u, NULL); +#endif } static void command_subscribe_event(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -654,14 +846,20 @@ static void command_subscribe_event(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t com pa_assert(command == PA_COMMAND_SUBSCRIBE_EVENT); if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { + pa_tagstruct_getu32(t, &idx) < 0) { pa_log("Invalid protocol reply"); pa_module_unload_request(u->module); return; } - if (e != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE)) + if (e != (PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE) && +#ifdef TUNNEL_SINK + e != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) && + e != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE) +#else + e != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE) +#endif + ) return; request_info(u); @@ -675,10 +873,16 @@ static void start_subscribe(struct userdata *u) { t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); pa_tagstruct_putu32(t, tag = u->ctag++); - pa_tagstruct_putu32(t, PA_SUBSCRIPTION_MASK_SINK_INPUT); + pa_tagstruct_putu32(t, PA_SUBSCRIPTION_MASK_SERVER| +#ifdef TUNNEL_SINK + PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SINK +#else + PA_SUBSCRIPTION_MASK_SOURCE +#endif + ); + pa_pstream_send_tagstruct(u->pstream, t); } -#endif static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; @@ -725,13 +929,8 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN #endif } - if (!pa_tagstruct_eof(t)) - goto parse_error; - -#ifdef TUNNEL_SINK start_subscribe(u); request_info(u); -#endif pa_assert(!u->time_event); pa_gettimeofday(&ntv); @@ -768,8 +967,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_assert(u->pdispatch == pd); if (command != PA_COMMAND_REPLY || - pa_tagstruct_getu32(t, &u->version) < 0 || - !pa_tagstruct_eof(t)) { + pa_tagstruct_getu32(t, &u->version) < 0) { if (command == PA_COMMAND_ERROR) pa_log("Failed to authenticate"); else @@ -785,21 +983,21 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t } #ifdef TUNNEL_SINK - pa_snprintf(name, sizeof(name), "Tunnel from host %s, user %s, sink %s", - pa_get_host_name(hn, sizeof(hn)), + pa_snprintf(name, sizeof(name), "%s@%s", pa_get_user_name(un, sizeof(un)), + pa_get_host_name(hn, sizeof(hn)), u->sink->name); #else - pa_snprintf(name, sizeof(name), "Tunnel from host %s, user %s, source %s", - pa_get_host_name(hn, sizeof(hn)), + pa_snprintf(name, sizeof(name), "%s@%s", pa_get_user_name(un, sizeof(un)), + pa_get_host_name(hn, sizeof(hn)), u->source->name); #endif reply = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME); pa_tagstruct_putu32(reply, tag = u->ctag++); - pa_tagstruct_puts(reply, name); + pa_tagstruct_puts(reply, "PulseAudio"); pa_pstream_send_tagstruct(u->pstream, reply); /* We ignore the server's reply here */ @@ -1004,7 +1202,7 @@ static int load_key(struct userdata *u, const char*fn) { u->auth_cookie_in_property = FALSE; if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { - pa_log_debug("using already loaded auth cookie."); + pa_log_debug("Using already loaded auth cookie."); pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); u->auth_cookie_in_property = 1; return 0; @@ -1016,7 +1214,7 @@ static int load_key(struct userdata *u, const char*fn) { if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) return -1; - pa_log_debug("loading cookie from disk."); + pa_log_debug("Loading cookie from disk."); if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) u->auth_cookie_in_property = TRUE; @@ -1108,7 +1306,7 @@ int pa__init(pa_module*m) { pa_sink_set_module(u->sink, m); pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); pa_sink_set_rtpoll(u->sink, u->rtpoll); - pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Tunnel to %s%s%s", u->sink_name ? u->sink_name : "", u->sink_name ? " on " : "", u->server_name)); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("%s%s%s", u->sink_name ? u->sink_name : "", u->sink_name ? " on " : "", u->server_name)); pa_xfree(t); #else @@ -1130,7 +1328,7 @@ int pa__init(pa_module*m) { pa_source_set_module(u->source, m); pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); pa_source_set_rtpoll(u->source, u->rtpoll); - pa_source_set_description(u->source, t = pa_sprintf_malloc("Tunnel to %s%s%s", u->source_name ? u->source_name : "", u->source_name ? " on " : "", u->server_name)); + pa_source_set_description(u->source, t = pa_sprintf_malloc("%s%s%s", u->source_name ? u->source_name : "", u->source_name ? " on " : "", u->server_name)); pa_xfree(t); #endif @@ -1237,5 +1435,9 @@ void pa__done(pa_module*m) { #endif pa_xfree(u->server_name); + pa_xfree(u->device_description); + pa_xfree(u->server_fqdn); + pa_xfree(u->user_name); + pa_xfree(u); } -- cgit From 201dff7b2e881228b14c4aa67fb51360f548043c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Oct 2007 02:05:53 +0000 Subject: ignore updates not relevant to us git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1996 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index c36e70b7..485b6f3b 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -675,6 +675,9 @@ static void sink_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint3 goto fail; } + if (strcmp(name, u->sink_name)) + return; + pa_xfree(u->device_description); u->device_description = pa_xstrdup(description); @@ -785,6 +788,9 @@ static void source_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uin goto fail; } + if (strcmp(name, u->source_name)) + return; + pa_xfree(u->device_description); u->device_description = pa_xstrdup(description); -- cgit From 72817f9d9dcd7548972b7d1090fefa19436ca538 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Oct 2007 02:35:00 +0000 Subject: rename stream names too, when the sink name changes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1997 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 485b6f3b..edc03c99 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -575,13 +575,15 @@ static pa_usec_t source_get_latency(pa_source *s) { static void update_description(struct userdata *u) { char *d; + char un[128], hn[128]; + pa_tagstruct *t; pa_assert(u); if (!u->server_fqdn || !u->user_name || !u->device_description) return; - d = pa_sprintf_malloc("%s's %s on %s", u->user_name, u->device_description, u->server_fqdn); + d = pa_sprintf_malloc("%s on %s@%s", u->device_description, u->user_name, u->server_fqdn); #ifdef TUNNEL_SINK pa_sink_set_description(u->sink, d); @@ -590,6 +592,23 @@ static void update_description(struct userdata *u) { #endif pa_xfree(d); + + d = pa_sprintf_malloc("%s for %s@%s", u->device_description, + pa_get_user_name(un, sizeof(un)), + pa_get_host_name(hn, sizeof(hn))); + + t = pa_tagstruct_new(NULL, 0); +#ifdef TUNNEL_SINK + pa_tagstruct_putu32(t, PA_COMMAND_SET_PLAYBACK_STREAM_NAME); +#else + pa_tagstruct_putu32(t, PA_COMMAND_SET_RECORD_STREAM_NAME); +#endif + pa_tagstruct_putu32(t, u->ctag++); + pa_tagstruct_putu32(t, u->channel); + pa_tagstruct_puts(t, d); + pa_pstream_send_tagstruct(u->pstream, t); + + pa_xfree(d); } static void server_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -989,15 +1008,15 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t } #ifdef TUNNEL_SINK - pa_snprintf(name, sizeof(name), "%s@%s", - pa_get_user_name(un, sizeof(un)), - pa_get_host_name(hn, sizeof(hn)), - u->sink->name); + pa_snprintf(name, sizeof(name), "%s for %s@%s", + u->sink_name, + pa_get_user_name(un, sizeof(un)), + pa_get_host_name(hn, sizeof(hn))); #else - pa_snprintf(name, sizeof(name), "%s@%s", - pa_get_user_name(un, sizeof(un)), - pa_get_host_name(hn, sizeof(hn)), - u->source->name); + pa_snprintf(name, sizeof(name), "%s for %s@%s", + u->source_name, + pa_get_user_name(un, sizeof(un)), + pa_get_host_name(hn, sizeof(hn))); #endif reply = pa_tagstruct_new(NULL, 0); -- cgit From b84489d8b3f382a847ac9ff2ed56cef2b4762efd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Oct 2007 14:05:18 +0000 Subject: handle tcp4: prefix for server specs correctly. (Closes #136) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1998 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/parseaddr.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/parseaddr.c b/src/pulsecore/parseaddr.c index 65ba64c1..149c9e00 100644 --- a/src/pulsecore/parseaddr.c +++ b/src/pulsecore/parseaddr.c @@ -103,9 +103,12 @@ int pa_parse_address(const char *name, pa_parsed_address *ret_p) { else if (pa_startswith(p, "unix:")) { ret_p->type = PA_PARSED_ADDRESS_UNIX; p += sizeof("unix:")-1; - } else if (pa_startswith(p, "tcp:") || pa_startswith(p, "tcp4:")) { + } else if (pa_startswith(p, "tcp:")) { ret_p->type = PA_PARSED_ADDRESS_TCP4; p += sizeof("tcp:")-1; + } else if (pa_startswith(p, "tcp4:")) { + ret_p->type = PA_PARSED_ADDRESS_TCP4; + p += sizeof("tcp4:")-1; } else if (pa_startswith(p, "tcp6:")) { ret_p->type = PA_PARSED_ADDRESS_TCP6; p += sizeof("tcp6:")-1; -- cgit From b03b5741ea689b3bb08b7fef9cc905cae3a5ad99 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Oct 2007 14:17:41 +0000 Subject: rename 'length' parameters in the API to 'bytes', to make their unit clear git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1999 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/simple.h | 4 ++-- src/pulse/stream.h | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/pulse/simple.h b/src/pulse/simple.h index f76c1d67..0ddd57e0 100644 --- a/src/pulse/simple.h +++ b/src/pulse/simple.h @@ -130,13 +130,13 @@ pa_simple* pa_simple_new( void pa_simple_free(pa_simple *s); /** Write some data to the server */ -int pa_simple_write(pa_simple *s, const void*data, size_t length, int *error); +int pa_simple_write(pa_simple *s, const void*data, size_t bytes, int *error); /** Wait until all data already written is played by the daemon */ int pa_simple_drain(pa_simple *s, int *error); /** Read some data from the server */ -int pa_simple_read(pa_simple *s, void*data, size_t length, int *error); +int pa_simple_read(pa_simple *s, void*data, size_t bytes, int *error); /** Return the playback latency. \since 0.5 */ pa_usec_t pa_simple_get_latency(pa_simple *s, int *error); diff --git a/src/pulse/stream.h b/src/pulse/stream.h index 65603262..8c6a90c1 100644 --- a/src/pulse/stream.h +++ b/src/pulse/stream.h @@ -271,7 +271,7 @@ typedef struct pa_stream pa_stream; typedef void (*pa_stream_success_cb_t) (pa_stream*s, int success, void *userdata); /** A generic request callback */ -typedef void (*pa_stream_request_cb_t)(pa_stream *p, size_t length, void *userdata); +typedef void (*pa_stream_request_cb_t)(pa_stream *p, size_t bytes, void *userdata); /** A generic notification callback */ typedef void (*pa_stream_notify_cb_t)(pa_stream *p, void *userdata); @@ -327,7 +327,7 @@ int pa_stream_disconnect(pa_stream *s); int pa_stream_write( pa_stream *p /**< The stream to use */, const void *data /**< The data to write */, - size_t length /**< The length of the data to write */, + size_t bytes /**< The length of the data to write in bytes*/, pa_free_cb_t free_cb /**< A cleanup routine for the data or NULL to request an internal copy */, int64_t offset, /**< Offset for seeking, must be 0 for upload streams */ pa_seek_mode_t seek /**< Seek mode, must be PA_SEEK_RELATIVE for upload streams */); @@ -340,16 +340,16 @@ int pa_stream_write( int pa_stream_peek( pa_stream *p /**< The stream to use */, const void **data /**< Pointer to pointer that will point to data */, - size_t *length /**< The length of the data read */); + size_t *bytes /**< The length of the data read in bytes */); /** Remove the current fragment on record streams. It is invalid to do this without first * calling pa_stream_peek(). \since 0.8 */ int pa_stream_drop(pa_stream *p); -/** Return the nember of bytes that may be written using pa_stream_write() */ +/** Return the nember of bytes that may be written using pa_stream_write(), in bytes */ size_t pa_stream_writable_size(pa_stream *p); -/** Return the number of bytes that may be read using pa_stream_read() \since 0.8 */ +/** Return the number of bytes that may be read using pa_stream_read(), in bytes \since 0.8 */ size_t pa_stream_readable_size(pa_stream *p); /** Drain a playback stream. Use this for notification when the buffer is empty */ -- cgit From 099e6903e91d418ecf23a1af4a92b5ceb101b0ea Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Oct 2007 15:08:13 +0000 Subject: make make distcheck pass git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2000 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 288c24ef..cbb47c72 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,7 +18,7 @@ # USA. EXTRA_DIST = bootstrap.sh LICENSE GPL LGPL doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in README todo -SUBDIRS=libltdl src doxygen +SUBDIRS=src doxygen MAINTAINERCLEANFILES = noinst_DATA = -- cgit From 0f0e729b9a252c7e79133cedef389b345232cae7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Oct 2007 15:23:56 +0000 Subject: make sjoerd happy: include ChangeLog built from svn logs in tarball git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2001 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Makefile.am b/Makefile.am index cbb47c72..79608a22 100644 --- a/Makefile.am +++ b/Makefile.am @@ -54,4 +54,11 @@ untabify: fedora-snapshot: dist cp $(distdir).tar.gz $$HOME/cvs.fedora/pulseaudio/devel/$(distdir).svn`date +%Y%m%d`.tar.gz +dist-hook: + if test -d .svn ; then \ + svn update ; \ + chmod u+w ${distdir}/ChangeLog || true ; \ + svn2cl -o ${distdir}/ChangeLog ; \ + fi + .PHONY: homepage distcleancheck doxygen -- cgit From 111b7591bdb18783799981c1e341ed2d9fe79ef5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Oct 2007 16:02:25 +0000 Subject: bump sonames git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2002 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 567dc4ed..e08c11c1 100644 --- a/configure.ac +++ b/configure.ac @@ -41,9 +41,9 @@ AC_SUBST(PA_PROTOCOL_VERSION, 11) AC_SUBST(LIBPULSE_VERSION_INFO, [3:0:3]) AC_SUBST(LIBPULSECORE_VERSION_INFO, [4:0:0]) -AC_SUBST(LIBPULSE_SIMPLE_VERSION_INFO, [0:0:0]) -AC_SUBST(LIBPULSE_BROWSE_VERSION_INFO, [1:0:1]) -AC_SUBST(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO, [0:2:0]) +AC_SUBST(LIBPULSE_SIMPLE_VERSION_INFO, [0:1:0]) +AC_SUBST(LIBPULSE_BROWSE_VERSION_INFO, [1:1:1]) +AC_SUBST(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO, [0:3:0]) AC_CANONICAL_HOST -- cgit From 5058a1e9ed700264df78409e0d629fb18a0263ef Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Oct 2007 18:35:08 +0000 Subject: save and restore errno in the sig handler git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2004 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/mainloop-signal.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/pulse/mainloop-signal.c b/src/pulse/mainloop-signal.c index 7d3017e2..e41ed14c 100644 --- a/src/pulse/mainloop-signal.c +++ b/src/pulse/mainloop-signal.c @@ -67,10 +67,16 @@ static pa_io_event* io_event = NULL; static pa_signal_event *signals = NULL; static void signal_handler(int sig) { + int saved_errno; + + saved_errno = errno; + #ifndef HAVE_SIGACTION signal(sig, signal_handler); #endif pa_write(signal_pipe[1], &sig, sizeof(sig), NULL); + + errno = saved_errno; } static void dispatch(pa_mainloop_api*a, int sig) { -- cgit From 38a1525a8928d8c60fbe5227970e6c4604c5fa73 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Nov 2007 00:06:31 +0000 Subject: add new function pa_yes_no() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2005 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/core-util.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index d26cf241..a6d22101 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -31,6 +31,7 @@ #include #include +#include struct timeval; @@ -62,6 +63,10 @@ void pa_reset_priority(void); int pa_parse_boolean(const char *s) PA_GCC_PURE; +static inline const char *pa_yes_no(pa_bool_t b) { + return b ? "yes" : "no"; +} + char *pa_split(const char *c, const char*delimiters, const char **state); char *pa_split_spaces(const char *c, const char **state); -- cgit From cecd8d4d7b987ff38357ee5127f6d7479843184f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Nov 2007 00:06:51 +0000 Subject: fix comment git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2006 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/core-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index eefcc584..3e70eb5c 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -541,7 +541,7 @@ void pa_make_realtime(void) { #define NICE_LEVEL (-11) /* Raise the priority of the current process as much as possible and -sensible: set the nice level to -15.*/ +sensible: set the nice level to -11.*/ void pa_raise_priority(void) { #ifdef HAVE_SYS_RESOURCE_H -- cgit From b343497d647f349b8b0a8adf50df8047ac27ecbc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Nov 2007 00:31:59 +0000 Subject: make the bool config parser actually parse bools git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2007 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/conf-parser.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pulsecore/conf-parser.c b/src/pulsecore/conf-parser.c index 0e0ba95a..12ea49c2 100644 --- a/src/pulsecore/conf-parser.c +++ b/src/pulsecore/conf-parser.c @@ -169,7 +169,8 @@ int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, } int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { - int *b = data, k; + int k; + pa_bool_t *b = data; pa_assert(filename); pa_assert(lvalue); @@ -181,7 +182,7 @@ int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue return -1; } - *b = k; + *b = !!k; return 0; } -- cgit From 65a6bff357a3ec27de8dd78e1201e75a7d959464 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Nov 2007 00:32:45 +0000 Subject: more pa_boolization git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2008 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/cli-command.c | 175 ++++++++++++++++++++++---------------------- src/pulsecore/cli-command.h | 8 +- src/pulsecore/cli.c | 8 +- 3 files changed, 96 insertions(+), 95 deletions(-) diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index 539fd34d..9bd1b509 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -58,7 +58,7 @@ struct command { const char *name; - int (*proc) (pa_core *c, pa_tokenizer*t, pa_strbuf *buf, int *fail); + int (*proc) (pa_core *c, pa_tokenizer*t, pa_strbuf *buf, pa_bool_t *fail); const char *help; unsigned args; }; @@ -77,46 +77,46 @@ enum { }; /* Prototypes for all available commands */ -static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); -static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); +static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); /* A method table for all available commands */ @@ -181,7 +181,7 @@ static uint32_t parse_index(const char *n) { return idx; } -static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { pa_core_assert_ref(c); pa_assert(t); pa_assert(buf); @@ -191,7 +191,7 @@ static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int return 0; } -static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const struct command*command; pa_core_assert_ref(c); @@ -207,7 +207,7 @@ static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int return 0; } -static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { char *s; pa_core_assert_ref(c); @@ -221,7 +221,7 @@ static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, i return 0; } -static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { char *s; pa_core_assert_ref(c); @@ -235,7 +235,7 @@ static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, i return 0; } -static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { char *s; pa_core_assert_ref(c); @@ -249,7 +249,7 @@ static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int return 0; } -static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { char *s; pa_core_assert_ref(c); @@ -263,7 +263,7 @@ static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, i return 0; } -static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { char *s; pa_core_assert_ref(c); @@ -277,7 +277,7 @@ static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *bu return 0; } -static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { char *s; pa_core_assert_ref(c); @@ -291,7 +291,7 @@ static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf return 0; } -static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { char s[256]; const pa_mempool_stat *stat; unsigned k; @@ -352,7 +352,7 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int return 0; } -static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { pa_core_assert_ref(c); pa_assert(t); pa_assert(buf); @@ -370,7 +370,7 @@ static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int return 0; } -static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { pa_module *m; const char *name; @@ -392,7 +392,7 @@ static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int return 0; } -static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { pa_module *m; uint32_t idx; const char *i; @@ -418,7 +418,7 @@ static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, in return 0; } -static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *n, *v; pa_sink *sink; uint32_t volume; @@ -454,7 +454,7 @@ static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *bu return 0; } -static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *n, *v; pa_sink_input *si; pa_volume_t volume; @@ -496,7 +496,7 @@ static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strb return 0; } -static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *n, *v; pa_source *source; uint32_t volume; @@ -532,7 +532,7 @@ static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf * return 0; } -static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *n, *m; pa_sink *sink; int mute; @@ -566,7 +566,7 @@ static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, return 0; } -static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *n, *m; pa_source *source; int mute; @@ -600,7 +600,7 @@ static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *bu return 0; } -static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *n, *v; pa_sink_input *si; uint32_t idx; @@ -640,7 +640,7 @@ static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf return 0; } -static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *n; pa_core_assert_ref(c); @@ -657,7 +657,7 @@ static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *b return 0; } -static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *n; pa_core_assert_ref(c); @@ -674,7 +674,7 @@ static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf return 0; } -static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *n; pa_client *client; uint32_t idx; @@ -703,7 +703,7 @@ static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *bu return 0; } -static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *n; pa_sink_input *sink_input; uint32_t idx; @@ -732,7 +732,7 @@ static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf return 0; } -static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *n; pa_source_output *source_output; uint32_t idx; @@ -761,7 +761,7 @@ static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_str return 0; } -static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { char *s; pa_core_assert_ref(c); @@ -776,7 +776,7 @@ static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *bu return 0; } -static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *n, *sink_name; pa_sink *sink; @@ -803,7 +803,7 @@ static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *bu return 0; } -static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *n; pa_core_assert_ref(c); @@ -824,7 +824,7 @@ static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf * return 0; } -static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *fname, *n; int r; @@ -849,7 +849,7 @@ static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *bu return 0; } -static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *pname; pa_core_assert_ref(c); @@ -870,7 +870,7 @@ static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf return 0; } -static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *fname, *sink_name; pa_sink *sink; @@ -893,7 +893,7 @@ static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, return pa_play_file(sink, fname, NULL); } -static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *a, *b; pa_core_assert_ref(c); @@ -911,7 +911,7 @@ static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *b return 0; } -static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *name; pa_core_assert_ref(c); @@ -932,7 +932,7 @@ static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf return 0; } -static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { char *s; pa_core_assert_ref(c); @@ -947,7 +947,7 @@ static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf * return 0; } -static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { pa_core_assert_ref(c); pa_assert(t); pa_assert(buf); @@ -957,7 +957,7 @@ static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf return 0; } -static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { pa_core_assert_ref(c); pa_assert(t); pa_assert(buf); @@ -968,7 +968,7 @@ static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, in return 0; } -static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *n, *k; pa_sink_input *si; pa_sink *sink; @@ -1011,7 +1011,7 @@ static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf return 0; } -static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *n, *k; pa_source_output *so; pa_source *source; @@ -1054,7 +1054,7 @@ static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_str return 0; } -static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *n, *m; pa_sink *sink; int suspend; @@ -1088,7 +1088,7 @@ static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *b return 0; } -static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *n, *m; pa_source *source; int suspend; @@ -1122,7 +1122,7 @@ static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf return 0; } -static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *m; int suspend; int ret; @@ -1152,7 +1152,7 @@ static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, i return 0; } -static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { +static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { pa_module *m; pa_sink *sink; pa_source *source; @@ -1261,7 +1261,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int return 0; } -int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *buf, int *fail, int *ifstate) { +int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *buf, pa_bool_t *fail, int *ifstate) { const char *cs; pa_assert(c); @@ -1293,9 +1293,9 @@ int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *b if (ifstate && *ifstate == IFSTATE_FALSE) return 0; if (!strcmp(cs, META_FAIL)) - *fail = 1; + *fail = TRUE; else if (!strcmp(cs, META_NOFAIL)) - *fail = 0; + *fail = FALSE; else { size_t l; l = strcspn(cs, whitespace); @@ -1358,11 +1358,11 @@ int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *b return 0; } -int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { +int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, pa_bool_t *fail) { return pa_cli_command_execute_line_stateful(c, s, buf, fail, NULL); } -int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int *fail) { +int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, pa_bool_t *fail) { char line[256]; FILE *f = NULL; int ifstate = IFSTATE_NONE; @@ -1396,7 +1396,7 @@ fail: return ret; } -int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { +int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, pa_bool_t *fail) { const char *p; int ifstate = IFSTATE_NONE; @@ -1421,4 +1421,3 @@ int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail) return 0; } - diff --git a/src/pulsecore/cli-command.h b/src/pulsecore/cli-command.h index 01bca8be..c90c8e08 100644 --- a/src/pulsecore/cli-command.h +++ b/src/pulsecore/cli-command.h @@ -31,15 +31,15 @@ * buffer *buf. If *fail is non-zero the function will return -1 when * one or more of the executed commands failed. *fail * may be modified by the function call. */ -int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail); +int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, pa_bool_t *fail); /* Execute a whole file of CLI commands */ -int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int *fail); +int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, pa_bool_t *fail); /* Split the specified string into lines and run pa_cli_command_execute_line() for each. */ -int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail); +int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, pa_bool_t *fail); /* Same as pa_cli_command_execute_line() but also take ifstate var. */ -int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *buf, int *fail, int *ifstate); +int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *buf, pa_bool_t *fail, int *ifstate); #endif diff --git a/src/pulsecore/cli.c b/src/pulsecore/cli.c index 3f3c9cde..85e08634 100644 --- a/src/pulsecore/cli.c +++ b/src/pulsecore/cli.c @@ -59,7 +59,8 @@ struct pa_cli { pa_client *client; - int fail, kill_requested, defer_kill; + pa_bool_t fail, kill_requested; + int defer_kill; }; static void line_callback(pa_ioline *line, const char *s, void *userdata); @@ -86,7 +87,8 @@ pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m) { pa_ioline_set_callback(c->line, line_callback, c); pa_ioline_puts(c->line, "Welcome to PulseAudio! Use \"help\" for usage information.\n"PROMPT); - c->fail = c->kill_requested = c->defer_kill = 0; + c->fail = c->kill_requested = FALSE; + c->defer_kill = 0; return c; } @@ -108,7 +110,7 @@ static void client_kill(pa_client *client) { pa_log_debug("CLI client killed."); if (c->defer_kill) - c->kill_requested = 1; + c->kill_requested = TRUE; else { if (c->eof_callback) c->eof_callback(c, c->userdata); -- cgit From e706f7bed759165573c9ec7e5e4f79a2f9b74228 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Nov 2007 00:33:14 +0000 Subject: pa_boolize the client config git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2009 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/client-conf.c | 11 +++++------ src/pulse/client-conf.h | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c index abd277a6..c054f663 100644 --- a/src/pulse/client-conf.c +++ b/src/pulse/client-conf.c @@ -58,10 +58,10 @@ static const pa_client_conf default_conf = { .default_sink = NULL, .default_source = NULL, .default_server = NULL, - .autospawn = 0, - .disable_shm = 0, + .autospawn = FALSE, + .disable_shm = FALSE, .cookie_file = NULL, - .cookie_valid = 0, + .cookie_valid = FALSE, }; pa_client_conf *pa_client_conf_new(void) { @@ -172,7 +172,7 @@ int pa_client_conf_env(pa_client_conf *c) { int pa_client_conf_load_cookie(pa_client_conf* c) { pa_assert(c); - c->cookie_valid = 0; + c->cookie_valid = FALSE; if (!c->cookie_file) return -1; @@ -180,7 +180,6 @@ int pa_client_conf_load_cookie(pa_client_conf* c) { if (pa_authkey_load_auto(c->cookie_file, c->cookie, sizeof(c->cookie)) < 0) return -1; - c->cookie_valid = 1; + c->cookie_valid = TRUE; return 0; } - diff --git a/src/pulse/client-conf.h b/src/pulse/client-conf.h index 6de64582..7cc975e6 100644 --- a/src/pulse/client-conf.h +++ b/src/pulse/client-conf.h @@ -30,9 +30,9 @@ typedef struct pa_client_conf { char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server, *cookie_file; - int autospawn, disable_shm; + pa_bool_t autospawn, disable_shm; uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; - int cookie_valid; /* non-zero, when cookie is valid */ + pa_bool_t cookie_valid; /* non-zero, when cookie is valid */ } pa_client_conf; /* Create a new configuration data object and reset it to defaults */ -- cgit From 44d7c9ad9bcfd8ab55d4ef7f6595c7ffd65da35d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Nov 2007 00:34:43 +0000 Subject: add nice and rtprio resource limit support; make rtprio and nice level to use configurable; some minor updates git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2010 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/daemon-conf.c | 177 +++++++++++++++++++++++++++++++++------------- src/daemon/daemon-conf.h | 24 +++++-- src/daemon/daemon.conf.in | 89 +++++++++++++++-------- src/daemon/main.c | 6 ++ 4 files changed, 210 insertions(+), 86 deletions(-) diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 920e3717..089b12fc 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -53,10 +54,13 @@ static const pa_daemon_conf default_conf = { .cmd = PA_CMD_DAEMON, - .daemonize = 0, - .fail = 1, - .high_priority = 0, - .disallow_module_loading = 0, + .daemonize = FALSE, + .fail = TRUE, + .high_priority = TRUE, + .nice_level = -11, + .realtime_scheduling = FALSE, + .realtime_priority = 5, /* Half of JACK's default rtprio */ + .disallow_module_loading = FALSE, .exit_idle_time = -1, .module_idle_time = 20, .scache_idle_time = 20, @@ -68,25 +72,31 @@ static const pa_daemon_conf default_conf = { .log_level = PA_LOG_NOTICE, .resample_method = PA_RESAMPLER_AUTO, .config_file = NULL, - .use_pid_file = 1, - .system_instance = 0, - .no_cpu_limit = 0, - .disable_shm = 0, + .use_pid_file = TRUE, + .system_instance = FALSE, + .no_cpu_limit = FALSE, + .disable_shm = FALSE, .default_n_fragments = 4, .default_fragment_size_msec = 25, .default_sample_spec = { .format = PA_SAMPLE_S16NE, .rate = 44100, .channels = 2 } #ifdef HAVE_SYS_RESOURCE_H - , .rlimit_as = { .value = 0, .is_set = 0 }, - .rlimit_core = { .value = 0, .is_set = 0 }, - .rlimit_data = { .value = 0, .is_set = 0 }, - .rlimit_fsize = { .value = 0, .is_set = 0 }, - .rlimit_nofile = { .value = 256, .is_set = 1 }, - .rlimit_stack = { .value = 0, .is_set = 0 } + , .rlimit_as = { .value = 0, .is_set = FALSE }, + .rlimit_core = { .value = 0, .is_set = FALSE }, + .rlimit_data = { .value = 0, .is_set = FALSE }, + .rlimit_fsize = { .value = 0, .is_set = FALSE }, + .rlimit_nofile = { .value = 256, .is_set = TRUE }, + .rlimit_stack = { .value = 0, .is_set = FALSE } #ifdef RLIMIT_NPROC - , .rlimit_nproc = { .value = 0, .is_set = 0 } + , .rlimit_nproc = { .value = 0, .is_set = FALSE } #endif #ifdef RLIMIT_MEMLOCK - , .rlimit_memlock = { .value = 16384, .is_set = 1 } + , .rlimit_memlock = { .value = 16384, .is_set = TRUE } +#endif +#ifdef RLIMIT_NICE + , .rlimit_nice = { .value = 31, .is_set = TRUE } /* nice level of -11 */ +#endif +#ifdef RLIMIT_RTPRIO + , .rlimit_rtprio = { .value = 9, .is_set = TRUE } /* One below JACK's default for the server */ #endif #endif }; @@ -334,6 +344,42 @@ static int parse_fragment_size_msec(const char *filename, unsigned line, const c return 0; } +static int parse_nice_level(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + pa_daemon_conf *c = data; + int32_t level; + + pa_assert(filename); + pa_assert(lvalue); + pa_assert(rvalue); + pa_assert(data); + + if (pa_atoi(rvalue, &level) < 0 || level < -20 || level > 19) { + pa_log("[%s:%u] Invalid nice level '%s'.", filename, line, rvalue); + return -1; + } + + c->nice_level = (int) level; + return 0; +} + +static int parse_rtprio(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { + pa_daemon_conf *c = data; + int32_t rtprio; + + pa_assert(filename); + pa_assert(lvalue); + pa_assert(rvalue); + pa_assert(data); + + if (pa_atoi(rvalue, &rtprio) < 0 || rtprio < sched_get_priority_min(SCHED_FIFO) || rtprio > sched_get_priority_max(SCHED_FIFO)) { + pa_log("[%s:%u] Invalid realtime priority '%s'.", filename, line, rvalue); + return -1; + } + + c->realtime_priority = (int) rtprio; + return 0; +} + int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { int r = -1; FILE *f = NULL; @@ -342,25 +388,28 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { { "daemonize", pa_config_parse_bool, NULL }, { "fail", pa_config_parse_bool, NULL }, { "high-priority", pa_config_parse_bool, NULL }, + { "realtime-scheduling", pa_config_parse_bool, NULL }, { "disallow-module-loading", pa_config_parse_bool, NULL }, + { "use-pid-file", pa_config_parse_bool, NULL }, + { "system-instance", pa_config_parse_bool, NULL }, + { "no-cpu-limit", pa_config_parse_bool, NULL }, + { "disable-shm", pa_config_parse_bool, NULL }, { "exit-idle-time", pa_config_parse_int, NULL }, { "module-idle-time", pa_config_parse_int, NULL }, { "scache-idle-time", pa_config_parse_int, NULL }, + { "realtime-priority", parse_rtprio, NULL }, { "dl-search-path", pa_config_parse_string, NULL }, { "default-script-file", pa_config_parse_string, NULL }, { "log-target", parse_log_target, NULL }, { "log-level", parse_log_level, NULL }, { "verbose", parse_log_level, NULL }, { "resample-method", parse_resample_method, NULL }, - { "use-pid-file", pa_config_parse_bool, NULL }, - { "system-instance", pa_config_parse_bool, NULL }, - { "no-cpu-limit", pa_config_parse_bool, NULL }, - { "disable-shm", pa_config_parse_bool, NULL }, { "default-sample-format", parse_sample_format, NULL }, { "default-sample-rate", parse_sample_rate, NULL }, { "default-sample-channels", parse_sample_channels, NULL }, { "default-fragments", parse_fragments, NULL }, { "default-fragment-size-msec", parse_fragment_size_msec, NULL }, + { "nice-level", parse_nice_level, NULL }, #ifdef HAVE_SYS_RESOURCE_H { "rlimit-as", parse_rlimit, NULL }, { "rlimit-core", parse_rlimit, NULL }, @@ -374,6 +423,12 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { #ifdef RLIMIT_MEMLOCK { "rlimit-memlock", parse_rlimit, NULL }, #endif +#ifdef RLIMIT_NICE + { "rlimit-nice", parse_rlimit, NULL }, +#endif +#ifdef RLIMIT_RTPRIO + { "rlimit-rtprio", parse_rlimit, NULL }, +#endif #endif { NULL, NULL, NULL }, }; @@ -381,40 +436,55 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { table[0].data = &c->daemonize; table[1].data = &c->fail; table[2].data = &c->high_priority; - table[3].data = &c->disallow_module_loading; - table[4].data = &c->exit_idle_time; - table[5].data = &c->module_idle_time; - table[6].data = &c->scache_idle_time; - table[7].data = &c->dl_search_path; - table[8].data = &c->default_script_file; - table[9].data = c; - table[10].data = c; - table[11].data = c; + table[3].data = &c->realtime_scheduling; + table[4].data = &c->disallow_module_loading; + table[5].data = &c->use_pid_file; + table[6].data = &c->system_instance; + table[7].data = &c->no_cpu_limit; + table[8].data = &c->disable_shm; + table[9].data = &c->exit_idle_time; + table[10].data = &c->module_idle_time; + table[11].data = &c->scache_idle_time; table[12].data = c; - table[13].data = &c->use_pid_file; - table[14].data = &c->system_instance; - table[15].data = &c->no_cpu_limit; - table[16].data = &c->disable_shm; + table[13].data = &c->dl_search_path; + table[14].data = &c->default_script_file; + table[15].data = c; + table[16].data = c; table[17].data = c; table[18].data = c; table[19].data = c; table[20].data = c; table[21].data = c; + table[22].data = c; + table[23].data = c; + table[24].data = c; #ifdef HAVE_SYS_RESOURCE_H - table[22].data = &c->rlimit_as; - table[23].data = &c->rlimit_core; - table[24].data = &c->rlimit_data; - table[25].data = &c->rlimit_fsize; - table[26].data = &c->rlimit_nofile; - table[27].data = &c->rlimit_stack; + table[25].data = &c->rlimit_as; + table[26].data = &c->rlimit_core; + table[27].data = &c->rlimit_data; + table[28].data = &c->rlimit_fsize; + table[29].data = &c->rlimit_nofile; + table[30].data = &c->rlimit_stack; #ifdef RLIMIT_NPROC - table[28].data = &c->rlimit_nproc; + table[31].data = &c->rlimit_nproc; #endif #ifdef RLIMIT_MEMLOCK #ifndef RLIMIT_NPROC #error "Houston, we have a numbering problem!" #endif - table[29].data = &c->rlimit_memlock; + table[32].data = &c->rlimit_memlock; +#endif +#ifdef RLIMIT_NICE +#ifndef RLIMIT_MEMLOCK +#error "Houston, we have a numbering problem!" +#endif + table[33].data = &c->rlimit_nice; +#endif +#ifdef RLIMIT_RTPRIO +#ifndef RLIMIT_NICE +#error "Houston, we have a numbering problem!" +#endif + table[34].data = &c->rlimit_rtprio; #endif #endif @@ -474,10 +544,17 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { pa_assert(c->log_level <= PA_LOG_LEVEL_MAX); - pa_strbuf_printf(s, "daemonize = %i\n", !!c->daemonize); - pa_strbuf_printf(s, "fail = %i\n", !!c->fail); - pa_strbuf_printf(s, "high-priority = %i\n", !!c->high_priority); - pa_strbuf_printf(s, "disallow-module-loading = %i\n", !!c->disallow_module_loading); + pa_strbuf_printf(s, "daemonize = %s\n", pa_yes_no(c->daemonize)); + pa_strbuf_printf(s, "fail = %s\n", pa_yes_no(c->fail)); + pa_strbuf_printf(s, "high-priority = %s\n", pa_yes_no(c->high_priority)); + pa_strbuf_printf(s, "nice-level = %i\n", c->nice_level); + pa_strbuf_printf(s, "realtime-scheduling = %s\n", pa_yes_no(c->realtime_scheduling)); + pa_strbuf_printf(s, "realtime-priority = %i\n", c->realtime_priority); + pa_strbuf_printf(s, "disallow-module-loading = %s\n", pa_yes_no(c->disallow_module_loading)); + pa_strbuf_printf(s, "use-pid-file = %s\n", pa_yes_no(c->use_pid_file)); + pa_strbuf_printf(s, "system-instance = %s\n", pa_yes_no(c->system_instance)); + pa_strbuf_printf(s, "no-cpu-limit = %s\n", pa_yes_no(c->no_cpu_limit)); + pa_strbuf_printf(s, "disable-shm = %s\n", pa_yes_no(c->disable_shm)); pa_strbuf_printf(s, "exit-idle-time = %i\n", c->exit_idle_time); pa_strbuf_printf(s, "module-idle-time = %i\n", c->module_idle_time); pa_strbuf_printf(s, "scache-idle-time = %i\n", c->scache_idle_time); @@ -486,10 +563,6 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { pa_strbuf_printf(s, "log-target = %s\n", c->auto_log_target ? "auto" : (c->log_target == PA_LOG_SYSLOG ? "syslog" : "stderr")); pa_strbuf_printf(s, "log-level = %s\n", log_level_to_string[c->log_level]); pa_strbuf_printf(s, "resample-method = %s\n", pa_resample_method_to_string(c->resample_method)); - pa_strbuf_printf(s, "use-pid-file = %i\n", c->use_pid_file); - pa_strbuf_printf(s, "system-instance = %i\n", !!c->system_instance); - pa_strbuf_printf(s, "no-cpu-limit = %i\n", !!c->no_cpu_limit); - pa_strbuf_printf(s, "disable-shm = %i\n", !!c->disable_shm); pa_strbuf_printf(s, "default-sample-format = %s\n", pa_sample_format_to_string(c->default_sample_spec.format)); pa_strbuf_printf(s, "default-sample-rate = %u\n", c->default_sample_spec.rate); pa_strbuf_printf(s, "default-sample-channels = %u\n", c->default_sample_spec.channels); @@ -508,6 +581,12 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { #ifdef RLIMIT_MEMLOCK pa_strbuf_printf(s, "rlimit-memlock = %li\n", c->rlimit_memlock.is_set ? (long int) c->rlimit_memlock.value : -1); #endif +#ifdef RLIMIT_NICE + pa_strbuf_printf(s, "rlimit-nice = %li\n", c->rlimit_memlock.is_set ? (long int) c->rlimit_nice.value : -1); +#endif +#ifdef RLIMIT_RTPRIO + pa_strbuf_printf(s, "rlimit-rtprio = %li\n", c->rlimit_memlock.is_set ? (long int) c->rlimit_rtprio.value : -1); +#endif #endif return pa_strbuf_tostring_free(s); diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h index 4d37861d..b8930bd7 100644 --- a/src/daemon/daemon-conf.h +++ b/src/daemon/daemon-conf.h @@ -26,6 +26,7 @@ ***/ #include +#include #include #ifdef HAVE_SYS_RESOURCE_H @@ -48,29 +49,32 @@ typedef enum pa_daemon_conf_cmd { #ifdef HAVE_SYS_RESOURCE_H typedef struct pa_rlimit { rlim_t value; - int is_set; + pa_bool_t is_set; } pa_rlimit; #endif /* A structure containing configuration data for the PulseAudio server . */ typedef struct pa_daemon_conf { pa_daemon_conf_cmd_t cmd; - int daemonize, + pa_bool_t daemonize, fail, high_priority, + realtime_scheduling, disallow_module_loading, - exit_idle_time, - module_idle_time, - scache_idle_time, - auto_log_target, use_pid_file, system_instance, no_cpu_limit, disable_shm; + int exit_idle_time, + module_idle_time, + scache_idle_time, + auto_log_target, + realtime_priority, + nice_level, + resample_method; char *script_commands, *dl_search_path, *default_script_file; pa_log_target_t log_target; pa_log_level_t log_level; - int resample_method; char *config_file; #ifdef HAVE_SYS_RESOURCE_H @@ -81,6 +85,12 @@ typedef struct pa_daemon_conf { #ifdef RLIMIT_MEMLOCK pa_rlimit rlimit_memlock; #endif +#ifdef RLIMIT_NICE + pa_rlimit rlimit_nice; +#endif +#ifdef RLIMIT_RTPRIO + pa_rlimit rlimit_rtprio; +#endif #endif unsigned default_n_fragments, default_fragment_size_msec; diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in index 2132bf3d..54acd8ea 100644 --- a/src/daemon/daemon.conf.in +++ b/src/daemon/daemon.conf.in @@ -20,42 +20,58 @@ ## Configuration file for the pulseaudio daemon. Default values are ## commented out. Use either ; or # for commenting -# Extra verbositiy -; verbose = 0 - ## Daemonize after startup -; daemonize = 0 +; daemonize = no ## Quit if startup fails -; fail = 1 - -## Renice the daemon to level -15 and try to get SCHED_FIFO -## scheduling. This a good idea if you hear annyoing noise in the -## playback. However, this is a certain security issue, since it works -## when called SUID root only. root is dropped immediately after gaining -## the nice level and SCHED_FIFO scheduling on startup. -; high-priority = 0 +; fail = yes + +## Renice the daemon to level -15. This a good idea if you experience +## drop-outs in the playback. However, this is a certain security +## issue, since it works when called SUID root only. root is dropped +## immediately after gaining the nice level on startup, thus it is +## presumably safe. +; high-priority = yes + +## Try to acquire SCHED_FIFO scheduling for the IO threads. The same +## security concerns as mentioned above apply. However, if PA enters +## an endless loop, realtime scheduling causes a system lockup. Thus, +## realtime scheduling should only be enabled on trusted machines for +## now. Please not that only the IO threads of PulseAudio are made +## real-time. The controlling thread is left a normally scheduled +## thread. Thus the enabling the high-priority option is orthogonal. +; realtime-scheduling = no + +## The realtime priority to acquire, if realtime-scheduling is +## enabled. (Note: JACK uses 10 by default, 9 for clients -- some +## PulseAudio threads might choose a priority a little lower or higher +## than this value.) +; realtime-priority = 5 + +## The nice level to acquire for the daemon, if high-priority is +## enabled. (Note: on some distributions X11 uses -10 by default.) +; nice-level = -11 ## Disallow module loading after startup -; disallow-module-loading = 0 +; disallow-module-loading = no ## Terminate the daemon after the last client quit and this time ## passed. Use a negative value to disable this feature. ; exit-idle-time = -1 -## Unload autoloaded modules after being idle for this time +## Unload autoloaded modules after being idle for this time ; module-idle-time = 20 -## Unload autoloaded sample cache entries after being idle for this time +## Unload autoloaded sample cache entries after being idle for this time ; scache-idle-time = 20 ## The path were to look for dynamic shared objects (DSOs aka ## plugins). You may specify more than one path seperated by -## colons. +## colons. ; dl-search-path = @PA_DLSEARCHPATH@ ## The default script file to load. Specify an empty string for not -## loading a default script file. The +## loading a default script file. The ; default-script-file = @PA_DEFAULT_CONFIG_FILE@ ## The default log target. Use either "stderr", "syslog" or @@ -63,31 +79,42 @@ ## true, otherwise to "stderr". ; log-target = auto +# Log level, one of debug, info, notice, warning, error. Log messages +# with a lower log level than specified here are not logged, +; log-level = notice + ## The resampling algorithm to use. Use one of src-sinc-best-quality, ## src-sinc-medium-quality, src-sinc-fastest, src-zero-order-hold, -## src-linear, trivial. See the documentation of libsamplerate for an -## explanation for the different methods. The method 'trivial' is the -## only algorithm implemented without usage of floating point -## numbers. If you're tight on CPU consider using this. On the other -## hand it has the worst quality of all. -; resample-method = sinc-fastest +## src-linear, trivial, speex-float-N, speex-fixed-N, ffmpeg. See the +## documentation of libsamplerate for an explanation for the different +## src- methods. The method 'trivial' is the most basic algorithm +## implemented. If you're tight on CPU consider using this. On the +## other hand it has the worst quality of them all. The speex +## resamplers take an integer quality setting in the range 0..9 +## (bad...good). They exist in two flavours: fixed and float. The +## former uses fixed point numbers, the latter relies on floating +## point numbers. On most desktop CPUs the float point resmapler is a +## lot faster, and it also offers slightly better quality. +; resample-method = speex-float-3 ## Create a PID file in /tmp/pulseaudio-$USER/pid. Of this is enabled ## you may use commands like "pulseaudio --kill" or "pulseaudio ## --check". If you are planning to start more than one pulseaudio ## process per user, you better disable this option since it ## effectively disables multiple instances. -; use-pid-file = 1 +; use-pid-file = yes ## Do not install the CPU load limit, even on platforms where it is -## supported. This option is useful when debugging/profiling +## supported. This option is useful when debugging/profiling ## PulseAudio to disable disturbing SIGXCPU signals. -; no-cpu-limit = 0 +; no-cpu-limit = no ## Run the daemon as system-wide instance, requires root priviliges -; system-instance = 0 +; system-instance = no -## Resource limits, see getrlimit(2) for more information +## Resource limits, see getrlimit(2) for more information. Set to -1 +## if PA shouldn't touch the resource limit. Not all resource limits +## are available on all operating systems. ; rlimit-as = -1 ; rlimit-core = -1 ; rlimit-data = -1 @@ -96,9 +123,11 @@ ; rlimit-stack = -1 ; rlimit-nproc = -1 ; rlimit-memlock = 16384 +; rlimit-nice = 31 +; rlimit-rtprio = 9 -## Disable shared memory data transfer -; disable-shm = 0 +## Disable shared memory data transfer +; disable-shm = no ## Default sample format ; default-sample-format = s16le diff --git a/src/daemon/main.c b/src/daemon/main.c index cd3cfcc8..249131e0 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -307,6 +307,12 @@ static void set_all_rlimits(const pa_daemon_conf *conf) { #ifdef RLIMIT_MEMLOCK set_one_rlimit(&conf->rlimit_memlock, RLIMIT_MEMLOCK, "RLIMIT_MEMLOCK"); #endif +#ifdef RLIMIT_NICE + set_one_rlimit(&conf->rlimit_nice, RLIMIT_NICE, "RLIMIT_NICE"); +#endif +#ifdef RLIMIT_RTPRIO + set_one_rlimit(&conf->rlimit_rtprio, RLIMIT_RTPRIO, "RLIMIT_RTPRIO"); +#endif } #endif -- cgit From 005ed41c3f83430ce936f55378c68f1e29557aeb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Nov 2007 01:42:34 +0000 Subject: save and restore errno in sig handler git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2011 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/cpulimit.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/daemon/cpulimit.c b/src/daemon/cpulimit.c index ab212129..b77dd443 100644 --- a/src/daemon/cpulimit.c +++ b/src/daemon/cpulimit.c @@ -113,6 +113,9 @@ static void write_err(const char *p) { /* The signal handler, called on every SIGXCPU */ static void signal_handler(int sig) { + int saved_errno; + + saved_errno = errno; pa_assert(sig == SIGXCPU); if (phase == PHASE_IDLE) { @@ -150,6 +153,8 @@ static void signal_handler(int sig) { write_err("Hard CPU time limit exhausted, terminating forcibly.\n"); _exit(1); /* Forced exit */ } + + errno = saved_errno; } /* Callback for IO events on the FIFO */ -- cgit From 41ea3b2fd4fa0a0a4d884ad00e9b3b060082515b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Nov 2007 01:45:01 +0000 Subject: add new option --realtime git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2012 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/cmdline.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c index 6b7b2671..0c840449 100644 --- a/src/daemon/cmdline.c +++ b/src/daemon/cmdline.c @@ -49,6 +49,7 @@ enum { ARG_FAIL, ARG_LOG_LEVEL, ARG_HIGH_PRIORITY, + ARG_REALTIME, ARG_DISALLOW_MODULE_LOADING, ARG_EXIT_IDLE_TIME, ARG_MODULE_IDLE_TIME, @@ -79,6 +80,7 @@ static struct option long_options[] = { {"verbose", 2, 0, ARG_LOG_LEVEL}, {"log-level", 2, 0, ARG_LOG_LEVEL}, {"high-priority", 2, 0, ARG_HIGH_PRIORITY}, + {"realtime", 2, 0, ARG_REALTIME}, {"disallow-module-loading", 2, 0, ARG_DISALLOW_MODULE_LOADING}, {"exit-idle-time", 2, 0, ARG_EXIT_IDLE_TIME}, {"module-idle-time", 2, 0, ARG_MODULE_IDLE_TIME}, @@ -124,8 +126,12 @@ void pa_cmdline_help(const char *argv0) { " --system[=BOOL] Run as system-wide instance\n" " -D, --daemonize[=BOOL] Daemonize after startup\n" " --fail[=BOOL] Quit when startup fails\n" - " --high-priority[=BOOL] Try to set high process priority\n" - " (only available as root)\n" + " --high-priority[=BOOL] Try to set high nice level\n" + " (only available as root, when SUID or\n" + " with elevated RLIMIT_NICE)\n" + " --realtime[=BOOL] Try to enable realtime scheduling\n" + " (only available as root, when SUID or\n" + " with elevated RLIMIT_RTPRIO)\n" " --disallow-module-loading[=BOOL] Disallow module loading after startup\n" " --exit-idle-time=SECS Terminate the daemon when idle and this\n" " time passed\n" @@ -224,14 +230,14 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d case ARG_DAEMONIZE: case 'D': - if ((conf->daemonize = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + if ((conf->daemonize = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) { pa_log("--daemonize expects boolean argument"); goto fail; } break; case ARG_FAIL: - if ((conf->fail = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + if ((conf->fail = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) { pa_log("--fail expects boolean argument"); goto fail; } @@ -253,21 +259,28 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d break; case ARG_HIGH_PRIORITY: - if ((conf->high_priority = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + if ((conf->high_priority = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) { pa_log("--high-priority expects boolean argument"); goto fail; } break; + case ARG_REALTIME: + if ((conf->realtime_scheduling = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) { + pa_log("--realtime expects boolean argument"); + goto fail; + } + break; + case ARG_DISALLOW_MODULE_LOADING: - if ((conf->disallow_module_loading = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + if ((conf->disallow_module_loading = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) { pa_log("--disallow-module-loading expects boolean argument"); goto fail; } break; case ARG_USE_PID_FILE: - if ((conf->use_pid_file = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + if ((conf->use_pid_file = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) { pa_log("--use-pid-file expects boolean argument"); goto fail; } @@ -311,21 +324,21 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d break; case ARG_SYSTEM: - if ((conf->system_instance = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + if ((conf->system_instance = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) { pa_log("--system expects boolean argument"); goto fail; } break; case ARG_NO_CPU_LIMIT: - if ((conf->no_cpu_limit = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + if ((conf->no_cpu_limit = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) { pa_log("--no-cpu-limit expects boolean argument"); goto fail; } break; case ARG_DISABLE_SHM: - if ((conf->disable_shm = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + if ((conf->disable_shm = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) { pa_log("--disable-shm expects boolean argument"); goto fail; } -- cgit From 641d1fa96485f7a258ad958c4031e655767808a8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Nov 2007 02:55:06 +0000 Subject: drop rt scheduling before we start our helper process git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2013 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/gconf/module-gconf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/gconf/module-gconf.c b/src/modules/gconf/module-gconf.c index c2ea7b27..799bdfbd 100644 --- a/src/modules/gconf/module-gconf.c +++ b/src/modules/gconf/module-gconf.c @@ -365,6 +365,8 @@ static int start_client(const char *n, pid_t *pid) { int max_fd, i; /* child */ + pa_reset_priority(); + close(pipe_fds[0]); dup2(pipe_fds[1], 1); -- cgit From 7bfd1b2f01613dd14b9ca478ae530c1641aa46a1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Nov 2007 02:58:26 +0000 Subject: make rtprio and nice level actually configurable git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2014 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/main.c | 7 ++-- src/modules/module-alsa-sink.c | 4 +- src/modules/module-alsa-source.c | 4 +- src/modules/module-combine.c | 4 +- src/modules/module-jack-sink.c | 8 ++-- src/modules/module-jack-source.c | 8 ++-- src/modules/module-oss.c | 4 +- src/pulsecore/core-util.c | 87 +++++++++++++++++++++++++++++----------- src/pulsecore/core-util.h | 4 +- src/pulsecore/core.c | 11 +++-- src/pulsecore/core.h | 7 ++-- 11 files changed, 94 insertions(+), 54 deletions(-) diff --git a/src/daemon/main.c b/src/daemon/main.c index 249131e0..01cbba18 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -419,9 +419,9 @@ int main(int argc, char *argv[]) { pa_log_set_target(conf->auto_log_target ? PA_LOG_STDERR : conf->log_target, NULL); if (conf->high_priority && conf->cmd == PA_CMD_DAEMON) - pa_raise_priority(); + pa_raise_priority(conf->nice_level); - if (suid_root && (conf->cmd != PA_CMD_DAEMON || !conf->high_priority)) { + if (suid_root && (conf->cmd != PA_CMD_DAEMON || !conf->realtime_scheduling)) { pa_drop_caps(); pa_drop_root(); } @@ -636,7 +636,6 @@ int main(int argc, char *argv[]) { } c->is_system_instance = !!conf->system_instance; - c->high_priority = !!conf->high_priority; c->default_sample_spec = conf->default_sample_spec; c->default_n_fragments = conf->default_n_fragments; c->default_fragment_size_msec = conf->default_fragment_size_msec; @@ -645,6 +644,8 @@ int main(int argc, char *argv[]) { c->module_idle_time = conf->module_idle_time; c->scache_idle_time = conf->scache_idle_time; c->resample_method = conf->resample_method; + c->realtime_priority = conf->realtime_priority; + c->realtime_scheduling = !!conf->realtime_scheduling; pa_assert_se(pa_signal_init(pa_mainloop_get_api(mainloop)) == 0); pa_signal_new(SIGINT, signal_callback, c); diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index a09247fe..88594cda 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -603,8 +603,8 @@ static void thread_func(void *userdata) { pa_log_debug("Thread starting up"); - if (u->core->high_priority) - pa_make_realtime(); + if (u->core->realtime_scheduling) + pa_make_realtime(u->core->realtime_priority); pa_thread_mq_install(&u->thread_mq); pa_rtpoll_install(u->rtpoll); diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index d840cac3..a862657f 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -592,8 +592,8 @@ static void thread_func(void *userdata) { pa_log_debug("Thread starting up"); - if (u->core->high_priority) - pa_make_realtime(); + if (u->core->realtime_scheduling) + pa_make_realtime(u->core->realtime_priority); pa_thread_mq_install(&u->thread_mq); pa_rtpoll_install(u->rtpoll); diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 665bf9dd..aca4ba32 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -233,8 +233,8 @@ static void thread_func(void *userdata) { pa_log_debug("Thread starting up"); - if (u->core->high_priority) - pa_make_realtime(); + if (u->core->realtime_scheduling) + pa_make_realtime(u->core->realtime_priority+1); pa_thread_mq_install(&u->thread_mq); pa_rtpoll_install(u->rtpoll); diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index 2cf8a58c..840867ce 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -214,8 +214,8 @@ static void thread_func(void *userdata) { pa_log_debug("Thread starting up"); - if (u->core->high_priority) - pa_make_realtime(); + if (u->core->realtime_scheduling) + pa_make_realtime(u->core->realtime_priority); pa_thread_mq_install(&u->thread_mq); pa_rtpoll_install(u->rtpoll); @@ -253,8 +253,8 @@ static void jack_init(void *arg) { pa_log_info("JACK thread starting up."); - if (u->core->high_priority) - pa_make_realtime(); + if (u->core->realtime_scheduling) + pa_make_realtime(u->core->realtime_priority+4); } static void jack_shutdown(void* arg) { diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index b62ebe7a..380f87eb 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -191,8 +191,8 @@ static void thread_func(void *userdata) { pa_log_debug("Thread starting up"); - if (u->core->high_priority) - pa_make_realtime(); + if (u->core->realtime_scheduling) + pa_make_realtime(u->core->realtime_priority); pa_thread_mq_install(&u->thread_mq); pa_rtpoll_install(u->rtpoll); @@ -230,8 +230,8 @@ static void jack_init(void *arg) { pa_log_info("JACK thread starting up."); - if (u->core->high_priority) - pa_make_realtime(); + if (u->core->realtime_scheduling) + pa_make_realtime(u->core->realtime_priority+4); } static void jack_shutdown(void* arg) { diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 19dceef2..51ab8a85 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -863,8 +863,8 @@ static void thread_func(void *userdata) { pa_log_debug("Thread starting up"); - if (u->core->high_priority) - pa_make_realtime(); + if (u->core->realtime_scheduling) + pa_make_realtime(u->core->realtime_priority); pa_thread_mq_install(&u->thread_mq); pa_rtpoll_install(u->rtpoll); diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 3e70eb5c..1a62bce4 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -512,8 +512,10 @@ char *pa_strlcpy(char *b, const char *s, size_t l) { return b; } -/* Make the current thread a realtime thread*/ -void pa_make_realtime(void) { +/* Make the current thread a realtime thread, and acquire the highest + * rtprio we can get that is less or equal the specified parameter. If + * the thread is already realtime, don't do anything. */ +int pa_make_realtime(int rtprio) { #ifdef _POSIX_PRIORITY_SCHEDULING struct sched_param sp; @@ -524,50 +526,87 @@ void pa_make_realtime(void) { if ((r = pthread_getschedparam(pthread_self(), &policy, &sp)) != 0) { pa_log("pthread_getschedgetparam(): %s", pa_cstrerror(r)); - return; + return -1; + } + + if (policy == SCHED_FIFO && sp.sched_priority >= rtprio) { + pa_log_info("Thread already being scheduled with SCHED_FIFO with priority %i.", sp.sched_priority); + return 0; } - sp.sched_priority = 1; + sp.sched_priority = rtprio; if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) != 0) { + + while (sp.sched_priority > 1) { + sp.sched_priority --; + + if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) == 0) { + pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread, with priority %i, which is lower than the requested %i.", sp.sched_priority, rtprio); + return 0; + } + } + pa_log_warn("pthread_setschedparam(): %s", pa_cstrerror(r)); - return; + return -1; } - pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread."); + pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread, with priority %i.", sp.sched_priority); + return 0; +#else + return -1; #endif - } -#define NICE_LEVEL (-11) - -/* Raise the priority of the current process as much as possible and -sensible: set the nice level to -11.*/ -void pa_raise_priority(void) { +/* Raise the priority of the current process as much as possible that + * is <= the specified nice level..*/ +int pa_raise_priority(int nice_level) { #ifdef HAVE_SYS_RESOURCE_H - if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) + if (setpriority(PRIO_PROCESS, 0, nice_level) < 0) { + int n; + + for (n = nice_level+1; n < 0; n++) { + + if (setpriority(PRIO_PROCESS, 0, n) == 0) { + pa_log_info("Successfully acquired nice level %i, which is lower than the requested %i.", n, nice_level); + return 0; + } + } + pa_log_warn("setpriority(): %s", pa_cstrerror(errno)); - else - pa_log_info("Successfully gained nice level %i.", NICE_LEVEL); + return -1; + } + + pa_log_info("Successfully gained nice level %i.", nice_level); #endif #ifdef OS_IS_WIN32 - if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) - pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError()); - else - pa_log_info("Successfully gained high priority class."); + if (nice_level < 0) { + if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) { + pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError()); + return .-1; + } else + pa_log_info("Successfully gained high priority class."); + } #endif + + return 0; } /* Reset the priority to normal, inverting the changes made by - * pa_raise_priority() */ + * pa_raise_priority() and pa_make_realtime()*/ void pa_reset_priority(void) { -#ifdef OS_IS_WIN32 - SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); -#endif - #ifdef HAVE_SYS_RESOURCE_H + struct sched_param sp; + setpriority(PRIO_PROCESS, 0, 0); + + memset(&sp, 0, sizeof(sp)); + pa_assert_se(pthread_setschedparam(pthread_self(), SCHED_OTHER, &sp) == 0); +#endif + +#ifdef OS_IS_WIN32 + SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); #endif } diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index a6d22101..c8760a1f 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -57,8 +57,8 @@ char *pa_strlcpy(char *b, const char *s, size_t l); char *pa_parent_dir(const char *fn); -void pa_make_realtime(void); -void pa_raise_priority(void); +int pa_make_realtime(int rtprio); +int pa_raise_priority(int nice_level); void pa_reset_priority(void); int pa_parse_boolean(const char *s) PA_GCC_PURE; diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index e67f15b5..9b420c94 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -107,7 +107,7 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) { c->scache = NULL; c->autoload_idxset = NULL; c->autoload_hashmap = NULL; - c->running_as_daemon = 0; + c->running_as_daemon = FALSE; c->default_sample_spec.format = PA_SAMPLE_S16NE; c->default_sample_spec.rate = 44100; @@ -134,10 +134,10 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) { c->resample_method = PA_RESAMPLER_SPEEX_FLOAT_BASE + 3; - c->is_system_instance = 0; - c->disallow_module_loading = 0; - c->high_priority = 0; - + c->is_system_instance = FALSE; + c->disallow_module_loading = FALSE; + c->realtime_scheduling = FALSE; + c->realtime_priority = 5; for (j = 0; j < PA_CORE_HOOK_MAX; j++) pa_hook_init(&c->hooks[j], c); @@ -217,4 +217,3 @@ void pa_core_check_quit(pa_core *c) { c->quit_event = NULL; } } - diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index dfa80f8d..9aeb7888 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -113,10 +113,11 @@ struct pa_core { pa_time_event *scache_auto_unload_event; - int disallow_module_loading, running_as_daemon; + pa_bool_t disallow_module_loading, running_as_daemon; pa_resample_method_t resample_method; - int is_system_instance; - int high_priority; + pa_bool_t is_system_instance; + pa_bool_t realtime_scheduling; + int realtime_priority; /* hooks */ pa_hook hooks[PA_CORE_HOOK_MAX]; -- cgit From 81233c178113e92862ac5da77fdfdd2e82a33990 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Nov 2007 11:23:45 +0000 Subject: make disallow-module-loading config option work again (original patch from Diego Petteno) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2015 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/daemon/main.c b/src/daemon/main.c index 01cbba18..051c323e 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -639,7 +639,6 @@ int main(int argc, char *argv[]) { c->default_sample_spec = conf->default_sample_spec; c->default_n_fragments = conf->default_n_fragments; c->default_fragment_size_msec = conf->default_fragment_size_msec; - c->disallow_module_loading = conf->disallow_module_loading; c->exit_idle_time = conf->exit_idle_time; c->module_idle_time = conf->module_idle_time; c->scache_idle_time = conf->scache_idle_time; @@ -666,7 +665,7 @@ int main(int argc, char *argv[]) { #endif if (conf->daemonize) - c->running_as_daemon = 1; + c->running_as_daemon = TRUE; oil_init(); @@ -682,6 +681,10 @@ int main(int argc, char *argv[]) { pa_log_error("%s", s = pa_strbuf_tostring_free(buf)); pa_xfree(s); + /* We completed the initial module loading, so let's disable it + * from now on, if requested */ + c->disallow_module_loading = !!conf->disallow_module_loading; + if (r < 0 && conf->fail) { pa_log("failed to initialize daemon."); #ifdef HAVE_FORK -- cgit From cb0d7ff60a60d4ba53491a2ebd46159200ee22dd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Nov 2007 22:50:32 +0000 Subject: add missing pthread libs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2016 fefdeb5f-60dc-0310-8127-8f9354f1896f --- libpulse-browse.pc.in | 2 +- libpulse-mainloop-glib.pc.in | 2 +- libpulse-simple.pc.in | 2 +- libpulse.pc.in | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libpulse-browse.pc.in b/libpulse-browse.pc.in index 7b9a59f4..66438b2a 100644 --- a/libpulse-browse.pc.in +++ b/libpulse-browse.pc.in @@ -6,6 +6,6 @@ includedir=${prefix}/include Name: libpulse-browse Description: PulseAudio Network Browsing API Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpulse-browse +Libs: -L${libdir} -lpulse-browse @PTHREAD_LIBS@ Cflags: -D_REENTRANT -I${includedir} Requires: libpulse diff --git a/libpulse-mainloop-glib.pc.in b/libpulse-mainloop-glib.pc.in index 0977f185..1a8bfa40 100644 --- a/libpulse-mainloop-glib.pc.in +++ b/libpulse-mainloop-glib.pc.in @@ -6,6 +6,6 @@ includedir=${prefix}/include Name: libpulse-mainloop-glib Description: GLIB 2.0 Main Loop Wrapper for PulseAudio Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpulse-mainloop-glib +Libs: -L${libdir} -lpulse-mainloop-glib @PTHREAD_LIBS@ Cflags: -D_REENTRANT -I${includedir} Requires: libpulse glib-2.0 diff --git a/libpulse-simple.pc.in b/libpulse-simple.pc.in index 4ccc3d58..00d1245a 100644 --- a/libpulse-simple.pc.in +++ b/libpulse-simple.pc.in @@ -6,6 +6,6 @@ includedir=${prefix}/include Name: libpulse-simple Description: Simplified Synchronous Client Interface to PulseAudio Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lpulse-simple +Libs: -L${libdir} -lpulse-simple @PTHREAD_LIBS@ Cflags: -D_REENTRANT -I${includedir} Requires: libpulse diff --git a/libpulse.pc.in b/libpulse.pc.in index 0f01799b..2193b2b9 100644 --- a/libpulse.pc.in +++ b/libpulse.pc.in @@ -8,4 +8,3 @@ Description: Client Interface to PulseAudio Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lpulse @PTHREAD_LIBS@ Cflags: -D_REENTRANT -I${includedir} -Requires: -- cgit From bc161b4b4aeb94df18622031217e73d27250cf2b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Nov 2007 22:51:46 +0000 Subject: comment the library versions a bit git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2017 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index e08c11c1..07db9823 100644 --- a/configure.ac +++ b/configure.ac @@ -39,12 +39,27 @@ AC_SUBST(PACKAGE_URL, [http://pulseaudio.org/]) AC_SUBST(PA_API_VERSION, 10) AC_SUBST(PA_PROTOCOL_VERSION, 11) +# The stable ABI for client applications, for the version info x:y:z +# always will hold y=z AC_SUBST(LIBPULSE_VERSION_INFO, [3:0:3]) -AC_SUBST(LIBPULSECORE_VERSION_INFO, [4:0:0]) + +# A simplified, synchronous, ABI-stable interface for client +# applications, for the version info x:y:z always will hold y=z AC_SUBST(LIBPULSE_SIMPLE_VERSION_INFO, [0:1:0]) + +# The ABI-stable network browsing interface for client applications, +# for the version info x:y:z always will hold y=z AC_SUBST(LIBPULSE_BROWSE_VERSION_INFO, [1:1:1]) + +# The ABI-stable GLib adapter for client applications, for the version +# info x:y:z always will hold y=z AC_SUBST(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO, [0:3:0]) +# An internally used, ABI-unstable library that contains the +# PulseAudio core, SONAMEs are bumped on every release, version info +# suffix will always be 0:0 +AC_SUBST(LIBPULSECORE_VERSION_INFO, [4:0:0]) + AC_CANONICAL_HOST if type -p stow > /dev/null && test -d /usr/local/stow ; then -- cgit From 95af1e616b061142da606637d42d493f9918cfea Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 4 Nov 2007 13:51:18 +0000 Subject: Add linker version script to hide non-ABI stable symbols in the client libraries. While this helps defining a more streamlined ABI, this also requires linking a lot of additional symbols into some PA client utilities which until now made use of the non-ABI stable symbols in libpulse. To minimize the effect on there size a bit, strip unused symbols by linking with -ffunction-sections -fdata-sections -Wl,--gc-sections git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2018 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 30 +++++--- src/map-file | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 240 insertions(+), 10 deletions(-) create mode 100644 src/map-file diff --git a/src/Makefile.am b/src/Makefile.am index b1393e34..dbb9adcd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -64,7 +64,7 @@ AM_LIBADD = $(PTHREAD_LIBS) AM_LDADD = $(PTHREAD_LIBS) # Only required on some platforms but defined for all to avoid errors -AM_LDFLAGS = -Wl,-no-undefined +AM_LDFLAGS = -Wl,-no-undefined -ffunction-sections -fdata-sections -Wl,--gc-sections if STATIC_BINS BINLDFLAGS = -static @@ -101,7 +101,8 @@ EXTRA_DIST = \ daemon/esdcompat.in \ utils/padsp \ modules/module-defs.h.m4 \ - daemon/pulseaudio-module-xsmp.desktop + daemon/pulseaudio-module-xsmp.desktop \ + map-file pulseconf_DATA = \ default.pa \ @@ -194,12 +195,12 @@ pasuspender_LDADD = $(AM_LDADD) libpulse.la $(LIBSNDFILE_LIBS) pasuspender_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) pasuspender_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -pacmd_SOURCES = utils/pacmd.c pulsecore/pid.c pulsecore/pid.h +pacmd_SOURCES = utils/pacmd.c pulsecore/pid.c pulsecore/pid.h pulsecore/core-util.c pulsecore/core-util.h pulsecore/core-error.c pulsecore/core-error.h pulsecore/log.c pulsecore/log.h pulsecore/once.c pulsecore/once.h $(PA_THREAD_OBJS) pacmd_CFLAGS = $(AM_CFLAGS) pacmd_LDADD = $(AM_LDADD) libpulse.la pacmd_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -pax11publish_SOURCES = utils/pax11publish.c +pax11publish_SOURCES = utils/pax11publish.c pulsecore/x11prop.c pulsecore/x11prop.h pulse/client-conf.c pulse/client-conf.h pulsecore/authkey.h pulsecore/authkey.c pulsecore/random.h pulsecore/random.c pulsecore/conf-parser.c pulsecore/conf-parser.h pulsecore/core-util.c pulsecore/core-util.h pulsecore/core-error.c pulsecore/core-error.h pulsecore/log.c pulsecore/log.h pulsecore/once.c pulsecore/once.h $(PA_THREAD_OBJS) pax11publish_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) pax11publish_LDADD = $(AM_LDADD) libpulse.la $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) pax11publish_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -374,7 +375,7 @@ sync_playback_CFLAGS = $(AM_CFLAGS) sync_playback_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) interpol_test_SOURCES = tests/interpol-test.c -interpol_test_LDADD = $(AM_LDADD) libpulse.la +interpol_test_LDADD = $(AM_LDADD) libpulse.la libpulsecore.la interpol_test_CFLAGS = $(AM_CFLAGS) interpol_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -525,7 +526,7 @@ libpulse_la_SOURCES += \ endif libpulse_la_CFLAGS = $(AM_CFLAGS) -libpulse_la_LDFLAGS = -version-info $(LIBPULSE_VERSION_INFO) +libpulse_la_LDFLAGS = -version-info $(LIBPULSE_VERSION_INFO) -Wl,-version-script=$(srcdir)/map-file libpulse_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) $(LIBICONV) if HAVE_X11 @@ -541,17 +542,17 @@ endif libpulse_simple_la_SOURCES = pulse/simple.c pulse/simple.h libpulse_simple_la_CFLAGS = $(AM_CFLAGS) libpulse_simple_la_LIBADD = $(AM_LIBADD) libpulse.la -libpulse_simple_la_LDFLAGS = -version-info $(LIBPULSE_SIMPLE_VERSION_INFO) +libpulse_simple_la_LDFLAGS = -version-info $(LIBPULSE_SIMPLE_VERSION_INFO) -Wl,-version-script=$(srcdir)/map-file -libpulse_browse_la_SOURCES = pulse/browser.c pulse/browser.h pulsecore/avahi-wrap.c pulsecore/avahi-wrap.h +libpulse_browse_la_SOURCES = pulse/browser.c pulse/browser.h pulsecore/avahi-wrap.c pulsecore/avahi-wrap.h pulsecore/core-util.c pulsecore/core-util.h pulsecore/core-error.c pulsecore/core-error.h pulsecore/log.c pulsecore/log.h pulsecore/once.c pulsecore/once.h $(PA_THREAD_OBJS) libpulse_browse_la_CFLAGS = $(AM_CFLAGS) $(AVAHI_CFLAGS) libpulse_browse_la_LIBADD = $(AM_LIBADD) libpulse.la $(AVAHI_LIBS) -libpulse_browse_la_LDFLAGS = -version-info $(LIBPULSE_BROWSE_VERSION_INFO) +libpulse_browse_la_LDFLAGS = -version-info $(LIBPULSE_BROWSE_VERSION_INFO) -Wl,-version-script=$(srcdir)/map-file libpulse_mainloop_glib_la_SOURCES = pulse/glib-mainloop.h pulse/glib-mainloop.c libpulse_mainloop_glib_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS) libpulse_mainloop_glib_la_LIBADD = $(AM_LIBADD) libpulse.la $(GLIB20_LIBS) -libpulse_mainloop_glib_la_LDFLAGS = -version-info $(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO) +libpulse_mainloop_glib_la_LDFLAGS = -version-info $(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO) -Wl,-version-script=$(srcdir)/map-file ################################### # OSS emulation # @@ -1459,4 +1460,13 @@ update-speex: update-ffmpeg: wget -O pulsecore/ffmpeg/resample2.c http://svn.mplayerhq.hu/ffmpeg/trunk/libavcodec/resample2.c?view=co +# Automatically generate linker version script. We use the same one for all public .sos +update-map-file: + ( echo "PULSE_0 {" ; \ + echo "global:" ; \ + ctags -I PA_GCC_PURE,PA_GCC_CONST -f - --c-kinds=p $(pulseinclude_HEADERS) | awk '/^pa_/ { print $$1 ";" }' | sort ; \ + echo "local:" ; \ + echo "*;" ; \ + echo "};" ) > $(srcdir)/map-file + .PHONY: utils/padsp diff --git a/src/map-file b/src/map-file new file mode 100644 index 00000000..427a3a78 --- /dev/null +++ b/src/map-file @@ -0,0 +1,220 @@ +PULSE_0 { +global: +pa_browser_new; +pa_browser_new_full; +pa_browser_ref; +pa_browser_set_callback; +pa_browser_set_error_callback; +pa_browser_unref; +pa_bytes_per_second; +pa_bytes_snprint; +pa_bytes_to_usec; +pa_channel_map_equal; +pa_channel_map_init; +pa_channel_map_init_auto; +pa_channel_map_init_mono; +pa_channel_map_init_stereo; +pa_channel_map_parse; +pa_channel_map_snprint; +pa_channel_map_valid; +pa_channel_position_to_pretty_string; +pa_channel_position_to_string; +pa_context_add_autoload; +pa_context_connect; +pa_context_disconnect; +pa_context_drain; +pa_context_errno; +pa_context_exit_daemon; +pa_context_get_autoload_info_by_index; +pa_context_get_autoload_info_by_name; +pa_context_get_autoload_info_list; +pa_context_get_client_info; +pa_context_get_client_info_list; +pa_context_get_module_info; +pa_context_get_module_info_list; +pa_context_get_protocol_version; +pa_context_get_sample_info_by_index; +pa_context_get_sample_info_by_name; +pa_context_get_sample_info_list; +pa_context_get_server; +pa_context_get_server_info; +pa_context_get_server_protocol_version; +pa_context_get_sink_info_by_index; +pa_context_get_sink_info_by_name; +pa_context_get_sink_info_list; +pa_context_get_sink_input_info; +pa_context_get_sink_input_info_list; +pa_context_get_source_info_by_index; +pa_context_get_source_info_by_name; +pa_context_get_source_info_list; +pa_context_get_source_output_info; +pa_context_get_source_output_info_list; +pa_context_get_state; +pa_context_is_local; +pa_context_is_pending; +pa_context_kill_client; +pa_context_kill_sink_input; +pa_context_kill_source_output; +pa_context_load_module; +pa_context_move_sink_input_by_index; +pa_context_move_sink_input_by_name; +pa_context_move_source_output_by_index; +pa_context_move_source_output_by_name; +pa_context_new; +pa_context_play_sample; +pa_context_ref; +pa_context_remove_autoload_by_index; +pa_context_remove_autoload_by_name; +pa_context_remove_sample; +pa_context_set_default_sink; +pa_context_set_default_source; +pa_context_set_name; +pa_context_set_sink_input_mute; +pa_context_set_sink_input_volume; +pa_context_set_sink_mute_by_index; +pa_context_set_sink_mute_by_name; +pa_context_set_sink_volume_by_index; +pa_context_set_sink_volume_by_name; +pa_context_set_source_mute_by_index; +pa_context_set_source_mute_by_name; +pa_context_set_source_volume_by_index; +pa_context_set_source_volume_by_name; +pa_context_set_state_callback; +pa_context_set_subscribe_callback; +pa_context_stat; +pa_context_subscribe; +pa_context_suspend_sink_by_index; +pa_context_suspend_sink_by_name; +pa_context_suspend_source_by_index; +pa_context_suspend_source_by_name; +pa_context_unload_module; +pa_context_unref; +pa_cvolume_avg; +pa_cvolume_channels_equal_to; +pa_cvolume_equal; +pa_cvolume_set; +pa_cvolume_snprint; +pa_cvolume_valid; +pa_frame_size; +pa_get_binary_name; +pa_get_fqdn; +pa_get_home_dir; +pa_get_host_name; +pa_get_library_version; +pa_gettimeofday; +pa_get_user_name; +pa_glib_mainloop_free; +pa_glib_mainloop_get_api; +pa_glib_mainloop_new; +pa_locale_to_utf8; +pa_mainloop_api_once; +pa_mainloop_dispatch; +pa_mainloop_free; +pa_mainloop_get_api; +pa_mainloop_get_retval; +pa_mainloop_iterate; +pa_mainloop_new; +pa_mainloop_poll; +pa_mainloop_prepare; +pa_mainloop_quit; +pa_mainloop_run; +pa_mainloop_set_poll_func; +pa_mainloop_wakeup; +pa_msleep; +pa_operation_cancel; +pa_operation_get_state; +pa_operation_ref; +pa_operation_unref; +pa_parse_sample_format; +pa_path_get_filename; +pa_sample_format_to_string; +pa_sample_size; +pa_sample_spec_equal; +pa_sample_spec_snprint; +pa_sample_spec_valid; +pa_signal_done; +pa_signal_free; +pa_signal_init; +pa_signal_new; +pa_signal_set_destroy; +pa_simple_drain; +pa_simple_flush; +pa_simple_free; +pa_simple_get_latency; +pa_simple_new; +pa_simple_read; +pa_simple_write; +pa_stream_connect_playback; +pa_stream_connect_record; +pa_stream_connect_upload; +pa_stream_cork; +pa_stream_disconnect; +pa_stream_drain; +pa_stream_drop; +pa_stream_finish_upload; +pa_stream_flush; +pa_stream_get_buffer_attr; +pa_stream_get_channel_map; +pa_stream_get_context; +pa_stream_get_index; +pa_stream_get_latency; +pa_stream_get_sample_spec; +pa_stream_get_state; +pa_stream_get_time; +pa_stream_get_timing_info; +pa_stream_new; +pa_stream_peek; +pa_stream_prebuf; +pa_stream_readable_size; +pa_stream_ref; +pa_stream_set_latency_update_callback; +pa_stream_set_name; +pa_stream_set_overflow_callback; +pa_stream_set_read_callback; +pa_stream_set_state_callback; +pa_stream_set_underflow_callback; +pa_stream_set_write_callback; +pa_stream_trigger; +pa_stream_unref; +pa_stream_update_timing_info; +pa_stream_writable_size; +pa_stream_write; +pa_strerror; +pa_sw_cvolume_multiply; +pa_sw_volume_from_dB; +pa_sw_volume_from_linear; +pa_sw_volume_multiply; +pa_sw_volume_to_dB; +pa_sw_volume_to_linear; +pa_threaded_mainloop_accept; +pa_threaded_mainloop_free; +pa_threaded_mainloop_get_api; +pa_threaded_mainloop_get_retval; +pa_threaded_mainloop_in_thread; +pa_threaded_mainloop_lock; +pa_threaded_mainloop_new; +pa_threaded_mainloop_signal; +pa_threaded_mainloop_start; +pa_threaded_mainloop_stop; +pa_threaded_mainloop_unlock; +pa_threaded_mainloop_wait; +pa_timeval_add; +pa_timeval_age; +pa_timeval_cmp; +pa_timeval_diff; +pa_timeval_load; +pa_timeval_store; +pa_usec_to_bytes; +pa_utf8_filter; +pa_utf8_to_locale; +pa_utf8_valid; +pa_xfree; +pa_xmalloc; +pa_xmalloc0; +pa_xmemdup; +pa_xrealloc; +pa_xstrdup; +pa_xstrndup; +local: +*; +}; -- cgit From 9ac93287a80cf970ccec399a3acaa9752b0193da Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 4 Nov 2007 14:11:53 +0000 Subject: Properly terminate pa_readlink() strings. Patch from Sjoerd Simons. Closes #149 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2019 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/core-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 1a62bce4..fb032f23 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -1562,7 +1562,7 @@ char *pa_readlink(const char *p) { } if ((size_t) n < l-1) { - c[l-1] = 0; + c[n] = 0; return c; } -- cgit From 0184d70ef18c1f8cd346508d2aa16b59d71065c3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 4 Nov 2007 14:17:48 +0000 Subject: add eventfd syscall nr for arm; patch from Sjoerd Simons; Closes #150 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2020 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/fdsem.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pulsecore/fdsem.c b/src/pulsecore/fdsem.c index 927bf00c..59eec18e 100644 --- a/src/pulsecore/fdsem.c +++ b/src/pulsecore/fdsem.c @@ -53,6 +53,10 @@ #define __NR_eventfd 284 #endif +#if !defined(__NR_eventfd) && defined(__arm__) +#define __NR_eventfd (__NR_SYSCALL_BASE+351) +#endif + #if !defined(SYS_eventfd) && defined(__NR_eventfd) #define SYS_eventfd __NR_eventfd #endif -- cgit From faf1fd76a9bb9e47c867f9aa4ea18a7a70a14aae Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 4 Nov 2007 16:50:23 +0000 Subject: pa_boolization git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2021 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-volume-restore.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index 77e6174f..8ef72b2a 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -64,7 +64,7 @@ static const char* const valid_modargs[] = { struct rule { char* name; - int volume_is_set; + pa_bool_t volume_is_set; pa_cvolume volume; char *sink; char *source; @@ -74,7 +74,7 @@ struct userdata { pa_hashmap *hashmap; pa_subscription *subscription; pa_hook_slot *sink_input_hook_slot, *source_output_hook_slot; - int modified; + pa_bool_t modified; char *table_file; }; @@ -141,7 +141,7 @@ static int load_rules(struct userdata *u) { while (!feof(f)) { struct rule *rule; pa_cvolume v; - int v_is_set; + pa_bool_t v_is_set; if (!fgets(ln, sizeof(buf_name), f)) break; @@ -176,9 +176,9 @@ static int load_rules(struct userdata *u) { goto finish; } - v_is_set = 1; + v_is_set = TRUE; } else - v_is_set = 0; + v_is_set = FALSE; ln = buf_name; @@ -328,15 +328,15 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 if (!r->volume_is_set || !pa_cvolume_equal(pa_sink_input_get_volume(si), &r->volume)) { pa_log_info("Saving volume for <%s>", r->name); r->volume = *pa_sink_input_get_volume(si); - r->volume_is_set = 1; - u->modified = 1; + r->volume_is_set = TRUE; + u->modified = TRUE; } if (!r->sink || strcmp(si->sink->name, r->sink) != 0) { pa_log_info("Saving sink for <%s>", r->name); pa_xfree(r->sink); r->sink = pa_xstrdup(si->sink->name); - u->modified = 1; + u->modified = TRUE; } } else { pa_assert(so); @@ -345,7 +345,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 pa_log_info("Saving source for <%s>", r->name); pa_xfree(r->source); r->source = pa_xstrdup(so->source->name); - u->modified = 1; + u->modified = TRUE; } } @@ -357,18 +357,18 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 if (si) { r->volume = *pa_sink_input_get_volume(si); - r->volume_is_set = 1; + r->volume_is_set = TRUE; r->sink = pa_xstrdup(si->sink->name); r->source = NULL; } else { pa_assert(so); - r->volume_is_set = 0; + r->volume_is_set = FALSE; r->sink = NULL; r->source = pa_xstrdup(so->source->name); } pa_hashmap_put(u->hashmap, r->name, r); - u->modified = 1; + u->modified = TRUE; } } @@ -433,7 +433,7 @@ int pa__init(pa_module*m) { u->hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); u->subscription = NULL; u->table_file = pa_xstrdup(pa_modargs_get_value(ma, "table", NULL)); - u->modified = 0; + u->modified = FALSE; u->sink_input_hook_slot = u->source_output_hook_slot = NULL; m->userdata = u; @@ -493,5 +493,3 @@ void pa__done(pa_module*m) { pa_xfree(u->table_file); pa_xfree(u); } - - -- cgit From 961ce33b5ee183236363ef39d1afa93d8e5605b3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 4 Nov 2007 16:51:26 +0000 Subject: fix two alignment issues found by the debian buildd gcc on sparc git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2022 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-esound-sink.c | 5 ++++- src/pulsecore/iochannel.c | 42 ++++++++++++++++++++++------------------ 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index 1c02cdfd..b18d3258 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -506,6 +506,7 @@ int pa__init(pa_module*m) { pa_modargs *ma = NULL; char *t; const char *espeaker; + uint32_t key; pa_assert(m); @@ -584,7 +585,9 @@ int pa__init(pa_module*m) { pa_log("Failed to load cookie"); goto fail; } - *(int32_t*) ((uint8_t*) u->write_data + ESD_KEY_LEN) = ESD_ENDIAN_KEY; + + key = ESD_ENDIAN_KEY; + memcpy((uint8_t*) u->write_data + ESD_KEY_LEN, &key, sizeof(key)); /* Reserve space for the response */ u->read_data = pa_xmalloc(u->read_length = sizeof(int32_t)); diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c index 01f17ab3..63ab2ad7 100644 --- a/src/pulsecore/iochannel.c +++ b/src/pulsecore/iochannel.c @@ -267,9 +267,11 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l ssize_t r; struct msghdr mh; struct iovec iov; - uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))]; + union { + struct cmsghdr hdr; + uint8_t data[CMSG_SPACE(sizeof(struct ucred))]; + } cmsg; struct ucred *u; - struct cmsghdr *cmsg; pa_assert(io); pa_assert(data); @@ -280,13 +282,12 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l iov.iov_base = (void*) data; iov.iov_len = l; - memset(cmsg_data, 0, sizeof(cmsg_data)); - cmsg = (struct cmsghdr*) cmsg_data; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_CREDENTIALS; + memset(&cmsg, 0, sizeof(cmsg)); + cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(struct ucred)); + cmsg.hdr.cmsg_level = SOL_SOCKET; + cmsg.hdr.cmsg_type = SCM_CREDENTIALS; - u = (struct ucred*) CMSG_DATA(cmsg); + u = (struct ucred*) CMSG_DATA(&cmsg.hdr); u->pid = getpid(); if (ucred) { @@ -302,8 +303,8 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l mh.msg_namelen = 0; mh.msg_iov = &iov; mh.msg_iovlen = 1; - mh.msg_control = cmsg_data; - mh.msg_controllen = sizeof(cmsg_data); + mh.msg_control = &cmsg; + mh.msg_controllen = sizeof(cmsg); mh.msg_flags = 0; if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) { @@ -318,7 +319,10 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_cr ssize_t r; struct msghdr mh; struct iovec iov; - uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))]; + union { + struct cmsghdr hdr; + uint8_t data[CMSG_SPACE(sizeof(struct ucred))]; + } cmsg; pa_assert(io); pa_assert(data); @@ -331,28 +335,28 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_cr iov.iov_base = data; iov.iov_len = l; - memset(cmsg_data, 0, sizeof(cmsg_data)); + memset(&cmsg, 0, sizeof(cmsg)); memset(&mh, 0, sizeof(mh)); mh.msg_name = NULL; mh.msg_namelen = 0; mh.msg_iov = &iov; mh.msg_iovlen = 1; - mh.msg_control = cmsg_data; - mh.msg_controllen = sizeof(cmsg_data); + mh.msg_control = &cmsg; + mh.msg_controllen = sizeof(cmsg); mh.msg_flags = 0; if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) { - struct cmsghdr *cmsg; + struct cmsghdr *cmh; *creds_valid = 0; - for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { + for (cmh = CMSG_FIRSTHDR(&mh); cmh; cmh = CMSG_NXTHDR(&mh, cmh)) { - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) { + if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_CREDENTIALS) { struct ucred u; - pa_assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))); - memcpy(&u, CMSG_DATA(cmsg), sizeof(struct ucred)); + pa_assert(cmh->cmsg_len == CMSG_LEN(sizeof(struct ucred))); + memcpy(&u, CMSG_DATA(cmh), sizeof(struct ucred)); creds->gid = u.gid; creds->uid = u.uid; -- cgit From bff4ca431b0146cb0cbb3935905f50714072a0d9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 5 Nov 2007 15:10:13 +0000 Subject: add a man page for the pulseaudio binary. More will follow. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2023 fefdeb5f-60dc-0310-8127-8f9354f1896f --- Makefile.am | 2 +- configure.ac | 40 ++++- man/Makefile.am | 60 ++++++++ man/pulseaudio.1.xml.in | 379 ++++++++++++++++++++++++++++++++++++++++++++++++ man/xmltoman.css | 30 ++++ man/xmltoman.dtd | 39 +++++ man/xmltoman.xsl | 129 ++++++++++++++++ src/daemon/cmdline.c | 2 +- 8 files changed, 678 insertions(+), 3 deletions(-) create mode 100644 man/Makefile.am create mode 100644 man/pulseaudio.1.xml.in create mode 100644 man/xmltoman.css create mode 100644 man/xmltoman.dtd create mode 100644 man/xmltoman.xsl diff --git a/Makefile.am b/Makefile.am index 79608a22..a41dc6c8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,7 +18,7 @@ # USA. EXTRA_DIST = bootstrap.sh LICENSE GPL LGPL doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in README todo -SUBDIRS=src doxygen +SUBDIRS=src doxygen man MAINTAINERCLEANFILES = noinst_DATA = diff --git a/configure.ac b/configure.ac index 07db9823..f6e548bc 100644 --- a/configure.ac +++ b/configure.ac @@ -28,7 +28,7 @@ m4_define(PA_MAJOR, [0]) m4_define(PA_MINOR, [9]) m4_define(PA_MICRO, [7]) -AC_INIT([pulseaudio], PA_MAJOR.PA_MINOR.PA_MICRO,[mzcbylcnhqvb (at) 0pointer (dot) de]) +AC_INIT([pulseaudio], PA_MAJOR.PA_MINOR.PA_MICRO,[mzchyfrnhqvb (at) 0pointer (dot) net]) AC_CONFIG_SRCDIR([src/daemon/main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) @@ -832,6 +832,43 @@ AC_SUBST(DBUS_LIBS) AC_SUBST(HAVE_DBUS) AM_CONDITIONAL([HAVE_DBUS], [test "x$HAVE_DBUS" = x1]) +### Build and Install man pages ### +AC_ARG_ENABLE(manpages, + AS_HELP_STRING([--disable-manpages],[Disable building and installation of man pages]), +[case "${enableval}" in + yes) manpages=yes ;; + no) manpages=no ;; + *) AC_MSG_ERROR([bad value ${enableval} for --disable-manpages]) ;; +esac],[manpages=yes]) + +if test x$manpages = xyes ; then + # + # XMLTOMAN manpage generation + # + AC_ARG_ENABLE(xmltoman, + AS_HELP_STRING([--disable-xmltoman],[Enable rebuilding of man pages with xmltoman]), + [case "${enableval}" in + yes) xmltoman=yes ;; + no) xmltoman=no ;; + *) AC_MSG_ERROR([bad value ${enableval} for --disable-xmltoman]) ;; + esac],[xmltoman=yes]) + + if test x$xmltoman = xyes ; then + AC_CHECK_PROG(have_xmltoman, xmltoman, yes, no) + fi + + if test x$have_xmltoman = xno -o x$xmltoman = xno; then + if ! test -e man/pulseaudio.1 ; then + AC_MSG_ERROR([*** xmltoman was not found or was disabled, it is required to build the manpages as they have not been pre-built, install xmltoman, pass --disable-manpages or dont pass --disable-xmltoman]) + exit 1 + fi + AC_MSG_WARN([*** Not rebuilding man pages as xmltoman is not found ***]) + xmltoman=no + fi +fi +AM_CONDITIONAL([USE_XMLTOMAN], [test "x$xmltoman" = xyes]) +AM_CONDITIONAL([BUILD_MANPAGES], [test "x$manpages" = xyes]) + #### PulseAudio system group & user ##### AC_ARG_WITH(system_user, AS_HELP_STRING([--with-system-user=],[User for running the PulseAudio daemon as a system-wide instance (pulse)])) @@ -914,6 +951,7 @@ AM_CONDITIONAL([FORCE_PREOPEN], [test "x$FORCE_PREOPEN" = "x1"]) AC_CONFIG_FILES([ Makefile src/Makefile +man/Makefile libpulse.pc libpulse-simple.pc libpulse-browse.pc diff --git a/man/Makefile.am b/man/Makefile.am new file mode 100644 index 00000000..b701a2ea --- /dev/null +++ b/man/Makefile.am @@ -0,0 +1,60 @@ +# $Id$ +# +# This file is part of PulseAudio. +# +# PulseAudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# PulseAudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with PulseAudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +pulseconfdir=$(sysconfdir)/pulse + +if BUILD_MANPAGES + +man_MANS = \ + pulseaudio.1 + +noinst_DATA = \ + pulseaudio.1.xml + +CLEANFILES = \ + $(noinst_DATA) + +pulseaudio.1.xml: pulseaudio.1.xml.in Makefile + sed -e 's,@pulseconfdir\@,$(pulseconfdir),g' \ + -e 's,@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),g' \ + -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' $< > $@ + +if USE_XMLTOMAN + +CLEANFILES += \ + $(man_MANS) + +pulseaudio.1: pulseaudio.1.xml Makefile + xmltoman $< > $@ + +xmllint: $(noinst_DATA) + for f in $(noinst_DATA) ; do \ + xmllint --noout --valid "$$f" || exit 1 ; \ + done + +endif + +endif + +EXTRA_DIST = \ + $(man_MANS) \ + pulseaudio.1.xml.in + xmltoman.css \ + xmltoman.xsl \ + xmltoman.dtd diff --git a/man/pulseaudio.1.xml.in b/man/pulseaudio.1.xml.in new file mode 100644 index 00000000..b30f4484 --- /dev/null +++ b/man/pulseaudio.1.xml.in @@ -0,0 +1,379 @@ + + + + + + + + + + + + pulseaudio [options] + pulseaudio --help + pulseaudio --dump-conf + pulseaudio --dump-modules + pulseaudio --dump-resample-methods + pulseaudio --cleanup-shm + pulseaudio --kill + pulseaudio --check + + + +

        PulseAudio is a networked low-latency sound server for Linux, POSIX and Windows systems.

        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + +

        ~/.pulse/daemon.conf, + @pulseconfdir@/daemon.conf: configuration settings + for the PulseAudio daemon. If the version in the user's home + directory does not exist the global configuration file is + loaded. See for + more information.

        + +

        ~/.pulse/default.pa, + @pulseconfdir@/default.pa: the default configuration + script to execute when the PulseAudio daemon is started. If the + version in the user's home directory does not exist the global + configuration script is loaded. See for more information.

        + +

        ~/.pulse/client.conf, + @pulseconfdir@/client.conf: configuration settings + for PulseAudio client applications. If the version in the user's + home directory does not exist the global configuration file is + loaded. See for + more information.

        + +
        + +
        + +

        SIGINT, SIGTERM: the PulseAudio daemon will shut + down (Same as --kill).

        + +

        SIGHUP: dump a long status report to STDOUT or + syslog, depending on the configuration.

        + +

        SIGUSR1: load module-cli, allowing runtime + reconfiguration via STDIN/STDOUT.

        + +

        SIGUSR2: load module-cli-protocol-unix, allowing + runtime reconfiguration via a AF_UNIX socket. See for more information.

        + +
        + +
        + +

        Group pulse-rt: if the PulseAudio binary is marked + SUID root, then membership of the calling user in this group + decides whether real-time and/or high-priority scheduling is + enabled. Please note that enabling real-time scheduling is a + security risk (see below).

        + +

        Group pulse-access: if PulseAudio is running as a system + daemon (see --system above) access is granted to + members of this group when they connect via AF_UNIX sockets. If + PulseAudio is running as a user daemon this group has no + meaning.

        + +

        User pulse, group pulse: if PulseAudio is running as a system + daemon (see --system above) and is started as root the + daemon will drop priviliges and become a normal user process using + this user and group. If PulseAudio is running as a user daemon + this user and group has no meaning.

        +
        + +
        + Blablub +
        + +
        +

        The PulseAudio Developers <@PACKAGE_BUGREPORT@>; PulseAudio is available from

        +
        + +
        +

        + , , , +

        +
        + +
        diff --git a/man/xmltoman.css b/man/xmltoman.css new file mode 100644 index 00000000..579a4fdc --- /dev/null +++ b/man/xmltoman.css @@ -0,0 +1,30 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with PulseAudio; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +***/ + +body { color: black; background-color: white; } +a:link, a:visited { color: #900000; } +h1 { text-transform:uppercase; font-size: 18pt; } +p { margin-left:1cm; margin-right:1cm; } +.cmd { font-family:monospace; } +.file { font-family:monospace; } +.arg { text-transform:uppercase; font-family:monospace; font-style: italic; } +.opt { font-family:monospace; font-weight: bold; } +.manref { font-family:monospace; } +.option .optdesc { margin-left:2cm; } diff --git a/man/xmltoman.dtd b/man/xmltoman.dtd new file mode 100644 index 00000000..121e62c8 --- /dev/null +++ b/man/xmltoman.dtd @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/man/xmltoman.xsl b/man/xmltoman.xsl new file mode 100644 index 00000000..8d4ca212 --- /dev/null +++ b/man/xmltoman.xsl @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + <xsl:value-of select="@name"/>(<xsl:value-of select="@section"/>) + + + +

        Name

        +

        + - +

        + + + +
        + + +

        + +

        +
        + + +

        + +

        +
        + + + + + + + + + + + + + + +
        + +
        +
        + + +

        Synopsis

        + +
        + + +

        Synopsis

        + +
        + + +

        Description

        + +
        + + +

        Options

        + +
        + + +

        + +
        + + +
        +
        + + + + + () + + + () + + + + + + + + +
        diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c index 0c840449..cfd2c841 100644 --- a/src/daemon/cmdline.c +++ b/src/daemon/cmdline.c @@ -144,7 +144,7 @@ void pa_cmdline_help(const char *argv0) { " --log-target={auto,syslog,stderr} Specify the log target\n" " -p, --dl-search-path=PATH Set the search path for dynamic shared\n" " objects (plugins)\n" - " --resample-method=[METHOD] Use the specified resampling method\n" + " --resample-method=METHOD Use the specified resampling method\n" " (See --dump-resample-methods for\n" " possible values)\n" " --use-pid-file[=BOOL] Create a PID file\n" -- cgit From 7fdc1ee0838d3c55e29d8f44f2919a60f9415e56 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 5 Nov 2007 23:56:00 +0000 Subject: add a couple of more man pages git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2024 fefdeb5f-60dc-0310-8127-8f9354f1896f --- man/Makefile.am | 72 ++++++++++++++++++++- man/esdcompat.1.xml.in | 91 ++++++++++++++++++++++++++ man/pacat.1.xml.in | 160 ++++++++++++++++++++++++++++++++++++++++++++++ man/pacmd.1.xml.in | 52 +++++++++++++++ man/pactl.1.xml.in | 145 +++++++++++++++++++++++++++++++++++++++++ man/paplay.1.xml.in | 129 +++++++++++++++++++++++++++++++++++++ man/pax11publish.1.xml.in | 153 ++++++++++++++++++++++++++++++++++++++++++++ man/pulseaudio.1.xml.in | 69 +++++++++++++++++++- 8 files changed, 867 insertions(+), 4 deletions(-) create mode 100644 man/esdcompat.1.xml.in create mode 100644 man/pacat.1.xml.in create mode 100644 man/pacmd.1.xml.in create mode 100644 man/pactl.1.xml.in create mode 100644 man/paplay.1.xml.in create mode 100644 man/pax11publish.1.xml.in diff --git a/man/Makefile.am b/man/Makefile.am index b701a2ea..a3427aa7 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -22,10 +22,22 @@ pulseconfdir=$(sysconfdir)/pulse if BUILD_MANPAGES man_MANS = \ - pulseaudio.1 + pulseaudio.1 \ + esdcompat.1 \ + pax11publish.1 \ + paplay.1 \ + pacat.1 \ + pacmd.1 \ + pactl.1 noinst_DATA = \ - pulseaudio.1.xml + pulseaudio.1.xml \ + esdcompat.1.xml \ + pax11publish.1.xml \ + paplay.1.xml \ + pacat.1.xml \ + pacmd.1.xml \ + pactl.1.xml CLEANFILES = \ $(noinst_DATA) @@ -35,6 +47,36 @@ pulseaudio.1.xml: pulseaudio.1.xml.in Makefile -e 's,@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),g' \ -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' $< > $@ +esdcompat.1.xml: esdcompat.1.xml.in Makefile + sed -e 's,@pulseconfdir\@,$(pulseconfdir),g' \ + -e 's,@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),g' \ + -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' $< > $@ + +pax11publish.1.xml: pax11publish.1.xml.in Makefile + sed -e 's,@pulseconfdir\@,$(pulseconfdir),g' \ + -e 's,@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),g' \ + -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' $< > $@ + +paplay.1.xml: paplay.1.xml.in Makefile + sed -e 's,@pulseconfdir\@,$(pulseconfdir),g' \ + -e 's,@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),g' \ + -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' $< > $@ + +pacat.1.xml: pacat.1.xml.in Makefile + sed -e 's,@pulseconfdir\@,$(pulseconfdir),g' \ + -e 's,@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),g' \ + -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' $< > $@ + +pacmd.1.xml: pacmd.1.xml.in Makefile + sed -e 's,@pulseconfdir\@,$(pulseconfdir),g' \ + -e 's,@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),g' \ + -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' $< > $@ + +pactl.1.xml: pactl.1.xml.in Makefile + sed -e 's,@pulseconfdir\@,$(pulseconfdir),g' \ + -e 's,@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),g' \ + -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' $< > $@ + if USE_XMLTOMAN CLEANFILES += \ @@ -43,6 +85,24 @@ CLEANFILES += \ pulseaudio.1: pulseaudio.1.xml Makefile xmltoman $< > $@ +esdcompat.1: esdcompat.1.xml Makefile + xmltoman $< > $@ + +pax11publish.1: pax11publish.1.xml Makefile + xmltoman $< > $@ + +paplay.1: paplay.1.xml Makefile + xmltoman $< > $@ + +pacat.1: pacat.1.xml Makefile + xmltoman $< > $@ + +pacmd.1: pacmd.1.xml Makefile + xmltoman $< > $@ + +pactl.1: pactl.1.xml Makefile + xmltoman $< > $@ + xmllint: $(noinst_DATA) for f in $(noinst_DATA) ; do \ xmllint --noout --valid "$$f" || exit 1 ; \ @@ -54,7 +114,13 @@ endif EXTRA_DIST = \ $(man_MANS) \ - pulseaudio.1.xml.in + pulseaudio.1.xml.in \ + esdcompat.1.xml.in \ + pax11publish.1.xml.in \ + paplay.1.xml.in \ + pacat.1.xml.in \ + pacmd.1.xml.in \ + pactl.1.xml.in \ xmltoman.css \ xmltoman.xsl \ xmltoman.dtd diff --git a/man/esdcompat.1.xml.in b/man/esdcompat.1.xml.in new file mode 100644 index 00000000..864dc5db --- /dev/null +++ b/man/esdcompat.1.xml.in @@ -0,0 +1,91 @@ + + + + + + + + + + + + esdcompat [options] + esdcompat --help + esdcompat --version + + + +

        esdcompat is a compatiblity script that takes the + same arguments as the ESD sound daemon , but uses them to start a the PulseAudio sound server with the appropriate parameters. It is + required to make PulseAudio a drop-in replacement for esd, i.e. it + can be used to make + start up PulseAudio instead of esd.

        + +

        It is recommended to make esd a symbolic link to this script.

        +
        + + + + + + + + + + + + + + +
        +

        The PulseAudio Developers <@PACKAGE_BUGREPORT@>; PulseAudio is available from

        +
        + +
        +

        + , +

        +
        + +
        diff --git a/man/pacat.1.xml.in b/man/pacat.1.xml.in new file mode 100644 index 00000000..35c7651b --- /dev/null +++ b/man/pacat.1.xml.in @@ -0,0 +1,160 @@ + + + + + + + + + + + + pacat [options] [FILE] + parec [options] [FILE] + paplay --help + paplay --version + + + +

        pacat is a simple tool for playing back or + capturing raw audio files on a PulseAudio sound server.

        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        +

        The PulseAudio Developers <@PACKAGE_BUGREPORT@>; PulseAudio is available from

        +
        + +
        +

        + , +

        +
        + +
        diff --git a/man/pacmd.1.xml.in b/man/pacmd.1.xml.in new file mode 100644 index 00000000..b760ba0e --- /dev/null +++ b/man/pacmd.1.xml.in @@ -0,0 +1,52 @@ + + + + + + + + + + + + pacmd + + + +

        This tool can be used to introspect or reconfigure a running + PulseAudio sound server during runtime. It connects to the sound + server and offers a simple live shell that can be used to enter + the commands also understood in the default.pa + configuration scripts.

        + +

        This program takes no command line options.

        +
        + +
        +

        The PulseAudio Developers <@PACKAGE_BUGREPORT@>; PulseAudio is available from

        +
        + +
        +

        + , , +

        +
        + +
        diff --git a/man/pactl.1.xml.in b/man/pactl.1.xml.in new file mode 100644 index 00000000..0b7b9a78 --- /dev/null +++ b/man/pactl.1.xml.in @@ -0,0 +1,145 @@ + + + + + + + + + + + + pulseaudio [options] stat + pulseaudio [options] list + pulseaudio [options] exit + pulseaudio [options] upload-sample FILENAME [NAME] + pulseaudio [options] play-sample NAME [SINK] + pulseaudio [options] remove-sample NAME + pulseaudio [options] move-sink-input ID SINK + pulseaudio [options] move-source-input ID SOURCE + pulseaudio [options] load-module NAME [ARGUMENTS ...] + pulseaudio [options] unload-module ID + pulseaudio [options] suspend-sink [SINK] 1|0 + pulseaudio [options] suspend-source [SOURCE] 1|0 + pulseaudio --help + pulseaudio --version + + + +

        PulseAudio is a networked low-latency sound server for Linux, POSIX and Windows systems.

        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        +

        The PulseAudio Developers <@PACKAGE_BUGREPORT@>; PulseAudio is available from

        +
        + +
        +

        + , +

        +
        + +
        diff --git a/man/paplay.1.xml.in b/man/paplay.1.xml.in new file mode 100644 index 00000000..bab45dc3 --- /dev/null +++ b/man/paplay.1.xml.in @@ -0,0 +1,129 @@ + + + + + + + + + + + + paplay [options] FILE + paplay --help + paplay --version + + + +

        paplay is a simple tool for playing back audio + files on a PulseAudio sound server. It understands all audio file + formats supported by libsndfile.

        +
        + + + + + + + + + + + + + + + + + + + + + + + +
        + +

        Due to a limitation in libsndfile + paplay currently does not always set the correct channel + mapping for playback of multichannel (i.e. surround) audio files, even if the channel mapping information is + available in the audio file.

        + +
        + +
        +

        The PulseAudio Developers <@PACKAGE_BUGREPORT@>; PulseAudio is available from

        +
        + +
        +

        + , +

        +
        + +
        diff --git a/man/pax11publish.1.xml.in b/man/pax11publish.1.xml.in new file mode 100644 index 00000000..1e3a1f01 --- /dev/null +++ b/man/pax11publish.1.xml.in @@ -0,0 +1,153 @@ + + + + + + + + + + + + pax11publish -h + pax11publish [options] [-d] + pax11publish [options] -e + pax11publish [options] -i + pax11publish [options] -r + + + +

        The pax11publish utility can be used to dump or + manipulate the PulseAudio server credentials that can be stored as + properties on the X11 root window.

        + +

        Please note that the loadable module + module-x11-publish exports the same information + directly from the PulseAudio sound server, and should in most + cases be used in preference over this tool.

        + +

        Use the following command to dump the raw + PulseAudio-specific data that is stored in your X11 root + window:

        + +

        xprop -root | grep ^PULSE_

        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + +
        +

        The PulseAudio Developers <@PACKAGE_BUGREPORT@>; PulseAudio is available from

        +
        + +
        +

        + , +

        +
        + +
        diff --git a/man/pulseaudio.1.xml.in b/man/pulseaudio.1.xml.in index b30f4484..1f53a60b 100644 --- a/man/pulseaudio.1.xml.in +++ b/man/pulseaudio.1.xml.in @@ -28,6 +28,7 @@ USA. pulseaudio [options] pulseaudio --help + pulseaudio --version pulseaudio --dump-conf pulseaudio --dump-modules pulseaudio --dump-resample-methods @@ -363,7 +364,73 @@ USA.
        - Blablub +

        To minimize the risk of drop-outs during playback it is + recommended to run PulseAudio with real-time scheduling if the + underlying platform supports it. This decouples the scheduling + latency of the PulseAudio daemon from the system load and is thus + the best way to make sure that PulseAudio always gets CPU time + when it needs it to refill the hardware playback + buffers. Unfortunately this is a security risk on most systems, + since PulseAudio runs as user process, and giving realtime + scheduling priviliges to a user process always comes with the risk + that the user misuses it to lock up the system -- which is + possible since making a process real-time effectively disables + preemption.

        + +

        To minimize the risk PulseAudio by default does not enable + real-time scheduling. It is however recommended to enable it + on trusted systems. To do that start PulseAudio with + --realtime (see above) or enabled the appropriate option in + daemon.conf. Since acquiring realtime scheduling is a + priviliged operation on most systems, some special changes to the + system configuration need to be made to allow them to the calling + user. Two options are available:

        + +

        On newer Linux systems the system resource limit RLIMIT_RTPRIO + (see for more information) + can be used to allow specific users to acquire real-time + scheduling. This can be configured in + /etc/security/limits.conf, a resource limit of 9 is recommended.

        + +

        Alternatively, the SUID root bit can be set for the PulseAudio + binary. Then, the daemon will drop root priviliges immediately on + startup, however retain the CAP_NICE capability (on systems that + support it), but only if the calling user is a member of the + pulse-rt group (see above). For all other users all + capababilities are dropped immediately. The advantage of this + solution is that the real-time priviliges are only granted to the + PulseAudio daemon -- not to all the user's processes.

        + +

        Alternatively, if the risk of locking up the machine is + considered too big to enable real-time scheduling, high-priority + scheduling can be enabled instead (i.e. negative nice level). This + can be enabled by passing --high-priority (see above) + when starting PulseAudio and may also be enabled with the + approriate option in daemon.conf. Negative nice + levels can only be enabled when the appropriate resource limit + RLIMIT_NICE is set (see for + more information), possibly configured in + /etc/security/limits.conf. A resource limit of 31 + (corresponding with nice level -11) is recommended.

        +
        + +
        + +

        The PulseAudio client libraries check for the existance of the + following environment variables and change their local configuration accordingly:

        + +

        $PULSE_SERVER: the server string specifying the server to connect to when a client asks for a sound server connection and doesn't explicitly ask for a specific server.

        + +

        $PULSE_SINK: the symbolic name of the sink to connect to when a client creates a playback stream and doesn't explicitly ask for a specific sink.

        + +

        $PULSE_SOURCE: the symbolic name of the source to connect to when a client creates a record stream and doesn't explicitly ask for a specific source.

        + +

        $PULSE_BINARY: path of PulseAudio executable to run when server auto-spawning is used.

        + +

        $PULSE_CLIENTCONFIG: path of file that shall be read instead of client.conf (see above) for client configuration.

        + +

        These environment settings take precedence -- if set -- over the configuration settings from client.conf (see above).

        +
        -- cgit From 0eb011bda093438044338946d575ff7845e6aa3c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 5 Nov 2007 23:56:30 +0000 Subject: minor cleanups of --help texts git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2025 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pactl.c | 2 +- src/utils/paplay.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/pactl.c b/src/utils/pactl.c index c963987f..eddbebc9 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -662,9 +662,9 @@ static void help(const char *argv0) { "%s [options] exit\n" "%s [options] upload-sample FILENAME [NAME]\n" "%s [options] play-sample NAME [SINK]\n" + "%s [options] remove-sample NAME\n" "%s [options] move-sink-input ID SINK\n" "%s [options] move-source-output ID SOURCE\n" - "%s [options] remove-sample NAME\n" "%s [options] load-module NAME [ARGS ...]\n" "%s [options] unload-module ID\n" "%s [options] suspend-sink [SINK] 1|0\n" diff --git a/src/utils/paplay.c b/src/utils/paplay.c index e7076d2d..fddbb18c 100644 --- a/src/utils/paplay.c +++ b/src/utils/paplay.c @@ -203,9 +203,9 @@ static void help(const char *argv0) { printf("%s [options] [FILE]\n\n" " -h, --help Show this help\n" " --version Show version\n\n" - " -v, --verbose Enable verbose operations\n\n" + " -v, --verbose Enable verbose operation\n\n" " -s, --server=SERVER The name of the server to connect to\n" - " -d, --device=DEVICE The name of the sink/source to connect to\n" + " -d, --device=DEVICE The name of the sink to connect to\n" " -n, --client-name=NAME How to call this client on the server\n" " --stream-name=NAME How to call this stream on the server\n" " --volume=VOLUME Specify the initial (linear) volume in range 0...65536\n" -- cgit From 5dbab0b23aa373f5eb61faf2b0cbae24f05570fa Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 6 Nov 2007 00:21:20 +0000 Subject: complete pactl man page git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2026 fefdeb5f-60dc-0310-8127-8f9354f1896f --- man/pactl.1.xml.in | 76 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 15 deletions(-) diff --git a/man/pactl.1.xml.in b/man/pactl.1.xml.in index 0b7b9a78..d30d5f7c 100644 --- a/man/pactl.1.xml.in +++ b/man/pactl.1.xml.in @@ -26,24 +26,26 @@ USA. - pulseaudio [options] stat - pulseaudio [options] list - pulseaudio [options] exit - pulseaudio [options] upload-sample FILENAME [NAME] - pulseaudio [options] play-sample NAME [SINK] - pulseaudio [options] remove-sample NAME - pulseaudio [options] move-sink-input ID SINK - pulseaudio [options] move-source-input ID SOURCE - pulseaudio [options] load-module NAME [ARGUMENTS ...] - pulseaudio [options] unload-module ID - pulseaudio [options] suspend-sink [SINK] 1|0 - pulseaudio [options] suspend-source [SOURCE] 1|0 - pulseaudio --help - pulseaudio --version + pactl [options] stat + pactl [options] list + pactl [options] exit + pactl [options] upload-sample FILENAME [NAME] + pactl [options] play-sample NAME [SINK] + pactl [options] remove-sample NAME + pactl [options] move-sink-input ID SINK + pactl [options] move-source-input ID SOURCE + pactl [options] load-module NAME [ARGUMENTS ...] + pactl [options] unload-module ID + pactl [options] suspend-sink [SINK] 1|0 + pactl [options] suspend-source [SOURCE] 1|0 + pactl --help + pactl --version -

        PulseAudio is a networked low-latency sound server for Linux, POSIX and Windows systems.

        +

        pactl can be used to issue control commands to the PulseAudio sound server.

        + +

        pactl only exposes a subset of the available operations. For the full set use the .

        @@ -130,6 +132,50 @@ USA.

        Move the specified recording stream (identified by its numerical index) to the specified source (identified by its symbolic name or numerical index).

        + + + + + + + + + +
        -- cgit From 1821f1f4994dfd0618ac290da54da683e7604f40 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 7 Nov 2007 13:50:47 +0000 Subject: add man pages for padsp, pabrowse, pasuspender git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2027 fefdeb5f-60dc-0310-8127-8f9354f1896f --- man/Makefile.am | 37 +++++++++++++++- man/pabrowse.1.xml.in | 49 +++++++++++++++++++++ man/padsp.1.xml.in | 112 +++++++++++++++++++++++++++++++++++++++++++++++ man/pasuspender.1.xml.in | 75 +++++++++++++++++++++++++++++++ 4 files changed, 271 insertions(+), 2 deletions(-) create mode 100644 man/pabrowse.1.xml.in create mode 100644 man/padsp.1.xml.in create mode 100644 man/pasuspender.1.xml.in diff --git a/man/Makefile.am b/man/Makefile.am index a3427aa7..e5ce5530 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -28,7 +28,10 @@ man_MANS = \ paplay.1 \ pacat.1 \ pacmd.1 \ - pactl.1 + pactl.1 \ + pasuspender.1 \ + padsp.1 \ + pabrowse.1 noinst_DATA = \ pulseaudio.1.xml \ @@ -37,7 +40,10 @@ noinst_DATA = \ paplay.1.xml \ pacat.1.xml \ pacmd.1.xml \ - pactl.1.xml + pactl.1.xml \ + pasuspender.1.xml \ + padsp.1.xml \ + pabrowse.1.xml CLEANFILES = \ $(noinst_DATA) @@ -77,6 +83,21 @@ pactl.1.xml: pactl.1.xml.in Makefile -e 's,@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),g' \ -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' $< > $@ +pasuspender.1.xml: pasuspender.1.xml.in Makefile + sed -e 's,@pulseconfdir\@,$(pulseconfdir),g' \ + -e 's,@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),g' \ + -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' $< > $@ + +padsp.1.xml: padsp.1.xml.in Makefile + sed -e 's,@pulseconfdir\@,$(pulseconfdir),g' \ + -e 's,@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),g' \ + -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' $< > $@ + +pabrowse.1.xml: pabrowse.1.xml.in Makefile + sed -e 's,@pulseconfdir\@,$(pulseconfdir),g' \ + -e 's,@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),g' \ + -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' $< > $@ + if USE_XMLTOMAN CLEANFILES += \ @@ -103,6 +124,15 @@ pacmd.1: pacmd.1.xml Makefile pactl.1: pactl.1.xml Makefile xmltoman $< > $@ +pasuspender.1: pasuspender.1.xml Makefile + xmltoman $< > $@ + +padsp.1: padsp.1.xml Makefile + xmltoman $< > $@ + +pabrowse.1: pabrowse.1.xml Makefile + xmltoman $< > $@ + xmllint: $(noinst_DATA) for f in $(noinst_DATA) ; do \ xmllint --noout --valid "$$f" || exit 1 ; \ @@ -121,6 +151,9 @@ EXTRA_DIST = \ pacat.1.xml.in \ pacmd.1.xml.in \ pactl.1.xml.in \ + pasuspender.1.xml.in \ + padsp.1.xml.in \ + pabrowse.1.xml.in \ xmltoman.css \ xmltoman.xsl \ xmltoman.dtd diff --git a/man/pabrowse.1.xml.in b/man/pabrowse.1.xml.in new file mode 100644 index 00000000..b539fb21 --- /dev/null +++ b/man/pabrowse.1.xml.in @@ -0,0 +1,49 @@ + + + + + + + + + + + + pabrowse + + + +

        pabrowse lists all PulseAudio sound servers on the + local network that are being announced with Zeroconf/Avahi.

        + +

        This program takes no command line arguments.

        +
        + +
        +

        The PulseAudio Developers <@PACKAGE_BUGREPORT@>; PulseAudio is available from

        +
        + +
        +

        + , +

        +
        + +
        diff --git a/man/padsp.1.xml.in b/man/padsp.1.xml.in new file mode 100644 index 00000000..610a9602 --- /dev/null +++ b/man/padsp.1.xml.in @@ -0,0 +1,112 @@ + + + + + + + + + + + + padsp [options] PROGRAM [ARGUMENTS ...] + padsp -h + + + +

        padsp starts the specified program and + redirects its access to OSS compatible audio devices + (/dev/dsp and auxiliary devices) to a PulseAudio + sound server.

        + +

        padsp uses the $LD_PRELOAD environment variable + that is interpreted by and thus + does not work for SUID binaries and statically built + executables.

        + +

        Equivalent to using padsp is starting an + application with $LD_PRELOAD set to + libpulsedsp.so

        +
        + + + + + + + + + + + + + + + + + + + + + + +
        +

        The PulseAudio Developers <@PACKAGE_BUGREPORT@>; PulseAudio is available from

        +
        + +
        +

        + , , +

        +
        + +
        diff --git a/man/pasuspender.1.xml.in b/man/pasuspender.1.xml.in new file mode 100644 index 00000000..8a73343a --- /dev/null +++ b/man/pasuspender.1.xml.in @@ -0,0 +1,75 @@ + + + + + + + + + + + + pasuspender [options] -- PROGRAM [ARGUMENTS ...] + pasuspender --help + pasuspender --version + + + +

        pasuspender is a tool that can be used to tell a + local PulseAudio sound server to temporarily suspend access to the + audio devices, to allow other + applications access them directly. pasuspender will + suspend access to the audio devices, fork a child process, and + when the child process terminates, resume access again.

        +
        + + + + + + + + + + + +
        +

        The PulseAudio Developers <@PACKAGE_BUGREPORT@>; PulseAudio is available from

        +
        + +
        +

        + , , , +

        +
        + +
        -- cgit From 1ef4bafc9a6ea0661e5b1a26948f8ab5b5b8afa2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 7 Nov 2007 13:52:07 +0000 Subject: warn if the sound server is not local git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2028 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pasuspender.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/utils/pasuspender.c b/src/utils/pasuspender.c index ae59086b..05d96a68 100644 --- a/src/utils/pasuspender.c +++ b/src/utils/pasuspender.c @@ -149,8 +149,10 @@ static void context_state_callback(pa_context *c, void *userdata) { if (pa_context_is_local(c)) { pa_operation_unref(pa_context_suspend_sink_by_index(c, PA_INVALID_INDEX, 1, suspend_complete, NULL)); pa_operation_unref(pa_context_suspend_source_by_index(c, PA_INVALID_INDEX, 1, suspend_complete, NULL)); - } else + } else { + fprintf(stderr, "WARNING: Sound server is not local, not suspending.\n"); start_child(); + } break; -- cgit From 445991287d541d15a9a446980e1485263ae55e10 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 8 Nov 2007 22:30:33 +0000 Subject: add remaing man pages git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2029 fefdeb5f-60dc-0310-8127-8f9354f1896f --- man/Makefile.am | 37 ++++- man/default.pa.5.xml.in | 58 +++++++ man/pacat.1.xml.in | 32 ++-- man/pulse-client.conf.5.xml.in | 115 +++++++++++++ man/pulse-daemon.conf.5.xml.in | 366 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 590 insertions(+), 18 deletions(-) create mode 100644 man/default.pa.5.xml.in create mode 100644 man/pulse-client.conf.5.xml.in create mode 100644 man/pulse-daemon.conf.5.xml.in diff --git a/man/Makefile.am b/man/Makefile.am index e5ce5530..0a355f95 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -31,7 +31,10 @@ man_MANS = \ pactl.1 \ pasuspender.1 \ padsp.1 \ - pabrowse.1 + pabrowse.1 \ + pulse-daemon.conf.5 \ + pulse-client.conf.5 \ + default.pa.5 noinst_DATA = \ pulseaudio.1.xml \ @@ -43,7 +46,10 @@ noinst_DATA = \ pactl.1.xml \ pasuspender.1.xml \ padsp.1.xml \ - pabrowse.1.xml + pabrowse.1.xml \ + pulse-daemon.conf.5.xml \ + pulse-client.conf.5.xml \ + default.pa.5.xml CLEANFILES = \ $(noinst_DATA) @@ -98,6 +104,21 @@ pabrowse.1.xml: pabrowse.1.xml.in Makefile -e 's,@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),g' \ -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' $< > $@ +pulse-daemon.conf.5.xml: pulse-daemon.conf.5.xml.in Makefile + sed -e 's,@pulseconfdir\@,$(pulseconfdir),g' \ + -e 's,@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),g' \ + -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' $< > $@ + +pulse-client.conf.5.xml: pulse-client.conf.5.xml.in Makefile + sed -e 's,@pulseconfdir\@,$(pulseconfdir),g' \ + -e 's,@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),g' \ + -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' $< > $@ + +default.pa.5.xml: default.pa.5.xml.in Makefile + sed -e 's,@pulseconfdir\@,$(pulseconfdir),g' \ + -e 's,@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),g' \ + -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' $< > $@ + if USE_XMLTOMAN CLEANFILES += \ @@ -133,6 +154,15 @@ padsp.1: padsp.1.xml Makefile pabrowse.1: pabrowse.1.xml Makefile xmltoman $< > $@ +pulse-daemon.conf.5: pulse-daemon.conf.5.xml Makefile + xmltoman $< > $@ + +pulse-client.conf.5: pulse-client.conf.5.xml Makefile + xmltoman $< > $@ + +default.pa.5: default.pa.5.xml Makefile + xmltoman $< > $@ + xmllint: $(noinst_DATA) for f in $(noinst_DATA) ; do \ xmllint --noout --valid "$$f" || exit 1 ; \ @@ -154,6 +184,9 @@ EXTRA_DIST = \ pasuspender.1.xml.in \ padsp.1.xml.in \ pabrowse.1.xml.in \ + pulse-daemon.conf.5.xml.in \ + pulse-client.conf.5.xml.in \ + default.pa.5.xml.in \ xmltoman.css \ xmltoman.xsl \ xmltoman.dtd diff --git a/man/default.pa.5.xml.in b/man/default.pa.5.xml.in new file mode 100644 index 00000000..0f826db6 --- /dev/null +++ b/man/default.pa.5.xml.in @@ -0,0 +1,58 @@ + + + + + + + + + + + +

        ~/.pulse/default.pa

        + +

        @pulseconfdir@/default.pa

        +
        + + +

        The PulseAudio sound server interprets the file + ~/.pulse/default.pa on startup, and when that file + doesn't exist @pulseconfdir@/default.pa. It + should contain directives in the PulseAudio CLI languages, as + documented on .

        + +

        The same commands can also be entered during runtime in the tool, allowing flexible runtime reconfiguration.

        +
        + +
        +

        The PulseAudio Developers <@PACKAGE_BUGREPORT@>; + PulseAudio is available from

        +
        + +
        +

        + , , +

        +
        + +
        diff --git a/man/pacat.1.xml.in b/man/pacat.1.xml.in index 35c7651b..e02ad667 100644 --- a/man/pacat.1.xml.in +++ b/man/pacat.1.xml.in @@ -109,11 +109,11 @@ USA.

        --format=FORMAT

        Capture or play back audio with the specified sample - format. Specify one of u8, s16le, - s16be, float32le, float32be, - ulaw, alaw. Depending on the endianess of - the CPU the formats s16ne, s16re, - float32ne, float32re (for native, + format. Specify one of u8, s16le, + s16be, float32le, float32be, + ulaw, alaw. Depending on the endianess of + the CPU the formats s16ne, s16re, + float32ne, float32re (for native, resp. reverse endian) are available as aliases. Defaults to s16ne.

        @@ -132,17 +132,17 @@ USA.

        Explicitly choose a channel map when playing back this stream. The argument should be a comma separated list of - channel names: front-left, front-right, - mono, front-center, rear-left, - rear-right, rear-center, lfe, - front-left-of-center, - front-right-of-center, side-left, - side-right, top-center, - top-front-center, top-front-left, - top-front-right, top-rear-left, - top-rear-right, top-rear-center, or any of - the 32 auxiliary channel names aux0 to - aux31.

        + channel names: front-left, front-right, + mono, front-center, rear-left, + rear-right, rear-center, lfe, + front-left-of-center, + front-right-of-center, side-left, + side-right, top-center, + top-front-center, top-front-left, + top-front-right, top-rear-left, + top-rear-right, top-rear-center, or any of + the 32 auxiliary channel names aux0 to + aux31.

        diff --git a/man/pulse-client.conf.5.xml.in b/man/pulse-client.conf.5.xml.in new file mode 100644 index 00000000..dbf8dc0b --- /dev/null +++ b/man/pulse-client.conf.5.xml.in @@ -0,0 +1,115 @@ + + + + + + + + + + + +

        ~/.pulse/client.conf

        + +

        @pulseconfdir@/client.conf

        +
        + + +

        The PulseAudio client library reads configuration directives from + a file ~/.pulse/client.conf on startup, and when that + file doesn't exist from + @pulseconfdir@/client.conf.

        + +

        The configuration file is a simple collection of variable + declarations. If the configuration file parser encounters either ; + or # for it ignores the rest of the line until its end.

        + +

        For the settings that take a boolean argument, the values + true, yes, on and 1 + are equivalent, resp. false, no, + off, 0.

        + +
        + +
        + + + + + + + + + + + + + + + + + +
        + +
        +

        The PulseAudio Developers <@PACKAGE_BUGREPORT@>; + PulseAudio is available from

        +
        + +
        +

        + , +

        +
        + +
        diff --git a/man/pulse-daemon.conf.5.xml.in b/man/pulse-daemon.conf.5.xml.in new file mode 100644 index 00000000..88bf8f58 --- /dev/null +++ b/man/pulse-daemon.conf.5.xml.in @@ -0,0 +1,366 @@ + + + + + + + + + + + +

        ~/.pulse/daemon.conf

        + +

        @pulseconfdir@/daemon.conf

        +
        + + +

        The PulseAudio sound server reads configuration directives from + a file ~/.pulse/daemon.conf on startup, and when that + file doesn't exist from + @pulseconfdir@/daemon.conf. Please note that the + server also reads a configuration script on startup + default.pa which also contains runtime configuration + directives.

        + +

        The configuration file is a simple collection of variable + declarations. If the configuration file parser encounters either ; + or # for it ignores the rest of the line until its end.

        + +

        For the settings that take a boolean argument, the values + true, yes, on and 1 + are equivalent, resp. false, no, + off, 0.

        + +
        + +
        + + + + + + + + + + + + + + + + + + + +
        + +
        + + + + + + + + + +
        + +
        + + + + + + + +
        + +
        + + + + + +
        + +
        + + + + + +
        + +
        + +

        See for + more information. Set to -1 if PulseAudio shall not touch the resource + limit. Not all resource limits are available on all operating + systems.

        + + + + + + + + + + + + +
        + +
        + +

        Most drivers try to open the audio device with these settings + and then fall back to lower settings. The default settings are CD + quality: 16bit native endian, 2 channels, 44100 Hz sampling.

        + + + + + + + +
        + +
        + +

        Some hardware drivers require the hardware playback buffer to + be subdivided into several fragments. It is possible to change + these buffer metrics for machines with high scheduling + latencies. Not all possible values that may be configured here are + available in all hardware. The driver will to find the nearest + setting supported.

        + + + + +
        + +
        +

        The PulseAudio Developers <@PACKAGE_BUGREPORT@>; PulseAudio is available from

        +
        + +
        +

        + , , , +

        +
        + +
        -- cgit From a2121d5e6f33b31481a014012b7eef43b8e500db Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 8 Nov 2007 22:31:30 +0000 Subject: strip most comments from the default configuration files, since the man page is now more elaborate and we don't want to maintain those docs redundantly at two places git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2030 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/daemon.conf.in | 87 +++++------------------------------------------ src/pulse/client.conf.in | 29 +++++----------- 2 files changed, 17 insertions(+), 99 deletions(-) diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in index 54acd8ea..f15d93e8 100644 --- a/src/daemon/daemon.conf.in +++ b/src/daemon/daemon.conf.in @@ -17,104 +17,38 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -## Configuration file for the pulseaudio daemon. Default values are -## commented out. Use either ; or # for commenting +## Configuration file for the PulseAudio daemon. See pulse-daemon.conf(5) for +## more information. Default values a commented out. Use either ; or # for +## commenting. -## Daemonize after startup ; daemonize = no - -## Quit if startup fails ; fail = yes +; disallow-module-loading = no +; use-pid-file = yes +; system-instance = no +; disable-shm = no -## Renice the daemon to level -15. This a good idea if you experience -## drop-outs in the playback. However, this is a certain security -## issue, since it works when called SUID root only. root is dropped -## immediately after gaining the nice level on startup, thus it is -## presumably safe. ; high-priority = yes +; nice-level = -11 -## Try to acquire SCHED_FIFO scheduling for the IO threads. The same -## security concerns as mentioned above apply. However, if PA enters -## an endless loop, realtime scheduling causes a system lockup. Thus, -## realtime scheduling should only be enabled on trusted machines for -## now. Please not that only the IO threads of PulseAudio are made -## real-time. The controlling thread is left a normally scheduled -## thread. Thus the enabling the high-priority option is orthogonal. ; realtime-scheduling = no - -## The realtime priority to acquire, if realtime-scheduling is -## enabled. (Note: JACK uses 10 by default, 9 for clients -- some -## PulseAudio threads might choose a priority a little lower or higher -## than this value.) ; realtime-priority = 5 -## The nice level to acquire for the daemon, if high-priority is -## enabled. (Note: on some distributions X11 uses -10 by default.) -; nice-level = -11 - -## Disallow module loading after startup -; disallow-module-loading = no - -## Terminate the daemon after the last client quit and this time -## passed. Use a negative value to disable this feature. ; exit-idle-time = -1 - -## Unload autoloaded modules after being idle for this time ; module-idle-time = 20 - -## Unload autoloaded sample cache entries after being idle for this time ; scache-idle-time = 20 -## The path were to look for dynamic shared objects (DSOs aka -## plugins). You may specify more than one path seperated by -## colons. ; dl-search-path = @PA_DLSEARCHPATH@ -## The default script file to load. Specify an empty string for not -## loading a default script file. The ; default-script-file = @PA_DEFAULT_CONFIG_FILE@ -## The default log target. Use either "stderr", "syslog" or -## "auto". The latter is equivalent to "sylog" in case daemonize is -## true, otherwise to "stderr". ; log-target = auto - -# Log level, one of debug, info, notice, warning, error. Log messages -# with a lower log level than specified here are not logged, ; log-level = notice -## The resampling algorithm to use. Use one of src-sinc-best-quality, -## src-sinc-medium-quality, src-sinc-fastest, src-zero-order-hold, -## src-linear, trivial, speex-float-N, speex-fixed-N, ffmpeg. See the -## documentation of libsamplerate for an explanation for the different -## src- methods. The method 'trivial' is the most basic algorithm -## implemented. If you're tight on CPU consider using this. On the -## other hand it has the worst quality of them all. The speex -## resamplers take an integer quality setting in the range 0..9 -## (bad...good). They exist in two flavours: fixed and float. The -## former uses fixed point numbers, the latter relies on floating -## point numbers. On most desktop CPUs the float point resmapler is a -## lot faster, and it also offers slightly better quality. ; resample-method = speex-float-3 -## Create a PID file in /tmp/pulseaudio-$USER/pid. Of this is enabled -## you may use commands like "pulseaudio --kill" or "pulseaudio -## --check". If you are planning to start more than one pulseaudio -## process per user, you better disable this option since it -## effectively disables multiple instances. -; use-pid-file = yes - -## Do not install the CPU load limit, even on platforms where it is -## supported. This option is useful when debugging/profiling -## PulseAudio to disable disturbing SIGXCPU signals. ; no-cpu-limit = no -## Run the daemon as system-wide instance, requires root priviliges -; system-instance = no - -## Resource limits, see getrlimit(2) for more information. Set to -1 -## if PA shouldn't touch the resource limit. Not all resource limits -## are available on all operating systems. ; rlimit-as = -1 ; rlimit-core = -1 ; rlimit-data = -1 @@ -126,14 +60,9 @@ ; rlimit-nice = 31 ; rlimit-rtprio = 9 -## Disable shared memory data transfer -; disable-shm = no - -## Default sample format ; default-sample-format = s16le ; default-sample-rate = 44100 ; default-sample-channels = 2 -## Default fragment settings, for device drivers that need this ; default-fragments = 4 ; default-fragment-size-msec = 25 diff --git a/src/pulse/client.conf.in b/src/pulse/client.conf.in index 3cfd9760..2bc8a7c8 100644 --- a/src/pulse/client.conf.in +++ b/src/pulse/client.conf.in @@ -17,29 +17,18 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. -## Configuration file for pulseaudio clients. Default values are -## commented out. Use either ; or # for commenting +## Configuration file for PulseAudio clients. See pulse-client.conf(5) for +## more information. Default values a commented out. Use either ; or # for +## commenting. -## Path to the pulseaudio daemon to run when autospawning. -; daemon-binary = @PA_BINARY@ - -## Extra arguments to pass to the pulseaudio daemon -; extra-arguments = --log-target=syslog --exit-idle-time=5 - -## The default sink to connect to -; default-sink = - -## The default source to connect to +; default-sink = ; default-source = - -## The default sever to connect to ; default-server = -## Autospawn daemons? -; autospawn = 0 +; autospawn = no +; daemon-binary = @PA_BINARY@ +; extra-arguments = --log-target=syslog --exit-idle-time=5 -### Cookie file -; cookie-file = +; cookie-file = -### Disable shared memory data transfer -; disable-shm = 0 +; disable-shm = no -- cgit From 14b974a6d870432554afc20710ad9f93f4833e88 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 8 Nov 2007 22:42:33 +0000 Subject: parse the pasuspend argument like any other boolean in PulseAudio git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2031 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 2 +- src/utils/pactl.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index dbb9adcd..91e22dfe 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -185,7 +185,7 @@ paplay_LDADD = $(AM_LDADD) libpulse.la $(LIBSNDFILE_LIBS) paplay_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) paplay_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -pactl_SOURCES = utils/pactl.c +pactl_SOURCES = utils/pactl.c pulsecore/core-util.c pulsecore/core-util.h pulsecore/core-error.c pulsecore/core-error.h pulsecore/log.c pulsecore/log.h pulsecore/once.c pulsecore/once.h $(PA_THREAD_OBJS) pactl_LDADD = $(AM_LDADD) libpulse.la $(LIBSNDFILE_LIBS) pactl_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) pactl_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) diff --git a/src/utils/pactl.c b/src/utils/pactl.c index eddbebc9..5425b131 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -850,7 +850,7 @@ int main(int argc, char *argv[]) { goto quit; } - suspend = !!atoi(argv[argc-1]); + suspend = pa_parse_boolean(argv[argc-1]); if (argc > optind+2) sink_name = pa_xstrdup(argv[optind+1]); @@ -863,7 +863,7 @@ int main(int argc, char *argv[]) { goto quit; } - suspend = !!atoi(argv[argc-1]); + suspend = pa_parse_boolean(argv[argc-1]); if (argc > optind+2) source_name = pa_xstrdup(argv[optind+1]); -- cgit From c8cdb06135e2e316a724098e5c0af7aa9e81091e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 9 Nov 2007 01:28:56 +0000 Subject: add support for likely()/unlikely() type macros git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2032 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/gccmacro.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/pulsecore/gccmacro.h b/src/pulsecore/gccmacro.h index e9f0d093..ecdc0578 100644 --- a/src/pulsecore/gccmacro.h +++ b/src/pulsecore/gccmacro.h @@ -60,7 +60,7 @@ #endif #ifndef PA_GCC_PURE -#ifdef __GNUCC__ +#ifdef __GNUC__ #define PA_GCC_PURE __attribute__ ((pure)) #else /** This function's return value depends only the arguments list and global state **/ @@ -69,7 +69,7 @@ #endif #ifndef PA_GCC_CONST -#ifdef __GNUCC__ +#ifdef __GNUC__ #define PA_GCC_CONST __attribute__ ((const)) #else /** This function's return value depends only the arguments list (stricter version of PA_GCC_PURE) **/ @@ -77,4 +77,14 @@ #endif #endif +#ifndef PA_LIKELY +#ifdef __GNUC__ +#define PA_LIKELY(x) __builtin_expect((x),1) +#define PA_UNLIKELY(x) __builtin_expect((x),0) +#else +#define PA_LIKELY(x) (x) +#define PA_UNLIKELY(x) (x) +#endif +#endif + #endif -- cgit From cb66762d6dea8ac8871bb23efbf8c9b77f8d08fd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 9 Nov 2007 01:29:50 +0000 Subject: add PA_CLAMP_LIKELY and PA_CLAMP_UNLIKELY macros git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2033 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/macro.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/macro.h b/src/pulsecore/macro.h index c6bba437..548e4ed9 100644 --- a/src/pulsecore/macro.h +++ b/src/pulsecore/macro.h @@ -31,6 +31,7 @@ #include #include +#include #ifndef PACKAGE #error "Please include config.h before including this file!" @@ -73,9 +74,12 @@ static inline size_t pa_page_align(size_t l) { #endif #ifndef CLAMP -#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) +#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) #endif +#define PA_CLAMP_LIKELY(x, low, high) (PA_LIKELY((x) > (high)) ? (high) : PA_LIKELY(((x) < (low)) ? (low) : (x))) +#define PA_CLAMP_UNLIKELY(x, low, high) (PA_UNLIKELY((x) > (high)) ? (high) : PA_UNLIKELY(((x) < (low)) ? (low) : (x))) + /* This type is not intended to be used in exported APIs! Use classic "int" there! */ #ifdef HAVE_STD_BOOL typedef _Bool pa_bool_t; -- cgit From 42ef0518eb05ca18fccae4d6fb79f2db0d7730d1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 9 Nov 2007 01:30:25 +0000 Subject: add a few missing macro definitions git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2034 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/endianmacros.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/pulsecore/endianmacros.h b/src/pulsecore/endianmacros.h index 8f7cfade..05d3262f 100644 --- a/src/pulsecore/endianmacros.h +++ b/src/pulsecore/endianmacros.h @@ -63,9 +63,15 @@ #define PA_UINT16_FROM_LE(x) PA_UINT16_SWAP(x) #define PA_UINT16_FROM_BE(x) ((uint16_t)(x)) + #define PA_UINT16_TO_LE(x) PA_UINT16_SWAP(x) + #define PA_UINT16_TO_BE(x) ((uint16_t)(x)) + #define PA_INT32_FROM_LE(x) PA_INT32_SWAP(x) #define PA_INT32_FROM_BE(x) ((int32_t)(x)) + #define PA_INT32_TO_LE(x) PA_INT32_SWAP(x) + #define PA_INT32_TO_BE(x) ((int32_t)(x)) + #define PA_UINT32_FROM_LE(x) PA_UINT32_SWAP(x) #define PA_UINT32_FROM_BE(x) ((uint32_t)(x)) @@ -81,9 +87,15 @@ #define PA_UINT16_FROM_LE(x) ((uint16_t)(x)) #define PA_UINT16_FROM_BE(x) PA_UINT16_SWAP(x) + #define PA_UINT16_TO_LE(x) ((uint16_t)(x)) + #define PA_UINT16_TO_BE(x) PA_UINT16_SWAP(x) + #define PA_INT32_FROM_LE(x) ((int32_t)(x)) #define PA_INT32_FROM_BE(x) PA_INT32_SWAP(x) + #define PA_INT32_TO_LE(x) ((int32_t)(x)) + #define PA_INT32_TO_BE(x) PA_INT32_SWAP(x) + #define PA_UINT32_FROM_LE(x) ((uint32_t)(x)) #define PA_UINT32_FROM_BE(x) PA_UINT32_SWAP(x) -- cgit From ecf349dc6cdb6737f3854c5c4678d336dcf10938 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 9 Nov 2007 01:30:46 +0000 Subject: add missing #include git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2035 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pactl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 5425b131..4519b13b 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -38,6 +38,7 @@ #include #include +#include #if PA_API_VERSION < 10 #error Invalid PulseAudio API version -- cgit From 3c17c7d44284a739ec1453a7470333c73f072eeb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 9 Nov 2007 02:12:09 +0000 Subject: fix CLAMP_LIKELY/UNLIKELY definition git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2036 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/gccmacro.h | 4 ++-- src/pulsecore/macro.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pulsecore/gccmacro.h b/src/pulsecore/gccmacro.h index ecdc0578..f1646653 100644 --- a/src/pulsecore/gccmacro.h +++ b/src/pulsecore/gccmacro.h @@ -79,8 +79,8 @@ #ifndef PA_LIKELY #ifdef __GNUC__ -#define PA_LIKELY(x) __builtin_expect((x),1) -#define PA_UNLIKELY(x) __builtin_expect((x),0) +#define PA_LIKELY(x) (__builtin_expect((x),1)) +#define PA_UNLIKELY(x) (__builtin_expect((x),0)) #else #define PA_LIKELY(x) (x) #define PA_UNLIKELY(x) (x) diff --git a/src/pulsecore/macro.h b/src/pulsecore/macro.h index 548e4ed9..98e023aa 100644 --- a/src/pulsecore/macro.h +++ b/src/pulsecore/macro.h @@ -77,8 +77,8 @@ static inline size_t pa_page_align(size_t l) { #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) #endif -#define PA_CLAMP_LIKELY(x, low, high) (PA_LIKELY((x) > (high)) ? (high) : PA_LIKELY(((x) < (low)) ? (low) : (x))) -#define PA_CLAMP_UNLIKELY(x, low, high) (PA_UNLIKELY((x) > (high)) ? (high) : PA_UNLIKELY(((x) < (low)) ? (low) : (x))) +#define PA_CLAMP_LIKELY(x, low, high) (PA_LIKELY((x) > (high)) ? (high) : (PA_LIKELY((x)<(low)) ? (low) : (x))) +#define PA_CLAMP_UNLIKELY(x, low, high) (PA_UNLIKELY((x) > (high)) ? (high) : (PA_UNLIKELY((x) < (low)) ? (low) : (x))) /* This type is not intended to be used in exported APIs! Use classic "int" there! */ #ifdef HAVE_STD_BOOL -- cgit From 7e0f547f2fd8ddfae1d807334dbc3428a3dfe374 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 9 Nov 2007 02:45:07 +0000 Subject: add support for 32bit integer samples git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2037 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 14 ++++- src/modules/oss-util.c | 2 + src/pulse/sample.c | 16 +++++- src/pulse/sample.h | 18 +++++- src/pulsecore/resampler.c | 4 +- src/pulsecore/sample-util.c | 61 +++++++++++++++++++-- src/pulsecore/sconv-s16be.c | 15 +++++ src/pulsecore/sconv-s16be.h | 20 +++++++ src/pulsecore/sconv-s16le.c | 131 +++++++++++++++++++++++++++++++++++++++++++- src/pulsecore/sconv-s16le.h | 20 +++++++ src/pulsecore/sconv.c | 8 +++ src/tests/resampler-test.c | 27 +++++++++ 12 files changed, 319 insertions(+), 17 deletions(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 906de58d..15ae1fc6 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -227,15 +227,19 @@ static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_s [PA_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE, [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE, [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, + [PA_SAMPLE_S32LE] = SND_PCM_FORMAT_S32_LE, + [PA_SAMPLE_S32BE] = SND_PCM_FORMAT_S32_BE, }; static const pa_sample_format_t try_order[] = { - PA_SAMPLE_S16NE, - PA_SAMPLE_S16RE, PA_SAMPLE_FLOAT32NE, PA_SAMPLE_FLOAT32RE, - PA_SAMPLE_ULAW, + PA_SAMPLE_S32NE, + PA_SAMPLE_S32RE, + PA_SAMPLE_S16NE, + PA_SAMPLE_S16RE, PA_SAMPLE_ALAW, + PA_SAMPLE_ULAW, PA_SAMPLE_U8, PA_SAMPLE_INVALID }; @@ -256,6 +260,10 @@ static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_s *f = PA_SAMPLE_S16LE; else if (*f == PA_SAMPLE_S16LE) *f = PA_SAMPLE_S16BE; + else if (*f == PA_SAMPLE_S32BE) + *f = PA_SAMPLE_S32LE; + else if (*f == PA_SAMPLE_S32LE) + *f = PA_SAMPLE_S32BE; else goto try_auto; diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index 015db4ca..9598feee 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -164,6 +164,8 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss) { [PA_SAMPLE_S16BE] = AFMT_S16_BE, [PA_SAMPLE_FLOAT32LE] = AFMT_QUERY, /* not supported */ [PA_SAMPLE_FLOAT32BE] = AFMT_QUERY, /* not supported */ + [PA_SAMPLE_S32LE] = AFMT_QUERY, /* not supported */ + [PA_SAMPLE_S32BE] = AFMT_QUERY, /* not supported */ }; pa_assert(fd >= 0); diff --git a/src/pulse/sample.c b/src/pulse/sample.c index ae2a0b9f..27c0df03 100644 --- a/src/pulse/sample.c +++ b/src/pulse/sample.c @@ -44,7 +44,9 @@ size_t pa_sample_size(const pa_sample_spec *spec) { [PA_SAMPLE_S16LE] = 2, [PA_SAMPLE_S16BE] = 2, [PA_SAMPLE_FLOAT32LE] = 4, - [PA_SAMPLE_FLOAT32BE] = 4 + [PA_SAMPLE_FLOAT32BE] = 4, + [PA_SAMPLE_S32LE] = 4, + [PA_SAMPLE_S32BE] = 4, }; pa_assert(spec); @@ -107,6 +109,8 @@ const char *pa_sample_format_to_string(pa_sample_format_t f) { [PA_SAMPLE_S16BE] = "s16be", [PA_SAMPLE_FLOAT32LE] = "float32le", [PA_SAMPLE_FLOAT32BE] = "float32be", + [PA_SAMPLE_S32LE] = "s32le", + [PA_SAMPLE_S32BE] = "s32be", }; if (f < 0 || f >= PA_SAMPLE_MAX) @@ -156,7 +160,7 @@ pa_sample_format_t pa_parse_sample_format(const char *format) { return PA_SAMPLE_S16RE; else if (strcasecmp(format, "u8") == 0 || strcasecmp(format, "8") == 0) return PA_SAMPLE_U8; - else if (strcasecmp(format, "float32") == 0 || strcasecmp(format, "float32ne") == 0) + else if (strcasecmp(format, "float32") == 0 || strcasecmp(format, "float32ne") == 0 || strcasecmp(format, "float") == 0) return PA_SAMPLE_FLOAT32NE; else if (strcasecmp(format, "float32re") == 0) return PA_SAMPLE_FLOAT32RE; @@ -168,6 +172,14 @@ pa_sample_format_t pa_parse_sample_format(const char *format) { return PA_SAMPLE_ULAW; else if (strcasecmp(format, "alaw") == 0) return PA_SAMPLE_ALAW; + else if (strcasecmp(format, "s32le") == 0) + return PA_SAMPLE_S32LE; + else if (strcasecmp(format, "s32be") == 0) + return PA_SAMPLE_S32BE; + else if (strcasecmp(format, "s32ne") == 0 || strcasecmp(format, "s32") == 0 || strcasecmp(format, "32") == 0) + return PA_SAMPLE_S32NE; + else if (strcasecmp(format, "s32re") == 0) + return PA_SAMPLE_S32RE; return -1; } diff --git a/src/pulse/sample.h b/src/pulse/sample.h index b307621e..2c13f57d 100644 --- a/src/pulse/sample.h +++ b/src/pulse/sample.h @@ -42,13 +42,15 @@ * * PulseAudio supports the following sample formats: * - * \li PA_SAMPLE_U8 - Unsigned 8 bit PCM. - * \li PA_SAMPLE_S16LE - Signed 16 bit PCM, little endian. - * \li PA_SAMPLE_S16BE - Signed 16 bit PCM, big endian. + * \li PA_SAMPLE_U8 - Unsigned 8 bit integer PCM. + * \li PA_SAMPLE_S16LE - Signed 16 integer bit PCM, little endian. + * \li PA_SAMPLE_S16BE - Signed 16 integer bit PCM, big endian. * \li PA_SAMPLE_FLOAT32LE - 32 bit IEEE floating point PCM, little endian. * \li PA_SAMPLE_FLOAT32BE - 32 bit IEEE floating point PCM, big endian. * \li PA_SAMPLE_ALAW - 8 bit a-Law. * \li PA_SAMPLE_ULAW - 8 bit mu-Law. + * \li PA_SAMPLE_S32LE - Signed 32 bit integer PCM, little endian. + * \li PA_SAMPLE_S32BE - Signed 32 bit integer PCM, big endian. * * The floating point sample formats have the range from -1 to 1. * @@ -117,6 +119,8 @@ typedef enum pa_sample_format { PA_SAMPLE_S16BE, /**< Signed 16 Bit PCM, big endian */ PA_SAMPLE_FLOAT32LE, /**< 32 Bit IEEE floating point, little endian, range -1 to 1 */ PA_SAMPLE_FLOAT32BE, /**< 32 Bit IEEE floating point, big endian, range -1 to 1 */ + PA_SAMPLE_S32LE, /**< Signed 32 Bit PCM, little endian (PC) */ + PA_SAMPLE_S32BE, /**< Signed 32 Bit PCM, big endian (PC) */ PA_SAMPLE_MAX, /**< Upper limit of valid sample types */ PA_SAMPLE_INVALID = -1 /**< An invalid value */ } pa_sample_format_t; @@ -126,19 +130,27 @@ typedef enum pa_sample_format { #define PA_SAMPLE_S16NE PA_SAMPLE_S16BE /** 32 Bit IEEE floating point, native endian */ #define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32BE +/** Signed 32 Bit PCM, native endian */ +#define PA_SAMPLE_S32NE PA_SAMPLE_S32BE /** Signed 16 Bit PCM reverse endian */ #define PA_SAMPLE_S16RE PA_SAMPLE_S16LE /** 32 Bit IEEE floating point, reverse endian */ #define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32LE +/** Signed 32 Bit PCM reverse endian */ +#define PA_SAMPLE_S32RE PA_SAMPLE_S32LE #else /** Signed 16 Bit PCM, native endian */ #define PA_SAMPLE_S16NE PA_SAMPLE_S16LE /** 32 Bit IEEE floating point, native endian */ #define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32LE +/** Signed 32 Bit PCM, native endian */ +#define PA_SAMPLE_S32NE PA_SAMPLE_S32LE /** Signed 16 Bit PCM reverse endian */ #define PA_SAMPLE_S16RE PA_SAMPLE_S16BE /** 32 Bit IEEE floating point, reverse endian */ #define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32BE +/** Signed 32 Bit PCM reverse endian */ +#define PA_SAMPLE_S32RE PA_SAMPLE_S32BE #endif /** A Shortcut for PA_SAMPLE_FLOAT32NE */ diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index b4447198..eebc9c04 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -240,7 +240,9 @@ pa_resampler* pa_resampler_new( if (r->map_required || a->format != b->format) { - if (a->format == PA_SAMPLE_FLOAT32NE || a->format == PA_SAMPLE_FLOAT32RE || + if (a->format == PA_SAMPLE_S32NE || a->format == PA_SAMPLE_S32RE || + a->format == PA_SAMPLE_FLOAT32NE || a->format == PA_SAMPLE_FLOAT32RE || + b->format == PA_SAMPLE_S32NE || b->format == PA_SAMPLE_S32RE || b->format == PA_SAMPLE_FLOAT32NE || b->format == PA_SAMPLE_FLOAT32RE) r->work_format = PA_SAMPLE_FLOAT32NE; else diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index 21771302..0383b567 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -100,6 +100,8 @@ void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { break; case PA_SAMPLE_S16LE: case PA_SAMPLE_S16BE: + case PA_SAMPLE_S32LE: + case PA_SAMPLE_S32BE: case PA_SAMPLE_FLOAT32: case PA_SAMPLE_FLOAT32RE: c = 0; @@ -380,10 +382,10 @@ void pa_volume_memchunk( t = (int32_t)(*d); t = (t * linear[channel]) / 0x10000; - t = CLAMP(t, -0x8000, 0x7FFF); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); *d = (int16_t) t; - if (++channel >= spec->channels) + if (PA_UNLIKELY(++channel >= spec->channels)) channel = 0; } break; @@ -403,10 +405,57 @@ void pa_volume_memchunk( t = (int32_t)(PA_INT16_SWAP(*d)); t = (t * linear[channel]) / 0x10000; - t = CLAMP(t, -0x8000, 0x7FFF); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); *d = PA_INT16_SWAP((int16_t) t); - if (++channel >= spec->channels) + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + case PA_SAMPLE_S32NE: { + int32_t *d; + size_t n; + unsigned channel; + int32_t linear[PA_CHANNELS_MAX]; + + for (channel = 0; channel < spec->channels; channel++) + linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000); + + for (channel = 0, d = (int32_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int32_t); n > 0; d++, n--) { + int64_t t; + + t = (int64_t)(*d); + t = (t * linear[channel]) / 0x10000; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *d = (int32_t) t; + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + break; + } + + case PA_SAMPLE_S32RE: { + int32_t *d; + size_t n; + unsigned channel; + int32_t linear[PA_CHANNELS_MAX]; + + for (channel = 0; channel < spec->channels; channel++) + linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000); + + for (channel = 0, d = (int32_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int32_t); n > 0; d++, n--) { + int64_t t; + + t = (int64_t)(PA_INT32_SWAP(*d)); + t = (t * linear[channel]) / 0x10000; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *d = PA_INT32_SWAP((int32_t) t); + + if (PA_UNLIKELY(++channel >= spec->channels)) channel = 0; } @@ -427,10 +476,10 @@ void pa_volume_memchunk( t = (int32_t) *d - 0x80; t = (t * linear[channel]) / 0x10000; - t = CLAMP(t, -0x80, 0x7F); + t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F); *d = (uint8_t) (t + 0x80); - if (++channel >= spec->channels) + if (PA_UNLIKELY(++channel >= spec->channels)) channel = 0; } break; diff --git a/src/pulsecore/sconv-s16be.c b/src/pulsecore/sconv-s16be.c index f74d0282..638beb2e 100644 --- a/src/pulsecore/sconv-s16be.c +++ b/src/pulsecore/sconv-s16be.c @@ -30,12 +30,27 @@ #define INT16_FROM PA_INT16_FROM_BE #define INT16_TO PA_INT16_TO_BE +#define INT32_FROM PA_INT32_FROM_BE +#define INT32_TO PA_INT32_TO_BE + #define pa_sconv_s16le_to_float32ne pa_sconv_s16be_to_float32ne #define pa_sconv_s16le_from_float32ne pa_sconv_s16be_from_float32ne #define pa_sconv_s16le_to_float32re pa_sconv_s16be_to_float32re #define pa_sconv_s16le_from_float32re pa_sconv_s16be_from_float32re +#define pa_sconv_s32le_to_float32ne pa_sconv_s32be_to_float32ne +#define pa_sconv_s32le_from_float32ne pa_sconv_s32be_from_float32ne + +#define pa_sconv_s32le_to_float32re pa_sconv_s32be_to_float32re +#define pa_sconv_s32le_from_float32re pa_sconv_s32be_from_float32re + +#define pa_sconv_s32le_to_s16ne pa_sconv_s32be_to_s16ne +#define pa_sconv_s32le_from_s16ne pa_sconv_s32be_from_s16ne + +#define pa_sconv_s32le_to_s16re pa_sconv_s32be_to_s16re +#define pa_sconv_s32le_from_s16re pa_sconv_s32be_from_s16re + #ifdef WORDS_BIGENDIAN #define SWAP_WORDS 0 #else diff --git a/src/pulsecore/sconv-s16be.h b/src/pulsecore/sconv-s16be.h index ad034489..454c9508 100644 --- a/src/pulsecore/sconv-s16be.h +++ b/src/pulsecore/sconv-s16be.h @@ -31,11 +31,31 @@ void pa_sconv_s16be_from_float32ne(unsigned n, const float *a, int16_t *b); void pa_sconv_s16be_to_float32re(unsigned n, const int16_t *a, float *b); void pa_sconv_s16be_from_float32re(unsigned n, const float *a, int16_t *b); +void pa_sconv_s32be_to_float32ne(unsigned n, const int32_t *a, float *b); +void pa_sconv_s32be_from_float32ne(unsigned n, const float *a, int32_t *b); +void pa_sconv_s32be_to_float32re(unsigned n, const int32_t *a, float *b); +void pa_sconv_s32be_from_float32re(unsigned n, const float *a, int32_t *b); + +void pa_sconv_s32be_to_s16ne(unsigned n, const int32_t *a, int16_t *b); +void pa_sconv_s32be_from_s16ne(unsigned n, const int16_t *a, int32_t *b); +void pa_sconv_s32be_to_s16re(unsigned n, const int32_t *a, int16_t *b); +void pa_sconv_s32be_from_s16re(unsigned n, const int16_t *a, int32_t *b); + #ifdef WORDS_BIGENDIAN #define pa_sconv_float32be_to_s16ne pa_sconv_s16be_from_float32ne #define pa_sconv_float32be_from_s16ne pa_sconv_s16be_to_float32ne #define pa_sconv_float32le_to_s16ne pa_sconv_s16be_from_float32re #define pa_sconv_float32le_from_s16ne pa_sconv_s16be_to_float32re + +#define pa_sconv_float32be_to_s32ne pa_sconv_s32be_from_float32ne +#define pa_sconv_float32be_from_s32ne pa_sconv_s32be_to_float32ne +#define pa_sconv_float32le_to_s32ne pa_sconv_s32be_from_float32re +#define pa_sconv_float32le_from_s32ne pa_sconv_s32be_to_float32re + +#define pa_sconv_s16be_to_s32ne pa_sconv_s32be_from_s16ne +#define pa_sconv_s16be_from_s32ne pa_sconv_s32be_to_s16ne +#define pa_sconv_s16le_to_s32ne pa_sconv_s32be_from_s16re +#define pa_sconv_s16le_from_s32ne pa_sconv_s32be_to_s16re #endif #endif diff --git a/src/pulsecore/sconv-s16le.c b/src/pulsecore/sconv-s16le.c index 6925052c..90e9b6d2 100644 --- a/src/pulsecore/sconv-s16le.c +++ b/src/pulsecore/sconv-s16le.c @@ -25,7 +25,10 @@ #include #endif +/* Despite the name of this file we implement S32 handling here, too. */ + #include +#include #include @@ -45,6 +48,14 @@ #define INT16_TO PA_INT16_TO_LE #endif +#ifndef INT32_FROM +#define INT32_FROM PA_INT32_FROM_LE +#endif + +#ifndef INT32_TO +#define INT32_TO PA_INT32_TO_LE +#endif + #ifndef SWAP_WORDS #ifdef WORDS_BIGENDIAN #define SWAP_WORDS 1 @@ -72,6 +83,25 @@ void pa_sconv_s16le_to_float32ne(unsigned n, const int16_t *a, float *b) { #endif } +void pa_sconv_s32le_to_float32ne(unsigned n, const int32_t *a, float *b) { + pa_assert(a); + pa_assert(b); + +#if SWAP_WORDS == 1 + + for (; n > 0; n--) { + int32_t s = *(a++); + *(b++) = (float) (((double) INT32_FROM(s))/0x7FFFFFFF); + } + +#else +{ + static const double add = 0, factor = 1.0/0x7FFFFFFF; + oil_scaleconv_f32_s32(b, a, n, &add, &factor); +} +#endif +} + void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, int16_t *b) { pa_assert(a); pa_assert(b); @@ -82,7 +112,7 @@ void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, int16_t *b) { int16_t s; float v = *(a++); - v = CLAMP(v, -1, 1); + v = PA_CLAMP_UNLIKELY(v, -1, 1); s = (int16_t) (v * 0x7FFF); *(b++) = INT16_TO(s); } @@ -95,6 +125,29 @@ void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, int16_t *b) { #endif } +void pa_sconv_s32le_from_float32ne(unsigned n, const float *a, int32_t *b) { + pa_assert(a); + pa_assert(b); + +#if SWAP_WORDS == 1 + + for (; n > 0; n--) { + int32_t s; + float v = *(a++); + + v = PA_CLAMP_UNLIKELY(v, -1, 1); + s = (int32_t) ((double) v * (double) 0x7FFFFFFF); + *(b++) = INT32_TO(s); + } + +#else +{ + static const double add = 0, factor = 0x7FFFFFFF; + oil_scaleconv_s32_f32(b, a, n, &add, &factor); +} +#endif +} + void pa_sconv_s16le_to_float32re(unsigned n, const int16_t *a, float *b) { pa_assert(a); pa_assert(b); @@ -108,6 +161,19 @@ void pa_sconv_s16le_to_float32re(unsigned n, const int16_t *a, float *b) { } } +void pa_sconv_s32le_to_float32re(unsigned n, const int32_t *a, float *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--) { + int32_t s = *(a++); + float k = (float) (((double) INT32_FROM(s))/0x7FFFFFFF); + uint32_t *j = (uint32_t*) &k; + *j = PA_UINT32_SWAP(*j); + *(b++) = k; + } +} + void pa_sconv_s16le_from_float32re(unsigned n, const float *a, int16_t *b) { pa_assert(a); pa_assert(b); @@ -117,8 +183,69 @@ void pa_sconv_s16le_from_float32re(unsigned n, const float *a, int16_t *b) { float v = *(a++); uint32_t *j = (uint32_t*) &v; *j = PA_UINT32_SWAP(*j); - v = CLAMP(v, -1, 1); + v = PA_CLAMP_UNLIKELY(v, -1, 1); s = (int16_t) (v * 0x7FFF); *(b++) = INT16_TO(s); } } + +void pa_sconv_s32le_from_float32re(unsigned n, const float *a, int32_t *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--) { + int32_t s; + float v = *(a++); + uint32_t *j = (uint32_t*) &v; + *j = PA_UINT32_SWAP(*j); + v = PA_CLAMP_UNLIKELY(v, -1, 1); + s = (int32_t) ((double) v * 0x7FFFFFFF); + *(b++) = INT32_TO(s); + } +} + +void pa_sconv_s32le_to_s16ne(unsigned n, const int32_t*a, int16_t *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--) { + *b = (int16_t) (INT32_FROM(*a) >> 16); + a++; + b++; + } +} + +void pa_sconv_s32le_to_s16re(unsigned n, const int32_t*a, int16_t *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--) { + int16_t s = (int16_t) (INT32_FROM(*a) >> 16); + *b = PA_UINT32_SWAP(s); + a++; + b++; + } +} + +void pa_sconv_s32le_from_s16ne(unsigned n, const int16_t *a, int32_t *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--) { + *b = INT32_TO(((int32_t) *a) << 16); + a++; + b++; + } +} + +void pa_sconv_s32le_from_s16re(unsigned n, const int16_t *a, int32_t *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--) { + int32_t s = ((int32_t) PA_UINT16_SWAP(*a)) << 16; + *b = INT32_TO(s); + a++; + b++; + } +} diff --git a/src/pulsecore/sconv-s16le.h b/src/pulsecore/sconv-s16le.h index 4203315a..4165f8a2 100644 --- a/src/pulsecore/sconv-s16le.h +++ b/src/pulsecore/sconv-s16le.h @@ -31,11 +31,31 @@ void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, int16_t *b); void pa_sconv_s16le_to_float32re(unsigned n, const int16_t *a, float *b); void pa_sconv_s16le_from_float32re(unsigned n, const float *a, int16_t *b); +void pa_sconv_s32le_to_float32ne(unsigned n, const int32_t *a, float *b); +void pa_sconv_s32le_from_float32ne(unsigned n, const float *a, int32_t *b); +void pa_sconv_s32le_to_float32re(unsigned n, const int32_t *a, float *b); +void pa_sconv_s32le_from_float32re(unsigned n, const float *a, int32_t *b); + +void pa_sconv_s32le_to_s16ne(unsigned n, const int32_t *a, int16_t *b); +void pa_sconv_s32le_from_s16ne(unsigned n, const int16_t *a, int32_t *b); +void pa_sconv_s32le_to_s16re(unsigned n, const int32_t *a, int16_t *b); +void pa_sconv_s32le_from_s16re(unsigned n, const int16_t *a, int32_t *b); + #ifndef WORDS_BIGENDIAN #define pa_sconv_float32be_to_s16ne pa_sconv_s16le_from_float32re #define pa_sconv_float32be_from_s16ne pa_sconv_s16le_to_float32re #define pa_sconv_float32le_to_s16ne pa_sconv_s16le_from_float32ne #define pa_sconv_float32le_from_s16ne pa_sconv_s16le_to_float32ne + +#define pa_sconv_float32be_to_s32ne pa_sconv_s32le_from_float32re +#define pa_sconv_float32be_from_s32ne pa_sconv_s32le_to_float32re +#define pa_sconv_float32le_to_s32ne pa_sconv_s32le_from_float32ne +#define pa_sconv_float32le_from_s32ne pa_sconv_s32le_to_float32ne + +#define pa_sconv_s16be_to_s32ne pa_sconv_s32le_from_s16re +#define pa_sconv_s16be_from_s32ne pa_sconv_s32le_to_s16re +#define pa_sconv_s16le_to_s32ne pa_sconv_s32le_from_s16ne +#define pa_sconv_s16le_from_s32ne pa_sconv_s32le_to_s16ne #endif #endif diff --git a/src/pulsecore/sconv.c b/src/pulsecore/sconv.c index 7f5da63f..8a3e830a 100644 --- a/src/pulsecore/sconv.c +++ b/src/pulsecore/sconv.c @@ -198,6 +198,8 @@ pa_convert_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f) { [PA_SAMPLE_ULAW] = (pa_convert_func_t) ulaw_to_float32ne, [PA_SAMPLE_S16LE] = (pa_convert_func_t) pa_sconv_s16le_to_float32ne, [PA_SAMPLE_S16BE] = (pa_convert_func_t) pa_sconv_s16be_to_float32ne, + [PA_SAMPLE_S32LE] = (pa_convert_func_t) pa_sconv_s32le_to_float32ne, + [PA_SAMPLE_S32BE] = (pa_convert_func_t) pa_sconv_s32be_to_float32ne, [PA_SAMPLE_FLOAT32NE] = (pa_convert_func_t) float32ne_to_float32ne, [PA_SAMPLE_FLOAT32RE] = (pa_convert_func_t) float32re_to_float32ne, }; @@ -214,6 +216,8 @@ pa_convert_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f) { [PA_SAMPLE_U8] = (pa_convert_func_t) u8_from_float32ne, [PA_SAMPLE_S16LE] = (pa_convert_func_t) pa_sconv_s16le_from_float32ne, [PA_SAMPLE_S16BE] = (pa_convert_func_t) pa_sconv_s16be_from_float32ne, + [PA_SAMPLE_S32LE] = (pa_convert_func_t) pa_sconv_s32le_from_float32ne, + [PA_SAMPLE_S32BE] = (pa_convert_func_t) pa_sconv_s32be_from_float32ne, [PA_SAMPLE_FLOAT32NE] = (pa_convert_func_t) float32ne_to_float32ne, [PA_SAMPLE_FLOAT32RE] = (pa_convert_func_t) float32re_to_float32ne, [PA_SAMPLE_ALAW] = (pa_convert_func_t) alaw_from_float32ne, @@ -234,6 +238,8 @@ pa_convert_func_t pa_get_convert_to_s16ne_function(pa_sample_format_t f) { [PA_SAMPLE_S16RE] = (pa_convert_func_t) s16re_to_s16ne, [PA_SAMPLE_FLOAT32BE] = (pa_convert_func_t) pa_sconv_float32be_to_s16ne, [PA_SAMPLE_FLOAT32LE] = (pa_convert_func_t) pa_sconv_float32le_to_s16ne, + [PA_SAMPLE_S32BE] = (pa_convert_func_t) pa_sconv_s32be_to_s16ne, + [PA_SAMPLE_S32LE] = (pa_convert_func_t) pa_sconv_s32le_to_s16ne, [PA_SAMPLE_ALAW] = (pa_convert_func_t) alaw_to_s16ne, [PA_SAMPLE_ULAW] = (pa_convert_func_t) ulaw_to_s16ne }; @@ -252,6 +258,8 @@ pa_convert_func_t pa_get_convert_from_s16ne_function(pa_sample_format_t f) { [PA_SAMPLE_S16RE] = (pa_convert_func_t) s16re_to_s16ne, [PA_SAMPLE_FLOAT32BE] = (pa_convert_func_t) pa_sconv_float32be_from_s16ne, [PA_SAMPLE_FLOAT32LE] = (pa_convert_func_t) pa_sconv_float32le_from_s16ne, + [PA_SAMPLE_S32BE] = (pa_convert_func_t) pa_sconv_s32be_from_s16ne, + [PA_SAMPLE_S32LE] = (pa_convert_func_t) pa_sconv_s32le_from_s16ne, [PA_SAMPLE_ALAW] = (pa_convert_func_t) alaw_from_s16ne, [PA_SAMPLE_ULAW] = (pa_convert_func_t) ulaw_from_s16ne, }; diff --git a/src/tests/resampler-test.c b/src/tests/resampler-test.c index 3b4a7386..5295995b 100644 --- a/src/tests/resampler-test.c +++ b/src/tests/resampler-test.c @@ -71,6 +71,16 @@ static void dump_block(const pa_sample_spec *ss, const pa_memchunk *chunk) { break; } + case PA_SAMPLE_S32NE: + case PA_SAMPLE_S32RE: { + uint32_t *u = d; + + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) + printf("0x%08x ", *(u++)); + + break; + } + case PA_SAMPLE_FLOAT32NE: case PA_SAMPLE_FLOAT32RE: { float *u = d; @@ -137,6 +147,23 @@ static pa_memblock* generate_block(pa_mempool *pool, const pa_sample_spec *ss) { break; } + case PA_SAMPLE_S32NE: + case PA_SAMPLE_S32RE: { + uint32_t *u = d; + + u[0] = 0x00000001; + u[1] = 0xFFFF0002; + u[2] = 0x7FFF0003; + u[3] = 0x80000004; + u[4] = 0x9fff0005; + u[5] = 0x3fff0006; + u[6] = 0x10007; + u[7] = 0xF0000008; + u[8] = 0x200009; + u[9] = 0x21000A; + break; + } + case PA_SAMPLE_FLOAT32NE: case PA_SAMPLE_FLOAT32RE: { float *u = d; -- cgit From 7bd3c0396dd0ebc7e312f5acbc02f5815eeeebc1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 9 Nov 2007 14:14:29 +0000 Subject: .la files for modules can probably be removed safely on all archs now git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2038 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Makefile.am b/src/Makefile.am index 91e22dfe..024988ba 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1447,6 +1447,7 @@ install-exec-hook: rm -f $(DESTDIR)$(modlibexecdir)/*.a rm -f $(DESTDIR)$(libdir)/libpulsedsp.a rm -f $(DESTDIR)$(libdir)/libpulsedsp.la + rm -f $(DESTDIR)$(modlibexecdir)/*.la massif: pulseaudio libtool --mode=execute valgrind --tool=massif --depth=6 --alloc-fn=pa_xmalloc --alloc-fn=pa_xmalloc0 --alloc-fn=pa_xrealloc --alloc-fn=dbus_realloc --alloc-fn=pa_xnew0_internal --alloc-fn=pa_xnew_internal ./pulseaudio -- cgit From 01490319d38c2f90749f9b7b555f332e2e7f3da9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 9 Nov 2007 14:19:40 +0000 Subject: remove PA_CLAMP_LIKELY macro because it doesn't really make sense. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2039 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/macro.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/macro.h b/src/pulsecore/macro.h index 98e023aa..4b62dd21 100644 --- a/src/pulsecore/macro.h +++ b/src/pulsecore/macro.h @@ -77,8 +77,10 @@ static inline size_t pa_page_align(size_t l) { #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) #endif -#define PA_CLAMP_LIKELY(x, low, high) (PA_LIKELY((x) > (high)) ? (high) : (PA_LIKELY((x)<(low)) ? (low) : (x))) #define PA_CLAMP_UNLIKELY(x, low, high) (PA_UNLIKELY((x) > (high)) ? (high) : (PA_UNLIKELY((x) < (low)) ? (low) : (x))) +/* We don't define a PA_CLAMP_LIKELY here, because it doesn't really + * make sense: we cannot know if it is more likely that the values is + * lower or greater than the boundaries.*/ /* This type is not intended to be used in exported APIs! Use classic "int" there! */ #ifdef HAVE_STD_BOOL -- cgit From c1985c2acc43f5d2c23e1e736588c5ef3a398a17 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 9 Nov 2007 14:20:12 +0000 Subject: replace a few CLAMPs by PA_CLAMP_UNLIKELY git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2040 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-ladspa-sink.c | 4 ++-- src/pulsecore/sample-util.c | 6 +++--- src/pulsecore/sconv.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c index 0265d971..6ed392ce 100644 --- a/src/modules/module-ladspa-sink.c +++ b/src/modules/module-ladspa-sink.c @@ -177,14 +177,14 @@ static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chun p = src + c; q = u->input; for (j = 0; j < n; j++, p += u->channels, q++) - *q = CLAMP(*p, -1.0, 1.0); + *q = PA_CLAMP_UNLIKELY(*p, -1.0, 1.0); u->descriptor->run(u->handle[c], n); q = u->output; p = dst + c; for (j = 0; j < n; j++, q++, p += u->channels) - *p = CLAMP(*q, -1.0, 1.0); + *p = PA_CLAMP_UNLIKELY(*q, -1.0, 1.0); } pa_memblock_release(tchunk.memblock); diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index 0383b567..001a997e 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -178,7 +178,7 @@ size_t pa_mix( if (volume->values[channel] != PA_VOLUME_NORM) sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); - sum = CLAMP(sum, -0x8000, 0x7FFF); + sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); } *((int16_t*) data) = (int16_t) sum; @@ -225,7 +225,7 @@ size_t pa_mix( if (volume->values[channel] != PA_VOLUME_NORM) sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); - sum = CLAMP(sum, -0x8000, 0x7FFF); + sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); } *((int16_t*) data) = PA_INT16_SWAP((int16_t) sum); @@ -272,7 +272,7 @@ size_t pa_mix( if (volume->values[channel] != PA_VOLUME_NORM) sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); - sum = CLAMP(sum, -0x80, 0x7F); + sum = PA_CLAMP_UNLIKELY(sum, -0x80, 0x7F); } *((uint8_t*) data) = (uint8_t) (sum + 0x80); diff --git a/src/pulsecore/sconv.c b/src/pulsecore/sconv.c index 8a3e830a..ebd74586 100644 --- a/src/pulsecore/sconv.c +++ b/src/pulsecore/sconv.c @@ -130,7 +130,7 @@ static void ulaw_from_float32ne(unsigned n, const float *a, uint8_t *b) { for (; n > 0; n--) { float v = *(a++); - v = CLAMP(v, -1, 1); + v = PA_CLAMP_UNLIKELY(v, -1, 1); v *= 0x1FFF; *(b++) = st_14linear2ulaw((int16_t) v); } @@ -168,7 +168,7 @@ static void alaw_from_float32ne(unsigned n, const float *a, uint8_t *b) { for (; n > 0; n--, a++, b++) { float v = *a; - v = CLAMP(v, -1, 1); + v = PA_CLAMP_UNLIKELY(v, -1, 1); v *= 0xFFF; *b = st_13linear2alaw((int16_t) v); } -- cgit From b0a68fd09ff6fa62accdc29307c5f445cc054a94 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 9 Nov 2007 17:11:45 +0000 Subject: optimize mixing code a bit. Add mixers for S32LE, S32BE, ULAW, ALAW and FLOAT32BE. Add volume adjusters for FLOAT32BE, ALAW, ULAW. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2041 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 8 +- src/pulsecore/sample-util.c | 560 +++++++++++++++++++++++++++++++++++--------- src/pulsecore/sample-util.h | 11 +- src/tests/mix-test.c | 261 +++++++++++++++++++++ 4 files changed, 727 insertions(+), 113 deletions(-) create mode 100644 src/tests/mix-test.c diff --git a/src/Makefile.am b/src/Makefile.am index 024988ba..8fe7be9d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -239,7 +239,8 @@ noinst_PROGRAMS = \ rtpoll-test \ sig2str-test \ resampler-test \ - smoother-test + smoother-test \ + mix-test if HAVE_SIGXCPU noinst_PROGRAMS += \ @@ -389,6 +390,11 @@ resampler_test_LDADD = $(AM_LDADD) libpulsecore.la resampler_test_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) resampler_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS) +mix_test_SOURCES = tests/mix-test.c +mix_test_LDADD = $(AM_LDADD) libpulsecore.la +mix_test_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) +mix_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS) + smoother_test_SOURCES = tests/smoother-test.c smoother_test_LDADD = $(AM_LDADD) libpulsecore.la smoother_test_CFLAGS = $(AM_CFLAGS) diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index 001a997e..4ea5d446 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -35,6 +35,7 @@ #include #include +#include #include "sample-util.h" #include "endianmacros.h" @@ -119,6 +120,58 @@ void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { memset(p, c, length); } +static void calc_linear_integer_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_sample_spec *spec) { + unsigned k; + + pa_assert(streams); + pa_assert(spec); + + for (k = 0; k < nstreams; k++) { + unsigned channel; + + for (channel = 0; channel < spec->channels; channel++) { + pa_mix_info *m = streams + k; + m->linear[channel].i = (int32_t) (pa_sw_volume_to_linear(m->volume.values[channel]) * 0x10000); + } + } +} + +static void calc_linear_integer_volume(int32_t linear[], const pa_cvolume *volume) { + unsigned channel; + + pa_assert(linear); + pa_assert(volume); + + for (channel = 0; channel < volume->channels; channel++) + linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000); +} + +static void calc_linear_float_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_sample_spec *spec) { + unsigned k; + + pa_assert(streams); + pa_assert(spec); + + for (k = 0; k < nstreams; k++) { + unsigned channel; + + for (channel = 0; channel < spec->channels; channel++) { + pa_mix_info *m = streams + k; + m->linear[channel].f = pa_sw_volume_to_linear(m->volume.values[channel]); + } + } +} + +static void calc_linear_float_volume(float linear[], const pa_cvolume *volume) { + unsigned channel; + + pa_assert(linear); + pa_assert(volume); + + for (channel = 0; channel < volume->channels; channel++) + linear[channel] = pa_sw_volume_to_linear(volume->values[channel]); +} + size_t pa_mix( pa_mix_info streams[], unsigned nstreams, @@ -126,11 +179,11 @@ size_t pa_mix( size_t length, const pa_sample_spec *spec, const pa_cvolume *volume, - int mute) { + pa_bool_t mute) { pa_cvolume full_volume; - size_t d = 0; unsigned k; + size_t d = 0; pa_assert(streams); pa_assert(data); @@ -141,50 +194,49 @@ size_t pa_mix( volume = pa_cvolume_reset(&full_volume, spec->channels); for (k = 0; k < nstreams; k++) - streams[k].internal = pa_memblock_acquire(streams[k].chunk.memblock); + streams[k].ptr = (uint8_t*) pa_memblock_acquire(streams[k].chunk.memblock) + streams[k].chunk.index; switch (spec->format) { + case PA_SAMPLE_S16NE:{ unsigned channel = 0; + int32_t linear[PA_CHANNELS_MAX]; + + calc_linear_integer_stream_volumes(streams, nstreams, spec); + calc_linear_integer_volume(linear, volume); for (d = 0;; d += sizeof(int16_t)) { int32_t sum = 0; + unsigned i; - if (d >= length) + if (PA_UNLIKELY(d >= length)) goto finish; - if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { - unsigned i; - - for (i = 0; i < nstreams; i++) { - int32_t v; - pa_volume_t cvolume = streams[i].volume.values[channel]; - - if (d >= streams[i].chunk.length) - goto finish; - - if (cvolume == PA_VOLUME_MUTED) - v = 0; - else { - v = *((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d)); + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int32_t v, cv = m->linear[channel].i; - if (cvolume != PA_VOLUME_NORM) - v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); - } + if (PA_UNLIKELY(d >= m->chunk.length)) + goto finish; - sum += v; + if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0)) + v = 0; + else { + v = *((int16_t*) m->ptr); + v = (v * cv) / 0x10000; } - if (volume->values[channel] != PA_VOLUME_NORM) - sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); - - sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); + sum += v; + m->ptr = (uint8_t*) m->ptr + sizeof(int16_t); } + sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); + sum = (sum * linear[channel]) / 0x10000; *((int16_t*) data) = (int16_t) sum; + data = (uint8_t*) data + sizeof(int16_t); - if (++channel >= spec->channels) + if (PA_UNLIKELY(++channel >= spec->channels)) channel = 0; } @@ -193,45 +245,135 @@ size_t pa_mix( case PA_SAMPLE_S16RE:{ unsigned channel = 0; + int32_t linear[PA_CHANNELS_MAX]; + + calc_linear_integer_stream_volumes(streams, nstreams, spec); + calc_linear_integer_volume(linear, volume); for (d = 0;; d += sizeof(int16_t)) { int32_t sum = 0; + unsigned i; - if (d >= length) + if (PA_UNLIKELY(d >= length)) goto finish; - if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { - unsigned i; + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int32_t v, cv = m->linear[channel].i; + + if (PA_UNLIKELY(d >= m->chunk.length)) + goto finish; + + if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0)) + v = 0; + else { + v = PA_INT16_SWAP(*((int16_t*) m->ptr)); + v = (v * cv) / 0x10000; + } + + sum += v; + m->ptr = (uint8_t*) m->ptr + sizeof(int16_t); + } + + sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); + sum = (sum * linear[channel]) / 0x10000; + *((int16_t*) data) = PA_INT16_SWAP((int16_t) sum); + + data = (uint8_t*) data + sizeof(int16_t); + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + case PA_SAMPLE_S32NE:{ + unsigned channel = 0; + int32_t linear[PA_CHANNELS_MAX]; + + calc_linear_integer_stream_volumes(streams, nstreams, spec); + calc_linear_integer_volume(linear, volume); - for (i = 0; i < nstreams; i++) { - int32_t v; - pa_volume_t cvolume = streams[i].volume.values[channel]; + for (d = 0;; d += sizeof(int32_t)) { + int64_t sum = 0; + unsigned i; - if (d >= streams[i].chunk.length) - goto finish; + if (PA_UNLIKELY(d >= length)) + goto finish; - if (cvolume == PA_VOLUME_MUTED) - v = 0; - else { - v = PA_INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d))); + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int64_t v; + int32_t cv = m->linear[channel].i; - if (cvolume != PA_VOLUME_NORM) - v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); - } + if (PA_UNLIKELY(d >= m->chunk.length)) + goto finish; - sum += v; + if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0)) + v = 0; + else { + v = *((int32_t*) m->ptr); + v = (v * cv) / 0x10000; } - if (volume->values[channel] != PA_VOLUME_NORM) - sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); + sum += v; + m->ptr = (uint8_t*) m->ptr + sizeof(int32_t); + } + + sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL); + sum = (sum * linear[channel]) / 0x10000; + *((int32_t*) data) = (int32_t) sum; + + data = (uint8_t*) data + sizeof(int32_t); + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + case PA_SAMPLE_S32RE:{ + unsigned channel = 0; + int32_t linear[PA_CHANNELS_MAX]; + + calc_linear_integer_stream_volumes(streams, nstreams, spec); + calc_linear_integer_volume(linear, volume); + + for (d = 0;; d += sizeof(int32_t)) { + int64_t sum = 0; + unsigned i; + + if (PA_UNLIKELY(d >= length)) + goto finish; + + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int64_t v; + int32_t cv = m->linear[channel].i; + + if (PA_UNLIKELY(d >= m->chunk.length)) + goto finish; + + if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0)) + v = 0; + else { + v = PA_INT32_SWAP(*((int32_t*) m->ptr)); + v = (v * cv) / 0x10000; + } - sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); + sum += v; + m->ptr = (uint8_t*) m->ptr + sizeof(int32_t); } - *((int16_t*) data) = PA_INT16_SWAP((int16_t) sum); - data = (uint8_t*) data + sizeof(int16_t); + sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL); + sum = (sum * linear[channel]) / 0x10000; + *((int32_t*) data) = PA_INT32_SWAP((int32_t) sum); + + data = (uint8_t*) data + sizeof(int32_t); - if (++channel >= spec->channels) + if (PA_UNLIKELY(++channel >= spec->channels)) channel = 0; } @@ -240,45 +382,133 @@ size_t pa_mix( case PA_SAMPLE_U8: { unsigned channel = 0; + int32_t linear[PA_CHANNELS_MAX]; + + calc_linear_integer_stream_volumes(streams, nstreams, spec); + calc_linear_integer_volume(linear, volume); for (d = 0;; d ++) { int32_t sum = 0; + unsigned i; - if (d >= length) + if (PA_UNLIKELY(d >= length)) goto finish; - if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { - unsigned i; + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int32_t v, cv = m->linear[channel].i; + + if (PA_UNLIKELY(d >= m->chunk.length)) + goto finish; + + if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0)) + v = 0; + else { + v = (int32_t) *((uint8_t*) m->ptr) - 0x80; + v = (v * cv) / 0x10000; + } + + sum += v; + m->ptr = (uint8_t*) m->ptr + 1; + } + + sum = (sum * linear[channel]) / 0x10000; + sum = PA_CLAMP_UNLIKELY(sum, -0x80, 0x7F); + *((uint8_t*) data) = (uint8_t) (sum + 0x80); + + data = (uint8_t*) data + 1; + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + case PA_SAMPLE_ULAW: { + unsigned channel = 0; + int32_t linear[PA_CHANNELS_MAX]; - for (i = 0; i < nstreams; i++) { - int32_t v; - pa_volume_t cvolume = streams[i].volume.values[channel]; + calc_linear_integer_stream_volumes(streams, nstreams, spec); + calc_linear_integer_volume(linear, volume); - if (d >= streams[i].chunk.length) - goto finish; + for (d = 0;; d ++) { + int32_t sum = 0; + unsigned i; - if (cvolume == PA_VOLUME_MUTED) - v = 0; - else { - v = (int32_t) *((uint8_t*) streams[i].internal + streams[i].chunk.index + d) - 0x80; + if (PA_UNLIKELY(d >= length)) + goto finish; + + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int32_t v, cv = m->linear[channel].i; - if (cvolume != PA_VOLUME_NORM) - v = (int32_t) (v * pa_sw_volume_to_linear(cvolume)); - } + if (PA_UNLIKELY(d >= m->chunk.length)) + goto finish; - sum += v; + if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0)) + v = 0; + else { + v = (int32_t) st_ulaw2linear16(*((uint8_t*) m->ptr)); + v = (v * cv) / 0x10000; } - if (volume->values[channel] != PA_VOLUME_NORM) - sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel])); + sum += v; + m->ptr = (uint8_t*) m->ptr + 1; + } + + sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); + sum = (sum * linear[channel]) / 0x10000; + *((uint8_t*) data) = (uint8_t) st_14linear2ulaw(sum >> 2); + + data = (uint8_t*) data + 1; + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + case PA_SAMPLE_ALAW: { + unsigned channel = 0; + int32_t linear[PA_CHANNELS_MAX]; + + calc_linear_integer_stream_volumes(streams, nstreams, spec); + calc_linear_integer_volume(linear, volume); + + for (d = 0;; d ++) { + int32_t sum = 0; + unsigned i; + + if (PA_UNLIKELY(d >= length)) + goto finish; + + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int32_t v, cv = m->linear[channel].i; - sum = PA_CLAMP_UNLIKELY(sum, -0x80, 0x7F); + if (PA_UNLIKELY(d >= m->chunk.length)) + goto finish; + + if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0)) + v = 0; + else { + v = (int32_t) st_alaw2linear16(*((uint8_t*) m->ptr)); + v = (v * cv) / 0x10000; + } + + sum += v; + m->ptr = (uint8_t*) m->ptr + 1; } - *((uint8_t*) data) = (uint8_t) (sum + 0x80); + sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); + sum = (sum * linear[channel]) / 0x10000; + *((uint8_t*) data) = (uint8_t) st_13linear2alaw(sum >> 3); + data = (uint8_t*) data + 1; - if (++channel >= spec->channels) + if (PA_UNLIKELY(++channel >= spec->channels)) channel = 0; } @@ -287,43 +517,88 @@ size_t pa_mix( case PA_SAMPLE_FLOAT32NE: { unsigned channel = 0; + float linear[PA_CHANNELS_MAX]; + + calc_linear_float_stream_volumes(streams, nstreams, spec); + calc_linear_float_volume(linear, volume); for (d = 0;; d += sizeof(float)) { float sum = 0; + unsigned i; - if (d >= length) + if (PA_UNLIKELY(d >= length)) goto finish; - if (!mute && volume->values[channel] != PA_VOLUME_MUTED) { - unsigned i; + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + float v, cv = m->linear[channel].f; + + if (PA_UNLIKELY(d >= m->chunk.length)) + goto finish; + + if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0)) + v = 0; + else { + v = *((float*) m->ptr); + v *= cv; + } + + sum += v; + m->ptr = (uint8_t*) m->ptr + sizeof(float); + } + + sum *= linear[channel]; + *((float*) data) = sum; - for (i = 0; i < nstreams; i++) { - float v; - pa_volume_t cvolume = streams[i].volume.values[channel]; + data = (uint8_t*) data + sizeof(float); + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + case PA_SAMPLE_FLOAT32RE: { + unsigned channel = 0; + float linear[PA_CHANNELS_MAX]; + + calc_linear_float_stream_volumes(streams, nstreams, spec); + calc_linear_float_volume(linear, volume); + + for (d = 0;; d += sizeof(float)) { + float sum = 0; + unsigned i; - if (d >= streams[i].chunk.length) - goto finish; + if (PA_UNLIKELY(d >= length)) + goto finish; - if (cvolume == PA_VOLUME_MUTED) - v = 0; - else { - v = *((float*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d)); + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + float v, cv = m->linear[channel].f; - if (cvolume != PA_VOLUME_NORM) - v *= pa_sw_volume_to_linear(cvolume); - } + if (PA_UNLIKELY(d >= m->chunk.length)) + goto finish; - sum += v; + if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0)) + v = 0; + else { + uint32_t z = *(uint32_t*) m->ptr; + z = PA_UINT32_SWAP(z); + v = *((float*) &z); + v *= cv; } - if (volume->values[channel] != PA_VOLUME_NORM) - sum *= pa_sw_volume_to_linear(volume->values[channel]); + sum += v; + m->ptr = (uint8_t*) m->ptr + sizeof(float); } - *((float*) data) = sum; + sum *= linear[channel]; + *((uint32_t*) data) = PA_UINT32_SWAP(*(uint32_t*) &sum); + data = (uint8_t*) data + sizeof(float); - if (++channel >= spec->channels) + if (PA_UNLIKELY(++channel >= spec->channels)) channel = 0; } @@ -332,7 +607,7 @@ size_t pa_mix( default: pa_log_error("ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format)); - abort(); + pa_assert_not_reached(); } finish: @@ -364,7 +639,7 @@ void pa_volume_memchunk( return; } - ptr = pa_memblock_acquire(c->memblock); + ptr = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index; switch (spec->format) { @@ -374,10 +649,9 @@ void pa_volume_memchunk( unsigned channel; int32_t linear[PA_CHANNELS_MAX]; - for (channel = 0; channel < spec->channels; channel++) - linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000); + calc_linear_integer_volume(linear, volume); - for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { + for (channel = 0, d = ptr, n = c->length/sizeof(int16_t); n > 0; d++, n--) { int32_t t; t = (int32_t)(*d); @@ -397,10 +671,9 @@ void pa_volume_memchunk( unsigned channel; int32_t linear[PA_CHANNELS_MAX]; - for (channel = 0; channel < spec->channels; channel++) - linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000); + calc_linear_integer_volume(linear, volume); - for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { + for (channel = 0, d = ptr, n = c->length/sizeof(int16_t); n > 0; d++, n--) { int32_t t; t = (int32_t)(PA_INT16_SWAP(*d)); @@ -421,10 +694,9 @@ void pa_volume_memchunk( unsigned channel; int32_t linear[PA_CHANNELS_MAX]; - for (channel = 0; channel < spec->channels; channel++) - linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000); + calc_linear_integer_volume(linear, volume); - for (channel = 0, d = (int32_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int32_t); n > 0; d++, n--) { + for (channel = 0, d = ptr, n = c->length/sizeof(int32_t); n > 0; d++, n--) { int64_t t; t = (int64_t)(*d); @@ -444,10 +716,9 @@ void pa_volume_memchunk( unsigned channel; int32_t linear[PA_CHANNELS_MAX]; - for (channel = 0; channel < spec->channels; channel++) - linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000); + calc_linear_integer_volume(linear, volume); - for (channel = 0, d = (int32_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int32_t); n > 0; d++, n--) { + for (channel = 0, d = ptr, n = c->length/sizeof(int32_t); n > 0; d++, n--) { int64_t t; t = (int64_t)(PA_INT32_SWAP(*d)); @@ -468,10 +739,9 @@ void pa_volume_memchunk( unsigned channel; int32_t linear[PA_CHANNELS_MAX]; - for (channel = 0; channel < spec->channels; channel++) - linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000); + calc_linear_integer_volume(linear, volume); - for (channel = 0, d = (uint8_t*) ptr + c->index, n = c->length; n > 0; d++, n--) { + for (channel = 0, d = ptr, n = c->length; n > 0; d++, n--) { int32_t t; t = (int32_t) *d - 0x80; @@ -485,20 +755,64 @@ void pa_volume_memchunk( break; } + case PA_SAMPLE_ULAW: { + uint8_t *d; + size_t n; + unsigned channel; + int32_t linear[PA_CHANNELS_MAX]; + + calc_linear_integer_volume(linear, volume); + + for (channel = 0, d = ptr, n = c->length; n > 0; d++, n--) { + int32_t t; + + t = (int32_t) st_ulaw2linear16(*d); + t = (t * linear[channel]) / 0x10000; + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *d = (uint8_t) st_14linear2ulaw(t >> 2); + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + break; + } + + case PA_SAMPLE_ALAW: { + uint8_t *d; + size_t n; + unsigned channel; + int32_t linear[PA_CHANNELS_MAX]; + + calc_linear_integer_volume(linear, volume); + + for (channel = 0, d = ptr, n = c->length; n > 0; d++, n--) { + int32_t t; + + t = (int32_t) st_alaw2linear16(*d); + t = (t * linear[channel]) / 0x10000; + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *d = (uint8_t) st_13linear2alaw(t >> 3); + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + break; + } + case PA_SAMPLE_FLOAT32NE: { float *d; int skip; unsigned n; unsigned channel; - d = (float*) ((uint8_t*) ptr + c->index); + d = ptr; skip = spec->channels * sizeof(float); n = c->length/sizeof(float)/spec->channels; - for (channel = 0; channel < spec->channels ; channel ++) { + for (channel = 0; channel < spec->channels; channel ++) { float v, *t; - if (volume->values[channel] == PA_VOLUME_NORM) + if (PA_UNLIKELY(volume->values[channel] == PA_VOLUME_NORM)) continue; v = (float) pa_sw_volume_to_linear(volume->values[channel]); @@ -508,6 +822,32 @@ void pa_volume_memchunk( break; } + case PA_SAMPLE_FLOAT32RE: { + uint32_t *d; + size_t n; + unsigned channel; + float linear[PA_CHANNELS_MAX]; + + calc_linear_float_volume(linear, volume); + + for (channel = 0, d = ptr, n = c->length/sizeof(float); n > 0; d++, n--) { + float t; + uint32_t z; + + z = PA_UINT32_SWAP(*d); + t = *(float*) &z; + t *= linear[channel]; + z = *(uint32_t*) &t; + *d = PA_UINT32_SWAP(z); + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + default: pa_log_warn(" Unable to change volume of format %s.", pa_sample_format_to_string(spec->format)); /* If we cannot change the volume, we just don't do it */ diff --git a/src/pulsecore/sample-util.h b/src/pulsecore/sample-util.h index 0a39d5ca..2ef8f924 100644 --- a/src/pulsecore/sample-util.h +++ b/src/pulsecore/sample-util.h @@ -39,7 +39,14 @@ typedef struct pa_mix_info { pa_memchunk chunk; pa_cvolume volume; void *userdata; - void *internal; /* Used internally by pa_mix(), should not be initialised when calling pa_mix() */ + + /* The following fields are used internally by pa_mix(), should + * not be initialised by the caller of pa_mix(). */ + void *ptr; + union { + int32_t i; + float f; + } linear[PA_CHANNELS_MAX]; } pa_mix_info; size_t pa_mix( @@ -49,7 +56,7 @@ size_t pa_mix( size_t length, const pa_sample_spec *spec, const pa_cvolume *volume, - int mute); + pa_bool_t mute); void pa_volume_memchunk( pa_memchunk*c, diff --git a/src/tests/mix-test.c b/src/tests/mix-test.c new file mode 100644 index 00000000..d07b1b0c --- /dev/null +++ b/src/tests/mix-test.c @@ -0,0 +1,261 @@ +/* $Id: resampler-test.c 2037 2007-11-09 02:45:07Z lennart $ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +static float swap_float(float a) { + uint32_t *b = (uint32_t*) &a; + *b = PA_UINT32_SWAP(*b); + return a; +} + +static void dump_block(const pa_sample_spec *ss, const pa_memchunk *chunk) { + void *d; + unsigned i; + + d = pa_memblock_acquire(chunk->memblock); + + switch (ss->format) { + + case PA_SAMPLE_U8: + case PA_SAMPLE_ULAW: + case PA_SAMPLE_ALAW: { + uint8_t *u = d; + + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) + printf("0x%02x ", *(u++)); + + break; + } + + case PA_SAMPLE_S16NE: + case PA_SAMPLE_S16RE: { + uint16_t *u = d; + + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) + printf("0x%04x ", *(u++)); + + break; + } + + case PA_SAMPLE_S32NE: + case PA_SAMPLE_S32RE: { + uint32_t *u = d; + + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) + printf("0x%08x ", *(u++)); + + break; + } + + case PA_SAMPLE_FLOAT32NE: + case PA_SAMPLE_FLOAT32RE: { + float *u = d; + + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) { + printf("%1.5f ", ss->format == PA_SAMPLE_FLOAT32NE ? *u : swap_float(*u)); + u++; + } + + break; + } + + default: + pa_assert_not_reached(); + } + + printf("\n"); + + pa_memblock_release(chunk->memblock); +} + +static pa_memblock* generate_block(pa_mempool *pool, const pa_sample_spec *ss) { + pa_memblock *r; + void *d; + unsigned i; + + pa_assert_se(r = pa_memblock_new(pool, pa_frame_size(ss) * 10)); + d = pa_memblock_acquire(r); + + switch (ss->format) { + + case PA_SAMPLE_U8: + case PA_SAMPLE_ULAW: + case PA_SAMPLE_ALAW: { + uint8_t *u = d; + + u[0] = 0x00; + u[1] = 0xFF; + u[2] = 0x7F; + u[3] = 0x80; + u[4] = 0x9f; + u[5] = 0x3f; + u[6] = 0x1; + u[7] = 0xF0; + u[8] = 0x20; + u[9] = 0x21; + break; + } + + case PA_SAMPLE_S16NE: + case PA_SAMPLE_S16RE: { + uint16_t *u = d; + + u[0] = 0x0000; + u[1] = 0xFFFF; + u[2] = 0x7FFF; + u[3] = 0x8000; + u[4] = 0x9fff; + u[5] = 0x3fff; + u[6] = 0x1; + u[7] = 0xF000; + u[8] = 0x20; + u[9] = 0x21; + break; + } + + case PA_SAMPLE_S32NE: + case PA_SAMPLE_S32RE: { + uint32_t *u = d; + + u[0] = 0x00000001; + u[1] = 0xFFFF0002; + u[2] = 0x7FFF0003; + u[3] = 0x80000004; + u[4] = 0x9fff0005; + u[5] = 0x3fff0006; + u[6] = 0x10007; + u[7] = 0xF0000008; + u[8] = 0x200009; + u[9] = 0x21000A; + break; + } + + case PA_SAMPLE_FLOAT32NE: + case PA_SAMPLE_FLOAT32RE: { + float *u = d; + + u[0] = 0.0; + u[1] = -1.0; + u[2] = 1.0; + u[3] = 4711; + u[4] = 0.222; + u[5] = 0.33; + u[6] = -.3; + u[7] = 99; + u[8] = -0.555; + u[9] = -.123; + + if (ss->format == PA_SAMPLE_FLOAT32RE) + for (i = 0; i < 10; i++) + u[i] = swap_float(u[i]); + + break; + } + + default: + pa_assert_not_reached(); + } + + pa_memblock_release(r); + + return r; +} + +int main(int argc, char *argv[]) { + pa_mempool *pool; + pa_sample_spec a; + pa_cvolume v; + + oil_init(); + pa_log_set_maximal_level(PA_LOG_DEBUG); + + pa_assert_se(pool = pa_mempool_new(FALSE)); + + a.channels = 1; + a.rate = 44100; + + v.channels = a.channels; + v.values[0] = pa_sw_volume_from_linear(0.9); + + for (a.format = 0; a.format < PA_SAMPLE_MAX; a.format ++) { + pa_memchunk i, j, k; + pa_mix_info m[2]; + void *ptr; + + printf("=== mixing: %s\n", pa_sample_format_to_string(a.format)); + + /* Generate block */ + i.memblock = generate_block(pool, &a); + i.length = pa_memblock_get_length(i.memblock); + i.index = 0; + + /* Make a copy */ + j = i; + pa_memblock_ref(j.memblock); + pa_memchunk_make_writable(&j, 0); + + /* Adjust volume of the copy */ + pa_volume_memchunk(&j, &a, &v); + + m[0].chunk = i; + m[0].volume.values[0] = PA_VOLUME_NORM; + m[0].volume.channels = a.channels; + m[1].chunk = j; + m[1].volume.values[0] = PA_VOLUME_NORM; + m[1].volume.channels = a.channels; + + k.memblock = pa_memblock_new(pool, i.length); + k.length = i.length; + k.index = 0; + + ptr = (uint8_t*) pa_memblock_acquire(k.memblock) + k.index; + pa_mix(m, 2, ptr, k.length, &a, NULL, FALSE); + pa_memblock_release(k.memblock); + + dump_block(&a, &i); + dump_block(&a, &j); + dump_block(&a, &k); + + pa_memblock_unref(i.memblock); + pa_memblock_unref(j.memblock); + pa_memblock_unref(k.memblock); + } + + pa_mempool_free(pool); + + return 0; +} -- cgit From d8e0c1c6bdb4fbfcc69d080ca78d76403f9e8760 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 9 Nov 2007 18:24:09 +0000 Subject: minor typo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2042 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/sample.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulse/sample.h b/src/pulse/sample.h index 2c13f57d..8f9f1733 100644 --- a/src/pulse/sample.h +++ b/src/pulse/sample.h @@ -50,7 +50,7 @@ * \li PA_SAMPLE_ALAW - 8 bit a-Law. * \li PA_SAMPLE_ULAW - 8 bit mu-Law. * \li PA_SAMPLE_S32LE - Signed 32 bit integer PCM, little endian. - * \li PA_SAMPLE_S32BE - Signed 32 bit integer PCM, big endian. + * \li PA_SAMPLE_S32BE - Signed 32 bit integer PCM, big endian. * * The floating point sample formats have the range from -1 to 1. * -- cgit From e313fe1b3d0d9f9945c41c151d72edbe9cf1ec54 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 9 Nov 2007 18:25:40 +0000 Subject: tag modules that may only be loaded once at most especially, and enforce that in the module loader git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2043 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/dumpmodules.c | 1 + src/modules/gconf/module-gconf.c | 8 ++++---- src/modules/module-alsa-sink.c | 9 +++++---- src/modules/module-alsa-source.c | 9 +++++---- src/modules/module-cli.c | 9 +++++---- src/modules/module-combine.c | 9 +++++---- src/modules/module-default-device-restore.c | 10 ++++------ src/modules/module-defs.h.m4 | 3 +++ src/modules/module-detect.c | 9 +++++---- src/modules/module-esound-compat-spawnfd.c | 9 +++++---- src/modules/module-esound-compat-spawnpid.c | 9 +++++---- src/modules/module-esound-sink.c | 9 +++++---- src/modules/module-hal-detect.c | 13 +++++++------ src/modules/module-jack-sink.c | 9 +++++---- src/modules/module-jack-source.c | 9 +++++---- src/modules/module-ladspa-sink.c | 9 +++++---- src/modules/module-lirc.c | 9 +++++---- src/modules/module-match.c | 11 +++++------ src/modules/module-mmkbd-evdev.c | 9 +++++---- src/modules/module-native-protocol-fd.c | 7 ++++--- src/modules/module-null-sink.c | 9 +++++---- src/modules/module-oss.c | 9 +++++---- src/modules/module-pipe-sink.c | 9 +++++---- src/modules/module-pipe-source.c | 9 +++++---- src/modules/module-protocol-stub.c | 25 +++++++++++++------------ src/modules/module-remap-sink.c | 9 +++++---- src/modules/module-rescue-streams.c | 7 ++++--- src/modules/module-sine.c | 10 +++++----- src/modules/module-suspend-on-idle.c | 7 ++++--- src/modules/module-tunnel.c | 13 +++++++------ src/modules/module-volume-restore.c | 9 +++++---- src/modules/module-x11-bell.c | 9 +++++---- src/modules/module-x11-publish.c | 9 +++++---- src/modules/module-x11-xsmp.c | 7 ++++--- src/modules/module-zeroconf-discover.c | 7 ++++--- src/modules/module-zeroconf-publish.c | 9 +++++---- src/modules/rtp/module-rtp-recv.c | 9 +++++---- src/modules/rtp/module-rtp-send.c | 9 +++++---- src/pulsecore/modinfo.c | 5 +++++ src/pulsecore/modinfo.h | 2 ++ src/pulsecore/module.c | 18 ++++++++++++++++++ src/pulsecore/module.h | 23 +++++++++++++++++++---- 42 files changed, 233 insertions(+), 160 deletions(-) diff --git a/src/daemon/dumpmodules.c b/src/daemon/dumpmodules.c index ad7fab20..68236c70 100644 --- a/src/daemon/dumpmodules.c +++ b/src/daemon/dumpmodules.c @@ -71,6 +71,7 @@ static void long_info(const char *name, const char *path, pa_modinfo *i) { printf("Author: %s\n", i->author); if (i->usage) printf("Usage: %s\n", i->usage); + printf("Load Once: %s\n", pa_yes_no(i->load_once)); } if (path) diff --git a/src/modules/gconf/module-gconf.c b/src/modules/gconf/module-gconf.c index 799bdfbd..fa9ab1cc 100644 --- a/src/modules/gconf/module-gconf.c +++ b/src/modules/gconf/module-gconf.c @@ -53,10 +53,10 @@ #include "module-gconf-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("GConf Adapter") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("") +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("GConf Adapter"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); #define MAX_MODULES 10 #define BUF_MAX 2048 diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 88594cda..636b413c 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -50,9 +50,10 @@ #include "alsa-util.h" #include "module-alsa-sink-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("ALSA Sink") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("ALSA Sink"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "sink_name= " "device= " @@ -62,7 +63,7 @@ PA_MODULE_USAGE( "fragments= " "fragment_size= " "channel_map= " - "mmap=") + "mmap="); #define DEFAULT_DEVICE "default" diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index a862657f..1a6113a7 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -51,9 +51,10 @@ #include "alsa-util.h" #include "module-alsa-source-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("ALSA Source") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("ALSA Source"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "source_name= " "device= " @@ -63,7 +64,7 @@ PA_MODULE_USAGE( "fragments= " "fragment_size= " "channel_map= " - "mmap=") + "mmap="); #define DEFAULT_DEVICE "default" diff --git a/src/modules/module-cli.c b/src/modules/module-cli.c index 84125214..71df5a0f 100644 --- a/src/modules/module-cli.c +++ b/src/modules/module-cli.c @@ -38,10 +38,11 @@ #include "module-cli-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Command line interface") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("exit_on_eof=") +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("Command line interface"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); +PA_MODULE_USAGE("exit_on_eof="); static const char* const valid_modargs[] = { "exit_on_eof", diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index aca4ba32..dd81653c 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -50,9 +50,10 @@ #include "module-combine-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Combine multiple sinks to one") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("Combine multiple sinks to one"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "sink_name= " "master= " @@ -62,7 +63,7 @@ PA_MODULE_USAGE( "format= " "channels= " "rate= " - "channel_map=") + "channel_map="); #define DEFAULT_SINK_NAME "combined" #define MEMBLOCKQ_MAXLENGTH (1024*170) diff --git a/src/modules/module-default-device-restore.c b/src/modules/module-default-device-restore.c index a816eae8..b550ae78 100644 --- a/src/modules/module-default-device-restore.c +++ b/src/modules/module-default-device-restore.c @@ -32,9 +32,10 @@ #include "module-default-device-restore-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Automatically restore the default sink and source") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("Automatically restore the default sink and source"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); #define DEFAULT_SINK_FILE "default-sink" #define DEFAULT_SOURCE_FILE "default-source" @@ -98,6 +99,3 @@ void pa__done(pa_module*m) { fclose(f); } } - - - diff --git a/src/modules/module-defs.h.m4 b/src/modules/module-defs.h.m4 index 5bff748e..a49e8329 100644 --- a/src/modules/module-defs.h.m4 +++ b/src/modules/module-defs.h.m4 @@ -10,6 +10,7 @@ define(`gen_symbol', `#define $1 'module_name`_LTX_$1')dnl #include #include +#include gen_symbol(pa__init) gen_symbol(pa__done) @@ -17,6 +18,7 @@ gen_symbol(pa__get_author) gen_symbol(pa__get_description) gen_symbol(pa__get_usage) gen_symbol(pa__get_version) +gen_symbol(pa__load_once) int pa__init(pa_module*m); void pa__done(pa_module*m); @@ -25,5 +27,6 @@ const char* pa__get_author(void); const char* pa__get_description(void); const char* pa__get_usage(void); const char* pa__get_version(void); +pa_bool_t pa__load_once(void); #endif diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index 7dc25243..95665931 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -47,10 +47,11 @@ #include "module-detect-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("just-one=") +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); +PA_MODULE_USAGE("just-one="); static const char* const valid_modargs[] = { "just-one", diff --git a/src/modules/module-esound-compat-spawnfd.c b/src/modules/module-esound-compat-spawnfd.c index f0f73fcf..8321192b 100644 --- a/src/modules/module-esound-compat-spawnfd.c +++ b/src/modules/module-esound-compat-spawnfd.c @@ -37,10 +37,11 @@ #include "module-esound-compat-spawnfd-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("ESOUND compatibility module: -spawnfd emulation") -PA_MODULE_USAGE("fd=") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("ESOUND compatibility module: -spawnfd emulation"); +PA_MODULE_LOAD_ONCE(TRUE); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_USAGE("fd="); static const char* const valid_modargs[] = { "fd", diff --git a/src/modules/module-esound-compat-spawnpid.c b/src/modules/module-esound-compat-spawnpid.c index 6562fe28..67f0a231 100644 --- a/src/modules/module-esound-compat-spawnpid.c +++ b/src/modules/module-esound-compat-spawnpid.c @@ -37,10 +37,11 @@ #include "module-esound-compat-spawnpid-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("ESOUND compatibility module: -spawnpid emulation") -PA_MODULE_USAGE("pid=") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("ESOUND compatibility module: -spawnpid emulation"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); +PA_MODULE_USAGE("pid="); static const char* const valid_modargs[] = { "pid", diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index b18d3258..f9bea63d 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -64,15 +64,16 @@ #include "module-esound-sink-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("ESOUND Sink") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("ESOUND Sink"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "sink_name= " "server=
        cookie= " "format= " "channels= " - "rate=") + "rate="); #define DEFAULT_SINK_NAME "esound_out" diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index a8ca7df3..00b66c16 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -53,15 +53,16 @@ #include "dbus-util.h" #include "module-hal-detect-symdef.h" -PA_MODULE_AUTHOR("Shahms King") -PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Shahms King"); +PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); #if defined(HAVE_ALSA) && defined(HAVE_OSS) -PA_MODULE_USAGE("api=") +PA_MODULE_USAGE("api="); #elif defined(HAVE_ALSA) -PA_MODULE_USAGE("api=") +PA_MODULE_USAGE("api="); #elif defined(HAVE_OSS) -PA_MODULE_USAGE("api=") +PA_MODULE_USAGE("api="); #endif struct device { diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index 840867ce..44da068f 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -64,16 +64,17 @@ * source support in JACK. */ -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("JACK Sink") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("JACK Sink"); +PA_MODULE_LOAD_ONCE(TRUE); +PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_USAGE( "sink_name= " "server_name= " "client_name= " "channels= " "connect= " - "channel_map=") + "channel_map="); #define DEFAULT_SINK_NAME "jack_out" diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index 380f87eb..93618020 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -54,16 +54,17 @@ /* See module-jack-sink for a few comments how this module basically * works */ -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("JACK Source") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("JACK Source"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); PA_MODULE_USAGE( "source_name= " "server_name= " "client_name= " "channels= " "connect=" - "channel_map=") + "channel_map="); #define DEFAULT_SOURCE_NAME "jack_in" diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c index 6ed392ce..50cdc459 100644 --- a/src/modules/module-ladspa-sink.c +++ b/src/modules/module-ladspa-sink.c @@ -45,9 +45,10 @@ #include "module-ladspa-sink-symdef.h" #include "ladspa.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Virtual LADSPA sink") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("Virtual LADSPA sink"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "sink_name= " "master= " @@ -57,7 +58,7 @@ PA_MODULE_USAGE( "channel_map= " "plugin= " "label= " - "control=") + "control="); struct userdata { pa_core *core; diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c index 21d93837..24542172 100644 --- a/src/modules/module-lirc.c +++ b/src/modules/module-lirc.c @@ -43,10 +43,11 @@ #include "module-lirc-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("LIRC volume control") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("config= sink= appname=") +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("LIRC volume control"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); +PA_MODULE_USAGE("config= sink= appname="); static const char* const valid_modargs[] = { "config", diff --git a/src/modules/module-match.c b/src/modules/module-match.c index 0155b2af..ed5f3076 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -46,10 +46,11 @@ #include "module-match-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Playback stream expression matching module") -PA_MODULE_USAGE("table=") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("Playback stream expression matching module"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); +PA_MODULE_USAGE("table="); #define WHITESPACE "\n\r \t" @@ -241,5 +242,3 @@ void pa__done(pa_module*m) { pa_xfree(u); } - - diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c index 47a10645..03c0e973 100644 --- a/src/modules/module-mmkbd-evdev.c +++ b/src/modules/module-mmkbd-evdev.c @@ -46,10 +46,11 @@ #include "module-mmkbd-evdev-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Multimedia keyboard support via Linux evdev") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("device= sink=") +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("Multimedia keyboard support via Linux evdev"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); +PA_MODULE_USAGE("device= sink="); #define DEFAULT_DEVICE "/dev/input/event0" diff --git a/src/modules/module-native-protocol-fd.c b/src/modules/module-native-protocol-fd.c index 2ef61c88..53f41896 100644 --- a/src/modules/module-native-protocol-fd.c +++ b/src/modules/module-native-protocol-fd.c @@ -37,9 +37,10 @@ #include "module-native-protocol-fd-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Native protocol autospawn helper") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("Native protocol autospawn helper"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); static const char* const valid_modargs[] = { "fd", diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index 3a4edec7..de35fff9 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -51,16 +51,17 @@ #include "module-null-sink-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Clocked NULL sink") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("Clocked NULL sink"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "format= " "channels= " "rate= " "sink_name=" "channel_map=" - "description=") + "description="); #define DEFAULT_SINK_NAME "null" diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 51ab8a85..a44ad083 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -76,9 +76,10 @@ #include "oss-util.h" #include "module-oss-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("OSS Sink/Source") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("OSS Sink/Source"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "sink_name= " "source_name= " @@ -91,7 +92,7 @@ PA_MODULE_USAGE( "fragments= " "fragment_size= " "channel_map= " - "mmap=") + "mmap="); #define DEFAULT_DEVICE "/dev/dsp" diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index 75748474..e720c8ad 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -50,16 +50,17 @@ #include "module-pipe-sink-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("UNIX pipe sink") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("UNIX pipe sink"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "sink_name= " "file= " "format= " "channels= " "rate=" - "channel_map=") + "channel_map="); #define DEFAULT_FILE_NAME "/tmp/music.output" #define DEFAULT_SINK_NAME "fifo_output" diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index 45708c68..02935649 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -49,16 +49,17 @@ #include "module-pipe-source-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("UNIX pipe source") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("UNIX pipe source"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "source_name= " "file= " "format= " "channels= " "rate= " - "channel_map=") + "channel_map="); #define DEFAULT_FILE_NAME "/tmp/music.input" #define DEFAULT_SOURCE_NAME "fifo_input" diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index 6bd78079..207e266e 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -76,7 +76,7 @@ #else #include "module-simple-protocol-unix-symdef.h" #endif - PA_MODULE_DESCRIPTION("Simple protocol "SOCKET_DESCRIPTION) +PA_MODULE_DESCRIPTION("Simple protocol "SOCKET_DESCRIPTION); PA_MODULE_USAGE("rate= " "format= " "channels= " @@ -84,7 +84,7 @@ "source= " "playback= " "record= " - SOCKET_USAGE) + SOCKET_USAGE); #elif defined(USE_PROTOCOL_CLI) #include #define protocol_new pa_protocol_cli_new @@ -98,8 +98,8 @@ #else #include "module-cli-protocol-unix-symdef.h" #endif - PA_MODULE_DESCRIPTION("Command line interface protocol "SOCKET_DESCRIPTION) - PA_MODULE_USAGE(SOCKET_USAGE) + PA_MODULE_DESCRIPTION("Command line interface protocol "SOCKET_DESCRIPTION); + PA_MODULE_USAGE(SOCKET_USAGE); #elif defined(USE_PROTOCOL_HTTP) #include #define protocol_new pa_protocol_http_new @@ -113,8 +113,8 @@ #else #include "module-http-protocol-unix-symdef.h" #endif - PA_MODULE_DESCRIPTION("HTTP "SOCKET_DESCRIPTION) - PA_MODULE_USAGE(SOCKET_USAGE) + PA_MODULE_DESCRIPTION("HTTP "SOCKET_DESCRIPTION); + PA_MODULE_USAGE(SOCKET_USAGE); #elif defined(USE_PROTOCOL_NATIVE) #include #define protocol_new pa_protocol_native_new @@ -140,11 +140,11 @@ #define AUTH_USAGE #endif - PA_MODULE_DESCRIPTION("Native protocol "SOCKET_DESCRIPTION) + PA_MODULE_DESCRIPTION("Native protocol "SOCKET_DESCRIPTION); PA_MODULE_USAGE("auth-anonymous= " "cookie= " AUTH_USAGE - SOCKET_USAGE) + SOCKET_USAGE); #elif defined(USE_PROTOCOL_ESOUND) #include #include @@ -167,19 +167,20 @@ #define AUTH_USAGE #endif - PA_MODULE_DESCRIPTION("ESOUND protocol "SOCKET_DESCRIPTION) + PA_MODULE_DESCRIPTION("ESOUND protocol "SOCKET_DESCRIPTION); PA_MODULE_USAGE("sink= " "source= " "auth-anonymous= " "cookie= " AUTH_USAGE - SOCKET_USAGE) + SOCKET_USAGE); #else #error "Broken build system" #endif -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_LOAD_ONCE(FALSE); +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_VERSION(PACKAGE_VERSION); static const char* const valid_modargs[] = { MODULE_ARGUMENTS diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c index e863c0c3..39a9245d 100644 --- a/src/modules/module-remap-sink.c +++ b/src/modules/module-remap-sink.c @@ -40,9 +40,10 @@ #include "module-remap-sink-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Virtual channel remapping sink") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("Virtual channel remapping sink"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "sink_name= " "master= " @@ -50,7 +51,7 @@ PA_MODULE_USAGE( "format= " "channels= " "rate= " - "channel_map=") + "channel_map="); struct userdata { pa_core *core; diff --git a/src/modules/module-rescue-streams.c b/src/modules/module-rescue-streams.c index 5cabef76..12957c9d 100644 --- a/src/modules/module-rescue-streams.c +++ b/src/modules/module-rescue-streams.c @@ -36,9 +36,10 @@ #include "module-rescue-streams-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("When a sink/source is removed, try to move their streams to the default sink/source") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("When a sink/source is removed, try to move their streams to the default sink/source"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); static const char* const valid_modargs[] = { NULL, diff --git a/src/modules/module-sine.c b/src/modules/module-sine.c index 65b8ee7f..41d9a51c 100644 --- a/src/modules/module-sine.c +++ b/src/modules/module-sine.c @@ -39,10 +39,11 @@ #include "module-sine-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Sine wave generator") -PA_MODULE_USAGE("sink= frequency=") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("Sine wave generator"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); +PA_MODULE_USAGE("sink= frequency="); struct userdata { pa_core *core; @@ -203,4 +204,3 @@ void pa__done(pa_module*m) { pa_xfree(u); } - diff --git a/src/modules/module-suspend-on-idle.c b/src/modules/module-suspend-on-idle.c index 5a711390..4746e2b7 100644 --- a/src/modules/module-suspend-on-idle.c +++ b/src/modules/module-suspend-on-idle.c @@ -37,9 +37,10 @@ #include "module-suspend-on-idle-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("When a sink/source is idle for too long, suspend it") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("When a sink/source is idle for too long, suspend it"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); static const char* const valid_modargs[] = { "timeout", diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index edc03c99..05cece7d 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -59,7 +59,8 @@ #ifdef TUNNEL_SINK #include "module-tunnel-sink-symdef.h" -PA_MODULE_DESCRIPTION("Tunnel module for sinks") +PA_MODULE_DESCRIPTION("Tunnel module for sinks"); +PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "server=
        " "sink= " @@ -68,10 +69,10 @@ PA_MODULE_USAGE( "channels= " "rate= " "sink_name= " - "channel_map=") + "channel_map="); #else #include "module-tunnel-source-symdef.h" -PA_MODULE_DESCRIPTION("Tunnel module for sources") +PA_MODULE_DESCRIPTION("Tunnel module for sources"); PA_MODULE_USAGE( "server=
        " "source= " @@ -80,11 +81,11 @@ PA_MODULE_USAGE( "channels= " "rate= " "source_name= " - "channel_map=") + "channel_map="); #endif -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_VERSION(PACKAGE_VERSION); #define DEFAULT_TLENGTH_MSEC 100 #define DEFAULT_MINREQ_MSEC 10 diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index 8ef72b2a..422bc7f2 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -48,10 +48,11 @@ #include "module-volume-restore-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Automatically restore the volume and the devices of streams") -PA_MODULE_USAGE("table=") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("Automatically restore the volume and the devices of streams"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); +PA_MODULE_USAGE("table="); #define WHITESPACE "\n\r \t" diff --git a/src/modules/module-x11-bell.c b/src/modules/module-x11-bell.c index 4eacbb1e..87c6849d 100644 --- a/src/modules/module-x11-bell.c +++ b/src/modules/module-x11-bell.c @@ -44,10 +44,11 @@ #include "module-x11-bell-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("X11 Bell interceptor") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink= sample= display=") +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("X11 Bell interceptor"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); +PA_MODULE_USAGE("sink= sample= display="); struct userdata { pa_core *core; diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c index f350126a..429c2a69 100644 --- a/src/modules/module-x11-publish.c +++ b/src/modules/module-x11-publish.c @@ -53,10 +53,11 @@ #include "module-x11-publish-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("X11 Credential Publisher") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("display=") +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("X11 Credential Publisher"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); +PA_MODULE_USAGE("display="); static const char* const valid_modargs[] = { "display", diff --git a/src/modules/module-x11-xsmp.c b/src/modules/module-x11-xsmp.c index 3e353caf..e9efa096 100644 --- a/src/modules/module-x11-xsmp.c +++ b/src/modules/module-x11-xsmp.c @@ -45,9 +45,10 @@ #include "module-x11-xsmp-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("X11 session management") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("X11 session management"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); static int ice_in_use = 0; diff --git a/src/modules/module-zeroconf-discover.c b/src/modules/module-zeroconf-discover.c index e4903718..061560c8 100644 --- a/src/modules/module-zeroconf-discover.c +++ b/src/modules/module-zeroconf-discover.c @@ -53,9 +53,10 @@ #include "module-zeroconf-discover-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Discovery") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Discovery"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); #define SERVICE_TYPE_SINK "_pulse-sink._tcp" #define SERVICE_TYPE_SOURCE "_non-monitor._sub._pulse-source._tcp" diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index 818a1b28..46969a24 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -52,10 +52,11 @@ #include "module-zeroconf-publish-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Publisher") -PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("port=") +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Publisher"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); +PA_MODULE_USAGE("port="); #define SERVICE_TYPE_SINK "_pulse-sink._tcp" #define SERVICE_TYPE_SOURCE "_pulse-source._tcp" diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index 6c018931..d8e7a781 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -58,13 +58,14 @@ #include "sdp.h" #include "sap.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Recieve data from a network via RTP/SAP/SDP") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("Recieve data from a network via RTP/SAP/SDP"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "sink= " "sap_address= " -) +); #define SAP_PORT 9875 #define DEFAULT_SAP_ADDRESS "224.0.0.56" diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index f36989bd..d7c50578 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -57,9 +57,10 @@ #include "sdp.h" #include "sap.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Read data from source and send it to the network via RTP/SAP/SDP") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("Read data from source and send it to the network via RTP/SAP/SDP"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "source= " "format= " @@ -69,7 +70,7 @@ PA_MODULE_USAGE( "port= " "mtu= " "loop=" -) +); #define DEFAULT_PORT 46000 #define SAP_PORT 9875 diff --git a/src/pulsecore/modinfo.c b/src/pulsecore/modinfo.c index da2df653..d1a78fbb 100644 --- a/src/pulsecore/modinfo.c +++ b/src/pulsecore/modinfo.c @@ -40,10 +40,12 @@ #define PA_SYMBOL_DESCRIPTION "pa__get_description" #define PA_SYMBOL_USAGE "pa__get_usage" #define PA_SYMBOL_VERSION "pa__get_version" +#define PA_SYMBOL_LOAD_ONCE "pa__load_once" pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl, const char *module_name) { pa_modinfo *i; const char* (*func)(void); + pa_bool_t (*func2) (void); pa_assert(dl); @@ -61,6 +63,9 @@ pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl, const char *module_name) { if ((func = (const char* (*)(void)) pa_load_sym(dl, module_name, PA_SYMBOL_VERSION))) i->version = pa_xstrdup(func()); + if ((func2 = (pa_bool_t (*)(void)) pa_load_sym(dl, module_name, PA_SYMBOL_LOAD_ONCE))) + i->load_once = func2(); + return i; } diff --git a/src/pulsecore/modinfo.h b/src/pulsecore/modinfo.h index 02e536c6..da6d5428 100644 --- a/src/pulsecore/modinfo.h +++ b/src/pulsecore/modinfo.h @@ -25,12 +25,14 @@ ***/ /* Some functions for reading module meta data from PulseAudio modules */ +#include typedef struct pa_modinfo { char *author; char *description; char *usage; char *version; + pa_bool_t load_once; } pa_modinfo; /* Read meta data from an libtool handle */ diff --git a/src/pulsecore/module.c b/src/pulsecore/module.c index dce91a71..e1680de5 100644 --- a/src/pulsecore/module.c +++ b/src/pulsecore/module.c @@ -46,6 +46,7 @@ #define PA_SYMBOL_INIT "pa__init" #define PA_SYMBOL_DONE "pa__done" +#define PA_SYMBOL_LOAD_ONCE "pa__load_once" #define UNLOAD_POLL_TIME 2 @@ -66,6 +67,7 @@ static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { pa_module *m = NULL; + pa_bool_t (*load_once)(void); pa_assert(c); pa_assert(name); @@ -82,6 +84,22 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { goto fail; } + if ((load_once = (pa_bool_t (*)(void)) pa_load_sym(m->dl, name, PA_SYMBOL_LOAD_ONCE))) { + + if (load_once()) { + pa_module *i; + uint32_t idx; + /* OK, the module only wants to be loaded once, let's make sure it is */ + + for (i = pa_idxset_first(c->modules, &idx); i; i = pa_idxset_next(c->modules, &idx)) { + if (strcmp(name, i->name) == 0) { + pa_log("Module \"%s\" should be loaded once at most. Refusing to load.", name); + goto fail; + } + } + } + } + if (!(m->init = (int (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_INIT))) { pa_log("Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.", name); goto fail; diff --git a/src/pulsecore/module.h b/src/pulsecore/module.h index 7a93a071..25f122d1 100644 --- a/src/pulsecore/module.h +++ b/src/pulsecore/module.h @@ -62,10 +62,25 @@ void pa_module_unload_request(pa_module *m); void pa_module_set_used(pa_module*m, int used); -#define PA_MODULE_AUTHOR(s) const char *pa__get_author(void) { return s; } -#define PA_MODULE_DESCRIPTION(s) const char *pa__get_description(void) { return s; } -#define PA_MODULE_USAGE(s) const char *pa__get_usage(void) { return s; } -#define PA_MODULE_VERSION(s) const char * pa__get_version(void) { return s; } +#define PA_MODULE_AUTHOR(s) \ + const char *pa__get_author(void) { return s; } \ + struct __stupid_useless_struct_to_allow_trailing_semicolon + +#define PA_MODULE_DESCRIPTION(s) \ + const char *pa__get_description(void) { return s; } \ + struct __stupid_useless_struct_to_allow_trailing_semicolon + +#define PA_MODULE_USAGE(s) \ + const char *pa__get_usage(void) { return s; } \ + struct __stupid_useless_struct_to_allow_trailing_semicolon + +#define PA_MODULE_VERSION(s) \ + const char * pa__get_version(void) { return s; } \ + struct __stupid_useless_struct_to_allow_trailing_semicolon + +#define PA_MODULE_LOAD_ONCE(b) \ + pa_bool_t pa__load_once(void) { return b; } \ + struct __stupid_useless_struct_to_allow_trailing_semicolon pa_modinfo *pa_module_get_info(pa_module *m); -- cgit From f873a2a22441d5eaacc5cbb502cbde829ee30a73 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 11 Nov 2007 02:30:59 +0000 Subject: add a simple fully-automatic fully-linearupmixer/downmixer and enable it by default git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2044 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 8 +- src/pulsecore/resampler.c | 568 +++++++++++++++++++++++++++++++++++++----- src/pulsecore/resampler.h | 8 +- src/pulsecore/sink-input.c | 4 +- src/pulsecore/source-output.c | 4 +- src/tests/remix-test.c | 91 +++++++ src/tests/resampler-test.c | 4 +- 7 files changed, 616 insertions(+), 71 deletions(-) create mode 100644 src/tests/remix-test.c diff --git a/src/Makefile.am b/src/Makefile.am index 8fe7be9d..1a24a529 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -240,7 +240,8 @@ noinst_PROGRAMS = \ sig2str-test \ resampler-test \ smoother-test \ - mix-test + mix-test \ + remix-test if HAVE_SIGXCPU noinst_PROGRAMS += \ @@ -395,6 +396,11 @@ mix_test_LDADD = $(AM_LDADD) libpulsecore.la mix_test_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) mix_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS) +remix_test_SOURCES = tests/remix-test.c +remix_test_LDADD = $(AM_LDADD) libpulsecore.la +remix_test_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) +remix_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS) + smoother_test_SOURCES = tests/smoother-test.c smoother_test_LDADD = $(AM_LDADD) libpulsecore.la smoother_test_CFLAGS = $(AM_CFLAGS) diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index eebc9c04..429759f0 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "speexwrap.h" @@ -49,7 +50,9 @@ #define EXTRA_SAMPLES 128 struct pa_resampler { - pa_resample_method_t resample_method; + pa_resample_method_t method; + pa_resample_flags_t flags; + pa_sample_spec i_ss, o_ss; pa_channel_map i_cm, o_cm; size_t i_fz, o_fz, w_sz; @@ -63,8 +66,8 @@ struct pa_resampler { pa_convert_func_t to_work_format_func; pa_convert_func_t from_work_format_func; - int map_table[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; - int map_required; + float map_table[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; + pa_bool_t map_required; void (*impl_free)(pa_resampler *r); void (*impl_update_rates)(pa_resampler *r); @@ -159,8 +162,8 @@ pa_resampler* pa_resampler_new( const pa_channel_map *am, const pa_sample_spec *b, const pa_channel_map *bm, - pa_resample_method_t resample_method, - int variable_rate) { + pa_resample_method_t method, + pa_resample_flags_t flags) { pa_resampler *r = NULL; @@ -169,37 +172,38 @@ pa_resampler* pa_resampler_new( pa_assert(b); pa_assert(pa_sample_spec_valid(a)); pa_assert(pa_sample_spec_valid(b)); - pa_assert(resample_method >= 0); - pa_assert(resample_method < PA_RESAMPLER_MAX); + pa_assert(method >= 0); + pa_assert(method < PA_RESAMPLER_MAX); /* Fix method */ - if (!variable_rate && a->rate == b->rate) { + if (!(flags & PA_RESAMPLER_VARIABLE_RATE) && a->rate == b->rate) { pa_log_info("Forcing resampler 'copy', because of fixed, identical sample rates."); - resample_method = PA_RESAMPLER_COPY; + method = PA_RESAMPLER_COPY; } - if (!pa_resample_method_supported(resample_method)) { - pa_log_warn("Support for resampler '%s' not compiled in, reverting to 'auto'.", pa_resample_method_to_string(resample_method)); - resample_method = PA_RESAMPLER_AUTO; + if (!pa_resample_method_supported(method)) { + pa_log_warn("Support for resampler '%s' not compiled in, reverting to 'auto'.", pa_resample_method_to_string(method)); + method = PA_RESAMPLER_AUTO; } - if (resample_method == PA_RESAMPLER_FFMPEG && variable_rate) { + if (method == PA_RESAMPLER_FFMPEG && (flags & PA_RESAMPLER_VARIABLE_RATE)) { pa_log_info("Resampler 'ffmpeg' cannot do variable rate, reverting to resampler 'auto'."); - resample_method = PA_RESAMPLER_AUTO; + method = PA_RESAMPLER_AUTO; } - if (resample_method == PA_RESAMPLER_COPY && (variable_rate || a->rate != b->rate)) { + if (method == PA_RESAMPLER_COPY && ((flags & PA_RESAMPLER_VARIABLE_RATE) || a->rate != b->rate)) { pa_log_info("Resampler 'copy' cannot change sampling rate, reverting to resampler 'auto'."); - resample_method = PA_RESAMPLER_AUTO; + method = PA_RESAMPLER_AUTO; } - if (resample_method == PA_RESAMPLER_AUTO) - resample_method = PA_RESAMPLER_SPEEX_FLOAT_BASE + 3; + if (method == PA_RESAMPLER_AUTO) + method = PA_RESAMPLER_SPEEX_FLOAT_BASE + 3; r = pa_xnew(pa_resampler, 1); r->mempool = pool; - r->resample_method = resample_method; + r->method = method; + r->flags = flags; r->impl_free = NULL; r->impl_update_rates = NULL; @@ -231,12 +235,12 @@ pa_resampler* pa_resampler_new( calc_map_table(r); - pa_log_info("Using resampler '%s'", pa_resample_method_to_string(resample_method)); + pa_log_info("Using resampler '%s'", pa_resample_method_to_string(method)); - if ((resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX) || - (resample_method == PA_RESAMPLER_FFMPEG)) + if ((method >= PA_RESAMPLER_SPEEX_FIXED_BASE && method <= PA_RESAMPLER_SPEEX_FIXED_MAX) || + (method == PA_RESAMPLER_FFMPEG)) r->work_format = PA_SAMPLE_S16NE; - else if (resample_method == PA_RESAMPLER_TRIVIAL || resample_method == PA_RESAMPLER_COPY) { + else if (method == PA_RESAMPLER_TRIVIAL || method == PA_RESAMPLER_COPY) { if (r->map_required || a->format != b->format) { @@ -281,7 +285,7 @@ pa_resampler* pa_resampler_new( } /* initialize implementation */ - if (init_table[resample_method](r) < 0) + if (init_table[method](r) < 0) goto fail; return r; @@ -373,7 +377,7 @@ size_t pa_resampler_max_block_size(pa_resampler *r) { pa_resample_method_t pa_resampler_get_method(pa_resampler *r) { pa_assert(r); - return r->resample_method; + return r->method; } static const char * const resample_methods[] = { @@ -449,36 +453,423 @@ pa_resample_method_t pa_parse_resample_method(const char *string) { return PA_RESAMPLER_INVALID; } +static pa_bool_t on_left(pa_channel_position_t p) { + + return + p == PA_CHANNEL_POSITION_FRONT_LEFT || + p == PA_CHANNEL_POSITION_REAR_LEFT || + p == PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER || + p == PA_CHANNEL_POSITION_SIDE_LEFT || + p == PA_CHANNEL_POSITION_TOP_FRONT_LEFT || + p == PA_CHANNEL_POSITION_TOP_REAR_LEFT; +} + +static pa_bool_t on_right(pa_channel_position_t p) { + + return + p == PA_CHANNEL_POSITION_FRONT_RIGHT || + p == PA_CHANNEL_POSITION_REAR_RIGHT || + p == PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER || + p == PA_CHANNEL_POSITION_SIDE_RIGHT || + p == PA_CHANNEL_POSITION_TOP_FRONT_RIGHT || + p == PA_CHANNEL_POSITION_TOP_REAR_RIGHT; +} + +static pa_bool_t on_center(pa_channel_position_t p) { + + return + p == PA_CHANNEL_POSITION_FRONT_CENTER || + p == PA_CHANNEL_POSITION_REAR_CENTER || + p == PA_CHANNEL_POSITION_TOP_CENTER || + p == PA_CHANNEL_POSITION_TOP_FRONT_CENTER || + p == PA_CHANNEL_POSITION_TOP_REAR_CENTER; +} + +static pa_bool_t on_lfe(pa_channel_position_t p) { + return + p == PA_CHANNEL_POSITION_LFE; +} + static void calc_map_table(pa_resampler *r) { - unsigned oc; + unsigned oc, ic; + pa_bool_t ic_connected[PA_CHANNELS_MAX]; + pa_bool_t remix; + pa_strbuf *s; + char *t; pa_assert(r); - if (!(r->map_required = (r->i_ss.channels != r->o_ss.channels || !pa_channel_map_equal(&r->i_cm, &r->o_cm)))) + if (!(r->map_required = (r->i_ss.channels != r->o_ss.channels || (!(r->flags & PA_RESAMPLER_NO_REMAP) && !pa_channel_map_equal(&r->i_cm, &r->o_cm))))) return; + memset(r->map_table, 0, sizeof(r->map_table)); + memset(ic_connected, 0, sizeof(ic_connected)); + remix = (r->flags & (PA_RESAMPLER_NO_REMAP|PA_RESAMPLER_NO_REMIX)) == 0; + for (oc = 0; oc < r->o_ss.channels; oc++) { - unsigned ic, i = 0; + pa_bool_t oc_connected = FALSE; + pa_channel_position_t b = r->o_cm.map[oc]; for (ic = 0; ic < r->i_ss.channels; ic++) { - pa_channel_position_t a, b; + pa_channel_position_t a = r->i_cm.map[ic]; + + if (r->flags & PA_RESAMPLER_NO_REMAP) { + /* We shall not do any remapping. Hence, just check by index */ + + if (ic == oc) + r->map_table[oc][ic] = 1.0; + + continue; + } + + if (r->flags & PA_RESAMPLER_NO_REMIX) { + /* We shall not do any remixing. Hence, just check by name */ + + if (a == b) + r->map_table[oc][ic] = 1.0; + + continue; + } + + pa_assert(remix); + + /* OK, we shall do the full monty: upmixing and + * downmixing. Our algorithm is relatively simple, does + * not do spacialization, delay elements or apply lowpass + * filters for LFE. Patches are always welcome, + * though. Oh, and it doesn't do any matrix + * decoding. (Which probably wouldn't make any sense + * anyway.) + * + * This code is not idempotent: downmixing an upmixed + * stereo stream is not identical to the original. The + * volume will not match, and the two channels will be a + * linear combination of both. + * + * This is losely based on random suggestions found on the + * Internet, such as this: + * http://www.halfgaar.net/surround-sound-in-linux and the + * alsa upmix plugin. + * + * The algorithm works basically like this: + * + * 1) Connect all channels with matching names. + * + * 2) Mono Handling: + * S:Mono: Copy into all D:channels + * D:Mono: Copy in all S:channels + * + * 3) Mix D:Left, D:Right: + * D:Left: If not connected, avg all S:Left + * D:Right: If not connected, avg all S:Right + * + * 4) Mix D:Center + * If not connected, avg all S:Center + * If still not connected, avg all S:Left, S:Right + * + * 5) Mix D:LFE + * If not connected, avg all S:* + * + * 6) Make sure S:Left/S:Right is used: S:Left/S:Right: If + * not connected, mix into all D:left and all D:right + * channels. Gain is 0.1, the current left and right + * should be multiplied by 0.9. + * + * 7) Make sure S:Center, S:LFE is used: + * + * S:Center, S:LFE: If not connected, mix into all + * D:left, all D:right, all D:center channels, gain is + * 0.375. The current (as result of 1..6) factors + * should be multiplied by 0.75. (Alt. suggestion: 0.25 + * vs. 0.5) + * + * S: and D: shall relate to the source resp. destination channels. + * + * Rationale: 1, 2 are probably obvious. For 3: this + * copies front to rear if needed. For 4: we try to find + * some suitable C source for C, if we don't find any, we + * avg L and R. For 5: LFE is mixed from all channels. For + * 6: the rear channels should not be dropped entirely, + * however have only minimal impact. For 7: movies usually + * encode speech on the center channel. Thus we have to + * make sure this channel is distributed to L and R if not + * available in the output. Also, LFE is used to achieve a + * greater dynamic range, and thus we should try to do our + * best to pass it to L+R. + */ + + if (a == b || a == PA_CHANNEL_POSITION_MONO || b == PA_CHANNEL_POSITION_MONO) { + r->map_table[oc][ic] = 1.0; + + oc_connected = TRUE; + ic_connected[ic] = TRUE; + } + } + + if (!oc_connected && remix) { + /* OK, we shall remix */ + + if (on_left(b)) { + unsigned n = 0; + + /* We are not connected and on the left side, let's + * average all left side input channels. */ + + for (ic = 0; ic < r->i_ss.channels; ic++) + if (on_left(r->i_cm.map[ic])) + n++; + + if (n > 0) + for (ic = 0; ic < r->i_ss.channels; ic++) + if (on_left(r->i_cm.map[ic])) { + r->map_table[oc][ic] = 1.0 / n; + ic_connected[ic] = TRUE; + } + + /* We ignore the case where there is no left input + * channel. Something is really wrong in this case + * anyway. */ + + } else if (on_right(b)) { + unsigned n = 0; + + /* We are not connected and on the right side, let's + * average all right side input channels. */ + + for (ic = 0; ic < r->i_ss.channels; ic++) + if (on_right(r->i_cm.map[ic])) + n++; + + if (n > 0) + for (ic = 0; ic < r->i_ss.channels; ic++) + if (on_right(r->i_cm.map[ic])) { + r->map_table[oc][ic] = 1.0 / n; + ic_connected[ic] = TRUE; + } + + /* We ignore the case where there is no right input + * channel. Something is really wrong in this case + * anyway. */ + + } else if (on_center(b)) { + unsigned n = 0; + + /* We are not connected and at the center. Let's + * average all center input channels. */ + + for (ic = 0; ic < r->i_ss.channels; ic++) + if (on_center(r->i_cm.map[ic])) + n++; + + if (n > 0) { + for (ic = 0; ic < r->i_ss.channels; ic++) + if (on_center(r->i_cm.map[ic])) { + r->map_table[oc][ic] = 1.0 / n; + ic_connected[ic] = TRUE; + } + } else { + + /* Hmm, no center channel around, let's synthesize + * it by mixing L and R.*/ + + n = 0; + + for (ic = 0; ic < r->i_ss.channels; ic++) + if (on_left(r->i_cm.map[ic]) || on_right(r->i_cm.map[ic])) + n++; + + if (n > 0) + for (ic = 0; ic < r->i_ss.channels; ic++) + if (on_left(r->i_cm.map[ic]) || on_right(r->i_cm.map[ic])) { + r->map_table[oc][ic] = 1.0 / n; + ic_connected[ic] = TRUE; + } + + /* We ignore the case where there is not even a + * left or right input channel. Something is + * really wrong in this case anyway. */ + } + + } else if (on_lfe(b)) { + + /* We are not connected and an LFE. Let's average all + * channels for LFE. */ + + for (ic = 0; ic < r->i_ss.channels; ic++) { + r->map_table[oc][ic] = 1.0 / r->i_ss.channels; + + /* Please note that a channel connected to LFE + * doesn't really count as connected. */ + } + } + } + } + + if (remix) { + unsigned + ic_unconnected_left = 0, + ic_unconnected_right = 0, + ic_unconnected_center = 0, + ic_unconnected_lfe = 0; + + for (ic = 0; ic < r->i_ss.channels; ic++) { + pa_channel_position_t a = r->i_cm.map[ic]; + + if (ic_connected[ic]) + continue; + + if (on_left(a)) + ic_unconnected_left++; + else if (on_right(a)) + ic_unconnected_right++; + else if (on_center(a)) + ic_unconnected_center++; + else if (on_lfe(a)) + ic_unconnected_lfe++; + } + + if (ic_unconnected_left > 0) { + + /* OK, so there are unconnected input channels on the + * left. Let's multiply all already connected channels on + * the left side by .9 and add in our averaged unconnected + * channels multplied by .1 */ + + for (oc = 0; oc < r->o_ss.channels; oc++) { + + if (!on_left(r->o_cm.map[oc])) + continue; + + for (ic = 0; ic < r->i_ss.channels; ic++) { + + if (ic_connected[ic]) { + r->map_table[oc][ic] *= .9; + continue; + } - a = r->i_cm.map[ic]; - b = r->o_cm.map[oc]; + if (on_left(r->i_cm.map[ic])) + r->map_table[oc][ic] = .1 / ic_unconnected_left; + } + } + } + + if (ic_unconnected_right > 0) { + + /* OK, so there are unconnected input channels on the + * right. Let's multiply all already connected channels on + * the right side by .9 and add in our averaged unconnected + * channels multplied by .1 */ + + for (oc = 0; oc < r->o_ss.channels; oc++) { + + if (!on_right(r->o_cm.map[oc])) + continue; + + for (ic = 0; ic < r->i_ss.channels; ic++) { + + if (ic_connected[ic]) { + r->map_table[oc][ic] *= .9; + continue; + } + + if (on_right(r->i_cm.map[ic])) + r->map_table[oc][ic] = .1 / ic_unconnected_right; + } + } + } + + if (ic_unconnected_center > 0) { + pa_bool_t mixed_in = FALSE; + + /* OK, so there are unconnected input channels on the + * center. Let's multiply all already connected channels on + * the center side by .9 and add in our averaged unconnected + * channels multplied by .1 */ + + for (oc = 0; oc < r->o_ss.channels; oc++) { - if (a == b || - (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_LEFT) || - (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_RIGHT) || - (a == PA_CHANNEL_POSITION_LEFT && b == PA_CHANNEL_POSITION_MONO) || - (a == PA_CHANNEL_POSITION_RIGHT && b == PA_CHANNEL_POSITION_MONO)) + if (!on_center(r->o_cm.map[oc])) + continue; - r->map_table[oc][i++] = ic; + for (ic = 0; ic < r->i_ss.channels; ic++) { + + if (ic_connected[ic]) { + r->map_table[oc][ic] *= .9; + continue; + } + + if (on_center(r->i_cm.map[ic])) { + r->map_table[oc][ic] = .1 / ic_unconnected_center; + mixed_in = TRUE; + } + } + } + + if (!mixed_in) { + + /* Hmm, as it appears there was no center channel we + could mix our center channel in. In this case, mix + it into left and right. Using .375 and 0.75 as + factors. */ + + for (oc = 0; oc < r->o_ss.channels; oc++) { + + if (!on_left(r->o_cm.map[oc]) && !on_right(r->o_cm.map[oc])) + continue; + + for (ic = 0; ic < r->i_ss.channels; ic++) { + + if (ic_connected[ic]) { + r->map_table[oc][ic] *= .75; + continue; + } + + if (on_center(r->i_cm.map[ic])) + r->map_table[oc][ic] = .375 / ic_unconnected_center; + } + } + } } - /* Add an end marker */ - if (i < PA_CHANNELS_MAX) - r->map_table[oc][i] = -1; + if (ic_unconnected_lfe > 0) { + + /* OK, so there is an unconnected LFE channel. Let's mix + * it into all channels, with factor 0.375 */ + + for (ic = 0; ic < r->i_ss.channels; ic++) { + + if (!on_lfe(r->i_cm.map[ic])) + continue; + + for (oc = 0; oc < r->o_ss.channels; oc++) + r->map_table[oc][ic] = 0.375 / ic_unconnected_lfe; + } + } + } + + + s = pa_strbuf_new(); + + pa_strbuf_printf(s, " "); + for (ic = 0; ic < r->i_ss.channels; ic++) + pa_strbuf_printf(s, " I%02u ", ic); + pa_strbuf_puts(s, "\n +"); + + for (ic = 0; ic < r->i_ss.channels; ic++) + pa_strbuf_printf(s, "------"); + pa_strbuf_puts(s, "\n"); + + for (oc = 0; oc < r->o_ss.channels; oc++) { + pa_strbuf_printf(s, "O%02u |", oc); + + for (ic = 0; ic < r->i_ss.channels; ic++) + pa_strbuf_printf(s, " %1.3f", r->map_table[oc][ic]); + + pa_strbuf_puts(s, "\n"); } + + pa_log_debug("Channel matrix:\n%s", t = pa_strbuf_tostring_free(s)); + pa_xfree(t); } static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) { @@ -518,6 +909,36 @@ static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) return &r->buf1; } +static void vectoradd_s16_with_fraction( + int16_t *d, int dstr, + const int16_t *s1, int sstr1, + const int16_t *s2, int sstr2, + int n, + float s3, float s4) { + + int32_t i3, i4; + + i3 = (int32_t) (s3 * 0x10000); + i4 = (int32_t) (s4 * 0x10000); + + for (; n > 0; n--) { + int32_t a, b; + + a = *s1; + b = *s2; + + a = (a * i3) / 0x10000; + b = (b * i4) / 0x10000; + + *d = (int16_t) (a + b); + + s1 = (const int16_t*) ((const uint8_t*) s1 + sstr1); + s2 = (const int16_t*) ((const uint8_t*) s2 + sstr2); + d = (int16_t*) ((uint8_t*) d + dstr); + + } +} + static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { unsigned in_n_samples, out_n_samples, n_frames; int i_skip, o_skip; @@ -560,16 +981,21 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { case PA_SAMPLE_FLOAT32NE: for (oc = 0; oc < r->o_ss.channels; oc++) { - unsigned i; + unsigned ic; static const float one = 1.0; - for (i = 0; i < PA_CHANNELS_MAX && r->map_table[oc][i] >= 0; i++) + for (ic = 0; ic < r->i_ss.channels; ic++) { + + if (r->map_table[oc][ic] <= 0.0) + continue; + oil_vectoradd_f32( (float*) dst + oc, o_skip, (float*) dst + oc, o_skip, - (float*) src + r->map_table[oc][i], i_skip, + (float*) src + ic, i_skip, n_frames, - &one, &one); + &one, &r->map_table[oc][ic]); + } } break; @@ -577,16 +1003,32 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { case PA_SAMPLE_S16NE: for (oc = 0; oc < r->o_ss.channels; oc++) { - unsigned i; - static const int16_t one = 1; - - for (i = 0; i < PA_CHANNELS_MAX && r->map_table[oc][i] >= 0; i++) - oil_vectoradd_s16( - (int16_t*) dst + oc, o_skip, - (int16_t*) dst + oc, o_skip, - (int16_t*) src + r->map_table[oc][i], i_skip, - n_frames, - &one, &one); + unsigned ic; + + for (ic = 0; ic < r->i_ss.channels; ic++) { + + if (r->map_table[oc][ic] <= 0.0) + continue; + + if (r->map_table[oc][ic] >= 1.0) { + static const int16_t one = 1; + + oil_vectoradd_s16( + (int16_t*) dst + oc, o_skip, + (int16_t*) dst + oc, o_skip, + (int16_t*) src + ic, i_skip, + n_frames, + &one, &one); + + } else + + vectoradd_s16_with_fraction( + (int16_t*) dst + oc, o_skip, + (int16_t*) dst + oc, o_skip, + (int16_t*) src + ic, i_skip, + n_frames, + 1.0, r->map_table[oc][ic]); + } } break; @@ -751,7 +1193,7 @@ static int libsamplerate_init(pa_resampler *r) { pa_assert(r); - if (!(r->src.state = src_new(r->resample_method, r->o_ss.channels, &err))) + if (!(r->src.state = src_new(r->method, r->o_ss.channels, &err))) return -1; r->impl_free = libsamplerate_free; @@ -809,10 +1251,10 @@ static void speex_resample_int(pa_resampler *r, const pa_memchunk *input, unsign static void speex_update_rates(pa_resampler *r) { pa_assert(r); - if (r->resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX) + if (r->method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->method <= PA_RESAMPLER_SPEEX_FIXED_MAX) pa_assert_se(paspfx_resampler_set_rate(r->speex.state, r->i_ss.rate, r->o_ss.rate) == 0); else { - pa_assert(r->resample_method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FLOAT_MAX); + pa_assert(r->method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->method <= PA_RESAMPLER_SPEEX_FLOAT_MAX); pa_assert_se(paspfl_resampler_set_rate(r->speex.state, r->i_ss.rate, r->o_ss.rate) == 0); } } @@ -823,10 +1265,10 @@ static void speex_free(pa_resampler *r) { if (!r->speex.state) return; - if (r->resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX) + if (r->method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->method <= PA_RESAMPLER_SPEEX_FIXED_MAX) paspfx_resampler_destroy(r->speex.state); else { - pa_assert(r->resample_method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FLOAT_MAX); + pa_assert(r->method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->method <= PA_RESAMPLER_SPEEX_FLOAT_MAX); paspfl_resampler_destroy(r->speex.state); } } @@ -839,8 +1281,8 @@ static int speex_init(pa_resampler *r) { r->impl_free = speex_free; r->impl_update_rates = speex_update_rates; - if (r->resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX) { - q = r->resample_method - PA_RESAMPLER_SPEEX_FIXED_BASE; + if (r->method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->method <= PA_RESAMPLER_SPEEX_FIXED_MAX) { + q = r->method - PA_RESAMPLER_SPEEX_FIXED_BASE; pa_log_info("Choosing speex quality setting %i.", q); @@ -849,8 +1291,8 @@ static int speex_init(pa_resampler *r) { r->impl_resample = speex_resample_int; } else { - pa_assert(r->resample_method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FLOAT_MAX); - q = r->resample_method - PA_RESAMPLER_SPEEX_FLOAT_BASE; + pa_assert(r->method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->method <= PA_RESAMPLER_SPEEX_FLOAT_MAX); + q = r->method - PA_RESAMPLER_SPEEX_FLOAT_BASE; pa_log_info("Choosing speex quality setting %i.", q); diff --git a/src/pulsecore/resampler.h b/src/pulsecore/resampler.h index 23e1acb7..778c738d 100644 --- a/src/pulsecore/resampler.h +++ b/src/pulsecore/resampler.h @@ -49,6 +49,12 @@ typedef enum pa_resample_method { PA_RESAMPLER_MAX } pa_resample_method_t; +typedef enum pa_resample_flags { + PA_RESAMPLER_VARIABLE_RATE = 1, + PA_RESAMPLER_NO_REMAP = 2, /* implies NO_REMIX */ + PA_RESAMPLER_NO_REMIX = 4 +} pa_resample_flags_t; + pa_resampler* pa_resampler_new( pa_mempool *pool, const pa_sample_spec *a, @@ -56,7 +62,7 @@ pa_resampler* pa_resampler_new( const pa_sample_spec *b, const pa_channel_map *bm, pa_resample_method_t resample_method, - int variable_rate); + pa_resample_flags_t flags); void pa_resampler_free(pa_resampler *r); diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 6f654b61..730f3e5c 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -154,7 +154,7 @@ pa_sink_input* pa_sink_input_new( &data->sample_spec, &data->channel_map, &data->sink->sample_spec, &data->sink->channel_map, data->resample_method, - !!(flags & PA_SINK_INPUT_VARIABLE_RATE)))) { + (flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0))) { pa_log_warn("Unsupported resampling operation."); return NULL; } @@ -750,7 +750,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { &i->sample_spec, &i->channel_map, &dest->sample_spec, &dest->channel_map, i->resample_method, - !!(i->flags & PA_SINK_INPUT_VARIABLE_RATE)))) { + (i->flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0))) { pa_log_warn("Unsupported resampling operation."); return -1; } diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 2a902dc2..5c52419e 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -122,7 +122,7 @@ pa_source_output* pa_source_output_new( &data->source->sample_spec, &data->source->channel_map, &data->sample_spec, &data->channel_map, data->resample_method, - !!(flags & PA_SOURCE_OUTPUT_VARIABLE_RATE)))) { + (flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0))) { pa_log_warn("Unsupported resampling operation."); return NULL; } @@ -415,7 +415,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { &dest->sample_spec, &dest->channel_map, &o->sample_spec, &o->channel_map, o->resample_method, - !!(o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE)))) { + (o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0))) { pa_log_warn("Unsupported resampling operation."); return -1; } diff --git a/src/tests/remix-test.c b/src/tests/remix-test.c new file mode 100644 index 00000000..d2fa6943 --- /dev/null +++ b/src/tests/remix-test.c @@ -0,0 +1,91 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +int main(int argc, char *argv[]) { + + static const pa_channel_map maps[] = { + { 1, { PA_CHANNEL_POSITION_MONO } }, + { 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT } }, + { 3, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_CENTER } }, + { 3, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_LFE } }, + { 3, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_REAR_CENTER } }, + { 4, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_CENTER, PA_CHANNEL_POSITION_LFE } }, + { 4, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_CENTER, PA_CHANNEL_POSITION_REAR_CENTER } }, + { 4, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT } }, + { 5, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_CENTER } }, + { 5, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_LFE } }, + { 6, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_LFE, PA_CHANNEL_POSITION_CENTER } }, + { 8, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_LFE, PA_CHANNEL_POSITION_CENTER, PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT } }, + { 0, { 0 } } + }; + + unsigned i, j; + pa_mempool *pool; + + oil_init(); + pa_log_set_maximal_level(PA_LOG_DEBUG); + + pa_assert_se(pool = pa_mempool_new(FALSE)); + + for (i = 0; maps[i].channels > 0; i++) + for (j = 0; maps[j].channels > 0; j++) { + char a[PA_CHANNEL_MAP_SNPRINT_MAX], b[PA_CHANNEL_MAP_SNPRINT_MAX]; + pa_resampler *r; + pa_sample_spec ss1, ss2; + + pa_log_info("Converting from '%s' to '%s'.\n", pa_channel_map_snprint(a, sizeof(a), &maps[i]), pa_channel_map_snprint(b, sizeof(b), &maps[j])); + + ss1.channels = maps[i].channels; + ss2.channels = maps[j].channels; + + ss1.rate = ss2.rate = 44100; + ss1.format = ss2.format = PA_SAMPLE_S16NE; + + r = pa_resampler_new(pool, &ss1, &maps[i], &ss2, &maps[j], PA_RESAMPLER_AUTO, 0); + + /* We don't really care for the resampler. We just want to + * see the remixing debug output. */ + + pa_resampler_free(r); + } + + + pa_mempool_free(pool); + + return 0; +} diff --git a/src/tests/resampler-test.c b/src/tests/resampler-test.c index 5295995b..820a0c1e 100644 --- a/src/tests/resampler-test.c +++ b/src/tests/resampler-test.c @@ -222,8 +222,8 @@ int main(int argc, char *argv[]) { pa_sample_format_to_string(b.format), pa_sample_format_to_string(a.format)); - pa_assert_se(forth = pa_resampler_new(pool, &a, NULL, &b, NULL, PA_RESAMPLER_AUTO, FALSE)); - pa_assert_se(back = pa_resampler_new(pool, &b, NULL, &a, NULL, PA_RESAMPLER_AUTO, FALSE)); + pa_assert_se(forth = pa_resampler_new(pool, &a, NULL, &b, NULL, PA_RESAMPLER_AUTO, 0)); + pa_assert_se(back = pa_resampler_new(pool, &b, NULL, &a, NULL, PA_RESAMPLER_AUTO, 0)); i.memblock = generate_block(pool, &a); i.length = pa_memblock_get_length(i.memblock); -- cgit From e043eaad9463ce1241b0049814d20bb2a7340990 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 11 Nov 2007 22:59:34 +0000 Subject: add new function pa_strnull() to simplify passing null strings to non-linux printf() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2045 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/macro.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pulsecore/macro.h b/src/pulsecore/macro.h index 4b62dd21..41af19c9 100644 --- a/src/pulsecore/macro.h +++ b/src/pulsecore/macro.h @@ -152,4 +152,8 @@ typedef int pa_bool_t; #define PA_PATH_SEP_CHAR '/' #endif +static inline const char *pa_strnull(const char *x) { + return x ? x : "(null)"; +} + #endif -- cgit From daf3a3ed8f2ee926df416617ca7b9b3823fdfa4c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 11 Nov 2007 23:00:38 +0000 Subject: pull code for starting helper processes out of module-gconf, clean it up, and stick into a new API pa_start_child_for_read() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2046 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/start-child.c | 162 ++++++++++++++++++++++++++++++++++++++++++++ src/pulsecore/start-child.h | 32 +++++++++ 2 files changed, 194 insertions(+) create mode 100644 src/pulsecore/start-child.c create mode 100644 src/pulsecore/start-child.h diff --git a/src/pulsecore/start-child.c b/src/pulsecore/start-child.c new file mode 100644 index 00000000..e01011d6 --- /dev/null +++ b/src/pulsecore/start-child.c @@ -0,0 +1,162 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2007 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_PRCTL_H +#include +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif + +#include +#include + +#include "start-child.h" + +int pa_start_child_for_read(const char *name, const char *argv1, pid_t *pid) { + pid_t child; + int pipe_fds[2] = { -1, -1 }; + + if (pipe(pipe_fds) < 0) { + pa_log("pipe() failed: %s", pa_cstrerror(errno)); + goto fail; + } + + if ((child = fork()) == (pid_t) -1) { + pa_log("fork() failed: %s", pa_cstrerror(errno)); + goto fail; + + } else if (child != 0) { + + /* Parent */ + pa_assert_se(pa_close(pipe_fds[1]) == 0); + + if (pid) + *pid = child; + + return pipe_fds[0]; + } else { +#ifdef __linux__ + DIR* d; +#endif + int max_fd, i; + + /* child */ + + pa_reset_priority(); + + pa_assert_se(pa_close(pipe_fds[0]) == 0); + pa_assert_se(dup2(pipe_fds[1], 1) == 1); + + if (pipe_fds[1] != 1) + pa_assert_se(pa_close(pipe_fds[1]) == 0); + + pa_close(0); + pa_assert_se(open("/dev/null", O_RDONLY) == 0); + + pa_close(2); + pa_assert_se(open("/dev/null", O_WRONLY) == 2); + +#ifdef __linux__ + + if ((d = opendir("/proc/self/fd/"))) { + + struct dirent *de; + + while ((de = readdir(d))) { + char *e = NULL; + int fd; + + if (de->d_name[0] == '.') + continue; + + errno = 0; + fd = strtol(de->d_name, &e, 10); + pa_assert(errno == 0 && e && *e == 0); + + if (fd >= 3 && dirfd(d) != fd) + pa_close(fd); + } + + closedir(d); + } else { + +#endif + + max_fd = 1024; + +#ifdef HAVE_SYS_RESOURCE_H + { + struct rlimit r; + if (getrlimit(RLIMIT_NOFILE, &r) == 0) + max_fd = r.rlim_max; + } +#endif + + for (i = 3; i < max_fd; i++) + pa_close(i); + +#ifdef __linux__ + } +#endif + +#ifdef PR_SET_PDEATHSIG + /* On Linux we can use PR_SET_PDEATHSIG to have the helper + process killed when the daemon dies abnormally. On non-Linux + machines the client will die as soon as it writes data to + stdout again (SIGPIPE) */ + + prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); +#endif + +#ifdef SIGPIPE + /* Make sure that SIGPIPE kills the child process */ + signal(SIGPIPE, SIG_DFL); +#endif + +#ifdef SIGTERM + /* Make sure that SIGTERM kills the child process */ + signal(SIGTERM, SIG_DFL); +#endif + + execl(name, name, argv1, NULL); + _exit(1); + } + +fail: + pa_close_pipe(pipe_fds); + + return -1; +} diff --git a/src/pulsecore/start-child.h b/src/pulsecore/start-child.h new file mode 100644 index 00000000..359b5044 --- /dev/null +++ b/src/pulsecore/start-child.h @@ -0,0 +1,32 @@ +#ifndef foopulsestartchildhfoo +#define foopulsestartchildhfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2007 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +int pa_start_child_for_read(const char *name, const char *argv1, pid_t *pid); + +#endif -- cgit From e8092bede9c2c9daac6c6035ca7a130b2c9a7e5b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 11 Nov 2007 23:01:44 +0000 Subject: Port module-gconf to make use of the new API pa_start_child_for_read() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2047 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/gconf/module-gconf.c | 137 +++------------------------------------ 1 file changed, 9 insertions(+), 128 deletions(-) diff --git a/src/modules/gconf/module-gconf.c b/src/modules/gconf/module-gconf.c index fa9ab1cc..836157d0 100644 --- a/src/modules/gconf/module-gconf.c +++ b/src/modules/gconf/module-gconf.c @@ -33,23 +33,16 @@ #include #include #include -#include - -#ifdef HAVE_SYS_PRCTL_H -#include -#endif -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif +#include #include #include #include #include #include #include -#include #include +#include #include "module-gconf-symdef.h" @@ -337,119 +330,6 @@ static void io_event_cb( } } -static int start_client(const char *n, pid_t *pid) { - pid_t child; - int pipe_fds[2] = { -1, -1 }; - - if (pipe(pipe_fds) < 0) { - pa_log("pipe() failed: %s", pa_cstrerror(errno)); - goto fail; - } - - if ((child = fork()) == (pid_t) -1) { - pa_log("fork() failed: %s", pa_cstrerror(errno)); - goto fail; - } else if (child != 0) { - - /* Parent */ - close(pipe_fds[1]); - - if (pid) - *pid = child; - - return pipe_fds[0]; - } else { -#ifdef __linux__ - DIR* d; -#endif - int max_fd, i; - /* child */ - - pa_reset_priority(); - - close(pipe_fds[0]); - dup2(pipe_fds[1], 1); - - if (pipe_fds[1] != 1) - close(pipe_fds[1]); - - close(0); - open("/dev/null", O_RDONLY); - - close(2); - open("/dev/null", O_WRONLY); - -#ifdef __linux__ - - if ((d = opendir("/proc/self/fd/"))) { - - struct dirent *de; - - while ((de = readdir(d))) { - char *e = NULL; - int fd; - - if (de->d_name[0] == '.') - continue; - - errno = 0; - fd = strtol(de->d_name, &e, 10); - pa_assert(errno == 0 && e && *e == 0); - - if (fd >= 3 && dirfd(d) != fd) - close(fd); - } - - closedir(d); - } else { - -#endif - - max_fd = 1024; - -#ifdef HAVE_SYS_RESOURCE_H - { - struct rlimit r; - if (getrlimit(RLIMIT_NOFILE, &r) == 0) - max_fd = r.rlim_max; - } -#endif - - for (i = 3; i < max_fd; i++) - close(i); -# -#ifdef __linux__ - } -#endif - -#ifdef PR_SET_PDEATHSIG - /* On Linux we can use PR_SET_PDEATHSIG to have the helper - process killed when the daemon dies abnormally. On non-Linux - machines the client will die as soon as it writes data to - stdout again (SIGPIPE) */ - - prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); -#endif - -#ifdef SIGPIPE - /* Make sure that SIGPIPE kills the child process */ - signal(SIGPIPE, SIG_DFL); -#endif - - execl(n, n, NULL); - _exit(1); - } - -fail: - if (pipe_fds[0] >= 0) - close(pipe_fds[0]); - - if (pipe_fds[1] >= 0) - close(pipe_fds[1]); - - return -1; -} - int pa__init(pa_module*m) { struct userdata *u; int r; @@ -465,7 +345,7 @@ int pa__init(pa_module*m) { u->io_event = NULL; u->buf_fill = 0; - if ((u->fd = start_client(PA_GCONF_HELPER, &u->pid)) < 0) + if ((u->fd = pa_start_child_for_read(PA_GCONF_HELPER, NULL, &u->pid)) < 0) goto fail; u->io_event = m->core->mainloop->io_new( @@ -498,16 +378,17 @@ void pa__done(pa_module*m) { if (!(u = m->userdata)) return; + if (u->pid != (pid_t) -1) { + kill(u->pid, SIGTERM); + waitpid(u->pid, NULL, 0); + } + if (u->io_event) m->core->mainloop->io_free(u->io_event); if (u->fd >= 0) - close(u->fd); + pa_close(u->fd); - if (u->pid != (pid_t) -1) { - kill(u->pid, SIGTERM); - waitpid(u->pid, NULL, 0); - } if (u->module_infos) pa_hashmap_free(u->module_infos, module_info_free, u); -- cgit From 5054f3623ff82ab0c263e15c47779b0caa841b29 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 11 Nov 2007 23:18:19 +0000 Subject: add new fun module that automatically mutes your audio devices when you leave with your bluetooth phone, and unmutes when you come back git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2048 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 36 +++ src/Makefile.am | 26 +- src/modules/bt-proximity-helper.c | 210 ++++++++++++++++ src/modules/module-bt-proximity.c | 492 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 763 insertions(+), 1 deletion(-) create mode 100644 src/modules/bt-proximity-helper.c create mode 100644 src/modules/module-bt-proximity.c diff --git a/configure.ac b/configure.ac index f6e548bc..b5834f0f 100644 --- a/configure.ac +++ b/configure.ac @@ -789,6 +789,36 @@ AC_SUBST(HAL_LIBS) AC_SUBST(HAVE_HAL) AM_CONDITIONAL([HAVE_HAL], [test "x$HAVE_HAL" = x1]) +#### BlueZ support (optional) #### + +AC_ARG_ENABLE([bluez], + AC_HELP_STRING([--disable-bluez], [Disable optional BlueZ support]), + [ + case "${enableval}" in + yes) bluez=yes ;; + no) bluez=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-bluez) ;; + esac + ], + [bluez=auto]) +if test "x${bluez}" != xno ; then + PKG_CHECK_MODULES(BLUEZ, [ bluez >= 3.0 ], + HAVE_BLUEZ=1, + [ + HAVE_BLUEZ=0 + if test "x$bluez" = xyes ; then + AC_MSG_ERROR([*** BLUEZ support not found]) + fi + ]) +else + HAVE_BLUEZ=0 +fi + +AC_SUBST(BLUEZ_CFLAGS) +AC_SUBST(BLUEZ_LIBS) +AC_SUBST(HAVE_BLUEZ) +AM_CONDITIONAL([HAVE_BLUEZ], [test "x$HAVE_BLUEZ" = x1]) + #### D-Bus support (optional) #### AC_ARG_ENABLE([dbus], @@ -1028,6 +1058,11 @@ if test "x${HAVE_LIBSAMPLERATE}" = "x1" ; then ENABLE_LIBSAMPLERATE=yes fi +ENABLE_BLUEZ=no +if test "x${HAVE_BLUEZ}" = "x1" ; then + ENABLE_BLUEZ=yes +fi + echo " ---{ $PACKAGE_NAME $VERSION }--- @@ -1048,6 +1083,7 @@ echo " Enable Async DNS: ${ENABLE_LIBASYNCNS} Enable LIRC: ${ENABLE_LIRC} Enable HAL: ${ENABLE_HAL} + Enable BlueZ: ${ENABLE_BLUEZ} Enable TCP Wrappers: ${ENABLE_TCPWRAP} Enable libsamplerate: ${ENABLE_LIBSAMPLERATE} System User: ${PA_SYSTEM_USER} diff --git a/src/Makefile.am b/src/Makefile.am index 1a24a529..36d27ef4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -736,6 +736,7 @@ libpulsecore_la_SOURCES += \ pulsecore/macro.h \ pulsecore/once.c pulsecore/once.h \ pulsecore/time-smoother.c pulsecore/time-smoother.h \ + pulsecore/start-child.c pulsecore/start-child.h \ $(PA_THREAD_OBJS) if OS_IS_WIN32 @@ -1052,11 +1053,13 @@ modlibexec_LTLIBRARIES += \ module-jack-source.la endif +pulselibexec_PROGRAMS = + if HAVE_GCONF modlibexec_LTLIBRARIES += \ module-gconf.la -pulselibexec_PROGRAMS = \ +pulselibexec_PROGRAMS += \ gconf-helper endif @@ -1071,6 +1074,14 @@ modlibexec_LTLIBRARIES += \ module-hal-detect.la endif +if HAVE_BLUEZ +modlibexec_LTLIBRARIES += \ + module-bt-proximity.la + +pulselibexec_PROGRAMS += \ + bt-proximity-helper +endif + # These are generated by a M4 script SYMDEF_FILES = \ @@ -1121,6 +1132,7 @@ SYMDEF_FILES = \ modules/module-rescue-streams-symdef.h \ modules/module-suspend-on-idle-symdef.h \ modules/module-hal-detect-symdef.h \ + modules/module-bt-proximity-symdef.h \ modules/gconf/module-gconf-symdef.h EXTRA_DIST += $(SYMDEF_FILES) @@ -1419,6 +1431,17 @@ gconf_helper_LDADD = $(AM_LDADD) $(GCONF_LIBS) libpulsecore.la gconf_helper_CFLAGS = $(AM_CFLAGS) $(GCONF_CFLAGS) gconf_helper_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +# Bluetooth proximity +module_bt_proximity_la_SOURCES = modules/module-bt-proximity.c +module_bt_proximity_la_LDFLAGS = -module -avoid-version +module_bt_proximity_la_LIBADD = $(AM_LIBADD) $(DBUS_LIBS) libpulsecore.la libdbus-util.la +module_bt_proximity_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) -DPA_BT_PROXIMITY_HELPER=\"$(pulselibexecdir)/bt-proximity-helper\" + +bt_proximity_helper_SOURCES = modules/bt-proximity-helper.c +bt_proximity_helper_LDADD = $(AM_LDADD) $(BLUEZ_LIBS) +bt_proximity_helper_CFLAGS = $(AM_CFLAGS) $(BLUEZ_CFLAGS) +bt_proximity_helper_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + ################################### # Some minor stuff # ################################### @@ -1455,6 +1478,7 @@ daemon.conf: daemon/daemon.conf.in Makefile install-exec-hook: chown root $(DESTDIR)$(bindir)/pulseaudio ; true chmod u+s $(DESTDIR)$(bindir)/pulseaudio + chmod u+s $(DESTDIR)$(pulselibexecdir)/bt-proximity-helper ln -sf pacat $(DESTDIR)$(bindir)/parec rm -f $(DESTDIR)$(modlibexecdir)/*.a rm -f $(DESTDIR)$(libdir)/libpulsedsp.a diff --git a/src/modules/bt-proximity-helper.c b/src/modules/bt-proximity-helper.c new file mode 100644 index 00000000..d80cc0c1 --- /dev/null +++ b/src/modules/bt-proximity-helper.c @@ -0,0 +1,210 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2007 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* + * Small SUID helper that allows us to ping a BT device. Borrows + * heavily from bluez-utils' l2ping, which is licensed as GPL2+, too + * and comes with a copyright like this: + * + * Copyright (C) 2000-2001 Qualcomm Incorporated + * Copyright (C) 2002-2003 Maxim Krasnyansky + * Copyright (C) 2002-2007 Marcel Holtmann + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#undef NDEBUG + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define PING_STRING "PulseAudio" +#define IDENT 200 +#define TIMEOUT 4 +#define INTERVAL 2 + +static void update_status(int found) { + static int status = -1; + + if (!found && status != 0) + printf("-"); + if (found && status <= 0) + printf("+"); + + fflush(stdout); + status = !!found; +} + +int main(int argc, char *argv[]) { + struct sockaddr_l2 addr; + union { + l2cap_cmd_hdr hdr; + uint8_t buf[L2CAP_CMD_HDR_SIZE + sizeof(PING_STRING)]; + } packet; + int fd = -1; + uint8_t id = IDENT; + int connected = 0; + + assert(argc == 2); + + for (;;) { + fd_set fds; + struct timeval end; + ssize_t r; + + if (!connected) { + + if (fd >= 0) + close(fd); + + if ((fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP)) < 0) { + fprintf(stderr, "socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP) failed: %s", strerror(errno)); + goto finish; + } + + memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + bacpy(&addr.l2_bdaddr, BDADDR_ANY); + + if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + fprintf(stderr, "bind() failed: %s", strerror(errno)); + goto finish; + } + + memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + str2ba(argv[1], &addr.l2_bdaddr); + + if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + + if (errno == EHOSTDOWN || errno == ECONNRESET || errno == ETIMEDOUT) { + update_status(0); + sleep(INTERVAL); + continue; + } + + fprintf(stderr, "connect() failed: %s", strerror(errno)); + goto finish; + } + + connected = 1; + } + + assert(connected); + + memset(&packet, 0, sizeof(packet)); + strcpy((char*) packet.buf + L2CAP_CMD_HDR_SIZE, PING_STRING); + packet.hdr.ident = id; + packet.hdr.len = htobs(sizeof(PING_STRING)); + packet.hdr.code = L2CAP_ECHO_REQ; + + if ((r = send(fd, &packet, sizeof(packet), 0)) < 0) { + + if (errno == EHOSTDOWN || errno == ECONNRESET || errno == ETIMEDOUT) { + update_status(0); + connected = 0; + sleep(INTERVAL); + continue; + } + + fprintf(stderr, "send() failed: %s", strerror(errno)); + goto finish; + } + + assert(r == sizeof(packet)); + + gettimeofday(&end, NULL); + end.tv_sec += TIMEOUT; + + for (;;) { + struct timeval now, delta; + + gettimeofday(&now, NULL); + + if (timercmp(&end, &now, <=)) { + update_status(0); + connected = 0; + sleep(INTERVAL); + break; + } + + timersub(&end, &now, &delta); + + FD_ZERO(&fds); + FD_SET(fd, &fds); + + if (select(fd+1, &fds, NULL, NULL, &delta) < 0) { + fprintf(stderr, "select() failed: %s", strerror(errno)); + goto finish; + } + + if ((r = recv(fd, &packet, sizeof(packet), 0)) <= 0) { + + if (errno == EHOSTDOWN || errno == ECONNRESET || errno == ETIMEDOUT) { + update_status(0); + connected = 0; + sleep(INTERVAL); + break; + } + + fprintf(stderr, "send() failed: %s", r == 0 ? "EOF" : strerror(errno)); + goto finish; + } + + assert(r >= L2CAP_CMD_HDR_SIZE); + + if (packet.hdr.ident != id) + continue; + + if (packet.hdr.code == L2CAP_ECHO_RSP || packet.hdr.code == L2CAP_COMMAND_REJ) { + + if (++id >= 0xFF) + id = IDENT; + + update_status(1); + sleep(INTERVAL); + break; + } + } + } + +finish: + + if (fd >= 0) + close(fd); + + return 1; +} diff --git a/src/modules/module-bt-proximity.c b/src/modules/module-bt-proximity.c new file mode 100644 index 00000000..f6125233 --- /dev/null +++ b/src/modules/module-bt-proximity.c @@ -0,0 +1,492 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2005-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dbus-util.h" +#include "module-bt-proximity-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("Bluetooth Proximity Volume Control"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); +PA_MODULE_USAGE( + "sink= " + "hci= " +); + +#define DEFAULT_HCI "hci0" + +static const char* const valid_modargs[] = { + "sink", + "rssi", + "hci", + NULL, +}; + +struct bonding { + struct userdata *userdata; + char address[18]; + + pid_t pid; + int fd; + + pa_io_event *io_event; + + enum { + UNKNOWN, + FOUND, + NOT_FOUND + } state; +}; + +struct userdata { + pa_module *module; + pa_dbus_connection *dbus_connection; + + char *sink_name; + char *hci, *hci_path; + + pa_hashmap *bondings; + + unsigned n_found; + unsigned n_unknown; + + pa_bool_t muted; +}; + +static void update_volume(struct userdata *u) { + pa_assert(u); + + if (u->muted && u->n_found > 0) { + pa_sink *s; + + u->muted = FALSE; + + if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, FALSE))) { + pa_log_warn("Sink device '%s' not available for unmuting.", pa_strnull(u->sink_name)); + return; + } + + pa_log_info("Found %u BT devices, unmuting.", u->n_found); + pa_sink_set_mute(s, FALSE); + + } else if (!u->muted && (u->n_found+u->n_unknown) <= 0) { + pa_sink *s; + + u->muted = TRUE; + + if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, FALSE))) { + pa_log_warn("Sink device '%s' not available for muting.", pa_strnull(u->sink_name)); + return; + } + + pa_log_info("No BT devices found, muting."); + pa_sink_set_mute(s, TRUE); + + } else + pa_log_info("%u devices now active, %u with unknown state.", u->n_found, u->n_unknown); +} + +static void bonding_free(struct bonding *b) { + pa_assert(b); + + if (b->state == FOUND) + pa_assert_se(b->userdata->n_found-- >= 1); + + if (b->state == UNKNOWN) + pa_assert_se(b->userdata->n_unknown-- >= 1); + + if (b->pid != (pid_t) -1) { + kill(b->pid, SIGTERM); + waitpid(b->pid, NULL, 0); + } + + if (b->fd >= 0) + pa_close(b->fd); + + if (b->io_event) + b->userdata->module->core->mainloop->io_free(b->io_event); + + pa_xfree(b); +} + +static void io_event_cb( + pa_mainloop_api*a, + pa_io_event* e, + int fd, + pa_io_event_flags_t events, + void *userdata) { + + struct bonding *b = userdata; + char x; + ssize_t r; + + pa_assert(b); + + if ((r = read(fd, &x, 1)) <= 0) { + pa_log_warn("Child watching '%s' died abnormally: %s", b->address, r == 0 ? "EOF" : pa_cstrerror(errno)); + + pa_assert_se(pa_hashmap_remove(b->userdata->bondings, b->address) == b); + bonding_free(b); + return; + } + + pa_assert_se(r == 1); + + if (b->state == UNKNOWN) + pa_assert_se(b->userdata->n_unknown-- >= 1); + + if (x == '+') { + pa_assert(b->state == UNKNOWN || b->state == NOT_FOUND); + + b->state = FOUND; + b->userdata->n_found++; + + pa_log_info("Device '%s' is alive.", b->address); + + } else { + pa_assert(x == '-'); + pa_assert(b->state == UNKNOWN || b->state == FOUND); + + if (b->state == FOUND) + b->userdata->n_found--; + + b->state = NOT_FOUND; + + pa_log_info("Device '%s' is dead.", b->address); + } + + update_volume(b->userdata); +} + +static struct bonding* bonding_new(struct userdata *u, const char *a) { + struct bonding *b = NULL; + DBusMessage *m = NULL, *r = NULL; + DBusError e; + const char *class; + + pa_assert(u); + pa_assert(a); + + pa_return_val_if_fail(strlen(a) == 17, NULL); + pa_return_val_if_fail(!pa_hashmap_get(u->bondings, a), NULL); + + dbus_error_init(&e); + + pa_assert_se(m = dbus_message_new_method_call("org.bluez", u->hci_path, "org.bluez.Adapter", "GetRemoteMajorClass")); + pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_STRING, &a, DBUS_TYPE_INVALID)); + r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->dbus_connection), m, -1, &e); + + if (!r) { + pa_log("org.bluez.Adapter.GetRemoteMajorClass(%s) failed: %s", a, e.message); + goto fail; + } + + if (!(dbus_message_get_args(r, &e, DBUS_TYPE_STRING, &class, DBUS_TYPE_INVALID))) { + pa_log("Malformed org.bluez.Adapter.GetRemoteMajorClass signal: %s", e.message); + goto fail; + } + + if (strcmp(class, "phone")) { + pa_log_info("Found device '%s' of class '%s', ignoring.", a, class); + goto fail; + } + + b = pa_xnew(struct bonding, 1); + b->userdata = u; + pa_strlcpy(b->address, a, sizeof(b->address)); + b->pid = (pid_t) -1; + b->fd = -1; + b->io_event = NULL; + b->state = UNKNOWN; + u->n_unknown ++; + + pa_log_info("Watching device '%s' of class '%s'.", b->address, class); + + if ((b->fd = pa_start_child_for_read(PA_BT_PROXIMITY_HELPER, a, &b->pid)) < 0) { + pa_log("Failed to start helper tool."); + goto fail; + } + + b->io_event = u->module->core->mainloop->io_new( + u->module->core->mainloop, + b->fd, + PA_IO_EVENT_INPUT, + io_event_cb, + b); + + dbus_message_unref(m); + dbus_message_unref(r); + + pa_hashmap_put(u->bondings, a, b); + + return b; + +fail: + if (m) + dbus_message_unref(m); + if (r) + dbus_message_unref(r); + + if (b) + bonding_free(b); + + dbus_error_free(&e); + return NULL; +} + +static void bonding_remove(struct userdata *u, const char *a) { + struct bonding *b; + pa_assert(u); + + pa_return_if_fail((b = pa_hashmap_remove(u->bondings, a))); + + pa_log_info("No longer watching device '%s'", b->address); + bonding_free(b); +} + +static DBusHandlerResult filter_func(DBusConnection *connection, DBusMessage *m, void *userdata) { + struct userdata *u = userdata; + DBusError e; + + dbus_error_init(&e); + + if (dbus_message_is_signal(m, "org.bluez.Adapter", "BondingCreated")) { + const char *a; + + if (!(dbus_message_get_args(m, &e, DBUS_TYPE_STRING, &a, DBUS_TYPE_INVALID))) { + pa_log("Malformed org.bluez.Adapter.BondingCreated signal: %s", e.message); + goto finish; + } + + bonding_new(u, a); + + return DBUS_HANDLER_RESULT_HANDLED; + + } else if (dbus_message_is_signal(m, "org.bluez.Adapter", "BondingRemoved")) { + + const char *a; + + if (!(dbus_message_get_args(m, &e, DBUS_TYPE_STRING, &a, DBUS_TYPE_INVALID))) { + pa_log("Malformed org.bluez.Adapter.BondingRemoved signal: %s", e.message); + goto finish; + } + + bonding_remove(u, a); + + return DBUS_HANDLER_RESULT_HANDLED; + } + +finish: + + dbus_error_free(&e); + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static int add_matches(struct userdata *u, pa_bool_t add) { + char *filter1, *filter2; + DBusError e; + int r = -1; + + pa_assert(u); + dbus_error_init(&e); + + filter1 = pa_sprintf_malloc("type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='BondingCreated',path='%s'", u->hci_path); + filter2 = pa_sprintf_malloc("type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='BondingRemoved',path='%s'", u->hci_path); + + if (add) { + dbus_bus_add_match(pa_dbus_connection_get(u->dbus_connection), filter1, &e); + + if (dbus_error_is_set(&e)) { + pa_log("dbus_bus_add_match(%s) failed: %s", filter1, e.message); + goto finish; + } + } else + dbus_bus_remove_match(pa_dbus_connection_get(u->dbus_connection), filter1, &e); + + + if (add) { + dbus_bus_add_match(pa_dbus_connection_get(u->dbus_connection), filter2, &e); + + if (dbus_error_is_set(&e)) { + pa_log("dbus_bus_add_match(%s) failed: %s", filter2, e.message); + dbus_bus_remove_match(pa_dbus_connection_get(u->dbus_connection), filter2, &e); + goto finish; + } + } else + dbus_bus_remove_match(pa_dbus_connection_get(u->dbus_connection), filter2, &e); + + + if (add) + pa_assert_se(dbus_connection_add_filter(pa_dbus_connection_get(u->dbus_connection), filter_func, u, NULL)); + else + dbus_connection_remove_filter(pa_dbus_connection_get(u->dbus_connection), filter_func, u); + + r = 0; + +finish: + pa_xfree(filter1); + pa_xfree(filter2); + dbus_error_free(&e); + + return r; +} + +int pa__init(pa_module*m) { + pa_modargs *ma = NULL; + struct userdata *u; + DBusError e; + DBusMessage *msg = NULL, *r = NULL; + DBusMessageIter iter, sub; + + pa_assert(m); + dbus_error_init(&e); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log("Failed to parse module arguments"); + goto fail; + } + + m->userdata = u = pa_xnew0(struct userdata, 1); + u->module = m; + u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); + u->hci = pa_xstrdup(pa_modargs_get_value(ma, "hci", DEFAULT_HCI)); + u->hci_path = pa_sprintf_malloc("/org/bluez/%s", u->hci); + u->n_found = u->n_unknown = 0; + u->muted = FALSE; + + u->bondings = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + + if (!(u->dbus_connection = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &e))) { + pa_log("Failed to get D-Bus connection: %s", e.message); + goto fail; + } + + if (add_matches(u, TRUE) < 0) + goto fail; + + pa_assert_se(msg = dbus_message_new_method_call("org.bluez", u->hci_path, "org.bluez.Adapter", "ListBondings")); + + if (!(r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->dbus_connection), msg, -1, &e))) { + pa_log("org.bluez.Adapter.ListBondings failed: %s", e.message); + goto fail; + } + + dbus_message_iter_init(r, &iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { + pa_log("Malformed reply to org.bluez.Adapter.ListBondings."); + goto fail; + } + + dbus_message_iter_recurse(&iter, &sub); + + while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) { + const char *a = NULL; + + dbus_message_iter_get_basic(&sub, &a); + bonding_new(u, a); + + dbus_message_iter_next(&sub); + } + + dbus_message_unref(r); + dbus_message_unref(msg); + + pa_modargs_free(ma); + + if (pa_hashmap_size(u->bondings) == 0) + pa_log_warn("Warning: no phone device bonded."); + + update_volume(u); + + return 0; + +fail: + + if (ma) + pa_modargs_free(ma); + + pa__done(m); + + dbus_error_free(&e); + + if (msg) + dbus_message_unref(msg); + + if (r) + dbus_message_unref(r); + + return -1; +} + +void pa__done(pa_module*m) { + struct userdata *u; + pa_assert(m); + + if (!(u = m->userdata)) + return; + + if (u->bondings) { + struct bonding *b; + + while ((b = pa_hashmap_steal_first(u->bondings))) + bonding_free(b); + + pa_hashmap_free(u->bondings, NULL, NULL); + } + + if (u->dbus_connection) { + add_matches(u, FALSE); + pa_dbus_connection_unref(u->dbus_connection); + } + + pa_xfree(u->sink_name); + pa_xfree(u->hci_path); + pa_xfree(u->hci); + pa_xfree(u); +} -- cgit From f7528825257d5d4b056268da3c82181f520a8ff6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 13 Nov 2007 17:35:48 +0000 Subject: fix loading of load-once modules if no other modules was loaded before git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2049 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/module.c b/src/pulsecore/module.c index e1680de5..ae140ff4 100644 --- a/src/pulsecore/module.c +++ b/src/pulsecore/module.c @@ -86,7 +86,7 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { if ((load_once = (pa_bool_t (*)(void)) pa_load_sym(m->dl, name, PA_SYMBOL_LOAD_ONCE))) { - if (load_once()) { + if (load_once() && c->modules) { pa_module *i; uint32_t idx; /* OK, the module only wants to be loaded once, let's make sure it is */ -- cgit From d17bb53d3ebfbd7046719400264bd87830c140d8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 13 Nov 2007 17:37:44 +0000 Subject: Completely rework ALSA device selection code: choose the device to open depending on the requested number of channels and channel map. In most cases it will now suffice to set default-channels=6 to enable 5.1 sound for all devices that support it git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2050 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 252 +++++++++++++++++++++++++++++++++++--- src/modules/alsa-util.h | 29 ++++- src/modules/module-alsa-sink.c | 85 ++++++------- src/modules/module-alsa-source.c | 69 +++++------ src/modules/module-bt-proximity.c | 2 +- src/modules/module-cli.c | 2 +- src/modules/module-detect.c | 3 +- src/modules/module-hal-detect.c | 4 +- src/modules/module-oss.c | 2 +- src/modules/rtp/module-rtp-send.c | 9 +- src/pulsecore/modargs.c | 2 +- src/pulsecore/modargs.h | 3 +- src/pulsecore/protocol-esound.c | 2 +- src/pulsecore/protocol-native.c | 4 +- src/pulsecore/protocol-simple.c | 4 +- 15 files changed, 350 insertions(+), 122 deletions(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 15ae1fc6..5b74c98c 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -34,6 +34,7 @@ #include #include +#include #include "alsa-util.h" @@ -284,13 +285,21 @@ try_auto: /* Set the hardware parameters of the given ALSA device. Returns the * selected fragment settings in *period and *period_size */ -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size, int *use_mmap) { +int pa_alsa_set_hw_params( + snd_pcm_t *pcm_handle, + pa_sample_spec *ss, + uint32_t *periods, + snd_pcm_uframes_t *period_size, + pa_bool_t *use_mmap, + pa_bool_t require_exact_channel_number) { + int ret = -1; snd_pcm_uframes_t buffer_size; unsigned int r = ss->rate; unsigned int c = ss->channels; pa_sample_format_t f = ss->format; snd_pcm_hw_params_t *hwparams; + pa_bool_t _use_mmap = use_mmap && *use_mmap; pa_assert(pcm_handle); pa_assert(ss); @@ -305,7 +314,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p (ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0) goto finish; - if (use_mmap && *use_mmap) { + if (_use_mmap) { if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) { /* mmap() didn't work, fall back to interleaved */ @@ -313,8 +322,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) goto finish; - if (use_mmap) - *use_mmap = 0; + _use_mmap = FALSE; } } else if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) @@ -326,8 +334,13 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0) goto finish; - if ((ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0) - goto finish; + if (require_exact_channel_number) { + if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, c)) < 0) + goto finish; + } else { + if ((ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0) + goto finish; + } if ((*period_size > 0 && (ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, period_size, NULL)) < 0) || (*periods > 0 && (ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0)) @@ -336,23 +349,14 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) goto finish; - if (ss->rate != r) { + if (ss->rate != r) pa_log_warn("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, r); - /* If the sample rate deviates too much, we need to resample */ - if (r < ss->rate*.95 || r > ss->rate*1.05) - ss->rate = r; - } - - if (ss->channels != c) { + if (ss->channels != c) pa_log_warn("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, c); - ss->channels = c; - } - if (ss->format != f) { + if (ss->format != f) pa_log_warn("Device %s doesn't support sample format %s, changed to %s.", snd_pcm_name(pcm_handle), pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f)); - ss->format = f; - } if ((ret = snd_pcm_prepare(pcm_handle)) < 0) goto finish; @@ -361,11 +365,20 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p (ret = snd_pcm_hw_params_get_period_size(hwparams, period_size, NULL)) < 0) goto finish; + /* If the sample rate deviates too much, we need to resample */ + if (r < ss->rate*.95 || r > ss->rate*1.05) + ss->rate = r; + ss->channels = c; + ss->format = f; + pa_assert(buffer_size > 0); pa_assert(*period_size > 0); *periods = buffer_size / *period_size; pa_assert(*periods > 0); + if (use_mmap) + *use_mmap = _use_mmap; + ret = 0; finish: @@ -404,6 +417,209 @@ int pa_alsa_set_sw_params(snd_pcm_t *pcm) { return 0; } +struct device_info { + pa_channel_map map; + const char *name; +}; + +static const struct device_info device_table[] = { + {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT } }, "front" }, + + {{ 4, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT }}, "surround40" }, + + {{ 5, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, + PA_CHANNEL_POSITION_LFE }}, "surround41" }, + + {{ 5, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, + PA_CHANNEL_POSITION_CENTER }}, "surround50" }, + + {{ 6, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, + PA_CHANNEL_POSITION_CENTER, PA_CHANNEL_POSITION_LFE }}, "surround51" }, + + {{ 8, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, + PA_CHANNEL_POSITION_CENTER, PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT }} , "surround71" }, + + {{ 0, { 0 }}, NULL } +}; + +static pa_bool_t channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) { + pa_bool_t in_a[PA_CHANNEL_POSITION_MAX]; + unsigned i; + + pa_assert(a); + pa_assert(b); + + memset(in_a, 0, sizeof(in_a)); + + for (i = 0; i < a->channels; i++) + in_a[a->map[i]] = TRUE; + + for (i = 0; i < b->channels; i++) + if (!in_a[b->map[i]]) + return FALSE; + + return TRUE; +} + +snd_pcm_t *pa_alsa_open_by_device_id( + const char *dev_id, + char **dev, + pa_sample_spec *ss, + pa_channel_map* map, + int mode, + uint32_t *nfrags, + snd_pcm_uframes_t *period_size, + pa_bool_t *use_mmap) { + + int i; + int direction = 1; + int err; + char *d; + snd_pcm_t *pcm_handle; + + pa_assert(dev_id); + pa_assert(dev); + pa_assert(ss); + pa_assert(map); + pa_assert(nfrags); + pa_assert(period_size); + + /* First we try to find a device string with a superset of the + * requested channel map and open it without the plug: prefix. We + * iterate through our device table from top to bottom and take + * the first that matches. If we didn't find a working device that + * way, we iterate backwards, and check all devices that do not + * provide a superset of the requested channel map.*/ + + for (i = 0;; i += direction) { + pa_sample_spec try_ss; + + if (i < 0) { + pa_assert(direction == -1); + + /* OK, so we iterated backwards, and now are at the + * beginning of our list. */ + + break; + + } else if (!device_table[i].name) { + pa_assert(direction == 1); + + /* OK, so we are at the end of our list. at iterated + * forwards. */ + + i--; + direction = -1; + } + + if ((direction > 0) == !channel_map_superset(&device_table[i].map, map)) + continue; + + d = pa_sprintf_malloc("%s:%s", device_table[i].name, dev_id); + pa_log_debug("Trying %s...", d); + + if ((err = snd_pcm_open(&pcm_handle, d, mode, SND_PCM_NONBLOCK)) < 0) { + pa_log_info("Couldn't open PCM device %s: %s", d, snd_strerror(err)); + pa_xfree(d); + continue; + } + + try_ss.channels = device_table[i].map.channels; + try_ss.rate = ss->rate; + try_ss.format = ss->format; + + if ((err = pa_alsa_set_hw_params(pcm_handle, &try_ss, nfrags, period_size, use_mmap, TRUE)) < 0) { + pa_log_info("PCM device %s refused our hw parameters: %s", d, snd_strerror(err)); + pa_xfree(d); + snd_pcm_close(pcm_handle); + continue; + } + + *ss = try_ss; + *map = device_table[i].map; + pa_assert(map->channels == ss->channels); + *dev = d; + return pcm_handle; + } + + /* OK, we didn't find any good device, so let's try the raw hw: stuff */ + + d = pa_sprintf_malloc("hw:%s", dev_id); + pa_log_debug("Trying %s as last resort...", d); + pcm_handle = pa_alsa_open_by_device_string(d, dev, ss, map, mode, nfrags, period_size, use_mmap); + pa_xfree(d); + + return pcm_handle; +} + +snd_pcm_t *pa_alsa_open_by_device_string( + const char *device, + char **dev, + pa_sample_spec *ss, + pa_channel_map* map, + int mode, + uint32_t *nfrags, + snd_pcm_uframes_t *period_size, + pa_bool_t *use_mmap) { + + int err; + char *d; + snd_pcm_t *pcm_handle; + + pa_assert(device); + pa_assert(dev); + pa_assert(ss); + pa_assert(map); + pa_assert(nfrags); + pa_assert(period_size); + + d = pa_xstrdup(device); + + for (;;) { + + if ((err = snd_pcm_open(&pcm_handle, d, mode, SND_PCM_NONBLOCK)) < 0) { + pa_log("Error opening PCM device %s: %s", d, snd_strerror(err)); + pa_xfree(d); + return NULL; + } + + if ((err = pa_alsa_set_hw_params(pcm_handle, ss, nfrags, period_size, use_mmap, FALSE)) < 0) { + + if (err == -EPERM) { + /* Hmm, some hw is very exotic, so we retry with plug, if without it didn't work */ + + if (pa_startswith(d, "hw:")) { + char *t = pa_sprintf_malloc("plughw:%s", d+3); + pa_log_debug("Opening the device as '%s' didn't work, retrying with '%s'.", d, t); + pa_xfree(d); + d = t; + + snd_pcm_close(pcm_handle); + continue; + } + + pa_log("Failed to set hardware parameters on %s: %s", d, snd_strerror(err)); + pa_xfree(d); + snd_pcm_close(pcm_handle); + return NULL; + } + } + + *dev = d; + + if (ss->channels != map->channels) + pa_channel_map_init_auto(map, ss->channels, PA_CHANNEL_MAP_ALSA); + + return pcm_handle; + } +} + int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { int err; diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h index 6f1f927e..36720b03 100644 --- a/src/modules/alsa-util.h +++ b/src/modules/alsa-util.h @@ -38,10 +38,37 @@ struct pa_alsa_fdlist *pa_alsa_fdlist_new(void); void pa_alsa_fdlist_free(struct pa_alsa_fdlist *fdl); int pa_alsa_fdlist_set_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, pa_mainloop_api* m); -int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size, int *use_mmap); +int pa_alsa_set_hw_params( + snd_pcm_t *pcm_handle, + pa_sample_spec *ss, + uint32_t *periods, + snd_pcm_uframes_t *period_size, + pa_bool_t *use_mmap, + pa_bool_t require_exact_channel_number); + int pa_alsa_set_sw_params(snd_pcm_t *pcm); int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev); snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback); +snd_pcm_t *pa_alsa_open_by_device_id( + const char *dev_id, + char **dev, + pa_sample_spec *ss, + pa_channel_map* map, + int mode, + uint32_t *nfrags, + snd_pcm_uframes_t *period_size, + pa_bool_t *use_mmap); + +snd_pcm_t *pa_alsa_open_by_device_string( + const char *device, + char **dev, + pa_sample_spec *ss, + pa_channel_map* map, + int mode, + uint32_t *nfrags, + snd_pcm_uframes_t *period_size, + pa_bool_t *use_mmap); + #endif diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 636b413c..e62b8a06 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -57,6 +57,7 @@ PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "sink_name= " "device= " + "device_id= " "format= " "channels= " "rate= " @@ -89,15 +90,16 @@ struct userdata { char *device_name; - int use_mmap; + pa_bool_t use_mmap; - int first; + pa_bool_t first; pa_rtpoll_item *alsa_rtpoll_item; }; static const char* const valid_modargs[] = { "device", + "device_id", "sink_name", "format", "channels", @@ -127,7 +129,7 @@ static int mmap_write(struct userdata *u) { if (n == -EPIPE) { pa_log_debug("snd_pcm_avail_update: Buffer underrun!"); - u->first = 1; + u->first = TRUE; } if ((err = snd_pcm_recover(u->pcm_handle, n, 1)) == 0) @@ -151,7 +153,7 @@ static int mmap_write(struct userdata *u) { if (err == -EPIPE) { pa_log_debug("snd_pcm_mmap_begin: Buffer underrun!"); - u->first = 1; + u->first = TRUE; } if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0) @@ -188,7 +190,7 @@ static int mmap_write(struct userdata *u) { if (err == -EPIPE) { pa_log_debug("snd_pcm_mmap_commit: Buffer underrun!"); - u->first = 1; + u->first = TRUE; } if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0) @@ -355,7 +357,8 @@ static int suspend(struct userdata *u) { static int unsuspend(struct userdata *u) { pa_sample_spec ss; - int err, b; + int err; + pa_bool_t b; unsigned nfrags; snd_pcm_uframes_t period_size; @@ -375,7 +378,7 @@ static int unsuspend(struct userdata *u) { period_size = u->fragment_size / u->frame_size; b = u->use_mmap; - if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b)) < 0) { + if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b, TRUE)) < 0) { pa_log("Failed to set hardware parameters: %s", snd_strerror(err)); goto fail; } @@ -405,7 +408,7 @@ static int unsuspend(struct userdata *u) { /* FIXME: We need to reload the volume somehow */ - u->first = 1; + u->first = TRUE; pa_log_info("Resumed successfully..."); @@ -628,7 +631,7 @@ static void thread_func(void *userdata) { if (work_done && u->first) { pa_log_info("Starting playback."); snd_pcm_start(u->pcm_handle); - u->first = 0; + u->first = FALSE; continue; } } @@ -709,7 +712,7 @@ int pa__init(pa_module*m) { pa_modargs *ma = NULL; struct userdata *u = NULL; - char *dev; + const char *dev_id; pa_sample_spec ss; pa_channel_map map; uint32_t nfrags, frag_size; @@ -721,7 +724,7 @@ int pa__init(pa_module*m) { const char *name; char *name_buf = NULL; int namereg_fail; - int use_mmap = 1, b; + pa_bool_t use_mmap = TRUE, b; snd_pcm_info_alloca(&pcm_info); @@ -761,7 +764,7 @@ int pa__init(pa_module*m) { u->module = m; m->userdata = u; u->use_mmap = use_mmap; - u->first = 1; + u->first = TRUE; pa_thread_mq_init(&u->thread_mq, m->core->mainloop); u->rtpoll = pa_rtpoll_new(); u->alsa_rtpoll_item = NULL; @@ -769,43 +772,35 @@ int pa__init(pa_module*m) { snd_config_update_free_global(); - dev = pa_xstrdup(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE)); - - for (;;) { - - if ((err = snd_pcm_open(&u->pcm_handle, dev, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { - pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err)); - pa_xfree(dev); - goto fail; - } + b = use_mmap; - b = use_mmap; - if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b)) < 0) { + if ((dev_id = pa_modargs_get_value(ma, "device_id", NULL))) { - if (err == -EPERM) { - /* Hmm, some hw is very exotic, so we retry with plughw, if hw didn't work */ + if (!(u->pcm_handle = pa_alsa_open_by_device_id( + dev_id, + &u->device_name, + &ss, &map, + SND_PCM_STREAM_PLAYBACK, + &nfrags, &period_size, + &b))) - if (pa_startswith(dev, "hw:")) { - char *d = pa_sprintf_malloc("plughw:%s", dev+3); - pa_log_debug("Opening the device as '%s' didn't work, retrying with '%s'.", dev, d); - pa_xfree(dev); - dev = d; + goto fail; - snd_pcm_close(u->pcm_handle); - u->pcm_handle = NULL; - continue; - } - } + } else { - pa_log("Failed to set hardware parameters: %s", snd_strerror(err)); - pa_xfree(dev); + if (!(u->pcm_handle = pa_alsa_open_by_device_string( + pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), + &u->device_name, + &ss, &map, + SND_PCM_STREAM_PLAYBACK, + &nfrags, &period_size, + &b))) goto fail; - } - break; } - u->device_name = dev; + pa_assert(u->device_name); + pa_log_info("Successfully opened device %s.", u->device_name); if (use_mmap && !b) { pa_log_info("Device doesn't support mmap(), falling back to UNIX read/write mode."); @@ -828,15 +823,11 @@ int pa__init(pa_module*m) { /* ALSA might tweak the sample spec, so recalculate the frame size */ frame_size = pa_frame_size(&ss); - if (ss.channels != map.channels) - /* Seems ALSA didn't like the channel number, so let's fix the channel map */ - pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); - if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) pa_log_warn("Error opening mixer: %s", snd_strerror(err)); else { - if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) || + if ((pa_alsa_prepare_mixer(u->mixer_handle, u->device_name) < 0) || !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Master", "PCM"))) { snd_mixer_close(u->mixer_handle); @@ -847,7 +838,7 @@ int pa__init(pa_module*m) { if ((name = pa_modargs_get_value(ma, "sink_name", NULL))) namereg_fail = 1; else { - name = name_buf = pa_sprintf_malloc("alsa_output.%s", dev); + name = name_buf = pa_sprintf_malloc("alsa_output.%s", u->device_name); namereg_fail = 0; } @@ -867,7 +858,7 @@ int pa__init(pa_module*m) { pa_sink_set_rtpoll(u->sink, u->rtpoll); pa_sink_set_description(u->sink, t = pa_sprintf_malloc( "ALSA PCM on %s (%s)%s", - dev, + u->device_name, snd_pcm_info_get_name(pcm_info), use_mmap ? " via DMA" : "")); pa_xfree(t); diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 1a6113a7..2d2bfa07 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -58,6 +58,7 @@ PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "source_name= " "device= " + "device_id= " "format= " "channels= " "rate= " @@ -89,13 +90,14 @@ struct userdata { char *device_name; - int use_mmap; + pa_bool_t use_mmap; pa_rtpoll_item *alsa_rtpoll_item; }; static const char* const valid_modargs[] = { "device", + "device_id", "source_name", "channels", "rate", @@ -342,7 +344,8 @@ static int suspend(struct userdata *u) { static int unsuspend(struct userdata *u) { pa_sample_spec ss; - int err, b; + int err; + pa_bool_t b; unsigned nfrags; snd_pcm_uframes_t period_size; @@ -362,7 +365,7 @@ static int unsuspend(struct userdata *u) { period_size = u->fragment_size / u->frame_size; b = u->use_mmap; - if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b)) < 0) { + if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b, TRUE)) < 0) { pa_log("Failed to set hardware parameters: %s", snd_strerror(err)); goto fail; } @@ -691,10 +694,10 @@ int pa__init(pa_module*m) { pa_modargs *ma = NULL; struct userdata *u = NULL; - char *dev; + const char *dev_id; pa_sample_spec ss; pa_channel_map map; - unsigned nfrags, frag_size; + uint32_t nfrags, frag_size; snd_pcm_uframes_t period_size; size_t frame_size; snd_pcm_info_t *pcm_info = NULL; @@ -703,7 +706,7 @@ int pa__init(pa_module*m) { const char *name; char *name_buf = NULL; int namereg_fail; - int use_mmap = 1, b; + pa_bool_t use_mmap = TRUE, b; snd_pcm_info_alloca(&pcm_info); @@ -750,43 +753,31 @@ int pa__init(pa_module*m) { snd_config_update_free_global(); - dev = pa_xstrdup(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE)); - - for (;;) { + if ((dev_id = pa_modargs_get_value(ma, "device_id", NULL))) { - if ((err = snd_pcm_open(&u->pcm_handle, dev, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { - pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err)); - pa_xfree(dev); + if (!(u->pcm_handle = pa_alsa_open_by_device_id( + dev_id, + &u->device_name, + &ss, &map, + SND_PCM_STREAM_CAPTURE, + &nfrags, &period_size, + &b))) goto fail; - } - - b = use_mmap; - if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b)) < 0) { - - if (err == -EPERM) { - /* Hmm, some hw is very exotic, so we retry with plughw, if hw didn't work */ - if (pa_startswith(dev, "hw:")) { - char *d = pa_sprintf_malloc("plughw:%s", dev+3); - pa_log_debug("Opening the device as '%s' didn't work, retrying with '%s'.", dev, d); - pa_xfree(dev); - dev = d; + } else { - snd_pcm_close(u->pcm_handle); - u->pcm_handle = NULL; - continue; - } - } - - pa_log("Failed to set hardware parameters: %s", snd_strerror(err)); - pa_xfree(dev); + if (!(u->pcm_handle = pa_alsa_open_by_device_string( + pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), + &u->device_name, + &ss, &map, + SND_PCM_STREAM_CAPTURE, + &nfrags, &period_size, + &b))) goto fail; - } - - break; } - u->device_name = dev; + pa_assert(u->device_name); + pa_log_info("Successfully opened device %s.", u->device_name); if (use_mmap && !b) { pa_log_info("Device doesn't support mmap(), falling back to UNIX read/write mode."); @@ -817,7 +808,7 @@ int pa__init(pa_module*m) { pa_log("Error opening mixer: %s", snd_strerror(err)); else { - if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) || + if ((pa_alsa_prepare_mixer(u->mixer_handle, u->device_name) < 0) || !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", NULL))) { snd_mixer_close(u->mixer_handle); u->mixer_handle = NULL; @@ -827,7 +818,7 @@ int pa__init(pa_module*m) { if ((name = pa_modargs_get_value(ma, "source_name", NULL))) namereg_fail = 1; else { - name = name_buf = pa_sprintf_malloc("alsa_input.%s", dev); + name = name_buf = pa_sprintf_malloc("alsa_input.%s", u->device_name); namereg_fail = 0; } @@ -847,7 +838,7 @@ int pa__init(pa_module*m) { pa_source_set_rtpoll(u->source, u->rtpoll); pa_source_set_description(u->source, t = pa_sprintf_malloc( "ALSA PCM on %s (%s)%s", - dev, + u->device_name, snd_pcm_info_get_name(pcm_info), use_mmap ? " via DMA" : "")); pa_xfree(t); diff --git a/src/modules/module-bt-proximity.c b/src/modules/module-bt-proximity.c index f6125233..62d530d4 100644 --- a/src/modules/module-bt-proximity.c +++ b/src/modules/module-bt-proximity.c @@ -261,7 +261,7 @@ static struct bonding* bonding_new(struct userdata *u, const char *a) { dbus_message_unref(m); dbus_message_unref(r); - pa_hashmap_put(u->bondings, a, b); + pa_hashmap_put(u->bondings, b->address, b); return b; diff --git a/src/modules/module-cli.c b/src/modules/module-cli.c index 71df5a0f..ab311a82 100644 --- a/src/modules/module-cli.c +++ b/src/modules/module-cli.c @@ -70,7 +70,7 @@ static void eof_and_exit_cb(pa_cli*c, void *userdata) { int pa__init(pa_module*m) { pa_iochannel *io; pa_modargs *ma; - int exit_on_eof = 0; + pa_bool_t exit_on_eof = FALSE; pa_assert(m); diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index 95665931..ee650dfd 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -222,7 +222,8 @@ static int detect_waveout(pa_core *c, int just_one) { #endif int pa__init(pa_module*m) { - int just_one = 0, n = 0; + pa_bool_t just_one = FALSE; + int n = 0; pa_modargs *ma; pa_assert(m); diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index 00b66c16..832bc73e 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -191,12 +191,12 @@ static pa_module* hal_device_load_alsa(struct userdata *u, const char *udi, char *sink_name = pa_sprintf_malloc("alsa_output.%s", strip_udi(udi)); module_name = "module-alsa-sink"; - args = pa_sprintf_malloc("device=hw:%u sink_name=%s", card, *sink_name); + args = pa_sprintf_malloc("device_id=%u sink_name=%s", card, *sink_name); } else { *source_name = pa_sprintf_malloc("alsa_input.%s", strip_udi(udi)); module_name = "module-alsa-source"; - args = pa_sprintf_malloc("device=hw:%u source_name=%s", card, *source_name); + args = pa_sprintf_malloc("device_id=%u source_name=%s", card, *source_name); } pa_log_debug("Loading %s with arguments '%s'", module_name, args); diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index a44ad083..8352a790 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -1139,7 +1139,7 @@ int pa__init(pa_module*m) { int fd = -1; int nfrags, frag_size; int mode, caps; - int record = 1, playback = 1, use_mmap = 1; + pa_bool_t record = TRUE, playback = TRUE, use_mmap = TRUE; pa_sample_spec ss; pa_channel_map map; pa_modargs *ma = NULL; diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index d7c50578..95ff15de 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -179,11 +179,11 @@ int pa__init(pa_module*m) { pa_source_output *o = NULL; uint8_t payload; char *p; - int r; + int r, j; socklen_t k; struct timeval tv; char hn[128], *n; - int loop = 0; + pa_bool_t loop = FALSE; pa_source_output_new_data data; pa_assert(m); @@ -274,8 +274,9 @@ int pa__init(pa_module*m) { goto fail; } - if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0 || - setsockopt(sap_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) { + j = !!loop; + if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &j, sizeof(j)) < 0 || + setsockopt(sap_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &j, sizeof(j)) < 0) { pa_log("IP_MULTICAST_LOOP failed: %s", pa_cstrerror(errno)); goto fail; } diff --git a/src/pulsecore/modargs.c b/src/pulsecore/modargs.c index 1311af3c..0dab254b 100644 --- a/src/pulsecore/modargs.c +++ b/src/pulsecore/modargs.c @@ -225,7 +225,7 @@ int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value) { return 0; } -int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value) { +int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, pa_bool_t *value) { const char *v; int r; diff --git a/src/pulsecore/modargs.h b/src/pulsecore/modargs.h index aa175885..504b9cd7 100644 --- a/src/pulsecore/modargs.h +++ b/src/pulsecore/modargs.h @@ -28,6 +28,7 @@ #include #include #include +#include typedef struct pa_modargs pa_modargs; @@ -44,7 +45,7 @@ const char *pa_modargs_get_value(pa_modargs *ma, const char *key, const char *de /* Return a module argument as unsigned 32bit value in *value */ int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value); int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value); -int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value); +int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, pa_bool_t *value); /* Return sample spec data from the three arguments "rate", "format" and "channels" */ int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *ss); diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 76ba9dd0..004e535e 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -1406,7 +1406,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { pa_protocol_esound *p = NULL; - int public = 0; + pa_bool_t public = FALSE; const char *acl; pa_assert(core); diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 9ae0f083..1d294746 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -2956,7 +2956,7 @@ static int load_key(pa_protocol_native*p, const char*fn) { static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_modargs *ma) { pa_protocol_native *p; - int public = 0; + pa_bool_t public = FALSE; const char *acl; pa_assert(c); @@ -2976,7 +2976,7 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo #ifdef HAVE_CREDS { - int a = 1; + pa_bool_t a = 1; if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &a) < 0) { pa_log("auth-group-enabled= expects a boolean argument."); return NULL; diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c index 64e2a81c..777def30 100644 --- a/src/pulsecore/protocol-simple.c +++ b/src/pulsecore/protocol-simple.c @@ -566,7 +566,7 @@ fail: pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { pa_protocol_simple* p = NULL; - int enable; + pa_bool_t enable; pa_assert(core); pa_assert(server); @@ -587,7 +587,7 @@ pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *serv p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL)); p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); - enable = 0; + enable = FALSE; if (pa_modargs_get_value_boolean(ma, "record", &enable) < 0) { pa_log("record= expects a numeric argument."); goto fail; -- cgit From 7b321eda3af7dbdd689152da9b3ca315d383b5b4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 13 Nov 2007 19:21:15 +0000 Subject: increase the pacmd timeout a bit git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2051 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/utils/pacmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c index 16e5822f..9583385b 100644 --- a/src/utils/pacmd.c +++ b/src/utils/pacmd.c @@ -80,7 +80,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { goto fail; } - pa_msleep(50); + pa_msleep(300); } if (i >= 5) { -- cgit From 15f56de8f2a10e092e11dfa3fc48ee28d2dd7e25 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 13 Nov 2007 19:39:23 +0000 Subject: don't touch RLIMIT:MEMBLOCK by default. This should improve out-of-the-box comaptibility with JACK git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2052 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/daemon-conf.c | 2 +- src/daemon/daemon.conf.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 089b12fc..3d63891c 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -90,7 +90,7 @@ static const pa_daemon_conf default_conf = { , .rlimit_nproc = { .value = 0, .is_set = FALSE } #endif #ifdef RLIMIT_MEMLOCK - , .rlimit_memlock = { .value = 16384, .is_set = TRUE } + , .rlimit_memlock = { .value = 0, .is_set = FALSE } #endif #ifdef RLIMIT_NICE , .rlimit_nice = { .value = 31, .is_set = TRUE } /* nice level of -11 */ diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in index f15d93e8..8d224e82 100644 --- a/src/daemon/daemon.conf.in +++ b/src/daemon/daemon.conf.in @@ -56,7 +56,7 @@ ; rlimit-nofile = 256 ; rlimit-stack = -1 ; rlimit-nproc = -1 -; rlimit-memlock = 16384 +; rlimit-memlock = -1 ; rlimit-nice = 31 ; rlimit-rtprio = 9 -- cgit From 4a39c2e462fa31c6aedb7c3d2a9a211b6e3611d1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 13 Nov 2007 19:56:01 +0000 Subject: don't fail if the bt-proximity-helper is not built git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2053 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index 36d27ef4..ebb8c6b4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1478,7 +1478,7 @@ daemon.conf: daemon/daemon.conf.in Makefile install-exec-hook: chown root $(DESTDIR)$(bindir)/pulseaudio ; true chmod u+s $(DESTDIR)$(bindir)/pulseaudio - chmod u+s $(DESTDIR)$(pulselibexecdir)/bt-proximity-helper + -chmod u+s $(DESTDIR)$(pulselibexecdir)/bt-proximity-helper ln -sf pacat $(DESTDIR)$(bindir)/parec rm -f $(DESTDIR)$(modlibexecdir)/*.a rm -f $(DESTDIR)$(libdir)/libpulsedsp.a -- cgit From 4c4761731df479a65f38ef0f4e9a079cd789ad3f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 13 Nov 2007 23:41:17 +0000 Subject: add array size to increase chance of detecting missing updates git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2054 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/channelmap.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pulse/channelmap.c b/src/pulse/channelmap.c index 2b8ef2b0..2b35ee75 100644 --- a/src/pulse/channelmap.c +++ b/src/pulse/channelmap.c @@ -36,7 +36,7 @@ #include "channelmap.h" -const char *const table[] = { +const char *const table[PA_CHANNEL_POSITION_MAX] = { [PA_CHANNEL_POSITION_MONO] = "mono", [PA_CHANNEL_POSITION_FRONT_CENTER] = "front-center", @@ -99,7 +99,7 @@ const char *const table[] = { [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = "top-rear-right" }; -const char *const pretty_table[] = { +const char *const pretty_table[PA_CHANNEL_POSITION_MAX] = { [PA_CHANNEL_POSITION_MONO] = "Mono", [PA_CHANNEL_POSITION_FRONT_CENTER] = "Front Center", @@ -531,4 +531,3 @@ int pa_channel_map_valid(const pa_channel_map *map) { return 1; } - -- cgit From 7462ab1aca6ffb7b1e97834e2a8d0e0129604f6f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 13 Nov 2007 23:42:15 +0000 Subject: Rework ALSA mixer channel detection code. This time we actually care about the channel names the ALSA mixer exports for us git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2055 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/alsa-util.c | 132 +++++++++++++++++++++++++++++++++++++-- src/modules/alsa-util.h | 2 + src/modules/module-alsa-sink.c | 52 ++++++++------- src/modules/module-alsa-source.c | 54 +++++++++------- 4 files changed, 192 insertions(+), 48 deletions(-) diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index 5b74c98c..40170e9c 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -310,8 +310,10 @@ int pa_alsa_set_hw_params( buffer_size = *periods * *period_size; - if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 || - (ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0) + if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) + goto finish; + + if ((ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0) goto finish; if (_use_mmap) { @@ -627,7 +629,7 @@ int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { pa_assert(dev); if ((err = snd_mixer_attach(mixer, dev)) < 0) { - pa_log_warn("Unable to attach to mixer %s: %s", dev, snd_strerror(err)); + pa_log_info("Unable to attach to mixer %s: %s", dev, snd_strerror(err)); return -1; } @@ -641,6 +643,8 @@ int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { return -1; } + pa_log_info("Successfully attached to mixer '%s'", dev); + return 0; } @@ -656,7 +660,7 @@ snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const snd_mixer_selem_id_set_name(sid, name); if (!(elem = snd_mixer_find_selem(mixer, sid))) { - pa_log_warn("Cannot find mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); + pa_log_info("Cannot find mixer control \"%s\".", snd_mixer_selem_id_get_name(sid)); if (fallback) { snd_mixer_selem_id_set_name(sid, fallback); @@ -671,3 +675,123 @@ snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const return elem; } + +static const snd_mixer_selem_channel_id_t alsa_channel_ids[PA_CHANNEL_POSITION_MAX] = { + [PA_CHANNEL_POSITION_MONO] = SND_MIXER_SCHN_MONO, /* The ALSA name is just an alias! */ + + [PA_CHANNEL_POSITION_FRONT_CENTER] = SND_MIXER_SCHN_FRONT_CENTER, + [PA_CHANNEL_POSITION_FRONT_LEFT] = SND_MIXER_SCHN_FRONT_LEFT, + [PA_CHANNEL_POSITION_FRONT_RIGHT] = SND_MIXER_SCHN_FRONT_RIGHT, + + [PA_CHANNEL_POSITION_REAR_CENTER] = SND_MIXER_SCHN_REAR_CENTER, + [PA_CHANNEL_POSITION_REAR_LEFT] = SND_MIXER_SCHN_REAR_LEFT, + [PA_CHANNEL_POSITION_REAR_RIGHT] = SND_MIXER_SCHN_REAR_RIGHT, + + [PA_CHANNEL_POSITION_LFE] = SND_MIXER_SCHN_WOOFER, + + [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = SND_MIXER_SCHN_UNKNOWN, + + [PA_CHANNEL_POSITION_SIDE_LEFT] = SND_MIXER_SCHN_SIDE_LEFT, + [PA_CHANNEL_POSITION_SIDE_RIGHT] = SND_MIXER_SCHN_SIDE_RIGHT, + + [PA_CHANNEL_POSITION_AUX0] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX1] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX2] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX3] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX4] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX5] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX6] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX7] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX8] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX9] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX10] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX11] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX12] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX13] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX14] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX15] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX16] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX17] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX18] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX19] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX20] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX21] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX22] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX23] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX24] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX25] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX26] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX27] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX28] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX29] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX30] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_AUX31] = SND_MIXER_SCHN_UNKNOWN, + + [PA_CHANNEL_POSITION_TOP_CENTER] = SND_MIXER_SCHN_UNKNOWN, + + [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = SND_MIXER_SCHN_UNKNOWN, + + [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = SND_MIXER_SCHN_UNKNOWN, + [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = SND_MIXER_SCHN_UNKNOWN +}; + + +int pa_alsa_calc_mixer_map(snd_mixer_elem_t *elem, const pa_channel_map *channel_map, snd_mixer_selem_channel_id_t mixer_map[], pa_bool_t playback) { + unsigned i; + pa_bool_t alsa_channel_used[SND_MIXER_SCHN_LAST]; + pa_bool_t mono_used = FALSE; + + pa_assert(elem); + pa_assert(channel_map); + pa_assert(mixer_map); + + memset(&alsa_channel_used, 0, sizeof(alsa_channel_used)); + + if (channel_map->channels > 1 && + ((playback && snd_mixer_selem_has_playback_volume_joined(elem)) || + (!playback && snd_mixer_selem_has_capture_volume_joined(elem)))) { + pa_log_info("ALSA device lacks independant volume controls for each channel, falling back to software volume control."); + return -1; + } + + for (i = 0; i < channel_map->channels; i++) { + snd_mixer_selem_channel_id_t id; + pa_bool_t is_mono; + + is_mono = channel_map->map[i] == PA_CHANNEL_POSITION_MONO; + id = alsa_channel_ids[channel_map->map[i]]; + + if (!is_mono && id == SND_MIXER_SCHN_UNKNOWN) { + pa_log_info("Configured channel map contains channel '%s' that is unknown to the ALSA mixer. Falling back to software volume control.", pa_channel_position_to_string(channel_map->map[i])); + return -1; + } + + if ((is_mono && mono_used) || (!is_mono && alsa_channel_used[id])) { + pa_log_info("Channel map has duplicate channel '%s', failling back to software volume control.", pa_channel_position_to_string(channel_map->map[i])); + return -1; + } + + if ((playback && (!snd_mixer_selem_has_playback_channel(elem, id) || (is_mono && !snd_mixer_selem_is_playback_mono(elem)))) || + (!playback && (!snd_mixer_selem_has_capture_channel(elem, id) || (is_mono && !snd_mixer_selem_is_capture_mono(elem))))) { + + pa_log_info("ALSA device lacks separate volumes control for channel '%s', falling back to software volume control.", pa_channel_position_to_string(channel_map->map[i])); + return -1; + } + + if (is_mono) { + mixer_map[i] = SND_MIXER_SCHN_MONO; + mono_used = TRUE; + } else { + mixer_map[i] = id; + alsa_channel_used[id] = TRUE; + } + } + + pa_log_info("All %u channels can be mapped to mixer channels. Using hardware volume control.", channel_map->channels); + + return 0; +} diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h index 36720b03..53d9a2fb 100644 --- a/src/modules/alsa-util.h +++ b/src/modules/alsa-util.h @@ -71,4 +71,6 @@ snd_pcm_t *pa_alsa_open_by_device_string( snd_pcm_uframes_t *period_size, pa_bool_t *use_mmap); +int pa_alsa_calc_mixer_map(snd_mixer_elem_t *elem, const pa_channel_map *channel_map, snd_mixer_selem_channel_id_t mixer_map[], pa_bool_t playback); + #endif diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index e62b8a06..14aef7c9 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -95,6 +95,8 @@ struct userdata { pa_bool_t first; pa_rtpoll_item *alsa_rtpoll_item; + + snd_mixer_selem_channel_id_t mixer_map[SND_MIXER_SCHN_LAST]; }; static const char* const valid_modargs[] = { @@ -505,9 +507,9 @@ static int sink_get_volume_cb(pa_sink *s) { for (i = 0; i < s->sample_spec.channels; i++) { long set_vol, vol; - pa_assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, i)); + pa_assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, u->mixer_map[i])); - if ((err = snd_mixer_selem_get_playback_volume(u->mixer_elem, i, &vol)) < 0) + if ((err = snd_mixer_selem_get_playback_volume(u->mixer_elem, u->mixer_map[i], &vol)) < 0) goto fail; set_vol = (long) roundf(((float) s->volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; @@ -539,7 +541,7 @@ static int sink_set_volume_cb(pa_sink *s) { long alsa_vol; pa_volume_t vol; - pa_assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, i)); + pa_assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, u->mixer_map[i])); vol = s->volume.values[i]; @@ -548,7 +550,7 @@ static int sink_set_volume_cb(pa_sink *s) { alsa_vol = (long) roundf(((float) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; - if ((err = snd_mixer_selem_set_playback_volume(u->mixer_elem, i, alsa_vol)) < 0) + if ((err = snd_mixer_selem_set_playback_volume(u->mixer_elem, u->mixer_map[i], alsa_vol)) < 0) goto fail; } @@ -826,10 +828,25 @@ int pa__init(pa_module*m) { if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) pa_log_warn("Error opening mixer: %s", snd_strerror(err)); else { + pa_bool_t found = FALSE; + + if (pa_alsa_prepare_mixer(u->mixer_handle, u->device_name) >= 0) + found = TRUE; + else { + char *md = pa_sprintf_malloc("hw:%s", dev_id); + + if (strcmp(u->device_name, md)) + if (pa_alsa_prepare_mixer(u->mixer_handle, md) >= 0) + found = TRUE; - if ((pa_alsa_prepare_mixer(u->mixer_handle, u->device_name) < 0) || - !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Master", "PCM"))) { + pa_xfree(md); + } + + if (found) + if (!(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Master", "PCM"))) + found = FALSE; + if (!found) { snd_mixer_close(u->mixer_handle); u->mixer_handle = NULL; } @@ -863,7 +880,7 @@ int pa__init(pa_module*m) { use_mmap ? " via DMA" : "")); pa_xfree(t); - u->sink->flags = PA_SINK_HARDWARE|PA_SINK_HW_VOLUME_CTRL|PA_SINK_LATENCY; + u->sink->flags = PA_SINK_HARDWARE|PA_SINK_LATENCY; u->frame_size = frame_size; u->fragment_size = frag_size = period_size * frame_size; @@ -875,35 +892,26 @@ int pa__init(pa_module*m) { pa_memchunk_reset(&u->memchunk); if (u->mixer_handle) { - /* Initialize mixer code */ - pa_assert(u->mixer_elem); - if (snd_mixer_selem_has_playback_volume(u->mixer_elem)) { - int i; - - for (i = 0; i < ss.channels; i++) - if (!snd_mixer_selem_has_playback_channel(u->mixer_elem, i)) - break; - - if (i == ss.channels) { - pa_log_debug("ALSA device has separate volumes controls for all %u channels.", ss.channels); + if (snd_mixer_selem_has_playback_volume(u->mixer_elem)) + if (pa_alsa_calc_mixer_map(u->mixer_elem, &map, u->mixer_map, TRUE) >= 0) { u->sink->get_volume = sink_get_volume_cb; u->sink->set_volume = sink_set_volume_cb; snd_mixer_selem_get_playback_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max); - } else - pa_log_info("ALSA device lacks separate volumes controls for all %u channels (%u available), falling back to software volume control.", ss.channels, i+1); - } + u->sink->flags |= PA_SINK_HW_VOLUME_CTRL; + } if (snd_mixer_selem_has_playback_switch(u->mixer_elem)) { u->sink->get_mute = sink_get_mute_cb; u->sink->set_mute = sink_set_mute_cb; + u->sink->flags |= PA_SINK_HW_VOLUME_CTRL; } u->mixer_fdl = pa_alsa_fdlist_new(); if (pa_alsa_fdlist_set_mixer(u->mixer_fdl, u->mixer_handle, m->core->mainloop) < 0) { - pa_log("failed to initialise file descriptor monitoring"); + pa_log("Failed to initialize file descriptor monitoring"); goto fail; } diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 2d2bfa07..23a2f921 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -93,6 +93,8 @@ struct userdata { pa_bool_t use_mmap; pa_rtpoll_item *alsa_rtpoll_item; + + snd_mixer_selem_channel_id_t mixer_map[SND_MIXER_SCHN_LAST]; }; static const char* const valid_modargs[] = { @@ -494,9 +496,9 @@ static int source_get_volume_cb(pa_source *s) { for (i = 0; i < s->sample_spec.channels; i++) { long set_vol, vol; - pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); + pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, u->mixer_map[i])); - if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, i, &vol)) < 0) + if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, u->mixer_map[i], &vol)) < 0) goto fail; set_vol = (long) roundf(((float) s->volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; @@ -528,7 +530,7 @@ static int source_set_volume_cb(pa_source *s) { long alsa_vol; pa_volume_t vol; - pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i)); + pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, u->mixer_map[i])); vol = s->volume.values[i]; @@ -537,7 +539,7 @@ static int source_set_volume_cb(pa_source *s) { alsa_vol = (long) roundf(((float) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; - if ((err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, alsa_vol)) < 0) + if ((err = snd_mixer_selem_set_capture_volume(u->mixer_elem, u->mixer_map[i], alsa_vol)) < 0) goto fail; } @@ -753,6 +755,8 @@ int pa__init(pa_module*m) { snd_config_update_free_global(); + b = use_mmap; + if ((dev_id = pa_modargs_get_value(ma, "device_id", NULL))) { if (!(u->pcm_handle = pa_alsa_open_by_device_id( @@ -800,16 +804,28 @@ int pa__init(pa_module*m) { /* ALSA might tweak the sample spec, so recalculate the frame size */ frame_size = pa_frame_size(&ss); - if (ss.channels != map.channels) - /* Seems ALSA didn't like the channel number, so let's fix the channel map */ - pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); - if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) pa_log("Error opening mixer: %s", snd_strerror(err)); else { + pa_bool_t found = FALSE; + + if (pa_alsa_prepare_mixer(u->mixer_handle, u->device_name) >= 0) + found = TRUE; + else { + char *md = pa_sprintf_malloc("hw:%s", dev_id); + + if (strcmp(u->device_name, md)) + if (pa_alsa_prepare_mixer(u->mixer_handle, md) >= 0) + found = TRUE; + + pa_xfree(md); + } - if ((pa_alsa_prepare_mixer(u->mixer_handle, u->device_name) < 0) || - !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", NULL))) { + if (found) + if (!(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", "Mic"))) + found = FALSE; + + if (!found) { snd_mixer_close(u->mixer_handle); u->mixer_handle = NULL; } @@ -843,7 +859,7 @@ int pa__init(pa_module*m) { use_mmap ? " via DMA" : "")); pa_xfree(t); - u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL; + u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY; u->frame_size = frame_size; u->fragment_size = frag_size = period_size * frame_size; @@ -855,30 +871,24 @@ int pa__init(pa_module*m) { if (u->mixer_handle) { pa_assert(u->mixer_elem); - if (snd_mixer_selem_has_capture_volume(u->mixer_elem)) { - int i; - - for (i = 0;i < ss.channels;i++) { - if (!snd_mixer_selem_has_capture_channel(u->mixer_elem, i)) - break; - } - - if (i == ss.channels) { + if (snd_mixer_selem_has_capture_volume(u->mixer_elem)) + if (pa_alsa_calc_mixer_map(u->mixer_elem, &map, u->mixer_map, FALSE) >= 0) { u->source->get_volume = source_get_volume_cb; u->source->set_volume = source_set_volume_cb; snd_mixer_selem_get_capture_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max); + u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL; } - } if (snd_mixer_selem_has_capture_switch(u->mixer_elem)) { u->source->get_mute = source_get_mute_cb; u->source->set_mute = source_set_mute_cb; + u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL; } u->mixer_fdl = pa_alsa_fdlist_new(); if (pa_alsa_fdlist_set_mixer(u->mixer_fdl, u->mixer_handle, m->core->mainloop) < 0) { - pa_log("failed to initialise file descriptor monitoring"); + pa_log("Failed to initialize file descriptor monitoring"); goto fail; } -- cgit From 9b75b9de563bb61ef4b8f2000ed973fecba1137a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 14 Nov 2007 16:09:03 +0000 Subject: add missing pa_boolization git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2056 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-jack-sink.c | 2 +- src/modules/module-jack-source.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c index 44da068f..46e128c9 100644 --- a/src/modules/module-jack-sink.c +++ b/src/modules/module-jack-sink.c @@ -273,7 +273,7 @@ int pa__init(pa_module*m) { jack_status_t status; const char *server_name, *client_name; uint32_t channels = 0; - int do_connect = 1; + pa_bool_t do_connect = TRUE; unsigned i; const char **ports = NULL, **p; char *t; diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c index 93618020..f81c719a 100644 --- a/src/modules/module-jack-source.c +++ b/src/modules/module-jack-source.c @@ -250,7 +250,7 @@ int pa__init(pa_module*m) { jack_status_t status; const char *server_name, *client_name; uint32_t channels = 0; - int do_connect = 1; + pa_bool_t do_connect = TRUE; unsigned i; const char **ports = NULL, **p; char *t; -- cgit From 1765b13386936bfc57cdd68ec9e97186e16bea9a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 14 Nov 2007 16:10:36 +0000 Subject: use a free list for allocating reply_info structs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2057 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/pdispatch.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c index 2c95d740..bdd7cde1 100644 --- a/src/pulsecore/pdispatch.c +++ b/src/pulsecore/pdispatch.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "pdispatch.h" @@ -98,6 +99,8 @@ static const char *command_names[PA_COMMAND_MAX] = { #endif +PA_STATIC_FLIST_DECLARE(reply_infos, 0, pa_xfree); + struct reply_info { pa_pdispatch *pdispatch; PA_LLIST_FIELDS(struct reply_info); @@ -129,7 +132,8 @@ static void reply_info_free(struct reply_info *r) { PA_LLIST_REMOVE(struct reply_info, r->pdispatch->replies, r); - pa_xfree(r); + if (pa_flist_push(PA_STATIC_FLIST_GET(reply_infos), r) < 0) + pa_xfree(r); } pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_cb_t*table, unsigned entries) { @@ -273,7 +277,9 @@ void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa pa_assert(PA_REFCNT_VALUE(pd) >= 1); pa_assert(cb); - r = pa_xnew(struct reply_info, 1); + if (!(r = pa_flist_pop(PA_STATIC_FLIST_GET(reply_infos)))) + r = pa_xnew(struct reply_info, 1); + r->pdispatch = pd; r->callback = cb; r->userdata = userdata; -- cgit From 461e36910a20a5cfa7ed333b718b705f9ec9d0fd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 14 Nov 2007 16:11:09 +0000 Subject: use a free list for allocation pa_operation objects git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2058 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/operation.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/pulse/operation.c b/src/pulse/operation.c index ed5eb4aa..8a782fd1 100644 --- a/src/pulse/operation.c +++ b/src/pulse/operation.c @@ -27,15 +27,20 @@ #include #include +#include #include "internal.h" #include "operation.h" +PA_STATIC_FLIST_DECLARE(operations, 0, pa_xfree); + pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t cb, void *userdata) { pa_operation *o; pa_assert(c); - o = pa_xnew(pa_operation, 1); + if (!(o = pa_flist_pop(PA_STATIC_FLIST_GET(operations)))) + o = pa_xnew(pa_operation, 1); + PA_REFCNT_INIT(o); o->context = c; o->stream = s; @@ -66,7 +71,9 @@ void pa_operation_unref(pa_operation *o) { if (PA_REFCNT_DEC(o) <= 0) { pa_assert(!o->context); pa_assert(!o->stream); - pa_xfree(o); + + if (pa_flist_push(PA_STATIC_FLIST_GET(operations), o) < 0) + pa_xfree(o); } } -- cgit From 413a8f8917256ef44a58fc8519bcc93644423373 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 14 Nov 2007 16:11:51 +0000 Subject: use a prio inheriting mutex for the threaded mainloop, to ease writing of RT clients git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2059 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulse/thread-mainloop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulse/thread-mainloop.c b/src/pulse/thread-mainloop.c index 9dd47ae3..e8c956bb 100644 --- a/src/pulse/thread-mainloop.c +++ b/src/pulse/thread-mainloop.c @@ -103,7 +103,7 @@ pa_threaded_mainloop *pa_threaded_mainloop_new(void) { return NULL; } - m->mutex = pa_mutex_new(TRUE, FALSE); + m->mutex = pa_mutex_new(TRUE, TRUE); m->cond = pa_cond_new(); m->accept_cond = pa_cond_new(); m->thread = NULL; -- cgit From 8bdad297e3aaeb7443a92aecd3cd26dbd47a421e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Nov 2007 23:46:22 +0000 Subject: add interface to PolicyKit git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2060 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/PulseAudio.policy | 49 ++++++++++ src/daemon/polkit.c | 223 +++++++++++++++++++++++++++++++++++++++++++ src/daemon/polkit.h | 29 ++++++ 3 files changed, 301 insertions(+) create mode 100644 src/daemon/PulseAudio.policy create mode 100644 src/daemon/polkit.c create mode 100644 src/daemon/polkit.h diff --git a/src/daemon/PulseAudio.policy b/src/daemon/PulseAudio.policy new file mode 100644 index 00000000..55ebbf9c --- /dev/null +++ b/src/daemon/PulseAudio.policy @@ -0,0 +1,49 @@ + + + + + + + + + + + Real-time scheduling for the PulseAudio daemon + System policy prevents PulseAudio from acquiring real-time scheduling. + + no + no + auth_admin_keep_always + + + + + High-priority scheduling (negative Unix nice level) for the PulseAudio daemon + System policy prevents PulseAudio from acquiring high-priority scheduling. + + no + no + auth_admin_keep_always + + + + diff --git a/src/daemon/polkit.c b/src/daemon/polkit.c new file mode 100644 index 00000000..362c5194 --- /dev/null +++ b/src/daemon/polkit.c @@ -0,0 +1,223 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +#include +#include + +#include "polkit.h" + +static pa_bool_t show_grant_dialog(const char *action_id) { + DBusError dbus_error; + DBusConnection *bus = NULL; + DBusMessage *m = NULL, *reply = NULL; + pa_bool_t r = FALSE; + uint32_t xid = 0; + int verdict; + + dbus_error_init(&dbus_error); + + if (!(bus = dbus_bus_get(DBUS_BUS_SESSION, &dbus_error))) { + pa_log_error("Cannot connect to session bus: %s", dbus_error.message); + goto finish; + } + + if (!(m = dbus_message_new_method_call("org.gnome.PolicyKit", "/org/gnome/PolicyKit/Manager", "org.gnome.PolicyKit.Manager", "ShowDialog"))) { + pa_log_error("Failed to allocate D-Bus message."); + goto finish; + } + + if (!(dbus_message_append_args(m, DBUS_TYPE_STRING, &action_id, DBUS_TYPE_UINT32, &xid, DBUS_TYPE_INVALID))) { + pa_log_error("Failed to append arguments to D-Bus message."); + goto finish; + } + + if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &dbus_error))) { + pa_log_warn("Failed to show grant dialog: %s", dbus_error.message); + goto finish; + } + + if (!(dbus_message_get_args(reply, &dbus_error, DBUS_TYPE_BOOLEAN, &verdict, DBUS_TYPE_INVALID))) { + pa_log_warn("Malformed response from grant manager: %s", dbus_error.message); + goto finish; + } + + r = !!verdict; + +finish: + + if (bus) + dbus_connection_unref(bus); + + dbus_error_free(&dbus_error); + + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + return r; +} + +int pa_polkit_check(const char *action_id) { + int ret = -1; + DBusError dbus_error; + DBusConnection *bus = NULL; + PolKitCaller *caller = NULL; + PolKitAction *action = NULL; + PolKitContext *context = NULL; + PolKitError *polkit_error = NULL; + PolKitSession *session = NULL; + PolKitResult polkit_result; + + dbus_error_init(&dbus_error); + + if (!(bus = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_error))) { + pa_log_error("Cannot connect to system bus: %s", dbus_error.message); + goto finish; + } + + if (!(caller = polkit_caller_new_from_pid(bus, getpid(), &dbus_error))) { + pa_log_error("Cannot get caller from PID: %s", dbus_error.message); + goto finish; + } + + /* This function is called when PulseAudio is called SUID root. We + * want to authenticate the real user that called us and not the + * effective user we gained through being SUID root. Hence we + * overwrite the UID caller data here explicitly, just for + * paranoia. In fact PolicyKit should fill in the UID here anyway + * -- an not the EUID or any other user id. */ + + if (!(polkit_caller_set_uid(caller, getuid()))) { + pa_log_error("Cannot set UID on caller object."); + goto finish; + } + + if (!(polkit_caller_get_ck_session(caller, &session))) { + pa_log_error("Failed to get CK session."); + goto finish; + } + + /* We need to overwrite the UID in both the caller and the session + * object */ + + if (!(polkit_session_set_uid(session, getuid()))) { + pa_log_error("Cannot set UID on session object."); + goto finish; + } + + if (!(action = polkit_action_new())) { + pa_log_error("Cannot allocate PolKitAction."); + goto finish; + } + + if (!polkit_action_set_action_id(action, action_id)) { + pa_log_error("Cannot set action_id"); + goto finish; + } + + if (!(context = polkit_context_new())) { + pa_log_error("Cannot allocate PolKitContext."); + goto finish; + } + + if (!polkit_context_init(context, &polkit_error)) { + pa_log_error("Cannot initialize PolKitContext: %s", polkit_error_get_error_message(polkit_error)); + goto finish; + } + + for (;;) { + +#ifdef HAVE_POLKIT_CONTEXT_IS_CALLER_AUTHORIZED + polkit_result = polkit_context_is_caller_authorized(context, action, caller, TRUE, &polkit_error); + + if (polkit_error_is_set(polkit_error)) { + pa_log_error("Could not determine whether caller is authorized: %s", polkit_error_get_error_message(polkit_error)); + goto finish; + } +#else + + polkit_result = polkit_context_can_caller_do_action(context, action, caller); + +#endif + + if (polkit_result == POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH || + polkit_result == POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_KEEP_SESSION || + polkit_result == POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_KEEP_ALWAYS || +#ifdef POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_ONE_SHOT + polkit_result == POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_ONE_SHOT || +#endif + polkit_result == POLKIT_RESULT_ONLY_VIA_SELF_AUTH || + polkit_result == POLKIT_RESULT_ONLY_VIA_SELF_AUTH_KEEP_SESSION || + polkit_result == POLKIT_RESULT_ONLY_VIA_SELF_AUTH_KEEP_ALWAYS +#ifdef POLKIT_RESULT_ONLY_VIA_SELF_AUTH_ONE_SHOT + || polkit_result == POLKIT_RESULT_ONLY_VIA_SELF_AUTH_ONE_SHOT +#endif + ) { + + if (show_grant_dialog(action_id)) + continue; + } + + break; + } + + if (polkit_result != POLKIT_RESULT_YES && polkit_result != POLKIT_RESULT_NO) + pa_log_warn("PolicyKit responded with '%s'", polkit_result_to_string_representation(polkit_result)); + + ret = polkit_result == POLKIT_RESULT_YES; + +finish: + + if (caller) + polkit_caller_unref(caller); + + if (action) + polkit_action_unref(action); + + if (context) + polkit_context_unref(context); + + if (bus) + dbus_connection_unref(bus); + + dbus_error_free(&dbus_error); + + if (polkit_error) + polkit_error_free(polkit_error); + + return ret; +} diff --git a/src/daemon/polkit.h b/src/daemon/polkit.h new file mode 100644 index 00000000..cbcf6a6a --- /dev/null +++ b/src/daemon/polkit.h @@ -0,0 +1,29 @@ +#ifndef foopolkithfoo +#define foopolkithfoo + +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2007 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +int pa_polkit_check(const char *action); + +#endif -- cgit From cf0d43e7d0edc19b3c2678d0288682b5611b30e7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Nov 2007 23:47:28 +0000 Subject: build PolicyKit support git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2061 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index ebb8c6b4..158560de 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -102,7 +102,8 @@ EXTRA_DIST = \ utils/padsp \ modules/module-defs.h.m4 \ daemon/pulseaudio-module-xsmp.desktop \ - map-file + map-file \ + daemon/PulseAudio.policy pulseconf_DATA = \ default.pa \ @@ -151,6 +152,17 @@ else pulseaudio_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -dlopen force $(foreach f,$(PREOPEN_LIBS),-dlopen $(f)) endif +if HAVE_POLKIT + +policy_DATA = daemon/PulseAudio.policy + +pulseaudio_SOURCES += daemon/polkit.c daemon/polkit.h +pulseaudio_CFLAGS += $(POLKIT_CFLAGS) +pulseaudio_LDADD += $(POLKIT_LIBS) + + +endif + ################################### # Utility programs # ################################### -- cgit From 07832d080aea8029f53ab211d30e286a4bfc7172 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Nov 2007 23:48:09 +0000 Subject: detect whether PolicyKit support is available git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2062 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/configure.ac b/configure.ac index b5834f0f..30a70e11 100644 --- a/configure.ac +++ b/configure.ac @@ -862,6 +862,47 @@ AC_SUBST(DBUS_LIBS) AC_SUBST(HAVE_DBUS) AM_CONDITIONAL([HAVE_DBUS], [test "x$HAVE_DBUS" = x1]) +#### PolicyKit support (optional) #### + +AC_ARG_ENABLE([polkit], + AC_HELP_STRING([--disable-polkit], [Disable optional PolicyKit support]), + [ + case "${enableval}" in + yes) polkit=yes ;; + no) polkit=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-polkit) ;; + esac + ], + [polkit=auto]) + +if test "x${polkit}" != xno ; then + + PKG_CHECK_MODULES(POLKIT, [ polkit-dbus ], + [ + HAVE_POLKIT=1 + saved_LIBS="$LIBS" + LIBS="$LIBS POLKIT_LIBS" + AC_CHECK_FUNCS(polkit_context_is_caller_authorized) + LIBS="$saved_LIBS" + AC_DEFINE([HAVE_POLKIT], 1, [Have PolicyKit]) + policydir=`pkg-config --variable prefix`/usr/share/PolicyKit/policy/ + AC_SUBST(policydir) + ], + [ + HAVE_POLKIT=0 + if test "x$polkit" = xyes ; then + AC_MSG_ERROR([*** PolicyKit support not found]) + fi + ]) +else + HAVE_POLKIT=0 +fi + +AC_SUBST(POLKIT_CFLAGS) +AC_SUBST(POLKIT_LIBS) +AC_SUBST(HAVE_POLKIT) +AM_CONDITIONAL([HAVE_POLKIT], [test "x$HAVE_POLKIT" = x1]) + ### Build and Install man pages ### AC_ARG_ENABLE(manpages, AS_HELP_STRING([--disable-manpages],[Disable building and installation of man pages]), @@ -1063,6 +1104,11 @@ if test "x${HAVE_BLUEZ}" = "x1" ; then ENABLE_BLUEZ=yes fi +ENABLE_POLKIT=no +if test "x${HAVE_POLKIT}" = "x1" ; then + ENABLE_POLKIT=yes +fi + echo " ---{ $PACKAGE_NAME $VERSION }--- @@ -1086,6 +1132,7 @@ echo " Enable BlueZ: ${ENABLE_BLUEZ} Enable TCP Wrappers: ${ENABLE_TCPWRAP} Enable libsamplerate: ${ENABLE_LIBSAMPLERATE} + Enable PolicyKit: ${ENABLE_POLKIT} System User: ${PA_SYSTEM_USER} System Group: ${PA_SYSTEM_GROUP} Realtime Group: ${PA_REALTIME_GROUP} -- cgit From d1d07783e0943ad51371978793d91f5b9990e17d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Nov 2007 01:19:28 +0000 Subject: add API to allow runtime reconfiguration of memblockqs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2063 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/memblockq.c | 95 +++++++++++++++++++++++++++++++++++------------ src/pulsecore/memblockq.h | 6 +++ 2 files changed, 78 insertions(+), 23 deletions(-) diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index a46155a9..8247feab 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -72,7 +72,6 @@ pa_memblockq* pa_memblockq_new( pa_memblockq* bq; pa_assert(base > 0); - pa_assert(maxlength >= base); bq = pa_xnew(pa_memblockq, 1); bq->blocks = bq->blocks_tail = NULL; @@ -84,36 +83,20 @@ pa_memblockq* pa_memblockq_new( pa_log_debug("memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", (unsigned long) maxlength, (unsigned long) tlength, (unsigned long) base, (unsigned long) prebuf, (unsigned long) minreq); - bq->maxlength = ((maxlength+base-1)/base)*base; - pa_assert(bq->maxlength >= base); + bq->missing = bq->requested = bq->maxlength = bq->tlength = bq->prebuf = bq->minreq = 0; + bq->in_prebuf = TRUE; - bq->tlength = ((tlength+base-1)/base)*base; - if (bq->tlength <= 0 || bq->tlength > bq->maxlength) - bq->tlength = bq->maxlength; - - bq->prebuf = (prebuf == (size_t) -1) ? bq->tlength/2 : prebuf; - bq->prebuf = ((bq->prebuf+base-1)/base)*base; - if (bq->prebuf > bq->maxlength) - bq->prebuf = bq->maxlength; - - bq->minreq = (minreq/base)*base; - - if (bq->minreq > bq->tlength - bq->prebuf) - bq->minreq = bq->tlength - bq->prebuf; - - if (!bq->minreq) - bq->minreq = 1; + pa_memblockq_set_maxlength(bq, maxlength); + pa_memblockq_set_tlength(bq, tlength); + pa_memblockq_set_prebuf(bq, prebuf); + pa_memblockq_set_minreq(bq, minreq); pa_log_debug("memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", (unsigned long)bq->maxlength, (unsigned long)bq->tlength, (unsigned long)bq->base, (unsigned long)bq->prebuf, (unsigned long)bq->minreq); - bq->in_prebuf = bq->prebuf > 0; bq->silence = silence ? pa_memblock_ref(silence) : NULL; bq->mcalign = NULL; - bq->missing = bq->tlength; - bq->requested = 0; - return bq; } @@ -688,3 +671,69 @@ size_t pa_memblockq_pop_missing(pa_memblockq *bq) { return l; } + +void pa_memblockq_set_maxlength(pa_memblockq *bq, size_t maxlength) { + pa_assert(bq); + + bq->maxlength = ((maxlength+bq->base-1)/bq->base)*bq->base; + + if (bq->maxlength < bq->base) + bq->maxlength = bq->base; + + if (bq->tlength > bq->maxlength) + pa_memblockq_set_tlength(bq, bq->maxlength); + + if (bq->prebuf > bq->maxlength) + pa_memblockq_set_prebuf(bq, bq->maxlength); +} + +void pa_memblockq_set_tlength(pa_memblockq *bq, size_t tlength) { + size_t old_tlength; + pa_assert(bq); + + old_tlength = bq->tlength; + + if (tlength <= 0) + tlength = bq->maxlength; + + bq->tlength = ((tlength+bq->base-1)/bq->base)*bq->base; + + if (bq->tlength > bq->maxlength) + bq->tlength = bq->maxlength; + + if (bq->minreq > bq->tlength - bq->prebuf) + pa_memblockq_set_minreq(bq, bq->tlength - bq->prebuf); + + bq->missing += (int64_t) bq->tlength - (int64_t) old_tlength; +} + +void pa_memblockq_set_prebuf(pa_memblockq *bq, size_t prebuf) { + pa_assert(bq); + + bq->prebuf = (prebuf == (size_t) -1) ? bq->tlength/2 : prebuf; + bq->prebuf = ((bq->prebuf+bq->base-1)/bq->base)*bq->base; + + if (prebuf > 0 && bq->prebuf < bq->base) + bq->prebuf = bq->base; + + if (bq->prebuf > bq->maxlength) + bq->prebuf = bq->maxlength; + + if (bq->prebuf <= 0 || pa_memblockq_get_length(bq) >= bq->prebuf) + bq->in_prebuf = FALSE; + + if (bq->minreq > bq->tlength - bq->prebuf) + pa_memblockq_set_minreq(bq, bq->tlength - bq->prebuf); +} + +void pa_memblockq_set_minreq(pa_memblockq *bq, size_t minreq) { + pa_assert(bq); + + bq->minreq = (minreq/bq->base)*bq->base; + + if (bq->minreq > bq->tlength - bq->prebuf) + bq->minreq = bq->tlength - bq->prebuf; + + if (bq->minreq < bq->base) + bq->minreq = bq->base; +} diff --git a/src/pulsecore/memblockq.h b/src/pulsecore/memblockq.h index 8c3e70fc..46637f10 100644 --- a/src/pulsecore/memblockq.h +++ b/src/pulsecore/memblockq.h @@ -142,4 +142,10 @@ size_t pa_memblockq_get_maxlength(pa_memblockq *bq); /* Return the prebuffer length in bytes */ size_t pa_memblockq_get_prebuf(pa_memblockq *bq); +/* Change metrics. */ +void pa_memblockq_set_maxlength(pa_memblockq *memblockq, size_t maxlength); +void pa_memblockq_set_tlength(pa_memblockq *memblockq, size_t tlength); +void pa_memblockq_set_prebuf(pa_memblockq *memblockq, size_t prebuf); +void pa_memblockq_set_minreq(pa_memblockq *memblockq, size_t minreq); + #endif -- cgit From 63fa021451e5bc97c1cdde35d0a90b8e9e090c73 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Nov 2007 01:20:16 +0000 Subject: add a couple of new opcodes, and document the versions the opcodes where added git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2064 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/native-common.h | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/pulsecore/native-common.h b/src/pulsecore/native-common.h index 9defc4a5..3ab2361b 100644 --- a/src/pulsecore/native-common.h +++ b/src/pulsecore/native-common.h @@ -36,10 +36,10 @@ enum { PA_COMMAND_TIMEOUT, /* pseudo command */ PA_COMMAND_REPLY, - /* Commands from client to server */ - PA_COMMAND_CREATE_PLAYBACK_STREAM, + /* CLIENT->SERVER */ + PA_COMMAND_CREATE_PLAYBACK_STREAM, /* Payload changed in v9, v12 (0.9.0, 0.9.8) */ PA_COMMAND_DELETE_PLAYBACK_STREAM, - PA_COMMAND_CREATE_RECORD_STREAM, + PA_COMMAND_CREATE_RECORD_STREAM, /* Payload changed in v9, v12 (0.9.0, 0.9.8) */ PA_COMMAND_DELETE_RECORD_STREAM, PA_COMMAND_EXIT, PA_COMMAND_AUTH, @@ -64,8 +64,8 @@ enum { PA_COMMAND_GET_MODULE_INFO_LIST, PA_COMMAND_GET_CLIENT_INFO, PA_COMMAND_GET_CLIENT_INFO_LIST, - PA_COMMAND_GET_SINK_INPUT_INFO, - PA_COMMAND_GET_SINK_INPUT_INFO_LIST, + PA_COMMAND_GET_SINK_INPUT_INFO, /* Payload changed in v11 (0.9.7) */ + PA_COMMAND_GET_SINK_INPUT_INFO_LIST, /* Payload changed in v11 (0.9.7) */ PA_COMMAND_GET_SOURCE_OUTPUT_INFO, PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, PA_COMMAND_GET_SAMPLE_INFO, @@ -92,18 +92,21 @@ enum { PA_COMMAND_KILL_CLIENT, PA_COMMAND_KILL_SINK_INPUT, PA_COMMAND_KILL_SOURCE_OUTPUT, + PA_COMMAND_LOAD_MODULE, PA_COMMAND_UNLOAD_MODULE, + PA_COMMAND_ADD_AUTOLOAD, PA_COMMAND_REMOVE_AUTOLOAD, PA_COMMAND_GET_AUTOLOAD_INFO, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, + PA_COMMAND_GET_RECORD_LATENCY, PA_COMMAND_CORK_RECORD_STREAM, PA_COMMAND_FLUSH_RECORD_STREAM, PA_COMMAND_PREBUF_PLAYBACK_STREAM, - /* Commands from server to client */ + /* SERVER->CLIENT */ PA_COMMAND_REQUEST, PA_COMMAND_OVERFLOW, PA_COMMAND_UNDERFLOW, @@ -112,14 +115,30 @@ enum { PA_COMMAND_SUBSCRIBE_EVENT, /* A few more client->server commands */ + + /* Supported since protocol v10 (0.9.5) */ PA_COMMAND_MOVE_SINK_INPUT, PA_COMMAND_MOVE_SOURCE_OUTPUT, + /* Supported since protocol v11 (0.9.7) */ PA_COMMAND_SET_SINK_INPUT_MUTE, PA_COMMAND_SUSPEND_SINK, PA_COMMAND_SUSPEND_SOURCE, + /* Supported since protocol v13 (0.9.8) */ + PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR, + PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR, + + PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE, + PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE, + + /* SERVER->CLIENT */ + PA_COMMAND_PLAYBACK_STREAM_SUSPENDED, + PA_COMMAND_RECORD_STREAM_SUSPENDED, + PA_COMMAND_PLAYBACK_STREAM_MOVED, + PA_COMMAND_RECORD_STREAM_MOVED, + PA_COMMAND_MAX }; -- cgit From 5a4959eb905e7f314c05f482eb4344ad4c7d0813 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Nov 2007 01:21:00 +0000 Subject: add short version history of the PA protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2065 fefdeb5f-60dc-0310-8127-8f9354f1896f --- PROTOCOL | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 PROTOCOL diff --git a/PROTOCOL b/PROTOCOL new file mode 100644 index 00000000..497fa47b --- /dev/null +++ b/PROTOCOL @@ -0,0 +1,80 @@ +### v8, implemented by >= 0.8 + +First version supported. + +### v9, implemented by >= 0.9.0 + +Reply for PA_COMMAND_CREATE_PLAYBACK_STREAM, +PA_COMMAND_CREATE_RECORD_STREAM now returns buffer_attrs that are used: + +Four new fields in reply of PA_COMMAND_CREATE_PLAYBACK_STREAM: + + maxlength + tlength + prebuf + minreq + +Two new fields in reply of PA_COMMAND_CREATE_RECORD_STREAM: + + maxlength + fragsize + +### v10, implemented by >= 0.9.5 + +New opcodes: + + PA_COMMAND_MOVE_SINK_INPUT + PA_COMMAND_MOVE_SOURCE_OUTPUT + +SHM data transfer support + +### v11, implemented by >= 0.9.7 + +Reply to to PA_COMMAND_GET_SINK_INPUT_INFO, PA_COMMAND_GET_SINK_INPUT_INFO_LIST gets new field at the end: + + mute + +New opcodes: + + PA_COMMAND_SET_SINK_INPUT_MUTE + PA_COMMAND_SUSPEND_SINK + PA_COMMAND_SUSPEND_SOURCE + +### v12, implemented by >= 0.9.8 + +S32LE, S32BE is now known as sample spec. + +Gained six new bool fields for PA_COMMAND_CREATE_PLAYBACK_STREAM, PA_COMMAND_CREATE_RECORD_STREAM request at the end: + + no_remap_channels + no_remix_channels + fix_format + fix_rate + fix_channels + no_move + variable_rate + +Reply to these opcodes now includes: + + sample_spec + channel_map + device_index + device_name + suspended + +New opcodes for changing buffer attrs: + + PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR + PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR + +New opcodes for changing sampling rate: + + PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE + PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE + +New opcodes for notifications: + + PA_COMMAND_PLAYBACK_STREAM_SUSPENDED + PA_COMMAND_CAPTURE_STREAM_SUSPENDED + PA_COMMAND_PLAYBACK_STREAM_MOVED + PA_COMMAND_CAPTURE_STREAM_MOVED -- cgit From 4ac6b53478be63ae5d0163a330e67e4134f17f89 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Nov 2007 01:21:53 +0000 Subject: minor typo fix git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2066 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 8352a790..a7df8a0c 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -1155,7 +1155,7 @@ int pa__init(pa_module*m) { } if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { - pa_log("record= and playback= expect numeric argument."); + pa_log("record= and playback= expect boolean argument."); goto fail; } -- cgit From 14a9b80afbb0bddc216462b72156f14e032e1b5e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Nov 2007 01:30:40 +0000 Subject: - Check process name when dealing with PID files - Add new PA_STREAM_FIX_CHANNELS, FIX_RATE, FIX_FORMAT, DONT_MOVE, VARIABLE_RATES to pa_sream_flags_t adn implement it - Expose those flags in pacat - Add notifications about device suspend/resume to the protocol and expose them in libpulse - Allow changing of buffer_attr during playback - allow disabling for remixing globally - hookup polkit support git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2067 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/daemon-conf.c | 24 +- src/daemon/daemon-conf.h | 3 +- src/daemon/daemon.conf.in | 1 + src/daemon/main.c | 169 ++++++++++---- src/map-file | 7 + src/modules/module-suspend-on-idle.c | 72 ++---- src/modules/module-volume-restore.c | 134 +++++++++-- src/pulse/context.c | 9 +- src/pulse/def.h | 79 ++++++- src/pulse/internal.h | 16 +- src/pulse/operation.c | 2 +- src/pulse/stream.c | 436 ++++++++++++++++++++++++++++++++++- src/pulse/stream.h | 71 +++++- src/pulsecore/cli-text.c | 14 +- src/pulsecore/core.c | 1 + src/pulsecore/core.h | 3 + src/pulsecore/pid.c | 34 ++- src/pulsecore/pid.h | 4 +- src/pulsecore/protocol-native.c | 365 +++++++++++++++++++++++++++-- src/pulsecore/sink-input.c | 46 +++- src/pulsecore/sink-input.h | 18 +- src/pulsecore/sink.c | 27 ++- src/pulsecore/source-output.c | 42 +++- src/pulsecore/source-output.h | 18 +- src/pulsecore/source.c | 27 ++- src/utils/pacat.c | 101 +++++++- src/utils/pacmd.c | 4 +- 27 files changed, 1497 insertions(+), 230 deletions(-) diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 3d63891c..c98c0218 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -71,6 +71,7 @@ static const pa_daemon_conf default_conf = { .log_target = PA_LOG_SYSLOG, .log_level = PA_LOG_NOTICE, .resample_method = PA_RESAMPLER_AUTO, + .disable_remixing = FALSE, .config_file = NULL, .use_pid_file = TRUE, .system_instance = FALSE, @@ -410,6 +411,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { { "default-fragments", parse_fragments, NULL }, { "default-fragment-size-msec", parse_fragment_size_msec, NULL }, { "nice-level", parse_nice_level, NULL }, + { "disable-remixing", pa_config_parse_bool, NULL }, #ifdef HAVE_SYS_RESOURCE_H { "rlimit-as", parse_rlimit, NULL }, { "rlimit-core", parse_rlimit, NULL }, @@ -458,33 +460,34 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { table[22].data = c; table[23].data = c; table[24].data = c; + table[25].data = &c->disable_remixing; #ifdef HAVE_SYS_RESOURCE_H - table[25].data = &c->rlimit_as; - table[26].data = &c->rlimit_core; - table[27].data = &c->rlimit_data; - table[28].data = &c->rlimit_fsize; - table[29].data = &c->rlimit_nofile; - table[30].data = &c->rlimit_stack; + table[26].data = &c->rlimit_as; + table[27].data = &c->rlimit_core; + table[28].data = &c->rlimit_data; + table[29].data = &c->rlimit_fsize; + table[30].data = &c->rlimit_nofile; + table[31].data = &c->rlimit_stack; #ifdef RLIMIT_NPROC - table[31].data = &c->rlimit_nproc; + table[32].data = &c->rlimit_nproc; #endif #ifdef RLIMIT_MEMLOCK #ifndef RLIMIT_NPROC #error "Houston, we have a numbering problem!" #endif - table[32].data = &c->rlimit_memlock; + table[33].data = &c->rlimit_memlock; #endif #ifdef RLIMIT_NICE #ifndef RLIMIT_MEMLOCK #error "Houston, we have a numbering problem!" #endif - table[33].data = &c->rlimit_nice; + table[34].data = &c->rlimit_nice; #endif #ifdef RLIMIT_RTPRIO #ifndef RLIMIT_NICE #error "Houston, we have a numbering problem!" #endif - table[34].data = &c->rlimit_rtprio; + table[35].data = &c->rlimit_rtprio; #endif #endif @@ -563,6 +566,7 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { pa_strbuf_printf(s, "log-target = %s\n", c->auto_log_target ? "auto" : (c->log_target == PA_LOG_SYSLOG ? "syslog" : "stderr")); pa_strbuf_printf(s, "log-level = %s\n", log_level_to_string[c->log_level]); pa_strbuf_printf(s, "resample-method = %s\n", pa_resample_method_to_string(c->resample_method)); + pa_strbuf_printf(s, "disable-remixing = %s\n", pa_yes_no(c->disable_remixing)); pa_strbuf_printf(s, "default-sample-format = %s\n", pa_sample_format_to_string(c->default_sample_spec.format)); pa_strbuf_printf(s, "default-sample-rate = %u\n", c->default_sample_spec.rate); pa_strbuf_printf(s, "default-sample-channels = %u\n", c->default_sample_spec.channels); diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h index b8930bd7..3dcafbfe 100644 --- a/src/daemon/daemon-conf.h +++ b/src/daemon/daemon-conf.h @@ -64,7 +64,8 @@ typedef struct pa_daemon_conf { use_pid_file, system_instance, no_cpu_limit, - disable_shm; + disable_shm, + disable_remixing; int exit_idle_time, module_idle_time, scache_idle_time, diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in index 8d224e82..d664962e 100644 --- a/src/daemon/daemon.conf.in +++ b/src/daemon/daemon.conf.in @@ -46,6 +46,7 @@ ; log-level = notice ; resample-method = speex-float-3 +; disable-remixing = no ; no-cpu-limit = no diff --git a/src/daemon/main.c b/src/daemon/main.c index 051c323e..236819e1 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -94,6 +94,7 @@ #include "dumpmodules.h" #include "caps.h" #include "ltdl-bind-now.h" +#include "polkit.h" #ifdef HAVE_LIBWRAP /* Only one instance of these variables */ @@ -281,17 +282,21 @@ static int create_runtime_dir(void) { #ifdef HAVE_SYS_RESOURCE_H -static void set_one_rlimit(const pa_rlimit *r, int resource, const char *name) { +static int set_one_rlimit(const pa_rlimit *r, int resource, const char *name) { struct rlimit rl; pa_assert(r); if (!r->is_set) - return; + return 0; rl.rlim_cur = rl.rlim_max = r->value; - if (setrlimit(resource, &rl) < 0) + if (setrlimit(resource, &rl) < 0) { pa_log_warn("setrlimit(%s, (%u, %u)) failed: %s", name, (unsigned) r->value, (unsigned) r->value, pa_cstrerror(errno)); + return -1; + } + + return 0; } static void set_all_rlimits(const pa_daemon_conf *conf) { @@ -324,9 +329,10 @@ int main(int argc, char *argv[]) { char *s; int r = 0, retval = 1, d = 0; int daemon_pipe[2] = { -1, -1 }; - int suid_root, real_root; + pa_bool_t suid_root, real_root; int valid_pid_file = 0; gid_t gid = (gid_t) -1; + pa_bool_t allow_realtime, allow_high_priority; #ifdef OS_IS_WIN32 pa_time_event *timer; @@ -357,8 +363,8 @@ int main(int argc, char *argv[]) { real_root = getuid() == 0; suid_root = !real_root && geteuid() == 0; #else - real_root = 0; - suid_root = 0; + real_root = FALSE; + suid_root = FALSE; #endif if (suid_root) { @@ -377,29 +383,12 @@ int main(int argc, char *argv[]) { * is just too risky tun let PA run as root all the time. */ } - setlocale(LC_ALL, ""); - - if (suid_root && (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) <= 0)) { - pa_log_info("Warning: Called SUID root, but not in group '"PA_REALTIME_GROUP"'. " - "For enabling real-time scheduling please become a member of '"PA_REALTIME_GROUP"' , or increase the RLIMIT_RTPRIO user limit."); - pa_drop_caps(); - pa_drop_root(); - suid_root = real_root = 0; - } - - LTDL_SET_PRELOADED_SYMBOLS(); - - pa_ltdl_init(); - -#ifdef OS_IS_WIN32 - { - WSADATA data; - WSAStartup(MAKEWORD(2, 0), &data); - } -#endif - - pa_random_seed(); + /* At this point, we are a normal user, possibly with CAP_NICE if + * we were started SUID. If we are started as normal root, than we + * still are normal root. */ + setlocale(LC_ALL, ""); + pa_log_set_maximal_level(PA_LOG_INFO); pa_log_set_ident("pulseaudio"); conf = pa_daemon_conf_new(); @@ -411,24 +400,123 @@ int main(int argc, char *argv[]) { goto finish; if (pa_cmdline_parse(conf, argc, argv, &d) < 0) { - pa_log("failed to parse command line."); + pa_log("Failed to parse command line."); goto finish; } pa_log_set_maximal_level(conf->log_level); pa_log_set_target(conf->auto_log_target ? PA_LOG_STDERR : conf->log_target, NULL); + if (suid_root) { + /* Ok, we're suid root, so let's better not enable high prio + * or RT by default */ + + allow_high_priority = allow_realtime = FALSE; + +#ifdef HAVE_POLKIT + if (conf->high_priority) { + if (pa_polkit_check("org.pulseaudio.acquire-high-priority") > 0) { + pa_log_info("PolicyKit grants us acquire-high-priority privilige."); + allow_high_priority = TRUE; + } else + pa_log_info("PolicyKit refuses acquire-high-priority privilige."); + } + + if (conf->realtime_scheduling) { + if (pa_polkit_check("org.pulseaudio.acquire-real-time") > 0) { + pa_log_info("PolicyKit grants us acquire-real-time privilige."); + allow_realtime = TRUE; + } else + pa_log_info("PolicyKit refuses acquire-real-time privilige."); + } +#endif + + if ((conf->high_priority || conf->realtime_scheduling) && pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) > 0) { + pa_log_info("We're in the group '"PA_REALTIME_GROUP"', allowing real-time and high-priority scheduling."); + allow_realtime = conf->realtime_scheduling; + allow_high_priority = conf->high_priority; + } + + if (!allow_high_priority && !allow_realtime) { + + /* OK, there's no further need to keep CAP_NICE. Hence + * let's give it up early */ + + pa_drop_caps(); + pa_drop_root(); + suid_root = real_root = FALSE; + + if (conf->high_priority || conf->realtime_scheduling) + pa_log_notice("Called SUID root and real-time/high-priority scheduling was requested in the configuration. However, we lack the necessary priviliges:\n" + "We are not in group '"PA_REALTIME_GROUP"' and PolicyKit refuse to grant us priviliges. Dropping SUID again.\n" + "For enabling real-time scheduling please acquire the appropriate PolicyKit priviliges, or become a member of '"PA_REALTIME_GROUP"', or increase the RLIMIT_NICE/RLIMIT_RTPRIO resource limits for this user."); + } + + } else { + + /* OK, we're a normal user, so let's allow the user evrything + * he asks for, it's now the kernel's job to enforce limits, + * not ours anymore */ + allow_high_priority = allow_realtime = TRUE; + } + + if (conf->high_priority && !allow_high_priority) { + pa_log_info("High-priority scheduling enabled in configuration but now allowed by policy. Disabling forcibly."); + conf->high_priority = FALSE; + } + + if (conf->realtime_scheduling && !allow_realtime) { + pa_log_info("Real-time scheduling enabled in configuration but now allowed by policy. Disabling forcibly."); + conf->realtime_scheduling = FALSE; + } + if (conf->high_priority && conf->cmd == PA_CMD_DAEMON) pa_raise_priority(conf->nice_level); - if (suid_root && (conf->cmd != PA_CMD_DAEMON || !conf->realtime_scheduling)) { - pa_drop_caps(); - pa_drop_root(); + if (suid_root) { + pa_bool_t drop; + + drop = conf->cmd != PA_CMD_DAEMON || !conf->realtime_scheduling; + +#ifdef RLIMIT_RTPRIO + if (!drop) { + + /* At this point we still have CAP_NICE if we were loaded + * SUID root. If possible let's acquire RLIMIT_RTPRIO + * instead and give CAP_NICE up. */ + + const pa_rlimit rl = { 9, TRUE }; + + if (set_one_rlimit(&rl, RLIMIT_RTPRIO, "RLIMIT_RTPRIO") >= 0) { + pa_log_info("Successfully increased RLIMIT_RTPRIO, giving up CAP_NICE."); + drop = TRUE; + } else + pa_log_warn("RLIMIT_RTPRIO failed: %s", pa_cstrerror(errno)); + } +#endif + + if (drop) { + pa_drop_caps(); + pa_drop_root(); + suid_root = real_root = FALSE; + } } + LTDL_SET_PRELOADED_SYMBOLS(); + pa_ltdl_init(); + if (conf->dl_search_path) lt_dlsetsearchpath(conf->dl_search_path); +#ifdef OS_IS_WIN32 + { + WSADATA data; + WSAStartup(MAKEWORD(2, 0), &data); + } +#endif + + pa_random_seed(); + switch (conf->cmd) { case PA_CMD_DUMP_MODULES: pa_dump_modules(conf, argc-d, argv+d); @@ -466,10 +554,10 @@ int main(int argc, char *argv[]) { case PA_CMD_CHECK: { pid_t pid; - if (pa_pid_file_check_running(&pid) < 0) { - pa_log_info("daemon not running"); - } else { - pa_log_info("daemon running as PID %u", pid); + if (pa_pid_file_check_running(&pid, "pulseaudio") < 0) + pa_log_info("Daemon not running"); + else { + pa_log_info("Daemon running as PID %u", pid); retval = 0; } @@ -478,8 +566,8 @@ int main(int argc, char *argv[]) { } case PA_CMD_KILL: - if (pa_pid_file_kill(SIGINT, NULL) < 0) - pa_log("failed to kill daemon."); + if (pa_pid_file_kill(SIGINT, NULL, "pulseaudio") < 0) + pa_log("Failed to kill daemon."); else retval = 0; @@ -496,9 +584,9 @@ int main(int argc, char *argv[]) { pa_assert(conf->cmd == PA_CMD_DAEMON); } - if (real_root && !conf->system_instance) { + if (real_root && !conf->system_instance) pa_log_warn("This program is not intended to be run as root (unless --system is specified)."); - } else if (!real_root && conf->system_instance) { + else if (!real_root && conf->system_instance) { pa_log("Root priviliges required."); goto finish; } @@ -645,6 +733,7 @@ int main(int argc, char *argv[]) { c->resample_method = conf->resample_method; c->realtime_priority = conf->realtime_priority; c->realtime_scheduling = !!conf->realtime_scheduling; + c->disable_remixing = !!conf->disable_remixing; pa_assert_se(pa_signal_init(pa_mainloop_get_api(mainloop)) == 0); pa_signal_new(SIGINT, signal_callback, c); diff --git a/src/map-file b/src/map-file index 427a3a78..f38baefd 100644 --- a/src/map-file +++ b/src/map-file @@ -156,26 +156,33 @@ pa_stream_flush; pa_stream_get_buffer_attr; pa_stream_get_channel_map; pa_stream_get_context; +pa_stream_get_device_index; +pa_stream_get_device_name; pa_stream_get_index; pa_stream_get_latency; pa_stream_get_sample_spec; pa_stream_get_state; pa_stream_get_time; pa_stream_get_timing_info; +pa_stream_is_suspended; pa_stream_new; pa_stream_peek; pa_stream_prebuf; pa_stream_readable_size; pa_stream_ref; +pa_stream_set_buffer_attr; pa_stream_set_latency_update_callback; +pa_stream_set_moved_callback; pa_stream_set_name; pa_stream_set_overflow_callback; pa_stream_set_read_callback; pa_stream_set_state_callback; +pa_stream_set_suspended_callback; pa_stream_set_underflow_callback; pa_stream_set_write_callback; pa_stream_trigger; pa_stream_unref; +pa_stream_update_sample_rate; pa_stream_update_timing_info; pa_stream_writable_size; pa_stream_write; diff --git a/src/modules/module-suspend-on-idle.c b/src/modules/module-suspend-on-idle.c index 4746e2b7..4c260d76 100644 --- a/src/modules/module-suspend-on-idle.c +++ b/src/modules/module-suspend-on-idle.c @@ -66,8 +66,6 @@ struct userdata { *source_output_unlink_slot, *sink_input_move_slot, *source_output_move_slot, - *sink_input_move_post_slot, - *source_output_move_post_slot, *sink_input_state_changed_slot, *source_output_state_changed_slot; }; @@ -131,27 +129,27 @@ static void resume(struct device_info *d) { } } -static pa_hook_result_t sink_input_new_hook_cb(pa_core *c, pa_sink_input *s, struct userdata *u) { +static pa_hook_result_t sink_input_fixate_hook_cb(pa_core *c, pa_sink_input_new_data *data, struct userdata *u) { struct device_info *d; pa_assert(c); - pa_sink_input_assert_ref(s); + pa_assert(data); pa_assert(u); - if ((d = pa_hashmap_get(u->device_infos, s->sink))) + if ((d = pa_hashmap_get(u->device_infos, data->sink))) resume(d); return PA_HOOK_OK; } -static pa_hook_result_t source_output_new_hook_cb(pa_core *c, pa_source_output *s, struct userdata *u) { +static pa_hook_result_t source_output_fixate_hook_cb(pa_core *c, pa_source_output_new_data *data, struct userdata *u) { struct device_info *d; pa_assert(c); - pa_source_output_assert_ref(s); + pa_assert(data); pa_assert(u); - if ((d = pa_hashmap_get(u->device_infos, s->source))) + if ((d = pa_hashmap_get(u->device_infos, data->source))) resume(d); return PA_HOOK_OK; @@ -185,56 +183,37 @@ static pa_hook_result_t source_output_unlink_hook_cb(pa_core *c, pa_source_outpu return PA_HOOK_OK; } -static pa_hook_result_t sink_input_move_hook_cb(pa_core *c, pa_sink_input *s, struct userdata *u) { - pa_assert(c); - pa_sink_input_assert_ref(s); - pa_assert(u); - - if (pa_sink_used_by(s->sink) <= 1) { - struct device_info *d; - if ((d = pa_hashmap_get(u->device_infos, s->sink))) - restart(d); - } - - return PA_HOOK_OK; -} - -static pa_hook_result_t sink_input_move_post_hook_cb(pa_core *c, pa_sink_input *s, struct userdata *u) { +static pa_hook_result_t sink_input_move_hook_cb(pa_core *c, pa_sink_input_move_hook_data *data, struct userdata *u) { struct device_info *d; - pa_assert(c); - pa_sink_input_assert_ref(s); - pa_assert(u); - - if ((d = pa_hashmap_get(u->device_infos, s->sink))) - resume(d); - - return PA_HOOK_OK; -} -static pa_hook_result_t source_output_move_hook_cb(pa_core *c, pa_source_output *s, struct userdata *u) { pa_assert(c); - pa_source_output_assert_ref(s); + pa_assert(data); pa_assert(u); - if (pa_source_used_by(s->source) <= 1) { - struct device_info *d; + if ((d = pa_hashmap_get(u->device_infos, data->destination))) + resume(d); - if ((d = pa_hashmap_get(u->device_infos, s->source))) + if (pa_sink_used_by(data->sink_input->sink) <= 1) + if ((d = pa_hashmap_get(u->device_infos, data->sink_input->sink))) restart(d); - } return PA_HOOK_OK; } -static pa_hook_result_t source_output_move_post_hook_cb(pa_core *c, pa_source_output *s, struct userdata *u) { +static pa_hook_result_t source_output_move_hook_cb(pa_core *c, pa_source_output_move_hook_data *data, struct userdata *u) { struct device_info *d; + pa_assert(c); - pa_source_output_assert_ref(s); + pa_assert(data); pa_assert(u); - if ((d = pa_hashmap_get(u->device_infos, s->source))) + if ((d = pa_hashmap_get(u->device_infos, data->destination))) resume(d); + if (pa_source_used_by(data->source_output->source) <= 1) + if ((d = pa_hashmap_get(u->device_infos, data->source_output->source))) + restart(d); + return PA_HOOK_OK; } @@ -395,18 +374,15 @@ int pa__init(pa_module*m) { u->sink_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], (pa_hook_cb_t) device_state_changed_hook_cb, u); u->source_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], (pa_hook_cb_t) device_state_changed_hook_cb, u); - u->sink_input_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], (pa_hook_cb_t) sink_input_new_hook_cb, u); - u->source_output_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], (pa_hook_cb_t) source_output_new_hook_cb, u); + u->sink_input_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], (pa_hook_cb_t) sink_input_fixate_hook_cb, u); + u->source_output_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], (pa_hook_cb_t) source_output_fixate_hook_cb, u); u->sink_input_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK_POST], (pa_hook_cb_t) sink_input_unlink_hook_cb, u); u->source_output_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], (pa_hook_cb_t) source_output_unlink_hook_cb, u); u->sink_input_move_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE], (pa_hook_cb_t) sink_input_move_hook_cb, u); u->source_output_move_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE], (pa_hook_cb_t) source_output_move_hook_cb, u); - u->sink_input_move_post_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_POST], (pa_hook_cb_t) sink_input_move_post_hook_cb, u); - u->source_output_move_post_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_POST], (pa_hook_cb_t) source_output_move_post_hook_cb, u); u->sink_input_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], (pa_hook_cb_t) sink_input_state_changed_hook_cb, u); u->source_output_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], (pa_hook_cb_t) source_output_state_changed_hook_cb, u); - pa_modargs_free(ma); return 0; @@ -449,8 +425,6 @@ void pa__done(pa_module*m) { pa_hook_slot_free(u->sink_input_unlink_slot); if (u->sink_input_move_slot) pa_hook_slot_free(u->sink_input_move_slot); - if (u->sink_input_move_post_slot) - pa_hook_slot_free(u->sink_input_move_post_slot); if (u->sink_input_state_changed_slot) pa_hook_slot_free(u->sink_input_state_changed_slot); @@ -460,8 +434,6 @@ void pa__done(pa_module*m) { pa_hook_slot_free(u->source_output_unlink_slot); if (u->source_output_move_slot) pa_hook_slot_free(u->source_output_move_slot); - if (u->source_output_move_post_slot) - pa_hook_slot_free(u->source_output_move_post_slot); if (u->source_output_state_changed_slot) pa_hook_slot_free(u->source_output_state_changed_slot); diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index 422bc7f2..192a2a78 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -52,14 +53,20 @@ PA_MODULE_AUTHOR("Lennart Poettering"); PA_MODULE_DESCRIPTION("Automatically restore the volume and the devices of streams"); PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(TRUE); -PA_MODULE_USAGE("table="); +PA_MODULE_USAGE( + "table= " + "restore_device= " + "restore_volume=" +); #define WHITESPACE "\n\r \t" - #define DEFAULT_VOLUME_TABLE_FILE "volume-restore.table" +#define SAVE_INTERVAL 10 static const char* const valid_modargs[] = { "table", + "restore_device", + "restore_volume", NULL, }; @@ -67,16 +74,20 @@ struct rule { char* name; pa_bool_t volume_is_set; pa_cvolume volume; - char *sink; - char *source; + char *sink, *source; }; struct userdata { + pa_core *core; pa_hashmap *hashmap; pa_subscription *subscription; - pa_hook_slot *sink_input_hook_slot, *source_output_hook_slot; + pa_hook_slot + *sink_input_new_hook_slot, + *sink_input_fixate_hook_slot, + *source_output_new_hook_slot; pa_bool_t modified; char *table_file; + pa_time_event *save_time_event; }; static pa_cvolume* parse_volume(const char *s, pa_cvolume *v) { @@ -220,12 +231,17 @@ static int save_rules(struct userdata *u) { void *state = NULL; struct rule *rule; + if (!u->modified) + return 0; + + pa_log_info("Saving rules..."); + f = u->table_file ? fopen(u->table_file, "w") : pa_open_config_file(NULL, DEFAULT_VOLUME_TABLE_FILE, NULL, &u->table_file, "w"); if (!f) { - pa_log("failed to open file '%s': %s", u->table_file, pa_cstrerror(errno)); + pa_log("Failed to open file '%s': %s", u->table_file, pa_cstrerror(errno)); goto finish; } @@ -249,6 +265,8 @@ static int save_rules(struct userdata *u) { } ret = 0; + u->modified = FALSE; + pa_log_debug("Successfully saved rules..."); finish: if (f) { @@ -289,6 +307,21 @@ static char* client_name(pa_client *c) { return t; } +static void save_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata) { + struct userdata *u = userdata; + + pa_assert(a); + pa_assert(e); + pa_assert(tv); + pa_assert(u); + + pa_assert(e == u->save_time_event); + u->core->mainloop->time_free(u->save_time_event); + u->save_time_event = NULL; + + save_rules(u); +} + static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { struct userdata *u = userdata; pa_sink_input *si = NULL; @@ -371,14 +404,48 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 pa_hashmap_put(u->hashmap, r->name, r); u->modified = TRUE; } + + if (u->modified && !u->save_time_event) { + struct timeval tv; + pa_gettimeofday(&tv); + tv.tv_sec += SAVE_INTERVAL; + u->save_time_event = u->core->mainloop->time_new(u->core->mainloop, &tv, save_time_callback, u); + } } -static pa_hook_result_t sink_input_hook_callback(pa_core *c, pa_sink_input_new_data *data, struct userdata *u) { +static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_new_data *data, struct userdata *u) { struct rule *r; char *name; pa_assert(data); + /* In the NEW hook we only adjust the device. Adjusting the volume + * is left for the FIXATE hook */ + + if (!data->client || !(name = client_name(data->client))) + return PA_HOOK_OK; + + if ((r = pa_hashmap_get(u->hashmap, name))) { + if (!data->sink && r->sink) { + if ((data->sink = pa_namereg_get(c, r->sink, PA_NAMEREG_SINK, 1))) + pa_log_info("Restoring sink for <%s>", r->name); + } + } + + pa_xfree(name); + + return PA_HOOK_OK; +} + +static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_input_new_data *data, struct userdata *u) { + struct rule *r; + char *name; + + pa_assert(data); + + /* In the FIXATE hook we only adjust the volum. Adjusting the device + * is left for the NEW hook */ + if (!data->client || !(name = client_name(data->client))) return PA_HOOK_OK; @@ -388,11 +455,6 @@ static pa_hook_result_t sink_input_hook_callback(pa_core *c, pa_sink_input_new_d pa_log_info("Restoring volume for <%s>", r->name); pa_sink_input_new_data_set_volume(data, &r->volume); } - - if (!data->sink && r->sink) { - if ((data->sink = pa_namereg_get(c, r->sink, PA_NAMEREG_SINK, 1))) - pa_log_info("Restoring sink for <%s>", r->name); - } } pa_xfree(name); @@ -400,7 +462,7 @@ static pa_hook_result_t sink_input_hook_callback(pa_core *c, pa_sink_input_new_d return PA_HOOK_OK; } -static pa_hook_result_t source_output_hook_callback(pa_core *c, pa_source_output_new_data *data, struct userdata *u) { +static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_output_new_data *data, struct userdata *u) { struct rule *r; char *name; @@ -422,6 +484,7 @@ static pa_hook_result_t source_output_hook_callback(pa_core *c, pa_source_output int pa__init(pa_module*m) { pa_modargs *ma = NULL; struct userdata *u; + pa_bool_t restore_device = TRUE, restore_volume = TRUE; pa_assert(m); @@ -431,20 +494,39 @@ int pa__init(pa_module*m) { } u = pa_xnew(struct userdata, 1); + u->core = m->core; u->hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - u->subscription = NULL; u->table_file = pa_xstrdup(pa_modargs_get_value(ma, "table", NULL)); u->modified = FALSE; - u->sink_input_hook_slot = u->source_output_hook_slot = NULL; + u->subscription = NULL; + u->sink_input_new_hook_slot = u->sink_input_fixate_hook_slot = u->source_output_new_hook_slot = NULL; + u->save_time_event = NULL; m->userdata = u; + if (pa_modargs_get_value_boolean(ma, "restore_device", &restore_device) < 0 || + pa_modargs_get_value_boolean(ma, "restore_volume", &restore_volume) < 0) { + pa_log("restore_volume= and restore_device= expect boolean arguments"); + goto fail; + } + + if (!(restore_device || restore_volume)) { + pa_log("Both restrong the volume and restoring the device are disabled. There's no point in using this module at all then, failing."); + goto fail; + } + if (load_rules(u) < 0) goto fail; u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscribe_callback, u); - u->sink_input_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], (pa_hook_cb_t) sink_input_hook_callback, u); - u->source_output_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], (pa_hook_cb_t) source_output_hook_callback, u); + + if (restore_device) { + u->sink_input_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], (pa_hook_cb_t) sink_input_new_hook_callback, u); + u->source_output_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], (pa_hook_cb_t) source_output_new_hook_callback, u); + } + + if (restore_volume) + u->sink_input_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], (pa_hook_cb_t) sink_input_fixate_hook_callback, u); pa_modargs_free(ma); return 0; @@ -478,19 +560,21 @@ void pa__done(pa_module*m) { if (u->subscription) pa_subscription_free(u->subscription); - if (u->sink_input_hook_slot) - pa_hook_slot_free(u->sink_input_hook_slot); - if (u->source_output_hook_slot) - pa_hook_slot_free(u->source_output_hook_slot); + if (u->sink_input_new_hook_slot) + pa_hook_slot_free(u->sink_input_new_hook_slot); + if (u->sink_input_fixate_hook_slot) + pa_hook_slot_free(u->sink_input_fixate_hook_slot); + if (u->source_output_new_hook_slot) + pa_hook_slot_free(u->source_output_new_hook_slot); if (u->hashmap) { - - if (u->modified) - save_rules(u); - + save_rules(u); pa_hashmap_free(u->hashmap, free_func, NULL); } + if (u->save_time_event) + u->core->mainloop->time_free(u->save_time_event); + pa_xfree(u->table_file); pa_xfree(u); } diff --git a/src/pulse/context.c b/src/pulse/context.c index 805cd44e..bc960e21 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -86,6 +86,10 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_UNDERFLOW] = pa_command_overflow_or_underflow, [PA_COMMAND_PLAYBACK_STREAM_KILLED] = pa_command_stream_killed, [PA_COMMAND_RECORD_STREAM_KILLED] = pa_command_stream_killed, + [PA_COMMAND_PLAYBACK_STREAM_MOVED] = pa_command_stream_moved, + [PA_COMMAND_RECORD_STREAM_MOVED] = pa_command_stream_moved, + [PA_COMMAND_PLAYBACK_STREAM_SUSPENDED] = pa_command_stream_suspended, + [PA_COMMAND_RECORD_STREAM_SUSPENDED] = pa_command_stream_suspended, [PA_COMMAND_SUBSCRIBE_EVENT] = pa_command_subscribe_event }; @@ -396,7 +400,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t /* Enable shared memory support if possible */ if (c->version >= 10 && pa_mempool_is_shared(c->mempool) && - c->is_local) { + c->is_local > 0) { /* Only enable SHM if both sides are owned by the same * user. This is a security measure because otherwise @@ -965,6 +969,9 @@ pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_ int pa_context_is_local(pa_context *c) { pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + + PA_CHECK_VALIDITY(c, c->is_local >= 0, PA_ERR_BADSTATE); return c->is_local; } diff --git a/src/pulse/def.h b/src/pulse/def.h index a7c475db..dabbc5eb 100644 --- a/src/pulse/def.h +++ b/src/pulse/def.h @@ -122,7 +122,7 @@ typedef enum pa_stream_flags { * ahead can be corrected * quickly, without the need to * wait. */ - PA_STREAM_AUTO_TIMING_UPDATE = 8 /**< If set timing update requests + PA_STREAM_AUTO_TIMING_UPDATE = 8, /**< If set timing update requests * are issued periodically * automatically. Combined with * PA_STREAM_INTERPOLATE_TIMING @@ -132,6 +132,83 @@ typedef enum pa_stream_flags { * pa_stream_get_latency() at * all times without a packet * round trip.*/ + PA_STREAM_NO_REMAP_CHANNELS = 16, /**< Don't remap channels by + * their name, instead map them + * simply by their + * index. Implies + * PA_STREAM_NO_REMIX_CHANNELS. Only + * supported when the server is + * at least PA 0.9.8. It is + * ignored on older + * servers.\since 0.9.8 */ + PA_STREAM_NO_REMIX_CHANNELS = 32, /**< When remapping channels by + * name, don't upmix or downmix + * them to related + * channels. Copy them into + * matching channels of the + * device 1:1. Only supported + * when the server is at least + * PA 0.9.8. It is ignored on + * older servers. \since + * 0.9.8 */ + PA_STREAM_FIX_FORMAT = 64, /**< Use the sample format of the + * sink/device this stream is being + * connected to, and possibly ignore + * the format the sample spec contains + * -- but you still have to pass a + * valid value in it as a hint to + * PulseAudio what would suit your + * stream best. If this is used you + * should query the used sample format + * after creating the stream by using + * pa_stream_get_sample_spec(). Also, + * if you specified manual buffer + * metrics it is recommended to update + * them with + * pa_stream_set_buffer_attr() to + * compensate for the changed frame + * sizes. Only supported when the + * server is at least PA 0.9.8. It is + * ignored on older servers. \since + * 0.9.8 */ + + PA_STREAM_FIX_RATE = 128, /**< Use the sample rate of the sink, + * and possibly ignore the rate the + * sample spec contains. Usage similar + * to PA_STREAM_FIX_FORMAT.Only + * supported when the server is at least + * PA 0.9.8. It is ignored on older + * servers. \since 0.9.8 */ + + PA_STREAM_FIX_CHANNELS = 256, /**< Use the number of channels and + * the channel map of the sink, and + * possibly ignore the number of + * channels and the map the sample spec + * and the passed channel map + * contains. Usage similar to + * PA_STREAM_FIX_FORMAT. Only supported + * when the server is at least PA + * 0.9.8. It is ignored on older + * servers. \since 0.9.8 */ + PA_STREAM_DONT_MOVE = 512, /**< Don't allow moving of this stream to + * another sink/device. Useful if you use + * any of the PA_STREAM_FIX_ flags and + * want to make sure that resampling + * never takes place -- which might + * happen if the stream is moved to + * another sink/source whith a different + * sample spec/channel map. Only + * supported when the server is at least + * PA 0.9.8. It is ignored on older + * servers. \since 0.9.8 */ + PA_STREAM_VARIABLE_RATE = 1024, /**< Allow dynamic changing of the + * sampling rate during playback + * with + * pa_stream_update_sample_rate(). Only + * supported when the server is at + * least PA 0.9.8. It is ignored + * on older servers. \since + * 0.9.8 */ } pa_stream_flags_t; /** Playback and record buffer metrics */ diff --git a/src/pulse/internal.h b/src/pulse/internal.h index 95593adb..873f1363 100644 --- a/src/pulse/internal.h +++ b/src/pulse/internal.h @@ -103,6 +103,7 @@ struct pa_stream { PA_LLIST_FIELDS(pa_stream); char *name; + pa_bool_t manual_buffer_attr; pa_buffer_attr buffer_attr; pa_sample_spec sample_spec; pa_channel_map channel_map; @@ -110,12 +111,17 @@ struct pa_stream { uint32_t channel; uint32_t syncid; int channel_valid; - uint32_t device_index; + uint32_t stream_index; pa_stream_direction_t direction; pa_stream_state_t state; + pa_bool_t buffer_attr_not_ready, timing_info_not_ready; uint32_t requested_bytes; + uint32_t device_index; + char *device_name; + pa_bool_t suspended; + pa_memchunk peek_memchunk; void *peek_data; pa_memblockq *record_memblockq; @@ -157,6 +163,10 @@ struct pa_stream { void *underflow_userdata; pa_stream_notify_cb_t latency_update_callback; void *latency_update_userdata; + pa_stream_notify_cb_t moved_callback; + void *moved_userdata; + pa_stream_notify_cb_t suspended_callback; + void *suspended_userdata; }; typedef void (*pa_operation_cb_t)(void); @@ -172,12 +182,16 @@ struct pa_operation { pa_operation_state_t state; void *userdata; pa_operation_cb_t callback; + + void *private; /* some operations might need this */ }; void pa_command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); void pa_command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_command_stream_suspended(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +void pa_command_stream_moved(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t callback, void *userdata); void pa_operation_done(pa_operation *o); diff --git a/src/pulse/operation.c b/src/pulse/operation.c index 8a782fd1..5d2da5b8 100644 --- a/src/pulse/operation.c +++ b/src/pulse/operation.c @@ -44,6 +44,7 @@ pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t cb PA_REFCNT_INIT(o); o->context = c; o->stream = s; + o->private = NULL; o->state = PA_OPERATION_RUNNING; o->callback = cb; @@ -63,7 +64,6 @@ pa_operation *pa_operation_ref(pa_operation *o) { PA_REFCNT_INC(o); return o; } - void pa_operation_unref(pa_operation *o) { pa_assert(o); pa_assert(PA_REFCNT_VALUE(o) >= 1); diff --git a/src/pulse/stream.c b/src/pulse/stream.c index 47906a5c..92420825 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -51,6 +51,7 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 12 || (ss->format != PA_SAMPLE_S32LE || ss->format != PA_SAMPLE_S32NE), PA_ERR_NOTSUPPORTED); PA_CHECK_VALIDITY_RETURN_NULL(c, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID); s = pa_xnew(pa_stream, 1); @@ -58,6 +59,8 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->context = c; s->mainloop = c->mainloop; + s->buffer_attr_not_ready = s->timing_info_not_ready = FALSE; + s->read_callback = NULL; s->read_userdata = NULL; s->write_callback = NULL; @@ -70,6 +73,10 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->underflow_userdata = NULL; s->latency_update_callback = NULL; s->latency_update_userdata = NULL; + s->moved_callback = NULL; + s->moved_userdata = NULL; + s->suspended_callback = NULL; + s->suspended_userdata = NULL; s->direction = PA_STREAM_NODIRECTION; s->name = pa_xstrdup(name); @@ -84,11 +91,17 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->channel = 0; s->channel_valid = 0; s->syncid = c->csyncid++; - s->device_index = PA_INVALID_INDEX; + s->stream_index = PA_INVALID_INDEX; s->requested_bytes = 0; s->state = PA_STREAM_UNCONNECTED; + + s->manual_buffer_attr = FALSE; memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); + s->device_index = PA_INVALID_INDEX; + s->device_name = NULL; + s->suspended = FALSE; + s->peek_memchunk.index = 0; s->peek_memchunk.length = 0; s->peek_memchunk.memblock = NULL; @@ -139,6 +152,7 @@ static void stream_free(pa_stream *s) { pa_memblockq_free(s->record_memblockq); pa_xfree(s->name); + pa_xfree(s->device_name); pa_xfree(s); } @@ -178,7 +192,7 @@ uint32_t pa_stream_get_index(pa_stream *s) { PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX); - return s->device_index; + return s->stream_index; } void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { @@ -262,6 +276,95 @@ finish: pa_context_unref(c); } +void pa_command_stream_moved(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_context *c = userdata; + pa_stream *s; + uint32_t channel; + const char *dn; + int suspended; + uint32_t di; + + pa_assert(pd); + pa_assert(command == PA_COMMAND_PLAYBACK_STREAM_MOVED || command == PA_COMMAND_RECORD_STREAM_MOVED); + pa_assert(t); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + + pa_context_ref(c); + + if (c->version < 12) { + pa_context_fail(c, PA_ERR_PROTOCOL); + goto finish; + } + + if (pa_tagstruct_getu32(t, &channel) < 0 || + pa_tagstruct_getu32(t, &di) < 0 || + pa_tagstruct_gets(t, &dn) < 0 || + pa_tagstruct_get_boolean(t, &suspended) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(c, PA_ERR_PROTOCOL); + goto finish; + } + + if (!dn || di == PA_INVALID_INDEX) { + pa_context_fail(c, PA_ERR_PROTOCOL); + goto finish; + } + + if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_MOVED ? c->playback_streams : c->record_streams, channel))) + goto finish; + + pa_xfree(s->device_name); + s->device_name = pa_xstrdup(dn); + s->device_index = di; + + s->suspended = suspended; + + if (s->moved_callback) + s->moved_callback(s, s->moved_userdata); + +finish: + pa_context_unref(c); +} + +void pa_command_stream_suspended(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_context *c = userdata; + pa_stream *s; + uint32_t channel; + int suspended; + + pa_assert(pd); + pa_assert(command == PA_COMMAND_PLAYBACK_STREAM_SUSPENDED || command == PA_COMMAND_RECORD_STREAM_SUSPENDED); + pa_assert(t); + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + + pa_context_ref(c); + + if (c->version < 12) { + pa_context_fail(c, PA_ERR_PROTOCOL); + goto finish; + } + + if (pa_tagstruct_getu32(t, &channel) < 0 || + pa_tagstruct_get_boolean(t, &suspended) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(c, PA_ERR_PROTOCOL); + goto finish; + } + + if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_SUSPENDED ? c->playback_streams : c->record_streams, channel))) + goto finish; + + s->suspended = suspended; + + if (s->suspended_callback) + s->suspended_callback(s, s->suspended_userdata); + +finish: + pa_context_unref(c); +} + void pa_command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_stream *s; pa_context *c = userdata; @@ -412,6 +515,9 @@ static void create_stream_complete(pa_stream *s) { pa_assert(PA_REFCNT_VALUE(s) >= 1); pa_assert(s->state == PA_STREAM_CREATING); + if (s->buffer_attr_not_ready || s->timing_info_not_ready) + return; + pa_stream_set_state(s, PA_STREAM_READY); if (s->requested_bytes > 0 && s->write_callback) @@ -426,6 +532,17 @@ static void create_stream_complete(pa_stream *s) { } } +static void automatic_buffer_attr(pa_buffer_attr *attr, pa_sample_spec *ss) { + pa_assert(attr); + pa_assert(ss); + + attr->tlength = pa_bytes_per_second(ss)/2; + attr->maxlength = (attr->tlength*3)/2; + attr->minreq = attr->tlength/50; + attr->prebuf = attr->tlength - attr->minreq; + attr->fragsize = attr->tlength/50; +} + void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_stream *s = userdata; @@ -445,13 +562,13 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED } if (pa_tagstruct_getu32(t, &s->channel) < 0 || - ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || + ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->stream_index) < 0) || ((s->direction != PA_STREAM_RECORD) && pa_tagstruct_getu32(t, &s->requested_bytes) < 0)) { pa_context_fail(s->context, PA_ERR_PROTOCOL); goto finish; } - if (pa_context_get_server_protocol_version(s->context) >= 9) { + if (s->context->version >= 9) { if (s->direction == PA_STREAM_PLAYBACK) { if (pa_tagstruct_getu32(t, &s->buffer_attr.maxlength) < 0 || pa_tagstruct_getu32(t, &s->buffer_attr.tlength) < 0 || @@ -469,6 +586,58 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED } } + if (s->context->version >= 12) { + pa_sample_spec ss; + pa_channel_map cm; + const char *dn = NULL; + int suspended; + + if (pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_get_channel_map(t, &cm) < 0 || + pa_tagstruct_getu32(t, &s->device_index) < 0 || + pa_tagstruct_gets(t, &dn) < 0 || + pa_tagstruct_get_boolean(t, &suspended) < 0) { + pa_context_fail(s->context, PA_ERR_PROTOCOL); + goto finish; + } + + if (!dn || s->device_index == PA_INVALID_INDEX || + ss.channels != cm.channels || + !pa_channel_map_valid(&cm) || + !pa_sample_spec_valid(&ss) || + (!(s->flags & PA_STREAM_FIX_FORMAT) && ss.format != s->sample_spec.format) || + (!(s->flags & PA_STREAM_FIX_RATE) && ss.rate != s->sample_spec.rate) || + (!(s->flags & PA_STREAM_FIX_CHANNELS) && !pa_channel_map_equal(&cm, &s->channel_map))) { + pa_context_fail(s->context, PA_ERR_PROTOCOL); + goto finish; + } + + pa_xfree(s->device_name); + s->device_name = pa_xstrdup(dn); + s->suspended = suspended; + + if (!s->manual_buffer_attr && pa_bytes_per_second(&ss) != pa_bytes_per_second(&s->sample_spec)) { + pa_buffer_attr attr; + pa_operation *o; + + automatic_buffer_attr(&attr, &ss); + + /* If we need to update the buffer metrics, we wait for + * the the OK for that call before we go to + * PA_STREAM_READY */ + + s->state = PA_STREAM_READY; + pa_assert_se(o = pa_stream_set_buffer_attr(s, &attr, NULL, NULL)); + pa_operation_unref(o); + s->state = PA_STREAM_CREATING; + + s->buffer_attr_not_ready = TRUE; + } + + s->channel_map = cm; + s->sample_spec = ss; + } + if (!pa_tagstruct_eof(t)) { pa_context_fail(s->context, PA_ERR_PROTOCOL); goto finish; @@ -491,15 +660,19 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); if (s->direction != PA_STREAM_UPLOAD && s->flags & PA_STREAM_AUTO_TIMING_UPDATE) { + /* If automatic timing updates are active, we wait for the * first timing update before going to PA_STREAM_READY * state */ + s->state = PA_STREAM_READY; request_auto_timing_update(s, 1); s->state = PA_STREAM_CREATING; - } else - create_stream_complete(s); + s->timing_info_not_ready = TRUE; + } + + create_stream_complete(s); finish: pa_stream_unref(s); @@ -525,7 +698,13 @@ static int create_stream( PA_STREAM_START_CORKED| PA_STREAM_INTERPOLATE_TIMING| PA_STREAM_NOT_MONOTONOUS| - PA_STREAM_AUTO_TIMING_UPDATE : 0))), PA_ERR_INVALID); + PA_STREAM_AUTO_TIMING_UPDATE| + PA_STREAM_NO_REMAP_CHANNELS| + PA_STREAM_NO_REMIX_CHANNELS| + PA_STREAM_FIX_FORMAT| + PA_STREAM_FIX_RATE| + PA_STREAM_FIX_CHANNELS| + PA_STREAM_DONT_MOVE : 0))), PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, !volume || volume->channels == s->sample_spec.channels, PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, !sync_stream || (direction == PA_STREAM_PLAYBACK && sync_stream->direction == PA_STREAM_PLAYBACK), PA_ERR_INVALID); @@ -537,15 +716,17 @@ static int create_stream( if (sync_stream) s->syncid = sync_stream->syncid; - if (attr) + if (attr) { s->buffer_attr = *attr; - else { + s->manual_buffer_attr = TRUE; + } else { /* half a second, with minimum request of 10 ms */ s->buffer_attr.tlength = pa_bytes_per_second(&s->sample_spec)/2; s->buffer_attr.maxlength = (s->buffer_attr.tlength*3)/2; s->buffer_attr.minreq = s->buffer_attr.tlength/50; s->buffer_attr.prebuf = s->buffer_attr.tlength - s->buffer_attr.minreq; s->buffer_attr.fragsize = s->buffer_attr.tlength/50; + s->manual_buffer_attr = FALSE; } if (!dev) @@ -585,6 +766,19 @@ static int create_stream( } else pa_tagstruct_putu32(t, s->buffer_attr.fragsize); + if (s->context->version >= 12 && s->direction != PA_STREAM_UPLOAD) { + pa_tagstruct_put( + t, + PA_TAG_BOOLEAN, flags & PA_STREAM_NO_REMAP_CHANNELS, + PA_TAG_BOOLEAN, flags & PA_STREAM_NO_REMIX_CHANNELS, + PA_TAG_BOOLEAN, flags & PA_STREAM_FIX_FORMAT, + PA_TAG_BOOLEAN, flags & PA_STREAM_FIX_RATE, + PA_TAG_BOOLEAN, flags & PA_STREAM_FIX_CHANNELS, + PA_TAG_BOOLEAN, flags & PA_STREAM_DONT_MOVE, + PA_TAG_BOOLEAN, flags & PA_STREAM_VARIABLE_RATE, + PA_TAG_INVALID); + } + pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL); @@ -921,8 +1115,10 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, } /* First, let's complete the initialization, if necessary. */ - if (o->stream->state == PA_STREAM_CREATING) + if (o->stream->state == PA_STREAM_CREATING) { + o->stream->timing_info_not_ready = FALSE; create_stream_complete(o->stream); + } if (o->stream->latency_update_callback) o->stream->latency_update_callback(o->stream, o->stream->latency_update_userdata); @@ -1084,6 +1280,22 @@ void pa_stream_set_latency_update_callback(pa_stream *s, pa_stream_notify_cb_t c s->latency_update_userdata = userdata; } +void pa_stream_set_moved_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + + s->moved_callback = cb; + s->moved_userdata = userdata; +} + +void pa_stream_set_suspended_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + + s->suspended_callback = cb; + s->suspended_userdata = userdata; +} + void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { pa_operation *o = userdata; int success = 1; @@ -1420,8 +1632,208 @@ const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s) { PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, - pa_context_get_server_protocol_version(s->context) >= 9, PA_ERR_NODATA); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->context->version >= 9, PA_ERR_NODATA); return &s->buffer_attr; } + +static void stream_set_buffer_attr_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int success = 1; + + pa_assert(pd); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); + + if (!o->context) + goto finish; + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + success = 0; + } else { + + if (o->stream->direction == PA_STREAM_PLAYBACK) { + if (pa_tagstruct_getu32(t, &o->stream->buffer_attr.maxlength) < 0 || + pa_tagstruct_getu32(t, &o->stream->buffer_attr.tlength) < 0 || + pa_tagstruct_getu32(t, &o->stream->buffer_attr.prebuf) < 0 || + pa_tagstruct_getu32(t, &o->stream->buffer_attr.minreq) < 0) { + pa_context_fail(o->context, PA_ERR_PROTOCOL); + goto finish; + } + } else if (o->stream->direction == PA_STREAM_RECORD) { + if (pa_tagstruct_getu32(t, &o->stream->buffer_attr.maxlength) < 0 || + pa_tagstruct_getu32(t, &o->stream->buffer_attr.fragsize) < 0) { + pa_context_fail(o->context, PA_ERR_PROTOCOL); + goto finish; + } + } + + if (!pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERR_PROTOCOL); + goto finish; + } + + o->stream->manual_buffer_attr = TRUE; + } + + if (o->stream->state == PA_STREAM_CREATING) { + o->stream->buffer_attr_not_ready = FALSE; + create_stream_complete(o->stream); + } + + if (o->callback) { + pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback; + cb(o->stream, success, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + + +pa_operation* pa_stream_set_buffer_attr(pa_stream *s, const pa_buffer_attr *attr, pa_stream_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + pa_assert(attr); + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->context->version >= 12, PA_ERR_NOTSUPPORTED); + + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command( + s->context, + s->direction == PA_STREAM_RECORD ? PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR : PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR, + &tag); + pa_tagstruct_putu32(t, s->channel); + + pa_tagstruct_putu32(t, attr->maxlength); + + if (s->direction == PA_STREAM_PLAYBACK) + pa_tagstruct_put( + t, + PA_TAG_U32, attr->tlength, + PA_TAG_U32, attr->prebuf, + PA_TAG_U32, attr->minreq, + PA_TAG_INVALID); + else + pa_tagstruct_putu32(t, attr->fragsize); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_set_buffer_attr_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +uint32_t pa_stream_get_device_index(pa_stream *s) { + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX); + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE, PA_INVALID_INDEX); + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->context->version >= 12, PA_ERR_NOTSUPPORTED, PA_INVALID_INDEX); + PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->device_index != PA_INVALID_INDEX, PA_ERR_BADSTATE, PA_INVALID_INDEX); + + return s->device_index; +} + +const char *pa_stream_get_device_name(pa_stream *s) { + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->context->version >= 12, PA_ERR_NOTSUPPORTED); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->device_name, PA_ERR_BADSTATE); + + return s->device_name; +} + +int pa_stream_is_suspended(pa_stream *s) { + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->context->version >= 12, PA_ERR_NOTSUPPORTED); + + return s->suspended; +} + +static void stream_update_sample_rate_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_operation *o = userdata; + int success = 1; + + pa_assert(pd); + pa_assert(o); + pa_assert(PA_REFCNT_VALUE(o) >= 1); + + if (!o->context) + goto finish; + + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; + + success = 0; + } else { + + if (!pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERR_PROTOCOL); + goto finish; + } + } + + o->stream->sample_spec.rate = PA_PTR_TO_UINT(o->private); + pa_assert(pa_sample_spec_valid(&o->stream->sample_spec)); + + if (o->callback) { + pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback; + cb(o->stream, success, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); +} + + +pa_operation *pa_stream_update_sample_rate(pa_stream *s, uint32_t rate, pa_stream_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(s->context, rate > 0 && rate <= PA_RATE_MAX, PA_ERR_INVALID); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->flags & PA_STREAM_VARIABLE_RATE, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->context->version >= 12, PA_ERR_NOTSUPPORTED); + + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); + o->private = PA_UINT_TO_PTR(rate); + + t = pa_tagstruct_command( + s->context, + s->direction == PA_STREAM_RECORD ? PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE : PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE, + &tag); + pa_tagstruct_putu32(t, s->channel); + pa_tagstruct_putu32(t, rate); + + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_update_sample_rate_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; + +} diff --git a/src/pulse/stream.h b/src/pulse/stream.h index 8c6a90c1..85473227 100644 --- a/src/pulse/stream.h +++ b/src/pulse/stream.h @@ -295,9 +295,38 @@ pa_stream_state_t pa_stream_get_state(pa_stream *p); /** Return the context this stream is attached to */ pa_context* pa_stream_get_context(pa_stream *p); -/** Return the device (sink input or source output) index this stream is connected to */ +/** Return the sink input resp. source output index this stream is + * identified in the server with. This is useful for usage with the + * introspection functions, such as pa_context_get_sink_input_info() + * resp. pa_context_get_source_output_info(). */ uint32_t pa_stream_get_index(pa_stream *s); +/** Return the index of the sink or source this stream is connected to + * in the server. This is useful for usage with the introspection + * functions, such as pa_context_get_sink_info_by_index() + * resp. pa_context_get_source_info_by_index(). Please note that + * streams may be moved between sinks/sources and thus it is + * recommended to use pa_stream_set_moved_callback() to be notified + * about this. This function will return with PA_ERR_NOTSUPPORTED when the + * server is older than 0.9.8. \since 0.9.8 */ +uint32_t pa_stream_get_device_index(pa_stream *s); + +/** Return the name of the sink or source this stream is connected to + * in the server. This is useful for usage with the introspection + * functions, such as pa_context_get_sink_info_by_name() + * resp. pa_context_get_source_info_by_name(). Please note that + * streams may be moved between sinks/sources and thus it is + * recommended to use pa_stream_set_moved_callback() to be notified + * about this. This function will return with PA_ERR_NOTSUPPORTED when the + * server is older than 0.9.8. \since 0.9.8 */ +const char *pa_stream_get_device_name(pa_stream *s); + +/** Return 1 if the sink or source this stream is connected to has + * been suspended. This will return 0 if not, and negative on + * error. This function will return with PA_ERR_NOTSUPPORTED when the + * server is older than 0.9.8. \since 0.9.8 */ +int pa_stream_is_suspended(pa_stream *s); + /** Connect the stream to a sink */ int pa_stream_connect_playback( pa_stream *s /**< The stream to connect to a sink */, @@ -346,10 +375,10 @@ int pa_stream_peek( * calling pa_stream_peek(). \since 0.8 */ int pa_stream_drop(pa_stream *p); -/** Return the nember of bytes that may be written using pa_stream_write(), in bytes */ +/** Return the number of bytes that may be written using pa_stream_write() */ size_t pa_stream_writable_size(pa_stream *p); -/** Return the number of bytes that may be read using pa_stream_read(), in bytes \since 0.8 */ +/** Return the number of bytes that may be read using pa_stream_read() \since 0.8 */ size_t pa_stream_readable_size(pa_stream *p); /** Drain a playback stream. Use this for notification when the buffer is empty */ @@ -378,9 +407,28 @@ void pa_stream_set_overflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, voi /** Set the callback function that is called when a buffer underflow happens. (Only for playback streams) \since 0.8 */ void pa_stream_set_underflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); -/** Set the callback function that is called whenever a latency information update happens. Useful on PA_STREAM_AUTO_TIMING_UPDATE streams only. (Only for playback streams) \since 0.8.2 */ +/** Set the callback function that is called whenever a latency + * information update happens. Useful on PA_STREAM_AUTO_TIMING_UPDATE + * streams only. (Only for playback streams) \since 0.8.2 */ void pa_stream_set_latency_update_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); +/** Set the callback function that is called whenever the stream is + * moved to a different sink/source. Use pa_stream_get_device_name()or + * pa_stream_get_device_index() to query the new sink/source. This + * notification is only generated when the server is at least + * 0.9.8. \since 0.9.8 */ +void pa_stream_set_moved_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); + +/** Set the callback function that is called whenever the sink/source + * this stream is connected to is suspended or resumed. Use + * pa_stream_is_suspended() to query the new suspend status. Please + * note that the suspend status might also change when the stream is + * moved between devices. Thus if you call this function you very + * likely want to call pa_stream_set_moved_callback, too. This + * notification is only generated when the server is at least + * 0.9.8. \since 0.9.8 */ +void pa_stream_set_suspended_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); + /** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. \since 0.3 */ pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata); @@ -447,6 +495,21 @@ const pa_channel_map* pa_stream_get_channel_map(pa_stream *s); * PulseAudio 0.9. \since 0.9.0 */ const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s); +/** Change the buffer metrics of the stream during playback. The + * server might have chosen different buffer metrics then + * requested. The selected metrics may be queried with + * pa_stream_get_buffer_attr() as soon as the callback is called. Only + * valid after the stream has been connected successfully and if the + * server is at least PulseAudio 0.9.8. \since 0.9.8 */ +pa_operation *pa_stream_set_buffer_attr(pa_stream *s, const pa_buffer_attr *attr, pa_stream_success_cb_t cb, void *userdata); + +/* Change the stream sampling rate during playback. You need to pass + * PA_STREAM_VARIABLE_RATE in the flags parameter of + * pa_stream_connect() if you plan to use this function. Only valid + * after the stream has been connected successfully and if the server + * is at least PulseAudio 0.9.8. \since 0.9.8 */ +pa_operation *pa_stream_update_sample_rate(pa_stream *s, uint32_t rate, pa_stream_success_cb_t cb, void *userdata); + PA_C_DECL_END #endif diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index a77bcc2c..b64cafe2 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -236,7 +236,7 @@ char *pa_source_output_list_to_string(pa_core *c) { " index: %u\n" "\tname: '%s'\n" "\tdriver: <%s>\n" - "\tflags: %s%s\n" + "\tflags: %s%s%s%s%s%s%s\n" "\tstate: %s\n" "\tsource: <%u> '%s'\n" "\tlatency: <%0.0f usec>\n" @@ -248,6 +248,11 @@ char *pa_source_output_list_to_string(pa_core *c) { o->driver, o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE ? "VARIABLE_RATE " : "", o->flags & PA_SOURCE_OUTPUT_DONT_MOVE ? "DONT_MOVE " : "", + o->flags & PA_SOURCE_OUTPUT_NO_REMAP ? "NO_REMAP " : "", + o->flags & PA_SOURCE_OUTPUT_NO_REMIX ? "NO_REMIX " : "", + o->flags & PA_SOURCE_OUTPUT_FIX_FORMAT ? "FIX_FORMAT " : "", + o->flags & PA_SOURCE_OUTPUT_FIX_RATE ? "FIX_RATE " : "", + o->flags & PA_SOURCE_OUTPUT_FIX_CHANNELS ? "FIX_CHANNELS " : "", state_table[pa_source_output_get_state(o)], o->source->index, o->source->name, (double) pa_source_output_get_latency(o), @@ -289,7 +294,7 @@ char *pa_sink_input_list_to_string(pa_core *c) { " index: %u\n" "\tname: <%s>\n" "\tdriver: <%s>\n" - "\tflags: %s%s\n" + "\tflags: %s%s%s%s%s%s%s\n" "\tstate: %s\n" "\tsink: <%u> '%s'\n" "\tvolume: <%s>\n" @@ -303,6 +308,11 @@ char *pa_sink_input_list_to_string(pa_core *c) { i->driver, i->flags & PA_SINK_INPUT_VARIABLE_RATE ? "VARIABLE_RATE " : "", i->flags & PA_SINK_INPUT_DONT_MOVE ? "DONT_MOVE " : "", + i->flags & PA_SINK_INPUT_NO_REMAP ? "NO_REMAP " : "", + i->flags & PA_SINK_INPUT_NO_REMIX ? "NO_REMIX " : "", + i->flags & PA_SINK_INPUT_FIX_FORMAT ? "FIX_FORMAT " : "", + i->flags & PA_SINK_INPUT_FIX_RATE ? "FIX_RATE " : "", + i->flags & PA_SINK_INPUT_FIX_CHANNELS ? "FIX_CHANNELS " : "", state_table[pa_sink_input_get_state(i)], i->sink->index, i->sink->name, pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)), diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index 9b420c94..cf018509 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -138,6 +138,7 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) { c->disallow_module_loading = FALSE; c->realtime_scheduling = FALSE; c->realtime_priority = 5; + c->disable_remixing = FALSE; for (j = 0; j < PA_CORE_HOOK_MAX; j++) pa_hook_init(&c->hooks[j], c); diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index 9aeb7888..ce45e300 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -54,6 +54,7 @@ typedef enum pa_core_hook { PA_CORE_HOOK_SOURCE_STATE_CHANGED, PA_CORE_HOOK_SOURCE_DESCRIPTION_CHANGED, PA_CORE_HOOK_SINK_INPUT_NEW, + PA_CORE_HOOK_SINK_INPUT_FIXATE, PA_CORE_HOOK_SINK_INPUT_PUT, PA_CORE_HOOK_SINK_INPUT_UNLINK, PA_CORE_HOOK_SINK_INPUT_UNLINK_POST, @@ -62,6 +63,7 @@ typedef enum pa_core_hook { PA_CORE_HOOK_SINK_INPUT_NAME_CHANGED, PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED, PA_CORE_HOOK_SOURCE_OUTPUT_NEW, + PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE, PA_CORE_HOOK_SOURCE_OUTPUT_PUT, PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK, PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST, @@ -118,6 +120,7 @@ struct pa_core { pa_bool_t is_system_instance; pa_bool_t realtime_scheduling; int realtime_priority; + pa_bool_t disable_remixing; /* hooks */ pa_hook hooks[PA_CORE_HOOK_MAX]; diff --git a/src/pulsecore/pid.c b/src/pulsecore/pid.c index 55ff2088..f3c9faaa 100644 --- a/src/pulsecore/pid.c +++ b/src/pulsecore/pid.c @@ -42,6 +42,7 @@ #endif #include +#include #include #include @@ -260,8 +261,8 @@ fail: * exists and the PID therein too. Returns 0 on succcess, -1 * otherwise. If pid is non-NULL and a running daemon was found, * return its PID therein */ -int pa_pid_file_check_running(pid_t *pid) { - return pa_pid_file_kill(0, pid); +int pa_pid_file_check_running(pid_t *pid, const char *binary_name) { + return pa_pid_file_kill(0, pid, binary_name); } #ifndef OS_IS_WIN32 @@ -269,12 +270,14 @@ int pa_pid_file_check_running(pid_t *pid) { /* Kill a current running daemon. Return non-zero on success, -1 * otherwise. If successful *pid contains the PID of the daemon * process. */ -int pa_pid_file_kill(int sig, pid_t *pid) { +int pa_pid_file_kill(int sig, pid_t *pid, const char *binary_name) { int fd = -1; char fn[PATH_MAX]; int ret = -1; pid_t _pid; - +#ifdef __linux__ + char *e = NULL; +#endif if (!pid) pid = &_pid; @@ -286,6 +289,23 @@ int pa_pid_file_kill(int sig, pid_t *pid) { if ((*pid = read_pid(fn, fd)) == (pid_t) -1) goto fail; +#ifdef __linux__ + if (binary_name) { + pa_snprintf(fn, sizeof(fn), "/proc/%lu/exe", (unsigned long) pid); + + if ((e = pa_readlink(fn))) { + char *f = pa_path_get_filename(e); + if (strcmp(f, binary_name) +#if defined(__OPTIMIZE__) + /* libtool likes to rename our binary names ... */ + && !(pa_startswith(f, "lt-") && strcmp(f+3, binary_name) == 0) +#endif + ) + goto fail; + } + } +#endif + ret = kill(*pid, sig); fail: @@ -295,13 +315,17 @@ fail: pa_close(fd); } +#ifdef __linux__ + pa_xfree(e); +#endif + return ret; } #else /* OS_IS_WIN32 */ -int pa_pid_file_kill(int sig, pid_t *pid) { +int pa_pid_file_kill(int sig, pid_t *pid, const char *exe_name) { return -1; } diff --git a/src/pulsecore/pid.h b/src/pulsecore/pid.h index 0f25d1c8..1d6de7b5 100644 --- a/src/pulsecore/pid.h +++ b/src/pulsecore/pid.h @@ -26,7 +26,7 @@ int pa_pid_file_create(void); int pa_pid_file_remove(void); -int pa_pid_file_check_running(pid_t *pid); -int pa_pid_file_kill(int sig, pid_t *pid); +int pa_pid_file_check_running(pid_t *pid, const char *binary_name); +int pa_pid_file_kill(int sig, pid_t *pid, const char *binary_name); #endif diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 1d294746..48d5cd70 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -202,12 +202,16 @@ enum { static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk); static void sink_input_drop_cb(pa_sink_input *i, size_t length); static void sink_input_kill_cb(pa_sink_input *i); +static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend); +static void sink_input_moved_cb(pa_sink_input *i); static void send_memblock(connection *c); static void request_bytes(struct playback_stream*s); static void source_output_kill_cb(pa_source_output *o); static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk); +static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend); +static void source_output_moved_cb(pa_source_output *o); static pa_usec_t source_output_get_latency_cb(pa_source_output *o); static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk); @@ -248,6 +252,8 @@ static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint3 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = NULL, @@ -323,7 +329,13 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_REMOVE_AUTOLOAD] = command_remove_autoload, [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream, - [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream + [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream, + + [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr, + [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr, + + [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate, + [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate }; /* structure management */ @@ -435,12 +447,12 @@ static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, i static record_stream* record_stream_new( connection *c, pa_source *source, - const pa_sample_spec *ss, - const pa_channel_map *map, + pa_sample_spec *ss, + pa_channel_map *map, const char *name, uint32_t *maxlength, uint32_t fragment_size, - int corked) { + pa_source_output_flags_t flags) { record_stream *s; pa_source_output *source_output; @@ -462,7 +474,7 @@ static record_stream* record_stream_new( pa_source_output_new_data_set_sample_spec(&data, ss); pa_source_output_new_data_set_channel_map(&data, map); - if (!(source_output = pa_source_output_new(c->protocol->core, &data, corked ? PA_SOURCE_OUTPUT_START_CORKED : 0))) + if (!(source_output = pa_source_output_new(c->protocol->core, &data, flags))) return NULL; s = pa_msgobject_new(record_stream); @@ -473,21 +485,30 @@ static record_stream* record_stream_new( s->source_output->push = source_output_push_cb; s->source_output->kill = source_output_kill_cb; s->source_output->get_latency = source_output_get_latency_cb; + s->source_output->moved = source_output_moved_cb; + s->source_output->suspend = source_output_suspend_cb; s->source_output->userdata = s; s->memblockq = pa_memblockq_new( 0, *maxlength, 0, - base = pa_frame_size(ss), + base = pa_frame_size(&s->source_output->sample_spec), 1, 0, NULL); + *maxlength = pa_memblockq_get_maxlength(s->memblockq); + s->fragment_size = (fragment_size/base)*base; if (s->fragment_size <= 0) s->fragment_size = base; - *maxlength = pa_memblockq_get_maxlength(s->memblockq); + + if (s->fragment_size > *maxlength) + s->fragment_size = *maxlength; + + *ss = s->source_output->sample_spec; + *map = s->source_output->channel_map; pa_idxset_put(c->record_streams, s, &s->index); @@ -602,8 +623,8 @@ static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, static playback_stream* playback_stream_new( connection *c, pa_sink *sink, - const pa_sample_spec *ss, - const pa_channel_map *map, + pa_sample_spec *ss, + pa_channel_map *map, const char *name, uint32_t *maxlength, uint32_t *tlength, @@ -611,8 +632,8 @@ static playback_stream* playback_stream_new( uint32_t *minreq, pa_cvolume *volume, uint32_t syncid, - int corked, - uint32_t *missing) { + uint32_t *missing, + pa_sink_input_flags_t flags) { playback_stream *s, *ssync; pa_sink_input *sink_input; @@ -656,7 +677,7 @@ static playback_stream* playback_stream_new( data.client = c->client; data.sync_base = ssync ? ssync->sink_input : NULL; - if (!(sink_input = pa_sink_input_new(c->protocol->core, &data, corked ? PA_SINK_INPUT_START_CORKED : 0))) + if (!(sink_input = pa_sink_input_new(c->protocol->core, &data, flags))) return NULL; s = pa_msgobject_new(playback_stream); @@ -671,17 +692,19 @@ static playback_stream* playback_stream_new( s->sink_input->peek = sink_input_peek_cb; s->sink_input->drop = sink_input_drop_cb; s->sink_input->kill = sink_input_kill_cb; + s->sink_input->moved = sink_input_moved_cb; + s->sink_input->suspend = sink_input_suspend_cb; s->sink_input->userdata = s; start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0; - silence = pa_silence_memblock_new(c->protocol->core->mempool, ss, 0); + silence = pa_silence_memblock_new(c->protocol->core->mempool, &s->sink_input->sample_spec, 0); s->memblockq = pa_memblockq_new( start_index, *maxlength, *tlength, - pa_frame_size(ss), + pa_frame_size(&s->sink_input->sample_spec), *prebuf, *minreq, silence); @@ -694,6 +717,9 @@ static playback_stream* playback_stream_new( *minreq = (uint32_t) pa_memblockq_get_minreq(s->memblockq); *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq); + *ss = s->sink_input->sample_spec; + *map = s->sink_input->channel_map; + s->minreq = pa_memblockq_get_minreq(s->memblockq); pa_atomic_store(&s->missing, 0); s->drain_request = 0; @@ -1022,6 +1048,7 @@ static void sink_input_drop_cb(pa_sink_input *i, size_t length) { /* pa_log("after_drop: %u %u", pa_memblockq_get_length(s->memblockq), pa_memblockq_is_readable(s->memblockq)); */ } +/* Called from main context */ static void sink_input_kill_cb(pa_sink_input *i) { playback_stream *s; @@ -1033,6 +1060,42 @@ static void sink_input_kill_cb(pa_sink_input *i) { playback_stream_unlink(s); } +/* Called from main context */ +static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend) { + playback_stream *s; + pa_tagstruct *t; + + pa_sink_input_assert_ref(i); + s = PLAYBACK_STREAM(i->userdata); + playback_stream_assert_ref(s); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, s->index); + pa_tagstruct_put_boolean(t, suspend); + pa_pstream_send_tagstruct(s->connection->pstream, t); +} + +/* Called from main context */ +static void sink_input_moved_cb(pa_sink_input *i) { + playback_stream *s; + pa_tagstruct *t; + + pa_sink_input_assert_ref(i); + s = PLAYBACK_STREAM(i->userdata); + playback_stream_assert_ref(s); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, s->index); + pa_tagstruct_putu32(t, i->sink->index); + pa_tagstruct_puts(t, i->sink->name); + pa_tagstruct_put_boolean(t, pa_sink_get_state(i->sink) == PA_SINK_SUSPENDED); + pa_pstream_send_tagstruct(s->connection->pstream, t); +} + /*** source_output callbacks ***/ /* Called from thread context */ @@ -1070,6 +1133,41 @@ static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec); } +/* Called from main context */ +static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend) { + record_stream *s; + pa_tagstruct *t; + + pa_source_output_assert_ref(o); + s = RECORD_STREAM(o->userdata); + record_stream_assert_ref(s); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, s->index); + pa_tagstruct_put_boolean(t, suspend); + pa_pstream_send_tagstruct(s->connection->pstream, t); +} + +/* Called from main context */ +static void source_output_moved_cb(pa_source_output *o) { + record_stream *s; + pa_tagstruct *t; + + pa_source_output_assert_ref(o); + s = RECORD_STREAM(o->userdata); + record_stream_assert_ref(s); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, s->index); + pa_tagstruct_putu32(t, o->source->index); + pa_tagstruct_puts(t, o->source->name); + pa_pstream_send_tagstruct(s->connection->pstream, t); +} + /*** pdispatch callbacks ***/ static void protocol_error(connection *c) { @@ -1104,6 +1202,8 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC pa_sink *sink = NULL; pa_cvolume volume; int corked; + int no_remap = 0, no_remix = 0, fix_format = 0, fix_rate = 0, fix_channels = 0, no_move = 0, variable_rate = 0; + pa_sink_input_flags_t flags = 0; connection_assert_ref(c); pa_assert(t); @@ -1122,9 +1222,27 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC PA_TAG_U32, &minreq, PA_TAG_U32, &syncid, PA_TAG_CVOLUME, &volume, - PA_TAG_INVALID) < 0 || - !pa_tagstruct_eof(t) || - !name) { + PA_TAG_INVALID) < 0 || !name) { + protocol_error(c); + return; + } + + if (c->version >= 12) { + /* Since 0.9.8 the user can ask for a couple of additional flags */ + + if (pa_tagstruct_get_boolean(t, &no_remap) < 0 || + pa_tagstruct_get_boolean(t, &no_remix) < 0 || + pa_tagstruct_get_boolean(t, &fix_format) < 0 || + pa_tagstruct_get_boolean(t, &fix_rate) < 0 || + pa_tagstruct_get_boolean(t, &fix_channels) < 0 || + pa_tagstruct_get_boolean(t, &no_move) < 0 || + pa_tagstruct_get_boolean(t, &variable_rate) < 0) { + protocol_error(c); + return; + } + } + + if (!pa_tagstruct_eof(t)) { protocol_error(c); return; } @@ -1136,8 +1254,8 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, maxlength > 0 && maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, maxlength >= pa_frame_size(&ss), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, maxlength > 0, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); if (sink_index != PA_INVALID_INDEX) { sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); @@ -1147,7 +1265,17 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); } - s = playback_stream_new(c, sink, &ss, &map, name, &maxlength, &tlength, &prebuf, &minreq, &volume, syncid, corked, &missing); + flags = + (corked ? PA_SINK_INPUT_START_CORKED : 0) | + (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) | + (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) | + (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) | + (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) | + (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) | + (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) | + (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0); + + s = playback_stream_new(c, sink, &ss, &map, name, &maxlength, &tlength, &prebuf, &minreq, &volume, syncid, &missing, flags); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); reply = reply_new(tag); @@ -1159,7 +1287,7 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC /* pa_log("initial request is %u", missing); */ if (c->version >= 9) { - /* Since 0.9 we support sending the buffer metrics back to the client */ + /* Since 0.9.0 we support sending the buffer metrics back to the client */ pa_tagstruct_putu32(reply, (uint32_t) maxlength); pa_tagstruct_putu32(reply, (uint32_t) tlength); @@ -1167,6 +1295,20 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC pa_tagstruct_putu32(reply, (uint32_t) minreq); } + if (c->version >= 12) { + /* Since 0.9.8 we support sending the chosen sample + * spec/channel map/device/suspend status back to the + * client */ + + pa_tagstruct_put_sample_spec(reply, &ss); + pa_tagstruct_put_channel_map(reply, &map); + + pa_tagstruct_putu32(reply, s->sink_input->sink->index); + pa_tagstruct_puts(reply, s->sink_input->sink->name); + + pa_tagstruct_put_boolean(reply, pa_sink_get_state(s->sink_input->sink) == PA_SINK_SUSPENDED); + } + pa_pstream_send_tagstruct(c->pstream, reply); } @@ -1239,6 +1381,8 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_tagstruct *reply; pa_source *source = NULL; int corked; + int no_remap = 0, no_remix = 0, fix_format = 0, fix_rate = 0, fix_channels = 0, no_move = 0, variable_rate = 0; + pa_source_output_flags_t flags = 0; connection_assert_ref(c); pa_assert(t); @@ -1250,18 +1394,48 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_tagstruct_gets(t, &source_name) < 0 || pa_tagstruct_getu32(t, &maxlength) < 0 || pa_tagstruct_get_boolean(t, &corked) < 0 || - pa_tagstruct_getu32(t, &fragment_size) < 0 || - !pa_tagstruct_eof(t)) { + pa_tagstruct_getu32(t, &fragment_size) < 0) { + protocol_error(c); + return; + } + + if (c->version >= 12) { + /* Since 0.9.8 the user can ask for a couple of additional flags */ + + if (pa_tagstruct_get_boolean(t, &no_remap) < 0 || + pa_tagstruct_get_boolean(t, &no_remix) < 0 || + pa_tagstruct_get_boolean(t, &fix_format) < 0 || + pa_tagstruct_get_boolean(t, &fix_rate) < 0 || + pa_tagstruct_get_boolean(t, &fix_channels) < 0 || + pa_tagstruct_get_boolean(t, &no_move) < 0 || + pa_tagstruct_get_boolean(t, &variable_rate) < 0) { + protocol_error(c); + return; + } + } + + if (!pa_tagstruct_eof(t)) { protocol_error(c); return; } + flags = + (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) | + (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) | + (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) | + (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) | + (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) | + (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) | + (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) | + (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0); + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, source_index != PA_INVALID_INDEX || !source_name || (*source_name && pa_utf8_valid(source_name)), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, maxlength > 0, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); if (source_index != PA_INVALID_INDEX) { @@ -1272,7 +1446,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY); } - s = record_stream_new(c, source, &ss, &map, name, &maxlength, fragment_size, corked); + s = record_stream_new(c, source, &ss, &map, name, &maxlength, fragment_size, flags); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); reply = reply_new(tag); @@ -1287,6 +1461,20 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_tagstruct_putu32(reply, (uint32_t) s->fragment_size); } + if (c->version >= 12) { + /* Since 0.9.8 we support sending the chosen sample + * spec/channel map/device/suspend status back to the + * client */ + + pa_tagstruct_put_sample_spec(reply, &ss); + pa_tagstruct_put_channel_map(reply, &map); + + pa_tagstruct_putu32(reply, s->source_output->source->index); + pa_tagstruct_puts(reply, s->source_output->source->name); + + pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_SUSPENDED); + } + pa_pstream_send_tagstruct(c->pstream, reply); } @@ -2291,6 +2479,134 @@ static void command_flush_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_U pa_pstream_send_simple_ack(c->pstream, tag); } +static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + connection *c = CONNECTION(userdata); + uint32_t idx; + uint32_t maxlength, tlength, prebuf, minreq, fragsize; + pa_tagstruct *reply; + + connection_assert_ref(c); + pa_assert(t); + + if (pa_tagstruct_getu32(t, &idx) < 0) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + + if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) { + playback_stream *s; + + s = pa_idxset_get_by_index(c->output_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY); + + if (pa_tagstruct_get( + t, + PA_TAG_U32, &maxlength, + PA_TAG_U32, &tlength, + PA_TAG_U32, &prebuf, + PA_TAG_U32, &minreq, + PA_TAG_INVALID) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, maxlength > 0, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); + + pa_memblockq_set_maxlength(s->memblockq, maxlength); + pa_memblockq_set_tlength(s->memblockq, tlength); + pa_memblockq_set_prebuf(s->memblockq, prebuf); + pa_memblockq_set_minreq(s->memblockq, minreq); + + reply = reply_new(tag); + pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_maxlength(s->memblockq)); + pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_tlength(s->memblockq)); + pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_prebuf(s->memblockq)); + pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_minreq(s->memblockq)); + + } else { + record_stream *s; + size_t base; + pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR); + + s = pa_idxset_get_by_index(c->record_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + + if (pa_tagstruct_get( + t, + PA_TAG_U32, &maxlength, + PA_TAG_U32, &fragsize, + PA_TAG_INVALID) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, maxlength > 0, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); + + pa_memblockq_set_maxlength(s->memblockq, maxlength); + + base = pa_frame_size(&s->source_output->sample_spec); + s->fragment_size = (fragsize/base)*base; + if (s->fragment_size <= 0) + s->fragment_size = base; + + if (s->fragment_size > pa_memblockq_get_maxlength(s->memblockq)) + s->fragment_size = pa_memblockq_get_maxlength(s->memblockq); + + reply = reply_new(tag); + pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_maxlength(s->memblockq)); + pa_tagstruct_putu32(reply, s->fragment_size); + } + + pa_pstream_send_tagstruct(c->pstream, reply); +} + +static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + connection *c = CONNECTION(userdata); + uint32_t idx; + uint32_t rate; + + connection_assert_ref(c); + pa_assert(t); + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_getu32(t, &rate) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, rate > 0 && rate <= PA_RATE_MAX, tag, PA_ERR_INVALID); + + if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) { + playback_stream *s; + + s = pa_idxset_get_by_index(c->output_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY); + + pa_sink_input_set_rate(s->sink_input, rate); + + } else { + record_stream *s; + pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE); + + s = pa_idxset_get_by_index(c->record_streams, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + + pa_source_output_set_rate(s->source_output, rate); + } + + pa_pstream_send_simple_ack(c->pstream, tag); +} + static void command_set_default_sink_or_source(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { connection *c = CONNECTION(userdata); const char *s; @@ -2340,6 +2656,7 @@ static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t com } else { record_stream *s; + pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME); s = pa_idxset_get_by_index(c->record_streams, idx); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 730f3e5c..ec0914ec 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -93,7 +93,7 @@ pa_sink_input* pa_sink_input_new( pa_sink_input *i; pa_resampler *resampler = NULL; - char st[PA_SAMPLE_SPEC_SNPRINT_MAX]; + char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_assert(core); pa_assert(data); @@ -132,6 +132,24 @@ pa_sink_input* pa_sink_input_new( pa_return_null_if_fail(pa_cvolume_valid(&data->volume)); pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels); + if (flags & PA_SINK_INPUT_FIX_FORMAT) + data->sample_spec.format = data->sink->sample_spec.format; + + if (flags & PA_SINK_INPUT_FIX_RATE) + data->sample_spec.rate = data->sink->sample_spec.rate; + + if (flags & PA_SINK_INPUT_FIX_CHANNELS) { + data->sample_spec.channels = data->sink->sample_spec.channels; + data->channel_map = data->sink->channel_map; + } + + pa_assert(pa_sample_spec_valid(&data->sample_spec)); + pa_assert(pa_channel_map_valid(&data->channel_map)); + + /* Due to the fixing of the sample spec the volume might not match anymore */ + if (data->volume.channels != data->sample_spec.channels) + pa_cvolume_set(&data->volume, data->sample_spec.channels, pa_cvolume_avg(&data->volume)); + if (!data->muted_is_set) data->muted = 0; @@ -140,6 +158,9 @@ pa_sink_input* pa_sink_input_new( pa_return_null_if_fail(data->resample_method < PA_RESAMPLER_MAX); + if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], data) < 0) + return NULL; + if (pa_idxset_size(data->sink->inputs) >= PA_MAX_INPUTS_PER_SINK) { pa_log_warn("Failed to create sink input: too many inputs per sink."); return NULL; @@ -154,7 +175,9 @@ pa_sink_input* pa_sink_input_new( &data->sample_spec, &data->channel_map, &data->sink->sample_spec, &data->sink->channel_map, data->resample_method, - (flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0))) { + ((flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) | + ((flags & PA_SINK_INPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) | + (core->disable_remixing || (flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) { pa_log_warn("Unsupported resampling operation."); return NULL; } @@ -199,6 +222,7 @@ pa_sink_input* pa_sink_input_new( i->attach = NULL; i->detach = NULL; i->suspend = NULL; + i->moved = NULL; i->userdata = NULL; i->thread_info.state = i->state; @@ -215,11 +239,12 @@ pa_sink_input* pa_sink_input_new( pa_assert_se(pa_idxset_put(core->sink_inputs, pa_sink_input_ref(i), &i->index) == 0); pa_assert_se(pa_idxset_put(i->sink->inputs, i, NULL) == 0); - pa_log_info("Created input %u \"%s\" on %s with sample spec %s", + pa_log_info("Created input %u \"%s\" on %s with sample spec %s and channel map %s", i->index, i->name, i->sink->name, - pa_sample_spec_snprint(st, sizeof(st), &i->sample_spec)); + pa_sample_spec_snprint(st, sizeof(st), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map)); /* Don't forget to call pa_sink_input_put! */ @@ -307,6 +332,7 @@ void pa_sink_input_unlink(pa_sink_input *i) { i->attach = NULL; i->detach = NULL; i->suspend = NULL; + i->moved = NULL; if (linked) { pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index); @@ -709,6 +735,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { pa_sink *origin; pa_usec_t silence_usec = 0; pa_sink_input_move_info info; + pa_sink_input_move_hook_data hook_data; pa_sink_input_assert_ref(i); pa_assert(PA_SINK_INPUT_LINKED(i->state)); @@ -750,14 +777,18 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { &i->sample_spec, &i->channel_map, &dest->sample_spec, &dest->channel_map, i->resample_method, - (i->flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0))) { + ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) | + ((i->flags & PA_SINK_INPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) | + (i->core->disable_remixing || (i->flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) { pa_log_warn("Unsupported resampling operation."); return -1; } } else new_resampler = NULL; - pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE], i); + hook_data.sink_input = i; + hook_data.destination = dest; + pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE], &hook_data); memset(&info, 0, sizeof(info)); info.sink_input = i; @@ -870,6 +901,9 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) { pa_sink_update_status(origin); pa_sink_update_status(dest); + if (i->moved) + i->moved(i); + pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_POST], i); pa_log_debug("Successfully moved sink input %i from %s to %s.", i->index, origin->name, dest->name); diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 3f8e2039..8975db9e 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -53,7 +53,12 @@ static inline pa_bool_t PA_SINK_INPUT_LINKED(pa_sink_input_state_t x) { typedef enum pa_sink_input_flags { PA_SINK_INPUT_VARIABLE_RATE = 1, PA_SINK_INPUT_DONT_MOVE = 2, - PA_SINK_INPUT_START_CORKED = 4 + PA_SINK_INPUT_START_CORKED = 4, + PA_SINK_INPUT_NO_REMAP = 8, + PA_SINK_INPUT_NO_REMIX = 16, + PA_SINK_INPUT_FIX_FORMAT = 32, + PA_SINK_INPUT_FIX_RATE = 64, + PA_SINK_INPUT_FIX_CHANNELS = 128 } pa_sink_input_flags_t; struct pa_sink_input { @@ -107,7 +112,11 @@ struct pa_sink_input { /* If non-NULL called whenever the the sink this input is attached * to suspends or resumes. Called from main context */ - void (*suspend) (pa_sink_input *i, int b); /* may be NULL */ + void (*suspend) (pa_sink_input *i, pa_bool_t b); /* may be NULL */ + + /* If non-NULL called whenever the the sink this input is attached + * to changes. Called from main context */ + void (*moved) (pa_sink_input *i); /* may be NULL */ /* Supposed to unlink and destroy this stream. Called from main * context. */ @@ -181,6 +190,11 @@ typedef struct pa_sink_input_new_data { pa_sink_input *sync_base; } pa_sink_input_new_data; +typedef struct pa_sink_input_move_hook_data { + pa_sink_input *sink_input; + pa_sink *destination; +} pa_sink_input_move_hook_data; + pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data); void pa_sink_input_new_data_set_sample_spec(pa_sink_input_new_data *data, const pa_sample_spec *spec); void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const pa_channel_map *map); diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index dccb34cc..fcc91cb1 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -149,23 +149,16 @@ pa_sink* pa_sink_new( static int sink_set_state(pa_sink *s, pa_sink_state_t state) { int ret; + pa_bool_t suspend_change; pa_assert(s); if (s->state == state) return 0; - if ((s->state == PA_SINK_SUSPENDED && PA_SINK_OPENED(state)) || - (PA_SINK_OPENED(s->state) && state == PA_SINK_SUSPENDED)) { - pa_sink_input *i; - uint32_t idx; - - /* We're suspending or resuming, tell everyone about it */ - - for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) - if (i->suspend) - i->suspend(i, state == PA_SINK_SUSPENDED); - } + suspend_change = + (s->state == PA_SINK_SUSPENDED && PA_SINK_OPENED(state)) || + (PA_SINK_OPENED(s->state) && state == PA_SINK_SUSPENDED); if (s->set_state) if ((ret = s->set_state(s, state)) < 0) @@ -176,8 +169,20 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) { s->state = state; + if (suspend_change) { + pa_sink_input *i; + uint32_t idx; + + /* We're suspending or resuming, tell everyone about it */ + + for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) + if (i->suspend) + i->suspend(i, state == PA_SINK_SUSPENDED); + } + if (state != PA_SINK_UNLINKED) /* if we enter UNLINKED state pa_sink_unlink() will fire the apropriate events */ pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], s); + return 0; } diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 5c52419e..576ddcf2 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -71,7 +71,7 @@ pa_source_output* pa_source_output_new( pa_source_output *o; pa_resampler *resampler = NULL; - char st[PA_SAMPLE_SPEC_SNPRINT_MAX]; + char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_assert(core); pa_assert(data); @@ -103,11 +103,28 @@ pa_source_output* pa_source_output_new( pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map)); pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels); + if (flags & PA_SOURCE_OUTPUT_FIX_FORMAT) + data->sample_spec.format = data->source->sample_spec.format; + + if (flags & PA_SOURCE_OUTPUT_FIX_RATE) + data->sample_spec.rate = data->source->sample_spec.rate; + + if (flags & PA_SOURCE_OUTPUT_FIX_CHANNELS) { + data->sample_spec.channels = data->source->sample_spec.channels; + data->channel_map = data->source->channel_map; + } + + pa_assert(pa_sample_spec_valid(&data->sample_spec)); + pa_assert(pa_channel_map_valid(&data->channel_map)); + if (data->resample_method == PA_RESAMPLER_INVALID) data->resample_method = core->resample_method; pa_return_null_if_fail(data->resample_method < PA_RESAMPLER_MAX); + if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], data) < 0) + return NULL; + if (pa_idxset_size(data->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { pa_log("Failed to create source output: too many outputs per source."); return NULL; @@ -122,7 +139,9 @@ pa_source_output* pa_source_output_new( &data->source->sample_spec, &data->source->channel_map, &data->sample_spec, &data->channel_map, data->resample_method, - (flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0))) { + ((flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) | + ((flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) | + (core->disable_remixing || (flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) { pa_log_warn("Unsupported resampling operation."); return NULL; } @@ -153,6 +172,7 @@ pa_source_output* pa_source_output_new( o->detach = NULL; o->attach = NULL; o->suspend = NULL; + o->moved = NULL; o->userdata = NULL; o->thread_info.state = o->state; @@ -163,11 +183,12 @@ pa_source_output* pa_source_output_new( pa_assert_se(pa_idxset_put(core->source_outputs, o, &o->index) == 0); pa_assert_se(pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL) == 0); - pa_log_info("Created output %u \"%s\" on %s with sample spec %s", + pa_log_info("Created output %u \"%s\" on %s with sample spec %s and channel map %s", o->index, o->name, o->source->name, - pa_sample_spec_snprint(st, sizeof(st), &o->sample_spec)); + pa_sample_spec_snprint(st, sizeof(st), &o->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map)); /* Don't forget to call pa_source_output_put! */ @@ -229,6 +250,7 @@ void pa_source_output_unlink(pa_source_output*o) { o->attach = NULL; o->detach = NULL; o->suspend = NULL; + o->moved = NULL; if (linked) { pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); @@ -379,6 +401,7 @@ pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { pa_source *origin; pa_resampler *new_resampler = NULL; + pa_source_output_move_hook_data hook_data; pa_source_output_assert_ref(o); pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state)); @@ -415,13 +438,17 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { &dest->sample_spec, &dest->channel_map, &o->sample_spec, &o->channel_map, o->resample_method, - (o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0))) { + ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) | + ((o->flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) | + (o->core->disable_remixing || (o->flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) { pa_log_warn("Unsupported resampling operation."); return -1; } } - pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE], o); + hook_data.source_output = o; + hook_data.destination = dest; + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE], &hook_data); /* Okey, let's move it */ pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL); @@ -447,6 +474,9 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { pa_source_update_status(origin); pa_source_update_status(dest); + if (o->moved) + o->moved(o); + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_POST], o); pa_log_debug("Successfully moved source output %i from %s to %s.", o->index, origin->name, dest->name); diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index e38a1e5a..d6da8d00 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -49,7 +49,12 @@ static inline pa_bool_t PA_SOURCE_OUTPUT_LINKED(pa_source_output_state_t x) { typedef enum pa_source_output_flags { PA_SOURCE_OUTPUT_VARIABLE_RATE = 1, PA_SOURCE_OUTPUT_DONT_MOVE = 2, - PA_SOURCE_OUTPUT_START_CORKED = 4 + PA_SOURCE_OUTPUT_START_CORKED = 4, + PA_SOURCE_OUTPUT_NO_REMAP = 8, + PA_SOURCE_OUTPUT_NO_REMIX = 16, + PA_SOURCE_OUTPUT_FIX_FORMAT = 32, + PA_SOURCE_OUTPUT_FIX_RATE = 64, + PA_SOURCE_OUTPUT_FIX_CHANNELS = 128 } pa_source_output_flags_t; struct pa_source_output { @@ -81,9 +86,13 @@ struct pa_source_output { * disconnected from its source. Called from IO thread context */ void (*detach) (pa_source_output *o); /* may be NULL */ + /* If non-NULL called whenever the the source this output is attached + * to changes. Called from main context */ + void (*moved) (pa_source_output *o); /* may be NULL */ + /* If non-NULL called whenever the the source this output is attached * to suspends or resumes. Called from main context */ - void (*suspend) (pa_source_output *o, int b); /* may be NULL */ + void (*suspend) (pa_source_output *o, pa_bool_t b); /* may be NULL */ /* Supposed to unlink and destroy this stream. Called from main * context. */ @@ -135,6 +144,11 @@ typedef struct pa_source_output_new_data { pa_resample_method_t resample_method; } pa_source_output_new_data; +typedef struct pa_source_output_move_hook_data { + pa_source_output *source_output; + pa_source *destination; +} pa_source_output_move_hook_data; + pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_data *data); void pa_source_output_new_data_set_sample_spec(pa_source_output_new_data *data, const pa_sample_spec *spec); void pa_source_output_new_data_set_channel_map(pa_source_output_new_data *data, const pa_channel_map *map); diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 9a6902ae..5fd65cef 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -126,23 +126,16 @@ pa_source* pa_source_new( static int source_set_state(pa_source *s, pa_source_state_t state) { int ret; + pa_bool_t suspend_change; pa_assert(s); if (s->state == state) return 0; - if ((s->state == PA_SOURCE_SUSPENDED && PA_SOURCE_OPENED(state)) || - (PA_SOURCE_OPENED(s->state) && state == PA_SOURCE_SUSPENDED)) { - pa_source_output *o; - uint32_t idx; - - /* We're suspending or resuming, tell everyone about it */ - - for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx))) - if (o->suspend) - o->suspend(o, state == PA_SINK_SUSPENDED); - } + suspend_change = + (s->state == PA_SOURCE_SUSPENDED && PA_SOURCE_OPENED(state)) || + (PA_SOURCE_OPENED(s->state) && state == PA_SOURCE_SUSPENDED); if (s->set_state) if ((ret = s->set_state(s, state)) < 0) @@ -153,8 +146,20 @@ static int source_set_state(pa_source *s, pa_source_state_t state) { s->state = state; + if (suspend_change) { + pa_source_output *o; + uint32_t idx; + + /* We're suspending or resuming, tell everyone about it */ + + for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx))) + if (o->suspend) + o->suspend(o, state == PA_SINK_SUSPENDED); + } + if (state != PA_SOURCE_UNLINKED) /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */ pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], s); + return 0; } diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 96b6adb7..68e308d8 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -40,7 +40,7 @@ #define TIME_EVENT_USEC 50000 -#if PA_API_VERSION < 9 +#if PA_API_VERSION < 10 #error Invalid PulseAudio API version #endif @@ -69,6 +69,8 @@ static pa_sample_spec sample_spec = { static pa_channel_map channel_map; static int channel_map_set = 0; +static pa_stream_flags_t flags = 0; + /* A shortcut for terminating the application */ static void quit(int ret) { assert(mainloop_api); @@ -105,7 +107,8 @@ static void do_stream_write(size_t length) { /* This is called whenever new data may be written to the stream */ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { - assert(s && length); + assert(s); + assert(length > 0); if (stdio_event) mainloop_api->io_enable(stdio_event, PA_IO_EVENT_INPUT); @@ -119,7 +122,8 @@ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { /* This is called whenever new data may is available */ static void stream_read_callback(pa_stream *s, size_t length, void *userdata) { const void *data; - assert(s && length); + assert(s); + assert(length > 0); if (stdio_event) mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT); @@ -130,7 +134,8 @@ static void stream_read_callback(pa_stream *s, size_t length, void *userdata) { return; } - assert(data && length); + assert(data); + assert(length > 0); if (buffer) { fprintf(stderr, "Buffer overrun, dropping incoming data\n"); @@ -159,6 +164,7 @@ static void stream_state_callback(pa_stream *s, void *userdata) { case PA_STREAM_READY: if (verbose) { const pa_buffer_attr *a; + char cmt[PA_CHANNEL_MAP_SNPRINT_MAX], sst[PA_SAMPLE_SPEC_SNPRINT_MAX]; fprintf(stderr, "Stream successfully created.\n"); @@ -172,9 +178,16 @@ static void stream_state_callback(pa_stream *s, void *userdata) { assert(mode == RECORD); fprintf(stderr, "Buffer metrics: maxlength=%u, fragsize=%u\n", a->maxlength, a->fragsize); } - } + fprintf(stderr, "Using sample spec '%s', channel map '%s'.\n", + pa_sample_spec_snprint(sst, sizeof(sst), pa_stream_get_sample_spec(s)), + pa_channel_map_snprint(cmt, sizeof(cmt), pa_stream_get_channel_map(s))); + + fprintf(stderr, "Connected to device %s (%u, %ssuspended).\n", + pa_stream_get_device_name(s), + pa_stream_get_device_index(s), + pa_stream_is_suspended(s) ? "" : "not "); } break; @@ -186,6 +199,24 @@ static void stream_state_callback(pa_stream *s, void *userdata) { } } +static void stream_suspended_callback(pa_stream *s, void *userdata) { + assert(s); + + if (verbose) { + if (pa_stream_is_suspended(s)) + fprintf(stderr, "Stream device suspended.\n"); + else + fprintf(stderr, "Stream device resumed.\n"); + } +} + +static void stream_moved_callback(pa_stream *s, void *userdata) { + assert(s); + + if (verbose) + fprintf(stderr, "Stream moved to device %s (%u, %ssuspended).\n", pa_stream_get_device_name(s), pa_stream_get_device_index(s), pa_stream_is_suspended(s) ? "" : "not "); +} + /* This is called whenever the context status changes */ static void context_state_callback(pa_context *c, void *userdata) { assert(c); @@ -199,7 +230,8 @@ static void context_state_callback(pa_context *c, void *userdata) { case PA_CONTEXT_READY: { int r; - assert(c && !stream); + assert(c); + assert(!stream); if (verbose) fprintf(stderr, "Connection established.\n"); @@ -212,16 +244,18 @@ static void context_state_callback(pa_context *c, void *userdata) { pa_stream_set_state_callback(stream, stream_state_callback, NULL); pa_stream_set_write_callback(stream, stream_write_callback, NULL); pa_stream_set_read_callback(stream, stream_read_callback, NULL); + pa_stream_set_suspended_callback(stream, stream_suspended_callback, NULL); + pa_stream_set_moved_callback(stream, stream_moved_callback, NULL); if (mode == PLAYBACK) { pa_cvolume cv; - if ((r = pa_stream_connect_playback(stream, device, NULL, 0, pa_cvolume_set(&cv, sample_spec.channels, volume), NULL)) < 0) { + if ((r = pa_stream_connect_playback(stream, device, NULL, flags, pa_cvolume_set(&cv, sample_spec.channels, volume), NULL)) < 0) { fprintf(stderr, "pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(c))); goto fail; } } else { - if ((r = pa_stream_connect_record(stream, device, NULL, 0)) < 0) { + if ((r = pa_stream_connect_record(stream, device, NULL, flags)) < 0) { fprintf(stderr, "pa_stream_connect_record() failed: %s\n", pa_strerror(pa_context_errno(c))); goto fail; } @@ -280,7 +314,10 @@ static void stream_drain_complete(pa_stream*s, int success, void *userdata) { static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { size_t l, w = 0; ssize_t r; - assert(a == mainloop_api && e && stdio_event == e); + + assert(a == mainloop_api); + assert(e); + assert(stdio_event == e); if (buffer) { mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL); @@ -330,7 +367,10 @@ static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_even /* Some data may be written to STDOUT */ static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { ssize_t r; - assert(a == mainloop_api && e && stdio_event == e); + + assert(a == mainloop_api); + assert(e); + assert(stdio_event == e); if (!buffer) { mainloop_api->io_enable(stdio_event, PA_IO_EVENT_NULL); @@ -429,7 +469,16 @@ static void help(const char *argv0) { " float32be, ulaw, alaw (defaults to s16ne)\n" " --channels=CHANNELS The number of channels, 1 for mono, 2 for stereo\n" " (defaults to 2)\n" - " --channel-map=CHANNELMAP Channel map to use instead of the default\n", + " --channel-map=CHANNELMAP Channel map to use instead of the default\n" + " --fix-format Take the sample format from the sink the stream is\n" + " being connected to.\n" + " --fix-rate Take the sampling rate from the sink the stream is\n" + " being connected to.\n" + " --fix-channels Take the number of channels and the channel map\n" + " from the sink the stream is being connected to.\n" + " --no-remix Don't upmix or downmix channels.\n" + " --no-remap Map channels by index instead of name.\n" + , argv0); } @@ -441,6 +490,11 @@ enum { ARG_SAMPLEFORMAT, ARG_CHANNELS, ARG_CHANNELMAP, + ARG_FIX_FORMAT, + ARG_FIX_RATE, + ARG_FIX_CHANNELS, + ARG_NO_REMAP, + ARG_NO_REMIX }; int main(int argc, char *argv[]) { @@ -464,6 +518,11 @@ int main(int argc, char *argv[]) { {"format", 1, NULL, ARG_SAMPLEFORMAT}, {"channels", 1, NULL, ARG_CHANNELS}, {"channel-map", 1, NULL, ARG_CHANNELMAP}, + {"fix-format", 0, NULL, ARG_FIX_FORMAT}, + {"fix-rate", 0, NULL, ARG_FIX_RATE}, + {"fix-channels",0, NULL, ARG_FIX_CHANNELS}, + {"no-remap", 0, NULL, ARG_NO_REMAP}, + {"no-remix", 0, NULL, ARG_NO_REMIX}, {NULL, 0, NULL, 0} }; @@ -549,6 +608,26 @@ int main(int argc, char *argv[]) { channel_map_set = 1; break; + case ARG_FIX_CHANNELS: + flags |= PA_STREAM_FIX_CHANNELS; + break; + + case ARG_FIX_RATE: + flags |= PA_STREAM_FIX_RATE; + break; + + case ARG_FIX_FORMAT: + flags |= PA_STREAM_FIX_FORMAT; + break; + + case ARG_NO_REMIX: + flags |= PA_STREAM_NO_REMIX_CHANNELS; + break; + + case ARG_NO_REMAP: + flags |= PA_STREAM_NO_REMAP_CHANNELS; + break; + default: goto quit; } diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c index 9583385b..daa6a96e 100644 --- a/src/utils/pacmd.c +++ b/src/utils/pacmd.c @@ -50,7 +50,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { size_t ibuf_index, ibuf_length, obuf_index, obuf_length; fd_set ifds, ofds; - if (pa_pid_file_check_running(&pid) < 0) { + if (pa_pid_file_check_running(&pid, "pulseaudio") < 0) { pa_log("no PulseAudio daemon running"); goto fail; } @@ -75,7 +75,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) { if (r >= 0) break; - if (pa_pid_file_kill(SIGUSR2, NULL) < 0) { + if (pa_pid_file_kill(SIGUSR2, NULL, "pulseaudio") < 0) { pa_log("failed to kill PulseAudio daemon."); goto fail; } -- cgit From 0f5fa473f8b0498fcb341f95e985426b947865bd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Nov 2007 01:31:04 +0000 Subject: increment api and protocol version git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2068 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 30a70e11..80a9979f 100644 --- a/configure.ac +++ b/configure.ac @@ -36,8 +36,8 @@ AM_INIT_AUTOMAKE([foreign -Wall]) AC_SUBST(PA_MAJORMINOR, "PA_MAJOR.PA_MINOR") AC_SUBST(PACKAGE_URL, [http://pulseaudio.org/]) -AC_SUBST(PA_API_VERSION, 10) -AC_SUBST(PA_PROTOCOL_VERSION, 11) +AC_SUBST(PA_API_VERSION, 11) +AC_SUBST(PA_PROTOCOL_VERSION, 12) # The stable ABI for client applications, for the version info x:y:z # always will hold y=z -- cgit From 40db06de5f49c3fa50599e746e63aca00f07c889 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Nov 2007 22:55:28 +0000 Subject: when speaking to a client with a version < 12, hide S32 sample specs, and make them appaear as FLOAT32 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2069 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-native.c | 77 +++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 18 deletions(-) diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 48d5cd70..46405f10 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -1899,16 +1899,38 @@ static void command_remove_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED pa_pstream_send_simple_ack(c->pstream, tag); } -static void sink_fill_tagstruct(pa_tagstruct *t, pa_sink *sink) { +static void fixup_sample_spec(connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) { + pa_assert(c); + pa_assert(fixed); + pa_assert(original); + + *fixed = *original; + + if (c->version < 12) { + /* Before protocol version 12 we didn't support S32 samples, + * so we need to lie about this to the client */ + + if (fixed->format == PA_SAMPLE_S32LE) + fixed->format = PA_SAMPLE_FLOAT32LE; + if (fixed->format == PA_SAMPLE_S32BE) + fixed->format = PA_SAMPLE_FLOAT32BE; + } +} + +static void sink_fill_tagstruct(connection *c, pa_tagstruct *t, pa_sink *sink) { + pa_sample_spec fixed_ss; + pa_assert(t); pa_sink_assert_ref(sink); + fixup_sample_spec(c, &fixed_ss, &sink->sample_spec); + pa_tagstruct_put( t, PA_TAG_U32, sink->index, PA_TAG_STRING, sink->name, PA_TAG_STRING, sink->description, - PA_TAG_SAMPLE_SPEC, &sink->sample_spec, + PA_TAG_SAMPLE_SPEC, &fixed_ss, PA_TAG_CHANNEL_MAP, &sink->channel_map, PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX, PA_TAG_CVOLUME, pa_sink_get_volume(sink), @@ -1921,16 +1943,20 @@ static void sink_fill_tagstruct(pa_tagstruct *t, pa_sink *sink) { PA_TAG_INVALID); } -static void source_fill_tagstruct(pa_tagstruct *t, pa_source *source) { +static void source_fill_tagstruct(connection *c, pa_tagstruct *t, pa_source *source) { + pa_sample_spec fixed_ss; + pa_assert(t); pa_source_assert_ref(source); + fixup_sample_spec(c, &fixed_ss, &source->sample_spec); + pa_tagstruct_put( t, PA_TAG_U32, source->index, PA_TAG_STRING, source->name, PA_TAG_STRING, source->description, - PA_TAG_SAMPLE_SPEC, &source->sample_spec, + PA_TAG_SAMPLE_SPEC, &fixed_ss, PA_TAG_CHANNEL_MAP, &source->channel_map, PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX, PA_TAG_CVOLUME, pa_source_get_volume(source), @@ -1965,15 +1991,19 @@ static void module_fill_tagstruct(pa_tagstruct *t, pa_module *module) { } static void sink_input_fill_tagstruct(connection *c, pa_tagstruct *t, pa_sink_input *s) { + pa_sample_spec fixed_ss; + pa_assert(t); pa_sink_input_assert_ref(s); + fixup_sample_spec(c, &fixed_ss, &s->sample_spec); + pa_tagstruct_putu32(t, s->index); pa_tagstruct_puts(t, s->name); pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX); pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX); pa_tagstruct_putu32(t, s->sink->index); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_put_sample_spec(t, &fixed_ss); pa_tagstruct_put_channel_map(t, &s->channel_map); pa_tagstruct_put_cvolume(t, &s->volume); pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s)); @@ -1984,16 +2014,20 @@ static void sink_input_fill_tagstruct(connection *c, pa_tagstruct *t, pa_sink_in pa_tagstruct_put_boolean(t, pa_sink_input_get_mute(s)); } -static void source_output_fill_tagstruct(pa_tagstruct *t, pa_source_output *s) { +static void source_output_fill_tagstruct(connection *c, pa_tagstruct *t, pa_source_output *s) { + pa_sample_spec fixed_ss; + pa_assert(t); pa_source_output_assert_ref(s); + fixup_sample_spec(c, &fixed_ss, &s->sample_spec); + pa_tagstruct_putu32(t, s->index); pa_tagstruct_puts(t, s->name); pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX); pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX); pa_tagstruct_putu32(t, s->source->index); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_put_sample_spec(t, &fixed_ss); pa_tagstruct_put_channel_map(t, &s->channel_map); pa_tagstruct_put_usec(t, pa_source_output_get_latency(s)); pa_tagstruct_put_usec(t, pa_source_get_latency(s->source)); @@ -2001,15 +2035,19 @@ static void source_output_fill_tagstruct(pa_tagstruct *t, pa_source_output *s) { pa_tagstruct_puts(t, s->driver); } -static void scache_fill_tagstruct(pa_tagstruct *t, pa_scache_entry *e) { +static void scache_fill_tagstruct(connection *c, pa_tagstruct *t, pa_scache_entry *e) { + pa_sample_spec fixed_ss; + pa_assert(t); pa_assert(e); + fixup_sample_spec(c, &fixed_ss, &e->sample_spec); + pa_tagstruct_putu32(t, e->index); pa_tagstruct_puts(t, e->name); pa_tagstruct_put_cvolume(t, &e->volume); pa_tagstruct_put_usec(t, pa_bytes_to_usec(e->memchunk.length, &e->sample_spec)); - pa_tagstruct_put_sample_spec(t, &e->sample_spec); + pa_tagstruct_put_sample_spec(t, &fixed_ss); pa_tagstruct_put_channel_map(t, &e->channel_map); pa_tagstruct_putu32(t, e->memchunk.length); pa_tagstruct_put_boolean(t, e->lazy); @@ -2079,9 +2117,9 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u reply = reply_new(tag); if (sink) - sink_fill_tagstruct(reply, sink); + sink_fill_tagstruct(c, reply, sink); else if (source) - source_fill_tagstruct(reply, source); + source_fill_tagstruct(c, reply, source); else if (client) client_fill_tagstruct(reply, client); else if (module) @@ -2089,9 +2127,9 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u else if (si) sink_input_fill_tagstruct(c, reply, si); else if (so) - source_output_fill_tagstruct(reply, so); + source_output_fill_tagstruct(c, reply, so); else - scache_fill_tagstruct(reply, sce); + scache_fill_tagstruct(c, reply, sce); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -2134,9 +2172,9 @@ static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma if (i) { for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) { if (command == PA_COMMAND_GET_SINK_INFO_LIST) - sink_fill_tagstruct(reply, p); + sink_fill_tagstruct(c, reply, p); else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST) - source_fill_tagstruct(reply, p); + source_fill_tagstruct(c, reply, p); else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST) client_fill_tagstruct(reply, p); else if (command == PA_COMMAND_GET_MODULE_INFO_LIST) @@ -2144,10 +2182,10 @@ static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) sink_input_fill_tagstruct(c, reply, p); else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST) - source_output_fill_tagstruct(reply, p); + source_output_fill_tagstruct(c, reply, p); else { pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); - scache_fill_tagstruct(reply, p); + scache_fill_tagstruct(c, reply, p); } } } @@ -2160,6 +2198,7 @@ static void command_get_server_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE pa_tagstruct *reply; char txt[256]; const char *n; + pa_sample_spec fixed_ss; connection_assert_ref(c); pa_assert(t); @@ -2176,7 +2215,9 @@ static void command_get_server_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE pa_tagstruct_puts(reply, PACKAGE_VERSION); pa_tagstruct_puts(reply, pa_get_user_name(txt, sizeof(txt))); pa_tagstruct_puts(reply, pa_get_fqdn(txt, sizeof(txt))); - pa_tagstruct_put_sample_spec(reply, &c->protocol->core->default_sample_spec); + + fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec); + pa_tagstruct_put_sample_spec(reply, &fixed_ss); n = pa_namereg_get_default_sink_name(c->protocol->core); pa_tagstruct_puts(reply, n); -- cgit From 6b932f0a50a8459399a8b79eb91132c8bacf22b9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Nov 2007 23:03:19 +0000 Subject: update man pages a bit git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2070 fefdeb5f-60dc-0310-8127-8f9354f1896f --- man/pacat.1.xml.in | 25 +++++++++++++++++++++++++ man/pulse-daemon.conf.5.xml.in | 6 ++++++ 2 files changed, 31 insertions(+) diff --git a/man/pacat.1.xml.in b/man/pacat.1.xml.in index e02ad667..748d136d 100644 --- a/man/pacat.1.xml.in +++ b/man/pacat.1.xml.in @@ -145,6 +145,31 @@ USA. aux31.

        + + + + + + + + + +
        diff --git a/man/pulse-daemon.conf.5.xml.in b/man/pulse-daemon.conf.5.xml.in index 88bf8f58..2768e24e 100644 --- a/man/pulse-daemon.conf.5.xml.in +++ b/man/pulse-daemon.conf.5.xml.in @@ -101,6 +101,12 @@ USA. overwrite or allow overwriting of the resampler to use.

        + +